第二章的习题答案
Exercise 2.1: What are the differences between int, long, long long, and short? Between an unsigned and a signed type? Between a float and a double?
A few notable things:
C++ guarantees a char is exactly one byte which is at least 8 bits, short is at least 16 bits, int is at least 16 bits, and long is at least 32 bits. It also guarantees the unsigned version of each of these is the same size as the original, for example, sizeof(unsigned short) == sizeof(short).
When writing portable code, you shouldn’t make additional assumptions about these sizes.
Refs:
Exercise 2.2: To calculate a mortgage payment, what types would you use for the rate, principal, and payment? Explain why you selected each type.
rate/principal/payment could be some value that comes with decimals but doesn't require too much precision, such as 2.5%, 525555.90, 1333.25, So the float type would handle them all perfectly.
notes: typical float in memory: sign: 1bit, exponent : 8bits, Mantissa: 23bits. Good enough range for almost all of the data above.
Ref:
Exercise 2.3: What output will the following code produce?
/*Q1*/
unsigned u = 10, u2 = 42;
std::cout << u2 - u << std::endl;
std::cout << u - u2 << std::endl;
/*result*/
32
4,294,967,264 //2^32 + (10-42)
/*Q2*/
int i = 10, i2 = 42;
std::cout << i2 - i << std::endl;
std::cout << i - i2 << std::endl;
std::cout << i - u << std::endl;
std::cout << u - i << std::endl;
/*result*/
32
-32
0
0
Exercise 2.4: Write a program to check whether your predictions were correct. If not, study this section until you understand what the problem is.
#include <iostream>
int main(int argc, char const *argv[])
{
unsigned u = 10, u2 = 42;
int i = 10, i2 = 42;
std::cout << u2 - u << std::endl;
std::cout << u - u2 << std::endl;
std::cout << i2 - i << std::endl;
std::cout << i - i2 << std::endl;
std::cout << i - u << std::endl;
std::cout << u - i << std::endl;
return 0;
}
the result matches what we got in ex.2.3.
Exercise 2.5: Determine the type of each of the following literals. Explain the differences among the literals in each of the four examples:
(a) 'a', L'a', "a", L"a"
'a' : char
L'a' : wchar_t
"a" : string
L"a" : wchar_t string
(b) 10, 10u, 10L, 10uL, 012, 0xC
10 : decimal
10u : unsigned decimal
10L : long decimal
10ul : unsigned long decimal
012 : octal
0xC: Hex
(c) 3.14, 3.14f, 3.14L
3.14 : double
3.14f : float
3.14L: long double
10, 10u, 10., 10e-2
10 : decimal
10u : unsigned decimal
10. : double
10e-2 : double
Exercise 2.6: What, if any, are the differences between the following definitions:
int month = 9, day = 7;
int month = 09, day = 07;
The definition in first-line defines dates in decimal. The second line is trying to define the date in octal, however, the 09 is not a valid number in octal. The correct way to define Seq.7th in octal is:
int month = 011, day = 07;
Exercise 2.7: What values do these literals represent? What type does each have?
(a) "Who goes with F\145rgus?\012"
print result: Who goes with Fergus?J, String
(b) 3.14e1L
print result: 3.14, long double
(c) 1024f
print result: this is not the right way to represent a float literal. f suffix can only apply to float point number, e.g. 1024.0
(d) 3.14L
print result: 3.14 long double
Exercise 2.8: Using escape sequences, write a program to print 2M followed by a newline. Modify the program to print 2, then a tab, then an M, followed by a newline.
#include <iostream>
int main(int argc, char const *argv[])
{
std::cout << "2M in escape Seq: " << "2\x4d\n";
std::cout << "2M in escape Seq [modver]: " << "2\t\x4d\n";
return 0;
}
Exercise 2.9: Explain the following definitions. For those that are illegal, explain what’s wrong and how to correct it.
(a) std::cin >> int input_value; //illegal, value for initialization must be defined
fix: int input_value = 0; std::cin >> input_value;
(b) int i = { 3.14 }; //illegal, list initialization does not allow narrowing conversation
fix: float I = {3.14};
(c) double salary = wage = 9999.99; //illegal, wage wasn't defined earlier so that it can't be used as a value for initialization.
fix: double salary = 9999.99, wage = 9999.99;
(d) int i = 3.14; //legal, but the the value of i will be truncated to 3.
fix: float i = 3.14
Exercise 2.10: What are the initial values, if any, of each of the following variables?
std::string global_str;
int global_int;
int main()
{
int local_int;
std::string local_str;
}
global_str: empty string
global_int: 0
local_int:uninitialized
std::string local_str: empty string
Exercise 2.11: Explain whether each of the following is a declaration or a definition.
extern int ix = 1024; //definition, value ix has been initialized.
int uy; //definition, memory is allocated for the varible
extern int iz; //declaration, extern keyword lead the value to be declared but not defined.
Exercise 2.12: Which, if any, of the following names are invalid?
(a) int double = 3.14; //invalid, double is a reserved keyword
(b) int _; //valid
(c) int catch-22; //invalid, "-" is not a valid character for naming variable.
(d) int 1_or_2 = 1; //invalid, variable name can't start with numbers.
(e) double Double = 3.14; //valid
Exercise 2.13: What is the value of j in the following program?
int i = 42;
int main()
{
int i = 100;
int j = i;
}
j
will be 100
, because it is initialized by the local variable i
.
Exercise 2.14: Is the following program legal? If so, what values are printed?
int i = 100, sum = 0;
for (int i = 0; i != 10; ++i)
sum += i;
std::cout << i << " " << sum << std::endl;
it is legal. However, the variable i
in scope of for
statement is different from the global variable i
,so the global i
doesn't control the for loop. Also, because global variable sum
was used in for loop, so for loop affects the value of sum
.100
, 45
。
Exercise 2.15: Which of the following definitions, if any, are invalid? Why?
(a) int ival = 1.01; //valid, an int deifinition
(b) int &rval1 = 1.01; //invalid, reference must bound to an object
(c) int &rval2 = ival; //valid
(d) int &rval3; //invalid, reference must bound to an initialized object
Exercise 2.16: Which, if any, of the following assignments are invalid? If they are valid, explain what they do.
int i = 0, &r1 = i; double d = 0, &r2 = d;
(a) r2 = 3.14159; //valid
(b) r2 = r1; //valid. it is actually assigned i to the d, type conversion happened.
(c) i = r2; //valid, double to int
(d) r1 = d;//valid, double to int
Exercise 2.17: What does the following code print?
int i, &ri = i;
i = 5; ri = 10;
std::cout << i << " " << ri << std::endl;
Since ri
is refering to i
, assign 10
to ri
is equal to assign 10
to i
, which changes the value of i
from 5
to 10
. Thus the final result is 10
, 10
。
Exercise 2.18: Write code to change the value of a pointer. Write code to change the value to which the pointer points.
#include <iostream>
int main(int argc, char const *argv[])
{
int i = 100;
int j = 200;
//change the value of the pointer
int *p1 = &i;
p1 = &j;
std::cout <<"i: " << i << " j: " << j << " p1 points to: " << *p1 << std::endl;
//change the value to which the pointer points
//p1 is now pointing the j
*p1 = 300;
std::cout <<"i: " << i << " j: " << j << " p1 points to: " << *p1 << std::endl;
return 0;
}
Exercise 2.19: Explain the key differences between pointers and references.
Exercise 2.20: What does the following program do?
int i = 42; //initialized a int type variable i
int *p1 = &i; //initiazed a pointer that point to the address of variable i
*p1 = *p1 * *p1; //pi dereferenced. This line is equal to i = i * i. the 1st、2rd、4th * are dereference operator, the 3rd * is doing multiplication. The result will be 42 * 42 = 1764
Exercise 2.21: Explain each of the following definitions. Indicate whether any are illegal and, if so, why.
int i = 0;
(a) double* dp = &i; //illegal, the type of the pointer must be identical to type of which object it points to.
(b) int *ip = i; //illegal, initializer must be an address(an int* value)
(c) int *p = &i; //legal
Exercise 2.22: Assuming p is a pointer to int, explain the following code:
if (p) // if p is a null pointer , the condition is false, otherwise the condition is true.
if (*p) // if the object which p points to has value 0, the condition is false, otherwise the condition is true.
Exercise 2.23: Given a pointer p, can you determine whether p points to a valid object? If so, how? If not, why not?
We can't determine whether a pointer points to a valid object.
There is no way to distinguish a valid address from an invalid one formed from the bits that happen to be in the memory in which the pointer was allocated.
Exercise 2.24: Why is the initialization of p legal but that of lp illegal?
int i = 42; void *p = &i; long *lp = &i;
By definition, a void type pointer can point to any type of variable. The limitation on a void type pointer is we can't use it to edit the content of the object to which the pointer points since editing requires a certain type of object. Thus, p is legal. However, pointer initialization requires the type pointer, and the type of initializer must identical. Initializing a long-type pointer with an int-type object is not allowed.
Exercise 2.25: Determine the types and values of each of the following variables.
(a) int* ip, i, &r = i; //ip is an pointer. i is an interger variable, r is a reference refer to i.
(b) int i, *ip = 0; // i is an int variable. ip is a pointer that can point to an int object, but now it is set to be a null pointer.
(c) int* ip, ip2; // ip is an pointer points to the a int variable. ip2 is an int variable.
Exercise 2.26: Which of the following are legal? For those that are illegal, explain why.
(a) const int buf; //illegal, const variable must initialized
(b) int cnt = 0; //legal
(c) const int sz = cnt; //legal
(d) ++cnt; ++sz; // ++sz is illegal, sz is a const int variable that can't be modified
Exercise 2.27: Which of the following initializations are legal? Explain why.
(a) int i = -1, &r = 0;
//illegal, reference r must bind to an initialized object
(b) int *const p2 = &i2;
//legal, initializing a const pointer with address of an int object
(c) const int i = -1, &r = 0;
//legal, reference to const can be initialized with literal
(d) const int *const p3 = &i2;
//legal, initializing a const pointer with address of an int object. future editing of i2 is not allowed through this pointer.
(e) const int *p1 = &i2;
//legal, editing of i2 is not allowed through pointer p1
(f) const int &const r2;
//illegal. there is no const reference since reference is not an object. besides, reference initialization requires a certain initialized object.
(g) const int i2 = i, &r = i;
//legal, i will be converted to aconst int to fit the r.
Exercise 2.28: Explain the following definitions. Identify any that are illegal.
(a) int i, *const cp; //illegal, const pointer must be initialized.
(b) int *p1, *const p2; //illegal, const pointer must be initialized.
(c) const int ic, &r = ic; //illegal, a non-const reference can't be bound to an const object
(d) const int *const p3; //illegal, const pointer must be initialized.
(e) const int *p; //legal pointer to int const
Exercise 2.29: Uing the variables in the previous exercise, which of the following assignments are legal? Explain why.
(a) i = ic; // legal, const int to int
(b) p1 = p3; // illegal //p3 is a pointer not can't be changed and can't help with the modification. p1 can either modify or change the pointing location
(c) p1 = ⁣ // illegal, ic is const int, p1 is pointer to non-const
(d) p3 = ⁣ // illegal, p3 can't be changed
(e) p2 = p1; // illegal, p2 can't be changed
(f) ic = *p3; // illegal, ic can't be changed
Exercise 2.30: For each of the following declarations indicate whether the object being declared has top-level or low-level const.
const int v2 = 0; int v1 = v2;
int *p1 = &v1, &r1 = v1;
const int *p2 = &v2, *const p3 = &i, &r2 = v2;
//v2 is top-level const
//p2 is lower-level const, p3 is top-level + lower-level const, r2 is lower-level const.
Exercise 2.31: Given the declarations in the previous exercise determine whether the following assignments are legal. Explain how the top-level or low-level const applies in each case.
r1 = v2; //legal, r1 is non-const, v2 is top-level const. copy v2 to r1 will ignore the top-level const
p1 = p2; //illegal, p1 is non-const, p2 is low-level const.
p2 = p1; //legal, p2 is low-const, p1 is non-const, however, can be convert to low-const
p1 = p3; //illegal, p3 has low-level const part that can't be copied to a non-const object
p2 = p3; //legal, both p2 and p3 has low-level const parts. top-level part in p3 is ignored during the copy.
Exercise 2.32: Is the following code legal or not? If not, how might you make it legal?
int null = 0, *p = null;
I suppose the coder just wants to get a null pointer. Since a null pointer initialization is only allowed to use literal, giving an int variable that is equal to 0 to initialize the pointer is invalid. Two different ways to fix this:
int *p = nullptr;
int *p = 0;
Exercise 2.33: Using the variable definitions from this section, determine what happens in each of these assignments:
a = 42; //ok, a is an int
b = 42; //ok, a is an int
c = 42; //ok, a is an int
d = 42; //error, d is an pointer to int
e = 42; //error, e is an pointer to const int
g = 42; //error, g is already bound to ci. however, reference like g can be initialized by literal.
Write a program containing the variables and assignments from the previous exercise. Print the variables before and after the assignments to check whether your predictions in the previous exercise were correct. If not, study the examples until you can convince yourself you know what led you to the wrong conclusion.
#include <iostream>
int main(int argc, char const *argv[])
{
int i = 0, &r = i;
const int ci = i, &cr = ci;
auto a = r; // a is an int
std::cout << a << std::endl;
a = 42;
std::cout << a << std::endl;
auto b = ci; // b is an int, top-level const ignored
std::cout << b << std::endl;
b = 42;
std::cout << b << std::endl;
auto c = cr; // c is an int, top-level const ignored
std::cout << c << std::endl;
c = 42;
std::cout << c << std::endl;
auto d = &i; // d is int*
std::cout << *d << std::endl;
*d = 42; //a fix
std::cout << *d << std::endl;
auto e = &ci; // e is pointer to const int
std::cout << *e << std::endl; //ci can't be modified
auto &g = ci; // g is an reference to const
std::cout << g << std::endl; // ci can't be modified
return 0;
}
>Exercise 2.35: Determine the types deduced in each of the following definitions. Once you’ve figured out the types, write a program to see whether you were correct.
<code cpp>
/*deduction*/
const int i = 42;
auto j = i; // j is an int
const auto &k = i; //k is an reference that refers to const int i
auto *p = &i; //p is an pointer points to const int i
const auto j2 = i, &k2 = i; //j2 is an const int, k2 is an reference to const
#include <iostream>
#include <typeinfo>
int main(int argc, char const *argv[])
{
const int i = 42;
auto j = i;
const auto &k = i;
auto *p = &i;
const auto j2 = i, &k2 =i;
std::cout << "j is: " << typeid(j).name() << std::endl;
std::cout << "k is: " << typeid(k).name() << std::endl;
std::cout << "p is: " << typeid(p).name() << std::endl;
std::cout << "j2 is: " << typeid(j2).name() << std::endl;
std::cout << "k2 is: " << typeid(k2).name() << std::endl;
return 0;
}
Exercise 2.36: In the following code, determine the type of each variable and the value each variable has when the code finishes:
int a = 3, b = 4;
decltype(a) c = a; // c is an int, 3
decltype((b)) d = a; //d is an reference to int a, 3
++c;
++d;
++c
yields c+1 = 4
; ++d
yields a+1 = 4
.
Exercise 2.37: Assignment is an example of an expression that yields a reference type. The type is a reference to the type of the left-hand operand. That is, if i is an int, then the type of the expression i = x is int&. Using that knowledge, determine the type and value of each variable in this code:
int a = 3, b = 4;
decltype(a) c = a; // c is int with value 3.
decltype(a = b) d = a; // d is an int& refers to a, with value 3.
Exercise 2.38: Describe the differences in type deduction between decltype and auto. Give an example of an expression where auto and decltype will deduce the same type and an example where they will deduce differing types.
auto
requires initialization, decltype don't(except for the reference)auto
will return the type based on evaluation, but decltype will return it based on the declaration. So we saw a lot of types convert happen during the auto type deduction, but the decltype always returns what the expression declared.
int i = 0;
int &r = i;
const int ci = 0;
/*same type*/
auto a1 = i; //return int
decltype(i) a2 = i; //return int
/*different types*/
auto b1 = ci; //return int
decltype(ci) b2 = ci; //return const int
/*another differents types*/
auto r1 = r; //return int
decltype(r) r2 = r; //return int&
Exercise 2.39: Compile the following program to see what happens when you forget the semicolon after a class definition. Remember the message for future reference.
struct Foo { /* empty */ } // Note: no semicolon
int main()
{
return 0;
}
output:
ex_2_39.cc:3:2: error: expected ‘;’ after struct definition
}
^
;
Exercise 2.40: Write your own version of the Sales_data class.
struct Sales_data {
std::string bookNo = "";
unsigned int unitSold = 0;
double soldPrice = 0.0;
double revenue = 0.0;
};
Exercise 2.41: Use your Sales_data class to rewrite the exercises in § 1.5.1 (p. 22), § 1.5.2 (p. 24), and § 1.6 (p. 25). For now, you should define your Sales_data class in the same file as your main function.
/*
* 1.5.1-ex.1.20
* Reading a set of book sales and print
*/
#include <iostream>
#include <string>
struct Sales_data {
std::string bookNo = "";
unsigned int unitSold = 0;
double soldPrice = 0.0;
};
int main(int argc, char const *argv[])
{
Sales_data book;
while(std::cin >> book.bookNo >> book.unitSold >> book.soldPrice) {
std::cout << "ISBN: " << book.bookNo
<< " Copies Sold: " << book.unitSold
<< " Revenue: " << book.unitSold * book.soldPrice
<< " Unit Prine: " << book.soldPrice
<< std::endl;
}
return 0;
}
/*
* 1.5.1-ex.1.21
* Reading two sales that have same ISBN and produce there sum
*/
#include <iostream>
#include <string>
struct Sales_data {
std::string bookNo = "";
unsigned int unitSold = 0;
double soldPrice = 0.0;
double revenue = 0.0;
};
int main(int argc, char const *argv[])
{
Sales_data book1, book2;
std::cin >> book1.bookNo >> book1.unitSold >> book1.soldPrice;
std::cin >> book2.bookNo >> book2.unitSold >> book2.soldPrice;
book1.revenue = book1.unitSold * book1.soldPrice;
book2.revenue = book2.unitSold * book2.soldPrice;
if(book1.bookNo == book2.bookNo) {
std::cout <<"ISBN: " << book1.bookNo
<<" Total copies sold: " << book1.unitSold + book2.unitSold
<<" Revenue: " << book1.revenue + book2.revenue
<<" Average price: " << (book1.revenue + book2.revenue) / (book1.unitSold + book2.unitSold)
<<std::endl;
return 0;
} else {
std::cerr << "ISBN must be the same! " << std::endl;
return -1;
}
return 0;
}
/*
* 1.5.1-ex.1.22 to 1.6-ex.1.25
* Reading a set of trans, if they refer to the same ISBN,
* then give the sum of then and count the total copies sold
*/
#include <iostream>
#include <string>
struct Sales_data {
std::string bookNo = "";
unsigned int unitSold = 0;
double soldPrice = 0.0;
double revenue = 0.0;
};
int main(int argc, char const *argv[])
{
Sales_data book;
if(std::cin >> book.bookNo >> book.unitSold >> book.soldPrice) {
book.revenue = book.unitSold * book.soldPrice;
Sales_data curBook;
while(std::cin >> curBook.bookNo >> curBook.unitSold >> curBook.soldPrice) {
if(curBook.bookNo == book.bookNo) {
curBook.revenue = curBook.unitSold * curBook.soldPrice;
book.unitSold += curBook.unitSold;
book.revenue += curBook.revenue;
}
else {
double aver_price = book.revenue / book.unitSold;
std::cout << "ISBN: " << book.bookNo
<< " Copies sold: " << book.unitSold
<< " Revenue: " << book.revenue
<< " Average price: " << aver_price
<< std::endl;
//reset the book to the current book
book.bookNo = curBook.bookNo;
book.unitSold = curBook.unitSold;
book.soldPrice = curBook.soldPrice;
book.revenue = curBook.unitSold * curBook.soldPrice;
}
}
double aver_price = book.revenue / book.unitSold;
std::cout << "ISBN: " << book.bookNo
<< " Copies sold: " << book.unitSold
<< " Revenue: " << book.revenue
<< " Average price: " << aver_price
<< std::endl;
return 0;
}
else {
std::cerr << "No data?" << std::endl;
return -1;
}
return 0;
}
Exercise 2.42: Write your own version of the Sales_data.h header and use it to rewrite the exercise from § 2.6.2 (p. 76).
/* header Sales_data.h */
#ifndef SALES_DATA_H
#define SALES_DATA_H
#include <string>
struct Sales_data {
std::string bookNo = "";
unsigned int unitSold = 0;
double soldPrice = 0.0;
double revenue = 0.0;
};
#endif
/*
* 1.5.1-ex.1.20
* Reading a set of book sales and print
*/
#include <iostream>
#include <string>
#include "Sales_data.h"
main(int argc, char const *argv[])
{
Sales_data book;
while(std::cin >> book.bookNo >> book.unitSold >> book.soldPrice) {
std::cout << "ISBN: " << book.bookNo
<< " Copies Sold: " << book.unitSold
<< " Revenue: " << book.unitSold * book.soldPrice
<< " Unit Prine: " << book.soldPrice
<< std::endl;
}
return 0;
}
/*
* 1.5.1-ex.1.21
* Reading two sales that have same ISBN and produce there sum
*/
#include <iostream>
#include <string>
#include "Sales_data.h"
int main(int argc, char const *argv[])
{
Sales_data book1, book2;
std::cin >> book1.bookNo >> book1.unitSold >> book1.soldPrice;
std::cin >> book2.bookNo >> book2.unitSold >> book2.soldPrice;
book1.revenue = book1.unitSold * book1.soldPrice;
book2.revenue = book2.unitSold * book2.soldPrice;
if(book1.bookNo == book2.bookNo) {
std::cout <<"ISBN: " << book1.bookNo
<<" Total copies sold: " << book1.unitSold + book2.unitSold
<<" Revenue: " << book1.revenue + book2.revenue
<<" Average price: " << (book1.revenue + book2.revenue) / (book1.unitSold + book2.unitSold)
<<std::endl;
return 0;
} else {
std::cerr << "ISBN must be the same! " << std::endl;
return -1;
}
return 0;
}
/*
* 1.5.1-ex.1.22 to 1.6-ex.1.25
* Reading a set of trans, if they refer to the same ISBN,
* then give the sum of them and count the total copies sold
*/
#include <iostream>
#include <string>
#include "Sales_data.h"
int main(int argc, char const *argv[])
{
Sales_data book;
if(std::cin >> book.bookNo >> book.unitSold >> book.soldPrice) {
book.revenue = book.unitSold * book.soldPrice;
Sales_data curBook;
while(std::cin >> curBook.bookNo >> curBook.unitSold >> curBook.soldPrice) {
if(curBook.bookNo == book.bookNo) {
curBook.revenue = curBook.unitSold * curBook.soldPrice;
book.unitSold += curBook.unitSold;
book.revenue += curBook.revenue;
}
else {
double aver_price = book.revenue / book.unitSold;
std::cout << "ISBN: " << book.bookNo
<< " Copies sold: " << book.unitSold
<< " Revenue: " << book.revenue
<< " Average price: " << aver_price
<< std::endl;
//reset the book to the current book
book.bookNo = curBook.bookNo;
book.unitSold = curBook.unitSold;
book.soldPrice = curBook.soldPrice;
book.revenue = curBook.unitSold * curBook.soldPrice;
}
}
double aver_price = book.revenue / book.unitSold;
std::cout << "ISBN: " << book.bookNo
<< " Copies sold: " << book.unitSold
<< " Revenue: " << book.revenue
<< " Average price: " << aver_price
<< std::endl;
return 0;
}
else {
std::cerr << "No data?" << std::endl;
return -1;
}
return 0;
}