程序崩溃使用malloc()和free()

时间:2013-07-21 18:14:39

标签: c malloc free

在尝试释放内存部分时,我似乎崩溃了我的程序。以下是我的链接列表的整体结构:

typedef struct {
    char                            *dataitem;
    struct listelement              *link;
    int16_t                         wordSize;
    int16_t                         (*libWord)[Q];
    char                            gpioValue;
    struct listelement              *syllables;
}listelement;

调用此函数时程序崩溃:

recordedWordsPointer = RemoveItem(recordedWordsPointer);                            // get rid of any junk stored in the recorded buffer

其中:

volatile listelement *recordedWordsPointer;

在libWord中存储了值,如果有另一个则指向下一个链接,否则为NULL。以下显示输入功能时会发生什么:

listelement * RemoveItem (listelement * listpointer) {
    cpu_irq_disable();
    listelement * tempp = listpointer;

    while( listpointer->syllables != NULL ){
        RemoveSyllable(listpointer->syllables);
    }
    if( listpointer != NULL ){
        tempp = listpointer -> link;
        free (listpointer->dataitem);
        free (listpointer->libWord);
        free (listpointer);
    }
    cpu_irq_enable();   
    return tempp;
}

void RemoveSyllable (listelement * listpointer) {

    while( listpointer->syllables != NULL ){
        RemoveSyllable(listpointer->syllables);
    }
    free (listpointer->dataitem);
    free (listpointer->libWord);
    free (listpointer);
    listpointer = NULL;
    return;
}

我想知道我是否做错了导致内存崩溃?

谢谢!

编辑:

我被要求展示如何构建内存位置以提供帮助。我使用以下两个函数:

listelement * AddItem (listelement * listpointer, char* name, int16_t size, int16_t wordLength, int16_t (*words)[Q]) {
    // returns listPointer at the beginning of list
    listelement * lp = listpointer;
    listelement * listPointerTemp;
    char ErrorHandler = NULL;
    // are we at the end of the list?
    if (listpointer != NULL) {
        // move down to the end of the list
        while (listpointer -> link != NULL)
        listpointer = listpointer -> link;
        listPointerTemp = listpointer;
        listpointer -> link = (struct listelement  *) malloc (sizeof (listelement));
        // on fail end links becomes NULL already above
        if(listpointer -> link != NULL){
            listpointer = listpointer -> link;
            listpointer -> link = NULL;
            listpointer -> wordSize = wordLength;
            listpointer -> syllables = NULL;

            listpointer -> dataitem = (char*) malloc ((size + 1)*sizeof(char));
            if(listpointer -> dataitem != NULL){
                for(int i=0; i<size ; i++){
                    listpointer -> dataitem[i] = name[i];
                }
                listpointer -> dataitem[size] = NULL;

                listpointer -> libWord =  (int16_t(*)[Q])malloc(wordLength*Q*sizeof(int16_t));
                if(listpointer -> libWord != NULL){
                    for (int16_t row=0 ; row < wordLength ; row++){
                        for (int col=0 ; col < Q ; col++){
                            listpointer -> libWord[row][col]  = words[row][col];
                        }
                    }
                    ErrorHandler = 1;
                }else{
                    free(listpointer->dataitem);
                    free(listpointer);
                    listPointerTemp -> link = NULL;
                }
            }else{
                free(listpointer);
                listPointerTemp -> link = NULL;
            }
        }
        if(ErrorHandler == NULL){
            //failure
            usart_write_line(&AVR32_USART0,"\r\n--------------------------------------------\r\n");
            usart_write_line(&AVR32_USART0,"Ran out of Memory!  Word not created.\r\n");
            usart_write_line(&AVR32_USART0,"\r\n--------------------------------------------\r\n");
        }
        return lp;
    } else {
        listpointer = (struct listelement  *) malloc (sizeof (listelement));

        if(listpointer != NULL){
            listpointer -> link = NULL;
            listpointer -> wordSize = wordLength;
            listpointer -> syllables = NULL;

            listpointer -> dataitem = (char*) malloc ((size + 1)*sizeof(char));
            if(listpointer -> dataitem != NULL){
                for(int16_t i=0; i<size ; i++){
                    listpointer -> dataitem[i] = name[i];
                }
                listpointer -> dataitem[size] = NULL;

                listpointer -> libWord =  (int16_t(*)[Q])malloc(wordLength*Q*sizeof(int16_t));
                if(listpointer -> libWord != NULL){
                    for (int16_t row=0 ; row < wordLength ; row++){
                        for (int col=0 ; col < Q ; col++){
                            listpointer -> libWord[row][col]  = words[row][col];
                        }
                    }
                    ErrorHandler = 1;
                }else{
                    free(listpointer->dataitem);
                    free(listpointer);
                    listPointerTemp -> link = NULL;
                }
            }else{
                free(listpointer);
                listPointerTemp -> link = NULL;
            }
        }
        if(ErrorHandler == NULL){
            //failure
            usart_write_line(&AVR32_USART0,"\r\n--------------------------------------------\r\n");
            usart_write_line(&AVR32_USART0,"Ran out of Memory!  Word not created.\r\n");
            usart_write_line(&AVR32_USART0,"\r\n--------------------------------------------\r\n");
        }
        return listpointer;
    }
}

listelement* AddSyllable (listelement * listpointer, char* name, int16_t size, int16_t wordLength, int16_t (*words)[Q]) {
    // returns listPointer at the beginning of list
    listelement * lp = listpointer;
    listelement * listPointerTemp;
    char ErrorHandler = NULL;
    // are we at the end of the list?
    if (listpointer != NULL) {
        // move down to the end of the list
        while (listpointer -> syllables != NULL)
        listpointer = listpointer -> syllables;
        listPointerTemp = listpointer;
        listpointer -> syllables = (struct listelement  *) malloc (sizeof (listelement));
        // on fail end links becomes NULL already above
        if(listpointer -> syllables != NULL){
            listpointer = listpointer -> syllables;
            listpointer -> link = NULL;
            listpointer -> wordSize = wordLength;

            listpointer -> dataitem = (char*) malloc ((size + 1)*sizeof(char));
            if(listpointer -> dataitem != NULL){
                for(int i=0; i<size ; i++){
                    listpointer -> dataitem[i] = name[i];
                }
                listpointer -> dataitem[size] = NULL;

                listpointer -> libWord =  (int16_t(*)[Q])malloc(wordLength*Q*sizeof(int16_t));
                if(listpointer -> libWord != NULL){
                    for (int16_t row=0 ; row < wordLength ; row++){
                        for (int col=0 ; col < Q ; col++){
                            listpointer -> libWord[row][col]  = words[row][col];
                        }
                    }
                    ErrorHandler = 1;
                }else{
                    free(listpointer->dataitem);
                    free(listpointer);
                    listPointerTemp -> syllables = NULL;
                }
            }else{
                free(listpointer);
                listPointerTemp -> syllables = NULL;
            }
        }
        if(ErrorHandler == NULL){
            //failure
            usart_write_line(&AVR32_USART0,"\r\n--------------------------------------------\r\n");
            usart_write_line(&AVR32_USART0,"Ran out of Memory!  Word not created.\r\n");
            usart_write_line(&AVR32_USART0,"\r\n--------------------------------------------\r\n");
        }
        return lp;
    } else {
        listpointer = (struct listelement  *) malloc (sizeof (listelement));

        if(listpointer != NULL){
            listpointer -> link = NULL;
            listpointer -> wordSize = wordLength;

            listpointer -> dataitem = (char*) malloc ((size + 1)*sizeof(char));
            if(listpointer -> dataitem != NULL){
                for(int16_t i=0; i<size ; i++){
                    listpointer -> dataitem[i] = name[i];
                }
                listpointer -> dataitem[size] = NULL;

                listpointer -> libWord =  (int16_t(*)[Q])malloc(wordLength*Q*sizeof(int16_t));
                if(listpointer -> libWord != NULL){
                    for (int16_t row=0 ; row < wordLength ; row++){
                        for (int col=0 ; col < Q ; col++){
                            listpointer -> libWord[row][col]  = words[row][col];
                        }
                    }
                    ErrorHandler = 1;
                }else{
                    free(listpointer->dataitem);
                    free(listpointer);
                    listPointerTemp -> syllables = NULL;
                }
            }else{
                free(listpointer);
                listPointerTemp -> syllables = NULL;
            }
        }
        if(ErrorHandler == NULL){
            //failure
            usart_write_line(&AVR32_USART0,"\r\n--------------------------------------------\r\n");
            usart_write_line(&AVR32_USART0,"Ran out of Memory!  Word not created.\r\n");
            usart_write_line(&AVR32_USART0,"\r\n--------------------------------------------\r\n");
        }
        return listpointer;
    }
}

2 个答案:

答案 0 :(得分:2)

您的RemoveSyllable函数实际上并未将syllables成员设置为NULL。你认为它在例程中,但实际上你只是在局部变量中改变它的值。

答案 1 :(得分:1)

初步观察

这是对代码的部分解构,而不是完整的答案。

您是否打开了编译器警告?如果没有,为什么不呢?

typedef struct {
    char                            *dataitem;
    struct listelement              *link;
    int16_t                         wordSize;
    int16_t                         (*libWord)[Q];
    char                            gpioValue;
    struct listelement              *syllables;
} listelement

请注意,linksyllables成员并未将您struct的匿名typedef指向listelement。他们指出了一些其他完全不相关的结构。编译器对此抱怨不已 - 有充分的理由。修复很简单:将typedef struct {更改为typedef struct listelement {。但是我们不应该在你的代码中处理这么多混乱。

您有时也会误用NULL。例如,char ErrorHandler = NULL;生成警告,指针正在转换为不同大小的整数。 NULL不一定是0;它至少有时是((void *)0)或类似的东西。您还使用NULL代替'\0'将字符串的结束字节设置为空字节 - 这也会引发编译器警告。这些都是嘈杂而不是非常严重,但你应该瞄准那些用最少的转换来静默编译的代码(也就是说,不要简单地在所有地方强制转换来关闭编译器警告)。

你写道:

    if(listpointer -> link != NULL){

忽略大括号的位置(受到合法辩论),你应该在if后面留一个空格,->周围不能有任何空格。关于空格的类似评论适用于while;在调用和定义中,在函数名和左括号之间不使用空格也是常规的。

这个警告很严重:

usart.c:297:5: warning: passing argument 1 of ‘RemoveItem’ discards ‘volatile’ qualifier from pointer target type [enabled by default]
usart.c:253:14: note: expected ‘struct listelement *’ but argument is of type ‘volatile struct listelement *’

基本上,当您拨打recordedWordsPointer时,会移除RemoveItem的易变性,这会使volatile的存在变得多余。如果是volatile,则必须确保使用它的所有地方都知道这一点。或者,更简单地说,删除volatile限定符。

每个AddItem()AddSyllable()似乎都存在大量代码重复。你的目标应该是消除每个功能的一半左右。


现在我必须使用我们如何真正使用这些功能,这样才能看出出了什么问题。这很难,尤其是因为AddItem()AddSyllable()函数的参数包括一个神秘的int16_t (*words)[Q]。如果你能展示一个简单的main()程序,它可以用适当的参数调用这些函数(它应该是初始化的数据结构,而不是从文件读取的值),这将有所帮助。

重构代码

减少代码量的一个关键重构是创建一个函数,使listelement给出名称,大小,单词数和单词。以下dupstr()功能与strdup()不同;它需要一个长度并复制一个可能更长的字符串的许多字符。

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

enum { Q = 16 };

typedef struct listelement
{
    char                *dataitem;
    struct listelement  *link;
    int16_t              wordSize;
    int16_t            (*libWord)[Q];
    struct listelement  *syllables;
} listelement;

static int AVR32_USART0 = 0;

static void cpu_irq_disable(void);
static void cpu_irq_enable(void);   
static void usart_write_line(int *ptr, char *msg);
extern void RemoveSyllable(listelement *listpointer);
extern listelement *RemoveItem(listelement *listpointer);
extern listelement *AddSyllable(listelement *listpointer, char *name, int16_t size, int16_t wordLength, int16_t (*words)[Q]);
extern listelement *AddItem(listelement *listpointer, char *name, int16_t size, int16_t wordLength, int16_t (*words)[Q]);

/* Duplicate string - or use POSIX strdup() */
static char *dupstr(const char *name, int16_t size)
{
    char *str = malloc(size+1);
    if (str != NULL)
    {
        memmove(str, name, size);
        str[size] = '\0';
    }
    return str;
}

static listelement *makeElement(const char *name, int16_t size, int16_t wordLength, int16_t (*words)[Q])
{
    listelement *listpointer = (listelement *)malloc(sizeof(listelement));
    // on fail end links becomes NULL already above
    if (listpointer != NULL)
    {
        listpointer->dataitem = dupstr(name, size);
        listpointer->libWord =  (int16_t(*)[Q])malloc(wordLength*Q*sizeof(int16_t));
        if (listpointer->dataitem == NULL || listpointer->libWord == 0)
        {
            free(listpointer->dataitem);
            free(listpointer->libWord);
            free(listpointer);
            listpointer = NULL;
        }
        else
        {
            listpointer->link = NULL;
            listpointer->wordSize = wordLength;
            listpointer->syllables = NULL;
            for (int16_t row=0; row < wordLength; row++)
            {
                for (int col=0; col < Q; col++)
                {
                    listpointer->libWord[row][col] = words[row][col];
                }
            }
        }
    }
    return listpointer;
}

static void reportError(void)
{
    usart_write_line(&AVR32_USART0,"\r\n--------------------------------------------\r\n");
    usart_write_line(&AVR32_USART0,"Ran out of Memory!  Word not created.\r\n");
    usart_write_line(&AVR32_USART0,"\r\n--------------------------------------------\r\n");
}

listelement *AddItem(listelement *listpointer, char *name, int16_t size, int16_t wordLength, int16_t (*words)[Q])
{
    listelement *lp = listpointer;
    char ErrorHandler = 0;
    if (listpointer != NULL)
    {
        while (listpointer->link != NULL)
            listpointer = listpointer->link;
        listpointer->link = makeElement(name, size, wordLength, words);
        if (listpointer->link != NULL)
        {
            listpointer = listpointer->link;
            ErrorHandler = 1;
        }
    }
    else
    {
        listpointer = makeElement(name, size, wordLength, words);
        if (listpointer != NULL)
            ErrorHandler = 1;
        lp = listpointer;
    }
    if (ErrorHandler == 0)
        reportError();
    return lp;
}

listelement *AddSyllable(listelement *listpointer, char *name, int16_t size, int16_t wordLength, int16_t (*words)[Q])
{
    listelement *lp = listpointer;
    char ErrorHandler = 0;
    if (listpointer != NULL)
    {
        while (listpointer->syllables != NULL)
            listpointer = listpointer->syllables;
        listpointer->syllables = makeElement(name, size, wordLength, words);
        if (listpointer->syllables != NULL)
            ErrorHandler = 1;
    }
    else 
    {
        listpointer = makeElement(name, size, wordLength, words);
        if (listpointer != NULL)
            ErrorHandler = 1;
        lp = listpointer;
    }
    if (ErrorHandler == 0)
        reportError();
    return lp;
}

listelement *RemoveItem(listelement *listpointer)
{
    cpu_irq_disable();
    listelement * tempp = listpointer;

    while (listpointer->syllables != NULL)
    {
        RemoveSyllable(listpointer->syllables);
    }
    if (listpointer != NULL)
    {
        tempp = listpointer->link;
        free (listpointer->dataitem);
        free (listpointer->libWord);
        free (listpointer);
    }
    cpu_irq_enable();   
    return tempp;
}

void RemoveSyllable(listelement *listpointer)
{
    while (listpointer->syllables != NULL)
    {
        RemoveSyllable(listpointer->syllables);
    }
    free(listpointer->dataitem);
    free(listpointer->libWord);
    free(listpointer);
    listpointer = NULL;
    return;
}

static void cpu_irq_disable(void) { AVR32_USART0 = 0; }
static void cpu_irq_enable(void)  { AVR32_USART0 = 1; }   
static void usart_write_line(int *ptr, char *msg)
{
    *ptr = !*ptr;
    fprintf(stderr, "%s", msg);
}

int main(void)
{
    listelement *recordedWordsPointer = 0;
    recordedWordsPointer = RemoveItem(recordedWordsPointer);
}

我没有证明那里的每一个变化都有声音,但我确信addSyllable()addItem()函数使用makeElement()函数更容易阅读整个堆做了大部分的重复工作。毫无疑问,还有改进的余地。代码需要一个真正运行函数的工作main()(并且上面的代码不符合条件)。

我对如何处理指向数组的指针有所保留,但是我没有把代码带到我可以有用地运行valgrind的机器上(遗憾的是Mac OS X 10.8.x不受{ {1}},但)。我没有证明这是错的;我怀疑它是错的。它将帮助我无法看到调用代码,并将变量的定义作为指向数组的指针传递。