Tw-city.info

IT Новости
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Функции в программировании c

Функции в языке Си

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

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

Семантика функции определяет способ реализации функции. Обычно представляет собой тело функции.

Определение функции

Каждая функция в языке Си должна быть определена, то есть должны быть указаны:

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

Определение функции имеет следующий синтаксис:

Пример : Функция сложения двух вещественных чисел

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

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

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

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

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

Разбиение программ на функции дает следующие преимущества:

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

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

Вызов функции

Общий вид вызова функции

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

Возврат в вызывающую функцию

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

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

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

Функции могут и не возвращать значения, а просто выполнять некоторые вычисления. В этом случае указывается пустой тип возвращаемого значения void , а оператор return может либо отсутствовать, либо не возвращать никакого значения:

Пример : Посчитать сумму двух чисел.

В языке Си нельзя определять одну функцию внутри другой.

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

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

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

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

Рекурсивные функции

Функция, которая вызывает сама себя, называется рекурсивной функцией .

Рекурсия — вызов функции из самой функции.

Пример рекурсивной функции — функция вычисления факториала.

Функции

Введение

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

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

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

Мы уже знакомы с многими функциями и знаем, как их вызывать – это функции библиотек stdio, stdlib, string, conio и пр. Более того, main – это тоже функция. Она отличается от остальных только тем, что является точкой входа при запуске приложения.
Функция в си определяется в глобальном контексте. Синтаксис функции:

Самый простой пример – функция, которая принимает число типа float и возвращает квадрат этого числа

Внутри функции sqr мы создали локальную переменную, которой присвоили значение аргумента. В качестве аргумента функции передали число 9,3. Служебное слово return возвращает значение переменной tmp. Можно переписать функцию следующим образом:

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

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

Если функция не принимает аргументов, то скобки оставляют пустыми. Можно также написать слово void:

Формальные и фактические параметры

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

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

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

Передача аргументов

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

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

Вот теперь программа выводит
200
100
100
Здесь также была создана локальная переменная, но так как передан был адрес, то мы изменили значение переменной d, используя её адрес в оперативной памяти.

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

Но эта функция выведет ERROR. Мы передали адрес переменной. Внутри функции init была создана локальная переменная a, которая хранит адрес массива. После выхода из функции эта локальная переменная была уничтожена. Кроме того, что мы не смогли добиться нужного результата, у нас обнаружилась утечка памяти: была выделена память на куче, но уже не существует переменной, которая бы хранила адрес этого участка.

Читать еще:  Операторы в программировании c

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

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

В этом примере утечки памяти не происходит. Мы выделили память с помощью функции malloc, скопировали туда строку, а после этого вернули указатель. Локальные переменные были удалены, но переменная test хранит адрес участка памяти на куче, поэтому можно его удалить с помощью функции free.

Объявление функции и определение функции. Создание собственной библиотеки

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

Это смешанная рекурсия – функция odd возвращает 1, если число нечётное и 0, если чётное.

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

Давайте создадим простую библиотеку. Для этого нужно будет создать два файла – один с расширением .h и поместить туда прототипы функций, а другой с расширением .c и поместить туда определения этих функций. Если вы работаете с IDE, то .h файл необходимо создавать в папке Заголовочные файлы, а файлы кода в папке Файлы исходного кода. Пусть файлы называются File1.h и File1.c
Перепишем предыдущий код. Вот так будет выглядеть заголовочный файл File1.h

Содержимое файла исходного кода File1.c

Наша функция main

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

Заголовочный файл, как и оговаривалось ранее, содержит прототип функций. Также здесь могут быть подключены используемые библиотеки. Макрозащита #define _FILE1_H_ и т.д. используется для предотвращения повторного копирования кода библиотеки при компиляции. Эти строчки можно заменить одной

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

Передача массива в качестве аргумента

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

В этом примере функция может иметь следующий вид

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

Либо, можно писать

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

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

На этом первое знакомство с функциями заканчивается: тема очень большая и разбита на несколько статей.

Функции в C++ — урок 6

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

А вот аналогичный пример с функцией:

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

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

Если функция не возвращает никакого значения, то она должна иметь тип void (такие функции иногда называют процедурами)

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

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

    Перед вами тривиальная программа, Hello, world, только реализованная с использованием функций.

    Если мы хотим вывести «Hello, world» где-то еще, нам просто нужно вызвать соответствующую функцию. В данном случае это делается так: function_name(); . Вызов функции имеет вид имени функции с последующими круглыми скобками. Эти скобки могут быть пустыми, если функция не имеет аргументов. Если же аргументы в самой функции есть, их необходимо указать в круглых скобках.

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

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

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

    В данном случае функция check_pass имеет тип string, следовательно она будет возвращать только значение типа string, иными словами говоря строку. Давайте рассмотрим алгоритм работы этой программы.

    Самой первой выполняется функция main(), которая должна присутствовать в каждой программе. Теперь мы объявляем переменную user_pass типа string, затем выводим пользователю сообщение «Введите пароль», который после ввода попадает в строку user_pass. А вот дальше начинает работать наша собственная функция check_pass() .

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

    Аргумент функции — это, если сказать простым языком переменные или константы вызывающей функции, которые будет использовать вызываемая функция.

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

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

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

    Теперь мы проверяем, правильный ли пароль ввел пользователь или нет. если пользователь ввел правильный пароль, присваиваем переменной error_message соответствующее значение. если нет, то сообщение об ошибке.

    После этой проверки мы возвращаем переменную error_message . На этом работа нашей функции закончена. А теперь, в функции main(), то значение, которое возвратила наша функция мы присваиваем переменной error_msg и выводим это значение (строку) на экран терминала.

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

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

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

    Совет: не бойтесь экспериментировать, это очень хорошая практика, а после прочтения данной статьи порешайте элементарные задачи, но с использованием функций. Это будет очень полезно для вас.

    Если Вы найдете какие-либо ошибки в моем коде, обязательно напишите об этом в комментариях. здесь же можно задавать все вопросы.

    Пользовательские функции в Си

    Пожалуйста, приостановите работу AdBlock на этом сайте.

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

    Помните, мы говорили о парадигмах программирования, а точнее о структурном программировании. Основной идеей там было то, что любую программу можно можно написать используя только три основных конструкции: следование, условие и цикл. Теперь к этим конструкциям мы добавим ещё одну – «подпрограммы» – и получим новую парадигму процедурное программирование» .

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

    Читать еще:  Язык программирования шарп

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

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

    Как устроены функции

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

    С телом функции всё ясно: там описывается алгоритм работы функции. Давайте разберёмся с заголовком. Он состоит из трёх обязательных частей:

    • тип возвращаемого значения;
    • имя функции;
    • аргументы функции.

    Сначала записывается тип возвращаемого значения, например, int , как в функции main . Если функция не должна возвращать никакое значение в программу, то на этом месте пишется ключевое слово void . Казалось бы, что раз функция ничего не возвращает, то и не нужно ничего писать. Раньше, кстати, в языке Си так и было сделано, но потом для единообразия всё-таки добавили. Сейчас современные компиляторы будут выдавать предупреждения/ошибки, если вы не укажете тип возвращаемого значения.
    В некоторых языках программирования функции, которые не возвращают никакого значения, называют процедурами (например, pascal). Более того, для создания функций и процедур предусмотрен различный синтаксис. В языке Си такой дискриминации нет.

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

    Давайте посмотрим на заголовки уже знакомых нам функций.

    Как создать свою функцию

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

    Рис.1 Уточнение структуры программы. Объявление функций.

    Как видите, имеется аж два места, где это можно сделать.

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

    Давайте я подробно опишу, как будет работать эта программа. Выполняется тело функции main . Создются целые переменные x , y и m . В переменные x и y считываются данные с клавиатуры. Допустим мы ввели 3 5 , тогда x = 3 , y = 5 . Это вам всё и так должно быть понятно. Теперь следующая строчка

    Переменной m надо присвоить то, что находится справа от знака = . Там у нас указано имя функции, которую мы создали сами. Компьютер ищет объявление и описание этой функции. Оно находится выше. Согласно этому объявлению данная функция должна принять два целочисленных значения. В нашем случае это значения, записанные в переменных x и y . Т.е. числа 3 и 5 . Обратите внимание, что в функцию передаются не сами переменные x и y , а только значения (два числа), которые в них хранятся. То, что на самом деле передаётся в функцию при её вызове в программе, называется фактическими параметрами функции.

    Теперь начинает выполняться функция max_num . Первым делом для каждого параметра, описанного в заголовке функции, создается отдельная временная переменная. В нашем случае создаются две целочисленных переменных с именами a и b . Этим переменным присваиваются значения фактических параметров. Сами же параметры, описанные в заголовке функции, называются формальными параметрами. Итак, формальным параметрам a и b присваиваются значения фактических параметров 3 и 5 соответственно. Теперь a = 3 , b = 5 . Дальше внутри функции мы можем работать с этими переменными так, как будто они обычные переменные.

    Создаётся целочисленная переменная с именем max , ей присваивается значение b . Дальше проверяется условие a > b . Если оно истинно, то значение в переменной max следует заменить на a .

    Далее следует оператор return , который возвращает в вызывающую программу (функцию main ) значение, записанное в переменной max , т.е. 5 . После чего переменные a , b и max удаляются из памяти. А мы возвращаемся к строке

    Функция max_num вернула значение 5 , значит теперь справа от знака = записано 5 . Это значение записывается в переменную m. Дальше на экран выводится строчка, и программа завершается.

    Внимательно прочитайте последние 4 абазаца ещё раз, чтобы до конца уяснить, как работает программа.

    А я пока расскажу, зачем нужен нижний блок описания функций. Представьте себе, что в вашей программе вы написали 20 небольших функций. И все они описаны перед функцией main . Не очень-то удобно добираться до основной программы так долго. Чтобы решить эту проблему, функции можно описывать в нижнем блоке.

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

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

    Всё очень просто. Обратите внимание, что у прототипа функции можно не указывать имена формальных параметров, достаточно просто указать их типы. В примере выше я именно так и сделал.

    Практика

    Решите предложенные задачи:

    Для удобства работы сразу переходите в полноэкранный режим

    Записная книжка программиста-новичка, C#, SQL, PHP и все-все-все

    Я ведь это уже делал, но хрен теперь найдешь тот кусок кода, гуглим снова… Где бы найти простое и понятное руководство для начинающего, а не тонкости для мега-гуру?

    Навигация по записям

    Самоучитель по C# для начинающих. 02. Функции, классы, обьекты, коллекции

    2.1 Функции.

    Вернемся к старой задаче — выводе данных о людях. У нас есть разные люди с данными в виде отдельных фамилии, имени, отчества, которые надо вывести на экран — вида Пушкин Александр Сергеевич и Пушкин А.С. Чтобы задача была правдоподобней можно имитировать ввод данных пользователем или загрузку из внешнего источника, но все это будет пустой тратой времени — реальные приложения все равно работают с графическим и/или веб-интерфейсом. Просто держим в уме что в реальности людей не два, а две тысячи и заранее их имена не известны.

    Получаем уродливый код

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

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

    Слова public static отложим на пару минут в сторону, string означает, что функция вернет назад строку, CreateFio(string surname, string name, string otchestvo) — название функции и описание того, что она принимает на вход три строки.

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

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

    Весь код тестовой программы с функциями

    2.2 Классы и объекты

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

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

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

    А вот каждый конкретный человек со своими значениями ФИО будет экземпляром класса человек. Точно так же как каждый ящик со своими значениями высоты, ширины и глубины будет являться экземпляром класса ящик. Само собой у каждого класса может быть масса других параметров — например и у человека и у ящика может быть параметр масса, у человека может быть параметр пол — мужской или женский, а вот у ящика пол вряд ли будет (хотя кто знает, что нам готовит непредсказуемое будущее)

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

    В профессиональном программировании считается дурным тоном давать свободный и бесконтрольный доступ к хранимым в классе данным. Чтобы запретить доступ извне к свойству Surname для него надо прописать другой модификатор доступа, вместо public — private. Записывать и считывать данные надо будет через специальные функции, аналогичные тем функциям, которые на самом деле что-то вычисляют в духе GetFio. Чтобы не возиться с написанием кучи функций типа GetName и SetName в C# применяется специальный механизм свойств, на основании которых уже при компиляции программы автоматически генерятся эти однотипные функции. Такой способ облегчить жизнь программисту называется синтаксическим сахаром. В Visual Studio есть даже специальная функция для этого.

    Читать еще:  Программирование на powershell

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

    Обратите внимание, насколько проще стал код, в котором создаются и выводятся на экран люди.

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

    2.3 Структура программ реального мира. Пространства имен.

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

    Для нашей тестовой программы мы используем пространство имен TestConsoleApplication, состоящее из двух классов — Program и Person.

    Класс Program автоматически создается для каждого Net приложения, это стандартный класс. Как правило он состоит из одной функции/метода static void Main(string[] args), которая выполняется при запуске приложения.

    Разработчики C# и .Net очень любят классы. Просто очень-очень. Так что в итоге здесь все является классами и даже функции без классов не существуют. Если вам не нужны ни классы ни экземпляры, и вы хотите просто сделать нескольких функций — вам все равно придется создать класс, в который добавить несколько статических (не требующих создания экземпляра) функций.

    Классическим пример такой функции может послужить умножение

    Которое где-то в другом месте вызывается как

    Но на самом деле в .Net уже есть такой класс со сборником арифметических функций Math — в который входят функции для вычисления всевозможных синусов, тангенсов, квадратных корней, округления чисел.

    Другой пример класса который по сути своей является библиотекой функций — класс Convert, содержащий функции для преобразования одних типов данных в другие

    В .Net Framework входит множество уже готовых классов от программистов Microsoft, разделенных на множество пространств имен. Самые-самые базовые входят в пространство имен System.

    Теперь можно полностью обьяснить использовавшийся в этой и предыдущей статьях код

    В данном случае мы вызываем функцию public static void WriteLine(string value) из класса Console входящего в пространство имен System. И уже где-то там внутри нее, скорее всего еще несколькими уровнями ниже выполняется рисование по пикселям окна с консолью и наших букв.

    Чтобы не писать каждый раз пространство имен используется директива using

    и на самом деле если мы уже прописали

    то вывод текста в консоль можно было бы записать проще (помешали лень и копирование в буфер)

    В C# классами и обьектами является все, в том числе строки. Каждая строка — это на самом деле экземпляр класса String. Теперь можно понять и следующий код:

    Здес мы вызываем один из методов класса String — public string Substring(int startIndex, int length), который возвращает кусок строки и принимает два аргумента, индекс символа, с которого надо начать вырезание подстроки (нумерация начинается с 0) и длину вырезаемой подстроки.

    Если же нам не нужны методы вообще, просто хочется собрать в кучку данные — можно использовать структуры. С другой стороны можно создать специальный класс без функций, с одними данными — для этого есть умное название обьект для передачи данных (Data Transfer Object, DTO).

    2.4 Особенности хранения данных в памяти. Ссылочные и простые типы данных. Область видимости переменных.

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

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

    В C# дела обстоят иначе. Для самых простых типов данных память компьютера выделяется автоматически, написав int counter; мы автоматически получим место в памяти, в которое будет по умолчанию записан 0.

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

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

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

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

    А вот так все будет в порядке.

    Другой вариант первой ошибки

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

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

    Наглядный пример более сложной задачи, при решении о которой необходимо помнить об особенностях работы сборщика мусора — использование Word для вывода данных в отчеты . В этом случае мы используем ресурс, неподвластный сборщику мусора — программу Word, запускаемую и управляемую из нашего кода. Если она становится ненужна, то ее надо закрывать вручную из кода — иначе на компьютере начнут плодится невидимые Word’ы в неограниченных количествах.

    2.5 Массивы, коллекции и цикл foreach

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

    В чем же отличие массивов от списков? Подробности относятся к продвинутым знаниям, но в целом под массив место в памяти выделяется сразу и если надо изменить его размер, то место приходится выделять заново. Под список фиксированный объем не выделяется, он меняется динамически, но операции над элементами выполняются медленнее. Таким образом массив быстрее и лучше работает, если количество элементов не меняется, список — если меняется. Но в большинстве случаев эта разница в скорости не заметна на фоне других факторов. Продвинутые программисты хорошо понимают разницу между ArrayList, Dictionary, HashSet, LinkedList, Collection и другими типами коллекций.

    Обходить все элементы в каком-то множестве приходится так часто, что в большинстве современных языков для этого сделали особый цикл, в C# это цикл foreach, «для каждого».

    Выйти из цикла можно с помощью ключевых слов break — просто прекращается выполнение цикла и continue — пропускает текущую итерацию и переходит к следующей

    Ссылка на основную публикацию
    ВсеИнструменты 220 Вольт
    Adblock
    detector
    ×
    ×