С указателями Вопрос - PullRequest
8 голосов
/ 10 июля 2009

Для:

int *a;

a - это адрес, где может храниться целое число. &a - это адрес, где хранится. Тогда где хранится &a? И где хранится &(&a)? И где хранится &(&(&a))? Где останавливается это хранение адресов?

Ответы [ 14 ]

7 голосов
/ 10 июля 2009

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

Например:

functionCall( &a ); // address will be in a temporary variable used for passing the parameter
int** b = &a; // address will be stored in variable b
otherFunctionCall( &&a ); // illegal, since &a is an expression operator & can't be applied to it
4 голосов
/ 10 июля 2009

a не является «адресом, где может храниться целое число». a - переменная, достаточно большая, чтобы содержать адрес целого числа. Единственное целое число, которое вы можете сохранить непосредственно в a, - это адрес целого числа, рассматриваемого как само целое число:

int *a;
int b;

a = &b;

printf("a is now %x\n", (unsigned int) a);

Правильно, что сам a имеет адрес, который &a, но этот адрес не сохраняется где-то явно во время выполнения.

Вы можете хранить что-то похожее на целое число 0:

.
a = 0;

Но это всего лишь сокращенный синтаксис для "указателя NULL", то есть значение указателя гарантированно не будет адресом какого-либо фактического объекта.

4 голосов
/ 10 июля 2009

&a является константой.

&(&a) незаконно.

3 голосов
/ 10 июля 2009

& a является адресом. Это значение, результат оператора & применяется к a, оно не "сохраняется" и не имеет адреса, поэтому & (& a) является недействительным Это как 2 + 3.

2 голосов
/ 10 июля 2009

int *a - это переменная размером с указатель, точно так же, как int b будет автоматической переменной int.

Если это объявление находится в функции, эта переменная является автоматической и сохраняется в [stack] (http://en.wikipedia.org/wiki/Stack_(data_structure)#Hardware_stacks) во время выполнения (простое уменьшение стека выделяет для нее память).

Если объявление является глобальным, то 'a' просто отображается в области .DATA исполняемого файла.

Любые добавленные знаки & могут «создавать хранилище» из-за временных переменных, которые вы используете для hold'em;):

b = &a; //the address in the executable's .DATA or on the stack (if `a` auto)
c = &b; //the address of `b` on the stack, independent of `a` or `&a`
d = &c; //the address of `c` on the stack, independent of `a` or `&a`
z = &(&a); //error: invalid lvalue in unary '&'

Последняя строка жалуется на тот факт, что & требует, чтобы операндом был lvalue. То есть что-то присваиваемое - как b и c выше. (&a) as является результатом выражения, которое нигде не сохраняется, поэтому не является lvalue.

1 голос
/ 12 июля 2009

В C переменная x может выступать в качестве значения (с правой стороны от =, где она называется rvalue ), или она может действовать как контейнер для значений (в левой части =, где оно называется lvalue ). Вы можете взять адрес x, потому что вы можете взять адрес любой lvalue - это даст вам указатель на контейнер. Но так как указатель является значением, а не контейнером, вы никогда не сможете взять &(&x). Фактически для любого lvalue l, &l допустимо, но &(&l) никогда не разрешено.

1 голос
/ 11 июля 2009

В основе вашей проблемы, похоже, лежит непонимание физической природы памяти и указателей. Не так, как работает код. Как я уверен, вы знаете, физическая память состоит из большой группы соседних ячеек. Адреса этих ячеек фиксируются и жестко кодируются самим компьютером, а не программными приложениями или языком программирования, который вы используете. Когда вы ссылаетесь на & a, вы имеете в виду физический блок памяти, в котором в настоящее время хранится ваше значение, которое вы сохранили в памяти компьютера. «a» - это просто имя, которое вы дали компьютеру, чтобы он точно знал, в каком блоке памяти найти значение, которое вы сохранили. Я думаю, что это в значительной степени покрывает адрес памяти.
Теперь перейдем к указателям. Указатель - это еще один адрес памяти, на который ссылается компьютер. У него есть любое имя, которое вы ему дадите. В этом случае это должно называться как-нибудь еще, кроме того же имени, которое вы дали вашему первому значению. Давайте назовем это «б». На основании того, как вы это заявили. Ячейка памяти b может содержать только один тип данных ... другую ячейку памяти .... поэтому, когда я говорю: b = & a, я говорю, что адрес памяти равен 'b' (который предназначен только для хранения адреса памяти), для хранения адреса памяти «а». Между тем в другой части города в адресе памяти «а» хранится целое число.

Надеюсь, это не смутило, я старался не показывать вам всю техногу. Если вы все еще в замешательстве. Опубликуйте еще раз, я объясню с кодом в следующий раз.

-UBcse

1 голос
/ 10 июля 2009

Вы можете продолжать идти вечно:

int value = 742;
int *a = &value;
void *b = &a;
void *c = &b;
void *d = &c;

Вы бы не поместили его в одну строку, не назначив его чему-либо - в этом случае он был бы недействительным.

0 голосов
/ 10 июля 2009
int* a;

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

Что касается вашего вопроса о том, где & a хранится, скорее всего, в реестре. Если вы не используете значение, оно будет немедленно отброшено. (И регистры не имеют адресов памяти, поэтому вы не можете сделать & (& a))

0 голосов
/ 10 июля 2009

& a - это число, которое является r-значением: вы можете хранить его где-нибудь, если хотите, в переменной, которую вы объявите или разместите, типа int *.

Для остроумия:

int a = 42;
&a; /* this does not store the address of a because you've not assigned the value to a variable */
int **aptr = &a; /* aptr is on the stack */
int **aptr2 = (int*)malloc(sizeof(int*));
aptr2 = &a; /* aptr2 is in the heap */

& (& a) не является допустимым синтаксисом. Если вы хотите указатель на указатель на int:

int b = 39;
int *bptr = &b;
int **ptr2bptr = &bptr;

Вы должны повысить уровни косвенности.

С вышеупомянутым вы можете сделать это, если хотите:

printf("%d\n", *aptr);
printf("%d\n", *aptr2);
printf("%d\n", *bptr);
printf("%d\n", **ptr_to_bptr);

Производство продукции:

42
42
39
39
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...