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