【问题标题】:Learning Pointers in CC中的学习指针
【发布时间】:2010-02-02 22:36:38
【问题描述】:

过去 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);
}

【问题讨论】:

  • 如果您是 C 新手,并且没有使用调试器(我认为这是所有 printfs 的原因),我建议您花点时间使用一个,因为这样可以节省很多时间并且把许多奇怪的虫子做成肉馅。无论如何,这就是我的经历。

标签: c pointers printf bus


【解决方案1】:

问题在于 EnterName 中的这一行:

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

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

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

*AnEntry = ptr;

到:

if (AnEntry)
    *AnEntry = ptr;

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

【讨论】:

  • 感谢工作。现在我想起来了,这是有道理的。再次感谢!
  • 在主题上,每个 SymEntry 的 Next 指针在所有情况下都应设置为 NULL,而在“else”情况下则不是。
  • 是的,我也发现了。此外,我现在修复的 FindName 函数中有一个无限循环...忘记遍历列表。
【解决方案2】:

在您学习的过程中,您的代码中有一些风格上的 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;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-18
    • 1970-01-01
    • 1970-01-01
    • 2021-05-16
    • 2011-11-14
    • 2010-09-26
    • 1970-01-01
    相关资源
    最近更新 更多