C 指向数组第一个元素的常量指针的指针是如何工作的?
我想测试是否可以更改指向C中数组第一个元素的常量指针。在测试过程中,我得到了一些奇怪的输出,我不明白:C 指向数组第一个元素的常量指针的指针是如何工作的?,c,arrays,pointers,C,Arrays,Pointers,我想测试是否可以更改指向C中数组第一个元素的常量指针。在测试过程中,我得到了一些奇怪的输出,我不明白: //Constant pointer to pointer to constant value void test(int const * * const a) { //printf("%d", **a); //Program crashes (2) (*a)++; } int main() { int a[5] = { 1,2,3,4,5 }; test(
//Constant pointer to pointer to constant value
void test(int const * * const a) {
//printf("%d", **a); //Program crashes (2)
(*a)++;
}
int main()
{
int a[5] = { 1,2,3,4,5 };
test(&a);
printf("%d", *a); //Prints 5 as output (1)
return 0;
}
当我尝试编译(*a)++时,我希望编译器会给出一个错误,但是我可以运行代码,但是当我尝试打印元素时,我得到一个奇怪的值(1)
然后我想打印出数组第一个元素的值(2)。当我尝试此操作时,程序崩溃。程序在
printf
处崩溃,因为test
假设当它取消引用a
时,结果对象是指针。如果它是一个,并且包含一个有效地址,则第二次取消引用将生成一个int对象。唉,a
包含数组的地址,它在数字上是它的第一个元素的地址。其中的4或8个字节被视为一个地址(因为test
认为*a
是一个指针),然后代码尝试访问地址1处的内存,以便打印该地址处假定的int值。但是地址无效,因此程序崩溃
既然我们已经确定程序将数组开头的数据视为指向int的指针,我们就知道
(*a)+
的作用:它将数组中的值增加sizeof(int)
,以便“指针”指向下一个int“元素”。我猜您机器上的int是4字节长的,因为1+4=5,这是打印出来的。通过执行&a
您正在创建一个指向数组的指针(int(*)[]
)
然后,当这个指向数组的指针被传递到test
函数时,它被转换为指向指针的指针(int**
)
然后(*a)+代码>是UB
1。那么为什么是5?
在类似于GCC的现代C实现中,指向数组的指针与数组的开头具有相同的数值,当数组衰减为指针时,地址值也具有相同的数值:它们都是数组的开头地址
因此,在test
中,int**a
指向数组的开头,(*a)++
将指针延迟为int*
,并将指针增加1int
元素,这通常是通过将sizeof(int)
添加到指针的数值来实现的
然后,1+sizeof(int)
给你5
2。为什么在第二种情况下会崩溃?
假设您使用的是32位x86机器,或指针类型与int
type大小相同的机器,则*a
等于1
。然后进一步取消对1
处内存地址的指针的引用通常会导致segfault。此代码在C中是非法的,您应该得到编译器诊断。(如果没有,请提高警告级别)。运行生成的任何可执行文件的结果都是毫无意义的
该代码是非法的,因为int(*)[5]
未隐式转换为int const**
指向C中数组的第一个元素的常量指针
没有这样的事。你误解了数组是什么。数组是一系列连续的元素inta[5]
类似于inta代码>除了有5
整数而不是1
之外
inta代码>和inta[1]代码>导致相同的内存布局。唯一的区别是用于访问该内存的语法。我发现看到printf(“%p\n”,a)很有启发性代码>和printf(“%p\n”,&a)当a
是数组时,code>打印相同的地址<代码>&a
的类型为int(*)[5]
,与您所说的不同。另外,由于它不是数组类型,所以不会衰减(更不用说衰减为int**
)。