Увод в програмирането  alpha
Указатели, основни операции

Указателят е променлива, чиято стойност е адрес от паметта.

Дефниране на указател:

        име_на_тип *име_на_указателя;

На мястото на име_на_тип може да стои всеки валиден тип в C/C++.

Име_на_указател е идентификатор.

Note
За да дефинираме указател името на указателя трябва да има префикс *

Дефинираният тип на указателя трябва да съответства на типа на обекта, към който сочи указателя.

Ако това не е изпълнено програмистът трябва да знае какво точно ще се случи. В подобна ситуация повечето компилатори предупреждават за несъответстието.

Примери за дефиниране на указатели:

        int *p;
        float *p1;
        double z, *p2;
        // Тук само p2 е указател!

След като дефинираме даден указател той съдържа произволна стойност и трябва да бъде използван едва след като е инициализиран, т.е. след като ми присвоена дадена стойност, която е валиден адрес от паметта на компютъра. По определение указателите са променливи и следователно могат да бъдат инициализирани по общите правила за инициализиране на променливи.

Note
Ако указателят има стойност 0, тогава той е свободен и не посочва нищо.

Инициализиране на свободен указател:

        p = NULL;
        // или:
        p = 0 ;

Използването на указател, който има стойност "0" е опасна. Не се знае какво се случва. Стойност 0 може да се използва като маркер ( флаг ) за идентификатор за грешка и др.

Note
Указателите не са цели числа и не трябва да се използват като цели променливи!

Операции с указатели:

& операнд -> дава адреса на операнда. Операндът трябва да бъде променлива.

операнд -> дава променливата, чийто адрес се определя от операнда. Операндът е израз, който има като стойност адрес.

Двете операции по-горе са едномерни ( унарни ) операции. Следователно и двете се изпълняват от тясно на ляво и са с висок приоритет.

Пример за работа с указатели:

        float x,y, *px, *py;
        x = 3.14;
        // на х се присвоява стойност 3.14
        
        px = &x;
        // На указателя px се присвоява адреса на променливата x.
        
        y = *px+10;
        // 1. *px се замества със стойността на клетката намираща се на адреса сочен от px, т.е. стойността на х.
        // 2. Към 3.14 ( стойността на x ) се прибавя 10.
        
        py = px;
        // Адресът на px се присвоява от py.

Чрез x се осъществава пряк достъп до x, а чрез *px косвен достъп.

Забележка:

        y = ++ *px; 
        // равносилно с:
        y = ++x;
        
        y = (*px)--;
        // равносилно с:
        y = x--;

Пример:

        float x,y;
        int *px; 
        x = 3.14;
        
        px = &x; // px = (int * ) ( &x);
        y = *px;

При извикването на px = се взимат двата младши байта и те се разглеждат като допълнителен код на цялото число.

Чрез указателите се осъществява няколкократен косвен достъп до променливи.

        int x, *px, **pxx;

x - пряк достъп до променлива

px - еднократен косвен достъп до променлива

pxx - двукратен косвен достъп до променлива

На указател не може да се присвои адрес на променлива от тип const, защото това би било непряк начин за промяна на стойността й.

        const int initial = 100;
        int *ptr = &initial;  // този ред дава грешка при компилиране!

Възможно е дефиниране на указател, който сочи към променлива от тип const. Това става по следния начин:

        const int *ptr = & initial;

Указателят към константа може да получи друга стойност, но променливата извлечена с него не може да бъде променяна:

        const int k=1;
        ptr = &k;
        *ptr = 3; // дава грешка при компилация!

Възможно е да дефинираме указател, който е константа:

        int * const ptr1 = &k; 
        // Самият указател е const.
        *ptr1 = 5;
        int a=2;
        ptr1 = &a; - грешка;
        
        int *const ptr2 = &initial; 
        // указател, който е константа и сочи към константа.