تجميع البيانات تحت مظلة واحدة باستخدام الـ Struct

السلام عليكم ورحمة الله وبركاته

وقت القراءة: ≈ 10 دقائق

المقدمة

شارفنا على الانتهاء من هذه السلسلة الجميلة عن أساسيات البرمجة
واليوم سيكون معنا موضوع مهم جداً وهو كيفية تجميع البيانات تحت مظلة واحدة

وهو مهم جدا لأنه سيمهد لنا الطريق للحديث عن الـ Object Oriented Programming وهو موضوع مهم جداً في عالم البرمجة وعالم كامل بحد ذاته

المهم نحن سنتحدث عن الـ Struct وهو نوع من البيانات يمكنك تعريفه بنفسك وتجميع البيانات تحته
وفي لغات أخرى يسمى Object مثل في الـ Typescript والـ Javascript

لنبدأ بالشرح ومعنا أول سؤال إذا كنت تريد بيانات مستخدم مثلاً
ماذا ستفعل ؟

ستقول لي أنا سأقوم بتعريف متغيرات لكل بيانات المستخدم
وليكن هكذا

string name = "Ahmed";
int age = 25;
string email = "[email protected]";

هذا جيد، الآن قم بتعريف بيانات أخرى لمستخدم آخر

string name2 = "Mahmoud";
int age2 = 24;
string email2 = "[email protected]";

هذا جيد أيضاً، قم بتعريف بيانات لمستخدم آخر

string name3 = "Kamal";
int age3 = 20;
string email3 = "[email protected]";

هل ترى المشكلة ؟
ستجد نفسك مع كل مستخدم تقوم بتعريف متغيرات جديدة
وتبدأ بترقيم هذه المتغيرات لتمييز بيانات كل مستخدم

هل يمكنك أن تقول لي أين المتغير الذي يحمل اسم Mahmoud ؟ ستقول لي أنه name2
هل يمكنك أن تقول لي أين البريد الإلكتروني لـ Kamal ؟ ستقول لي أنه email3

لكن هذه على مقياس بسيط جداً، ماذا لو كان لديك 100 مستخدم ؟ هل ستقوم بتعريف 100 نسخة من هذه البيانات وترقمها ؟

لنفترض أن رقمتها وسألتك أي المتغيرات الخاصة بالمستخدم الذي اسمه Kamal هل ستتذكر رقمه ؟
لنفترض أنك تذكرت رقمه وقلت لي أنه name3 هذا بسبب أنك كإنسان أو كشخص كتب هذا الكود ستجاوب على هذا السؤال
حسنًا إن سألنا نفس السؤال للبرنامج هل سيفهم أن الـ name3 يعود لـ Kamal ؟ وبالتبعية هل سيعرف أن الـ age3 والـ email3 يعود لـ Kamal ؟

سؤال أخر إن قلت لك أحضر لي أسماء كل المستخدمين الذين أعمارهم أكبر من 20 سنة كيف ستقوم بحل هذه المسألة برمجيًا ؟
المشكلة هنا أنه لا يوجد رابط حقيقي بين المتغيرات بالنسبة للغة البرمجة إنها مجرد متغيرات مختلفة عشوائية لديها، ولا يوجد شيء حقيقي يربطهم
أنت كإنسان لديك الوعي لتفهم أن الـ age2 مرتبط بـ name2 بسبب أن إسم المتغير ينتهي برقم 2
هل سيفهم البرنامج او اللغة هذا الأمر ؟

هنا يأتي دور الـ Struct ليسهل عليك تجميع البيانات تحت مظلة واحدة وتنظيمها وإدارتها

ما هو الـ Struct وكيف ننشئه ؟

الـ Struct هو نوع من الأدوات التي توفرها لغات البرمجة لتسمح لك بتعريف وتجميع البيانات تحت مظلة واحدة
وستجد في باقي اللغات يسمى Object وهو نفس الفكرة
وأيضًا عندما تدخل عالم الـ OOP ستجد شيء يدعى الـ Class وهو مشابه كثيرً للـ Struct لكن يحمل مزايا أكثر

دعنا نركز على الـ Struct ونرى كيف يمكننا استخدامه

أولاً قم بتعريف الـ Struct

struct اسم {
    // بيانات المستخدم
};

هنا لتعريف الـ Struct نقوم بكتابة الكلمة struct ثم نكتب اسم الـ Struct ونفتح قوسين المجموعة {}
وبداخل القوسين نقوم بتعريف بيانات المستخدم

هنا نحن نريد إنشاء Struct للمستخدمين
لذا بديهيًا سنسميه User ثم سنعرف بداخل بيانات مثل الإسم والعمر والبريد الإلكتروني

struct User {
    string name;
    int age;
    string email;
};

هنا قمنا بتعريف Struct يحمل اسم User ويحتوي على بيانات المستخدم
هذا مجرد تعريف لنخبر لغة البرمجة كيف سيتعامل مع الشيء المدعو User وما هي البيانات التي يحملها
لأنك كما تعرف لغات البرمجة لا تعرف ما هو User وما هي البيانات التي يحملها

على سبيل المثال البرنامج لا يفهم ما هي الحيوانات البرمجة بشكل عام لا تعرف شيء يدعى Animal
انه مصطلح نستعمله نحن البشر، لكن البرنامج لا يعرفه، الأمر مماثل للسيارات البرنامج لا يعرف شيء يدعى سيارة
بمعنى اخر أي شيء نفهمه نحن البشر البرنامج لن يفهمه

فلذلك نحتاج لشيء لوصفه للبرنامج ليعرف كيف يتعامل معاه لذا نحن نستخدم الـ Struct و الذي من خلاله نصنف أو نمثل للبرنامج الشيء الغريب عليه ونبدأ في وصفه
نمثله أي نعطيه خواص وافعال وهي المتغيرات التي تمثل خواصه والدوال التي ستمثل الافعال

مثل ما فعلنا في الـ User نحن قمنا بتعريف بيانات المستخدم
وأخبرناه أنهنك شيء يدعى User ويحمل بيانات مثل الإسم والعمر والبريد الإلكتروني

تعريف متغير من الـ Struct

بعد أن قمنا بتعريف الـ Struct نحن نستطيع الآن استخدامه كنوع بيانات جديد أي data type مثل الـ int والـ string وغيرها
ونستطيع تعريف متغيرات من نوع الـ Struct وتخزين البيانات بها

User user1;

هنا قمنا بتعريف متغير من نوع User وأسميناه user1
الأمر بسيط جداً وهو مشابه لتعريف متغير من نوع int أو string

int number;
string name;

هنا نحن نتعامل مع الـ User بنفس الطريقة كنوع بيانات نحن قمنا بإنشائها
فهنا نحن نقوم بإنشاء متغير من نوع User ونسميه user1 وهذا المتغير سيحمل بيانات المستخدم

تخزين البيانات في متغير من الـ Struct

الآن بعد بإنشاء Struct لنعرف الـ User للغة البرمجة

struct User {
    string name;
    int age;
    string email;
};

وبعد أن قمنا بإنشاء متغير من نوع User وأسميناه user1

User user1;

الآن لدينا متغير من نوع User وهو user1 ونريد تخزين بيانات المستخدم فيه
نحن نعرف أن هذا المتغير بداخله 3 متغيرات name و age و email والتي عرفناها في الـ Struct
ولذا السؤال حاليًا هو كيف نصل إلى هذه المتغيرات التي بداخل المتغير user1 ؟

الطريقة بسيطة جداً وهي عن طريقة الـ dot أي النقطة .

user1.name = "Ahmed";

لاحظ هنا أننا نقوم بكتابة اسم المتغير user1 ثم نكتب النقطة . ثم نكتب اسم المتغير الذي نريد الوصول إليه
وهنا نحن استطعنا الوصول إلى المتغير name الذي بداخل المتغير user1 وقمنا بتخزين القيمة Ahmed فيه

نستطيع الآن تخزين البيانات الأخرى بنفس الطريقة

user1.name = "Ahmed";
user1.age = 25;
user1.email = "[email protected]";

لاحظ الآن أن المتغيرات name و age و email أصبحت تنتمي إلى كيان موحد يجمعها وهو المتغير user1
وليست متفرقة كما كانت في السابقة


يمكنك اعطاء البيانات عند تعريف المتغير بشكل مباشر

User user1 = {"Ahmed", 25, "[email protected]"};

لاحظ هنا أننا نعرفها كأنها أراي ونعطيها القيم مباشرة
لكنها ليست أراي بل هي Struct ولذلك يمكنك تعريفها بهذه الطريقة
لكن هذه علي مراعاة ترتيب البيانات بالترتيب الذي تم تعريفها به في الـ Struct

بمعنى أنه أننا هنا قمنا بتعريف الـ User بالترتيب name ثم age ثم email
لذا عند تعريف المتغير user1 يجب أن نعطيه القيم بنفس الترتيب

struct User {
    string name;
    int age;
    string email;
};

User user1 = {"Ahmed", 25, "[email protected]"}; // ✅
User user2 = {25, "Ahmed", "[email protected]"}; // ❌
User user3 = {"Ahmed", "[email protected]", 25}; // ❌

User user4 = {"[email protected]", 25, "Ahmed"}; // ... ✅ لكن البريد الإلكتروني سيكون الاسم والاسم سيكون  البريد الإلكتروني

أراي من الـ Struct ؟

قلنا أن الـ Struct نستخدمه لتعريف نوع بيانات جديد للغة مثل الـ int والـ string وهذا ما قمنا به
وأنشأنا نوع بيانات جديد يدعى User

لذا طالما يمكننا عمل أراي من الـ int والـ string فهل يمكننا عمل أراي من الـ Struct ؟
الاجابة بالطبع نعم

User users[3];

هنا قمنا بتعريف أراي من الـ User وأسميناه users وطوله 3 بمعنى أنه أراي يحتوي على 3 عناصر من الـ User
بالتالي المستخدم الأول سيكون في الـ index رقم 0
والمستخدم التاني سيكون في الـ index رقم 1
والمستخدم الثالث سيكون في الـ index رقم 2

وهنا يمكنك تخزين البيانات في كل عنصر من الأراي بنفس الطريقة

users[0].name = "Ahmed";
users[0].age = 25;
users[0].email = "[email protected]";

// أو بشكل مباشر

users[1] = {"Mahmoud", 24, "[email protected]"};
users[2] = {"Kamal", 20, "[email protected]"};

حل مسألة عن طريق الـ Struct

الآن لنرجع لسؤالنا السابق إذا كان لديك 100 مستخدم كيف ستقوم بتخزين بياناتهم والوصول إليها ؟
الآن بعد أن تعرفنا على الـ Struct أظن اجابة السؤال واضحة

User users[100] = {
    {"Ahmed", 25, "[email protected]"},
    {"Mahmoud", 24, "[email protected]"},
    {"Kamal", 20, "[email protected]"},
    {"Ali", 15, "[email protected]"},
    {"Salah", 30, "[email protected]"},
    // ...
};

هنا قمنا بتعريف أراي من الـ User وطوله 100 وقمنا بتعريف بيانات المستخدمين مباشرة
كأننا الآن نمتلك قاعدة بيانات صغيرة تحتوي على 100 مستخدم

ما رأيك في السؤال الذي طرحته سابقًا أحضر لي أسماء كل المستخدمين الذين أعمارهم أكبر من 20 سنة ؟ الآن نحن نمتلك أراي من الـ User وكل مستخدم لديه بياناته الخاصة متجمعة تحت مظلة واحدة
بالتالي يمكننا الآن القيام بالعمليات البحثية والتحليلية على هذه البيانات بسهولة

تريد أن تعرف كم عدد المستخدمين الذين أعمارهم أكبر من 20 سنة ؟ حسنًا لا مشكلة
يمكننا عمل loop على الأراي ومع كل لفة نقوم بالتحقق من عمر المستخدم وإذا كان أكبر من 20 نقوم بطباعة اسمه

for (int i = 0; i < 100; i++) {
    if (users[i].age > 20) {
        cout << users[i].name << '\n';
    }
}

// OUTPUT:
// Ahmed
// Mahmoud
// Salah
// ... etc

لاحظ هنا أننا قمنا بعمل loop على الأراي بالتالي مع كل لفة سيكون users[i] هو المستخدم الذي نقف عنده لأن i هو الـ index الذي يزيد بمقدار 1 مع كل لفة
وبعد ذلك نقوم بالتحقق من عمر المستخدم بشرط بسيط users[i].age > 20 فإذا كان أكبر من 20 نقوم بطباعة اسمه


ما رأيك بسؤال آخر، ابحث عن صاحب هذا البريد الإلكتروني [email protected]
هل يمكنك القيام بذلك ؟ بالطبع يمكنك

for (int i = 0; i < 100; i++) {
    if (users[i].email == "[email protected]") {
        cout << users[i].name << '\n';
        break; // لا داعي لاستكمال البحث  طالما عثرنا على المطلوب
    }
}

هنا قمنا بعمل loop على الأراي ونقوم بالتحقق من البريد الإلكتروني لكل مستخدم
وإذا وجدنا المستخدم الذي يحمل البريد الإلكتروني المطلوب نقوم بطباعة اسمه وننهي البحث

الخاتمة

كما رأينا الـ Struct هو أداة مهمة جداً في البرمجة لتجميع البيانات تحت مظلة واحدة
وتسهل علينا الكثير من الأمور وتساعدنا في تنظيم البيانات وإدارتها والوصول إليها بسهولة
وهي تتبع مبدأ الـ Encapsulation وهو مبدأ مهم في الـ OOP وسنتحدث عنه في مقالات الـ OOP الموجودة في المدونة

هناك أمور تعمدت أن لا أتطرق لها في هذا المقال متعلقة بالـ Struct لأنها تتعلق بالـ OOP لذا سنتحدث عنها في مقالات الـ OOP
وهي مثل الـ Constructor وإنشاء دوال خاصة بالـ Struct والتي تسمى Methods وغيرها من الأمور

ويمكنك أن اريك نبذة خاطفة عن انشاء دالة خاصة بالـ Struct وهي

struct User {
    string name;
    int age;
    string email;

    void print() {
        cout << "Name: " << name << '\n';
        cout << "Age: " << age << '\n';
        cout << "Email: " << email << '\n';
    }
};

User user1 = {"Ahmed", 25, "[email protected]"};
user1.print();

هنا قمنا بإنشاء دالة داخل الـ Struct وهي print وهذه الدالة تقوم بطباعة بيانات المستخدم
وبعد ذلك قمنا بإنشاء متغير من الـ User وأسميناه user1 وقمنا بطباعة بياناته بواسطة الدالة print
وهذا مثال بسيط عن كيفية إنشاء دوال خاصة بالـ Struct

بالطبع تعمدت أن لا أتطرق لهذه الأمور لأنني أريد أن استفيض فيها في مقالات الـ OOP


بالطبع مفهوم الـ Struct ليس محصورًا في الـ C أو C++ فقط بل هو موجود في العديد من لغات البرمجة الأخرى

ففي لغة Go يوجد مفهوم الـ Struct ويكتب هكذا

type User struct {
    name string
    age int
    email string
}

user1 := User{
    name: "Ahmed",
    age: 25,
    email: "[email protected]"
}

ففي الـ Typescript والـ Javascript يوجد مفهوم الـ Object وهو نفس الفكرة
ويكتب هكذا

let user = {
  name: 'Ahmed',
  age: 25,
  email: '[email protected]',
};

وفي الـ Python يوجد مفهوم الـ Dictionary

user = {
    'name': 'Ahmed',
    'age': 25,
    'email': '[email protected]',
}

وغيرهم من اللغات الأخرى


وأيضًا يوجد عالم كامل قائم على فكرة الـ Struct وتجميع البيانات تحت مظلة واحدة وكل تلك الأمور
وهو عالم الـ Object Oriented Programming وهو شيء مهم جدًا في عالم البرمجة وستجده في أي لغة تقريبًا وهو اسلوب برمجي يعتمد على الـ Object والـ Class والـ Encapsulation والـ Inheritance والـ Polymorphism وغيرها من المفاهيم الهامة
وشرحناها في مقالات الـ OOP الموجودة في المدونة

وهذا هو النهاية لهذا المقال وأتمنى أن تكون قد استفدت منه وأن تكون قد فهمت مفهوم الـ Struct وكيفية استخدامه
لم أكن أريد أن أطيل عليك في هذا المقال لأنني أريد أن أترك لك الفرصة لتجربة الأمور بنفسك وتكتشفها بنفسك
ولأمهد لك الطريق لتتعرف على الـ OOP والعالم الجميل الذي ستدخله