尝试将字典加载到内存时出现 C 中的分段错误(cs50 pset5,拼写器)
Segmentation fault in C when trying to load dictionary into memory (cs50 pset5, speller)
我已经部分完成了 cs50 的 pset5,但是每次我尝试 运行 我的程序时,我都会因为某种原因遇到段错误。
在我的 load
函数中,我打开字典文件并通过调用 init_table()
初始化我的散列 table。然后,我使用fscanf
扫描字典文件,为字典中的每个单词创建一个node *n
,并将dict_word
中的单词复制到这个节点中。然后我使用我的 hash
函数(基于 djb2)来存储这个节点的单词的索引。
如果table[index] == NULL
,那么我将table[index]
和一个名为head
的节点都设置为节点n
,并将下一个地址设置为NULL
].否则,我将下一个节点设置为 table[index]
,将 table[index]
设置为当前节点,n
。
我还没有释放任何内存,因为这将在另一个名为 unload
的函数中完成,但我怀疑我当前的问题可能是由于其他原因造成的。任何帮助将不胜感激。
// Implements a dictionary's functionality
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// Number of buckets in hash table (A-Z)
const unsigned int N = 5381;
// Hash table
node *table[N];
// initialize hash table (set all values to NULL)
// reference video: https://youtu.be/2Ti5yvumFTU
void init_table()
{
for (int i = 0; i < N; i++)
{
table[i] = NULL;
}
}
// Hashes word to a number
// hash function: djb2
// retrieved from http://www.cse.yorku.ca/~oz/hash.html
unsigned int hash(const char *word)
{
unsigned int hash_value = N;
int c;
while ((c = *word++))
{
hash_value = ((hash_value << 5) + hash_value) + c; /* hash * 33 + c */
}
return hash_value;
}
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
// open dictionary file, check if NULL
FILE *dict_file = fopen(dictionary, "r");
if (dict_file == NULL)
{
return false;
}
init_table();
// create char for each dictionary word (max length + nul)
char dict_word[LENGTH + 1];
// create beginning node that serves as first item in linked list
node *head;
// scan until end of file
while (fscanf(dict_file, "%s", dict_word) != EOF)
{
// create a node n for each word and copy string into it
node *n = malloc(sizeof(node));
if (n == NULL)
{
return false;
}
strcpy(n->word, dict_word);
// hash the word and store as index (which tells which linked list to use)
int index = hash(n->word);
// if table[index] is NULL, set it and head as node n, set next node as NULL
if (table[index] == NULL)
{
head = table[index] = n;
n->next = NULL;
}
// otherwise set next node as table[index], table[index] as current node n
else
{
n->next = head;
table[index] = n;
}
}
return true;
}
EDIT:在阅读了 Boris Lipschitz 的回答后,我意识到了这个问题并进一步学习了如何使用调试器来解决它。我修改了 const unsigned int N = 5381
并将 N
的值更改为 25
以表示字母表中每个字母的桶(尽管我稍后可能会更改此值以优化我的程序)。对于我的 hash
函数,正如鲍里斯所说,没有什么可以阻止 hash_value
超过 N
,所以我将 return hash_value;
改为 return hash_value % N;
,这将给我一个在 table.
的适当范围内的输出
您的 hash
函数中绝对没有任何东西可以阻止它达到 5381 或更高。然后你用它访问table
...砰,分段错误。
反向问题:你为什么不直接 运行 在调试器中编写你的代码?你知道答案的速度比我们任何人都可能做出的回应更快。
我已经部分完成了 cs50 的 pset5,但是每次我尝试 运行 我的程序时,我都会因为某种原因遇到段错误。
在我的 load
函数中,我打开字典文件并通过调用 init_table()
初始化我的散列 table。然后,我使用fscanf
扫描字典文件,为字典中的每个单词创建一个node *n
,并将dict_word
中的单词复制到这个节点中。然后我使用我的 hash
函数(基于 djb2)来存储这个节点的单词的索引。
如果table[index] == NULL
,那么我将table[index]
和一个名为head
的节点都设置为节点n
,并将下一个地址设置为NULL
].否则,我将下一个节点设置为 table[index]
,将 table[index]
设置为当前节点,n
。
我还没有释放任何内存,因为这将在另一个名为 unload
的函数中完成,但我怀疑我当前的问题可能是由于其他原因造成的。任何帮助将不胜感激。
// Implements a dictionary's functionality
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// Number of buckets in hash table (A-Z)
const unsigned int N = 5381;
// Hash table
node *table[N];
// initialize hash table (set all values to NULL)
// reference video: https://youtu.be/2Ti5yvumFTU
void init_table()
{
for (int i = 0; i < N; i++)
{
table[i] = NULL;
}
}
// Hashes word to a number
// hash function: djb2
// retrieved from http://www.cse.yorku.ca/~oz/hash.html
unsigned int hash(const char *word)
{
unsigned int hash_value = N;
int c;
while ((c = *word++))
{
hash_value = ((hash_value << 5) + hash_value) + c; /* hash * 33 + c */
}
return hash_value;
}
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
// open dictionary file, check if NULL
FILE *dict_file = fopen(dictionary, "r");
if (dict_file == NULL)
{
return false;
}
init_table();
// create char for each dictionary word (max length + nul)
char dict_word[LENGTH + 1];
// create beginning node that serves as first item in linked list
node *head;
// scan until end of file
while (fscanf(dict_file, "%s", dict_word) != EOF)
{
// create a node n for each word and copy string into it
node *n = malloc(sizeof(node));
if (n == NULL)
{
return false;
}
strcpy(n->word, dict_word);
// hash the word and store as index (which tells which linked list to use)
int index = hash(n->word);
// if table[index] is NULL, set it and head as node n, set next node as NULL
if (table[index] == NULL)
{
head = table[index] = n;
n->next = NULL;
}
// otherwise set next node as table[index], table[index] as current node n
else
{
n->next = head;
table[index] = n;
}
}
return true;
}
EDIT:在阅读了 Boris Lipschitz 的回答后,我意识到了这个问题并进一步学习了如何使用调试器来解决它。我修改了 const unsigned int N = 5381
并将 N
的值更改为 25
以表示字母表中每个字母的桶(尽管我稍后可能会更改此值以优化我的程序)。对于我的 hash
函数,正如鲍里斯所说,没有什么可以阻止 hash_value
超过 N
,所以我将 return hash_value;
改为 return hash_value % N;
,这将给我一个在 table.
您的 hash
函数中绝对没有任何东西可以阻止它达到 5381 或更高。然后你用它访问table
...砰,分段错误。
反向问题:你为什么不直接 运行 在调试器中编写你的代码?你知道答案的速度比我们任何人都可能做出的回应更快。