0中/EN
旧站Article / Cabin ID 11

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.

Published May 18, 2021 Updated Jun 2, 2021 /en/blog/cpp-primer-chapter-two-exercises
ZaunEkko 自制 · pixiv 流行二次元风格 · night
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

0

No comments yet.