Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Функции динамического распределения памяти




Для динамического распределения памяти используются операторы new и delete, но кроме этого, существуют специализированные библиотеки функций (Таблица 3). Их прототипы содержатся в файлах alloc.h и stdlib.h.

Таблица 3. Функции динамического распределения памяти

Функция Краткое описание
calloc void *calloc(size_t nitems, size_t size); выделяет память под nitems элементов по size байт и инициализирует ее нулями
malloc void *malloc(size_t size); выделяет память объемом size байт
realloc void *realloc (void *block, size_t size); пытается переразместить ранее выделенный блок памяти, изменив его размер на size
free void free(void *block); пытается освободить блок, полученный посредством функции calloc, malloc или realloc

Так как функции malloc() и calloc() возвращают нетипизированный указатель void *, то необходимо выполнять его явное преобразование в указатель объявленного типа:

char *str = NULL; str = (char *) calloc(10, sizeof(char)); char *str; if ((str = (char *) malloc(10)) == NULL) { printf("Not enough memory to allocate buffer\n"); exit(1); } char *str; str = (char *) malloc(10); printf("String is %s\nAddress is %p\n", str, str); str = (char *) realloc(str, 20); printf("String is %s\nAddress is %p\n", str, str); free (str);

Функции calloc и malloc выделяют блоки памяти, функция malloc при этом выделяет заданное число байт, тогда как calloc выделяет и инициализирует нулями массив элементов заданного размера.

Задание случайного числа – функция rand()

Для работы со случайными числами применяются функции randomize (инициализирует генератор) и rand (генерирует число из диапазона от 0 до RAND_MAX) библиотеки stdlib.h. Для псевдослучайных чисел, не ограниченных RAND_MAX можно написать собственный макрос:

#define rndm(a, b) (rand()%b-a)+a // Генерирует псевдослучайное число между a и b.

Лабораторная работа № 3. Указатели.

Продолжительность – 4 часа.

Максимальный рейтинг – 8 баллов.

Цель работы

Научиться работать со статическими и динамическими переменными. Освоить применение операций адресации и разадресации. Научиться выделять память под динамические переменные и освобождать ее при помощи операторов new и delete. Освоить обращение к динамическим объектам. Научиться выделять память под динамические переменные и освобождать ее при помощи функций calloc, malloc и free. Научиться визуализировать адреса статических и динамических объектов. Освоить функции randomize() и rand() генерирующие случайные числа.

Задание на лабораторную работу

1. Задать статическую переменную Х заданного типа (Таблица 4) и присвоить ей случайное значение. Задать переменную-указатель XPtr и присвоить ей адрес переменной Х. Задать указатель YPtr и присвоить ему адрес выделенной (оператором new) ячейки динамической памяти заданного типа, присвоить ей адрес переменной Х. Присвоить содержимому этой ячейки случайное значение.

2. Вывести на экран адреса указателей и значения переменных, на которые они указывают. Удалить динамическую переменную.

3. Увеличить на 1 значение указателя XPtr, вычислить, на сколько байт изменился адрес, сравнить его с размером sizeof() заданного типа.

4. Задать две динамические переменные APtr и BPtr при помощи функций calloc и malloc. Присвоить им случайные значения. Задать нетипизированный указатель VPtr и c его помощью поменять местами значения переменных APtr и BPtr.

5. Вывести на экран адреса указателей и значения переменных, на которые они указывают. Удалить динамические переменные.

Таблица 4. Варианты индивидуальных заданий

Тип переменной Х Диапазон случайного значения rand() Тип переменных APtr и BPtr
1. double -327.3*1034 … 435.6*1034 int
2. float -327.3 … 435.6 unsigned int
3. long double -1*10318 … 1*10318 long
4. int -300 … 300 double
5. unsigned int 12 … 1200 long double
6. long -456789 … 987654 float
7. unsigned long 1 … 32456789 double
8. double -567.3*1087 … 678.5*1087 long
9. float -234.5 … 543.2 int
10. long double -5*10321 … 5*10123 unsigned int
11. int -10 … 10 float
12. unsigned int 0 … 100 double
13. long -987654 … 123456 float
14. unsigned long 1 … 1092837465 double
15. double -555.5*1055 … 444.4*1044 unsigned int
16. float -0.3 … 0.3 long
17. long double 1*10-18 … 2*10-18 int
18. int -100 … 100 float
19. unsigned int 1 … 5 double
20. long 1 … 10 float

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

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

Описать функцию (описать заголовок, прототип функции) – означает определить ее имя, тип_возвращаемого_значения и список_формальных_параметров, записываемых через запятую (строка 1 листинга).

Задать функцию – значит, помимо описания заголовка, задать и все команды тела функции (строки 7‑12 листинга). Если функция не должна возвращать никакого значения, то тип_возвращаемого_значения нужно задать как void, иначе в теле функции должен присутствовать оператор return, возвращающий значение соответствующего типа (строка 11 листинга).

12 3 4 5 67 8 9 10 11 12 тип_возвращаемого_значения имя(список_формальных_параметров); // прототипmain() {... x = имя(список_фактических_параметров); // вызов функции... }// задание функции тип_возвращаемого_значения имя(список_формальных_параметров) { тело функции... return возвращаемое_значение; }

После того, как функция имя() описана и задана, она может быть вызвана из тела главной функции main() или других функций программы. Та точка основной программы, в которой была вызвана функция, называется точка вызова (или точка возврата) – выполнение основной программы в этой точке приостанавливается (прерывается) и выполняется тело_функции, по завершению работы функции возвращаемое_значение передается в точку возврата, после чего выполнение основной программы будет продолжено. В нашем листинге точка возврата находится в 4 строке после символов "x =".

Важным является следующий момент: при вызове функции вместо формальных параметров, данных в описании и задании функции, будут подставлены фактические значения этих параметров и выполнение тела функции будет производиться над фактическими значениями переменных. Естественно, типы переменных из списков формальных и фактических параметров должны совпадать. Собственно, имена переменных в списке формальных параметров не важны, их можно не указывать – как в примере ниже.

Рассмотрим программу, печатающую степени числа 2:

float pow(float, int); // прототип функции, которая задана в другом месте main() { for (int i=0; i<10; i++) cout << pow(2,i) << "\n"; // вызов функции }

Первая строка функции – ее прототип (описание), указывающее, что pow – функция, получающая параметры типа float и int и возвращающая float. Прототип функции используется для того, чтобы сделать определенными обращения к функции в других местах.

При вызове функции тип каждого параметра сопоставляется с ожидаемым типом точно так же, как если бы инициализировалась переменная описанного типа. Это гарантирует надлежащую проверку и преобразование типов. Например, обращение pow(12.3,"abcd") вызовет недовольство компилятора, поскольку "abcd" является строкой, а не int. При вызове pow(2,i) компилятор производит неявное преобразование 2 к типу float, как того требует функция. Функция pow может быть определена так:

float pow(float x, int n) // задание функции pow() { if (n < 0) error("\nsorry, negative exponent to pow()\n"); // извините, отрицательный показатель для pow() switch (n) { case 0: return 1; // выход из рекурсии case 1: return x; default: return x*pow(x,n-1); // рекурсия } }

Первая часть определения функции задает имя функции, тип возвращаемого ею значения (если таковое имеется) и типы и имена ее параметров (если они есть). Значение возвращается из функции с помощью оператора return.

Если функция не возвращает значения, то ее следует описать как void:

void swap(int* p, int* q) // поменять местами { int t = *p; *p = *q; *q = t; }

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

#include <iostream> using namespace std; void outto5(int n) { for (int i=0; i<n; i++) if (i==5) return; // даже если n>5, выводиться будут числа до 5 else cout << i << " "; } int sumab(int a, int b) { return a+b; } int main() { outto5(10); cout<<"сумма 3 и 4 = "<<sumab(3,4)<<endl; return 0; cout << "...не важно, что..."; // эта часть кода никогда не выполнится }
Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...