به بخش هشتم خوش اومدید!
توی هفت بخش قبلی ما از الگوریتمها شروع کردیم و بعد الگوریتمها توی کامپیوتر رو بررسی کردیم، توی دوتا ویدیو یاد گرفتیم که چهجوری توی محیطهای مختلف یه پروژهی سیپلاسپلاس بسازیم و یاد گرفتیم چهجوری اولین برنامهمون رو بنویسیم، یاد گرفتیم به بزرگتر! ببخشید دنیا! سلام کنیم، شرطها و بعد از اون حلقهها رو یاد گرفتیم و بیشتر در مورد حلقهها یاد گرفتیم تا به اینجا رسیدیم.
همونطور که دفعهی قبل اشاره کردم اینها پایههای اولیهی بیشتر زبانهای برنامهنویسی هستن که یهجورایی میشه گفت آجرهای ساختمونی هستن که میسازیم. البته تشبیه کردن برنامهنویسی به ساختونسازی یه جورایی غلطه (دلیلش رو بعداً میفهیمد) ولی فعلاً این مثال کارمون رو راه میندازه.
امروز میخوایم بریم سراغ توابع. مطمئناً توابع رو از دروس ریاضی دبیرستان یادتون هست (اگر هنوز بهش نرسیدید یا یادتون نیست مهم نیست!) توی توابع رو میشه به ماشینهایی تشبیه کرد که یک ورودی میگیرن و روی ورودی یکسری کار انجام میدن و یه خروجی میدن. مثلاً تابع توان ۲ هر عددی که ورودی بگیره رو به توان دو میرسه و خروجی میده. یعنی اگر بهش ۲ بدیم بهمون ۴ بر میگردونه.
توابع توی کامپیوتر هم تکهکدهایی هستن که ما خارج از رویهی اصلی برنامه تعریف میکنیم (اگر یادتون باشه گفتم که برنامه از اولین خط کد که بعد از int main(){ مینویسیم آغاز میشه و در آخرین خط قبل از return 0;} تموم میشه و به این محدوده رویهی اصلی برنامه میگیم) و توی رویهی اصلی برنامه ازشون استفاده میکنیم.
توی کامپیوتر هم توابع تا حد زیادی شبیه نوع ریاضیشون تعریف میشن که البته کاملتر میشه. اولین تفاوت اینه که توابع میتونن چندتا (تعداد نامحدودی!) ورودی بگیرن. البته توی ریاضی هم میشه ورودی تابع رو یه زوج مرتب (یا سه تایی مرتب یا n تایی مرتب) بدیم که البته توی ریاضیات دبیرستان معمولاً گفته نمیشه.
دومین تفاوت اینه لازم نیست که تابع حتماً خروجی داشته باشه. البته در سطح سیستمعامل حتی تابعهایی که نیازی به خروجی ندارن (مثل خاموش کردن کامپیوتر) هم خروجی (معمولا) عددی دارن که نشون بده که آیا کارمون درست انجام شده یا نه.
خوب اولین سؤالی که پیش میاد اینه که چرا باید توابع رو یاد بگیریم؟ (در واقع توابع رو یاد نمیگیریم چون تابع یه تعریفه! بلکه یاد میگیریم که چهجوری یه تابع رو تعریف کنیم و ازش استفاده کنیم) جوابش رو اینجوری بهتون میدم:
خیلی وقتها ما توی برنامهمون کارهای تکراری انجام میدیم. مثلاً فرض کنید که توی برنامه سهجا لازمه که چک کنیم که یه عدد اول هست یا نه. برای این کار با چیزایی که تا الان یاد گرفتیم باید سهجا از if و for برای اینکار استفاده میکردیم. ولی کارمون راحتتر نمیشه اگر بتونیم یهبار کد چک کردن اول بودن یه عدد رو بنویسیم و بعداً ازش استفاده کنیم؟
و کاربرد دیگهی این کار هم اینه که دیباگ برنامه خیلی آسون میشه. خیلی راحتتر میشه مشکل رو توی چند خط جدا از رویهی اصلی برنامه پیدا کرد تا این که بخوایم اون رو توی چندصد خط کد وسط رویهی اصلی پیدا کنیم. مخصوصاً اگر اون تیکه کد رو تکرار هم کرده باشیم! که اگر اینجوری باشه کارمون چند برابر میشه :(
ماهم با این که نمیدونستیم قبلاً مثال تابع رو دیدیم و باهاش کار کردیم. بله! اون چیزی که شما اول برنامهتون مینویسید (نه دقیقاً اولش!) یعنی ()int main یه تابعه. اول بذارید یاد بگیریم چهجوری یه تابع رو تعریف کنیم بعدش به main میرسیم.
همونطور که فهمیدیم تابع یه ورودی میگیره و یکسری کار انجام میده (که ممکنه روی ورودیها باشه) و یه خروجی میده (که ممکنه خروجی هم نده!). توی سیپلاسپلاس تابعهامون رو باید با چندتا چیز مشخص کنیم. یکی از این خصوصیات (که معلومه لازمه!) اسم تابعمونه. مثل متغیرها اسم تابعمون هم نباید با عدد شروع بشه ولی میتونه شامل اعداد، حروف بزرگ و کوچیک و خط فاصله «-» و زیرفاصله «ـ» باشه.
قواعد مختلفی برای نامگذاری توابع وجود داره ولی اونی که من خیلی دوسش دارم (و توی سیشارپ هم رایجتره، توی سیپلاسپلاس کمتر) اینه که ۱. اسم تابع رو باید کامل بنویسید ۲. وقتی فرق بین کلمات رو با حروف بزرگ مشخص کنید ۳. (این قائده رو بعداً تکمیل میکنم) اول اسم تابع هم باید با حرف بزرگ شروع بشه.
قائدهی سوم رو برای این گفتم چون توی جاوااسکریپت رسمه که حرف اول کلمه اول اسم تابع کوچیک باشه ولی کلمات بعد با حرف بزرگ شروع بشن.
مثلاً اگر تابعمون قراره Hello World رو چاپ کنه اسمش رو HelloWorld میذاریم. (بدیهی!) کاربرد این روش هم اینه که بعداً با دیدن اسم تابع متوجه میشیم که چیکار میکنه. البته راستش رو بخواهید اکثر توابع استاندارد سیپلاسپلاس از این قائده پیروی نمیکنن و طبعا فهمیدن کار تابع به کمک اسمشون هم گاو نر میخواهد و مرد کهن! ولی توی سیشارپ بهصورت کاملاً آدمیزادی اسم تابع رو بر اساس کارش ساختن و دل خیلیها رو هم شاد کردن :)
خصیصهی بعدی که تابع لازم داره داشته باشه نوع خروجیشه. یعنی باید مشخص کنیم که آیا تابع ما خروجیای میده یا نمیده و اگر خروجی میده از چه نوعیه (انواع متغیرها رو که یادتون نرفته؟) مثلاً اگر قراره تابعمون دوتا عدد رو باهم جمع بزنه و مقدار نهایی رو خروجی بده نوع خروجیمون باید عددی باشه (اگر ورودیها عدد صحیح ینی int باشن خروجی باید int باشه و اگر double یا float باشن خروجی باید از همون نوع باشه و ترکیب دونوع از اینها رو هم بعداً توی همین بخش بررسی میکنیم)
و سومین و آخرین چیزی که باید مشخص کنیم هم ورودیهاییه که تابعمون قراره بگیره. یعنی اگر قراره جمع دوتا عدد رو چاپ کنه پس باید دوتا عدد رو ورودی بگیره. طریقهی مشخصکردن ورودیها هم مثل تعریفکردن متغیرهاست. با این تفاوت که میتونیم توی جاهای دیگه یکبار نوع متغیر رو بنویسیم و بعد متغیرهای همنوع رو با , از هم جدا کنیم. (مثلاً میتونیم برای تعریف a و b و c از نوع عدد صحیح بنویسیم int a,b,c; ) در صورتی که برای ورودی توابع نمیتونیم از این استفاده کنیم. چون ورودیهای متفاوت تابع رو با , از هم جدا میکنیم. (مثلاً اگر تابع قراره دوتا عدد رو جمع بزنه ورودی رو بهشکل int a , int b مینویسیم)
و بعد از اینکه خصوصیات تابعمون رو مشخص کردیم مثل وقتی که تعدادی دستور رو در زیرمجموعه if یا for یا while قرار میدادیم، دستوراتمون رو بهشکل یک بلوک کد (یعنی بین کروشه باز «{» و کروشه بسته «}») بعد از نوشتن مشخصات تابع مینویسیم و اینجوری سیپلاسپلاس وقتی که تابع رو صدا بزنیم دستورات زیرشون اجرا میکنه.
مطمئناً قاعدهی خاصی وجود داره که به سیپلاسپلاس خصوصیات تابعمون رو بفهمونیم. برای تعریف یک تابع باید اول از همه نوعش رو بنویسیم. بعد از نوشتن نوعش میریم سراغ اسم تابع که با یک فاصله از نوع تابع جدا میشه و همونطور که گفتم نمیتونه با عدد شروع بشه و میتونه شامل کارکترهای مجاز و حروف باشه و بعد از اسم تابع هم (اینبار بدون فاصله) یک پرانتز باز میکنیم و توی پرانتز ورودیهای تابع رو با همون قاعدهای که یاد گرفتیم مینویسیم (و اگر تابع ورودی نداشت فقط پرانتز رو باز میکنیم و میبندیم) و بعد از اون (ترجیحاً در خط بعد ولی اهمیتی نداره که بریم خط بعد یا نه) کروشه رو باز میکنیم، دستورات رو مینویسیم و کروشه رو میبندیم.
خوب حالا بیاید با مثالهای عملی بیشتر با تابعها آشنا بشیم. اول بیاید چندتا تابع رو تعریف کنیم و بعد از اینکه کاملاً یاد گرفتیم، یاد میگیریم چهجوری توی برنامهی اصلی ازشون استفاده کنیم.
سادهترین مثال چاپ کردن Hello Worldه. یا قاعدهی مورد علاقهی من اسم تابعمون میشه HelloWorld؛ تابعمون خروجی نداره و توی سیپلاسپلاس تابعی که خروجی نداره رو بهجای نوع خروجی از واژهی void استفاده میکنیم و همونطور که معلومه تابعمون ورودی هم نداره (البته میشه برای اذیت کردن مثلاً ۴۰ تا ورودی برای تابع در نظر بگیریم که خوب زیاد عاقلانه نیست!) پس تعریف تابعمون اینجوری میشه:
void HelloWorld() { cout << "Hello World!"; }
یا مثلاً برای جمع دوتا عدد صحیح نوع خروجی intه، اسم تابع رو Plus میذاریم و ورودیهاش هم دوتا عدد صحیح a و b هستن:
int Plus(int a,int b) { return a+b; }
همونطور که توی برنامهی بالا میبینید ما از یه دستوری استفاده کردیم که شما قبلاً استفادهی بیمصرفش رو توی قالب اصلی برنامهمون (که توی بخش سوم معرفی کردم) استفاده میشد و قرار هم نبود که بدونید چیکار میکنه. return همونطور که از اسمش معلومه کارش بر گردوندن خروجیه. مطمئناً وقتی توی تعریف تابع نوع خروجی تعیین میکنیم پس باید یهجوری اون نوع رو برگردونیم دیگه! و خوب یه مثال یادآوری هم بزنیم و بعد بریم سراغ صدا زدن تابع توی کد اصلی: برای پیدا کردن عدد بزرگتر بین دوتا عدد تابعمون اینجوری میشه:
int Check(int a,int b) { if(a>=b) return a; return b; }
که البته یه نکته هم داره این مثال: وقتی که توی تابع از return استفاده میکنید و دستور return اجرا میشه دیگه دستورات بعدش اجرا نمیشه. یعنی توی کد بالا اگر a از b بزرگتر باشه a رو بر میگردونه و دیگه به دستورات بعدش کاری نداره ولی اگر b از a کوچیکتر باشه از if میپره و return b; رو اجرا میکنه.
خوب برای صدا کردن توابع توی کد اصلی به اسم تابع و ورودیهاش (در صورت وجود) نیاز داریم. برای اینکار هم اول اسم تابع رو مینویسیم و بعد پرانتز رو باز میکنیم و ورودیهاش رو مینویسیم و بعد هم پرانتز رو میبندیم. و البته دوتا چیز یادمون نمیره: اول نقطه ویرگول و دوم این که موقع واردکردن ورودیها دیگه لازم نیست که نوع ورودی رو بنویسیم.
نکتهی بعدی اینه که فقط و فقط وقتی میتونیم از یه تابع استفاده کنیم که اون تابع قبل از کدمون تعرف شده باشه.
حالا توی یه مثال تمام آموزههامون رو بررسی میکنیم. و ایندفعه کد رو کامل مینویسم:
#include <iostream> using namespace std; void HelloWorld() { cout << "hello world!"; } int Plus(int a,int b) { return a+b; } int Max(int a,int b) { if(a>=b) return a; return b; } int main() { HelloWorld(); int c,d; cin >> c >> d; cout << Plus(c,d) << endl << Max(c,d); return 0; }
قانونی که بالا گفتم فقط توی کد اصلی برقرار نیست بلکه همهجا برقراره. یعنی توی تابع HelloWorld نمیتونید از تابع Plus یا Max استفاده کنید همینطور توی Plus نمیتونید از Max استفاده کنید.
توی کد اصلی برنامه ما اول تابع HelloWorld رو فراخوانی کردیم و بعدش c و d رو تعریف کردیم و مقادیرش رو از کاربر گرفتیم و جمعشون و عدد بزرگتر رو چاپ کردیم. اسم متغیرها رو مخصوصاً بهجای a و b،از c و d استفاده کردم که فکر نکنید که اسم متغیری که به تابع ورودی میدیم باید با اسم متغیر ورودی تابع که موق تعریف اسم میذاریم یکی باشه. حتی میشه خودمون دستی عدد بدیم به تابع. مثلاً int f=Max(2,3); متغیر f رو تعریف میکنه و مقدارش رو هم برابر مقدار خروجی تابع Max قرار میده.
خوب فکر کنم این دفعه خیلی بیشتر حرف زدیم و کافی باشه.
برای بخش بعد پیشنهاد میکنم:
-تابعی بنویسید که سه تا عدد رو بگیره و اونها رو به ترتیب خروجی بده. (میتونید چندتا تابع بنویسید)
-تحقیق کنید ببینید که آیا راهی وجود داره که قبل از نوشتن کد تابع از اون استفاده کنیم؟ (مثلاً توابع رو زیر main بنویسیم)
-تابعی بنویسید که درست بودن پسورد رو چک کنه.
-یه برنامه بنویسید که اولش پسورد کاربر رو بگیره و از تابعی که توی مثال قبل نوشتید استفاده کنید که اون رو چک کنه.
-یه برنامهی کامل بنویسید که یه تابع برای set کردن پسورد داشته باشه و یه تابع برای set کردن اون. اول برنامه کاربر پسورد رو set کنه و بعد ازش پسورد رو بگیرید. بعد بتونه با نوشتن دستور logout از سیستم (!) خارج بشه و دوباره پسوردش رو بگیره. بعد اگر نوشت setpassword اول ازش پسورد قبلی رو بگیرید و بعد دوبار پسورد جدید رو ازش بگیرید و پسورد رو عوض کنید.
-توی تمرین بالا (اگر این کار رو انجام ندادید) دستور setpassword و پسوردی که اول برنامه از کاربر میگیرید رو توی یک تابع بگنجونید. یعنی به تابع (مثلاً به اسم SetPass) داشته باشید که اول برنامه اون رو صدا بزنید و وقتی هم که کاربر نوشت setpassword اون رو صدا بزنید و خودش تشخیص بده که باید چیکار کنه.
-توی تمرین بالا (اگر اینکار رو انجام ندادید) یه تابع برای پردازش دستور داشته باشید. یعنی مثلاً داشته باشید Do که توی ورودیش چیزی که کاربر نوشته رو به تابع میدید و تابع خودش کاری که باید رو انجام میده.
-یهکم خلاقیت به خرج بدید و دستورات برنامهتون رو بیشتر کنید.
سلام
ممنون
خیلی آموزشهای خوبی هستن
من رسیدم به بخش 4
مؤفق باشید
سلام!
لطف دارید :)
اعتراض دارم! در ++C هم اسم بيشتر توابع عين آدمه! مثال خلف اگه بزنيد، خوشحال ميشم.
عزیزم کی میفهمه که cout ینی console out؟!؟ یا مثلا strlen که البته اینا واضحهاش بود :)) بدتر از اینم داریم. شما یک سال کلا تو دنیای توابعش بودی اینا برات آدمیزادی به حساب میاد :)
سلام ممنون
بسیار خوب و آموزنده بود، متشکرم ادمین عزیز
بسیار عالی بود