我是C的新手,所以我在制作哈希表和malloc-ing空间方面遇到了麻烦。
我正在做一个anagram解算器。现在我仍然在为这个程序创建哈希表的步骤。我试图通过使用一些随机参数调用函数来测试我的插入函数以查看它是否正常工作。
然而,我不断收到分段错误,我使用valgrind来追踪它崩溃的地方。
你能说出我错过了什么吗?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int hash(char *word)
{
int h = 0;
int i, j;
char *A;
char *a;
// an array of 26 slots for 26 uppercase letters in the alphabet
A = (char *)malloc(26 * sizeof(char));
// an array of 26 slots for 26 lowercase letters in the alphabet
a = (char *)malloc(26 * sizeof(char));
for (i = 0; i < 26; i++) {
A[i] = (char)(i + 65); // fill the array from A to Z
a[i] = (char)(i + 97); // fill the array from a to z
}
for (i = 0; i < strlen(word); i++) {
for (j = 0; j < 26; j++) {
// upper and lower case have the same hash value
if (word[i] == A[j] || word[i] == a[j]) {
h += j; // get the hash value of the word
break;
}
}
}
return h;
}
typedef struct Entry {
char *word;
int len;
struct Entry *next;
} Entry;
#define TABLE_SIZE 20 // test number
Entry *table[TABLE_SIZE] = { NULL };
void init() {
// create memory spaces for each element
struct Entry *en = (struct Entry *)malloc(sizeof(struct Entry));
int i;
// initialize
for (i = 0; i < TABLE_SIZE; i++) {
en->word = "";
en->len = 0;
en->next = table[i];
table[i] = en;
}
}
void insertElement(char *word, int len) {
int h = hash(word);
int i = 0;
// check if value has already existed
while(i < TABLE_SIZE && (strcmp(table[h]->word, "") != 0)) {
// !!!! NEXT LINE IS WHERE IT CRASHES !!!
if (strcmp(table[h]->word, word) == 0) { // found
table[h]->len = len;
return; // exit function and skip the rest
}
i++; // increment loop index
}
// found empty element
if (strcmp(table[h]->word, "") == 0) {
struct Entry *en;
en->word = word;
en->len = len;
en->next = table[h];
table[h] = en;
}
}
int main() {
init(); // initialize hash table
// test call
insertElement("kkj\0", 2);
int i;
for ( i=0; i < 10; i++)
{
printf("%d: ", i);
struct Entry *enTemp = table[i];
while (enTemp->next != NULL)
{
printf("Word: %s, Len:%d)", enTemp->word, enTemp->len);
enTemp = enTemp->next;
}
printf("\n");
}
return 0;
}
答案 0 :(得分:2)
没有必要从malloc转换返回值,这样做可以掩盖其他错误。
以下行malloc内存永远不会被释放,因此哈希函数中存在内存泄漏。
// an array of 26 slots for 26 uppercase letters in the alphabet
A = (char *)malloc(26 * sizeof(char));
// an array of 26 slots for 26 lowercase letters in the alphabet
a = (char *)malloc(26 * sizeof(char));
根据定义,sizeof(char)保证为1,因此不必乘以sizeof(char)。
您的代码也假设字符的ascii布局,这是无法保证的。
在init()函数中,你有
// create memory spaces for each element
struct Entry *en = (struct Entry *)malloc(sizeof(struct Entry));
没有做评论所说的。它只为一个struct Entry分配足够的内存。也许你打算把它放在循环中。
对于固定的表大小,您也可以只有一个struct Entry数组 直接而不是指向这样的指针数组。即。
struct Entry table[TABLE_SIZE] = { 0 };
然后你不需要malloc内存用于条目本身,只需要内容。
在初始化循环中
for (i = 0; i < TABLE_SIZE; i++) {
en->word = "";
en->len = 0;
en->next = table[i];
table[i] = en;
}
每个en-&gt; next设置为自身,并且所有表元素都设置为相同的值。第一次通过循环时,en-&gt; next设置为table [0],由于你的静态初始化器,此时为NULL。然后将table [0]设置为en。
第二次循环,en-&gt; next设置为table [1],也是null。并且en没有改变,它仍然指向早期malloc的结果。然后将table [1]设置为en,这与之前的值相同。所以,当你完成后,表的每个元素都被设置为相同的值,并且en-&gt; next是NULL。
我没有通过哈希函数进行跟踪,但我没有立即看到 任何限制使用哈希值到表的可能索引的东西。当我测试它时,“kkj \ 0”(顺便说一句,C中的字符串文字已经空终止,因此不需要\ 0。)的哈希值为29,超出了有效值 表的索引。所以你正在访问超出表限制的内存 阵列。在那一刻,所有赌注都已关闭,几乎任何事情都可能发生。一个 在这种情况下,seg故障实际上是一个很好的结果,因为它是立即的 显而易见的事情是错的。您需要以表为模的哈希值 用于修复数组边界问题的大小,即h%TABLE_SIZE。