(C语言)关于scanf函数,你晕了吗?我带你来打败他

        今天在写一道题时,编程结果,真的是令我头大,大家在平时可能也会遇到,所以,认真看看吧!应该会有收获的。

目录

一、题目

二、错误解答

三、出错地点

四、下面是关于scanf函数的一些相关知识

   1、scanf函数的说明:

   2、scanf函数的工作原理:

   3、scanf在输入上的特点:

   4、scanf函数使用时的注意事项:

五、出错原因:

六、解决问题的思路

七、解决方案:

方案1:

方案2:

方案3:

方案4:

方案5:

方案6:

八、正确代码

九、总结:  


一、题目

        有一个字符串,内有若干个字符, 今输入一个字符, 编写一个函数将字符串中该字符删去。

二、错误解答

起初我的代码是这样的

错误代码):

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
void Delete(char arr[], int n)
{
	char b = 0;//要删除的字符
	int i = 0;//循环
	int k = 0;
	printf("请输入想删除的字符:");
	scanf("%c", &b);
	for (i = 0; i < n; i++)
	{
		if (arr[i] != b)
		{
			arr[k] = arr[i];
			k++;
		}
	}//实现了删除
	for (i = 0; i < k; i++)
	{
		printf("%c", arr[i]);
	}//新的字符串的输出
	printf("\n");
}
int main()
{
	char arr[100]={0};
	int n=0;
	printf("请输入一串字符:");
	scanf("%s", arr);
	n = strlen(arr);//计算字符串长度
	Delete(arr, n);
	return 0;
}

        看似没有问题,那我们一起看一下运行结果:

       在这里我输入了字符串kfgg,但是我还没有来的及输入我想要删除的字符时,新的字符串都已经打印出来了。

三、出错地点

问题出现在哪儿呢?

——在scanf这儿

四、下面是关于scanf函数的一些相关知识

   1、scanf函数的说明:

        (1)、使用 scanf 时需要包含头文件stdio.h

        (2)、scanf函数是一个阻塞式函数:函数执行后,会等待用户输入。

   2、scanf函数的工作原理:

          在c的标准输入函数scanf,使用的是行缓冲的标准输入缓冲区(知道有缓冲区这个概念即可)。而我们在输入结束,其实就是按下回车键进行换行时,缓冲区不仅会有我们输入的数据,还会有我们输入的换行字符‘\n’

注:

        (1、缓冲行:我们输入的字符放入缓冲区,直到输入了回车键进行换行才进行后续操作。

        (2、当我们运用scanf函数时,需要输入字符串时,scanf并不是直接从我们的键盘上获取输入的信息,而是从缓冲区中获取信息,这个所谓的缓冲区,是我们在键盘上输入后暂时保存输入信息的地方。当对于输入的信息放在缓冲区中存在空格时,scanf函数只能获取空格前的信息(一般情况)。

   3、scanf在输入上的特点:

       (1)、scanf是先往缓冲区中写入数据,然后再把数据从缓冲区中取出。

        (2)、scanf函数的结束的标志通常有3种,遇到空格,回车,或者tab;遇到非法输入也会自动结束;或者是按照格式控制符的指定来结束,如:%5d(不要和 printf 中%5d混淆)。

        (3)、如果我们输入数据是%d,那么,其分隔符为空格,回车,tab;无论我们输入数据是空格,回车,tab等其他字符,都会被系统忽略。

        (4)、如果我们输入数据是 %s,那么,其分隔符为空格,回车,tab。

       (5)、如果我们输入的数据是%c类型时,那么就不能随意插入空格,回车,tab等其其他字符,空白字符(空格符、回车符(enter)、制表符(tab)和转义字符都会被作为有效字符。

   4、scanf函数使用时的注意事项:

       (1)、scanf()函数中格式控制后面是变量地址,而不是变量名。

       (2)、scanf函数中,除了格式控制字符串以外没有其他字符,其输入的数据用空格、tab、enter分开即可。

       (3)、scanf函数中,如果除了格式控制字符串以外还有其他的字符,那我们在输入时,其数据的对应位置也要输入相同的字符(我的表达可能不太准确),下面看一个例子,就会明白:

#include<stdio.h>
int main()
{
	int a = 0;
	int b = 0;
	printf("请输入a,b的值:");
	scanf("a=%d,b=%d", &a, &b);
	printf("a=%d,b=%d", a, b);
	return 0;
}

此时,如果我们在键盘上只输入3空格4,那输出就会出错:

我们需要输入相应位置的其他字符,如图: 

        浅浅注意一下,a=3,b=4中间有一个逗号喔!如果不想加他,就要在代码里,在scanf中把中间的逗号去掉咯!(如果把逗号换成空格,那你输入时也要在二者之间有空格)

        (4)、 最主要的一点,认真看:

          scanf()会忽略前置的空白符——(%c除外)

        什么意思呢?

        就是说你在键盘上不论敲出多少个空白符,系统依旧在等待你输入,就是因为它会忽略掉前置的所有空白符,导致缓冲区依然是空的。而scanf又是一个阻塞式函数,所以就会一直等待你输入咯!

当我们用%c格式声明,输入字符时,空格字符和转义字符都会被作为有效字符

使用"%c":

例:scanf("%c",&a);

        首先缓冲区是空的,等待你输入一个字符(%c,要求scanf一次只能读取一个字符),假设你这时输入了一个字符‘h’,然后回车,这时候缓冲区里的内容就是“h\n”,然后scanf把h拿走了,缓冲区里面还剩下了一个\n,当你下次再使用scanf("%c",&a),就会直接拿走上次遗留的\n。

五、出错原因:

了解了这些之后,再来看出错原因,就很清晰了,我们现在回到我们一开始出错的地方:

出现错误的原因:我们输入一个字符串kfgg后,scanf将我们的kfgg取走了,但是缓冲区中还存放着一个"\n",而我们下一个scanf中是%c,他一次只读取一个字符,直接将"\n"取出了,所以我们还没有来及输入,程序都已经结束。

六、解决问题的思路

缓冲区中存在着我们不想要的东西,那我们把它清除掉或者提前把他取出来就好啦!

七、解决方案:

第一个scanf后面加上以下代码

方案1:

fflush(stdin);

fflush(stdin);是主动清空缓冲区的。

fflush(stdin)在VC6上可以使用;或者保证你的编译器环境在C11以前;如果你用的是VS,这个函数只支持VS2015之前的版本(2015也用不了),其函数被取消了该功能;linux下的gcc不支持。

注:(1、不建议使用

       (2、C、C++的标准里从来没有定义过fflush(stdin)。

方案2:

setbuf(stdin,NULL);

setbuf(stdin,NULL);是使stdin输入流由默认缓冲区转为无缓冲区。

注:

(1、缓冲区没有了,缺点:效率下降!!!

(2、不建议使用

方案3:

char c_tmp;

while((c_tmp=getchar()!='\n')&&c_tmp!=EOF);

清理缓存中的垃圾数据,利用while循环,再利用getchar()函数来逐个读取键盘缓冲区剩余的字符,最后当getchar()遇到 '\n' 时,while循环条件不成立,循环结束。

这种使用的是c语言的基本语法,什么情况下都是支持的。

注:

     这里是清除了缓冲区的所有内容。

方案4:

getchar();

        getchar能向缓冲区中读取一个字节,加上它,其目的在于主动吸收掉上一个scanf执行后,遗留在缓冲区里的 "\n" 。

方案5:

在第二个scanf中加一个空格:

——>注意,所谓的第二个scanf指的是按照运行顺序来说的

具体操作:

scanf("  %c", &b);

——>空格加在%c的前面

        一般情况下是不建议大家在使用scanf时使用空格,但是在这里就不一样了,这里空格用来屏蔽空白符(空格符、回车符(enter)、制表符(tab)),也就是把第一个scanf遗留的 "\n" 屏蔽掉了。

注意:

       (1、这里会屏蔽掉前面所有的空白符,注意啊,是所有喔!所以前面遗留的 "\n" 也包含在内了呀!

       (2、养成好习惯,一定一定不要在scanf的格式控制字符串的后面加空格,

如:scanf("%c  ", &b);

方案6:

gets(arr);

把第一个scanf("%s",arr);更改为gets(arr);

        gets()函数时从标准输入设备读取字符串,以回车结束读取,使用 '\0' 结尾,回车符 '\n' 被舍弃但是并没有遗留在缓冲区。

最后来看一下正确代码吧!

八、正确代码

代码里面我用的是方案5,其他代码也在里面,只是给他们注释掉了。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
void Delete(char arr[], int n)
{
	char b = 0;//要删除的字符
	int i = 0;//循环
	int k = 0;
	printf("请输入想删除的字符:");
	scanf(" %c", &b);
	for (i = 0; i < n; i++)
	{
		if (arr[i] != b)
		{
			arr[k] = arr[i];
			k++;
		}
	}//实现了删除
	for (i = 0; i < k; i++)
	{
		printf("%c", arr[i]);
	}//新的字符串的输出
	printf("\n");
}
int main()
{
	char arr[100]={0};
	int n=0;
	printf("请输入一串字符:");
	scanf("%s", arr);
	//gets(arr);
	n = strlen(arr);//计算字符串长度
	//char c_tmp;
	//while ((c_tmp = getchar() != '\n') && c_tmp != EOF);
	// 
	//setbuf(stdin, NULL);
	// 
	//getchar();

	Delete(arr, n);
	return 0;
}

看一下结果咯:

九、总结: 

        当使用多个 scanf 时,并且当中有使用 %c 的格式控制符时,养成一个好习惯,每次使用完scanf,都在后面加上一个getchar()。

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙洋静

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值