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

dba*_*osa 15 c gcc pointers addressof

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

char name[20];
scanf("%s",&name);
Run Code Online (Sandbox Code Playgroud)

这并不奇怪,因为他们正在学习......令人惊讶的是,除了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");
}
Run Code Online (Sandbox Code Playgroud)

编译和执行:

$ 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
Run Code Online (Sandbox Code Playgroud)

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

我怀疑是因为我无法获取数组的地址(因为我不能拥有& &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);
}
Run Code Online (Sandbox Code Playgroud)

打印:

$ ./a.out 
1 1 1
1 0 0
Run Code Online (Sandbox Code Playgroud)

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

caf*_*caf 24

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

| int | int | ... | int |
Run Code Online (Sandbox Code Playgroud)

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

(&test) -----------> | int | int | ... | int |
Run Code Online (Sandbox Code Playgroud)

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

当你test在任何不是或者是一sizeof&运算符的操作数的地方使用这个名字时,它会被评估为指向它的第一个元素的指针.所以test你传递给它的foo()是一个指向test[0]元素的指针:

(test) -----------------\
                        v
(&test) -----------> | int | int | ... | int |
Run Code Online (Sandbox Code Playgroud)

您可以看到这两者都指向相同的地址 - 虽然&test指向整个数组,并且test指向数组的第一个元素(仅显示这些值具有的不同类型).

  • 我喜欢ascii art :)现在有了这张照片,很容易解释为什么将`1`添加到`&test`会超出数组,并且将`1`添加到`test`只会超出第一个元素. (7认同)

Sou*_*sou 9

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

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

  • @WhirlWind:不,它不依赖于系统.将address-of运算符应用于数组具有明确定义的语义 - 它必须生成数组本身的地址.该数组被定义为基类型的连续对象序列,因此数组的地址和第一个对象的地址是相同的位置(但具有不同的类型). (3认同)

Mac*_*ehl 5

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

char name[20];
Run Code Online (Sandbox Code Playgroud)

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

检查地址(&name + 1).它不同于形式&name通过 sizeof(char [20]).