C++Primer中文版(第四版)习题及详细分析

2025-04-26

习题 1.1

查看所用的编译器文档,了解它所用的文件命名规范。编译并运行本节的main 程序。 【解答】

一般而言,C++编译器要求待编译的程序保存在文件中。C++程序中一般涉及两 类文件:头文件和源文件。大多数系统中,文件的名字由文件名和文件后缀(又 称扩展名)组成。文件后缀通常表明文件的类型,如头文件的后缀可以是.h 或.hpp 等;源文件的后缀可以是.cc 或.cpp 等,具体的后缀与使用的编译器有

关。通常可以通过编译器所提供的联机帮助文档了解其文件命名规范。 习题1.2

修改程序使其返回-1。返回值-1 通常作为程序运行失败的指示器。然而,系统 不同,如何(甚至是否)报告main 函数运行失败也不同。重新编译并再次运行 程序,看看你的系统如何处理main 函数的运行失败指示器。 【解答】

笔者所使用的Windows操作系统并不报告main 函数的运行失败,因此,程序返 回-1 或返回0 在运行效果上没有什么区别。但是,如果在DOS 命令提示符方式 下运行程序,然后再键入echo %ERRORLEVEL%命令,则系统会显示返回值-1。 习题1.3

编一个程序,在标准输出上打印“Hello, World”。

#include #include %using namespace std; int main()

{ system(\ cout<<\ return 0; }

习题1.4

我们的程序利用内置的加法操作符“+”来产生两个数的和。编写程序,使用乘 法操作符“*”产生两个数的积。

#include #include %using namespace std; int main()

{ system(\ cout<<\ int v1,v2; cin>>v1>>v2; cout<<\ return 0; }

习题1.5

我们的程序使用了一条较长的输出语句。重写程序,使用单独的语句打印每一

个操作数。

#include #include %using namespace std; int main() {

system(\

cout << \int v1, v2;

cin >> v1 >> v2;

cout << \cout << v1;

cout << \cout << v2; cout << \cout << v1 + v2 ; cout << endl; return 0; }习题1.6

解释下面的程序段:

std::cout << \<< \<< \<< std::endl;

这段代码合法吗?如果合法,为什么?如果不合法,又为什么? 【解答】

这段代码不合法。

注意,第1、2、4 行的末尾有分号,表示这段代码包含三条语句,即第1、2 行 各为一个语句,第3、4 行构成一个语句。“<<”为二元操作符,在第2、3 两 条语句中,第一个“<<”缺少左操作数,因此不合法。 在第2、3 行的开头加上“std::cout”,即可更正。 习题1.7

编译有不正确嵌套注释的程序。 【解答】

由注释对嵌套导致的编译器错误信息通常令人迷惑。例如,在笔者所用的编译 器中编译1.3 节中给出的带有不正确嵌套注释的程序: #include /*

* comment pairs /* */ cannot nest.

* \* as is the rest of the program */

int main() {

return 0; }

编译器会给出如下错误信息:

error C2143: syntax error : missing ';' before '<'

error C2501: 'include' : missing storage-class or type specifiers warning C4138: '*/' found outside of comment (第6 行)

error C2143: syntax error : missing ';' before '{' (第8 行)

error C2447: '{' : missing function header (old-style formal list?)(第 8 行) 习题1.8

指出下列输出语句哪些(如果有)是合法的。 std::cout << \std::cout << \

std::cout << /* \

预测结果,然后编译包含上述三条语句的程序,检查你的答案。纠正所遇到的 错误。 【解答】

第一条和第二条语句合法。

第三条语句中<<操作符之后至第二个双引号之前的部分被注释掉了,导致<<操 作符的右操作数不是一个完整的字符串,所以不合法。在分号之前加上一个双 引号即可更正。 习题1.9

下列循环做什么? sum 的最终值是多少? int sum = 0;

for (int i = -100; i <= 100; ++i) sum += i; 【解答】

该循环求-100~100 之间所有整数的和(包括-100 和100)。 sum 的最终值是0。 习题1.10

用for 循环编程,求从50~100 的所有自然数的和。然后用while 循环重写该程 序。

【解答】

用for 循环编写的程序如下: #include #include \int main() {

int sum = 0; system(\

for (int i = 50; i <= 100; ++i) sum += i;

std::cout << \<< sum << std::endl;

return 0; }

用while 循环编写的程序如下: #include #include %using namespace std; int main() {

int sum=0, i=50; system(\ while(i<=100) {

sum+=i; i++; }

cout<<\ return 0; }

习题1.11

用while 循环编程,输出10~0 递减的自然数。然后用for 循环重写该程序。 【解答】

用while 循环编写的程序如下: #include #include %using namespace std; int main() { int i=10;

system(\ while(i>=0) {

cout<

cout<

用for 循环编写的程序如下: #include #include %using namespace std; int main()

{ system(\

for (int i=10;i>=0;i--) {

cout<

cout<

习题1.12

对比前面两个习题中所写的循环。两种形式各有何优缺点? 【解答】

在for 循环中,循环控制变量的初始化和修改都放在语句头部分,形式较简洁, 且特别适用于循环次数已知的情况。在while 循环中,循环控制变量的初始化 一般放在while 语句之前,循环控制变量的修改一般放在循环体中,形式上不 如for 语句简洁,但它比较适用于循环次数不易预知的情况(用某一条件控制 循环)。两种形式各有优点,但它们在功能上是等价的,可以相互转换。 习题1.13

编译器不同,理解其诊断内容的难易程度也不同。编写一些程序,包含本小节 “再谈编译”部分讨论的那些常见错误。研究编译器产生的信息,这样你在编 译更复杂的程序遇到这些信息时不会陌生。 【解答】

对于程序中出现的错误,编译器通常会给出简略的提示信息,包括错误出现的 文件及代码行、错误代码、错误性质的描述。如果要获得关于该错误的详细信 息,一般可以根据编译器给出的错误代码在其联机帮助文档中查找。 习题1.14

如果输入值相等,本节展示的程序将产生什么问题? 【解答】

sum 的值即为输入值。因为输入的v1 和v2 值相等(假设为x),所以lower 和 upper 相等,均为x。for 循环中的循环变量val 初始化为lower,从而val<=upper

为真,循环体执行一次,sum 的值为val(即输入值x);然后val 加1,val 的 值就大于upper,循环执行结束。 习题1.15

用两个相等的值作为输入编译并运行本节中的程序。将实际输出与你在习题 1.14 中所做的预测相比较,解释实际结果和你预计的结果间的不相符之处。 【解答】

运行1.4.3 节中给出的程序,输入两个相等的值(例如3,3),则程序输出为: Sum of 3 to 3 inclusive is 3 与习题1.14 中给出的预测一致。 习题1.16

编写程序,输出用户输入的两个数中的较大者。 #include #include %using namespace std; int main() {

system(\

cout<<\ int v1,v2; cin>>v1>>v2; if(v1>=v2)

cout<<\ else

cout<<\ return 0; }

习题1.17

编写程序,要求用户输入一组数。输出信息说明其中有多少个负数。 #include #include %using namespace std; int main() {

int amount = 0, value; system(\

// 读入数据直到遇见文件结束符,计算所读入的负数的个数 while (cin >> value) if (value <= 0) ++amount;

cout << \ << amount << std::endl; return 0; }

习题1.18

编写程序,提示用户输入两个数并将这两个数范围内的每个数写到标准输出。 #include #include %using namespace std; int main() {

system(\

cout<<\ int v1,v2; cin>>v1>>v2;

int lower,upper; lower=v1; upper=v2; if(v1>=v2) {

upper=v1;

lower=v2; }

cout<<\<

for(;lower<=upper;lower++) cout<

cout<

return 0; }

习题1.19

如果上题给定数1000 和2000,程序将产生什么结果?修改程序,使每一行输出 不超过10 个数。 【解答】

所有数的输出连在一起,不便于阅读。 程序修改如下:

#include #include %using namespace std; int main() {

system(\

cout<<\ int v1,v2; cin>>v1>>v2;

int lower,upper; lower=v1; upper=v2; if(v1>=v2) {

upper=v1; lower=v2; }

cout<<\<

for(int count=1;lower<=upper;lower++,count++) {

cout<

}

cout<

return 0; }

习题1.20

编写程序,求用户指定范围内的数的和,省略设置上界和下界的if 测试。假定 输入数是7 和3,按照这个顺序,预测程序运行结果。然后按照给定的数是7 和 3 运行程序,看结果是否与你预测的相符。如果不相符,反复研究关于for 和 while 循环的讨论直到弄清楚其中的原因。 #include #include %using namespace std; int main() {

system(\

cout<<\ int v1,v2,sum=0; cin>>v1>>v2;

for(int val=v1;val<=v2;val++) {

sum+=val; }

cout<<\<< \endl;

return 0; }

如果输入数据为7 和3,则v1 值为7,v2 值为3。for 语句头中将val 的初 始值设为7,第一次测试表达式val <= v2 时,该表达式的值为false,for 语 句的循环体一次也不执行,所以求和结果sum 为0。 习题1.21

本书配套网站(http://www.awprofessional.com/cpp_primer)的第1 章的代 码目录下有Sales_ item.h 源文件。复制该文件到你的工作目录。编写程序, 循环遍历一组书的销售交易,读入每笔交易并将交易写至标准输出。 #include

#include \#include %using namespace std; int main() {

Sales_item book; system(\

cout << \ while (cin >> book) {

// 输出ISBN,售出书的本数,总收入,平均价格

cout << \average price are: \ cout << book <

return 0; }

习题1.22

编写程序,读入两个具有相同ISBN 的Sales_item 对象并产生它们的和。 #include

#include \#include %using namespace std; int main() {

Sales_item trans1, trans2; // 读入交易 system(\

cout << \ cin >> trans1 >> trans2;

if (trans1.same_isbn(trans2))

cout << \ << \

<< \ << endl << trans1 + trans2; else

cout << \ return 0; }

习题1.23

编写程序,读入几个具有相同ISBN 的交易,输出所有读入交易的和。 #include

#include \#include %using namespace std; int main() {

Sales_item total, trans;

system(\

cout << \

if (cin >> total) {

while (cin >> trans)

if (total.same_isbn(trans)) // ISBN 相同 total = total + trans; } else

{ // ISBN 不同

cout << \ return -1; }

// 输出交易之和

cout << \ << \

<< \ <

else {

cout << \ return -1; }

return 0; }

习题1.24

编写程序,读入几笔不同的交易。对于每笔新读入的交易,要确定它的ISBN 是 否和以前的交易的ISBN 一样,并且记下每一个ISBN 的交易的总数。通过给定 多笔不同的交易来测试程序。这些交易必须代表多个不同的ISBN,但是每个ISBN 的记录应分在同一组。 #include

#include \#include %using namespace std; int main()

{

Sales_item trans1, trans2; int amount; system(\

cout << \ cin >> trans1; amount=1;

while (cin >> trans2)

if (trans1.same_isbn(trans2)) ++amount; else {

cout << \ << amount <

cout << \ << amount <

/*习题1.25

使用源自本书配套网站的Sales_item.h 头文件,编译并执行1.6 节给出的书店 程序。*/ 习题1.26

在书店程序中,我们使用了加法操作符而不是复合赋值操作符将trans 加到 total 中,为什么我们不使用复合赋值操作符? 【解答】

因为在1.5.1 节中提及的Sales_item 对象上的操作中只包含了+和=,没有包含 +=操作。(但事实上,使用Sales_item.h 文件,已经可以用+=操作符取代=和+ 操作符的复合使用。) 习题2.1

int、long 和short 类型之间有什么差别? 【解答】

它们的最小存储空间不同,分别为16 位、32 位和16 位。一般而言,short 类 型为半个机器字(word)长,int 类型为一个机器字长,而long 类型为一个或 两个机器字长(在32 位机器中,int 类型和long 类型的字长通常是相同的)。 因此,它们的表示范围不同。 习题2.2

unsigned 和signed 类型有什么差别? 【解答】

前者为无符号类型,只能表示大于或等于0 的数。后者为带符号类型,可以表

示正数、负数和0。 习题2.3

如果在某机器上short 类型占16 位,那么可以赋给short 类型的最大数是什么?

unsigned short 类型的最大数又是什么? 【解答】

若在某机器上short 类型占16 位,那么可以赋给short 类型的最大数是215-1, 即32767;而unsigned short 类型的最大数为216-1,即65535。 习题2.4

当给16 位的unsigned short 对象赋值100000 时,赋的值是什么? 【解答】 34464。

100000 超过了16 位的unsigned short 类型的表示范围,编译器对其二进制表 示截取低16 位,相当于对65536 求余(求模,%),得34464。 习题2.5

float 类型和double 类型有什么差别? 【解答】

二者的存储位数不同(一般而言,float 类型为32 个二进制位,double 类型为

64 个二进制位),因而取值范围不同,精度也不同(float 类型只能保证6 位 有效数字,而double 类型至少能保证10 位有效数字)。 习题2.6

要计算抵押贷款的偿还金额,利率、本金和付款额应分别选用哪种类型?解释 你选择的理由。 【解答】

利率可以选择float 类型,因为利率通常为百分之几。一般只保留到小数点后 两位,所以6 位有效数字就足以表示了。

本金可以选择long 类型,因为本金通常为整数。long 类型可表示的最大整数一

般为231-1(即2147483647),应该足以表示了。

付款额一般为实数,可以选择double 类型,因为float 类型的6 位有效数字可 能不足以表示。 习题2.7

解释下列字面值常量的不同之处。 (a) 'a',L'a',\

(b) 10,10u,10L,10uL,012,0xC (c) 3.14,3.14f,3.14L 【解答】

'a',L'a',\

'a'为char 型字面值,L'a'为wchar_t 型字面值,\为字符串字面值,L\为 宽字符串字面值。

(b) 10,10u,10L,10uL,012,0xC

10 为int 型字面值,10u 为unsigned 型字面值,10L 为long 型字面值,10uL 为unsigned long 型字面值,012 为八进制表示的int 型字面值,0xC 为十六

进制表示的int 型字面值。 (c) 3.14,3.14f,3.14L

3.14 为double 型字面值,3.14f 为float 型字面值,3.14L 为long double 型 字面值。 习题2.8

确定下列字面值常量的类型:

(a) –10 (b) -10u (c) -10. (d) -10e-2 【解答】 (a) int 型

(b) unsigned int 型 (c) double 型 (d) double 型 习题2.9

下列哪些(如果有)是非法的?

(a) \(b) 3.14e1L (c) \(d) 1024f (e) 3.14UL (f) \comment\【解答】

(c) 非法。因为字符串字面值与宽字符串字面值的连接是未定义的。 (d) 非法。因为整数1024 后面不能带后缀f。 (e) 非法。因为浮点字面值不能带后缀U。

(f) 非法。因为分两行书写的字符串字面值必须在第一行的末尾加上反斜线。 习题2.10

使用转义字符编写一段程序,输出2M,然后换行。修改程序,输出2,跟着一 个制表符,然后是M,最后是换行符。 【解答】

输出2M、然后换行的程序段: // 输出\和换行字符

std::cout << \修改后的程序段:

// 输出'2', '\\t', 'M'和换行字符

std::cout << '2' << '\\t' << 'M' << '\\n'; 习题2.11

编写程序,要求用户输入两个数——底数(base)和指数(exponent),输出 底数的指数次方的结果。 #include #include %using namespace std; int main() {

int base,exponent; long result=1;

system(\

cout<<\ cin>>base>>exponent;

if(exponent<0) {

cout<<\ return -1; }

if(exponent>0) {

for(int cnt=1;cnt<=exponent;cnt++) result*=base; }

cout<

return 0; }

习题2.12

区分左值和右值,并举例说明。 【解答】

左值(lvalue)就是变量的地址,或者是一个代表“对象在内存中的位置”的 表达式。

右值(rvalue)就是变量的值,见2.3.1 节。

变量名出现在赋值运算符的左边,就是一个左值;而出现在赋值运算符右边的 变量名或字面常量就是一个右值。 例如:

val1=val2/8

这里的val1 是个左值,而val2 和8 都是右值。 习题2.13

举出一个需要左值的例子。 【解答】

赋值运算符的左边(被赋值的对象)需要左值,见习题2.12。 习题2.14

下面哪些(如果有)名字是非法的?更正每个非法的标识符名字。 (a) int double = 3.14159; (b) char _; (c) bool catch-22; (d) char 1_or_2 ='1'; (e) float Float = 3.14f; 【解答】

(a) double 是C++语言中的关键字,不能用作用户标识符,所以非法。此语句 可改为:double dval = 3.14159;。

(c) 名字catch-22 中包含在字母、数字和下划线之外的字符“-”,所以非法。 可将其改为:catch_22;。 (d) 名字1_or_2 非法,因为标识符必须以字母或下划线开头,不能以数字开头。 可将其改为:one_or_two;。 习题2.15

下面两个定义是否不同?有何不同? int month = 9, day = 7; int month =09, day = 07;

如果上述定义有错的话,那么应该怎样改正呢? 【解答】

这两个定义不同。前者定义了两个int 型变量,初值分别为9 和7;后者也定义 了两个int 型变量,其中day 被初始化为八进制值7;而month 的初始化有错: 试图将month 初始化为八进制值09,但八进制数字范围为0~7,所以出错。可 将第二个定义改为:

int month =011, day = 07; 习题2.16

假设calc 是一个返回double 对象的函数。下面哪些是非法定义?改正所有的 非法定义。

(a) int car = 1024, auto = 2048; (b) int ival = ival;

(c) std::cin >> int input_value; (d) double salary = wage = 9999.99; (e) double calc = calc(); 【解答】

(a) 非法:auto 是关键字,不能用作变量名。使用另一变量名,如aut 即可更 正。

(c) 非法:>>运算符后面不能进行变量定义。改为: int input_value;

std::cin >> input_value;

(d) 非法:同一定义语句中不同变量的初始化应分别进行。改为: double salary = 9999.99, wage = 9999.99;

注意,(b)虽然语法上没有错误,但这个初始化没有实际意义,ival 仍是未初始化的。 习题2.17

下列变量的初始值(如果有)是什么? std::string global_str; int global_int; int main() {

int local_int;

std::string local_str; // ... return 0; }

【解答】

global_str 和local_str 的初始值均为空字符串,global_int 的初始值为0, local_int 没有初始值。 习题2.18

解释下列例子中name 的意义: extern std::string name;

std::string name(\

extern std::string name(\【解答】

第一条语句是一个声明,说明std::string 变量name 在程序的其他地方定义。 第二条语句是一个定义,定义了std::string 变量name,并将name 初始化为 \。

第三条语句也是一个定义,定义了std::string 变量name,并将name 初始化为 \,但这个语句只能出现在函数外部(即,name 是一个全局变量)。 习题2.19

下列程序中j 的值是多少? int i = 42; int main() {

int i = 100; int j = i; // ... }

【解答】

j 的值是100。j 的赋值所使用到的i 应该是main 函数中定义的局部变量i,因 为局部变量的定义会屏蔽全局变量的定义。 习题2.20

下列程序段将会输出什么? int i = 100, sum = 0;

for (int i = 0; i != 10; ++i) sum += i;

std::cout << i << \【解答】 输出为: 100 45

for 语句中定义的变量i,其作用域仅限于for 语句内部。输出的i 值是for 语 句之前所定义的变量i 的值。 习题2.21

下列程序合法吗? int sum = 0;

for (int i = 0; i != 10; ++i) sum += i;

std::cout << \

<< \【解答】

不合法。因为变量i 具有语句作用域,只能在for 语句中使用,输出语句中 使用i 属非法。 习题2.22

下列程序段虽然合法,但是风格很糟糕。有什么问题呢?怎样改善? for (int i = 0; i < 100; ++i) // process i 【解答】

问题主要在于使用了具体值100 作为循环上界:100 的意义在上下文中没有体现

出来,导致程序的可读性差;若100 这个值在程序中出现多次,则当程序的需 求发生变化(如将100 改变为200)时,对程序代码的修改复杂且易出错,导致 程序的可维护性差。

改善方法:设置一个const 变量(常量)取代100 作为循环上界使用,并为该 变量选择有意义的名字。 习题2.23

下列哪些语句合法?对于那些不合法的使用,解释原因。 (a) const int buf; (b) int cnt = 0; const int sz = cnt; (c) cnt++; sz++; 【解答】

(a) 不合法。因为定义const 变量(常量)时必须进行初始化,而buf 没有初 始化。

(b) 合法。

(c) 不合法。因为修改了const变量sz 的值。 习题2.24

下列哪些定义是非法的?为什么?如何改正? (a) int ival = 1.01; (b) int &rval1 = 1.01;

(c) int &rval2 = ival; (d) const int &rval3 = 1; 【解答】 (b)非法。

因为rval1 是一个非const引用,非const 引用不能绑定到右值,而1.01 是一 个右值。可改正为: int &rval1 = ival;

(假设ival 是一个已定义的int 变量)。 习题2.25

在习题2.24 给出的定义下,下列哪些赋值是非法的?如果赋值合法,解释赋值 的作用。

(a) rval2 = 3.14159; (b) rval2 = rval3; (c) ival = rval3; (d) rval3 = ival; 【解答】

(d)非法。因为rval3 是一个const引用,不能进行赋值。

合法赋值的作用:

(a)将一个double 型字面值赋给int 型变量ival,发生隐式类型转换,ival 得 到的值为3。

(b)将int 值1 赋给变量ival。 (c)将int 值1 赋给变量ival。 习题2.26

(a)中的定义和(b)中的赋值存在哪些不同?哪些是非法的? (a) int ival = 0; (b) ival = ri; const int &ri = 0; ri = ival; 【解答】

int ival = 0; 定义ival 为int 变量,并将其初始化为0。

const int &ri = 0; 定义ri 为const 引用,并将其绑定到右值0。 ival = ri; 将0 值赋给ival。

ri = ival; 试图对ri 赋值,这是非法的,因为ri 是const 引用, 不能赋值。 习题2.27

下列代码输出什么? int i, &ri = i; i = 5; ri =10;

std::cout << i << \【解答】 输出: 10 10

ri 是i 的引用,对ri 进行赋值,实际上相当于对i 进行赋值,所以输出i 和 ri 的值均为10。 习题2.28

编译以下程序,确定你的编译器是否会警告遗漏了类定义后面的分号。 class Foo { // empty

} // Note: no semicolon int main() {

return 0; }

如果编译器的诊断结果难以理解,记住这些信息以备后用。 【解答】

在笔者所用的编译器中编译上述程序,编译器会给出如下错误信息:

error C2628: 'Foo' followed by 'int' is illegal (did you forget a ';'?) (第4 行)

warning C4326: return type of 'main' should be 'int or void' instead of 'Foo' (第5 行)

error C2440: 'return' : cannot convert from 'int' to 'Foo' (第 6 行)

也就是说,该编译器会对遗漏了类定义后面的分号给出提示。

习题2.29

区分类中的public 部分和private 部分。 【解答】

类中public 部分定义的成员在程序的任何部分都可以访问。通常在public 部 分放置操作,以便程序中的其他部分可以执行这些操作。

类中private 部分定义的成员只能被作为类的组成部分的代码(以及该类的友 元)访问。通常在private 部分放置数据,以对对象的内部数据进行隐藏。 习题2.30

定义表示下列类型的类的数据成员: (a) 电话号码 (b) 地址

(c) 员工或公司 (d) 某大学的学生 【解答】

(a) 电话号码

class Tel_number { public:

//...对象上的操作 private:

std::string country_number; std::string city_number; std::string phone_number; };

(b) 地址

class Address { public:

//...对象上的操作 private:

std::string country; std::string city; std::string street; std::string number; };

(c) 员工或公司 class Employee { public:

// ...对象上的操作 private:

std::string ID; std::string name; char sex;

Address addr; Tel_number tel; };

class Company { public:

// ...对象上的操作 private:

std::string name; Address addr; Tel_number tel; };

(d) 某大学的学生 class Student { public:

// ...对象上的操作 private:

std::string ID; std::string name; char sex;

std::string dept; // 所在系 std::string major; Address home_addr; Tel_number tel; };

注意,在不同的具体应用中,类的设计会有所不同,这里给出的只是一般性的 简单例子。 习题2.31

判别下列语句哪些是声明,哪些是定义,请解释原因。 (a) extern int ix = 1024 ; (b) int iy ;

(c) extern int iz ;

(d) extern const int &ri ; 【解答】

(a)是定义,因为extern 声明进行了初始化。 (b)是定义,变量定义的常规形式。 (c)是声明,extern 声明的常规形式。 (d)是声明,声明了一个const 引用。 习题2.32

下列声明和定义哪些应该放在头文件中?哪些应该放在源文件中?请解释原 因。

(a) int var ;

(b) const double pi = 3.1416; (c) extern int total = 255 ;

(d) const double sq2 = squt (2.0) ; 【解答】

(a)、(c)、(d)应放在源文件中,因为(a)和(c)是变量定义,定义通常应放在源 文件中。(d)中的const 变量sq2 不是用常量表达式初始化的,所以也应该放在 源文件中。

(b)中的const 变量pi 是用常量表达式初始化的,应该放在头文件中。

// 把vector 对象的所有元素复制给新数组 #include #include using namespace std; int main() {

vector ivec; int ival;

//读入元素数据并建立vector

cout << \while (cin >> ival) ivec.push_back(ival); //动态创建数组

int *pia = new int[ivec.size()]; //复制元素

int *tp = pia;

for (vector::iterator iter = ivec.begin(); iter != ivec.end(); ++iter, ++tp) *tp = *iter;

//释放动态数组的内存 delete [] pia; return 0; }

习题4.29

对本节第5 条框中的两段程序: (a) 解释这两段程序实现的功能。

(b) 平均来说,使用string 类型的程序执行速度要比用C 风格字符串的快很多,

在我们用了5 年的PC 机上其平均执行速度分别是: user 0.47 # string class

user 2.55 # C-style character string 你预计的也一样吗?请说明原因。 【解答】

(a) 这两段程序的功能是:执行一个循环次数为1000000 的循环,在该循环的 循环体中:创建一个新字符串,将一个已存在的字符串复制给新字符串,然后 比较两个字符串,最后释放新字符串。

(b) 使用C 风格字符串的程序需要自己管理内存的分配和释放,而使用string 类型的程序由系统自动进行内存的分配和释放,因此比使用C 风格字符串的程 序要简短,执行速度也要快一些。 习题4.30

编写程序连接两个C 风格字符串字面值,把结果存储在一个C 风格字符串中。 然后再编写程序连接两个string 类型字符串,这两个string 类型字符串与前 面的C 风格字符串字面值具有相同的内容。 【解答】

连接两个C 风格字符串字面值的程序如下: // 连接两个C 风格字符串字面值, // 把结果存储在一个C 风格字符串中 #include int main() {

const char *cp1 = \const char *cp2 = \

size_t len = strlen(cp1) + strlen(cp2); char *result_str = new char[len+1]; strcpy(result_str, cp1); strcat(result_str, cp2); delete [] result_str; return 0; }

相应的连接两个string 类型字符串的程序如下: // 连接两个string 类型字符串 #include using namespace std; int main() {

const string str1(\const string str2(\string result_str; result_str = str1; result_str += str2; return 0; }

习题4.31

编写程序从标准输入设备读入字符串,并把该串存放在字符数组中。描述你的 程序如何处理可变长的输入。提供比你分配的数组长度长的字符串数据测试你 的程序。 【解答】

// 从标准输入设备读入字符串,并把该串存放在字符数组中 #include #include #include using namespace std; int main() {

string in_str;// 用于读入字符串的string 对象 const size_t str_size = 10; char result_str[str_size+1]; // 读入字符串

cout << \<< \cin >> in_str;

// 计算需复制的字符的数目

size_t len = strlen(in_str.c_str()); if (len > str_size) { len = str_size;

cout << \<< \<< str_size << \}

// 复制len 个字符至字符数组result_str

strncpy(result_str, in_str.c_str(), len); // 在末尾加上一个空字符(null 字符) result_str[len+1] = '\\0'; return 0; }

为了接受可变长的输入,程序中用一个string 对象存放读入的字符串,然后使 用strncpy 函数将该对象的适当内容复制到字符数组中。因为字符数组的长度 是固定的,因此首先计算字符串的长度。若该长度小于或等于字符数组可容纳 字符串的长度,则复制整个字符串至字符数组,否则,根据数组的长度,复制 字符串中前面部分的字符,以防止溢出。

注意,上述给出的是满足题目要求的一个解答,事实上,如果希望接受可变长 的输入并完整地存放到字符数组中,可以采用动态创建数组来实现。 习题4.32

编写程序用int 型数组初始化vector 对象。 【解答】

// 用int 型数组初始化vector 对象 #include #include using namespace std; int main() {

const size_t arr_size = 8; int int_arr[arr_size]; // 输入数组元素

cout << \for (size_t ix = 0; ix != arr_size; ++ix) cin >> int_arr[ix];

// 用int 型数组初始化vector 对象

vector ivec(int_arr, int_arr + arr_size); return 0; }

习题4.33

编写程序把int 型vector 复制给int 型数组。 【解答】

// 把int 型vector 复制给int 型数组 #include #include using namespace std; int main() {

vector ivec; int ival;

// 输入vector 元素

cout << \while (cin >> ival) ivec.push_back(ival); // 创建数组

int *parr = new int[ivec.size()]; // 复制元素 size_t ix = 0;

for (vector::iterator iter = ivec.begin(); iter != ivec.end(); ++iter, ++ix) parr[ix] = *iter; // 释放数组

delete [] parr; return 0; }

习题4.34

编写程序读入一组string 类型的数据,并将它们存储在vector 中。接着,把 该vector 对象复制给一个字符指针数组。为vector 中的每个元素创建一个新 的字符数组,并把该vector 元素的数据复制到相应的字符数组中,最后把指向 该数组的指针插入字符指针数组。 【解答】 //4-34.cpp

//读入一组string 类型的数据,并将它们存储在vector 中。 //接着,把该vector 对象复制给一个字符指针数组。 //为vector 中的每个元素创建一个新的字符数组,

//并把该vector 元素的数据复制到相应的字符数组中, //最后把指向该数组的指针插入字符指针数组 #include #include #include using namespace std; int main() {

vector svec;

string str;

// 输入vector 元素

cout << \while (cin >> str) svec.push_back(str); // 创建字符指针数组

char **parr = new char*[svec.size()]; // 处理vector 元素 size_t ix = 0;

for (vector::iterator iter = svec.begin(); iter != svec.end(); ++iter, ++ix) { // 创建字符数组

char *p = new char[(*iter).size()+1]; // 复制vector 元素的数据到字符数组 strcpy(p, (*iter).c_str());

// 将指向该字符数组的指针插入到字符指针数组 parr[ix] = p; }

// 释放各个字符数组

for (ix =0; ix != svec.size(); ++ix) delete [] parr[ix]; // 释放字符指针数组 delete [] parr; return 0; }

习题4.35

输出习题4.34 中建立的vector 对象和数组的内容。输出数组后,记得释放字 符数组。 【解答】 //4-35.cpp

//读入一组string 类型的数据,并将它们存储在vector 中。 //接着,把该vector 对象复制给一个字符指针数组: //为vector 中的每个元素创建一个新的字符数组,

//并把该vector 元素的数据复制到相应的字符数组中, //然后把指向该数组的指针插入字符指针数组。 //输出建立的vector 对象和数组的内容 #include #include #include using namespace std; int main() {

vector svec; string str;


C++Primer中文版(第四版)习题及详细分析.doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:人教版2024初二(上册)期中测试题 (含答案)

相关阅读
本类排行
× 游客快捷下载通道(下载后可以自由复制和排版)

下载本文档需要支付 7

支付方式:

开通VIP包月会员 特价:29元/月

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信:xuecool-com QQ:370150219