变量和常量
本节将介绍变量和常量的概念、声明和使用方法。
上一节我们了解了数据类型是什么,知道了数据类型用于规定数据的种类和范围。但是在实际编程中,我们需要一个容器来存储这些数据,这个容器就是变量和常量。我们可以把变量和常量想象成带有标签的盒子,用来存放不同类型的数据。
编程语言为我们提供了“变量”和“常量”这两种基本的存储方式。它们就像是程序中的“容器”或“盒子”,每个盒子都有一个标签(名字),用来标识盒子里的内容。
变量是什么
变量是程序运行过程中可以存储数据的容器。变量的最大特点是盒子里的内容可以随时更换,也就是说,变量存储的数据在程序运行期间可以被修改。每个变量都有一个名字(标签),通过这个名字我们可以随时访问盒子里的内容,也可以把新的数据放进去。
从计算机的角度来看,变量其实就是内存中的一块空间。我们给这块空间起一个名字,并指定它能存放什么类型的数据(比如整数、浮点数、字符等)。在程序运行时,我们理论上可以随时读取或修改这块空间里的内容。
常量是什么
常量也是一种数据容器,但它和变量最大的不同是:盒子里的内容一旦放进去就不能再更换。常量的值在程序运行期间始终保持不变。常量适合用来存储那些不会发生变化的数据,比如圆周率、一天的小时数等。
Tips
在一些编程语言(如 Java、Kotlin、Rust、Swift)中,除了“常量”之外,还存在“不可变变量”的概念。不可变变量和常量非常相似,都是盒子里的内容不能被更换,但它们在语义上有一些细微的区别。
- 常量通常指的是在编译期间就确定了值,整个程序运行过程中都不会改变。
- 不可变变量则是指在程序运行期间,变量的值一旦初始化就不能再被修改,但它的值可以在运行时确定(比如通过计算得到)。
在 C++ 中,使用 const 关键字声明的变量既可以被称为常量,也可以被称为不可变变量。它们的行为和常量一样,初始化后值不可更改。虽然 C++ 习惯上称之为“常量”,但理解为“不可变变量”也没有问题。
定义变量与常量
变量的定义
定义一个变量很简单。在 C++ 中定义一个变量的格式如下:
<类型名> <变量名> [= <初始值>] [, <变量名> [= <初始值>], ...];例如,你可以通过以下方式定义变量:
int a = 10, b = 20;
int c;
int d = 10, e, f = 20;变量名、常量名和函数名等被称为“标识符”。C++ 标识符的命名必须遵循以下的规则:
以下的定义是合法的
int thisIsAVariable, _aVariable, Variable123, var_1, Var_1;而以下所有标识符都是不合法的
int 123Variable, this-is-a-variable, var@1, var!, V ar;
int a = 1;
int a = 2; // 这也是不合法的,因为 a 已经被定义过
a = 2;
int a; // 这也是不合法的,应该在使用前定义标识符。使用 auto 关键字自动推断类型
在 C++11 及之后的版本中,可以使用 auto 关键字让编译器自动推断变量的类型。这样可以让代码更加简洁,尤其是在变量类型很复杂或者不容易书写时非常有用。
auto 的基本用法如下:
auto a = 10; // a 被推断为 int 类型
auto b = 3.14; // b 被推断为 double 类型
auto c = "hello"; // c 被推断为 const char* 类型注意,auto 只能用于变量定义时,并且必须初始化,因为编译器需要根据初始值来推断类型。
auto 适合用于类型复杂或不易书写的场景,比如迭代器、模板类型等。使用 auto 可以减少代码冗余,提高可读性,但也要注意不要滥用,避免让代码的类型变得不明确。
变量的赋值
变量定义之后,我们可以通过赋值语句来修改变量的值,也可以通过变量名来访问变量的值。
int a = 10; // 定义一个整型变量 a,并初始化为 10
a = 20; // 修改 a 的值为 20
int b; // 定义一个整型变量 b
b = a + 10; // 修改 b 的值为 a 的值加上 10
cout << b; // 输出 b 的值(使用 b)
int x, y, z; // 定义三个整型变量 x, y, z
x = y = z = 10; // 链式赋值,从右往左赋值,先修改 z 的值为 10,然后修改 y 的值为 z 的值,最后修改 x 的值为 y 的值。从结果而言,x、y、z 的值都是 10。在赋值语句中,C++ 会先计算赋值符号 = 右边的表达式(右值),然后将结果赋给左边的变量(左值)。如果有链式赋值,C++ 会从右往左依次计算并赋值(可以看上方的例子)。
常量的定义
常量的定义与变量类似,只不过需要加上 const 关键字。
const <数据类型> <常量名> = <初始值> [, <常量名> = <初始值>, ...];与变量定义唯一不同的是,常量必须要设定初始值,因为常量一旦完成初始化,值就不能再被修改。
const int MAX_SIZE = 100, MIN_SIZE = 10;
const double PI = 3.1415926;
PI = 3.14; // ❌ 错误,常量不能被修改const auto 自动推断还有几种常量的定义方法:#define 宏定义常量 和 C++11 出现的 constexpr 编译期常量。这些常量的定义方法会在后面的章节中提到,此处不在赘述。
变量和常量的作用域
在编程中,“作用域”这个词指的是变量或常量可以被访问的范围。你可以把作用域想象成一个“房间”,在这个房间里你可以看到和使用某些盒子(变量或常量),但出了房间我们就无法在访问和修改这些盒子的内容了。
在 C++ 里,变量和常量的作用域通常由它们定义的位置决定。
举个例子:
int a = 10; // 这是在全局作用域定义的变量,也被称为全局变量
int main() {
int b = 20; // 这是在 main 函数内部定义的变量,也被称为局部变量
{
int c = 20; // 这是在 {} 代码块内部定义的变量,也被称为局部变量
cout << a << endl; // 可以访问 a
cout << b << endl; // 可以访问 b
cout << c << endl; // 可以访问 c
}
cout << a << endl; // 可以访问 a
cout << b << endl; // 可以访问 b
cout << c << endl; // ❌ 错误,c 只能在上面的 {} 代码块的作用域内部访问
}全局变量可以在整个程序中访问,函数内部定义的变量只能在该函数内使用,而在代码块 {} 内定义的变量则只能在这个代码块里访问,出了代码块就无法再使用。也就是说,变量只能在它被定义的范围内有效,超出这个范围就无法访问。
变量的作用域也决定了它的生命周期——也就是变量“活着”的时间。局部变量在进入代码块时创建,离开代码块时销毁。全局变量在程序开始时创建,程序结束时销毁。
Footnotes
-
C++ 常见关键字(或称保留字)包括:
auto,break,case,catch,char,class,const,const_cast,continue,default,delete,do,double,dynamic_cast,else,enum,explicit,export,extern,false,float,for,friend,goto,if,inline,int,long,mutable,namespace,new,operator,private,protected,public,register,reinterpret_cast,return,short,signed,sizeof,static,static_cast,struct,switch,template,this,throw,true,try,typedef,typeid,typename,union,unsigned,using,virtual,void,volatile,wchar_t,while,xor,xor_eq等等。 ↩