Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
программирование билеты-ответы.doc
Скачиваний:
16
Добавлен:
24.09.2019
Размер:
113.15 Кб
Скачать

12. Статическая, автоматическая и динамическая память. Создание и удаление динамических объектов. Типичные ошибки, воникающие при использовании динамической памяти.( « учётка памяти»)

В C++ разработчику доступно три вида памяти:

  1. статическая или глобальная – в неё попадают глобальные переменные, объявленные вне каких-либо блоков, а также статические переменные, перед объявлением которых указывался модификатор static (мы их пока не использовали, поскольку их основная особенность в том, что они сохраняют свои значения между вызовами тех функций, где к ним обращаются).

  2. стековая или локальная – выделяется внутри блоков для тех элементов, которые в этих блоках объявляются. Очищение локальной памяти происходит при выходе из блока. В отличие от статической, которая выделяется при запуске программы и освобождается при её завершении.

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

Только динамическая память может явно освобождаться с помощью команд, а не за счёт структуры программы. Это позволяет обрабатывать в программе большие наборы данных, своевременно освобождая память от промежуточных результатов.

Обращение к динамической памяти возможно только через указатели. Её использование оправдано, в первую очередь, при работе с большими массивами.

int *p;

p = new int; // создание

*p = 13;

cout << *p;

delete p; // удаление

При удалении элемента из динамической памяти не происходит её очистка, перезапись нулями или что-то подобное, размещённые там значения остаются, но помечаются как свободные участки памяти, т.е. они в любой момент могут быть перезаписаны нашей или какой-то другой программой.

Пример создания динамического массива:

int *p;

p = new int[13];

int *s;

s = p;

for(int i = 1; i < 13; i++){

*s = rand()%10;

cout << *s << ‘ ‘;

}

delete [] p;

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

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

Пример 1:

int *p;

p = new int[100];

int a = 5;

p = &a;

delete [] p; // ошибка, потому что p смотрит не на динамическую память

Пример 2:

int *p;

for (int i=1; i <= 5; i++){

p = new int[10];

}

delete [] p;

int *p;

int a=25;

p=&a;

if(a>10){ int*p;

p=new int[150];

}

Delete[]p; // ошибка

При попытке освобождения памяти окажется что мы обращаемся к указателю р, который направлен не на динамический диапазон из 150 элементов, а на обычную переменную а. её удалить из памяти мы не можем она хранится в статической памяти. При этом динамический массив в момент окончания блока условного оператора будет потерян в памяти( произойдёт утечка).

13. Функции в С++. Прототип и описание функции. Формальные и фактические параметры.

Функции в C++

Подпрограммой называется именованная группа операторов, решающая какую-то конкретную задачу. Эту подпрограмму повторно можно запускать несколько раз, обращаясь к ней по имени из разных мест основной программы.

Чтобы подпрограмма могла выполнять не только одинаковые, но и однотипные действия (например, чтобы выводить размер не только с именем n, но и любой массив имя и размер которые нам известны) используется, так называемые, параметры или аргументы подпрограмм, которые в момент вызова указывают в подпрограмме, с какими элементами из основной программы она должна работать.

Среди подпрограмм выделяют процедуры и функции. Те и другие могут выполнять самые разные операции над элементами основной программы, но функции в результате своей работы в то место, откуда были вызваны, также возвращают значения конкретного типа (число, ссылку на массив и т.д.). Функция, не возвращающая значения – процедура.

Объявление функции должно происходить до её первого использования, а описание может располагаться где угодно.

Итак, конкретизируем понятие функции:

Функция — это определенная группа операций с уникальным именем, которая может:

Вызываться по имени в любом месте программы.

Получать определенный набор значений из внешней программы в момент вызова.

Возвращать в качестве значения некоторый результат заранее заданного типа.

int proiz (int, int);

int main (void){

int a = 5;

int b = 8;

cout << proiz (a, b); // 40

return 0;

}

int proiz (int x, int y){

int t = x * y;

return t;

};

Создание функции

До того, как функция будет вызвана, она должна быть объявлена.

Объявление функции, аналогично объявлению переменной, указываются имя функции, тип значения, которое она может возвращать, набор её параметров (для каждого параметра задаётся тип и, при желании, имя).

Объявление функции называют также её прототипом.

Схема:

Тип_результата Имя_функции (Тип_пар1, Тип_пар2, ...);

Тип_результата — некоторый существующий (например, встроенный) тип данных или ключевое слово void, указывающее на то что функция никакого значения возвращать не будет.

Имя_функции — уникальный для данного пространства имён идентификатор.

Тип_парN — некоторый существующий (например, встроенный) тип данных для N-oro аргумента.

Примеры:

int max (int, int);

double cube (double)

float massa();

void printarr(*int, int);

Перечислим основные элементы описания функций:

  1. Указывается тип возвращаемого значения. Если создаём не функцию, а процедуру, то вместо типа пишем слово void.

  2. Задаём уникальное имя для функции. В программе не должно быть других элементов с таким же именем.

  3. В круглых скобках перечисляются формальные параметры функции через запятую. Для каждого из параметров указывается его тип, а также имя, под которым он будет виден внутри функции. Если предполагается, что у функции совсем не будет параметров, то круглые скобки оставляются пустыми, либо в них пишется слово void.

  4. Далее следует блок, внутри которого перечисляются все действия, что должна выполнить функция. Из функции можно обращаться ко всем доступным переменным программы, но делать этого не рекомендуется, поскольку в этом случае функция становится непереносимой. Блок с операциями называется телом функции.

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

Формальные и фактические параметры

Формальные параметры существуют в прототипе и теле определения функции. Они задаются некоторыми уникальными именами и внутри функции доступны как локальные переменные.

Фактические параметры существуют в основной программе. Они указываются при вызове функции на месте формальных.

В момент вызова функции значения фактических параметров присваиваются формальным. Соответственно, имена формальных и фактических параметров могут совпадать, это не вызовет конфликта.

Пример:

int n = -25; // глобальная переменная

int modul (int n) { // n - формальный параметр

if(n<0) n = -1 * n; // n будет перекрывать глобальную переменную с именем n

return n;

}

int main(void) {

cout << modul(n); // 25, значение глобальной переменной n будет передано в функцию

cout << n; // -25, но работа внутри функции пойдёт с локальной переменной n

return 0;

}

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