asyan.org
добавить свой файл
1
Лабораторна робота № 20

Тема: Розробка програм з покажчиками

Ціль роботи: вивчити конструкції й оператори мови С++ для роботи з покажчиками.

Обладнання: ПК,ПО Borland C++
Теоретичні відомості

Самим могутнім інструментом у С, безумовно, є покажчики і для того, щоб опанувати програмуванням у З, необхідно опанувати умінням використовувати покажчики.

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

Розглянемо основні поняття і принципи роботи з покажчиками.

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

Синтаксис оголошення покажчиків:

тип*ім'я_покажчика.

Читається даний запис так:

ім'я_покажчика є покажчиком на тип. Символ «*» (зірочка) говорить про те, що дана перемінна є покажчик на заданий тип.

Приклад:

int * x; // x є покажчиком на тип int (ціле).

Таким чином, можна оголосити покажчик на будь-який тип: стандартний чи створений користувачем, у тому числі може бути оголошений покажчик на покажчик, на будь-який тип-void.

Покажчик на тип void сполучимо з будь-яким іншим покажчиком. Наприклад, припустимий запис:

int *x;

void *y;

y = x;

Розмір покажчика, тобто розмір ділянки пам'яті, відведеного під адресу, залежить від моделі пам'яті, у якій пишеться програма. Відзначимо їхню назву і вкажемо розмір покажчиків у байтах: малюсінька (2), маленька (2), середня (4), компактна (4), велика (4), величезна (4).

Для вказівки розміру покажчика використовують модифікатори: за замовчуванням near (2 байти), far (4 байти), huge (4 байти).

Покажчик може використовуватися як константний, котрий зв'язаний з однією постійною коміркою пам'яті:

float  const ptr; // константний покажчик

Покажчик може бути зв'язаний і з константами:

const float  ptr; // покажчик на константний тип

Можливо також наступне вираження:

сonst float сonst ptr; // константний покажчик на константний тип.
Основні операції з покажчиками

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

Приклад:

int*x; int d; // не плутати разадресуванням з зірочкою при оголошенні покажчика

int у = *х // у = 4;

У першому рядку перемінн-покажчику х привласнюється адреса, де зберігається значення перемінної d у другому рядку перемінної в привласнюється разіменоване значення покажчика х, тобто значення 4. Якщо першу операцію написати без адреси, тобто х = d х оголошений як int*x), то х буде вказувати на комірку пам'яті з адресою ??:4 (?? - у залежності від моделі пам'яті) і значення перемінної в буде дорівнює значенню, що зберігається по зазначеній адресі.

Операція визначення адреси & повертає адресу пам'яті свого операнда (перемінної, константи, функції і т.д.). Формат одержання адреси наступний:

адреса = & перемінна;
Приклад: int x, *y; y = &a; // покажчик y містить адреса х

Крім того, покажчики можна привласнювати один одному, якщо вони одного типу.
Приклад: int a, *x, *y; x =y;

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

char*a = "Slovo", c;

c = *(a+3); // c = 'v'

char*a, *b = "ABCDE";

a = b + 2; c = *(- - a;

char k = *a; int d = b-a)
Динамічне розміщення покажчиків у пам'яті
Щоб не викликати конфлікт в операційній чи системі не порушити роботу додатка, потрібно виділяти місце для зазначеного типу даних у припустимому просторі пам'яті, що називається «heap» чи «купа».

Виділення (якщо є можливість) пам'яті і присвоєння її адреси покажчику, по якому можна працювати з описаним типом здійснюється бібліотечною функцією malloc ( ) чи alloc(), (заголовний файл ), яку необхідно попередньо включити в програму директивою # include. Ці функції при наступних виділеннях пам'яті запобігають конфлікти між покажчиками.

Формат використання даної функції:

покажчик = (тип_покажчика*) malloc (розмір_виділюваної_пам'яті_байт);

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

Наприклад, функція динамічного розподілу пам'яті може сприймати розмір (у байтах) об'єкта, для якого виділяється пам'ять, і повертати покажчик на тип void

double*dp;

d = (double*) malloc (sizeof(double)); // функція malloc () виділяє пам'ять

free dp: *dp = 22. / 7.0 // звільнення динамічних виділень пам'яті.

При використанні функції забезпечується перетворення значення, що повертається, з покажчика на тип void у покажчик на тип double.

Приклад
/* ЗАНЯТТЯ N 8

Виконав студент групи ......... Петров Ю.В.

Застосування покажчиків при роботі з перемінними

різних типів, зміна значень перемінних за адресою

і по посиланню. Приклади операцій з покажчиками */
#include

#include

#include

#include

int a; //Оголошення глобальної перемінної типу int

int main(void)

{char c1,c2,buf[20]; //buf-покажчик на тип char

char *pc;

char *pst="\"slovo\"";//Оголошення покажчиків на тип char

int *pi= &a;

float *pf, f=26.6; //Оголошення покажчика на тип float

double *pd, d; //Оголошення покажчика на тип double

double &sd= d; //Оголошення посилання на тип double

void *pv; //Оголошення покажчика на тип void

char *pchar=(char *)malloc(20);//Виділення пам'яті в купі

clrscr(); // Оголошення функції void *malloc(size_t size);

pc=&c1; pf=&f; pd=&d;

printf(" Уведення перемінної c1 типу char: ");

scanf("%c",pc); //Функція введення даних, & - операція узяття

//адреси відсутня

printf(" Виведення перемінної c1 типу char: ");

printf("%c\n",*pc);

fflush(stdin);

pc=&c2;

printf(" Уведення перемінної c2 типи char: ");

scanf("%c",pc); //Функція введення даних, & - операція узяття

//адреси відсутня

printf("Виведення перемінної c2 типи char: ");

printf("%c\n",*pc);

printf("\n Уведення перемінної (a) типу int: ");

scanf("%d",pi);

a+=5; ++*pi; //Зміна а = а+5+1

printf(" \t Виведення (a) після зміни а=а+5+1\n");

printf(" Формат висновку (int): +6d #6o #8x\n");

printf("\t\t |%+6d|%#6o|%#8x|\n ",a,*pi,*pi);

printf("\n Виведення вихідного рядка: %s\n",pst);

pc=pst;

printf("Виведення рядка в циклі:\n");

while(*pc!='\0') { printf(" %s",pc); pc++; }

printf("\n Уведення рядка в масив: ");

scanf("%s",buf);

pv=buf; //Використання покажчика (pv) на тип void

printf("Виведення рядка з масиву: %s\n",(char *)pv); //pv -void

printf(" Уведення рядка в динамічну пам'ять: ");

scanf("%s",pchar);

printf("Виведення рядка з динамічної пам'яті: %s\n",pchar);

printf(" Уведення перемінних типу float and double (через пробіл):\n");

printf("\t\t ");

scanf("%f %lf",pf,pd);

pv=pf; //Використання покажчика (pv) на тип void

*pf=*(float *)pv*10; //f*=10;

*pd=sd+*(float *)pv; //Використання посилання (sd) на тип double

pv=pd; //d+=f;

printf("\t Виведення результатів розрахунку f*=10 d+=f\n");

printf(" Формат Виведення (float): 10.6f 10.6e +10.6g\n");

printf("\t\t |%10.6f|%10.6e|%+10.6g|\n",f,*pf,*pf);

printf(" Формат Виведення (double): 10.8lf 10.8e 10.8g\n");

printf("\t\t |%10.8lf|%10.8e|%+10.8g|\n ",*pd,*(double *)pv,sd);

getche();

return 0;

}

/* Уведення перемінної c1 типу char: w

Виведення перемінної c1 типу char: w

Уведення перемінної c2 типи char: t

Виведення перемінної c2 типи char: t
Уведення перемінної (a) типу int: 40

Виведення (a) після зміни а=а+5+1

Формат Виведення (int): +6d #6o #8x

| +46| 056| 0x2e|
Виведення вихідного рядка: "slovo"

Виведення рядка в циклі:

"slovo" slovo" lovo" ovo" vo" o" "

Уведення рядка в масив: unsigned

Виведення рядка з масиву: unsigned

Уведення рядка в динамічну пам'ять: dinamo

Виведення рядка з динамічної пам'яті: dinamo

Уведення перемінних типу float and double (через пробіл):

1.5 20.4

Виведення результатів розрахунку *pf=*pf*10; *pd=*pd+f;

Формат Виведення (float): 10.6f 10.6e +10.6g

| 15.000000|1.500000e+01| +15|

Формат Виведення (double): 10.8lf 10.8e 10.8g

|35.40000000|3.54000000e+01| +35.4|

*/
Приклад програми на С++

Привласнити раз іменованому покажчику на тип Р1 значення арифметичного вираження АВ, яке включає покажчики на типи Р2 і Р3. Арифметичне вираження реалізувати у виді функції, яка повертає покажчик на тип Р1. Вивести на екран значення покажчика Р2 і значення на який він посилається. Індивідуальні завдання взяти з таблиці 8.1.

Варіант

Р1

АВ

Р2

Р3




long

sin(p2)/tan(p3)

int

float


#include

#include

long int *AB(int i,float f);

void main()

{long z,*P1=&z;

int x,*P2=&x;

float y,*P3=&y;

*P2=2;

*P3=1.1;

*P1=*AB(*P2,*P3);

cout<<"P1="<<*P1<<"\n";

cout<<"Значение P2: "<

}

long int *AB(int i,float f)

{long a,*rezultat=&a;

*rezultat=sin(i)/tan(f);

return rezultat;

}
Хід роботи
1.Вивчити теоретичні відомості.

2.Відповідно до індивідуального завдання розробити алгоритм застосування покажчиків.

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

4.Набрати програму на комп'ютері й усунути помилки.

5.Одержати результат.

6.Оформити звіт і зробити Захист роботи по роботі.

7.Підготуватися до захисту лабораторної роботи, вивчивши контрольні питання по даній темі.
Індивідуальне завдання

Привласнити раз іменованому покажчику на тип Р1 значення арифметичного вираження АВ, яке включає покажчики на типи Р2 і Р3. Арифметичне вираження реалізувати у виді функції, яка повертає покажчик на тип Р1. Вивести на екран значення покажчика Р2 і значення на який він посилається. Індивідуальні завдання взяти з таблиці 8.1.

Таблиця 8.1 - індивідуальні завдання

Варіант

Р1

АВ

Р2

Р3




long

(1/sin((р2)2))р3

int

float




float

(abs(p3))1/p2

long

double




double

tan((p3)2)p2/3

int

long




float

(ln(p2)p3)p2

char

unsigned long int




long double

sin(abs(p3)p2)

double

long int




long

sin(p2)/tan(p3)

int

float




unsigned long int

(++p3)/(--p2)

short int

int




long double

((1+(++p2))/p3)p2

long int

float




signed long int

(sin(--p2)-(p3))p3

char

int




long int

(1/sin(p2))p3

unsigned long int

int




double

sin(p3)1/p2

double

float




double

cos(p2/p3)

int

double




int

(--p2)+(++p3)

unsigned int

short int




signed int

(sin(p2)/tan(p3))p3

short int

char




long double

ln(--p2)1/p3

float

double




double

1.2*(10-(
--p3))+p3

double

short int




double

tan((p3)2)p2/3

double

float




float

(ln(p2)p3)p2

int

double




long double

sin(abs(p3)p2)

unsigned int

short int




long double

((1+(++p2))/p3)p2

double

long int




signed long int

(sin(--p2)-(p3))p3

int

float




long int

(1/sin(p2))p3

short int

int




long double

sin(abs(p3)p2)

char

int




long

sin(p2)/tan(p3)

unsigned long int

int




double

sin(p3)1/p2

double

float




double

cos(p2/p3)

int

double




int

(--p2)+(++p3)

unsigned int

short int




long double

((1+(++p2))/p3)p2

short int

char




signed long int

(sin(--p2)-(p3))p3

float

double




long int

(1/sin(p2))p3

double

short int



Вимоги до змісту звіту приведені в лабораторній роботі №1.
Контрольні запитання

1.Дайте визначення покажчику.

2.Який синтаксис оголошення покажчика?

3.З якими модифікаторами може бути використаний покажчик?

4.Чим відрізняється (*) в оголошенні покажчика й у вираженні, де він використовується?

5.Що таке операція звертання за адресою?

6.Що таке операція узяття адреси?

7.Як би Ви привласнили адресу перемінної з крапкою, що плаває, salary покажчику з ім'ям pt_sal?

8.Чи обов'язково покажчик при його оголошенні?

9.У чому особливості використання покажчика на тип void?

10.Для чого застосовується константа NULL?

11.Що таке динамічне виділення пам'яті, де вона виділяється і за допомогою яких функцій?

12.Чи можна привласнювати покажчики одного типу?

13.Як здійснити приведення типу покажчика?Поясните приклади, приведені в теоретичній частині.