Отличие процедур от функций в программировании

Процедуры и функции — методы класса

Аннотация: Процедуры и функции — две формы функционального модуля. Чем отличаются эти формы? Процедуры и функции — это методы класса. Описание методов (процедур и функций). Синтаксис. Атрибуты доступа. Формальные аргументы. Статус аргументов. Тело методов. Вызов процедур и функций. Фактические аргументы. Семантика вызова. Поля класса или аргументы метода? Поля класса или функции без аргументов? Проектирование класса Account. Функции с побочным эффектом. Перегрузка методов.

Процедуры и функции — функциональные модули

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

Процедуры и функции — методы класса

Долгое время процедуры и функции играли не только функциональную, но и архитектурную роль. Весьма популярным при построении программных систем был метод функциональной декомпозиции «сверху вниз», и сегодня еще играющий важную роль. Но с появлением ООП архитектурная роль функциональных модулей отошла на второй план. Для ООП-языков, к которым относится и язык C#, в роли архитектурного модуля выступает класс . Программная система строится из модулей, роль которых играют классы , но каждый из этих модулей имеет содержательную начинку, задавая некоторую абстракцию данных.

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

В данном контексте понятие класс распространяется и на все его частные случаи — структуры, интерфейсы, делегаты.

В языке C# нет специальных ключевых слов — procedure и function, но присутствуют сами эти понятия. Синтаксис объявления метода позволяет однозначно определить, чем является метод — процедурой или функцией .

Прежнюю роль библиотек процедур и функций теперь играют библиотеки классов . Библиотека классов FCL, доступная в языке C#, существенно расширяет возможности языка. Знание классов этой библиотеки и методов этих классов совершенно необходимо для практического программирования на C# с использованием всей его мощи.

Читайте также:  Связь программирования и математики

Уже в лекции 1 мы говорили о роли библиотеки FCL — статическом компоненте Framework .Net. В лекции 4 рассматривались возможности класса Convert этой библиотеки , а в лекции 7 — классы Math и Random . Изучение классов FCL будет постоянно сопровождать наш курс.

Процедуры и функции. Отличия

Функция отличается от процедуры двумя особенностями:

  • всегда вычисляет некоторое значение, возвращаемое в качестве результата функции ;
  • вызывается в выражениях.

Процедура C# имеет свои особенности:

  • возвращает формальный результат void , указывающий на отсутствие результата ;
  • вызов процедуры является оператором языка;
  • имеет входные и выходные аргументы , причем выходных аргументов — ее результатов — может быть достаточно много.

Хорошо известно, что одновременное существование в языке процедур и функций в каком-то смысле избыточно. Добавив еще один выходной аргумент , любую функцию можно записать в виде процедуры . Справедливо и обратное. Если допускать функции с побочным эффектом , то любую процедуру можно записать в виде функции . В языке С — дедушке C# — так и сделали, оставив только функции . Однако значительно удобнее иметь обе формы реализации метода: и процедуры , и функции . Обычно метод предпочитают реализовать в виде функции тогда, когда он имеет один выходной аргумент , рассматриваемый как результат вычисления значения функции . Возможность вызова функций в выражениях также влияет на выбор в пользу реализации метода в виде функции . В других случаях метод реализуют в виде процедуры .

Описание методов (процедур и функций). Синтаксис

Синтаксически в описании метода различают две части — описание заголовка и описание тела метода:

заголовок_метода тело_метода

Рассмотрим синтаксис заголовка метода:

[атрибуты][модификаторы] имя_метода([список_формальных_аргументов])

Имя метода и список формальных аргументов составляют сигнатуру метода . Заметьте, в сигнатуру не входят имена формальных аргументов — здесь важны типы аргументов. В сигнатуру не входит и тип возвращаемого результата .

Квадратные скобки (метасимволы синтаксической формулы) показывают, что атрибуты и модификаторы могут быть опущены при описании метода. Подробное их рассмотрение будет дано в лекциях, посвященных описанию классов . Сейчас же упомяну только об одном из модификаторов — модификаторе доступа. У него четыре возможных значения, из которых пока рассмотрим только два — public и private . Модификатор public показывает, что метод открыт и доступен для вызова клиентами и потомками класса . Модификатор private говорит, что метод предназначен для внутреннего использования в классе и доступен для вызова только в теле методов самого класса . Заметьте, если модификатор доступа опущен, то по умолчанию предполагается, что он имеет значение private и метод является закрытым для клиентов и потомков класса .

Обязательным при описании заголовка является указание типа результата, имени метода и круглых скобок, наличие которых необходимо и в том случае, если сам список формальных аргументов отсутствует. Формально тип результата метода указывается всегда, но значение void однозначно определяет, что метод реализуется процедурой . Тип результата, отличный от void , указывает на функцию . Вот несколько простейших примеров описания методов:

void A() ; int B(); public void C();

Методы A и B являются закрытыми , а метод С — открыт . Методы A и С реализованы процедурами , а метод B — функцией , возвращающей целое значение.

Источник

Функции и процедуры

Функции в программировании совсем незначительно отличаются от функций в математике. И там, и там нам нужен аргумент и возращаемое значение. Но не всё так просто.

Также существуют процедуры — блоки кода, не возращающие никакого значения, также могут не принимать аргументы.

Процедуры

Процедуры в языке C++ имеют тип void. Создадим процедуру, печатающую приветствие:

Вызываем данную процедуру в главной функции main:

Теперь создадим процедуру, которая будет печатать приветствие заданное число раз.

void hello(int n)  for (int i = 0; i  n; i++) cout  <"Hello!"  <endl; >

n — аргумент данной процедуры.

В функции main вызываем процедуру и указываем в скобках параметры:

int main()  hello(5); return 0; >

Таким образом, процедура hello печатает приветствии на экран 5 раз.

Функции

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

int sqr(int x)  return x * x; // возвращаем >

Здесь int — это тип возвращаемого значения, а return — это сам возврат.

int main()  cout  <sqr(13); return 0; >

Данный код возвел 13 в квадрат.

Также можем придумать что-то интересное:

bool is_zero(int n)  if (n == 0) return true; else return false; >

Аргументы функции

В качестве аргумента мы можем использовать значение по умолчанию:

long double energy(long double m, long double c = 10e+8)  return m * c * c; >

Данная функция вычисляет энергию по известному закону: \(E = mc^2\).

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

  • Перадача массива в функцию. Допустим, что перед нами поставили задачу: написать функцию, которая примет массив как аргумент и вернет среднее арифметическое его элементов. Чтобы передать массив в функцию, нужно передать указатель на первый элемент массива и размер самого массива. Вот так реализуется наша функция:
double average(int arr[], int size) // int arr[] int * arr  double sum = 0; for (int i = 0; i  size; i++) sum += arr[i]; return sum / size; > int main()  int arr[] =  1,3,8,16,2,32 >; // 6 элементов cout  <average(arr, 6); return 0; >

Рекурсия

Важным понятием в программировании является рекурсия. Рекурсия — это когда функция вызывает сама себя. Классическим примером рекурсии является факториал, когда значение умножениется на значение функции, уменьшенное на единицу, и так до 1. В данном случае 1 — базовый случай рекурсии. Базовый случай — это значение, которое должно остановить рекурсию. Если базовый случай отсутствует, мы получим бесконечную рекурсию.

int factorial(int n)  if (n == 0 || n == 1) // базовый случай return 1; else return n * factorial(n - 1); // обращение к самой себе >

Встроенные в язык функции

Вы наверняка уже встречались с функциями, встроенными в C++. Рассмотрим самые полезные и важные:

// возможно потребуется подключение sqrt(n); // квадратный корень pow(n, 2.0); // n^2 abs(n); // модуль sin(n); asin(n); // тригонометрические функции log(n); // логарифм round(n); // математическое округление ceil(n); // округление в большую сторону floor(n); // округление в меньшую сторону trunc(n); // отбрасывание дробной части числа exp(x); // экспонента

Рандом

rand() — это функция псевдослучайных чисел. Почему псевдослучайных? Потому, что при каждом запуске она будет генерировать одни и те же значения. Для того, чтобы пользоваться рандомом, подключаем библиотеку .

Заполним массив псевдослучайными числами при помощи rand():

int arr[100]; for (int i = 0; i  10; i++) arr[i] = rand(); for (int i = 0; i  10; i++) cout  <arr[i]  <" ";

Как можем заметить, при каждом запуске числа не меняются. Что же делать?

Выход есть! Используем высококачественный генератор случайных чисел — mt19937 rndm. Этот генератор основан на вихре Марсенна. Чтобы его использовать нам нужно зерно генерации. В качестве зерна можем использовать время, для этого подключаем .

int arr[100]; mt19937 rndm; rndm.seed(time(0)); // устанавливаем зерно for (int i = 0; i  10; i++) arr[i] = rndm(); for (int i = 0; i  10; i++) cout  <arr[i]  <" ";

Теперь уже больше походит на генерацию случайных чисел!

Стиль программирования и функции

Кака правило, оформление кода выше (когда функция пишется сразу после прототипа) подходит для маленьких проектов. Однако на практике такой подход не применяется. В больших проектах сначала пишется прототип функции — объявление функции без тела:

int sum(int a, int b); // прототип функции sum

Уже после главной функции мы пишем полную функцию с телом:

int sum(int a, int b)  return a + b; >

Таким образом весь наш файл main.cpp выглядит следующим образом:

#include using namespace std; int sum(int a, int b); int main()  cout  <sum(2,2); return 0; > int sum(int a, int b)  return a + b; >

В дальнейшем, когда мы будем пробовать писать собственные классы, мы будем все объявления хранить в заголовочном файле, а определения в другом файле. Таким образом, наш проект будет состоять из трех файлов: Header.h, Definition.cpp и main.cpp.

Стиль программирования, является не требованием, а пожеланием, потому что чистый, структурированный код улучшает его понимание другими людьми, и способствует более продуктивной работе. Поэтому в сообществе программистов были приняты некоторые соглашения касательно правил написания кода.

Источник

Оцените статью