Справочник от Автор24
Поделись лекцией за скидку на Автор24

Функции и многофайловые программы в Си

  • 👀 459 просмотров
  • 📌 412 загрузок
Выбери формат для чтения
Загружаем конспект в формате pdf
Это займет всего пару минут! А пока ты можешь прочитать работу в формате Word 👇
Конспект лекции по дисциплине «Функции и многофайловые программы в Си» pdf
Лекция 2. Функции и многофайловые программы в Си 2.1. Общие сведения о подпрограммах и функциях Функции являются частным случаем подпрограмм. Подпрограмма - автономно оформленный алгоритм, который может быть использован другим алгоритмом. Подпрограммы (или аналогичные им конструкции) имеются во всех алгоритмических языках. Их использование позволяет избежать повторного программирования одинаковых (с точностью до обозначений и констант) частей алгоритма, увеличивает наглядность программ (за счет укрупнения операторов), упрощает разделение труда между несколькими программистами, делает возможным создание библиотек типовых алгоритмов, упрощает отладку программ. Использование подпрограмм естественно при разработке алгоритмов методом нисходящего проектирования: задача порождает подзадачи, которые удобно оформить как подпрограммы. Главным вопросом, который следует решить при проектировании подпрограмм, является вопрос о способе передачи данных между подпрограммой и программой. В любом алгоритмическом языке существует два основных способа передачи данных: через список параметров подпрограммы и через глобальные переменные (общие области, внешние имена). Первый способ дает возможность подстановки, т. е. передачи в подпрограмму при каждом обращении к ней нового параметра. В список параметров подпрограммы включаются переменные, значения которых должны быть переданы из программы в подпрограмму и из подпрограммы в программу (т.е. "исходные" и "выходные" 1 переменные для подпрограммы). Во всех алгоритмических языках при использовании подпрограмм выделяются два момента: описание подпрограмм и обращение к ним (вызов). Под описанием подпрограммы понимается оформление ее алгоритма особым образом, так чтобы любая программа (или подпрограмма) могла его активизировать и выполнить над своими данныКавычки присутствуют потому, что в вводу и выводу эти термины здесь отношения не имеют 1 ми. Под обращением к подпрограмме понимается активизация подпрограммы; программа передает управление подпрограмме и пересылает ей данные, подпрограмма выполняет свой алгоритм и возвращает управление программе. При описании подпрограммы в списке параметров записываются формальные параметры, которые используются только в подпрограмме и при обращении к ней заменяются на фактические параметры, т. е. на соответствующие данные программы 2. Фактические параметры должны соответствовать формальным по количеству, порядку перечисления и типу. Существует два способа замены формальных параметров на фактические:"по ссылке" (call-by-reference) и "по значению" (call-byvalue). Передача параметра "по ссылке" означает передачу в подпрограмму адреса фактического параметра. При этом любое изменение формального параметра внутри подпрограммы есть изменение соответствующего фактического параметра. Поэтому константы и выражения нельзя передавать "по ссылке" - они могут измениться. Передача параметров "по значению" означает пересылку значения фактического параметра в ячейку, соответствующую формальному параметру, при обращении к подпрограмме. Это обеспечивает сохранность величины фактического параметра. Изменение формального параметра внутри подпрограммы никак не отражается на фактическом. "По значению" нельзя передавать переменные-результаты подпрограммы; их следует передавать "по ссылке". Если фактическое значение может быть константой или выражением, то следует использовать замену "по значению". Заметим, что при передаче "по ссылке", как правило, экономится память, так как формальные параметры не копируют фактические; поэтому массивы обычно передаются "по ссылке". При передаче "по значению" обычно экономится время работы подпрограммы (за счет отсутствия переадресации при обращении к формальным параметрам). Здесь имеется некоторая аналогия с формулой. Вместо обозначений, участвующих в формуле можно подставить другие обозначения, числа или выражения. 2 2 В большинстве алгоритмических языков имеется два вида подпрограмм: подпрограммы общего назначения (они часто называются процедурами) и функции. Функции следует использовать, если подпрограмма имеет одно выходное значение; классическими примерами функций во всех алгоритмических языках являются стандартные математические функции: синус, косинус, абсолютная величина и т. д. Имя функции является не только именем ее алгоритма, но и именем результата; это имя можно использовать в выражениях (как sin, cos, abs, и т. д.) Говорят, что функция через свое имя возвращает единственный (или основной) результат. Си, пожалуй, является исторически первым языком программирования, где отсутствуют подпрограммы общего назначения (есть только функции). Конечно, существуют специальные приемы, которые позволяют на базе функции Си получить конструкцию, аналогичную процедуре. 2.2. Функции СИ Как всегда при изучении подпрограмм, рассмотрим два вопроса: описание функций Си и обращение к ним. 2.2.1. Описание функции Общий вид описания функций: Тип Имя_Функции(Список_Формальных_Параметров) { Описания данных Операторы return(выражение, возвращаемое функцией) } Конструкция Тип Имя_Функции(Список_Формальных_Параметров) называется заголовком, остальная часть - блоком функции. Для того, чтобы запрограммировать вызов функции, достаточно знать заголовок. В заголовке тип - тип возвращаемого значения; если он отсутствует, то по умолчанию принимается int. В операторе return указывается выражение, значение которого присваивается имени функции; этот основной или единственный результат функции. В качестве типа 3 может использоваться слово void3; в этом случае значение через имя функции не возвращается, т. е. имеем аналог подпрограммы общего назначения; тогда, естественно, return не нужен. Имя_Функции имеет два смысла: 1) имя алгоритма; более строго, имя функции - это особый указатель (указатель на функцию), его значение - адрес точки входа в функцию; 2) возвращаемое значение (имя функции можно использовать в выражениях). Заметим, что использование имени функции внутри ее блока рассматривается как обращение функции к ней самой (рекурсивное обращение). После имени функции обязательно должны идти скобки со списком параметров (если этот список не пустой). Использовать имя функции в выражениях как имя простой переменной нельзя. Если это необходимо по смыслу задачи, например, для накапливания результата, то следует завести промежуточную переменную и использовать ее вместо имени функции, а затем ее значение присвоить имени функции с помощью оператора return (см. пример 2 п.2.2.4). Если имя функции main, то это главная функция, она первой получает управление после запуска программы; main обязательно присутствует в программе, и только один раз. В настоящем пособии рассматриваем main без параметров, хотя Си позволяет разрабатывать программы с параметрами. Список формальных параметров.имеет вид: тип1 параметр1, тип2 параметр2,..., типN параметрN В список формальных параметров во всех алгоритмических языках включаются переменные, которые передаются из главной (или другой вызывающей) функции в вызываемую функцию и из вызываемой функции в вызывающую. Иначе говоря, формальные параметры — это “вход” и “выход” функции. У формальных параметров-массивов при описании можно не указывать число значений первого индекса. Void (англ.) -пустой, свободный, незанятый; в Си это ключевое слово используется в двух значениях: либо отсутствующее значение, либо любой тип. 3 4 Если список формальных параметров отсутствует или вместо него стоит слово void, то нет передачи значений в функцию. Замена формальных параметров на фактические в Си происходит только “по значению”, поэтому у переменных-результатов функции в список формальных параметров следует включать адрес (вспомните функцию scanf –п. 1.3.3). Имя массива является адресом начала массива, поэтому массивы в Си передаются только "по ссылке", передачу массивов “по значению” осуществить невозможно. 2.2.2. Обращение к функции Существует два способа обращения к функции: 1) как к процедуре общего назначения, т. е. можно для вызова функции использовать оператор Имя_Функции(Список_Фактических_Параметров) 2) как к функции, т. е. можно указатель функции Имя_Функции(Список_Фактических_Параметров) - использовать в выражениях. Для функции типа void допустим только первый способ. Заметим еще раз, что фактические параметры должны соответствовать формальным по количеству, порядку перечисления и типу. 2.2.3. Место описания функции в программе Функция не может быть описана внутри другой функции. Функция (как всё в программе) должна быть описана до использования; если это не так, то до использования необходимо поместить прототип (шаблон) функции. Самый простой и лучший вариант шаблона: заголовок функции, в котором могут отсутствовать имена формальных параметров (но присутствуют их типы). Формальное отличие шаблона от заголовка функции состоит в присутствии точки с запятой после скобки, закрывающей список формальных параметров. Наличие шаблона позволяет компилятору контролировать соответствие типа возвращаемого функцией значения и соответствие количества и типов формальных и фактических параметров. 5 Общеупотребительная практика состоит в соблюдении следующих правил: 1) надо ставить шаблоны в начало программного файла; 2) удобно записывать часто употребляемые шаблоны в заголовочный файл, подключаемый к программе директивой include препроцессора (см. п. 2.3.3). Обратите внимание, что в всех рассмотренных примерах Си-программ с помощью директивы include подключались именно файлы, содержащие шаблоны библиотечных функций, т. е. заголовочные файлы. 2.2.4. Примеры программ, использующих функции Пример 1. Даны две матрицы: а из 3-х строк и 5 столбцов (в дальнейшем будем условно записывать а[3*5]) и b[7*3]. Вычислить минимальные значения для каждой строки каждой из этих матриц. Естественно, вычисление минимальных значений строк произвольной матрицы следует оформить как функцию (назовем ее minmatr), а затем применить ее два раза к конкретным (фактическим) матрицам а и b. Алгоритм ввода одинаков для матриц а и b, поэтому ввод также оформим как функцию (назовем ее matrin). Аналогично вывод массива результатов будет процедура masout. Поясним, как составляются заголовки на примере функции minmatr. Функция имеет столько результатов, сколько строк у матрицы, все они равноправны, поэтому нет причины передавать один из них через имя функции, и, следовательно, тип функции - void. В список формальных параметров передаются "входные" данные для функции: матрица а и ее размеры (n - число строк, m - число столбцов), и "выходные" данные: min - массив минимальных значений строк. Заметим, что обозначения, принятые в одной функции (a, n,m,min) никоим образом не связаны с обозначениями в других функциях (в том числе main), т. е. программирование функций выполняется автономно друг от друга. Переменная min - результат работы функции, поэтому в список формальных параметров должен быть включен ее адрес. Так как min является массивом, то это требование удовлетворяется автоматически, без применения специальных операций. 6 Типы фактических и формальных параметров должны совпадать, поэтому размеры формальных массивов должны подходить и для матрицы а, и для матрицы b. Чтобы удовлетворить этому требованию, используем максимальный второй размер (число столбцов), подходящий и для а, и для b, т. е. память под массивы отводится с избытком. Первый размер - число строк - в списке формальных параметров можно не указывать. Получаем заголовок: void minmatr(float a[ ][5],int n,int m,float min[ ]). Дальнейшие комментарии приведены в тексте программы. Блоксхема функции minmatr приведена на рис. 10. Программа: #include #include void masout(float a[ ],int n,char c);/* если стоит ";", то это шаблон*/ /*первый размер у массивов-формальных параметров можно*/ /* не указывать, второй задан по максимуму*/ void matrin(float [ ][5],int n,int m,char с);/* c -имя матрицы*/ /* используется при выводе пояснительных фраз и приглашений*/ void minmatr(float [ ][5],int n,int m,float min[ ]); /* n и m во всех функциях передаются по значению, т. к. их*/ /*фактические значения - константы*/ void main() {float a[3][5],b[7][5], mina[3], minb[7]; matrin(a,3,5,'a'); matrin(b,7,3,'b'); minmatr(a,3,5,mina); minmatr(b,7,3,minb); masout(mina,3,'a'); masout(minb,7,'b'); } void minmatr(float a[][5],int n,int m,float min[]) {int i,j; for (i=0; i #include float min(float a[], int n); void masin(float a[],int n,char c); void main() {float a[5],b[8],srmin; masin(a,5,'a'); masin(b,8,'b'); srmin=(min(a,5)+min(b,8))/2; printf("Полусумма минимумов pавна %4.1f\n",srmin); } float min(float a[], int n) {int i; float m;/*переменная m заменяет min, т. к. использование*/ m=a[0]; /*предполагает рекурсивное обращение к функции*/ for (i=1;i #include void kv_ur(float a, float b, float c, float *d, float *x1, float *x2); // *d - дискриминант // если *d<0, то *х1 и *х2 - действительная и мнимая часть комп. коpней, // иначе *х1 и *х2 - два действительных коpня. void main() {float a, b, c, d, x1, x2; printf("введите коэффициенты a,b,c уpавнения\n", a, b, c); scanf("%f%f%f", &a, &b, &c); kv_ur(a, b, c, &d, &x1, &x2); if (d<0) {printf("уpавнение имеeт комплексно-сопpяженные коpни\n"); printf("действ. часть =%f , мнимая часть =%f\n", x1,x2); } else {printf("уравнение имеeт два действительных коpня\n", "x1=%fx2=%f\n", x1,x2); } } void kv_ur(float a, float b, float c, float *d, float *x1, float *x2) {*d=b*b-4*a*c; if(*d<0) {*x1=-b/2/a; *x2=sqrt(-*d)/2/a; 11 } else {*x1=-b/2/a+sqrt(*d); *x2=-b/2/a-sqrt(*d); } } 2.3. Краткие сведения о препроцессоре Си Получение исполняемой программы (с расширением .exe) из исходного текста на языке Си происходит в несколько этапов. На самом первом этапе с исходным текстом программы работает специальная программа - препроцессор. Основная цель препроцессора - закончить формирование исходного текста программы на Си. Затем окончательный текст программы подвергается компиляции, в результате которой генерируется объектный файл. После этого компоновщик формирует загрузочный модуль. Обычно препроцессор вызывается компилятором автоматически. Однако при необходимости можно использовать автономную программу препроцессора CPP.EXE. Результатом ее работы является окончательно сформированный препроцессором файл со всеми включенными файлами и другими выполненными директивами препроцессора. Возможный вид команды вызова препроцессора: СРР -Р- IДиректория ИмяИсхФайла где ИмяИсхФайла - имя файла с расширением .с или .срр, -Р- отключение опции вывода номеров строк в результирующем файле, IПуть - опция указания директории, где находятся включаемые файлы. О других опциях программы СРР можно узнать, вызвав ее без параметров. Результатом работы препроцессора является текстовый файл с тем же именем, что и исходный, но с расширением .i. Директивы препроцессора позволяют заменять сокращения (так называемые макро) на полный текст, отыскивать необходимые файлы и вставлять в программу их содержимое, влиять на условия компиля- 12 ции и выполнять некоторые другие функции (распознавать модель памяти, выводить сообщения об ошибках и др.). Директивы препроцессора (иногда называемые командными строками) начинаются со знака # в первой позиции строки. 2.3.2.Директива макроопределения #define Директива #define определяет макро (макрос, макроопределение). Общий вид директивы: #define Имя_Макро Последовательность_Символов Каждое вхождение Имя_Макро заменяется препроцессором на Последовательность_Символов. Процесс замены называется расширением макро. Расширению не подлежат группы символов, входящие в состав комментариев, строковых литералов и символьных констант. Директиву #define можно отменить директивой #undef: #undef ИмяМакро После директивы #undef ИмяМакро становится неопределенным. Наиболее распространенное применение #define - это обозначение часто встречающихся констант, числовых и строковых. Например, #define N 100 #define PRIGL "Введите исходные данные" Принято для обозначения макро использовать большие буквы, так же как малые для имен переменных программы (но это не обязательно). Если последовательность символов не помещается на одной строке, то для переноса используется символ \: #define PRIMER "Наш текст не помещается\ на одной строке" Макро может иметь параметры. Каждый раз при расширении параметры заменяются параметрами макро в программе. Общий вид описания макро с параметрами: #define Имя_Макро(Список_Параметров) Тело_Макро Пример: #define square(x) ((x)*(x)) /*макро с формальным параметром*/ 13 ... int i,j; ... j=square(i); /*расширяется в j=((i)*(i)) */ Аргумент макро необходимо заключать в круглые скобки, чтобы вместо формального параметра можно было подставлять выражение. Пример "неприятности" при отсутствии скобок: #define square(x) x*x /*макро с форм. параметром без скобок*/ ... int i,j,l;... j=square(i+l);/*расширяется в j=i+l*i+l -нет перемножения аргументов*/ Макро с параметрами похожи на процедуры - но только на первый взгляд! Отличия макро от процедур: обращение к процедуре генерирует в объектном модуле команду безусловного перехода с возвратом и передачу параметров, обращение к макро приводит к вставке в исходную программу тела макро; поэтому применение макро увеличивает код программы, но экономит время выполнения (за счет отсутствия пересылки параметров). Обычно не рекомендуется использовать макро вместо процедур, так как при применении макро отсутствует всякий контроль правильности подстановки параметров. 2.3.3. Директива #include включения файлов Директива #include позволяет включать в исходную программу любые текстовые файлы. Формы директивы: #include <СпецификацияФайла> #include "СпецификацияФайла" #include ИмяМакро Первая форма директивы предполагает, что включаемый файл будет отыскиваться в стандартных директориях (это как бы указание системе «ищи, где сама знаешь»). Вторая форма указывает, что поиск файла осуществляется по маршруту, заданному в " "; если файл там не найден, то просматриваются стандартные директории. Третья форма показывает, что существует макроопределение, заменяющее Имя_Макро на спецификацию файла в угловых скобках или двойных кавычках. 14 2.3.4. Директивы условной компиляции Они позволяют производить выборочную компиляцию программы. Самый простой вид такой директивы: #if ЛогическоеВыражение TRUE-секция #else FALSE-секция #endif Пример: В зависимости от того, определен ли макрос NAME, регулируется значение макроса BUF. #ifdef NAME #define BUF 135 #else #define BUF 80 #endif 2.4. Многофайловые СИ-программы 2.4.1. Структура программы на Си. Область действия переменных Программа на Си состоит из одного или нескольких файлов (текстовых). Исходные текстовые файлы программы содержат описания функций, одна из которых обязательно main, прототипы (шаблоны) функций, директивы препроцессора и описания глобальных переменных, констант, типов (т. е. описания глобальных имен, отличных от функций). Локальное имя - описанное внутри функции; может использоваться только в этой функции. Глобальное имя - описанное вне функций; доступно в части программы от точки описания до конца файла. Существует термин область действия имени. Это часть программы, в которой понятие, обозначенное этим именем, доступно. Таким образом, область действия локального имени - блок функции, в которой оно объявлено; глобального - от места объявления до конца файла. Если требуется воспользоваться глобальным именем вне области его действия (в области от начала файла до объявления имени 15 или в другом файле), то нужно повторить объявление имени, предварив его описателем extern. Объявление extern не предусматривает распределение памяти; оно лишь делает нужное имя доступным. Пример. файл 1 файл 2 float a; extern float a; int i; f3() main () {a=...; {int i;extern float b; } a=...; b=...; extern int c; } f4() float f1() { a=... {int i; a=... } } f5() float b; {a=...; float f2() } {int i;a=...; b=...; int c; } ... Глобальная переменная а может использоваться во всех функциях файла 1, т. к. она описана в самом начале файла 1; она также доступна всем функциям файла 2, потому что объявление extern float a стоит в начале файла 2. Глобальная переменная i файла 1 недоступна ни одной функции этого файла, так как каждая функция имеет локальную переменную i. Описание int i приводит к выделению ячейки памяти под переменную i каждый раз при входе в блок {...},где стоит это описание; при выходе из блока эта ячейка освобождается. Локальные i доступны только в блоке своей функции, а глобальная i - во всем файле 1, за исключением этих функций. Глобальная переменная b файла 1 может использоваться в функции f2, т. к. объявлена до описания f2. В функциях, описанных выше объявления b, эта переменная недоступна. Объявление extern float b в блоке функции main, позволяет этой функции использовать b; тем не менее, для f1 переменная b остается недоступной. 16 В файле 2 вместо двух объявлений int c и extern int c можно было бы оставить только int c, поместив его на место extern int c. Рекомендации. 1. По возможности описания глобальных переменных, в том числе и extern, следует ставить в начало файла. 2. Не стоит делать глобальными промежуточные переменные (например, i в программе, приведенной ниже), потому что: 1) это делает подпрограмму менее универсальной, так как приводит к появлению непонятного пользователю "стыка" - промежуточной глобальной переменной; 2) приводит к неэкономному расходованию памяти, так как глобальные переменные занимают память в течение всего времени работы программы. Однако допустимо использование глобальных переменных для передачи данных между подпрограммами (если не требуется подстановка параметров). Так, если бы в примере 1 п.2.2.4 требовалось обработать одну матрицу, то можно было бы использовать функции без параметров: #include #include void masout(); void matrin(); void minmatr(); float a[3][5],min[3]; void main() {matrin(); minmatr(); masout(); } void minmatr () {int i,j; for (i=0; i<3; i++) {min[i]=a[i][0]; for (j=1;j<5; j++) if (a[i][j]
«Функции и многофайловые программы в Си» 👇
Готовые курсовые работы и рефераты
Купить от 250 ₽
Решение задач от ИИ за 2 минуты
Решить задачу
Помощь с рефератом от нейросети
Написать ИИ
Получи помощь с рефератом от ИИ-шки
ИИ ответит за 2 минуты

Тебе могут подойти лекции

Смотреть все 588 лекций
Все самое важное и интересное в Telegram

Все сервисы Справочника в твоем телефоне! Просто напиши Боту, что ты ищешь и он быстро найдет нужную статью, лекцию или пособие для тебя!

Перейти в Telegram Bot