Программирование · 12 min read · Oct 09, 2025
Изучение C/C++ шаг за шагом - Страница 6
06. Постепенное изучение C/C++ — Программирование на C - Функции
Функции
| I. Введение | |
| II. Определение функции | |
| III. Типы функций | |
| IV. Встроенные функции |
| | 1. Числовые функции
- Строковые функции
- Функции тестирования символов | | | V. Пользовательские функции | | | 1. Простые функции
- Функция с аргументами
- Функция с возвратом
- Функция с рекурсией | | | VI. Указатели и функции | | | 1. Передача параметров по ссылке
- Вызов по значению
- Вызов по ссылке | | | VII. Локальные и глобальные | | | VIII. Спецификаторы класса хранения | | | Автоматический класс хранения
Регистровый класс хранения
Статический класс хранения
Внешний класс хранения |
I. Введение
Вот программа для печати адреса человека дважды, которая написана как с использованием функций, так и без использования функций. Это продемонстрирует преимущества функций.
| | #include
int main()
{
printf(“\nИмя человека”);
printf(“\nУлица, Квартира//Дом № “);
printf(“\nиндекс, Город”);
printf(“\nСтрана”);
printf(“\nИмя человека”);
printf(“\nУлица, Квартира//Дом № “);
printf(“\nиндекс, Город”);
printf(“\nСтрана”);
return 0;
} | #include
void address()
{
printf(“\nИмя человека”);
printf(“\nУлица, Квартира//Дом № “);
printf(“\nиндекс, Город”);
printf(“\nСтрана”);
}
int main()
{
address();
address();
return 0;
} |
II. Определение функции
Блок операторов, который может принимать значения в качестве аргументов и возвращать результаты вызывающей программе. Таким образом, функция — это самодостаточный блок операторов, выполняющий конкретную задачу.
III. Типы функций
| | - Встроенные функции/ Библиотечные функции/ Предопределенные функции
- Пользовательские функции |
IV. Библиотечные функции
Библиотечные функции разработаны производителем программного обеспечения, они загружаются на диск каждый раз, когда загружается программное обеспечение.
Следующие функции являются примерами библиотечных функций.
1. Числовые функции
| Функция | Синтаксис | Пример | Результат |
| Abs | Abs(n) | abs(-35) | 35 |
| ceil | ceil(n) | ceil(45.232) | 46 |
| floor | floor(n) | floor(45.232) | 45 |
| fmod | fmod(n,m) | fmod(5,2) | 1 |
| cos | cos(n) | cos(60) | 0.5 |
| sin | sin(n) | sin(60) | 0.866 |
| tan | tan(n) | tan(60) | 1.732 |
| sqrt | sqrt(n) | sqrt(25) | 5 |
| pow | pow(n,m) | pow(2,3) | 8 |
2. Строковые функции
| Функции | Синтаксис | Пример |
| strlen | strlen(str) | strlen(“Компьютер”) |
| strcpy | strcpy(target,source) | strcpy(res,”Pass”) |
| strcat | strcat(target,source) | strcat(“mag”,”gic”) |
| strcmp | strcmp(str1,str2) | strcmp(“abc”,”Abc”) |
| strrev | strrev(target,scr) | fstrrev(res,”LIRIL”) |
3. Функции тестирования символов
| Функция | Описание |
| isalnum | является ли буквой или цифрой |
| isalpha | является ли буквой |
| isdigit | является ли цифрой |
| iscntrl | является ли обычным управляющим символом |
| isascii | является ли допустимым символом ASCII |
| islower | является ли символом в нижнем регистре |
| isupper | является ли символом в верхнем регистре |
| isspace | является ли пробелом |
| isxdigit | является ли шестнадцатеричным символом |
Существует огромная библиотека доступных функций, я привел вам лишь небольшую часть из нее. Для получения дополнительных библиотечных функций обратитесь к справочному руководству.
V. Пользовательские функции
Программы, которые вы уже видели, выполняют разделение труда. Когда вы вызываете gets, puts или strcmp, вам не нужно беспокоиться о том, как работают внутренности этих функций.
Эти и около 400 других функций уже определены и скомпилированы для вас в библиотеке Turbo C. Чтобы использовать их, вам нужно только включить соответствующий заголовочный файл в вашу программу, “Библиотека времени выполнения,” в справочнике библиотеки, чтобы убедиться, что вы понимаете, как вызывать функции и какое значение (если есть) они возвращают.
Но вам нужно будет написать свои собственные функции. Для этого вам нужно разбить ваш код на отдельные секции (функции), каждая из которых выполняет одну понятную задачу для ваших функций, которые вы можете вызывать по всему вашему коду так же, как вы вызываете функции библиотеки C.
Шаги для реализации функции
| | 1. Объявление
- Вызов функции
- Определение |
| | • Каждая функция должна быть объявлена в начале программы.
• Определение функции содержит фактический код выполнения задачи.
• Если функция определена в начале программы, нет необходимости в объявлении функции. |
Пример функции для демонстрации реализации
| | / 32_egfun.c /
#include
void address(); / Объявление /
int main()
{
address(); / Вызов функции /
address(); / Вызов функции /
return 0;
}
void address() / Определение /
{
printf(“\nИмя человека”);
printf(“\nУлица, Квартира//Дом № “);
printf(“\nиндекс, Город”);
printf(“\nСтрана”);
} |
Пользовательские функции можно разделить на 4 типа в зависимости от того, как мы их вызываем.
| | 1. Простые функции
- Функция с аргументами
- Функция с возвратом
- Функция с рекурсией |
1. Простые функции
Выполняет конкретную задачу, не требует аргументов и значений возврата.
Пример простой функции
| | / 33_line.c /
#include
void line(); / Объявление /
int main()
{
line(); / Вызов функции /
return 0;
}
void line() / Определение /
{
int i;
for(i =1;i<80; i++)
putch(‘*’);
} |
2. Функция с аргументами
Функция, которая принимает аргументы, называется функцией с аргументами.
Пример.
| | / 34_argu.c /
void line(char ch, int n)
int main()
{
line(“-“, 50);
line(“*”, 8);
return 0;
}
void line(char ch, int n)
{
int i;
for( i = 1; i<=n; i++ )
putch(ch);
} |
3. Функция с возвратом значений
Функция, которая может возвращать значения вызывающей программе, называется функцией с возвратом значений.
Пример.
| | / 35_retu.c /
int abs(int n);
int main()
{
int res;
printf(“%d”, abs(-35))
res = abs(-34); / Вызов функции/
printf(“%d”, res);
return 0;
}
void abs(int n)
{
if( n < 0 )
n = n * -1;
return n;
} |
4. Функция с рекурсией
Если оператор внутри тела функции вызывает ту же функцию, это называется ‘рекурсией’. Иногда это называется ‘круговым определением’, рекурсия — это процесс определения чего-то в терминах самого себя.
Примеры рекурсивных функций
| | / Следующая программа демонстрирует вызов функции самой себя /
int main( )
{
printf(“\nПривет”);
main( ); / Функция, которая может вызывать саму себя /
return 0;
} Не запускайте эту программу, это все еще объяснение, поэтому программа логически недействительна.
Тот же вывод можно получить с помощью другой функции: void disp( );
int main( )
{
disp( );
return 0;
}
void disp( )
{
printf(“\nПривет”);
disp( );
} |
Программа должна завершаться в определенный момент, поэтому ключ рекурсии заключается в мягком прерывании, которое можно определить с помощью условного оператора.
Проверьте следующий пример:
| | / 36_recursion.c /
int i = 1; / Объявление глобальной переменной /
void disp( );
int main( )
{
disp( );
return 0;
}
void disp( )
{
printf(“\nПривет %d “, i);
i ++;
if( i < 10 ) / если значение i меньше 10, то снова вызываем функцию /
disp( );
} |
| | Программа для нахождения факториала данного числа:
/ 37_fact.c /
int factorial(int x);
void main
{
int a, fact;
printf(“\nВведите любое число “); scanf(“%d”, &a);
fact = factorial(a);
printf(“\nФакториал = %d”, fact);
}
int factorial(int x)
{
int f = 1, i;
for( i = x; i>=1; i–)
f = f i;
return f;
} | Чтобы найти факториал данного числа с помощью рекурсии
/ 38_fact.c /
int rec_fact(int x);
int main( )
{
int a, fact;
printf(“\nВведите любое число “); canf(“%d”, &a);
fact = rec_fact(a);
printf(“\nЗначение факториала = %d”, fact);
return 0;
}
int f = 1;
int rec_fact(int x)
{
if( x > 1)
f = x rec_fact(x-1);
return f;
} |
VI. Указатели и функции
| | Передача параметров по ссылке
Вызов по значению
Вызов по ссылке |
1. Передача параметров по ссылке
Указатель может использоваться в объявлении функции, и это позволяет легко представить и получить доступ к сложной функции. Определение функции использует указатели двумя способами
| | – Вызов по значению
- Вызов по ссылке |
Механизм вызова по ссылке быстрее по сравнению с механизмом вызова по значению, потому что в вызове по ссылке передается адрес, и манипуляции с адресами быстрее, чем с обычными переменными. Более того, создается только одно место в памяти для каждого из фактических параметров.
Когда часть программы, фактические аргументы, вызывает функцию, и значения, измененные внутри функции, будут возвращены в вызывающую часть программы в измененном виде. Это называется вызовом по ссылке или вызовом по адресу. Использование указателя в качестве аргумента функции в этом механизме позволяет изменять объекты данных глобально, т.е. как внутри функции, так и внутри вызывающей части программы. Когда указатель передается функции, адрес аргумента передается функциям, и содержимое этого адреса доступно глобально. Изменения, внесенные в формальные параметры (параметры, используемые в функции), влияют на оригинальное значение фактических параметров (параметры, используемые в вызове функции в вызывающей программе).
Пример.
| | / 39_func.c /
void func_c( int *x );
int main()
{
int i = 100;
int *a;
a = &i;
printf(“\nЗначение = %d”, i);
func_c(a);
printf(“\nЗначение = %d”, i);
return 0;
}
void func_c( int x )
{
(x) ++;
printf(“\nЗначение в функции = %d “, *x);
} |
В приведенной выше программе всего три оператора ‘printf’, два в функции main() и один в подпрограмме функции. Из-за эффекта первого оператора ‘printf’ значение i печатается как 100. Позже вызывается функция, и внутри функции значение изменяется на 101 из-за инкремента. Измененное значение снова возвращается в main() и печатается как 101.
Таким образом, вывод:
| | Значение = 100
Значение в функции = 101
Значение = 101 |
Больше о вызовах функций
После первой встречи с указателями давайте вернемся к тому, чему мы изначально хотели научиться – двум типам вызовов функций: вызову по значению и вызову по ссылке. Аргументы обычно могут передаваться функции одним из двух способов:
| | a. Отправка значений аргументов
b. Отправка адресов аргументов |
2. Вызов по значению
В первом методе ‘значение’ каждого из фактических аргументов в вызывающей функции копируется в соответствующие формальные аргументы вызываемой функции. При этом методе изменения, внесенные в формальные аргументы в вызываемой функции, не влияют на значения фактических аргументов в вызывающей функции. Следующая программа иллюстрирует вызов по значению.
| | / 40_callbyvalue.c /
void swap( int x, int y )
int main( )
{
int a = 10, b = 20;
swap( a ,b );
printf(“\n a = %d, b = %d “, a, b);
return 0;
}
void swap( int x, int y )
{
int t;
t = x;
x = y;
y = t;
printf(“\nx = %d, y = %d”, x, y);
} |
Вывод приведенной выше программы будет:
| | x = 20 y = 10
A = 10 b = 20 |
Обратите внимание, что значения a и b остаются неизменными после обмена значениями x и y.
3. Вызов по ссылке
На этот раз адреса фактических аргументов в вызывающей функции копируются в формальные аргументы вызываемой функции. Это означает, что используя эти адреса, мы получим доступ к фактическим аргументам и, следовательно, сможем манипулировать ими. Следующая программа иллюстрирует этот факт.
| | 41_callbyref.c /
void swap( int x, int y )
int main()
{
int a = 10, b = 20;
swap( &a, &b);
printf(“\na = %d, b = %d”, a, b);
return 0;
}
void swap( int x, int y )
{
int t;
t = x; x = y; y = t;
} |
Вывод приведенной выше программы будет:
| | A = 20, b = 10 |
Обратите внимание, что эта программа успешно меняет значения a и b, используя их адреса, хранящиеся в x и y. Обычно в программировании на C мы делаем вызов по значению. То есть в общем случае вы не можете изменить фактические аргументы. Но если это необходимо, это всегда можно достичь с помощью вызова по ссылке.
Используя вызов по ссылке разумно
мы можем создать функцию, которая может вернуть более одного значения за раз, что обычно невозможно. Это показано в программе, приведенной ниже.
| | / 42_callbyref.c /
void areaperi(int r, float a, float p)
int main()
{
int radius;
float area, perimeter;
printf(“\nВведите радиус круга:”); scanf(“%d”, &radius);
areaperi(radius, &area, &perimeter);
printf(“\nПлощадь = %f “, area);
printf(“\nПериметр = %f”, perimeter);
return 0;
}
void areaperi(int r, float a, float p)
{
a = 3.14 r r; p = 2 3.14 r;
} |
И вот вывод:
| | Введите радиус круга 5
Площадь = 78.500000
Периметр = 31.400000 |
Здесь мы делаем смешанный вызов, в том смысле, что мы передаем значение radius, но адреса area и perimeter. И поскольку мы передаем адреса, любое изменение, которое мы вносим в значения, хранящиеся по адресам, содержащимся в переменных a и p, будет эффективно изменено в main. Поэтому, когда управление возвращается из функции areaperi( ), мы можем вывести значения area и perimeter.
Таким образом, мы смогли вернуть два значения из вызываемой функции и, следовательно, преодолели ограничение оператора return, который может возвращать только одно значение из функции за раз.
VII. Локальные и глобальные переменные
Согласно области видимости идентификаторов переменные объявляются как типы.
| | / 42_globalid.c /
int i=4000; / Объявление глобальной переменной/
int main()
{
int a=10, b=20; / Локальная переменная /
int i=100; / Локальная переменная /
printf(“%d %d”, a, b);
printf(“\nЛокальная i : %d”, i); / Доступ к локальной переменной /
printf(“\nГлобальная i : %d “, ::i); / Доступ к глобальной переменной /
return 0;
} |
Примечание: Оператор разрешения области видимости ( :: ) доступен только в C++.
VIII. Спецификаторы класса хранения
На данный момент мы уже знакомы с объявлением переменных. Чтобы полностью определить переменную, необходимо указать не только ее ‘тип’, но и ‘ Класс хранения ‘.
Согласно этому разделу переменные не только имеют ‘тип данных’, но также имеют ‘Класс хранения’.
Классы хранения делятся на 4 типа
| | 1. Автоматический класс хранения
- Регистровый класс хранения
- Статический класс хранения
- Внешний класс хранения |
1. Автоматический класс хранения
| Ключевое слово | auto | |
| Хранение | Память | |
| Значение по умолчанию | Нулевое | |
| Область видимости | Локальная для блока, в котором переменная определена | |
| Жизнь | До выполнения его блока |
Пример:
| | / 43_auto.c /
#include
int main()
{
auto int i, j;
printf(“%d %d”, i, u);
return 0;
} |
2. Регистровый класс хранения
| Ключевое слово | register | |
| Хранение | Регистры ЦП | |
| Значение по умолчанию | Нулевое | |
| Область видимости | Локальная для блока, в котором переменная определена | |
| Жизнь | До выполнения его блока |
Пример:
| | / 44_register.c /
#include
int main( )
{
register int i, j;
for(i=1;i<=10;i++)
printf(“\n%d”, i);
return 0;
} |
3. Статический класс хранения
| Ключевое слово | static | |
| Хранение | Память | |
| Значение по умолчанию | Ноль | |
| Область видимости | Локальная для блока, в котором переменная определена | |
| Жизнь | Значение переменной сохраняется между различными вызовами функции |
Пример:
| | / 45_static.c /
#include
void add();
int main()
{
add();
add();
add();
return 0;
}
void add()
{
static int i = 1;
printf(“%d\n”,i++);
} |
4. Внешний класс хранения
| Ключевое слово | extern | |
| Хранение | Память | |
| Значение по умолчанию | Ноль | |
| Область видимости | Глобальная | |
| Жизнь | Пока выполнение программы не завершится |
Пример:
| | / 46_extern.c /
#include
int i;
void add(); / Внешняя переменная /
int main( )
{
extern j=10; / Внешняя переменная /
for(i=1;i<=10;i++)
add();
return 0;
}
void add( )
{
j++;
printf(“%d %d\n”, i, j);
} |
Get new posts in your inbox
No spam. Unsubscribe anytime.