为什么在取消引用指向数组的指针时 C 程序会崩溃?
Why does C program crash when dereferencing pointer to an array?
我有一个简单的C代码:
int main()
{
int test[10] = {1,2,3,4,5,6,7,8,9,10};
int **ptr = &test;
printf("%d\n", (*ptr)[0]);
return 0;
}
一到printf
行就崩溃了:
Process returned -1073741819 (0xC0000005) execution time : 0.865 s
在 Ubuntu 上编译代码时,它给了我警告:
test.c:8:17: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
int **ptr = &test;
但是,如果我改为在堆上动态分配内存,则代码有效:
int main()
{
int *test = malloc(sizeof(int)*10);
for (int i = 0; i < 10; i++) {
test[i]=i;
}
int **ptr = &test;
printf("%d\n", (*ptr)[1]);
return 0;
}
请给我解释一下,为什么当数组在堆上而不是在堆栈上时代码可以工作?
为了让您的 ptr
变量成为 "address of an array of integers" 您实际上需要一个更微妙(和神秘)的声明。
这会起作用:
int (*ptr)[10] = &test;
正如它声明的那样,当取消引用时(即当您实际 使用 表达式 *ptr
时),它将是一个数组(包含 10 个元素)。
在某些方面,声明的结构有点像 pointers-to-functions。
编辑:在你的第二种情况下,test
是一个普通的旧指针(由 malloc
调用分配给它的值);因此,它本身就是一个 变量,其地址可以被获取(就像你的 int **ptr = &test;
行一样 - 正确)。
但是,在第一种情况下('fixed'数组),test
指的是一块内存;在许多方面,这可以 用作 作为指向第一个元素的指针(例如,就像在函数调用中一样)。但是编译器可能会为 "address of the address of the first element?" 分配什么值?这就是在这种情况下使用 &test
尝试分配失败的原因。
但是,根据上一段,您有权询问编译器如何使用此答案中给出的代码确定 &test
的值(分配给 ptr
) ?那么,如果您将以下行添加到您的程序中:
printf("%p %p\n", test, &test);
您将看到 test
和 &test
(您可以将 &test
更改为 ptr
- 输出将相同)具有 同值!因此,使用此 'arcane' 声明,您为编译器提供了足够的信息以了解如何处理 "array pointer" - 基本上,它有点 'ignores' (或绕过)第一级取消引用,以数组第一个元素的地址结束(按原样)。
我有一个简单的C代码:
int main()
{
int test[10] = {1,2,3,4,5,6,7,8,9,10};
int **ptr = &test;
printf("%d\n", (*ptr)[0]);
return 0;
}
一到printf
行就崩溃了:
Process returned -1073741819 (0xC0000005) execution time : 0.865 s
在 Ubuntu 上编译代码时,它给了我警告:
test.c:8:17: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
int **ptr = &test;
但是,如果我改为在堆上动态分配内存,则代码有效:
int main()
{
int *test = malloc(sizeof(int)*10);
for (int i = 0; i < 10; i++) {
test[i]=i;
}
int **ptr = &test;
printf("%d\n", (*ptr)[1]);
return 0;
}
请给我解释一下,为什么当数组在堆上而不是在堆栈上时代码可以工作?
为了让您的 ptr
变量成为 "address of an array of integers" 您实际上需要一个更微妙(和神秘)的声明。
这会起作用:
int (*ptr)[10] = &test;
正如它声明的那样,当取消引用时(即当您实际 使用 表达式 *ptr
时),它将是一个数组(包含 10 个元素)。
在某些方面,声明的结构有点像 pointers-to-functions。
编辑:在你的第二种情况下,test
是一个普通的旧指针(由 malloc
调用分配给它的值);因此,它本身就是一个 变量,其地址可以被获取(就像你的 int **ptr = &test;
行一样 - 正确)。
但是,在第一种情况下('fixed'数组),test
指的是一块内存;在许多方面,这可以 用作 作为指向第一个元素的指针(例如,就像在函数调用中一样)。但是编译器可能会为 "address of the address of the first element?" 分配什么值?这就是在这种情况下使用 &test
尝试分配失败的原因。
但是,根据上一段,您有权询问编译器如何使用此答案中给出的代码确定 &test
的值(分配给 ptr
) ?那么,如果您将以下行添加到您的程序中:
printf("%p %p\n", test, &test);
您将看到 test
和 &test
(您可以将 &test
更改为 ptr
- 输出将相同)具有 同值!因此,使用此 'arcane' 声明,您为编译器提供了足够的信息以了解如何处理 "array pointer" - 基本上,它有点 'ignores' (或绕过)第一级取消引用,以数组第一个元素的地址结束(按原样)。