در زبان C، وقتی که نام آرایه به عنوان آرگومان تابع ظاهر میشود، آدرس اولین عنصر آرایه تعبیر میگردد. بنابراین هنگامی که آرایهای را به عنوان آرگومان به تابع گذر یا انتقال میدهیم، تمامی آرایه به آن تابع انتقال مییابد. این روش انتقال آرگومان به تابع، با آنچه در مورد انتقال متغیرهای معمولی به تابع در فصل مربوط به توابع بیان شد و فراخوانی با مقدار نامیدیم متفاوت است. روش فراخوانی جدید را فراخوانی با آدرس یا فراخوانی با ارجاع نامند. در این روش به جای کپی دادهها، آدرس آنها به تابع انتقال مییابد.
برای گذر دادن آرایهای به تابع باید فقط نام آن بدون کروشه و بدون اندیس، به عنوان آرگومان واقعی، در فراخوانی تابع ظاهر گردد. در تعریف تابع نیز باید آرگومان فرمال متناظر آن به همان طریق نوشته شود و به عنوان آرایه تعریف گردد. بدین طریق که نام آرایه همراه با یک زوج کروشه بدون اندیس نوشته شود و نوع داده آن نیز مشخص گردد.
مثال ۷ـ۷ قطعه برنامه زیر نحوه فرستادن یا گذردادن آرایه را به تابع نشان میدهد.
main()
{
int n ; /* variable declaration */
float avg ; /* variable declaration */
float list [100] ; /* array definition */
float average () ; /* function declaration */
….
avg = average (n , list) ;
….
}
float average (a , x) /* function definition */
int a ; /* formal argument declaration */
float x[ ] ; /* formal argument (array) declaration */
{
….
}
ملاحظه میکنید که تابع فرعی average در داخل تابع اصلی فراخوانده شده است. این تابع دارای دو آرگومان است: یکی متغیر n که نوع آن int و معرف تعداد عناصر آرایه است. دیگری آرایه یکبعدی list که نوع عناصر آن float است. همچنین میبینید که در فراخوانی تابع، آرایه list به صورت متغیر ساده ظاهر شده است.
در تعریف تابع نیز در سطر اول دو آرگومان فرمال را که a و x نامیده شدهاند مشاهده میکنید. سپس در دو سطر بعدی دو آرگومان مزبور به ترتیب بهصورت int و آرایه یکبعدی از نوع float توصیف شدهاند. ملاحظه میکنید که بین آرگومان واقعی n و آرگومان فرمال a تناظر وجود دارد. به طریق مشابه تناظری بین آرگومان واقعی list و آرگومان فرمال x وجود دارد. در واقع لازم نیست که آرگومانهای واقعی با آرگومانهای فرمال همنام باشند و به همین دلیل آرگومانهای فرمال را متغیرهای مجازی یا ساختگی نیز مینامند. همچنین ملاحظه میکنید که بزرگی آرایه x، در توصیف آرگومان فرمال، مشخص نشده است. همین طور مشاهده میکنید که در تعریف تابع به صورت پیشنمونه یا prototype در تابع اصلی، پس از نام تابع فقط یک زوج پرانتز تهی به کار رفته است.
حال اگر در تعریف تابع فرعی، توصیف آرگومانهای آن نیز در همان خط اول تابع، پس از ذکر نام تابع در درون زوج پرانتز انجام گیرد، باید در تعریف پیشنمونه در تابع اصلی نیز این تناظر محفوظ بماند؛ یعنی باید پس از نام تابع آرگومانهای آن نیز در درون زوج پرانتز توصیف گردند (برخلاف حالت قبل که فقط یک زوج پرانتز تهی به کار میرفت). قطعه برنامه زیر همان مثال قبلی را با این شیوه نشان میدهد.
main
{
int n ; /* variable declaration */
float avg ; /* variable declaration */
float list [100] ; /* array definiation */
float average (int , float[ ]) ; /* function declaration */
….
avg = average (n , list) ;
….
}
float average (int a , float x [ ]) /* function definition */
{
….
….
}
در انتقال نام آرایه به تابع، آدرس اولین عنصر آرایه به تابع منتقل میشود؛ یعنی نام آرایه، آدرس اولین عنصر آرایه تفسیر میشود. وقتی که تابع فراخوانی میشود، این آدرس به آرگومان فرمال متناظر آن اختصاص مییابد. پس آرگومان مزبور به عنوان اشارهگر به اولین عنصر آرایه برمیگردد. بنابراین هر عملی که در تابع فرعی روی آرایه انجام گیرد، نتیجه آن در تابع اصلی (یا تابع فراخواننده) نیز منعکس میشود. به طوری که بیان شد، این شیوه فراخوانی تابع را فراخوانی با آدرس نامند.
وقتی که در درون تابع فراخوانده شده به عنصر آرایه مراجعه میشود، اندیس عنصر مورد نظر به مقدار اشارهگر افزوده میگردد تا به آدرس آن عنصر در درون آرایه دلالت نماید. پس هر عنصری از آرایه به سادگی در درون تابع در دسترس قرار میگیرد و به طوری که گفتیم هر عنصر آرایه که در درون تابع تغییر یابد، اثر این تغییر در تابع فراخواننده نیز منعکس خواهد شد.
مثال ۷ـ۸ برنامه زیر برنامه سادهای را نشان میدهد که آرایهای ۳ عنصری را به تابع گذر میدهد و مقادیر عنصر آرایه در درون آن تابع تغییر مییابد. مقادیر عناصر آرایه در سه موقعیت از برنامه نوشته شده است تا اثر این تغییرات را نشان دهد.
# include<stdio.h>
main ()
{
int count , a [3] ; /* array definition */
void modify (int a[ ]) ; / * function declaration */
printf(“\n from main , before calling the function: \n”) ;
for (count = 0 ; count<=2 ; + + count)
{
a[count] = count + 1 ;
printf (“a[%d] = %d\n” , count , a[count]) ;
}
modify(a) ;
printf (“\n from main , after calling the function: \n”) ;
for (count = 0 ; count<=2 ; ++ count)
printf (“a[%d] = %d\n” , count , a[count]) ;
}
void modify (int a[ ]) /* function definition */
{
int count ;
printf (“\n from the function , after modifying the values: \n”) ;
for (count = 0 ; count< = 2 ; ++ count)
{
a[count] = -9 ;
printf (“a[%d] = %d” , count , a [count]) ;
}
return ;
}
در اولین حلقهای که در درون تابع اصلی ظاهرمیگردد، مقادیرa [0] = 1 , a [1] = 2 , a [2] = 3 به عناصر آرایه نسبت داده میشود و همین مقادیر با دستورprintf نمایش مییابد. سپس، آرایه مزبور به تابع modify گذر داده میشود که در درون تابع مزبور به هریک از عناصر آرایه مقدار ۹- نسبت داده میشود. سپس همین مقادیر جدید در آن تابع چاپ میگردد. بالاخره پس از برگشت کنترل از تابع فرعی به تابع اصلی، دوباره مقادیر عناصر آرایه نمایش مییابد.
اگر برنامه مزبور اجرا گردد، خروجی زیر را خواهیم داشت.
from main , before calling the function:
a [0] = 1
a [1] = 2
a [2] = 3
from the function , after modifying the values:
a [0] = -9
a [1] = -9
a [2] = -9
from main , after calling the function:
a [0] = -9
a [1] = -9
a [2] = -9
این نتایج نشان میدهد که تغییرات اعمال شده با تابع modify روی آرایه، در تابع اصلی نیز منعکس شده است.