Функция – это именованная последовательность описаний и операторов, выполняющая какое-либо законченное действие. Функция может принимать параметры и возвращать значение.
Любая программа на C++ состоит из функций, одна из которых должна иметь имя main (с нее начинается выполнение программы). Функция начинает выполняться в момент вызова. Любая функция должна быть объявлена и определена. Как и для других величин, объявлений может быть несколько, а определение только одно. Объявление функции должно находиться в тексте раньше ее вызова для того, чтобы компилятор мог осуществить проверку правильности вызова.
Объявление функции (прототип, заголовок, сигнатура) задает ее имя, тип возвращаемого значения и список передаваемых параметров.
[ класс ] тип имя ([ список_параметров ])[ throw ( исключения )];
int sum(int a, int b); // объявление функции
Определение функции содержит, кроме объявления, тело функции, представляющее собой последовательность операторов и описаний в фигурных скобках:
Программирование на Си. #5. Функции.
[ класс ] тип имя ([ список_параметров ])[ throw ( исключения )]
int sum(int a, int b) < return (a + b);>// определение функции
Рассмотрим составные части определения.
С помощью необязательного модификатора класс можно явно задать область видимости функции, используя ключевые слова extern и static :
• extern – глобальная видимость во всех модулях программы (по умолчанию);
• static – видимость только в пределах модуля, в котором определена функция.
Тип возвращаемого функцией значения может быть любым, кроме массива и функции (но может быть указателем на массив или функцию). Если функция не должна возвращать значение, указывается тип void .
Имя должно быть уникальным, если используется модификатор extern . Желательно, чтобы имя несло смысловую нагрузку (отражало действия выполняемые функцией).
Список параметров определяет величины, которые требуется передать в функцию при ее вызове. Элементы списка параметров разделяются запятыми. Для каждого параметра, передаваемого в функцию, указывается его тип и имя (в объявлении имена можно опускать).
В заголовке функции можно задать список исключений, которые она может прямо или косвенно порождать. Поскольку заголовок является интерфейсом функции, указание в нем списка исключений дает пользователям функции необходимую информацию для ее использования, а также гарантию, что при возникновении непредвиденного исключения эта ситуация будет обнаружена.
Типы исключений перечисляются в скобках через запятую после ключевого слова throw , расположенного за списком параметров функции, например:
void fl() throw (int, const char*) < /* Тело функции */ >
Функция fl должна генерировать исключения только типов int и const char *. Функция f 2 должна генерировать только исключения типа указателя на класс Oops или производных от него классов.
Если ключевое слово throw не указано, функция может генерировать любое исключение. Пустой список означает, что функция не должна порождать исключений:
Что такое функции в программировании?
void f () throw ()
Указание списка исключений ни к чему не обязывает – функция может прямо или косвенно породить исключение, которое она обещала не использовать. Эта ситуация обнаруживается во время исполнения программы и приводит к вызову стандартной функции unexpected , которая по умолчанию вызывает функцию terminate . Функция terminate по умолчанию вызывает функцию abort , которая завершает выполнение программы.
В определении, в объявлении и при вызове одной и той же функции типы и порядок следования параметров должны совпадать. На имена параметров ограничений по соответствию не накладывается, поскольку функцию можно вызывать с различными аргументами, а в прототипах имена компилятором игнорируются (они служат только для улучшения читаемости программы). Тип возвращаемого значения и типы параметров совместно определяют тип функции.
Вызов функции
Для вызова функции в простейшем случае нужно указать ее имя, за которым в круглых скобках через запятую перечисляются имена передаваемых аргументов. Вызов функции может находиться в любом месте программы, где по синтаксису допустимо выражение того типа, который формирует функция. Если тип возвращаемого функцией значения не void , она может входить в состав выражений или, в частном случае, располагаться в правой части оператора присваивания.
Пример функции, возвращающей сумму двух целых величин:
int sum(int a, int b) < return (a + b);>// определение функции
int a = 2, b = 3, c, d;
с = sum(a, b); // вызов функции
Определение функции должно находится до функции main (). Все величины, описанные внутри функции, а также ее параметры, являются локальными. Областью их действия является функция. При вызове функции, как и при входе в любой блок, в стеке выделяется память под локальные автоматические переменные. Кроме того, в стеке сохраняется содержимое регистров процессора на момент, предшествующий вызову функции, и адрес возврата из функции для того, чтобы при выходе из нее можно было продолжить выполнение вызывающей функции.
При выходе из функции соответствующий участок стека освобождается, поэтому значения локальных переменных между вызовами одной и той же функции не сохраняются. Если этого требуется избежать, при объявлении локальных переменных используется модификатор static :
void f(int a)
static int n = 0;
Статическая переменная n размещается в сегменте данных и инициализируется один раз при первом выполнении оператора, содержащего ее определение. Автоматическая переменная m инициализируется при каждом входе в функцию. Автоматическая переменная р инициализируется при каждом входе в блок цикла. Программа выведет на экран:
Источник: h-l-l.ru
Общие сведения о функциях языка С
Аннотация: В лекции рассматриваются особенности объявления и определений функций, способов задания формальных параметров и типов возвращаемых данных, вызов функций, передача аргументов по значению и по ссылке.
Теоретическая часть
Принципы программирования на языке С основаны на понятии функции. Например, к системным функциям относятся printf() , scanf() , gets() , putchar() и др. Функции – это строительные элементы языка С и то место , в котором выполняется вся работа программы [10.1].
Большие программы обычно состоят из нескольких пользовательских функций и ряда системных функций. Функция – самостоятельная единица программы. Функции повышают уровень модульности программы, облегчают ее чтение, внесение изменений и коррекцию ошибок.
В основе всех программ на языке программирования С лежат одни и те же фундаментальные элементы – функции [10.2]. В частности, функция main() является обязательной для любой программы. Во всех программах С определяется единая внешняя функция с именем main() , служащая точкой входа в программу, то есть первой функцией, выполняемой после запуска программы [10.3].
Ни одна программа в языке С не может обойтись без функций.
Функция в языке С играет ту же роль, что и подпрограммы или процедуры в других языках [10.4]. Каждая функция языка С имеет имя и список аргументов. По соглашению, принятому в языке С, при записи имени функции после него ставятся круглые скобки [10.4]. Это соглашение позволяет легко отличить имена переменных от имен функций.
Рассмотрим модельный пример программы, в которой, кроме функции main() , содержатся еще три функции [10.4].
#include int main(void) /* Главная функция */ < /* Начало тела функции */ function1(); /* вызов первой функции */ function2(); /* вызов второй функции */ function3(); /* вызов третьей функции */ >/* Конец тела функции main() */ /* Начало определения первой функции */ function1() < /* Начало тела первой функции */ /* Операторы первой функции */ /* Конец тела первой функции */ >/* Начало определения второй функции */ function2() < /* Начало тела второй функции*/ /* Операторы второй функции */ /* Конец тела второй функции*/ >/* Начало определения третьей функции */ function3() < /* Начало тела третьей функции*/ /* Операторы третьей функции */ /* Конец тела третьей функции*/ >
В условной (модельной) программе имеются четыре функции: main() , function1() , function2() , function3() . Эти функции не имеют аргументов.
Позднее рассмотрим функции, которые имеют аргументы. Аргументы функции – это величины, которые передаются функции во время ее вызова. Аргумент , стоящий в операторе вызова функции, называется фактическим параметром. Аргументы, стоящие в заголовке функции, называются формальными параметрами. В языке С функция может возвращать значение в вызывающую программу посредством оператора return . Оператор возврата из функции в точку вызова имеет две формы [10.5]:
return; return выражение;
В общем виде функция выглядит следующим образом [10.1]:
возвр-тип имя-функции(список параметров)
Тело_функции – это часть определения функции, ограниченная фигурными скобками и непосредственно размещенная вслед за заголовком функции. Тело функции может быть либо составным оператором , либо блоком [10.1]. В языке С определения функций не могут быть вложенными, т.е. внутри одной функции нельзя объявить и расписать тело другой функции.
Возвращаемый тип возвр-тип функции определяет тип данного, возвращаемого функцией. Например, это могут быть int , float , double и т.д. В случае, когда функция ничего не возвращает, ей присваивается тип void .
Функция может возвращать любой тип данных , за исключением массивов. Список параметров – это список , элементы которого отделяются друг от друга запятыми [10.1]. При вызове функции параметры принимают значения аргументов. Если функция без параметров, то такой пустой список можно указать в явном виде, поместив для этого внутри скобок ключевое слово void . Все параметры функции (входящие в список параметров) должны объявляться отдельно, причем для каждого из них надо указывать и тип, и имя. В общем виде список объявлений параметров должен выглядеть следующим образом [10.1]:
fun(тип имя_перем1, тип имя_перем2. тип имя_перем N)
fun(int i, int j, float k, char str1, char str2)
Рассмотрим пример программы с выводом сообщения не в главной функции main() , а в другой:
#include #include void printMessage (void) < printf(«nt hello, worldn»); return; printf(«nt 123n»); >int main(void)
Результат выполнения программы показан на рис. 10.1.
Рис. 10.1. Вывод сообщения с помощью двух функций
Программа состоит из двух функций: printMessage() и main() . Выполнение программы всегда начинается с функции main() , которую называют еще главной. Внутри функции main() происходит вызов функции printMessage() без параметров. Когда происходит вызов функции , выполнение программы передается непосредственно вызванной функции. Внутри функции printMessage() выполняется только утверждение
printf(«nt hello, worldn»);
Несмотря на то, что в функции printMessage() есть еще одно утверждение printf(«nt 123n») , которое не выполняется, поскольку используется утверждение возврата ( return ) из функции.
В языке С функция введена как один из производных типов .
Формальные параметры в определениях функций могут объявляться в форме прототипа [10.3]. Прототипы дают компилятору возможность тщательнее выполнять проверку типов аргументов [10.1]. Если используются прототипы, то компилятор может обнаружить любые сомнительные преобразования типов аргументов, необходимые при вызове функции, если тип ее параметров отличается от типов аргументов. Компилятор также обнаружит различия в количестве аргументов, использованных при вызове функции, и в количестве параметров функции.
В общем случае прототип функции должен выглядеть таким образом [10.1]:
тип имя_функции(тип имя_парам1, тип имя_парам2. тип им_парамN);
В приведенной выше программе прототип функции printMessage() не использовался, так как сама функция была объявлена до главной функции main() . Для переносимости С -кода в С ++ использование прототипа функции обязательно. Поэтому к хорошему стилю программирования относится использование прототипов функций, поскольку большие программы обычно состоят из нескольких функций, часто расположенных в различных файлах.
Вышеприведенная программа с использованием прототипа функции printMessage() будет выглядеть следующим образом:
#include #include //void printMessage (void);//Прототип функции int main(void) < void printMessage (void); //Прототип функции printMessage(); // Вызов функции printf(«n Press any key: «); _getch(); return 0; >// Определение функции void printMessage (void)
В листинге программы показаны две возможности использования прототипа функции printMessage() . При этом, сама функция printMessage() объявлена после функции main() .
Формальные параметры функции определены в прототипе функции. При обращении к функции используются фактические параметры, называемые аргументами функции.
Список фактических параметров – это список выражений, количество которых равно количеству формальных параметров функции ( исключение составляют функции с переменным числом параметров). Соответствие между формальными и фактическими параметрами устанавливается по их взаимному расположению в списках. Между формальными и фактическими параметрами должно быть соответствие по типам.
Синтаксис языка С предусматривает только один способ передачи параметров – передачу по значениям. Это означает, что формальные параметры функции локализованы в ней, т.е. недоступны вне определения функции и никакие операции над формальными параметрами в теле функции не изменяют значений фактических параметров [10.4].
Передача параметров по значению предусматривает следующие шаги [10.4]:
- При компиляции функции выделяются участки памяти для формальных параметров, т.е. формальные параметры оказываются внутренними объектами функции. При этом для параметров типа float формируются объекты типа double , а для параметров типов char и short int создаются объекты типа int. Если параметром является массив, то формируется указатель на начало этого массива, и он служит представлением массива-параметра в теле функции.
- Вычисляются значения выражений, использованных в качестве фактических параметров при вызове функции.
- Значения выражений – фактических параметров заносятся в участки памяти, выделенные для формальных параметров функции.
- В теле функции выполняется обработка с использованием значений внутренних объектов-параметров, и результат передается в точку вызова функции как возвращаемое ею значение.
- Никакого влияния на фактические параметры (на их значения) функция не оказывает.
- После выхода из функции освобождается память, выделенная для ее формальных параметров.
Важным является момент, что объект вызывающей программы, использованный в качестве фактического параметра, не может быть изменен из тела функции. Для подобного изменения существует косвенная возможность изменять значения объектов вызывающей программы действиями в вызванной функции. Это становится возможным с помощью указателя (указателей), когда в вызываемую функцию передается адрес любого объекта из вызывающей программы. С помощью выполняемого в тексте функции разыменования указателя осуществляется доступ к адресуемому указателем объекту из вызывающей программы. Тем самым, не изменяя самого параметра ( указатель — параметр постоянно содержит только адрес одного и того объекта), можно изменять объект вызывающей программы.
Массивы и строки также могут быть параметрами функции. В этом случае внутрь функции передается только адрес начала массива. Тогда можно в качестве параметра использовать указатель . Приведем два равноправных прототипа функций:
float fun(int n, float A[ ], float B[ ]); float fun(int n, float *a, float *b);
Поскольку массив передается в функцию как указатель , внутри функции можно изменять значения элементов массива–фактического параметра, определенного в вызывающей программе. Это возможно и при использовании индексирования, и при разыменовании указателей на элементы массива.
В языке С существует возможность создавать функции, число аргументов которых не определено – функции с переменным числом аргументов [1]. При этом следует указать только количество аргументов. Пример прототипа функции с переменным числом аргументов:
int fun(int n, ј);
Многоточие (ј) в прототипе функции означает, что функция получает переменное число аргументов любого типа. Многоточие должно всегда находиться в конце списка параметров [1].
Макросы и определения заголовочного файла переменных аргументов stdarg.h (табл. 10.1) предоставляют программисту средства, необходимые для построения функций со списком аргументов переменной длины [1].
va_list | Тип, предназначающийся для хранения информации, необходимой макросам va_start , va_arg и va_end . Чтобы получить доступ к аргументам в списке переменной длины, необходимо объявить объект типа va_list |
va_start | Макрос, который вызывается перед обращением к аргументам списка переменной длины. Он инициализирует объект, объявленный с помощью va_list , для использования макросами va_arg и va_end |
va_arg | Макрос, расширяющийся до выражения со значением и типом следующего аргументов списке переменной длины. Каждый вызов его изменяет объект, объявленный с помощью va_list так, что объект указывает на следующий аргумент списка |
va_end | Макрос обеспечивает нормальный возврат из функции, на список аргументов которой ссылается макрос va_start |
Примеры обращений к функции с фактическими аргументами :
double k; double v1 = 1.5, v2 = 2.5, v3 = 3.5; // Первый вариант, где 3 – количество аргументов k = fun(3,v1, v2, v3); // Второй вариант, где 0.0 – завершающий нуль списка аргументов k = fun(v1, v2, v3, 0.0);
Источник: intuit.ru
Передача параметров функции main
Функция main, с которой начинается выполнение С++-программы, может быть определена с параметрами, которые передаются из внешнего окружения, например, из командной строки. Во внешнем окружении действуют свои правила представления данных, а точнее, все данные представляются в виде строк символов.
Для передачи этих строк в функцию main используются два параметра, первый параметр служит для передачи числа передаваемых строк, второй для передачи самих строк. Общепринятые (но не обязательные) имена этих параметров argc и argv. Параметр argc имеет тип int, его значение формируется из анализа командной строки и равно количеству слов в командной строке, включая и имя вызываемой программы (под словом понимается любой текст не содержащий символа пробел). Параметр argv это массив указателей на строки, каждая из которых содержит одно слово из командной строки. Если слово должно содержать символ пробел, то при записи его в командную строку оно должно быть заключено в кавычки.
Функция main может иметь и третий параметр, который принято называть argp, и который служит для передачи в функцию main параметров операционной системы (среды) в которой выполняется С++-программа.
int main (int argc, char *argv[], char *argp[])
Если, например, командная строка С++-программы имеет вид:
A:>cprog working ‘C program’ 1
то аргументы argc, argv, argp представляются в памяти как показано в схеме на рис.1.
argc [ 4 ] argv [ ]—> [ ]—> [A:cprog.exe ] [ ]—> [working ] [ ]—> [C program ] [ ]—> [1 ] [NULL] argp [ ]—> [ ]—> [path=A:;C:\0] [ ]—> [lib=D:LIB ] [ ]—> [include=D:INCLUDE ] [ ]—> [conspec=C:COMMAND.COM] [NULL] Рис.1. Схема размещения параметров командной строки
Операционная система поддерживает передачу значений для параметров argc, argv, argp, а на пользователе лежит ответственность за передачу и использование фактических аргументов функции main.
Пример: Необходимо в командной строке ввести целое число, которое будет преобразовано в двоичный, 8-ричный и 16-ричный формат и выведено на экран.
void f_dva(int a);
int main (int argc, char *argv[])
Источник: studopedia.ru