Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
maximum.docx
Скачиваний:
2
Добавлен:
24.04.2019
Размер:
33.9 Mб
Скачать

7.3. Краткие итоговые сведения

Отметим отличия и особенности хорошего стиля работы с рассмотренными циклическими операторами.

Цикл с предусловием

(пока условие истинно)

Цикл с постусловием

(до истинности условия)

  1. До начала цикла должны быть сделаны начальные установки переменных, управляющих условием цикла, для корректного входа в цикл

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

  1. Цикл работает пока условие истинно (пока True)

  1. Цикл работает пока условие ложно (пока False)

  1. Цикл завершается, когда условие становится ложным (до False)

  1. Цикл завершается, когда условие становится истинным (до True)

  1. Цикл может не выполниться ни разу, если исходное значение условия при входе в цикл False

  1. Цикл обязательно выполнится как минимум один раз

  1. Если в теле цикла требуется выполнить более одного оператора, то необходимо использовать составной оператор

  1. Независимо от количества операторов в теле цикла, использование составного оператора не требуется

Цикл со счетчиком (с параметром) For

  • Начальная установка переменной счетчика цикла до заголовка не требуется

  • Изменение в теле цикла значений переменных, стоящих в заголовке не допускается

  • Количество итераций цикла неизменно и точно определяется значениями нижней и верхней границ и шага приращения

  • Нормальный ход работы цикла может быть нарушен оператором goto или процедурами Break и Continue

  • Цикл может не выполниться ни разу, если шаг цикла будет изменять значение счетчика от нижней границы в направлении, противоположном верхней границе

32. Подпрограммы

См вопрос номер 20

33. Работа с динамическими переменными и указателями

34. Статические и динамические переменные. Основные ошибки при работе с динамическими переменными и указателями.

Ошибки при работе с динамическими переменными и указателями.

1. Утечка памяти

При использовании динамически распределяемых переменных часто возникает общая проблема, называемая утечкой динамической памяти. Утечка памяти – это ситуация, когда пространство выделяется в динамически распределяемой памяти и затем теряется – по каким-то причинам ваш указатель не указывает больше на распределенную область, так что вы не можете освободить пространство. Общей причиной утечек памяти является переприсваивание динамических переменных без освобождения предыдущих. Простейшим случаем является следующий (на Паскале):

var IntPointer :^ Integer;

begin

    New (IntPointer);

    New (IntPointer);

end.

При первом вызове New в динамически распределяемой памяти выделяется 2 байта, и на них устанавливается указатель IntPointer. Второй вызов New выделяет другие 2 байта, и IntPointer устанавливается на них. Теперь у вас нет указателя, ссылающегося на первые 2 байта, поэтому вы не можете их освободить. В программе эти байты будут потеряны. В итоге программе (а, зачастую, и вовсе даже не той, которая память бездумно «потребила») может просто не хватить памяти.

2. Несоответствие типов при присваивании указателей (только для С++)

Значение одного указателя можно присвоить другому. Если указатели одного типа, то один можно присваивать другому с помощью обычной операции присваивания (см. в теме «Типы переменных»).

Если указатели ссылаются на различные типы, то при присваивании значения одного указателя другому, необходимо использовать преобразование типов. Без преобразования можно присваивать любому указателю указатель void. Преобразование типов для статических переменных рассматривалось ранее (информацию высылала в электронном виде).

Рассмотрим примеры работы с указателями различных типов.

Пример №1

#include <iostream.h>

#include <math.h>

int main()

{ float PI=3.14159,*p1;

double *p2;

p1=&PI; //В переменную p1 записываем адрес PI

p2=(double *)p1; //указателю на double присваиваем значение, которое ссылается на тип float.

Cout<<"По адресу p1=”<<p1<<”хранится значение“<<*p1;

Cout<<"По адресу p2=”<<p2<<”хранится значение“<<*p2; }

Результатом этой программы будет:

По адресу p1=0012FF7C хранится 3.14159

По адресу p2=0012FF7C хранится 2.642140e-308

Почему? В указателях p1 и p2 хранится один и тот же адрес, но значения, на которые они ссылаются, оказываются разными. Это связано с тем, указатель типа *float адресует 4 байта, а указатель *double – 8 байт. После присваивания p2=(double *)p1; при обращении к *p2 происходит следующее: к переменной, хранящейся по адресу p1, дописывается еще 4 байта из памяти. Что в них хранится – неизвестно, а число разрядов, отводимых на смещенную экспоненту и мантиссу будет браться для типа double. В результате значение *p2 не совпадает со значением *p1.

Пример №2

#include <stdio.h>

#include <math.h>

int main()

{

double PI=3.14159,*p1;

float *p2;

p1=&PI;

p2=(float *)p1;

cout<<"По адресу p1=”<<p1<<” хранится значение ”<<*p1);

cout<<"По адресу p2=”<<p2<<” хранится значение ”<<*p2); }

После присваивания p2=(double *)p1; при обращении к *p2 происходит следующее: из переменной, хранящейся по адресу p1, выделяется  только 4 байта. В результате и в этом случае значение *p2 не совпадает со значением *p1.

ВЫВОД. При преобразовании указателей разного типа приведение типов разрешает только синтаксическую проблему присваивания. Следует помнить, что операция * над указателями различного типа, ссылающимися на один и тот же адрес, возвращает различные значения.

3. Неинициализированный указатель (для С++)

Каждый раз при работе с указателями необходимо выполнять их инициализацию, т.е. задавать адрес на выделенную область памяти. Так, в Паскале при объявлении переменной-указателя ей автоматически присваивается значение nil. В С++ при объявлении переменной-указателя они указывают на произвольную область памяти, с которой СРАЗУ можно работать как с обычной переменной.

Пример

int* ptr;

*ptr = 10;

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

35. Указатели. Применение указателей. Преобразование типов указателей.

См 33 вопрос.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]