【问题标题】:Address is not stack'd, malloc'd or (recently) free'd地址不是stack'd,malloc'd或(最近)free'd
【发布时间】:2015-07-12 04:43:21
【问题描述】:

我是 C 新手,所以在制作哈希表和分配空间时遇到了麻烦。

我正在做一个字谜求解器。现在我还在为这个程序创建哈希表的步骤。我正在尝试通过使用一些随机参数调用该函数一次来测试我的插入函数以查看它是否正常工作。

但是,我不断遇到分段错误,我使用 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;
}

【问题讨论】:

  • 怀疑你想要一个副本:en-&gt;word = strdup(word);
  • 注意:这只会使 1 en struct Entry *en = (struct Entry *)malloc(sizeof(struct Entry));
  • 关于系统函数" malloc() 1) 不要强制转换返回值 2) 始终检查 (!=NULL) 返回值以确保操作成功
  • 关于这一行:'insertElement("kkj\0", 2);'文字“kkj\0”的格式不正确。当定义一个 char 数组时,比如这个字面量,编译器会自动附加一个 '\0' 所以这个字面量在内存中会是:'k','k','j','\0','\ 0' 这不是我们所需要的。

标签: c malloc hashtable


【解决方案1】:

不需要从 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 table[TABLE_SIZE] = { 0 };

然后您就不需要为条目本身分配内存,只需为内容分配内存。

在你的初始化循环中

for (i = 0; i < TABLE_SIZE; i++) {
    en->word = "";
    en->len = 0;
    en->next = table[i];
    table[i] = en;
}

每个 en->next 都设置为自身,并且所有表格元素都设置为相同的值。第一次通过循环,en->next 设置为 table[0],由于您的静态初始化程序,此时它为 NULL。然后将 table[0] 设置为 en。

第二次循环,en->next设置为table[1],同样为null。并且 en 没有改变,它仍然指向之前 malloc 的结果。然后将 table[1] 设置为 en,这与您之前的值相同。所以,当你完成后,table 的每个元素都设置为相同的值,并且 en->next 为 NULL。

我没有追踪过哈希函数,但我没有立即看到 将散列值的使用限制为表的可能索引的任何东西。当我测试它时,“kkj\0”(顺便说一句,C 中的字符串文字已经以 null 结尾,因此不需要 \0。)的哈希值为 29,超出了有效值 表的索引。因此,您正在访问表限制之外的内存 大批。到那时,所有的赌注都没有了,几乎任何事情都可能发生。一种 在这种情况下 seg fault 实际上是一个很好的结果,因为它立即 很明显有些不对劲。您需要将哈希值取模表 修复数组边界问题的大小,即 h % TABLE_SIZE。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多