深入了解一下C语言scanf()库函数

2023-11-09

目录

一、scanf函数的定义

二、scanf函数的返回值

三、scanf函数的控制符

四、scanf函数控制符的使用

1.一般用法

2.scanf()函数%[]控制符的用法

2.1%[]控制符的两种形式

2.2 "-"字符的使用

3.键盘缓冲区残余信息问题

4.scanf()函数错误输入造成程序死锁或出错的解决方法    


 声明:本人是正在学习C语言的小白一枚,以下是本人目前对scanf函数的理解,如有错误欢迎评论区指正。

一、scanf函数的定义

int scanf( const char *format [,argument]... );

scanf函数是C语言的一个库函数,它在头文件stdio.h中被定义。所以想要使用scanf必须加上#include<stdio.h>。scanf()函数的功能是按指定的格式把数据输入指定的变量中。

二、scanf函数的返回值

scanf函数返回成功读入的数据项数返回值为int型,读入数据时遇到了“文件结束”则返回EOF。例:

注意:如果scanf中%d是连着写的如“%d%d%d”,在输入数据时,数据之间不可以用逗号分隔,只能用空白字符(空格或tab键或者回车键)分隔——“1 (空格)2(tab) 3” 或 “1(tab)2(回车)3”等。若是“%d,%d,%d”,则在输入数据时需要加“,”,如“1,2,3”。

int main()
 {
	 int a, b, c;
	 int d = scanf("%d%d%d", &a, &b, &c);
	 printf("%d,%d,%d\n", a, b, c);
	 printf("scanf函数返回值=%d\n",d);
	 return 0;
 }

1.scanf函数成功读入a,b,c则函数返回3. 

 2.scanf函数只成功读入a,b则函数返回2.

3.输入错误的格式scanf函数一项也没能读入则函数返回0.

 4.错误或遇到end of file,返回值为EOF(-1).

三、scanf函数的控制符

scanf()函数的控制符太多了,以下是我从网上找到的一部分可能不够全面。

 修饰符

修饰符 意义
* 滞后赋值;示例:"%*d"
域宽 指定输入数据所占宽度(列数),域宽应为正整数 
hh b把整数读作signed char或unsigned char;示例:"%hhd" "%hhu"
ll b把整数读作long long或unsigned long long(c99);示例:"%lld" "%llu"
h,l或L "%hd"和"%hi"指示该值将会储存在一个short int中。"%ho"、"%hx"和"%hu"指示该值将会储存在一个unsigned short int中。"%ld"和"%li"指示该值将会储存在一个long中。"%lo"、"%lx"和"%lu"指示该值将会储存在一个unsigned long中。"%le"、"%lf"和"%lg"指示该值以double类型储存。将L(而非l)与e、f和g一起使用指示该值以long double类型储存。如果没有这些修饰符,d、i、o和x指示int类型,而e、f和g指示float类型;

转换说明符

转换说明符 意义
%c 把输入解释称一个字符
%d 把输入解释称一个有符号十进制整数
%e,%f,%g,%a 把输入解释称一个浮点数(%a是c99标准)
%E,%F,%G,%A 把输入解释称一个浮点数(%A是c99标准)
%i 把输入解释称一个有符号十进制整数
%o 把输入解释称一个有符号八进制整数
%p 把输入解释称一个指针(一个地址)
%s 把输入解释称一个字符串,输入内容以第一个非空白字符作为开始,并且包含直到下一个空白字符的全部字符
%u 把输入解释称一个无符号十进制整数
%x,%X 把输入解释称一个无符号十六进制整数
[] 字符集合

四、scanf函数控制符的使用

1.一般用法

#include<stdio.h>
int main()
 {
	
	 int a, b, c;
	 scanf("%d%d%d", &a, &b, &c);
	 printf("%d,%d,%d\n", a, b, c);

	 return 0;
 }

   (1) &a、&b、&c中的&是地址运算符,分别获得这三个变量的内存地址。
   (2) "%d%d%d"是按十进值格式输入三个数值。输入时,在两个数据之间可以用一个或多个空格、tab键、回车键分隔。

#include<stdio.h>
 int main()
 {
	
	 int a, b, c;
	 scanf("a=%d,b=%d,c=%d", &a, &b, &c);//假如输入1 2 3这三个数,输入格式为a=1,b=2,c=3
	 printf("%d,%d,%d\n", a, b, c);

	 return 0;
 }

 (1)scanf()的格式控制串可以使用其它非空白字符,但在输入时必须输入这些字符。

在用"%c"输入时,空格和“转义字符”均作为有效字符。

例:
scanf("%c%c%c",&c1,&c2,&c3); 
输入:a(空格)b(空格)c(回车)
结果:a→c1,(空格)→c2,b→c3 (其余被丢弃)

2.scanf()函数%[]控制符的用法

2.1%[]控制符的两种形式

#include<stdio.h>
int main() {
	char String[100] = { 0 };
	scanf("%s",String);
	printf("%s",String);
	return 0;
}

 如果想实现输入 "I am bit"这样的字符串,你会发现得不到想要的结果。因为遇到了空格只读了第一个空格前的数据。针对这种带空格的字符串,可以使用%[]控制符来实现输入。

%[]控制符有两种形式,一种是以"^"开头, %[^……],在读字符时匹配[ ]中所有字符,如果输入的字符和[ ]中的任意字符相同就结束。另一种是不带"^",%[……],在读字符时匹配[ ]中所有字符,如果输入的字符和[ ]中的任意字符不相同就结束。

#include<stdio.h>
 int main()
 {
	 char String[100];
	 scanf("%[^z]",String);//带^,当输入字符为z的时候字符串输入结束
	 printf("%s\n",String);
	 return 0;
 }

 

#include<stdio.h>
 int main()
 {
	 char String[100];
	 scanf("%[abcd]",String);//不带^,当输入字符除abcd外任意字符的时候字符串输入结束
	 printf("%s\n",String);
	 return 0;
 }

2.2 "-"字符的使用

"-"字符在其两边都有有效字符的时候表示"-"两边字符间的所有字符(按ASCLL表排序)如a-d表示abcd这四个字符,0-9表示012……9这10个字符,如果"-"只有一边有有效字符或者两边都没有有效字符则它只表示一个"-"字符。

#include<stdio.h>
 int main()
 {
	 char String[100];
	 scanf("%[^0-9]",String);//当输入字符为0 1 2 …… 9中任意字符的时候字符串输入结束
	 printf("%s\n",String);
	 return 0;
 }

3.键盘缓冲区残余信息问题

#include<stdio.h>
int main() {
	int a=0 ;
	char b=0 ;
	scanf("%d",&a);
	scanf("%c",&b);
	printf("a=%d b=%cb=%d",a,b,b);
	return 0;
}

 执行这段代码会发现scanf("%c",&b);这句不用输入数据到输入缓冲区,它自己就能拿到数据。什么原因呢?我们用printf("c=%d",b);将C用int表示出来,发现结果是 b=10 ,ASCII值为10是什么?就是换行(\n).对了,第一个scanf("%d",&a)我们打一下"Enter"键,向键盘缓冲区发去一个“回车”(\n),而\n被scanf()函数“错误”地赋给了b。
解决办法:可以在两个scanf()函数之后加个fflush(stdin);,还有加getch(); (这是别人说的,我发现在vs编译器下getch,并不会从输入缓冲区拿数据,更像是直接从键盘拿)getchar();也可以,但是要视具体scanf()语句加哪个,但是加fflush(stdin);不管什么情况都可行。

函数名: fflush 
功  能: 清除一个流 
用  法: int fflush(FILE *stream);

#include<stdio.h>
int main() {
	int a=0 ;
	char b=0 ;
	scanf("%d",&a);
	fflush(stdin);
	scanf("%c",&b);
	printf("a=%d b=%cb=%d",a,b,b);
	return 0;
}

4.scanf()函数错误输入造成程序死锁或出错的解决方法
    

//
#include <stdio.h>
int main()
{
  int a,b,c;  /*计算a+b*/
  scanf("%d,%d",&a,&b);
  c=a+b;
  printf("%d+%d=%d",a,b,c);
}
//

如上程序,如果正确输入a,b的值,那么没什么问题,但是一旦输入了错误的类型,你的程序不是死锁,就是得到一个错误的结果,这可能所有人都遇到过的问题吧?

解决方法:scanf()函数执行成功时的返回值是成功读取的变量数,也就是说,你这个scanf()函数有几个变量,如果scanf()函数全部正常读取,它就返回几。但这里还要注意另一个问题,如果输入了非法数据,键盘缓冲区就可能还个有残余信息问题。
正确的例程:

//
#include <stdio.h>
int main()
{
  int a,b,c;  /*计算a+b*/
  while(scanf("%d,%d",&a,&b)!=2)fflush(stdin);
  c=a+b;
  printf("%d+%d=%d",a,b,c);
} 
//

参考文章

scanf函数详解

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

深入了解一下C语言scanf()库函数 的相关文章

随机推荐

  • qt修改构建套件

    1 qtcreator 工具 选项 qtVersion 添加 选择要添加的qmake 2 点击构建套件 选择对应的编译器 3 选择对应的调试器 解决can not find qmake conf问题
  • Synchronized(对象锁)和Static Synchronized(类锁)的区别

    Synchronized和Static Synchronized区别 通过分析这两个用法的分析 我们可以理解java中锁的概念 一个是实例锁 锁在某一个实例对象上 如果该类是单例 那么该锁也具有全局锁的概念 一个是全局锁 该锁针对的是类 无
  • 打造万物识别之利器!微信扫一扫植物识别篇技术解析

    导语 冬去春来日渐暖 柳絮萌芽草生根 立春已过 又到了户外踏青赏花的季节 再过段时间 公园 郊外 路边各种鲜花都会渐次开放 大家踏春的时候都会拍一些好看的照片 发一些朋友圈 写一些花语 市场上也出现了不少识花app 用户下载app 拍张照片
  • 单播与多播mac地址

    MAC 地址 Media Access Control Address 是一个用于识别网络设备的唯一标识符 每个网络设备都有一个独特的 MAC 地址 用于在局域网中进行通信 单播MAC地址 单播MAC地址用于单播通信 即一对一的通信模式 当
  • static静态代码块

    static静态代码块 public class Person 静态代码块 在类加载时候执行静态代码块 只会执行一次 static System out println Person static initializer 实例初始化块 每次
  • 富文本编辑器 VUE-QUILL-EDITOR 使用教程

    一 基础用法 1 NPM 导入 VUE QUILL EDITOR npm install vue quill editor save 2 引入 VUE QUILL EDITOR 在全局中引入 import Vue from vue impo
  • 如何实现单链表任意两个元素交换(不包括表头)

    凭第一感觉写的版本 算法和思路有好的想法再优化 交换链表任意两个元素 void SwapItem LinkedList head int posA int posB 从非头结点开始交换操作 保证至少存在两个节点 assert head he
  • 教你如何用C语言做一个简单的贪吃蛇

    小时候大家可能都玩过贪吃蛇 但有没有想过自己做一个出来玩玩看 今天我们就教大家用C语言做一个简单的贪吃蛇游戏 这里没有采用图形界面去做 而是采用win32控制台 首先 先把做好的游戏初始界面和游戏截图先展示一下 游戏初始界面如图 游戏截图如
  • Vue切换路由,页面回到上一次缓存的滚动位置(代码量少,通用有效)

    需求 当切换不同路由时 期望切换后的路由页面保留上次滚动的位置 解决思路 利用路由中的meta属性 对不同路由页面滚动的位置做缓存 切换路由时 获取当前路由meta属性中缓存的滚动位置 再自动滚动到此位置即可 具体代码 router js文
  • Kali Linux安装教程

    虚拟机Vmware Worksation下Kali Linux安装教程 本次安装Vmware Worksation采用的是15 5 pro 下载kali镜像 首先进入kali官网 https www kali org 点击Downloads
  • GIT操作:把当前仓库的一个分支push到另一个仓库的指定分支

    背景 有时候我们想把当前仓库A的一个指定分支1 推给 另一个仓库B的另一个指定分支2 可以通过2个主要命令git remote xxx 和 git push newOrigin 当前分支 目标分支 完成 示例 假设有2个仓库uu和uunew
  • java什么时候需要用序列化?

    文章目录 一 Java序列化概述 二 什么时候用序列化 三 项目创建很多对象怎么优化 场景 优化思路一 加条件判断 优化思路二 使用clone浅拷贝 一 Java序列化概述 简单说就是为了保存在内存中的各种对象的状态 也就是实例变量 不是方
  • vscode 缩进,取消自动格式化,溢出不换行

    Ctrl P gt 在输入框中输入 settings json 打开第一个 取消自动换行 editor wordWrap off 代码缩进 editor tabSize 4 取消每次保存的时候自动格式化 editor formatOnSav
  • 离散数学:常用的数学符号

    x A x 是 A 的元素 x A x 不是 A 的元素 A B A 是 B 的子集 或 A 包含于 B B 包含 A A B A 是 B 的真子集 A B B 不包含 A 或 A 不包含 B A B A 与 B 有相同的元素 A B A
  • zookeeper的Linux下安装和使用 单机版/集群版

    这个是单节点的 集群的在另一篇文章里做了说明 一 解压zookeeper的tar包 二 到zookeeper的conf目录下 拷贝zoo sample cfg 为zoo cfg 记住名字必须叫zoo cfg root VM 0 7 cent
  • 【高级篇 / SDWAN】(7.0) ❀ 07. DNS 解析最快的宽带优先上网 ❀ FortiGate 防火墙

    自从配置SD WAN之后 很多人反应网速变慢了 打开网站卡半天 你有没有接到过这种投诉 其实这是因为DNS解析的原因 由于多条宽带属于不同的运营商 而运营商自带的DNS对自己宽带的解析很快 但对其它宽带就会报错 所以我们只能使用通用DNS
  • 2021-08-06

    在编译OKVIS中 执行make j8时报错的解决方法 1 根据github上OKVIS的安装步骤一步一步执行 由于github经常进不去 我就进了gitee网站查到OKVIS的安装步骤 参考链接 https gitee com bill4
  • vue 引入 二维码

    vue cli3 动态生成二维码 不带logo的 第一步 先下载插件 npm install qrcodejs2 save 第二步 在需要生成二维码的 页面 导入 import QRCode from qrcodejs2 第三步 在页面中引
  • [云原生专题-34]:K8S - 核心概念 - 网络 - Web服务器与反向代理服务器nginx入门介绍

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 https blog csdn net HiWangWenBing article details 122806880 目录 第1章 常见网
  • 深入了解一下C语言scanf()库函数

    目录 一 scanf函数的定义 二 scanf函数的返回值 三 scanf函数的控制符 四 scanf函数控制符的使用 1 一般用法 2 scanf 函数 控制符的用法 2 1 控制符的两种形式 2 2 字符的使用 3 键盘缓冲区残余信息问