You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言指针、数组偏移与结构体运算代码疑问求解

C语言指针相关代码问题解答

待分析完整代码如下:

#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   

    (*pV).sign = text + *decimal;  // text + 4  对应字符串"-2!"
    *(pV + 1) = pV[0]; // 即pV[1] = pV[0] = *pV
    ++pV[1].values;         
    ++*pV[1].values;        
    printf("%d %s\n", *pV->values, pV->sign);
    printf("%d %s\n",*pV->pN[1].values, pV->pN[1].sign);

    return 0;
}

疑问1:decimal + decimal[2]运算逻辑与数组名语义

  • 单独作为表达式使用的数组名decimal,语义是指向数组首元素的常量指针,类型为int*,存储的地址就是decimal[0]的内存地址。
  • decimal[2]是下标访问,对应数组第三个元素的值,也就是1。
  • C语言指针加法规则:类型* 指针 + 整数n,返回指针向后偏移n个对应类型长度后的新地址,指向原位置后第n个同类型元素。因此decimal + decimal[2]等价于decimal + 1,指向数组下标为1的元素decimal[1],该地址存储的值为2。
  • 你的猜测完全正确:C语言中下标访问本质是指针偏移的语法糖,arr[i]与*(arr + i)完全等价,因此decimal + decimal[2]就是&decimal[1],解引用后拿到的值就是decimal[1] = 2。

疑问2:++pV[1].values;执行逻辑与作用对象

  • 先明确C语言运算符优先级:数组下标访问[]、结构体成员访问.优先级相同,遵循左结合规则,优先级高于前置自增运算符++。该语句的运算顺序为:
    1. 计算pV[1],拿到calloc分配的第二个trace结构体实例
    2. 读取该结构体的values成员,这是一个int*类型的指针变量
    3. 前置++直接作用在这个int*指针上,将指针向后偏移1个int类型长度:初始时pV[1].values和pV[0].values值相同,都指向decimal[1],执行完该语句后,pV[1].values修改为指向decimal[2]。
  • 与pV[++1].values的核心区别:
    1. 作用对象完全不同:原语句的++修改的是结构体的values指针成员的指向;pV[++1].values中++的作用目标是下标位置的数值。
    2. pV[++1].values本身是非法C语法:前置++要求操作数是可修改的左值,字面量1是右值,无法被修改,编译阶段就会报错。如果将下标位置替换为可修改变量(如int i=0; pV[++i].values),逻辑是先自增下标变量,再取对应下标的结构体成员,和原语句修改指针指向的逻辑没有关联。
  • 注意:pV[1] = pV[0]是结构体值拷贝,两个结构体的values是独立的指针变量,仅初始值相同,修改pV[1].values的指向不会影响pV[0].values。

疑问3:++*pV[1].values;执行逻辑

按优先级拆解运算顺序(.优先级最高,其次是解引用*,最后是前置++):

  1. 先取pV[1].values:经过上一行代码修改,该指针当前指向decimal[2],也就是存储值为1的int元素地址
  2. 对指针做解引用操作*,直接拿到decimal[2]这个int变量本身
  3. 前置++作用在这个int变量上,将decimal[2]的值从1自增为2。

最终输出结果成因

逐行梳理到printf语句前的内存状态:

  1. 初始状态:decimal数组元素为{4,2,1},text字符串内存布局为'W','o','r','d','-','2','!','\0'
  2. calloc分配2个连续的trace结构体,首地址赋值给pV,初始内存全为0
  3. pV->pN = pV:第一个结构体pV[0]的pN指针指向自身,也就是pV数组首地址
  4. pV->values = decimal + decimal[2]:decimal[2]值为1,因此pV[0].values指向decimal[1],对应存储值为2
  5. (*pV).sign = text + *decimal:*decimal是decimal[0]值为4,因此pV[0].sign指向text下标为4的位置,也就是字符串"-2!"的首地址
  6. *(pV + 1) = pV[0]:将pV[0]的所有成员值拷贝给pV[1],此时pV[1]的三个成员初始值和pV[0]完全一致:sign指向"-2!",values指向decimal[1],pN指向pV首地址
  7. ++pV[1].values:将pV[1]的values指针向后偏移1个int长度,指向decimal[2],pV[0].values不受影响,仍然指向decimal[1]
  8. ++*pV[1].values:将decimal[2]的值从1自增为2,此时decimal数组变为{4,2,2}

两个printf的输出逻辑:

  • 第一个printf:*pV->values取pV[0].values指向的值,也就是decimal[1] = 2;pV->sign是pV[0].sign指向的"-2!",因此第一行输出2 -2!
  • 第二个printf:pV->pN等于pV也就是数组首地址,pV->pN[1]就是pV[1];*pV->pN[1].values取pV[1].values指向的值,也就是自增后的decimal[2] = 2;pV->pN[1].sign是pV[1].sign指向的"-2!",因此第二行也输出2 -2!,和预期结果完全一致。

内容的提问来源于stack exchange,提问作者Sylenthio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 21:18:21