Где в памяти мои переменные, хранящиеся в C?
Учитывая, что память разделена на четыре сегмента: данные, куча, стек и код, где находятся глобальные переменные, статические переменные, типы константных данных, локальные переменные (определенные и объявленные в функциях), переменные (в основной функции), указатели, а динамически выделенное пространство (используя malloc и calloc) хранится в памяти?
Я думаю, что они будут распределены следующим образом:
- Глобальные переменные ---→ данные
- Статические переменные ---→ данные
- Постоянные типы данных -→ код
- Локальные переменные (объявленные и определенные в функциях) ----→ stack
- Переменные, объявленные и определенные в основной функции -→ heap
- Указатели (например,
char *arr
, int *arr
) ---→ heap - Динамически распределяемое пространство (используя malloc и calloc) ----→ стек
Я имею в виду эти переменные только с точки зрения Си.
Пожалуйста, поправьте меня, если я ошибаюсь, поскольку я новичок в C.
Ответы
Ответ 1
Вы получили некоторые из этих прав, но тот, кто написал вопросы, обманул вас хотя бы на один вопрос:
- глобальные переменные ------- > данные (правильные)
- статические переменные ------- > данные (правильные)
- постоянные типы данных ----- > код и/или данные. Рассмотрим строковые литералы для ситуации, когда сама константа будет храниться в сегменте данных, а ссылки на нее будут встроены в код
- локальные переменные (объявленные и определенные в функциях) -------- > stack (correct)
- переменные, объявленные и определенные в функции
main
----- > куча также стека (учитель пытался обмануть вас)
- указатели (ex:
char *arr
, int *arr
) ------- > heap данные или стек в зависимости от контекста. C позволяет объявить глобальный или static
указатель, и в этом случае сам указатель окажется в сегменте данных.
- динамически распределенное пространство (используя
malloc
, calloc
, realloc
) -------- > стек куча
Стоит отметить, что "стек" официально называется "классом автоматического хранения".
Ответ 2
Для тех будущих посетителей, которым может быть интересно узнать об этих сегментах памяти, я пишу важные моменты о 5 сегментах памяти в C:
Некоторые хедз-ап:
- Всякий раз, когда выполняется программа на С, в ОЗУ для выполнения программы выделяется некоторая память. Эта память используется для хранения часто исполняемого кода (двоичных данных), программных переменных и т.д. Ниже сегменты памяти говорят о том же:
- Обычно существуют три типа переменных:
- Локальные переменные (также называемые автоматическими переменными в C)
- Глобальные переменные
- Статические переменные
- Вы можете иметь глобальные статические или локальные статические переменные, но указанные выше три являются родительскими типами.
5 сегментов памяти в C:
1. Сегмент кода
- Сегмент кода, также называемый текстовым сегментом, представляет собой область памяти, которая содержит часто исполняемый код.
- Сегмент кода часто доступен только для чтения, чтобы избежать риска переопределения путем программирования ошибок, таких как переполнение буфера и т.д.
- Сегмент кода не содержит программные переменные, такие как локальная переменная (также называемая автоматическими переменными в C), глобальными переменными и т.д.
- На основе реализации C сегмент кода может также содержать литералы строки только для чтения. Например, когда вы выполняете
printf("Hello, world")
, тогда строка "Hello, world" создается в сегменте кода/текста. Это можно проверить с помощью команды size
в ОС Linux.
- Дальнейшее чтение
Сегмент данных
Сегмент данных делится на две нижерасположенные части и обычно находится ниже области кучи или в некоторых реализациях над стеком, но сегмент данных никогда не лежит между областью кучи и стека.
2. Неинициализированный сегмент данных
- Этот сегмент также известен как bss.
- Это часть памяти, которая содержит:
- Неинициализированные глобальные переменные (включая переменные указателя)
- Неинициализированные постоянные глобальные переменные.
- Неинициализированные локальные статические переменные.
- Любая глобальная или статическая локальная переменная, которая не инициализируется, будет храниться в сегменте неинициализированных данных
- Например: глобальная переменная
int globalVar;
или статическая локальная переменная static int localStatic;
будут сохранены в сегменте неинициализированных данных.
- Если вы объявляете глобальную переменную и инициализируете ее как
0
или NULL
, то все равно она перейдет в неинициализированный сегмент данных или bss.
- Дальнейшее чтение
3. Инициализированный сегмент данных
- В этом сегменте хранятся:
- Инициализированные глобальные переменные (включая переменные указателя)
- Инициализированные постоянные глобальные переменные.
- Инициализированные локальные статические переменные.
- Например: глобальная переменная
int globalVar = 1;
или статическая локальная переменная static int localStatic = 1;
будут сохранены в сегменте инициализированных данных.
- Этот сегмент может быть дополнительно классифицирован в инициализированную область только для чтения и инициализированную область чтения-записи. Инициализированные постоянные глобальные переменные войдут в инициализированную область только для чтения, в то время как переменные, значения которых могут быть изменены во время выполнения, будут отправляться в инициализированную область чтения и записи.
- Размер этого сегмента определяется размером значений в исходном коде программы и не изменяется во время выполнения.
- Дальнейшее чтение
4. Стековый сегмент
- Сегмент стека используется для хранения переменных, которые создаются внутри функций (функция может быть основной функцией или определяемой пользователем функцией), переменная типа
- Локальные переменные для функции (включая переменные указателя)
- Аргументы, переданные функции
- Обратный адрес
- Переменные, хранящиеся в стеке, будут удалены, как только закончится выполнение функции.
- Дальнейшее чтение
5. Сегмент кучи
- Этот сегмент предназначен для поддержки распределения динамической памяти. Если программист хочет выделить некоторую память динамически, то в C это делается с помощью методов
malloc
, calloc
или realloc
. - Например, когда
int* prt = malloc(sizeof(int) * 2)
будет выделено восемь байтов в куче, а адрес памяти этого места будет возвращен и сохранен в переменной ptr
. Переменная ptr
будет находиться либо в стеке, либо в сегменте данных в зависимости от способа его объявления/использования.
- Дальнейшее чтение
Ответ 3
Исправлены неправильные предложения
constant data types -----> code //wrong
локальные постоянные переменные ----- > стек
инициализированная глобальная постоянная переменная ----- > сегмент данных
неинициализированная глобальная постоянная переменная ----- > bss
variables declared and defined in main function -----> heap //wrong
переменные, объявленные и определенные в основной функции ----- > стек
pointers(ex:char *arr,int *arr) -------> heap //wrong
dynamically allocated space(using malloc,calloc) --------> stack //wrong
указатели (ex: char * arr, int * arr) ------- > размер этой переменной указателя будет в стеке.
Учтите, что вы распределяете память из n байтов (используя malloc
или calloc
) динамически, а затем указываете на переменную указателя. Теперь, когда n
байты памяти находятся в куче, а переменная указателя возвращает 4 байта (если 64-битная машина 8 байтов), которая будет в стеке, чтобы сохранить начальный указатель n
байтов памяти.
Примечание. Переменные указателя могут указывать на память любого сегмента.
int x = 10;
void func()
{
int a = 0;
int *p = &a: //Now its pointing the memory of stack
int *p2 = &x; //Now its pointing the memory of data segment
chat *name = "ashok" //Now its pointing the constant string literal
//which is actually present in text segment.
char *name2 = malloc(10); //Now its pointing memory in heap
...
}
динамически распределенное пространство (с использованием malloc, calloc) -------- > heap
Ответ 4
Популярная архитектура настольных систем делит виртуальную память процесса на несколько сегментов:
-
Текстовый сегмент: содержит исполняемый код. Указатель инструкции принимает значения в этом диапазоне.
-
Сегмент данных: содержит глобальные переменные (т.е. объекты со статической связью). Разделенные на данные только для чтения (такие как строковые константы) и неинициализированные данные ( "BSS" ).
-
Сегмент стека: содержит динамическую память для программы, то есть бесплатное хранилище ( "куча" ) и локальные фреймы стека для всех потоков. Традиционно стек C и куча C приходили в сегмент стека с противоположных концов, но я считаю, что практика была отменена, потому что она слишком опасна.
Программа C обычно ставит объекты со статическим хранением в сегмент данных, динамически распределенные объекты в свободном хранилище и автоматические объекты в стеке вызовов потока, в котором он живет.
На других платформах, например, в реальном режиме реального времени x86 или на встроенных устройствах, вещи, очевидно, могут быть радикально различны.
Ответ 5
Я имею в виду эти переменные только с точки зрения C.
С точки зрения языка С, все, что имеет значение, - это объем, охват, связь и доступ; точно, как элементы сопоставляются с разными сегментами памяти, зависит от конкретной реализации, и это будет меняться. Стандарт языка вообще не говорит о сегментах памяти. Большинство современных архитектур работают в основном одинаково; переменные блока и аргументы функции будут выделены из стека, объем файла и статические переменные будут выделены из сегмента данных или кода, динамическая память будет выделена из кучи, некоторые постоянные данные будут храниться в сегментах только для чтения и т.д.
Ответ 6
указатели (ex: char * arr, int * arr) ------- > heap
Нет, они могут находиться в стеке или в сегменте данных. Они могут указывать в любом месте.
Ответ 7
- Переменные/автоматические переменные --- > раздел стека
- Динамически распределенные переменные --- > раздел кучи
- Инициализированные глобальные переменные → раздел данных
- Неинициализированные глобальные переменные → раздел данных (bss)
- Статические переменные → раздел данных
- Строковые константы → раздел текста/раздел кода
- Функции → раздел текста/раздел кода
- Текстовый код → раздел текста/раздел кода
- Регистры → регистры CPU
- Входы командной строки → раздел защиты окружающей среды/командной строки
- Экологические переменные → раздел защиты окружающей среды/командной строки
Ответ 8
Одна вещь, которую нужно помнить о хранилище, это как бы правило. Компилятору не требуется помещать переменную в определенное место - вместо этого он может размещать ее там, где пожелает, до тех пор, пока скомпилированная программа ведет себя так, как если бы она была программой, запущенной на абстрактной машине C в соответствии с ее правилами. Это относится ко всем периодам хранения. Например:
- переменная, к которой не обращаются все, может быть полностью удалена - она не имеет хранения... нигде. Пример - посмотрите, как в сгенерированном коде ассемблера
42
но нет знака 404
. - переменная с автоматическим сроком хранения, для которой не указан адрес, вообще не должна храниться в памяти. Примером будет переменная цикла.
- переменная, которая является
const
или эффективной const
не обязательно должна быть в памяти. Пример - компилятор может доказать, что foo
эффективно const
и включает его использование в код. bar
имеет внешнюю связь, и компилятор не может доказать, что он не будет изменен вне текущего модуля, поэтому он не встроен. - объект, выделенный с помощью
malloc
не обязательно должен находиться в памяти, выделенной из кучи! Пример - обратите внимание, что в коде нет вызова malloc
и при этом значение 42 никогда не сохраняется в памяти, оно сохраняется в регистре! - таким образом, объект, который был выделен с помощью
malloc
и ссылка потеряна без освобождения объекта со free
не требует утечки памяти... - объект, выделенный
malloc
не обязательно должен находиться в куче ниже прерывания программы (sbrk(0)
) в Unixen...