“地址”(&)被忽略的数组/地址是gcc吗?

我是入门编程课程的助教,有些学生犯了这种错误:

char name[20]; scanf("%s",&name); 

这并不奇怪,因为他们正在学习……令人惊讶的是,除了gcc警告之外,代码也起作用(至少这部分)。 我一直在努力理解,并编写了以下代码:

 void foo(int *v1, int *v2) { if (v1 == v2) printf("Both pointers are the same\n"); else printf("They are not the same\n"); } int main() { int test[50]; foo(&test, test); if (&test == test) printf("Both pointers are the same\n"); else printf("They are not the same\n"); } 

编译和执行:

 $ gcc test.c -g test.c: In function 'main': test.c:12: warning: passing argument 1 of 'foo' from incompatible pointer type test.c:13: warning: comparison of distinct pointer types lacks a cast $ ./a.out Both pointers are the same Both pointers are the same 

谁能解释为什么他们没有什么不同?

我怀疑是因为我无法获取数组的地址(因为我不能拥有& &x ),但在这种情况下代码不应该编译。

编辑:我知道数组本身与第一个元素的地址相同,但我认为这与此问题无关。 例如:

 int main() { int a[50]; int * p = a; printf("%d %d %d\n", p == a, p == &a[0], &p[0] == a); printf("%d %d %d\n", p == &a, &p == a, &p == &a); } 

打印:

 $ ./a.out 1 1 1 1 0 0 

我不明白为什么第二行以1开头。

在您的示例中,数组test是一个50个ints的块。 所以它看起来像这样:

 | int | int | ... | int | 

将一元&运算符应用于数组时,将获得该数组的地址。 就像你将它应用于其他任何东西一样,真的。 所以&test是一个指向50个ints块的指针:

 (&test) -----------> | int | int | ... | int | 

指向50个int的数组的指针具有int (*)[50]类型 – 这就是&test的类型。

当你在任何不是sizeof或unary- & operator的操作数的地方使用名称test时,它被评估为指向其第一个元素的指针。 因此,传递给foo()test将计算为指向test[0]元素的指针:

 (test) -----------------\ v (&test) -----------> | int | int | ... | int | 

您可以看到这两者都指向相同的地址 – 尽管&test指向整个数组,而test指向数组的第一个元素(仅显示这些值具有的不同类型 )。

实际上,它们是不同的,它们至少没有相同的类型。

但是在C中,数组的地址与数组中第一个元素的地址相同,这就是为什么“它们没有不同”,基本上,它们指向同一个东西。

如果你定义一个像这样的数组

 char name[20]; 

name可以隐式转换为char* ,但&name的类型为char (*)[20] (指向20个字符的数组的指针)。 地址是一样的。

检查(&name + 1)的地址。 它的forms&namesizeof(char [20])

在大多数情况下,数组的名称将计算其初始元素的地址。 两个例外是当它是sizeof或一元&的操作数时。

一元&给出其论点的地址。 数组的地址与其初始元素的地址相同,因此(void*)&array == (void*)array将始终为true。

当转换为指向其初始元素的指针时, array的类型为T *&array的类型是T (*)[n] ,其中n是数组中元素的数量。 从而,

 int* p = array; // Works; p is a pointer to array[0] int* q = &array; // Doesn't work; &array has type int (*)[10] int (*r)[10] = &array; // Works; r is a pointer to array 

我相信这是一个gcc优化。 想一想。

  • &test指向test地址
  • test指向test的第一个元素或&test[0]
  • [0]* (大部分)相同*

所以根据这个&test 可能 &test不同,但gcc优化了这一点,因为在这一点上没有额外的间接级别的目的。