【问题标题】:C using malloc and free correctly in a program I wrote在我编写的程序中正确使用 malloc 和 free 的 C
【发布时间】:2015-12-15 12:30:27
【问题描述】:

在我参加的一门课程中,有一个 pset 涉及读取字典文件,并从中创建哈希表,通过检查是否可以找到文本中的单词来检查另一个文件中单词的正确拼写在哈希表中。然后从内存中卸载它。

程序中有两个文件。我没有编写的一个文件(并且肯定没有问题),它首先运行并调用我编写的 .c 文件的函数:

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

#include "dictionary.h"

#define DICSIZE 10000

typedef struct node
{

    char* word;
    struct node* next;

} 
node;

typedef struct table
{
    node** table;
    unsigned int wordCount;
}
table;

// initialize table for scope purposes
struct table* hashTable = NULL;

// declaration of the hash function
unsigned long hashDJB2(unsigned char *str);
// declaration of the string duplication function
char* mystrdup(const char* s);
// declaration of the lowercase function
char* returnLowerCase(const char* str);

/**
 * Returns true if word is in dictionary else false.
 */
bool check(const char* word)
{
    node* list = NULL;
    char* wrd = returnLowerCase(word);
    unsigned long hashValue = hashDJB2((unsigned char*) wrd);
    for (list = hashTable->table[hashValue]; list != NULL; list = list->next) {

        if (strcmp(list->word, wrd) == 0) {
            return true;
        }
    }
    free(wrd);
    return false;
}

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

    // allocation of memory for the table structure
    if ((hashTable = malloc(sizeof(struct table))) == NULL) {

        printf("Error allocating memory for table pointer\n");
        return false;

    }

    // allocate pointers to table itself
    if ((hashTable->table = malloc((sizeof(node*) * DICSIZE) + sizeof(unsigned int))) == NULL) {

        printf("Error allocating memory for heads of list\n");
        return false;

    }

    // initialize head nodes to NULL
    for (int i = 0; i < DICSIZE; i++) {

        hashTable->table[i] = NULL;
    }

    // initialize wordCount to zero
    hashTable->wordCount = 0;

    /*
    * Till now, was the creation of the backbone structure.
    * Now, implementation of hash() function and loading the words
    * onto the table.
    */ 

    FILE* dp;
    dp = fopen(dictionary, "r");

    if (dp == NULL) {
        printf("Error in reading from dictionary\n");
        return false;
    }

    // reading words from dictionary
    char newWord[LENGTH + 1];
    while (fscanf(dp, "%s", newWord) == 1) {


        // determine the hash value of the 
        unsigned long hashValue = hashDJB2((unsigned char*) newWord);

        // in the pset, they say i don't have to check whether the word already exists
        // if (! check((const char*) newWord)) {

            // if not, insert a new node:

            // attempt to create a new node
            node* newNode = NULL;
            if ((newNode = malloc(sizeof(node))) == NULL) {

                printf("Error: couldnt allocate a new node\n");
                return false;
            }

            // insert new node to the beginning of the list
            newNode->word = mystrdup(newWord);
            newNode->next = hashTable->table[hashValue];
            hashTable->table[hashValue] = newNode;
            hashTable->wordCount++;

        //}
    }    
    //free(dp);
    return true;
}

/**
 * Returns number of words in dictionary if loaded else 0 if not yet loaded.
 */
unsigned int size(void)
{

    unsigned int wordCount = hashTable->wordCount;
    return wordCount;
}

/**
 * Unloads dictionary from memory.  Returns true if successful else false.
 */
bool unload(void)
{

    node* head = NULL;
    long i = 0;
    for (head = hashTable->table[i]; head != NULL; head = hashTable->table[++i]) {

        node* list = NULL;
        for (list = head; list != NULL; list = head) {

            head = head->next;
            free(list->word);
            free(list);
        }
    }
    free(hashTable->table);
    free(hashTable);
    return true;
}

// djb2 algorithm, created by Dan Bernstein
unsigned long hashDJB2(unsigned char *str)
{
    unsigned long hash = 5381;
    int c;

    while ((c = *str++))
        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */

    return hash % DICSIZE;
}

char* mystrdup(const char* s)
{
    char* p = malloc(sizeof(char) * strlen(s)+1);
    if (p) strcpy(p, s);
    return p;
}

char* returnLowerCase(const char* str) {

    int len = strlen(str);
    char* p = malloc(sizeof(char) * (len + 1));
    for (int i = 0; i < len; i++) {
        p[i] = tolower(str[i]);
    }
    p[len + 1] = '\0'; // this line made the program crash. It was fixed already.

    return p;
}

首先“speller.c”(我从 pset 获得)调用 load() 函数,然后调用 check() 函数数万次(取决于文本中的单词数),然后卸下()。我的检查和卸载部分有问题。当文本很小时, check() 功能正常,但是当它变大时,我会收到如下错误:

拼写器:malloc.c:2372: sysmalloc: 断言 `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2]) ) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 *(sizeof(size_t))) - 1)) & ~((2 *(sizeof (size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long) old_end & pagemask) == 0)' 失败。 中止(核心转储)

第一个问题,好像是我分配内存的方式有问题。另一个问题是我无法释放所有分配的内存。

由于某种原因,valgrinds --track-origins=yes 不起作用,所以我从中得到的只是:

==3852== 
==3852== HEAP SUMMARY:
==3852==     in use at exit: 101,650 bytes in 18,547 blocks
==3852==   total heap usage: 305,376 allocs, 286,829 frees, 2,730,448 bytes allocated
==3852== 
==3852== LEAK SUMMARY:
==3852==    definitely lost: 101,298 bytes in 18,546 blocks
==3852==    indirectly lost: 0 bytes in 0 blocks
==3852==      possibly lost: 0 bytes in 0 blocks
==3852==    still reachable: 352 bytes in 1 blocks
==3852==         suppressed: 0 bytes in 0 blocks
==3852== Rerun with --leak-check=full to see details of leaked memory
==3852== 
==3852== For counts of detected and suppressed errors, rerun with: -v
==3852== Use --track-origins=yes to see where uninitialised values come from
==3852== ERROR SUMMARY: 57191 errors from 5 contexts (suppressed: 0 from 0)

我很想在这方面得到一些帮助。

【问题讨论】:

  • 用户 Paul R 对“p[len + 1] = '\0';”发表评论后,我已修复它,程序停止崩溃。此外,我在 check() 函数中添加了“free(wrd)”,然后在字典中找到一个单词后返回 true。这仅导致 1 个上下文中的 1 个错误,以及 1 个块中 352 个字节的内存泄漏。

标签: c memory-management malloc valgrind free


【解决方案1】:

一个错误(可能还有其他错误),在returnLowerCase()

p[len + 1] = '\0';

应该是:

p[len] = '\0';

(您已分配len + 1 字符,因此有效索引为0..len(含),实际字符串位于索引0..len-1 处,\0 终止符位于索引len 处。)

【讨论】:

  • 天哪,谢谢!这使我的程序免于在调用 check() 时崩溃。现在剩下的就是正确释放内存了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-20
  • 2021-12-11
  • 2019-03-29
  • 1970-01-01
  • 2011-04-14
  • 2015-04-23
  • 2012-03-16
相关资源
最近更新 更多