تبلیغات

سلام دوستان.

قبل از هر چیز بخاطر وقفه ای که بین قرار دادن جلسات آموزش افتاده از شما معذرت خواهی می کنم.

قبلا گفتم،یه بار دیگه هم می گم. این جلسات مطعلق به سایت رشد است.اگر عجله دارید در دیدن جلسات می تونید به این سایت مراجعه کنید.

 

در جلسه‌ی گذشته با مفهوم توابع در زبان‌های برنامه‌نویسی، و کاربرد‌های آن، و همچنین مفهوم برنامه‌نویسی ساخت‌یافته آشنا شدیم. در این جلسه با نحوه‌ی تعریف توابع آشنا خواهیم شد.

همانطور که در جلسه‌ی گذشته هم اشاره شد، وقتی تابعی توسط تابع دیگری فراخوانی می‌شود، دستورات آن تابع اجرا می‌شود. پس از اجرای دستورات تابع، کنترل اجرای برنامه به برنامه فراخوان بر می‌گردد. پس از برگشت از تابع فراخوانی شده، اولین دستور بعد از فراخوانی تابع (در تابع فراخوان) اجرا می‌شود.

بحث را با تعریف تابع دنبال خواهیم کرد. برای تعریف تابع باید اهداف تابع مشخص باشد. اینکه تابع باید دقیقاً چه بخش از مسولیت‌های کل برنامه را انجام دهد و بر آن اساس چه ورودی و خروجی‌هایی دارد.


تعریف توابع




یک تابع در زبان C طبق الگوی زیر تعریف می‌شود:

<نوع خروجی تابع) نام تابع <ورودی‌های تابع)
{
<دستور 1>
<دستور 2>
.
.
.
n دستور
}



الگوی تابع:
خط اول هر تابع را، که متشکل از نام تابع، ورودی‌ها و خروجی‌های تابع است را الگو یا پروتوتایپ (Prototype) تابع می‌گویند.

نام تابع:
نام تابع باید از قوانین Identifierها در زبان C پیروی کند، یعنی همان قوانینی که برای تعیین نام متغیرها و یا کلاً هر شناسه‌ای که در زبان C ، باید رعایت شود. نام تابع را معمولاً متناسب با مسولیتی که آن تابع بر عهده دارد تعیین می‌کنند.


وردوی تابع


ما می‌توانیم در هنگام فراخوانی هر تابع، اطلاعاتی را به آن منتقل کنیم تا تابع بر اساس این اطلاعات رفتار مناسبی انجام دهد، در زبان C به این ورودی‌های تابع، پارامتر می‌گویند.

در حقیقت پارامترها وسیله‌ای برای تبادل اطلاعات بین تابع فراخوان و فراخوانی شونده هستند. یک پارامتر می‌تواند یکی از انواع داده در زبان C مثل int، char و ... باشد. همچنین برای هر پارامتر باید یک نام تعیین شود. تعریف پارامترهای یک تابع دقیقاً مانند تعریف متغیر است. مثلاً برای تعریف تابعی که فقط یک ورودی از جنس int دارد باید خط اول تابع به این شکل باشد:

نام تابع نوع خروجی تابع (int temp)


برای دسترسی به اطلاعات ورودی در داخل تابع، باید از نام پارامتر مربوطه استفاده کنیم. مثلاً اگر بخواهیم مقدار ورودی تابع بالا چک کنیم که آیا از عدد فرضی 100 بزرگ‌تر است با خیر می‌توانیم دستور زیر را در داخل تابع بنویسیم:

نام تابع نوع خروجی تابع (int temp)
{
if (temp > 100)
{
دستورات
}
else
{
دستورات
}
}


اگر بخواهیم بیش از یک ورودی داشته باشیم، باید در داخل پرانتز پارامترها را با کاما از یکدیگر جدا کنیم:

<نام تابع <نوع خروجی تابع (int temp, int temp2)


چگونه مقدار ورودی تابع را تعیین می‌کنیم؟

همانطور که گفتیم مقدار ورودی تابع در هنگام فراخوانی تابع تعیین می‌شود. در قسمت فرواخوانی تابع به این موضوع خواهیم پرداخت.


خروجی تابع



در تعریف بالا <نوع خروجی تابع> یکی از انواع موجود در C مثل int یا char یا ... است، که توسط کاربر تعریف می‌شود. تابع می‌تواند مقداری را بر اساس نوع خروجی تابع به تابع فراخواننده باز گرداند. در صورتی که تابع ما خروجی نداشته باشد، باید به جای نوع خروجی، کلمه‌ی کلیدی «void» را بنویسیم.

بر خلاف ورودی‌های تابع، خروجی نیازی به نام ندارد. همچنین یک تابع نمی‌تواند بیش از یک خروجی داشته باشد. برای باز گرداندن یک مقدار به عنوان خروجی، باید آن مقدار را در جلوی کلمه‌ی کلیدی «return» بعد از آخرین خط دستورات تابع بنویسیم. مثلاً فرض کنید تابعی که خروجی آن از جنس int تعریف شده است، می‌خواهد مقدار 100 را به عنوان خروجی بازگرداند، شکل کلی آن این‎گونه خواهد بود:

int ورودی تابع) نام تابع)
{
دستور1;
دستور2;
دستور3;
...
return 100;
}


این مقدار ممکن است در داخل یک متغیر ذخیره شده باشد و شما بخواهید مقدار داخل متغیر را به‌عنوان خروجی بازگردانید، برای این کار کافیست در جلوی return نام متغیر را بنویسید. به‌عنوان مثال، خط زیر، مقدار داخل متغیر temp را که قبلاً از جنس int تعریف شده است را باز می‌گرداند.

return temp;


دقت کنید که دستور return حتماً باید در آخرین خط هر تابع نوشته شود، زیرا دستوراتی که بعد از این دستور نوشته شوند، اجرا نخواهند شد، و روند اجرای برنامه به تابع فراخواننده باز گردانده خواهد شد. استفاده از مقداری که به عنوان خروجی باز گردانده می‌شود مربوط فراخوانی تابع است که در آن بخش به آن اشاره خواهیم کرد. بحث در مورد فراخوانی توابع و نحوه‌ی کار با ورودی و خروجی‌های تابع را به جلسه‌ی آینده موکول خواهیم کرد. حالا برای جمع‌بندی مطالب این جلسه، یک مثال کامل را مطرح می‌کنیم.

یک تابع به نام move برای کنترل حرکت روبات تعریف خواهیم کرد. این تابع خروجی ندارد، اما یک ورودی از جنس کاراکتر دارد. این کاراکتر 4 مقدار متفاوت میتواند داشته باشد. اگر این ورودی حرف F باشد، روبات باید به سمت جلو حرکت کند. اگر B باشد، به سمت عقب. R باشد به سمت راست؛ و L باشد باید به سمت چپ حرکت کند.

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

(void move char(dir
{
if (dir == ‘F’)
{دستورات مربوط به جلو رفتن روبات را اینجا می‌نویسیم}

else if (dir == ‘B’)
{دستورات مربوط به عقب رفتن روبات را اینجا می‌نویسیم}

else if (dir == ‘R’)
{دستورات مربوط به راست رفتن روبات را اینجا می‌نویسیم}

else if (dir == ‘L’)
{دستورات مربوط به چپ رفتن روبات را اینجا می‌نویسیم}

}


همانطور که می‌دانید، نام تنها پارامتر این تابع، dir است که از جنس کاراکتر تعریف شده است.
خروجی تابع هم Void تعریف شده است و به این معنی است که این تابع خروجی ندارد.

در ادامه در مورد فراخوانی توابعی که تعریف شده‌اند و نحوه‌ی کار با ورودی و خروجی‌های آن‌ها بحث خواهیم کرد.

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

برای اجرای دستورات هر تابع، باید تابع فراخوانی شود. برای فراخوانی توابع، کافیست نام تابع را در هر قسمت از برنامه که به آن تابع نیاز هست، بنویسید. سپس مقادیری که باید به عنوان ورودی به تابع تحویل شود را در جلوی نام تابع در داخل یک پرانتز بنویسید. و در پایان هم ";" را فراموش نکنید. به عنوان مثال برای تابعی با نام move به شکل زیر عمل می‌کنیم:

move(مقادیر ورودی)

نحوه‌ی تعیین ورودی‌های تابع

به عنوان مثال تابع ()move را از جلسه‌ی گذشته در نظر بگیرید. این تابع برای کنترل حرکت روبات نوشته شده است و باید یک کاراکتر را به عنوان ورودی دریافت کند.فرض کنید در قسمتی از برنامه می‌خواهیم به روبات دستور جلو رفتن بدهیم. برای این کار کافیست تابع ()move را با مقدار ورودی (‘F’)، فراخوانی کنیم. برای این کار، کافیست دستور زیر را بنویسید:

move(‘F')

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

temp( ‘F’ , 200);


همان‌طور که می‌بینید تابع temp دو ورودی دارد که یکی از جنس حروف (Character) و دیگری از جنس عددی (Integer) است. دقت کنید که اگر جنس پارامتر از Char باشد، باید کاراکترهایی که به عنوان ورودی به تابع ارسال می‌شوند، در داخل ‘ ‘ قرار گیرند. اطلاعاتی که در هنگام فراخوانی تابع، در جلوی نام تابع (در داخل پرانتز) به عنوان مقادیر ورودی ظاهر می شوند، آرگومان تابع نام دارند. دقت داشته باشید پارامتر ها متغیرهایی هستند که هنگام تعریف تابع، در جلوی نام تابع و در داخل پرانتز قرار می گیرند، اما آرگومان‌ها در هنگام فراخوانی در جلوی نام تابع درج می‌شوند.

نحوه‎ی استفاده از خروجی تابع

همان‌طور که در جلسه‌ی گذشته توضیح داده شد، هر تابع می‌تواند یک مقدار را به عنوان خروجی تابع به فراخواننده بازگرداند. این مقدار از طریق نام تابع قابل دسترسی خواهد بود. یعنی همان‌طور که مقداری که داخل هر متغیر ذخیره شده است از طریق نام آن متغیر قابل دسترسی است، مقداری که به عنوان خروجی تابع بازگردانده شده است هم، از طریق نام تابع قابل دسترسی است. به عنوان مثال تابع زیر را در نظر بگیرید:

int compass ()
{
دستورات مربوطه;
return degree;
}

این تابع برای خواندن مقدار سنسور قطب‌نمای الکتریکی نوشته شده است که این مقدار همان زاویه‌ی قطب نما نسبت به قطب‌های کره‌ی زمین است؛ و یک خروجی از جنس int دارد که حامل زاویه‌ای است که قطب نمای الکتریکی نشان می‌دهد. حالا هر کجا که نام تابع نوشته شود، یکبار تابع فراخوانی می‌شود و خروجی تابع از طریق نام تابع قابل دسترسی خواهد بود. به عنوان مثال اگر بخواهیم خروجی تابع بالا را از طریق یک دستور شرطی چک کنیم، می‌توان دستور زیر را نوشت.

if ( compass() > 128)
{ دستورات;}

همچنین می‌توان مقدار خروجی را داخل یک متغیر کمکی ذخیره کرد، به‌عنوان مثال:

Temp= compass();

دقت داشته باشید که اگر تابع، پارامتر ورودی هم نداشته باشد، باید پرانتزِ باز و بسته جلوی نام تابع درج شود.

همان‌طور که گفته شد، ما نمی‌توانیم هیچ بخش از برنامه را خارج از توابع بنویسیم، یعنی هر خط از برنامه‌ی ما، باید حتماً در یکی از توابع گنجانده شده باشد. اما سوال این جاست که تا کنون که ما کار با توابع را بلد نبودیم، دستوراتی که می‌نوشتیم چگونه اجرا می‌شدند؟

تابع main():

در هر برنامه‌ای که در زبان C نوشته می‌شود، می‌بایست تابعی با نام ()main وجود داشته باشد. روند اجرای برنامه از همین تابع شروع می‌شود، یعنی اولین تابعی که دستوراتش اجرا می‌شود همین تابع است. برای اجرای هر برنامه‌ای که ما در زبان C می‌نویسیم، تابع ()main در برنامه‌یِ ما، توسط سیستم عامل فراخوانی می‌شود، و پس از اجرای تمام دستورات ()main، کنترل دوباره به سیستم عامل باز گردانده می‌شود. در حقیقت، تابع ()main تنها تابعی است که وجودش الزامی است و با اتمام کار این تابع، روند اجرای دستورات برنامه هم پایان می‌رسد.

در محیط CodeVision هم در همان ابتدا تابع ()main توسط CodeWizard تعریف می‌شود و دیگر نیازی نیست ما مجدداً این تابع را تعریف کنیم. با کمی دقت می‌توانید الگوی تعریف تابع ()main را در برنامه پیدا کنید. نکته‌ی مهم این که همان‌طور که در بالا گفته شد، پس از اجرای دستورات تابع ()main کار برنامه به اتمام می‌رسد و میکروکنترلر دیگر کاری انجام نمی‌دهد، به همین خاطر اگر می‌خواهیم برنامه‌ای که نوشته‌اید مکرراً اجرا شود باید آن‌ها را در داخل یک حلقه‌ای بنویسیم که دستوراتش بی نهایت بار تا زمانی که میکروکنترلر روشن است انجام شود. برای این کار می‌توانید از حلقه‌ی ()while به شکل زیر استفاده کنید:

while(1)
{
دستورات;
}

نوشتن عدد "1" به جای شرط حلقه، در داخل پرانتز، به این مفهوم است که شرط اجرای حلقه همواره برقرار است و دستورات داخل حلقه باید بی‌نهایت بار انجام شوند. اما خوشبختانه CodeWizard این کار را هم برای ما انجام داده است و حلقه‌ای به شکل بالا برای کار ما تعریف کرده است که ما دستوراتمان را در داخل آن حلقه بنویسیم. (برای یاد آوری رجوع شود به جلسه‌ی 26).

نکته‌ی مهم در مورد تعریف توابع

توابع باید در کدام قسمت برنامه تعریف شوند؟ برای این که توابعی که تعریف می‌کنیم در همه‌ی بخش‌های برنامه قابل استفاده و فراخوانی باشند، باید آن‌ها درست قبل از تابع ()main تعریف کنیم. یعنی ابتدا خطی که الگوی تابع ()main نوشته شده است را پیدا کنید، سپس هر تابعی که می‌خواهید را قبل از آن تعریف کنید. البته بحث در مورد حوزه‌ی استفاده و دسترسی به توابع بسیار مفصل است،اما این مطالب برای انجام کارهای ما کفایت می‌کنند. برای کسب اطلاعات بیشتر در این زمینه، می‌توانید به بخش توابع از ک تاب مهندس جعفرنژاد قمی یا سایر کتاب‌های آموزش زبان C مراجعه کنید.

نکته‌ای مهم در مورد شروع برنامه‌های ساخت‌یافته

ابتدا بدون پرداختن به جزئیات پیاده سازی توابع، ورودی‌ها و خروجی‌های تابع، بدنه‌ی اصلی برنامه را بنویسید. به عبارت دیگر، در قدم اول لازم نیست تک تک دستورات داخل توابع را بنویسید، ابتدا فقط تعیین کنید هر تابع قرار است چه عملی را انجام دهد و از آن در قسمت‌های مورد نیاز استفاده کنید.


در قدم بعد، به تعریف جزئیات داخل توابع بر اساس نیازی که به آن‌ها وجود دارد بپردازید.

منتظر سولات و نظرات دوستان خوبم هستم.