Лекция 9 Функции
Массивы-параметры функции Передача массива в функцию Пример: void array_enter(int a[], int size) { int i; for (i = 0; i < size; i++) { scanf("%d", &a[i]); } void main() { int a[10]; array_enter(a, 10); }
Массивы-параметры функции Передача массива как указателя: Пример: void array_print(int *a, int size) { int i; for (i = 0; i < size; i++) { printf("%5d ", a[i]); /* a[i] можно заменить на *(a+i) */ } void main() { int a[10] = {... }; array_print(a, 10); }
Строки как параметры функций Строковый параметр определяется как массив ( char [] ) или как указатель ( char * ) Пример (определение длины строки): int len(char* s) /* допустимо так же: int len(char s[]) */ { int n; for (n =0; s[n] != '\0'; n++); return n; }
Различие между указателем и массивом в качестве параметров Пример 1: int len(char s[]) {... s++; /* ОШИБКА. */... } Пример 2: int len(char* s) {... s++; /* ошибки нет. Операция допустима */... }
Различие между указателем и массивом в качестве параметров Пример (определение длины строки): int len(char* s) { int n = 0; while (*s++ != '\0') /* проверяем признак конца строки, */ n++; /* сдвигаем указатель s и увеличиваем n*/ return n; }
Многомерные массивы как параметры функции Определение параметра функции в виде многомерного массива: [ ][ ]…[ ] Пример: void enter_matrix(int a[7][8]) { int i,j; for (i = 0; i < 7; i++) for (j = 0; j < 8; j++) scanf("%d", &a[i][j]); }
Многомерные массивы как параметры функции Первый размер массива является необязательным. Пример: void enter_matrix(int a[][8], int rows) { int i,j; for (i = 0; i < rows; i++) for (j = 0; j < 8; j++) scanf("%d", &a[i][j]); } void main() { int a[10][8], b[5][8], c[5][5]; enter_matrix(a, 10); /* первая матрица с 10-ю строками */ enter_matrix(b, 5); /* вторая матрица с 5-ю строками */ enter_matrix(c, 5); /* ОШИБКА! Кол-во столбцов различается */ }
Использование функций Задача: составить функцию my_print, выводящую на экран n чисел в виде: * 12 * 3 * 0 * 4 * Вариант решения задачи: void my_print(int n, int numbers[]) { int i; for (i = 0; i < n; i++) /* выводим n чисел */ printf("* %d ", numbers[i]); printf("*\n"); /* выводим завершающий символ * */ } void main() { int a[4] = {12, 3, 0, 4}; /* массив выводимых чисел */ my_print(4, a); /* выводим числа */ }
Функции со списком аргументов переменной длины Функция со списком аргументов переменной длины (функция с множественными параметрами) определяется: (,...) Пример: int printf(char *fmt,...) int scanf(char *fmt,...) void my_print(int n,...); Примеры использования функции со списком аргументов переменной длины: printf("Год: %d, месяц: %02d, день%d", 2007, 4, 12); printf("Hello, %s", "МИЭТ"); printf(); /* ОШИБКА! Как минимум один параметр! */
Функции со списком аргументов переменной длины Объявляем функцию my_print для использования со списком аргументов переменной длины: void myprint(int n,...); Вопросы: 1)Какое у аргументов будет имя? 2)Как определить количество аргументов? 3)Как «шагать» по списку аргументов, чтобы «перебрать» все аргументы? Ответы: 1)У этих аргументов нет имени 2)Никак. Количество аргументов должно быть передано функции в виде аргумента. 3)Используя библиотеку stdarg.h
Функции со списком аргументов переменной длины Для работы со списком аргументов переменной длины необходимо подключить библиотеку stdarg.h (#include ) Содержимое данной библиотеки: Тип va_list служит для описания переменной, которая будет по очереди указывать на каждый из аргументов. Макрос va_start(ap) инициализирует переменную ap чтобы она указывала на первый безымянный аргумент. Макрос va_arg(ap) на каждом своем вызове выдает очередной аргумент, а ap передвигает на следующий: Макрос va_end(ap) делает очистку всего, что необходимо.
Функции со списком аргументов переменной длины void my_print(int n,...) { va_list ap; /* объявляем переменную, ассоциированную */ /* со списком переменной длины */ int i; va_start(ap, n); /* устанавливает ap на 1-й безымянный */ /* аргумент */ for (i = 0; i < n; i++) { int number = va_arg(ap, int); /* берем текущий элемент */ /* списка. Сдвигаем ap на следующий */ printf("* %d ", number); /* выводим его на экран */ } printf("*\n"); va_end(ap); /* очистка, когда все сделано */ }
Тип va_list как тип аргумента функции Задача: определить функцию, аналогичную printf, которая будет автоматически добавлять перевод строки. Решение: void my_printf(const char* fmt,...) { /* ? ? ? */ /* Проблема! Как передать в функцию printf список аргументов переменной длины? */ } Решение проблемы: необходимо использовать функцию: int vprintf(const char* fmt, va_list args);
Тип va_list как тип аргумента функции Определение функции void my_printf(const char* fmt,...) { va_list ap; /* объявляем переменную, ассоциированную /* со списком переменной длины */ va_start(ap, fmt); /* устанавливает ap на 1-й /* безымянный аргумент */ vprintf(fmt, ap); /* выводим на экран все аргументы в /* соответствии с форматной строкой */ printf("\n"); /* перевод на следующую строку */ }
Указатели на функции Тип «указатель на функцию» - это тип, переменная которого указывает на функцию. Указатель на функцию – это выражение или переменная, используемая для представления адреса функции. Объявление переменной типа «указатель на функцию» (* ) ( ); Компилятор языка Си проверяет соответствие типа возвращаемого функцией значения и спецификацию параметров у переменных типа «указатель на функцию» и функций, на которые они указывают.
Операции над указателями на функции Пример: /* Определяем нашу функцию */ int my_func(int a, float b) { … } void main() { /* my_func_ptr – указатель на функцию типа int с двумя параметрами: int и float */ int (*my_func_ptr)(int, float); my_func_ptr = my_func; /* операция присваивания */ my_func_ptr(100, 3.14); /* операция вызова */ my_func_ptr = main(); /* ОШИБКА! Типы ф-й не соответствуют. */ my_func_ptr(); /* ОШИБКА! Несоответствие параметров */ }
Указатели на функции Пример использования. Задача: найти максимальный или минимальный элемент массива (по решению пользователя). /* функция возвращает 1 если a < b и 0 если наоборот */ int less(int a, int b); /* функция возвращает 1 если a > b и 0 если наоборот */ int greater(int a, int b); void main() { int A[100]; char decision;... printf("Найти максимальный?(Y/N)"); scanf("%c", &decision); (продолжение на следующем слайде)
Указатели на функции (продолжение) /* объявляем переменную типа */ int (*compare)(int, int); /* указатель на функцию */ if (decision == 'Y') /* присваиваем ей указатель */ compare = greater; /* на greater(int,int) */ else /* или */ compare = less; /* на less(int,int) */ /* Ищем необходимый элемент */ n = a[0]; for (i = 1; i < 100; i++) /* используем compare для */ if (compare(a[i], n)) /* сравнения */ n = a[i]; printf("Значение: %d", n); /* вывод на экран */ }
Указатели на функции как параметры функции Пример. Задача: отсортировать массив либо по-возрастанию, либо по- убыванию (в зависимости от решения пользователя) void sort(int size, int a[], int (*compare)(int, int)) { /* сортировка с использованием compare в качестве метода сравнения двух элементов */... } void main() { int a[100];... printf("Сортировать по-возрастанию?"); if (getch() == 'Y') sort(100, a, less); else sort(100, a, greater);... }
Рекурсия Рекурсия – это прямое или косвенное обращение функции к самой себе. Функция, использующая рекурсию называется рекурсивной. Пример: int factorial(int n) { if (n == 0) return 1; return n * factorial(n-1); }