11

When I read books about C language, the two level pointer bothered me a lot.

char s[5][5];
char *s[5];
char (*s)[5];

so what is the difference between them?

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
storen
  • 1,025
  • 10
  • 22

4 Answers4

17

In C, it is better to speak out the declaration. Then, it becomes intuitive. For this, you follow the right-left convention. Here is how it goes:

char *s[5];

How do you speak it? For that you start at the right of the variable name s and then go to the left. So you start by saying "s is a/an", On the right, you see a [] and you say "s is an array ... ". And then you go to the left and see the *, and say "s is an array of pointers." And that is what it is. It si an array of 5 pointers. You can store different pointers in this array.

Now for the other one:

char (*s)[5];

You start the same way. "s is a/an", and then look at the (). Anything within the () is bound to s closer than anything outside. So the * is more closely bound with s than []. So You now say, "s is a pointer ..." and now you go out of the parenthesis and see the []. So you continue, "s is a pointer to an array". And that is exactly what it is. It is a pointer, which will point to the first element of an array.

Now follow the same logic and try to guess what the following will be:

int (*callme)(int a, int b)
int (*callme[10])(int a, int b)

Hint, the last one can be used to create lookup tables for functions.

Edit:

As mentioned in the comments, there is also a char in the beginning. I have never ben able to figure out an easy way of speaking this, but is generally clear from the context. For example, in the first example, the char defines the type of the array, while in the second example, it defines pointer. In the exercises I have posted, the int defines the type for the return values of the functions. Generally with definitions such as these, there will be exactly one item with the undefined type. And thats how I figure out where the type goes.

Cœur
  • 37,241
  • 25
  • 195
  • 267
ssm
  • 5,277
  • 1
  • 24
  • 42
  • You forgot to include `char`; `char *s[5]` is not an array of 5 “different pointers” of any type, it is specifically an array of 5 pointers *to `char`*. – Dour High Arch Nov 20 '14 at 02:53
  • That is true. I should have mentioned that. – ssm Nov 20 '14 at 02:54
  • I don't think it's fully correct to say `()` has greater precedence. Maybe you meant the presence of parentheses may alter the *binding* of complicated declarators. –  Nov 20 '14 at 02:59
  • It's worth pointing out that neither `a` or `b` are necessary to the declarations. `(int, int)` is sufficient. – David C. Rankin Nov 20 '14 at 03:02
  • Binding is definitely better here. My english isnt the best. Thanks! – ssm Nov 20 '14 at 03:03
  • I take it back. [How are (complex) declarations parsed in terms of precedence and associativity?](https://stackoverflow.com/questions/24685173/how-are-complex-declarations-parsed-in-terms-of-precedence-and-associativity) suggests that precedence does apply here. –  Nov 20 '14 at 03:08
  • Precedence and associativity is definitely how we look at the rules but the result is still the way in which the binding takes place. I do actually like the word very much. – ssm Nov 20 '14 at 03:11
  • can you tell me more about the lookup tables for functions? `int (*callme[10])(int a, int b)` how to use this ? – storen Nov 21 '14 at 01:52
  • You can look up what the `interrupt vector table` is. You can simulate that for your error processing needs. You can also use that if you are programming a state machine (a robot, the turtle in Turtle Graphics, a simulation of a simple processor) which has a list of simple primitive commands, which you can store in an array, and then use an array of numbers for making a complex commands. – ssm Nov 22 '14 at 00:42
  • In a lot of GUI work (in the older days) different GUI events would provide different numbers, and you would have to match numbers to functions. This is also a place where you would be able to use this function. – ssm Nov 22 '14 at 00:42
  • So in summary, any place where you would use a lot of if conditions for selecting from a largish function list, you can use an array of pointers to functions. It is a little difficult to give examples in comments, but I am sure you can look up examples for `arrays of pointers to functions` in google. – ssm Nov 22 '14 at 00:44
8
  • first is 2 dimensional array of char
  • second is array of pointer to char
  • third is pointer to an array of char
missellorin
  • 389
  • 2
  • 5
  • 23
3

While declaration was covered, perhaps differences in usage should also be pointed out:

char s[5][5]; --

  • s points to an area of allocated memory (heap if global, stack if local),
  • you may safely write up to 25 char values at s[0][0] .. s[4][4] (or at s[0] .. s[24]),
  • sizeof(s) == 25.

char *s[5]; --

  • s points to an area of allocated memory (heap if global, stack if local),
  • you may safely write up to 5 pointer values at s[0] .. s[4],
  • sizeof(s) == 40 (*).

char (*s)[5]; --

  • s does not point to any allocated memory -- it's merely an uninitialized pointer at this point,
  • you may safely write one pointer value at &s,
  • sizeof(s) == 8 (*).

(*) note: assuming a 64-bit architecture.

Community
  • 1
  • 1
xbug
  • 1,394
  • 1
  • 11
  • 18
3

1.char s[5][5];
Here s is two dimensional array with 5 rows and 5 columns. Where in this 5 rows and 5 columns you will save element of type character.

2.char *s[5]; s is a one dimensional array with 5 elements each element is of type pointer to character.

3.char (*s)[5]; s is a pointer here not array. S points to a array of characters. for eg.

char arr[5][5]; char(*s)[5]; s = arr;

s[0][0] will be same as array of arr[0][0]

dido
  • 29
  • 3
  • Is `char(*s)[5]`just a pointer? are there some difference between `char *s`,`char (*s)[5]` and `char (*s)[10]`? – storen Nov 21 '14 at 01:41
  • @storen Yes char(*s)[5] is just a pointer. But it is a pointer to an array of char. For Eg: 1. `char(*s)[5]; char arr[2][5]; s = arr;` In this s is pointing to an array of 5 elements which is first row of arr. If you do s++ then s points to second row of arr. 2. 'char *s; char arr[5]; s = arr; Here s points to first element of the array which is character. If you do s++ it points to next character` – dido Nov 21 '14 at 05:14
  • but I want to know how the compiler know this pointer's type is int,the other is char? when we define a `int * a` type,does the compiler not only store the value `a`,but also store the type of the `a`, so it may has some extra memory expense? – storen Nov 22 '14 at 01:19