我正在尝试编写一个程序,使用输入重定向将文件中的条目读入动态分配的结构数组中。我的程序编译得很好但是我遇到了分段错误而且我找不到原因。
这是我的计划:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct StudentData
{
char* name;
char* major;
double gpa;
} Student;
int main()
{
Student* data = (Student*)malloc(sizeof(Student)*5);
int i;
for(i = 0; i < 5; i++)
{
// allocate memory for name and read input
data[i].name = malloc(50);
*(data+i)->name == scanf("%s", (char*)&data[i].name);
// allocate memory for major and read input
data[i].major = malloc(30);
*(data+i)->major == scanf("%s", (char*)&data[i].major);
// read input for gpa
(data+i)->gpa == scanf("%lf", &data[i].gpa);
//print array
printf("%s\n%s\n%f\n", data[i].name, data[i].major, data[i].gpa);
}
}
任何线索?如果它看起来很明显,那是因为我对C来说比较新!
答案 0 :(得分:6)
这一行:
*(data+i)->name == scanf("%s", (char*)&data[i].name);
暂时忽略奇怪和无效==
,&data[i].name
是错误的,因为你正在获取指针的地址。此处data[i].name
就足够了,因为name
字段已经是scanf
可以写入的地址。
而(char*)
的演员阵容可能关闭编译器 - 你为此目的输了吗:-)?由于&data[i].name
的类型为char**
,scanf
不接受,因此除非您强行将其投放到char*
。
作为一般性建议,请尽量避免使用scanf
- 它会导致非常不安全的代码(正如您刚才看到的那样!)而是使用fgets
来读取一行(来自标准输入) )然后将这条线分解为其成分。这最初可能需要更多的代码来实现,但会带来更安全,更可预测的代码。
答案 1 :(得分:2)
*(data+i)->name == scanf("%s", (char*)&data[i].name);
您在比较scanf
的返回值是什么?只需删除第一部分。此外,data[i].name
已经是指针,因此您不应再次使用该地址。它应该只是:
scanf("%s", data[i].name); // no & because name is already a pointer
同样地:
scanf("%s", data[i].major);
scanf("%lf", &data[i].gpa); // & here because gpa is just a double
答案 2 :(得分:1)
scanf使用了一些不必要的代码,例如*(data+i)->name ==
。这没有任何用处(并且可能导致段错误)。如果它没有导致访问错误,它会将scanf的返回值与指针进行比较,然后忽略比较结果。 (一个像样的编译器会对此发出警告。)
在删除多余的代码之后,它在技术上是可以的,除了没有什么可以阻止缓冲区溢出。这可以通过控制输入数据或增加字符串长度的限制来完成,例如使用scanf("%50s", data[i].name);
答案 3 :(得分:0)
&data[i].name
和&data[i].major
属于char **
类型,因此您无法安全地将其投放到char *
。
丢失&符将纠正您的错误。
使用scanf()还存在其他逻辑错误,但这可能是压倒性的 - 如果您输入超过50个字符的名称后重新访问此代码,那就太好了。