- الرئسية
- اتصل بنا
- اخبار خفيفة
- جديد المواقع
- العاب الفيديو
- تعليم برمجة
- موبايلات
- ستلايت
- خدع ومهارات
- جديد البرامج
- اشهار مواقع
دروس في سي بلس بلس ++C - مجال الرؤيا على مستوى الكتلة البرمجية الخاصة Block Scope
2007-09-26تعرف الكتلة البرمجية الخاصة على أنها سلسلة من التعليمات البرمجية المكتوبة بلغة C++ والتي تنحصر بين قوسين البداية { والنهاية } ويطلق عليها اسم التعليمة المركبة. وقد تكون هذه التعليمة تابعة لجملة الشرط if أو جمل التحكم مثلwhile do-whil switch كما أنها قد تكون كتلة برمجية مستقلة وغير تابعة لأي جملة تحكم تكتب داخل الاقتران الرئيسي main بهدف تنسيق النص البرمجي وتقسيمه لأجزاء صغيرة أو أنها تعليمة تحكم برمجي خطية تقع ضمن سطر واحد مثل جملة التكرار for إذ يمكننا كتابة حلقة تكرار متكاملة في أركانها الأساسية ضمن سطر واحد
وعند التصريح عن متغير جديد داخل أي كتلة برمجية فان مدى رؤية ذلك المتغير يكون محصور داخل الكتلة ولا يمكن إن نستخدم المتغير خارج الكتلة بأي حال من الأحوال طالما إننا لا نتعامل مع العنونة غير المباشرة Reference أو المؤشرات Pointers والتي سنتعرف عليها في الدروس اللاحقة.
في الأمثلة التالية سنعالج بعض الحالات والمفاهيم الجديدة المتعلقة بالكتلة البرمجية الخاصة. وفي مثالنا الأول سنصرح عن المتغير B من النوع عدد صحيح int داخل حلقة التحكم while والتي تعتبر كتلة برمجية خاصة ثم سنحاول استخدام نفس المتغير بتعليمة طباعة cout خارج مدى حلقة التكرار while
#include<iostream.h> void main() {//بداية البرنامج int X=10; int Y=1; while(Y<=X) {//بداية حلقة التكرار int B=8;//المتغير المحلي ++y; }//نهاية حلقة التكرار cout<<B; }//نهاية البرنامج
كما لوحظ في البرنامج السابق فان عملية التصريح عن المتغير B تمت داخل كتلة حلقة التكرار وبذلك سيكون مجال رؤية وتأثر المتغير B مغلقا داخل نفس الحلقة, وعند تنفيذ البرنامج سيعرض مترجم C++ على تعليمة الطباعة كونها تتعامل مع المتغير B ورسالة الاعتراض ستكون على النحو التالي: error C2065: "B" : undeclared identifier
والمعنى البرمجي للرسالة السابقة أن المترجم وجد متغير غير مصرح عنه (معرف) ولا يمكن تنفيذ تعليمة الطباعة. ولكن البعض منا سيقول كيف يكون المتغير B غير معرف للمترجم علما بأنه تم التصريح عنه ودعمه بالقيمة 8 قبل تعليمة الطباعة؟ الجواب على هذا التساؤل بسيط حيث إن علمية التصريح وإسناد القيمة للمتغير تمت داخل كتلة خاصة وبذلك حصرنا مجال التعامل مع المتغير داخل الكتلة البرمجية الخاصة, وإذا أردت تنفيذ تعليمة الطباعة بصورة صحيحة فعليك إن تدخلها داخل مجال الكتلة الخاصة " حلقة" while أو إن تعرف المتغير B على انه متغير عام أو شامل Global
مثال2: سنصرح في مثالنا هذا عن المتغير B مرتين, في المرة الأولى على المستوى العام ليكون مجاله كامل نطاق البرنامج وفي المرة الثانية داخل كتلة برمجية خاصة لنرى ما الذي سيحدث عند التعامل معه في الحالتين:
#include<iostream.h> int B=8;//Bالمتغير العام void main() {//بداية البرنامج for(int i=1;i<=5;i++) {//بداية حلقة التكرار int B=2;//المتغير المحلي cout<<B<<endl; }//نهاية حلقة التكرار cout<<B; }//نهاية البرنامج
كما تلاحظ,يوجد لدينا متغيرين يحملان نفس الاسم الأول معرف في بداية البرنامج وخارج الاقتران الرئيسي main ويحمل القيمة 8. أما الثاني فهو معرف داخل كتلة التكرار for ويحمل القيمة 2 وعند تنفيذ البرنامج ستجد ن تعليمة الطباعة الأولى والتي تقع ضمن مجال حلقة التكرار ستقوم بطباعة القيمة 21 مكررة بعدد مرات تنفيذ حلقة التكرار ولن تتغير القيمة العائدة للمتغير المحلي B=2
أما تعليمة الطباعة الثانية والتي تقع خارج مجال حلقة التكرار فستطبع القيمة 8 العائدة للمتغير B العام. ويفسر ما سبق بان المتغير العام B=8 حجب عن الكتلة البرمجية الخاصة " حلقة" for كونها تحتوي تصريح عن متغير محلي بنفس الاسم B=2 ولذلك تستطيع حلقة التكرار التعامل مع المتغير العام B=8 أما تعليمة الطباعة القانية فهي خارج الكتلة الخاصة لحلقة التكرار وسنتعامل بصورة مباشرة مع المتغير العام B=8
مثال3 : لنتعرف في المثال التالي على أسلوب جديد إلا وهو فريق تسد الذي يستخدم في تقسيم البرنامج لعدة كتل خاصة عبر تابعة لأي جملة تحكم أو حلقة تكرار أو اقتران فرعي.
#include<iostream.h> int x=1;//متغير عام void main() {//بداية البرنامج {//بداية كتلة خاصة 1 int x=10; cout<<x<<endl; }//نهاية الكتلة الخاصة 1 {//بداية كتلة خاصة2 int x=5; cout<<x<<endl; }//نهاية الكتلة الخاصة 2 cout<<x; }//نهاية البرنامج
البرنامج السابق يوضح فكرة تقسيم البرنامج لعدة كتلة برمجية خاصة مستقلة وهنا تجدر الإشارة إلى إن هذا الأسلوب يشبه لحد كبير فكرة الإجراءات الفرعية والهدف منه هو تنسيق البرنامج وسهولة السيطرة عليه فبدل من إن يكون البرنامج كتلة برمجية واحدة يمكنك تقسيمه لعدة كتلة بما يعرف بمبدأ فرق تسد Divide and Conquer والفائدة من هذا الأسلوب هي إمكانية التعديل على كتلة برمجية صغيرة بدلا من محاولة التعديل على البرنامج بأكمله. ولكن عليك الانتباه هنا إلى مدى رؤية المتغيرات ومعرفة مجال كل كتغير.. فكل ما ينطبق على مجال الرؤيا داخل الإجراءات الفرعية ينطبق على الكتلة البرمجية الخاصة. وستلاحظ عند تنفيذ البرنامج السابق إن المتغير X معرف على ثلاثة مستويات وهي:
- على المستوى العام.
- على مستوى الكتلة الخاصة الأولى X=10
- على مستوى الكتلة الخاصة الثانية X=5
مثال 4: ادرس المثال التالي وحاول معرفة أي المغيرات يعامل على انه محلي وأيها يعامل على أنه متغير عام وهل يوجد أي خطا في البرنامج؟
#include<iostream.h> int X=5; void main() { while(X<6) { int X=1; ++X; cout<<X<<endl; } }
عند تنفيذ البرنامج ستجد إننا وقعنا في خطا برمجي من شانه إن يدخل البرنامج في حلقة تكرار غير منهية والسبب في ذلك يعود لعدم التميز بين المتغير العام والمتغير المحلي, فبعد إن عرفنا المتغير X=5 على صورة متغير عام في بداية البرنامج استخدمناه كشرط توقف لحلقة التكرار while ثم صرحنا داخل حلقة التكرار عن متغير جديد محلي بنفس الاسم ولكن بقيمة مختلفة X=1 ثم عملنا على زيادة قيمة X بواحد داخل حلقة التكرار على أمل إن تصل القيمة لـ 6 وتنتهي بذلك الحلقة.
والسبب في هذا الخطأ أم المغير المستخدم كشرط للحلقة هو المتغير العام X=5 أما المتغير الذي تجرب عليه عملية الزيادة فهو المغير المحلي الذي يقع في مجال الكتلة الخاصة التابعة لحلقة while وكون إن المتغير العام والمتغير المحلي يحملان نفس الاسم فمن المؤكد انه سيتم حجب المتغير العام عن كتلة الحلقة وعن عملية الزيادة, أما داخل تعليمة شرط توقف الحلقة التي لا تقع ضمن كتلة حلقة التكرار فالمتغير هنا المتغير العام ولن تجرب عليه أي عملية زيادة ولذلك سيستمر البرنامج في تكرار تعليمة الطباعة إلى ما لا نهاية.
وفي الختام, نؤكد على ضرورة إتقان مجالات الرؤيا حتى لا تقع في أخطاء برمجية من الصعب اكتشافها أو حتى حلها.



