关于scanf

scanf 的「按图索骥」原理

什么是scanf

scanf 是用来记录用户键盘输入的输入

scanf("格式字符串", &变量); 中,双引号里的内容就是给电脑下的“死命令”。

scanf有安全性问题

如果必须使用请在头部

#include <stdio.h>前加上#define _CRT_SECURE_NO_WARNINGS 1或者在项目名-右键-属性-C/C++-预处理器加上 _CRT_SECURE_NO_WARNINGS来屏蔽警告(C4996)

1. 核心结论:原样输入原则

除了以 % 开头的占位符(如 %d, %s),你在双引号里写的任何字符,用户在键盘上都必须原封不动地输入,否则匹配就会失败。

  • 写了 aaa%d:用户必须输入 aaa18,电脑才能把 18 存到变量去。
  • 写了 %d, %d:用户必须在两个数字中间打一个英文逗号
  • 写了 年龄=%d:用户必须输入 年龄=18

结论:双引号里的非占位符就像是“通行证”,打错了或者漏打了,后面的数据电脑就拒收

案例1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
int age;
printf("请输入aaa再加上你的年龄:");
// 这里的 aaa 是强制匹配项

scanf("aaa%d", &age);

printf("你的年龄是:%d 岁\n", age);
// 如果没有输入aaa程序就不会进行响应
return 0;
}

2. 为什么 \n 会让程序“卡死”?

这是最特殊的规则。在 scanf 中,空格、回车(\n)、制表符(\t)统称为“空白符”。

  • 逻辑陷阱:当你写 scanf("%d\n", &age); 时,\n 的意思是“跳过后面所有的空白字符”。

  • 死循环现象:你输入数字后敲回车,这个回车被 \n 匹配掉了。但电脑不知道后面还有没有更多的空格或回车,它会一直等,直到你输入一个非空白字符(比如随便打个字母或数字)为止。

  • 感官体验:你觉得程序卡死了,其实它只是在等你输入一个“带头大哥”来结束空白符的等待。

    案例2

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #define _CRT_SECURE_NO_WARNINGS 1
    #include <stdio.h>

    int main()
    {
    int num;
    printf("请输入一个数字(注意:这个 scanf 后面带了 \\n): \n");

    // 这里的 \n 会让程序进入“等不到头”的状态
    scanf("%d\n", &num);

    printf("终于运行到这一行了!你输入的数字是:%d\n", num);

    return 0;
    }

    scanf 的逻辑里,它不觉得\n “循环”,它觉得这是一个“过滤过程”。

    1. 它是怎么“过滤”的?

    当你写了 scanf("%d\n", &a);

    • 第 1 步: 你输入数字 10scanf 拿走了它。
    • 第 2 步: 你按下回车。scanf 里的 \n 发现了一个回车,它想:“这是个空白,我要继续往后找,直到看到不是空白的东西。”
    • 第 3 步: 你又按了 10 次回车,或者打了 100 个空格。scanf 依然想:“这些全是空白,我继续跳过。”
    • 第 4 步: 你终于打了一个字符 x 或者数字 5
    • 第 5 步: scanf 眼睛一亮:“终于看到一个‘正经’字符了!”
    • 第 6 步: 重点来了!它会把这个 x 吐回到缓冲区(留给下一个 scanf 用),然后才觉得自己的任务完成了,程序才会继续往下走。

    2. 笔记总结:怎样才能“叫醒”它?

    你输入的内容 电脑的反应 能结束吗?
    回车 (Enter) 认为是空白符,继续等 不能
    空格 (Space) 认为是空白符,继续等 不能
    制表符 (Tab) 认为是空白符,继续等 不能
    字母 (a, b, c…) 发现非空白,完成匹配 可以
    数字 (1, 2, 3…) 发现非空白,完成匹配 可以
    符号 (!, @, #…) 发现非空白,完成匹配 可以

    3. 给你的“避坑”结论

    所以,并不是“输入什么都可以结束”,而是“输入任何不是空格/回车的东西”才能结束。

    为什么这很危险?

    因为你最后为了结束 scanf 而多打的那个字符(比如那个 x),并没有消失。它还留在电脑的缓存区里。如果你紧接着下面还有一个 scanf 要读字符,它会直接读到那个 x,导致你的程序再次乱套。

3. 避坑指南总结表

写法 实际意义 推荐程度
scanf("%d", &a); 只读数字,回车自动触发结束 ⭐⭐⭐⭐⭐ (最标准)
scanf("aaa%d", &a); 必须先打 aaa 才能读数字 ⭐ (除非特殊格式需求)
scanf("%d\n", &a); 读完数字后,必须再打个字符才能继续 ❌ (千万别写,会卡住,导致内存溢出)
scanf("%d ", &a); (%d后有空格) 同上,空格也会导致需要额外输入 ❌ (容易误触)

4. 终极记忆口诀

printf 里面随你写,想怎么换行就换行。

scanf 里面要干净,除了百分号啥也别剩。

补充建议:

如果你想让用户知道该输什么,应该把提示文字写在 printf 里,而不是 scanf 里。

  • ❌ 错误写法scanf("请输入年龄:%d", &age); (用户得照着打一遍“请输入年龄:”,累死了)

  • ✅ 正确写法

    1
    2
    printf("请输入年龄:"); 
    scanf("%d", &age);