Programmer’s Reference


ГЛАВА 2 - Функции , интервали , именовани пространства и хедъри



страница3/19
Дата21.09.2016
Размер2.35 Mb.
#10416
1   2   3   4   5   6   7   8   9   ...   19

ГЛАВА 2 - Функции , интервали , именовани пространства и хедъри

Функциите са изграждащите блокове на С/С++ програмите. Елементите от програма включително функциите съществуват в един или повече интервала. В С++ има специален интервал наречен именовано пространство . Прототипите за всички стандартни функции са декларирани във различни хедъри. Тези теми са разгледани тук.



Функции

Същината на С/С++ програмата е функцията. Тя е мястото в което се извършва цялата дейност на програмата. Общата форма на функция е :



връщан-тип име_на_функция(списък с параметри)

{

тяло на функцията

}

Типа на върнатите данни е определен от връщан-тип. Списък с параметри е разделен със запетайки списък от променливи които ще получават някакви аргументи подадени на функцията. Например следващата функция има два целочислени параметъра i и j и double параметър наречен count :



void f (int i , int j , double count)

{ . . .

Забележете че трябва да декларирате всеки параметър отделно. В С++ ако функцията няма параметри тогава нейния списък с параметри е празен. В С за определяне на празен списък с параметри използвайте думата void. Тук е пример :

int f ( void )

{ . . .

Тази употреба на void в С++ е разрешена но е излишна. В С ако връщания тип не е точно определен той по подразбиране е int. Стандартния С++ не поддържа подразбиране за int но повечето С++ компилатори го разрешават.

Функцията прекъсва и се връща автоматично на извикващата процедура когато се срещне последната фигурна скоба. Вие можете да направите по – ранно връщане със използване на израза return. Всички функции с изключение на онези декларирани като void , връщат стойност. Типа на връщаната стойност трябва да отговаря на типа деклариран от функцията . Ако израза return е част от не- void функция , връщаната стойност от функцията е стойността в израза return. В С++ е възможно създаването на общи функции използвайки ключовата дума template (Виж “template” в ”Справочника на ключовите думи”)

Рекурсия

В С/С++ функциите могат да извикват себе си . Това е наречено рекурсия и функцията която извиква себе си се нарича рекурсивна . Прост пример функцията factr() показана тук която изчислява факториела на цяло число. Факториела на числото N е произведението от всички числа от 1 до N . Например 3 факториел е 1х2х3 или 6.

// Изчислява факториела на число използвайки рекурсия

int factr ( int n)



{

int answer;

if (n==1) return 1;

answer = factr (n – 1 ) *1;

return answer ;

}

Когато factr () е извикана с аргумент 1 функцията връща 1, иначе тя връща произведението factr ( n – 1) * n .За изчисляването на този израз factr () e извикана със n – 1 .Този процес продължава докато n стане равна на 1 и извикванията към функцията започнат връщане . Когато factr () накрая върне първоначалното извикване , крайната върната стойност ще бъде факториела на първоначалния аргумент . Когато функция извиква себе си , нови локални променливи и параметри заделят място в стека и кода на функцията се изпълнява със тези нови променливи от неговото начало . Рекурсивното извикване не прави ново копие на функцията . Само аргументите са нови . Когато всяка рекурсия се върне старите локални променливи и параметри се премахват от стека и изпълнението се подновява от точката на рекурсивното извикване вътре във функцията . Рекурсивните функции може да се каже че излизат навън и се връщат обратно .


Програмен съвет

Рекурсивните функции трябват да бъдат използвани внимателно. Рекурсивните версии на много методи се изпълняват малко по бавно от техните итеративни еквиваленти поради прибавянето отгоре на повтарящи се извиквания на функции . Много рекурсивни извиквания към функции могат да причинят препълване на стека .Понеже съхранението на параметрите на функцията и локалните променливи е в стека и всяко ново извикване създава копие на тези променливи във него и мястото се изчерпва и ако това стане се получава препълване на стека . Ако това се случи в нормално използване на дебъгната рекурсивна функция опитайте да увеличите заделянето на място в стека за вашата програма . Когато пишете рекурсивни функции вие трябва да включите условен израз някъде който предизвиква връщане от функцията без изпълнение на рекурсивното извикване . Ако не го направите веднъж щом извикате функцията тя ще извиква себе си докато не се изчерпи стека . Това е много честа грешка когато разработвате рекурсивни функции . Използвайте щедро изходни изрази при разработката и така вие може да видите какво е започнало и да прекъснете изпълнението ако видите че сте направили грешка.



Предефиниране на функции

В С++ функциите могат да бъда предефинирани . Когато е предефинирана функция , две или повече функции споделят еднакво име . Обаче всяка версия на предефинираната функция трябва да има различен брой или тип параметри (връщаните типове на функцията могат също да се различават но това не е необходимо ) . Когато се извика предефинирана функция , компилатора решава коя версия да използва базирайки се на типа и броя на аргументите извиквайки функцията имаща най – близко съвпадение . Например имайки тези три предефинирани функции:

void myfunc ( int a ) {

cout<< “a is “ << a << endl;

}

// предефинирана myfunc



void myfunc ( int a, int b ) {

cout<< “a is “ << a << endl;

cout<< “b is “ <

}

// предефинирана отново myfunc



void myfunc ( int a, double b) {

cout <<”a is “ << a <

cout <<”b is “ << b << endl ;

}

следните извиквания са разрешени :


myfunc (10 ) ; // извиква myfunc ( int )

myfunc ( 12 , 24 ) ; // извиква myfunc ( int , int )

myfunc ( 99 , 123.23 ) ; // извиква myfunc ( int , double )

Във всички случай типа и броя на аргументите определя коя версия на myfunc ( ) е в действителност изпълнена . Предефинирането на функции не се поддържа в С .



Подразбиращи се аргументи

В С++ вие можете да присвоите на параметър на функция подразбираща се стойност , която ще бъде използвана автоматично когато няма съответен аргумент определен при извикването на функцията . Подразбиращата се стойност е определена по начин синтактично подобен на инициализацията на променлива . Например тази функция присвоява на нейните два параметъра подразбиращи се стойности:

void myfunc ( int a = 0 , int b = 10 )

{ // . . .

Давайки подразбиращи се аргументи , myfunc ( ) може да бъде легално извикана по тези три начина :

myfunc ( ~ ); // а по подразбиране 0;

// b по подразбиране 10

myfunc (-1 ); // на а се подава - 1; b по подразбидране 10

myfunc ( - 1 , 99 ); //на а се подава -1; b е 99

Когато създавате функции които имат подразбиращи се аргументи , вие може да определите подразбирещите се стойности само веднъж , или във прототипа на функцията или във нейната дефиниция (вие не можете да ги определяте на всяко място , дори ако използвате еднакви стойности ). Обикновенно подразбиращите се стойности се определят във прототипа .Когато давате на функция подразбиращи се аргументи запомнете че трябва да определите всички подразбиращи се аргумент първи . Веднъж щом започнете да определяте подразбиращи се аргументи ,не можете да ги смесвате със неподразбиращи се .Подразбиращите се аргументи не се поддържат от С .

Прототипи

В С++ всички функции трябва да имат прототип . В С прототипите са технически незадължителни , но са силно препоръчвани . Общата форма на прототип е показана тук :



връщан- тип име ( списък с параметри ) ;

Всъщност прототипа е просто връщания тип , името и списъка с параметри на дефиницията на функцията следван от точка и запетайка . Следващия пример показва прототипа на функцията fn ( ) :



float fn ( float x ) ; // прототип

.



.

.

// дефиниция на функцията

float fn ( float x ) ;

{

// . . .

}

За определяне прототипа на функция приемаща променлив брой аргументи , използвайте три последователни точки където започва променливия брой параметри . Например функцията printf ( ) може да има следния прототип:

int printf ( const char *format , . . .) ;

Когато определяте прототип за предефинирана функция всяка версия на тази функция трябва да има свой прототип .Когато член функция е декларирана в своя клас , това представлява прототипа за функцията . В С за да определите прототип на функция която няма параметри използвайте void в нейния списък с параметри .



Програмен съвет

Два термина са обикновенно обърквани в програмирането на С/С++ : декларация и дефиниция . Тук е обяснено какво означават . Декларацията определя името и типа на обект . Дефиницията заделя място за съхраняването му . Това се отнася и за функциите . Декларирането на функция (прототип ) определя връщания тип , името и параметрите на функцията .Самата функция (тоест функцията със нейното тяло ) е нейната дефиниция .В много случай декларацията е също и дефиниция . Например когато не – extern променлива е декларирана тя е също и дефинирана . Или когато е дефинирана по – рано функция за употреба , нейната дефиниция също служи като декларация .



Разбиране на интервалите и продължителността на съществуване на променлива


С и С++ определят правила на интервала които управляват видимостта и продължителността на живот на обектите . Макар че има няколко тънкости в повечето случай има два интервала : глобален и локален .Глобалния интервал съществува извън всички други интервали . Име декларирано в глобалния интервал е известно навсякъде във програмата . Например глобална променлива е на разположение за употреба от всички функции в програмата . Глобалните променливи съществуват през цялото времетраене на програмата . Локалния интервал е дефиниран чрез блок . Така локалния интервал е започнал при отварящата фигурна скоба и завършва при затварящата скоба . Име декларирано във локален интервал е познато само в този интервал . Понеже блоковете могат да бъдат вложени , локалните интервали също могат да бъдат вложени . Разбира се най- общия локален интервал е този дефиниран чрез функция . Локалните променливи се създават когато техния блок е започнал и се разрушават когато техния блок е напуснат . Това значи че локалните променливи не държат техните стойности между извикванията на функцията . Вие обаче може да използвате модификатора static да запазите стойностите между извикванията . В С++ локалните променливи могат да бъдат декларирани почти навсякъде във блока . В С те трябва да бъдат декларирани в началото на блока , преди всеки действащ израз да се изпълни . Например следния код е валиден за С++ , но не и за С :

void f ( int a )

{

int a ;

a = 10 ;

int b ; // ОК за С++, но не и за С

Глобална променлива трябва да бъде декларирана извън всички функции включително и функцията main ( ) . Глобалните променливи се обикновенно поставят на върха на файла преди main ( ) , за улесняване на четенето и понеже променлива трябва да бъде декларирана преди да се използва . Формалните параметри на функция са също локални променливи и като изключим тяхната работа при получаването на стойността на от извикващите аргументи , се държат и могат да бъдат използвани както всяка друга локална променлива .



Именовани пространства

В С++ е възможно създаването на локален интервал използвайки ключовата дума namespace . Именованото пространство определя декларативен регион .Неговото предназначение е да локализира имената . Общата форма на namespace e показана тук :

namespace име {

// . . .

}

Тук име е името на именованото пространство . Това е пример :

namespace MyNameSpace {

int count ;

}

Това създава именовано пространство наречено MyNameSpace и променлива count декларирана във него . Имена декларирани във именовано пространство могат да бъдат насочени точно към други изрази в същото именовано пространство . Извън тяхнто именовано пространство , имената могат да бъдат достигнати по два начина . Първо вие може да използвате оператора за включване на интервал . Например приемайки MyNameSpace като горния , следващия израз е валиден :

MyNameSpace :: count = 10 ;

Вие можете също да определите израз using , който внася определено име или именовано пространство в текущия интервал . Това е пример :

using namespace MyNameSpace ;

count = 100 ;

В този случай count може да бъде посочено точно понеже е било внесено във текущия интервал . Традиционно заглавията декларирани в С++ библиотеката бяха във глобалното ( тоест неименовано ) пространство . Обаче сегашната спецификация за С++ слага всичките тези заглавия във именованото просранство std .



Функцията main ( )

В С/С++ програма изпълнението започва от main ( ) ( Windows програмите извикват WinMain ( ) , но това е специален случай ). Вие не трябва да имате повече от една функция наречена main ( ) .Когато main ( ) се прекъсне , програмата приключва и контрола се подава обратно на операционната система . Функцията main ( ) няма прототип. Така различни форми на main ( ) могат да бъдат използвани . И за С и за С++ следващите версии на main ( ) са валидни ( други форми са също позволени ) :

int main ( )

int main ( int argc , char * argv[ ] )

Както показва втората форма , най – малко два параметъра се поддържат от main ( ) .Това са argc и argv ( някой компилатори ще разрешат и допълнителни параметри ). Тези две променливи ще съдържат ще съдържат броя на аргументите от командния ред и указател към тях съответно . Параметъра argc е цяло число и неговата стойност ще бъде най - малко 1 понеже името на програмата е първи аргумент що се касае за С/С++. Параметъра argv трябва да бъде деклариран като масив от символни указатели . Всеки указател сочи към аргумент от командния ред . Тяхната употреба е показана по – надолу в къса програма която ще отпечати вашето име на екрана :


#include

using namespace std ;

int main ( int argc, char * argv[] )

{

if (argc < 2 )

cout <<”Enter your name . \n “ ;

else

cout <<” hello “ << argv[] ;

return 0;

}


Аргументи на функция


Ако функция използва аргументи тя трябва да декларира променливи които приемат стойностите на аргументите . Тези променливи са наречени формални параметри на функцията . Те се държат като всяка друга локална променлива вътре във функцията и се създават при влизане във функцията и се разрушават при изход от нея . Както и с локалните променливи , вие можете да правите присвоявания за формалните параметри на функцията или да ги използвате във всеки разрешен С/С++ израз . Дори макар тези променливи да изпълняват специална задача да получават стойност от аргументите подадени на функцията , те могат да бъдат използвани като всяка друга локална променлива . Най – общо предаването на аргументи е по два начина .Първия е наречен извикване по стойност .Този метод копира стойността на аргумент във формалния параметър на функцията . Промените направени върху параметрите на функцията нямат ефект на променливите използвани за извикването и . Втория начин за подаване на параметри на функция е означен като извикване по адрес . В този метод , адреса на аргумента се копира в параметъра . Вътре във функцията се използва за достъп до действителния аргумент използван в извикването . Това значи че промените направени върху параметъра се отразяват върху променливата използвана за извикването на функцията . По подразбиране С и С++ използват извикване по стойност за подаване на аргументи . Това значи че във функция вие обикновенно не можете да промените променливите използвани за извикване на функцията . Разгледайте следната функция :

int sqr ( int x )



{

x = x * x ;

return x ;

}

В този пример , когато се извърши присвояването x = x * x , само се променя локалната променлива х . Аргумента използван да извика sqr ( ) още има неговата първоначална стойност . Запомнете че само копие на стойноста на аргумента се подава на функция . Какво се случва вътре във функцията няма ефект върху променливата използвана при извикването.



Подаване на указатели


Дори макар че С/С++ използват извикване по стойност за подаването на параметри по подразбиране , възможно е ръчно да конструирате извикване по адрес чрез подаване на указател към аргумента . Понеже това подава адреса на аргумента на функцията , тогава е възможно да промените стойността на аргумента извън функцията . Указатели се подават на функциите като всяка друга стойност . Разбира се необходимо е да декларирате параметрите като типове указатели . Например функцията swap ( ) , която разменя стойностите на нейните два целочислени аргумента следва :

//използва параметри указатели

void swap ( int * x , int * y )

{

int temp;

temp = * x ; // запазва стойноста на адреса х

* x = * y ; // слага у във х

*у = temp ; // слага х във у

}

Важно е да запомните че swap ( ) ( или всяка друга функция която използва параметри указатели ) трябва да бъде извикана със адреса на аргументите . Следващия фрагмент показва правилния начин за извикване на swap ( ) :



int a , b ;

A = 10 ;

B = 20 ;

swap ( & a , & b );

В този пример , swap ( ) е извикана със адреса на а и b . Унарния оператор & се използва да получи адреса на променливите . По този начин адресите на а и b , a не техните стойности се подават на функцията swap ( ) . След извикването , а ще има стойност 20 а b ще има стойност 10 .


Параметри псевдоними

В С++ е възможно автоматично да подадете адрес на променлива към функция . Това се осъществява чрез използването на параметър псевдоним . Когато използвате параметър псевдоним , адреса на аргумента се подава на функцията и тя оперира със аргумента а не със копие . За създаване на параметър псевдоним , сложете пред неговото име & (амперсанд) . Вътре във функцията можете да използвате параметъра нормално без никаква нужда от употреба на оператора * ( астерикс ) . Компилатора автоматично ще прехвърли адреса за вас . Например следващия код създава версия на swap ( ) която използва два параметъра псевдоними за разменяне стойностите на нейните два аргумента :

//използва параметри псевдоними

void swap ( int & x , int & y )



{

int temp;

temp = x ; //запазва стойноста на адреса х

x = y ; //слага у във х

у = temp ; //слага х във у

}

Когато извиквате swap ( ) , вие просто използвайте нормалния синтаксис на извикване . Това е пример :

int a , b ;

A = 10 ;

B = 20 ;

swap ( a , b );

Понеже сега х и у са параметри псевдоними , адресите на а и b се генерират автоматично и подават на функцията . Вътре във функцията имената на параметрите се използват без никаква нужда от оператора * понеже компилатора автоматично се отнася към извикващите аргументи всеки път когато се използват x и y . Параметрите псевдоними се използват само във С++ .



Конструктори и деструктори

В С++ , клас може да съдържа функция конструктор , функция деструктор или и двете . Конструктора се извиква когато се създава обект от класа , а деструктора се извиква когато се разрушава обект от класа . Конструктора има еднакво име като класа на който е член а името на деструктора е същото като името на неговия клас с изключение на това че пред него има ~ (тилда ) Нито конструктора , нито деструктора имат връщана стойност . Функциите конструктори могат да имат параметри . Вие може да използвате тези параметри да подадете стойност към конструктора , която може да бъде използвана за инициализацията на обект . Аргументите които са подадени към параметрите се определят когато се създава всеки обект . Например този фрагмент илюстрира как да подадете аргумент на конструктора :

class myclass {

int a ;

public :

myclass ( int i ) { a = i ;} //конструктор

~myclass ( ) { cout << “Destructing . . . “ ;}



} ;

// . . .

myclass ob ( 3 ) ; //подава 3 на i

Когато ob е деклариран стойността 3 се подава към параметъра на конструктора i който я присвоява на а .



Спецификатори на функция


С++ дефинира три спецификатора за функция : inline , virtual и explicit . Спецификатора inline е заявка към компилатора да разшири кода на функция в реда вместо да я извиква . Ако компилатора не може да постави функцията на реда , той е свободен да отхвърли заявката . И член и не – член функции могат да бъдат определени като inline . Virtual функция се дефинира в базовия клас и се предефинира от производния клас . Виртуалните функции са начина по който С++ поддържа полиморфизъм . Спецификатора explicit се прилага само към конструкторите . Конструктор определен като explicit ще бъде само използван когато инициализацията точно се прилага както определя конструктора . Никакво автоматично преобразуване не става ( тя създава “ непреобразуващ конструктор “ ) .

Свързваща спецификация


Понеже често свързвате С++ функция със функции генерирани от друг език ( такъв като С ) , С++ позволява да определите свързваща спецификация която казва на компилатора как да свърже функцията . Тя има тази обща форма :

extern език прототип на функцията

Както можете да видите , свързващата спецификация е разширение на ключовата дума extern . Тук “ език “ означава езика за който искате да се свърже функцията . С и С++ свързване са гарантирани да се поддържат .Вашия компилатор може също да поддържа и други свързвания . За деклариране на няколко функции използващи една спецификация , вие може да използвате тази обща форма :

extern език “ {



прототипи на функциите

}

Свързващата спецификация се поддържа само във С++ и я няма във С .



Стандартните библиотеки на С и С++

Нито С нито С++ имат ключови думи изпълняващи I/O , манипулиращи низове , изпълняват различни математически изчисления или изпълняват някакви други полезни процедури . Начина по който тези неща са изпълнени е чрез използване на множество от предефинирани библиотечни функции които са доставени със компилатора . Има два основни стила библиотеки :функционалната библиотека на С и С++ класовата библиотека , която е приложена само за С++ . И двете библиотеки са описани по – късно във този справочник . Преди вашата програма да може да използва библиотечна функция , тя трябва да включи подходящ хедър . За С програми , хедърите се определят използвайки техните файлови имена , които завършват на . H . Хедърните файлове са дефинирани от ANSI C стандарта както е показано тук:



С хедър файл Поддържа

assert . h Макроса assert ( )



ctype . h Манипулиране на символи

errno . h Сведения за грешки

float . h Зависещи от изпълнението числа със плаваща точка

iso646 . h Няколко макроса които могат да бъдат използвани на мястото на различни оператори , такива като not за ! или xor за ^

limits . h Различни зависещи от изпълнението лимити

local .h Функцията setlocale ( )

math . h Различни дефиниции използвани за математическата библиотека

setjmp . h Нелокален скок

signal . h Сигнални стойности

stdarg . h Аргументен списък със променлива дължина

stddef . h Общо употребявани константи

stdio . h Файлов I/O

stdlib . h Разнообразни декларации

string .h Низови функции

time . h Системно време и функции за дата

wctype . h Манипулиране със широки символи

wchar . h Функции за широки символи
В модерната спецификация за С++ , хедърите се определят чрез използване на стандартни хедърни имена , които не завършват със .h . Тези хедъри в нов стил не определят имена на файлове . Вместо това те са просто стандартни идентификатори които компилатора може да манипулира както му е удобно . Това значи че хедъра може да бъде съпоставен на файлово име , но не е задължително . Новите С++ хедъри са показани тук . Тези отнасящи се до стандартната шаблонна библиотека ( STL ) са означени :
С++ хедър Поддържа

<algorythm> Различни операции в контейнери ( STL )



Битсети ( STL )

Комплексни числа

Опашки с два края ( STL )

Манипулиране на изключения

Базиран на потоци файлов I/O

Различни функции ( STL )

I/O манипулатори

I/O класове от ниско ниво
Съвременни декларации за I/O системата

Стандартни I/O класове

Входни потоци

Достъп до съдържанието на контейнери (STL)

Различни изпълнителни лимити

Линейни списъци ( STL )

Локализационна информация

Карти ( ключове със стойности ) ( STL )
Заделяне на памет ( STL )

Заделяне на памет чрез използване на new

Числови операции с общо предназначение

Изходни потоци

Опашки ( STL )

Множества ( STL )

Низови потоци

Стекове ( STL )

Стандартни изключения

Буферирани потоци

Стандартния клас string ( STL )

Информация за типа по време на изпълнение

Шаблони с общо предназначение ( STL )

Операции върху масиви съдържащи стойности

Вектори ( динамични масиви ) ( STL )
С++ също дефинира следните хедъри в нов стил които съответстват на С хедърите :

<cassert>











В стандартния С++ , цялата информация отнасяща се до стандартната библиотека е дефинирана в именованото пространство std . Tака , за получаване на директен достъп до тези имена , вие ще трябва да включите следващия using израз след включването на необходимите хедъри .

using namespace std ;

Програмен съвет

Ако използвате стар С++ компилатор , тогава той може да не поддържа новите С++ хедъри или командата namespace . Ако случая е такъв , тогава вие трябва да използвате старите в традиционен стил хедъри . Те използват еднакви имена като новите хедъри но включват .h ( така те приличат на С хедъри ) . Например следващото включва <iostream> използвайки традиционно обръщане :



#include

Когато използвате хедъри в традиционен стил , всички имена дефинирани от хедъра се поставят в глобалното именовано пространство , а не във това определено от std . Така не се изисква израз using .




Каталог: books
books -> Тайнствената сила на пирамидите Богомил Герасимов Страхът на времето
books -> В обятията на шамбала
books -> Книга се посвещава с благодарност на децата ми. Майка ми и жена ми ме научиха да бъда мъж
books -> Николай Слатински “Надеждата като лабиринт” София, Издателство “виденов & син”, 1993 год
books -> София, Издателство “Българска книжница”, 2004 год. Рецензенти доц д. ик н. Димитър Йончев, проф д-р Нина Дюлгерова Научен редактор проф д-р Петър Иванов
books -> Николай Слатински “Измерения на сигурността” София, Издателство “Парадигма”, 2000 год
books -> Книга 2 щастие и успех предисловие
books -> Превръщане на числа от една бройна система в друга
books -> Тантриското преобразяване


Сподели с приятели:
1   2   3   4   5   6   7   8   9   ...   19




©obuch.info 2024
отнасят до администрацията

    Начална страница