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

ما هي الوظيفة في لغة C؟
وظيفة في البرمجة C الدوال هي كتلة برمجية قابلة لإعادة الاستخدام، تُسهّل فهم البرنامج واختباره، كما تُمكّن من تعديله بسهولة دون تغيير البرنامج الأصلي. تُقسّم الدوال الشيفرة البرمجية وتُجزّئ البرنامج إلى وحدات لتحقيق نتائج أفضل وأكثر فعالية. باختصار، يُقسّم البرنامج الكبير إلى برامج فرعية متعددة تُسمى دوال.
عندما تقوم بتقسيم برنامج كبير إلى وظائف مختلفة، يصبح من السهل إدارة كل وظيفة على حدة. كلما حدث خطأ في البرنامج، يمكنك بسهولة التحقق من الوظائف المعيبة وتصحيح تلك الأخطاء فقط. يمكنك بسهولة الاتصال واستخدام الوظائف كلما كانت مطلوبة مما يؤدي تلقائيًا إلى توفير الوقت والمساحة.
مكتبة مقابل. وظائف محددة من قبل المستخدم
يحتوي كل برنامج "C" على وظيفة واحدة على الأقل وهي الوظيفة الرئيسية، ولكن يمكن أن يحتوي البرنامج على أي عدد من الوظائف. الوظيفة الرئيسية () في لغة C هي نقطة البداية للبرنامج.
في البرمجة C، تنقسم الوظائف إلى نوعين:
- وظائف المكتبة
- الوظائف المعرفة من قبل المستخدم
الفرق بين المكتبة والوظائف المحددة من قبل المستخدم في لغة C هو أننا لا نحتاج إلى كتابة رمز لوظيفة المكتبة. إنه موجود بالفعل داخل ملف الرأس الذي نقوم بتضمينه دائمًا في بداية البرنامج. كل ما عليك فعله هو كتابة اسم الوظيفة واستخدامه مع بناء الجملة المناسب. Printf، scanf هي أمثلة لوظيفة المكتبة.
في حين أن الدالة المحددة من قبل المستخدم هي نوع من الدوال التي يتعين علينا فيها كتابة نص الدالة واستدعاء الدالة كلما طلبنا من الدالة إجراء بعض العمليات في برنامجنا.
إن الوظيفة المحددة من قبل المستخدم في لغة C يكتبها المستخدم دائمًا، ولكن في وقت لاحق يمكن أن تكون جزءًا من مكتبة "C". إنها ميزة رئيسية لبرمجة "C".
تنقسم وظائف برمجة C إلى ثلاثة أنشطة مثل،
- إعلان الوظيفة
- تعريف الوظيفة
- استدعاء وظيفة
إعلان الوظيفة
تعريف الدالة يعني كتابة اسم الدالة في البرنامج. وهو جزء أساسي لاستخدام الدوال في الكود. في تعريف الدالة، نحدد اسم الدالة التي سنستخدمها في برنامجنا، تمامًا كما هو الحال في تعريف المتغيرات. لا يمكننا استخدام أي دالة ما لم يتم تعريفها في البرنامج. يُطلق على تعريف الدالة أيضًا اسم "نموذج الدالة".
عادة ما تتم إعلانات الوظائف (وتسمى النموذج الأولي) فوق الوظيفة الرئيسية () وتأخذ الشكل العام:
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
نناقش تفاصيل البرنامج:
- نعلن عن متغير عالمي صحيح مع 1348 كقيمة أولية.
- نعلن ونحدد دالة test() التي لا تأخذ وسيطات ولا تُرجع قيمة. تقوم هذه الوظيفة فقط بطباعة قيمة المتغير العام لتوضيح أنه يمكن الوصول إلى المتغيرات العامة في أي مكان في البرنامج.
- نقوم بطباعة المتغير الشامل داخل الوظيفة الرئيسية.
- نستدعي دالة الاختبار لطباعة قيمة المتغير الشامل.
في لغة 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
هنا، نناقش تفاصيل البرنامج:
- نعلن عن دالتنا المضروب العودية التي تأخذ معاملًا صحيحًا وترجع مضروب هذه المعلمة. ستستدعي هذه الوظيفة نفسها وتقلل الرقم حتى الخروج أو الوصول إلى الشرط الأساسي. عندما يكون الشرط صحيحا، سيتم ضرب القيم التي تم إنشاؤها مسبقا في بعضها البعض، ويتم إرجاع القيمة العاملية النهائية.
- نعلن ونهيئ متغيرًا صحيحًا بقيمة "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
يوضح البرنامج أعلاه استخدام دالة مضمنة لجمع رقمين. وكما نرى، فقد قمنا بإرجاع عملية الجمع على رقمين داخل الدالة المضمنة فقط دون كتابة أي أسطر إضافية. أثناء استدعاء الدالة، قمنا فقط بتمرير القيم التي يتعين علينا إجراء عملية الجمع عليها.




