A Crash Course in C - Part 7

Structures and Unions.

التراكيب و التجمعيات Structures and Unions

تسمح التراكيب بإنشاء أنواع مٌعرفة من قبل المستخدم user-defined types و تتضمن تلك الانواع مجموعة من المتغيرات التي قد تكون من انواع مختلفة سواء من الأنواع الأساسية في لغة C او انواع آخري مُعرفة من قبل المستخدم تحت اسم واحد ليسهل التعامل معها و ادارتها، و تساهم التراكيب بدور كبير في إنشاء برمجيات معقدة و ضخمة، فهي تسمح بمعالجة البيانات ذات الصلة كوحدة واحدة بدلا من التعامل معاها ككيانات منفصلة موفرة سهولة في قراءة و التعديل علي الملف المصدري و طرق افضل و اسرع لحل المشاكل المعقدة.

يتم تعريف التراكيب بستخدام الكلمة المحجوزة struct، و يتم التعريف عن المتغيرات داخل الـ Block الخاص بالتراكيب علي النحو التالي:

المثال التالي يقوم بإنشاء تركيب بسيط مكون من متغيريين من النوع int:

و يشار الي المتغيرات داخل التركيبة ( في هذه الحالة المتغيريين x y ) علي انهم اعضاء members في التركيبة Point.

و يمكن إنشاء متغيرات من نوع التركيبة في نهاية الـ Block الخاص بها كالتالي:

او تعريفها لاحقا بستخدام الكلمة المحجوزة struct يليها اسم التركيبة و اسماء المتغيرات من نوع التركيبة علي النحو التالي:

كما يمكننا إعطاء قيمة للمتغيرات داخل التركيبة علي النحو التالي:

مما سينتج عنه إعطاء قيمة للمتغيرات حسب ترتيب التعريف عنها داخل التركيبة، فهنا علي سبيل المثال سيساوي المتغير x القيمة 320 و y القيمة 0. مع ذلك يمكن تخطي الإلتزام بالترتيب لإعضاء المصفوفة بستخدام التهيئة المخصصة و التي يشار اليها بإسم Designated Initialization، تأخذ الشكل التالي:

المثال التالي يوضح استخدام الـ Designated initialization:

structz

كما يمكننا استخدام المؤثر الخاص بالأعضاء . للوصول للمتغيرات علي النحو التالي:

مع ذلك لا يمكننا تعيين قيمة لأعضاء التركيبة داخلها مثال:

السبب في ذلك انه عند التعريف عن انواع البيانات لا يتم تخصيص عنواين ذاكرة لها. ولكن يتم فقط تخصيص الذاكرة عندما يتم استخدام التراكيب للتعريف عن متغيرات من نوعها.

اما بالنسبة للعمليات المسموح إجرائها علي التراكيب فهي نفسها العمليات المسموح بها للأنواع الأساسية مثل int او double فقد يتم نسخ التركيبة او تعيين قيمة متغيراتها لكن لا يمكن مقارنة تركيبين بشكل مباشر، يمكن كذلك تمرير التراكيب كوسائط للدوال و إعادتها كقيمة مرجعة، مثال:

و كما هو الحال مع اي متغير آخر يتم تمرير التراكيب حسب القيمة pass by value كما في المثال اعلاه مع وسائط الدالة point_difference

مما سيترتب عليه كون التعديل علي قيمة p2 داخل الدالة غير مؤثر علي قيمتها خارج الدالة. مع ذلك يمكن ان يكون تمرير التراكيب حسب القيمة غير فعال إذا كانت التراكيب كبيرة. و بشكل عام يكون تمرير مؤشر للتركيبة اكثر فاعلية من عمل نسخة منها. و الحصول علي عنوان متغير تابع للتركيبة يتشابه مع الطريقة العادية التي يتم استخدامها مع الأنواع الأساسية، مثال:

و يتم استخدام العلامة <- علي النحو التالي لتبسيط استخدام مؤشرات التراكيب:

 

مصفوفات من التراكيب Arrays of Structures

كما في الأنواع الأساسية، يمكن إنشاء مصفوفات من التراكيب علي الشكل التالي.

Structarre

في المثال السابق قمنا بإنشاء مصفوفة من عشر عناصر من نوع التركيب Point، مما يعني ان لكل عنصر من العشرة عناصر المتغيرين x و y الخاصين بيه. كذلك يمكننا تعيين قيمة للعناصر اثناء التعريف عن المصفوفة عن طريق وضعها بين {} كما انه لا يلزم تحديد حجم معين للمصفوفة و تركها ليتم تعيين قيمتها بشكل ديناميكي. المثال التالي ينشيء مصفوفة من نوع التركيب Point بحجم اربعة عناصر و يقوم بطباعة القيم الخاصة بكل عنصر.

structarr

لاحظ استخدام sizeof لحساب عدد عناصر المصفوفة في المثال السابق:

 

الكلمة المحجوزة Typedefs

تتشابه الكلمة المحجوزة typedef في عملها مع الكلمة المحجوزة define، و توفر وسيلة لإنشاء أسماء أنواع بيانات جديدة. typedef لا تنشيء انواع جديدة بذاتها، لكنها تضيف اسمًا جديدًا لبعض الأنواع الموجودة.

و تأخذ typedef الشكل التالي:

المثال التالي يقوم بتعريف الأسم string لنوع البيانات*char

typedef1

 

و تمكنا typedef من استخدام التراكيب بشكل افضل حيث انها تلغي الحاجة لإعادة كتابة الكلمة المحجوزة struct في كل مرة نقوم بستخدام التراكيب و يتم ذلك علي شكل من الشكلين التاليين:

المثال التالي يوضح استخدام typedef لإنشاء التركيبة Point من ثم استخدامها في دالة ستقوم بإرجاع مؤشر لمساحة تم تخصيصها بستخدام malloc من نفس نوع التركيبة:

pstruct