Сканирование в текстовом файле в связанный список
Я только изучаю связанные списки, и мне нужно выполнить задание, состоящее из множества частей, но я начинаю, и самое первое, что мне нужно сделать, - это прочитать входной файл в связанный список. Часть файла:
George Washington, 2345678
John Adams, 3456789
Thomas Jefferson, 4567890
James Madison, 0987654
James Monroe, 9876543
John Quincy Adams, 8765432
и содержит в общей сложности 26 строк.
Все, что я хочу сейчас сделать - это просто прочитать в файле. Я пытаюсь с помощью этого кода (в основном на данный момент)
#include <stdio.h>
#include <stdlib.h>
struct node{
char name[20];
int id;
struct node *next;
}*head;
int main(void){
struct node *temp;
temp = (struct node *)malloc(sizeof(struct node));
head = temp;
FILE *ifp;
ifp = fopen("AssignmentOneInput.txt", "r");
int c = 0;
while(c<26){
fscanf(ifp, "%s", &temp->name);
fscanf(ifp, "%d", &temp->id);
printf("%d\n", c);
temp = temp->next;
c++;
}
Для вывода я знаю, что имя и первый идентификатор сканируются, потому что значение c отображается как 0 (сейчас я произвольно использую значение c для управления fscanf). Но после этого программа вылетает. Так что проблема должна быть с temp = temp->next;
Компилируется нормально.
Я очень новичок в связанных списках, поэтому я действительно не знаю, что я делаю.
Ваша помощь ценится!
3 ответа
В следующих строках вы выделили достаточно места для одного элемента вашего списка (один struct node
) и указал ваш head
указатель на это:
temp = (struct node *)malloc(sizeof(struct node));
head = temp;
Позже вы читаете в значения в name
а также id
поля этого элемента:
fscanf(ifp, "%s", &temp->name);
fscanf(ifp, "%d", &temp->id);
Но что делает temp->next
указать на? Вы только что выделили пространство для одного элемента. Вам нужно выделить место для каждого последующего элемента, когда вы добавляете его в список.
Редактировать: как указано ниже @merlin2011, этот ответ просто поможет вам разрешить сбой программы, но не будет полностью работать так, как вы ожидаете. Тем не менее, надеюсь, вы сможете лучше отладить его, если он не дает сбоя.
Прежде всего, так как вы пишете в C
нет необходимости разыгрывать malloc
,
Во-вторых, вы должны выделить память для каждого нового узла самостоятельно.
В-третьих, имя массива уже распадается на указатель, поэтому не стоит брать &
об этом, потому что тогда вы получите указатель на указатель, который не то, что вы хотите.
Наконец, вам нужно исправить scanf
синтаксис для обработки пробелов в ваших полях.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node{
char name[20];
int id;
struct node *next;
}*head;
int main(void){
struct node *temp;
temp = malloc(sizeof(struct node));
temp->next = NULL;
head = temp;
FILE *ifp;
ifp = fopen("AssignmentOneInput.txt", "r");
int c = 0;
char buffer[1024];
memset(buffer, 0, 1024);
while(c<5){
fgets(buffer, 1024, ifp);
sscanf(buffer, "%19[^,], %d", temp->name, &temp->id);
printf("%d %s %d\n",c, temp->name, temp->id);
temp->next = malloc(sizeof(struct node));
temp = temp->next;
temp->next = NULL;
c++;
}
}
Основная проблема, безусловно, temp = temp->next
устанавливает временное поле next
это никогда не инициализировалось, в результате чего код сегментировался. неисправность в следующем цикле.
Есть связанные проблемы списка и проблемы ввода. Рекомендую не выделять места, пока хорошие данные не найдены.
Начните с temp_head
, Код использует только next
поле temp_head
,
struct node temp_head;
temp_head.next = NULL;
struct node *p = &temp_head;
Всякий раз, когда код читает данные строки, рекомендуем использовать fgets()
читать строку, а затем сканировать буфер.
char buf[100];
while (fgets(buf, sizeof buf, ifp) != NULL) {
struct node nbuf;
Сканирование буфера с помощью sscanf()
, использование '%[^,]'
читать до ','
,
if (2 != sscanf(buf, " %19[^,],%d", nbuf.name, &nbuf.id)) {
break; // Invalid data encountered
}
nbuf.next = NULL;
// Code does not allocate data until good data was found
p->next = malloc(sizeof *(p->next));
if (p->next == NULL) break; // OOM
p = p->next;
*p = nbuf; // Copy the data
}
head = temp_head.next;
Заметки:
Актерский состав в temp = (struct node *)malloc(sizeof(struct node));
не нужен
Рассмотрим этот стиль распределения: temp = malloc(sizeof *temp)
ИМО проще кодировать и меньше поддерживать.
fscanf(ifp, "%s", &temp->name); fscanf(ifp, "%d", &temp->id);
имеет 3 проблемы: нет ограничений на ввод строки, не требуется &
и неспособность проверить результаты сканирования. Обратите внимание на использование кода (2 != sscanf(buf, " %19[^,], %d", nbuf.name, &nbuf.id)
, который ограничивает ввод строки до 19 char
(оставляя место для прекращения '\0'
, не использует &
когда поле является массивом, и проверяет, что 2 поля были успешно проверены.
До конца main()
, код должен освободить распределенные данные.