قواعد مجالات الرؤيـة:
بعــد أن انتهينـا مـن أساسـيات التوابـع فسنمضــي قـدماً فـي الحـديث عــن
المتغيرات ولكن هذه المرة من وجهـة نظر التوابع ؛ لسنا هــنا بصـدد الحـديث
عـن الانـواع الداخلية لأنمـاط البيانـات مثـل int .. وغيرهـا ، بـل حسـب قواعـد
مجالات الرؤيـة لدى هذه الدالة ؛ عـموماً فهــناك ثلاثــة أنــواع للمتغيـرات مـن
وجهـة نظر التوابع هـي كالتالي:
1- المتغيرات الخاصـة:
2- المتغيرات العامـة:
3- المتغيرات الساكنـة:
وسنأتي على كل منها.
المتغيرات الخاصـة Variables Local :
هل تتذكر كلامنا السابق في الفصول الأولى من الكتاب حــول الكتـل ، التـابع
في الحقيقـة ليس إلا كتلة وبالتالي فحينما تقوم بكتابة هـذا القـوس { فـذلك
يعـني أنك قمت بتدمير جميع المتغيـرات التـي تـم الإعـلان عــنها بعــد قـوس
الفتح } ، وكما أن الأمر ينطبق علـى توابـع ودوال التكـرار فـالأمر نفســه هــنا
بالنسبــة للتوابــع ، إذا قمـت بالتصــريح عــن أي متغيــر فـي أي تــابع فحينمــا
ينتهي تنفيذ هذا التابع فإن جميع متغيراتـه تكون انتهـت معــه أيضـاً وبالتـالي
فحينمــا تقــوم بإســتدعاء نفــس التــابع مــرة أخـــرى فســيتعامل البرنــامج مــع
المتغيــرات وكأنهــا متغيــرات جديــدة لــم تــتم ترجمتهــا ســابقاً ، ومثــال الكـــود
السابق هـو مثال نموذجي لما نتكلم عـنه.
المتغيرات العامة Variables Global :
بعـكس النوع السابق فإن المتغيرات العامـة هـي متغيرات يتم الإعـلان عــنها
خارج أي تابع آخر ، وجميع توابع البرنامج بإمكانها إستخدامها والتعامل معها ،
وحتى نفهـم هذا النـوع بشكل أفضـل ، فدعــنا نفـرض أن لـدينا تـابعين اثنـين
هـما:
Void test1( )
{
int g=1,k;
}
void test2()
{
int b, g=2;
}
كما ترى فإن التـابعين الاثنـين test1 و test2 يقومـان بـالإعلان عــن متغيـرين
اثنين إلا أن الأمر الذي نـود التأكيد عليه هـو أن أحد التابعين لا يستطيع رؤيــة
متغيـرات التـابع الآخـر وبالتـالي فـلا يسـتطيع التعامـل معهـا لأنـه لا يسـتطيع
رؤيتها ، وكما نرى فإن للتابعين الاثنين متغيرين اثنين لهـما نفس الاسم وهــو
g ولكن ليس لهـما نفس مكان الذاكرة وليس لهـما نفـس القيمــة فـالمتغير g
له نسختين ، كل تابع له نسخـة منهــما ، الآن لـو قمنـا بكتابـة تعريـف لمتغيـر
جـــديد خــارج أي كتلــة ســواء for أو while أو أي تــابع آخــر فحينهــا ســتكون
متغيرات عامـة أي أن جميع الكتـل تسـتطيع رؤيتهـا ، وبالتـالي التعامـل معهـا
وكأنها متغيرات خاصـة ، إلا أن الفـرق هــنا هــو أن أي تغييـر فـي قيمــة هـذا
المتغير من أي تابع في البرنـامج فـإن التغييـر سـيبقى حتـى انتهـاء البرنـامج
بشكل نهائي.
المتغيرات الساكنـة Variables Static:
المتغيرات الساكنـة تأخذ مزايا النـوعين السابقين فهـي أولاً نفـس المتغيـرات
الخاصـة أي أن هـناك تابع وحيد يستطيع رؤيتها هــو التـابع الـذي تـم الإعـلان
عـنها داخله وثانياً أنها لا تنتهـي أو تمـوت حينمـا يـتم انتهـاء تنفيـذ التـابع فـي
المرة الواحدة فمثلاً لو قمنا بكتابة متغير ساكن ضمن تعريف تابع ما ، فحينمـا
يتم تنفيذ هـذا التـابع وقـام فرضـاً بزيـادة قيمــة المتغيـر السـاكن إلـى 2 ، ثـم
انتهى تنفيـذ هـذا التـابع فـإن هـذا المتغيـر السـاكن لا ينتهـي معــه وسـيظل
محتفظاً بالقيمـة 2 حتى يتم استدعاء التـابع مـرة أخــرى وسـيجد أن المتغيـر
الساكن أصبح كما هـو عليه في المرة السابقــة ولـن يعــود إلـى القيمــة 0 ؛
باختصار بإمكان تشبيه المتغيرات الساكنـة على أنها متغيرات خاصـة لا تموت
حتى بانتهاء تنفيذ التابع.
وعـموماً فإن التصريح عـن هذه المتغيرات يتم بالكلمـة المفتاحيـة static كمـا
يرى من هذا السطر:
static int number;
مثال عـملي:
سنقوم الآن بكتابـة تـابع يقـوم بمضاعفــة العــدد الوسـيط إلـى ضعفــه ومـن
الممكن أن يكون هذا التابع بدايـة لك لكي تقوم بإنشاء برنامج حاسبـة آليـة:
CODE
1. #include <iostream>
2. using namespace std;
3.
4. double binate (float b)
5. {
6. return b*b;
7. }
8.
9. void main()
10. {
11. float a;
12. cin>> a;
13. double m=binate(a);
14. cout << m << endl;
15. }
تـم تعريـف التـابع ( )binate فـي الأسـطر مـن 4 إلـى 7 حيـث يسـتقبل عــدد
وسيط واحد وهـو b من النـوع float ويقوم بضربه في نفسـه وإعـادة القيمــة
إلى التابع main .
سنتقدم الآن أكثر وسنقوم بكتابة برنــامج أكثـر عـملانيــة وأكثـر فائـدة وهـذه
المرة فسنستخدم المؤشرات والمتغيرات العامـة كذلك.
البرنامج الذي نحن بصدده عبارة عـن قواسم عـدد ، المستخــدم يـدخل عــدد
ما ثم يقوم البرنامج بإنشاء مصفوفـة ثم إسناد كل قاسم مـن هـذه القواسـم
إلى عـنصر من عـناصر المصفوفـة ؛ إليك كـود البرنامج:
CODE
كـود يقوم بحساب قواسم أي عـدد // .1
2. #include <iostream>
3. using namespace std;
4.
المتغيرات العــامـة //;divides* float .5
6. int times;
7. //////////////////////////////
النمــاذج المصغرة// ;(x int)HowTimes void .8
9. void pointer();
10. void TheMain(int x);
11. ////////////////////////////
التابع الرئيسي // ()main void .12
13. {
14. int a;
15. cin>> a;
16. TheMain(a);
17. for(int i=0;i<times;i++)
18. cout <<divides[i]<< endl;
19. cout << "The Many Of How Number Divides Is:\t"
20. <<times
21. <<endl;
22. }
23. ///////////////////////
24. void pointer( )
25. {
26. divides=new float[times];
27. }
28. /////////////////////////
29. void HowTimes(int x)
30. {
31. for (int i=1;i<=x;i++)
32. if(x%i==0) ++times;
33. }
34. /////////////////////
35. TheMain(int x)
36. {
37. HowTimes(x);
38. pointer();
39. for (int i=1,int j=0;j<times,i<=x;i++)
40. if(x%i==0){
41. divides[j]=i;
42. j++;}
43. }
لقد احتـوى هذا المثال على مواضيع كثيرة سنقوم بمناقشتها حالاً.
فكرة البرنامج:
لهذا البرنامج متغيران عامين رئيسين هـما:
- المتغير العام times : وهذا المتغير يحسب عـدد الأعــداد التـي تقسـم
العـدد المراد إيجاد قواسمـه.
- المؤشر divides: بعـد أن يحسب البرنـامج عــدد قواسـم العــدد فإنــه
يقوم بحجز مصفوفة عدد عـناصرها يساوي قيمــة المتغيـر times ، ثـم
يقوم البرنامج يتخـزين قواسم العـدد في المصفوفـة divides.
أيضاً فإن لهذا البرنامج ثلاث توابع وهـي كالتالي:
1- التـابع (x int)HowTimes : يسـتقبل هــذا العــدد الــرقم الـذي أدخلــه
المستخـدم ويقوم بحساب عـدد قواسمـه ويخزنهـا فـي المتغيـر العـام
.times
2- التـابع ( )pointer : يقـوم هـذا التـابع بحجـز الـذاكرة للمؤشـر divides
وهـو يحجز له مصفوفـة حتى يخـزن فيهـا جميـع قواسـم العــدد الـذي
أدخله المستخـدم.
3- التابع (x int)TheMain : يعتبر هـذا التـابع هــو أهــم تـابع حيـث يقـوم
بإســتقبال الــرقم الــذي أدخلــه المستخـــدم ويــتحكم فــي التــابعين
السابقين ويحسب قواسم العـدد ويخزنها في مصفوفـة divides.
هذه هـي فكرة هذا البرنامج بشكل عام ولكن هــناك بعـض النقـاط الجــديدة
التي يجب التوقف عـندها وشرحها للقارئ العـزيز
بعــد أن انتهينـا مـن أساسـيات التوابـع فسنمضــي قـدماً فـي الحـديث عــن
المتغيرات ولكن هذه المرة من وجهـة نظر التوابع ؛ لسنا هــنا بصـدد الحـديث
عـن الانـواع الداخلية لأنمـاط البيانـات مثـل int .. وغيرهـا ، بـل حسـب قواعـد
مجالات الرؤيـة لدى هذه الدالة ؛ عـموماً فهــناك ثلاثــة أنــواع للمتغيـرات مـن
وجهـة نظر التوابع هـي كالتالي:
1- المتغيرات الخاصـة:
2- المتغيرات العامـة:
3- المتغيرات الساكنـة:
وسنأتي على كل منها.
المتغيرات الخاصـة Variables Local :
هل تتذكر كلامنا السابق في الفصول الأولى من الكتاب حــول الكتـل ، التـابع
في الحقيقـة ليس إلا كتلة وبالتالي فحينما تقوم بكتابة هـذا القـوس { فـذلك
يعـني أنك قمت بتدمير جميع المتغيـرات التـي تـم الإعـلان عــنها بعــد قـوس
الفتح } ، وكما أن الأمر ينطبق علـى توابـع ودوال التكـرار فـالأمر نفســه هــنا
بالنسبــة للتوابــع ، إذا قمـت بالتصــريح عــن أي متغيــر فـي أي تــابع فحينمــا
ينتهي تنفيذ هذا التابع فإن جميع متغيراتـه تكون انتهـت معــه أيضـاً وبالتـالي
فحينمــا تقــوم بإســتدعاء نفــس التــابع مــرة أخـــرى فســيتعامل البرنــامج مــع
المتغيــرات وكأنهــا متغيــرات جديــدة لــم تــتم ترجمتهــا ســابقاً ، ومثــال الكـــود
السابق هـو مثال نموذجي لما نتكلم عـنه.
المتغيرات العامة Variables Global :
بعـكس النوع السابق فإن المتغيرات العامـة هـي متغيرات يتم الإعـلان عــنها
خارج أي تابع آخر ، وجميع توابع البرنامج بإمكانها إستخدامها والتعامل معها ،
وحتى نفهـم هذا النـوع بشكل أفضـل ، فدعــنا نفـرض أن لـدينا تـابعين اثنـين
هـما:
Void test1( )
{
int g=1,k;
}
void test2()
{
int b, g=2;
}
كما ترى فإن التـابعين الاثنـين test1 و test2 يقومـان بـالإعلان عــن متغيـرين
اثنين إلا أن الأمر الذي نـود التأكيد عليه هـو أن أحد التابعين لا يستطيع رؤيــة
متغيـرات التـابع الآخـر وبالتـالي فـلا يسـتطيع التعامـل معهـا لأنـه لا يسـتطيع
رؤيتها ، وكما نرى فإن للتابعين الاثنين متغيرين اثنين لهـما نفس الاسم وهــو
g ولكن ليس لهـما نفس مكان الذاكرة وليس لهـما نفـس القيمــة فـالمتغير g
له نسختين ، كل تابع له نسخـة منهــما ، الآن لـو قمنـا بكتابـة تعريـف لمتغيـر
جـــديد خــارج أي كتلــة ســواء for أو while أو أي تــابع آخــر فحينهــا ســتكون
متغيرات عامـة أي أن جميع الكتـل تسـتطيع رؤيتهـا ، وبالتـالي التعامـل معهـا
وكأنها متغيرات خاصـة ، إلا أن الفـرق هــنا هــو أن أي تغييـر فـي قيمــة هـذا
المتغير من أي تابع في البرنـامج فـإن التغييـر سـيبقى حتـى انتهـاء البرنـامج
بشكل نهائي.
المتغيرات الساكنـة Variables Static:
المتغيرات الساكنـة تأخذ مزايا النـوعين السابقين فهـي أولاً نفـس المتغيـرات
الخاصـة أي أن هـناك تابع وحيد يستطيع رؤيتها هــو التـابع الـذي تـم الإعـلان
عـنها داخله وثانياً أنها لا تنتهـي أو تمـوت حينمـا يـتم انتهـاء تنفيـذ التـابع فـي
المرة الواحدة فمثلاً لو قمنا بكتابة متغير ساكن ضمن تعريف تابع ما ، فحينمـا
يتم تنفيذ هـذا التـابع وقـام فرضـاً بزيـادة قيمــة المتغيـر السـاكن إلـى 2 ، ثـم
انتهى تنفيـذ هـذا التـابع فـإن هـذا المتغيـر السـاكن لا ينتهـي معــه وسـيظل
محتفظاً بالقيمـة 2 حتى يتم استدعاء التـابع مـرة أخــرى وسـيجد أن المتغيـر
الساكن أصبح كما هـو عليه في المرة السابقــة ولـن يعــود إلـى القيمــة 0 ؛
باختصار بإمكان تشبيه المتغيرات الساكنـة على أنها متغيرات خاصـة لا تموت
حتى بانتهاء تنفيذ التابع.
وعـموماً فإن التصريح عـن هذه المتغيرات يتم بالكلمـة المفتاحيـة static كمـا
يرى من هذا السطر:
static int number;
مثال عـملي:
سنقوم الآن بكتابـة تـابع يقـوم بمضاعفــة العــدد الوسـيط إلـى ضعفــه ومـن
الممكن أن يكون هذا التابع بدايـة لك لكي تقوم بإنشاء برنامج حاسبـة آليـة:
CODE
1. #include <iostream>
2. using namespace std;
3.
4. double binate (float b)
5. {
6. return b*b;
7. }
8.
9. void main()
10. {
11. float a;
12. cin>> a;
13. double m=binate(a);
14. cout << m << endl;
15. }
تـم تعريـف التـابع ( )binate فـي الأسـطر مـن 4 إلـى 7 حيـث يسـتقبل عــدد
وسيط واحد وهـو b من النـوع float ويقوم بضربه في نفسـه وإعـادة القيمــة
إلى التابع main .
سنتقدم الآن أكثر وسنقوم بكتابة برنــامج أكثـر عـملانيــة وأكثـر فائـدة وهـذه
المرة فسنستخدم المؤشرات والمتغيرات العامـة كذلك.
البرنامج الذي نحن بصدده عبارة عـن قواسم عـدد ، المستخــدم يـدخل عــدد
ما ثم يقوم البرنامج بإنشاء مصفوفـة ثم إسناد كل قاسم مـن هـذه القواسـم
إلى عـنصر من عـناصر المصفوفـة ؛ إليك كـود البرنامج:
CODE
كـود يقوم بحساب قواسم أي عـدد // .1
2. #include <iostream>
3. using namespace std;
4.
المتغيرات العــامـة //;divides* float .5
6. int times;
7. //////////////////////////////
النمــاذج المصغرة// ;(x int)HowTimes void .8
9. void pointer();
10. void TheMain(int x);
11. ////////////////////////////
التابع الرئيسي // ()main void .12
13. {
14. int a;
15. cin>> a;
16. TheMain(a);
17. for(int i=0;i<times;i++)
18. cout <<divides[i]<< endl;
19. cout << "The Many Of How Number Divides Is:\t"
20. <<times
21. <<endl;
22. }
23. ///////////////////////
24. void pointer( )
25. {
26. divides=new float[times];
27. }
28. /////////////////////////
29. void HowTimes(int x)
30. {
31. for (int i=1;i<=x;i++)
32. if(x%i==0) ++times;
33. }
34. /////////////////////
35. TheMain(int x)
36. {
37. HowTimes(x);
38. pointer();
39. for (int i=1,int j=0;j<times,i<=x;i++)
40. if(x%i==0){
41. divides[j]=i;
42. j++;}
43. }
لقد احتـوى هذا المثال على مواضيع كثيرة سنقوم بمناقشتها حالاً.
فكرة البرنامج:
لهذا البرنامج متغيران عامين رئيسين هـما:
- المتغير العام times : وهذا المتغير يحسب عـدد الأعــداد التـي تقسـم
العـدد المراد إيجاد قواسمـه.
- المؤشر divides: بعـد أن يحسب البرنـامج عــدد قواسـم العــدد فإنــه
يقوم بحجز مصفوفة عدد عـناصرها يساوي قيمــة المتغيـر times ، ثـم
يقوم البرنامج يتخـزين قواسم العـدد في المصفوفـة divides.
أيضاً فإن لهذا البرنامج ثلاث توابع وهـي كالتالي:
1- التـابع (x int)HowTimes : يسـتقبل هــذا العــدد الــرقم الـذي أدخلــه
المستخـدم ويقوم بحساب عـدد قواسمـه ويخزنهـا فـي المتغيـر العـام
.times
2- التـابع ( )pointer : يقـوم هـذا التـابع بحجـز الـذاكرة للمؤشـر divides
وهـو يحجز له مصفوفـة حتى يخـزن فيهـا جميـع قواسـم العــدد الـذي
أدخله المستخـدم.
3- التابع (x int)TheMain : يعتبر هـذا التـابع هــو أهــم تـابع حيـث يقـوم
بإســتقبال الــرقم الــذي أدخلــه المستخـــدم ويــتحكم فــي التــابعين
السابقين ويحسب قواسم العـدد ويخزنها في مصفوفـة divides.
هذه هـي فكرة هذا البرنامج بشكل عام ولكن هــناك بعـض النقـاط الجــديدة
التي يجب التوقف عـندها وشرحها للقارئ العـزيز