- •Алгоритм.
- •Множественный выбор switch.
- •Оператор do … while ( с постусловием ).
- •Do оператор ;
- •Оператор цикла for.
- •Использование операторов break и continue в циклах.
- •Функции ввода-вывода.
- •Общий вид программы.
- •Вложенные циклы.
- •Адреса и указатели.
- •Массивы.
- •Int a[10] ; // целочисленный вектор из 10 элементов.
- •Векторы.
- •Сортировка вектора.
- •Матрицы.
- •Строки.
- •Подпрограммы.
- •Директива препроцессора #define .
- •Области видимости.
- •Классы памяти.
- •Рекурсия.
- •Подготовка к зачету.
- •Структуры.
- •Int ball [4] ; // описание третьего поля – оценки.
- •Очередь.
- •Линейные списки.
- •Деревья.
- •Int n, k ; // ее размерности
- •Void print ( void ) // печать матрицы
- •Определение методов вне класса.
- •Частные и общие данные.
- •Конструктор.
- •Перегрузка операторов.
- •Неявный указатель *this.
- •Дружественные функции.
- •Класс множество.
- •Наследование.
- •Объекто-ориентированное программирование.
- •Список вопросов к экзамену.
- •Литература.
Подпрограммы.
Подпрограмма или функция – это именованная часть программы, реализующая законченный алгоритм.
Все программы на С состоят из подпрограмм, с главной подпрограммой - main() мы уже встречались. Она выглядит так:
main()
{
операторы реализующие алгоритм.
}
Первая строка – заголовок функции далее в{} ее тело.
main – имя подпрограммы, в скобках перечень параметров, в данном случае отсутствует.
Иначе заголовок главной функции можно записать так:
void main( void )
void – означает отсутствие, в первом случае результата функции во втором параметров. При отсутствии перед именем функции в ее заголовке типа результата берется по умолчанию int.
main()
Поэтому при таком оформлении функции транслятор требует оператор - return 1 ;
Описание подпрограммы, в общем виде, выглядит так:
тип результата ИМЯ( тип параметр1,тип параметр2,…тип параметрК)
{ формальные параметры
тело
return результат ;
}
Если нет результата, а есть эффект, то в теле функции нет оператора return.
Вызов функции может является как отдельным оператором, так и встраиваться в другие операторы, но всегда имеет:
ИМЯ( параметр1, параметр2,… параметрК)
фактические параметры
Например следующие вызовы стандартных функций:
scanf (“%d”, &a) ; // вызов функции самостоятельный оператор, у нее нет результата.
h=strlen(text) ; // результат выполнения функции присваивается переменной.
printf (“%d”, strlen(text)) ; // два вызова разных функций, один внутри другого.
Выполняется правило - формальные и фактические параметры соответствуют друг другу по количеству, типу и порядку следования.
Как располагаются подпрограммы друг относительно друга? Существуют два разных варианта.
#include< > #include< >
int func( int a) // подпрограмма int func( int ) ; // декларация
{ main() // главная программа
int b ; {
… int k, s ;
return b ; …
} k=func(s) ;
…
main() // главная программа }
{ int func( int a) // подпрограмма
int k, s ; {
… int b ;
k=func(s) ; …
… return b ;
} }
Для чего нужны подпрограммы? Они реализуют два важнейших принципа программирования:
- модульность
- повторяемость
Модульность – это возможность разбивать программу на небольшие логически законченные фрагменты.
Трудные задачи часто разбиваются на отдельные логически законченные куски, которые связываются по данным, и выполняются различными людьми. Каждый фрагмент можно создавать независимо от других.
Повторяемость – это возможность в различных местах пользоваться одним и тем же нужным фрагментом без его повторного написания.
В таких случаях каждый раз вызывается одна и та же подпрограмма.
Рассмотрим простейшие подпрограммы.
Заданы 2 целых числа, используя подпрограмму, определить максимальное из них.
#include<stdio.h>
int max( int a , int b)
{
if( a>b ) return a ;
else return b ;
}
main()
{
int m , n , maxim ;
scanf (“%d” , &m ) ;
scanf (“%d” , &n ) ;
maxim=max( m , n ) ; // вызов функции max
printf (“максимальное число = %d “ , maxim ) ;
}
Заданы два целых числа, поменять местами их значения.
#include<stdio.h>
void change ( int a , int b )
{
int x ;
x=a ; a=b ; b=x ; // обмен значениями а и b через промежуточную переменную – х.
}
main ()
int a=5 , b=10 ;
printf (“%d %d” , a , b ) ;
change (a , b) ;
printf (“\n%d %d” , a , b ) ;
}
На экране вы увидите неожиданную вещь:
5 10
5 10
Значения переменных не переставляются! Где же ошибка? Если вставить печать в функцию change, то увидим, что там все в порядке и значения a и b переставляются. Почему же в main не изменилось ни чего? Для того чтобы это понять, нужно знать, как осуществляется движение информации в подпрограмму и обратно. Разберемся в этом..
В момент вызова функции, значение фактического параметра - а присваивается первому формальному параметру. Переменные - а в main и – а в change физически совершенно разные, между ними нет никакой связи после заполнения - а из change в момент вызова. Поэтому их можно обозначать разными именами. Совершенно аналогично для переменной - b. После выполнения перестановки нужно вернуть значения двух переменных, но это невозможно результат может быть только один. Т.е. в этом случае назад в главную подпрограмму ничего не возвращается, поэтому значения a и b в ней не изменяются.
Исправим эту ошибку. В главной функции main изменится только вызов функции:
change (&a , &b) ;
что означает передать в подпрограмму не значения переменных –а и b, а их адреса.
Функция будет выглядеть по другому:
void change ( int *a , int *b )
{
int x ;
x=*a ; *a=*b ; *b=x ; // перестановка значений в главной программе через их адреса.
}
В этом случае работа в подпрограмме change производится не с формальными параметрами, а с фактическими через их адреса, т.е. из функции change мы ссылаемся на место в памяти отведенное на а и b в main.
Интересные примеры работы с подпрограммами при использовании векторов и матриц.
Обнулить вектор при помощи функции.
#include<stdio.h>
void arrz ( int [] , int) ; // декларация функции
void main ( void )
{
int arr[10] , i ;
for ( i=0 : i<10 ; i++)
scanf (“%d” , &arr[i]) ;
arrz ( arr ,10) ; // вызов функции
for ( i=0 : i<10 ; i++)
printf (“%d” , &arr[i]) ;
}
void arrz ( int array[] , int num) // заголовок функции
{
int i ;
for ( i=0 : i<num ; i++)
array[i]=0 ;
}
В данном случае функция arrz тоже работает с адресом вектора arr[10], расположенного в main. И обнуляет она именно его, поэтому функция arrz не имеет результата, а имеет эффект.
При работе с матрицей в подпрограмме нужно соблюдать большую осторожность. Необходимо указывать структуру матрицы, хотя бы в одном индексе array[10][], или работать через адрес, для матрицы этот формальный параметр будет выглядеть так int **array. Подробнее об этом можно прочесть у Т.А. Павловской, С/С++ программирование на языке высокого уровни, С-П, 2001, стр.78.
Рассмотрим пример: каждую из произвольного количества матриц разной размерности транспонировать.
#include<stdio.h>
void mtran( int matr[10][], int n )
{
int i, j, k ;
for ( i=0 ; i<n ; i++)
for ( j=i+1 ; j<n ; j++)
{
k=matr[i][j] ;
matr[i]j]=matr[j][i] ;
matr[j]i]=k ;
}
}
void main (void)
{
int arr[10][10], i, j, k, n ;
do // цикл для обработки произвольного количества матриц «пока не надоест»
{
printf(“ введите размерность матрицы “) ;
scanf(“%d” , &n );
printf(“ введите матрицу \n “) ;
for ( i=0 ; i<n ; i++)
for ( j=0 ; j<n ; j++)
scanf(“%d” , &arr[i][j] );
mtran( arr, n ) ; // вызов функции, транспонирующей матрицу
printf(“ транспонированная матрица \n“) ;
for ( i=0 ; i<n ; i++)
{
for ( j=0 ; j<n ; j++)
printf(“%d” , arr[i][j] );
printf(“ \n“) ;
}
printf(“ повторить? 1-да, 0-нет “) ;
scanf(“%d” , &k );
while (k==1) ;
}
}
