Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
3
Добавлен:
14.11.2017
Размер:
582.65 Кб
Скачать

Подпрограммы в языке С

Программы на любом языке программирования обычно помимо главной программы (функции main в языке С) включают также ряд вспомогательных программ – подпрограмм. Это относительно самостоятельные части программы, решающие некоторые частные задачи. Они вызываются из главной программы или из других подпрограмм. Главные преимущества использования подпрограмм:

они позволяют структурировать программу, сделать ее более понятной, исключив излишнюю детализацию кода главной программы и подпрограмм верхнего уровня;

один раз описав подпрограмму, ее можно вызывать неоднократно в любом месте данной программы, а включив в состав библиотек, также вызывать и из других программ.

Технология и языки программирования

11

Подпрограммы в языке С

Все подпрограммы в языке С называются функциями, но по своему действию они эквивалентны как функциям языка Паскаль, если возвращают в качестве результата одно значение, так и процедурам языка Паскаль, если они возвращают несколько значений. В этом случае передача данных извне в

функцию и передача результатов работы из функции в другие функции,

включая главную функцию, осуществляется через ее параметры.

Все функции до их вызова быть описаны. Параметры функций в их описании называются формальными, поскольку они не имеют конкретных значений. При вызове функции вместо формальных параметров в функцию подставляются их фактические значения, поэтому они называются

фактическими параметрами.

В отличие от Паскаля, С++ и ряда других языков программирования, в которых передача данных через параметры подпрограмм возможна и по значению, и по ссылке, в языке С принят только способ передачи по значению. В этом случае при вызове функции создаются копии ее локальных

переменных, которые по завершении работы функции уничтожаются, а

значения фактических параметров функции остаются без изменений, даже если во время работы функции соответствующие им переменные были изменены. Чтобы избежать потери результатов, через параметры передаются не сами переменные, а указатели на них, т.е. адреса. Формальные параметры функции объявляются указателями. Пример на

следующем слайде.

Технология и языки программирования

12

Подпрограммы в языке С

#include <stdio.h> #include <math.h>

//Описания функций пользователя

//В описаниях у параметров (аргументов) функций указываются типы float sinc(float x) // описание математической функции sinc(x)

{

if(x == 0) return 1; else return sin(x)/x;

}

char upcase(char c) // функция преобразования букв из строчных в прописные

{

return c-32;

}

void MinMax(int a, int b, int *min, int *max)

//функция возвращает мин. и макс. значения двух чисел или 0, если они одинаковые

{

if (a < b) {*min = a; *max = b;} if (a > b) {*min = b; *max = a;} if (a == b) {*min =0; *max = 0;}

}

/* входные параметры функции a и b – переменные, т.е. имена ячеек памяти, а выходные (возвращаемые) параметры min и max не имена ячеек, а указатели на них, т.е. их адреса. Внутри функции мы работаем не с адресами, а с содержимым ячеек памяти, поэтому мы указываем знак * перед адресами. Этот оператор дает содержимое по значению адреса */

Технология и языки программирования

13

Подпрограммы в языке С

int main(void)

//Вызов описанных функций

//При вызове функций типы их параметров не указываются!!!

{

printf("%10.3f\n%c\n", sinc(0), upcase('a')); // вызов sinc() и upcase() int v = 7, w = 2;

MinMax(v,w,&v,&w); // вызов функции MinMax()

/* v и w – входные параметры (имена ячеек с исходными данными), а &v и &w – адреса ячеек памяти, в которые мы помещаем результаты.

Результаты возвращаются только через адреса!!! Оператор & дает адрес переменной, перед которой он записан.

В этом примере мы поместили результаты в те же самые ячейки, в которых находились исходные данные: в ячейку v мы поместили значение мин., а в ячейку w – значение макс., но это не обязательно, можно было использовать и другие ячейки памяти */

printf("%d %d\n",v,w); return 0;

}

Технология и языки программирования

14

Подпрограммы в языке С

В предыдущем примере функции были описаны до вызывающей их главной функции, что вполне допустимо. Однако, в языке С функции – подпрограммы чаще описывают после главной функции. Для того, чтобы компилятор имел нужную информацию при обработке кода, содержащего вызовы таких функций

до их описания, перед главной функцией помещают описания прототипов

функций. Прототип содержит имя и тип функции, а также список ее параметров (если они имеются) с указанием их типов. Имена параметров указывать не обязательно, можно указать только типы. Пример:

void swp(int*, int*); // прототип функции обмена значениями двух переменных int main(void)

{

int v=27, w=7; printf("%d %d\n",v,w); swp(&v,&w); printf("%d %d\n",v,w); return 0;

}

void swp(int *p, int *q) // описание функции обмена значениями двух переменных

{

int t = *p; *p = *q; *q = t;

}

Технология и языки программирования

15

Основные алгоритмы

Нахождение наибольшего (наименьшего) значения среди элементов массива

Будем рассматривать нахождение наибольшего значения. Наименьшее значение находится аналогично, с минимальными изменениями алгоритма.

Для выполнения алгоритма требуется одна переменная (ячейка памяти), тип

которой соответствует типу элементов массива. Там будет храниться текущее значение максимального по величине элемента массива, а после завершения

– наибольший элемент массива. Будем считать, что в массиве числа. Алгоритм следующий

Объявляем переменную и заносим туда первый элемент массива.

Движемся вдоль массива слева направо, перебирая в цикле индексы

элементов, начиная со 2-го, и повторяем следующие действия:

Сравниваем величину числа в нашей ячейке памяти и текущий элемент массива, на индекс (номер) которого указывает счетчик цикла. Если число в массиве больше, чем число в ячейке, то заносим туда число из массива (старое значение пропадает), иначе, ничего не делая, переходим к

следующему элементу массива.

Когда проделаем эти действия с последним элементом массива, то в ячейке будет находиться максимальное по величине число.

Пример программы, реализующей описанный алгоритм, приведен на следующем слайде

Технология и языки программирования

16

Основные алгоритмы

#include <stdio.h> #define n 5

int main(int argc, char *argv[])

{

int a[n];

printf("Enter elements of array:\n\n"); int i; for (i=0; i < n; i++)

{

printf("a[%d]= ",i); scanf("%d", &a[i]);

}

puts("\n");

for (i=0; i < n; i++) printf("%d ",a[i]); puts("\n"); // MAX finding

int max=a[0];

for (i=1; i < n; i++) if (a[i] > max) max = a[i]; printf("MAX = %d\n\n", max);

return 0;

}

Технология и языки программирования

17

Основные алгоритмы

Алгоритм суммирования ряда чисел – накапливающий сумматор (аккумулятор)

Содержимое ячейки памяти обнуляется, затем к нему прибавляется первое число, а результат сохраняется в той же ячейке. К новому содержимому ячейки прибавляется 2-е число, результат сохраняется снова в ней же и т.д.

В реальных вычислителях

Функциональная схема устройства выполнения

для промежуточного

операции суммирования с накоплением

хранения данных

X := X + X

используются регистры,

как показано на рисунке

в языке С можно записать более кратко: Х += X

 

Адреса ячеек памяти, из которых загружаются данные для суммирования при выполнении оператора цикла, формирует адресный генератор, который настраивается в соответствии с данными, указанными в описании оператора цикла

S

 

W

 

 

R

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

X

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Запись

 

Чтение

 

 

 

 

Ячейки памяти

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

X1

 

 

 

 

 

 

 

 

 

 

X2

 

R

 

 

 

 

 

 

 

 

 

X3

 

Чтение

 

 

 

 

Xj

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

RG SM

RG

сумматор

RG

Тактовые импульсы

RG - регистр, устройство временного хранения данных

Технология и языки программирования

18

Основные алгоритмы

Пример программы определения количества чисел меньших 50, которые кратны 7 и не делятся на 3, а также вычисления суммы этих чисел

#include <stdio.h>

int main(int argc, char *argv[])

{

int sum = 0; int x = 7; int i = 0; while (x < 50)

{

if (x % 3 != 0)

{

sum += x; i++;

}

x += 7;

}

printf("The number of digits = %d The sum = %d\n\n", i, sum); return 0;

}

Технология и языки программирования

19

Суммирование членов ряда Лейбница 1 – 1/3 + 1/5 – 1/7 + 1/9 +… ≈ π/4, вычисление π и оценка

погрешности аппроксимации

#define pi 3.1415926 #include <stdio.h> #include <math.h>

float fpi(int);

int main(void)

{

int n; char proc = '%'; printf("N= "); scanf("%d",&n); float res = fpi(n);

float err = fabs(res - pi)/pi*100;

printf("\nPI ~ %8.6f Err = %4.1f %c\n\n",res, err, proc); return 0;

}

float fpi(int k)

{

float sum = 0;

int i; for (i = 0; i < k; i++)

{

int zn; if(i % 2 == 0) zn = 1; else zn = -1; sum += (float) zn /(2*i+1);

}

return 4.0 * sum;

}

Технология и языки программирования

20

Соседние файлы в папке Бочаров презентации 1 семестр