在典型的 scanf() 呼叫中不會使用換行符

當這個程式

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

int main(void) {
    int num = 0;
    char str[128], *lf;

    scanf("%d", &num);
    fgets(str, sizeof(str), stdin);

    if ((lf = strchr(str, '\n')) != NULL) *lf = '\0';
    printf("%d \"%s\"\n", num, str);
    return 0;
}

使用此輸入執行

42
life

輸出將是 42 "" 而不是預期的 42 "life"

這是因為在 scanf() 的呼叫中沒有消耗 42 之後的換行符,並且在讀取 life 之前它被 fgets() 使用。然後,fgets() 在閱讀 life 之前停止閱讀。

為了避免這個問題,在知道線的最大長度 - 例如線上判斷系統中解決問題時 - 有用的一種方法是避免直接使用 scanf() 並通過 fgets() 讀取所有線。你可以使用 sscanf() 來解析讀取的行。

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

int main(void) {
    int num = 0;
    char line_buffer[128] = "", str[128], *lf;

    fgets(line_buffer, sizeof(line_buffer), stdin);
    sscanf(line_buffer, "%d", &num);
    fgets(str, sizeof(str), stdin);

    if ((lf = strchr(str, '\n')) != NULL) *lf = '\0';
    printf("%d \"%s\"\n", num, str);
    return 0;
}

另一種方法是在使用 scanf() 之後和使用 fgets() 之前讀取直到你擊中換行符。

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

int main(void) {
    int num = 0;
    char str[128], *lf;
    int c;

    scanf("%d", &num);
    while ((c = getchar()) != '\n' && c != EOF);
    fgets(str, sizeof(str), stdin);

    if ((lf = strchr(str, '\n')) != NULL) *lf = '\0';
    printf("%d \"%s\"\n", num, str);
    return 0;
}