القائمة الرئيسية

الصفحات

C - Quick Guide / الدليل السريع

 لغة C هي لغة ذات أغراض عامة عالية المستوى تم تطويرها في الأصل بواسطة Dennis M. Ritchie لتطوير نظام تشغيل UNIX في Bell Labs. تم تنفيذ C لأول مرة على كمبيوتر DEC PDP-11 في عام 1972.

في عام 1978 ، أنتج Brian Kernighan و Dennis Ritchie أول وصف متاح للجمهور لـ C ، والمعروف الآن باسم معيار K&R.

تمت كتابة نظام التشغيل UNIX ، والمترجم C ، وجميع برامج تطبيقات UNIX بشكل أساسي في C. أصبحت C الآن لغة احترافية مستخدمة على نطاق واسع لأسباب مختلفة -

  • سهل التعلم
  • لغة منظمة
  • تنتج برامج فعالة
  • يمكنه التعامل مع الأنشطة منخفضة المستوى
  • يمكن تجميعها على مجموعة متنوعة من منصات الكمبيوتر

حقائق عن C

  • تم اختراع لغة C لكتابة نظام تشغيل يسمى UNIX.

  • C هي خليفة للغة B التي تم تقديمها في أوائل السبعينيات.

  • تم إضفاء الطابع الرسمي على اللغة في عام 1988 من قبل المعهد الوطني الأمريكي للمعايير (ANSI).

  • تمت كتابة نظام التشغيل UNIX بالكامل بلغة C.

  • اليوم C هي لغة برمجة النظام الأكثر استخدامًا وشعبية.

  • تم تنفيذ معظم البرامج الحديثة باستخدام C.

  • تمت كتابة نظام التشغيل Linux OS و RDBMS MySQL الأكثر شيوعًا اليوم بلغة C.

لماذا نستخدم C؟

تم استخدام C في البداية لتطوير النظام ، وخاصة البرامج التي يتكون منها نظام التشغيل. تم اعتماد لغة C كلغة لتطوير النظام لأنها تنتج رمزًا يعمل بسرعة تقارب سرعة الشفرة المكتوبة بلغة التجميع. بعض الأمثلة على استخدام لغة سي قد تكون -

  • أنظمة التشغيل
  • مترجمي اللغة
  • المجمعين
  • محرري النصوص
  • التخزين المؤقت للطباعة
  • برامج تشغيل الشبكة
  • البرامج الحديثة
  • قواعد بيانات
  • مترجمي اللغة
  • خدمات

برامج ج

يمكن أن يختلف برنامج AC من 3 أسطر إلى ملايين السطور ويجب كتابته في ملف نصي واحد أو أكثر بامتداد ".c" ؛ على سبيل المثال ، hello.c . يمكنك استخدام "vi" أو "vim" أو أي محرر نصوص آخر لكتابة برنامج C في ملف.

يفترض هذا البرنامج التعليمي أنك تعرف كيفية تحرير ملف نصي وكيفية كتابة التعليمات البرمجية المصدر داخل ملف برنامج.

c- إعداد البيئة

إعداد البيئة المحلية

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

محرر النص

سيتم استخدام هذا لكتابة البرنامج الخاص بك. تتضمن أمثلة برامج التحرير القليلة Windows Notepad ، وأمر تحرير نظام التشغيل ، و Brief ، و Epsilon ، و EMACS ، و vim أو vi.

يمكن أن يختلف اسم وإصدار برامج تحرير النصوص باختلاف أنظمة التشغيل. على سبيل المثال ، سيتم استخدام Notepad على Windows ، ويمكن استخدام vim أو vi على Windows وكذلك على Linux أو UNIX.

الملفات التي تقوم بإنشائها باستخدام المحرر الخاص بك تسمى الملفات المصدر وهي تحتوي على أكواد البرنامج المصدرية. عادةً ما يتم تسمية الملفات المصدر لبرامج C بالملحق " .c ".

قبل بدء البرمجة ، تأكد من أن لديك محرر نصوص واحد في مكانه وأن لديك خبرة كافية لكتابة برنامج كمبيوتر وحفظه في ملف وتجميعه وتنفيذه في النهاية.

مترجم سي

الكود المصدري المكتوب في ملف المصدر هو المصدر الذي يمكن قراءته من قبل الإنسان لبرنامجك. يجب "تجميعها" إلى لغة الآلة حتى تتمكن وحدة المعالجة المركزية الخاصة بك من تنفيذ البرنامج وفقًا للإرشادات المقدمة.

المترجم يجمع أكواد المصدر في البرامج النهائية القابلة للتنفيذ. المترجم المتاح الأكثر استخدامًا والمجاني هو مترجم GNU C / C ++ ، وإلا يمكنك الحصول على مترجمين إما من HP أو Solaris إذا كان لديك أنظمة التشغيل المعنية.

يوضح القسم التالي كيفية تثبيت برنامج التحويل البرمجي GNU C / C ++ على أنظمة تشغيل مختلفة. نستمر في ذكر C / C ++ معًا لأن مترجم GNU gcc يعمل مع لغات البرمجة C و C ++.

التثبيت على UNIX / Linux

إذا كنت تستخدم Linux أو UNIX ، فتحقق مما إذا كان GCC مثبتًا على نظامك عن طريق إدخال الأمر التالي من سطر الأوامر -

$ gcc -v

إذا كان لديك مترجم GNU مثبتًا على جهازك ، فيجب أن يطبع رسالة على النحو التالي -

Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr .......
Thread model: posix
gcc version 4.1.2 20080704 (Red Hat 4.1.2-46)

إذا لم يتم تثبيت GCC ، فسيتعين عليك تثبيته بنفسك باستخدام الإرشادات التفصيلية المتاحة على https://gcc.gnu.org/install/

تمت كتابة هذا البرنامج التعليمي استنادًا إلى Linux وتم تجميع جميع الأمثلة المقدمة على نكهة Cent OS لنظام Linux.

التثبيت على نظام التشغيل Mac OS

إذا كنت تستخدم نظام التشغيل Mac OS X ، فإن أسهل طريقة للحصول على GCC هي تنزيل بيئة تطوير Xcode من موقع ويب Apple واتباع إرشادات التثبيت البسيطة. بمجرد الانتهاء من إعداد Xcode ، ستتمكن من استخدام مترجم GNU لـ C / C ++.

Xcode متاح حاليًا على developer.apple.com/technologies/tools/ .

التثبيت على الويندوز

لتثبيت GCC على Windows ، تحتاج إلى تثبيت MinGW. لتثبيت MinGW ، انتقل إلى صفحة MinGW الرئيسية ، www.mingw.org ، واتبع الرابط إلى صفحة تنزيل MinGW. قم بتنزيل أحدث إصدار من برنامج التثبيت MinGW ، والذي يجب تسميته MinGW- <version> .exe.

أثناء تثبيت Min GW ، كحد أدنى ، يجب عليك تثبيت gcc-core و gcc-g ++ و binutils و MinGW runtime ، ولكن قد ترغب في تثبيت المزيد.

أضف الدليل الفرعي bin الخاص بتثبيت MinGW إلى متغير بيئة PATH ، بحيث يمكنك تحديد هذه الأدوات في سطر الأوامر بأسمائها البسيطة.

بعد اكتمال التثبيت ، ستتمكن من تشغيل gcc و g ++ و ar و ranlib و dlltool والعديد من أدوات GNU الأخرى من سطر أوامر Windows.

ج- هيكل البرنامج

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

مرحبًا بالعالم مثال

يتكون برنامج AC بشكل أساسي من الأجزاء التالية -

  • أوامر المعالج المسبق
  • المهام
  • المتغيرات
  • أقوال وتعابير
  • تعليقات

دعونا نلقي نظرة على رمز بسيط يطبع الكلمات "Hello World" -


#include <stdio.h>

int main() {
   /* my first program in C */
   printf("Hello, World! \n");
   
   return 0;
}

دعونا نلقي نظرة على أجزاء مختلفة من البرنامج أعلاه -

  • السطر الأول من البرنامج #include <stdio.h> هو أمر ما قبل المعالج ، والذي يخبر مترجم C بتضمين ملف stdio.h قبل الانتقال إلى التحويل البرمجي الفعلي.

  • السطر التالي int main () هو الوظيفة الرئيسية حيث يبدأ تنفيذ البرنامج.

  • السطر التالي / *...*/ سوف يتجاهله المترجم وقد تم وضعه لإضافة تعليقات إضافية في البرنامج. لذلك تسمى هذه السطور التعليقات في البرنامج.

  • السطر التالي printf (...) هو وظيفة أخرى متوفرة في C والتي تؤدي إلى ظهور الرسالة "Hello، World!" ليتم عرضها على الشاشة.

  • السطر التالي يعود 0 ؛ ينهي الدالة main () ويعيد القيمة 0.

تجميع وتنفيذ برنامج سي

دعونا نرى كيفية حفظ الكود المصدري في ملف ، وكيفية تجميعه وتشغيله. فيما يلي الخطوات البسيطة -

  • افتح محرر نصوص وأضف الكود المذكور أعلاه.

  • احفظ الملف باسم hello.c

  • افتح موجه الأوامر وانتقل إلى الدليل حيث قمت بحفظ الملف.

  • اكتب gcc hello.c واضغط على Enter لتجميع التعليمات البرمجية الخاصة بك.

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

  • الآن ، اكتب a.out لتنفيذ برنامجك.

  • سترى الإخراج "Hello World" مطبوعًا على الشاشة.

$ gcc hello.c
$ ./a.out
Hello, World!

تأكد من وجود برنامج التحويل البرمجي gcc في مسارك وأنك تقوم بتشغيله في الدليل الذي يحتوي على الملف المصدر hello.c.

ج - النحو الأساسي

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

الرموز في C

يتكون برنامج AC من العديد من الرموز المميزة والرمز المميز هو إما كلمة رئيسية أو معرف أو ثابت أو سلسلة حرفية أو رمز. على سبيل المثال ، تتكون عبارة C التالية من خمسة رموز مميزة -

printf("Hello, World! \n");

الرموز الفردية هي -

printf
(
   "Hello, World! \n"
)
;

فاصلة منقوطة

في برنامج C ، الفاصلة المنقوطة عبارة عن فاصل بيان. أي أنه يجب إنهاء كل بيان فردي بفاصلة منقوطة. يشير إلى نهاية كيان منطقي واحد.

فيما يلي بيانان مختلفان -

printf("Hello, World! \n");
return 0;

تعليقات

التعليقات مثل مساعدة النص في برنامج سي الخاص بك ويتم تجاهلها من قبل المترجم. تبدأ بـ / * وتنتهي بالأحرف * / كما هو موضح أدناه -

/* my first program in C */

لا يمكن أن يكون لديك تعليقات داخل التعليقات ولا تظهر ضمن سلسلة أو أحرف حرفية.

معرفات

معرف التيار المتردد هو اسم يستخدم لتحديد متغير أو وظيفة أو أي عنصر آخر محدد بواسطة المستخدم. يبدأ المعرف بحرف من A إلى Z أو من a إلى z أو شرطة سفلية "_" متبوعًا بصفر أو أكثر من الأحرف والشرطات السفلية والأرقام (من 0 إلى 9).

لا يسمح C بأحرف الترقيم مثل @ و $ و٪ داخل المعرفات. لغة C لغة برمجة حساسة لحالة الأحرف . وهكذا، القوى العاملة و القوى العاملة هما معرفات مختلفة في C. هنا بعض الأمثلة من معرفات مقبولة -

mohd       zara    abc   move_name  a_123
myname50   _temp   j     a23b9      retVal

الكلمات الدالة

تعرض القائمة التالية الكلمات المحجوزة في C. لا يجوز استخدام هذه الكلمات المحجوزة كثوابت أو متغيرات أو أي أسماء معرفات أخرى.


autoelselongswitch
breakenumregistertypedef
caseexternreturnunion
charfloatshortunsigned
constforsignedvoid
continuegotosizeofvolatile
defaultifstaticwhile
dointstruct_Packed
double

مسافة بيضاء في C.

يُعرف السطر الذي يحتوي على مسافة بيضاء فقط ، ربما مع تعليق ، على أنه سطر فارغ ، ويتجاهله مترجم C تمامًا.

المسافة البيضاء هي المصطلح المستخدم في لغة سي لوصف الفراغات وعلامات التبويب وأحرف السطر الجديد والتعليقات. تفصل المسافة البيضاء جزءًا من العبارة عن الآخر وتمكن المحول البرمجي من تحديد مكان انتهاء أحد العناصر في العبارة ، مثل int ، ويبدأ العنصر التالي. لذلك ، في البيان التالي -

int age;

يجب أن يكون هناك حرف مسافة بيضاء واحد على الأقل (عادة مسافة) بين int والعمر حتى يتمكن المترجم من التمييز بينهما. من ناحية أخرى ، في البيان التالي -

fruit = apples + oranges;   // get the total fruit

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

ج- أنواع البيانات

تشير أنواع البيانات في c إلى نظام شامل يستخدم للإعلان عن المتغيرات أو الوظائف من أنواع مختلفة. يحدد نوع المتغير مقدار المساحة التي يشغلها في التخزين وكيف يتم تفسير نمط البت المخزن.

يمكن تصنيف الأنواع في C على النحو التالي -

الأب رقم.أنواع ووصف
1

أنواع أساسية

إنها أنواع حسابية ويتم تصنيفها أيضًا إلى: (أ) أنواع الأعداد الصحيحة و (ب) أنواع الفاصلة العائمة.

2

الأنواع المعدودة

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

3

اكتب باطل

يشير فراغ محدد النوع إلى عدم توفر أي قيمة.

4

الأنواع المشتقة

وهي تشمل (أ) أنواع المؤشرات ، (ب) أنواع الصفيف ، (ج) أنواع الهياكل ، (د) أنواع الاتحاد و (هـ) أنواع الوظائف.

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

أنواع عدد صحيح

يقدم الجدول التالي تفاصيل أنواع الأعداد الصحيحة القياسية مع أحجام التخزين ونطاقات القيمة -

اكتبحجم التخزينمدى القيمة
char1 byte-128 to 127 or 0 to 255
unsigned char1 byte0 to 255
signed char1 byte-128 to 127
int2 or 4 bytes-32,768 to 32,767 or -2,147,483,648 to 2,147,483,647
unsigned int2 or 4 bytes0 to 65,535 or 0 to 4,294,967,295
short2 bytes-32,768 to 32,767
unsigned short2 bytes0 to 65,535
long8 bytes or (4bytes for 32 bit OS)-9223372036854775808 to 9223372036854775807
unsigned long8 bytes0 to 18446744073709551615

للحصول على الحجم الدقيق لنوع أو متغير على منصة معينة، يمكنك استخدام sizeof المشغل. ينتج عن تعبيرات sizeof (النوع) حجم تخزين الكائن أو الكتابة بالبايت. فيما يلي مثال للحصول على حجم من نوع مختلف على جهاز باستخدام ثابت مختلف محدد في ملف العنوان limits.h -


#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <float.h>

int main(int argc, char** argv) {

    printf("CHAR_BIT    :   %d\n", CHAR_BIT);
    printf("CHAR_MAX    :   %d\n", CHAR_MAX);
    printf("CHAR_MIN    :   %d\n", CHAR_MIN);
    printf("INT_MAX     :   %d\n", INT_MAX);
    printf("INT_MIN     :   %d\n", INT_MIN);
    printf("LONG_MAX    :   %ld\n", (long) LONG_MAX);
    printf("LONG_MIN    :   %ld\n", (long) LONG_MIN);
    printf("SCHAR_MAX   :   %d\n", SCHAR_MAX);
    printf("SCHAR_MIN   :   %d\n", SCHAR_MIN);
    printf("SHRT_MAX    :   %d\n", SHRT_MAX);
    printf("SHRT_MIN    :   %d\n", SHRT_MIN);
    printf("UCHAR_MAX   :   %d\n", UCHAR_MAX);
    printf("UINT_MAX    :   %u\n", (unsigned int) UINT_MAX);
    printf("ULONG_MAX   :   %lu\n", (unsigned long) ULONG_MAX);
    printf("USHRT_MAX   :   %d\n", (unsigned short) USHRT_MAX);

    return 0;
}

عندما تقوم بتجميع وتنفيذ البرنامج أعلاه ، فإنه ينتج النتيجة التالية على Linux -

CHAR_BIT    :   8
CHAR_MAX    :   127
CHAR_MIN    :   -128
INT_MAX     :   2147483647
INT_MIN     :   -2147483648
LONG_MAX    :   9223372036854775807
LONG_MIN    :   -9223372036854775808
SCHAR_MAX   :   127
SCHAR_MIN   :   -128
SHRT_MAX    :   32767
SHRT_MIN    :   -32768
UCHAR_MAX   :   255
UINT_MAX    :   4294967295
ULONG_MAX   :   18446744073709551615
USHRT_MAX   :   65535

أنواع النقطة العائمة

يقدم الجدول التالي تفاصيل أنواع النقطة العائمة القياسية مع أحجام التخزين ونطاقات القيم ودقتها -

اكتبحجم التخزينمدى القيمةدقة
float4 byte1.2E-38 to 3.4E+386 decimal places
double8 byte2.3E-308 to 1.7E+30815 decimal places
long double10 byte3.4E-4932 to 1.1E+493219 decimal places

يحدد ملف الرأس float.h وحدات الماكرو التي تسمح لك باستخدام هذه القيم وتفاصيل أخرى حول التمثيل الثنائي للأرقام الحقيقية في برامجك. المثال التالي يطبع مساحة التخزين التي يشغلها نوع عائم وقيم نطاقه -


#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <float.h>

int main(int argc, char** argv) {

    printf("Storage size for float : %d \n", sizeof(float));
    printf("FLT_MAX     :   %g\n", (float) FLT_MAX);
    printf("FLT_MIN     :   %g\n", (float) FLT_MIN);
    printf("-FLT_MAX    :   %g\n", (float) -FLT_MAX);
    printf("-FLT_MIN    :   %g\n", (float) -FLT_MIN);
    printf("DBL_MAX     :   %g\n", (double) DBL_MAX);
    printf("DBL_MIN     :   %g\n", (double) DBL_MIN);
    printf("-DBL_MAX     :  %g\n", (double) -DBL_MAX);
    printf("Precision value: %d\n", FLT_DIG );

    return 0;
}

عندما تقوم بتجميع وتنفيذ البرنامج أعلاه ، فإنه ينتج النتيجة التالية على Linux -

Storage size for float : 4 
FLT_MAX      :   3.40282e+38
FLT_MIN      :   1.17549e-38
-FLT_MAX     :   -3.40282e+38
-FLT_MIN     :   -1.17549e-38
DBL_MAX      :   1.79769e+308
DBL_MIN      :   2.22507e-308
-DBL_MAX     :  -1.79769e+308
Precision value: 6

نوع الفراغ

يحدد نوع الفراغ عدم توفر أي قيمة. يتم استخدامه في ثلاثة أنواع من المواقف -

الأب رقم.أنواع ووصف
1

ترجع الدالة على أنها باطلة

هناك العديد من الوظائف في لغة C لا تُرجع أي قيمة أو يمكنك القول أنها ترجع باطلة. الوظيفة التي لا تحتوي على قيمة إرجاع لها نوع الإرجاع على أنها فارغة. على سبيل المثال ، خروج باطل (حالة int) ؛

2

الحجج الدالة على أنها باطلة

هناك وظائف مختلفة في لغة C لا تقبل أي متغير. يمكن للدالة التي لا تحتوي على معلمة قبول الفراغ. على سبيل المثال ، int rand (void) ؛

3

مؤشرات للإبطال

يمثل مؤشر type void * عنوان الكائن ، ولكن ليس نوعه. على سبيل المثال ، وظيفة تخصيص الذاكرة باطلة * malloc (size_t size) ؛ إرجاع مؤشر إلى الفراغ والذي يمكن تحويله إلى أي نوع بيانات.

c- المتغيرات

المتغير ليس سوى اسم يُعطى لمنطقة التخزين التي يمكن لبرامجنا معالجتها. كل متغير في C له نوع معين ، والذي يحدد حجم وتصميم ذاكرة المتغير ؛ نطاق القيم التي يمكن تخزينها في تلك الذاكرة ؛ ومجموعة العمليات التي يمكن تطبيقها على المتغير.

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

الأب رقم.النوع والوصف
1

char

نموذجيًا ثماني بتات واحدة (بايت واحد). إنه نوع عدد صحيح.

2

int

الحجم الأكثر طبيعية للعدد الصحيح للآلة.

3

float

قيمة فاصلة عائمة أحادية الدقة.

4

double

قيمة فاصلة عائمة مزدوجة الدقة.

5

void

يمثل غياب النوع.

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

تعريف متغير في c

يخبر تعريف المتغير المترجم عن مكان وكمية التخزين التي سيتم إنشاؤها للمتغير. يحدد تعريف المتغير نوع البيانات ويحتوي على قائمة بمتغير واحد أو أكثر من هذا النوع على النحو التالي -

type variable_list;

هنا، نوع يجب أن يكون نوع C بيانات صالحة بما في ذلك شار، w_char، كثافة، تطفو، مزدوجة، منطقي، أو أي كائن المعرفة من قبل المستخدم. و variable_list قد تتكون من أسماء المعرف واحد أو أكثر مفصولة بفواصل. يتم عرض بعض التصريحات الصالحة هنا -

int    i, j, k;
char   c, ch;
float  f, salary;
double d;

السطر int i ، j ، k ؛ يعلن ويحدد المتغيرات i و j و k ؛ التي توجه المترجم لإنشاء متغيرات تسمى i و j و k من النوع int.

يمكن تهيئة المتغيرات (تعيين قيمة أولية) في إعلانها. يتكون المُهيئ من علامة يساوي متبوعة بتعبير ثابت على النحو التالي -

type variable_name = value;

بعض الأمثلة -

extern int d = 3, f = 5;    // declaration of d and f. 
int d = 3, f = 5;           // definition and initializing d and f. 
byte z = 22;                // definition and initializes z. 
char x = 'x';               // the variable x has the value 'x'.

للتعريف بدون مُهيئ: يتم تهيئة المتغيرات ذات مدة التخزين الثابتة ضمنيًا باستخدام NULL (جميع البايت لها القيمة 0) ؛ القيمة الأولية لجميع المتغيرات الأخرى غير محددة.

إعلان متغير في ج

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

يكون التصريح عن المتغير مفيدًا عندما تستخدم ملفات متعددة وتقوم بتعريف المتغير الخاص بك في أحد الملفات التي ستكون متاحة في وقت ربط البرنامج. ستستخدم الكلمة الأساسية extern للإعلان عن متغير في أي مكان. على الرغم من أنه يمكنك التصريح عن متغير عدة مرات في برنامج C الخاص بك ، إلا أنه يمكن تعريفه مرة واحدة فقط في ملف أو وظيفة أو كتلة من التعليمات البرمجية.

مثال

جرب المثال التالي ، حيث تم الإعلان عن المتغيرات في الأعلى ، ولكن تم تعريفها وتهيئتها داخل الوظيفة الرئيسية -

#include <stdio.h>

// Variable declaration:
extern int a, b;
extern int c;
extern float f;

int main () {

   /* variable definition: */
   int a, b;
   int c;
   float f;
 
   /* actual initialization */
   a = 10;
   b = 20;
  
   c = a + b;
   printf("value of c : %d \n", c);

   f = 70.0/3.0;
   printf("value of f : %f \n", f);
 
   return 0;
}

عندما يتم تجميع التعليمات البرمجية أعلاه وتنفيذها ، فإنها تنتج النتيجة التالية -

value of c : 30
value of f : 23.333334

ينطبق نفس المفهوم على إعلان الوظيفة حيث تقدم اسمًا للوظيفة في وقت إعلانها ويمكن تعريفها الفعلي في أي مكان آخر. على سبيل المثال -

// function declaration
int func();

int main() {

   // function call
   int i = func();
}

// function definition
int func() {
   return 0;
}

Lvalues ​​و Rvalues ​​في C

يوجد نوعان من التعبيرات في لغة سي -

  • lvalue - التعبيرات التي تشير إلى موقع ذاكرة تسمى تعبيرات "lvalue". قد تظهر قيمة lvalue إما في الجانب الأيسر أو الأيمن من المهمة.

  • rvalue - يشير المصطلح rvalue إلى قيمة بيانات مخزنة في بعض العناوين في الذاكرة. rvalue هو تعبير لا يمكن تعيين قيمة له مما يعني أن rvalue قد تظهر على الجانب الأيمن ولكن ليس على الجانب الأيسر من المهمة.

المتغيرات هي قيم lvalues ​​ولذلك قد تظهر على الجانب الأيسر من المهمة. القيم الحرفية الرقمية هي قيم rvalues ​​ولذلك قد لا يتم تعيينها ولا يمكن أن تظهر على الجانب الأيسر. ألق نظرة على العبارات الصحيحة وغير الصالحة التالية -

int g = 20; // valid statement

10 = 20; // invalid statement; would generate compile-time error

c- الثوابت والحرفية

تشير الثوابت إلى القيم الثابتة التي لا يجوز للبرنامج تغييرها أثناء تنفيذه. تسمى هذه القيم الثابتة أيضًا القيم الحرفية .

يمكن أن تكون الثوابت من أي نوع من أنواع البيانات الأساسية مثل ثابت عدد صحيح أو ثابت عائم أو ثابت حرف أو سلسلة حرفية . هناك ثوابت التعداد كذلك.

يتم التعامل مع الثوابت تمامًا مثل المتغيرات العادية باستثناء أنه لا يمكن تعديل قيمها بعد تعريفها.

عدد صحيح حرفي

يمكن أن يكون العدد الصحيح الحرفي ثابتًا عشريًا أو ثمانيًا أو سداسيًا عشريًا. تحدد البادئة الأساس أو الجذر: 0x أو 0X للسداسي عشري ، و 0 للثماني ، ولا شيء للعشري.

يمكن أن يكون للعدد الصحيح الحرفي أيضًا لاحقة تتكون من مزيج من U و L ، من أجل عدم الإشارة والطويل ، على التوالي. يمكن أن تكون اللاحقة كبيرة أو صغيرة ويمكن أن تكون بأي ترتيب.

فيما يلي بعض الأمثلة على القيم الحرفية الصحيحة -

212         /* Legal */
215u        /* Legal */
0xFeeL      /* Legal */
078         /* Illegal: 8 is not an octal digit */
032UU       /* Illegal: cannot repeat a suffix */

فيما يلي أمثلة أخرى لأنواع مختلفة من القيم الحرفية -

85         /* decimal */
0213       /* octal */
0x4b       /* hexadecimal */
30         /* int */
30u        /* unsigned int */
30l        /* long */
30ul       /* unsigned long */

الفاصلة العائمة Literals

تحتوي الفاصلة العائمة على جزء صحيح ونقطة عشرية وجزء كسري وجزء أُس. يمكنك تمثيل القيم الحرفية للفاصلة العائمة إما في شكل عشري أو شكل أسي.

أثناء تمثيل النموذج العشري ، يجب تضمين العلامة العشرية أو الأس أو كليهما ؛ وأثناء تمثيل النموذج الأسي ، يجب تضمين جزء العدد الصحيح أو الجزء الكسري أو كليهما. يتم تقديم الأس الموقع بواسطة e أو E.

فيما يلي بعض الأمثلة على حرفية الفاصلة العائمة -

3.14159       /* Legal */
314159E-5L    /* Legal */
510E          /* Illegal: incomplete exponent */
210f          /* Illegal: no decimal or exponent */
.e55          /* Illegal: missing integer or fraction */

ثوابت الشخصية

يتم وضع الأحرف الحرفية في علامات اقتباس مفردة ، على سبيل المثال ، يمكن تخزين "x" في متغير بسيط من نوع char .

يمكن أن يكون الحرف الحرفي حرفًا عاديًا (على سبيل المثال ، "x") ، أو تسلسل هروب (على سبيل المثال ، "\ t") ، أو حرفًا عامًا (على سبيل المثال ، "\ u02C0").

هناك أحرف معينة في C تمثل معنى خاصًا عندما تسبقها شرطة مائلة للخلف على سبيل المثال ، سطر جديد (\ n) أو علامة تبويب (\ t).

فيما يلي مثال لإظهار بعض أحرف تسلسل الهروب -


#include <stdio.h>

int main() {
   printf("Hello\tWorld\n\n");

   return 0;
}

عندما يتم تجميع التعليمات البرمجية أعلاه وتنفيذها ، فإنها تنتج النتيجة التالية -

Hello World

سلسلة حرفية

يتم وضع القيم الحرفية أو الثوابت في السلسلة بين علامتي اقتباس "". تحتوي السلسلة على أحرف تشبه الأحرف الحرفية: أحرف عادية ، وتسلسلات هروب ، وأحرف عامة.

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

فيما يلي بعض الأمثلة على السلاسل الحرفية. جميع الأشكال الثلاثة هي سلاسل متطابقة.

"hello, dear"

"hello, \

dear"

"hello, " "d" "ear"

تحديد الثوابت

هناك طريقتان بسيطتان في لغة C لتعريف الثوابت -

  • باستخدام #define preprocessor.

  • باستخدام كلمة const .

  • #define Preprocessor

    فيما يلي نموذج لاستخدام #define preprocessor لتحديد ثابت -

    #define identifier value
    

    The following example explains it in detail −

    #include <stdio.h>
    
    #define LENGTH 10   
    #define WIDTH  5
    #define NEWLINE '\n'
    
    int main() {
       int area;  
      
       area = LENGTH * WIDTH;
       printf("value of area : %d", area);
       printf("%c", NEWLINE);
    
       return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    value of area : 50
    

    الكلمة الرئيسية const

    يمكنك استخدام بادئة const للإعلان عن الثوابت بنوع معين على النحو التالي -

    const type variable = value;
    

    يوضح المثال التالي ذلك بالتفصيل -


    #include <stdio.h>
    
    int main() {
       const int  LENGTH = 10;
       const int  WIDTH = 5;
       const char NEWLINE = '\n';
       int area;  
       
       area = LENGTH * WIDTH;
       printf("value of area : %d", area);
       printf("%c", NEWLINE);
    
       return 0;
    }

    عندما يتم تجميع التعليمات البرمجية أعلاه وتنفيذها ، فإنها تنتج النتيجة التالية -

    value of area : 50
    

    لاحظ أنه من الممارسات البرمجية الجيدة تحديد الثوابت في الأحرف الكبيرة.

    c- فئات التخزين

    تحدد فئة التخزين نطاق (الرؤية) وفترة حياة المتغيرات و / أو الوظائف داخل برنامج C. إنها تسبق النوع الذي تعدله. لدينا أربع فئات تخزين مختلفة في برنامج C -

    • تلقاءي
    • تسجيل
    • ثابتة
    • خارجي

    فئة التخزين التلقائي

    في السيارات فئة تخزين هي فئة تخزين افتراضية لجميع المتغيرات المحلية.

    {
       int mount;
       auto int month;
    }

    The example above defines two variables with in the same storage class. 'auto' can only be used within functions, i.e., local variables.

    فئة التخزين التسجيل

    في السجل يستخدم فئة تخزين لتحديد المتغيرات المحلية التي يجب أن يتم تخزينها في السجل بدلا من ذاكرة الوصول العشوائي. هذا يعني أن المتغير له حجم أقصى يساوي حجم التسجيل (عادةً كلمة واحدة) ولا يمكن تطبيق عامل التشغيل "&" عليه (لأنه لا يحتوي على موقع ذاكرة).

    {
       register int  miles;
    }

    يجب استخدام السجل فقط للمتغيرات التي تتطلب وصولاً سريعًا مثل العدادات. وتجدر الإشارة أيضًا إلى أن تعريف "السجل" لا يعني أنه سيتم تخزين المتغير في السجل. هذا يعني أنه قد يتم تخزينه في سجل اعتمادًا على قيود الأجهزة والتنفيذ.

    فئة التخزين الثابت

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

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

    في البرمجة بلغة C ، عندما يتم استخدام static في متغير عام ، فإنه يتسبب في مشاركة نسخة واحدة فقط من هذا العضو من قبل جميع كائنات فئته.


    #include <stdio.h>
     
    /* function declaration */
    void func(void);
     
    static int count = 5; /* global variable */
     
    main() {
    
       while(count--) {
          func();
       }
    	
       return 0;
    }
    
    /* function definition */
    void func( void ) {
    
       static int i = 5; /* local static variable */
       i++;
    
       printf("i is %d and count is %d\n", i, count);
    }

    When the above code is compiled and executed, it produces the following result −

    i is 6 and count is 4
    i is 7 and count is 3
    i is 8 and count is 2
    i is 9 and count is 1
    i is 10 and count is 0
    

    فئة التخزين الخارجية

    يتم استخدام فئة التخزين الخارجي لإعطاء مرجع لمتغير عام يكون مرئيًا لجميع ملفات البرنامج. عند استخدام "extern" ، لا يمكن تهيئة المتغير ، ومع ذلك ، فإنه يشير إلى اسم المتغير في موقع تخزين تم تحديده مسبقًا.


    عندما يكون لديك ملفات متعددة وتحدد متغيرًا عامًا أو وظيفة ، والتي سيتم استخدامها أيضًا في ملفات أخرى ، فسيتم استخدام extern في ملف آخر لتوفير مرجع للمتغير أو الوظيفة المحددة. فقط للفهم ، يتم استخدام extern للإعلان عن متغير شامل أو وظيفة في ملف آخر.


    يتم استخدام المعدّل الخارجي بشكل شائع عندما يكون هناك ملفان أو أكثر يشتركان في نفس المتغيرات أو الوظائف العامة كما هو موضح أدناه.

    First File: main.c

    #include <stdio.h>
     
    int count ;
    extern void write_extern();
     
    main() {
       count = 5;
       write_extern();
    }

    Second File: support.c

    #include <stdio.h>
     
    extern int count;
     
    void write_extern(void) {
       printf("count is %d\n", count);
    }

    هنا ، يتم استخدام extern للإعلان عن العدد في الملف الثاني ، حيث تم تعريفه في الملف الأول main.c. الآن ، قم بتجميع هذين الملفين على النحو التالي -

    $gcc main.c support.c
    

    سوف ينتج البرنامج القابل للتنفيذ a.out. عند تنفيذ هذا البرنامج ، فإنه ينتج النتيجة التالية -

    count is 5
    

    c- المشغلين

    المشغل هو رمز يخبر المترجم بأداء وظائف رياضية أو منطقية محددة. لغة C غنية بالمشغلات المضمنة وتوفر الأنواع التالية من المشغلين -

    • العمليات الحسابية
    • العوامل العلاقية
    • العوامل المنطقية
    • عوامل Bitwise
    • مشغلي التخصيص
    • مشغلي متفرقات

    سننظر ، في هذا الفصل ، في طريقة عمل كل مشغل.

    العمليات الحسابية

    يوضح الجدول التالي جميع المعاملات الحسابية التي تدعمها لغة سي. افترض أن المتغير A يحمل 10 والمتغير B يحمل 20 ثم -

    عرض الأمثلة

    المشغل أو العاملوصفمثال
    +يضيف معاملين.أ + ب = 30
    يطرح المعامل الثاني من الأول.أ - ب = -10
    *يضاعف كلا المعاملين.أ * ب = 200
    /يقسم البسط على البسط.B / A = 2
    ٪عامل المعامل والباقي بعد قسمة عدد صحيح.ب٪ أ = 0
    ++عامل الزيادة يزيد قيمة العدد الصحيح بمقدار واحد.أ ++ = 11
    -Decrement operator decreases the integer value by one.أ - = 9

    العوامل العلاقية

    يوضح الجدول التالي جميع العوامل العلائقية التي يدعمها C. افترض أن المتغير A يحمل 10 والمتغير B يحمل 20 ثم -

    عرض الأمثلة

    المشغل أو العاملDescriptionمثال
    ==للتحقق مما إذا كانت قيم المعاملين متساوية أم لا. إذا كانت الإجابة بنعم ، يصبح الشرط صحيحًا.(أ == ب) ليس صحيحًا.
    ! =للتحقق مما إذا كانت قيم المعاملين متساوية أم لا. إذا كانت القيم غير متساوية ، يصبح الشرط صحيحًا.(أ! = ب) صحيح.
    >للتحقق مما إذا كانت قيمة المعامل الأيسر أكبر من قيمة المعامل الأيمن. إذا كانت الإجابة بنعم ، يصبح الشرط صحيحًا.(A> B) ليس صحيحًا.
    <للتحقق مما إذا كانت قيمة المعامل الأيسر أقل من قيمة المعامل الأيمن. إذا كانت الإجابة بنعم ، يصبح الشرط صحيحًا.(A <B) هو الصحيح.
    > =للتحقق مما إذا كانت قيمة المعامل الأيسر أكبر من قيمة المعامل الأيمن أو مساوية لها. إذا كانت الإجابة بنعم ، يصبح الشرط صحيحًا.(أ> = ب) ليس صحيحًا.
    <=للتحقق مما إذا كانت قيمة المعامل الأيسر أقل من قيمة المعامل الأيمن أو مساوية لها. إذا كانت الإجابة بنعم ، يصبح الشرط صحيحًا.(أ <= ب) صحيح.

    العوامل المنطقية

    يوضح الجدول التالي جميع العوامل المنطقية التي تدعمها لغة C. افترض أن المتغير A يحمل 1 والمتغير B يحمل 0 ، ثم -

    عرض الأمثلة

    المشغل أو العاملوصفمثال
    &&يسمى عامل التشغيل المنطقي AND. إذا كان كلا المعاملين غير صفري ، يصبح الشرط صحيحًا.(A && B) خطأ.
    ||يسمى عامل التشغيل المنطقي. إذا كان أي من المعاملين غير صفري ، يصبح الشرط صحيحًا.(A || B) صحيح.
    !يسمى المنطقي ليس عامل. يتم استخدامه لعكس الحالة المنطقية لمعامله. إذا كان الشرط صحيحًا ، فإن عامل التشغيل المنطقي NOT سيجعله خطأ.(A && B) صحيح.

    عوامل Bitwise

    Bitwise operator works on bits and perform bit-by-bit operation. The truth tables for &, |, and ^ is as follows −

    pqp & qp | qp ^ q
    00000
    01011
    11110
    10011

    افترض أ = 60 و ب = 13 في تنسيق ثنائي ، سيكونان على النحو التالي -

    أ = 0011 1100

    B = 0000 1101

    -----------------

    أ & ب = 0000 1100

    أ | ب = 0011 1101

    أ ^ ب = 0011 0001

    ~ أ = 1100 0011

    يسرد الجدول التالي عوامل تشغيل البت التي يدعمها C. افترض أن المتغير "A" يحمل 60 ومتغير "B" يحمل 13 ، ثم -

    عرض الأمثلة

    المشغل أو العاملDescriptionمثال
    &ينسخ العامل الثنائي AND قليلاً إلى النتيجة إذا كانت موجودة في كلا المعاملين.(أ ، ب) = 12 ، أي 0000 1100
    |يقوم عامل التشغيل الثنائي بنسخ بعض الشيء إذا كان موجودًا في أي من المعاملين.(أ | ب) = 61 ، أي 0011 1101
    ^يقوم عامل تشغيل XOR الثنائي بنسخ البت إذا تم تعيينه في معامل واحد ولكن ليس في كليهما.(أ ^ ب) = 49 ، أي 0011 0001
    ~المشغل التكميلي لـ Binary One أحادي وله تأثير "تقليب" البتات.(~ أ) = ~ (60) ، أي. -0111101
    <<Binary Left Shift Operator. The left operands value is moved left by the number of bits specified by the right operand.أ << 2 = 240 أي 1111 0000
    >>مشغل ثنائي التحول الأيمن. يتم نقل قيمة المعاملات اليسرى إلى اليمين بعدد البتات المحدد بواسطة المعامل الأيمن.أ >> 2 = 15 أي 0000 1111

    مشغلي التخصيص

    يسرد الجدول التالي عوامل التشغيل التي تدعمها لغة C -

    عرض الأمثلة

    Operatorوصفمثال
    =عامل التعيين البسيط. يعيّن قيمًا من معاملات الجانب الأيمن إلى معامل الجانب الأيسرC = A + B ستخصص قيمة A + B إلى C.
    + =إضافة عامل التعيين AND. يقوم بإضافة المعامل الأيمن إلى المعامل الأيسر وتعيين النتيجة إلى المعامل الأيسر.C + = A تعادل C = C + A
    -=اطرح عامل التعيين. يقوم بطرح المعامل الأيمن من المعامل الأيسر وتعيين النتيجة إلى المعامل الأيسر.C - = A تعادل C = C - A
    * =اضرب و عامل التعيين. يقوم بضرب المعامل الأيمن بالمعامل الأيسر وتعيين النتيجة إلى المعامل الأيسر.C * = A تعادل C = C * A
    / =قسمة عامل التعيين AND. يقسم المعامل الأيسر بالمعامل الأيمن ويعين النتيجة إلى المعامل الأيسر.C / = A تعادل C = C / A
    %=عامل التخصيص والمعامل. يأخذ المعامل باستخدام معاملين ويسند النتيجة إلى المعامل الأيسر.C٪ = A يكافئ C = C٪ A
    << =التحول الأيسر وعامل التعيين.C << = 2 هي نفسها C = C << 2
    >> =Right shift AND assignment operator.C >> = 2 هو نفسه C = C >> 2
    & =Bitwise AND عامل التعيين.C & = 2 هي نفسها C = C & 2
    ^ =المعامل OR الحصري على مستوى البت ومعامل التعيين.C ^= 2 is same as C = C ^ 2
    | =على مستوى البت شامل OR ومعامل التخصيص.C | = 2 هو نفسه C = C | 2

    عوامل متنوعة Oper sizeof & ternary

    إلى جانب المشغلين الذين تمت مناقشتهم أعلاه ، هناك عدد قليل من المشغلين المهمين الآخرين بما في ذلك sizeof و ؟ : بدعم من لغة سي.

    عرض الأمثلة

    Operatorوصفمثال
    sizeof()إرجاع حجم متغير.sizeof (أ) ، حيث يكون a عددًا صحيحًا ، سيعيد 4.
    &إرجاع عنوان المتغير.&أ؛ إرجاع العنوان الفعلي للمتغير.
    *مؤشر إلى متغير.*أ؛
    ؟ :التعبير الشرطي.إذا كانت الحالة صحيحة؟ ثم قيمة X: وإلا قيمة Y

    Operators Precedence in C

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

    على سبيل المثال ، x = 7 + 3 * 2 ؛ هنا ، تم تعيين x 13 ، وليس 20 لأن عامل التشغيل * له أسبقية أعلى من + ، لذلك يتم ضربه أولاً بـ 3 * 2 ثم يتم جمعه في 7.

    هنا ، تظهر العوامل ذات الأولوية الأعلى أعلى الجدول ، بينما تظهر العوامل الأقل أولوية في الجزء السفلي. ضمن التعبير ، سيتم تقييم عوامل الأولوية الأعلى أولاً.

    عرض الأمثلة

    فئةالمشغل أو العاملالترابطية
    بوستفيكس() [] -> . ++ - -من اليسار إلى اليمين
    أحادي+ -! ~ ++ - - (النوع) * & sizeofمن اليمين الى اليسار
    المضاعفة* /٪من اليسار إلى اليمين
    مادة مضافة+ -Left to right
    يحول<< >>من اليسار إلى اليمين
    العلائقية<<=>> =من اليسار إلى اليمين
    المساواة== !=من اليسار إلى اليمين
    أحادي المعامل AND&من اليسار إلى اليمين
    Bitwise XOR^من اليسار إلى اليمين
    أحادي المعامل OR|Left to right
    المنطقية AND&&من اليسار إلى اليمين
    منطقي أو||من اليسار إلى اليمين
    الشرط؟:من اليمين الى اليسار
    Assignment= + = - = * = / =٪ = >> = << = & = ^ = | =من اليمين الى اليسار
    فاصلةومن اليسار إلى اليمين

    c- اتخاذ القرار

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

  • العرض أدناه هو الشكل العام لهيكل اتخاذ القرار النموذجي الموجود في معظم لغات البرمجة -


    C programming language assumes any non-zero and non-null values as true, and if it is either zero or null, then it is assumed as false value.

    توفر لغة البرمجة C الأنواع التالية من بيانات اتخاذ القرار.

    الأب رقم.البيان والوصف
    1if statement

    و بيان إذا يتكون من تعبير منطقي تليها بيانات واحدة أو أكثر.

    2if...else statement

    و بيان إذا يمكن أن تتبعها اختياري بيان آخر ، الذي ينفذ عند تعبير منطقي غير صحيح.

    3متداخلة عبارات if

    يمكنك استخدام واحد if or else if statement داخل آخر if or else if statement (s).

    4بيان التبديل

    التبديل يسمح بيان متغير لفحصها من أجل المساواة ضد قائمة القيم.

    5عبارات التبديل المتداخلة

    يمكنك استخدام عبارة تبديل واحدة داخل عبارة (عبارات) تبديل أخرى .

    The ? : Operator

    لقد قمنا بتغطية المشغل الشرطي؟ : في الفصل السابق والتي يمكن استخدامها لتحل محل عبارات if ... else . لها الشكل العام التالي -

    Exp1 ? Exp2 : Exp3;
    

    حيث تمثل Exp1 و Exp2 و Exp3 تعبيرات. لاحظ استخدام القولون ووضعه.

    The value of a ? expression is determined like this −

    • يتم تقييم Exp1. إذا كان هذا صحيحًا ، فسيتم تقييم Exp2 وتصبح قيمة الكل؟ التعبير.

    • If Exp1 is false, then Exp3 is evaluated and its value becomes the value of the expression.

    c- الحلقات

    قد تواجه مواقف ، عندما يلزم تنفيذ كتلة من التعليمات البرمجية عدة مرات. بشكل عام ، يتم تنفيذ التعليمات بالتسلسل: يتم تنفيذ العبارة الأولى في الوظيفة أولاً ، متبوعة بالثانية ، وهكذا.

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

    تسمح لنا تعليمة loop بتنفيذ عبارة أو مجموعة من العبارات عدة مرات. فيما يلي الشكل العام لبيان الحلقة في معظم لغات البرمجة -



    توفر لغة البرمجة C الأنواع التالية من الحلقات للتعامل مع متطلبات التكرار.

    الأب رقم.نوع الحلقة والوصف
    1while loop

    يكرر عبارة أو مجموعة من العبارات عندما يكون شرط معين صحيحًا. يختبر الحالة قبل تنفيذ جسم الحلقة.

    2لحلقة

    ينفذ سلسلة من العبارات عدة مرات ويختصر الكود الذي يدير متغير الحلقة.

    3افعل ... أثناء التكرار

    It is more like a while statement, except that it tests the condition at the end of the loop body.

    4حلقات متداخلة

    يمكنك استخدام حلقة واحدة أو أكثر داخل أي حلقة أخرى while، for، or do .. while loop.

    بيانات التحكم في الحلقة

    تغير عبارات التحكم في الحلقة التنفيذ من تسلسله الطبيعي. عندما يترك التنفيذ نطاقًا ، يتم إتلاف جميع الكائنات التلقائية التي تم إنشاؤها في هذا النطاق.

    يدعم C عبارات التحكم التالية.

    الأب رقم.بيان التحكم والوصف
    1بيان كسر

    ينهي الحلقة أو عبارة التبديل وينقل التنفيذ إلى العبارة التي تلي الحلقة أو التبديل مباشرةً.

    2تواصل البيان

    يتسبب في أن تتخطى الحلقة الجزء المتبقي من جسدها وتعيد اختبار حالتها على الفور قبل التكرار.

    3goto statement

    ينقل التحكم إلى البيان المصنف.

    الحلقة اللانهائية

    تصبح الحلقة حلقة لا نهائية إذا لم يصبح الشرط خاطئًا أبدًا. تستخدم حلقة for بشكل تقليدي لهذا الغرض. نظرًا لعدم الحاجة إلى أي من التعبيرات الثلاثة التي تشكل حلقة 'for' ، يمكنك إنشاء حلقة لا نهاية لها بترك التعبير الشرطي فارغًا.

    #include <stdio.h>
     
    int main () {
    
       for( ; ; ) {
          printf("This loop will run forever.\n");
       }
    
       return 0;
    }

    When the conditional expression is absent, it is assumed to be true. You may have an initialization and increment expression, but C programmers more commonly use the for(;;) construct to signify an infinite loop.

    NOTE − You can terminate an infinite loop by pressing Ctrl + C keys.

    C - Functions

    الوظيفة هي مجموعة من العبارات التي تؤدي معًا مهمة. يحتوي كل برنامج C على وظيفة واحدة على الأقل ، وهي main () ، ويمكن لجميع البرامج البسيطة تحديد وظائف إضافية.

    You can divide up your code into separate functions. How you divide up your code among different functions is up to you, but logically the division is such that each function performs a specific task.

    A function declaration tells the compiler about a function's name, return type, and parameters. A function definition provides the actual body of the function.

    توفر مكتبة C القياسية العديد من الوظائف المضمنة التي يمكن لبرنامجك الاتصال بها. على سبيل المثال ، strcat () لربط سلسلتين ، memcpy () لنسخ موقع ذاكرة إلى موقع آخر ، والعديد من الوظائف الأخرى.

    يمكن أيضًا الإشارة إلى الوظيفة على أنها طريقة أو إجراء فرعي أو إجراء ، إلخ.

    تحديد الوظيفة

    الشكل العام لتعريف الوظيفة في لغة البرمجة C هو كما يلي -

    return_type function_name( parameter list ) {
       body of the function
    }

    A function definition in C programming consists of a function header and a function body. Here are all the parts of a function −

    • نوع الإرجاع - قد ترجع الدالة قيمة. نوع return هو نوع البيانات للقيمة التي تُرجعها الدالة. تقوم بعض الوظائف بتنفيذ العمليات المطلوبة دون إرجاع قيمة. في هذه الحالة ، فإن return_type هي الكلمة الأساسية void .

    • اسم وظيفة − This is the actual name of the function. The function name and the parameter list together constitute the function signature.

    • المعلمات - تشبه المعلمة عنصرًا نائبًا. عندما يتم استدعاء دالة ، فإنك تقوم بتمرير قيمة إلى المعلمة. يشار إلى هذه القيمة على أنها معلمة أو وسيطة فعلية. تشير قائمة المعلمات إلى نوع معلمات الوظيفة وترتيبها ورقمها. المعلمات اختيارية ؛ بمعنى ، قد لا تحتوي الوظيفة على معلمات.

    • جسم الوظيفة - يحتوي جسم الوظيفة على مجموعة من العبارات التي تحدد وظيفة الوظيفة.

    مثال

    الموضح أدناه هو الكود المصدري لوظيفة تسمى max () . تأخذ هذه الوظيفة معلمتين num1 و num2 وتُرجع القيمة القصوى بينهما -

    /* function returning the max between two numbers */
    int max(int num1, int num2) {
    
       /* local variable declaration */
       int result;
     
       if (num1 > num2)
          result = num1;
       else
          result = num2;
     
       return result; 
    }

    Function Declarations

    A function declaration tells the compiler about a function name and how to call the function. The actual body of the function can be defined separately.

    A function declaration has the following parts −

    return_type function_name( parameter list );
    

    For the above defined function max(), the function declaration is as follows −

    int max(int num1, int num2);
    

    أسماء المعامِلات ليست مهمة في إعلان الوظيفة فقط نوعها مطلوب ، لذلك ما يلي هو أيضًا إعلان صالح -

    int max(int, int);
    

    إعلان الوظيفة مطلوب عند تحديد دالة في ملف مصدر واحد واستدعاء هذه الوظيفة في ملف آخر. في مثل هذه الحالة ، يجب أن تعلن عن الوظيفة في أعلى الملف التي تستدعي الوظيفة.

    استدعاء وظيفة

    While creating a C function, you give a definition of what the function has to do. To use a function, you will have to call that function to perform the defined task.

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

    لاستدعاء دالة ، ما عليك سوى تمرير المعلمات المطلوبة مع اسم الوظيفة ، وإذا كانت الدالة ترجع قيمة ، فيمكنك تخزين القيمة التي تم إرجاعها. على سبيل المثال -


    #include <stdio.h>
     
    /* function declaration */
    int max(int num1, int num2);
     
    int main () {
    
       /* local variable definition */
       int a = 100;
       int b = 200;
       int ret;
     
       /* calling a function to get max value */
       ret = max(a, b);
     
       printf( "Max value is : %d\n", ret );
     
       return 0;
    }
     
    /* function returning the max between two numbers */
    int max(int num1, int num2) {
    
       /* local variable declaration */
       int result;
     
       if (num1 > num2)
          result = num1;
       else
          result = num2;
     
       return result; 
    }

    We have kept max() along with main() and compiled the source code. While running the final executable, it would produce the following result −

    Max value is : 200 

    وسيطات دالة

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


    المعلمات الرسمية تتصرف مثل المتغيرات المحلية الأخرى داخل الدالة ويتم إنشاؤها عند إدخال في الدالة و إتلاف عند الخروج.


    أثناء استدعاء دالة، هناك طريقتان يمكن تمرير الوسائط إلى function −

    Sr.No.Call Type & Description
    1Call by value

    تقوم هذه الطريقة بنسخ القيمة الفعلية لوسيطة إلى المعلمة الرسمية للدالة. في هذه الحالة ، لا تؤثر التغييرات التي تم إجراؤها على المعلمة داخل الدالة على الوسيطة.

    2اتصل بالإشارة

    This method copies the address of an argument into the formal parameter. Inside the function, the address is used to access the actual argument used in the call. This means that changes made to the parameter affect the argument.

    بشكل افتراضي ، يستخدم C استدعاء حسب القيمة لتمرير الوسائط. بشكل عام ، هذا يعني أن الكود داخل دالة لا يمكنه تغيير الوسائط المستخدمة لاستدعاء الوظيفة.

    ج- قواعد النطاق

    النطاق في أي برمجة هو منطقة من البرنامج حيث يمكن أن يكون للمتغير المحدد وجوده ولا يمكن الوصول إليه بعد ذلك المتغير. هناك ثلاثة أماكن حيث يمكن التصريح عن المتغيرات بلغة البرمجة C -

    • داخل دالة أو كتلة تسمى المتغيرات المحلية .

    • خارج جميع الوظائف وهو ما يسمى المتغيرات العالمية .

    • في تعريف معلمات الوظيفة التي تسمى المعلمات الرسمية .

    دعونا نفهم ما هو محلي and global variables, and formal parameters.

    المتغيرات المحلية

    المتغيرات المعلنة داخل دالة أو كتلة تسمى المتغيرات المحلية. يمكن استخدامها فقط من خلال العبارات الموجودة داخل تلك الوظيفة أو كتلة التعليمات البرمجية. لا تعرف المتغيرات المحلية أنها تعمل خارج نطاقها. يوضح المثال التالي كيفية استخدام المتغيرات المحلية. هنا جميع المتغيرات a و b و c محلية إلى دالة main ().


    #include <stdio.h>
     
    int main () {
    
      /* local variable declaration */
      int a, b;
      int c;
     
      /* actual initialization */
      a = 10;
      b = 20;
      c = a + b;
     
      printf ("value of a = %d, b = %d and c = %d\n", a, b, c);
     
      return 0;
    }

    المتغيرات العالمية

    يتم تعريف المتغيرات العمومية خارج دالة، عادةً أعلى البرنامج. المتغيرات العمومية عقد قيمها طوال عمر البرنامج الخاص بك ويمكن الوصول إليها داخل أي من الوظائف المحددة للبرنامج.


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


    #include <stdio.h>
     
    /* global variable declaration */
    int g;
     
    int main () {
    
      /* local variable declaration */
      int a, b;
     
      /* actual initialization */
      a = 10;
      b = 20;
      g = a + b;
     
      printf ("value of a = %d, b = %d and g = %d\n", a, b, g);
     
      return 0;
    }

    A program can have same name for local and global variables but the value of local variable inside a function will take preference. Here is an example −


    #include <stdio.h>
     
    /* global variable declaration */
    int g = 20;
     
    int main () {
    
      /* local variable declaration */
      int g = 10;
     
      printf ("value of g = %d\n",  g);
     
      return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    value of g = 10
    

    Formal Parameters

    Formal parameters, are treated as local variables with-in a function and they take precedence over global variables. Following is an example −


    #include <stdio.h>
     
    /* global variable declaration */
    int a = 20;
     
    int main () {
    
      /* local variable declaration in main function */
      int a = 10;
      int b = 20;
      int c = 0;
    
      printf ("value of a in main() = %d\n",  a);
      c = sum( a, b);
      printf ("value of c in main() = %d\n",  c);
    
      return 0;
    }
    
    /* function to add two integers */
    int sum(int a, int b) {
    
       printf ("value of a in sum() = %d\n",  a);
       printf ("value of b in sum() = %d\n",  b);
    
       return a + b;
    }

    When the above code is compiled and executed, it produces the following result −

    value of a in main() = 10
    value of a in sum() = 10
    value of b in sum() = 20
    value of c in main() = 30
    

    Initializing Local and Global Variables

    When a local variable is defined, it is not initialized by the system, you must initialize it yourself. Global variables are initialized automatically by the system when you define them as follows −

    Data TypeInitial Default Value
    int0
    char'0'
    يطفو0
    مزدوج0
    المؤشرلا شيء

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

    C - Arrays

    المصفوفات نوع من بنية البيانات التي يمكنها تخزين مجموعة متسلسلة ذات حجم ثابت من العناصر من نفس النوع. تُستخدم المصفوفة لتخزين مجموعة من البيانات ، ولكن غالبًا ما يكون من المفيد التفكير في المصفوفة كمجموعة من المتغيرات من نفس النوع.

    بدلاً من التصريح عن متغيرات فردية ، مثل number0 و number1 و ... و number99 ، فإنك تعلن عن متغير مصفوفة واحد مثل الأرقام وتستخدم الأرقام [0] والأرقام [1] و ... ، والأرقام [99] لتمثيلها المتغيرات الفردية. يتم الوصول إلى عنصر معين في المصفوفة بواسطة فهرس.

    تتكون جميع المصفوفات من مواقع ذاكرة متجاورة. يتوافق العنوان الأدنى مع العنصر الأول والعنوان الأعلى للعنصر الأخير.

    المصفوفات في لغة C.

    Declaring Arrays

    للإعلان عن مصفوفة في لغة C ، يحدد المبرمج نوع العناصر وعدد العناصر التي تتطلبها المصفوفة على النحو التالي -

    type arrayName [ arraySize ];
    

    هذا يسمى مصفوفة أحادية البعد . و arraySize يجب أن يكون ثابت أكبر عدد صحيح من الصفر و نوع يمكن أن يكون أي نوع C بيانات صالحة. على سبيل المثال ، للإعلان عن مصفوفة من 10 عناصر تسمى Balance of type double ، استخدم هذه العبارة -

    double balance[10];
    

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

    تهيئة المصفوفات

    يمكنك تهيئة مصفوفة في C إما واحدًا تلو الآخر أو باستخدام جملة واحدة على النحو التالي -

    double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};
    

    لا يمكن أن يكون عدد القيم بين الأقواس الكبيرة {} أكبر من عدد العناصر التي نعلن عنها للمصفوفة الواقعة بين قوسين مربعين [].

    إذا حذفت حجم المصفوفة ، فسيتم إنشاء مصفوفة كبيرة بما يكفي لاستيعاب التهيئة. لذلك ، إذا كتبت -

    double balance[] = {1000.0, 2.0, 3.4, 7.0, 50.0};
    

    ستقوم بإنشاء نفس المصفوفة تمامًا كما فعلت في المثال السابق. فيما يلي مثال لتعيين عنصر واحد من المصفوفة -

    balance[4] = 50.0;
    

    The above statement assigns the 5th element in the array with a value of 50.0. All arrays have 0 as the index of their first element which is also called the base index and the last index of an array will be total size of the array minus 1. Shown below is the pictorial representation of the array we discussed above −

    عرض صفيف

    الوصول إلى عناصر المصفوفة

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

    double salary = balance[9];
    

    فإن العبارة أعلاه تأخذ 10 عشر عنصرا من مجموعة وتعيين القيمة إلى متغير الراتب. يوضح المثال التالي كيفية استخدام جميع المفاهيم الثلاثة المذكورة أعلاه. التصريح والتخصيص والوصول إلى المصفوفات -


    #include <stdio.h>
     
    int main () {
    
       int n[ 10 ]; /* n is an array of 10 integers */
       int i,j;
     
       /* initialize elements of array n to 0 */         
       for ( i = 0; i < 10; i++ ) {
          n[ i ] = i + 100; /* set element at location i to i + 100 */
       }
       
       /* output each array element's value */
       for (j = 0; j < 10; j++ ) {
          printf("Element[%d] = %d\n", j, n[j] );
       }
     
       return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    Element[0] = 100
    Element[1] = 101
    Element[2] = 102
    Element[3] = 103
    Element[4] = 104
    Element[5] = 105
    Element[6] = 106
    Element[7] = 107
    Element[8] = 108
    Element[9] = 109
    

    Arrays in Detail

    Arrays are important to C and should need a lot more attention. The following important concepts related to array should be clear to a C programmer −

    Sr.No.Concept & Description
    1Multi-dimensional arrays

    يدعم C المصفوفات متعددة الأبعاد. أبسط شكل من أشكال المصفوفة متعددة الأبعاد هو المصفوفة ثنائية الأبعاد.

    2Passing arrays to functions

    يمكنك تمرير مؤشر إلى الدالة إلى مصفوفة عن طريق تحديد اسم المصفوفة بدون فهرس.

    3مجموعة العودة من وظيفة

    يسمح C للدالة بإرجاع مصفوفة.

    4مؤشر إلى مصفوفة

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

    ج - المؤشرات

    المؤشرات في لغة C سهلة وممتعة للتعلم. يتم تنفيذ بعض مهام برمجة لغة سي بسهولة أكبر باستخدام المؤشرات ، بينما لا يمكن تنفيذ مهام أخرى ، مثل تخصيص الذاكرة الديناميكي ، بدون استخدام المؤشرات. لذلك يصبح من الضروري تعلم المؤشرات لتصبح مبرمج سي مثالي. لنبدأ في تعلمهم بخطوات بسيطة وسهلة.

    كما تعلم ، كل متغير هو موقع ذاكرة وكل موقع ذاكرة له عنوانه المحدد والذي يمكن الوصول إليه باستخدام عامل علامة العطف (&) ، والذي يشير إلى عنوان في الذاكرة. ضع في اعتبارك المثال التالي ، الذي يطبع عنوان المتغيرات المحددة -


    #include <stdio.h>
    
    int main () {
    
       int  var1;
       char var2[10];
    
       printf("Address of var1 variable: %x\n", &var1  );
       printf("Address of var2 variable: %x\n", &var2  );
    
       return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    Address of var1 variable: bff5a400
    Address of var2 variable: bff5a3f6
    

    What are Pointers?

    و المؤشر هو متغير قيمته هو عنوان متغير آخر، أي عنوان المباشر من موقع الذاكرة. مثل أي متغير أو ثابت ، يجب أن تعلن عن مؤشر قبل استخدامه لتخزين أي عنوان متغير. الشكل العام لإعلان متغير المؤشر هو -

    type *var-name;
    

    Here, type is the pointer's base type; it must be a valid C data type and var-name is the name of the pointer variable. The asterisk * used to declare a pointer is the same asterisk used for multiplication. However, in this statement the asterisk is being used to designate a variable as a pointer. Take a look at some of the valid pointer declarations −

    int    *ip;    /* pointer to an integer */
    double *dp;    /* pointer to a double */
    float  *fp;    /* pointer to a float */
    char   *ch     /* pointer to a character */
    

    نوع البيانات الفعلي لقيمة جميع المؤشرات ، سواء كان عددًا صحيحًا أو عددًا عائمًا أو حرفًا أو غير ذلك ، هو نفسه ، وهو رقم سداسي عشري طويل يمثل عنوان ذاكرة. الاختلاف الوحيد بين مؤشرات أنواع البيانات المختلفة هو نوع بيانات المتغير أو الثابت الذي يشير إليه المؤشر.

    كيف تستخدم المؤشرات؟

    هناك عدد قليل من العمليات المهمة ، والتي سنقوم بها بمساعدة المؤشرات بشكل متكرر. (أ) نحدد متغير المؤشر ، (ب) نحدد عنوان المتغير للمؤشر و (ج) أخيرًا نصل إلى القيمة على العنوان المتاح في متغير المؤشر. يتم ذلك باستخدام عامل التشغيل الأحادي * الذي يُرجع قيمة المتغير الموجود في العنوان المحدد بواسطة المعامل الخاص به. المثال التالي يستخدم هذه العمليات -


    #include <stdio.h>
    
    int main () {
    
       int  var = 20;   /* actual variable declaration */
       int  *ip;        /* pointer variable declaration */
    
       ip = &var;  /* store address of var in pointer variable*/
    
       printf("Address of var variable: %x\n", &var  );
    
       /* address stored in pointer variable */
       printf("Address stored in ip variable: %x\n", ip );
    
       /* access the value using the pointer */
       printf("Value of *ip variable: %d\n", *ip );
    
       return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    Address of var variable: bffd8b3c
    Address stored in ip variable: bffd8b3c
    Value of *ip variable: 20
    

    NULL Pointers

    It is always a good practice to assign a NULL value to a pointer variable in case you do not have an exact address to be assigned. This is done at the time of variable declaration. A pointer that is assigned NULL is called a null pointer.

    مؤشر NULL هو ثابت بقيمة صفر محددة في العديد من المكتبات القياسية. ضع في اعتبارك البرنامج التالي -


    #include <stdio.h>
    
    int main () {
    
       int  *ptr = NULL;
    
       printf("The value of ptr is : %x\n", ptr  );
     
       return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    The value of ptr is 0
    

    في معظم أنظمة التشغيل ، لا يُسمح للبرامج بالوصول إلى الذاكرة على العنوان 0 لأن هذه الذاكرة محجوزة بواسطة نظام التشغيل. ومع ذلك ، فإن عنوان الذاكرة 0 له أهمية خاصة ؛ يشير إلى أن المؤشر لا يهدف إلى الإشارة إلى موقع ذاكرة يمكن الوصول إليه. ولكن وفقًا للاتفاقية ، إذا احتوى المؤشر على القيمة الخالية (صفر) ، فمن المفترض أنه لا يشير إلى أي شيء.


    للتحقق من وجود مؤشر فارغ ، يمكنك استخدام عبارة "if" على النحو التالي -

    if(ptr)     /* succeeds if p is not null */
    if(!ptr)    /* succeeds if p is null */
    

    المؤشرات بالتفصيل

    المؤشرات لها مفاهيم كثيرة ولكنها سهلة وهي مهمة جدًا لبرمجة لغة سي. يجب أن تكون مفاهيم المؤشر المهمة التالية واضحة لأي مبرمج سي -

    الأب رقم.المفهوم والوصف
    1مؤشر حسابي

    هناك أربع معاملات حسابية يمكن استخدامها في المؤشرات: ++ ، - ، + ، -

    2صفيف من المؤشرات

    يمكنك تحديد المصفوفات لتحتوي على عدد من المؤشرات.

    3من المؤشر إلى المؤشر

    يتيح لك C أن يكون لديك مؤشر على مؤشر وما إلى ذلك.

    4تمرير المؤشرات إلى الوظائف في C.

    يؤدي تمرير وسيطة عن طريق المرجع أو العنوان إلى تمكين تغيير الوسيطة التي تم تمريرها في دالة الاستدعاء من خلال الوظيفة التي تم استدعاؤها.

    5مؤشر العودة من الوظائف في C

    يسمح C للدالة بإرجاع مؤشر إلى المتغير المحلي والمتغير الثابت والذاكرة المخصصة ديناميكيًا أيضًا.

    c- الأوتار

    السلاسل هي في الواقع مصفوفة أحادية البعد من الأحرف منتهية بحرف فارغ '\ 0'. وبالتالي ، تحتوي السلسلة المنتهية بقيمة خالية على الأحرف التي تتكون منها السلسلة متبوعة بعلامة فارغة .

    يُنشئ الإعلان والتهيئة التاليان سلسلة تتكون من كلمة "Hello". للاحتفاظ بالحرف الفارغ في نهاية المصفوفة ، يكون حجم مصفوفة الأحرف التي تحتوي على السلسلة واحدًا أكثر من عدد الأحرف في كلمة "مرحبًا".

    char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
    

    إذا اتبعت قاعدة تهيئة المصفوفة ، فيمكنك كتابة العبارة أعلاه على النحو التالي -

    char greeting[] = "Hello";
    

    فيما يلي عرض الذاكرة للسلسلة المحددة أعلاه في C / C ++ -


    في الواقع ، لا تضع الحرف الفارغ في نهاية ثابت السلسلة. يقوم مترجم C تلقائيًا بوضع '\ 0' في نهاية السلسلة عندما يقوم بتهيئة المصفوفة. دعونا نحاول طباعة السلسلة المذكورة أعلاه -


    #include <stdio.h>
    
    int main () {
    
       char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
       printf("Greeting message: %s\n", greeting );
       return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    Greeting message: Hello
    

    C supports a wide range of functions that manipulate null-terminated strings −

    Sr.No.الوظيفة والغرض
    1

    strcpy (s1 ، s2) ؛

    Copies string s2 into string s1.

    2

    strcat (s1 ، s2) ؛

    يربط السلسلة s2 بنهاية السلسلة s1.

    3

    strlen (s1) ؛

    إرجاع طول السلسلة s1.

    4

    strcmp (s1 ، s2) ؛

    تُرجع 0 إذا كانت s1 و s2 متطابقتين ؛ أقل من 0 إذا كانت s1 <s2 ؛ أكبر من 0 إذا كانت s1> s2.

    5

    strchr (s1 ، الفصل) ؛

    إرجاع مؤشر إلى التواجد الأول للحرف ch في السلسلة s1.

    6

    strstr (s1 ، s2) ؛

    إرجاع مؤشر إلى التواجد الأول للسلسلة s2 في السلسلة s1.

    يستخدم المثال التالي بعض الوظائف المذكورة أعلاه -


    #include <stdio.h>
    #include <string.h>
    
    int main () {
    
       char str1[12] = "Hello";
       char str2[12] = "World";
       char str3[12];
       int  len ;
    
       /* copy str1 into str3 */
       strcpy(str3, str1);
       printf("strcpy( str3, str1) :  %s\n", str3 );
    
       /* concatenates str1 and str2 */
       strcat( str1, str2);
       printf("strcat( str1, str2):   %s\n", str1 );
    
       /* total lenghth of str1 after concatenation */
       len = strlen(str1);
       printf("strlen(str1) :  %d\n", len );
    
       return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    strcpy( str3, str1) :  Hello
    strcat( str1, str2):   HelloWorld
    strlen(str1) :  10
    

    C - Structures


    • لقب
    • مؤلف
    • موضوعات
    • معرف الكتاب

    تحديد هيكل

    لتعريف هيكل ، يجب عليك استخدام بيان Struct . يحدد بيان الهيكل نوع بيانات جديد ، مع أكثر من عضو واحد. شكل بيان الهيكل كما يلي -

    struct [structure tag] {
    
       member definition;
       member definition;
       ...
       member definition;
    } [one or more structure variables];  

    علامة الهيكل اختيارية وتعريف كل عضو هو تعريف متغير عادي، مثل int i; أو تطفو و؛ أو أي تعريف متغير صالح آخر. في نهاية تعريف البنية، قبل فاصلة منقوطة النهائي، يمكنك تحديد واحد أو أكثر من متغيرات البنية ولكن اختياري. هنا هو الطريقة التي قد تعلن هيكل الكتاب -

    struct Books {
       char  title[50];
       char  author[50];
       char  subject[100];
       int   book_id;
    } book;  

    الوصول إلى أعضاء الهيكل

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


    #include <stdio.h>
    #include <string.h>
     
    struct Books {
       char  title[50];
       char  author[50];
       char  subject[100];
       int   book_id;
    };
     
    int main( ) {
    
       struct Books Book1;        /* Declare Book1 of type Book */
       struct Books Book2;        /* Declare Book2 of type Book */
     
       /* book 1 specification */
       strcpy( Book1.title, "C Programming");
       strcpy( Book1.author, "Nuha Ali"); 
       strcpy( Book1.subject, "C Programming Tutorial");
       Book1.book_id = 6495407;
    
       /* book 2 specification */
       strcpy( Book2.title, "Telecom Billing");
       strcpy( Book2.author, "Zara Ali");
       strcpy( Book2.subject, "Telecom Billing Tutorial");
       Book2.book_id = 6495700;
     
       /* print Book1 info */
       printf( "Book 1 title : %s\n", Book1.title);
       printf( "Book 1 author : %s\n", Book1.author);
       printf( "Book 1 subject : %s\n", Book1.subject);
       printf( "Book 1 book_id : %d\n", Book1.book_id);
    
       /* print Book2 info */
       printf( "Book 2 title : %s\n", Book2.title);
       printf( "Book 2 author : %s\n", Book2.author);
       printf( "Book 2 subject : %s\n", Book2.subject);
       printf( "Book 2 book_id : %d\n", Book2.book_id);
    
       return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    Book 1 title : C Programming
    Book 1 author : Nuha Ali
    Book 1 subject : C Programming Tutorial
    Book 1 book_id : 6495407
    Book 2 title : Telecom Billing
    Book 2 author : Zara Ali
    Book 2 subject : Telecom Billing Tutorial
    Book 2 book_id : 6495700
    

    Structures as Function Arguments

    You can pass a structure as a function argument in the same way as you pass any other variable or pointer.


    #include <stdio.h>
    #include <string.h>
     
    struct Books {
       char  title[50];
       char  author[50];
       char  subject[100];
       int   book_id;
    };
    
    /* function declaration */
    void printBook( struct Books book );
    
    int main( ) {
    
       struct Books Book1;        /* Declare Book1 of type Book */
       struct Books Book2;        /* Declare Book2 of type Book */
     
       /* book 1 specification */
       strcpy( Book1.title, "C Programming");
       strcpy( Book1.author, "Nuha Ali"); 
       strcpy( Book1.subject, "C Programming Tutorial");
       Book1.book_id = 6495407;
    
       /* book 2 specification */
       strcpy( Book2.title, "Telecom Billing");
       strcpy( Book2.author, "Zara Ali");
       strcpy( Book2.subject, "Telecom Billing Tutorial");
       Book2.book_id = 6495700;
     
       /* print Book1 info */
       printBook( Book1 );
    
       /* Print Book2 info */
       printBook( Book2 );
    
       return 0;
    }
    
    void printBook( struct Books book ) {
    
       printf( "Book title : %s\n", book.title);
       printf( "Book author : %s\n", book.author);
       printf( "Book subject : %s\n", book.subject);
       printf( "Book book_id : %d\n", book.book_id);
    }

    When the above code is compiled and executed, it produces the following result −

    Book title : C Programming
    Book author : Nuha Ali
    Book subject : C Programming Tutorial
    Book book_id : 6495407
    Book title : Telecom Billing
    Book author : Zara Ali
    Book subject : Telecom Billing Tutorial
    Book book_id : 6495700
    

    Pointers to Structures

    You can define pointers to structures in the same way as you define pointer to any other variable −

    struct Books *struct_pointer;
    

    Now, you can store the address of a structure variable in the above defined pointer variable. To find the address of a structure variable, place the '&'; operator before the structure's name as follows −

    struct_pointer = &Book1;

    To access the members of a structure using a pointer to that structure, you must use the → operator as follows −

    struct_pointer->title;

    Let us re-write the above example using structure pointer.


    #include <stdio.h>
    #include <string.h>
     
    struct Books {
       char  title[50];
       char  author[50];
       char  subject[100];
       int   book_id;
    };
    
    /* function declaration */
    void printBook( struct Books *book );
    int main( ) {
    
       struct Books Book1;        /* Declare Book1 of type Book */
       struct Books Book2;        /* Declare Book2 of type Book */
     
       /* book 1 specification */
       strcpy( Book1.title, "C Programming");
       strcpy( Book1.author, "Nuha Ali"); 
       strcpy( Book1.subject, "C Programming Tutorial");
       Book1.book_id = 6495407;
    
       /* book 2 specification */
       strcpy( Book2.title, "Telecom Billing");
       strcpy( Book2.author, "Zara Ali");
       strcpy( Book2.subject, "Telecom Billing Tutorial");
       Book2.book_id = 6495700;
     
       /* print Book1 info by passing address of Book1 */
       printBook( &Book1 );
    
       /* print Book2 info by passing address of Book2 */
       printBook( &Book2 );
    
       return 0;
    }
    
    void printBook( struct Books *book ) {
    
       printf( "Book title : %s\n", book->title);
       printf( "Book author : %s\n", book->author);
       printf( "Book subject : %s\n", book->subject);
       printf( "Book book_id : %d\n", book->book_id);
    }

    When the above code is compiled and executed, it produces the following result −

    Book title : C Programming
    Book author : Nuha Ali
    Book subject : C Programming Tutorial
    Book book_id : 6495407
    Book title : Telecom Billing
    Book author : Zara Ali
    Book subject : Telecom Billing Tutorial
    Book book_id : 6495700 

    حقول بت

    تسمح حقول البت بتعبئة البيانات في هيكل. هذا مفيد بشكل خاص عندما تكون الذاكرة أو تخزين البيانات بسعر أعلى. تشمل الأمثلة النموذجية -


    تعبئة عدة أشياء في كلمة آلية. على سبيل المثال يمكن ضغط أعلام 1 بت.


    قراءة تنسيقات الملفات الخارجية - يمكن قراءة تنسيقات الملفات غير القياسية ، على سبيل المثال ، بأعداد صحيحة 9 بت.


    يتيح لنا C القيام بذلك في تعريف البنية بوضع: طول البت بعد المتغير. على سبيل المثال -

    struct packed_struct {
       unsigned int f1:1;
       unsigned int f2:1;
       unsigned int f3:1;
       unsigned int f4:1;
       unsigned int type:4;
       unsigned int my_int:9;
    } pack;

    هنا ، تحتوي الحزمة المعبأة على 6 أعضاء: أربعة أعلام 1 بت f1..f3 ، نوع 4 بت و 9 بت my_int.


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


    ج- النقابات

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


    تعريف الاتحاد

    لتعريف الاتحاد ، يجب عليك استخدام بيان الاتحاد بنفس الطريقة التي استخدمتها أثناء تحديد البنية. يحدد بيان الاتحاد نوع بيانات جديدًا مع أكثر من عضو واحد لبرنامجك. شكل بيان الاتحاد كما يلي

    union [union tag] {
       member definition;
       member definition;
       ...
       member definition;
    } [one or more union variables];  

    تعتبر علامة الاتحاد اختيارية وكل تعريف عضو هو تعريف متغير عادي ، مثل int i؛ أو تطفو و ؛ أو أي تعريف متغير صالح آخر. في نهاية تعريف الاتحاد ، قبل الفاصلة المنقوطة النهائية ، يمكنك تحديد متغير واحد أو أكثر ، ولكنه اختياري. إليك الطريقة التي ستحدد بها نوع الاتحاد المسمى Data الذي يحتوي على ثلاثة أعضاء i و f و str -

    union Data {
       int i;
       float f;
       char str[20];
    } data;  

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


    ستكون الذاكرة التي يشغلها الاتحاد كبيرة بما يكفي لاستيعاب أكبر عضو في الاتحاد. على سبيل المثال ، في المثال أعلاه ، سيشغل نوع البيانات 20 بايت من مساحة الذاكرة لأن هذه هي أقصى مساحة يمكن أن تشغلها سلسلة أحرف. يعرض المثال التالي الحجم الإجمالي للذاكرة التي يشغلها الاتحاد أعلاه -


    #include <stdio.h>
    #include <string.h>
     
    union Data {
       int i;
       float f;
       char str[20];
    };
     
    int main( ) {
    
       union Data data;        
    
       printf( "Memory size occupied by data : %d\n", sizeof(data));
    
       return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    Memory size occupied by data : 20
    

    Accessing Union Members

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

    #include <stdio.h>
    #include <string.h>
     
    union Data {
       int i;
       float f;
       char str[20];
    };
     
    int main( ) {
    
       union Data data;        
    
       data.i = 10;
       data.f = 220.5;
       strcpy( data.str, "C Programming");
    
       printf( "data.i : %d\n", data.i);
       printf( "data.f : %f\n", data.f);
       printf( "data.str : %s\n", data.str);
    
       return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    data.i : 1917853763
    data.f : 4122360580327794860452759994368.000000
    data.str : C Programming
    

    هنا ، يمكننا أن نرى أن قيم i و f أعضاء الاتحاد قد تلفتا لأن القيمة النهائية المخصصة للمتغير قد احتلت موقع الذاكرة وهذا هو سبب طباعة قيمة عضو str بشكل جيد للغاية.

    الآن دعنا ننظر إلى نفس المثال مرة أخرى حيث سنستخدم متغيرًا واحدًا في كل مرة وهو الغرض الرئيسي من وجود اتحادات -


    #include <stdio.h>
    #include <string.h>
     
    union Data {
       int i;
       float f;
       char str[20];
    };
     
    int main( ) {
    
       union Data data;        
    
       data.i = 10;
       printf( "data.i : %d\n", data.i);
       
       data.f = 220.5;
       printf( "data.f : %f\n", data.f);
       
       strcpy( data.str, "C Programming");
       printf( "data.str : %s\n", data.str);
    
       return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    data.i : 10
    data.f : 220.500000
    data.str : C Programming
    

    Here, all the members are getting printed very well because one member is being used at a time.

    C - Bit Fields

    افترض أن برنامج C الخاص بك يحتوي على عدد من المتغيرات TRUE / FALSE مجمعة في بنية تسمى الحالة ، على النحو التالي -

    struct {
       unsigned int widthValidated;
       unsigned int heightValidated;
    } status;

    تتطلب هذه البنية 8 بايت من مساحة الذاكرة ولكن في الواقع ، سنقوم بتخزين 0 أو 1 في كل من المتغيرات. توفر لغة البرمجة C طريقة أفضل للاستفادة من مساحة الذاكرة في مثل هذه المواقف.

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

    struct {
       unsigned int widthValidated : 1;
       unsigned int heightValidated : 1;
    } status;

    تتطلب البنية أعلاه 4 بايت من مساحة الذاكرة لمتغير الحالة ، ولكن سيتم استخدام 2 بت فقط لتخزين القيم.

    إذا كنت ستستخدم ما يصل إلى 32 متغيرًا كل منها بعرض 1 بت ، فستستخدم بنية الحالة أيضًا 4 بايت. ولكن بمجرد أن يكون لديك 33 متغيرًا ، فإنه سيخصص الفتحة التالية من الذاكرة وسيبدأ استخدام 8 بايت. دعونا نتحقق من المثال التالي لفهم المفهوم -


    #include <stdio.h>
    #include <string.h>
    
    /* define simple structure */
    struct {
       unsigned int widthValidated;
       unsigned int heightValidated;
    } status1;
    
    /* define a structure with bit fields */
    struct {
       unsigned int widthValidated : 1;
       unsigned int heightValidated : 1;
    } status2;
     
    int main( ) {
       printf( "Memory size occupied by status1 : %d\n", sizeof(status1));
       printf( "Memory size occupied by status2 : %d\n", sizeof(status2));
       return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    Memory size occupied by status1 : 8
    Memory size occupied by status2 : 4
    

    Bit Field Declaration

    يحتوي إعلان حقل البت على الشكل التالي داخل بنية -

    struct {
       type [member_name] : width ;
    };

    The following table describes the variable elements of a bit field −

    الأب رقم.العنصر والوصف
    1

    اكتب

    نوع عدد صحيح يحدد كيفية تفسير قيمة حقل البت. قد يكون النوع عدد صحيح أو عدد صحيح أو عدد صحيح بدون توقيع.

    2

    اسم عضو

    اسم حقل البت.

    3

    العرض

    عدد البتات في حقل البت. يجب أن يكون العرض أقل من عرض البت للنوع المحدد أو مساويًا له.

    المتغيرات المعرفة بعرض محدد مسبقا تسمى حقول بت . يمكن أن يحتوي حقل البت على أكثر من بت واحد ؛ على سبيل المثال ، إذا كنت بحاجة إلى متغير لتخزين قيمة من 0 إلى 7 ، فيمكنك تحديد حقل بت بعرض 3 بتات على النحو التالي -

    struct {
       unsigned int age : 3;
    } Age;

    يوجه تعريف البنية أعلاه مترجم C إلى أن متغير العمر سيستخدم 3 بتات فقط لتخزين القيمة. إذا حاولت استخدام أكثر من 3 بتات ، فلن تسمح لك بذلك. دعونا نجرب المثال التالي -


    #include <stdio.h>
    #include <string.h>
    
    struct {
       unsigned int age : 3;
    } Age;
    
    int main( ) {
    
       Age.age = 4;
       printf( "Sizeof( Age ) : %d\n", sizeof(Age) );
       printf( "Age.age : %d\n", Age.age );
    
       Age.age = 7;
       printf( "Age.age : %d\n", Age.age );
    
       Age.age = 8;
       printf( "Age.age : %d\n", Age.age );
    
       return 0;
    }

    When the above code is compiled it will compile with a warning and when executed, it produces the following result −

    Sizeof( Age ) : 4
    Age.age : 4
    Age.age : 7
    Age.age : 0
    

    c- محرف

    توفر لغة البرمجة C كلمة أساسية تسمى typedef ، والتي يمكنك استخدامها لإعطاء نوع اسم جديد. فيما يلي مثال لتعريف مصطلح BYTE للأرقام أحادية البايت -

    typedef unsigned char BYTE;
    

    بعد تعريف النوع هذا ، يمكن استخدام المعرف BYTE كاختصار لنوع char غير الموقعة ، على سبيل المثال. .

    BYTE  b1, b2;
    

    حسب الاصطلاح ، يتم استخدام الأحرف الكبيرة لهذه التعريفات لتذكير المستخدم بأن اسم النوع هو اختصار رمزي بالفعل ، ولكن يمكنك استخدام الأحرف الصغيرة ، على النحو التالي -

    typedef unsigned char byte;
    

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


    #include <stdio.h>
    #include <string.h>
     
    typedef struct Books {
       char title[50];
       char author[50];
       char subject[100];
       int book_id;
    } Book;
     
    int main( ) {
    
       Book book;
     
       strcpy( book.title, "C Programming");
       strcpy( book.author, "Nuha Ali"); 
       strcpy( book.subject, "C Programming Tutorial");
       book.book_id = 6495407;
     
       printf( "Book title : %s\n", book.title);
       printf( "Book author : %s\n", book.author);
       printf( "Book subject : %s\n", book.subject);
       printf( "Book book_id : %d\n", book.book_id);
    
       return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    Book  title : C Programming
    Book  author : Nuha Ali
    Book  subject : C Programming Tutorial
    Book  book_id : 6495407
    

    typedef vs #define

    #define is a C-directive which is also used to define the aliases for various data types similar to typedef but with the following differences −

    • يقتصر typedef على إعطاء أسماء رمزية للأنواع فقط حيث يمكن استخدام #define لتعريف الاسم المستعار للقيم أيضًا ، q. ، يمكنك تحديد 1 كـ ONE وما إلى ذلك.

    • typedef interpretation is performed by the compiler whereas #define statements are processed by the pre-processor.

    يوضح المثال التالي كيفية استخدام #define في برنامج -


    #include <stdio.h>
     
    #define TRUE  1
    #define FALSE 0
     
    int main( ) {
       printf( "Value of TRUE : %d\n", TRUE);
       printf( "Value of FALSE : %d\n", FALSE);
    
       return 0;
    }

    عندما يتم تجميع التعليمات البرمجية أعلاه وتنفيذها ، فإنها تنتج النتيجة التالية -

    Value of TRUE : 1
    Value of FALSE : 0
    

    ج- المدخلات والمخرجات

    عندما نقول إدخال ، فهذا يعني إدخال بعض البيانات في البرنامج. يمكن إعطاء الإدخال في شكل ملف أو من سطر الأوامر. توفر برمجة C مجموعة من الوظائف المضمنة لقراءة المدخلات المعينة وإدخالها إلى البرنامج حسب المتطلبات.

    عندما نقول الإخراج ، فهذا يعني عرض بعض البيانات على الشاشة أو الطابعة أو في أي ملف. توفر برمجة C مجموعة من الوظائف المضمنة لإخراج البيانات على شاشة الكمبيوتر بالإضافة إلى حفظها في ملفات نصية أو ثنائية.

    الملفات القياسية

    تعامل برمجة C جميع الأجهزة كملفات. لذلك يتم التعامل مع الأجهزة مثل الشاشة بنفس طريقة معالجة الملفات ويتم فتح الملفات الثلاثة التالية تلقائيًا عند تشغيل أحد البرامج لتوفير الوصول إلى لوحة المفاتيح والشاشة.

    ملف قياسيمؤشر الملفجهاز
    الإدخال القياسيstdinلوحة المفاتيح
    الإخراج القياسيstdoutScreen
    خطأ تقليديstderrشاشتك

    مؤشرات الملف هي وسيلة للوصول إلى الملف لغرض القراءة والكتابة. يشرح هذا القسم كيفية قراءة القيم من الشاشة وكيفية طباعة النتيجة على الشاشة.

    دالتا getchar () و putchar ()

    تقوم وظيفة int getchar (void) بقراءة الحرف التالي المتاح من الشاشة وإعادته كعدد صحيح. تقرأ هذه الوظيفة حرفًا واحدًا فقط في كل مرة. يمكنك استخدام هذه الطريقة في الحلقة في حالة رغبتك في قراءة أكثر من حرف من الشاشة.

    تقوم وظيفة int putchar (int c) بوضع الحرف الذي تم تمريره على الشاشة وإرجاع نفس الحرف. تضع هذه الوظيفة حرفًا واحدًا فقط في كل مرة. يمكنك استخدام هذه الطريقة في الحلقة في حالة رغبتك في عرض أكثر من حرف على الشاشة. تحقق من المثال التالي -

    #include <stdio.h>
    int main( ) {
    
       int c;
    
       printf( "Enter a value :");
       c = getchar( );
    
       printf( "\nYou entered: ");
       putchar( c );
    
       return 0;
    }

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

    $./a.out
    Enter a value : this is test
    You entered: t
    

    يحصل () ويضع () وظائف

    و شار * يحصل (تشار * ق) وظيفة يقرأ خط من ستدين إلى أشار عازلة لمن الصورة until either a terminating newline or EOF (End of File).

    تقوم وظيفة int puts (const char * s) بكتابة السطر الجديد اللاحق 's' و 'a' إلى stdout .

    ملاحظة: على الرغم من أنه قد تم إهمال استخدام وظيفة get () ، إلا أنك تريد استخدام fgets () بدلاً من استخدام الدالة get .

    #include <stdio.h>
    int main( ) {
    
       char str[100];
    
       printf( "Enter a value :");
       gets( str );
    
       printf( "\nYou entered: ");
       puts( str );
    
       return 0;
    }

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

    $./a.out
    Enter a value : this is test
    You entered: this is test
    

    وظائف scanf () و printf ()

    تقوم وظيفة int scanf (تنسيق const char * ، ...) بقراءة الإدخال من تيار الإدخال القياسي stdin وتفحص الإدخال وفقًا للتنسيق provided.

    و printf الباحث (شار CONST * تنسيق، ...) وظيفة يكتب الإخراج إلى معيار دفق إخراج المعياري وتنتج الانتاج وفقا لشكل المقدمة.

    و شكل يمكن أن يكون سلسلة ثابت بسيطة، ولكن يمكنك تحديد٪ s، و٪ د، ج٪،٪ و، الخ، لطباعة أو قراءة الجمل، وعدد صحيح، حرف أو تطفو على التوالي. هناك العديد من خيارات التنسيق الأخرى المتاحة والتي يمكن استخدامها بناءً على المتطلبات. دعنا ننتقل الآن بمثال بسيط لفهم المفاهيم بشكل أفضل -

    #include <stdio.h>
    int main( ) {
    
       char str[100];
       int i;
    
       printf( "Enter a value :");
       scanf("%s %d", str, &i);
    
       printf( "\nYou entered: %s %d ", str, i);
    
       return 0;
    }

    When the above code is compiled and executed, it waits for you to input some text. When you enter a text and press enter, then program proceeds and reads the input and displays it as follows −

    $./a.out
    Enter a value : seven 7
    You entered: seven 7
    

    هنا ، تجدر الإشارة إلى أن scanf () تتوقع إدخالًا بنفس التنسيق الذي قدمته٪ s و٪ d ، مما يعني أنه يتعين عليك تقديم مدخلات صالحة مثل "عدد صحيح من السلسلة". إذا قمت بتوفير "سلسلة سلسلة" أو "عدد صحيح" ، فسيتم افتراض أنها إدخال خاطئ. ثانيًا ، أثناء قراءة سلسلة ، يتوقف scanf () عن القراءة بمجرد أن يصادف مسافة ، لذا فإن "هذا اختبار" عبارة عن ثلاث سلاسل لـ scanf ().

    ج - ملف الإدخال / الإخراج

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

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

    فتح الملفات

    يمكنك استخدام وظيفة fopen () لإنشاء ملف جديد أو لفتح ملف موجود. سيؤدي هذا الاستدعاء إلى تهيئة كائن من النوع FILE ، والذي يحتوي على جميع المعلومات اللازمة للتحكم في التدفق. النموذج الأولي لاستدعاء الوظيفة هو كما يلي -

    FILE *fopen( const char * filename, const char * mode );
    

    هنا ، اسم الملف عبارة عن سلسلة حرفية ستستخدمها لتسمية ملفك ، ويمكن أن يحتوي وضع الوصول على إحدى القيم التالية -

    الأب رقم.الوضع والوصف
    1

    r

    يفتح ملف نصي موجود لغرض القراءة.

    2

    w

    يفتح ملف نصي للكتابة. إذا لم يكن موجودًا ، فسيتم إنشاء ملف جديد. هنا سيبدأ برنامجك في كتابة المحتوى من بداية الملف.

    3

    a

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

    4

    r+

    يفتح ملف نصي للقراءة والكتابة.

    5

    w+

    Opens a text file for both reading and writing. It first truncates the file to zero length if it exists, otherwise creates a file if it does not exist.

    6

    a+

    يفتح ملف نصي للقراءة والكتابة. يقوم بإنشاء الملف إذا لم يكن موجودًا. ستبدأ القراءة من البداية ولكن الكتابة يمكن إلحاقها فقط.

    إذا كنت ستتعامل مع الملفات الثنائية ، فستستخدم أوضاع الوصول التالية بدلاً من تلك المذكورة أعلاه -

    "rb", "wb", "ab", "rb+", "r+b", "wb+", "w+b", "ab+", "a+b"
    

    إغلاق ملف

    لإغلاق ملف ، استخدم الوظيفة fclose (). النموذج الأولي لهذه الوظيفة هو -

    int fclose( FILE *fp );
    

    و fclose (-) ترجع الدالة صفر على النجاح، أو EOF إذا كان هناك خطأ في إغلاق الملف. تقوم هذه الوظيفة بالفعل بمسح أي بيانات لا تزال معلقة في المخزن المؤقت إلى الملف ، وتغلق الملف ، وتحرر أي ذاكرة مستخدمة للملف. EOF هو ثابت محدد في ملف الرأس stdio.h .

    هناك العديد من الوظائف التي توفرها مكتبة C القياسية لقراءة وكتابة ملف ، حرفًا بحرف ، أو في شكل سلسلة ثابتة الطول.

    كتابة ملف

    فيما يلي أبسط وظيفة لكتابة الأحرف الفردية إلى تيار -

    int fputc( int c, FILE *fp );
    

    تكتب الدالة fputc () قيمة حرف الوسيطة c إلى تدفق الإخراج المشار إليه بواسطة fp. تقوم بإرجاع الحرف المكتوب المكتوب على النجاح وإلا EOF إذا كان هناك خطأ. يمكنك استخدام الوظائف التالية لكتابة سلسلة منتهية بقيمة خالية إلى دفق -

    int fputs( const char *s, FILE *fp );
    

    تكتب الدالة fputs () السلسلة s إلى تدفق الإخراج المشار إليه بواسطة fp. تقوم بإرجاع قيمة غير سالبة عند النجاح ، وإلا يتم إرجاع EOF في حالة حدوث أي خطأ. يمكنك استخدام وظيفة int fprintf (FILE * fp، const char * format، ...) لكتابة سلسلة في ملف. جرب المثال التالي.

    تأكد من توفر دليل / tmp . إذا لم يكن كذلك ، فقبل المتابعة ، يجب عليك إنشاء هذا الدليل على جهازك.

    #include <stdio.h>
    
    main() {
       FILE *fp;
    
       fp = fopen("/tmp/test.txt", "w+");
       fprintf(fp, "This is testing for fprintf...\n");
       fputs("This is testing for fputs...\n", fp);
       fclose(fp);
    }

    When the above code is compiled and executed, it creates a new file test.txt in /tmp directory and writes two lines using two different functions. Let us read this file in the next section.

    قراءة ملف

    فيما يلي أبسط وظيفة لقراءة حرف واحد من ملف -

    int fgetc( FILE * fp );
    

    و fgetc () وظيفة يقرأ حرف من ملف الإدخال المشار إليه من قبل تنظيم الأسرة. القيمة المعادة هي الحرف الذي تمت قراءته ، أو في حالة حدوث أي خطأ ، فإنه يُرجع EOF . تسمح الوظيفة التالية بقراءة سلسلة من الدفق -

    char *fgets( char *buf, int n, FILE *fp );
    

    تقرأ الوظائف fgets () ما يصل إلى حرف n-1 من دفق الإدخال المشار إليه بواسطة fp. يقوم بنسخ سلسلة قراءة في المخزن المؤقت BUF ، بإلحاق اغية حرف لإنهاء السلسلة.

    إذا واجهت هذه الوظيفة حرفًا جديدًا في السطر '\ n' أو نهاية الملف EOF قبل أن يقرأوا الحد الأقصى لعدد الأحرف ، فإنها ترجع فقط الأحرف المقروءة حتى تلك النقطة بما في ذلك حرف السطر الجديد. يمكنك أيضًا استخدام دالة int fscanf (FILE * fp، const char * format، ...) لقراءة السلاسل من ملف ، لكنها تتوقف عن القراءة بعد مواجهة أول حرف مسافة.

    #include <stdio.h>
    
    main() {
    
       FILE *fp;
       char buff[255];
    
       fp = fopen("/tmp/test.txt", "r");
       fscanf(fp, "%s", buff);
       printf("1 : %s\n", buff );
    
       fgets(buff, 255, (FILE*)fp);
       printf("2: %s\n", buff );
       
       fgets(buff, 255, (FILE*)fp);
       printf("3: %s\n", buff );
       fclose(fp);
    
    }

    When the above code is compiled and executed, it reads the file created in the previous section and produces the following result −

    1 : This
    2: is testing for fprintf...
    
    3: This is testing for fputs...
    

    Let's see a little more in detail about what happened here. First, fscanf() read just This because after that, it encountered a space, second call is for fgets() which reads the remaining line till it encountered end of line. Finally, the last call fgets() reads the second line completely.

    وظائف الإدخال / الإخراج الثنائية

    هناك نوعان من الوظائف التي يمكن استخدامها للمدخلات والمخرجات الثنائية -

    size_t fread(void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file);
                  
    size_t fwrite(const void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file);

    يجب استخدام هاتين الوظيفتين لقراءة أو كتابة كتل من الذكريات - عادةً المصفوفات أو الهياكل.

    C - Preprocessors

    و C قبل المعالج ليست جزءا من المجمع، بل هي خطوة منفصلة في عملية الترجمة. بعبارات بسيطة ، يعد المعالج الأولي للغة C مجرد أداة لاستبدال النص ويوجه المترجم للقيام بالمعالجة المسبقة المطلوبة قبل التجميع الفعلي. سوف نشير إلى المعالج الأولي C باسم CPP.

    تبدأ جميع أوامر المعالج المسبق برمز التجزئة (#). يجب أن يكون أول حرف غير فارغ ، ولإمكانية القراءة ، يجب أن يبدأ توجيه المعالج المسبق في العمود الأول. يسرد القسم التالي جميع توجيهات المعالج المسبق المهمة -

    الأب رقم.التوجيه والوصف
    1

    #define

    يستبدل ماكرو المعالج المسبق.

    2

    #include

    إدراج رأس معين من ملف آخر.

    3

    undef

    يقوم بإلغاء تعريف ماكرو المعالج المسبق.

    4

    #ifdef

    إرجاع صحيح إذا تم تعريف هذا الماكرو.

    5

    ifdef

    إرجاع صحيح إذا لم يتم تعريف هذا الماكرو.

    6

    #ifdef

    اختبار ما إذا كان شرط وقت الترجمة صحيحًا.

    7

    #else

    البديل لـ #if.

    8

    #elif

    # آخر و #if في بيان واحد.

    9

    #else

    ينتهي الشرطي المعالج.

    10

    #error

    يطبع رسالة خطأ على stderr.

    11

    pragma

    يصدر أوامر خاصة للمترجم باستخدام طريقة معيارية.

    أمثلة المعالجات المسبقة

    تحليل الأمثلة التالية لفهم التوجيهات المختلفة.

    #define MAX_ARRAY_LENGTH 20
    

    يطلب هذا التوجيه من CPP استبدال مثيلات MAX_ARRAY_LENGTH بـ 20. استخدام #define for constants to increase readability.

    #include <stdio.h>
    #include "myheader.h"

    These directives tell the CPP to get stdio.h from System Libraries and add the text to the current source file. The next line tells CPP to get myheader.h from the local directory and add the content to the current source file.

    #undef  FILE_SIZE
    #define FILE_SIZE 42

    يخبر CPP بإلغاء تعريف FILE_SIZE الحالي وتعريفه كـ 42.

    #ifndef MESSAGE
       #define MESSAGE "You wish!"
    #endif

    يخبر CPP بتعريف MESSAGE فقط إذا لم تكن MESSAGE محددة بالفعل.

    #ifdef DEBUG
       /* Your debugging statements here */
    #endif

    يخبر CPP بمعالجة البيانات المرفقة إذا تم تعريف DEBUG. يكون هذا مفيدًا إذا قمت بتمرير العلامة -DDEBUG إلى برنامج التحويل البرمجي gcc في وقت التحويل البرمجي. سيحدد هذا DEBUG ، لذا يمكنك تشغيل تصحيح الأخطاء وإيقافه بسرعة أثناء التجميع.

    وحدات ماكرو معرفة مسبقا

    يحدد ANSI C عددًا من وحدات الماكرو. على الرغم من أن كل واحد متاح للاستخدام في البرمجة ، إلا أنه لا ينبغي تعديل وحدات الماكرو المحددة مسبقًا بشكل مباشر.

    الأب رقم.الماكرو والوصف
    1

    __DATE__

    التاريخ الحالي كحرف حرفي بتنسيق "MMM DD YYYY".

    2

    __FILE__

    الوقت الحالي كحرف حرفي بتنسيق "HH: MM: SS".

    3

    __FILE__

    هذا يحتوي على اسم الملف الحالي كسلسلة حرفية.

    4

    __LINE__

    يحتوي هذا على رقم السطر الحالي باعتباره ثابتًا عشريًا.

    5

    __STDC__

    يتم تعريفه على أنه 1 عندما يتوافق المترجم مع معيار ANSI.

    لنجرب المثال التالي -

    #include <stdio.h>
    
    int main() {
    
       printf("File :%s\n", __FILE__ );
       printf("Date :%s\n", __DATE__ );
       printf("Time :%s\n", __TIME__ );
       printf("Line :%d\n", __LINE__ );
       printf("ANSI :%d\n", __STDC__ );
    
    }

    When the above code in a file test.c is compiled and executed, it produces the following result −

    File :test.c
    Date :Jun 2 2012
    Time :03:36:24
    Line :8
    ANSI :1
    

    مشغلي المعالجات المسبقة

    يقدم المعالج الأولي C العوامل التالية للمساعدة في إنشاء وحدات الماكرو -

    عامل استمرارية الماكرو (\)

    عادةً ما يقتصر الماكرو على سطر واحد. يتم استخدام عامل متابعة الماكرو (\) لمتابعة ماكرو طويل جدًا بالنسبة إلى سطر واحد. على سبيل المثال -

    #define  message_for(a, b)  \
       printf(#a " and " #b ": We love you!\n")

    عامل Stringize (#)

    عند استخدام عامل السلسلة أو علامة الرقم ("#") ضمن تعريف ماكرو ، يحول معلمة الماكرو إلى ثابت سلسلة. يمكن استخدام عامل التشغيل هذا فقط في الماكرو الذي يحتوي على وسيطة محددة أو قائمة معلمات. على سبيل المثال -


    #include <stdio.h>
    
    #define  message_for(a, b)  \
       printf(#a " and " #b ": We love you!\n")
    
    int main(void) {
       message_for(Carole, Debra);
       return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    Carole and Debra: We love you!
    

    The Token Pasting (##) Operator

    يدمج عامل لصق الرمز المميز (##) ضمن تعريف الماكرو وسيطتين. يسمح بضم رمزين مميزين منفصلين في تعريف الماكرو في رمز مميز واحد. على سبيل المثال -


    #include <stdio.h>
    
    #define tokenpaster(n) printf ("token" #n " = %d", token##n)
    
    int main(void) {
       int token34 = 40;
       tokenpaster(34);
       return 0;
    }

    عندما يتم تجميع التعليمات البرمجية أعلاه وتنفيذها ، فإنها تنتج النتيجة التالية -

    token34 = 40
    

    حدث ذلك لأن هذا المثال ينتج عنه الإخراج الفعلي التالي من المعالج المسبق -

    printf ("token34 = %d", token34);

    هذا المثال يبين تسلسل من ## رمزي ن في token34 وهنا استخدمنا كلا stringize و رمزي اللصق .

    المشغل المحدد ()

    يتم استخدام عامل التشغيل المعرّف للمعالج المسبق في التعبيرات الثابتة لتحديد ما إذا تم تعريف المعرف باستخدام #define. إذا تم تعريف المعرف المحدد ، تكون القيمة صحيحة (ليست صفرية). إذا لم يتم تعريف الرمز ، تكون القيمة خاطئة (صفر). تم تحديد عامل التشغيل المحدد على النحو التالي -


    #include <stdio.h>
    
    #if !defined (MESSAGE)
       #define MESSAGE "You wish!"
    #endif
    
    int main(void) {
       printf("Here is the message: %s\n", MESSAGE);  
       return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    Here is the message: You wish!
    

    وحدات ماكرو ذات معلمة

    تتمثل إحدى الوظائف القوية لـ CPP في القدرة على محاكاة الوظائف باستخدام وحدات ماكرو ذات معلمات. على سبيل المثال ، قد يكون لدينا بعض الكود لتربيع رقم على النحو التالي -

    int square(int x) {
       return x * x;
    }

    يمكننا إعادة الكتابة فوق الكود باستخدام ماكرو على النحو التالي -

    #define square(x) ((x) * (x))

    يجب تحديد وحدات الماكرو التي تحتوي على وسيطات باستخدام التوجيه #define قبل استخدامها. قائمة الوسائط محاطة بأقواس ويجب أن تتبع اسم الماكرو على الفور. غير مسموح بالمسافات بين اسم الماكرو والأقواس المفتوحة. على سبيل المثال -


    #include <stdio.h>
    
    #define MAX(x,y) ((x) > (y) ? (x) : (y))
    
    int main(void) {
       printf("Max between 20 and 10 is %d\n", MAX(10, 20));  
       return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    Max between 20 and 10 is 20
    

    ج - ملفات الرأس

    ملف الرأس هو ملف بامتداد .h يحتوي على إعلانات دالة C وتعريفات ماكرو لمشاركتها بين عدة ملفات مصدر. هناك نوعان من ملفات الرأس: الملفات التي يكتبها المبرمج والملفات التي تأتي مع المترجم.

    أنت تطلب استخدام ملف رأس في برنامجك عن طريق تضمينه مع توجيه المعالجة المسبقة C # تضمين ، كما رأيت تضمين ملف رأس stdio.h ، والذي يأتي مع برنامج التحويل البرمجي الخاص بك.

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

    من الممارسات البسيطة في برامج C أو C ++ أننا نحتفظ بجميع الثوابت ووحدات الماكرو والمتغيرات العالمية على مستوى النظام ونماذج الوظائف في ملفات الرأس وتضمين ملف الرأس هذا حيثما كان ذلك مطلوبًا.

    تضمين بناء الجملة

    يتم تضمين ملفات رأس المستخدم والنظام باستخدام توجيه المعالجة المسبقة #include . له الشكلين التاليين -

    #include <file>
    

    يستخدم هذا النموذج لملفات رأس النظام. يبحث عن ملف يسمى "ملف" في قائمة قياسية لأدلة النظام. يمكنك إضافة الدلائل إلى هذه القائمة مسبقًا باستخدام الخيار -I أثناء تجميع التعليمات البرمجية المصدر.

    #include "file"
    

    يستخدم هذا النموذج لملفات الرأس الخاصة بالبرنامج الخاص بك. يبحث عن ملف يسمى "ملف" في الدليل الذي يحتوي على الملف الحالي. يمكنك إضافة الدلائل إلى هذه القائمة مسبقًا باستخدام الخيار -I أثناء تجميع التعليمات البرمجية المصدر.

    تشمل العملية

    و # تشمل أعمال التوجيهية بتوجيه C المعالج لمسح الملف المحدد كمدخل قبل المتابعة مع بقية الملف المصدر الحالي. يحتوي الإخراج من المعالج الأولي على الإخراج الذي تم إنشاؤه بالفعل ، متبوعًا بالإخراج الناتج من الملف المضمن ، متبوعًا بالإخراج الذي يأتي من النص بعد التوجيه #include . على سبيل المثال ، إذا كان لديك ملف header.h على النحو التالي -

    char *test (void);
    

    وبرنامج رئيسي يسمى program.c يستخدم ملف الرأس ، مثل هذا -

    int x;
    #include "header.h"
    
    int main (void) {
       puts (test ());
    }

    سيشاهد المترجم دفق الرمز المميز نفسه كما لو قرأ program.c.

    int x;
    char *test (void);
    
    int main (void) {
       puts (test ());
    }

    رؤوس لمرة واحدة فقط

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

    #ifndef HEADER_FILE
    #define HEADER_FILE
    
    the entire header file file
    
    #endif

    يُعرف هذا البناء عمومًا باسم غلاف #ifndef . عندما يتم تضمين الرأس مرة أخرى ، سيكون الشرط خطأ ، لأنه تم تعريف HEADER_FILE. سيتخطى المعالج المسبق محتويات الملف بالكامل ، ولن يراه المحول البرمجي مرتين.

    يشمل المحسوبة

    في بعض الأحيان يكون من الضروري تحديد واحد من عدة ملفات رأس مختلفة لتضمينها في برنامجك. على سبيل المثال ، قد تحدد معلمات التكوين لاستخدامها في أنواع مختلفة من أنظمة التشغيل. يمكنك القيام بذلك بسلسلة من الشروط على النحو التالي -

    #if SYSTEM_1
       # include "system_1.h"
    #elif SYSTEM_2
       # include "system_2.h"
    #elif SYSTEM_3
       ...
    #endif

    ولكن مع نموها ، تصبح مملة ، وبدلاً من ذلك يوفر المعالج المسبق القدرة على استخدام ماكرو لاسم الرأس. وهذا ما يسمى التضمين المحسوب . بدلاً من كتابة اسم رأس كوسيطة مباشرة لـ # تضمين ، يمكنك ببساطة وضع اسم ماكرو هناك -

    #define SYSTEM_H "system_1.h"
    ...
    #include SYSTEM_H
    

    سيتم توسيع SYSTEM_H ، وسيبحث المعالج المسبق عن system_1.h كما لو أن # include قد تمت كتابته بهذه الطريقة في الأصل. يمكن تعريف SYSTEM_H بواسطة Makefile الخاص بك مع خيار -D.

    ج - نوع الصب

    إن صب النوع هو طريقة لتحويل متغير من نوع بيانات إلى نوع بيانات آخر. على سبيل المثال ، إذا كنت تريد تخزين قيمة "طويلة" في عدد صحيح بسيط ، فيمكنك كتابة cast "long" إلى "int". يمكنك تحويل القيم من نوع إلى آخر بشكل صريح باستخدام عامل الصب كما يلي -

    (type_name) expression
    

    ضع في اعتبارك المثال التالي حيث يتسبب عامل التشغيل في تقسيم متغير عدد صحيح على آخر ليتم إجراؤه كعملية فاصلة عائمة -


    #include <stdio.h>
    
    main() {
    
       int sum = 17, count = 5;
       double mean;
    
       mean = (double) sum / count;
       printf("Value of mean : %f\n", mean );
    }

    عندما يتم تجميع التعليمات البرمجية أعلاه وتنفيذها ، فإنها تنتج النتيجة التالية -

    Value of mean : 3.400000
    

    وتجدر الإشارة هنا إلى أن عامل الصب له الأسبقية على القسمة ، لذلك يتم تحويل قيمة المجموع أولاً إلى النوع مزدوج ، وفي النهاية يتم تقسيمها على العدد الذي ينتج عنه قيمة مزدوجة.

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

    ترقية عدد صحيح

    ترقية عدد صحيح هي العملية التي يتم من خلالها تحويل القيم من نوع عدد صحيح "أصغر" من int أو غير موقعة int إلى int أو int . ضع في اعتبارك مثالاً لإضافة حرف بعدد صحيح -


    #include <stdio.h>
    
    main() {
    
       int  i = 17;
       char c = 'c'; /* ascii value is 99 */
       int sum;
    
       sum = i + c;
       printf("Value of sum : %d\n", sum );
    }

    When the above code is compiled and executed, it produces the following result −

    Value of sum : 116
    

    هنا ، قيمة المجموع هي 116 لأن المترجم يقوم بترقية عدد صحيح ويحول قيمة 'c' إلى ASCII قبل تنفيذ عملية الإضافة الفعلية.

    التحويل الحسابي المعتاد

    و التحويلات الحسابية المعتادة تتم ضمنيا للادلاء القيم الخاصة بها إلى نوع شائع. يقوم المترجم أولاً بتنفيذ ترقية عدد صحيح ؛ إذا كانت المعاملات لا تزال تحتوي على أنواع مختلفة ، فسيتم تحويلها إلى النوع الذي يظهر أعلى مستوى في التسلسل الهرمي التالي -

    التحويل الحسابي المعتاد

    لا يتم إجراء التحويلات الحسابية المعتادة لمشغلي التخصيص ، ولا للعوامل المنطقية && و ||. دعونا نأخذ المثال التالي لفهم المفهوم -


    #include <stdio.h>
    
    main() {
    
       int  i = 17;
       char c = 'c'; /* ascii value is 99 */
       float sum;
    
       sum = i + c;
       printf("Value of sum : %f\n", sum );
    }

    When the above code is compiled and executed, it produces the following result −

    Value of sum : 116.000000
    

    هنا ، من السهل أن نفهم أن c الأول يتم تحويله إلى عدد صحيح ، ولكن نظرًا لأن القيمة النهائية مزدوجة ، يتم تطبيق التحويل الحسابي المعتاد ويقوم المترجم بتحويل i و c إلى "float" ويضيفهم للحصول على نتيجة "float".

    ج - معالجة الخطأ

    على هذا النحو ، لا توفر برمجة C دعمًا مباشرًا لمعالجة الأخطاء ولكنها لغة برمجة نظام ، فهي توفر لك الوصول على مستوى أدنى في شكل قيم إرجاع. معظم استدعاءات دالة C أو حتى Unix ترجع -1 أو NULL في حالة حدوث أي خطأ وتعيين رمز خطأ errno . يتم تعيينه كمتغير عام ويشير إلى حدوث خطأ أثناء أي استدعاء للدالة. يمكنك العثور على العديد من رموز الأخطاء المحددة في ملف الرأس <error.h>.

    لذلك يمكن للمبرمج C التحقق من القيم التي تم إرجاعها ويمكنه اتخاذ الإجراء المناسب بناءً على قيمة الإرجاع. من الممارسات الجيدة تعيين errno على 0 في وقت تهيئة البرنامج. تشير القيمة 0 إلى عدم وجود خطأ في البرنامج.

    errno ، perror (). و strerror ()

    توفر لغة البرمجة C وظائف perror () و strerror () والتي يمكن استخدامها لعرض الرسالة النصية المرتبطة بالخطأ .

    • و perror () يعرض وظيفة السلسلة التي تمرر إلى ذلك، متبوعا بنقطتين، مسافة، ومن ثم تمثيل نصية من قيمة errno الحالية.

    • و strerror () وظيفة، والتي ترجع مؤشر إلى تمثيل نصية من قيمة errno الحالية.

    دعنا نحاول محاكاة حالة خطأ ونحاول فتح ملف غير موجود. أنا هنا أستخدم كلتا الوظيفتين لإظهار الاستخدام ، ولكن يمكنك استخدام طريقة واحدة أو أكثر لطباعة أخطائك. النقطة الثانية المهمة التي يجب ملاحظتها هي أنه يجب عليك استخدام دفق ملف stderr لإخراج جميع الأخطاء.

    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    
    extern int errno ;
    
    int main () {
    
       FILE * pf;
       int errnum;
       pf = fopen ("unexist.txt", "rb");
    	
       if (pf == NULL) {
       
          errnum = errno;
          fprintf(stderr, "Value of errno: %d\n", errno);
          perror("Error printed by perror");
          fprintf(stderr, "Error opening file: %s\n", strerror( errnum ));
       } else {
       
          fclose (pf);
       }
       
       return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    Value of errno: 2
    Error printed by perror: No such file or directory
    Error opening file: No such file or directory
    

    Divide by Zero Errors

    إنها مشكلة شائعة أنه في وقت قسمة أي رقم ، لا يتحقق المبرمجون مما إذا كان المقسوم عليه صفرًا ، وفي النهاية ينتج عنه خطأ في وقت التشغيل.

    يُصلح الكود أدناه هذا عن طريق التحقق مما إذا كان المقسوم عليه صفرًا قبل القسمة -


    #include <stdio.h>
    #include <stdlib.h>
    
    main() {
    
       int dividend = 20;
       int divisor = 0;
       int quotient;
     
       if( divisor == 0){
          fprintf(stderr, "Division by zero! Exiting...\n");
          exit(-1);
       }
       
       quotient = dividend / divisor;
       fprintf(stderr, "Value of quotient : %d\n", quotient );
    
       exit(0);
    }

    When the above code is compiled and executed, it produces the following result −

    Division by zero! Exiting...
    

    حالة الخروج من البرنامج

    إنها ممارسة شائعة للخروج بقيمة EXIT_SUCCESS في حالة خروج البرنامج بعد عملية ناجحة. هنا ، EXIT_SUCCESS هو ماكرو ويتم تعريفه على أنه 0.

    إذا كانت لديك حالة خطأ في برنامجك وكنت على وشك الخروج ، فيجب عليك الخروج بالحالة EXIT_FAILURE والتي تم تعريفها على أنها -1. لذلك دعونا نكتب البرنامج أعلاه على النحو التالي -


    #include <stdio.h>
    #include <stdlib.h>
    
    main() {
    
       int dividend = 20;
       int divisor = 5;
       int quotient;
     
       if( divisor == 0) {
          fprintf(stderr, "Division by zero! Exiting...\n");
          exit(EXIT_FAILURE);
       }
    	
       quotient = dividend / divisor;
       fprintf(stderr, "Value of quotient : %d\n", quotient );
    
       exit(EXIT_SUCCESS);
    }

    When the above code is compiled and executed, it produces the following result −

    Value of quotient : 4
    

    ج- العودية

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

    void recursion() {
       recursion(); /* function calls itself */
    }
    
    int main() {
       recursion();
    }

    The C programming language supports recursion, i.e., a function to call itself. But while using recursion, programmers need to be careful to define an exit condition from the function, otherwise it will go into an infinite loop.

    تعد الدوال التكرارية مفيدة جدًا في حل العديد من المشكلات الرياضية ، مثل حساب عاملي الرقم ، وتوليد سلسلة فيبوناتشي ، إلخ.

    عامل رقم

    يحسب المثال التالي مضروب رقم معين باستخدام دالة تكرارية -


    #include <stdio.h>
    
    unsigned long long int factorial(unsigned int i) {
    
       if(i <= 1) {
          return 1;
       }
       return i * factorial(i - 1);
    }
    
    int  main() {
       int i = 12;
       printf("Factorial of %d is %d\n", i, factorial(i));
       return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    Factorial of 12 is 479001600
    

    سلسلة فيبوناتشي

    المثال التالي يولد سلسلة فيبوناتشي لرقم معين باستخدام دالة تكرارية -


    #include <stdio.h>
    
    int fibonacci(int i) {
    
       if(i == 0) {
          return 0;
       }
    	
       if(i == 1) {
          return 1;
       }
       return fibonacci(i-1) + fibonacci(i-2);
    }
    
    int  main() {
    
       int i;
    	
       for (i = 0; i < 10; i++) {
          printf("%d\t\n", fibonacci(i));
       }
    	
       return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    0	
    1	
    1	
    2	
    3	
    5	
    8	
    13	
    21	
    34
    

    ج- الحجج المتغيرة

    في بعض الأحيان ، قد تصادف موقفًا ، عندما تريد الحصول على وظيفة ، والتي يمكن أن تأخذ عددًا متغيرًا من الوسائط ، مثل المعلمات ، بدلاً من عدد محدد مسبقًا من المعلمات. توفر لغة البرمجة C حلاً لهذا الموقف ويُسمح لك بتحديد وظيفة يمكنها قبول عدد متغير من المعلمات بناءً على متطلباتك. يوضح المثال التالي تعريف هذه الوظيفة.

    int func(int, ... ) {
       .
       .
       .
    }
    
    int main() {
       func(1, 2, 3);
       func(1, 2, 3, 4);
    }

    It should be noted that the function func() has its last argument as ellipses, i.e. three dotes (...) and the one just before the ellipses is always an int which will represent the total number variable arguments passed. To use such functionality, you need to make use of stdarg.h header file which provides the functions and macros to implement the functionality of variable arguments and follow the given steps −

    • قم بتعريف دالة بمعاملتها الأخيرة مثل علامات الحذف والوظيفة التي تسبق علامات الحذف هي دائمًا int والتي ستمثل عدد الوسائط.

    • قم بإنشاء متغير نوع va_list في تعريف الوظيفة. يتم تعريف هذا النوع في ملف الرأس stdarg.h.

    • استخدم المعلمة int والماكرو va_start لتهيئة متغير va_list إلى قائمة وسيطات. يتم تعريف الماكرو va_start في ملف رأس stdarg.h.

    • استخدم ماكرو va_arg ومتغير va_list للوصول إلى كل عنصر في قائمة الوسائط.

    • استخدم ماكرو va_end لتنظيف الذاكرة المخصصة لمتغير va_list .

    الآن دعنا نتبع الخطوات المذكورة أعلاه ونكتب وظيفة بسيطة يمكنها أخذ العدد المتغير من المعلمات وإرجاع متوسطها -


    #include <stdio.h>
    #include <stdarg.h>
    
    double average(int num,...) {
    
       va_list valist;
       double sum = 0.0;
       int i;
    
       /* initialize valist for num number of arguments */
       va_start(valist, num);
    
       /* access all the arguments assigned to valist */
       for (i = 0; i < num; i++) {
          sum += va_arg(valist, int);
       }
    	
       /* clean memory reserved for valist */
       va_end(valist);
    
       return sum/num;
    }
    
    int main() {
       printf("Average of 2, 3, 4, 5 = %f\n", average(4, 2,3,4,5));
       printf("Average of 5, 10, 15 = %f\n", average(3, 5,10,15));
    }

    When the above code is compiled and executed, it produces the following result. It should be noted that the function average() has been called twice and each time the first argument represents the total number of variable arguments being passed. Only ellipses will be used to pass variable number of arguments.

    Average of 2, 3, 4, 5 = 3.500000
    Average of 5, 10, 15 = 10.000000
    

    C - Memory Management

    يشرح هذا الفصل الإدارة الديناميكية للذاكرة في C. توفر لغة البرمجة C وظائف عديدة لتخصيص الذاكرة وإدارتها. يمكن العثور على هذه الوظائف في ملف الرأس <stdlib.h> .

    الأب رقم.الوظيفة والوصف
    1

    باطل * calloc (عدد int ، حجم int) ؛

    هذه وظيفة تخصص مجموعة من الأسطوانات عناصر كل منها في حجم بايت سيكون حجم .

    2

    باطل مجاني (عنوان * باطل) ؛

    تقوم هذه الوظيفة بإصدار كتلة من كتلة الذاكرة المحددة بواسطة العنوان.

    3

    باطل * malloc (عدد int) ؛

    هذه وظيفة تخصص مجموعة من الأسطوانات بايت وتركها غير مهيأة.

    4

    void * realloc (void * address، int newsize) ؛

    تقوم هذه الوظيفة بإعادة تخصيص الذاكرة لتوسيعها حتى حجم الأخبار .

    تخصيص الذاكرة ديناميكيًا

    أثناء البرمجة ، إذا كنت على دراية بحجم المصفوفة ، فهذا سهل ويمكنك تحديده كمصفوفة. على سبيل المثال ، لتخزين اسم أي شخص ، يمكن أن يصل إلى 100 حرف كحد أقصى ، بحيث يمكنك تحديد شيء ما على النحو التالي -

    char name[100];
    

    لكن دعنا الآن نفكر في موقف ليس لديك فيه فكرة عن طول النص الذي تريد تخزينه ، على سبيل المثال ، تريد تخزين وصف مفصل حول موضوع ما. نحتاج هنا إلى تحديد مؤشر للحرف دون تحديد مقدار الذاكرة المطلوبة وبعد ذلك ، بناءً على المتطلبات ، يمكننا تخصيص الذاكرة كما هو موضح في المثال أدناه -


    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main() {
    
       char name[100];
       char *description;
    
       strcpy(name, "Zara Ali");
    
       /* allocate memory dynamically */
       description = malloc( 200 * sizeof(char) );
    	
       if( description == NULL ) {
          fprintf(stderr, "Error - unable to allocate required memory\n");
       } else {
          strcpy( description, "Zara ali a DPS student in class 10th");
       }
       
       printf("Name = %s\n", name );
       printf("Description: %s\n", description );
    }

    When the above code is compiled and executed, it produces the following result.

    Name = Zara Ali
    Description: Zara ali a DPS student in class 10th
    

    Same program can be written using calloc(); only thing is you need to replace malloc with calloc as follows −

    calloc(200, sizeof(char));

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

    تحجيم وتحرير الذاكرة

    عندما يخرج البرنامج الخاص بك ، يقوم نظام التشغيل تلقائيًا بتحرير كل الذاكرة المخصصة بواسطة برنامجك ولكن كممارسة جيدة عندما لا تكون في حاجة إلى ذاكرة بعد الآن ، يجب عليك تحرير تلك الذاكرة عن طريق استدعاء الوظيفة مجانًا () .

    بدلاً من ذلك ، يمكنك زيادة أو تقليل حجم كتلة الذاكرة المخصصة عن طريق استدعاء الوظيفة realloc () . دعونا نتحقق من البرنامج أعلاه مرة أخرى ونستفيد من وظائف realloc () و free () -


    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main() {
    
       char name[100];
       char *description;
    
       strcpy(name, "Zara Ali");
    
       /* allocate memory dynamically */
       description = malloc( 30 * sizeof(char) );
    	
       if( description == NULL ) {
          fprintf(stderr, "Error - unable to allocate required memory\n");
       } else {
          strcpy( description, "Zara ali a DPS student.");
       }
    	
       /* suppose you want to store bigger description */
       description = realloc( description, 100 * sizeof(char) );
    	
       if( description == NULL ) {
          fprintf(stderr, "Error - unable to allocate required memory\n");
       } else {
          strcat( description, "She is in class 10th");
       }
       
       printf("Name = %s\n", name );
       printf("Description: %s\n", description );
    
       /* release memory using free() function */
       free(description);
    }

    When the above code is compiled and executed, it produces the following result.

    Name = Zara Ali
    Description: Zara ali a DPS student.She is in class 10th
    

    You can try the above example without re-allocating extra memory, and strcat() function will give an error due to lack of available memory in description.

    ج - حجج سطر الأوامر

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

    يتم التعامل مع وسيطات سطر الأوامر باستخدام وسيطات الدالة main () حيث تشير argc إلى عدد الوسائط التي تم تمريرها ، بينما تشير argv [] إلى مصفوفة مؤشر تشير إلى كل وسيطة تم تمريرها إلى البرنامج. فيما يلي مثال بسيط يتحقق مما إذا كانت هناك أي حجة يتم توفيرها من سطر الأوامر واتخاذ الإجراءات وفقًا لذلك -

    #include <stdio.h>
    
    int main( int argc, char *argv[] )  {
    
       if( argc == 2 ) {
          printf("The argument supplied is %s\n", argv[1]);
       }
       else if( argc > 2 ) {
          printf("Too many arguments supplied.\n");
       }
       else {
          printf("One argument expected.\n");
       }
    }

    When the above code is compiled and executed with single argument, it produces the following result.

    $./a.out testing
    The argument supplied is testing

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

    $./a.out testing1 testing2
    Too many arguments supplied.

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

    $./a.out
    One argument expected

    وتجدر الإشارة إلى أن argv [0] يحمل اسم البرنامج نفسه و argv [1] هو مؤشر إلى وسيطة سطر الأوامر الأولى المقدمة ، و * argv [n] هي الوسيطة الأخيرة. إذا لم يتم توفير وسيطات ، فستكون argc واحدة ، وإذا مررت وسيطة واحدة ، فسيتم تعيين argc على 2.

    يمكنك تمرير جميع وسائط سطر الأوامر مفصولة بمسافة ، ولكن إذا كانت الوسيطة نفسها تحتوي على مسافة ، فيمكنك تمرير هذه الوسائط بوضعها داخل علامات اقتباس مزدوجة "" أو علامات اقتباس مفردة ". دعنا نعيد كتابة المثال أعلاه مرة أخرى حيث سنطبع اسم البرنامج ونمرر أيضًا وسيطة سطر الأوامر عن طريق وضع علامات اقتباس مزدوجة داخل -

    #include <stdio.h>
    
    int main( int argc, char *argv[] )  {
    
       printf("Program name %s\n", argv[0]);
     
       if( argc == 2 ) {
          printf("The argument supplied is %s\n", argv[1]);
       }
       else if( argc > 2 ) {
          printf("Too many arguments supplied.\n");
       }
       else {
          printf("One argument expected.\n");
       }
    }

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

    $./a.out "testing1 testing2"
    
    Progranm name ./a.out
    The argument supplied is testing1 testing2
    

    الصفحة التالية                                                                             الصفحة السابقة  
أنت الان في اول موضوع
هل اعجبك الموضوع :

تعليقات