C++ scanf()函数安全性问题
scanf()是C语言中的一个输入函数。与printf函数一样,都被声明在头文件stdio.h里,因此在使用scanf函数时要加上#include <stdio.h>。(在有一些实现中,printf函数与scanf函数在使用时可以不使用预编译命令#include <stdio.h>。)它是格式输入函数,即按用户指定的格式从键盘上把数据输入到指定的变量之中。
int scanf(const char * restrict format,...);
函数的第一个参数是格式字符串,它指定了输入的格式,并按照格式说明符解析输入对应位置的信息并存储于可变参数列表中对应的指针所指位置。每一个指针要求非空,并且与字符串中的格式符一一顺次对应。
函数 scanf() 是从标准输入流stdin (标准输入设备,一般指向键盘)中读内容的通用子程序,可以说明的格式读入多个字符,并保存在对应地址的变量中。
scanf函数返回成功读入的数据项数,读入数据时遇到了“文件结束”则返回EOF。
scanf()函数安全性问题
(1)在高版本的 Visual Studio 编译器中,scanf 被认为是不安全的,被弃用,应当使用scanf_s代替 scanf。
(2) 对于字符串数组或字符串指针变量,由于数组名可以转换为数组和指针变量名本身就是地址,因此使用scanf()函数时,不需要在它们前面加上"&"操作符。
(3) 可以在格式化字符串中的"%"各格式化规定符之间加入一个整数,表示任何读操作中的最大位数。
(4) scanf函数中没有类似printf的精度控制。
如: scanf("%5.2f",&a); 是非法的。不能企图用此语句输入小数为2位的实数。
(5) scanf中要求给出变量地址,如给出变量名则会出错
如 scanf("%d",a);是非法的,应改为scanf("%d",&a);才是合法的。
(6) 在输入多个数值数据时,若格式控制串中没有非格式字符作输入数据之间的间隔,则可用空格,TAB或回车作间隔。
C编译在碰到空格,TAB,回车或非法数据(如对“%d”输入“12A”时,A即为非法数据)时即认为该数据结束。
(7) 在输入字符数据(%c)时,若格式控制串中无非格式字符,则认为所有输入的字符均为有效字符。
例如:
scanf("%c%c%c",&a,&b,&c);
输入为:
d e f
只有当输入为:def(字符间无空格) 时,才能把'd'赋于a,'e'赋予b,'f'赋予c。 如果在格式控制中加入空格作为间隔,则把'd'赋予a, ' '(空格)赋予b,'e'赋予c。因为%c 只要求读入一个字符,后面不需要用空格作为两个字符的间隔,因此把' '作为下一个字符送给b。
如
scanf("%c %c %c",&a,&b,&c);
我们用一些例子来说明一些规则:则输入时各数据之间可加空格。
#include<stdio.h>int main(void){char a,b;printf("input character a,b\n");scanf("%c%c",&a,&b);/*注意两个%c之间没有任何符号*/printf("%c%c\n",a,b);return 0;}
输入:由于scanf函数"%c%c"中没有空格,输入M N,结果输出只有M。而输入改为MN时则可输出MN两字符,见下面的输入运行情况: input character a,b
1
屏幕显示:
#include <stdio.h> int main(void) {char a,b; printf("input character a,b\n"); scanf("%c %c",&a,&b);/*注意两个%c之间的空格*/ printf("\n%c%c\n",a,b); return 0; }
本例表示scanf格式控制串"%c %c"之间有空格时, 输入的数据之间可以有空格间隔。
(8) 如果格式控制串中有非格式字符则输入时也要输入该非格式字符。
例如:
scanf("%d,%d,%d",&a,&b,&c);
其中用非格式符“ , ”作间隔符,故输入时应为:
5,6,7
又如:
scanf("a=%d,b=%d,c=%d",&a,&b,&c);
则输入应为
a=5,b=6,c=7
如输入的数据与输出的类型不一致时,虽然编译能够通过,但结果将不正确。
#include <stdio.h> int main(void) { int a; printf("input a number"); scanf("%d",&a); printf("%ld",a); return 0; }
如将scanf("%d",&a); 语句改为 scanf("%ld",&a);由于输入数据类型为整型, 而输出语句的格式串中说明为长整型,因此输出结果和输入数据不符。输出并不是输入的值。
输入数据为长整型,输入输出数据才相等。
问题一
如何让scanf()函数正确接受有空格的字符串?如: I love you!
#include <stdio.h>
int main(void)
{
char str[80];
scanf("%s",str);
printf("%s",str);
return 0;
}
I love you!
I
上述程序并不能达到预期目的。因为scanf扫描到"I"后面的空格就认为对str的扫描结束(空格没有被扫描),并忽略后面的" love you!"。值得注意的是,我们改动一下上面的程序来验证一下:
#include<stdio.h>#include<windows.h>int main(void){char str[80],str1[80],str2[80];scanf("%s",str);/*此处输入:I love you!*/printf("%s\n",str);Sleep(5000);/*这里等待5秒,告诉你程序运行到什么地方*//***不是sleep(5)*1,函数名是Sleep不是sleep。*2,Windows API中,unsigned Sleep(unsigned)应该是毫秒ms.*/scanf("%s",str1);/*这两句无需你再输入,是对stdin流再扫描*/scanf("%s",str2);/*这两句无需你再输入,是对stdin流再扫描*/printf("%s\n",str1);printf("%s\n",str2);return 0;}
I love you!
Iloveyou!
#include<stdio.h>int main(void){char str[50];scanf("%[^\n]",str);/*scanf("%s",string);不能接收空格符*/printf("%s\n",str);return 0;}
问题二
#include<stdio.h>int main(void){int a;char c;while(c!='N'){scanf("%d",&a);scanf("%c",&c);printf("a=%dc=%c\n",a,c);/*printf("c=%d\n",c);*/}return 0;}
#include<stdio.h>int main(void){int a;char c;while(c!='N'){scanf("%d",&a);fflush(stdin);scanf("%c",&c);fflush(stdin);printf("a=%dc=%c\n",a,c);}return 0;}
版本1:运行出错的程序这里再给一个用“空格符”来处理缓冲区残余信息的示例:
#include<stdio.h>int main(void){int i;char j;for(i=0;i<10;++i)scanf("%c",&j);/*这里%前没有空格*/printf("%c",j);/*在输入十个字符之后*/return 0;}
#include<stdio.h>int main(void){int i;char j;for(i=0;i<10;++i)scanf(" %c",&j);/*注意这里%前有个空格*/printf("%c",j);/*在输入十个字符之后,验证打印出来的字符是否是自己输入的最后一个字符(即输入的第十个字符)*/return 0;}
我们输入:接着,我们运行看看,首先,运行第一个版本(错误的程序)
问题三
#include<stdio.h>int main(void){int a=0,b=0,c=0,ret=0;ret=scanf("%d%d%d",&a,&b,&c);printf("第一次读入数量:%d\n",ret);ret=scanf("%d%d%d",&a,&b,&c);printf("第二次读入数量:%d\n",ret);return 0;}
正确输入的话:我们定义了a,b,c三个变量来接受输入的内容,定义了变量ret来接收scanf函数的返回值。
但是当输入内容与格式换字符串不匹配时,结果会令人大跌眼镜(仔细分析会对scanf函数和stdin流有更深入的哦):
执行到第二个scanf时,字符’b’还是与格式化字符串不匹配,stdin流仍然被阻塞,所以没有提示输入,scanf函数将0返回。
#include<stdio.h>int main(void){int a=0,b=0,c=0,ret=0;ret=scanf("%d%d%d",&a,&b,&c);printf("第一次读入数量:%d\n",ret);ret=scanf("%c%d%d",&a,&b,&c);printf("第二次读入数量:%d\n",ret);return 0;}
当把第二个scanf函数内的格式化字符串改为”%c%d%d”时,运行结果如下:
执行到第一个scanf函数时,由于输入’b’的原因scanf函数直接返回1,stdin流阻塞。
有上述问题可知,当使用scanf函数时,如果遇到一些匪夷所思的问题,在scanf函数后正确使用fflush(stdin);,清空输入缓冲区,可以解决很多问题。以本题为例:
#include<stdio.h>int main(void){int a=0,b=0,c=0,ret=0;ret=scanf("%d%d%d",&a,&b,&c);fflush(stdin);printf("第一次读入数量:%d\n",ret);ret=scanf("%d%d%d",&a,&b,&c);fflush(stdin);printf("第二次读入数量:%d\n",ret);return 0;}
问题四
#include<stdio.h>int main(void){int a,b,c;scanf("%d,%d",&a,&b);c=a+b;/*计算a+b*/printf("%d+%d=%d",a,b,c);return 0;}
#include<stdio.h>int main(void){int a,b,c;while(scanf("%d%d",&a,&b)!=2)fflush(stdin);c=a+b;printf("%d+%d=%d",a,b,c);return 0;}
fflush(stdin)这个方法在GCC下不可用。(在VC6.0下可以)补充
如果stream指向输出流或者更新流(update stream),并且这个更新流
执行的操作不是输入,那么fflush函数将把任何未被写入的数据写入stream
指向的文件(如标准输出文件stdout)。否则,fflush函数的行为是不确定的。
C和C++的标准里从来没有定义过 fflush(stdin)。
fflush(NULL)清空所有输出流和上面提到的更新流。如果发生写错误,fflush
由此可知,如果 stream 指向输入流(如 stdin),那么 fflush 函数的行为是不确定的。故而使用
fflush(stdin) 是不正确的,至少是移植性不好的。
/*此函数可以和scanf函数一起使用,但使用%c输入时要注意,即此函数只能用于缓冲区非空的情况*/#include<stdio.h>void flush(){char c;while((c=getchar())!='\n'&&c!=EOF);}intmain(void){int a,b,c;/*计算a+b*/while(scanf("%d%d",&a,&b)!=2)flush();c=a+b;printf("%d+%d=%d",a,b,c);return 0;}
#include<stdio.h>int main(void){inti,c;while(1){printf("Pleaseinputaninteger:");scanf("%d",&i);if(feof(stdin)||ferror(stdin)){//如果用户输入文件结束标志(或文件已被读完),或者发生读写错误,则退出循环//dosomethingbreak;}//没有发生错误,清空输入流。通过while循环把输入流中的余留数据“吃”掉while((c=getchar())!='\n'&&c!=EOF);//可直接将这句代码当成fflush(stdin)的替代,直接运行可清除输入缓存流//使用scanf("%*[^\n]");也可以清空输入流,不过会残留\n字符。printf("%d\n",i);}return 0;}
C++ scanf()函数安全性问题相关推荐
- scanf()函数的详解以及使用时需要注意的一些细节-C语言基础
这篇文章要探讨的是"scanf()函数的详解以及使用时需要注意的一些细节".涉及scanf()函数的应用和需要注意的问题.属于C语言基础篇(持续更新). scanf()(函数原型: ...
- scanf()函数的用法和实践
scanf()函数的用法和实践 摘要: 本文阐述了基于ANSI,Win 95,Win NT上的 C/C++语言中scanf()函数的用法,以及在实际使用中常见错误及对策. 关键词: scanf() 一 ...
- scanf 接收 空格 输入_你需要知道的scanf函数用法
scanf函数 上一节中我们讨论了,如何将整数,浮点数,字符串打印到屏幕上去.既然有输出,怎么能没有输入呢?这一节中,我们来介绍与printf相反的scanf函数. scanf的功能是将键盘输 ...
- C语言基础之--scanf函数
写代码的时候,我们可以看得出,几乎每一个C程序都会包括输入输出.输入输出是程序中最基本的操作之一.C语言本身并不提供输入输出的语句,输入输出操作是由C标准函数库中的函数来实现的.今天就先说说输入:sc ...
- C语言中的scanf()函数介绍
1.scanf函数:读取从键盘输入的数据 在C语言中,有多个函数可以从键盘获得用户输入: scanf():和 printf() 类似,scanf() 可以输入多种类型的数据 getchar().get ...
- scanf函数详解与缓冲区
1.基本信息 函数原型: int scanf( char *format, args, ...); 函数返回值: 读入并赋给args的数据个数,遇到文件结束返回EOF,出错返回0. 函数功能: sca ...
- C语言scanf函数详解
函数名: scanf 功 能: 运行格式化输入 用 法: int scanf(char *format[,argument,...]); scanf()函数是通用终端格式化输入函数,它从标准输入设 ...
- scanf函数和printf函数
C程序实现输出和输入的 主要是printf函数 和 scanf函数,这两个函数是格式输入输出 格式声明由%和格式字符组成 如%d,%f 格式字符: d格式符:用来输出一个有符号的十进制整数 c格式 ...
- c语言scarf函数原型,scanf 函数原型.doc
scanf 函数原型.doc scanf 函数原型 scanf 函数原型 int scanf( const char *format, ... ); scanf()函数是格式化输入函数,它从标准输入设 ...
最新文章
- Pytorch多进程最佳实践
- 漫漫MySQL之路(1.MySQL简介和诞生)
- spring容器的设值注入和构造注入
- 查看CentOS系统运行了多久使用uptime命令
- 一文看懂数据预处理最重要的3种思想和方法
- pytorch torch.utils.data.Dataset
- Pandas GroupBy对象 索引与迭代
- 7 款 Python 可视化工具对比
- 问答方式学 Node.js
- Python入门教程100天:Day09-面向对象进阶
- ArcGIS水文分析实战教程(13)流域提取流程
- Gantt - attachEvent事件监听 - 两个参数事件
- 最佳平方逼近 matlab,最佳平方逼近的Matlab
- web设计字体规范_适用于Web设计人员的30种高质量免费字体
- FFmpeg屏幕录制
- Java实验报告(三)
- 博士申请 | 伦敦帝国理工学院李烨教授招收智能信号处理方向全奖博士生
- 硬盘都白菜价了,可我们连卖“白菜”都不够格
- AP 外币发票付款总结
- matlab归一化函数,以及还原归一化。
热门文章
- mysql语法6_全面接触SQL语法(6)_mysql
- linux ftp 后台执行,Linux环境CENTOS下apache-ftpserver搭建配置及后台启动
- cesium js 路径_Cesium开发学习路径
- php二叉树广度插入数据,php-如何在不使用广度优先遍历的情况下找到二叉树级别k的节点数?...
- 工程制图 (零件图)
- opencv阈值化(五)
- keras从入门到放弃(七)多层感知器训练
- 梦世界服务器修改指令,我的世界梦世界有哪些指令必须知道 梦世界所有必须知道指令汇总...
- 大讲台大数据特训学习笔记
- 语音合成:模拟最像人类声音的系统