Студопедия

КАТЕГОРИИ:

АстрономияБиологияГеографияДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРиторикаСоциологияСпортСтроительствоТехнологияФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника


Ініціалізація вказівок




Вказівки найчастіше використовують при роботі із динамічною пам'яттю, яка називається купою (heap). Це вільна пам'ять, в якій можна під час виконання програми виділяти місце відповідно до потреб. Доступ до виділених ділянок динамічної пам'яті, званих динамічними змінними, проводиться тільки через вказівки. Час життя динамічних змінних – від точки створення до кінця програми або до явного звільнення пам'яті. У C++ використовується два способи роботи з динамічною пам'яттю.

При визначенні вказівки треба прагнути виконати її ініціалізацію, тобто присвоєння початкового значення. Ненавмисне використання неініціалізованих вказівок призводить до помилок в програмах.

Існує п’ять засобів завдання початкового значення змінній-вказівці:

1. Описати вказівку поза будь-якою функцією або оголосити її як static. Початковим значенням є нульова адреса пам’яті – 0. Перед тим, як почати користуватися вказівкою, варто зарезервувати пам’ять під значення.

2. Привласнити вказівці адресу змінної.

3. Привласнити вказівці значення іншої вказівки, до цього моменту вже правильно ініціалізованної.

4. Використовувати оператори динамічного розподілу пам’яті, такі як new, deleteі delete[].

5. Привласнити значення конкретної адреси (константи), при цьому необхідно привести константу до типу вказівки.

Приклади ініціалізації вказівок:

 

int *p1;

 

void main()

{

static int *p2;

 

int s = 10;

int *p3 = &s;

//int *p3 (&s);

 

int *p4,*p5;

p4 = &s;

p5 = p4;

}

 

Присвоювання адреси змінної age вказівці p_age

 

int age=30;

int *p_age;

p_age=&age;

 

Можна ініціалізовувати під час оголошення:

 

int age=30;

int *p_age=&age;

 

Адреса Пам’ять
350606 /age/
 
350982 /p_age/

 

Для виведення значення змінної age можна використовувати 2 варіанта:

1) cout << age;

2) cout << *p_age;

Оператор * ставиться перед змінними вказівками тільки в двох випадках:

1. При оголошенні змінної-вказівки.

2. Для отримання значення, на яке вона вказує.

Після оголошення вказівки на конкретний тип об’єкта C++, спроба використання цієї вказівки для посилання на інший тип призведе до помилки:

 

void main()

{

int* k;

int j;

char c;

 

j = 5;

c = 'C';

k = &j; //це припустимо

k = &c; //це призведе до помилки

}

 

Існує спеціальний тип вказівки void* на об’єкти C++ будь-якого типу, що виключає помилки компілятора, що стосуються вказівок. Вказівки типу void* можна використовувати в будь-яких цілях:

 

void main()

{

void* k;

int j;

float f;

char c;

 

//тут усе правильно

k = &j;

k = &f;

k = &c;

}

 

Вказівки voidмають важливу властивість: типізована вказівка може бути привласнена вказівці void, але не навпаки. Щоб привласнити вказівку void типізованій вказівці, необхідно використовувати явне перетворення типів, інакше компілятор видає повідомлення про помилку:

 

void main()

{

void* vp;

int* ip;

int i = 5;

char* cp;

char c = 'A';

 

ip = &i; //правильно

vp = &i; //правильно

 

cp = &c; //правильно

vp = &c; //правильно

 

ip = vp; //цього робити неможна

cp = vp; //цього робити неможна

 

vp = ip; //правильно

vp = cp; //правильно

}

 

У C++ такі оператори, як new, delete і delete[], виділяють і звільняють блоки пам’яті в купі. Такий вид пам’яті звичайно називають динамічною пам’яттю, тому що вона створюється і знищується при виконанні програми.

Припустимо, необхідно виділити пам’ять для масиву з 10 цілих чисел. Для цього достатньо написати:

 

int* ip;

ip = new int[10];

 

або ще коротше:

 

int* ip = new int[10];

 

Даний код оголошує вказівку ip та ініціалізує її значенням, що повернуте new. Оператор new повертає вказівку на початок виділеного блока пам’яті.

Якщо виділяється пам’ять за допомогою оператора new, необхідно зазначити точний її обсяг. Цей обсяг зовсім необов’язково знати під час компіляції, але він повинен бути відомий під час виконання програми:

 

//Введення значення змінної

int n;

cin >> n;

//запитується блок пам’яті для збереження n цілих

int* ip = new int[n];

 

При запиті блоку пам’яті виділяється деякий обсяг пам’яті з глобальної купи. Обсяг розподіленого блоку трохи перевищує запитаний обсяг пам’яті, тому що потрібно ще зберігати додаткову інформацію, щоб адміністратор купи міг управляти блоками.

Оператор new поверне ненульову вказівку, навіть якщо запросити нуль байтів. При використанні вказівки, повернутої new, неминуче виникнення проблем, тому що для даного блоку пам’яті реально не виділено.

 

void main()

{

//буде повернута значуща вказівка!

int* ip = new int[0];

}

 

Оператор new дозволяє ініціалізувати зазначеним значенням динамічно виділені дані, як показано нижче:

 

//ініціалізація цілого значенням 10

int* value = new int(10);

 

Створивши в глобальній купі об’єкт, ви відповідаєте за його видалення. Ця операція для компілятора більш складна, ніж операція створення об’єкта. Чому? Роздивимося такий код:

 

int* ip = new int[10];

delete ip;

 

Скільки пам’яті буде звільнено за допомогою операції delete? Оператору new передається інформація про число типізованих елементів, для котрих необхідно виділити пам’ять. Оператор delete одержує тільки типізовану вказівку. У C++ адміністратор купи використовує вказівку для пошуку виділеного блоку пам’яті. Купа також містить додаткову інформацію, включаючи розмір кожного виділеного блоку. Використовуючи цю приховану інформацію, адміністратор може визначити, скільки звільнити пам’яті.

Для видалення масивів використовується оператор delete[]. Такий код показує його використання:

 

char* ср = new char[10];

delete[] ср;

 

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

Приклад п’ятого засобу завдання початкового значення вказівки. Виведення символу "A".

 

#include <iostream>

using namespace std;

 

void main()

{

char* c = (char*)0x003434A0;

*c = 'A';

cout<<*c;

}

 

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


Поделиться:

Дата добавления: 2014-12-30; просмотров: 198; Мы поможем в написании вашей работы!; Нарушение авторских прав





lektsii.com - Лекции.Ком - 2014-2024 год. (0.006 сек.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав
Главная страница Случайная страница Контакты