人
我正在努力理解这三个声明之间的差异:
char p[5];
char *p[5];
char (*p)[5];
我试图通过做一些测试来找到它,因为阅读声明和类似的东西的每个指南到目前为止都没有帮助我。我写了这个小程序并且它没有工作(我已经尝试了其他类型的第三个声明的使用,我已经用完了选项):
#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[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;
}
第一个和第二个工作没问题,我明白他们做了什么。第三个声明的含义是什么,使用它的正确方法是什么?
谢谢!
答案 0 :(得分:13)
第三个是指向5个字符数组的指针,而第二个是指向char的5个指针的数组。
想象一下:
________ _____________________
|0x7777| -------> | H | e | l | l | o |
|______| |_0_|_1_|_2_|_3_|_4_|
p ^
|
0x7777
而第二个看起来像那样:
"abc" "def" "ghi" "jkl" "mno"
^ ^ ^ ^ ^
| | | | |
____________________________________
|0x9999|0x7777|0x3333|0x2222|0x6666|
|___0__|___1__|___2__|___3__|___4__|
p
这是了解指针和数组之间差异的关键之一。数组是一个对象,其大小是每个元素的大小乘以计数,而指针只是一个地址。
在第二种情况下,sizeof(p)
将产生5 * the_size_of_a_pointer
。
在第三种情况下,sizeof(p)
将产生the_size_of_a_pointer
,通常为4
或8
,具体取决于目标计算机。
答案 1 :(得分:4)
答案 2 :(得分:4)
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声明语法是围绕表达式的类型构建的,而不是对象。这个想法是声明的形式与表达式的形式相匹配,就像在代码中出现一样。
在上面的例子中,我们正在处理数组。在第一种情况下,p
是char
的数组;要访问特定的字符值,我们只需索引到数组:
val = p[i];
表达式p[i]
的类型为char
,因此p
的声明为char p[5]
。
在下一种情况下,p
是指向char的指针数组;要访问该值,我们将索引到数组中并取消引用结果:
val = *p[i];
像[]
这样的后缀运算符的优先级高于*
之类的一元运算符,所以上面的解析为
val = *(p[i]);
表达式*p[i]
的类型为char
,因此p
的声明为char *p[5]
。
在最后一种情况下,p
是一个指向char数组的指针,因此要访问char值,我们必须取消引用数组指针然后下标到结果中:
val = (*p)[i];
由于[]
的优先级高于一元*
,因此我们必须使用括号将*
与p
明确分组(而不是p[i]
)。同样,表达式(*p)[i]
的类型为char
,因此p
的声明为char (*p)[5]
。
修改强>
指向数组的指针显示在以下上下文中:
您明确地获取了N维数组的地址:
int x[10];
int (*px)[10] = &x;
请注意,虽然表达式x
和&x
会产生相同的 value (数组的第一个元素的地址),它们具有不同的类型(int *
vs int (*)[10]
)。
您正在动态分配数组类型对象:
int (*px)[10] = malloc(sizeof *px);
N维数组表达式“衰变”为指向(N-1)维度数组的指针:
int x[10][20];
foo(x);
...
void foo(int (*px)[20]){...}
答案 3 :(得分:3)
char (*p3)[5];
实际上声明了一个指向5 char
数组的指针。这意味着它应该指向一个指向5 char
数组的指针。它不会分配5个任何东西,只是指针,它应该指向指向5 char
的东西。
所以,正确的用法是:
#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;
}
如果要使用p3访问该p1字符串的单个位置以访问它,则必须执行(*p3)[2]
。它将进入第三个位置。这是因为你首先必须将p3转换为p1(在进行位置算术之前进行(*p3)
解除引用),然后访问该地址的第三个位置(由解除引用的指针指向)。