You are on page 1of 37

‫الفصــــــــــل ‪ .

5‬الجمــــــــــل‬
‫‪Chapter 5. Statements‬‬

‫الـمحتويات‬
‫‪Contents‬‬

‫‪5.1 Simple Statements‬‬ ‫‪ 5٫1‬الجمــــــل البسيــــــطة‬

‫‪5.2 Statement Scope‬‬ ‫‪ 5٫2‬نطــــــاق الجمــــــلة‬

‫‪5.3 Conditional Statements‬‬ ‫‪ 5٫3‬الجمــــــل الرشطيــــــة‬

‫‪5.4 Iterative Statements‬‬ ‫‪ 5٫4‬الجمــــــل التكراريــــــة‬

‫‪5.5 Jump Statements‬‬ ‫‪ 5٫5‬جمــــــل القفــــــز‬

‫‪5.6 try Blocks and Exception Handling‬‬ ‫جرب_ ومعالجــــــة اﻻستثناءات‬


‫‪ 5٫6‬كتل ّ‬

‫‪Chapter Summary‬‬ ‫ملخــــــص الفصــــــل‬

‫‪Defined Terms‬‬ ‫مصطلحــــــات معرفــــــة‬

‫مثل معظم اللغات ‪ ،‬توفر يس‪++‬‬


‫جمالً للتنفيذ الرشطي ‪ ،‬وحلقات تنفذ بشكل متكرر نفس بنية الكود ‪،‬‬ ‫•‬
‫وجمل قفز تقاطع جمل تدفق التحكم‪.‬‬ ‫•‬
‫سيبحث هذا الفصل بالتفصيل في الجمل اليت تدعمها يس‪.++‬‬ ‫•‬

‫يتم تنفيذ الجمل بالتسلسل‪.‬‬


‫يعترب التنفيذ املتسلسل غري ٍ‬
‫كاف عدا في أبسط الربامج‪ .‬لذلك ‪،‬‬ ‫•‬
‫أيضا مجموعة من جمل تدفق التحكم اليت تسمح بمسارات تنفيذ أكرث تعقي ًدا‪.‬‬
‫تعرف لغة يس‪ً ++‬‬
‫ّ‬ ‫•‬
‫‪ 5٫1‬الجمــــــــــل البسيــــــطة‬
‫‪5.1. Simple Statements‬‬

‫تنتهي معظم الجمل في يس‪ ++‬بفاصلة منقوطة‪.‬‬


‫يصبح تعبري ما ‪ ،‬مثل ‪ ، ival + 5‬جملة تعبري عندما تتبعها فاصلة منقوطة‪.‬‬ ‫•‬
‫تتسبب الجملة التعبريية في تقييم التعبري وإهمال نتيجته ‪:‬‬ ‫•‬

‫;‪ival + 5‬‬ ‫‪// rather useless expression statement‬‬


‫;‪cout << ival‬‬ ‫‪// useful expression statement‬‬

‫أول جملة غري مجدية إلى حد كبري‪:‬‬


‫لقد تم الجمع لكن لم يتم استخدام النتيجة‪.‬‬ ‫•‬
‫شيوعا ‪ ،‬تحتوي جملة التعبري على تعبري له تأثري جانيب عند تقييمه ‪ -‬مثل تعيني قيمة جديدة‬
‫ً‬ ‫بشكل أكرث‬ ‫•‬
‫ملتغري ‪ ،‬أو طباعة نتيجة ‪.-‬‬

‫‪Null Statements‬‬ ‫الجمل الخالية‬

‫أيضا باسم الجمل الالغية‪.‬‬


‫أبسط جملة هي الجملة الخالية ‪ ،‬واملعروفة ً‬
‫الجملة الخالية عبارة عن فاصلة منقوطة واحدة ‪:‬‬

‫‪; // null statement‬‬

‫تعترب الجملة الخالية مفيدة عندما تتطلب اللغة جملة لكن منطق الربنامج ال يتطلب ذلك‪.‬‬
‫شيوعا لها يكون عندما يمكن تنفيذ عمل بنية الحلقة عرب رشطها‪.‬‬
‫ً‬ ‫االستخدام األكرث‬ ‫•‬

‫على سبيل املثال ‪ ،‬قد نرغب في قراءة قناة مدخالت ‪ ،‬وتجاهل كل يشء نقرأه حىت نواجه قيمة معينة ‪:‬‬

‫‪// read until hit end-of-file or find input equal to sought‬‬


‫)‪while (cin >> s && s != sought‬‬
‫‪; // null statement‬‬

‫ضمنيا ‪ s‬ملعرفة ما إذا كانت القراءة ناجحة‪.‬‬


‫ً‬ ‫يقرأ هذا الرشط قيمة من املدخالت القياسية ويخترب‬ ‫•‬
‫بافرتاض نجاح القراءة ‪ ،‬يخترب جزء الرشط الثاني ما إذا كانت القيمة اليت نقرأها تساوي القيمة املطلوبة‪.‬‬ ‫•‬
‫إذا وجدنا القيمة اليت نريدها ‪ ،‬نخرج من حلقة ‪.while‬‬ ‫•‬
‫عدا ذلك ‪ ،‬يتم تقييم صحة الرشط مرة أخرى ‪ ،‬بقراءة قيمة أخرى من ‪.cin‬‬ ‫•‬

‫أفضل املمارسات‬

‫ينبغي التعليق على الجمل الخالية‪ .‬هكذا يمكن ألي شخص يقرأ الكود أن يرى أن الجملة قد حذفت عن قصد‪.‬‬
‫احذر الفواصل املنقوطة املفقودة أو الغريبة‬
‫‪Beware of Missing or Extraneous Semicolons‬‬

‫ألن الجملة الخالية تعترب جملة ‪ ،‬فهي رشعية في أي مكان نتوقع فيه جملة‪.‬‬
‫غالبا ما تكون الفاصلة املنقوطة اليت قد تبدو غري رشعية أكرث من جملة خالية‪.‬‬
‫ً‬ ‫ولهذا ‪،‬‬ ‫•‬

‫يحتوي الجزء التالي على جملتني ‪ -‬واحدة تعبريية وأخرى خالية ‪:‬‬

‫‪ival = v1 + v2; ; // ok: second semicolon is superfluous null statement‬‬

‫على الرغم من أن الجملة الخالية غري الرضورية غالبًا غري مرضة ‪،‬‬ ‫•‬
‫إال أن فاصلة منقوطة إضافية تتبع رشط ‪ while‬أو ‪ if‬بإمكانها تغيري نية املربمج بشكل كبري‪.‬‬ ‫•‬

‫فمثالً ‪ ،‬سوف يتكرر الكود التالي إلى ما ﻻ نهاية ‪:‬‬

‫‪// disaster: extra semicolon: loop body is this null statement‬‬


‫‪while (iter != svec.end()) ; // while body is empty statement‬‬
‫;‪++iter‬‬ ‫‪// increment not part of loop‬‬

‫جزءا من الحلقة‪.‬‬
‫ً‬ ‫على عكس املسافة الخالية ‪ ،‬فإن الزتايد ليس‬ ‫•‬
‫بنية الحلقة هي الجملة الخالية املكونة من الفاصلة املنقوطة اليت تتبع الرشط‪.‬‬ ‫•‬

‫تحذير‬

‫دائما لطيفة‪.‬‬
‫ً‬ ‫الجمل الخالية الدخيلة ليست‬

‫)‪Compound Statements (Blocks‬‬ ‫الجمل املركبة (الكتل)‬

‫الجملة املركبة ‪ ،‬يشار إليها عاد ًة باسم الكتلة ‪،‬‬


‫وهي تسلسل جمل وإعالنات (قد تكون فارغة) محاطة بزوج من األقواس املتعرجة‪.‬‬ ‫•‬
‫الكتلة عبارة عن نطاق‪.‬‬ ‫•‬
‫بالتالي ﻻ يمكن الوصول إلى األسماء اليت قدمت داخل الكتلة إﻻ في تلك الكتلة وفي الكتل املتداخلة داخلها‪.‬‬ ‫•‬
‫تظهر األسماء حيث تم تعريفها حىت نهاية الكتلة املتضمنة (على الفور)‪.‬‬ ‫•‬

‫يتم استخدام الجمل املركبة عندما تتطلب اللغة جملة واحدة لكن منطق برنامجنا يحتاج إلى أكرث من واحدة‪.‬‬
‫مثالً ‪ ،‬يجب أن تكون بنية حلقة ‪ while‬أو ‪ for‬جملة واحدة ‪،‬‬ ‫•‬
‫لكننا في الغالب سنحتاج لتنفيذ أكرث من جملة في بنية الحلقة‪.‬‬ ‫•‬
‫نقوم بذلك عن طريق إرفاق الجمل بأقواس معقوفة ‪ ،‬وبالتالي تحويل تسلسل جمل إلى كتلة‪.‬‬ ‫•‬

‫كمثال ‪ ،‬تذكر حلقة ‪ while‬في الربنامج في الفقرة ‪: 1.4.1‬‬

‫{ )‪while (val <= 10‬‬


‫;‪sum += val‬‬ ‫‪// assigns sum + val to sum‬‬
‫;‪++val‬‬ ‫‪// add 1 to val‬‬
‫}‬

‫تطلب منطق برنامجنا جملتني لكن قد تحتوي حلقة ‪ while‬على جملة واحدة فقط‪.‬‬ ‫•‬
‫وبإحاطة هذه الجمل بأقواس معقوفة ‪ ،‬جعلناها في جملة واحدة (مركبة)‪.‬‬ ‫•‬

‫ملحوظة‬

‫ال يتم إنهاء الكتلة بفاصلة منقوطة‪.‬‬

‫أيض ا تعريف كتلة خالية عن طريق كتابة زوج من أقواس معقوفة بال جمل‪ .‬فكتلة خالية تعادل جملة ﻻغية ‪:‬‬
‫يمكننا ً‬

‫)‪while (cin >> s && s != sought‬‬


‫‪{ } // empty block‬‬

‫تمارين القسم ‪5.1‬‬


‫تمرين ‪:5.1‬‬
‫‪ -‬ما املقصود بجملة الغية؟ مىت يمكنك استخدامها؟‬
‫تمرين ‪:5.2‬‬
‫‪ -‬ما املقصود بكتلة؟ مىت يمكنك استخدامها؟‬
‫التمرين ‪:5.3‬‬
‫‪ -‬استخدم عامل الفاصلة إلعادة كتابة حلقة ‪ while‬من الفقرة ‪ 1.4.1‬بحيث ال تتطلب بعد ذلك كتلة‪.‬‬
‫‪ -‬ارشح ما إذا كانت إعادة الكتابة هذه تحسن أو تقلل من قابلية قراءة هذا الكود‪.‬‬
‫‪ 5٫2‬نطــــــاق الجمــــــــــلة‬
‫‪5.2. Statement Scope‬‬

‫بدل_ ‪ switch‬و طالـما_ ‪ while‬و ﻷجل_ ‪.for‬‬


‫يمكننا تعريف متغريات داخل بنية التحكم في جمل إذا_ ‪ if‬و ّ‬
‫تشاهد املتغريات املعرفة في بنية التحكم فقط داخل تلك الجملة وتكون خارج النطاق بعد انتهاء الجملة ‪:‬‬

‫‪while (int i = get_num()) // i created and initialized on each iteration‬‬


‫;‪cout << i << endl‬‬
‫;‪i = 0‬‬ ‫‪// error: i is not accessible outside loop‬‬

‫إذا احتجنا إلى الوصول إلى متغري التحكم ‪ ،‬فيجب تعريف ذلك املتغري خارج الجملة‪:‬‬

‫‪// find first negative element‬‬


‫;)(‪auto beg = v.begin‬‬
‫)‪while (beg != v.end() && *beg >= 0‬‬
‫;‪++beg‬‬
‫))(‪if (beg == v.end‬‬
‫‪// we know that all elements in v greater than or equal to zero‬‬

‫يتم استخدام قيمة الكائن املعرف في بنية تحكم بواسطة تلك البنية‪ .‬لذلك ‪ ،‬يجب تهيئة مثل هذه املتغريات‪.‬‬

‫تمارين القسم ‪5.2‬‬

‫التمرين ‪:5.4‬‬
‫‪ -‬ارشح كاًل من األمثلة التالية ‪،‬‬
‫‪ -‬قم بتصحيح أي مشاكل تكتشفها‪.‬‬

‫)‪(a‬‬ ‫} ‪while (string::iterator iter != s.end()) { /* . . . */‬‬


‫)‪(b‬‬ ‫} ‪while (bool status = find(word)) { /* . . . */‬‬
‫} ‪if (!status) { /* . . . */‬‬
‫‪ 5٫3‬الجمــــــــــل الرشطــــــية‬
‫‪5.3. Conditional Statements‬‬

‫توفر يس‪ ++‬جملتني تسمحان بتنفيذ مرشوط‪.‬‬


‫بناء على رشط‪.‬‬
‫ً‬ ‫تقرر الجملة الرشطية إذا_ ‪ if‬تدفق تحكم‬ ‫•‬
‫بناء على‬
‫ً‬ ‫بدل_ ‪ switch‬تعبريًا رقمياً صحيحا وتختار أحد مسارات التنفيذ املتعددة‬
‫بينما تُقيِّم الجملة ّ‬ ‫•‬
‫قيمة التعبري‪.‬‬

‫‪5.3.1. The if Statement‬‬ ‫‪ 5٫3٫1‬الجملة إذا_‬

‫بناء على صحة الرشط املحدد‪.‬‬


‫ً‬ ‫تقوم جملة إذا_ بتنفيذ جملة أخرى بشكل مرشوط‬
‫هناك نوعان من نماذج إذا_ ‪ :‬أحدهما يتضمن الفرع وإﻻ_ ‪ else‬واآلخر بدونه‪.‬‬ ‫•‬

‫الصياغة النحوية البسيط لـ إذا_ كالتالي ‪:‬‬

‫)رشط ‪if (condition‬‬


‫جملة ‪statement‬‬

‫أما جملة إذا_ ذات الفرع ‪ else‬صياغتها كالتالي‪:‬‬

‫)رشط ‪if (condition‬‬


‫جملة ‪statement‬‬
‫‪else‬‬
‫جملة‪statement2 2‬‬

‫في كال النموذجني ‪ ،‬يجب وضع الرشط بني قوسني‪.‬‬ ‫•‬


‫يمكن أن يكون الرشط تعبريًا أو إعال ًنا عن متغري ُمهيأ‪.‬‬ ‫•‬
‫يجب أن يكون للتعبري أو املتغري نوع قابل للتحويل إلى منطقي‪.‬‬ ‫•‬
‫وكالعادة ‪ ،‬يمكن أن تكون أي من الجملتني‪-‬اﻷولى أو الثانية عبارة عن كتلة‪.‬‬ ‫•‬
‫صحيحا ‪ ،‬فسيتم تنفيذ الجملة‪ .‬وبعد اكتمالها ‪ ،‬يستمر تنفيذ ما بعد إذا_ الرشطية‪.‬‬
‫ً‬ ‫إذا كان الرشط‬ ‫•‬
‫أما إن كان الرشط خاطًئ ا ‪ ،‬يتم تخطي الجملة‪ .‬في إذا_ البسيطة ‪ ،‬يستمر التنفيذ مع ما بعد إذا_‪.‬‬ ‫•‬
‫في حالة إذا_وإال_ ‪ ،‬سيتم تنفيذ الجملة‪.2-‬‬ ‫•‬

‫‪Using an if else Statement‬‬ ‫استخدام جملة إذا_وإﻻ_‬

‫لتوضيح جملة إذا_ ‪ ،‬سنحسب درجة حرفية من درجة رقمية‪.‬‬


‫سنفرتض أن الدرجات الرقمية ترتاوح من صفر إلى ‪ 100‬ضمناً‪.‬‬ ‫•‬
‫تحصل الدرجة ‪ 100‬على "‪ ، "++ A‬والصفوف األقل من ‪ 60‬تحصل على "‪، "F‬‬ ‫•‬
‫وترتاوح الدرجات األخرى في مجموعات من عرشة‪:‬‬ ‫•‬
‫تحصل الدرجات من ‪ 60‬إلى ‪ 69‬على "‪ ، "D‬و ‪ 70‬إلى ‪ 79‬درجة "‪ ، "C‬وهكذا‪.‬‬ ‫•‬

‫متجها ‪ vector‬لالحتفاظ بالدرجات الحرفية املمكنة‪:‬‬


‫ً‬ ‫سنستخدم‬

‫;}"‪vector<string> scores = {"F", "D", "C", "B", "A", "A++‬‬

‫لحل هذه املشكلة ‪ ،‬يمكننا استخدام جملة إذا_ وإال لتنفيذ إجراءات مختلفة لفشل واجتياز الدرجات‪:‬‬

‫‪// if grade is less than 60 it's an F, otherwise compute a subscript‬‬


‫;‪string lettergrade‬‬
‫)‪if (grade < 60‬‬
‫;]‪lettergrade = scores[0‬‬
‫‪else‬‬
‫;]‪lettergrade = scores[(grade - 50)/10‬‬

‫اعتما ًدا على قيمة الدرجة ‪ ،grade‬نقوم بتنفيذ الجملة اليت تأتي بعد إذا_ أو بعد وإﻻ‪.‬‬ ‫•‬
‫ففي الحالة وإﻻ_ ‪ ،‬نحسب الفهرسة من ‪ grade‬بطرح ‪ grade‬من ‪ 50‬لنحسب أكرب نطاق للدرجات الفاشلة‪.‬‬ ‫•‬
‫ثم نستخدم قسمة صحيحة بدون باقي لتحسب فهرس ‪( scores‬الدرجة الحرفية) املناسب‪.‬‬ ‫•‬

‫‪Nested if Statements‬‬ ‫جمل إذا_ املتداخلة‬

‫سنجعل برنامجنا أكرث تشوي ًقا ‪ ،‬ونضيف إشارة موجب أو سالب إلى الدرجات الناجحة‪.‬‬
‫سنعطي عالمة موجب للدرجات املنتهية بـ ‪ 8‬أو ‪ ، 9‬وعالمة السالب لتلك اليت تنتهي بـ ‪ 0‬أو ‪ 1‬أو ‪: 2‬‬

‫)‪if (grade % 10 > 7‬‬


‫‪lettergrade += '+'; // grades ending in 8 or 9 get a +‬‬
‫)‪else if (grade % 10 < 3‬‬
‫‪lettergrade += '-'; // those ending in 0, 1, or 2 get a -‬‬

‫وبناء عليه نقرر ما إذا كان يجب إضافة موجب أو سالب‪.‬‬


‫ً‬ ‫هنا نستخدم عامل باقي القسمة ‪ modulus‬ﻷخذ الباقي‬
‫سنقوم بعد ذلك بدمج الكود الذي يضيف إشارة املوجب أو السالب إلى الكود الذي يجلب الدرجة الحرفية ‪:‬‬

‫‪// if failing grade, no need to check for plus or minus‬‬


‫)‪if (grade < 60‬‬
‫;]‪lettergrade = scores[0‬‬
‫{ ‪else‬‬
‫‪lettergrade = scores[(grade - 50)/10]; // fetch letter grade‬‬
‫‪if (grade != 100) // add plus or minus only if not already A++‬‬
‫)‪if (grade % 10 > 7‬‬
‫‪lettergrade += '+'; // grades ending in 8 or 9 get a +‬‬
‫)‪else if (grade % 10 < 3‬‬
‫‪lettergrade += '-'; // grades ending in 0, 1, 2 get a -‬‬
‫}‬
‫الحظ أننا نستخدم كتلة لرنفق الجمل ما بعد جملة ‪ else‬األولى‪.‬‬ ‫•‬
‫فإن كانت الدرجة ‪ 60‬أو أكرث ‪ ،‬فلدينا إجراءان يتعني علينا القيام بهما‪:‬‬ ‫•‬
‫إحضار الدرجة الحرفية من ‪ ، scores‬وتعيني عالمة موجب أو سالب بشكل مرشوط‪.‬‬ ‫•‬

‫‪Watch Your Braces‬‬ ‫راقب أقواسك‬

‫من الخطأ الشائع نسيان األقواس املتعرجة عندما يتوجب تنفيذ جمل متعددة ككتلة‪.‬‬

‫في املثال التالي ‪،‬‬


‫على عكس املسافة البادئة ‪ ،‬يحدث الكود الخاص بإضافة عالمة املوجب أو السالب دون قيد أو رشط‪:‬‬ ‫•‬

‫)‪if (grade < 60‬‬


‫;]‪lettergrade = scores[0‬‬
‫‪else // WRONG: missing curly‬‬
‫;]‪lettergrade = scores[(grade – 50)/10‬‬
‫‪// despite appearances, without curly brace, this code is always executed‬‬
‫‪// failing grades will incorrectly get a - or a +‬‬
‫)‪if (grade != 100‬‬
‫)‪if (grade % 10 > 7‬‬
‫‪lettergrade += '+'; // grades ending in 8 or 9 get a +‬‬
‫)‪else if (grade % 10 < 3‬‬
‫‪lettergrade += '-'; // grades ending in 0, 1, 2 get a -‬‬

‫صحيحا‪.‬‬
‫ً‬ ‫صعبا للغاية ألن الربنامج يبدو‬
‫ً‬ ‫قد يكون الكشف عن خطأ كهذا‬ ‫•‬
‫دائما باستخدام األقواس بعد "‪ "if‬أو "‪"else‬‬
‫ً‬ ‫لتجنب مثل هذه املشاكل ‪ ،‬تويص بعض أنماط كتابة الكود‬ ‫•‬
‫(وكذلك حول بنية "‪ "while‬و "‪.)"for‬‬
‫فالقيام بذلك يؤدي إلى تجنب أي ارتباك محتمل‪.‬‬ ‫•‬
‫أيضا أن األقواس موجودة أصالً إذا تطلبت التعديالت الالحقة للكود إضافة جمل‪.‬‬
‫وهذا يعين ً‬ ‫•‬

‫أفضل املمارسات‬

‫تملك العديد من محررات وبيئات تطوير الربمجة أدوات تضع مسافة بادئة تلقائية ملصدر الكود ملطابقة‬
‫بنيتها‪ .‬من الجيد استخدام هذه األدوات مىت توفرت‪.‬‬

‫‪Dangling else‬‬ ‫متدليات (وإال_)‬

‫عندما نقوم بتداخل ‪ if‬داخل ‪ if‬أخرى ‪ ،‬فمن املمكن أن تكون فروع إذا_ أكرث من فروع ‪.else‬‬
‫في الواقع ‪ ،‬يشتمل برنامج الدرجات لدينا على أربعة ‪ if‬واثنان من ‪.else‬‬ ‫•‬
‫السؤال الذي يطرح نفسه‪ :‬كيف نعرف أي ‪ if‬ينتمي إليه ‪ else‬؟‬ ‫•‬

‫هذه املشكلة ‪ -‬واليت يشار إليها عاد ًة باسم متدليات ‪ - else‬شائعة في العديد من لغات الربمجة اليت تحتوي على‬
‫جمل ‪ if‬و ‪.if else‬‬
‫تحل اللغات املختلفة هذه املشكلة بطرق مختلفة‪.‬‬ ‫•‬
‫في لغة يس‪ ، ++‬يتم حل الغموض عرب مطابقة كل فرع ‪ else‬مع أقرب حالة ‪ if‬سابقة ال مثيل لها‪.‬‬ ‫•‬
‫يواجه املربمجون أحيا ًنا مشكلة عندما يكتبون أكواداً تحتوي على ‪ if‬أكرث من فروع ‪.else‬‬ ‫•‬

‫لتوضيح املشكلة ‪ ،‬سنعيد كتابة الجزء الداخلي ‪ if else‬والذي يضيف عالمة املوجب أو السالب باستخدام‬
‫مجموعة مختلفة من الرشوط‪:‬‬

‫‪// WRONG: execution does NOT match indentation; else goes with inner if‬‬
‫)‪if (grade % 10 >= 3‬‬
‫)‪if (grade % 10 > 7‬‬
‫;'‪lettergrade += '+‬‬ ‫‪// grades ending in 8 or 9 get a +‬‬
‫‪else‬‬
‫;'‪lettergrade += '-‬‬ ‫‪// grades ending in 3, 4, 5, 6 will get -‬‬

‫تشري املسافة البادئة في الكود إلى أننا نعزتم استخدام "‪ "else‬مع ‪ if‬الخارجية ‪،‬‬ ‫•‬
‫نعزتم تنفيذ فرع ‪ else‬عندما تنتهي الدرجة برقم أقل من ‪.3‬‬ ‫•‬
‫ومع ذلك ‪ ،‬على الرغم من نوايانا ‪ ،‬وعلى عكس املسافة البادئة ‪،‬‬ ‫•‬
‫إال أن فرع ‪ else‬يعترب جزءا من ‪ if‬الداخلية‪.‬‬ ‫•‬
‫حيث سيضاف الرمز "‪ "-‬إلى درجات تنتهي من ‪ 3‬إلى ‪ 7‬ضمناً!‬ ‫•‬

‫إن تم وضع مسافة بادئة بشكل صحيح ملطابقة التنفيذ الفعلي ‪ ،‬فسيصبح ما كتبناه هو‪:‬‬

‫‪// indentation matches execution path, not programmer's intent‬‬


‫)‪if (grade % 10 >= 3‬‬
‫)‪if (grade % 10 > 7‬‬
‫;'‪lettergrade += '+‬‬ ‫‪// grades ending in 8 or 9 get a +‬‬
‫‪else‬‬
‫;'‪lettergrade += '-‬‬ ‫‪// grades ending in 3, 4, 5, 6 will get -‬‬

‫‪Controlling the Execution Path with Braces‬‬ ‫التحكم بمسار التنفيذ عرب اﻷقواس‬

‫يمكننا أن نجعل ‪ else‬جزءاً من ‪ if‬الخارجية من خالل إرفاق ‪ if‬الداخلية ضمن كتلة‪:‬‬

‫‪// add + for grades end in 8 or 9 and - for ending in 0, 1, or 2‬‬


‫{ )‪if (grade % 10 >= 3‬‬
‫)‪if (grade % 10 > 7‬‬
‫;'‪Lettergrade += '+‬‬ ‫‪// grades ending in 8 or 9 get a +‬‬
‫‪} else‬‬ ‫‪// curlies force else to go with outer if‬‬
‫;'‪lettergrade += '-‬‬ ‫‪// grades ending in 0, 1, or 2 will get a -‬‬

‫ال تمتد الجمل خارج حدود الكتلة ‪،‬‬ ‫•‬


‫لذلك ينتهي الجزء الداخلي عند اإلغالق قبل ‪.else‬‬ ‫•‬
‫جزءا من ‪ if‬الداخلية‪.‬‬
‫ً‬ ‫ال يمكن أن يكون ‪else‬‬ ‫•‬
‫اآلن ‪ ،‬أقرب ‪ if‬غري مطابق هو ‪ if‬الخارجية ‪ ،‬وهو ما كنا نرغب فيه طوال الوقت‪.‬‬ ‫•‬

‫قسم التمارين ‪5.3.1‬‬


‫التمرين ‪:5.5‬‬
‫باستخدام جملة ‪ ، if-else‬اكتب نسختك الخاصة من الربنامج لتوليد التقدير باألحرف من تقدير رقمي‪.‬‬
‫التمرين ‪:5.6‬‬
‫أعد كتابة برنامج التقدير الخاص بك الستخدام العامل الرشطي (الفقرة ‪ )4.7‬بدال ً من جملة ‪.if-else‬‬
‫التمرين ‪:5.7‬‬
‫صحح األخطاء املوجودة في كل جزء من أجزاء اﻷكواد التالية‪:‬‬
‫)‪(a) if (ival1 != ival2‬‬
‫‪ival1 = ival2‬‬
‫;‪else ival1 = ival2 = 0‬‬
‫)‪(b) if (ival < minval‬‬
‫;‪minval = ival‬‬
‫;‪occurs = 1‬‬
‫))(‪(c) if (int ival = get_value‬‬
‫;‪cout << "ival = " << ival << endl‬‬
‫)‪if (!ival‬‬
‫;"‪cout << "ival = 0\n‬‬
‫)‪(d) if (ival = 0‬‬
‫;)(‪ival = get_value‬‬
‫التمرين ‪:5.8‬‬
‫‪ -‬ما املقصود بـ "متدليات ‪"else‬؟‬
‫‪ -‬كيف يتم حل البنود األخرى في يس‪++‬؟‬

‫‪5.3.2. The switch Statement‬‬ ‫بدل_‬


‫‪ 5٫3٫2‬الجملة ّ‬

‫بدل_ طريقة مالئمة لالختيار من بني عدد (ربما كبري) من البدائل الثابتة‪.‬‬
‫توفر جملة ّ‬
‫كمثال ‪ ،‬افرتض أننا نريد حساب عدد مرات ظهور كل حرف من الحروف املتحركة الخمسة ضمن نص ما‪.‬‬ ‫•‬
‫سيكون منطق برنامجنا كما يلي‪:‬‬ ‫•‬
‫اقرأ كل حرف في املدخالت‪.‬‬ ‫•‬
‫قارن كل حرف بمجموعة حروف العلة‪.‬‬ ‫•‬
‫إذا كان الحرف يطابق أحد أحرف العلة ‪ ،‬أضف ‪ 1‬إلى عداد الحروف املتحركة‪.‬‬ ‫•‬
‫اعرض النتائج‪.‬‬ ‫•‬

‫فعلى سبيل املثال ‪ ،‬عند تشغيل الربنامج على نص هذا الفصل ‪ ،‬سيكون اإلخراج كالتالي‪:‬‬

‫‪Number of vowel a: 3195‬‬


‫‪Number of vowel e: 6230‬‬
‫‪Number of vowel i: 3102‬‬
‫‪Number of vowel o: 3289‬‬
‫‪Number of vowel u: 1033‬‬

‫بدل_‪:‬‬
‫يمكننا حل مشكلتنا مبارشة باستخدام جملة ّ‬
‫‪// initialize counters for each vowel‬‬
‫;‪unsigned aCnt = 0, eCnt = 0, iCnt = 0, oCnt = 0, uCnt = 0; char ch‬‬
‫{ )‪while (cin >> ch‬‬
‫‪// if ch is vowel, increment appropriate counter‬‬
‫{ )‪switch (ch‬‬
‫;‪case 'a': ++aCnt; break‬‬
‫;‪case 'e': ++eCnt; break‬‬
‫;‪case 'i': ++iCnt; break‬‬
‫;‪case 'o': ++oCnt; break‬‬
‫} ;‪case 'u': ++uCnt; break‬‬
‫}‬
‫‪// print results‬‬
‫'‪cout << "Number of vowel a: \t" << aCnt << '\n‬‬
‫'‪<< "Number of vowel e: \t" << eCnt << '\n‬‬
‫'‪<< "Number of vowel i: \t" << iCnt << '\n‬‬
‫'‪<< "Number of vowel o: \t" << oCnt << '\n‬‬
‫;‪<< "Number of vowel u: \t" << uCnt << endl‬‬

‫بدل_ عن طريق تقييم تعبري بني قوسني يتبع الكلمة املفتاحية ‪.switch‬‬
‫يتم تنفيذ جملة ّ‬ ‫•‬
‫قد يكون هذا التعبري إعال ًنا عن متغري ُمهيأ‪.‬‬ ‫•‬
‫يتم تحويل التعبري إلى نوع رقمي صحيح‪.‬‬ ‫•‬
‫تتم مقارنة نتيجة التعبري بالقيمة املرتبطة بكل حالة ‪.case‬‬ ‫•‬
‫إذا تطابق التعبري مع قيمة تسمية الحالة ‪ ، case label‬يبدأ التنفيذ بالجملة األولى اليت تأتي بعد تلك‬ ‫•‬
‫التسمية‪.‬‬
‫يستمر التنفيذ بشكل طبيعي من هذا الجملة حىت نهاية ‪ switch‬أو حىت الجملة اكرس_ ‪.break‬‬ ‫•‬

‫سننظر في الجملة اكرس_ ‪ break‬بالتفصيل في الفقرة ‪، 5.5.1‬‬


‫ولكن ‪ ،‬باختصار ‪ ،‬تقطع اكرس_ ‪ break‬تدفق التحكم الحالي‪.‬‬ ‫•‬
‫بدل_‪.‬‬
‫في هذه الحالة ‪ ،‬تنقل اكرس_ التحكم إلى خارج ّ‬ ‫•‬
‫بدل_ هو الجملة الوحيد في بنية ‪.while‬‬
‫في هذا الربنامج ‪ ،‬يكون ّ‬ ‫•‬
‫بدل_ هذا إلى إعادة التحكم إلى ‪ while‬الداخلية‪.‬‬
‫يؤدي الخروج من ّ‬ ‫•‬
‫وألنه ال توجد جمل أخرى في ‪ ، while‬يستمر التنفيذ على الرشط في ‪.while‬‬ ‫•‬

‫بدل_‪.‬‬
‫إذا لم يتم العثور على تطابق ‪ ،‬فسيتم التنفيذ في أول جملة تأتي بعد ّ‬
‫بدل_ إلى إعادة التحكم لرشط ‪.while‬‬
‫كما نعلم بالفعل ‪ ،‬في هذا املثال ‪ ،‬يؤدي الخروج من ّ‬ ‫•‬

‫معا باسم تسمية الحالة ‪.case label‬‬


‫تُعرف الكلمة ‪ case‬والقيمة املرتبطة بها ً‬
‫يجب أن تكون تسمية الحالة تعبريات ثابتة رقمية صحيحة ‪:‬‬ ‫•‬

‫;)(‪char ch = getVal‬‬
‫;‪int ival = 42‬‬
‫{ )‪switch(ch‬‬
‫‪case 3.14: // error: noninteger as case label‬‬
‫‪case ival: // error: nonconstant as case label‬‬
‫… ‪//‬‬

‫من الخطأ أن يكون ألي تسمييت حالة نفس القيمة‪.‬‬ ‫•‬


‫أيضا تسمية حالة خاصة ‪ ،‬هي افرتاضية ‪ ،‬نغطيها ﻻحقاً‪.‬‬
‫هناك ً‬ ‫•‬

‫‪Control Flow within a switch‬‬ ‫بدل_‬


‫التحكم في التدفق داخل ّ‬

‫من املهم أن نفهم أن التنفيذ يتدفق عرب تسميات الحالة‪ .‬بعد تطابق تسمية الحالة ‪،‬‬
‫يبدأ التنفيذ عند هذه التسمية ويستمر عرب جميع الحاالت املتبقية أو حىت يقاطعها الربنامج رصاح ًة‪.‬‬ ‫•‬
‫ولتجنب تنفيذ أكواد تسميات الحالة الالحقة ‪ ،‬يجب أن نخرب املرتجم رصاح ًة بإيقاف التنفيذ‪.‬‬ ‫•‬
‫في معظم الحاالت ‪ ،‬تكون الجملة األخرية قبل تسمية الحالة التالية هي اكرس_ ‪.break‬‬ ‫•‬

‫تماما‪.‬‬
‫ً‬ ‫بدل_ االفرتايض هو املطلوب‬
‫ومع ذلك ‪ ،‬هناك مواقف يكون فيها سلوك ّ‬
‫يمكن أن يكون لكل تسمية حالة قيمة وحيدة فقط ‪،‬‬ ‫•‬
‫ولكن في بعض األحيان يكون لدينا قيمتان أو أكرث تشرتكان في مجموعة مشرتكة من اإلجراءات‪.‬‬ ‫•‬
‫في مثل هذه الحاالت ‪ ،‬نحذف جملة اكرس_ ‪، break‬‬ ‫•‬
‫مما يسمح للربنامج بالوقوع في تسميات حاالت متعددة‪.‬‬ ‫•‬

‫فمثالً ‪ ،‬قد نرغب في حساب إجمالي عدد أحرف العلة فقط‪:‬‬

‫;‪unsigned vowelCnt = 0‬‬


‫‪// ...‬‬
‫{ )‪switch (ch‬‬ ‫‪// any occurrence of a, e, i, o, or u increments vowelCnt‬‬
‫‪case 'a':‬‬
‫‪case 'e':‬‬
‫‪case 'i':‬‬
‫‪case 'o':‬‬
‫} ;‪case 'u': ++vowelCnt; break‬‬

‫قمنا هنا بتكديس عدة تسميات حالة بال جمل اكرس_ ‪.break‬‬ ‫•‬
‫سيتم تنفيذ نفس الكود عندما يكون ‪ ch‬حر ًفا متحر ًكا‪.‬‬ ‫•‬

‫ونظرًا ألن برامج يس‪ ++‬حرة الشكل ‪،‬‬


‫فال يلزم ظهور تسميات الحالة في سطر جديد‪.‬‬ ‫•‬
‫جميعا في سطر واحد‪:‬‬
‫ً‬ ‫يمكننا التأكيد على أن الحاالت تمثل نطا ًقا من القيم عرب رسدها‬ ‫•‬

‫{ )‪switch (ch‬‬ ‫‪// alternative legal syntax‬‬


‫} ;‪case 'a': case 'e': case 'i': case 'o': case 'u': ++vowelCnt; break‬‬
‫أفضل املمارسات‬

‫قدم تعليقاً ملنطق من الحذف‪.‬‬


‫نادرا ما يحدث إغفال اكرس_ ‪ break‬في نهاية تسمية حالة ‪ .‬إذا حذفت اكرس_ ‪ّ ،‬‬
‫ً‬

‫نسيان الجملة اكرس_ مصدر أخطاء شائع‬


‫‪Forgetting a break Is a Common Source of Bugs‬‬

‫من املفاهيم الخاطئة الشائعة االعتقاد بأنه يتم فقط تنفيذ الجمل املرتبطة بتسمية الحالة املطابقة‪.‬‬
‫بدل_ حساب حروف العلة الخاص بنا‪:‬‬
‫على سبيل املثال ‪ ،‬إليك تنفيذ غري صحيح لجملة ّ‬

‫!‪// warning: deliberately incorrect‬‬


‫{ )‪switch (ch‬‬
‫‪case 'a': ++aCnt; // oops: should have a break statement‬‬
‫‪case 'e': ++eCnt; // oops: should have a break statement‬‬
‫‪case 'i': ++iCnt; // oops: should have a break statement‬‬
‫‪case 'o': ++oCnt; // oops: should have a break statement‬‬
‫} ;‪case 'u': ++uCnt‬‬

‫لفهم ما يحدث ‪ ،‬افرتض أن قيمة ‪ ch‬هي "‪."e‬‬ ‫•‬


‫يقفز التنفيذ إلى الكود الذي يلي تسمية الحالة "‪ ، "e‬واليت تزيد من قيمة ‪. eCnt‬‬ ‫•‬
‫أيضا‪.‬‬
‫سيستمر التنفيذ عرب تسميات الحالة ‪ ،‬وسزييد ‪ iCnt‬و ‪ oCnt‬و ‪ً uCnt‬‬ ‫•‬

‫أفضل املمارسات‬
‫بالرغم من أنه ليس من الرضوري تضمني اكرس_ بعد آخر تسمية للحالة ‪،‬‬ ‫•‬
‫إﻻ أن الطريقة األكرث أما ًنا هي كتابة اكرس_‪.‬‬ ‫•‬
‫وهكذا ‪ ،‬إذا تمت إضافة حالة إضافية الح ًقا ‪ ،‬فسيكون اكرس_ في مكانه بالفعل‪.‬‬ ‫•‬

‫‪The default Label‬‬ ‫التسمية "افرتايض"‬

‫بدل_‪.‬‬
‫يتم تنفيذ الجمل اليت تلي التسمية "افرتايض" عندما ال تتطابق تسمية الحالة مع قيمة تعبري ّ‬

‫على سبيل املثال ‪،‬‬


‫قد نضيف عدا ًدا لتتبع عدد األحرف اليت نقرأها‪.‬‬ ‫•‬
‫سزنيد العداد ‪ -‬املسمى ‪ - otherCnt‬في الحالة افرتايض ‪:‬‬ ‫•‬

‫‪// if ch is vowel, increment appropriate counter‬‬


‫{ )‪switch (ch‬‬
‫;‪case 'a': case 'e': case 'i': case 'o': case 'u': ++vowelCnt; break‬‬
‫} ;‪default: ++otherCnt; break‬‬

‫في هذا اإلصدار ‪ ،‬إذا لم يكن ‪ ch‬حر ًفا متحر ًكا ‪ ،‬فسيبدأ التنفيذ عند التسمية افرتايض وسزنيد ‪.otherCnt‬‬
‫أفضل املمارسات‬

‫قد يكون من املفيد تعريف التسمية افرتايض حىت إن لم يكن هناك عمل للحالة افرتايض‪.‬‬
‫يشري تعريف تسمية افرتايض خال للقراء الحقاً إلى أنه تم النظر في تلك الحالة‪.‬‬

‫قد ال تكون التسمية قائمة بذاتها ؛ يجب أن يسبق جملة أو تسمية حالة أخرى‪.‬‬ ‫•‬
‫بدل_ بحالة افرتايض ليس له عمل يقوم به ‪،‬‬
‫إذا انتهى ّ‬ ‫•‬
‫فيجب أن يتبع التسمية افرتايض جملة الغية أو كتلة خالية‪.‬‬ ‫•‬

‫بدل_‬
‫تعريف املتغري داخل بنية ّ‬
‫‪Variable Definitions inside the Body of a switch‬‬

‫بدل_ عرب تسميات الحاالت‪.‬‬


‫كما رأينا ‪ ،‬يمكن أن يقفز التنفيذ في كود ّ‬
‫بدل_ قبل تلك الحالة‪.‬‬
‫عندما يقفز التنفيذ إلى حالة معينة ‪ ،‬يتم تجاهل أي كود حدث داخل ّ‬ ‫•‬
‫تثري حقيقة تخطي الكود سؤااًل مثريًا لالهتمام‪:‬‬ ‫•‬
‫ماذا يحدث إذا تضمن الكود الذي تم تخطيه تعري ًفا ملتغري؟‬ ‫•‬

‫اإلجابة هي أنه من غري الرشعي القفز من مكان يكون فيه املتغري باستخدام ُمهئي خارج النطاق إلى مكان يكون فيه‬
‫هذا املتغري في النطاق ‪:‬‬

‫‪case true:‬‬
‫‪// this switch statement is illegal because‬‬
‫‪// these initializations might be bypassed‬‬
‫‪// error: control bypasses implicitly initialized variable‬‬
‫;‪string file_name‬‬
‫‪// error: control bypasses explicitly initialized variable‬‬
‫;‪int ival = 0‬‬
‫;‪int jval‬‬ ‫‪// ok: because jval is not initial‬‬
‫;‪break‬‬
‫‪case false:‬‬
‫‪// ok: jval is in scope but is uninitialized‬‬
‫‪jval = next_num(); // ok: assign a value to jval‬‬
‫‪if (file_name.empty()) // file_name in scope but wasn't initialized‬‬
‫‪// ...‬‬

‫ٍ‬
‫فعندئذ في أي وقت يقفز التحكم فيه إلى الحالة ‪، false‬‬ ‫إن كان هذا الكود رشعياً ‪،‬‬ ‫•‬
‫فإنه سيتجاوز تهيئة ‪ file_name‬و ‪.ival‬‬ ‫•‬
‫وهذه املتغريات ستكون في النطاق‪.‬‬ ‫•‬
‫يمكن أن تستخدم أكواد ما بعد حالة ‪ false‬تلك املتغريات‪ .‬مع ذلك ‪ ،‬لم يتم تهيئتها‪.‬‬ ‫•‬
‫نتيجة لذلك ‪ ،‬ال تسمح لنا اللغة بالقفز فوق التهيئة إن كان املتغري املهئي في النطاق عند النقطة اليت ينتقل‬ ‫•‬
‫إليها عنرص التحكم‪.‬‬
‫إذا احتجنا إلى تعريف متغري وتهيئته لحالة معينة ‪،‬‬
‫فيمكننا القيام بذلك عن طريق تعريف املتغري داخل كتلة ‪،‬‬ ‫•‬
‫وبالتالي التأكد من أن املتغري خارج النطاق عند نقطة أي تسمية الحقة‪.‬‬ ‫•‬

‫{ ‪case true:‬‬
‫‪// ok: declaration statement within a statement block‬‬
‫;)(‪string file_name = get_file_name‬‬
‫… ‪//‬‬
‫}‬
‫;‪break‬‬
‫‪case false:‬‬
‫‪if (file_name.empty()) // error: file_name is not in scope‬‬

‫قسم التمارين ‪5.3.2‬‬


‫التمرين ‪:5.9‬‬
‫برنامجا باستخدام سلسلة من جمل ‪ if‬لحساب عدد حروف العلة في النص املقروء من ‪.cin‬‬
‫ً‬ ‫اكتب‬

‫التمرين ‪:5.10‬‬
‫‪ -‬هناك مشكلة واحدة في برنامج حساب الحروف املتحركة لدينا حيث قمنا بتطبيقه‪:‬‬
‫‪ -‬ال يتم احتساب األحرف الكبرية كأحرف متحركة‪.‬‬
‫برنامجا يعد كاًل من األحرف الصغرية والكبرية كحرف متحرك مناسب‬
‫ً‬ ‫‪ -‬اكتب‬
‫‪ -‬أي ‪ ،‬يجب أن يحسب برنامجك كالً من "‪ "a‬و "‪ "A‬كجزء من ‪ ، aCnt‬وهكذا دواليك‪.‬‬

‫التمرين ‪:5.11‬‬
‫‪ -‬قم بتعديل برنامج حساب الحروف املتحركة الخاص بنا بحيث‬
‫أيض ا بحساب عدد املسافات الفارغة وعالمات التبويب واألسطر الجديدة اليت تمت قراءتها‪.‬‬
‫‪ -‬يقوم ً‬

‫التمرين ‪:5.12‬‬
‫‪ -‬قم بتعديل برنامج حساب الحروف املتحركة الخاص بنا بحيث‬
‫‪ -‬يحسب عدد مرات تكرارات التسلسالت التالية املكونة من حرفني‪ ff :‬و ‪ fl‬و ‪.fi‬‬

‫التمرين ‪:5.13‬‬
‫يحتوي كل برنامج في النص املمزي أدناه على خطأ برمجي شائع‪ .‬قم بتحديد وتصحيح كل خطأ‪.‬‬

‫)‪(a‬‬
‫;‪unsigned aCnt = 0, eCnt = 0, iouCnt = 0‬‬
‫;)(‪char ch = next_text‬‬
‫{ )‪switch (ch‬‬
‫;‪case 'a': aCnt++‬‬
‫;‪case 'e': eCnt++‬‬
‫} ;‪default: iouCnt++‬‬

‫)‪(b‬‬
‫;)(‪unsigned index = some_value‬‬
‫{ )‪switch (index‬‬
‫‪case 1:‬‬
int ix = get_value(); ivec[ ix ] = index; break;
default:
ix = ivec.size()-1; ivec[ ix ] = index; }

(c)
unsigned evenCnt = 0, oddCnt = 0;
int digit = get_num() % 10;
switch (digit) {
case 1, 3, 5, 7, 9:
oddcnt++; break;
case 2, 4, 6, 8, 10:
evencnt++; break; }

(d)
unsigned ival=512, jval=1024, kval=4096;
unsigned bufsize;
unsigned swt = get_bufCnt();
switch(swt) {
case ival:
bufsize = ival * sizeof(int); break;
case jval:
bufsize = jval * sizeof(int); break;
case kval:
bufsize = kval * sizeof(int); break; }
‫‪ 5٫4‬الجمــــــــــل التكراريــــــة‬
‫‪5.4. Iterative Statements‬‬

‫صحيحا‪.‬‬
‫ً‬ ‫متكررا حىت يكون الرشط‬
‫ً‬ ‫توفر الجمل التكرارية ‪ ،‬املعروفة باسم الحلقات ‪ ،‬تنفيذًا‬
‫الجملتان طالـما_ ‪ while‬و ألجل_ ‪ for‬تختربان الرشط قبل تنفيذ البنية‪.‬‬ ‫•‬
‫بينما تقوم الجملة افعل_طالـما_ ‪ do while‬بتنفيذ البنية ثم اختبار رشطها‪.‬‬ ‫•‬

‫‪5.4.1. The while Statement‬‬ ‫‪ 5٫4٫1‬الجملة طالـما_‬

‫تقوم جملة طالـما_ ‪ while‬بتنفيذ البنية بشكل متكرر طاملا كان الرشط صحيحاً‪ .‬صياغتها النحوية هي ‪:‬‬

‫)الرشط ‪while (condition‬‬


‫البنية ‪statement‬‬

‫غالبا ما تكون كتلة) طاملا تم تقييم الرشط على أنه صحيح‪.‬‬


‫ً‬ ‫في ‪ ، while‬يتم تنفيذ البنية (واليت‬ ‫•‬
‫ال يسمح أن يكون الرشط فارغا‪ .‬فإذا أسفر أول تقييم للرشط عن خطأ ‪ ،‬فلن يتم تنفيذ البنية‪.‬‬ ‫•‬
‫يمكن أن يكون الرشط تعبريًا أو إعال ًنا عن متغري ُمهيأ‪.‬‬ ‫•‬
‫وفي العادة ‪ ،‬يجب أن يقوم الرشط نفسه أو بنية الحلقة بعمل يشء ما لتغيري قيمة التعبري‪.‬‬ ‫•‬
‫عدا ذلك ‪ ،‬فلن تنتهي الحلقة أبدا‪.‬‬ ‫•‬

‫ملحوظة‬

‫يتم إنشاء وإتالف املتغريات املعرفة في رشط طاملا_ أو في بنيته في كل تكرار‪.‬‬

‫‪Using a while Loop‬‬ ‫استخدام حلقة طالـما_‬

‫تُستخدم حلقة ‪ while‬بشكل عام عندما نريد التكرار إلى ما ﻻ نهاية ‪ ،‬فمثال عندما نقرأ املدخالت‪.‬‬
‫أيضا عندما نريد الوصول إلى قيمة متغري التحكم في حلقة بعد انتهاءها‪.‬‬
‫تكون طالـما_ مفيدة ً‬ ‫•‬

‫فمثال‪:‬‬

‫;‪vector<int> v; int i‬‬


‫‪// read until end-of-file or other input failure‬‬
‫)‪while (cin >> i‬‬
‫;)‪v.push_back(i‬‬
‫‪// find first negative element‬‬
‫;)(‪auto beg = v.begin‬‬
‫)‪while (beg != v.end() && *beg >= 0‬‬
‫;‪++beg‬‬
‫))(‪if (beg == v.end‬‬
‫‪// we know that all elements in v greater than or equal to zero‬‬

‫الحلقة األولى تقرأ البيانات من املدخالت القياسية‪.‬‬ ‫•‬


‫ليس لدينا أي فكرة كم مرة سيتم تنفيذ هذه الحلقة‪.‬‬ ‫•‬
‫ستفشل الحالة عندما تقرأ ‪ cin‬بيانات غري صالحة ‪ ،‬أو تواجه فشل مدخالت ما ‪ ،‬أو تصل لنهاية امللف‪.‬‬ ‫•‬
‫تستمر الحلقة الثانية حىت نجد قيمة سالبة‪.‬‬ ‫•‬
‫عندما تنتهي الحلقة ‪ ،‬فإن ‪ beg‬إما تساوي ()‪ ، v.end‬أو تشري إلى عنرص في ‪ v‬قيمته أقل من الصفر‪.‬‬ ‫•‬
‫يمكننا استخدام حالة ‪ beg‬خارج ‪ while‬لتقرير مزيد من املعالجة‪.‬‬ ‫•‬

‫تمارين القسم ‪5.4.1‬‬


‫التمرين ‪:5.14‬‬
‫برنامجا لقراءة السالسل من املدخالت القياسية بحثًا عن الكلمات املكررة‪.‬‬
‫ً‬ ‫‪ -‬اكتب‬
‫‪ -‬يجب أن يجد الربنامج أماكن في املدخالت حيث يتم اتباع كلمة واحدة مبارشة بنفسها‪.‬‬
‫‪ -‬تتبع أكرب عدد من املرات اليت يحدث فيها تكرار واحد والكلمة اليت يتم تكرارها‪.‬‬
‫‪ -‬اطبع أقىص عدد من التكرارات ‪ ،‬أو اطبع رسالة تفيد بعدم تكرار أي كلمة‪.‬‬
‫‪ -‬على سبيل املثال ‪ ،‬إذا كان املدخالت هو‬
‫‪how now now now brown cow cow‬‬
‫‪ -‬يجب أن تشري املخرجات إلى أن الكلمة ‪ now‬حدثت ثالث مرات‪.‬‬

‫‪5.4.2. Traditional for Statement‬‬ ‫‪ 5٫4٫2‬جملة ﻷجل_ التقليدية‬

‫الصياغة النحوية لجملة ﻷجل_ هي ‪:‬‬

‫)تعبري ‪; expression‬رشط ‪; condition‬جملة أولية ‪for (init-statement‬‬


‫‪statement‬‬ ‫البنية‬

‫غالبا ما يُشار إلى ‪ for‬والجزء املوجود داخل األقواس باسم رأس ‪.for‬‬
‫ً‬ ‫•‬
‫يجب أن تكون الجملة األولية جملة إعالن أو تعبري أو جملة خالية‪.‬‬ ‫•‬
‫أيضا اعتبار شكل نحوي آخر مثل‬
‫تنتهي كل من تلك الجمل بفاصلة منقوطة ‪ ،‬لذا يمكن ً‬ ‫•‬

‫)تعبري ‪; expression‬رشط ‪; condition‬مهئي ‪for (initializer‬‬


‫‪Statement‬‬ ‫بنية‬

‫بشكل عام ‪ ،‬يتم استخدام الجملة اﻷولية لتهيئة أو تعيني قيمة أولية يتم تعديلها على مدار الحلقة‪.‬‬ ‫•‬
‫بينما يعمل الرشط كعنرص تحكم في الحلقة‪.‬‬ ‫•‬
‫طاملا يتم تقييم الرشط على أنه صحيح ‪ ،‬يتم تنفيذ البنية‪.‬‬ ‫•‬
‫إذا أسفر أول تقييم للرشط عن خطأ ‪ ،‬فلن يتم تنفيذ البنية‪.‬‬ ‫•‬
‫يقوم التعبري عاد ًة بتعديل املتغري (ــات) املهيأ(ة) في الجملة اﻷولية واختبارهـ(ــا) في الرشط‪.‬‬ ‫•‬
‫يتم تقييم التعبري مع كل تكرار للحلقة‪.‬‬ ‫•‬
‫وكالعادة ‪ ،‬يمكن أن تكون البنية إما جملة واحدة أو جمالً مركبة‪.‬‬ ‫•‬
‫‪Execution Flow in a Traditional for Loop‬‬ ‫تدفق التنفيذ في حلقة ألجل_ تقليدية‬

‫في ضوء حلقة ‪ for‬التالية من الفقرة ‪: 3.2.3‬‬

‫‪// process characters in s until run out or hit whitespace‬‬


‫;‪for (decltype(s.size()) index = 0‬‬
‫)‪index != s.size() && !isspace(s[index]); ++index‬‬
‫‪s[index] = toupper(s[index]); //capitalize current character‬‬

‫ترتيب التقييم على النحو التالي‪:‬‬


‫‪ .1‬يتم تنفيذ الجملة األولية مرة واحدة بداية الحلقة‪.‬‬
‫هنا ‪ ،‬يتم تعريف الفهرس ‪ index‬وتهيئته على الصفر‪.‬‬
‫‪ .2‬بعد ذلك ‪ ،‬يتم تقييم الرشط‪.‬‬
‫مساويا لـ ‪ s.size‬وكان الحرف في ]‪ s[index‬ليس مسافة بيضاء ‪،‬‬
‫ً‬ ‫إن لم يكن الفهرس‬
‫فسيتم تنفيذ بنية ‪ .for‬عدا ذلك ‪ ،‬تنتهي الحلقة‪.‬‬
‫فإن كان الرشط خاطًئ ا في أول تكرار ‪ ،‬فلن يتم تنفيذ بنية ‪ for‬إطالقاً‪.‬‬
‫صحيحا ‪ ،‬فسيتم تنفيذ بنية ‪.for‬‬
‫ً‬ ‫‪ .3‬أما إن كان الرشط‬
‫في هذه الحالة ‪ ،‬تجعل بنية ‪ for‬حالة حرف ]‪ s[index‬حرفا كبريا‪.‬‬
‫‪ .4‬أخريًا ‪ ،‬يتم تقييم التعبري‪ .‬هنا ‪ ،‬يزتايد الفهرس بمقدار ‪.1‬‬

‫تمثل هذه الخطوات األربع أول تكرار لحلقة ﻷجل_‪.‬‬


‫يتم تنفيذ الخطوة ‪ 1‬مرة واحدة فقط عند الدخول إلى الحلقة‪.‬‬ ‫•‬
‫تتكرر الخطوات ‪ 2‬و ‪ 3‬و ‪ 4‬حىت يتم تقييم الرشط على أنه خطأ ‪-‬‬ ‫•‬
‫أي عندما نواجه حرف مسافة بيضاء في ‪ ، s‬أو عندما يكون الفهرس أكرب من ()‪. s.size‬‬ ‫•‬

‫ملحوظة‬

‫يجدر بنا أن نتذكر أن رؤية أي كائن معرف داخل رأس ‪ for‬يقترص على بنية حلقتها‪.‬‬ ‫•‬
‫بالتالي ‪ ،‬في هذا املثال ‪ ،‬ال يمكن الوصول إلى ‪ index‬بعد اكتمال ‪.for‬‬ ‫•‬

‫‪Multiple Definitions in the for Header‬‬ ‫التعريفات املتعددة في رأس حلقة ﻷجل_‬

‫كما هو حال أي إعالن آخر ‪ ،‬يمكن أن تعرف الجملة األولية عدة كائنات‪.‬‬
‫مع ذلك ‪ ،‬قد تكون الجملة األولية جملة إعالن وحيدة فقط‪.‬‬ ‫•‬
‫لذلك ‪ ،‬يجب أن يكون لجميع املتغريات نفس النوع األسايس‪.‬‬ ‫•‬

‫كمثال ‪ ،‬قد نكتب حلقة لتكرار عنارص متجه في النهاية على النحو التالي‪:‬‬

‫‪// remember size of v and stop when get to original last element‬‬
‫)‪for (decltype(v.size()) i = 0, sz = v.size(); i != sz; ++i‬‬
‫;)]‪v.push_back(v[i‬‬
‫في هذه الحلقة نعرف كالً من الفهرس‪ ، i :‬واملتحكم في الحلقة‪ ، sz :‬في الجملة األولية‪.‬‬

‫‪Omitting Parts of the for Header‬‬ ‫حذف أجراء من رأس حلقة ﻷجل_‬

‫يمكن أن يحذف رأس ﻷجل_ أياً من (أو كل) الجملة األولية‪ ،‬أو الرشط أو التعبري‪.‬‬
‫فبإمكاننا استخدام جملة خالية للجملة األولية عندما تكون التهيئة غري رضورية‪.‬‬ ‫•‬

‫على سبيل املثال ‪ ،‬قد نعيد كتابة الحلقة اليت تبحث عن أول رقم سالب في متجه بحيث تستخدم ‪: for‬‬

‫;)(‪auto beg = v.begin‬‬


‫)‪for ( /* null */ ; beg != v.end() && *beg >= 0; ++beg‬‬
‫‪; // no work to do‬‬

‫الحظ أن الفاصلة املنقوطة رضورية لتشري إلى عدم وجود جملة أولية‪.‬‬ ‫•‬
‫بشكل أكرث دقة ‪ ،‬تمثل الفاصلة املنقوطة جملة أولية خالية‪.‬‬ ‫•‬
‫أيضا ألن عمل الحلقة كلها يحدث داخل الرشط والتعبري‪.‬‬
‫في هذه الحلقة ‪ ،‬تكون بنية ‪ for‬خالية ً‬ ‫•‬
‫يقرر الرشط الوقت الذي يحني فيه التوقف عن البحث ويزتايد التعبري في املكرر‪.‬‬ ‫•‬

‫إن حذف الرشط يعادل كتابة "‪ "true‬كرشط‪.‬‬


‫دائما على أنه صحيح ‪،‬‬
‫ً‬ ‫ونظرًا ألن الرشط يتم تقييمه‬ ‫•‬
‫يجب أن تحتوي بنية ﻷجل_ على جملة تنهي الحلقة‪ .‬وإال فإن الحلقة ستنفذ إلى ما ال نهاية ‪:‬‬ ‫•‬

‫{ )‪for (int i = 0; /* no condition */ ; ++i‬‬


‫!‪// process i; code inside loop must stop iteration‬‬
‫}‬

‫أيضا حذف التعبري من الرأس‪.‬‬


‫يمكننا ً‬
‫في مثل هذه الحلقات ‪ ،‬يجب على الرشط أو البنية أن تفعل شيًئ ا لدفع التكرار‪.‬‬ ‫•‬

‫كمثال ‪ ،‬سنعيد كتابة حلقة ‪ while‬اليت تقرأ املدخالت في متجه أعداد صحيحة ‪:‬‬

‫;‪vector<int> v‬‬
‫) ‪for (int i; cin >> i; /* no expression */‬‬
‫;)‪v.push_back(i‬‬

‫في هذه الحلقة ليست هناك حاجة لتعبري ألن الرشط يغري قيمة ‪.i‬‬ ‫•‬
‫يخترب الرشط تدفق املدخالت بحيث تنتهي الحلقة عندما نقرأ كل املدخالت أو نواجه خطأ فيها‪.‬‬ ‫•‬

‫قسم التمارين ‪5.4.2‬‬


‫التمرين ‪:5.15‬‬
‫‪ -‬ارشح كل حلقة من الحلقات التالية‪.‬‬
‫‪ -‬صحح أي مشاكل تكتشفها‪.‬‬
‫)‪(a‬‬ ‫} ‪for (int ix = 0; ix != sz; ++ix) { /* . . . */‬‬
‫)‪if (ix != sz‬‬
‫‪// . . .‬‬
‫)‪(b‬‬ ‫;‪int ix‬‬
‫} ‪for (ix != sz; ++ix) { /* . . . */‬‬
‫)‪(c‬‬ ‫} ‪for (int ix = 0; ix != sz; ++ix, ++ sz) { /* . . . */‬‬

‫التمرين ‪:5.16‬‬
‫‪ -‬الحلقة ‪ while‬جيدة بشكل خاص في التنفيذ بينما هناك رشط ما ؛‬
‫‪ -‬على سبيل املثال ‪ ،‬عندما نحتاج إلى قراءة القيم حىت نهاية امللف‪.‬‬
‫عموما على أنها حلقة خطوة‪ :‬يتخطى الفهرس نطا ًقا من القيم في مجموعة‪.‬‬ ‫ً‬ ‫‪ -‬يُنظر إلى حلقة ‪for‬‬
‫اصطالحيا لكل حلقة ثم أعد كتابة كل حلقة باستخدام بنية الحلقة األخرى‪.‬‬
‫ً‬ ‫استخداما‬
‫ً‬ ‫‪ -‬اكتب‬
‫‪ -‬إذا كان بإمكانك استخدام حلقة واحدة فقط ‪ ،‬فماذا ستختار؟ ملاذا ا؟‬
‫التمرين ‪:5.17‬‬
‫برنامجا لتحديد ما إذا كان أحد املتجهني هو بادئة لآلخر‪.‬‬
‫ً‬ ‫‪ -‬باستخدام متجهني من ‪ ، ints‬اكتب‬
‫‪ -‬بالنسبة للمتجهات ذات الطول غري املتساوي ‪ ،‬قارن عدد عنارص املتجه األصغر‪.‬‬
‫‪ -‬على سبيل املثال ‪ ،‬بالنظر إلى املتجهات اليت تحتوي على ‪ 0‬و ‪ 1‬و ‪ 1‬و ‪ 2‬و ‪ ، 8 ، 5 ، 3 ، 2 ، 1 ، 1 ، 0‬على التوالي ‪،‬‬
‫صحيحا‪.‬‬
‫ً‬ ‫يجب أن يعود برنامجك‬

‫‪5.4.3. Range for Statement‬‬ ‫‪ 5٫4٫3‬جملة ﻷجل_ للنطاق‬

‫قدم املعيار الجديد أبسط جملة ﻷجل_ يمكن استخدامها للتكرار عرب عنارص الحاوية أو تسلسالت أخرى‪.‬‬
‫الصياغة النحوية لجملة ألجل_للنطاق هي‪:‬‬

‫)تعبري ‪ : expression‬إعالن ‪for (declaration‬‬


‫بنية ‪statement‬‬

‫يجب أن يمثل التعبري تسلساًل ‪ ،‬مثل قائمة ُمهئي بأقواس ‪ ،‬أو مصفوفة ‪ ،‬أو كائن نوع مثل متجه أو سلسلة تملك‬
‫عضو بداية ونهاية تعود بمكررات‪.‬‬
‫يعرف اإلعالن متغرياً‪ .‬يجب أن يكون من املمكن تحويل كل عنرص من عنارص التسلسل إلى نوع املتغري‪.‬‬ ‫ّ‬ ‫•‬
‫أسهل طريقة للتأكد من تطابق األنواع هي استخدام محدد النوع التلقائي ‪.auto‬‬ ‫•‬
‫بهذه الطريقة سوف يستنتج املرتجم النوع بالنسبة لنا‪.‬‬ ‫•‬
‫مرجعيا‪.‬‬
‫ً‬ ‫نوعا‬
‫إذا أردنا الكتابة إلى عنارص في التسلسل ‪ ،‬فيجب أن يكون متغري الحلقة ً‬ ‫•‬
‫في كل تكرار ‪ ،‬يتم تعريف متغري التحكم وتهيئته على القيمة التالية في التسلسل ‪،‬‬ ‫•‬
‫وبعد ذلك يتم تنفيذ البنية‪ .‬وكالعادة ‪ ،‬يمكن أن تكون البنية جملة واحدة أو كتلة‪.‬‬ ‫•‬
‫ينتهي التنفيذ بمجرد معالجة كل العنارص‪.‬‬ ‫•‬

‫لقد رأينا بالفعل العديد من هذه الحلقات ‪ ،‬ولكن للتأكد من تكاملها ‪ ،‬إليك حلقة تضاعف قيمة كل عنرص في متجه‪:‬‬

‫;}‪vector<int> v = {0,1,2,3,4,5,6,7,8,9‬‬
‫‪// range variable must be reference so we can write to elements‬‬
‫)‪for (auto &r : v‬‬ ‫‪// for each element in v‬‬
‫;‪r *= 2‬‬ ‫‪// double value of each element in v‬‬

‫هنا يعلن رأس ‪ for‬عن متغري التحكم في الحلقة ‪ ، r‬ويربطه بـ ‪.v‬‬ ‫•‬
‫نستخدم ‪ auto‬للسماح للمرتجم باستنتاج النوع الصحيح لـ ‪.r‬‬ ‫•‬
‫وألننا نريد تغيري قيمة العنارص في ‪ ، v‬فإننا نعلن عن ‪ r‬كمرجع‪.‬‬ ‫•‬
‫عندما نعني على ‪ r‬داخل الحلقة ‪ ،‬فإن هذا التعيني يغري العنرص الذي يرتبط به ‪.r‬‬ ‫•‬

‫يتم تعريف ﻷجل_ للنطاق برشوط مساوية ﻷجل_ التقليدية ‪:‬‬

‫{ )‪for (auto beg = v.begin(), end = v.end(); beg != end; ++beg‬‬


‫‪auto &r = *beg; // r must be reference so we can change element‬‬
‫;‪r *= 2‬‬ ‫‪// double value of each element in v‬‬
‫}‬

‫اآلن وبعد أن عرفنا كيف يعمل ﻷجل_ للنطاق ‪،‬‬ ‫•‬


‫يمكننا أن نفهم ملاذا قلنا في الفقرة ‪ 3.3.2‬أنه ال يمكننا استخدام ﻷجل_ للنطاق إلضافة عنارص إلى متجه‬ ‫•‬
‫(أو حاوية أخرى)‪.‬‬
‫ذلك ﻷنه في ﻷجل_ للنطاق ‪ ،‬يتم تخزين قيمة ()‪ end‬مؤق ًتا‪.‬‬ ‫•‬
‫فإذا أضفنا عنارص إلى التسلسل (أو أزلناها منه)‪ ،‬فقد يتم إبطال قيمة ()‪. end‬‬ ‫•‬
‫سيكون لدينا املزيد لنقوله حول هذه األمور في الفصل التاسع‪.‬‬ ‫•‬

‫‪5.4.4. The do while Statement‬‬ ‫‪ 5٫4٫4‬الجملة افعل_طالـما_‬

‫تعترب جملة افعل_طالـما_ ‪ do while‬عبارة عن جملة طالـما_ ‪ while‬لكن يتم اختبار رشطها بعد تنفيذ بنيتها‪.‬‬
‫وبغض النظر عن قيمة الرشط ‪ ،‬نقوم بتنفيذ البنية مرة على األقل‪ .‬الشكل النحوي لها كما يلي‪:‬‬

‫‪do‬‬
‫‪statement‬‬ ‫بنية‬
‫;)رشط ‪while (condition‬‬

‫ملحوظة‬

‫تنتهي افعل_طالـما_ بفاصلة منقوطة بعد رشط بني قوسني‪.‬‬

‫في افعل_ ‪ ، do‬يتم تنفيذ الجملة قبل تقييم الرشط‪.‬‬ ‫•‬


‫فارغا‪.‬‬
‫ً‬ ‫ال يسمح أن يكون الرشط‬ ‫•‬
‫إذا تم تقييم الرشط على أنه خطأ ‪ ،‬فإن الحلقة تنتهي ؛ عدا ذلك ‪ ،‬تتكرر الحلقة‪.‬‬ ‫•‬
‫يجب تعريف املتغريات املستخدمة في الرشط خارج بنية جملة افعل_طالـما_ ‪.do while‬‬ ‫•‬

‫يمكننا كتابة برنامج يقوم بإجراء عمليات جمع (إلى ما ﻻ نهاية) باستخدام ‪: do while‬‬

‫‪// repeatedly ask user for pair of numbers to sum‬‬


‫;‪string rsp‬‬ ‫‪// used in condition; can't be defined inside do‬‬
‫{ ‪do‬‬
‫;" ‪cout << "please enter two values:‬‬
‫;‪int val1 = 0, val2 = 0; cin >> val1 >> val2‬‬
‫‪cout << "The sum of " << val1 << " and " << val2‬‬
‫"‪<< " = " << val1 + val2 << "\n\n‬‬
‫;" ‪<< "More? Enter yes or no:‬‬
‫;‪cin >> rsp‬‬
‫;)'‪} while (!rsp.empty() && rsp[0] != 'n‬‬

‫تبدأ الحلقة بمطالبة املستخدم برقمني‪.‬‬ ‫•‬


‫ثم يطبع مجموعهم ويسأل عما إذا كان املستخدم يرغب في عمل جمع آخر‪.‬‬ ‫•‬
‫يتحقق الرشط أن املستخدم قد قدم ر ًدا‪.‬‬ ‫•‬
‫إذا لم يكن كذلك ‪ ،‬أو إذا كانت املدخالت تبدأ بـ ‪ ، n‬يتم الخروج من الحلقة‪ .‬عدا ذلك ستتكرر الحلقة‪.‬‬ ‫•‬
‫ونظرًا ألن الرشط ال يتم تقييمه إال بعد تنفيذ البنية أو الكتلة ‪،‬‬ ‫•‬
‫فإن حلقة ‪ do while‬ال تسمح بتعريفات متغرية داخل الرشط ‪:‬‬ ‫•‬

‫{ ‪do‬‬
‫‪// . . .‬‬
‫;)‪mumble(foo‬‬
‫‪} while (int foo = get_foo()); // error: declaration in do condition‬‬

‫إذا تمكنا من تعريف املتغريات في الرشط ‪ ،‬فسيحدث استخدام للمتغري قبل تعريفه!‬

‫قسم التمارين ‪5.4.4‬‬


‫التمرين ‪:5.18‬‬
‫‪ -‬ارشح كل حلقة من الحلقات التالية‪.‬‬
‫‪ -‬صحح أي مشاكل تكتشفها‪.‬‬
‫‪(a) do‬‬
‫‪int v1,‬‬ ‫;‪v2‬‬
‫<< ‪cout‬‬ ‫; "‪"Please enter two numbers to sum:‬‬
‫‪if (cin‬‬ ‫)‪>> v1 >> v2‬‬
‫<< ‪cout‬‬ ‫;‪"Sum is: " << v1 + v2 << endl‬‬
‫;)‪while (cin‬‬

‫{ ‪(b) do‬‬
‫‪// . . .‬‬
‫;))(‪} while (int ival = get_response‬‬

‫{ ‪(c) do‬‬
‫;)(‪int ival = get_response‬‬
‫;)‪} while (ival‬‬

‫التمرين ‪:5.19‬‬
‫برنامجا يستخدم حلقة ‪ do while‬ليطلب بشكل متكرر سلسلتني من املستخدم‬
‫ً‬ ‫‪ -‬اكتب‬
‫‪ -‬قم بإظهار السلسلة األقل من األخرى‪.‬‬
‫‪ 5٫5‬جمــــــــــل القفــــــز‬
‫‪5.5. Jump Statements‬‬

‫جمل القفز تقطع تدفق التنفيذ‪ .‬تقدم لغة يس‪ ++‬أربع جمل قفز ‪:‬‬
‫اكرس_ ‪ ، break‬و استمر_ ‪ ، continue‬و اذهب_إلى ‪ goto‬سنغطيها في هذا الفصل ‪،‬‬ ‫•‬
‫وجملة ِ‬
‫أعد ‪ ، return‬اليت سنتناولها في الفصل السادس‪.‬‬ ‫•‬

‫‪5.5.1. The break Statement‬‬ ‫‪ 5٫5٫1‬الجملة اكرس_‬

‫تنهي جملة اكرس_ ‪ break‬أقرب الجمل املتضمنة‪:‬‬


‫بدل_ ‪.switch‬‬
‫طالـما_ ‪ while‬ـ افعل_طالـما_ ‪ do while‬ـ ﻷجل_ ‪ for‬و ّ‬ ‫•‬
‫يستأنف التنفيذ في الجملة اليت تأتي مبارشة بعد الجملة املنتهية‪.‬‬ ‫•‬
‫بدل_‬
‫يمكن أن تظهر اكرس_ فقط داخل جمل تكرارية أو جملة ّ‬ ‫•‬
‫(بما في ذلك الجمل الداخلية أو الكتل املتداخلة داخل تلك الحلقات)‪.‬‬ ‫•‬

‫بدل_ مغلقة فقط ‪:‬‬


‫يؤثر اكرس_ على أقرب حلقة أو ّ‬

‫;‪string buf‬‬
‫{ ))(‪while (cin >> buf && !buf.empty‬‬
‫{ )]‪switch(buf[0‬‬
‫‪case '-':‬‬
‫‪// process up to first blank‬‬
‫{ )‪for (auto it = buf.begin()+1; it != buf.end(); ++it‬‬
‫)' ' == ‪if (*it‬‬
‫‪break; // #1, leaves for loop‬‬
‫… ‪//‬‬
‫}‬
‫‪// break #1 transfers control here‬‬
‫‪// remaining '-' processing:‬‬
‫‪break; // #2, leaves switch statement‬‬
‫‪case '+':‬‬
‫… ‪//‬‬
‫‪} // end switch‬‬
‫‪// end of switch: break #2 transfers control here‬‬
‫‪} // end while‬‬

‫تنهي اكرس_ املصنفة ‪ 1#‬حلقة ﻷجل_ اليت تتبع تسمية حالة السالب‪.‬‬ ‫•‬
‫بدل_ املتضمنة وفي الواقع ال ينهي حىت معالجة الحالة الحالية‪.‬‬
‫فهو ال ينهي جملة ّ‬ ‫•‬
‫إضافيا للتعامل مع السالب أو اكرس_ اليت‬
‫ً‬ ‫تستمر املعالجة بأول جملة تأتي بعد ﻷجل_ ‪ ،‬واليت قد تكون كوداً‬ ‫•‬
‫تكمل هذه الحالة‪.‬‬
‫بدل_ لكنها ال تنهي حلقة ‪ while‬املتضمنة‪.‬‬
‫تنهي اكرس_ املصنفة ‪ّ 2#‬‬ ‫•‬
‫تستمر املعالجة بعد اكرس_ هذه عن طريق تنفيذ الرشط في ‪.while‬‬ ‫•‬

‫قسم التدريبات ‪5.5.1‬‬


‫التمرين ‪:5.20‬‬
‫برنامج ا لقراءة سالسل من املدخالت القياسية حىت تظهر الكلمة نفسها مرتني متتاليتني أو تتم قراءة جميع‬
‫ً‬ ‫‪ -‬اكتب‬
‫الكلمات‪.‬‬
‫‪ -‬استخدم حلقة ‪ while‬لقراءة النص كلمة واحدة في كل مرة‪.‬‬
‫‪ -‬استخدم جملة ‪ break‬إلنهاء الحلقة إذا ظهرت الكلمة مرتني على التوالي‪.‬‬
‫‪ -‬اطبع الكلمة إذا تكررت مرتني متتاليتني ‪ ،‬أو اطبع رسالة تفيد بعدم تكرار أي كلمة‪.‬‬

‫‪5.5.2. The continue Statement‬‬ ‫‪ 5٫5٫2‬الجملة استمر_‬

‫فورا التكرار التالي‪.‬‬


‫تُنهي جملة استمر_ التكرار الحالي ألقرب حلقة متضمنة وتبدأ ً‬
‫• يمكن أن تظهر جملة استمر_ داخل حلقة ‪ ، for‬أو ‪ ، while‬أو ‪، do while‬‬
‫بما في ذلك الجمل الداخلية أو الكتل املتداخلة داخل تلك الحلقات‪.‬‬ ‫•‬
‫ومثل جملة اكرس_ ‪ ، break‬فإن استمر_ داخل حلقة متداخلة تؤثر فقط على أقرب حلقة متضمنة‪.‬‬ ‫•‬
‫مضمنًا داخل جملة تكرارية‪.‬‬
‫ّ‬ ‫بدل_ هذا‬
‫بدل_ إﻻ إذا كان ّ‬
‫لكن على عكس جملة اكرس_ ‪ ،‬ﻻ تظهر استمر_ داخل ّ‬ ‫•‬

‫الجملة استمر_ تقطع التكرار الحالي ؛ حيث يبقى التنفيذ داخل الحلقة‪.‬‬
‫في حالة ‪ while‬أو ‪ ، do while‬يستمر التنفيذ من خالل تقييم الرشط‪.‬‬ ‫•‬
‫أما في حلقة ‪ for‬التقليدية ‪ ،‬يستمر التنفيذ عند التعبري داخل رأس ‪.for‬‬ ‫•‬
‫وفي حلقة ‪ for‬النطاق ‪ ،‬يستمر التنفيذ عن طريق تهيئة متغري التحكم على العنرص التالي في التسلسل‪.‬‬ ‫•‬

‫على سبيل املثال ‪،‬‬


‫تقرأ الحلقة التالية املدخالت القياسية لكلمة واحدة في كل مرة‪.‬‬ ‫•‬
‫ستتم معالجة الكلمات اليت تبدأ برشطة سفلية فقط‪.‬‬ ‫•‬
‫بالنسبة ألي قيمة أخرى ‪ ،‬ننهي التكرار الحالي ونحصل على املدخالت التالية ‪:‬‬ ‫•‬

‫;‪string buf‬‬
‫{ ))(‪while (cin >> buf && !buf.empty‬‬
‫)'_' =! ]‪if (buf[0‬‬
‫‪continue; // get another input‬‬
‫‪// still here? input starts with underscore; process buf . .‬‬
‫}‬

‫قسم التدريبات ‪5.5.2‬‬


‫التمرين ‪:5.21‬‬
‫‪ -‬قم بمراجعة الربنامج من التمرين الوارد في البند ‪ 5.5.1‬بحيث يبحث فقط عن كلمات مكررة تبدأ بحرف كبري‪.‬‬

‫‪5.5.3. The goto Statement‬‬ ‫‪ 5٫5٫3‬الجملة اذهب_إلى‬


‫توفر جملة اذهب_إلى ‪ goto‬قفزة غري مرشوطة من ‪ goto‬إلى جملة أخرى في نفس الدالة‪.‬‬

‫أفضل املمارسات‬

‫ينبغي أال تستخدم الربامج جمل ‪ goto‬ـ حيث تجعلها صعبة الفهم والتعديل‪.‬‬

‫الشكل النحوي لجملة اذهب_إلى ‪ goto‬هو‬

‫;‪goto label‬‬

‫يعرف جملة‪.‬‬
‫معرف ّ‬
‫حيث التسمية ‪ label‬هي ّ‬
‫ٍ‬
‫متبوع بنقطتني‪:‬‬ ‫أما الجملة املسماة فيمكن أن تكون أي جملة يسبقها معرف‬

‫;‪end : return‬‬ ‫‪// labeled statement; may be target of goto‬‬

‫املعر فات املسماة مستقلة عن األسماء املستخدمة للمتغريات واملعرفات األخرى‪.‬‬


‫ّ‬ ‫•‬
‫ومن ثم ‪ ،‬قد يكون للتسمية نفس املعرف الخاص بكيان آخر في الربنامج دون التدخل في االستخدامات‬ ‫•‬
‫األخرى لهذا املعرف‪.‬‬
‫يجب أن يكون كل من ‪ goto‬والجملة املسماة اليت تنقل إليه التحكم في نفس الدالة‪.‬‬ ‫•‬
‫بدل_ ‪ ،‬ال يمكن لـ ‪ goto‬نقل التحكم من نقطة يكون فيها املتغري األولي خارج النطاق‬‫وكما هو حال جملة ّ‬ ‫•‬
‫إلى نقطة يكون فيها هذا املتغري في النطاق‪:‬‬

‫… ‪//‬‬
‫;‪goto end‬‬
‫‪int ix = 10; // error: goto bypasses initialized variable definition‬‬
‫‪end:‬‬
‫‪// error: code here could use ix but goto bypassed its declaration‬‬
‫;‪ix = 42‬‬

‫ال بأس بالذهاب إلى الخلف فوق تعريف تم تنفيذه بالفعل‪.‬‬


‫لكن الذهاب إلى نقطة ما قبل تعريف املتغري يدمر املتغري ويعيد تكوينه‪:‬‬

‫‪// backward jump over initialized variable definition is okay‬‬


‫‪begin:‬‬
‫;)(‪int sz = get_size‬‬
‫{ )‪if (sz <= 0‬‬
‫;‪goto begin‬‬
‫}‬

‫هنا يتم تدمري ‪ sz‬عند تنفيذ ‪.goto‬‬ ‫•‬


‫يتم تعريفه وتهيئته من جديد عندما يمر عنرص التحكم مرة أخرى عرب تعريفه بعد الذهاب إلى الخلف نحو‬ ‫•‬
‫‪.begin‬‬
‫قسم التدريبات ‪5.5.3‬‬
‫التمرين ‪:5.22‬‬
‫‪ -‬يمكن كتابة املثال األخري في هذا القسم القفز للوراء إلى ‪ begin‬بشكل أفضل باستخدام حلقة‪.‬‬
‫‪ -‬أعد كتابة الكود إلزالة ‪.goto‬‬
‫جرب_ ومعالجــــــة اﻻستثنــــــاءات‬
‫‪ 5٫6‬كتل ّ‬
‫‪5.6. try Blocks and Exception Handling‬‬

‫االستثناءات هي حاالت شاذة وقت التشغيل تحصل خارج األداء الطبيعي للربنامج ‪ -‬مثل فقد اتصال قاعدة البيانات‬
‫أو مواجهة مدخالت غري متوقعة ‪.-‬‬
‫• يمكن أن يكون التعامل مع السلوك الشاذ أحد أصعب أجزاء تصميم أي نظام‪.‬‬
‫يتم استخدام معالجة االستثناءات بشكل عام عندما يكتشف جزء ما من الربنامج مشكلة ال يمكنه حلها‪،‬‬ ‫•‬
‫وتكون املشكلة بحيث ال يمكن متابعة جزء االكتشاف من الربنامج‪.‬‬ ‫•‬
‫في مثل هذه الحاالت ‪ ،‬يحتاج جزء الكشف إلى وسيلة لإلشارة إلى حدوث يشء ما وأنه ال يمكن أن يستمر‪.‬‬ ‫•‬
‫عالوة على ذلك ‪ ،‬يحتاج جزء الكشف إلى وسيلة لإلشارة إلى املشكلة ؛‬ ‫•‬
‫دون معرفة أي جزء من الربنامج سيتعامل مع الحالة االستثنائية‪.‬‬ ‫•‬
‫بعد اإلشارة إلى ما حدث ‪ ،‬يتوقف جزء الكشف عن املعالجة‪.‬‬ ‫•‬

‫الربنامج الذي يحتوي على كود قد يثري استثناء (عادة) له جزء آخر للتعامل مع كل ما حدث‪.‬‬
‫على سبيل املثال ‪ ،‬إن كانت املشكلة عبارة عن مدخالت غري صالحة ‪،‬‬ ‫•‬
‫قد يطلب جزء املعالجة من املستخدم توفري املدخالت الصحيحة‪.‬‬ ‫•‬
‫إذا فقدت قاعدة البيانات ‪ ،‬فقد ينبه جزء املعالجة املشغل‪.‬‬ ‫•‬

‫يدعم التعامل مع االستثناءات هذا التعاون بني الكشف عن أجزاء الربنامج والتعامل معها‪.‬‬
‫في يس‪ ، ++‬تتضمن معالجة االستثناءات ‪:‬‬ ‫•‬
‫طرح التعبريات ‪: throw expressions‬‬ ‫•‬
‫يستخدمها جزء الكشف ليرش إلى أنه واجه شيًئ ا ال يمكنه التعامل معه‪ .‬نقول أن طرح يثري استثناء‪.‬‬ ‫•‬
‫جرب_ ‪: try‬‬ ‫كتل ّ‬ ‫•‬
‫يستخدمها جزء املعالجة للتعامل مع استثناء‪.‬‬ ‫•‬
‫جرب_ بالكلمة ‪ try‬وتنتهي بجملة التقط_ ‪ catch‬أو أكرث‪.‬‬
‫تبدأ كتلة ّ‬ ‫•‬

‫جرب_ ‪ try‬بواسطة إحدى جمل‬


‫عاد ًة ما يتم التعامل مع االستثناءات اليت يتم طرحها من اﻷكواد املنفذة داخل كتلة ّ‬
‫التقط_ ‪.catch‬‬
‫أيضا باسم معالجات االستثناء‪.‬‬
‫ونظرًا ألنها "تعالج" االستثناء ‪ ،‬تُعرف جمل التقط_ ‪ً catch‬‬ ‫•‬
‫وهي مجموعة فئات استثناء تُستخدم لتمرير معلومات حول ما حدث بني الطرح والتقط_ املرتبط به‪.‬‬ ‫•‬
‫في الجزء املتبقي من هذا القسم ‪ ،‬سنقدم هذه املكونات الثالثة ملعالجة االستثناءات‪.‬‬ ‫•‬
‫أيضا املزيد لنقوله حول االستثناءات في الفصل الثامن عرش‪.‬‬
‫سيكون لدينا ً‬ ‫•‬

‫‪5.6.1. A throw Expression‬‬ ‫‪ 5٫6٫1‬التعبري طرح‬

‫يستخدم جزء الكشف من الربنامج تعبري طرح ‪ throw expression‬إلثارة استثناء‪.‬‬


‫متبوعا بتعبري ‪.expression‬‬
‫ً‬ ‫يتكون الطرح من الكلمة ‪throw‬‬ ‫•‬
‫يحدد نوع التعبري نوع االستثناء الذي يتم طرحه‪.‬‬ ‫•‬
‫عادة ما يتبع تعبري الطرح فاصلة منقوطة ‪ ،‬ما يجعلها داخل جملة تعبري‪.‬‬ ‫•‬

‫وكمثال بسيط ‪ ،‬تذكر الربنامج الوارد في الفقرة ‪ 1.5.2‬الذي جمع كائين عنرص املبيعات ‪،‬‬
‫قام ذلك الربنامج بفحص ما إذا كانت السجالت اليت قرأها تشري إلى نفس الكتاب‪.‬‬ ‫•‬
‫فإن لم تكن كذلك ‪ ،‬سيطبع رسالة ويخرج‪.‬‬ ‫•‬

‫;‪Sales_item item1, item2‬‬


‫;‪cin >> item1 >> item2‬‬
‫‪// first check that item1 and item2 represent same book‬‬
‫{ ))(‪if (item1.isbn() == item2.isbn‬‬
‫;‪cout << item1 + item2 << endl‬‬
‫;‪return 0‬‬ ‫‪// indicate success‬‬
‫{ ‪} else‬‬
‫;‪cerr << "Data must refer to same ISBN" << endl‬‬
‫‪return -1; // indicate failure‬‬
‫}‬

‫في برنامج أكرث واقعية ‪ ،‬يمكن فصل جزء يضيف عنارص عن جزء يدير التفاعل مع املستخدم‪.‬‬ ‫•‬
‫في تلك الحالة ‪ ،‬قد نعيد كتابة الفحص لطرح استثناء بدال ً من إعادة مؤرش خطأ ‪:‬‬ ‫•‬

‫‪// first check that data for same item‬‬


‫))(‪if (item1.isbn() != item2.isbn‬‬
‫;)"‪throw runtime_error("Data must refer to same ISBN‬‬
‫‪// if we're still here,‬‬ ‫‪ISBNs same‬‬
‫;‪cout << item1 + item2 << endl‬‬

‫في هذا الكود ‪ ،‬إذا كانت أرقام ‪ ISBN‬مختلفة ‪،‬‬ ‫•‬


‫فإننا نطرح تعبريًا يمثل كائنًا نوع خطأ_وقت_تشغيل ‪.runtime_error‬‬ ‫•‬
‫حيث يؤدي طرح استثناء إلى إنهاء الدالة الحالية ونقل التحكم إلى معالج يعرف كيفية معالجة هذا الخطأ‪.‬‬ ‫•‬

‫نوع خطأ_وقت_التشغيل هو أحد أنواع استثناءات املكتبة القياسية ويتم تعريفه في عنوان ‪.stdexcept‬‬
‫سيكون لدينا املزيد لنقوله عن هذه األنواع بعد قليل‪.‬‬ ‫•‬
‫يجب أن نهئي خطأ_وقت_تشغيل عن طريق إعطائه سلسلة نصية أو سلسلة أحرف على نمط اليس‪.‬‬ ‫•‬
‫توفر هذه السلسلة معلومات إضافية حول ماهية املشكلة‪.‬‬ ‫•‬

‫‪5.6.2. The try Block‬‬ ‫جرب_‬


‫‪ 5٫6٫2‬الكتلة ّ‬

‫جرب_ ‪ try‬هو كالتالي ‪:‬‬


‫الشكل العام لكتلة ّ‬

‫{ ‪try‬‬
‫‪program-statements‬‬
‫{ ) ‪} catch ( exception-declaration‬‬
‫‪handler-statements‬‬
‫{ ) ‪} catch ( exception-declaration‬‬
‫‪handler-statements‬‬
‫… ‪} //‬‬

‫جرب_ بكلمة ‪ try‬متبوعة بكتلة ‪ -‬كالعادة ‪ -‬عبارة عن سلسلة جمل محاطة بأقواس معقوفة‪.‬‬
‫تبدأ كتلة ّ‬ ‫•‬
‫جرب_ قائمة بجملة التقط_ ‪ catch‬أو أكرث‪.‬‬
‫تأتي بعد كتلة ّ‬ ‫•‬
‫تتكون التقط_ من ثالثة أجزاء‪:‬‬ ‫•‬
‫كلمة ‪ ، catch‬وإعالن كائن (قد يكون بدون اسم) بني قوسني (يشار إليه بإعالن االستثناء) ‪ ،‬وكتلة‪.‬‬ ‫•‬
‫عند تحديد التقاط ملعالجة استثناء ‪ ،‬يتم تنفيذ الكتلة املرتبطة‪.‬‬ ‫•‬
‫جرب_‪.‬‬
‫وبمجرد انتهاء التقط_ ‪ ،‬يستمر التنفيذ بجملة ما بعد الجملة التقط_ األخرية من كتلة ّ‬ ‫•‬

‫جرب_ ‪ try‬املنطق العادي للربنامج‪.‬‬


‫تشكل جمل الربنامج داخل ّ‬
‫• مثل أي كتل أخرى ‪ ،‬يمكن أن تحتوي على أي جملة يس‪ ، ++‬بما في ذلك اإلعالنات‪.‬‬
‫وكما هو حال أي كتلة ‪ ،‬املتغريات املعلن عنها داخل كتلة ‪ try‬ال يمكن الوصول إليها من خارج الكتلة ‪-‬‬ ‫•‬
‫وباﻷخص ‪ ،‬ال يمكن الوصول إليها من خالل الجملة التقط_ ‪.catch‬‬ ‫•‬

‫‪Writing a Handler‬‬ ‫كتابة معالج‬

‫في املثال السابق ‪ ،‬استخدمنا ‪ throw‬لتجنب جمع عنرصي مبيعات يمثالن كتابني مختلفني‪.‬‬
‫تخيلنا أن جزء الربنامج الذي جمع عنرصي مبيعات كان منفصالً عن الجزء الذي يتواصل مع املستخدم‪.‬‬ ‫•‬
‫قد يحتوي الجزء الذي يتفاعل مع املستخدم على رمز مشابه ملا يلي للتعامل مع االستثناء الذي تم طرحه‪:‬‬ ‫•‬

‫{ )‪while (cin >> item1 >> item2‬‬


‫{ ‪try‬‬
‫‪// execute code that will add two Sales_items‬‬
‫‪// if addition fails, code throws runtime_error exception‬‬
‫{ )‪} catch (runtime_error err‬‬
‫‪// remind user that ISBNs must match and prompt for another pair‬‬
‫;‪cout << err.what() << "\nTry Again? Enter y or n" << endl‬‬
‫;‪char c; cin >> c‬‬
‫)'‪if (!cin || c == 'n‬‬
‫;‪break‬‬ ‫‪// break out of while loop‬‬
‫}‬ ‫}‬

‫جرب_ ‪.try‬‬
‫املنطق العادي للربنامج الذي يدير التفاعل مع املستخدم يظهر داخل كتلة ّ‬ ‫•‬
‫استثناء من نوع ‪.runtime_error‬‬
‫ً‬ ‫جرب_ ألنه قد يطرح‬
‫يتم تغليف هذا الجزء من الربنامج داخل ّ‬ ‫•‬
‫جرب_ هذه على جملة التقط_ ‪ catch‬واحدة ‪ ،‬تعالج استثناءات نوع خطأ_وقت_تشغيل‪.‬‬
‫تحتوي كتلة ّ‬ ‫•‬
‫جرب_ في خطأ_وقت_تشغيل‪.‬‬
‫يتم تنفيذ الجمل في كتلة ما بعد التقط_ إذا تسبب الكود املوجود داخل كتلة ّ‬ ‫•‬
‫يعالج التقاطنا الخطأ عرب طباعة رسالة ومطالبة املستخدم باإلشارة إلى ما إذا كان سيستمر أم ال‪.‬‬ ‫•‬
‫إذا قام املستخدم بإدخال "‪ ، "n‬فسيتم تنفيذ الكرس ونخرج من ‪.while‬‬ ‫•‬
‫عدا ذلك ‪ ،‬ينخفض التنفيذ إلى قوس اإلغالق من ‪، while‬‬ ‫•‬
‫والذي سينقل التحكم مرة أخرى إلى رشط ‪ while‬للتكرار التالي‪.‬‬ ‫•‬

‫مطالبة املستخدم سيطبع اإلعادة من ()‪. err.what‬‬


‫نحن نعلم أن ‪ err‬خطأ من نوع خطأ_وقت_تشغيل ‪،‬‬ ‫•‬
‫لذلك يمكننا أن نستنتج أن ‪ what‬هي دالة عضو من فئة خطأ_وقت_تشغيل‪.‬‬ ‫•‬
‫تحدد كل فئة من فئات استثناءات املكتبة دالة عضو تسمى ‪.what‬‬ ‫•‬
‫ال تأخذ تلك الدوال أي وسيطات وتعيد سلسلة أحرف نمط اليس (على سبيل املثال ‪ ،‬مؤرش حرف ثابت)‪.‬‬ ‫•‬
‫يقوم عضو ‪ what‬في خطأ_وقت_تشغيل بإعادة نسخة من السلسلة املستخدمة لتهيئة كائن معني‪.‬‬ ‫•‬
‫استثناء ‪ ،‬فسيتم طباعة هذا اﻻلتقاط‬
‫ً‬ ‫إذا كان الكود املوضح في القسم السابق قد طرح‬ ‫•‬

‫‪Data must refer to same ISBN‬‬


‫‪Try Again? Enter y or n‬‬

‫يتم الخروج من الدوال خالل البحث عن معالج‬


‫‪Functions Are Exited during the Search for a Handler‬‬

‫استثناء‪.‬‬
‫ً‬ ‫جرب_ قبل مواجهة كود يطرح‬
‫في األنظمة املعقدة ‪ ،‬قد يمر مسار تنفيذ الربنامج عرب عدة كتل ّ‬
‫جرب_ ‪،‬‬
‫جرب_ دالة بها كتلة ّ‬
‫فعلى سبيل املثال ‪ ،‬قد تستدعي كتلة ّ‬ ‫•‬
‫جرب_ خاصة بها ‪ ،‬وهكذا‪.‬‬
‫وبدورها تستدعي أخرى بكتلة ّ‬ ‫•‬

‫البحث عن معالج يعد انعكاساً لسلسلة االستدعاء‪.‬‬


‫• عند طرح استثناء ‪ ،‬يتم البحث عن الدالة اليت طرحت االستثناء أوالً‪.‬‬
‫فإذا لم يتم العثور على التقاطها املطابق ‪ ،‬فسيتم إنهاء تلك الدالة‪.‬‬ ‫•‬
‫ويتم البحث بعد ذلك عن الدالة اليت استدعت الدالة اليت ألقت الطرح‪.‬‬ ‫•‬
‫أيضا‪.‬‬
‫إذا لم يتم العثور على معالج ‪ ،‬يتم إنهاء تلك الدالة ً‬ ‫•‬
‫ويتم البحث عن مستدعي تلك الدالة بعد ذلك ‪ ،‬وهكذا ‪...‬‬ ‫•‬
‫يتم عمل نسخة احتياطية من مسار التنفيذ حىت يتم العثور على نوع مناسب‪.‬‬ ‫•‬
‫إذا لم يتم العثور على التقط_ مناسب ‪ ،‬يتم نقل التنفيذ إلى دالة مكتبة إنها تسمى ‪.terminate‬‬ ‫•‬
‫يعتمد سلوك تلك الدالة على النظام لكنها تضمن إيقاف تنفيذ املزيد من الربنامج‪.‬‬ ‫•‬

‫جرب_ بنفس الطريقة ‪:‬‬


‫تتم معالجة االستثناءات اليت تحدث في الربامج اليت ال تعرف أي كتل ّ‬
‫جرب_ ‪ ،‬فال يمكن أن يكون هناك معالجات‪.‬‬
‫فبعد كل يشء ‪ ،‬إذا لم تكن هناك كتل ّ‬ ‫•‬
‫جرب_ وحدث استثناء ‪،‬‬
‫إذا كان الربنامج ال يحتوي على كتل ّ‬ ‫•‬
‫يتم استدعاء الدالة ‪ terminate‬ويتم إنهاء الربنامج‪.‬‬ ‫•‬

‫احذر ‪ :‬كتابة كود االستثناء اآلمن أمر صعب‬


‫‪Writing Exception Safe Code is Hard‬‬

‫من املهم إدراك أن االستثناءات تقطع التدفق الطبيعي للربنامج‪.‬‬ ‫•‬


‫ففي النقطة اليت يحدث فيها االستثناء ‪ ،‬ربما تم إجراء بعض حسابات طلبها املستدعي ‪،‬‬ ‫•‬
‫بينما ظلت أخرى من غري إجراء‪.‬‬ ‫•‬
‫بشكل عام ‪ ،‬قد يعين تجاوز جزء من الربنامج أن كائنًا ما تُرك في حالة غري صالحة أو غري كاملة ‪،‬‬ ‫•‬
‫أو مورداً ما لم يتم تحريره ‪ ،‬وما إلى ذلك‪.‬‬ ‫•‬
‫يُقال إن الربامج اليت "تنظف" بشكل صحيح أثناء معالجة االستثناءات آمنة لالستثناء‪.‬‬ ‫•‬
‫إﻻ أن كتابة كود االستثناء اآلمن أمر صعب بشكل عجيب ‪،‬‬ ‫•‬
‫ويعد (إلى حد كبري) خارج نطاق هذا الكتاب التمهيدي‪.‬‬ ‫•‬
‫تستخدم بعض الربامج االستثناءات ببساطة لتنهي الربنامج عند حدوث حالة استثناء‪.‬‬ ‫•‬
‫بشكل عام ال تقلق مثل هذه الربامج بشأن أمان االستثناءات‪.‬‬ ‫•‬
‫بشكل عام يجب أن تكون الربامج اليت تتعامل مع االستثناءات وتستمر في املعالجة ‪...‬‬ ‫•‬
‫على دراية مستمرة بما إذا كان قد يحدث استثناء ‪،‬‬ ‫•‬
‫وما يجب أن يفعله الربنامج لضمان صالحية الكائنات وعدم ترسب املوارد ‪،‬‬ ‫•‬
‫واستعادة الربنامج إلى الحالة املناسبة‪.‬‬ ‫•‬
‫سنشري أحيا ًنا إلى تقنيات شائعة بشكل خاص مستخدمة لتعزيز أمان االستثناءات‪.‬‬ ‫•‬
‫مع ذلك ‪ ،‬يجب على القراء الذين تتطلب برامجهم معالجة استثناء قوية أن يدركوا ‪...‬‬ ‫•‬
‫أن التقنيات اليت نغطيها غري كافية في حد ذاتها لتحقيق أمان االستثناءات‪.‬‬ ‫•‬

‫‪5.6.3. Standard Exceptions‬‬ ‫‪ 5٫6٫3‬اﻻستثناءات القياسية‬

‫تعر ف مكتبة يس‪ ++‬عدة فئات تستخدمها لإلبالغ عن مشكالت تمت مواجهتها في الدوال في املكتبة القياسية‪.‬‬
‫ّ‬
‫أيضا إلى استخدامها في الربامج اليت نكتبها‪.‬‬
‫تهدف فئات االستثناء هذه ً‬ ‫•‬
‫يتم تحديد هذه الفئات في أربعة عناوين‪:‬‬ ‫•‬
‫‪: The exception header - 1‬‬
‫يعرف النوع األكرث عمومية من فئة االستثناء املسماة ‪.exception‬‬ ‫•‬
‫حيث أنها تشري فقط إلى حدوث استثناء لكنها ال تقدم معلومات إضافية‪.‬‬ ‫•‬
‫‪: The stdexcept header - 2‬‬
‫تعرف العديد من فئات استثناءات األغراض العامة ‪ ،‬واليت تم رسدها في الجدول ‪.5.1‬‬ ‫•‬

‫الجدول ‪ .5.1‬فئات االستثناء القياسية املحددة في <‪>stdexcept‬‬

‫‪exception‬‬ ‫أكرث أنواع املشاكل عمومية‬

‫‪runtime_error‬‬ ‫املشكلة اليت يمكن اكتشافها فقط في وقت التشغيل‪.‬‬

‫‪range_error‬‬ ‫خطأ وقت التشغيل‪ :‬نتيجة تم إنشاؤها خارج نطاق القيم ذات املعىن‪.‬‬

‫‪overflow_error‬‬ ‫خطأ وقت التشغيل‪ :‬حساب تجاوز الحد األقىص‪.‬‬

‫‪underflow_error‬‬ ‫خطأ وقت التشغيل‪ :‬حساب تجاوز الحد األدنى‪.‬‬

‫‪logic_error‬‬ ‫خطأ في منطق الربنامج‪.‬‬

‫‪domain_error‬‬ ‫خطأ منطقي‪ :‬وسيطة ال توجد نتيجة لها‪.‬‬

‫‪invalid_argument‬‬ ‫خطأ منطقي‪ :‬وسيطة غري مناسبة‪.‬‬


‫‪length_error‬‬ ‫خطأ منطقي‪ :‬محاولة إنشاء كائن أكرب من الحجم األقىص لهذا النوع‪.‬‬

‫‪out_of_range‬‬ ‫خطأ منطقي‪ :‬استخدم قيمة خارج النطاق الصالح‪.‬‬

‫‪: The new header - 3‬‬


‫تعرف نوع االستثناء ‪ ، bad_alloc‬سنغطيه في الفصل ‪.١٢‬‬ ‫•‬
‫‪: The type_info header - 4‬‬
‫يعرف نوع استثناء ‪ ، bad_cast‬سنغطيه في الفصل ‪.١٩‬‬ ‫•‬

‫تحتوي فئات استثناءات املكتبة على عدد قليل من العمليات‪.‬‬


‫يمكننا إنشاء ونسخ وتخصيص كائنات من أي نوع من أنواع االستثناءات‪.‬‬ ‫•‬
‫كما يمكننا تهيئة استثناءات افرتاضية وكائنات ‪ bad_alloc‬و ‪ bad_cast‬؛‬ ‫•‬
‫ال يمكن توفري ُمهئي لكائنات من هذه األنواع من االستثناءات‪.‬‬ ‫•‬

‫أنواع االستثناءات األخرى لها سلوك معاكس‪:‬‬


‫يمكننا تهيئة هذه الكائنات إما على سلسلة أو سلسلة من نمط لغة اليس ‪،‬‬ ‫•‬
‫افرتاضيا‪.‬‬
‫ً‬ ‫لكن ال يمكننا تهيئتها‬ ‫•‬
‫عندما نقوم بإنشاء كائنات من أي من أنواع االستثناءات األخرى هذه ‪ ،‬يجب أن نوفر ُمهيًئ ا‪.‬‬ ‫•‬
‫يتم استخدام هذا املُهئي لتوفري معلومات إضافية حول الخطأ الذي حدث‪.‬‬ ‫•‬

‫تعرف أنواع االستثناءات عملية واحدة تسمى ‪.what‬‬


‫ال تأخذ هذه الدالة أي وسيطات وتقوم بإعادة مؤرش حرف ثابت يشري إلى سلسلة أحرف نمط اليس‪.‬‬ ‫•‬
‫الغرض من سلسلة أحرف نمط اليس هذه هو توفري نوع من الوصف النيص لالستثناء الذي تم طرحه‪.‬‬ ‫•‬
‫تعتمد محتويات سلسلة نمط اليس املعادة على نوع كائن االستثناء‪.‬‬ ‫•‬
‫بالنسبة لألنواع اليت تأخذ ُمهئي سلسلة ‪ ،‬تقوم الدالة ‪ what‬بإعادة تلك السلسلة‪.‬‬ ‫•‬
‫وبالنسبة لألنواع األخرى ‪ ،‬تختلف قيمة السلسلة اليت يتم إعادتها حسب املرتجم‪.‬‬ ‫•‬

‫قسم التمارين ‪5.6.3‬‬


‫التمرين ‪:5.23‬‬
‫برنامج ا يقرأ عددين صحيحني من املدخالت القياسية ويطبع نتيجة قسمة الرقم األول على الثاني‪.‬‬
‫ً‬ ‫اكتب‬

‫التمرين ‪:5.24‬‬
‫‪ -‬راجع برنامجك لطرح استثناء إذا كان الرقم الثاني صفرًا‪.‬‬
‫‪ -‬اخترب برنامجك بمدخالت صفرية ملعرفة ما يحدث على نظامك إذا لم يتم اكتشاف استثناءك‪.‬‬

‫التمرين ‪:5.25‬‬
‫‪ -‬قم بمراجعة برنامجك من التمرين السابق الستخدام كتلة ‪ try‬اللتقاط االستثناء‪.‬‬
‫‪ -‬يجب أن تطبع جملة ‪ catch‬رسالة إلى املستخدم وتطلب منه توفري رقم جديد وتكرار الكود داخل ‪.try‬‬
‫ملخــــــــــص الفصــــــــــل‬
‫‪Chapter Summary‬‬

‫توفر يس‪ ++‬عد ًدا محدو ًدا من الجمل‪ .‬تؤثر معظمها على تدفق التحكم داخل الربنامج‪:‬‬
‫الجمل طالـما_ ‪ while‬و ﻷجل_ ‪ for‬و افعل_طالـما_ ‪ do while‬توفر التنفيذ التكراري‪.‬‬ ‫•‬
‫وبدل_ ‪ switch‬التنفيذ املرشوط‪.‬‬
‫توفر الجملتان إذا_ ‪ّ if‬‬ ‫•‬
‫توفر الجملة استمر_ ‪ continue‬إيقاف التكرار الحالي للحلقة‪.‬‬ ‫•‬
‫بدل_‪.‬‬
‫توفر الجملة اكرس_ ‪ break‬خروجاً من حلقة أو جملة ّ‬ ‫•‬
‫توفر الجملة اذهب_إلى ‪ goto‬نقل عنرص التحكم إلى جملة مسماة‪.‬‬ ‫•‬
‫جرب_‬
‫جرب_ ‪ try‬و التقط_ ‪ catch‬تعريفاً لكتلة ّ‬ ‫توفر الجمل ّ‬ ‫•‬
‫وتتضمن سلسلة من جمل قد تؤدي إلى استثناء‪.‬‬ ‫•‬
‫وتهدف الجملة (الجمل) التقط_ ‪ catch‬إلى معالجة استثناء (ــات) قد تطرحها األكواد املرفقة‪.‬‬ ‫•‬
‫الجملة طرح التعبري ‪، throw expression‬‬ ‫•‬
‫تخرج من كتلة من اﻷكواد ‪ ،‬وتحول التحكم إلى جملة التقط_ ‪ catch‬مرتبطة‪.‬‬ ‫•‬
‫الجملة ِ‬
‫أعد ‪ ، return‬توقف تنفيذ دالة‪.‬‬ ‫•‬
‫أعد ‪ return‬في الفصل السادس‪).‬‬ ‫(سنغطي جمل ِ‬ ‫•‬

‫إضافة إلى ذلك ‪،‬‬


‫هناك جمل تعبري وجمل إعالن‪.‬‬ ‫•‬
‫تؤدي جمل التعبري إلى تقييم تعبري موضوعياً‪.‬‬ ‫•‬
‫وقد سبق وصف اإلعالنات وتعريفات املتغريات في الفصل الثاني‪.‬‬ ‫•‬
‫مصطلحــــــــــات معــــــــــرفة‬
‫‪Defined Terms‬‬

‫كتلة‪ :‬تسلسل من جمل صفرية أو أكرث محاطة بأقواس معقوفة‪.‬‬


‫‪block‬‬
‫الكتلة عبارة عن جملة ‪ ،‬لذلك يمكن أن تظهر في أي مكان يُتوقع فيه جملة‪.‬‬

‫بدل_‪.‬‬‫جملة اكرس_‪ :‬ينهي أقرب حلقة أو جملة ّ‬


‫‪break statement‬‬
‫بدل_‪.‬‬
‫ينقل التنفيذ إلى أول جملة تلي حلقة منتهية أو ّ‬

‫بدل_‪.‬‬
‫تسمية الحالة‪ :‬تعبري ثابت يتبع كلمة ‪ case‬األساسية في جملة ّ‬
‫‪case label‬‬
‫بدل_ نفس القيمة‪.‬‬
‫ال يجوز أن يكون لتسميات حالة في نفس جملة ّ‬

‫جملة التقط_ ‪ :‬الكلمة األساسية ‪ catch‬وإعالن استثناء بني قوسني وكتلة من الجمل‪.‬‬
‫‪catch clause‬‬ ‫يقوم الكود املوجود داخل جملة التقط_ بكل ما هو رضوري للتعامل مع استثناء من النوع املحدد‬
‫في إعالن االستثناء الخاص به‪.‬‬

‫‪compound‬‬
‫جملة مركبة ‪ :‬مرادف للكتلة‪.‬‬
‫‪statement‬‬

‫جملة استمر_ ‪ :‬تنهي التكرار الحالي ألقرب حلقة متضمنة‪.‬‬


‫‪continue‬‬
‫ينقل تنفيذ رشط حلقة في ‪ while‬أو ‪ ، do while‬إلى التكرار التالي في ‪ for‬النطاق‪ ،‬أو‬
‫‪statement‬‬
‫إلى التعبري في رأس حلقة ‪ for‬التقليدية‪.‬‬

‫متدلية (وإﻻ_) ‪ :‬تستخدم لإلشارة إلى مشكلة كيفية معالجة جمل إذا_ املتداخلة اليت يوجد فيها‬
‫‪ ifs‬أكرث من ‪.else‬‬
‫‪dangling else‬‬ ‫دائما إقران ‪ else‬بأقرب ما سبق مما ال مثيل له‪.‬‬
‫ً‬ ‫في يس‪ ، ++‬يتم‬
‫الحظ أنه يمكن استخدام األقواس املتعرجة إلخفاء إذا_ الداخلي بشكل فعال إذا كان األمر كذلك‬
‫بحيث يمكن للمربمج التحكم في ما إذا كان يجب أن يتطابق مع ‪.else‬‬

‫‪default label‬‬ ‫بدل_‪.‬‬


‫التسمية افرتايض ‪ :‬تسمية حالة تتطابق مع أي قيمة غري متطابقة يتم حسابها في تعبري ّ‬

‫‪do while‬‬ ‫جملة افعل_طالـما_ ‪ :‬مثل جملة طالـما_‪ ،‬فيما عدا أنه يتم اختبار الرشط في نهاية الحلقة وليس‬
‫‪statement‬‬ ‫في بدايتها‪ .‬يتم تنفيذ الجملة داخل افعل_طالـما_ مرة واحدة على األقل‪.‬‬
‫‪exception‬‬ ‫فئات االستثناء ‪ :‬مجموعة فئات تحددها املكتبة القياسية الستخدامها لتمثيل األخطاء‪.‬‬
‫‪classes‬‬ ‫يرسد الجدول ‪ 5.1‬فئات استثناءات األغراض العامة‪.‬‬

‫‪exception‬‬ ‫إعالن االستثناء ‪ :‬إعالن في جملة التقط_ ‪ .catch‬يعرف هذا اإلعالن نوع استثناءات يمكن‬
‫‪declaration‬‬ ‫اللتقط_ معالجتها‪.‬‬

‫‪exception‬‬ ‫معالج االستثناء ‪ :‬كود يتعامل مع استثناء مرفوع في جزء آخر من الربنامج‪.‬‬
‫‪handler‬‬ ‫مرادف ملصطلح التقط_‪.‬‬

‫‪exception safe‬‬ ‫يستخدم مصطلح االستثناء اآلمن لوصف برامج تترصف بشكل صحيح عند طرح استثناءات‪.‬‬

‫‪expression‬‬
‫جملة تعبريية متبوعة بفاصلة منقوطة‪ .‬تؤدي جملة التعبري إلى تقييم التعبري‪.‬‬
‫‪statement‬‬

‫‪flow of control‬‬ ‫تدفق التحكم‪ :‬مسار التنفيذ من خالل الربنامج‪.‬‬

‫جملة ﻷجل_ ‪ :‬تكرار يوفر التنفيذ التكراري‪.‬‬


‫‪for statement‬‬
‫تُستخدم عاد ًة للدخول في حاوية أو لتكرار عملية حسابية لعدد معني من املرات‪.‬‬

‫جملة اذهب_إلى ‪ :‬تتسبب في نقل غري مرشوط للتحكم إلى جملة معنونة محددة في مكان آخر‬
‫‪goto statement‬‬
‫في نفس الدالة‪ goto .‬تشوش على تدفق التحكم داخل الربنامج وينبغي تجنبها‪.‬‬

‫‪if else‬‬ ‫جملة إذا_وإﻻ_ ‪" :‬تنفيذ مرشوط" للشفرة بعد "‪ if‬أو بعد ‪، "else‬‬
‫‪statement‬‬ ‫اعتما ًد ا على القيمة الحقيقية للرشط‪.‬‬

‫صحيحا ‪،‬‬
‫ً‬ ‫بناء على قيمة رشط محدد‪ .‬إن كان الرشط‬
‫ً‬ ‫جملة إذا_ ‪ :‬تنفيذ مرشوط‬
‫‪if statement‬‬
‫فسيتم تنفيذ بنية إذا_‪ .‬إذا لم يكن كذلك ‪ ،‬فإن التحكم يتدفق إلى جملة تأتي بعد إذا_‪.‬‬

‫‪labeled‬‬ ‫معرف متبوع بنقطتني‪.‬‬


‫جملة مسماة ‪ :‬جملة مسبوقة بتسمية‪ .‬التسمية هي ّ‬
‫‪statement‬‬ ‫معرفات التسمية مستقلة عن االستخدامات األخرى لنفس املعرف‪.‬‬
‫‪null statement‬‬ ‫جملة ﻻغية ‪ :‬جملة خالية‪ .‬يشار إليها بفاصلة منقوطة واحدة‪.‬‬

‫رفع‪ :‬غالبا ما يستخدم كمرادف للطرح‪.‬‬


‫‪raise‬‬
‫يتحدث مربمجو يس‪ ++‬عن "طرح" أو "إثارة" استثناء بالتبادل‪.‬‬

‫‪range for‬‬
‫جملة ﻷجل_ للنطاق ‪ :‬جملة تتكرر عرب تسلسل‪.‬‬
‫‪statement‬‬

‫بد ل_ ‪ :‬جملة رشطية تبدأ بتقييم التعبري الذي يتبع الكلمة ‪.switch‬‬‫جملة ّ‬
‫‪switch‬‬ ‫ينتقل عنرص التحكم إلى الجملة املسماة بتسمية حالة تطابق قيمة التعبري‪.‬‬
‫‪statement‬‬ ‫إذا لم يكن هناك تسمية مطابقة ‪ ،‬فسيستمر التنفيذ في التسمية "افرتايض" ‪ ،‬إن وجدت ‪،‬‬
‫بدل_ إن لم توجد تسمية "افرتايض”‪.‬‬ ‫أو يخرج من ّ‬

‫إنهاء وظيفة املكتبة اليت يتم استدعاؤها في حالة عدم اكتشاف استثناء‪.‬‬
‫‪terminate‬‬
‫إلنهاء أو إحباط الربنامج‪.‬‬

‫‪throw‬‬ ‫طرح تعبري ‪ :‬يقطع مسار التنفيذ الحالي‪ .‬يقوم كل طرح بطرح كائن وتنقل التحكم إلى أقرب‬
‫‪expression‬‬ ‫جملة التقط_ ‪ catch‬متضمنة يمكنها التعامل مع نوع االستثناء الذي تم طرحه‪.‬‬

‫جرب_ ‪ :‬كتلة محاطة بالكلمة األساسية ‪ try‬وواحد أو أكرث من جمل التقط_‪.‬‬ ‫كتلة ّ‬
‫استثناء وكان أحد جمل التقط_ يتطابق مع نوعه‪،‬‬
‫ً‬ ‫جرب‬‫إذا أثار الكود املوجود داخل كتلة ّ‬
‫‪try block‬‬
‫فسيتم معالجته بواسطة التقط_ هذا‪ .‬عدا ذلك ‪،‬‬
‫جرب متضمنة أو بإنهاء الربنامج‪.‬‬
‫يتم التعامل مع االستثناء بواسطة كتلة ّ‬

‫جملة طالـما_ ‪ :‬تكرار ينفذ الجملة الهدف طاملا أن الرشط املحدد صحيح‪.‬‬
‫‪while statement‬‬
‫يتم تنفيذ الجملة صفر أو أكرث من املرات ‪ ،‬اعتما ًدا على صحة الرشط‪.‬‬

You might also like