• 字符串读取引申的问题


    可能在面试的时候经常会被问到:下面的代码有问题吗?

     1 #include <stdio.h>
     2 
     3 int main(void)
     4 {
     5     char buff[10];
     6     memset(buff, 0, sizeof(buff));
     7     gets(buff);
     8     printf("%s
    ", buff);
     9 
    10     return 0;
    11 }

    答案当然是:有问题。因为这段代码存在一个隐藏很深的问题,就是它使用了gets()方法。该函数原型如下:

    char* gets(char *s)

    此方法接受一个字符数组参数,但是却没有检查此数组是否有足够的空间来拷贝数据。gets()函数是不安全的,不推荐使用,一般情况下编译器也会给出警告提示:the `gets' function is dangerous and should not be used。gets()不检查预留存储区是否能够容纳实际输入的数据。多出来的字符简单的溢出到相邻的存储区,可能会导致错误。

    所以,这里我们一般用fgets()方法更好,函数原型如下:

    char* fgets(char *s, int n, FILE *stream); 

    一般使用fgets()函数,都是读取文件当中的n-1个字符到s中,其实,此函数还有一个很好的用处就是从标准输入流中读取字符串,而且不用担心输入的字符个数超出了字符数组的大小而导致溢出的问题!要怎样做呢?如下:

    char str[10];  
    fgets(str, siezof(str), stdin); 

    值得注意的是:谨记fgets()只读取n-1个字符所以,fgets()读取到换行符、文件尾或读完n-1个字符便会进行返回。

    再来看看下面一段测试代码:

     1 #include <stdio.h>
     2 #include <string.h>
     3 
     4 int main(void)
     5 {
     6     char str[5];
     7     int  len;
     8 
     9     fgets(str, sizeof(str), stdin);
    10     len = strlen(str);
    11 
    12     printf("%d
    ", len);
    13 
    14     return 0;
    15 }

    从代码中可以看到,字符数组长度为5,那么我们使用fgets()方法最多只可以读取4个字符。但是,我们在使用strlen()读取字符串长度时还有一点小细节要注意:

    (1) 输入字符串小于n-1,使用回车结束输入

    奇怪的是,当我们输入3个字符的时候,strlen()返回的字符串长度为4,这主要是因为使用fgets()方法将回车符也写入到了数组中,此时的数组内容如下所示:

    (2) 输入字符串小于n-1,使用重定向文件内容作为输入,遇到文件为停止

    首先用记事本编辑如下所示的文本文件:

    然后,在控制台中调用该程序,并将输入重定向到刚才编写的文本文件:

    可见,如果遇到文件尾,那么strlen()能够返回正确的字符串长度。

    (3)如果输入字符串大于n-1,那么任何情况下结束,strlen()返回的长度都是n-1.

    但是,有时候我也不能确定到底会是使用手动输入还是使用文件重定向,因此,我可以在原有代码的基础上加以改进,以保证不管使用哪种方法,得到的字符串长度都是正确的:

    1 fgets(str, sizeof(str), stdin);
    2 len = (int)strlen(str);
    3 if (str[len-1] == '
    '){
    4     str[len-1] = '';
    5     --len;
    6 }
    7 printf("Get: %s of size %d
    : ", str, len);
  • 相关阅读:
    ARM标准汇编与GNU汇编
    使用友元,编译出错fatal error C1001: INTERNAL COMPILER ERROR (compiler file 'msc1.cpp', line 1786) 的解决
    C++中值传递,引用传递,指针传递
    C++命名空间的用法
    关于初始化C++类成员
    vivi的配置与编译
    C++ 容器
    vivi分区问题,及移植时需要修改的地方(转)
    基于S3C2410的VIVI移植
    拷贝构造函数什么时候调用?
  • 原文地址:https://www.cnblogs.com/xiaomanon/p/4466332.html
Copyright © 2020-2023  润新知