第二章 变量和基本类型
2.1基本内置类型
2.1.1算术类型
包括整型和浮点型,C++11规定char最小8位,int最小16位,long long最小64 位,允许编译器赋予它们更大的尺寸如float32位。其中,char对应一个机器字节。
可寻址的最小内存块:字节(byte),有8位.
一个字(word)通常有4个字节,32位。
signed char理论上表示-128-127的值。
当知晓数值不可能为负数的时候,用unsigned无符号类型。
2.1.2类型转换(convert)
bool b = 42; // b =1
int i = b; // i = 1
i = 3.14; // i = 3,只保留浮点数整数部分。
double p = i; // p = 3.0
unsigned char c = -1; // c = 255,无符号数超出范围mod256
//原理 0 - 1,而unsigned 0-255
signed char c2 = 256; /
//当我们给有符号数赋予超出范围的数值后,undefine.
unsigned u = 10;
int i = -42;
std::cout<< u + i << std::endl;
//输出4295967264,unsigned int大小取模后的结果
另一个很经典的例子,408曾经考过,一直循环,
i = 0后减一得到2int
for(unsigned int i = 10;i>=0;i--)
std::cout << i << std::endl;
2.1.3字面量(literal)
整型和浮点型字面量
字符和字符串字面量
转移序列 \n \t \字符 一般只看前三位,注意反斜杠
指定字面量的值 。。。 疑问:真的有用吗?
2.2变量
变量是可供程序操作的存储空间。
2.2.1变量定义
初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,以一个新的值代替。
列表初始化,用花括号初始化变量。
int units_sold = 0;
int units_sold = {0};
int units_sold{0}'
int units_sold(0);
建议初始化每一个内置类型的变量,简单可靠的防止访问未初始化变量中不确定值产生的错误。
2.2.2变量声明和定义的关系
C++支持分离式编译。
声明:使变量名字被程序所知,因为分离式编译的程序可能有多个文件,
一个文件可能要使用另一个文件的变量名,因此要声明一下。
extern int i ; // 声明i而非定义i
int j ; // 定义j
注意:声明不要显式初始化变量,即赋值。
C++是一门静态类型的语言,其在编译阶段检查类型。
编译器会检查数据类型是否支持要执行的运算。
2.2.3标识符
int somename, someName, SOMENAME;
标识符必须由字母或下划线开头,大小写敏感,不能是关键字名字
定义在函数体外的标识符不能以下划线开头。
变量命名规范:
1.变量名一般用小写字母,如 index,不要使用 Index
2.用户自定义的类名一般大写字母开头,如 Sales_item
3.多个单词加下划线,如 student_loan, 不要使用studentloan
若能坚持,必将有效。
2.2.4名字的作用域
作用域Scope大多数以花括号隔开,
2.3复合类型
复合类型包括引用和指针。
引用是为对象起了另一个名字。
引用本身并不是一个对象,一旦定义了引用,就无法再将它绑定到其他对象上。
int i = 1024;
int &r = i;
r的值和i一直绑定。
指针是本身就是一个对象,允许对指针进行赋值和拷贝,也无需在定义时赋初值。定义时,变量符号前必须有 *
获取对象的地址
int ival = 42;
int *p = &ival;
指针存放某个对象的地址。
利用指针访问对象
int ival = 42;
int *p = &ival;
cout << *p;
如果指针指向了一个对象,
则允许使用解引用符*来访问该对象。
给解引用符指向的对象赋值,相当于给该对象赋值。
关键概念:有些符号具有多重含义
int i = 42;
int &r = i; //引用
int *p; // 定义p指针
p = &i;
*p = i;
int &r2 = *p;
空指针不指向任何对象。
int *p1 = nullptr; //字面量nullptr初始化指针
int *p2 = 0;
int *p3 = NULL;
三者等价,都是定义空指针。
建议:初始化所有指针。
如果使用了未经初始化的指针,则该指针的所占内存空间的当前内容将被看做一个地址值。访问该指针,相当于访问一个本不存在的位置上的本不存在的对象,如果该地址中恰有内容,就会产生十分棘手的问题。
2.3.3理解复合类型的声明
int i = 1024, *p = &i, &r = i;
基本数据类型只有一个,但声明符的形式却可以不同,也就是说一条定义语句中可能定义出不同类型的变量。
指向指针的指针
2.4const限定符
const ing buff_size = 512;
编译器会在编译过程中把用到buff_size的地方全部替换成512,
仅在文件内有效,不同文件用const需要对该变量重复定义,
解决办法是在各个文件中,不管是声明还是定义都添加extern关键字
file1.cc中:
extern const int buffsize = fcn();
--------
file1.h中
extern const int buffsize;
2.5处理类型
类型别名: 有助于理解使用该类型的真正目的。
typedef double wages; // wages和double是同义词
typedef wages base, *p; // p 是 double* 的同义词
另外一种别名声明的方式
using SI = Sales_item; // 同义词
P61 指针、常量和类型别名没看懂
2.5.2 auto类型
auto 可以让编译器替我们分析表达式所属的类型,通过初试值来推算变量的类型,显然,auto定义的变量必须有初试值。
auto item = Sales_item1 + Sales_item2;
item 类型为Sales_item
auto i = 0, *p = &i;
2.5.3decltype类型
有时希望从表达式的类型推断要定义的变量的类型,但是不想用该表达式的值初始化变量,因此引入decltype ,他的作用是选择并返回操作数的数据类型。
const int ci = 0, &cj = ci;
decltype(ci) x = 0; // x的类型是const int
decltype(cj) y = x; // y的类型是const int& , y绑定x
decltype(cj) z; // 错误,z是一个引用,必须初始化
int i = 42, *p = &i, &r = i;
decltype(r+0) b; //正确,b是一个未初始化的int
decltype(*p) c; // 错误,c是int&,必须初始化