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

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

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

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");
}

Jetbrains全家桶1年46,售后保障稳定

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

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] = '
#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");
}
'
; 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 = '
#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");
}
'
; ch != '\n'; ++i) { ch = getchar(); if (i >= N) { //当超出字符串长度时, 继续接受键盘输入的字符,直到输入\n为止 //这是为了防止字符串输入完成后输入的字符会被下一个需要输入的数据接收 continue; } if (ch == '\n' || i == N - 1) { str[i] = '
#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");
}
'
; 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语言中输入一个字符串时应该根据实际情况 , 灵活运用输入方法 , 并不是有缺点就不能用 .
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 进程间通信方式——共享内存「建议收藏」

    进程间通信方式——共享内存「建议收藏」进程间通信方式共享内存和与共享内存函数详解,以及模拟共享内存实现进程间通信,以及共享内存的优缺点。

  • Ubuntu下安装lrzsz「建议收藏」

    Ubuntu下安装lrzsz「建议收藏」Ubuntu安装lrzsz使用阿里云时想要上传文件到服务器,使用Xshell远程上传文件,提示安装lrzsz,所以了解一下lrzsz的安装过程在此记录一下。1、下载lrzsz压缩包#wgethttps://ohse.de/uwe/releases/lrzsz-0.12.20.tar.gz2、解压#tarzxvflrzsz-0.12.20.tar.gz   …

  • Suse发生了错误Access denied for user &#39;&#39;@&#39;localhost&#39; to&amp;

    Suse发生了错误Access denied for user &#39;&#39;@&#39;localhost&#39; to&amp;

  • LaTex数学公式_markdown怎么写数学公式

    LaTex数学公式_markdown怎么写数学公式LaTeX数学公式,包含前言,注意事项,插入公式,注释,编号,转义字符,换行与对齐,字体,空格,上下标,括号,大括号和行标,分式,开方,对数,省略号,最值,方程组和分段函数,累加和累乘,矢量,积分,极限,导数与偏导,矩阵,表格,希腊字母,运算符,戴帽符号,特殊符号,等等。

  • 对象数组(C++学习笔记 20)[通俗易懂]

    对象数组(C++学习笔记 20)[通俗易懂]一、对象数组的定义所谓对象数组,指每一个数组元素都是对象的数组,即若一个类有若干个对象,我们把这一系列的对象用一个数组来存放。对象数组的元素是对象,不仅具有数据成员,而且还有函数成员。定义一个一维数组的格式如下:类名数组名[下标表达式]与基本数据类型的数组一样,在使用对象数组时也只能访问单个数组元素,其一般形式为:数组名[下标].成员名在建立数组时,同样要调用构造函数。有几个数组元…

  • VMware下载安装教程_安装vmware虚拟机

    VMware下载安装教程_安装vmware虚拟机全网最详细的VMware虚拟机下载安装教程第一步下载虚拟机1.进入VMware官网,点击左侧导航栏中的下载,选择下拉列表中的产品下载,再点击图中标记的WorkstationPro,如下图所示。2.选择自己需要的版本和操作系统,在这里以Windows系统为例,点击转至下载,如下图所示。-3.点击转至下载后也在此处可以选择版本。选择好版本后点击立即下载。如下图所示。4.注意,需要登录之后才能下载。若无账号可点击注册后登录。如下图所示。二、安装虚拟机1.进入下载路径,双击.

发表回复

您的电子邮箱地址不会被公开。

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