簡體   English   中英

從文本文件中讀取 3 個字符串

[英]Reading 3 strings from a text file

我無法從一行讀取 3 個字符串,移動到下一個,並將它們正確地放入我的結構中。

我的文本文件如下所示:

- John Johnson Math
- Eric Smith Biology
- etc

我需要按學生選擇的班級來安排他們。 我應該如何讀取第一個字符串作為名稱然后是空白,第二個作為姓氏,第三個作為類並為每一行執行此操作,然后正確存儲在我的結構中? 這是我現在所擁有的:

#include <stdio.h>
#include <stdlib.h>
#define MAX 30

typedef struct students {
    char nameFirst[MAX];
    char NameLast[MAX];
    char choClass[MAX];
    struct students *next;
} Students;

int main() {
    FILE *in;
    Students *first = NULL, *New = NULL, *last = NULL, *old = NULL, *current = NULL;
    in = fopen("studenti.txt", "r");
    if (in == NULL)
    {
        printf("Cannot open file!\n");
        return 1;
    }
while (i = fgetc(in) != (int)(EOF))
{
    New = calloc(1, sizeof(Students));
    if (first == NULL)
        first = New;
    else
        last->next = New;

    j = 0;
    while (i != (int)(' '))
    {
        New->nameFirst[j++] = (char)i;
        i = fgetc(in);
    }
    New->nameFirst[j] = '\0';
}
}

繼續評論,你為什么用鏈表來解決這個問題? 您可以使用鏈表,但開銷和代碼復雜度超出了要求。 直接的方案是類型的簡單動態數組students 數組的好處還是很大的。 直接訪問所有學生,通過一次調用qsort簡單排序,簡單添加等。

不要誤會我的意思,如果你的任務是使用鏈表,通過各種手段做,但你應該看看類型的動態數組student ,在那里你可以realloc需要更多的學生你可能添加喜歡。

例如:

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

enum { MAXC = 30, MAXS = 60, MAXLN = 128 };

typedef struct students {
    char first[MAXC];
    char last[MAXC];
    char class[MAXC];
} students;

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

    students *array = NULL;
    size_t i, idx = 0, maxs = MAXS;
    char buf[MAXLN] = "";
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    /* allocate/validate maxs students in array */
    if (!(array = malloc (maxs * sizeof *array))) {
        fprintf (stderr, "error: virtual memory exhausted.\n");
        return 1;
    }

    while (fgets (buf, MAXLN, fp)) {    /* read each line into buf */
        /* separate in to struct members */
        if (sscanf (buf, "- %s %s %s", array[idx].first,
                    array[idx].last, array[idx].class) != 3)
            continue;

        if (++idx == maxs) {    /* check against current allocations */
            void *tmp = realloc (array, (maxs + MAXS) * sizeof *array);
            if (!tmp) {         /* valdate realloc array succeeded */
                fprintf (stderr, "error: realloc memory exhausted.\n");
                break;          /* or break and use existing data   */
            }
            array = tmp;        /* assign reallocated block to array */
            maxs += MAXS;       /* update current allocations size   */
        }
    }
    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    printf ("\nstudents:\n\n");     /* output formatted data   */
    for (i = 0; i < idx; i++) {
        char tmp[2 * MAXC + 2] = "";
        strcpy (tmp, array[i].last);
        strcat (tmp, ", ");
        strcat (tmp, array[i].first);
        printf (" %-60s %s\n", tmp, array[i].class);
    }
    putchar ('\n');

    free (array);   /* free all allocated memory */

    return 0;
}

注意:如果您的數據文件確實沒有以'- '開始每一行,那么只需將其從sscanf格式字符串中刪除)

示例輸入

$ cat dat/studentclass.txt
- John Johnson Math
- Eric Smith Biology
- etc.

示例使用/輸出

$ ./bin/structstudents <dat/studentclass.txt

students:

 Johnson, John                                                Math
 Smith, Eric                                                  Biology

內存錯誤/檢查

在您編寫的任何動態分配內存的代碼中,您對分配的任何內存塊都有 2 個責任:(1) 始終保留一個指向內存塊起始地址的指針,因此,(2) 當它不是時可以釋放它不再需要。

您必須使用內存錯誤檢查程序來確保您沒有在分配的內存塊之外/之外寫入,嘗試讀取或基於未初始化的值進行跳轉,並最終確認您已釋放所有內存已分配。

對於 Linux valgrind是正常的選擇。 例如

$ valgrind ./bin/structstudents <dat/studentclass.txt
==14062== Memcheck, a memory error detector
==14062== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==14062== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==14062== Command: ./bin/structstudents
==14062==

students:

 Johnson, John                                                Math
 Smith, Eric                                                  Biology

==14062==
==14062== HEAP SUMMARY:
==14062==     in use at exit: 0 bytes in 0 blocks
==14062==   total heap usage: 1 allocs, 1 frees, 5,400 bytes allocated
==14062==
==14062== All heap blocks were freed -- no leaks are possible
==14062==
==14062== For counts of detected and suppressed errors, rerun with: -v
==14062== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)

始終確認所有堆塊都已釋放——不可能發生泄漏,而且同樣重要錯誤摘要:0 個上下文中的 0 個錯誤

查看它,讓我知道數組方法是否適合您的需求以及您是否有任何問題。

class成員排序

為了數組排序struct studentsclass ,最簡單的方法是使用qsort功能。 它是 C 庫(包括stdio.h )提供的標准排序函數。 您可以按students結構的任何成員進行排序。 您甚至可以按類別和名稱排序。

新程序員對qsort的唯一問題是編寫比較函數以傳遞給qsort ,以便按所需順序對其進行排序。 比較函數將接收一個指向學生結構數組中兩個元素的指針。 傳遞的參數作為void * ( 實際上是const void * ) 傳遞。 就像任何void指針一樣,您必須先將其強制轉換為正確的類型,然后才能取消引用它。 (在這種情況下students * )因此,您只需要一個將void指針轉換為strcmp students *並將值傳遞給strcmp的函數。 例子:

int compare (const void *a, const void *b)
{ 
    return strcmp (((students *)a)->class, ((students *)b)->class);
}

唯一剩下的就是調用qsort (在代碼中的fclose之后):

qsort (array, idx, sizeof *array, compare);

然后您的輸出按類排序。

如果您想在按class排序后按last進一步排序,而不是在classstrcmp上返回,請測試結果是否不等於零,並返回該結果。 如果classstrcmp的結果為零,那么您只需return strcmp (((students *)a)->last, ((students *)b)->last); 這只是首先按class排序,但如果類相同,則按last進一步排序。 例如:

int compare (const void *a, const void *b)
{ 
    int r;
    if ((r = strcmp (((students *)a)->class, ((students *)b)->class)))
        return r;

    return strcmp (((students *)a)->last, ((students *)b)->last);
}

示例輸入

$ cat dat/studentclass.txt
- Wade Williams Biology
- John Johnson Math
- Eric Smith Biology
- etc.

示例使用/輸出

$ ./bin/structstudents <dat/studentclass.txt

students:

 Smith, Eric                                                  Biology
 Williams, Wade                                               Biology
 Johnson, John                                                Math

花時間學習qsort

暫無
暫無

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

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