【问题标题】:realloc: invalid next size and malloc: memory corruption (fast)realloc:下一个大小无效和 malloc:内存损坏(快速)
【发布时间】:2014-08-26 21:00:26
【问题描述】:

我正在从 K 和 R C 编程书籍中做一个有趣的练习。该程序用于从用户输入的一组行中找到最长的行,然后将其打印出来。

输入:

This is a test

This is another long test

this is another long testthis is another long test

观察:

前两个输入运行良好,但对于较大的字符串(第三个输入)失败

错误:

Error in `./longest': realloc(): invalid next size: 0x000000000246e010 ***
Error in `./longest': malloc(): memory corruption (fast): 0x000000000246e030 ***

我的努力:

自 2 天以来我一直在尝试调试这个(橡皮鸭调试),但逻辑似乎很好。 GDB 指向 _getline 函数中的 realloc 调用,并在顶部显示带有 glibc.so 内存分配调用的巨大回溯。

这是我写的(部分是直接从书中摘录的):-

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

int MAXLINE =  10;
int INCREMENT = 10;

char* line = NULL, *longest = NULL;

void _memcleanup(){
    free(line);
    free(longest);      
}

void copy(char longest[], char line[]){
    int i=0;
    char* temp = realloc(longest,(MAXLINE)*sizeof(char));
    if(temp == NULL){
        printf("%s","Unable to allocate memory");
        _memcleanup();
        exit(1);
    }
    longest = temp;

    while((longest[i] = line[i]) != '\0'){
        ++i;
    }    
}

int _getline(char s[]){
  int i,c;
  for(i=0; ((c=getchar())!=EOF && c!='\n'); i++){
    if(i == MAXLINE - 1){
      char* temp = realloc(s,(MAXLINE + INCREMENT)*sizeof(char));
      if(temp == NULL){
        printf("%s","Unable to allocate memory");
        _memcleanup();
        exit(1);
      }

      s= temp;
      MAXLINE += INCREMENT;
    }
    s[i] = c;
  }

  if(c == '\n'){
      s[i++] = c;
  }

  s[i]= '\0';

  return i;
} 

int main(){
  int max=0, len;

  line = malloc(MAXLINE*sizeof(char));
  longest = malloc(MAXLINE*sizeof(char));

  while((len = _getline(line)) > 0){
    printf("%d%d", len, MAXLINE);
    if(len > max){
      max = len;
      copy(longest, line);
    }
  }
  if(max>0){
    printf("%s",longest);
  }

  _memcleanup();
  return 0;
}

【问题讨论】:

  • 认为可能需要if(i == MAXLINE - 2){ in _getline()
  • i == MAXLINE - 2 时,不会发生 realloc。如果下一个getchar(),现在是i == MAXLINE - 1,是'\n',循环结束,s[MAXLINE - 1] = '\n';那么s[MAXLINE]= '\0';,就是UB。
  • realloc() invalid old size 的可能重复项
  • 附带说明,我花了大约 30 秒的时间认为 MAXLINE 是一个常数。最好不要命名常量或宏等变量。

标签: c realloc


【解决方案1】:

双指针本身并不能解决您的问题。您有两个主要问题。您可以通过将字符串作为字符串输入来查看它们,并且当您传递第 20 个字符时会注意到出现问题。 (例如01234567890123456789

您已在全局范围内声明了linelongest。因此,虽然您可以重写_getline (char **s),但您也可以简单地将_getline 末尾的line 更新为memcpy(包括string.h)。例如:

    memcpy (line, s, (size_t)i);

    return i;
}

这可以解决您的_getline 问题。问题二是相当直截了当的。您不是在 copy 中以空值终止 longest。 (您选择与全局变量同名的参数也会带来挑战)包括以下修复副本:

        ++i;
    }

    longest[i] = '\0';
}

如果您将这两种更改都结合起来,那么我相信您会发现您的日常工作。然后你可以重写_getline (char **s) 并传递&amp;line 作为另一个练习。例如,您可以将_getline 重写为:

int
_getline (char **s) {
    int i, c;
    for (i = 0; ((c = getchar ()) != EOF && c != '\n'); i++) {
        if (i == MAXLINE - 1) {
            char *temp = realloc (*s, (MAXLINE + INCREMENT) * sizeof (char));
            if (temp == NULL) {
                printf ("%s", "Unable to allocate memory");
                _memcleanup ();
                exit (1);
            }
            *s = temp;
            MAXLINE += INCREMENT;
        }
        (*s)[i] = c;
    }

    if (c == '\n') {
        (*s)[i++] = c;
    }

    (*s)[i] = '\0';

    return i;
}

然后将 main 中的调用修改为:

while ((len = _getline (&line)) > 0) {

【讨论】:

  • 感谢您的感谢。我知道你对这个很头疼,因为我也差点把头发拔了:)
【解决方案2】:

您正在重新分配复制的地址(因为参数)。
C中的参数每次都是原始值的副本;万一
一个指针,它将指向相同的位置,但地址本身被复制。

realloc 调整与地址关联的缓冲区大小,到目前为止一切正常。
但它可以重新定位整个事物并分配一个全新的地址,
并且这个新地址(如果发生)将在函数返回 main 后丢失。

使用双指针:
传递 char **s 而不是 char *s (==char s[]) 作为形式参数,
通过&amp;xyz 而不是xyz 作为实际值,并在函数内部,
使用*xyz**xyz(或(*xyz)[index])作为地址和值。

其他:
全局变量很难看(与参数命名相同时会令人困惑),
乘以 sizeof(char) 是无稽之谈,因为它每次都是 1,
大写的名称应该用于#define,而不是变量。

【讨论】:

  • 如何避免丑陋的全局变量?我的情况是我需要在同一组指针上调用多个函数。
  • 好吧,在 main 中创建变量并将其作为参数传递。如果您包含双指针内容并将 (poimter) 添加到 int 以获取 to 数字,则复制已经可以...
猜你喜欢
  • 1970-01-01
  • 2013-02-15
  • 1970-01-01
  • 1970-01-01
  • 2020-10-26
  • 2012-05-22
  • 1970-01-01
  • 2020-12-27
相关资源
最近更新 更多