دورة ماك للعرب - برمجة Apple
Carbon القسم الأول - المبتدئ
لغة C
الدرس الثالث: مبادئ اللغة - مزيدا من لغة C
السبت الموافق 22-ربيع الأول- 1429هـ 29-3-2008م
_________________________________________________
المصدر: كتاب (داخل Carbon) - تأليف أبو بكر، جميع الحقوق محفوظة لماك للعرب فقط.
المرجع: داخل الماكنتوش وهو مرجع Apple الخاص بها.
_________________________________________________
لغة C الموحدة:
سنتناول في دروسنا لغة C القياسية الموحدة وهي التي تعرف باسم ANSI C.
ويقصد بـ ANSI «المعهد الأمريكي القومي للمقاييس» - American National Standards Institute-.
وأما فائدة ANSI C هي أن تضمن بأن النص البرمجي المكتوب يمكن نقله من نظام تشغيل معين إلى أخر دون ظهور المشاكل، فيمكن نقل البرنامج من الماكنتوش إلى Windows أو العكس.
الأهداف:- مزيدا من الحلقات: حلقتي do..while و while المنطقية.
- المصفوفات في لغة C.
- الإدخال والإخراج.
- طريقة أخرى للإدخال والإخراج.
- اختبار الحالات والشروط باستخدام بديل أمر اختبار الشروط (إذا) if.
مصطلحات ومعناها:- Computer: وتعني باللغة العربية الحاسوب، ومن الخطأ أن نقول: الحاسب الآلي، أو الحاسب أو الكمبيوتر.
- Code: النص البرمجي ويعرف أيضا باسم «الشيفرة» وأيضا يعرف باسم: «المصدر source»، ويقصد به ما يكتبه المبرمج من أوامر ونصوص لتشكل في النهاية برنامجا معينا، ويطلق على السطر الواحد أيضا.
- Compiler: المترجم والذي يقوم بتحويل النص البرمجي أو الشيفرة، من اللغة المعنية (في حالتنا من لغة C) إلى تعليمات لغة الآلة، ولا يفهم هذه اللغة إلا وحدة المعالجة المركزية في الحاسوب CPU، ويقوم بحفظ التعليمات وجمعها في ملف الهدف، ويسمى الهدف باللغة الإنجليزية بـ: object.
- Linker: الرابط أو الموصل، وهو البرنامج الذي يقوم بتحويل ملف الهدف إلى برنامج تطبيقي قابل للتنفيذ.
حلقتي do..while و while المنطقية:
لقد سبق أن تناولنا حلقة العداد for، وسنتناول الأن حلقتين منطقيتين:
- أولا: حلقة do while المنطقية:
- توصف حلقة do..while بالمنطقية لأن شرطها منطقي، وتختلف عن حلقة for بأن شرطها قد يكون مبنيا على القيمة البولينية المنطقية، وتستخدم كما يلي:
كود:
int i = 1;
do
{
printf("%d%s", i, " ");
i++;
} while (i<=10);
- في السطر الأول تم تعريف المتغير i وتحديد قيمته الافتراضية وهي القيمة 1، أي أن قيمة المتغير i تساوي 1.
- تبدأ حلقة do..while في السطر الثاني مباشرة، ويجب كتابتها على هذه الصورة، فتبدأ الحلقة بالأمر do، ثم فتح قوس الحاصرة، وكتابة الجمل المطلوب تكرار تنفيذها وبعد ذلك إغلاق قوس الحاصرة، ثم كتابة أمر الشرط while وتحديد شرطه بين الأقواس. ويجب إقفال هذه الحلقة بالفاصلة المنقوطة لأنها جملة من جمل لغة C.
لاحظ أن هذه الحلقة تعطينا نفس النتيجة السابقة التي حصلنا عليها بكتابة حلقة for في الدرس الثاني. ومعنى هذه الحلقة كما يلي:
نفذ هذه السطور ثم استمر في تنفيذها (وهي التي بين قوسي الحاصرة) طالما أن قيمة المتغير i أصغر من أو تساوي 10.
- لاحظ السطر الخامس: i++; حيث تزداد قيمة i بمقدار واحد كما سبق ذكره في الدرس الثاني، قم بحذفه وأعد التنفيذ. مالذي سيحدث؟. إن قيمة i ستبقى 1، وهي دائما أصغر من 10 أي أن شرط حلقة do..while يتحقق دائما مما يؤدي إلى عدم توقف الحلقة عن إعادة وتكرار التنفيذ، وتبقى عملية طباعة قيمة i على الشاشة جارية دون توقف، وهو ما يعرف بالحلقة الأبدية، وهذا هو الفرق الرئيسي بين حلقة do..while وحلقة for، فحلقة for تستخدم لإعادة وتكرار التنفيذ مرات محددة ولا تستخدم كحلقة أبدية، بينما حلقة do..while تستخدم كحلقة أبدية. لعلك لاحظت عند فتح برنامج ما، فإنه يبقى مفتوحا حتى تقوم باختيار الأمر «إنهاء» أو Quit. أي أن حلقته الرئيسية لا تتوقف من تلقاء نفسها، لأن الشرط هنا هو اختيار إنهاء البرنامج عن طريق القائمة أو استخدام اختصار لوحة المفاتيح، إذن إن حلقة for لا تصلح لأن تكون الحلقة الرئيسية للبرنامج!.
- ثانيا: حلقة while المنطقية:
- توصف أيضا حلقة while بالمنطقية لأن شرطها منطقي كذلك، ويتحدد شرطها في بدايتها بعكس حلقة do..while على النحو التالي:
كود:
int i = 1;
while (i<=10)
{
printf("%d%s", i, " ");
i++;
};
- في السطر الأول تم تعريف المتغير i وتحديد قيمته الافتراضية وهي القيمة 1، أي أن قيمة المتغير i تساوي 1.
- تبدأ حلقة while في السطر الثاني مباشرة، ويجب كتابتها على هذه الصورة، فتبدأ الحلقة بالأمر while، ثم يتم كتابة شرطها بين الأقواس، ثم فتح قوس الحاصرة، وكتابة الجمل المطلوب تكرار تنفيذها وبعد ذلك إغلاق قوس الحاصرة، وإقفال الحلقة بالفاصلة المنقوطة لأنها جملة من جمل لغة C.
لاحظ أن هذه الحلقة تعطينا نفس النتيجة السابقة التي حصلنا عليها بكتابة حلقة for في الدرس الثاني. وحلقة do..while في المثال السابق. ومعنى هذه الحلقة كما يلي:
نفذ هذه السطور (وهي التي بين قوسي الحاصرة) طالما أن قيمة المتغير i أصغر من أو تساوي 10.
المصفوفات في لغة C:- سبق لكم دراسة المصفوفات (Arrays) في الرياضيات، إذ من فوائدها أنها تستخدم لترتيب ودراسة البيانات، وحل المعادلات آنيا، كما أنها تسهل حل المعادلات المعقدة في مختلف المجالات كعلم الحركة والسكون والميكانيكا والفيزياء. وسنتناول الأن موضوعها في لغة البرمجة C.
- ألق نظرة على هذه المثال:
كود:
int A[5], i;
A[0] = 10;
A[1] = 2 * A[0];
A[2] = A[1] - A[0];
A[3] = 4;
A[4] = 5;
printf ("%s", "The elemets of our [A] Array are = { ");
for (i = 0; i < 5; i++ )
if (i < 4)
printf ("%d%s", A[i], ", ");
else
printf ("%d", A[i]);
printf ("%s", " }\n\n");
- في السطر الأول تم تعريف متغير المصفوفة A، لاحظ أن المصفوفة تُعرّف بإضافة القوس الكبير [] إلى أي متغير، والرقم 5 يوضح عدد عناصر المصفوفة، أي أن المصفوفة الأن تحتوي على خمس عناصر، وبعبارة أخرى لدينا الأن خمس متغيرات لها الاسم نفسه وهو A و لها نفس النوع وهو int، لكنها تختلف في رقم الفهرس، فالعنصر الأول يتم التعبير عنه بـ:
والعنصر الثاني يتم التعبير عنه بـ:
والعنصر الخامس هو:
وهكذا..
- ملاحظة: إن أرقام الفهارس تبدأ في لغة C من الصفر دائما، ولهذا كان آخر عناصر المصفوفة A هو العنصر ذو الفهرس 4.
- وفي السطر الأول أيضا تم تعريف المتغير i وهو من النوع int، لاستخدامه لاحقا في حلقة العداد for.
- والأسطر 2 وحتى السطر 6 تم تعيين قيم مختلفة لكل عنصر من عناصر المصفوفة A على حدة، لاحظ أن طريقة تعيين قيم لعناصر المصفوفة هي نفس طريقة تعيين قيم للمتغيرات.
- ملاحظة: إن عنصر المصفوفة ما هو إلا متغير عادي، ويجري عليه ما يجري على المتغيرات.
- وفي السطر السابع يتم طباعة هذه الجملة:
كود:
The elemets of our [A] Array are = {
- وفي السطر الثامن تبدأ حلقة العداد for، لاحظ أن القيمة الابتدائية للمتغير i هي الصفر، وأن شرط الحلقة هو «طالما قيمة i أصغر من 5»، مما يعني أن هذه الحلقة سيتكرر تنفيذها خمس مرات فقط. كما استخدمنا أمر اختبار الشرط if وذلك لطباعة العنصر الأخير من المصفوفة بأمر مستقل لوحده وهو الأمر الذي يلي else، وبقية العناصر يتم طباعتها بالأمر الذي يلي if وذلك من أجل الترتيب والتنسيق فقط. وفي السطر الأخير يتم طباعة قوس الحاصرة.
- الأن ألق نظرة على هذا المثال:
كود:
int B[5] = { 5, 7, 8, 9, 10 };
- في هذا المثال تم تعريف المصفوفة B وعدد عناصرها خمس، كما تم تعيين قيم لجميع عناصرها أثناء التعريف، فالعنصر الأول قيمته 5، والعنصر الثاني قيمته 7، والثالث قيمته 8، والرابع قيمته 9 والعنصر الأخير وهو الخامس قيمته 10.
- إن المصفوفتين A و B في المثالين السابقين ذات بعد واحد فقط، فنستطيع بأي منهما تمثيل صف واحد من الجدول أو عمود واحد فقط، وإذا ما أردنا أن نقوم بتمثيل الجدول بأكمله فإننا بحاجة إلى إعادة تعريف المصفوفة لتكون ذات بعدين على النحو التالي:
المصفوفة B أصبحت ذات بعدين، وعدد عناصرها يساوي: 5*7=35، ونستطيع تمثيل جدول يتكون من 35 خلية كحد أقصى.
مثال لتعيين القيمة 100 لأحد عناصر المصفوفة وليكن العنصر ذو الرتبة: الصف الثالث والعمود الخامس، فإن ذلك يتم كما يلي:
أهمية المصفوفات:
- تعد المصفوفات من أهم أدوات البرمجة على الإطلاق، فمثلا:
- وثائق برنامج محرر الصور الشهير Adobe PhotoShop ما هي إلا مصفوفات ذات بعدين. وكذلك جداول برنامج Microsoft Excel ما هي إلا مصفوفات ذات بعدين.
- وكذلك النصوص المكتوبة في أي برنامج محرر نصوص كبرنامج Microsoft Word و برنامج الناشر الصحفي وبرنامج Adobe InDesign ما هي إلا مصفوفات.
- لقد لاحظت أهمية المصفوفات، إذن عليك التمرن عليها كثيرا، وسنتناولها بشكل كبير جدا عند برمجة لعبة X-O بمشيئة الله عز وجل.
الإخال والإخراج:
ويقصد بالإدخال هو إدخال قيم معينة إلى الحاسوب عبر أحد أجهزة الإدخال، ويقصد بالإخراج هو إخراج قيم معينة من الحاسوب عبر أحد أجهزة الإخراج، ولقد سبق أن تعرفنا على طريقة الطباعة على الشاشة باستخدام الروتين printf وهذه العملية ما هي إلا عملية إخراج على الشاشة، فيتم إخراج (طباعة وإظهار) القيم المعنية على الشاشة. ماذا لو أردنا أن نتيح للمستخدم من خلال برنامج بسيط إدخال قيم محددة ثم نطبق عليها بعض المعادلات الرياضية البسيطة، كأن نسأله كم طول المربع، ثم نجعل البرنامج يعطيه مساحة هذا المربع. لنقم بذلك الأن:
إن الروتين scanf هو المسؤول عن إدخال القيم عن طريق لوحة المفاتيح، وهو على النحو التالي:
كود:
int i;
printf("%s", "Enter a value:");
scanf("%d", &i);
printf("%s%d", "The value you entered:", i);
- في السطر الأول تم تعريف المتغير i.
- وفي السطر الثاني تم طباعة الجملة Enter a value، وهذا كما تعلمناه سابقا. تذكر أن الوسيطة الأولى "%s" تعني أن القيم المراد طباعتها على الشاشة هي جملة sentence.
- وفي السطر الثالث استخدمنا الروتين scanf للسماح للمستخدم بإدخال قيمة رقمية يتم تخزينها في المتغير i، ستجد عند تنفيذ البرنامج ظهور علامة الوميض (|) وذلك لدلالة على أن البرنامج ينتظر منك إدخال قيمة محددة. لاحظ أن الوسيطة الأولى تحدد نوع القيم المراد إدخالها، وهي هنا قيم عشرية decimal، والوسيطة الثانية هي إشارة إلى المتغير المراد تخزين القيمة فيه، لاحظ أننا كتبنا علامة & قبل المتغير، وذلك لتمرير عنوانه بدلا منه، فالإشارة إلى المتغير هي عنوانه، وقد سبق تبيان ذلك في الدرس الثاني.
- وفي السطر الأخير يتم طباعة الجملة The value you entered: متبوعة بالقيمة التي أدخلتها.
طريقة أخرى للإدخال والإخراج:- إن الروتينات التي سبق استخدامها في عملية الإدخال والإخراج printf و scanf هي من روتينات لغة C، والأن سنستخدم لغة C++ للقيام بعملية الإدخال و الإخراج:
- عند إنشاء المشروع يجب أن يكون نوعه C++ Tool، قم بإنشاء مشروع جديد وبدلا من أن يكون Carbon Application اختر C++ Tool وذلك من القائمة Command Line Utility. بعد أن تنتهي من إنشاء المشروع، افتح الملف main.cpp، ستجده يحتوي على الأسطر الأربعة الأولى من هذه الشيفرة (أكمل الشيفرة لتطابق هذا المثال):
كود:
#include <iostream>
int main (int argc, char * const argv[]) {
// insert code here...
std::cout << "Hello, World!\n";
int i;
std::cout << "Enter your number:";
std::cin >> i;
std::cout << "Your number is:" << i;
return 0;
}
- ففي السطر الأول يتم إحضار مكتبة الإدخال والإخراج الخاصة بلغة C++ وهي المسؤولة عن العناصر التي سنستخدمها بدلا من الروتينات التي تعلمناها كالروتين printf، واسم هذه المكتبة iostream وتعني الإدخال والإخراج عبر خط مجرى تدفق البيانات، وتعتمد برمجة C++ على العناصر بشكل كبير إلا أنني لن أتشعب فيها أبدا، فغرضنا الأن تعلم برمجة Apple باستخدام واجهة الماكنتوش الرسومية وتقنية Carbon.
- وفي السطر الثاني نجد الروتين الأساسي، وله وسيطتان.
- وفي السطر الثالث تعليق بسيط يتم تجاهله.
- والسطر الرابع: تمت كتابة العنصر cout لطباعة الجملة Hello, World! على الشاشة، لاحظ أن هذا العنصر له طريقة خاصة جدا فهنا يجب أن يسبقه النمط std:: وهو من النوع namespace، ويستخدم هذا النوع لضم مجموعة من العناصر وروتيناتها وأنماطها معا تحت اسم موحد. وفي هذا المثال اسم النمط الذي يضم جميع عناصر مكتبة iostream هو std. ولاحظ أيضا أنك يجب أن تبدأ كل ما تريد طباعته على الشاشة بمعامل الإخراج (>>).
وإذا ما أردت طباعة أكثر من شيء استخدم العنصر cout كما يلي:
كود:
std::cout << "Hello, World!\n" << i << "This cout prints 3 thing on screen";
- وفي السطر الخامس تم تعريف المتغير i، وفي السطر السادس تمت كتابة الجملة Enter your number:.
- وفي السطر السابع استخدم عنصر الإدخال cin، لاحظ أن معامل الإدخال يجب أن يسبق المتغير المراد تخزين القيمة فيه.
- وفي السطر الثامن يتم طباعة الجملة Your number is: متبوعة بالرقم الذي أدخلته.
- وفي السطر التاسع يعود الروتين الأساسي بالقيمة 0.
اختبار الحالات والشروط باستخدام بديل أمر اختبار الشروط (إذا) if:
لنتناول هذا المثال:
كود:
int x;
x = 2;
switch (x)
{
case 1:
printf("%s", "x = 1");
break;
case 2:
printf("%s", "x = 2");
break;
case 3:
printf("%s", "x = 3");
break;
case 4:
printf("%s", "x = 4");
break;
case 5:
printf("%s", "x = 5");
break;
default:
printf("%s", "x is unkonw");
}
- في السطر الأول تم تعريف المتغير x، وفي السطر الثاني تم تخزين القيمة 2 فيه، أي أن قيمته الأن تساوي 2.
- وفي السطر الثالث يبدأ الأمر switch وهو بديل أمر اختبار الشروط، بدراسة واختبار حالة المتغير x، لاحظ أن المتغير المراد اختبار حالته يجب كتابته بين قوسين كما هو موضح في المثال. بعد ذلك يتم فتح قوس الحاصرة.
- وفي السطر الخامس استخدمنا الأمر case لدراسة حالة x عند قيمة محددة، لاحظ أن هذه القيمة تم تحديدها وهي 1، أي أنه إذا كانت قيمة x تساوي 1 فإن الأسطر التالية سيتم تنفيذها مباشرة، وإلا سيتم دراسة حالات أخرى إن وجدت، وفي هذا المثال يتم دراسة خمس حالات مختلفة، لاحظ وجود أمر التوقف break للفصل بين كل حالة على حدة، وذلك لمنع استمرار تنفيذ الحالات المتبقية في حال تطابق أحدها على المتغير، فمثلا لو لم نضف هذا الأمر بعد الحالة الثانية case 2 لظهر على الشاشة مايلي:
على الرغم من أن قيمة x تساوي 2. وفي حالة إضافة أمر الحالة الافتراضية default كما في المثال السابق فإنها ستنفذ فقط إذا لم تنطبق جميع الحالات المراد دراستها على المتغير.
- قم بتغيير السطر الثاني وأعطه القيم 1 و 3 و 4 و 5 و 10 وتأكد من أن الحالات التي يتم تنفيذها هي التي تنطبق على قيمة المتغير x.
إن أمر دراسة الحالات switch هو أفضل من أمر اختبار الشروط if، إذ يعد أكثر ترتيبا ومناسبا أكثر للحالات الطويلة كأن يتم دراسة أكثر من 10 حالات لمتغير واحد، إلا أنه في بعض الأحيان لا غنى لنا عن الأمر if.
- إن المثال التالي باستخدام أمر اختبار الشروط if مساو تماما للمثال السابق باستخدام أمر دراسة الحالات switch:
كود:
int x;
x = 2;
if (x == 1)
printf("%s", "x = 1");
else if (x == 2)
printf("%s", "x = 2");
else if (x == 3)
printf("%s", "x = 3");
else if (x == 4)
printf("%s", "x = 4");
else if (x == 5)
printf("%s", "x = 5");
else
printf("%s", "x is unkonw");
- انتهى شرح هذا الدرس، وبه نكون قد أنهينا مبادئ لغة C التي تعد غاية في الأهمية، بإذن الله نحن قادرون على الإنطلاق والمضي قدما في تعلم برمجة Carbon.
وإليك أسئلة المناقشة وورشة العمل لتحسّن من مستواك بسرعة، وعليك أن تجيب عليها وتنشرها في قسم الإجابات.
ملاحظة: تم تقييم كل سؤال بنقاط محددة، وسأقوم بجمع النقاط لكل مشترك على حدة وإعطائها لكم عبر منتدى البرمجة في موقع ماك للعرب.
أسئلة ومناقشة:
س1: (2 نقاط)
مالفرق بين كل من: حلقة do..while وحلقة while؟
س2: (4 نقاط)
قم بكتابة برنامج يطلب إدخال قيمة معينة عن طريق لوحة المفاتيح، ولتكن هذه القيمة 10، ثم يقوم البرنامج بجمع الأرقام من 1 إلى القيمة التي أدخلتها، لاحظ أن مجموع الأرقام من 1 إلى 10 يساوي 55،
مراعيا في برنامجك ما يلي:
استخدام الحلقات (
لك حرية اختيار الحلقة)، واستخدام روتين خاص ليقوم بعملية الجمع.
يجب أن يكون شكل البرنامج أثناء التنفيذ كما يلي:
كود:
Enter a value: 10
The summation from 1 to 10 = 55.
س3: (4 نقاط)
قم بكتابة برنامج يطلب إدخال قيمة معينة عن طريق لوحة المفاتيح، ولتكن هذه القيمة 5، ثم يقوم بحساب المضروب لهذه القيمة. تذكر أن مضروب 5 يعبر عنها رياضيا بالرمز 5! (علامة التعجب)، ولحساب مضروب 5 فإننا نجري عملية ضرب الأعداد من 1 إلى 5 كما يلي: 5 * 4 * 3 * 2 * 1، إن مضروب 5 = 120.
مراعيا في برنامجك ما يلي:
استخدام حلقة while، واستخدام روتين خاص لإيجاد ناتج المضروب، أعط هذا الروتين الاسم:
Factorial.
يجب أن يكون شكل البرنامج أثناء التنفيذ كما يلي:
كود:
Enter a value: 5
The factorial of (5) = 120.
س4: (10 نقاط)
إكتشف الأخطاء وصححها إن وجدت في كل مما يلي:
كود:
int A[7];
A[7] = 10;
std::cout A[7];
كود:
int x = 3;
switch (x)
case 1:
printf ("%s", x);
case 2:
printf ("%s", x);
case 3:
printf ("%s", x);
case 4:
printf ("%s", x);
كود:
int Mat[3] = { 1, 2, 3, 4};
كود:
int i,j;
for (i=0; i< 10; i++)
for j=i; j < (i*2); j++
if( j - i = i)
std::cout << " J is two times greater than I.." ;
بعد أن تقوم بتصحيح الخطأ في نص الشيفرة السابق، كم مرة ستظهر هذه الجملة: J is two times greater than I، ولماذا؟ وإذا لم تظهر ما التعديل المطلوب عمله على البرنامج لتظهر؟
كود:
int i, j;
for (i=0; i< 10; i++)
for (j=2; j<= 4; j++)
for (a=0; a< 5; a++)
for (b=1; b<8; b++)
printf("%d%s", i+j+a+b, " ");
بانتظار استفساراتكم وأسئلتكم، وبالتوفيق إن شاء الله.