یکی از چیزهایی که شاید برای برنامهنویسهایی که از زبونهایی مثل Fortran یا Pascal میان عجیب به نظر برسه، نحوهی ارسال آرگومانها (arguments) به توابعه.
در زبان C، تمام آرگومانها به تابع بهصورت «Call by Value» (ارسال بر اساس مقدار) فرستاده میشن.
اما این یعنی چی دقیقاً؟
Call by Value یعنی چی؟
وقتی یه تابع در C صدا زده میشه، مقدار آرگومانها به تابع داده میشه، نه خود متغیر اصلی.
به عبارت دیگه، تابع فقط یه کپی از مقدار متغیرها رو دریافت میکنه، نه خود متغیرها.
بنابراین اگه داخل تابع مقدار آرگومان رو تغییر بدیم، تغییری در متغیر اصلی خارج از تابع ایجاد نمیشه.
این دقیقاً برعکسهی چیزی که در زبونهایی مثل Fortran یا Pascal اتفاق میافته، که در اونها تابع به خود متغیر اصلی (Call by Reference) دسترسی داره و میتونه مقدارش رو تغییر بده.
مزیت Call by Value در C
شاید در نگاه اول به نظر برسه که Call by Value یه محدودیت باشه،
اما در واقع یه مزیت بزرگ محسوب میشه
چون باعث میشه:
-
کدها مستقلتر و امنتر بشن.
-
نیازی به تعریف متغیرهای اضافه برای جلوگیری از تداخل نباشه.
-
هر تابع فقط با دادههای خودش کار کنه و به بقیه قسمتها آسیبی نزنه.
در واقع، پارامترهایی که به تابع فرستاده میشن، درست مثل متغیرهای محلی (local variables) عمل میکنن که از قبل مقداردهی شدن.
مثال: تابع power نسخه ۲
بریم سراغ یه مثال تا موضوع کاملاً جا بیفته
/* power: محاسبهی base به توان n (نسخهی دوم) */
int power(int base, int n)
{
int p;
for (p = 1; n > 0; --n)
p = p * base;
return p;
}
توضیح کد بالا
در این نسخهی جدید از تابع power،
دیگه از متغیر کمکی i استفاده نکردیم!
چون از خود پارامتر n بهعنوان شمارندهی حلقه استفاده کردیم.
داخل حلقه، n کم میشه تا زمانی که به صفر برسه.
اما نکتهی جالب اینه که این تغییر فقط روی کپی n داخل تابع اثر داره،
و n اصلی که در تابع main فرستاده شده، هیچ تغییری نمیکنه.
یعنی وقتی power(2, 5) صدا زده میشه،
داخل تابع n از ۵ تا ۰ کم میشه، ولی مقدار 5 در بیرون تابع همون ۵ باقی میمونه.
اگه بخوایم متغیر اصلی رو تغییر بدیم چی؟
گاهی لازمه تابع، مقدار یه متغیر رو مستقیماً در بیرون تابع تغییر بده.
در این حالت باید آدرس متغیر (Pointer) رو به تابع بفرستیم، نه خود مقدارش.
تابع هم باید پارامترش رو از نوع pointer تعریف کنه تا بتونه مقدار واقعی رو از طریق اون آدرس تغییر بده.
مثلاً چیزی شبیه به مثال زیر (فقط برای درک مفهوم، توضیح کامل اشارهگرها در فصل ۵ گفته میشه)
void changeValue(int *x) {
*x = 10; // مقدار اصلی متغیر در بیرون تابع تغییر میکنه
}
اما فعلاً فقط بدون که تا وقتی از Call by Value استفاده میکنی،
تابع فقط با یه کپی از مقدار سر و کار داره، نه خود متغیر.
وضعیت خاص آرایهها (Arrays)
حالا یه نکتهی مهم دربارهی آرایهها
وقتی اسم یه آرایه رو به تابع میفرستی (مثلاً arr)،
در واقع آدرس اولین عنصر آرایه به تابع داده میشه،
نه یه کپی از کل آرایه.
به همین خاطر، اگه داخل تابع یکی از عناصر آرایه رو تغییر بدی،
اون تغییر در بیرون تابع هم اعمال میشه
یعنی آرایهها در واقع بهصورت غیرمستقیم By Reference عمل میکنن.