2

在过去的 48 小时左右,我一直在努力尝试在 C 中实现这个哈希表函数。我的代码相当长(我意识到它不是最有效的,其中一些更多的是我在玩 C 来获得感觉它是如何工作的等)。

我遇到的问题是底部的主程序的最后一行(打印 MyEntry->Name)。我收到总线错误,不确定原因。我不相信我应该在主驱动程序中为这个指针分配内存,但我可能是错的。

很抱歉这段代码的长度。BTW SymEntry 是 'struct SymEntry{char *Name, void *Attributes, struct SymEntry *Next}

#include <strings.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdbool.h>
#include "SymTab.h"



struct SymTab * CreateSymTab(int Size)
{
   struct SymTab *symtable;
   if(!(symtable=malloc(sizeof(struct SymTab)))) return NULL;
   if(!(symtable->Contents=calloc(Size, sizeof(struct SymEntry*)))) {
          free(symtable);
          return NULL;
   }

   symtable->Size=Size;
   return symtable;
}

/* hash form hash value for string s, taken from 'The C Programming Language'*/
unsigned hash(struct SymTab *ATable, const char *s)
{
     unsigned hashval, size;
     size = ATable->Size;;
     for (hashval = 0; *s != '\0'; s++)
         hashval = *s + 31 * hashval;
     return hashval % size;
}

bool EnterName(struct SymTab *ATable,
          const char *Name,
          struct SymEntry **AnEntry)
{
          struct SymEntry *ptr;
          unsigned hashvalue;
          char *string;
          struct SymEntry *previous;

          string = malloc(strlen(Name)+1);
          AnEntry=(struct SymEntry**)malloc(sizeof(struct SymEntry*));

          strcpy(string, Name);
          printf("string is: is %s\n",string);
          hashvalue = hash(ATable, string);

          printf("hv is %d\n",hashvalue);
          ptr = ATable->Contents[hashvalue];
          previous = NULL;

          while(ptr)
          {
              printf("WHILE LOOP\n");
              if(!(strcmp(ptr->Name,string)))
              {
                  printf("if(!strcmp(ptr->Name,string))\n");
                  *AnEntry = ptr;
                  return true;
              }
              previous = ptr;
              ptr=ptr->Next;
          }
          if(previous)
          {
              printf("IF (PREVIOUS)\n");
              if(!(ptr=malloc(sizeof(struct SymEntry)))) return false;
              if(!(ptr->Name=string))
              {
                  printf("if(!(ptr->Name=string))\n");
                  free(ptr);
                  return false;
              }
              ptr->Name = string;
              previous->Next = ptr;
              printf("Previous->Next: %s\n", previous->Next->Name);
              *AnEntry = ptr;
              return false;
          }
          else
          {
              printf("ELSE (PREVIOUS)\n");
              if(!(ptr=malloc(sizeof(struct SymEntry)))) return false;
              if(!(ptr->Name=string))
              {
                  printf("if(!(ptr->Name=string))\n");
                  free(ptr);
                  return false;
              }
              ptr->Name = string;
              ATable->Contents[hashvalue] = ptr;
              printf("here\n");
              *AnEntry = ptr;
              printf("there\n");
              return false;
          }

}

struct SymEntry * FindName(struct SymTab *ATable, const char *Name)
{
   struct SymEntry *Entry;
   unsigned hashvalue;

   hashvalue = hash(ATable, Name);
   Entry = ATable->Contents[hashvalue];

   while(Entry)
   {
               if(strcmp(Name,Entry->Name)==0)
               {
                                              return Entry;
               }
   }
   return NULL;
}



main(int argc, char **argv)
{
   struct SymTab *mysymtab;
   struct SymEntry *myEntry;

   mysymtab = CreateSymTab(1);
   const char *string1 = "HELLO";
   printf("%d\n",6);
   EnterName(mysymtab, string1, &myEntry);
   printf("first: %s\n", mysymtab->Contents[0]->Name);
   EnterName(mysymtab, string1, NULL);
   EnterName(mysymtab, "WORLD", NULL);
   printf("second: %s\n", mysymtab->Contents[0]->Name);
   printf("second->Next: %s\n", mysymtab->Contents[0]->Next->Name);
   EnterName(mysymtab, "!@#$%", &myEntry);
   printf("third: %s\n", mysymtab->Contents[0]->Name);
   printf("third->Next: %s\n", mysymtab->Contents[0]->Next->Name);
   printf("third->Next->Next: %s\n", mysymtab->Contents[0]->Next->Next->Name);
   printf("myEntry->Name: %s\n", myEntry->Name);
}
4

2 回答 2

7

问题是 EnterName 中的这一行:

AnEntry=(struct SymEntry**)malloc(sizeof(struct SymEntry*));

您需要删除它,因为您希望 AnEntry 指向调用者指定的参数。

由于 AnEntry 可能为 NULL,因此您还需要更改以下每个实例:

*AnEntry = ptr;

到:

if (AnEntry)
    *AnEntry = ptr;

发生的事情是,当函数启动时,AnEntry 指向调用者想要更改的指针。当您更改 AnEntry 的值(即AnEntry = ...;)时,您的代码不会修改调用者希望您更改的指针,而是一些内部指针。因此,当 EnterName 返回时,myEntry 仍然指向内存中的某个随机位置。

于 2010-02-02T22:40:35.610 回答
0

在你学习的时候,你的代码中有一些风格上的 WTF。以这部分为例。

if(!(ptr=malloc(sizeof(struct SymEntry)))) return false;
if(!(ptr->Name=string))
{
    printf("if(!(ptr->Name=string))\n");
    free(ptr);
    return false;
}
ptr->Name = string;

这是不一致的。您为上面的 AnEntry 转换了 malloc 的返回,但不是这个 malloc。做一个或另一个,但不要混合它。更好的是,以根本不需要演员的方式编写它。

你不应该在 if 语句中赋值。虽然在 malloc 情况下您想要做什么仍然很清楚,但意图在字符串分配中被混淆了。特别是因为它是多余的。当 if 计算结果为 true 时,ptr 立即被释放。当它评估为假时,将再次完成完全相同的分配。此外,在这种情况下,它会阻止明显的优化。

这是重写的相同代码:

if (string == NULL)
{
    printf("string == NULL\n");
    return false;
}
ptr = malloc(sizeof *ptr);
if (ptr == NULL)
{
    return false;
}
ptr->Name = string;
于 2010-02-03T07:28:43.077 回答