簡體   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