Разъяснение указателей и ссылок на C ++ - PullRequest
1 голос
/ 16 ноября 2010

Это в основном просто для того, чтобы помочь мне лучше понять указатели, поэтому, если вы, ребята, можете подтвердить / опровергнуть / объяснить что-либо, похоже, что я не понимаю должным образом, я был бы очень признателен.Примеры использования почтовых ящиков, тетушек, улиц и всего этого дерьма просто сбивают с толку.

int a = 5;

int b = &a; // b will be the memory address of 'a'

int *c = a; // c will be the value of 'a' which is 5

int *d = &a; // d will be a pointer to the memory address of 'a'

int &e = a; // what would this be?


void FunctionA()
{
     int a = 20;
     FunctionB(&a);
     // a is now 15?
}

void FunctionB(int *a)
{
     a = 15;
}

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

Ответы [ 6 ]

3 голосов
/ 16 ноября 2010

Я возьму вещи по одному:

int b = &a; // b will be the memory address of 'a'

Нет.Компилятор (вероятно) не допустит этого.Вы определили b как int, но &a - это адрес int, поэтому инициализация не будет работать.

int *c = a;

Нет - та же проблема,но наоборот.Вы определили c как указатель на int, но вы пытаетесь инициализировать его значением для целого числа.

int *d = &a;

Да -вы определили d как указатель на int, и вы присваиваете ему адрес int - это нормально.Адрес int (или массива int s) - это то, что содержит указатель на int.

int &e = a;

Это определяет e как ссылку на int и инициализируетэто как ссылка на a.Это совершенно законно, но, вероятно, не очень полезно.Просто для справки, наиболее распространенное использование ссылки - это параметр функции (хотя, конечно, существуют и другие цели).

void FunctionA() { int a = 20; FunctionB(&a); }
void FunctionB(int *a) { a = 15; }

Чтобы это работало, вам нужно изменить назначение в FunctionB:

void FunctionB(int *a) { *a = 15; }

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

1 голос
/ 16 ноября 2010

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

Получите большойлист миллиметровки и положите его вдоль стола перед вами.Это память вашего компьютера.Каждый блок представляет один байт.Выберите строку и поместите число «100» под полем слева.Это «самый низкий адрес» памяти.(Я выбрал 100 в качестве произвольного числа, которое не равно 0, вы можете выбрать другое.) Пронумеруйте поля в порядке возрастания слева направо.

+---+---+---+---+---+--
|   |   |   |   |   | ...
+---+---+---+---+---+--
100  101 102 103 104  ...

Теперь представьте, что int имеет размер один байт.Вы восьмибитный компьютер.Запишите свой int a в одну из коробок.Номер под окном является его адресом.Теперь выберите другое поле, содержащее int *b = &a.int *b также является переменной, хранящейся где-то в памяти, и это указатель, содержащий &a, который произносится как "адрес А".

int  a = 5;
int *b = &a;
  a       b 
+---+---+---+---+---+--
| 5 |   |100|   |   | ...
+---+---+---+---+---+--
 100 101 102 103 104  ...

Теперь вы можете использовать эту модель длявизуально прорабатывайте любые другие комбинации значений и указателей, которые вы видите.Это упрощение (потому что, как скажут педанты языка, указатель не является обязательно адресом, а память не обязательно последовательной, и есть стек, куча, регистры и т. Д.на), но это довольно хорошая аналогия для 99% компьютеров и микроконтроллеров.

Вы также можете расширить модель для настоящих четырехбайтовых int с ...

int a = 5;
char b = 2;
  a   a   a   a   b
+---+---+---+---+---+--
| 0 | 0 | 0 | 5 | 2 | ...
+---+---+---+---+---+--
 100 101 102 103 104  ...
1 голос
/ 16 ноября 2010

int a = 5;

Пока все хорошо.

int b = & a; // b будет адресом памяти для 'a'

Это на самом деле ошибка компиляции. Вы, вероятно, имеете в виду int *b=&a;. b - это указатель на целое число. edit: Если вы хотите получить адрес в числовой форме, вам нужно привести приведение к целому числу: int b=(int)&a;

int * c = a; // c будет значением 'a', которое равно 5

Этот более запутанный. По сути, указатель - это просто число, конечно, но этот тип присваивания небезопасен (как вы можете видеть, вы назначаете 5 указателю и пытаетесь разыменовать, что, скорее всего, приведет к сбою вашей программы). Если вы действительно хотите, чтобы c указывал на область памяти 5, вы должны явно сообщить компилятору, что знаете, что делаете: int *c=(int *)a.

int * d = & a; // d будет указателем на адрес памяти 'a'

Это верно, так же, как вы, вероятно, подразумеваете под вторым.

int & e = a; // что бы это было?

e является «ссылкой» на a. Внутренне это просто указатель на a, но вам не нужно вручную разыменовывать его, компилятор обрабатывает это за вас.

void FunctionA () {int a = 20; FunctionB (& а); // а сейчас 15? }

Да.

void FunctionB (int * a) {a = 15; }

... при условии, что вы напишите это как *a=15;. Вы перезаписываете значение, на которое указывает a, а не сам указатель.

Вы, кажется, в целом смущены этим, я рекомендую прочитать книгу "Мышление в C ++", она действительно хорошо написана!

1 голос
/ 16 ноября 2010
int &e = a; // what would this be?

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

0 голосов
/ 16 ноября 2010

int &e=a; является ссылкой на «а».

и это ошибки:


int b = &a;
int *c = a;
0 голосов
/ 16 ноября 2010

Я думаю, что вы имеете в виду:

int *b = &a;, который создает указатель с именем b, указывающий на значение a (b - указатель, являющийся адресом a)

int c = *b;, (или просто int c = a, если вы хотите, чтобы c имел значение a). В этом случае * разыменовывает указатель b

FunctionA() См. Ниже, тогда a будет 15 (вы передаете адрес a в FunctionB)

void FunctionB(int *a) {*a = 15;} устанавливает значение 15 (* разыменование)

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