← C++ 教材目录(共 13 章)

第 1 章 先让程序跑起来

red wenzi · 2026-09-15 · 编程语言 · C++ · 📖 预计阅读 24 分钟 · 共 7 道练习
🎯 本章你会学到:写下第一个程序、看懂编译过程、学会读报错。建议边读边敲代码,每节的练习先自己做,再展开答案对照。

本章目标:跑通你的第一个 C++ 程序;看懂一个程序是怎么从源码变成可执行文件的;学会读报错、用编译选项。

1.1 第一个程序

先别管理论,把下面这个程序敲出来、编译、跑起来。这是所有 C++ 学习的起点。

心智模型:C++ 为什么看着这么杂

很多人学 C++ 觉得内容杂,是因为它同时背着三个时代:带类的 C(对象与继承)、模板(泛型)、现代特性(lambda、智能指针)。这三层会一直混在一起出现,你现在只需要知道它们存在,以后每学一个语法点,问一句“它是为哪一层服务的”,就不会乱。C++ 的设计哲学叫“零开销抽象”:你写的高级写法,运行时不该比手写底层代码慢。

⚠️ 易错点 不用一次性搞懂所有特性。先学会写能跑的程序,特性逐个遇到再逐个学。

从源码到可执行文件的四步

一个 .cpp 文件变成能运行的程序,要经过四步:① 预处理:处理 #include、#define,本质是纯文本复制;② 编译:把每个 .cpp 单独翻译成机器码,得到 .o 目标文件;③ 汇编:转成机器码(通常和编译一起完成);④ 链接:把所有目标文件和用到的库拼成可执行文件,这时才检查“某个函数到底有没有被实现”。

⚠️ 易错点 由此产生 C++ 特有的两类错误:编译错误(语法、类型)和链接错误(函数没实现)。记住口诀:编译期看声明,链接期看定义。

第一个程序逐行拆解

下面每一行的作用:#include <iostream> 引入标准输入输出库(尖括号表示去系统目录找);int main() 是程序入口,返回类型必须是 int(和 Java 的 void main 不同);std::cout << 表示把右边的数据送进输出流;<< 是运算符重载(同一个符号在整数运算里是左移,在这里叫插入运算符);std::endl 是换行并刷新缓冲区;return 0 表示正常结束(省略也等价于 return 0)。

示例代码
#include <iostream>          // 标准输入输出流
int main() {                 // 程序入口,返回类型必须是 int
    std::cout << "Hello, C++" << std::endl;
    return 0;                // 正常结束
}
运行结果
Hello, C++
⚠️ 易错点 字符串必须用双引号;cout << a << b 不会自动加空格和换行,都要自己写。

编译命令:每天都会用的一条

手敲完代码后,在终端(PowerShell)里执行下面的命令编译并运行。这些开关的意思:-std=c++17 用 C++17 标准;-Wall -Wextra 打开大部分警告(C++ 里警告非常重要,很多错误只以警告形式出现);-o hello 指定输出文件名。

示例代码
g++ -std=c++17 -Wall -Wextra -o hello hello.cpp
.\hello.exe        # Windows PowerShell 运行
⚠️ 易错点 -Wall -Wextra 一定要一直开着。C++ 里不少“看起来能跑其实有问题”的代码只会在编译时给你一个 warning。
hello.cpp预处理#include 展开编译生成汇编汇编生成 .o链接拼成可执行编译期只管声明;链接期才检查定义——"函数没实现"属于链接错误
图 1:一个 .cpp 到可执行文件要经过的四步,以及每一步的报错类型

✍️ 本节练习

1.1.1必做输出我的名片

写一个程序,第一行输出你的名字,第二行输出“开始学 C++ 啦”,每行都要换行。

输入 无

输出 两行,第一行是你的名字,第二行是“开始学 C++ 啦”。

样例输入
(本题无输入)
样例输出
小明
开始学 C++ 啦

💡 提示 用 std::cout,结尾用 '\n' 换行。

✅ 查看参考答案与解析
#include <iostream>
int main() {
    std::cout << "小明" << '\n';
    std::cout << "开始学 C++ 啦\n";
    return 0;
}

解析 字符串必须用双引号包住;'\n' 是换行字符。

1.1.2挑战链式输出

用一条 std::cout 语句输出三个数 1、2、3,要求数字之间用一个空格隔开,最后换行。

输入 无

输出 1 2 3(空格分隔,末尾换行)。

样例输入
(本题无输入)
样例输出
1 2 3

💡 提示 cout 不会自动加空格,需要自己写 ' '。

✅ 查看参考答案与解析
#include <iostream>
int main() {
    std::cout << 1 << ' ' << 2 << ' ' << 3 << '\n';
    return 0;
}

解析 cout << a << b 输出的是紧挨着的两个值,分隔符要自己加。

1.2 输入输出

输入输出是新手最容易卡住的地方,因为报错往往看不出原因。这一节把最常见的写法直接记住。

cout:流,不是拼接

std::cout 是一个“输出流”对象,<< 把数据一件一件送进去。注意它不会自动加空格、不会自动换行——cout << 1 << 2 输出的是 12,不是 1 2。分隔符要自己写。

⚠️ 易错点 endl 会刷新缓冲区,大量输出时比 '\n' 慢很多,算法题里统一用 '\n'。

cin:读入的两种方式

std::cin >> a >> b 会跳过所有空白字符(空格、换行、制表)再读入;而 std::getline 读一整行(读到换行为止),适合含空格的文字。两者混用有一个经典坑:cin >> n 之后缓冲区里还留着一个换行符,直接 getline 会读到一个空串。

示例代码
#include <iostream>
#include <string>
int main() {
    int n;
    std::string line;
    std::cin >> n;
    std::cin.ignore();              // 吃掉 n 后面遗留的换行符
    std::getline(std::cin, line);   // 读一整行(可含空格)
    std::cout << n << '\n' << line << '\n';
    return 0;
}
运行结果
5
hello world
⚠️ 易错点 cin >> x 读字符串遇到空白就停,所以“hello world”只会读到 hello;要整行必须 getline。

输入加速两行(算法题必备)

写算法题时在 main 开头加上这两行,cin/cout 会快很多:std::ios::sync_with_stdio(false) 关闭与 C 标准库的同步;std::cin.tie(nullptr) 解除 cin 与 cout 的绑定。另外格式化输出用 <iomanip> 的 fixed 和 setprecision。

示例代码
#include <iomanip>
#include <iostream>
int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    double pi = 3.14159265;
    std::cout << std::fixed << std::setprecision(3) << pi << '\n';
    return 0;
}
运行结果
3.142
⚠️ 易错点 printf 和 cin 不要混用,混用后输出顺序可能错乱。

✍️ 本节练习

1.2.1必做两数之和

读入两个整数 a 和 b,输出 a + b 的结果。

输入 一行两个整数 a b。

输出 一个整数,a 与 b 的和。

样例输入
3 5
样例输出
8

💡 提示 std::cin >> a >> b; 一次读两个数。

✅ 查看参考答案与解析
#include <iostream>
int main() {
    int a, b;
    std::cin >> a >> b;
    std::cout << a + b << '\n';
    return 0;
}

解析 cin 会自动跳过空格和换行,所以一行读两个数很简单。

1.2.2挑战带空格的整行

先读入一个整数 n,再读入一整行文字(可能含空格),把 n 和这行文字各输出一行。注意:n 后面紧跟的换行不能影响 getline。

输入 第一行整数 n;第二行一行文字(可含空格)。

输出 第一行输出 n,第二行原样输出文字。

样例输入
5
hello world
样例输出
5
hello world

💡 提示 cin >> n 会把换行符留在缓冲区,需要 std::cin.ignore() 吃掉它再 getline。

✅ 查看参考答案与解析
#include <iostream>
#include <string>
int main() {
    int n;
    std::string line;
    std::cin >> n;
    std::cin.ignore();              // 吃掉 n 后面遗留的换行符
    std::getline(std::cin, line);   // 读一整行
    std::cout << n << '\n';
    std::cout << line << '\n';
    return 0;
}

解析 这是 cin 和 getline 混用的经典坑:>> 不消耗换行,ignore() 专门用来丢弃它。

1.3 编译报错与调试习惯

报错信息是学习 C++ 最直接的老师。学会读报错,能省下你 80% 的卡壳时间。

读报错的两个习惯

第一,先看第一条错误,不要看最后一条——后面的错误经常是第一条引发的连锁反应。第二,先看文件名和行号,再看描述。编译器提示的位置有时会偏移一行,比如“缺少分号”往往指的是上一行末尾。

⚠️ 易错点 一次修一个错误,改完重新编译。不要一次性改十处,否则不知道哪处修对了哪处改坏了。

警告就是潜在的错误

C++ 里很多错误只以警告形式出现(比如 if (x = 5) 永远为真、变量未初始化)。打开 -Wall -Wextra 后,见到 warning 就修,不要无视。养成“零警告”的习惯,比什么都值。

⚠️ 易错点 区别 warning 和 error:error 编译不过,warning 能编译但大概率有隐患。两者都要处理。

手敲,不要复制粘贴

learncpp 和几乎所有优秀教程都强调:示例代码要亲手敲一遍。手敲会让你熟悉常见错误(漏分号、方向写反、括号不配对),也能让你熟悉各种报错信息长什么样。敲完再试着改改数字、改改逻辑,观察输出变化——改代码比抄代码学得快。

⚠️ 易错点 遇到报错先自己读 3 分钟,想不出来再看答案。直接抄答案 = 没练到。

✍️ 本节练习

1.3.1必做修好这段代码

下面这段代码编译不过(有 3 处错误),请手敲一遍,修复后编译运行,让它输出 Hello, C++。

坏代码(有 3 处错误)
#include <iostream>
int main() {
    std::cout >> "Hello, C++" << std::endl   // 3 处错误
    return 0;
}

输入 无

输出 Hello, C++

样例输入
(本题无输入)
样例输出
Hello, C++

💡 提示 错误藏在:缺头文件、>> 方向、缺分号。

✅ 查看参考答案与解析
#include <iostream>
int main() {
    std::cout << "Hello, C++" << std::endl;
    return 0;
}

解析 三处错误:1) 缺 #include <iostream>;2) << 方向写反成 >>;3) 缺分号。修复后零错误零警告。

1.3.2挑战零警告编译

写一个程序输出 Hello, C++,然后用这条命令编译,要求零警告零错误:g++ -std=c++17 -Wall -Wextra -o hello hello.cpp

输入 无

输出 Hello, C++

样例输入
(本题无输入)
样例输出
Hello, C++

💡 提示 -Wall -Wextra 会打开大部分警告;如果看到 warning 就要修。

✅ 查看参考答案与解析
#include <iostream>
int main() {
    std::cout << "Hello, C++" << '\n';
    return 0;
}

解析 C++ 里很多错误只以警告形式出现,养成零警告编译的习惯。

本章小结

🧩 本章综合练习

这几道题把本章多个知识点串起来,建议合上资料独立完成,再展开答案对照。

1.A综合命令行名片卡:cin / getline / 格式化输出

读入一个整数 n(1~5),再读入 n 行文字(每行可能含空格),按格式输出。这道题把第 1 章的三个坑一次踩全:cin 和 getline 混用要 ignore、换行要自己写、输出格式要严格对齐。

输入 第一行一个整数 n;接下来 n 行,每行一段文字(可含空格)。

输出 第 1 行 n=数字;之后 n 行 line i: 内容(i 从 1 开始)。

样例输入
3
hello world
C++ 新手
第四天
样例输出
n=3
line 1: hello world
line 2: C++ 新手
line 3: 第四天

💡 提示 cin >> n 之后缓冲区还留着换行,必须 std::cin.ignore() 再 getline。

✅ 查看参考答案与解析
#include <iostream>
#include <string>
int main() {
    int n{};
    std::cin >> n;
    std::cin.ignore();                 // 吃掉 n 后面的换行
    std::cout << "n=" << n << '\n';
    for (int i = 1; i <= n; ++i) {
        std::string line;
        std::getline(std::cin, line);  // 读一整行,保留空格
        std::cout << "line " << i << ": " << line << '\n';
    }
    return 0;
}

解析 cin >> 跳过空白、getline 读整行,两者混用必须先 ignore。用 '\n' 而不是 endl,大量输出时更快。

📚 本文概念都在知识大全:

编译与链接 · 编译选项 · 输入输出流 · 头文件