我认为数组变量不能在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无法再为您提供编译时结果.