|
Указатель – это особый вид переменной. Если обычная переменная хранит значение, то указатель хранит адрес ячейки памяти, в которых что-то хранится. От обычных переменных указатель можно отличить по символу «звездочка» перед идентификатором при определении указателя: int *iptr; // указатель iptr на переменную типаint char *str; // указатель str на символ Следует разделять значение указателя и значение по указателю. Значение указателя есть адрес ячейки, а значение по указателю – значение из ячеек по этому адресу. Значение указателю надо присваивать с использованием оператора взятия адреса переменной &: int *iptr; // объявляем указатель наint int var1, var2; // объявляем 2 переменных типаint iptr = &var2; // задаем значение указателя iptr равным адресу переменной var2 Теперь обращение по указателю iptr приведет к тому, что будет использовано значение переменной var2. Кстати, можно присвоить указателю и константное значение, т. е. так: iptr = 0x012F; Но в этом случае во-первых, компилятор выдаст предупреждение, а во-вторых, вы должны четко осознавать последствия работы со значением памяти, на которую этот указатель указывает, т. е. с ячейками по адресу 0×012F. Кстати, избежать предупреждения компилятора можно очень просто: задав принудительно тип константы, как «пустой указатель», т. е. указатель, который указывает «куда-то»: iptr = (void*)0x012F;
Для обращения по указателю используется операция разименования указателя, выражающаяся в том, перед идентификатором указателя записывается символ «звездочка»: *iptr = 12; // теперь окажется, что var2 == 12 Значение по указателю можно использовать, как обычную переменную, т. е. для работы с ним можно использовать все операторы, допустимые для переменных. А вот с операциями над самим указателем есть ряд тонкостей, главная из которых заключается в том, что указатель изменяется на величину, кратную размеру в байтах того типа, на который он указывает. Рассмотрим пример: int *iptr = (void*)0x100; iptr++; int *nptr = iptr; Вопрос: чему равен nptr? Правильный ответ не 0×101, а 0×102, так как размер типа int равен 2 байта. Самое интересное, что в Си нет разницы между указателем и массивом, кроме как в форме определения переменных! Следующие 2 определения абсолютно идентичны: char *str; // указатель на строку char str[]; // массив символов Соответственно, идентификатор любого массива есть ни что иное, как указатель на данные, тип которых определен при описании массива. Отсюда вытекает ряд способов использования указателя по аналогии с массивом, например, можно обращаться по указателю: int *iptr = (void*)0x100; *iptr = 9; iptr[1] = 10; iptr[2] = 11; В результате выполнения этих операторов окажется, что в памяти по адресу 0×100 хранится число 9, по адресу 0×102 хранится 10 и по адресу 0×104 хранится 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) | Просмотров: 1317
 Ваш коментарий будет первым | |
Только зарегистрированные пользователи могут оставлять коментарии. Пожалуйста зарегистрируйтесь или войдите в ваш аккаунт. |