English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
في هذا الدرس، ستعلم عن أنواع الهياكل في برمجة C. ستعلم كيفية تعريف واستخدام الهياكل من خلال أمثلة.
في برمجة لغة C، غالبًا ما تحتاج إلى تخزين عدة خصائص للكائنات. لا يجب أن تكون الكائنات مملوكة فقط لنوع واحد من المعلومات. يمكن أن يكون لها خصائص مختلفة من أنواع بيانات مختلفة.
يُمكن تعريف جملة C Arrays لتخزين متغيرات تحتوي على نفس نوع البيانات.هيكلهو نوع بيانات مخصص آخر متاح في البرمجة بلغة C، ويُسمح بتصفية عنصر بيانات مختلفة.
يُستخدم هيكل لتمثيل سجل، افتراضًا إذا كنت ترغب في تتبع حركة الكتب في مكتبة، قد تحتاج إلى تتبع الخصائص التالية لكل كتاب:
العنوان
المؤلف
الموضوع
رقم الهيكل
لإعداد هيكل، يجب عليك استخدام struct كلمة مفتاحية. تعريف جملة struct يحدد نوع بيانات جديد يحتوي على عدة أعضاء، ويكون نمط جملة struct كالتالي:
struct tag { member-list member-list member-list ... }; variable-list ;
tag هي علامة هيكل.
member-list هي تعريف متغيرات قياسية، مثل int i; أو float f، أو أي تعريف متغير صالح آخر.
variable-list متغير هيكل،يُحدد في نهاية الهيكل، قبل آخر نقطة ثنائية، يمكنك تحديد متغير هيكل واحد أو أكثر. إليك كيفية إعلان هيكل Book:
struct Books { char title[50]; char author[50]; char subject[100]; int book_id; }; book;
في العادة،tag،member-list،variable-list عندما لا يتجاوزها هذا الجزء 2. إليك مثال على ذلك:
//يُعلن هذا الإعلان عن هيكل يحتوي على 3 أعضاء، هم int a، char b و double c //وإعلان عن متغير هيكل s1 //لم يتم تحديد علامة الهيكل لهذا الهيكل struct { int a; char b; double c; }; s1; //يُعلن هذا الإعلان عن هيكل يحتوي على 3 أعضاء، هم int a، char b و double c //تم تسمية علامة الهيكل بSIMPLE وليس تم إعلان أي متغيرات struct SIMPLE { int a; char b; double c; }; //هيكل بمناسبة SIMPLE مع إعلان متغيرات t1، t2، t3 struct SIMPLE t1, t2[20], *t3; //يمكن أيضًا استخدام typedef لإنشاء نوع جديد typedef struct { int a; char b; double c; }; Simple2; //يمكن الآن استخدام Simple2 كنوع لإعلان متغيرات الهيكلية الجديدة Simple2 u1, u2[20], *u3;
في الإعلان أعلاه، يتم اعتبار الإعلانين الأول والثاني كنوعين مختلفين، حتى لو كانا يحتويان على قائمة أعضاء متطابقة، إذا كان t3=&s1، فإنه غير قانوني.
يمكن أن تحتوي أعضاء الهيكل على هيكل آخر، أو إشارات إلى نوع الهيكل الخاص بهم، وعادةً ما يستخدم هذا النوع من الإشارات لإنشاء هيكل بيانات متقدم مثل قوائم و árboles.
//إعلان هذا الهيكل يحتوي على هيكل آخر struct COMPLEX { char string[100]; struct SIMPLE a; }; //إعلان هذا الهيكل يحتوي على إشارة إلى نوع نفسه struct NODE { char string[100]; struct NODE *next_node; };
إذا كان هناك تضارب بين الهيكلين، فإنه يجب إعلان واحد منهما بشكل غير كامل، مثلما يلي:
struct B; //إعلان غير كامل للهيكل B //يحتوي الهيكل A على إشارة إلى الهيكل B struct A { struct B *partner; //أعضاء أخرى; }; //يحتوي الهيكل B على إشارة إلى الهيكل A، ويتم إعلان B بعد إعلان A struct B { struct A *partner; //أعضاء أخرى; };
مثل باقي أنواع المتغيرات، يمكن تحديد القيم الافتراضية للمتغيرات من النوع الهيكلية عند تعريفها.
#include <stdio.h> struct Books { char title[50]; char author[50]; char subject[100]; int book_id; } book = {" ", "w3codebox", "لغة البرمجة", 123456}; int main() { printf("عنوان الكتاب: %s\nالمؤلف: %s\nالموضوع: %s\nBookID %d\n", book.title, book.author, book.subject, book.book_id); }
نتيجة الإخراج التنفيذي هي:
عنوان الكتاب: المؤلف: w3codebox الموضوع: BookID 123456
للوصول إلى أعضاء الهيكل، نستخدم}}المعرف (.)المعرف هو نقطة بين اسم متغير الهيكل والعضو الذي نريد الوصول إليه. يمكنك استخدام struct استخدام الكلمات المفتاحية لتحديد متغيرات أنواع الهياكل. يظهر المثال التالي استخدامه:
#include <stdio.h> #include <string.h> struct Books { char title[50]; char author[50]; char subject[100]; int book_id; }; int main( ) { struct Books Book1; /* إعلان Book1، نوعه هو Books */ struct Books Book2; /* إعلان Book2، نوعه هو Books */ /* تفاصيل Book1 */ strcpy( Book1.title, "C 编程语言"); strcpy( Book1.author, "Nuha Ali"); strcpy( Book1.subject, "C 编程语言教程"); Book1.book_id = 6495407; /* تفاصيل Book2 */ strcpy( Book2.title, "JAVA编程语言"); strcpy( Book2.author, "Seagull Ali"); strcpy( Book2.subject, "JAVA编程语言教程"); Book2.book_id = 6495700; /* 输出 Book1 信息 */ printf( "Book 1 书名:%s\n", Book1.title); printf( "Book 1 作者:%s\n", Book1.author); printf( "Book 1 主题:%s\n", Book1.subject); printf( "Book 1 编号:%d\n", Book1.book_id); /* 输出 Book2 信息 */ printf( "Book 2 书名:%s\n", Book2.title); printf( "Book 2 作者:%s\n", Book2.author); printf( "Book 2 主题:%s\n", Book2.subject); printf( "Book 2 编号:%d\n", Book2.book_id); return 0; }
عند تجميع وتنفيذ الكود أعلاه، سيتم إنتاج النتيجة التالية:
عنوان كتاب 1: C البرمجة كاتب كتاب 1: Nuha Ali موضوع كتاب 1: تعليم لغة البرمجة C رقم كتاب 1: 6495407 عنوان كتاب 2: JAVA البرمجة كاتب كتاب 2: Seagull Ali موضوع كتاب 2: تعليم لغة البرمجة JAVA رقم كتاب 2: 6495700
يمكنك وضع الهيكل كمعامل للدالة، وطرق التوليد مشابهة لتوليد المتغيرات من الأنواع الأخرى أو المشاركات.
#include <stdio.h> #include <string.h> struct Books { char title[50]; char author[50]; char subject[100]; int book_id; }; /* إعلان الدالة */ void printBook( struct Books book ); int main( ) { struct Books Book1; /* إعلان Book1، نوعه هو Books */ struct Books Book2; /* إعلان Book2، نوعه هو Books */ /* تفاصيل Book1 */ strcpy( Book1.title, "C 编程语言"); strcpy( Book1.author, "Nuha Ali"); strcpy( Book1.subject, "C 编程语言教程"); Book1.book_id = 6495407; /* تفاصيل Book2 */ strcpy( Book2.title, "JAVA编程语言"); strcpy( Book2.author, "Seagull Ali"); strcpy( Book2.subject, "JAVA编程语言教程"); Book2.book_id = 6495700; /* 输出 Book1 信息 */ printBook( Book1 ); /* 输出 Book2 信息 */ printBook( Book2 ); return 0; } void printBook( struct Books book ); { printf( "Book 书名:%s\n", book.title); printf( "Book 作者:%s\n", book.author); printf( "Book 主题:%s\n", book.subject); printf( "Book 编号:%d\n", book.book_id); }
عند تجميع وتنفيذ الكود أعلاه، سيتم إنتاج النتيجة التالية:
عنوان الكتاب: لغة البرمجة C كاتب الكتاب: Nuha Ali موضوع الكتاب: تعليم لغة البرمجة C رقم الكتاب: 6495407 عنوان الكتاب: لغة البرمجة JAVA كاتب الكتاب: Seagull Ali موضوع الكتاب: تعليم لغة البرمجة JAVA رقم الكتاب: 6495700
يمكنك تعريف إشارة البنية بنفس الطريقة التي تعريفها باستخدام إشارة البنية لأي نوع آخر، كما يلي:
struct Books *struct_pointer;
الآن، يمكنك حفظ عنوان البنية في متغير الإشارة المحدد مسبقًا. للحصول على عنوان البنية، يجب وضع عمودية & أمام اسم البنية، كما يلي:
struct_pointer = &Book1;
للوصول إلى أعضاء البنية باستخدام إشارة البنية التي تشير إلى البنية، يجب استخدام عمودية ->، كما يلي:
struct_pointer->title;
دعونا نستخدم إشارة البنية لاعادة كتابة المثال السابق، هذا سيساعدك على فهم مفهوم إشارات البنية:
#include <stdio.h> #include <string.h> struct Books { char title[50]; char author[50]; char subject[100]; int book_id; }; /* إعلان الدالة */ void printBook( struct Books *book ); int main( ) { struct Books Book1; /* إعلان Book1، نوعه هو Books */ struct Books Book2; /* إعلان Book2، نوعه هو Books */ /* تفاصيل Book1 */ strcpy( Book1.title, "C 编程语言"); strcpy( Book1.author, "Nuha Ali"); strcpy( Book1.subject, "C 编程语言教程"); Book1.book_id = 6495407; /* تفاصيل Book2 */ strcpy( Book2.title, "JAVA编程语言"); strcpy( Book2.author, "Seagull Ali"); strcpy( Book2.subject, "JAVA编程语言教程"); Book2.book_id = 6495700; /* من خلال نقل عنوان Book1 إلى خارج الـ Book1 لعرض معلومات الـ Book1 */ printBook( &Book1 ); /* من خلال نقل عنوان Book2 إلى خارج الـ Book2 لعرض معلومات الـ Book2 */ printBook( &Book2 ); return 0; } void printBook(struct Books *book) { printf("عنوان الكتاب: %s\n", book->title); printf("كاتب الكتاب: %s\n", book->author); printf("موضوع الكتاب: %s\n", book->subject); printf("رقم الكتاب: %d\n", book->book_id); }
عند تجميع وتنفيذ الكود أعلاه، سيتم إنتاج النتيجة التالية:
عنوان الكتاب: لغة البرمجة C كاتب الكتاب: Nuha Ali موضوع الكتاب: تعليم لغة البرمجة C رقم الكتاب: 6495407 عنوان الكتاب: لغة البرمجة JAVA كاتب الكتاب: Seagull Ali موضوع الكتاب: تعليم لغة البرمجة JAVA رقم الكتاب: 6495700
بعض المعلومات عند تخزينها، لا تحتاج إلى استخدام بايت كامل، بل يكفي استخدام عدة أو بايت واحد من مراكز البايت الثنائية. على سبيل المثال، عند تخزين مقياس، تكون هناك حالتان فقط: 0 و 1، ويكفي استخدام 1 من مراكز البايت الثنائية. من أجل توفير مساحة التخزين وتسهيل المعالجة، يقدم لغة C أيضًا بنية بيانات تُدعى "منطقة بايت" أو "منطقة قطاع".
تُعرف "مناطق البايت" بأنها تقسيم مراكز البايت الثنائية في بايت واحد إلى عدة مناطق مختلفة، ويُوضح عدد مراكز البايت في كل منطقة. كل منطقة لها اسم منطقة، مما يسمح بالعمل على اسم المنطقة في البرنامج. بذلك يمكن تمثيل عدة كيانات مختلفة باستخدام منطقة بايت ثنائية واحدة.
مثال تقليدي:
عند استخدام 1 من مراكز البايت الثنائية لتخزين مقياس، تكون هناك حالتان فقط: 0 و 1.
قراءة تنسيق ملف خارجي - يمكن قراءة تنسيقات ملف غير معايير. على سبيل المثال: عدد عشري من 9 أرقام.
تعريف منطقة البايت مشابه لتحديد بنية، ويأخذ الشكل التالي:
struct اسم بنية مناطق البايت { قائمة مناطق البايت };
شكل قائمة مناطق البايت:
محدد النوع الموضح اسم منطقة البايت: طول منطقة البايت
مثال:
struct bs{ int a:8; int b:2; int c:6; };data;
شرح data كمتغير bs، يأخذ مساحة إجمالية من اثنين من البايتات. حيث تشغل منطقة a 8 من البايتات، منطقة b تشغل 2 من البايتات، منطقة c تشغل 6 من البايتات.
دعونا نرى مثالاً آخرًا:
struct packed_struct { unsigned int f1:1; unsigned int f2:1; unsigned int f3:1; unsigned int f4:1; unsigned int type:4; unsigned int my_int:9; }; pack;
في هذا السياق، يحتوي packed_struct على 6 أعضاء: أربعة معرفات مكونة من 1 نقطه f1..f4، وواحد من 4 نقاط نوع، وواحد من 9 نقاط my_int.
هناك بعض الملاحظات حول تعريف النصائح البتية:
يمكن تخزين نصي بت في نفس الوحدة، إذا لم يكن هناك مساحة كافية في الوحدة الواحدة لتخزين نصي بت آخر، فإن النصي البت يتم تخزينه من الوحدة التالية. يمكن أيضًا تحديد بدء تخزين نصي بت من وحدة التخزين التالية. على سبيل المثال:
struct bs{ unsigned a:4; unsigned :4; /* فضاء فارغ */ unsigned b:4; /* تبدأ من وحدة التخزين التالية */ unsigned c:4 }
في تعريف هذا المجال البت، يأخذ 'a' 4 نقط من الكتروني الأول، ويملأ الـ 4 النقاط الأخرى بـ 0 لتحقيق عدم الاستخدام، وتبدأ 'b' من الكتروني الثاني، وتأخذ 4 نقاط، وتأخذ 'c' 4 نقاط.
بما أن النصائح البتية لا يمكن أن تتجاوز كلا البتين، لا يمكن أن تتجاوز طول النصائح البتية طول البت الواحد، مما يعني أن لا يمكن أن تتجاوز 8 نقط ثنائية. إذا كان الطول الأقصى أكبر من طول عدد الكتروني الكامل للحاسوب، قد يسمح بعض المحولات بالتداخل في ذاكرة المجال، وربما يخزن بعض المحولات الجزء الأكبر من المجال في الكتروني التالي.
يمكن أن تكون النصائح البتية غير مأخوذة الاسم، وفي هذه الحالة يتم استخدامها فقط كملء أو ضبط الموقع. لا يمكن استخدام النصائح البتية غير المأخوذة الاسم. على سبيل المثال:
struct k{ int a:1; int :2; /* لا يمكن استخدام الـ 2 هذا */ int b:3; int c:2; };
من خلال التحليل السابق، يمكن ملاحظة أن النصائح البتية في جوهرها نوع هيكل، ولكن أعضاؤها يتم توزيعها بشكل داخلي على الأسطر الثنائية.
استخدام النصائح البتية يشبه استخدام أعضاء الهيكل، ويكون على الشكل التالي:
اسم المتغير البتية.اسم النصي البتية اسم المتغير البتية -> اسم النصي البتية
يمكن استخدام تنسيقات متعددة للنصائح البتية.
انظر مثال التالي:
main(){ struct bs{ unsigned a:1; unsigned b:3; unsigned c:4; }; bit,*pbit; bit.a=1; /* 为位域赋值(应注意赋值不能超过该位域的允许范围) */ bit.b=7; /* 为位域赋值(应注意赋值不能超过该位域的允许范围) */ bit.c=15; /* 为位域赋值(应注意赋值不能超过该位域的允许范围) */ printf("%d,%d,%d\n",bit.a,bit.b,bit.c); /* 输出三个域的内容的整型格式 */ pbit=&bit; /* أعطيت عنوان متغير البيتة bit لعنوان المتغير الإشارة pbit */ pbit->a=0; /* أعاد تعيين جزء البيت a باستخدام طريقة الإشارة، وأعطيته قيمة 0 */ pbit->b&=3; /* تم استخدام عمليات حسابية بيتية مركبة "&="، ما يعادله: pbit->b=pbit->b&3، القيمة الأصلية في جزء البيت b هي 7، والنتيجة من عملية الجمع البياني مع 3 هي 3 (111&011=011، قيمة عشرية 3) */ pbit->c|=1; /* تم استخدام عمليات حسابية بيتية مركبة "|="، ما يعادله: pbit->c=pbit->c|1، والنتيجة هي 15 */ printf("%d,%d,%d\n",pbit->a,pbit->b,pbit->c); /* قام بإخراج القيم الثلاثة لهذه الأجزاء باستخدام طريقة الإشارة */ }
في المثال السابق، تم تعريف هيكل البتة bs مع ثلاثة أجزاء بيتية a،b،c. يوضح ذلك متغيرات النوع bs ومتغيرات الإشارة إلى النوع bs. هذا يعني أن يمكن استخدام أجزاء البيتات أيضًا بالإشارة.
نستخدم كلمة المفتاح typedef لإنشاء اسم بديل للنوع البياني. عادة ما يتم استخدامه مع الهياكل لتسهيل صياغة إعلان المتغيرات.
هذا الكود
struct Distance{ int feet; float inch; }; int main() { struct Distance d1, d2; }
يساوي
typedef struct Distance{ int feet; float inch; } distances; int main() { distances d1, d2; }
يمكنك إنشاء هيكل داخل هيكل في لغة البرمجة C. على سبيل المثال،
struct complex { int imag; float real; }; struct number { struct complex comp; int integers; } num1, num2;
افترض، أنت تريد تعيين قيمة المتغير imag الخاص ب num2 إلى 11، كيف تفعل ذلك؟ انظر إلى مثال أدناه:
num2.comp.imag = 11;
افترض أنك تريد تخزين معلومات شخص ما: اسمه، رقم بطاقة الهوية الخاصة به وسعيه. يمكنك إنشاء متغيرات مختلفة مثل name،citNo و salary لتخزين هذه المعلومات.
كيف يمكنك تخزين معلومات عدة أشخاص؟ الآن، تحتاج إلى إنشاء متغيرات مختلفة لكل شخص وللمعلومة: name1،citNo1،salary1،name2،citNo2،salary2،،، إلخ.
الطريقة الأفضل هي جمع جميع المعلومات في هيكل Person الواحد تحت اسم واحد، واستخدامه لكل شخص.