Начало Решаване на проблеми



страница4/19
Дата20.01.2017
Размер4.54 Mb.
#13105
ТипГлава
1   2   3   4   5   6   7   8   9   ...   19
Глава 1: Типове данни в С++

Езикът С++ предлага набор от предварително дефинирани

типове данни, оператори за обработката им, както и няколко

оператори за програмен контрол. Тези елементи определят

азбуката, чрез която могат да бъдат написани множество големи

системи, приложими в реалния свят. На това базисно ниво С++ е

един прост език. Неговата изразителна сила се увеличава чрез

поддържането на механизми, които позволяват на програмиста да

дефинира нови даннови съвкупности.

Първата стъпка при усвояването на С++ - разбирането

на базисния език - е тема на тази и следващата глава. Тази

глава обсъжда предварително дифинираните типове данни пояснява

механизма за конструиране на нови типове данни, докато глава 2

разглежда предварително дефинираните операции и оператори.

Текстът на програмата, която пишем, както и данните,

които обработваме, са записани в паметта на компютъра като

последователност от битове. Всеки бит представлява единична

клетка, където могат да се съдържат стойностите 0 или 1. На

физичен език тези стойности са елктрически заряди,

съответствуващи на "off" или "on". Обикновено част от паметта

на компютъра изглежда така:
...00011011011100010110010000111011...
Съвкупността от битове на това ниво няма структура. Трудно е

да се говори за този поток от битове по който и да е смислен

начин.

Върху последователността от битове се налага структура



като се счита, че те са групирани в байтове и думи. Най - общо

казано, байтът е съвкупност от 8 бита. Обикновено една дума се

образува от 16 или 32 бита. Размерът на байта и думата варират

между различните компютри. За тези стойности често се казва,

че са машинно зависими. Фигура 1.1. показва горната

последователност от битове, организирана в четири адресуеми

редици от байтове.

Организацията на паметта ни позволява да се обръщаме

към подходяща съвкупност от битове. По такъв начин вече е

възможно да говорим за думата на адрес 1024 или за байта на

адрес 1040, което ни позволява да казваме например, че байта

на адрес 1032 не е равен на байта от адрес 1048.

Но все още не е възможно да се говори смислено за

съдържанието на байта на адрес 1032. Защо? Защото не знаем как

да интерпретираме неговата битова последователност. За да

говорим за значението на байта от адрес 1032, ние трябва да

знаем типа на стойността, която е представена.

Абстракцията на типовете ни позволява да правим

смислена интерпретация на битова последователност с фиксирана

дължина. Символите, целите и реалните числа са примери за

ЇЇЇЇЇЇЇЇЇЇЇЇ

ЇЇЇЇЇЇЇЇЇЇЇЇ

16.
1024 0 0 0 1 1 0 1 1

1032 0 1 1 1 0 0 0 1

1040 0 1 1 0 0 1 0 0

1048 0 0 1 1 1 0 1 1

Фиг. 1.1 Адресуема машинна памет
типове данни. Други типове са адресите в паметта и машинните

инструкции, които управляват работата на компютъра.

С++ предлага един предварително дефиниран набор от

типове на данни, който позволява представянето на цели и

реални числа и на смостоятелни символи.
- Типът char може да бъде използуван за представяне на

единични символи или малки цели числа. Записва се в една

машинна дума.
- Типът int се използува за представяне на цели

стойности. Обикновено се записва в една машинна дума.


С++ предлага също short и long integer типове.

Фактическият размер на тези типове е машинно зависим. Типовете

char, short, int и long се наричат цели типове. Целите типове

могат да бъдат със или без знак (signed/unsigned). Разликата

се проявява в предназначението на най-левия бит на типа. Ако

типът има знак,най-левият бит се интерпретира като знаков бит,

а останалите битове представят стойността. Ако типът представя

беззнакова стойност, всички битове определят стойността. Ако

знаковият бит има съдържание 1, стойността се интерпретира

като отрицателна; ако е 0, като положителна. Един 8-битов

signed char може да представи стойностите от -128 до 127; а

unsigned char - от 0 до 255.

Типовете float и double представят реални числа с

единична и двойна точност.(ў) Обикновено типът float се

представя в една дума, а double - в две. Истинският размер е

машинно зависим. Изборът на типа данни се определя от размера

на стойностите, които трябва да бъдат записвани. Например, ако

стойностите никога не надхвърлят 255 и не са по-малки от 0,

тогава типът unsigned char е подходящ. Обаче, ако се очаква

стойностите да надхвърлят 255, е необходимо да се избере някой

от по-големите даннови типове.

ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ

(ў) Третият тип данни, представящ реални числа long double,

вероятно ще бъде добавен в близко бъдеще. Long double е

предложен за включване към стандарта на езика C ANSI.

ЇЇЇЇЇЇЇЇЇЇЇЇ


ЇЇЇЇЇЇЇЇЇЇЇЇ

17.
1.1. Константни стойности
Когато в дадена програма се появява стойност като 1,

например, тя се приема за литерална константа: литерална,

защото можем да говорим за нея само като за стойност,

константа, защото стойността й не може да бъде променяна.

Всеки литерал има съответен тип. 1, например е от тип

int. 3.14159 е литерална константа от тип double. Считаме

литералните константи за неадресуеми; въпреки, че тяхната

стойност е разположена някъде в паметта, достъпът до този

адрес не е съществен.

Целите литерални константи могат да бъдат написани в

десетичен, осмичен или шестнадесетичен вид. ( Това не променя

битовото представяне на стойността.) Стойността 20, например,

може да бъде записана по един от следните три начина:
20 // десетичен

024 // осмичен

0х14 // шестнадесетичен
Водещата нула за литерална константа от цял тип указва, че

константата е от осмичен тип. Представяне, използуващо 0х или

0Х в началото на константата, указва, че тя е в

шестнадесетичен запис. (Приложение А обсъжда отпечатването на

стойности в осмичен и шестнадесетичен запис).

Всяка цяла литерална константа може да бъде дефинирана

от тип long чрез записване на L или l след стойността й.

(Буквата L може да бъде главна или малка). Използуването на

малка буква l не се препоръчва, понеже лесно може да бъде

сбъркана с цифрата 1. По подобен начин цяла литерална

константа може да бъде дефинирана като unsigned чрез добавяне

на U или u след стойността й. Литерална константа от тип

unsigned long може също да се дефинира. Например,
128u 1024UL 1L 8Lu
Реалните литерални константи могат да бъдат записвани

чрез експонента или по обичайния начин. При първото

представяне експонентата може да бъде записана като се

използуват буквите Е или е. Реална литерална константа може да

бъде дефинирана и от тип float чрез записване на F или f след

стойността й. Ето няколко примера за реални литерални

константи:
3.14159F 0.1f 0.0

3e1 1.0E-3 2.


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

бъдат записани чрез заграждането на символа в единични

кавички. Например,
'a' '2' ',' ' ' (blank)
Непечатуемите символи, единичните или двойните кавички, както

и обърнатата наклонена черта могат да бъдат представени чрез

следните escape - последователности:

ЇЇЇЇЇЇЇЇЇЇЇЇ


ЇЇЇЇЇЇЇЇЇЇЇЇ

18.
newline \n

horizontal tab \t

vertical tab \v

backspace \b

carrige return \r

formfeed \f

alert (bell) \a

backslash \\

question mark \?

single quote \'

double quote \"
Може да бъде използувана и обобщена escape - последователност.

Тя изглежда така:


\ооо
където ооо представлява последователност от една, две или три

осмични цифри. Стойността, представена чрез осмичните цифри,

представлява числената стойност на символа в символния набор

на машината. Примерите, които следват, представляват литерални

константи, като се използува символния набор ASCII:
\7 (bell) \14 (newLine)

\0 (null) \062 ('2')


Всяка низова литерална константа представлява съвкупност от

нула или повече символа, обградени с двойни кавички.

Непечатуемите символи могат да бъдат представяни чрез техните

escape - последователности. Низов литерал може да заеме

няколко реда от текста на програмата. Обратната наклонена

черта като последен символ на реда указва, че низовият литерал

продължава на следващия ред. Следва пример за низови литерални

константи:


"" (null string)

"a"


"\nCC\toptions\tfile:[cC]\n"

"a multi-line \

string literal signal its \

continuation with a backslash"


Низовият литерал е от тип масив от символи. Той се състои от

низов литерал и ограничаващия символ null, добавен от

компилатора. Например, докато 'a' представя единичния символ

а, то "a" се записва като символа а, следван от символа null.

Символът null се използува за отбелязване на края на низа.

ЇЇЇЇЇЇЇЇЇЇЇЇ


ЇЇЇЇЇЇЇЇЇЇЇЇ

19.
1.2. Променливи
Представете си, че Ви е дадена задача да изчислите 2

на степен 10. Нашият първи опит би могъл да изглежда така:


#include
main()

{

// a first solution



cout << 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2;

cout << "\n";

return 0;

}
Написаното работи, въпреки че ще ни се наложи да преброим два

или три пъти дали сме записали константата 2 точно 10 пъти.

Само тогава ще бъдем доволни. Нашата програма правилно дава

отговор 1024.

Сега обаче, ни се налага да изчислим 2, повдигнато на

17 степен, а след това на 23. Неприятно е да променяме

програмата си всеки път. Още по-лошо, изглежда поразително

лесно да се направи грешка като се постави една двойка в

повече или по-малко. Обаче, понеже сме внимателни, ние

избягваме грешките.

Накрая ни се налага да направим таблица, която да

съдържа степените на двойката от 0 до 31. Ако използуваме

литерални константи в директни кодови последователности ще ни

бъдат нобходими 64 реда от следния вид:
cout << "2 raised to the power of X\t";

cout << 2 * ... * 2;


където Х ще се увеличава с единица за всяка кодова двойка.

В този момент, а може би и по-рано, ние осъзнаваме, че

трябва да има по-добър начин. Както и наистина има. Решението

изисква въвеждането на две понятия, които все още не са

формално дефинирани:
1. Променливи, които позволяват да се съхраняват и

възстановяват стойности.


2. Съвкупност от управляващи оператори, които

позволяват многократното изпълнение на част от програмния код.


Например, ето един втори начин за изчисляване на 2 на 10

степен:


ЇЇЇЇЇЇЇЇЇЇЇЇ

ЇЇЇЇЇЇЇЇЇЇЇЇ

20.
#include
main()

{

// a second more general solution



int value = 2;

int pow = 10;


cout << value

<< " raised to the power of "

<< pow << ": \t";
for ( int i = 1, res = 1; i <= pow; ++i )

{

res = res * value;



}
cout << res << "\n";

return 0;

}
Операторът, започващ с for, се нарича оператор за цикъл:

докато i е по-малко или равно на pow, се изпълнява тялото на

for, затворено във фигурни скоби. Цикълът for се нарича

поточно управляващ оператор. (Програмните орератори са описани

подробно в гл. 2).

value, pow, res и i са променливи, които позволяват да

се съхраняват, променят и възстановяват стойности. Те са тема

на следващите подглави. Първо, обаче, нека приложим друго ниво

на обобщанане на програмата като отделим част от програмата,

която изчислява степента на величината и да я дефинираме като

отделна функция.
unsigned int

pow ( int val, int exp )

{

//compute val raised to exp power



for ( unsigned int res = 1; exp > 0; --exp );

res = res * val;

return res;

}
Всяка задача, която изисква изчисляването на някаква степен на

дадена стойност, сега може просто да извика pow() с подходящо

множество от аргументи. Исканата таблица от степени на

двойката сега може да бъде получена по следния начин:

ЇЇЇЇЇЇЇЇЇЇЇЇ


ЇЇЇЇЇЇЇЇЇЇЇЇ

21.
#include
extern unsigned int pow ( int, int );

main()


{

int val = 2;

int exp = 16;
cout << "\mThe Power of 2\n";

for ( int i = 0; i <= exp; ++i )

cout << i << ": " << pow ( val, i ) << "\n";

return 0;

}
Таблица 1.1 представя резултата от изпълнението на тази

програма.


The Power of 2
0: 1

1: 2


2: 4

3: 8


4: 16

5: 32


6: 64

7: 128


8: 256

9: 512


10: 1024

11: 2048


12: 4096

13: 8192


14: 16384

15: 32768

16: 65536

Таблица 1.1 Степени на 2


Тази реализация на pow() не проверява онези особени

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

стойността - резултат е много голяма.
Упражнение 1-1. Какво ще стане ако pow() бъде извикана

с отрицателен втори аргумент? Как може да бъде променена pow()

за да обработва това?

ЇЇЇЇЇЇЇЇЇЇЇЇ


ЇЇЇЇЇЇЇЇЇЇЇЇ

22.
Упражнение 1-2. Всеки тип данни има долна и горна

граница за стойностите, които може да поддържа, определени от

броя на битовете, отделени за представянето му. Как това може

да се отрази на pow()? Как да бъде променена функцията pow()

за да обработва повиквания като pow( 2, 48 )?

Какво е променлива?


Всяка променлива се идентифицира от име, дефинирано

от потребителя. Тя има и съответен тип. Например, следващият

оператор дефинира променлива ch от тип char:
char ch;
char спецификатор на тип. short, int, long, float и double

също представят типови спецификации. Изобщо, всяка декларация

трябва да започва с типов спецификатор. Типовете на данните

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

и набора от операции, които могат да бъдат прилагани над този

тип данни. (За нашите предположения char ще има размер в

битове 8).

Както променливите, така и константите се съхраняват в

паметта и са свързани с определен тип. Разликата се състои в

това, че променливите са адресуеми. Т.е., има две стойности,

свързани с дадена променлива:
1. Нейната стойност, съхранена на някакво място в

паметта. Това поянкога се нарича нейна rvalue (произнася се

"are-value").
2. Стойността, определяща местоположението й; т.е.,

адреса в паметта, където е записана величината. Това понякога

се нарича нейна lvalue (произнася се "ell-value").
В израза
ch = ch - '0';
променливата ch се намира както от ляво така и отдясно на

оператора за присвояване. Написана от ляво, тя трябва да бъде

прочетена. Стойността й се извлича от местоположението й в

паметта. След това символният литерал се изважда от тази

стойност. Терминът rvalue произлиза от местоположението на

променливата в дясно на оператора за присвояване. Тя може да

бъде четена, но не и променяна. За нея може да се мисли като

за стойност за четене.

Написана от дясно, променливата ch ще бъде записвана.

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

стойност на ch върху предходната стойност. Терминът lvalue

произлиза от разположението на променливата от лявата страна

на оператора за присвояване. За нея може да се мисли като за

стойност на местоположение.

ЇЇЇЇЇЇЇЇЇЇЇЇ

ЇЇЇЇЇЇЇЇЇЇЇЇ

23.
ch се означава като обект. Всеки обект представя

някаква област от паметта. ch представя област от паметта с

размер 1 байт.

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

съхранена. Дефиницията определя името на променливата и нейния

тип. Съответно, би могла да бъде добавена и начална стойност

за променливата. Трябва да има една и само една дефиниция на

дадена променлива в програма.

Декларацията на променливата обявява, че променливата

съществува и е дефинирана някъде. Тя се състои от името на

променливата, типа й и ключовата дума extern. (За повече

информация, вж. раздел 3.9 (стр. 124) Програмен обхват).

Декларацията не е дефиниция. Тя не предизвиква заделяне на

място в памет. По-скоро тя едно твърдение, че дефиницията на

променливата съществува някъде в текста на програмата. Една

променлива може да бъде декларирана неколкократно в

програмата.

В С++ всяка променлива трябва да бъде дефинирана или

декларирана в програмата преди да може да бъде използувана.

Име на променлива


Името на променливата, т.е. нейният идентификатор,

може да бъде образувано от букви, цифри и подчертаващо

тиренце. Главните и малките букви са различими. Няма езиково

наложено ограничение върху разрешената дължина на името, тя е

различна за различните реализации.

В С++ има набор от думи, предназначени за използуване

от езика като ключови думи. Предварително дефинираните типови

спецификатори, например, са запазени думи. Идентификаторите,

които са ключови думи, не могат да бъдат използувани като

програмни идентификатори. Таблица 1.2 дава списък на

запазените ключови думи в С++.(ў)

Съществуват множество общоприети споразумения за

именуване на идентификатори, подпомагащи читаемостта на

програмата:


- Обикновено идентификаторът се записва с малки букви.
- Идентификаторът има мнемонично име; т.е., име, което

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


- Идентификаторите, които се състоят от няколко думи,

се записват или с разделящо подчертаващо тире или като се

използуват главни букви за всяка включена дума. Ннапример,

може да се напише is_empty или isEmpty, но не isempty.

ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ

(ў) Забележете, че template е предполагаема ключова дума за

възможно бъдещо разширение на С++ за поддържане на

параметризирани типове.

ЇЇЇЇЇЇЇЇЇЇЇЇ

ЇЇЇЇЇЇЇЇЇЇЇЇ

24.

asm delete if register template



auto do inline return try

break double int short typedef

case else long signed union

catch enum new sizeof unsigned

char extern operator static virtual

class float overload struct void

const for private switch volatile

continue friend protected this while

default goto public
Таблица 1.2 Ключови думи в С++

Дефиниции на променливи


Една проста дефиниция се състои от спецификатор на тип

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

Ето някои примери на прости дифиниции:
double salary;

double wage;

int month;

int day;


int year;

unsigned long distance;


Когато се дефинира повече от един идентификатор за

даден тип, списъкът от идентификатори, записан след

спецификатора на тип, се разделя чрез запетаи. Този списък

може да бъде разположен на няколко реда. Ограничава се от

точка и запетая. Например, предходните дефиниции могат да

бъдат записани по следния начин:


double salary, wage;

int month,

day, year;

unsigned long distance;


Всяка проста дефиниция определя типа и идентификатора

на променливата. Тя не дава начална стойност. За променлива,

която няма начална стойност, се казва че е неинициализирана.

Всяка неинициализирана променлива фактически има стойност; но

по-скоро може да се каже, че стойността й е недефинирана. Това

е така, понеже паметта, отделена за съхраняване на

променливата не е изтрита. Просто е останало това, което е

било записано в паметта при предходното използуване на тази

памет. Когато се чете една неинициализирана променлива

случайната битова последователност се интерпретира като нейна

стойност. Тази стойност ще се променя за различните изпълнения

на програмата. Следната премерна програма илюстрира случайния

характер на неинициализираните данни.

ЇЇЇЇЇЇЇЇЇЇЇЇ


ЇЇЇЇЇЇЇЇЇЇЇЇ

25.
#include
const iterations = 2;

void func()

{

// illustrate danger of uninitialized variables


int value1, value2; // uninitialized

static int depth = 0;


if ( depth < iterations )

{

++depth;



func();

}

else depth = 0;


cout << "\nvalue1:\t" << value1;

cout << "\nvalue2:\t" << value2;

cout << "\tsum:\t" << value1 + value2;

}
main()

{

for ( int i = 0; i < iterations; ++i )



func();

}
Когато тази програма бъде компилирана и изпълнена, се

получава следния по-скоро изненадващ изход (освен това, тези

резултати ще се променят при всяяко компилиране и изпълнение

на програмата):
value1: 0 value2: 74924 sum: 74924

value1: 0 value2: 68748 sum: 68748

value1: 0 value2: 68756 sum: 68756

value1: 148620 value2: 2350 sum: 150970

value1: 2147479844 value2: 671088640

sum: -1476398812

value1: 0 value2: 68756 sum: 68756
В тази програма iterations се използува като

константа. Това се отбелязва с ключовата дума const.

Константите се разглеждат в раздел 1.5 (стр. 36) на тази

глава. depth представлява локална статична променлива.

Значението на думата static се разяснява в раздел 3.10 (стр.

132) при обсъждането на обхвата. func() е описана като

рекурсивна функция. Раздел 3.1 (стр. 105) разглежда

рекурсивните функции.

В дефиницията на една прменлива може да й се даде

първоначална стойност. За променлива, на която е дадена

първоначална стойност в декларацията се казва, че е

инициализирана. Ето няколко примера за инициализиране на

променливи:

ЇЇЇЇЇЇЇЇЇЇЇЇ


ЇЇЇЇЇЇЇЇЇЇЇЇ

26.
#include
double price = 109.99, discount = 0.16,

salePrice = price * discount;


int val = getValue();

unsigned absVal = abs ( val );


Пледварително дефинираната функция abs(), намираща се в

библиотеката math, връща абсолютната стойност на аргумента си.

getValue() е функция, дефинирана от потребителя, която връща

случайно цяло число. Променливите могат да бъдат

инициализирани със произволни сложни изрази.

1.3. Указателни типове


Променливата указател съдържа стойност, която

представлява адрес на обект в паметта. Чрез указатела можем да

се обърнем към обекта непряко. Едно типично използуване на

указатели е за създаване на свързани списъци и управление на

обекти, адресирани по време на изпълнение на програмата.

Всеки указател се свързва с определен тип. Типът на

данните определя типа на обекта, който ще бъде адресиран чрез

указателя. Например, указател от тип int ще соче обект от тип

int. Съответно, за да сочи обект от тип double указателят

трябва да се дефинира от тип double.


Каталог: files -> tu files
tu files -> Увод в компютърната графика
tu files -> Xii. Защита и безопасност на ос
tu files -> Електрически апарати
tu files -> Средства за описание на синтаксиса
tu files -> Stratofortress
tu files -> Писане на скриптове за bash шел : версия 2
tu files -> 6Технологии на компютърната графика 1Модели на изображението
tu files -> Z=f(x), където x- входни данни; z
tu files -> Body name библиотека global Matrix imports (достъп по име) … var m[N, N] := … end decl., proc … resource f final code imports node, Matrix end name var x: node node; if x … Matrix m[3,4] :=: … end


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




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

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