如何修复运行时错误:加载类型为'const char的空指针

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何修复运行时错误:加载类型为'const char的空指针相关的知识,希望对你有一定的参考价值。

我需要编写在哈希表中加载字典的函数。我对错误消息感到困惑: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;

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

答案

       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而不是哈希结果作为哈希表中的索引,如果N大于26你读/写哈希表,在另一种情况下你不把这个词放在右边因为第一个在索引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(单词可以存储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;

因为全局哈希表初始化为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,则返回索引不是哈希表的有效索引


出于可读性原因,请用#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)

以上是关于如何修复运行时错误:加载类型为'const char的空指针的主要内容,如果未能解决你的问题,请参考以下文章

如何修复 GCC 编译中的 const char * 构造函数转换链错误

如何修复这个与 div 相关的运行时错误为零?

如何修复解析器错误消息:无法加载类型?

在 Windows 机器上运行 RSKj 节点时如何修复 LevelDB 库加载错误?

如何修复错误'设计者必须创建类型的实例“”但不能因为它标记为抽象“

错误:对类型为'const ItemInstance'的引用无法绑定到类型为'void'的右值