簡體   English   中英

用C學習指針

[英]Learning Pointers in C

在過去48個小時左右的時間里,我一直在努力嘗試在C中實現此哈希表功能。我的代碼相當長(我意識到這不是最有效的方法,其中有些是我與C一起玩以獲得更多對其工作方式的感覺等)。

我遇到的問題是主程序的最后一行在底部(打印MyEntry-> Name)。 我收到總線錯誤,不確定為什么。 我不認為我應該在主驅動程序中為此指針分配內存,但是我可能錯了。

抱歉,這段代碼的長度。 BTW SymEntry是'struct SymEntry {char *名稱,無效*屬性,struct 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, "!@#$%", &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);
}

問題是EnterName中的這一行:

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

您需要刪除它,因為您希望AnEntry指向調用方指定的參數。

由於AnEntry可能為NULL,因此您還需要更改以下每個實例:

*AnEntry = ptr;

至:

if (AnEntry)
    *AnEntry = ptr;

發生的情況是,當函數啟動時,AnEntry指向調用者想要更改的指針。 當您更改AnEntry的值(即AnEntry = ...; )時,您的代碼將不會修改調用者希望您更改的指針,而是會修改一些內部指針。 因此,當EnterName返回時,myEntry仍指向內存中的某個隨機位置。

在學習時,您的代碼中包含一些樣式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;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM