الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

Beware When Returning Pointers From A Function

مغلق
بدأه Robatic في 5 يناير 2008 · 1 رد · 1,579 مشاهدة · في لغة C و ++C
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم

سنرى اليوم كيفية إنشاء دالة تقوم بإرجاع مؤشر، أول شيء سيخطر على بالك قد يكون

int* somefunction();

نعم هذا صحيح ولكن هناك بعض الأشياء التي يجب وضعها في الحسبان، دعونا نكمل.

تمهيد:

قبل كل شيء دعوني أوضح ماهية العلاقة بين الـ Pointers والـ Arrays عن طريق سؤالي لكم عن ما إذا كان الكود التالي صحيح أم لا ؟

int array[100];
int* ptr = array;

نعم الكود السابق صحيح ، من هنا نرى أن هناك علاقة وطيدة بين الـ Pointers والـ Arrays

كلنا نعرف أن الـ [ ] تمكنا من الدخول على محتويات المصفوفه ولكن كيف سيكون الوضع في حالة المؤشرات ؟؟؟ دعونا نرى الكود التالي

#include <iostream>

using namespace std;

void main()
{
	int a[] = {1,2,3};
	int* ptr = a;

	for(int i = 0; i < 3; i++)
		cout << *ptr++ << endl;
}

لاحظ أنه عندما نزيد في قيمة المؤشر ptr فنحن نزيد على الموقع "Address" الذي يؤشر عليه حاليا وليس على قيمة هذا العنوان

وهذا ما يسمى بـ Pointers Arithmetic، ويمكن كتابة الكود السابق بالشكل التالي:

#include <iostream>

using namespace std;

void main()
{
	int a[] = {1,2,3};
	int* ptr = a;

	for(int i = 0; i < 3; i++)
		cout << *(ptr + i) << endl;
}

إلى هنا كل شيء على ما يرام، إسمحوا لي أن اتكلم عن نفسي قليلا

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

ثم سألت نفسي كيف أقوم بكتابة دالة تقوم بإرجاع Array ؟؟ في بداية الأمر قلت أن الفكرة بسيطة فقط أقوم بتحديد النوع ثم إستخدام العلامة [ ]

ولكن كل محاولاتي بآئت بالفشل إلى أن تعلمت المؤشرات، وبصراحة المؤشرات غيرت طريقتي ونظرتي في البرمجة بلغة C++.

الآن وقبل أن نكمل دعوني أعطيكم معلومة قد تكون قديمة للبعض منكم وهي كيفية حساب طول مصفوفة معينة بدون إستخدام المؤشرات

وتكمن الفكرة في إستخدام الدالة أول الـ Operator sizeof

هذه الدالة تقوم بحساب حجم المتغير أو حجم نوع المتغير ، إليكم الكود التالي:

#include <iostream>

using namespace std;

void main()
{
	cout << "Size of int: " << sizeof(int) << endl;
	cout << "Size of char: " << sizeof(char) << endl;
	cout << "Size of double: " << sizeof(double) << endl;
}

أعتقد ان للكود السابق قد بين فكرة عمل الدالة sizeof والآن بنفس الطريقة نقدر ان نحسب حجم الـ array ولنقل

أن لدينا array من نوع int وحجمها 100

int a[100]

لو كتبانا

sizeof a

ستكون النتيجة 400، حجم الـ int يساوي 4 إذا حجم 100 int يساوي 400، إذا لكي نحسب حجم الـ array a نكتب الكود التالي :

cout << sizeof a / sizeof(int) << endl;

عن طريق قسمة حجم الـ array على حجم نوعها

والآن دعونا نكمل إلى كيفية إرجاع مصفوفة من دالة، هذا سيكون الـ signature للدالة

returnType* function_name (params)

دعونا نحاكي السيناريو التالي:

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

#include <iostream>

using namespace std;

int* getArray() 
{
	int tempArr[10];

	for (int i = 0; i < 10; i++)
		tempArr = i + 1;

	return tempArr;
}

void printArr(int x[], int count)
{
	for (int i = 0; i < count; i++)
		cout << x << endl;
}

void main()
{
	int* arr = getArray();

	printArr(arr, 10);
}

أو أو أو ؟؟؟ لم تكن النتائج كما هي متوقعه !!!!!!!!!

هناك قاعدة في لغة C++ قول

لا تقوم بإرجاع مؤشر (تم تعريفة محليا ) من داخل دالة

Never Ever return a locally defined pointer

لحل هذه المشكلة نقوم بما يسمى Dynamic allocation وهو بكل بساطة عبارة عن حجز موقع ما في الذاكرة الحرة بحيث لا يتم حذفة بمجرد الخروج من الـ scope ولكن يتم حذفة يدويا او عند إنهاء البرنامج كاملا، وإليكم تعديل الكود السابق

#include <iostream>

using namespace std;

int* getArray() 
{
	int* tempArr = new int[10];

	for (int i = 0; i < 10; i++)
		tempArr = i + 1;

	return tempArr;
}

void printArr(int x[], int count)
{
	for (int i = 0; i < count; i++)
		cout << x << endl;
}

void main()
{
	int* arr = getArray();

	printArr(arr, 10);

	delete arr;
}

أرجوا أن تكونوا قد إستفدتم من هذا الشرح المتواضع وأرجوا من الله العلي القدير ان يكتب لي الأجر والثواب وينفعني وإياكم

أخوكم Robatic

أتمنى للجميع برمجة سعيدة

#2

السلام عليكم,,

مرحبا أخ Robatic,,

لمحة جميلة من عالم المؤشرات في ++C و شرح أجمل أخي العزيز,

في الحقيقة مشكلة إرجاع البيانات بالمرجع من الدوال هي سبب ابتكار الـ Garbage Collector بالمناسبة :D

و لا أعتقد أنه يوجد لغة غير ++C/C تمكنك من التعامل مع الذاكرة بشكل يدوي تماماً كما شرحت في الدرس,

بالمناسبة أيضاً, دائماً ما يشتكي المبرمجون من المؤشرات في ++C, رغم وجود المكتبة الرائعة STL, و لذلك تلاحظ أن معظم المشاريع الكبيرة لا تستخدم المؤشرات و المصفوفات الثابتة إلا عند وجود حالة ملحة تستدعي استخدامهما,

بدلاً من ذلك يتم استخدام الـ Vector (الذي صمم كبديل للمصفوفات العادية) لحل مشاكل إدارة الذاكرة دون التضحية بأداء البرنامج ككل B)

تحياتي ,,

تم تعديل هذه المشاركة بواسطة Khaled.Alshaya في 5 يناير 2008 في 11:46

هذا الموضوع مغلق.

مواضيع مشابهة