Динамическое перераспределение памяти с использованием realloc - PullRequest
2 голосов
/ 28 октября 2009

Я изучаю C ++. Я пытаюсь изучить это динамическое распределение памяти. В приведенном ниже коде я пытаюсь выделить память, используя malloc и realloc.

int main (void)  {
  char *g = (char*) malloc (sizeof(char) * 2);
  g = "ab";
  g = (char*) realloc (g, sizeof(char) * 200);
  strcpy (g, "cdefg");
  cout << g << endl;
  return 0;
}

Я получаю ошибка сегментации ошибка при выполнении этого кода.

Я видел другие потоки SO, рекомендующие использовать vector или new вместо использования вышеупомянутого подхода. Так как я пытаюсь освоить этот подход, поэтому эти ответы не относятся к моему вопросу.

Я столкнулся со сценарием, в котором этот подход будет хорошо приспособлен, например, если я читаю необработанный текстовый файл, используя функцию ifstream.read, и читаю, скажем, 1024 байта. Теперь, если я хочу убедиться, что я не читаю слово, которое разбито из-за размера 1024 байта, я должен читать дальше с этой позиции, используя ifstream.get, чтобы достичь, пока не будет найден пробел. В этом случае мне нужно настроить буфер (который составляет 1024) немного больше. Я намерен использовать realloc здесь, чтобы выделить ему больше памяти.

Пожалуйста, не стесняйтесь поправлять меня, если я где-то ошибаюсь.

Ответы [ 5 ]

9 голосов
/ 28 октября 2009

В

g = "ab";

вы указываете g на чанк, расположенный в статическом хранилище, а не в куче, затем в

g = (char*) realloc (g, sizeof(char) * 200); 

вы пытаетесь позвонить realloc() с этим адресом, принадлежащим за пределами кучи. Это неопределенное поведение и вылетает ваша программа. Вы можете звонить realloc() только с адресами, возвращенными malloc() или realloc() (или нулевым указателем).

Проблема в том, что вы имели в виду это:

strcpy( g, "ab" ); 

но по ошибке написал это:

g = "ab";

Первый будет работать нормально - g изначально настроен на адрес, возвращаемый malloc().

Есть еще одна проблема - вы изначально выделяете слишком мало памяти. Вы должны выделить дополнительный байт для нулевого терминатора.

7 голосов
/ 28 октября 2009

Есть много проблем с вашим кодом. Прежде всего, вы не должны использовать malloc и друзей, если вы программируете на C ++.

char *g = (char*) malloc (sizeof(char) * 2);
g = "ab";

по электронной почте Ой. Вы только что потеряли 2 байта памяти, возвращенной вызовом malloc, потому что теперь g указывает на возможное место только для чтения, где хранится "ab".

g = (char*) realloc (g, sizeof(char) * 200);

realloc можно вызвать только по указателю, возвращенному более ранним malloc.

Даже если вы передали действительный указатель на realloc, realloc может вернуть NULL, если перераспределение завершится неудачно. В этом случае ранее выделенная память остается выделенной, но вы перезаписываете единственную переменную, указывающую на эту память, что делает невозможным освобождение более раннего выделения. См. Имея динамическое выделение массива, могу ли я изменить его размер? в списке часто задаваемых вопросов C.

Также обратите внимание, что для "ab" требуется три байта памяти, а не два. Наконец, sizeof(char) всегда и везде 1, поэтому нет необходимости использовать sizeof(char) в ваших malloc вызовах.

Правильная C версия вашей программы будет выглядеть так:

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

int main (void)  {
    char *tmp;
    char *g = malloc(3);
    if ( !g ) {
        return EXIT_FAILURE;
    }

    strcpy(g, "ab");

    tmp = realloc (g, 200);
    if ( !tmp ) {
        return EXIT_FAILURE;
    }
    g = tmp;

    strcpy (g, "cdefg");
    puts(g);
    return 0;
}

В версии C ++ вы должны использовать string, а не планировать массивы символов старого стиля C.

См. мой ответ на другой вопрос для примера того, как перераспределить буфер для чтения полных строк для второй части вашего вопроса.

Тем не менее, обратите внимание, что код также C , и я уверен, что есть лучшие способы делать то, что вы хотите в C ++. Я просто недостаточно знаю стандартную библиотеку C ++, чтобы дать вам правильное решение в C ++.

3 голосов
/ 28 октября 2009

Проблема в том, что строка:

g = "ab";

устанавливает указатель g на другое местоположение. Он не копирует содержимое. Вы теряете исходное местоположение, и когда вы используете g в realloc, вы будете realloc неправильно указывать.

Заменить строку на:

strcpy(g, "ab");

Конечно, вам понадобится три байта для хранения строки и завершающий символ '\0'.

Тем не менее, malloc и realloc - это вещи в стиле C. Если вы используете C ++, вы должны попробовать new и delete и, вероятно, использовать тип string для хранения строк.

2 голосов
/ 28 октября 2009

Вам нужно увеличить исходный malloc до 3, чтобы включить нулевой терминатор, и использовать strcpy для установки содержимого в "ab"

char *g = (char*) malloc (sizeof(char) * 3);
strcpy(g , "ab");
0 голосов
/ 28 октября 2009

По второй части вашего вопроса:

Рассмотрите возможность использования std::vector.

std::vector<char> g;
g.resize(1024);
// fill up g
// decide you need another hundred bytes at the end of g
g.resize(1124);
// memory will automatically be released when g goes out of scope

Обратите внимание, что для передачи указателя на начало буфера теперь вам нужно будет сказать &g[0] вместо простого g.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...