Download presentation
Presentation is loading. Please wait.
1
بسم الله الرحمن الرحيم
2
تهيه كننده: دکتر حسن توکلی
برنامه سازي تعداد واحد: 3 تهيه كننده: دکتر حسن توکلی
3
جلسه پنجم « توابع»
4
آنچه در اين جلسه مي خوانيد:
1- توابع كتابخانهاي C++ استاندارد 2- توابع ساخت كاربر 3- برنامۀ آزمون 4- اعلانها و تعاريف تابع 5- كامپايل جداگانۀ توابع 6- متغيرهاي محلي، توابع محلي ›››
5
››› 7- تابع void 8 - توابع بولي 9- توابع ورودي/خروجي (I/O)
10- ارسال به طريق ارجاع (آدرس) 11- ارسال از طريق ارجاع ثابت 12-توابع بيواسطه ›››
6
13- چندشکلي توابع 14- تابع main() 15- آرگومانهاي پيشفرض
7
››› هدف کلي: شناخت و معرفي توابع و مزاياي استفاده از تابع در برنامهها
هدفهاي رفتاري: انتظار ميرود پس از پايان اين جلسه بتوانيد: - اهميت توابع و مزيت استفاده از آنها را بيان کنيد. - «اعلان» و «تعريف» تابع را بدانيد و خودتان توابعي را ايجاد کنيد. - «برنامۀ آزمون» را تعريف کرده و دليل استفاده از آن را بيان نماييد. - مفهوم «آرگومان» را بدانيد. - تفاوت ارسال به طريق «ارجاع» و ارسال به طريق «مقدار» و ارسال به طريق «ارجاع ثابت» را بيان کنيد و شکل استفاده از هر يک را بدانيد. هدف کلي: شناخت و معرفي توابع و مزاياي استفاده از تابع در برنامهها ›››
8
- «تابع بيواسطه» را شناخته و نحوۀ معرفي آن را بدانيد.
- چندشکلي توابع را تعريف کنيد و شيوۀ آن را بدانيد. - طريقۀ بهکارگيري آرگومانهاي پيشفرض را بدانيد. - فرق بين تابع void با ساير توابع را بدانيد.
9
1-مقدمه برنامههاي واقعي و تجاري بسيار بزرگتر از برنامههايي هستند که تاکنون بررسي کرديم. براي اين که برنامههاي بزرگ قابل مديريت باشند، برنامهنويسان اين برنامهها را به زيربرنامههايي بخشبندي ميکنند. اين زيربرنامهها «تابع» ناميده ميشوند. توابع را ميتوان به طور جداگانه کامپايل و آزمايش نمود و در برنامههاي مختلف دوباره از آنها استفاده کرد.
10
2- توابع كتابخانهاي C++ استاندارد
قبلا برخي از آنها را استفاده كردهايم: ثابت INT_MAX که در <climits> تعريف شده ، تابع ()sqrt که در <cmath> تعريف شده است و... .
11
تابع جذر sqrt() ريشۀ دوم يك عدد مثبت، جذر آن عدد است. تابع مانند يک برنامۀ کامل، داراي روند ورودي - پردازش - خروجي است هرچند که پردازش، مرحلهاي پنهان است. يعني نميدانيم که تابع روي عدد 2 چه اعمالي انجام ميدهد که 41421/1 حاصل ميشود.
12
برنامۀ سادۀ زير، تابع از پيش تعريف شدۀ جذر را به کار ميگيرد:
#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; } براي اجراي يك تابع مانند تابع sqrt() کافي است نام آن تابع به صورت يک متغير در دستورالعمل مورد نظر استفاده شود، مانند زير: y=sqrt(x);
13
اين کار «فراخواني تابع» يا «احضار تابع» گفته ميشود
اين کار «فراخواني تابع» يا «احضار تابع» گفته ميشود. بنابراين وقتي كد sqrt(x) اجرا شود، تابع sqrt() فراخواني ميگردد. عبارت x درون پرانتز «آرگومان» يا «پارامتر واقعي» فراخواني ناميده ميشود. در چنين حالتي ميگوييم كه x توسط «مقدار» به تابع فرستاده ميشود. لذا وقتي x=3 است، با اجراي کد sqrt(x) تابع sqrt() فراخواني شده و مقدار 3 به آن فرستاده ميشود. تابع مذکور نيز حاصل را به عنوان پاسخ برميگرداند…
14
Main() … اين فرايند در نمودار زير نشان داده شده. Sqrt() int 3 x 3 y double متغيرهاي x و y در تابع main() تعريف شدهاند. مقدار x که برابر با 3 است به تابع sqrt() فرستاده ميشود و اين تابع مقدار را به تابع main() برميگرداند. جعبهاي كه تابع sqrt() را نشان ميدهد به رنگ تيره است، به اين معنا كه فرايند داخلي و نحوۀ کار آن قابل رويت نيست.
15
{ for (float x=0; x < 2; x += 0.2)
مثال 2-5 آزمايش يك رابطۀ مثلثاتي اين برنامه هم از سرفايل <cmath> استفاده ميكند. هدف اين است که صحت رابطۀ 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; }
16
خروجي برنامه: برنامۀ مقدار x را در ستون اول، مقدار Sin2x را در ستون دوم و مقدار 2SinxCosx را در ستون سوم چاپ ميكند. خروجي نشان ميدهد که براي هر مقدار آزمايشي x، مقدار Sin2x با مقدار 2SinxCosx برابر است.
17
بيشتر توابع معروف رياضي كه در ماشينحسابها هم وجود دارد در سرفايل <cmath> تعريف شده است. بعضي از اين توابع در جدول زير نشان داده شده: مثال شرح تابع acos(0.2) مقدار را برميگرداند کسينوس معکوسx (به راديان) acos(x) asin(0.2) مقدار را برميگرداند سينوس معکوس x (به راديان) asin(x) atan(0.2) مقدار را برميگرداند تانژانت معکوس x (به راديان) atan(x) ceil( ) مقدار 4.0 را برميگرداند مقدار سقف x (گرد شده) ceil(x) cos(2) مقدار را برميگرداند کسينوس x (به راديان) cos(x) exp(2) مقدار را برميگرداند تابع نمايي x (در پايه e) exp(x) fabs(-2) مقدار 2.0 را برميگرداند قدر مطلق x fabs(x)
18
floor(3.141593) مقدار 3.0 را برميگرداند
مقدار کف x (گرد شده) floor(x) log(2) مقدار را برميگرداند لگاريتم طبيعي x (در پايه e) log(x) log10(2) مقدار را برميگرداند لگاريتم عمومي x (در پايه 10) log10(x) pow(2,3) مقدار 8.0 را برميگرداند x به توان p pow(x,p) sin(2) مقدار را برميگرداند سينوس x (به راديان) sin(x) sqrt(2) مقدار را برميگرداند جذر x sqrt(x) tan(2) مقدار را برميگرداند تانژانت x (به راديان) tan(x)
19
توجه داشته باشيد که هر تابع رياضي يک مقدار از نوع double را برميگرداند. اگر يك نوع صحيح به تابع فرستاده شود، قبل از اين كه تابع آن را پردازش کند، مقدارش را به نوع double ارتقا ميدهد.
20
#include <cstdlib>
اين سرفايلها از كتابخانۀ C استاندارد گرفته شدهاند. استفاده از آنها شبيه استفاده از سرفايلهاي C++ استاندارد (مانند <iostream> ) است. براي مثال اگر بخواهيم تابع اعداد تصادفي rand() را از سرفايل <cstdlib> به كار ببريم، بايد دستور پيشپردازندۀ زير را به ابتداي فايل برنامۀ اصلي اضافه کنيم: #include <cstdlib> بعضي از سرفايلهاي كتابخانۀ C++ استاندارد که کاربرد بيشتري دارند در جدول زير آمده است: شرح سرفايل تابع <assert> را تعريف ميکند <assert> توابعي را براي بررسي کاراکترها تعريف ميکند <ctype> ثابتهاي مربوط به اعداد مميز شناور را تعريف ميکند <cfloat> محدودۀ اعداد صحيح را روي سيستم موجود تعريف ميکند <climits> توابع رياضي را تعريف ميکند <cmath> توابعي را براي ورودي و خروجي استاندارد تعريف ميکند <cstdio> توابع کاربردي را تعريف ميکند <cstdlib> توابعي را براي پردازش رشتهها تعريف ميکند <cstring> توابع تاريخ و ساعت را تعريف ميکند <ctime>
21
3- توابع ساخت كاربر گرچه توابع بسيار متنوعي در کتابخانۀ C++ استاندارد وجود دارد ولي اين توابع براي بيشتر وظايف برنامهنويسي كافي نيستند. علاوه بر اين برنامهنويسان دوست دارند خودشان بتوانند توابعي را بسازند و استفاده نمايند.
22
مثال 3-5 تابع cube() int cube(int x) { // returns cube of x:
يك مثال ساده از توابع ساخت كاربر: int cube(int x) { // returns cube of x: return x*x*x; } اين تابع، مكعب يك عدد صحيح ارسالي به آن را برميگرداند. بنابراين فراخواني cube(2) مقدار 8 را برميگرداند.
23
يك تابع ساخت كاربر دو قسمت دارد:
1-عنوان بدنه. عنوان يك تابع به صورت زير است: (فهرست پارامترها) نام نوع بازگشتي مثال: int cube(int x) { … بدنه تابع } نوع بازگشتي تابع cube() که در بالا تعريف شد، int است. نام آن cube ميباشد و يک پارامتر از نوع int به نام x دارد. يعني تابع cube() يک مقدار از نوع int ميگيرد و پاسخي از نوع int تحويل ميدهد. بدنۀ تابع، يك بلوك كد است كه در ادامۀ عنوان آن ميآيد. بدنه شامل دستوراتي است كه بايد انجام شود تا نتيجۀ مورد نظر به دست آيد. بدنه شامل دستور return است كه پاسخ نهايي را به مكان فراخواني تابع برميگرداند.
24
دستور return دو وظيفۀ عمده دارد
دستور return دو وظيفۀ عمده دارد. اول اين که اجراي تابع را خاتمه ميدهد و دوم اين که مقدار نهايي را به برنامۀ فراخوان باز ميگرداند. دستور return به شکل زير استفاده ميشود: return expression; به جاي expression هر عبارتي قرار ميگيرد که بتوان مقدار آن را به يک متغير تخصيص داد. نوع آن عبارت بايد با نوع بازگشتي تابع يکي باشد. عبارت int main() که در همۀ برنامهها استفاده کردهايم يک تابع به نام «تابع اصلي» را تعريف ميکند. نوع بازگشتي اين تابع از نوع int است. نام آن main است و فهرست پارامترهاي آن خالي است؛ يعني هيچ پارامتري ندارد.
25
تنها هدف اين برنامه، امتحان کردن تابع و بررسي صحت کار آن است.
4- برنامۀ آزمون تنها هدف اين برنامه، امتحان کردن تابع و بررسي صحت کار آن است. وقتي يک تابع مورد نياز را ايجاد کرديد، فورا بايد آن تابع را با يک برنامۀ ساده امتحان کنيد. چنين برنامهاي برنامۀ آزمون ناميده ميشود. برنامۀ آزمون يک برنامۀ موقتي است که بايد «سريع و کثيف» باشد؛ يعني: لازم نيست در آن تمام ظرافتهاي برنامهنويسي – مثل پيغامهاي خروجي، برچسبها و راهنماهاي خوانا – را لحاظ کنيد.
26
مثال 4-5 يك برنامۀ آزمون براي تابع 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 را وارد كند.
27
ميتوان رابطۀ بين تابع main() و تابع cube() را شبيه اين شکل تصور نمود:
هر عدد صحيحي که خوانده ميشود، با استفاده از کد cube(n) به تابع cube() فرستاده ميشود. مقدار بازگشتي از تابع، جايگزين عبارت cube(n) گشته و با استفاده از cout در خروجي چاپ ميشود. دقت كنيد كه تابع cube() در بالاي تابع main() تعريف شده زيرا قبل از اين كه تابعcube() در تابع main() به كار رود، كامپايلر C++ بايد در بارۀ آن اطلاع حاصل كند. 5 n int 125 cube() main() x ميتوان رابطۀ بين تابع main() و تابع cube() را شبيه اين شکل تصور نمود:
28
مثال 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);}
29
{ // returns larger of the two given integers: if (x < y) return y;
توابع ميتوانند بيش از يک دستور 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 که زودتر اجرا شود مقدار مربوطهاش را بازگشت داده و تابع را خاتمه ميدهد.
30
5- اعلانها و تعاريف تابع
به دو روش ميتوان توابع را تعريف نمود: 1-توابع قبل از تابع main() به طور كامل با بدنه مربوطه آورده شوند. 2-راه ديگري که بيشتر رواج دارد اين گونه است که ابتدا تابع اعلان شود، سپس متن برنامۀ اصليmain() بيايد، پس از آن تعريف کامل تابع قرار بگيرد.
31
اعلان تابع شبيه اعلان متغيرهاست.
اعلان تابع با تعريف تابع تفاوت دارد. اعلان تابع، فقط عنوان تابع است که يک سميکولن در انتهاي آن قرار دارد. تعريف تابع، متن کامل تابع است که هم شامل عنوان است و هم شامل بدنه. اعلان تابع شبيه اعلان متغيرهاست. يک متغير قبل از اين که به کار گرفته شود بايد اعلان شود. تابع هم همين طور است با اين فرق که متغير را در هر جايي از برنامه ميتوان اعلان کرد اما تابع را بايد قبل از برنامۀ اصلي اعلان نمود.
32
در اعلان تابع فقط بيان ميشود که نوع بازگشتي تابع چيست، نام تابع چيست و نوع پارامترهاي تابع چيست.
همينها براي کامپايلر کافي است تا بتواند کامپايل برنامه را آغاز کند. سپس در زمان اجرا به تعريف بدنۀ تابع نيز احتياج ميشود که اين بدنه در انتهاي برنامه و پس از تابع main() قرار ميگيرد.
33
فرق بين «آرگومان» و «پارامتر» :
پارامترها متغيرهايي هستند که در فهرست پارامتر يک تابع نام برده ميشوند. پارامترها متغيرهاي محلي براي تابع محسوب ميشوند؛ يعني فقط در طول اجراي تابع وجود دارند. آرگومانها متغيرهايي هستند که از برنامۀ اصلي به تابع فرستاده ميشوند.
34
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;} مثال 6-5 تابعmax() با اعلان جدا از تعريف آن اين برنامه همان برنامۀ آزمون تابع max() در مثال 5-6 است. اما اينجا اعلان تابع بالاي تابع اصلي ظاهر شده و تعريف تابع بعد از برنامۀ اصلي آمده است: توجه كنيد كه پارامترهاي x و y در بخش عنوان تعريف تابع آمدهاند (طبق معمول) ولي در اعلان تابع وجود ندارند.
35
6- كامپايل جداگانۀ توابع
اغلب اين طور است که تعريف و بدنۀ توابع در فايلهاي جداگانهاي قرار ميگيرد. اين فايلها به طور مستقل کامپايل1 ميشوند و سپس به برنامۀ اصلي که آن توابع را به کار ميگيرد الصاق2 ميشوند. توابع کتابخانۀ C++ استاندارد به همين شکل پيادهسازي شدهاند و هنگامي که يکي از آن توابع را در برنامههايتان به کار ميبريد بايد با دستور راهنماي پيشپردازنده، فايل آن توابع را به برنامهتان ضميمه کنيد. اين کار چند مزيت دارد:
36
1- اولين مزيت «مخفيسازي اطلاعات» است.
2-مزيت ديگر اين است که توابع مورد نياز را ميتوان قبل از اين که برنامۀ اصلي نوشته شود، جداگانه آزمايش نمود. 3-سومين مزيت اين است که در هر زماني به راحتي ميتوان تعريف توابع را عوض کرد بدون اين که لازم باشد برنامۀ اصلي تغيير يابد. 4-چهارمين مزيت هم اين است که ميتوانيد يک بار يک تابع را کامپايل و ذخيره کنيد و از آن پس در برنامههاي مختلفي از همان تابع استفاده ببريد.
37
تابع max() را به خاطر بياوريد
تابع max() را به خاطر بياوريد. براي اين که اين تابع را در فايل جداگانهاي قرار دهيم، تعريف آن را در فايلي به نام max.cpp ذخيره ميکنيم. فايل max.cpp شامل کد زير است: int max(int x, int y) { if (x < y) return y; else return x; } max.cpp
38
حال كافي است عبارت:#include <test
حال كافي است عبارت:#include <test.cpp> را به اول برنامه اصلي وقبل ازmain() اضافه كنيم: #include <test.cpp> int main() { // tests the max() function: int m, n; do { cin >> m >> n; cout << "\tmax(" << m << "," << n << ") = " << max(m,n) << endl; } while (m != 0);}
39
نحوۀ کامپايل کردن فايلها و الصاق آنها به يکديگر به نوع سيستم عامل و نوع کامپايلر بستگي دارد. در سيستم عامل ويندوز معمولا توابع را در فايلهايي از نوع DLL کامپايل و ذخيره ميکنند و سپس اين فايل را در برنامۀ اصلي احضار مينمايند. فايلهاي DLL را به دو طريق ايستا و پويا ميتوان مورد استفاده قرار داد. براي آشنايي بيشتر با فايلهاي DLL به مرجع ويندوز و کامپايلرهاي C++ مراجعه کنيد.
40
6- متغيرهاي محلي، توابع محلي
متغير محلي، متغيري است که در داخل يک بلوک اعلان گردد. اين گونه متغيرها فقط در داخل همان بلوکي که اعلان ميشوند قابل دستيابي هستند. چون بدنۀ تابع، خودش يک بلوک است پس متغيرهاي اعلان شده در يک تابع متغيرهاي محلي براي آن تابع هستند. اين متغيرها فقط تا وقتي که تابع در حال کار است وجود دارند. پارامترهاي تابع نيز متغيرهاي محلي محسوب ميشوند.
41
* مثال 7-5 تابع فاكتوريل اعداد فاكتوريل را در مثال 8-5 ديديم. فاكتوريل عدد صحيح n برابر است با: 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 نيز محلي است زيرا درون بدنۀ تابع اعلان شده است.
42
همان گونه که متغيرها ميتوانند محلي باشند، توابع نيز ميتوانند محلي باشند.
يک تابع محلي تابعي است که درون يک تابع ديگر به کار رود. با استفاده از چند تابع ساده و ترکيب آنها ميتوان توابع پيچيدهتري ساخت. به مثال زير نگاه کنيد. تابع محلي در رياضيات، تابع جايگشت را با p(n,k) نشان ميدهند. اين تابع بيان ميکند که به چند طريق ميتوان k عنصر دلخواه از يک مجموعۀ n عنصري را کنار يکديگر قرار داد. براي اين محاسبه از رابطۀ زير استفاده ميشود:
43
اين تابع، خود از تابع ديگري که همان تابع فاکتوريل است استفاده کرده است.
شرط به کار رفته در دستور if براي محدود کردن حالتهاي غير ممکن استفاده شده است. در اين حالتها، تابع مقدار 0 را برميگرداند تا نشان دهد که يک ورودي اشتباه وجود داشته است. پس به 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); }
44
برنامۀ آزمون براي تابع perm() در ادامه آمده است: 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
45
7- تابع void لازم نيست يك تابع حتما مقداري را برگرداند. در C++ براي مشخص کردن چنين توابعي از کلمۀ کليدي void به عنوان نوع بازگشتي تابع استفاده ميکنند يک تابع void تابعي است که هيچ مقدار بازگشتي ندارد. از آنجا كه يك تابع void مقداري را برنميگرداند، نيازي به دستور return نيست ولي اگر قرار باشد اين دستور را در تابع void قرار دهيم، بايد آن را به شکل تنها استفاده کنيم بدون اين که بعد از کلمۀ return هيچ چيز ديگري بيايد: return; در اين حالت دستور return فقط تابع را خاتمه ميدهد.
46
توابع بولي فقط دو مقدار را برميگردانند: true يا false .
8- توابع بولي در بسياري از اوقات لازم است در برنامه، شرطي بررسي شود. اگر بررسي اين شرط به دستورات زيادي نياز داشته باشد، بهتر است که يک تابع اين بررسي را انجام دهد. اين کار مخصوصا هنگامي که از حلقهها استفاده ميشود بسيار مفيد است. توابع بولي فقط دو مقدار را برميگردانند: true يا false . اسم توابع بولي را معمولا به شکل سوالي انتخاب ميکنند زيرا توابع بولي هميشه به يک سوال مفروض پاسخ بلي يا خير ميدهند.
47
{ // returns true if n is prime, false otherwise:
مثال 10-5 تابعي كه اول بودن اعداد را بررسي ميكند کد زير يك تابع بولي است كه تشخيص ميدهد آيا عدد صحيح ارسال شده به آن، اول است يا خير: bool isPrime(int n) { // returns true if n is prime, false otherwise: 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 }
48
9- توابع ورودي/خروجي (I/O)
بخشهايي از برنامه که به جزييات دست و پا گير ميپردازد و خيلي به هدف اصلي برنامه مربوط نيست را ميتوان به توابع سپرد. در چنين شرايطي سودمندي توابع محسوستر ميشود. فرض کنيد نرمافزاري براي سيستم آموزشي دانشگاه طراحي کردهايد که سوابق تحصيلي دانشجويان را نگه ميدارد. در اين نرمافزار لازم است که سن دانشجو به عنوان يکي از اطلاعات پروندۀ دانشجو وارد شود. اگر وظيفۀ دريافت سن را به عهدۀ يک تابع بگذاريد، ميتوانيد جزيياتي از قبيل کنترل ورودي معتبر، يافتن سن از روي تاريخ تولد و ... را در اين تابع پيادهسازي کنيد بدون اين که از مسير برنامۀ اصلي منحرف شويد.
49
مثال بعد يک تابع ورودي را نشان ميدهد.
قبلا نمونهاي از توابع خروجي را ديديم. تابع PrintDate() در مثال 9-5 هيچ چيزي به برنامۀ اصلي برنميگرداند و فقط براي چاپ نتايج به کار ميرود. اين تابع نمونهاي از توابع خروجي است؛ يعني توابعي که فقط براي چاپ نتايج به کار ميروند و هيچ مقدار بازگشتي ندارند. توابع ورودي نيز به همين روش کار ميکنند اما در جهت معکوس. يعني توابع ورودي فقط براي دريافت ورودي و ارسال آن به برنامۀ اصلي به کار ميروند و هيچ پارامتري ندارند. مثال بعد يک تابع ورودي را نشان ميدهد.
50
مثال 11-5 تابعي براي دريافت سن كاربر
تابع سادۀ زير، سن کاربر را درخواست ميکند و مقدار دريافت شده را به برنامۀ اصلي ميفرستد. اين تابع تقريبا هوشمند است و هر عدد صحيح ورودي غير منطقي را رد ميکند و به طور مکرر درخواست ورودي معتبر ميکند تا اين که يک عدد صحيح در محدودۀ 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"; }
51
{ // tests the age() function: int a = age();
يك برنامۀ آزمون و خروجي حاصل از آن در ادامه آمده است: 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 How old are you? 99 You are 99 years old.
52
تا اين لحظه تمام پارامترهايي كه در توابع ديديم به طريق مقدار ارسال شدهاند. يعني ابتدا مقدار متغيري که در فراخواني تابع ذکر شده برآورد ميشود و سپس اين مقدار به پارامترهاي محلي تابع فرستاده ميشود. مثلا در فراخواني cube(x) ابتدا مقدار x برآورد شده و سپس اين مقدار به متغير محلي n در تابع فرستاده ميشود و پس از آن تابع کار خويش را آغاز ميکند. در طي اجراي تابع ممکن است مقدار n تغيير کند اما چون n محلي است هيچ تغييري روي مقدار x نميگذارد.
53
پس خود x به تابع نميرود بلکه مقدار آن درون تابع کپي ميشود.
تغيير دادن اين مقدار کپي شده درون تابع هيچ تاثيري بر x اصلي ندارد. به اين ترتيب تابع ميتواند مقدار x را بخواند اما نميتواند مقدار x را تغيير دهد. به همين دليل به x يک پارامتر «فقط خواندني» ميگويند. وقتي ارسال به وسيلۀ مقدار باشد، هنگام فراخواني تابع ميتوان از عبارات استفاده کرد. مثلا تابع cube() را ميتوان به صورتcube(2*x-3) فراخواني کرد يا به شکل cube(2*sqrt(x)-cube(3)) فراخواني نمود. در هر يک از اين حالات، عبارت درون پرانتز به شکل يک مقدار تکي برآورد شده و حاصل آن مقدار به تابع فرستاده ميشود.
54
10- ارسال به طريق ارجاع (آدرس)
ارسال به طريق مقدار باعث ميشود که متغيرهاي برنامۀ اصلي از تغييرات ناخواسته در توابع مصون بمانند. اما گاهي اوقات عمدا ميخواهيم اين اتفاق رخ دهد. يعني ميخواهيم که تابع بتواند محتويات متغير فرستاده شده به آن را دستکاري کند. در اين حالت از ارسال به طريق ارجاع استفاده ميکنيم.
55
براي اين که مشخص کنيم يک پارامتر به طريق ارجاع ارسال ميشود، علامت را به نوع پارامتر در فهرست پارامترهاي تابع اضافه ميکنيم. اين باعث ميشود که تابع به جاي اين که يک کپي محلي از آن آرگومان ايجاد کند، خود آرگومان محلي را به کار بگيرد. به اين ترتيب تابع هم ميتواند مقدار آرگومان فرستاده شده را بخواند و هم ميتواند مقدار آن را تغيير دهد. در اين حالت آن پارامتر يک پارامتر «خواندني-نوشتني» خواهد بود. &
56
هر تغييري که روي پارامتر خواندني-نوشتني در تابع صورت گيرد به طور مستقيم روي متغير برنامۀ اصلي اعمال ميشود. به مثال زير نگاه کنيد. * مثال 12-5 تابع swap() تابع كوچك زير در مرتب کردن دادهها کاربرد فراوان دارد: void swap(float& x, float& y) { // exchanges the values of x and y: float temp = x; x = y; y = temp; } هدف اين تابع جابجا کردن دو عنصري است که به آن فرستاده ميشوند. براي اين منظور پارامترهاي x و y به صورت پارامترهاي ارجاع تعريف شدهاند: float& x, float& y
57
void swap(float&, float&) // exchanges the values of x and y:
عملگر ارجاع & موجب ميشود كه به جاي x و y آرگومانهاي ارسالي قرار بگيرند. برنامۀ آزمون و اجراي آزمايشي آن در زير آمده است: 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); } a = 55.5, b = 88.8 a = 88.8, b = 55.5
58
هنگام فراخواني تابع swap(a,b)
وقتي فراخواني swap(a,b) اجرا ميشود، x به a اشاره ميکند و y به b. سپس متغير محلي temp اعلان ميشود و مقدار x (که همان a است) درون آن قرار ميگيرد. پس از آن مقدار y (که همان b است) درون x (يعني a) قرار ميگيرد و آنگاه مقدار temp درون y (يعني b) قرار داده ميشود. نتيجۀ نهايي اين است که مقادير a و b با يکديگر جابجا مي شوند. شکل مقابل نشان ميدهد که چطور اين جابجايي رخ ميدهد: هنگام فراخواني تابع swap(a,b) 55.5 a float main() x float& 88.8 b y swap() 88.8 a float swap() main() x float& 55.5 b y temp بعد از بازگشت
59
به اعلان تابع swap() دقت کنيد:
void swap(float&, float&) اين اعلان شامل عملگر ارجاع & براي هر پارامتر است. برنامهنويسان c عادت دارند که عملگر ارجاع & را به عنوان پيشوند نام متغير استفاده کنند (مثلfloat &x) در C++ فرض ميکنيم عملگر ارجاع & پسوند نوع است (مثل float& x) به هر حال کامپايلر هيچ فرقي بين اين دو اعلان نميگذارد و شکل نوشتن عملگر ارجاع کاملا اختياري و سليقهاي است.
60
مثال 13-5 ارسال به طريق مقدار و ارسال به طريق ارجاع
اين برنامه، تفاوت بين ارسال به طريق مقدار و ارسال به طريق ارجاع را نشان ميدهد: void f(int,int&); int main() { int a = 22, b = 44; cout << "a = " << a << ", b = " << b << endl; f(a,b); f(2*a-3,b); cout << "a = " << a << ", b = " << b << endl;} void f(int x , int& y) { x = 88; y = 99;} تابع f() دو پارامتر دارد که اولي به طريق مقدار و دومي به طريق ارجاع ارسال ميشود. فراخواني f(a,b) باعث ميشود که a از طريق مقدار به x ارسال شود و b از طريق ارجاع به y فرستاده شود. a = 22, b = 44 a = 22, b = 99
61
شکل زير نحوۀ کار تابع f() را نشان ميدهد.
22 a int main() x 44 b y int& f() هنگام فراخواني تابع f(a,b) 22 a int main() 88 xx 99 b y int& f() بعد از بازگشت
62
در جدول زير خلاصۀ تفاوتهاي بين ارسال از طريق مقدار و ارسال از طريق ارجاع آمده است.
int& x; int x; پارامتر x يک ارجاع است پارامتر x يک متغير محلي است x مترادف با آرگومان است x يک کپي از آرگومان است ميتواند محتويات آرگومان را تغيير دهد تغيير محتويات آرگومان ممکن نيست آرگومان ارسال شده از طريق ارجاع فقط بايد يک متغير باشد آرگومان ارسال شده از طريق مقدار ميتواند يک ثابت، يک متغير يا يک عبارت باشد آرگومان خواندني-نوشتني است آرگومان فقط خواندني است
63
يكي از مواقعي كه پارامترهاي ارجاع مورد نياز هستند جايي است كه تابع بايد بيش از يك مقدار را بازگرداند. دستور return فقط ميتواند يك مقدار را برگرداند. بنابراين اگر بايد بيش از يك مقدار برگشت داده شود، اين كار را پارامترهاي ارجاع انجام ميدهند.
64
* مثال 14-5 بازگشت بيشتر از يك مقدار
تابع زير از طريق دو پارامتر ارجاع، دو مقدار را بازميگرداند: area و circumference (محيط و مساحت) براي دايرهاي که شعاع آن عدد مفروض r است: void ComputeCircle(double& area, double& circumference, double r) { // returns the area and circumference of a circle with radius r: const double PI = ; area = PI*r*r; circumference = 2*PI*r; }
65
برنامۀ آزمون تابع فوق و يک اجراي آزمايشي آن در شکل زير نشان داده شده است:
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;}
66
12- ارسال از طريق ارجاع ثابت
ارسال پارامترها به طريق ارجاع دو خاصيت مهم دارد: اول اين که تابع ميتواند روي آرگومان واقعي تغييراتي بدهد دوم اين که از اشغال بيمورد حافظه جلوگيري ميشود. روش ديگري نيز براي ارسال آرگومان وجود دارد: ارسال از طريق ارجاع ثابت. اين روش مانند ارسال از طريق ارجاع است با اين فرق که تابع نميتواند محتويات پارامتر ارجاع را دستکاري نمايد و فقط اجازۀ خواندن آن را دارد. براي اين که پارامتري را از نوع ارجاع ثابت اعلان کنيم بايد عبارت const را به ابتداي اعلان آن اضافه نماييم.
67
مثال 15-5 ارسال از طريق ارجاع ثابت
سه طريقه ارسال پارامتر در تابع زير به کار رفته است: void f(int x, int& y, const int& z) { x += z; y += z; cout << "x = " << x << ", y = " << y << ", z = " << z << endl; } در تابع فوق اولين پارامتر يعني x از طريق مقدار ارسال ميشود، دومين پارامتر يعني y از طريق ارجاع و سومين پارامتر نيز از طريق ارجاع ثابت.
68
برنامۀ آزمون و يک اجراي آزمايشي از مثال قبل:
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); f(2*a-3,b,c); } 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 تابع فوق پارامترهاي x و y را ميتواند تغيير دهد ولي قادر نيست پارامتر z را تغيير دهد. تغييراتي که روي x صورت ميگيرد اثري روي آرگومان a نخواهد داشت زيرا a از طريق مقدار به تابع ارسال شده. تغييراتي که روي y صورت ميگيرد روي آرگومان b هم تاثير ميگذارد زيرا b از طريق ارجاع به تابع فرستاده شده.
69
ارسال به طريق ارجاع ثابت بيشتر براي توابعي استفاده ميشود که عناصر بزرگ را ويرايش ميکنند مثل آرايهها يا نمونۀ کلاسها که در جلسههاي بعدي توضيح آنها آمده است. عناصري که از انواع اصلي هستند (مثل int يا float) به طريق مقدار ارسال ميشوند به شرطي که قرار نباشد تابع محتويات آنها را دستکاري کند.
70
13- توابع بيواسطه تابعي که به شکل بيواسطه تعريف ميشود، ظاهري شبيه به توابع معمولي دارد با اين فرق که عبارت inline در اعلان و تعريف آن قيد شده است. مثال 16-5 تابع cube() به شکل بيواسطه اين همان تابع cube() مثال 3-5 است: inline int cube(int x) { // returns cube of x: return x*x*x; } تنها تفاوت اين است كه كلمۀ كليدي inline در ابتداي عنوان تابع ذکر شده. اين عبارت به كامپايلر ميگويد كه در برنامه به جاي cube(n) کد واقعي (n)*(n)*(n) را قرار دهد.
71
. به برنامۀ آزمون زير نگاه کنيد:
int main() { // tests the cube() function: cout << cube(4) << endl; int x, y; cin >> x; y = cube(2*x-3);} اين برنامه هنگام کامپايل به شکل زير درميآيد، گويي اصلا تابعي وجود نداشته: cout << (4) * (4) * (4) << endl; y = (2*x-3) * (2*x-3) * (2*x-3);} احتياط: استفاده از توابع بيواسطه ميتواند اثرات منفي داشته باشد. مثلا اگر يک تابع بيواسطه داراي 40 خط کد باشد و اين تابع در 26 نقطه مختلف از برنامۀ اصلي فراخواني شود، هنگام کامپايل بيش از هزار خط کد به برنامۀ اصلي افزوده ميشود. همچنين تابع بيواسطه ميتواند قابليت انتقال برنامۀ شما را روي سيستمهاي مختلف کاهش دهد. وقتي كامپايلر کد واقعي تابع را جايگزين فراخواني آن ميکند، ميگوييم که تابع بيواسطه، باز ميشود.
72
14- چندشکلي توابع در C++ ميتوانيم چند تابع داشته باشيم که همگي يک نام دارند. در اين حالت ميگوييم که تابع مذکور، چندشکلي دارد. شرط اين کار آن است که فهرست پارامترهاي اين توابع با يکديگر تفاوت داشته باشد. يعني تعداد پارامترها متفاوت باشد يا دست کم يکي از پارامترهاي متناظر هم نوع نباشند.
73
مثال 17-5 چندشکلي تابع max()
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); }
74
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);
75
در اين برنامه سه تابع با نام max() تعريف شده است.
وقتي تابع max() در جايي از برنامه فراخواني ميشود، کامپايلر فهرست آرگومان آن را بررسي ميکند تا بفهمد که کدام نسخه از max بايد احضار شود. مثلا در اولين فراخواني تابع max() دو آرگومان int ارسال شده، پس نسخهاي که دو پارامتر int در فهرست پارامترهايش دارد فراخواني ميشود. اگر اين نسخه وجود نداشته باشد، کامپايلر intها را به double ارتقا ميدهد و سپس نسخهاي که دو پارامتر double دارد را فرا ميخواند.
76
14- تابع main() برنامههايي که تا کنون نوشتيم همه داراي تابعي به نام main() هستند. منطق C++ اين طور است که هر برنامه بايد داراي تابعي به نام main() باشد. در حقيقت هر برنامه کامل، از يک تابع main() به همراه توابع ديگر تشکيل شده است که هر يک از اين توابع به شکل مستقيم يا غير مستقيم از درون تابع main() فراخواني ميشوند.
77
خود برنامه با فراخواني تابع main() شروع ميشود.
چون اين تابع يک نوع بازگشتي int دارد، منطقي است که بلوک تابع main() شامل دستور return 0; باشد هرچند که در برخي از کامپايلرهاي C++ اين خط اجباري نيست و ميتوان آن را ذکر نکرد. مقدار صحيحي که با دستور return به سيستم عامل برميگردد بايد تعداد خطاها را شمارش کند. مقدار پيشفرض آن 0 است به اين معنا که برنامه بدون خطا پايان گرفته است. با استفاده از دستور return ميتوانيم برنامه را به طور غيرمعمول خاتمه دهيم.
78
مثال 18-5 استفاده از دستور return براي پايان دادن به يك برنامه
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; } دستور return تابع فعلي را خاتمه ميدهد و کنترل را به فراخواننده بازميگرداند. به همين دليل است که اجراي دستور return در تابع main() کل برنامه را خاتمه ميدهد. Enter two integers: 99 17 99/17 = 5
79
1 - استفاده از دستور return 2 - فراخواني تابع exit()
چهار روش وجود دارد که بتوانيم برنامه را به شکل غيرمعمول (يعني قبل از اين که اجرا به پايان بلوک اصلي برسد) خاتمه دهيم: 1 - استفاده از دستور return 2 - فراخواني تابع exit() 3 - فراخواني تابع abort() 4 – ايجاد يک حالت استثنا اين تابع در سرفايل <cstdlib> تعريف شده است. تابع exit() براي خاتمه دادن به کل برنامه در هر تابعي غير از تابع main() مفيد است.
80
مثال 19-5 استفاده از تابع exit() براي پايان دادن به برنامه
#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)1 – Exception { // returns the reciprocal of x: if (x = = 0) exit(1); // terminate the program return 1.0/x; } دراين برنامۀ اگر كاربر عدد 0 را وارد کند، تابع reciprocal() خاتمه مييابد و برنامه بدون هيچ مقدار چاپي به پايان ميرسد
81
15- آرگومانهاي پيشفرض
در C++ ميتوان تعداد آرگومانهاي يک تابع را در زمان اجرا به دلخواه تغيير داد. اين امر با استفاده از آرگومانهاي اختياري و مقادير پيشفرض امکانپذير است. براي اين که به يک پارامتر مقدار پيشفرض بدهيم بايد آن مقدار را در فهرست پارامترهاي تابع و جلوي پارامتر مربوطه به همراه علامت مساوي درج کنيم. به اين ترتيب اگر هنگام فراخواني تابع، آن آرگومان را ذکر نکنيم، مقدار پيشفرض آن در محاسبات تابع استفاده ميشود. به همين خاطر به اين گونه آرگومانها، آرگومان اختياري ميگويند.
82
مثال 20-5 آرگومانهاي پيشفرض
double p(double, double, double=0, double=0, double=0); int main() { // tests the p() function: double x = ; 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; مثال 20-5 آرگومانهاي پيشفرض برنامۀ زير حاصل چند جملهاي درجه سوم را پيدا ميکند. براي محاسبۀ اين مقدار از الگوريتم هورنر استفاده شده. به اين شکل که براي کارايي بيشتر، محاسبه به صورت دستهبندي ميشود: p(x,7) = 7 p(x,7,6) = p(x,7,6,5) = – Default p(x,7,6,5,4) =
83
دقت کنيد که پارامترهايي که مقدار پيشفرض دارند بايد در فهرست پارامترهاي تابع بعد از همۀ پارامترهاي اجباري قيد شوند مثل: 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 همچنين هنگام فراخواني تابع، آرگومانهاي ذکر شده به ترتيب از چپ به راست تخصيص مييابند و پارامترهاي بعدي با مقدار پيشفرض پر ميشوند. مثلا در تابع p() که در بالا قيد شد، فراخواني p(8.0,7,6) باعث ميشود که پارامتر x مقدار 8.0 را بگيرد سپس پارامتر a0 مقدار 7 را بگيرد و سپس پارامتر a1 مقدار 6 را بگيرد. پارامترهاي a2 و a3 مقدار پيشفرضشان را خواهند داشت. اين ترتيب را نميتوانيم به هم بزنيم. مثلا نميتوانيم تابع را طوري فرا بخوانيم که پارامترهاي x و a0 و a3 مستقيما مقدار بگيرند ولي پارامترهاي a1 و a2 مقدار پيشفرضشان را داشته باشند.
84
پايان جلسه پنجم
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.