gpt4 book ai didi

c - 如何从FILE中加载多个 "clones"结构? C

转载 作者:行者123 更新时间:2023-11-30 20:58:30 26 4
gpt4 key购买 nike

我想学习如何从文本文件加载多个结构(许多学生:姓名、索引、地址...),如下所示:

Achilles, 9999
Hector, 9998
Menelaos, 9997
... and so on

结构可以是这样的:

struct student_t {
char *name;
int index;
}

我的尝试(不起作用;我什至不确定 fgets+sscanf 是否是一个不错的选择):

int numStudents=3; //to simplify... I'd need a function to count num of lines, I imagine
int x, y=1000, err_code=1;

FILE *pfile = fopen("file.txt", "r");
if(pfile==0) {return 2;}

STUDENT* students = malloc(numStudents * sizeof *students);

char buffer[1024];
char *ptr[numStudents];
for (x = 0; x < numStudents; x++){ //loop for each student
students[x].name=malloc(100); //allocation of each *name field
fgets(buffer, 100, pfile); //reads 1 line containing data of 1 student, to buffer
if(x==0) *ptr[x] = strtok(buffer, ",");//cuts buffer into tokens: ptr[x] for *name
else *ptr[x] = strtok(NULL, ","); //cuts next part of buffer
sscanf(ptr[x], "%19s", students[x].name); //loads the token to struct field
*ptr[y] = strtok(NULL, ","); //cuts next part of the buffer
students[y].index = (int)strtol(ptr[y], NULL, 10); //loads int token to struct field
*buffer='\0';//resets buffer to the beginning for the next line from x++ fgets...
y++;//the idea with y=1000 is that I need another pointer to each struct field right?
}

for (x = 0; x < numStudents; x++)
printf("first name: %s, index: %d\n",students[x].name, students[x].index);

return students;

然后 printf 来查看加载了什么。 (为了简化我的真实结构,有 6 个字段)。我知道一个很好的方法来从用户输入中加载 1 个学生...( How to scanf commas, but with commas not assigned to a structure? C ) 但是要加载多个学生,我有这个想法,但我不确定它是否太笨拙而无法工作或只是写得很糟糕。

后来我会尝试按姓名对学生进行排序,甚至可能尝试进行重新分配缓冲区,以增加其大小以及将新学生加载到缓冲区......然后对内容进行排序已加载...但我想首先我需要将其从文件加载到缓冲区,然后从缓冲区加载到填充结构,然后才能对其进行排序?...

非常感谢您的帮助!

最佳答案

C 有点苛刻。我使用 GNU getline下面,它可能不可移植,您最终可能会自己实现。为了简单起见,我使用 stdin 作为输入 FILE *
该程序将学生列表读入 students 数组中。然后我通过比较索引对学生进行排序,然后按姓名排序,每次都打印出来。
您的代码有点困惑 - 尝试编写一个单独的函数来加载单个学生,您不需要 char ptr[students] 只需一个 char *ptr 用于strtok 函数。 strtok 有点复杂,我更喜欢多次使用 strchr 。我使用 memcpy 从字符串中复制名称,并记住将其分隔为空。

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>

struct student_s {
char *name;
int index;
};

static int students_name_cmp(const void *a, const void *b)
{
const struct student_s *s1 = a;
const struct student_s *s2 = b;
return strcmp(s1->name, s2->name);
}

static int students_index_cmp(const void *a, const void *b)
{
const struct student_s *s1 = a;
const struct student_s *s2 = b;
return s1->index - s2->index;
}

int main()
{
struct student_s *students = NULL;
size_t students_cnt = 0;
FILE *fp = stdin;
size_t read;
char *line = NULL;
size_t len = 0;

// for each line
while ((read = getline(&line, &len, fp)) != -1) {

// resize students!
students = realloc(students, (students_cnt + 1) * sizeof(*students));
// handle erros
if (students == NULL) {
fprintf(stderr, "ERROR allocating students!\n");
exit(-1);
}

// find the comma in the line
const const char * const commapos = strchr(line, ',');
if (commapos == NULL) {
fprintf(stderr, "ERROR file is badly formatted!\n");
exit(-1);
}
// student has the neme between the start to the comma adding null delimeter
const size_t namelen = (commapos - line) + 1;
// alloc memory for the name and copy it and null delimeter it
students[students_cnt].name = malloc(namelen * sizeof(char));
// handle errors
if (students[students_cnt].name == NULL) {
fprintf(stderr, "ERROR allocating students name!\n");
exit(-1);
}
memcpy(students[students_cnt].name, line, namelen - 1);
students[students_cnt].name[namelen] = '\0';

// convert the string after the comma to the number
// strtol (sadly) discards whitespaces before it, but in this case it's lucky
// we can start after the comma
errno = 0;
char *endptr;
const long int tmp = strtol(&line[namelen], &endptr, 10);
// handle strtol errors
if (errno) {
fprintf(stderr, "ERROR converting student index into number\n");
exit(-1);
}
// handle out of range values, I use INT_MIN/MAX cause index is int, no better idea, depends on application
if (tmp <= INT_MIN || INT_MAX <= tmp) {
fprintf(stderr, "ERROR index number is out of allowed range\n");
exit(-1);
}
students[students_cnt].index = tmp;

// handle the case when the line consist of any more characters then a string and a number
if (*endptr != '\n' && *endptr != '\0') {
fprintf(stderr, "ERROR there are some rabbish characters after the index!");
exit(-1);
}

// finnally, increment students count
students_cnt++;
}
if (line) {
free(line);
}

// sort by index
qsort(students, students_cnt, sizeof(*students), students_index_cmp);

// print students out sorted by index
printf("Students sorted by index:\n");
for (size_t i = 0; i < students_cnt; ++i) {
printf("student[%zu] = '%s', %d\n", i, students[i].name, students[i].index);
}

// now we have students. We can sort them.
qsort(students, students_cnt, sizeof(*students), students_name_cmp);

// print students out sorted by name
printf("Students sorted by name:\n");
for (size_t i = 0; i < students_cnt; ++i) {
printf("student[%zu] = '%s', %d\n", i, students[i].name, students[i].index);
}

// free students, lucky them!
for (size_t i = 0; i < students_cnt; ++i) {
free(students[i].name);
}
free(students);

return 0;
}

对于标准输入上的以下输入:

Achilles, 9999
Hector, 9998
Menelaos, 9997

程序输出:

Students sorted by index:
student[0] = 'Menelaos', 9997
student[1] = 'Hector', 9998
student[2] = 'Achilles', 9999
Students sorted by name:
student[0] = 'Achilles', 9999
student[1] = 'Hector', 9998
student[2] = 'Menelaos', 9997

测试版本可用 here on onlinegdb .

关于c - 如何从FILE中加载多个 "clones"结构? C,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52190170/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com