Deprecated: mysql_connect(): The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead in /home/studb20/public_html/index.php on line 4
 1.8.3 Основні операції над покажчиками - Програмування С, С++теорія та практика (частина 1) - Studbook
Главная->Інформатика та програмування->Содержание->1.8.3 Основні операції над покажчиками

Програмування С, С++теорія та практика (частина 1)

1.8.3 Основні операції над покажчиками

Мова Сі надає можливість використання адрес змінних програми за допомогою основних операцій - & та * •

За допомогою основних операцій можна отримати значення адреси змінної а використовуючи непряму адресацію - одержати значення змінної за її адресою.

Призначення цих операцій:

& ім‘я змінної - одержання адреси; визначає адресу розміщення значення змінної визначеного типу;

*  ім‘я-покажчика - отримання значення визначеного типу за вказаною адресою; визначає вміст змінної, розміщеної за адресою, що міститься у даному покажчику; це - непряма адресація (інші назви - “зняття значення за покажчиком” або “розіменування” ).

Оператор присвоювання значення адреси покажчику має вигляд:

Ім‘я_змінної_покажчика = & ім'я змінної;

Наприклад:

іп£ і, *рі;   /* рі -змінна покажчик */

рі = &і;  /* рі одержує значення адреси 'і' */

Операція & - визначення адреси змінної повертає адресу ОП свого операнда. Операндом операції & повинне бути ім'я змінної того ж типу, для якого визначений покажчик лівої частини оператора присвоювання, що одержує значення цієї адреси. У вищенаведеному прикладі це тип іпі.

Операції * і & можна писати впритул до імені операнду або через пробіл. Наприклад: &і, * рі.

Непряма адресація змінної за допомогою операції * здійснює доступ до змінної за покажчиком, тобто повернення значення змінної, розташованої за адресою, що міститься у покажчику. Операнд операції

* обов’язково повинен бути типу покажчик. Результат операції * - це значення, на яке вказує (адресує, посилається) операнд. Тип результату

-   це тип, визначений при оголошенні покажчика.

У загальному вигляді оператор присвоювання, що використовує ім'я покажчика та операцію непрямої адресації, можна представити у вигляді:

ім'я змінної * ім'я-покажчика;

де ім‘я-покажчика - це змінна або константа, що містить адресу розміщення значення, необхідного для змінної лівої частини оператора присвоювання.

Наприклад:

і= *рі; /* 'і' одержує значення, розташоване за

адресою, що міститься в покажчику 'рі' */

Як і будь-які змінні, змінна рі типу покажчик має адресу і значення. Операція & над змінною типу покажчик: &рі - дає адресу місця розташування самого покажчика, рі - ім'я покажчика визначає його значення, а *рі - значення змінної, що адресує покажчик.

Звичайно, усі ці значення можна надрукувати. Наприклад, за допомогою наступної програми:

#іпс1ийе <з,Ьгііо.Ь>

Vоій. таіп ()

{

сЬаг с = 'А'; іп£ і = 7776; іп£ *рі = &і; сЬаг *рс = &с;

ргіп^£ ("рі=%и,*рі=%й, &рі=%и\п", рі, *рі, &рі); ргіп^£ ("рс=%и, *рс=%с, &рс=%и\п", рс, *рс, &рс);

}

У результаті виконання буде виведено: рі = 65522, *рі = 7776, &рі = 65520 рс = 65525, *рс = А, &рс = 65518

Одне з основних співвідношень при роботі з покажчиками - це симетричність операцій адресації та непрямої адресації. Вона полягає в тому, що:

&х == х, тобто вміст за адресою змінної х є значення х. Наприклад, оголошення покажчика рі і змінних і та _):

іп£ *рі, і = 123, і;

рі = &і; /*-присвоювання покажчику значення адреси і */ І = *рі; /* - присвоювання і вмісту за адресою рі */

Тут змінна ] отримує вміст, розташований за адресою змінної і, тобто значення змінної, що адресує покажчик рі: ] = * рі = * &і = і;. Два останніх вищенаведених оператора виконують те саме, що один оператор: ] = і.

Для повного остаточного розуміння процесів, що відбувається у пам’яті при маніпуляції з покажчиками, розглянемо ще такий фрагмент:

Vоій. £ипс () {

іп£ х ;

іп£ *рх; /* рх - покажчик на змінну типу іп£*/ рх= &х ; /* адреса змінної х заноситься в рх*/

*рх=77;     /* число зберігається за адресою, на яку

вказує рх */

}

Розглянемо цей приклад на конкретному малюнку: функція займає область пам’яті, починаючи з адреси 0x100, х знаходиться за адресою 0x102, а рх - 0x106. Тоді перша операція присвоювання, коли значення &х(0х102) зберігається в рх, матиме вигляд, зображений на рис. 1.11 зліва:

Наступну операцію, коли число 77 записується за адресою, яка знаходиться в рх та дорівнює 0х102 (адреса х), відображає рис. 1.11 справа. Запис *рх надає доступ до вмісту комірки, на яку вказує рх.

рх=&х; ^                                         ^ *рх=77;

 

 

0x100

 

 

0x100

X

 

0x102

X

77

0x102

 

 

0x104

 

 

0x104

рх

0x102

0x106

рх

0x102

0x106

 

 

0x108

 

 

0x108

 

 

0x10а

 

 

0x10а

Рис. 1.11. Схематичне представлення значень в ОП

 

Далі наведений приклад програми виводу значень покажчика і вмісту, розташованого за адресою, що він зберігає.

#іпс1игіе<5'Ьгі±о. Ь>

Vоій. таіп ()

{

іп£ і = 123, *рі = &і; /* рі-покажчик на значення типу іп£ */

ргіп^£("розмір покажчика рі = %гі\п", зігео£ (рі)); ргіп'ЬЕС адреса розміщення покажчика рі=%и\п", &рі) ; ргіп'ЬЕС адреса змінної і = %и\п", &і)                         ;

ргіп^£("значення покажчика рі = %и\п", рі) ; ргіп^£("значення за адресою рі = %гі\п", *рі) ; ргіп^£("значення змінної і = %гі\п", і) ;

}

Результати виконання програми: розмір покажчика рі = 2

адреса розміщення покажчика рі = 65522 адреса змінної і= 65524 значення покажчика рі = 65524 значення за адресою рі = 123 значення змінної і = 123

Покажчики можна використовувати:

1.                                              у          виразах,  наприклад,         для одержання    значень,

розташованих за адресою, що зберігається у покажчику;

2.       у лівій частині операторів присвоювання, наприклад:

a.        для одержання значення адреси, за якою розташоване значення змінної;

b.         для одержання значення змінної.

Наприклад, якщо рі - покажчик цілого значення (змінної і), то *рі можна використовувати в будь-якому місці програми, де можна використовувати значення цілого типу. Наприклад: іп£ і = 123, і, *рі;

рі = &і; /*рі у лівій частині оператора присвоювання */

І = *рі + 1; /*-це еквівалентно: і = і + 1;

рі-у виразі правої частини оператора присвоювання*/

Виклик значення за покажчиком можна використовувати також як фактичні параметри при звертанні до функцій. Наприклад:

й. = 8^^■Ь ( (йоиЬІе) *рі) ;                              /*       *рі   -          фактичний       параметр                  */

ЕзсапЬ (£,                                           рі );                   /*          рі   -          фактичний       параметр                  */

ргіп'ЬЕ ("%й\п", *рі ) ;                                        /*       *рі   -          фактичний       параметр                  */

У виразах унарні операції    & і *, пов'язані з покажчиками, мають

більший пріоритет, ніж арифметичні. Наприклад:

*рх = &х;

у = 1 + *рх; /*-спочатку виконується '*', потім '+' */

Останній оператор еквівалентний: у = 1 + х;

Для звертання до значення за допомогою покажчика-змінної його можна використовувати в операторі присвоювання скрізь, де може бути ім'я змінної. Наприклад, після виконання оператора: рх = &х; цілком еквівалентними є такі описи:

Оператор:           Його еквівалент:                     Або:

*рх =0;      х = 0;

*                         рх += 1; * рх = * рх + 1; х = х + 1;

(*рх)++ ;    *рх = *рх + 1; х = х + 1;

(*рх)--;     *рх = *рх - 1; х = х - 1;

Наступна програма демонструє найпростіше практичне використання покажчиків, виводячи звичайну послідовність літер алфавіту:

#іпс1ийе <з,Ьгііо.Ь>

сЬаг с; /* змінна символьного типу*/ таіп()

{

сЬаг *рс; /* покажчик на змінну символьного типу*/ рс=&с;

£ог(с='А';с<='2';с++) ргіп^£("%с",*рс); ге'Ьигп 0;

}

У операторі ргіпґ/(“%с ”, *рс) має місце розіменування покажчика (*рс) - передача у функцію значення, що зберігається за адресою, яка міститься у змінній рс. Щоб дійсно довести, що рс є псевдонімом с, спробуємо замінити *рс на с у виклику функції - і після заміни програма працюватиме абсолютно аналогічно. Оскільки покажчики обмежені заданим типом даних, типовою серйозною помилкою їх використання буває присвоєння адреси одного типу даних покажчика іншого типу, на що компілятор реагує таким чином:

“Зизрісіоиз роіпіег сопуегзіоп іп Ніпсііоп таіп()”

На ТС це лише попередження (підозріле перетворення покажчика у функції таіп()(?!)), і якщо на нього ніяк не відреагувати, то програма працюватиме й надалі (адже помилку зафіксовано не буде) і залишається лише здогадуватися, який результат буде надалі. Зазначимо, що компілятор ВС++ з приводу такого “підозрілого перетворення” пішов все-таки далі:                він          просто відмовляється

працювати, видаючи повідомлення про помилку. Відповідальність за ініціалізацію покажчиків повністю покладається на програміста, і більш детально про це йтиметься далі.

 

45