C++PrimerPlus第6版 第四章——复合类型

1,复合类型主要包含:数组、结构、联合、枚举、类、指针、引用等。

2,数组。长度必须确定。即编译阶段,数组的长度就得确定好。所以只能使用常量(#define、const)声明数组长度。如果使用变量声明数组长度,编译器就不知道要分配多少的内存空间。

3,typeName arrayName[arraySize]。数组下标从0开始。

4,数组初始化规则:

c++:数组名是数组首元素的地址,不能将一个数组直接赋值给另一个数组。并且数组的初始化可以使用列表初始化,赋值只能通过一个元素一个元素赋值。如:

上面三种都是可以初始化的方式。hotelTips的前两个元素为5.0,2.5,后面三个元素为0;totals的所有元素为0;things一个四个元素,分别为1,5,3,8.数组元素个数通过编译器计算得到。

c++11规则:列表初始化。不允许缩窄变化。

5,字符串:

c风格的字符串、string类。

c风格字符串:字符数据,后加空字符。空字符的ascii码为0.如下图: 

字符数组不一定是c风格字符串,c风格字符串一定是字符数组。

6,sizeof关键字获取变量的内存空间大小。头文件cstring中有个strlen函数,能获取字符串长度。即空字符前面的字符个数。不包括空字符。所以如果一个字符串m。需要至少strlen(m)+1的数组空间来存储。

7,

上图,左边时源码文件,右边是程序运行结果。

由于键盘不能输入空字符,所以c++使用空白符(空格、tab键、换行符)来表示字符串结束。我们输入Alistair Dreeb。IO输入缓冲区包含Alistair Dreeb,当输入name字符数组时,碰到空格就结束输入。IO输入缓冲区还剩下Dreeb。下一次输入(cin>>dessert),程序直接读取Dreeb,而不需要用户再输入数据。

8,cin.getline()。为解决上面的问题,需要调用cin.getline()每次读取一行数据。

cin.get().与上面的方法类似,唯一的区别是,前者会读取一行,并将换行符丢弃。而后者不会将换行符丢弃。

可以通过这种方式读取一行,并将换行符丢弃。(这里使用重载思想):

9,

左边是源代码,中间是程序输出,最后是解决途径。

之所以address没有机会输入,是因为程序读入1966后,还有一个换行符留在输入缓冲区。当读入address,直接将换行符认为是空行读入。可以通过最后的方式解决此问题。即将空行通过cin.get()读入。

10,string类:string类在标准名称空间std中。所以使用时需要添加using编译指令。或使用std::string来引用。

 c风格字符串复制、拼接需要调用cstring头文件的函数strcpy、strcat。如果使用string类(需要头文件string),那么字符串的复制和拼接直接使用赋值(=)、拼接(+)。如:string a=“hello”。string b=a;string c += “c++”;

不同之处:使用string类更加安全。如:

上图site数组的大小为10字节,而strcat试图将12个字符都拼接到site。这样就导致踩内存(覆盖了相邻内存)。使用string类会自动调节大小。所以更加安全。

11,string类的size函数相当于c风格字符串的strlen函数。

12,对于string类的IO:string类出现比cin(istream类)、cout(ostream类)晚,当时的IO设计并未考虑到string类,所以不能直接cin或cout一个string类的对象。可以使用getline(cin,str),从cin输入到string类对象str。这里的关键技术是友元函数。可以使得getline函数成为string类的友元函数。这样就能访问string类对象了。关于友元函数、友元类,在后面的章节会讲解。

13,其他类型的字符串字面值:

R"()"里面的内容是不会进行转义的。这种字符串格式称为原始字符串。

14,结构

结构vs数组:数组的每个元素的类型相同。但实际项目中,很有可能需要存储一个对象的信息,但这些信息需要不同的数据类型进行存取,这时候就需要结构来表示。

结构vs类:结构的默认访问权限为public,类的默认访问权限为private。c类型的结构没有函数,c++类型的结构可以有函数。

15,结构类型的声明:如

结构的声明仅仅是声明一种自定义类型,并没有创建对应类型的变量。编译器还没有为其分配存储空间。

16,结构类型的声明可以在函数内部,也可以在函数外部。在函数内部声明,则只能在函数内部使用。在函数外部声明,则可以在函数外面从结构声明以下的所有函数使用。如下图

 

17,结构类型的初始化:

值之间通过逗号隔开。

18,结构之间的赋值:将一个结构变量赋值给另一个结构变量,会将结构变量的各个成员依次赋值,即使结构变量是数组,也会赋值数组各个元素,而不仅仅赋值数组首地址。

19,声明结构变量:

下面是声明并初始化结构变量:

匿名结构变量:

这种结构没有名称,也就是说,后面就不能声明这种类型的变量了。

20,结构数组:数组的每一个元素时一个结构。

21,共用体union:一次只使用共用体的一个类型。所以union的变量大小是union类型的最大成员的内存大小。

              

上面的one4all类型结构变量pail的大小为8字节(大多数系统double、long都是8字节)。所以pail.int_val=15只占用8字节的前4个字节来存储int类型的int_val并且值为15.当执行pail.double_val=1.38时,pail结构的8个字节用来存储8个字节的1.38.

22,共用体union主要使用在当一个数据项有多种类型时,但不会同时存在,可以节省空间。如下:(idval是商品id,商品id有时候是long类型,有时候是字符串类型,但不会同时存在。所以通过union可以节省空间)

下面时匿名共用体的用法

 虽然现在的内存不算特别稀缺的资源,但如果用于编写嵌入式程序,则内存就显得特别宝贵。union就可以用于节省内存空间。

23,创建符号常量的另一种形式:枚举。enum

如果不进行强制类型转换,只能将枚举量赋值给枚举变量。

spectrum band ;

枚举变量只定义了赋值运算符。当然有些实现没有这种限制。

 

枚举量可以被提升为整形,但整形不能自动转换为枚举类型。  如下图:

最后一条语句,orange+red的值计算为int,int类型的值不能直接赋值给枚举变量。

24,枚举类型的强制类型转换:

25,枚举变量的值:

26,枚举的范围:

 27,指针vs普通变量:指针存储的是变量的地址,通过接触指针引用可以访问指针存储的地址对应的值。普通变量存储的是变量的值。可以通过地址运算符(&)获取变量的地址。相当于一个变量给你,你可以获取值也可以获取地址。给你一个指针,你也可以获取指针指向的地址(就是指针的值),也可以获取指针指向的地址对应的值(指针的值对应的地址对应的值)。如下图:

jumbo变量和*pe都是代表值(一个是变量,一个是指针),&jumbo和pe都是代表地址(一个是变量,一个是指针)。

注意:

其中,p1是指针,p2是int类型。

踩内存(很危险):

还有个问题:

                  

如上图:左边将十六进制int类型赋值给int类型指针,是不对的。右边将int类型强制转换为int型指针即可。虽然int类型值0xB8000000可以作为地址(因为地址也是int类型),但是int类型与c++的地址有不同的运算方式,所以不允许直接赋值,需要强制类型转换。

28,指针的内存结构:

可以看到,指针自己占用一个地址1006,里面存储的是ducks的地址1000.ducks的地址1000存储的是值12.指针最大的用处是通过new在堆中动态分配内存来赋给指针进行管理。这里有个概念:动态联编、静态联编。动态联编是指运行阶段才确定数组的长度并分配内存。静态联编指编译时就确定数组的长度并分配存储空间。使用new运算符来创建动态数组,使用delete来释放new创建的动态数组。

如下图:

其中红框应该去掉。

29,使用new分配内存的格式:

使用new创建动态数组:

释放动态数组:

30,指针和数组名的区别:指针是可以变量。数组名是常量,只指向数组的第一个元素,不能改变。

31,常规变量的+1就加1,指针变量的+1就是增加指针指向的类型所对应的大小。如 int a=100;a+1得到101;而int* b=&a;b+1事实上是将指针b的值加4(一般系统是这样的)。这样指针b就指向下一个地址。这个特性用在数组特别方便。如下图:

pw先指向数组第一个元素,pw+1,pw的值将8,就指向20000.0。

32,指针和数组是可以相互转换使用的。

33,数组拓展:

 34,

 所以,要打印字符串对应的地址,可以将其强制类型转换为其他类型的指针(不能是字符类型指针),如void*或者int*。否则会被当作字符串打印。

35,数组的替代品:模板类vector。需要包含头文件vector。并且在名字空间std中。

  

 

原文地址:https://www.cnblogs.com/zhoubiao20170424/p/7634769.html