操作长字符串时内存损坏

时间:2019-02-23 01:08:26

标签: c memory-corruption

我正在编写一个程序以打印出任何大于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;
}

1 个答案:

答案 0 :(得分:2)

您的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的函数,以便它可以修改指针和结构的大小,并且调用者可以看到更改。