سری جدیدی از آموزشهای برنامهنویسی آغاز شده است. این سری منقضی شده است. پیشنهاد میکنیم این سری را ادامه ندهید!
در بخش قبلی در مورد برنامه، متغیرها و چند تابع از پاسکال چیزهایی یادگرفتیم. حال میخواهیم سراغ فیلترکردن اطلاعات برویم.
شرطها در پاسکال
در بیشتر مواقع ما نیاز به تصمیمگیری در مورد اطلاعات ورودی کاربر داریم. مثلا یک ماشینحساب ساده نیاز دارد بداند که در حال حاضر کدام عملگر را بین دو عدد ورودی اعمال کند. یعنی نیاز است که بررسی کنیم که کاربر کدام علامت (+ – / ×) را وارد کرده است؛ این کار با اعمال شروط امکانپذیر است.
ساختار کلی شرطها
در پاسکال شرطها به شکل زیر نوشته میشوند:
if {} then
{Do something};
که پس از if باید شرط خود را قرار دهیم و پس از then نیز دستوری قرار میگیرد که اگر شرط درست بود باید اجرا شود.
کامنتها
در بیشتر مواقع در برنامهنویسی شما نیاز خواهید داشت که توضیحاتی برای کدهای خود بنویسید. بزارید اینطور توضیح دهم که فرض کنید شما برنامهای با ۱۸۰۰۰ خط نوشتهاید و در هنگام اجرا در خط ۱۵۴۳۶ام آن مشکلی پیش آمده است. مطمئنا انرژی خیلیخیلیخیلی زیادی باید صرف کنید تا بفهمید که قرار بوده در خط ۱۵۴۳۶ چه اتفاقی بیافتد (در این حد که در زبانی مثل پاسکال شاید مجبور باشید ۱۰۰۰ خط قبل و بعد از آن را بررسی کنید تا بفهمید! ولی نگران نباشید، قرار نیست شما برنامهنویس پاسکال باشید!). ولی در هنگام برنامهنویسی کافی است ۱ میلیونیم آن انرژی را صرف کتید و جلوی آن خط کامنتی بگذارید که قرار است چه اتفاقی بیافتد (به همین سادگی! در مورد انرژی زیاد اغراق نمیکنم. در پروژهی خامهعسل ما با همین مشکل روبرو هستیم و هنوز هم نتوانستیم خودمان را از این باتلاق بیرون بکشیم!)
در پاسکال کامنتها به دو صورت در کدهای شما قرار میگیرند:
(*your comment line 1
Line 2
Line 3
Line 4*)
یا
{your comment line 1
Line 2
Line 3
Line 4}
که تا آنجایی که ما فهمیدیم هیچ فرقی با یکدیگر ندارند!
خوب برگردیم سراغ شرطهای خودمان.
فرض کنید که میخواهیم سن کاربرمان را بپرسیم. در مرحلهی اول لازم است چک کنیم که کاربر سنش را غلط وارد نکند. پس با فرض این موضوع که در زمان نوح (ع) زندگی نمیکنیم بیشترین سن را ۲۰۰ سال و کمترین را ۰ در نظر میگیریم. پس برنامه به شکل زیر خواهد بود:
var
age: integer;
ageOK: boolean;
begin
writeln('plz enter you age:');
readln(age);
ageOK:= false;
if a>0 then
if a<200 then
ageOK:= true;
{do another things}
end.
خوب در برنامهی بالا ما دو شرط را درون هم قرار دادیم. یعنی در کل به این صورت میشود که اگر شرط اول درست باشد، پاسکال دستور درون شرط را اجرا میکند که از قضا اینجا یک شرط دیگر است و آن هم اجرا میشود و پس از پایان شروط نیز پاسکال به انجام دستورات بعدی ادامه میدهد.
دورزدن پاسکال با begin و end; !
اگر متوجه شدهباشید در دستور پس از if شما اجازه دارید فقط یک دستور را اجرا نمایید و این موضوع مطمئنا مشکلزا خواهد بود. برای همین هم ما میتوانیم با یک «تکهبرنامه» این محدودیت را دور بزنیم. مثلا فرض کنید در برنامهی بالا به کاربر بگوییم که شما که سنتان از ۰ کمتر است در زمان سفر کردهاید یا اگر سنشان از ۲۰۰ بیشتر است میتوانند خودشان را به کتاب رتبههای سالیانهی گینس معرفی کنند!
پس برنامه به شکل زیر تغییر میکند:
var
age: integer;
ageOK: boolean;
begin
writeln('plz enter you age:');
readln(age);
ageOK:= false;
if a>0 then
begin
if a<200 then
begin
ageOK:= true;
end;
if ageOK=false then
writeln('The Guinness Book should know you!');
end;
if ageOK=false then
writeln('Did you do time travelling?!? Or did you see Karim Khan Zand?!? ');
{do another things}
end.
پس ما بهجای قرار دادن یک دستور، چند دستور را در قالب یک «تکهبرنامه» قرار دادیم. توجه داشته باشید که طریقهی نوشتن تکهبرنامهها به صورت خطی است یعنی هر begin با اولین end; پایان مییابد و تکهبرنامهها یکدیگر را قطع نمیکنند (یعنی نمیشود یک تکهبرنامه (پسر) داخل یک تکهبرنامهی دیگر (پدر) آغاز شود ولی پدر قبل از پسر به اتمام برسد {احترامی چیزی گفتن!})
البته این برنامه، برنامهی بزرگی شد چون هنوز مبحث بعدی را نیاموختهایم!
انجام کاری در صورت درست نبودن شرط
در برنامهی بالا برای اینکه بفهمیم که شرط غلط انجام شده یا نه مجبور شدیم چک کنیم که دستوری که درون شرط بوده انجام شده یا نه ولی همیشه از این شانسها نداریم که بتوانیم انجامشدن دستور را چک کنیم (مثلا فرض کنید درون دستور فقط نوشتهای چاپ میکردیم. در آنصورت بعید میدانم با پاسکال میتوانستیم چک کنیم که چیزی در کنسول چاپ شده است یا نه!)
برای انجام کاری در صورت درست نبودن شرط باید از کلیدواژهی else استفاده کرد. ساختار کلی if – else به شکل زیر است:
if {if statement} then
begin
{do something}
end;
else
begin
{do something}
end;
پس حالا برنامهای که نوشتیم به شکل زیر در میآید:
var
age: integer;
ageOK: boolean;
begin
writeln('plz enter you age:');
readln(age);
ageOK:= false;
if a>0 then
begin
if a<200 then
begin
ageOK:= true;
end;
else
writeln('The Guinness Book should know you!');
end;
else
writeln('Did you do time travelling?!? Or did you see Karim Khan Zand?!?');
{do another things}
end.
که از برنامهی قبلی جمعوجورتر است.
خوب با این اوصاف ما میتوانیم برنامهای چندمنظوره برای کاربر بسازیم. یعنی در ابتدا یک منو چاپ کنیم و به کاربر اجازه دهیم تا از بین گزینههای موجود یکی را انتخاب کند. مثلا برنامهی زیر میتواند مثال مناسب و انعطافپذیری باشد {برنامهای جامع برای همهی سلیقهها!}
var
menu: integer;
begin
writeln('Hi, Welcome to my beautiful user friendly application designed for 2013 uesrs!');
writeln('Please chose one the items below:');
writeln('- Press 1 for Do job 1');
writeln('- Press 2 for Do job 1');
writeln('- Press 3 for Do job 1');
writeln('- Press 4 for Do job 1');
writeln('- or Press anything else to close this beautiful application');
writeln('I"m waiting …');
readln(menu)
if menu=1 then
begin
{Do Job 1}
end;
if menu=2 then
begin
{Do Job 2}
end;
if menu=3 then
begin
{Do Job 3}
end;
if menu=4 then
begin
{Do Job 4}
end;
writeln('I"m Happy you used my beautiful user friendly application!');
writeln('Have a good time');
writeln('Good Bye!');
readln();
end.
خوب فکر نمیکنم نیازی به توضیح داشتهباشید {اگر در مورد نوشتههای انگلیسی نیاز به توضیح دارید در دیدگاه بیان کنید!} پس بهتر است تا دیر نشده به سراغ مبحث بعدی برویم {الان ساعت ۲:۱۳ بامداد!}
کدهای چرخشی
در مواقعی شما نیاز دارید تا کاری را چندبار انجام دهید. مثلا بخواهید نمرهی ۲۰ نفر را از کاربر بگیرید و میانگین آنها را برای آنها چاپ کنید {این مثال واقعا تکراری بود! فکر کنم هر کتاب آموزشی را که باز کنید این مثال را بتوانید تویش پیدا کنید!} یا کارهای جالبتر مثلا چاپ یک مثلث متساویالساقین ستارهای به ساق ۲۰ خط {از این کارها هم انجام میدهیم! کمی صبر کنید} مطمئنا استفاده از کپی و پیست {مثلا ۲۰ تا readln بنویسیم!} ، روش جالبی برای گرفتن ورودی (نمرات) یا چاپ خروجی (یک مثلث نسبتا بزرگ!) نخواهد بود.
اینجاست که چرخشها یا Loopها به کمک شما میآیند.
for
میتوان گفت for معمولترین دستور چرخشی در زبانهای برنامهنویسی است. در دستور for ما یک شمارنده داریم و یک هدف و از مقدار اولیهی شمارنده یکییکی به آن اضافه میکنیم و در هر بار اضافهکردن به شمارنده، یک بار دستوری که قرار است اجرا شود را اجرا میکنیم {نگران نباشید. ما قرار نیست این کار را انجام دهیم. پاسکال خودش این کار را برای ما انجام میدهد!}
چون در دستور for ما نیاز به یک متغیر به عنوان شمارنده داریم، فرض میکنیم که متغیر i در ابتدای برنامه تعریف شده است. پس ساختار for به شکل زیر خواهد بود:
for i:=0 to 100 do
{do something}
یا اگر بخواهیم پاسکال را دور بزنیم به شکل زیر در خواهد آمد:
for i:=0 to 100 do
begin
{do something}
end;
ساختار چینش درختی برنامه
اگر دقت کرده باشید در برنامههایی که در بالا مثال زدیم هروقت که دستورات بهعنوان فرزند دستورات دیگری بودند از یک Tab (یا ۸ تا اسپیس) استفاده کردیم. این ساختار به خواناتر شدن کد کمک بسیاری میکند و به کسی که کد را میخواند کمک میکند تا راحتتر آن را درک کنند. به شما پیشنهاد میکنیم که شما هم در کدهایتان از این ساختار استفاده کنید.
البته زیاد لازم نیست زحمت بکشید. فقط محیط ویرایشگر پاسکال بلد نیست خودش کدها رو مرتب کنه. چند وقت دیگه که وارد سیپلاسپلاس و سیشارپ شدیم دیگه در این مورد مشکلی نخواهیم داشت چون هزار ماشاالله همهی محیطهای جدید در جهت راحتی و تنبلی برنامهنویسها کار میکنند و کم مونده ازشون درخواست کنیم که کد رو برامون بنویسند! البته الانش هم همین کامپایلرها یهجورایی دارن برامون کدها رو مینویسن. {داستان اسمبلی رو که یادتون نرفته؟!؟}
خوب بهتره بحث for رو ادامه بدیم.
به رسم اکثر آموزشها اول برنامهی میانگین رو به عنوان مثال در اینجا قرار میدیم:
var
now: integer;
avg: real;
i: integer;
begin
readln(now);
avg:=now;
for i:=1 to 19 do
begin
readln(now);
end;
avg:=avg/20;
writeln(avg);
end.
خوب در برنامهی بالا for را تا ۱۹ رفتیم چون یکی از نمرهها را قبلا از کاربر گرفتهبودیم. توجه داشته باشید که حتی میتوان تعداد ورودیها را نیز از کاربر گرفت. یعنی لزومی ندارد که نقاط شروع و پایان for را از قبل تعیین کنیم و میتوانیم آنها را نیز به کاربر بسپاریم.
حالا میخواهیم مثلثی مثل مثلث زیر چاپ کنیم
*
**
***
****
*****
******
برای اینکار لازم است از یک for تو در تو استفاده کنیم. به این معنی که درون یک for، یک for دیگر قرار دهیم.
برای جالبتر شدن نیز تعداد خطوط را به کاربر میسپاریم {در هنگام نگارش این سطور یعنی ساعت ۲:۵۱ بامداد نویسنده کمی خوابش میاید. اگر برنامه کمنمک یا پرنمک بود ببخشید!}
var
i,j,n: integer;
begin
writeln('Welcome to my wonderful mathematical application.');
writeln('You are here and want me to draw a triangle for you!');
writeln('So I"m waiting for you to give me length of it"s leg …');
readln(n);
for i:=1 to n do
begin
for j:=1 to I do
write('*');
writeln();
end;
writeln('I finished drawing. Don"t forget to pay me otherwise I will not draw any other things for you! :X');
writeln('Honestly there are a lot of consumers waiting for me to draw things for them!');
end.
و خوب فکر میکنم برنامه نیاز به توضیح ندارد. فقط اینکه for پدر در برنامهی ما نقش اشارهگر خط را بازی میکرد و با هر حرکت آن یک خط رسم میشد و به همین دلیل نیز در انتهای دستورات آن writeln() مشاهده میشود (برای اینکه در خروجی به خط بعدی برویم!). {ساعت ۳ بامداد است. ادامهاش برای فردا!}
تا نشدهست آن تمام
{صبح بخیر!} بعد از for پرکاربرد ترین دستور چرخشی while است. مفهوم کلی آن این است که تا وقتی که یک شرط صحیح است کاری را انجام بده. مثلا منوی کاربرپسند (User Friendly!) که با if نوشتیم اگر تنها یک بار اجرا شود کاربردی ندارد (برای هر ابزار برنامه باید دوباره اجرا شود. مثل اینکه کاربر برنامههای جداگانهی مختلف را اجرا کند) ولی اگر کاربر بتواند ابزارهای مختلف را استفاده کند و هروقت که خواست خارج شود مثلا ۰ را بزند، برنامهی ما کاربرپسندتر میشود!
پس برنامهی کاربرپسندمان را اینطور ویرایش میکنیم:
var
menu: integer;
mCheck: integer;
begin
writeln('Hi, Welcome to my beautiful user friendly application designed for 2013 uesrs!');
mCheck:= true;
while mCheck do
begin
writeln('Please chose one the items below:');
writeln('- Press 1 for Do job 1');
writeln('- Press 2 for Do job 1');
writeln('- Press 3 for Do job 1');
writeln('- Press 4 for Do job 1');
writeln('- or Press anything else to close this beautiful application');
writeln('I"m waiting …');
readln(menu)
if menu=1 then
begin
{Do Job 1}
continue;
end;
if menu=2 then
begin
{Do Job 2}
continue;
end;
if menu=3 then
begin
{Do Job 3}
continue;
end;
if menu=4 then
begin
{Do Job 4}
continue;
end;
mCheck:= false;
end;
writeln('I"m Happy you used my beautiful user friendly application!');
writeln('Have a good time');
writeln('Good Bye!');
readln();
end.
continue و break، دو دستور کاربردی برای کنترل چرخشها
گاهی اوقات لازم است که ما اجرای دستورات چرخش را متوقف کنیم و به چرخش ادامه دهیم و یا کلا از چرخش بیرون بیاییم. مثلا در برنامهی بالا لازم است که پس از اینکه کاری که کاربر تعیین کردهاست را انجام دادیم، دیگر به کارمان ادامه ندهیم (وگرنه mCheck برابر false میشود و حلقه ادامه نمییابد!) برای همین از دستور continue استفاده کردیم.
اما در برنامهی بالا میتوانستیم بهجای تعریف یک متغیر اضافی از دستور break استفاده کنیم که نتیجهی نهایی میشود برنامهی پایین:
var
menu: integer;
begin
writeln('Hi, Welcome to my beautiful user friendly application designed for 2013 uesrs!');
while true do
begin
writeln('Please chose one the items below:');
writeln('- Press 1 for Do job 1');
writeln('- Press 2 for Do job 1');
writeln('- Press 3 for Do job 1');
writeln('- Press 4 for Do job 1');
writeln('- or Press anything else to close this beautiful application');
writeln('I"m waiting …');
readln(menu)
if menu=1 then
begin
{Do Job 1}
continue;
end;
if menu=2 then
begin
{Do Job 2}
continue;
end;
if menu=3 then
begin
{Do Job 3}
continue;
end;
if menu=4 then
begin
{Do Job 4}
continue;
end;
break;
end;
writeln('I"m Happy you used my beautiful user friendly application!');
writeln('Have a good time');
writeln('Good Bye!');
readln();
end.
اعمال منطقی پاسکال
اگر تا حالا فکر میکردید که کامپیوتر دنیای درهم و برهمی است اشتباه میکردید! بلکه کامپیوتر منطقیترین موجود جهان است {البته از مجموع همهی منطقها چیزهای درهم و برهمی ساخته میشوند مثل ویندوز، اینترنت و کلی چیز دیگر! اشتباه نکنید! کامیپوتر منطقی است، اما ما کاملا منطقی نیستیم و این باعث آشوب میشد!}
اما خیلی وقتها لازم است که در یک شرط چند گزارهی منطقی را باهم چک کنیم. مثلا در مثالی که برای if آوردیم، خیلی بهتر میشد اگر آن شرط تو در تو را در یک شرط بزرگتر جمع آوری کنیم. اما مانند دنیای منطق، اینجا هم چند عملگر منطقی برای گزارهها وجود دارد که آنها را بررسی میکنیم:
and
اگر لازم باشد که هر دو (یا چند) شرط در یک زمان برقرار باشند باید از and استفاده کرد. مثلا برنامهی مثال را میتوان به شکل زیر نوشت:
var
age: integer;
ageOK: boolean;
begin
writeln('plz enter you age:');
readln(age);
ageOK:= false;
if (a>0) and (a<200) then
ageOK:= true;
{do another things}
end.
توجه دقت کنید که حتما از پرانتز () برای جداکردن گزارهها استفاده کنید.
or
گاهی اوقات درست بودن یکی از شروط کافی است. مثلا میخواهیم نمرات دانشآموز را از طریق ایمیل برای پدر یا مادر او ارسال کنیم {فرستادن ایمیل در پاسکال؟!؟ عمرا!} و ما لیستی داریم که شامل ایمیل دانشآموز، ایمیل پدر و ایمیل مادر اوست. پس لازم است که فردی که ایمیل براش ارسال میشود پدر یا مادر دانشآموز باشد. در این حالت شرط ما به شکل زیر خواهد آمد (فرض میکنیم متغیر type مقادیر s (دانش آموز)، f (پدر) و m (مادر) را داشته باشد)
if (type='f') or (type='m') then
{send mail!}
یا میتوان از یک راه بهتر استفاده کرد و آن این است که چک کنیم که فرد دانشآموز نباشد. پس if ما به شکل زیر خواهد آمد:
if type<>'s' then
{send email!}
not
اگر بخواهیم برعکس یک گزارهی شرطی را چک کنیم، باید از عملگر not استفاده کنیم. مثلا در مثال بالا «اگر فرد دانشآموز نبود» را به شکل زیر هم میتوان نوشت
if not (type='s') then
{send email!}
البته در برنامهنویسی کاربردی پیشنهاد میشود که از حالت اول استفاده کنید. چون در حالت دوم شما دو عمل منطقی روی گزاره انجام میدهید (اول گزارهی منطقی true یا false را برمیگرداند و سپس آنرا برعکس میکنیم!) که در کارهای واقعی همین باعث مشکلاتی در ساختار برنامه میشود {اندک، اندک جمع گردد وانگهی دریا شود. همینا جمع میشه بعد برنامهتون نیمساعت طول میکشه تا یه جمع ساده رو انجام بده!}
عملگرهای مقایسهای
در مثالهای این بخش از عملگرهای مختلفی در شرایط مختلف استفاده کردیم که بد نیست آنها را نیز توضیح دهیم {در اصل در یک جا جمعآوری کنیم برای شب امتحان!} (چون مثال در بالا وجود دارد دیگر آنها را تکرار نمیکنیم}
- تساوی: اگر بخواهیم تساوی بین دو متغیر (یا یک متغیر و یک چیز ثابت) را چک کنیم از علامت = استفاده میکنیم.
- کوچکتر، بزرگتر: برای بررسی کوچکتری و بزرگتری مانند ریاضیات شیرین دورهی ابتدایی {از ابتدایی شروع و تا کنون ادامه دارد!} از < و > استفاده میکنیم و اگر بخواهیم بزرگتر مساوی یا کوچکتر مساوی را چک کنیم از <= یا >= استفاده میکنیم.
- نامساوی: برای این چک کنیم که دو عبارت مساوی نباشند باید از <> استفاده کنیم.
خوب در این بخش شروط و چرخشها (حلقهها) را آموختیم. بخش بعدی مفاهیم برنامهنویسی به اتمام میرسد و وارد برنامهنویسی سیپلاسپلاس میشویم {بخش بعدی پاسکال تمام میشود! هورا!} تا کمی عملیتر برنامهنویسی یاد بگیریم.
تمرینها
با تشکر از اینکه تمارین بخش قبلی را حل کردید برای این بخش هم تعدادی تمرین در نظر گرفتهایم. اگر احیانا کسی زحمت کشید و هر کدام از تمارین را حل کرد ما هم کمی انگیزه پیدا میکنیم و جواب تمرینها را در نوشتهای منتشر میکنیم {به قول استاد خوب حسابانمان :نمیخواهید یاد بگیرید اصلا چرا میاد نوشته رو میخونید. برید به مامانتون بگید من نمیخوام یاد بگیرم برید سیگار فروش شید چرا هی وقتتون رو با خوندن این چرتوپرتها تلف میکنید؟ :دی}
- ب.ب.ک (برنامهای بنویسید که) قد دانشآموزان را بگیرد (تعداد دانشآموزان را نیز کاربر تعیین میکند) و میانگین، کوتاهترین و بلندترین قد آنها را چاپ کند.
- ب.ب.ک ابتدا دو عدد از کاربر بگیرد و سپس با یک محیط کاربرپسند از او بپرسد که قرار است با آن عددها چه کاری بکند (جمع، صرب، تقسیم، تفریق) و نتیجه را چاپ کند.
- برنامهای بنویسید که یکسری آدرس صفحات بگیرد و تعداد آنهایی که از سایت دو برنامهنویس هستند را چاپ کند.
پینوشت: اگر مشکلی دارید میتوانید در دیدگاهی مشکل خود را بیان کنید و یا اگر بخشی از این آمورش نادرست است لطفا اطلاع دهید {متشکرم!}
یک نکتهی مهم {سوال انحرافی}: در مثالهای بالا (در کدهای بالا) اشتباه در دو مثال تکرار شده (راهنمایی یک کلیدواژه اشتباها بهعنوان متغیر استفاده شده) آیا میتوانید آن را بیابید؟