2.变量和基本类型
2.1基本内置类型
2.1.1算数类型
算数类型:
整形(字符型,布尔型)
浮点型
算数类型尺寸:
该数据类型所占的比特数
类型 含义 最小尺寸 值
bool 布尔类型 未定义 真(true)或(false)
char 字符 8位
wchar_t 宽字符 16位
char16_t Unicode字符 16位
char32_t Unicode字符 32位
short 短整型 16位
int 整型 16位
long 长整型 32位
long long 长整型 64位
float 单精度浮点数 6位有效数字
double 双精度浮点数 10位有效数字
long double 扩展精度浮点数 10位有效数字
char大小 = 机器字节大小
long long>=long>=int>=short
带符号类型和无符号类型
unsigned int = unsigned
char:有可能表现为signed char,也有可能表示unsigned char,视编译器不同而不同
signed char
unsigned char
如何选择数据类型:
*明确数据不为负数,用unsigned数据类型
*int执行整数运算
*double执行浮点数运算
选型示例
银行利率,本金,付款的数据类型选择,都是double型
原因:利率本金付款都可能是整数或者实数,因此应该是浮点数运算,据上面总结用double类型最合适
2.1.2类型转换
bool b = 42; //b为真
int i = b; //i的值为1
i = 3.14; //i的值为3
double pi = i; //pi的值为3.0
unsigned char c = -1; //假设char占8比特,c的值为255
signed char c2 = 256;//假设char占8比特,c2的值是未定义的
*非bool—>bool
0 —>false
非0—>true
*bool—>非bool
false—>0
true —>1
*浮点数—>整型
保留浮点数中小数点之前的部分
*整型—>浮点数
小数部分记为0,如果该整数所占空间超过浮点类型的容量,精度可 能有损失
*用无符号类型表示超过其范围的数
此数对无符号类型表示数值总数取模后的余数
*用带符号类型表示超过其范围的数
结果是未定义
*不要混用unsigned和signed在一个表达式中
2.1.3字面值常量
八进制:0开头的整数,\XXX(后面3位才是8进制)
十进制:
十六进制:0x或者0X开头的整数,\x
字符常量:’a’
字符串字面常量:”hello world”(最后还有‘\0’)
字符和字符串字面值
前缀 含义 类型
u Unicode16字符 char16_t
U Unicode32字符 char32_t
L 宽字符 wchar_t
u8 UTF-8(仅用于字符串字面常量) char
整型字面值
后缀 最小匹配类型
u/U unsigned
l/L long
ll/LL long long
浮点型字面值
后缀 最小匹配类型
f/F float
l/L long double
bool字面值
false true
指针字面值
nullptr
2.2变量
2.2.1变量定义
类型说明符+变量名,变量名…;
例如:
int sum = 0,value,units_sold = 0;
Sales_item item;
std::string book(“0-201-78345-X”);
对象:具有某种数据类型的内存空间,能被程序修改的数据
值:只读数据
初始值
初始化:对象创建时获得了一个特定的值
例如:
double prince = 109.99,discount = price*0.16;
double salePrice = applyDiscount(price,discount);
初始化:不是赋值,创建变量时赋予其一个初始值
赋值:把对象当前值檫除,用一个新的值替代
列表初始化
int units_sold = 0;
int units_sold = {0};
int units_sold{0};
int units_sold(0);
long double ld = 3.1415926536;
int a(ld),b = {ld};//错误,转换未执行,因为存在丢失信息的危险
int c(ld),d = ld;
默认初始化
内置类型的变量未被显示初始化,定义于任何函数体之外被初始化为0
定义在函数体内部不被初始化
类对象没有显示初始化,其值由类确定
std::string empty;`//empty非显式的初始化为一个空串
Sales_item item; //被默认初始化的Sales_item对象
2.2.2变量声明和定义的关系
声明:使名字被程序所知
定义:创建与名字关联的实体
extern int i; //声明i并非定义i
int j; //声明并定义j
extern double pi = 3.1415;//定义
变量只能被定义一次,但是可以被多次声明
c++是静态类型语言,在编译阶段检查类型(类型检查)
对象类型决定了对象所能参与的运算,在c++语言中编译器负责检查数据类型是否支持要执行的运算,如果不支持,报错并不会生成可执行文件
2.2.3标识符
必须以下划线_或者字母开始
大小写敏感
用户自定义的标识符不能连续出现两个下划线
不能以下划线_紧邻大写字母开头
定义在函数体外的标识符不能以下划线_开头
标识符要体现具体含义
变量用小写字母,例如int index,不要写成int Index或者int INDEX
用户自定义类以大写字母开头,例如:Sales_item
如果标识符有多个单词组成,单词之间要明显区分开来,例如:stdudent_loan或者stdudentLoan,不要写成stdudentloan
2.2.4名字的作用域
作用域
同一个名字在不同作用域中可能指向不同的实体
名字的有效区始于名字的声明语句,以声明语句所在的作用域末端结束
全局作用域
块作用域
在对象第一次被使用的地方附近定义这个对象
嵌套的作用域
内层作用域
外层作用域
#include
int reused = 42;
int main()
{
int unique = 0;
std::cout<" " <::endl;
//使用全局变量reused;输出42,0
int reused = 0;
std::cout<" " <::endl;
//使用局部变量reused;输出0,0
std::cout<<::reused<<" "<::endl;
//显示访问全局变量reused;输出42,0
return 0;
}
如果函数有可能用到某全局变量,则不宜在定义一个同名的局部变量
2.3复合类型
基于其他类型定义的类型
引用和指针
2.3.1引用
为对象起了另一个名字
int ival = 1024;
int &refVal = ival;
//refVal是ival另外一个名字
int &refVal2;
//报错,引用必须被初始化
绑定
引用即别名
为一个已经存在的对象起另外一个名字
引用的定义
int i = 1024,i2 = 2048;
//i和i2都是int
int &r = i,r2 = i2;
//r是一个引用,与i绑定在一起,r2是int
int i3 = 1024,&ri = i3;
//i3是int,ri是一个引用,与i3绑定在一起
int &r3 = i3,&r4 = i2;
//r3和r4都是引用
引用类型要和绑定的对象严格匹配
引用只能绑定在对象上,不能绑定字面值或者某个表达式计算结果
int &refVal4 = 10;
//错误,引用类型的初始值必须是对象
double dval = 3.14;
int &refVal5 = dval;
//错误,引用类型和绑定对象要是同一个类型
2.3.2指针
指向另外一种类型
指针本身就是一个对象,允许对指针赋值和拷贝,在指针生命周期内,它可以先后指向几个不同的对象
指针无需在定义时赋初值,在块作用域内,如果不赋初值,它将拥有一个不确定的值
int *ip1,*ip2;
//ip1,ip2都是指向int型对象的指针
double dp,*dp2;
//dp2是指向double型对象的指针,dp是double型对象
获取对象的地址
int ival = 42;
int *p = &ival;
double dval;
double *pd = &dval;
double *pd2 = pd;
int *pi = pd;
//错误,指针pi类型和pd类型不匹配
pi = &dval;
//错误,试图把double类型对象的地址赋给int
利用指针访问对象
解引用符(操作符*)
int val = 42;
int *p = &val;
cout<<*p;
*p = 0;
cout<<*p;
&和*多重含义
int i = 42;
int &r = i;//引用,r是i的别名
int *p;//声明,p是指针
p = &i;//&取地址
*p = i;//*解引用
int &r2 = *p;//&引用,*解引用
空指针
不指向任何对象
int *p1 = nullptr;//等价于int *p1 = 0;
int *p2 = 0;//直接将p2初始化字面量0
int *p3 = NULL;//要#include ,等价于int *p3 = 0;
NULL预处理变量
int zero = 0;
pi = zero;//错误,不能把int变量直接赋值给指针
初始化所有指针变量为0或者nullptr
赋值和指针
一旦定义了引用,就无法在绑定到另外对象
指针可以指向其他对象
int i = 42;
int *pi = 0;//pi被初始化,但没有指向任何对象
int *pi2 = &i;//pi2被初始化,存有i的地址
int *pi3;//如果pi3定义在块内,则pi3的值无法确定
pi3 = pi2;//pi3和pi2指向了同一个对象i
pi2 = 0;//pi2不指向任何对象
赋值永远是改变等号左边的对象
pi = &val;//pi的值改变了,现在pi指向了ival
*pi = 0;//val的值被改变了,指针pi并没有改变,指针pi指向的对象发生改变了
其他指针操作
int ival = 1024;
int *pi = 0;
int pi2 = &ival;
if(pi)//pi的值是0,因此条件是false
//
if(pi2)//pi2指向ival,因此条件是true
//
任何非0指针对应的条件值都是true
==与!=
他们都为空
指向同一对象
指向一个对象,指向另一对象的下一地址
void*指针
可以存放任意对象的地址
double obj = 3.14,*pd = &obj;
void *pv = &obj;//obj可以是任意类型的对象
pv = pd;//pv可以存放任意类型的指针
拿它和别的指针作比较
作为函数的输入或者输出
赋值给另一个void*
不能直接操作void*指针所指对象
2.3.3理解复合类型的声明
int i = 1024,*p = &i,&r = i;
//i是int型数,p是一个int型指针,r是一个int型引用
定义多个变量
指向指针的指针
int ival = 1024;
int *pi = &ival;//pi指向一个int型数
int **ppi = π//ppi指向一个int型指针
指向指针的引用
int i = 42;
int *p;
int *&r = p;//r是一个对指针p的引用
r = &i;//r引用了一个指针,因此给r赋值&i就是令p指向i
*r = 0; //解应用r得到i,也就是p指向的对象,将i的值改为0
从右往左读取和理解变量
2.4const限定符
const int bufsize = 512;
2.4.1const的引用
2.4.2指针合const
2.4.3顶层const
2.4.4constexper和常量表达式
2.5处理类型
2.5.1类型别名
2.5.2auto类型说明符
2.5.3decltype类型指示符
2.6自定义数据类型
2.6.1定义Sales_data类型
2.6.2使用Sales_data类
2.6.3编写自己的头文件