C++: تمرين: المؤشرات والمراجع الشامل

آخر تحديث: 2026-08-26

الدروس السابقة غطت المؤشرات والمراجع بشكل منفصل، لكن في البرامج الحقيقية تُستخدم معًا.

في هذا الدرس، سنتدرب على جعل المؤشرات والمراجع يعملان معًا من خلال عدة أمثلة شاملة.


1. مثال 1: عكس سلسلة باستخدام المؤشرات*

▶ مثال 1: عكس سلسلة (الصعوبة ⭐⭐)

TEXT 📖 للعرض فقط
#include <iostream>
#include <cstring>

void reverseString(char* str) {
	int len = std::strlen(str);
	char* left = str;
	char* right = str + len - 1;
	
	while (left < right) {
		// تبديل الأحرف التي يشير إليها left وright
		char temp = *left;
		*left = *right;
		*right = temp;
		
		left++;
		right--;
	}
}

int main() {
	char str[] = "Hello, World!";
	std::cout << "Before reversal: " << str << std::endl;
	
	reverseString(str);
	
	std::cout << "After reversal: " << str << std::endl;
	
	return 0;
}

الخرج:

TEXT 📖 للعرض فقط
Before reversal:
After reversal:


2. مثال 2: مصفوفة بنى ديناميكية*

▶ مثال 2: تخصيص مصفوفة طلاب ديناميكيًا (الصعوبة ⭐⭐⭐)

CPP
#include <iostream>
#include <string>

struct Student {
	std::string name;
	int age;
	double score;
};

int main() {
	int n;
	std::cout << "Enter number of students: ";
	std::cin >> n;
	
	// تخصيص مصفوفة طلاب ديناميكيًا
	Student* students = new Student[n];
	
	// إدخال معلومات الطلاب
	for (int i = 0; i < n; i++) {
		std::cout << "Enter name for student " << i + 1 << ": ";
		std::cin.ignore();
		std::getline(std::cin, students[i].name);
		
		std::cout << "Enter age: ";
		std::cin >> students[i].age;
		
		std::cout << "Enter score: ";
		std::cin >> students[i].score;
	}
	
	// إخراج جميع معلومات الطلاب
	std::cout << "\n========== Student List ==========\n";
	for (int i = 0; i < n; i++) {
		std::cout << i + 1 << ". " << students[i].name 
			<< ", Age: " << students[i].age 
			<< ", Score: " << students[i].score << std::endl;
	}
	
	// تحرير الذاكرة
	delete[] students;
	
	return 0;
}
▶ جرّب الكود

الخرج:

TEXT 📖 للعرض فقط
Enter number of students:
Enter name for student :
Enter age:
Enter score:

========== Student List ==========

. 


3. مثال 3: أساسيات القائمة المرتبطة (اختياري)*

(1) 3.1 ما هي القائمة المرتبطة؟

القائمة المرتبطة هي بنية بيانات ديناميكية — كل عنصر (عقدة) يخزن بيانات ومؤشر للعقدة التالية.

التشبيه من الواقع المكافئ البرمجي
صيد الكنز (كل دليل يشير لموقع الدليل التالي) قائمة مرتبطة

▶ مثال 3: قائمة مرتبطة بسيطة (الصعوبة ⭐⭐⭐)

TEXT 📖 للعرض فقط
#include <iostream>

struct Node {
	int data;
	Node* next;
};

int main() {
	// إنشاء عقد
	Node* head = new Node{1, nullptr};
	Node* second = new Node{2, nullptr};
	Node* third = new Node{3, nullptr};
	
	// ربط العقد
	head->next = second;
	second->next = third;
	
	// اجتياز القائمة المرتبطة
	Node* current = head;
	while (current != nullptr) {
		std::cout << current->data << " ";
		current = current->next;
	}
	std::cout << std::endl;
	
	// تحرير الذاكرة
	delete head;
	delete second;
	delete third;
	
	return 0;
}

الخرج:

TEXT 📖 للعرض فقط
 

💡 نصيحة: القوائم المرتبطة موضوع مهم في هياكل البيانات — هذه مجرد مقدمة مختصرة. ستتعلم المزيد من هياكل البيانات لاحقًا.



4. تمرين تطبيقي: دفتر العناوين (نسخة الذاكرة الديناميكية)*

▶ مثال 4: دفتر عناوين ديناميكي (الصعوبة ⭐⭐⭐)

CPP
#include <iostream>
#include <string>
#include <cstring>

struct Contact {
	char name[50];
	char phone[20];
	Contact* next; // مؤشر القائمة المرتبطة
};

Contact* head = nullptr; // مؤشر رأس القائمة المرتبطة

void addContact(const std::string& name, const std::string& phone) {
	Contact* newContact = new Contact;
	std::strcpy(newContact->name, name.c_str());
	std::strcpy(newContact->phone, phone.c_str());
	newContact->next = head; // العقدة الجديدة تشير للرأس الأصلي
	head = newContact; // تحديث الرأس
}

void printContacts() {
	if (head == nullptr) {
		std::cout << "Address book is empty!" << std::endl;
		return;
	}
	
	std::cout << "\n========== Address Book ==========\n";
	Contact* current = head;
	int index = 1;
	while (current != nullptr) {
		std::cout << index << ". " << current->name 
			<< " - " << current->phone << std::endl;
		current = current->next;
		index++;
	}
}

int main() {
	addContact("MOTO", "13800138000");
	addContact("Alice", "13900139000");
	addContact("Bob", "13700137000");
	
	printContacts();
	
	// تحرير الذاكرة (اختياري)
	// ...
	
	return 0;
}
▶ جرّب الكود

الخرج:

TEXT 📖 للعرض فقط
Address book is empty!

========== Address Book ==========

. 

❓ أسئلة شائعة

س: متى أستخدم مؤشرات مقابل مراجع؟ ج:> - إذا كان المعامل قد يُعدّل ويحتاج لتمثيل "لا شيء" (مثلاً: فشل البحث) → مؤشر (nullptr) > - إذا كان المعامل قد يُعدّل لكنه دائمًا له قيمة → مرجع > - إذا كان المعامل لا يحتاج تعديل → مرجع ثابت (موصى به) > - إذا كان تخصيص الذاكرة الديناميكية مطلوبًا → مؤشر (new) س: لماذا القوائم المرتبطة أفضل من المصفوفات؟ ج:> - المصفوفة: حجم ثابت، الإدراج/الحذف يتطلب إزاحة جميع العناصر اللاحقة (بطيء) > - القائمة المرتبطة: حجم ديناميكي، الإدراج/الحذف يتطلب تغيير المؤشرات فقط (سريع)

لكن القوائم المرتبطة لها أيضًا عيوب: لا وصول عشوائي (لإيجاد العنصر i يجب الاجتياز من الرأس).

س: كيف أتجنب تسرب الذاكرة؟ ج:> 1. تأكد من اقتران new وdelete > 2. عيّن المؤشر إلى nullptr فورًا بعد التحرير > 3. استخدم المؤشرات الذكية (std::unique_ptr، std::shared_ptr، ستُغطى لاحقًا)


س: ما الأهم في التمرين مع المؤشرات؟ ج: افهم المفاهيم الأساسية أولاً، ثم عززها من خلال أمثلة عملية.

📖 ملخص


📝 تمارين

  1. أساسي (الصعوبة ⭐): اكتب دالة void swap(int* a, int* b) تبدل قيم متغيرين باستخدام المؤشرات.

  2. متوسط (الصعوبة ⭐⭐): اكتب برنامجًا يخصص مصفوفة int ديناميكيًا، يتيح للمستخدم إدخال حجم المصفوفة ومحتوياتها، ثم يعكس المصفوفة ويُخرجها.

  3. متقدم (الصعوبة ⭐⭐⭐): وسّع برنامج "دفتر العناوين الديناميكي":

    1. أضف ميزة "حذف جهة اتصال"
    2. أضف ميزة "بحث عن جهة اتصال"
    3. حرر جميع الذاكرة المخصصة ديناميكيًا عند انتهاء البرنامج

5. 🚀 الخطوات التالية*

تهانينا! لقد أكملت جميع دروس المرحلة 4 (المؤشرات والمراجع). بعد ذلك، ندخل المرحلة 5 (البرمجة كائنية التوجه) — تعلم أقوى ميزة في C++، فهم الأصناف، الكائنات، الوراثة، وتعدد الأشكال!

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%