第4章 复合类型

打印 上一主题 下一主题

主题 550|帖子 550|积分 1650

说明

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

目录

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

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

使用[index]访问索引为 index的数组元素,索引从 0 开始,最后一个元素的索引比数组长度小 1
  1. //声明长度为12的short数组
  2. short months[12];
  3. //访问它的第1个元素
  4. months[0];
  5. //访问它的最后一个元素
  6. months[11];
复制代码
注意:编译器不会检查索引是否有效,例如可以访问months[101]或者给它赋值,编译器并不会指出错误(有时会给个警告,不是以错误的形式指出),但是程序运行后,这种赋值可能破坏数据或代码,也可能导致程序异常终止,因此需人为确保程序使用有效的索引值。
4.1.2 数组初始化及赋值

只有在定义数组时才能使用初始化,也不能将一个数组赋给另一个数组,但可以逐元素赋值。初始化数组时,提供的值可以少于数组的元素数目,剩余的元素编译器会自动初始化为 0。
  1. //定义时初始化全部元素
  2. int arr1[4] = {3, 6, 8, 10};
  3. //定义时只指定第一个值,剩余元素初始化为0
  4. int arr2[4] = {3};
  5. //定义时全部初始化为0
  6. int arr3[4] = {0};
  7. //定义时指定全部元素,让编译器自动统计元素个数
  8. int arr4[] = {3, 6, 8, 10};
  9. //C++11初始化方式:可省略等号
  10. int arr5[4]{3, 6, 8, 10};
  11. //C++11初始化方式:默认初始化为0
  12. int arr6[4] = {};
  13. int arr7[4]{};
复制代码
注意:使用大括号进行列表初始化时禁止缩窄转换
4.2 字符串

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

常用的初始化方法如下:
  1. //逐个字符初始化,需人为加空字符
  2. char cat[8] = {'f','a','t','e','s','s','a','\0'};
  3. //使用字符串常量进行初始化,自动添加空字符
  4. char bird[11] = "Mr. Cheeps";
  5. //字符数组剩余元素自动初始化为空字符
  6. char boss[8] = "Bozo";
  7. //让编译器计算字符数组长度,长度为8
  8. char fish[] = "Bubbles";
  9. //C++11字符串初始化
  10. char fish[] = {"Bubbles"};
  11. char fish[]{"Bubbles"};
复制代码
注意:字符串常量(使用双引号)不能与字符常量(使用单引号)互换。在 ASCII 系统上,字符常量'S'只是 83 的另一种写法,但"S"不是字符常量,它表示的是两个字符(字符S和字符\0)组成的字符串,更糟糕的是,"S"实际上表示的是字符串所在的内存地址。
C++ 允许将两个用引号括起来的字符串拼接成一个,任何两个由空白分隔的字符串常量都将自动拼接成一个。下面所有输出语句都是等效的:
  1. //输出
  2. cout << "Medical cotton swab.\n";
  3. //使用空格分隔的拼接
  4. cout << "Medical cot" "ton swab.\n";
  5. //使用换行分隔的拼接
  6. cout << "Medical cot"
  7.             "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
  1. //将字符串arrayName2复制到数组arrayName1中
  2. strcpy(arrayName1,arrayName2);
  3. //将字符串arrayName2添加到数组arrayName1末尾
  4. strcat(arrayName1,arrayName2);
复制代码
4.8.2 数组名

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

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

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

杀鸡焉用牛刀

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表