Повреждение памяти при манипулировании длинной строкой

Я пишу программу для распечатки любого строкового ввода длиннее 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 ответ

Ваш 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 поэтому он может изменять указатель и размер в структуре, и вызывающие абоненты могут видеть изменения.

Другие вопросы по тегам