C++学习笔记——复合类型

三. 复合类型

3.1 数组

数组是一种数据格式,能够存储多个同类型的值。数组声明应指出:

        · 存储在每个元素中的值的类型;

        · 数组名;

        · 数组中的元素数。

声明数组的通用格式:

typeName arrayName[arraySize];

示例:short months[12];

C++数组从0开始编号,使用带索引的方括号表示法来指定数组元素。

arrayone.cpp

#include <iostream>


int main()
{
	using namespace std;
	int yams[3];
	yams[0] = 7;
	yams[1] = 8;
	yams[2] = 6;

	int yamcosts[3] = { 20, 30, 5 };

	cout << "Total yams = ";
	cout << yams[0] + yams[1] + yams[2] << endl;
	cout << "The package with " << yams[1] << " yams costs ";
	cout << yamcosts[1] << " cents per yam.\n";
	int total = yams[0] * yamcosts[0] + yams[1] * yamcosts[1];
	total = total + yams[2] * yamcosts[2];
	cout << "The total yam expense is " << total << " cents.\n";

	cout << "\nSize of yam array = " << sizeof yams;
	cout << " bytes.\n";
	cout << "Size of one element = " << sizeof yams[0];
	cout << " bytes.\n";

	return 0;
}

3.1.1 数组的初始化规则

·只有在定义数组时才能使用初始化,此后就不能初始化了,也不能将一个数组赋给另一个数组;

·可以使用下标分别给数组中的元素赋值;

·初始化数组时,提供的值可以少于数组的元素数目,编译器将把其他元素设为0;

·如果初始化数组时方括号为空,C++编译器将计算元素个数

3.1.2 C++11数组初始化方法

新增:

·初始化数组时,可省略等号;

double  earning[4] {1.2e4, 1.6e4, 1.7e4};

·可不在大括号内包含任何东西,这将把所有元素都设置为零;

unsigned int counts[10] = {};

float balances[100] = {};

·列表初始化禁止缩窄转换。

3.2 字符串

char dog[3] = {'a', 'b', 'c'};        //非字符串

char cat[3] = {'d', 'e', '\0'};        //字符串

char fish[] = "Bubbles";        //字符串常量

3.2.1 拼接字符串常量

任何由两个空白(空格、制符表和换行符)分隔的字符串常量都将自动拼接成一个:

cout << "I'd give my right ar"

"m to be a great violinst.\n";

3.2.2 在数组中使用字符串

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

string.cpp

#include <iostream>
#include <cstring>

int main()
{
	using namespace std;
	const int Size = 15;
	char name1[Size];
	char name2[Size] = "C++owboy";

	cout << "Howdy!I'm " << name2;
	cout << "! What's your name?\n";
	cin >> name1;
	cout << "Well, " << name1 << ", your name has ";
	cout << strlen(name1) << " letters and is stored\n";
	cout << "in an array of " << sizeof(name1) << " bytes.\n";
	cout << "Your initial is " << name1[0] << ".\n";
	name2[3] = '\0';
	cout << "Here are the first 3 characters of my name: ";
	cout << name2 << endl;

	return 0;
}

3.2.3 字符串输入

        cin使用空白(空格、制表符和换行符)来确定字符串的结束位置,这意味着cin在获取字符数组输入时只读取一个单词。读取该单词后, cin将该字符串放到数组中,并自动在结尾添加空字符。
        实际结果是,cin 把 Alistair作为第一个字符串,并将它放到name数组中。这把 Dreeb 留在输入队列中。当cin在输入队列中搜索用户喜欢的甜点时,它发现了Dreeb,因此 cin读取 Dreeb,并将它放到dessert数组中。

3.2.4 每次读取一行字符串输入

istream中的类提供了一些面向行的类成员函数:getline()和get(),getline()将丢弃换行符,而get()将换行符保留在输入序列里。

1. 面向行的输入:getline()

        getline()函数读取整行,它使用通过回车键输入的换行符来确定输入结尾。要调用这种方法,可以使用cin.getline()。该函数有两个参数。第一个参数是用来存储输入行的数组的名称,第二个参数是要读取的字符数。如果这个参数为20,则函数最多读取19个字符,余下的空间用于存储自动在结尾处添加的空字符。getline()成员函数在读取指定数目的字符或遇到换行符时停止读取。

instr.cpp

#include <iostream>
#include <cstring>

int main()
{
	using namespace std;
	const int ArSize = 20;
	char name[ArSize];
	char dessert[ArSize];

	cout << "Enter your name:\n";
	cin.getline(name, ArSize);
	cout << "Enter your favorite dessert:\n";
	cin.getline(dessert, ArSize);
	cout << "I have some delicious " << dessert;
	cout << " for you, " << name << ".\n";

	return 0;
}

2. 面向行的输入:get()

第一种调用方式:

cin.get(name, ArSize);

cin.get();

cin.get(dessert, ArSize);

使用不带任何参数的cin.get()调用可读取下一个字符(即使是换行符),可以用它来处理换行符,为读取下一行输入做好准备。

第二种调用方式:

cin.get(name, ArSize).get();

3.3 string类简介

strtype1.cpp

#include <iostream>
#include <cstring>

int main()
{
	using namespace std;
	char charr1[20];
	char charr2[20] = "jaguar";
	string str1;
	string str2 = "panther";

	cout << "Enter a kind of feline: ";
	cin >> charr1;
	cout << "Enter another kind of feline: ";
	cin >> str1;
	cout << "Here are some feline:\n";
	cout << charr1 << " " << charr2 << " "
		 << str1 << " " << str2
		 << endl;
	cout << "The third letter in " << charr2 << " is "
		 << charr2[2] << endl;
	cout << "The third letter in " << str2 << " is "
		 << str2[2] << endl;
	return 0;
}

string对象和字符数组之间的主要区别是,可以将string对象声明为简单变量,而不是数组。

3.3.1 C++11字符串初始化

string third_date = {"The Bread Bowl"};

string fourth_date {"Hank's Fine Eats"};

3.3.2 赋值、拼接和附加

· 可以将一个string对象赋给另一个string对象。

· 可以使用运算符+将两个string对象合并起来,还可以使用运算符+=将字符串附加到string对象的末尾。

strtype2.cpp

#include <iostream>
#include <cstring>

int main()
{
	using namespace std;
	string s1 = "penguin";
	string s2, s3;

	cout << "You caan assign one string object to another: s2 = s1\n";
	s2 = s1;
	cout << "s1: " << s1 << ", s2: " << s2 << endl;
	cout << "You can assign a C-style string object.\n";
	cout << "s2 = \"buzzard\"\n";
	s2 = "buzzard";
	cout << "s2: " << s2 << endl;
	cout << "You can concatenate strings: s3 = s1 + s2\n";
	s3 = s1 + s2;
	cout << "s3: " << s3 << endl;
	cout << "You can append strings.\n";
	s2 += " for a day";
	cout << "s2 += \" for a day\" yields s2 = " << s2 << endl;
	return 0;
}

转义序列\"表示双引号,而不是字符串结尾。

3.3.3 string类的其他操作

两种确定字符串中字符数的方法:

int len1 = str1.size();

int len2 = strlen(charr1);

3.3.4 string类I/O

#include <iostream>
#include <string>
#include <cstring>

int main()
{
	using namespace std;
	char charr[20];
	string str;

	cout << "Length of string in charr before input: "
		 << strlen(charr) << endl;
	cout << "Length of string in str before input: "
		 << str.size() << endl;
	cout << "Enter a line of text:\n";
	cin.getline(charr, 20);
	cout << "You entered: " << charr << endl;
	cout << "Enter another line of text:\n";
	getline(cin, str);
	cout << "Length of string in charr after input: "
		 << strlen(charr) << endl;
	cout << "Length of string in str after input: "
		 << str.size() << endl;
	return 0;
}

3.4  结构简介

3.4.1 在程序中使用结构

structur.cpp

#include <iostream>

struct inflatable
{
	char name[20];
	float volume;
	double price;
};

int main()
{
	using namespace std;
	inflatable guest =
	{
		"Glorious Gloria",
		1.88,
		29.99
	};
	inflatable pal =
	{
		"Audacious Arthur",
		3.12,
		32.99
	};

	cout << "Expand your guest list with " << guest.name;
	cout << " and " << pal.name << "!\n";
	cout << "You can have both for $";
	cout << guest.price + pal.price << " !\n";
	return 0;
}

结构声明的位置:

3.4.2 结构可以将string类作为成员

#include <string>
using namespace std;
struct inflatable
{
    string name;
    float volume;
    double price;
};

3.4.3 结构数组

arrstruc.cpp

#include <iostream>

struct inflatable
{
	char name[20];
	float volume;
	double price;
};

int main()
{
	using namespace std;
	inflatable guests[2] =
	{
		{"Bambi",0.5,21.99},
		{"Godzilla",2000,565.99}
	};

	cout << "Yhe guests " << guests[0].name << " and " << guests[1].name
		 << "\nhave a combined volume of "
		 << guests[0].volume + guests[1].volume << " cubic feet.\n";
	return 0;
}

3.5 共用体

        共用体(union)是一种数据格式,它能够存储不同的数据类型,但只能同时存储其中的一种类型。也就是说,结构可以同时存储int、long 和 double,共用体只能存储int、long或double。共用体的句法与结构相似,但含义不同。

        共用体的用途之一是,当数据项使用两种或更多种格式(但不会同时使用)时,可节省空间。另外,共用体常用于操作系统数据结构或硬件数据结构。

3.6 枚举

C++的enum工具箱提供了另一种创建符号常量的方式,这种方式可以代替const。示例:

enum spectrum{red, orange, yellow, green, blue, violet, ultroviolet};

这条语句完成两项工作:

· 让spectrum成为新类型的名称;spectrum被称为枚举(enumeration),就像struct变量被称为结构一样。
· 将red. orange. yellow等作为符号常量,它们对应整数值0~7。这些常量叫作枚举量(enumerator)。
可以用枚举名来声明这种类型的变量:

spectrum band;

在不进行强制类型转换的情况下,只能将定义枚举时使用的枚举量赋给这种枚举的变量,如下:

band = blue;        //valid

band = 2000;        //invalid

枚举常被用来定义相关的符号常量,而不是新类型。

可以使用赋值运算符来显式地设置枚举量地值:

enum bits{one = 1, two = 2, four = 4, eight = 8};

3.7 指针和自由存储空间

address.cpp

#include <iostream>


int main()
{
	using namespace std;
	int donuts = 6;
	double cups = 4.5;

	cout << "donuts value = " << donuts;
	cout << " and donuts address = " << &donuts << endl;
	cout << "cups value = " << cups;
	cout << " and cups address = " << &cups << endl;
	return 0;
}

指针是一种特殊类型的变量,用于存储值的地址。*运算符被称为间接值或解除引用运算符,将其用于指针,可以得到该地址处存储的值。

pointer.cpp

#include <iostream>

int main()
{
	using namespace std;
	int updates = 6;
	int * p_updates;
	p_updates = &updates;

	cout << "Value: updates = " << updates;
	cout << ", *p_updates = " << *p_updates << endl;

	cout << "Address: &updates = " << &updates;
	cout << ", p_updates = " << p_updates << endl;

	*p_updates = *p_updates + 1;
	cout << "Now updates = " << updates << endl;
	return 0;
}

        从中可知,int变量updates 和指针变量p_updates只不过是同一枚硬币的两面。变量updates 表示值,并使用&运算符来获得地址;而变量 p_updates表示地址,并使用*运算符来获得值。由于p_updates指向 updates,因此*p_updates和updates完全等价。可以像使用int变量那样使用*p_updatcs。正如程序表明,甚至可以将值赋给*p_updates。这样做将修改指向的值,即updates。

3.7.1 声明和初始化指针

指针声明必须指定指针指向的数据类型。

#include <iostream>

int main()
{
	using namespace std;
	int higgens = 5;
	int* pt = &higgens;
	cout << "Value of higgens = " << higgens
		 << "; Address of higgens = " << &higgens << endl;
	cout << "Value of *pt = " << *pt
		 << "; Value of pt = " << pt << endl;
	return 0;
}

3.7.2 指针的危险

        在C++中创建指针时,计算机将分配用来存储地址的内存,但不会分配用来存储指针所指向的数据的内存,为数据提供内存是一个独立的步骤,错误示例:

long * fellow;

*fellow = 223323;

一定要在对指针应用解除引用运算符*之前,将指针初始化为一个确定的、适当的地址。

3.7.3 指针和数字

错误示例:

int * pt;

pt = 0xB8000000;

正确示例:

int * pt;

pt  = (int *) 0xb8000000;        //强制类型转化

3.7.4 使用new来分配内存

为一个数据对象(可以是结构,也可以是基本类型)获得并指定分配内存的通用格式如下:

typename * pointer_name = new typename;

use_new.cpp

#include <iostream>

int main()
{
	using namespace std;
	int nights = 1001;
	int* pt = new int;
	*pt = 1001;
	
	cout << "nights value = ";
	cout << nights << ": location " << &nights << endl;
	cout << "int ";
	cout << "value = " << *pt << ": location = " << pt << endl;
	double* pd = new double;
	*pd = 10000001.0;

	cout << "double ";
	cout << "vlalue = " << *pd << ": location = " << pt << endl;
	cout << "location of pointer pd: " << &pd << endl;
	cout << "size of pt = " << sizeof(pt);
	cout << ": size of *pt = " << sizeof(*pt) << endl;
	cout << "size of pd = " << sizeof(pd);
	cout << ": size of *pd = " << sizeof(*pd) << endl;
	return 0;
}

3.7.5 使用delete释放内存

int * ps = new int;

...

delete ps;

这将释放ps指向的指针,但不会删除ps本身。另外,不能使用delete来释放声明变量所获得的内存,如下:

int jugs = 5;

int * pi = &jugs;

delete pi;        //错误用法

只能用delete来释放使用new分配的内存。

3.7.6 使用new来创建动态数组

1. 使用new创建动态数组

int * psome = new int [10];

new运算符返回第一个元素的地址。释放内存:

delete [] psome;

使用new和delete时,应遵守以下规则:

· 不要使用delete来释放不是new分配的内存;

· 不要使用delete释放同一个内存块两次;

· 如果使用new [] 为数组分配内存,则应使用delete [] 来释放;

· 如果使用new [] 为一个实体分配内存,则应使用delete(没有方括号)来释放;

· 对空指针使用delete是安全的。

为数组分配内存的通用格式如下:

type_name * pointer_name = new type_name [num_elements];

2. 使用动态数组

可以把指针当作数组名使用:psome[0],psome[1],...(数组和指针基本等价)

arraynew.cpp

#include <iostream>

int main()
{
	using namespace std;
	double* p3 = new double[3];
	p3[0] = 0.2;
	p3[1] = 0.5;
	p3[2] = 0.8;
	cout << "p3[1] is" << p3[1] << ".\n";
	p3 = p3 + 1;	//不能修改数组名的值,但指针变量可以修改
	cout << "Now p3[0] is " << p3[0] << " and ";
	cout << "p3[1] is " << p3[1] << ".\n";
	p3 = p3 - 1;
	delete[] p3;
	return 0;
}

3.8 指针、数组和指针算数

addpntrs.cpp

#include <iostream>

int main()
{
	using namespace std;
	double wages[3] = { 10000.0, 20000.0, 30000.0 };
	short stacks[3] = { 3, 2, 1 };

	//两种获取数组地址的方式
	double* pw = wages;
	short* ps = &stacks[0];

	cout << "pw = " << pw << ", *pw = " << *pw << endl;
	pw = pw + 1;
	cout << "add 1 to the pw pointer:\n";
	cout << "pw = " << pw << ", *pw  = " << *pw << "\n\n";
	cout << "ps = " << ps << ", *ps = " << *ps << endl;
	ps = ps + 1;
	cout << "add 1 to the ps pointer:\n";
	cout << "ps = " << ps << ", *ps = " << *ps << "\n\n";

	cout << "access two elemnets with notation\n";
	cout << "stacks[0] = " << stacks[0]
		<< ", stacks[1] = " << stacks[1] << endl;
	cout << "access two elemnents with pointer notation\n";
	cout << "*stacks = " << *stacks
		<< ", *(stacks + 1) = " << *(stacks + 1) << endl;

	cout << sizeof(wages) << " = size of wages array\n";
	cout << sizeof(pw) << " = size of pw pointer\n";
	return 0;
}

在多数情况下,C++将数组名解释为数组第一个元素的地址。

将指针变量加1后,其增加的值等于指向的类型占用的字节数。总之,使用new来创建数组以及使用指针来访问不同的元素很简单,只要把指针当作数组名对待即可。

3.8.1 指针小结

1. 声明指针

double * pn;

char * pc;

2. 给指针赋值

double * pn;

double * pa;

char * pc;

double bubble = 3.2;

pn = &bubble;

pc = new char;

pa = new double[30];

3. 对指针解除引用

对指针解除引用意味着获得指针指向的值。

cout << *pn;

*pc = 'S';

另一种对指针解除引用的方法是使用数组表示法,例如,pn[0]和*pn是一样的。不能对未被初始化为适当地址的指针解除引用。

4. 区分指针和指针所指向的值

int * pt = new int;

*pt = 5;

5. 数组名

在多数情况下,C++将数组名视为数组的第一个元素的地址。

int tacos[10];

将sizeof运算符用于数组名时,此时将返回整个数组的长度(字节)。

6. 指针算数

C++允许将指针和整数相加。加1的结果等于原来的地址值加上指向的对象占用的总字节数。还可以将一个指针减去另一个指针,获得两个指针的差。后一种运算将得到一个整数,仅当两个指针指向同一个数组时,这种运算才有意义;这将得到两个元素的间隔。

7. 数组的动态联编和静态联编

使用数组声明来创建数组时,将采用静态联编,即数组的长度在编译时设置:

int tacos[10];

使用new[]运算符创建数组时,将采用动态联编(动态数组),即将在运行时为数组分配空间,其长度也将在运行时设置。使用完这种数组后,应使用delete[]释放其占用的内存:

int size;

cin >> size;

int * pz = new int [size];

...

delete [] pz;

8. 数组表示法和指针表示法

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

int * pt = new int[10];

*pt = 5;

pt[0] = 6;

pt[9] = 44;

int coats[10];

*(coats + 4) = 12;

3.8.2 指针和字符串

在 cout 和多数C++表达式中,char数组名、char指针以及用引号括起的字符串常量都被解释为字符串第一个字符的地址。

ptrstr.cpp

#include <iostream>
#include <cstring>
int main()
{
	using namespace std;
	char animal[20] = "bear";
	const char* bird = "wren";
	char* ps;

	cout << animal << " and ";
	cout << bird << "\n";

	cout << "Enter a kind of animal: ";
	cin >> animal;

	ps = animal;
	cout << ps << "!\n";
	cout << "Before using strcpy():\n";
	cout << animal << " at " << (int*)animal << endl;
	cout << ps << " at " << (int*)ps << endl;
	
	ps = new char[strlen(animal) + 1];
	strcpy_s(ps, strlen(animal) + 1, animal);
	cout << "After using strcpy():\n";
	cout << animal << " at " << (int*)animal << endl;
	cout << ps << " at " << (int*)ps << endl;
	delete[] ps;
	return 0;
}

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

3.8.3 使用new创建动态结构

如果结构标识符是结构名,则使用句点运算符;如果标识符是指向结构的指针,则使用箭头运算符。

newstrct.cpp

#include <iostream>

struct inflactable
{
	char name[20];
	float volume;
	double price;
};

int main()
{
	using namespace std;
	inflactable* ps = new inflactable;
	cout << "Enter name of inflactable item: ";
	cin.get(ps->name, 20);
	cout << "Enter volume in cubic feet: ";
	cin >> (*ps).volume;
	cout << "Enter price: $";
	cin >> ps->price;
	cout << "Name: " << (*ps).name << endl;
	cout << "Volume: " << ps->volume << " cubic feet\n";
	cout << "Price: $" << ps->price << endl;
	delete ps;
	return 0;
}

3.8.4 自动存储、静态存储和动态存储

1. 自动存储

        在函数内部定义的常规变量使用自动存储空间,被称为自动变量( automatic variable),这意味着它们在所属的函数被调用时自动产生,在该函数结束时消亡。
        实际上,自动变量是一个局部变量,其作用域为包含它的代码块。代码块是被包含在花括号中的一段代码。到目前为止,我们使用的所有代码块都是整个函数。然而,在下一章将会看到,函数内也可以有代码块。如果在其中的某个代码块定义了一个变量,则该变量仅在程序执行该代码块中的代码时存在。
        自动变量通常存储在栈中。这意味着执行代码块时,其中的变量将依次加入到栈中,而在离开代码块时,将按相反的顺序释放这些变量,这被称为后进先出(LIFO)。因此,在程序执行过程中,栈将不断地增大和缩小。

2. 静态存储

        静态存储是整个程序执行期间都存在的存储方式。使变量成为静态的方式有两种:一种是在函数外面定义它;另一种是在声明变量时使用关键字static:

        static double fee = 56.50;

        自动存储和静态存储的关键在于:这些方法严格地限制了变量地寿命。变量可能存在于程序的整个生命周期(静态变量),也可能只是在特定函数被执行时存在(自动变量)。

3. 动态存储

        new和delete运算符提供了一种比自动变量和静态变量更灵活的方法。它们管理了一个内池,这在C++中被称为自由存储空间(free store)或堆(heap)。该内存池同用于静态变量和自动变量的内存是分开的。new和 delete 能够在一个函数中分配内存,而在另一个函数中释放它。因此,数据的生命周期不完全受程序或函数的生存时间控制。与使用常规变量相比,使用new和delete让程序员对程序如何使用内存有更大的控制权。然而,内存管理也更复杂了。在栈中,自动添加和删除机制使得占用的内存总是连续的,但new和delete的相互影响可能导致占用的自由存储区不连续,这使得跟踪新分配内存的位置更困难。

3.9 类型组合

mixtypes.cpp

#include <iostream>

struct antarctica_years_end
{
	int year;
};

int main()
{
	antarctica_years_end s01, s02, s03;		//结构变量
	s01.year = 1998;
	antarctica_years_end* pa = &s02;	//指向结构的指针
	pa->year = 1999;
	antarctica_years_end trio[3];	//结构数组
	trio[0].year = 2003;
	std::cout << trio->year << std::endl;
	const antarctica_years_end* arp[3] = { &s01,&s02,&s03 };	//指针数组
	std::cout << arp[1]->year << std::endl;
	const antarctica_years_end** ppa = arp;
	auto ppb = arp;

	std::cout << (*ppa)->year << std::endl;
	std::cout << (*(ppb + 1))->year << std::endl;
	return 0;
}

3.10 数组的替代品

3.10.1 模板类vector

        模板类vector类似于string类,也是一种动态数组。可以在运行阶段设置vector对象的长度,可在末尾附加新数据,还可以在中间插入新数据。

        首先,要使用vector对象,必须包含头文件vector;其次,vector包含在名称空间std中,可以使用using编译指令、using声明或std::vector。第三,模板使用不同的语法来指出它存储的类型。第四,vector类使用不同的语法来指定元素数。示例:

#include <vector>
...
using namespace std;
vector<int> vi;
int n;
cin >> n;
vector<double> vd(n);

        下面的声明创建一个名为vt的vector对象,它可以存储n_elem个类型为typeName的元素:

        vector<typeName> vt(n_elem);

        其中n_elem可以是整型常量,也可以是整型变量。

3.10.2 模板类array

        下面的声明创建一个名为arr的array对象,它包含n_elem个类型为typename的元素:

        array<typeName,n_elem> arr;

        n_elem不能是变量。

3.10.3 比较数组、vector对象和array对象

choices.cpp

#include <iostream>
#include <vector>
#include <array>

int main() 
{
    using namespace std;
    double a1[4] = { 1.2,2.4,3.6,4.8 };
    vector<double> a2(4);
    a2[0] = 1.0 / 3.0;
    a2[1] = 1.0 / 5.0;
    a2[2] = 1.0 / 7.0;
    a2[3] = 1.0 / 9.0;
    array<double, 4> a3 = { 3.14,2.72,1.62,1.41 };
    array<double, 4> a4;
    a4 = a3;
    cout << "a1[2]: " << a1[2] << " at " << & a1[2] << endl;
    cout << "a2[2]: " << a2[2] << " at " << & a2[2] << endl;
    cout << "a3[2]: " << a3[2] << " at " << & a3[2] << endl;
    cout << "a4[2]: " << a4[2] << " at " << & a4[2] << endl;
    a1[-2] = 20.2;
    cout << "a1[-2]: " << a1[-2] << " at " << &a1[-2] << endl;
    cout << "a3[2]: " << a3[2] << " at " << &a3[2] << endl;
    cout << "a4[2]: " << a4[2] << " at " << &a4[2] << endl;

    return 0;
}

        首先,注意到无论是数组、vector 对象还是array对象,都可使用标准数组表示法来访问各个元素。其次,从地址可知,array 对象和数组存储在相同的内存区域(即栈)中,而vector对象存储在另一个区域(自由存储区或堆)中。第三,注意到可以将-一个 array对象赋给另- -个array对象;而对于数组,必须逐元素复制数据。

        a1[-2] = 20.2;        //等价于 *(a1-2) = 20.2;即找到a1所指的地方,向前移两个double

3.11 总结

        数组、结构和指针是C++的3种复合类型。数组可以在一个数据对象中存储多个同种类型的值。通过使用索引或下标,可以访问数组中各个元素。
        结构可以将多个不同类型的值存储在同一个数据对象中,可以使用成员关系运算符来访问其中的成员。使用结构的第一步是创建结构模板,它定义结构存储了哪些成员。模板的名称将成为新类型的标识符,然后就可以声明这种类型的结构变量。
        共用体可以存储一个值,但是这个值可以是不同的类型,成员名指出了使用的模式。
        指针是被设计用来存储地址的变量。我们说,指针指向它存储的地址。指针声明指出了指针指向的对象的类型。对指针应用解除引用运算符,将得到指针指向的位置中的值。
        字符串是以空字符为结尾的一系列字符。字符串可用引号括起的字符串常量表示,其中隐式包含了结尾的空字符。可以将字符串存储在 char 数组中可以用被初始化为指向字符串的 char 指针表示字符串。函数strlen()返回字符串的长度,其中不包括空字符。函数strcpy()将字符串从一个位置复制到另一个位置。在使用这些函数时,应当包含头文件cstring或string.h。
        头文件string支持的C++ string类提供了另一种对用户更友好的字符串处理方法。具体地说string对象将根据要存储的字符串自动调整其大小,用户可以使用赋值运算符来复制字符串。

        new 运算符允许在程序运行时为数据对象请求内存。该运算符返回获得内存的地址,可以将这个地址赋给一个指针,程序将只能使用该指针来访问这块内存。如果数据对象是简单变量,则可以使用解除引用运算符(*)来获得其值如果数据对象是数组,则以像使用数组名那样使用指针来访问元素;如果数据对象是结构,则可以用指针解除引用运算符(->)来访问其成员。
        指针和数组紧密相关。如果ar 是数组名,则表达式ar[i]被解释为*(ar+i),其中数组名被解释为数组第一个元素的地址。这样,数组名的作用和指针相同。反过来,可以使用数组表示法,通过指针名来访问new分配的数组中的元素。
        运算符new和delete 允许显式控制何时给数据对象分配内存,何时将内存归还给内存池。自动变量是在函数中声明的变量,而静态变量是在函数外部或者使用关键字 static声明的变量,这两种变量都不太灵活。自动变量在程序执行到其所属的代码块(通常是函数定义)时产生,在离开该代码块时终止。静态变量在整个程序周期内都存在。
        C++98新增的标准模板库(STL)提供了模板类 vector,它是动态数组的替代品。C++11提供了模板类array,它是定长数组的替代品。

  • 20
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值