Transcript 674387937x

Slide 1


Slide 2

‫إن ذاكرة الحاسب هي عبارة عن مصفوفة من البايتات ‪.‬‬

‫المتحول ‪ : variable‬هو مكان في الذاكرة نحفظ فيه قيمة محرفية أو رقمية‬
‫أو غير ذلك‪ ،‬ويختلف حجم هذا المتحول على حسب نوعه فقد يكون حجمه‬
‫بايت واحد فقط في حال كان من النمط ‪ ، char‬ويكون حجمه ‪ 4 bytes‬في‬
‫حال كان من النمط ‪ ، integer‬وهكذا ‪....‬‬
‫فإننا عندما نقوم بحجز متحول من النمط ‪ integer‬فإنه يتم حجز ‪4 bytes‬‬
‫له في الذاكرة ‪.‬‬


Slide 3

‫أما عندما نقوم بتعريف متحول من النمط ‪ char‬فإنه يتم حجز بايت واحد‬
‫فقط له ‪.‬‬
‫وعندما نقوم بإنشاء متحول من صف ما ‪ object from class‬فإن هذا‬
‫المتحول سيأخذ حجماً في الذاكرة يناسب الصف المعرف ‪.‬‬


Slide 4

‫إن كل متحول في الذاكرة له عنوان ‪ ،‬للحصول على عنوان متحول ما‬
‫نستخدم العالمة & ونتبعها باسم المتحول ‪.‬‬
‫مثال ‪ :‬ليكن المتحول ‪ x‬من النمط ‪ integer‬ويحمل القيمة ‪ 10‬أي ‪:‬‬
‫)‪( 10‬‬
‫)‪(0x1BFE9C‬‬

‫‪int‬‬
‫;‪x = 10‬‬
‫; ‪cout<‫;‪cout<<&x<
‫ال يمكن التعديل على عنوان متحول ما ‪ ،‬أي أن الكتابة التالية هي خاطئة ‪:‬‬
‫;‪&x = 11‬‬
‫)‪(Error‬‬


Slide 5

‫أمثلة عن تعريف المتحوالت‬

‫وكيفية الحجز بالذاكرة‪ ،‬وكيفية‬
‫معرفة عناوين المتحوالت‬


Slide 6

‫االسم المستعار ‪ r‬هو اسم مرادف لمتغير آخر ‪.‬‬

‫إذا طلبت المتحول ‪ r‬كأنني طلبت المتحول ‪ n‬ويكون لهما نفس المكان في الذاكرة ‪.‬‬


Slide 7

‫إن ‪ r‬و ‪ n‬لهما مكان واحد في الذاكرة وإن التعامل مع أحدهم يعني كأننا‬
‫نتعامل مع اآلخر‪ ،‬فإن إنقاص أحدهم يؤدي حتماً إلى إنقاص اآلخر ‪.‬‬


Slide 8

‫المؤشر ‪ : pointer‬هو أيضاً مكان في الذاكرة ولكنه يحوي عنوان‬
‫)‪ (address‬متحول آخر(وهي قيمة عددية مكتوبة بالنظام الست عشري‬
‫وتمثل عنوان متحول ما في الذاكرة)‪ ،‬ودائماً يكون حجم المؤشر ‪4 bytes‬‬
‫مهما كان محتواه ‪.‬‬
‫إن المؤشرات تعطي لغة ‪ c++‬فاعلية وسرعة كبيرتين‪.‬‬

‫ولكن إن التفكير والعمل بالمؤشرات يتطلب الدقة والحذر ‪.‬‬


Slide 9

‫إن المؤشرات تمكننا من إنشاء أغراض أثناء الـ ‪. Runtime‬‬

‫حيث إننا سابقاً كنا نقوم بتعريف مصفوفة حصراً طولها ثابت ‪:‬‬
‫; ]‪int vector[5‬‬

‫أما إذا كتبنا التالي ‪:‬‬

‫)‪(Error‬‬

‫; ‪int i‬‬
‫;‪cin>>i‬‬
‫; ]‪int vector[i‬‬


Slide 10

‫عن طريق المؤشرات يمكننا بناء أنماط معطيات جديدة مثل ‪:‬‬

‫)‪(Tree , Stack , Queue , linked list , …..‬‬
‫المؤشرات تمكننا من تمرير متحول إلى تابع على أنه متحول دخل وخرج‬
‫معا‪ ،‬حيث يمكننا التعديل على المتحول داخل التابع ‪ ،‬وبعد الخروج من‬
‫التابع نجد أن قيمة المتحول قد تغيرت عمّا كانت عليه قبل استدعاء التابع ‪.‬‬


Slide 11

‫يتم تعريف المؤشر تبعاً للصيغة التالية ‪:‬‬

‫أمثلة ‪:‬‬


Slide 12

‫يتم إعطاء قيمة ابتدائية للمؤشر عن طريق ‪:‬‬

‫إن‬

‫‪ NULL‬هي معرفة في المكتبتين‬

‫>‪
‫وهنا ال يشير المؤشر إلى أي موقع في الذاكرة‪.‬‬

‫‪and‬‬

‫>‪

Slide 13

‫يجب أن يكون نمط المؤشر من نفس نمط المعطيات التي يشير عليها كما في المثال‬

‫السابق‪ ،‬أما الكتابة التالية فهي خاطئة ‪:‬‬

‫تنويه‪:‬‬

‫إن تعريف المؤشر قد يكون بأحد األشكال التالية ‪:‬‬


Slide 14

‫مثال ‪:‬‬

‫وهنا المؤشر ‪ yPtr‬يحوي عنوان المتحول ‪ y‬وبالتالي فإنه يشير إلى المتحول ‪. y‬‬


Slide 15

‫مثال آخر ‪:‬‬


Slide 16

‫مثال آخر ‪:‬‬

‫نالحظ أن قيمة المؤشر ‪ p‬هي عنوان المتحول ‪. a‬‬
‫وبما أن المؤشر ‪ p‬هو متحول وبالتالي فإنه له عنوان نحصل عليه بكتابة ‪. &p‬‬


Slide 17

‫يمكن الوصول إلى قيمة المتحول الذي يشير إليه المؤشر ‪ p‬عن طريق استخدام ‪. *p‬‬

‫يسمى المعامل *‬
‫بـ‬

‫‪Dereferencing‬‬
‫‪Operator‬‬
‫وتسمى العملية بـ‬
‫‪Dereferencing‬‬


Slide 18

‫يمكن الوصول إلى قيمة المتحول الذي يشير إليه المؤشر ‪ p‬عن طريق استخدام ‪. *p‬‬

‫احذر استعمال ‪ *p‬في حال كان المؤشر ال يشير إلى شيء أي في حال كان يحوي‬
‫‪. Null‬‬

‫ولنتجنب حدوث األخطاء نستخدم التالي ‪:‬‬


Slide 19


Slide 20


Slide 21


Slide 22


Slide 23


Slide 24


Slide 25

‫تذكر أن قيمة المؤشر هي عنوان متحول وليس قيمة ما ! ‪.‬‬
‫وتذكر أيضاً أن استخدام ‪ *p‬تعني قيمة المتحول الذي يشير إليه‬
‫المؤشر ‪ p‬لذلك تجنب استعمال هذا التعبير ‪ *p‬في حال كان المؤشر ال‬
‫يشير إلى شيء أي )‪. (NULL‬‬


Slide 26


Slide 27


Slide 28


Slide 29

‫ما هو الفرق بين التعبيرين ‪*p1 = *p2‬‬

‫و‬

‫‪p1 = p2‬‬

‫?‬

‫التعبير األول ‪ *p1 = *p2 :‬معناه وضع في المتحول الذي يشير إليه‬
‫‪ p1‬نفس قيمة المتحول الذي يشير إليه ‪. p2‬‬
‫التعبير الثاني‪ p1 = p2 :‬معناه جعل قيمة المؤشر ‪ p1‬نفس قيمة المؤشر‬
‫‪ p2‬أي يمكننا القول أيضاً جعل ‪ p1‬يشير إلى المكان الذي يشير إليه ‪. p2‬‬


Slide 30

‫ما هو الفرق بين التعبيرين ‪*p1 = *p2‬‬

‫و‬

‫‪p1 = p2‬‬

‫?‬


Slide 31

‫ما هو الفرق بين التعبيرين ) ‪ if ( *p1 == *p2‬و ) ‪? if ( p1 == p2‬‬
‫التعبير األول ‪ if ( *p1 == *p2 ) :‬معناه هل قيمة المتحول الذي يشير إليه ‪p1‬‬

‫تساوي قيمة المتحول الذي يشير إليه ‪. p2‬‬
‫التعبير الثاني‪ if ( p1 == p2 ) :‬هل قيمة المؤشر ‪ p1‬هي نفس قيمة المؤشر ‪p2‬‬
‫أي يمكننا القول أيضاً هل المؤشران ‪ p1‬و ‪ p2‬يشيران إلى نفس المكان في الذاكرة‪...‬‬

‫تذكر أن قيمة مؤشر ما هي عنوان في الذاكرة ‪.‬‬


Slide 32

‫يوجد ثالث طرق لتمرير المتحوالت إلى تابع‬
‫وهي ‪:‬‬
‫التمرير بالقيمة ‪. by value‬‬

‫التمرير بالمرجع عن طريق العناوين (وسطاء التابع هي عناوين) ‪.‬‬
‫التمرير بالمرجع عن طريق المؤشرات (وسطاء التابع هي مؤشرات)‪.‬‬


Slide 33

‫الطريقة األولى ‪ :‬التمرير بالقيمة ‪by value‬‬

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


Slide 34

‫الطريقة الثانية ‪ :‬التمرير بالمرجع عن طريق العناوين (وسطاء التابع هي عناوين)‬

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

‫حيث أنه بعد الخروج من‬
‫التابع تكون المتحوالت قد تم‬
‫تعديل قيمها ‪.‬‬


Slide 35

‫الطريقة الثالثة‪ :‬التمرير بالمرجع عن طريق المؤشرات (وسطاء التابع هي مؤشرات)‬

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

‫حيث أنه بعد الخروج من‬
‫التابع تكون المتحوالت قد تم‬
‫تعديل قيمها ‪.‬‬
‫انتبه إلى االستدعاء‪.‬‬


Slide 36

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


Slide 37

‫بعد الخروج من التابع يزول المتحول المحلي‬
‫‪ x‬ولكن قيمته تبقى موجودة في الذاكرة ‪.‬‬

‫المؤشر ‪ p‬يبقى يشير إلى مكان في الذاكرة‬
‫يحوي القيمة ‪. 5‬‬

‫يمكن التعديل على القيمة الموجودة في مكان‬
‫الذاكرة الذي يشير إليه المؤشر ‪ p‬عن طريق الـ‬
‫‪. Dereferencing Operator‬‬
‫نتيجة البرنامج هي ‪. 6‬‬


Slide 38

‫بعد استدعاء التابع والخروج منه نجد‬
‫أن المتحول ‪ x‬يزول ولكن قيمته تبقى‬
‫موجودة في الذاكرة ويمكن الوصول إليها‬
‫بواسطة المؤشر ‪. p‬‬
‫إن السطر ‪ (*p)++‬يؤدي إلى زيادة قيمة‬
‫المتحول الذي يشير إليه المؤشر ‪. p‬‬
‫نتيجة البرنامج هي ‪. 6‬‬


Slide 39

‫يجب عند تعريف مرجع ما إعطاءه قيمة ابتدائية مباشرة ‪.‬‬

‫يجب عدم استعمال الـ ‪ Dereferencing Operator‬مع مؤشر يؤشر‬
‫إلى الشيء ‪.‬‬


Slide 40

‫إن المؤشر ‪ p‬يشير إلى المتحول ‪n‬‬
‫إن ‪ r‬هو اسم مستعار للمتحول الذي‬

‫يحوي القيمة ‪ *p‬أي أنه اسم مستعار‬
‫للمتحول ‪. n‬‬
‫إن * و & تعمالن عمالن متعاكسان فإن ‪:‬‬

‫و‬

‫‪n == *p‬‬

‫‪p == &n‬‬

‫ويمكن التعبير عن ذلك أيضاً بـً ‪:‬‬
‫‪n == *&n‬‬

‫و‬

‫‪p == &*p‬‬


Slide 41

‫إذا قمنا بتعريف متحول ما على أنه ‪ const‬ثم قمنا بتعديله فإنه سيظهر لنا‬
‫‪. Compiler Error‬‬
‫عند تعريف أي متحول على أنه ‪ const‬يجب إعطاءه قيمة ابتدائية مباشرة‬
‫وال يمكن أبداً تعديلها وإن محاولة تعديلها سيظهر خطأ ‪Compiler‬‬
‫‪. Error‬‬

‫تذكر دائماً أن بعد المصفوفة هو ثابت سواء كان متحول تم التصريح عنه‬
‫على أنه ‪ const‬أو كان قيمة عددية ثابتة‪.‬‬


Slide 42

‫الحجز الديناميكي باستخدام المؤشرات‬
‫‪Dynamic Allocation‬‬
‫‪Using Pointers‬‬


Slide 43

‫نحن معتادون على الحجز الستاتيكي في الذاكرة ‪. static allocation‬‬
‫حيث أن أبعاد المصفوفة هو ثابت يكون معروف مسبقاً وبالتالي هنا يتم‬

‫الحجز في الذاكرة أثناء مرحلة الـ ‪. Compiling‬‬
‫إذا أردنا أن يكون حجم المصفوفة متغير أي أنه غير معروف مسبقاً‬
‫فإننا سنلجأ الستخدام الحجز الديناميكي ‪dynamic allocation‬‬

‫وهنا يتم الحجز في الذاكرة أثناء مرحلة الـ ‪. Runtime‬‬


Slide 44

‫عندما نقوم بإنشاء أغراض أثناء الـ ‪. Runtime‬‬
‫عندما نقوم بإنشاء مصفوفات بأبعاد غير معروفة مسبقاً حيث يتم معرفة حجم‬
‫المصفوفة أثناء التنفيذ فمثالً قد يدخل المستخدم حجم المصفوفة من لوحة المفاتيح ‪.‬‬
‫الحجز الديناميكي يُمكننا من التعامل مع الذاكرة بشكل أقرب حيث يمكننا أن نحرر ما‬

‫تم حجزه في الذاكرة أثناء الـ ‪ Runtime‬قبل االنتهاء من تنفيذ البرنامج ‪.‬‬


Slide 45

‫إذاً هناك نوعين للحجز في الذاكرة ‪:‬‬
‫‪ ‬الحجز الستاتيكي ‪:static allocation‬‬

‫يتم تعريف المتحول عند التصريح عنه مثالً ‪. int x = 3‬‬
‫يتم إزالة المتحول بعد الخروج من مجاله أي بعد الخروج من ‪.Local Block‬‬

‫‪ ‬الحجز الديناميكي ‪) dynamic allocation‬ويتم باستخدام المؤشرات(‪:‬‬
‫يتم تعريف المتحول عن طريق التعليمة ‪. new‬‬

‫يتم إزالة المتحول عن طريق التعليمة ‪. delete‬‬


Slide 46


Slide 47

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


Slide 48

‫ويمكن الكتابة أيضاً على مرحلتين كما في المثال التالي ‪:‬‬

‫تتم عملية الحجز الديناميكية في مكان في الذاكرة يدعى ‪ heap‬الكومة ‪.‬‬
‫عند التصريح عن التعليمة‬

‫أي حجز مكان في الكومة بحجم أربعة بايتات ‪ ،‬فإذا‬

‫كان هناك متسع في الذاكرة بهذا الحجم تتم عملية الحجز بنجاح وترد التعليمة ‪ new‬عنوان مكان الذاكرة‬
‫الذي تم به الحجز ‪ ،‬وإال فإن قيمة المؤشر تكون ‪ NULL‬أي أن المؤشر ال يشير إلى شيء ‪.‬‬


Slide 49

‫في المثال السابق تم حجز مكان في الذاكرة للنمط ‪ integer‬وتم إنشاء‬
‫مؤشر اسمه ‪ p‬وجعلنا ‪ p‬يشير إلى ذلك المكان في الذاكرة من دون أن نضع‬
‫قيمة ابتدائية في ذلك المكان في الذاكرة وهذا هو االستخدام األول للتعليمة‬
‫‪. new‬‬


Slide 50

‫في المثال السابق تم حجز مكان في الذاكرة للنمط ‪ integer‬وتم إنشاء‬
‫مؤشر اسمه ‪ p‬وجعلنا ‪ p‬يشير إلى ذلك المكان في الذاكرة ‪ ،‬وتم وضع‬
‫القيمة ‪ 5‬في ذلك المكان في الذاكرة وهذا هو االستخدام الثاني للتعليمة ‪new‬‬
‫‪.‬‬


Slide 51

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

‫هنا يمكن أن يكون بُعد المصفوفة متغير( ‪ ،‬وهذا هو االستخدام الثالث للتعليمة ‪. new‬‬


Slide 52

‫في السطر األول يتم تخصيص الذاكرة للمتحول المسمى ‪ x‬أثناء الـ ‪. Compile‬‬
‫في السطر الثاني يتم تخصيص مكان في الذاكرة لمتحول غير مسمى وجعلنا المؤشر‬
‫‪ p‬يشير إلى ذلك المكان في ذلك ‪ ،‬وكل هذا يحصل أثناء الـ ‪ ، Runtime‬ونتذكر بأننا‬

‫يمكننا الوصول إلى محتوى ذلك المكان في الذاكرة عن طريق الـ ‪. *p‬‬


Slide 53

‫إن التعليمة ‪ delete‬متبوعة باسم مؤشر ما تقوم بالتالي ‪:‬‬


Slide 54

‫إن التعليمة ‪ delete‬تقوم بـ ‪:‬‬
‫تحرير مكان الذاكرة المحجوز في الكومة أي يتم حذف القيم التي كان‬
‫موجودة في ذلك المكان في الذاكرة ‪.‬‬
‫إن التعليمة ‪ delete‬ال ترد شي ‪.‬‬
‫إن التعليمة ‪ delete‬تعمل عكس عمل التعليمة ‪. new‬‬


Slide 55


Slide 56


Slide 57


Slide 58

‫يمكن إنشاء مكان في الكومة دون وضع قيمة فيه عن طريق‪:‬‬
‫‪new int‬‬
‫) ( ‪new int‬‬
‫وفي كال الحالتين يتم وضع قيمة عشوائية في المكان المحجوز ‪.‬‬
‫ذكرنا بأنه عند إنشاء مكان في الذاكرة بشكل ديناميكي قد ال يكون هناك‬
‫متسع في الذاكرة وهنا التعليمة ‪ new int‬ترد القيمة ‪. NULL‬‬


Slide 59

‫هنا نقوم بالتأكد من أنه تمت عملية إنشاء المكان في الذاكرة بشكل‬
‫صحيح عن طريق فحص إذا كان المؤشر قيمته ‪. NULL‬‬


Slide 60

‫عملية التسرب في الذاكرة تحصل عندما يتم حجز في الذاكرة بشكل ديناميكي دون أن‬
‫يتم إلغاء الحجز فالقيمة ‪ 3‬تبقى موجودة في الذاكرة دون إمكانية الوصول إليها‪.‬‬


Slide 61

‫عملية التسرب في‬
‫الذاكرة تحصل عندما‬
‫يتم حجز في الذاكرة‬
‫بشكل ديناميكي دون أن‬
‫يتم إلغاء الحجز ‪.‬‬
‫ما الحل ؟؟‬
‫; ‪delete ptr‬‬


Slide 62

try it


Slide 63

b is 5


Slide 64

b is -8415113


Slide 65

*iPtr is 5


Slide 66