[英]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 students
在class
,最簡單的方法是使用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
進一步排序,而不是在class
的strcmp
上返回,請測試結果是否不等於零,並返回該結果。 如果class
上strcmp
的結果為零,那么您只需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.