Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекция_Информатика.doc
Скачиваний:
1
Добавлен:
16.09.2019
Размер:
143.36 Кб
Скачать

1.2.2 Изменение переменных в функции из других функций

С использованием указателей:

Пример:

void swap(int *a, int *b)

{

int temp;

temp=*a;

*a=*b;

*b=temp;

}

main()

{

int a,b;

swap(&a,&b);

}

С использованием ссылочных переменных:

При передаче в функцию указателей в теле функции необходимо использовать явно операцию разадресации (* адрес объекта). Это усложняет синтаксис. Чтобы исключить этот недостаток в языке Си были введены ссылки.

Ccылка – это другое имя переменной (объекта). Синтаксис объявления ссылочной переменной имеет следующий вид:

Тип &имя ссылки=имя объекта;

Например:

int x = 20;

float y;

int &n = x;

float &m =y;

После таких объявлений ссылочные переменные n и m будут определять местоположение в памяти переменных x и y, т.е., если ссылке присваивается значение, то и переменная получит тоже значение.

При объявлении ссылочной переменной она обязательно должна быть проинициализирована, так как в противном случае неясно на какой объект будет производиться ссылка. При обращении к ссылочным переменным нет необходимости в операции снятия ссылки, т. е. переменные n и m будут обрабатываться как “нормальные” переменные типов int и float.

Запишем теперь программу, изменяющую значения переменных с использованием ссылочных переменных:

void swap(int &a, int &b)

{

int temp;

temp = a;

a = b;

b = temp;

}

main()

{

int a, b;

a=2; b=3;

swap(a, b);

}

Передача массивов в качестве параметров

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

Пример:

void mass ( int n, int m, float A[10] )

{

int i;

for( i = 0; i < 10; i++)

scanf( “ %f ”, &A[ i ] );

}

main()

{

float B[10];

int a, b;

a = 3;

b = 3;

mass(a, b, B);

}

Следует

1.2.3 Рекурсивные вызовы функций

Любая функция в языке Си может быть вызвана рекурсивно, т. е. она может вызвать саму себя. Классический пример рекурсии – это вычисление факториала числа n! =1*2*3…*n.

Пример рекурсивной функции, вычисляющей значение факториала для n> 0:

fact (int n) // Название функции

{

int a;

if (n = = 1) return 1;

a = fact (n – 1)*n;

return a;

}

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

1.2.4 Функции с переменным количеством параметров

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

Формат заголовка такой функции:

Тип имя (спецификация_явных_параметров, …)

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

Пример:

long summa (int k, …)

{

int *p=&k;

long t=0;

for(;k;k--)t+=*(++p);

return t;

}

У каждой функции c переменным количеством параметров есть механизм определения количества и типов списка параметров функции при ее вызове. Существует два подхода:

1) Предусматривает передачу в функцию значения реального количества фактических параметров. Значения реального количества используемых фактических параметров можно передавать в функцию с помощью одного из явно задаваемых параметров.

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

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

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

Пример

#include <stdio.h>

long summa (int k, …) //k - число суммируемых параметров

{

int *p=&k;

long t=0;

for(; k; k--) t+=*(++p);

return t;

}

main()

{

long r,p;

r=summa(2,6,4);

p=summa(6,1,2,3,4,5,6);

printf (“r=%d\n”,r);

printf (“p=%d\n”,p);

}

Результат выполнения программы:

r=10

p=21

Для доступа к списку параметров используется указатель p типа int*. Вначале ему присваивается адрес явно заданного параметра k, т.е. он устанавливается на начало списка параметров в памяти (в стеке). Затем в цикле указатель p перемещается по адресам следующих фактических параметров, соответствующих неявным формальным параметрам. С помощью операции (*p) выполняется выборка их значений. Параметром цикла суммирования служит аргумент k, значение которого уменьшается на 1 после каждой итерации и, наконец, становится равным 0.

Особенность функции – возможность работы только с целочисленными фактическими параметрами, так как указатель p после обработки значения очередного параметра перемещается вперед на величину sizeof(int) и должен быть всегда установлен на начало следующего параметра.

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

Пример

#include <stdio.h>

double prod (double arg, …)

{

double aa = 1.0; // Формируемое произведение

double *p=&arg; // Настроили указатель на первый параметр

if(*p == 0.0) return 0.0;

for(; *p; p++) aa*=*p;

return aa;

}

void main()

{

double r, p;

r=prod(2.0, 4.0, 3.0, 0.0);

p=prod(1.4, 3.0, 0.0, 16.0);

printf (“r=%d\n”,r);

printf (“p=%d\n”,p);

}

Результат выполнения программы:

r=9.0

p=4.4

В функции prod перемещение указателя p по списку фактических параметров выполняется всегда за счет изменения p на величину sizeof(double). Поэтому все фактические параметры при обращении к функции prod должны иметь тип double. В вызовах функции проиллюстрированы некоторые варианты задания параметров. Обратите внимание на вариант с нулевым значением параметра в середине списка. Параметры вслед за этим значением игнорируются.

Чтобы функция с переменным количеством параметром могла воспринимать параметры различных типов, необходимо в качестве исходных данных каким-то образом передавать ей информацию о типах параметров. Для однотипных параметров возможно, например, такое решение – передавать с помощью дополнительного обязательного параметра признака типа параметров. Запишем функцию, выбирающую минимальное из значений параметров, которые могут быть двух типов: или только long, или только int. Признак типа параметра будем передавать как значение первого обязательного параметра. Второй обязательный параметр определяет количество параметров, из значений которых выбирается минимальное. В следующей программе предложен один из вариантов решения сформулированной задачи:

#include <stdio.h>

long minimum (char z, int k, …)

{

if(z==’i’)

{

int *pi=&k+1; // настроили на первый необязательный параметр

int min =*pi; // значение первого необязательного параметра

for (; k; k--, pi++)

min = min >*pi ? *pi : min;

return (long) min;

}

if(z==’l’)

{

long *pl = (long*)(&k+1);

long min = *pl; // Значение первого параметра

for (;k;k--,pl++)

min = min >*pl ? *pl : min;

return (long)min;

}

printf(“неверно задан 1-й параметр”);

return 2222L;

}

void main()

{

long p,p1;

p=minimum(‘l’,2,10L,20L);

p1=minimum(‘i’, 3,11,2,3);

}