По крайней мере три ошибки, которые независимо вызвали segfault:
Во-первых, newNode->word
используется unitialized , поэтому он указывает на случайную память, поэтому strcpy
будет segfault. Лучше использовать strdup
Кроме того, после того, как вы положили newNode
в таблицу, вы делаете free(newNode)
, делая то, что он указывает на недействительным. Это приводит к тому, что второй l oop переходит в состояние сбоя
В-третьих, во втором l oop, если table[i]
равно нулю, while (tmp->next != NULL)
будет прерваться из-за ошибки
Я комментировал и исправил ваш код:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// file to read
#define dictionary "dictionary.txt"
// No. of buckets
const unsigned int N = 10;
typedef struct node {
char *word;
struct node *next;
} node;
node *table[10];
// hash function
unsigned int
hash(char *word)
{
// TODO
unsigned int hash = 5381;
int c = 0;
while (c == *word++)
hash = ((hash << 5) + hash) + c;
// NOTE: not a bug but probably better
#if 0
return hash % 10;
#else
return hash % N;
#endif
}
int
main(void)
{
// initialize array heads to NULL
for (int i = 0; i < N; i++) {
table[i] = NULL;
}
// Open file to read
FILE *indata = fopen(dictionary, "r");
if (indata == NULL) {
printf("cant open\n");
return 1;
}
// variable to store words read from the file
char *words = malloc(sizeof(char) * 20);
if (words == NULL) {
printf("no memory\n");
return 1;
}
// While loop to read through the file
while (fgets(words, 20, indata)) {
// get the index of the word using hash function
int index = hash(words);
// create new node
node *newNode = malloc(sizeof(node));
if (newNode == NULL) {
printf("here\n");
return 1;
}
// make the new node the new head of the list
// NOTE/BUG: word is never set to anything valid -- possible segfault here
#if 0
strcpy(newNode->word, words);
#else
newNode->word = strdup(words);
#endif
newNode->next = table[index];
table[index] = newNode;
// free memory
// NOTE/BUG: this will cause the _next_ loop to segfault -- don't deallocate
// the node you just added to the table
#if 0
free(newNode);
#endif
}
// free memory
free(words);
// loop to print out the values of the hash table
for (int i = 0; i < N; i++) {
node *tmp = table[i];
// NOTE/BUG: this test fails if the tmp is originally NULL (i.e. no entries
// in the given hash index)
#if 0
while (tmp->next != NULL) {
#else
while (tmp != NULL) {
#endif
printf("%s\n", tmp->word);
tmp = tmp->next;
}
}
// loop to free all memory of the hash table
for (int i = 0; i < N; i++) {
if (table[i] != NULL) {
node *tmp = table[i]->next;
free(table[i]);
table[i] = tmp;
}
}
// close the file
fclose(indata);
}
ОБНОВЛЕНИЕ:
Я создал программу со связанным списком до того, как она сохранит целое число в списке, int number; struct node *next;
а я использовал newNode->number = 5;
и это сработало, почему в этом случае это не так ?? Это потому, что я здесь работаю со строками ??
Разница в том, что word
является указателем . Ему должно быть присвоено значение, прежде чем его можно будет использовать. strcpy
не не присваивает значение word
. Он пытается использовать содержимое word
в качестве адреса назначения копии.
Но другие две ошибки происходят независимо от того, * word
является char *
против number
будучи int
.
Если вы определили word
не как указатель, а как фиксированный массив [не так хорош в этом использовании], strcpy
сработало бы. То есть вместо char *word;
, если вы сделали (например) char word[5];
Но то, что вы сделали, лучше [с изменением strdup
], если вы не можете гарантировать, что длина word
может держать вход. strdup
гарантирует это.
Но обратите внимание, что я [намеренно] сделал word
только пять символов, чтобы проиллюстрировать проблему. Это означает, что добавляемое слово может быть длиной всего 4 символа [нам нужен один дополнительный байт для нулевого символа-терминатора]. Вам нужно было бы использовать strncpy
вместо strcpy
, но strncpy
имеет проблемы [он делает не гарантированно добавить нулевой символ в конце, если длина источника слишком велика].
Кстати, сегодня существует еще один вопрос, на который есть ответ, который может помочь пролить немного света на различия вашего элемента word
struct: Разница в распределении памяти элемента структуры (указатель или массив) в C