Оголошення вказівника, операції, пов’язані з вказівниками 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Оголошення вказівника, операції, пов’язані з вказівниками



Вказівник (покажчик, англ. pointer) – це особливий тип даних, значенням якого є адреса певного байта оперативної пам'яті. Найчастіше вказівник зберігає адресу першого байта одного з об’єктів програми. Це називається посиланням на вказаний об’єкт.

Вказівники можуть бути константними і змінними: константні вказівники зберігають незмінну адресу оперативної пам'яті, зокрема константними вказівниками є імена масивів і символьних рядків; вказівники – змінні є змінними програми, їм можна надавати значення адрес різних ділянок оперативної пам'яті.

Як і для змінних, вказівники необхідно оголошувати. Синтаксис оголошення змінних такий:

 

базовий_тип * ім’я_вказівника;

 

тут базовий тип – тип об’єктів програми, адреси яких може зберігати даний вказівник; це може бути довільний стандартний тип або тип користувача; * - ознака того, що наступна змінна є вказівником; ім’я вказівника – ідентифікатор.

З вказівниками пов’язані дві унарні операції: & - визначення адреси, * - звертання до об’єкта за адресою.

Значенням операції визначення адреси змінної є адреса операнда (тобто змінної), перед яким стоїть знак &. Розглянемо фрагмент програми:

 

#include <iostream>

using namespace std;

int main() {

int a = 5, *pa;

pa = &a;

cout << pa << endl;

}

 

тут змінна а – звичайна змінна цілого типу, ра – вказівник на ціле. В результаті виконання рядка pa = &a; змінна ра буде містити адресу першого байти пам'яті, яку займає змінна а.

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

 

#include <iostream>

using namespace std;

int main() {

int a = 5, *pa;

char c = 'z';

pa = &c;        // Помилка, базовий тип вказівника і

                     // тип змінної не співпадають

}

 

Існують такі обмеження щодо застосування операції визначення адреси: не можна визначати адресу константи; не можна визначати адресу виразу; не можна визначати адресу змінної з класом пам'яті register.

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

 

int a = 5, *pa = &a;

 

Вказівники можна також ініціалізувати значеннями адрес – констант:

 

char *pc = (char *) 0x04cd;

 

Існує константа NULL, яку можна присвоювати вказівникам всіх типів. Вважається що вказівник, значенням якого є NULL, не посилається на жоден об’єкт програми. Такий вказівник називають порожнім вказівником.

Операндом операції звертання за адресою є вказівник або адреса ділянки пам'яті, а результатом – значення об’єкта, який зберігається в цій ділянці. Цю операцію також називають розадресацією, вона є зворотною до операції взяття адреси. Результат цієї операції має тип, що був заданий як базовий в оголошенні вказівника. Звертання через вказівник можна використовувати всюди, де синтаксично може бути записаний об’єкт даного типу. Наприклад:

 

#include <iostream>

using namespace std;

int main() {

int a = 5, *pa;

pa = &a;        // Отримали адресу змінної а

*pa = 12;       // Змінили значення змінної а

cout << *pa << endl;

cout << a << endl;

}

 

В оголошеннях вказівників можна вказувати кваліфікатор const. Роль цього кваліфікатора визначається місцем його запису.

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

 

#include <iostream>

using namespace std;

int main() {

int a = 5;

const int b = 123;

const int * cp;

cp = &a;      // Можна змінювати значення вказівника

*cp = 12;      // Помилка, не можна змінювати значення

                // об’єкта, на який посилається вказ-к

cp = &b;

cout << *cp << endl; // Можна читати значення об’єкта, на

                     // який посилається вказівник

}

 

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

 

#include <iostream>

using namespace std;

int main() {

int a = 5, b = 12;

int * const cp = &a;

cp = &b;        // Помилка, не можна змінювати значення

                     // константного вказівника

*cp = 12;      // Можна змінювати значення об’єкта, на

                     // який посилається вказівник

cout << *cp << endl; // Можна читати значення об’єкта, на

                     // який посилається вказівник

}

Адресна арифметика

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

Операції присвоєння, порівняння та віднімання бінарні, обидва операнди цих операцій обов’язково повинні бути вказівниками або адресними виразами з однаковим базовим типом. Операції збільшення чи зменшення значень вказівників можуть бути як унарними (постфіксний або префіксний інкремент або декремент вказівника) і бінарними – збільшення (зменшення) значення вказівника на задану цілочислову величину.

Приклад використання операції присвоєння значень вказівників:

 

#include <iostream>

using namespace std;

int main() {

int a = 5;

int * p1, * p2;

p1 = &a;

p2 = p1;

*p2 = 123;

cout << a << endl;

}

 

Над вказівниками (або адресними виразами) можна виконувати всі операції порівняння мови С++. Результатом виконання операції є величина логічного типу. Наприклад:

 

#include <iostream>

using namespace std;

int main() {

int a = 5, b = 5;

int * p1, * p2;

p1 = &a;

p2 = &b;

if (p1 == p2) // Порівнюємо значення вказівників

     cout << "p1 == p2" << endl;

else

     cout << "p1!= p2" << endl;

if (*p1 > *p2) // Порівнюємо значення, на які

                     // посилаються вказівники, тобто а і b

     cout << "a > b" << endl;

else

     cout << "a <= b" << endl;

}

 

До значення вказівника можна додавати (чи віднімати від нього) довільне ціле число. Результатом операції збільшення (зменшення) вказівника є нова адреса. Наприклад

 

#include <iostream>

using namespace std;

int main() {

int a[ 5 ] = { 1, 2, 3, 4, 5 };

int * p;

p = &a[ 0 ];    // Адреса першого елемента масиву

cout << *p << endl; // Виводимо перший елемент масиву

p++;            // Адреса другого елемента масиву

cout << *p << endl; // Виводимо другий елемент масиву

}

 

У попередньому прикладі при виконанні операції p++ значення вказівника буде збільшуватися на sizeof(базовий_тип), тобто sizeof(int). Після виконання операції інкремента вказівник буде посилатися на наступне ціле значення в пам'яті, тобто на наступний елемент масиву.

У загальному випадку, при збільшенні (зменшенні) значення вказівника на ціле число k фактично він буде змінюватися на k * sizeof(базовий_тип) і буде вказувати на інше значення базового типу в пам'яті. Таким чином, величина, яка додається до вказівника або віднімається нього завжди кратна розміру базового типу цього вказівника.

 

#include <iostream>

using namespace std;

int main() {

int a[ 5 ] = { 1, 2, 3, 4, 5 };

int * p;

p = &a[ 0 ];    // Адреса першого елемента масиву

cout << *p << endl; // Виводимо перший елемент масиву

p += 2;         // Адреса третього елемента масиву

cout << *p << endl; // Виводимо третій елемент масиву

}

 

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

 

#include <iostream>

using namespace std;

int main() {

int a[ 5 ] = { 1, 2, 3, 4, 5 };

int * p1, * p2;

p1 = & a[ 0 ];  // Адреса першого елемента масиву

p2 = & a[ 4 ];  // Адреса останнього елемента масиву

cout << p2 - p1;     // 4 елемента: 0-й, 1-й, 2-й, 3-й

}

 

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

 

#include <iostream>

using namespace std;

int main() {

int a[ 5 ] = { 1, 2, 3, 4, 5 };

int * p;

p = & a[ 0 ];   // Адреса першого елемента масиву

cout << *(p + 3); // Виводимо 4-й елемент масиву

}

 

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



Поделиться:


Последнее изменение этой страницы: 2021-12-15; просмотров: 64; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.191.216.163 (0.015 с.)