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


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

فصل پنجم توابع در ++ 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;} -->

mohsen_mahyar@yahoo.com

فصل پنجم

  C++ در « توابع »

5 مقدمه 1

برنامه های واقعی و تجاری بسیار بزرگ تر از برنامه هایی هستند که تاکنون بررسی

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

نامیده می شوند. توابع را « تابع » به زیربرنامه هایی بخش بندی می کنند. این زیربرنامه ها

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

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

استاندارد C++ 5 توابع کتابخانه ای ‐2

مجموعه ای است که شامل توابع از پیش تعریف . این توابع و عناصر از طریق

تعریف <climits> که در INT_MAX قبلا برخی از آن ها را استفاده کرده ایم : ثابت

2)، تابع ‐ تعریف شده (مثال 15 <cmath> که در sqrt() 2)، تابع ‐ شده (مثال 1

که در time() 4) و تابع ‐ تعریف شده (مثال 22 <cstdlib> که در rand()

 

 

 

فصل پنجم / توابع 131

4). اولین مثال این بخش، استفاده از یک تابع ‐ تعریف شده (مثال 24 <ctime>

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

sqrt() 5 تابع جذر ‐ * مثال 1

ریشۀ دوم یک عدد مثب ت، جذر آن عدد است. ریشۀ دوم 9، عدد 3 است .

می توانیم تابع جذر را به شکل یک جعبۀ سیاه تصور کنیم که وقتی عدد 9 درون آن

قرار گیرد، عدد 3 از آن خارج می شود و وقتی عدد 2 در آن قرار گیرد، عدد

1/41421 از آن خارج می شود. تابع مانند یک برنامۀ کامل، دارای روند ورودی

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

1 حاصل می شود. تنها چیزی / تابع روی عدد 2 چه اعمالی انجام می دهد که 41421

1 جذر است و مجذور آن، عدد / که لازم است بدانیم این است که عدد 41421

ورودی 2 بوده است.

برنامۀ سادۀ زیر، تابع از پیش تعریف شدۀ جذر را به کار می گیرد:

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

#include <iostream> // defines the cout object

using namespace std;

int main()

{ //tests the sqrt() function:

for (int x=0; x < 6; x++)

cout << "\t" << x << "\t" << sqrt(x) << endl;

}

0 0

1 1

2 1.41421

3 1.73205

4 2

5 2.23607

این برنامه، ریشۀ دوم اعداد صفر تا پنج را چاپ م یکند. هر وقت اجرای برنامه به

اجرا می گردد. گرچه کد اصلی تابع مذکور sqrt() می رسد، تابع sqrt(x) عبارت

پنهان شده اما می توانیم مطمئن باشیم که به جای عبارت C++ درون کتابخانۀ

در اولین #include <cmath> قرار می گیرد. به دستور x مقدار جذر sqrt(x)

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

را sqrt() خط برنامه توجه کنید. کامپایلر به این خط نیاز دارد تا بتواند تعریف تابع

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

وجود دارد.

کافی است نام آن تابع به صورت یک sqrt() برای اجرای یک تابع مانند تابع

متغیر در دستورالعمل مورد نظر استفاده شود، مانند زیر:

y=sqrt(x).

sqrt(x) گفته می شود. بنابراین وقتی کد « احضار تابع » یا « فراخوانی تابع 1 » این کار

یا « آرگومان 2 » درون پرانتز x فراخوانی می گردد. عبارت sqrt() اجرا شود، تابع

توسط x فراخوانی نامیده م یشود. در چنین حالتی می گوییم که « پارامتر واقعی »

تابع sqrt(x) است، با اجرای کد x= 3 به تابع فرستاده می شود. لذا وقتی 3 « مقدار »

فراخوانی شده و مقدار 3 به آن فرستاده می شود. تابع مذکور نیز حاصل sqrt()

1.73205 را به عنوان پاسخ

برمی گرداند. این فرایند در نمودار

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

تعریف main() در تابع y و

که برابر با 3 x شده اند. مقدار

فرستاده sqrt() است به تابع

برمی گرداند. جعبه ای که تابع main() می شود و این تابع مقدار 1.73205 را به تابع

را نشان می دهد به رنگ تیره است، به این معنا که فرایند داخلی و نحوۀ کار sqrt()

آن قابل رویت نیست.

5 آزمایش یک رابطۀ مثلثاتی ‐ * مثال 2

استفاده می کند. هدف این است که صحت <cmath> این برنامه هم از سرفایل

به شکل تجربی بررسی شود. Sin2x=2SinxCosx رابطۀ

int main()

{ // tests the identity sin 2x = 2 sin x cos x:

for (float x=0; x < 2; x += 0.2)

cout << x << "\t\t" << sin(2*x) << "\t"

3

1.73205

x

y

int

double

3

1.73205

main() sqrt()

1 – Function call 2 – Argument 3 – Pass by value

 

فصل پنجم / توابع 133

<< 2*sin(x)*cos(x) << endl;

}

0 0 0

0.2 0.389418 0.389418

0.4 0.717356 0.717356

0.6 0.932039 0.932039

0.8 0.999574 0.999574

1 0.909297 0.909297

1.2 0.675463 0.675463

1.4 0.334988 0.334988

1.6 -0.0583744 -0.0583744

1.8 -0.442521 -0.442521

را در ستون دوم و مقدار Sin2x را در ستون اول، مقدار x برنامۀ بالا مقدار

2 را در ستون سوم چاپ می کند. خروجی نشان می دهد که برای هر SinxCosx

2 برابر است. البته این نتایج به SinxCosx با مقدار Sin2x مقدار ،x مقدار آزمایشی

طور کلی اثبات نمی کند که رابطۀ مذکور صحیح است اما به طور تجربی نشان می دهد

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

به درستی کار کند و خطای گردکردن رخ ندهد. x += امر سبب می شود که کد 0.2

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

یعنی می توانیم بنویسیم:

y = sqrt(2);

cout << 2*sin(x)*cos(x);

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

y = sqrt(1 + 2*sqrt(3 + 4*sqrt(5)))

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

تعریف شده است. بعضی از این توابع در جدول زیر نشان داده شده: <cmath>

<cmath> بعضی از توابع تعریف شده در سرفایل

تابع شرح مثال

مقدار 1.36944 را برمی گرداند acos( به رادیان) ( 0.2 ) x کسینوس معکوس acos(x)

مقدار 0.201358 را برمی گرداند asin( به رادیان) ( 0.2 ) x سینوس معکوس asin(x)

مقدار 0.197396 را برمی گرداند atan( به رادیان) ( 0.2 ) x تانژانت معکوس atan(x)

 

 

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

مقدار 4.0 را برمی گرداند ceil( گرد شده) ( 3.141593 ) x مقدار سقف ceil(x)

مقدار 0.416147 - را برمی گرداند cos( به رادیان) ( 2 ) x کسینوس cos(x)

مقدار 7.38906 را برمی گرداند exp(2) (e در پایه ) x تابع نمایی exp(x)

مقدار 2.0 را برمی گرداند fabs(-2) x قدر مطلق fabs(x)

مقدار 3.0 را برمی گرداند floor( گرد شده) ( 3.141593 ) x مقدار کف floor(x)

مقدار 0.693147 را برمی گرداند log(2) (e در پایه ) x لگاریتم طبیعی log(x)

مقدار 0.30103 را برمی گرداند log10(2) ( در پایه 10 ) x لگاریتم عمومی log10(x)

مقدار 8.0 را برمی گرداند pow(2,3) p به توان x pow(x,p)

مقدار 0.909297 را برمی گرداند sin( به رادیان) ( 2 ) x سینوس sin(x)

مقدار 1.41421 را برمی گرداند sqrt(2) x جذر sqrt(x)

مقدار 2.18504 - را برمی گرداند tan( به رادیان) ( 2 ) x تانژانت tan(x)

را double توجه داشته باشید که هر تابع ریاضی یک مقدار از نوع

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

ارتقا می دهد. double پردازش کند، مقدارش را به نوع

استاندارد که کاربرد بیشتری دارند در C++ بعضی از سرفای لهای کتابخانۀ

جدول زیر آمده است:

استاندارد C++ بعضی از سرفایل های کتابخانۀ

استاندارد گرفته شده اند. استفاده از آن ها شبیه C این سرفایل ها از کتابخانۀ

است. برای مثال اگر ( <iostream> استاندارد (مانند C++ استفاده از سرفایل های

سرفایل شرح

را تعریف می کند <assert> تابع <assert>

توابعی را برای بررسی کاراکترها تعریف می کند <ctype>

ثابت های مربوط به اعداد ممیز شناور را تعریف می کند <cfloat>

محدودۀ اعداد صحیح را روی سیستم موجود تعریف می کند <climits>

توابع ریاضی را تعریف می کند <cmath>

توابعی را برای ورودی و خروجی استاندارد تعریف می کند <cstdio>

توابع کاربردی را تعریف می کند <cstdlib>

توابعی را برای پردازش رشت هها تعریف می کند <cstring>

توابع تاریخ و ساعت را تعریف می کند <ctime>

 

 

فصل پنجم / توابع 135

به کار ببریم، باید <cstdlib> را از سرفایل rand() بخواهیم تابع اعداد تصادفی

دستور پیش پردازندۀ زیر را به ابتدای فایل برنامۀ اصلی اضافه کنیم:

#include <cstdlib>

5 توابع ساخت کاربر ‐3

استاندارد وجود دارد ولی این توابع C++ گرچه توابع بسیار متنوعی در کتابخانۀ

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

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

cube() 5 تابع ‐ * مثال 3

یک مثال ساده از توابع ساخت کاربر:

int cube(int x)

{ // returns cube of x:

return x*x*x;

}

این تابع، مکعب یک عدد صحیح ارسالی به آن را برم یگرداند. بنابراین فراخوانی

مقدار 8 را برمی گرداند. cube(2)

یک تابع ساخت کاربر دو قسمت دارد: عنوان و بدنه. عنوان یک تابع به صورت

زیر است:

( فهرست پارامترها) نام نوع بازگشتی

می باشد cube است. نام آن int ، که در بالا تعریف شد cube() نوع بازگشتی تابع

int یک مقدار از نوع cube() دارد. یعنی تابع x به نام int و یک پارامتر از نوع

تحویل می دهد. پس عنوان تابع فوق عبارت است از: int می گیرد و پاسخی از نوع

int cube(int x)

بدنۀ تابع، یک بلوک کد است که در ادامۀ عنوان آن م یآید. بدنه شامل دستوراتی

return است که باید انجام شود تا نتیجۀ مورد نظر به دست آید. بدنه شامل دستور

 

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

عبارت cube است که پاسخ نهایی را به مکان فراخوانی تابع برمی گرداند. بدنۀ تابع

است از:

{ // returns cube of x:

return x*x*x;

}

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

معمولا بدنۀ بزرگ تری دارند اما عنوان تابع اغلب روی یک سطر جا می شود.

دو وظیفۀ عمده دارد. اول این که اجرای تابع را خاتمه return دستور

return می دهد و دوم این که مقدار نهایی را به برنامۀ فراخوان باز می گرداند. دستور

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

return expression;

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

تخصیص داد. نوع آن عبارت باید با نوع بازگشتی تابع یکی باشد.

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

main است. نام آن int را تعریف می کند. نوع بازگشتی این تابع از نوع « تابع اصلی »

است و فهرست پارامترهای آن خالی است؛ یعنی هیچ پارامتری ندارد.

5 برنامۀ آزمون ‐4

وقتی یک تابع مورد نیاز را ایجاد کردید، فورا باید آن تابع را با یک برنامۀ ساده

امتحان کنید. چنین برنام های برنامۀ آزمون 1 نامیده می شود. تنها هدف این برنامه، امتحان

کردن تابع و بررسی صحت کار آن است. برنامۀ آزمون یک برنامۀ موقتی است که باید

باشد؛ یعنی لازم نیست در آن تمام ظراف تهای برنامه نویسی – مثل « سریع و کثیف »

پیغام های خروجی، برچسب ها و راهنماهای خوانا – را لحاظ کنید. وقتی با استفاده از

برنامۀ آزمون، تابع را آزمایش کردید دیگر به آن احتیاجی نیست و می توانید برنامۀ

آزمون را دور بریزید.

1 – Testing program

 

فصل پنجم / توابع 137

cube() 5 یک برنامۀ آزمون برای تابع ‐ * مثال 4

و برنامۀ آزمون آن است: cube() کد زیر شامل تابع

int cube(int x)

{ // returns cube of x:

return x*x*x;

}

int main()

{ // tests the cube() function:

int n=1;

while (n != 0)

{ cin >> n;

cout << "\tcube(" << n << ") = " << cube(n) << endl;

}

}

5

cube(5) = 125

-6

cube(-6) = -216

0

cube(0) = 0

برنامۀ بالا اعداد صحیح را از ورودی می گیرد و مکعب آن ها را چاپ م یکند تا این که

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

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

در خروجی چاپ می شود. cout گشته و با استفاده از cube(n) عبارت

می توان رابطۀ بین تابع

را cube() و تابع main()

شبیه این شکل تصور نمود:

مقدار 5 را به تابع main() تابع

می فرستد و تابع cube()

n 5

int

5

125

main() cube()

x 5

int

 

 

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

به وسیلۀ مقدار n بازمی گرداند. آرگومان main() مقدار 125 را به تابع cube()

x ، فرستاده می شود. به بیان ساده تر وقتی تابع فراخوانی می شود x به پارامتر صوری

را می گیرد. n مقدار

تعریف شده زیرا قبل از main() در بالای تابع cube() دقت کنید که تابع

باید در بارۀ آن C++ به کار رود، کامپایلر main() در تابع cube() این که تابع

اطلاع حاصل کند.

را نشان می دهد که این تابع از max() مثال بعدی یک تابع ساخت کاربر به نام

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

max() 5 یک برنامۀ آزمون برای تابع ‐ * مثال 5

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

را برمی گرداند:

int max(int x, int y)

{ // returns larger of the two given integers:

int z;

z = (x > y) ? x : y ;

return z;

}

int main()

{ // tests the max() function:

int m, n;

do

{ cin >> m >> n;

cout << "\tmax(" << m << "," << n << ") = "

<< max(m,n) << endl;

}

while (m != 0);

}

3 9

max(3,9) = 9

2 -2]

 

 

فصل پنجم / توابع 139

max(2,-2) = 2

0 0

max(0,0) = 0

دارد که مقدار بزرگ تر در آن نگهداری شده و z یک متغیر محلی به نام max() تابع

می گردد. main() به تابع return سپس این مقدار با استفاده از دستور

را max() داشته باشند. مثلا تابع return توابع می توانند بیش از یک دستور

مانند این نیز می توانستیم بنویسیم:

int max(int x, int y)

{ // returns larger of the two given integers:

if (x < y) return y;

else return x;

}

که زودتر اجرا شود مقدار مربوطه اش را بازگشت داده return در این کد هر دستور

و تابع را خاتمه می دهد.

زیرا اجرا را ( break نوعی دستور پرش است (شبیه دستور return دستور

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

می توان آن را در هر نقطۀ دیگری از تابع قرار داد.

5 اعلان ها و تعاریف تابع ‐5

در دو مثال آخر، تعریف کامل تابع در ابتدای برنامه آمد و زیر آن متن برنامۀ

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

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

اعلان 1 شود، سپس متن برنامۀ اصلی بیاید، پس از برنامۀ اصلی تعریف 2 کامل تابع قرار

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

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

سمیکولن در انتهای آن قرار دارد ولی تعریف تابع، متن کامل تابع است که هم شامل

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

1 – Declaration 2 – Definition

 

 

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

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

در هر جایی از برنامه می توان اعلان کرد اما تابع را باید قبل از برنامۀ اصلی اعلان نمود.

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

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

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

قرار می گیرد. main() انتهای برنامه و پس از تابع

را بدانیم. پارامترها متغیرهایی هستند « پارامتر 2 » و « آرگومان 1 » اکنون باید فرق بین

پارامترهای تابع y و x که در فهرست پارامتر یک تابع نام برده می شوند. در مثال قبلی

هستند. پارامترها متغیرهای محلی برای تابع محسوب می شوند؛ یعنی فقط در max()

طول اجرای تابع وجود دارند. آرگومان ها متغیرهایی هستند که از برنامۀ اصلی به تابع

هستند. وقتی یک max() آرگومان های تابع n و m فرستاده می شوند. در مثال قبلی

تابع فراخوانی می شود، مقدار آرگومان ها درون پارامترهای تابع قرار می گیرد تا تابع

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

شده اند. یعنی مقدار آرگوما نها جایگزین پارامترهای متناظرشان می شوند. در مثال بالا

به ترتیب جایگزین n و m فراخوانی می شود، مقدار آرگومان های max() وقتی تابع

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

یا می توان یک (max( آرگومان ها، یک مقدار ثابت را به تابع فرستاد (مثل ( 22,44

قرار می گیرد x 2 در *m که مقدار max(2*m, 3-n) عبات را به تابع فرستاد (مثل

قرار می گیرد). y 3- در n و مقدار

با اعلان جدا از تعریف آن max() 5 تابع ‐ * مثال 6

5 است. اما این جا اعلان ‐ در مثال 5 max() این برنامه همان برنامۀ آزمون تابع

تابع بالای تابع اصلی ظاهر شده و تعریف تابع بعد از برنامۀ اصلی آمده است:

int max(int,int);

// returns larger of the two given integers:

int main()

1 – Argument 2 – Para فصل پنجم / توابع 141

{ // tests the max() function:

int m, n;

do

{ cin >> m >> n;

cout << "\tmax(" << m << "," << n << ") = "

<< max(m,n) << endl;

}

while (m != 0);

}

int max(int x, int y)

{ if (x < y) return y;

else return x;

}

در بخش عنوان تعریف تابع آمده اند (طبق معمول) y و x توجه کنید که پارامترهای

ولی در اعلان تابع وجود ندارند.

5 کامپایل جداگانۀ توابع ‐6

اغلب این طور است که تعریف و بدنۀ توابع در فایل های جداگانه ای قرار

می گیرد. این فایل ها به طور مستقل کامپایل 1 می شوند و سپس به برنامۀ اصلی که آن

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

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

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

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

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

توابع به برنامه نویس دیگری بدهید تا برنامۀ اصلی را تکمیل کند. به این ترتیب آن

برنامه نویس از جزییات توابع و نحوۀ اجرای داخلی آن ها چیزی نمی داند (نباید هم

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

دانستن آن ها برای برنامه نویس ضروری نیست از دید او مخفی می ماند. تجربه نشان

1 – Compiling 2 - Linking meter

 

 

 

 

 

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

داده که پنهان سازی اطلاعات، فهمیدن برنامۀ اصلی را آسان می کند و پروژه های بزرگ

با موفقیت اجرا می شوند.

مزیت دیگر این است که توابع مورد نیاز را می توان قبل از این که برنامۀ اصلی

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

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

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

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

« بسته بندی نرم افزار » پیش می رود بدون این که یکی منتظر دیگری بماند. به این دیدگاه

می گویند.

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

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

مرتب کردن فهرستی از اعداد ایجاد کرده اید و آن را جداگانه کامپایل و ذخیره نموده اید

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

برای مرتب سازی یافتید، فقط کافی است فایل تابع را اصلاح و کامپایل کنید و دیگر

نیازی نیست که برنامۀ اصلی را دس تکاری نمایید.

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

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

نوشتن یک برنامۀ جدید می کنید، شاید برخی از توابع مورد نیاز را از قبل داشته باشید.

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

تولید نرم افزار را افزایش می دهد.

را به خاطر بیاورید. برای این که این تابع را در فایل جداگانه ای max() تابع

قرار دهیم، تعریف آن را در

max.cpp فایلی به نام

ذخیره می کنیم. فایل

شامل کد مقابل max.cpp

است:

int max(int x, int y)

{ if (x < y) return y;

else return x;

}

max.cpp

 

فصل پنجم / توابع 143

test.cpp حالا سراغ برنامۀ اصلی می رویم. متن برنامۀ اصلی را در فایلی به نام

ذخیره می نماییم. این فایل شامل کد زیر است:

فقط اعلان شده است. در اولین خط از برنامۀ اصلی max() در برنامۀ اصلی، تابع

int دارد و یک مقدار از نوع int دو پارامتر از نوع max() اعلان شده که تابع

برمی گرداند.

نحوۀ کامپایل کردن فایل ها و الصاق آ نها به یکدیگر به نوع سیستم عامل و نوع

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

کامپایل و ذخیره می کنند و سپس این فایل را در برنامۀ اصلی احضار می نمایند. DLL1

را به دو طریق ایستا و پویا می توان مورد استفاده قرار داد. برای آشنایی DLL فایل های

مراجعه کنید. c++ به مرجع ویندوز و کامپایلرهای DLL بیشتر با فایل های

5 متغیرهای محلی، توابع محلی ‐6

متغیر محلی 2، متغیری است که در داخل یک بلوک اعلان گردد. این گونه

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

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

int max(int,int);

// returns larger of the two given integers:

int main()

{ // tests the max() function:

int m, n;

do

{ cin >> m >> n;

cout << "\tmax(" << m << "," << n << ") = "

<< max(m,n) << endl;

}

while (m != 0);

}

test.cpp

1 – Data Link Library 1 – Local variable

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

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

پارامترهای تابع نیز متغیرهای محلی محسوب می شوند.

5 تابع فاکتوریل ‐ * مثال 7

برابر است با: n 4 دیدیم. فاکتوریل عدد صحیح ‐ اعداد فاکتوریل را در مثال 8

n! = n(n-1)(n-2)..(3)(2)(1)

را محاسبه می کند : n تابع زیر، فاکتوریل عدد

long fact(int n)

{ //returns n! = n*(n-1)*(n-2)*...*(2)*(1)

if (n < 0) return 0;

int f = 1;

while (n > 1)

f *= n--;

return f;

}

یک متغیر محلی است زیرا در فهرست n پارامتر .f و n : این تابع دو متغیر محلی دارد

نیز محلی است زیرا درون بدنۀ تابع اعلان شده. f پارامترهای تابع اعلان شده. متغیر

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

long fact(int);

// returns n! = n*(n-1)*(n-2)*...*(2)*(1)

int main()

{ // tests the factorial() function:

for (int i=-1; i < 6; i++)

cout << " " << fact(i);

cout << endl;

}

0 1 1 2 6 24 120

برای این که برنامۀ بالا قابل اجرا باشد، یا باید فایل تابع فاکتوریل را به آن الصاق کنیم

و یا این که تعریف تابع فاکتوریل را به انتهای آن اضافه نماییم.

 

فصل پنجم / توابع 145

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

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

ساده و ترکیب آن ها می توان توابع پیچیده تری ساخت. به مثال زیر نگاه کنید.

5 تابع جایگشت ‐ * مثال 8

نشان می دهند. این تابع بیان می کند p(n,k) در ریاضیات، تابع جایگشت را با

عنصری را کنار یکدیگر n عنصر دلخواه از یک مجموعۀ k که به چند طریق می توان

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

P(n k) = n!

            (k , n) !

 

 

 

برای مثال:

12

2

24

2!

4!

(4 2)!

(4,2) 4! = = =

P =

پس به 12 طریق می توانیم دو عنصر دلخواه از یک مجموعۀ چهار عنصری را کنار هم

1} حالت های ممکن عبارت است , 2, 3, بچینیم. برای دو عنصر از مجموعۀ { 4

از:

12, 13, 14, 21, 23, 24, 31, 32, 34, 41, 42, 43

کد زیر تابع جایگشت را پیاده سازی می کند:

long perm(int n, int k)

{ // returns P(n,k), the number of the permutations of k from n:

if (n < 0) || k < 0 || k > n) return 0;

return fact(n)/fact(n-k);

}

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

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

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

در ادامه آمده است: perm() است. برنامۀ آزمون برای تابع

1 – Local function

 

 

 

 

 

 

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

long perm(int,int);

// returns P(n,k), the number of permutations of k from n:

int main()

{ // tests the perm() function:

for (int i = -1; i < 8; i++)

{ for (int j= -1; j <= i+1; j++)

cout << " " << perm(i,j);

cout << endl;

}

}

0 0

0 1 0

0 1 1 0

0 1 2 2 0

0 1 3 6 6 0

0 1 4 12 24 24 0

0 1 5 20 60 120 120 0

0 1 6 30 120 360 720 720 0

0 1 7 42 210 840 2520 5040 5040 0

در یک فایل باشد. fact() و perm() البته ضروری است که تعریف دو تابع

void 5 تابع ‐7

برای مشخص کردن C++ لازم نیست یک تابع حتما مقداری را برگرداند. در

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

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

5 تابعی که به جای شمارۀ ماه ها ، نام آن ها را می نویسد ‐ * مثال 9

void PrintDate(int,int,int);

// prints the given date in literal form:

int main()

{ // tests the PrintDate() function:

int day, month, year;

do

فصل پنجم / توابع 147

{ cin >> day >> month >> year;

PrintDate(day,month,year);

}

while (month > 0);

}

void PrintDate(int d, int m, int y)

{ // prints the given date in literal form:

if (d < 1 || d > 31 || m < 1 || m > 12 || y < 0)

{ cout << "Error: parameter out of range.\n";

return;

}

Cout << d;

switch (m)

{ case 1: cout << "Farvardin "; break;

case 2: cout << "Ordibehesht "; break;

case 3: cout << "Khordad "; break;

case 4: cout << "Tir "; break;

case 5: cout << "Mordad "; break;

case 6: cout << "Shahrivar "; break;

case 7: cout << "Mehr "; break;

case 8: cout << "Aban "; break;

case 9: cout << "Azar "; break;

case 10: cout << "Dey "; break;

case 11: cout << "Bahman "; break;

case 12: cout << "Esfnad "; break;

}

cout << y << endl;

}

7 12 1383

7 Esfand 1383

15 8 1384

15 Aban 1384

0 0 0

Error: parameter out of range.

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

هیچ مقداری را برنمی گرداند. تنها هدف این تابع، چاپ تاریخ PrintDate() تابع

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

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

31 چاپ شوند. اصلاح این ناهنجاری را Esfand مقادیر غیرممکنی مانند 1384

به عنوان تمرین به دانشجو وا می گذاریم.

return مقداری را برنمی گرداند، نیازی به دستور void از آ نجا که یک تابع

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

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

return;

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

معمولا برای انجام یک کار مشخص استفاده می شوند مثل تابع بالا void توابع

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

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

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

می دهد. رعایت این قرارداد به خوانایی و درک بهتر برنام هتان کمک می کند.

5 توابع بولی ‐8

در بسیاری از اوقات لازم است در برنامه، شرطی بررسی شود. اگر بررسی این

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

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

. false یا true : بولی فقط دو مقدار را برمی گردانند

5 تابعی که اول بودن اعداد را بررسی می کند ‐ * مثال 10

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

آن، اول است یا خیر:

bool isPrime(int n)

{ // returns true if n is prime, false otherwise:

 

فصل پنجم / توابع 149

float sqrtn = sqrt(n);

if (n < 2) return false; // 0 and 1 are not primes

if (n < 4) return true; // 2 and 3 are the first primes

if (n%2 == 0) return false; // 2 is the only even prime

for (int d=3; d <= sqrtn; d += 2)

if (n%d == 0) return false; // n has a nontrivial divisor

return true; // n has no nontrivial divisors

}

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

را true اول نیست. اگر هیچ مقسوم علیهی یافت نشد مقدار n برمی گرداند یعنی

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

نظر می گیرد: 1 – اعداد کوچک تر از دو اول نیستند. 2‐ عدد دو اول است. 3 – هر

عدد زوج غیر از دو اول نیست. 4 – حداقل یکی از مقسو معلیه های عدد از جذر آن

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

برمی گردد true برابر با 2 یا 3 باشد مقدار n برمی گردد. اگر false باشد مقدار

برمی گردد زیرا false زوج باشد باز هم n اول است. در غیر این صورت اگر n یعنی

شروع for زوج هم نبود آنگاه حلقۀ n هیچ عدد زوجی غیر از دو اول نیست. اگر

کوچک تر n می شود و در این حلقه بررسی می شود که آیا عددی هست که از جذر

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

را بررسی کنیم (چرا؟) n فرد کوچک تر از جذر

یک برنامۀ آزمون و خروجی آن در ادامه آمده است:

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

#include <iostream> // defines the cout object

using namespace std;

bool isPrime(int);

// returns true if n is prime, false otherwise;

int main()

{ for (int n=0; n < 80; n++)

if (isPrime(n)) cout << n << " ";

cout << endl;

}

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

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79

بهتر است بدانید که این تابع، بهینه نیست. هر عدد مرکب(غیر اول) را می توان به

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

بودن یک عدد کافی است بررسی شود که آیا این عدد به اعداد اول قبل از خودش قابل

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

ذخیره کنیم. آرایه ها را در فصل بعدی بررسی می کنیم.

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

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

نام گرفته زیرا پاسخ می دهد که آیا عدد مذکور اول است یا خیر. این نحو isPrime

نام گذاری گرچه اجباری نیست اما درک برنامه را آسا نتر می کند و به یادآوری وظیفۀ

یا isLower() استاندارد توابع بولی مثل C++ تابع نیز کمک می نماید. در کتابخانۀ

به همین شیوه نام گذاری شده اند. isUpper()

(I/O) 5 توابع ورودی/خروجی 1 ‐9

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

اصلی برنامه مربوط نیست را می توان به توابع سپرد. در چنین شرایطی سودمندی توابع

محسوس تر می شود. فرض کنید نرم افزاری برای سیستم آموزشی دانشگاه طراحی

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

سن دانشجو به عنوان یکی از اطلاعات پروندۀ دانشجو وارد شود. اگر وظیفۀ دریافت

سن را به عهدۀ یک تابع بگذارید، می توانید جزییاتی از قبیل کنترل ورودی معتبر، یافتن

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

اصلی منحرف شوید.

5‐ در مثال 9 PrintDate() قبلا نمونه ای از توابع خروجی را دیدیم. تابع

هیچ چیزی به برنامۀ اصلی برنمی گرداند و فقط برای چاپ نتایج به کار می رود. این

تابع نمونه ای از توابع خروجی است؛ یعنی توابعی که فقط برای چاپ نتایج به کار

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

1 – Input/Output functions

 

 

 

فصل پنجم / توابع 151

در جهت معکوس. یعنی توابع ورودی فقط برای دریافت ورودی و ارسال آن به برنامۀ

اصلی به کار می روند و هیچ پارامتری ندارند. مثال بعد یک تابع ورودی را نشان

می دهد.

5 تابعی برای دریافت سن کاربر ‐ * مثال 11

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

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

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

در محدودۀ 7 تا 120 دریافت دارد:

int age()

{ // prompts the user to input his/her age and returns that value:

int n;

while (true)

{ cout << "How old are you: ";

cin >> n;

if (n < 0) cout << "\a\tYour age could not

be negative.";

else if (n > 120) cout << "\a\tYou could not

be over 120.";

else return n;

cout << "\n\tTry again.\n";

}

}

است و این حلقه به ظاهر بی پایان به نظر می رسد. اما true ، شرط کنترل حلقه

درون حلقه نه تنها مقدار ورودی معتبر را به برنامۀ اصلی می فرستد return دستور

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

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

آنگاه ( n> یا 120 n< می شود و تابع خاتمه می یابد. اگر ورودی قابل قبول نباشد ( 7

است) و سپس \a یک بوق اخطار پخش می شود (که این بوق حاصل چاپ کاراکتر

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

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

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

علاوه بر این فهرست پارامترهای تابع خالی است زیرا از برنامۀ اصلی چیزی دریافت

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

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

یک برنامۀ آزمون و خروجی حاصل از آن در ادامه آمده است:

int age()

int main()

{ // tests the age() function:

int a = age();

cout << "\nYou are " << a << " years old.\n";

}

How old are you? 125

You could not be over 120

Try again.

How old are you? -3

Your age could not be negative

Try again.

How old are you? 99

You are 99 years old.

5 ارسال به طریق ارجاع 1 (آدرس) ‐14

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

یعنی ابتدا مقدار متغیری که در فراخوانی تابع ذکر شده برآورد می شود و سپس این

ابتدا cube(x) مقدار به پارامترهای محلی تابع فرستاده می شود. مثلا در فراخوانی

در تابع فرستاده می شود و n برآورد شده و سپس این مقدار به متغیر محلی x مقدار

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

به x نمی گذارد. پس خود x محلی است هیچ تغییری روی مقدار n تغییر کند اما چون

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

را بخواند x اصلی ندارد. به این ترتیب تابع می تواند مقدار x درون تابع هیچ تاثیری بر

1 – Reference

فصل پنجم / توابع 153

« فقط خواندنی » یک پارامتر x را تغییر دهد. به همین دلیل به x اما نمی تواند مقدار

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

فراخوانی cube(2*x- را می توان به صورت ( 3 cube() استفاده کرد. مثلا تابع

فراخوانی نمود. در هر یک از cube(2*sqrt(x)-cube( کرد یا به شکل (( 3

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

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

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

ناخواسته در توابع مصون بمانند. اما گاهی اوقات عمدا می خواهیم این اتفاق رخ دهد.

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

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

برای این که مشخص کنیم یک پارامتر به طریق ارجاع ارسال می شود، علامت &

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

به جای این که یک کپی محلی از آن آرگومان ایجاد کند، خود آرگومان محلی را به کار

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

« خواندنی‐ نوشتنی » می تواند مقدار آن را تغییر دهد. در این حالت آن پارامتر یک پارامتر

خواهد بود. هر تغییری که روی پارامتر خواندنی‐نوشتنی در تابع صورت گیرد به طور

مستقیم روی متغیر برنامۀ اصلی اعمال می شود. به مثال زیر نگاه کنید.

swap() 5 تابع ‐ * مثال 12

تابع کوچک زیر در مرتب کردن داد هها کاربرد فراوان دارد:

void swap(float& x, float& y)

{ // exchanges the values of x and y:

float temp = x;

x = y;

y = temp;

}

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

به صورت پارامترهای ارجاع تعریف شده اند: y و x منظور پارامترهای

 

 

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

float& x, float& y

آرگومان های ارسالی قرار بگیرند. y و x عملگر ارجا ع & موجب می شود که به جای

برنامۀ آزمون و اجرای آزمایشی آن در زیر آمده است:

void swap(float&, float&)

// exchanges the values of x and y:

int main()

{ // tests the swap() function:

float a = 55.5, b = 88.8;

cout << "a = " << a << ", b = " << b << endl;

swap(a,b);

cout << "a = " << a << ", b = " << b << endl;

}

a = 55.5, b = 88.8

a = 88.8, b = 55.5

سپس .b به y اشاره می کند و a به x ، اجرا می شود swap(a,b) وقتی فراخوانی

است) درون آن قرار a که همان ) x اعلان می شود و مقدار temp متغیر محلی

y می گیرد. پس از آن مقدار

x است) درون b (که همان

قرار می گیرد و آنگاه (a (یعنی

یعنی ) y درون temp مقدار

قرار داده می شود. نتیجۀ (b

و a نهایی این است که مقادیر

با یکدیگر جابجا می شوند. b

شکل مقابل نشان می دهد که

چطور این جابجایی رخ

می دهد:

swap()

a 55.5

float

main()

x

float&

b 88.8

float

y

float&

هنگام فراخوانی تابع

swap(a b)

a 88.8

float

main() swap()

x

float&

b 55.5

float

y

float&

temp 55.5

float

بعد از

بازگشت

 

فصل پنجم / توابع 155

دقت کنید: swap() به اعلان تابع

void swap(float&, float&)

عادت دارند که c این اعلان شامل عملگر ارجاع & برای هر پارامتر اس ت. برنامه نویسان

C++ در (float &x عملگر ارجاع & را به عنوان پیشوند نام متغیر استفاده کنند (مثل

به هر حال (float& x فرض می کنیم عملگر ارجاع & پسوند نوع است (مثل

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

اختیاری و سلیقه ای است.

5 ارسال به طریق مقدار و ارسا ل به طریق ارجاع ‐ * مثال 13

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

می دهد:

void f(int,int&);

// changes reference argument to 99:

int main()

{ // tests the f() function:

int a = 22, b = 44;

cout << "a = " << a << ", b = " << b << endl;

f(a,b);

cout << "a = " << a << ", b = " << b << endl;

f(2*a-3,b);

cout << "a = " << a << ", b = " << b << endl;

}

void f(int x , int& y)

{ // changes reference argument to 99:

x = 88;

y = 99;

}

a = 22, b = 44

a = 22, b = 99

a = 22, b = 99

 

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

دو پارامتر دارد که اولی به طریق مقدار و دومی به طریق ارجاع ارسال f() تابع

b ارسال شود و x از طریق مقدار به a باعث می شود که f(a,b) می شود. فراخوانی

یک متغیر محلی است که مقدار 22 به آن x فرستاده شود. بنابراین y از طریق ارجاع به

است که مقدار فعلی آن 44 b یک ارجاع به متغیر y فرستاده می شود در حالی که

ندارد. همچنین a قرار می گیرد که این تاثیری بر x مقدار 88 در f() می باشد. در تابع

است، b در حقیقت یک نام مستعار برای y قرار می گیرد که چون y مقدار 99 در

هنوز مقدار 22 را دارد a ، به 99 تغییر می کند. هنگامی که تابع خاتمه یابد b مقدار

b فقط خواندنی است و آرگومان a به 99 تغییر یافته است. آرگومان b ولی مقدار

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

در جدول زیر خلاصۀ تفاوت های بین ارسال از طریق مقدار و ارسال از طریق

ارجاع آمده است.

ارسال از طری ق مقدار در مقایس ه با ارسا ل از طری ق ارجاع

ارسال از طریق مقدار ارسال از طریق ارجاع

int& x; int x;

یک ارجاع است x یک متغیر محلی است پارامتر x پارامتر

مترادف با آرگومان است x یک کپی از آرگومان است x

تغییر محتویات آرگومان ممکن نیست می تواند محتویات آرگومان را تغییر دهد

a 22

int

main()

x 22

int

b 44

int

y

int&

f()

هنگام فراخوانی

f(a b) تا

a 22

int

main()

x 88

int

b 99

int

y

int&

بعد از f()

بازگشت

فصل پنجم / توابع 157

آرگومان ارسال شده از طریق مقدار می تواند

یک ثابت، یک متغیر یا یک عبارت باشد

آرگومان ارسال شده از طریق ارجاع فقط باید

یک متغیر باشد

آرگومان فقط خواندنی است آرگومان خواندنی‐نوشتنی است

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

فقط می تواند یک مقدار را برگرداند. return بیش از ی ک مقدار را بازگرداند. دستور

بنابراین اگر باید بیش از یک مقدار برگشت داده شود، این کار را پارامترهای ارجاع

انجام می دهند.

5 بازگشت بیشتر از ی ک مقدار ‐ * مثال 14

و area : تابع زیر از طریق دو پارامتر راجاع، دو مقدار را بازمی گرداند

r محیط و مساح ت) برای دایره ای که شعاع آن عدد مفروض ) circumference

است:

void ComputeCircle(double& area, double& circumference, double r)

{ // returns the area and circumference of a circle with radius r:

const double PI = 3.141592653589793;

area = PI*r*r;

circumference = 2*PI*r;

}

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

void ComputerCircle(double&, double&, double);

// returns the area and circumference of a circle with radius r;

int main()

{ // tests the ComputeCircle() function:

double r, a, c;

cout << "Enter radius: ";

cin >> r;

ComputeCircle(a, c, r);

cout << "area = " << a << ", circumference = "

<< c << endl;

}

 

 

 

 

 

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

Enter radius: 100

area = 31415.9, circumference = 628.319

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

فهرست پارامترها قرار داده شده اند. رعایت این قاعده باعث می شود که نظم برنامه

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

یک قرارداد است و رعایت آن اجباری نیست.

5 ارسال از طری ق ارجاع ثابت ‐11

ارسال پارامترها به طریق ارجاع دو خاصیت مهم دارد: اول این که تابع می تواند

روی آرگومان واقعی تغییراتی بدهد و دوم این که از اشغال بی مورد حافظه جلوگیری

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

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

حافظه اشغال می کند. حال اگر آرگومان اصلی خیلی حجیم باشد (مثل یک تصویر

گرافیکی) آنگاه ارسال از طریق مقدار باعث می شود که حافظه به میزان دوبرابر مصرف

شود؛ بخشی برای آرگومان اصلی و بخشی دیگر برای نسخه محلی که در تابع به کار

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

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

تابع می تواند مقدار پارامتر ارجاع را دس تکاری کند. اگر تابع نمی بایست پارامتر مذکور

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

برای این که عیب مذکور برطرف شود و شیء اصلی از تغییرات ناخواسته درون

روش سومی را برای ارسال آرگومان پیشنهاد می کند: ارسال از C++ ، تابع مصون باشد

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

نمی تواند محتویات پارامتر ارجاع را دس تکاری نماید و فقط اجازۀ خواندن آن را دارد.

را به const برای این که پارامتری را از نوع ارجاع ثابت اعلان کنیم باید عبارت

ابتدای اعلان آن اضافه نماییم.

1 – Constant reference

 

فصل پنجم / توابع 159

5 ارسال از طریق ارجاع ثابت ‐ * مثال 15

سه طریقه ارسال پارامتر در تابع زیر به کار رفته است:

void f(int x, int& y, const int& z)

{ x += z;

y += z;

cout << "x = " << x << ", y = " << y << ", z = "

<< z << endl;

}

از طریق مقدار ارسال می شود، دومین پارامتر x در تابع فوق اولین پارامتر یعنی

از طریق ارجاع و سومین پارامتر نیز از طریق ارجاع ثابت. برنامۀ آزمون و یک y یعنی

اجرای آزمایشی از آن در ذیل آمده است:

void f(int, int&, const int&);

int main()

{ // tests the f() function:

int a = 22, b = 33, c = 44;

cout << "a = " << a << ", b = " << b << ", c = "

<< c << endl;

f(a,b,c);

cout << "a = " << a << ", b = " << b << ", c = "

<< c << endl;

f(2*a-3,b,c);

cout << "a = " << a << ", b = " << b << ", c = "

<< c << endl;

}

a = 22, b = 33, c = 44

x = 66, y = 77, z = 44

a = 22, b = 77, c = 44

x = 85, y = 121, z = 44

a = 22, b = 121, c = 44

را تغییر z را می تواند تغییر دهد ولی قادر نیست پارامتر y و x تابع فوق پارامترهای

a نخواهد داشت زیرا a صورت می گیرد اثری روی آرگومان x دهد. تغییراتی که روی

صورت می گیرد روی آرگومان y از طریق مقدار به تابع ارسال شده. تغییراتی که روی

از طریق ارجاع به تابع فرستاده شده. b هم تاثیر می گذارد زیرا b

 

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

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

را ویرایش می کنند مثل آرایه ها یا نمونۀ کلاس ها که در فص لهای بعدی توضیح آن ها

به طریق مقدار (float یا int آمده است. عناصری که از انواع اصلی هستند (مثل

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

5 توابع بی واسطه 1 ‐12

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

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

برنامه پی گیری شود. همچنین باید متغیرهای محلی تابع ایجاد شوند و حافظ های برای

آن ها تخصیص یابد و همچنین آرگومان ها به این متغیرها ارسال شوند تا درنهایت تابع

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

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

دارد. در « سربار » اضافی می طلبد. در اصطلاح می گویند که فراخوانی و اجرای تابع

بعضی حالت ها بهتر است با تعریف تابع به شکل بی واسطه از سربار اجتناب کنیم.

تابعی که به شکل بی واسطه تعریف می شود، ظاهری شبیه به توابع معمولی دارد با این

در اعلان و تعریف آن قید شده است. inline فرق که عبارت

به شکل بی واسطه cube() 5 تابع ‐ * مثال 16

5 است : ‐ مثال 3 cube() این همان تابع

inline int cube(int x)

{ // returns cube of x:

return x*x*x;

}

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

کد واقعی cube(n) عبارت به کامپایلر می گوید ک ه در برنامه به جای

را قرار دهد. به برنامۀ آزمون زیر نگاه کنید: (n)*(n)*(n)

1 – Inline

فصل پنجم / توابع 161

int main()

{ // tests the cube() function:

cout << cube(4) << endl;

int x, y;

cin >> x;

y = cube(2*x-3);

}

این برنامه هنگام کامپایل به شکل زیر درمی آید، گویی اصلا تابعی وجود نداشته:

int main()

{ // tests the cube() function:

cout << (4) * (4) * (4) << endl;

int x, y;

cin >> x;

y = (2*x-3) * (2*x-3) * (2*x-3);

}

وقتی کامپایلر کد واقعی تابع را جایگزین فراخوانی آن می کند، می گوییم که تابع

بی واسطه، باز می شو.د

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

تابع بی واسطه دارای 40 خط کد باشد و این تابع در 26 نقطه مختلف از برنامۀ اصلی

فراخوانی شود، هنگام کامپایل بیش از هزار خط کد به برنامۀ اصلی افزوده می شود.

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

کاهش دهد.

5 چندشکلی توابع ‐13

می توانیم چند تابع داشته باشیم که همگی یک نام دارند. در این حالت C++ در

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

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

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

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

max() 5 چندشکلی تابع ‐ * مثال 17

را تعریف کردیم. حالا توابع دیگری با همان نام ولی max() 5 تابع ‐ در مثال 3

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

int max(int, int);

int max(int, int, int);

int max(double, double);

int main()

{ cout << max(99,77) << " " << max(55,66,33) << " " <<

max(44.4,88.8);

}

int max(int x, int y)

{ // returns the maximum of the two given integers:

return (x > y ? x : y);

}

int max(int x, int y, int z)

{ // returns the maximum of the three given integers:

int m = (x > y ? x : y); // m = max(x , y)

return ( z > m ? z : m);

}

int max(double x, double y)

{ // return the maximum of the two given doubles:

return (x>y ? x : y);

}

99 66 88.0

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

برنامه فراخوانی می شود، کامپایلر فهرست آرگومان آن را بررسی می کند تا بفهمد که

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

در فهرست پارامترهایش int ارسال شده، پس نسخه ای که دو پارامتر int آرگومان

 

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

 

فصل پنجم / توابع 163

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

دارد را فرا می خواند. double ارتقا می دهد و سپس نسخ های که دو پارامتر double

استفاده می شوند. چندشکلی C++ توابعی که چندشکلی دارند بسیار فراوان در

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

main() 5 تابع ‐14

اکنون که با توابع آشنا شده ایم، نگاه دقیق تری به برنامه ها بیاندازیم. برنامه هایی که

این طور است C++ هستند. منطق main() تا کنون نوشتیم همه دارای تابعی به نام

باشد. در حقیقت هر برنامه کامل، از main() که هر برنامه باید دارای تابعی به نام

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

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

دارد، int شروع می شود. چون این تابع یک نوع بازگشتی main() فراخوانی تابع

باشد هرچند که در return شامل دستور ; 0 main() منطقی است که بلوک تابع

این خط اجباری نیست و می توان آن را ذکر نکرد. مقدار C++ برخی از کامپایلرهای

به سیستم عامل برمی گردد باید تعداد خطاها را return صحیحی که با دستور

شمارش کند. مقدار پیش فرض آن 0 است به این معنا که برنامه بدون خطا پایان گرفته

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

برای پایان دادن به یک برنامه return 5 استفاده از دستور ‐ * مثال 18

int main()

{ // prints the quotient of two input integers:

int n, d;

cout << "Enter two integers: ";

cin >> n >> d;

if (d = = 0) return 0;

cout << n << "/" << d << " = " << n/d << endl;

}

Enter two integers: 99 17

99/17 = 5

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

اگر کاربر برای ورودی دوم 0 را وارد کند، برنامه بدون چاپ خروجی پایان می یابد:

Enter two integers: 99 0

تابع فعلی را خاتمه می دهد و کنترل را به فراخواننده return دستور

کل main() در تابع return بازمی گرداند. به همین دلیل است که اجرای دستور

برنامه را خاتمه می دهد.

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

که اجرا به پایان بلوک اصلی برسد) خاتمه دهیم:

return 1 ‐ استفاده از دستور

exit() 2 ‐ فراخوانی تابع

abort() 3 ‐ فراخوانی تابع

4 – ایجاد یک حالت استثنا 1

در مثال زیر شرح داده شده. این تابع در exit() طریقۀ به کارگیری تابع

برای خاتمه دادن به کل exit() تعریف شده است. تابع <cstdlib> سرفایل

مفید است. به مثال بعدی توجه کنید. main() برنامه در هر تابعی غیر از تابع

برای پایان دادن به برنامه exit() 5 استفاده از تابع ‐ * مثال 19

#include <cstdlib> // defines the exit() function

#include <iostream> // defines thi cin and cout objects

using namespace std;

double reciprocal(double x);

int main()

{ double x;

cin >> x;

cout << reciprocal(x);

}

double reciprocal(double x)

{ // returns the reciprocal of x:

1 – Exception

 

 

فصل پنجم / توابع 165

if (x = = 0) exit(1); // terminate the program

return 1.0/x;

}

خاتمه می یابد و reciprocal() در برنامۀ بالا اگر کاربر عدد 0 را وارد کند، تابع

برنامه بدون هیچ مقدار چاپی به پایان می رسد.

5 آرگومان های پیش فرض 1 ‐15

می توان تعداد آرگومان های یک تابع را در زمان اجرا به دلخواه تغییر C++ در

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

5 آرگومان های پیش فرض ‐ * مثال 20

برنامۀ زیر حاصل چند جمل های درجه سوم 3

3

2

0 1 2 را پیدا a + a x + a x + a x

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

دسته بندی می شود: a0 + (a1 + (a2 + a3x)x)x کارایی بیشتر، محاسبه به صورت

double p(double, double, double=0, double=0, double=0);

int main()

{ // tests the p() function:

double x = 2.0003;

cout << "p(x,7) = " << p(x,7) << endl;

cout << "p(x,7,6) = " << p(x,7,6) << endl;

cout << "p(x,7,6,5) = " << p(x,7,6,5) << endl;

cout << "p(x,7,6,5,4) = " << p(x,7,6,5,4) << endl;

}

double p(double x, double a0, double a1=0, double a2=0, double a3=0)

{ // returns a0 + a1*x + a2*x^2 + a3*x^3:

return a0 + (a1 + (a2 + a3*x)*x)*x;

}

p(x,7) = 7

p(x,7,6) = 19.0018

p(x,7,6,5) = 39.0078

p(x,7,6,5,4) = 71.0222

1 – Default

 

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

فراخوانی شود، چندجمله ای درجه سوم p(x, a0, a1, a2, a هنگامی که ( 3

3

3

2

0 1 2 مقدار پیش فرض a و 3 a و 2 a محاسبه می شود اما چون 1 a + a x + a x + a x

نیز فراخوانی نمود. این p(x,a 0 را دارند، تابع مذکور را می توان به صورت ( 0

ارزیابی خواهد a است که برابر با 0 p(x,a فراخوانی معادل فراخوانی ( 0,0,0,0

فراخوانی نمود . این p(x,a0,a شد. همچنین می توان تابع فوق را به صورت ( 1

است که چندجمله ای درجه اول p(x,a0,a فراخوانی معادل فراخوانی ( 1,0,0

a a x 0 1 p(x,a0,a1,a + را محاسبه می نماید. به همین ترتیب فراخوانی ( 2

چندجمله ای درجه دوم 2

0 1 2را محاسبه می کند و همچنین فراخوانی a + a x + a x

چند جمله ای درجه سوم 3 p(x,a0,a1,a2,a3)

3

2

0 1 2 را a + a x + a x + a x

محاسبه می کند. پس این تابع را می توان با 2 یا 3 یا 4 یا 5 آرگومان فراخوانی کرد.

برای این که به یک پارامتر مقدار پیش فرض بدهیم باید آن مقدار را در فهرست

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

ترتیب اگر هنگام فراخوانی تابع، آن آرگومان را ذکر نکنیم، مقدار پیش فرض آن در

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

اختیاری می گویند.

دقت کنید که پارامترهایی که مقدار پیش فرض دارند باید در فهرست پارامترهای

تابع بعد از همۀ پارامترهای اجباری قید شوند مثل:

void f( int a, int b, int c=4, int d=7, int e=3); // OK

void g(int a, int b=2, int c=4, int d, int e=3); // ERROR

همچنین هنگام فراخوانی تابع، آرگومان های ذکر شده به ترتیب از چپ به راست

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

مقدار x باعث می شود که پارامتر p( که در بالا قید شد، فراخوانی ( 8.0,7,6 p()

مقدار 6 را a مقدار 7 را بگیرد و سپس پارامتر 1 a 8.0 را بگیرد سپس پارامتر 0

مقدار پیش فرض شان را خواهند داشت. این ترتیب را a و 3 a بگیرد. پارامترهای 2

و x نمی توانیم به هم بزنیم. مثلا نمی توانیم تابع را طوری فرا بخوانیم که پارامترهای

مقدار پیش فرض شان را a و 2 a مستقیما مقدار بگیرند ولی پارامترهای 1 a و 3 a0

داشته باشند. فصل پنجم / توابع 167

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

استاندارد در کدام سرفایل تعریف شد هاند؟ C++ 1 – توابع ریاضی

<cmath> ب – سرفایل <iostream> الف – سرفایل

<iomanip> د – سرفایل <cstdlib> ج – سرفایل

کدام گزینه صحیح نیست؟ int f(float a) 2 – در تعریف

را تعریف می کند f الف – این کد تابعی به نام

دارد float ب – تابع فوق متغیری از نوع

است int ج ‐ نوع بازگشتی این تابع از نوع

است. int د – پارامتر این تابع از نوع

در تابع چه کاری انجام می دهد؟ return 3 – دستور

الف – تابع را خاتمه می دهد

ب – مقدار نهایی را به فراخواننده برمی گرداند

ج – نوع بازگشتی تابع را مشخص می کند

د – الف و ب

4 – کدام عبارت صحیح نیست؟

الف – پارامترهای تابع، متغیرهای محلی برای آن تابع محسوب می شوند

ب – متغیرهای اعلان شده در یک تابع، متغیرهای محلی آن تابع محسوب می شوند

ج – متغیرهای محلی تابع، فقط در طول اجرای تابع موجودند

د – متغیرهای محلی تابع در سراسر برنامه معتبرند

5 – تابعی که مقداری را برنمی گرداند، نوع بازگشتی آن چگونه اعلان می شود؟

null ب – از نوع void الف – از نوع

د – لازم نیست نوع بازگشتی قید شود int ج – از نوع پیش فرض

6 – نوع بازگشتی یک تابع بولی چیست؟

const – د bool – ج void – ب int – الف

7 – عملگر ارجاع کدام یک از گزینه های زیر است؟

الف ‐ * ب ‐ & ج ‐ <- د ‐ :

 

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

است؟ « خواندنی‐نوشتنی » 8 – چه زمانی یک آرگومان

الف – وقتی از طریق مقدار ارسال شود

ب – وقتی از طریق ارجاع ثابت ارسال شود

ج – وقتی از طریق ارجاع ارسال شود

اعلان شود const د – وقتی با پیشوند

9 – کدام گزینه صحیح است؟

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

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

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

د – چند مقدار را می توان به تابع فرستاد و تابع می تواند چند مقدار را بازگرداند

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

int – د void – ج inline – ب const – الف

11 – کدام عبارت در رابطه با چندشکلی توابع صحیح است؟

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

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

ج – یک تابع چندشکلی باید نام های متفاوت ولی فهرست پارامترهای یکسان داشته باشد

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

اعلان void f(int k, int x=0, int y= به شکل ( 1 f 12 – اگر تابع

شده باشد آنگاه:

دارای مقدار پیش فرض نیست. k الف – پارامتر

دارای مقدار پیش فرض 0 است. x ب – پارامتر

دارای مقدار پیش فرض 1 است. y ج – پارامتر

د – همه موارد فوق صحیح است.

13 – چرا در برنام ههای بزرگ تعریف توابع را در فایل جداگانه ای قرار می دهند؟

الف – به این دلیل که مدیریت برنامه آسان شود

ب – به این دلیل که اصل پنها نسازی اطلاعات رعایت شود

ج – به این دلیل که بتوان در برنام ههای دیگر هم از آن توابع استفاده کرد

 

فصل پنجم / توابع 169

د – همه موارد فوق

اعلان شده باشد آنگاه: void g(int m, int& n) به شکل g 14 – اگر تابع

به طریق ارجاع ارسال شده m الف – پارامتر

به طریق ارجاع ارسال شده n ب – پارامتر

به طریق ارجاع ثابت ارسال شده m ج – پارامتر

به طریق ارجاع ثابت ارسال شده n د – پارامتر

فراخوانی شود آنگاه کدام عبارت g(x, y); 15 – اگر تابع سوال 14 به شکل

صحیح است؟

را می تواند تغییر دهد x الف – تابع مقدار

را می تواند تغییر دهد y ب – تابع مقدار

را می تواند تغییر دهد y و مقدار x ج – تابع مقدار

د – تابع مقدار هیچ کدام را نمی تواند تغییر دهد.

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

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

1‐ استفاده از تابع برای بخش بندی برنامه چه مزایایی دارد؟

2‐ چه تفاوتی بین اعلان یک تابع و تعریف آن است ؟

3‐ اعلان یک تابع کجا می تواند قرار بگیرد؟

نیاز است؟ include 4‐ برای استفاده از چه توابعی به دستور

5‐ گذاشتن تعریف یک تابع در یک فایل جداگانه چه مزیتی دارد؟

6‐ کامپایل کردن یک تابع به طور جداگانه چه مزیتی دارد؟

7‐ چه تفاوت هایی بین ارسال یک پارامتر از طریق مقدار و ارسا ل آن از طری ق ارجاع

وجود دارد ؟

8‐ چه تفاوت هایی بی ن ارسال یک پارامتر از طری ق ارجاع و ارسال آن از طریق ارجا ع

ثابت وجود دارد ؟

گفته می شود؟ « فقط خواندنی » 9‐ چرا به پارامتری که از طریق مقدار ارسال م یشود

گفته می شود؟ « خواندنی‐نوشتنی » چرا به پارامتری که از طریق ارجاع ارسال می شود

10 ‐ چه اشتباهی در اعلا ن زیر هست ؟

int f(int a, int b=0, int c);

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

با ی ک پارامتر ارجاع می تواند به یک تابع غیر void 1‐ توضیح دهید چگونه یک تابع

با یک پارامتر مقدار تبدیل گردد. void

cos 2x = 2cos2 x − 5 بنویسید که صحت رابطۀ مثلثاتی 1 ‐ 2‐ برنامه ای شبیه مثال 2

را تحقیق کند.

را cos2 x + sin2 x = 5 بنویسید که صحت رابطۀ مثلثاتی 1 ‐ 3‐ برنامه ای شبیه مثال 2

تحقیق کند.

را تحقیق کند. bn = e(n log b) 5 بنویسید که صحت تساوی ‐ 4‐ برنامه ای شبیه مثال 2

را که به شکل زیر اعلان می شود، نوشته و آزمایش کنید. این تابع از min() 5‐ تابع

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

int min(int,int,int,int);

 

 

فصل پنجم / توابع 171

را که به شکل زیر اعلان می شود نوشته و آزمایش کنید. این تابع با max() 6‐ تابع

5 بزرگ ترین عدد در بین چهار عدد ‐ مثال 5 max(int,int) استفاده از تابع

صحیح داده شده را برمی گرداند.

int max(int,int,int,int);

که به شکل زیر اعلان می شود را نوشته و آزمایش کنید. این تابع با min() 7‐ تابع

کوچک ترین عدد را از میان چهار عدد صحیح min(int,int) استفاده از تابع

ارسال شده به آن، پیدا کرده و برمی گرداند.

int main(int,int,int,int);

را که میانگین چهار عدد را برم یگرداند، نوشته و آزمایش average() 8‐ تابع

کنید:

float average(float x1, float x2, float x3, float x4)

را که میانگین حداکثر چهار عدد را بر می گرداند، نوشته و average() 9‐ تابع

آزمایش کنید:

float average(float x1, float x2 =0, float x3=0, float x4=0)

4 را ‐ پیاده سازی کنید(مثال 9 for را با ی ک حلقۀ fact() 10 ‐ تابع فاکتوریال

سرریز شود. fact(n) موجب می شود که n ببینید). مشخص کنید که چه مقداری از

فرمول زیر اس ت: p(n,k) 11 ‐ موثرترین طریق برای محاسبۀ جایگشت تابع

P(n,k) = n(n −1)(n − 2)...(n − k + 2)(n − k +1)

با استفاده از این رابطه ، تابع . n-k+ تا 1 n عدد صحیح از k یعنی حاصل ضرب

5 را بازنویسی و آزمایش کنید. ‐ مثال 10 perm()

عنصری که k ( تعداد زیرمجموعه های متفاوت (نامرتب c(n,k) 12 ‐ تابع ترکیب

عنصری ساخته شود را نشان می دهد. این تابع با رابطۀ n ممکن است از یک مجموعۀ

زیر بیان می شود:

!( )!

( , ) !

k n k

C n k n

=

این تابع را پیاده سازی و آزمایش کنید.

را می توان با استفاده از رابطۀ زیر بیان نمود: c(n,k) 13 ‐ تابع ترکیب

!

( , ) ( , )

k

C n k = P n k

 

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

5 را بازنویسی کرده و آزمایش کنید. ‐ با استفاده از این رابطه، برنامۀ مسالۀ 13

رابطۀ زیر است: c(n,k) 14 ‐ روش موثرتر برای محاسبۀ

C(n,k) = ((((((n /1)(n −1)) / 2)(n − 2)) /3)...(n − k + 2)) /(k −1))(n − k +1)) / k

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

ضرب می شود و بر یک واحد بیشتر از مقدار قبلی با شروع از یک، تقسیم n فعلی

5 را بازنویسی و آزمایش کنید. ‐ می شود. با استفاده از رابطۀ فوق، تابع مسالۀ 13

استفاده کنید. for 5 از حلقۀ ‐ راهنمایی: مانند مسالۀ 12

15 ‐ مثلث خیام یک آرایۀ سه گوش از اعداد به شکل زیر است:

1

1 1

1 2 1

1 3 3 1

1 4 6 4 1

1 5 10 10 5 1

1 6 15 20 15 6 1

1 7 21 35 35 21 7 1

1 8 28 56 70 56 28 8 1

5 نگاه کنید). ‐ است (به مساله 13 c(n,k) هر عدد در مثل ث خیام یکی از ترکیبات

k و ستون n اگر ردیف ها وستون ها را با شروع از 0 شمارش کنیم ، عدد واقع در ردیف

در ردیف شماره 6 و c(6,2) = است. به عنوان مثال عدد 15 c(n,k) برابر با

5 یک مثلث ‐ ستون شماره 2 است . برنامه ای بنویسید که با استفاده از تابع مساله 14

خیام دوازده ردیفی چاپ کند.

که به شکل زیر اعلان می شود را نوشته و آزمایش کنید: digit() 16 ‐ تابع

int digit(int n, int k);

عدد صحی ح 29415 n را برمی گرداند. برای مثال اگر n ام عدد صحیح k این تابع رقم

رقم digit(n, رقم 5 را بازمی گرداند و فراخوانی ( 2 digit(n, باشد، تابع ( 0

4 را برم یگرداند. توجه کنید ک ه رقم ها از راست به چپ و با شروع از 0 شمارش

می شوند.

17 ‐ تابعی را نوشته و آزمایش کنید که الگوریتم اقلیدس را برای بازگرداند ن

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

مسألۀ 11 از فصل چهارم نگاه کنید)

 

فصل پنجم / توابع 173

18 ‐ تابعی را نوشته و آزمایش کنید که با استفاده از تابع بزرگ ترین مقسوم علیه

مشترک (مسألۀ 17 ) کوچک ترین مضرب مشترک دو عدد صحیح مثبت را برگرداند.

که به شکل زیر اعلان می شود را نوشته و آزمایش کنید: power() 19 ‐ تابعی به نام

double power(double x, int p);

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

را 20 مرتبه در خودش ضرب می کند. x مقدار x استفاده کنید که برای محاسبۀ 20

20 ‐ یونانی های باستان اعداد را به صورت هندسی طبقه بندی می کردند. برای مثال به

یک عدد مثلثی می گفتند اگر آن عدد می توانست

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

عدد مثلثی اول اعداد 0 و 1 و 3 و 6 و 10

و 15 و 21 و 28 و 36 و 45 هستند. تابع بولی زیر را نوشته و آزمایش کنید. اگر

یک عدد مثلثی باشد این تابع مقدار 1 را برمی گرداند وگرنه 0 برگشت داده می شود: n

int isTriangular(int n);

را نوشته و آزمایش کنید. این تابع تشخیص می دهد که آیا issquare() 21 ‐ تابع

عدد داده شده یک عدد مربعی است یا خیر:

int isSquare(int n);

اولین ده عدد مربعی اعداد 0 و 1 و 4 و 9 و

16 و 25 و 36 و 49 و 64 و 81 هستند .

یک دایره با شعا ع داده c و محیط a که مساحت ComputeCircle() 22 ‐ تابع

را برمی گرداند، نوشته وامتحان کنید: r شدۀ

void computeCircle(float& a, float& c, float r);

از یک مثلث با p و محیط a که مساحت ComputeTriangle() 23 ‐ تابع

را محاسبه می نماید، نوشته و آزمایش کنید: c و b و a اضلاع به طول

void computeTriangle(float& a, float& p, float a, float b, float c);

را برای یک کره s و مساحت سطح v که حجم computeSphere() 24 ‐ تابع

برمی گرداند، نوشته و آزمایش کنید: r با شعاع داده شدۀ

void ComputeSphere(float& v, float& s, float r);

n = 1 n = 3 n = 6

n = 1 n = 4 n = 9

mohsen_mahyar@yahoo.com

 

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