الدالة printf في لغة البرمجة سي
Ahmed AbuelfatehAhmed Abuelfateh

الدالة printf في لغة البرمجة سي

شرح إستخدامات دالة الطباعة printf في لغة البرمجة سي - C، كيفية طباعة قيم المتغيرات بداخل النصوص، شرح لكيفية تنسيق الطباعة في برنامج سطر الأوامر بإستخدام الدالة printf

الدالة printf() هي الدالة الأساسية المستخدمة لطباعة الجمل النصية في لغة البرمجة سي، والإسم هو إختصار للمصطلح print formatted، حيث تتيح الدالة printf() التحكم في طريقة طباعة الجمل النصية أو ما يعرف بتنسيق الجمل النصيه، وإمكانية طباعة قيم المتغيرات بداخل النص المراد طباعته.

الدالة printf() هي الدالة الأساسية للتحكم في مخرجات البرامج (الطباعة) المكتوبة بلغة البرمجة سي، ولكن نظرا لأن معظم لغات البرمجة الأخرى تم إنشاء مترجماتها سواء كانت Compilers أو Interpreters بإستخدام لغة البرمجة C، فإن هذه الدالة موجودة في معظم لغات البرمجة، على سبيل المثال PHP, GO, JAVA, MATLAB, PERL, R, RUBY والعديد من لغات البرمجة الأخرى.

قبل التعرف على كيفية إستخدام الدالة printf() يجب عليك أولا أن تعرف أن الإستخدام الخاطيء لهذه الدالة قد يؤدي إلى إغلاق البرنامج بشكل مفاجيء أو ما يعرف بتحطم البرنامج Crash، وقد يؤدي أيضا إلى وجود العديد من الثغرات الأمنية البرمجية بداخل كود البرنامج، لذلك وجب التنويه.

تعريف الدالة printf()

الدالة معرفة في المكتبة stdio.h الخاصة بلغة البرمجة سي، أو المكتبة cstdio في لغة البرمجة C++، لذلك يجب كتابة الأمر #include <stdio.h> في بداية الكود قبل إستخدامها.

النموذج المستخدم لتعريف الدالة أو ما يعرف بـ function prototype أو function definition هو كالتالي

int printf(const char * format...);

حيث يمثل المتغير format النص، والثلاثة نقاط ... تتيح إضافة عدد غير محدد مسبقا من المتغيرات أو الـ arguments، حيث يعرف هذا النوع من الدوال بـ Variadic function.

تقوم الدالة بإرجاع return عدد الأحرف التي تم طباعتها في حالة تنفيذ العملية بنجاح أو تقوم بإعادة رقم سالب في حالة الفشل في تنفيذ عملية الطباعة.

عند إستدعاء الدالة يجب أن يتم تمرير متغير نصي واحد على الأقل، فلا يمكن إستدعاؤها بدون تمرير أي متغيرات.

إستخدامات الدالة printf()

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

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

في هذا المثال نفترض أنك تريد طباعة الجملة التالية Result = x، بحيث يتم إستبدال الحرف x بقيمة المتغير، ولكي يتم تنفيذ هذه العملية يجب على الدالة معرفة أن الحرف x هو متغير وليس حرف، لذلك يتم إستخدام رموز خاصة ليتم إستبدالها من قبل الدالة بقيمة المتغير، وهو ما يعرف بـ Placeholder.

وكما تعرف أن كل أنواع البيانات يتم تمثيلها في الحاسوب على هيئة أعداد ثنائية (صفر و واحد)، ولغة البرمجة سي تتعامل مع البيانات على مستوى أقرب إلى لغة الآلة، لذلك يجب أيضا تحديد نوع المتغير الذي نريد طباعة قيمته، لكي تتمكن الدالة من ترجمة المتغير طبقا لنوعه إلى القيمة الصحيحة، لذلك في هذا المثال نريد أن يتم طباعة الجملة Result =، متبوعة بقيمة المتغير العددي x، لذلك سوف نقوم بكتابة الأمر على الشكل التالي

printf("Result = %d"x);

حيث قمنا بكتابة الجملة المراد طباعتها بين علامات تنصيص مزدوجة double quote، وقمنا بحجز مكان بداخل النص Placeholder، ليتم طباعة قيمة المتغير بداخله عن طريق كتابة الحرف % متبوعا بالحرف d، فالرمز % بالنسبة للدالة printf() يعتبر ذو معنى خاص (حيث يتم إستبداله بقيمة المتغير) الذي تم تحديد نوعه عن طريق الحرف d، ثم قمنا بتمرير المتغير x كـ argument ثاني للدالة.

يوجد مجموعة محددة من الحروف التي يمكن إستخدامها مع الرمز % للتحكم في طريقة طباعة قيم المتغيرات، حيث يمثل كل حرف نوع محدد من البيانات، والجدول التالي يوضح الحروف المحددة للإستخدام مع الرمز % ونوع البيانات الخاص بكل حرف

الرمزالإستخدامالصيغة
%يستخدم هذا الرمز ليتم طباعة الرمز المئوي كما هو، حيث أن هذا الرمز يعتبر رمز خاص بالنسبة للدالة، فلا يمكن كتابته كما هو إلا إذا قمت بكتابته مرتين%%
d, iيستخدم الحرف d أو الحرف i، لطباعة الأعداد الصحيحة والتي تتمثل في نوع البيانات int، كلاهما يقومان بطباعة الأعداد الصحيحة في الدالة printf() دون أي إختلاف، ولكن يختلفان في المهمة إذا تم إستخدامهم في الدالة scanf() وهي الدالة التي تستخدم في عملية إدخال البيانات المنسقة، حيث عند إستخدام حرف الـ i مع الدالة scanf() يتم قراءة الرقم الصحيح المدخل بالتمثيل الثماني إذا كان مسبوقا بالرقم 0، أو بالتمثيل السادس عشر Hexadecimal إذا تم إدخال الرقم مسبوقا بـ 0x وهي طريقة كتابة البيانات بالنظام السادس عشر.%d, %i
uيستخدم الحرف u لطباعة الأعداد الصحيحة التي لا تحتوي على إشارة، والتي تتمثل في نوع البيانات unsigned int، فكما نعرف أن الأعداد يتم تمثيلها بإستخدام نظام المتمم الثنائي (Two's Complement)، بما يعني أن الرقم السالب يتم حفظه في الذاكرة على هيئة المتمم الثنائي لنفس الرقم الموجب، وبالتالي يمكننا إستخدام الحرف u، لطباعة الرقم كما تم تمثيله في الذاكرة.%u
cيستخدم الحرف c لطباعة البيانات من النوع char والتي تمثل حرف واحد أو رمز خاص من مجموعة الحروف ASCII.%c
sيستخدم الحرف s لطباعة نص يحتوي على أكثر من حرف، يعرف هذا النوع من البيانات في معظم لغات البرمجة بـ string، ولكن لغة البرمجة سي لا يوجد بها هذا النوع من البيانات، ولكي يتم كتابة نص يحتوي على أكثر من حرف في لغة البرمجة سي يتم إستخدام مصفوفة Array من النوع char على أن يكون آخر حرف في هذا النص هو الرمز \0 أو كما يعرف بـ NULL، وهذا النوع من البيانات يسمى بـ Null Terminated String.%s
f, Fيستخدم الحرف f أو F لطباعة الأعداد الطبيعية و التي تحتوي على أرقام عشرية، ويعرف هذا النوع من البيانات بـ float أو double وهو الأكثر إستخداما، والفرق بين حرف الـ f الصغير والحرف الكبير يتمثل في طباعة الرقم مالانهاية Infinity و الرقم NaN والمعروف بـ Not a Number، حيث الحرف الصغير يقوم بطباعة الكلمات السابقة بحروف صغيرة Small أما الحرف الكبير F فيقوم بطباعة الكلمات بحروف كبيرة Capital.%f, %F
e, Eيستخدم الحرف e أو E لطباعة الأعداد العشرية من النوع float أو double بالطريقة العلمية والمعروفة بـ Scientific Notation، وهي عبارة عن كتابة الأعداد العشرية مرفوعة لأس يمثل عدد الخانات العشرية، وهي الطريقة المتبعة لتمثيل البيانات العشرية والمعروفه بـ IEEE-32 و IEEE-64.%e, %E
g, Gيستخدم الحرف g أو G لطباعة الأعداد العشرية من النوع float أو double، حيث يتم طباعة الأعداد بالطريقة العادية fixed-point إذا كان يمكن كتابة العدد بهذه الطريقة، فإذا كان العدد أكبر من أن يتم طباعته بهذه الطريقة يتم طباعة العدد بإستخدام طريقة الـ scientific-notation، والفرق بين الحرف الصغير والكبير يتمثل في طريقة طباعة رمز الأس في العدد إما بحرف e صغير أو حرف E كبير في حالة ما تم طباعة العدد بالطريقة الثانية.%g, %G
x, Xيستخدم الحرف x أو X لطباعة الأعداد الصحيحة التي لا تحتوي على إشارة، أي من النوع unsigned int، بطريقة التمثيل العددي السادس عشر Hexadecimal، والفرق بين الحرف الصغير والكبير يتمثل في طباعة الرمز 0x السابق للعدد إما بحرف صغير أو كبير.%x, %X
a, Aيستخدم الحرف a أو A لطباعة الأعداد العشرية من النوع float أو double بطريقة تمثيل الأعداد بالنظام السداسي عشر، والفرق بين الحرف الكبير والصغير يتمثل في طباعة الرمز 0x السابق للعدد إما بحرف كبير أو صغير.%a, %A
oيستخدم الحرف o لطباعة الأعداد الصحيحة بدون إشارة من النوع unsigned int بطريقة تمثيل الأعداد بالنظام الثماني Octal.%o
nيستخدم الحرف n لتسجيل عدد الأحرف التي تم طباعتها بنجاح عن طريق حفظها بداخل Pointer يتم تمريره للدالة، ولا يتم طباعة أي نتيجة عن هذه العملية، وتعد هذه العملية من الثغرات الأمنية في الدالة printf() لذلك لا ينصح بإستخدامها في البرامج.%n

أمثلة على إستخدامات الدالة printf()

خلال هذه الأمثلة سوف نكتب الكود الخاص بدالة الطباعة فقط، ولكي تتمكن من تجربة الكود يتوجب عليك كتابة الأوامر في داخل الدالة main() كما تم التوضيح في مقالة الأكواد الأساسية لكتابة برنامج بلغة السي.

في الأمثلة التالية سوف نستخدم الرمز \n في نهاية كل جملة نصية، وهو الرمز الخاص بطباعة سطر جديد.

طباعة رقم بنسبة مئوية

double rate = 79.3;
printf("Rate = %f%%\n"rate); // Rate = 79.3%

في هذا المثال إستخدمنا الرمز %f لطباعة قيمة المتغير rate، والرمز %% لطباعة العلامة المئوية، ونتيجة الطباعة موضحة في التعليق بجانب دالة الطباعة.

طباعة رقم صحيح

int num = -255;
 
printf("INTEGER: num = %d\n"num); // num = -255
printf("UNSIGNED: num = %u\n"num); // num = 4294967041

في هذا المثال إستخدمنا رقم صحيح سالب، لتوضيح كيفية التعامل مع نوع البيانات unsigned int، حيث قمنا بإستخدام الرمز %d لطباعة الرقم كما هو، والخطوة الثانية إستخدمنا الرمز %u لطباعة القيمة المخزنة في الذاكرة على أنها قيمة عددية لا تحتوي على إشارة، فإذا رجعنا إلى النظام الثنائي سوف نجد أن القيمة -255 سوف يتم تسجيلها بطريقة المكمل الثنائي، مما يعني أن العدد الثنائي الذي يمثل القيمة -255 هو 

1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 0000 0001

مع الأخذ في الإعتبار أن نوع البيانات int يتم تخزينه في 32bit، وهو الأمر الشائع في معظم أنظمة التشغيل، فإذا قمنا بتحويل هذه القيمة الثنائية إلى النظام العشري Decimal سوف نجد أن القيمة مساوية للرقم 4294967041، وهو ما تم طباعته.

ومن هذا المثال يتضح أهمية تحديد نوع البيانات في دالة الطباعة printf()، حيث أن الدالة تتعامل مع البيانات على طبيعة تمثيلها في الذاكرة، وهي أحد أهم مميزات لغة البرمجة سي وهو قربها من لغة الآلة.

طباعة حرف أو أكثر

char c = 'A';
char str[] = "Abuelfateh";
 
printf("Character c = %c and inline char = %c\n"c'B');
// Character c = A and inline char = B
 
printf("String str = %s and inline string = %s\n"str"AHMED");
// String str = Abuelfateh and inline string = AHMED

في هذا المثال إستخدمنا الرمز %c لطباعة حرف واحد من النوع char، حيث طبعنا أولا قيمة المتغير c ثم قمنا بتمرير الحرف B للدالة ليتم طباعته بديلا للتكرار الثاني للرمز %c، وسوف تلاحظ أننا قمنا بتمرير الحرف B بين علامة تنصيص مفردة Single-Quote وهو الطريقة المتبعة مع الرموز من النوع char في لغة البرمجة سي.

وفي الدالة الثانية قمنا بطباعة سلسلة من الحروف أو ما يعرف بـ char Array أو string، بإستخدام الرمز %s، وقمنا أيضا بتمرير قيمة نصية ثابته وفي حالة السلسلة يتم كتابة النص بين علامة التنصيص المزدوجة Double-Quote.

تنسيق الطباعة في الدالة printf()

لكي نوضح الفكرة العامة لتنسي الطباعة، نطلب منك تجربة الكود التالي

#include <stdlib.h>
#include <stdio.h>
 
int main() {
 
  for (int i = 1i < 1000001i *= 10)
    printf("%d i value\n"i);
 
  system("pause");
  return 0;
}

عند تجربة الكود السابق سوف تظهر نتيجة الطباعة كما في الشكل التالي

unformatted-text-using-printf

تنسيق العرض width

في حالة ما إذا أردت طباعة مجموعة من الأرقام (أو الحروف) مع إمكانية التحكم في الحيز أو العرض width الذي يتم طباعة المتغير بداخله، أو بمعنى آخر إذا أردت أن يتم طباعة الأرقام أي كان عدد رموزها بالمحاذاة مع باقي الأرقام، بحيث يتم طباعة الجملة i value أيضا في نفس المكان من كل سطر، فكل ما عليك هو إستخدام رمز خاص لتحديد الحد الأدنى الذي يتم حجزة لطباعة المتغير.

وبالتالي سوف نقوم بتعديل دالة الطباعة في المثال السابق لتصبح كالتالي

printf("%*d i value\n"7i);

في هذا المثال قمنا بإضافة علامة النجمة * والمعروفة بـ Asterisk بعد الرمز % وقبل الحرف الخاص بنوع البيانات d، لتصبح %*d، ثم قمنا بتمرير الرقم 7 ليتم إستبدال علامة النجمة به ثم المتغير i.

عند تنفيذ الكود السابق سوف تقوم الدالة بحجز سبعة أماكن لحروف ليتم طباعة قيمة المتغير بهم، وإذا كان عدد أحرف المتغير أكبر من 7، فسوف يتم طباعة الحروف أو الأرقام المكونة لقيمة المتغير كاملة، وإن كان طول الأحرف أقل من 7 فسوف يتم إضافة مسافات space حتى يصبح طول المتغير 7 أحرف على الأقل.

ويمكن كتابة الكود السابق بالطريقة المختصرة (وهي الأكثر إستخداما)، حيث يتم كتابة الرقم الممثل لعرض الحقل مباشرة قبل الحرف d، كالتالي

printf("%7d i value\n"i);

بعد تنفيذ الكود السابق سوف تظهر النتيجة بالشكل التالي

formatted-text-using-printf

وهنا لاحظ أن الأرقام تم طباعتها بالمحاذاة إلى اليمين، وهو الوضع الإفتراضي للطباعة، فإذا ما أردت تغيير ذلك ليتم طباعة الأرقام بالمحاذاة من اليسار إلى اليمين كما في الجزء الثاني من الشكل السابق، نقوم بإستخدام علامة الطرح، الرمز - قبل علامة النجمة، ليصبح الكود printf("%-*d i value\n", 7, i); أو printf("%-7d i value\n", i); وهو رمز خاص من الرموز المسماه بـ الأعلام أو Flags، وهي مجموعة من الرموز الخاصة التي تستخدم للتحكم في تنسيق الطباعة، والجدول التالي يوضح مجموعة الرموز التي يمكن أن يتم إستخدامها كـ أعلام، وشرح لإستخداماتهم.

جدول حقل الأعلام - Flags Field

الرمزالإستخدام
-تستخدم علامة الطرح أو Minus، لتغيير المحاذاة الإفتراضية لتصبح من اليسار إلى اليمين، كما تعرفنا في المثال السابق.
+علامة الجمع أو Plus، تستخدم مع الأرقام الصحيحة أو الكسرية ليتم طباعة الإشارة الموجبة أو السالبة قبل الرقم، بالنسبة للأرقام الموجبة يتم طباعتها كما هي بدون إشارة، ولكن عند إضافة الرمز +، يتم إضافة خانة الإشارة قبل طباعة الرقم، إذا كان الرقم سالب سوف يتم طباعة الإشارة السالبة كما هي.
 علامة المسافة أو Space، تستخدم مع الأرقام الموجبة ليتم طباعة مسافة قبل الرقم، وعادة ما تستخدم لتنسيق طباعة الأرقام حيث تترك خانة قبل الرقم الموجب ليكون الرقم بمحاذاة أي رقم سالب في السطر السابق أو اللاحق.
0الرمز صفر أو Zero، يستخدم مع الرمز الخاص بالتحكم في العرض، حيث يعتبر الوضع الإفتراضي لتنسيق عرض الطباعة هو إضافة مسافات فارغة قبل قيمة المتغير، فإذا كان المتغير عددي وأردت طباعة أصفار على يسار الرقم، يمكنك إستخدام الرمز 0 للتنفيذ هذه المهمة.
#رمز الهاش أو الشباك أو Hash، ويستخدم مع مجموعة من الحروف
الحروف g و G، حيث يقوم بالحفاظ على طباعة الأصفار من اليمين في الأرقام العشرية، والوضع الإفتراضي هو إزالة هذه الأصفار.
الحروف f و F و e و E و g و G، يتم دائما طباعة العلامة العشرية.
الحروف o و x و X، يتم طباعة الرموز 0 و 0x و 0X على التوالي، قبل طباعة قيمة الرقم، فالوضع الإفتراضي لهذه الحروف هو طباعتها كما هي، وجرى العرف على التمييز بين الأنظمة العددية عن طريق كتابة رمز معبر عن النظام العددي قبل الرقم.

عند البحث عن الرموز التي يمكن إستخدامها مع الدالة printf() سوف تجد العديد من الرموز الأخرى، ولكن لن أقوم بذكرها حيث أنها غير رسمية، أي أنها قد تتواجد في بعض المترجمات ولا تتواجد في المترجمات الأخرى، ولذلك سوف نلتزم بالرموز الرسمية، والتي تم النص على وجودها في المعيار الخاص بلغة البرمجة C.

9307

Discussion

  • Anonymous
    Anonymous
    amazing
    • Reply to Anonymous
    • Captcha
    • Notify me of follow up comments via email.

  • Add new Comment
  • Captcha
  • Notify me of follow up comments via email.