【问题标题】:Invalid free() when trying to reorder a linked list尝试重新排序链表时 free() 无效
【发布时间】:2019-09-03 21:06:16
【问题描述】:

我正在尝试通过交换指针来重新排序链表。它一直有效,直到我尝试释放内存然后它给了我一个错误。

我已经通过交换数据而不是指针来让它工作,但我很好奇为什么这会导致我的记忆出现问题。这是我的代码

typedef struct myArray {
    void *data;
    struct myArray *next;
} myArray_t;

int main(int argc, char **argv) {
    myArray *ma = paramsToList(argc, argv);
    revArray(&ma);
    printArray(ma);
    free(ma);
    return 0;
}

myArray_t *paramsToList(int ac, char *const *av) {
    myArray *ma = (myArray*)malloc((ac) * sizeof(myArray));
    int i = 0;
    while (i < ac) {
        ma[i].data = av[i];
        if (i < ac - 1) {
            ma[i].next = &ma[i + 1];
        } else {
            ma[i].next = NULL;
        }
        i++;
    }
    return ma;
}

void revArray(myArray_t **begin) {
    myArray *cur = begin[0];
    myArray *prev = NULL;
    myArray *next = cur->next;
    while (cur != NULL) {
        cur->next = prev;
        prev = cur;
        cur = next;
        if (cur != NULL) {
            next = cur->next;
        }
    }
    begin[0] = prev;
}

运行代码时出现此错误

valgrind ./a.out one two three

three
two
one
./a.out
==3662== Invalid free() / delete / delete[] / realloc()
==3662==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3662==    by 0x400604: main (example.c:20)
==3662==  Address 0x51fc070 is 48 bytes inside a block of size 64 alloc'd
==3662==    at 0x4C2AB80: malloc (in /usr/lib/valgrind    /vgpreload_memcheck-amd64-linux.so)
==3662==    by 0x40062B: paramsToList(int, char* const*) (example.c:26)
==3662==    by 0x4005DC: main (example.c:17)
==3662== 
==3662== 
==3662== HEAP SUMMARY:
==3662==     in use at exit: 64 bytes in 1 blocks
==3662==   total heap usage: 1 allocs, 1 frees, 64 bytes allocated
==3662== 
==3662== LEAK SUMMARY:
==3662==    definitely lost: 64 bytes in 1 blocks
==3662==    indirectly lost: 0 bytes in 0 blocks
==3662==      possibly lost: 0 bytes in 0 blocks
==3662==    still reachable: 0 bytes in 0 blocks
==3662==         suppressed: 0 bytes in 0 blocks
==3662== Rerun with --leak-check=full to see details of leaked memory
==3662== 
==3662== For counts of detected and suppressed errors, rerun with: -v
==3662== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

【问题讨论】:

  • for() 循环有什么问题? #style
  • for( i = 0; i &lt; ac; i++ ) { /* ... */ }?
  • for( ; cur != NULL; next = cur-&gt;next ) { /* ... */ }?

标签: c pointers struct malloc valgrind


【解决方案1】:

您只能将由malloc()/realloc()/calloc() 返回的指针传递给free(),并且您传递的节点是指向ma 的指针加上一些偏移量,恰好是&amp;ma[ac - 1]

您可以只更改节点的内容而不是节点本身,或者只是编写一个普通的链表,其中每个节点都分配有malloc()

【讨论】:

  • 问题出在begin[0] = prev;。由于begin&amp;ma,因此更改begin[0] 会更改ma。因此,当您free(ma) 时,您不会释放从malloc 获得的相同地址。
【解决方案2】:

您必须将malloc() 返回的原始指针传递给free()

由于revarray修改了地址接收到的指针,所以必须保存原来的指针,以便以后传递给free()

另请注意,revArray 可以通过删除测试以设置 next 来简化。

这是修改后的版本:

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

typedef struct myArray {
    void *data;
    struct myArray *next;
} myArray_t;

myArray_t *paramsToList(int ac, char *const *av) {
    myArray *ma = (myArray *)malloc(ac * sizeof(myArray));
    if (ma == NULL)
        return NULL;
    for (int i = 0; i < ac; i++) {
        ma[i].data = av[i];
        if (i < ac - 1) {
            ma[i].next = &ma[i + 1];
        } else {
            ma[i].next = NULL;
        }
    }
    return ma;
}

void revArray(myArray_t **begin) {
    myArray *cur = *begin;
    myArray *prev = NULL;
    myArray *next = cur->next;
    while (cur != NULL) {
        next = cur->next;
        cur->next = prev;
        prev = cur;
        cur = next;
    }
    *begin = prev;
}

int main(int argc, char **argv) {
    myArray *ma = paramsToList(argc, argv);
    myArray *orig_ma = ma;
    revArray(&ma);
    printArray(ma);
    free(orig_ma);
    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-06
    • 2021-02-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-07
    • 2013-02-01
    • 1970-01-01
    • 2019-05-26
    相关资源
    最近更新 更多