5-x 第五章总结与测验

章节回顾

常量constant是指在程序执行过程中不可改变的值。C++支持两种常量类型:命名常量和字面量常量。

命名常量named constant是与标识符关联的常量值。字面量常量Literal constant是不与标识符关联的常量值。

值不可变的变量称为常量变量constant variable。可通过const关键字使变量成为常量。常量变量必须初始化。在值传递或值返回时应避免使用const。

类型限定符type qualifier是修饰类型行为的关键词。截至C++23标准,C++仅支持constvolatile作为类型限定符。

常量表达式constant expression是指可在编译时求值的表达式。非常量表达式有时称为运行时表达式runtime expression

编译时常量compile-time constant是指其值在编译时已知的常量。运行时常量runtime constant是指其初始化值需在运行时才确定的常量。

constexpr 变量必须是编译时常量,并用常量表达式初始化。函数参数不能是 constexpr。

字面量Literals是直接嵌入代码的值。字面量具有类型,可通过字面量后缀改变其默认类型。

魔数magic number是指含义模糊或可能需要后期修改的字面量(通常为数字)。请勿在代码中使用魔数,应改用符号常量。

日常生活中我们使用十进制decimal计数,该系统包含10个数字。计算机采用二进制binary,仅有2个数字。C++还支持八进制octal(基数8)和十六进制hexadecimal(基数16)。这些都属于数制范例numeral systems,即用于表示数字的符号集合(数字)。

字符串string是由连续字符组成的集合,用于表示文本(如名称、单词和句子)。字符串常量始终用双引号括起。C++中的字符串常量采用C风格字符串,其类型特殊且难以操作。

std::string提供了处理文本字符串的便捷安全方式。该类定义在头文件中,但初始化(或赋值)及复制成本较高。

std::string_view提供对现有字符串(C 风格字符串常量、std::string 或 char 数组)的只读访问,且无需复制。若 std::string_view 指向已被销毁的字符串,则称为悬空dangling视图。当 std::string 被修改时,所有指向该字符串的视图均失效invalidated。使用无效视图(除非重新验证其有效性)将导致未定义行为。

由于C风格字符串常量在整个程序中存在,因此将std::string_view设置为C风格字符串常量是可行的,甚至可将此类视图作为函数返回值。

子字符串substring是指现有字符串中连续的字符序列。


测验时间

问题 #1

为什么命名常量通常比字面常量更优?

显示解答

在程序中使用字面常量(又称魔数)会降低程序的可读性与可维护性。符号常量(命名常量)有助于记录数字的实际含义,且在声明处修改符号常量即可同步更新其所有使用位置的值。

为什么 const/constexpr 变量通常比 #define 符号常量更优?

显示解答

#define 常量不会在调试器中显示,且更容易发生命名冲突。

问题 #2

找出以下代码中的3个问题:

#include <cstdint> // for std::uint8_t
#include <iostream>

int main()
{
  std::cout << "How old are you?\n";

  std::uint8_t age{};
  std::cin >> age;

  std::cout << "Allowed to drive a car in Texas: ";

  if (age >= 16)
      std::cout << "Yes";
  else
      std::cout << "No";

  std::cout << '.\n';

  return 0;
}

期望输出示例:

How old are you?
6
Allowed to drive a car in Texas: No
How old are you?
19
Allowed to drive a car in Texas: Yes

image
image

显示答案

  1. 在第8行,年龄被定义为std::uint8_t类型。由于std::uint8_t通常被定义为char类型,在此处使用它会导致程序行为如同输入输出字符值而非数值。例如,若用户输入年龄为“18”,程序仅会提取字符'1'。由于1的ASCII值为49,系统将判定用户年龄为49岁。由于年龄值无需特定最小整数宽度,应使用常规int类型存储。同时可移除#include
  2. 第13行使用了魔数16。尽管上下文能明确其含义,但更推荐使用常量表达式constexpr变量赋值16。
  3. 第18行中的'.\n'是多字符字面量,会输出错误值。应改为双引号表示(“.\n”)。

问题 #3

std::string 与 std::string_view 的主要区别是什么?

使用 std::string_view 时可能出现什么问题?

显示答案

std::string 提供可修改的字符串。其初始化和复制成本较高。

std::string_view 提供对其他位置字符串的只读视图。其初始化和复制成本较低。当被查看的字符串在 std::string_view 销毁前被销毁时,std::string_view 可能存在危险。

问题 #4

编写一个程序,询问两个人的姓名和年龄,然后输出哪个人的年龄更大。

以下是程序运行的一次示例输出:

Enter the name of person #1: John Bacon
Enter the age of John Bacon: 37
Enter the name of person #2: David Jenkins
Enter the age of David Jenkins: 44
David Jenkins (age 44) is older than John Bacon (age 37).

image

显示提示

提示:使用 std::getline() 输入该人的姓名。

显示解答

#include <iostream>
#include <string>
#include <string_view>

std::string getName(int num)
{
    std::cout << "Enter the name of person #" << num << ": ";
    std::string name{};
    std::getline(std::cin >> std::ws, name); // read a full line of text into name

    return name;
}

int getAge(std::string_view sv)
{
    std::cout << "Enter the age of " << sv << ": ";
    int age{};
    std::cin >> age;

    return age;
}

void printOlder(std::string_view name1, int age1, std::string_view name2, int age2)
{
    if (age1 > age2)
        std::cout << name1 << " (age " << age1 <<") is older than " << name2 << " (age " << age2 <<").\n";
    else
        std::cout << name2 << " (age " << age2 <<") is older than " << name1 << " (age " << age1 <<").\n";
}

int main()
{
    const std::string name1{ getName(1) };
    const int age1 { getAge(name1) };

    const std::string name2{ getName(2) };
    const int age2 { getAge(name2) };

    printOlder(name1, age1, name2, age2);

    return 0;
}

问题 #5

在上题的解答中,为什么 main 中的变量 age1 不能是 constexpr?

显示解答

constexpr 变量需要常量表达式初始化器,而 getAge() 的调用在常量表达式中是不被允许的。因此,我们只能将该变量声明为 const。
posted @ 2026-02-17 16:59  游翔  阅读(0)  评论(0)    收藏  举报