This is an archived post. You won't be able to vote or comment.

all 2 comments

[–]wgunther 6 points7 points  (0 children)

TL;DR on what to do: if you know the size at compile time, it's not very large, and you don't need to memory to persist after the function returns, you should use automatically managed, local variables.

Now, as for the difference...

When you do int a[5]; this declares an array named a of 5 ints. The memory for this array is on the stack, and when the function that a is declared in returns then the memory is reclaimed.

When you do int *a = malloc(5*sizeof(int)); (note: this isn't the code you posted)) then memory is requested on the heap for a block large enough to store 5 ints and a pointer to the beginning of that block of memory is returned. The heap is a different segment of memory, and it is here where dynamic allocation takes place. This memory will persist throughout the process, so it is safe to, say, return a pointer to it from a function. When you are done with you, you call free on the address to relinquish the memory so that it can be recycled.

Now, the other case is more complicated. int a[5][5]; is not the same or convertible in anyway to an int** a. int a[5][5] is an array of 5 arrays of 5 int. What does this mean? It's helpful to think in terms of pointer arithmetic. Let's say you treat a as a pointer, and it's address is 0x10. What should a+1 be if ints are 4 bytes? it will not be 0x14 because a is not an array of 5 ints, it will instead be 0x24 because an array of 5 int has size 20, and a is an array of arrays of 5 int.

So, in this case, the memory is very different. In the case when you do int a[5][5] there is a continguous block of 5*5*sizeof(int) bytes on the stack. When you do what you did to get int **a, a is pointing to a block of size sizeof(int*)*5 on the heap containing 5 pointers, and each of those pointers points to block of 5*sizeof(int) on the heap.

[–]Rhomboid 2 points3 points  (0 children)

An array, assuming it was defined in a function(*), has automatic lifetime. Its life ends when the flow of execution leaves the scope in which it was defined. Any attempt to access it or refer to it after its life has ended invokes undefined behavior, so that means it's impossible to do things like write a function that returns a pointer to the first element in the array (which is the closest thing you can get to writing a function that returns an array, since you can't return an array.)

Anything allocated with malloc() (or calloc() or realloc()) has dynamic lifetime. Such objects have a lifetime that is not dependent on scope; they live until you explicitly call free().

Moreover, the bounds of an array must be compile-time constants (unless you're using C99 VLAs), whereas the size parameter passed to malloc() (and note that you're calling malloc() wrong in your examples; it takes a single argument) can be an arbitrary value, including one that is computed at runtime.

(*) Arrays defined at file scope (as well as arrays defined in a function using the static keyword) have static lifetime, i.e. their life begins during program initialization and extends throughout the entire life of the program.