Munmap_chunk():无效指针,已中止(核心已转储),realloc():下一个大小无效

Munmap_chunk(): invalid pointer, Aborted (core dumped), realloc(): invalid next size

我正在编写代码,用户可以在其中输入 Minesweeper 的字段,其中 '.' 是空字段,'*' 是炸弹。程序将从输入中读取字段的大小,然后 打印整个游戏字段 ,其中字段 '.' 被替换为该字段周围的炸弹数量,如果该字段没有任何它打印 '.',如果该字段是 '*',它只打印 '*'

我们不知道输入(游戏场)有多大输入以 EOF 结束。我的程序适用于 "normal"(小)输入,例如 10x10 游戏场、50x50 游戏场、20x4 游戏场等。我将输入输入 arr,然后将每个索引复制到 arr2,这样我就可以得到另一个输入 arr 并且我不会丢失之前的输入。 两个数组都是一维的。在 arr2 中,如果炸弹 (' * ') 在它周围,我将索引值从 '.' 更改为数字(即 2)。

输入示例:

.*.
*.*

输出示例:

2*2
*3*

但是,当我尝试输入具有 216 行和 10 列 (216x10) 的游戏字段时,会发生以下情况:

Valgrind 表示没有内存泄漏或低输入错误。

由于我是内存管理和指针的新手,我无法找出问题出在哪里。 如果您提出问题并尝试帮助我,我将不胜感激。

我在这里显示的代码应该是有问题的部分(并且是程序的开头)。其余代码应该没问题,并基于这部分工作。


    int main()
    {
      int err, size=200;
      char *arr=NULL;
      char *arr2=(char*)malloc(sizeof(char)*size);
      size_t bufsize=0;
      printf("Enter game field:\n");
      while(true)
      {
         for (int i=0;i<size;i++)
            {
                err=getline(&arr,&bufsize,stdin);
                if (i==(size-2))
                {
                    size *= 3;
                    arr2=(char*)realloc(arr2,sizeof(char)*size);
                }
                for (int j=0;j<(err-1);j++)
                {
                    arr2[l]=arr[j];
                    l++;
                }
                /*rest of the code*/
            }
      }

.
.
.

简答:

arr2 的分配对于大型板来说太小(总共 >200 字节),考虑在每次迭代时调整它的大小以处理未知大小。

  // existing line
  err=getline(&arr,&bufsize,stdin);
  if ( err > 0 ) {
      size += err ;
      arr2 = realloc(arr2, size) ;
      // Append arr to arr2.
  }

或类似。

长答案:

存在编译错误 - 代码引用变量 'l'(在 arr2[] = arr[j] 中),但没有声明它(或指定它的值)。假设这是在 main 中声明的(或静态的)并初始化为零。

在每次迭代中,代码将输入行 arr 的内容附加到 arr2。初始分配给 arr2 的只有 200 个字节。在大板 (216x10) 上,这将在迭代 20 中超出 arr2 的大小。

迭代 198 (i==size-2) 上的分配允许代码处理电路板总大小小于 200 字节(10x10,...)的小问题。

Valgrind:

在我的机器 (Mint 19) 上,valgrid 正确识别了 216x10 板的缓冲区溢出:

==61030== Memcheck, a memory error detector
==61030== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==61030== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==61030== Command: ./a.out
==61030== 
Enter game field:
==61030== Invalid write of size 1
==61030==    at 0x10882A: main (gg.c:25)
==61030==  Address 0x522d108 is 0 bytes after a block of size 200 alloc'd
==61030==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==61030==    by 0x10878C: main (gg.c:9)
==61030==