Архив рубрики: Функции, Рекурсия, Область видимости переменных

В этой рубрике собраны статьи о функциях, рекурсии, области видимости переменных в языке программирования C++

Область видимости переменных (часть 2)




c++, локальные и глобальные переменные, область видимости переменных, с++ для начинающих, пространство именВы уже познакомились с первой статьей по теме Локальные и глобальные переменные. Область видимости в С++. Хотелось бы ещё немного дополнить её. А именно примером с пространствами имен. Я не зря писал префикс std:: перед оператором вывода cout. и endl. Это тоже одна из формаций области видимости — пространство имен. Если не вдаваться в особые подробности, пространство имен, это некая группа операторов / функций / переменных / типов, объединенная в такую себе «фракцию» с именем std.

std это пространство имен из заголовочного файла (хедера по нашему) iostream. cout, cin, endl и др. — это все «династия» std. Если не подключить его в коде и не написать std:: перед этими операторами, С++ скажет «давай до свиданья». Потому что он не в курсе, что это за cout такой без «фамилии». Кстати в С++ и придуман оператор using namespace, который позволяет не писать имя пространства в качестве префикса к каждому входящему в него оператору . Это для удобства сделано, но нужно с этим оператором быть аккуратнее, если есть одноименные функции используемые в программе из разных пространств имен.

Пространство имен хорошо там, где нужно сгруппировать что-то в область видимости по имени. Например в программе могут быть описаны две разные функции sum(). Одна возвращает целое, вторая вещественное. Если по заданию их нельзя описывать как перегруженные, то можно вкрутить их в пространство имен:

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

c++, локальные и глобальные переменные, область видимости переменных, с++ для начинающих, пространство имен

Вообще пространство имен может стать спорным моментом относительно теории области видимости. По факту это просто группировка по имени, но действует она так же, как и блок операторов {…}. Хочешь обратиться к операторам из этого пространства — будь добр обратись сначала к имени пространства: integer :: sum() Тут двоеточие :: — это оператор расширения области видимости.

Пожалуй последнее, что можно сказать — область видимости весьма показательна в ООП (объектно ориентированное программирование). Когда в классе программист описывает private свойство (переменую или функцию-метод), он задает ей область видимости. Например в коде типа:

Свойства k и kc имеют разные области видимости. Первая доступна только внутри методов класса. К ней нельзя обратиться в основной программе, она приватная (private ). Закрытая для всех, кроме области видимости самого класса.

Вторая публичная (public). Её область видимости выходит за пределы класса. Из программы, где будет вызываться объект этого класса она доступна.

c++, локальные и глобальные переменные, область видимости переменных, с++ для начинающих, пространство имен

kc объявлена как публичная переменная, её область видимости в отличии от переменой k , шире. Поэтому компилятор не против её использования вне пределов класса.

Какой можно сделать из всего этого вывод? Гики с пеной у рта кричат на всех порталах — «долой глобальные переменные!». Гикам нравится ограничивать область видимость, локализуя и упаковывая всё в классы или пространства имен. Гики есть гики. Программист не должен злоупотреблять областью видимости, иначе получится, оказия, когда чтоб обратиться к переменной нужно писать её путь. Т.е. что-то типа myname::group1::PeremenkiDlaPrepoda::i Ну жесть просто.

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

Если вы не смотрели видео по теме Область видимости в С++ в предыдущем уроке — специально для вас размещаем его тут:

Рассылка новых уроков по программированию:

Локальные и глобальные переменные. Область видимости.




c++, локальные и глобальные переменные, область видимости переменных, с++ для начинающихДля примерного понимания локализации переменных пожалуй начнем с аллегории. Что такое «Локальность»? Это ограниченность места дееспособности. Область видимости переменной — это тот участок кода (функция, цикл, пространство имени), в котором эта переменная объявлена (прописана). Вне этого участка — компилятор её не видит (она недоступна).

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

Давайте разберем пример поближе. Итак мы имеем переменную i, которая описана вне любых функций в программе. Ее область видимости и действия — вся программа без ограничения. А раз она «легитимна» во всей программе, во всех ее функциях и блоках операторов, заключенных в {}, то её называют Глобальной переменной.

Так же у нас в примере видна функция sum(), которая чего-то делает. В ней внутри описана вторая переменная — k. Она уже имеет конкретную «прописку» — функция. При этом данная переменная не может быть использована за пределами функции. Т.е. если в функции main() дописать еще и вывод этой k на экран, компилятор начнет «ругаться». Он ее просто напросто не видит вне функции sum(). Проверьте:

Переменная k называется локальной, и ее область видимости определена открывающей и закрывающей фигурными скобками функции sum(){…}. Дальше них ей хода нет, поэтому и использовать её нельзя вне этой функции. Компилируем:

c++, локальные и глобальные переменные, область видимости переменных, с++ для начинающих

Однако, нужно также учесть, что область видимости распространяется и на внутренние блоки. Для примера можно рассмотреть такой код:

Здесь проявлены следующие области видимости:

  • Глобальная — i = 2 принадлежит ей;
  • Локальная относительно функции — переменная k;
  • Локальная относительно цикла for() — вторая i.

Несмотря на то, что у for есть своя область видимости, сам for принадлежит функции sum(). А значит он, и все что в нем находится, подчиняется локальной области видимости этой функции. Т.е. все переменные, определенные в функции так же действительны и в теле for, что и позволяет работать оператору k += 1 (он же k = k+1 или k++).

Интереснее дело обстоит с переменной i, которая описана внутри for. Несмотря на имя, идентичное с глобальной переменной описанной выше, это уже другая переменная.

Как только цикл свое отработал, переменная i, описанная в нём, теряет свои полномочия, или иначе говоря — «освобождается» от обязанностей. Это не шутка — именно так и поступает менеджер памяти. Когда переменная описывается, менеджер резервирует под неё память, а когда её область видимости заканчивается — память эта освобождается. Менеджер памяти у себя помечает, что этот участок памяти более не принадлежит кому-либо, и его можно отдавать под запись других данных.

Для закрепления еще один легкий примерчик:

Здесь область видимости описана блоками операторов, ограничивающимися {}, Т.е. первый cout выведет 2, потому что определен блок операторов, в котором сработает это cout. И в этом же блоке определена локальная переменная с именем а, из нее он и возьмет значение прежде всего.

c++, локальные и глобальные переменные, область видимости переменных, с++ для начинающих

А уже за пределами {} оператор cout выведет 0, поскольку для него не существует той а, что равнялась 2. Его область видимости совпадает с другой а, которая равна 0, и определена выше вложенного блока.

Вообще запомните — в реальной жизни никогда не надо давать одинаковые имена переменным (за исключением тех, что классически используют для счетчиков циклов. Например i, j, k. Если у вас 10 циклов в коде и они не вложенные, то для каждого из них можно объявлять и определять счетчик с именем i. Это нормально). В других случаях, всегда давайте переменным уникальные имена, если не хотите, чтобы вас потом «вспоминали» программисты, которые будут разбираться в вашем коде.

Предлагаем также просмотреть видеоурок по теме область видимости. Автор видеоурока: Марков Денис

Рассылка новых уроков по программированию:

Встроенные функции (inline-функции)




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

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

Итак, что из себя представляет обычная функция? Возьмем например простой пример — вычисление факториала.

Достаточно простые вычисления факториала (5!) в цикле for, и возврат результата из функции. С++ расценивает эту функцию как некий блок операций, сгруппированный в отдельный блок. Блок этот после компиляции помещается в ячейки памяти единожды в коде, и тело функции (цикл в данном случае) нигде больше в скомпилированной программе не повторяется. Все красиво — получается некий участок памяти, принадлежавший программе, на который процессор при необходимости перескакивает с того места, где находит вызов.

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

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

Если описать наш факториал так:

То вместо

мы получим разворот функции в набор операторов:

как будто бы сами в коде написали в этом месте.

Соответственно код типа:

превратится в

Если мерить философски — количество кода с inline функцией увеличилось. Вместо одной строки вызова функции ее тело, подставленное вместо вызова , дало целых 6 строк. Так же будет и в скомпилированной программе — количество операторов возрастет многократно — на столько, сколько операторов в теле функции и сколько раз ее вписали в программу.

Т.е. различие между inline функцией и обычной функцией — дублирование кода тела функции везде, где она оказывается задействована. В обычной функции, её тело находится в единственном экземпляре в одном и том же месте внутри программы.

Где здесь выгода спросите вы? Экономится время процессора на прыжки с места вызова в тело функции. Если функция огромная и используется в нескольких местах, то inline получается не совсем выгодно. Однако, если функция (тело её) маленькое, с минимальным количеством операторов, решающих задачу, в старину было удобнее отказаться от прыжка и просто подставить их в нужное место, как будто сам программист там их описал.

Как бы там ни было, в бытовых условиях да еще и на современных компьютерах, программы, использующие inline подстановку тела функции вместо вызова, не дают особых преимуществ. Поэтому использовать этот вид функции приходится достаточно редко. ИМХО, ему место в музее славы. Хотя, чтоб быть до конца честным, такой подход дает свои плоды тем, кто программирует контроллеры, процессоры и прочие железяки. Но там свои особенности и свой подход, и в это углубляться сейчас не стоит. Использовать встроенную функцию (inline функцию) или нет — решать самому программисту. От себя могу добавить только одно — не стоит делать это там, где этого не требуется по заданию.




Рассылка новых уроков по программированию:

Рекурсия в С++





рекурсия с++, рекурсия c++

В C++ любая функция кроме main() может вызывать саму себя. То есть в теле функции может быть размещен вызов этой же функции. Это называется рекурсией.

Когда программа выполняет код рекурсивной функции — она будет выполнять его бесконечно, если не предусмотреть условие выхода из рекурсии. Об этом надо помнить, чтобы избежать зацикливания вызовов. Поэтому в определении рекурсивной функции обязательно надо указывать условие выхода. Например, можно разместить её вызов внутри блока if.

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

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

будет выполняться тоже 10 раз, но значение someNumber будет меняться в обратном порядке. Сначала оно будет соответствовать тому, что передалось в функцию на 10 уровне рекурсии, потом тому что передалось на 9 уровне и т.д.

рекурсия с++, рекурсия c++

Хочу обратить внимание на важный момент. При каждом рекурсивном вызове создается новая переменная someNumber с новым значением. Эти переменные будут занимать какое-то место в оперативной памяти. Если вызовов 10, как в нашем примере, то и в памяти будет храниться 10 переменных с разными значениями. Можно дописать в программу вывод на экран адресов, по которым хранятся эти значения и убедиться в этом:

Передаем в функцию число 2: recursionGoDown(2); Уровней рекурсии будет 3.

рекурсия с++, рекурсия c++

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

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

Но, как утверждают опытные программисты и многие авторы книг, это не значит, что рекурсия бесполезна. Есть задачи, решать которые, используя итерации циклов, сложно и громоздко. А рекурсивное решение выглядит лучше. Для начального уровня, пока вы изучаете только основы программирования на C++, вам достаточно просто понимать, что из себя представляет рекурсия и как она работает.

Посмотрите ещё видео по теме Рекурсия с 6′ (Автор видео: Денис Марков).

Рассылка новых уроков по программированию:

Шаблоны функций C++





шаблоны функций c++, шаблоны функций с++, template c++

Немного ранее была рассмотрена тема о перегрузке функций в C++. Вы узнали о возможности написать несколько функций с одинаковым именем, которые выполняют одинаковые задачи. Основное отличие между ними — сигнатура (типы параметров и/или количество параметров). При запуске программы, компилятор сам выберет, какую из перегруженных функций применить (исходя из того, что передано в функцию)

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

шаблоны функций c++, шаблоны функций с++, template c++

Определяя шаблон функции мы использовали зарезервированные слова C++: template и typename. template говорит о том, что сейчас будет определен шаблон. А в угловых скобках после typename дается условное имя типу данных. Тут, вместо имени T, можно присвоить любое (очень желательно корректное) имя.

Далее определяется сама функция. Тип возвращаемого значения указываем T. Параметры: число типа T, и число типа int. Эта функция считает процент от числа и возвращает значение в программу. И число, и процент передаются как параметры. Например первым параметром мы передадим в функцию целое число (100). Во время запуска, компилятор отметит себе что T это int и заменит в шаблоне функции все эти T на int. Таким образом для компилятора функция примет вид:

шаблоны функций c++, шаблоны функций с++, template c++

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

В итоге на экране увидим такой результат расчетов:шаблоны функций c++, шаблоны функций с++, template c++

Говоря об определении шаблона функции, хочется добавить, что в угловые скобки после ключевого слова template возможно записать несколько условных имен для типов данных. Зачем это может понадобиться? Рассмотрим такой пример:

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

Первый и второй параметры функции определены, как параметры типа T. С вызовами функции в строках 19-20 проблем не возникает, так как передаваемые параметры имеют одинаковый тип данных. Проблемы возникнут в строке 22 при компиляции. И это понятно. Компилятор запутается. Он не может преобразовать тип int в double.

шаблоны функций c++, шаблоны функций с++, template c++

Чтобы обойти эту проблему, надо написать другой шаблон.

Тут typename T_1 обозначает тип параметра, который передается в функцию первым. typename T_2 соответственно обозначает тип второго параметра. Такой вариант определения шаблона функции предупредит ошибки, возникающие при передаче параметров разных типов.

шаблоны функций c++, шаблоны функций с++, template c++

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

шаблоны функций c++, шаблоны функций с++, template c++

приводит к следующим ошибкам:

шаблоны функций c++, шаблоны функций с++, template c++

В шаблоне мы определили условные им типов T_1 и T_2, а в сигнатуре прописали только тип T_1 .

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

шаблоны функций c++, шаблоны функций с++, template c++

оно равнозначно тому определению, которое мы рассматривали

шаблоны функций c++, шаблоны функций с++, template c++

Ранее, до выхода стандарта C++98, в шаблонах всегда использовали слово class. Сейчас же лучше, когда появилось ключевое слово typename , лучше применять его. Так как оно более явно говорит о том, что имена T_1 и T_2 представляют тип.

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

Обязательно посмотрите видео. О шаблонах с 14-й минуты:

Рассылка новых уроков по программированию:

Перегрузка функций в C++





перегрузка функций с++, перегрузка функций c++

Возможно, кого-то из новичков пугает название темы «Перегрузка функций»? Меня пугало. Казалось — это что-то, с чем придется долго разбираться. На самом деле, перегрузку функций очень легко понять. Сложного нет ничего.

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

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

В следующей программе определены три перегруженные функции с именем sumElements(). Все они вычисляют сумму элементов массивов. Одна принимает массив типа int и его размер. Вторая принимает массив типа double и его размер. Третья принимает два массива с типом элементов int и double и их размер.

Определения перегруженных функций находятся в строках 31 — 61. В них создается переменная для накопления суммы значений элементов массива. В цикле for сумма накапливается. Далее полученное значение возвращается в программу, на место вызова перегруженной функции.

Обращение ко всем трём функциям производится по одному и тому-же имени — строки 17, 21, 25. Передав в функцию при вызове массив типа int и его размер, компилятор сам автоматически определит, какую из трёх перегруженных функций ему необходимо использовать. Точно так же произойдет и во время вызова остальных функций.

перегрузка функций с++, перегрузка функций c++

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

Как делать не надо:

перегрузка функций с++, перегрузка функций c++

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

Посмотрите короткое видео о перегрузке:

Рассылка новых уроков по программированию:

Параметры (аргументы) функции по умолчанию.




c++ параметры  по умолчанию, c++ аргументы  по умолчанию Мы уже говорили о параметрах функции в отдельной статье. В этой — мы коротко разберемся, что такое параметры функции по умолчанию. Понять это несложно. Используют их в программировании в основном для удобства. Например нам надо нарисовать 5 одинаковых прямоугольников. Для этого мы можем написать функцию, которая принимает параметры по умолчанию. Рисует она, допустим, прямоугольник 10 на 10 символов. И этот символ всегда ‘@’:

Хотя мы не передавали в функции никаких параметров при вызове, мы увидим пять одинаковых прямоугольников из символов ‘@’ на нашем экране. Функция использовала те значения, которые были присвоены параметрам по умолчанию при её определении.

Но это не всё. Даже если мы определили параметры по умолчанию — есть удобная возможность изменить их значения при вызове.

Допустим, надо нарисовать прямоугольник 5 символов в ширину. Остальные параметры (10 символов в высоту и сам символ ‘@’ ) нас устраивают. Тогда в функцию мы передаем только один параметр. Оставшиеся параметры функция возьмет из заданных по умолчанию.

c++ параметры  по умолчанию, c++ аргументы  по умолчанию

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

c++ параметры  по умолчанию, c++ аргументы  по умолчанию

На экране увидим:

c++ параметры  по умолчанию, c++ аргументы  по умолчанию

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

параметры  по умолчанию с++, аргументы по умолчанию с++, c++

На картинке параметр по умолчанию последний : char symb = ‘@’. Если их надо определить два — то точно так же это будут два крайних справа:

Если вы объявляете прототип функции — надо определить параметры по умолчанию именно в прототипе. В самом определении функции этого делать уже не надо. Пожалуй всё. Если что-то не понятно — спрашивайте в комментариях.

Рассылка новых уроков по программированию:

Функции в C++




функции в с++, функции c++

Пройдя не такой уж долгий путь от нашего первого урока к этому, вы «подошли» к изучению функций в C++. Функции — это именованный фрагмент кода, который повторяется в программе 2 или больше раз . Когда мы пишем функцию, необходимо дать ей имя и в дальнейшем, чтобы её вызвать в программе (из main() или из другой функции), надо обратиться к ней по этому имени.

Мы уже встречали функции в предыдущих уроках. Это функции для строк (символьных массивов) strlen(), strcmp(), функция для генерации случайных чисел rand(). Мы их применяли в программах и, например, передавали в функцию strlen() строку, а она нам возвращала количество символов в этой строке (целое число). Это конечно происходило не волшебным образом, а функция принимала нашу строку, обрабатывала её и возвращала нам значение, которое подсчитала. То есть кто-то до нас написал этот самый код функции, которая считает длину строки и мы успешно ею пользуемся в своих программах. И эта функция здорово экономит наше время, сокращает количество строк кода и облегчает его читаемость.

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

До определённого времени можно обходиться и без функций. Вместо этого плодить одинаковый участок кода во всей программе. Но если придется изменить этот код (усовершенствовать или что-то убрать из него), придется вносить изменения по всей программе. Лучше сразу освоить тему функций и активно применять.

Определить функцию можно двумя способами:

  • до main-функции;
  • после main-функции. В этом случае необходимо до main-функции объявить прототип собственной функции.

В этой статье и следующих мы будем пользоваться вторым способом, так как он является более распространённым. Первый способ можно использовать, если функция одна и её код совсем небольшой. Пока мы пишем простые программы, такое встречается часто. Но для программ посложней, будем писать несколько функций которые будут состоять не из 2-3 строк, а побольше. Покажу вам как выглядит определение функции до main():

С использованием прототипа это будет выглядеть так:

Прототип функции размещен в строке 4, а её определение находится в самом низу программы в строках 20 — 25. Что касается выполнения программы: сначала компилятор прочтет прототип. Это даст ему знать о том, что где-то после main() располагается определение этой функции. Далее начнется выполнение главной функции main(). Выполняться она будет, пока компилятор не встретит имя функции ourFunctionForPrint(). Тогда он найдет определение этой функции, которое расположено после main(), по имени, указанному в прототипе, выполнит её код, после чего снова вернется к выполнению команд main-функции.

В итоге на экране увидим:

функции в с++, функции c++

Поговорим об определении функций.

Функции в C++ могут не возвращать никаких значений (как в примере) и могут возвращать какое-либо значение. Если функция не возвращает ничего, то это функция типа void.

Синтаксис функции, которая не возвращает значений:

функции c++, функции в с++

Имя функции следует давать придерживаясь правил для имен переменных. Единственное — желательно чтобы оно содержало глагол, так как функция выполняет действие. Например если она считает среднее арифметическое можно дать название calculateAverage, если выводит что-то на экран — showText. Имя должно говорить за себя, чтобы не пришлось оставлять лишние комментарии в коде.

Параметры (или аргументы функции) — это данные, которые функция принимает и обрабатывает в теле. Если функции не нужно ничего принимать для обработки, круглые скобки оставляют пустыми. Согласно правилам High Integrity C++ Coding Standard желательно не определять функции с большим количеством параметров (больше 6).

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

Принимает один параметр:

В 10-й строке кода функция получает параметр — целое число 7. С ним (с этим числом) произойдет то, что описано в определении функции — строки 16 — 22. А именно — это число подставится в заголовок цикла for. Выражение i < questionCount станет равнозначным i < 7 . В итоге мы увидим на экране 7 знаков вопроса.

функции в с++, функции c++

Принимает три параметра:

функции c++, функции в с++

Синтаксис функции, которая возвращает значение:

функции в с++, функции c++

Такие функции отличаются тем, что необходимо указать тип значения, которое вернет функция в результате своей работы. Сам возврат значения в программу оформляется оператором return и это значение программа получит в том месте, где функция была вызвана . return может возвращать переменную, константу или результат выражения (например: return variable1 - variable2; ). В теле функции могут находиться несколько операторов return. Тогда, работа функции завершится, если сработает какой-то один из этих операторов. Например:

Определение функции располагается в строках 28 — 34. Если пользователь введет +, сработает блок if в строке 30, а в нём соответственно сработает return d1 + d2; . После этого код функции уже не будет обрабатываться дальше. Компилятор вернется к выполнению main-функции.

функции c++, функции в с++

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

Еще немного о прототипе: прочитав его до main, компилятор получает сведения о том, какой тип возвращаемого значения будет у функции (или она вообще не возвращает значения — имеет тип void) и о том, какие параметры будут в неё переданы, в каком количестве и в какой последовательности.

Прототип int calculateSomeDigits(int d1, int d2, char ch); говорит компилятору, что функция вернет на место её вызова целое число и о том, что при вызове в нее должно быть передано два целых числа и один символ. При вызове функции, мы должны передать ей столько параметров сколько указано в её заголовке при определении. Передавать параметры необходимо в том же порядке, как они определены в круглых скобках за именем функции. Иначе возникнут ошибки при компиляции либо программа будет работать некорректно.

Синтаксис прототипа функции:

прототип функции в C++

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

функции в с++, функции c++, прототип функции

Имена переменных-параметров в прототипе можно не указывать. Следующий прототип равнозначен тому, что выше.

функции в с++, функции c++, прототип функции

На мой взгляд, все же лучше объявлять прототипы функций с указанием имён параметров. Особенно если параметров несколько и они имеют одинаковый тип. Для читаемости и понимания программы так будет лучше.

Чтобы закрепить то, о чём говорили в этой статье, надо попрактиковаться. Смотрите статью с задачами на функции в C++ . В ней вы так же найдете информацию о том, как передавать в функции массивы в виде параметров. Совет — не просто читайте, а пишите код! Желательно своими силами.

Видео по теме:

Следите за обновлениями на нашем сайте и делитесь ссылками на статьи с друзьями!

Рассылка новых уроков по программированию: