C++ Primer 【第四版】第五章 表达式

来源:互联网 发布:vb简易计算器代码 编辑:程序博客网 时间:2024/06/10 05:39

习题5.1

在下列表达式中,加入适当的圆括号以标明其计算顺序。编译该表达式并输出

其值,从而检查你的回答是否正确。

12/ 3 * 4 + 5 * 15 + 24 % 4 / 2

【解答】

加入如下所示的圆括号以标明该表达式的计算顺序:

(((12/ 3) * 4) + (5 * 15)) + ((24 % 4) / 2)

习题5.2

计算下列表达式的值,并指出哪些结果值依赖于机器?

-30* 3 + 21 / 5

-30+ 3 * 21 / 5

30/ 3 * 21 % 5

-30/ 3 * 21 % 4

C++Primer4版)习题解答

91

【解答】

各表达式的值分别为-86-180-2。其中,最后一个表达式的结果值依赖于机器,因为

该表达式中除操作只有一个操作数为负数。

习题 5.3

编写一个表达式判断一个int型数值是偶数还是奇数。

【解答】

如下表达式可以判断一个int型数值(假设为ival)是偶数还是奇数:

ival% 2 == 0

ival是偶数,则该表达式的值为真(true),否则为假(false)。

习题 5.4

定义术语“溢出”的含义,并给出导致溢出的三个表达式。

【解答】

溢出:表达式的求值结果超出了其类型的表示范围。

如下表达式会导致溢出(假设int类型为16 位):

1000* 1000

32766+ 5

3276* 20

在这些表达式中,各操作数均为int类型,因此这些表达式的类型也是int,但它们的计算

结果均超出了16int 型的表示范围(-32768~32767),导致溢出。

习题 5.5

解释逻辑与操作符、逻辑或操作符以及相等操作符的操作数在什么时候计算。

【解答】

逻辑与、逻辑或操作符采用称为“短路求值”(short-circuit evaluation)的求值策略,即先

计算左操作数,再计算右操作数,且只有当仅靠左操作数的值无法确定该逻辑运算的结果

时,才会计算右操作数。

C++Primer4版)习题解答

92

相等操作符的左右操作数均需进行计算。

习题 5.6

解释下列while循环条件的行为:

char*cp = "Hello World" ;

while( cp && *cp )

【解答】

while循环的条件为:当指针cp 为非空指针并且cp 所指向的字符不为空字符null'\0'

时执行循环体。即该循环可以对字符串"Hello World"中的字符进行逐个处理。

习题 5.7

编写while循环条件从标准输入设备读入整型(int)数据,当读入值为42时循

环结束。

【解答】

intval;

cin>> val;

while(val != 42)

或者,while循环条件也可以写成

while(cin >> ival && ival != 42)

习题5.8

编写表达式判断4个值abcd 是否满足a 大于bb大于c 而且c 大于d

的条件。

【解答】

表达式如下:

a> b && b > c && c > d

习题5.9

假设有下面两个定义:

C++Primer4版)习题解答

93

unsignedlong ul1 =3, ul2 = 7;

下列表达式的结果是什么?

(a)ul1 & ul2 (b) ul1 && ul2

(c)ul1 | ul2 (d) ul1 || ul2

【解答】

各表达式的结果分别为3true7true

习题 5.10

重写bitset表达式:使用下标操作符对测验结果进行置位(置1)和复位(置

0)。

【解答】

bitset<30>bitset_quiz1;

bitset_quiz1[27]= 1;

bitset_quiz1[27]= 0;

习题5.11

请问每次赋值操作完成后,id 的值分别是多少?

inti; double d;

d= i = 3.5;

i= d = 3.5;

【解答】

赋值语句d=i=3.5;完成后,id 的值均为3。因为赋值操作具有右结合性,所以首先

3.5赋给i(此时发生隐式类型转换,将double型字面值3.5转换为int 型值3,赋给i),

然后将表达式i=3.5的值(即赋值后i 所具有的值3)赋给d

赋值语句 i=d=3.5;完成后,d的值为3.5i 的值为3。因为先将字面值3.5赋给d,然后

将表达式d=3.5的值(即赋值后d 所具有的值3.5)赋给i(这时也同样发生隐式类型转换)。

习题 5.12

解释每个if条件判断产生什么结果?

C++Primer4版)习题解答

94

if( 42 = i ) // ...

if( i = 42 ) // ...

【解答】

前者发生语法错误,因为其条件表达式42=i是一个赋值表达式,赋值操作符的左操作数必

须为一个左值,而字面值42不能作为左值使用。

后者代码合法,但其条件表达式i=42是一个永真式(即其逻辑值在任何情况下都为true),

因为该赋值表达式的值为赋值操作完成后的i值(42),而42 为非零值,解释为逻辑值true

习题 5.13

下列赋值操作是不合法的,为什么?怎样改正?

doubledval; int ival; int *pi;

dval= ival = pi = 0;

【解答】

该赋值语句不合法,因为该语句首先将0值赋给pi,然后将pi 的值赋给ival,再将ival

值赋给dvalpiivaldval 的类型各不相同,因此要完成赋值必须进行隐式类型转换,

但系统无法将int型指针pi 的值隐式转换为ival所需的int型值。

可改正如下:

doubledval; int ival; int *pi;

dval= ival = 0;

pi= 0;

习题5.14

虽然下列表达式都是合法的,但并不是程序员期望的操作,为什么?怎样修改这些表

达式以使其能反映程序员的意图?

(a)if ( ptr = retrieve_pointer() != 0 )

(b)if ( ival = 1024 )

(c)ival += ival + 1;

【解答】

对于表达式(a),程序员的意图应该是将retrieve_pointer()的值赋给ptr,然后判断ptr

C++Primer4版)习题解答

95

的值是否为0, 但因为操作符“=” 的优先级比“!=”低, 所以该表达式实际上是将

retrieve_pointer()是否为0的判断结果true false 赋给ptr,因此不是程序员期望的操作。

对于表达式(b),程序员的意图应该是判断ival的值是否与1024 相等,但误用了赋值操

作符。

对于表达式(c),程序员的意图应该是使ival的值增加1,但误用了操作符“+=”。

各表达式可修改如下:

(a)if ( (ptr = retrieve_pointer()) != 0 )

(b)if ( ival == 1024 )

(c)ival += 1; ival++; ++ival;

习题5.15

解释前自增操作和后自增操作的差别。

【解答】

前自增操作和后自增操作都使其操作数加1,二者的差别在于:前自增操作将修改后操作数

的值作为表达式的结果值;而后自增操作将操作数原来的、未修改的值作为表达式的结果

值。

习题 5.16

你认为为什么C++不叫作++C

【解答】

C++之名是Rick Mascitti1983 年夏天定名的( 参见The C++ Programming

Language(SpecialEdition) 1.4节),C说明它本质上是从C 语言演化而来的,“++”是C语言

的自增操作符。C++语言是C语言的超集,是在C 语言基础上进行的扩展(引入了new

deleteC语言中没有的操作符,增加了对面向对象程序设计的直接支持,等等),是先有

C语言,再进行++。根据自增操作符前、后置形式的差别(参见习题5.15的解答),C++

表示对C语言进行扩展之后,还可以使用C 语言的内容;而写成++C 则表示无法再使用C

的原始值了,也就是说C++不能向下兼容C了,这与实际情况不符。

习题 5.17

如果输出vector内容的while 循环使用前自增操作符,那会怎么样?

【解答】

将导致错误的结果:ivec的第一个元素没有输出,并企图对一个多余的元素进行解引用。

C++Primer4版)习题解答

96

习题5.18

编写程序定义一个vector对象,其每个元素都是指向string 类型的指针,读

取该vector对象,输出每个string 的内容及其相应的长度。

【解答】

//定义一个vector对象,其每个元素都是指向string类型的指针,

//读取该vector对象,输出每个string的内容及其相应的长度

#include<iostream>

#include<string>

#include<vector>

usingnamespace std;

intmain()

{

vector<string*>spvec;

//读取vector对象

stringstr;

cout<< "Enter some strings(Ctrl+Z to end)" << endl;

while(cin >> str) {

string*pstr = new string; //指向string对象的指针

*pstr= str;

spvec.push_back(pstr);

}

//输出每个string的内容及其相应的长度

vector<string*>::iteratoriter = spvec.begin();

while(iter != spvec.end()) {

C++Primer4版)习题解答

97

cout<< **iter << (**iter).size() << endl;

iter++;

}

//释放各个动态分配的string对象

iter= spvec.begin();

while(iter != spvec.end()) {

delete*iter;

iter++;

}

return0;

}

习题5.19

假设itervector<string>::iterator 类型的变量,指出下面哪些表达式是

合法的,并解释这些合法表达式的行为。

(a)*iter++; (b) (*iter)++;

(c)*iter.empty(); (d) iter->empty();

(e)++*iter; (f) iter++->empty();

【解答】

(a)(d)(f)合法。

这些表达式的执行结果如下:

(a)返回iter所指向的string对象,并使iter 1

(d)调用iter所指向的string对象的成员函数empty

(f)调用iter所指向的string对象的成员函数empty,并使iter 1

习题5.20

C++Primer4版)习题解答

98

编写程序提示用户输入两个数,然后报告哪个数比较小。

【解答】

可编写程序如下:

//提示用户输入两个数,然后报告哪个数比较小

#include<iostream>

usingnamespace std;

intmain()

{

intval1, val2;

//提示用户输入两个数并接受输入

cout<< "Enter two integers:" << endl;

cin>> val1 >> val2;

//报告哪个数比较小

cout<< "The smaller one is"

<<(val1 < val2 ? val1 : val2) << endl;

return0;

}

习题5.21

编写程序处理vector<int>对象的元素:将每个奇数值元素用该值的两倍替换。

【解答】

//处理vector<int>对象的元素:

//将每个奇数值元素用该值的两倍替换

#include<iostream>

#include<vector>

C++Primer4版)习题解答

99

usingnamespace std;

intmain()

{

vector<int>ivec(20,1);//ivec包含20个值为1 的元素

//将每个奇数值元素用该值的两倍替换

for(vector<int>::iterator iter = ivec.begin();

iter!= ivec.end(); ++iter)

*iter= (*iter % 2 == 0 ? *iter : *iter * 2);

return0;

}

习题5.22

编写程序输出每种内置类型的长度。

【解答】

//输出每种内置类型的长度

#include<iostream>

usingnamespace std;

intmain()

{

cout<< "type\t\t\t" << "size" << endl

<<"bool\t\t\t" << sizeof(bool) << endl

<<"char\t\t\t" << sizeof(char) << endl

<<"signed char\t\t" << sizeof(signed char) << endl

<<"unsigned char\t\t" << sizeof(unsigned char) << endl

<<"wchar_t\t\t\t" << sizeof(wchar_t) << endl

C++Primer4版)习题解答

100

<<"short\t\t\t" << sizeof(short) << endl

<<"signed short\t\t" << sizeof(signed short) << endl

<<"unsigned short\t\t" << sizeof(unsigned short) << endl

<<"int\t\t\t" << sizeof(int) << endl

<<"signed int\t\t" << sizeof(signed int) << endl

<<"unsigend int\t\t" << sizeof(unsigned int) << endl

<<"long\t\t\t" << sizeof(long) << endl

<<"sigend long\t\t" << sizeof(signed long) << endl

<<"unsigned long\t\t" << sizeof(unsigned long) << endl

<<"float\t\t\t" << sizeof(float) << endl

<<"double\t\t\t" << sizeof(double) << endl

<<"long double\t\t" << sizeof(long double) << endl;

return0;

}

习题5.23

预测下列程序的输出,并解释你的理由。然后运行该程序,输出的结果和你预

测的一样吗?如果不一样,为什么?

intx[10]; int *p = x;

cout<< sizeof(x)/sizeof(*x) << endl;

cout<< sizeof(p)/sizeof(*p) << endl;

【解答】

在表达式sizeof(x)中,x是数组名,该表达式的结果为数组x 所占据的存储空

间的字节数,为10int 型元素所占据的字节数。

表达式sizeof(*x)的结果是指针常量x所指向的对象(数组中第一个int 型元

素)所占据的存储空间的字节数。

C++Primer4版)习题解答

101

表达式sizeof(p)的结果是指针变量p所占据的存储空间的字节数。

表达式sizeof(*p)的结果是指针变量p所指向的对象(一个int 型数据)所占

据的存储空间的字节数。

各种数据类型在不同的系统中所占据的字节数不一定相同,因此在不同的系统

中运行上述程序段得到的结果不一定相同。在Microsoft Visual C++ .NET 2003

系统中,一个int型数据占据4 个字节,一个指针型数据也占据4 个字节,因

此运行上述程序得到的输出结果为:

10

1

习题5.24

本节的程序与5.5节在vector 对象中添加元素的程序类似。两段程序都使用递

减的计数器生成元素的值。本程序中,我们使用了前自减操作,而5.5节的程

序则使用了后自减操作。解释为什么一段程序中使用前自减操作而在另一段程

序中使用后自减操作。

【解答】

5.5节的程序中必须使用后自减操作。如果使用前自减操作,则是用减1后的

cnt值创建ivec的新元素,添加到ivec 中的元素将不是10~1,而是9~0

本节的程序中使用后自减操作或前自减操作均可,因为对cnt的自减操作和对

cnt值的使用不是出现在同一表达式中,cnt自减操作的前置或后置形式不影响

cnt值的使用。

习题5.25

根据表5-4的内容,在下列表达式中添加圆括号说明其操作数分组的顺序(即

计算顺序):

(a)! ptr == ptr->next

(b)ch = buf[ bp++ ] != '\n'

【解答】

添加圆括号说明其计算顺序如下:

(a)((! ptr) == (ptr->next))

(b)(ch = ((buf[ (bp++) ]) != '\n'))

C++Primer4版)习题解答

102

习题5.26

习题5.25中的表达式的计算次序与你的意图不同,给它们加上圆括号使其以你

所希望的操作次序求解。

【解答】

添加圆括号获得与上题不同的操作次序如下:

(a)! (ptr == ptr->next)

(b)(ch = buf[ bp++ ]) != '\n'

习题5.27

由于操作符优先级的问题,下列表达式编译失败。请参照表5-4解释原因,应

该如何改正?

strings = "word";

//add an 's' to the end, if the word doesn't already end in 's'

stringpl = s + s[s.size() - 1] == 's' ? "" : "s" ;

【解答】

由表5-4可知,在语句string pl = s + s[s.size() - 1] =='s' ? "" : "s" ;

中,赋值、加法、条件操作符三者的操作次序为:先执行“+”操作,再用表达

s + s[s.size() - 1]的结果参与条件操作,最后将条件操作的结果赋给pl

但表达式s + s[s.size() - 1]的结果是一个string对象,不能与字符's'进行

相等比较,所以编译失败。

改正为:string pl = s + (s[s.size() - 1] == 's' ? "" :"s") ;

习题5.28

除了逻辑与和逻辑或外,C++没有明确定义二元操作符的求解次序,编译器可自

由地提供最佳的实现方式。只能在“实现效率”和程序语言使用中“潜在的缺

陷”之间寻求平衡。你认为这可以接受吗?说出你的理由。

【解答】

这可以接受。

因为,操作数的求解次序通常对结果没什么影响。只有当二元操作符的两个操

作数涉及同一对象,并改变该对象的值时,操作数的求解次序才会影响计算结

C++Primer4版)习题解答

103

果;后一种情况只会在部分(甚至是少数)程序中出现。在实际使用中,这种

“潜在的缺陷”可以通过程序员的努力得到弥补,但“实现效率”的提高却能

使所有使用该编译器的程序受益,因此利大于弊。

习题5.29

假设ptr指向类类型对象,该类拥有一个名为ival int 型数据成员,vec

保存int型元素的vector 对象,而ivaljvalkval 都是int 型变量。请解

释下列表达式的行为,并指出哪些(如果有的话)可能是不正确的,为什么?

如何改正?

(a)ptr->ival != 0 (b) ival != jval < kval

(c)ptr != 0 && *ptr++ (d) ival++ && ival

(e)vec[ival++] <= vec[ival]

【解答】

表达式的行为如下:

(a)判断ptr所指向的对象的ival 成员是否不等于0

(b)判断ival是否不等于“jval 是否小于kval”的判断结果,即判断ival

否不等于true1)或false0)。

(c)判断ptr是否不等于0。如果ptr 不等于0,则求解&&操作的右操作数,即,

ptr1,且判断ptr原来所指向的对象是否为0

(d)判断ivalival+1 是否为true(非0值)(注意,如果ival false

则无需继续判断ival+1)。

(e)判断vec[ival]是否小于或等于vec[ival+1]

其中,(d)(e)可能不正确,因为二元操作符的两个操作数涉及同一对象,并

改变该对象的值。

可改正如下:

(d)ival && ival + 1

(e)vec[ival] <= vec[ival + 1]

习题5.30

下列语句哪些(如果有的话)是非法的或错误的?

C++Primer4版)习题解答

104

(a)vector<string> svec(10);

(b)vector<string> *pvec1 = new vector<string>(10);

(c)vector<string> **pvec2 = new vector<string>[10];

(d)vector<string> *pv1 = &svec;

(e)vector<string> *pv2 = pvec1;

(f)delete svec;

(g)delete pvec1;

(h)delete [] pvec2;

(i)delete pv1;

(j)delete pv2;

【解答】

错误的有(c)(f)

(c)的错误在于:pvec2是指向元素类型为stringvector 对象的指针的指

针(即pvec2的类型为vector<string> **),而new 操作返回的是一个指向元

素类型为stringvector 对象的指针,不能用于初始化pvec2

(f)的错误在于:svec是一个vector对象,不是指针,不能对它进行delete

作。

习题5.31

根据5.12.2节的变量定义,解释在计算下列表达式的过程中发生了什么类型转

换?

(a)if (fval)

(b)dval = fval + ival;

(c)dval + ival + cval;

记住,你可能需要考虑操作符的结合性,以便在表达式含有多个操作符的情况

下确定答案。

【解答】

C++Primer4版)习题解答

105

(a)fval的值从float 类型转换为bool类型。

(b)ival的值从int 类型转换为float类型,再将fval + ival的结果值转

换为double类型,赋给dval

(c)ival的值从int 类型转换为double类型,cval的值首先提升为int

型,然后从int型转换为double 型,与dval+ ival 的结果值相加。

习题5.32

给定下列定义:

charcval; int ival; unsigned int ui;

floatfval; double dval;

指出可能发生的(如果有的话)隐式类型转换:

(a)cval = 'a' + 3; (b) fval = ui – ival * 1.0;

(c)dval = ui * fval; (d) cval = ival + fval + dval;

【解答】

(a)'a'首先提升为int类型,再将'a' + 3 的结果值转换为char 型,赋给cval

(b)ival转换为double型与1.0 相乘,ui 转换为double型再减去ival * 1.0

的结果值,减操作的结果转换为float型,赋给fval

(c)ui转换为float型与fval 相乘,结果转换为double 型,赋给dval

(d)ival转换为float型与fval 相加,结果转换为double 型,再与dval 相加,

结果转换为char型,赋给cval

习题5.33

给定下列定义:

intival; double dval;

conststring *ps; char *pc; void *pv;

用命名的强制类型转换符号重写下列语句:

(a)pv = (void*)ps; (b) ival = int(*pc);

C++Primer4版)习题解答

106

(c)pv = &dval; (d) pc = (char*) pv;

【解答】

(a)pv = static_cast<void*> (const_cast<string*> (ps));

(b)ival = static_cast<int> (*pc);

(c)pv = static_cast<void*> (&dval);

(d)pc = static_cast<char*> (pv);__

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 出轨怀孕了该怎么办呢 瑞安医保卡丢了怎么办 包裹一直在揽收怎么办 揽收超时的快件怎么办 快递被别人偷了怎么办 行驶证副本丢了怎么办 眼睛进了石灰粉怎么办 高铁网上没票了怎么办 限行尾号是字母怎么办 手指被刺扎肿了怎么办 手上进了小刺怎么办 招投标标书丢了怎么办 冒险岛2装备红了怎么办 宝宝屁股腌红了怎么办 宝宝肛门红痒怎么办啊 宝宝屁屁溃烂了怎么办 脸过敏起红疙瘩怎么办 一岁宝宝屁股红怎么办 屁眼肉凸出来了怎么办 陶笛声音变闷了怎么办 吃三七粉上火了怎么办 红枣核吞下去了怎么办 话梅核吞下去了怎么办 芒果和海鲜吃了怎么办 小孩咳嗽喉咙有痰怎么办 4岁宝宝喉咙有痰怎么办 20天新生儿有痰怎么办 孩子嗓子老是有痰怎么办 买的哈密瓜不甜怎么办 吉他琴颈变形了怎么办 hcg值长得慢怎么办 蚊子老在耳边叫怎么办 刚买来的鲜海参怎么办 天冷手指关节疼怎么办 未满一年驾龄上高速违章怎么办 榴莲太生剥开了怎么办 榴莲开了没熟怎么办 榴莲打开了没熟怎么办 榴莲开口了没熟怎么办 榴莲没熟打开了怎么办 不熟的榴莲没熟怎么办