簡體   English   中英

來自stdin的fget具有不可預測的輸入大小

[英]fgets from stdin with unpredictable input size

我正在嘗試從stdin讀取一行,但是我不知道如何正確處理輸入大小至少等於限制的情況。 示例代碼:

void myfun() {
    char buf[5];
    char somethingElse;

    printf("\nInsert string (max 4 characters): ");
    fgets (buf, 5, stdin);

    ...

    printf("\nInsert char: ");
    somethingElse = getchar();
}

現在,用戶可以做三件事:

  1. 輸入少於4個字符 (加上換行符):在這種情況下,stdin中沒有任何內容,隨后的getchar()正確等待用戶輸入;
  2. 正好輸入4個字符 (加上換行符):在這種情況下,stdin中還有一個換行符,隨后的getchar()讀取它;
  3. 輸入超過4個字符 (加上換行符):在這種情況下,stdin中至少還剩下一個字符,隨后的getchar()讀取該字符,並至少留了一個換行符。

情況23需要使用while(getchar() != '\\n')類的東西來清空stdin ,而情況1則不需要任何其他操作。 當我從閱讀的答案類似的問題和c-FAQ了解,有了解實際的情況是1或沒有描述的一個沒有標准/可移植的方法。

我做得好嗎? 還是實際上一種便攜式的方法? 還是完全不同的方法?

如果有空間, fgets函數會將換行符存儲在緩沖區中。 因此,如果字符串中的最后一個字符不是換行符,則說明您需要刷新緩沖區。

fgets (buf, 5, stdin);
if (strrchr(buf, '\n') == NULL) {
    // flush buffer
    int c;
    while ((c = getchar()) != '\n') && (c != EOF));
}

如果有人假設永遠不會讀取空字符 '\\0' ,那么@dbush答案將起作用。

如果讀取了空字符 ,則strrchr(buf, '\\n')找不到可能已經讀取的任何'\\n'

代碼可以預先設置緩沖區,以查看最后是否讀取了'\\n'

buf[sizeof buf - 2] = '\n';
if (fgets (buf, sizeof buf, stdin)) {
  if (strrchr(buf, '\n') == NULL) {
    // incomplete line read.  (the usual detection)
  } else if (buf[sizeof buf - 2] != '\n') {
    // incomplete line read with prior null character  (see below note).
  }
}

然而,C標准並未指定在buf[]讀取的數據是否保持不變,因此用某種模式預填充緩沖區不足以檢測是否讀取了空字符 '\\0'

是一種便攜式方法嗎?

最可移植的方法是使用重復調用fgetc()或類似方法代替fgets()

也許是完全不同的方法?

我建議使用fgetc()或通用但不符合C標准的getline()


另一種選擇:使用scanf("%4[^\\n]%n", buf, &n) :這很麻煩 ,但是可以使用一種便攜式方法。 即使某些字符空字符,它也會跟蹤在'\\n'之前讀取的字符數

  int n = 0;
  cnt = scanf("%4[^\n]%n", buf, &n);  // Cumbersome to get that 4 here.
  // Lots of TBD code now needed:
  // Handle if cnt != 1 (\n to be read or EOF condition)
  // Handle if n == sizeof buf - 1, (0 or more to read)
  // Handle if n < sizeof buf - 1, (done, now get \n)
  // A \n may still need to be consumed
  // Handle EOF conditions

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM