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)
全栈程序员-站长的头像全栈程序员-站长

相关推荐

  • 世界上公认最快的学习法 – 弗曼学习法

    世界上公认最快的学习法 – 弗曼学习法诺贝尔物理学奖得主-理查德·弗曼的学习方法,是世界上公认最快的学习方法,主要有四个步骤:1、选择一个你想要理解的知识;2、设想一下,你要向别人传授这个知识;3、如果过程中出现了问题,就重新回顾这个知识;4、让你的讲解越来越简单易懂。转载于:https://www.cnblogs.com/javalyy/p/10648980.html…

    2022年5月1日
  • 2k21本世代和次世代生涯一样吗_nba2k21次世代价格

    2k21本世代和次世代生涯一样吗_nba2k21次世代价格原题链接对于在中国大学MOOC(http://www.icourse163.org/ )学习“数据结构”课程的学生,想要获得一张合格证书,总评成绩必须达到 60 分及以上,并且有另加福利:总评分在 [G, 100] 区间内者,可以得到 50 元 PAT 代金券;在 [60, G) 区间内者,可以得到 20 元PAT代金券。全国考点通用,一年有效。同时任课老师还会把总评成绩前 K 名的学生列入课程“名人堂”。本题就请你编写程序,帮助老师列出名人堂的学生,并统计一共发出了面值多少元的 PAT 代金券。输入格

    2022年8月8日
  • jrebel 无效无法更换lisence

    jrebel 无效无法更换lisence

    2020年11月19日
  • CSS检测的高像素密度屏幕设备[通俗易懂]

    CSS检测的高像素密度屏幕设备

    2022年1月17日
  • Ubuntu下VLC播放器的字幕乱码问题

    Ubuntu下VLC播放器的字幕乱码问题为了为可能进入的实验室实习做准备,今天重新装上了Ubuntu,今天的安装总的来说还是顺利多了。在播放软件上,这次我选择了VLC,因为感觉mplayer虽然强大,但是始终界面不是十分友好。而VLC也是灰常强大的。但是,在Linux下播放电影时,经常会遇到乱码的问题,下面就谈谈我的经验。造成字幕乱码的原因可能有两个:1.GB字符的解码:因为Linux下中文默认采取utf-

    2022年7月15日
  • 如何修改redis的端口号_redis配置文件详解

    如何修改redis的端口号_redis配置文件详解redis修改默认端口的方法是:首先要先下载文件并解压编译及安装,安装好后全局启动并且设置密码,然后再修改端口号,最后指定运行配置即可【推荐课程:redis教程】(1)通过下面的链接进行下载,然后再用以下命令进行,解压,编译,安装下载地址:http://download.redis.io/redis-stable.tar.gztarxzfredis-4.0.9.tar.gzcdredis-4…

    2022年9月18日

发表回复

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

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