Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
47
Добавлен:
12.02.2016
Размер:
147.46 Кб
Скачать

Міністерство освіти і науки україни

Національний університет “Львівська політехніка”

ДИНАМІЧНЕ ВИДІЛЕННЯ ПАМЯТІ

ІНСТРУКЦІЯ

до лабораторної роботи № 12 з курсу

“Основи програмування”

для базового напрямку “Програмна інженерія”

Затверджено

На засіданні кафедри

програмного забезпечення

Протокол № від

ЛЬВІВ – 2011

1. МЕТА РОБОТИ

Мета роботи – навчитися створювати нові типи даних у вигляді структур та об’єднань, а також розробляти алгоритми їх обробки засобами мови С++.

2. ТЕОРЕТИЧНІ ВІДОМОСТІ

2.1 Динамічні змінні

Бувають ситуації, коли заздалегідь невідомо, скільки даних потрібно обробити у програмі. Особливо це стосується роботи з масивами – при оголошенні статичного масиву для нього виділяється жорстко фіксована пам’ять. Однак, подекуди ця жорстко фіксована кількість елементів масиву може перевищувати реальну кількість даних або ж навпаки – бути недостатньою. Якщо масив не може вмістити потрібну кількість даних, доведеться переписувати і повторно компілювати програму. Один з типових підходів при використанні статичних масивів – виділити пам’ять з запасом, а заповнити даними лише частину масиву і в якійсь змінній зберігати фактичну кількість елементів масиву. У цьому випадку виділена пам’ять використовується неефективно. Крім того, статичні змінні “живуть” визначений час – або до кінця роботи програми, або до кінця її певного блока. Взагалі кажучи, часто статична змінна вже не є потрібною, а все ще займає пам’ять.

У С++ існує можливість динамічно розподіляти пам’ять у ході виконання програми, тобто, виділяти стільки пам’яті, скільки її насправді потрібно, і звільнити її тоді, коли вона вже не буде потрібною. Пам’ять виділяється з так званої вільної пам’яті. Розмір вільної пам’яті залежить від операційної системи та моделі пам’яті комп’ютера. Динамічні змінні не мають імен, а доступ до них здійснюється через вказівники. Динамічні об’єкти розміщаються у “кучі” (англомовний термін-відповідник: heap). Для управління вільною пам’яттю у С++ використовуються пара операторів new та delete та “успадкований” від мови С набір функцій malloc(), calloc(), realloc() та free().

2.2 Використання операторів new та delete

Оператор new у С++ дозволяє виділити потрібну кількість пам’яті. В якості операнда new використовує ім’я типу. Якщо пам’ять буде успішно виділена, то new поверне вказівник на початок виділеної ділянки пам’яті, а інакше new поверне значення NULL. Доброю практикою є пересвідчитися, чи результат new не дорівнює NULL, замість одразу звертатися до пам’яті, припускаючи, що вона була успішно виділена. Вказівник слід оголошувати відповідного типу.

Наприклад:

char* p = new char; /* створення динамічної змінної розміром, визначеним типом char, тобто, розміром в 1 байт */ int* p = new int; /* створення динамічної змінної розміром, визначеним типом int */

char* p = new char[100]; /* створення масиву розміром у 100 змінних типу char */

int* p = new int[100]; /* створення масиву розміром 100 змінних типу int */

struct student{

char surname[50];

char name[50];

int mark;

};

int k = 10;

student * p = new student[k]; /* створення масиву розміром у k змінних типу student; k є саме змінною, а не константою, що було б недопустимо при створенні статичного масиву */

Звільнення пам’яті здійснюється оператором delete:

delete p; /* де p є вказівником на початок раніше виділеної області пам’яті */

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

#include "stdafx.h"

#include <iostream>

#include "conio.h"

using namespace std;

int main() {

int N;

cout<<"Haw many items does our array contain?"<<endl;

cin>>N;

int * pp = new int[N];

int *p = pp; /* за допомогою вказівника p будемо переміщатися по динамічному масиву, тоді як вказівник pp лишимо незмінним – він буде вказувати на початок блока пам'яті */

if(p) { /* якщо пам'ять була успішно виділена */

for (int i=0;i<N; i++) { /* ввід N елементів масиву */

cout<<"Enter "<<(i+1)<<"-th item"<<endl;

cin>>*p;

p++;

}

p = pp + (N-1); /* встановлюємо вказівник p на останній елемент масиву та у циклі виводимо на екран всі N елементів масиву*/

for (int i=N;i>0; i--) {

cout<<*p<<endl;

p--;

}

delete pp;

}

_getch();

return 0;

}

З динамічним масивом можна працювати які зі звичайним масивом – через індекси:

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

#include "stdafx.h"

#include <iostream>

#include "conio.h"

using namespace std;

int main() {

int N;

cout<<"Haw many items does our array contain?"<<endl;

cin>>N;

int * p = new int[N];

if(p) {/* якщо пам'ять була успішно виділена */

for (int i=0;i<N; i++)

{ /* ввід N елементів масиву */

cout<<"Enter "<<(i+1)<<"-th item"<<endl;

cin>>p[i];

}

for (int i=N-1;i>=0; i--)

{

cout<<p[i]<<endl;

}

}

delete p;

_getch();

return 0;

}

Приклад. В наступній програмі резервується 100 елементів масиву типу int, а використовується лише стільки, скільки користувач задає з клавіатури – ввід припиняється, коли введено нечислові дані.

#include "stdafx.h"

#include <iostream>

#include "conio.h"

using namespace std;

int main()

{

int * pp = new int[100];

int * p = pp;

if(p) {

char str[10];

int i = 1;

p = pp+1;

while(i<100)

{

cout<<"Enter "<<i<<"-th item"<<endl;

cin>>str;

if(!atoi(str)) break;

else

{

*p = atoi(str);

p++;

i++;

}

}

*pp = i - 1;

if(*pp)

for (p = pp+1;p!=pp+*pp+1; p++)

{

cout<<*p<<endl;

}

}

delete pp;

_getch();

return 0;

}

Приклад. У динамічній пам’яті виділяється пам’ять для зберігання 100 екземплярів структур student. Полям екземплярів структур присвоюються значення, задані з клавіатури. Кожного разу користувачеві пропонується ввести прізвище наступного студента або ж слово ‘end’. Введені дані розцінюються як рядки символів, а в поле структури mark, що є цілим числом, записується результат функції atoi. Якщо введено нечислові дані, відбудеться вихід з циклу. Далі, усі екземпляри структур виводяться на екран у тому ж порядку, в якому вони були задані.

#include "stdafx.h"

#include <iostream>

#include "conio.h"

using namespace std;

int main()

{

struct student{

char surname[50];

char name[50];

int mark;

};

int N;

student * pp = new student[100]; /* виділяється фіксована ділянка динамічної пам’яті з запасом */

if(pp){ /* якщо пам'ять була успішно виділена */

student * p = pp; /* вказівником p переміщатимемося по динамічному масиву екземплярів структур */

char str[50];

int i = 1;

while(i<100)

{

cout<<"Enter the surname of "<<i<<"-th student or the word 'end'"<<endl;

cin>>str;

if(!strcmp(str,"end")) break; /* якщо користувач ввів слово ‘end’, відбувається вихід з циклу */

else /* інакше продовжуємо задавати інші поля того ж екземпляра структури */

{

strcpy(p->surname,str);

cout<<"Enter the name of "<<i<<"-th student"<<endl;

cin>>str;

strcpy(p->name,str);

cout<<"Enter the mark of "<<i<<"-th student"<<endl;

cin>>str;

if(atoi(str))

p->mark = atoi(str);

else break;

i++;

p++;

}

}

N = (i-1);

for(p=pp; p!=pp+N;p++)

{

cout<<p->surname<<"\t";

cout<<p->name<<"\t";

cout<<p->mark<<"\t";

cout<<endl;

}

}

delete pp;

_getch();

return 0;

}

Приклад. В наступній програмі передбачається заповнення полів екземплярів структур даними, зчитаними з текстового файлу (один рядок файлу містить дані для одного екземпляра структури, розділені знаками табуляції). Спочатку зчитується кількість рядків у файлі (файл відкривається для читання і зчитується по рядках, причому кожного разу спеціально оголошена змінна збільшується на 1). Після завершення читання файл закривається. Тоді в динамічній пам'яті виділяється область для зберігання стількох екземплярів структур, скільки рядків знайдено у текстовому файлі. Файл знову відкривається для читання – у циклі while поки не досягнуто кінець файлу на кожній ітерації зчитується один рядок. Кожен зчитаний рядок розділяється на окремі дані за допомогою функції strtok. Відокремлені дані записуються на кожній ітерації у відповідні поля поточного екземпляра структури у динамічній пам’яті (там, де це потрібно, виконується приведення типів).

#include "stdafx.h"

#include <iostream>

#include <fstream>

#include "conio.h"

using namespace std;

int main() {

struct student{

char surname[50];

char name[50];

int mark;

};

char strfromfile[200]; /* у цю змінну будемо зчитувати вміст файлу по рядках */

ifstream f1("student.txt");

int k = 0; /* у змінній k зберігатимемо кількість рядків у текстовому файлі student.txt */

while(!f1.eof())

{

f1.getline(strfromfile,200);

k++;

}

f1.close();/* закриваємо файл */

student * pp = new student[k]; /* виділяємо рівно стільки вільної пам’яті, скільки потрібно для створення масиву екземплярів структури student */

if(pp) { /* якщо пам'ять була успішно виділена */

student * p = pp;

char str[50];

int i = 1;

ifstream f2("student.txt"); /* знову відкриваємо файл student.txt для читання */

char *pw; /* вказівник для розділення зчитаних рядків на окремі дані */

while(!f2.eof()) /* поки не досягнутий кінець файлу */

{

f2.getline(strfromfile,200); /* читаємо поточний рядок у змінну strfromfile, припускаючи, що довжина кожного рядка файлу не перевищує 200 символів; на кожній ітерації циклу курсор посувається на одну позицію */

int j = 0;

pw = strtok(strfromfile, "\t"); /* дані розділяються за символами табуляції */

while(pw !=NULL)

{

switch(j) /* на кожній ітерації циклу while зі зчитаного текстового рядка виділяється одна певна частина даних, яка записується у відповідне поле структури */

{

case 0: strcpy(p->surname,pw);break;

case 1: strcpy(p->name,pw);break;

case 2: p->mark=atoi(pw);break;

}

pw = strtok (NULL, "\t");

j++;

}

p++;

}

/* вивід полів усіх структур на екран; поля однієї структури розділяються знаками табуляції, а різні екземпляри структури записуються в різних рядках */

for(p=pp; p!=pp+k; p++)

{

cout<<p->surname<<"\t";

cout<<p->name<<"\t";

cout<<p->mark<<"\t";

cout<<endl;

}

}

delete pp;

_getch();

return 0;

}

Соседние файлы в папке ОП (лаби) [1-13]