Принятый ответ немного вводит в заблуждение.
Когда вы используете malloc (), память
может быть получен доступ
где-нибудь в вашем коде, предполагая, что
вы можете увидеть переменную, которая имеет
указатель, возвращаемый функцией malloc ().
Это в равной степени относится к любой памяти, выделенной в C или C ++, будь то куча, стек или статическая память. Просто поместите & перед локальной переменной, и теперь у вас есть ключ, который позволяет любой другой части программы получить доступ к хранилищу для этой переменной и использовать его так же эффективно, как если бы они могли видеть само имя переменной.
Имена локальных переменных видны только внутри области, в которой они объявлены, но их хранилище доступно из любого места, в любом потоке, при условии, что адрес был взят и передан.
Опасно, и все же часто необходимо, брать адрес локальных переменных в C / C ++, и поэтому, к сожалению, невозможно эффективно использовать эти языки, не понимая этого.
UPDATE
@ Кевинф говорит:
Использование локального адреса в рамках локального вполне допустимо, но ваше предложение НЕ безопасно для памяти
Важно различать scope и life . Область действия относится к идентификаторам (например, именам переменных), и это набор мест в вашем коде, где идентификатор может быть упомянут. Это концепция времени компиляции.
Это отдельное понятие от безопасности памяти или времени жизни объекта в месте хранения. Это концепция времени выполнения. Например:
void g(int *p)
{
(*p)++;
}
void f()
{
int n = 1;
g(&n);
}
Здесь идентификатор n
находится только в области видимости в f
. Имя хранилища, которое существует во время работы f
. Мы получаем адрес &n
этого хранилища и передаем его g
. Обратите внимание, что g
не может использовать имя n
напрямую. n
здесь не в поле зрения! Тем не менее, хранилище идеально подходит в этом примере , поскольку f
еще не завершено (ожидает завершения g
).
Большинство реальных программ на C и C ++ часто делают это, и это разрешено стандартом. Это ни вообще безопасно, ни вообще небезопасно. Иногда это безопасно, а иногда нет. Это основная проблема с C и C ++. Неопределенное поведение не всегда обнаруживается при локальном исследовании функции; Вы должны знать, как оно используется в более широком контексте.
Более поздние изменения в языке (в g ++ используйте опцию -std=c++14
для компиляции этого) предлагают другие способы изучения этой серой области:
auto f()
{
int n = 1;
auto g = [&]
{
++n;
cout << "Incremented to " << n << endl;
};
g();
return g;
}
void h()
{
auto g = f();
cout << "Returned into h" << endl;
g();
}
Внутри f
, n
находится в области видимости. И g
содержит экземпляр лямбды, тело которой также является частью области действия n
. И звонок на g
внутри f
в порядке. Но в f
, когда мы сохраняем лямбду в другой переменной с именем g
, последующий вызов к ней не допускается! Мы, даже не используя &n
, неявным образом захватили место хранения, которое нам больше не доступно, поскольку его время жизни было ограничено продолжительностью нашего вызова до f
.
Кстати, когда я говорю, что не разрешено, оно будет компилироваться. Но в моей системе это печатает:
Incremented to 2
Returned into h
Incremented to 167772162
Что явно демонстрирует неопределенное поведение.