Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

7 Структурное программирование 2012

.pdf
Скачиваний:
11
Добавлен:
29.02.2016
Размер:
310.72 Кб
Скачать

1

7 Структурное программирование

7.1 Общие сведения о структурном программировании

С увеличением объемов программ возникла необходимость в представлении программы в виде иерархии относительно обособленных фрагментов. Была разработана технология структурного программирования. При этом вся программа представляет собой последовательность вызовов отдельных подпрограмм. Это дает следующие преимущества:

-сокращение объема программ за счет однократного описания повторяющихся частей программ;

-повышение наглядности программ, и как следствие упрощение процесса создания программ;

-сокращение времени на отладку и верификацию программ.

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

В языках программирования подпрограммы повторяет в миниатюре структуру самой программ. В сильно структурированных языках подпрограммы внутри себя могут содержать собственные вложенные подпрограммы, стоящие на более низкой ступени иерархии. Операторная часть головной программы при структурном программировании представляет вызовы ранее описанных подпрограмм.

 

 

 

 

Головная программа

 

Верхний уровень иерархии

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1-й

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

 

 

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

 

 

 

 

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

 

уровень

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2-й

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

 

 

 

 

 

Подпрограмма АБ

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

уровень

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

N-й

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Подпрограмма NAА

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

уровень

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Рисунок 7.1 – Иерархическая структура программы Языки С и С++ являются слабоструктурированными языками и имеют только первый

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

Рекомендуется выбирать объем подпрограммы так, чтобы вся ее операторная часть помещалась на экране.

Описание текста подпрограмм производится в разделе объявления подпрограмм, который обычно помещается перед операторной частью программ. Элементы, описанные в подпрограмме, называются локальными, а компоненты программы (или подпрограммы верхнего уровня иерархии), где объявлена данная подпрограмма, - глобальными.

В языках программирования получили распространение два типа подпрограмм:

1)подпрограммы-процедуры, которые предназначены для выполнения определенной относительно обособленной системы операций;

2)подпрограммы-функции, реализуют вычислительный алгоритм расчета конкретного значения.

В языках программирования С и С++ все подпрограммы являются функциями, которые могут использоваться как самостоятельные операторы и вызываться внутри других выражений и операторов. Однако аналогом процедуры в С является функция, которая не возвращает тип результата (т.е. результат - void) и не может использоваться в других выражениях и операторах программы.

При написании подпрограмм соблюдаются следующие правила видимости имен:

2

1)имя локального компонента подпрограммы (констант, переменных и т.п.) должно быть уникальным по отношению ко всей программе;

2)в подпрограмме известны все компоненты, описанные выше по структуре дерева иерархии программы (если объявить переменную в разделе описания головной программы, то она доступна во всех подпрограммах, а если в подпрограмме, то в самой подпрограмме и вложенных в нее локальных подпрограммах);

3)если имя локального компонента совпадает с глобальным компонентом, то в операторной части подпрограммы одноименный глобальный элемент становится недоступным.

В схемах программ и алгоритмов вызов подпрограммы обозначается символом «Предопределенный процесс», внутри которого записывается имя подпрограммы и указывается список фактических параметров.

Рисунок 7.2 – Изображение символа вызова подпрограммы

7.2 Подпрограммы в языках программирования С и С++

Вязыках программирования С и С++ подпрограммы представлены функциями. Определение функции является способом задать то, как должно делаться некоторое действие. В каждой программе на С имеется хотя бы одна функция – main, которая реализует основной вычислительный процесс, внутри которой могут вызываться другие заданные пользователем или стандартные функции.

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

1)возвращающие результат в точку вызова, они могут использоваться внутри других выражений и операторов языка;

2)не возвращающие результат, которые используются только как выражения язы-

ка.

Функция не может быть вызвана, пока она не описана. Описание функции задает имя функции, тип возвращаемого функцией значения (если таковое есть), число и типы параметров, которые должны быть в вызове функции.

Формат описания функции в С++ имеет структуру

тип_результата имя_функции(список_формальных параметров) { тело функции

return результат;

}

В структуре описания функции различают следующие части:

-тип возвращаемого результата в точку вызова;

-имя функции;

-список формальных параметров, который может быть пустым;

-тело функции, которое заканчивается возвращением результата в точку вызо-

ва с помощью return (не используется в void функциях).

Тип результата показывает скалярный тип данных, возвращаемый в точку вызова. Если функция не может использоваться в других выражениях, то она возвращает тип void. Но рекомендуется использовать тип int для получения кода ошибки выполнения программы, который при успешном выполнении программы возвращается как 0.

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

Список параметров используется для обмена данными между внешним блоком и внутренней частью функции. Формальные параметры – переменные, которые используются как шаблон для указания операций над вводимыми данными при описании программной реализации тела функции. При вызове функций вместо имен формальных переменных ука-

3

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

(тип имя_параметра_1, тип имя_параметра_2, , тип имя_параметра_N)

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

Из функции, которая не описана как void, должно возвращаться ее значение. Возвращаемое значение задается оператором return. Пример функции определения фак-

ториала

с

использованием оператора ?:

int

fac(int n)

{return (n>1) ? n*fac(n-1) : 1; }

В

функции может быть больше одного оператора return. Например, при:

int

fac(int n)

 

{

if (n > 1)

return n*fac(n-1);

 

else

return 1;

}

// конец fac

-------------------------------------------

Тип возвращаемого выражения проверяется на согласованность с возвращаемым типом, и выполняются необходимые преобразования типов.

Пример описания функции нахождения значения третьей степени от передаваемого в нее действительного числа удвоенной точности

double cube(double x) { return x*x*x;

} //-------------------------------------

Описания операторных частей функций производится после тела головной функции main. Однако здесь имеется проблема, связанная с тем, что вызовы функций могут выполняться внутри main, т.е. раньше ее описания. Поэтому производится предварительное объявление прототипа функции перед описанием main. Прототип функции представляет собой ее заголовок, включающий тип возвращаемого результата, имя функции и списка параметров. Каждая функция, вызываемая в программе, должна быть определена только один раз. Определение функции - это описание функции, в котором приводится тело функции. Структура программы на С++ имеет вид

#include <заголовочный_файл> глобальные_данные_программы; объявление прототипов_функций_пользователя; определение головной функции main; определение функций пользователя.

Пример программы, которая выводит кубическую степень от введенного с клавиа-

туры числа с помощью функции cube.

 

 

 

#include <iostream.h>

 

 

 

 

double X;

 

 

// Глобальные данные

 

 

double cube(double x);

 

// Прототип функции куба

 

int main(void)

 

 

// Описание головной

функции

 

{ cout << "\nВведите число Х=";

// Вывод приглашения

на экран

cin >> X;

 

 

// Ввод исходных данных

 

cout << "\Кубическая степень : " << cube(X); // Вывод

ответа

 

return 0;

 

 

// Возвращения кода завершения работы

} // конец main ---------------------------------------------

 

double cube(double x)

// Описание

тела функции

 

 

{ return x*x*x;

 

// Возращение результата расчета

в точку вызова

} // конец функции cube -------------------------------------

 

Чтобы избежать

расходов на вызов функции, функцию можно

описать

как inline,

а чтобы обеспечить

более

быстрый доступ к параметрам, их

можно

описать как

register. Одна их следует использовать, только если это действительно необходимо.

7.3 Типы параметров подпрограмм в языках С и С++

Объявление функции со списком аргументов используется для организации обмена данными между подпрограммой и вызывающей ее программой. Список формальных параметров указывается после имени подпрограммы и заключается в скобки. Каждый параметр,

4

объявленный в этом списке, является локальной переменной по отношению к самой подпрограмме. Параметры списка разделяются между собой символом «,».

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

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

1)передача по значению;

2)передача данных по ссылке;

3)передача данных с помощью параметров–массивов и параметров-структур;

4)передача данных со значением по умолчанию;

5)незаданное число параметров;

6)передача в качестве параметра имени подпрограммы.

7.3.1 Передача данных в параметрах по значению

При способе передачи данных по значению значение фактического параметра в точке вызова передается переменной формального параметра, любые изменения формального параметра внутри подпрограммы не сказываются на значении переменной фактического параметра. Формат объявления параметра

тип_результата ммя_функции (тип_параметра имя_параметра);

Пример программы, использующей функцию, возвращающую минимальное значение из

двух параметров, передаваемых по значению.

 

#include <iostream.h>

// подключение заголовочных

#include <conio.h>

// файлов

float get_min(float X, float Y);

// объявление прототипа функции

int main()

// описание главной функции

{ float x,y;

// объявление локальных переменных

cout << "\nx=";

// ввод данных с консоли

cin >> x;

 

cout << "\ny=";

 

cin >> y;

 

cout << "\nmin=" << get_min(x,y); // вызов функции

getch();

// приостановка вывода на консоль

return 0;

// вывод кода нормального завершения

} // конец главной функции ------------------------------------

float get_min(float X, float Y)

// описание функции

{ return (X<Y)? X : Y;

// использование триадного оператора

} // конец функции -------------------------------------------

7.3.2 Передача данных в параметрах по ссылке

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

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

тип_результата ммя_функции (базовый_тип_параметра *имя_параметра);

При вызове функции следует учитывать для фактических параметров, не являю-

щихся указателями, необходимо

указывать

оператор взятия адреса

&.

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

переменных вещественного типа, используя передачу парметров по

ссылке.

#include <iostream.h>

// подключение ресурсов модуля потоков cin и cout

#include <conio.h>

// подключение модуля управления

консолью

void swap(float *X, float *Y); //

объявление прототипа функции перестановки

int main()

//

описание главной функции

{ float x, y;

// объявление переменных

 

 

 

5

 

 

cout << "\nx=";

//

вывод запроса

на экран

cin >> x;

//

ввод значения

x с клавиатуры

cout << "\ny=";

//

вывод запроса

на экран

cin >> y;

//

ввод значения

y с клавиатуры

swap(&x,&y);

//

вызов функции

перестановки

cout << "\n x=" << x << " y="

<< y;

// вывод результатов

getch();

//

приостановка закрытия консоли

return 0;

//

возвращение кода успешного завершения

}// -------------------- конец main

 

 

void swap(float *X, float *Y)

// описание функции перестановки

{ float tmp=*X;

// объявление локальной переменной

*X=*Y;

// перестановка

 

 

*Y=tmp;

 

 

 

 

}// -------------------- конец swap

Передача большого объекта по ссылке может быть гораздо эффективнее, чем передача его по значению, однако при этом имеется опасность изменения значения переменной фактического параметра. Тогда такой параметр можно описать с помощью слова const указанного перед типом, чтобы указать, что ссылка применяется по соображениям эффективности, а не для получения значение объекта из функции:

void f(const large *arg)

{ // значение arg не может быть изменено в теле функции

}

Описание параметра указателя как const сообщает, что значение объекта, указываемого указателем, функцией не изменяется.

7.3.3 Параметры-массивы и параметры-структуры

Массив не передается по значению, а передается указатель на его первый элемент. При этом компилятор автоматически преобразует переменную массива в ссылочный тип данных вне зависимости от описания параметра. При этом не обязательно указывать размеры массива, так как внутри программы не отслеживаются автоматически.

Размер массива недоступен внутри вызываемой функции. Это можно обойти несколькими способами. Так как строки оканчиваются нулем, поэтому их размер можно вычислить по поиску «\0». Для других массивов можно передавать их размер с помощью дополнительных параметров, которые задают размер, или определяют тип, содержащий указатель и индикатор длины, и передавать его вместо просто массива. Например:

void compute1(int* vec_ptr,

int vec_size);

// один способ

struct

Tvector

// другой

способ с помощью структуры

{ int* ptr;

//

указатель на целочисленный массив

int

size;

//

размер

массива

 

};

 

 

 

 

 

void compute2(vec v);

Для многомерных массивов можно вместо них использовать векторы указателей,

которые

не требуют специального рассмотрения. Например:

char*

day[] = { "mon", "tue", "wed", "thu", "fri", "sat", "sun" };

Пример программы определения среднего значения вводимого с клавиатуры одно-

мерного

вещественного массива с помощью функции:

#include <iostream.h>

 

float

get_middle(float *M, int size); // объявление прототипа функции

float

mf[1000];

// Исходный массив

int main()

// описание главной функции

{

int

Size;

// Переменная размера массива

 

cout << " size =";

 

 

cin

>> Size;

// ввод числа элементов

 

for(int i=0;i<Size;i++)

// цикл ввода элементов

 

{ cout << "\n mf[" << i << "]=";

 

 

cin >> mf[i];

 

}// конец цикла for

cout <<

"\n middle="

<< get_middle(mf,Size); //

вызов функции

return 0;

 

 

//

код

завершения

}// конец

main ---------------------------------------

 

 

 

 

 

float get_middle(float

*M, int size)

//

описание функции

{ float middle=0;

 

//

начальное

значение

 

6

for(int i=0; i< size; i++) middle+=M[i];// цикл суммирования

return middle/size;

// возврат среднего значения

}// конец функции ----------------------------------

 

При использовании в качестве параметров функций переменных-структур возможно

следующее:

 

1)использование для передачи данных по значению;

2)использовать для передачи данных по ссылке.

При передаче данных по ссылке внутри тела функции используется указатель на структуру. Доступ к данным полей структуры выполняется с помощью оператора «стрелка» (->). Который автоматически выполняет операцию разыменовывания. Формат:

имя_указателя_на_структуру->имя_поля Пример использования параметра-структуры для функции чтения полей с клавиа-

туры и передачи их в программу.

 

 

 

int entry(struct sman* man)

// Определение функции ввода данных структуры

{ cout << "\nИмя клиента

 

: ";

 

cin >> man->name;

 

 

 

 

cout << "\nОтчество клиента

 

: ";

 

cin >> man->name2;

 

 

 

 

cout << "\nФамилия клиента

 

: ";

 

cin >> man->family;

 

 

 

 

cout << "\nГод рождения клиента : ";

 

cin >> man->year;

 

 

 

 

cout << "\nНомер счета клиента

: ";

 

cin >> man->number;

 

 

 

 

return 0;

// Код успешного окончания процесса

} // ---------------------------------------

 

При передаче параметров-структур по значению рекомендуется указывать описа-

ние параметра struct в формате

 

 

 

 

struct имя_типа_структуры переменная_структуры

Пример подпрограммы записи структуры в текстовый файл с передачей данных по

значению.

 

 

 

 

 

int fsave(char fname[80], struct sman man)

// Сохраняемая структура

{ ifstream fin(fname,ios_base::in);

// попытка чтения файла

ofstream fout;

 

 

 

 

if (fin)

{ fin.close();

 

 

// если файла существует

 

fout.open(fname,ios_base::app);

// то открывается для добавления

 

}

 

 

 

 

else fout.open(fname,ios_base::out);

// если нет то открывается заново

fout << "Имя

: " << man.name << endl;

 

fout << "Отчество

: " << man.name2 << endl;

fout << "Фамилия

: " << man.family << endl;

fout << "Год рождения : " << man.year << endl;

 

fout << "Телефон : " << man.number << endl;

 

fout.close();

 

 

 

// закрытие потока

return 0;

// Код успешного окончания процесса

}//-------------------------------------

 

7.3.4 Параметры по умолчанию

 

 

Один,

последний

параметр

в

списке, можно

описать как параметр со значением

по умолчанию. В простом вызове функции не нужно указывать для него значение фактического параметра, так как оно считается уже известным. Если же при вызове значение параметра по умолчанию следует переопределить, то только тогда указывается его фактическое значение.

Параметр по умолчанию проходит проверку типа во время описания функции и вычисляется во время ее вызова. Задавать параметр по умолчанию можно только в прото-

типе

функции

и

только

для

последних

аргументов,

используя

формат

тип имя_функции (, тип_параметра

имя_параметра = значение_по_умолчанию);

 

 

например:

 

 

 

 

 

 

 

 

 

 

int f1(int, int =0, char*

=0);

// верно

 

 

 

int g1(int =0, int =0, char*);

// ошибка

 

 

 

int f2(int =0, int, char*

=0);

// ошибка

 

 

7

Пример программы, содержащей подпрограмму degree для возведения вещественного числа основания в положительную беззнаковую степень, которая имеет параметр

степени

по умолчанию равный двум.

 

#include

<iostream.h>

 

double degree(double x, unsigned int n=2);

// прототип функции

int main()

 

// главная функция

{

double

d;

 

// основание

 

int i;

 

 

// степень

 

cout << "\n Число = ";

 

 

cin >>

d;

 

// ввод основания

 

cout << "\n Квадрат числа " << degree(d);

// вывод квадрата

 

return

0;

 

// код завершения

}

// конец main

---------------------------------------------

 

double degree(double x, unsigned int n)

 

{

double

res=1;

 

 

 

for(int i=1; i<=n; i++) res=res*x;

 

 

return

res;

// возврат результата

 

}

//----------------------------------------------------------

 

 

 

7.3.5 Перегрузка имен Функций

Следует давать разным функциям различные имена. Однако возможна ситуация когда функции выполняют одинаковую работу над параметрами разных типов, тогда удобно присвоить одинаковое имя. В С и С++ использование одного имени для различных действий над различными типами называется перегрузкой (overloading). Имя может использоваться более чем для одной функции, только если оно сначала описано как перегруженное (в C++Builder это делать не требуется). Например:

overload print; void print(int); void print(char*);

Поиск функции, которую надо вызвать, компилятор выполняет в три шага:

1)поиск функции, точно соответствующей описанию списка параметров, и ее использование в случае успеха;

2)поиск соответствующей функции, используя встроенные преобразования, и использование любой найденной функции;

3)поиск соответствующей функции, используя преобразования, определенные пользователем, и если множество преобразований единственно, использовать найденную функцию.

К параметрам функций с перегруженными именами стандартные C++ правила преобразования применяются не полностью. Преобразования, могущие уничтожить информацию, не выполняются.

Пример, в котором преобразование необходимо: overload print(double), print(long);

void f(int a); { print(a);

}

Здесь a может быть напечатано или как double, или как long. Неоднозначность разрешается явным преобразованием типа (или print(long(a)) или print(double(a))).

Пример программы, использующей перегрузку функций определения максимума

#include <iostream.h> #include <conio.h>

//---------- перегрузка имен функций ----------------------

int

max(int

a, int b, int c);

// Максимум трех целочисленных переменных

double max(double x, double y); // Максимум двух вещественных значений

int

main()

 

 

// Головная функция

{

int A, B, C;

// Локальные переменные

 

 

cout <<

"\na=";

 

 

 

 

cin >> A;

 

 

 

 

cout <<

"\nb=";

 

 

 

 

cin >> B;

 

 

 

 

cout <<

"\nc=";

 

 

 

 

cin >> C;

 

 

 

 

cout <<

"\n max=" << max(A,B,C);

// Сравнение трех значений

8

 

cout << "\n max=" << max(10,-0.3);

// Сравнение двух значений

getch();

 

return 0;

 

}//----------------------------------------------------------------------

 

int max(int a, int b, int c) // Максимум трех целочисленных

{if((a>b)&&(a>c)) return a;

else if ((b>a)&&(b>c)) return b;

else return c; }//--------------------------------------------------

double max(double x, double y) // Максимум двух вещественных значений

{if(x>y) return x ; else return y;

} //---------------------------------

7.3.6 Незаданное число параметров

Для некоторых функций невозможно задать число и тип всех параметров, которые можно ожидать в вызове. Такую функцию описывают, завершая список описаний параметров многоточием (...). Например:

int printf(char* ...);

Это задает, что в вызове printf должен быть по меньшей мере один параметр, char*, а остальные могут быть, а могут и не быть. Например:

printf("Hello, world\n");

printf("Мое имя %s %s\n", first_name, second_name); printf("%d + %d = %d\n",2,3,5);

Такая функция полагается на информацию, которая недоступна компилятору при интерпретации ее списка параметров. В случае printf() первым параметром является строка формата, содержащая специальные последовательности символов, позволяющие printf() правильно обрабатывать остальные параметры. %s означает "параметр char*", а %d означает "параметр int". Однако, компилятор этого не знает, поэтому он не может убедиться в том, что ожидаемые параметры имеют соответствующий тип. Например:

printf("Мое имя %s %s\n",2);

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

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

7.4 Параметры функции main

Вбольшинстве программ нет необходимости использовать аргументы функции main. В этом случае она описывается как

int main() или int main(void)

ВBorland C++ возможно использовать до трех параметров в качестве аргументов main. Аргументы main возвращают параметры командной строки загруженной программы. Прототип main при этом примет вид

int main (int argc, char* argv[], char* env[])

где argc – число параметров командной строки;

argv[] – вектор указателей строк значений параметров, где первый соответствует полному имени загруженной программы.

env[] – вектор указателей на строки переменных окружения command.com. Возможно использовать не полный список аргументов, а только один или два:

main(int

argc)

 

//

один аргумент

main(int

argc,

char* argv[])

//

два аргумента

Пример программы, отображающей на экране параметры использованной при ее загрузке командной строки:

#include <conio.h> #include <stdio.h>

int main(int argc, char *argv[], char *env[])

{printf("\n Число параметров командной строки : %i",argc); if (argc>1)

{ for(int i=0; i<argc; i++)

printf("\n %i -я строка : %s",i+1,argv[i]); // вывод элемента строки } // конец if

 

 

 

9

 

getch();

// приостановка

вывода на

консоль

return 0;

//

возврат кода

успешного

завершения программы

}

//

конец программы

 

Пример программы просмотра файла, имя

которого вводится в командной строке

#include <iostream.h>

 

 

#include <fstream.h>

 

 

ifstream fin;

// файловый поток чтения

 

int main(int N, char *str[])

 

 

{ char p[2];

// строка содержимого файла

 

if(N>1) { cout << "Просмотр файла " << str[1];

fin.open(str[1],ios::in);

// открытие файла

if (!fin) cout << "\nОшибка открытия файла" ;

else { while(!fin.eof())

//

цикл чтения файла

 

{ fin.write(p,1);

//

буферезированное чтение из файла

 

cout << p ;

//

вывод на экран

} // конец цикла while

}// конец блока else

fin.close();

// закрытие файла

} // конец if

 

return 0; // возврат кода отсутствия ошибки

} // конец main ---------------------------------------

7.5 Указатель на функцию

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

тип_функции (*имя_указателя)(список_формальных_аргументов);

Чтобы вызвать некоторую функцию с его помощью сначала необходимо присвоить ему адрес вызываемой функции в формате

имя_указателя = &имя_вызываемой_функции;

Вызов функции с помощью указателя производится записью указателя со списком фактических параметров в виде

(*имя_указателя)(список_фактических_параметров);

Например:

void error(char* p) { /* тело функции */ }

void (*efct)(char*);

// указатель на функцию

void f()

 

 

 

{

efct = &error;

//

efct указывает на

error

 

(*efct)("error");

//

вызов error через

efct

}

 

 

 

 

Чтобы вызвать функцию через указатель, надо сначала этот указатель разыменовать, например (*efct). Поскольку операция вызова функции имеет более высокий приоритет, чем операция разыменования *, то нельзя писать просто *efct("error").

У указателей на функции типы параметров описываются аналогично функциям. В присваиваниях указателя должно соблюдаться точное соответствие полного типа функ-

ции и параметров. Например:

 

 

 

 

void

(*pf)(char*);

// указатель

на void (char*)

void

f1(char*);

// функция с

интерфейсом void(char*)

pf =

&f1;

//

связывание указателя с

функцией

(*pf)("asdf");

//

вызов функции f1 через

указатель

Правила передачи параметров для непосредственных вызовов функции и для вызовов функции через указатель одинаковы. Удобно определить имя типа указатель-на- функцию с помощью описателя типа typedef. Пример:

typedef int (*SIG_TYP)(); typedef void (*SIG_ARG_TYP); SIG_TYP signal(int SIG_ARG_TYP);

Пример программы, которая в зависимости от кода запроса рассчитывает экранную таблицу точек для функции типа double одной переменной на заданном интервале с помощью функции show, которая имеет одним из аргументов указатель функции. В программе возможен выбор одной расчетной функции из двух: y=sin(x) или z=cos(x).

 

10

 

#include <math.h>

 

 

#include <iostream.h>

 

 

const double max=20;

// Число расчетных

точек

double f(double x);

// прототип первой

расчетной функции

double z(double x);

// прототип второй

расчетной функции

int show(double xn, double xk, double(*y) (double X)); // прототип функции расчета

int main()

 

 

// головная функция

 

{ char ans;

 

 

// переменная ответа на запрос

double Xn, Xk;

 

 

// Начальное и

конечное значение аргумента

cout << "\nXn = ";

 

 

// Запрос на ввод

 

cin >> Xn;

 

 

// Ввод начальной точки

 

cout << "\nXk = ";

 

 

// Запрос на ввод

 

cin >> Xk;

 

 

// Ввод конечной точки

 

do {

 

 

// Начало цикла выбора расчетной функции

 

cout << "\n Выберите функцию для расчета";

// Вывод экранного меню

 

cout << "\n 0 - f(x)";

 

 

 

 

 

cout << "\n 1 - z(x)\n";

 

 

 

 

cin >> ans;

 

 

//

Ввод ответа выбора

} while((ans!='1')&&(ans!='0'));

//

Проверка корректности ответа

switch(ans)

 

 

//

Выбор расчетной функции

{ case '0' : show(Xn,Xk,&f);

 

//

выбор первой функции

 

break;

 

 

 

 

 

 

case '1' : show(Xn,Xk,&z);

 

//

выбор второй функции

 

break;

 

 

 

 

 

};

// конец оператора switch

 

 

return 0;

 

 

//

вывод кода успешного завершения

} // конец головной функции --------------------------------------------------

 

 

 

 

double f(double x)

 

// определение первой расчетной функции

{ return sin(x);

 

// возврат синуса

 

 

} // конец тела функции f --------------------------------------------

 

 

 

 

double z(double x)

 

// определение второй расчетной функции

{ return cos(x);

 

// возврат косинуса

 

 

} // конец тела z ----------------------------------------------------

 

 

 

 

 

int show(double xn, double xk, double (*y)(double X))

// определение функции

{ double hx, xx, yy;

// локальные переменные шага и текущих аргумента и функции

hx=(xk-xn)/(max+1);

// вычисление шага расчета

для заданного числа точек

xx=xn;

// начальная инициализация

аргумента

 

do

{ yy=y(xx);

// начало расчетного цикла

 

 

 

printf("\n X= %6.3f

Y= %6.3f",xx,yy); //

вывод текущей точки

 

xx+=hx;

 

 

//

наращивание аргумента

} // конец функции show

----------------------------------------

 

 

 

 

Возможно использование массивов указателей на функцию. Пример программы, рассчитывающей значение числа X по указанному номеру операции

#include <iostream.h> #include <conio.h>

typedef double (* TPF)(double); // тип указателя на функцию double f(double) #pragma hdrstop

double

f1(double x)

{return 1/x; };

//

Функция расчета

обратного значения

double

f2(double x)

{return x*x; };

//

функция расчета

второй степени

double

f3(double x)

{return x*x*x; };//

функция расчета

третьей степени

TPF vf[]={f1,f2,f3};

 

//

Описание массива функций

int main(int argc, char* argv[])

 

 

 

{ double X;

// Число

 

 

 

int N;

// Номер операции

 

 

 

cout

<< "X="; cin

>> X; // Ввод по

запросу числа

 

cout

<< "N="; cin

>> N; // Ввод по

запросу номера операции

if ((N>=0)&&(N<3)) cout << "Ответ : "

<< vf[N](X); //

контроль номера операции

else

cout << "Ошибка!!!";

 

//

Сообщение об ошибке

getch();

 

 

 

 

 

return 0; }//--------------------------------------------------------------------------

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]