- •Московский государственный социальный университет академия информатики и информационных технологий
- •Введение
- •Часть. Основы программирования на Си
- •1.1. Структура простейшей Си-программы
- •1.2. Данные в Си и операции над ними
- •1.2.1. Свойства ячейки памяти. Переменные и константы
- •1.2.2. Типы данных в Си
- •1.2.3. Правила записи констант в Си
- •1.2.4. Описание переменных и именованных констант в Си.
- •1.2.5. Выражения в Си
- •1.3. Операторы преобразования данных
- •1.3.1. Общие положения
- •1.3.2. Функция форматного выводаprintf()
- •1.3.3. Функция форматного вводаscanf()
- •1.4. Разработка программ на Си
- •1.4.1. Понятие о качестве программы и основные технологические принципы разработки программ
- •1.4.2. Алгоритм и способы его записи.
- •1.4.3. Изображение алгоритмов в виде блок-схем
- •1.4.4. Базовые структуры алгоритмов и их кодирование на Си.
- •1. Следование
- •2. Разветвление (развилка)
- •If (условие)
- •If (условие)
- •3. Цикл
- •1.4.4. Примеры разработки программ
- •1.5. Массивы и указатели
- •1.5.1. Понятие массива. Основные правила работы с массивами в Си
- •1.5.2. Примеры программ с массивами.
- •1.5.3. Инициализация массивов
- •1.5.4. Указатели в Си10
- •1.5.5. Связь массивов с указателями в Си
- •Часть. Функции и многофайловые программы в Си
- •2.1. Общие сведения о подпрограммах и функциях
- •2.2. Функции си
- •2.2.1. Описание функции
- •2.2.2. Обращение к функции
- •2.2.3. Место описания функции в программе
- •2.2.4. Примеры программ, использующих функции
- •2.3. Краткие сведения о препроцессоре Си
- •2.3.2.Директива макроопределения #define
- •2.3.3. Директива #include включения файлов
- •2.3.4. Директивы условной компиляции
- •2.415. Многофайловые си-программы
- •2.4.1. Структура программы на Си. Область действия переменных
- •2.4.2. Время жизни и класс памяти переменных
- •Описатели класса памяти
- •2.4.3 Понятие о файле проекта
- •Часть. Обработка символьной информации и документов сложной структуры
- •3.1. Обработка символьной информации на Си
- •3.1.1. Символьный тип
- •3.1.2. Работа со строками символов в Си. Строковые литералы. .
- •3.1.3. Функции и макросы для работы с символьной информацией
- •3.1.4. Примеры программ
- •3.2. Тип "структура" в Си
- •Структура
- •3.3. Файлы в Си
- •3.3.1. Общие понятия.
- •3.2.Функции Си для работы с файлами
- •3.3.3. Примеры программ, использующих файлы
- •Литература
- •Содержание
2.2.3. Место описания функции в программе
Функция не может быть описана внутри другой функции. Функция (как всё в программе) должна быть описана до использования; если это не так, то до использования необходимо поместить прототип (шаблон)функции. Самый простой и лучший вариант шаблона: заголовок функции, в котором могут отсутствовать имена формальных параметров (но присутствуют их типы). Формальное отличие шаблона от заголовка функции состоит в присутствии точки с запятой после скобки, закрывающей список формальных параметров. Наличие шаблона позволяет компилятору контролировать соответствие типа возвращаемого функцией значения и соответствие количества и типов формальных и фактических параметров.
Общеупотребительная практика состоит в соблюдении следующих правил:
1) надо ставить шаблоны в начало программного файла;
удобно записывать часто употребляемые шаблоны в заголовочный файл, подключаемый к программе директивой includeпрепроцессора (см. п. 2.3.3). Обратите внимание, что в всех рассмотренных примерах Си-программ с помощью директивы include подключались именно файлы, содержащие шаблоны библиотечных функций, т. е. заголовочные файлы.
2.2.4. Примеры программ, использующих функции
Пример 1. Даны две матрицы: а из 3-х строк и 5 столбцов (в дальнейшем будем условно записывать а[3*5]) иb[7*3]. Вычислить минимальные значения для каждой строки каждой из этих матриц.
Естественно, вычисление минимальных значений строк произвольной матрицы следует оформить как функцию (назовем ее minmatr), а затем применить ее два раза к конкретным (фактическим) матрицам а иb. Алгоритм ввода одинаков для матриц а иb, поэтому ввод также оформим как функцию (назовем ееmatrin). Аналогично вывод массива результатов будет процедураmasout.
Поясним, как составляются заголовки на примере функции minmatr.Функция имеет столько результатов, сколько строк у матрицы, все они равноправны, поэтому нет причины передавать один из них через имя функции, и, следовательно, тип функции -void.В список формальных параметров передаются "входные" данные для функции: матрицаа и ее размеры (n - число строк,m - число столбцов), и "выходные" данные:min - массив минимальных значений строк. Заметим, что обозначения, принятые в одной функции (a, n,m,min) никоим образом не связаны с обозначениями в других функциях (в том числеmain), т. е. программирование функций выполняется автономно друг от друга. Переменнаяmin- результат работы функции, поэтому в список формальных параметров должен быть включен ее адрес. Так какmin является массивом, то это требование удовлетворяется автоматически, без применения специальных операций.
Типы фактических и формальных параметров должны совпадать, поэтому размеры формальных массивов должны подходить и для матрицы а, и для матрицы b. Чтобы удовлетворить этому требованию, используем максимальный второй размер (число столбцов), подходящий и для а, и дляb, т. е. память под массивы отводится с избытком.Первый размер - число строк - в списке формальных параметров можно не указывать.
Получаем заголовок:
void minmatr(float a[ ][5],int n,int m,float min[ ]).
Дальнейшие комментарии приведены в тексте программы. Блок-схема функцииminmatr приведена на рис. 10.
Программа:
#include <stdio.h>
#include <math.h>
void masout(float a[ ],intn,charc);/* если стоит ";", то это шаблон*/
/*первый размер у массивов-формальных параметров можно*/
/*не указывать, второй задан по максимуму*/
void matrin(float [ ][5],intn,intm,char с);/* c -имя матрицы*/
/* используется при выводе пояснительных фраз и приглашений*/
void minmatr(float [ ][5],intn,intm,floatmin[ ]);
/* n и mво всех функциях передаются по значению, т. к. их*/
/*фактические значения - константы*/
void main()
{float a[3][5],b[7][5], mina[3], minb[7];
matrin(a,3,5,'a'); matrin(b,7,3,'b');
minmatr(a,3,5,mina); minmatr(b,7,3,minb);
masout(mina,3,'a'); masout(minb,7,'b');
}
void minmatr(float a[][5],int n,int m,float min[])
{int i,j;
for (i=0; i<n; i++)
{min[i]=a[i][0];/* минимум каждой строки вычисляется*/
/*последовательным сравнением*/
for (j=1;j<m; j++)
if (a[i][j]<min[i])
min[i]=a[i][j];
}
}
void matrin(float a[][5],int n,int m,char c)
{int i,j;
printf("Введите матрицу%1c %2d * %2d\n",c,n,m);
for (i=0;i<n;i++)
for (j=0;j<m;j++)
scanf("%f",&a[i][j]);
}
void masout(float a[],int n,char c)
{int i;
printf("Минимальные значения строк матрицы%1c\n",c);
for (i=0;i<n;i++)
printf("%4.1f ",a[i]);
printf("\n");
}
Пример 2. Вычислить полусумму минимальных значений двух одномерных массивов: а[5] и b[8].
Два раза повторяющийся с точностью до обозначений и констант алгоритм вычисления минимального значения одномерного массива оформим как функцию, назовем ее min. Ввод массивов также оформим как функцию.
Заметим, что у функции min один результат, логично возвращать его через имя функции, тип функции будетfloat(совпадает с типом результата).
#include <stdio.h>
#include <math.h>
float min(float a[], int n);
void masin(float a[],int n,char c);
void main()
{float a[5],b[8],srmin;
masin(a,5,'a'); masin(b,8,'b');
srmin=(min(a,5)+min(b,8))/2;
printf("Полусумма минимумов pавна %4.1f\n",srmin);
}
float min(float a[], int n)
{int i; float m;/*переменнаяm заменяет min, т. к. использование*/
m=a[0]; /*предполагает рекурсивное обращение к функции*/
for (i=1;i<n;i++)
if (a[i]<m )
m=a[i];
return (m);
}
void masin(float a[],int n,char c)
{int i;
printf(" Введите массив %1c из %1d элементов\n",c,n);
for (i=0;i<n;i++)
scanf("%f",&a[i]);
}
Пример 3. Приведенная ниже программа содержит функциюkv_urрешения квадратного уравненияax2+bx+c=0. Результаты функции: дискриминант уравнения и либо два действительных корня, либо действительная и мнимая часть комплексно-сопряженных корней. Результаты должны передаваться по имени, поэтому в список формальных параметров включены их адреса. В главной функции вводятся значения коэффициентов уравнения, вызываетсяkv_urи выводятся результаты.
#include <stdio.h>
#include <math.h>
void kv_ur(float a, float b, float c, float *d, float *x1, float *x2);
// *d - дискриминант
// если *d<0, то *х1 и *х2 - действительная и мнимая часть комп. коpней,
// иначе *х1 и *х2 - два действительных коpня.
void main()
{float a, b, c, d, x1, x2;
printf("введите коэффициенты a,b,c уpавнения\n", a, b, c);
scanf("%f%f%f", &a, &b, &c);
kv_ur(a, b, c, &d, &x1, &x2);
if (d<0)
{printf("уpавнение имеeт комплексно-сопpяженные коpни\n");
printf("действ. часть =%f , мнимая часть =%f\n", x1,x2);
}
else
{printf("уравнение имеeт два действительных коpня\n", "x1=%fx2=%f\n", x1,x2);
}
}
void kv_ur(float a, float b, float c, float *d, float *x1, float *x2)
{*d=b*b-4*a*c;
if(*d<0)
{*x1=-b/2/a;
*x2=sqrt(-*d)/2/a;
}
else
{*x1=-b/2/a+sqrt(*d);
*x2=-b/2/a-sqrt(*d);
}
}