缓冲及其与函数的交互?

时间:2017-06-02 05:03:39

标签: c string

在理解以下代码时我遇到了一些问题。 如果String的长度小于指定的大小(即' n' here),它是一个从键盘读取字符串的程序。

如果字符串的长度大于指定的大小,则该行上的剩余字符将被丢弃。

更具体地说,我想知道缓冲区内发生了什么以及getchar()如何读取数据而不是将其存储在缓冲区中。

char * s_gets(char * st, int n)
{
     char * ret_val;
     int i = 0;
     ret_val = fgets(st, n, stdin);

     if (ret_val) // i.e., ret_val != NULL
     {
          while (st[i] != '\n' && st[i] != '\0')
          i++;

          if (st[i] == '\n')
               st[i] = '\0';

          else // must have words[i] == '\0'
          while (getchar() != '\n')
                continue;

     }

     return ret_val;
}

1 个答案:

答案 0 :(得分:0)

代码略有缺陷,但或多或​​少地完成了概述的工作。它使用fgets()来完成大量工作。从标准输入读取最多n - 1个字符。当它返回时,有几种可能性:

  1. (EOF)没有什么可以阅读的。缓冲区中没有任何内容,但fgets()返回NULL
  2. (正常)已读取一行并将其拟合到缓冲区st中。缓冲区包含换行符。
  3. (Overlong)已读取部分行,但输入未找到换行符。
  4. (没有换行的EOF)读取了一些数据,但在检测到EOF之前没有换行。
  5. 案例1最简单:代码返回NULL。通过扫描读取的字符串来处理案例2以查找换行符。如果找到换行符,则会用空字节覆盖它。案例3同时处理;如果找到的值不是换行符,则它必须是空字节。代码进入一个循环,读取更多字符,直到读取换行符。案例4与案例3的效果类似,但是循环中的代码错误地处理了这个问题 - 它没有检测到并处理EOF,因此代码将陷入无限循环。这是一个需要修复的错误。

    getchar()循环未向缓冲区st分配任何内容 - 它不会对st进行任何更改。它继续包含由fgets()读取的空终止字符串。 getchar()循环读取并丢弃读取的不适合缓冲区的行上剩余的任何字符。

    代码应为:

    char *s_gets(char *st, int n)
    {
        assert(n > 1 && st != NULL);
        char *ret_val = fgets(st, n, stdin);
    
        if (ret_val != NULL)
        {
            int i = 0;
            while (st[i] != '\n' && st[i] != '\0')
                i++;
            if (st[i] == '\n')
                st[i] = '\0';
            else
            {
                int c;
                while ((c = getchar()) != EOF && c != '\n')
                    continue;
            }
        }
    
        return ret_val;
    }
    

    NULL或原始字符串的返回值与fgets()使用的相同,但它不是最有用的返回值。如果代码返回它读取的字符串的长度,或者如果它遇到EOF(或读取错误)则返回EOF,这将更有用。信息随时可用 - 变量i