【C++ 变量与常量】变量的定义、初始化、const 与 constexpr

张开发
2026/4/9 12:18:11 15 分钟阅读

分享文章

【C++ 变量与常量】变量的定义、初始化、const 与 constexpr
1. 什么是变量什么是常量变量在程序运行过程中其值可以改变的量。可以把它想象成一个有名字的“盒子”盒子里可以放不同类型的数据。常量其值在程序运行过程中不能被改变。一旦初始化后试图修改常量会导致编译错误。2. 变量的定义与初始化2.1 变量的定义语法类型 变量名;或类型 变量名 初始值;#includeiostreamusingnamespacestd;intmain(){intage;// 定义变量 age类型为 int此时值未初始化垃圾值age18;// 赋值intscore95;// 定义并初始化推荐写法doublepi3.14;chargradeA;cout年龄: age, 分数: scoreendl;return0;}2.2 初始化方式C 提供了多种初始化语法方式示例说明赋值初始化int a 10;最常用直观函数形式初始化int a(10);构造函数风格统一初始化列表初始化int a{10};C11 起推荐防止窄化转换intx5;// 赋值初始化inty(5);// 直接初始化intz{5};// 统一初始化推荐intw{5};// 等号加花括号也可以// 列表初始化会防止数据丢失窄化转换inta3.14;// 允许但 a 变成 3丢失小数部分intb{3.14};// 编译错误窄化转换小数转整数不允许2.3 默认初始化与未初始化变量全局变量、静态变量会被默认初始化为 0。局部变量不会自动初始化其值是未定义的垃圾值使用前必须显式赋值。intglobal_var;// 全局变量默认值为 0intmain(){intlocal_var;// 未初始化值不确定危险staticintstatic_var;// 静态局部变量默认值为 0coutglobal_varendl;// 0coutstatic_varendl;// 0// cout local_var endl; // 输出垃圾值行为未定义return0;}⚠️警告使用未初始化的局部变量会导致不可预测的结果甚至程序崩溃。务必养成定义时初始化的习惯。3. 常量const与constexpr3.1const常量const修饰的变量一旦初始化后就不能再修改。constintDAYS_IN_WEEK7;// 必须初始化// DAYS_IN_WEEK 8; // 错误不能修改常量constdoublePI3.1415926;const可以修饰函数参数、返回值、成员函数等后续文章会深入。3.2constexpr常量表达式C11 起constexpr表示该变量的值在编译时就能确定可用于数组大小、模板参数等需要编译时常量的场景。constexprintARRAY_SIZE10;// 编译时常量intarr[ARRAY_SIZE];// 合法因为 ARRAY_SIZE 编译时已知intgetSize(){return20;}constexprintsize2getSize();// 错误getSize() 不是 constexpr 函数区别总结特性constconstexpr初始化时机运行时或编译时必须是编译时能否修改否否能否用于数组大小仅在部分编译器支持 VLA 时可以因为编译时已知修饰函数表示函数不会修改成员表示函数可在编译时求值简单记忆const是“运行时只读”constexpr是“编译时已知”。4. 内存模型讲解浅显易懂当程序运行时变量被存放在内存的不同区域。让我们画一张简单清晰的图。高地址 ┌─────────────────┐ │ 栈 (Stack) │ ← 局部变量如 main 中的 age, score │ (向下增长) │ 函数调用时的参数、返回地址 ├─────────────────┤ │ 堆 (Heap) │ ← 动态分配的内存new/malloc本章暂未涉及 ├─────────────────┤ │ 数据段 (Data) │ │ ┌─────────────┐ │ │ │ .rodata │ │ ← 只读数据段字符串字面量、const 常量取决于编译器 │ ├─────────────┤ │ │ │ .data │ │ ← 已初始化的全局变量、静态变量 │ ├─────────────┤ │ │ │ .bss │ │ ← 未初始化的全局变量、静态变量会被清零 │ └─────────────┘ │ ├─────────────────┤ │ 代码段 (Text) │ ← 程序的二进制指令 └─────────────────┘ 低地址具体例子constintGLOBAL_CONST100;// 通常放在 .rodata只读intglobal_var42;// 放在 .dataintglobal_uninit;// 放在 .bss默认 0intmain(){constintlocal_const10;// 通常放在栈上但编译器可能优化为直接替换intlocal_var20;// 放在栈上staticintstatic_var5;// 放在 .data静态局部return0;}栈上的变量当main函数被调用时系统在栈上分配一块空间栈帧。local_var就在其中函数返回后这块空间被回收。.rodata段只读任何试图修改该段内存的行为都会导致运行时错误段错误。.bss段不占用可执行文件的实际空间但程序加载时会被清零。关键点const变量不一定放在只读内存段取决于编译器优化但编译器会阻止你修改它。constexpr变量则几乎肯定在编译时就被求值可能根本不占用内存直接作为立即数嵌入指令。5. 常见错误与避坑错误示例问题正确做法const int a;const 变量未初始化定义时必须初始化int arr[n];其中 n 是普通变量标准 C 不允许变长数组使用constexpr或动态分配int x 10; const int r x;然后尝试通过r修改不能通过常量引用修改需要修改就不要用 const将constexpr函数在运行时调用可以但失去了编译时优势确保参数也是编译时常量6. 练习题题目请编写一个程序完成以下要求定义一个constexpr整数kStudentCount 5。定义一个const浮点数kPi 3.14159。定义一个未初始化的局部整数uninit_val然后直接输出它观察结果理解垃圾值。定义一个静态局部整数counter初始化为 0每次调用一个函数Increment()时counter增加 1 并返回。在main中调用三次输出每次的返回值。尝试修改kPi观察编译错误。输出示例uninit_val的值每次运行可能不同未初始化的值4200136 第1次调用1 第2次调用2 第3次调用3附加挑战尝试用const和constexpr分别定义一个数组大小验证constexpr可以而普通const如果初始化不是编译时常量不行。提示关于附加挑战中的arr2[size_const]在标准 C 中数组大小必须是编译时常量。虽然size_const是const但如果它的初始化值在编译时已知有些编译器如 GCC会将其视为常量表达式但为了可移植性应使用constexpr。上期答案/** * file sum.cpp * brief 读取两个整数输出它们的和 * author (你的名字) * date 2025-01-15 */#includeiostreamusingnamespacestd;/** * brief 计算两个整数的和 * param a 第一个整数 * param b 第二个整数 * return 两数之和 */intAdd(inta,intb){intsumab;// 临时存储和returnsum;}intmain(){intfirst_num,second_num;cout请输入两个整数;cinfirst_numsecond_num;intresultAdd(first_num,second_num);cout它们的和是resultendl;return0;}总结变量是存储数据的基本单元常量让数据不可变增强代码安全性和可读性。const保证运行时只读constexpr强调编译时求值。理解内存分区栈、数据段、只读段有助于写出更高效的代码。下一篇文章我们将学习基本数据类型进一步夯实基础。赶快动手写代码试试修改常量的后果并观察静态局部变量的神奇行为吧

更多文章