Най-четените учебни материали
Най-новите учебни материали
***ДОСТЪП ДО САЙТА***
ДО МОМЕНТА НИ ПОСЕТИХА НАД 2 500 000 ПОТРЕБИТЕЛИ
БЕЗПЛАТНИТЕ УЧЕБНИ МАТЕРИАЛИ ПРИ НАС СА НАД 7 700
Ако сме Ви били полезни, моля да изпратите SMS с текст STG на номер 1092. Цената на SMS е 2,40 лв. с ДДС.
Вашият СМС ще допринесе за обогатяване съдържанието на сайта.
SMS Login
За да използвате ПЪЛНОТО съдържание на сайта изпратете SMS с текст STG на номер 1092 (обща стойност 2.40лв.)Какво представлява една С++ програма |
![]() |
![]() |
![]() |
При самостоятелно запознаване с езика С++ естествено възникват два въпроса: 1. Какво представлява една С++ програма? Как се пише? 2. Веднъж написана, как може да бъде изпълнена? Тази глава описва основните знания и действия, необходими за получаването на изпълнима програма от изходен код на С++. 0.1. Решаване на проблемиПрограмите най-често се пишат в отговор на проблеми или задачи, които трябва да бъдат решени. Нека да разгледаме един пример. Магазин за книги въвежда във файл заглавието и издателя на всяка книга, която продава. Информацията се въвежда по реда на продаваните книги. Всеки две седмици собственикът на ръка изчислява броя на екземплярите на всички продадени книги, както и бройките, отнасящи се до различните издатели. Списъкът се подрежда в азбучен ред и се използува за реорганизация. Вие сте помолени да предложите програма за тази работа. Един от методите за решаване на голям проблем е раздробяването му на няколко малки проблема. За щастие, тези малки проблеми са по-лесни за решаване. Проблемът на книжарницата се разделя на четири подпроблема или задачи:
Точки 1, 3 и 4 представят проблеми, които знаем как да решим; те не се нуждаят от допълнително разпадане. Точка 2, обаче, представя проблем, който не може да бъде решен директно. Затова прилагаме своя метод към нея: 2а. Подреждаме продадените книги по издатели. 2б. За всеки издател подреждаме продажбите по заглавие. 2в. Сравняват се съседните заглавия във всяка издателска група. За всяка съответствуваща двойка, се увеличава броят на появите на първият елемент на двойката и се изтрива вторият. Точки 2а, 2б и 2в също вече представят проблеми, които знаем как да решим. Тъй като вече сме в състояние да решим всички подпроблеми, които бяхме формулирали, то фактически сме решили и по-големия проблем. Последователността от действия ще бъде:
Описаната последователност от действия може да бъде на-речена алгоритъм. Следващата стъпка е описване на алгоритъма в термините на някой програмен език - в този случай на С++. 0.2. С++ програма В С++ всяко действие се представя чрез израз. Израз, ограничен с “;” представлява оператор. Най-малката независи-ма единица в езика е оператора. В естествените езици аналогичната конструк ция е изречение. Следващите изрази, напри-мер, са оператори на С++.
Първият оператор е един декларативен оператор. Той дефинира област от паметта на компютъра, свързана с името value, където могат да се записват цели числа. Вторият оператор е оператор за п 0исвояване. Той помества в паметта на компютъра, свързана с името value, резултата от събирането на 7 и 1. Третият оператор е оператор за изход. Сout описва изход, насочен към потребителския терминал. << е оператор за изход. Операторът записва в cout, т.е . на потребителския терминал, стойността, съхранена в областта от компютърната памет, свързана с името value. Операторите логически се групират в единици, наречени функции. Например, всички оператори, необходими за четене от файла продажби,са организирани във функция, наречена readIn(). Съответно, с ъздаваме и функциите sort(), compact() и print(). В С++ всяка програма трябва да съдържа функция, нарече-на main(), написана от програмиста, преди да може да бъде изпълнена. Следва пример за дефиниране на main() за гореописания алгоритъм. int main() {
} Програмата на С++ започва да се изпълнява от първия оператор на main(). В този случай, програмата започва с изпълнението на функцията readIn(). Изпълнението й продължава чрез последователното (зпълнение на операторите в main(). Тя приключва нормално с изпълнението на последния оператор на main(). Всяка функция се състои от четири части: тип на резултата, име на функцията, списък от аргументи и тяло. Първите три елемента заедно образуват прототипа на функцията. Списъкът от аргументи, затворен в скоби, съдържа списък от нула или повече аргументи, отделени със запетая. Тялото на функцията е затворено в скоби от вида “{ }”. То съдържа последователност от програмни оператори. В този пример, в тялото на main() се извикват заизпълнение функциите readIn(), sort(), compact() и print(). Когато тези функци приключат работа, се изпълнява операторът return 0. Това е един предварително дефиниран оператор на С++, предоставящ метод за прекратяване на изпълнението на функция. Когато операторът е съпътствуван от стойност, 0 например, тази стойност става стойност, която функцията връща. В този случай, връщаната стойност 0 показва успешното приключване на изпълнението на main(). Нека сега да подготвим програмата за изпълнение. Първо трябва да предложим дефиниции за readIn(), sort(), compact() и print(). В този момент следните фиктивни примери са достатъчно добри.
viod се използува за да укаже, че функцията не връща стойност. Както е дефинирано, всяка функция просто ще съобщи за своето съществуване чрез написване на съответния текст върху терминала на потребителя, когато бъде извикана от main(). По-късно бихме могли да заменим фиктивния пример със самото тяло, когато то бъде реализирано. Този метод на последователно увеличаване на кода на програмата е полезен за контролиране на програмните грешки, които неминуемо допускаме. Да се опитваме да направим работеща програма отведнъж е просто много сложно и объркващо. Всеки файл, съдържащ текст на програма се състои от две части - име на файл и разширение. Разширението често определя съдържанието на файла. Това разширение ще се променя при различните реализации на С++. При операционната система UNIX, името на С++ файла може да бъде завършено както със “.с”, така и със “.С”. Употребата на малка буква “.с” показва съществуващата връзка между програмните езици С++ и С. (Всички файлове, съдържащи програми на С трябва да завършват със “.с”). За да бъде различаван С++ програмен файл, използувайте разширение “.С”. (ў) Въведете следната пълна програма в един С++ кодов файл.
void compact() { cout << “compact()\n”; } viod write() { cout << “write()\n”; } int main() {
} Stream.h е един от т.н. заглавни файлове. Той съдържа информация за cout, която е необходима за написаната програма. #include е една предпроцесорна директива. Тя указва добавянето на съдържанието на stream.h към нашия текстов файл. Част 0.5 разглежда предпроцесорните директиви. След като вече програмата е записана във файл може да бъде компилирана. Това се прави така ($ е системния показалец): $ СС prog1.C Името на командата, използувано за извикване на компилатора на С++ ще бъде различно за различните реализации. СС е името на командата, използувано от AT&T C++ Language System, Release 2.0. Направете справка в своя наръчник или попитайте вашия системен администратор за името на С++ компилатора във вашата система. Част от работата на вашия компютър е да анализира текста на програмата за коректност. Компютърът не може да установи дали логиката на вашата програма е правилна, но може да открие грешки във формата на програмата. Най-общо програмните грешки, които компилаторът открива са: 1. Синтактични грешки. Програмистът е направил “граматическа грешка” според езика С++. Например:
} 2. Грешки за типове. Данните в С++ се свързват с типове. Стойността 10, например, е цяла. Думата “hello”, заградена от двойни кавички е символен низ. Ако на дадена функция очакваща аргумент от цял тип се подаде аргумент тип низ, компилаторът ще сигнализира за грешка при типовете. Всяко съобщение за грешка съдържа номер на ред и кратко описание на причината, поради която се счита, че вие сте сгрешили. Препоръчва се грешките да се коригират в последователността, в която се появяват. Често единична грешка може да предизвика лавинообразен ефкет и компилаторът да съобщи за повече гришки, отколкото фактически съществуват. След като коригирате текста на програмата си, можете да я компилирате отново. За операционната система MS-DOS, обаче, разширението “.c” не е допустимо - MS-DOS не прави разлика между малки и големи букви. Реализацията на С++ под управлението на MS-DOS поддържа следните разширения на файлове:
Втората част от работата на компилатора е да преведе формално коректния програмен текст. Този превод, наречен генерация на код, фактчески генерира обектов или асемблерен текст, разбираем за компютъра на който програмата ще бъде изпълнявана. Резултатът от успешна компилация е изпълним файл. По подразбиране, при системата на автора този файл се нарича a.out. Той може да бъде изпълнен както следва: $ a.out
Командната опция “-о име” позволява на програмиста да даде име на програмния файл, различно от a.out. Например, командният ред $ CC prog1 prog1.C ще създаде изпълним файл prog1. За да се изпълни тази програма трябва да се напише: $ prog1 Освен езиковия компилатор реализацията на С++ предлага и набор от стандартни библиотеки. Библиотеките са съвкупност от предварително дефинирани функци. В С++, например, входът и изходът се поддържат от стандартна С++ библиотека. Програмистите могат да използуват библиотечните функции в програмите си по същия начин, по който използуват функциите, които са написали. Най-голямото предимство на програмните библиотеки е това, че позволяват на добри програмисти да комплектоват своите знания за използуване от множество други програмисти. Малко от нас, например, знаят как работи електричеството, но повечето знаят как да включат осветлението. Добрата библиотека може да бъде използувана така лесно, както и ключа за осветление. В следващата част се прави един кратък преглед на входно-изходната библиотека.
Входът и изходът не са част от езика С++, но се поддържат от библиотека, написана на С++ и позната като iostream ( вх/изх. поток). Приложение А разглежда подробно тази библиотека(ў). В този дял е дадена достатъчна информация за начинаещия читател. Входът, постъпващ от потребителският терминал, наречен стандартен вход, е свързан с предварително дефинирания във вх/изх. поток вход cin (произнася се “see-in”). Изходът, насочен към потребителския терминал, се нарича стандартен изход и се свързва с предварително дефинирания във вх/изх. поток изход cout (произнася се “see-out”). Операторът за изход (“<<”) се използува за изпращане на стойност към стандартния изход. Например:
Последователността от символи \n представя символа нов ред. При писане той предизвиква насочване на печата на следващия ред. Последователност от входно-изходни оператори може да бъде обединена в един оператор. Например, cout << “The sum of 7 + 3 = “ << 7 + 3 << “\n”; Всеки следващ изходен оператор може да бъде добавен на свой ред към cout. За четимост обеднените изходни оператори могат да се разположат на няколко реда. На следващите три реда е записан един изходен оператор. Читателят, разполагащ с реализация на С++, която не се основава на версия 2.0, има по-ранната версия на библиотеката, наречена stream. Примерите в тази книга използуват подмножество, общо за двете версии.
Съответно операторът за вход (“ >> “) се използува за четене на стойност от стандартния вход. Например, следната програма реализира прост алгоритъм за четене на две стойности, определяне на по-голямата от тях и отпечатването й.
По тази програма могат да бъдат направени няколко забележки. Описани са три имена на функции преди да бъде дефинирана функцията main(). Първоначалният списък се нарича предварителна декларация, съобщаваща на програмата, че тези функции съществуват и описанията им могат да бъдат намерени някъде в текста на програмата, представена от този файл или в отделен файл. Всяка функция трябва да бъде деклакирана преди да може да бъде викана. Предварителната декларация е един от начините да се направи това. val1 и val2 се наричат променливи. Операторът int val1, val2; дефинира тези променливи за програмата. И променливите трябва да бъдат обявени преди да могат да бъдат използувани. Продробен преглед на променливите е направен в глава 1. v1 и v2, наричани формални параметри, изграждат списъка от аргументи на функциите read2() и max(). val е единствения формален параметър на writeMax(). Същността на дефиницията им е разгледана в дял 3.6, където се обсъжда как се описват параметрите на функции. Читателят сигурно е забелязал, че main() e описана малко по- различно този път. Не е описан явно типа на връщания резултат. Това е разрешено в С++: функция, за която не е зададен тип за връщане, връща тип цяло число по подразбиране. Когато програмата бъде компилирана и изпълнена се получава следния изход (потребителят е въвел стойностите 17 и 124):
Двете стойности, 17 и 124, са разделени с интервал. Интервалите, табулациите и новите редове са празно пространство (white space) за С++. Операторът cin >> v1 >> v2; правилно чете двете стойности, защото операторът за изход (“>>”) пропуска цялото празно пространство, което е въведено. Предварителната дефиниция на cin и cout се съдържа в stream.h. Ако програмистът забрави да включи този файл, всички обръщения към cin и cout ще бъдат отбелязани от компилатора като грешки. Включването на предварителните декларации показва първичната употреба на заглавния файл. ( Част 4.5 разглежда заглавните файлове в подробности). Съществува и един трети вх/изх. поток, cerr (произнася се “see-err”), наречен стандартна грешка, който също се свързва с потребителския терминал. cerr се използува за да уведомява потребителя относно някои особени състояния на програмата по време на изпълнение. Например, следната част от програма предпазва програмиста от деление на нула:
Следващата програма чете по един символ от стандартния вход докато не срещне end-of-file. Тя брои прочетените редове и символи. Изходът й има следния вид: lineCount characterCount
case ‘ ‘ : break; case ‘\n’: ++lineCnt; break; default : ++charCnt; break; } }
} get() е функция, принадлежаща на вх/изх. поток, която чете символи го записва като свой аргумент - в този случай, ch. Последователността от два символа \n представя символа tab. Операторът switch сигурява условен преход според стойносттана селектора си. Ако стойността му съвпада с някой от описаните след думата case стойности, се изпълнява оператора, съответствуващ на тази стойност. Ако съответствие не може да бъде намерено, се изпълняват операторите, записани след default. За всеки прочетен символ за нов ред се увелчава стойността на lineCnt с 1. charCnt се увеличава с 1 всеки път, когато е прочетен символ, който не е табулатор, интервал или нов ред. Операторът while, наричан оператор за цикъл, осигурява многократно изпълнение на група от оператори докато някакво условие има стойност истина. В този случай, операторът switch се изпълнява докато get() чете символ от стандартния вход. (Операторите while и switch са описани в глава 5). Упражнение 0-1. Въведете програмата във файл prog2.c и я компилирайте в изпълним файл, наречен prog2. Упражнение 0-2. Изпълнете програмата с текста на предишното упражнение. Изпълнете я отново с текст, съдържащ само празни интервали. Изпълнете я за текст, съдържащ само знака end-of-file. Упражнение 0-3. Преработете програмата така, че да брои табулаторите (tabCnt) и интервалите (blankCnt). Нека изходът да изглежда така.
0.4. Няколко думи за коментарите Коментарите се пишат за да подпомагат четенето на програмите. Те могат да поясняват алгоритъма на функцията, да описват употребата на променливите или да поясняват други аспекти по текста на програмата. Коментарите не увеличават размера на изпълнимата програма. Те се отстраняват от компилатора преди генерацията на кода. В С++ са дефинирани два типа коментари. Двойката (“/* /”) описва коментарите в езика С. Началото на коментара се определя чрез “/”. Всичко, което следва тези символи ще бъде трерирано от компилатора като коментар до срещането на символите “*/”. Коментар може да бъде поставян там, където могат да се поставят тавулатори, интервали или символи за нов ред и той може да заема няколко реда от програмата. Например, /*
void home(); /* move cursor to 0,0 */ void refresh(); /* redraw Screen */ private: /* Classes support “information hiding”. */ /* Information hiding restricts a program’s */ /* access to the internal representation of */ /* a class (its data). This is done through */ /* use of the “private:” label */ char cursor; / current Screen position */ }; Многото коментари, разположени хаотично в пограмния код, могат да напрвят текста неясен. Например, обградената с коментари дефиниция на cursor почти я скрива. Изобщо, за предпочитане е коментарът да се помества в цялостен блок над текста, който пояснява. Коментарите не могат да бъдат влагани. Т.е., коментар не можеда се поставя във вътрешността на друг коментар. Въведете програмата, написана по-нататък в текста. Тя ще предизвика генерирането на серия от грешки. Как бихте могли да се справите с това? #include /* comment pairs /* */ do not nest. “do not nest” is considerd sourse code, as are both these lines and the next.*/ main() { cout << “hello, world\n”; } Вторият тип коментари се означава чрез двойката символи //, ограничаващи коментар от един ред. Текстът, записан от дясно на този ограничител, се третира като коментар и се игнорира от компилатора. Например,
{ int v1, v2; // hold values from user read2( v1, v2 ); // declared in myIO.h
} isOdd( int val ) { /* return 1 if val is odd; otherwise, return 0 * % is the modulus operator; 3 % 2 yields 1. */ return( val % 2 != 0 ); } Тази програма определя дали стойностите са четни или нечетни. Тя използува функцията read2(), дефинирана в предходния подраздел. Прототипът на тази функция е зададен в заглавния файл myIO.h. Когато програмата бъде компилирана и изпълнена, ще бъде изведено следното (стойностите 497 и -25 са въведени от потребителя):
25 is odd Двойката символи, ограничаваща коментарите, не може да бъдат разделяни с интервал. Следните два реда, например, няма да бъдат разглеждани като коментари, а по-скоро като част от програмния текст: / * not a comment: white space not allowed */ // also not a comment: must be // Обикновено програмите съдържат както единия тип коментари, така и другия. Обширните разяснения най-често се организират в коментар като се използува двойката коментарни ограничители. За бележки, разположени на половин или един ред се използуват символите //. 0.5. Директиви на предпроцесораРедом със стандартните библиотеки се предлага набор от стандартни заглавни файлове, такива като stream.h. Тези заглавни файлове съдържат цялата информация, необходма на потребителя, за да използува лесно библиотеките. За да имаме достъп до промен-ливите и функциите, дефинирани в тези библиотеки, ние трябва да включим съответния заглавен файл в нашата програма. Заглавните файлове стават част от нашата програма като се използува директивата include. Директивите се определят като се постави знака # в първата колона от реда в нашата програма. Директивите се обработват преди извикването на езиковия ком-пилатор. Програмата, която обработва директивите се нарича пред-процесор. Директивата #include чете от съдържанието на именован файл. Тя има един от следните два формата:
Ако името на файла е затворено в ъглови скоби (“”) се подразбира, че файлът е преаварително дефиниран, или стандартен, заглавен файл. Търсенето за откриването му ще бъде проведено в предварително дефинирано множество от местоположения, което може да бъде променяно чрез опцията -I на командата СС. Например, командата $ CC -I incl -I/usr/local/include prog1.c указва на предпроцесора да потърси първо в директория incl, а после в /usr/local/include, преди да преглежда предварително дефинираното множество от местоположения. При първият открит екземпляр на файла се преустановява търсенето. Ако името на файла е затворено в двойни кавички се подразбира, че това е заглавен файл, създаден от потребителя. Търсенето му започва от текущата директория. Ако не бъде намерен там се преглежда множеството на предварително дефинираните местоположения. Опцията -I също работи със заглавни файлове, дефинирани от потребителя. Всеки включен файл може също да съдържа директива #include. Поради това е възможно даден заглавен файл да бъде включен неколкократно в изходен файл. Могат да бъдат използувани условни директиви за да се предотврати многократната обработка на даден заглавен файл. Например,
Условната директива #ifndef приема стойност истина, когато името, което следва не е дефинирано все още. Когато условната директива приеме стойност true съвкупността от редове до #endif се считат включени. Ако условната директива приеме стойност false, тези редове ще бъдат игнорирани. Директивата #define дефинира името, което я следва. В този случай тя дефинира STRING_H. Ако заглавият файл String.h се включва отново директивата #ifndef ще приеме стойност false и съдържанието на Stream.h нъма да бъде включено повторно. Директивата #ifdef приема стойност true, когато името, записано след нея, е дефинирано. Например,
for AT&T 3B ocmputers goes here */
for Sun computers goes here */ #endif С++ предварително дефинира името __cplusplus (две подчертаващи тиренца). Потребител, който желае да смесва програми, написани на С и С++, трябва да запише следното:
Операторите между директивите #else и #endif ще бъдат вклю-чени ако директивата #ifdef приеме стойност true. Предпроцесорът е тясно свързан с езика С (често се нарича cpp, С - пред-процесор). Много реализации просто използуват предпроцесора на С и следователно не разпознават коментара на С++, ограничаван от //. Ако желаете да включите коментар в директива #define по-безопасно е да използувате обичайния за С коментар.
|