今天看了看复合类型,并不难,我发现每天看完C++都比前一天晚一会,今天快五点半才看完,昨天看到5点。而且这几天都没看games101了TWT,昨晚打了一晚上三国杀,但当内奸赢了一把很爽就是了。
第四章比较长,分两天看完吧。
没想到最后是花了三天,10号差几页没看完,11号课比较多,一点没看,拖到了12号……
4.1 数组
sizeof
运算符返回类型或数据对象的长度(单位为字节)。用于数组名,得到的是整个数组的字节数,用于数组元素,则是元素的长度{}初始化
{}初始化列表只能用于数组初始化,不能用于后续赋值
如果使用{}初始化数组的一部分,那么编译器会把其他元素设置为0
c++11使用{}:
可以省略
=
{}不包含内容,则所有元素设置为0
列表初始化禁止缩窄转换
4.2 字符串
C++两种处理字符串方式:C风格字符串、string类库
C风格字符串:
存储在char数组中
以空字符结尾,
\0
,ASCII码为0
可以用字符串常量来初始化char数组,比如
"abc"
,\0
会自动加到结尾,如果还有空余位置,会自动设置为\0
有时候,字符串很长,无法放到一行中。C++允许拼接字符串字面值,即将两个用引号括起的字符串合并为一个。事实上,任何两个由空白(空格、制表符和换行符)分隔的字符串常量都将自动拼接成一个。
面向行的输入:
getline(),通过回车键输入的换行符来确定输入结尾
cin.getline(name,20)
数组名,要读取的字符数(最多读取的数目,数组其余位置添加空字符)
get(),与getline相似,唯一的不同是不再读取并丢弃换行符,而是留在输入队列中,所以需要额外使用一次get()来吸收换行符
cin.get(name,20)
可以连续get或getline(因为函数会返回一个cin对象)
- cin.get(name,20).get();//有点酷,因为外行可能看不懂哈哈
get的优点:
- get使输入更精准,使用get可以知道停止读取的原因是由于读取了整行还是已经填满,只需要查看下一个输入字符是否为换行符。但getline因为会自动吸收换行符,所以无论如何,下一个输入字符都不会是换行符
空行问题,cin读取字符串后,会把回车键生成的换行符留在输入队列,导致后面的getline或者get会认为是一个空行,所以会把空字符串赋给数组
4.3 string类简介
使用string类时,某些操作比数组简单:
不能将一个数组赋给另一个数组,但可以将一个string对象赋给另一个string对象
简化字符串合并,使用
+
getline的不同用法:
cin.getline(charr,10)
函数时istream类的一个类方法(cin是istream的一个对象)getline(cin,str)
,string的用法,说明函数不是类方法
其他形式字符串字面值:wchar_t、char16_t、char32_t,C++分别使用前缀L、u、U来表示
1
wchar_t title[] = L"abc def";
C+11还支持Unicode字符编码方案UTF-8。:在这种方案中,根据编码的数字值,字符可能存储为1~4个八位组。C++使用前缀u8来表示这种类型的字符串字面值。
C++11新增的另一种类型是原始(raw)字符串。在原始字符串中,字符表示的就是自己。
1
cout<<R"(Jim"King" Tutt uses "\n" instead of endl.)"
输入原始字符串时,按回车键不仅会移到下一行,还将在原始字符串中添加回车字符。
如果想打印
)"
呢?只需要在"
和(
之间添加其他字符,当然结尾处也要加,相当于使用新的一个字符串来表示开头和结尾,比如R"+*(
表示开头,)+*"
表示结束
4.4 结构简介
结构是C++OOP堡垒(类)的基石
C++11结构使用{}初始化
等号可选
不包含内容则所有成员设置成0
不允许缩窄
可以使用赋值运算符
=
将结构赋给另一个同类型的结构
4.5 共用体
共用体(union)是一种数据格式,它能够存储不同的数据类型,但只能同时存储其中的一种类型。也就是说:结构可以同时存储int、long和double,共用体只能存储int、long或double。所以,共用体的长度为其最大成员的长度
用途之一:当数据项使用两种或更多种格式(但不会同时使用)时,可节省空间。
匿名共用体(anonymous union)没有名称,其成员将成为位于相同地址处的变量。显然,每次只有二个成员是当前的成员
共用体通常用于(但并非只能用于)节省内存
4.6 枚举
enum spectrum {red,orange,yellow,green,blue,violet,indigo,ultraviolet};
让spectrum成为新类型的名称;spectrum被称为枚举(enumeration),就像struct变量被称为结构一样。
将red、orange、yellow等作为符号常量,它们对应整数值0~7。这些常量叫作枚举量(enumerator).在默认情况下,将整数值赋给枚举量,第一个枚举量的值为0,第二个枚举量的值为1,依次类推。
在不进行强制类型转换的情况下,只能将枚举量赋给枚举的变量,不能直接赋值数字
强制类型转换:
band = spectrum(3)
,如果数字越界,结果不确定,不会出错,但不能依赖得到的结果设置枚举量的值:
可以显式地直接赋值:enum bits{one =1,two= 2,four =4,eight =8};
指定的值必须事整数,也可以只显式地定义其中一些枚举量的值:enum bigstep{first,second =100,third};
后面没被初始化的枚举量的值将比前面的大1
可以创建多个值相同的枚举量:enum{zero,null= 0,one,numero_uno= 1};
枚举的取值范围:
上限:找到大于最大值的、最小的2的幂,减1:101的上限就是127(128-1)
下限:同上限:-6的下限-7(-(8-1))
4.7 指针和自由存储空间
显示地址时,cout使用16进制表示法,因为这是常用于描述内存的表示法,我在我vs试了下,不是十六进制表示法,是十进制,有些系统不会把两个变量存储在相邻的内存单元中,比如我的
面向对象编程与传统的过程性编程的区别在于,OOP强调的是在运行阶段(而不是编译阶段)进行决策
*运算符被称为间接值(indirect value)或解除引用(dereferencing)运算符
在C++中,
int*
是一种复合类型,是指向int的指针C++中创建指针时,计算机只会分配用来存储地址的内存,但不会分配用来存储指针所指向的数据的内存,为数据提供空间是一个独立的步骤。下面这个例子是危险的:
1 2
long* fellow; *fellow = 23333;
指针不是整型,C++不循序将数字值赋给指针,但可以使用强制类型转换,如:
int* p = (int*)0xB80000000
int* pn = new it;
pn指向了一个数据对象,指的是为数据项分配的内存块而不是OOP中的对象,虽然不如变量好用,但它使程序在管理内存方面有更大的控制权double* p = new double;*p = 0.1;
中,sizeof(p)为指针的大小,为4,sizeof(*p)为double的大小,为8变量存储在栈,而new从被称为堆或自由存储区的内存区域分配内存(后面第9章会详细介绍)
内存耗尽,new会引发异常
delete指针不会删除指针p本身,而是释放其指向的内存
不要尝试释放已经释放的内存,不能使用delete释放声明变量所获得的内存如:
int jugs = 5;int* p=&jugs;
不能delete这个pdelete是通过new的内存块的地址来删的,不是指针这个变量,多个指针可能指向同一个内存块,也就是说多个指针变量存储的地址相同,所以delete其中任何一个都会删除内存块
对于大型数据,应使用new,这正是new的用武之地!
动态数组:
在编译时给数组分配内存被称为静态联编(static binding)。但使用new时,如果在运行阶段需要数组,则创建它,不需要就不创建,还可以在程序运行时选择长度,这杯称作静态联编(dynamic binding)。这种数组称为动态数组。
使用new创建动态数组:
1 2
int* psome = new int[10]; delete []psome;
new和delete的规则
不要使用delete来释放不是new分配的内存
不要使用delete释放同一个内存块两次
如果使用new[]为数组分配内存,则应使用delete[]来释放
如果使用new为一个实体分配内存,则应使用delete(没有方括号)来释放
对空指针应用delete是安全的。
4.8 指针、数组和指针算术
指针和数组基本等价的原因在于指针算术(pointer arithmetic)和C++内部处理数组的方式。指针变量加1后,增加的量等于它指向的类型的字节数。比如指向double的指针+1后,则数值会+8(如果系统对double使用8个字节存储)
自动存储、静态存储和动态存储
自动存储:
在函数内部定义的常规变量使用自动存储空间被称为自动变量(automatic variable),这意味着它们在所属的函数被调用时自动产生,在该函数结束时消亡。
自动变量通常存储在栈中。这意味着执行代码块时,其中的变量将依次加入到栈中,而在离开代码块时,将按相反的顺序释放这些变量
静态存储:
静态存储是整个程序执行期间都存在的存储方式。使变量成为静态的方式有两种:一种是在函数外面定义它;另一种是在声明变量时使用关键字static:
static double a = 0.1;
自动存储和静态存储的关键在于:这些方法严格地限制了变量的寿命。变量可能存在于程序的整个生命周期(静态变量),也可能只是在特定函数被执行时存在(自动变量)
动态存储:
- new和delete运算符提供了一种比自动变量和静态变量更灵活的方法。它们管理了一个内存池,这在C++中被称为自由存储空间(free store)或堆(heap)。该内存池同用于静态变量和自动变量的内存是分开的。
4.9 类型组合
- 其实就是说数组、结构、指针可以组合使用
4.10 数组的替代品
模板类vector和array是数组的替代品
模板类vector
- 模板类vector类似于string类,也是一种动态数组。您可以在运行阶段设置vector对象的长度,可在末尾附加新数据,还可在中间插入新数据。基本上,它是使用new创建动态数组的替代品。实际上,vector类确实使用new和delete来管理内存,但这种工作是自动完成的。存放在自由存储区或堆
模板类array(C++11)
vector类的功能比数组强大,但付出的代价是效率稍低。如果您需要的是长度固定的数组,使用数组是更佳的选择,但代价是不那么方便和安全。有鉴于此,C+11新增了模板类array,它也位于名称空间std中。与数组一样,array对象的长度也是固定的,也使用栈(静态内存分配),而不是自由存储区,因此其效率与数组相同,但更方便,更安全
array<typename, n_elem> arr;
:n_elem不能是变量,C++11中可以对vector和array使用列表初始化,C++98不能对vector使用array可以将一个array对象赋给另一个array对象,但数组不行,只能逐元素复制
vector和array使用
at()
可以在运行期间捕获非法索引,程序默认将中断,代价就是运行时间更长