وظائف في برمجة C مع أمثلة: العودية والمضمنة

⚡ ملخص ذكي

الدوال في لغة البرمجة C عبارة عن كتل برمجية قابلة لإعادة الاستخدام، تقسم البرنامج الكبير إلى برامج فرعية أصغر، مما يسهل فهمها واختبارها وتعديلها. تحتوي كل دالة على جزء إعلان، وجزء تعريف، وجزء استدعاء.

  • 🧩 ما هي وظائف هذه الدوال؟ تقوم الدالة بتجميع التعليمات القابلة لإعادة الاستخدام، بحيث ينقسم البرنامج الكبير إلى برامج فرعية أصغر وأكثر قابلية للإدارة وأسهل في تصحيح الأخطاء.
  • 📚 نوعين: وظائف المكتبة مثل printf و scanf جاهزة للاستخدام، بينما الوظائف المعرفة من قبل المستخدم يكتبها المبرمج.
  • 📝 ثلاثة أجزاء: يتضمن استخدام الدالة إعلانها أو نموذجها الأولي، وتعريفها أو جسمها، والاستدعاء الذي يقوم بتشغيلها.
  • 🎯 الحجج: يتم تمرير القيم حسب الموضع، وبشكل افتراضي، حسب القيمة، لذلك يظل المتغير الأصلي دون تغيير داخل الدالة المستدعاة.
  • 🌐 مجال العمل المتغيرات المحلية موجودة فقط داخل وظيفتها، بينما تحتفظ المتغيرات العامة والثابتة بقيمها عبر البرنامج أو بين الاستدعاءات.
  • 🤖 مساعدة الذكاء الاصطناعي: يقوم برنامج GitHub Copilot والمساعدون المدعومون بالذكاء الاصطناعي بإنشاء وظائف C، واقتراح أنواع الإرجاع، والإشارة إلى عمليات الإرجاع المفقودة أو الوسائط غير المتطابقة.

وظائف في البرمجة سي

ما هي الوظيفة في لغة C؟

وظيفة في البرمجة C الدوال هي كتلة برمجية قابلة لإعادة الاستخدام، تُسهّل فهم البرنامج واختباره، كما تُمكّن من تعديله بسهولة دون تغيير البرنامج الأصلي. تُقسّم الدوال الشيفرة البرمجية وتُجزّئ البرنامج إلى وحدات لتحقيق نتائج أفضل وأكثر فعالية. باختصار، يُقسّم البرنامج الكبير إلى برامج فرعية متعددة تُسمى دوال.

ما هي الوظيفة في C

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

مكتبة مقابل. وظائف محددة من قبل المستخدم

يحتوي كل برنامج "C" على وظيفة واحدة على الأقل وهي الوظيفة الرئيسية، ولكن يمكن أن يحتوي البرنامج على أي عدد من الوظائف. الوظيفة الرئيسية () في لغة C هي نقطة البداية للبرنامج.

في البرمجة C، تنقسم الوظائف إلى نوعين:

  1. وظائف المكتبة
  2. الوظائف المعرفة من قبل المستخدم

الفرق بين المكتبة والوظائف المحددة من قبل المستخدم في لغة C هو أننا لا نحتاج إلى كتابة رمز لوظيفة المكتبة. إنه موجود بالفعل داخل ملف الرأس الذي نقوم بتضمينه دائمًا في بداية البرنامج. كل ما عليك فعله هو كتابة اسم الوظيفة واستخدامه مع بناء الجملة المناسب. Printf، scanf هي أمثلة لوظيفة المكتبة.

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

إن الوظيفة المحددة من قبل المستخدم في لغة C يكتبها المستخدم دائمًا، ولكن في وقت لاحق يمكن أن تكون جزءًا من مكتبة "C". إنها ميزة رئيسية لبرمجة "C".

تنقسم وظائف برمجة C إلى ثلاثة أنشطة مثل،

  1. إعلان الوظيفة
  2. تعريف الوظيفة
  3. استدعاء وظيفة

إعلان الوظيفة

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

عادة ما تتم إعلانات الوظائف (وتسمى النموذج الأولي) فوق الوظيفة الرئيسية () وتأخذ الشكل العام:

return_data_type function_name (data_type arguments);
  • نوع البيانات المرجعة: هو نوع البيانات لدالة القيمة التي يتم إرجاعها إلى عبارة الاستدعاء.
  • يتبع اسم الدالة: أقواس
  • يتم وضع أسماء الوسائط مع تعريفات أنواع البيانات الخاصة بها اختيارياً داخل الأقواس.

سننظر في البرنامج التالي الذي يوضح كيفية إعلان دالة مكعب لحساب قيمة مكعب لمتغير عدد صحيح

#include <stdio.h>
/*Function declaration*/
int add(int a,b);
/*End of Function declaration*/
int main() {

ضع في اعتبارك أن الدالة لا تُرجع بالضرورة قيمة. في هذه الحالة، يتم استخدام الكلمة الأساسية void.

على سبيل المثال، يشير تعريف الدالةoutput_message إلى أن الدالة لا تُرجع قيمة: voidput_message();

تعريف الوظيفة

تعريف الوظيفة يعني مجرد كتابة نص الوظيفة. يتكون نص الوظيفة من البيانات التي ستؤدي مهمة محددة. يتكون الجسم الوظيفي من جملة واحدة أو مجموعة من العبارات. وهو أيضًا جزء إلزامي من الوظيفة.

int add(int a,int b)	//function body	
{
	int c;
	c=a+b;
	return c;
}

استدعاء وظيفة

تعني استدعاءات الوظائف استدعاءات الوظائف كلما كانت مطلوبة في البرنامج. عندما نستدعي وظيفة، فإنها تؤدي عملية صُممت من أجلها. استدعاءات الوظائف هي جزء اختياري من البرنامج.

  result = add(4,5);

إليكم الكود الكامل:

#include <stdio.h>
int add(int a, int b);	//function declaration
int main()
{
	int a=10,b=20;
	int c=add(10,20); 	//function call
	printf("Addition:%d\n",c);
	getch();
}
int add(int a,int b)	//function body
{
	int c;
	c=a+b;
	return c;
}

الإخراج:

Addition:30

الحجج الوظيفية

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

بشكل افتراضي، يتم تمرير الوسائط بالقيمة، حيث يتم إعطاء نسخة من البيانات للدالة المستدعاة. ولن يتغير المتغير الذي تم تمريره فعلياً.

نحن نأخذ في الاعتبار البرنامج التالي الذي يوضح المعلمات التي تم تمريرها حسب القيمة:

int add (int x, int y); 
int main() {
  int a, b, result;
  a = 5;
  b = 10;
  result = add(a, b);
  printf("%d + %d\ = %d\n", a, b, result);
return 0;}
int add (int x, int y) { 
x += y;
  return(x);}

مخرجات البرنامج هي :

5 + 10 = 15

ضع في اعتبارك أنه تم تمرير قيم a وb لإضافة دالة ولم يتم تغييرها لأنه تم تمرير قيمتها فقط إلى المعلمة x.

نطاق متغير

النطاق المتغير يعني رؤية المتغيرات داخل كود البرنامج.

في لغة C، تكون المتغيرات المُعلنة داخل دالة ما محليةً ضمن نطاق ذلك الجزء من الكود، ولا يمكن الوصول إليها من خارج تلك الدالة. أما المتغيرات المُعلنة خارج جميع الدوال، فتكون عامة ويمكن الوصول إليها من البرنامج بأكمله. كذلك، يمكن الوصول إلى الثوابت المُعلنة باستخدام #define في بداية البرنامج من البرنامج بأكمله. لنفترض البرنامج التالي الذي يطبع قيمة المتغير العام من كلٍّ من الدالة الرئيسية (main) والدالة المُعرَّفة من قِبل المستخدم:

#include <stdio.h>
int global = 1348;
void test();
int main() {
  printf("from the main function : global =%d \n", global);
  test () ;
return 0;}

void test (){
printf("from user defined function : global =%d \n", global);}

النتيجة:

from the main function : global =1348
from user defined function : global =1348

نناقش تفاصيل البرنامج:

نطاق متغير

  1. نعلن عن متغير عالمي صحيح مع 1348 كقيمة أولية.
  2. نعلن ونحدد دالة test()‎ التي لا تأخذ وسيطات ولا تُرجع قيمة. تقوم هذه الوظيفة فقط بطباعة قيمة المتغير العام لتوضيح أنه يمكن الوصول إلى المتغيرات العامة في أي مكان في البرنامج.
  3. نقوم بطباعة المتغير الشامل داخل الوظيفة الرئيسية.
  4. نستدعي دالة الاختبار لطباعة قيمة المتغير الشامل.

في لغة C، عندما يتم تمرير الوسائط إلى معلمات الوظيفة، تعمل المعلمات كمتغيرات محلية سيتم تدميرها عند الخروج من الوظيفة.

عند استخدام المتغيرات العالميةاستخدمها بحذر لأنها قد تؤدي إلى حدوث أخطاء ويمكن أن تتغير في أي مكان في البرنامج. يجب تهيئتها قبل الاستخدام.

المتغيرات الثابتة

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

يستخدم البرنامج التالي متغيرًا ثابتًا:

#include <stdio.h>
void say_hi();
int main() {    
  int i;
  for (i = 0; i < 5; i++) { say_hi();}
   return 0;}
void say_hi() {
  static int calls_number = 1;
  printf("Hi number %d\n", calls_number);
  calls_number ++; }

يعرض البرنامج :

Hi number 1
Hi number 2
Hi number 3
Hi number 4
Hi number 5

وظائف تكرارية

لنفترض أن مضروب عدد ما يتم حسابه على النحو التالي 6! = 6 * 5 * 4 * 3 * 2 * 1.

يتم إجراء هذا الحساب بشكل متكرر بحساب الحقيقة * (الحقيقة -1) حتى تساوي الحقيقة 1.

الدالة العودية هي دالة تستدعي نفسها وتتضمن شرط خروج لإنهاء الاستدعاءات العودية. في حالة حساب الرقم العاملي، يكون شرط الخروج هو حقيقة تساوي 1. تعمل عملية التكرار عن طريق استدعاءات "التكديس" حتى يصبح شرط الخروج صحيحًا.

فمثلا:

#include <stdio.h>
int factorial(int number);
int main() {    
  int x = 6;
  printf("The factorial of %d is %d\n", x, factorial(x)); 
  return 0;}
int factorial(int number) {
 if (number == 1)    return (1); /* exiting condition */
  else
    return (number * factorial(number - 1));
}

يعرض البرنامج:

 The factorial of 6 is 720

هنا، نناقش تفاصيل البرنامج:

وظائف تكرارية

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

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

وظائف تكرارية

وظائف مضمنة

تُستخدم الوظيفة في برمجة C لتخزين التعليمات الأكثر استخدامًا. يتم استخدامه لنموذجية البرنامج.

عندما يتم استدعاء دالة، ينتقل مؤشر التعليمات إلى تعريف الدالة. بعد تنفيذ دالة، يعود مؤشر التعليمات إلى العبارة التي انتقل منها إلى تعريف الدالة.

عندما نستخدم الوظائف، فإننا نحتاج إلى وظيفة إضافية مؤشر انتقل إلى تعريف الوظيفة والعودة إلى البيان. ولإلغاء الحاجة إلى رؤوس المؤشرات هذه، نستخدم الوظائف المضمنة.

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

تُستخدم الوظائف المضمنة في الغالب للحسابات الصغيرة. فهي ليست مناسبة عندما يتعلق الأمر بالحوسبة الكبيرة.

تتشابه الدالة المضمنة مع الدالة العادية باستثناء أن الكلمة الأساسية inline توضع قبل اسم الدالة. يتم إنشاء الدوال المضمنة باستخدام بناء الجملة التالي:

inline function_name ()
{
    //function definition
}

دعونا نكتب برنامجًا لتنفيذ وظيفة مضمنة.

inline int add(int a, int b)		//inline function declaration
{
	return(a+b);
}
int main()
{
	int c=add(10,20);
	printf("Addition:%d\n",c);
	getch();
}

الإخراج:

Addition: 30

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

الأسئلة الشائعة

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

المعامل الفعلي هو القيمة الحقيقية أو المتغير الذي يمرره المستدعي أثناء استدعاء الدالة. أما المعامل الصوري فهو العنصر النائب المُسمى في تعريف الدالة التي تستقبله. ويتم التطابق بينهما حسب الموقع، الأول مع الأول، والثاني مع الثاني.

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

تُتيح الدوال إمكانية إعادة الاستخدام، بحيث يتم تشغيل كتلة واحدة عدة مرات، كما تُعزز التجزئة، مما يُقسّم البرنامج الكبير إلى أجزاء أصغر. وتُحسّن أيضًا من سهولة قراءة البرنامج، وتُبسّط عملية الاختبار والتصحيح، وتُخفي التفاصيل المعقدة تحت اسم واحد، مما يُوفّر وقت التطوير.

الدالة main() هي نقطة البداية التي يبدأ عندها كل برنامج مكتوب بلغة C تنفيذه. يستدعيها نظام التشغيل أولاً، وقيمتها المُعادة، والتي عادةً ما تكون 0، تُشير إلى نجاح العملية. قد تتطلب الدالة argc و argv لاستقبال وسائط سطر الأوامر.

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

نعم. يمكن لمساعد البرمجة المدعوم بالذكاء الاصطناعي كتابة دالة بلغة C من خلال موجه أوامر بلغة بسيطة، واقتراح المعاملات وأنواع القيم المُعادة، والإشارة إلى الأخطاء مثل عدم وجود قيمة مُعادة أو عدم تطابق الوسيط. يُنصح دائمًا بتجميع الدالة المُولّدة واختبارها قبل الاعتماد عليها.

مساعد الطيار جيثب يكتب دوال C، ويُكمل جسم الدالة من اسمها أو تعليق قصير، ويقترح التصريحات والحلقات والاستدعاءات المتكررة. غالبًا ما يُضيف نموذجًا أوليًا مطابقًا أعلى الدالة main()، مع ذلك، يُنصح بمراجعة منطقها.

تلخيص هذه التدوينة بـ: