指向数组第一个元素的常量指针的指针是如何工作的?

时间:2015-11-07 19:23:16

标签: 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(&a);
    printf("%d", *a); //Prints 5 as output (1)

    return 0;
}

我希望编译器在尝试编译(* a)++时给出错误,但我可以运行代码,但是当我尝试打印元素时,我得到一个奇怪的值(1)。

然后我想打印出数组第一个元素的值(2)。当我尝试这个时,程序崩溃了。

3 个答案:

答案 0 :(得分:2)

程序在printf崩溃,因为test假定在解引用a时,结果对象是指针。如果它是一个并且包含有效地址,则第二个解除引用将产生一个int对象。唉,a包含数组的地址,它在数字上是第一个元素的地址。 4或8个字节被认为是一个地址(因为test认为*a是指针),然后代码尝试访问地址1 的内存以便打印在该地址处假定的int值。但地址无效,因此程序崩溃。

现在我们已经确定程序认为数组开头的数据是指向int的指针,我们知道(*a)++做了什么:它将值增加sizeof(int)以便“指针“指向下一个int”元素“。我猜你机器上的int是4个字节长,因为1 + 4 = 5,打印出来。

答案 1 :(得分:2)

通过执行&a,您正在创建一个指向数组的指针(int (*)[])。

然后当这个指向数组的指针传递给test函数时,它被转换为指向指针的指针(int **);

然后(*a)++;是UB。

<强> 1。那么为什么5?

在类似GCC的C的现代实现中,指向数组的指针具有与数组开头相同的数值,因此当数组衰减到指针时的地址值:它们都是数组的起始地址。

因此,在test中,int **a指向数组的开头,(*a)++将指针称为int *,并将指针递增1 int element,通常实现为将sizeof(int)添加到指针的数值。

然后,1+sizeof(int)给你5。

<强> 2。为什么它在第二种情况下崩溃?

假设您使用的是32位x86计算机或指针类型与int类型相同的某台计算机,则*a等于1。然后在1的内存地址处进一步解除引用指针通常会给你一个段错误。

答案 2 :(得分:1)

此代码在C中是非法的,您应该获得编译器诊断。 (如果没有,请调高警告级别)。运行任何可执行文件的结果都是没有意义的。

代码是非法的,因为int (*)[5]不会隐式转换为int const **

  

指向C

中数组的第一个元素的常量指针

没有这样的事情。你误解了什么是数组。数组是一系列连续的元素。 int a[5]int a;类似,只是有5个而不是1

int a;int a[1];导致相同的内存布局。唯一的区别是用于访问该内存的语法。