C指针问题,让我理解十进制+十进制[2]



你好,我有 3 个问题/3 行代码我不明白。 如果有人能帮助我,那就太好了。 我的理解仍然不是鸡蛋中的黄色。 这些问题被注释为//QUESTION:

#include <stdio.h>
#include <stdlib.h>
struct trace {
char *sign;
int *values;
struct trace *pN;
};
int main() {
int decimal[] = {4,2,1};
char text[]="Word-2!";
struct trace *pV;
pV = (struct trace*) calloc(2, sizeof(struct trace));
pV->pN = pV;
pV->values = decimal + decimal[2]; // = 2   
// QUESTION: explanation why decimal + decimal[2] is 2 / what is decimal (not *decimal). 
// My guess is: decimal[0 + decimal[2]] = decimal[0 + 1] = decimal[1] = 2

(*pV).sign = text + *decimal;  // text + 4  //"-2!";
*(pV + 1) = pV[0]; // pV[1] = pV[0] = *pV
++pV[1].values;         // QUESTION: what does this do?  the ++ in front of pV instead of pV[++1].values
++*pV[1].values;        // QUESTION: what does this do?
printf("%d %sn", *pV->values, pV->sign);
printf("%d %sn",*pV->pN[1].values, pV->pN[1].sign);
return 0;
}

编辑:这样做的目的是找出这 2 个 printf 中显示的内容,它们都是: "2-2!" "2-2!">

你难以理解该代码是有充分理由的;这很令人讨厌。 它试图说明指针和数组的一些怪异行为,但它以一种过于"棘手"且难以理解的方式完成。 它混合和匹配数组和指针表示法,并且在访问成员的方式上不一致。 这也不安全。 这是如何编写 C 代码的一个很好的例子。

在我们开始之前,先介绍一下语法备忘单:

a[i] == *(a + i), therefore
a[0] == *(a + 0) == *a
p->m == (*p).m == (*(p + 0)).m == p[0].m

所以:

pV->values = decimal + decimal[2];

TL/DR- 这是将pV->values(与(*pV).values相同,与pV[0].values相同)设置为指向decimals数组的第二个元素;图形上,它看起来像这样:

+---+        +---+                          +---+
pV:|   | -----> |   | pV[0].sign      decimal: | 4 | decimal[0]
+---+        +---+                          +---+
|   | pV[0].values ----------> | 2 | decimal[1]
+---+                          +---+
|   | pV[0].pN                 | 1 | decimal[2]
+---+                          +---+
|   | pV[1].sign
+---+
|   | pV[1].values
+---+
|   | pV[1].pN
+---+

相当于写作

pV->values = &decimal[1];

在这种情况下,表达式decimal从类型"int的 3 元素数组"衰减"到"指向int的指针"类型,表达式的值是数组第一个元素的地址(我们将在后面讨论为什么会这样)。 对于这个指针值,我们将存储在decimal[2]中的值相加,即1

pV->values = decimal + 1;

将 1 添加到指针将生成指向指向类型的下一个对象的指针,该对象不一定是下一个字节;如果decimal[0]的地址是0x8000的,并且int宽度为 4 个字节,则上面相加的结果是0x8004而不是0x8001

(*pV).sign = text + *decimal;

TL/DR - 这会将pV->sign设置为指向text字符串的"-"字符;*decimal与包含值4decimal[0]相同,所以上面相当于

(*pV).sign = &text[4];

到程序的这一点上,我们遇到以下情况:

+---+        +---+                            +---+
pV:|   | --+--> |   | pV[0].sign ---+   decimal: | 4 | decimal[0]
+---+   |    +---+               |            +---+
|    |   | pV[0].values ------------> | 2 | decimal[1]
|    +---+               |            +---+
+--- |   | pV[0].pN      |            | 1 | decimal[2]
+---+               |            +---+
|   | pV[1].sign    |
+---+               |            +---+
|   | pV[1].values  |      text: |'W'| text[0]
+---+               |            +---+
|   | pV[1].pN      |            |'o'| text[1]
+---+               |            +---+
|            |'r'| text[2]
|            +---+
|            |'d'| text[3]
|            +---+
+----------> |'-'| text[4]
+---+
|'2'| text[5]
+---+
|'!'| text[6]
+---+
| 0 | text[7]
+---+

++pV[1].values;

TL/DR - 这会将pV[1].values设置为指向decimal[2]

表达式++pV[1].values解析为++(pV[1].values)- 我们将 1 添加到pV[1].values。 在程序的前面,我们将pV[0]的内容复制到pV[1],并且我们设置了pV[0].values指向decimal[1]。 就像我上面说的,向指针添加 1 会生成指向指向类型的下一个对象的指针;因此,pV[1].values现在指向decimal[3].

所以现在我们的图片是这样的:

+---+        +---+                            +---+
pV:|   | --+--> |   | pV[0].sign ---+   decimal: | 4 | decimal[0]
+---+   |    +---+               |            +---+
|    |   | pV[0].values ------------> | 2 | decimal[1]
|    +---+               |            +---+
+--- |   | pV[0].pN      |   +------> | 1 | decimal[2]
|    +---+               |   |        +---+
|    |   | pV[1].sign ---+   |
|    +---+               |   |        +---+
|    |   | pV[1].values -----+  text: |'W'| text[0]
|    +---+               |            +---+
+--- |   | pV[1].pN      |            |'o'| text[1]
+---+               |            +---+
|            |'r'| text[2]
|            +---+
|            |'d'| text[3]
|            +---+
+----------> |'-'| text[4]
+---+
|'2'| text[5]
+---+
|'!'| text[6]
+---+
| 0 | text[7]
+---+

++*pV[1].values;

TL/DR- 我们正在增加decimal[3]的价值。

与前面的表达式类似,++*pV[1].values解析为++(*pV[1].values)。 我们不是在pV[1].values上加 1,而是在pV[1].values指向的事物上加 1,即decimal[3]。 所以最后,在一切都说完了之后,我们的图片是这样的:

+---+        +---+                            +---+
pV:|   | --+--> |   | pV[0].sign ---+   decimal: | 4 | decimal[0]
+---+   |    +---+               |            +---+
|    |   | pV[0].values ------------> | 2 | decimal[1]
|    +---+               |            +---+
+--- |   | pV[0].pN      |   +------> | 2 | decimal[2]
|    +---+               |   |        +---+
|    |   | pV[1].sign ---+   |
|    +---+               |   |        +---+
|    |   | pV[1].values -----+  text: |'W'| text[0]
|    +---+               |            +---+
+--- |   | pV[1].pN      |            |'o'| text[1]
+---+               |            +---+
|            |'r'| text[2]
|            +---+
|            |'d'| text[3]
|            +---+
+----------> |'-'| text[4]
+---+
|'2'| text[5]
+---+
|'!'| text[6]
+---+
| 0 | text[7]
+---+

那么为什么数组表达式会"衰减"成指针表达式呢?

C 派生自早期名为 B 的编程语言 - 在 B 中,当您声明一个数组时,编译器将留出一个单独的字来存储数组第一个元素的偏移量。 鉴于声明

auto a[5];

你会在内存中有这样的东西:

+---+
a: |   | ----------+
+---+           |
...            |
+---+           |
|   | a[0] <----+
+---+
|   | a[1]
+---+
|   | a[2]
+---+
|   | a[3]
+---+
|   | a[4]
+---+

数组下标操作a[i]被定义为*(a + i)- 给定一个存储在a中的地址,从该地址偏移i单词并取消引用结果。

Ritchie 想将 B 的数组行为保留在 C(a[i] == *(a + i)中),但他不想存储行为所需的单独指针。 相反,我们有这个规则:

6.3.2.1 左值、数组和函数指示符
...
     3 除非它是sizeof运算符、_Alignof运算符或 一元&运算符,或者是用于初始化数组的字符串文本,该表达式具有 类型"类型数组"转换为类型为"指向类型的指针"的表达式,该表达式指向 到数组对象的初始元素,并且不是左值。如果数组对象具有 注册存储类,行为未定义。
C2011 在线草稿

当您用 C 声明一个数组时,例如

int a[5];

你在内存中得到这个:

+---+
a: |   | a[0]
+---+
|   | a[1]
+---+
|   | a[2]
+---+
|   | a[3]
+---+
|   | a[4]
+---+

数组下标操作a[i]仍然定义为*(a + i),但不是将指针值存储在名为a的单独对象中,而是根据需要计算指针值。 因此,表达式decimaltext最终计算为指针值。

//

问题:解释为什么十进制 + 十进制[2] 是 2/什么是 十进制(不是*十进制).
//我的猜测是:十进制[0 + 十进制[2]] = 十进制[0 + 1] = 十进制1 = 2

严格来说,decimal + decimal[2]并不2.它是指针,指向包含2的内存(因为简单decimal指向decimal[0],并且添加到这个指针decimal[2],即1,得到decimal[1],即2)。

对于接下来的两个问题,查看运算符优先级表很有用。

++pV[1].values; // it's basically ++(pv[1].values), i.e. incrementing of the pointer 'values'
++*pV[1].values; // it's basically ++(*(pv[1].values)), i.e. incrementing of the integer value, pointed by the pointer 'values'

相关内容

  • 没有找到相关文章