一、基础:程序结构与输出

这两章一共 9 道题,全部不需要读入任何数据。程序自己算,自己输出。

这是故意安排的。初学者同时卡两件事的时候,会分不清是谁的错——程序没输出,到底是 printf 的格式串写错了,还是 scanf 没读到?往往调半小时才发现是输入格式不对。这两章把输入拿掉,只留输出,错了就只有一种可能。

把这一页当成热身,但它不是走过场。 你得在这里把三件事变成肌肉记忆:代码骨架怎么敲、输出怎么控制、算术怎么写。第 3 章开始读输入,这三件事就不会再有人提醒你。

1. 你的第一个程序

你要解决的问题只有一个:让屏幕上出现你指定的字。

1.1 四行骨架

所有 C++ 程序都长这个样子。以后你写到几千行,外面这层壳也不变:

#include <bits/stdc++.h>
using namespace std;

int main() {
    printf("Hello, World!\n");
    return 0;
}

很多人第一天就把这四行背下来了,然后一直照着敲,从没想过每行在干什么。我们花三分钟拆开——因为你迟早会遇到它们出问题的时候,那时候不知道哪行在干什么,就只能干瞪眼。

#include <bits/stdc++.h>

#include 的意思是「把另一个文件的内容原样抄到这里」。bits/stdc++.h 是个特殊文件,它把所有标准库一次性全抄进来。

正经的 C++ 教程会教你 #include <iostream>、#include <cmath> 一个个写。竞赛里不这么干——记不住哪个函数在哪个头文件里,多抄一点进来,编译器多干活,你少查一次文档。

这行不是 C++ 标准

bits/stdc++.h 是 GCC 编译器自带的,不在 C++ 标准里,Windows 的 MSVC 上编译不过。

但你不会用 MSVC。OJ 用 GCC,Dev-C++ 用 GCC,你现在能碰到的所有环境都是 GCC。放心用。

using namespace std;

标准库的东西都放在一个叫 std 的命名空间里。不写这一行,你每次都得写 std::printf、std::scanf、std::string。

代价是:如果哪天你自己定义了一个叫 printf 的变量,会和标准库撞名。初学阶段不会撞,写就是了。

int main()

程序从 main 开始执行,花括号里的代码从上到下一条条跑。int 表示这个函数最后要交回一个整数——就是下面的 return 0;。

return 0;

告诉操作系统「程序正常结束」。

严格说现代 C++ 里 main 的 return 0 可以省略,编译器会自动补上。但别省:一是老编译器会警告,二是「函数有返回值就写出来」这个习惯,第 27 章讲函数时你会知道有多重要。

1.2 让它说话:printf

printf 读作 "print-f",意思是「按格式打印」。括号里用一对双引号包住要输出的内容:

printf("Hello, World!\n");

双引号里的这部分叫格式串。格式串里的字符会原样送到屏幕上,只有一种情况例外——反斜杠开头的东西。

\n 是最常用的一个,表示换行:

printf("第一行\n第二行\n");

屏幕上是两行。\n 写在引号里面,看起来是两个字符,编译器会把它们当成一个换行符。

常用的反斜杠写法就下面这几个:

写法 意思 什么时候用
\n 换行 基本每一行输出都要
\t 制表符,约 8 个空格宽 输出要按列对齐时(第 12 章九九乘法表)
\\ 一个反斜杠本身 很少用
\" 一个双引号本身 要输出引号时

C++ 还有一种写法叫 cout

你会看到别人写 cout << "Hello" << endl;,效果和 printf("Hello\n"); 一样。

这本讲义统一用 printf,不用 cout。 为什么?下一章讲输入的时候会说明白——输入输出是配套的,混着用只会给自己找麻烦。现在你只要知道:看见别人的 cout 别慌,它是同一个意思。

第一个程序

现在动手。这题只要求你把上面那四行骨架敲对、把要求的文字原样输出。

敲的时候别复制粘贴。手敲一遍,你会自然记住哪里有分号、哪里有引号。

1.3 输出必须一字不差

接下来四道题的输出要求各不相同——有的要多一行,有的要多个空格,有的要改标点。你必须逐字读题目的输出要求。

这不是出题人为难你。OJ 判断对错的方式是:把你的输出和标准答案逐字符比对。多一个空格、少一个换行、逗号用了全角,都算错。

举个最容易踩的例子:

printf("Hello,World\n");   // 错:逗号是全角
printf("Hello, World\n");   // 对

这两个逗号长得几乎一样,但全角的 , 占两个字节,半角的 , 占一个。编译器不认全角标点,而且报错信息往往指向别的地方,让你找半天。

交之前先把输入法切成英文

新手第一个编译错误里,一半是全角标点。写代码时输入法保持英文,只在写注释和字符串内容时才切中文。

肉眼判断方法:全角逗号 , 比半角逗号 , 明显宽一圈,而且后面会自带半个字的间距。

一模一样的输出

四道题,四个不同的输出要求。每做一题,先读题 → 再写 → 再交,不要凭感觉一口气写完。

如果某一题反复错又不知道错在哪:把格式串末尾的 \n 临时改成 |\n,跑一次。那个竖线会告诉你「你的输出到底到哪儿结束」——是多了一个空格,还是少了一个换行。

第 1 章验收

做完这 5 题,你应该能做到:

  • 不看任何资料,默写出四行骨架
  • 说清楚 #include、using namespace、main、return 0 各自的作用
  • 一眼看出自己的逗号是全角还是半角

做不到就回去再看一遍 1.1,别往下走。

2. 让程序自己算

第 1 章你只能输出写死的字。这一章开始,让程序算出结果再输出。

2.1 %d:在格式串里留个坑

第 1 章的格式串里全是固定的字。现在要在中间塞一个「算出来的数」,得先留个坑:

printf("%d\n", 3 + 5);

屏幕上是 8。

%d 是占位符,意思是「这里要放一个整数」。逗号后面那个 3 + 5 会被算出来,填进坑里。

这个顺序不能反,也不能漏:

printf("%d\n", 3 + 5);      // 8        对
printf(3 + 5, "%d\n");      // 错        参数顺序反了
printf("3 + 5\n");          // 3 + 5     输出了这几个字符本身,没有算

%d 的 d 是 decimal(十进制)。以后还会遇到 %f(小数)、%c(字符)、%s(字符串)——它们都是坑,区别只是往坑里放什么类型的东西。类型不放对,输出就是一串乱码。

多个数就多个坑,按顺序填:

printf("%d %d\n", 3, 5);          // 3 5
printf("%d+%d=%d\n", 3, 5, 8);    // 3+5=8

坑的个数必须和后面的参数个数对上。 少一个,printf 会去读一个不存在的位置,输出随机值;多一个,多的被忽略。这两种情况编译器都不报错,只能你自己数。

printf 最大的特点:它不检查你

printf 是 C 语言留下来的老函数,编译器只知道「第一个参数是个字符串」,不知道后面该有几个参数、该是什么类型。

所以 printf("%d\n") 少写参数、printf("%f\n", 3) 类型不对,都能编译通过,然后在运行时给你一个莫名其妙的结果。

以后遇到「输出是乱码 / 是随机数 / 是 0」,第一个怀疑对象就是格式串和参数对不上。

2.2 五个算术运算符

运算符 含义 例子 结果
+ 加 3 + 5 8
- 减 3 - 5 -2
* 乘 3 * 5 15
/ 除 7 / 2 3,不是 3.5
% 取余(余数) 7 % 2 1

* 和 % 是初学者最容易写错的两个:数学里写 ×,代码里必须写 *;% 在数学里是百分号,在这里是「除完剩多少」。

2.3 整数除法会吃掉小数

7 / 2 的结果是 3,不是 3.5。这条规则会让很多人第一次栽跟头。

原因是:7 和 2 都是整数(int),C++ 规定整数除整数,结果还是整数,小数部分直接扔掉。不是四舍五入,是直接砍掉。

printf("%d\n", 7 / 2);       // 3
printf("%d\n", 1 / 2);       // 0   ← 不是 0.5,是 0
printf("%d\n", 7 % 2);       // 1   ← 余数

想要小数结果,至少让一边变成小数。这时候不能再用 %d 了,得换成 %f:

printf("%f\n", 7.0 / 2);     // 3.500000
printf("%.2f\n", 7.0 / 2);   // 3.50

%f 是给小数留的坑。它默认输出 6 位小数,%.2f 表示保留 2 位——这个写法第 5 章专门讲,现在知道有这么回事就行。

7.0 是浮点数,浮点数除以整数,结果就是浮点数。现在先记住一句话:看到除法,先问自己「我要不要小数」。

还有一条更隐蔽的:% 只能用在整数上。7.5 % 2 编译不过。

2.4 优先级和括号

C++ 的运算顺序跟数学一样:先乘除取余,后加减。2 + 3 * 4 是 14。

拿不准就加括号。括号不要钱,猜错要命:

printf("%d\n", (2 + 3) * 4);   // 20
printf("%d\n", 2 + 3 * 4);     // 14

写表达式时,如果你自己都要想两秒钟才能确定顺序,那就加括号。三个月后回来看这段代码的人是你自己。

纯计算的输出

这四道题不需要读入,题目直接给出算式,你算出结果输出即可。先用纸算一遍,再写代码验证——如果你算的和程序算的不一样,那就是你对某条规则理解错了,这个差值比题目本身有价值。

卡住的话,对着 2.2 那张表一行一行核:是不是把 % 当成百分号了,是不是两个整数相除却指望有小数。

第 2 章验收

  • 能说清 7 / 2 和 7.0 / 2 为什么不一样
  • 知道 % 两侧必须是整数
  • 遇到算不准的表达式,第一反应是加括号而不是凭记忆

这一页的 9 道题全部通过,就可以进第 3 章了。第 3 章开始读输入——那才是真正的分水岭。

延伸阅读

服务器上有一整套 OI-Wiki(621 页),是给竞赛选手写的参考手册。下面几页跟这一页相关,但不是每一页都该现在看——标了「现在跳过」的,等以后再说。

  • 可以先看:C++ 语法基础 —— 同一个骨架的 printf 版本。比赛里两种写法都能见到,你现在用哪个都行
  • 可以先看:Hello, World! —— 第一份代码逐行拆解,还讲了 Dev-C++ 和 MinGW 怎么装
  • 可以先看:运算 —— 运算符优先级完整表。拿不准 a + b * c 先算谁的时候回来查

看不懂是正常的,不是你的问题

OI-Wiki 默认读者已经会写程序、目标是打 NOI。你现在需要的那部分,讲义里已经写了; wiki 是用来「以后查得更深」的,不是用来补课的。

© HiJudge · 内容采用 CC BY-NC-SA 4.0 许可协议            此页面修订于: 2026-11-01 03:44:09

results matching ""

    No results matching ""