2016-04-27 121 views
-4

我無法從一行讀取3個字符串,移動到下一個字符串,並將它們正確放入結構中。從文本文件中讀取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'; 
} 
} 
+1

您顯示的代碼看起來並不像真正的努力。你有沒有嘗試讀取文件?以任何方式?在那裏有很多例子,當然你可以進一步發展,而不僅僅是打開文件。或者至少做一些嘗試。 – kaylum

+0

我正在嘗試'while(fgets(name,MAX,in)!=(int)(EOF))'用指針做一些事情,但是我從編譯器得到了寫訪問衝突,我想我錯了。 –

+0

你更好地服務於創建學生數組並放下'next'指針。鏈表會使您的項目不必要地複雜化。 –

回答

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個responsibilites:(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纔能有它的排序所需的順序。 比較函數將接收一個指向你的結構student數組中的兩個元素的指針。參數傳遞爲void *(實際上爲const void *)。就像任何void指針一樣,您必須將其轉換爲適當的類型,然後才能對其進行解引用。 (在這種情況下爲students *)因此,您只需要一個將void指針轉換爲students *並將值傳遞給strcmp的函數。例如:

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

唯一剩下的(在代碼fclose後)調用qsort

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

你的輸出繼而被類排序。

然後,如果您想進一步排序由last名稱由class排序,而不是在strcmp返回爲class,試驗後,如果結果不等於零,並返回結果。如果strcmp的結果爲class爲零,那麼您只需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的時間。

+0

非常感謝你,先生,不,我不需要使用struct,我會像你說的那樣去完成它,這是一個高質量的答案,對我來說,尤其是內存部分,非常感謝! –

+0

很高興能提供幫助,每個人都需要一兩個例子來學習C,學習C的關鍵是慢下來,有很多東西需要學習,C低級控制C提供了一種方法,它是由你來決定的每一塊你使用的內存,大多數其他語言在後臺處理內存管理時遇到很大麻煩,在C中它取決於你,所以*慢下來*並花費時間來理解' char',然後是一個'char','struct'和'str數組的數組uct'等,你會做得很好。 –

+0

我像你說的那樣列出了這個列表,而且它工作得很好,我的問題是,我應該如何按照字母順序排列列表,而不是按名字排序?我應該使用哪些功能? –