Изучение указателей в C - PullRequest
       13

Изучение указателей в C

2 голосов
/ 03 февраля 2010

Последние 48 часов я резала зубы, пытаясь реализовать эту функцию хэш-таблицы в C. Мой код довольно длинный (я понимаю, что он не самый эффективный, некоторые из них мне больше нравятся)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);
}

Ответы [ 2 ]

7 голосов
/ 03 февраля 2010

Проблема в этой строке в EnterName:

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

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

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

*AnEntry = ptr;

до:

if (AnEntry)
    *AnEntry = ptr;

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

0 голосов
/ 03 февраля 2010

Пока вы учитесь, в вашем коде есть несколько стилистических 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 немедленно освобождается. Когда оно оценивается как ложное, то же самое назначение выполняется снова. Кроме того, в этом случае это предотвращает очевидную оптимизацию.

Вот тот же код, переписанный:

if (string == NULL)
{
    printf("string == NULL\n");
    return false;
}
ptr = malloc(sizeof *ptr);
if (ptr == NULL)
{
    return false;
}
ptr->Name = string;
...