自己写的C++11 Primer Plus 学习笔记,如有雷同不胜荣幸,如有错误敬请指正
1. 开始
1. main函数
建议使用 int main() 并且可选return 0; (因为编译器默认添加);
避免使用 void main() 因为它可能在一些系统上无法工作。
2. 头文件名
头文件命名约定| 头文件类型 | 约定 | 事例 | 说明 |
|---|---|---|---|
| C++旧风格 | 以.h结尾 | iostream.h | C++程序可以使用 |
| C旧风格 | 以.h结尾 | math.h | C,C++程序可以使用 |
| C++新式风格 | 没有扩展名 | iostream | C++程序可以使用,使用 namespace std |
| 转换后的C | 加上前缀 c,没有扩展名 | cmath | C++程序可以使用,可以使用不是C的特性,如:namespace std |
3. 名称空间: using namespace std
4. cout输出:
1. cout<<endl(换行) 可以确保程序继续运行前刷新输出,而\n不能提供这样的确保。
2. dec, hex, oct : 分别指示 cout 以十进制,十六进制,八进制格式显示整数。
3. cout 一般会删除浮点数结尾的零,可以使用 cout.setf(ios_base::fixed,ios_base::floatfield) 覆盖此行为
5. 代码格式化:
- 一行代码中不可分割的元素叫标记
- 空格,制表符和回车统称空白
2. 处理数据
1. 变量名命名规则
- 在名称中只能使用字母字符,数字和下划线
- 名称的第一个 字符不能是数字
- 区分大小写
- 不能将 C++ 关键字用作名称
- 以两个下划线或下划线和大写字母打头的名称被保留给实现(编译器及其使用的资源)使用。以一个下划线开头的名称被保留给实现,用作全局标示符。
- C++对于名称的长度理论上没有限制 (ANSI C(C99标准)只保证名称中的前63个字符有意义)
2. 整形
- short 至少16位
- int 至少与 short 一样长(自然长度)
- long 至少32位,且至少与 int 一样长
- long long 至少64位,且至少与 long 一样长
注:
1. 自然长度:指的是计算机处理起来效率最高的长度,尽可能选用自然长度
2. 如果知道变量可能表示的整数值大于16位整数的最大可能值,则使用 long ,即使系统上 int 为32位。这样做可以确保移植的安全性。
3. 假设要将程序从 int 为16位的系统移到 int 为32位的系统,则用于存储 int 的数组的内存量将加倍,但 short 数组不受影响。
4. 整数后面的 l 或 L 后缀表示为 long 常量,u 或 U 表示 unsigned int 常量,ul 表示 unsigned long 常量,ll 或 LL 表示long long 常量,ull, Ull, uLL, ULL 表示 unsigned long long 常量。
3. 初始化方式
int a = 123int b(234)int c = {345}或int c{345}=> 该方法可以更好的防范类型转换错误(具体可以参考后面的类型转换)
注: 如果不对函数内部定义的变量进行初始化,那么变量的值将是不确定的,这意味着变量的值将是它被创建之前的相应的内存单元保存的值。
4. 字符
- 通用字符名:
\u后面是8个十六进制位,\U后面是16个十六进制位。 - wchar_t (宽字符类型)可以表示扩展字符集,其类型是一种整数类型,可以加上前缀
L来指示,使用wcin, wcout处理wchar_t流。
wchar_t bob = L'P';
wcout << L"tall" << endl;
- char16_t 与 char32_t 类型都是无符号整形,前者长16位,后者长32位,分别用
u与U前缀表示。 - 原始字符串 在原始字符串中,字符表示的就是自己,如:
R"( cahr )"和R"+*( "(char)" )+*"
5. const 限定符
- 它能够明确指定类型
- 可以使用 C++ 的作用域规则将定义限制在特定的函数或文件中(作用于规则描述了名称在各种模块中的可知程度)
- 可以将 const 用于更复杂的类型(后续文章会多次提及)
6. 浮点数
计算机将浮点数分成两部分存储,一部分标示值,另一部分用于对值进行放大或缩小
表示方法:
- 标准小数点表示法 如:12.34
- E 表示法 如:2.34E23, 3.4e-2
优缺点:
- 优点:可以表示整数之间的值,且有缩放因子,所以表示的范围更大
- 缺点:浮点运算的速度通常比整数慢,且精度将降低,可以参考 IEEE 754-1985
7. 类型转化
专递参数时的类型转换通常由 C++ 函数原型控制。
列表初始化不允许缩窄,即变量的类型可能无法强制转换。
const int code = 66; //有 const
int x = 66; //无 const
char c1 {31325}; //narrowing,not allowed,31325超过一个字节表示的整数,同时 {} 不允许缩窄。注意下面的 c5
char c2 = {66}; //allowed because char can hold 66
char c3 {code}; //ditto c2
char c4 = {x}; //not allowed,x is not constant
x = 31325;
char c5 = x; //allowed- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
整形提升(自动转换): 在计算表达式时,C++ 将 bool, char, unsigned char, signed char, short 转换为 int .
不同类型进行算术运算时(自动转换):
- 如果有一个操作数的类型是 long double,则将另一个操作数转换为 long double
- 否则,如果有一个操作数的类型是 double,则将另一个操作数转换为 double
- 否则,如果有一个操作数的类型是 float,则将另一个操作数转换为 float
- 否则,说明操作数都是整形,因此执行整形提升
- 在这种情形下,如果两个操作数都是有符号或无符号的,且其中一个操作数的级别比另一个低,则转换为级别高的类型。
- 如果一个操作数位有符号的,另一个操作数位无符号的,且无符号操作数的级别比有符号操作数高,则将有符号操作数转换为无符号操作数所属的类型。
- 否则,如果有符号类型可表示无符号类型的所有可能值,则将无符号操作数转换为有符号操作数所属类型。
- 否则,将两个操作数都转换为有符号类型的无符号版本。
强制类型转换: 强制类型转换不会修改变量本身,而是创建一个新的,制定类型的值。格式:通用->(typeName)value / typeName(value) ,更严格-> static_cast<typeName>(value)
auto: 自动类型推断,也可用于指出当前变量为局部自动变量
3. 复合类型
1. 数组
初始化数组:
- 可省略等号
int arr[4] = {1,2,3,4};
int arr[4] {1,2,3,4};
- 可不在大括号内包含任何东西
int arr[4] = {};
int arr[4] {};
- 初始化时,禁止缩窄转换
2. 字符串
C-风格字符串性质:以空字符结尾,空字符被写作 \0 ,其 ASCII 码为0,用来标记字符串的结尾。
应使用 strcpy() 或 strncpy(),而不是赋值运算符来将字符串附给数组
char dog[8] = {'b','e','a','u','x',' ','I','I'}; //not a string!
char dog[8] = {'b','e','a','u','x',' ','I','\0'}; //a string!- 1
- 2
char str = 'S'; //#1
char str = "S"; //#2 illegal type mismatch- 1
- 2
注意: “S” 不是字符常量,它表示的是两个字符(字符S和 \0 )组成的字符串。更糟糕的是,”S” 实际上表示的是字符串所在的内存地址。
3. 字符串输入
- cin: cin 使用空白(空格,制表符和换行符)来确定字符串的结束位置
- cin.getline(arrName,arrSize): getline() 函数读取整行,它使用通过回车键输入的换行符来确定输入结尾。
- cin.get(): 其中一种方法与 getline() 相似,但是会将换行符丢弃在输入队列中。解决:
cin.get(arrName,arrSize).get(); - 空行和其他问题: 当 get() 读取空行后将设置失效位,这意味着接下来的输入将被阻断。解决:
cin.clear()。如果输入行包含的字符数比指定的多,则 getline() 和 get() 将把余下的字符留在输入队列中,而 getline() 还会设置失效位,并关闭后面的输入。
4. 结构体,共用体,枚举
结构体::
C++ 不提倡使用外部变量,但提倡使用外部结构声明。
如果结构标示符是结构名,则使用句点运算符;如果标识符是指向结构的指针,则使用箭头运算符。
定义:
struct inflatable
{
char name[20];
float volume;
double price;
};- 1
- 2
- 3
- 4
- 5
- 6
声明结构的不同:
struct inflatable gooes; //C
inflatable vincent; //C++- 1
- 2
结构体中的位字段: 字段的类型应为整形或枚举,接下来是冒号,冒号后面是一个数字,它指定了使用的位数。
struct torgle_register
{
unsigned int SN : 4; //4 bits for SN value
unsigned int : 4; //4 bits unused
bool goodIn : 1; //valid input (1 bit)
bool goodTorgle : 1; //successful torgling
}- 1
- 2
- 3
- 4
- 5
- 6
- 7
共用体::
空间: 共用体的长度为其最大成员的长度。
用途: 当数据项使用两种或更多种格式时,可节省空间。
union one4all
{
int int_val;
long long_val;
double double_val;
};- 1
- 2
- 3
- 4
- 5
- 6
枚举::
enum spectrum {red,orange,yellow,green,blue,violet,indigo,ultraviolet}- 1
- 让 spectrum 成为新类型的名称;spectrum被称为枚举
- 将red,orange,yellow等作为符号常量,第一个枚举量的值位0,第二个位1,以此类推。
枚举是整形,可被提升为 int 类型,但 int 类型不能自动转换为枚举类型
也可以这样定义枚举:
enum bits{one = 1,two = 2,four = 4,eight = 8};
bits myFlag;- 1
- 2
myFlag = bits(6); 是合法的,6不是枚举值,但它位于枚举定义的取值范围内。
5. 指针和自由存储空间
对每个指针变量名都需要使用一个 * : int* p1,p2 创建一个指针 p1 和一个int 变量 p2
指针的危险:在C++中创建指针时,计算机将分配用来存储地址的内存,但不会分配用来存储指针所指向的数据的内存。
警告:一定要在对指针应用解除引用运算符(*)之前,将指针初始化为一个确定的,适当的地址。
int *pt;
pt = (int*) 0xB8000000;- 1
- 2
这样的赋值语句的两边都是整数的地址,因此这样的赋值有效。注意,pt 是 int 值的地址并不意味着 pt 本身的类型是 int。例如:有些平台,int 类型是2bit,而地址是4bit.
new运算符::
int *pn = new int;- 1
new int 告诉程序,需要适合存储 int 的内存,new 运算符根据类型来确定需要多少字节的内存。然后,它找到这样的内存,并返回其地址。接下来,将地址附给 pn,pn是被声明为指向 int 的指针。
变量 pn 的值被存储在被成为栈的内存区域中,而 new 从被成为堆或自由存储区的内存区域分配内存
静态联编: 在编译时给数组分配内存。
动态联编: 在程序运行时选择数组的长度,即在程序运行时为数组分配空间,其长度也将在运行时设置。这意味着数组是在程序运行时创建的,即动态数组:int * psome = new int[10];
delete运算符::
int * ps = new int;
delete ps;
int * psome = new int[10];
delete [] psome;- 1
- 2
- 3
- 4
只能用 delete 来释放使用 new 分配的内存。然而,对空指针使用 delete 是安全的
new 与delete规则:
- 不要使用 delete 来释放不是 new 分配的内存
- 不要使用 delete 释放同一个内存块两次
- 如果使用 new [] 为数组分配内存,则应该使用 delete [] 来释放
- 如果使用 new [] 为一个实体分配内存,则应该使用 delete(无方括号) 来释放
- 对空指针使用 delete 是安全的
指针运算:: 将指针变量加 1 后,增加的量等于它指向的类型的字节数。将指向 double 的指针加 1 后,如果系统对 double 使用8字节存储,则数值将增加8.
6. 自动存储,静态储存,动态存储
自动变量: 在函数内部定义的常规变量使用自动储存空间。
静态储存: 静态储存是在整个程序执行期间都存在的存储方式。一:在函数外面定义,二:在声明变量时使用关键字static
动态存储: 管理一个内存池,在C++ 中被称为自由存储空间或堆,该内存池同用于静态变量和自动变量的内存是分开的。
7. at():
vector<double>a2(4) = {1.0,2.0,3.0,4.0};- 1
使用 at() 时,将在运行期捕获非法索引,因为 a2[-2] 是被允许的。