* 18_POINTERS.txt *
УКАЗАТЕЛИ ========= void f(int x){ x = 7; }
main(){ int y = 17; f(y); printf("y=%d\n", y); /* печатает: y=17 */ }
В аргументе x передаётся КОПИЯ значения y, поэтому x=7; не изменяет значения у. Как все же сделать, чтобы вызываемая функция могла изменять значение переменной?
Отбросим два способа:
- объявление y как глобальной (много глобальных переменных - плохой стиль),
- y=f(y); (а что если надо изменить МНОГО переменных? return, к несчастью, может вернуть лишь одно значение).
Используется новая для нас конструкция: УКАЗАТЕЛЬ.
Пример (@)
void f(int *ptr){ /* #2 */ *ptr = 7; /* #3 */ }
main (){ int y=17;
f(&y); /* #1 */ printf("y=%d\n", y); /* печатает: y=7 */ }
Ну как, нашли три отличия от исходного текста?
Мы вводим две новые конструкции:
&y "указатель на переменную y" или "адрес переменной y"
*ptr означает "разыменование указателя ptr" (подробнее - позже)
int *ptr; означает объявление переменной ptr, которая может содержать в себе указатель на переменную, хранящую int-число.
Для начала определим, что такое указатель.
int var1, var2, z; /* целочисленные переменные */ int *pointer; /* указатель на целочисленную переменную */
var1 = 12; var2 = 43; pointer = &var1;
Мы будем изображать указатель в виде СТРЕЛКИ; это хороший прием и при практическом программировании. ________ /pointer/ _/_______/_ | значение| Переменная, хранящая указатель | есть | (адрес другой переменной) | | | &var1 | | | |_______|_| | |&var1 - сам указатель на var1 - | "стрелка, указывающая на переменную var1". V Она обозначается &var1 ________ / var1 / _/_______/_ | значение| | есть | | 12 | |_________|
Таким образом, УКАЗАТЕЛЬ - это "стрелка, указывающая на некий ящик-переменную". Начало этой стрелки можно (в свою очередь) хранить в какой-нибудь переменной.
При этом, если стрелка указывает на переменную типа int, то тип переменной, хранящей начало стрелки, есть int *
Если типа char, то тип - char *
АДРЕС (указатель на) можно взять только от переменной или элемента массива, но не от выражения.
int x; int arr[5];
Законно &x стрелка на ящик "x" & arr[3] стрелка на ящик "arr[3]"
Незаконно &(2+2) тут нет именованного "ящика", на который указывает стрелка, да и вообще ящика нет.