Я пытаюсь понять, где вещи хранятся в памяти (стек/куча, есть ли другие?) при запуске программы c. При компиляции выдается предупреждение: функция возвращает адрес локальной переменной:
char *giveString (void)
{
char string[] = "Test";
return string;
}
int main (void)
{
char *string = giveString ();
printf ("%s\n", string);
}
Запуск дает разные результаты, просто печатает тарабарщину. Из этого я понял, что массив символов, называемый строкой в функции giveString(), сохраняется в кадре стека функции giveString() во время ее работы. Но если я изменю тип строки в giveString() с массива char на указатель char:
char *string = "Test";
Я не получаю предупреждений, и программа выводит "Тест". Значит ли это, что строка символов "Test" теперь находится в куче? Он определенно больше не находится в кадре стека giveString(). Что именно происходит в каждом из этих двух случаев? И если эта строка символов расположена в куче, так что все части программы могут получить к ней доступ через указатель, будет ли она никогда не освобождена до завершения программы? Или освободилось бы место в памяти, если бы на него не было указателей, например, если бы я не вернул указатель на main? (Но это возможно только со сборщиком мусора, как в Java, верно?) Является ли это особым случаем выделения кучи, который применим только к указателям на постоянные строки символов (жестко запрограммированные строки)?
Ответ 1 · рейтинг 7 · Variable Length Coder
Вы, кажется, смущены тем, что делают следующие утверждения.
char string[] = "Test";
Этот код означает: создать в локальном кадре стека массив достаточного размера и скопировать в него содержимое константной строки "Test".
char *string = "Test";
Этот код означает: установите указатель так, чтобы он указывал на константную строку "Тест".
В обоих случаях "Тест" находится в сегменте const или cstring вашего двоичного файла, где существуют неизменяемые данные. Его нет ни в куче, ни в стеке. В первом случае вы создаете копию "Test", которую можете изменить, но эта копия исчезает после возврата вашей функции. В последнем случае вы просто указываете на него, поэтому вы можете использовать его, как только ваша функция вернется, но вы никогда не сможете его изменить.
Вы можете думать о фактической строке "Test" как о глобальной и всегда находящейся в памяти, но концепция выделения и освобождения обычно не применима к константным данным.
Ответ 2 · Chris Eberle
Нет. Строка "Test" все еще находится в стеке, она находится только в части data стека, которая в основном настраивается до запуска программы. Он есть, но вы можете думать об этом как о "глобальных" данных.
Следующее может немного прояснить ситуацию для вас:
char string[] = "Test"; // declare a local array, and copy "Test" into it
char* string = "Test"; // declare a local pointer and point it at the "Test"
// string in the data section of the stack
Ответ 3 · Heisenbug
Это потому, что во втором случае вы создаете постоянную строку:
char *string = "Test";
Значение, указанное строкой, является константой и никогда не может измениться, поэтому оно выделяется во время компиляции как статическая переменная (но это все еще стек, а не куча).