повреждение памяти при манипулировании длинной строкой - PullRequest
0 голосов
/ 23 февраля 2019

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

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

...