المقدمة
من فترة كنت نشتغل على مشروع وقعدت بشكل مباشر نتعامل مع المؤشرات Pointers، في الغالب لو كنت بتبدا مسيرتك مع لغة الC المؤشرات راح تكون جنبك طالما تتعامل مع لغة الC دائمًا، عيب المؤشرات أنها صعبة الإستيعاب من البداية بحيث أنه المفهوم يعتبر جديد وغريب نسبيًا بحيث أن مع بداية التعلم الشخص لهذه لغة من بداية أو لأول مرة في عالم البرمجة بيكون المفهوم غريب بعض الشئ، على العموم هو نحاول نطرح سلسلة مقالات حول لغة C من فترة لفترة حيث أنه بنبدأ بالمؤاشرت حاليًا وجزء الأول راح يتعلق كفكرة من الأول وطرح المقالات بيكون بلغة العامية بعض الشئ لو في أي تعليق بخصوص هذا الموضوع أترك تعليق في الأسفل
لنبدأ بالمؤشرات، المؤشرات في لغة الC تعتبر جزء لا يتجزأ عنها وبالأخص أنها راح تعطيك مرونة وقوة في كتابة برنامجك، وبجانب هذا تعتبر شق مهم في إدارة الذاكرة بالنسبة للغة C، إتقانك للمؤشرات وفهمك ليهم بشكل جيد، راح يخليك تكتب برامج بلغة C بشكل كويس.
أذن ماهي المؤشرات أو ماهو المؤشر بحد ذاته، الفكرة من مؤشر هي إنك تأخذ عنوان المتغير لاحظ قلت أنه ياخذ عنوان المتغير وليس قيمة المتغير بحد ذاته، يعنى لما تحاول تسند قيمة لمتغير بطريقة هذه
int i = 10;
وكما تلاحظ محتوى المتغير راح يكون رقم 10، توا المتغير بحد ذاته في لغة الC وربما كل لغات البرمجية الأخرى، تتكون من عنوان في الذاكرة وقيمة ليحملها هذا العنوان، وتذكر أنه أسم المتغير الi أو غيره مايعنى شئ للكومبيوتر لأن يفهم بالعناوين والقيم، أسم المتغيرعادة يرمز له symbol ونفس الأمر مع اسم الدوال والstruct، الsymbol ماهي إلا مجرد تسهيل لنا نحن كمبرمجين للعمل على حل المشاكل.
بجانب أن قلت المتغير يتكون من عنوان وقيمة، نفس الأمر ينطبق على متغير من نوع مؤشر pointer، غير أن نوع القيمة ليست مثل نوع المتغير الإعتيادي يعنى مثل integer أو float أو user-defined structure، قيمته تكمن في عنوان المتغير يعنى المتغير من نوع مؤشر هو متغير يخزن قيم عناوين المتغير بالطريقة هذه
int i = 10;
int *pInt = &i;
لاحظ في المثال السابق أن علامة * دلالة على أنه المتغير من نوع مؤشر pointer ولأي نوع يأشر، يأشر لنوع integer، يعنى (pInt is pointer to int ) ، طبعًا الشئ هذا مهم ويأخذ في الحسبان بشكل كبير وراح أتطرق لسبب ليش نوع المتغير مهم في عمليات المؤشر pointer arithmetic.
توا السؤال كيف يأخذ عنوان المتغير ؟؟ تتم العملية عن طريق مايسمى بعملية referencing وبإستعمال عملية &، حيث أن ال& تعطيك عنوان المتغير في الذاكرة ويسندها للمؤشر، (يجدر الذكر أنه لا يجب الخلط بين & كعملية AND و ك& كعملية referencing حيث تستعمل الأخيرة في عملية إسناد عنوان المتغير للمؤشر أو لدالة كتمريرها كعنوان reference).
توا سؤال أخر يطرح، هل عملية التعامل مع المتغيرات من النوع مؤشر pointer مثل المتغير الإعتيادي ؟؟ الإجابة إيه ولا، كيف يعنى ؟؟
واحد من تطبيقات المؤشر pointer وهي أكثرها شيوعًا أنه يتم تمرير المتغيرات كعنوان reference، أو بالأحرى تتم عملية تبادل البيانات بسرعة بدون مايدير copying يعنى نسخ قيم المتغير، ليتضح أنه في كفاءة في التعامل مع المتغيرات والقيم الكبيرة لي تستهلك وقت في النسخ حيث أن يتم إستعمال المؤشرات بأخذ عنوان المتغير بدل مايأخذ القيمة بشكل كامل وينسخها كلها.
التعامل مع المؤشرات
التعامل مع المؤشرات عادة تنقسم لنوعين، تعامل معه كمتغير عادي أو كمؤشر، كيف تتعامل معاه كمتغير عادي؟؟ خلي نجي نشوفوا للمثال هذا
// usual variable
int i = 10;
// i لا حظ أن تم أخذ عنوان المتغير
int *iPtr = &i;
// لإستعماله كمتغير عادي أو بالأحرى تعامل معاه كأنه متغير تحتاج إلى عملية تسمى
// Dereferencing
// حيث تتيح لك أخذ قيمة المتغير أو تغيره
// i هنا تم نسخ قيمة المتغير السابق
// y إلى
int y = *iPtr;
في الكود السابق يوضح أني خزنت قيمة لكان يأشرلها المتغير iPtr للمتغير i لي y، ركز هنا أني قلت يأشرلها مش يأخذ قيمة المتغير الiPtr، المتغير iPtr بحد ذاته عنوان يعنى يأشر لعنوان معين زي عنوان الi، والi قيمتها تساوي 10، بمعنى أن الy نسخت بشكل غير مباشر قيمة الi عن طريق المؤشر iPtr بإستعمال عملية Dereferencing يعنى بإضافة * قبل المؤشر iPtr في عملية الإسناد القيمة، ركز أني قلت الإسناد، يعنى باهي لو درت هكي
int y = iPtr;
ليصير هنى بالضبط أنك تنسخ في عنوان المتغير i، هل تقدر تتلاعب بقيمة المؤشر iPtr ؟؟؟ نعم، تقدر تغير قيمة المؤشر يأما بقيمته بإستعمال Dereferencing
int i = 10;
int iPtr = &i;
*iPtr = 10*10;
// قيمة المتغير راح تتغير إلى 100 لأن لصار مثل هذه
i = 10*10;
كيف ممكن تغيرت قيمة الi ؟؟ تتفكر لما قتلك أن المتغير من نوع مؤشر يأخذ عنوان المتغير يعنى بالضبط يأِشرله ليه يعنى زي عملية ربط بينه وبين المتغير i مثل ماتقول أي تغير تديره للمتغير iPtr ينطبق على i لأن iPtr مخزن فيه عنوان المتغير i في نفس الوقت أيضًا المتغير iPtr عنده عنوان خاص بيه مثل ماموضح في الصورة
أو يمكنك تتلاعب بقيمة العنوان وتغير عنوان المؤشر لمكان أخر عن طريق يأما الإسناد أو increamting.
شن الفائدة المكتسبة من تعامل مع المتغيرة والإضافة لنستفيد منها أو يضيف حاجات جديدة لخبرتي ؟؟
الفائدة أن لما بتتعامل مع الدوال وتمرر القيم بين الدوال ممكن حي تمرر قيم من نوع structure ولهو عبارة نوع من البيانات يعرفها المتسخدم وتكون فيها أكثر من نوع وغالبًا يكون حجم الstructure كبير ولما تمرر structure معين لدالة حي يكون الأمر مستنزف للبرنامج ويأخذ وقت لنسخ على خاطر أنك بتقرأ قيم ؟؟!! لهذا المؤاشرات تعتبر حل مناسب للمشاكل هذه فقط مرر عنوان structure ودير عملية dereferencing وأقرا القيم بشكل أكفا، يعنى مرر المتغيرات كعنوان بدل كقيم ويعتبر من الgood practice في لغة الC، مع إعتبار هل أنك تحتاج تغير قيمة المتغير أو لا ،ولتفادي هذه المشكلة من المبرمج يتم إضافة const لمنع من أي تغير بشكل غير متوقع
int readFoo(const UserStruct *p);
كيفية تمرير المتغيرات للدوال وغيرها من المواضيع التي طرحها ،ستكون في المقالة القادمة أرجو أن تكون المقالة مفيدة ولو عندك تعليق خليه 😁