scanf

时间:2024-10-14 07:08:45

用于,给变量输入值

#include <stdio.h>
int main()
{
	int score = 0;//成绩 
	printf("请输入一个值:");
	scanf("%d", &score); //& 取地址操作符 
	printf("score = %d\n", score);
	return 0;
}

注意

如果此时使用的是VS,则会报错

在这里插入图片描述
意思为: scanf函数可能是不安全的,考虑使用scanf_s函数来替代
scanf_s函数是VS种msvc这个编译器提供的函数,不是C语言本身的库函数
如果在代码中使用scanf_s函数,那这个代码只能在VS上编译,不具有跨平台性

解决办法:使用_CRT_SECURE_NO_WARNINGS

将:

#define _CRT_SECURE_NO_WARNINGS 1

放到代码的第一行(#include之前),1可以省略

  • 如果每次使用scanf函数时都要加这个代码,会比较繁琐,下面介绍一个一劳永逸的办法

目标:在创建.c文件的时候,自动在第一行加上这句话

原理:.c/.cpp的文件在新建的时候,都是拷贝了一个文件 newc++file.cpp
故应在该文件的第一行加上这句话,那么产生的新文件中就会自动有这个代码

1.使用everything,查找newc++file.cpp
在这里插入图片描述
2.单击鼠标右键,找到打开路径,找到这个文件

在这里插入图片描述

3.单击右键,找到在记事本中编辑

在这里插入图片描述
4.将这句代码放入即可

在这里插入图片描述
也可以在VS中打开
在这里插入图片描述
CTRL+S保存
在这里插入图片描述
保存
在这里插入图片描述

在这里插入图片描述
没有权限
此时,CTRL+C拷贝newc++file.cpp这个文件,将它放到桌面上
再将其用VS打开,添加那句代码,保存
但是此时这个文件还在桌面上,应当将其拷贝回去
在这里插入图片描述
替换成功之后,就会变为1KB
在这里插入图片描述
重新打开VS即可
如果在新建项的时候需要这一语句,需要 显示所有模板,否则没有
在这里插入图片描述

接下来我们回到对scanf()的说明:

例:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
	char arr[5];
	scanf("%s",arr);//arr是数组名,数组名就是地址 
	printf("%s",arr);
	return 0;
}
  • 输入一个少于五个字符的字符串:

在这里插入图片描述

  • 输入一个多于五个字符的字符串:

在这里插入图片描述

如果输入的字符串太长,arr无法存储,scanf依然会将数据存放在arr中,就可能存在非法访问内存

scanf的基本用法

scanf()函数用于读取用户的键盘输入。
程序运行到这个语句时,会停下来,等待用户从键盘输入
用户输入数据按下回车键后, scanf( )就会处理用户的输入,将其存入变量。
它的原型定义在头文件 stdio.h
scanf()的语法跟printf()类似

int i=e;
scanf("%d",&i);|

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

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

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

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

读取多个值:

scanf("%d%d%f%f", &m,&n,&x,&y);

上面示例中,格式字符串 %d%d%f%f,表示用户输入的前两个是整数,后两个是浮点数这四个值依次放入m,n、x、y四个变量

scanf() 处理数值占位符时,会自动过滤空白字符,包括空格、制表符、换行符等。
所以,用户输入的数据之间,有一个或多个空格不影响scanf()解读数据
另外,用户使用回车键,将输入分成几行,也不影响解读

每次按下回车键以后,scanf()就会开始解读,如果第一行匹配第一个占位符,那么下次按下回车键时,就会从第二个占位符开始解读

scanf()处理用户输入的原理是,用户的输入先放入缓存,等到按下回车键后,按照占位符对缓存进行解读。解读用户输入时,会从上一次解读遗留的第一个字符开始,直到读完缓存,或者遇到第一个不符合条件的字符为止

#include <stdio.h>
int main()
{
	int x;
	float y;
	//用户输入"	-13.34e12# 0"	
	scanf("%d", &x);
	printf("%d\n", x);
	scanf("%f", &y);
	printf("%f\n", y);
	return 0;
}

输出如下:

在这里插入图片描述

为什么会出现这种输出呢?

因为x是整数,所以读到.就会停止,故x里为-13
从上一次读到的位置继续往右走
因为y是浮点数,所以读到#时就会停止

scanf的返回值

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

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

#include <stdio.h>
int main()
{
	int a=0;	
	int b=0;	
	float f = 0.0f;	
	int r = scanf("%d %d %f",&a,&b, &f);
	printf("a=%d b=%d f=%f\n",a,b,f);	
	printf("r = %d\n",r);	
	return 0;	
}

输入输出测试:

输入:2 3 #
输出:
在这里插入图片描述
f为浮点数,但是输入了#,#没有被读取,故scanf返回值为2

输入:3个CTRL+Z(VS中)
输出:读取失败
在这里插入图片描述
要想让scanf在读取任何数据之前,就读取失败,按CTRL+Z

在**Devc++**中,输入一个CTRL+Z即可
在这里插入图片描述
多组输入的题目中,会使用到scanf的返回值

scanf()的占位符

scanf()的占位符和printf()的占位符基本一致

常用的占位符:

  • %c:字符
    %d:整数
    %f:float类型浮点数
    %lf: double 类型浮点数
    %Lf: long double类型浮点数
    %s: 字符串。
    %[ ]:在方括号中指定一组匹配的字符(比如%[0-9]),遇到不在集合之中的字符,匹配将会停止

上面所有占位符之中,除了%c以外,都会自动忽略起首的空白字符
%c 不忽略空白字符,总是返回当前第一个字符,无论该字符是否为空格

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

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	char a= 0;
	scanf("%c", &a);
	printf("---%c---\n", a);
	return 0;
}

在这里插入图片描述
此时读取的是第一个空格

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	char a= 0;
	scanf(" %c", &a);//在%c前加一个空格,可以在读取到有效字符之前,跳过前面的空格
	printf("---%c---\n", a);
	return 0;
}

此时读取到的是x
在这里插入图片描述

%s不能简单地等同于字符串
它的规则是,从当前第一个非空白字符开始读起,直到遇到空白字符(即空格、换行符、制表符等)为止

因为%s不会包含空白字符,所以无法用来读取多个单词,除非多个%s一起使用。这也意味着,scanf()不适合读取可能包含空格的字符串
另外,scanf()遇到%s占位符,会在字符串变量末尾存储一个空字符\0

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	char arr[20];
	scanf(" %s", arr);
	printf("%s\n", arr);
	return 0;
}

没有空格时:

在这里插入图片描述
abcdef\0

有空格时:

在这里插入图片描述
abc\0

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

为了防止这种情况,使用%s占位符时,应该指定读入字符串的最长长度,即写成 %[m]s
[m]是一个整数,表示读取字符串的最大长度,后面的字符将被丢弃

#include <stdio.h>
 int main()
 {
	char name[11];	
	scanf("%10s",name);	

	return	0;
}

上面示例中,name是一个长度为11的字符数组,scanf()的占位符%10s表示最多读取用户输入的10个字符,后面的字符将被丢弃,这样就不会有数组溢出的风险了

赋值忽略符

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

#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;	
}

输入格式正确:
在这里插入图片描述

输入格式错误:
因为year,month,day都是整型,所以在读取到/时就已经停止了,/后面内有被读取到,所以month和day都为0
在这里插入图片描述

另一个例子:

#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;	
}

错误输入:

在这里插入图片描述
正确输入:

在这里插入图片描述

scanf函数中指定的格式,要和输入的数据的格式严格匹配才可以正确读取数字

为了避免这种情况,scanf()提供了一个赋值忽略符(assignment suppression character).
只要把*加在任何占位符的百分号后面,该占位符就不会返回值,解析后将被丢弃

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	int year = 0;
	int month = 0;
	int day = 0;
	scanf("%d%*c%d%*c%d", &year, &month, &day);	
	printf("%d/%d/%d\n", year, month, day);
	return 0;
}

在这里插入图片描述

在这里插入图片描述
%*c就是在这个占位符的百分号后面,加入了赋值忽略符 *,表示这个占位符没有对应的变量,解读后不必返回

ps:又到周末啦!开心
制作不易,继续关注博主,跟着博主一起学习吧!

最后:

**

“以清净心看世界,以欢喜心过生活,

以平常心生情味,以柔软心除挂碍。

“没有销声匿迹,我在,热爱生活~ ”

**