[英]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.