答案目录

第4章 表达式

练习4.1

105

练习4.2

(a) 可改为 *(vec.begin())

(b)可改为 (*vec.begin()+1)

练习4.4

1
2
3
4
5
int main()
{
cout << 12/3*4+5*15+24%4/2 << endl;
// 91
}

练习4.5

1
2
3
4
cout << -30 * 3 + 21 / 5 << endl;// -86
cout << -30 + 3 * 21 / 5 << endl;// -18
cout << 30 / 3 * 21 % 5 << endl;// 0
cout << -30 / 3 * 21 % 4 << endl;// -2

练习4.6

1
2
3
4
5
6
7
8
9
10
int main()
{
int a = 0;
if (a % 2)
cout << a << " is odd" << endl;
else
{
cout << a << " is even" << endl;
}
}

练习4.7

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

练习4.8

相等运算符先求值,逻辑与、逻辑或运算优先级相同,按照从左到右的顺序求值

练习4.9

1
2
3
const char *cp = "Hello World";
if (cp && *cp);
// cp是一个地址,不为0。再取*cp的值,为一个字符串,不为0.最后两者相与,值为真。

练习4.10

1
2
3
4
5
6
7
8
int main()
{
int a;
while ((cin >> a) && (a != 42))
{
}
cout << "input the 42,stop" << endl;
}

练习4.11

1
if ((a>b) && (b>c) && (c>d))

练习4.12

i != (j<k) 先判断j<k,i为得到的布尔值取反

练习4.13

1
2
d = i = 3.5;          // i = 3, d = 3; i = 3.5, 将3.5隐式转化为整型。
i = d = 3.5; // d = 3.5, i = 3.4.14

练习4.14

1
2
if (42 = i)            //报错,不能对常量42赋值。
if (i = 42) // 将42赋值给i,if条件为真。

练习4.15

1
2
3
4
  //dval = ival = pi = 0;
// pi存的是地址,给pi赋值为0,即要访问地址为0的内存?
// 应改为:
dval = ival = *pi = 0;

练习4.16

1
2
if (p = getPtr()!= 0)		        // 可能会先判断!=, 再把结果赋值给p,改为if ((p = getPtr()) != 0)
if (i = 1024) // 会把1024赋值给i,再进行判断,改为if (i == 1024)

练习4.17

前置的递增运算符:先算后用,后置的递增运算符:先用后算。递减相同

练习4.18

会先向后移动一个元素,再输出移动后的值。输出范围为第二个元素到最后一个元素的下一个元素。由于最后一个元素的下一个元素未知,所以会访问到未知内存

练习4.19

1
2
3
ptr != 0 && *ptr++;        //判断ptr是否为空,并且ptr指向的值是否为0;
ival ++ && ival; // 判断ival及ival++是否为空。运算的顺序为,先计算++,在进行&&
vec[ival++] <= vec[ival]; // 运算顺序未知,比如ival = 1,编译器有可能先算vec[ival++],得到ival=2,再计算vec[ival],这样就得不到预期结果。因此改成vec[ival+1] <= vec[ival];

练习4.20

1
2
3
4
5
6
*iter++;                    // 合法,先对iter+1,再返回iter初始值的副本,再对该副本进行解引用
(*iter)++; // 不合法,不能对string类型进行++操作。
*iter.empty(); // 不合法,不能对指针指向的值判空。可改为(*iter).empty();
iter->empty(); // 合法
++*iter; // 不合法,先求*iter,在进行++操作,不能对string类型做++操作,可改为 *(++iter);
iter++->empty(); //合法,++和->的优先级一样,所以遵循自左向右结合,先算iter++的值,返回iter初始值的副本,再进行empty()判断。iter->empty等价于(*iter).empty

练习4.21

1
2
3
4
5
6
7
8
9
10
int main()
{
vector<int> ivec = { 1, 2, 3, 4, 5, 6 };

for (auto& iter : ivec) {
iter = (iter % 2 == 1) ? iter * 2 : iter;
cout << iter << " ";
}
cout << endl;
}

练习4.22

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
int main()
{
int grade;
string finalgrade;

while (cin >> grade)
{
// approach 1
finalgrade = (grade > 90) ? "high pass" : ((grade < 60) ? "fail" : ((grade < 75) ? "low pass" : "pass"));

// approch 2
if (grade > 90)
{
finalgrade = "hign pass";
}
else if (grade < 60)
{
finalgrade = "fail";
}
else if (grade < 75)
{
finalgrade = "low pass";
}
else
{
finalgrade = "pass";
}

cout << finalgrade << endl;
}
}

练习4.23

1
2
3
4
string s = "word";
// string p1 = s + s[s.size()-1] == 's' ? "" : "s";
// 条件语句优先级较低,要给其加括号。
string p1 = s + (s[s.size()-1] == 's' ? "" : "s");

练习4.25

<< 二进制左移运算符,左操作数的值向左移动右操作数指定的位数
>> 二进制右移运算符,左操作数的值向右移动右操作数指定的位数

q =0000 0000 0000 0000 0000 0000 0111 0001

~q = 1111 1111 1111 1111 1111 1111 1000 1110

(~q) << 6 = 1111 1111 1111 1111 1110 0011 1000 0000

练习4.26

因为老师学生有31个,所使用的类型最少需要有32位,但是在某些机器上,unsigned int 可能就不是32位了

练习4.27

1
2
3
4
5
unsigned long ul1 = 3, ul2 = 7;
cout << (ul1 & ul2) << endl; // 0011 & 0111 = 0011 = 3
cout << (ul1 | ul2) << endl; // 0011 | 0111 = 0111 = 7
cout << (ul1 && ul2) << endl; // 3 && 7 = 1
cout << (ul1 || ul2) << endl;4.28 // 3 || 7 = 1

练习4.28

1
2
3
4
5
6
7
8
9
10
11
int main()
{
cout << sizeof(int) << endl; // 4
cout << sizeof(char) << endl; // 1
cout << sizeof(short) << endl; // 2
cout << sizeof(long) << endl; // 4
cout << sizeof(float) << endl; // 4
cout << sizeof(double) << endl; // 8
cout << sizeof(long double) << endl; // 8
cout << sizeof(long long) << endl; // 8
}

练习4.29

1
2
3
4
5
6
7
int main()
{
int x[10]; int* p = x;
cout << sizeof(x) / sizeof(*x) << endl; // 10, sizeof(x) = 10*4, sizeof(*x) = 4;
cout << sizeof(p) / sizeof(*p) << endl; // 2, sizeof(p)的含义:p是一个int *类型,因此得出的大小应该是指针的大小。
// sizeof(*p)的含义:*p已经对p解引用了,*p实际就是int类型,因此sizeof(*p)得到的是一个int型的大小。
}

练习4.30

1
2
3
4
sizeof x +  y;                // sizeof(x) +  y; 
sizeof p->mem[i]; // sizeof (p->mem[i]);
sizeof a < b; // sizeof (a) < b;
sizeof f(); // sizeof (f());

练习4.31

在for循环中使用前置版本和后置版本都能得到相同的结果。这里使用前置版本的原因,就是4.5节中的建议所述:“前置版本的递增运算符避免了不必要的工作,它把值加1后直接返回改变了运算对象。与之相比,后置版本需要将原始值存储下来以便于返回这个未修改的内容,如果我们不需要修改前的值,那么后置版本的操作就是一种浪费。”

练习4.32

1
2
3
4
5
6
7
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和ptr的作用相同,一个使用下标遍历,一个使用指针遍历

练习4.33

因为逗号表达式的优先级最低,按照预期,如果someValue为真,冒号后面的语句不会再执行了,但实际上,编译器会认为冒号后面的–x属于三目运算符中的语句,而–y属于一个单独的语句。也就是( someValue ? ++x, ++y : --x), --y;

因此,如果someValue为真,则执行++x,++y,–y,最后得到的结果是y本身。如果someValue为假,则执行–x,–y,最终的结果是–y的值

练习4.34

类型 名称 类型 名称
bool flag char cval
short sval unsignedshort usval
int ival unsigned int uival
long lval unsigned long ulval
float fval double dval
1
2
3
if (fval)                  // float类型转化为bool类型
dval = fval + ival; // int先转化为float,然后赋值给dval时再转化为double类型
dval + ival * cval; // char先转化为int,然后int转化为double

练习4.35

1
2
3
4
5
6
7
8
9
10
char cval;
int ival;
unsigned int ui;
float fval;
double dval;

cval = 'a' + 3; // ‘a’先转化为int进行计算,得到的结果再转化为char
fval = ui - ival * 1.0; // ival先转化为double,ui也转化为double,double再截为float
dval = ui * fval; // unsigned int先提升为float,float再转为double
cval = ival + fval + dval; // ival先转为float,float再转为double,最后double转为char

练习4.36

1
i *= static_cast<int> (d);

练习4.37

1
2
3
4
5
6
7
8
9
10
int i;
double d;
const string *ps;
char *pc;
void *pv;

pv = (void *)ps; // pv = const_cast<string *>(ps); 去除底层const属性。
i = int(*pc); // i = static_cast<int>(*pc);
pv = &d; // pv = static_cast<void *>(&d);
pc = (char *)pv; // pc = reinterpret_cast<char *> (pv);

练习4.38

1
2
double slope = static_cast<double>(j/i);
//将j/i的结果转化为double类型,再赋值给slope