2011-09-08 35 views
18
#include<stdio.h> 
main() 
{ int x[3][5]={{1,2,10,4,5},{6,7,1,9,10},{11,12,13,14,15}}; 


printf("%d\n",x); 
printf("%d\n",*x); } 

这里首先printf会打印第一个元素的地址。 那么为什么不第二个printf打印地址x的值,即第一个值。 要打印我需要写入** x的值。请解释C中指针的含糊性?

+0

你肯定第一个printf将打印地址,而不是价值? –

回答

26

对于指针来说,x[0]*x相同。由此得出*x[0]**x相同。

*x[0]

xint[3][5],在表达式中使用时,其被转换到int(*)[5]。所以x [0]是类型int[5](第一个5元素“行”)的左值,它被再次转换为int*,并取消引用其第一个元素。

*x沿着相同的路线进行评价,除了第一个非关联化用星号(相对于分度),以及没有第二解引用完成的,因此我们最终int[5]类型的左值,它被传递给printf作为其第一个元素的指针。

+0

是的,但我得到的地址,当我打印“X”,所以当我做手术* X我应该得到的价值存储在该地址... – dejavu

+0

是的,没有。你真的得到了存储在地址上的值,这是“我正在谈论的int [5]'类型的左值。然而,数组不是C中的第一类,它们被传递给函数作为它们第一个元素的指针。所以'printf'得到指向5的第一个'int'的指针,它的地址与'x'的第一个元素的地址相同。 IOW,'(void *)x ==(void *)* x',这就是你所看到的。 – jpalecek

+0

我编辑了这个问题..这是我的怀疑......那是误印。 – dejavu

-1

想象一个2-d数组作为指针数组,数组中的每个元素都指向另一个数组中的第一个元素。当您取消引用x时,将得到x指向的内存位置中的值...指向int的第一个int的指针。当您取消引用该指针时,您将获得第一个元素。

+3

这不是准确的。你当然可以拥有一个有效的2-d锯齿阵列,但是实际的存储只是逐行连续的,而通过乘法完成解引用。 – Yuliy

+0

@Yuliy:我明白这不是它如何实现的,但它是理解为什么需要解除引用两次的简单方法。 – Daniel

+1

@Daniel:Yuliy的观点站立。 C新手对此已经有足够的疑惑,并且已经有太多尝试将“二维数组”分配为一系列指针,应避免任何进一步导致误解的风险。 –

4

当用作函数的参数时,数组衰减成指向数组第一个元素的指针。也就是说,x衰减到的对象类型是指向第一个子数组的指针,它是指向int或基本上int (*)[5]的数组的指针。当您拨打printf("%d\n",*x)时,您不会将整数值输入到printf,而是指向第一个子阵列x的指针。由于该子阵列也将衰减到指向第一个子阵列元素的指针,因此您可以执行**x来取消引用该后续指针并获取第一个子阵列x的第一个元素。这与*x[0]实际上是相同的,按运算符优先级将索引到x的第一个子数组中,然后将指针解引用到第一个子数组将衰减到的第一个子数组的元素。

0

由于*x的类型是“指向5个数组的指针”。所以,你需要一个更提领来获得的第一个元素

PS:

#include <typeinfo> 
#include <iostream> 

typedef int arr[5]; // can't compile if put arr[4] here 
void foo(arr& x) 
{ 
} 

int main() 
{ 
    int x[3][5]={{1,2,10,4,5},{6,7,1,9,10},{11,12,13,14,15}}; 

    std::cout << typeid(*x).name() << std::endl;// output: int [5] 

    foo(x[0]); 
    return 0; 
} 

+0

'* x'的类型是“指向'int'”('int *')的指针。它是'x'本身,在数组类型衰减到表达式中的指针之后,该表达式的类型为“指向5个int的数组的指针”。 –

+0

Erm,'* x'的类型是“5个整数”,所以我稍微错了。在大多数情况下,这种衰减会输入“指向int的指针”。在任何解释中,它肯定没有类型“指向5个整数的数组”。 –

+0

是的,我改变了我的原始信息并添加了一些“证明”。 – qehgt