realloc():无效的下一个大小:后跟一个 32 位寄存器

realloc(): invalid next size: followed by a 32bit register

所以我一直在用 C 语言编写一个 mtf 编码器,但无论我做什么,我都 运行 遇到了 realloc() 错误。我已经检查过我的逻辑是否有错误(并且可能有),方法是使用打印语句查看我是否越界了我当前 malloc 的数组(添加一个超过我原始数组大小的字符串)这似乎不是问题所在。我使用过 GDB 和 Valgrind,当 Valgrind 遇到分段错误时,GDB 给了我一条神秘的消息。这是我第一次使用动态内存,我对问题出在哪里感到很困惑,下面是我的代码以及 GDB 错误:

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

int count = 0;


move_to_front(int index, char** words){
    int i;
    char *t = words[index];

    for(i = index; i>1; i--){
       words[i] = words[i-1];
    }

    words[1] = t;

}


char** reallocate_words(char** words, int* words_size_pointer){
   printf("We're entering here\n");
   printf("%d", *words_size_pointer);
   int temp = *words_size_pointer;
   char** tempor;
   temp = temp*2;
   printf("%d", temp);
   tempor = (char**) realloc(words, temp);
   int i = *words_size_pointer;
   for(i; i<temp; i++){
       tempor[i] = (char*) malloc(120);
    }
   words_size_pointer = &temp;
   return tempor;

 }

void encode_word(int* words_size_pointer, FILE *f, char* word, char** words){
    if(count == 0){
        words[1] = word;
        fputs(words[1], f);
        count++;
    }
    int i;
    for(i=0; i<=count; i++){
        if(strcmp(words[i], word) == 0){
            break;
        }
    }
    if(i>=(*words_size_pointer)){
        printf("%d\n", i);
        words = reallocate_words(words, words_size_pointer);
        words[count+1] = word;
        count++;
        fputc(count+128, f);
        fputs(words[count], f);
        move_to_front(count, words);
    }
    if(i>count){
        words[count+1] = word;
        count++;
        fputc(count+128, f);
        fputs(words[count], f);
        move_to_front(count, words);
    }
    else{
        fputc(i+128, f);
        move_to_front(i, words);
    }



}

void sep_words(char** words, char *line, int* words_size_pointer, FILE *f){
    char* x;
    int i = 0;
    x = strtok(line, " ");
    while(x != NULL){
        encode_word(words_size_pointer,f, x, words);
        x = strtok(NULL, " ");
    }   
}


void readline(FILE *f_two, FILE *f, char** words, int* words_size_pointer){
    char *line;
    size_t len = 0;
    ssize_t temp;
    int count;
    do{
    temp = getline(&line,&len,f);
    printf("%s", line);
    if(temp!= -1){
        sep_words(words, line, words_size_pointer, f_two);

    }
    }while(temp!=-1);

}


int main(int argc, char *argv[]){
    int x;
    int i;
    int j;
    x = strlen(argv[1]);
    char fi[x];
    char mtf[3] = "mtf";
    FILE *f;
    FILE *f_two;
    for(j = 0; j<(x-3); j++){
       fi[j] = argv[1][j];
    }
    strcat(fi, mtf);
    f = fopen(argv[1], "r");
    f_two = fopen(fi, "w");
    fputc(0xFA, f_two);
    fputc(0XCE, f_two);
    fputc(0XFA, f_two);
    fputc(0XDF, f_two);
    if(f == NULL){
        return 1;
    }

    char** words;
    words = (char **) malloc(20);
    for(i = 0; i<20; i++){
        words[i] = (char*) malloc(120);
    }
    int words_size = 20;
    int* words_size_pointer = &words_size;

    readline(f_two, f, words, words_size_pointer);
    return 0;
}

关于 GDB 错误:

    *** Error in `/file_loc/mtfcoding2': realloc(): invalid next size: 0x0000000000603490 ***
2040 \This is due to print statements within my function.
Program received signal SIGABRT, Aborted.
0x00007ffff7a4acc9 in __GI_raise (sig=sig@entry=6)
    at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56  ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.

感谢您的宝贵时间! :)

好吧,对于初学者来说,您的 move_to_front 正在掉线。这是一个非常严重的内存泄漏,并且考虑到 C 和内存泄漏的性质,可能是您的段错误的原因(目前)。你应该这样做

for(i = index; i > 1; i--){
    char* tmp = words[i];
    words[i] = words[i-1];
    words[i-1] = tmp;
}

否则,您所做的就是用 index 处的指针覆盖从 indexwords[2] 的指针。另外,您似乎喜欢从 1 而不是 0 开始 words 数组。那些差一的错误也会伤害到您。

此外(如我之前的评论所述),words_size_pointer = &temp; 不太正确。改为这样做 *words_size_pointer = temp;。第一种方式只是局部指针重新赋值,但您希望更改反映在调用者的作用域中,因此您必须取消引用指针并修改它。

mallocrealloc 需要 字节数 作为参数。但是,您正在编写如下代码:

char** words;
words = (char **) malloc(20);
for(i = 0; i<20; i++){
    words[i] = (char*) malloc(120);

您分配了 20 字节,但随后写入了 20 个指针(可能需要 80 字节)。要解决此问题,您需要计算存储 20 个指针需要多少字节。一个安全的方法是 use malloc as recommended by SO:

words = malloc(20 * sizeof *words);

您在 realloc 通话中遇到了同样的问题。


此行无效:words_size_pointer = &temp;。也许你的意思是 *words_size_pointer = temp; 。确保您清楚地了解这两行之间的区别。

注意。可能还有其他错误。

这似乎是由您在 readline 函数中调用 getline 引起的。

char *line;
size_t len = 0;
...
temp = getline(&line,&len,f);

getline 要求 lineNULL(在这种情况下 len 的值被忽略)或者 line 必须是返回的指针malloccallocrealloc。如果 line 不是 NULL,并且 len 不够大,则通过调用 realloc 调整 line 的大小。这是关键点:line 指向某个 malloc 未返回的随机地址,因此 getline 尝试使用 realloc 来增加缓冲区大小,因为 0 字节就是太小了。

你这里也有缓冲区溢出:

char mtf[3] = "mtf";
...
for(j = 0; j<(x-3); j++){
   fi[j] = argv[1][j];
}
strcat(fi, mtf);

因为您使 mtf 的大小只有 3 个字节,所以它后面可能会也可能不会紧跟一个空终止符。调用 strcat 时,如果 mtf 后面没有紧跟内存中的 0 字节,假设您不写太远远超出 fi 数组的末尾,导致程序崩溃并出现 SIGSEGV(段错误)。以下任何一项都可以更正它:

char mtf[4] = "mtf";
//OR
char mtf[] = "mtf";
//OR
const char *mtf = "mtf";

但是,因为 fi 仅由 x 个字节组成,所以您最终将使用 strcat 添加的空终止符写入 fi[x] .这是一个问题,因为 char fi[x]; 意味着您只有数组索引 0 到 x - 1 可用。使用 x = strlen(argv[1]) + 1.

修复此部分