第四章 复合类型

4.1 数组

数组可以存储60个int类型的值、12个short值或365个float值。
要创建数组,可使用声明语句。数组声明应指出以下三点:
存储在每个元素中的值的类型;
数组名;
数组中的元素数;

short months[12];		// creats array of 12 short 

程序清单 4.1 arrayone.cpp

// arrayone.cpp -- small arrays fo integers
#include<iostream>
int main()
{
	using namespace std;
	int yams[3];		// create array with three elements
	yams[0] = 7;		// assign value to flaot element
	yams[1] = 8;
	yams[2] = 6;
	
	int yamcosts[3] = {20, 30, 5};	// create, initializa array
	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 << " centa.\n";
	cout << "\nSize of yams array = " << sizeof yams;
	cout << " bytes.\n";
	cout << "Size of one element = " << sizeof yams[0];
	cout << " bytes.\n";
	return 0;
 } 
Total yams = 21
The package with 8 yams costs 30 cents per yam.
The total yam expense is 297 centa.

Size of yams array = 12 bytes.
Size of one element = 4 bytes.

4.1.1 程序说明

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

int cards[4] = {3, 6, 8, 10};		// okay
int hand[4];						// okay
hand[4] = {5, 6, 7, 9};				// not allowed
hand = cards;						// not allowed 

初始化hotelTips的前两个元素

float hotelTips[5] = {1.0, 2.0}

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

4.1.3 C++ 数组初始化方法
初始化数组时可省略等号

int cards[4] {3, 6, 8, 10};		// okay

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

int cards[4] = {};		// okay

列表初始化禁止缩窄转换

4.2 字符串

char dog[8] = {'b','a'};		// not a string;
char cat[8] = {'b','a','\0');		// a string!
char bird[11] = "Mr.Cheeps";		// the \0 is understood

4.2.1 拼接字符串常量
下面所有的输出语句都是等效的

cout << "I'd give my right arm to be" " a great violinist.\n";
cout << "'d give my right arm to be a great violinist.\n";
cout << "I'd give my right ar"
"m to be a great violinist.\n";

4.2.2 在数组中使用字符串
程序清单4.2 string.cpp

// strings.cpp -- storing strings in an array
#include<iostream>
#include<cstring>	// for the strlen() function
int main()
{
	using namespace std;
	const int Size = 15;
	char name1[Size];					// empty array
	char name2[Size] = "C++owboy";		// initialized array
	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';			// set to null cahracter 
	cout << "Here are the first 3 characters of my name: ";
	cout << name2 << endl;
	return 0;
}
Howdy! I'm C++owboy! What's your name?
Bing
Well, Bing, your name has 4 letters and is stored
in an array of 15 bytes.
Your initial is B.
Here are the first 3 characters of my name: C++

strlen()函数返回的是存储在数组中的字符串的长度,而不是数组本身的长度。
另外,strlen()只计算可见的字符,而不把空字符计算在内。
程序清单4.3 instr1.cpp

// instr1.cpp -- reading more than one string
#include<iostream>
int main()
{
	using namespace std;
	const int ArSize = 20;
	char name[ArSize];
	char dessert[ArSize];
	
	cout << "Enter your name:\n";
	cin >> name;
	cout << "Enter your favorite dessert:\n";
	cin >> dessert;
	cout << "I have some delicious " << dessert;
	cout << " for you. " << name << ".\n";
	return 0;
 } 
Enter your name:
bing
Enter your favorite dessert:
cake
I have some delicious cake for you. bing.

4.2.4 每次读取一行字符串输入
1、面向行的输入:getline()
getline()函数读取整行,它使用通过回车键输入的换行符来确定输入结尾。
第一参数:存储输入行的数组的名称
第二参数:要读取的字符数,如果这个参数为20,则函数最多读取19个字符,余下的空间用于存储自动在结尾处添加的空字符。

cin.getline(name,20)

程序清单4.4 instr2.cpp

// instr2.cpp -- reading more than one word with getline
#include<iostream>
int main()
{
	using namespace std;
	const int ArSize = 20;
	char name[ArSize];
	char dessert[ArSize];
	
	cout << "Enter your name:\n";
	cin.getline(name, ArSize);		// reads through newline 
	cout << "Enter your favorite dessert:\n";
	cin.getline(dessert, ArSize);
	cout << "I have some delicious " << dessert;
	cout << " for you. " << name << ".\n";
	return 0;
 } 
Enter your name:
bing bing
Enter your favorite dessert:
chocolate cake
I have some delicious chocolate cake for you. bing bing.

2、面向行的输入: get()
使用不带任何参数的cin.get()调用可读取写一个字符(即使是换行符)

cin.get(name, Arsize);		// read first line
cin.get();					// read newline 
cin.get(dessert, Arisize)	// read second line

程序清单 4.5 instr3.cpp

// instr3.cpp -- reading more than one word with get() & get() 
#include<iostream>
int main()
{
	using namespace std;
	const int ArSize = 20;
	char name[ArSize];
	char dessert[ArSize];
	
	cout << "Enter your name:\n";
	cin.get(name, ArSize).get();		// read  string, newline
	cout << "Enter your favorite dessert:\n";
	cin.get(dessert, ArSize).get();
	cout << "I have some delicious " << dessert;
	cout << " for you. " << name << ".\n";
	return 0;
 } 
Enter your name:
k night
Enter your favorite dessert:
cute cake
I have some delicious cute cake for you. k night.

3、空行和其他问题
当get()读取空行后将设置失效位(failbit)。这意味着接下来的输入将被阻断,但可以用下面的命令类恢复输入:

cin.clear();

4.2.5 混合输入字符串和数字
程序清单 4.6 numstr.cpp

// numstr.cpp -- following number input with line input
#include <iostream>
int main()
{
	using namespace std;
	cout << "What year was your house built?\n";
	int year;
	cin >> year;
	cout << "What is its street address?\n";
	char address[80];
	cin.getline(address, 80);
	cout << "Year built: " << year << endl;
	cout << "Address: " << address << endl;
	cout << "Done!\n";
	return 0;
 } 
What year was your house built?
1999
What is its street address?
Year built: 1999
Address:
Done!

用户根本没有输入地址的机会。问题在于,当cin读取年份,将回车键生成的换行符留在了输入队列中。后面的cin.getline()看到换行符后,将认为是一个空行,并将一个空字符串赋给address数组。解决之道是,在读取地址之前先读取并丢弃换行符。
解决方法一:

cin >> year;
cin.get();		// or cin.get(ch);
(cin >> year).get();		// or (cin >> year).get(ch);
What year was your house built?
1999
What is its street address?
bbb ccc city
Year built: 1999
Address: bbb ccc city
Done!

4.3 string类简介

程序清单4.7 strtype1.cpp

// strtype1.cpp -- using the C++ string class
#include<iostream>
#include<string>				// make string class available
int main()
{
	using namespace std;
	char charr1[20];		// create an empty array
	char charr2[20] = "jaguar";		// create an initialized array
	string str1;			// create an empty string object
	string str2 = "panther";		// create an initialized string
	
	cout << "Enter a kind of feline: ";
	cin >> charr1;
	cout << "Enter another kind of feline:";
	cin >> str1;				// use cin for input
	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;	// use array notation
	
	return 0;
	 
 } 
Enter a kind of feline: tiger
Enter another kind of feline:panda
Here are some feline:
tiger jaguar panda panther
The third letter in jaguar is g
The third letter in panther is n

4.3.1 C++字符串初始化
4.3.2 赋值、拼接和附加
使用string类时,某些操作比使用数组时更简单。例如,不能将一个数组赋给另一个数组,但可以将一个string对象赋给另一个string对象:

char charr1[20];		// create an empty array
char charr2[20]  = "jaguar";		// create an initialized array
string str1;						// create an empty string object
string st2 = "panther"; 			// create an initialized string
charr1 = charr2;					// INVALID,no array assignment
str1 = str2;						// VALID, object assignment ok

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

string str3;
str3 = str1 + str2;		// assign str3 the joined strings
str1 += str2;			// add str2 to the end of str1

程序清单4.8 strtype2.cpp

//  strtype2.cpp -- assigning, adding, and appending
#include<iostream>
#include<string>		// make string class available
int main()
{
	using namespace std;
	string s1 = "penguin";
	string s2, s3;
	
	cout << "You can 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 to a 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";
	s1 += s2;
	cout << "s1 += s2 yields s1 = " << s1 << endl;
	s2 += " for a day";
	cout << "s2 += \" for a day\" yields s2 = " << s2 << endl;
	
	return 0;
 } 
You can assign one string object to another: s2 = s1
s1: penguin, s2: penguin
You can assign a C-style string to a string object.
s2 = "buzzard"
s2: buzzard
You can concatenate strings: s3 = s1 + s2
s3: penguinbuzzard
You can append strings.
s1 += s2 yields s1 = penguinbuzzard
s2 += " for a day" yields s2 = buzzard for a day

4.3.3 string类的其他操作

strcpy(charr1, charr2);		// copy charr2 to charr1
strcat(charr1, charr2);		// append contents of charr2 to charr1

程序清单4.9 strtype3.cpp

// strtype3.cpp -- more string class features
#include<iostream>
#include<string> 				// make string class available
#include<cstring>				// C-style string library
int main()
{
	using namespace std;
	char charr1[20];
	char charr2[20] = "jaguar";
	string str1;
	string str2 = "panther";
	
	// assignment for string objects and character arrays
	str1 = str2;			// copy str2 to str1
	strcpy(charr1, charr2);	// copy charr2 to charr1
	// appending for string objects and character arrays
	str1 += " paste";		// add paste to end of str1
	strcat(charr1, " juice") ; // add juice to end of charr1
	// finding the length of a string object and a C-style string
	int len1 = str1.size();		// obtain length of str1
	int len2 = strlen(charr1);	// obtain length of charr1
	
	cout << "The string " << str1 << " contains "
		 << len1 << " character.\n";
	cout << "The string " << charr1 << " contains "
		 << len2 << " characters.\n";
		 
	return 0; 
 } 
The string panther paste contains 13 character.
The string jaguar juice contains 12 characters.

4.3.4 string类 I/O
程序清单4.10 strtype4.cpp

// strtype4.cpp -- line input
#include<iostream>
#include<string>		// make string class availble
#include<cstring>		// C-style string library
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);		// indicate maximum length
	cout << "You entered: " << charr << endl;
	cout << "Enter another line of txt:\n";
	getline(cin, str);		// cin now an argument; no length specifier
	cout << "You entered: " << str << endl;
	cout << "Length of string in charr after input: "
		 << strlen(charr) << endl;
	cout << "Length of string in str after input: "
		 << str.size() << endl;
		 
	return 0;
 } 
Length of string in charr before input: 1
Length of string in str before input: 0
Enter a line of text:
peanut butter
You entered: peanut butter
Enter another line of txt:
blueberry jam
You entered: blueberry jam
Length of string in charr after input: 13
Length of string in str after input: 13

4.4 结构简介

程序清单4.11 structur.cpp

// structure.cpp -- a simple structure
#include <iostream>
struct inflatable  // structure declaraction
{
	char name[20];
	float volume;
	double price;
};

int main()
{
	using namespace std;
	inflatable guest = 
	{
		"Glorious Gloria", 		// name value
		1.88,					// volume value
		29.99					// price value
	};			// guest is a structure variable of type inflatable
	// It's Initialized to the indicated values
	inflatable pal = 
	{
		"Audacious Arthur",
		3.12,
		32.99
	 } ;    // pal is a second variable of type inflatable
	 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;
}
Expand your guest list with Glorious Gloria and Audacious Arthur!
You can have both for $62.98:

4.4.2 C++ 结构初始化

inflatable duck {"Daphne", 0.12, 9.98};		// can omit the = in C++11

如果大括号内未包含任何东西,各个成员都将设置为零。

inflatable mayor{};

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

// structure.cpp -- a simple structure
#include <string>
struct inflatable  // structure declaraction
{
	std::string name; 
	float volume;
	double price;
};

4.4.4 其他结构属性
程序清单 4.12 assgn_st.cpp

// assgn_st.cpp -- assigning structures
#include <iostream>
struct inflatable  // structure declaraction
{
	char name[20];
	float volume;
	double price;
};

int main()
{
	using namespace std;
	inflatable bouquet = 
	{
		"sunflowers", 		
		0.20,				
		12.49			
	};			
	inflatable choice;
	cout << "bouquet: " << bouquet.name << " for $";
	cout << bouquet.price << endl;
	
	choice = bouquet;   // assign one structure to another
	cout << "choice: " << choice.name << " for $";
	cout << choice.price << endl;
	return 0;
}
bouquet: sunflowers for $12.49
choice: sunflowers for $12.49

初始化时同时完成定义结构和创建结构变量

struct perks
{
	int key_number;
	char car[12];
} mr_glitz = 
{
	7,		// value for my_glitz.key_number member
	"Packard" 	// value for my_glitz.car member 
};

当声明没有名称的结构类型时,名称默认为position
4.4.5 结构数组
程序清单 4.13 arrstruc.cpp

// arrstruc.cpp -- an array of structure
#include<iostream>
struct inflatable
{
	char name[20];
	float volume;
	double price;
 } ;
 int main()
 {
 	using namespace std;
 	inflatable guests[2] = 			// initializing an array of structs
	{
		{"Bambi", 0.5, 21.99},		// first structure in array
		{"Godzilla", 2000, 565.99}	// next structure in array
	 } ;
	 
	 cout << "The guests " << guests[0].name << " and " << guests[1].name
	 	  << "\nhave a combined volume of "
	 	  << guests[0].volume + guests[1].volume << " cubic feet.\n";
	return 0;
 }
The guests Bambi and Godzilla
have a combined volume of 2000.5 cubic feet.

4.5 共用体

共用体(union)是一种数据格式,它能够存储不同的数据类型,但只能同时存储其中的一种类型。

union one4all
{
	int int_val;
	long long_val;
	double double_val;
};

one4all pail;
pail.int_val = 15; 			// store an int
cout << pail.int_val;
pail.double_val = 1.38;		// store a double, int value is lost
cout << pail.double_val;

4.6 枚举

enum允许定义新类型

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

这条语句完成两项工作。
1、让spectrum成为新类型的名称:spectrum被称为枚举(enumeration)
2、将red、orange、yellow等作为符号常量,它们对应整数值0-7.这些常量叫做枚举量(enumerator)
4.6.1 设置枚举量的值
使用赋值运算符显式设置枚举量的值

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

指定的值必须是整数。也可以显示地定义其中一些枚举量地值:

enum bigstep{first, second = 100, third};

这里,first在默认情况下为0。后面没有被初始化地枚举量的值将比其前面的枚举量大1。因此,third的值为101。
最后,可以创建多个值相同的枚举量:

enum{zero, null = 0, one, numero_uno = 1};

其中,zero和null都为0,one和numero_uno都为1。
4.6.2 枚举的取值范围

枚举上限:大于最大值的、小于2的幂,将它减去1.
枚举下限:最小值不小于0,则取值范围的下限为0;最小值小于0,比它小的,最大的2的幂,加1.

4.7 指针和自由存储空间

程序清单4.14 address.cpp

// address.cpp -- using the & operator to find addresses
# 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;
 } 
donuts value = 6 and donuts address = 0x70fe0c
cups value = 4.5 and cups address = 0x70fe00

指针名表示的是地址。*运算符被称为间接值(indirect value)或解除引用(dereferencing)运算符,将其应用于指针,可以得到该地址处存储的值。
程序清单 4.15 pointer.cpp

// pointer.cpp -- our first pointer varaible
#include <iostream>
int main()
{
	using namespace std;
	int updates = 6;		// declare a variable
	int * p_updates;	// declare pointer to an int
	p_updates = &updates;	// assign address of int to pinter
	
	// express values two ways
	cout << "Values: updates = " << updates;
	cout << ", *p_updates = " << *p_updates << endl;
	// express address two ways
	cout << "Addresses: &updates = " << &updates;
	cout << ", p_updates = " << *p_updates << endl;
	// use pointer to change value
	*p_updates = *p_updates + 1;
	cout << "Now updates = " << updates << endl;
	return 0;
 } 
Values: updates = 6, *p_updates = 6
Addresses: &updates = 0x70fe04, p_updates = 6
Now updates = 7

声明和初始化指针
int*是一种类型——指向int的指针

int *ptr;
int* ptr;
int*ptr;
int* p1, p2; //创建一个指针(p1)和一个int变量(p2) 

程序清单4.16 init.ptr.cpp

// init_ptr.cpp -- initialize a pointer
#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;
 } 
Value of higgens = 5; Address of higgens = 0x70fe04
Value of *pt = 5; Value of pt = 0x70fe04

4.7.2 指针的危险
一定要在对指针应用接触引用运算符(*)之前,将指针初始化为一个确定的、适当的地址
4.7.3指针和数字

4.7.4 使用new来分配内存
程序清单4.17 use_new.cpp

// use_new.cpp -- using the new operator
#include<iostream>
int main()
{
	using namespace std;
	int nights = 1001;
	int * pt = new int;				// allocate space for an int
	*pt = 1001;						// store a value there
	
	cout << "nights value = ";
	cout << nights << ": location " << &nights << endl;
	cout << "int ";
	cout << "value = " << *pt << ": location = " << pt << endl;
	double * pd = new double;			// allocate space for a double
	*pd = 10000001.0;					// store a double there
	
	cout << "double value = " << *pd << ": location = " << pd;
	cout << 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;
 } 
nights value = 1001: location 0x70fe04
int value = 1001: location = 0x171540
double value = 1e+007: location = 0x171560
location of pointer pd: 0x70fdf8
size of pt = 8: size of *pt = 4
size of pd = 8: size of *pd = 8

4.7.5 使用delete释放内存

int * ps = new int;		// allocate memory with new
...						// use the memory
delete ps;				// free memory with delete when done
delete ps;				// not ok now
int jugs = 5; 			// ok
int * pi = &jugs;		// ok
delete pi;				// not allowed, memory not alloctaed by new 

4.7.6 使用new来创建动态数组
1、使用new创建动态数组
不要使用delete来释放不是new分配的内存
不要使用delete释放同一个内存块两次
如果使用new[]为数组分配内存,则应使用delete[]来释放
如果使用new[]为一个实体分配内存,则应使用delete(没有方括号)来释放。
对空指针应用delete是安全的
2、使用动态数组
程序清单4.18 arraynew.cpp

// arraynew.cpp -- using the new operator for arrays
#include<iostream>
int main()
{
	using namespace std;
	double * p3 = new double [3];	// space for 3 doubles
	p3[0] = 0.2;					// treat p3 like an array name
	p3[1] = 0.5;	
	p3[2] = 0.8;
	cout << "p3[1] is " << p3[1] << ".\n";
	p3 = p3 + 1;			// increment the pointer
	cout << "Now p3[0] is " << p3[0] << " and ";
	cout << "p3[1] is " << p3[1] << ".\n";
	p3 = p3 - 1;
	delete [] p3;		// free the memory
	return 0; 
 } 
p3[1] is 0.5.
Now p3[0] is 0.5 and p3[1] is 0.8.

指针、数组和指针算术

程序清单 4.19 addpntrs.cpp

// addpntrs.cpp -- pointer addition
#include<iostream>
int main()
{
	using namespace std;
	double wages[3] = {10000.0, 20000.0, 30000.0};
	short stacks[3] = {3, 2, 1};
	
	// here are two ways to get the adress of an array
	double * pw = wages;	//name of an array = address
	short * ps = &stacks[0];	// or use address operator
	// with array element
	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 elements with array notation\n";
	cout << "stacks[0] = " << stacks[0]
		 << ", stacks[1] = " << stacks[1] << endl;
	cout << "access two elements with pointer notation\n";
	cout << "*stacks = " << stacks[0]
		 << ", *(stacks + 1) = " << *(stacks + 1) << endl;
	cout << sizeof(wages) << " = size of wages array\n";
	cout << sizeof(pw) << " = size of pw pointer\n";
	return 0;

 } 
// addpntrs.cpp -- pointer addition
#include<iostream>
int main()
{
	using namespace std;
	double wages[3] = {10000.0, 20000.0, 30000.0};
	short stacks[3] = {3, 2, 1};
	
	// here are two ways to get the adress of an array
	double * pw = wages;	//name of an array = address
	short * ps = &stacks[0];	// or use address operator
	// with array element
	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 elements with array notation\n";
	cout << "stacks[0] = " << stacks[0]
		 << ", stacks[1] = " << stacks[1] << endl;
	cout << "access two elements with pointer notation\n";
	cout << "*stacks = " << stacks[0]
		 << ", *(stacks + 1) = " << *(stacks + 1) << endl;
	cout << sizeof(wages) << " = size of wages array\n";
	cout << sizeof(pw) << " = size of pw pointer\n";
	return 0;

 } 
pw = 0x70fde0, *pw = 10000
add 1 to the pw pointer:
pw = 0x70fde8, *pw = 20000

ps = 0x70fdd0, *ps = 3
add 1 to the ps pointer:
ps = 0x70fdd2, *ps = 2

access two elements with array notation
stacks[0] = 3, stacks[1] = 2
access two elements with pointer notation
*stacks = 3, *(stacks + 1) = 2
24 = size of wages array
8 = size of pw pointer  // 对指针应用sizeof得到的是指针长度

4.8.1 程序说明
4.8.2 指针小结
4.8.3 指针和字符串
程序清单 4.20 ptrstr.cpp

// ptrstr.cpp -- using pointers to strings
#include<iostream>
#include<cstring>				// declare strlen(), strcpy()
int main()
{
	using namespace std;
	char animal[20] = "bear";		// animal holds bear
	const char * bird = "wren";		// bird holds address of string
	char * ps;						// uninialized
	cout << animal << " and ";		// display bear
	cout << bird << "\n";			// dispaly wren
	cout << "Enter a kind of animal: ";
	cin >> animal;			// ok if input < 20 chars
	ps = animal;			// set ps to point to string
	cout << ps << "!\n";	// ok, same as using animal
	cout << "Before using strpcy():\n";
	cout << animal << " at " << (int *) animal << endl;
	cout << ps << " at " << (int *) ps << endl;
	ps = new char[strlen(animal)+1];	// get new storage
	strcpy(ps, animal);					// copy string to new storage
	cout << "After using strcpy():\n";
	cout << animal << " at " << (int *) animal << endl;
	cout << ps << " at " << (int *) ps << endl;
	delete [] ps;
	return 0;
 } 
bear and wren
Enter a kind of animal: fish
fish!
Before using strpcy():
fish at 0x70fdf0
fish at 0x70fdf0
After using strcpy():
fish at 0x70fdf0
fish at 0x1e1540

4.8.4 使用new创建动态结构
程序清单4.21 newstrct.cpp

// newstct.cpp -- using new with a structure
#include<iostream>
struct inflatable
{
	char name[20];
	float volume;
	double price;
 } ;
 int main()
 {
 	using namespace std;
 	inflatable * ps = new inflatable;   // allot memroy for structure
 	cout << "Enter name of inflatble item: ";
 	cin.get(ps->name, 20);				// method 1 for member access
	cout << "Enter volume in cubic feet: ";
	cin >> (*ps).volume;				// method 2 for member access
	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; 
	  
 	
 }
Enter name of inflatble item: Bing
Enter volume in cubic feet: 1.4
Enter price: $20
Name: Bing
Volume: 1.4 cubic feet
Price: $20

1、一个使用new和delete的示例
程序清单4.22定义了一个函数getname(),该函数返回一个指向输入字符串的指针。该函数将输入读入到一个大型的临时数组中,然后使用new[]创建一个刚好能够存储该输入字符串的内存块,并返回一个指向该内存块的指针。
程序清单4.22 delete.cpp

// delete.cpp -- using the delete operator
#include<iostream>
#include<cstring> 		// or string.h
using namespace std;
char * getname(void);	// function prototype
int main()
{
	char * name;		// create pointer but no storage
	name = getname();	// assign address of string to name
	cout << name << " at " << (int *)name << "\n";
	delete [] name;		// memory freed
	name = getname();	// reuse freed memory
	cout << name << " at " << (int *)name << "\n";
	delete [] name;		// memory freed again
	return 0; 
 } 
 
 char * getname()		// retrurn pointer to new string
 {
 	char temp[80];		// temporary storage
 	cout << "Enter last name: ";
 	cin >> temp;
 	char * pn = new char[strlen(temp) + 1];
 	strcpy(pn, temp);	// copy string into smaller space
 	return pn;			// temp lost when function ends 
  } 
Enter last name: bing
bing at 0x1b1540
Enter last name: cing
cing at 0x1b1540

4.8.5 自动存储、静态存储和动态存储
1、自动存储
在函数内部定义的常规变量使用自动存储空间,被称为自动变量(automatic variable),这意味着它们在所属的函数被调用时自动产生,在该函数结束时消亡。
2、静态存储
静态存储是整个程序执行期间都存在的存储方式。使变量成为静态的方式有两种:一种是在函数外面定义它;另一种是在声明变量时使用关键字static:

static double fee = 56.50;

3、动态存储
new和delete运算符提供了一种比自动变量和静态变量更灵活的方法。它们管理了一个内存池,这在C++中被称为自由存储空间(free store)或堆(heap)。该内存池用用于静态变量和自动变量的内存是分开的。让用户在一个函数中分配内存,而在另一个函数中释放它。

4.9 类型组合

创建数组

struct antarctica_years_end
{
	int year;
};

创建这种类型的变量

anatarctica_years_end s01, s02, s03;	// s01, s02, s03 are structures

然后使用成员运算符访问其成员:

s01.year = 1998;

可创建指向这种结构的指针:

anatarctica_year_end * pa = &s02;

将该指针设置为有效地址后,就可使用间接成员运算符来访问成员:

pa->year = 1999;

可创建结构数组:

antarctica_years_end trio[3];		//array of 3 structures

然后,可以使用成员运算符访问元素的成员:

trio[0].year = 2003;	// trio[0] is a structure

其中trio是一个数组,trio[0]是一个结构,而trio[0].year是该结构的一个成员。由于数组名是一个指针,因此也可使用间接成员运算符:

(trio+1)->year = 2004;	// same as trio[1].year = 2004;

可创建指针数组:

const antarctica_year_end * arp[3] = {&s01, &s02, &s03};

arp是一个指针数组,arp[1]是一个指针,可将间接成员运算符应用于它,以访问成员

std::cout << arp[1]->year << std::endl;

可创建指向上述数组的指针

const antarctica_years_end ** ppa = arp;

程序清单 4.23 mixtypes.cpp

// mixtypes.cpp -- some type combinations
#include<iostream>

struct antarctica_years_end
{
	int year;
 } ;
 int main()
 {
 	antarctica_years_end s01, s02, s03;	// s01, s02, s03 are structures
 	s01.year = 1998;
	antarctica_years_end * pa = &s02;
	pa->year = 1999;
	antarctica_years_end trio[3];		//array of 3 structures
	trio[0].year = 2003;	// trio[0] is a structure
	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;
	const antarctica_years_end ** ppb = arp;		//C++11 automatica type ** ppb = arp;
	std::cout << (*ppa)->year << std::endl;
	std::cout << (*(ppb+1))->year << std::endl;
	return 0; 
 }
2003
1999
1998
1999

4.10 数组的替代品

4.10.1 模板类vector
1、要使用vector对象,必须包含头文件vector.
2、vetor包含在名称空间std中,因此可使用using编译指令、using声明或std::vector
3、模板使用不同的语法来指出它存储的数据类型
4、vector类使用不同的语法来制定元素数

#include<vector>
...
using namespacec std;
vector<int>vi;		//create a zero-size array of int
int n;
cin >> n;
vector<double>vd(n);	// create an array of n doubles

4.10.2 模板类array(C++11)

#include<array>
...
using namespace std;
array<int, 5>ai;	// create array object of 5 ints
array<double, 4> ad = {1.2 2.1 3.43 4.3};

4.10.3 比较数组、vector对象和array对象
程序清单 4.24 choices.cpp

// choices.cpp --array variations
#include<iostream>
#include<vector>	
#include<array>		//C++
int main()
{
	using namespace std;
	double a1[4] = {1.2, 3.3, 4.4, 5.5};
	vector<double> a2(4);		// create vector with 4 elements
	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 = {1.23, 2.34, 3.45, 4.56};
	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;
}
 
a1[2]: 4.4 at 0x71fda0
a2[2]: 0.142857 at 0xd1550
a3[2]: 3.45 at 0x71fdc0
a4[2]: 3.45 at 0x71fde0
a1[-2]: 20.2 at 0x71fd80
a3[2]: 3.45 at 0x71fdc0
a4[2]: 3.45 at 0x71fde0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值