第2章:变量和基本数据类型
2.1 基本内置数据类型
C++的内置数据类型包括了算数类型和空类型
2.1.1 算术类型
算数数据有两类:
- 整形(这里面包括了字符型(char)和布尔类型(T or F))
- 浮点型(单精度float,双精度double)
其中char占一个字节,int占四个字节
注意:当使用浮点数运算时一般用double,因为float通常精度不够,而两者实际的计算代价相差无几
2.1.2 类型转换
当我们将两种不同的数据类型进行运算时,程序会自动的进行类型转换
这种类型转换被称为强制类型转换
2.1.3 字面值常量
字面值常量的形式和值决定了它的数据类型,我们可以通过它一眼看出值的类型
比如:看到42就知道整形,4.2是浮点型
字符和字符串字面值
而字符型的字面值则是由单引号括起来,如 'a'
字符串的字面值则是由双引号括起来,如 "abcd"
注意:
- 字符串实际上是由常量字符构成的数组
- 编译器会在字符串的结尾添加一个空字符('\0'),因此字符串的实际长度要比所含字符多一个长度
如:(字符串) "A" ,实际上所占两个字符,分别为本身的字符 'A' 和编译器添加的 '\0'
而字符 'A' ,实际上所占就是本身一个字符
2.2 变量
变量的本质是一个拥有名字,可以操作的存储空间。
可以将变量理解为一排 ”保险柜“ ,变量存储空间的大小就相当于 ”保险柜“的大小,不同的数据类型的变量就相当于不同种类的”保险柜“ 。
而对象则更像是一种特殊的变量,因为对象的定义就是具有某种数据类型的内存空间。
2.2.1 变量定义
定义与声明的区别
定义语法:数据类型 变量名
声明语法:extern 数据类型 变量名
在C++中定义与声明是有所区别
-
定义变量时,系统会开辟一块存储空间,然后还有一串16进制的数字来表示空间地址,我们就通过变量名代替这串数字来访问这块空间。
可以简单理解为 我们新开了一个 ”保险柜“ ,并有着与其相对于号码牌的钥匙。而变量名就是这个带编号的钥匙
-
声明变量时,系统并不会开辟新空间,而是告诉编译器,这个变量已经存在了,接下来可以直接使用
声明变量并不是新开一个”保险柜“,而是提醒编译器,在之前已经有一个一样的”保险柜“了
声明的作用,为了实现多个文件中的代码共享,仅定义一次变量后,可以通过多次声明在不同的文件中使用
所以,我们在声明变量的时候不会为其显示初始化,因为这样就变成了定义,而失去了声明原本的意义
初始值
当定义变量的时候获得一个特定值,它就被初始化了
-
初始化的值不一定要求数值型,也可以是任意复杂的表达式
-
如果我们不显式的给出初始值,内置的数据类型变量会根据定义的位置决定
- 定义在函数外的变量都会被初始化为0
- 定义在函数内则不初始化
如:double price=109.99,discount=price*0.16
初始化和赋值的区别
在C++中,初始化和赋值是两种不同的操作
int a=1; //定义变量的时候得到了一个初值1,这是初始化
int b;//根据位置,可能初始化,也可能不初始化
b=2;//擦去原有的值,用2代替,这就是赋值
- 初始化是在创建变量时给其一个初始值
- 赋值是把当前变量的值擦除,而用一个新值代替
2.2.2 标识符
C++标识符由字母,数字以及下划线组成,其中必须以字母或下划线开头
不能使用关键字作为标识符
2.3 复合类型
基于其他类型定义的类型,指针和引用就是复合类型。
2.3.1 引用
引用是为变量起另一个名字。
当我们把变量当成一个 ”保险柜“ ,变量名就是 ”带编号的钥匙“ ,而定义引用就相当于给 “保险柜” 再设置一个备用钥匙。
语法:
int a=10;
int &A=a; //A是a的另一个名字
int &A; //错误,引用必须初始化
- 为引用赋值,实际上是把值赋给了与引用绑定的对象
这里的意思是,我们通过备用钥匙来操作"保险柜"的存取等功能,实际对象还是原本的”保险柜“
定义:
大部分引用的数据类型要和所绑定的变量严格匹配,并且只能绑定在变量上,不能绑定字面量等。
注意:
- 当我们定义引用时,引用的初始值就与变量绑定在一起,就不能将引用重新绑定在其他变量上。
就是说,当我们给一个 "保险柜" 设置 "备用钥匙" 之后,这个 "备用钥匙" 就不能再开其他柜子了
- 引用定义时就必须为其初始化
我们在配置备用钥匙的时候,必须要有原本的钥匙才行
- 强调:引用并非变量,而是将已有的变量起另外一个名字
引用只是备用钥匙,而不是柜子
2.3.2 指针
指针本身就是一个变量,存放的其他变量的地址,允许对指针赋值和拷贝,可以先后指向不同变量。
所以指针本身也是一个小柜子,只不过里面只存放“钥匙”
获取对象地址
指针存放着某个变量的地址,使用取地址符( & )获取地址。
语法:
int a=10;
int *p;
int *p=&a;
上述这段话的意思,可以将其理解为, “将a柜子的钥匙,放到p柜子里”
注意:
- 大部分指针类型要和它指向的变量类型严格匹配
指针值
指针的值(地址)应属于下列4种状态
- 指向一个对象(放着柜子的钥匙)
- 指向紧邻对象所占空间的下一个位置(放着不知道哪的钥匙)
- 空指针(没钥匙)
- 无效指针,上述之外的情况
注意:
- 尽管2,3种形式的指针有效,但它们并没有指向任何具体对象,所以此类指针不能被访问
利用指针访问对象
如果指针指向了一个对象,则运行用解引用符( * )来访问该对象
int a=42;
int *p=&a;
cout<<*p //输出 42
注意:
& 和 * 的多重含义
int i=10;
- 如果 & 跟着类型名出现,是引用
int &r=i;
- 如果 * 跟着类型名出现,是指针
int *p;
- 如果 & 出现在表达式中,就是取地址符
p=&i;
- 如果 * 出现在表达式中,就是解引用符
*p=i;
解引用仅适用于确实指向某个对象的有效指针
空指针
空指针不指向任何对象,在试图使用一个指针代码之前,先检查其是否为空
int *p1=nullptr; //等价于int *p1=0;
int *p2=0;
int *p3=NULL; //等价于int *p1=0;
注意:初始化所有指针
如果使用了未初始化的指针,则它当前所占内存空间将被看作一个地址值,去访问一个本不存在的对象
赋值和指针
- 赋值永远改变的是等号左侧的对象
- 指针里面只能存放地址
int a=10;
//int *p=a; //错误 指针里面只能存放地址
int *p=&a; //正确,指针p的初始值改变,现在指向a的地址
*p=20; //正确, 指针p解引用,实际改变a的值
2.3.3 理解复合类型的声明
指向指针的指针
通过 ***** 的个数,可以区分指针的级别, ****** 表示指向指针的指针
就是将 “钥匙” 到第一个指针内,然后将第一个指针的 “钥匙” 放到第二个指针内
int a=10;
int *pi=&a; //将a的钥匙放入p内
int **ppi=&pi //将pi的钥匙放入ppi内
\
2月22日更新