Вівторок, 19.03.2024, 08:19
Гость

Мішатронік

Мобільна версія | Додати у вибране  | Мій профіль | Вихід | RSS |
Меню сайту
Наше опитування
Яка мова вам ближче?
Всього відповідей: 11
Статистика

Онлайн всього: 1
Гостей: 1
Користувачів: 0


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

 

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

 

Каждая функция может вызвать саму себя. Действие, состоящее в том, что функция вызывает сама себя, называется рекурсией.

 

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

 
! Так как при каждом обращении к рекурсивной функции создается новый набор объектов автоматической памяти, локализованных в теле функции, то при использовании рекурсивных алгоритмов с глубокой вложенностью рекурсии может быстро произойти переполнение стека реализации рекурсий, поэтому надежнее использовать итерационные алгоритмы. Например, пусть нужно реализовать "салфетку Серпинского" (геометрический фрактал). Как она образуется? Рисуется треугольник и в нем средние линии. В образованных при углах исходного треугольника новых треугольниках опять рисуются средние линии и так далее до заданного порядка вложенности рекурсии. Полученная "салфетка Серпинского" допускает другое, не рекурсивное, построение с помощью моделирования методом Монте-Карло.
 

Локальные переменные

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

 

Нахождение адресов

В результате выполнения операции & определяется адрес ячейки памяти, которая соответствует переменной. Если age - имя переменной, то &age - ее адрес. Можно представить себе адрес как ячейку памяти, но можно рассматривать его и как метку, которая используется компилятором для идентификации переменной. Предположим, мы имеем оператор

 
age=105;
 

Пусть также адрес ячейки, где размещается переменная age - 15125. В результате выполнения оператора

 
printf("%d %d\n", age, &age);
 

получим 105 15125.

 

Указатели, первое знакомство

Указатель - некоторое символическое представление адреса. В описанном примере &age означает указатель на переменную age. Фактический адрес - это число, а символическое представление адреса &age является константой типа указательАдрес ячейки, отводимой переменной age, в процессе выполнения программы не меняется. В языке Си имеются и переменные типа указатель. Точно так же как значением переменной типа char является символ, а значением переменной типа int - целое число, значением переменной типа указатель служит адрес некоторой величины. Если мы дадим указателю имя ptr, то сможем написать, например, такой оператор:

 
ptr = &age; 
/* присваивает адрес age переменной ptr */
 

Мы говорим в этом случае, что ptr указывает на age. Различие между двумя формами записи, ptr и &age, заключается в том, что ptr - это переменная, в то время как &age - константа. В случае необходимости мы можем сделать так, чтобы переменнаяptr указывала на какой-нибудь другой объект:

 
ptr = &name; 
/*ptr указывает на name, а не на age*/
 

Теперь значением переменной ptr является адрес переменной name.

 

Операция косвенной адресации *

Предположим, мы знаем, что в переменной ptr содержится ссылка на переменную name. Тогда для доступа к значению этой переменной можно воспользоваться операцией косвенной адресации *:

 
val = *ptr;
/* определение значения, на которое указывает ptr */
 

Последние два оператора, взятые вместе, эквивалентны следующему:

 
val = name;
 

Описание указателей

Примеры описания указателей:

 
int *pi; /*указатель на переменную типа целого*/
char *pc; /*указатель на символьную переменную*/
float *pf, *pg; 
/* указатели на переменные с плавающей точкой*/
 

Спецификация типа задает тип переменной, на которую ссылается указатель, а символ звездочка ( * ) определяет саму переменную как указатель. Описание вида int *pi говорит , что pi - это указатель и что *pi - величина типа int.

 

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

 
function1(x);
 

происходит передача значения переменной x. Если же мы используем форму обращения

 
function2(&x);
 

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

 
function1(num)
int num;
 

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

 
function2(&ptr)
int *ptr;
 
! Пользуйтесь первой формой, если входное значение необходимо функции для некоторых вычислений или действий, и второй формой, если функция должна будет изменять значения переменных в вызывающей программе. Программисты, работающие на языке Паскаль, могут заметить, что первая форма вызова аналогична обращению с параметром-значением, а вторая-с параметром-переменной.

Подведем итоги по указателям

Когда за знаком & следует имя переменной, результатом операции является адрес указанной переменной.

 

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

 

Пример:

 
age = 105;
ptr =&age;/*указатель на age*/
val= *ptr;
 

Результатом выполнения этого фрагмента является присваивание значения 105 переменной val.

 

Типичное определение функции имеет следующий вид:

 
имя (список аргументов)
описание аргументов
тело функции
 

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

 

Аргументы используются для передачи значений из вызывающей программы в функцию. Использование ключевого слова returnпозволяет передавать в вызывающую программу одно значение из вызываемой функции. Обычно выполнение функции не оказывает никакого влияния на значения переменных вызывающей программы. Чтобы иметь возможность непосредственно изменять значения переменных вызывающей программы, необходимо использовать указатели в качестве аргументов. Это может оказаться необходимым в случае, если в вызывающую программу требуется передать более чем одно значение.

 

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

 

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

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

 
тип имя(спецификация-явных-параметров,...);
 

Здесь тип - тип возвращаемого функцией значения; имя - имя функции.

 

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

 

Пример:

 
#include <stdio.h>
/* Функция суммирует значения своих параметров */
long summa(int m,...) /*m - число параметров*/
{
 int *p=&m; /*настроили указатель на параметр m*/
 long t=0;
 for(;m>0;m--) t+=*++p;
 return t;
}
void main()
{
 printf("\n summa(2,6,4)=%d",summa(2,6,4));
 printf("\n summa(6,1,2,3,4,5,6)=%d", summa(6,1,2,3,4,5,6));
}

 

Форма входа
Пошук
Друзі сайту
Календар
«  Березень 2024  »
ПнВтСрЧтПтСбНд
    123
45678910
11121314151617
18192021222324
25262728293031

Єдина Країна! Единая Страна!