02.程序设计入门
程序设计入门
本章介绍程序设计的基础知识,重点讲解C语言的核心要素。内容涵盖头文件的作用、变量类型定义、主函数结构及程序语句规范,详细解析输入输出函数scanf
与printf
的格式化用法。通过顺序结构示例(如数值运算、图形输出)和分支结构(条件判断、运算符选择)演示基本逻辑设计,并结合评测系统机制强调代码格式与数据精度的重要性。本章通过典型例题帮助读者掌握程序设计的基本流程、语法规则及调试技巧,为后续算法学习奠定基础。
C语言基本要素
C++ 兼容 C 语言的语法,所以我们不必拘泥于“.c”还是“.cpp”这样的扩展名,新手不用管那么多,无论是写C++风格还是C语言风格,一律在C++的编译环境(.cpp文件)中写就好。
头文件
为了避免从电脑直接看得懂的“01011...”写起,或者从“MOV”、“ADD”这类非常底层的“汇编语言”写起,我们学习一个相对“高级”的语言,即C语言。那些高频使用的“向屏幕输出一些字符”等操作,C语言已经帮我们做好了,我们只需要“告诉”C语言,让C语言去要求电脑做这些事。
“告诉”这个动作需要特定的指令来做,而C语言怎么知道这个指令是做什么的呢?它把不同类型的功能封装在了不同的文件里,所以我们要先让编译器知道,我们要用哪些文件里的功能,就要把这些文件“包含”进来,这就是“include”指令,包含进来的文件叫“头文件”。
现在要包含一个处理“输入输出”这类操作的功能包,这个头文件是“stdio.h”,“std”是标准(standard)的缩写,“io”是“input/output”的缩写。
这样接下来的程序,就可以用“stdio.h”里包含的功能。
包含头文件的语法是:
- 一个
#
符号,表示现在要做一些“特殊”的事情,“#”后面不同的内容对应不同的事情 #
后紧跟“include”,表示我们现在要做的是“包含头文件”这样的事情,至于能做其它什么事情,以后再了解- 头文件用一对
<>
包裹
1 | #include<stdio.h> |
变量
要计算总要有计算的对象,基础的计算对象就是“变量”,可以类比学过的代数,\(x,y,z...\) 这样的代数,然后把数字代进去就能计算不同的数据。
代数有整数有小数,在电脑中还有字符,要让电脑看得懂,能合理的用“0101...”这样的二进制存储,需要告诉它这些代数是什么类型,这就是变量类型。
先了解最常用的:
- int:整数(1,2,-6... 这样的数)
- double: 浮点数(0.4、2.5、5.0...这样有小数部分的精度的数)
变量还有一些其它的类型,以后用到再了解。
主函数
C语言的功能是由“函数”组成的,初高中学过“函数”的概念,是把一些代数丢进去,完成固定的一套计算。比如 \(f(y)=x*2+1\) ,C语言的函数可以延申这个概念,把一些变量(变量可以是 \(x,y,z\) 这样的代数,也可以是更复杂的结构)丢进去,完成固定的程序逻辑。
一个程序运行,总得有一个开端,即从哪里开始,这就是“主函数”的作用,告诉系统从这里开始。
函数可以有返回值(算完之后告诉调用它的地方它算出了个什么类型的东西),也可以没有返回值,但主函数必须有返回值,这是C语言的规则,它用来告诉操作系统这个程序执行的是否成功。
1 | int main() { |
主函数的语法是:
int
:主函数返回值必须是int
,不能是别的main
:表示函数的名字,main
这个名字是专门用于主函数的,不能用其它名字,大小写也不能改()
:一个小括号里写函数的参数,主函数有特定的参数,不过可以省略,初学时可以先不管它的参数{}
:包裹定义主函数要做的事的代码return 0;
:主函数包裹的代码的末尾必须是return 0;
,表示当执行到这里的时候,向调用主函数的“东西”(比如操作系统的某个进程)告知本程序正常结束。
这里“//
”是注释语法,用于写一些帮助自己回忆代码是干什么的注释,对电脑来说这些内容不存在,纯粹是给人看的。
程序语句
C语言中常规程序的语句末尾都要有分号“;
”,表示一个语句的结束(以下语句的含义后文会说明)。
1 | int a, b; |
定义变量
1 | int a, b; |
这里定义两个变量 a
和 b
,他们是
int
类型。
赋值
数学中“=
”表示两个变量/数字相等,而程序中,“=
”表示将右边的值存入左边的变量,变量是一个可以改变的代数。
1 | int a = 3, b; |
输入
让用户在弹出的黑框框中输入想要的数字,再用输入的数字计算,就有了用户交互,这样程序就可以做很多事了。
我们前面已经#include<stdio.h>
,所以可以用输入输出相关的功能了:
1 | int a, b; |
scanf
也是函数,"%d%d", &a, &b
就是传给它的参数。
"%d%d"
表示要输入两个整数,这里%
用于标识输入,%
之后跟的内容具体定义了要输入什么,好让电脑在内存中做好准备,%d
就是要输入一个整数(int
),如果是%lf
就是要输入一个double
。&a
对应前一个%d
,用户在黑框框输入的第一个数就会存入a
这个变量,同理&b
对应第二个%d
,&
是“取地址”符号,&a
表示指向a
的内存地址,这里先不用了解那么多,知道这个格式能输入数据即可。
知识点:
int
的输入输出都用%d
,double
的输入用%lf
,输出用%f
。这时你可能有个疑问,没错确实有个输入是%f
的变量类型float
,但编程之初我们不想讨论过多内容,减轻初学者压力,这里简单说就是float
能表达的精度不够,而现代计算机性能很好,在算法竞赛中我们都用double
就好了。
计算
计算a+b
的和,很直观在代码中写a+b
即可,它得到的结果可以存入一个变量,也可以直接当参数传给函数。
比如 int c = a + b;
就把 a+b
的结果存入
c
。
输出
printf("%d\n", a + b);
就把a+b
的结果作为参数传给 printf
这个函数,这里的%d
和scanf
的%d
含义一样,printf
用于输出,所以就是把a+b
的结果作为整数的格式输出。
\n
表示输出后换一行(在文本编辑器里换一行就是敲一下回车)。
double
的输出用%f
,注意这里没有“l
”。
知识点:输出也会有一些特异的需求,比如输出小数保留多少位,输出整数能不能右对齐前面补空格让总长度固定等,就会有
%.3f
、%02d
等用法,当遇到时,可查资料寻找可用的格式化方法。
一个基本的a+b
1 |
|

例:输出浮点数
读入一个双精度浮点数(double
),分别按输出格式
%f
,%f
保留 5 位小数,%e
和
%g
的形式输出这个数,每次在单独一行上输出。
输入:
1 | 12.3456789 |
输出:
1 | 12.345679 |
1 |
|
评测系统的机制
把代码通过网页(或软件)提交到评测系统,评测系统会在后台编译并执行你的代码,将一系列你看不到的输入数据发送给你的程序,将输出的内容和答案对比,然后告诉你你的代码是否正确。
新手经常会问“我样例都通过了为什么提交了还不对呢”,这里再次强调一下:评测系统会测许多并不会让你看到的其它数据。
在电脑中,空格“”,回车等内容也都是由“字符”来表达的,它们都有编码,传统评测系统对答案的格式有严格的要求,你的程序的输出结果要与评测机上的答案完全一致才能通过。
比如假设评测机上的答案是
1 | 1 |
如果你的程序输出的是 123
或
1 2 3
,就都无法通过。
找一个OJ的a+b
的题,提交你的代码试试把

顺序结构
顺序结构是程序设计中最基本、最简单的控制结构之一。它指的是程序按照代码书写的先后顺序依次执行,从上到下逐条执行语句,没有跳跃、分支或循环。在顺序结构中,每一条语句都会被执行一次,并且严格按照它们在源代码中的排列顺序执行。
上文的例子都是顺序结构,先定义变量,然后输入,然后输出,然后return
……
例:用“*
”输出菱形
用 *
构造一个对角线长 5 个字符,倾斜放置的菱形。
1 | * |
因为图形很简单,不需要做特别的逻辑处理,简单粗暴用printf
输出它就好。
图形分为 5 行,且要考虑每个空格也是答案的一部分,输出这样的内容肯定是错误的:
1 | * |
每一行要把“”和“
*
”都打出来,且要把换行的符号(“\n
”)也打出来,答案如下:
1 |
|
例 计算 \((a+b)/c\) 的值
给定 3 个整数 \(a, b, c\), 计算 \((a+b)/c\) ,其中 \(/\) 是整除运算。
输入
1 | 1 1 3 |
输出
1 | 0 |
“整除运算”的意思是只取计算结果的整数部分,小数部分省略。
知识点:大多编程语言默认相同类型的变量在计算过程中类型不变,
int
只能存整数,它无法表达1/2=0.5
这样的概念,故int
与int
之间的计算,编译器默认结果自动取整,也就刚好符合“整除运算”的要求,即1整除2=0
,保留0.5
的整数部分0
。
1 |
|
知识点:在读入多个数字的时候,
scanf
的格式化输入%d
会自动跳过不是数字的符号,从而方便我们不用关心输入的数字之间有多少空格、多少换行,即无论输入的是还是
1 1 1 3
1
2
3 1 1
3scanf("%d%d%d", &a, &b, &c);
都能正确地完成输入
例 浮点数向零舍入
输入一个双精度浮点数,将其向零舍入到整数。说明:向零舍入的含义是,正数向下舍入,负数向上舍入。
输入数据范围是 \(-10^{15}\leq x \leq 10^{15}\)。
这是一个 double
向整数转换的任务,在编程语言中向0
舍入是默认机制,不需要我们写特别的代码逻辑。
关于强制转换,可以直接将double
赋值给整数变量,也可以给值前面加(变量类型)
来得到转换后的值。
知识点:题目告知输入范围,并不是让你来判断题目输入的对不对,而是给你一个信息,让你知道在处理一个什么规模的问题,从而调整自己的实现思路。
知识点:
int
可以表达的范围是-2147483648~2147483647
,也就是32
个二进制位能表达的范围,更大的整数类型是long long
,它有64
个二进制位,能表达-9,223,372,036,854,775,808~9,223,372,036,854,775,807
,大约 \(10^{19}\),它对应的输入输出占位符是%lld
输入
1 | 2.3 |
输出
1 | 2 |
1 |
|
分支结构
分支结构(也称为选择结构)是程序设计中用于实现条件判断和不同路径执行的重要控制结构。通过分支结构,程序可以根据特定条件选择执行不同的代码块,从而实现更复杂的功能和逻辑处理。
if语句
1 | if(条件) { |
或者
1 | if(条件1) { |
例 整数大小比较
输入两个整数,比较它们的大小。若 \(x>y\) ,输出 >
;若
\(x=y\) ,输出 =
;若
\(x<y\),输出 <
。
数据范围 \(0\leq x \leq 2^{32}, -2^{31} \leq y \leq 2^{31}\)
输入:
1 | 1000 100 |
输出:
1 | > |
- 这题范围很大,用
long long
- 因为
=
是赋值用的,判断相等得用==
- 输出的好习惯:单行输出都带上
\n
在结尾换行
1 |
|
三元运算符
在“非此即彼”且逻辑简单的时候,用三元运算可简化代码,写起来很“帅”
1 | 条件 ? 符合条件执行这里 : 不符合条件执行这里 |
上题用三元运算符也可以完成,不过它不是“非此即彼”的,有三种情况,可以三元运算套三元运算,这样写:
1 |
|
switch
一个变量或表达式有多种可能的目标值,可以用switch:
1 | switch(变量) { |
注意:除最后的default外,每个 case
最后必须有
break
,否则它之后的 case
也会被执行
例 简单计算器
给两个数字、一个符号,如果符号不是加减乘除则输出Invalid operator!
,如果除0则输出Divided by zero!
输入
1 | 1 2 + |
输出
1 | 3 |
1 |
|
知识点: - 字符需要用
char
这个变量类型, - 读入%d
能自动跳过空白,但%c
不行,它会读空白字符,题目输入由空格隔开,所以要加一个空格占位后再写%c
- 字符常量用单引号'
,后面课程的字符串章节会更详细的讲解