2016-04-27 123 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

我像你说的那样列出了这个列表,而且它工作得很好,我的问题是,我应该如何按照字母顺序排列列表,而不是按名字排序?我应该使用哪些功能? –