char* Распределение пространства

Насколько я понимаю, в C и C++ создание массива символов путем вызова:

char *s = "hello";

фактически создает два объекта: массив символов только для чтения, который создается в статическом пространстве, что означает, что он существует в течение всего времени выполнения программы, и указатель на эту память. Указатель является локальной переменной для своей области, а затем умирает.

Мой вопрос: что происходит с массивом, когда указатель умирает? Если я выполняю приведенный выше код внутри функции, означает ли это, что у меня есть утечка памяти после выхода из функции?


person yelsayed    schedule 09.08.2013    source источник
comment
то, что вы называете статическим пространством, с точки зрения исполняемого файла является сегментом данных (или родат). Это фактически глобальная переменная, просто вы не делаете ее (глобально) видимой/вы не даете ей (глобальное) имя.   -  person FrankH.    schedule 09.08.2013
comment
Строка не обязательно доступна только для чтения. Это может быть, и в средах, где это возможно, это, вероятно, так. См. stackoverflow.com/questions/1704407/   -  person jarmod    schedule 09.08.2013
comment
Просто чтобы уточнить здесь, приветствие создается, когда программа компонуется. Раздел кода, содержащий присваивание, никогда не нужно вызывать, но строка будет доступна.   -  person user888379    schedule 09.08.2013


Ответы (6)


он живет на протяжении всей программы

Именно, формально он имеет длительность хранения static.

что происходит с массивом, когда указатель умирает?

Ничего.

Если я выполняю приведенный выше код внутри функции, означает ли это, что у меня есть утечка памяти после выхода из функции?

Нет, из-за (1). (Массив «освобождается» только при выходе из программы.)

person Community    schedule 09.08.2013
comment
Что еще более важно, массив создается только один раз. - person Luaan; 17.06.2015

Нет, утечки нет.

Буквенная строка хранится в разделе данных программы, который обычно загружается на страницу памяти, доступную только для чтения. Все эквивалентные строковые литералы обычно указывают на одно и то же место в памяти — это своего рода синглтон.

char const *a = "hello";
char const *b = "hello";

printf("%p %p\n", a, b);

Это должно отображать одинаковые значения для двух указателей, и последовательные вызовы одной и той же функции также должны печатать одни и те же значения.

(Обратите внимание, что вы должны объявить такие переменные как char const * -- указатель на постоянный символ -- поскольку данные являются общими. Изменение строкового литерала с помощью указателя является поведением undefined. В лучшем случае вы разрушите свою программу, если страница памяти доступна только для чтения. , и в худшем случае вы измените значение каждого вхождения этого строкового литерала во всей программе.)

person cdhowie    schedule 09.08.2013
comment
Буквенная строка хранится в разделе данных программы — скажем, на x86 с использованием компилятора, который создает исполняемый файл ELF. Это не универсально :) Терминология такова, что он имеет статическую продолжительность хранения. - person ; 09.08.2013
comment
Далеко не всегда одинаковые строковые литералы используют одну и ту же память. По крайней мере один компилятор, который я использовал, имеет возможность сделать строковые литералы доступными для записи (как они были изначально) и гарантирует, что каждый литерал будет занимать разную память (так что модификация одного не изменяет другой). - person James Kanze; 09.08.2013

const char* s = "Привет"; является частью кода (программы) - следовательно, константа никогда не изменяется (если только у вас нет какого-то неприятного механизма, изменяющего код во время выполнения)

person Community    schedule 09.08.2013

Мой вопрос: что происходит с массивом, когда указатель умирает? Если я выполняю приведенный выше код внутри функции, означает ли это, что у меня есть утечка памяти после выхода из функции?

Нет, не будет утечки памяти, и с массивом ничего не произойдет, когда указатель умрет.

Утечка памяти возможна только при динамическом распределении через malloc(). Когда ты что-то malloc(), ты должен free() сделать это позже. Если этого не сделать, произойдет утечка памяти. В вашем случае это «статическое выделение»: выделение и освобождение этого пространства памяти будут освобождены автоматически, и вам не нужно с этим справляться.

person nouney    schedule 09.08.2013

означает ли это, что у меня есть утечка памяти после выхода из функции?

Нет, утечки памяти нет, строковые литералы имеют статическую длительность и будут освобождены, когда программа завершится. Цитата из проекта стандарта C++ раздел 2.14.5 String literals подраздел 8:

Обычные строковые литералы и строковые литералы UTF-8 также называются узкими строковыми литералами. Узкий строковый литерал имеет тип «массив из n const char», где n — размер строки, как определено ниже, и имеет статическое время хранения.

В разделе 3.7.1 Static storage duration говорится:

[...] Хранилище для этих сущностей должно длиться в течение всего срока действия программы

Обратите внимание на C++, эта строка:

char *s = "hello";

использует устаревшее преобразование, см. предупреждение C++: устаревшее преобразование из строковой константы в 'char*' [-Wwrite-strings] для получения дополнительной информации. Детали.

Правильный путь будет следующим:

const char *s = "hello";
person Shafik Yaghmour    schedule 09.08.2013

вам нужно только освободить, если вы используете malloc или новый

РЕДАКТИРОВАТЬ:

char* строка = "строка"; выделение памяти является статическим и не является хорошей практикой (если это будет константа, объявление должно быть const char *), потому что это находится в стеке, когда функция завершается, она должна быть уничтожена вместе с остальными локальные переменные и аргументы. вам нужно использовать определенные malloc/free и new/delete, когда вы выделяете память для своей переменной, например: char *string = new char[64]; --> удалить строку; char *string = malloc(sizeof(char) * 64); --> бесплатно(строка); // это не лучшая практика, если вам не нужно использовать C

person Mr.Monshaw    schedule 09.08.2013
comment
Это не правильно. Нужно использовать delete для каждого объекта newed. Также без объяснения того, почему это так, это очень плохой ответ. - person stefan; 09.08.2013