[英]notation confusion in C when variable is a pointer
当我有一个指针变量f
指向定义为的struct X
时,我对 C 中的符号感到困惑:
struct Y {
int d;
struct X *e;
};
struct X {
int *a;
int b[4];
struct Y c;
};
然后我有这个:
f->c.e->c.e[0].a[0]
我不明白的是部分ce[0].a[0]
。
我不确定ce[0]
是什么,然后ce[0].a[0]
是什么。 (也不确定ce[0]
是否与struct X
的起始地址相距 20 个偏移量)。 假设这里的指针是 4 个字节,整数是 4 个字节。 所以int *a
+ int b[4]
+ int d
= 20 偏移量? 是f->ce->ce[0]
的意思吗? 有f->ce->ce[3]
吗? f->ce->ce[4]
? f->ce->ce[5]
?
我很困惑,因为通常对于指针变量说k
,当变量k
指向结构变量时,我总是看到k->x
、 k->y
、 k->l
来引用结构中的变量。 但是在这种情况下,我看到了ce->ce[0].a[0]
的符号。 e[0].a[0]
有效吗? 我猜e[0]
不是指针,因为如果它是指针e[0]
必须始终使用->
符号来引用它指向的结构中的变量,但是因为它使用 (dot .
) 代替of (arrow ->
), e[0].a[0]
所以我猜在这种情况下e[0]
不是指针,对吧?
那么我对这里给定的struct X
、 struct Y
和给定的指针变量f
中的ce[0].a[0]
的含义有点困惑。
ce
是指向struct X
的指针,因此ce[0]
是ce
指向的struct X
。
如果ce
是指向 4 struct Y
数组的第一个元素的指针,则该数组的 4 个元素可以称为ce[0]
、 ce[1]
、 ce[2]
和ce[3]
。
对于所有指针p
, p[0]
等价于*p
或*(p + 0)
(甚至0[p]
)。
在这种情况下, f->ce->ce[0].a[0]
等价于f->ce->ce->a[0]
和*f->ce->ce->a
。 使用哪种语法是风格和可读性的问题。 当索引为或可以不为零时,使用[]
的数组语法通常更具可读性,如果是指向单个对象的指针,则首选->
语法。
实际的实现细节,例如指针和整数大小在这里无关紧要,但请记住,结构中成员的偏移量可能会受到对齐约束的影响:例如在大多数当前的 64 位系统中,一个int
仍然有 4字节,但指针使用 8 个字节,因此struct Y
中e
的偏移量必须与8
的倍数对齐,因此是8
,而不是4
。 在d
和e
之间插入 4 个填充字节。 另请注意,如果d
旨在存储由e
指向的数组中的元素数,则它可能应该使用size_t
类型定义。
混淆来自于在 C 中使用指针的多种方式。
声明一个简单的数组如下:
<type> <name>[<size>];
// More concretely
int array_of_ints[5];
// Accessing its elements is straightforward
array_of_ints[0] = 42;
但是,如果您无法提前知道尺寸怎么办? 您必须使用例如malloc
分配内存,它为您提供指向数组开头的指针:
int * array_of_ints = malloc(sizeof(int) * 5);
// Access its elements the same way as arrays declared on the stack
array_of_ints[0] = 42;
为什么相同的语法可以用于两种类型( int[5]
与int *
)?
这是因为在引擎盖下编译器以完全相同的方式对待它。 数组的名称实际上是指向它的第一个元素的指针,我们可以在这里看到:
void foo(int * array)
{
printf("%d\n", *array); // *array and array[0] are interchangeable
}
int bar()
{
int array[5];
array[0] = 42;
foo(array);
}
所以一个数组可以衰减为一个指针。 该语言允许您使用[]
运算符,因为编译器实际上使用指针算法对其进行了翻译:
array[0]
与*array
相同,但更准确地说,与*(array + 0)
相同。
那么你怎么知道你有一个指向单个值的指针还是一个指向数组第一个值的值的指针呢? 好吧,没有上下文,你不能。 从孤立函数的角度来看,您无法知道采用char *
参数是否意味着它是字符串参数或指向单个 char 变量的指针。 开发人员可以通过传递数组的大小或正确命名变量(例如char * str
与char * c
)、编写文档等方式来明确说明。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.