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