Interpretation of Int (*A)[3]

Interpretation of int (*a)[3]

First, you mean "typedef" not "typecast" in your question.

In C, a pointer to type T can point to an object of type T:

int *pi;
int i;
pi = &i;

The above is simple to understand. Now, let's make it a bit more complex. You seem to know the difference between arrays and pointers (i.e., you know that arrays are not pointers, they behave like them sometimes though). So, you should be able to understand:

int a[3];
int *pa = a;

But for completeness' sake: in the assignment, the name a is equivalent to &a[0], i.e., a pointer to the first element of the array a. If you are not sure about how and why this works, there are many answers explaining exactly when the name of an array "decays" to a pointer and when it does not:

  • My answer to a question titled type of an array,
  • Another answer with examples of instances when the name of an array does not decay to a pointer, and
  • The answers to what is array decaying.

I am sure there are many more such questions and answers on SO, I just mentioned some that I found from a search.

Back to the topic: when we have:

int foo[2][3];

foo is of type "array [2] of array [3] of int". This means that foo[0] is an array of 3 ints, and foo[1] is an array of 3 ints.

Now let's say we want to declare a pointer, and we want to assign that to foo[0]. That is, we want to do:

/* declare p somehow */
p = foo[0];

The above is no different in form to the int *pa = a; line, because the types of a and of foo[0] are the same. So, we need int *p; as our declaration of p.

Now, the main thing to remember about arrays is that "the rule" about array's name decaying to a pointer to its first element applies only once. If you have an array of an array, then in value contexts, the name of the array will not decay to the type "pointer to pointer", but rather to "pointer to array". Going back to foo:

/* What should be the type of q? */
q = foo;

The name foo above is a pointer to the first element of foo, i.e., we can write the above as:

q = &foo[0];

The type of foo[0] is "array [3] of int". So we need q to be a pointer to an "array [3] of int":

int (*q)[3];

The parentheses around q are needed because [] binds more tightly than * in C, so int *q[3] declares q as an array of pointers, and we want a pointer to an array. int *(q[3]) is, from above, equivalent to int *q[3], i.e., an array of 3 pointers to int.

Hope that helps. You should also read C for smarties: arrays and pointers for a really good tutorial on this topic.

About reading declarations in general: you read them "inside-out", starting with the name of the "variable" (if there is one). You go left as much as possible unless there is a [] to the immediate right, and you always honor parentheses. cdecl should be able to help you to an extent:

$ cdecl
cdecl> declare p as pointer to array 3 of int
int (*p)[3]
cdecl> explain int (*p)[3]
declare p as pointer to array 3 of int

To read

int (*a)[3];

a # "a is"
(* ) # parentheses, so precedence changes.
# "a pointer to"
[3] # "an array [3] of"
int ; # "int".

For

int *a[3];

a # "a is"
[3] # "an array [3] of"
* # can't go right, so go left.
# "pointer to"
int ; # "int".

For

char *(*(*a[])())()

a # "a is"
[] # "an array of"
* # "pointer to"
( )() # "function taking unspecified number of parameters"
(* ) # "and returning a pointer to"
() # "function"
char * # "returning pointer to char"

(Example from c-faq question 1.21. In practice, if you are reading such a complicated declaration, there is something seriously wrong with the code!)

When int a[3] has been defined, is there any difference between int* b = a and int (*c)[3] = &a

Both b and c point to the same memory but the difference is big:

  1. These are two different types (pointer to int and pointer to an array of 3 ints)
  2. b is dereferenced to a single integer pointed by b while c is dereferenced to an array of 3 ints which means you can assign an integer to *b (*b = 10;) but you can't do the same for c (but only with specified index (*c)[0] = 10)
  3. Pointer arithmetic is also different b + 1 will increase the value of b by sizeof(int) while c + 1 will increase the value of c by 3*sizeof(int)

If they're different, when should I use one way instead of choosing
the other one?

As any other type in C, it should be used based on your needs and application. Most commonly used is the int *b; option since it gives you more flexibility. With such pointer you can handle array of any size, it is more commonly used and more readable. While pointer to an array binds you to an array of pre-defined size, its syntax is less readable (in my opinion) and thus will be harder to review/debug the code. In my experience I've never seen a production code which uses pointer to an array but this doesn't mean you cannot use it if you find any advantage of it in your application.

Not understanding the difference between *p[3] and (*p)[3]

int a[3] = {1,2,3};
int (*p)[3];
p=&a;
printf("%d %d %d",(*p)[0],(*p)[1],(*p)[2]);

At first you will have to understand the difference between a and &a. Value of both a and &a will be same. But There is huge difference in the meaning of them. Here a represent the first element of an array i.e. &a[0] and &a represent the whole or complete array. If you do a+1 you will find the address of next element in the array i.e. &a[1] but if you perform &a+1, it will give the next address to the complete array i.e. here &a+1 = &a[2]+1. Thus here p=&a means you have assigned the address of an array of size 3 to a pointer p.

What is difference between int (*p)[3] and int *p[3]?

int *p[3];  // type of p is int *[3]

declares p as an array 3 of int * (i.e., an array of three int *)

and

int (*p)[3];  // type of p is int (*)[3]

declares p as a pointer to an array 3 of int (i.e., a pointer to an array of three int)

What is the meaning of int (*pt)[5] in c

int *arr[5]

arr is array of 5 pointers

int (*arr)[5]

arr is a pointer to an array of 5 integer elements

Check the code below:

int a[5] = { 1,2,3,4,5};
int (*arr)[5] = &a;
printf("%d",(*arr)[2]);

Now the array element can be accessed like

(*arr)[i] not *arr[i]

What is the meaning of char *a[3]?

This one works perfectly and can take indefinite amount of string
length. Why is that?

Both of them are undefined behavior. It's just that undefined behavior isn't guaranteed to fail in any specific fashion, it can appear to work properly and then cause problems in different circumstances (which could include running the same program again on the same machine). On my machine, if I run this code, it crashes. The underlying issue is the same: a[0] is uninitialized and isn't pointing anywhere valid, just like a in the first program. Either way you'll have to allocate memory for the string that you're reading in:

int main(void)
{
char *a[1];
a[0] = malloc(20);
scanf("%19s", a[0]);
printf("%s \n", a[0]);
free(a[0]);
return 0;
}

Or without dynamical memory allocation:

int main(void)
{
char a[20];
scanf("%19s", a);
printf("%s \n", a);
return 0;
}

To answer the original question in the title: char*a[3] means "declare a as and array of 3 pointers to char".

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

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.

Meaning of the following C declarations

You need to decompose them, the last two are easier:

char (*(*x())[])();
char (*x)(); // A pointer to a function returning char with any args.
char (*x[])(); // An array of such pointers.
char (*(*x)[])(); // A pointer to such array.
char (*(*x())[])(); // A function returning such pointer: A function returning a pointer to
// an array of pointer to function returning char with any args.

char(*(*x[3])())[5];
char(*x)(); // A pointer to a function returning char with any args.
char(*x)()[5]; // A pointer to a function returning an array of 5 chars (any args).
char((*x)())[5]; // Same as above.
char(*(*x)())[5]; // A pointer to a function returning a pointer to an array of 5 chars.
char(*(*x[3])())[5]; // An array of 3 of these pointers.

void (*b(int, void (*f)(int)))(int);
X b(int, void(*f)(int)); // A function returning X and taking an int and a pointer to
// a function f taking an int and returning nothing.
void (*b())(int); // A function taking nothing and returning a pointer to a function
// taking and int and returning nothing.
void (*b(int, void (*f)(int)))(int); // Combination of the two above, a function taking and
// an int and a pointer to a function f and returning
// a pointer to a function.

void(*ptr)(int(*)[2], int(*)(void)); // This one is easier:
void(*ptr)(); // A pointer to a function with no args and returning nothing.
void(*ptr)(int(*)[2], int(*)(void)); // A pointer to a function returning nothing and taking:
// - A pointer to an array of 2 int
// - A pointer to a function returning int with no args.

You can check all these using cdecl.org.

Some tips when you need to decompose such declarations:

  1. A function returning a pointer to an array or to a function is not common, but you have to know how to declare them:
int (*f())[5];   // A function returning a pointer to an array of 5 int.
int (*f())(int); // A function returning a pointer to a function int (*)(int).

Notice that within these 2 declarations, part of the return type appears after the parameter list of the function, which is why those are often confusing when you encounter them for the first time.


  1. You can always remove the name of parameters in function:
int b(void(*f)(int), int(*p)[2]);
int b(void(*)(int), int(*)[2]); // Same as above

  1. If the name is directly next to a square-bracket, e.g. x[N], then it is an « array N of something »:
int (*x[3])();  // x is an array of 3 pointers to functions int(*)().
int (*x[4])[5]; // x is an array of 4 pointers to array of 5 int.
int (*x)[4]; // x is not an array.

What is the meaning of int(a[::-1]) in Python?

Assuming a is a string. The Slice notation in python has the syntax -

list[<start>:<stop>:<step>]

So, when you do a[::-1], it starts from the end towards the first taking each element. So it reverses a. This is applicable for lists/tuples as well.

Example -

>>> a = '1234'
>>> a[::-1]
'4321'

Then you convert it to int and then back to string (Though not sure why you do that) , that just gives you back the string.



Related Topics



Leave a reply



Submit