c - 为什么 C 程序在取消引用数组指针时会崩溃?

标签 c windows pointers mingw double-pointer

我有一个简单的 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 变量成为“整数数组的地址”,你实际上需要一个更微妙(和神秘)的声明。

这会起作用:

int (*ptr)[10] = &test;

因为它声明,当取消引用时(即当您实际使用表达式*ptr时),它将是一个数组(包含 10 个元素)。

在某些方面,声明的结构有点类似于 pointers-to-functions 的结构。 .

编辑:在第二种情况下,test是一个普通的旧指针(通过malloc调用为其分配了一个值);因此,它本身就是一个变量,其地址可以被获取(正如您的 int **ptr = &test; 行所做的那样 - 正确)。

但是,在第一种情况(“固定”数组)中,test 引用一 block 内存;在许多方面,这可以用作指向第一个元素的指针(例如,就像在函数调用中一样)。但是编译器可以为“第一个元素的地址的地址”分配什么值?这就是在本例中使用 &test 尝试分配失败的原因。

但是,根据上一段,您有权询问编译器如何使用代码确定 &test 的值(分配给 ptr)在这个答案中给出?好吧,如果您将以下行添加到您的程序中:

printf("%p %p\n", test, &test);

您将看到 test&test (您可以将 &test 更改为 ptr - 输出将为相同)具有完全相同的值!因此,使用这个“神秘”声明,您可以为编译器提供足够的信息来了解如何处理“数组指针” - 基本上,它有点“忽略”(或绕过)第一级解引用,最终得到地址数组的第一个元素(按原样)。

关于c - 为什么 C 程序在取消引用数组指针时会崩溃?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59923746/

相关文章:

c++ - 将 dword 的 void* 表示形式转换为 wstring

c - 如何将此结构放入动态分配的空间中?

在c中更改int数组中的值

c++ - weak_ptr - 取消引用 - 如果过期则抛出

c - 我尝试添加链接列表时遇到问题,但调试器说无法访问临时内存

C 链表查找函数

c++ - printf 与 cstdio 和 iostream 在汇编级别上的差异

c - 括号运算符说明

windows - 如何在 Windows 上安装 scikits.audiolab 0.11.0

IntelliJ Idea 中的 Windows 深色标题栏?