1、C++中认为:void修饰返回值表示:不返回任何值;void修饰参数表列,表示:不接受任何参数、若参数表列里什么也不写,表示:可接受任意类型的参数。
2、C++中规定short <= int <= long <= long long
3、注意隐式类型转换实例:
bool b = 42;// b = 1 ( 因为b为布尔值,非0即1)
int i = b; // i = 1
i = 3.141; // i =3 (因为i为整型值)
double pi = i;// pi = 3.0
unsigned char c = -1;// c = 255 (char型占8bit,(2^8+(-1))% 2^8 = 255)
singed char c2 = 256 // c2 = 未知错误 (当给有符号数一个超出其范围的值,将使程序发生不可预测的结果)
4、当有符号数和无符号数一起计算时,都将转换成无符号数,再进行计算,但尽量避免此类情况的发生。
5、转义序列
换行符 \n 横向制表符 \t 报警(响铃)符 \a
纵向制表符 \v 退格符 \b 双引号 \"
反斜杠 \\ 问号 \? 单引号 \'
回车符 \r 进纸符 \f
泛化的转义字符:\x后的一位或多位十六进制数;\后的1~3位八进制数。例如:
\7 (响铃) \12 (换行) \40(空格)\0(空字符) \115 (字符M)\x4d (字符M)
6、指定字面值的类型
表2.1: 指定字面值类型 | |||
字符和字符串字面值 | |||
前缀 | 含义 | 类型 | |
u | Unicode16字符 | Char16_t | |
U | Unicode32字符 | Char32_t | |
L | 宽字符 | Wchar_t | |
u8 | UTF-8(仅用于字符串字面常量) | Char | |
整型字面值 | 浮点型字面值 | ||
后缀 | 最小匹配类型 | 后缀 | 类型 |
U或u | Unsigned | F或f | float |
L或l | long | L或l | long double |
LL或ll | long long |
|
|
指针字面值:nullptr布尔字面值:true 或 false
C++定义了初始化的多种不同方式,如以下4个语句均可实现定义units_sold并将其初始化为0:
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) ; //正确,转换执行,且确实丢失了部分值
默认初始化:
string 默认初始化一个空字符串;全局变量默认初始化为0;
注意:未初始化的变量是一个不确定的值,使用未初始化的值可能使程序发生不可预测的结果。所以建议为了程序安全考虑,建议变量在定义时一定记得初始化。
8、标识符
a 标识符必须由字母、数字和下划线组成,且以字母或下划线开头;
b c++中所保留的函数或关键字不能用作标识符 ;
c 用户自定义的标志符不可以连续出现两个下划线,也不能以下划线紧跟大写字母开头;
d 定义在函数体外的标识符也不能以下划线开头。
变量命名规则:
a 标识符要能体现实际含义
b 变量名一般用小写字母
c 用户自定义的类名一般用大写字母开头
d 标志符如果由多个单词组成一般单词之间需要有明显的区分,一般以首字母大写或下划线区分
9、引用
a 引用即别名:引用不是对象,它只是对象的一个别名。
b 定义引用时必须对其初始化,且之后不可以更改绑定的对象,也不能定义引用的引用。
c 引用的类型和其绑定的对象之间的类型必须严格匹配,除以下两种情况:
i 初始化常量引用时允许用任意表达式作为初始值,只要求该表达式的结果能转换成引用类型即可。如: double dval = 3.14 ; const int &ri = dval;
ii 允许将一个常量引用绑定到非const对象、字面值、表达式上。如:const int &r1 = (32+5);
10、指针
a 空指针:
几种生成空指针的方式:int *p1 = nullptr;int *p1 = 0; int *p1 = NULL(需要加#include cstdlib);
空指针可用于存放任何类型对象的地址,同时也不能直接操作空指针所指的对象。
b 指向指针的引用:因为引用不是一个对象故不可以定义指向引用的指针,但可以定义指向指针的引用。如 int i = 42; int *p = & i ; int *&r = p 此处的r即为指向指针的引用
指针和引用的区别:
指针是“指向”内存中的某个对象,而引用是“绑定到”内存中的某个对象,他们之间都实现了对象的间接访问,二者的区别主要有:
其一:指针本身就是一个对象,允许对指针进行赋值和拷贝,而且在指针的生命周期中它可以指向不同的对象;而引用不是一个对象,仅仅是对象的一个别名,可以对其赋值,但不可以拷贝,且一旦绑定到某个对象上将无法更改。
其二:指针可以随时进行初始化,即不必定义时;引用则必须在定义时就进行初始化。
11、const限定符
a const修饰的对象一经建立,其值将不能再改变,所以const修饰的变量定义时必须初始化,且之后不可以做左值。
b const int 可以和普通int 值一样的参与算术运算,只要不改变其值,其和普通int值基本没区别。
c const对象的作用域为文件作用域。若要使其在各个文件中共享必须在定义和引用前同时加extern 关键字
d “常量的引用”即“对const的引用”。
i 初始化常量引用时允许用任意表达式作为初始值,只要求该表达式的结果能转换成引用类型即可。
ii 允许将一个常量引用绑定到非const对象、字面值、表达式上。
12、顶层const
a、我们知道,指针本身是一个对象,同时它还可以指向另一个对象,故就存在指针本身是不是常量和它指向的对象是不是常量,这两个相互独立的问题。
顶层const(top-level const)表示:指针本身是个常量,或者任意的对象是常量;
底层const(low-level const)表示:指针所指对象是个常量,底层const只与指针、引用等复合类型的基本类型部分有关。注意:用于声明引用的const都是底层 const。
b、当执行对象的拷贝操作时,常量是顶层const还是底层const区别明显。其中,顶层const不受影响,即执行拷贝操作,被拷贝对象的值不会被改变。但,底层const在执行拷贝操作时,烤入和拷出的对象必须具有相同的底层const资格,或者两个对象的数据类型必须能够转换。一般来说非常量可以转换为常量,反之不行。
13、常量表达式
常量表达式:其值不会改变并且在编译阶段就可以得到计算结果的表达式。字面值和用常量表达式初始化的const对象都是常量表达式。
一个对象是不是常量表达式由它的数据类型和初始值共同决定的。
C++11新标准规定,允许将变量声明为constexpr类型以便编译器来验证变量的值是否是一个常量表达式。声明为constexpr的变量一定是一个常量,且必须用常量表达式进行初始化。
字面值类型:算数类型、引用、指针。指针在定义为constexpr时,初始值必须是nullptr或者0,或者存储于某个固定地址的对象(函数体内定义的变量一般来说并非存放在固定地址当中,因此constexpr指针不能指向这样的变量);同时允许函数定义一类有效范围超出函数体本身的变量,这类变量和函数体外定义的变量一样有固定地址;constexpr修饰的指针,constexpr修饰符只对指针有效,不影响指针所指对象;constexpr修饰的指针可以指向常量也可以指向非常量。
不属于字面值类型:自定义类、IO库、string类型。也就不能定义为constexpr。
补充:部分课后习题答案
练习 2.3
unsigned u = 10;u2 = 42;
std :: cout << u2 - u << std :: endl; // 32
std :: cout << u - u2 << std :: endl; // (2^32-32)%2^32=4294967264 (其中int 型占32bit ,2^32=4294967296)
int i = 10,i2 = 42; //默认为有符号
std :: cout << i2 - i << std :: endl; // 32
std :: cout << i - i2 << std :: endl; // -32
std :: cout << i - u << std :: endl; // 0
std :: cout << u - i << std :: endl; // 0
练习2.5:指出下述字面值的数据类型并说明每组内几种字面值的区别
(a)'a' //字符a ; L'a' //宽字符a ; "a" //字符串a ; L'a' //宽字符型字符串a ; ,
(b)10 //int 10 ; 10u //无符号数10 ; 10L //long int 10 ; 10uL //long unsigned int 10 ;
012 //八进制数表示的10; 0xc/ /十六进制表示的10
练习2.6:下面两组定义是否有区别,有请叙述之
int month = 9 , day = 7 ; //十进制表示的int month = 9 , day = 7 ;编译可通过。
int month = 09 , day = 07 ; //八进制表示的int month = 9(错误了,正确表示法为:month =0 11), day = 7 ;编译无法通过,改后可以。
练习2.9:解释下列定义的含义。对于非法的,说明其错误原因并改正
(a) std :: cin >> int input_value ; //非法,输入运算符后面必须跟一个明确的已经定义好的变量名而不是定义变量语句。改正:int input_value ;std :: cin >> input_value ;
(b) int i = {3.14} ; //非法,因为用{}进行初始化时发生信息丢失会报错,程序无法编译执行。改正:int i = (3.14) 或 float i = {3.14};
(c) double salary = wage =9999.99; //非法,声明多个变量需要用,将其隔开。改正:double salary , wage ;salary = wage =9999.99;
(d)int i = 3.14 ; //合法,但会警告。建议改为:float i = 3.14;
练习2.27:下面那些初始化是合法的?说明原因
(a)int i = -1,&r = 0 ; //不合法,因为其是普通的引用而非常量引用,所以不能用字面值
(b)int * const p2 = &i //合法的,常指针可以指向普通的指针
(c)const int i = -1 , &r = 0 //合法,常量引用可以直接使用字面值
(d)const int * const p3 = &i //合法,只是p3将永远指向&i,不可以改变其指向,同时也不可以通过p3来更改i的值
(e)const int *p1 = &i ; //合法,只是不能通过p1来更改i的值
(f)const int &const r2 ; //非法,引用本身不是对象,所以不可以对引用再加const即最左边的const错误,同时,引用必须初始化。
(g)const int i2 = i ; &r = i //合法,常量引用可以绑定到非常量引用上。
练习2.28:说明下面的定义的意义,挑出其中不合法的
(a)int i ,*const cp ; //不合法,i是普通的int型OK,但cp为常指针,其指向不可以改变,所以必须初始化
(b)int *p1, * const p2; //不合法,p1为普通指针,OK;但p2同cp一样为常指针,其指向不可以改变,所以必须初始化
(c)const int ic , &r = ic; //不合法,ic 为const int型变量,所以必须初始化;若ic已初始化,r为其常量引用,OK。
(d)const int * const p3 ; //不合法,同cp一样,p3为常指针,其指向不可以改变,所以必须初始化
(e)const int *p ; //合法,但是p没有初始化,如若直接使用会造成不可预知的结果,所以不建议如此使用。
练习2.29:假设已经有了上一个练习中定义的那些变量,则下面的哪些语句是合法的?并说明原因
(a)i = ic ; //合法,只要不改变const int 型的变量的值,其使用方法和普通int型没区别,所以合法
(b)p1 = p3 ; //不合法,const类型的指针可以接受非const的指针但反过来非const类型的指针不可以接受指向const变量的指针
(c)p1 = ⁣ //不合法,普通指针不可以指向常变量;反过来常指针可以指向普通变量
(d)p3 = ⁣ //不合法,p3是一个常指针,不可以改变其指向
(e)p2 = p1; //不合法,p2是常指针,不可以被赋值
(f)ic = *p3 ; //不合法,ic是常变量,不可以被赋值
p57页例子
int i = 0;
int *const p1 = &i ; //顶层const,指针p1自身不可改变
const int ci = 42 ; //顶层const,ci本身不可改变
const int *p2 = &ci ; //底层const,指针p2所指内容不可改变
const int *const p3 ; //前一个const是底层const,表示p3所指内容不可改变;后一个const是顶层const表示p3本身不可改变
const int &r = ci ; //底层const,所有修饰引用的const均为底层const
p58页例子(部分变量定义见上题)
int *p = p3; //错误,p3包含底层const定义,而p没有
p2 = p3; //正确,p2和p3都具有底层const
p2 = &i; //正确,非const可以转换成const
int &r = ci; //错误,非const类型的引用无法绑定到const类型的变量上
const int &r2 = i //正确,const类型的引用可以绑定到非const类型上