Скачать презентацию Язык Си Часть 4 ФУНКЦИИ ДИНАМИЧЕСКАЯ ПАМЯТЬ Скачать презентацию Язык Си Часть 4 ФУНКЦИИ ДИНАМИЧЕСКАЯ ПАМЯТЬ

SI_4_chast.pptx

  • Количество слайдов: 37

Язык Си. Часть 4 ФУНКЦИИ. ДИНАМИЧЕСКАЯ ПАМЯТЬ. Язык Си. Часть 4 ФУНКЦИИ. ДИНАМИЧЕСКАЯ ПАМЯТЬ.

Зачем нужны функции? 1. Структурирование программы – разбиение большой задачи на более мелкие части. Зачем нужны функции? 1. Структурирование программы – разбиение большой задачи на более мелкие части. 2. Использование уже написанного кем-то кода – стандартных и сторонних библиотек.

Прототип функции – это объявление функции, не содержащее тела функции, но указывающее имя функции, Прототип функции – это объявление функции, не содержащее тела функции, но указывающее имя функции, арность (количество аргументов), типы аргументов и возвращаемый тип данных. Шаблон прототипа функции: Тип_возвращаемого_значения имя_функции (тип_аргумента 1, тип аргумента 2, …); Прототип: int printf(const char *format[, argument, . . . ]); Использование: printf("hello, world"); /* функция вывода информации на экран*/

Оператор return выражениенеобяз. ; Предназначен для возврата результата выполнения функции. После его выполнения текущая Оператор return выражениенеобяз. ; Предназначен для возврата результата выполнения функции. После его выполнения текущая функция завершает свою работу и передает управление коду, вызвавшему функцию (в случае функции main() – операционной системе). Если функция ничего не возвращает, то оператор return не является обязательным. Пример1: void set_property(){операция 1; …} Пример2: int set_property(){операция 1; … return 0; }

Пример Задача: матрица 5*5 заполняется случайными целыми числами от 0 до 10. Вывести те Пример Задача: матрица 5*5 заполняется случайными целыми числами от 0 до 10. Вывести те строки матрицы, сумма чисел в которых не превышает 20. Алгоритм: Заполнить матрицу случайными числами //1 Вывести исходную матрицу //2 for(каждой строки матрицы) //3 if(сумма чисел в строке меньше 20) //4 Вывести строку //5

#include <stdio. h> Программа #include <stdlib. h> int get. Sum(int row[]); void print. Row(int #include Программа #include int get. Sum(int row[]); void print. Row(int row[]); int main(){ int array[5][5], i, j; for(i = 0; i< 5; i++) 1 for(j = 0; j<5; j++) array[i][j] = random(10); printf("Input matrix: n"); 2 for(i = 0; i< 5; i++) print. Row(array[i]); printf("Result matrix: n"); for(i = 0; i < 5; i++) 3 if(get. Sum(array[i]) <= 20) print. Row(array[i]); } 4 5

//Реализация функций int get. Sum(int row[]) { int i, sum = 0; for(i = //Реализация функций int get. Sum(int row[]) { int i, sum = 0; for(i = 0; i < 5; i++) sum += row[i]; return sum; } void print. Row(int row[]) { int i; for(i = 0; i < 5; i++) printf("%d ", row[i]); printf("n"); }

1. Вызывающий код может игнорировать возвращаемое функцией значение: 2. При объявлении и реализации функции 1. Вызывающий код может игнорировать возвращаемое функцией значение: 2. При объявлении и реализации функции в скобках записываются формальные параметры: double sin(double x); 3. При вызове в функции передаются фактические параметры или аргументы: double sin = sin(x); 4. Аргументы в функции передаются с помощью стека или регистров процессора.

Соответствие между формальными и фактическими параметрами: ➢ по типу, ➢ по порядку следования, ➢ Соответствие между формальными и фактическими параметрами: ➢ по типу, ➢ по порядку следования, ➢ по количеству float pow_int (float x, int n). . . z = pow_int( cos(y), 3 ); // Если: … (…, 3. 5), // то преобразование в int: 3

Передача аргументов в функцию В языке Си при вызове функции в нее передаются только Передача аргументов в функцию В языке Си при вызове функции в нее передаются только значения аргументов! Не существует способа изменить локальную переменную вызывающей функции, действуя внутри вызываемой функции. void change. A(int a); int main() { int a = 0; printf("%d ", a); change. A(a); printf("%d ", a); } void change. A(int a) { a++; } Значение а не изменится!

Передача указателя в функцию Функция, меняющая значения двух переменных местами void swap(int х, int Передача указателя в функцию Функция, меняющая значения двух переменных местами void swap(int х, int у) void swap(int *рх, int *py) /* НЕПРАВИЛЬНО */ /* обмен местами *рх и *ру */ { { int temp; temp = x; temp = *рх; x = у; *рх = *ру; у = temp; } int temp; *ру = temp; }

В функцию нужно передавать указатель, когда: 1. В функции нужно изменять значение переданных в В функцию нужно передавать указатель, когда: 1. В функции нужно изменять значение переданных в нее аргументов (функция swap()). 2. Когда из функции нужно возвращать более одного значения. /*функция для нахождения частного и остатка от деления remainder - остаток, quotient - частное, divider - делимое, divider - делитель*/ int get. Rem. And. Quotient(int dividend, int divider, int* remainder); int main() { int remainder, k = 10; int quotient = get. Rem. And. Quotient (k, 3, &remainder); printf("%d: 3=%d; %d%%3=%d", k, quotient, k, remainder); } int get. Rem. And. Quotient(int dividend, int divider, int * remainder) { *remainder = dividend % divider; return dividend / divider ; }

Передача массивов в функцию Одномерные статические массивы • fun ( int m[100], int n Передача массивов в функцию Одномерные статические массивы • fun ( int m[100], int n ); // плохо • fun ( int m[ ], int n ); // так себе • fun ( int *m, int n ); // хорошо При передаче одномерного массива в функцию через стек передается только указатель на 0 -ой элемент (весь массив в стек не копируется).

Двумерные статические массивы fun (int arr[10], int m, int n); fun (int arr[ ][10], Двумерные статические массивы fun (int arr[10], int m, int n); fun (int arr[ ][10], int m, int n); // + Количество столбцов указывать обязательно! void print. Array(int *arr, int n, int m); int main(){ int k[10], i, j; … print. Array(&k[0][0], 10); } void print. Array(int *arr, int n, int m) { for(int i = 0; i

Макрос NULL _null. h #ifndef NULL # if defined(__cplus) || defined(_Windows) # define NULL Макрос NULL _null. h #ifndef NULL # if defined(__cplus) || defined(_Windows) # define NULL 0 # else # define NULL ((void *)0) # endif #endif Используется для присваивания указателю нулевого значения. Для каждого типа указателей существует (согласно определению языка) особое значение - "нулевой указатель", которое отлично от всех других значений и не указывает на какой-либо объект или функцию. Тут можно почитать подробнее: http: //faqs. org. ru/progr/c_cpp/cfaqrus. htm

Динамическая память Динамическая память

Динамическая память (Дин. П) В тех случаях, когда необходимо обрабатывать большие объемы данных, не Динамическая память (Дин. П) В тех случаях, когда необходимо обрабатывать большие объемы данных, не помещающиеся в стек, либо когда при компиляции объем обрабатываемых данных неизвестен, память под данные необходимо выделять в процессе работы программы, т. е. динамически. Статические массивы (int array[10]) компилятор сам создает в стеке, так как они являются локальными переменными, динамические же массивы будут создаваться в куче (область динамической памяти), а управлять этой памятью должен программист. Основное правило: Вся выделенная «вручную» память должна быть освобождена как только она перестает быть нужной!

#include <stdlib. h> #include <stdio. h> int main() { int * ptr; //Указатель на #include #include int main() { int * ptr; //Указатель на начало блока памяти int i = 0, N = sizeof(*ptr) * 10; //Размер блока в байтах ptr = (int *)malloc(N); //Выделение памяти if (ptr == NULL) //Если функция malloc вернула NULL { printf("Memory fail!"); // Сообщить об ошибке … getch(); return 0; // … и выйти из программы } memset(ptr, 0, N); //Обнуление памяти for(i = 0; i< 10; i++) //Заполнение массива ptr[i] += i; for(i = 0; i< 10; i++) //Вывод массива printf("%d ", ptr[i]); getch(); free(ptr); //Освобождение памяти return 0; }

#include <stdlib. h> Выделение* Дин. П Пр-п: void * malloc(size_t size); Исп: ptr = #include Выделение* Дин. П Пр-п: void * malloc(size_t size); Исп: ptr = malloc(N); Тип size_t – целое неотрицательное число. Используется в качестве параметра там, где необходимо указание количества байт (размера блока). Для выделения динамической памяти используется функция malloc(). В нее передается число байт памяти, которые необходимо выделить в куче. Функция возвращает указатель на выделенный блок в случае успешного выделения, иначе – NULL. После использования функции malloc всегда проверять, успешно ли выделилась память! (проверять указатель на NULL). После выделения память всегда нужно инициализировать! *Предоставление

Инициализация Дин. П 1. С помощью функции memset() #include <string. h> Прототип: void *memset(void Инициализация Дин. П 1. С помощью функции memset() #include Прототип: void *memset(void *ptr, int c, size_t n); Инициализирует n первых байт блока памяти, на который указывает ptr значением c. Исп-е: memset(ptr, 0, N); 2. В цикле как массив элементов for(i = 0; i< 10; i++) ptr[i] = 0;

Выделение Дин. П - продолжение void *calloc(size_t n, size_t size); Выделяет память под n Выделение Дин. П - продолжение void *calloc(size_t n, size_t size); Выделяет память под n элементов по size байт каждый. Выделенная память будет обнулена. int * q = (int *) calloc(100, sizeof(int)); //q будет указывать на начало массива из 100 int’ов, инициализированных нулями. void *realloc(void *ptr, size_t size); Функция изменяет размер выделенной памяти (на которую указывает ptr, полученный из вызова malloc, calloc или realloc). Если размер, указанный в параметре size больше, чем тот, который был выделен под указатель ptr, то проверяется, есть ли возможность выделить недостающие ячейки памяти подряд с уже выделенными. Если места недостаточно, то выделяется новый участок памяти размером size и данные по указателю ptr копируются в начало нового участка.

Освобождение Дин. П Всю выделенную с помощью функций maloc(), calloc(), realloc() память нужно всегда Освобождение Дин. П Всю выделенную с помощью функций maloc(), calloc(), realloc() память нужно всегда освобождать, иначе память будет «утекать» . Для освобождения памяти, выделенной функцией malloc() существует функция free(). Прототип: void free(void *ptr); Исп-е: free(ptr);

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

Этапы: выделить блок оперативной памяти под массив указателей; выделить блоки оперативной памяти под одномерные Этапы: выделить блок оперативной памяти под массив указателей; выделить блоки оперативной памяти под одномерные массивы, представляющие собой строки искомой матрицы; записать адреса строк в массив указателей.

Выделения памяти с использованием массива указателей Выделения памяти с использованием массива указателей

Компилятору явно будет указано количество строк и количество столбцов в массиве. Компилятору явно будет указано количество строк и количество столбцов в массиве.

 int main() { int **a; // указатель на строку int i, j, n, int main() { int **a; // указатель на строку int i, j, n, m; printf("Введите количество строк: "); scanf("%d", &n); printf("Введите количество столбцов: "); scanf("%d", &m); a = (int**)malloc(n*sizeof(int*)); // Выделение памяти под указатели на строки // Ввод элементов массива for(i=0; i

Выделение памяти под двумерные массивы 2 способ Выделение памяти под двумерные массивы 2 способ

Двумерная матрица, содержащая n строк и m столбцов, будет располагаться в оперативной памяти в Двумерная матрица, содержащая n строк и m столбцов, будет располагаться в оперативной памяти в форме ленты, состоящей из элементов строк. Индекс любого элемента двумерной матрицы можно получить по формуле index = i*m+j; где i - номер текущей строки; j - номер текущего столбца. index = 1*4+3=7 Объем памяти, который потребуется, для размещения двумерного массива, n·m·(размер элемента)

Компилятору явно не указывается количество элементов в строке и столбце двумерного массива, традиционное обращение Компилятору явно не указывается количество элементов в строке и столбце двумерного массива, традиционное обращение к элементу путем указания индекса строки и индекса столбца является некорректным a[i][j] – некорректно *(p+i*m+j) – корректно p - указатель на массив, m - количество столбцов, i - индекс строки, j - индекс столбца.

int main() { int *a; // указатель на массив int i, j, n, m; int main() { int *a; // указатель на массив int i, j, n, m; printf("Введите количество строк: "); scanf("%d", &n); printf("Введите количество столбцов: "); scanf("%d", &m); a = (int*) malloc(n*m*sizeof(int)); // Выделение памяти // Ввод элементов массива for(i=0; i

Выделение памяти под двумерные массивы Свободные массивы Выделение памяти под двумерные массивы Свободные массивы

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

int main() { int **a; int i, j, n, *m; system( int main() { int **a; int i, j, n, *m; system("chcp 1251"); system("cls"); printf("Введите количество строк: "); scanf("%d", &n); a = (int**)malloc(n*sizeof(int*)); m = (int*)malloc(n*sizeof(int)); // массив кол-ва элементов строк // Ввод элементов массива for(i = 0; i

Выделение памяти под 3 х-мерные и n-мерные массивы Выделение памяти под 3 х-мерные и n-мерные массивы

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