درس چهارم – دستورالعملهای کنترلی، حلقهها
در این درس نحوه استفاده از دستورالعملهای کنترل حلقه در زبان C# را فرا خواهید گرفت. هدف این درس فهم و درک موارد زیر میباشد :
ü حلقه while
ü حلقه do-while
ü حلقه for
ü حلقه foreach
ü مطالب تکمیلی درباره دستورالعمل break
ü فراگیری نحوه بکارگیری دستورالعمل continue
در درس قبل، نحوه ایجاد یک حلقه بسیار ساده را با استفاده از دستور goto را فرا گرفتید. در همان مطلب نیز اشاره کردیم که این روش، روش مناسبی جهت ایجاد حلقه نیست. در این درس با نحوه صحیح ایجاد حلقهها در زبان C# آشنا خواهید شد. اولین دستوری که با آن آشنا میشوید نیز دستور while است.
حلقه while
ابتدا به مثال زیر توجه نمایید.
using System;
class WhileLoop
{
public static void Main()
{
int myInt = 0;
while (myInt < 10)
{
Console.Write("{0} ", myInt);
myInt++;
}
Console.WriteLine();
}
}
مثال 1-4 که در بالا ملاحظه میکنید، یک حلقه while ساده را نشان میدهد. این حلقه با کلمه کلیدی while آغاز شده و سپس به دنبال آن یک عبارت منطقی قرار میگیرد و مورد بررسی قرار میگیرد. تمامی دستورالعملهای کنترلی از یک عبارت منطقی بهره میگیرند و این بدین معناست که ابتدا این عبارت باید بررسی شود تا مشخص شود مقدار این عبارت true است یا false. در این مثال مقدار متغیر myInt مورد بررسی قرار میگیرد تا چک شود آیا مقدارش از 10 کوچکتر هست یا خیر. چون در ابتدای برنامه به این متغیر مقدار صفر تخصیص داده شده است، عبارت منطقی مقدار true را باز میگرداند و سپس بلوک قرار گرفته بعد از عبارت منطقی مورد اجرا قرار میگیرد.
درون بلوک while ابتدا مقدار متغیر myInt در کنسول نمایش داده میشود و سپس یک واحد به مقدار این متغیر افزوده میگردد. پس از اتمام بلوک while، عبارت منطقی مجددا کنترل میشود و در صورتیکه این عبارت مقدار true بازگرداند، حلقه while مجدداً اجرا میشود. زمانیکه عبارت منطقی مقدار false برگرداند، اجرا برنامه به اولین دستور بعد از بلوک while منتقل میشود. در این مثال اعداد صفر تا 9 بر روی صفحه نمایش داده میشوند و سپس یک خط خالی چاپ شده و اجرای برنامه خاتمه مییابد.
حلقه بعدی که بسیار شبیه به حلقه while میباشد، حلقه do-while است.
حلقه do-while
ابتدا به مثال 2-4 توجه نمایید.
using System;
class DoLoop
{
public static void Main()
{
string myChoice;
do
{
// منویی نمایش داده میشود
Console.WriteLine("My Address Book ");
Console.WriteLine("A - Add New Address");
Console.WriteLine("D - Delete Address");
Console.WriteLine("M - Modify Address");
Console.WriteLine("V - View Addresses");
Console.WriteLine("Q - Quit ");
Console.WriteLine("Choice (A,D,M,V,or Q): ");
// ورودی کاربر بررسی میشود
myChoice = Console.ReadLine();
// تصمیمی بر اساس ورودی کاربر گرفته میشود
switch(myChoice)
{
case "A":
case "a":
Console.WriteLine("You wish to add an address.");
break;
case "D":
case "d":
Console.WriteLine("You wish to delete an address.");
break;
case "M":
case "m":
Console.WriteLine("You wish to modify an address.");
break;
case "V":
case "v":
Console.WriteLine("You wish to view the address list.");
break;
case "Q":
case "q":
Console.WriteLine("Bye.");
break;
default:
Console.WriteLine("{0} is not a valid choice", myChoice);
break;
}
Console.Write("Press Enter key to continue...");
Console.ReadLine();
Console.WriteLine();
} while (myChoice != "Q" && myChoice != "q");
}
}
مثال 2-4 نحوه استفاده از حلقه do-while را نشان میدهد. ساختار نوشتاری این دستور بصورت زیر است :
do
{
دستورالعملهای مورد استفاده در بلوک این دستور، هر دستورالعمل معتبر زبان C# میتواند باشد. عبارت منطقی نیز همانند نمونههائیست که تا کنون با آنها آشنا شدیم و یکی از دو مقدار true یا false را بر میگرداند.
یکی از مصارف عمده حلقه do به جای حلقه while، مواردی است که میخواهیم یکسری دستورالعمل خاص، که آنها را درون بلوک do قرار میدهیم، حداقل یکبار اجرا شوند. در این مثال ابتدا یک منو برای کاربر نمایش داده میشود و سپس ورودی از وی دریافت میگردد. چون حلقه while عبارت منطقی خود در ابتدای اجرای حلقه بررسی مینماید، از اینرو تضمینی برای اجرای دستورات درون بلوک وجود نخواهد داشت، مگر شما بطور صریح برنامه را طوری طراحی نمایید که این عمل اتفاق بیفتد.
یک نگاه کلی به مثال 2-4 بیندازیم. در متد Main() متغیر myChoice را از نوع رشتهای تعریف نمودهایم. سپس یکسری دستورات را بر روی کنسول چاپ نمودهایم. این دستورات منوهای انتخاب برای کاربر هستند. ما باید ورودی از کاربر دریافت کنیم که چون این عمل از طریق Console.ReadLine() صورت گرفته، باید در متغیری از نوع رشتهای قرار گیرد و از اینرو این ورودی را در myChoice قرار دادهایم. ما باید ورودی را از کاربر دریافت کنیم و بر روی آن پردازش انجام دهیم. یک روش کارآمد برای این منظور استفاده از دستورالعمل switch است. همانطور که در دستور switch ملاحظه میکنید، بری default نیز دستوری در نظر گرفته شده است که نشان میدهد مقدار ورودی معتبر نیست.
حلقه for
به مثال 3-4 توجه کنید.
using System;
class ForLoop
{
public static void Main()
{
for (int i=0; i < 20; i++)
{
if (i == 10)
break;
if (i % 2 == 0)
continue;
Console.Write("{0} ", i);
}
Console.WriteLine();
}
}
مثال 3-4 یک حلقه for را نشان میدهد. استفاده از حلقه for برای زمانی مناسب است که دقیقاً بدانید که حلقه چندبار باید تکرا شود. محتویات درون پرانتزهای حلقه for از سه قسمت تشکیل شده است :
(
initializer list لیستی از عبارات است که بوسیله کاما از یکدیگر جدا میشوند. این عبارات تنها یکبار در طول دوره کاری حلقه for پردازش میشوند. همانطور که در مثال 3-4 نیز ملاحظه میکنید، این قسمت معمولا برای تعیین متغیری عددی جهت آغاز عمل شمارش مورد استفاده قرار میگیرد.
پس از اینکه عبارتهای دورن initializer list پردازش شد، حلقه for به سراغ قسمت بعدی، یعنی عبارات منطقی(boolean expression) میرود. در این قسمت تنها یک عبارت منطقی میتوان قرار داد ولی هر اندازه که بخواهید میتوانید این عبارت منطقی را پیچیده نمایید، فقط توجه نمایید که این عبارت باید بگونهای شود که مقدار true یا false برگرداند. از این عبارت منطقی معمولا جهت کنترل متغیر شمارشی استفاده میشود.
هنگامیکه عبارت منطقی مقدار true بازگرداند، دستورالعملهای بلوک for اجرا میشوند. در مثال 3-4 ما از دو دستور if درون حلقه for نیز استفاده کردهایم. اولین دستور if بررسی میکند که آیا مقدار متغیر i برابر با 10 هست یا نه. در اینجا یک نمونه دیگر از استفاده دستور break را ملاحظه میکنید. عملکرد دستور break در اینجا نیز همانند مورد استفاده آن در دستور switch است. در صورت اجرای دستور break اجرای حلقه for خاتمه یافته و اجرای برنامه به اولین دستور بعد از حلقه for منتقل میشود.
دومین دستور if با اسقتاده از عملگر باقیمانده (%) بررسی میکند که آیا متغیر i بر 2 بخش پذیر هست یا نه. در صورتیکه متغیر i بر 2 بخش پذیر باشد، دستور continue اجرا میشود. پس از اجرای دستور continue از سایر دستورات حلقه for که بعد از continue قرار گرفتهاند صرفهنظر میشود و اجرای برنامه به اول حلقه for باز میگردد.
قسمت سوم در حلقه for، قسمت postloopaction list است. پس از اینکه تمامی دستورات درون حلقه for اجرا شد، اجرای حلقه به این قسمت باز میگردد. این قسمت لیستی از عملیاتی است که میخواهید پس از اجرای دستورات درون بلوک حلقه for انجام شوند. در مثال 3-4 این عمل، اضافه کردن یک واحد به متغیر شمارشی است. پس از افزوده شدن یک واحد به متغیر شمارشی، عبارت منطقی مجدداً مورد بررسی قرار میگیرد و در صورتیکه مقدار این عبارت برابر با true باشد، حلقه for مجدداً اجرا میگردد. حلقه for تا زمانیکه عبارت منطقی برابر با true باشد اجرا میشود.
حلقه foreach
به مثال 4-4 توجه کنید.
using System;
class ForEachLoop
{
public static void Main()
{
string[] names = {"Hadi", "Salehy", "C#", "Persian"};
foreach (string person in names)
{
Console.WriteLine("{0} ", person);
}
}
}
حلقه foreach برای پیمایش مجموعهها بسیار مناسب است. یک نمونه از مجموعهها در C#، آرایهها هستند که در مثال 4-4 نیز مورد استفاده قرار گرفته است. اولین کاری که در متد Main() صورت گرفته، اعلان آرایه names از نوع رشتهای و مقدار دهی آن است.
درون پرانتزهای foreach عبارتی متشکل از دو المان قرار دارد که این المانها بوسیله کلمه کلیدی in از یکدیگر جدا شدهاند. المان سمت راست، مجموعهایست که میخواهید اعضای آنرا مورد پیمایش قرار دهید. المان سمت چپ، متغیری از نوع مجموعه مورد نظر است که مقادیر پیمایش شده را بر میگرداند.
در هربار پیمایش، عنصری جدیدی از مجموعه درخواست میشود. این درخواستها از طریق متغیر فقط خواندنی تعریف شده درون پرانتزهای foreach بازگردانده میشوند. تا زمانیکه عنصری در مجموعه وجود داشته باشد که مورد پیمایش قرار نگرفته است، حلقه foreach به کار خود ادامه خواهد داد زیرا عبارت منطقی حلقه foreach مقدار true را باز میگرداند. به محض اینکه تمامی عناصر مجموعه پیمایش شد، عبارت منطقی برابر با false شده و اجرای حلقه foreach خاتمه مییابد. در این حالت اجرای برنامه به اولین دستور بعد از حلقه foreach منتقل میگردد.
در مثال 4-4، متغیری از نوع رشته با نام person برای نگهداری عناصری که از آرایه names خوانده میشود، تعریف کردهایم. تا زمانیکه اسمی در آرایه names وجود داشته باشد، در متغیر person قرار میگیرد و درون حلقه foreach بوسیله دستور Console.WriteLine() در خروجی نمایش داده میشود.
نکته : یکی از مهمترین ویژگیهای حلقه foreach در آنست که فقط میتواند عناصر یک مجموعه را بخواند و نمیتواند تغییری در آنها ایجاد نماید. مزیت دیگر آن، پیمایش تمامی عناصر مجموعه بدون اطلاع از تعداد عناصر موجود در آن است.
خلاصه
در این درس با نحوه کار با دستورالعملهای for، while، do-while و foreach آشنا شدید. حلقه while تا زمانیکه شرطش صحیح باشد انجام میشود بدین معنی که تا زمانیکه عبارت منطقی آن دارای مقدار true باشد، دستورات درون بلوک آن اجرا میشوند. حلقه do، دستورات بلوک خود را حداقل یکبار اجرا میکند و سپس شرط مورد نظر را بررسی مینماید و در صورتیکه عبارت منطقی آن مقدار true بازگرداند، دستورات بلوک خود را تکرار مینماید. حلقه for دستورات بلوک خود را به تعداد دفعات مشخص اجرا مینماید و حلقه foreach عناصر یک مجموعه را مورد پیمایش قرار میدهد. در نهایت نیز اشاره میشود که روند اجرای حلقهها با استفاده از دستورات break و continue تغییر مینماید.
درس سوم – دستورالعملهای کنترلی و شرطی
در این درس با دستورالعملهای کنترل و انتخاب در C# آشنا میشوید. هدف این درس عبارتست از :
بررسی دستور if و انواع مختلف آن
در درسهای گذشته، برنامههایی که مشاهده میکردید از چندین خط دستور تشکیل شده بودند که یکی پس از دیگری اجرا میشدند و سپس برنامه خاتمه مییافت. در این برنامهها هیچ عمل تصمیمگیری صورت نمیگرفت و تنها دستورات برنامه به ترتیب اجرا میشدند. مطالب این درس نحوه تصمیمگیری در یک برنامه را به شما نشان میدهد.
اولین دستور تصمیمگیری که ما آنرا بررسی مینماییم، دستورالعمل if است. این دستور دارای سه فرم کلی : تصمیمگیری ساده، تصمیمگیری دوگانه، تصمیمگیری چندگانه میباشد.
مثال 1-3 – فرمهای دستورالعمل if
using System;
class IfSelect
{
public static void Main()
{
string myInput;
int myInt;
Console.Write("Please enter a number: ");
myInput = Console.ReadLine();
myInt = Int32.Parse(myInput);
//تصمیمگیری ساده و اجرای عمل داخل دو کروشه
if (myInt > 0)
{
Console.WriteLine("Your number {0} is greater than zero.", myInt);
}
//تصمیمگیری ساده و اجرای عمل بدون استفاده از دو کروشه
if (myInt < 0)
Console.WriteLine("Your number {0} is less than zero.", myInt);
// تصمیمگیری دوگانه
if (myInt != 0)
{
Console.WriteLine("Your number {0} is not equal to zero.", myInt);
}
else
{
Console.WriteLine("Your number {0} is equal to zero.", myInt);
}
// تصمیمگیری چندگانه
if (myInt < 0 || myInt == 0)
{
Console.WriteLine("Your number {0} is less than or equal to zero.", myInt);
}
else if (myInt > 0 && myInt <= 10)
{
Console.WriteLine("Your number {0} is between 1 and 10.", myInt);
}
else if (myInt > 10 && myInt <= 20)
{
Console.WriteLine("Your number {0} is between 11 and 20.", myInt);
}
else if (myInt > 20 && myInt <= 30)
{
Console.WriteLine("Your number {0} is between 21 and 30.", myInt);
}
else
{
Console.WriteLine("Your number {0} is greater than 30.", myInt);
}
} //Main()پایان متد
} //IfSelectپایان کلاس
برنامه 1-3 از یک متغیر myInt برای دریافت ورودی از کاربر استفاده مینماید، سپس با استفاده از یک سری دستورات کنترلی، که همان دستور if در اینجاست، عملیات خاصی را بسته به نوع ورودی انجام میدهد. در ابتدای این برنامه عبارت Please enter a umber: در خروجی چاپ میشود. دستور Console.ReadLine() منتظر میماند تا کاربر ورودی وارد کرده و سپس کلید Enter را فشار دهد. همانطور که در قبل نیز اشاره کردهایم، دستور Console.ReadLine() عبارت ورودی را به فرم رشته دریافت مینماید پس مقدار ورودی کاربر در اینجا که یک عدد است به فرم رشتهای در متغیر myInput که از نوع رشتهای تعریف شده است قرار میگیرد. اما میدانیم که برای اجرای محاسبات و یا تصمیمگیری بر روی اعداد نمیتوان از آنها در فرم رشتهای استفاده کرد و باید آنها را بصورت عددی مورد استفاده قرار داد. به همین منظور باید متغیر myInput را به نحوی به مقدار عددی تبدیل نماییم. برای این منظور از عبارت Int32.Parse() استفاده مینماییم. این دستور مقدار رشتهای متغیر داخل پرانتزش را به مقدار عددی تبدیل کرده و آنرا به متغیر دیگری از نوع عددی تخصیص میدهد. در این مثال نیز همانطور که دیده میشود، myInput که تز نوع رشتهای است در داخل پرانتز قرار گرفته و این مقدار برابر با myInt که از نوع int است قرار گرفته است. با این کار مقدار عددی رشته ورودی کاربر به متغیر myInt تخصیص داده میشود. (توضیح کاملتری در مورد Int32 و سایر تبدیلات مشابه به آن در درسهای آینده و در قسمت نوعهای پیشرفته مورد بررسی قرار میگیرند.)حال ما متغیری از نوع مورد نظر در دست داریم و میتوانیم با استفاده از دستور if بر روی آن پردازش انجام داده و تصمیمگیری نماییم.
دستور if
اولین دستور بصورت if (boolean expression) {statements} آورده شده است. دستور if با استفاده از کلمه کلیدی if آغاز میشود. سپس یک عبارت منطقی درون یک زوج پرانتز قرار میگیرد . پس از بررسی این عبارات منطقی دستورالعمل/دستورالعملهای داخل کروشه اجرا میشوند. همانطور که مشاهده مینمایید، دستور if یک عبارت منطقی را بررسی میکند. در صورتیکه مقدار این عبارات true باشد دستورهای داخل بلوک خود را اجرا مینماید(قبلا توضیح داده شد که دستورهایی که داخل یک زوج کروشه {} قرار میگیرند در اصطلاح یک بلوک نامیده میشوند.) و در صورتیکه مقدار آن برابر با false باشد اجرای برنامه به بعد از بلوک if منتقل میشود. در این مثال همانطور که ملاحظه مینمایید، عبارت منطقی دستور if بشکل if(myInt > 0) است. در صورتیکه مقدار myInt بزرگتر از عدد صفر باشد، دستور داخل بلوک if اجرا میشود و در غیر اینصورت اجرای برنامه به بعد از بلوک if منتقل میگردد.
دومین دستور if دراین برنامه بسیار شبیه به دستور اول است، با این تفاوت که در این دستور، دستور اجرایی if درون یک بلوک قرار نگرفته است. در صورتیکه بخواهیم با استفاده از دستور if تنها یک دستورالعمل اجرا شود، نیازی به استفاده از بلوک برای آن دستورالعمل نمیباشد. استفاده از بلوک تنها زمانی ضروری است که بخواهیم از چندین دستور استفاده نماییم.
دستور if-else
در بیشتر موارد از تصمیمگیریهای دوگانه یا چندگانه استفاده میشود. در این نوع تصمیمگیریها، دو یا چند شرط مختلف بررسی میشوند و در صورت true بودن یکی از آنها عمل مربوط به آن اجرا میگردد. سومین دستور if در این برنامه نشان دهنده یک تصمیمگیری دوگانه است. در این حالت درصورتیکه عبارت منطقی دستور if برابر با true باشد دستور بعد از if اجرا میشود و در غیر اینصورت دستور بعد از else به اجرا در میآید. در حقیقت در این حالت میگوئیم " اگر شرط if صحیح است دستورات مربوط به if را انجام بده و درغیر اینصورت دستورات else را اجرا کن".
فرم کلی دستور if-else بصورت زیر است :
if (boolean expression)
{statements}
else
{statements}
که در آن boolean expression عبارت منطقی است که صحت آن مورد بررسی قرار میگیرد و statements دستور یا دستوراتی است که اجرا میگردند.
دستور if-else if … else یا if تودرتو
در صورتیکه نیاز باشد تا چندین حالت منطقی مورد بررسی قرار گیرد و دستورات مربوط به یکی از آنها اجرا شود، از فرم تصمیمگیری چندگانه استفاده مینماییم. این نوع استفاده از دستور if در اصطلاح به if تودرتو (Nested If) معروف است چراکه در آن از چندین دستور if مرتبط به یکدیگر استفاده شده است. چهارمین دستور if در مثال 1-3 استفاده از if تودرتو را نشان میدهد. در این حالت نیز دستور با کلمه کلیدی if آغاز میگردد. شرطی بررسی شده و در صورت true بودن دستورات مربوط به آن اجرا میگردد. اما اگر مقدار این عبارت منطقی false بود آنگاه شرطهای فرعی دیگری بررسی میشوند.این شرطهای فرعی با استفاده از else if مورد بررسی قرار میگیرند. هر یک از این شرطها دارای عبارات منطقی مربوط به خود هستند که در صورت true بودن عبارت منطقی دستورات مربوط به آنها اجرا میگردد و در غیر اینصورت شرط بعدی مورد بررسی قرار میگیرد. باید توجه کنید که در ساختار if تودرتو تنها یکی از حالتها اتفاق میافتد و تنها یکی از شرطها مقدار true را بازمیگرداند.
فرم کلی if تودرتو بشکل زیر است :
if (boolean expression)
{statements}
else if (boolean expression)
{statements}
…
else
{statements}
عملگرهای OR و AND (|| و &&)
نکته دیگری که باید در اینجا بدان اشاره کرد، نوع شرطی است که در عبارت منطقی دستور if آخر مورد استفاده قرار گرفته است. در این عبارت منطقی از عملگر || استفاده شده است که بیانگر OR منطقی است. عملگر OR زمانی مقدار true بازمیگرداند که حداقل یکی از عملوندهای آن دارای مقدار true باشد. بعنوان مثال در عبارت (myInt < 0 || myInt == 0)، در صورتیکه مقدار متغیر myInt کوچکتر یا مساوی با صفر باشد، مقدار عبارت برابر با true است. نکته قابل توجه آنست که در زبان C#، همانطور که در درس دوم به آن اشاره شد، دو نوع عملگر OR وجود دارد. یکی OR منطقی که با || نمایش داده میشود و دیگری OR معمولی که با | نشان داده میشود. تفاوت بین این دو نوع OR در آنست که OR معمولی هر دو عملگر خود را بررسی مینماید اما OR منطقی تنها در صورتیکه عملگر اول آن مقدار false داشته باشد به بررسی عملگر دوم خود میپردازد.
عبارت منطقی (myInt > 0 && myInt <= 10) حاوی عملگر AND شرطی (&&) میباشد. این عبارت در صورتی مقدار true بازمیگرداند که هر دو عملوند AND دارای مقدار true باشند. یعنی در صورتیکه myInt هم بزرگتر از صفر باشد و هم کوچگتر از 10، مقدار عبارت برابر با true میگردد. در مورد AND نیز همانند OR دو نوع عملگر وجود دارد. یکی AND معمولی (&) و دیگری AND شرطی (&&). تفاوت این دو نیز در آنست که AND معمولی (&) همیشه هر دو عملوند خود را بررسی مینماید ولی AND شرطی (&&) تنها هنگامی به بررسی عملوند دوم خود میپردازد که مقدار اولین عملوندش برابر با true باشد. عملگرهای منطقی (|| و &&) را در اصطلاح عملگرهای میانبر (short-circuit) مینامند چراکه تنها در صورت لزوم عملوند دوم خود را بررسی مینمایند و از اینرو سریعتر اجرا میشوند.
بررسی دستور switch
همانند دستور if، دستور switch نیز امکان تصمیمگیری را در یک برنامه فراهم مینماید.
مثال 2-3 – دستورالعمل switch
using System;
class SwitchSelect
{
public static void Main()
{
string myInput;
int myInt;
begin:
Console.Write("Please enter a number between 1 and 3: ");
myInput = Console.ReadLine();
myInt = Int32.Parse(myInput);
// بهمراه متغیری از نوع صحیح switch دستور
switch (myInt)
{
case 1:
Console.WriteLine("Your number is {0}.", myInt);
break;
case 2:
Console.WriteLine("Your number is {0}.", myInt);
break;
case 3:
Console.WriteLine("Your number is {0}.", myInt);
break;
default:
Console.WriteLine("Your number {0} is not between 1 and 3.", myInt);
break;
} //switchپایان بلوک
decide:
Console.Write("Type "continue" to go on or "quit" to stop: ");
myInput = Console.ReadLine();
// بهمراه متغیری از نوع رشتهای switch دستور
switch (myInput)
{
case "continue":
goto begin;
case "quit":
Console.WriteLine("Bye.");
break;
default:
Console.WriteLine("Your input {0} is incorrect.", myInput);
goto decide;
} //switchپایان بلوک
} //Main()پایان متد
} //SwitchSelectپایان کلاس
مثال 2-3 دو مورد استفاده از دستور switch را نشان میدهد. دستور switch بوسیله کلمه کلیدی switch آغاز شده و به دنبال آن عبارت دستور switch قرار میگیرد. عبارت دستور switch میتواند یکی از انواع زیر باشد : sbyte, byte, short, ushort, int, uint, long, ulong, char, string, enum .(نوع enum در مبحث جداگانهای مورد بررسی قرار خواهد گرفت.) در اولین دستور switch در مثال 2-3، عبارت دستور switch از نوع عددی صحیح (int) میباشد.
به دنبال دستور و عبارت switch، بلوک switch قرار میگیرد که در آن گزینههایی قرار دارند که جهت منطبق بودن با مقدار عبارت switch مورد بررسی قرار میگیرند. هر یک از این گزینهها با استفاده از کلمه کلیدی case مشخص میشوند. پس از کلمه کلیدی case خود گزینه قرار میگیرد و به دنبال آن ":" و سپس دستوری که باید اجرا شود. بعنوان مثال به اولین دستور switch در این برنامه توجه نمایید. در اینجا عبارت دستور switch از نوع int است. هدف از استفاده از دستور switch آنست که از بین گزینههای موجود در بلوک switch، گزینهای را که مقدارش با مقدار عبارت switch برابر است پیدا شده و عمل مرتبط با آن گزینه اجرا شود. در این مثال مقدار متغیر myInt بررسی میشود. سپس اگر این مقدار با یکی از مقادیر گزینههای داخل بلوک switch برابر بود، دستور یا عمل مربوط به آن گزینه اجرا میگردد. توجه نمایید که در این مثال منظور ما از گزینه همان عدد پس از case است و منظور از دستور عبارتی است که پس از ":" قرار گرفته است. بعنوان مثال، در دستور زیر :
case 1:
Console.WriteLine("Your number is {0}.", myInt);
عدد 1، گزینه مورد نظر ما و دستور Console.WriteLine(…)، عمل مورد نظر است. در صورتیکه مقدار myInt برابر با عدد 1 باشد آنگاه دستور مربوط به case 1 اجرا میشود که همان Console.WriteLine("Your number is {0}.", myInt); است. پس از منطبق شدن مقدار عبارت switch با یکی از case ها، بلوک switch باید خاتمه یابد که این عمل بوسیله استفاده از کلمه کلیدی break، اجرای برنامه را به اولین خط بعد از بلوک switch منتقل مینماید.
همانطور که در ساختار دستور switch مشاهده مینمایید، علاوه بر case و break، دستور دیگری نیز در داخل بلوک وجود دارد. این دستور یعنی default، برای زمانی مورد استفاده قرار میگیرد که هیچ یک از گزینههای بلوک switch با عبارت دستور switch منطبق نباشند. به عبارت دیگر درصورتیکه مقدار عبارت switch با هیچ یک از گزینههای case برابر نباشد، دستور مربوط به default اجرا میگردد. استفاده از این دستور در ساختار بلوک switch اختیاری است. همچنین قرار دادن دستور break پس از دستور default نیز اختیاری میباشد.
همانطور که قبلاً نیز گفته شد پس از هر دستور case، به منظور خاتمه دادن اجرای بلوک switch باید از یک break استفاده نمود. دو استثنا برای این موضوع وجود دارد. اول اینکه دو دستور case بدون وجود کد و دستورالعملی در بین آنها، پشت سر هم قرار گیرند و دیگری در زمانیکه از دستور goto استفاده شده باشد.
در صورتیکه دو دستور case بدون وجود کدی در بین آنها، پشت سر یکدیگر قرار گیرند، بدین معناست که برای هر دو case مورد نظر یک عمل خاص در نظر گرفته شده است. به مثال زیر توجه نمایید.
switch (myInt)
{
case 1:
case 2:
case 3:
Console.WriteLine("Your number is {0}.", myInt);
break;
default:
Console.WriteLine("Your number {0} is not between 1 and 3.", myInt);
break;
}
در این مثال، همانطور که مشاهده میکنید، سه دستور case بدون وجود کدی در بین آنها پشت سر یکدیگر قرار گرفتهاند. این عمل بدین معناست که برای تمامی گزینههای 1، 2 و 3 دستور ;(Console.WriteLine("Your number is {0}.", myInt اجرا خواهد شد. یعنی اگر مقدار myInt برابر با هر یک از مقادیر 1، 2 و 3 باشد، یک دستور برای آن اجرا میشود.
نکته قابل توجه دیگر در مورد بلوک switch آنست که، دستورات case حتماً نباید یک دستور باشد بلکه میتوان از یک بلوک دستور برای case استفاده نمود.
دومین استفاده از دستور switch در مثال 2-3، دارای عبارتی از نوع رشتهایست. در این بلوک switch چگونگی استفاده از دستور goto نیز نشان داده شده است. دستور goto اجرای برنامه را به برچسبی (label) که معین شده هدایت مینماید. در حین اجرای این برنامه، اگر کاربر رشته continue وارد نماید، این رشته با یکی از گزینههای دومین switch منطبق میشود. چون دستور case مربوط به این گزینه دارای دستور goto است، اجرای برنامه به برچسبی که این دستور مشخص کرده فرستاده میشود، بدین معنی که اجرای برنامه به ابتدای جایی میرود که عبارت begin: در آنجا قرار دارد (در اوایل متد Main()). بدین صورت اجرای برنامه از بلوک switch خارج شده و به ابتدای برنامه و در جائیکه برچسب begin: قرار گرفته ارسال میشود. در این برنامه، استفاده از چنین حالتی استفاده از goto باعث ایجاد یک حلقه شده است که با وارد کردن عبارت quit اجرای آن به پایان میرسد.
در صورتیکه هیچ یک از عبارات continue و یا quit وارد نشوند، اجرای switch به گزینه default میرود و در این گزینه ابتدا پیغام خطایی بر کنسول چاپ شده و سپس با استفاده از دستور goto پرشی به برچسب decide صورت میگیرد. پس از پرش به برچسب decide، از کاربر پرسیده میشود که آیا میخواهد اجرای برنامه را ادامه دهد یا خیر.( با وارد کردن گزینههای continue یا quit) همانطور که میبینید در اینجا نیز حلقهای تولید شده است.
استفاده از دستور goto در بلوک switch میتواند موثر باشد اما باید توجه نمایید که استفادههای بی مورد از دستور goto باعث ناخوانا شدن برنامه شده و عیبیابی (Debug) برنامه را بسیار دشوار مینماید. در برنامهنویسیهای امروزی استفاده از دستور goto بغیر از موارد بسیار لازم و ضروری منسوخ شده و به هیچ عنوان توصیه نمیشود. برای تولید و ساخت حلقه نیز دستورات مفید و سودمندی در زبان تعبیه شدهاند که استفاده از goto را به حداقل میرسانند. دستورات حلقه در مبحث آینده مورد بررسی قرار خواهند گرفت.
نکته پایانی این مبحث آنست که توجه نمایید که به جای استفاده از دستور switch میتوانید از چندین دستور if-else استفاده نماید. دو قطعه برنامه زیر معادل یکدیگر میباشند.
switch(myChar)
{
case 'A' :
Console.WriteLine("Add operation ");
break;
case 'M' :
Console.WriteLine("Multiple operation ");
break;
case 'S' :
Console.WriteLine("Subtraction operation ");
break;
default :
Console.WriteLine("Error, Unknown operation ");
break;
}
معادل بلوک switch با استفاده از if-else
if (myChar == 'A')
Console.WriteLine("Add operation ");
else if (myChar == 'M')
Console.WriteLine("Multiple operation ");
else if (myChar == 'S')
Console.WriteLine("Subtraction operation ");
else
Console.WriteLine("Error, Unknown operation ");
همانطور که ملاحظه میکنید استفاده از بلوک دستور switch بسیار سادهتر از استفاده از if-else های تودرتو است.
در این درس با نحوه تصمیمگیری در برنامه بوسیله دستور if و switch آشنا شدید. با نحوه عملکرد و استفاده دستور goto نیز آشنایی پیدا کردید. در پایان مجدداً یادآوری میکنم که در استفاده از دستور goto با احتیاط عمل نمایید و به جز در موارد ضروری از آن استفاده نکنید.
ادامه درس دوم
یکی دیگر از انواع دادهای در زبان C#، آرایهها (Arrays) میباشند. یک آرایه را به عنوان مخزنی برای نگهداری اطلاعات در نظر میگیریم که دارای لیستی از محلهایی است که در آنها اطلاعات ذخیره شده است و از طریق این لیست میتوان به اطلاعات آنها دسترسی پیدا نمود. به هنگام اعلان آرایهها باید نوع، اندازه و تعداد بعد آنها را نیز معین نمود.
مثال 4- آرایهها و عملیات بر روی آنها
using System;
class Array
{
public static void Main()
{
int[] myInts = { 5, 10, 15 };
bool[][] myBools = new bool[2][];
myBools[0] = new bool[2];
myBools[1] = new bool[1];
double[,] myDoubles = new double[2, 2];
string[] myStrings = new string[3];
Console.WriteLine("myInts[0]: {0}, myInts[1]: {1}, myInts[2]: {2}", myInts[0],
myInts[1], myInts[2]);
myBools[0][0] = true;
myBools[0][1] = false;
myBools[1][0] = true;
Console.WriteLine("myBools[0][0]: {0}, myBools[1][0]: {1}", myBools[0][0],
myBools[1][0]);
myDoubles[0, 0] = 3.147;
myDoubles[0, 1] = 7.157;
myDoubles[1, 1] = 2.117;
myDoubles[1, 0] = 56.00138917;
Console.WriteLine("myDoubles[0, 0]: {0}, myDoubles[1, 0]: {1}", myDoubles[0, 0], myDoubles[1, 0]);
myStrings[0] = "Joe";
myStrings[1] = "Matt";
myStrings[2] = "Robert";
Console.WriteLine("myStrings[0]: {0}, myStrings[1]: {1}, myStrings[2]: {2}",
myStrings[0], myStrings[1], myStrings[2]);
}
}
خروجی مثال 4 بصورت زیر است :
myInts[0]: 5, myInts[1]: 10, myInts[2]: 15
myBools[0][0]: True, myBools[1][0]: True
myDoubles[0, 0]: 3.147, myDoubles[1, 0]: 56.00138917
myStrings[0]: Joe, myStrings[1]: Matt, myStrings[2]: Robert
در این مثال انواع مختلفی از آرایهها اعلان شدهاند. در ابتدا یک آرایه تک بعدی، سپس آرایهای دندانهدار و در نهایت نیز یک آرایه دو بعدی در این مثال اعلان شدهاند.
اولین اعلان در این برنامه مربوط به اعلان آرایه تک بعدی myInts میباشد که از نوع int بوده و دارای 3 عضو میباشد که تعداد این اعضا با اعلان چند مقدار در داخل { } معین شده است. همانطور که از این اعلان دریافت میشود، آرایه تک بعدی بصورت زیر تعریف میشود :
type[] arrayName;
که در آن type نوع آرایه و arrayName نام آرایه ایست که تعریف مینمائیم.
اما در ابتدا گفته شد که به هنگام اعلان آرایهها اندازه آنها نیز باید مشخص شود. برای تعیین اندازه آرایه، یعنی تعدا عناصری که آرایه در خود جای میدهد، میتوان به چند روش عمل نمود. اولین و سادهترین روش که در این مثال نیز آورده شده است، تخصیص مقادیری به آرایه در داخل یک زوج { } است. بسته به نوع آرایه، تعداد عناصری که داخل این زوج { } قرار میگیرند، تعداد عناصر آرایه میباشند و مقادیر عناصر آرایه نیز همان مقادیری است که داخل { } قرار گرفته است. به عنوان مثال در مثال 4، اولین آرایه ما دارای 3 عنصر است که مقادیر آنها به ترتیب برابر با 5، 10 و 15 میباشد.
روش دیگر جهت تعیین اندازه آرایه استفاده از روش تعریف کامل آرایه است که به فرم کلی زیر میباشد.
type[] arrayName = new type[n];
که در این تعریف، استفاده از کلمه کلیدی new باعث ایجاد نمونهای جدید از نوع مورد نظر، میشود. n نیز تعداد عناصر آرایه است که میخواهیم آنرا تولید نماییم. در این حالت باید توجه داشت که آرایهای تهی را تولید نمودهایم و هیچ عنصری را در آرایه جای ندادهایم و در برنامه باید آرایه را مقدار دهی نماییم. به مثال زیر توجه کنید.
int[] myArray = new int[15];
این مثال آرایهای تک بعدی از نوع int را با اندازه 15 عنصر تولید مینماید. یعنی این آرایه قادر است تا 15 عنصر از نوع int را در خود ذخیره نماید.
گونه دیگری از آرایهها، آرایههای چند بعدی (Multi Dimensional Arrays) هستند که برای نگهداری اطلاعات از چندین بعد استفاده میکنند و بیشتر برای نگداری جداول و ماتریسها مورد استفاده قرار میگیرند. فرم کلی اعلان این آرایهها بصورت زیر است :
type[ , , … , ] arrayName = new type[n1, n2, …. , nm];
که در آن تعداد ابعاد آرایه با ویرگول مشخص شده و n1 تا nm نیز تعداد عناصر هر یک از ابعاد است. بعنوان مثال تعریف یک آرایه سه بعدی به فرم زیر است :
char[ , , ] charArray = new char[3,5,7];
در این مثال یک آرایه سه بعدی از نوع char تولید کردهایم که ابعاد آن به ترتیب دارای 3، 5 و 7 عنصر میباشند.
نوع دیگری از آرایهها، آرایههای دندانهدار (Jagged Arrays) هستند. این نوع آرایهها تنها در زبان C# وجود دارند و در صرفهجویی حافظه بسیار موثر میباسند. یک آرایه دندانهدار، در حقیقت یک آرایه تک بعدی است که هر یک از اعضای آن خود یک آرایه تک بعدی میباشند. اندازه این عناصر میتواند متفاوت باشد و تفاوت این آرایهها با آرایههای چند بعدی در همین جا نمایان میشود. استفاده از این آرایهها در مواردی کاربرد دارد که نیازی نیست تا تمامی ابعاد آرایه دارای تعداد عناصر مساوی باشند. بعنوان مثال فرض کنید میخواهید آرایهای جهت نگهداری تعداد روزهای ماههای مختلف سال تهیه کنید. در صورتیکه بخواهید از آرایه چند بعدی استفاده نمایید، چون تعداد روزهای تمامی ماههای سال یکسان نیست، مجبورید تا تعداد عناصر تمام بعدهای آرایه را برابر با بزرگترین تعداد روز ماهها، یعنی 31، تعریف نمایید. ولی چون تنها 6 ماه دارای 31 روز میباشند، برای 6 ماه دیگر تعدادی از عناصر آرایه هیچگاه مورد استفاده قرار نمیگیرند و حافظه را به هدر دادهایم. اما در صورتیکه برای این مثال از آرایههای دندانهدار استفاده نماییم، میتوانیم یک آرایه دندانهدار 12 عنصری تعریف نماییم و سپس تعداد عناصر هر یک از اعضای آنرا برابر با تعداد روزهای ماه مورد نظر تعریف کنیم :
با استفاده از آرایه چند بعدی :
int[ , ] monthArray = new int[12,31];
با استفاده از آرایه دندانهدار :
int[][] monthArray = new int[12][];
در تعریف اول که در آن از آرایه چند بعدی استفاده کردیم، مشاهده میکنید که آرایهای دو بعدی تعریف کردهایم که بعد اول آن 12 عضو و بعد دوم آن 31 عضو دارد. این عمل دقیقاً همانند ایجاد یک جدول برای نگهداری روزهای ماههای سال است.
اما در حالت دوم که در آن از آرایه دندانهدار بهره بردهایم، یک آرایه تعریف نمودهایم که بعد اول آن 12 عضو دارد ولی بعد دوم آنرا را تعریف نکردهایم که دارای چند عضو است و هر یک از عناصر بعد اول آرایه میتواند دارای تعداد اعضای متفاوتی باشد که با استفاده از این روش میتوان به هر یک از ماههای سال تعداد روزهای مورد نظر آن ماه را تخصیص داد و فضایی بلا استفاده ایجاد نخواهیم کرد. توجه نمایید که چون تعداد عناصر بعد دیگر این آرایه معین نشده است در برنامه باید این تعداد عنصر را مشخص نماییم :
monthArray[1] = new int[31];
monthArray[10] = new int [30];
مشاهده میکنید که به هر ماه، تعدا عنصر مورد نیاز خود را تخصیص دادهایم. تنها باید به تفاوت اعلان آرایههای دندانهدار با آرایههای چند بعدی توجه نمایید.
دسترسی به عناصر آرایه از طریق اندیس امکان پذیر است. اندیس شماره محل ذخیرهسازی دادههای ما میباشد که با دادن این شماره میتوانیم به داده مورد نظر دسترسی پیدا کنیم. در C# همانند C و C++ اندیس خانههای آرایه از صفر آغاز میگردد یعنی اولین خانه آرایه دارای شماره صفر است و عناصر بعدی به ترتیب یک واحد به اندیسشان اضافه میگردد. پس شماره اندیس آرایه همیشه یک واحد کمتر از تعداد عناصر آن است، یعنی آرایهای که 10 عضو دارد بزرگترین اندیس خانههایش 9 میباشد. دسترسی به عناصر هر یک از ابعاد آرایه با اندیس امکان پذیر است. معمولاً به بعد اول آرایه سطر و به بعد دوم آن ستون میگوید. مثلاً monthArray[3,7] عنصر واقع در سطر 3 و ستون 7 آرایه را مشخص مینماید.(توجه داشته باشید که اندیس دهی آرایه از صفر آغاز میشود و بعنوان مثال intArray[12] به خانه شماره 12 آرایه اشاره میکند اما فراموش نکنید چون اندیس آرایه از صفر آغاز میشود خانه شماره 12 آرایه، سیزدهمین داده شما را در خود جای میدهد.)
12
11
10
9
8
7
6
5
4
3
2
1
0
اگر شکل فوق را آرایهای تک بعدی تصور نمایید، مشاهده مینمایید که خانه شماره 5 آرایه حاوی اطلاعات مربوط به ششمین داده ورودی شما میباشد.
نکته دیگری که باید در مورد تعریف آرایههای این مثال متذکر شوم در مورد آریههائیست که از نوع string تعریف میشوند. دوستانی که با زبان C کار کردهاند حتماً میدانند که آرایهای از نوع رشتهای در C وجود ندارد و برای نگهداری چندین رشته در یک آرایه باید از آرایه دو بعدی استفاده کرد. در C# این قابلیت فراهم شده تا با استفاده از یک آرایه تک بعدی بتوان چندین رشته را ذخیره نمود بدین صورت که هر یک از عناصر آرایه نک بعدی محلی برای ذخیرهسازی یک رشته است و همانند زبان C نیاز به پردازشهای گاه پیچیده بر روی آرایههای چند بعدی بمنظور کار با رشتهها، وجود ندارد. بعنوان یک توضیح کمی اختصاصی عرض میکنم که در زبانهایی مانند C، در صورتیکه میخواستید چندین رشته را در آرایهای ذخیره کنید تا بتوانید با اندیس به آنها دسترسی داشته باشید، مجبور به تعریف یک آرایه دو بعدی بودید که با استفاده از تنها اندیس اول آرایه میتوانستید به عناصر رشتهای آرایه دسترسی پیدا کنید، اما در C# تنها با استفاده از یک آرایه تک بعدی میتوان همان کار را انجام داد.
string[] stringArray = {"My name is Hadi", "This is C# Persian Blog"}
…..
Console.WriteLine("{0}",stringArray[0]);
…..
همانطور که در این مثال ملاحظه میکنید، آرایهای از نوع رشته تعریف شده و دو عنصر به آن تخصیص داده شده است و در جایی در متن برنامه با استفاده از اندیس از اولین عنصر این آرایه برای نمایش در خروجی استفاده گردیده است. خروجی این برنامه به شکل زیر است :
My name is Hadi
مطلب این درس در اینجا به پایان میرسد. در صورتیکه نیاز دارید تا در مورد عملگرهای زبان C# بیشتر توضیح دهم حتماً ذکر کنید تا در مطلب بعدی توضیح کاملتری در مورد آنها برای شما تهیه کنم. خیلی دوست داشتم که در مورد تمام عملگرهای زبان C# در همین درس توضیح بدهم اما هم فرصت اندک است و هم حجم مطلب این قسمت زیاد میشد و هم اینکه فکر کردم احتمالاً دوستان با این عملگرها آشنایی دارند. نکته دیگری که باید به آن اشاره کنم و اینست که در این سایت سعی شده است تا زبان برنامهنویسی C# به سادگی و به سرعت آموزش داده شود و علت اینکه به برخی از جزئیات تخصصی پرداخته نمیشود نیز همین مطلب میباشد. در آینده در مورد آرایهها بیشتر صحبت میکنم چون عناصر مفید و سودمندی هستند. امید است پس از کامل کردن مطالب مقدماتی در این سایت و با همکاری شما عزیزان بتوانم به مطالب پیشرفتهتری از زبان C# بپردازم. بیان نظرات و پیشنهادات شما چه در زمینه مطالب ارائه شده و چه در زمینه متن ارائه شده به شما از لحاظ سادگی و روانی در درک، مرا در امر بهبود مطالب یاری مینماید.