关于【C语言】中scanf与getchar的用法和常见错误详解

news2024/11/15 15:41:57

写这篇博客的起因是最近博主自己学习中总是遇到类似的错误,并曾百思不得其解。
今天分享出来是希望帮助大家在写代码时避免这些错误。话不多说,我们直接开始吧!

在这里插入图片描述

君兮_的个人主页

勤时当勉励 岁月不待人

C/C++ 游戏开发


输入函数scanf与getchar

  • 一.scanf的用法
    • 1. scanf(“输入控制符”, 输入参数);
    • 2.scanf(“输入控制符非输入控制符”, 输入参数)
      • 输入多个参数
    • 3.scanf的返回值
  • 二.getchar的用法
    • 1.getchar的返回类型及使用效果
  • 三.几种常见错误详解
    • 1.不理解原理导致的错误
    • 2.输入参数不符合输入控制符要求
  • 总结
    • 参考博客

一.scanf的用法

  • 我们先来看看再MSDN里对scanf的解释
    在这里插入图片描述
    - scanf 的功能用一句话来概括就是“通过键盘给程序中的变量赋值”。
  • 下面来讲讲它的两种基本用法:

1. scanf(“输入控制符”, 输入参数);

功能:将从键盘输入的字符转化为“输入控制符”所规定格式的数据,然后存入以输入参数的值为地址的变量中。

  • 在通常情况下,我们不希望某个值是由我们程序员指定的,而是在程序运行中由用户从键盘输入的,这更能满足在日常使用时用户的需要,提高我们程序的灵活性
  • 用 scanf 即可实现即可很好的满足我们的要求:
# include <stdio.h>
int main()
{
    int n=0;
    scanf("%d", &n);  //&n 表示取变量 n 的地址,&是取地址符
    printf("n = %d\n", i);
    return 0;
}

  • 上面这个基本的程序中,有以下两点需要注意:

  • (1)我们从键盘输入的全部都是字符。比如从键盘输入 125,它表示的并不是数字 125,而是字符 ‘1’、字符 ‘2’ 和字符 ‘5’。
    操作系统在接收键盘数据时会将它当成字符来接收。这时就需要用“输入控制符”把它转化成相应的内容(如%d 是有符号十进制数 %f 是浮点数)。

  • 上面代码中的%d就是要将从键盘输入的这些合法的字符转化成对应的十进制数字。比如经过 %d 转化之后,字符 125 就是数字 125 了。

  • (2)&是一个取地址运算符,&加变量名表示“该变量的地址”,所以&n就表示变量 n 的地址。又称为“取地址n”,相当于将数据存入以变量 n 的地址为地址的变量中(即存入变量n的地址中)。也就是把转化后的数字125放到变量 n 中

  • 总的来说
    scanf 语句的意思就是:从键盘上输入字符 125,然后%d将这三个字符转化成十进制数 125,“&n” 找到变量 n 的地址,把数字 125 放到以变量 n 的地址为地址的变量中,即变量 i 中,所以最终的输出结果就是n=125。

注意:

int main()
{
	
	char n[20] = {0};
	printf("请输入:>");
	scanf("%s", n);
	}
  • 很多初学者看到这段代码可能会想:这个scanf中没有加&n,会不会是错的?
  • 恭喜你!!!---------------------------------------------------回答错误
  • 我们要透过代码看到其本质,这段代码在使用时,是把输入内容放到一个名字为n的char类型的数组里,而不是变量n中,因此当然是对的。

2.scanf(“输入控制符非输入控制符”, 输入参数)

这种用法我是墙裂建议大家在平时敲代码时不要去使用的,因为在使用过程中对用户非常不友好。但咱们这里是介绍用法,还是简单介绍一下,顺便讲讲改进的方法。

# include <stdio.h>
int main(void)
{
    int n;
    scanf("n = %d", &i);
    printf("n = %d\n", i);
    return 0;
}

  • 在 scanf 中,所有的“非输入控制符”都要原样输入。
  • 接下来我来讲讲为什么不推荐使用这种用法
  • 这种输入方法必须满足原样输入,当用户使用时,但凡输入的和你设置的格式有一点不同都不行,哪怕只是多或者少了一个空格。
  • 比如要从键盘给变量 n 赋值 123,那么必须要输入n=123才正确,少一个或者多一个都是错误的。

改进方法:

int main()
{
    int n;
    printf("请输入 n = ");
    scanf("%d", &n);
    printf("n = %d\n", n);
    return 0;
}

  • 通常在输入前我们加上类似“请输入 n = ”这种代码的目的是提示用户应该输入什么内容,改善用户的使用体验。

  • 具体效果
    在这里插入图片描述

  • 这样改进既改进了我们的输入格式,又不至于在使用scanf时出错。

输入多个参数

# include <stdio.h>
int main(void)
{
    int m, n;
    scanf("%d%d", &m, &n);
    printf("m = %d, n = %d\n", m, n);
    return 0;
}

  • 通过键盘给多个变量赋值与给一个变量赋值其实是一样的。比如给两个变量赋值就写两个 %d,然后“输入参数”中对应写上两个 “取地址变量” ;给三个变量赋值就写三个 %d,然后“输入参数”中对应写上三个 “取地址变量” ……

  • 从键盘输入数据时,给多个变量赋的值之间一定要用空格、回车或者 Tab 键隔开,用以区分给不同变量赋的值。而且空格、回车或 Tab 键的数量不限。一般使用一个空格即可。


3.scanf的返回值

  • scanf的返回值我有一篇博客有具体介绍,这里不过多缀叙,博客链接如下:关于C语言中scanf多组输入的实现

二.getchar的用法

1.getchar的返回类型及使用效果

  • getchar常用来读取字符
  • 以下为msdn中的解释
    在这里插入图片描述
int getchar(void)

返回类型为int,参数为void.

  • getchar返回的其实是字符的ASCII码值(整数)。
  • getchar在读取结束或者失败的时候,会返回EOF(end of file,本质上是-1.)。
  • 接下来通过代码简单解释一下
#include<stdio.h>
int main()
{
	int n = 0;
	while ((n = getchar()) != EOF)//判断返回值是否是EOF
	{
		putchar(n);//打印输入的n
	}

	return 0;
}

注意:

  • 使用getchar时,每次getchar只会读取一个字符
  • 如果上面的代码不用while循环的话,输入123,putchar就只会输出1。

三.几种常见错误详解

1.不理解原理导致的错误

  • 下面以getchar为例具体讲解一下这种错误的产生及解决方法
  • 代码如下:
#include<stdio.h>
int main()
{
	char password[20] = {0};
	printf("请输入密码:");
	
	scanf("%s", password);//以字符串的形式输入

	printf("请确认密码(Y/N):>");//用户输入Y/N确认
	int ch = getchar();
	if (ch == 'Y')
	{
		printf("确认成功\n");
	}
	else
	{
		printf("确认失败\n");
	}

	return 0;
}

  • 来看看这段代码运行的结果
    在这里插入图片描述
  • 嗯?什么情况,我还没输入Y或N怎么就确认失败了??

在这里插入图片描述


  • 好了,这里我就不卖关子了。
    在这里插入图片描述
  • scanf和getchar这两个输入函数,它们都是从键盘上得到我们的数据,而不是直接从键盘上来读取我们的数据。它们和键盘之间有一个区域叫输入缓冲区。所有输入的数据都会先放在输入缓冲区中。
  • 在存放输入的数据时,输入函数先来看看输入缓冲区中是否有数据,如果有,它就直接拿走并储存,而不需要从键盘再输入数据,如果输入缓冲区中什么都没有,则需要从键盘输入,再拿走。
  • 带入上面的代码试试
    在这里插入图片描述
  • 当我们输入123456时,为了把“123456”放进去,其实还敲了一个回车,因此实际上输入缓冲区中存放的是“123456\n”。

在这里插入图片描述

  • 程序继续运行,此时它把“123456”提取出来,输入缓冲区中还留有一个“\n”.
    在这里插入图片描述

  • 注意:
    程序走到这一步后,进行第二次从键盘中读取( int ch = getchar() ),此时输入缓冲区中还滞留有上次未提前出来的“\n”,因此不再从键盘上读取数据,直接把“\n”从输入缓冲区提取出来。此时ch的地址中存放的就是“\n”,显然不等于’Y’,所以输出为“确认失败”


看了上面的讲解,你弄懂了吗?接下来我们来讲讲改进方法

  • 其实改进很简单,它不是在输入缓冲区中还滞留有“\n”吗?我再使用一个输入函数把它给读走不就行啦?
int main()
{
	char password[20] = { 0 };
	printf("请输入密码:");

	scanf("%s", password);

	printf("请确认密码(Y/N):>");
	getchar();//把多余的\n取走
	int ch = getchar();
	if (ch == 'Y')
	{
		printf("确认成功\n");
	}
	else
	{
		printf("确认失败\n");
	}

	return 0;
}

在这里插入图片描述

  • 这种方法雀氏可行,但是如果这样呢?

请输入密码:12345 6(中间加空格)

在这里插入图片描述

  • ?怎么又这样了??我不是把“\n”读走了吗?
  • 解释亿下:
    在这里插入图片描述
  • 此时输入缓冲区中是这样的。

在这里插入图片描述

  • 轮到scanf来取缓冲区中的数据,当它读到空格的时候,它就不再继续往下读了(这是scanf的一个作用性质)。
  • 所以scanf就只取走了12345,而缓冲区中还剩下(空格)6\n。
    在这里插入图片描述
  • 此时,getchar()读取一个字符,它把空格给读走了,输入缓冲区中剩下6\n.
    在这里插入图片描述
  • 最后,int ch = getchar()把6给读走,不等于’Y’,于是打印“确认失败”
    在这里插入图片描述

  • 难道没有什么办法避免这种错误吗?
  • 什么话,没有办法我会把这种错误写出来吗??这不是自己打自己脸吗?
  • 解决方案
    介于输入缓冲区中一直存放有数据未被清理,我们需要把缓冲区中多余的数据先全部清走
  • 方式:
    采用一个循环,只要没读到\n,我们就一直用getchar读。
  • 代码实现如下:
#include<stdio.h>
int main()
{
	char password[20] = {0};

	printf("请输入密码:");
	scanf("%s", password);
	while ( getchar() != '\n');//把缓冲区中多余的内容全读走,直到\n停止
	printf("请确认密码(Y/N):>");
	int ch = getchar();
	if (ch == 'Y')
	{
		printf("确认成功\n");
	}
	else
	{
		printf("确认失败\n");
	}

	return 0;
}

  • 结果:
    在这里插入图片描述
  • 完美解决

在这里插入图片描述


2.输入参数不符合输入控制符要求

  • 比如以下代码:
# include <stdio.h>
int main(void)
{
    char m;
    int n;
    scanf("%c%d", &m);
    printf("m = %c, n = %d\n", m, n);
    return 0;
}

  • 不做过多解释,scanf中输入控制符要求你输入两个数据,结果你的输入参数只输入了一个,你觉得这可能正确吗?
  • 但其实对于多组输入来说,不输入正确个数的数据也有一定意义,详情可以看看我的这篇博客:关于C语言中scanf多组输入的实现
  • 需要注意的是:
  • 一但发生这种错误时,编译器可能并不会报错,但是从程序上来说它是绝对错误的,当发现异常时,一定要多多注意认真检查一下输入函数。

总结

  • 以上就是今天要讲的所有内容啦
    有任何疑问欢迎在评论区或者私信博主指出哦。

  • 大噶(家)下次见啦!

如果感觉有帮助的话不妨三连一下这个新人博主。你们的支持就是我更新的动力。

(可莉请求你们三连支持一下博主!!!点击下方评论点赞收藏帮帮可莉吧)
在这里插入图片描述

参考博客

  • C语言中scanf函数用法详解
  • 关于getchar的用法及实例解析

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/659145.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[架构之路-213]- 架构 - 架构设计过程快速概览与在线画图工具

目录 第一步&#xff1a;业务系统 &#xff08;1&#xff09;收集目标系统的用户需求 &#xff08;2&#xff09;定义用例图 第二步 领域建模 &#xff08;1&#xff09;业务流程定义 &#xff08;2&#xff09;业务功能分解 &#xff08;3&#xff09;非功能性架构&…

贝莱德出手了!

* * * 原创&#xff1a;刘教链 * * * 号外&#xff1a;今天在“刘教链Pro”发表了头条《内参&#xff1a;贝莱德向SEC申请的究竟是BTC信托还是现货ETF&#xff1f;信托和ETF的5点关键区别》&#xff0c;以及次条《私钥争夺战》&#xff0c;欢迎关注公众号“刘教链Pro”并阅读。…

mysql压缩包方式安装、data数据恢复

前言 最近电脑重装了系统&#xff0c;C盘彻底格式化了&#xff0c;但是D盘中的文件还是保留了下来。 我的MySQL的数据都在D盘了&#xff0c;想要重新恢复MySQL&#xff0c;还是很简单的&#xff1a; 重新安装Mysql将源数据拷贝到新的Mysql的data目录下 顺便记录一下MySQL压缩…

遥感数字图像处理教程复习整理

目录 01 说明 遥感影像的存储方式 BSQ方式 BIL方式 BIP方式 如何计算图像存储空间大小(字节数)&#xff1f; 简单的单位换算 计算公式 简单地 复杂地 如何查看影像的基本信息/辅助信息&#xff1f; 如何进行直方图的阈值分割&#xff1f; 辐射校正 系统辐射校正 …

SonarQube社区版安装插件实现扫描多分支

社区版不支持扫描多分支 社区版不支持扫描多分支&#xff0c;收费版才支持&#xff0c;开源社区有插件可以实现多分支的扫描 插件下载 点击此处跳转下载地址 我的SonarQube是安装的最新版本10&#xff0c;下载的插件版本也是最新的1.14.0&#xff0c;切记下载相对应支持的插件…

html学习与总结表单input系列标签

文章目录 表单标签input系列标签表单input总结button按钮标签select下拉菜单标签textarea文本域标签label标签 表单标签 input系列标签 标签属性说明inputtext文本框inputpassword密码框inputradio单选框inputcheckbok复选框 checked 默认选中inputfile文件上传 multiple 设置…

springboot整合spring-data-redis

前言 其实&#xff0c;整合是一个循序渐进的学习&#xff0c;你肯定是要了解之前底层的相关知识&#xff0c;才能够具体知道现在框架方法api到底tm有什么作用&#xff0c;所以建议先看看我之前的redis博客。 可以不看&#xff0c;但是可以以我这个为目录&#xff0c;针对性得…

python图像处理实战(二)—图像几何变换

&#x1f680;写在前面&#x1f680; &#x1f58a;个人主页&#xff1a;https://blog.csdn.net/m0_52051577?typeblog &#x1f381;欢迎各位大佬支持点赞收藏&#xff0c;三连必回&#xff01;&#xff01; &#x1f508;本人新开系列专栏—python图像处理 ❀愿每一个骤雨初…

Python接口自动化测试实战

目录 前言&#xff1a; 1.接口定义&#xff1a; 2.基本流程 3.需求分析 4.用例设计 5.脚本开发 5.3结果校验 6.结果分析 前言&#xff1a; Python是一款在自动化测试领域应用广泛的编程语言。通过使用Python的测试框架&#xff08;如unittest和pytest&#xff09;&…

【第一次】21级计科计算机组成原理课外练习

【第一次】21级计科计算机组成原理课外练习 一、判断题二、单选题三、多选题四、主观题 一、判断题 1-1 国防科技大学成功研制的“银河-II”通用并行巨型机的峰值速度超过同为国防科技大学研制的“天河一号”超级计算机。 错误 1-2 目前高端光刻机技术被荷兰ASML公司垄断&…

简要介绍 | 行人重识别 Person Re-identification

注1&#xff1a;本文系“简要介绍”系列之一&#xff0c;仅从概念上对行人重识别进行非常简要的介绍&#xff0c;不适合用于深入和详细的了解。 注2&#xff1a;“简要介绍"系列的所有创作均使用了AIGC工具辅助” 探索行人重识别技术&#xff1a;原理、挑战与未来展望 行人…

数字IC前端学习笔记:仲裁轮询(二)

相关文章 数字IC前端学习笔记&#xff1a;LSFR&#xff08;线性反馈移位寄存器&#xff09; 数字IC前端学习笔记&#xff1a;跨时钟域信号同步 数字IC前端学习笔记&#xff1a;信号同步和边沿检测 数字IC前端学习笔记&#xff1a;锁存器Latch的综合 数字IC前端学习笔记&am…

【代码阅读软件】VSCode最新版本 下载、安装、配置

目录 一、概述二、安装 VSCode 详细步骤三、基础配置3.1 安装中文插件3.2 安装其他插件 一、概述 VSCode 全称是 Visual Studio Code&#xff0c;是一款免费且开源的现代化代码编辑器&#xff0c;几乎支持所有主流开发语言的语法高亮、智能代码补全、代码片段提示、自定义快捷键…

(2023,网络修剪)探索 few-shot 图像生成中的不相容知识迁移

Exploring Incompatible Knowledge Transfer in Few-shot Image Generation 公众号&#xff1a;EDPJ 目录 0. 摘要 1. 简介 2. 相关工作 3. 基础 4. FSIG 中不兼容的知识转移 4.1 调查不相容的知识 4.2 实验设置 4.3 结果和分析 5. 建议的方法 5.1 通过网络修剪进…

SpringCloud02:Eureka

什么是Eureka&#xff1f; 基于Restful的注册中心 Eureka基本的架构 Springcloud 封装了Netflix公司开发的Eureka模块来实现服务注册与发现 (对比Zookeeper).Eureka采用了C-S的架构设计&#xff0c;EurekaServer作为服务注册功能的服务器&#xff0c;他是服务注册中心.而系统…

React从入门到实战 -组件的三大核心属性(1)state

State state是组件对象最重要的属性&#xff0c;值是对象&#xff08;可以包含多个Key-value的组合&#xff09;组件被称为状态机&#xff0c;通过更新组件的state来更新对应的页面显示&#xff08;重新渲染组件&#xff09; class MyComponent extends React.Component {rend…

023.【回溯算法】

1. 回溯算法 回溯算法也叫试探法&#xff0c;它是一种系统地搜索问题而求解的方法。回溯算法可以找出所有解的一般性&#xff0c;同时可以避免不正确的数值。一旦发现不正确的数值&#xff0c;就不再继续下一层而是返回到上一层&#xff0c;以节省时间。简单来说&#xff0c;回…

OpenVino 2023.0学习使用(1)-简介

模型制备 每一个深度学习工作流程都是从获取模型开始的。您可以选择准备一个自定义的网络&#xff0c;使用现成的解决方案并根据您的需求进行调整&#xff0c;甚至可以从在线数据库下载并运行预先训练的网络&#xff0c;例如TensorFlow Hub&#xff0c;Hugging Face&#xff0…

C++入门:类和对象(中)

目录 前言&#xff1a; 一&#xff1a;类的6个默认成员函数 二&#xff1a;构造函数(第一个成员) (1)概念 (2)特性 (3)特性的解析 ⭐特性4 ⭐特性5 ⭐特性6 ⭐特性7 三&#xff1a;初始化列表 (1)引入 (2)概念 (3)注意 四&#xff1a;析构函数(第二个成员) …

2023年软件测试的高薪机会在哪?

没入行或已经入行测试的小伙伴们&#xff0c;快看过来。来看看你们的高薪机会在哪里&#xff01; 我们先来看几个高薪招聘需求&#xff01; 高薪招聘需求1 要求看起来不是很高&#xff0c;应届生和在校生都可以&#xff0c;而且薪资达到了12K&#xff0c;14薪。 但是&#xff0…