0

For working with graphics, I need to have an array of unsigned char. It must be 3 dimensional, with the first dimension being size 4, (1st byte Blue, 2nd byte Green, 3rd byte Red, 4th byte Unused). A simple array for a 640x480 image is then done like this:

unsigned char Pixels[4][640][480]

But the problem is, it always crashes the program immediately when it is run. It compiles fine. It links fine. It has no errors or warnings. But when it's run it immediately crashes. I had many other lines of code, but it is this one I found that causes the immediate crash. It's not like I don't have enough RAM to hold this data. It's only a tiny amount of data, just enough for a single 640x480 full color image. But I've only seen such immediate crashes before, when a program tries to read or write to unallocated memory (for example using CopyMemory API function, where the source or destination either partially or entirely outside the memory space of already defined variables). But this isn't such a memory reading or writing operation. It is a memory allocating operation. That should NEVER fail, unless there's not enough RAM in the PC. And my PC certainly has enough RAM (no modern computer would NOT have enough RAM for this). Can somebody tell me why it is messing up? Is this a well known problem with VC++ 6.0?

  • 3
    It has nothing to do with VC++ 6.0. Stack memory is very limited, allocate it on the heap (I would suggest using a vector for this, you could wrap it to deal with the indexing for you). – Borgleader Nov 28 '14 at 13:41
  • 4th byte should be named alpha. – stark Nov 28 '14 at 13:43
  • In VB6 all of this allocation is done internally. I Have defined some absolutely HUGE byte arrays in VB6. I'm not sure what VB6 is doing, nor do I need to, because it just works. I thought that defining huge pieces of memory was an easy task. – Ben Hutchinson Nov 28 '14 at 13:44
  • VB6 allocates the array data on the heap. Exactly as you should be doing. – Bathsheba Nov 28 '14 at 13:45
  • 3
    If you are porting an application, why not try a newer compiler over VC6? – Niall Nov 28 '14 at 13:45
  • 1
    Please show the full real code you are using to create this memory. – Neil Kirk Nov 28 '14 at 13:45
  • It's not used as alpha for BITMAPINFOHEADER. Only for BITMAPHEADER4 or larger newer is alpha even available. 32bit images for bitmaps using the BITMAPINFOHEADER, have the last byte completely unused. Some programs still interpret the 4th channel as alpha, but the official MS specs for BITMAPINFOHEADER, does not use alpha. It is stated to be unused, so you should NOT expect that a program reading a bitmap with BITMAPINFOHEADER to read the 4th channel as alpha, as it's not defined as such in the official Microsoft specs for BITMAPINFOHEADER bitmaps. – Ben Hutchinson Nov 28 '14 at 13:48
  • @NeilKirk The above code that I posted is the one line of code that is used to create the array, and the internals of whatever memory allocation is needed to accomplish that, should theoretically be happening behind the scenes. – Ben Hutchinson Nov 28 '14 at 13:50
  • @Bathsheba How do I manually do in VC++ what VB6 automatically does (allocate memory on the heap) for making an array? Any code samples for that? I thought that typing "unsigned char Pixels[4][640][480]" did the normal memory allocation procedure, and that this procedure was identical to VB's equivalent which is "Dim Pixels(3,639,479) as Byte". – Ben Hutchinson Nov 28 '14 at 13:53
  • Build a class to represent the data which it will do via a heap allocation. – Bathsheba Nov 28 '14 at 13:55
  • 1
    The code you provided won't compile, as it's missing a semi-colon. This may seem pedantic but knowing EXACTLY how the memory is declared is important to diagnose this problem. You seem to think you don't need to understand how memory is allocated in C++. You do. – Neil Kirk Nov 28 '14 at 13:57
  • 1
    @BenHutchinson: VB and C++ are very different languages and the sooner you stop trying to apply your VB knowledge to C++ the better. – Blastfurnace Nov 28 '14 at 13:57
  • 1
    @Bathsheba: (update: see you deleted this suggestion) making it static does not force *heap* allocation at all... it puts the data in the data segment used for compile-time allocated lifetime-as-long-as-the-program data, as distinct from the heap that uses runtime allocation with lifetime based on the programmer-orchestrated `new` and `delete` or `malloc`/`realloc`/`free` calls. – Tony Delroy Nov 28 '14 at 13:58
  • 1
    @BenHutchinson *"The above code that I posted is the one line of code that is used to create the array, and the internals of whatever memory allocation is needed to accomplish that, should theoretically be happening behind the scenes."* - that line does very different things if in a global or namespace scope vs. inside a function. – Tony Delroy Nov 28 '14 at 14:00

2 Answers2

4

If this is inside a function, then it will be allocated on the stack at runtime. It is more than a megabyte, so it might well be too big for the stack. You have two obvious options:

(i) make it static:

static unsigned char Pixels[4][640][480];

(ii) make it dynamic, i.e. allocate it from the heap (and don't forget to delete it when you have finished):

unsigned char (*Pixels)[640][480] = new unsigned char[4][640][480];
...
delete[] Pixels;

Option (i) is OK if the array will be needed for the lifetime of the application. Otherwise option (ii) is better.

TonyK
  • 16,761
  • 4
  • 37
  • 72
3

Visual C++ by default gives programs 1MB of stack. The size the array you are trying to allocate on the stack is 1200KB which is going to bust your stack. You need to allocate your array on the heap. std::vector is your best bet for this.

using namespace std;
vector<vector<vector<unsigned char>>> A(4, vector<vector<unsigned char>>(640, vector<unsigned char>(480, 0)));

This looks a bit more confusing but will do what you want in terms of initialising the array and means you don't have to worry about memory leaks.

Alternatively if this isn't an option then it is possible to increase the stack size by passing /STACK: followed by the desired stack size in bytes to the linker.

Edit: in the interests of speed you may wish to use a single allocated block of memory instead:

std::unique_ptr<unsigned char [][640][480]> A(new unsigned char [4][640][480]);
sjdowling
  • 2,994
  • 2
  • 21
  • 31
  • 1
    This looks rather inefficient! To access `A[x][y][z]` requires three levels of indirection, each with its own offset calculation, instead of a single offset calculation for a multi-dimensional array. – TonyK Nov 28 '14 at 14:12
  • @TonyK That's a good point, however I would still always recommend the use of RAII containers except in exceptional circumstances. – sjdowling Nov 28 '14 at 14:32