Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабник по C.pdf
Скачиваний:
74
Добавлен:
01.06.2015
Размер:
876.9 Кб
Скачать

– 20 –

int n;

int Probel( char *str); // Прототип функции gets(string);

puts(”Вот наша строка”);

n= Probel(string); //Вызов функции printf(”Кол-во пробелов %d”, n);

} // main

// определение функции Probel int Probel( char *str ){

int i; count=0;

for(i=0; str[i]!=’\0’; i++); if ( str[i]==’ ’) count++; return count;

} // Probel //Конец программы

(Здесь string – аргумент функции Probel, str – формальный параметр, void и int – типы возвращаемого функцией значения. Отметим, что в списке параметров прототипа достаточно было бы записать char *).

5.2. КЛАССЫ ПАМЯТИ

Класс памяти переменной определяет ее область видимости и время существования

(табл. 3).

Пример: auto int number;

Выше сплошной черты в таблице классы описываются внутри функции (внутри блока), остальные вне функций.

Таблица 3

класс памяти

ключевое слово

существование

видимость

автоматический

аuto

временно

блок

регистровый

register

временно

блок

статический

static

постоянно

блок

внешний

extern

постоянно

файл, все файлы

внешний статический

static

постоянно

файл

Класс auto (автоматическая) приписывается переменным по умолчанию. Область видимости ограничена той функцией, в которой эти переменные описаны. Эти переменные создаются в момент начала работы функции и ликвидируются в момент завершения ее работы, т.е. время существования соответствует времени выполнения функции. В частности, переменные i, count видимы только в функции Probel.

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

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

Пример: int value; void main() {

extern int value;

...

}

void func() {

© 1998 Калачев Д.П., Лутай В.Н.

– 21 –

int value;

...

}

void Proof() { extern int value;

...

}

Для функций main и Proof переменная value – внешняя. В функции func переменная value – локальная, значение которой не совпадает со значением внешней переменной в

Proof и main.

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

Статическая переменная, объявленная внутри функции, с точки зрения области видимости подобна автоматической, а с точки зрения времени существования – глобальной.

Пример: void main() { int i;

void print();

for( i=1; i<=3; i++) print();

}

void print() { int number=0; static int stay=0;

printf(”Номер = %d состояние = %d \n”, number++, stay++ );

}

Здесь number – локальная переменная, stay – статическая. Функция print вызывается три раза.

Номер 1 состояние 1 Номер 1 состояние 2 Номер 1 состояние 3

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

Пример:

/*начало файла */

. . .

static char buf [10]; int myfunc() { ... }; /* Конец файла */

Переменная buf доступна только функции myfunc, но не выше; она недоступна и функциям в других файлах программы.

Для уменьшения времени выполнения программы значения переменных можно хранить не в оперативной памяти, а в регистрах процессора. Таким переменным должен быть присвоен класс register. В остальном они аналогичны автоматическим. Регистровыми можно объявлять несколько переменных, однако реально их будет столько, сколько свободных регистров у процессора.

© 1998 Калачев Д.П., Лутай В.Н.

– 22 –

5.3. ВОЗВРАЩЕНИЕ ЗНАЧЕНИЙ

При вызове функций в вызывающей программе может быть использован или не использован результат работы функции. Функция возвращает в функцию, ее вызвавшую, всегда одно значение: значение простой переменной или ее адрес или адрес составной переменной – массива, структуры. Если вызов функции является частью выражения, то в вызываемой функции должен ставиться оператор return(возвращаемое_значение); при этом тип возвращаемого значения должен совпадать с типом функции в ее заголовке. По умолчанию функция имеет целый тип. Если функция не возвращает значений (например, она осуществляет только печать данных), то она должна иметь тип void; оператор return при этом можно опустить.

В качестве примера запишем функцию, вычисляющую значения синуса с шагом 0.1, в диапазоне от 0 до 1 с точностью 0.0001.

Известное разложения в ряд имеет вид sin(x)=x-x^3/3!+x^5/5! ... Запишем этот ряд следующим образом:

A = A1-A2+A3... , где

AN+1 = -AN*x^2/(2*N*(2*N+1))

или

AN+1 = -AN*KN

(Здесь применен стандартный прием программирования для числовых рядов, состоящий в нахождении зависимости между соседними членами ряда).

void main() { double x=0, y;

double sin(double); // Прототип функции while (x<1) {

y=sin(x); // Вызов функции

printf(”x=%f sin(x)=%f\n”,x,y); //Печать значений x=x+0.1;

}

} //main

// описание функции double sin( double z) { int n=1;

double A, A1, A2;

A1=z; A=A2=A1; //А - сумма ряда,А1 - текущий член ряда, А2 - его модуль while (A2>0.0001) { // Точность проверяется по значению текущего члена ряда

A1 = -A1*z*z/(2*n*(2*n+1)) ; A = A+A1;

A2 = (A1>0)? A1:-A1; // Вычисление модуля n++;

}

return (A); } // sin

5.4.АРГУМЕНТЫ ФУНКЦИИ

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

Пример: функция перестановки значений х и у. void main() {

int x, y;

void swap(int,int); // Прототип функции x=1; y=5;

swap(x,y); // Вызов функции

© 1998 Калачев Д.П., Лутай В.Н.

– 23 – printf(”x=%d, y=%d\n”); // Вывод значений

}

// Описание функции

void swap( int z1, int z2) {

int buf; // Поле для промежуточного хранения buf=z1;

z1=z2;

z2=buf;

}

Результат: х=1, у=5.

Функция не изменила значения исходных переменных. Объясняется это тем, что обмен значений она произвела в копиях переменных x и y.

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

void swap( int *z1, int *z2) { int buf;

buf = *z1; *z1 = *z2; *z2 = buf;

}

swap( &x, &y );

Здесь в функцию передаются адреса переменных х и у. По-прежнему, в функции создаются копии этих адресов. Но так как *z1 и *z2 являются значениями исходных переменных, то мы получим желаемый результат.

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

void main() { int mas[10];

...

myFunct(mas); // Вызов функции

...

} // main

void myFunct(int massiv[]) {

...

} // myFunct

Если функция работает не с массивом, а с его отдельными элементами, то как и в первом случае следует прибегать к указателям.

Структуры передаются в функции также по имени.

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

Положим, что указатель на произвольную функцию – funct. Тогда для того, чтобы обратиться к такой функции, следует написать – (*funct)(...);

В качестве примера рассмотрим программу вычисления определенного интеграла от функции sin(x) в пределах от a до b. Подынтегральную функцию назовем Sinus, функцию, вычисляющую интеграл, – Integral. В качестве метода численного интегрирования выберем простейший метод прямоугольников с разбиением интервала интегрирования на М отрезков.

#include <stdio.h>

#include <math.h> //Подключение математической библиотеки const int M=20;

double Sinus(double x){

© 1998 Калачев Д.П., Лутай В.Н.