Подтвердить что ты не робот

Адрес переменной с помощью указателя

Рассмотрим следующий код в C

int x=100;
int*addr=&x;

Я знаю, что addr сохранит адрес xA-вопроса, который продолжает появляться в моем сознании, заключается в том, что указатель addr будет иметь свой собственный адрес, и с ним снова можно будет получить доступ с помощью оператора ampersand, и это тоже будет храниться где-то, поэтому мы имеем здесь бесконечная рекурсия по адресам, так где это заканчивается?

4b9b3361

Ответ 1

Адрес addr не "хранится" где-либо явно, это просто так. Если вы должны были объявить вторую переменную и использовать ее для хранения этого адреса, то обязательно это займет пространство:

int **addr2 = &addr;

Вы можете думать о памяти как о серии ящиков. Предполагая, что 4 байта int и указатели, и порядок байтов младшего порядка, ваш сценарий может выглядеть так:

+----------+--+--+--+--+
| Address  |Data bytes |
+----------+--+--+--+--+
|0x00000000|64|00|00|00|
+----------+--+--+--+--+
|0x00000004|00|00|00|00|
+----------+--+--+--+--+

Адрес показан слева, байты, содержащиеся в этом месте справа. Вы можете увидеть значение 100, хранящееся в первых четырех байтах (100 десятичных чисел - 0x64 в шестнадцатеричном формате). Второе 4-байтовое местоположение содержит значение 0x00000000, которое является адресом x. Адрес 0x00000004 не сохраняется нигде.

Теперь, если мы добавим второй указатель, мы будем использовать больше памяти:

+----------+--+--+--+--+
|0x00000008|04|00|00|00|
+----------+--+--+--+--+

Это будет память, используемая для представления указателя addr2, и вы можете видеть, что он содержит адрес addr, то есть 0x00000004.

Разыменование addr2 с выражением *addr2 даст значение по адресу 0x00000004, то есть 0x00000000 с типом int *. Де-ссылка на то, что еще раз дает int по этому адресу, то есть 0x00000064.

Поскольку этот макет памяти выбран компилятором, он "знает" задействованные адреса и может просто подставить так, что, когда ссылки на код addr2, он генерирует инструкции, которые управляют адресом 0x00000008 и т.д. В реальном коде это, вероятно, все произойдет в стеке, но принцип тот же.

Заключительное примечание: ознакомьтесь с рекомендацией @Phil Perry; вышеупомянутое упрощает и делает черным множество вещей, которые должны быть несколько абстрактными. Это то, как он действительно работает во многих современных архитектурах, но многие из упомянутых вещей не гарантируются C, поэтому вы не можете действительно зависеть от них, чтобы всегда оставаться правдой. Я имел в виду вышеприведенное в качестве иллюстрации (надеюсь) сделать концепции слабее менее расплывчатыми.

Ответ 2

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

int         a = 1;
int       *pa = &a;
int     **ppa = &pa;
int   ***pppa = &ppa;
int ****ppppa = &pppa;
...

Вот быстрая аналогия: скажем, у вас есть ноутбук с пронумерованными страницами и строками. Предположим, вы сделали заметку на стр. 3, строка 8, а затем вы хотите ссылаться на эту заметку из другого места. Возможно, вы можете написать на стр. 7, строка 20, ссылку "см. Примечание на стр. 3, строка 8". Теперь ссылка имеет свой собственный "адрес", а именно, стр. 7, строка 20. Вы также можете ссылаться на нее - на странице 8, строка 1, вы можете написать "см. Примечание на стр. 7, строка 20". Вы можете продолжать эту цепочку ссылок столько, сколько пожелаете.

Ответ 3

C реализует так называемую машину фон Неймана. Вы можете скомпилировать C на других компьютерах, если вы можете заставить компьютер делать то, что сделает машина фон Неймана.

Итак, что такое машина фон Неймана? С извинениями перед BBC, большинство людей полагают, что программы в памяти имеют строгие и четкие представления о коде и данных, но на самом деле - из единой перспективы фон Неймана - пространство для программной памяти больше похоже на большой шар wibbly- wobbly, numbery-wumbery... stuff. Вы можете получить доступ и даже изменить его как данные, или вы можете запускать его как код. Но это последнее не очень хорошая идея, если вы не уверены, что это рабочий код, который является одной из причин, по которым люди не используют сборку очень часто. Языки программирования более высокого уровня тщательно упорядочивают числа во что-то, что (в идеале) работает: они не идеальны в этом, а C по своей конструкции менее совершенен в нем, чем большинство. Но они обычно выполняют свою работу.

Теперь, что это связано с вашим вопросом? Как вы говорите, каждая переменная должна иметь адрес, а C должен знать, для чего эти адреса используются для их использования. Точные сведения о реализации могут варьироваться от компилятора к компилятору, а иногда и по разным настройкам в компиляторе, но в некоторых случаях программа даже не знает имена переменных до того момента, пока она дойдет до уровня машинного кода. Все адреса оставлены, и они действительно используются.

Эти адреса решаются компилятором. В конечном счете, они становятся частью самого кода. Они хранятся в областях, к которым вы обычно не должны обращаться, но можете, если вам действительно нужно. Эти области в основном там, где рекурсия прекращается.

Ответ 4

У вас нет бесконечной рекурсии. Каждая переменная имеет свой адрес и что она. Теперь, если вы определяете переменную, которая равна адресу другой переменной, чем сама адресная переменная будет храниться где-то и будет иметь адрес. Сам адрес не имеет адреса переменной, которая хранит его.

Ответ 5

Концептуально пространство памяти выделяется только для указателя при сохранении адреса:

1) В вашем случае: int*addr=&x;, addr будет занимать sizeof(int*) байт памяти. (Но компилятор оставляет за собой право не хранить указатель в памяти: он может содержать его в регистре CPU).

2) &x не выделяет явное хранилище.

3) &&x, &&&x и т.д. не являются синтаксически действительными, поэтому вам не нужно беспокоиться о потенциальной рекурсии.

Тот факт, что && использовался как незаконный синтаксис, разрешал использовать С++ 11 для этого для ссылок на r-значение.

Ответ 6

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

Ответ 7

Давайте посмотрим так. У нас есть память limited. Если эта целая память, ограниченный объем памяти выделяется для компиляторов для STORE их переменных. U может объявлять столько переменных, сколько пожелает, но придет время, когда вы не сможете сделать больше переменных, потому что allocated memory пробежит пространство. Итак, что касается вашего вопроса, ответ NO. нет бесконечной рекурсии из-за ограниченного выделенного пространства для хранения переменных.

Ответ 8

Указатели похожи на дом и его адрес в местности. Дом реальный, и его адрес - это способ найти дом. Предположим, что есть два дома, X и ptr, и мне нужно сохранить адрес (возможно, написав его в листе бумаги) одного дома, скажем X в другом доме, скажем, ptr. С этой договоренностью Если мне нужно знать адрес X, я могу посмотреть в ptr, но что там в X, мне нужно лично посетить дом. Но в настоящее время меня совсем не интересует адрес ptr.

Чтобы ускорить процесс

ptr and X are two houses.

//lets say &X is a sheet of paper containing the address of house X. I am going to keep this address in the house ptr. So the address of X is stored in ptr.

ptr = &X;

//Now what about ptr. Only if I need to know the address, I need to write the address in some paper and store it again in some other house. Else I am happy to know the house exits. 

Ответ 9

Это зависит...

Это зависит от компилятора и уровня оптимизации. Есть вероятность, что компилятор решит не хранить указатель "addr" в первичной памяти, а просто сохранить его значение в регистре, используя его, чтобы найти х в первичной памяти.

Ответ 10

Здесь много хороших ответов, но позвольте мне добавить еще один. Я хочу прояснить довольно тонкий момент, сделанный Вирсабой. Вы сказали:

указатель addr будет иметь свой собственный адрес и который может быть снова доступен с помощью оператора ampersand, и это тоже будет храниться где-нибудь

Это предложение неверно тонким способом. Вот правильная фраза:

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

Указатель - это значение. Все значения хранятся где-то. Но не все места хранения имеют адреса! Есть места хранения, у которых нет адресов - они называются регистрами, а компилятор может использовать регистр для любого места хранения при условии, что адрес это место хранения никогда не берется.

Итак, когда вы говорите:

int x = 100;
int*addr = &x;

Тогда место хранения, связанное с переменной x, должно иметь адрес, потому что его адрес занят. Но нет требования, чтобы место хранения, связанное с addr, имело адрес, потому что его адрес никогда не принимался; поэтому он может быть зарегистрирован. Он не обязан быть зарегистрированным, но он может быть.

Имеют смысл?

Ответ 11

Ответ на @unwind хорош, но есть огромное огромное предостережение: язык C позволяет вам создать указатель на что угодно, и это может вызвать у вас проблемы. Рассмотрим эту крошечную программу на C:

/*
 * show that a variable allocated on the heap sticks around, while a
 * variable allocated on the stack vanishes after its enclosing
 * function returns.  Holding a pointer to the latter can lead to 
 * unexpected results.
 */
#include <stdio.h>

int heapvar = 20;

int *get_heapvar_ptr() {
  return &heapvar;
}

int *get_stackvar_ptr() {
  int stackvar = 30;
  return &stackvar;
}

int main() {
  int *heap_ptr = get_heapvar_ptr();
  int *stack_ptr = get_stackvar_ptr();

  /* should print value = 20 */
  printf("heapvar address = %#x, heapvar value = %d\n", heap_ptr, *heap_ptr);
  /* you might expect this to print value = 30, but it (probably) doesn't */
  printf("stackvar address = %#x, stackvar value = %d\n", stack_ptr, *stack_ptr);
}

При запуске (по крайней мере, в моей среде) я получаю:

heapvar address = 0x22a8018, heapvar value = 20
stackvar address = 0x5d957fac, stackvar value = 0

Обратите внимание, что значение "стоп файл" теперь равно нулю, даже если оно было равно 20. Это связано с тем, что stack_ptr указывает на место в стеке, которое было перезаписано какой-либо другой функцией.

К чести, компилятор предупредил меня warning: address of stack memory associated with local variable, но мораль этой истории заключается в том, что арифметика указателя на C очень мощная и соответственно опасная!