[读书笔记] C++ Primer Plus -6Ed #1 -1.11.2019

C++ Primer Plus, 6th Edition [美]Stephen Prata [译]张海龙 袁国忠 人民邮电出版社

中文版 ISBN: 9787115279460

分类:计算机/编程语言/C++

配套网站:http://box.ptpress.com.cn/y/978-7-115-27946-0


一直想花上几天回顾一下 C++ Primer Plus 和 C++ Primer ,这些天准备实施这个计划,并整理下以前写在 GitHub 的笔记

如果快的话,也准备再回顾几本别的书,一切先看回顾的快慢再做规划

——1.9.2019


1.预备知识

1.C与C++的起源

1970s,贝尔实验室 Dennis Ritchic -> C语言

1980s,贝尔实验室 Bjarne Stroustrup -> C++语言

     <The C++ Programming Language> <The design and Evolution of C++>

C++是C的超集,任何有效的C程序都是有效的C++程序

2.可移植性

障碍:1>.硬件 2>.语言

美国国家标准局ANSI  国际标准化组织ISO

K&R C (经典C, Classic C) Kernighan & Ritchic <The C Programming Language>

ANSI C (标准C)

C++98 C++11

3.各平台上的使用:

-std=c++11

g++: g++ -std=c++0x

4.源文件扩展名

.C  .cc  .cxx  .c  .cpp  .c++


2.开始学习C++

2.1.进入C++

1.程序调整

cin.get();  //程序运行后,让窗口一直开着

2.输入输出

cout cin

C++可以使用C语言的printf()、scanf()等函数,只需添加stdio.h

3.C++预处理器、iostream文件

#include <iostream>

cin和cout来自于iostream

头文件名:有 些 C 头文件被转换为C++头文件,这些文件被重新命名,去掉了扩展名h( 使之成为C++风格的名称),并在文件名称前面加上前缀c (表明其来自C语言)。对于纯粹的C++头文件(如iostream)来说,去掉 h 的头文件也可以称之为包含于名称空间 namespace std
4.名称空间

5.使用cout进行C++输出

<< 符号 C++有很多运算符重载的现象

endl 控制符,将输出流的输出移到下一行,相当于 \n。endl 可确保程序继续运行前刷新输出(将其立即显示在屏幕上),而使用 "\n" 不能提供这样的保证

2.2.C++语句

1.变量必须声明,在C++中,变量声明不必须都得在函数或过程的开始位置,一般在首次使用该变量前声明它

2.cout可直接输出数字和字符串,不用像 printf 那样声明发送的是什么类型

此外 cout 是可扩展的,即可以重新定义cout,使 cout 能够识别和显示所开发的新数据类型

3.使用cin

4.类简介

类是用户定义的一种数据类型。要定义类,需要描述它能够表示什么信息和可对数据执行哪些操作。类定义描述的是数据格式及其用法,而对象则是根据数据格式规范创建的实体。
cout 为一个ostream类对象,ostream类定义(iostream文件的一部分)了ostream对象表示的数据以及对它可以执行的操作

cin 为一个istream类对象,也是在iostream文件内定义的

C++提供了两种发送信息的方式:1>.类方法 2>.重新定义运算符

2.3.函数

1.调用函数

1>.在源代码文件中输入函数原型

2>.声明包含该函数的头文件

#include <cmath>  //或者为#include <math.h>

2.在多函数程序中使用using编译指令

在函数外且在函数前放置编译指令 using namespace std; 即可使得文件中其后面的所有函数位于同一名称空间

1>.将 using namespace std; 放在函数定义之前,让文件中所有函数可以使用std中的所有元素

2>.将 using namespace std; 放在特定函数中,仅该函数内可使用

3>.在函数中使用 using std::cout; 这样的编译指令,使在该函数中可以使用cout

4>.全部使用前缀 std::


3.处理数据

OOP的本质是设计并扩展自己的数据类型,设计自己的数据类型就是让类型与数据匹配

内置的C++类型分两组:基本类型和复合类型。本章为基本数据

3.1.简单数据

1.变量名

在名称中只能使用字母字符、数字和下划线。名称的第一个字符不能是数字。C++区分大写字符与小写字符。不能将C++关键字用作名称。以两个下划线或下划线和大写字母打头的名称被保留给实现(编译器及其使用的资源)使用。以一个下划线开头的名称被保留给实现,用作全局标识符。C++对于名称的长度没有限制,名称中所有的字符都有意义,但有些平台有长度限制。

2.整型

基本整型:char、short、int、long、long long(按宽度递增),每种类型都有有符号版本和无符号版本

short 至少 16 位;int 至少与 short —样长;long 至少 32 位 ,且至少与 int —样长;long long 至少 64 位 ,且至少与 long —样长。

"字节"的含义有赖于实现,在不同计算机或不同系统中,各种类型变量的位长可能不尽相同,由此可能引发程序移植时的错误

sizeof 运算符 可返回类型或变量的长度

头文件 <climits> 中包含了关于整型限制的信息,即定义了各种限制的符号名称

#define 同#include,也是预处理器编译指令(C遗留下的)

3.变量的初始化

C++11 用于数组和结构的初始化方法:{ }

4.无符号类型

unsigned short/int/long/long long

unsigned int 可直接简写为 unsigned

5.选择类型

一般,int 被视为最自然的长度,自然长度指的是计算机处理起来效率最高的长度

6.整型字面值

整型字面值,即常量,是显式地书写的常量。与 C 相同,C++ 能够以三种不同的计数方式来书写整数:基数为 10、基数为 8 (老式UNIX版木)和基数为16 (硬件黑客的最爱)

C++表示法:C++使用前一/两位来标识数字常量的基数。如果第一位为1〜9 ,则基数为 10 (十进制):因此93是以 10 为基数的。如果第一位是0 , 第二位为 1〜7 , 则基数为 8 (八进制);因此 042 的基数是 8 , 它相当于十进制数34。如果前两位为0x或0X,则基数为 16 (十六进制)

cout 可以指示以何种基数输出,只需在输出前输入 cout << dec/hex/oct(十/十六/八);

7.C++如何确定常量的类型

后缀:整数后面的 l 或 L 后缀表示该整数为 long 常量,u 或 U 后缀表示 unsigned int 常量,ul(可以采用任何一种顺序,大写小写均可)表示 unsigned long常量(由于小写 l 看上去像 1,因此应使用大写 L 作后缀,即uL),ll或LL后缀表示 long long 变量

8.char类型

专存储字符 (字母和数字),同时char为比short更小的整型。常用的字符集为ASCII字符集,C++上使用的是其主机系统的编码,可以存储更多的值

cout类的成员函数 cout.put() - 输出一个字符

char字面值 - 将字符用单引号扩起,可以书写字符常量,其代表的即为字符的数值编码

转义字符 (数字转义字符或符号转义字符):

字符名称ASCII符号C++代码十进制ASCII码十六进制ASCII码
换行符NL(LF)\n100xA
水平制表符HT\t90x9
垂直制表符VT\v110xB
退格BS\b80x8
回车CR\r130xD
振铃BEL\a7

0x7

反斜杠\\\920x5C
问号?\?630x3F
单引号'\'390x27
双引号"\"340x22

作为字符常量时,应用单引号扩起;将其放在字符串中时,不用单引号

通用字符名,通用字符名可以以 \u 或 \U 打头。\u 后面是8个十六进制位,\U 后面则是 16 个十六进制位。这些位表示的是字符的ISO10646码点 (ISO10646是一种正在制定的国际标准,为大量的字符提供了数值编码。即 Unicode)

signed char 与 unsigned char,char 默认无符号。如果将char用作数值类型,unsigned char类型的表示范围通常为 0〜255,而 signed char的表示范围为 -128~127

wcha_t,宽字符类型,可以表示扩展字符集。cin 和 cout 将输入输出看做char流,因此不可处理 wcha_t 类型,可用 wcin 和wcout,另外可加前缀 L 指示宽字符常量和宽字符串,即 wcha_t bob = L'P';

C++11 新增类型:char16_t 和 char32_t,均为无符号。C++11使用前缀 u 表示 char16_t 字符常量和字符吊常量, 如 u‘C’ 和 u“be good”;并使用前缀U表示char32_t常 量,如U‘R’和U"dirty rat’’。类型char16_t与/u00F6形式的通用字符名匹配,而类型char32_t与/U0000222B形式的通用字符名匹配。前缀u和U分别指出字符字面值的类型为char16_t和char32_t。

9.bool类型

George Boole 开发的数学表示法。true、false 都可转换为 int 类型。任何数字值或指针值都可以隐式转换为 bool 值:非零值为true,零为 false

3.2.const限定符

1.限定变量为只读常量,注意要在声明中对 const 进行初始化,若声明常量时没有提供值,则该常量的值将不确定,且无法修改

2.const 与 #define 相比,const 要更好些。首先,它能够明确指定类型。其次,可以使用C++的作用域规则将定义限制在特定的函数或文件中(作用域规则描述了名称在各种模块中的可知程度,将在第9章讨论)。第三,可以将const用于更复杂的类型,如第4章将介绍的数组和结构。

3.3.浮点数

1.浮点数存储时,计算机将这样的值分成两部分存储。一部分表示值,另一部分用于对值进行放大或缩小,即基准值与缩放因子。浮点数能够表示小数值、非常大和非常小的值,它们的内部表示方法与整数有天壤之别。

2.书写浮点数: 1>.标准小数点表示法 2>.E表示法(适合于非常大/小的数)

3.浮点类型: 1>.float 2>.double 3>.long double。这些类型是按它们可以表示的有效数位和允许的指数最小范围来描述的。有效位(significant figure) 是数字中有意义的位。C 和 C++ 对于有效位数的要求是,float 至少 32 位,double 至少 48 位且不少于 float,long double 至少和 double —样多。这三种类型的有效位数可以一样多。然而通常,float为 32 位,double 为 64 位,long double 为 80、96 或 128 位。可从头文件 cfloat 或 float.h 看关于浮点数的批注项

ostream类有 方法 self(),cout.self(ios_base::fixed,ios_base::floatfield);  防止程序把较大的值切换为E表示法,并使程序显示到小数点后6位

4.浮点常量,默认为 double,使用后缀 f 或 F 可使变量定义为 float 类型,使用后缀 l 或 L 可使变量定义为 long double,或在数字值前加 (float) 来定义类型

5.浮点数的优缺点: 1>.可表示整数之间的值,且表示范围大得多 2>.运算速度慢,精度低

6.注意: float仅可保证数字中的前6位或前7位有效

3.4.C++算术运算符

1.基本运算符:+ - * / %

2.运算符优先级与结合性

3.除法分支的结果,取决于操作数的类型,若两操作数均为整数,结果亦为整数,其小数部分将被丢弃。若其一为浮点数,结果亦为浮点数。若两操作数类型不同,会将其自动转换为同一类型再计算

4.运算符重载,/ 可以表示不同类型变量的计算,即为运算符的重载,C++可以扩展运算符重载

5.求模运算符,返回整数除法的余数

6.类型转换,C++中有11种整型和3种浮点类型,有多种类型转换: 1>.将一种算术类型的值陚给另一种算术类型的变量时,C++将对值进行转换 2>.表达式中包含不同的类型时,C++将对值进行转换 3>.将参数传递给函数时,C++将对值进行转换

类型转换的规则:

1>.初始化和赋值进行的转换,将一种类型的值赋给另一种类型变量,值将转换为接受变量的类型。这时可能有问题

2>.以{}方式初始化时进行的转换 (C++11),即列表初始化,但变量的类型可能无法表示赋给它的值,列表初始化禁止缩窄转换

3>.表达式中的转换,整型提升

4>.传递参数时的转换,整型提升

5>.强制类型转换,可通过强制类型转换机制显示地进行类型转换,强制类型转换不会修改变量本身,而是创建一个新的、指定类型的值,可以在表达式中使用这个值。强制转换的通用格式如下: (typeName) value 或 typeName (value)。此外C++中还有四个强制类型转换符,如static_cast<typeName> (value)

7.C++11中新定义的auto声明,使编译器能根据初始值的类型推断变量的类型


4.复合类型

4.1.数组

1.数组声明时应指出: 1>.存储在每个元素中值得类型 2>.数组名 3>.数组中的元素数

short months[12];       //typeName arrayName[arraySize];

2.sizeof 运算符返回类型或数据对象的长度 (单位为字节)。注意,如果将 sizeof 运算符用于数组名,得到的将是整个数组中的字节数。但如果将 sizeof 用于数组元素,则得到的将是元紊的长度 (单位为字节)

3.只有在定义数组时才可使用初始化,不可将一个数组赋给另一个数组

4.C++11 的列表初始化 (大括号),可用于所有类型,注意列表初始化禁止缩窄转换

5.C++ 标准模板库 (STL) 提供了一种数组替代品—模板类 vector,而 C++11 新增了模板类 array。这些替代品比内置复合类型数组更复杂,但也更灵活

4.2.字符串

1.C++处理字符串的方式有两种。第一种来自C语言,常被称为 C- 风格字符串 (C-style string),另一种是基于string类库的方法。

2.C-风格字符串,一系列字符存储在char数组中,并以空字符结尾,写作\0,其ASCII码为0,用来标记字符串的结尾

char bird[11] = "Faith_bian";   char fish[] = "Sylar";  //隐式地包括结尾的空字符,多出的元素全部设置为\0

3.在数组中使用字符串。要将字符串存储到数组中,最常用的方法有两种: 1>.将数组初始化为字符串常量 2>.将键盘或文件输入读入到数组中

<cstring>  或  <string.h>

4.sizeof 运算符指出整个数组的长度; strlen() 函数返回的是存储在数组中的字符串的长度,strlen() 只计算可见的字符,而不把空字符计算在内

5.字符串输入,1>.空格 2>.字符串的长度

6.可以每次读取一行字符串输入,istream 类提供的函数: getline()get(),读取一行输入,直到达到换行符。随后 getline() 将丢弃换行符,而 get() 将换行符保留在输入序列中。

getline(),要调用这种方法,可以使用 cin.getline()。该函数有两个参数。第一个参数是用来存储输入行的数组的名称,第二个参数是要读取的字符数,若为 n,则最多读取 n-1 个字符。当读取到换行符时,剩余元素存储为 \0

get(),有几种变体:

1>.工作方式同getline(),不同之处为读取到的换行符会存储到字符串中  cin.get(name, ArSize);

2>.不需任何参数的cin.get调用,可读取下一个字符,可用来处理换行符  cin.get();

3>.将两个类成员函数拼接起來(合并)  cin.get(name, ArSize).get(); 同cin.getline(name1, ArSize).getline(name2, ArSize);

7.空行和其他问题,遇到空行会对 get() 设置失效位,可用 cin.clear() 恢复输入。输入字符串可能比分配的长,getline() 和 get() 将把余下的字符留在输入队列中,而 getline() 还会设置失效位,并关闭后面的输入

8.混合输入字符串和数字,混合输入数字和面向行的字符串会导致问题,解决办法: 1>.使用没有参数的 get() 2>.使用接受一个char 参数的 get()

4.3.string类简介

1.string类使用起来比数组简单,同时提供了将字符串作为一种数据类型的表示方法 。string类定义隐藏了字符串的数组性质,并使之可以像处理普通变量那样处理字符串

<string>

2.使用 string 对象的方式与使用字符数组相同: 1>.可以使用 C- 风格字符串来初始化 string 对象 2>.可以使用 cin 来将键盘输入存储到 string 对象中 3>.可以使用 cout 来显示 string 对象 4>.可以使用数组表示法来访问存储在 string 对象中的字符。

3.赋值、拼接和附加。不能将一个数组赋给另一个数组,但可以将一个 string 对象赋给另一个 string 对象。可使用 + 将两 string 对象合并起来。字符串长度可使用类方法 size()。

对C-风格字符串 (字符数组) ,为字符串赋值不能直接赋值,用 <cstring> 中的 strcpy() 可将字符串复制到字符数组中,使用strcat() 将字符串附加到字符数组末尾

4.string 类 I/O,可以使用 cin 和运算符 << 来将输入存储到 string 对象中,使用 cout 和运算符 << 来显示 string 对象。但每次读取一行而不是一个单词时,用法不同

对数组:cin.getline(char,20); 为类方法

对 string 对象:getline(cin,str); 不是类方法,在 istream 类中没有处理 string 对象的类方法

未初始化的数组内容未定义,其长度不为零且随机。未初始化的 string 对象为 0

5.其他形式的字符串字面值:wchar_t、char16_t、char32_t 分别使用前缀 L、u、U 表示,如 wchar_t title[] = L"CN Dota";

6.C++11 支持 Unicode 字符编码方案 UTF-8,使用前缀 u8 表示

7.C++11 新增原始字符串,在原始字符串中,字符表示的就是自己,使用"(和)"用作界定符,并使用前缀 R 表示。输入原始字符串时,按回车不仅会移到下一行,还将在原始字符串中添加回车字符。若想在原始字符串中输出"(和)",可使用类似 R"+*()+*" 的表示方法

4.4.结构简介 struct

1.结构是一种比数组更灵活的数据格式,因为同一个结构可以存储多种类型的数据,这使得能够将多种类型的信息放在一个结构中,从而将数据的表示合并到一起。

结构是用户定义的类型,而结构声明定义了这种类型的数据域性。定义了类型后,便可以创建这种类型的变量。创建结构包括两步。首先,定义结构描述一 它描述并标记了能够存储在结构中的各种数据类型。然后按描述创建结构变量 (结构数据对象)

C++ 允许在声明结构变量时省略关键字 struct,并用成员运算符( . )来访问各个成员

2.结构声明的位置,一种选择可以将声明放在main()函数中,紧跟在开始括号的后面。另一种选择是将声明放到main()的前面。外部声明可以被其后面的任何函数使用,而内部声明只能被该声明所域的函数使用。变量也可以在函数内部和外部定义,外部变量由所有的函数共享

3.结构初始化也可以使用列表初始化的方法。初始化时若未设置各成员的值,则全部成员将会设置为0。另外string类也可以作为结构的成员

4.可以将结构作为参数传递给函数,也可以让函数返回一个结构。还可以使用赋值运算符( = )将结构赋给另一个同类型的结构,这样结构中每个成员都将被设置为另一个结构中相应成员的值,即使成员是数组,称为成员赋值。可以初始化以这种方式创建的变量。

5.还可以声明没有名称的结构类型,方法是省略名称,同时定义一种结构类型和一个这种类型的变最:
struct {int x; int y;} position; -> 创建一个名为position的结构变量

6.C++结构除了成员变量外,还可以有成员函数

7.结构数组,inflatable结构包含一个数组 (name)。也可以创建元素为结构的数组,方法和创建基本类型数组完全相同。

例如,要创建一个包含100个 inflatable结构的数组,可以这样做: inflatable gifts [100];  gifts将是一个inflatable数组,其中的每个元素(如gifts[0]或 gifts[99])都是inflatable对象,可以与成员运算符一起使用。注意,gifts本身是一个数组,而不是结构。由于数组中每个元素都是结构,因此可以使用结构初始化的方式来提供它的值

8.结构中的位字段,C++中可以指定占用特定位数的结构成员。字段的类型应为整型或枚举 (稍后将介绍),接下来是冒号,冒号后面是一个数字,它指定了使用的位数。可以使用没有名称的字段来提供间距。

struct cc
{
     unsigned int SN : 4; 
}

4.5.共用体 union

1.共用体可以存储不同的数据类型,但只能同时存储其中一种类型。由于共用体每次只能存储一个值,因此它必须有足够的空间来存储最大的成员,所以,共用体的长度为其最大成员的长度

union cc
{
     int int_val;
     long long_val; 
}

2.匿名共用体 (anonymous union) 没有名称,其成员将成为位于相同地址处的变量。显然,每次只有一个成员是当前的成员

union
{
     int int_val;
     long long_val; 
}

共用体常用于节省内存

4.6.枚举 enum

1.为一种定义符号常量的方法

enum spectrum (red, orange, yellow);  //默认情况下,将整数值赋给枚举值,即 0、1、2...

枚举没有算术运算

2.枚举量是整型,可被提升为 int 类型,但 int 类型不能自动转换为枚举类型

若只打算创建枚举类型的常量,可以省略枚举类型的名称

3.可以使用赋值运算符来显式地设置枚举量的值,指定的值必须是整数。也可以只显式地定义其中一些枚举量的值。可以创建多个值相同的枚举量

4.枚举的取值范围,C++ 现在通过强制类型转换,增加了可赋给枚举变量的合法值。每个枚举都有取值范围 (range),通过强制类型转换,可以将取值范围中的任何整数值赋给枚举变量,即使这个值不是枚举值。取值范围:枚举量中最大值与最小值即为取值范围的上限和下限

5.选择用多少空间来存储枚举由编译器决定。对于取值范围较小的枚举,使用一个字节或更少的空间;而对于包含 long 类型值的枚举,则使用 4 个字节。

4.7.指针和自由存储空间

1.指针是一个变量,其存储的是值的地址,而不是值本身。指针用于存储值得地址,因此制作名表示的是地址

地址运算符 &

*运算符 间接值或解除引用运算符,将其应用于指针,可以得到该地址处存储的值,其等效为 int 变量

2.声明和初始化指针,声明指针时必须指定指向的数据的类型

int * p;  //p是地址 *p 是 int 类型数据

int* p; int *p; int * p; 都可以。在C++中,int* 是一种复合类型,是指向 int 的指针 

将指针初始化为一个地址: int h = 5; int * p = &h;   //p 成为 h 的地址,*p 即为 h

3.注意: 不能直接将数字设为指针的地址,要将数字值作为地址来使用,应通过强制类型转换将数字转换为适当的地址类型:

int * p;  pt = {int *} 0xB8000000;

4.分配内存

可以使用 malloc() 来分配内存

使用 new 来分配内存,new 将找到一个长度正确的内存块,并返回该内存块的地址。程序员的责任是将该地址赋给一个指针

int * p = new int;  //p指向的是数据对象,而不是变量。

普通的变量存储在栈内,而 new 从堆内分配内存。有时没有足够内存而用 new 时会引发异常,会成为空指针。空指针不会指向有效的数据,常用来表示运算符或函数失败

5.使用 delete 来释放内存,这样会释放指针指向的内存,不会删除指针本身,并可以将其重新指向另一个新分配的内存块

int * p = new int;  ...  delete p;  

new 和 delete 要配对使用,只能用 delete 释放使用 new 分配的内存,对空指针使用 delete 是安全的

不要释放已经释放的内存,其结果将是不确定的。另外不要创建两个指向同一个内存块的指针

6.使用 new 来创建动态数组

在编译时给数组分配内存被称为静态联编,还可以在程序运行时选择数组的长度,这称为动态联编。意味着数组是在程序运行时创建的,这种数组叫作动态数组

int t[10];  //静态联编

int * p = new int[10];  //使用 new[] 创建数组将采用动态联编(动态数组)

使用静态联编时,必须在编写程序时指定数组的长度;使用动态联编时,程序将在运行时确定数组的长度。

使用 new 创建动态数组,只要将数组的元素类型和元素数目告诉 new 即可

int * p = new int [10];  //new运算符返回创建的10个 int 值的内存块的第一个元素的地址

7.当程序使用完 new 分配的内存块时,应使用 delete 释放它们。然而对于使用 new 创建的数组,应使用另一种格式的 delete 来释放

delete [] p;

另外如果使用 new [] 为一个实体分配内存,应使用不带方括号的 delete 来释放

8.编写程序时,必须让程序跟踪元素的数目。另外 sizeof 运算符不能用来确定动态分配的数组包含的字节数

9.对于动态数组,可以直接使用 p[0] 来使用其第一个元素,第二个元素即用 p[1]

不能修改数组名的值。但指针是变量,因此可以修改它的值,即可以改变指针地址

p=p+1 可以使指针直接指向下一个元素的地址,而非下一字节

4.8.指针、数组和指针算术

1.指针和数组基本等价的原因在于指针算术和 C++ 内部处理数组的方式,将指针变量加 1 后, 增加的量等于它指向的类型的宇节数,可理解为 C++ 将数组名解释为地址

C++ 将数组名解释为数组第 1 个元素的地址

另外对于数组,以下两种表示方法相同: int i[3] = [3, 2, 1];  *(i+1)  i[1]

数组和指针很多情况下的使用很相似,其区别之一是可以修改指针的值,而数组名是常量。另一区别是,对数组使用 sizeof 得到的是数组的长度,而指针得到的是指针的长度

两个指针可以相减,其结果得到一个整数。仅当两个指针指向同一个数组时,这种运算才有意义,这样可以得到两元素的间隔

使用方括号数组表示法等同于对指针解除引用

2.一般,给 cout 提供一个指针,将打印地址。但如果指针类型为 char*,则 cout 将打印指针指向的字符串。如果要显示的是字符串的地址,则必须将这种指针强制转换为另一种指针类型,如 int*

3.复制字符串,初始化数组时,使用 = 运算符,否则应使用 strcpy() 或 strncpy()

4.使用 new 创建动态结构,将 new 用于结构由两步组成:创建结构和访问其成员。要创建结构,需要同时使用结构类型和 new

cc为一个结构,则  cc * ps = new cc;  可创建一名为 ps 的动态结构

5.访问成员,C++ 中的箭头成员运算符 ->,可用于指向结构的指针

若 ps 指向一个结构,ps->price 是被指向的结构的 price 成员

另一个访问成员的办法是用成员运算符( . ),即 (*ps).price是被指向结构的price成员

6.管理数据内存的方式: 自动存储、静态存储、动态存储和线程存储

1>.自动存储,在函数内部定义的常规变景使用自动存储空间,被称为自动变量。它们在所属函数被调用时自动产生,在函数结束时消亡。自动变量是一个局部变量,其作用域为包含它的代码块

自动变量通常存储在栈中。这意味着执行代码块时,其中的变量将依次加入到栈中,而在离开代码块时,将按相反的顺序释放这些变量,这被称为后进先出(LIF0)

2>.静态存储,一种是在函数外面定义它;另一种是在声明变量时使用关键字 static:

3>.动态存储,使用 new 和 delete 运算符,存储在堆中

在栈中,自动添加和删除机制使得占用的内存总是连续的,但 new 和 delete 的相互影响可能导致占用的自由存储区不连续,这使得跟踪新分配内存的位置更困难

若一味使用 new 而不 delete,会引发内存泄漏

4.9.类型组合

数组、结构和指针的组合使用

4.10.数组的替代品

1.模板类vector  <vector> 

由 C++98 新增的标准模板库 STL 提供

类似于 string 类,也是一种动态数组。可以在运行阶段设置 vector 对象的长度,可在末尾附加新数据,还可在中间插入新数据。它是使用 new 创建动态数组的替代品,同时它也用 new 和 delete 管理内存

vector<int> vi;  //vi是一个vector<int>对象

由于 vector 对象在您插入或添加值时自动调整长度,因此可以将 vi 的初始长度设置为零

vector< typeName> vt(n_elem);    //创建一个名为 vt 的 vector 对象,它可存储 n_elem 个类型为 typeName 的元素,n_elem 可以是整型常量,也可以是整型变量

vector类的功能比数组强大,但付出的代价是效率稍低

2.模板类array   <array>

由C++11提供

array 对象的长度也是固定的,也使用栈(静态内存分配),而不是自由存储区。其效率和数组相同,且更方便、更安全

array<int, 5> ai;  //ai是一个包含5个int的array对象

array<typeName, n_elem> arr;    //创建一个名为 arr 的 array 对象,它包含 n_elem 个类型为 typename 的元素

3.比较数组、vector 对象和 array 对象

无论是数组、vector 对象还是 array 对象,都可使用标准数组表示法 [] 来访问各个元素

array 对象和数组存储在相同的内存区域 (即栈) 中,而 vcctor 对象存储在另一个区域 (自由存储区或堆) 中

可以将一个 array 对象赋给另一个 array 对象,而对于数组,必须逐元素复制数据。

C++ 不检查数组的超界错误,而 vector 和 array 对象可以选择禁止超界

另外 vector 和 array 对象有成员函数 at(),此外使用 begin() 和 end() 可以确定边界,以避免无意间超界

4.中括号表示法和成员函数 at() 的差别在于,使用 at() 时,将在运行期间捕获非法索引,而程序默认将中断 。这种额外检查的代价是运行时间更长


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值