I'm trying to grasp the differences between these three declarations:
char p[5];
char *p[5];
char (*p)[5];
I'm trying to find this out by doing some tests, because every guide of reading declarations and stuff like that has not helped me so far. I wrote this little program and it's not working (I've tried other kinds of use of the third declaration and I've ran out of options):
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void) {
char p1[5];
char *p2[5];
char (*p3)[5]; 开发者_JAVA百科
strcpy(p1, "dead");
p2[0] = (char *) malloc(5 * sizeof(char));
strcpy(p2[0], "beef");
p3[0] = (char *) malloc(5 * sizeof(char));
strcpy(p3[0], "char");
printf("p1 = %s\np2[0] = %s\np3[0] = %s\n", p1, p2[0], p3[0]);
return 0;
}
The first and second works alright, and I've understood what they do. What is the meaning of the third declaration and the correct way to use it?
Thank you!
The third is a pointer to an array of 5 chars, whereas the second is an array of 5 pointers to char.
Imagine it like this:
________ _____________________
|0x7777| -------> | H | e | l | l | o |
|______| |_0_|_1_|_2_|_3_|_4_|
p ^
|
0x7777
Whereas the second one looks like that:
"abc" "def" "ghi" "jkl" "mno"
^ ^ ^ ^ ^
| | | | |
____________________________________
|0x9999|0x7777|0x3333|0x2222|0x6666|
|___0__|___1__|___2__|___3__|___4__|
p
This is one of the cases where understanding the difference between pointers and arrays is crucial. An array is an object whose size is the size of each of its elements times the count, whereas a pointer is merely an address.
In the second case, sizeof(p)
will yield 5 * the_size_of_a_pointer
.
In the third case, sizeof(p)
will yield the_size_of_a_pointer
, which is usually 4
or 8
, depending on the target machine.
It's a pointer to an array of chars. It is explained in the C FAQ. In the future, when you don't understand a declaration, use cdecl
or cdecl(1)
.
char p[5]; // p is a 5-element array of char
char *p[5]; // p is a 5-element array of pointer to char
char (*p)[5]; // p is a pointer to a 5-element array of char
C declaration syntax is built around the types of expressions, not objects. The idea is that the form of the declaration matches the form of the expression as it would appear in the code.
In the cases above, we're dealing with arrays. In the first case, p
is an array of char
; to access a particular character value, we would simply index into the array:
val = p[i];
The type of the expression p[i]
is char
, thus the declaration of p
is char p[5]
.
In the next case, p
is an array of pointers to char; to access the value, we index into the array and dereference the result:
val = *p[i];
Postfix operators like []
have a higher precedence than unary operators like *
, so the above is parsed as
val = *(p[i]);
The type of the expression *p[i]
is char
, thus the declaration of p
is char *p[5]
.
In the final case, p
is a pointer to an array of char, so to access a char value we have to dereference the array pointer and then subscript into the result:
val = (*p)[i];
Because []
has higher precedence than unary *
, we have to use parentheses to explicitly group *
with p
(as opposed to p[i]
). Again, the type of the expression (*p)[i]
is char
, so the declaration of p
is char (*p)[5]
.
EDIT
Pointers to arrays show up in the following contexts:
You're explicitly taking the address of an N-dimensional array:
Note that while the expressionsint x[10]; int (*px)[10] = &x;
x
and&x
yield the same value (the address of the first element of the array), they have different types (int *
vsint (*)[10]
).You're dynamically allocating an array-type object:
int (*px)[10] = malloc(sizeof *px);
An N-dimensional array expression "decays" into a pointer to an (N-1)-dimension array:
int x[10][20]; foo(x); ... void foo(int (*px)[20]){...}
char (*p3)[5];
actually declares a pointer to an array of 5 char
. It means it should point to a pointer that points to an array of 5 char
. It doesn't allocate 5 of anything, just a pointer, and it should point to something that points to 5 char
.
So, the correct use is:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void) {
char p1[5];
char *p2[5];
char (*p3)[5];
strcpy(p1, "dead");
p2[0] = (char *) malloc(5 * sizeof(char));
strcpy(p2[0], "beef");
p3 = &p1;
printf("p1 = %s\np2[0] = %s\np3 = %s\n", p1, p2[0], *p3);
return 0;
}
If you want to access a single position of that p1 string using p3 to access it, you must do (*p3)[2]
, for example. It'll access the third position. That is because you first must transform p3 into p1 (the (*p3)
dereferences before doing the position arithmetics) and then access the third position of that address (pointed by the dereferenced pointer).
精彩评论