【问题标题】:How to fix runtime error: load of null pointer of type 'const char如何修复运行时错误:加载 'const char 类型的空指针
【发布时间】:2019-03-25 12:24:36
【问题描述】:

我需要编写在哈希表中加载字典的函数。我对错误消息感到困惑:c:37:20 运行时错误:加载类型为“const char”的空指针,在分段错误中运行。

我尝试改变加载功能,但仍然没有帮助。并且还尝试为哈希表分配内存,因为我认为问题可能在于内存泄漏。

`  // Represents number of buckets in a hash table
#define N 26

// Represents a node in a hash table
typedef struct node
{
    char word[LENGTH + 1];
    struct node *next;
}
node;

// Represents a hash table
node *hashtable[N];
// Hashes word to a number between 0 and 25, inclusive, based on its first letter
unsigned int hash(const char *word)
{
    // Allocates memory for hashtable
    int  *ht = malloc(26*sizeof(int));
    if(!ht)
    {
        unload();
        return false;
    }
    return tolower(word[0]) - 'a';  // this is error line 37:20
}

// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{

    // Initialize hash table
    for (int i = 0; i < N; i++)
    {
        hashtable[i] = NULL;
    }

    // Open dictionary
    FILE *file = fopen(dictionary, "r");
    if (file == NULL)
    {
        unload();
        return false;
    }

    // Buffer for a word
    char word[LENGTH + 1];

    // Insert words into hash table
    while (fscanf(file, "%s", word) != EOF)
    {

        for (int i = 0; i < N; i++ )
        {
            // Allocate memory for node for each new word
            node *new_node = malloc(sizeof(node));
            if (!new_node)
            {
                unload();
                return false;
            }
            // Copies word into node
            strcpy(new_node->word, word);
            new_node->next = NULL;
            // Hashes word
            hash(new_node->word);
            // Inserts word into linked list
            if(hashtable[i] == 0)
            {
                hashtable[i] = new_node;

            }
            else if(hashtable[i] == new_node)
            {
               new_node->next = hashtable[i];
               hashtable[i] = new_node;
            }
        }
    }

    // Close dictionary
    fclose(file);

    // Indicate success
    return true;
}

加载字典时,函数 load 应该返回 true。但我得到分段错误。这是否意味着我没有从加载函数中得到正确的输出?

【问题讨论】:

  • 缺少的东西:第 37 行是哪一行
  • 对不起,如果我的问题有任何错误。我是第一次使用堆栈))))你可以在代码中看到它 return tolower(word[0]) - 'a'; // 这是错误行 37:20
  • 另外,有问题的代码不是minimal reproducible example - 例如node 的定义是什么
  • 另外hash 返回一个,您可能希望将其存储在变量中并稍后使用,但我没有看到任何证据 - 而是丢弃返回值并稍后使用i
  • 这是结构节点和哈希表的定义 // 表示哈希表中的桶数 #define N 26 也许我 malloc memoryfor hashtable 的方式错误? // 表示哈希表中的一个节点 typedef struct node { char word[LENGTH + 1];结构节点*下一个; } 节点; // 表示一个哈希表节点 *hashtable[N];

标签: c


【解决方案1】:

       new_node->next = NULL;
       hash(new_node->word);
       // Inserts word into linked list
       if(hashtable[i] == 0)
       {
           hashtable[i] = new_node;

       }
       else if(hashtable[i] == new_node)
       {
          new_node->next = hashtable[i];
          hashtable[i] = new_node;
       }

你不使用 hash() 的结果并且你使用 i 而不是散列结果作为 hashtable 中的索引,如果 N 大于 26,您从 hashtable 中读取/写入,在另一种情况下,您没有将单词放在正确的条目中,因为第一个在索引 0,下一个在索引1 等等,不管他们的第一个字母

注意else if(hashtable[i] == new_node) 永远不会为真,实际上永远不会到达,因为if(hashtable[i] == 0) 始终为真,因为您限制了要阅读的字数

必须是类似的东西,做最小的改变

        int h = hash(new_node->word);

        // Inserts word into linked list
        if(hashtable[h] == 0)
        {
            hashtable[h] = new_node;
            new_node->next = NULL;
        }
        else 
        {
           new_node->next = hashtable[h];
           hashtable[h] = new_node;
        }

但实际上可以简化为:

        int h = hash(new_node->word);

        new_node->next = hashtable[h];
        hashtable[h] = new_node;

注意我想你不会多次阅读同一个词(它是一本字典)


待办事项

while (fscanf(file, "%s", word) != EOF)

很危险,因为如果读取的单词长度超过 LENGTH,则没有保护

假设 LENGTH 是 32 do(这个词可以多存储 32 个字符,最后的空字符):

while (fscanf(file, "%32s", word) == 1)

没有理由有循环:

   for (int i = 0; i < N; i++ )
   {
    ...
   }

删除它(当然不是它的主体),所以:

while (fscanf(file, "%32s", word) == 1)
{
    // Allocate memory for node for each new word
    node *new_node = malloc(sizeof(node));
    if (!new_node)
    {
        unload();
        return false;
    }
    // Copies word into node
    strcpy(new_node->word, word);

    int h = hash(new_node->word);

    new_node->next = hashtable[h];
    hashtable[h] = new_node;
}

部分

// Initialize hash table
for (int i = 0; i < N; i++)
{
    hashtable[i] = NULL;
}

没用,因为 hashtable 是全局的,用 0 初始化

如果你想重新加载字典,你需要在重置为NULL之前释放链表


内存泄漏

hash 中的 malloc 没用,只会造成内存泄漏,删除它:

// Hashes word to a number between 0 and 25, inclusive, based on its first letter
unsigned int hash(const char *word)
{
    return tolower(word[0]) - 'a';
}

警告如果第一个字母不是 a-z 或 A-Z,则返回索引不是 hashtable

的有效索引

出于可读性原因,将#define N 26 替换为#define N ('z' - 'a' + 1)


添加缺失定义的提案:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#define bool int
#define true 1
#define false 0

// Represents number of buckets in a hash table
#define N ('z' - 'a' + 1)

// Represent max word length
#define LENGTH 32

// Represents a node in a hash table
typedef struct node
{
    char word[LENGTH + 1];
    struct node * next;
}
node;

// Represents a hash table
node * hashtable[N];

// Hashes word to a number between 0 and 25, inclusive, based on its first letter
unsigned int hash(const char *word)
{
  return tolower(word[0]) - 'a';
}

// probable goal : empty hashtable 
void unload()
{
  for (size_t i = 0; i != N; ++i) {
    while (hashtable[i] != NULL) {
      node * next = hashtable[i]->next;

      free(hashtable[i]);
      hashtable[i] = next;
    }
  }  
}

// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
  // Open dictionary
  FILE * file = fopen(dictionary, "r");

  if (file == NULL)
    return false;

  // Buffer for a word
  char word[LENGTH + 1];

  // Insert words into hash table
  while (fscanf(file, "%32s", word) == 1)
  {
    if (isalpha(word[0])) {
      // Allocate memory for node for each new word
      node * new_node = malloc(sizeof(node));

      if (!new_node)
      {
        unload();
        return false;
      }

      // Copies word into node
      strcpy(new_node->word, word);

      int h = hash(new_node->word);

      new_node->next = hashtable[h];
      hashtable[h] = new_node;
    }
  }

  // Close dictionary
  fclose(file);

  // Indicate success
  return true;
}

int main(int argc, char ** argv)
{
  if (argc != 2)
    printf("Usage : %s <dictionary>\n", *argv);
  else if (!load(argv[1]))
    fprintf(stderr, "Error when loading '%s'\n", argv[1]);
  else {
    puts("dictionary content");

    for (size_t i = 0; i != N; ++i) {
      node * n = hashtable[i];

      if (n != NULL) {
        printf("%c :", i + 'a');
        do {
          printf(" %s", n->word);
          n = n->next;
        } while (n != NULL);
        putchar('\n');
      }
    }

    unload();
  }
}

编译和执行:

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra -Wall d.c
pi@raspberrypi:/tmp $ cat d
alternate
bellow and
Below
dictionary
Hash main zombie
test
Zorro
pi@raspberrypi:/tmp $ ./a.out
Usage : ./a.out <dictionary>
pi@raspberrypi:/tmp $ ./a.out d
dictionary content
a : and alternate
b : Below bellow
d : dictionary
h : Hash
m : main
t : test
z : Zorro zombie

valgrind下执行:

pi@raspberrypi:/tmp $ valgrind ./a.out d
==2370== Memcheck, a memory error detector
==2370== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2370== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==2370== Command: ./a.out d
==2370== 
dictionary content
a : and alternate
b : Below bellow
d : dictionary
h : Hash
m : main
t : test
z : Zorro zombie
==2370== 
==2370== HEAP SUMMARY:
==2370==     in use at exit: 0 bytes in 0 blocks
==2370==   total heap usage: 13 allocs, 13 frees, 5,872 bytes allocated
==2370== 
==2370== All heap blocks were freed -- no leaks are possible
==2370== 
==2370== For counts of detected and suppressed errors, rerun with: -v
==2370== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)

【讨论】:

  • 非常感谢,布鲁诺!但是哈希表只有 26 个桶(ASCII 中的字母,而不是我应该使用链表(我插入节点的地方)而且 s the part of a task to use this hashfunction with return value only first letters. And I really dont 不明白如何链接节点和哈希表桶,这是数组元素,不是指针
  • @ksju 是的,你实现了一种哈希表,所以你有同义词,并且为同义词使用链表是经典的。如果您考虑到我在回答中所说的内容,那一定没问题,并且您可以阅读任意数量的单词(不限于 26 个)
  • @ksju 我错过了说您需要删除 for (int i = 0; i &lt; N; i++ ) (但不是它的正文),因为我认为目标是仅通过首字母引用单词
  • 我也错过了,这部分代码是CS 50任务,有些代码是默认的,例如哈希函数,节点和哈希表声明,我不能改变它公式(仅散列第一个字母)。但我对错误消息在他们的(CS50)代码中而不是我的这一事实感到困惑
  • @ksju 没问题,除了命名 hash 并不真正对应函数的目标。如果您进行更改,我所说的您的程序必须有效。我编辑了答案以添加完整定义更多执行示例
猜你喜欢
  • 2020-06-01
  • 2021-05-11
  • 1970-01-01
  • 2020-01-03
  • 2023-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多