C语言中从键盘输入字符串时的一些问题[通俗易懂]

C语言中从键盘输入字符串时的一些问题[通俗易懂]C语言中从键盘输入字符串时的一些问题1.scanf()scanf()在输入字符串时有很大的弊端,例如:1).scanf()在从键盘读入字符时并不会根据所定义的字符数组的大小来控制读入多少个,而是从scanf()中传入的地址开始一直访问下一个元素的内存,碰见空格符或者回车符时才停止读入并存入结束符’\0’,这就有可能造成了一个在C中非常严重的问题,访问非法内存.如果…

C语言中从键盘输入字符串时的一些问题

1.scanf()

scanf()在输入字符串时有很大的弊端, 例如:
1). scanf()在从键盘读入字符时并不会根据所定义的字符数组的大小来控制读入多少个 , 而是从scanf( ) 中传入的地址开始一直访问下一个元素的内存 , 碰见空格符或者回车符时才停止读入并存入结束符’\0’ , 这就有可能造成了一个在C中非常严重的问题 , 访问非法内存 . 如果所输字符数量大于字符数组的长度 , 当scanf()将把字符存入字符数组的最后一个元素后 , scanf()还会继续往后访问内存 , 将接收的字符继续存入 , 但之后的内存是我们未申请的非法内存 , 会发生未知错误 , 例如以下代码:
2). 第二点也就是第一点中的遇到空格符停止读入并存入结束符’\0’, 也就是说scanf()存不了空格符

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define N 10
void main() { 
   
	char str1[N];
	printf("请输入字符串str1\n");
	scanf("%s", str1);
	printf("str1为:\n%s\n",str1);
	system("pause");
}

代码中 , 字符数组最多存十个元素 , 结果却输出了超过十个的字符并发生了错误程序异常终止
在这里插入图片描述

2.gets()

gets(char* str)函数 , gets()函数与scanf()类似 , 但读入时只碰见 ‘\n’才停止读入并自动加上 ‘\0’,也存在和scanf()一样的访问非法内存的可能 .

最新版本的C标准(2011年)最终将该功能从其规范中删除。该函数在C ++中已弃用(截至2011年标准,遵循C99 + TC3)。所以不建议使用gets()函数

3.fgets()

fgets(char* str, int n,stdin )函数在输入字符串时是从标准输入流中读取一个长度为(n – 1)的字符串 , 并存放到字符数组str中
其中n是要求得到的字符个数 , 但实际上只会读入(n – 1)个,在最后加一个’\0’ . 如果在读取完(n – 1)个字符之前碰见换行符’\n’ ,读入即结束, 但’\n’ 也会作为有效字符存入字符串中,然后在’\n’后再存入’\0’
1). fgets( )函数的优点是不会再像scanf()函数一样发生访问非法内存的问题 , 也可以存如scanf()存不了的空格符
2). 说起缺点 , fgets在取完(n – 1)个字符之前碰见换行符’\n’ ,’\n’ 也会作为有效字符存入字符串中,然后在’\n’后再存入’\0’
在很多时候我们都不希望有这个换行符的出现 , 只能再写代码消去这个’\n’
3). fgets()函数在连续输入多个字符串时(也不能算是fgets()函数的缺点) , 但有时也会给我们带来麻烦) , 例如:
char str1[10];
char str2[10];
在输入str1时输入了超过9个的字符如 : abcdefghigklm\n
这时我们会发现 , str2根本不需要我们重新在键盘输入 , 而是存入了 abcdefghijklm’\n’ 中的 jklm\n
此时
字符串str1是”abcdefghi”
字符串str2是”jklm”
这是因为输入str1的函数在读取标准输入流中的字符时读到 i 时读取完成 , 此时剩下的jklm\n还在缓存区静静地等待被读取
此时fgets()在输入str2时直接读取了缓冲区的 jklm\n由于遇到了’\n’(或者读入了(n – 1)个字符)再存入’\0’,此时str2的输入已经完成 , 并不需要我们再次输入 .
让我们举个例子来看一下这几个特点 :

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define N 10
#include<string.h>
void main() { 
   
	char str[N];
	char str1[N];
	char str2[N];
	printf("请输入字符串str\n");
	fgets(str, N, stdin);
	printf("请输入字符串str1\n");
	fgets(str1, N, stdin);
	printf("请输入字符串str2\n");
	fgets(str2, N, stdin);
	printf("str为:\n%s\n", str);
	printf("str1为:\n%s\n", str1);
	printf("str2为:\n%s\n", str2);
	system("pause");
}

运行时并未像scanf()那样出现越界问题导致程序异常终止的情况 , 但也输出了我们不想看到的 ‘\n’ , str2也并不是从我们再次输入的 , 而是从缓存区直接读取的
在这里插入图片描述

4. 我们也可以利用输入单个字符的函数与循环来输入一个字符串

举个例子 , 如以下代码 :

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define N 10
void main() { 
   
	char str1[N];
	printf("请输入字符串str1\n");
	for (int i = 0, ch;; ++i) { 
   
		ch = getchar();
		if (i == N - 1 || ch == '\n') { 
   
			str1[i] = '\0';
			break;
		}
		str1[i] = ch;
	}
	printf("str1为:\n%s\n", str1);
	system("pause");
}

可以看出输入也可以不越界
在这里插入图片描述
而且也不会像fgets()函数一样输入的字符串小于数组长度(n – 1)时有换行符 ‘\n’ 的问题
在这里插入图片描述
当然 , 循环形式和输入字符的函数还有其他, 例如, 用scanf(“%c”,ch) 也可以 , 这里就不一 一 举例 .

总之 , 对库函数不满意的话 , 自己也可以写一个符合自己要求的函数或代码来实现 .

例如 :

#include<stdio.h>
#include<stdlib.h>
#define N 10
void fun(char* str) { 
   
	for (int i = 0, ch = '\0'; ch != '\n'; ++i) { 
   
		ch = getchar();
		if (i >= N) { 
   //当超出字符串长度时, 继续接受键盘输入的字符,直到输入\n为止
			//这是为了防止字符串输入完成后输入的字符会被下一个需要输入的数据接收
			continue;
		}
		if (ch == '\n' || i == N - 1) { 
   
			str[i] = '\0';
			continue;
		}
		str[i] = ch;
	}
}
void main() { 
   
	char str[N];
	char str1[N];
	char str2[N];
	printf("请输入字符串str\n");
	fun(str);
	printf("请输入字符串str1\n");
	fun(str1);
	printf("请输入字符串str2\n");
	fun(str2);
	printf("str为:\n%s\n", str);
	printf("str1为:\n%s\n", str1);
	printf("str2为:\n%s\n", str2);
	system("pause");
}

如图, 即可以输入空格, 也不会越界 , 也没有从缓存区读取字符存入字符数组的问题
这里是引用

小结 :

在C语言中输入一个字符串时应该根据实际情况 , 灵活运用输入方法 , 并不是有缺点就不能用 .
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/234561.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 惠普台式机如何装系统_惠普的台式机如何用u盘安装系统

    惠普台式机如何装系统_惠普的台式机如何用u盘安装系统惠普在计算机行业是一个很有声誉的品牌,无论是台式机还是笔记本,惠普都是一款值得考虑和购买的品牌产品之一。但是当计算机系统出了问题需要重装系统时,很多人并不知道如何进行系统的重装,那么惠普的台式机如何进行重装系统呢?下面介绍一下台式小机惠普电脑怎么装系统。惠普电脑装系统步骤阅读1、打开浏览器搜索云骑士官网,找到云骑士官网并点击打开。2、在官网下载云骑士一键重装系统软件,下载后打开云骑士装机大师。3、…

    2022年8月13日
  • 大数据与云计算,物联网三者的区别和关联是_云计算侧重于数据分析

    大数据与云计算,物联网三者的区别和关联是_云计算侧重于数据分析大数据与云计算  为解决互联网应用对大规模计算能力、数据存储能力的迫切需求,云计算的概念被提出。云计算是一种分布式计算平台,通过虚拟技术将海量的硬件资源和虚拟资源虚拟成虚拟资源池,并根据需求任务的大小,向虚拟资源池获取相应的计算和存储资源。  在大数据处理的需求下,出现了许多优秀的云计算平台,例如Apache开源的Hadoop、Google的MapReduce、微软的Dryad等。  在处…

    2022年10月6日
  • jsonObject转map_java 对象转map

    jsonObject转map_java 对象转map直接上代码,实现了对嵌套的对象进行转换。privateMap&amp;lt;String,Object&amp;gt;toMap(JSONObjectobject){Map&amp;lt;String,Object&amp;gt;map=newHashMap&amp;lt;String,Object&amp;gt;();Objectvalue;Stringkey;for(Iterator&amp;lt;?&

    2022年8月23日
  • Windows 技术篇-LDSGameMaster文件夹有什么用,删除方法

    Windows 技术篇-LDSGameMaster文件夹有什么用,删除方法LDS是鲁大师的拼写,应该是用过鲁大师,偷偷给你安装的。分析:没什么用,流氓程序,还很大占地方,4个G,可以放心的卸掉。卸载方法:找到里面的卸载程序来卸载,卸载完后把文件夹删除就好了。

    2022年6月14日
  • 浅析 Laravel 底层原理:契约(Contracts)「建议收藏」

    浅析 Laravel 底层原理:契约(Contracts)

    2022年2月15日
  • Remobjects使用经验

    Remobjects使用经验RemObjectsRemObjects提示:我们相信本文是正确的,但我们不做任何保证.在此感谢Henrick写的文章,很高兴在此发表.介绍RemObjects是功能强大可扩展的远程框架;但是当考虑

    2022年7月1日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号