|
Программирование >> Элементы языков с и с++
Глава 4 Создание и использование функций в процессе программной реализации алгоритмов часто возникает необходимость выполнения повторяющихся действий на разных группах данных. Например, требуется вычислять синусы заданных величин или начислять заработную плату работникам. Ясно, что неразумно всякий раз, когда надо вычислить синус какого-то аргумента или начислить зарплату какому-то работнику, создавать заново соответствующую программу именно под конкретные данные. Напрашивается вывод, что этот процесс надо как-то параметризовать, т. е. создать параметрическую программу, которая могла бы, например, вычислять синус от любого аргумента, получая извне его конкретное значение, или создать программу, которая бы начисляла зарплату любому работнику, получая данные конкретного работника. Такие программы, созданные с использованием формальных значений своих параметров, при передаче им конкретных значений параметров возвращают пользователю результаты расчетов. Их называют функциями по аналогии с математическими функциями. Если в математике определена некая функция у =J{x\,X2,...,x,w), то на конкретном наборе данных {х\\,Х2\,...,Х!\} эта функция возвратит вычисленное ею значение >! = Дд:1, .V21,..., jc.vi). В данном случае можем сказать, что аргументы дг1, Х2,..., Xfj- это формальные параметры функции f(), а хц, -21,-.., хц\ - их конкретные значения. Функция в языке С объявляется почти аналогичным образом: задается тип возвращаемого ею значения (из рассмотренного материала мы знаем, что переменные могут иметь типы int, float, long и т.д.). Тип значения, возвращаемого функцией, может быть таким, как и тип переменных. После задания типа возвращаемого значения задается имя функции (как и для математической функции). Затем в круглых скобках указываются ее аргументы - формальные параметры, каждый из которых должен быть описан ( Примечание В языке С типом функции может быть специальный тип voido, когда функция ничего не возвращает. Такая функция вырождается в подпрограмму - конструкцию, которая просто производит некоторые вычисления. Далее формируется тело функции- программный код, реализующий тот алгоритм, который и положено выполнять определяемой функции. Например, объявим условную функцию расчета зарплаты одного работника: float salary(int TabNom, int Mes) /*здесь должен быть программный код расчета зарплаты*/ return(значение вычисленной зарплаты); Тип возвращаемого значения - float, т. к. сумма зарплаты, в общем случае, число не целое. Имя функции- salary. У функции два формальных параметра и оба целого типа: табельный номер работника и номер месяца, за который должен производиться расчет. Особым признаком функции является наличие оператора returno, который возвращает результат расчетов. После того как такая функция разработана, пользоваться ею можно так же, как мы пользуемся математической функцией. Для данного примера мы смогли бы записать: float у; y=salary(1001,12); или: float y=salary(1001,12); или: int tn=1001; int ins=12; float y=salary(tn.ms); Bo всех случаях при обращении к функции мы в ее заголовочную часть подставляли вместо формальных параметров их конкретные значения. Каков внутренний механизм параметризации программы и превращения ее в функцию? Мы описываем в заголовке формальные параметры и затем в теле функции используем их при создании программного кода так, как будто известны их значения. Это возможно благодаря тому, что компилятор, когда начнет компилировать функцию, соотнесет с каждым ее параметром определенный ад- так, как если бы он описывался в программе самостоятельно вне функции. Это только первая часть объявления функции в языке С. Создание некоторых функций Перейдем теперь от столь пространного введения к созданию некоторых функций и проверке их работы в основной программе. рес некоторого места в так называемой стековой памяти, созданной специально для обеспечения вызова подпрограмм из других программ. А функция - это ведь тоже своего рода подпрограмма, да еще и возвращающая некоторое значение, а не только получающая какой-то результат расчетов. Размер такой адресованной области для каждого параметра определяется типом описанного формального параметра. Выделяется место и для будущего возвращаемого результата. В теле функции будет построен программный код, работающий, когда речь идет о формальных параметрах, с адресами не обычной, а стековой памяти. Когда мы, обращаясь к функции, передаем ей фактические значения параметров, то эти значения пересылаются по тем адресам стека, которые были определены для формальных параметров (т. е. кладутся на полочки в стеке, отведенные для формальных параметров). Но программный код тела функции как раз и работает с этими полочками , содержащими параметры. Поскольку тело строится так, что оно работает с полочками , то остается только класть на них разные данные и получать соответствующие результаты. Вот это и осуществляется, когда мы каждый раз передаем функции конкретные значения ее параметров. Отсюда можно сделать выводы: поскольку передаваемые функции значения пересылаются в стековую память (т. е. там формируется их копия), то сама функция, работая со стеком и ни с чем другим, не может изменять значения переменных, которые подставляются в ее заголовочную часть вместо формальных параметров. В примере мы писали float y=saiary(tn,ms), подставляя вместо формальных параметров таьыот и мез значения переменных tn и IIIS. И мы утверждаем, что значения tn и ms не изменятся. Если же передавать функции не значения переменных, а их адреса, то переменные, адреса которых переданы в качестве фактических параметров, смогут изменяться в теле функции. Ведь по адресу можно записать все что угодно, где бы он ни находился (в стеке или в обычной памяти). Функции в основной программе должны описываться до начала самой программы: либо их текст располагается до tmain о, либо он подключается к tmain о оператором ttinclude (который тоже стоит раньше tmaino в тексте), если функция расположена где-то в другом файле.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |