Чтение онлайн

ЖАНРЫ

Программирование. Принципы и практика использования C++ Исправленное издание
Шрифт:

Link* p = greek_gods–>find("Mars");

if (p) p–>value = "Ares";

Перенесем Зевса в список греческих богов.

Link* p2 = norse_gods–>find("Zeus");

if (p2) {

if (p2==norse_gods) norse_gods = p2–>next;

p2–>erase;

greek_gods = greek_gods–>insert(p2);

}

И

наконец, выведем список на печать.

void print_all(Link* p)

{

cout << "{ ";

while (p) {

cout << p–>value;

if (p=p–>next) cout << ", ";

}

cout << " }";

}

print_all(norse_gods);

cout<<"\n";

print_all(greek_gods);

cout<<"\n";

В итоге получим следующий результат:

{ Freia, Odin, Thor }

{ Zeus, Poseidon, Ares, Athena, Hera }

Какая из этих версий лучше: та, в которой функция

insert
и другие являются функциями-членами, или та, в которой они не принадлежат классу? В данном случае это не имеет значения, но вспомните, что было написано в разделе 9.7.5.

Следует отметить, что мы создали не класс списка, а только класс узла. В результате мы вынуждены следить за тем, какой указатель ссылается на первый элемент. Эти операции можно было бы сделать лучше, определив класс

List
, но структура класса, продемонстрированная выше, является общепринятой. Стандартный класс
list
рассматривается в разделе 20.4.

Задание

Это задание состоит из двух частей. Первые упражнения должны дать вам представление о динамических массивах и их отличии от класса

vector
.

1. Разместите в свободной памяти массив, состоящий из десяти чисел типа

int
, используя оператор
new
.

2. Выведите в поток

cout
значения десяти чисел типа
int
.

3. Освободите память, занятую массивом (используя оператор

delete[]
).

4. Напишите функцию

print_array10(ostream& os, int* a)
, выводящую в поток
os
значения из массива
a
(содержащего десять элементов).

5. Разместите в свободной памяти массив, состоящий из десяти чисел типа

int
; инициализируйте его значениями 100, 101, 102 и т.д.; выведите эти значения на печать.

6. Разместите в свободной памяти массив, состоящий из одиннадцати чисел типа

int
; инициализируйте его значениями 100, 101, 102 и т.д.; выведите эти значения на печать.

7. Напишите функцию

print_array(ostream& os, int* a, int n)
, выводящую в поток
os
значения массива
a
(содержащего n элементов).

8. Разместите в свободной памяти массив, состоящий

из двадцати чисел типа
int
; инициализируйте его значениями 100, 101, 102 и т.д.; выведите эти значения на печать.

9. Вы не забыли удалить массивы? (Если забыли, сделайте это сейчас.)

10. Выполните задания 5, 6 и 8, используя класс

vector
, а не массив, и функцию
print_vector
вместо функции
print_array
.

Вторая часть задания посвящена указателям и их связи с массивами. Используйте функцию

print_array
из последнего задания.

1. Разместите в свободной памяти переменную типа

int
, инициализируйте ее число 7 и присвойте ее адрес указателю
p1
.

2. Выведите на печать значения указателя

p1
и переменной типа
int
, на которую он ссылается.

3. Разместите в свободной памяти массив, состоящий из семи чисел типа

int
; инициализируйте его числами 1, 2, 4, 8 и т.д.; присвойте адрес массива указателю
p2
.

4. Выведите на печать значение указателя

p2
и массив, на который он ссылается.

5. Объявите указатель типа

int*
с именем
p3
и инициализируйте его значением указателя
p2
.

6. Присвойте указатель

p1
указателю
p2
.

7. Присвойте указатель

p3
указателю
p2
.

8. Выведите на печать значения указателей

p1
и
p2
, а также то, на что они ссылаются.

9. Освободите всю память, которую использовали.

10. Разместите в свободной памяти массив, состоящий из десяти чисел типа

int
; инициализируйте их числами 1, 2, 4, 8 и т.д.; присвойте его адрес указателю
p1
.

11. Разместите в свободной памяти массив, состоящий из десяти чисел типа

int
, присвойте его адрес указателю
p2
.

12. Скопируйте значения из массива, на который ссылается указатель

p1
, в массив, на который ссылается указатель
p2
.

13. Повторите задания 10–12, используя класс

vector
, а не массив.

Контрольные вопросы

1. Зачем нужны структуры данных с переменным количеством элементов?

2. Назовите четыре вида памяти, используемой в обычных программах.

3. Что такое свободная память? Как еще ее называют? Какие операторы работают со свободной памятью?

4. Что такое оператор разыменования и зачем он нужен?

5. Что такое адрес? Как язык С++ манипулирует с адресами?

6. Какую информацию об объекте несет указатель, который на него ссылается? Какую полезную информацию он теряет?

7. На что может ссылаться указатель?

8. Что такое утечка памяти?

9. Что такое ресурс?

10. Как инициализировать указатель?

11. Что такое нулевой указатель? Зачем он нужен?

12. Когда нужен указатель (а не ссылка или именованный объект)?

13. Что такое деструктор? Когда он нужен?

14. Зачем нужен виртуальный деструктор?

15. Как вызываются деструкторы членов класса?

16. Что такое приведение типов? Когда оно необходимо?

17. Как получить доступ к члену класса с помощью указателя?

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