SI_4_chast.pptx
- Количество слайдов: 37
Язык Си. Часть 4 ФУНКЦИИ. ДИНАМИЧЕСКАЯ ПАМЯТЬ.
Зачем нужны функции? 1. Структурирование программы – разбиение большой задачи на более мелкие части. 2. Использование уже написанного кем-то кода – стандартных и сторонних библиотек.
Прототип функции – это объявление функции, не содержащее тела функции, но указывающее имя функции, арность (количество аргументов), типы аргументов и возвращаемый тип данных. Шаблон прототипа функции: Тип_возвращаемого_значения имя_функции (тип_аргумента 1, тип аргумента 2, …); Прототип: int printf(const char *format[, argument, . . . ]); Использование: printf("hello, world"); /* функция вывода информации на экран*/
Оператор return выражениенеобяз. ; Предназначен для возврата результата выполнения функции. После его выполнения текущая функция завершает свою работу и передает управление коду, вызвавшему функцию (в случае функции main() – операционной системе). Если функция ничего не возвращает, то оператор return не является обязательным. Пример1: void set_property(){операция 1; …} Пример2: int set_property(){операция 1; … return 0; }
Пример Задача: матрица 5*5 заполняется случайными целыми числами от 0 до 10. Вывести те строки матрицы, сумма чисел в которых не превышает 20. Алгоритм: Заполнить матрицу случайными числами //1 Вывести исходную матрицу //2 for(каждой строки матрицы) //3 if(сумма чисел в строке меньше 20) //4 Вывести строку //5
#include
//Реализация функций 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. При объявлении и реализации функции в скобках записываются формальные параметры: 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 *py) /* НЕПРАВИЛЬНО */ /* обмен местами *рх и *ру */ { { int temp; temp = x; temp = *рх; x = у; *рх = *ру; у = temp; } int temp; *ру = temp; }
В функцию нужно передавать указатель, когда: 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[ ], int n ); // так себе • fun ( int *m, int n ); // хорошо При передаче одномерного массива в функцию через стек передается только указатель на 0 -ой элемент (весь массив в стек не копируется).
Двумерные статические массивы 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 0 # else # define NULL ((void *)0) # endif #endif Используется для присваивания указателю нулевого значения. Для каждого типа указателей существует (согласно определению языка) особое значение - "нулевой указатель", которое отлично от всех других значений и не указывает на какой-либо объект или функцию. Тут можно почитать подробнее: http: //faqs. org. ru/progr/c_cpp/cfaqrus. htm
Динамическая память
Динамическая память (Дин. П) В тех случаях, когда необходимо обрабатывать большие объемы данных, не помещающиеся в стек, либо когда при компиляции объем обрабатываемых данных неизвестен, память под данные необходимо выделять в процессе работы программы, т. е. динамически. Статические массивы (int array[10]) компилятор сам создает в стеке, так как они являются локальными переменными, динамические же массивы будут создаваться в куче (область динамической памяти), а управлять этой памятью должен программист. Основное правило: Вся выделенная «вручную» память должна быть освобождена как только она перестает быть нужной!
#include
#include
Инициализация Дин. П 1. С помощью функции memset() #include
Выделение Дин. П - продолжение 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() память нужно всегда освобождать, иначе память будет «утекать» . Для освобождения памяти, выделенной функцией malloc() существует функция free(). Прототип: void free(void *ptr); Исп-е: free(ptr);
Выделение памяти под двумерные массивы 1 способ Выделения памяти с использованием массива указателей
Этапы: выделить блок оперативной памяти под массив указателей; выделить блоки оперативной памяти под одномерные массивы, представляющие собой строки искомой матрицы; записать адреса строк в массив указателей.
Выделения памяти с использованием массива указателей
Компилятору явно будет указано количество строк и количество столбцов в массиве.
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 способ
Двумерная матрица, содержащая 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; 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("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-мерные массивы
Чтобы создать трёхмерный массив, по аналогии, необходимо сначала определить указатель на указатель, после чего выделить память под массив указателей на указатель, после чего проинициализировать каждый из массивов и т. д.


