变量和基本类型
1 基本内置类型
c++定义了一套包括算数类型和空类型在内的基本数据类型。
2.1.1 算数类型(前三个是整型)
算数类型包括布尔值(bool),字符(char),整数(int),浮点数(float)。
1.布尔值
布尔值就是在判断语句中常用,非零即ture,零即false。
2.字符
分为char,wchar_t(宽字符),char16_t(unicode,占16bit),char_32(unicode,占32bit)
*后二者在对字符有要求的特殊要求的硬件中使用
3.整数型
short型,int型(16bit,无符号最大值为2的16次方),long int型(32bit),long long型(64bit,c11标准中加入)
4.浮点数型(带小数)
单精度float(6位有效数字),双精度double(10位有效数字),扩展精度long double(10位有效数字,c11标准新加入)
带符号型和无符号型
除去布尔型和扩展字符型,所以类型俱有符号型signed与无符号型unsigned俩种,符号型与无符号型的差别在开始第一bit是否存放符号,符号型存放,所以符号型的最大值为无符号型的0.5倍,最小值是最大值的相反数。
字符型被分为了三种,char,singed char,unsigned char,但却只有俩种表现,char和类型signed char并不一样,因为char会表现为unsigne或signed,具体和使用的编译器有关。
类型选择经验
知道数值不可能为负时,选用无符号类型
使用Int执行整数运算,不够时候在用long long
执行浮点数运算选用double
在算术表达式中不要使用char或bool,因为char在一些机器上有符号,另一些上没有,不然的话就指定到底是有无符号。
2.1.2类型转换
类型转换就是把一种给定类型转换为另一种相关类型,这里书上有几个例子。
bool b=42;//这里是布尔值,非0即1,所以b=1;
int i=b;//i=1;布尔值赋予非布尔值,false=0, ture=1
i=3.14; //i取整数部分,i=3,截取不是四舍五入,只留了小数前面部分
double pi=i; //pi=3.0;整数赋予浮点数,小数部分记为0
unsigned char c=-1;//因为是无符号,赋值为负号,则=该型最大数+该负数,这里=256+(-1)=255
signed char c2=256;//signe取值范围为-128到+128,超出范围,c2为未定义。
***注意,不能将符号型与无符号型混用,(相加相减)计算机会将符号型转换为无符号型,若无符号型为负,按上面unsigned转换一样转化,如果是int类型,会转化成一个很大的正数。
2.13字面值常量
整形字面值可以写成十进制数、八进制数或十六进制数的形式。
以0开头的整数代表八进制数:024 (代表十进制数20)
以0x或0X开头的整数代表十六进制数:0x14或0X14(代表十进制数20)
而20,则表示的是十进制数。
由单引号括起来的一个字符称为char 型字面值,双引号括起来的零个或多个字符则构成字符串型字面值。
转义序列 是被当成一个字符使用‘’,如换行符为\n 空格符为\40 后面数字如何太多,只看前几个。作用主要是某些符号程序员不能直接使用
字面值可以添加前缀后缀来改变默认类型。
P37
2.2变量
变量提供一个有名字的,可供程序操作的存储空间。
2.2.1变量定义
变量的定义首先是变量类型,(类型说明符)之后紧跟一个或多个变量名,变量名之间用“,”隔开。
eg. int a,b;//定义a,b为俩个int型变量。
*****初始化
初始化是在创建变量的时候给予一个特定的值,赋值是把之前的值抹去并赋予一个新的值,是完全不同的俩种操作。
*****初始化的几种形式:
- int a=0;//普通的赋值
- int a(0);//将0赋予a;
- int a{0};//列表赋值法,需要注意的是当使用列表赋值法并且有丢失数据的风险时,会返回error;
- float a=3.14;int b={a};//错误,有丢失数据的风险。改为int b=a;就可以正确执行。
默认初始化
当建立一个变量而未显式初始化(即没有明确地赋予一个值),则变量将被默认初始化。
所有在函数体外部定义的变量默认初始化都是0,若是string(字符串型)则被初始化为一个空字符串。
所有在函数体内部的内置变量将不被初始化。
*类的对象如果没有初始化,其值由类确定。
注意未初始化的变量将带来无法预计的后果
2.2.2变量的声明和定义的关系
c++语言为了支持分离式编译(separate compilation),将声明和定义区分开来。声明(declaration)使得名字为程序所知,一个文件若想使用其他文件的变量需要使用声明符号extern。定义负责创建与名字关联的实体。
变量声明规定了变量的类型和名字,定义多了申请存储空间。
eg:
extern int i; //声明i 而非定义
extern int i = 3; // 变成了定义,在函数体内部,若是初始化一个extern变量,将会error
int j; // 声明并定义
2.2.3标识符
c++的标识符同c语言一样,由数字,下划线,字母表示,必须以字母或下划线开头,不能连续俩个下划线,例如__asd是非法标识符。
且标识符不应该使用c/c++的关键字。
对于命名规范一般有四点不成文的通用习惯:
1.标识符要有实际含义;
2.变量名一般使用小写字母;
3.自定义的类名一般使用大写字母开头;
4.如果标识符由多个单词组成,一般使用_代替空格。
2.2.4名字的作用域
作用域(scope)是程序的一部分,其中名字有特殊的含义。c++中大多数时候以花括号作为作用域的分隔,而名字的作用域始于声明语句,以声明语句所在的作用域末端作为结束。
作用域分为全局作用域和块作用域,亦可以分为外层作用域和内层作用域,内层作用域可以覆盖外层作用域。
2.3复合类型
复合类型是指基于其他类型所定义的类型,这里讲述引用和指针俩种。
2.3.1引用
引用是为变量起了另外一个名字,引用类型引用了另外一种类型。
eg. int a=1;//定义了变量
int &b=a;//b引用a,b与a绑定;
b=0;//b=0等同于a=0的操作。
几条重要规则
*引用必须被初始化,否则会报错
*定义引用时,程序把引用和它的初始值绑定在一起,而不是将初始值拷贝给引用
除了一些特殊情况(常量引用+),引用类型都要和与之绑定的对象严格匹配。
引用只能绑定在对象上,而不能与字面值或某个表达式的计算结果绑定在一起
2.3.2指针
指针是指向(point to)另外一种类型的复合类型。
指针与引用的不同之处:
1.指针本身是一个对象,允许对指针进行拷贝和赋值。
2.指针无需在定义时赋初值。
定义指针类型 就是d的形式 ,其中d是变量名。在多个变量中,这个只是修饰其后变量,对其他变量不产生作用。*的数量没有限制,按照逻辑关系理解。
eg:
int ival=42;
int *p=&ival;// p存放变量ival的地址,或者说p是指向变量ival的指针
double b, *a; //b是double型变量,*a是指向double类型的指针。
int *a=&b;//a指向b?错误,int型指针只能指向int的变量。(指针类型都要和它所指对象严格匹配)
**若要利用指针访问对象,使用解引用符就可以,这里要注意解引用符仅适用于那些确切的指向某个对象的指针。
*p=0;// 经由p为变量ival 赋值。
***同一符号的不同含义
int i=42;//初始化i为42;
int &r=i;//引用操作;
int *p;//定义一个指针变量;
p=&i;//将i的地址赋予p;
p=&i;//将i赋予p;
int &r2=*p;//r2是一个指针的别名,他引用了一个指针。
空指针
空指针不指向任何对象,一般定义如下:
int *a=0;
int *a=NULL;//尽量避免使用。
int a=nullptr;//c++11刚刚引入的方法。
访问未经初始化的指针会引发运行错误,建议初始化所以指针,或者定义为空。
把Int变量直接赋给指针是错误的操作,即使Int变量恰好等于0也不行。
void 指针
可用于存放任意对象地址,一个void 指针存放着一个地址,但是我们并不清楚该地址到底是什么类型的对象,所以无法确定能在这个对象上做什么操作,因此这个东西主要用在作为函数的输入输出,拿它和个别指针比较、或者赋给另外一个void指针。
2.3.3理解复合类型说明
对于复合类型,从右到左阅读有助于弄清他的真实含义。
eg. int *&r=p;//r是一个对指针p的引用。
理解:离变量名最近的符号对变量的类型有最直接的影响,故r 是一个引用,声明符的其他部分用以确定r引用的类型是什么,*符号说明r引用的是一个指针。最后,声明的基本数据类型部分指出r引用的是一个Int指针。