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

مالفرق بين ان اضع الدوال فوق ال main او اسفله والاعلان فوقها

بدأه mr.4one في 25 يونيو 2010 · 34 رد · 1,684 مشاهدة · في الأسئلة المجابة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

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

اخواني جزاكم الله خير ..

بصراحه بشرح الكتاب قال لي فيه مميزات بين ان اضع الدوال تحت الـ main او فوقها ..ولكن لم افهم قصده نهائيـا ..لم يشرح بدقه .. حيث يفهم المبتدئ ..

الان مثل هذا المثال ..

ان يضع داله تحت الـ main

249226278.jpg

اريد فوائدها ومميزاتها .. ؟؟؟

وكيف تعاملها مع الذاكره وهو الاهم .. وماهي استخداماتها .. ومافرقها بينها وبين الـ داله فوق الـ main ؟

اتمنى ايضاح شامل عنها حتى اتمكن من هالدرس ..

وجزاكم الله خير ..

#2

أنا مبتدأ مثلك, لكن أعتقد أنه لا يوجد فرق.

لكن لو وضعتها تحت, يجب أن تضع prototype . و أظن هذه هي الطريقة المفضله. (كما موضحة بالكود بالأعلى)

#3

اخي جزاك الله خير .. ولكن بالكتاب عرض المميزات ولكن لا افهمها .. اطلاقا .. ولا اعتقد ان هنا بالسي بلس بلس .. طرق تتشابه .. فكل طريقه لها مميزه

واتمنى من الخبره عرضها لنا

#4

اخى الكريم تعرف ان الكومبايلر يبدأ بالترجمة من اليسار الى اليمين و من اعلى الى اسفل

و تعلم ايضا ان التنفيذ لا يبدأ الى عندما يصل الى دالة ال main

و عندما تكتب الدوال قبل ال main فأنت تضيع وقتك ووقت البرنامج فى قراءة سطور برمجية ستحتاجها بعد قليل فى برنامجك و ستعيد تنفيذها مرة اخرى عندما تنادى هذة الدوال

فمن الافضل ان تقوم بعمل Declaration للدالة قبل الmain ثم تكتب ال body الخاص بها بعد ال main

مثل اى متغير عادى نعمل له Declaration اولا قم نستخدمه فيما بعد حتى يكون البرنامج متعرف عليه مسبقا

int x;

و عندما تقوم بعمل calling للدوال يقوم البرنامج بالذهاب اليها مباشرة

تم تعديل هذه المشاركة بواسطة اسراء شلبى في 25 يونيو 2010 في 06:24

1
00020309t.gif

1958_1963.gif
#5

يعني فقط .. عشان ماتعب الذاكره . .بالترجمــه .. !!!

واعمل لها اعلان فوق الـ Main عشان اعرفـه ان فيه داله هيك .. اسمها هيك والبارمتر حقها هيك .. صح .. ؟

ولا يوجد فايده ثانيــه .. !!

وجزاكي الله الف خير ياسراء .. دائم تجاوبين ع الاسئله .

#6

اسألتك جميلة على فكرة

بتغيب عن المنتدى و بترجع بأسئلة كويسة

ربنا يوفقك

00020309t.gif

1958_1963.gif
#7

شكرا يا أستاذه إسراء :D

#8
هويدي كتب:

شكرا يا أستاذه إسراء :D

تلميذتك اخى هويدي :)

00020309t.gif

1958_1963.gif
#9

جزاك الله خيراً أخت إسراء

هناك نقاط أخرى:

1- تنظيم الشفرة وتسهيل تصحيحها.

2- ماذا لو كانت دالتان تستدعيان بعضهما، فالدالة A تستدعي الدالة B، والدالة B تستدعي الدالة A، فحينها يجب أن يكون هناك نموذج مصغر لإحداهما على الأقل، لكي تستطيعا القيام بالعملية، حيث أن الدالة حين تستدعي دالة أخرى، فإنها تبحث عنها فوقها في الشفرة، فإما أن تجد تعريف الدالة، أو أن تجد تصريحها (نموذجها المصغر Prototype)، وإما ألا تجد ما تريده، وحينها لا تعمل.

3- لا يمكنك تعريف القيم الافتراضية لبعض الوسائط إلا في النموذج المصغر (ستتعرف على هذا قريباً بإذن الله).

4- لست متأكداً، لكن أظن أنك أيضاً لا تستطيع تحديد إن كانت الدالة خطية Inline أم لا إلا في النموذج المصغر (ستتعرف على هذا أيضاً بإذن الله :D).

بالنسبة لوضع الدالة في الذاكرة، فهو على حد علمي أن الدالة توضع في مكان محدد من الذاكرة (إن لم تكن خطية Inline)، ويتم استدعاءها من ذاك المكان عند الحاجة.

1

هذه الجملة خاطئة  :wacko: 


#10

شاكر لك .. أخي عبود ..بس ياليت تشرح نقطه رقم 3 و4 .. ..

والله يوفقك .. "

#11

السلام عليكم

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

وهي ماذكرته في ردها :

اقتباس
و عندما تكتب الدوال قبل ال main فأنت تضيع وقتك ووقت البرنامج فى قراءة سطور برمجية ستحتاجها بعد قليل فى برنامجك و ستعيد تنفيذها مرة اخرى عندما تنادى هذة الدوال

هل هذا الكلام مؤكد؟

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

لذلك يقوم البرنامج بقراءة الكود كاملا عند تصريف البرنامج فقط بينما لايقوم بذلك عند تنفيذ البرنامج فهو يبدأ من الدالة الرئيسية Main ثم يرجع لأي دالة عند استدعائها من الدالة الرئيسية .

أختي الفاضلة اسراء شلبى هل أنتي متأكدة مما ذكرتيه؟

وإن كان كذلك فهل الأمر منطبق أيضا على لغات الدوت نت؟

تحياتي لكم جميعا

تم تعديل هذه المشاركة بواسطة hfsh80 في 26 يونيو 2010 في 01:33

#12

صحيح كلامك اخي ..وهذا ماتعلمته بالسي بلس بلس انه يبدا بقرائته للـ main

واتمنى ان اسراء تؤكد لناالمعلومه ..

وانا اثق بها لذلك لم اشك بردهـا ..ولكن انت شككتـني بزياده ..بمعرفتي ذلك

تم تعديل هذه المشاركة بواسطة mr.4one في 26 يونيو 2010 في 02:35

#13
اقتباس
لذلك يقوم البرنامج بقراءة الكود كاملا عند تصريف البرنامج فقط بينما لايقوم بذلك عند تنفيذ البرنامج فهو يبدأ من الدالة الرئيسية Main ثم يرجع لأي دالة عند استدعائها من الدالة الرئيسية .

أعتقد هذا ما تقصده هي بالظبط.

فعند الترجمه-التصريف (compile) - على حد كلامك و كلام الأخت إسراء - فإن المترجم يقوم بقراءة الكود سطر سطر و يحوله إلى صيغه تنفيذيه (أو MSIL في حالة .NET )

و بالتالي فإن لم يوجد prototype للدالة get_max() قبل ال main , فإن المترجم سوف يعترض على الإشاره لهذه الدالة في ال main .

أما عند التنفيذ, فيتم التنفيذ من ال main .

هل هذا صحيح يا إسراء؟ هل هذا صحيح يا أخي؟ هل هذا صحيح يا خبراءنا ؟؟

#14

اخى الكريم اولا كلامى اخدته من الجامعة اعرف انه بسيط و كنت انتظر دخول احد الخبراء

اما للنقطة التى علقت عليها

فأنا اقصد ذلك

اقتباس
لذلك يقوم البرنامج بقراءة الكود كاملا عند تصريف البرنامج فقط بينما لايقوم بذلك عند تنفيذ البرنامج فهو يبدأ من الدالة الرئيسية Main ثم يرجع لأي دالة عند استدعائها من الدالة الرئيسية .
00020309t.gif

1958_1963.gif
#15
اقتباس

شاكر لك .. أخي عبود ..بس ياليت تشرح نقطه رقم 3 و4 .. ..

بإذن الله

لعل هذا الاقتباس يوضح لك مجمل النقطة الثالثة:

اقتباس

الوسائط المفترضة Default Parameters:

يمكنك وضع قيمة مفترضة Default Value لوسيط ما بحيث إذا تم تجاهل تمرير قيمة لهذا الوسيط يتم تمرير القيمة المفترضة له. وذلك بوضع (قيمة ما =) بعد اسم الوسيط في النموذج المصغر للدالة. مثلاً:

int myFunc(int x= 10);

فهذه الدالة يمكن استدعاؤها هكذا:

c= myFunc(25);

لتكون قيمة x مساوية للـ25. أو هكذا:

c= myFunc();

لتكون قيمة x مساوية للـ10 لأنه تم تجاهل تمرير قيمة لهذا الوسيط، فتم تمرير القيمة المفترضة وهي 10.

لاحظ أن القيم المفترضة توضع في النموذج المصغر فقط، أما ترويسة الدالة فتبقى:

int myFunc(int x)

- يأخذ تعيين القيم المفترضة بالموقع وليس بالاسم، لذلك ليس من الضروري أن يطابق اسم الوسيط في النموذج المصغر اسمه في التعريف.

- عند تعيين قيمة مفترضة لوسيط ما، يجب تعيين قيم مفترضة لكل الوسائط بعده.

- في حال كان هناك أكثر من وسيط مفترض في دالة واحدة، فلا يمكن عند الاستدعاء تمرير قيمة لأحد هذه الوسائط المفترضة دون تمرير قيمة للوسيط المفترض الذي يسبقه.

وهذا لتوضيح النقطة الرابعة:

اقتباس

الدوال الخطية Inline Functions:

عند تعريف دالة، يقوم المترجم بإنشاء نسخة منها في الذاكرة، ويقفز إليها كلما تم استدعاء هذه الدالة.

بعض الدوال تكون صغيرة، وسيكون القفز إليها في كل استدعاء مضيعة للوقت، لذلك يمكن جعلها خطية Inline بحيث يقوم المترجم عند التنفيذ بنسخ تعليماتها كما هي، ووضعها في كل مكان يتم استدعاؤها فيه، وذلك بوضع كلمة inline قبل نوع إرجاع الدالة في النموذج المصغر. كالتالي على سبيل المثال:

inline int myFunc(int a);

- قد يتجاهل المترجم كون دالة ما خطية ويتعامل معها على أنها دالة عادية في حال وجد حجمها كبيراً جداً.

والله أعلم

لاحظوا إخواني أن أهم نقطة قد تكون أن الدالة التي يتم استدعاؤها يجب أن تكون قبل الدالة المستدعية، أو أن يكون نموذجها المصغر قبلها، لست متأكداً، لكن السبب قد يكون أن الـStack الخاص بها لا ينشأ في الذاكرة إلا عند تصريحها، فإذا أرادت دالة أخرى استدعاءها ولم يكن الـStack الخاص بها موجوداً في الذاكرة بعد، فسيحدث خطأ.

هذا استنتاج شخصي، والله تعالى أعلم.

تم تعديل هذه المشاركة بواسطة Abboodd في 26 يونيو 2010 في 12:02

1

هذه الجملة خاطئة  :wacko: 


#16

جزاك الله الف خير اخوي عبود ..

بس بكلامك .. قلت الداله ( ألخطيه ) يعني اكيد في انواع اخرى لدوال .. ياليت تذكرها .. وتذكر وش الفرق بينهم .. مع مثال بسيط جدا ولو سطـر ..

#17

الدوال من هذه الناحية تقسم فقط إلى عادية وخطية -على حد علمي-

الفرق بينهما:

الدوال العادية: يختار لها مكان محدد في الذاكرة، يتم استدعاؤها منه.

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

أذكر أن السؤال كان في البداية عن النماذج المصغرة :)

أمزح معك فقط، لكن المسير التسلسلي في التعلم أفضل من تجميع المعلومات من هنا وهناك :)

بالتوفيق

1

هذه الجملة خاطئة  :wacko: 


#18

جزاك الله الف خير اخوي عبوود .. فعـلا .. افدتني .."

واتمنى احـد الاخوه ع طاري الدوال .. يفيدني بـ هذه الداله انا كتبتهــا بنفسي .. من استنتاجي .. بس ماني مستعوبه مع انه من استنتاجي

#include<iostream>
using namespace std;

void str(int &x)
{
	x=5;
}
void main()
{
	int r=3;
	str(r);
	cout<<r;

}

الحين ارسلت المتغير r الى االداله ( سؤال الاول : هل ارسلت المتغير r ام قيمتـه ولماذا ) (وكيف استقبل x الموقع مع انه ليس مؤشر ) .. وشكرا

#19
mr.4one كتب:

جزاك الله الف خير اخوي عبوود .. فعـلا .. افدتني .."

واتمنى احـد الاخوه ع طاري الدوال .. يفيدني بـ هذه الداله انا كتبتهــا بنفسي .. من استنتاجي .. بس ماني مستعوبه مع انه من استنتاجي

#include<iostream>
using namespace std;

void str(int &x)
{
	x=5;
}
void main()
{
	int r=3;
	str(r);
	cout<<r;

}

الحين ارسلت المتغير r الى االداله ( سؤال الاول : هل ارسلت المتغير r ام قيمتـه ولماذا ) (وكيف استقبل x الموقع مع انه ليس مؤشر ) .. وشكرا

هنا pass by referance

يعنى بعت المتغير نفسه وتغير فيه زى ما انت عاوز

ولم الداله تغير فيه هياثر على المتغير الاصلى اللى هو r يعنى هنا هيطبع 5

انما اذا عملت pass by value فانت بعت قيمته بس

وغيرت القيمه دى زى ما انت عاوز لكن مش اثرت هناك لانك اسااسا باع مثلالا 3 وليس اسم المتغير الذى يحمل الـ 3 اللى هو ف حالتنا r

وفى تلك الحاله هيطبع 3 الكود الخاص بهذه الحاله انك تحذف علامه & من الكود بتاعك

هيكون كدا

#include<iostream> 
using namespace std; 

void str(int x) 
{ 
        x=5; 
} 
void main() 
{ 
        int r=3; 
        str(r); 
        cout<<r; 
 // here print r=3 not 5 as this is call by value
}

يعنى ايه سوالك التانى هذا

(وكيف استقبل x الموقع مع انه ليس مؤشر )

مو فاهمك

ممكن توضح كى افيدك ان شاء الله

او احد الاخوه يكون فهم السوال يفيدك ان شاء الله

تم تعديل هذه المشاركة بواسطة Mahmoud Kelany في 26 يونيو 2010 في 23:02

1 −1

Software Developer
Mahmoudkelany.com


 

#20

جزاك الله خيراً أخ محمود، كفيت ووفيت :)

اقتباس

يعنى ايه سوالك التانى هذا

(وكيف استقبل x الموقع مع انه ليس مؤشر )

عندما ترسل الوسيط إلى الدالة، إما أن ترسله بالقيمة By Value، وحينها ما سيتم هو نسخ قيمته وإرسالها إلى الدالة.

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

بالتوفيق

هذه الجملة خاطئة  :wacko: 


#21

انا فاهم اني ارسلت بالمرجع ياخوان ..

وانا ارســلت موقع الـr والمعروف الذي يستقبل المواقع هو المؤشر .. المؤشر هو قيمته ( موقع لمتغير اخر ) صحيح .. ؟ فـ كيف بـ متغير يستقبل موقع متغير اخر .. ؟

وانا اعلم اني وضعت &X ولكن يبقى متغير .. ؟؟

هل بالمعنى ان عندما كتبت &x انه سوف يستقبل الموقع ؟ وليس القيمه ؟؟ اي ان الداله هي الي تختار من المرسل ماتريد .. .!!! موقع او قيمه

#22

اخى الكريم انت عندما تكتب هكذا

void str(int &x)

فأنت تقوم بارسال قيمة المتغير نفسه الى الدالة

و ليس نسخة من قيمته

و اى تغير سيحدث فى القيمة داخل الدالة سنعكس بدوره على المتغير

اى لو اضفنا اى قيمة سنجد ان قيمة المتغير نفسه قد زادت

دعنا نحلل الكود

عندما كتبت هكذا

int r=3;
        str(r);

فأنت ارسلت المتغير r نفسة الى الدالة و ليس نسخة من قيمتة

و نجد ان بداخل الدالة قمنا بعمل

    x=5;

اى قمنا بتغيير قيمة المتغير r نفسه

اى ان هذا التغير انعكس على المتغير r فيصبح قيمته 5

اما عن هذا السؤال

اقتباس

(وكيف استقبل x الموقع مع انه ليس مؤشر )

فأنت تقوم بعمل متغير اخر

و تقوم بكتابة هذا الكود

int address=&x;

نجد هنا ان قيمة المتغير address تحتوى على عنوان المتغير x فى الذاكرة و ليس القيمة الذى يحتويها العنوان

فقط

00020309t.gif

1958_1963.gif
#23

عفواً أخت إسراء لم يكن ردك موجوداً حين كتبت ردي.

اقتباس

لاحظ أن المرجع هو فعلياً عبارة عن اسم مستعار Alias للمتغير، فهو المتغير نفسه في الذاكرة، لكن باسم آخر.

حين تضع &، فأنت ترسل بالمرجع، أي أن المتغير كما هو يدخل في الدالة.

ربما يمكننا القول:

إذا أرسلت بالقيمة، أي بدون * وبدون &، فأنت لم ترسل إلا قيمة المتغير، والدالة تنسخ هذه القيمة وتتعامل معها كمتغير محلي فيها.

إذا أرسلت بالمؤشر، أي بوضع *، فعندها أنت ترسل موقع أو عنوان Address المتغير، والدالة ستتعامل مع المؤشر على أنه عنوان للمتغير الأصلي، وبالتالي يمكنك التغيير في المتغير، وذلك بواسطة المؤشر الذي يشير إليه.

إذا أرسلت بالمرجع، أي بوضع &، فعندها يمكنك القول إنك قد أرسلت المتغير نفسه كما هو ووضعته في الدالة، وبالتالي يمكنك التغيير عليه.

وبالتالي، لتغيير قيمة متغير مرسل إلى دالة، يجب أن يأتي هو بنفسه (عن طريق المرجع)، أو أن نأتي بعنوانه (عن طريق المؤشر). أما إذا أتينا بنسخة عنه (عن طريق القيمة)، فإن أي تغيير نقوم به سيكون على هذه النسخة وليس على المتغير نفسه.

أرجو أن أكون قد أفدت

والله تعالى أعلم.

بالتوفيق

تم تعديل هذه المشاركة بواسطة Abboodd في 26 يونيو 2010 في 23:56

هذه الجملة خاطئة  :wacko: 


#24
اقتباس
فـ كيف بـ متغير يستقبل موقع متغير اخر .. ؟

هكذا

int address=&x;

اقتباس
ا كتبت &x انه سوف يستقبل الموقع

نعم

اقتباس
؟ اي ان الداله هي الي تختار من المرسل ماتريد .. .!!! موقع او قيمه

لا

اخى الكريم انت عندما تكتب هكذا

void str(int &x)

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

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

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

انت تعلم لو كتبت هكذا داخل ال main

int x;

و قمت بداخل دالة اخرى و كتبت نفس السطر

int x;

سيقوم البرنامج بحجز مكانين فى الذاكرة

مكان للمتغير الاول و مكان للمتغير الثانى

و البرنامج يتعامل مع عنواين متغيرات و ليس اسماء

اما لو كنت كتبت هكذا

void str(int x)

فأنت قد ارسلت نسخة من قيمة المتغير r فقط

و سيقوم البرنامج بحجز مكان فى الذاكرة للمتغير xو يضع فيه القيمة المنسوخة

00020309t.gif

1958_1963.gif
#25
اقتباس
ذا أرسلت بالقيمة، أي بدون * وبدون &، فأنت لم ترسل إلا قيمة المتغير، والدالة تنسخ هذه القيمة وتتعامل معها كمتغير محلي فيها.

إذا أرسلت بالمؤشر، أي بوضع *، فعندها أنت ترسل موقع أو عنوان Address المتغير، والدالة ستتعامل مع المؤشر على أنه عنوان للمتغير الأصلي، وبالتالي يمكنك التغيير في المتغير، وذلك بواسطة المؤشر الذي يشير إليه.

إذا أرسلت بالمرجع، أي بوضع &، فعندها يمكنك القول إنك قد أرسلت المتغير نفسه كما هو ووضعته في الدالة، وبالتالي يمكنك التغيير عليه.

وبالتالي، لتغيير قيمة متغير مرسل إلى دالة، يجب أن يأتي هو بنفسه (عن طريق المرجع)، أو أن نأتي بعنوانه (عن طريق المؤشر). أما إذا أتينا بنسخة عنه (عن طريق القيمة)، فإن أي تغيير نقوم به سيكون على هذه النسخة وليس على المتغير نفسه.

اعتقد الرد محتاج مراجعة

رفع حالة التأهب :ph34r:

00020309t.gif

1958_1963.gif

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

عدد الزوار حالياً

المتواجدون خلال آخر دقيقتين · يتحدّث كل ٣٠ ثانية

—الإجمالي—أعضاء مسجّلون—زوار بدون تسجيل

جارٍ التحقق من المتواجدين…