【问题标题】:Address 0x0 is not stack'd, malloc'd or (recently) free'd地址 0x0 没有被堆栈、malloc 或(最近)释放
【发布时间】:2012-04-12 21:21:03
【问题描述】:

我对 C 很陌生,似乎无法弄清楚以下代码有什么问题。

int main() {
    char filen[] = "file.txt";
    FILE *file = fopen ( filen, "r" );
    if ( file != NULL )
    {
        char line [ 128 ];
        while ( fgets ( line, sizeof line, file ) != NULL ) /* read a line */
        {
            int i;
            char *result;
            for(i=0; i< NUM;i++)
            {
                char *rep;
                rep = (char *) malloc (sizeof(mychars[i][0]));
                strcpy(rep, mychars[i][0]);
                char *with;
                with = (char *) malloc (sizeof(mychars[i][1]));
                strcpy(with, cgichars[i][1]);
                result = (char *) malloc (sizeof(char) * 128);
                result = str_replace(line, rep, with);
            }


            fputs(result, stdout);
        }
    }
    fclose ( file );


    return 0;
}

Valgrind 给我这个错误:

==4266== Invalid read of size 1
==4266==    at 0x4C286D2: __GI_strlen (mc_replace_strmem.c:284)
==4266==    by 0x5118A8D: fputs (iofputs.c:37)
==4266==    by 0x400A0F: main (repl.c:35)
==4266==  Address 0x0 is not stack'd, malloc'd or (recently) free'd

repl.c 对应于这段代码以 fputs 开头的行。

另外,mychars 是一个二维数组,如下所示:

char *mychars[NUM][2] = {
  "a", "97",
  "b", "98",
  ....

谁能告诉我如何解决这个问题?此外,任何关于我应该如何改进当前代码(尤其是使用 malloc)的指针都将不胜感激。

编辑: str_replace 代码

char *str_replace(char *str, char *orig, char *rep) {
  char buffer[4096];
  char *p;

  if(!(p = strstr(str, orig)))
    return NULL;

  strncpy(buffer, str, p-str);
  buffer[p-str] = '\0';
  sprintf(buffer+(p-str), "%s%s", rep, p+strlen(orig));

  return buffer;

}

EDIT 2 str_replace 和 main 的新代码

出于测试目的,我已将 str_replace 方法替换为此处的方法:

What is the function to replace string in C?

而我的主线略有改动:

int main() {
    static const char filen[] = "file.txt";
    FILE *file = fopen ( filen, "r" );
    if ( file != NULL )
    {
        char line [ 128 ];
        while ( fgets ( line, sizeof line, file ) != NULL ) /* read a line */
        {
            int i;
            char *result;
            for(i=0; i< NUM;i++)
            {
                char *rep;
                rep = (char *) malloc (sizeof(mychars[i][0]));
                strcpy(rep, mychars[i][0]);
                char *with;
                with = (char *) malloc (sizeof(mychars[i][1]));
                strcpy(with, mychars[i][1]);
                result = str_replace(line, rep, with);
            }


            fputs(result, stdout);
        }
    }
    fclose ( file );


    return 0;
}

但我还是得到了

==6730== Invalid read of size 1
==6730==    at 0x4C286D2: __GI_strlen (mc_replace_strmem.c:284)
==6730==    by 0x5118A8D: fputs (iofputs.c:37)
==6730==    by 0x400995: main (repl.c:29)
==6730==  Address 0x0 is not stack'd, malloc'd or (recently) free'd

也许最令人沮丧的部分是不知道这些无效读取错误是什么

编辑 3 我已经更新了 for 循环中心的代码:

        int i;
        char* result;
        result = &line[0];
        for(i=0; i< NUM_CGICHARS;i++)
        {
            char *rep;
            rep = (char *) malloc (sizeof(char));
            strcpy(rep, cgichars[i][1]);
            char *with;
            with = (char *) malloc (sizeof(char)*3);
            strcpy(with, cgichars[i][0]);
            result = str_replace(result, rep, with);
            fputs(result, stdout);
            free(rep);
            free(with);
        }

现在我开始得到输出了!然而,仅在两次迭代之后,我得到了一个分段错误,而 valgrind 给了我一大堆这样的:

==9130== Invalid read of size 1
==9130==    at 0x4C286D2: __GI_strlen (mc_replace_strmem.c:284)
==9130==    by 0x5118A8D: fputs (iofputs.c:37)
==9130==    by 0x4009DF: main (teststep1.c:27)
==9130==  Address 0x0 is not stack'd, malloc'd or (recently) free'd

【问题讨论】:

    标签: c valgrind


    【解决方案1】:

    这两行

                result = (char *) malloc (sizeof(char) * 128);
                result = str_replace(line, rep, with);
    

    您首先为result 分配空间,然后通过返回str_replace 来覆盖它,然后立即释放它。该函数可能返回0,因此您的fputs 失败。

    顺便说一句,不要返回 malloc,在 C 中这是多余的,可能会隐藏您忘记包含原型的事实。

    编辑:您的str_replace 函数的内存处理完全错误。永远不要返回指向局部变量的指针,离开函数后该空间无效。

    【讨论】:

    • Jens,谢谢,但我仍然不知道如何解决这个问题。上面 str_replace 的代码
    • @varatis,对于str_replace,请参阅我的编辑。对于您程序的逻辑,我很难理解您想要实现的目标。为什么要在循环内分配一些东西然后擦除,以及在哪里使用fputs 中最后一个分配的值?
    • 我正在尝试逐行读取文件,并且对于每一行,将该行的某些字符替换为 mychars 指定的字符串
    • Jens,我已将我的 str_replace 方法替换为在编辑链接中找到的方法,以便我可以正确调试我的 main() 函数。但是,我仍然遇到类似的错误。
    • @varatis,你应该明确地将你的问题减少到更小的问题上。暂时不要尝试在for 循环中和几行中进行多次替换,这太复杂了。只需在不使用forwhile 循环的情况下进行一次替换,然后尝试输出结果。实际上,替换已经是错误的术语,因为您将无法进行简单的字符替换,您的源字符串和目标字符串的长度似乎不同。
    【解决方案2】:

    如果NUM 为0,则result 未初始化,可能是0

    您没有检查对malloc() 的调用结果,因此失败可能意味着您正在尝试写入NULL 指针。

    mychars 在哪里声明?

    【讨论】:

    • 它们都在导入的“mychars.h”文件中声明。但我也注意到,除了包含 str_replace 外,这有效......我将继续添加该代码
    • malloc 返回NULL 现在非常罕见,尤其是对于实现内存过度使用的操作系统。
    • @James:查找“内存过度使用”和“oom 杀手”。在某些系统中,如果您向malloc 请求内存(超过可用内存),malloc 将返回一个有效指针(虚拟地址),并且在您实际写入每一页之前它不会引起问题。一旦您需要写入操作系统没有的内存页面,OOM Killer 将根据优先系统终止进程,以释放更多页面供您写入。不过,如果 OOM Killer 认为它“低优先级”,它也可以杀死你自己的进程。
    • Here's 更好的解释
    • 那篇文章并没有特别补充它,在我看来这是一个糟糕的主意。只需检查 NULL 并酌情处理。
    【解决方案3】:

    您没有显示mychars 是如何声明的,但是这一行:

    rep = (char *) malloc (sizeof(mychars[i][0]))
    

    看起来它可能只分配一个字节。此外,您分配了大量内存并且从不释放它。在这里:

    result = (char *) malloc (sizeof(char) * 128);
    result = str_replace(line, rep, with);
    

    您使用malloc 分配内存,然后通过在其顶部分配另一个函数的返回值来完全丢弃指向该内存的指针。

    【讨论】:

    • dreamlax,再次感谢您的帮助,但我该如何解决/更改此问题?
    猜你喜欢
    • 1970-01-01
    • 2023-02-23
    • 2020-04-07
    • 1970-01-01
    • 2017-09-13
    • 2018-10-12
    • 1970-01-01
    • 2019-08-21
    • 1970-01-01
    相关资源
    最近更新 更多