الإدخال/الإخراج

عند تشغيل المستخدم لبرنامج ما، تظهر له شاشة تُسمّى الطرفية (terminal). من خلال هذه الشاشة يمكن للبرنامج عرض المعلومات أو استقبالها من المستخدم. نُطلق على عملية عرض المعلومات اسم الإخراج (output)، وعلى عملية استقبال المعلومات من المستخدم اسم الإدخال (input).

التيارات (Streams)

يُنفَّذ الإدخال والإخراج في لغة ++C من خلال ما يُسمّى التيارات (streams). التيار هو نوع بيانات (datatype) يمكنه استقبال البيانات أو إرسالها (أو كليهما). تياران الرئيسيان المستخدمان في ++C هما cin للإدخال وcout للإخراج.

للتعامل مع التيارات، نستخدم العاملين << و >>، كما في الأمثلة التالية:

stream << variable; // تُغذي قيمة المتغير إلى التيار
stream >> variable; // تأخذ البيانات من التيار وتخزنها في المتغير

في الحالة الأولى، لا يتغير المتغير، أما في الحالة الثانية فإن المتغير يحصل على قيمة جديدة.

Noteملحوظة

يشير مصطلح “Stream” هنا إلى نوع (type)، بينما cin وcout هما متغيران من هذا النوع.

ولكي نتمكن من استخدام التيارات (cin و cout)، يجب أن نضيف السطر #include <iostream> في بداية البرنامج.

cout

افترض أنك كتبت البرنامج التالي:

int x = 5;
// add 1 if x is divisible by 3 and add 2 otherwise
int y = x + (x % 3 == 0 ? 1 : 2);

المتغير y مخزَّن في الذاكرة، ولا توجد طريقة للمستخدم لمعرفة قيمته. إذا أردت أن تُظهر هذه القيمة للمستخدم، فعليك إخراجها إلى الطرفية.

cout << y;

سيعرض هذا السطر قيمة المتغير y على الطرفية. وإذا أردنا طباعة نص عادي، نستخدم "..." كما يلي:

cout << "The value of y is";
cout << y;

النتيجة ستكون:

The value of y is7

وهذا لا يبدو صحيحًا تمامًا، والسبب هو أن ++C لا تفهم ما يبدو مناسبًا أو غير مناسب بصريًا، فهي تنفذ التعليمات كما هي. وبما أننا لم نحدد وجود مسافة بعد كلمة “is”، لم يُضف البرنامج واحدة. لذا يجب أن نكتب:

cout << "The value of y is ";
cout << y;

ويمكننا طباعة تعبيرات متعددة في السطر نفسه:

cout << "The value of y is " << y;

كما يمكننا طباعة رمز السطر الجديد '\n' للانتقال إلى سطر جديد:

cout << "Hello" << '\n' << "World";

الناتج سيكون:

Hello
World

cin

نعرف الآن كيفية كتابة برنامج يُعرّف البيانات ويتعامل معها ويطبعها. لكن المشكلة أن البرنامج يقوم بالعمليات نفسها في كل مرة يُشغَّل فيها. قد نرغب أحيانًا في كتابة برنامج يسمح للمستخدم بإدخال القيم في كل مرة. لهذا نستخدم cin.

int x;
cin >> x;
cout << "You entered: " << x;

في هذا المثال، يتوقف تنفيذ البرنامج عند التعليمة cin >> x حتى يُدخل المستخدم قيمة في الطرفية ثم يضغط على Enter. بعد ذلك تُخزَّن القيمة في المتغير x.

مثال على الإدخال:

5

الناتج المتوقع:

You entered: 5
Noteملحوظة

لاحظ أن العاملين المستخدمين في cin وcout مختلفان: >> مع cin، و<< مع cout.

الدالة getline

عند استخدام cin، يقرأ التيار حتى يجد فراغًا أبيض أو نهاية الإدخال. أحيانًا قد نرغب في قراءة السطر كاملًا حتى لو احتوى على مسافات. لهذا نستخدم الدالة getline.

string s;
getline(cin, s);

cout << "The line is: " << s;

لاستخدام getline يجب تمرير معاملين: التيار الذي نريد القراءة منه، والمتغير الذي سنخزن فيه النتيجة.

Cautionحذر

لا يُنصح باستخدام cin وgetline معًا في البرنامج نفسه.

مسألة تدريبية

مسألة تدريبية

اكتب برنامجًا يقرأ عددين صحيحين ويطبع أولًا الأصغر منهما ثم الأكبر، كل واحد في سطر منفصل.

حل المسألة التدريبية

خطوات حل المسألة كالتالي:

  • تعريف متغيرين من نوع عدد صحيح لتخزين المدخلات.
  • استخدام cin لقراءة القيم.
  • تعريف متغيرين إضافيين لتخزين الإجابات.
  • استخدام العامل الثلاثي (ternary operator) لتحديد الأصغر والأكبر.
  • استخدام cout لطباعة النتيجة.
int a, b;
cin >> a >> b; // يمكن قراءة عدة متغيرات في السطر نفسه

int small = (a < b ? a : b);
int large = (a > b ? a : b);

cout << small << '\n' << large;

الإدخال/الإخراج السريع (Fast I/O)

عند استخدام cout، قد لا تُعرَض البيانات مباشرة على الشاشة، إذ تُخزَّن أحيانًا مؤقتًا (في ذاكرة مؤقتة buffer) لتسريع التنفيذ. بشكل افتراضي، كلما استُخدم cin، تُفرَّغ هذه الذاكرة، وهو ما قد يُبطئ الأداء أحيانًا.

بالإضافة إلى ذلك، إذا كانت الذاكرة المؤقتة ممتلئة، فقد تُفرَّغ تلقائيًا أثناء التنفيذ. يمكننا فصل ارتباط cin بـ cout وجعل cout يفرّغ البيانات مرة واحدة فقط في نهاية التنفيذ بإضافة السطرين التاليين:

cin.tie(0); // tie the cin stream to stream (0) i.e no stream
cin.sync_with_stdio(0);
Importantمهم

في المسابقات البرمجية، تُختبَر البرامج تلقائيًا، ولا يُدخل المستخدم القيم يدويًا، بل تُقرأ من ملف. وقد تكون هذه المدخلات كبيرة جدًا. لذا عندما تحتوي المسألة على كمية ضخمة من الإدخال (مئات الآلاف من الأرقام مثلًا)، من المهم وضع السطرين السابقين في بداية الكود لتجنّب بطء التنفيذ.