Рассылка закрыта
При закрытии подписчики были переданы в рассылку "Как создать свой сайт и заработать?" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
Программирование с нуля - это совсем просто! 37) Подпрограммы
Информационный Канал Subscribe.Ru |
Программирование с нуля - это совсем просто!37) ПодпрограммыТакие последовательности команд, выполняющиеся по вызову :) и имеющие отношение к определенному объекту приложения (например, форме) называют в объектном программировании методы (см. 33 занятие). Однако явно выделенные наборы команд, объединенные общей идеей, могут быть привязаны к объекту, а могут быть и непривязаны к нему. Например, функция Sin() - это такой же выделенный набор команд, рассчитывающий синус параметра. Он не имеет отношения ни к каким объектам (хотя для удобства может быть включен например в одну из стандартных библиотек). Для таких самостоятельных наборов команд существует старое название подпрограмма. В Бейсике она и по сей день обозначается ключевым словом Sub (сокращение от Subroutine, подпрограмма). Подпрограмма позволяет создавать именованные (это важно! для вычисления синуса используется имя Sin, а для косинуса - Cos, и обращение происходит по имени подпрограммы, как и с переменными) последовательности команд, которые можно вызывать из других мест программы независимо друг от друга, обращаясь к названию такой последовательности. Уже упоминавшиеся методы объектов - фактически такие же последовательности команд, вызываемые при обращении к названиям этих методов. В общем случае, между методами и подпрограммами нет особой разницы, просто методы привязаны к понятию объекта, а подпрограммы в классическом понимании более независимы. Sin - подпрограмма, а метод обработки нажатия на клавишу имеет смысл только в рамках конкретной формы (объекта) с конкретной кнопкой. Одна принципиальная причина, по которой были придуманы подпрограммы - это возможность повторного использования кода. Чтобы каждый раз не писать вычисление синуса :) Сами подпрограммы (как и методы) обычно делятся в свою очередь на две группы. В Паскале это деление явное, в Си его нет вообще. Подпрограмма может быть процедурой, а может быть функцией. Все их отличие в том, что процедура - это набор команд, выполняемый при обращении к имени этой процедуры, и все :) , а функция - такой же набор команд, который дополнительно вычисляет некоторое значение и, как говорят, возвращает его вызвавшей его программе (которая, в свою очередь, тоже может быть подпрограммой). То есть Sin() - это функция, так как она возвращает значение синуса, а например обработчик нажатия на кнопку - процедура, так как просто выполняется набор команд, и ничего обратно и никуда не возвращается. Для этого в Паскале есть разные ключевые слова, procedure и function. В Бейсике соответственно Sub и Function. А вот в Си все подпрограммы считаются функциями. Процедур там нету. А если подпрограмма ничего не рассчитывает, то даже специальный тип данных придуман, void называется, "пустой" тип - вроде есть данное типа void, а на самом деле его нету. Рассмотрим создание подпрограммы на примере броска кости. Допустим, мы хотим создать функцию, которая будет имитировать бросание шестигранного кубика, и возвращать значение, лежащее в диапазоне от одного до шести. Поэтому тип возвращаемого ей значения очевидно будет целыми числом и определится словом Integer. Назовем эту функцию Dice6. Где нам начать ввод этой функции в исходном тексте? Компиляторы устроены так (хотя и не все), что не понимают обращения к некоторой подпрограмме, если она не была описана ранее. То есть если сначала к ней обратиться, а потом только опишем, то будет ошибка. Но это только в случае, если мы делаем автономную подпрограмму, ни к каким объектам не привязанную. Если же мы сразу опишем метод объекта, то он поймется и поймается в любом месте независимо от места описания. Однако пока мы до объектов не добрались, поэтому просто запомним такое правило - описывать подпрограмму как можно раньше. В текущем модуле, где мы сделали показ случайного значения от 1 до 6, вернитесь повыше и найдите строчки implementation {$R *.dfm} ЭТо начало раздела, где присутствуют описания всех подпрограмм. Скорее всего, далее там будет наш обработчик нажатия на кнопку:
procedure TForm1.Button1Click(Sender: TObject);
Перед ним, после команды {$R *.dfm} (это такое хитрое включение описания формы из дизайнера, что где на ней расположено), и начнем ввод описания функции Dice6. Оно будет начинаться с ключевого слова Function, за которым необходимо указать ее имя (как в случае с именем переменной), а затем уже знакомая нам пара "логических" скобок begin / end:
function Dice6
end;
Вся группа команд , входящая в состав некоторой подпрограммы между begin/end, называется телом :) подпрограммы . Далее, нам надо указать, значение какого типа наша функция возвращает. Это, очевидно, тип Integer (целые), поэтому следом за именем функции после двоеточия надо записать этот тип и поставить точку с запятой. ВОт такой в Паскале синтаксис. Правила записи различных конструкций языка программирования называются синтаксисом языка.
function Dice6: Integer;
end;
Перед словом begin можно вставить раздел, где объявляются переменные - все они будут локальными, как уже говорилось, то есть к ним обращаться можно лишь в пределах данной функции.
function Dice6: Integer;
end;
Никакие параметры для этой функции не нужны. Ведь мы заранее знаем что у нашего кубика шесть граней , а никаких других дополнительных данных нам не потребуется. Случайные значения мы уже умеем рассчитывать. Все, что нам надо - это выражение random(6)+1 . Только что с ним делать, ведь нам требуется подсказать компилятору, что данное выражение будет представлять собой значение, которое наша функция Dice6 должна возвращать после своего вызова. Для этого мы воспользуемся обычным оператором присваивания, в правой части которого укажем созданное нами выражение, а в левой - название некоторой условной переменной Result (описывать ее не надо):
function Dice6: Integer;
В данном случае эта запись выглядит как оператор присваивания, хотя на самом деле это просто синтаксис записи команды на запоминание возвращаемого функцией значения. Так принято :) Такая форма записи достаточно наглядна. Она не означает, что слово Result можно также применять в других ситуациях в качестве названия переменной - например в правой части операторов присваивания. Это не более чем правило записи и синтаксиса любой функции Теперь мы можем использовать функцию Dice6 точно так же, как и все остальные функции типа Sin.
procedure TForm1.Button1Click(Sender: TObject);
Дополняем функцию параметром Виртуальный шестигранный кубик будет полезен в разных приложениях, но во многих случаях было бы удобно иметь более универсальный кубик, количество граней которого мы могли бы создавать самостоятельно - например, в качестве параметра соответствующей функции. Сделать это не сложно. Создадим новую функцию и назовем ее Dice. Это название отличается от предыдущего Dice6 (по смыслу :) тем , что не привязано к конкретному числу граней . Впрочем , за выбор названий целиком отвечает программист , поэтому при желании вы всегда можете изменить Dice на более вам симпатичное . Теперь добавим функции Dice параметр, характеризующий количество граней нашего кубика. Он будет иметь тип Integer - целое число. Чтобы указать, что у фунции есть параметр (как у Sin есть параметр, значение угла, синус которого надо вычислить), сразу за ее именем в круглых скобках надо, как при описании переменной, задать название этого параметра (произвольный ранее не описанный идентификатор; назовем его для примера Sides), и через двоеточие - тип этого параметра: Function Dice (Sides: Integer): Integer; Название параметра - вещь условная, считайте, что это просто локальная переменная в пределах описания подпрограммы. Название параметра своим именем надо только для того, чтобы как-то к нему обращаться в теле функции. В теле Dice вместо конкретного значения 6 (число граней) мы поставим обращение к этому параметру:
function Dice(Sides: Integer): Integer;
Нетрудно убедится, что работает эта функция нормально. Ее текст во многом схож с текстом функции Dice6. Но так как у нас теперь есть реализация универсального кубика, можно переделать функцию Dice6, основываясь на новых возможностях:
function Dice6: Integer;
Здесь мы даже не используем повторно старый код , а просто обращаемся к универсальной функции с соответствующим параметром. Только расположить это описание надо после описания Dice, иначе обращение к Dice из Dice6 не будет найдено (ранее его компилятор не встретил). А если параметр, переданный в данную функцию, будет ошибочным? Например, программист случайно в качестве количества граней укажет значение 0 или отрицательное число. Чтобы избежать подобных источников потенциальных ошибок, воспользуемся классическим приемом защиты от дурака - предварительно проверим, больше ли нуля значение, передаваемое через параметр Sides. Если оно меньше или равно единице (одной грани), то будем считать, что функция возвращает нулевое значение. Во всех остальных случаях функция будет рассчитывать корректное значение, лежащее в диапазоне от единицы до заданного количества граней. Такую проверку реализуем с помощью условного оператора:
function Dice(Sides: Integer): Integer;
if Sides >= 1 then
else
end;
У подпрограммы может быть несколько параметров (конечно, не обязательно одного типа), тогда они перечисляются через точку с запятой: function XXX( a: Integer; b: Real; c: String ): Integer; А вызов ее будет например таким:
XXX( 10, 3.14, ' строка-параметр ' );
Процедура записывается также, только не надо указывать возвращаемый тип в заголовке:
procedure XXX( a: Integer; b: Real; c: String ); Соответственно, и не требуется использовать запись Result := ... так как возвращаемое значение в процедуре не формируется. Задание. Расширьте функцию Dice, добавив еще один параметр нижней грани. То есть чтобы случайное рассчитывалось не от 1 до N, а от M до N. При этом надо проверить, больше ли N чем M. На форме сделайте два поля ввода, одно для нижней грани, другое для верхней. А по нажатии на кнопку бросайте кубик не один, а тысячу раз (в цикле), и покажите суммарное и среднее значение выпадавших величин. В Бейсике запись такая:
function Dice6 As Integer
Начинается и заканчивается тело функции с Function и End Function. В заголовке после ключевого слова As (в Паскале вместо As было двоеточие) пишется тип возвращаемого значения. Только вместо условной переменной Result для фиксации возвращаемой величины в левой части оператора присваивания указывается имя самой функции Dice6, синтаксис такой :) Параметры, если есть, указываются с предварительным словом ByVal (что это такое, потом рассмотрим):
function Dice(ByVal Sides As Integer) As Integer
Обращаться к ней так же: MyLabel.Text = Str( Dice(6) ) А если нужна процедура, то воспользуемся ключевыми словами Sub / End Sub :
Sub MoeProceDure()
end Sub
В Си++ запись схожая, хотя тоже своеобразная. Сначала ставится тип возвращаемого функцией значения (в Си все подпрограммы считаются функциями; если хотите процедуру сделать, просто в качестве такого типа укажите void), затем имя функции, затем круглые скобки со списком параметров (обязательны всегда, даже если список пустой), а далее - пара фигурных скобок, внутри которых - ее тело :)
int dice6()
}
Для возврата вычисленного значения применяется такая запись: return возвращаемое-значение ; Например: return x ; Важно! В отличие от вариантов Паскаля и Бейсика, когда мы заносили возвращаемое значение в условную переменную Result (или переменную, совпадающую в Бейсике с именем функции), после чего работа функции продолжалась, в Си оператор return немедленно прекращает выполнение функции. То есть в Паскале можно было так написать:
...
и значение 5 естественным образом было бы использовано как возвращаемое, а потом печаталась бы строка итд, то в Си в ходе выполнения команд
...
оператор return сразу прервет текущую функцию, и до вывода строки очередь уже не дойдет. Нужная нам функция тогда так запишется:
int dice6()
В круглые скобки, результат я для наглядности просто взял :) Переменные можно свои объявить внутри фигурных скобок:
int dice6()
Параметры указываются так же, как и переменные - тип, идентификатор-имя, если несколько, то через запятую.
int dice(int sides)
В Си++ переменные вообще можно где угодно объявлять, однако это хоть и гибко, но не очень наглядно. Область действия таких локальных переменных ограничена ближайшими скобками фигурными, то есть можно так записать:
if( sides >= 1 )
При этом переменные n будут разные, хотя и называются одинаково. Но к ним можно обращаться лишь в пределах ближайшей пары { } , поэтому вот так записать нельзя:
int dice(int sides)
return n;
Обе переменные n определены в пределах своих пар скобок, а оператор return, обращающийся к n, уже вне их находится. Вот так лучше всего во всех отношениях (группируем описания всех переменных в начале логического блока и не множим их внутри локальных пар { } !!! ) :
int dice(int sides)
if( sides >= 1 )
return n;
Теперь и описание n, и return n находятся на одном уровне скобок . Теперь возможно будет понятна структура - шаблон консольной программы:
int main(int argc, char* argv[]) Это код, который генерируется автоматически средой разработки. Видно, что это функция main - она просто считается главной в консольной программе и запускается на выполнение автоматически. А ее параметры - это на самом деле список параметров консольной программы (аргументы), мы потом их изучим. Возвращает эта главная функция значение 0 (на системном уровне он трактуется как код возврата программы, 0 - значит работа завершена успешно). Несколько новых компонентов. КОмпонент Shape (панель Additional) позволяет на форме создавать разноцветные круги, квадраты, эллипсы. Конкретная форма задается свойством Shape, который может принимать значения, из списка stRectangle, stSquare, stRoundRect, stRoundSquare, stEllipse, stCircle. То есть форму такого расположенного на форме объекта можно менять динамически, по нажатию на кнопку:
procedure TForm1.Button1Click(Sender: TObject);
И цвет соответственно, свойство Color, только оно в данном компоненте хитрое, само вложено в свойство Brush (кисть), поэтому к нему по цепочке надо обращаться: Shape1.Brush.Color := clRed; Зато у кисти есть еще одно подсвойство Style, которое определяет способ "заливки" внутренности объекта - сплошное bsSolid, в решеточку bsCross итд. Вы всегда можете конкретные значения некоторого свойства посмотреть в инспекторе объектов, в выпадающем списке. Shape1.Brush.Style := bsCross; Немного схожий с ним компонент Bevel, рядышком справа от Shape, выпуклые/впуклые :) панели, рамки и линии позволяет создавать. Его главные свойства - Shape и Style. А в разделе Standard есть компонент Panel для создания панелей декоративных, на которых удобно группировать элементы управления, выделяя их визуально. Панель оформляется с помощью свойств, связанных с внешним видом ее каемки - BorderStyle, BorderWidth, BevelWidth, BevelInner, BevelOuter. Кроме того, можно использовать кнопки с картинками - с панели Additional взять самые первые BitBtn или SpeedButton, они как обычные кнопки работают, только через свойство Glyph можно задать картинку, которая будет показываться на самой кнопке. (сочинение 7-летнего Тараса по теме "Кем я хочу стать когда я буду большим") Я хочу стать программистом, когда выросту большим, потому что это классная работа и простая. Поэтому в наше время столько программистов и все время становится больше. Программистам не нужно ходить в школу, им нужно учиться читать на компьютерном языке, что бы они могли с компьютером разговаривать. Думаю, что они должны уметь читать тоже, что бы знать в чем дело, когда все напереполох. Программисты должны быть смелыми, что бы не пугаться, когда все перепуталось так что никто не разберет, или если придется разговаривать на английском языке по-иностранному, что бы знать, что надо делать. У программистов должно быть хорошее зрение, что бы видеть сквозь одежду и что бы не бояться секретарш, потому что с ними приходиться работать. Еще мне нравитса зарплата, которую программисты получают. Они получают столько денег, что не успевают их все тратить. Это происходит потому, что все считают работу программиста трудной, кроме программистов, которые знают, как это просто. Нет ничего такого, что бы мне не понравилось, кроме того что девочкам нравятся программисты и все хотят выйти за них замуж, и поэтому женщин надо гнать, что бы не мешали работать. Надеюсь, что у меня нет аллергии на офисную пыль, потому что на нашу собаку у меня аллергия. Eсли у меня будет аллергия на офисную пыль, программиста из меня не получится и придется искать настоящую работу. Компьютерный юмор http://jorj.brest.by/ (c) 2004 Сергей Бобровский bobrovsky@russianenterprisesolutions.com
Школа программирования с нуля
Все предыдущие выпуски базового курса тут:
|
http://subscribe.ru/
http://subscribe.ru/feedback/ |
Подписан адрес: Код этой рассылки: comp.soft.prog.prognull |
Отписаться |
В избранное | ||