Введение |
Массивы, строки и структуры |
Операторы |
Операции |
Переменные и типы |
Пояснения к курсовой работе |
Препроцессор |
Работа с файлами |
Стандарты безопасного кодирования |
Указатели и динамическая память |
Ввод-вывод |
Функции в языках программирования используются, чтобы
hypot
или сортировка) или стороннюю библиотеку (например, функции GUI).Вызов функции выполняется как имя(список_аргументов)
где список_аргументов это последовательность выражений через запятую. Скобки обязательны, даже если список аргументов пустой (скобки после идентификатора всегда являются признаком, что идентификатор является именем функции). Результат функции может использоваться для дальнейших вычислений или игнорироваться:
int x, n, sum=0;
scanf("%d",&n); // игнорируем результат
while(scanf("%d",&x)==1) { // ввести целые числа до конца файла или ошибки ввода
sum+=x;
}
Перед вызовом функции функция должна объявлена или определена. Объявление функции состоит из заголовка и ;
. Определение функции состоит из заголовка и тела функции. Заголовок функции имеет вид:
спецификатор
extern
– применяется для функций по умолчанию, можно не писать;static
– функция доступна только в этом модуле (см. далее);inline
– встраиваемая функция, может применяться только для небольших функций из 1-3 операторов, вместо вызова будет подставлен скомпилированный код этой функции, поэтому определение функции должно быть известно компилятору перед вызовом.void
.double atan2(double, double); // Где указать x, а где y? Пусть будет x,y... А почему ответ неправильный?
double atan2(double y, double x); // Понятно, сначала y, потом x
void
, в C++ можно не писать ничего.Для возврата результата из функции последним оператором в блоке должен быть bb"return" quad "выражение" bb";". Для функций с типом результата void
можно написать bb"return;" или не писать ничего. Также разрешается не писать return 0;
в конце тела функции main
. В остальных случаях функция возвращает мусор, а компилятор предупреждает о возможной ошибке.
Оператор return
можно использовать для досрочного выхода из функции (как goto
в точку за последним оператором тела функции).
Пример функции:
#include <stdio.h>
int isprime(int n) {
if(n==1) return 0;
for(int i=2; i*i<=n; ++i)
if(n%i==0) return 0;
return 1;
}
int main() {
int n;
scanf("%d",&n);
printf("%d is%s prime\n",n,isprime(n)?"":" not");
}
Аргументы при вызове функции копируются в параметры, поэтому изменение параметра не отражается на аргументе:
#include <stdio.h>
void test(int n) {
n+=1;
printf("%d\n",n);
}
int main() {
int n=10;
test(n);
printf("%d\n",n);
}
В С есть возможность определить функции с переменным количеством параметров. Примерами таких функциями являются scanf и printf. Реальное количество аргументов при вызове должно быть указано в одном из первых аргументов функции, например, у scanf и printf количество вводимых или выводимых значений определяется по количеству спецификаторов формата в первом аргументе функции. Рассмотрим на примере:
#include <stdio.h>
#include <stdarg.h> // заголовочный файл для функций и типов для работы с переменным количеством параметров
int sum(int n, ...) { // после 1 параметра указываем ...
int s=0;
va_list args; // список переменных параметров
va_start(args, n); // ... начинается после параметра n
for (int i=0; i<n; ++i) {
s+= va_arg(args, int); // извлекаем очередной параметр типа int
}
va_end(args); // завершение обработки
return s;
}
int main() {
printf("%d\n", sum(4, 5, 10, 50, 101));
printf("%d\n", sum(6, 1, 2, 3, 10, 20, 30));
}
В С++ можно изменять количество аргументов при вызове функции, давая параметрам значения по умолчанию в объявлении функции. Например, функция для создания окна в графической библиотеке имеет 2 обязательных (размеры окна) и 5 опциональных параметров, поэтому её можно вызывать, указывая от 2 до 7 аргументов:
int initwindow(int width, int height, const char* title="Windows BGI", int left=0, int top=0, bool dbuf=false, bool closeall=true );
...
// примеры вызова
initwindow(800,600); // initwindow(800,600,"Windows BGI",0,0,false,true);
initwindow(800,600,"Editor",100,50); // initwindow(800,600,"Editor",100,50,false,true);
initwindow(800,600,"Editor",100,50,true,false); // initwindow(800,600,"Editor",100,50,true,false);
Аргументы этой функции являются позиционными, нельзя при вызове пропустить какой-то параметр и указать значение для следующего. Можно реализовать подобие опциональных ключевых параметров, для задания значения которым нужно указать имя параметра. Для это в С можно использовать структуру-значение:
typedef struct window_params {
int width;
int height;
const char* title;
int left;
int top;
bool dbuf;
bool closeall;
} window_params;
int initwindow2(window_params params) {
return initwindow(params.width, params.height, params.title?params.title:"Windows BGI", params.left, params.top, params.dbuf, params.closeall);
}
...
// примеры вызова
initwindow2((window_params){800,600}); // initwindow(800,600,"Windows BGI",0,0,false,false);
initwindow2((window_params){800,600,.title="Editor", .top=50, .closeall=true}); // initwindow(800,600,"Editor",0,50,false,true);
Рекурсия возникает, когда функция вызывает саму себя прямо или косвенно. Чтобы рекурсивная функция была корректной, в начале функции должно быть условие завершения рекурсии, а при рекурсивном вызове должно происходить уменьшение сложности задачи.
#include <stdio.h>
int gcd(int a, int b) { // НОД(a,b)
if(b==0) return a; // завершение рекурсии
return gcd(b, a%b); // упрощение задачи и рекурсивный вызов
}
int main() {
int a,b;
scanf("%d %d",&a,&b);
printf("%d\n", gcd(a,b));
}