Партнерка на США и Канаду по недвижимости, выплаты в крипто
- 30% recurring commission
- Выплаты в USDT
- Вывод каждую неделю
- Комиссия до 5 лет за каждого referral
Лабораторна робота № 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(), (заголовний файл <mem. h>), яку необхідно попередньо включити в програму директивою # include. Ці функції при наступних виділеннях пам'яті запобігають конфлікти між покажчиками.
Формат використання даної функції:
<покажчик> = (<тип_покажчика>*) malloc (<розмір_виділюваної_пам'яті_байт>);
Покажчик на один тип може бути перетворений у покажчик на інший тип. При цьому забезпечується можливість перетворення покажчика на об'єкт даного розміру в покажчик на об'єкт меншого розміру в покажчик на об'єкт меншого розміру і зворотного без змін.
Наприклад, функція динамічного розподілу пам'яті може сприймати розмір (у байтах) об'єкта, для якого виділяється пам'ять, і повертати покажчик на тип void
double*dp;
d = (double*) malloc (sizeof(double)); // функція malloc () виділяє пам'ять
free dp: *dp = 22. / 7.0 // звільнення динамічних виділень пам'яті.
При використанні функції забезпечується перетворення значення, що повертається, з покажчика на тип void у покажчик на тип double.
Приклад
/* ЗАНЯТТЯ N 8
Виконав студент групи.........
Застосування покажчиків при роботі з перемінними
різних типів, зміна значень перемінних за адресою
і по посиланню. Приклади операцій з покажчиками */
#include <stdio. h>
#include <conio. h>
#include <string. h>
#include <alloc. h>
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 (через пробіл):
Виведення результатів розрахунку *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.|3.e+01| +35.4|
*/
Приклад програми на С++
Привласнити раз іменованому покажчику на тип Р1 значення арифметичного вираження АВ, яке включає покажчики на типи Р2 і Р3. Арифметичне вираження реалізувати у виді функції, яка повертає покажчик на тип Р1. Вивести на екран значення покажчика Р2 і значення на який він посилається. Індивідуальні завдання взяти з таблиці 8.1.
Варіант | Р1 | АВ | Р2 | Р3 |
long | sin(p2)/tan(p3) | int | float |
#include<iostream. h>
#include<math. h>
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: "<<P2<<"\nЗначение данного P2: "<<*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-( | 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.Як здійснити приведення типу покажчика? Поясните приклади, приведені в теоретичній частині.


