Skip to content

Commit

Permalink
Add solutions to all exercises in chapter 4.
Browse files Browse the repository at this point in the history
  • Loading branch information
Jaege committed Jan 12, 2016
1 parent 6f6b6f3 commit bdf9a9d
Show file tree
Hide file tree
Showing 38 changed files with 409 additions and 0 deletions.
7 changes: 7 additions & 0 deletions ch4/4.1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include <iostream>

int main() {
std::cout << (5 + 10 * 20 / 2) << std::endl; // 105

return 0;
}
7 changes: 7 additions & 0 deletions ch4/4.10.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include <iostream>

int main() {
int i;
while (std::cin >> i && i != 42) { /* do something */ }
return 0;
}
8 changes: 8 additions & 0 deletions ch4/4.11.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include <iostream>

int main() {
int a, b, c, d;
std::cin >> a >> b >> c >> d;
if (a > b && b > c && c > d) { /* do something */ }
return 0;
}
5 changes: 5 additions & 0 deletions ch4/4.12.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
The expression `i != j < k` is the same with `i != (j < k)`.

First, `j < k` is evaluated and the result is a `bool`(either `true` or `false`).

Second, `i != true` or `i != false` is evaluated. Since `i` is an `int`, the `bool` will be converted to `int`, which means `i != 1` or `i != 0` is evaluated.
12 changes: 12 additions & 0 deletions ch4/4.13.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include <iostream>

int main() {
int i;
double d;
d = i = 3.5;
std::cout << d << ' ' << i << std::endl; // 3 3
i = d = 3.5;
std::cout << d << ' ' << i << std::endl; // 3.5 3

return 0;
}
3 changes: 3 additions & 0 deletions ch4/4.14.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
`if (42 = i) // ...` is an error.

`if (i = 42) // ...` will first assign 42 to `i` and yield the value of `i` as the condition expression of `if` statement. And because 42 is nonzero, the condition will be `true`.
11 changes: 11 additions & 0 deletions ch4/4.15.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
int main() {
double dval;
int ival;
int *pi;
//dval = ival = pi = 0;
// the type of `pi` is `int *` which cannot be converted to `int`
dval = ival = 0;
pi = 0;

return 0;
}
3 changes: 3 additions & 0 deletions ch4/4.16.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
`if (p = getPtr() != 0)` is the same with `if (p = (getPtr() != 0))` and should be `if ((p = getPtr()) != 0)`.

`if (i = 1024)` may be `if (i == 1024)`.
3 changes: 3 additions & 0 deletions ch4/4.17.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The prefix increment operator increases the operand and return the operand itself as an lvalue.

The postfix increment operator increases the operand and return a copy of the operand's original value as an rvalue.
1 change: 1 addition & 0 deletions ch4/4.18.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The loop will print all elements except the first one in the vector, and also try to dereference to one past the last element, which is an error. Also, if there is no negative value in the vector, the loop will continue to dereference whatever in memeory until a negative value is found, which is a disaster.
16 changes: 16 additions & 0 deletions ch4/4.19.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
(a)
ptr != 0 && *ptr++

The expression means if `ptr` is not null pointer, then point to whatever next in memory and return a copy of the value of the original `int` variable. Since we don't know what next in memory is, it will be an error if we dereference `ptr` after the expression. The expression may be:
ptr != 0 && (*ptr)++

(b)
ival++ && ival

The expression first increases the value of `ival` and return a copy of the original value, then if the original value is nonzero, the right hand operand `ival`(the incremented one) is evaluated, if it is also nonzero, the expression is `true`, else it is `false.

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

The order of evaluation of `<=` operator's operands is undefined. The expression should be:
++ival, vec[ival] <= vec[ival + 1]
9 changes: 9 additions & 0 deletions ch4/4.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
(a)
* vec.begin() ==> * ((vec.begin)())

The order is: member selector, function call, dereference.

(b)
* vec.begin() + 1 ==> ( * ((vec.begin)())) + 1

The order is: member selector, function call, dereference, add.
11 changes: 11 additions & 0 deletions ch4/4.20.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
(a) `*iter++;` is legal. The expression moves `iter` to point to the next element and returns the value of the original element.

(b) `(*iter)++` is not legal. The expression means increasing value of the element, but the value is a `string` and `string` does not have `++` operator.

(c) `*iter.empty()` is not legal. Because `iter` is an iterator and has no member named `empty`.

(d) `iter->empty()` is legal. The expression means check if the string pointed by `iter` is empty.

(e) `++*iter` is not legal. The expression means increasing value of the element, but the value is a `string` and `string` does not have `++` operator.

(f) `iter++->empty()` is legal. The expression means move `iter` to point to the next element and check if that `string` is empty.
16 changes: 16 additions & 0 deletions ch4/4.21.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include <iostream>
#include <vector>

int main() {
std::vector<int> iv;
int i;
while (std::cin >> i)
iv.push_back(i);
for (auto &elem : iv)
elem = elem % 2 ? elem + elem : elem;
for (const auto &elem : iv)
std::cout << elem << ' ';
std::cout << std::endl;

return 0;
}
30 changes: 30 additions & 0 deletions ch4/4.22.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include <iostream>

int main() {
int grade;
std::cin >> grade;

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

// Note that the conditional operator is right associative, meaning that the
// operands are grouped from right to left.

if (grade > 90)
std::cout << "high pass" << std::endl;
else if (grade > 75)
std::cout << "pass" << std::endl;
else if (grade >= 60)
std::cout << "low pass" << std::endl;
else
std::cout << "fail" << std::endl;

// The `if` statements are relatively easy to understand when the conditions
// do not have much braches.

return 0;
}
12 changes: 12 additions & 0 deletions ch4/4.23.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include <string>
using std::string;

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

// The precedence of the conditional operator is lower than arithmetic operator.

return 0;
}
13 changes: 13 additions & 0 deletions ch4/4.24.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
If the operator were left associative, then the expression

grade > 90 ? "high pass"
: grade < 60 ? "fail" : "pass";

would be evaluated as:

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

which means:

- if the grade is greater than 90, then return "high pass", which is not empty string and evaluate to `true`, then return "fail";
- else evaluates `grade < 60` and takes the result as the condition for the second conditional operator, which means if the grade is less than 60, return "fail", else return "pass".
16 changes: 16 additions & 0 deletions ch4/4.25.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
`~'q' << 6` is the same as `(~'q') << 6`.

1. The operand of `~` operator is a "small integer"(`char` here), thus its value is first promoted to a larger integral type(`int` here).

'q' = 01110001 promoted to
00000000 00000000 00000000 01110001

2. After the `~` operator evaluated,

~'q' 11111111 11111111 11111111 10001110

3. Left shift,

~'q' << 6 11111111 11111111 11100011 10000000

4. The result is -7296.
1 change: 1 addition & 0 deletions ch4/4.26.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The standard guarantees the minimum size of `int` is 16 bits, and the minimum size of `long` is 32 bits. Since the teacher has 30 students in a class, which needs at least 30 bits, `int` would be not enough to hold all the results.
12 changes: 12 additions & 0 deletions ch4/4.27.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include <iostream>

int main() {
unsigned long ul1 = 3, ul2 = 7;

std::cout << (ul1 & ul2) << std::endl; // 3
std::cout << (ul1 | ul2) << std::endl; // 7
std::cout << (ul1 && ul2) << std::endl; // 1, means true
std::cout << (ul1 || ul2) << std::endl; // 1, means true

return 0;
}
17 changes: 17 additions & 0 deletions ch4/4.28.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <iostream>

int main() {
std::cout << "char " << sizeof(char) << std::endl;
std::cout << "wchar_t " << sizeof(wchar_t) << std::endl;
std::cout << "char16_t " << sizeof(char16_t) << std::endl;
std::cout << "char32_t " << sizeof(char32_t) << std::endl;
std::cout << "short " << sizeof(short) << std::endl;
std::cout << "int " << sizeof(int) << std::endl;
std::cout << "long " << sizeof(long) << std::endl;
std::cout << "long long " << sizeof(long long) << std::endl;
std::cout << "float " << sizeof(float) << std::endl;
std::cout << "double " << sizeof(double) << std::endl;
std::cout << "long double " << sizeof(long double) << std::endl;

return 0;
}
10 changes: 10 additions & 0 deletions ch4/4.29.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include <iostream>

int main() {
int x[10];
int *p = x;
std::cout << sizeof(x) / sizeof(*x) << std::endl; // 10
std::cout << sizeof(p) / sizeof(*p) << std::endl; // the size of a pointer / the size of an int

return 0;
}
3 changes: 3 additions & 0 deletions ch4/4.3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
I think that is an acceptable trade-off. When an expression refers to and change the same object, we can always seperate that expression into several expressions to avoid the situation except where:
- The operator involved is one of _and `&&`, or `||`, conditional `?:`, comma `,`_ operator,
- The subexpression that change the operand is itself the operand of another subexpression.
4 changes: 4 additions & 0 deletions ch4/4.30.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
(a) `sizeof(x) + y`
(b) `sizeof(p->mem[i])`
(c) `sizeof(a) < b`
(d) `sizeof(f())`
27 changes: 27 additions & 0 deletions ch4/4.31.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include <iostream>
#include <vector>

int main() {
std::vector<int> ivec(10);
std::vector<int>::size_type cnt = ivec.size();
for (std::vector<int>::size_type ix = 0; ix != ivec.size(); ++ix, --cnt)
ivec[ix] = cnt;
for (const auto &e : ivec)
std::cout << e << " ";
std::cout << std::endl;

// Because we don't need the value returned by postfix operator, and making a
// copy of an object may be a heavy operation, so prefix operator is prefered
// here.

cnt = ivec.size();
for (std::vector<int>::size_type ix = 0; ix != ivec.size(); ix++, cnt--)
ivec[ix] = cnt;
for (const auto &e : ivec)
std::cout << e << " ";
std::cout << std::endl;

// The results are same.

return 0;
}
19 changes: 19 additions & 0 deletions ch4/4.32.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
int main() {
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) {
/* some code */
}

// First, the loop created a pointer `ptr` point to the first element of the
// array `ia` and an index `ix`.
//
// Then the loop will check if the index is at one past the last of the array
// and if the pointer point to the element at one past the last of the array,
// if these are not true, the loop continues.
//
// Every time, the index will increase 1 and the pointe will move to point
// the next element.

return 0;
}
9 changes: 9 additions & 0 deletions ch4/4.33.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
The expression

sameValue ? ++x, ++y : --x, --y

is the same as

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

Then it will be easy to notice that whatever `sameValue` evaluated, `--y` will always be evaluated.
3 changes: 3 additions & 0 deletions ch4/4.34.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(a) `fval` is converted to `bool`.
(b) `ival` is converted to `float`, then added to `fval`, finally the result is converted to `double`.
(c) `cval` is promoted to `int`, then multiplied by `ival`, then the result is converted to `double`, then added to `dval`.
27 changes: 27 additions & 0 deletions ch4/4.35.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
int main() {
char cval = 0;
int ival = 0;
unsigned int ui = 0;
float fval = 0;
double dval = 0;

cval = 'a' + 3;
// 'a' is promoted to `int`, then added to `3`, then converted to `char`.

fval = ui - ival * 1.0;
// `ival` is converted to double, then multiplied by `1.0`. The result is
// converted to `unsigned int`, then subtracted by `ui`. The result is
// converted to `float`, then assigned to `fval`.

dval = ui * fval;
// Since `float` usually has more bits then `unsigned int`, `ui` is converted
// to `float`, then multiplied by `fval`. The result is converted to
// `double`, then assigned to `dval`.

cval = ival + fval + dval;
// `ival` is converted to `float`, then added to `fval`. The result is
// converted to `double`, then added to `dval`. The result is converted to
// `char`, then assigned to `cval`.

return 0;
}
6 changes: 6 additions & 0 deletions ch4/4.36.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
int main() {
int i = 0;
double d = 0;
i *= static_cast<int>(d);
return 0;
}
26 changes: 26 additions & 0 deletions ch4/4.37.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include <string>

int main() {
int i = 0;
double d = 0;
std::string str("some string");
const std::string *ps = &str;
char c = 'c';
char *pc = &c;
void *pv;

//pv = (void*)ps;
pv = static_cast<void *>(const_cast<std::string *>(ps));
//pv = const_cast<std::string *>(ps); // Also work.

//i = int(*pc);
i = static_cast<int>(*pc);

//pv = &d;
pv = static_cast<void *>(&d);

//pc = (char*) pv;
pc = static_cast<char *>(pv);

return 0;
}
1 change: 1 addition & 0 deletions ch4/4.38.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The expression first did integral division `j / i`, then converted the result to `double` and assigned it to `slope`. The result is the same as `double slope = j / i;`.
8 changes: 8 additions & 0 deletions ch4/4.4.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include <iostream>

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

return 0;
}
10 changes: 10 additions & 0 deletions ch4/4.5.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include <iostream>

int main() {
std::cout << -30 * 3 + 21 / 5 << std::endl; // -86
std::cout << -30 + 3 * 21 / 5 << std::endl; // -18
std::cout << 30 / 3 * 21 % 5 << std::endl; // 0
std::cout << -30 / 3 * 21 % 4 << std::endl; // -2

return 0;
}
Loading

0 comments on commit bdf9a9d

Please sign in to comment.