In C, I know I can dynamically allocate a two-dimensional array on the heap using the following code:
int** someNumbers = malloc(arrayRows*sizeof(int*));
for (i = 0; i < arrayRows; i++) {
someNumbers[i] = malloc(arrayColumns*sizeof(int));
}
Clearly, this actually creates a one-dimensional array of pointers to a bunch of separate one-dimensional arrays of integers, and "The System" can figure out what I mean when I ask for:
someNumbers[4][2];
But when I statically declare a 2D array, as in the following line...:
int someNumbers[ARRAY_ROWS][ARRAY_COLUMNS];
...does a similar structure get created on the stack, or is it of another form completely? (i.e. is it a 1D array of pointers? If not, what is it, and how do references to it get figured out?)
Also, when I said, "The System," what is actually responsible for figuring that out? The kernel? Or does the C compiler sort it out while compiling?
In answer to your also: Both, though the compiler is doing most of the heavy lifting.
In the case of statically allocated arrays, "The System" will be the compiler. It will reserve the memory like it would for any stack variable.
In the case of the malloc'd array, "The System" will be the implementer of malloc (the kernel usually). All the compiler will allocate is the base pointer.
The compiler is always going to handle the type as what they are declared to be except in the example Carl gave where it can figure out interchangeable usage. This is why if you pass in a [][] to a function it must assume that it is a statically allocated flat, where ** is assumed to be pointer to pointer.
in memory is equal to:
To access a particular 2D array consider the memory map for an array declaration as shown in code below:
To access each element, its sufficient to just pass which array you are interested in as parameters to the function. Then use offset for column to access each element individually.
A static two-dimensional array looks like an array of arrays - it's just laid out contiguously in memory. Arrays are not the same thing as pointers, but because you can often use them pretty much interchangeably it can get confusing sometimes. The compiler keeps track properly, though, which makes everything line up nicely. You do have to be careful with static 2D arrays like you mention, since if you try to pass one to a function taking an
int **
parameter, bad things are going to happen. Here's a quick example:In memory looks like this:
exactly the same as:
But if you try to pass
array1
to this function:you'll get a warning (and the app will fail to access the array correctly):
Because a 2D array is not the same as
int **
. The automatic decaying of an array into a pointer only goes "one level deep" so to speak. You need to declare the function as:or
To make everything happy.
This same concept extends to n-dimensional arrays. Taking advantage of this kind of funny business in your application generally only makes it harder to understand, though. So be careful out there.
The answer is based on the idea that C doesn't really have 2D arrays - it has arrays-of-arrays. When you declare this:
You are asking for
someNumbers
to be an array of 4 elements, where each element of that array is of typeint [2]
(which is itself an array of 2int
s).The other part of the puzzle is that arrays are always laid out contiguously in memory. If you ask for:
then that will always look like this:
(4
sometype_t
objects laid out next to each other, with no spaces in between). So in yoursomeNumbers
array-of-arrays, it'll look like this:And each
int [2]
element is itself an array, that looks like this:So overall, you get this: