我是入门编程课程的助教,有些学生犯了这种错误:
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
开头。
答案 0 :(得分:23)
在您的示例中,数组test
是一个50 ints
的块。所以它看起来像这样:
| int | int | ... | int |
将一元&
运算符应用于数组时,您将获得数组的地址 。就像你将它应用于其他任何东西一样,真的。因此&test
是一个指向50 ints
(&test) -----------> | int | int | ... | int |
指向50个整数数组的指针的类型为int (*)[50]
- 这是&test
的类型。
当您在任何不是test
或一元 - sizeof
运算符的操作数的地方使用名称&
时,会将其评估为指向其第一个元素的指针。因此,传递给test
的{{1}}会计算为指向foo()
元素的指针:
test[0]
你可以看到这两个都指向同一个地址 - 尽管(test) -----------------\
v
(&test) -----------> | int | int | ... | int |
指向整个数组,&test
指向数组的第一个元素(仅显示在这些值具有的不同类型。
答案 1 :(得分:9)
实际上,它们是不同的,它们至少没有相同的类型。
但是在C中,数组的地址与地址相同 数组中的第一个元素就是“它们没有区别”的原因,基本上,它们指向同一个东西。
答案 2 :(得分:5)
如果您定义类似
的数组char name[20];
name
可隐式转换为char*
,但&name
的类型为char (*)[20]
(指向20个字符数组的指针)。地址是一样的。
检查(&name + 1)
的地址。它与&name
的{{1}}不同。
答案 3 :(得分:2)
数组的名称,在大多数情况下,将计算为其初始元素的地址。两个例外是它是sizeof
或一元&
的操作数。
一元&
给出了其参数的地址。数组的地址与其初始元素的地址相同,因此(void*)&array == (void*)array
将始终为真。
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
答案 4 :(得分:-2)
我相信这是一个gcc优化。想一想。
&test
指向test
test
指向test
或&test[0]
[0]
与*
所以根据这个&test
可以与test
不同,但是gcc会优化它,因为在这一点上没有额外的间接级别的目的。