الدوارات في C++

الدوارات

تسبب الدوارة loop في تكرار جزء من البرنامج جزء من البرنامج عددا من المرات . ويظل التكرار مستمرا طالما كان شرط الدوارة متحققا . ولدينا ثلاثة أنواع من الدوارات , For, while, do …while , نعرض لها فيما يلي :

الدوارة for

الدوارة for هي أسهل صورة من الدوارات فعناصرها مجمعة في عبارة واحدة , كما أنها من الخصائص الجوهرية في لغات البرمجة , فقط ظلت لفترة طويلة من الزمن الدوارة الوحيدة في لغة البيزك .

وتستخدم الدوارة لتكرار جزء من البرنامج عددا محددا من المرات , وتستخدم عادة (وليس دائما ) حينما تكون عالما مسبقا عدد المرات التي تريد للبرنامج أن يكررها .

وإليك مثالا لذلك .

Fordemo.cpp

fordemo.cpp


 


// fordemo.cpp


// demonstrates simple FOR loop


#include <iostream.h>


 


void main()


   {


   int j;                     // define a loop variable


 


   for(j=0; j<15; j++)        // loop from 0 to 14,


     cout << j * j << "  ";   // displaying the square of j


   }




وخرج البرنامج كما تري هو الأعداد من 0 إلي 196 .



كيف سارت هذه الدوارة ؟



إن صياغة هذه الدوارة ( وكافة الدوارات الأخري ) يتكون من عنصرين : عبارة الدوارة loop statement , ومضمون الدوارة loop body , ومضمون الدوارة هي الأمر ( أو الأوارم ) التي تكررها الدوارة طالما كان شرط تشغيلها متحققا , وهي في مثالنا الأمر الوحيد :



Cout <<j*j << '' '' ;



أما عبارة الدوارة for فهي كما تري تتكون من ثلاثة عناصر تحتوي عادة ( وليس دائما ) علي نفس المتغير , والذي هو مثالنا المتغير j . والعناصر الثلاثة هي :



1- الاستهلال initialization : يستهل المتغير بقيمة ما تحدد الشرط الابتدائي لتشغيل الدوارة , وقد استهل المتغير في مثالنا بالقيمة 0 . ولو كان الاستهلاك بقيمة أخري , فإن الناتج سوف يبدأ بها .



2- الاختيار test : يتضمن عنصر الاختيار مؤثرا علائقيا يمثل شرط تشغيل الدوارة ويجري اختياره بعد كل دورة . وينتهي التكرار حين يصبح هذا الشرط غير متحقق . وفي مثالنا , فإن شرط الدوارة هو أن يكون المتغير j أقل من 15 . عندئذ يتوقف عمل الدوارة , وينتقل التحكم في سير البرنامج إلي العبارة التالية للدوارة مباشرة .



3- العداد increment expression : تتغير قيمة المتغير j في العنصر الثالث إلي أن تصل قيمته القيمة المطلوبة في الشرط لإنهاء الدوارة , وقد يكون التغير متزايدا , إذا كان المتغير مستهلا بقيمة أقل من قيمته في شرط الاختبار ( كما في حالة مثالنا ) , أو متناقصا في حالة العكس ( راجع المثال factor .cpp في هذا الفصل ) .



وتلاحظ أن عبارة أية دوارة ومضمونها لا يفصلا بفاصلة منقوطة , حيث إن عبارة الدوارة لا تمثل أمرا من أوامر البرنامج , بل هي وضع لشرط تشغيلها . وفي حالة عدم الانتباه لذلك , فإن محول من أوامر البرنامج , بل هي وضع لشرط تشغيلها . وفي حالة عدم الانتباه لذلك , فإن محول الصياغة سوف يعتبر عبارة الدوارة بمثابة أمر مستقل عن مضمونها , وسوف تحصل علي نتائج غير متوقعة .



وفي نفس الوقت تلاحظ أن العناصر الثلاثة في عبارة الدوارة for تفصل بفاصلة منقوطة , حيث يعتبر كل عنصر بمثابة أمر داخلي في عبارة الدوارة .



ويبين الشكل توضيحا لصياغة الدوارة for , كما يبين الشكل أسلوب عملها .



Roundabouts in C





















شكل صياغة الدوارة for























Object-Oriented Programming in C   _Page_0107_Image_0001



شكل عمل الدوارة for





الدوارة متعددة العبارات



ربما نحتاج لتنفيذ عدد من العبارات أثناء عمل الدوارة بمعني أن مضمون الدوارة يضم أكثر من أمر . والمتبع في هذه الحالة أن يضم مضمون الدوارة بين قوسين حلزونيتين , بالضبط كما نفعل مع الدوال . وعليك ملاحظة أن القوس الحلزوني الأخير لا ينتهي بفاصلة منقوطة , بينما تنتهي كل عبارة داخلية في مضمون الدوارة بذلك , كشأن كافة أوامر البرنامج , كما هو موضح بالجزء b من الشكل .



ويستخدم المثال التالي ثلاثة عبارات تنفذ كل دورة , لطبع مكعبات الأعداد من 1 إلي 10 علي عمودين .



Cubelist.cpp




cubelist.cpp


 


// cubelist.cpp


// lists cubes from 1 to 10


#include <iostream.h>


#include <iomanip.h>                    // for setw


 


void main()


   {


   int numb;                            // define loop variable


 


   for(numb=1; numb<=10; numb++)        // loop from 1 to 10


      {


      cout << setw(4) << numb;          // display 1st column


      int cube = numb*numb*numb;        // calculate cube


      cout << setw(6) << cube << endl;  // display 2nd column


      }


   }




وقد أجرينا تعديلا في صياغة الدوارة , ولكي نبين أنه لا توجد قواعد صارمة في الموضوع , فقد استهللنا المتغير بالعدد 1 , ثم جعلنا الشرط " أكبر من أو يساوي " حتي تنفذ الدوار عند الرقم 10 , ونصل بذلك لعشرة مرات من التكرار , ولكن بصورة خلاف التي اتبعناها في المثال السابق .



مدي رؤية المتغيرات



حين يتضمن مضمون الدوارة عدة عبارات محتواة بين القوسين الحلزونين , يطلق علي هذه المجموعة كتلة block , ومن الخصائص الهامة للكتل أن المتغير المعرف داخلها لا يكون مرئيا خارجها , بمعني أن أية عبارة خارج هذه الكتلة لا يمكنها التعامل مع مثل هذا المتغير , وكأنها لا تراه . ومن قبيل ذلك المتغير cube المعرف داخل موضوع الدوارة , فلو أنك كتبت بعد قوس العبارة :



Cube = 10 ;



فإن محول الصياغة سوف ينذرك بأنه لا يعرف هذا المتغير , لكونه غير معرف خارج الكتلة .



ومن مزايا تحديد رؤية المتغيرات بالنطاق المعرفة به هو إمكان استخدام نفس الاسم في موضوع أخر خارج الكتلة .



استخدام الهوامش في صياغة البرامج



من العادات الحسنة في البرمجة حسن استغلال مسافات الهوامش بحيث يكون البرنامج سهل التتبع حسن المظهر , فتلاحظ في برنامجنا أننا جعلنا لموضوع الدوارة هامشا أكبر , فظهر مزاحا لليمين عن عبارة الدوارة تطبيقا لهذا العرف .



وهناك أسلوب مألوف أخر للصياغة , وهو وضع القوس الحلزوني الأول المحدد للكتلة أمام عبارة الدوارة , علي الوجه التالي :



For ( numb=1 ; numb<=10;numb++ ) {



Cout << setw(4)…



….



}



وهنا نوفر سطرا من البرنامج , ولكن تتبع البرنامج يكون أكثر صعوبة فمتابعة فتح الأقواس وغلقها من الوسائل الفعالة في تتبع البرنامج واكتشاف السهو به .



مراقبة عمل الدوارة



يمكنك استغلال إمكانية تصحيح البرامج debugging المبنية في أي من النظامين بور لاند أو تيربو لعمل عرض جيد لعمل الدوارات , والخاصية الجوهرية هنا هي " السير خطوة خطوة single stepping , والتي تيسرها بيئة البرمجة المتكاملة , افتح مشروع البرنامج المطلوب تصحيحه , وشوشة التحرير المحتويه علي الملف المصدري له ( في التيربو لست محتاجا لفتح المشروع ) . والأن , أضغط ببساطة علي المفتاح f8 , وقد يعاد ترجمة البرنامج إذا كان ذلك ضروريا , ثم يضائ أول سطر فيه . والسطر المضاء هو السطر الذي يكون علي وشك التنفيذ . ومع كل ضغطة علي نفس المفتاح , ينتقل التنفيذ إلي السطر التالي .



وبتطبيق ذلك علي المثال المعطي , تلاحظ أولا أن التوجيهات في صدر البرنامج لا تضاء , حيث لا تعتبر سطورا للتنفيذ . واصل الضرب علي المفتاح , وحينما تدخل في الدوارة , سوف تلاحظ كيف يتكرر التنفيذ دوريا .



وبينما تراقب التنفيذ قد تراه ممتعا أن تتابع تطور تغير قيم بعض المتغيرات , وللقيام بذلك افتح شاشة المراقبة Watch , اختر الأمر Debug/Add Watch , أما في التربو سي++ فأختر الأمر Debug/Watches ثم من القائمة الفرعية اختر Add Watch . في الصندوق الحواري الذي يظهر , أكتب اسم المتغير الذي تريد مراقبته , وهو في حالتنا هذه المتغير numb . يمكنك الأن مراقبته , تري أمامه رسالة : undefined symbol , لا تهتم بهذه الرسالة , فهي تقول ببساطة أن المتغير لم يدخل في التنفيذ بعد , وقد تري عند التشغيل أن المتغير قد أخذ قيما غريبة , أيضا لا تهتم , فهي القيم العشوائية في المتغير إلي أن يدخل في التنفيذ [



وخاصتي التقدم خطوة خطوة والمراقبة أداتان قويتان لتصحيح البرنامج إذا لم يسر في طريقه المرسوم .



العد التنازلي



كما نوهنا من قبل , ليس ضروريا أن يكون العد في الدوارة تصاعديا , بل يمكن أن يكون تناقصيا , حين تحدد الرقم النهائي للتكرار كقيمة استهلاكية , ويكون شرط الاختبار هو الوصول للصفر , كما تري في المثال التالي والذي يستخدم لإيجاد المفكوك الضرب للعداد المدخل .



Factor.cpp




factor.cpp


 


// factor.cpp


// calculates factorials, demonstrates FOR loop


#include <iostream.h>


 


void main()


   {


   unsigned int numb;                


   unsigned long fact=1;             // long for larger numbers


 


   cout << "\nEnter a number: ";


   cin >> numb;                      // get number


 


   for(int j=numb; j>0; j--)         // multiply 1 by


      fact *= j;                     // numb, numb-1, ..., 2, 1


   cout << "Factorial is " << fact;  // result is factorial


   }




في هذا المثال يتخذ المتغير j قيمة العدد المدخل من المستخدم , وتتناقص هذه القيمة مع كل دورة إلي أن تصل للصفر , فتتوقف الدوارة .



وقد استخدمنا التعريف unsigned long حيث إن مفكوك حتي أصغر الأعداد هو عدد كبير . وحتي مع هذا التعريف , فإن أكبر عدد يمكنك إدخاله هو 12 .



تعريف المتغير في موضع استخدامه



كما تلاحظ هنا أننا لم نعرف المتغير j في بداية البرنامج كما نفعل عادة في تعريف المتغيرات بل عرفناه داخل عبارتها :



For (int j=numb; j……..



وتعريف المتغيرات في موضع استخدامها أمر معتاد في السي ++ , ويزيد من وضوح البرنامج] بالنسبة للمتغيرات شائعة الاستخدام في البرنامج [ والمتغير المعرف بهذه الطريقة يكون مرئيا لبقية البرنامج بدءا من هذه النقطة (علي عكس المتغيرات المعرفة في الكتل ,فهي لا تكون مرئية خارج الكتلة ) .



الدوارة while



الدوارة for تقوم بتنفيذ عملية معينة عددا من المرات . فماذا تفعل لو لم تكن عالما مسبقا عدد مرات تنفيذ الدوارة ؟



الحل هو استخدام نوع أخر من الدوارات هو الدوارة while .



والمثال التالي , وهو البرنامج endon0.cpp يسألك أن تدخل مجموعة من الأعداد , وحين تدخل رقم الصفر , ينتهي البرنامج , وبالطبع لا يعلم مسبقا متي ستقرر ذلك .



Endon0.cpp






endon0.cpp


 


// endon0.cpp


// demonstrates WHILE loop


#include <iostream.h>


 


void main()


   {


   int n = 99;       // make sure n isn't initialized to 0


 


   while( n != 0 )   // loop until n is 0


      cin >> n;      // read a number into n


   }




وتبدو الدوارة while كما لو كانت صورة بسيطة من الدوارة for فهي تحتوي علي عنصر الاختبار , ولكن دون العنصرين الأخرين . ويبين الشكل عمل هذه الدوارة .





















Object-Oriented Programming in C   _Page_0113_Image_0001



شكل صياغة الدوارة while





























Object-Oriented Programming in C   _Page_0114_Image_0001



شكل طريقة عمل الدوارة while



وشرط استمرار الدوارة هو



N ! = 0



ويعني أن الدوارة تظل عاملة طالما كانت قيمة المتغير لا تساوي الصفر .



والبساطة في هذه الدوارة مضللة , فرغم عدم وجود عنصر استهلاك , فإن المتغير يجب أن يأخذ قيمة في البدء , وهو ما تم بالعبارة :



// make sure n isn't initialized to 0 int n = 99;



كما يجب أن يتضمن مضمون الدوارة عبارة تضمن تغير المتغير الخاص بها , وإلا فإن الدوارة لن تنتهي أبداً وهي في مثالنا هي العبارة :



Cin>>n;



العبارات المتعددة في الدوارة while



في المثال التالي , يتضمن مضمون الدوارة عدة عبارات , وهو صورة متطورة من البرنامج cubelist.cpp الخاص بالدوارة for , وإلا أنه يحسب الأس الرابع بأعداد من 1 فصاعدا , ولكن بشرط ألا تتجاوز الإجابة أربعة أرقام , علينا إذن أن نضع شرط الدوارة بأن تنتهي عند العدد 9999 .



While4.cpp




while4.cpp


 


// while4.cpp


// prints numbers raised to fourth power


#include <iostream.h>


#include <iomanip.h>             // for setw


 


void main()


   {


   int pow=1;                    // power initially 1


   int numb=1;                   // numb goes from 1 to ???


 


   while( pow<9999 )             // loop while power < 4 digits


      {


      cout << setw(2) << numb;          // display number


      cout << setw(5) << pow << endl;   // display fourth power


      ++numb;                    // get ready for next power


      pow = numb*numb*numb*numb;        // calculate fourth power


      }


   }




وستجد من ناتج البرنامج أن الدوارة تقف عند العدد 9 , والأس الرابع له هو 6561 إذ يأتي بعد ذلك العدد 10 , وأسه الرابع 10.000 وهو يخرج عن الشرط المطلوب , فتنتهي الدوارة .



الأولوية والمؤثرات العلائقية



يمس البرنامج موضوع الأولوية بين المؤثرات , وهو ينتج ما يسمي " متتابعة فيبوناتشي Fibonacci series , وهي علي الشكل التالي :



1 1 2 3 5 8 13 21 34 55



بمعني أن كل عدد تأل هو مجموع العددين السابقين عليه , ولها تطبيقات طريفة , واستخدامات في علوم كثيرة منها الحاسوب وعلوم النبات .



Fibo.cpp




fibo.cpp


 


// fibo.cpp


// demonstrates WHILE loops using fibonacci series


#include <iostream.h>


 


void main()


   {                           // largest unsigned long


   const unsigned long limit = 4294967295;


   unsigned long next=0;       // next-to-last term


   unsigned long last=1;       // last term


 


   while( next < limit / 2 )   // don't let results get too big


      {


      cout << last << "  ";    // display last term


      long sum = next + last;  // add last two terms


      next = last;             // variables move forward


      last = sum;              //    in the series


      }


   }






ويستخدم البرنامج متغيرات من النوع unsigned long وهو أكبر الأنواع مدي , وشرط الدوارة هو ألا تتجاوز العدد التالي في المتتابعة مدي هذا النوع . وقد عرفنا هذا الحد , وهو المتغير limit علي أنه من النوع الثابت , وأعطينا قيمة أقصي عدد يمكن تخزينه في النوع المذكور . ثم وضعنا شرط الدوارة ألا يتجاوز العدد التالي , والذي خصص له المتغير next نصف هذا الحد , حتي لا يزيد المجموع عن الحد المسموح به . وعلي ذلك فإن عبارة الشرط تستخدم مؤثرين :



(next < limit / 2 )



والهدف منها مقارنة العدد التالي بنصف الحد , بمعني أننا نريد أن تجري عملية القسمة قبل عملية المقارنة . وحين نطلب أمرا كهذا , فإننا نضع العملية المطلوب إجراؤها أولا بين قوسين , ولكنا لم نفعل في هذه الحالة , لأن عملية المؤثرات الحسابية لها أولوية في التنفيذ علي المؤثرات العلائقية , وهو ما يضمن لنا القسمة بطبيعتها تجري قبل المقارنة .



الدوارة do … while



في الدوارة السابقة تجري عملية اختبار الشرط قبل بدء الدوارة , فإذا لم يتحقق الشرط فلن ندخل في الدوارة أصلا , وأحيانا يكون هذا ما نقصده . ولكن قد نريد أن نضمن أن تعمل الدوارة مرة واحدة علي الأقل , في حالة كهذه , نستخدم الدوارة do …. While التي سنعرض لها الأن , والتي تضع شرط الاختبار في نهاية الدوارة بعد الكلمة الحاكمة while .



والبرنامج التالي يدعوك لإدخال رقمين , مقسوم عليه , ويجري عملية القسمة ويخرج النتيجة , حاصل القسمة والباقي إن وجد , ويستخدم البرنامج كلا من مؤثري القسمة والباقي .



Divdo.cpp




divdo.cpp


 


// divdo.cpp


// demonstrates DO loop


#include <iostream.h>


 


void main()


   {


   long dividend, divisor;


   char ch;


 


   do                                   // start of do loop


      {                                 // do some processing


      cout << "Enter dividend: "; cin >> dividend;


      cout << "Enter divisor: ";  cin >> divisor;


      cout << "Quotient is " << dividend / divisor;


      cout << ", remainder is " << dividend % divisor;


 


      cout << "\nDo another? (y/n): ";  // do it again?


      cin >> ch;


      }


   while( ch != 'n' );                  // loop condition


   }




والجزء الأغلب من البرنامج يوجد بداخل الدوارة , فالكلمة الحاكمة فيها do تحدد بدايتها , ثم يأتي القوس الحلزوني الذي يحدد الكتلة الخاصة بموضوع الدوارة . وفي نهاية الدوارة تأتي الكلمة الحاكمة while لتحدد الشرط الخاص بالدوارة . وعملها هنا مماثل تماما للدوارة السابقة غير أنها في النهاية , الأمر الذي يجب معه أن تقفل عبارتها بفاصلة منقوطة , وهو أمر يسهل عليك نسيانه . ويبين الشكل صياغة الدوارة , كما يبين الشكل طريقة عملها .























Object-Oriented Programming in C   _Page_0113_Image_0001



شكل صياغة الدوارة do



وبعد كل دورة يسأل المستخدم البرنامج إن كان يريد إدخال عملية أخري , وعلي المستخدم أن يضرب علي حرف y ] أو أي حرف [ إذا أراد الاستمرار في العمل . وفي هذه الحالة يظل الشرط



Ch != 'n'



متحققا , ] هذا الشرط معناه أن الحرف المدخل ليس n [ . وفي حالة إدخال الحرف n يكون الشرط غير متحقق , فتنتهي الدوارة . وإليك مثالا من عمل البرنامج :



Enter dividend: 11



Enter divisor: 3



Quotient is 3, remainder is 2



Do another ? (y/n): y



Enter dividend: 222



Enter divisor: 17



Quotient is 3, remainder is 1



Do another ? (y/n): n





















Object-Oriented Programming in C   _Page_0114_Image_0001



شكل طريقة عمل الدوارة do



اختيار نوع الدوارة



لقد قدمنا إشارات عامة حول استخدام الدوارات , فالدوارة for مناسبة في حالة معرفتك مسبقا بعدد مرات التكرار . وتستخدم الدوارتان الأخريان في حالة عدم معرفتك بذلك فتستخدم الدوارة while حينما لا تريد أن تبدأ الدوارة عملها إذا كان الشرط غير متحقق والدوارة while ........ do إذا أردت تنفيذ الدوارة مرة علي الأقل , ثم يجري اختبار الشرط .



وليست هذه بالقواعد الصارمة , فإختيار الدوارات يخضع أساسا للتذوق , ولكل مبرمج طريقته في الصياغة . فيمكنك من حيث المبدأ أن تستخدم أية دوارة لتنفيذ أية مهمة , مراعيا وضوح الصياغة وسهولة تتبعها .

تعليقات

المشاركات الشائعة من هذه المدونة

المؤثرات الحسابية في C++

الرسم Graphics

دوال النمط الرسومي في ++C