C数组指针问题

dha*_*0us 2 c arrays pointers

我认为数组变量不能在C中更改,即数组的基址是不可更改的,但下面的代码与我的假设相矛盾:

#include <stdlib.h>
#include <stdio.h>

void changeArray(int **a)
{
   *a = malloc(sizeof(int));  
}

int main()
{
   int a[10];
   a[0] = 1;
   printf("%d\n",a[0]);
   changeArray(&a);
   printf("%d\n",a[0]);
}
Run Code Online (Sandbox Code Playgroud)

此代码打印:

1
6750576(some random value)
Run Code Online (Sandbox Code Playgroud)

很明显,数组的基址已被更改.这怎么可能?

Joh*_*itb 14

代码正在玩邪恶的指针游戏,没有运气.您正在将具有类型的指针传递给int(*)[10]希望指针具有类型的函数int**.您传递的指针的值为数组的"基址".

因此,当你取消引用时int**,它会在该地址处认为它得到了一个int*,即使它看起来是一个int对象.它将返回的地址写入该malloc存储单元.

回到main,打印出那个单元格.请注意,它是数组的第一个元素的,而不是数组的第一个元素的地址.所以打印的是您在被调用函数中写入的地址的整数值解释.

你做的是未定义的行为:函数想要一个int**,所以你必须给它一个int**,


以下是我认为您对此事的看法

  • 你听到有人说数组名是一个指向其第一个元素的常量指针
  • 你获取该指针的地址,抛弃任何const
  • 您乐意在指针中写入其他地址,并希望它不会崩溃
  • 您再次使用该数组,期望它现在"覆盖"malloc创建的未初始化的内存区域.

但这种观点存在缺陷.第一点是最有缺陷的,因为数组名称不是常量指针.如果第一点是正确的,那么实际上你的代码片段会更有意义.但是,在极少数情况下(sizeof,address-of),数组名称将生成一个地址值,该值在您在表达式中使用时引用其第一个元素.

因为在使用address-of时不会生成该地址值,所以您将获得指向该数组的指针(这正是您使用address-of运算符编写的).由于数组及其第一个元素具有相同的地址是有意义的,因此数组的地址恰好等于其第一个元素的地址.所以你实际上做的是写入第一个元素,而不是写入一些指针(实际上不存在).


对评论的回应

考虑当阵列的类型在实践中很重要时(在这些实验中)会发生什么.你有一个数组,其元素本身就是数组.

// array of 3 "array of 10 int"
int a[3][10];
Run Code Online (Sandbox Code Playgroud)

因此,通过a在除&和之外的表达式中使用sizeof,您将获得指向第一个元素的指针int(*)[10].这是至关重要的,因为下面写入一个偏移2*sizeof(int)*10字节的整数

a[2][0] = 1;
  // (a + 2) refers to a offset by 2*sizeof(int)*10 bytes
Run Code Online (Sandbox Code Playgroud)

如果a在那个表达式中给你一个int**,那么编译器就不知道它应该在哪里1正确地存储整数,因为关于元素类型的任何大小信息都会丢失.它肯定可以将大小存储在内存中,但在哪里?在数组中,没有空间.此外,sizeof无法再为您提供编译时结果.

  • +1,还有疯狂?这是......不,我不会去那里.;-) (2认同)