从文本文件中读取3个字符串

时间:2016-04-27 23:06:08

标签: c

我无法从一行读取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 个答案:

答案 0 :(得分:0)

继续发表评论,您为什么要使用链接列表来解决此问题?您可以使用链接列表,但开销和代码复杂性超出了要求。直接解决方案是类型students的简单动态数组。数组或重要的好处。只需拨打qsort,简单添加等,即可直接访问所有学生,简单排序。

不要误会我的意思,如果你的任务是使用链接列表,那么你应该这样做,但是你应该真正看一下{{1}类型的动态数组},您可以根据需要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.

内存错误/检查

在你的动态分配内存的任何代码中,你有2个责任关于任何分配的内存块:(1)总是保留一个指向内存块起始地址的指针,所以,(2)它可以在释放时释放它不再需要了。

必须使用内存错误检查程序,以确保您没有在已分配的内存块之外/之外写入,尝试读取或基于未初始化的值跳转,最后确认您已拥有释放了你分配的所有内存。

对于Linux $ ./bin/structstudents <dat/studentclass.txt students: Johnson, John Math Smith, Eric Biology 是正常的选择。 e.g。

valgrind

始终确认释放所有堆块 - 不可能泄漏并且同样重要错误摘要:0个上下文中的0个错误

仔细看看,如果阵列方法符合您的需求并且您有任何疑问,请告诉我。

$ 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) 成员排序

为了按classstruct students数组进行排序,最简单的方法是使用class函数。它是C库提供的标准排序功能(包括qsort)。您可以按stdio.h结构的任何成员进行排序。您甚至可以按类和名称进行排序。

新程序员与students的唯一问题是编写 compare 函数以传递给qsort,以便按所需顺序排序。 compare 函数将接收指向struct student数组中两个元素的指针。参数传递以qsort传递(实际为void *)。就像任何const void *指针一样,您必须先将其强制转换为正确的类型,然后才能取消引用它。 (在这种情况下为void)因此,您只需要一个将students *指针强制转换为void并将值传递给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); 排序后按last名称进一步排序,而不是返回class strcmp,请测试结果是否相等为零,并返回该结果。如果classstrcmp的结果为零,那么您只需class首先按return strcmp (((students *)a)->last, ((students *)b)->last);排序,但如果类相同,则按{进一步排序} {1}}。例如:

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.