تبلیغات
Bcode.ir - حلقه‌های تکرار در ++C

حلقه‌های تکرار در ++C

نویسنده :
تاریخ:سه شنبه 3 فروردین 1395-03:38 ق.ظ

حلقه تکرار c++

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

  • حلقه‌ی تکرار while
این نوع حلقه ساده‌ترین نوع حلقه‌ی تکرار در این زبان برنامه‌نویسی است. فرم کلی حلقه‌ی while به این صورت است:

while( شرط اجرای حلقه )

{
  دستورات داخل حلقه
}

عبارت‌های داخل حلقه تا زمانی که شرط اجرای حلقه صحیح باشد اجرا خواهند شد. به عنوان مثال:

int n = 1;
while( n <= 10 )
{
  cout << n << endl;
  n++;
}

در این قطعه کد، ابتدا متغیر n با عدد یک مقداردهی می‌شود. سپس شرط n ≤ 10 بررسی می‌شود که صحیح است. پس اجرای قطعه کد با دستورات داخل حلقه ادامه پیدا می‌کند. در این حلقه مقدار n چاپ شده و یک واحد به آن اضافه می‌شود. سپس کنترل برنامه به ابتدای حلقه باز می‌گردد. اگر شرط حلقه همچنان صحیح باشد، عبارت‌های داخل آن مجددا اجرا خواهند شد. در نتیجه قطعه کد فوق اعداد یک تا ده را به ترتیب در سطرهای جداگانه‌ی خروجی چاپ خواهد کرد.

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

int n = 11;
while( n <= 10 )
{
  cout << n << endl;
  n++;
}
     
 این قطعه کد خروجی ندارد. چرا که شرط اجرای حلقه هنگام ورود به آن نیز نادرست است.
 
  • حلقه‌ی تکرار do-while

فرم کلی این حلقه به صورت زیر است:
  
do
{
  دستورات داخل حلقه
}while( شرط اجرای حلقه );

تنها تفاوت این حلقه با حلقه‌ی while در این است که شرط اجرای حلقه‌ی do-while در انتهای آن بررسی می‌شود. به عنوان مثال:

int n = 1;
do
{
  cout << n << endl;
  n++;
}while( n <= 10 );

در این قطعه کد نیز همانند قطعه کد قبلی اعداد یک تا ده در خروجی چاپ می‌شوند.
تفاوت این دو حلقه در قطعه کد زیر - که برای حلقه‌ی while هم نوشته شده بود - آشکار می‌شود:

int n = 11;
do
{
  cout << n << endl;
  n++;
}while( n <= 10 );
    
همانگونه که عنوان شد، در حلقه‌ی while شرط اجرای دستورات داخل حلقه در ابتدای آن بررسی می‌شود. اما در حلقه‌ی do-while این شرط در انتهای آن قرار دارد. در نتیجه دستورات داخل حلقه قبل از رسیدن به شرط حلقه یک بار اجرا می‌شوند. یعنی قطعه کد فوق عدد 11 را چاپ کرده و سپس با توجه به اینکه شرط n ≤ 10 نادرست است، کنترل برنامه به داخل حلقه باز نمی‌گردد.

    به طور خلاصه می‌توان گفت: تفاوت حلقه‌ی do-while با حلقه‌ی while در این است که دستورات داخل حلقه‌ی do-while حداقل یک بار اجرا می‌شوند. بیشتر کاربردهای چنین حلقه‌ای هم به خاطر همین خاصیت آن است.

  • حلقه‌ی تکرار for
ساده‌ترین نوع تعریف حلقه‌ی for به این ترتیب است:


for( نمو ; شرط اجرای حلقه ; مقداردهی اولیه )
{
  دستورات داخل حلقه
}

 به مثال زیر توجه کنید:

int n;
for( n = 1 ; n <= 10 ; n++ )
{
  cout << n << endl;
}

 این حلقه نیز اعداد یک تا ده را در خروجی چاپ می‌کند. اما چگونه؟

 با اجرای خط اول، متغیر n تعریف می‌شود. سپس بخش "مقداردهی اولیه" اجرا شده و مقدار n برابر عدد یک می‌شود. پس از آن "شرط اجرای حلقه" بررسی می‌شود. این شرط همانند شروط حلقه‌های قبلی عمل کرده و در صورت نادرست بودن کنترل برنامه از حلقه خارج می‌شود. اما اگر شرط صحیح باشد کنترل برنامه وارد حلقه شده و دستورات داخل آن اجرا می‌شوند. در اجرای بعدی بخش "مقداردهی اولیه" اجرا نمی‌شود. اما قبل از بررسی "شرط اجرای حلقه"، عملیات بخش "نمو" اجرا می‌شوند. همانگونه که شرح داده شد، این عملیات در اجرای اول و زمان ورود به حلقه اجرا نمی‌شوند. پس از نمو، شرط اجرای حلقه بررسی شده و به همین ترتیب اجرای برنامه ادامه پیدا می‌کند.

توجه داشته باشید که لزومی ندارد نمو همواره افزایش یک واحدی باشد:

for( n = 1 ; n <= 10 ; n += 1 )
for( n = 1 ; n <= 10 ; n += 2 )
for( n = 10 ; n >= 1 ; n -= 1 )
for( n = 10 ; n >= 1 ; n-- )
for( n = 1 ; n <= 100 ; n *= 2 )
for( n = 100 ; n >= 1 ; n /= 10 )     

تمامی این عبارت‌ها صحیح هستند.

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

int sum( int arr[ ], int size)
{
  int i, sum = 0;
  for( i = 0 ; i < size ; i++ )
  {
    sum += arr[ i ];
  }
  return sum;
}
     
همانطور که می‌دانید، اندیس آرایه‌ها در زبان ++C از صفر شروع می‌شوند. پس اگر تعداد عناصر آن size باشد، اندیس‌ها از صفر تا size - 1 خواهند بود. حلقه‌ی for فوق نیز با شروع از عدد صفر و افزایش یک واحد در هر اجرا، مجموع عناصر اندیس‌های صفر تا size - 1 را محاسبه می‌کند.

نکته: تعریف ارائه شده برای حلقه‌ی for می‌تواند با استفاده از حلقه‌ی while به صورت زیر شبیه‌سازی شود:

مقداردهی اولیه

while( شرط اجرای حلقه )
{
  دستورات داخل حلقه
}
  
این شبیه‌سازی دو حسن دارد. اول اینکه عملکرد حلقه‌ی for و ترتیب اجرای بخش‌های سه‌گانه‌ی آن بهتر مشخص می‌شود. و دوم، ما را متوجه نکته‌ی مهمی می‌کند: لزومی ندارد بخش‌های سه‌گانه‌ی حلقه‌ی for از عبارت‌های محاسباتی تشکیل شده باشند. هر کدام از بخش‌های مقداردهی اولیه و نمو می‌توانند شامل هر دستور متعارفی از این زبان باشند. شرط اجرای حلقه هم می‌تواند هرگونه شرطی (نه لزوما محاسباتی) باشد. در ضمن توجه داشته باشید که وارد کردن اطلاعات هر کدام از این بخش‌ها اختیاری است. به مثال ساده‌ی زیر توجه کنید:

int n = 0;
for( ; n < 0 || n > 20 ; )
{
  cout << "Enter a number between 0 and 20: ";
  cin >> n;
}
 
   
 چنین حلقه‌ای بدون مقداردهی اولیه و نمو است. در صورتی که کاربر عددی بیرون از بازه‌ی صفر و بیست وارد کند، شرط ادامه‌ی حلقه صحیح بوده و برنامه مجددا با چاپ پیامی منتظر ورود اطلاعات خواهد ماند. البته حلقه‌هایی نظیر این حلقه بیشتر با while یا do-while پیاده‌سازی می‌شوند.

نکته: حلقه‌ی for به صورت زیر نیز استفاده می‌شود:   

for( int n = 1 ; n <= 10 ; n++ )
{
  دستورات داخل حلقه


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

int n = 1;
while( n <= 10 )
{
  دستورات داخل حلقه
  n++;
}


حلقه‌ی for محدوده‌ای (Ranged-Based)

یکی از کاربردهای مهم حلقه‌ی for پیمایش مجموعه‌ای از داده‌ها (مثل آرایه یا vector) از ابتدا تا انتها به منظور انجام عملیات مختلف است:
    

int array[ 10 ] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

for( int i = 0 ; i < 10 ; i++ )

{

  cout << array[ i ] << endl;

}

    استاندارد c++11 شکل جدیدی از حلقه‌ی for برای چنین کاربردی پیشنهاد می‌دهد:   

for( int x : array )
{
  cout << x << endl;


 بر اساس این تعریف در هر تکرار یک عضو آرایه‌ی array در متغیر x قرار گرفته و دستورات داخل حلقه اجرا می‌شود. این ساختار برای هر نوع مجموعه‌ای از اشیاء که قابلیت تشخیص ابتدا و انتهای آن وجود داشته و عملگرهایی برای پیمایش آنها تعریف شده باشد (مثل آرایه، vector، list و ...) قابل استفاده است.

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

void func( int arr[ ] )
{
  for( int x : arr )
  {
    cout << x << endl;
  }
}

تذکر: زمانی که متغیر به صورت

for( int x : array )

  تعریف می‌شود، در هر تکرار یک کپی از مقدار عنصر در x قرار می‌گیرد. در نتیجه تغییر x اثری در آرایه ندارد. به عنوان مثال، قطعه کد زیر تغییری در عناصر array ایجاد نمی‌کند:   

for( int x : array )
{
  cin >> x;


در این حالت متغیر x باید به صورت متغیر مرجع تعریف شود:     

for( int &x : array )
{
  cin >> x;
}

 از قطعه کدی مانند

for( const className &x : array )

 نیز زمانی استفاده می‌شود که هدف تغییر دادن عناصر مجموعه‌ی array نبوده، اما کپی هر شی از نوع className در متغیر x از لحاظ زمانی یا مصرف حافظه به صرف نیست. در چنین شرایطی استفاده از متغیر مرجع (برای اجتناب از کپی) با کلمه‌ی کلیدی const (برای جلوگیری از تغییر) توصیه می‌شود.
     
ماکروی for_each

ماکروی for_each از مجموعه توابع کتابخانه‌ی استاندارد ++C است که تعریف آن در فایل سرآیند algorithm قرار دارد. این ماکرو نیز همانند حلقه‌ی for محدوده‌ای عمل می‌کند. با این تفاوت که امکان تعیین ابتدا و انتهای بازه مورد نظر وجود دارد:

void print( int n )
{
  cout << n << endl;
}
int main( )
{
  std::vector< int > arr = { 1, 2, 3, 4, 5 };
  for_each( arr.begin() + 1, arr.end() - 1, print );
}
 

    خروجی این برنامه اعداد 2 تا 4 بوده و عملکرد ماکروی for_each معادل حلقه‌ی for زیر است:     

for( std::vector<int>::iterator it = arr.begin() + 1 ; it != arr.end() - 1 ; it++ )
{
   print( *it );
}
 

دستور break

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

تابع زیر در آرایه‌ی n عنصری arr (با عناصر متمایز) به دنبال خانه‌ای با محتوای x می‌گردد و شماره‌ی اندیس این خانه را به عنوان نتیجه باز می‌گرداند:   

int search( int[ ] arr, int n, int x )
{
  int i, result = -1;
  for( i = 0 ; i < n ; i++ )
  {
    if( arr[ i ] == x )
    {
      result = i;
    }
  }
  return result;
}   

روش کار تابع ساده است: با استفاده از حلقه‌ی تکرار for اندیس‌های صفر تا n - 1 برای یافتن عنصر مورد نظر پیمایش می‌شوند. اگر چنین عنصری یافت شود شماره‌ی اندیس خانه مربوطه در result قرار می‌گیرد. اگر یافت نشود، مقدار result همان منفی یک باقی می‌ماند که در تعریف آن مقداردهی شده است. چنین عددی هرگز نمی‌تواند شماره‌ی اندیس یک خانه‌ی آرایه در زبان ++C باشد. بنابراین روش خوبی برای نشان دادن عدم موفقیت عملیات جستجو است.

    این تابع جستجو از لحاظ الگوریتمی ایرادی ندارد. اما می‌توان در پیاده‌سازی آن کمی دقیق‌تر بود. فرض کنید n برابر صد هزار بوده و عدد x در خانه‌ی دوم آرایه قرار داشته باشد. پس در تکرار دوم حلقه، عنصر مورد نظر یافت می‌شود. اما کنترل برنامه تا پایان یافتن بررسی تمامی صد هزار عنصر در داخل حلقه خواهد ماند. این بررسی کاملا بیهوده بوده و موجب اتلاف وقت خواهد شد. این مشکل را می‌توان با دستور break حل کرد:

int search( int[ ] arr, int n, int x )
{
  int i, result = -1;
  for( i = 0 ; i < n ; i++ )
  {
    if( arr[ i ] == x )
    {
      result = i;
      break;
    }
  }
  return result;
}

تفاوت این تابع با تابع قبلی تنها در دستور break است. با استفاده از این دستور، هرگاه شرط arr[ i ] == x صحیح باشد، پس از تخصیص مقدار i به result، دستور break اجرا می‌شود. اجرای این دستور موجب می‌شود که کنترل برنامه از حلقه خارج شده و به اولین خط بعد از آن منتقل شود. بنابراین اگر عنصر مورد نظر ما در خانه‌ی شماره‌ی دو قرار داشته باشد، دستورات داخل حلقه تنها سه بار (شماره‌ها از صفر شروع می‌شوند) تکرار می‌شوند.     

دستور continue

این دستور برای ادامه‌ی کار حلقه از تکرار بعدی آن استفاده می‌شود. به عبارت دیگر، زمانی که کنترل برنامه در داخل حلقه به دستور continue می‌رسد، از تمامی دستورات بعدی حلقه تا انتهای آن صرف نظر شده و به شروع تکرار بعدی حلقه می‌رسد. اگر حلقه‌ی مورد نظر حلقه‌ی while یا do-while باشد، شرط ادامه‌ی حلقه بررسی می‌شود؛ اما اگر حلقه‌ی for باشد، ابتدا بخش نمو اجرا شده و سپس شرط حلقه بررسی می‌شود. به مثال ساده‌ی زیر توجه کنید:

int i, s = 0, p = 1;
for( i = 1 ; i <= 10 ; i++ )
{
  if( i % 2 == 0 )
  {
    continue;
  }
  s += i;
  p *= i;
}

 در این حلقه اگر i عدد زوجی باشد، دستور continue اجرا شده و کنترل اجرای برنامه به ابتدای تکرار بعدی می‌رود. در نتیجه به مقدار i یک واحد افزوده شده و سپس شرط ادامه‌ی حلقه بررسی می‌شود.

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

حلقه‌هایی با شرط همواره صحیح

تمام حلقه‌های تکرار برای ادامه‌ی کار خود شرطی را بررسی می‌کنند. این شرط می‌تواند یک عبارت مقایسه‌ای ساده، ترکیب عبارات محاسباتی یا هر ساختار دیگری باشد. اگر این شرط به گونه‌ای باشد که همیشه صحیح باشد، حلقه‌هایی با شرط همواره صحیح به وجود می‌آیند. در این حلقه‌ها شرط ادامه‌ی حلقه همواره صحیح است. پس در حالت عادی حلقه هرگز خاتمه پیدا نمی‌کند! چنین حلقه‌هایی اگر به درستی کنترل نشوند به یک حلقه‌ی بدون توقف تبدیل می‌شوند که در اصطلاح به آنها حلقه‌ی بی‌نهایت گفته می‌شود. حلقه‌های بی‌نهایت گاهی در اثر اشتباهات منطقی در پیاده‌سازی الگوریتم بروز می‌دهند و باعث شکست اجرای صحیج برنامه می‌شوند. اما اگر در داخل حلقه و در جای مناسب از دستور break استفاده شود، چنین حلقه‌هایی نیز پایان‌پذیر خواهند بود:
   
int n;
while( 1 )    // while( true )
{
  cout << "Enter a positive number:";
  cin >> n;
  if( n > 0 )
  {
    break;
  }


شرط اجرای این حلقه عدد یک است. در زبان ++C هر عدد غیر صفر (صحیح یا اعشاری) معنی درست و عدد صفر معنی نادرست می‌دهد. پس حلقه‌ی فوق یک حلقه با شرط صحیح است. در داخل حلقه از کاربر عدد مثبتی درخواست می‌شود. اگر کاربر صفر یا یک عدد منفی وارد کند شرط n > 0 صحیح نبوده و کنترل برنامه مجددا به ابتدای حلقه منتقل خواهد شد، تا عدد دیگری از کاربر دریافت کند. اما اگر شرط n > 0 صحیح باشد، دستور break اجرا شده و کنترل برنامه از حلقه خارج خواهد شد. یعنی تکرار حلقه تا زمانی ادامه پیدا می‌کند که کاربر عدد مثبتی وارد نکرده است. به محض اینکه اولین عدد مثبت وارد شد، کنترل برنامه نیز از حلقه خارج می‌شود. البته در این مثال خاص می‌توان حلقه‌ی فوق را به صورت زیر نیز پیاده‌سازی کرد: 

int n;
do
{
  cout << "Enter a positive number:";
  cin >> n;

}while( n <= 0 );  

 اگر برای حلقه‌ی for شرطی را قائل نشویم، به مفهوم شرط همواره درست است:
    
int n;
for ( ; ; )
{
  cout << "Enter a positive number:";
  cin >> n;
  if( n > 0 )
  {
    break;
  } 
}   

 توجه: علامت‌های سمیکالن (;) همیشه باید نوشته شوند. 

حلقه‌های تو در تو

در زبان برنامه‌نویسی ++C امکان استفاده از حلقه‌های تکرار تو در تو نیز وجود دارد. قطعه کد زیر جدول ضرب اعداد 4 تا 9 را در خروجی چاپ می‌کند:

int i, j;
for( i = 4 ; i < 10 ; i++ )
{
  for( j = 4 ; j < 10 ; j++ )
  {
    cout << i * j << " ";
  }
  cout << endl;
}   

حلقه‌ی داخلی وظیفه‌ی چاپ اعداد هر سطر را دارد. پس از اتمام این حلقه، دستوری اجرا می‌شود که مکان‌نما را به ابتدای سطر بعدی می‌برد. پس در هر سطر یک ردیف از جدول ضرب چاپ می‌شود.   

در پایان به دو نکته توجه داشته باشید:

 1- در این ساختارها اگر مجموعه دستورات داخل حلقه تنها شامل یک دستور باشد، نیازی به استفاده از آکولاد برای مشخص کردن بلوک مجموعه دستورات داخل حلقه وجود ندارد.

 2- عبارت‌های دستوری break ،while ،do ،for و continue جزو کلمات کلیدی زبان برنامه‌نویسی ++C هستند.



تلگرام

دسته بندی : C++& C 

برچسب ها: درس حلقه های تکرار سی پلاس، while و do while و for سی پلاس پلاس، فرق while و do while، انواع حلقه for در زبان C، کاربرد break و continue در سی پلاس، آموزش حلقه های تکرار سی پلاس، کاربرد ماکرو for each در c،

نظرات() 
 
لبخندناراحتچشمک
نیشخندبغلسوال
قلبخجالتزبان
ماچتعجبعصبانی
عینکشیطانگریه
خندهقهقههخداحافظ
سبزقهرهورا
دستگلتفکر
نظرات پس از تایید نشان داده خواهند شد.