جلسه پنجم

« توابع»

1-مقدمه

برنامه‌هاي واقعي و تجاري بسيار بزرگ‌تر از برنامه‌هايي هستند که تاکنون بررسي کرديم. براي اين که برنامه‌هاي بزرگ قابل مديريت باشند، برنامه‌نويسان اين برنامه‌ها را به زيربرنامه‌هايي بخش‌بندي مي‌کنند. اين زيربرنامه‌ها «تابع» ناميده مي‌شوند. توابع را مي‌توان به طور جداگانه کامپايل و آزمايش نمود و در برنامه‌هاي مختلف دوباره از آن‌ها استفاده کرد. 

2- توابع كتابخانه‌اي C++ استاندارد

«كتابخانۀ C++ استاندارد» مجموعه‌اي است که شامل توابع‌ از پيش تعريف شده و ساير عناصر برنامه است‌. اين توابع و عناصر از طريق «سرفايل‌ها» قابل دستيابي‌اند.

قبلا برخي از آن‌ها را استفاده كرده‌ايم‌: ثابت INT_MAX که در <climits> تعريف شده ، تابع ()sqrt که در <cmath> تعريف شده است و... .

 

تابع جذر sqrt()

ريشۀ دوم يك عدد مثبت‌، جذر آن عدد است.

تابع مانند يک برنامۀ کامل، داراي ‌روند ورودي - پردازش - خروجي است هرچند که پردازش، مرحله‌اي پنهان است. يعني نمي‌دانيم که تابع روي عدد 2 چه اعمالي انجام مي‌دهد که 41421/1 حاصل مي‌شود.

 

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

#include  // defines the sqrt() function

#include  // 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;

}

براي اجراي يك تابع مانند تابع sqrt() کافي است نام آن تابع به صورت يک متغير در دستورالعمل مورد نظر استفاده شود، مانند زير:

y=sqrt(x);

 

اين کار «فراخواني تابع» يا «احضار تابع» گفته مي‌شود. بنابراين وقتي كد sqrt(x) اجرا شود، تابع sqrt() فراخواني مي‌گردد. عبارت x درون پرانتز «آرگومان» يا «پارامتر واقعي» فراخواني ناميده مي‌شود. در چنين حالتي مي‌گوييم كه x توسط «مقدار» به تابع فرستاده مي‌شود. لذا وقتي x=3 است، با اجراي کد sqrt(x) تابع sqrt() فراخواني شده و مقدار 3 به آن فرستاده مي‌شود. تابع مذکور نيز حاصل 1.73205 را به عنوان پاسخ برمي‌گرداند… 

اين فرايند در نمودار زير نشان داده شده.

 Main()

Image and video hosting by TinyPic

 

متغيرهاي x و y در تابع main() تعريف شده‌اند. مقدار x که برابر با 3 است به تابع sqrt() فرستاده مي‌شود و اين تابع مقدار 1.73205 را به تابع main() برمي‌گرداند. جعبه‌اي كه تابع sqrt() را نشان مي‌دهد به رنگ تيره است، به اين معنا كه فرايند داخلي و نحوۀ کار آن قابل رويت نيست.

 

مثال 2-5 آزمايش يك رابطۀ مثلثاتي

اين برنامه هم از سرفايل استفاده‌ مي‌كند. هدف اين است که صحت رابطۀ Sin2x=2SinxCosx به شکل تجربي بررسي شود.

int main()

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

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

 << 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

برنامۀ مقدار x را در ستون اول، مقدار Sin2x را در ستون دوم و مقدار 2SinxCosx را در ستون سوم چاپ‌ مي‌كند. 

خروجي نشان مي‌دهد که براي هر مقدار آزمايشي x، مقدار Sin2x با مقدار 2SinxCosx برابر است.

 

بيشتر توابع معروف رياضي كه در ماشين‌حساب‌ها هم وجود دارد در سرفايل  تعريف شده است. بعضي از اين توابع در جدول زير نشان داده شده:

مثال

شرح

تابع

acos(0.2) مقدار 1.36944 را برمي‌گرداند

کسينوس معکوسx  (به راديان)

acos(x)

asin(0.2) مقدار 0.201358 را برمي‌گرداند

سينوس معکوس x (به راديان)

asin(x)

atan(0.2) مقدار 0.197396 را برمي‌گرداند

تانژانت معکوس x (به راديان)

atan(x)

ceil(3.141593) مقدار 4.0 را برمي‌گرداند

مقدار سقف x (گرد شده)

ceil(x)

cos(2) مقدار -0.416147 را برمي‌گرداند

کسينوس x (به راديان)

cos(x)

exp(2) مقدار 7.38906 را برمي‌گرداند

تابع نمايي x (در پايه e)

exp(x)

fabs(-2) مقدار 2.0 را برمي‌گرداند

قدر مطلق x

fabs(x)

 

 

floor(3.141593) مقدار 3.0 را برمي‌گرداند

مقدار کف x (گرد شده)

floor(x)

log(2) مقدار 0.693147 را برمي‌گرداند

لگاريتم طبيعي x (در پايه e)

log(x)

log10(2) مقدار 0.30103 را برمي‌گرداند

لگاريتم عمومي x (در پايه 10)

log10(x)

pow(2,3) مقدار 8.0 را برمي‌گرداند

x به توان p

pow(x,p)

sin(2) مقدار 0.909297 را برمي‌گرداند

سينوس x (به راديان)

sin(x)

sqrt(2) مقدار 1.41421 را برمي‌گرداند

جذر x

sqrt(x)

tan(2) مقدار -2.18504 را برمي‌گرداند

تانژانت x (به راديان)

tan(x)

 

 

توجه داشته باشيد که هر تابع رياضي يک مقدار از نوع double را برمي‌گرداند. اگر يك نوع صحيح به تابع فرستاده شود، قبل از اين كه تابع آن را پردازش کند، مقدارش را به نوع double‌ ارتقا مي‌دهد.

 

بعضي از سرفايل‌هاي كتابخانۀ C++ استاندارد که کاربرد بيشتري دارند در جدول زير آمده است:

اين سرفايل‌ها از كتابخانۀ‌ C استاندارد گرفته شده‌اند. استفاده از آن‌ها شبيه استفاده از سرفايل‌هاي C++ استاندارد (مانند ) است. براي مثال اگر بخواهيم تابع اعداد تصادفي rand() را از سرفايل به كار ببريم، بايد دستور پيش‌پردازندۀ زير را به ابتداي فايل برنامۀ‌ اصلي اضافه کنيم:

#include                                                                                                      

شرح

سرفايل

تابع را تعريف مي‌کند

<assert>

توابعي را براي بررسي کاراکترها تعريف مي‌کند

<ctype>

ثابت‌هاي مربوط به اعداد مميز شناور را تعريف مي‌کند

<cfloat>

محدودۀ اعداد صحيح را روي سيستم موجود تعريف مي‌کند

<climits>

توابع رياضي را تعريف مي‌کند

<cmath>

توابعي را براي ورودي و خروجي استاندارد تعريف مي‌کند

<cstdio>

توابع کاربردي را تعريف مي‌کند

<cstdlib>

توابعي را براي پردازش رشته‌ها تعريف مي‌کند

<cstring>

توابع تاريخ و ساعت را تعريف مي‌کند

<ctime>


3- توابع ساخت كاربر

گرچه توابع بسيار متنوعي در کتابخانۀ‌ C++ استاندارد وجود دارد ولي اين توابع براي بيشتر وظايف‌ برنامه‌نويسي كافي نيستند. علاوه بر اين برنامه‌نويسان دوست دارند خودشان بتوانند توابعي را بسازند و استفاده نمايند.

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

يك مثال ساده از توابع ساخت كاربر:

int cube(int x)

{ // returns cube of x:

 return x*x*x;

}

اين تابع، مكعب يك عدد صحيح ارسالي به آن را برمي‌گرداند. بنابراين فراخواني cube(2) مقدار 8 را برمي‌گرداند.

يك تابع ساخت كاربر دو قسمت دارد:

1-عنوان  2- بدنه.

عنوان يك تابع به صورت زير است:

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

مثال:

int cube(int x)

{

بدنه تابع  

}

 

بدنۀ تابع، يك بلوك كد است كه در ادامۀ عنوان آن مي‌آيد. بدنه شامل دستوراتي است كه بايد انجام شود تا نتيجۀ مورد نظر به دست آيد. بدنه شامل دستور return است كه پاسخ نهايي را به مكان فراخواني تابع برمي‌گرداند.

نوع بازگشتي تابع cube() که در بالا تعريف شد، int است. نام آن cube مي‌باشد و يک پارامتر از نوع int به نام x دارد. يعني تابع cube() يک مقدار از نوع int مي‌گيرد و پاسخي از نوع int تحويل مي‌دهد.

 

دستور return دو وظيفۀ عمده دارد. اول اين که اجراي تابع را خاتمه مي‌دهد و دوم اين که مقدار نهايي را به برنامۀ فراخوان باز مي‌گرداند. دستور return به شکل زير استفاده مي‌شود:

return expression;

به جاي expression هر عبارتي قرار مي‌گيرد که بتوان مقدار آن را به يک متغير تخصيص داد. نوع آن عبارت بايد با نوع بازگشتي تابع يکي باشد.

عبارت int main() که در همۀ برنامه‌ها استفاده کرده‌ايم يک تابع به نام «تابع اصلي» را تعريف مي‌کند. نوع بازگشتي اين تابع از نوع int است. نام آن main است و فهرست پارامترهاي آن خالي است؛ يعني هيچ پارامتري ندارد.

 

4- برنامۀ آزمون

تنها هدف اين برنامه، امتحان کردن تابع و بررسي صحت کار آن است.

 

وقتي يک تابع مورد نياز را ايجاد کرديد، فورا بايد آن تابع را با يک برنامۀ ساده امتحان کنيد. چنين برنامه‌اي برنامۀ آزمون ناميده مي‌شود.

برنامۀ آزمون يک برنامۀ موقتي است که بايد «سريع و کثيف» باشد؛ 

 يعني:

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

مثال 4-5 يك برنامۀ آزمون براي تابع cube()

کد زير شامل تابع 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; }}

برنامۀ حاضر اعداد صحيح را از ورودي مي‌گيرد و مكعب آن‌ها را چاپ مي‌كند تا اين كه كاربر مقدار 0 را وارد كند.

هر عدد صحيحي که خوانده مي‌شود، با استفاده از کد cube(n) به تابع cube() فرستاده مي‌شود. مقدار بازگشتي از تابع، جايگزين عبارت cube(n) گشته و با استفاده از cout در خروجي چاپ مي‌شود.

دقت كنيد كه تابع cube() در بالاي تابع main() تعريف شده زيرا قبل از اين كه تابعcube() در تابع main() به كار رود، كامپايلر C++ بايد در بارۀ‌ آن اطلاع حاصل كند.

 

مي‌توان رابطۀ بين تابع main() و تابع cube() را شبيه اين شکل تصور نمود:

Image and video hosting by TinyPic

 

مثال 5-5 يك برنامۀ آزمون براي تابع max()

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

int max(int x, int y)

{ // returns larger of the two given integers:

 int z;

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

 return z;

}

int main()

{ int m, n;

 do

 { cin >> m >> n;

 cout << "\tmax(" << m << "," << n << ") = " << max(m,n) << endl; }

 while (m != 0);}

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

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- اعلان‌ها و تعاريف تابع

به دو روش ميتوان توابع را تعريف نمود:

1-توابع قبل از تابع main() به طور كامل با بدنه مربوطه آورده شوند.

2-راه ديگري که بيشتر رواج دارد اين گونه است که ابتدا تابع اعلان شود، سپس متن برنامۀ اصليmain() بيايد، پس از آن تعريف کامل تابع قرار بگيرد.

اعلان تابع با تعريف تابع تفاوت دارد.

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

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

 

يک متغير قبل از اين که به کار گرفته شود بايد اعلان شود. تابع هم همين طور است با اين فرق که متغير را در هر جايي از برنامه مي‌توان اعلان کرد اما تابع را بايد قبل از برنامۀ اصلي اعلان نمود.

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

 همين‌ها براي کامپايلر کافي است تا بتواند کامپايل برنامه را آغاز کند. سپس در زمان اجرا به تعريف بدنۀ تابع نيز احتياج مي‌شود که اين بدنه در انتهاي برنامه و پس از تابع main() قرار مي‌گيرد.

فرق بين «آرگومان» و «پارامتر» :

پارامترها متغيرهايي هستند که در فهرست پارامتر يک تابع نام برده مي‌شوند.

 پارامترها متغيرهاي محلي براي تابع محسوب مي‌شوند؛ يعني فقط در طول اجراي تابع وجود دارند. 

آرگومان‌ها متغيرهايي هستند که از برنامۀ اصلي به تابع فرستاده مي‌شوند.

 

مثال 6-5 تابعmax() با اعلان‌ جدا از تعريف آن

اين برنامه همان برنامۀ آزمون تابع max() در مثال 5-6 است. اما اين‌جا اعلان تابع بالاي تابع اصلي ظاهر ‌شده و تعريف تابع بعد از برنامۀ اصلي آمده است:

 

int max(int,int);

int main()

{ 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;}

توجه كنيد كه پارامترهاي x و y در بخش عنوان تعريف تابع آمده‌اند (طبق معمول) ولي در اعلان تابع وجود ندارند.