Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what is `int *userMask[3][4]` pointing to?

Tags:

arrays

c

pointers

I am modifying some code and came across a declaration that I am having trouble understanding:

int *userMask[3][4] = {0};

What exactly is this pointing to? Is it a matrix where every element is a pointer? Or is it pointing to a matrix of size [3][4]?

Thanks


I guess my question is how userMask[2][maskElement][user] can work when it is declared as int. Wouldn't userMask have to be int[] for that to work properly? I must not be understanding this right...

On a side note, thanks for your suggestion about cdecl Robert. However, does anyone know how to use it in an XP command prompt? All I can get is syntax error :(

like image 573
Tim Avatar asked Sep 10 '25 16:09

Tim


1 Answers

Short answer

Given userMask is declared as

int *userMask[3][4];

then userMask has type int*[3][4]. It's a 2d array of pointers to int. The size of the outer dimension is 3, the size of the inner dimension is 4. Really that is nothing more than a 3-element 1d array which element type is another 4-element 1d array which element type is int*.

Steps explained

So if you do

userMask[2][maskElement][user]

then essentially with the first two indices you pick the particular pointer out of the 2d array:

int * p = userMask[2][maskElement];

then you pick an int somewhere offset from that pointer by doing

p[user]

now that code is all in userMask[2][maskElement][user].

Valid C Code

To do it step by step with valid c code (don't worry if you don't understand everything yet in the following):

int * userMask[3][4] = { { 0 } };
int ** pa = userMask[2]; /* int*[4] becomes int** implicitly */
int * pi = pa[maskElement];
int i = pi[user];

assert(i == userMask[2][maskElement][user]);

Difference between Arrays and Pointers

So i think i show you something important. The array above does not contain pointers to arrays. Lets look how different they behave, which many c programmers don't expect:

int array[5][4][3];
/* int[4][3] implicitly converts to int(*)[3] (pointer to first element) */
int (*parray)[3] = array[0]; 
int ** pint = (int**) array[0]; /* wrong!! */

Now, what will happen if we do parray[1] and pint[1] ? The first will advance parray by sizeof(int[3]) bytes (3 * sizeof(int)), the second will advance by only sizeof( int* ) bytes. So actually while the first gives you the correct array array[0][1], the second will give you ( char * )array[0] + sizeof( int* ), which is somewhere we don't really want it to be. But grabbing the wrong offset is not all about it. Because it doesn't know an array is accessed, it will try to interpret what is at pint[1] as an int*. Say your array was initialized with 0x00. Then it will do the next index step based off address 0x00 (Doing pint[1][0] for example). Oh noes - utterly undefined behavior! So it's really important to stress the difference.

Conclusion

This was more than you asked for, but I think it's quite important to know these details. Especially if you want to pass 2d arrays to functions then this knowledge is really useful.

like image 179
Johannes Schaub - litb Avatar answered Sep 12 '25 14:09

Johannes Schaub - litb