C++ التعامل مع المصفوفات
مفهوم المصفوفات في C++
المصفوفة ( Array ) عبارة عن متغير واحد يتألف من عدة عناصر ( Elements ) من نفس النوع.
و كل عنصر في المصفوفة يمكن تخزين قيمة واحدة فيه.
عناصر المصفوفة تتميز عن بعضها من خلال رقم محدد يعطى لكل عنصر يسمى index.
أول عنصر في المصفوفة دائماً يكون رقمه 0.
الآن, عليك معرفة أن عدد عناصر المصفوفة ثابت, أي بمجرد أن قمت بتحديده لا يمكنك تغييره من جديد, مع الإشارة إلى أنك تستطيع تغيير قيم هذه العناصر متى شئت.
فوائد المصفوفات
تقليل عدد المتغيرات المتشابهة, فمثلاً إذا كنا نريد تعريف 10 متغيرات نوعهم
int, نقوم بتعريف مصفوفة واحدة تتألف من 10 عناصر.التعامل مع الكود يصبح أسهل, لأنك إذا قمت بتخزين المعلومات داخل مصفوفة, تستطيع تعديلهم, مقارنتهم أو جلبهم كلهم دفعة واحدة بكود صغير جداً باستخدام حلقة.
تستطيع الوصول لأي عنصر من خلال رقم الـ index الخاص به.
تعريف مصفوفة في C++
هناك ثلاث طرق يمكنك اتباعها لتعريف مصفوفة (Declare Array) جديدة سنتعرف عليها تباعاً.
datatype[size] arrayName;
// الأسلوب التالي يستخدم لتعريف مصفوفة مع تحديد قيمها الأولية
datatype[] arrayName = {value1, value2, ..};
// الأسلوب التالي يستخدم لتعريف مصفوفة مع تحديد عدد عناصرها و قيمة بعض عناصرها
datatype[size] arrayName = {value1, value2, ..};
datatype: هو نوع القيم التي يمكن تخزينها في عناصر المصفوفة.
size: هو عدد عناصر المصفوفة.
arrayName: هو إسم المصفوفة.
[]: هذا الرمز يمثل من كم بعد تتألف المصفوفة.
أمثلة حول طريقة تعريف مصفوفة أحادية ( One Dimensional Array ).
أمثلة
// و تتألف من 5 عناصر int نوعها ,arr هنا قمنا بتعريف مصفوفة ذات بعد واحد إسمها
int arr[5];
// و وضعنا فيها 6 عناصر, و هذا يعني أن عدد عناصرها أصبح 6 لأننا لم نحدد عدد عناصرها int نوعها ,arr هنا قمنا بتعريف مصفوفة ذات بعد واحد إسمها
int arr[] = {1, 2, 3, 4, 5, 6};
// و تتألف من 5 عناصر, و قمنا بوضع قيم أولية في أول 3 عناصر فيها int نوعها ,arr هنا قمنا بتعريف مصفوفة ذات بعد واحد إسمها
int arr[5] = {1, 2, 3};
أمثلة حول طريقة تعريف مصفوفة ثنائية ( Two Dimensional Array ).
أمثلة
// و تتألف من 3 × 4 عناصر int نوعها ,arr هنا قمنا بتعريف مصفوفة ذات بعدين إسمها
int arr[4][3];
// وضعنا فيها مصفوفتين تتألف كل واحدة منهما من 3 عناصر, هذا يعني أن المصفوفة تتألف من 2 × 3 عناصر int نوعها ,arr هنا قمنا بتعريف مصفوفة ذات بعدين إسمها
int arr[][] = {
{1, 2, 3},
{4, 5, 6}
};
// و تتألف من 3 × 4 عناصر, وقمنا بوضع 6 قيم أولية فيها int نوعها ,arr هنا قمنا بتعريف مصفوفة ذات بعدين إسمها
int arr[4][3] = {
{1, 2, 3},
{4, 5, 6}
};
الوصول لعناصر المصفوفة في C++
لنفترض الآن أننا قمنا بتعريف مصفوفة نوعها int, إسمها a, و تتألف من 5 عناصر.
int a[] = { 10, 20, 30, 40, 50 };
يمكنك تصور شكل المصفوفة a في الذاكرة كالتالي.
بما أن المصفوفة تتألف من 5 عناصر, تم إعطاء العناصر أرقام indexes بالترتيب من 0 إلى 4.
إذاً هنا أصبح عدد عناصر المصفوفة يساوي 5 و هو ثابت لا يمكن تغييره لاحقاً في الكود.
و للوصول لقيمة أي عنصر نستخدم index العنصر الذي تم إعطاؤه له.
في المثال التالي, قمنا بتعريف مصفوفة, ثم غيرنا قيمة العنصر الأول فيها, و من ثم عرضنا قيمة جميع العناصر.
مثال
#include <iostream>
using namespace std;
int main()
{
// هنا قمنا بتعريف مصفوفة تتألف من 5 عناصر
int arr[] = {10, 20, 30, 40, 50};
// هنا قمنا بتغيير قيمة العنصر الأول و العنصر الأخير في المصفوفة
arr[0] = 1;
arr[4] = 5;
// هنا قمنا بعرض قيم جميع عناصر المصفوفة
cout << "arr[0] = " << arr[0] << endl;
cout << "arr[1] = " << arr[1] << endl;
cout << "arr[2] = " << arr[2] << endl;
cout << "arr[3] = " << arr[3] << endl;
cout << "arr[4] = " << arr[4] << endl;
return 0;
}
•سنحصل على النتيجة التالية عند التشغيل
arr[0] = 1 arr[1] = 20 arr[2] = 30 arr[3] = 40 arr[4] = 5
طريقة وضع قيم أولية لعناصر المصفوفة في C++
إذا قمت بإنشاء مصفوفة جديدة مع تحديد عدد عناصرها فقط و بدون إعطائها قيم أولية, من المحتمل أن تجد قيم غريبة في بعض عناصرها.
سبب ذلك أن هذه القيم كانت موجودة مسبقاً في الذاكرة لا أكثر.
لذا في حال أردت إنشاء مصفوفة جديدة مع حذف أي قيم إفتراضية قد تكون موجودة فيها, يجب أن تقوم بتمرير القيمة الإفتراضية التي تريد وضعها لعناصر المصفوفة لحظة إنشائها.
في المثال التالي, قمنا بتعريف مصفوفة تتألف من 5 عناصر و لم نعطها قيم أولية, ثم قمنا بعرض القيم الإفتراضية الموجودة فيها.
المثال الأول
#include <iostream>
using namespace std;
int main()
{
// هنا قمنا بتعريف مصفوفة تتألف من 5 عناصر
int arr[5];
// هنا قمنا بعرض القيم الإفتراضية الموجودة في عناصر المصفوفة
cout << "arr[0] = " << arr[0] << endl;
cout << "arr[1] = " << arr[1] << endl;
cout << "arr[2] = " << arr[2] << endl;
cout << "arr[3] = " << arr[3] << endl;
cout << "arr[4] = " << arr[4] << endl;
return 0;
}
•عند تشغيل البرنامج حصلنا على نتيجة غريبة حيث وجدنا قيم إفتراضية في بعض العناصر.
•ملاحظة: من الطبيعي أن لا تظهر لك نفس النتيجة التي ظهرت لنا لأن هذه القيم هي قيم عشوائية.
arr[0] = 8 arr[1] = 0 arr[2] = 42 arr[3] = 0 arr[4] = 15275776
في المثال التالي قمنا بوضع القيمة 0 كقيمة أولية لجميع عناصر المصفوفة, ثم قمنا بعرض قيمها.
المثال الثاني
#include <iostream>
using namespace std;
int main()
{
// هنا قمنا بتعريف مصفوفة تتألف من 5 عناصر مع تحديد أن القيمة الإفتراضية في جميع عناصرها هي 0
int arr[5] = {0};
// هنا قمنا بعرض القيم الإفتراضية الموجودة في عناصر المصفوفة
cout << "arr[0] = " << arr[0] << endl;
cout << "arr[1] = " << arr[1] << endl;
cout << "arr[2] = " << arr[2] << endl;
cout << "arr[3] = " << arr[3] << endl;
cout << "arr[4] = " << arr[4] << endl;
return 0;
}
•سنحصل على النتيجة التالية عند تشغيل البرنامج.
arr[0] = 0 arr[1] = 0 arr[2] = 0 arr[3] = 0 arr[4] = 0
طريقة معرفة عدد عناصر المصفوفة في C++
إذا أردت معرفة عدد عناصر أي مصفوفة, يمكنك الحصول عليه من خلال قسمة حجم المصفوفة, على نوع العناصر المخزنة فيها.
مثال
#include <iostream>
using namespace std;
int main()
{
// هنا قمنا بتعريف مصفوفة تتألف من 5 عناصر مع تحديد أن القيمة الإفتراضية في جميع عناصرها هي 0
int arr[] = {1, 2, 3, 4, 5};
// n على حجم نوع أول عنصر فيها, و من ثم قمنا بتخزين الناتج في المتغير arr هنا قمنا بقسمة عدد عناصر المصفوفة
int n = sizeof(arr) / sizeof(arr[0]);
// n الذي قمنا بتخزينه في المتغير arr هنا قمنا بطباعة عدد عناصر المصفوفة
cout << "Number of elements in the array is: " << n;
return 0;
}
•سنحصل على النتيجة التالية عند تشغيل البرنامج.
Number of elements in the array is: 5
و هذه بعض الطرق الأخرى التي قد تجد أنها تستخدم لمعرفة أحجام المصفوفات.
// يمكنك الحصول على عدد عناصر المصفوفة مهما كان نوعها من خلال الأسلوب التالي sizeof(arrayName) / sizeof(arrayElement[0]) // يمكنك أن تستخدم الأسلوب التالي int إذا كان نوع المصفوفة هو sizeof(arrayName) / sizeof(int) // يمكنك أن تستخدم الأسلوب التالي string إذا كان نوع المصفوفة هو sizeof(arrayName) / sizeof(string)
ملاحظة
الأسلوب الذي استخدمناه لمعرفة عدد عناصر المصفوفة يمكن تطبيقه على أي نوع بيانات آخر و لكن لا يمكن استخدامه مع المؤشرات ( Pointers ) و التي سنتعرف عليها في دروس لاحقة.
التعامل مع المصفوفة بواسطة حلقة في C++
عند التعامل مع المصفوفات فإنك على الأغلب ستستخدم حلقة للمرور على قيمها سواء للبحث عن قيمة فيها, تحديث قيمها, أو لمجرد طباعة القيم الموجودة فيها.
في المثال التالي إفترضنا أن عدد عناصر المصفوفة التي سنعرض قيمها معروف.
المثال الأول
#include <iostream>
using namespace std;
int main()
{
// هنا قمنا بإنشاء مصفوفة تحتوي على 3 قيم نصية
string fruits[3] = {"Apple", "Banana", "Orange"};
// على سطر جديد fruits هنا قمنا بإنشاء حلقة, في كل دورة تقوم بعرض قيمة من القيم الموجودة في المصفوفة
for (int i=0; i<3; i++)
{
cout << fruits[i] << endl;
}
return 0;
}
•سنحصل على النتيجة التالية عند التشغيل
Apple Banana Orange
في المثال التالي إفترضنا أن عدد عناصر المصفوفة التي سنعرض قيمها غير معروف.
المثال الثاني
#include <iostream>
using namespace std;
int main()
{
// هنا قمنا بإنشاء مصفوفة تحتوي على 3 قيم نصية
string fruits[] = {"Apple", "Banana", "Orange"};
// n و من ثم تخزينه في المتغير fruits هنا قمنا بحساب عدد عناصر المصفوفة
int n = sizeof(fruits) / sizeof(fruits[0]);
// على سطر جديد fruits هنا قمنا بإنشاء حلقة, في كل دورة تقوم بعرض قيمة من القيم الموجودة في المصفوفة
for (int i=0; i<n; i++)
{
cout << fruits[i] << endl;
}
return 0;
}
•سنحصل على النتيجة التالية عند التشغيل
Apple Banana Orange
الحلقة foreach في C++
إبتداءاً من إصدار المترجم C++ 11 تم إضافة حلقة for جديدة إسمها Foreach Loop.
هذه الحلقة تسمح لك بالمرور على جميع عناصر المصفوفة دون الحاجة لتعريف عداد و تحديد أين يبدأ و أين ينتهي.
طريقة تعريف الحلقة Foreach
{
    // statements
}
element: هو متغير عادي نقوم بتعريفه بداخل الحلقة و نعطيه نفس نوع المصفوفة التي نضعها بعد النقطتين, لأنه في كل دورة سيقوم بتخزين قيمة عنصر من عناصرها, لذلك يجب جعل نوعه مثل نوعها.
array: هي المصفوفة التي نريد الوصول لجميع عناصرها.
statements: هي جميع الأوامر الموضوعة في الحلقة و هي تتنفذ في كل دورة.
إذاً هنا تقوم الحلقة بالمرور على جميع عناصر المصفوفة بالترتيب من العنصر الأول إلى العنصر الأخير, و في كل دورة تقوم بتخزين قيمة العنصر في المتغير الذي قمنا بتعريفه.
سنقوم الآن بكتابة برنامج بسيط يعرض قيم جميع عناصر مصفوفة باستخدام الحلقة Foreach.
مثال
#include <iostream>
using namespace std;
int main()
{
// هنا قمنا بإنشاء مصفوفة تحتوي على 3 قيم نصية
string fruits[] = {"Apple", "Banana", "Orange"};
// element في المتغير fruits هنا في كل دورة سيتم تخزين قيمة عنصر من عناصر المصفوفة
for (string element: fruits)
{
// element هنا سيتم عرض القيمة التي تخزنت في المتغير
cout << element << endl;
}
return 0;
}
•سنحصل على النتيجة التالية عند التشغيل
Apple Banana Orange
في دروس لاحقة ستتعلم كيف تمرر مصفوفة لدالة و كيف تعرّف مصفوفة ترجع دالة.
بالإضافة إلى ذلك, ستتعرف على أنواع أخرى من المصفوفات ليس لها أحجام محددة و يمكن التعامل معها بحرية أكثر.
C++ إدخال بيانات من المستخدم
مقدمة
في الدروس السابقة, كنا نكتب الكود ثم نقوم بتجربته فيتنفذ كما هو, بمعنى أننا كنا أصلاً نعرف ما سيظهر عند تشغيل الكود لأننا كنا نقوم بتحديد قيم المتغيرات قبل تشغيل البرنامج.
في هذا الدرس ستتعلم كيف تنشئ برنامح يتفاعل مع المستخدم, حيث أنك عندما تقوم بتشغيله سيطلب من المستخدم إدخال بيانات, و بعد إدخالها سيقوم البرنامج بمعالجتها و فعل شيء معين بها.
أمر الإدخال cin في C++
لجعل المستخدم قادر على إدخال بيانات في البرنامج أثناء اشتغاله نستخدم أمر الإدخال cin >>.
الأمر cin موجود في الحزمة std و لهذا يجب ان تكتب std::cin إن لم تكن تريد تضمين الحزمة std في برنامجك.
في كل مرة تقوم فيها باستدعاء هذا الأمر يقوم المترجم بانتظارك لإدخال عدد أو كلمة واحدة من لوحة المفاتيح ( Keyboard ).
بعد الإنتهاء من الإدخال و النقر على الزر Enter سيتم إرجاع الشيء الذي قمت بإدخاله في المكان الذي تم منه إستدعاء الأمر cin >>.
مثال
#include <iostream>
using namespace std;
int main()
{
// لتخزين المعلومات التي سيدخلها المستخدم لاحقاً age و name قمنا بتجهيز المتغيرين
string name;
int age;
// name هنا سيطلب من المستخدم إدخال إسمه و من ثم سيتم تخزين الإسم الذي يدخله في المتغير
cout << "What's your name? ";
cin >> name;
// age هنا سيطلب من المستخدم إدخال عمره و من ثم سيتم تخزين الرقم الذي يدخله في المتغير
cout << "How old are you? ";
cin >> age;
// في الأخير قمنا بعرض المعلومات التي يدخلها المستخدم بشكل مرتب
cout << "Your name is " << name << ", and your age is " << age << " years.";
return 0;
}
•سنحصل على النتيجة التالية عند التشغيل مع الإشارة إلى أننا قمنا بتعليم البيانات التي إنتظرنا البرنامج لإدخالها من لوحة المفاتيح باللون الأصفر.
How old are you? 25
Your name is Mhamad, and your age is 25 years.
الفرق بين الأمر cin و الأمر cout
في البداية معرفة سبب تسمية الأوامر بهذه الكلمات سيسهل عليك تذكر الفرق بينهما, لذا تذكر دائماً أصلهما:
cinيقصد بها كلمة See In و التي بدورها تستخدم لإدخال قيمة في المتغير.coutيقصد بها كلمة See Out و التي بدورها تستخدم للحصول على قيمة المتغير.
الأمر cin نضع بعده إسم المتغير الذي سنخزن القيمة التي يدخلها المستخدم فيها و تكون الأسهم باتجاه اليمين كالتالي.
// x قم بتخزين ما سيدخله المستخدم في المتغير cin >> x;
الأمر cout نضع بعده أي شيء نريد عرضه أو أي متغير نريد عرض قيمته و تكون الأسهم باتجاه اليسار كالتالي.
// x قم بعرض القيمة المدخلة في المتغير cout << "x = " < < a;
المشاكل التي يسببها إدخال مسافات فارغة
تذكر دائماً أن الأمر cin >> يستخدم لإدخال رقم أو كلمة واحدة فقط بمعنى أنه لا يجب أن يحتوي ما تدخله على مسافات فارغة.
في حال كان ما أدخلته يحتوي على مسافات فارغة, سيسبب ذلك مشاكل في الكود لأن المترجم سيعتبر أنك تحاول إدخال مجموعة قيم و ليس قيمة واحدة.
عندما يجدك المترجم قمت بإدخال مجموعة قيم في ذات الوقت الذي تحاول فيه أن تخزن قيمة واحدة فقط في متغير, سيعتبر أنك تريد إدخال القيم الأخرى في المرات القادمة التي تطلب فيها من المستخدم أن يدخل قيم.
في المثال التالي, قمنا بإنشاء برنامج يطلب من المستخدم إدخال إسمه و بريده الإلكتروني, بعدها يعرض له ما قام بإدخاله.
عند تشغيل البرنامج سنتعمد إدخال إسم المستخدم الكامل (إسمه و إسم عائلته) مع وضع مسافة فارغة بينهما حتى ترى الخطأ الذي سيحدث.
مثال
#include <iostream>
using namespace std;
int main()
{
// لتخزين المعلومات التي سيدخلها المستخدم لاحقاً email و name قمنا بتجهيز المتغيرين
string name;
string email;
// name هنا سيطلب من المستخدم إدخال إسمه و من ثم سيتم تخزين الإسم الذي يدخله في المتغير
cout << "Enter your name: ";
cin >> name;
// email هنا سيطلب من المستخدم إدخال بريده الإلكتروني و من ثم سيتم تخزين البريد الذي يدخله في المتغير
cout << "Enter your email: ";
cin >> email;
// في الأخير قمنا بعرض المعلومات التي يدخلها المستخدم بشكل مرتب
cout << "\n\n---------------------";
cout << "\nName = " << name;
cout << "\nEmail = " << email;
return 0;
}
•سنحصل على النتيجة التالية عند التشغيل مع الإشارة إلى أننا قمنا بتعليم البيانات التي إنتظرنا البرنامج لإدخالها من لوحة المفاتيح باللون الأصفر.
Enter your email: <- لاحظ أنه لم ينتظرنا لندخل البريد الإلكتروني بل إعتبر أنه تم إدخاله
---------------------
Name = Mhamad <- name فقط في المتغير Mhamad لاحظ أنه قام بوضع
Email = Harmush <- بشكل تلقائي email في المتغير Harmush لاحظ أنه قام بوضع
إدخال نص بواسطة الدالة getline()
إذا أردت جعل المستخدم قادر على إدخال أكثر من كلمة و تخزين كل ما يدخله في متغير نصّي واحد, يمكنك إستخدام الأمر cin لجعل المترجم ينتظر المستخدم حتى يدخل ما يشاء, و من ثم تقوم بتغليف ما سيتم إدخاله بواسطة الدالة getline() و التي ستقوم باعتبار كل ما تم إدخاله عبارة عن نص واحد.
إذاً الأمر التالي هو ما تحتاجه لإستقبال نص من المستخدم.
// x قم بتخزين كل النص الذي سيدخله المستخدم في المتغير getline(cin, x);
ملاحظة: الدالة getline() موجودة في الحزمة std و لهذا يجب ان تكتب std::getline(std::cin, x) إن لم تكن تريد تضمين الحزمة std في برنامجك.
في المثال التالي قمنا بتعريف مثال يطلب من المستخدم إدخال إسمه الكامل (إسمه و إسم عائلته) و من ثم يعرض له رسالة ترحيب.
مثال
#include <iostream>
using namespace std;
int main()
{
// لتخزين الإسم الذي سيدخله المستخدم لاحقاً name قمنا بتجهيز المتغير
string name;
// name هنا سيطلب من المستخدم إدخال إسمه الكامل و من ثم سيتم تخزين الإسم الذي يدخله في المتغير
cout << "Enter your name: ";
getline(cin, name);
// في الأخير قمنا بعرض المعلومات التي يدخلها المستخدم بشكل مرتب
cout << "Welcome " << name;
return 0;
}
•سنحصل على النتيجة التالية عند التشغيل مع الإشارة إلى أننا قمنا بتعليم البيانات التي إنتظرنا البرنامج لإدخالها من لوحة المفاتيح باللون الأصفر.
Welcome Mhamad Harmush
C++ الدوال
مفهوم الدوال في C++
الدالة ( Function ) عبارة عن مجموعة أوامر مجمعة في مكان واحد و تتنفذ عندما نقوم باستدعائها.
في الدروس السابقة تعرفنا على الكثير من العديد من الدوال الجاهزة في C++ و التي تستخدم للتعامل مع النصوص و الأرقام.
في هذا الدرس سنتعلم كيفية إنشاء دوال جديدة و كيفية استخدامها.
أمثلة حول الدوال الجاهزة
أسماء بعض الدوال التي قمنا باستخدامها في الدروس السابقة.
length(); insert(); replace(); fmax(); floor();
مصطلحات تقنية
الدوال الجاهزة في C++ يقال لها Built-in Functions.
الدوال التي يقوم المبرمج بتعريفها يقال لها User-defined Functions.
بناء الدوال في C++
عند تعريف أي دالة في C++ عليك إتباع الشكل التالي:
{
    // Function Body
}
• returnType: يحدد النوع الذي سترجعه الدالة عندما تنتهي أو إذا كانت لن ترجع أي قيمة.
• functionName: يمثل الإسم الذي نعطيه للدالة, و الذي من خلاله يمكننا استدعاءها.
• Parameter List: المقصود بها الباراميترات ( وضع الباراميترات إختياري ).
• Function Body: تعني جسم الدالة, و المقصود بها الأوامر التي نضعها في الدالة.
نوع الإرجاع ( returnType ) في الدالة يمكن أن يكون أي نوع من أنواع البيانات الموجودة في C++ ( int - double - bool - string إلخ.. ).
و يمكن وضع إسم لكلاس معين, و هنا يكون القصد أن الدالة ترجع كائن من هذا الكلاس ( لا تقلق ستتعلم هذا في دروس لاحقة ).
في حال كانت الدالة لا ترجع أي قيمة, يجب وضع الكلمة void مكان الكلمة returnType.
أمثلة حول تعريف دوال جديدة في C++
في المثال التالي قمنا بتعريف دالة إسمها myFunction, نوعها void, و تحتوي على أمر طباعة فقط.
بعدها قمنا باستدعائها في الدالة main() حتى يتم تنفيذ أمر الطباعة الموضوع فيها.
المثال الأول
#include <iostream>
using namespace std;
// عند استدعاءها تقوم بطباعة جملة myFunction هنا قمنا بتعريف دالة إسمها
void myFunction() {
cout << "My first function is called";
}
int main()
{
// حتى يتنفذ الأمر الموضوع فيها myFunction() هنا قمنا باستدعاء الدالة
myFunction();
return 0;
}
•سنحصل على النتيجة التالية عند التشغيل.
My first function is called
هنا قمنا بتعريف دالة إسمها greeting, عند إستدعاءها نمرر لها إسم فتطبع رسالة ترحيب للإسم الذي تم تمريره لها.
المثال الثاني
#include <iostream>
using namespace std;
// عند استدعاءها تقوم بطباعة جملة greeting هنا قمنا بتعريف دالة إسمها
void greeting(string name)
{
cout << "Hello " << name << ", welcome to our company.";
}
int main()
{
// حتى يتنفذ الأمر الموضوع فيها greeting() هنا قمنا باستدعاء الدالة
greeting("Mhamad");
return 0;
}
•سنحصل على النتيجة التالية عند التشغيل.
Hello Mhamad, welcome to our company.
هنا قمنا بتعريف دالة إسمها getSum, عند إستدعاءها نمرر لها عددين فترجع لنا ناتج جمعهما.
المثال الثالث
#include <iostream>
using namespace std;
// عند إستدعاءها نمرر لها عددين فتقوم بإرجاع ناتج جمعهما get_sum هنا قمنا بتعريف دالة إسمها
int getSum(int a, int b)
{
return a + b;
}
int main()
{
// x في المتغير get_sum() هنا قمنا بتخزين ناتج العددين 3 و 5 الذي سترجعه الدالة
int result = getSum(3, 7);
// و التي ستساوي 10 result هنا قمنا بعرض قيمة المتغير
cout << "Result = " << result;
return 0;
}
•سنحصل على النتيجة التالية عند التشغيل.
Result = 10
إعطاء قيمة إفتراضية للباراميترات في C++
C++ تتيح لك وضع قيم إفتراضية للباراميترات مما يجعلك عند إستدعاء الدالة مخيّر على تمرير قيم مكان الباراميترات بدل أن تكون مجبراً على ذلك.
مصطلحات تقنية
القيمة الإفتراضية التي نضعها للباراميتر يقال لها Default Argument.
في المثال التالي قمنا بتعريف دالة إسمها printLanguage.
هذه الدالة فيها باراميتر واحد إسمه language يملك النص "English" كقيمة إفتراضية.
كل ما تفعله هذه الدالة عند إستدعاءها هو طباعة قيمة الباراميتر language.
ملاحظة: بما أن الباراميتر language يملك قيمة بشكل إفتراضية, فهذا يعني أنك لم تعد مجبر على تمرير قيمة له عند إستدعاء الدالة لأنه أصلاً يملك قيمة.
مثال
#include <iostream>
using namespace std;
// و يمكنك عدم تمرير قيمة لأنه أصلاً يملك قيمة language عند إستدعاءها يمكنك تمرير قيمة لها مكان الباراميتر .printLanguage هنا قمنا بتعريف دالة إسمها
void printLanguage(string language="English")
{
cout << "Your language is " << language << endl;
}
int main()
{
// "English" و بالتالي ستظل قيمته language بدون تمرير قيمة مكان الباراميتر printLanguage() هنا قمنا باستدعاء الدالة
printLanguage();
// "Arabic" و بالتالي ستصبح قيمته language للباراميتر 'Arabic' مع تمرير القيمة printLanguage() هنا قمنا باستدعاء الدالة
printLanguage("Arabic");
return 0;
}
•سنحصل على النتيجة التالية عند التشغيل.
Your language is English Your language is Arabic
إنتبه
إذا كانت الدالة تملك أكثر من باراميتر و تريد وضع قيمة إفتراضية لأحد الباراميترات التي تمكلها فقط فيجب وضع الباراميترات التي تملك قيم إفتراضية في الآخر.
إن لم ترد ذلك ستكون مجبر على وضع قيم إفتراضية لجميع الباراميترات الموجودة بعد أول باراميتر وضعت له قيمة إفتراضية.
هنا وضعنا لك عدة أمثلة حول الأخطاء التي قد تقع فيها عند وضع قيم إفتراضية حتى تتعلم كيف تتجنبها.
أين يجب تعريف الدوال في C++
مترجم لغة C++ يقرأ الكود سطراً سطراً مع تنفيذ الأوامر الموضوعة في كل سطر بشكل مباشر عندما يتم تشغيل البرنامج.
لهذا السبب يجب دائماً أن تكون الدالة التي تريد استدعاءها معرّفة سابقاً حتى لا يظهر لك مشكلة عند تشغيل البرنامج.
في المثال التالي, قمنا بوضع الدالة myFunction() بعد الدالة التي قمنا باستدعائها منها.
المشكلة التي ستحدث عند التشغيل هنا سببها أن المترجم سيكون لا يعرف ما هي myFunction() حيث أنه تم استدعاءها قبل أن يقوم المترجم قد سبق و قرأها.
المثال الأول
#include <iostream>
using namespace std;
int main()
{
// myFunction() هنا قمنا باستدعاء الدالة
myFunction();
return 0;
}
// التي تحتوي على أمر طباعة فقط myFunction هنا قمنا بتعريف الدالة
void myFunction()
{
cout << "My first function is called";
}
•سيظهر الخطأ التالي عند التشغيل و الذي يعني أن المترجم لم يعرف ما هي myFunction التي تحاول استدعاءها في السطر الثامن.
حل مشكلة عدم التعرف على الدالة
لحل مشكلة عدم التعرف على الدالة التي حدثت في المثال السابق عندنا خيارين:
إبقاء الدالة
myFunction()مكانها و ذكر تعريفها ( Function Declartion ) في أول الملف فقط, و هذه الطريقة تعتبر الأكثر تفضيلاّ.وضع الدالة
myFunction()فوق الدالةmain()حتى يقوم المترجم بقرائها و التعرف عليها و تصبح قادر على استدعاءها في الدالةmain()الموجودة بعدها.
في المثال التالي, قمنا بإبقاء الدالة myFunction() مكانها و ذكر تعريفها ( Function Declartion ) قبل أن يتم استدعاءها في الدالة main().
إذاً لن يحدث أي مشكلة عند استدعاء الدالة myFunction() من الدالة main() لأن المترجم سيكون لديه علم بأن الدالة myFunction() موجودة فعلاً.
المثال الثاني
#include <iostream>
using namespace std;
// حتى يقوم المترجم بالتعرف عليها و نصبح قادرين على استخدامها myFunction الدالة ( Declartion ) هنا قمنا بوضع تعريف
void myFunction();
int main()
{
// myFunction() هنا قمنا باستدعاء الدالة
myFunction();
return 0;
}
// أو بمعنى آخر تعريف ما سيحدث عندما يتم استدعاءها ,myFunction الدالة ( body ) هنا قمنا بتعريف جسم
void myFunction()
{
cout << "My first function is called";
}
•في الدالة main() سيتم استدعاء و تتنفذ الدالة myFunction() بدون أي مشاكل و سنحصل على النتيجة التالية عند التشغيل.
My first function is called
نصيحة
الأفضل دائماً وضع تعريفات الدوال ( Functions Declartions ) قبل الدالة main() و تعريف محتوى هذه الدوال بعدها كالتالي لأن قراءة الكود ستصبح أسهل بالنسبة لك.
المثال التالي يريك فقط كيف تقوم بترتيب الكود إذا كنت تنوي تعريف العديد من الدوال في الملف.
المثال الثالث
#include <iostream>
using namespace std;
// نقوم بذكر تعريف جميع الدوال التي سنقوم بإنشائها لاحقاً main() قبل الدالة
void printMessage();
void greeting(string name);
// و فيها يمكننا استدعاء أي دالة قمنا بذكر تعريفها سابقاً بدون أي مشاكل main() هنا نقوم بتعريف الدالة
int main()
{
// greeting() و printMessage() هنا يمكننا استدعاء
return 0;
}
// لأنه قمنا بذكر أنها موجودة من قبل printMessage() هنا نقوم بتعريف الدالة
void printMessage()
{
// هنا نكتب ما سيحدث عند استدعاءها
}
// لأنه قمنا بذكر أنها موجودة من قبل greeting() هنا نقوم بتعريف الدالة
void greeting(string name)
{
// هنا نكتب ما سيحدث عند استدعاءها
}
C++ أخطاء قد تظهر بسبب وضع قيم إفتراضية للباراميترات
في جميع الأمثلة, سنفترض أننا نريد تعريف دالة و في كل مرة نحاول تمرير قيم إفتراضية لبعض عناصرها.
المثال الأول
في المثال التالي قمنا بإعطاء c قيمة إفتراضية و هذا لن يسبب مشكلة لأنه لا يوجد بعده أي باراميتر.
void printMax(int a, int b, int c=0)
{
}
المثال الثاني
المثال التالي فيه مشكلة حيث أننا قمنا بإعطاء b قيمة إفتراضية و لم نعطي قيمة إفتراضية للباراميتر c الموجود بعده.
هذا الأمر سيؤدي لظهور مشكلة عند تشغيل الكود.
void printMax(int a, int b=0, int c)
{
}
هذه الدالة ستسبب الخطأ التالي في الكود و الذي يعني أن المشكلة هي نسيان وضع قيمة إفتراضية للباراميتر الثالث.
المثال الثالث
في المثال التالي قمنا بإعطاء b و c قيم إفتراضية و هذا لن يسبب مشكلة لأنه لا يوجد بعدهما أي باراميتر.
void printMax(int a, int b=0, int c=0)
{
}
المثال الرابع
المثال التالي فيه مشكلة حيث أننا قمنا بإعطاء a قمية إفتراضية و لم نعطي قيمة إفتراضية للباراميترين b و c الموجودين بعده.
هذا الأمر سيؤدي لظهور مشكلة عند تشغيل الكود.
void printMax(int a=0, int b, int c)
{
}
هذه الدالة ستسبب الخطأ التالي في الكود و الذي يعني أن المشكلة هي نسيان وضع قيمة إفتراضية للباراميترين الثاني و الثالث.
error: default argument missing for parameter 3 of 'void printMax(int, int, int)'
المثال الخامس
في المثال التالي قمنا بإعطاء a و b و c قيم إفتراضية, أي كل البارميترات و بالتالي لا يوجد أي مشكلة هنا.
void printMax(int a=0, int b=0, int c=0)
{
}
