[英]Reading file data to array of structures while allocating memory dynamically
我需要帮助解决以下代码。 使用gcc编译代码后,它可以像./compiledFile inputFile.txt
一样运行。在这种情况下,对于每种变量名称和courseID,在为每个变量动态分配内存时,应该让inputFile.txt读取它,但是我的代码无法正常工作。 我最不了解并且需要帮助的地方是分配内存,将数据插入结构并打印数据,如下例所示。 通过这段代码,您可以看出我是c语言以及动态内存分配和结构的新手。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct people
{
char* name[10];
char* courseID[15];
int grade;
};
void printData(struct people student[], int count);
int main(int argc, char* argv[])
{
FILE *in_file;
char buffer[30];
char *token, *del=",";
int count=0;
struct people student[20];
if(( in_file = fopen(argv[1], "r")) == NULL)
{
printf("unable to open the file");
}
while (fgets(buffer, sizeof(buffer), in_file))
{
student = malloc(sizeof(struct people));
token = strtok(buffer, del);
strcpy(student[count].name, token);
count++;
}
fclose(in_file);
printData(student, count);
}
void printData(struct people student[], int count)
{
int i;
for(i=0; i<count; i++)
{
printf("%s", student[i].courseID);
if (strcmp((student[i].name, student[i].courseID) > 0))
{
printf("%s %s", student[i].name, student[i].grade)
}
}
}
data.txt文件包含以下内容,以逗号分隔:
John,MATH 1324,90 David,SCI 1401,88 Omondi,MATH 1324,89 David,MATH 1324,90
打印时,它应如下所示:
MATH 1324
John 90
Omondi 89
David 90
SCI 1401
David 88
首先,如果您还可以共享运行此程序时得到的实际输出或错误,那将是很好的。
在大多数情况下,当我们不知道数据元素的实际大小时,将使用动态内存分配,但是在这里,您已经将struct people student的大小固定为20
struct people student[20];
这绝对没问题,但是您可以在while循环中执行malloc
student = malloc(sizeof(struct student);
您已经使用数组声明分配了20个位置,现在不需要malloc。 如果您想使用带有指针的动态内存分配用于学习目的,则应首先将学生声明为键入struct people的指针
struct people* student;
在while循环中动态分配内存
student=(struct people*) malloc(sizeof(struct people));
然后访问它
*(student+count)
希望这对您有帮助,如果您仍然有疑问/问题,请编辑问题,并包括在编译/运行此程序时遇到的输出/错误。
问题代码的几个问题...
1)main()的定义:
int main(int argc, char* argv[])
它必须返回一个整数。 在main()的末尾添加return语句,并进行适当的“ CLEANUP”部分:
printData(student, count);
CLEANUP:
if(in_file)
fclose(in_file);
return(0);
}
2)更好地处理fopen()错误情况:
if(( in_file = fopen(argv[1], "r")) == NULL)
{
printf("unable to open the file");
goto CLEANUP;
}
并且,初始化in_file
指针:
int main(int argc, char* argv[])
{
FILE *in_file = NULL;
3)接下来,需要确定student
的确切定义。 它是静态数组还是动态分配数组的指针? 我将假定您要使用动态数组(给出问题文本)。 但是,此假设与以下行冲突,该行将student
定义为静态数组:
struct people student[20];
更改为:
struct people *student = NULL;
4)现在,以下问题代码为每个学生分配了一个新的(单独的)内存块:
student = malloc(sizeof(struct people));
但是,需要的是所有学生记录都在同一块内存中的一个阵列中。 因此,需要的是扩展一块内存,以便在读取学生记录时包括它们,如下所示:
while (fgets(buffer, sizeof(buffer), in_file))
{
void *tmp = realloc(student, sizeof(struct people) * (count + 1));
if(NULL == tmp)
{
printf("realloc() failed.\n");
goto CLEANUP;
}
student = tmp;
token = strtok(buffer, del);
5)看一下人员结构:
struct people
{
char* name[10];
char* courseID[15];
int grade;
};
看起来问题代码在涉及指针和数组时有些困难。 该代码正在尝试将name和courseID字段定义为指针和数组。 鉴于问题在于动态分配内容,我选择朝这个方向发展。 因此,此结构应更改为以下内容:
struct people
{
char *name;
char *courseID;
int grade;
};
6)因此,每次循环时,学生姓名都将放置在分配的存储中,并由.name字段指向。 因此,更改此:
token = strtok(buffer, del);
strcpy(student[count]->name, token);
count++;
}
对此:
token = strtok(buffer, del);
student[count].name = strdup(token);
count++;
}
7)我不明白这行的意图:
if (strcmp((student[i].name, student[i].courseID) > 0))
我倾向于消除它。
8)以下行有缺陷:
printf("%s %s", student[i].name, student[i].grade)
将其更改为此值以打印整数grade
(并且不要忘记结尾的分号):
printf("%s %d\n", student[i].name, student[i].grade);
'\\ n'使输出看起来更好,每行一条记录。
9)由于student
是指向动态分配的内存(而不是静态数组)的指针,因此请更改以下内容:
void printData(struct people student[], int count)
对此:
void printData(struct people *student, int count)
10)现在,完成解析数据的任务; 由此:
token = strtok(buffer, del);
strcpy(student[count].name, token);
count++;
}
对此:
token = strtok(buffer, del);
student[count].name = strdup(token);
token = strtok(NULL, del);
student[count].courseID = strdup(token);
token = strtok(NULL, del);
student[count].grade = strtol(token, NULL, 10);
count++;
}
11)现在,为了使生活更轻松,对数组进行排序。 首先按CourseID,然后按名称:
...
count++;
}
/** Sort the array by coursID, then by name. **/
qsort(student, count, sizeof(*student), CmpStudentRecs);
printData(student, count);
...
这将需要附加的“比较学生记录”功能:
int CmpStudentRecs(const void *recA, const void *recB)
{
int result = 0;
struct people *stuRecA = (struct people *)recA;
struct people *stuRecB = (struct people *)recB;
/** First compare the courseIDs **/
result=strcmp(stuRecA->courseID, stuRecB->courseID);
/** Second (if courseIDs match) compare the names **/
if(!result)
result=strcmp(stuRecA->name, stuRecB->name);
return(result);
}
12)使用printData()函数进行一些最后润饰:
void printData(struct people *student, int count)
{
int i;
char *courseID = "";
for(i=0; i<count; i++)
{
if(strcmp(courseID, student[i].courseID))
{
printf("%s\n", student[i].courseID);
courseID = student[i].courseID;
}
printf("\t%s %d\n", student[i].name, student[i].grade);
}
}
成品。 输出:
SLES11SP2:~/SO> ./test data.txt
MATH 1324
David 90
John 90
Omondi 89
SCI 1401
David 88
SLES11SP2:~/SO>
更改的定义people
来:
struct people { char name[10]; char courseID[15]; int grade; };
假设name
不能超过9个字符,而coursID
不能超过14个字符。 如果不正确,请相应地更改它们。
该行:
student = malloc(sizeof(struct student);
在几种方面是错误的。
student
已经被宣布为people
。 您不能将其分配为指向malloc
分配的malloc
。
struct student
不是一个类型。
该行可以删除。
线
strcpy(student[count].name, token);
可能会造成问题,如果长度token
长于10
(您选择或任何大小name
中people
)。 较安全的方法是使用strncpy
。
strncpy(student[count].name, token, 10); student[count].name[9] = '\\0';
您尚未在任何地方设置courseID
的值。 但是,您正在尝试在printData
打印它。 你的grade
是一样的。 您需要更新输入行的处理以正确设置这些行。
将while
循环更改为:
while (fgets(buffer, sizeof(buffer), in_file)) { token = strtok(buffer, del); strncpy(student[count].name, token, 10); student[count].name[9] = '\\0'; token = strtok(NULL, del); strncpy(student[count].courseID, token, 15); student[count].courseID[14] = '\\0'; token = strtok(NULL, del); student[count].grade = atoi(token); count++; }
在printData
有几个语法错误。 但是,修复这些语法错误不会满足您的打印要求。 如果对数据进行排序,则按所需顺序打印数据将更加容易。 以下功能将帮助您对数据进行排序。
int compareStudent(const void* ptr1, const void* ptr2) { struct people* p1 = (struct people*)ptr1; struct people* p2 = (struct people*)ptr2; return (strcmp(p1->courseID, p2->courseID)); } void sortData(struct people student[], int count) { qsort(student, count, sizeof(struct people), compareStudent); }
您可以拨打sortData
调用之前printData
或致电sortData
在第一printData
。 打印数据的逻辑需要一点点更新。 这是更新的printData
。
void printData(struct people student[], int count) { int i; int j; sortData(student, count); for(i=0; i<count; ++i) { printf("%s\\n", student[i].courseID); printf("%s %d\\n", student[i].name, student[i].grade); for ( j = i+1; j < count; ++j ) { if (strcmp(student[i].courseID, student[j].courseID) == 0) { printf("%s %d\\n", student[j].name, student[j].grade); } else { i = j-1; break; } } } }
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct people {
char name[10];//char *name[10] is array of pointer
char courseID[15];
int grade;
};
void printData(struct people student[], int count);
int main(int argc, char* argv[]){
FILE *in_file;
char buffer[30];
char *token, *del=",";
int count=0;
struct people student[20];
if((in_file = fopen(argv[1], "r")) == NULL){
printf("unable to open the file");
return -1;//It is not possible to continue the process
}
while (fgets(buffer, sizeof(buffer), in_file)){
//student = malloc(sizeof(struct people));//It is by securing an array already
token = strtok(buffer, del);
strcpy(student[count].name, token);
token = strtok(NULL, del);
strcpy(student[count].courseID, token);
token = strtok(NULL, del);
student[count].grade = atoi(token);
count++;
}
fclose(in_file);
printData(student, count);
}
int cmp(const void *a, const void *b){
const char *x = ((const struct people*)a)->courseID;
const char *y = ((const struct people*)b)->courseID;
return strcmp(x, y);
}
void printData(struct people student[], int count){
qsort(student, count, sizeof(struct people), cmp);//sort by courseID
char *prev = "";
int i;
for(i=0; i<count; i++){
if(strcmp(prev, student[i].courseID)!=0){
prev = student[i].courseID;
printf("\n%s\n", prev);
}
printf("%-9s %d\n", student[i].name, student[i].grade);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.