跳至内容
Topos Uranos

摘要

这节课开启本课程的第八个也是最后一个单元,主题是更大的程序。它说明本单元的宗旨:组织、验证和调试那些已经无法装进一个文件、也无法装进脑子里的程序;介绍本单元的三节课以及把它们串起来的线索,这条线索使课程第一课开启的循环得以闭合(规格说明、构建、验证);回顾本单元假定已有的知识,也就是整门课程;提出本单元要解决的问题,即一个单文件程序在测试它所用的数据上运行正常,却对其规格说明边界上的一个错误保持沉默;预先介绍测试与证明的区别;并说明本单元通向何处,包括结课项目和“C++ 程序设计 II”课程。

学习目标

  1. 描述本单元的内容顺序,并说明每节课为后一节课提供了什么。
  2. 借助一个例子,回顾函数声明与定义的区别、规定函数的契约,以及把多个文件变成一个程序的两个阶段(编译与链接)。
  3. 借助一个例子,预先认识用若干用例测试一个程序与证明它对所有容许输入都正确之间的区别。
  4. 认清学完本单元和本课程时应当会做什么,并把它与将在“C++ 程序设计 II”中学习的内容区分开来。

入门测评

在学习本单元之前,先测一测自己的起点是有益的。这项测评不计分:它为学习指引方向。前七道题检查本单元假定已经掌握的内容(声明与定义、前置条件、第 6 单元中一个函数的契约、链接器的消息、二分查找的用例、跟踪表,以及越出向量范围的读取);其后的三道题按课的顺序涉及本单元的核心思想,在这几道题里,“我还不知道”是诚实的回答。每个答案都会解释要点,并指出讲解这一要点的那节课;同样的能力会在总结课中再次测量。

入门测评

开始本单元之前,先测一测你的起点。这是一次简短的自我测评:不计分,结果只保存在你的浏览器中。

  1. 第 1 题来自前面的单元写在 main 之前的 int gcd(int a, int b); 这一行做了什么?

  2. 第 2 题来自前面的单元函数 toBase(n, base) 的前置条件是“n >= 0 且 2 <= base <= 10”。谁必须保证它成立?

  3. 第 3 题来自前面的单元第 6.4 课的函数 binarySearch(values, target) 返回 target 的一个位置,若找不到则返回 values.size()。它的前置条件是什么?

  4. 第 4 题来自前面的单元一个程序编译时没有错误,但在构建可执行文件时出现 undefined reference to `tetrahedral(int)'。是哪个阶段出了问题?

  5. 第 5 题来自前面的单元下面哪一组用例最能考验一个二分查找?

  6. 第 6 题来自前面的单元执行 int a{0}; int b{1}; for (int i{0}; i < 4; ++i) { const int t{a + b}; a = b; b = t; } 之后,a 和 b 各是多少?

  7. 第 7 题来自前面的单元为什么 std::vector<int> v{1, 2}; std::println("{}", v[2]); 在本课程的选项下会停止运行,而只用 -O2 编译、不带检测器时,却可能输出一个任意的数?

  8. 第 8 题一个带有头文件保护的头文件定义了(而不只是声明了)double scale(double x),没有 inline,并且 main.cpp 和 report.cpp 都包含了它。构建程序时会发生什么?

  9. 第 9 题一个函数通过了五百个精心挑选的自动化测试。可以断言什么?

  10. 第 10 题一个断点设在循环内的 total += k; 这一行上,程序第三次停在那里。高亮显示的这一行表示什么?