变量
变量是指内容可变化的量,是访问和保存数据的媒介。
变量的声明和定义
- 变量的声明确定了变量的类型、大小、名字等信息,定义则是在声明的基础上为变量分配内存。可以粗浅的认为:
type val1; //是声明
type val2 = val; //(val是常量)是定义
- 同一个变量可以在多处申明,但只能有一个定义。
- 关键字extern表示变量或函数的定义在别的文件中,提示编译器在别的模块中寻找此变量或函数的定义。
#include<iostream>
using namespace std;
int main(){
extern int a;
cout << a << endl; //输出结果为3.
return 0;
}
extern int a = 3;
变量的作用域和生存期
变量的作用域是指变量可以被引用的区域,分为三类:局部,全局,文件。具有局部作用域的变量称为局部变量,具有全局和文件作用域的称为全局变量。
- 大部分变量具有局部作用域,它们声明在函数内部。其作用域开始于变量声明的位置,并在标志该函数块结束的右括号处结束。
void test(int a){ //形参a的作用域开始于此
int b = 1; //局部变量b的作用域开始于此
if(a){
int c = a+b; //块内变量c的作用域开始于此
} //c的作用域在此结束
} //a、b的作用域在此结束
- 全局变量声明在函数外部,其作用域一般从变量声明的位置开始,在程序源文件结束处结束。
- 文件作用域是指在函数外部声明的变量只在当前文件范围内可用,但不能被其他文件内的函数访问。一般在变量声明时在前加上static关键字。当将多个独立编译的源文件链接成一个程序时,可以利用static修饰符避免一个文件中的外部变量由于与其他文件中的变量同名而发生冲突。
static int x = 1; //静态变量x的作用域开始于此,结束于当前文件
void test(){
...
}
在同一个作用域内声明的变量不能同名
可以使用作用域限定符“::”来访问不同作用域的全局变量(不能动别人的局部变量)
std::string a;
MyString::string b;
变量的生存期是指在程序执行的过程中,一个变量从创建到被撤销的一段时间,它确定了变量是否存在。变量的生存期与作用域密切相关,一般变量只有在生存后才可见。但作用域与生存期还是有一些区别:作用域是指变量在源程序中的一段静态区域,而生存期是指变量在程序执行过程中存在的一段动态时间。有些变量(函数参数)没有生存期,但是有作用域;有些变量虽然在生存期,但却不在作用域。
存储类型
当执行C++程序时,系统除了为程序可执行代码分配内存,还为不同存储属性的变量分配不同类型的内存空间,系统为变量分配内存的方式决定了变量的作用域和生存期。C++程序中的变量有3种内存分配方式:静态分配、自动分配和动态分配。
系统可以为每个程序分配一个固定的静态存储区,静态分配是指在这个固定区域内为变量分配的内存空间。对于静态分配内存空间的变量,在编译时就分配了内存空间,在程序开始执行时变量就占用内存,直到程序结束时,变量释放。
在程序运行后,系统将为程序开辟一块称为栈的活动存储区,栈按照“后进先出”的方式使用存储空间。自动分配是指在栈中为变量临时分配的内存空间。对于自动分配内存空间的变量,程序运行后,在变量作用域开始时由系统自动为变量分配内存,在作用域结束后即释放内存。
动态分配是指利用一个被称为堆的内存块为变量分配内存空间,堆使用静态存储区和栈之外的部分内存。动态分配是一种完全由程序本身控制内存的使用的分配方式。对于动态分配内存空间的变量,程序运行后,利用new运算符自动分配内存,利用delete运算符或程序结束运行释放内存。
new用于为各种数据类型分配内存,并把分配到的内存首地址赋给相应的指针。new的功能类似于malloc()函数。
<指针变量> = new<数据类型>; //指针变量的类型要于数据类型对应。
int* p;
p = new int; //给单个对象申请分配内存
p = new int(1); //给单个对象申请分配内存并初始化赋值
p = new int[5] //从p开始的五个连续内存空间,每个空间的大小与数据类型有关。
当程序不再需要由new分配的内存空间时,可以用delete释放这些空间。
delete <指针变量>; //删除new给指针变量的内存地址
delete []<指针变量>; //删除new给指针变量的连续内存地址,中括号内不需要说明对象个数
使用new和delete时需注意:
- 用new运算符申请分配的内存空间,必须用delete释放。
- 对于一个已分配内存的指针,只能用delete释放一次。
- delete作用的指针对象必须是由new分配内存空间的首地址。
- 用new运算符为多个对象申请分配内存空间时,不能提供初始化。
初始化变量
所谓的变量初始化,就是对变量一个初始的赋值,此操作可以在变量定义时进行,也可以在定义后再进行。
当定义一个变量时,我们应进行初始化,除了系统会帮我们初始化的变量外(如全局变量,静态变量或外部变量,系统会帮我们初始化成0,null)。对于局部变量,它是在一个堆或栈中如果我们不给它初始化,那我们再用它时就很难决定它的当前状态。
未初始化的变量是C和C++程序中错误的常见来源。养成在使用内存之前先清除的习惯,可以避免这种错误,在定义变量的时候就将其初始化。
变量命名
变量命名于标识符命名相似
- 变量名的第一个字符必须是字母、下划线“_”或@。
- 第一个字符后的字符可以是字母、下划线或数字。
- 由字母(大写A~Z或小写a~z)、数字(0~9)和下划线(_)组成。
- 不能包含除下划线之外的任何特殊字符。
- 不能包含换行、空格、制表符等空白字符。
- 不能包含C++保留字,例如int、main等。
- 要区分大小写,例如temp和Temp是不同的。
- 变量长度无限制,但系统只会取前1024个字符。
- 变量名要有意义,要一看便懂,提高可读性,便于系统维护。
- 如果名称包含一个以上的单词,最好单词首字母大写。
- 在习惯上都趋于用小写字符命名。
常量
常量是指内容固定不变的量,无论程序怎样变化执行,它的值永远不会变。在编程中,常量常用于保存像圆周率之类的常数。
常量分为字面常量和符号常量(又称标识符常量)两种表示方法。如25,−3.26,‘a’,“constant”等都是字面常量,即字面本身就是它的值。符号常量是一个标识符,对应着一个存储空间,该空间中保存的数据就是该符号常量的值,这个数据是在定义符号常量时赋予的,是以后不能改变的。
声明常量时在数据类型前加上const关键字,同时为其赋值。在声明以外的其他地方都不可以再对其进行赋值。
const int Pi = 3.14;
也可以用#define定义常量
#define MAX 8
二者的区别在于:
- const常量有数据类型,而宏常量没有数据类型:编译器可以对const进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换中可能会产生意料不到的错误(边际效应)。
- 有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。在C++程序中只使用const常量而不使用宏常量,即const常量完全取代宏常量。
- 编译器处理方式不同:define宏是在预处理阶段展开;const常量在编译运行阶段使用。
- 存储方式不同:define宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存;const常量会在内存中分配(可以是堆中,也可以是栈中)。
小结
回头再看一次,发现之前还有很多遗漏的细节问题,也有很多模糊不清的地方,真真实实的有不小的收获。