【问题标题】:Error in ./thrash: free(): invalid pointer./thrash 中的错误:free():无效指针
【发布时间】:2018-09-17 15:16:43
【问题描述】:

我意识到这个问题已经被问过好几次了,但没有一个解决方案对我有任何帮助。我正在编写一个实验室程序,该程序在 C 中分配大量内存,特别是一个 char 指针数组,每个指针都分配了 4096 字节的内存页面大小。

char** pgs =(char**) malloc(sizeof(char *) * pages);
if(pgs == NULL){
    printf("Failed to allocate memory");
    exit(0);
}
int i;
for(i = 0; i < pages; i++){
    pgs[i] = malloc(4096);
    /*if(pgs[i] == NULL){
    printf("Failed to allocate memory");
    exit(0);
    }*/
*pgs[i] = "\0";
/*if(pgs[i] == NULL){
    printf("Failed to allocate memory");
    exit(0);
}*/
}

在程序的中间,这个数组的元素被随机访问和修改,以引起抖动(作为实验室的一部分):

while(time(NULL) - startTime < seconds){
    long rando = rand() % pages;
    if(modify > 0){
        *pgs[rando]++;
    }
    else{
        long temp = *pgs[rando];
    }

在程序结束时,我尝试释放此内存:

for(i = 0; i < pages; i++){
    free(pgs[i]);
}


free(pgs);

然而,我得到了可怕的“无效指针”错误。如果有人对如何解决此问题有任何建议或知识,请分享。

【问题讨论】:

  • 请准确缩进代码。另外,不要包含注释掉的代码——并且不要包含两个被注释掉的代码副本。这将有助于更容易理解您的要求。
  • 您没有收到*pgs[i] = "\0"; 的编译器警告吗?不要发布编译器抱怨的代码,除非您的问题是“为什么编译器抱怨此代码?”
  • 您的问题是您的修改代码*pgs[rando]++; 等效于*(pgd[rando]++),而不是您想象的(*pgs[rando])++;。您正在增加指针,而不是指向的数据。因此,当您释放它时,分配的不是指针,因此您会收到消息。
  • 另外,通常使用exit(1);exit(EXIT_FAILURE); 表示程序失败; exit(0);exit(EXIT_SUCESS); 表示程序成功。 —— 请注意,您的修改代码仅修改了每页分配的 4096 字节中的一个字节,因此它并不会真正地影响内存管理(至少,大多数缓存一次缓存少于 4096 字节)。
  • *pgs[i] = "\0";应该是*pgs[i] = '\0'; 注意'x'"x"不同

标签: c pointers memory malloc free


【解决方案1】:

您展示的程序片段显示出许多问题,其中一些已在 cmets 中发现:

  • 程序应该报告标准错误,而不是标准输出。
  • 如果程序失败,程序应该以非零状态退出。
  • 程序应该在没有警告的情况下编译。
  • 一般消息和特别是错误消息应以换行符结尾。
  • 程序只尝试修改每一页的一个字节。

但是,主要问题是问题中的代码使用了*pgs[rando]++,它旨在修改分配的内存。这等价于*(pgs[rando]++),它递增指针,然后读取值并丢弃它——而不是等价于(*pgs[rando])++,它会修改字节pgs[rando][0]。问题中的代码应生成有关value computed is not used 的警告(如果您确保编译时将所有警告都视为错误,则会生成错误)。因为您的代码正在递增指针,所以使用 free() 返回到内存分配系统的值通常与内存分配系统返回给您的值不同,因此您确实将无效指针传递给 @ 987654327@.

此代码避免了上述问题。它执行固定数量的迭代并且不使用time()。它打印sum,以便优化器无法优化对内存的读取访问。

/* SO 4971-2352 */

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

enum { PAGESIZE = 4096 };

int main(void)
{
    int pages = PAGESIZE;
    char **pgs = (char **)malloc(sizeof(char *) * pages);
    if (pgs == NULL)
    {
        fprintf(stderr, "Failed to allocate memory\n");
        exit(EXIT_FAILURE);
    }
    for (int i = 0; i < pages; i++)
    {
        pgs[i] = malloc(PAGESIZE);
        if (pgs[i] == NULL)
        {
            fprintf(stderr, "Failed to allocate memory\n");
            exit(EXIT_FAILURE);
        }
        memset(pgs[i], '\0', PAGESIZE);     // Or use calloc()!
    }

    size_t sum = 0;
    for (int i = 0; i < PAGESIZE * PAGESIZE; i++)
    {
        int pagenum = rand() % pages;
        int offset = rand() % PAGESIZE;
        int modify = i & 2;
        if (modify != 0)
        {
            pgs[pagenum][offset]++;
        }
        else
        {
            sum += pgs[pagenum][offset];
        }
    }

    printf("Sum: 0x%.8zX\n", sum);

    for (int i = 0; i < pages; i++)
        free(pgs[i]);
    free(pgs);

    return 0;
}

我将该代码称为 thrash31.c 并将其编译为 thrash31 使用:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror thrash31.c -o thrash31
$

使用计时程序运行时,我得到了输出:

$ timecmd -u -- thrash31
2018-04-07 15:48:58.546809 [PID 9178] thrash31
Sum: 0x001FE976
2018-04-07 15:48:59.355508 [PID 9178; status 0x0000]  -  0.808699s
$

因此,运行大约需要 0.8 秒。每次生成的总和都是相同的,因为代码没有为随机数生成器提供种子。

【讨论】:

  • 本来想早点回复的,谢谢你的帮助。此代码有效并解决了我的问题。
猜你喜欢
  • 1970-01-01
  • 2018-06-18
  • 1970-01-01
  • 1970-01-01
  • 2018-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-21
相关资源
最近更新 更多