杀鸡焉用牛刀 发表于 2022-8-31 23:56:43

第4章 复合类型

说明

看《C++ Primer Plus》时整理的学习笔记,部分内容完全摘抄自《C++ Primer Plus》(第6版)中文版,Stephen Prata 著,张海龙 袁国忠译,人民邮电出版社。只做学习记录用途。

目录

[*]说明
[*]4.1 数组

[*]4.1.1 数组访问
[*]4.1.2 数组初始化及赋值

[*]4.2 字符串

[*]4.2.1 C - 风格字符串的初始化及拼接
[*]4.2.2 C - 风格字符串的使用
[*]4.2.3 C - 风格字符串的输入与输出

[*]4.3 string 类简介

[*]4.3.1 string 对象的初始化
[*]4.3.2 string 对象的赋值、拼接和附加
[*]4.3.3 string 对象的其他操作
[*]4.3.4 string 对象的输入与输出
[*]4.3.5 其他形式的字符串常量

[*]4.4 结构简介

[*]4.4.1 定义和使用结构
[*]4.4.2 结构初始化
[*]4.4.3 结构赋值及其他属性
[*]4.4.4 结构数组
[*]4.4.5 结构中的位字段

[*]4.5 共用体
[*]4.6 枚举

[*]4.6.1 枚举的定义
[*]4.6.2 枚举的取值范围
[*]4.6.3 枚举变量的赋值及其他属性

[*]4.7 指针

[*]4.7.1 声明和初始化指针
[*]4.7.2 使用 new 来分配内存
[*]4.7.3 使用 delete 来释放内存
[*]4.7.4 使用 new 创建动态数组
[*]4.7.5 使用 new 创建动态结构
[*]4.7.6 内存管理

[*]4.8 指针算术和数组名

[*]4.8.1 指针算术
[*]4.8.2 数组名
[*]4.8.3 指针和字符串

[*]4.9 类型组合
[*]4.10 数组的替代品

[*]4.10.1 模板类 vector
[*]4.10.2 模板类 array(C++11)
[*]4.10.3 比较数组、vector 对象和 array 对象


复合类型是基于基本整型和浮点类型创建的,影响最为深远的复合类型是类,除类外,C++ 还支持几种更普遍的复合类型,它们都来自 C 语言,例如:数组、结构、指针等。
4.1 数组

数组能够存储多个同类型的值,计算机在内存中依次存储数组的各个元素。数组声明应包含三点:元素类型、数组名、数组中的元素总数,如下:
//数组声明
typeName arrayName;其中的表达式 arraySize不能是变量,它必须是整型常量或const值,也可以是常量表达式(如8*sizeof(int)),即表达式中所有值在编译时都是已知的。C++ 标准模板库(STL)提供了一种数组替代品,模板类vector,C++11 新增了模板类array,这些替代品比内置复合类型数组更复杂、更灵活,这将在后面章节介绍。声明数组后,数组中的元素总数也可以使用以下方式计算出来:
//数组中的元素总数
arraySize = sizeof(arrayName)/sizeof(typeName);4.1.1 数组访问

使用访问索引为 index的数组元素,索引从 0 开始,最后一个元素的索引比数组长度小 1。
//声明长度为12的short数组
short months;

//访问它的第1个元素
months;

//访问它的最后一个元素
months;注意:编译器不会检查索引是否有效,例如可以访问months或者给它赋值,编译器并不会指出错误(有时会给个警告,不是以错误的形式指出),但是程序运行后,这种赋值可能破坏数据或代码,也可能导致程序异常终止,因此需人为确保程序使用有效的索引值。
4.1.2 数组初始化及赋值

只有在定义数组时才能使用初始化,也不能将一个数组赋给另一个数组,但可以逐元素赋值。初始化数组时,提供的值可以少于数组的元素数目,剩余的元素编译器会自动初始化为 0。
//定义时初始化全部元素
int arr1 = {3, 6, 8, 10};

//定义时只指定第一个值,剩余元素初始化为0
int arr2 = {3};

//定义时全部初始化为0
int arr3 = {0};

//定义时指定全部元素,让编译器自动统计元素个数
int arr4[] = {3, 6, 8, 10};

//C++11初始化方式:可省略等号
int arr5{3, 6, 8, 10};

//C++11初始化方式:默认初始化为0
int arr6 = {};
int arr7{};注意:使用大括号进行列表初始化时禁止缩窄转换。
4.2 字符串

C++ 处理字符串的方式有两种:第一种来自 C 语言,常被称为 C-风格字符串,第二种是下一节将介绍的string类。
C-风格字符串将字符串存储在char数组中,并以空字符结尾。空字符被写作\0,其 ASCII 码为 0,用来标记字符串的结尾。很多处理字符串的函数(如cout输出字符串)都逐个处理字符串中的字符,直到到达空字符为止,无论是否超过了char数组的实际大小。
4.2.1 C - 风格字符串的初始化及拼接

常用的初始化方法如下:
//逐个字符初始化,需人为加空字符
char cat = {'f','a','t','e','s','s','a','\0'};

//使用字符串常量进行初始化,自动添加空字符
char bird = "Mr. Cheeps";

//字符数组剩余元素自动初始化为空字符
char boss = "Bozo";

//让编译器计算字符数组长度,长度为8
char fish[] = "Bubbles";

//C++11字符串初始化
char fish[] = {"Bubbles"};
char fish[]{"Bubbles"};注意:字符串常量(使用双引号)不能与字符常量(使用单引号)互换。在 ASCII 系统上,字符常量'S'只是 83 的另一种写法,但"S"不是字符常量,它表示的是两个字符(字符S和字符\0)组成的字符串,更糟糕的是,"S"实际上表示的是字符串所在的内存地址。
C++ 允许将两个用引号括起来的字符串拼接成一个,任何两个由空白分隔的字符串常量都将自动拼接成一个。下面所有输出语句都是等效的:
//输出
cout << "Medical cotton swab.\n";

//使用空格分隔的拼接
cout << "Medical cot" "ton swab.\n";

//使用换行分隔的拼接
cout << "Medical cot"
            "ton swab.\n";4.7.6 内存管理

C++ 有 3 种管理数据内存的方式:自动存储、静态存储和动态存储(也称自由存储空间或堆)。

[*]自动存储:在函数内部定义的常规变量使用自动存储空间,被称为自动变量,自动变量是一个局部变量,其作用域为包含它的代码块(代码块指包含在花括号中的一段代码)。自动变量通常存储在栈(stack)中,执行代码块时,其中的变量将依次加入到栈中,离开代码块时,将按相反的顺序自动释放这些变量,即后进先出(LIFO),这种机制使得栈的内存通常是连续的。
[*]静态存储:静态变量将存在于程序的整个生命周期,而不是代码块内,使变量成为静态变量的方式有两种:在函数外面定义它、声明变量时加上关键字static。
[*]动态存储:new和delete管理一个内存池,这在 C++ 中被称为自由存储空间(free store)或堆(heap)。该内存池同自动存储、静态存储是分开的,数据的生命周期完全由程序员控制,可以在一个函数中分配内存,而在另一个函数中释放它,这使得自由存储空间通常是不连续的。
C++11 新增了第 4 种方式:线程存储,这将在第 9 章学习。
4.8 指针算术和数组名

4.8.1 指针算术

C++ 允许将指针和整数相加,指针加 1 的结果等于原来的地址值加上指向的对象占用的总字节数;还可以将指针相减,获得两个指针的差,最后得到一个整数,指针减法仅当两个指针指向同一个数组时,运算结果才有意义。如下示例中假设short宽 2 字节,数组首地址为 0x0028ccf0:
//将字符串arrayName2复制到数组arrayName1中
strcpy(arrayName1,arrayName2);

//将字符串arrayName2添加到数组arrayName1末尾
strcat(arrayName1,arrayName2);4.8.2 数组名

C++ 将数组名解释为其第一个元素的地址,而对数组名应用地址运算符时,得到的是整个数组的地址。从数字上而言,这两个地址相同,无需区分;但从概念上特别是需要运用指针算术时,需要明白两者的区别。如下示例中假设short宽 2 字节,系统为 32 位,数组首地址为0x0028ccf0,指针变量ptr和ptrc的区别如下:

[*]变量ptr的类型是short*,存储的是一个 2 字节内存块的地址,它指向的对象是short类型,记号*ptr与tacos等价。
[*]变量ptrc的类型是short(*),存储的是一个 20 字节内存块的地址,它指向的对象是包含 10 个元素的short数组,记号*ptrc与tacos等价。
//声明并初始化数组short tacos = {5,2,8,4,1,2,2,4,6,8};//声明并初始化指针short *ptr = tacos;short (*ptrc) = &tacos;//访问数组第三个元素cout
页: [1]
查看完整版本: 第4章 复合类型