读入字符串函数的几个要点

1.
摘自百度: gets()函数用来从标准输入设备(键盘)读取字符串直到换行符结束,但换行符会被丢弃,然后在末尾添加'\0'字符。其调用格式为:

    gets(s);

其中s为字符串变量(字符串数组名或字符串指针)。

gets从标准输入设备读字符串函数,其可以无限读取,不会判断上限,以回车结束读取,所以程序员应该确保buffer的空间足够大,以便在执行读操作时不发生溢出。


    这样的话, 那gets到底能不能读入换行符呢
我试过一些代码:
#include <stdio.h>
  int main(void) 
  {
  	int a;
  	char b[40];
  	scanf("%d",a);
  	gets(b);
  	printf("%s",b);
    return 0;
 }

运行结果为:


输入1后,程序便结束,说明gets()已经将换行符读入了,那么实践证明能够这样,关键是原理是如何,即缓冲区的作用原理是什么?

  而且,我修改了一下代码:

      

#include <stdio.h>
  int main(void) 
  {
  	char a[40];
  	char b[40];
  	gets(a);
  	gets(b);
  	printf("%c",b[2]);
     return 0;
 }

    运行结果为:

  

修改之后,第二个gets便不会读入换行符,这又是为什么?

 先对第一个代码的解释与疑问:

    第一段已经说明了,gets函数是会把换行符读入然后舍弃并换成'\0'这个字符,我们可以试验:

 
#include <stdio.h>
  int main(void) 
  {
  	int a;
  	char b[40];
  	scanf("%d",a);
  	gets(b);
  	printf("%d",b[0]);
    return 0;
 }

   运行结果:

 

 可以看出,字符串数组b的第一个元素的ASC2码的值便是0,即'\0'的ASC2码值。

那么这样就更能解释第二个代码了,第一个gets已经将换行符读入了,所以第二个gets就读不到第一串字符的换行符了。

  ①但是这样我就更加对缓冲区有疑问了,它的作用原理到底是什么?

     按下回车后,到底什么会留在缓冲区,什么会被刷新呢?

    现在我对这个问题还不是很理解,希望大家能指点一二。

ps:摘自百度:gets()函数读取到\n(我们输入的回车)于是停止读取,但是它不会把\n包含到字符串里面去。然而,和它配合使用的puts函数,却在输出字符串的时候自动换行。


2.

代码:

#include <stdio.h>
  int main(void) 
  {
    char a[3] ;
    int b;
    scanf("%d",&b);
    scanf("%s",a);  	
    printf("%d",b);
  return 0;
  }

从中

  1.用scanf("%s",a)不会读入换行符(再输入b以后,应该还有一个换行符,如果是gets,应该会吃掉这个换行符)

  2.数组越界后,输出还是和输入的一样(查过一些资料,有时候可能会出错)

这里猜测,第二点是因为,数组越界后,以后的数据可能会保存到这段内存之外的内存区,(有时候出错可能是因为内存之外的内存区被系统禁用),但是我无法具体解释b的值。

 在这里便区别一下scanf(“%s”)和gets:

摘自百度:

1、 gets功能为读入一行,并将换行符转换为字符串结束符。
2、 scanf("%s",s);读入时,遇到空白字符,包括空格,制表符,换行符时均会停止输入。

从功能上可以看出不同之处:
1 终止条件不同。gets只有遇到\n时才会结束输入,而scanf遇到空格或制表符时,也会结束输入。
比如输入"test string\n"。
用gets得到的字符串为"test string", 二用scanf得到的是"test"。

2 终止后,对终止字符处理不同。
比如输入为"test\nabcd"。
执行gets后,\n不会留在缓冲区中,即这时调用getchar得到的字符是'a'。
执行scanf后,\n会留在缓冲区,这时调用getchar得到的字符是'\n'。

问题:②这一节中的代码里,scanf("%s”,a)是不会把上一次输入留下的换行符读入的,为什么?(为什么gets可以读入换行符呢呢)

在这里我解释不了,希望大家指点。

  


3.返回值:

 gets返回值: 摘自百度:读入成功,返回与参数buffer相同的指针;读入过程中遇到EOF(End-of-File)或发生错误,返回NULL指针。所以在遇到返回值为NULL的情况,要用ferrorfeof函数检查是发生错误还是遇到EOF。

 所以返回一个指针,因此有一个语句应该这样写:

while (gets(c)!=NULL)

而不是

while (gets(c)!=EOF)



4.gets函数的危害:

   摘自百度: 本函数可以无限读取,不会判断上限,所以程序员应该确保buffer的空间足够大,以便在执行读操作时不发生溢出。如果溢出,多出来的字符将被写入到堆栈中,这就覆盖了堆栈原先的内容,破坏一个或多个不相关变量的值。这个事实导致gets函数只适用于玩具程序,为了避免这种情况,我们可以用fgets(stdin) (fgets实际上可以读取标准输入(即大多数情况下的键盘输入),具体参阅fgets词条)来替换gets()。在V7的手册(1979年)中说明:为了向后兼容,gets删除换行符,gets并不将换行符存入缓冲区

   顺水推舟,介绍一下fgets和gets_s,

gets_s:

  摘自百度:

#include <stdio.h>    //这个头文件包含gets()函数,这个函数在ISO/IEC 9899 2011(C11)标准中被移除
int main(void)
{
    char str1[5];  //不要char*p,然后gets(p),这是错误的,因为p没有指向有效的内存,它可能指向任何非法地址                   //     地方的未知大小的内存块,这样以来,就可能修改了不属于本程序的内存的内容
    gets(str1);
    printf("%s\n", str1);
    return 0;
}
 
#include <stdio.h>//gets_s()用法
#define CH 20
int main(void)
{
    char ch[CH];
    printf("请输入你的名字:\n");
    gets_s(ch,CH);             //这里不能用gets_s(ch);
    printf("这是你的名字:%s\n", ch);
    return 0;
}

反正我的编译器版本还没跟上这个函数


fgets:

  摘自百度:

函数原型
char *fgets(char *buf, int bufsize, FILE *stream);
参数
*buf: 字符型指针,指向用来存储所得数据的地址。
bufsize: 整型数据,指明存储数据的大小。
*stream: 文件结构体指针,将要读取的文件流。
返回值
     1.成功,则返回第一个参数buf;
     2. 在读字符时遇到end-of-file,则eof指示器被设置,如果还没读入任何字符就遇到这种情况,则buf保持原来的内容,返回NULL;

     3. 如果发生读入错误,error指示器被设置,返回NULL,buf的值可能被改变。

fgets相比于gets有一个显著的差别就是fgets会将行末的换行符算到读入的字符串里面。所以相同且正常(输入无错误,缓冲区够大)的情况下,fgets读入的字符串会比gets在末尾'\0'前面多一个换行符

      代替gets:

char a[4];
fgets(a,sizeof(a),stdin);

   好处:读取指定大小的数据,避免gets函数从stdin接收字符串而不检查它所复制的缓存的容积导致的缓存溢出问题。


但是,这里有一个问题,fegets会不会读上一个换行符?

   和gets一样,会,解决办法就是刷新缓冲区(fflsuh(stdin))或者加一个getchar().

 

   



 







  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值