Теоретична частина. Вказівник- це змінна, в якій зберігається адреса іншого об’єкта

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

Змінна, що зберігає адресу комірки пам’яті, має бути оголошена як вказівник. Оголошення вказівника складається з імені базового типу, символу * і імені змінної. Загальна форма виглядає наступним чином:

int *p;

 

Базовий тип вказівника визначається базовим типом змінної, на яку він посилається.

Існує два спеціальні оператори роботи з вказівниками –це оператор розіменування вказівника * і оператор взяття адреси &. Оператор & є унарним і повертає адресу свого операнда. Наприклад, оператор присвоєння

А=&c

записує у вказівник адресу змінної с. Ця адреса відноситься до комірки пам’яті, яку займає с. Адреса і значення змінної в жоден спосіб не пов’язані.

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

Пріоритет операцій * і & вищий за пріоритет всіх арифметичних операцій, за винятком унарного мінуса.

Якщо адреса займає декілька комірок пам’яті , її адресою вважається адреса першої комірки.

Необхідно слідкувати за тим, що вказівник посилається на змінну правильного типу. Розглянемо приклад ( в результат виконання програми змінній у мало бути присвоєно значення змінної х)

#include <stdio.h>

 

int main(void)

{

double x = 100.1, y;

int *p;

p = (int *) &x; /* Вказівник цілого типу р посилається на змінну подвійної точності

y = *p;/Оператор працює не так, як вимагалося

printf("%f", y);.Число 100.1 не виводиться

return 0;

}

Вказівник можна присвоїти іншому вказівнику.

Приклад

#include <stdio.h>

 

int main(void)

{

int x;

int *p1, *p2;

p1 = &x;

p2 = p1;

printf(" %p", p2); /* Виводить адресу змінної х, не її значення */

return 0;

}

У прикладі на змінну х посилаються обидва вказівника р1 і р2.

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

До вказівників можна застосовувати операції порівняння. Як правило, це робиться тоді, коли вказівними посилаються на той самий об’єкт, наприклад, масив. Розглянемо в якості прикладу пару функцій для роботи зі стеками, в які записують і з яких зчитують цілі числа. Стек-це список, доступ до елементів якого здійснюється за принципом „першим увійшов-останнім вийшов”. Стеки використовуються в компіляторах, інтерпретаторах, програмах обробки електронних таблиць. Щоб створити стек, необхідні дві функції push () і pop ().

Функція push () заносить числа в стек, а функція рор() видобуває їх звідтам. У наведеній нижче програмі вони керуються функцією . При вводі числа з клавіатури програма заносить його в стек. Якщо користувач ввів 0, значення видобувається зі стеку. Програма припинить роботу при введенні -1.

#include <stdio.h>

#include <stdlib.h>

 

#define SIZE 50

 

void push(int i);

int pop(void);

 

int *tos, *p1, stack[SIZE];

 

int main(void)

{

int value;

 

tos = stack; /* tos вказує на вершину стеку */

p1 = stack; /* Ініціалізація p1 */

 

do {

printf("Enter value: ");

scanf("%d", &value);

if(value!=0) push(value);

else printf("value on top is %d\n", pop());

} while(value!=-1);

 

return 0;

}

 

void push(int i)

{

p1++;

if(p1==(tos+SIZE)) {

printf("Stack Overflow.\n");

exit(1);

}

*p1 = i;

}

 

int pop(void)

{

if(p1==tos) {

printf("Stack Underflow.\n");

exit(1);

}

p1--;

return *(p1+1);

}

Як бачимо, стек реалізовано у вигляді масиву stack. Спочатку вказівними pi і tos посилаються на перший елемент стека. Потім вказівник рі починає переміщуватись по стеку, а tos зберігає значення вершини. Це дозволяє запобігти переповненню стека і звертанню до порожнього стека. Функції push () і pop () можна застосовувати відразу після ініціалізації стека. У кожній з них виконується перевірка, чи не вийшов вказівник за межі допустимого діапазону значень.

Вказівники і масиви тісно пов язані між собою. Розглянемо приклад:

char str[80], *p1;

p1 = str;

Тут вказівнику р1 присвоєна адреса першого елементу масиву. Щоб отримати доступ до 5-го елементу масиву, треба виконати один з двох операторів

str[4] або

*(p1+4)

Як і звичайні змінні, вказівники можна розміщати в масивах. Оголошення масиву, що складається з 10 змінних, виглядає наступним чином

int *x[10];

Щоб присвоїти адресу цілочисельної змінної var третьому елементу масиву вказівників, виконуємо оператор

x[2]=&var;

Щоб видобути значення змінної використовуючи вказівник розіменування

*x[2]

Масив вказівників передається у функцію в звичайний спосіб-достатньо вказати його ім’я в якості аргументу.

Приклад

void display_array(int *q[])

int t;

for(t=0; t<10; t++)

 

printf("%d ", *q[t]);

 

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

Приклад

#include <stdio.h>

int main(void) {

int x, *p, **q;

x = 10;

P = &x;

q = &p;

printf("%d", **q) //вивід числа х

Незважаючи на те, що функція не є змінною, вона також розташовується в пам’яті, і як наслідок, її адресу можна присвоювати вказівнику. Ця адреса вважається точкою входу в функцію. Саме вона використовується при її виклику. Це дозволяє також передавати функції в якості аргументів іншим функціям.

Будь-яка змінна є іменованою областю пам’яті, яка резервується під час компіляції, а вказівники служать лише псевдонімами для областей пам’яті, до яких в разі потреби можна звернутись просто по імені. Справжня цінність вказівників виявляється тоді, коли для зберігання даних в процесі виконання програми виділяється неіменована область пам’яті. У цьому випадку вказівники є єдиним засобом доступу до цієї пам’яті. У С++ є два способи виділити пам'ять: з допомогою бібліотечної функції malloc або з допомогою оператора new

Прототип функції виглядає наступним чином

void *malloc(size_t кількість байтів)

Наприклад

char *p;

р= malloc(lOOO); /*виділити 1000 байт *

або

int *p;

*p=(int*)malloc(50*sizeof(int));.виділити память під 50 цілих чисел

Функція free є протилежністю malloc –вона звільняє раніше зайняту динамічну область пам’яті. Прототип функції виглядає наступним чином

void free(void *p)

Синтаксис використання оператора new

int *p=new int

Вираз new int повідомляє програмі, що необхідна нова область для збереження даних типу int. Оператор new аналізує тип, щоб знати, скільки байт необхідно виділити. Потім він відшукує область пам’яті і повертає адресу. Далі адреса присвоюється змінній р, яка оголошується вказівником на тип int. Тепер р є адресою, а *р –значенням, що зберігається за цією адресою.

Звільнити зарезервований блок пам’яті можна з допомогою оператора delete

delete *p;

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

 








Дата добавления: 2015-07-24; просмотров: 1544;


Поиск по сайту:

При помощи поиска вы сможете найти нужную вам информацию.

Поделитесь с друзьями:

Если вам перенёс пользу информационный материал, или помог в учебе – поделитесь этим сайтом с друзьями и знакомыми.
helpiks.org - Хелпикс.Орг - 2014-2024 год. Материал сайта представляется для ознакомительного и учебного использования. | Поддержка
Генерация страницы за: 0.015 сек.