C++ Primer, Chapter 2: Answers for the First Half
Notes and sample answers for early Chapter 2 exercises on primitive types, literals, initialization, declarations, references, pointers, and scope.
Contents12 sections
C++ Primer Chapter 2 — first-half answers
These are my working answers while studying C++ systematically. They cover the first part of Chapter 2; the remaining exercises were still in progress when this note was written.
Exercises 2.1 and 2.2
Integer types differ in size and therefore in the range of values they can represent. Unsigned types use every bit for the magnitude, while signed types also represent negative values. float and double differ mainly in precision; double is generally the better default for values such as interest rates, principal, and payments.
Exercises 2.3 and 2.4
#include <iostream>
int main() {
unsigned u = 10, u2 = 42;
std::cout << u2 - u << std::endl; // 32
std::cout << u - u2 << std::endl; // wraps modulo the unsigned range
int i = 10, i2 = 42;
std::cout << i2 - i << std::endl; // 32
std::cout << i - i2 << std::endl; // -32
std::cout << i - u << std::endl; // 0
std::cout << u - i << std::endl; // 0
}
Exercises 2.5–2.7: literal types
// (a) 'a', L'a', "a", L"a"
// char, wide character, string, wide string
// (b) 10, 10u, 10L, 10uL, 012, 0xC
// int, unsigned int, long, unsigned long, octal, hexadecimal
// (c) 3.14, 3.14f, 3.14L
// double, float, long double
// (d) 10, 10u, 10., 10e-2
// int, unsigned int, double, double
int month = 09; is invalid because a leading zero denotes an octal integer and octal digits stop at 7.
// "Who goes with F\145rhus?\012"
// \145 is the octal code for 'e'; \012 is a newline.
// 3.14e1L -> long double value 31.4
// 1024f -> float value 1024.0
// 3.14L -> long double value 3.14
Exercise 2.8
#include <iostream>
int main() {
std::cout << "2M\n" << std::endl;
std::cout << "2\tM\n" << std::endl;
}
Exercises 2.9 and 2.10: initialization
#include <iostream>
#include <string>
std::string global_str;
int global_int;
int main() {
// std::cin >> int input_value; // invalid: declare the variable first
// int i = {3.14}; // invalid narrowing list initialization
// double salary = wage = 9999.99; // invalid if wage is not declared
int i = 3.14; // valid; i becomes 3
int local_int; // uninitialized
std::string local_str; // empty string
std::cout << global_str << '\n'
<< global_int << '\n'
<< local_int << '\n'
<< local_str << std::endl;
}
Global variables receive default initialization; a local built-in type such as local_int does not.
Exercise 2.11: declarations and definitions
extern int ix = 1024; // definition; an initializer makes it a definition
int iy; // definition
extern int iz; // declaration only
An initialized extern definition belongs at namespace scope, not inside a function.
Exercise 2.12: identifiers
// int double = 3.14; // invalid: keyword
int _; // valid inside a function
// int and = 2; // invalid: alternative operator token
// int catch-22; // invalid: hyphen
// int 1_or_2 = 1; // invalid: starts with a digit
double Double = 3.14; // valid: C++ is case-sensitive
Names reserved to the implementation—such as those containing double underscores or beginning with an underscore followed by an uppercase letter—should be avoided.
Exercises 2.13 and 2.14: scope
#include <iostream>
int i = 42;
int main() {
int i = 100;
int j = i; // uses the local i, so j is 100
std::cout << j << std::endl;
}
#include <iostream>
int main() {
int i = 100, sum = 0;
for (int i = 0; i != 10; ++i) {
sum += i;
}
std::cout << i << ' ' << sum << std::endl;
}
The loop variable is separate from the outer i; the final output is 100 45.
Exercises 2.15–2.17: references
int ival = 1.01; // valid conversion to int
// int &rval1 = 1.01; // invalid: non-const int reference cannot bind here
int &rval2 = ival;
// int &rval3; // invalid: a reference must be initialized
int i = 0, &r1 = i;
double d = 0, &r2 = d;
r2 = 3.14159; // assigns d
r2 = r1; // assigns i to d
i = r2; // converts d to int
r1 = d; // assigns d to i through r1
int i;
int &ri = i;
i = 5;
ri = 10;
// i and ri both now observe the value 10.
Exercises 2.18–2.24: pointers
int i = 42;
int *p = &i;
*p = 52; // changes i
p = nullptr; // p no longer points to i
A pointer can later point to a different object. A reference remains bound to the object used at initialization.
int i = 42;
int *p1 = &i;
*p1 = *p1 * *p1; // i becomes 1764
Pointer types must match the pointed-to object:
int i = 0;
// double *dp = &i; // invalid type
// int *ip = i; // invalid: i is a value, not an address
int *p = &i; // valid
Testing p checks whether the pointer is null. Testing *p checks the pointed-to value and is only valid after establishing that p is non-null.
int i = 42;
void *p = &i; // a void pointer can hold an object address
// long *lp = &i; // invalid type mismatch
Exercise 2.25: reading declarations
int *ip, i, &r = i;
// ip: pointer to int; i: int; r: reference to i
int i2, *p2 = nullptr;
// i2: int; p2: null pointer to int
int *ip2, ip3;
// ip2: pointer to int; ip3: int
The key is to read each declarator separately: * and & belong to the variable being declared, not globally to the base type.
Related posts
Discussion / approved
Comments
No comments yet.