7. Что такое указатель и для чего он нужен?
Автор ARV   
18.12.2009 г.

Указатель - это особый вид переменной. Если обычная переменная хранит значение, то указатель хранит адрес ячейки памяти, в которых что-то хранится. От обычных переменных указатель можно отличить по символу «звездочка» перед идентификатором при определении указателя:

int *iptr; // указатель iptr на переменную типа int
char *str; // указатель str на символ

Следует разделять значение указателя и значение по указателю. Значение указателя есть адрес ячейки, а значение по указателю - значение из ячеек по этому адресу. Значение указателю надо присваивать с использованием оператора взятия адреса переменной &:

int *iptr; // объявляем указатель на int
int var1, var2; // объявляем 2 переменных типа int
iptr = &var2; // задаем значение указателя iptr равным адресу переменной var2

Теперь обращение по указателю iptr приведет к тому, что будет использовано значение переменной var2. Кстати, можно присвоить указателю и константное значение, т.е. так:

iptr = 0x012F;

Но в этом случае во-первых, компилятор выдаст предупреждение, а во-вторых, вы должны четко осознавать последствия работы со значением памяти, на которую этот указатель указывает, т.е. с ячейками по адресу 0x012F. Кстати, избежать предупреждения компилятора можно очень просто: задав принудительно тип константы, как «пустой указатель», т.е. указатель, который указывает «куда-то»:

iptr = (void*)0x012F;

 

Для обращения по указателю используется операция разименования указателя, выражающаяся в том, перед идентификатором указателя записывается символ «звездочка»:

*iptr = 12; // теперь окажется, что var2 == 12

Значение по указателю можно использовать, как обычную переменную, т.е. для работы с ним можно использовать все операторы, допустимые для переменных. А вот с операциями над самим указателем есть ряд тонкостей, главная из которых заключается в том, что указатель изменяется на величину, кратную размеру в байтах того типа, на который он указывает. Рассмотрим пример:

int *iptr = (void*)0x100;
iptr++;
int *nptr = iptr;

Вопрос: чему равен nptr? Правильный ответ не 0x101, а 0x102, так как размер типа int равен 2 байта.

Самое интересное, что в Си нет разницы между указателем и массивом, кроме как в форме определения переменных! Следующие 2 определения абсолютно идентичны:

char *str; // указатель на строку
char str[]; // массив символов

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

int *iptr = (void*)0x100;
*iptr = 9;
iptr[1] = 10;
iptr[2] = 11;

В результате выполнения этих операторов окажется, что в памяти по адресу 0x100 хранится число 9, по адресу 0x102 хранится 10 и по адресу 0x104 хранится 11.

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

char array[10] = {1,2,3,4,5,6,7,8,9,10};
int var = 10;
long *lptr = (void*)array;
lptr[2] = 12;

В приведенном примере нет ни одной ошибки, но к каким последствиям он приведет?! «Неожиданно» переменная var окажется обнуленной...


Добавить в любимые (0) | Просмотров: 11195

  Коментарии (2)
 1 Написал(а) Настоящее имя, в 09:53 21.10.2011
так и не понял, почему же var окажется обнуленной??? :?
 2 Написал(а) Настоящее имя, в 10:19 21.10.2011
кажись понял...наверное потому что мы переопределили символьный масив в long, отсюда число 12 запишется начиная с 9,10 + 2 байта, что перезапишет var...

Только зарегистрированные пользователи могут оставлять коментарии.
Пожалуйста зарегистрируйтесь или войдите в ваш аккаунт.