此外,void 为空类型,即当函数不返回任何值时以空类型作为返回类型。
1,内置类型的机器实现计算机以比特序列来存储数据,每个比特非 0 即 1 ,例如:0001101101111011100111…
比特 < 字节 < 字
大多数情况下
字节 = 8 比特;字 = 4 字节 / 8 字节 = 32 比特 / 64 字节。 2,字符和字符串字面值
由单引号括起来的字符称为 char 型字面值,双引号括起来的零个或多个字符则构成字符串字面值。
字符串字面值:实际上是由常量字符构成的数组,编译器会在每个字符串的结尾处添加一个空字符(’ '),因此**字符串字面值的实际长度要比它的内容多 1 **。 二、变量 1,初始化
初始化:创建变量时赋予一个初始值。
赋值:把对象当前的值擦除,而以一个新值来代替。
2,变量的声明和定义初始化不是赋值!
声明:声明使得名字为程序所知,一个文件如果想使用别处定义的名字则必须包含对那个名字的声明。
定义:定义则负责创建与名字相关联的实体。
extern int i; //声明 i 而非定义 iint i; //声明并定义 i
3,变量的命名规范标识符要能体现具体含义变量名一般用小写字母,如 index,不要使用 Index用户自定义的类名一般以大写字母开头,如 Sales_item如果标识符由多个单词组成,则单词间应有明显区分,如 student_loan,或 studentLoan ,不要使用 studentloan。 三、复合类型 1,引用
引用为对象起了另外一个名字(引用不是一个对象,只是一个名字)。具体来说,定义引用时,程序把引用和它的初始值对象绑定在一起,而不是将初始值拷贝给引用。一旦引用初始化完成,引用将和它的初始值对象一直绑定在一起。(即必须赋初值)
int val = 1024;int &ref_val = val; // 正确的引用: ref_val 指向 val
引用只能绑定在对象上(且必须类型一样),而不能与字面值或某一个表达式的计算结果绑定在一起。
int val = 1024;int ref_val = 1024; // 错误!
定义一个引用后,对引用的所有操作都是在与之绑定的对象上进行的。(包括赋值,获取值…等)由于引用不是对象,因此不能定义引用的引用。 2,指针
指针也能实现对其他对象的间接访问,但是指针本身是一个对象,可以进行正常的赋值和拷贝;在指针的生命周期内可以赋值给多个对象。
指针存放某个对象的地址
int val = 24;int *p = &val; // 等式右边找地址,等式左边存地址
如果指针指向了一个对象,则允许使用解引用符 * 来访问该对象。
int val = 24;int *p = &val; cout << *p; //这里的*指的是解引用,上面的*是声明指针类型,用法不同!
像 & 和 * 这样的符号,既能当表达式里的运算符,也能作为声明的一部分出现,符号的上下文决定了它的用法。
1,如果 & 和 * 紧挨着类型名出现,那它就是声明的一部分int *p1 = nullptr;int * p;
2,如果 & 和 * 出现在表达式里,那就是 取地址 和 解引用 符
p = & val;
空指针
int *p1 = nullptr; //建议使用
nullptr 是一种特殊类型的字面值,它可以被转换成任意其他类型的指针类型。
int *p1 = 0;
将指针直接初始化为字面值 0 。
int *p1 = NULL; //尽量避免使用
NULL 是一个预处理变量。预处理器是在编译之前先运行的一段程序,在遇到一个预处理变量时,预处理器会直接将其替换成实际值。因此用 NULL 和用 0 效果相同。
Tips:建议初始化所有的指针。
指针的赋值
记住一个原则:赋值改变的永远是等号左侧的对象
p = &val; // p是指针,指针被改变说明指针指向的对象变成了val,p存放的地址值也被改变*p = 0; // *p是被p指向的对象,该赋值语句将该对象赋值为0
四、const 限定符 1,定义常量 有时候我们希望定义一种变量,它的值不能被改变,这时候就需要用 const 来修饰这个变量。
这时候,bufsize 就从变量变成了常量。
const int bufsize = 512; // 常量的初始化
常量不允许被赋值和修改,任何试图对常量 bufsize 进行赋值的行为都将引发错误。const 对象必须被初始化。
bufsize = 512; // 错误,常量不能赋值!const int bufsize; // 错误,没有初始化常量!
2,对常量的引用可以使用 const 对 const 对象进行引用,称为对常量的引用。
注意:引用常量对象时必须使用常量引用,否则会报错。
const int r = 1024;const int &r1 = r; // 引用是常量,被引用的对象也是常量int &r2 = r; // 错误!不能用非常量引用引用常量对象
3,常量引用可以使用 const 对非常量对象进行引用,称为常量引用。
int r = 1024;const int &r1 = r; // 可以使用常量引用引用变量const int &r2 = 2048; // 可以使用常量引用引用数值const int &r3 = r * 2 + 1; // 可以使用常量引用引用表达式
但是为什么常量引用能被多类型初始化呢?引用的规定不是说过被引用对象和引用必须是同类型吗?
第一个例外情况:在初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可。
原因:
以下面一段代码为例double val = 3.14;const int &p = val;
此处引用类型是 int ,但是 val 类型却是双精度浮点数,编译器为了确保让 p 绑定一个整数,编译器会先经过如下过程:
double val = 3.14;const int temp = val; // 编译器由双精度浮点数生成一个临时的整型变量const int &p = temp; // 再让 p 绑定这个临时量
这个临时量对象是指:当编译器需要一个空间来暂存表达式的求值结果时临时创建的一个未命名的对象。
虽然说常量引用可以引用变量,但是变量不能由常量引用定义的别名去改变。
int i = 1024;int &p1 = i; // p1正常引用const int &p2 = i; // p2常量引用p1 = 0; // 正常引用修改绑定对象的值,合法。p2 = 0; // 错误!无法通过常量引用改变被绑定对象的值
4,指针与 const指向常量的指针(常量不变)
指向常量的指针和常量引用一样,只是不能通过指针来改变对象的值,没说不能通过其他途径改变对象的值。
存放常量的地址,只能用指向常量的指针。
const int val = 1; // 常量const int *p = &val; // 指向常量的指针
常量指针(指针不变)
简单来说就是,指针是一个常量。指针的指向(地址)不能改变,但是指针指向的值可以改变。
int num = 0;int *const p = # // 常量指针 p 指向了 num 的地址*p = 1; // p 指向的内容可变,合法。
5,顶层const、底层const顶层 const:表示对于任意的对象它本身是常量。底层 const:表示指针或引用所指的对象是常量。
例如在执行拷贝操作时,对于顶层 const 而言没什么影响,因为拷贝不会改变被拷贝对象的值;但对于底层 const 而言就不能忽视,拷入和拷出的对象都必须有相同的底层 const 资格,或者两个对象的数据类型必须能够相互转换,否则就不行。
五、处理类型 1,类型别名类型别名是一个名字,它是某种类型的同义词。
利用 typedef 定义别名
typedef double newdouble; // newdouble 是 double 的别名typedef newdouble *ddouble; // ddouble 是 *double 的别名
利用 using 定义别名
using dddouble = double; // dddouble 是 double 的别名
2,auto 类型说明符在赋值时,auto 让编译器通过初始值来推算变量的类型,而不需要程序员自己判断。因此,用 auto 定义变量时一定要有初始值。
auto val = val1 + val2; // val会初始化为val1与val2相加的结果
使用 auto 引入可以在一条语句中声明多个变量,但其基本数据类型必须一样。
auto i = 0, *p = &i ; // 整数和整型指针,合法auto sz = 0, pi = 3.14; // 错误!整型和浮点型。
3,decltype 类型指示符decltype 可以选择并返回操作数的数据类型。在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值。
decltype(f()) sum = n; // decltype将函数f()调用时的返回类型作为sum的类型
使用 decltype 时,它会返回包括顶层 const 和引用在内的完整数据类型。
const int i = 0, &j = i;decltype(i) x = 0; // i 是顶层const,x的类型也是顶层constdecltype(j) y = x; // j 是顶层const引用,y的类型也是 const int & ,y被绑定给x。decltype(j) z; // 错误!引用必须初始化。
如果 decltype 的表达式是加上了括号的变量,结果将是引用。
int i = 0;decltype((i)) d; // 错误!d 的类型是int& ,必须初始化decltype(i) e; // 合法,e 的类型是int
**原因:**赋值语句是可以产生引用的一类典型表达式。如果 decltype 里是一个赋值语句,那么返回的类型便是引用;而变量是可以看成赋值语句左值的特殊表达式,如果在 decltype 里对变量加括号,编译器就会将其看成一个表达式,返回值就会是引用了。