وقتی تابعی توسط تابع دیگر و فراخوانی میشود، دستورات آن تابع اجرا می شوند پس از اجرای دستورات تابع، کنترل اجرای برنامه به برنامه فراخوان برمیگردد. پس از برگشت از تابع فراخوان شده، اولین دستور بعد از فراخوانی تابع اجرا میشود. در این آموزش به روش ارسال پارامتر به توابع می پردازیم.
انواع روش های ارسال پارامتر ها به توابع
پارامترها را به چند طریق می توان از توابع فراخوان به توابع فراخوانی شده ارسال کرد.
- ارسال پارامتر به توابع از طریق مقدار
- ارسال پارامتر به توابع از طریق ارجاع
۱- ارسال پارامتر به توابع از طریق مقدار
در روش ارسال پارامتر به توابع از طریق مقدار، حداکثر یک مقدار را میتوان به قسمتی که از آنجا تابع صدا زده شده است برگرداند هنگامیکـه تـابع صدا زده میشوند مقادیر در متغیرها کپی میشوند و هر گونه تغییر در پارامترها تاثیری بر آرگومانها ندارد. در فراخوانی توسط مقدار، آرگومانهای ارسالی توسط تابع فراخواننده، در پارامترهای متناظر تابع فراخوانی شده، کپی می گردند. بنابراین تابع فراخوانی شده عملیات خود را برروی یک کپی از آرگومانهای ارسالی انجام می دهد. درنتیجه، در صورت انجام هرگونه تغییری برروی این کپی توسط تابع فراخوانی شده، متغیر اصلی در تابع فراخواننده تغییر نخواهد کرد. مزیت این نوع فراخوانی در این است که می توان بدون هیچ نگرانی از تغییر ناخواسته متغیرها، آنها را به هر تابعی ارسال کرد، چرا که فقط یک کپی از آنها به تابع ارسال می شود.
نکته: در زبا ن C، در حالت عادی فراخوانی توسط مقدار صورت می پذیرد.
void test(int a, int b) { printf(“Function test : a=%d and b=%d \n”,a,b); a ++ ; b *= 2; printf(“Function test : a=%d and b=%d \n”,a,b); } void main() { int x, y; x = 10; y = 8; printf(“Function main : x=%d and y=%d \n”,x,y); test(x,y) ; printf(“Function main : x=%d and y=%d \n”,x,y); }
خروجی کد بالا:
Function main : x=10 and y=8 Function test : a=10 and b=8 Function test : a=11 and b=16 Function main : x=10 and y=8
همانگونه آه مشاهده می آنید، گرچه پارامترهای aو b در داخل تابع test تغییر آرده اند، اما پس از بازگشت به تابع فراخواننده یعنی ، main آرگومانهای متناظر به آنها یعنی xو y همچنان همان مقادیر اولیه خود را دارا هستند. شکل زیر نحوه کار را نشان می دهد.
همانطور که گفته شد، این نحوه فراخوانی حالت پیش فرض در زبان C بوده ومعمولا نیز برنامه نویسان ترجیح می دهند از این روش برای ارسال آرگومانها به توابع استفاده نمایند، چرا که متغیرها را در برابر تغییرات ناخواسته در هنگام ارسال به توابع دیگر حفظ می کنند. اما گاهی لازم است که تابع فراخوانی شده بتواند مقدار متغیرهای دریافتی را تغییر دهد، و این تغییرات در متغیرهای اصلی ارسال شده از طرف تابع فراخواننده نیز اعمال شود. در اینصورت باید از روش فراخوانی توسط ارجاع استفاده نماییم.
در روش فراخوانی با مقدار، تعداد مقادیری را که توابع فراخوانی شونده می تواند برگردانند مشخص می کند. در روش فراخوانی توابع با مقدار، دو دسته توابع می تواند وجود داشته باشد:
- توابعی که هیچ مقداری را بر نمی گردانند.
- توابعی که فقط یک مقدار را بر می گردانند.
۱-۱- توابعی که هیچ مقداری را بر نمی گردانند.
ممکن است در برنامه، از توابعی استفاده کنیم که آن توابع، پس از فراخوانی، عملیات مورد نظر را انجام دهند و خروجی هایی مورد انتظار را تولید و چاپ نمایند و هیچ مقداری را به توابع فراخوان تحویل ندهند در بسیاری از مسئلهها که با کامپیوتر حل میشوند، اینگونه توابع به چشم میخورند. در اینجا با ذکر یک مثال به این توابع را مورد بررسی قرار می دهیم.
#include <stdio.h> #include <conio.h> int sqr(int x); void main() { int t=10 ; printf("\n t=%d,square is:",t); printf("%d",sqr(t)); getch(); } int sqr(int x) { int y ; y=x*x; return y; }
خروجی کد بالا:
t=10,aqurare is:100
تابع sqr برای انجام عمل توان نوشته شده است که پارامتر آن x بوده و از نوع صحیح است ( به چگونگی تعریف نوع پارامتر دقت شود ). پس از فراخوانی تابع sqr مقدار آرگومان t در پارامتر x کپی می شود و از این لحظه به بعد هیچ کاری با t نیست. در این تابع، نتیجه عمل در متغیر y قرار می گیرد و سپس توسط دستور return مقدار متغیر y به تابع فراخواننده برگردانده می شود. این مقدار در نام تابع sqr قرار می گیرد.
۱-۲- توابعی که مقداری را بر می گردانند.
در بسیاری از مسئله هایی که توسط کامپیوتر حل میشود، نیاز به نوشتن توابع است که یک مقدار را برگردانند. مثل تابع سینوس که یک زاویه را برمیگرداند. اینگونه توابع کاربردهای فراوانی دارند. برای نوشتن اینگونه توابع، نوع آنها را باید در الگوی تابع و عنوان تابع مشخص کرد.
return (<عبارت>) ;
return <عبارت> ;
تفاوتی بین دو روش کاربرد return وجود ندارد. مقداری که توسط دستور return برگشت داده می شود، در نام توابع قرار میگیرد. در توابع فراخواننده میتوان نام تابع را به متغیری نسبت داد و از محتویات آن استفاده کرد. به عنوان مثال، اگر ()f1 یک تابع از نوع int و x متغیری از نوع int باشد، دستور زیر، تابع ()f1 را فراخوانی میکند. مقداری را که توسط دستور return در نام تابع ()f1 قرار میگیرد، در x قرار میدهد. در اینجا تابع ()f1 فاقد آرگومان می باشد.
x = f1() ;
#include <stdio.h> #include <conio.h> float f(float,float,char); int main(){ clrscr(); float a,b,sub,mul,div; printf("a b?"); scanf("%f%f",&a,&b); sub=f(a,b,'+'); mul=f(a,b,'*'); div=f(a,b,'/'); printf("sub=%f mul=%f div=%f",sub,mul,div); getch(); return 0; } float f(float a,float b,char c){ if (c=='+') return a-b; else if(c=='*') return a*b; else if(c=='/') return a/b; }
۲- ارسال پارامتر به توابع از طریق ارجاع
در روش ارسال پارامتر به توابع به صورت ارجاع، خود آرگومانهای اصلی، به تابع فراخوانی شده ارسال می گردد. در نتیجه، هرگونه تغییری در پارامترهایی تابع فراخوانی شده، مقدار آرگومانهای اصلی در تابع فراخوانی کننده را نیز تغییر خواهد داد. در C اولیه، تنها راه فراخوانی توابع توسط ارجاع، استفاده از متغیرهای اشاره گر بود، اما در استاندارد جدید C ،می توان این کار را به روش ساده تری و با استفاده از متغیرهای ارجاعی انجام داد. یک متغیر ارجاعی، در حقیقت یک نام مترادف و یا یک جایگزین برای یک متغیر دیگر است. برای تعریف یک متغیر ارجاعی از علامت & پس از نوع متغیر مورد ارجاع استفاده می کنیم. بعنوان مثال به نمونه زیر توجه کنید:
#include <stdio.h> void main() { int a = 10; int &r = a; r ++; printf("a=%d and r=%d \n",a,r); a ++; printf("a=%d and r=%d \n",a,r); }
خروجی کد بالا:
a = 11 and r = 11 a = 12 and r = 12
توضیح: مثال فوق نشان می دهد که در حقیقت a و r یک متغیر هستند و هرگونه تغییری در هریک از این دو، دیگری را نیز تغییر خواهد داد.
برای ارسال آرگومانها توسط ارجاع، کافی است پارامترهای تابع مورد نظر را بصورت متغیر ارجاعی تعریف نماییم. در اینصورت، این پارامترها در حقیقت یک ارجاع به آرگومانهای ارسالی خواهند بود و در نتیجه هرگونه تغییری در آنها، آرگومانهای اصلی در تابع فراخوانی آننده را نیز تغییر خواهد داد. بعبارت بهتر، در این روش بجای آنکه یک آپی از آرگومانها در پارامترها قرار گیرد، خود آرگومانها به تابع فراخوانی شده ارسال خواهند شد. بعنوان مثال، همان تابع قسمت قبلی را که بصورت فراخوانی توسط مقدار عمل می کرد، مجددا به روش فراخوانی با ارجاع باز نویسی می کنیم تا تفاوت این دو مشخص گردد:
void test(int &a, int &b) { printf(“Function test : a=%d and b=%d \n”,a,b); a ++ ; b *= 2; printf(“Function test : a=%d and b=%d \n”,a,b); } void main() { int x, y;x = 10; y = 8; printf(“Function main : x=%d and y=%d \n”,x,y); test(x,y) ; printf(“Function main : x=%d and y=%d \n”,x,y); }
خروجی کد بالا:
Function main : x=10 and y=8 Function test : a=10 and b=8 Function test : a=11 and b=16 Function main : x=11 and y=16
همانگونه که مشاهده می کنید، تغییر پارامترهای a و b در داخل تابع test باعث شده آه آرگومانهای متناظر آنها در تابع فراخواننده، یعنی x و y نیز تغییر نمایند. شکل زیر نحوه کار را نشان می دهد.
*برنامه ای که کاراکترهایی را از ورودی خوانده و تشخیص می دهد آیا کاراکتر وارد شده a ، b و یا غیر از این دو حرف بوده است. ضمنا این برنامه قبل از انجام عمل مقایسه، با استفاده از یک تابع کاراکترهای خوانده شده را به حروف کوچک تبدیل می کند (کد اسکی حروف بزرگ درباره ۶۵ و ۹۱ است که اگر به این بازه ۳۲ واحد اضافه شود کد اسکی حروف کوچک حاصل خواهد شد).
#include <stdio.h> #include <conio.h> char getcha(); void main() { char ch ; printf("\n type a character:"); ch=getcha(); switch(ch) { case 'a': printf("\n you typed the"); printf("character ‘a’"); break ; case 'b': printf("\n you typed the"); printf("character ‘b’"); break ; default: printf("\n you typed no ‘a’"); printf("and no ‘b’"); getch(); } } char getcha() { char cl ; cl=getch(); if(cl>64 && cl<91) cl+=32 ; return cl; }
خروجی کد بالا:
type a character : s ‘you typed no ‘a’ and no ‘b