Смекни!
smekni.com

Основы программирования на языке Си (стр. 8 из 27)

именно этипеременныеучаствуютвпоследующихвычисленияхвнутрифункции.

3.1 Передача параметров по значению

Функции, принимающиепараметрыпо значению, "безопасны" втомсмысле,

что онинемогутслучайноизменитьпеременныевызывающейфункции (т.е. уфунк-

ций нетскрытыхпобочных эффектов). Большинствофункцийпроектируютсяименно

таким образом.

Программа 3.1 поясняет, почемуважногарантировать "сохранность" перемен-

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

корень изчисла, введенногопользователем:

Введите положительное число:

4

Факториал 4! равен 24, а квадратный корень из 4 равен 2.

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

"sqrt(...)". Библиотечнойфункциидлявычисленияфакториаланет, поэтомупри-

дется написатьсобственнуюфункцию (вычисляющуюдлялюбогоположительного

целого числаn значение n!=(1*2*3*...*n)).

#include<iostream.h>

#include<math.h>

int factorial(int number);

// ГЛАВНАЯ ФУНКЦИЯ:

int main()

{

int whole_number;

cout << "Введите положительное число:&bsol;n";

cin >> whole_number;

cout << "Факториал " << whole_number << "! равен ";

cout << factorial(whole_number);

cout << ", а квадратный корень из " << whole_number;

cout << " равен " << sqrt(whole_number) << ".&bsol;n";

return 0;

}

// КОНЕЦ ГЛАВНОЙ ФУНКЦИИ

// ФУНКЦИЯ ДЛЯ ВЫЧИСЛЕНИЯ ФАКТОРИАЛА:

int factorial(int number)

{

int product = 1;

for ( ; number > 0 ; number--)

product *= number;

34

return product;

}

// КОНЕЦ ФУНКЦИИ

Программа 3.1.

Если быфункция "factorial(...)" изменялапеременнуювызывающей

функции, топрограмма 3.1 выдавалабыследующийответ (формальноправильный,

но посмыслузадачинекорректный):

Введите положительное число:

4

Факториал 4! равен 24, а квадратный корень из 0 равен 0.

3.2 Передача параметров по ссылке

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

данного ейпараметра. Рассмотримпрограмму 2.1. С 10-йпо 14-юстрокувнейвы-

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

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

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

теля создадимфункцию "get_dimensions". Вданномслучаенеобходимо, чтобыэта

функция изменялазначенияпеременных "this_length" и "this_width" (переданныхей

в качествепараметров) –помещалавнихзначения, введенныепользователемскла-

виатуры. Изменениепараметровфункциивозможноприпередачепараметровпо

ссылке. Утакихпараметроввзаголовкефункциипослеименитипауказываетсясим-

вол "&".

#include<iostream.h>

int area( int length, int width );

void get_dimensions( int& length, int& width );

// ГЛАВНАЯ ФУНКЦИЯ:

int main()

{

int this_length, this_width;

get_dimensions( this_length, this_width );

cout << "Площадь прямоугольника с размерами ";

cout << this_length << "x" << this_width;

cout << " равна " << area( this_length, this_width ) << "&bsol;n";

return 0;

}

// КОНЕЦ ГЛАВНОЙ ФУНКЦИИ

// ФУНКЦИЯ ВВОДА РАЗМЕРОВ ПРЯМОУГОЛЬНИКА:

void get_dimensions( int& length, int& width )

{

cout << "Введите длину: ";

cin >> length;

cout << "Введите ширину: ";

cin >> width;

cout << "&bsol;n";

35

}

// КОНЕЦ ФУНКЦИИ

// ФУНКЦИЯ ВЫЧИСЛЕНИЯ ПЛОЩАДИ:

int area( int length, int width )

{

return length*width;

}

// КОНЕЦ ФУНКЦИИ

Программа 3.2.

Функция _______"get_dimensions" изменяетзначенияпараметров "this_length" и

"this_width", ноневозвращаетникакогозначения (т.е. неявляется "функцией" вма-

тематическом смысле). Этотфактотражаетсяивпрототипе, ивопределениифунк-

ции –вкачествевозвращаемогозначенияуказантип "void" ("пустой" тип).

4. Полиморфизм и перегрузка функций

Одним изхарактерныхсвойствобъектно-ориентированногоязыка, втомчисле

и Си++, являетсяполиморфизм –использованиеодногоименидлявыполненияраз-

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

вается перегрузкой. ДляосновныхоперацийСи++ перегрузкаужевстроенавязык:

например, усложениясуществуеттолькоодноимя, "+", ноегоможноприменятьдля

сложения какцелых, такивещественныхзначений. Этаидеярасширяетсянаобра-

ботку операций, определенныхпользователем, т.е., функций.

Перегруженные функцииимеютодинаковыеимена, норазныеспискипарамет-

ров ивозвращаемыезначения (см. программу 4.1).

#include<iostream.h>

int average( int first_number, int second_number,

int third_number );

int average( int first_number, int second_number );

// ГЛАВНАЯ ФУНКЦИЯ:

int main()

{

int number_A = 5, number_B = 3, number_C = 10;

cout << "Целочисленное среднее чисел " << number_A << " и ";

cout << number_B << " равно ";

cout << average(number_A, number_B) << ".&bsol;n&bsol;n";

cout << "Целочисленное среднее чисел " << number_A << ", ";

cout << number_B << " и " << number_C << " равно ";

cout << average(number_A, number_B, number_C) << ".&bsol;n";

return 0;

}

// КОНЕЦ ГЛАВНОЙ ФУНКЦИИ

// ФУНКЦИЯ ДЛЯ ВЫЧИСЛЕНИЯ ЦЕЛОЧИСЛЕННОГО СРЕДНЕГО

// ЗНАЧЕНИЯ 3-Х ЦЕЛЫХ ЧИСЕЛ:

int average( int first_number, int second_number,

int third_number )

36

{

return ((first_number + second_number + third_number)/3);

}

// КОНЕЦ ФУНКЦИИ

// ФУНКЦИЯ ДЛЯ ВЫЧИСЛЕНИЯ ЦЕЛОЧИСЛЕННОГО СРЕДНЕГО

// ЗНАЧЕНИЯ 2-Х ЦЕЛЫХ ЧИСЕЛ:

int average( int first_number, int second_number )

{

return ((first_number + second_number)/2);

}

// КОНЕЦ ФУНКЦИИ

Программа 4.1.

Программа 4.1. выводитнаэкрансообщения:

Целочисленное среднее чисел 5 и 3 равно 4.

Целочисленное среднее чисел 5, 3 и 10 равно 6.

5. Процедурная абстракция и "хороший" стиль программирования

Функции помогаютприменятьдляразработкипрограммструктурныйметод

проектирования "сверху вниз". Приэтомрешаемаязадачаделитсянаподзадачи (иза-

тем напод-подзадачиит.д.). Длярешениякаждойподзадачипрограммистреализует

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

функций.

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

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

возможных возвращаемыхзначений.

Опытные программистынаначальныхэтапахразработкичастоприменяют

пустые функции (заглушки), которыесодержаттолькооператорвозвратазначениясо-

ответствующего типа. Этифункцийоблегчаютотладкуглавнойфункцииилипросто

функции болеевысокогоуровня.

Выделение врешаемойзадачефункций методом "сверхувниз" частоназывает-

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

друг отдругафункцийширокоприменяетсяпередачапараметровпозначениюило-

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

сматривать подобныефункциикак "черныеящики". Дляихиспользованиязнатьде-

тали реализациинеобязательно.

6. Модульное программирование

Помимо метода "сверхувниз", вторымважнымметодомструктурногопроек-

тирования являетсяметодмодульногопрограммирования. Онпредполагаетразделе-

ние текстапрограммынанесколькофайлов, вкаждомизкоторыхсосредоточеныне-

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

В программахнаСи++ частоприменяютсябиблиотечныефункции (например,

"sqrt(...)"). Дляиспользованиябольшинства функций, втомчислеибиблиотечных,

необходимы двафайла (вскобкахпримерыданыдля "sqrt(...)"):

Заголовочный файл ("math.h") спрототипомфункции ("sqrt(...)" имногих

других математическихфункций). Поэтомувпрограммах, вызывающих

37

"sqrt(...)", естьстрока "#include <math.h>", анеявноеобъявлениеэтой

функции.

Файл реализации (дляпользовательскихфункцийэтофайлысисходным

текстом наСи++, абиблиотечныефункцииобычнохранятсявскомпилиро-

ванном видевспециальныхбиблиотечных файлах, например,

"libcmtd.lib"). Файлыреализациипользовательскихфункций (обычнос

расширением ".cpp") содержатопределенияэтихфункций.

Разделение исходноготекстаназаголовочныефайлыифайлыреализациипо-

казано впрограмме 6.1, котораявыполняеттежедействия, чтоипрограмма 4.1. Те-

перь программасостоитизтрехфайлов: главногофайла, заголовочногофайласопи-

саниями двухфункцийрасчетасреднегозначения, исоответствующегофайлареали-

зации.

В главномфайлесодержитсяследующийтекст:

#include <iostream.h>

#include "averages.h"

int main()

{

int number_A = 5, number_B = 3, number_C = 10;

cout << "Целочисленное среднее чисел " << number_A << " и ";

cout << number_B << " равно ";

cout << average(number_A, number_B) << ".&bsol;n&bsol;n";

cout << "Целочисленное среднее чисел " << number_A << ", ";

cout << number_B << " и " << number_C << " равно ";

cout << average(number_A, number_B, number_C) << ".&bsol;n";

return 0;

}

Главный файл программы 6.1.

Обратите внимание, чтоимяфайластандартнойбиблиотеки "iostream.h" вди-

рективе препроцессора "include" заключеновугловыескобки ("<>"). Файлысимена-

ми вугловыхскобкахпрепроцессорищетвбиблиотечныхкаталогах, указанныхвна-

стройках компилятора. Именапользовательскихзаголовочныхфайловобычноза-

ключаются вдвойныекавычки, ипрепроцессорищетихвтекущемкаталогепро-

граммы.

Далее приведеносодержимоефайла "averages.h". Внем естьидентификатор

препроцессора "AVERAGES_H" ислужебныесловапрепроцессора "ifndef" ("еслинеоп-

ределено"), "define" ("определить") и "endif" ("конецдирективыif"). Идентифика-

тор "AVERAGES_H" являетсяглобальным символическимименемзаголовочногофайла.

Первые двестрокифайласлужатзащитойотповторнойобработкитекстазаголовоч-

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

"#include "averages.h"" встречаетсянесколькораз.

В заголовочныхфайлах, кромепрототиповфункций, часторазмещаютсяопи-

сания глобальных константипользовательскихтипов. Подробнееобэтомговоритсяв