int x=10;
int *y=&x;
int *z= &y;
printf("%d\n",*(*z));
我想了解为什么我们需要int **z
?这有什么不对?
答案 0 :(得分:3)
让我们一步一步,不管吗?
int x = 10;
此代码在某个内存位置创建一个int
变量,并将其值设置为10.可以通过方便的名称x
访问此变量。
int *y=&x;
此代码在某个内存位置创建指向int
变量的指针,并将其值设置为x
变量的地址。可以通过方便的名称y
访问此变量。如果您打印了值y
,则会获得x
的地址。如果您取消引用y
(通过执行*y
)并打印结果,那么您将得到10
int *z= &y; // error
这将无法编译:{{1}}是指向z
的类型指针。由于int
已经是指向y
的指针,因此当您获取其地址(通过执行int
)时,您获得的是指向&y
指针的指针。这就是你需要双星的原因。
int
现在这将编译。此代码创建指向int **z = &y;
变量指针的指针,并将其值设置为变量int
的地址。如果您现在打印了值y
,那么您将获得z
的地址。如果您取消引用y
(通过执行z
)并打印结果,您将获得*z
的地址。
答案 1 :(得分:3)
这是一个方便的表格,显示了基于您的声明的各种表达式的类型:
Expression Type Value
---------- ---- -----
x int 10
&x int * address of x
y int * address of x
&y int ** address of y
由于表达式 &y
的类型为int **
,您需要将z
声明为int **
以保留该值(因此表达式&z
将具有类型int ***
)。
那么,为什么重要呢?指针是指针是指针,对吗?
嗯,不一定。指向不同类型的指针可能具有不同的大小和表示。来自online 2011 standard:
6.2.5类型
...
28指向void
的指针应具有与a相同的表示和对齐要求 指向字符类型的指针。 48)同样,指向合格或不合格版本的指针 兼容类型应具有相同的表示和对齐要求。所有 指向结构类型的指针应具有相同的表示和对齐要求 彼此相同。所有指向联合类型的指针都应具有相同的表示形式 对齐要求彼此。指向其他类型的指针不必相同 表示或对齐要求。
48)相同的表示和对齐要求意味着可互换性 函数的参数,函数的返回值和联合的成员。
在桌面和服务器领域,大多数架构都是这样的,所有指针类型都具有相同的大小和表示,但是有很多奇怪的架构并不是这样。您可以使用单词寻址架构,其中多个char
值被打包到一个单词中; a char *
需要有几个额外的位来索引该单词以获得特定的char
值。您可以使用哈佛架构,其中数据的地址行数少于代码的地址行数(反之亦然),因此指向对象类型的指针和指向函数类型的指针将具有不同的大小。
这里还有另一个问题:指针算术。由于y
指向int
类型的对象,因此表达式y++
会使y
前进到指向int
类型的下一个对象。由于z
指向int *
类型的对象,因此表达式z++
会使z
前进到指向int *
类型的下一个对象。如果int
和int *
的尺寸不同,则y
和z
会提前不同的金额。
简而言之,输入很重要,即使是指针也是如此。
答案 2 :(得分:2)
x
是int
类型的变量,意味着它包含整数值。 10
的类型为int
。
y
是int*
类型的变量,意味着它包含一个表示存储类型int
的值的内存地址的值。一元运算符&
生成其参数的内存地址,通常包含类型信息,因此x
是一个int {{1}所持有的任何地址的类型将是x
。
int*
是z
类型的变量,意味着它包含一个表示int**
类型变量地址的值。 int*
生成&y
的内存地址,因此结果的类型为y
。
包含类型信息的原因不仅仅是严格/静态类型的问题;执行指针算法的方式(例如int**
,相当于p++
)将根据所指向类型的大小而不同。因此,对于指向4字节值的指针,将指针递增1将导致指向原始位置后四个字节的位置的指针,而对于指向1字节值的指针,将指针递增1将导致指向原始位置后一个字节的位置。实质上,向指针添加整数会产生p += 1
。
当然,您可以在指针类型上使用内联强制转换来更改整数上的因子,但这是另一个时间的主题。
答案 3 :(得分:1)
因此你需要一颗双星。
x = 10(x地址处的内存保持hte值为10)。
y = x的地址。如果你取消引用y(* y),它会显示10.如果你在y的地址打印了值,它会显示x的地址。如果你打印y的地址,它会显示一些与这三件事不同的东西。
z =到y的地址。请记住,当您取消引用z now(* z)时,它将为您提供y处保存的值,即x的地址。当你重新引用它时,它会给你x的地址值,这就是你想要的(因此,你需要双重引用的原因)。
答案 4 :(得分:1)
在c / c ++中,从右到左阅读变量声明很有帮助,以便更好地理解它们的类型。在您的代码段中,这将产生以下描述:
x
是int
y
是指向int
z
是指向int
在第一行中,您要将10
分配给x
。由于10
是int
,因此成功没有问题。
在第二行,您要将x
的地址指定给y
。由于指针包含地址,x
是int
而y
是指向int
的指针,此行也会成功。
第三行是你遇到麻烦的地方。您要将y
的地址指定给z
。 z
希望地址为int
,因为它获取指向int
的指针的地址。
正如DardDust所提到的,你需要更改z
的定义,以便它是指向整数的指针。
int **z = &y;
一旦你有了这个,就会更容易理解最后一行和你的第一个问题。
printf
函数需要int
,但您使用的是z
。为了获得int
值,您需要进行双重取消引用。第一个取消引用将返回指向int
的指针,第二个取消引用int
本身。
答案 5 :(得分:0)
x
是int
类型的变量,存储在内存中。&x
返回存储x
的内存位置的地址。那是一个指针。因此&x
返回的类型为int *
。现在,使用变量y
将此指针再次存储在内存中的某个位置。z
获取&y
的地址。变量y
已经存储了一个指针,所以现在你有一个指向int的指针的指针,即int **
。printf
语句中,您需要抓取该链:
*z
读取z
指向的内存。由于z
的内存位置为y
,*z
会返回y
的内存位置。y
指向的内存(间接)。并且y
指向x
,因此您最终会阅读x
。有点头脑扭曲,但在与C一起工作时理解至关重要。
答案 6 :(得分:0)
每次需要a pointer to
时,您需要在类型中添加*
:
int x=10;
声明一个int并为其赋值10
- >没有a pointer to
所以没有*
int *y=&x;
声明一个指向int的指针并保存并为其分配x
存储位置的地址
- > 1
a pointer to
所以1
*
最后
int **z= &y;
声明指向int的指针,并为其指定存储y
的地址
- > 2
a pointer to
所以2
*