2015-11-07 102 views
-1

我想测试我能不能改变常量指针,它指向下一个数组的第一个元素测试时我得到了一些奇怪的输出,我不明白:指向数组第一个元素的常量指针的指针是如何工作的?

//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)。当我尝试这个时,程序崩溃。

回答

2

通过做&a你正在指向一个数组(int (*)[])。

然后,当这个指针数组传递到test功能,它的转换成指针的指针(int **);

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

1.那么为什么是5?

对于像GCC这样的C的现代实现,指向数组的指针与数组的开头具有相同的数值,当数组衰减到指针时,地址值也是如此:它们都是阵列。

所以,在testint **a指向的数组的开始,(*a)++ deferences指针如int *和由1个int元件,其通常作为添加sizeof(int)到指针的数值实现递增指针。

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

2.为什么在第二种情况下崩溃?

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

+0

谢谢你,那是一个很棒的解释! – Agnaroc

+0

我发现它很有启发性,当'a'是一个数组时,我发现'printf(“%p \ n”,a);''和'printf(“%p \ n”,&a);''会打印相同的地址! – Prayag

+0

'&a ''具有类型'int(*)[5]',而不是你所说的。另外,由于这不是数组类型,因此它不会衰减(更不用说衰减到'int **')。 –

2

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

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

1

这段代码在C中是非法的,你应该得到一个编译器诊断。 (如果没有,请调高警戒级别)。运行任何可执行程序的结果都是没有意义的。

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

恒定指针指向的数组的第一个元素用C

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

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

相关问题