Где в памяти мои переменные, хранящиеся в 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...