Г. Шилдт - Полный справочник по C++ (1109478), страница 29
Текст из файла (страница 29)
Глава 6. Функции Мьпс1ийе <вттьпО.Ь> Этпс1ийе <втй1о.Ь> иоьй рг геиегве(сиах *в)> хпт ва?п(иозй) ( рг геиетве("Я люблю С++"): тетихп 0; ) иоьй рт теиетве(сиах *в) гад?веет ьпт т; ?от(т=втг1еп(в)-1? т>=0: т--) ритсьат(в[с)) Как только строка появляется на экране, функции рх х.е гехве [) ничего не остается делать, и она возвращает управление в точку, откуда была вызвана. На самом деле этот способ используется довольно редко, поскольку, во-первых, это снижает наглялносп и эффективность функции, а во-вторых, в большинстве случаев она должна вернуть некий результат. Функция может солержать несколько операторов гееигп. Например, функция я?пй виЬвет() в следующей программе возвращает начальную позицию подстроки, входящей в заданную строку, а если подстрока не найдена, возвращает числа -1.
Мьпс1ийе <втй1о. Ь> ?пт Гьпй виЬвтт(сбат *в1, сЬат *в2) тпе ва?п(ио?й) ( 1?(тзпй виЬвтт("0++ прекрасен", "красен" ) !=- -1) ргзптг("подстрока не найдена"); гетигп 0; ) /* Возвращает индекс первого символа подстроки в2, входящей в строку в1. */ ?пт хьпй виЬвсг(сиат *в1, сьат *в2) ( тедьвеет ?пт с; сЬат *р, *р2; Гог(т=аг в1[т1; те+) ( р = ав1[т)[ р2 = в2; иЬ11е("р2 аа *р2==*Р! ( р++; р2++; ) ?г(("р2) хетага ег /* Первый оператор гетитп */ 1 гетигп -1; /* Второй оператор тетитп */ ) Часть 1.
Основы языка С++: подынажес[во С Возвращаемые значения Все функции, за исключением функции, объявленных со спсцифякатором чеье(, с помощью оператора хеецха возвра(лают некий результат. В соответствии со сзандартом С89, если Функция, возвращающая значение, не использует для этого оператор хеецха, в вызывающий модуль возвращается "мусор", т.е. случайное значение. В языке С++ (и в стандарте С99) всс функции, возвращающие значение, долзкпы делать это с помощью оператора хесиха.
Иными словами, если в объявлении указано, что Функция возвращает некое значение, любои оператор хееихп, расположенный в ее теле, должен быть связан с определенной переменной. Однако, если по~ок управления достигнет конца функции, возвращающей значение, не встретив на своем пути оператор хаеиха, в вызывакнций модуль также вернется "мусор". Несмотря на то что эта ошибка не относится к разряду синтаксических, она является принципиальным изъяном программы и должна быть исключена. Если функция нс объявлена со спецификатором чоы, сс можно использовать в качестве операнда в любом выражении. Таким образом, фрагмент программы, приведенный ниже, является совершенно правильным.
| х = ромах(у); 11(пах(х,у) > 100) ргъпСГ( больше")р Гол(с)з=дегспах О; 1ес(101С(сл); ) Как правило, функция не должна стоять в левой части оператора присваивания. Следовательно, оператор а яшар(х,у) = 100; /* Неправильный оператор */ является ошибочным.
Компилятор языка С/С+ ь распознает эту ошибку и вьиаст соответствующее сообщение. (Как указывается в части 2, язык С++ допускает несколько интересных исключений из этого правила, что позволяет указывать некоторые функции в левой части оператора присваивания.) Функции можно разделить на три категории. К первой ка~е~ории опюсятся вычислительные функции. Они выполняют некие операции над своими аргументами и возвращают результат вычислении. Их можно назвать "настоящими'* функциями. К примеру, "настоящими" являются стандартныс библиотечные функции ацхе() и а1аО, вычисляющие квадратный корень и синус соответственно. Функции второго типа выполняют обработку информации.
Их возвращаемое значение просто означает, успешно ли завершены операции. В качестве примера можно указать библиотечную функцию яс1оваО, закрывающую фаил. если файл закрыт успешно, функция возвращает значение О, в противном случае она возвращает консганту вж. И, наконец, Функции третьего вида не имеют явно возвращаемого значения. По с)ществу, эти функции являются процедурами и не вычисляют никакого результата.
К этой категории относится Функция ехьс(), прекращающая выполнение программы. Все функции, нс возвращающие никаких значений, следует объявлять с помощью спецификатора уо1а. Такие функции нельзя использовать в выражениях Иногда функции, не вычисляющие ничего интересного, все равно что-то возврашают. Например, функция рхдпеЕ() возвращает количество символов, выведенных на экран.
Было бы интересно увидеть программу, в которой это значение имело какой-то смысл. Иными словами, хотя все функции, за исключением функций, объявленных с помощью спсцификатора моьа, возвращают какие-то значения, использовать их в дальнейших вычислениях совершенно не обязательно. При обсуждении функций часто возникает вопрос: "Обязательно ли присваивать значение, возвращаемое функцией, какой-то переменной, объявленной в вызывающем модуле?".
Нет, не обязательно. Если оператор присваивания не указан, возвращаемое значение просто игнорируется. Рассмотрим программу, в которой используется функция ша1() . Глава б. Функции ((ъпс1ибе <зе()то. Ь> 1пе гти1(ъле а, зве )з) 1пс ваьл(чоЫ) ъпе х„у, а; х=10;у=-20; = мт1(х, у); /* 1 т/ ртъ СГ( Ъа", 1(х.У))' /* 2 '/ щс1(х, у); /* 3 '/ ъпе лм1(ьпе а, ЫС )з) хеестп а*)з) В первой строке значение, возврашаемое функцией ме1(), присваивается переменной х Во второй строке возврашаемос значение ничему не присваивается, но используется внутри функции рхвпся().
И, наконец, в третьей строке значение, возврашаемое с помошью оператора хеситп, отбрасывается, поскольку оно ничему не присваивается и не является частью какого-либо выражения. Возврат указателей Несмотря на то что функции, возвращающие указатели, ничем нс отличаются от обычных, с ними связано несколько важных понятий. Указатели не являются целочисленными переменными. Они содержат адреса переменных, имеющих определенный тип. Используя адресную арифметику, следует иметь в зилу, что результаты ее операций зависят от базового типа указателей.
Например, при увеличении целочисленного указателя на единицу его значение увеличится на 4 (если целые числа занимают 4 байт памяти). Как правило, при каждом увеличении (или уменьшении) указа~ела на единицу, он перемешается на следуюшую (или предьшушую) переменную этого типа. Поскольку размер переменных, имеюших разные типы, варьируется, компилятор лолжен знать, с каким типом данных связан тот или инои указатель. По этой причине функция, возврашаюшая указатель, должна явно объявлять сто тип, Например, нельзя применять оператор тееохп для возврата указателя, имсюшего тип )згс *, если в объявлении функции указано.
что она возврашает указатель типа с)тах *! Чтобы вернуть указатель, в объявлении функции следует указать соответствуюц(ий тип возврашасмого значения. Например, следуюшая функция возвращает указатель па первое вхожление символа с в строку я, /* Возврацает указатель на первое вхождение символа с в строку з.
*/ слет *теесл(сЬах с, слет *з) иЫ.1е(с!=*з ьа *з) з*т; хеесгп(з); ) Если символ не найден, возвращается нуль. Рассмотрим короткую программу, в которой используется функция месс)з(). Часть ). Основы языка С++„подмножество С Вьпс1ийе <втйьо.)г> спал *гласе)г(с)гат с, с)гат *в); /* Прототип */ 1пг. иа1п(чо1й) с)гат в(80), *р, скн деев(в)г с)г = десс)гат(); р = инес)г(с)г, в) 11(*р) /* Есть вхожление "/ рт1птт("%в '.
р); е1ве ртьптт("Символ не обнаружен.") тегптп Ог ) Эта программа сначала считывает строку, а затем — символ. Если символ входит в строку, программа выводит ее на экран, начиная с позиции, в которой обггаружс~ < искомый символ. В противном случае программа выдает сообщение "Символ не обнаружен**. Функции типа )ГоЫ Функции, объявленные с помощью спецификатора чоьй, не возвращают никаких значений. Это не позволяет использовать такие функции а выражениях и предотвращает их неправильное применение.
например, функция ртапе чете1са1<) выводит на экран с~року, переданную ей в качестве аргумента, размещая ее символы один под другим. Поскольку эта функция ничего не возвращает, на месте типа возвращаемого значения указано ключевое слово чоай. чозй ртьпт четсьса1(с)гат "вст) ( и)г11е(*втт) рт1птт<"Ъсхп", *вета+); Рассмотрим пример, в котором используется функция рт1пе чете1са1(). Мьпс1ийе <всй1о.)з> чотй ртьпт четтьса1(спат *втт) г /* Прототип */ ьпт иаьп(ьпт атдс, с)гат *атдч()) ( 11(атдс > 1) ртьпт четт1са1<атдч(1)) тетотп О; чотй ртгпт четтьса1(онат *втт) ( и)г11е<*нет) ртьптт("всхп", *ест++); Глава 6. Функции 11 последнее, в ранних версиях языка С ключевое слово тоЫ не определялось. )а,нм образом. в старых программах функции, нс возврашаюшис никаких значений, вместо спсцификатора тодд по умолчанию использовали тпп тпе.
Не удивляйтесь, лстпс н1в такие примеры где-нибудь в архиве. Зачем нужен оператор гейгп а функции п)а)пЦ Функция пв1п() возвращает целое число вызвавшему сс процессу, как правило, опепзцпсл шой системе. Вызвав функцию ен1е () с зтим аргументом, вы получите тот же самый аффект. С форлпсльной точки зрения. сели функция падп() ничего нс возврашает явным образом. то вызываюшему процессу передастся цсопределсннсы значение. На ирак~ цкс многие компиляторы языка С/С++ по умолчанию возврац(а»от шсло О, ио пола: яться на зто нс стоит, поскольку зто снизгп машинонезависимость вагцсй программы. ''~ Рекурсия Б языке С/Сл+ Функция может вызывать саму себя. Функции, вызывающие сами себя. ~ созываются рекурсивными (гесцгз)ус). Рекурсия — зто процесс определения какого-либо пш но на через него же.
Иногда его называют кй»егмым апре/)елениел~ (сйсц1аг с)с(нп(юп). Простым примером рекурсивной функции является функция васек(), вычисляюшая факториал целого числа. Факториалом называется число и, представляюшее собой произведение всех целых чисел от 1 до и. Например, факториал числа 3 равен 1 х 2 х 3 = 6. Рассмотрим рекурсивный и итеративный варианты функции васек().
/ Рекурсивный вариант "/ 1пт десет(тпт и) (пт апеыет; (т(в==1» теглотп(1); апвыет = тесет(п-1)*п; /* рекурсивный вызов "/ тегцтп(апеыет»г ) /* Итеративный вариант */ дпт бесе(тпт и) ( зпс т, еггвыет; апвыет =- 1; тот(т=1; т<=п; тл+! апвыет=апвыет (т) тетытп(апвыет) Итеративный вариант функции васек() выглядит проша. В нем используется цикл, чстчик которо~о пробегает значения от 1 до и и последовательно умножается на прсдыдуший результат.