در توابع بازگشتی شما باید در هر مرحله از اجرای تابع، مقادیر فعلی پارامتر های آن تابع را در خاطر بسپارید، تابع را مجددا
با مقادیر جدیدی اجرا کنید و وقتی اجرای تابع داخلی تمام شد، دوباره همان مقدار پارامتر های قبلی را بکار بگیرید.
اول با یک مثال ساده تر شروع کنیم.
فرض کنید ما تابعی داریم به نام test که مقدار x را چاپ می کند و اگر x از یک بزرگتر بود تابع را برای x - 1 هم اجرا می کند :
کد:
void test(int x)
{
printf("%d\n", x);
if (x > 1)
test(x - 1)
}
حالا اگر ما این تابع را با مقدار ورودی 3 اجرا کنیم (مراحل را با حروف انگلیسی مشخص کردم) :
َA: اول مقدار x (یعنی مقدار 3) چاپ می شود.
A: چون x از 1 بزرگتر است تابع با مقدار ورودی 2 اجرا می شود :
B: اول مقدار x (یعنی مقدار 2) چاپ می شود.
B: چون x از 1 بزرگتر است تابع با مقدار ورودی 1 اجرا می شود :
C: اول مقدار x (یعنی مقدار 1) چاپ می شود.
C: چون x از 1 بزرگتر نیست تابع دیگر اجرا نمی شود.
پس در نهایت در این مثال ما مقدار 321 را در خروجی چاپ کرده ایم.
خب حالا اگر ما جای سطر printf را عوض کنیم، اول اگر x از یک بزرگتر بود تابع را برای x - 1 هم اجرا می کند، و بعد مقدار
x را چاپ می کند :
کد:
void test(int x)
{
if (x > 1)
test(x - 1)
printf("%d\n", x);
}
حالا این تابع تغییر یافته را با مقدار ورودی 3 اجرا می کنیم :
A: چون x از 1 بزرگتر است تابع با مقدار ورودی 2 اجرا می شود :
B: چون x از 1 بزرگتر است تابع با مقدار ورودی 1 اجرا می شود :
C: چون x از 1 بزرگتر نیست تابع دیگر اجرا نمی شود.
C: مقدار x (یعنی مقدار 1) چاپ می شود.
B: مقدار x (یعنی مقدار 2) چاپ می شود.
A: مقدار x (یعنی مقدار 3) چاپ می شود.
پس در نهایت در این مثال ما برعکس مقدار پیشین یعنی مقدار 123 را در خروجی چاپ کرده ایم.
این مثال نشان می دهد که اگر جای دو سطر در تابع بازگشتی عوض شود، چقدر روی نتیجه خروجی تاثیر دارد.
خب حالا کد برنامه شما رو با همون عدد 123 مرحله به مرحله تحلیل می کنیم :
کد:
void write_v(int x)
{
if (x < 10)
printf("%d\n", x);
else
{
write_v(x / 10);
printf("%d\n", x % 10);
}
}
A: در مرحله اول x با مقدار 123 وارد تابع write_v میشه. x ما از 10 کوچکتر نیست، پس قسمت else شرط if اجرا میشه.
A: ما در قسمت else دو تا فرمان داریم که اولی اش فراخوانی مجدد تابع write_v و دومی یک printf است.
A: چون فراخوانی write_v قبل از printf انجام میشه، باید اجرای فعلی تابع رو نیمه کاره متوقف کنیم و اول write_v داخلی
را تحلیل کنیم و دوباره اجرای فعلی تابع رو از دستور printf ادامه بدیم.
پس قبل از هر چیز فرمان write_v داخلی رو تحلیل می کنیم :
A: حالا write_v با مقدار 10 / x اجرا میشه، یعنی مقدار 12 (چون تقسیم بصورت اعداد صحیح انجام میشه ،قسمت اعشاری
تقسیم دور ریخته می شود).
B: یعنی ما تابع write_v را با مقدار 12 برای x اجرا می کنیم.
B: در سطر اول تابع بررسی میشه که آیا x از 10 کوچکتر است یا خیر.
B: مقدار 12 از 10 بزرگتر است پس بخش else شرط if اجرا می شود.
B: در بخش else مجددا یک فراخوانی write_v با مقدار 10 / x داریم، یعنی با مقدار 1
B: مطابق روال اجرای برنامه، تابع را در وضعیت فعلی متوقف می کنیم و یکبار دیگر write_v را با مقدار 1 برای x اجرا می کنیم :
C: در سطر اول تابع بررسی می شود که آیا x از 10 کوچکتر است یا خیر. 1 از 10 کوچکتر است، پس بخش اول if اجرا می شود.
C: در قسمت اول شرط if
مقدار 1 در خروجی چاپ می شود.
C: در ادامه کدی در داخل تابع نیست، پس اجرای فعلی تابع با مقدار 1 خاتمه یافته است.
اکنون باید برگردیم به همان موقعیتی که قبلا در آن قرار داشتیم، یعنی جایی که مقدار x برابر 12 بود و فراخوانی write_v با مقدار 10 / x انجام داده بودیم.
B: فرمان بعدی در آن موقعیت printf است که مقدار باقیمانده تقسیم x را بر 10 چاپ می کند،
B: مقدار x برابر 12 است پس باقیمانده تقسیم 2 است و
2 در خروجی چاپ می شود.
B: در ادامه اجرای فعلی تابع دیگر کدی نیست، پس اجرای تابع با مقدار x برابر با 12 خاتمه یافته.
حالا باید برگردیم به اجرای تابع اصلی در وضعیتی که متوقف کرده بودیم، جایی که مقدار x برابر 123 بود و تابع write_v با مقدار 10 / x اجرا کردیم.
A: فرمان بعدی در آن موقعیت printf است که مقدار باقیمانده تقسیم x را بر 10 چاپ می کند، x برابر 123 است پس باقیمانده
تقسیم 3 است و
3 در خروجی چاپ می شود.
A: در ادامه اجرای تابع دیگر کدی نمانده است و اجرای تابع به پایان خود می رسد.
در ادامه ما اجرای تو در توی دیگری هم نداشتیم پس بازگشت به تابع main انجام می شود.