Динамическое распределение памяти - PullRequest
1 голос
/ 20 июня 2011

У меня небольшая путаница в концепции динамического распределения памяти. Если мы объявляем указатель, скажем, указатель на символ, нам нужно выделить достаточное пространство памяти.

char* str = (char*)malloc(20*sizeof(char));
str = "This is a string";

Но это тоже будет работать.

char* str = "This is a string";

Так в каком случае мы должны выделить пространство памяти?

Ответы [ 7 ]

7 голосов
/ 20 июня 2011

В первом примере у вас утечка памяти

char* str = (char*)malloc(20*sizeof(char)); 
str = "This is a string"; // memory leak

Выделенный адрес будет заменен новым. Новый адрес - это адрес для «Это строка».

И вам следует сменить второй образец.

const char* str = "This is a string";  

Из-за «Это строка» защищена от записи область.

4 голосов
/ 20 июня 2011

Предположительно фрагмент кода C ++ 98

char* str = (char*)malloc(20*sizeof(char));
str = "This is a string";

выполняет следующее: (1) выделяет 20 байт, сохраняя указатель на этот блок памяти в str, и (2) сохраняет указатель на буквенную строку в str. Теперь у вас нет возможности сослаться на ранее выделенный блок, и вы не можете его освободить. У тебя утечка памяти.

Обратите внимание, что, поскольку str был объявлен как char*, компилятор практически не может определить, пытаетесь ли вы использовать его для изменения литерала. К счастью, в C ++ 0x не будет компилироваться . Мне действительно нравится это изменение правила!

Фрагмент кода

char* str = "This is a string";

хранит указатель на строковый литерал в переменной char* с именем str, как в первом примере, и так же, как в этом примере, он не будет компилироваться с компилятором C ++ 0x.

Вместо этой глупости используйте, например, std::string из стандартной библиотеки и распространяйте const свободно по всему коду.

Приветствия и hth.,

2 голосов
/ 20 июня 2011

Присвоение переменной char* указывает на что-то еще, так зачем вы выделяли память в первую очередь, если сразу забыли об этом?Это утечка памяти.Вы, вероятно, имели в виду это:

char* str = (char*)malloc(20*sizeof(char));
strcpy(str, "This is a string");
// ...
free(str);

Это скопирует вторую строку в первую.Поскольку это тег C ++, вы должны использовать std::string:

#include <string>

std::string str = "This is a string";

. Не требуется ручное выделение и освобождение памяти, а присвоение делает то, что вы думаете.

2 голосов
/ 20 июня 2011

В первом примере вы динамически выделяете память из кучи. Это может быть изменено, и это должно быть освобождено. Во втором примере компилятору статически выделяется память, и она не может быть изменена и не должна быть освобождена. Вы должны использовать const char*, а не char*, чтобы строковые литералы отражали это и обеспечивали безопасное использование.

1 голос
/ 20 июня 2011

Строковые литералы являются особым случаем в языке.Давайте посмотрим на ваш код поближе, чтобы лучше это понять:

Сначала вы выделяете буфер в памяти и присваиваете адрес этой памяти str:

char* str = (char*)malloc(20*sizeof(char));

Затем выприсвойте строковый литерал str.Это перезапишет то, что str удерживалось ранее, поэтому вы потеряете свой динамически выделенный буфер, что случайно приведет к утечке памяти.Если вы хотите изменить выделенный буфер, вам нужно в какой-то момент разыменовать str, как в str[0] = 'A'; str[1] = '\0';.

str = "This is a string";

Итак, каково значение str сейчас?Компилятор помещает все строковые литералы в статическую память, поэтому время жизни каждого строкового литерала в программе равно времени жизни всей программы.Это утверждение скомпилировано в простое присваивание, подобное str = (char*)0x1234, где 0x1234 должен быть адресом, по которому компилятор поместил строковый литерал.

Это объясняет, почему это работает хорошо:

char* str = "This is a string";

Обратите также внимание, что статическая память не должна изменяться во время выполнения, поэтому вы должны использовать const char* для этого назначения.

Так что в этом случае мы должны выделить памятьпробел?

Во многих случаях, например, когда вам нужно изменить буфер.Другими словами;когда вам нужно указать что-то, что не может быть статической строковой константой.

1 голос
/ 20 июня 2011

Я хочу добавить к Ответ Алексея Малистова , добавив, что вы можете избежать утечки памяти в своем первом примере, скопировав «Это строка» в str, как в следующем коде:

char* str = (char*)malloc(20*sizeof(char));
strcpy(str, "This is a string");

Пожалуйста, обратите внимание, что может Я не имею в виду, что у вас есть до. Это просто добавление к ответу, чтобы добавить значение этой теме.

1 голос
/ 20 июня 2011

В первом примере вы просто делаете что-то не так.Вы выделяете динамическую память в куче и позволяете str указывать на нее.Затем вы просто позволяете str указывать на строковый литерал и выделенная память просачивается (вы не копируете строку в выделенную память, вы просто меняете адрес, на который указывает str, вам придется использовать strcpy в первом примере).

...