首页 > 解决方案 > 操作长字符串时内存损坏

问题描述

我正在编写一个程序来打印任何长于 3 的行输入。

它适用于一些相当长的输入行,但是对于太长的字符串,我收到了内存损坏的错误消息

*** Error in `./print-80': malloc(): memory corruption (fast): 0x00000000022ff030 ***

我不知道错误来自哪里。谁能解释我为什么会出现错误以及如何解决它?下面是程序

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

#define LIMIT 3
#define LEAST_LENGTH 3

//function prototype
void copy(char* from, char* to);
int getline(char* s, int capacity);
int increase_capacity(char* s, int capacity);

int main(void) 
{
    int length, i;
    char* line = calloc(LIMIT, sizeof(char));

    while ((length = getline(line, LIMIT)) > 0)
    {
        if (length > LEAST_LENGTH)
            printf("Output: %s\n", line);

        //reset the line
        for (i = 0; i < length; i++)
            *(line + i) = 0;
    }

    free(line);
    return 0;
}

int getline(char* line, int capacity) 
{
    int c, length;

    length = 0;

    while ((c = getchar()) != EOF && c != '\n')
    {
        if (length > (capacity - 1))
        {
            capacity = increase_capacity(line, capacity);
            printf("Address of line after increasing cap: %p\n", line);
        }

        line[length++] = c;
    }

    if (c == '\n')
        line[length++] = '\0';

    return length;
}

int increase_capacity(char* s, int capacity) 
{
    int i;
    capacity *= 2;
    char *new_s = calloc(capacity, sizeof(char));

    copy(s, new_s);
    s = new_s;

    free(new_s);
    return capacity;
}

void copy(char* from, char* to) 
{
    int i = 0;
    while ((to[i] = from[i]) != '\0')
        ++i;
}

标签: cmemory-corruption

解决方案


您的increase_capacity函数可以更改存储数据的地址。但它不会将此信息返回给它的调用者。所以getline将写入旧的缓冲区地址。同样,main没有办法获得新地址,所以它会访问旧地址和free一个可能已经被释放的块。

此外,您的increase_capacity函数分配内存来保存数据,然后释放该内存。这样就没有地方保存数据了!

int increase_capacity(char* s, int capacity) 
 {
    int i;
    capacity *= 2;
    char *new_s = calloc(capacity, sizeof(char)); // allocate a larger block

    copy(s, new_s); // copy the data into the larger block
    s = new_s; // stash a pointer to the larger block in a local

    free(new_s); // free the block?!
    return capacity;
 }

所以我们分配一个新块,将数据复制到其中,然后释放它。这是没有意义的,我们需要保留更大的块,因为这是增加容量的功能的全部意义。我们也不返回新块的地址,所以即使我们没有释放它,也没有其他代码可以访问它,我们只会泄漏它。双重哎呀。

我建议您创建一个struct同时保存指向块的指针及其大小的。将指向它的指针传递struct给类似的函数,increase_capacity以便它可以修改结构中的指针和大小,调用者可以看到更改。


推荐阅读