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

C语言结构体指针成员访问:两段示例代码运行差异原因求解

问题原因解析

核心本质:野指针访问导致的未定义行为

首先明确前提:C语言中函数内部定义的非静态局部变量,不会被自动初始化,其值为对应内存地址中遗留的随机垃圾值。

你两段代码的核心操作SECOND->second->a = 9,本质上是三层访问:

  • 第一步:SECOND指向你定义的栈变量b,这一步是合法的(你已经执行了SECOND = &b)
  • 第二步:访问b的成员second,这是一个struct first*类型的指针,但是你从来没有显式给这个指针赋值过,它的值是随机垃圾值
  • 第三步:通过这个垃圾值指针访问它的成员a,属于典型的野指针访问,是C语言标准定义的未定义行为,程序可能崩溃、可能输出随机值,也可能碰巧正常运行。

为什么加了被注释的两行代码就碰巧能运行

加了那两行代码后,栈内存的分配顺序是:

  1. 分配struct first C变量,这是一块合法的struct first类型内存空间
  2. 分配指针变量FIRST,并把它的值设为&C,也就是C变量的地址
  3. 接下来分配struct second b变量,它的第一个成员second对应的内存地址,刚好残留了之前写入的&C的值
    相当于碰巧让b.second指向了合法的C变量,这时候访问b.second->a就不会触发非法内存访问,所以程序碰巧能正常运行。

注意:这只是巧合,完全依赖编译器的栈分配规则和运行环境,换个编译器或者编译选项可能就会崩溃,本质仍然是错误代码。大概率是你写第一段代码时漏了显式给SECOND->second赋值的步骤,才会出现这种靠运气运行的情况。


为什么注释掉那两行就会崩溃

注释掉那两行后,栈上不会分配C变量和FIRST指针,b.second的垃圾值就是完全随机的非法地址,直接通过这个地址写入9会触发操作系统的内存保护,直接报段错误崩溃。


正确的写法

要避免野指针,必须显式给b.second赋值,不要依赖栈内存的巧合值,修改后的代码如下:

#include<stdio.h>
int main()
{
    struct first{
        char *name;
        int a;
    };

    struct second{
        struct first *second;
        int z;
    };

    struct first C; // 分配实体变量
    struct second b;
    struct second *SECOND = &b;
    
    // 显式给指针成员赋值,不要依赖默认值
    SECOND->second = &C;
    
    SECOND->second->a = 9;
    printf("%d", SECOND->second->a);
    return 0;    
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 23:06:03