Если ссылаться на постоянные строки символов с помощью указателей, постоянно ли занята память?

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


person spectra    schedule 22.09.2011    source источник


Ответы (3)


Вы, кажется, смущены тем, что делают следующие утверждения.

char string[] = "Test";

Этот код означает: создать в локальном кадре стека массив достаточного размера и скопировать в него содержимое константной строки "Test".

char *string = "Test";

Этот код означает: установите указатель так, чтобы он указывал на константную строку «Тест».

В обоих случаях «Тест» находится в сегменте const или cstring вашего двоичного файла, где существуют неизменяемые данные. Его нет ни в куче, ни в стеке. В первом случае вы создаете копию «Test», которую можете изменить, но эта копия исчезает после возврата вашей функции. В последнем случае вы просто указываете на него, поэтому вы можете использовать его, как только ваша функция вернется, но вы никогда не сможете его изменить.

Вы можете думать о фактической строке «Test» как о глобальной и всегда находящейся в памяти, но концепция выделения и освобождения обычно не применима к константным данным.

person Variable Length Coder    schedule 23.09.2011

Нет. Строка "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
person Chris Eberle    schedule 22.09.2011
comment
Константная строка не помещалась бы в стек — большинство компиляторов помещали бы ее в секцию кода только для чтения, хотя в прошлом многие компиляторы помещали ее в секцию инициализированных данных. И что такое раздел данных стека? - person Dipstick; 23.09.2011

Это потому, что во втором случае вы создаете постоянную строку:

char *string = "Test";

Значение, указанное строкой, является константой и никогда не может измениться, поэтому оно выделяется во время компиляции как статическая переменная (но это все еще стек, а не куча).

person Heisenbug    schedule 22.09.2011