33 分钟带你速通C语言
不信请看阅读时长
注意:本篇教程处于 Beta 测试阶段。如果你遇到了看不懂、不会做、有错别字、程序报错等问题,请在评论区留言,作者不一定保证会及时赶来谢罪,但一定会认真做修订,谢谢各位的贡献。
感慨于大学本科课程教的 C 语言普遍拉完了,故抽出摸鱼时间撰写本文,供各位同学自救使用。
本篇教程不讲废话,不扯定义,实用第一,以实例代替习题,帮你快速掌握 C 语言编程的基本操作,也可以用作知识速查表。
必备品:一台电脑。对英语和数学水平零要求。
安装 IDE
IDE 的正式中文名叫做“集成开发环境”。在很久以前,IDE 还没有发明的时候,人们编写程序需要用到很多工具软件,包括编辑器(编写代码)、编译器(把源代码编译成可执行的程序)、调试器(给程序排除问题)等等。IDE 则是集各类工具于一体的编程工具箱,可以很方便地编写、运行程序。
小熊猫 C++ 是一款非常适合新手入门的 IDE,开源免费,简单好用。安装步骤如下:
在电脑上打开右边的链接,转到官方下载页面:https://royqh.net/redpandacpp/download/
从“蓝奏云网盘”和“百度云网盘”两种下载方式中二选一,记住链接右边的分享码,然后点击对应的蓝色链接。输入对应的分享码后就能看到文件列表。

下载完成后运行,即可打开安装包。按照指引,一直点击“下一步”即可完成安装。
初次启动小熊猫 C++ 时,会弹出配置向导。可以在深色和浅色外观之中根据自己的喜好进行选择,记得将默认语言切换成 C,然后点击右下角的确定。

把小熊猫的编辑器想象成一个带有多标签页功能的记事本,可以对源代码文件进行打开、编辑、保存等操作。点击上排按钮中的三角形(或者按下键盘上的 F11)可以编译并运行正在编辑的源代码。

编写第一个程序
把下面这段代码复制粘贴到小熊猫的编辑区中(点击代码块右上角的剪贴板符号可以一键复制),点击上排按钮中的保存键(或者按下键盘快捷键 Ctrl+S),在电脑中选择一个喜欢的地方保存你的代码,然后按下运行键(或者键盘上的 F11)。
1
2
3
4
5
6
7
#include <stdio.h>
int main()
{
printf("Hello World!");
return 0;
}
可以看到弹出了一个黑底白字的窗口(由于笔者的电脑配置问题,实际看到的效果与图片中略有出入),第一行写着 “Hello World!”。这个黑底白字的窗口就是你创造的程序。切换到这个窗口,按下键盘上任意的按键可以关闭这个程序。当然也可以直接点击窗口右上角的按钮来关闭。
你可以随意更改第 6 行双引号中的文本(甚至是输入中文),再次点击运行即可看到不一样的效果。
本文之后出现的代码,都请务必复制粘贴到 IDE 中,自己动手运行一遍。最好还能根据自己的理解,对代码做一些修改后再尝试运行,即使编译出错或者运行结果不对也不要紧,尝试修复错误并了解出错的原因,可以很大程度地提升编程水平。
如果你想打印多行文本的话,在需要换行的地方写 \n 即可。其中 \ 是反斜杠符号,在键盘上的位置通常是回车(Enter)键上面一个。
1
2
3
4
5
6
7
#include <stdio.h>
int main()
{
printf("学了C语言\n手机电脑单片机\n全都能编程\n最有用");
return 0;
}
C 语言程序的基本结构
第 1 行 #include 开头的代码是编译器预处理命令。目前你不需要了解它有什么用,只需要会默写(或者复制粘贴)即可。
第 3 行的 int main() 定义了程序的主函数。听不懂没关系,你只需要知道任何程序都从这一行开始执行代码。
第 5 行的 printf 用处是往屏幕上打印文本。注意这个语句的用法,先有一层圆括号 (),然后再用双引号 "" 把要打印的内容包起来。C 语言代码中所有的符号都是英文输入法下打出的符号,请不要在敲代码时使用中文输入法。
第 6 行的 return 0 表示这里是程序的终点。在主函数中,程序一碰到 return 就会立即结束,忽略之后的任何代码。例如下面的这个程序只会打印 123,而不会打印 123456:
1
2
3
4
5
6
7
8
9
#include <stdio.h>
int main()
{
printf("123");
return 0;
printf("456");
return 0;
}
所有会被执行的语句都需要有一个分号 ; 结尾。单独的一个分号被视为一个什么都不做的空语句。例如下面的这个程序什么也不会输出:
1
2
3
4
5
6
7
#include <stdio.h>
int main()
{
;
return 0;
}
代码格式与注释
在 C 语言代码中,任何换行和多余的空格都是可以忽略的。仅有两个例外:
- 编译器预处理命令(如
#include <...>)必须单独占一行。 - 双引号(
"")包裹的字符串不能换行,而且内部的空格会被认为是字符串的一部分。
例如,下面的这个程序与一开始打印 “Hello World!” 的程序效果一模一样:
1
2
#include <stdio.h>
int main(){printf("Hello World!");return 0;}
甚至也可以写成这样:
1
2
3
4
5
6
7
8
#include <stdio.h>
int
main ( )
{
printf ( "Hello World!" ) ;
return 0 ;
}
只不过,排版整齐的代码更方便阅读,有利于编程的人理解程序的逻辑。小熊猫 C++ 支持一键排版代码,只需点击菜单栏中的 代码 -> 对代码重新排版,或者按下键盘快捷键 Ctrl+Shift+A。
注释是指给人提供参考,而在编译时会被忽略的文本。C 语言支持两种注释,分别为单行和多行:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
/*
这是一块多行注释
你可以尝试把这个程序全文复制粘贴到编辑区,然后运行
*/
int main()
{
// 这是一行单行注释
printf("Hello everyone!"); // 跟大家打个招呼!
printf("//"); // 字符串内的符号都是字符串的一部分,不会触发注释
// printf("I prefer not to speak my name.");
// 小提示:给一行代码加上注释,可以方便地将其“禁用”。需要恢复时,去掉注释符号即可。
return 0;
}
C 语言程序的编译流程
如果你足够细心,会发现小熊猫 C++ 在保存代码时会保存一个拓展名为 .c 的文件。这个文件就是你用 C 语言写出来的源程序。
你可以尝试用 Windows 自带的记事本打开这个 .c 文件。事实是记事本也可以毫无障碍地浏览、编辑 C 语言源代码,因为用 C 语言写出来的代码本质上就是一堆文本,和 .txt 文本文档是一样的,唯一的区别在于文件拓展名的不同。
问题来了,既然 C 语言代码本质上就是一堆文本,那么电脑要怎么运行这个程序呢?此时需要另一种软件的帮助:编译器。
编译器可以读取你写的 C 语言代码,然后将其转换为电脑可以运行的 .exe 程序。这个转换的过程叫做编译。
编译的具体过程十分复杂,此处只是简单的介绍。小熊猫 C++ 自带了一份编译器,在小熊猫 C++ 中点击“运行”时,小熊猫 C++ 会自动编译你的程序并运行它,因此十分方便快捷。
变量
计算机中一切信息都是以数字的形式储存的。变量就是储存数字的容器。
C 语言中的变量有很多类型,类似于酒店中的客房分为单间、标间等不同房型,可以满足储存各式各样数字的需求。
可以用这样的语句创建变量:<类型> <变量名>;
键盘上的等于号 = 被叫做赋值符号,用途是把符号右边的数字储存到符号左边的变量中。请看例子:
1
2
3
4
5
6
7
8
#include <stdio.h>
int main()
{
int a; // 创建(或者说定义)了一个类型为int、名称为a的变量
a=5; // 变量a现在储存了一个整数5
return 0;
}
但是这个程序什么也没有输出。我们可以用 printf 来输出变量的值:
1
2
3
4
5
6
7
8
9
#include <stdio.h>
int main()
{
int a;
a=5;
printf("The value of a is %d",a);
return 0;
}
请注意这里 printf 与之前格式的不同。双引号中出现了一个东西 %d,它叫做格式占位符,意思就是说“a 的值应该在这里出现”。
双引号中格式占位符的数量,应该与括号内所附带变量的数量一致。占位符与变量是依次一一对应的。例如下面的程序会输出 3.1.2:
1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
int main()
{
int a,b,c; // 这样可以一次性定义多个相同类型的变量
a=1;
b=2;
c=3;
printf("%d.%d.%d",c,a,b);
return 0;
}
C 语言中常见的变量类型如下:
| 类型 | 格式占位符 | 用途 |
|---|---|---|
| int | %d | 储存整数,支持的范围为 $-2^{31}$ ~ $2^{31}-1$(约为 21 亿) |
| long long | %lld | 储存整数,支持的范围为 $-2^{63}$ ~ $2^{63}-1$(约为 922 亿亿) |
| short | %hd | 储存整数,支持的范围为 $-2^{15}$ ~ $2^{15}-1$(约为 3 万) |
| char | %c | 储存一个字符,C 语言中字符的本质是一个取值范围为 0 ~ 255 的整数,详见下文 |
| float | %f | 储存实数 |
| double | %lf | 储存实数,支持比 float 更好的精确度 |
注意,不同类型的变量,在输入和输出时使用的格式占位符是不同的。如果在编程时没有注意匹配,尽管编译时不会报错,但在运行时会出现无法预料的错误。
变量的命名
并不是任何文本都可以成为变量的名称。变量名需要满足以下要求:
- 只能是大小写英文字母(
a-z,A-Z)、数字(0-9)和下划线(_)的组合。 - 第一个字符不能是数字。
- 不能和 C 语言关键字相同。
以下是一些合规和无效的变量名的实例:
1
2
Good: a, xyz, Num, my_var, var123, _i, NAME
Bad: 123num(第一个字符不能是数字), 变量一号(不能是中文), $x(出现了无效的符号), int(与关键字相同)
从键盘输入
使用 scanf 可以实现从键盘向程序输入信息。它的用法与 printf 很像,请看例子:
1
2
3
4
5
6
7
8
9
#include <stdio.h>
int main()
{
int x;
scanf("%d",&x);
printf("你输入的数是%d",x);
return 0;
}
运行程序,发现弹出的窗口里什么也没有,实际上程序正在等待用户输入数字。随便输入一个整数(比如 123),然后按下回车(Enter)键,即可完成输入,程序继续运行。
scanf 的用法与 printf 很像,括号内都是一个带有格式占位符的字符串,后带若干个变量。不同之处在于,scanf 中的变量名前面需要带有 & 符号,它的真实名字是取地址符。目前你无需理解它的用途,只需要记住在 scanf 中需要用到即可。
修改 scanf 中的格式字符串,可以让程序在读入文本时智能提取其中的数字。例如以下程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
int main()
{
int a,b,c;
scanf("a=%d b=%d c=%d",&a,&b,&c);
printf("a is %d, b is %d and c is %d",a,b,c);
return 0;
}
/*
输入: a=4 b=88 c=205
输出: a is 4, b is 88 and c is 205
*/
scanf 会尽力从输入的文本中匹配格式字符串,直到匹配完毕,或者遇到其“不能理解的字符”后停止。如果在匹配停止时,有格式占位符还没有被处理,那么对应变量的值将不会发生任何改变。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
int main()
{
int a=0; // 可以在定义变量时快捷地为其指定一个初始值
scanf("a=%d",&a);
printf("a is %d",a);
return 0;
}
/*
输入: a=666
输出: a is 666
输入: a=1.23
输出: a is 1
输入: 123
输出: a is 0
输入: man! what is a?
输出: a is 0
*/
数学运算
可以用变量、数字和运算符组成表达式,从而进行运算。
1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
int main()
{
int a,b,c;
a=16;
b=9;
c=a+b; // 计算a+b的值(16+9=25),然后把这个值赋值给变量c
printf("%d",c);
return 0;
}
C 语言支持加减乘除四则运算,其中乘号使用星号 * 代替,除号使用正斜杠 / 代替。注意,整数除以整数,得到的结果是商的整数部分,只有在除号任意一边是实数时,得到的结果才是实数。
用小括号包裹表达式的一部分,可以在运算时将其视作一个整体。运算顺序遵守“先乘除,后加减,从左往右依次算”。多层括号请全部使用小括号,而不要使用中括号(方括号 [])或大括号(花括号 {}),它们有别的用处。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
int main()
{
int res;
res=16/5+3*(2-1)+(2*(4-2));
printf("%d",res);
return 0;
}
/*
解析:
16/5 + 3*(2-1) + (2 * (4-2))
= 3 + 3*1 + 2*2
= 3+3+4
= 10
*/
C 语言还有一种特殊的运算符 %,用来求整数除法中的余数。求余运算的优先级与乘法、除法相同。
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
int main()
{
int res;
res=32%6;
printf("%d\n",res); // 2
res=15%2;
printf("%d\n",res); // 1
res=20%5;
printf("%d\n",res); // 0
return 0;
}
结合上文所讲的输入,我们可以编写一些简单的计算器。例如以下程序可以把摄氏度转化为华氏度:
1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
int main()
{
double cel,fah;
scanf("%lf",&cel);
fah=cel*9/5+32;
printf("%lf",fah);
return 0;
}
printf 输出的值不一定是单个独立的变量,也可以直接输出表达式的值。例如以下程序可以计算两个整数的和:
1
2
3
4
5
6
7
8
9
#include <stdio.h>
int main()
{
int a,b;
scanf("%d %d",&a,&b);
printf("%d",a+b);
return 0;
}
赋值符号左边的变量也可以出现在赋值符号右边的表达式中,程序会先用变量原本的值计算右边表达式的值,然后用结果覆盖左边变量所储存的值。
1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
int main()
{
int a;
scanf("%d",&a);
a=a*2+1;
printf("%d",a);
return 0;
}
C 语言支持一些快捷的赋值语句,用来改变变量所储存的值。请看例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
int main()
{
int a=2;
a+=5; // a的新值比原来大5,等效于a=a+5
a-=3; // a的新值比原来小3,等效于a=a-3
a*=2; // a储存的数值翻倍,等效于a=a*2
a/=3; // a的新值是原来的值除以3的商,等效于a=a/3
a++; // a储存的数值增加1,等效于a=a+1或a+=1
a--; // a储存的数值减少1,等效于a=a-1或a-=1
// 某些地方还能看到++a和--a,它们分别与a++和a--类似,目前不需要知道两者的区别
printf("%d",a);
return 0;
}
条件语句
if-else 语句可以用来选择性地执行一段语句。格式如下:
1
2
3
4
5
6
7
8
9
10
11
12
if(条件)
{
语句1;
语句2;
...
}
else
{
语句a;
语句b;
...
}
如果程序准备执行 if 处的语句,会先判断括号内的条件是否成立。如果成立,那么会执行上方大括号内的 语句1;语句2;...,并跳过下方大括号的内容;反之,如果不成立,那么会跳过上方大括号的内容,执行下方大括号的 语句a;语句b;...。
特别地,如果在条件不成立时不打算做任何事,那么可以省略 else 和与其连接的大括号,变成如下格式:
1
2
3
4
5
6
if(条件)
{
语句1;
语句2;
...
}
如果在准备执行 if 处语句时条件成立,那么程序会执行大括号内的 语句1;语句2;...;否则跳过大括号内的语句,继续往后执行。
如果大括号内的语句只有一条,那么大括号可以省略,变成如下格式:
1
2
if(条件) 语句1;
else 语句2;
C 语言支持判断数字之间的大小和相等关系,符号和对应含义如下:
| 符号 | 含义 |
|---|---|
== | 相等 |
!= | 不相等 |
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
注意判断相等需要使用两个等号,单个等号的含义是赋值。
例如下面的程序,如果用户输入的整数小于等于 18,那么会输出两句话,否则只输出一句话。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
int main()
{
int age;
printf("What is your age? :");
scanf("%d",&age);
if(age<=18)
{
printf("You are young!\n");
}
printf("Hello there!");
return 0;
}
条件判断中也可以使用表达式。例如下面的程序会判断用户输入的整数是奇数还是偶数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
int main()
{
int x;
scanf("%d",&x);
if(x%2==1)
{
printf("odd");
}
else
{
printf("even");
}
return 0;
}
逻辑运算符
逻辑与和逻辑或运算符可以以特定关系连接两个条件,相当于中文里的“并且”和“或者”,其中 || 表示“或者”,&& 表示“并且”。| 可以通过按住键盘上的 Shift 同时按下反斜杠键(\,一般在 Enter 回车键上方)打出来。
&& 的优先级高于 ||。逻辑运算符构成的表达式中也可以使用括号,将表达式的一部分视为一个整体。
例如下面这个程序可以判断用户输入的年龄是否合理(处于 0 到 100 之间):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
int main()
{
int age;
printf("What is your age? :");
scanf("%d",&age);
if(age<0 || age>100)
{
printf("Not a valid age!");
}
else
{
printf("OK!");
}
return 0;
}
再例如,下面这个程序可以用来判断闰年(四年一闰,百年不闰,四百年又闰):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
int main()
{
int year;
scanf("%d",&year);
if (year%400==0 || (year%4==0 && year%100!=0))
{
printf("leap year");
}
else
{
printf("common year");
}
return 0;
}
逻辑运算的顺序是从左到右,并且遵循“偷懒原则”(科学地说,这两种运算符具有“短路效应”)。如果 || 左侧的条件已经被判定为“成立”,那么程序就不会判断其右边的条件,直接认为表达式是“成立”;如果 && 左侧的条件已经被判定为“不成立”,那么程序就不会判断其右边的条件,直接认为表达式是“不成立”。
以上面判断闰年的程序为例:
- 如果
year是 400 的整数倍(year%400==0成立),那么这一年一定是闰年,程序不会再继续计算||右边的式子,直接输出 “leap year”; - 否则,程序计算右边括号里的表达式。
- 如果
year不是 4 的整数倍(year%4==0不成立),那么这一年一定不是闰年,程序不会再继续计算&&右边的式子,直接输出 “common year”; - 否则,程序继续计算
&&右边的式子。year已经是 4 的整数倍,如果它还不是 100 的整数倍(year%100!=0成立),那么这一年就是闰年,整个表达式被判定为“成立”,程序输出 “leap year”;- 否则,这一年不是闰年,整个表达式被判定为“不成立”,程序输出 “common year”。
- 如果
还有一种逻辑运算符 !,名为逻辑非,可以用来反转条件,即“成立”变为“不成立”,“不成立”变为“成立”。例如,!(year%100==0) 和 year%100!=0 是两个等效的表达式。
注意 != 中的感叹号,它是“不等号”的一部分,而不是逻辑运算符。逻辑非运算符必须要放置在一个完整的表达式之前。
数值与逻辑的关系
除了上述的逻辑表达式以外,一般的变量甚至是数学表达式也可以当作逻辑条件使用。把一个数字当成一个逻辑条件处理时,数值为 0 则认为这个条件不成立,除此之外的任何值都认为这个条件成立。
例如,这一段代码永远会输出 “Yes”:
1
2
3
4
5
6
7
8
if(616)
{
printf("Yes");
}
else
{
printf("No");
}
再例如,下面这一段代码,大括号内的语句永远都不会被执行:
1
2
3
4
if(0 && 1)
{
printf("我是棍木");
}
再例如,上文提到的判断奇偶数的程序,可以简化如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
int main()
{
int x;
scanf("%d",&x);
if(x%2)
{
printf("odd");
}
else
{
printf("even");
}
return 0;
}
反过来,逻辑表达式的结果也可以被当成是一个数字,可以储存在变量中,甚至是参与数学表达式的运算。把逻辑条件当作数字处理时,“成立”的条件数值上等于 1,“不成立”的条件数值上等于 0。
例如,下面这个程序会输出 3,因为第 7 行的 4 个条件里只有 3 个是成立的:
1
2
3
4
5
6
7
8
9
#include <stdio.h>
int main()
{
int x;
x = (3>2) + (4!=5) + (999==999) + (50>80);
printf("%d",x);
return 0;
}
循环语句
循环语句可以用来反复多次地执行一段代码。C 语言的循环语句分为 while 和 for。
while 循环
while 语句的格式如下:
1
2
3
4
5
6
while(条件)
{
语句1;
语句2;
...
}
当程序准备执行 while 处的语句时,会先判断括号内的条件是否成立。如果条件成立,那么会执行大括号内的 语句1;语句2;...,之后再次回到条件判断,如果条件成立,那么再执行大括号内的语句,如此循环。如果某一次条件判断为不成立,那么大括号内的语句就会被跳过,程序继续往后执行。
与 if-else 类似,如果大括号内只有一条语句,那么大括号可以省略,变成如下格式:
1
while(条件) 语句1;
例如,下面的程序可以输出 1 到 10 的整数:
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
int main()
{
int i=1;
while(i<=10)
{
printf("%d ",i);
i++;
}
printf("\n");
return 0;
}
再例如,下面的程序会无休无止地输出 “ha”:
1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
int main()
{
while(233)
{
printf("ha ");
}
return 0;
}
while 循环还有一种变种 do-while,格式如下:
1
2
3
4
5
6
do
{
语句1;
语句2;
...
} while(条件);
程序在运行 do 处的语句时,无论如何都会先运行一遍大括号内部的 语句1;语句2;...,之后判断括号内的条件是否成立,如果成立则再次运行大括号内的语句,如此循环,直到某一次括号内的条件判断为不成立,程序再继续往后执行。
例如,下面的程序会从大到小输出 32 到 2 的所有 2 的幂次:
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
int main()
{
int i=32;
do
{
printf("%d ",i);
i/=2;
} while(i>1);
printf("\n");
return 0;
}
for 循环
for 语句的格式如下:
1
2
3
4
5
6
for(语句1;条件2;语句3)
{
语句a;
语句b;
...
}
程序在运行 for 语句时,首先会执行一次括号内的 语句1;然后判断 条件2 是否成立,如果成立,就执行大括号内的 语句a;语句b;...,并且再执行一次括号内的 语句3,之后又回到条件判断,如此循环。如果某一次 条件2 被判定为不成立,那么循环结束,程序继续往后执行。
注意括号内的 语句3 结尾不能带有分号。
与 if-else 类似,如果大括号内只有一条语句,那么大括号可以省略,变成如下格式:
1
for(语句1;条件2;语句3) 语句a;
for 语句的功能也可以用 while 语句实现,如下:
1
2
3
4
5
6
7
8
9
语句1;
while(条件2)
{
语句a;
语句b;
...
语句3;
}
for 循环最常用的场景是“将某一段代码循环执行特定的次数”。例如,下面的程序可以输出 1 到 10 的整数:
1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
int main()
{
for(int i=1;i<=10;i++)
{
printf("%d ",i);
}
printf("\n");
return 0;
}
这个程序的功能与上文用 while 实现的程序效果是完全一致的,但是更加清晰易读,只需要看 for 所在的行就能知道变量 i 的取值“从哪开始,到哪结束”。
再例如,下面的程序可以输入一个整数,然后输出这么多个“Hi”:
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
printf("Hi ");
}
printf("\n");
return 0;
}
for 的 语句1、条件2 和 语句3 都是可以选择省略的。如果 语句1 或 语句3 被省略,那么相应时刻就不会执行对应的语句;如果 条件2 被省略,那么每一次条件判断都默认会当作“成立”。特别地,如果三者都被省略,那么就会创造一个永远不会结束的循环。例如下面的程序会无休无止地输出 “ha”:
1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
int main()
{
for(;;)
{
printf("ha ");
}
return 0;
}
for 也有一些比较巧妙的用法。比如下面这个程序可以输入一个正整数,然后把这个整数按数位逆序输出(比如输入 123,输出 321):
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
int main()
{
int n;
scanf("%d",&n);
for(;n>0;n/=10)
{
printf("%d",n%10);
}
printf("\n");
return 0;
}
循环控制语句
循环控制语句可以在循环语句中间控制循环的运行。在 while 和 for 循环中都可以使用循环控制语句。一般来说,循环控制语句都需要配合 if-else 语句使用。
continue; 语句可以提前跳到下一轮循环。例如,下面的程序可以输出 1 到 50 中不是 7 的倍数的数:
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
int main()
{
for(int i=1;i<=50;i++)
{
if(i%7==0) continue;
printf("%d ",i);
}
printf("\n");
return 0;
}
在 for 循环中使用 continue; 时,小括号内的 语句3 依然会被执行。
break; 语句可以提前强行终止循环,让程序继续执行循环之后的语句。例如,下面的程序会输出 10 次“Hi”:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
int main()
{
int i=0;
while(616)
{
printf("Hi ");
i++;
if(i==10) break;
}
printf("\n");
return 0;
}
在 for 循环中使用 break; 时,小括号内的 语句3 最后不会被执行。
语句的嵌套
上文所讲的 if-else、while 和 for 语句都可以相互之间进行任意嵌套,从而实现更复杂的逻辑。
在### 循环控制语句一节中已经出现了 for 或 while 循环内嵌套 if 语句。我们来看看多层 if-else 语句的嵌套。
例如,下面的程序可以根据输入的分数来给出评级。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
int main()
{
int s;
scanf("%d",&s);
if(s>=100)
{
printf("S");
}
else
{
if(s>=80)
{
printf("A");
}
else
{
if(s>=60)
{
printf("B");
}
else
{
printf("C");
}
}
}
return 0;
}
- 如果输入的分数大于等于 100,那么输出 S,后面的所有语句都被跳过,程序结束。
- 否则,进入第二层判断。如果分数大于等于 80,那么输出 A,跳过第二层
else,程序结束。 - 否则,进入第三层判断。如果分数大于等于 60,那么输出 B,跳过第三层
else,程序结束。 - 否则,进入第三层的
else,输出 C,程序结束。
注意,完整的一套 if-else 整体可以被视为一条语句。因此,上面的程序可以简化如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
int main()
{
int s;
scanf("%d", &s);
if (s >= 100)
printf("S");
else
if (s >= 80)
printf("A");
else
if (s >= 60)
printf("B");
else
printf("C");
return 0;
}
多层嵌套中 if 与 else 的对应关系通常难以直观地看出。if 与 else 配对的规则可以类比于左括号与右括号的配对。事实上,因为 if-else 的配对实在难以通过肉眼判定,在实际开发中,有很多人会有意识地避免 else 的使用。
现在再来看循环的嵌套。例如下面的程序会输出 54 个 “Ciallo~ (^.^)”,分为 9 行,每行 6 个:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
int main()
{
for(int i=1;i<=9;i++)
{
for(int j=1;j<=6;j++)
{
printf("Ciallo~ (^.^) ");
}
printf("\n");
}
return 0;
}
- 最外层由变量 i 控制的循环会执行 9 次。每一次循环会执行如下操作:
- 进入内层的一个循环,由变量 j 控制,执行 6 次,每次都输出一个
Ciallo~ (^.^); - 内层循环结束后,输出一个换行符号
\n。
- 进入内层的一个循环,由变量 j 控制,执行 6 次,每次都输出一个
在嵌套的循环内使用循环控制语句时,只对目前最内层的循环生效。例如,以下程序会输出 10 到 99 中个位数不是 3、6、9 的整数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
int main()
{
for(int i=1;i<=9;i++)
{
for(int j=1;j<=9;j++)
{
if(j%3==0) continue;
printf("%d ",i*10+j);
}
}
return 0;
}
更多学习资料
- cppreference.net - 权威 C/C++ 参考文档网站,相当于 C/C++ 语言的电子词典。另有中文版可供参阅。
- OI Wiki - 为竞赛选手打造的编程语言与算法百科,内容比较硬核。
- 菜鸟教程 - C 语言篇 - 通俗易懂、深入浅出、章节式的系统 C 语言教程。比我写得好多了。
- 洛谷 - “入门与面试”题库 - 一些适合新手熟悉语言特性的练习题。
- 必应国内版 - 有啥不懂记得多找搜索引擎。比百度好用得多得多。
- AI?建议初学者慎用 AI 聊天机器人,因为 AI 写的程序通常不易于理解、修改。
致谢
- 感谢 doublewestie 指出少打了个分号;
- 感谢两位不愿透露姓名的朋友指出部分段落看不懂的问题。
次回予告
本教程可能会有下篇,计划讲解如下内容:
- 函数
- 变量的作用域
- 数组
- 字符和字符串
因为只有摸鱼时间才有动力写这种东西,所以不保证能够在有生之年发布。如果你想早点看到下篇,请和我一起希望 DUT 能够多一些水课(逃

