一觉睡醒,全世界计算机水平下降100倍,而我却精通C语言——scanf函数

大家好啊,我是小象٩(๑òωó๑)۶
我的博客:Xiao Fei Xiangζั͡ޓއއ
很高兴见到大家,希望能够和大家一起交流学习,共同进步。*

这一节我们主要来学习scanf的基本用法,了解scanf返回值,懂得scanf占位符和赋值忽略符的知识,然后我们还会学习到关于Visual studio环境下scanf不安全解决办法,这个可能是很多新手朋友一开始用vs都会遇到的问题

文章目录

  • 一、scanf函数
      • [1.1 基本用法](#1.1 基本用法)
      • [1.2 scanf的返回值](#1.2 scanf的返回值)
      • [1.3 占位符](#1.3 占位符)
      • [1.4 赋值忽略符](#1.4 赋值忽略符)
  • [(重要)关于Visual studio环境下scanf不安全解决办法](#(重要)关于Visual studio环境下scanf不安全解决办法)
  • 结尾

一、scanf函数

在C语言中,scanf函数是一个非常重要的输入函数 ,它用于从标准输入(通常是键盘)读取格式化的输入数据 。与printf函数类似,scanf也使用格式说明符来指定输入数据的类型和格式 。然而,与printf不同的是,scanf需要变量的地址来存储输入的数据

当我们有了变量,我们需要给变量输入值就可以使用 scanf 函数,如果需要将变量的值输出在屏幕上的时候可以使用 printf 函数,来看一个例子:

c 复制代码
#include <stdio.h>
int main()
{
 int score = 0;
 printf("请输⼊成绩:");
 scanf("%d", &score);
 printf("成绩是:%d\n", score);
 return 0;
}

运行一下:

画图演示:

注:标准输入一般指的就是键盘,标准输出一般指的就是屏幕

那接下来我们介绍下 scanf 函数。

1.1 基本用法

scanf( ) 函数用于读取用户的键盘输入

程序运行到这个语句时,会停下来,等待用户从键盘输入。

用户输入数据、按下回车键后, scanf() 就会处理用户的输入,将其存入变量。

它的原型定义在头文件 stdio.h 。

scanf() 的语法跟 printf() 类似。

c 复制代码
scanf("%d", &i);

它的第一个参数是一个格式字符串 ,里面会放置占位符(与 printf() 的占位符基本一致),告诉编译器如何解读用户的输入,需要提取的数据是什么类型。

这是因为 C 语言的数据都是有类型的, scanf() 必须提前知道用户输入的数据类型,才能处理数据。

它的其余参数就是存放用户输入的变量,格式字符串里面有多少个占位符,就有多少个变量。

上面例子中, scanf() 的第一个参数 %d ,表示用户输入的应该是一个整数。 %d 就是一个占位符, % 是占位符的标志 , d 表示整数。第二个参数 &i 表示将用户从键盘输入的整数存入变量i

注意:变量前面必须加上 & 运算符(指针变量除外),因为 scanf() 传递的不是值,而是地址, 即将变量 i 的地址指向用户输入的值。

如果这里的变量是指针变量(比如字符串变量),那就不用加 & 运算符。

下⾯是一次将键盘输入读入多个变量的例子。

c 复制代码
scanf("%d%d%f%f", &i, &j, &x, &y);

上面例子中,格式字符串 %d%d%f%f ,表示用户输入的前两个是整数,后两个是浮点数,比如 1

-20 3.4 -4.0e3 。这四个值依次放入 i 、 j 、 x 、 y 四个变量。

scanf() 处理数值占位符时,会自动过滤空白字符,包括空格、制表符、换行符等。

scanf()处理数值占位符时,会自动过滤空白字符,包括空格、制表符、换行符,scanf输出字符占位符的时候,不忽略空白字符,总是返回当前第一个字符,无论该字符是否为空格。

所以,用户输入的数据之间,有一个或多个空格不影响 scanf() 解读数据 。另外,用户使用回车键,将输入分成几行,也不影响解读。

举个例子:

输入:

c 复制代码
1
-20
3.4
-4.0e3

上面例子中,用户分成四行输入,得到的结果与一行输入是完全一样的。每次按下回车键以后,scanf() 就会开始解读,如果第一行匹配第一个占位符,那么下次按下回车键时,就会从第二个占位符开始解读。

scanf() 处理用户输入的原理是,用户的输入先放入缓存,等到按下回车键后,按照占位符对缓存进行解读

解读用户输入时,会从上一次解读遗留的第⼀个字符开始,直到读完缓存,或者遇到第一个不符合条件的字符为止。

来看个例子:

c 复制代码
# include <stdio.h> 
int main()
{
	int x = 0;
	float y = 0;
	scanf("%d", &x);
	printf("%d\n", x);
	scanf("%f", &y);
	printf("%f\n", y);
	return 0;
}

我们输入 -13.45e12# 0看看结果:

上面例子中, scanf() 读取用户输入时, %d 占位符会忽略起首的空格,从 - 处开始获取数据,读取到 -13 停下来,因为后面的 . 不属于整数的有效字符。这就是说,占位符 %d 会读到 -13 。

第二次调用 scanf() 时,就会从上一次停止解读的地方,继续往下读取。这二次读取的首字符是 . ,由于对应的占位符是 %f ,会读取到 .45e12 ,这是采用科学计数法的浮点数格式。后面的 # 不属于浮点数的有效字符,所以会停在这里。

由于 scanf() 可以连续处理多个占位符,所以上面的例子也可以写成下面这样:

c 复制代码
#include <stdio.h>
int main()
{
	int x = 0;
	float y = 0;
	scanf("%d%f", &x, &y);
	printf("%d\n", x);
	printf("%f", y);
	return 0;
}

1.2 scanf的返回值

scanf() 的返回值是一个整数 ,表示成功读取的变量个数。
如果没有读取任何项,或者匹配失败,则返回 0

如果在成功读取任何数据之前,发生了读取错误或者遇到读取到文件结尾,则返回常量 EOF (-1)

EOF - end of file 文件结束标志

1.3 占位符

scanf() 常用的占位符如下,与 printf() 的占位符基本一致

• %c :字符。

• %d :整数。

• %f : float 类型浮点数。

• %lf : double 类型浮点数。

• %Lf :long double 类型浮点数。

• %s :字符串。

• %[ ] :在方括号中指定一组匹配的字符(比如%[0-9]),遇到不在集合之中的字符,匹配将会停止。

上面所有占位符之中,除了 %c 以外,都会自动忽略起首的空白字符

%c 不忽略空白字符,总是返回当前第⼀个字符,无论该字符是否为空格。

如果要强制跳过字符前的空白字符,可以写成 scanf(" %c", &ch) ,即 %c 前加上一个空格,表示跳过零个或多个空白字符。

下面要特别说一下占位符 %s,它其实不能简单地等同于字符串。它的规则是,从当前第一个非空白字符开始读起,直到遇到空白字符(即空格、换行符、制表符等)为止。 因为 %s不会包含空白字符,所以无法用来读取多个单词,除非多个 %s 一起使用。这也意味着,scanf()不适合读取可能包含空格的字符串,比如书名或歌曲名。另外, scanf() 遇到 %s 占位符,会在字符串变量末尾存储⼀个空字符 \0

scanf() 将字符串读入字符数组时,不会检测字符串是否超过了数组长度。所以,储存字符串时,很可能会超过数组的边界,导致预想不到的结果。为了防止这种情况,

使用 %s 占位符时,应该指定读入字符串的最长长度

,即写成 %[i]s ,其中的 [i] 是一个整数表示读取字符串的最大长度,后面的字符将被丢弃

c 复制代码
#include <stdio.h>
int main()
{
 char name[11];
 scanf("%10s", name);
 
 return 0;
}

上面例子中, name 是一个长度为11的字符数组, scanf() 的占位符 %10s 表示最多读取用户输入的10个字符,

为什么是10个字符呢?因为上面说到过scanf() 遇到 %s 占位符,会在字符串变量末尾存储⼀个空字符
\0,所以11减掉一个\0,就剩10个字符了。

而后面的字符将被丢弃,这样就不会有数组溢出的风险了。

1.4 赋值忽略符

有时,用户的输入可能不符合预定的格式。

c 复制代码
#include <stdio.h>
int main()
{
 int year = 0;
 int month = 0;
 int day = 0;
 scanf("%d-%d-%d", &year, &month, &day);
 printf("%d %d %d\n", year, month, day);
 return 0;
}

上面例子中,如果用户输入 2024-11-5 ,就会正确解读出年、月、日。问题是用户可能输入其他格式,比如 2024/11/5 ,这种情况下, scanf() 解析数据就会失败。

为了避免这种情况, scanf() 提供了⼀个赋值忽略符(assignment suppression character) * 。

只要把 * 加在任何占位符的百分号后面,该占位符就不会返回值,解析后将被丢弃。

c 复制代码
#include<stdio.h>
int main()
{
 int year = 0;
 int month = 0;
 int day = 0;
 scanf("%d%*c%d%*c%d", &year, &month, &day);
 return 0;
}

上面例子中, %*c 就是在占位符的百分号后面,加入了赋值忽略符 * ,表示这个占位符没有对应的变量,解读后不必返回。

(重要)关于Visual studio环境下scanf不安全解决办法

举个例子:

c 复制代码
#include<stdio.h>
int main()
{
	int a = 0;
	scanf("%d", &a);
	printf("%d", a);
	return 0;
}

在 Visual studio 的环境,如果你直接使用scanf函数,可能会遇到下列这样情况导致程序无法正常运行:

来看看下面这一行错误提示:

错误 C4996 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. test_2024_11_09 D:\code\c-language-basic-code\test_2024_11_09\test_2024_11_09\test 2024 11 9.c 6

从中我们可以知道两个信息:

1.scanf不安全,可以使用scanf_s来代替

2.可以使用_CRT_SECURE_NO_WARNINGS来禁用警告

这里我们建议使用第二种方法,我们可以在代码的最上方,像这样:

我们在第一行添加**#define _CRT_SECURE_NO_WARNINGS 1**

当然,我们也有一劳永逸的方法

我们可以下载一个everyting软件 (可以私信我要这个软件),然后找到图中的这个文件,我们先打开这个文件的目录

然后复制一个到桌面上然后用记事本打开 ()

在记事本中输入这一串字符一般没必要手敲输入,复制粘贴就可以了

最后把文件复制回去替换就可以了


这样就完美解决啦!

最后的最后,我们来做一道题:题目链接

题目比较简单(不会的也可以私信问我),就直接给参考做法吧:

c 复制代码
#include <stdio.h>

int main() 
{
    int a= 0;
    int b= 0;
    int shan = 0;
    int yushu = 0;
         scanf("%d %d",&a,&b);
         shan=a/b;
         yushu=a%b;
       printf("%d %d",shan,yushu);
    return 0;
}

结尾

这一课的内容就到这里了,下节课继续学习C语言的分支
如果内容有什么问题的话欢迎指正,有什么问题也可以问我!

相关推荐
Lee川20 小时前
优雅进化的JavaScript:从ES6+新特性看现代前端开发范式
javascript·面试
Lee川1 天前
从异步迷雾到优雅流程:JavaScript异步编程与内存管理的现代化之旅
javascript·面试
晴殇i1 天前
揭秘JavaScript中那些“不冒泡”的DOM事件
前端·javascript·面试
绝无仅有1 天前
Redis过期删除与内存淘汰策略详解
后端·面试·架构
绝无仅有1 天前
Redis大Key问题排查与解决方案全解析
后端·面试·架构
AAA梅狸猫1 天前
Looper.loop() 循环机制
面试
AAA梅狸猫1 天前
Handler基本概念
面试
Wect1 天前
浏览器缓存机制
前端·面试·浏览器
掘金安东尼1 天前
Fun with TypeScript Generics:玩转 TS 泛型
前端·javascript·面试
掘金安东尼1 天前
Next.js 企业级落地
前端·javascript·面试