Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: ТОП 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 ); Первая – прототип функции без параметров, возвращающей указатель на <тип>, вторая – прототип указателя на функцию, возвращающей значение данного типа. Пример. Вычислить и напечатать таблицу функции: Интеграл вычислять методом трапеций.
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; просмотров: 424; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 216.73.216.196 (0.011 с.) |