【问题标题】:can anyone tell me what mgetline is doing in ? i cant understand谁能告诉我 getline 在做什么?我无法理解
【发布时间】:2021-09-11 13:43:01
【问题描述】:

我无法理解 mgetline 在这段代码中的作用。 谁能帮帮我?

int mgetline(char s[],int lim)
{
    int c, i;
    
    for(i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
        s[i] = c;
    
    if(c == '\n')
    {
        s[i] = c;
        ++i;
    }
    
    s[i] = '\0';

    return i;
}

【问题讨论】:

  • 它具有额外的好处,您可以指定要读取的字符数,这样您就不会溢出输入缓冲区。此外,它确保字符串以空值结尾。有没有让你难以理解的台词?
  • getchar() 调用中可以看出,该函数读取了一些输入。为了您在学习 C 方面的进步,最好尽可能自己分析代码并提出具体问题。您还可以在调试器中逐步运行您的程序,看看它是如何工作的。不幸的是,for 循环可能难以调试,因为在 for 语句中组合了多个条件。
  • 它用一行文本加载传递的数组。你到底有什么不明白的?
  • 注意,当 lim 为 1 时,可能存在缓冲区溢出。c 应初始化为非 \n 的任何值。

标签: c algorithm


【解决方案1】:

该函数基本上从标准输入流stdin 中一个接一个地读取字符,直到您输入\n(换行符)或达到slim 的数组限制。字符存储在char s[] 中,并返回读取内容的长度。

很难更详细地回答,因为有点不清楚你不明白什么,但我尝试对代码进行注释以使其更清晰。

这是相同的代码,只是重新格式化以适合我的 cmets。

int mgetline(char s[], int lim) {
    int c, i;
    
    for(i = 0;                // init-statement, start with `i` at zero
        i < lim - 1           // condition, `i` must be less than `lim - 1`
        &&                    // condition, logical AND
        (c = getchar()) !=EOF // (function call, assignment) condition, `c` must not be EOF
        &&                    // condition, logical AND
        c != '\n';            // condition, `c` must not be `\n` (newline)
        ++i)                  // iteration_expression, increase i by one
    {
        s[i] = c;             // store the value of `c` in `s[i]`
    }

    if(c == '\n') {           // if a newline was the last character read
        s[i] = c;             // store it
        ++i;                  // and increase i by one
    }
    
    s[i] = '\0';              // store a null terminator last

    return i;                 // return the length of the string stored in `s`
}

for 循环的condition 部分中,您有3 个条件必须全部为true,循环才能进入语句for(...;...;...) statement。我已将该语句放入代码块中,以便更容易查看范围。 EOF 是一个特殊值,如果输入流 (stdin) 关闭,则由 getchar() 返回。

注意:如果您传递 一个 char (lim == 1) 的数组,此函数将导致 未定义的行为。任何读取未初始化变量的程序都有未定义的行为 - 这是一件坏事。在这种情况下,如果lim == 1,您将在循环后读取c,然后c 仍将未初始化。

要么初始化它:

int mgetline(char s[], int lim) {
    int c = 0, i;

或退出该功能:

int mgetline(char s[], int lim) {
    if(lim < 2) {
        if(lim == 1) s[0] = '\0';
        return 0;
    }
    int c, i;

【讨论】:

  • 如果出现文件结尾或读取错误,字符的读取也会停止。
  • @PaulHankin EOF 在评论部分的右侧。 “c 不能是 EOF” - 我试图在下面的文字中解释 EOF 是什么。正常的文件结尾和读取错误都会使其返回EOF,因此它涵盖了这两种情况。
  • 关于 lim==1,如果变量 c 没有被初始化,并且碰巧等于 \n,那么两个字节被写入缓冲区 s[]。