Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Связь между вызывающей и вызываемой функциями
Схема обмена данными между процедурами:
Входные аргументы Выходные аргументы Результат Исходные данные Результаты
Входные параметры Выходные параметры
Возвращаемое значение функции разумно считать специфическим выходным параметром. Механизмы передачи данных Существуют 2 механизма передачи информации между процедурами: по значению и по адресу (ссылке, имени, наименованию). Передача по значению подразумевает копирование аргумента и отправку в вызываемую процедуру его копии. Это означает, что изменить в вызываемой процедуре значение исходного аргумента нельзя! Очевидно, что таким образом можно передавать только входные данные. Во втором механизме передается адрес аргумента и, следовательно, возможно его изменение в вызываемой процедуре. Этот механизм применяется для выходных данных (результатов работы) вызываемой процедуры. В языке C реализован механизм передачи по значению, поэтому для обеспечения возврата результатов выполнения процедур применяются оператор & (найти адрес по имени), * (извлечь содержимое памяти по заданному адресу) и специальные типы переменных, называемые указателями ( pointer ). Указатель – переменная, значением которой является адрес другой переменной. Указатель дает информацию о типе переменной, адрес которой он хранит. Формат определения указателей: <тип> *<имя>[, *<имя>]...; Символ * перед именем в определении переменной говорит о том, что она является указателем. Указатели, как и обычные переменные, могут быть организованы в массивы и входить в состав структур. Пример. int *kol, *nom, x, y, *px; double * rasst, *dlina; .................................. px=&x; y=*px; Это эквивалентно y=x. Более подробно работа с указателями будет рассмотрена в другом разделе. В языке Basic можно реализовать оба механизма передачи аргументов. По умолчанию (без специального указания) используется передача по адресу. Данных, подобных указателям, нет. Прототипы функций (C) Поскольку каждая процедура может транслироваться независимо, в вызывающей процедуре должна быть помещена информация о том, в каком порядке будут передаваться аргументы в вызываемую процедуру, о типах и организации каждого параметра, в том числе и возвращаемого значения. Для этой цели в языках C и C++ применяется конструкция языка, называемая прототипом функции. В языке C употребление прототипа рекомендуется, но не является обязательным, в C++ отсутствие прототипа вызывает ошибку трансляции.
Формат прототипа: <тип><имя>(<тип_параметра>[<имя>][, <тип_параметра>[<имя>]]...); Пример. Прототип функции вычисления определенного интеграла методом трапеций. double trap(double, double, int, double (*)(double)); Вызов функции: ................................................................................. i=trap(0, alfa, 20, f1);/* Без прототипа ошибка: 0 – целое значение*/ ................................................................................. Если типы аргумента и соответствующего параметра не совпадают, то выполняется в соответствии с прототипом допустимое преобразование и в память, выделяемую транслятором этому параметру, попадает уже преобразованное значение. Аналогичные манипуляции производятся при возврате результатов в вызывающую процедуру. Имя параметра в прототипе указывать необязательно, сущесвенно лишь задание его типа. Все библиотечные функции среды разработки имеют прототипы, которые хранятся в специальных заголовочных или, как их еще называют,.h файлах. Способ подключения таких файлов будет рассмотрен ниже. Пример. Все математические функции имеют в качестве параметров и возвращаемого значения данные типа double. Их прототипы хранятся в заголовочном файле math.h. Например, double sin( double ); В Basic при несовпадении типов аргумента и параметра автоматического преобразования нет, поэтому в данном случае происходит ошибка трансляции. Ниже будет показано, как можно дать указание транслятору выполнить такое преобразование. Передача скаляров Возвращаемое значение C Если возвращаемое значение имеет тип не int, то указание типа в заголовке функции обязательно. В подпрограммах для указания типа возвращаемого значения (которого нет) используется ключевое слово void. См. выше. Пример. float max( float a, float b){ ........................ } Basic Тип возвращаемого значения в функциях надо указывать всегда. Если он не указан, то функция возвращает тип variant, который будет рассмотрен в другом разделе. Синтаксис подпрограмм такого указания не требует.
Входные данные C Перед передачей входные аргументы, если требуется, преобразуются в соответствии с прототипом. Пример. Вызывающая процедура Вызываемая процедура float a, max( float, float ); float max( float a, float b){ int b; ......................................................... y=2+3.5*max(a, b); // Целая переменная b преобразуется к типу float } Basic Если есть необходимость застраховаться от возможности изменения входных данных в вызываемой процедуре, то необходимо передавать такие аргументы по значению, т.е. их копии. Для этого в определении процедуры перед таким параметром нужно записать ключевое слово ByVal. Пример. function Max(ByVal a as double, ByVal b as double) as double Для того, чтобы вынудить транслятор выполнять автоматическое преобразование аргумента к типу параметра, достаточно заключить аргумент в скобки. Пример. y=2+3.5*max((a), (b)) Выходные данные C Поскольку в языках C и C++ реализована передача аргументов по значению, то для того, чтобы в вызываемой процедуре можно было изменять значение исходного аргумента, туда необходимо передавать адрес области памяти, где хранится аргумент. При этом функция не может изменить этот адрес, а содержание может. Для получения адреса используется оператор &. Следовательно, соответствующий параметр – указатель!! Пример. Дана матрица {aij}, i,j=1...10. Найти max{aij} и его индексы. float maxmatr(float a[10][10], int * k, int * l){ float max; int i, j; max = a[0][0]; for (*k=*l=i=0; i<10; i++){ for (j=0; j<10; j++){ if (max<a[ i ][ j ]){max=a[ i ][ j ]; *k=i; *l=j; } } } return max; }/* End maxmatr */ Соответствующий фрагмент вызывающей процедуры имеет вид: float maxmatr(float a[ ][10], int *, int*), // Прототип maxim, // Максимальный элемент a[10][10]; // Исходная матрица int m, n; // Ее размеры .................................. maxim=maxmatr(a, & m, & n); Употребление конструкции float a[ ][10] будет пояснено ниже. Те же вычисления можно реализовать в виде подпрограммы. void maxmatr(float a[10][10], int *k, int * l, float * max){ float * max; ...................... Также везде надо заменить max на *max и убрать инструкцию return. Пример. Функция scanf: список данных – это выходные аргументы, поэтому при обращении надо использовать адреса (&), printf: список данных – входные аргументы, поэтому используются значения. Basic Поскольку по умолчанию аргументы передаются по адресу, то никаких ухищрений не требуется. Если изменить значение аргумента в вызываемой процедуре, то оно сохранится после возврата. Передача массивов C Если аргумент процедуры – массив, то используется механизм передачи по адресу. При этом в список аргументов включается имя массива, в вызываемую процедуру передается адрес первого элемента (с нулевыми индексами) и массив некопируется в локальную память функции. При описании float a[10][10] обращение вида: <имя_функции>(a) эквивалентно обращению: <имя_функции>(& a[0][0]). Следовательно, массивы-параметры занимают память, отводимую в вызывающей процедуре массивам-аргументам, поэтому в вызываемой процедуре допустимы описания вида float b[], a[][10]; Длины всех измерений, кроме первого, надо задавать, чтобы правильно извлечь из памяти значения нужного элемента массива (см. формулу в параграфе "Распределение массивов"). Допустимо даже несоответствие размерностей аргумента и параметра. Пример. Аргументы Параметры float a[5][5], b[36]; float a[ ], b[ ][6]; Пример. Вычислить: z=uТbu, где {ui]}, i=1...4; {bij]}, i,j=1...4.
/* Вычисление квадратичной формы */ void main( void ){ float u[4], /* Входной вектор */ b[4][4], /* Входная матрица */ v[4], /* Вектор b*u */ z, /* Результат */ scalar( float u[ ], float v[ ]); /*Скалярное произведение векторов */ int i, j; /* Умножение матрицы на вектор */ void matrix(float b[ ][4], float u[ ], float v[ ]); printf("Исходный вектор:\n"); for (i=0; i<4; i++){ scanf("%f", & u[ i ]); } printf("Исходная матрица:\n"); for (i=0; i<4; i++){ for (j=0; j<4; j++){ scanf("%f", & b[ i ][ j ]); } } matrix(b, u, v); z=scalar(v, u); printf("\n\n\nКвадратичная форма равна %.5g\n", z); }/* End main */ /* Умножение матрицы на вектор */ void matrix(floa t a[ ][4], float x[ ], floa t y[ ]){ int i, j; for (i=0; i<4; i++){ for (y[ i ]=j=0; j<4; j++){ y[ i ] += a[ i ][ j ]*x[ j ]; } } }/* End matrix */ /* Скалярное произведение векторов */ float scalar (float x[ ], float y[ ]){ int i; float z; for (z=i=0; i<4; i++){ z+=x[ i ]*y[ i ]; } return z; }/* End scalar */ Basic Массивы передаются также по адресу, поэтому изменение их в вызывающей процедуре затруднений не вызывает. Дальнейший материал относится только к языкам C и C++. В языке Basic подобных средств нет. Передача функций В этом разделе рассмотрим передачу в качестве аргумента имени функции. Этот специфический вид аргумента позволяет придать программе универсальность. Пример. Найти y=min(f(x)), где {xi}, i=1...n. Существует множество методов нахождения экстремума функции многих переменных, практически не зависящих от вида функции, минимум которой отыскивается. Сопряжение, т.е. имя функции со списком аргументов, min_fun(x, n, dx, eps, f) практически одинаково для различных методов. Здесь вектор (одномерный массив) x является одновременно и входным параметром (начальное приближение), и выходным (найденная точка минимума); n – число координат; dx – начальный шаг поиска; eps – точность нахождения минимума; f – имя минимизируемой функции. Передаваемое значение является адресом функции. Следовательно, соответствующий параметр – указатель на функцию. Это специфический объект, характерный только для языков C и С++. Формат объявления: [<тип>](*<имя>)(); Чтобы при вызове в вызывающей процедуре имя функции-аргумента не рассматривалось бы транслятором как простая переменная, необходимо в ней объявить прототип минимизируемой функции: float f1(float [ ]), min_fun(float [ ], int, float, float, float (*)()), z; .......................... z=min_fun(s, l, delta_x, epsilon, f1); Вызываемая процедура: float min_fun(float x[ ], int n, float dx, float eps, float (*f)()){ .......................... } Следует раличать записи: [<тип>] *f( void ); и [<тип>](*f)( void ); Первая – прототип функции без параметров, возвращающей указатель на <тип>, вторая – прототип указателя на функцию, возвращающей значение данного типа.
Пример. Вычислить и напечатать таблицу функции: Интеграл вычислять методом трапеций. /* Вычислить таблицу y=f(alfa) */ void main(void){ double f1(double), // Подинтегральная функция y, // Значение интеграла alfa, // Параметр trap(double, double, int, double (*)()); // Метод трапеций / for (alfa=2; alfa<3.05; alfa+=.1){ y=trap(.15, alfa, 20, f1); printf("%10cальфа=%.1lf интеграл=%.6lf\n", ' ', alfa, y); } } // End main /* Интегрирование методом трапеций */ double trap(double a, // Нижний предел интегрирования double b, // Верхний -------------------- int k, // Число элементарных интервалов double (*f)()){ // Подинтегральная функция double dx, // Размер элементарного интервала t; int i; dx=(b-a)/k; t=((*f)(a)+(*f)(b))/2; for (i=1; i<k; i++){ t += (*f)(a+i*dx); } return dx*t; } /* End trap */ /* Подинтегральная функция */ double f1 (double x){ return exp(x)*cos(pow(x, 3));//Без прототипов все эти функции возвращают // int } /* End f1 */ Вопросы для самопроверки и контроля Вопросы для самопроверки 1. Что такое блок? 2. Есть ли в языке Basic главная процедура? 3. В каком языке не определено понятие подпрограммы? 4. Что такое указатель на функцию? 5. Чем являются выходные скалярные параметры в языке C? 6. Что передается в вызываемую процедуру, если аргумент – имя массива? Контрольные вопросы 1. Чем отличается статическое и динамическое распределение памяти? 2. Что является минимальным элементом структуры программы в языке C? 3. Зачем нужны процедуры? 4. В чем отличие передачи аргументов по значению от передачи по адресу? 5. Перечислите различия в инструкциях возврата значения функции в языках Basic и C. 6. Является ли возвращаемое значение функции выходным параметром? ПРЕПРОЦЕССОР Этот раздел касается только языков C и C++. Препроцессор – это специальная программа, обрабатывающая текст приложения до этапа его трансляции. Основные функции: определение символических констант и включение файлов. В отличие от инструкций управляющие конструкции препроцессора называют директивами (признак директивы: символ "#" в первой позиции). Действие директивы (область действия) распространяется до конца файла, содержащего текст программы (если не встретится специальная отменяющая директива). Директивы могут располагаться в произвольном месте программы.
|
||||||||
Последнее изменение этой страницы: 2017-02-08; просмотров: 322; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.146.105.194 (0.104 с.) |