我想了解为什么我们需要`int ** z`?

时间:2013-06-06 15:48:03

标签: c

int x=10;
int *y=&x;

int *z= &y;

printf("%d\n",*(*z));

我想了解为什么我们需要int **z?这有什么不对?

7 个答案:

答案 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 *类型的下一个对象。如果intint *的尺寸不同,则yz会提前不同的金额。

简而言之,输入很重要,即使是指针也是如此。

答案 2 :(得分:2)

xint类型的变量,意味着它包含整数值。 10的类型为int

yint*类型的变量,意味着它包含一个表示存储类型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 ++中,从右到左阅读变量声明很有帮助,以便更好地理解它们的类型。在您的代码段中,这将产生以下描述:

xint

y是指向int

的指针

z是指向int

的指针

在第一行中,您要将10分配给x。由于10int,因此成功没有问题。

在第二行,您要将x的地址指定给y。由于指针包含地址,xinty是指向int的指针,此行也会成功。

第三行是你遇到麻烦的地方。您要将y的地址指定给zz希望地址为int,因为它获取指向int的指针的地址。

正如DardDust所提到的,你需要更改z的定义,以便它是指向整数的指针。

int **z = &y;

一旦你有了这个,就会更容易理解最后一行和你的第一个问题。

printf函数需要int,但您使用的是z。为了获得int值,您需要进行双重取消引用。第一个取消引用将返回指向int的指针,第二个取消引用int本身。

答案 5 :(得分:0)

  • xint类型的变量,存储在内存中。
  • &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 *