在我自学C++过程中,我选择了C++Primer这本书,并对部分代码习题进行了求解以及运行结果。接下来几个月我将为大家定时按章节更新习题答案与运行结果,运行环境(Visual Studio Code,windows 11):
C++ Primer (第五版)习题答案总目录:
https://blog.youkuaiyun.com/weixin_48467622/article/details/136418131?spm=1001.2014.3001.5501
目录
4.2 根据4.12节中的表,在下述表达式的合理位置添加括号,使得添加括号后运算对象的组合顺序与添加括号前一致。
4.3 C++语言没有明确规定大多数二元运算符的求值顺序,给编译器优化留下了余地。这种策略实际上是在代码生成效率和程序潜在缺陷之间进行了权衡,你认为这可以接受吗?请说出你的理由。
4.4 在下面的表达式中添加括号,说明其求值过程及最终结果。编写程序编译该(不加括号的)表达式并输出结果验证之前的推断。
4.8 说明在逻辑与、逻辑或及相等性运算符中运算对象的求值顺序。
4.10 为while 循环写一个条件,使其从标准输入中读取整数,遇到 42 时停止。
4.11 书写一条表达式用于测试4个值a、b、c、d的关系,确保a大于b、b大于c、c大于d。
4.21 编写一段程序,使用条件运算符从 vector 中找到哪些元素的值是奇数,然后将这些奇数值翻倍。
4.25 如果一台机器上 int 占 32 位、char 占8位,用的是 Latin-1 字符集,其中字符’q’ 的二进制形式是 01110001,那么表达式’q’ << 6的值是什么?
4.29 推断下面代码的输出结果并说明理由。实际运行这段程序,结果和你想象的一样吗?如不一样,为什么?
4.30 根据4.12节中的表,在下述表达式的适当位置加上括号,使得加上括号之后的表达式的含义与原来的含义相同。
4.31 本节的程序使用了前置版本的递增运算符和递减运算符,解释为什么要用前置版本而不用后置版本。要想使用后置版本的递增递减运算符需要做哪些改动?使用后置版本重写本节的程序。
4.36 假设 i 是int类型,d 是double类型,书写表达式 i*=d 使其执行整数类型的乘法而非浮点类型的乘法。
4.2 根据4.12节中的表,在下述表达式的合理位置添加括号,使得添加括号后运算对象的组合顺序与添加括号前一致。
(a) *vec.begin()
(b) *vec.begin() + 1
(a) *(vec.begin())
(b) (*(vec.begin())) + 1
4.3 C++语言没有明确规定大多数二元运算符的求值顺序,给编译器优化留下了余地。这种策略实际上是在代码生成效率和程序潜在缺陷之间进行了权衡,你认为这可以接受吗?请说出你的理由。
可以接受。C++的设计思想是尽可能地“相信”程序员,将效率最大化。然而这种思想却有着潜在的危害,就是无法控制程序员自身引发的错误。因此 Java 的诞生也是必然,Java的思想就是尽可能地“不相信”程序员。
4.4 在下面的表达式中添加括号,说明其求值过程及最终结果。编写程序编译该(不加括号的)表达式并输出结果验证之前的推断。
12 / 3 * 4 + 5 * 15 + 24 % 4 / 2
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
cout << (((12/3)*4)+(5*15))+((24%4)/2) << endl;
cout << 12 / 3 * 4 + 5 * 15 + 24 % 4 / 2 << endl;
return 0;
}
4.6 写出一条表达式用于确定一个整数是奇数还是偶数。
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
int i = 0;
cin >> i;
if (i % 2)
{
cout << "奇数!" << endl;
}
else
{
cout << "偶数!" << endl;
}
return 0;
}
4.8 说明在逻辑与、逻辑或及相等性运算符中运算对象的求值顺序。
- 逻辑与运算符和逻辑或运算符都是先求左侧运算对象的值再求右侧运算对象的值,当且仅当左侧运算对象无法确定表达式的结果时才会计算右侧运算对象的值。这种策略称为 短路求值。
- 相等性运算符未定义求值顺序。
4.9 解释在下面的if语句中条件部分的判断过程。
const char *cp = "Hello World";
if (cp && *cp)
首先判断 cp
,cp
不是一个空指针,因此 cp
为真。然后判断 *cp
,*cp
的值是字符 ‘H’,非0。因此最后的结果为真。
4.10 为while 循环写一个条件,使其从标准输入中读取整数,遇到 42 时停止。
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
int i = 0;
while (cin >> i && i != 42);
if (i == 42)
{
cout << "over" << endl;
}
return 0;
}
4.11 书写一条表达式用于测试4个值a、b、c、d的关系,确保a大于b、b大于c、c大于d。
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
int a = 0, b = 0, c = 0, d = 0;
if (cin >> a >> b >> c >> d && a > b && b > c && c > d)
{
cout << "Right!" << endl;
}
else
{
cout << "Wrong!" << endl;
}
return 0;
}
4.17 说明前置递增运算符和后置递增运算符的区别。
前置递增运算符将对象本身作为左值返回,而后置递增运算符将对象原始值的副本作为右值返回。
4.21 编写一段程序,使用条件运算符从 vector 中找到哪些元素的值是奇数,然后将这些奇数值翻倍。
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
vector<int> v = { 0,1,2,3,4,5,6,7,8,9,10 };
for (auto& i : v)
{
i = i % 2 ? 2 * i : i;
}
for (auto i : v)
{
cout << i << ",";
}
cout << endl;
return 0;
}
4.22 本节的示例程序将成绩划分为high pass、pass 和 fial 三种,扩展该程序使其进一步将 60 分到 75 分之间的成绩设定为 low pass。要求程序包含两个版本:一个版本只使用条件运算符;另一个版本使用1个或多个if语句。哪个版本的程序更容易理解呢?为什么?
第二个版本容易理解。当条件运算符嵌套层数变多之后,代码的可读性急剧下降。而if else 的逻辑很清晰。
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
int grade = 0;
string finalgrade;
cin >> grade;
finalgrade = (grade > 90) ? "High pass" :
(grade > 75) ? "Low pass" :
(grade > 60) ? "Pass" :
"Fial";
cout << finalgrade << endl;
if (grade > 90)
{
finalgrade = "High pass";
}
else if (grade > 75)
{
finalgrade = "Low pass";
}
else if (grade > 60)
{
finalgrade = "Pass";
}
else
{
finalgrade = "Fial";
}
cout << finalgrade << endl;
return 0;
}
4.25 如果一台机器上 int 占 32 位、char 占8位,用的是 Latin-1 字符集,其中字符’q’ 的二进制形式是 01110001,那么表达式’q’ << 6的值是什么?
首先将char类型提升为int 类型,等同于 00000000 00000000 00000000 01110001 << 6,结果是 00000000 00000000 00011100 01000000,转换是十进制是7232。
4.27 下列表达式的结果是什么?
unsigned long ul1 = 3, ul2 = 7;
(a) ul1 & ul2
(b) ul1 | ul2
(c) ul1 && ul2
(d) ul1 || ul2
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
unsigned long u11 = 3, u12 = 7;
cout << (u11 & u12) << endl;
cout << (u11 | u12) << endl;
cout << (u11 && u12) << endl;
cout << (u11 || u12) << endl;
return 0;
}
4.28 编写一段程序,输出每一种内置类型所占空间的大小。
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
cout << "bool:\t\t" << sizeof(bool) << " bytes" << endl << endl;
cout << "char:\t\t" << sizeof(char) << " bytes" << endl;
cout << "wchar_t:\t" << sizeof(wchar_t) << " bytes" << endl;
cout << "char16_t:\t" << sizeof(char16_t) << " bytes" << endl;
cout << "char32_t:\t" << sizeof(char32_t) << " bytes" << endl << endl;
cout << "short:\t\t" << sizeof(short) << " bytes" << endl;
cout << "int:\t\t" << sizeof(int) << " bytes" << endl;
cout << "long:\t\t" << sizeof(long) << " bytes" << endl;
cout << "long long:\t" << sizeof(long long) << " bytes" << endl << endl;
cout << "float:\t\t" << sizeof(float) << " bytes" << endl;
cout << "double:\t\t" << sizeof(double) << " bytes" << endl;
cout << "long double:\t" << sizeof(long double) << " bytes" << endl << endl;
cout << "int8_t:\t\t" << sizeof(int8_t) << " bytes" << endl;
cout << "uint8_t:\t" << sizeof(uint8_t) << " bytes" << endl;
cout << "int16_t:\t" << sizeof(int16_t) << " bytes" << endl;
cout << "uint16_t:\t" << sizeof(uint16_t) << " bytes" << endl;
cout << "int32_t:\t" << sizeof(int32_t) << " bytes" << endl;
cout << "uint32_t:\t" << sizeof(uint32_t) << " bytes" << endl;
cout << "int64_t:\t" << sizeof(int64_t) << " bytes" << endl;
cout << "uint64_t:\t" << sizeof(uint64_t) << " bytes" << endl;
return 0;
}
4.29 推断下面代码的输出结果并说明理由。实际运行这段程序,结果和你想象的一样吗?如不一样,为什么?
int x[10]; int *p = x;
cout << sizeof(x)/sizeof(*x) << endl;
cout << sizeof(p)/sizeof(*p) << endl;
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
int x[10];
int* p = x;
cout << sizeof(x) / sizeof(*x) << endl;
cout << sizeof(p) / sizeof(*p) << endl;
return 0;
}
4.30 根据4.12节中的表,在下述表达式的适当位置加上括号,使得加上括号之后的表达式的含义与原来的含义相同。
(a) sizeof x + y
(b) sizeof p->mem[i]
(c) sizeof a < b
(d) sizeof f()
(a) (sizeof x) + y
(b) sizeof (p->mem[i])
(c) (sizeof a) < b
(d) sizeof (f())
4.31 本节的程序使用了前置版本的递增运算符和递减运算符,解释为什么要用前置版本而不用后置版本。要想使用后置版本的递增递减运算符需要做哪些改动?使用后置版本重写本节的程序。
后置版本需要将未修改的值保存下来,以便返回,如果不需要未修改的值就使用前置版本。使用后置版本无需改动。
4.32 解释下面这个循环的含义。
constexpr int size = 5;
int ia[size] = { 1, 2, 3, 4, 5 };
for (int *ptr = ia, ix = 0;
ix != size && ptr != ia+size;
++ix, ++ptr) { /* ... */ }
ptr和ix的功能都是为了遍历数组,功能一样,实现的过程不一样,ptr是指针方式实现,ix是索引方式实现。
4.33 根据4.12节中的表说明下面这条表达式的含义。
someValue ? ++x, ++y : --x, --y
如果 someValue的值为真,x 和 y 的值都自增并返回 y 值,然后丢弃 y 值,y递减并返回 y 值。如果 someValue的值为假,x 递减并返回 x 值,然后丢弃 x 值,y递减并返回 y 值。
(someValue ? ++x, ++y : --x), --y
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
int someValue = 0;
int x = 1, y = 1;
cout << (someValue ? ++x, ++y : --x, --y) << endl;
cout << "x=" << x << endl;
cout << "y=" << y << endl;
return 0;
}
4.35 假设有如下的定义:
char cval;
int ival;
unsigned int ui;
float fval;
double dval;
请回答在下面的表达式中发生了隐式类型转换吗?如果有,指出来。
(a) cval = 'a' + 3;
(b) fval = ui - ival * 1.0;
(c) dval = ui * fval;
(d) cval = ival + fval + dval;
(a) ‘a’ 转换为 int ,然后与 3 相加的结果转换为 char
(b) ival 转换为 double,ui 转换为 double,结果转换为 float
(c)ui 转换为 float,结果转换为 double
(d) ival 转换为 float,与fval相加后的结果转换为 double,最后的结果转换为char
4.36 假设 i 是int类型,d 是double类型,书写表达式 i*=d 使其执行整数类型的乘法而非浮点类型的乘法。
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
int i = 10;
double d = 66666.66666;
i *= static_cast<int>(d);
cout << i << endl;
return 0;
}
4.37 用命名的强制类型转换改写下列旧式的转换语句。
int i; double d; const string *ps; char *pc; void *pv;
(a) pv = (void*)ps;
(b) i = int(*pc);
(c) pv = &d;
(d) pc = (char*)pv;
- (a) pv = static_cast<void*>(const_cast<string*>(ps));
- (b) i = static_cast(*pc);
- (c)pv = static_cast<void*>(&d);
- (d) pc = static_cast<char*>(pv);