2013-05-21 63 views
2

我现在正在研究哈佛大学的cs50的pset6,问题是要实现一个trie词典。 我终于设法使它工作一个小问题。无法正确释放内存

  1. 当我运行valgrind检查内存泄漏时,它告诉我我释放了比分配的多一个,但在卸载函数中看不到任何问题。
  2. 它也警告我有一些未初始化的值,但我无法弄清楚,尽管它不会影响结果。

这里是我的全部代码:

/**************************************************************************** 
* dictionary.c 
* 
* Computer Science 50 
* Problem Set 6 
* 
* valgrind warn that there are uninitialized values, could be the node struct, but don't 
* know how to initialize it, anyway, it works at last! 
* 
* Implements a dictionary's functionality. 
***************************************************************************/ 

#include <stdbool.h> 
#include <ctype.h> 
#include "dictionary.h" 
#include <string.h> 
#include <stdio.h> 
#include <stdlib.h> 

#define HASHTABLE_SIZE 5000 

int count = 0;  // gloabal counter 

typedef struct node {   // data structure 
    bool end_word; 
    struct node *children[27]; 
    } node; 

int 
charNumber(char c); // function prototype 

void 
freeNode(node *currentNode); 

node root = {false,{NULL}}; 
/* 
* Returns true if word is in dictionary else false. 
*/ 

bool 
check(const char *word) 
{ 
    node *ptr = &root; 
    for (int i=0;i<strlen(word);i++) 
    { 
     if (ptr->children[charNumber(word[i])] == NULL) 
      return false; 
     ptr = ptr->children[charNumber(word[i])]; 
    } 
    if (ptr->end_word) 
     return true; 
    else 
     return false; 
} 


/* 
* Loads dictionary into memory. Returns true if successful else false. 
*/ 

bool 
load(const char *dictionary) 
{ 
// char word[LENGTH+1]; // must initialize to zero! Or there will be some weird problem. 
    FILE *fp = fopen(dictionary,"r"); 
    if (fp == NULL) 
     return false; 
    while (!feof(fp)) 
    { 
     char word[LENGTH+1] = {}; 
     fscanf(fp,"%s\n",word); // have to use "%s\n" instead of "%s", or the count will be wrong, don't know why. 
     count++;  
     node *ptr = &root; 
     for (int i=0;i<strlen(word);i++) 
     { 
      if (ptr->children[charNumber(word[i])] == NULL) 
      { 
       node *new = malloc(sizeof(node)); 
       *new = (node) {false,{NULL}};  // initiallization 
       ptr->children[charNumber(word[i])] = new; 
       ptr = new; 
      } 
      else 
      { 
       ptr = ptr->children[charNumber(word[i])]; 
      } 
     } 
     ptr->end_word = true; 
    } 
fclose(fp);   
return true; 
} 


/* 
* caculate a number for the character 
*/ 

int 
charNumber(char c) 
{ 
    int num; 
    if (c == '\'') 
     return 26; 
    else if(c >= 'A' && c <= 'Z') 
     c += 32; 
    num = c - 'a'; 
    return num; 
} 



/* 
* Returns number of words in dictionary if loaded else 0 if not yet loaded. 
*/ 

unsigned int 
size(void) 
{ 
    if (count) 
     return count; 
    else 
     return 0; 
} 


/* 
* Unloads dictionary from memory. Returns true if successful else false. 
*/ 

bool 
unload(void) 
{ 
    freeNode(&root); 
    return true;   // can't figure out when to return false... 
} 

void freeNode(node *currentNode) 
{ 
    for (int i=0;i<27;i++) 
    { 
     if (currentNode->children[i] != NULL) 
      freeNode(currentNode->children[i]); 
    } 
    free(currentNode); 
} 

下面是一些Valgrind的输出:

==22110== Invalid free()/delete/delete[] 
==22110== at 0x4024ECD: free (vg_replace_malloc.c:366) 
==22110== by 0x8048F90: freeNode (dictionary_tries.c:152) 
==22110== by 0x8048F45: unload (dictionary_tries.c:141) 
==22110== by 0x8048AB5: main (speller.c:158) 
==22110== Address 0x804a5a0 is 0 bytes inside data symbol "root" 
==22110== 
--22110-- REDIR: 0x40b2930 (strchrnul) redirected to 0x4028570 (strchrnul) 


==22110== 
==22110== HEAP SUMMARY: 
==22110==  in use at exit: 0 bytes in 0 blocks 
==22110== total heap usage: 367,083 allocs, 367,084 frees, 41,113,776 bytes allocated 
==22110== 
==22110== All heap blocks were freed -- no leaks are possible 
==22110== 
==22110== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 14 from 9) 
==22110== 
==22110== 1 errors in context 1 of 1: 
==22110== Invalid free()/delete/delete[] 
==22110== at 0x4024ECD: free (vg_replace_malloc.c:366) 
==22110== by 0x8048F90: freeNode (dictionary_tries.c:152) 
==22110== by 0x8048F45: unload (dictionary_tries.c:141) 
==22110== by 0x8048AB5: main (speller.c:158) 
==22110== Address 0x804a5a0 is 0 bytes inside data symbol "root" 
==22110== 
--22110-- 
--22110-- used_suppression:  14 U1004-ARM-_dl_relocate_object 
==22110== 
==22110== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 14 from 9) 
+0

不使用'new'变量名。 – taocp

+4

请不要用C++标记C代码;这些语言本身的内存管理技术完全不同。在C++中,'new'是一个关键字,所以你的代码是严格的,但严格来说是C代码,与C++无关。 –

+0

如果'valgrind'给你警告,那么你应该在问题中包含那些警告的代表性例子。如果'valgrind'没有给出精确的行号,则需要在启用调试的情况下编译代码(通常为'-g'),以便它可以告诉您哪些行号出错。请注意,'malloc()'不会初始化内存。当你第一次分配它时,你似乎没有初始化结构中的“子”部分,这会导致问题。 –

回答

2

假设你load函数打开一个空白文件。 feof(fp)最初将返回0,因为读取操作尚未使用; EOF标志只有在读操作返回一个表示错误的值后才会被设置。这是错误所在。在你的情况下,你需要循环返回值fscanf(fp,"%s\n",word);而不是返回值feof。例如:

while (fscanf(fp, "%s", word) == 1) { 
    /* ... */ 
} 

if (feof(fp)) { 
    /* The loop ended due to EOF */ 
} 
else if (ferror(fp)) { 
    /* The loop ended due to some file input error */ 
} 
else { 
    /* The loop ended because the input was invalid 
    * (this applies to input where a conversion is 
    * required eg. the conversion in %d, %u, %f, etc... */ 
} 

要精心,feof只确定为什么上次读取失败

这会在空白文件的情况下导致此警告的原因是word将包含不确定的信息。

此外,freeNode(&root);是错误的,因为free只是要在由callocreallocmalloc返回指针调用。

0
node root = {false,{NULL}}; 

不是在堆中分配,但你尝试释放它喜欢它是

unload(void) 
{ 
    freeNode(&root); 
+0

实际上,'root'是一个全局变量,因此不太可能在堆栈上分配,因为它没有被动态分配,因此不应该被释放,但是 –

+0

更新了..但是它在哪里呢? ? – xaxxon

+0

哪里有实施决定把它记住堆栈和堆是在同一个地方... – Sebivor