繁体   English   中英

如何在C中进行行输入?

[英]How to take a line input in C?

我试图在C中输入整行。最初我做了,

char line[100] // assume no line is longer than 100 letters.
scanf("%s", line);

忽略安全漏洞和缓冲区溢出,我知道这只需要一个字输入。 我又修改了

scanf("[^\n]", line);

当然,这不能超过一行输入。 但是,以下代码遇到了无限循环,

while(fscanf(stdin, "%[^\n]", line) != EOF)
{
    printf("%s\n", line);
} 

这是因为\\n从未被消耗过,它会反复在同一点停止并在line具有相同的值。 所以我将代码重写为

while(fscanf(stdin, "%[^\n]\n", line) != EOF)
{
    printf("%s\n", line);
}

对于从文件中输入的内容,这段代码运行得非常完美(或者我认为如此)。 但是对于来自stdin ,这会产生神秘,怪异,不清晰的行为。 仅在输入第二行之后,才会打印第一行。 我无法理解实际情况。

我要做的就是这个。 记下字符串,直到遇到\\n ,将其存储line ,然后从输入缓冲区使用\\n 现在打印此line并为输入的下一行做好准备。 还是我被误导了?

但是,在发布此问题时,我发现了一个更好的选择,

while(fscanf(stdin, "%[^\n]%*c", line) != EOF)
{
    printf("%s\n", line);
}

这在所有情况下均完美无缺。 但是我的问题仍然存在。 这个代码怎么来的

while(fscanf(stdin, "%[^\n]\n", line) != EOF)
{
    printf("%s\n", line);
}

对于来自文件的输入有效,但是是否导致来自标准输入的输入问题?

使用fgets() @FredK

char buf[N];
while (fgets(buf, sizeof buf, stdin)) {
  // crop potential \n if desired.
  buf[strcspn(buf, "\n")] = '\0'; 
  ...
}

尝试将scanf()用于用户输入存在许多问题,这使其易于受到滥用或代码攻击。

// Leaves trailing \n in stdin
scanf("%[^\n]", line)

// Does nothing if line begins with \n. \n remains in stdin
// As return value not checked, use of line may be UB.
// If some text read, consumes \n and then all following whitespace: ' ' \n \t etc.
//    Then does not return until a non-white-space is entered.
//    As stdin is usually buffered, this implies 2 lines of user input.
// Fails to limit input.
scanf("%[^\n]\n", line)

// Does nothing if line begins with \n. \n remains in stdin
// Consumes 1 char after `line`, even if next character is not a \n
scanf("%99[^\n]%*c", line)

通常,对EOF进行检查是错误的检查。 @Weather Vane一次输入\\ n时,由于未填充line ,因此返回0。 0 != EOF ,代码继续使用通向UB的未初始化line

while(fscanf(stdin, "%[^\n]%*c", line) != EOF)

考虑在以下输入“ 1234 \\ n”。 当第一个fscanf()读取“ 123”,扔掉“ 4”,下一个fscanf()调用陷入\\ n时,可能会发生无限循环。

while(fscanf(stdin, "%3[^\n]%*c", line) != EOF)

在检查*scanf()的结果时, 请检查所需的内容 ,而不要检查不需要的值之一。 (但即使以下情况也有其他麻烦)

while(fscanf(stdin, "%[^\n]%*c", line) == 1)

关于最接近的scanf()以读取一行

char buf[100];
buf[0] = 0;
int cnt = scanf("%99[^\n]", buf);
if (cnt == EOF) Handle_EndOfFile();
// Consume \n if next stdin char is a \n
scanf("%*1[\n]");
// Use buf;

while(fscanf(stdin, "%[^\\n]%*c", line) != EOF)
对于来自文件的输入有效,但是是否导致来自标准输入的输入问题?

发布示例代码和输入/数据文件将很有用。 在发布少量代码的情况下,可能存在某些原因。

line超限是UB
输入以\\n开头到UB
文件或stdin都不以相同模式打开。 \\r不能翻译成一个。


注意:当一行为100个字符时,以下操作失败。 因此,满足假设cal仍然会导致UB。

char line[100] // assume no line is longer than 100 letters.
scanf("%s", line);

就个人而言,我认为fgets()的设计不正确。 当我读取一行时,无论长度如何,我都希望完整读取它(填充所有RAM除外)。 fgets()不能一that而就。 如果行很长,则必须多次手动运行它,直到到达换行符为止。 在这方面,特定于glibc的getline()更方便。 这是一个模仿GNU的getline()的函数:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

long my_getline(char **buf, long *m_buf, FILE *fp)
{
    long tot = 0, max = 0;
    char *p;
    if (*m_buf == 0) { // empty buffer; allocate
        *m_buf = 16;   // initial size; could be larger
        *buf = (char*)malloc(*m_buf); // FIXME: check NULL
    }
    for (p = *buf, max = *m_buf;;) {
        long l, old_m;
        if (fgets(p, max, fp) == NULL)
            return tot? tot : EOF; // reach end-of-file
        for (l = 0; l < max; ++l)
            if (p[l] == '\n') break;
        if (l < max) { // a complete line
            tot += l, p[l] = 0;
            break;
        }
        old_m = *m_buf;
        *m_buf <<= 1; // incomplete line; double the buffer
        *buf = (char*)realloc(*buf, *m_buf); // check NULL
        max = (*m_buf) - old_m;
        p = (*buf) + old_m - 1; // point to the end of partial line
    }
    return tot;
}

int main(int argc, char *argv[])
{
    long l, m_buf = 0;
    char *buf = 0;
    while ((l = my_getline(&buf, &m_buf, stdin)) != EOF)
        puts(buf);
    free(buf);
    return 0;
}

我通常使用自己的readline()函数。 我刚才写了这个my_getline() 尚未经过全面测试。 请谨慎使用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM