2

私は過去48時間ほど歯を食いしばっており、このハッシュテーブル関数をCで実装しようとしています。私のコードはかなり長いです(これは最も効率的ではないことに気づきました。それがどのように機能するかなどの感触)。

私が抱えている問題は、メインプログラムの最後の行が一番下にあることです(MyEntry-> Nameを出力します)。バスエラーが発生しましたが、理由がわかりません。このポインタのメインドライバにメモリを割り当てることになっているとは思いませんが、間違っている可能性があります。

このコードの長さについて申し訳ありません。ところで、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-case で何をしたいのかはまだ明らかですが、意図は文字列の割り当てで難読化されています。特に余計だから。if が true と評価されると、ptr はすぐに解放されます。false と評価されると、まったく同じ割り当てが再度行われます。さらに、この場合、明らかな最適化が妨げられます。

同じコードを次のように書き直します。

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 に答える