ایران سرفراز- نرم افزار وپروژهای دانشجویی


نرم افزار وپروژهای دانشجویی

ادامه فصل اول ودوم مقدمات برنامه نویسی با ++C

<!-- /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:"Times New Roman";} @page Section1 {size:612.0pt 792.0pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:35.4pt; mso-footer-margin:35.4pt; mso-paper-source:0;} div.Section1 {page:Section1;} -->

C++ فصل اول ودوم / مقدمات برنامه نویسی با ادامه

9‐ برنامۀ زیر سن کاربر را از ورودی دریافت کرده و سپس آن مقدار را در خروجی چاپ

می کند اما خطوط این برنامه به هم ریخته است. آن را به ترتیب درست مرتب کنید:

int main()

{ // testing:

cout << "Your age is: " << age << " years." << endl;

cin >> age;

cout << "Enter your age: ";

int age;

return 0;

}

تمرین های برنامه نویسی

1‐ برنامه ای بنویسید که همۀ حروف الفبای انگلیسی را به ترتیب چاپ کند به طوری

که کنار هر حرف بزرگ، مشابه کوچک آن هم وجود داشته باشد.

6 مانند زیر چاپ کند. × را در ی ک بلوک 7 B 2‐ برنامه ای بنویسید که به وسیلۀ ستاره ها، حرف

*****

* *

* *

*****

* *

* *

*****

3‐ برنامه ای نوشته و اجرا کنید ک ه اولین حرف نام فامیل شما را به وسیلۀ ستاره ها در

7 چاپ کند. × یک بلوک 7

4‐ برنامه ای نوشته و اجرا کنید که نشان دهد چه اتفاقی می افتد اگر هر یک از ده

سویچ خروجی زیر چاپ شود:

\a , \b , \n , \r , \t , \v , \' , \" , \\ , \?

5‐ برنامه ای را نوشت ه و اجرا کنید ک ه مجموع ، تفاض ل، حاصل ضرب ، خارج قسمت و

باقیماندۀ دو عدد 60 و 7 را چاپ کند.

6‐ برنامه ای را نوشته و اجرا کنید که دو عدد صحیح از ورودی گرفته و مجموع ،

تفاضل ، حاصل ضرب ، خارج قسمت و باقیماندۀ آن دو عدد را چاپ کند.

 

فصل دوم

« انواع اصلی »

2 انواع دادۀ عددی – 1

ما در زندگی روزمره از داده های مختلفی استفاده می کنیم: اعداد ، تصاویر،

نوشته ها یا حروف الفبا، صداها، بوها و ... . با پردازش این داد هها می توانیم تصمیماتی

اتخاذ کنیم، عک سالعمل هایی نشان دهیم و مسال های را حل کنیم. رایانه ها نیز قرار است

همین کار را انجام دهند. یعنی داده هایی را بگیرند، آ نها را به شکلی که ما تعیین

می کنیم پردازش کنند و در نتیجه اطلاعات مورد نیازمان را استخراج کنند. اما رایانه ها

یک محدودیت مهم دارند: فقط اعداد را می توانند پردازش کنند. پس هر داده ای برای

این که قابل پردازش باشد باید تبدیل به عدد شود. ممکن است عجیب به نظر برسد که

مثلا صدا یا تصویر را چطور می توان به اعداد تبدیل کرد اما این کار واقعا در رایانه ها

« اعداد دودویی 1 » انجام می گیرد و هر نوع داد های به ترکیبی از صفرها و یک ها که

خوانده می شوند، تبدیل می گردد. سر و کار داشتن با اعدادی که فقط از صفرها و

یک های طولانی تشکیل شده اند بسیار گیج کننده و وقت گیر است. علاوه بر این مایلیم

که با داده های واقعی در برنامه ها کار کنیم. بنابراین در زبا نهای برنامه نویسی، این تبدیل

1 – Binary

26 برنامه سازی پیشرفته

داده ها به کامپایلر واگذار شده است و برنام هنویس با خیال راحت می تواند انواع واقعی

را که آن زبان در اختیار می گذارد به کار برد. وقتی برنامه کامپایل شد، این داد هها خود

به خود به اعداد دودویی تبدیل می شوند.

نوع ممیز شناور 2 » و « نوع صحیح 1 » : دو نوع اصلی داده وجود دارد C++ در

همۀ انواع دیگر از روی این دو ساخته می شوند (به شکل زیر دقت کنید).

نوع صحیح برای نگهداری

اعداد صحیح (اعداد 0 و 1 و 2 و

...) استفاده می شود. این اعداد بیشتر

برای شمارش به کار می روند و

دامنه محدودی دارند.

نوع ممیز شناور برای

نگهداری اعداد اعشاری استفاده

می شود. اعداد اعشاری بیشتر برای

اندازه گیری دقیق به کار می روند و

دامنۀ بزرگ تری دارند. یک عدد

187 را / اعشاری مثل 352

18/7352 یا × می توان به شکل 10

102 ‐ 1/87352 یا 1 ×

18735/2 و یا ... نوشت. به این ترتیب با کم و زیاد کردن ×10 ‐ 1873/52 یا 2 ×10

توان عدد 10 ممیز عدد نیز جابه جا می شود. به همین دلیل است که به اعداد اعشاری

می گویند. « اعداد ممیز شناور »

2 متغیر عدد صحیح – 2

شش نوع متغیر عدد صحیح دارد که در شکل آمده است. تفاوت این شش C++

نوع مربوط به میزان حافظۀ مورد استفاده و محدودۀ مقادیری است که هر کدام

انواع اصلی

انواع صحیح

boolean نوع

bool

نوع شمارشی

enum

نوع کاراکتری

char

unsigned char

wchar_t

نوع عددی صحیح

short

int

long

unsigned short

unsigned int

unsigned long

انواع ممیز شناور

float

double

long double

1 – Integer 2 – Floating point

فصل دوم / انواع اصلی 27

می توانند داشته باشند. این میزان حافظۀ مورد استفاده و محدودۀ مقادیر، بستگی زیادی

به سخت افزار و همچنین سیستم عامل دارد. یعنی ممکن است روی یک رایانه، نوع

دو بایت از حافظه را اشغال کند در int

حالی که روی رایانه ای از نوع دیگر نوع

به چهار بایت حافظه نیاز داشته int

<limits> باشد. با استفاده از سرفایل

می توان مشخص نمود که هر نوع عدد

صحیح روی رایانه تان چه محدوده ای دارد.

2 محدوده های نوع عدد صحیح – * مثال 1

را چاپ می کند: C++ این برنامه محدوده های شش نوع عدد صحیح در

#include <iostream>

#include <limits> //defines the constants SHRT_MIN, etc.

using namespace std;

int main()

{ //prints some of the constants stored in the <limits>

header:

cout << "minimum short = " << SHRT_MIN << endl;

cout << "maximum short = " << SHRT_MAX << endl;

cout << "minimum unsigned short = 0" << endl;

cout << "maximum unsigned short = " << USHRT_MAX << endl;

cout << "minimum int = " << INT_MIN << endl;

cout << "maximum int = " << INT_MAX << endl;

cout << "minimum unsigned int = 0" << endl;

cout << "maximum unsigned int = " << UINT_MAX << endl;

cout << "minimum long = " << LONG_MIN << endl;

cout << "maximum long = " << LONG_MAX << endl;

cout << "minimum unsigned long = 0" << endl;

cout << "maximum unsigned long = " << ULONG_MAX << endl;

return 0;

}

minimum short = -32768

maximum short = 32767

انواع اصلی

انواع صحیح

نوع عددی صحیح

short

int

long

unsigned short

unsigned int

unsigned long

28 برنامه سازی پیشرفته

minimum unsigned short = 0

maximum unsigned short = 65535

minimum int = -2147483648

maximum int = 2147483647

minimum unsigned int = 0

maximum unsigned int = 4294967295

minimum long = -2147483648

maximum long = 2147483647

minimum unsigned long = 0

maximum unsigned long = 4294967295

، SHRT_MAX ، SHRT_MIN حاوی تعریف شناسه های <limits> سرفایل

و سایر شناس ههایی است که در برنامۀ بالا استفاده شده است. این USHRT_MAX

شناسه ها گستره ای که نوع عدد صحیح مربوطه می تواند داشته باشد را نشان می دهند.

حداقل چه مقداری short نشان می دهد که متغیری از نوع SHRT_MIN مثلا شناسه

short بیان می کند که متغیری از نوع SHRT_MAX می تواند داشته باشد و شناسه

حداکثر چه مقداری می تواند داشته باشد. مثال بالا روی یک رایانه با پردازنده

با سیستم عامل ویندوز 98 اجرا شده است. خروجی این مثال نشان Pentium II

می دهد که شش نوع عدد صحیح در این رایانه محدوده های زیر را دارند:

short: - 32,767 تا 32,786 (28 ⇒ 1 byte)

int: - 2,147,483,647 تا 2,147,483,648 (232 ⇒ 4 bytes)

long: - 2,147,483,647 تا 2,147,483,648 (232 ⇒ 4 bytes)

unsigned short: 65,535 تا 0 (28 ⇒ 1 byte)

مانند long با دقت در این جدول مشخص می شود که در رایانۀ مذکور، نوع

است. unsigned int نیز مانند unsigned long است و نوع int نوع

گرچه ممکن است این انواع روی رایانه ای از نوع دیگر متفاوت باشد.

وقتی برنامه ای می نویسید، توجه داشته باشید که از نوع صحیح مناسب استفاده

کنید تا هم برنامه دچار خطا نشود و هم حافظۀ سیستم را هدر ندهید.

2 محاسبات اعداد صحیح – 3

اکنون که با انواع متغیرهای عدد صحیح آشنا شدیم، می خواهیم از این متغیرها در

مانند اغلب زبان های برنامه نویسی برای محاسبات C++ . محاسبات ریاضی استفاده کنیم

 

فصل دوم / انواع اصلی 29

از عملگرهای جمع (+) ، تفریق (-) ، ضرب (*) ، تقسیم (/) و باقیمانده (%) استفاده

می کند.

2 محاسبات اعداد صحیح – * مثال 2

برنامۀ زیر نحوۀ استفاده و عملکرد عملگرهای حسابی را نشان می دهد:

int main()

{ //tests operators +, -, *, /, and %:

int m=54;

int n=20;

cout << "m = " << m << " and n = " << n << endl;

cout << "m+n = " << m+n << endl; // 54+20 = 74

cout << "m-n = " << m-n << endl; // 54-20 = 34

cout << "m*n = " << m*n << endl; // 54*20 = 1080

cout << "m/n = " << m/n << endl; // 54/20 = 2

cout << "m%n = " << m%n << endl; // 54%20 = 14

return 0;

}

m = 54 and n = 20

m+n = 74

m-n = 34

m*n = 1080

m/n = 2

m%n = 14

جالب توجه است. حاصل این تقسیم برابر با 2 است نه 2.7 توجه m/n نتیجۀ تقسیم

به این مطلب بسیار مهم است. این امر نشان می دهد که حاصل تقسیم یک عدد صحیح

بر عدد صحیح دیگر، همواره یک عدد صحیح است نه عدد اعشاری. همچنین به

نیز دقت کنید. عملگر % باقیماندۀ تقسیم را به دست می دهد. یعنی حاصل m%n حاصل

54 برابر با 14 است که این مقدار، باقیماندۀ تقسیم 54 بر 20 است. % عبارت 20

2 عملگرهای افزایشی و کاهشی – 4

برای دستکاری مقدار متغیرهای صحیح، دو عملگر جالب دیگر دارد: C++

عملگر ++ مقدار یک متغیر را یک واحد افزایش می دهد و عملگر -– مقدار یک متغیر

30 برنامه سازی پیشرفته

را یک واحد کاهش می دهد. اما هر کدام از این عملگرها دو شکل متفاوت دارند:

پسوندی » و شکل « پیشوندی » شکل

در شکل . --n یا ++m در شکل پیشوندی، عملگر قبل از نام متغیر می آید مثل

تفاوت شکل پیشوندی با . n-- یا m++ پسوندی، عملگر بعد از نام متغیر می آید مثل

شکل پسوندی در این است که در شکل پیشوندی ابتدا متغیر، متناسب با عملگر،

افزایش یا کاهش می یابد و پس از آن مقدار متغیر برای محاسبات دیگر استفاده می شود

ولی در شکل پسوندی ابتدا مقدار متغیر در محاسبات به کار می رود و پس از آن مقدار

متغیر یک واحد افزایش یا کاهش می یابد. برای درک بهتر این موضوع به مثال بعدی

توجه کنید.

2 استفاده از عملگرهای پیش افزایشی و پس افزایشی – * مثال 3

int main()

{ //shows the difference between m++ and ++m:

int m, n;

m = 75;

n = ++m; // the pre-increment operator is applied to m

cout << "m = " << m << ", n = " << n << endl;

m = 75;

n = m++; // the post-increment operator is apllied to m

cout << "m = " << m << ", n = " << n << endl;

return 0;

}

m = 45, n = 45

m = 45, n = 44

در خط پنجم برنامه یعنی در عبارت

n = ++m;

به 76 افزایش می یابد و m از عملگر پیش افزایشی استفاده شده است. پس ابتدا مقدار

داده می شود. بنابراین وقتی در خط ششم مقدار این دو متغیر n سپس این مقدار به

خواهد بود. n = و 76 m = چاپ می شود، 76

 

فصل دوم / انواع اصلی 31

از عملگر پس افزایشی n = m++; در خط هشتم برنامه یعنی در عبارت

تخصیص می یابد و پس از n که 75 است به m استفاده شده است. بنا بر این ابتدا مقدار

به 76 افزایش داده می شود. پس وقتی در خط نهم برنامه مقدار این دو m آن مقدار

خواهد بود. n = است ولی 75 m = متغیر چاپ می شود، 76

فراوان به کار می روند. گاهی C++ عملگرهای افزایشی و کاهشی در برنامه های

به شکل پیشوندی و گاهی به شکل پسوندی؛ این بستگی به منطق برنامه دارد که کجا

از کدام نوع استفاده شود.

2 عملگرهای مقدارگذاری مرکب – 5

قبلا از عملگر = برای مقدارگذاری در متغیرها استفاده کردیم. مثلا دستور

m مقدار m = m+ قرار می دهد و همچنین دستور ; 8 m مقدار 75 را درون m=75;

عملگرهای دیگری دارد که مقدارگذاری در C++ . را هشت واحد افزایش می دهد

m متغیرها را تسهیل می نمایند. مثلا با استفاده از عملگر =+ می توانیم هشت واحد به

m += اضافه کنیم اما با دستور کوتا هتر: ; 8

است با این تفاوت که کوتا هتر است. به m = m + دستور بالا معادل دستور ; 8

می گویند زیرا ترکیبی از عملگرهای + و = می باشد. « عملگر مرکب » += عملگر

عبارتند از: =+ و =- و =* و =/ و =% C++ پنج عملگر مرکب در

نحوۀ عمل این عملگرها به شکل زیر است:

m += 8; → m = m + 8;

m -= 8; → m = m - 8;

m *= 8; → m = m * 8;

m /= 8; → m = m / 8;

m %= 8; → m = m % 8;

مثال زیر، کار این عملگرها را نشان می دهد.

2 کاربرد عملگرهای مرکب – * مثال 4

int main()

{ //tests arithmetic assignment operators:

 

32 برنامه سازی پیشرفته

int n=22;

cout << " n = " << n << endl;

n += 9; // adds 9 to n

cout << "After n += 9, n = " << n << endl;

n -= 5; //substracts 5 from n

cout << "After n -= 5, n = " << n << endl;

n *= 2; //multiplies n by 2

cout << "After n *= 2, n = " << n << endl;

n /= 3; //divides n by 3

cout << "After n /= 3, n = " << n << endl;

n %= 7; //reduces n to the remainder from dividing by 4

cout << "After n %= 7, n = " << n << endl;

return 0;

}

n = 22

After n += 9, n = 31

After n -= 5, n = 26

After n *= 2, n = 52

After n /= 3, n = 17

After n %= 7, n = 3

2 انواع ممیز شناور – 6

عدد ممیز شناور به بیان ساده همان عدد اعشاری است. عددی مثل 123.45

یک عدد اعشاری است. برای این که مقدار این عدد در رایانه ذخیره شود، ابتدا باید به

شکل دودویی تبدیل شود:

123.45 = 1111011.01110012

اکنون برای مشخص نمودن محل اعشار در عدد، تمام رقم ها را به سمت راست ممیز

منتقل می کنیم. البته با هر جابجایی ممیز، عدد حاصل باید در توانی از 2 ضرب شود:

123.45 = 0.11110110111001 × 27

نمای » ، و به 7 که توان روی دو است « مانتیس عدد » به مقدار 11110110111001

گفته می شود. از آن جا که ممیز می تواند به شکل شناور جابجا شود، به اعداد « عدد

اعشاری اعداد ممیز شناور می گویند. حال برای ذخیره سازی عدد مفروض کافی است

 

 

فصل دوم / انواع اصلی 33

که مانتیس و نما را ذخیره کنیم. هنگامی که بخواهیم این مقدار ذخیره شده را بازیابی

کنیم، سیستم عامل نما و مانتیس را در مسیری عکس مسیر بالا به کار می گیرد تا عدد

123.45 را از روی آن دوباره بسازد. در مورد عددی مثل عدد مذکور ممکن است

این روش ذخیره سازی، طولانی و بی مورد به نظر برسد. اما اعداد ممیز شناور شامل

اعداد خیلی کوچک مثل 0.000000001 یا اعداد خیلی بزرگ مثل

100000000.00000002 هستند که ذخیره سازی و انجام محاسبات ریاضی روی

آن ها با استفاده از مانتیس و نما بسیار آسان تر است.

و نوع double و نوع float سه نوع ممیز شناور وجود دارد: نوع C++ در

. long double

از چهار بایت برای نگهداری عدد استفاده می کند، نوع float معمولا نوع

از هشت یا ده یا دوازده یا شانزده long double از هشت بایت و نوع double

32 بیتی (چهار بایتی) از 23 بیت برای ذخیره سازی مانتیس float بایت. در یک

استفاده می شود و 8 بیت نیز برای ذخیره سازی نما به کار می رود و یک بیت نیز

علامت عدد را نگهداری می کند.

64 بیتی (هشت بایتی) از 52 بیت برای ذخیره سازی مانتیس double در یک

استفاده می شود و 11 بیت برای نگهداری نما به کار می رود و یک بیت نیز علامت

عدد را نشان می دهد.

2 تعریف متغیر ممیز شناور – 7

تعریف متغیر ممیز شناور مانند تعریف متغیر صحیح است. با این تفاوت که از

برای مشخص نمودن نوع متغیر استفاده می کنیم. double یا float کلمۀ کلیدی

را از نوع ممیز شناور تعریف می کند. دستور x متغیر float x; مثلا دستور

را از نوع ممیز شناور تعریف کرده و مقدار اولیۀ x متغیر float x=12.3;

را y و x دو متغیر double x,y= 12.3 را درون آن قرار می دهد. دستور ; 0

مقدار 0.0 y هنوز مشخص نیست ولی x تعریف می کند که مقدار double از نوع

دارد.

34 برنامه سازی پیشرفته

2 حساب ممیز شناور – * مثال 5

اعداد ممیز شناور را نیز مثل اعداد صحیح می توانیم در محاسبات به کار ببریم.

2 است با این تفاوت – مثال زیر این موضوع را نشان می دهد. این مثال مانند مثال 2

هستند: float که متغیرها از نوع ممیز شناور

int main()

{ //tests operators +, -, *, /, and %:

float x=54.0;

float y=20.0;

cout << "x = " << x << " and y = " << y << endl;

cout << "x+y = " << x+y << endl; // 54.0+20.0 = 74.0

cout << "x-y = " << x-y << endl; // 54.0-20.0 = 34.0

cout << "x*y = " << x*y << endl; // 54.0*20.0 = 1080.0

cout << "x/y = " << x/y << endl; // 54.0/20.0 = 2.7

return 0;

}

x = 54 and y = 20

x+y = 74

x-y = 34

x*y = 1080

x/y = 2.7

به پاسخ های بالا دقت کنید: بر خلاف تقسیم اعداد صحیح، تقسیم اعداد ممیز شناور به

54.0 / 20.0 = صورت بریده شده نیست: 2.7

دو برابر double در این است که نوع double با نوع float تفاوت نوع

float دقتی بسیار بیشتر از double از حافظه استفاده می کند. پس نوع float

است. float وقت گیرتر از محاسبات double دارد. به همین دلیل محاسبات

بنابراین اگر در برنام ههایتان به محاسبات و پاسخ های بسیار دقیق نیاز دارید، از نوع

استفاده کنید. ولی اگر سرعت اجرا برایتان اهمیت بیشتری دارد، نوع double

را به کار بگیرید. Float

 

فصل دوم / انواع اصلی 35

2 شکل علمی مقادیر ممیز شناور – 8

اعداد ممیز شناور به دو صورت در ورودی و خروجی نشان داده می شوند: به

علمی » و به شکل « ساده » شکل

1.234567 شکل × مقدار 12345.67 شکل ساده عدد است و مقدار 104

علمی همان عدد است. مشخص است که شکل علمی برای نشان دادن اعداد خیلی

کوچک و همچنین اعداد خیلی بزرگ، کارآیی بیشتری دارد:

-0.000000000123 = -1.23×10-10

123000000000 = 1.23×1011

یا e برای نشان دادن حالت علمی اعداد ممیز شناور از حرف انگلیسی C++ در

استفاده می کنیم: E

-1.23×10-10 = -1.23e-10

1.23×1011 = 1.23e11

هنگام وارد کردن مقادیر ممیز شناور، می توانیم از شکل ساده یا شکل علمی

استفاده کنیم. هنگام چاپ مقادیر ممیز شناور، معمولا مقادیر بین 0.1 تا 999.999 به

شکل ساده چاپ می شوند و سایر مقادیر به شکل علمی نشان داده می شوند.

2 شکل علمی اعداد ممیز شناور – * مثال 6

1) را /x) را از ورودی گرفته و معکوس آن (x) برنامۀ زیر یک عدد ممیز شناور

چاپ می کند:

int main()

{ // prints reciprocal value of x:

double x;

cout << "Enter float: "; cin >> x;

cout << "Its reciprocal is: " << 1/x << endl;

return 0;

}

Enter float: 234.567e89

Its reciprocal is: 4.26317e-92

 

 

36 برنامه سازی پیشرفته

دیدیم. این انواع برای محاسبات استفاده C++ تا این جا انواع عددی را در

انواع دیگری C++ می شوند و تقریبا در هر برنام های که می نویسید به کار می روند. اما

نیز دارد که کاربردهای دیگری دارند. نوع بولین که برای عملیات منطقی استفاده

می شود و نوع کاراکتری که برای به کار گرفتن کاراکترها تدارک دیده شده است و نوع

شمارشی که بیشتر برای مجموعه هایی که برنامه نویس تعریف می کند به کار می رود.

این انواع جدید گرچه کاربردشان با اعداد تفاوت دارد اما در حقیقت به شکل اعداد

صحیح در رایانه ذخیره و شناسایی می شوند. به همین دلیل این نوع ها را نیز

می شمارند. در ادامۀ این فصل به بررسی این C++ زیرمجموعه ای از انواع صحیح در

انواع می پردازیم.

bool 2 نوع بولین 1 – 9

یک نوع صحیح است که متغیرهای این نوع فقط می توانند مقدار bool نوع

به معنی نادرست false به معنی درست و true . داشته باشند false یا true

برای مقداردهی به این false یا true است. گرچه درون برنامه مجبوریم از عبارات

نوع متغیر استفاده کنیم، اما این مقادیر در اصل به صورت 1 و 0 درون رایانه ذخیره

مثال زیر این مطلب را نشان می دهد. .false و 0 برای true می شوند: 1 برای

bool 2 استفاده از متغیرهای نوع – * مثال 7

int main()

{ //prints the vlaue of a boolean variable:

bool flag=false;

cout << "flag = " << flag << endl;

flag = true;

cout << "flag = " << flag << endl;

return 0;

}

flag = 0

flag = 1

1 – Boolean

فصل دوم / انواع اصلی 37

تعریف شده و با bool از نوع falg در خط سوم از برنامۀ بالا متغیری به نام

مقداردهی اولیه شده است. در خط بعدی مقدار این متغیر در خروجی false مقدار

تغییر یافته است و دوباره مقدار متغیر true چاپ شده و در خط پنجم مقدار آن به

داده ایم اما در true و false مقدار flag چاپ شده است. گرچه به متغیر

خروجی به جای آن ها مقادیر 0 و 1 چاپ شده است.

char 2 نوع کاراکتری ‐ 10

یک کاراکتر یک حرف، رقم یا نشانه است که یک شمارۀ منحصر به فرد دارد. به

عبارت عامیانه، هر کلیدی که روی صفحه کلید خود می بینید یک کاراکتر را نشان

می دهد (البته به غیر از کلیدهای مالتی مدیا یا کلیدهای اینترنتی که اخیرا در

و 'z' تا 'a' و 'Z' تا 'A' صفحه کلید ها مرسوم شده اند). مثلا هر یک از حروف

هر یک از اعداد ' 0' تا ' 9' و یا نشانه های '~' تا '+' روی صفحه کلید را یک

کاراکتر می نامند. رایانه ها برای شناسایی کاراکترهای استاندارد از جدول اسکی استفاده

می کنند. با دقت در این جدول خواهید دید که هر کاراکتر یک شمارۀ منحصر به فرد

کد 65 دارد. کاراکترها در رایانه به شکل عددی شان ذخیره 'A' دارد. مثلا کاراکتر

به شکل عدد 'A' می شوند اما به شکل کاراکتری شان نشان داده می شوند. مثلا کاراکتر

در آن ذخیره شده را 'A' 65 ذخیره می شود اما اگر سعی کنیم متغیری که کاراکتر

را در خروجی می بینیم نه عدد 65 را. A چاپ کنیم، شکل

استفاده می کنیم. یک char برای تعریف متغیری از نوع کاراکتر از کلمه کلیدی

یک کاراکتر 'A' کاراکتر باید درون دو علامت آپستروف (') محصور شده باشد. پس

است؛ همچنین ' 8' یک کاراکتر است اما 8 یک کاراکتر نیست بلکه یک عدد صحیح

است.

مثال بعدی نحوۀ به کارگیری متغیرهای کاراکتری را نشان می دهد.

char 2 استفاده از متغیرهای نوع – * مثال 8

int main()

{ //prints the character and its internally stored integer value:

char c ='A';

 

38 برنامه سازی پیشرفته

cout << "c = " << c << ", int(c) = " << int(c) << endl;

c ='t';

cout << "c = " << c << ", int(c) = " << int(c) << endl;

c ='\t'; // the tab character

cout << "c = " << c << ", int(c) = " << int(c) << endl;

c ='!';

cout << "c = " << c << ", int(c) = " << int(c) << endl;

return 0;

}

c = A, int(c) = 65

c = t, int(c) = 116

c = , int(c) = 9

c = !, int(c) = 33

'A' تعریف شده و با مقدار char از نوع c در خط سوم از برنامۀ بالا متغیری به نام

چاپ شده که در c مقدارگذاری اولیه شده است. سپس در خط بعدی ابتدا مقدار

دیده می شود نه مقدار عددی آن. در ادامۀ خط چهارم، با استفاده از A خروجی همان

یعنی 65 در خروجی چاپ خواهد شد. در خطوط c مقدار عددی int(c) دستور

و معادل c اختصاص یافته و به همین ترتیب مقدار c بعدی کاراکترهای دیگری به

عددی آن چاپ شده است.

c = '\t'; : به خط هفتم برنامه نگاه کنید

را روی '\t' یک کاراکتر خاص است. اگر سعی کنیم کاراکتر '\t' کاراکتر

صفحه نمایش نشان دهیم، هفت جای خالی روی صفحه دیده می شود(به خروجی دقت

کنید). غیر از این کاراکتر، کاراکترهای خاص دیگری نیز هستند که کارهایی مشابه این

که در فصل قبل دیدیم و مکا ننما را به سطر بعدی '\n' انجام می دهند. مثل کاراکتر

منتقل می کند. این کاراکترها برای شکل دهی صفحه نمایش و کنترل آن استفاده می شوند.

کاراکترهای خاص در جدول اسکی بین شمار ههای 0 تا 32 قرار گرفت هاند. سعی کنید

مثل برنامۀ بالا یک برنامۀ آزمایشی بنویسید و با استفاده از آن مقادیر کاراکترهای خاص

را چاپ کنید تا ببینید چه اتفاقی می افتد. لابه لای برنامه های بعدی از این کاراکترهای

خاص استفاده خواهیم کرد تا با آ نها بهتر آشنا شوید.

فصل دوم / انواع اصلی 39

enum 2 نوع شمارشی – 11

انواع جدیدی که C++ علاوه بر انواعی که تا کنون بررسی کردیم، می توان در

کاربر نیاز دارد نیز ایجاد نمود. برای این کار راه های مختلفی وجود دارد که بهترین و

قوی ترین راه، استفاده از کلا سها است(فصل ده)، اما راه ساده تری نیز وجود دارد و آن

است. enum استفاده از نوع شمارشی

یک نوع شمارشی یک نوع صحیح است که توسط کاربر مشخص می شود. نحو

تعریف یک نوع شمارشی به شکل زیر است:

enum typename{enumerator-list}

نام نوع جدید است که کاربر مشخص typename ، کلمه ای کلیدی است enum که

مجموعه مقادیری است که این نوع جدید می تواند enumerator-list می کند و

داشته باشد. به عنوان مثال به تعریف زیر دقت کنید:

enum Day{SAT,SUN,MON,TUE,WED,THU,FRI}

یک نوع جدید است و متغیرهایی که از این نوع تعریف می شوند می توانند Day حالا

را داشته باشند: FRI و THU و WED و TUE و MON و SUN و SAT یکی از مقادیر

Day day1,day2;

day1 = MON;

day2 = THU;

و محدودۀ مقادیرش را تعیین کردیم، می توانیم متغیرهایی Day وقتی نوع جدید

تعریف Day از نوع day و 2 day از این نوع جدید بسازیم. در کد بالا متغیرهای 1

مقداردهی شده است. THU با مقدار day و 2 MON با مقدار day شده اند. آنگاه 1

و ... هر چند که به همین شکل به کار می روند اما در SUN و SAT مقادیر

رایانه به شکل اعداد صحیح 0 و 1 و 2 و ... ذخیره می شوند. به همین دلیل است که

و ... یک شمارشگر 1 می گویند. وقتی فهرست SUN و SAT به هر یک از مقادیر

شمارشگرهای یک نوع تعریف شد، به طور خودکار مقادیر 0 و 1 و 2 و ... به ترتیب

1 – Enumerator

40 برنامه سازی پیشرفته

به آ نها اختصاص می یابد. هرچند که می توان این ترتیب را شکست و مقادیر صحیح

دلخواهی را به شمارشگرها نسبت داد:

enum Day{SAT=1,SUN=2,MON=4,TUE=8,WED=16,THU=32,FRI=64}

اگر فقط بعضی از شمارشگرها مقداردهی شوند، آنگاه سایر شمارشگرها که

مقداردهی نشده اند مقادیر متوالی بعدی را خواهند گرفت:

enum Day{SAT=1,SUN,MON,TUE,WED,THU,FRI}

دستور بالا مقادیر 1 تا 7 را به ترتیب به روزهای هفته تخصیص خواهد داد.

همچنین دو یا چند شمارشگر در یک فهرست می توانند مقادیر یکسانی داشته باشند:

enum Answer{NO=0,FALSE=0,YES=1,TRUE=1,OK=1}

YES دارای مقدار یکسان 0 و شمارشگرهای FALSE و NO در کد بالا دو شمارشگر

نیز دارای مقدار یکسان 1 هستند. پس کد زیر معتبر است و به درستی OK و TRUE و

کار می کند:

Answer answer;

cin >> answer;

if (answer==TRUE) cout << "you said OK.";

به اولین خط کد فوق نگاه کنید. این خط ممکن است کمی عجیب به نظر برسد:

Answer answer;

تعریف می کند. اولین قانون در Answer از نوع answer این خط متغیری به نام

بین حروف کوچک و بزرگ تفاوت قایل C++» : را به خاطر بیاورید C++ برنامه های

را در خ طهای قبلی یک Answer . متفاوت است answer با Answer پس .« است

است. یعنی Answer را متغیری که از نوع answer نوع شمارشی تعریف کردیم و

یا FALSE یا OK یا TRUE یا YES متغیری است که می تواند یکی از مقادیر answer

را داشته باشد. نحوۀ انتخاب نام ها آزاد است اما بیشتر برنام هنویسان از توافق زیر در NO

برنامه هایشان استفاده می کنند:

فصل دوم / انواع اصلی 41

1 – برای نام ثابت ها از حروف بزرگ استفاده کنید

2 – اولین حرف از نام نوع شمارشی را با حرف بزرگ بنویسید.

3 – در هر جای دیگر از حروف کوچک استفاده کنید.

رعایت این توافق به خوانایی برنامه تان کمک می کند. همچنین سبب می شود که انواع

char و float و int شمارشی که کاربر تعریف می کند از انواع استاندارد مثل

راحت تر تمیز داده شود.

شمارشگرها قواعد خاصی دارند. نام شمارشگر باید معتبر باشد. یعنی کلمۀ

کلیدی نباشد، با عدد شروع نشود و نشانه های ریاضی نیز نداشته باشد. پس تعریف زیر

غیرمعتبر است:

enum Score{A+,A,A-,B+,B,B-,C+,C,C-}

نام های غیرمعتبری هستند چون در نام آن ها از C- و C+ و B- و B+ و A- و A+ زیرا

نشانه های ریاضی استفاده شده.

علاوه بر این شمارشگرهای هم نام نباید در محدود ههای مشترک استفاده شوند.

برای مثال تعریف های زیر را در نظر بگیرید:

enum Score{A,B,C,D}

enum Group{AB,B,BC}

Group و Score در هر دو تعریف B دو تعریف بالا غیرمجاز است زیرا شمارشگر

آمده است.

آخر این که نام شمارشگرها نباید به عنوان نام متغیرهای دیگر در جاهای دیگر

برنامه استفاده شود. مثلا:

enum Score{A,B,C,D}

float B;

char c;

را نباید به عنوان نام متغیرهای دیگر به کار برد زیرا این نام ها C و B در تعریف های بالا

به کار رفته است. پس اگر این سه تعریف در یک محدوده Score در نوع شمارشی

 

42 برنامه سازی پیشرفته

خود » باشند، دو تعریف آخری غیرمجاز خواهد بود. انواع شمارشی برای تولید کد

به کار می روند، یعنی کدی که به راحتی درک شود و نیاز به توضیحات اضافی « مستند

نداشته باشد. مثلا تعاریف زیر خودمستند هستند زیرا به راحتی نام و نوع کاربرد و

محدودۀ مقادیرشان درک می شود:

enum Color{RED,GREEN,BLUE,BLACK,ORANGE}

enum Time{SECOND,MINUTE,HOUR}

enum Date{DAY,MONTH,YEAR}

enum Language{C,DELPHI,JAVA,PERL}

enum Gender{MALE,FEMALE}

2 تبدیل نوع، گسترش نوع – 12

در قسمت های قبلی با انواع عددی آشنا شدیم و نحوۀ اعمال ریاضی آن ها را

مشاهده نمودیم اما در محاسبات ریاضی که انجام دادیم همۀ متغیرها از یک نوع بودند.

اگر بخواهیم در یک محاسبه دو یا چند متغیر از انواع مختلف به کار ببریم چه اتفاقی

می افتد؟

قانون کلی این است که در محاسباتی که چند نوع متغیر وجود دارد، جواب

همیشه به شکل متغیری است که دقت بالاتری دارد. یعنی اگر یک عدد صحیح را با

یک عدد ممیز شناور جمع ببندیم، پاسخ به شکل ممیز شناور است. به این منظور ابتدا

متغیرها و مقادیری که از نوع با دقت کمتر هستند به نوع با دقت بیشتر تبدیل می شوند

و سپس محاسبه روی آن ها انجام می شود. پس اگر یک عدد صحیح را با یک عدد ممیز

شناور جمع ببندیم، ابتدا عدد صحیح تبدیل به یک عدد ممیز شناور می شود، سپس این

عدد با عدد ممیز شناور دیگر جمع بسته می شود و واضح است که پاسخ نیز به شکل

در چنین C++ ممیز شناور خواهد بود. این کار به شکل خودکار انجام می گیرد و

محاسباتی به شکل خودکار متغیرهای با دقت کمتر را به متغیرهایی با دقت بیشتر تبدیل

می کند تا همه متغیرها از یک نوع شوند و آنگاه محاسبه را انجام می دهد و پاسخ را نیز

به شکل نوع با دقت بیشتر به دست می دهد. به این عمل گسترش نوع می گویند.

فصل دوم / انواع اصلی 43

اما اگر عکس این عمل مورد نظر باشد، یعنی اگر بخواهیم یک متغیر صحیح را با

یک متغیر ممیز شناور جمع ببندیم و بخواهیم که حاصل از نوع صحیح باشد نه ممیز

شناور، چه باید بکنیم؟ در چنین حالتی از عملگر تبدیل نوع استفاده می کنیم. این تبدیل

خودکار نیست بلکه کاملا باید دستی انجام شود و برنام هنویس، خود باید مراقب این

عمل باشد. برای این که مقدار یک متغیر از نوع ممیز شناور را به نوع صحیح تبدیل

استفاده می کنیم. int() کنیم از عبارت

مثال های زیر تبدیل نوع و گسترش نوع را نشان می دهند.

2 تبدیل نوع – * مثال 9

تبدیل می کند: int را به نوع double این برنامه، یک نوع

int main()

{ // casts a double value as an int:

double v=1234.987;

int n;

n = int(v);

cout << "v = " << v << ", n = " << n << endl;

return 0;

}

v = 1234.987, n = 1234

و با مقدار 1234.987 تعریف شده است. double از نوع v در این برنامه متغیر

تعریف گشته است. در خط پنجم از کد بالا از تبدیل نوع int از نوع n همچنین متغیر

استفاده شده:

n = int(v);

تبدیل می شود و سپس این int ابتدا به نوع v با استفاده از این دستور، مقدار

int() قرار می گیرد. خروجی برنامه نشان می دهد که وقتی از عملگر n مقدار درون

می شود، گرد نمی شود. یعنی قسمت اعشاری « بریده » استفاده کنیم، عدد ممیز شناور

عدد به طور کامل حذف می شود و فقط قسمت صحیح آن باقی می ماند. بنابراین وقتی

44 برنامه سازی پیشرفته

تبدیل شود، حاصل برابر با 1234 خواهد بود و int عدد 1234.987 به نوع

قسمت اعشاری آن (هر قدر هم بزرگ باشد) نادیده گرفته می شود.

در تبدیل نوع همواره نوع و مقدار متغیرهای تبدیل شده بدون تغییر می ماند. در

نیز v تا پایان برنامه به همان مقدار 1234.987 باقی مانده و نوع v برنامۀ بالا مقدار

مانده است. تنها اتفاقی که افتاده این است که double تغییر نکرده و همچنان از نوع

قرار گیرد. n شده تا این مقدار درون int در یک محل موقتی تبدیل به v مقدار

2 گسترش نوع – * مثال 10

برنامۀ زیر یک عدد صحیح را با یک عدد ممیز شناور جمع می کند:

int main()

{ // adds an int value with a double value:

int n = 22;

double p = 3.1415;

p += n;

cout << "p = " << p << ", n = " << n << endl;

return 0;

}

p = 24.1415, n = 22

از مقدار صحیح 22 به مقدار اعشاری 22.0 گسترش n در برنامۀ بالا ابتدا مقدار

جمع می شود. حاصل یک عدد ممیز شناور p می یابد و سپس این مقدار با مقدار قبلی

است.

2 گسترش نوع – * مثال 11

گسترش می دهد: double و float ، int را به char این برنامه، یک

int main()

{ //prints promoted values of 65 from char to double:

char c='A'; cout << " char c = " << c << endl;

short k=c; cout << " short k = " << k << endl;

int m=k; cout << " int m = " << m << endl;

long n=m; cout << " long n = " << n << endl;

float x=n; cout << " float x = " << x << endl;

فصل دوم / انواع اصلی 45

double y=x; cout << " double y = " << y << endl;

return 0;

}

char c = A

short k = 65

int m = 65

long n = 65

float x = 65

double y = 65

در آن قرار گرفته 'A' تعریف شده و کاراکتر char از نوع c در مثال بالا ابتدا متغیر

k است قرار گرفته. چون نوع short که از نوع k درون متغیر c است. سپس مقدار

گسترش می یابد و مقدار 65 که short به نوع c است، پس مقدار c بالاتر از نوع

قرار می گیرد. k است درون 'A' معادل عددی کاراکتر

است که نوع int از نوع m . قرار می گیرد m درون متغیر k در خط بعدی، مقدار

گسترش می یابد و این مقدار int به k می باشد. پس مقدار short بالاتری از

نهاده می شود. m گسترش یافته درون

گسترش یافته و درون long به نوع m به همین ترتیب در خطوط بعدی مقدار

قرار می گیرد. x گسترش یافته و درون float نیز به نوع n قرار می گیرد. مقدار n

قرار می گیرد. دقت کنید که y گسترش می یابد و درون double نیز به نوع x مقدار

در خروجی به جای آن که 65.0 باشد به شکل 65 نشان داده شده. این y و x مقدار

مقدار، یک عدد صحیح نیست اما چون قسمت اعشاری آن صفر است، اعشار حذف

شده و 65 تنها نشان داده شده است.

2 برخی از خطاهای برنامه نویسی – 13

را شناختیم، می توانیم از این انواع در برنام ههای C++ اکنون که انواع متغیر در

مفیدتر و جدی تر استفاده کنیم. اما باید دقت نمود که اگر از متغیرها به شکل نادرست

یا کنترل نشده استفاده کنیم، برنامه دچار خطا می شود. البته عوامل دیگری نیز هست که

باعث می شود اجرای برنامه مختل گردد، مثل استفاده از متغیری که تعریف نشده یا جا

انداختن سمیکولن انتهای دستورها. این قبیل خطاها که اغلب خطاهای نحوی هستند و

 

 

46 برنامه سازی پیشرفته

نامیده می شوند و به راحتی « خطای زمان کامپایل » توسط کامپایلر کشف می شوند

می توان آن ها را رفع نمود. اما خطاهای دیگری نیز وجود دارند که کشف آن ها به

خطای » راحتی ممکن نیست و کامپایلر نیز چیزی راجع به آن نمی داند. به این خطاها

می گویند. برخی از خطاهای زمان اجرا سبب می شوند که برنامه به طور « زمان اجرا

کامل متوقف شود و از کار بیفتد. در چنین حالتی متوجه می شویم که خطایی رخ داده

است و در صدد کشف و رفع آن برمی آییم. برخی دیگر از خطاهای زمان اجرا، برنامه

را از کار نمی اندازند بلکه برنامه همچنان کار می کند اما پاسخ های عجیب و نادرست

می دهد. این بدترین نوع خطاست زیرا در حالات خاصی رخ می دهد و گاهی سبب

گیج شدن برنام هنویس می گردد. در بخ شهای بعدی برخی از خطاهای رایج زمان اجرا

را نشان می دهیم تا در برنامه هایتان از آن ها پرهیز کنید؛ دست کم اگر با پاس خهای

غیرمنتظره و غلط مواجه شدید، محل رخ دادن خطا را راح تتر پیدا کنید.

2 سرریزی 1 عددی – 14

محدودۀ وسیعی از اعداد را double یا نوع ممیز شناور long نوع صحیح

باشد، double یا long می توانند نگهداری کنند. به بیان ساد هتر، متغیری که از نوع

گنجایش زیادی دارد. اما حافظۀ رایانه ها متناهی است. یعنی هر قدر هم که یک متغیر

گنجایش داشته باشد، بالاخره مقداری هست که از گنجایش آن متغیر بیشتر باشد. اگر

سعی کنیم در یک متغیر مقداری قرار دهیم که از گنجایش آن متغیر فراتر باشد، متغیر

می شود. مثل یک لیوان آب که اگر بیش از گنجایش آن در لیوان آب بریزیم، « سرریز »

سرریز می شود. در چنین حالتی می گوییم که خطای سرریزی رخ داده است.

2 سرریزی عدد صحیح – * مثال 12

را در 1000 ضرب می کند تا سرانجام سرریز شود: n این برنامه به طور مکرر

int main()

{ //prints n until it overflows:

int n =1000;

cout << "n = " << n << endl;

1 – Overflow

فصل دوم / انواع اصلی 47

n *= 1000; // multiplies n by 1000

cout << "n = " << n << endl;

n *= 1000; // multiplies n by 1000

cout << " n = " << n << endl;

n *= 1000; // multiplies n by 1000

cout << " n = " << n << endl;

return 0;

}

n = 1000

n = 1000000

n = 1000000000

n = -727379968

این مثال نشان می دهد رایانه ای که این برنامه را اجرا کرد ه است ، نمی تواند بیشتر

از 1,000,000,000 را با 1000 به طور صحیح ضرب کند.

2 سرریزی عدد ممیز شناور – * مثال 13

را به توان x این برنامه شبیه چیز ی است که در مثال قبل ذکر شد؛ به طور مکرر

می رساند تا ای ن که سرریز شود.

int main()

{ //prints x until it overflows:

float x=1000.0;

cout << "x = " << x << endl;

x *= x; //multiplies n by itself; i.e., it squares x

cout << "x = " << x << endl;

x *= x; //multiplies n by itself; i.e., it squares x

cout << "x = " << x << endl;

x *= x; //multiplies n by itself; i.e., it squares x

cout << "x = " << x << endl;

x *= x; //multiplies n by itself; i.e., it squares x

cout << "x = " << x << endl;

return 0;

}

x = 1000

x = 1e+06

x = 1e+1248 برنامه سازی پیشرفته

x = 1e+24

x = inf

را با شروع از 1000 بیش از سه بار x مثال بالا نشان می دهد که این رایانه نمی تواند

نمادی است که به معنای بی نهایت می باشد inf مجذور کند. آخرین خروجی یعنی

به معنای بی انتها است). infinity (این نماد مخفف

به تفاوت سرریزی عدد صحیح و سرریزی ممیز شناور توجه کنید. وقتی یک

می شود اما « گردانیده » عدد صحیح سرریز شود، عدد سرریز شده به یک مقدار منفی

به معنای بی نهایت را به دست inf وقتی یک عدد ممیز شناور سرریز شود، نماد

می دهد، نشانه ای مختصر و مفید.

2 خطای گرد کردن 1 – 15

خطای گرد کردن نوع دیگری از خطاس ت که اغلب وقتی رایانه ها روی اعداد

1 ممکن است به صورت / حقیقی محاسبه می کنند، رخ می دهد. برای مثال عدد 3

1 نیست . به این اختلاف، خطای گرد / 0.333333 ذخیره شود که دقیقا معاد ل 3

1 مقدار دقیق / کرد ن می گویند. این خطا از آن جا ناشی می شود که اعدادی مثل 3

ندارند و رایانه نمی تواند این مقدار را پیدا کند، پس نزدیک ترین عدد قابل محاسبه را

به جای چنین اعدادی منظور می کند. در بعض ی حالات ، این خطاها می تواند مشکلات

حادی را ایجاد کند.

2 خطای گرد کردن – * مثال 14

این برنامه محاسبات ساده ای را انجام می دهد تا خطای گرد کردن را نشان دهد:

int main()

{ //illustrates round-off error:

double x = 1000/3.0;

cout << "x = " << x << endl; // x = 1000/3

double y = x-333.0;

cout << "y = " << y << endl; // y = 1/3

double z = 3*y-1.0;

1 – Round-offفصل دوم / انواع اصلی 49

cout << "z = " << z << endl; // z = 3(1/3) - 1

if (z == 0) cout << "z == 0.\n";

else cout << "z does not equal 0.\n"; //z != 0

return 0;

}

x = 333.333

y = 0.333333

z = -5.68434e-14

z does not equal 0.

1000 یعنی 3 / برابر با 3 x منطق برنامه به این شکل است که ابتدا مقدار

3331 است.

1 است / یعنی 333 از آن کسر می شود و حاصل که برابر با 3 x سپس قسمت صحیح

در 3 ضرب می شود تا حاصل برابر با 1 شود. این مقدار از y قرار می گیرد. حالا y در

صفر باشد اما پاسخ z قرار می گیرد. انتظار این است که z 1 کم می شود و حاصل در

صفر نیست! z برنامه به ما می گوید که

اشکال برنامۀ بالا در کجاست؟ منطق برنامه که درست است، پس جایی در

1 را برابر با / است. رایانه مقدار 3 y محاسبات باید غلط باشد. مشکل در مقدار

1/ 0.333333 محاسبه نموده است، حال آن که می دانیم این مقدار دقیقا برابر با 3

1 را پیدا کند / نیست. این خطا از آن جا ناشی می شود که رایانه نمی تواند مقدار دقیق 3

چون این مقدار به تعداد نامتناهی اعشار 3 دارد، پس رایانه این مقدار را گرد می کند و

0.333333 را می دهد. این مقدار در محاسبات بعدی استفاده « نسبتا درست » مقدار

می شود اما چون دقیق نیست، پاسخ های بعدی نیز به تناسب بر میزان خطا می افزاید.

صفر نمی شود، هرچند که بسیار نزدیک به صفر باشد. z نتیجه این است که مقدار

مثال بالا نکتۀ مهمی را در استفاده از متغیر های ممیز شناور نشان می دهد:

زیرا در متغیرهای ممیز « هیچ گاه از متغیر ممیز شناور برای مقایسه برابری استفاده نکنید »

شناور خطای گرد کردن سبب می شود که پاسخ با آن چه مورد نظر شماست متفاوت

بسیار نزدیک صفر است، اما رایانه همین مقدار z باشد. در حالت بالا گر چه مقدار

کوچک را صفر نمی داند. پس مقایسۀ برابری شکست می خورد.

50 برنامه سازی پیشرفته

2 خطای گرد کردن پنهان – * مثال 15

برنامۀ زیر با استفاده از رابطۀ معادلات درجه دوم، ریشه های این معادله ها را پیدا

می کند:

#include <cmath> //defines the sqrt() function

#include <iostream>

using namespace std;

int main()

{ //implements the quadratic formula

float a, b, c;

cout << "Enter the coefficients of a quadratic equation:"

<< endl;

cout << "\ta: ";

cin >> a;

cout << "\tb: ";

cin >> b;

cout << "\tc: ";

cin >> c;

cout << "The equation is: " << a << "*x*x + " << b

<< "*x + " << c << " = 0" << endl;

float d = b*b - 4*a*c; // discriminant

float sqrtd = sqrt(d);

float x1 = (-b + sqrtd /(2*a);

float x2 = (-b - sqrtd /(2*a);

cout << "The solutions are:" << endl;

cout << "\tx1 = " << x1 << endl;

cout << "\tx2 = " << x2 << endl;

cout << "check:" << endl;

cout << "\ta+x1*x1 + b*x1 + c = " << a*x1*x1 + b*x1 + c

<< endl;

cout << "\ta+x2*x2 + b*x2 + c = " << a*x2*x2 + b*x2 + c

<< endl;

return 0;

}

 

فصل دوم / انواع اصلی 51

می گیرد و سپس ax2 + bx + c = را برای معادلۀ 0 c و b و a این برنامه ضرایب

از نوع c و b و a را پیدا کند. برای این کار سه متغیر x و 2 x سعی می کند ریشه های 1

تعریف شده اند تا بتوانند مقادیر اعشاری را هم از ورودی بگیرند. خط هشتم float

را دریافت می کنند (دقت کنید که از کاراکتر c و b و a تا سیزدهم از برنامۀ بالا مقادیر

در پیغام های خروجی استفاده شده تا قبل از هر ورودی، هفت جای '\t' خاص

چاپ نمی شود). پس از دریافت ضرایب، یک بار t خالی قرار بگیرد. ولی خود حرف

دیگر شکل کلی معادله ای که مورد نظر کاربر بوده است چاپ می شود.

تشکیل شده است. این مقدار درون b2 − 4ac در خط یازدهم، رابطۀ دلتا یعنی

است، قرار گرفته. در خط بعدی مقدار float نام دارد و از نوع d متغیر دیگری که

جذر عددی sqrt() محاسبه شده است. تابع sqrt() جذر دلتا با استفاده از تابع

<cmath> که درون پرانتزهایش قرار می گیرد را به دست می دهد. این تابع در سرفایل

به ابتدای برنامه #include<cmath> تعریف شده. پس راهنمای پیش پردازندة

نگهداری شده تا sqrtd افزوده شده است. مقدار جذر دلتا درون متغیر دیگری به نام

به دست آید. x و 2 x با استفاده از آن در خطوط بعدی مقادیر 1

که بدست آمده است دوباره در x و 2 x در چهار خط آخر برنامه، مقادیر 1

معادله جای گذاری می شود تا بررسی شود که آیا جواب معادله صفر می شود یا خیر. به

تحقیق می شود. x و 2 x این وسیله صحت پاسخ های 1

2 را حل کرده است: x2 +1x − 3 = خروجی زیر نشان می دهد که برنامه، معادلۀ 0

Enter the coeficients of a quadratic equation:

a: 2

b: 1

c: -3

The equation is: 2*x*x + 1*x + -3 = 0

The solutions are:

x1 = 1

x2 = -1.5

check:

a*x1*x1 + b*x1 + c = 0

a*x2*x2 + b*x2 + c = 0

 

 

 

 

52 برنامه سازی پیشرفته

را پیدا کرده است و آزمون پاسخ نیز x2=- و 1.5 x1= می بینید که برنامه پاس خهای 1

جواب صفر داده است. خروجی دیگری از برنامه نشان می دهد که برنامه تلاش کرده

2 را حل کند ولی شکست می خورد: x2 + 8.001x + 8.002 = معادله 0

Enter the coeficients of a quadratic equation:

a: 2

b: 8.001

c: 8.002

The equation is: 2*x*x + 8.001*x + 8.002 = 0

The solutions are:

x1 = -1.9995

x2 = -2.00098

check:

a*x1*x1 + b*x1 + c = 5.35749e-11

a*x2*x2 + b*x2 + c = -2.96609e-1

که در اجرای بالا به دست آمده، در آزمون شرکت کرده و پاسخی بسیار x مقدار 1

در آزمون شکست خورده زیرا جواب معادله x نزدیک به صفر داده است. اما مقدار 2

به ازای آن صفر نیست. چه چیزی باعث شده تا معادله پاسخ غلط بدهد؟ جواب باز هم

یک پاسخ گردشده است نه یک پاسخ دقیق. این پاسخ x در خطای گرد کردن است. 2

گردشده دوباره در یک محاسبه دیگر شرکت می کند. پاسخ این محاسبه هم گردشده

است. پس انحراف از جواب افزایش می یابد و نتیجه ای دور از انتظار به بار می آورد.

2 انواع دیگری از خطاهای زمان اجرا – * مثال 16

دوباره به برنامۀ محاسبۀ ریشه ها برگردیم. به اجرای زیر نگاه کنید:

Enter the coeficients of a quadratic equation:

a: 1

b: 2

c: 3

The equation is: 1*x*x + 2*x + 3 = 0

The solutions are:

x1 = nan

x2 = nan

check:

a*x1*x1 + b*x1 + c = nan

a*x2*x2 + b*x2 + c = nan

 

فصل دوم / انواع اصلی 53

1 حل شود. این معادله جواب حقیقی x2 + 2x + 3 = در این اجرا سعی شده تا معادله 0

تلاش می کند جذر sqrt() ندارد زیرا دلتا منفی است. وقتی برنامه اجرا شود، تابع

داده nan یک عدد منفی را بگیرد ولی موفق نمی شود. در این حالت پاسخ

است یعنی پاسخ عددی نیست). not a number مخفف عبارت nan) می شود

را خواهد nan سپس هر محاسبۀ دیگری که از این مقدار استفاده کند، همین پاسخ

آمده است. nan داشت. به همین دلیل در همۀ خروجی ها پاسخ

سرانجام به اجرای زیر دقت نمایید:

Enter the coeficients of a quadratic equation:

a: 0

b: 2

c: 5

The equation is: 0*x*x + 2*x + 5 = 0

The solutions are:

x1 = nan

x2 = -inf

check:

a*x1*x1 + b*x1 + c = nan

0 حل شود. این معادله دارای x2 + 2x + 5 = در این اجرا کوشش شده تا معادلۀ 0

است اما برنامه نمی تواند این جواب را بیابد و با پاس خهای عجیبی x= جواب 2.5

صفر است و در حین اجرای برنامه، سعی می شود a روبرو می شویم. علت این است که

عددی بر صفر تقسیم شود. یعنی برنامه معادلۀ زیر را حل می کند:

0

0

0

2 2

2(0)

(2) (2) 4(0)(5)

2

2 4 2

1 =

− +

=

− + −

=

− + −

=

a

x b b ac

داریم: x بدست می آید. همچنین برای 2 nan در چنین حالتی دوباره پاسخ

0

4

0

2 2

2(0)

(2) (2) 4(0)(5)

2

2 4 2

2

=

− −

=

− − −

=

− − −

=

a

x b b ac

یعنی بی نهایت منفی است. –inf پاسخ این تقسیم، عبارت

 

54 برنامه سازی پیشرفته

ثابت های عددی هستند. یعنی می توانید این –inf و inf و nan سه نشانۀ

مقادیر را در محاسبات به کار ببرید اما نتیجه معمولا بی فایده است. مثلا می توانید

خواهد بود. inf جمع کنید یا از آن تفریق نمایید اما نتیجه باز هم inf عددی را با

2 حوزۀ متغیرها – 16

متغیرها بخش مهمی از هر برنامه هستند. استفاده از متغیرهایی با نوع نامناسب

سبب هدر رفتن حافظه و کاهش سرعت و افزایش خطاهای زمان اجرا می شود. انتخاب

نام های نامفهوم یا ناقص سبب کاهش خوانایی برنامه و افزایش خطاهای برنامه نویسی

حوزه 1 » . می شود. استفاده از متغیرها در حوزۀ نامناسب هم سبب بروز خطاهایی می شود

محدوده ای است که یک متغیر خاص اجازه دارد در آن محدوده به کار رود یا « متغیر

فراخوانی شود.

واژه مناسبی است که می توان به وسیلۀ آن حوزۀ C++ در « بلوک 2 » اصطلاح

متغیر را مشخص نمود. یک بلوک برنامه، قسمتی از برنامه است که درون یک جفت

علامت کروشه { } محدود شده است. در برنامه هایی که تاکنون دیدیم از بلوک

یک کروشه باز } گذاشته ایم int main() استفاده کرده ایم. همیشه بعد از عبارت

و در پایان برنامه یک کروشه بسته { قرار دادیم. پس تمام برنام ههایی که تا کنون ذکر

شد، یک بلوک داشته. به طور کلی می توان گفت که حوزۀ یک متغیر از محل اعلان آن

شروع می شود و تا پایان همان بلوک ادامه می یابد. خارج از آن بلوک نمی توان به متغیر

دسترسی داشت. همچنین قبل از این که متغیر اعلان شود نمی توان آن را استفاده نمود.

مثال زیر را بررسی کنید.

2 حوزۀ متغیرها – * مثال 17

برنامۀ زیر خطادار است:

int main()

{ //illustrates the scope of variables:

x = 11; // ERROR: this is not in the scope of x

int x;

 

فصل دوم / انواع اصلی 55

{

x = 22; // OK: this is in the scope of x

y = 33; // ERROR: this is not in the scope of y

int y;

x = 44; // OK: this is in the scope of x

y = 55; // OK: this is in the scope of y

}

x = 66; // OK: this is in the scope of x

y = 77; // ERROR: this is not in the scope of y

return 0;

}

شروع int main() برنامۀ بالا دو بلوک تودرتو دارد. اولین بلوک بعد از عبارت

می شود و در خط آخر برنامه بسته می شود. بلوک داخلی نیز از خط پنجم آغاز می شود

و در خط دهم پایان می یابد. نحوۀ تورفتگی خطوط برنامه به درک و تشخیص شروع و

پایان بلوک ها کمک می کند. خط پنجم تا دهم تورفتگی بیشتری دارد، یعنی این خطوط

تشکیل یک بلوک می دهند. همچنین خط دهم به بعد تورفتگی به اندازۀ خط سوم و

چهارم دارد، یعنی مجموعه این خطوط هم در یک حوزۀ مشترک قرار دارند.

در خط چهارم اعلان شده است. پس x اولین خطا در خط سوم رخ داده. متغیر

x از خط چهارم به بعد شروع می شود، در حالی که در خط سوم متغیر x حوزۀ

است. x فراخوانی شده و این خارج از محدودۀ

در خط هفتم اعلان شده. y دومین خطا در خط ششم اتفاق افتاده است. متغیر

فراخوانی شده و y از خط هفتم به بعد است، در حالی که در خط ششم y پس حوزۀ

است. y این خارج از محدودۀ

در y است. گرچه y سومین خطا که در خط دوازدهم روی داده نیز مربوط به

خطوط قبلی تعریف شده اما این تعریف در یک بلوک داخلی بوده است. این بلوک

داخلی در خط دهم به پایان رسیده است. پس تمام تعاریفی که در این بلوک وجود

1 – Scope 2 – Block

56 برنامه سازی پیشرفته

فقط از خط هفتم تا خط دهم y داشته نیز فقط تا خط دهم اعتبار دارد. یعنی حوزۀ

است، آن را به کار برد. y است. لذا نمی توان در خط دوازدهم که خارج از محدوده

مثال بالا مطلب ظریفی را بیان می کند: می توانیم در یک برنامه، چند متغیر

متفاوت با یک نام داشته باشیم به شرطی که در حوزه های مشترک نباشند. آخرین برنامۀ

فصل اول این موضوع را به خوبی نشان می دهد.

2 متغیرهای تودرتو – * مثال 18

int x = 11; // this x is global

int main()

{ //illustrates the nested and parallel scopes:

int x = 22;

{ //begin scope of internal block

int x = 33;

cout << "In block inside main() : x = " << x << endl;

} //end scope of internal block

cout << "In main() : x = " << x << endl;

cout << "In main() : ::x = " << ::x << endl;

return 0;

} //end scope of main()

In block inside main() : x = 33

In main() : x = 22

In main() : ::x = 11

که مقدار 11 دارد یک x وجود دارد. اولین x در برنامۀ بالا سه شیء متفاوت با نام

متغیر سراسری است زیرا داخل هیچ بلوکی قرار ندارد. پس حوزۀ آن سراسر برنامه

با مقدار 22 main() درون بلوک x است. دومین ( main() (حتی خارج از بلوک

قبلی x حوزه x است. این main() تعریف شده است. پس حوزۀ آن تا پایان بلوک

اول مخفی x دوم دیده می شود و x فقط main() را کور می کند. یعنی درون بلوک

دوم را خواهیم دید. x ارجاع کنیم فقط x می شود. پس اگر درون این بلوک به

فقط تا پایان x در یک بلوک داخلی تعریف شده است. حوزه این x سومین

قبلی را کور می کند. پس اگر درون این بلوک x حوزۀ هر دو x همان بلوک است. این

 

فصل دوم / انواع اصلی 57

x ، سوم را خواهیم دید. وقتی از این بلوک خارج شویم x را فراخوانی کنیم فقط x

main() قبلی آزاد می شود و دوباره می توان به مقدار آن دسترسی داشت. اگر از بلوک

اول آزاد خواهد شد. برنامه را از اول دنبال کنید و خروجی را x ، نیز خارج شویم

معتبر بوده است. در خط دهم از عملگر :: x بررسی نمایید تا متوجه شوید که کدام

می گویند. این عملگر را در فص لهای « جداسازی حوزه » استفاده شده. به آن عملگر

بعدی بررسی می کنیم. در این جا فقط می گوییم با عملگر جداسازی حوزه می توان به

که x یعنی متغیر ::x یک شی که خارج از حوزۀ فعلی است دسترسی پیدا کنیم. پس

در حوزۀ بیرونی است.

می بینید که تعریف چند متغیر در یک برنامه با نام یکسان به شیوۀ بالا ممکن و

مجاز است. اما سعی کنید از این کار اجتناب کنید زیرا در غیر این صورت همیشه

مجبورید به خاطر بسپارید که الان داخل کدام حوزه هستید و کدام متغیر مورد نظر

شماست. این طوری راحت ترید؟ اختیار با شماست!

58 برنامه سازی پیشرفته

پرسش های گزینه ای

1 – از میان انواع زیر، کدام یک نوع صحیح حساب نمی شود؟

bool ( د char ( ج int ( ب double ( الف

m/n باشد، آنگاه حاصل n= و 4 m= باشند و 6 short هر دو از نوع n و m 2 – اگر

برابر است با:

nan ( الف ) 1 ب ) 1.5 ج ) 2 د

باشد، حاصل n= و 4 m= باشد و 6.0 int از نوع n و double از نوع m 3 – اگر

چقدر است؟ m/n

nan ( الف ) 1 ب ) 1.5 ج ) 2 د

است. اگر بخواهیم حاصل short از نوع n و متغیر float از نوع m 4 – متغیر

باید از نوع ................. باشد. k نگهداریم، آنگاه k را در متغیری به نام m*n

long ( ب short ( الف

int ( د float ( ج

برابر با 7 z برابر با 5 و مقدار اولیۀ y اگر مقدار اولیۀ z += ++y 5 – در عبارت

پس از اجرای آن دستور عبارت است از: z باشد،حاصل

الف ) 12 ب ) 6 ج ) 5 د ) 13

1.23 معادل کدام یک از اعداد زیر است؟ e- 6 – عدد 1

- الف ) 12.3 ب ) 12.3 - ج ) 0.123 د ) 1.23

برابر int(a) با مقدار 5.63 باشد، آنگاه حاصل float متغیری از نوع a 7 – اگر

است با:

الف ) 5 ب ) 6 ج ) 0.63 د ) 5.6

از نوع صحیح باشد باید: m/n 8 – برای این که حاصل

از نوع صحیح باشد n ( از نوع صحیح باشد ب m ( الف

از نوع صحیح باشد n و هم m از نوع صحیح باشد د ) هم n و یا m ج ) یا

9 – برای تعریف انواع شمارشی از چه کلمۀ کلیدی استفاده می شود؟

const ( د sqrt ( ج enum ( ب include ( الف

 

فصل دوم / انواع اصلی 59

که از نوع کاراکتری است بگذاریم از ch را درون متغیر M 10 – اگر بخواهیم کاراکتر

چه دستوری استفاده می کنیم؟

ch = "M"; ( ب ch = M; ( الف

ch M ( د ch = 'M'; ( ج

است؟ C++ 11 – خطای گرد کردن مربوط به کدام نوع در

الف ) نوع ممیز شناور ب ) نوع صحیح

ج ) نوع کاراکتری د ) نوع شمارشی

سرریز شود، چه مقداری در آن قرار می گیرد؟ int 12 – اگر یک متغیر از نوع

د ) عدد صحیح منفی nan ( ج inf ( ب –inf ( الف

60 برنامه سازی پیشرفته

پرسش های تشریحی

برابر 2 است. بعد از n برابر 5 و مقدار m 1‐ قبل از اجرای دستورات زیر، مقدار

چیست؟ n و m اجرای هر یک از دستورات زیر مقدار جدید

a. m *= n++;

b. m += --n;

2‐ مقدار هر یک از عبارات زیر را پس از مقداردهی برآورد کنید. ابتدا فرض کنید که

برابر 7 است. n برابر 25 و m

a. m - 8 - n

b. m = n = 3

c. m%n

d. m%n++

e. m%++n

f. ++m - n‐‐

3‐ دو دستور زیر چه تفاوتی با هم دارند؟

char ch = 'A';

char ch = 65;

4‐ برای پیدا کردن کاراکتری که کد اسکی آن 100 است، چه کدی را م یتوانید اجرا

کنید؟

چیست و چرا به این نام نامیده م یشود؟ « ممیز شناور » 5‐ معنای

6‐ سرریزی عددی چیست؟

7‐ فرق سرریزی عدد صحیح با سرریزی عدد ممیز شناور چیست؟

8‐ خطای زمان اجرا چیست؟ مثال هایی برای دو نوع متفاوت از خطاهای زمان اجرا بنویسید.

9‐ خطای زمان کامپایل چیست؟ مثال هایی برای دو نوع متفاوت از خطاهای زمان

کامپایل بنویسید.

10 ‐ کد زیر چه اشتباهی دارد؟

enum Semester {FALL, SPRING, SUMMER};

enum Season {SPRING, SUMMER, FALL, WINTER};

11 ‐ کد زیر چه اشتباهی دارد؟

فصل دوم / انواع اصلی 61

enum Friends {"Jerry", "Henry", "W.D"};

تمرین های برنامه نویسی

کم کند. n بنویسید که 1 را از متغیر عدد صحیح C++ 1‐ چهار دستور متفاوت

بنویسید که مشابه جملۀ زیر عمل کند بدون این که از عملگر C++ 2‐ یک بلوک کد

++ استفاده کنید.

n = 100 + m++;

بنویسید که مشابه جملۀ زیر عمل کند بدون این که از عملگر C++ 3‐ یک بلوک کد

++ استفاده کنید.

n = 100 + ++m;

را y کم کند و سپس z را از y و x تکی بنویسید که مجموع C++ 4‐ یک دستور

افزایش دهد.

را کاهش بدهد و سپس آن را به n تکی بنویسید که متغیر C++ 5‐ یک دستور

اضافه کند. total

شود. short 7‐ برنامه ای را نوشته و اجرا کنید که موجب خطای پاریزی متغیری از نوع

2 نوشته و اجرا کنید که تنها کد اسکی ده حرف صدادار ‐ 8‐ برنامه ای مانند مثال 8

استفاده کنید) « الف » بزرگ و کوچک را چاپ می کند.(برای بررسی خروجی، از ضمیمۀ

float به جای double 2 را طوری تغییر دهید که از نوع ‐ 9‐ برنامۀ مثال 15

استفاده کند. سپس مشاهده کنید که این برنامه چطور با ورود یهایی که خطای زمان

اجرا را نشان م یدهند، بهتر اجرا می شود.

10 ‐ برنامه ای بنویسید که اینچ را به سانتیمتر تبدیل کند. برای مثا ل اگر کاربر 16.9

42.946 چاپ شود.(یک cm را برای یک طول بر حسب اینچ وارد کند، خروجی

اینچ برابر 2.54 سانتیمتر است)

 

62 برنامه سازی پیشرفته

mohsen_mahyar@yahoo.com

   + MOHSEN GHASEMI - ۱٢:٠٦ ‎ق.ظ ; ۱۳۸٩/٥/۱٧