تماس درباره   صفحه اصلی
  زبان ++C > تابع  
 
 

تابع


توابع در ++C در اين بخش توضيح داده می شود. توابع بلاک های مستقلی از کد هستند که کار خاصی را انجام می دهند. هنگامی که برنامه نياز به انجام آن کار دارد تابع را صدا می زند. تابع اساس برنامه نويسی ساختيافته است که باعث بالارفتن کارائی برنامه ها و آسانتر شدن برنامه نويسی می شود. نحوه ايجاد و فراخوانی تابع به علاوه متغير های محلی و نحوه ارسال و دريافت پارامترهای تابع، توابع پيش ساخته و بازگشتی نيز شرح داده می شود.

تعريف تابع
فراخوانی تابع
دستور return
ارسال مقدار به تابع
متغيرهای محلی
سربارگذاری توابع
توابع پيش ساخته
فايل های ضميمه
توابع بازگشتی


تابع (function) بلاکی ازکد است که تحت يک نام گروه بندی می شود. بدين ترتيب بلاک کد می تواند بعد با استفاده از نامش اجرا شود. اين عمل فراخوانی تابع (function call) ناميده می شود. وقتی تابعی فراخوانی می شود دستورات درون تابع اجرا می شود. در انتهای تابع اجرا به همان محلی که تابع فراخوانی شده بود برمی گردد. ممکن است پارامترهایی به تابع ارسال شود. معمولا تابع معمولا مقداری را به برنامه فراخوان برمی گرداند.

برنامه ای که از تابع استفاده می کند به صورت ساختيافته (structured) است. يعنی وظايف توسط بخش های مستقل انجام می پذيرد. برنامه نويسی ساختيافته روی طراحی به روش top-down تاکيد دارد. در اين روش مسئله به وظايف مختلف تقسيم می شود و هر وظيفه توسط يک تابع انجام می پذيرد. بدنه تایع اصلی کوچک می شود و جزئيات درون توابع قرار می گيرند. به اين ترتيب نوشتن و اشکال زدائی برنامه های پيچيده آسانتر می شود. علاوه بر اين استفاده مجدد توابع در برنامه های ديگر ميسر می شود.

هر تابع بايد تنها يک کار را انجام دهد و از انجام چند کار در يک تابع بايد پرهيز شود.


تعريف تابع

تعريف تابع (function definition) شامل کدهائی است که هنگام فراخوانی تابع بايد اجرا شود. تعريف تابع شامل دو قمت است: اعلان و بدنه. اولين خط تعريف تابع اعلان يا هدر است که اسم تابع، نوع مقدار برگشتی و آرگومان های تابع را مشخص می کند. بعد از هدر بدنه تابع قرار می گيرد. بدنه تابع بلاکی از دستورات است که درون يک جفت آکولاد محصور می شود و هر زمان که تابع فراخوانی می شود اجرا می شود.

فرم کلی تعريف تابع به صورت زير است:

return_type function_name( arg-type name-1,...,arg-type name-n)
{
   /* statements; */
}


مثال. تابع مربع يک عدد.

double square(double n)        /* function header */
{
   return n * n;                    /* function body */
}


اعلان تابع

در تابع مثال فوق خط double square(double n) اعلان تابع است. خط اعلان شامل 3 قسمت است:

1.نوع برگشتی
نوع برگشتی تابع نوع داده مقداری است که توسط تابع محاسبه و به برنامه فراخوان برگردانده می شود. نوع برگشنی می تواند از هر نوع استانداردی باشد. اگر نوع برگشتی تابع قيد نشده باشد از نوع int درنظر گرفته می شود. اگر تابع مقداری را بر نمی گرداند نوع برگشتی آن void بايد تعريف می شود.

2.نام تابع
تابع اولیه که برنامه با آن شروع می شود main نام دارد. بقیه توابع هر نام دلخواهی می توانند بگیرند. نام تابع از قوانین نامگذاری متغیرها تبعیت می کند. بهتر است نام تابع بیان کننده کاری که تابع انجام می دهد باشد. مثلا اگر تابع برای محاسبه مربع یک عدد است نام هایی مثل square_num یا number_square یا num_2 مناسب است.

3.لیست پارامترها
تابع می تواند هیچ، یک یا چند پارامتر داشته باشد. اگر تابعی پارامتر بگيرد به اين معنی است که به مقاديری نياز دارد تا روی آنها کار کند. در مثال تابع مربع، عددی که می خواهید مربع کنید باید به تابع داده شود. این عدد پارامتر تابع است. پارامترها از هر نوع داده ای می تواند باشد.. اگر تابع بيش از يک پارامتر بگيرد پارامترها توسط کاما جدا می شوند و نوع و نام هر پارامتر باید جداگانه مشخص شود. برای اعلان تابعی بدون پارامتر پرانتز بايد خالی بماند.

مثال. تابع زير دارای سه آرگومان x، y و z است.

void func1(int x, float y, char z)

توجه کنيد که در انتهای اعلان تابع علامت سميکولن وجود ندارد واگر گذاشته شود کامپايلر پيغام خطا صادر می شود.

گاهی بين پارامتر و آرگومان اشتباه پيش می آيد. يک پارامتر (parameter) يک محلی در هدر تابع است که برای ذخيره مقدار آرگومان عمل می کند. پارامترهای تابع ثابت هستند و در طی اجرای برنامه تغيير نمی کنند. يک آرگومان مقدار وافعی ارسال شده به تابع توسط دستور فراخوانی است. هر زمان که تابعی فراخوانی می شود آرگومان های مختلف می تواند به آن ارسال شود. درون تابع به آرگومان ها توسط نام پارامترهای متناظر دسترسی می شوند.

بدنه تابع

قسمت دوم تعريف تابع بدنه تابع (function body) است که با آکولاد {} محصور می شود و مشابه بلاکی از کد است. بدنه تابع بلافاصله بعد از اعلان تابع قرار می گيرد. دستورات لازم که برای انجام وظيفه تابع در اينجا نوشته می شود. وقتی تابع فراخوانی می شود اجرای آن از ابتدای بدنه تابع شروع می شود و وقتی به انتهای تابع يا دستور return برسد پايان می پذيرد.

تابع ممکن است مقداری را به فراخواننده خود برگرداند. مقدار برگشتی تابع باید از همان نوعی باشد که در اعلان تابع ذکر شده است در غیر اینصورت با خطای mistake erroe مواجه می شوید.


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

#include <iostream.h>
double square(double n);
int main() {
   double num;
   do {
      cout << "What do you want to know the square "
      << "of (enter 0 to quit): ";
      cin >> num;
      cout << "The square of " << num << " is "
      << square(num) << ".\n";
   } while (num != 0);
}
double square(double n) {
   return n * n;
}


فراخوانی تابع

هر زمان که به تابع نياز باشد نام آن صدا زده می شود. اين عمل فراخوانی تابع ناميده می شود. برنامه يا تابعی ک تابع را فراخوانی می کند فراخواننده تابع (function caller) ناميد می شود. هنگام فراخوانی تابع، مقدار آرگومان های تابع بايد مشخص شود.

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


مثال. تابع square به صورت زير در برنامه اصلی صدا زده می شود.

double sq = square(num);
cout << sq;
يا
cout << square(num);

مثال. فراخوانی تابعی که آرگومانی ندارد. تابع مربع اعداد 1 تا 10 را نمايش می دهد.

#include <iostream.h>
void squares();
main() {
   squares();
}
void squares() {
   int loop;
   for (loop=1;loop < 10;loop++);
      cout << loop*loop;
}


پروتوتايپ تابع

کامپایلر ++C نمی تواند تابعی را صدا بزند که چیزی درباره آن نمی داند. باید قبل از فراخوانی تابع به کامپایلر اجازه دهید بداند تابع چیست و چه کار می کند. یک راه برای انجام این کار اطمینان از نوشتن بدنه تابع قبل از فراخوانی آن است. را ه دیگر استفاده از پروتوتايپ تابع (prototype) است. پروتوتايپ تابع شرحی از نام، نوع برگشتی و نوع آرگومانهای تابع به کامپايلر ارائه می دهد. به اين ترتيب هنگام فراخوانی تابع کامپايلر صحت فراخوانی را بررسی می کند که آيا نوع و تعداد آرگومانهای ارسال شده به تابع و استفاده از مقدار برگشتی صحيح است يا خير.


مثال. پروتوتايپ تابع square.

double square(double n);


پروتوتايپ تابع مشابه اعلان تابع است منتها هميشه به سمیکولن(;) ختم می شود. یعد از تکميل تابع با استفاده از امکانcopy-and-paste اديتور می توانيد هدر تابع را کپی کرده و پروتوتايپ آنرا بسازيد. فقط دقت کنيد در انتهای آن علامت سميکولن را اضافه کنيد.

پروتوتايپ توابع بهتر است در ابتدای برنامه و قبل از تایع اصلی باشند.
در پروتوتايپ اسم متغيرهای آرگومان هم می تواند ذکر شود ولی اختياری است.


دستور return

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

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

تابع ممکن است دارای چند دستور return باشد تا بتواند در شرايط متفاوت مقادير مختلف را برگرداند. در اين صورت اولين دستورreturn که اجرا می شود موثر است.


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

#include <iostream.h>
int larger_of( int , int );
int main() {
   int x, y, z;
   cout <<"Enter two different integer values: ";
   cin >> x >> y;
   z = larger_of(x,y);
   cout << "\nThe larger value is " << z;
   return 0;
}
int larger_of( int a, int b) {
   if (a > b) return a;
   else return b;
}


همان طور که قبلا گفته شده است main هم يک تابع است البته با کمی تفاوت. تابع main نیازی به پروتوتایپ ندارد و اتوماتيک هنگام اجرای برنامه فراخوانی می شود و هرگز در کد برنامه صدا زده نمی شود تابع main يک عدد صحيح را می تواند برگرداند که صفر يا غيرصفر است. اگر اجرای برنامه بطور موفق به انتها رسيده باشد مقدار صفر و در غيراينصورت يک مقدار غيرصفر در مقابل دستور return نوشته می شود.


ارسال مقدار به تابع

وقتی مقداری به تابع ارسال می شود یک کپی از محتویات آرگومان به پارامتر نسبت داده می شود یعنی در اصل پارامتر یک کپی از متغیری است که به تابع ارسال می شود و مقدار آن خارج از تابع تغییر نمی کند. این روش ارسال یک متغیر با مقدار (passing variable by value) نامیده می شود. که روش معمول است. روش دیگر ارسال یک متغیر به تابع به صورت مرجع (called by reference) است. در این حالت به جای یک کپی از مقدار متغیر آدرس آن به تابع داده می شود بنابراين نام متغیر و نام پارامتربه یک مکان حافظه ارجاع می کنند. یعنی پارامتر متغیر جدیدی نیست بلکه همان متغیر قبلی با نام جدید است. در این حالت وقتی متغیر درون تابع تغییر می کند متغیر خارج از تابع هم تغییر می کند.

برای تعيين پارامتری به صورت مرجع کافی است علامت & (عملگر آدرس) قبل از پارامتر تابع در اعلان اضافه شود.


مثال. متغير m به صورت مقداری به تابع ارسال شده است. خروجی تابع عدد 1 است.

#include <iostream.h>
void f(int n) {
   n = 4;
}
int main() {
   int m = 1;
   cout << m << "\n";
   f(m);
   cout << m << "\n";
}

مثال. پارامتر number مرجع است.

#include <iostream.h>
void demo(float &number);
int main () {
   float num1;
   cout << "Please enter a number. \n";
   cin >> num1;
   cout << "Before the demo function your number is " << num1 << "\n";
   demo(num1);
   cout << "After the demo function your number is still " << num1 << "\n";
   return 0;
}
void demo(float &number) {
   number = number * 3;
   cout << "Inside the demo function the number is now " << number << "\n";
}


متغيرهای محلی

متغيرهائی که درون تابع تعريف می شوند متغيرهای محلی (local variables) ناميده می شوند. محلی بر اين دلالت دارد که متغيرها تنها خاص تابع هستند و از متغيرهای هم نام در هر جای ديگر برنامه مجزا می باشند. تابع می تواند هر تغييری روی آنها بدهد بدون اينکه روی قسمت های ديگر برنامه اثر داشته باشد. متغيرهائی که خارج از هر بلاکی تعريف می شوند متغير های سراسری (global variables) ناميده می شوند و در کليه توابع قابل دسترسی هستند.


مثال. در برنامه زير متغير m سراسری است و توسط کليه توابع قابل دسترسی و تغيير است. درحاليکه دو متغير n از هم مستقل هستند و هرکدام تنها درون تابعی که اعلان شده اند تغيير می کنند.

#include <iostream.h>
int m;        // M is a global variable
int f(int n) {
   n++;
   return n;
}
int g() {
   m++;
   return m;
}
int main() {
   int n = 5;
   cout << "n = " << n << "\n";
   cout << "f(n) = " << f(n) << "\n";
   cout << "n = " << n << "\n";
   m = 5;
   cout << "m = " << m << "\n";
   cout << "g() = " << g() << "\n";
   cout << "m = " << m << "\n";
}


سربارگذاری توابع

اکثر زبان های برنامه نويسی برنامه نويس را ملزم می کنند برای هر تابع نام منحصر بفردی را تعريف کنند. ويژگی چندريختی (polymorphism) در زبان ++C اين امکان را فراهم کرده که یک نام برای بیش از یک تابع به طور مشترک استفاده شود. اين عمل سربارگذاری توابع (function overloading) هم ناميده می شود. برای اينکه کامپايلر توابع هم نام را از هم تشخيص دهد نوع و تعداد پارامترهای توابع بايد با هم متقاوت باشد. کامپایلر از نوع آرگومان متوجه می شود کدام تابع فراخوانی شده است.


مثال.

#include <iostream.h>
float cube_number(float num);
int cube_number(int num);
int main() {
   float number;
   float number3;
   cout << "Please enter a number \n";
   cin >> number;
   number3 = cube_number(number);
   cout << number << " cubed is " << number3;
   return 0;
}
int cube_number(int num) {
   return num * num * num;
}
float cube_number(float num) {
   return num * num * num;
}


توابع پيش ساخته

علاوه بر توابع متعددی که می توانید بسازید ++C توابع آماده مفیدی را در اختيار می گذارد. توابع پيش ساخته (built-in functios) يا کتابخانه ای توابعی هستند که می توانيد از آنها در برنامه استفاده کنيد. برای استفاده از يک تابع کتابخانه ای ابتدا تابع و شرح آنرا را از مراجع برنامه نو‍یسی پيدا کنيد. هر تابع کتابخانه ای دارای يک هدر فايل است که پروتوتايپ تابع را دربردارد و توسط دستور include# با‍يد به برنامه ضميمه شود. تابع را طبق گرامر آن فراخوانی کنيد. اگر در فراخوانی تابع اشتباهی وجود داشته باشد کامپايلر پيغام خطا می دهد.

توابع ریاضی

هدرفايلشرحتابع
<math.h> یک زاویه را گرفته کسینوس آنرا می دهد double cos(double);
<math.h> یک زاویه را گرفته سینوس آنرا می دهد double sin(double);
<math.h> یک زاویه را گرفته تانژانت آنرا می دهد double tan(double);
<math.h> یک عدد را گرفته لگاریتم طبیعی آنرا بر می گرداند double log(double);
<math.h> عدد اولی را به توان دومی می رساند double pow(double,double);
<math.h> دو ضلع مثلث قائم الزاویه را گرفته و طول وتر را می دهد double hypot(double,double);
<math.h> ریشه دوم عدد صحیح را برمی گرداند double sqrt(double);
<math.h> قدرمطلق یک عدد صحیح را برمی گرداند int abs(int);
<math.h> قدرمطلق يک عدد اعشاری را برمی گرداند double fabs(double);
<math.h> بزرگترين عدد صحیحی که کمتر یا مساوی آرگومان باشد را برمی گرداند double floor(double);
<math.h> کوچکترين عدد صحیحی که بيشتر یا مساوی آرگومان باشد را برمی گرداند double ceil(double);
هدرفايلشرحتابع
<stdlib.h> یک عدد صحیح را به معادل کاراکتری تبدیل می کند. Radix مبنای عدد صحیح است char *itoa(int value, char *buffer, int radix)
<stdlib.h> یک کاراکتر را به یک عدد صحیح معادل تبدیل می کند int atoi(const char *string);
<ctype.h> کاراکتر را به حالت کوچک تبدیل می کند int tolower(int c);
<ctype.h> کاراکتر را به حالت بزرگ تبدیل می کند int toupper(int c);
<string.h> ههر چیزی که در source باشد در مقصد کپی می کند. Size تعداد کپی را معین می کند void *memcpy(*destination, *source, size)
<string.h> distination را با کارکتری که در replacement قرار دارد تنظیم می کند void *memset(*destination, replacement, size)

عملگر & با تابع itoa بکار می رود. x=itoa(&a);


مثال. memcpy و memset اکثرا برای داده هائی مانند ساختمان و آرايه بکار می روند. برنامه زير آرايه x را در y کپی می کند.

#include <iostream.h>
#include <string.h>
int main() {
   int x[10]={1,2,4,6,6,9,0,11,7,2};
   int y[10];
   memcpy(x,y,10);
   return 0;
}


توابع زمان

با اضافه کردن فایل هدر time می توان به توابع زمان دسترسی پیدا کرد. برخی توابع پر استفاده در جدول زیر آمده است:

هدرفايلشرحتابع
<time.h> تعداد ثانیه های سپری شده از ساعت 00:00 اول ژانویه 1970 را می دهد time_t time(time_t *time);
<time.h> زمان را به ساختمان tm با ساعت محلی تبدیل می کند struct tm *localtime(const time_t *time);
<time.h> تفاوت دو زمان را می دهد double difftime(time_t time2,time_1 time1);
<time.h> تایمر را به ساختمان tm با ساعت GMT تبدیل می کند struct tm *gmttime(const time_t *time);
<time.h> زمان را به رشته ای شامل ساعت و تاریخ متناسب با زمان محلی در فرمت خوانا تبدیل می کند. Char *ctime(const time_t *time);

مثال. برنامه زير ساعت و تاريخ جاری سيستم را می دهد.

#include <ctime.h>
#include <iostream.h>
int main () {
   time_t rawtime;
   time ( &rawtime );
   cout << "Current date and time is: "<< ctime (&rawtime);
   return 0;
}


توابع اعداد تصادفی

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

هدرفايلشرحتابع
<stdlib.h> يک عدد تصادفی بين 0 و RAND_MAX را بر می گرداند. int rand(void);
<stdlib.h> يک عدد تصادفی بين 0 و n-1 را بر می گرداند. int random(int n);
<stdlib.h> , <time.h> تولید اعداد تصادفی در هر اجرا srand ((time(NULL));

مثال. برنامه زير 10 عدد تصادفی را نمايش می دهد.

#include <time.h>
#include <iostream.h>
#include <stdlib.h>
int main() {
   int i,j;
   srand(time(NULL));
   for( i = 0;i < 10;i++ ){
      j= rand();
      cout << j << endl; }
   return 0;
}


فايل های ضميمه

همانطور که در قسمت قبل مشاهده کرديد ++C تعداد زيادی تابع کتابخانه ای دارد. شما هم می توانيد توابع خود را درون يک فايل کتابخانه ای جمع کنيد. اگر قصد داريد يک فايل کتابخانه بسازيد ابتدا يک فايل هدر برای پروتوتايپ های کليه توابع کتابخانه خود بسازيد و با پسوند .h ذخيره کنيد. اگر اين فايل در فولدر جاری باشد توسط دستور #include "header.h" يا اگر در فولدر INCLUDE کامپايلر باشد توسط #include <header.h> پيدا می شود. سپس کليه توابع را به يک فايل کتابخانه منتقل کنيد. توابع کتابخانه ای معمولا انشعاب .lib يا .a را دارند.


برنامه ای شامل فايل کتابخانه ای و هدر فايل


توابع بازگشتی

اين امکان وجود دارد که يک تابع خودش را صدا بزند. در اين حالت تابع را بازگشتی (recursive) می نامند. يک تابع بازگشتی بايد دارای شرطی باشد که به ازای آن خود را فراخوانی نمی کند. روش بازگشتی برای مسائلی استفاده می شود که مسئله اصلی می تواند به نسخه های کوچک تری از نسخه اصلی شکسته شود.


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

#include <iostream.h>
void recursive_function(int start, int end) {
   if (start < end) {
      cout << start << " ";
      recursive_function(start + 1, end); }
}
int main() {
   recursive_function(1, 10);
   return 0;
}


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

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

0! = 1
n! = n * (n-1) * (n-2) * ... * 2 * 1 for n > 0

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

long factorial(int n) {
   int k;
   long result = 1;
   for (k = 2; k <= n; k++)
      result = result * k;
   return result;
}

اما تابع فاکتوريل را به صورت زير نيز می تواند تعريف کرد:

0! = 1
n! = n * (n-1)! for n > 0

که با توجه ضابطه فوق تابع بازگشتی آن به صورت زير نوشته می شود:

long factorial(int n) {
   if ((n == 0) || (n == 1))   // stopping cases
      return 1;
   else           // recursive case
      return n * factorial(n - 1);
}

تابع بازگشتی معروف ديگر فيبوناچی است که ضابطه آن صورت زير است:

fib(0) = 1
fib(1) = 1
fib(n) = fib(n-1) + fib(n-2) for n > 1

تابع بازگشتی فيبوناچی به صورت زير است:

long fib(int n) {
   if ((n == 0) || (n == 1))   // stopping cases
      return 1;
   else           // recursive case
      return fib(n - 1) + fib(n - 2);
}


 


 


صفحه اصلی| PDF| درباره| تماس