воскресенье, 13 сентября 2009 г.

Указатели

В двух словах. 

int i = 7;
int* pi = &i; //Указатель на int. Проинициализирован адресом i.
int** ppi = &pi //Указатель на int*, т.е. указатель на указатель на int. Проинициализирован адресом pi.

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

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

Переменная i может хранить любое значение типа int. pi - адрес любой переменной int. ppi - адрес любой переменной типа int*(например адрес pi).

Все это легко проверяется. В моем примере:

cout << i << (long)&i; //7 2293572
cout << pi << (long)&pi; //2293572 2293568
cout << ppi << (long)&ppi; //22968 2293564
cout << *pi << **ppi << (long)*ppi; //7 7 2293572

(long) - преобразование перед выводом. Без него адреса выводятся в шеснадцатеричном виде. * - операция разыменования. То есть *pi возвращает значение переменной, находящуюся по адресу pi. *ppi == pi == &i

Был еще сложный для меня момент: указатели на int и на int* (и вообще все указатели) так похожи, раз хранят только адрес. Почему же нельзя сделать просто указатель на переменную любого типа. Вообще говоря можно. Но в таком случае можно легко ошибиться. Например случайно указать на переменную int, и думать про себя, что это объект. А благодаря типизации, компилятор будет следить за этим, а среда разработки будет помогать автозавершением кода для более сложных типов.

Уф, пока писал и проверял, сам все понял :)

2 комментария:

  1. Хороший пример, я тоже попробовал написать простенькую программку и разобрался. Но возник интересный вопрос. Смотри:
    int a = 7;
    int* b = &a;
    int** c = &b;
    int*** d = &c;
    cout << ***d << endl;
    До какого момента вот так можно создавать указатель на указатель? Должен же быть какой-то предел?

    ОтветитьУдалить
  2. Думаю, что хватит всем :) Даже указатель 300-го уровня работает нормально. Вообще физически все указатели это одно и то же, просто 4-байтовое (на 32-битных системах) число, а эти все звездочки просто для большей наглядности. Можно вообще обойтись одним void* и приводить его к чему нужно, но так легко запутаться и проще отдать это на откуп компилятору.

    ОтветитьУдалить

Можно использовать теги <b>, <i>