热将 TXT 文件转换为结构数组 - 分段错误?
Hot to convert TXT File to Array of struct - segmentation fault?
正在尝试从文本文件中提取数据并将该数据放入数组中。
文件包含一定数量的行,每一行都遵循相同的配置:
Number FamilyName FirstName GPA
需要的数组是struct数组
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 25
typedef struct ppl {
int login;
char *p_name;
char *p_surname;
}person;
int main(void)
{
char *line = NULL;
person *data=malloc(MAX*sizeof(person));
float *gpa=malloc(MAX*sizeof(float));
size_t length=0;
FILE* txtfile;
if ((txtfile=fopen("file.txt","r"))==NULL) return -1;
int i=0; // the counter for the for loop
int buf_ID; // buffer variable for the sscanf test
char buf_name[256]; // same
char buf_surname[256]; // same
float buf_grade; // same
while ((read = getline(&line, &length,txtfile)) != -1 && i<MAX)
{
if(sscanf(line,"%d %s %s%*s %f", &buf_ID, buf_name, buf_surname, &buf_grade)==4)
{
data[i].login=buf_ID;
data[i].p_name= malloc(strlen(buf_name)+1);
strcpy(data[i].p_name, buf_name);
data[i].p_surname= malloc(strlen(buf_surname)+1);
strcpy(data[i].p_surname, buf_surname);
gpa[i]=buf_grade;
i++;
}
}
int j;
printf("ID | Name | Surname | GPA\n");
for(j=0;j<i;j++)
{
printf("%d | %s | %s | %f\n", data[j].login, data[j].p_name, data[j].p_surname, gpa[j]);
}
fclose(txtfile);
return 0;
}
(经常编辑的代码 - 我正在填充无用的文本,因为 post 不会以其他方式发布)
我看到你现在为你的数组分配了内存。好
现在关于 char *
缓冲区 buf_name
等。也许最好在这里进行静态分配,例如
char buf_name[256];
您将重新使用此缓冲区,因此静态分配没问题。
下一步:
查找 getline 函数:http://man7.org/linux/man-pages/man3/getline.3.html
并检查所有参数是否正确。
现在使用调试器将程序步进 sscanf
。跨过它并检查变量是否已被 sscanf
正确读取(使用调试器是学习 C 的重要部分)。
接下来要问问自己,您的人员数组是否具有所需的全部内存。如果不是,你打算如何分配内存?
您已经使用 malloc 分配了一组人员。每个人都有一些与之相关的数据。数据由原始类型和复合类型组成。基本类型是 int、float、double 和 char。复合类型由其中的一些组成。字符串是复合类型,因为它由多个字符组成。
所以你在数组中的人有与他们相关的字符串数据,作为指针,但指针没有与之相关的内存。您需要分配内存来保存字符串数据。你的数据->p_name=malloc(MAX*100);`不正确。
对于你阅读的每个人,你应该分配字符串内存来保存 sscanf
放入固定大小缓冲区的字符串数据:
data[i].p_name= malloc(strlen(buf_name)+1);
strcpy(data[i].p_name, buf_name);
其他字符串数据也一样。 (当然,你在循环中执行此操作!)
Nb:对于原始类型,数据由编译器分配;对于复合类型,您必须分配内存。
Nb: C 中的字符串以空字符结尾。因此所需的内存比字符串的长度多一倍。
What is that second sscanf
doing there in your loop???
最后复制ID:
data[i].login= buf_id;
请注意,您没有将成绩存储在 person 中,并且 gpa
没有分配内存(因此您可能会再次遇到段错误)。
您的程序现在 运行 不会出现段错误。但是你的循环不正确:
你有一个 for 循环正好循环了 25 次;在循环中,你有一个 while 循环,它读取数据并将其放入 persons 中。但是 persons 的索引只在 for 循环中更新,而不是在 while 循环中更新。读取最后一行数据后,while 循环停止,for 循环的下一次迭代开始。但是,没有更多的数据。
所以你需要另一种类型的循环,循环 最多 25 次(因为你没有更多的人)并且没有更多数据时停止。
一个for循环就可以了; while 循环也可以。但不是两者。你能想出这两种变体吗?
您的程序现在 运行。最后一点:"clean up!" 删除不再需要的东西,确保代码正确缩进和格式化,并添加一个循环来打印数组,这样你就可以检查并正确查看它 运行。
希望您在开发这个程序时玩得开心。
正在尝试从文本文件中提取数据并将该数据放入数组中。
文件包含一定数量的行,每一行都遵循相同的配置:
Number FamilyName FirstName GPA
需要的数组是struct数组
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 25
typedef struct ppl {
int login;
char *p_name;
char *p_surname;
}person;
int main(void)
{
char *line = NULL;
person *data=malloc(MAX*sizeof(person));
float *gpa=malloc(MAX*sizeof(float));
size_t length=0;
FILE* txtfile;
if ((txtfile=fopen("file.txt","r"))==NULL) return -1;
int i=0; // the counter for the for loop
int buf_ID; // buffer variable for the sscanf test
char buf_name[256]; // same
char buf_surname[256]; // same
float buf_grade; // same
while ((read = getline(&line, &length,txtfile)) != -1 && i<MAX)
{
if(sscanf(line,"%d %s %s%*s %f", &buf_ID, buf_name, buf_surname, &buf_grade)==4)
{
data[i].login=buf_ID;
data[i].p_name= malloc(strlen(buf_name)+1);
strcpy(data[i].p_name, buf_name);
data[i].p_surname= malloc(strlen(buf_surname)+1);
strcpy(data[i].p_surname, buf_surname);
gpa[i]=buf_grade;
i++;
}
}
int j;
printf("ID | Name | Surname | GPA\n");
for(j=0;j<i;j++)
{
printf("%d | %s | %s | %f\n", data[j].login, data[j].p_name, data[j].p_surname, gpa[j]);
}
fclose(txtfile);
return 0;
}
(经常编辑的代码 - 我正在填充无用的文本,因为 post 不会以其他方式发布)
我看到你现在为你的数组分配了内存。好
现在关于 char *
缓冲区 buf_name
等。也许最好在这里进行静态分配,例如
char buf_name[256];
您将重新使用此缓冲区,因此静态分配没问题。
下一步:
查找 getline 函数:http://man7.org/linux/man-pages/man3/getline.3.html 并检查所有参数是否正确。
现在使用调试器将程序步进 sscanf
。跨过它并检查变量是否已被 sscanf
正确读取(使用调试器是学习 C 的重要部分)。
接下来要问问自己,您的人员数组是否具有所需的全部内存。如果不是,你打算如何分配内存?
您已经使用 malloc 分配了一组人员。每个人都有一些与之相关的数据。数据由原始类型和复合类型组成。基本类型是 int、float、double 和 char。复合类型由其中的一些组成。字符串是复合类型,因为它由多个字符组成。
所以你在数组中的人有与他们相关的字符串数据,作为指针,但指针没有与之相关的内存。您需要分配内存来保存字符串数据。你的数据->p_name=malloc(MAX*100);`不正确。
对于你阅读的每个人,你应该分配字符串内存来保存 sscanf
放入固定大小缓冲区的字符串数据:
data[i].p_name= malloc(strlen(buf_name)+1);
strcpy(data[i].p_name, buf_name);
其他字符串数据也一样。 (当然,你在循环中执行此操作!)
Nb:对于原始类型,数据由编译器分配;对于复合类型,您必须分配内存。
Nb: C 中的字符串以空字符结尾。因此所需的内存比字符串的长度多一倍。
What is that second
sscanf
doing there in your loop???
最后复制ID:
data[i].login= buf_id;
请注意,您没有将成绩存储在 person 中,并且 gpa
没有分配内存(因此您可能会再次遇到段错误)。
您的程序现在 运行 不会出现段错误。但是你的循环不正确:
你有一个 for 循环正好循环了 25 次;在循环中,你有一个 while 循环,它读取数据并将其放入 persons 中。但是 persons 的索引只在 for 循环中更新,而不是在 while 循环中更新。读取最后一行数据后,while 循环停止,for 循环的下一次迭代开始。但是,没有更多的数据。
所以你需要另一种类型的循环,循环 最多 25 次(因为你没有更多的人)并且没有更多数据时停止。
一个for循环就可以了; while 循环也可以。但不是两者。你能想出这两种变体吗?
您的程序现在 运行。最后一点:"clean up!" 删除不再需要的东西,确保代码正确缩进和格式化,并添加一个循环来打印数组,这样你就可以检查并正确查看它 运行。
希望您在开发这个程序时玩得开心。