C: الإدخال والإخراج
الإدخال والإخراج أشبه بمحادثة بينك وبين الحاسوب - printf هو الحاسوب يتحدث معك، و scanf هو أنت تتحدث مع الحاسوب. أصب التنسيق، وإلا س تتحدثان بلا تفاهم.
1. إخراج printf المنسق
يرمز printf إلى "print formatted" (طباعة منسقة). وسيطته الأولى هي سلسلة تنسيق، تليها القيم المراد إخراجها.
(1) محددات التنسيق الأساسية
| المحدد | الغرض | مثال | المخرجات |
|---|---|---|---|
%d |
عدد صحيح عشري | printf("%d", 42) |
42 |
%f |
فاصلة عائمة | printf("%f", 3.14) |
3.140000 |
%c |
محرف واحد | printf("%c", 'A') |
A |
%s |
سلسلة نصية | printf("%s", "hi") |
hi |
%x |
سداسي عشري | printf("%x", 255) |
ff |
%o |
ثماني | printf("%o", 8) |
10 |
%p |
عنوان المؤشر | printf("%p", &a) |
قيمة العنوان |
%% |
علامة نسبة حرفية | printf("100%%") |
100% |
#include <stdio.h>
int main(void) {
int age = 25;
float height = 175.5f;
char grade = 'A';
printf("العمر: %d، الطول: %.1f، التقدير: %c\n", age, height, grade);
return 0;
}
العمر: 25، الطول: 175.5، التقدير: A
(2) العرض والمحاذاة
يمكنك إدراج أرقام بين % ومحدد التنسيق للتحكم في عرض المخرجات:
%5d: عرض أدنى 5 محارف، محاذاة لليمين%-5d: عرض أدنى 5 محارف، محاذاة لليسار%05d: حشو بالأصفار حتى 5 أرقام
#include <stdio.h>
int main(void) {
int num = 42;
printf("[%5d]\n", num);
printf("[%-5d]\n", num);
printf("[%05d]\n", num);
printf("[%+5d]\n", num);
return 0;
}
[ 42]
[42 ]
[00042]
[ +42]
(3) دقة الفاصلة العائمة
%.2f: رقمان بعد الفاصلة العشرية%8.2f: إجمالي عرض 8 محارف على الأقل، رقمان بعد الفاصلة العشرية%-8.2f: نسخة محاذاة لليسار
#include <stdio.h>
int main(void) {
double pi = 3.14159265358979;
printf("افتراضي: %f\n", pi);
printf("منزلتان: %.2f\n", pi);
printf("6 منازل: %.6f\n", pi);
printf("8.2: %8.2f\n", pi);
return 0;
}
افتراضي: 3.141593
منزلتان: 3.14
6 منازل: 3.141593
8.2: 3.14
%f افتراضيا 6 منازل عشرية. استخدم %.0f لإخفاء الجزء العشري بالكامل.
2. قراءة الإدخال بـ scanf
يرمز scanf إلى "scan formatted" (مسح منسق). يقرأ البيانات من المدخلات القياسية وفقا لسلسلة التنسيق ويخزنها في متغيرات.
(1) الاستخدام الأساسي
#include <stdio.h>
int main(void) {
int age;
float score;
printf("أدخل عمرك: ");
scanf("%d", &age);
printf("أدخل درجتك: ");
scanf("%f", &score);
printf("العمر: %d، الدرجة: %.1f\n", age, score);
return 0;
}
أدخل عمرك: 20
أدخل درجتك: 92.5
العمر: 20، الدرجة: 92.5
& (معامل أخذ العنوان)، تخبر scanf "خزّن القيمة في هذا العنوان." نسيان & هو أكثر أخطاء المبتدئين شيوعا - البرنامج لن يُخطئ لكنه سينهار.
(2) قراءة عدة قيم
#include <stdio.h>
int main(void) {
int a, b, c;
printf("أدخل ثلاثة أعداد صحيحة (مفصولة بمسافات): ");
scanf("%d %d %d", &a, &b, &c);
printf("أدخلت: %d، %d، %d\n", a, b, c);
return 0;
}
أدخل ثلاثة أعداد صحيحة (مفصولة بمسافات): 10 20 30
أدخلت: 10، 20، 30
افتراضيا، يستخدم scanf المسافات البيضاء (مسافات، أسطر جديدة، جدولات) لفصل القيم المختلفة.
(3) قراءة المحارف والسلاسل النصية
#include <stdio.h>
int main(void) {
char ch;
char name[20];
printf("أدخل محرفا: ");
scanf(" %c", &ch);
printf("أدخل اسمك (بدون مسافات): ");
scanf("%s", name);
printf("المحرف: %c، الاسم: %s\n", ch, name);
return 0;
}
%c (" %c") تتجاوز محارف المسافات البيضاء، وإلا ستقرأ سطرا جديدا متبقيا من إدخال سابق. %s يقرأ سلسلة نصية لكنه يتوقف عند المسافة البيضاء. name اسم مصفوفة، وهو بالفعل عنوان، لذا لا حاجة لـ &.
(4) القيمة المرجعة لـ scanf
تُرجع scanf عدد المتغيرات المقروءة بنجاح. يمكن استخدام هذه الميزة للتحقق من صحة الإدخال:
#include <stdio.h>
int main(void) {
int num;
printf("أدخل عددا صحيحا: ");
int result = scanf("%d", &num);
if (result == 1) {
printf("تمت القراءة بنجاح: %d\n", num);
} else {
printf("إدخال غير صالح!\n");
}
return 0;
}
أدخل عددا صحيحا: abc
إدخال غير صالح!
3. getchar و putchar
getchar() تقرأ محرفا واحدا من لوحة المفاتيح، و putchar() تُخرج محرفا واحدا إلى الشاشة. هما أبسط وأكفأ من scanf("%c") و printf("%c").
#include <stdio.h>
int main(void) {
char ch;
printf("أدخل محرفا: ");
ch = getchar();
printf("أدخلت: ");
putchar(ch);
putchar('\n');
return 0;
}
أدخل محرفا: X
أدخلت: X
(1) قراءة سطر كامل
getchar() مع حلقة يمكنها قراءة سطر كامل حتى يُصادف سطر جديد:
#include <stdio.h>
int main(void) {
char ch;
printf("أدخل سطرا من النص: ");
while ((ch = getchar()) != '\n') {
putchar(ch);
}
putchar('\n');
return 0;
}
أدخل سطرا من النص: مرحبا بالعالم!
مرحبا بالعالم!
while ((ch = getchar()) != '\n') أسلوب كلاسيكي: اقرأ محرفا أولا في ch، ثم تحقق إن كان سطرا جديدا. لاحظ أن الأقواس الخارجية حول الإسناد إلزامية.
4. مشاكل المخزن المؤقت
المدخلات القياسية في C تستخدم التخزين المؤقت السطري: لا يُسلّم سطر البيانات بالكامل إلى المخزن المؤقت ليقرأه البرنامج إلا بعد أن يضغط المستخدم Enter. هذا يمكن أن يسبب بعض المشاكل المحيرة.
(1) المشكلة: scanf %c تقرأ سطرا جديدا متبقيا
#include <stdio.h>
int main(void) {
int num;
char ch;
printf("أدخل عددا صحيحا: ");
scanf("%d", &num);
printf("أدخل محرفا: ");
scanf("%c", &ch);
printf("العدد=%d، المحرف=%d\n", num, ch);
return 0;
}
أدخل عددا صحيحا: 42
أدخل محرفا: العدد=42، المحرف=10
بعد كتابة 42 والضغط على Enter، المخزن المؤقت يحتوي على 42\n. يقرأ scanf("%d") الرقم 42، بينما يقرأ scanf("%c") فورا الـ \n المتبقي (كود ASCII 10)، دون انتظارك لكتابة محرف.
(2) الحلول
الحل 1: إضافة مسافة قبل %c (موصى به)
scanf(" %c", &ch);
المسافة تتجاوز جميع محارف المسافات البيضاء (بما فيها الأسطر الجديدة والمسافات والجدولات).
الحل 2: استخدام getchar() لامتصاص المتبقي
scanf("%d", &num);
getchar();
scanf("%c", &ch);
الحل 3: تفريغ مخزن الإدخال المؤقت
int c;
while ((c = getchar()) != '\n' && c != EOF) {}
fflush(stdin) لتفريغ مخزن الإدخال المؤقت - إنه سلوك غير معرف في معيار C. بعض المترجمات تدعمه، لكنه غير قابل للنقل.
▶ مثال
اكتب برنامجا يقرأ عددا صحيحا ومحرفا، مع معالجة متبقيات المخزن المؤقت بشكل صحيح:
#include <stdio.h>
int main(void) {
int age;
char gender;
printf("أدخل عمرك: ");
scanf("%d", &age);
printf("أدخل جنسك (ذ/م): ");
scanf(" %c", &gender);
printf("العمر: %d، الجنس: %c\n", age, gender);
return 0;
}
أدخل عمرك: 25
أدخل جنسك (ذ/م): ذ
العمر: 25، الجنس: ذ
▶ مثال
استخدم getchar() لقراءة المحارف واحدا تلو الآخر وعد عدد الحروف والأرقام في سطر:
#include <stdio.h>
int main(void) {
char ch;
int letters = 0;
int digits = 0;
printf("أدخل سطرا من النص: ");
while ((ch = getchar()) != '\n') {
if (ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') {
letters++;
} else if (ch >= '0' && ch <= '9') {
digits++;
}
}
printf("حروف: %d، أرقام: %d\n", letters, digits);
return 0;
}
أدخل سطرا من النص: Hello 2024!
حروف: 5، أرقام: 4
5. puts و fputs
puts() تُخرج سلسلة نصية وتُضيف تلقائيا سطرا جديدا. هي أبسط من printf ومثالية لإخراج النص البسيط:
#include <stdio.h>
int main(void) {
puts("مرحبا بالعالم!");
puts("سطر جديد تلقائي، لا حاجة لـ \\n");
return 0;
}
مرحبا بالعالم!
سطر جديد تلقائي، لا حاجة لـ \n
puts() أكفأ من printf("%s\n", ...) لأنها لا تحتاج لتحليل سلسلة تنسيق. حين لا تحتاج تنسيقا، فضّل puts.
❓ أسئلة شائعة
& أمامها؟& يأخذ عنوان المتغير. فقط أسماء المصفوفات لا تحتاجه، لأن اسم المصفوفة هو بالفعل عنوان أول عنصر فيها.scanf(" %c", &ch) لتجاوز المسافات البيضاء.%d الصغيرة تقابل int؛ %D الكبيرة غير قياسية. لكن %x تطبع سداسي عشري بأحرف صغيرة (abcdef) بينما %X تطبع بأحرف كبيرة (ABCDEF) - هذا صالح.scanf("%s") يتوقف عند المسافة البيضاء. استخدم fgets(name, sizeof(name), stdin) لقراءة سطر كامل - يدعم المسافات وهو أكثر أمانا.📖 ملخص
printfيستخدم محددات التنسيق للتحكم في المخرجات: العرض، الدقة، المحاذاة، الحشوscanfيتطلب&قبل المتغيرات؛ أضف مسافة قبل%cلتجنب قراءة الأسطر الجديدة المتبقيةgetchar/putcharخيارات كفؤة لإدخال/إخراج المحرف الواحد- التخزين المؤقت السطري يسبب مشاكل بيانات متبقية بين استدعاءات scanf و getchar
- القيمة المرجعة لـ scanf يمكن استخدامها للتحقق من نجاح الإدخال
📝 تمارين
- اكتب برنامجا يقرأ نصف قطر دائرة ويُخرج مساحتها ومحيطها باستخدام تنسيق
%.2fفي printf. - اكتب برنامجا يستخدم
getchar()لقراءة سطر من الإدخال ويعد عدد الحروف الكبيرة والصغيرة التي يحتويها. - اكتب برنامجا يقرأ عددا صحيحا ويُخرجه بالصيغ العشرية (
%d) والسداسية عشرية (%x) والثمانية (%o).