ترجمة آلية تحت المراجعة
الأسبوع 1: لغة C
المصدر الأصلي على CS50المحاضرة الأولى (Lecture 1)
- مرحبًا!
- الشيفرة المصدرية
- Visual Studio Code لـ CS50
- مرحبًا بالعالم
- من الصفر إلى لغة C
- ملفات الرأس وصفحات دليل CS50
- مرحبًا، أنت
- لينكس
- الشروط
- الأنواع
- رموز التنسيق
- المتغيرات
- compare.c
- agree.c
- الحلقات وmeow.c
- الوظائف
- الصحة، التصميم، الأسلوب
- ماريو
- المشغلين
- التلخيص
مرحبًا! (Welcome!)
- في جلستنا السابقة، تعرفنا على لغة Scratch، وهي لغة برمجة مرئية.
- قد يكون تعلم مفاهيم علوم الحاسوب أمرًا صعبًا للغاية. في الواقع، يمكن أن تشعر وكأنك تشرب من خرطوم إطفاء. تذكر: المهم في النهاية هو المكاسب التي ستحققها خلال الأسابيع والأشهر القادمة من خلال عملك الجاد ودراستك في هذه الدورة.
- في الواقع، سيتم الاستفادة من جميع مفاهيم البرمجة الأساسية المقدمة في Scratch عندما تتعلم كيفية برمجة أي لغة برمجة. تعد الوظائف والشروط والحلقات والمتغيرات الموجودة في Scratch بمثابة وحدات بناء أساسية ستجدها في أي لغة برمجة.
الشيفرة المصدرية (Source Code)
- تذكر أن الأجهزة لا تفهم إلا الملفات الثنائية. حيث يكتب البشر الشيفرة المصدرية، قائمة تعليمات للكمبيوتر يمكن للإنسان قراءتها، ولا تفهم الآلات إلا ما يمكننا تسميته الآن كود الجهاز. رمز الآلة هذا هو نمط من الآحاد والأصفار الذي ينتج التأثير المطلوب.
-
اتضح أنه يمكننا التحويل الشيفرة المصدرية في كود الجهاز باستخدام برنامج خاص جدًا يسمى a مترجم. سنقدم لك اليوم مترجمًا يسمح لك بتحويل الشيفرة المصدرية إلى لغة البرمجة C إلى رمز الجهاز.
flowchart LR in["الشيفرة المصدرية"] --> BOX[" compiler "] BOX --> out["شيفرة الآلة"] - اليوم، بالإضافة إلى تعلم كيفية البرمجة، ستتعلم كيفية كتابة تعليمات برمجية جيدة.
Visual Studio Code لـ CS50 (Visual Studio Code for CS50)
- محرر النصوص المستخدم في هذه الدورة هو Visual Studio Code، المعروف أيضًا باسم VS Code، يشار إليه بمودة باسم cs50.dev، والذي يمكن الوصول إليه عبر نفس عنوان URL.
- أحد أهم الأسباب التي تجعلنا نستخدم VS Code هو أنه يحتوي على جميع البرامج المطلوبة للدورة التدريبية المحملة مسبقًا عليه. تم تصميم هذه الدورة والتعليمات الواردة هنا مع وضع VS Code في الاعتبار.
- يعد تثبيت البرنامج الضروري للدورة يدويًا على جهاز الكمبيوتر الخاص بك بمثابة صداع مرهق. من الأفضل دائمًا استخدام VS Code للمهام في هذه الدورة.
- يمكنك فتح VS Code على cs50.dev.
-
يمكن تقسيم IDE إلى عدد من المناطق:
لاحظ أن هناك مستكشف الملفات على الجانب الأيسر حيث يمكنك العثور على ملفاتك. علاوة على ذلك، لاحظ أن هناك منطقة في المنتصف تسمى أ محرر النصوص حيث يمكنك تعديل برنامجك. وأخيراً هناك أ command line interface، والمعروف باسم أ سطر الأوامر, سطر الأوامر، أو النافذة الطرفية، حيث يمكننا إرسال الأوامر إلى الكمبيوتر في السحابة. - ستلاحظ أيضًا في واجهة المستخدم الرسومية (GUI) على الشريط الأيسر أدوات متنوعة ومستكشف الملفات.
- نظرًا لأن بيئة التطوير المتكاملة (IDE) هذه تم تكوينها مسبقًا بجميع البرامج الضرورية، فيجب عليك استخدامها لإكمال جميع المهام الخاصة بهذه الدورة التدريبية.
مرحبًا بالعالم (Hello World)
-
سنستخدم ثلاثة أوامر لكتابة برنامجنا الأول وتجميعه وتشغيله:
code hello.c make hello ./helloالأمر الأول، يقوم
code hello.cبإنشاء ملف ويسمح لنا بكتابة تعليمات لهذا البرنامج. الأمر الثاني،make hello, يجمع الملف من تعليماتنا في لغة C ويقوم بإنشاء ملف قابل للتنفيذ يسمىhello. الأمر الأخير،./hello، يقوم بتشغيل البرنامج المسمىhello. -
يمكننا إنشاء برنامجك الأول بلغة C عن طريق الكتابة
code hello.cفي النافذة الطرفية. لاحظ أننا قمنا عمدا بتصغير اسم الملف بالكامل وقمنا بتضمين ملف امتداد.c. ثم، في محرر النصوص الذي يظهر، اكتب الشيفرة كما يلي:// A program that says hello to the world #include <stdio.h> int main(void) { printf("hello, world\n"); }لاحظ أن كل حرف أعلاه يخدم غرضًا ما. إذا قمت بكتابته بشكل غير صحيح، فلن يعمل البرنامج.
printfهي دالة يمكنها إخراج سطر من النص. لاحظ موضع علامات الاقتباس والفاصلة المنقوطة. علاوة على ذلك، لاحظ أن\nيقوم بإنشاء سطر جديد بعد الكلماتhello, world. - بالنقر مرة أخرى في النافذة الطرفية، يمكنك تجميع الشيفرة الخاصة بك عن طريق التنفيذ
make hello. لاحظ أننا نغفل.c.makeهي أداة بناء ستقوم بتجميع ملفاتناhello.cوتحويله إلى برنامج يسمىhello. إذا لم ينتج عن تنفيذ هذا الأمر أي أخطاء، فيمكنك المتابعة. إذا لم يكن الأمر كذلك، فتحقق جيدًا من الرمز الخاص بك للتأكد من مطابقته لما ورد أعلاه. - الآن، اكتب
./helloوسيقوم برنامجك بتنفيذ القولhello, world. - الآن، افتح مستكشف الملفات الموجود على اليسار. ستلاحظ أن هناك الآن ملفًا يسمى
hello.cوملف آخر يسمى يحتويhello.hello.cعلى الشيفرة المصدرية الخاص بك والذي يمكن قراءته بواسطة البشر والمترجم.helloهو ملف قابل للتنفيذ يحتوي على رمز الجهاز الذي يمكن للكمبيوتر تشغيله مباشرة.
من الصفر إلى لغة C (From Scratch to C)
- في سكراتش، استخدمنا
sayحظر لعرض أي نص على الشاشة. في الواقع، في لغة C، لدينا وظيفة تسمىprintfيفعل هذا بالضبط. -
لاحظ أن الشيفرة الخاص بنا يستدعي هذه الوظيفة بالفعل:
printf("hello, world\n");لاحظ أنه يتم استدعاء الدالة printf. الوسيطة التي تم تمريرها إلى printf هي
hello, world\nمحاط بعلامات اقتباس مزدوجة. يتم إغلاق بيان الشيفرة بـ a;. -
الأخطاء في الشيفرة شائعة، خاصة فيما يتعلق ببناء الجملة مثل الفواصل المنقوطة وعلامات الاقتباس. قم بتعديل الشيفرة الخاص بك كما يلي:
// \n is missing #include <stdio.h> int main(void) { printf("hello, world"); }لاحظ
\nاختفى الآن. - في نافذتك الطرفية، قم بتشغيل
make hello. لأنك قمت بتغيير البرنامج الخاص بك، يجب عليك إعادة ترجمة البرنامج الخاص بك. - الكتابة
./helloفي نافذة المحطة، كيف تغير برنامجك؟ هذا\الحرف يسمى حرف الهروب يخبر المترجم بذلك\nهي تعليمات خاصة لإنشاء فاصل أسطر. -
هناك أحرف هروب أخرى يمكنك استخدامها:
\n create a new line \r return to the start of a line \" print a double quote \' print a single quote \\ print a backslash -
قم باستعادة البرنامج الخاص بك إلى ما يلي:
// A program that says hello to the world #include <stdio.h> int main(void) { printf("hello, world\n"); }لاحظ الفاصلة المنقوطة و تمت استعادة
\n.
ملفات الرأس وصفحات الدليل CS50 (Header Files and CS50 Manual Pages)
- العبارة في بداية الشيفرة
#include <stdio.h>هو أمر خاص جدًا يخبر المترجم أنك تريد استخدام إمكانيات مكتبةstdio.h، أ ملف الرأس. يتيح لك هذا، من بين العديد من الأشياء الأخرى، الاستفادة منprintf. لاحظ أنه لم يتم استدعاؤه استوديو: إنه كذلك مكتبةstdio.h. - A عبارة عن مجموعة من الشيفرة التي أنشأها شخص ما. المكتبات عبارة عن مجموعات من الشيفرة والوظائف المكتوبة مسبقًا والتي كتبها الآخرون في الماضي والتي يمكننا استخدامها في الشيفرة الخاصة بنا.
- يمكنك القراءة عن جميع إمكانيات هذه المكتبة على صفحات الدليل. توفر الصفحات اليدوية وسيلة يمكن من خلالها فهم ما تفعله الأوامر المختلفة وكيفية عملها بشكل أفضل.
-
اتضح أن CS50 لديه مكتبة خاصة به تسمى
cs50.h. هناك العديد من الوظائف التي تم تضمينها والتي توفر عجلات التدريب أثناء البدء في لغة C:get_char get_double get_float get_int get_long get_string - تم تثبيت هذه المكتبات مسبقًا لك على cs50.dev. إذا كنت تحاول استخدام هذه المكتبات على جهاز الكمبيوتر الخاص بك، فمن المحتمل أن تضطر إلى تثبيتها. لهذا السبب يجب عليك استخدام cs50.dev في هذه الدورة، حيث أنها تحتوي على كافة البرامج الضرورية المثبتة لك.
- دعنا نستخدم هذه المكتبة في برنامجك.
مرحبًا، أنت (Hello, You)
- تذكر أنه في برنامج Scratch كان لدينا القدرة على سؤال المستخدم، "ما اسمك؟" وقل "مرحبًا" مع هذا الاسم الملحق به.
-
في لغة C، يمكننا أن نفعل الشيء نفسه. قم بتعديل الشيفرة الخاص بك كما يلي:
// get_string and printf with incorrect placeholder #include <cs50.h> #include <stdio.h> int main(void) { string answer = get_string("What's your name? "); printf("hello, answer\n"); }ال يتم استخدام الدالة
get_stringللحصول على سلسلة من المستخدم. ثم المتغير يتم تمريرanswerإلى وظيفةprintf. - قيد التشغيل
make helloمرة أخرى في نافذة الوحدة الطرفية، لاحظ ظهور العديد من الأخطاء. -
بالنظر إلى الأخطاء، لم يتم التعرف على
stringوget_stringبواسطة المترجم. نحن بحاجة إلى تزويد المترجم بهذه التعريفات عن طريق إضافة مكتبة تسمىcs50.h. ونلاحظ ذلك أيضاًanswerلم يتم توفيره كما أردنا. قم بتعديل الشيفرة الخاص بك كما يلي:// get_string and printf with %s #include <cs50.h> #include <stdio.h> int main(void) { string answer = get_string("What's your name? "); printf("hello, %s\n", answer); }ال يتم استخدام الدالة
get_stringللحصول على سلسلة من المستخدم. ثم المتغير تم تمريرanswerإلى وظيفةprintf.%sيخبر وظيفةprintfلتحضير نفسها لتلقي أstring. - الآن، قيد التشغيل
make helloمرة أخرى في نافذة الوحدة الطرفية، يمكنك تشغيل البرنامج الخاص بك عن طريق الكتابة./hello. يطلب البرنامج الآن اسمك ثم يقول مرحبًا مع إرفاق اسمك، كما هو مقصود. -
answerهو مكان احتجاز خاص نسميه أ متغير تم الاتصال بـ.answerمن النوعstringويمكنه الاحتفاظ بأي سلسلة بداخله. هناك الكثير أنواع البيانات، مثلint,bool,char، وغيرها الكثير. -
%sهو عنصر نائب يسمى a كود التنسيق الذي يخبر وظيفةprintfللتحضير لتلقي أstring.answerهو يتم تمريرstringإلى%s.
لينكس (Linux)
- لقد تم استخدام واجهة سطر الأوامر (CLI) من أجل
makeوقم بتشغيل برنامجنا. - غالبًا ما تكون واجهة سطر الأوامر (CLI) أكثر فائدة من واجهة المستخدم الرسومية (GUI) لتنفيذ الأوامر والعمل مع ملفاتنا.
- في نافذة الوحدة الطرفية، واجهة سطر الأوامر (CLI)، تتضمن بعض الأوامر الشائعة التي قد نستخدمها ما يلي:
-
cd، لتغيير دليلنا الحالي (المجلد) -
cpلنسخ الملفات والأدلة -
ls، لإدراج الملفات في الدليل -
mkdir، لإنشاء دليل -
mvلنقل (إعادة تسمية) الملفات والأدلة -
rmلإزالة (حذف) الملفات -
rmdirلإزالة (حذف) الدلائل
-
- الأكثر استخدامًا هو
lsوالذي سيسرد جميع الملفات الموجودة في الدليل الحالي. المضي قدما واكتبlsفي النافذة الطرفية واضغطenter. سترى جميع الملفات الموجودة في المجلد الحالي.
الشروط (Conditionals)
- من العناصر الأساسية الأخرى التي استخدمتها في برنامج Scratch هي الشرطية. على سبيل المثال، قد ترغب في القيام بشيء واحد إذا كانت x أكبر من y. علاوة على ذلك، قد ترغب في القيام بشيء آخر إذا لم يتم استيفاء هذا الشرط.
- نحن نلقي نظرة على بعض الأمثلة من سكراتش.
-
في لغة C، يمكنك مقارنة قيمتين كما يلي:
// Conditionals that are mutually exclusive if (x < y) { printf("x is less than y\n"); } else { printf("x is not less than y\n"); }لاحظ كيف إذا
x < y، تحدث نتيجة واحدة. إذاxلا يقل عنy، ثم تحدث نتيجة أخرى. -
وبالمثل، يمكننا التخطيط لثلاث نتائج محتملة:
// Conditional that isn't necessary if (x < y) { printf("x is less than y\n"); } else if (x > y) { printf("x is greater than y\n"); } else if (x == y) { printf("x is equal to y\n"); }لاحظ أنه ليست كل هذه الأسطر من الشيفرة مطلوبة. كيف يمكننا التخلص من الحساب غير الضروري أعلاه؟
-
ربما خمنت أنه يمكننا تحسين هذا الشيفرة على النحو التالي:
// Compare integers if (x < y) { printf("x is less than y\n"); } else if (x > y) { printf("x is greater than y\n"); } else { printf("x is equal to y\n"); }لاحظ كيف تم استبدال العبارة النهائية بـ
else.
الأنواع (Types)
-
هناك العديد من أنواع البيانات المتوفرة في لغة C:
bool char float int long string ...
رموز التنسيق (Format Codes)
- في وقت سابق، ربما تتذكر أننا استخدمنا عنصرًا نائبًا
%sلسلسلة فيprintf. يُسمى هذا العنصر النائب أ كود التنسيق. -
printfيسمح بالعديد من رموز التنسيق. فيما يلي قائمة غير شاملة بتلك التي يمكنك استخدامها في هذه الدورة:%c %f %i %li %s%cيستخدم لـchar(الحرف) المتغيرات.%fيستخدم لـfloatمتغيرات (الفاصلة العائمة).%iيستخدم لـintأو متغيرات صحيحة.%liيستخدم لـlongمتغيرات عددية.%sيستخدم لـstringالمتغيرات. يمكنك معرفة المزيد عن هذا على صفحات الدليل. - سنستخدم العديد من أنواع البيانات المتوفرة في لغة C طوال هذه الدورة.
المتغيرات (Variables)
-
في لغة C، يمكنك تعيين قيمة لـ
intأو عدد صحيح كما يلي:int counter = 0;لاحظ كيف يتم استدعاء المتغير
counterمن النوعintتم تعيين القيمة0. -
يمكن أيضًا برمجة لغة C لإضافة واحد إليها
counterعلى النحو التالي: تتم إضافةcounter = counter + 1;لاحظ كيف
1إلى قيمةcounter. -
يمكن أيضًا تمثيل ذلك على النحو التالي:
counter += 1; -
يمكن تبسيط ذلك بشكل أكبر من أجل:
counter++;لاحظ كيف يتم استخدام
++لإضافة 1. -
يمكنك أيضًا طرح واحد من
counterعلى النحو التالي:counter--;لاحظ كيف، في بناء الجملة هذا، تمت إزالة
1من قيمةcounter.
compare.c
- باستخدام هذه المعرفة الجديدة حول كيفية تعيين قيم للمتغيرات، يمكنك برمجة العبارة الشرطية الأولى.
-
في النافذة الطرفية، اكتب
code compare.cواكتب الشيفرة كما يلي:// Conditional, Boolean expression, relational operator #include <cs50.h> #include <stdio.h> int main(void) { // Prompt user for integers int x = get_int("What's x? "); int y = get_int("What's y? "); // Compare integers if (x < y) { printf("x is less than y\n"); } }لاحظ أننا قمنا بإنشاء متغيرين، و
intأو تم استدعاء عدد صحيحxواتصل آخرy. يتم ملء قيم هذه باستخدام وظيفةget_int. - يمكنك تشغيل الشيفرة الخاصة بك عن طريق التنفيذ
make compareفي النافذة الطرفية، متبوعًا بـ./compare. إذا تلقيت أي رسائل خطأ، فتحقق من الرمز الخاص بك بحثًا عن الأخطاء. -
يمكننا تحسين برنامجك عن طريق البرمجة كما يلي:
// Conditionals #include <cs50.h> #include <stdio.h> int main(void) { // Prompt user for integers int x = get_int("What's x? "); int y = get_int("What's y? "); // Compare integers if (x < y) { printf("x is less than y\n"); } else if (x > y) { printf("x is greater than y\n"); } else { printf("x is equal to y\n"); } }لاحظ أنه تم الآن احتساب كافة النتائج المحتملة.
- يمكنك إعادة إنشاء البرنامج وإعادة تشغيله واختباره.
- من خلال فحص هذه البرامج في مخططات انسيابية مختلفة، يمكنك رؤية كفاءة قرارات تصميم الشيفرة لدينا. يمكن ترجمة أي كتلة من الشيفرة تقريبًا إلى شكل مرئي.
agree.c
- بالنظر إلى نوع بيانات آخر يسمى أ
char، يمكننا بدء برنامج جديد عن طريق الكتابةcode agree.cفي النافذة الطرفية. - حيث أ
stringعبارة عن سلسلة من الأحرف، أcharهو حرف واحد. -
في محرر النصوص، اكتب الشيفرة كما يلي:
// Comparing against lowercase char #include <cs50.h> #include <stdio.h> int main(void) { // Prompt user to agree char c = get_char("Do you agree? "); // Check whether agreed if (c == 'y') { printf("Agreed.\n"); } else if (c == 'n') { printf("Not agreed.\n"); } }لاحظ أنه يتم استخدام علامات الاقتباس المفردة للأحرف المفردة (
char)، بينما يتم استخدام علامات الاقتباس المزدوجة للسلاسل. علاوة على ذلك، لاحظ ذلك==يضمن وجود شيء ما يساوي إلى شيء آخر، حيث سيكون لعلامة المساواة الواحدة وظيفة مختلفة تمامًا في لغة C. - يمكنك اختبار الشيفرة الخاص بك عن طريق الكتابة
make agreeفي النافذة الطرفية، متبوعًا بـ./agree. -
يمكننا أيضًا السماح بإدخال الأحرف الكبيرة والصغيرة:
// Comparing against lowercase and uppercase char #include <cs50.h> #include <stdio.h> int main(void) { // Prompt user to agree char c = get_char("Do you agree? "); // Check whether agreed if (c == 'y') { printf("Agreed.\n"); } else if (c == 'Y') { printf("Agreed.\n"); } else { printf("Not agreed.\n"); } }لاحظ أنه يتم تقديم خيارات إضافية. ومع ذلك، هذه ليست تعليمات برمجية فعالة.
-
يمكننا تحسين هذا الشيفرة كما يلي:
// Logical operators #include <cs50.h> #include <stdio.h> int main(void) { // Prompt user to agree char c = get_char("Do you agree? "); // Check whether agreed if (c == 'Y' || c == 'y') { printf("Agreed.\n"); } else { printf("Not agreed.\n"); } }لاحظ ذلك تم الآن إنشاء
||يعني بشكل فعال أو.
الحلقات وmeow.c (Loops and meow.c)
- يمكننا أيضًا استخدام كتلة بناء الحلقة من Scratch في برامج C الخاصة بنا.
-
في نافذتك الطرفية، اكتب
code meow.cواكتب الشيفرة كما يلي:// Opportunity for better design #include <stdio.h> int main(void) { printf("meow\n"); printf("meow\n"); printf("meow\n"); }لاحظ أن هذا يتم على النحو المنشود ولكن لديه فرصة لتصميم أفضل. يتكرر الشيفرة مرارا وتكرارا.
-
يمكننا تحسين برنامجنا عن طريق تعديل الشيفرة الخاصة بك على النحو التالي:
// Better design #include <stdio.h> int main(void) { int i = 3; while (i > 0) { printf("meow\n"); i--; } }لاحظ أننا قمنا بإنشاء
intiوقم بتعيين القيمة له3. ومن ثم نقوم بإنشاء أwhileحلقة سيتم تشغيلها طالماi > 0. وبعد ذلك، يتم تشغيل الحلقة. في كل مرة يتم طرح1منiباستخدامi--. -
وبالمثل، يمكننا تنفيذ عد الأنواع عن طريق تعديل الشيفرة الخاص بنا على النحو التالي:
// Print values of i #include <stdio.h> int main(void) { int i = 1; while (i <= 3) { printf("meow\n"); i++; } }لاحظ كيف عدادنا
iيبدأ في1. في كل مرة يتم تشغيل الحلقة، سيتم زيادة العداد بمقدار1. بمجرد أن يصبح العداد أكبر من3، سوف يقوم بإيقاف الحلقة. -
بشكل عام، في علوم الحاسوب، نقوم بالعد من الصفر. من الأفضل مراجعة الشيفرة الخاص بك على النحو التالي:
// Better design #include <stdio.h> int main(void) { int i = 0; while (i < 3) { printf("meow\n"); i++; } }لاحظ أننا الآن نعد من الصفر.
- هناك أداة أخرى في صندوق الأدوات الخاص بنا للتكرار وهي
forحلقة. -
يمكنك تحسين تصميم موقعنا بشكل أكبر
meow.cبرنامج باستخدامforحلقة. قم بتعديل الشيفرة الخاص بك كما يلي: تتضمن حلقة// Better design #include <stdio.h> int main(void) { for (int i = 0; i < 3; i++) { printf("meow\n"); } }لاحظ أن يتم استخدام كتلة
forثلاث وسائط. الحجة الأولىint i = 0يبدأ العداد عند الصفر. الحجة الثانيةi < 3هو الشرط الذي يتم التحقق منه. وأخيرا الحجةi++يخبر الحلقة بأن تزيد بمقدار واحد في كل مرة يتم فيها تشغيل الحلقة. -
يمكننا أيضًا التكرار إلى الأبد باستخدام الشيفرة التالي:
// Infinite loop #include <cs50.h> #include <stdio.h> int main(void) { while (true) { printf("meow\n"); } }لاحظ ذلك تم الآن إنشاء
trueسيكون هو الحال دائمًا. لذلك، سيتم تشغيل الشيفرة دائمًا. سوف تفقد السيطرة على نافذتك الطرفية عن طريق تشغيل هذا الرمز. يمكنك الخروج من حلقة لا نهائية عن طريق الضربcontrol-Cعلى لوحة المفاتيح (يرسل هذا إشارة SIGINT لإنهاء البرنامج). -
يمكننا أن نطلب من المستخدم عدد مرات المواء عن طريق تعديل الشيفرة كالتالي: يتم تعريف
// Prompts user for n. #include <cs50.h> #include <stdio.h> int main(void) { int n = get_int("What's n? "); for (int i = 0; i < n; i++) { printf("meow\n"); } }لاحظ ذلك تم الآن إنشاء
nمن قبل المستخدم. ثم هناكnمواء. -
ماذا يحدث إذا أدخل المستخدم شيئًا أقل من الصفر؟ قم بتعديل الشيفرة الخاص بك كما يلي:
// Prompts user again if need be. (Poor design.) #include <cs50.h> #include <stdio.h> int main(void) { int n = get_int("What's n? "); if (n < 0) { n = get_int("What's n? "); } for (int i = 0; i < n; i++) { printf("meow\n"); } }لاحظ أن هذا قد يمنع المستخدم من كتابة رقم أقل من الصفر مرة واحدة. ولكن ماذا يحدث إذا فعلوا ذلك عدة مرات؟
-
قم بتحسين الشيفرة الخاص بك كما يلي: سيتم تشغيل حلقة
// Uses a loop with continue/break. #include <cs50.h> #include <stdio.h> int main(void) { int n; while (true) { n = get_int("What's n? "); if (n < 0) { continue; } else { break; } } for (int i = 0; i < n; i++) { printf("meow\n"); } }لاحظ أن يتم استخدام كتلة
whileإلى الأبد حتىnأكبر من أو يساوي الصفر. -
ومع ذلك، يمكن تحسين هذا الشيفرة بشكل أكبر:
// Uses a loop with just break. #include <cs50.h> #include <stdio.h> int main(void) { int n; while (true) { n = get_int("What's n? "); if (n >= 0) { break; } } for (int i = 0; i < n; i++) { printf("meow\n"); } }لاحظ كيف تم تبسيط الشيفرة السابقة لدينا، وإزالة الأسطر غير الضرورية من الشيفرة.
-
يشبه أ حلقة
while، يمكننا تنفيذ هذا الشيفرة باستخدام ملف حلقةdo-while: سيتم تشغيل// Uses a do-while loop instead. #include <cs50.h> #include <stdio.h> int main(void) { int n; do { n = get_int("What's n? "); } while (n < 0); for (int i = 0; i < n; i++) { printf("meow\n"); } }لاحظ أن يتم استخدام كتلة
doدائمًا مرة واحدة على الأقل. سيتم تكرار هذا الجزء من الشيفرة أثناء ذلكnأقل من الصفر. - قد ترى العين الناقدة أننا نستطيع ذلك مجردة بعيدا الجزء من الشيفرة الذي يتموء.
الوظائف (Functions)
-
بينما سنقدم المزيد من الإرشادات لاحقًا، يمكنك إنشاء وظيفتك الخاصة داخل لغة C كما يلي:
void meow(void) { printf("meow\n"); }الأولي
voidيعني أن الدالة لا تُرجع أية قيم. ال(void)يعني أنه لم يتم توفير أي قيم للوظيفة. -
يمكن استخدام هذه الوظيفة في الوظيفة الرئيسية كما يلي:
// Abstraction #include <stdio.h> void meow(void); int main(void) { for (int i = 0; i < 3; i++) { meow(); } } // Meow once void meow(void) { printf("meow\n"); }لاحظ كيف يتم استدعاء الدالة
meowباستخدام الدالة تعليماتmeow(). وهذا ممكن لأن يتم تعريف وظيفةmeowفي الجزء السفلي من الشيفرة، و النموذج الأولي من الوظيفة متوفرة في الجزء العلوي من الشيفرة كـvoid meow(void). -
الخاص بك يمكن تعديل وظيفة
meowبشكل أكبر لقبول الإدخال:// Abstraction with parameterization #include <stdio.h> void meow(int n); int main(void) { meow(3); } // Meow some number of times void meow(int n) { for (int i = 0; i < n; i++) { printf("meow\n"); } }لاحظ أن النموذج الأولي قد تغير إلى
void meow(int n)لإظهار ذلكmeowيقبلintكمدخل له. -
عند العمل مع المتغيرات والوظائف، من المهم فهم نطاق للمتغير. خذ بعين الاعتبار الشيفرة التالي: تم تعريف
// Demonstrates scope #include <stdio.h> void meow(int n); int main(void) { int n = 3; meow(n); } // Meow some number of times void meow(int n) { for (int i = 0; i < n; i++) { printf("meow\n"); } }لاحظ كيف
nفي وظيفةmain. وبسبب ذلك،nيقع فقط في نطاق وظيفةmain. الطريقة الوحيدة التي وظيفةmeowقادرة على الاستخدامnهي تلك النسخة يتم تمريرnإلى وظيفةmeow.meowلا يستخدم النسخة الأصليةnمن وظيفةmain. بدلا من ذلك، فإنه يستخدم نسخته الخاصة منn. -
مع بعض التعديلات على الشيفرة الخاص بنا، يمكننا الحصول على مدخلات المستخدم: يتم استخدام
// User input #include <cs50.h> #include <stdio.h> void meow(int n); int main(void) { int n; do { n = get_int("Number: "); } while (n < 1); meow(n); } // Meow some number of times void meow(int n) { for (int i = 0; i < n; i++) { printf("meow\n"); } }لاحظ ذلك تم الآن إنشاء
get_intللحصول على رقم من المستخدم.nإلىmeow. -
يمكننا أيضًا إجراء اختبار للتأكد من صحة المدخلات التي نحصل عليها من المستخدم:
// Return value #include <cs50.h> #include <stdio.h> int get_positive_int(void); void meow(int n); int main(void) { int n = get_positive_int(); meow(n); } // Get number of meows int get_positive_int(void) { int n; do { n = get_int("Number: "); } while (n < 1); return n; } // Meow some number of times void meow(int n) { for (int i = 0; i < n; i++) { printf("meow\n"); } }لاحظ أنه تم استدعاء دالة جديدة
get_positive_intيطلب من المستخدم عددًا صحيحًا أثناءn < 1. بعد الحصول على عدد صحيح موجب، سيتم تنفيذ هذه الوظيفةreturn nالعودة إلى وظيفةmain.
الصحة، التصميم، الأسلوب (Correctness, Design, Style)
- يمكن تقييم الشيفرة على ثلاثة محاور.
- أولاً، الصحة يشير إلى "هل يعمل الشيفرة على النحو المنشود؟" يمكنك التحقق من صحة الشيفرة الخاصة بك مع
check50. - ثانيا، التصميم يشير إلى "ما مدى جودة تصميم الشيفرة؟" يمكنك تقييم تصميم الشيفرة الخاصة بك باستخدام
design50. - أخيرًا، النمط
يشير إلى "ما مدى جمالية الشيفرة واتساقه؟" يمكنك تقييم نمط الشيفرة الخاصة بك باستخدام
style50.
ماريو (Mario)
- لقد ركز كل ما ناقشناه اليوم على العناصر الأساسية المختلفة لعملك كعالم كمبيوتر ناشئ.
- سيساعدك ما يلي في التوجه نحو العمل على حل مشكلة محددة لهذا الفصل بشكل عام: كيف يمكن للمرء التعامل مع مشكلة متعلقة بعلوم الحاسوب؟
-
تخيل أننا أردنا محاكاة الصورة المرئية للعبة Super Mario Bros. بالنظر إلى مجموعات الأسئلة الأربعة الموضحة في الصورة، كيف يمكننا إنشاء كود يمثل هذه الكتل الأفقية الأربع تقريبًا؟

-
في النافذة الطرفية، اكتب
code mario.cوالشيفرة كما يلي:// Prints a row of 4 question marks #include <stdio.h> int main(void) { printf("????\n"); }لاحظ أنه تمت طباعة أربع علامات استفهام.
-
باستخدام الحلقة، يمكننا طباعة علامات الاستفهام بشكل أكثر كفاءة:
// Prints a row of 4 question marks with a loop #include <stdio.h> int main(void) { for (int i = 0; i < 4; i++) { printf("?"); } printf("\n"); }لاحظ كيف تتم طباعة أربع علامات استفهام هنا باستخدام حلقة.
-
وبالمثل، يمكننا تطبيق نفس المنطق لإنشاء ثلاث كتل رأسية.

-
لتحقيق ذلك، قم بتعديل الشيفرة الخاص بك كما يلي:
// Prints a column of 3 bricks with a loop #include <stdio.h> int main(void) { for (int i = 0; i < 3; i++) { printf("#\n"); } }لاحظ كيف تتم طباعة ثلاثة قوالب عمودية باستخدام حلقة.
-
ماذا لو أردنا دمج هذه الأفكار لإنشاء مجموعة من الكتل ثلاثية في ثلاثة؟

-
يمكننا اتباع المنطق أعلاه، والجمع بين نفس الأفكار. قم بتعديل الشيفرة الخاص بك كما يلي:
// Prints a 3-by-3 grid of bricks with nested loops #include <stdio.h> int main(void) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { printf("#"); } printf("\n"); } }لاحظ وجود حلقة واحدة داخل حلقة أخرى. تحدد الحلقة الأولى الصف الرأسي الذي تتم طباعته. لكل صف، تتم طباعة ثلاثة أعمدة. بعد كل صف، تتم طباعة سطر جديد.
-
ماذا لو أردنا التأكد من عدد الكتل ثابت، أي أنه غير قابل للتغيير؟ قم بتعديل الشيفرة الخاص بك كما يلي:
// Prints a 3-by-3 grid of bricks with nested loops using a constant #include <stdio.h> int main(void) { const int n = 3; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { printf("#"); } printf("\n"); } }لاحظ كيف
nأصبح الآن ثابتًا. لا يمكن تغييره أبدا. -
كما هو موضح سابقًا في هذه المحاضرة، يمكننا ذلك وظيفة مجردة بعيدا إلى وظائف. خذ بعين الاعتبار الشيفرة التالي:
// Helper function #include <stdio.h> void print_row(int width); int main(void) { const int n = 3; for (int i = 0; i < n; i++) { print_row(n); } } void print_row(int width) { for (int i = 0; i < width; i++) { printf("#"); } printf("\n"); }لاحظ كيف تتم طباعة صف من خلال وظيفة جديدة.
المشغلين (Operators)
-
المشغلين يشير إلى العمليات الرياضية التي يدعمها المترجم الخاص بك. في لغة C، تتضمن هذه العوامل الرياضية ما يلي:
-
+للإضافة -
-للطرح -
*للضرب -
/للتقسيم -
%للباقي
-
- سنستخدم كل هذه العوامل في هذه الدورة.
-
دعونا ننفذ الآلة الحاسبة الخاصة بنا عن طريق الكتابة
code calculator.cفي المحطة وتعديل الشيفرة الخاص بنا على النحو التالي:// Addition with int #include <cs50.h> #include <stdio.h> int main(void) { // Prompt user for x int x = get_int("What's x? "); // Prompt user for y int y = get_int("What's y? "); // Add numbers int z = x + y; // Perform addition printf("%i\n", z); }لاحظ كيف قمنا بإنشاء متغير ثالث
zلتخزين مجموعxوy، ثم اطبع النتيجة باستخدام%i(محدد التنسيق للأعداد الصحيحة). -
يمكننا كتابة تعليمات برمجية أكثر كفاءة على النحو التالي:
// Addition with int, without third variable #include <cs50.h> #include <stdio.h> int main(void) { // Prompt user for x int x = get_int("What's x? "); // Prompt user for y int y = get_int("What's y? "); // Perform addition printf("%i\n", x + y); }لاحظ أننا قمنا بإلغاء الحاجة إلى المتغير الثالث
zعن طريق إجراء الإضافة مباشرة داخل بيانprintf، مما يجعل الشيفرة الخاص بنا أكثر إيجازًا. -
يمكننا استخدام الضرب:
// Doubles a number #include <cs50.h> #include <stdio.h> int main(void) { // Prompt user for x int x = get_int("What's x? "); // Double it printf("%i\n", x * 2); }لاحظ كيف نستخدم عامل الضرب
*لمضاعفة قيمة الإدخال، مما يوضح عملية حسابية أخرى بخلاف الجمع. -
الأعداد الصحيحة في
Cيمكن أن يعد عاليًا جدًا. خذ بعين الاعتبار ما يلي:// Overflow #include <cs50.h> #include <stdio.h> int main(void) { int dollars = 1; while (true) { char c = get_char("Here's $%i. Double it and give to next person? ", dollars); if (c == 'y') { dollars *= 2; } else { break; } } printf("Here's $%i.\n", dollars); }لاحظ كيف يقوم البرنامج بمضاعفة المبلغ بالدولار بشكل متكرر. في النهاية، سيتجاوز العدد الصحيح الحد الأقصى لقيمته و"التجاوز"، ويلتف حول رقم سالب أو صفر.
- يحدث تجاوز عدد صحيح عندما تنتج عملية حسابية قيمة تتجاوز الحد الأقصى لسعة التخزين لنوع البيانات، مما يتسبب في التفاف القيمة بشكل غير متوقع.
- أحد التحديات التي تواجه لغة C هو أنه على الرغم من أنها توفر لك تحكمًا هائلاً في كيفية استخدام الذاكرة، إلا أنه يجب على المبرمجين أن يكونوا على دراية تامة بالمخاطر المحتملة لإدارة الذاكرة.
- تشير الأنواع إلى البيانات المحتملة التي يمكن تخزينها في متغير. على سبيل المثال، أ
تم تصميم
charلاستيعاب حرف واحد مثلaأو2. - الأنواع مهمة جدًا لأن كل نوع له حدود معينة. على سبيل المثال، بسبب الحدود في الذاكرة، أعلى قيمة موقعة
intعادةً ما يكون2147483647، في حين أنه غير موقعintيمكن أن تصل4294967295. إذا حاولت حسابintأعلى من الحد الأقصى، وهو تجاوز العدد الصحيح سيؤدي إلى تخزين قيمة غير صحيحة في هذا المتغير. - يحدد عدد البتات نطاق القيم التي يمكننا تمثيلها.
- يمكن أن يكون لهذا تأثيرات كارثية في العالم الحقيقي.
-
يمكننا حل هذه المشكلة باستخدام ملف
longنوع المتغير:// long #include <cs50.h> #include <stdio.h> int main(void) { long dollars = 1; while (true) { char c = get_char("Here's $%li. Double it and give to next person? ", dollars); if (c == 'y') { dollars *= 2; } else { break; } } printf("Here's $%li.\n", dollars); }لاحظ أننا تغيرنا من
intإلىlongوالاستخدام%liبدلاً من%iفي سلاسل التنسيق الخاصة بنا. أ يمكن لـlongتخزين قيم أكبر بكثير منint، يؤخر (ولكن لا يزيل) مشكلة الفائض. -
ربما تعلم أن الأعداد الصحيحة ومتغيرات الفاصلة العائمة لها اختلاف كبير: القدرة على تمثيل أرقام أقل من
1. خذ بعين الاعتبار ما يلي:// Division with ints, demonstrating truncation #include <cs50.h> #include <stdio.h> int main(void) { // Prompt user for x int x = get_int("What's x? "); // Prompt user for y int y = get_int("What's y? "); // Divide x by y printf("%i\n", x / y); }لاحظ أنه عند قسمة عددين صحيحين، تقوم لغة C بإجراء قسمة عدد صحيح واقتطاع (تجاهل) أي جزء عشري. على سبيل المثال، 7/2 سيعطي 3، وليس 3.5.
- عدم دقة النقطة العائمة يوضح أن هناك حدودًا لمدى دقة أجهزة الكمبيوتر في حساب الأرقام.
- أثناء قيامك بالبرمجة، انتبه بشكل خاص لأنواع المتغيرات التي تستخدمها لتجنب المشاكل داخل الشيفرة الخاصة بك.
-
قمنا بفحص بعض الأمثلة على الكوارث التي يمكن أن تحدث من خلال الأخطاء المتعلقة بالنوع.
-
وبالمثل، يمكننا ذلك
castعدد صحيح ليكون أfloat. خذ بعين الاعتبار ما يلي:// Casting #include <cs50.h> #include <stdio.h> int main(void) { // Prompt user for x int x = get_int("What's x? "); // Prompt user for y int y = get_int("What's y? "); // Divide x by y printf("%f\n", (float) x / y); }لاحظ كيف قمنا بالإلقاء
xإلى أfloatقبل استخدام القسمة(float) x. يؤدي هذا إلى تحويل العدد الصحيح إلى رقم الفاصلة العائمة، مما يسمح للقسمة بإنتاج نتيجة عشرية بدلاً من الاقتطاع. -
يمكننا استخدامه
floatطوال الوقت:// Floats #include <cs50.h> #include <stdio.h> int main(void) { // Prompt user for x float x = get_float("What's x? "); // Prompt user for y float y = get_float("What's y? "); // Divide x by y printf("%.50f\n", x / y); }لاحظ أننا نستخدم
get_floatللإدخال و%.50fلعرض ما يصل إلى 50 منزلة عشرية، مما يكشف عن حدود دقة الفاصلة العائمة حيث قد تظهر النتيجة أرقامًا غير متوقعة بسبب قيود التمثيل الثنائي.
التلخيص (Summing Up)
في هذا الدرس، تعلمت كيفية تطبيق الكتل البرمجية الإنشائية التي تعلمتها في Scratch على لغة البرمجة C. تعلمت…
- كيفية إنشاء برنامجك الأول في لغة C.
- كيفية استخدام سطر الأوامر.
- حول الوظائف المحددة مسبقًا والتي تأتي أصلاً مع لغة C.
- كيفية استخدام المتغيرات والشروط والحلقات.
- كيفية إنشاء وظائفك الخاصة لتبسيط وتحسين الشيفرة الخاصة بك.
- كيفية تقييم الشيفرة الخاص بك على ثلاثة محاور: الصحة والتصميم والأسلوب.
- كيفية دمج التعليقات في الشيفرة الخاصة بك.
- كيفية الاستفادة من الأنواع والعوامل والآثار المترتبة على اختياراتك.
نراكم في المرة القادمة!