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++Primer(4版)习题解答
91
【解答】
各表达式的值分别为-86、-18、0、-2。其中,最后一个表达式的结果值依赖于机器,因为
该表达式中除操作只有一个操作数为负数。
习题 5.3
编写一个表达式判断一个int型数值是偶数还是奇数。
【解答】
如下表达式可以判断一个int型数值(假设为ival)是偶数还是奇数:
ival% 2 == 0
若 ival是偶数,则该表达式的值为真(true),否则为假(false)。
习题 5.4
定义术语“溢出”的含义,并给出导致溢出的三个表达式。
【解答】
溢出:表达式的求值结果超出了其类型的表示范围。
如下表达式会导致溢出(假设int类型为16 位):
1000* 1000
32766+ 5
3276* 20
在这些表达式中,各操作数均为int类型,因此这些表达式的类型也是int,但它们的计算
结果均超出了16位int 型的表示范围(-32768~32767),导致溢出。
习题 5.5
解释逻辑与操作符、逻辑或操作符以及相等操作符的操作数在什么时候计算。
【解答】
逻辑与、逻辑或操作符采用称为“短路求值”(short-circuit evaluation)的求值策略,即先
计算左操作数,再计算右操作数,且只有当仅靠左操作数的值无法确定该逻辑运算的结果
时,才会计算右操作数。
C++Primer(4版)习题解答
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个值a、b、c和d 是否满足a 大于b、b大于c 而且c 大于d
的条件。
【解答】
表达式如下:
a> b && b > c && c > d
习题5.9
假设有下面两个定义:
C++Primer(4版)习题解答
93
unsignedlong ul1 =3, ul2 = 7;
下列表达式的结果是什么?
(a)ul1 & ul2 (b) ul1 && ul2
(c)ul1 | ul2 (d) ul1 || ul2
【解答】
各表达式的结果分别为3、true、7、true。
习题 5.10
重写bitset表达式:使用下标操作符对测验结果进行置位(置1)和复位(置
0)。
【解答】
bitset<30>bitset_quiz1;
bitset_quiz1[27]= 1;
bitset_quiz1[27]= 0;
习题5.11
请问每次赋值操作完成后,i和d 的值分别是多少?
inti; double d;
d= i = 3.5;
i= d = 3.5;
【解答】
赋值语句d=i=3.5;完成后,i和d 的值均为3。因为赋值操作具有右结合性,所以首先
将3.5赋给i(此时发生隐式类型转换,将double型字面值3.5转换为int 型值3,赋给i),
然后将表达式i=3.5的值(即赋值后i 所具有的值3)赋给d。
赋值语句 i=d=3.5;完成后,d的值为3.5,i 的值为3。因为先将字面值3.5赋给d,然后
将表达式d=3.5的值(即赋值后d 所具有的值3.5)赋给i(这时也同样发生隐式类型转换)。
习题 5.12
解释每个if条件判断产生什么结果?
C++Primer(4版)习题解答
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的
值赋给dval。pi、ival和dval 的类型各不相同,因此要完成赋值必须进行隐式类型转换,
但系统无法将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++Primer(4版)习题解答
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 Mascitti在1983 年夏天定名的( 参见The C++ Programming
Language(SpecialEdition) 1.4节),C说明它本质上是从C 语言演化而来的,“++”是C语言
的自增操作符。C++语言是C语言的超集,是在C 语言基础上进行的扩展(引入了new、
delete等C语言中没有的操作符,增加了对面向对象程序设计的直接支持,等等),是先有
C语言,再进行++。根据自增操作符前、后置形式的差别(参见习题5.15的解答),C++
表示对C语言进行扩展之后,还可以使用C 语言的内容;而写成++C 则表示无法再使用C
的原始值了,也就是说C++不能向下兼容C了,这与实际情况不符。
习题 5.17
如果输出vector内容的while 循环使用前自增操作符,那会怎么样?
【解答】
将导致错误的结果:ivec的第一个元素没有输出,并企图对一个多余的元素进行解引用。
C++Primer(4版)习题解答
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++Primer(4版)习题解答
97
cout<< **iter << (**iter).size() << endl;
iter++;
}
//释放各个动态分配的string对象
iter= spvec.begin();
while(iter != spvec.end()) {
delete*iter;
iter++;
}
return0;
}
习题5.19
假设iter为vector<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++Primer(4版)习题解答
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++Primer(4版)习题解答
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++Primer(4版)习题解答
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 所占据的存储空
间的字节数,为10个int 型元素所占据的字节数。
表达式sizeof(*x)的结果是指针常量x所指向的对象(数组中第一个int 型元
素)所占据的存储空间的字节数。
C++Primer(4版)习题解答
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++Primer(4版)习题解答
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++Primer(4版)习题解答
103
果;后一种情况只会在部分(甚至是少数)程序中出现。在实际使用中,这种
“潜在的缺陷”可以通过程序员的努力得到弥补,但“实现效率”的提高却能
使所有使用该编译器的程序受益,因此利大于弊。
习题5.29
假设ptr指向类类型对象,该类拥有一个名为ival 的int 型数据成员,vec 是
保存int型元素的vector 对象,而ival、jval和kval 都是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是
否不等于true(1)或false(0)。
(c)判断ptr是否不等于0。如果ptr 不等于0,则求解&&操作的右操作数,即,
ptr加1,且判断ptr原来所指向的对象是否为0。
(d)判断ival及ival+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++Primer(4版)习题解答
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是指向元素类型为string的vector 对象的指针的指
针(即pvec2的类型为vector<string> **),而new 操作返回的是一个指向元
素类型为string的vector 对象的指针,不能用于初始化pvec2。
(f)的错误在于:svec是一个vector对象,不是指针,不能对它进行delete 操
作。
习题5.31
根据5.12.2节的变量定义,解释在计算下列表达式的过程中发生了什么类型转
换?
(a)if (fval)
(b)dval = fval + ival;
(c)dval + ival + cval;
记住,你可能需要考虑操作符的结合性,以便在表达式含有多个操作符的情况
下确定答案。
【解答】
C++Primer(4版)习题解答
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++Primer(4版)习题解答
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);__
- 【重学《C++Primer第四版》】第五章、表达式
- 《C++primer(第五版)》学习之路-第四章:表达式
- C++ Primer 【第四版】第五章 表达式
- 《C++primer》第五版 第四章 第五章 笔记
- C++Primer第五版【学习笔记】——第四章 表达式
- c++ primer(第五版)笔记 第四章 表达式
- 《C++ Primer 第五版》学习笔记-第四章-表达式
- 第五章C++Primer表达式
- c++primer第四章 表达式
- C++primer plus(第四版)第五章习题参考
- C primer plus(第五版)编程练习第四章
- C++primer第五版第四章学习笔记
- C++Primer 中文版 第五版 第四章课后习题答案
- C++primer(第五版)第四章表达式学习笔记(含习题c++源代码和C++11特性)
- C++Primer笔记 第五章 表达式
- C++primer学习笔记-第五章表达式
- c++primer第四章表达式小结-4
- c++ primer(第五版)学习笔记及习题答案代码版(第四章)表达式
- 程序员的45个好习惯
- HDU 2289 Cup 二分
- 黑马程序员---------动态代理类与AOP
- Sed学习笔记
- C/C++编辑器Source Insight技巧收集
- C++ Primer 【第四版】第五章 表达式
- hdu3832-Earth Hour-最短路dij
- 那些我们容易忽略的好点子
- 音频 PCM音频编码格式详解
- GOF 23种设计模式 创建类模式 (2) 工厂方法模式
- Spring MVC防止XSS攻击
- 问题:子进程父进程哪个先执行:【转】关于 fork 和父子进程的理解 + 【转】
- 机房收费系统——子窗体最小化
- UVA - 725 Division (暴力枚举)