C: تطبيق: تمارين للمبتدئين
تعلّم البرمجة كتعلّم السباحة — قراءة الكتب لا تغني عن النزول إلى الماء. يربط هذا الدرس بين الدروس التسعة الأولى من خلال كتابة 3 برامج مصغّرة كاملة.
1. المشروع 1: محوّل من سلسزيوس إلى فهرنهايت
يجمع هذا المشروع بين المتغيرات والعمليات الحسابية والإدخال/الإخراج. الصيغة هي:
F = C x 9 / 5 + 32
(1) تحليل المتطلبات
- الإدخال: درجة الحرارة بالسلسزيوس (قد تكون عشرية)
- الإخراج: درجة الحرارة المقابلة بالفهرنهايت، مقرّبة إلى منزلة عشرية واحدة
- توسيع: إخراج أيضًا درجة الحرارة بالكلفن (K = C + 273.15)
(2) المفاهيم الأساسية
- نوع
doubleلتخزين الأعداد العشرية scanf("%lf")لقراءة عدد عشري مضاعف الدقةprintf("%.1f")للتحكم في المنازل العشرية- أسبقية المؤثرات في التعابير الحسابية
▶ مثال
#include <stdio.h>
int main(void) {
double celsius;
printf("Enter temperature in Celsius: ");
scanf("%lf", &celsius);
double fahrenheit = celsius * 9.0 / 5.0 + 32.0;
double kelvin = celsius + 273.15;
printf("\n===== Temperature Conversion =====\n");
printf("Celsius: %.2f C\n", celsius);
printf("Fahrenheit:%.2f F\n", fahrenheit);
printf("Kelvin: %.2f K\n", kelvin);
printf("==================================\n");
return 0;
}
Enter temperature in Celsius: 36.5
===== Temperature Conversion =====
Celsius: 36.50 C
Fahrenheit:97.70 F
Kelvin: 309.65 K
==================================
9.0 / 5.0 بدلًا من 9 / 5، لأن القسمة الصحيحة 9/5 تساوي 1 وليس 1.8، مما ينتج نتائج خاطئة.
(3) الأخطاء الشائعة
- القسمة الصحيحة:
celsius * 9 / 5تقتطع9/5إلى 1 → اكتب9.0/5.0بدلًا من ذلك - استخدام
%fفيscanfمعdouble: يجب استخدام%lfمعdouble؛ وprintfيمكنه استخدام%fمعdouble - نسيان
&:scanf("%lf", celsius)سيتسبب بانهيار ←scanf("%lf", &celsius)
(4) تحدي توسيع
هل يمكنك عكس التحويل — إدخال فهرنهايت وإخراج سلسزيوس؟ الصيغة هي C = (F - 32) x 5 / 9.
2. المشروع 2: مدقق السنوات الكبيسة
يجمع هذا المشروع بين الجمل الشرطية والمؤثرات المنطقية ومؤثر باقي القسمة.
(1) قواعد السنة الكبيسة
- قابلة للقسمة على 4 ولكن ليس على 100 → سنة كبيسة
- قابلة للقسمة على 400 → سنة كبيسة أيضًا
- خلاف ذلك → سنة عادية
يُعبَّر عنها كشرط منطقي:
(year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)
(2) تحليل المتطلبات
- الإدخال: عدد صحيح موجب يمثل سنة
- الإخراج: ما إذا كانت السنة كبيسة أم عادية، وعدد أيام فبراير
- تحقق دفاعي: معالجة المدخلات غير الصالحة (أعداد سالبة أو صفر)
(3) المفاهيم الأساسية
- باقي القسمة
%للتحقق من القابلية للقسمة - المؤثرات المنطقية
&&و||لدمج الشروط - بنية متعددة الفروع
if-else if-else - التحقق من المدخلات
▶ مثال
#include <stdio.h>
int main(void) {
int year;
printf("Enter a year: ");
scanf("%d", &year);
if (year <= 0) {
printf("Error: Year must be a positive integer\n");
return 1;
}
int is_leap = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
int feb_days = is_leap ? 29 : 28;
printf("\n===== Result =====\n");
printf("Year: %d\n", year);
printf("Type: %s\n", is_leap ? "Leap year" : "Common year");
printf("Feb days: %d\n", feb_days);
printf("==================\n");
return 0;
}
Enter a year: 2000
===== Result =====
Year: 2000
Type: Leap year
Feb days: 29
==================
اختبر بعض السنوات الحدية:
| السنة | النتيجة المتوقعة | السبب |
|---|---|---|
| 2000 | سنة كبيسة | قابلة للقسمة على 400 |
| 1900 | سنة عادية | قابلة للقسمة على 100 ولكن ليس على 400 |
| 2024 | سنة كبيسة | قابلة للقسمة على 4 ولكن ليس على 100 |
| 2023 | سنة عادية | غير قابلة للقسمة على 4 |
(4) الاشتقاق خطوة بخطوة
يخطئ المبتدئون غالبًا في شرط السنة الكبيسة. لنشتقه خطوة بخطوة:
- الخطوة الأولى: القسمة على 4 → غالبًا سنة كبيسة
- الخطوة الثانية: لكن سنوات القرن القابلة للقسمة على 100 عادة ليست كبيسة → أضف الشرط "وغير قابلة للقسمة على 100"
- الخطوة الثالثة: لكن سنوات القرن القابلة للقسمة على 400 هي كبيسة → أضف الشرط "أو قابلة للقسمة على 400"
3. المشروع 3: آلة حاسبة بسيطة
يجمع هذا المشروع بين switch-case والحلقات والإدخال/الإخراج والعمليات الحسابية.
(1) تحليل المتطلبات
- الإدخال: رقمان ومؤثر (+ - * /)
- الإخراج: نتيجة الحساب
- تحقق دفاعي: عرض رسالة عند القسمة على صفر
- حلقة: سؤال ما إذا كان المستخدم يريد المتابعة بعد كل حساب
(2) المفاهيم الأساسية
switch-caseلمعالجة المؤثراتdo-whileللحسابات المتكررة- التحقق من القسمة على صفر
- محاذاة الإخراج المنسّق
continueلتخطي العمليات غير الصالحة
▶ مثال
#include <stdio.h>
int main(void) {
double a, b;
char op;
char again;
do {
printf("\n===== Simple Calculator =====\n");
printf("Enter expression (e.g. 3 + 5): ");
scanf("%lf %c %lf", &a, &op, &b);
printf("--------------------\n");
switch (op) {
case '+':
printf("%.2f + %.2f = %.2f\n", a, b, a + b);
break;
case '-':
printf("%.2f - %.2f = %.2f\n", a, b, a - b);
break;
case '*':
printf("%.2f * %.2f = %.2f\n", a, b, a * b);
break;
case '/':
if (b == 0) {
printf("Error: Division by zero!\n");
} else {
printf("%.2f / %.2f = %.2f\n", a, b, a / b);
}
break;
default:
printf("Error: Unsupported operator '%c'\n", op);
break;
}
printf("--------------------\n");
printf("Continue? (Y/N): ");
scanf(" %c", &again);
} while (again == 'Y' || again == 'y');
printf("Goodbye!\n");
return 0;
}
===== Simple Calculator =====
Enter expression (e.g. 3 + 5): 10 / 3
--------------------
10.00 / 3.00 = 3.33
--------------------
Continue? (Y/N): Y
===== Simple Calculator =====
Enter expression (e.g. 3 + 5): 5 / 0
--------------------
Error: Division by zero!
--------------------
Continue? (Y/N): N
Goodbye!
(3) نقاط التصميم البارزة
- صيغة الإدخال:
scanf("%lf %c %lf", &a, &op, &b)تقرأ ثلاث قيم في استدعاء واحد، مفصولة بمسافات — مختصرة وطبيعية - حماية القسمة على صفر: في
case '/'، تحقق منb == 0أولًا لتجنب خطأ وقت التنفيذ - التحكم بالحلقة:
do-whileتضمن حسابًا واحدًا على الأقل؛ والمستخدم يختار المتابعة - معالجة المخزن المؤقت: المسافة قبل
%cفيscanf(" %c", &again)تتجاوز سطر السطر الجديد المتبقي من الإدخال السابق
(4) تحدي توسيع
أضف مؤثر باقي القسمة % إلى الآلة الحاسبة (لاحظ أن المعاملات يجب أن تكون أعدادًا صحيحة)، وتلميحًا للأُس (باستخدام دالة pow من math.h).
4. مراجعة شاملة للمعرفة
تغطي هذه المشاريع الثلاثة المعرفة الأساسية من الدروس التسعة الأولى:
| المشروع | المفاهيم المغطّاة |
|---|---|
| تحويل درجات الحرارة | المتغيرات والأنواع، الحساب، تنسيق printf، إدخال scanf، فخ القسمة الصحيحة |
| مدقق السنوات الكبيسة | باقي القسمة، مؤثرات العلاقات، المؤثرات المنطقية، if-else، المؤثر الثلاثي، التحقق من المدخلات |
| الآلة الحاسبة البسيطة | switch-case، حلقة do-while، continue، معالجة المخزن المؤقت، التحقق من القسمة على صفر |
(1) خطوات عامة لكتابة برامج جيدة
- فهم المتطلبات: ما الإدخال؟ ما الإخراج؟ ما حالات الحد؟
- اختر الهياكل: أي الجمل تستخدم؟ if أم switch؟ for أم while؟
- اكتب شيفرة زائفة: صف المنطق بلغة طبيعية أولًا، ثم حوّلها إلى C
- نفّذ تدريجيًا: اكتب واختبر أثناء التقدم؛ لا تكتب كل شيء دفعة واحدة قبل التنقيح
- اختبر شاملًا: اختبر القيم العادية وقيم الحدود والقيم غير الصالحة
❓ أسئلة شائعة
scanf إلى %lf مع double بينما يستخدم printfالمتغير %f؟scanf معرفة الحجم الدقيق للمعامل لكتابة الذاكرة بشكل صحيح؛ double و float لهما أحجام مختلفة. في printf، يُرقّى float تلقائيًا إلى double، لذا يعمل %f مع كليهما.b == 0 لعدد عشري موثوقة؟==، لكن عندما يُدخل المستخدم 0 مباشرة، يكون 0.0 تمامًا. الأسلوب الأكثر دقة هو fabs(b) < 1e-10، والذي يتطلب math.h.printf في نقاط رئيسية لإخراج قيم المتغيرات الوسيطة، وضيّق نطاق الخطأ تدريجيًا. يُسمى هذا "التنقيح بـ printf" — أبسط وأكثر تقنيات التنقيح فعالية.📖 ملخص
- كتابة برامج كاملة هي أسرع طريقة لإتقان C؛ القراءة وحدها لن تكفي
- القسمة الصحيحة هي أكثر الفخاخ شيوعًا في الحساب العشري — تأكد من كتابة أحد المعاملات على الأقل كعدد عشري
- اشتق الشروط المعقدة خطوة بخطوة: اكتب القاعدة الأساسية أولًا، ثم أضف التصحيحات
- switch-case مقترنة بـ do-while هي النمط الكلاسيكي للقوائم التفاعلية
- سير العمل العام للبرمجة: فهم المتطلبات → اختر الهياكل → اكتب شيفرة زائفة → نفّذ → اختبر
📝 تمارين
- أضف ميزة التحويل العكسي إلى برنامج درجات الحرارة: أدخل 1 للتحويل من سلسزيوس إلى فهرنهايت، و2 للتحويل من فهرنهايت إلى سلسزيوس، باستخدام switch أو if-else.
- حسّن برنامج السنوات الكبيسة ليقبل سنة بداية وسنة نهاية، ثم يُخرج جميع السنوات الكبيسة في ذلك النطاق (باستخدام حلقة for).
- أضف باقي القسمة
%والقسمة الصحيحة إلى الآلة الحاسبة. لاحظ أن باقي القسمة يتطلب معاملات أعداد صحيحة، لذا اطلب من المستخدم إدخال أعداد صحيحة.