【问题标题】:strange free() invalid pointer C奇怪的 free() 无效指针 C
【发布时间】:2016-03-30 17:08:33
【问题描述】:

我修改了很多次的这段代码有问题(但总是出现错误): 似乎在释放“过滤器”的最后一个索引时出错

char** read_and_filter(int fd) {
  char buf[MAXLENGTH];
  char **bufs=NULL;
  char ch;
  int j = 0, len = 0, t = 0;
  while (!t && read(fd,&ch,1) == 1) {
    switch (ch) {
    case '\n':
      t = 1;
    case ' ':
      bufs = realloc(bufs, (j+1)*sizeof(char*));
      bufs[j++] = strndup(buf,len);
      memset(buf,0,len);
      len = 0;
      break;
    default:
      buf[len++] = ch;
    }
  }
  bufs[j] = 0;
  return bufs;
}

int main(int argc, char **argv) {
  char **filter;
  int i,fd = open("input.txt",O_RDONLY);
  filter = read_and_filter(fd);
  for(i = 0; filter[i]; i++) {
    printf("%s\n",filter[i]);
    free(filter[i]);
  }
  return 0;
}

这是输出:

0x1521030
HOME
0x1521050
2
0x1521070
A
0x1521010
8
0x15210c0
D
*** Error in `./test': free(): invalid pointer: 0x00000000015210c0 ***

我还尝试使用 valgrind 调试它(它说分配器尝试释放 9 个字节,而字符总和为 8,很奇怪,不是吗?)和 gdb 但没有任何效果。 input.txt的第一行是“HOME 2 A 8 D\n”

【问题讨论】:

  • 没有文档价值的变量名会让小猫哭泣。 j? t?好的,在花时间阅读代码时很容易弄清楚它们,但您可以通过合理的命名使其更容易。即使您不想让自己变得更容易,当您要求其他人无偿帮助您解决问题时,您也应该让他们尽可能简单地完成任务。除此之外,您的输出似乎与您提供的程序不匹配;在您的代码未打印的每个字符串之前,似乎都有指针值。
  • 这些语句在释放时产生了问题 - buf[len++] = ch;。当您更改指针指向的内容时。
  • @ameyCU 嗯,不,这不会以任何方式改变任何指针
  • 还有一个可能应该在case '\n' 中的break 语句。如果您打算让代码不间断地流过下一个,您真的想在此处添加注释以表明它。
  • 分配大小为 9,因为 C 字符串中嵌入了 NUL

标签: c pointers malloc free realloc


【解决方案1】:

这些行第一次执行时

bufs = realloc(bufs, (j+1)*sizeof(char*));
bufs[j++] = strndup(buf,len);

您获得了 1 个指针的内存(j 为 0)。这不会为您在函数末尾写的 NULL 留下空间

bufs[j] = 0;

所以你的写入超出了分配的内存,因此有未定义的行为。每次扩展缓冲区长度时也是如此。

【讨论】:

  • 如果我去掉 bufs[j] = 0 错误是:0x1a14030 HOME 0x1a14050 2 0x1a14070 A 0x1a14010 8 0x1a140c0 D 0x21 Segmentation Fault
  • 你必须比你多分配一个元素。 realloc(bufs, (j+2)*sizeof(char*))
  • 您还必须在循环释放其元素后free(filter)
  • 通常在有人使用 malloc 或 realloc 的情况下,他们会留出一点空间为空,我一直用它来打破 for 和 while 循环,但在这个示例代码中它不起作用
  • 如果这些答案之一解决了您的问题,请“接受”它。
【解决方案2】:

read_and_filter 末尾的 bufs[j] = 0; 写入未分配的内存。你从来没有realloc-ed 你的bufs 额外的0

【讨论】:

    【解决方案3】:

    内存泄漏发生在两个地方 - strdup 和 realloc

    一个答案是使用 malloc 为 main 中的缓冲区进行初始内存分配,然后将指向已分配内存的指针传递给函数。然后该函数可以重新分配缓冲区,并将数据复制到其中。

    从函数返回时,main 可以直接从缓冲区访问数据,因为它有一个指向它的有效指针,然后可以在关闭之前释放该内存。

    根据valgrind,以下没有失忆。

    void read_and_filter(int fd, char **bufs) {
      char buf[100];
      char ch;
      int j = 0, len = 0, t = 0;
      while (!t && read(fd,&ch,1) == 1) {
        switch (ch) {
        case '\n':
          t = 1;
        case ' ':
          *bufs = realloc(*bufs, (j + 2)*sizeof(char*));
          strncpy(bufs[j++], buf, len);
          memset(buf,0,len);
          len = 0;
          break;
        default:
          buf[len++] = ch;
        }
      }
      bufs[j] = 0;
      return;
    }
    
    int main(int argc, char **argv) {
      char *bptr = malloc(1);
      int fd = open("input.txt", O_RDONLY);
    
      read_and_filter(fd, &bptr);
    
      printf("%s\n", bptr);
      free(bptr);
      return 0;
    

    但是我不能确定这是否完全复制了 OP 的预期功能,但整体方法确实解决了内存问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-31
      • 2012-02-21
      • 1970-01-01
      • 2021-05-16
      • 1970-01-01
      • 2013-06-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多