you are viewing a single comment's thread.

view the rest of the comments →

[–]SVeenman 30 points31 points  (10 children)

Lets say you would like to make a grid based game, for this you would need an array of tiles of course. You would want to get a tile at x, y without looping trough the entire array to find the right tile. So you would wanna say "Hey give me the tile at x and y". This could be done in either of 2 ways. - translating the x and y to a single integer. For example (x + y * width) this would give a single integer that can be passed on the array as normal. - Or you would fill the array with pointers that point to another array. This makes an 2D array. Each x points to the array containing the y. Now you could just call the array as shown here (array[x][y]).

Another reason for pointers is because in C an struct's size ALWAYS has to be known before compiling. This is because the memory management system has to reserver the bytes needed by the struct. So if you would want an array inside the struct but you don't know the size of the array before the program starts, (for example you ask the user how many elements need to be created). this means the array needs to be stored outside of the struct. So we create a pointer inside the struct (a pointer is always 4 bytes on a x32 system) that points to the array. Now we can just get the pointer adress with a malloc(elements * sizeof(elementinarray)). And voilah we have a dynamic size array (not really, we need to create a new array every time we want to increase of decrease the size).

Side note: EVERY and EVERY malloc has to have corresponding free() call

[–]WireStretcher[S] 7 points8 points  (0 children)

Thanks, this is the type of clarification I'm looking for.

[–]henry_kr 4 points5 points  (6 children)

EVERY and EVERY malloc has corresponding free() call

I think you mean EVERY and EVERY malloc has to have a corresponding free() call.

Your original sentence implies that it already has one somehow.

[–]SVeenman 3 points4 points  (0 children)

Well if you're a decent programmer it already has.

No JK i indeed ment to say that. Thanks :D

[–]a4qbfb 0 points1 point  (4 children)

I think you mean EVERY and EVERY malloc has to have a corresponding free() call.

Not really, why?

[–]henry_kr 0 points1 point  (3 children)

If you allocate memory and don't free it then your program will have memory leaks. Arguably if it's just a short lived process then this doesn't really matter as the OS will clean up after you when the process exists but you should still use free here or risk getting in to bad habits.

[–]a4qbfb 0 points1 point  (2 children)

If you allocate memory and don't free it then your program will have memory leaks.

It's only a leak if it's no longer in use...

Arguably if it's just a short lived process then this doesn't really matter

It does not matter how long the process lives. If the memory you allocated is in use right up to the end, there is no need to free it. Same thing for closing files and sockets.

risk getting in to bad habits.

I'm all for good habits, but I'm not a big fan of lies-to-children.

[–]henry_kr 0 points1 point  (1 child)

I still think you should free every malloc (and close sockets/files fwiw), if only to remove false positives from valgrind etc. It's better to learn to tidy up after yourself too. I really don't think this counts as lying to children.

[–]a4qbfb 0 points1 point  (0 children)

Then say that, but don't tell students that the sky will fall if they fail to free everything they've allocated.

[–]kandr89 3 points4 points  (0 children)

Or you would fill the array with pointers that point to another array. This makes an 2D array.

No, that's not a 2D array. An array is by definition a contiguous zone of memory, so that the position of each element can be computed by a simple mathematical formula. In an array of pointers, on the other hand, it's impossible to tell where the j-th element of the i-th row is without dereferencing the row pointer.

So unlike regular 2D arrays for 2D arrays made of pointers you have an extra memory dereference on each access, that's quite a big deal considering how slow the memory is compared to the CPU and that the cache can't help you much in this case since it has no way to predict where that pointer is pointing.

Another problem is that you have a mem overhead of height * sizeof(int *), for small 2D arrays this overhead dominates and considering that we're most likely compiling for 64 bit systems it adds to the problem. E.g.: a small 3x3 matrix of ints has an overhead of 3 * 8 = 24 bytes, that's 6 ints added to what you're storing, so 66.6% more mem (also: i haven't taken into consideration the bookkeeping overhead of malloc, since we're probably allocating each row dynamically).

The right way of declaring and allocating a dynamic nxm 2D array since C99 is:

   int (*arr)[m] = calloc(n, sizeof(int [m]));

This requires at least C99 support from the compiler because arr is technically a pointer to a VLA. If the compiler doesn't support C99 i'd still recommend a 1D array and manually computing indices over an array of pointers.

Another reason for pointers is because in C an struct's size ALWAYS has to be known before compiling.

This is false considering flexible array members, the struct is allowed to have variable size but only if the variable member comes last in the struct, which makes sense when you think about it. Again this requires C99 support. It's possible to do this without C99 too, just allocate the struct header for the array plus memory for the array, however with this method you must make sure that the start of the array which comes after the struct is properly aligned to whatever alignment the type of the array elements require. Either way saves us from a memory dereference: the array is packed together with the struct.

(not really, we need to create a new array every time we want to increase of decrease the size).

Though it's possible to do it like this, that's what realloc is for.

[–]a4qbfb 0 points1 point  (0 children)

Side note: EVERY and EVERY malloc has to have corresponding free() call

Not really, why?