C++primer 第五版 第四章练习题

4.1 表达式 5 + 10 * 20 / 2 的求值结果是多少?

105

4.2 根据4.12节中的表,在下述表达式的合理位置添加括号,使得添加括号后运算对象的组合顺序与添加括号前一致。

*vec.begin()
*vec.begin() + 1
//.和() 同等级符合左结合律,*次之,+最低。
*(vec.begin())
(*(vec.begin())) + 1

4.4 在下面的表达式中添加括号,说明其求值过程及最终结果。编写程序编译该(不加括号的)表达式并输出结果验证之前的推断。

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

4.5 写出下列表达式的求值结果。

-30 * 3 + 21 / 5  // -90+4 = -86
-30 + 3 * 21 / 5  // -30+63/5 = -30+12 = -18
30 / 3 * 21 % 5   // 10*21%5 = 210%5 = 0
-30 / 3 * 21 % 4  // -10*21%4 = -210%4 = -2

4.6 写出一条表达式用于确定一个整数是奇数还是偶数。

if(int num % 2 == 0){}

4.7 溢出是何含义?写出三条将导致溢出的表达式。

当计算的结果超出该类型所能表示的范围时就会产生溢出。

short s = 32767; ++s; 
unsigned u = 0; --u;  
unsigned short us = 65535; ++us; 

4.8 说明在逻辑与、逻辑或及相等性运算符中运算对象的求值顺序。

逻辑与和逻辑或都是先看运算符左侧对象的结果,如果看完左侧的没法确定最终结果就继续看右侧的。相等性的运算符没有定义求值顺序。

4.9 解释在下面的if语句中条件部分的判断过程。

const char *cp = "Hello World";
if (cp && *cp)

先看指针cp是不是一个空指针,不是,继续往下看,对*cp解引用,得到“H”是个非0值,最后结果为真。

4.10 为while 循环写一个条件,使其从标准输入中读取整数,遇到 42 时停止。

int num;
while(cin >> num && num != 42)

4.11 书写一条表达式用于测试4个值a、b、c、d的关系,确保a大于b、b大于c、c大于d。

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

4.12 假设i、j 和k 是三个整数,说明表达式 i != j < k 的含义。

先进行j< k的比较,得结果true或者false,然后转换成1 或者 0 ,如果i不等于1 或者0就返回真,否则为假。最终为bool类型。

4.13 在下述语句中,当赋值完成后 i 和 d 的值分别是多少?

int i;   double d;
d = i = 3.5; // i = 3, d = 3.0
i = d = 3.5; // d = 3.5, i = 3

4.14 执行下述 if 语句后将发生什么情况?

if (42 = i)   // 错误。赋值运算符左侧必须是一个可修改的左值。
if (i = 42)   // true.

4.15 下面的赋值是非法的,为什么?应该如何修改?

double dval; int ival; int *pi;
dval = ival = pi = 0;

p 是指针,不能赋值给 int ,应该改为:

dval = ival = 0;
pi = 0;

4.16 尽管下面的语句合法,但它们实际执行的行为可能和预期并不一样,为什么?应该如何修改?

if (p = getPtr() != 0)
if (i = 1024)

条件判断结果总为 true, 改为:

if ((p=getPtr()) != 0)
if (i == 1024)

4.17 说明前置递增运算符和后置递增运算符的区别。

前置递增运算符将对象本身作为左值返回,而后置递增运算符将对象原始值的副本作为右值返回。

4.18 如果132页那个输出vector对象元素的while循环使用前置递增运算符,将得到什么结果?

第一个元素不会输出,并且最后对 v.end() 进行取值,结果是未定义的。

4.19 假设 ptr 的类型是指向 int 的指针、vec 的类型是vector、ival 的类型是int,说明下面的表达式是何含义?如果有表达式不正确,为什么?应该如何修改?

(a) ptr != 0 && *ptr++  
(b) ival++ && ival
(c) vec[ival++] <= vec[ival] 

(a) 判断ptr 不是一个空指针,并且ptr 当前指向的元素的值也为真,然后将ptr指向下一个元素
(b) 判断 ival 的值为真,并且 (ival + 1) 的值也为真
© 表达式有误。C++并没有规定 <= 运算符两边的求值顺序,

4.20 假设 iter 的类型是 vector::iterator, 说明下面的表达式是否合法。如果合法,表达式的含义是什么?如果不合法,错在何处?

(a) *iter++;
(b) (*iter)++;
(c) *iter.empty();
(d) iter->empty();
(e) ++*iter;
(f) iter++->empty();

(a)合法。返回迭代器所指向的元素,然后迭代器递增。
(b)不合法。因为vector元素类型是 string,没有 ++ 操作。
©不合法。这里应该加括号。
(d)合法。判断迭代器当前的元素是否为空。
(e)不合法。string 类型没有 ++ 操作。
(f)合法。判断迭代器当前元素是否为空,然后迭代器递增。

4.21 编写一段程序,使用条件运算符从 vector 中找到哪些元素的值是奇数,然后将这些奇数值翻倍。

//int main(){
//    vector<int> v1;
//    for(int i = 1; i != 7; ++i){
////        v1.push_back(i);
//        v1.push_back(i);
//    }
//    for(auto &v : v1){
//        v = (v % 2 == 0 ? v : v * 2);
//    }
//    for(auto v : v1){
//        cout << v << " ";
//    }
//  return 0;
//}

4.22 本节的示例程序将成绩划分为high pass、pass 和 fial 三种,扩展该程序使其进一步将 60 分到 75 分之间的成绩设定为 low pass。要求程序包含两个版本:一个版本只使用条件运算符;另一个版本使用1个或多个if语句。哪个版本的程序更容易理解呢?为什么?

int main(){
    int grade = 75;

    string finalGrade = (grade > 90) ? "high pass" : (grade < 75) ? "low pass" : (grade < 60) ? "fail" : "pass";
    cout << finalGrade << endl;

    if(grade > 90){
        finalGrade = "high pass";
    }else if(grade < 75){
        finalGrade = "low pass";
    }else if(grade >60){
        finalGrade = "pass";
    }else{
        finalGrade = "fail";
    }
    cout << finalGrade << endl;
    return 0;
}

第二个版本容易理解。当条件运算符嵌套层数变多之后,可读性差。

4.23 因为运算符的优先级问题,下面这条表达式无法通过编译。根据4.12节中的表指出它的问题在哪里?应该如何修改?

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

加法运算符的优先级高于条件运算符。因此要改为:

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

4.24 本节的示例程序将成绩划分为 high pass、pass、和fail三种,它的依据是条件运算符满足右结合律。假如条件运算符满足的是左结合律,求值的过程将是怎样的?

如果条件运算符满足的是左结合律。那么

finalgrade = (grade > 90) ? "high pass" : (grade < 60) ? "fail" : "pass";

等同于

finalgrade = ((grade > 90) ? "high pass" : (grade < 60)) ? "fail" : "pass";

假如此时 grade > 90 ,第一个条件表达式的结果是 “high pass” ,而字符串字面值的类型是 const char *,非空所以为真。因此第二个条件表达式的结果是 “fail”。这样就出现了自相矛盾的逻辑。

4.25 如果一台机器上 int 占 32 位、char 占8位,用的是 Latin-1 字符集,其中字符’q’ 的二进制形式是 01110001,那么表达式’q’ << 6的值是什么?

首先转为int 类型,等同于 00000000 00000000 00000000 01110001 << 6,结果是 00000000 00000000 00011100 01000000

4.26 在本节关于测验成绩的例子中,如果使用unsigned int 作为quiz1 的类型会发生什么情况?

在有的机器上,unsigned int 类型可能只有 16 位,因此结果是未定义的。

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

unsigned long ul1 = 3, ul2 = 7;
(a) ul1 & ul2 //3
(b) ul1 | ul2 //7
(c) ul1 && ul2 //true
(d) ul1 || ul2 //true

4.28 编写一段程序,输出每一种内置类型所占空间的大小。

int main(){
//    size_t i = sizeof(int);//4
//    size_t i = sizeof(short);//2
//    size_t i = sizeof(long);8
//    size_t i = sizeof(float); 4
//    size_t i = sizeof(double); 8
//    size_t i = sizeof(long long); 8
//    size_t i = sizeof(unsigned int); 4
//    size_t i = sizeof(unsigned long); 8
//    size_t i = sizeof(unsigned short);2
//    size_t i = sizeof(bool);1
    size_t i = sizeof(long double); //16
    cout << i << endl;
}

4.29 推断下面代码的输出结果并说明理由。实际运行这段程序,结果和你想象的一样吗?如不一样,为什么?

int x[10];   int *p = x;
cout << sizeof(x)/sizeof(*x) << endl; // 10 
cout << sizeof(p)/sizeof(*p) << endl;// 2 sizeof(p)是指针所占内存大小,看硬件我的是8, sizeof(*p)是p所指对象的大小为4 

4.30 根据4.12节中的表,在下述表达式的适当位置加上括号,使得加上括号之后的表达式的含义与原来的含义相同。

//sizeof的优先级高于算术运算符,低于成员选择和函数调用
(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) { /* ... */ }

遍历数组 ia,指针和ix都是计数用的。

4.33 根据4.12节中的表说明下面这条表达式的含义。

someValue ? ++x, ++y : --x, --y

实际上等价于

(someValue ? ++x, ++y : --x), --y

如果 someValue的值为真,x 和 y 的值都自增并返回 y 值,然后丢弃 y 值,y递减并返回 y 值。如果 为假,x 递减并返回 x 值,然后丢弃 x 值,y递减并返回 y 值。

4.34 根据本节给出的变量定义,说明在下面的表达式中奖发生什么样的类型转换:

(a) if (fval)//fval 转换为 bool 类型
(b) dval = fval + ival;//ival 转换为 float ,相加的结果转换为 double
(c) dval + ival * cval;//cval 转换为 int,然后相乘的结果转换为 double

4.35 假设有如下的定义:

char cval;
int ival;
unsigned int ui;
float fval;
double dval;

请回答在下面的表达式中发生了隐式类型转换吗?如果有,指出来。

(a) cval = 'a' + 3;//'a' 转换为 int ,然后与 3 相加的结果转换为 char
(b) fval = ui - ival * 1.0;//ival 转换为 double,ui 转换为 double,结果转换为 float
(c) dval = ui * fval;// ui 转换为 float,结果转换为 double
(d) cval = ival + fval + dval;// ival 转换为 float,与fval相加后的结果转换为 double,最后的结果转换为char

4.36 假设 i 是int类型,d 是double类型,书写表达式 i*=d 使其执行整数类型的乘法而非浮点类型的乘法。

i *= static_cast<int>(d);

4.37 用命名的强制类型转换改写下列旧式的转换语句。

int i; double d; const string *ps; char *pc; void *pv;
(a) pv = (void*)ps;//pv = static_cast<void*>(const_cast<string*>(ps));
(b) i = int(*pc);// i = static_cast(*pc);
(c) pv = &d;//pv = static_cast<void*>(&d);
(d) pc = (char*)pv;//pc = static_cast<char*>(pv);

4.38 说明下面这条表达式的含义。

double slope = static_cast<double>(j/i);

将 j/i 的值转换为 double,然后赋给slope。

发布了8 篇原创文章 · 获赞 1 · 访问量 457

猜你喜欢

转载自blog.csdn.net/Echo_Hsu/article/details/105502534