用scanf函数输入数据
基础语法: scanf("格式化控制字符串", 地址列表);
示例代码
int a; //创建一个int型的变量a
scanf("%d", &a); //&与变量结合,叫做取地址运算符
-
备注:我们的变量除了拥有变量名外,还拥有其在内存的编号,我们把这个编号称之为内存地址。所以我们的变量有两种访问方式,一种是通过变量名,一种是通过内存地址。
-
核心作用:将键盘输入的数据存入地址列表指定的内存单元中。
核心注意事项
地址列表必须是内存地址,不能直接传变量,常量或表达式等。
-
普通变量:直接通过&变量名获取地址
-
字符串数组:数组本身就是首地址,无需加取地址符&,但需要确保数组长度足够容纳输入的字符串(包含结束符\\n)
示例代码
char str[10];
scanf("%s", str);
格式控制字符串的规则
-
格式说明符需要与输入数据类型,地址列表顺序一一对应。
-
若格式控制字符串包含普通字符,输入时必须在对应位置输入相同字符。
示例代码
int year, month, day;
scanf("%d年%d月%d日", &year, &month, &day);//此时控制台录入:年月日不能省略
案例
输入多个整数
示例代码
#include <stdio.h>
int main(int argc,char *argv[])
{
int a, b, c;
printf("输入3个整数: \\n");
scanf("%d%d%d", &a, &b, &c);
printf("a=%d,b=%d,c=%d\\n",a, b, c);
return 0;
}
运行结果
//以下三种方式赋值,来输出结果
/20260803$ ./a.out
输入3个整数:
12 2 60
a=12,b=2,c=60
/20260803$ ./a.out
输入3个整数:
12 2 60 //使用Tab分格
a=12,b=2,c=60
/20260803$ ./a.out
输入3个整数:
12
2
60
a=12,b=2,c=60
备注: 输入多个数据时可以通过空格,Tab,回车键任意一个进行分隔。
带普通字符的格式控制
| , | 使用逗号分隔,输入时也必须加逗号分隔 | scanf("%d,%d", &a, &b); |
| – | 使用短横线分隔,输入时也必须加短横线 | scanf("%d—%d", &a, &b); |
| 文字 | 添加文字分隔,输入时也需加上文字 | scanf("%d年%d月%d日"); |
关键细节
%c 格式输入字符的特殊处理
%c 会读取输入缓冲区中的所有字符(包含空格 ,Tab ,\\n,均视为有效输入)
示例代码
#include <stdio.h>
int main(int argc,char *argv[])
{
char a, b, c;
printf("输入三个字符: \\n");
scanf("%c%c%c", &a, &b, &c);
printf("a=%c,b=%c,c=%c\\n",a,b,c);
return 0;
}
运行结果
/20260803$ ./a.out
输入三个字符:
abc
a=a,b=b,c=c //正确
/20260803$ ./a.out
输入三个字符:
a b c
a=a,b= ,c=b //输入加空格,它也会把空格打印输出
解决方案:若需跳过空白字符,可在%c前加空格,如scanf(" %c %c %c", &a, &b, &c)。
数据型数据的输入与结束条件
输入整型(%d/%u等),浮点型(%f/%lf等),遇到非法字符(字母、符号等)视为输入结束。
int main(int argc,char *argv[])
{
int a, b, c;
printf("输入: \\n");
scanf("%d%d%d", &a, &b, &c);
printf("a=%d,b=%d,c=%d\\n",a,b,c);
return 0;
}
运行结果
/20260803$ ./a.out
输入:
1252h45
a=1252,b=4096,c=0
/20260803$ ./a.out
输入:
14h45354
a=14,b=4096,c=0
无符号类型的输入
推荐用%u,匹配unsigned int,避免符号位错误;若用%d输入(不推荐),可能因符号位解析错误导致溢出。
unsigned int u;
scanf("%u", &u); // 正确
scanf("%d", &u); // 不推荐,风险高
输入数据的格式控制、
分类
| 指定输入宽度 | scanf("%3d%3d", &a, &b); | 输入测试数据:1234567→ 结果:a=123, b=456,解释:从输入数据1234567中,截取前3列(123)赋值给a;在截取后续3列(456)赋值给b,剩余的7被舍弃。 |
| 跳过指定列数 | scanf("%2d%*3d%3d", &a, &b); | 输入测试数据:12345678 → 结果:a=12, b=678,解释:截取前2列(12)赋值给a,%*3d跳过中间3列(345),再截取后续3列(678)赋值给b |
scanf 中float 与double 的区别
| %f/%e | scanf输入单精度浮点型 | float |
| %lf/%le | scanf输入双精度浮点型 | double |
警示: printf 输出时,float 和 double 均可使用 %f/%e(double 会自动提升精度);但 scanf 输入时,float 必须用 %f,double 必须用 %lf,否则会导致数据读取异常。
补充格式说明符%n
%n用于统计已读取的字符个数
示例代码
#include <stdio.h>
int main(int argc,char *argv[])
{
int a, count;
printf("输入一个整数: \\n");
scanf("%d%n",&a, &count);
printf("a=%d, count=%d\\n",a, count);
return 0;
}
运行结果
/20260803$ ./a.out
输入一个整数:
748
a=748, count=3
/20260803$ ./a.out
输入一个整数:
85
a=85, count=2
输入输出缓冲区
概念
缓冲区是内存中专门用于暂存输入/输出数据的区域,就相当于“数据中转站”。
输入数据流向:外部设备(键盘)→输入缓冲区→程序(变量或数组等)
输出数据流向:程序→输出缓冲区→外部设备(显示器/命令终端)
缓冲区的三种类型
| 全缓冲 | 缓冲区填满时 | 磁盘文件读写(Windows默认4096字节,Linux默认1024字节) |
| 行缓冲 | 遇到换行符(\\n)或回车键时 | 标准输入(stdin,键盘)、标准输出(stdout,显示器) |
| 无缓冲 | 无缓冲,直接IO | 标准错误流(stderr,错误信息输出) |
缓冲区的刷新条件
数据从缓冲区写入外部设备的四种条件:
缓冲区填满(全缓冲触发,一般是文件读写)
遇到换行符 \\n(行缓冲触发)
手动调用 fflush() 函数(如 fflush(stdout) 刷新输出缓冲区),fflush(stdin) 行为未定义(UB),不推荐使用。
程序正常结束(进程退出时自动刷新所有缓冲区)
注意:scanf() 是从输入缓冲区读取数据,而非"刷新":若缓冲区已有数据,直接读取;若为空则等待用户输入。fflush(stdin)(刷新输入缓冲区)的行为在 C 标准中是未定义的(不同编译器表现不同),不能依赖。
缓冲区的核心作用
-
提高效率:减少程序与外部设备的直接交互次数(IO操作耗时远高于内存操作)
-
平滑数据流:避免因设备读写速度不匹配导致的数据丢失或阻塞。
缓冲区残留问题与解决
问题代码
#include <stdio.h>
int main(int argc,char *argv[])
{
int a, b;
printf("输入第一个运算数:\\n");
scanf("%d",&a);
printf("输入第二个运算数:\\n");
scanf("%d",&b);
printf("输入运算符:\\n");
char op;
scanf("%c",&op);
printf("%d %c %d = %d\\n",a, op, b, a + b);
return 0;
}
运算结果
/20260803$ ./a.out
输入第一个运算数:
14
输入第二个运算数:
16
输入运算符:
14
16 = 30
存在的问题:输入第2个数值后按回车,程序直接跳过运算符的输入,因为缓冲区中残留了\\n
解决问题:在给字符op赋值之前,先把缓冲区的所有字符清掉,
清理缓冲区的代码:while (getchar() != '\\n');
正确代码
#include <stdio.h>
int main(int argc,char *argv[])
{
int a, b;
printf("输入第一个运算数:\\n");
scanf("%d",&a);
printf("输入第二个运算数:\\n");
scanf("%d",&b);
printf("输入运算符:[+]");
char op;
while(getchar() !='\\n');
scanf("%c",&op);
printf("%d %c %d = %d\\n",a, op, b, a + b);
return 0;
}
运行结果
/20260803$ ./a.out
输入第一个运算数:
14
输入第二个运算数:
16
输入运算符:[+]+
14 + 16 = 30
条件判断基础
条件判断定义: 根据某个条件的成立与否,决定是否执行指定操作。

条件判断的结果
-
真(True):非0值,C语言中,为了统一管理,一般用1表示真。
-
假(False):0值。
关系与逻辑运算符
六种关系运算符:< <= > >=(高优先级) > == !=(低优先级)
三种逻辑运算符:!(逻辑非) > &&(逻辑与) > ||(逻辑或)
优先级规则:
| 1 | 逻辑运算符 | ! |
| 2 | 算数运算符 | * / % 高于 + – |
| 3 | 关系运算符 | < <= > >= 高于 == != |
| 4 | 逻辑运算符 | && 高于 || |
| 5 | 赋值运算符 | = += … |
案例:混合运算优先级
2 + 5 > 6 && !5 + 3 < 3
= 2 + 5 > 6 && 0 + 3 < 3
= 7 > 6 && 0 + 3 < 3
= 1 && 0 + 3 < 3
= 1 && 3 < 3
= 1 && 0
= 0
真值表:
| 非0 | 非0 | 0 | 1 | 1 |
| 非0 | 0 | 0 | 0 | 1 |
| 0 | 非0 | 1 | 0 | 1 |
| 0 | 0 | 1 | 0 | 0 |
逻辑运算符短路特性
短路特性是逻辑运算符的重要优化机制,对条件判断的执行有直接影响:
-
逻辑与(&&):左侧操作数为假时,右侧操作数不执行(结果直接为假)
-
逻辑或(||):左侧操作数为真时,右侧操作数不执行(结果直接为真)
案例:设a=4,b=5
| !a | 0 | a=4(非0为真),逻辑非后为假 |
| a && b | 1 | 两侧均为非0,结果为真 |
| a || b | 1 | 左侧操作数为真,触发短路,直接返回真 |
| !a || b | 1 | 左假右真,结果为真 |
| 4 && 0 || 2 | 1 | 4 && 0为0,0 || 2为1 |
用if语句实现分支结构
单分支(if…)
基本语法:
// 复合语句(多条语句)需要{}包裹
if (条件表达式)
{
// 语句块(分支体),也就是{}包裹的整体内容
}
// 但语句可省略{},以下两种写法完全等价
if (条件表达式) 语句;
if (条件表达式)
语句;
// 注意:该语句属于流程控制语句中的分支语句,是极少数无需分号;结尾的语句
功能:
-
条件表达式返回的结构是逻辑值,如果为真(非0),执行后续语句块,再执行if语句后其他代码。
-
如果条件为假(0):跳过后续语句块,直接执行if循环后的其他代码。
案例1:计算分段函数
-
需求:计算并输出下列分段函数的值:
$$
y = \\begin{cases} -2 \\quad x<0\\\\ \\\\ 2 \\quad\\quad x\\geq0 \\end{cases}
$$ -
示例代码:
#include <stdio.h>
int main(int argc,char *argv[])
{
int x, y = -2;
printf("输入一个整数:");
scanf("%d",&x);
if (x >=0) y = 2;
printf("x=%d,y=%d\\n",x,y);
return 0;
}
//运行结果
/20260806$ ./a.out
输入一个整数:5
x=5,y=2
/20260806$ ./a.out
输入一个整数:-8
x=-8,y=-2
案例2:求最大最小值
-
需求:从控制台输入a,b,c三个整数,输出其中的最大值和最小值。
-
分析:
-
定义变量a,b,c,接收控制台的输入,定义变量max,min存储最大值最小值。
-
初始化max=min=a,默认第一个数为最大数和最小数,a必须初始化
-
依次将max与b,c比较,更新最大值
-
依次将min与b,c比较,更新最小值
-
-
示例代码:
#include <stdio.h>
int main(int argc,char *argv[])
{
int a, b, c, max, min;
printf("输入三个整数:");
scanf("%d %d %d",&a,&b,&c);
max = min = a;
if (max < b) max = b;
if (max < c) max = c;
if (min > b) min = b;
if (min > c) min = c;
printf("%d%d%d中最大的值是%d,最小值是%d\\n",a,b,c,max,min);
return 0;
}
//运行结果
/20260806$ ./a.out
输入三个整数:4 2 6
426中最大的值是6,最小值是2
/20260806$ ./a.out
输入三个整数:7 8 9
789中最大的值是9,最小值是7
注意事项:
-
局部变量(函数中定义的变量)未赋值前的值是未定的(垃圾值),禁止在赋值前使用(否则结果不可预料);
-
全局变量(函数外部定义的变量)或静态变量(使用static修改)会被系统默认初始化为0;
int g_a; // 全局变量,系统会默认初始化为0
int main()
{
int m_b; // 局部变量,其值不确定(垃圾值)未赋值前使用会导致未定义行为(UB)
printf("%d,%d\\n", g_a, m_b); // 0,值不确定(垃圾值)
} -
书写规范建议:
-
if (flag == 1) 建议简化if(flag),举例:int flag = 1; if(flag)
-
if (flag == 0) 建议简化if(!flag),举例:int flag = 1; if(!flag)
注意:if(flag) 检查"flag是否为非零值",而 if(flag==1) 检查"flag是否精确等于1"。当flag=2时,前者为真、后者为假,两者有重要的语义差异,请根据实际需求选择。
-
双分支(if..else..)
基本语法:
// 复合语句需要{}包裹
if (条件表达式)
{
语句1; // 条件为真时执行
}
else
{
语句2; // 条件为假时执行
}
// 单语句可省略{},以下两种写法完全等价
if (条件表达式) 语句1;
else 语句2;
if (条件表达式)
语句1;
else
语句2;
核心规则:
-
else 不能单独存在,必须与距离最近的未配对的if 配对。
-
条件无论真假,必须且执行其中一个。
功能说明:
-
if..else实现双分支选择,支持嵌套(建议嵌套层级<=3~4层,保证代码可读性和可维护性)
-
语句1和语句2均可为单语句或复合语句
案例:计算分段函数:
-
需求:计算并输出下列分段函数的值:
$$
y = \\begin{cases} -2 \\quad x<0\\\\ \\\\ 2 \\quad\\quad x\\geq0 \\end{cases}
$$ -
示例代码:
#include <stdio.h>
int main(int argc,char *argv[])
{
int x, y ;
printf("输入一个整数:");
scanf("%d",&x);
if (x >=0) y = 2;
else y = -2;
printf("x=%d,y=%d\\n",x,y);
return 0;
}
//运行结果
/20260806$ ./a.out
输入一个整数:12
x=12,y=2
/20260806$ ./a.out
输入一个整数:-20
x=-20,y=-2
多分支(if…else if…[else])
基本语法
// 写法1:嵌套if..else..(不推荐,可读性差)
if (表达式1) 语句1;
else
if (表达式2) 语句2;
…
else
if (表达式n) 语句n;
else 语句n+1;
// 写法2:并列if..else if..else..(推荐,可读性强)
if (表达式1) 语句1;
else if (表达式2) 语句2;
…
else if (表达式n) 语句n; // 根据情况可选
else 语句n+1; // 根据情况可选(无匹配条件时执行)
// 注意:复合语句必须用{}包裹起来,单语句可省略
核心规则
-
else 为可选部分,根据需求决定是否添加。
-
同一循环中只执行一条满足的分支,后续不再执行。
案例:成绩评定
-
需求:根据学生成绩(0~100)评级:
-
成绩 >= 90 → A级
-
成绩 >= 80 → B级
-
成绩 >= 60 → C级
-
成绩 < 60 → D级
-
-
示例代码
#include <stdio.h>
int main(int argc,char *argv[])
{
int score; //创建一个变量,用来存储成绩
printf("输入成绩:");
scanf("%d",&score);
if (score < 0 || score > 100)
{
printf("请输入0-100之间的数:\\n");
return ;
}
if (score >= 90) printf("A级\\n");
else if (score >= 80) printf("B级\\n");
else if (score >= 60) printf("C级\\n");
else printf("D级\\n");
return 0;
}
//运行结果
/20260808$ ./a.out
输入成绩:78
C级
/20260808$ ./a.out
输入成绩:-45
请输入0-100之间的数:
/20260808$ ./a.out
输入成绩:55
D级
/20260808$ ./a.out
输入成绩:95
A级
多分支的注意事项
-
语句1和语句2均可为复合语句(需要用{}包裹),或空语句(例如:if(..);else;,正确但是无意义)
-
空语句:仅占语法位置,不执行任何操作。
示例代码
#include <stdio.h>
int main(int argc,char *argv[])
{
int a = 4, b = 3;
// 编译不报错,但是本身无意义
if (a > b); // 空语句
else; // 空语句
if (a % 2 != 0); // 条件为奇数,空语句
else printf("%d是一个偶数!\\n", a);
// 上面代码等价于下面写法
if (a % 2 == 0) printf("%d是一个偶数!\\n", a);
return 0;
}
if 语句的嵌套
基本语法
if (表达式1)
if (表达式2) 语句1; // 表达式1和表达式2均为真时执行
else 语句2; // 表达式1为真,表达式2为假时执行
else
if (表达式3) 语句3; // 表达式1为假,表达式3为真时执行
else 语句4; // 表达式1为假,表达式3为假时执行

核心规则:
① else 始终与前面最近的未配对 if配对(默认规则)
② 可通过添加{}强制指定配对关系(避免歧义)
③ 只要 if 语句内部包含另一个完整的 if(或 if..else),即属于嵌套结构
三目运算符(条件运算符)
基本语法: 表达式1 ? 表达式2 : 表达式3;
核心说明:
-
表达式1 为真→执行 表达式2 ,结果为表达式2 的值;
-
表达式1 为假→执行 表达式3 ,结果为表达式3 的值;
-
本质是单表达式双分支 if 的简写,仅适用于单语句场景(不能替代复合语句)
-
计算顺序:按照运算符优先级(从高到底)。
逻辑非(!) → 算数运算符(* / % → + -) → 关系运算符(> < >= <= → == !=) → 逻辑运算符(&& → ||) → 三目运算符(?:) → 赋值运算符(= += …)
案例1:计算分段函数(简化版)
-
需求:计算并输出下列分段函数的值:
$$
y = \\begin{cases} -2 \\quad x<0\\\\ \\\\ 2 \\quad\\quad x\\geq0 \\end{cases}
$$ -
示例代码:
#include <stdio.h>
int main(int argc,char *argv[])
{
// 定义两个变量x,y,x用来接收控制台的输入
int x,y;
printf("请输入一个整数:");
scanf("%d", &x);
// 使用三目运算符根据条件计算分段函数值
y = x < 0 ? -2 : 2;
printf("x=%d,y=%d\\n", x, y);
return 0;
}
//运行结果
/20260808$ ./a.out
输入一个整数:5
x=5,y=2
/20260808$ ./a.out
输入一个整数:-8
x=-8,y=-2
案例2:求最大最小值(简化版)
-
需求:从控制台输入a,b,c三个整数,输出其中的最大值和最小值。
-
示例代码:
#include <stdio.h>
int main(int argc,char *argv[])
{
// 创建变量a,b,c,接收控制台输入,创建变量max,min存储最大最小值
int a, b, c, max, min;
printf("请输入三个整数:\\n");
scanf("%d%d%d", &a, &b, &c);
// 使用三目运算符求最大值
// 外层的?: 先比较a和b,内层的?: 再与c比较
max = (a > b) ? (a > c ? a : c) : (b > c ? b : c);
// 使用三目运算符求最小值
min = (a < b) ? (a < c ? a : c) : (b < c ? b : c);
printf("%d,%d,%d中的最大值是%d,最小值是%d\\n", a, b, c, max, min);
return 0;
}
//运行结果
/20260808$ ./a.out
输入三个整数:4 2 6
426中最大的值是6,最小值是2
/20260808$ ./a.out
输入三个整数:7 8 9
789中最大的值是9,最小值是7
用switch语句实现分支结构
switch 语句专门用来实现多分支选择结构(多路分支),适用于条件为离散值的场景。
基本语法:
switch (表达式) // 表达式结果为离散值(int、char、enum(枚举,符号常量))
{
case 常量表达式1: // 常量表达式:字面量(12,3.14)、符号常量(PI)、枚举值(LEFT/RIGHT)
// { 笔试题中,可能会出现这样的代码,一般省略不写
语句1;
break; // 跳出switch语句(可选,无则触发穿透)
// }
case 常量表达式2:
语句2;
break;
…
case 常量表达式n:
语句n;
break;
default: // default一般写在所有case的最下面,无匹配case时执行,类似于if多分支的else
语句n+1;
break; // 若default写在所有case的下面,break可以省略掉,否则必须添加
}
注意:
-
switch的{}必须保留,case后的语句可用{}包裹,一般省略。
-
case和default的顺序没有固定语法要求。
-
表达式和常量表达式之间是等值(==)判断。

核心说明:
① 表达式类型限制:结果必须是整型(int、long)或字符型(char),不能是浮点型或字符串(因为case标签要求整型常量表达式,浮点数和字符串不是整型,编译时无法作为分支跳转目标)。
② case常量唯一性:每个case后的常量表达式值必须不同(否则编译报错),如同一个switch中,不能出现两个case 2
switch (..)
{
case 1:
…
break;
case 1: // case常量必须唯一,不能重复
…
break;
}
③ 执行顺序:先计算表达式值,匹配对应的case 常量表达式并执行后续语句;无匹配时执行default。
④ break穿透:若case后无break,执行完当前case语句后会继续执行下一个case,直到遇到break或switch结束。
⑤ 多case共用语句:多个case可共享同一组执行语句(无需重复编写)
案例1:判断季节
-
需求:输入一个月份判断是什么季节
#include <stdio.h>
int main(int argc,char *argv[])
{
int month;
printf("请输入月份:");
scanf("%d",&month);
switch(month)
{
case 12:
case 1:
case 2:
printf("冬季\\n");
break;
case 3:
case 4:
case 5:
printf("春季\\n");
break;
case 6:
case 7:
case 8:
printf("夏季\\n");
break;
case 9:
case 10:
case 11:
printf("秋季\\n");
break;
default:
printf("请输入1~12的整数:\\n");
}
return 0;
}
//运行结果
/20260808$ ./a.out
请输入月份:7
夏季
/20260808$ ./a.out
请输入月份:12
冬季
/20260808$ ./a.out
请输入月份:78
请输入1~12的整数:
案例2:成绩评定(版本2)
-
需求:输入百以内成绩,输出对应等级。
-
90~100:A级
-
80~89: B级
-
70~79: C级
-
60~69: D级
-
其他: E级
-
-
示例代码:
int main(int argc,char *argv[])
{
// 定义一个变量,用来存储成绩
int score;
printf("请输入一个成绩(0~100):");
scanf("%d", &score);
// 校验成绩的合法性
if (score < 0 || score >= 100)
printf("请输入0~100之间的整数!\\n");
else
switch (score / 10) // 在C语言中,整数除以整数,结果还是整数
{
case 10: // 100
case 9: // 90~99
printf("A级\\n");
break;
case 8:
printf("B级\\n");
break;
case 7:
printf("C级\\n");
break;
case 6:
printf("D级\\n");
break;
default:
printf("E级\\n");
}
return 0;
}
//运行结果
/20260808$ ./a.out
输入成绩:78
C级
/20260808$ ./a.out
输入成绩:-45
请输入0~100之间的数:
/20260808$ ./a.out
输入成绩:55
D级
/20260808$ ./a.out
输入成绩:95
A级
案例3:简易计算器
#include <stdio.h>
int main(int argc,char *argv[])
{
char op; //创建一个变量用来存储运算符
double num1, num2; //创建两个变量,用来存储计算数
//头设计
printf("———————\\n");
printf("| 简易计算器 |\\n");
printf("———————\\n");
printf("输入两个运算数:\\n");
scanf("%lf,%lf",&num1,&num2);
printf("输入运算符(+,-,*,/,%):\\n");
while (getchar() != '\\n');
scanf("%c",&op);
switch(op)
{
case '+':
printf("%.2lf + %.2lf = %.2lf\\n",num1,num2,num1+num2);
break;
case '-':
printf("%.2lf – %.2lf = %.2lf\\n",num1,num2,num1-num2);
break;
case '*':
printf("%.2lf * %.2lf = %.2lf\\n",num1,num2,num1*num2);
break;
case '/':
printf("%.2lf / %.2lf = %.2lf\\n",num1,num2,num1/num2);
break;
case '%':
printf("%.2lf % %.2lf = %.2lf\\n",num1,num2,(int)num1%(int)num2);
break;
}
return 0;
}
//运行结果
/20260808$ ./a.out
———————
| 简易计算器 |
———————
输入两个运算数:
12,78
输入运算符(+,-,*,/,%):
+
12.00 + 78.00 = 90.00
/20260808$ ./a.out
———————
| 简易计算器 |
———————
输入两个运算数:
96.3,85
输入运算符(+,-,*,/,%):
–
96.30 – 85.00 = 11.30




