realloc:下一个大小和malloc无效:内存损坏(快)

时间:2014-07-06 04:10:41

标签: c realloc

我正在练习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;
}

2 个答案:

答案 0 :(得分:5)

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

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

使用双指针:
传递char **s代替char *s(== char s[])作为形式参数,
&xyz整数xyz作为实际值传递,并在函数内传递 使用*xyz**xyz(或(*xyz)[index])获取地址和值。

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

答案 1 :(得分:3)

单独使用双指针,不是解决问题的方法。你有2个主要问题。您可以通过输入字符串作为字符串来查看它们,并且会在您传递第20个字符时发现问题。 (例如01234567890123456789

您已全局声明linelongest。因此,虽然您可以重写_getline (char **s),但您也可以使用line(包括_getline)在memcpy末尾更新string.h。例如:

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

    return i;
}

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

        ++i;
    }

    longest[i] = '\0';
}

如果你同时包含这两项修改,那么我相信你会发现你的日常工作。然后,您可以重新_getline (char **s)并传递&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;
}

然后将您的通话修改为:

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