在C语言中,当变量是指针时符号混淆



我对C中的符号感到困惑,当我有一个指针变量f指向struct X定义为:

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]

我不明白的是c.e[0].a[0]部分。

我不确定什么是c.e[0],然后也什么是c.e[0].a[0]。(也不确定c.e[0]是否与struct X的起始地址相差20个偏移量)。假设这里的指针是4个字节,integer是4个字节。所以int *a+int b[4]+int d= 20偏移?这是f->c.e->c.e[0]的意思吗?有f->c.e->c.e[3]吗?f->c.e->c.e[4]吗?f->c.e->c.e[5]?

我很困惑,因为通常对于指针变量说k,我总是看到k->x,k->y,k->l在变量k指向结构变量时引用结构内的变量。然而,在本例中,我看到了c.e->c.e[0].a[0]的符号。e[0].a[0]有效吗?我猜e[0]不是一个指针,因为如果它是一个指针e[0]必须始终使用->符号来指一个结构体中的变量它指向,但因为它使用(点.)而不是(箭头->),e[0].a[0]所以我猜e[0]在这种情况下是不是一个指针对吗?

然后我有点困惑,在我给定的struct X,struct Y和这里给定的指针变量fc.e[0].a[0]的含义是什么。

c.e是指向struct X的指针,所以c.e[0]c.e指向的struct X

如果c.e是指向4个struct Y的数组的第一个元素的指针,则该数组的4个元素可以被称为c.e[0]c.e[1]c.e[2]c.e[3]

对于所有的指针p,p[0]都等价于*p*(p + 0)(甚至0[p])。

在此例中,f->c.e->c.e[0].a[0]相当于f->c.e->c.e->a[0]*f->c.e->c.e->a。使用哪种语法是风格和可读性的问题。当索引为零时,使用[]的数组语法通常更具可读性,在指针指向单个对象的情况下,首选->语法。

实际的实现细节,如指针和整数大小在这里是无关的,但请记住,结构中成员的偏移量可能会受到对齐约束的影响:例如,在大多数当前64位系统中,int仍然有4个字节,但指针使用8个字节,因此struct Y中的e的偏移量必须在8的倍数上对齐,因此是8,而不是4。在de之间插入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]vs.int *)?

这是因为在底层,编译器以完全相同的方式处理它。数组名实际上是指向其第一个元素的指针,如我们在这里看到的:

void foo(int * array)
{
printf("%dn", *array); // *array and array[0] are interchangeable
}
int bar()
{
int array[5];
array[0] = 42;
foo(array);
}

所以数组可以衰减变成一个指针。语言允许使用[]运算符因为编译器实际上是用指针运算符进行翻译的:

array[0]*array相同,但更准确地说,与*(array + 0)相同。

你怎么知道你的指针是指向单个值还是指向数组的第一个值呢?好吧,没有上下文,你不能。从孤立函数的角度来看,您无法知道接受char *参数是否意味着它是字符串参数还是指向单个字符变量的指针。开发人员可以通过传递数组的大小,或者正确地命名变量(例如char * strvs.char * c),编写文档等来明确这一点。

相关内容

  • 没有找到相关文章

最新更新