|
Программирование >> Динамические структуры данных
Как упоминалось на втором семинаре, DBL EPSILON - это константа, определенная в файле <float.h>. Ее значение равно минимальному числу, которое, будучи прибавлено к единице, даст не равный единице результат. Теперь нашу функцию можно вызывать с одним параметром, к примеру: у = cosh(x): ВНИМАНИЕ - Функция может иметь несколько параметров со значениями по умолчанию. Они должны находиться в конце списка параметров. Вариант прототипа функции с использованием параметра ошибки, а также значением точности по умолчанию выглядит так: double cosh(const double х. int &err. const double eps = DBL EPSILON): Соответствующим образом изменится и вызов функции. Обратите внимание, что указание перед параметром ключевого слова const в данном случае (при передаче по значению) применяется только для того, чтобы четко указать, какие из параметров являются входными. В случае передачи по ссылке указание const, кроме того, дает возможность передавать на месте этого параметра константу. Теперь давайте посмотрим на нашу программу с другой стороны (с рассмотренных она нам уже порядком надоела). Мы оформили в виде функции вычисление суммы ряда, однако задача вывода таблицы значений функции сама по себе достаточно типична и может встретиться в других задачах. Поэтому было бы логично оформить ее решение также в виде функции. Задача 7.1 -а. Передача в функцию имени функции Назовем функцию вывода таблицы значений pri nttabl. Прежде всего надо определить ее интерфейс. Для того чтобы вывести таблицу, нашей функции потребуется знать диапазон и шаг изменения значений аргумента, а также какую, собственно, функцию мы собираемся вычислять. Всё? Нет, не все: забыли, что в функцию вычисления суммы ряда надо передавать точность, поэтому точность следует включить в список параметров вызывающей ее функции printtabl. Функция pri nttabl не возвращает никакого значения, то есть перед ее именем надо указать void. Как передать в функцию имя функции? Точно так же, как и любую другую величину: в списке параметров перед именем параметра указать его тип. До этого момента мы передавали в функцию величины стандартных типов, а теперь нам потребуется определить собственный тип. Тип функции определяется типом ее возвращаемого значения и типом ее параметров. Для нашей функции это выглядит так: double (*fun)(double. double): Здесь описывается указатель по имени fun на функцию, получающую два аргумента типа doubl е и возвращающую значение того же типа (от параметров по умолча- нию нам, к сожалению, придется отказаться). Часто, если описание типа сложное, с целью улучшения читаемости программы задают для него синоним с помощью ключевого слова typedef: typedef double (*Pfun)(double. double): В этом операторе задается тип Pf un, который можно использовать наряду со стандартными типами при описании переменных. Таким образом, заголовок функции печати таблицы должен иметь вид: void print tabl(Pfun fun. double Xn. double Xk. double dX, double eps): Запишем теперь текст программы, сведя к минимуму диагностику ошибок (при превышении максимально допустимого количества итераций функция завершается, возвращая О, а вызывающая программа бесстрастно выводит это значение): #include <stdio.h> #include <math.h> typedef double (*Pfun)(const double, const double): void print tabl(Pfun fun. const double Xn. const double Xk. const double dX. const double eps): double cosh(const double x. const double eps): int riain(){ double Xn. Xk. dX. eps: printf( Enter Xn. Xk. dX. eps \n ): scanf( XlfXlfXlfXlf .&Xn. &Xk. &dX. &eps): print tabl(cosh. Xn. Xk. dX, eps): return 0: void print tabl(Pfun fun. const double Xn, const double Xk. const double dX. const double eps) { printf( --......................-------\n ); printf( I X I Y \n ); pri ntf ( --------............------------\n ); for (double X = Xn: x <- Xk: x += dX) printf( X9.21f Ш.6д \n . x. fun(x. eps)): pri ntf ( --------------------------------\n ): double cosh(const double x. const double eps) { const int Maxlter - 500: double ch = 1. у - ch: for (int n - 0: fabs(ch) > eps: n++) { ch *= X * X /(2 * n + l)/(2 * n + 2): у + ch: if (п > Maxlter) return 0: return у: Функция print tab1 предназначена для вывода таблицы значений любой функции, принимающей два аргумента типа double и возвращающей значение того же типа. Как видите, наряду с большей общностью мы добились и лучшего структурирования программы, разбив ее на две логически не связанные подзадачи: вычисление функции и вывод таблицы. В главной программе остался только ввод исходных данных и вызов функции. Задача 7.2. Передача одномерных массивов в функцию Даны два массива из п целых чисел каждый. Определить, в каком из них больше положительных элементов. Очевидно, что для решения этой задачи потребуется подсчитать количество положительных элементов в двух массивах, то есть выполнить для обоих массивов одни и те же действия. Следовательно, эти действия надо поместить в функцию. Интерфейс функции: входные данные - массив и количество его элементов, результат - количество положительных элементов в массиве. Таким образом, заголовок функции должен иметь вид: int n posit(const int *a. const int n): Имя массива представляет собой указатель на его нулевой элемент, поэтому в функцию массивы передаются через указатели Количество элементов в массиве должно передаваться отдельным параметром, потому что, в отличие от строк символов, использующих признак конца строки, для массивов общего вида никакого признака конца массива не существует. Аналогичные задачи мы рассматривали на третьем семинаре, поэтому не будем останавливаться на алгоритме и сразу перейдем к написанию программы: #include <iostream.h> int n posit(const int *a, const int n); прототип функции int main(){ int i, n: cout Введите количество элементов: : cin n: int *a int *b new int[n]; new int[n]: cout Введите элементы первого массива: for (i = 0: i < n: i++) cin a[i]: Это же относится и к именам функций, передаваемых в функции. Все остальные величины могут быть переданы по значению. cout Введите элементы второго массива: ; for (i = 0: i < n: i++) cin b[i]: if (n posit(a. n) > n posit(b. n)) cout В первом положительных больше endl: else if(n posit(a. n) < n posit(b. n)) cout Bo втором положительных больше endl: else cout Одинаковое количество endl: return 0: int n posit(const int *a, const int n) { int count = 0: for (int i = 0: i < n: i++) if (a[i] > 0) count++; return count: В этой программе место под массивы выделяется в динамической области памяти, поскольку в задании не указано конкретное количество элементов. Однако функцию nposi t можно без изменений применять и для обычных массивов, потому что для каждого из них имя тоже является указателем на нулевой элемент, только константным. Например, опишем массив из 10 элементов и инициализируем первые шесть из них (оставшимся будут присвоены нулевые значения): int х[10] {2. 3. -1. -10. 4. -2}: cout n posit(x. 10): будет выведено значение 3 Заслуживает рассмотрения способ анализа результатов работы функции. Как видите, функция вызывается в составе выражения в условном операторе. Для перебора всех трех вариантов результата приходится вызывать ее для каждого массива дважды, что для больших массивов, конечно, нерационально. Чтобы избежать повторного вызова, можно завести две переменные, в которые записываются результаты обработки обоих массивов, а затем использовать эти переменные в условных операторах: int n pos1t a = n positCa. n). n posit b = n pos1t(b. n): if (n posit a > n posit b) cout В первом положительных больше endl: else if (n posit a < n posit b) cout Bo втором положительных больше endl: else cout Одинаковое количество endl: Надо сказать, что современные компиляторы обладают широкими возможностями оптимизации и сами отслеживают подобные ситуации, преобразуя код программы, но это не означает, что на эффективность своих программ вообще не надо обращать внимания. Главным же критерием при выборе варианта написания программы, тем не менее, остается простота ее структуры и читаемость. Мы не получили выигрыша в длине приведенной выше программы, использовав для вычисления количества положительных элементов функцию, но причина этому - лишь простота задачи. В реальных программах в виде отдельной функции оформляются более крупные законченные фрагменты. Разные авторы рекомендуют различные конкретные цифры, задающие длину функций, но сходятся в одном: функция должна быть не очень короткой, но и не очень длинной. Чаще всего советуют создавать функции длиной в один-два экрана. Впрочем, придерживаться разумной умеренности бывает полезно не только при написании программ... Задача 7.3. Передача строке функцию Написать программу, определяюию, сколько чисел содержится в каждой строке текстового файла. Длина каждой строки не превышает 100 символов. Эту задачу можно разбить на две: ввод данных из файла и их анализ. Для каждой строки проверка выполняется отдельно, поэтому в виде функции логично оформить поиск и подсчет количества чисел в одной строке. На вход функции будем подавать строку, а на выходе получать количество чисел в этой строке. Отличие передачи в функцию строки от передачи обычного массива состоит в том, что можно не передавать отдельным параметром размерность строки, а определять конец строки внутри функции по нуль-символу. Для простоты предположим, что числа М0Г3ГГ быть либо целые, либо вещественные с фиксированной точкой и непустой дробной частью. Распространить действие программы на другие виды чисел предоставляется вам в виде самостоятельного упражнения. #include <fstream.h> #include <ctype.h> int num num(const char *str): int nfiain(){ ifstream fin( test.txt , ios::in ios::nocreate): if (!fin) { cout Нет файла test.txt endl: return 0:} const int len = 101: int i = 1: char str[len]: while (fin.getline(str. len)) { cout B строке i содержится num nuni(str) чисел endl: i++: } return 0: int num num(const char *str) { int count = 0: while (*str) { if (isdigit(*str) && ! isdigit(*(str + D) && *(str + 1) != . ) count-n-; str++: } return count: Увеличение счетчика чисел в функции numnum происходит каждый раз, когда заканчивается число, то есть если после цифры стоит не цифра и не точка. Цикл заканчивается по достижении нуль-символа. Задача 7.4. Передача двумерных массивов в функцию Написать программу, определяющую, в какой строке целочисленной матрицы т х п находится самая длинная серия одинаковых элементов. Под серией имеются в виду элементы, расположенные подряд. В виде функции здесь удобно оформить решение основной задачи, оставив главной программе только ввод исходных данных и вывод результатов. Для удобства отладки ввод массива в программе выполняется из текстового файла. Первая строка файла содержит значения для тип, каждая следующая строка - набор чисел для одной строки матрицы. Память под массив выделяется в цикле для того, чтобы можно было задавать обе размерности массива в виде переменных (см. материал четвертого семинара). #include <fstream.h> int ser equals(int **a. const int m. const int n): int main(){ ifstream fin ( matrix.txt . ios::in ios::recreate): if (ifin) { cout Нет файла matrix.txt endl: return 0: } int m? n. i. j: fin m n: int **a = new int *[m]: ford - 0: i < m: i++) a[i] new int [n]: for (i - 0: i < m; i++) for (j = 0: j < n: j++) fin a[i][j]: int line = ser equals(a. m. n); if (line >= 0) cout Самая длинная серия в строке else cout Серий одинаковых элементов нет ; return 0: выделение памяти ввод массива вызов функции line: int ser equals(int **а. const int m. const int n){ int i. j. count, line = -1. maxcount = 0: for (i - 0: i < m; i++){ count = 0:
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |