c/c++中普通变量和指针变量赋值的几种情况

4 阅读3分钟

基于前提 int* p = nullptr; int a = 8;nullptr 是 C++ 中更安全的空指针,指向 0 地址,程序无权访问)分析几种赋值情况,用结构化表格拆解每一种写法的核心信息,包括类型匹配、编译/运行状态、错误原因/执行结果,一眼分清合法/非法场景:

写法等号两侧类型编译状态运行状态核心原因/执行结果关键结论
p = a左:int*(p)
右:int(a=8)
警告(非报错)无直接崩溃(但p变野指针)把数值8赋值给指针p,p的地址变为8(非法内存地址),p从“空指针”变成“野指针”;
仅赋值不解引用时程序不崩溃,但后续解引用必崩溃
类型不匹配,非法赋值
p = 9左:int*(p)
右:int(9)
警告(非报错)无直接崩溃(但p变野指针)把数值9赋值给指针p,p的地址变为9(非法内存地址),p成野指针;
仅赋值不崩溃,后续解引用必崩溃
类型不匹配,非法赋值
p = &a左:int*(p)
右:int*(&a)
完全通过(无警告/报错)正常(无崩溃)把变量a的合法内存地址赋值给p,p从“空指针”变为“指向a的合法指针”;
此时p的地址是a的真实地址(如0x7ffeefbff5c4)
类型匹配,合法赋值(推荐)
*p = &a左:int(*p)
右:int*(&a)
直接报错(无法编译)无法运行*p 是“p指向的int类型数值”,只能接收int值;
&a 是指针类型(地址),类型完全不兼容,编译器直接拦截
类型不匹配,编译错误(必改)
*p = a左:int(*p)
右:int(a=8)
完全通过(无警告/报错)立即崩溃类型匹配,但p是nullptr(指向0地址,系统保留);
解引用空指针往0地址写数值8,触发“内存非法访问”
类型匹配但指向非法,运行崩溃
*p = 9左:int(*p)
右:int(9)
完全通过(无警告/报错)立即崩溃类型匹配,但p是nullptr
解引用空指针往0地址写数值9,触发“内存非法访问”
类型匹配但指向非法,运行崩溃

补充关键细节(新手必懂)

  1. 关于“编译警告 vs 编译报错”

    • p=a/p=9 是“类型不匹配但编译器允许隐式转换”,所以仅出警告(如GCC的-Wint-conversion),但依然是非法写法;
    • *p=&a 是“类型完全不兼容(int无法接收int*)”,编译器直接报错,程序连编译都通不过。
  2. 关于“空指针(nullptr)的解引用”nullptr 是专门标记“指针无合法指向”的关键字,解引用*p(无论赋值什么)都会崩溃——因为它指向的0地址是操作系统内核保留的,普通程序无权读写。

  3. 合法场景的延伸(基于p=&a: 若先执行p=&a(让p指向合法地址),再执行*p=a/*p=9,则完全合法:

    int* p = nullptr;
    int a = 8;
    p = &a; // 先让p指向a的合法地址
    *p = a; // ✅ 合法:a的值保持8
    *p = 9; // ✅ 合法:a的值被改为9
    

核心规则总结(覆盖所有场景)

  1. 赋值给指针变量pp=xxx

    • 只有xxx是「int*类型的合法地址」(如&amalloc返回值),才合法;
    • 赋值普通int值(如a9),类型不匹配,p变野指针。
  2. 赋值给解引用指针*p*p=xxx

    • 第一步:检查类型——只有xxx是int类型(如a9),编译才通过;
    • 第二步:检查指向——只有p指向合法地址(如p=&a),运行才不崩溃;
    • 若p是nullptr/野指针,即使类型匹配,运行必崩溃。
  3. 绝对禁忌: 永远不要写*p=&a(类型不匹配,编译报错); 永远不要解引用nullptr/野指针(运行必崩溃)。