簡體   English   中英

如何使用 scanf 讀取文本文件中的下一行

[英]How do I read the next line in a text file using scanf

我有一個作業,我需要使用 scanf 從文本文件中讀取輸入並將輸入臨時存儲到結構中,最后使用 printf 打印。 我們不允許使用結構數組。

這是文本文件:

1010  Jose Manalo      3.5
2003  Luisa Santos     2.5
1008  Andres Espinosa  4.0

以下是給出的結構(String20 是一個 20 個字符的數組):

struct nameTag {
    String20 first;
    String20 last;
};

struct studentTag {
    int ID;
    struct nameTag name;
    float grade;
};

我的初始代碼如下所示(studentInfo 是我的 studentTag 結構變量):

scanf("%d %s %s %f", &studentInfo.ID, studentInfo.name.first, studentInfo.name.last, &studentInfo.grade);
printf("%d %s %s %.1f", studentInfo.ID, studentInfo.name.first, studentInfo.name.last, studentInfo.grade);

這當然只讀取和打印第一行

編輯(已解決):將 scanf 放入循環中直到達到 EOF 或 NULL 工作完美。 這是我所做的:

while(scanf("%d %s %s %f", &studentInfo.ID, studentInfo.name.first, studentInfo.name.last, &studentInfo.grade)!=NULL)
    printf("%d %s %s %.1f\n", studentInfo.ID, studentInfo.name.first, studentInfo.name.last, studentInfo.grade);

當您一次讀取一行時,請使用面向行的輸入函數,例如fgets()或 POSIX getline() 對於嘗試單獨使用scanf()讀取文件的新 C 程序員來說,這避免了許多陷阱。

單獨使用scanf()的問題很多,但歸結為嘗試讀取后輸入流中剩余的內容。 例如,當使用scanf()嘗試讀取整數值時,如果在數字之前遇到非數字,則會發生匹配失敗並且此時停止從輸入流中提取字符,將所有有問題的字符留在輸入中流未讀——除非您手動清空輸入流中的字符,否則只是等待在下一次嘗試讀取時再次咬您。 在讀取float作為最后一個值后, '\\n'留在未讀的輸入流中,如果在您下次讀取時,您的格式說明符不會忽略前導空格,空格將作為您的輸入。 (這只是冰山一角...)

因此,使用fgets()一次將整行讀取到適當大小的字符數組中。 這樣你一次消耗了整條線。 然后,您使用sscanf()從數據行中解析您需要的內容。 無論解析成功/失敗,您都不會影響從文件中讀取下一行數據。 數據的讀取和值的解析不再耦合在單個操作中。

將各個部分放在一起,在您的情況下,您可以執行以下操作:

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

#define MAXC  1024
#define MAXNM   20

typedef char String20[MAXNM];   /* your typedef */

struct nameTag {
    String20 first;
    String20 last;
};

struct studentTag {
    int ID;
    struct nameTag name;
    float grade;
};

int main (int argc, char **argv) {

    char buf[MAXC];     /* buffer to hold each line */
    size_t n = 0;       /* counter for number of students */
    struct studentTag std[MAXNM] = {{ .ID = 0 }};
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    /* read each line -- until array full of EOF reached */
    while (n < MAXNM && fgets (buf, MAXC, fp)) {
        struct studentTag tmp = { .ID = 0 };    /* temporary struct to fill */
        if (sscanf (buf, "%d %19s %19s %f",     /* parse value from line */
                    &tmp.ID, tmp.name.first, tmp.name.last, &tmp.grade) == 4)
            std[n++] = tmp; /* assign temp struct to array on success */
        else    /* on error */
            fprintf (stderr, "error: line format - %s", buf);
    }
    if (fp != stdin)   /* close file if not stdin */
        fclose (fp);

    for (size_t i = 0; i < n; i++)  /* output all stored student data */
        printf ("\nID: %d\nFirst: %s\nLast: %s\nGrade: %f\n",
                std[i].ID, std[i].name.first, std[i].name.last, std[i].grade);

    return 0;
}

注意:您總是通過檢查 return來驗證每個用戶輸入和每個值的解析,請參閱Henry Spencer 的 C 程序員的 10 條誡命 - 第 6 號“請注意...”

示例使用/輸出

使用dat/studenttag.txt中的dat/studenttag.txt ,您將提供文件名作為第一個參數並接收:

$ ./bin/readstudenttag dat/studenttag.txt

ID: 1010
First: Jose
Last: Manalo
Grade: 3.500000

ID: 2003
First: Luisa
Last: Santos
Grade: 2.500000

ID: 1008
First: Andres
Last: Espinosa
Grade: 4.000000

仔細檢查一下,如果您還有其他問題,請告訴我。

scanf用於從 stdin 讀取輸入流,也就是說,您可以使用的最近似的函數是 fscanf,類似於 scanf,但您可以指定要從中讀取的文件:

#include <stdio.h>

typedef char String20[20];

struct nameTag {
    String20 first;
    String20 last;
};

struct studentTag {
    int ID;
    struct nameTag name;
    float grade;
};

int main()
{
   FILE* f;
   if(!(f = fopen("file.txt", "r"))) {
       return 1;
   }

   struct studentTag studentInfo; 

   while(fscanf(f, "%d %19s %19s %f", &studentInfo.ID, studentInfo.name.first, studentInfo.name.last, &studentInfo.grade) == 4)
        printf("%d %s %s %.1f\n", studentInfo.ID, studentInfo.name.first, studentInfo.name.last, studentInfo.grade);
}

現場樣品

使用fscanf的返回來驗證是否讀取了正確數量的字段並將其用作停止參數。

請注意,對於 char 數組讀取,指定要讀取的字符串的長度很重要,例如,對於char[20]字符數組容器,您可以使用"%s19"說明符,以避免堆棧粉碎。

暫無
暫無

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

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