C - Почему переменные, созданные в al oop, имеют одинаковый адрес памяти? - PullRequest
4 голосов
/ 17 июня 2020

Просто простой пример моей проблемы:

while(condition){
    int number = 0;
    printf("%p", &number);
}

Эта переменная всегда будет в одном и том же адресе памяти. Почему?

И в чем реальная разница между объявлением его внутри или снаружи l oop тогда?

Нужно ли мне malloc переменную на каждой итерации, чтобы получать разные адреса?

Ответы [ 5 ]

8 голосов
/ 17 июня 2020

Эта переменная всегда будет по одному и тому же адресу памяти. Почему?

Это не обязательно, но ваш код настолько прост, что, вероятно, будет доступен на всех платформах. В частности, поскольку он хранится в стеке, он всегда находится в одном и том же месте относительно указателя стека. Имейте в виду, что вы не выделяете здесь память (не new или malloc), вы просто называете существующую (относительную к стеку) память.

И в чем реальная разница между объявлением это внутри или снаружи l oop тогда?

В данном случае scope. Переменная не существует за пределами фигурных скобок, в которых она находится. Также за пределами фигурных скобок ее место может занять другая переменная, если она умещается в памяти и компилятор решит это сделать.

Нужно ли мне mallo c переменную на каждой итерации, чтобы получать разные адреса?

Да, но я еще не видел хорошего использования malloc чтобы выделить место для int, которое простая переменная стека или стандартная коллекция не подойдут лучше.

5 голосов
/ 17 июня 2020

Эта переменная всегда будет по одному и тому же адресу памяти. Почему?

Компилятор решает, где должна быть переменная, учитывая ограничения операционной системы, гораздо эффективнее поддерживать переменную по одному и тому же адресу, чем перемещать ее на каждой итерации, но теоретически это могло произойти.

Вы не можете полагаться на то, что он каждый раз находится на одном и том же адресе.

И в чем реальная разница между объявлением этого внутри или за пределами l oop тогда?

Разница в времени жизни переменной, если она объявлена ​​в l oop, она будет существовать только внутри l oop, вы можете ' t получить к нему доступ после того, как l oop закончится.

Когда выполнение блока закончится, время жизни объекта закончится, и к нему больше нельзя будет получить доступ.

Будет Мне нужно mallo c переменную на каждой итерации, чтобы получать разные адреса?

malloc - дорогостоящая операция, нет смысла использовать mallo c переменную в каждая итерация, th при сказанном, опять же, компилятор решает, где выделяется память для него, вполне может быть, по тому же адресу или нет. утверждать, где он будет в следующем.

Есть разница в хранимых переменных, выделенные переменные будут в куче, а не в стеке, как в предыдущем случае.

3 голосов
/ 17 июня 2020

Он помещается в тот же адрес памяти для экономии памяти.

Единственное реальное различие между объявлением его внутри и без l oop состоит в том, что переменная больше не будет находиться в области за пределами l oop, если он был объявлен в l oop.

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

1 голос
/ 17 июня 2020

Эта переменная всегда будет по одному и тому же адресу памяти. Почему?

Объект , который обозначает number, имеет auto продолжительность хранения и существует только в течение времени жизни тела l oop, поэтому логически говоря, новый экземпляр создается и уничтожается на каждой l oop итерации.

Практически говоря, проще просто повторно использовать одну и ту же ячейку памяти для каждого l oop итерация, что и делают большинство (если не все) C компиляторов. Просто не гарантируется сохранение своего последнего значения от одной итерации к следующей (особенно если вы инициализируете ее на каждой итерации).

И какая реальная разница между объявлением его внутри или снаружи l oop тогда?

время жизни объекта (период выполнения программы, для которой гарантированно будет зарезервирована память) изменяется с тела l oop на тело функции. область идентификатора (область текста программы, в которой виден идентификатор) изменяется с тела l oop на тело всей функции.

Опять же, практически говоря, большинство компиляторов выделяют пространство стека для auto объектов, которые находятся в блоках при входе в функцию - например, с учетом кода

void foo( void )
{
  int bar;
  while ( bar = 0; bar < 10; bar++ )
  {
    int bletch = 2 * bar;
    ...
  }
}

большинство компиляторов будут генерировать инструкции для резервирования пространства стека для bar и bletch при вводе функции, вместо того, чтобы ждать записи l oop, чтобы зарезервировать место для bletch. Просто проще установить указатель стека один раз и покончить с этим. Хранилище гарантированно должно быть зарезервировано для bletch в течение срока жизни тела l oop, но в определении языка нет ничего, что говорило бы, что вы не можете зарезервировать его до этого.

Однако, если у вас есть такая ситуация:

void foo( void )
{
  int bar;
  while ( bar = 0; bar < 10; bar++ )
  {
    if ( bar % 2 == 0 ) // bar is even
    {
      int bletch = 2 * bar;
      ...
    }
    else
    {
      int blurga = 3 * bar + 1;
      ...
    }
  }

bletch и blurga не могут существовать одновременно, поэтому компилятор может только выделить место для одного дополнительного объекта int, и это же пространство будет использоваться для bletch или blurga в зависимости от значения bar.

0 голосов
/ 18 июня 2020

Существуют компиляторы, которые, несмотря на то, что вы объявляете переменную во внутреннем l oop, просто выделяют их на входе в функциональный блок.

Современные компиляторы обычно выделяют всю память для локальных переменных в одиночный выстрел при входе в функцию, так что это представляет только одно перемещение указателя стека против нескольких инструкций pu sh pop для получения того же результата.

Несмотря на это, есть еще одна проблема, которую вы не рассмотрели. Переменная во внутреннем l oop не видна за пределами l oop, и память, используемая ею, может использоваться для другой переменной снаружи. Вы знаете, что адрес памяти всегда один и тот же ... но вы не знаете, когда вы находитесь вне области видимости, если какой-либо из других переменных, которые вы используете для другого объекта, компилятор дает тот же адрес (это совершенно законно, так как ваша переменная автоматически c, и поэтому она перестает существовать, как только вы выйдете из блока (пара фигурных скобок, которые вы поместили вокруг l oop)

...