2010-02-02 3 views
2

Я прорезал зубы в течение последних 48 часов или около того, пытаясь реализовать эту функцию хеш-таблицы в C. Мой код довольно длинный (я понимаю, что он не самый эффективный, некоторые из них более я играю с C, чтобы понять, как это работает и т. д.).Учёные указатели в C

Проблема, с которой я столкнулся, связана с последней строкой моей основной программы внизу (печать MyEntry-> Name). Я получаю ошибку в автобусе и не знаю, почему. Я не думаю, что я должен выделить память в главном драйвере для этого указателя, но я мог ошибаться.

Просим простенько про длину этого кода. КСТАТИ SymEntry является «структура SymEntry {символ * Имя, пустота * Атрибуты, структура SymEntry * Следующий}

#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, "[email protected]#$%", &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); 
} 
+0

Если вы новичок в C, и не с помощью отладчика (который я предполагаю, является причиной всех printfs) Я рекомендую брать время, чтобы получить удобный с одним, поскольку это сэкономит много часов и сделает фарш многих любопытных ошибок. Во всяком случае, это был мой опыт. – 2010-02-02 22:51:15

ответ

7

Проблема эта линия в EnterName:

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

Вам нужно удалить, что, как вы хотите AnEntry указать аргумент, указанный вызывающим.

Поскольку AnEntry может быть NULL, то вам также необходимо изменить каждый экземпляр:

*AnEntry = ptr; 

к:

if (AnEntry) 
    *AnEntry = ptr; 

Что происходит в том, что при запуске функции, AnEntry указывает на указатель, который вызывающий хочет изменить. Когда вы изменяете значение AnEntry (i.e AnEntry = ...;), ваш код не будет изменять указатель, который вы хотите изменить, но какой-либо внутренний указатель. Поэтому, когда EnterName возвращается, myEntry все еще указывает на некоторое случайное место в памяти.

+0

Спасибо, что сработал. Теперь мне кажется, что я думаю об этом. Еще раз спасибо! – James

+0

Хотя по этому вопросу каждый указатель SymEntry Next должен быть установлен в NULL во всех случаях, чего нет здесь в случае «else». – 2010-02-02 22:51:57

+0

Я тоже поймал это. Кроме того, в функции FindName есть бесконечный цикл, который я исправил сейчас ... забыл пройтись по списку. – James

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; 

Это непоследовательно. Вы передали возврат malloc для AnEntry выше, но не этот malloc. Либо делать то или другое, но не смешивать его. Еще лучше, напишите это так, чтобы не было необходимости в создании.

Вы не должны назначать значения внутри if-операторов. Хотя по-прежнему ясно, что вы хотите сделать в случае malloc, намерение запутывается в назначении строки. Тем более, что это лишнее. Когда 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; 
Смежные вопросы