В чем причина моей ошибки сегментации? - PullRequest
1 голос
/ 22 сентября 2010

Я пытаюсь написать программу, которая читает записи из файла в динамически размещенный массив структур, используя перенаправление ввода.Моя программа компилируется нормально, но у меня ошибка сегментации, и я не могу найти причину.

Вот моя программа:

#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!

Ответы [ 4 ]

6 голосов
/ 22 сентября 2010

Эта строка:

*(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, чтобы прочитать строку (также из стандартного ввода), а затем разбить эту строку на составляющие.Это может первоначально потребовать немного больше кода для реализации, но приводит к гораздо более безопасному и более предсказуемому коду.

2 голосов
/ 22 сентября 2010
*(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
1 голос
/ 22 сентября 2010

Есть некоторый ненужный код, используемый с scanf, например *(data+i)->name ==.Это не делает ничего полезного (и, вероятно, вызывает segfault).Если бы это не вызывало ошибок доступа, он сравнил бы возвращаемое значение scanf с указателем, а затем проигнорировал результат сравнения.(Приличный компилятор предупредил бы об этом.)

После избавления от лишнего кода все будет технически нормально, за исключением того, что нет ничего, что могло бы предотвратить переполнение буфера.Это делается либо путем управления входными данными, либо путем добавления ограничений на длину строк, например, scanf("%50s", data[i].name);

0 голосов
/ 22 сентября 2010

&data[i].name и &data[i].major относятся к типу char **, поэтому вы не можете безопасно преобразовать его в char *.

Потеря амперсанда исправит вашу ошибку.

Существуют и другие логические ошибки при использовании scanf (), но это, вероятно, ошеломляет - было бы неплохо, если бы вы повторно просмотрели этот код после того, как вы ввели имя длиной более 50 символов.

...