Sie sind auf Seite 1von 108

‫ﺟﺎﻣﻌﺔ اﳌﻨﺼﻮرة‬

‫ﻛﻠﻴﺔ اﳍﻨﺪﺳﺔ‬

‫أﺻﻮل ﺑﺮﳎﺔ اﳊﺎﺳﺐ‬


‫‪C‬‬ ‫ﻣﻊ ﺗﻄﺒﻴﻘﺎت ﺑﻠﻐﺔ‬

‫ا‪.‬د‪ / .‬ﳏﻤﺪ ﻧﺒﻴﻞ ﺻﱪى‬


3 ............................................................................. BASIC CONCEPTS‫ ﻣﻔﺎھﯿﻢ أﺳﺎﺳﯿﺔ‬:‫ﻣﻘﺪﻣﺔ‬ 1.
3 .................................................................... WHAT IS A COMPUTER‫ﻣﺎ ھﻮ اﻟﺤﺎﺳﺐ اﻵﻟﻰ‬ .‫أ‬.1
5 ............................................................................ REPRESENTING DATA‫ﺗﻤﺜﯿﻞ اﻟﺒﯿﺎﻧﺎت‬ .‫ب‬.1
9 .................................................................. REPRESENTING OPERATIONS‫ﺗﻤﺜﯿﻞ اﻟﻌﻤﻠﯿﺎت‬ .‫ج‬.1
15 .................................................................... CONSTRUCTING PROGRAMS‫ﺑﻨﺎء اﻟﺒﺮاﻣﺞ‬ .‫د‬.1
15 ...................................................................................... Algorithm‫اﻷﻟﺠﻮرﯾﺘﻢ‬ .1.‫د‬1.
16 ............................................................structured programming ‫اﻟﺒﺮﻣﺠﺔ اﻟﮭﯿﻜﻠﯿﺔ‬ .2.‫د‬1.
18 ......................................................................... Writing programs‫ﻛﺘﺎﺑﺔ اﻟﺒﺮاﻣﺞ‬ .3.‫د‬1.
22 .................................................. BASIC LANGUAGE INSTRUCTIONS‫أواﻣﺮ اﻟﻠﻐﺔ اﻷﺳﺎﺳﯿﺔ‬ 2.
22 ............................................................................................ INTRODUCTION‫ﻣﻘﺪﻣﺔ‬ .‫أ‬.2
22 ........................................BASICS OF PROGRAMMING LANGUAGES‫أﺳﺎﺳﯿﺎت ﻟﻐﺎت اﻟﺒﺮﻣﺠﺔ‬ .‫ب‬.2
22 ................................................................................ Character set:‫اﻟﺤﺮوف‬ .1.‫ب‬.2
23 .......................................................................................... Words:‫اﻟﻜﻠﻤﺎت‬ .2.‫ب‬.2
23 ........................................................................................ Statements‫اﻟﺠﻤﻞ‬ .3.‫ب‬.2
24 ........................................................................................... Blocks‫اﻟﻔﻘﺮات‬ .4.‫ب‬.2
25 ................................................................................... BASICS OF C ‫أﺳﺎﺳﯿﺎت ﻟﻐﺔ ال‬ .‫ج‬.2
25 ................................................................................. Character set‫اﻟﺤﺮوف‬ .1.‫ج‬.2
25 ............................................................................................ Words‫اﻟﻜﻠﻤﺎت‬ .2.‫ج‬.2
26 ......................................................................................... Statements‫اﻟﺠﻤﻞ‬ .3.‫ج‬.2
26 ............................................................................................ Blocks‫اﻟﻔﻘﺮات‬ .4.‫ج‬.2
31 ......................................................................... PROGRAM STATEMENTS ‫أواﻣﺮ اﻟﺒﺮﻣﺠﺔ‬ 3.
31 ................................................... DATA DEFINITION STATEMENTS ‫أواﻣﺮ ﺗﻌﺮﯾﻒ اﻟﺒﯿﺎﻧﺎت‬ .‫أ‬.3
31 .................................................................................. Data types ‫أﻧﻮاع اﻟﺒﯿﺎﻧﺎت‬ .1.‫أ‬3.
32 ........................................................................................... constants ‫اﻟﺜﻮاﺑﺖ‬ .2.‫أ‬3.
33 ........................................................................................ variables ‫اﻟﻤﺘﻐﯿﺮات‬ .3.‫أ‬3.
35 .......................................................................... arrays ‫اﻟﻤﺘﺠﮭﺎت أو اﻟﻤﺼﻔﻮﻓﺎت‬ .4.‫أ‬3.
38 ................................................................................................. string ‫اﻟﺠﻤﻠﺔ‬ .5.‫أ‬3.
41 ................................. ASSIGNEMENT STATEMENT & EXPRESSIONS‫أﻣﺮ اﻹﺳﻨﺎد و اﻟﺘﻌﺒﯿﺮات‬ .‫ب‬.3
41 .......................................................................... General form:‫اﻟﺼﻮرة اﻟﻌﺎﻣﺔ‬ .1.‫ب‬3.
41 ............................................................ Arithmetic operations ‫اﻟﻌﻤﻠﯿﺎت اﻟﺤﺴﺎﺑﯿﺔ‬ .2.‫ب‬3.
46 ................................................................logical operations ‫اﻟﻌﻤﻠﯿﺎت اﻟﻤﻨﻄﻘﯿﺔ‬ .3.‫ب‬.3
47 ................................................... bitwise operations ‫اﻟﻌﻤﻠﯿﺎت ﻋﻠﻰ اﻷرﻗﺎم اﻟﺜﻨﺎﺋﯿﺔ‬ .4.‫ب‬3.
47 ..............................................................................side effects ‫اﻵﺛﺎر اﻟﺠﺎﻧﺒﯿﺔ‬ .5.‫ب‬.3
49 ...................................................................... Other operators‫ﻣﺆﺛﺮات أﺧﺮى‬ .6.‫ب‬.3
49 .................................................................... Precedence rules ‫ﻗﻮاﻋﺪ اﻷوﻟﻮﯾﺔ‬ .7.‫ب‬.3
51 ................................................. INPUT / OUTPUT STATEMENTS ‫أواﻣﺮ اﻹدﺧﺎل و اﻹﺧﺮاج‬ .‫ج‬.3
51 .................................................... formated input/output ‫اﻟﻘﺮاءة و اﻟﻜﺘﺎﺑﺔ اﻟﻤﺸﻜﻠﺔ‬ .1.‫ج‬3.
52 ................................................... format specifier ‫ﻣﻌﺮف أﺳﻠﻮب اﻟﻜﺘﺎﺑﺔ أو اﻟﻘﺮاءة‬ .2.‫ج‬3.
55 ........................... Character input/output statements‫أواﻣﺮ إدﺧﺎل و إﺧﺮاج اﻟﺤﺮوف‬ .3.‫ج‬3.
55 ...................................................................... File handling ‫اﻟﺘﻌﺎﻣﻞ ﻣﻊ اﻟﻤﻠﻔﺎت‬ .4.‫ج‬3.
59 ..................................... PROGRAM CONTROL STATEMENTS ‫أواﻣﺮ اﻟﺘﺤﻜﻢ ﻓﻰ ﺳﯿﺮ اﻟﺒﺮﻧﺎﻣﺞ‬ .‫د‬.3
59 .............................................................................. The if Statement - if ‫اﻷﻣﺮ‬ .1.‫د‬.3
62 .................................................. The switch statement - switch ‫أﻣﺮ اﻟﺘﻔﺮﯾﻊ اﻟﻤﺘﻌﺪد‬ .2.‫د‬3.
64 ..................................................... The while statement - "while ‫اﻓﻌﻞ‬-‫اﻷﻣﺮ "ﺑﯿﻨﻤﺎ‬ .3.‫د‬3.
67 ............................................ The do-while statement -"do-while ‫ﺑﯿﻨﻤﺎ‬-‫اﻷﻣﺮ "اﻓﻌﻞ‬ .4.‫د‬3.
68 ............................................................. The for statement -"for ‫اﻓﻌﻞ‬-‫اﻷﻣﺮ "ﻟﻘﯿﻢ‬ .5.‫د‬3.

1
71 .................................................. ADVANCED DATA STRUCTURES ‫ھﯿﺎﻛﻞ ﺑﯿﺎﻧﺎت ﻣﺘﻘﺪﻣﺔ‬ .4
71 .............................................................................................. POINTERS‫اﻟﻤﺆﺷﺮات‬ .‫أ‬.4
71 .................................................................... DEFINITION OF POINTERS‫ﺗﻌﺮﯾﻒ اﻟﻤﺆﺷﺮ‬ .‫ب‬.4
72 .......................................................Pointers and vectors‫اﻟﻤﺆﺷﺮات و اﻟﻤﺘﺠﮭﺎت‬ .1.‫ب‬.4
74 ....................................................... Pointer operations‫اﻟﻌﻤﻠﯿﺎت ﻋﻠﻰ اﻟﻤﺆﺷﺮات‬ .2.‫ب‬.4
75 ......................................... Dynamic memory allocation ‫اﻟﺤﺠﺰ اﻟﺪﯾﻨﺎﻣﯿﻜﻰ ﻟﻠﺬاﻛﺮة‬ .3.‫ب‬.4
79 ................................................................................SUBPROGRAMS ‫اﻟﺒﺮاﻣﺞ اﻟﺠﺰﺋﯿﺔ‬ .‫ج‬.4
79 ........................................................... procedure and function ‫اﻹﺟﺮاء و اﻟﺪاﻟﺔ‬ .1.‫ج‬.4
80 ................................... Function declaration and definition ‫إﻋﻼن وﺗﻌﺮﯾﻒ اﻟﺪوال‬ .2.‫ج‬.4
82 ..................................................................Function arguments ‫ﻣﺪﺧﻼت اﻟﺪاﻟﺔ‬ .3.‫ج‬.4
87 ......................................................... scope of variables ‫ﻣﺪى ﺗﻌﺮﯾﻒ اﻟﻤﺘﻐﯿﺮات‬ .4.‫ج‬.4
90 ......................................................... recursive functions ‫اﻟﺪوال ذاﺗﯿﺔ اﻻﺳﺘﺪﻋﺎء‬ .5.‫ج‬.4
94 ........ Functions as arguments to other functions ‫ﺗﻤﺮﯾﺮ اﻟﺪوال ﻛﻤﺪﺧﻼت ﻟﺪوال أﺧﺮى‬ .6.‫ج‬.4
98 ............................................................................DATA STRUCTURES ‫ھﯿﺎﻛﻞ اﻟﺒﯿﺎﻧﺎت‬ .‫د‬.4
98 .................................................................... structure definition ‫ﺗﻌﺮﯾﻒ اﻟﮭﯿﻜﻞ‬ .1.‫د‬.4
101 .................................................................................... linked lists ‫اﻟﺴﻼﺳﻞ‬ .2.‫د‬.4
103 ........................................................................................... ‫ﻋﻤﻠﯿﺎت أﺳﺎﺳﯿﺔ‬ .3.‫د‬.4
105 ................................................................................................... ‫ﻣﺴﺎﺋﻞ ﻣﺸﮭﻮرة‬ .‫ه‬.4

2
‫ﻣﻘﺪﻣﺔ‪ :‬ﻣﻔﺎﻫﻴﻢ أﺳﺎﺳﻴﺔ ‪Basic concepts‬‬ ‫‪.1‬‬
‫‪.1‬أ‪ .‬ﻣﺎ ﻫﻮ اﳊﺎﺳﺐ اﻵﱃ ‪What is a computer‬‬
‫اﳊﺎﺳــﺐ اﻵﱃ ﻣــﺎ ﻫــﻮ إﻻ أداة ﻟﻠﺘﻌﺎﻣــﻞ ‪ processing‬اﻷوﺗﻮﻣــﺎﺗﻴﻜﻰ ﻣــﻊ اﳌﻌﻠﻮﻣــﺎت ‪ .information‬ﻛــﺄى آﻟــﺔ‪ ،‬ﺗــﺪﺧﻠﻬﺎ‬
‫ﻣـﻮاد ﺧــﺎم و ﻫــﻰ ﻫﻨــﺎ اﳌﻌﻠﻮﻣــﺎت اﳌﺪﺧﻠــﺔ ‪) input information‬أو اﺧﺘﺼــﺎرا اﳌــﺪﺧﻼت(‪ .‬ﺗﻘــﻮم اﻵﻟــﺔ ﺑﻌﺪﺋــﺬ ﲟﻌﺎﳉــﺔ ﻫــﺬﻩ اﳌــﺎدة‬
‫اﳋﺎم ﻟﺘﻜﻮن ﻣﻨﻬﺎ ﻣﻨﺘﺠﺎ و ﻫﻮ ﻋﺒﺎرة ﻋــﻦ ﻣﻌﻠﻮﻣــﺎت أﺧـﺮى اﳌﻌﻠﻮﻣــﺎت اﳌﺨﺮﺟــﺔ ‪) output information‬أو اﺧﺘﺼــﺎرا اﳌﺨﺮﺟــﺎت(‪.‬‬
‫ﰱ ﻫ ــﺬا اﻟﺼ ــﺪد‪ ،‬ﻳﻨﻔ ــﺮد اﳊﺎﺳ ــﺐ اﻵﱃ ﻋ ــﻦ اﻵﻻت اﻟﻌﺎدﻳ ــﺔ ﲞﺎﺻ ــﻴﺔ ﳑﻴ ــﺰة ﻧﻮﺿ ــﺤﻬﺎ ﻓﻴﻤ ــﺎ ﻳﻠ ــﻰ‪ .‬إن اﻵﻻت اﻟﻌﺎدﻳ ــﺔ ﻏﺎﻟﺒ ــﺎ ﻣ ــﺎ ﺗﻜ ــﻮن‬
‫ﻣﺼﻤﻤﺔ ﻟﺘﻨﻔﻴﺬ ﻧﻮع ﻣﻌﲔ ﻣﻦ اﻟﻌﻤﻠﻴــﺎت أو ﻋﻠــﻰ اﻷﻛﺜــﺮ ﻋــﺪد ﳏــﺪود و ﻣﻌــﺮوف ﺳــﻠﻔﺎ ﻣــﻦ اﻟﻌﻤﻠﻴـﺎت‪ .‬و ﻟﻜــﻦ ﰱ اﳊﺎﺳــﺐ اﻵﱃ ﻓــﺈن‬
‫اﻟﻌﻤﻠﻴــﺔ اﳌﻄﻠــﻮب إﺟﺮاﺋﻬــﺎ ﻋﻠــﻰ اﳌــﺪﺧﻼت ﳝﻜــﻦ أن ﺗﻌــﺮف و ﻳﻌــﺎد ﺗﻌﺮﻳﻔﻬــﺎ ﻛﻤــﺎ ﻧﺸــﺎء‪ .‬ﰱ اﻟﻮاﻗــﻊ ﻓــﺈن اﻟﻌﻤﻠﻴــﺔ اﳌﻄﻠﻮﺑــﺔ ﻫــﻰ ﺟــﺰء ﻣــﻦ‬
‫اﳌﻌﻠﻮﻣــﺎت اﻟــﱴ ﺗــﺪﺧﻞ ﻟﻠﺤﺎﺳــﺐ‪ .‬أى أن اﳌﻌﻠﻮﻣــﺎت اﳌﺪﺧﻠــﺔ ﺗﻨﻘﺴــﻢ إﱃ ﻓﺌﺘــﲔ أﺳﺎﺳــﻴﺘﲔ‪ :‬اﻟﺒﻴــﺎ ت ‪ data‬و اﻟﻌﻤﻠﻴــﺎت أو اﻟـﱪاﻣﺞ‬
‫‪ .programs‬اﻟﺒﻴﺎ ت ﳝﻜﻦ أن ﺗﻜﻮن أرﻗﺎﻣﺎ أو أﲰــﺎء أو أى ﻧــﻮع آﺧــﺮ ﻣــﻦ اﳌﻌﻠﻮﻣــﺎت اﻟــﱴ ﻧﺮﻳــﺪ ﻣﻌﺎﳉﺘﻬــﺎ‪ .‬أﻣــﺎ اﻟـﱪاﻣﺞ ﻓﻤــﺎ ﻫــﻰ إﻻ‬
‫وﺻﻒ ﻟﻠﻌﻤﻠﻴﺎت اﳌﻄﻠﻮب ﺗﻨﻔﻴﺬﻫﺎ ﻋﻠﻰ اﳌﺪﺧﻼت ﻟﻠﺤﺼﻮل ﻋﻠﻰ اﳌﺨﺮﺟﺎت‪.‬‬
‫ﺗ ــﺪﺧﻞ اﳌﻌﻠﻮﻣ ــﺎت ﻟﻠﺤﺎﺳ ــﺐ )أﻧﻈ ــﺮ ﺷ ــﻜﻞ ‪ (1.1‬ﻋ ــﱪ أدوات اﻹدﺧ ــﺎل ‪ input devices‬ﻣﺜ ــﻞ ﻟﻮﺣ ــﺔ اﳌﻔ ــﺎﺗﻴﺢ‬
‫‪ keyboard‬أو ﻋﻀﻮ اﻟﺘﺄﺷﲑ ‪) pointing device‬أى اﻟﻔﺄرة ‪ (mouse‬أو اﻟﻘﻠﻢ اﻟﻀﻮﺋﻰ ‪.light pen‬‬
‫‪primary‬‬ ‫ﲣــﺰن اﳌﻌﻠﻮﻣــﺎت ﰱ ذاﻛــﺮة اﳊﺎﺳــﺐ ‪ memory‬اﻧﺘﻈــﺎرا ﳌﻌﺎﳉﺘﻬــﺎ‪ .‬ﺗﺴ ــﻤﻰ اﻟــﺬاﻛﺮة أﻳﻀــﺎ اﳌﺨــﺰن اﻷوﱃ‬
‫‪ storage‬ﻷﺳــﺒﺎب ﺳﺘﺘﻀــﺢ ﺑﻌــﺪ ﻗﻠﻴــﻞ‪ .‬اﻟــﺬاﻛﺮة ﻣــﺎ ﻫــﻰ إﻻ ﻋــﺪد ﻛﺒــﲑ ﻣــﻦ اﳋــﻼ ‪ cells‬اﳌﱰاﺻــﺔ اﻟﻮاﺣــﺪة ﺑﻌــﺪ اﻷﺧــﺮى ﺑﱰﺗﻴــﺐ ﻣــﺎ‬
‫ﲝﻴــﺚ ﳝﻜــﻦ اﻟﻮﺻــﻮل ﻷﻳــﺔ ﺧﻠﻴــﺔ ﲟﻌﺮﻓــﺔ رﻗﻤﻬــﺎ و ﻫــﻮ ﻣــﺎ ﻳﻌــﺮف ﺑﻌﻨـﻮان اﻟــﺬاﻛﺮة ‪ .memory address‬ﻷﺟــﻞ ﲣـﺰﻳﻦ اﳌﻌﻠﻮﻣــﺎت ﰱ‬
‫ﺧــﻼ اﻟــﺬاﻛﺮة‪ ،‬ﳚــﺐ أن ﺗﺸــﻔﺮ ‪ coded‬ﻫــﺬﻩ اﳌﻌﻠﻮﻣــﺎت‪ ،‬أى أﻧــﻪ ﻳﻌــﱪ ﻋــﻦ أى ﻋﻨﺼــﺮ ﻣــﻦ ﻫــﺬﻩ اﳌﻌﻠﻮﻣــﺎت ﺑﻮاﺳــﻄﺔ رﻗــﻢ ﻛــﻮدى ﺗﺒﻌــﺎ‬
‫ﻷﺳــﻠﻮب ﻣﺘﻔــﻖ ﻋﻠﻴــﻪ‪ .‬و ﺑــﺬﻟﻚ ﳝﻜــﻦ ﲢﻮﻳــﻞ أﻳــﺔ ﻣﻌﻠﻮﻣــﺔ ﺳـﻮاء ﻛﺎﻧــﺖ رﻗﻤــﺎ أو اﲰــﺎ ‪...‬اﱁ‪ ،‬إﱃ أرﻗــﺎم ﻛﻮدﻳــﺔ ﲣــﺰن ﰱ ﺧــﻼ اﻟــﺬاﻛﺮة‪.‬‬
‫ﺳﻨﺸــﺮح ﺗﻠــﻚ اﻟﻌﻤﻠﻴــﺔ ﺑﺸــﻰء ﻣــﻦ اﻟﺘﻔﺼــﻴﻞ ﰱ اﻟﻔﻘــﺮة ‪.1‬ب‪ .‬ﺣــﱴ اﻟـﱪاﻣﺞ ﳝﻜــﻦ أن ﻳــﺘﻢ ﲢﻠﻴﻠﻬــﺎ ﻟﻌﻤﻠﻴــﺎت أوﻟﻴــﺔ و ﻳﺮﻣــﺰ ﻟﻜــﻞ ﻋﻤﻠﻴــﺔ‬
‫أوﻟﻴــﺔ ﺑــﺮﻗﻢ ﻛــﻮدى و ﺑــﺬﻟﻚ ﲣــﺰن أﻳﻀــﺎ ﺟﻨﺒــﺎ إﱃ ﺟﻨــﺐ ﻣــﻊ اﻟﺒﻴــﺎ ت ﰱ ﺧــﻼ اﻟــﺬاﻛﺮة‪ ،‬ﻛﻤــﺎ ﺳــﻨﺮى ﰱ اﻟﻔﻘــﺮة ‪.1‬ج‪ .‬اﻟﺘﻌﺎﻣــﻞ ﻣــﻊ‬
‫اﳌﻌﻠﻮﻣــﺎت ﻳــﺘﻢ ﰱ اﻟﻮﺣــﺪة اﳊﺴــﺎﺑﻴﺔ و اﳌﻨﻄﻘﻴــﺔ )‪ Arithmetic and Logical Unit (ALU‬و اﻟــﱴ ﳝﻜــﻦ ﳍــﺎ أن ﺗﻘــﻮم‬
‫ﻟﻌﻤﻠﻴﺎت اﻷوﻟﻴﺔ ﻣﻦ ﲨﻊ أو ﻃﺮح أو ﺿﺮب أو ﻗﺴــﻤﺔ أو ﻣﻘﺎرﻧــﺔ ﺑــﲔ ﻛﻤﻴــﺎت ﳐﺘﻠﻔــﺔ ﳌﻌﺮﻓــﺔ أﻳﻬﻤــﺎ أﻛــﱪ‪ .‬إن ﲨﻴــﻊ اﻟﻌﻤﻠﻴــﺎت اﳌﻌﻘــﺪة‬
‫ﻟﻠﺘﻌﺎﻣﻞ ﻣﻊ اﳌﻌﻠﻮﻣﺎت ﻣﻦ ﺣﺴﺎب ﻣﺴﺎرات اﻷﺟﺮام اﻟﺴــﻤﺎوﻳﺔ إﱃ ﻣﺮاﺟﻌــﺔ ﺻــﺤﺔ اﻟﻘﻮاﻋــﺪ اﻟﻨﺤﻮﻳــﺔ ﰱ ﻧــﺺ ﳝﻜــﻦ ﲢﻠﻴﻠﻬــﺎ ﻟﻌــﺪد )ﻛــﱪ‬
‫أو ﺻﻐﺮ( ﻣﻦ اﻟﻌﻤﻠﻴﺎت اﻷوﻟﻴــﺔ اﻟﺒﺴــﻴﻄﺔ اﳌــﺬﻛﻮرة أﻋــﻼﻩ‪ .‬أن ذﻟــﻚ ﻳــﺬﻛﺮ ﻟﺘﻨــﻮع اﳍﺎﺋــﻞ ﻟﻠﻤﺮﻛﺒــﺎت اﻟﻜﻴﻤﺎوﻳــﺔ و اﻟــﱴ ﰱ اﻟﻨﻬﺎﻳــﺔ ﳝﻜــﻦ‬
‫أن ﲢﻠــﻞ ﻟﻌــﺪد ﳏــﺪود ﺟــﺪا ﻣــﻦ اﻟﻌﻨﺎﺻــﺮ و اﻟــﱴ ﺑــﺪورﻫﺎ ﳝﻜــﻦ ﲢﻠﻴــﻞ ذرا ــﺎ ﻟﻌــﺪد ﳏــﺪود ﺟــﺪا ﻣــﻦ اﳉﺴــﻴﻤﺎت اﻷوﻟﻴــﺔ )اﻟﱪوﺗــﻮن و‬
‫اﻟﻨﻴﻮﺗﺮون و اﻹﻟﻜﱰون(‪ .‬ﺳﻨﺘﻌﺮض ﺳﺮﻳﻌﺎ ﳌﺴﺄﻟﺔ ﲢﻠﻴﻞ اﻟﻌﻤﻠﻴﺎت ﻟﻌﻨﺎﺻﺮﻫﺎ اﻷوﱃ ﰱ اﻟﻔﻘﺮة ‪.1‬ء‪.‬‬

‫‪3‬‬
‫ﺣﺪﯾﺪ ﺧﺎم‬ ‫ﻣﻜﺒﺲ‬ ‫ﺣﺪﯾﺪ ﻣﺼﻨﻊ‬

‫‪Computer‬‬ ‫ﻣﺨﺰن ﺛﺎﻧﻮى‬


‫‪System‬‬

‫ذاﻛﺮة‬ ‫ﻣﻌﻠﻮﻣﺎت‬
‫ﻣﻌﻠﻮﻣﺎت‬ ‫‪1 2‬‬ ‫‪3‬‬ ‫‪4‬‬ ‫ﻣﻌﺎﻟﺠﺔ‬
‫ﺧﺎم‬
‫‪5‬‬ ‫‪6‬‬ ‫‪7‬‬ ‫‪8‬‬

‫ﺑﯿﺎﻧﺎت‬
‫‪+‬‬
‫ﻋﻤﻠﯿﺎت‬

‫وﺳﺎﺋﻞ‬
‫إدﺧﺎل‬
‫‪ALU‬‬ ‫‪CCU‬‬ ‫وﺳﺎﺋﻞ‬
‫*‪+-‬‬ ‫إﺧﺮاج‬
‫وﺣﺪة‬
‫ﻣﻌﺎﻟﺠﺔ‬
‫ﻣﺮﻛﺰﯾﺔ‬ ‫‪Registers‬‬
‫‪CPU‬‬

‫ﺷﻜﻞ ‪ – 1.1‬اﳊﺎﺳﺐ اﻵﱃ ﻛﻮﺳﻴﻠﺔ ﻟﻠﺘﻌﺎﻣﻞ اﻷوﺗﻮﻣﺎﺗﻴﻜﻰ ﻣﻊ اﻟﺒﻴﺎ ت‬


‫ﺑﻌﺪ ﻣﻌﺎﳉﺔ اﻟﺒﻴﺎ ت ﻓﺈ ﺎ ﺗﺴﺮى ﺧﺎرج اﳊﺎﺳﺐ اﻵﱃ ﻋﱪ أدوات اﻹﺧﺮاج ‪ output devices‬ﻣﺜــﻞ اﻟﺸﺎﺷــﺔ ‪ screen‬أو‬
‫اﻟﻄﺎﺑﻌﺔ ‪.printer‬‬
‫ﻧﻈ ـﺮا ﻻﻋﺘﺒــﺎرات ﺗﻜﻨﻮﻟﻮﺟﻴــﺔ ﳏﻀــﺔ‪ ،‬ﻓــﺈن اﳌﺨــﺰن اﻟــﺬى ﳓــﺘﻔﻆ ﻓﻴــﻪ ﳌﻌﻠﻮﻣــﺎت ﳝﻜــﻦ أن ﻳﺼــﻨﻊ ﲝﻴــﺚ ﳛﻘــﻖ أﺣــﺪ ﺷــﺮﻃﲔ‬
‫ﺑﺪون اﳉﻤﻊ ﺑﻴﻨﻬﻤــﺎ‪ .‬إﻣــﺎ أن ﻳﻜــﻮن ﺳـﺮﻳﻊ ﰱ ﻧﻘــﻞ اﳌﻌﻠﻮﻣــﺎت ﻣﻨــﻪ و إﻟﻴــﻪ )و ﻫــﻮ ﻣــﺎ ﻧﺴــﺘﺨﺪﻣﻪ ﰱ اﳌﺨــﺰن اﻷوﱃ أو اﻟــﺬاﻛﺮة(‪ .‬وإﻣــﺎ أن‬
‫ﻳﻜﻮن ﻗﺎدرا ﻋﻠﻰ ﺣﻔﻆ ﻛﻤﻴــﺔ ﻛﺒــﲑة ﻣــﻦ اﳌﻌﻠﻮﻣــﺎت وذﻟــﻚ ﺣــﱴ ﺑﻌــﺪ ﻗﻄــﻊ اﻟﺘﻴــﺎر اﻟﻜﻬــﺮﰉ‪ .‬ﻳﺴــﺘﺨﺪم اﻟﻨــﻮع اﻟﺜــﺎﱏ ﻓﻴﻤــﺎ ﻳﺴــﻤﻰ ﳌﺨــﺰن‬
‫اﻟﺜــﺎﻧﻮى ‪ secondary storage‬ﻷﺟــﻞ اﶈﺎﻓﻈــﺔ ﻋﻠــﻰ اﳌﻌﻠﻮﻣــﺎت ﺑﻌــﺪ ﻏﻠــﻖ اﳉﻬــﺎز‪ ،‬ﺑﻐــﺮض ﻣﻌﺎﳉﺘﻬــﺎ ﺑﺼــﻮرة أﺧــﺮى ﰱ ﻣـﺮات ﻻﺣﻘــﺔ‬
‫ﻣﺜﻼ‪ .‬و ﻟﺬﻟﻚ ﻓﺈﻧﻨﺎ ﻧﻠﺠﺄ داﺋﻤﺎ ﻟﻮﺿﻊ اﳌﻌﻠﻮﻣﺎت اﻟﱴ ﻧﺘﻌﺎﻣﻞ ﻣﻌﻬﺎ ﳊﻈﻴﺎ ﰱ اﳌﺨﺰن اﻷوﱃ ﰒ ﺑﻌﺪ ذﻟــﻚ ﳓــﺘﻔﻆ ﲟــﺎ ﻧﺮﻳــﺪ ﺣﻔﻈــﻪ ﺳـﻮاء‬
‫ﻛﺎن ﻣﺪﺧﻼت أو ﳐﺮﺟﺎت ﰱ اﳌﺨﺰن اﻟﺜﺎﻧﻮى‪ .‬ﻳﺘﻜﻮن اﳌﺨﺰن اﻟﺜﺎﻧﻮى ﻣﻦ اﻟﺸﺮاﺋﻂ اﳌﻤﻐﻨﻄﺔ ‪ magnetic tapes‬أو اﻷﻗـﺮاص اﳌﺮﻧــﺔ‬
‫‪ floppy disk‬أو اﻷﻗﺮاص ﻏﲑ اﳌﺮﻧﺔ ‪.Hard disk‬‬
‫ﰱ اﻟﻨﻬﺎﻳــﺔ ﳚــﺐ اﻟــﺘﺤﻜﻢ ﰱ ﻛــﻞ ﻫــﺬﻩ اﳌﻌــﺪات ﻟﻜــﻰ ﺗــﺆدى اﳌﻬــﺎم اﳌﻮﻛﻠــﺔ إﻟﻴﻬــﺎ و ﻳــﺘﻢ ذﻟــﻚ ﺑﻮاﺳــﻄﺔ وﺣــﺪة اﻟــﺘﺤﻜﻢ اﳌﺮﻛﺰﻳــﺔ‬
‫‪ .Central Control Unit CCU.‬ﺗﻘــﻮم وﺣــﺪة اﻟــﺘﺤﻜﻢ ﺻــﺪار اﻷواﻣــﺮ ﻟﻠﻤﻌــﺪات اﳌﺨﺘﻠﻔــﺔ )وﺣــﺪات اﻹدﺧــﺎل و اﻹﺧـﺮاج‪،‬‬

‫‪4‬‬
‫اﻟﻮﺣﺪة اﳊﺴﺎﺑﻴﺔ‪ ،‬اﳌﺨﺰن اﻟﺜﺎﻧﻮى‪ ،‬اﱁ( ﻟﻠﻘﻴﺎم ﲟﻬﺎﻣﻬﺎ و ﻣﺘﺎﺑﻌﺔ اﻟﺘﻨﻔﻴــﺬ‪ .‬ﺗﺘﻠﻘــﻰ وﺣــﺪة اﻟــﺘﺤﻜﻢ اﳌﺮﻛﺰﻳــﺔ اﻟﺘﻌﻠﻴﻤــﺎت ﻣﻨــﺎ ﺑﻮاﺳــﻄﺔ ﺑــﺮ ﻣﺞ‬
‫ﺧــﺎص ﻳﺴـﻤﻰ ﻧﻈــﺎم اﻟﺘﺸــﻐﻴﻞ ‪ .operating system.‬ﻳﻘــﻮم ﻧﻈــﺎم اﻟﺘﺸــﻐﻴﻞ ﻟﺘﻌــﺮف ﻋﻠــﻰ اﻷواﻣــﺮ اﻟﺼــﺎدرة ﻣــﻦ اﻟﺒﺸــﺮ )ﺳـﻮاء ﻣــﻦ‬
‫ﺧــﻼل ﻟﻮﺣــﺔ اﳌﻔــﺎﺗﻴﺢ أو ﻋﻀــﻮ اﻟﺘﺄﺷــﲑ( و ﺗﺮﲨﺘﻬــﺎ ﻷواﻣــﺮ ﺗﺴــﺘﻄﻴﻊ وﺣــﺪة اﻟــﺘﺤﻜﻢ اﳌﺮﻛﺰﻳــﺔ أن ﺗﺼــﺪرﻫﺎ و ﺗﺘــﺎﺑﻊ ﺗﻨﻔﻴــﺬﻫﺎ‪ .‬ﻣــﻦ أﻣﺜﻠــﺔ‬
‫أﻧﻈﻤﺔ اﻟﺘﺸﻐﻴﻞ…‪.DOS, UNIX, Windows, ...‬‬
‫اﺠﻤﻟﻤﻮﻋــﺔ اﳌﻜﻮﻧــﺔ ﻣــﻦ اﻟﻮﺣــﺪة اﳊﺴــﺎﺑﻴﺔ و اﳌﻨﻄﻘﻴــﺔ ‪ ALU‬و وﺣــﺪة اﻟــﺘﺤﻜﻢ اﳌﺮﻛﺰﻳــﺔ ‪ CCU‬ﻹﺿــﺎﻓﺔ ﻟــﺒﻌﺾ اﻟﺴــﺠﻼت‬
‫‪ registers‬ﺗﺴﻤﻰ وﺣﺪة اﳌﻌﺎﳉﺔ اﳌﺮﻛﺰﻳﺔ ‪ .Central Processing Unit CPU‬إن ﺳــﺮﻋﺔ ﻧﻘــﻞ اﳌﻌﻠﻮﻣــﺎت ﰱ اﻟﺴــﺠﻼت ﺗﻜــﻮن‬
‫ﻣــﻦ أﻋﻠــﻰ ﻣــﺎ ﳝﻜــﻦ‪ ،‬و ﺗﺴــﺘﺨﺪﻣﻬﺎ وﺣــﺪة اﳌﻌﺎﳉــﺔ اﳌﺮﻛﺰﻳ ـﺔ أﺳﺎﺳــﺎ ﻟﻠﻤﺴــﺎﻋﺪة ﰱ أداء ﻣﻬﻤﺘﻬــﺎ‪ .‬ﺑﻌــﺾ ﻫــﺬﻩ اﻟﺴــﺠﻼت ﻳﺴــﺘﺨﺪم ﰱ‬
‫ﻣﺘﺎﺑﻌــﺔ ﺗﻨﻔﻴــﺬ اﻟـﱪاﻣﺞ ﻣﺜــﻞ ﺳــﺠﻞ اﻷﻣــﺮ ‪ instruction register‬و ﻓﻴــﻪ ﳛــﺘﻔﻆ ﻷﻣــﺮ اﳉــﺎرى ﺗﻨﻔﻴــﺬﻩ و ﺳــﺠﻞ ﻋﻨ ـﻮان اﻷﻣــﺮ‬
‫‪ instruction address register‬و ﻓﻴﻪ ﳛﺘﻔﻆ ﺑﻌﻨﻮان اﻷﻣﺮ اﻟﺬى ﺳﻴﻨﻔﺬ ﺑﻌﺪ اﻷﻣﺮ اﳊﺎﱃ‪ .‬و ﻫﻨــﺎك ﺳــﺠﻼت أﺧــﺮى ﺗﺴــﺘﺨﺪم‬
‫ﰱ اﻟﻘﻴﺎم ﻟﻌﻤﻠﻴﺎت اﳊﺴﺎﺑﻴﺔ و اﳌﻨﻄﻘﻴﺔ ﻣﺜﻞ اﳌﺮﻛﻢ ‪.accumulator‬‬

‫‪.1‬ب‪ .‬ﲤﺜﻴﻞ اﻟﺒﻴﺎ ت ‪Representing data‬‬


‫ﻫﻨــﺎك أﻧـﻮاع ﻛﺜــﲑة ﻣــﻦ اﻟﺒﻴــﺎ ت و ﻟﻜــﻞ ﻧــﻮع أﺳــﻠﻮب ﻣﻨﺎﺳــﺐ ﻟﺘﻤﺜﻴﻠــﻪ ﲤﻬﻴــﺪا ﻟﺘﺨﺰﻳﻨــﻪ ﰱ اﳊﺎﺳــﺐ‪ .‬أوﻻ ﳝﻜــﻦ ﻟﻠﺒﻴــﺎ ت أن‬
‫ﺗﻜــﻮن ﺑﺴــﻴﻄﺔ ‪ simple‬أو ﻣﻬﻴﻜﻠــﺔ ‪) structured‬أﻧﻈــﺮ ﺷــﻜﻞ ‪ .(2.1‬اﻟﺒﻴــﺎ ت اﻟﺒﺴــﻴﻄﺔ ﲢــﻮى ﻣﻌﻠﻮﻣــﺔ واﺣــﺪة أوﻟﻴــﺔ ﻣﺜــﻞ رﻗــﻢ أو‬
‫ﺣﺮف‪ ..،‬اﱁ‪ .‬أﻣﺎ اﳌﻌﻠﻮﻣﺔ اﳌﻬﻴﻜﻠــﺔ ﻓﻬــﻰ ﺗﺘﻜــﻮن ﻣــﻦ ﻋــﺪد ﻣــﻦ اﳌﻌﻠﻮﻣــﺎت اﻟﺒﺴــﻴﻄﺔ اﳌﺮﺗﺒﻄــﺔ ﺑﺒﻌﻀــﻬﺎ اﻟــﺒﻌﺾ ﺑــﺮ ط ﻣﻨﻄﻘــﻰ ﻣــﺎ ﻟﺘﻜــﻮن‬
‫ﻛﻴــﺎ ‪ entity‬واﺣــﺪا‪ .‬ﻣﺜــﺎل ذﻟــﻚ اﳌﺘﺠﻬــﺎت اﳌﻜﻮﻧــﺔ ﻣــﻦ ‪ n‬ﻋﻨﺼــﺮ‪ ،‬أو ﺳــﺠﻞ ﻣﻮﻇــﻒ ﳛــﻮى اﲰــﻪ و ﺳــﻨﻪ و وﻇﻴﻔﺘــﻪ و ﻣﺮﺗﺒــﻪ‪..‬اﱁ‪.‬‬
‫ﺳﻨﺒﺪأ ﺳﺘﻌﺮاض اﻟﺒﻴﺎ ت اﻟﺒﺴﻴﻄﺔ ﻓﻴﻤﺎ ﻳﻠﻰ رﻛﲔ اﻟﺒﻴﺎ ت اﳌﺮﻛﺒﺔ ﳌﺮﺣﻠﺔ ﻻﺣﻘﺔ‪.‬‬
‫ﺻﺤﯿﺤﺔ‬
‫‪Numerical‬ﻋﺪدﯾﺔ‬ ‫‪Integer‬‬
‫ﺑﺴﯿﻄﺔ‬
‫‪Simple‬‬ ‫‪Character‬ﺣﺮﻓﯿﺔ‬ ‫ﺣﻘﯿﻘﯿﺔ‬
‫‪Real‬‬
‫‪Logical‬ﻣﻨﻄﻘﯿﺔ‬
‫أﻧﻮاع‬
‫اﻟﺒﯿﺎﻧﺎت‬
‫‪Pointer‬ﻣﺆﺷﺮ‬
‫‪Data‬‬
‫‪Types‬‬
‫‪String‬ﺟﻤﻠﺔ‬

‫ﻣﮭﯿﻜﻠﺔ‬ ‫‪Array‬ﻣﺼﻔﻮﻓﺔ‬
‫‪Struc-‬‬
‫‪tured‬‬ ‫ھﯿﻜﻞ‪ ،‬اﺗﺤﺎد‬
‫‪Structure, Union‬‬

‫‪File‬ﻣﻠﻒ‬

‫ﺷﻜﻞ ‪ – 2.1‬أﻧﻮاع اﻟﺒﻴﺎ ت ‪Data Types‬‬


‫اﻟﺒﻴــﺎ ت اﻟﺒﺴــﻴﻄﺔ ﺗﺘﻜــﻮن ﻣــﻦ اﻷﻋــﺪاد ‪ ،numerical data‬ﺻــﺤﻴﺤﺔ ‪ integer‬ﻛﺎﻧــﺖ أم ﺣﻘﻴﻘﻴــﺔ ‪ ،real‬أو اﳊــﺮوف‬
‫‪ character data‬أو اﻟﺒﻴﺎ ت اﳌﻨﻄﻘﻴﺔ ‪ .logical data‬ﺳﻨﺘﻨﺎول ﺑﻘﻠﻴﻞ ﻣﻦ اﻟﺘﻔﺼﻴﻞ أﺳﻠﻮب ﲤﺜﻴﻞ ﻛﻞ ﻧﻮع ﻣﻦ ﻫﺬﻩ اﻟﺒﻴﺎ ت‪.‬‬

‫‪5‬‬
‫اﻷﻋــﺪاد اﻟﺼــﺤﻴﺤﺔ ‪ integer numbers‬ﲤﺜــﻞ ﰱ ﺻــﻮرة ﻋــﺪد ﺛﻨــﺎﺋﻰ ‪ .binary number‬اﻟﻌــﺪد اﻟﺜﻨــﺎﺋﻰ ﻫــﻮ ﻋــﺪد‬
‫ﻣﻜﺘــﻮب اﺳــﺘﻨﺎدا ﻟﻸﺳــﺎس ‪ ،2‬ﺑﻌﻜــﺲ اﻟﻌــﺪد اﻟﻌﺸــﺮى اﻟــﺬى ﺗﻌــﻮد ﻋﻠﻴــﻪ اﻟﺒﺸــﺮ و اﳌﺒــﲎ ﻟﻸﺳــﺎس ‪ .10‬ﻓﺎﻟﻌــﺪد اﻟﻌﺸــﺮى ‪ 7041‬و‬
‫اﳌﻜﻮن ﻣﻦ ‪ 4‬أرﻗﺎم ﻋﺸﺮﻳﺔ ‪ decimal digits‬ﻣﻌﻨﺎﻩ‪:‬‬
‫‪7*103 + 0*102 + 4*101 + 1*100‬‬
‫أى أن ﻛــﻞ رﻗــﻢ ﻳﻈﻬــﺮ ﰱ اﻟﻌــﺪد ﻳﻌﺘــﱪ ﻣﻌــﺎﻣﻼ ﻟﻸﺳــﺎس )‪ 10‬ﰱ اﳌﺜــﺎل اﻟﺴــﺎﺑﻖ( ﻣﺮﻓﻮﻋــﺎ ﻷس ﻣﺘﺰاﻳــﺪ ﻣــﻦ اﻟﻴﻤــﲔ إﱃ اﻟﻴﺴــﺎر ﺑــﺪءا ﻣــﻦ‬
‫اﻷس ﺻــﻔﺮ إﱃ أﻋﻠــﻰ أس‪ .‬و ﻋﻠــﻰ ﻧﻔــﺲ اﳌﻨـﻮال ﻓــﺈن اﻟﻌــﺪد اﻟﺜﻨــﺎﺋﻰ ‪ 1011‬و اﳌﻜــﻮن ﻣــﻦ ‪ 4‬أرﻗــﺎم ﺛﻨﺎﺋﻴــﺔ ‪ binary digits‬ﻣﻌﻨــﺎﻩ‪:‬‬
‫‪1*23 + 0*22 + 1*21 + 1*20‬‬
‫)و ﻫﻮ ﻳﺴﺎوى ‪ 11‬ﺳﺘﺨﺪام اﻷﻋﺪاد اﻟﻌﺸﺮﻳﺔ(‪ .‬ﻟﺘﺠﻨﺐ اﻟﻠﺒﺲ ﰱ ﻓﻬﻢ ﻣﻌﲎ اﻟﻌــﺪد اﳌﻜﺘــﻮب‪ ،‬ﻧﻜﺘــﺐ أﺣﻴــﺎ اﻷﺳــﺎس اﺳــﻔﻞ اﻟــﺮﻗﻢ‬
‫‪(1011)2 = (11)10‬‬ ‫ﻣﺜﺎل ذﻟﻚ‪:‬‬
‫اﻷرﻗــﺎم اﻟﻌﺸـﺮﻳﺔ ﺗـﱰاوح ﻗﻴﻤﺘﻬــﺎ ﺑــﲔ ‪ 0‬و ‪ .9‬و ﻟــﻨﻔﺲ اﻟﺴــﺒﺐ ﻓــﺈن اﻷرﻗــﺎم اﻟﺜﻨﺎﺋﻴــﺔ ‪ binary digits‬ﳝﻜــﻦ أن ﺧــﺬ أﺣــﺪ‬
‫اﻟﻘﻴﻤﺘﲔ ‪ 0‬أو ‪ 1‬ﻓﻘﻂ‪ .‬و ﻟﺬﻟﻚ ﻓﺈن اﻷﻋﺪاد اﻟﺜﻨﺎﺋﻴﺔ ﺗﻨﺎﺳﺐ اﳊﺎﺳﺐ اﻵﱃ ﻟﺴﻬﻮﻟﺔ ﲤﺜﻴﻠﻬﺎ‪ .‬ﻓﻜﻞ رﻗــﻢ ﳝﻜــﻦ ﲤﺜﻴﻠــﻪ ﺑــﺪاﺋﺮة ﻛﻬﺮﺑﻴــﺔ ﳍــﺎ‬
‫أﺣﺪ ﺣﺎﻟﺘﲔ ﻻ ﻟﺚ ﳍﻤﺎ‪ :‬اﳊﺎﻟــﺔ ‪ 1‬و ﲤﺜــﻞ ﻣــﺜﻼ ﺑــﺪاﺋﺮة ﻣﻐﻠﻘــﺔ أو داﺋــﺮة ﺟﻬــﺪﻫﺎ ﻣﻮﺟــﺐ‪..‬اﱁ‪ ،‬و اﳊﺎﻟــﺔ ‪ 0‬و ﲤﺜــﻞ ﺑــﺪاﺋﺮة ﻣﻔﺘﻮﺣــﺔ أو‬
‫داﺋــﺮة ﺟﻬــﺪﻫﺎ ﺳــﺎﻟﺐ ‪..‬اﱁ‪ .‬اﻟــﺮﻗﻢ اﻟﺜﻨــﺎﺋﻰ اﳌﻔــﺮد ﻳﺴــﻤﻰ اﺧﺘﺼــﺎرا ‪ BiT‬و ﻫــﻰ ﻛﻠﻤــﺔ ﻣــﺄﺧﻮذة ﻣــﻦ ﺑﺪاﻳــﺔ و ﺎﻳــﺔ اﻟﻜﻠﻤﺘــﲔ ‪Binary‬‬
‫‪) digiT‬اﻟﻜﻠﻤﺔ ‪ bit‬ﰱ اﻟﻠﻐﺔ اﻹﳒﻠﻴﺰﻳﺔ ﺗﻌﲎ ﰱ اﻷﺻﻞ اﻟﺸــﻰء اﻟﻘﻠﻴــﻞ(‪ .‬ﺳــﻨﻜﺘﺐ اﻟﺮﻣــﺰ اﳌﻨــﺎﻇﺮ ﰱ اﻟﻠﻐــﺔ اﻟﻌﺮﺑﻴــﺔ‪ :‬ﺑﻴــﺖ‪ .‬ﻋــﺎدة ﻣــﺎ ﻳــﺘﻢ‬
‫ﲡﻤﻴﻊ ‪ 8‬ﺑﻴﺖ ﺳﻮ ﰱ وﺣﺪة واﺣــﺪة ﺗﺴــﻤﻰ ﻳــﺖ ‪) byte‬ﺷــﻜﻞ ‪ .(3.1‬وﻫــﻰ ﺗﻌــﲎ ﰱ اﻷﺻــﻞ اﻟﻘﻀــﻤﺔ! ﺣﻴــﺚ أن اﳊﺎﺳــﺐ ﻛــﺎن‬
‫ﻋــﺎدة ﻣــﺎ " ﻛــﻞ" اﳌﻌﻠﻮﻣــﺎت ﲟﻌــﺪل ‪ 8‬ﺑﻴــﺖ ﰱ اﳌــﺮة‪ .‬و اﻵن ﻓــﺈن اﳌﻌــﺪﻻت ﺗﻀــﺎﻋﻔﺖ إﱃ ‪ 16‬ﰒ ‪ 32‬ﰒ ‪ 64‬و ﻟﻜــﻦ ﻇﻠــﺖ ﻛﻠﻤــﺔ‬
‫ﻳﺖ ﺗﻌﲎ ‪ 8‬ﺑﻴﺖ‪.‬‬
‫ﺗﺒﻌﺎ ﳌﺪى ﺗﻐﲑ اﻟﻌﺪد اﻟﺼﺤﻴﺢ اﻟﺬى ﻧﺴﻌﻰ ﻟﺘﻤﺜﻴﻠﻪ‪ ،‬ﻓﺈﻧﻨﺎ ﻗﺪ ﳓﺘﺎج إﱃ ‪ 1‬أو ‪ 2‬أو ‪ 4‬ﻳﺖ أو أﻛﺜــﺮ‪ .‬ﻻﺣــﻆ أﻧﻨــﺎ ﳓﺘــﺎج‬
‫ﳊﺠﺰ ﻣﻜﺎن ﰱ اﻟﺬاﻛﺮة )اﳋﻠﻴــﺔ رﻗــﻢ ﻛــﺬا إﱃ رﻗــﻢ ﻛــﺬا( ﻟﺘﺨـﺰﻳﻦ اﻟﻌــﺪد اﳌﻄﻠــﻮب ﻗﺒــﻞ أن ﻧﻌــﺮف ﻗﻴﻤﺘــﻪ‪ .‬و ﻟﻜﻨﻨــﺎ ﳚــﺐ أن ﻧﻌــﺮف اﳌــﺪى‬
‫اﳌﺴﻤﻮح ﻟﺘﻐﲑ اﻟﻌﺪد اﻟﺼﺤﻴﺢ اﳌﻄﻠــﻮب ﲣﺰﻳﻨــﻪ ﻗﺒــﻞ أن ﻧﺘﻌﺎﻣــﻞ ﻣﻌــﻪ ﻟﻜــﻰ ﳝﻜــﻦ أن ﳓﺠــﺰ اﳌﻜــﺎن اﳌﻨﺎﺳــﺐ‪ .‬ﻓﻤــﺜﻼ إذا ﻋﺮﻓﻨــﺎ أن اﻟﻌــﺪد‬
‫اﳌﻄﻠﻮب ﲣﺰﻳﻨﻪ داﺋﻤﺎ ﻣﻮﺟﺐ و ﻻ ﺗﺘﻌﺪى ﻗﻴﻤﺘﻪ ‪ ،255‬ﻓﺈﻧﻨﺎ ﳝﻜﻦ أن ﳔﺰﻧﻪ ﰱ ﻳﺖ واﺣﺪ‪ ،‬ﺣﻴﺚ أن أﻗﻞ ﻗﻴﻤﺔ ﻟﻠﺒﺎﻳــﺖ ﻫــﻰ ﻋﻨــﺪﻣﺎ‬
‫ﺗﻜﻮن ﻛﻞ ﺑﻴﺖ ﺗﺴﺎوى ﺻﻔﺮا و أﻛﱪ ﻗﻴﻤﺔ ﻫﻰ ﻋﻨﺪﻣﺎ ﺗﻜﻮن ﻛﻞ ﺑﻴﺖ ﺗﺴﺎوى ‪:1‬‬
‫‪(11111111)2 = (255)10‬‬
‫‪8 bits = 1 byte‬‬

‫‪bits‬‬

‫‪Byte no. 1‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪1‬‬
‫‪Byte no. 2‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪1‬‬
‫‪Byte no. 3‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪1‬‬
‫ﺷﻜﻞ ‪ – 3.1‬ﺧﻼ اﻟﺬاﻛﺮة‬
‫أﻣــﺎ إذا ﻋﻠﻤﻨــﺎ أن اﻟﻌــﺪد اﳌﻄﻠــﻮب ﲤﺜﻴﻠــﻪ ﳝﻜــﻦ أن ﺗﻜــﻮن ﻗﻴﻤﺘــﻪ ﺳــﺎﻟﺒﺔ ﲝﻴــﺚ ﻳـﱰاوح داﺋﻤــﺎ ﺑــﲔ اﻟﻘﻴﻤﺘــﲔ ‪ -128‬و‪ +127‬ﻓﺈﻧﻨــﺎ ﳝﻜــﻦ‬
‫أﻳﻀــﺎ أن ﳕﺜﻠــﻪ ﺑﺒﺎﻳــﺖ واﺣــﺪ وﻟﻜــﻦ ﺳــﺘﺨﺪام أﺳــﻠﻮب ﳐﺘﻠــﻒ‪ .‬ﻳﺴــﺘﺨﺪم اﻟﺒﻴــﺖ اﻷول ﻟﺘﻤﺜﻴــﻞ اﻹﺷــﺎرة )‪ 0‬ﺗﻌــﲎ ﻣﻮﺟــﺐ و ‪ 1‬ﺗﻌــﲎ‬

‫‪6‬‬
‫ﺳﺎﻟﺐ( أﻣﺎ ﻗﻰ ال‪ 7‬ﺑﻴﺖ ﻓﻴﻤﻜﻦ أن ﺗﱰاوح ﻗﻴﻤﻬﻢ ﺑﲔ ‪) 0‬ﻛﻞ ﺑﻴﺖ ﻋﻠﻰ ﺣــﺪى ﺗﺴــﺎوى ‪ (0‬إﱃ ‪) 127‬ﻛــﻞ ﺑﻴــﺖ ﺗﺴــﺎوى ‪.(1‬‬
‫و ﳌﺜــﻞ ﻓــﺈن اﺳــﺘﺨﺪام ‪ 2‬ﻳــﺖ ﻣﺘﺘــﺎﻟﻴﲔ ﳝﻜﻨﻨــﺎ ﻣــﻦ ﲣ ـﺰﻳﻦ ﻋــﺪد ﺻــﺤﻴﺢ ﻳ ـﱰاوح ﺑــﲔ ‪ 0‬إﱃ ‪ 65535‬إذا ﻛــﺎن داﺋﻤــﺎ ﻣﻮﺟــﺐ أو‬
‫اﳌﺪى ‪ –32768‬إﱃ‪ +32767‬إذا ﻛﺎن ﻳﻘﺒﻞ اﻟﻘﻴﻢ اﳌﻮﺟﺒﺔ أو اﻟﺴــﺎﻟﺒﺔ‪ .‬ﺑــﺪأت ﺗﺘﻀــﺢ ﻟﻨــﺎ اﻵن ﺿــﺮورة ﻣﻌﺮﻓــﺔ ﻧــﻮع اﳌﻌﻠﻮﻣــﺔ اﻟــﱴ ﳚــﺐ‬
‫ﲣﺰﻳﻨﻬــﺎ ﻗﺒــﻞ أن ﻳــﺘﻢ اﻟﺘﺨ ـﺰﻳﻦ ﻓﻌــﻼ ﻟﻜــﻰ ﳝﻜــﻦ أن ﳓﺠــﺰ اﻟﻌــﺪد اﻟﺼــﺤﻴﺢ ﻣــﻦ اﻟﺒﺎﻳــﺖ ﳍــﺎ ﻹﺿــﺎﻓﺔ ﻻﺳــﺘﺨﺪام اﻷﺳــﻠﻮب اﳌﻨﺎﺳــﺐ‬
‫ﻟﻠﺘﺨ ـﺰﻳﻦ‪ ،‬و ﻣــﻦ ﰒ اﻻﺳــﱰﺟﺎع‪ .‬ﳝﻜــﻦ اﻟﺘﻌﺒــﲑ ﻋــﻦ ﻛــﻞ ﺣﺎﻟــﺔ ﻣــﻦ اﳊــﺎﻻت اﻟﺴــﺎﺑﻘﺔ ﺑﻜﻠﻤــﺔ ﻣﻨﺎﺳــﺒﺔ ﲣﺘﻠــﻒ ﺧــﺘﻼف ﻟﻐــﺔ اﳊﺎﺳــﺐ‬
‫اﳌﺴــﺘﺨﺪﻣﺔ‪ .‬ﻓﻤــﺜﻼ ﰱ ﻟﻐــﺔ ال ‪ C‬ﺗﻌــﱪ اﻟﻜﻠﻤــﺔ ‪ char‬ﻋــﻦ ﻋــﺪد ﺻــﺤﻴﺢ ﳛﺘــﻞ ‪ 1‬ﻳــﺖ و ﳝﻜــﻦ أن ﻳﻜــﻮن ﻣﻮﺟﺒــﺎ أو ﺳــﺎﻟﺒﺎ‪ ،‬أﻣــﺎ‬
‫‪ unsigned char‬ﻓﺘﻌﱪ ﻋﻦ ﻋﺪد ﺻﺤﻴﺢ ﻣﻮﺟﺐ ﳛﺘﻞ ‪ 1‬ﻳﺖ أﻳﻀﺎ و ﻟﻜﻦ ﺑــﺪون إﺷــﺎرة‪ .‬اﳊــﺎﻻت اﳌﻨــﺎﻇﺮة ﺳــﺘﺨﺪام ‪ 2‬ﻳــﺖ‬
‫ﺗﺴﻤﻰ ﻋﻠﻰ اﻟﱰﺗﻴﺐ ‪ int‬و ‪. unsigned int‬‬
‫اﻷﻋﺪاد اﳊﻘﻴﻘﻴﺔ )‪ real numbers‬أو اﻟﻜﺴﺮﻳﺔ( ﻳﻌﱪ ﻋﻨﻬﺎ أوﻻ ﻟﺼﻮرة اﻟﻘﺎﻧﻮﻧﻴﺔ ‪ canonical form‬اﻵﺗﻴﺔ ‪:‬‬
‫‪fraction * 2 exponent‬‬
‫ﺣﻴــﺚ ‪ fraction‬ﻫــﻮ ﻋــﺪد ﻛﺴــﺮى اﺻــﻐﺮ ﻣــﻦ ‪ 1‬و ﻟﻜﻨــﻪ ﻻ ﻳﻘــﻞ ﻋــﻦ ‪ .0.5‬ﻳﺴــﻤﻰ اﳉــﺰء ﻣــﻦ اﻟﻜﺴــﺮ اﳌﻮﺟــﻮد ﻋﻠــﻰ ﳝــﲔ اﻟﻌﻼﻣــﺔ‬
‫اﻟﻌﺸ ـﺮﻳﺔ ﻣﺎﻧﺘﻴﺴ ــﺎ ‪ .mantissa‬ﻣ ــﺎ ﻳ ــﺘﻢ ﲣﺰﻳﻨ ــﻪ ﻓﻌﻠﻴ ــﺎ ﻫ ــﻮ اﻷس ‪ exponent‬ﰱ ﻋ ــﺪد ﻣ ــﺎ ﻣ ــﻦ اﻟﺒﻴ ــﺖ ﻳﻠﻴ ــﻪ ﻣﺒﺎﺷ ــﺮة اﳌﺎﻧﺘﻴﺴ ــﺎ ﰱ ﻋ ــﺪد‬
‫ﻣﻨﺎﺳــﺐ ﻣــﻦ اﻟﺒﻴــﺖ أﻳﻀــﺎ ﺣﻴــﺚ أﻧــﻪ ﻻ داﻋــﻰ ﻟﺘﺨـﺰﻳﻦ اﻷﺳــﺎس ‪ 2‬وﻻ اﻟﻌﻼﻣــﺔ "‪ " 0.‬ﻷ ﻤــﺎ ﻣﻔﻬﻮﻣــﺎن ﺿــﻤﻨﺎ‪ .‬ﻳﻌﺘﻤــﺪ ﻣــﺪى اﻷﻋــﺪاد‬
‫اﳊﻘﻴﻘﻴــﺔ اﻟــﱴ ﳝﻜــﻦ ﲤﺜﻴﻠﻬــﺎ ﻋﻠــﻰ ﻋــﺪد اﻟﺒﻴــﺖ اﳌﺨﺼﺼــﺔ ﻟــﻸس ﻛﻤــﺎ ﺗﻌﺘﻤــﺪ دﻗــﺔ اﻟﺘﻤﺜﻴــﻞ ﻋﻠــﻰ ﻋــﺪد اﻟﺒﻴـﺖ اﳌﺨﺼﺼــﺔ ﻟﻠﻤﺎﻧﺘﻴﺴــﺎ‪ .‬ﻋﻠــﻰ‬
‫ﺳﺒﻴﻞ اﳌﺜﺎل‪ ،‬إذا ارد ﲤﺜﻴﻞ اﻟﻌﺪد اﻟﺜﻨﺎﺋﻰ اﻟﻜﺴﺮى‪:‬‬
‫‪(1101.11)2 = 1*23 + 1*22 + 0*21 + 1*20 + 1*2-1 + 1*2-2 = (13.75)10‬‬
‫ﻓﺈﻧﻨﺎ ﻧﺒﺪأ ﺑﻮﺿﻌﻪ ﰱ اﻟﺼﻮرة اﻟﻘﺎﻧﻮﻧﻴﺔ‪ ،‬و ذﻟﻚ ﺑﱰﺣﻴﻞ اﻟﻌﻼﻣﺔ اﻟﻌﺸﺮﻳﺔ‪:‬‬
‫‪100‬‬
‫)‪1101.11 = 0.110111 * (210‬‬
‫ﻻﺣﻆ أن اﻷس ﻣﻜﺘﻮب ﻷﻋﺪاد اﻟﺜﻨﺎﺋﻴﺔ و ﻫﻮ ﻳﺴﺎوى ‪ 4‬ﻟﻨﻈﺎم اﻟﻌﺸﺮى‪ .‬ﻗﺈذا ﻓﺮض أﻧﻨﺎ ﺳــﻨﺤﺠﺰ أول ‪ 8‬ﺑﻴــﺖ ﻟــﻸس ﰒ ﳔﺼــﺺ‬
‫‪ 24‬ﺑﻴﺖ ﻟﻠﻤﺎﻧﺘﻴﺴﺎ‪ ،‬ﻓﺈﻧﻨﺎ ﻧﻜﻮن ﻗﺪ اﺳﺘﺨﺪﻣﻨﺎ ‪ 4‬ﻳﺖ ﻟﻜﺘﺎﺑﺔ اﻟﻌﺪد ﻋﻠﻰ اﻟﺼﻮرة اﳌﻮﺿﺤﺔ ﰱ ﺷﻜﻞ ‪.4.1‬‬
‫‪Exponent‬‬

‫‪Byte no. 1‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪Mantissa‬‬

‫‪Byte no. 2‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪0‬‬

‫‪Byte no. 3‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬
‫‪Byte no. 4‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬
‫ﺷﻜﻞ ‪ – 4.1‬ﲤﺜﻴﻞ ﻋﺪد ﺣﻘﻴﻘﻰ )ﻛﺴﺮى(‬
‫ﻣــﺮة أﺧــﺮى ﺗﺘﻀــﺢ ﻟﻨــﺎ ﺿــﺮورة ﻣﻌﺮﻓــﺔ ﻧــﻮع اﳌﻌﻠﻮﻣــﺔ اﳌ ـﺮاد اﻟﺘﻌﺎﻣــﻞ ﻣﻌﻬــﺎ ﺳ ـﻮاء ﻟﺘﺨ ـﺰﻳﻦ أو اﻻﺳــﱰﺟﺎع ﻗﺒــﻞ اﻟﺘﻌﺎﻣــﻞ اﻟﻔﻌﻠــﻰ‬
‫ﻣﻌﻬــﺎ‪ .‬وﻟﻜــﻦ اﻟﺘﻨﻮﻳﻌــﺎت أﺻــﺒﺤﺖ أﻛﺜــﺮ اﺗﺴــﺎﻋﺎ ﻓﺎﻟﻌــﺪد اﻟــﺬى ﻧﺘﻌﺎﻣــﻞ ﻣﻌــﻪ ﳝﻜــﻦ أن ﻳﻜــﻮن ﺻــﺤﻴﺤﺎ أو ﻛﺴــﺮ و ﻛــﻞ ﺣﺎﻟــﺔ ﲢــﻮى‬
‫ﺣﺎﻻت ﻓﺮﻋﻴﺔ‪ .‬ﰱ ﻟﻐﺔ ال ‪ C‬ﺗﺴﺘﺨﺪم ﻛﻠﻤﺔ ‪ float‬ﻟﻠﺪﻻﻟﺔ ﻋﻠﻰ ﻋﺪد ﻛﺴﺮى ﻳﺘﻢ ﲣﺰﻳﻨﻪ ﻓﻴﻤــﺎ إﲨﺎﻟﻴــﻪ ‪ 4‬ﻳــﺖ ﺑﻴﻨﻤــﺎ ﺗﺴــﺘﺨﺪم ﻛﻠﻤــﺔ‬
‫‪double‬ﻟﻠﺘﻌﺒﲑ ﻋﻦ ﻋﺪد ﻛﺴﺮى ﳛﺘﻞ ﻣﺎ إﲨﺎﻟﻴﻪ ‪ 8‬ﻳﺖ‪.‬‬
‫اﳊــﺮوف ‪ character data‬ﻳﻌــﱪ ﻋﻨﻬــﺎ أوﻻ ﺑــﺮﻗﻢ ﻛــﻮدى ﺗﺒﻌــﺎ ﻷﺣــﺪ اﳉــﺪاول اﳌﺘﻔــﻖ ﻋﻠﻴﻬــﺎ ﻋﺎﳌﻴــﺎ‪ .‬اﳉــﺪول اﻷﻛﺜــﺮ ﺷــﻴﻮﻋﺎ‬
‫ﻫــﻮ ‪ ASCII‬ﺣﻴــﺚ ﻳﻌــﱪ ﻓﻴــﻪ ﻋــﻦ اﳊــﺮف'‪ 'A‬ﻟــﺮﻗﻢ ‪ 65‬و اﳊــﺮف '‪ 'B‬ﻟــﺮﻗﻢ ‪ 66‬اﱁ‪ .‬اﳊــﺮوف اﻟﺼــﻐﲑة ﲣﺘﻠــﻒ ﻋــﻦ اﻟﻜﺒــﲑة‪،‬‬

‫‪7‬‬
‫ﻓــﺎﳊﺮف '‪ 'a‬رﻗﻤــﻪ اﻟﻜــﻮدى ‪ 97‬و اﳊــﺮف '‪ 'b‬رﻗﻤــﻪ اﻟﻜــﻮدى ‪ .. 98‬اﱁ‪ .‬أﺣﻴــﺎ ﻣــﺎ ﺗﺴــﺘﺨﺪم اﻷرﻗــﺎم ﲟﻌــﲎ ﺣــﺮوف ﻣﺜــﺎل ذﻟــﻚ رﻗــﻢ‬
‫اﻟﺘﻠﻴﻔﻮن‪ .‬ﻓﻼ ﳝﻜﻦ أن ﻧﻌﺘﱪ أن رﻗﻢ اﻟﺘﻠﻴﻔﻮن ﻫﻮ ﻋﺪد ﺻﺤﻴﺢ ﳝﻜﻦ اﻟﺘﻌﺎﻣﻞ ﻣﻌــﻪ ﻟﻌﻤﻠﻴــﺎت اﳊﺴــﺎﺑﻴﺔ اﻟﻌﺎدﻳــﺔ ﻣــﻦ ﲨــﻊ أو ﺿــﺮب‪ .‬و‬
‫ﻟﻜﻨﻪ ﻫﻨﺎ ﻳﻘﻮم ﺑﺪور اﻟﺮﻣﺰ اﻟﺬى ﳝﻜﻦ أن ﻳﻘﻮم ﺑﻪ أى ﺣﺮف آﺧﺮ ﻣﻦ اﳊﺮوف اﳍﺠﺎﺋﻴﺔ‪ .‬و ﻟﺬا ﻓــﺈن اﳊــﺮف '‪ '0‬ﻳﻌﺎﻣــﻞ ﻛــﺄى ﺣــﺮف و‬
‫ﻳﺮﻣــﺰ ﻟــﻪ ﰱ ﺟــﺪول ‪ ASCII‬ﻟــﺮﻗﻢ اﻟﻜــﻮدى ‪ .48‬و ﻛــﺬﻟﻚ اﳊــﺮف '‪ '1‬رﻗﻤــﻪ اﻟﻜــﻮدى ‪ .. 49‬اﱁ‪ .‬و ﰱ اﻟﻨﻬﺎﻳــﺔ ﻓــﺈن اﻟﻌﻼﻣــﺎت‬
‫اﳋﺎﺻﺔ ﻣﺜﻞ اﻟﻘﻮس ')' أو اﻟﻔﺎﺻﻠﺔ '‪ ',‬ﳍﺎ أﻳﻀﺎ أرﻗﺎﻣﻬﺎ اﻟﻜﻮدﻳــﺔ ﰱ اﳉــﺪول‪ .‬ﻫﻨــﺎك ﻋــﺪد ﻣــﻦ اﻟﻌﻼﻣــﺎت اﳋﺎﺻــﺔ اﻟــﱴ ﺗﺴــﻤﻰ ﳊــﺮوف‬
‫اﻟﺒﻴﻀــﺎء‪ white characters‬و ﻫــﻰ ﺣــﺮوف وﻟﻜــﻦ ﻻ ﺗﻈﻬــﺮ ﰱ اﻟﻄﺒﺎﻋــﺔ ﻣﺜــﻞ اﳌﺴــﺎﻓﺔ ﺑــﲔ ﻛﻠﻤﺘــﲔ ' ' و ﺗﺴــﻤﻰ ‪ space‬أو اﻟﻘﻔــﺰ‬
‫إﱃ ﻣﻜــﺎن ﺑــﺖ ﰱ اﻟﺴــﻄﺮ ‪ Tab‬أو ﺑﺪاﻳــﺔ ﺳــﻄﺮ ﺟﺪﻳــﺪ ‪ End_of_Line ..‬اﱁ‪ .‬ﳜــﺰن اﻟــﺮﻗﻢ اﻟﻜــﻮدى ﰱ ﻳــﺖ ﳑــﺎ ﳝﻜﻨﻨــﺎ ﻣــﻦ‬
‫اﻟﺘﻌﺎﻣــﻞ ﻣــﻊ ‪ 256‬ﺣــﺮف ﳐﺘﻠــﻒ ﺗـﱰاوح أرﻗﺎﻣﻬــﺎ اﻟﻜﻮدﻳــﺔ ﺑــﲔ ‪ 0‬و ‪ .255‬اﻟﻜﻠﻤــﺎت أو اﳉﻤــﻞ ﲣــﺰن ﰱ ﻋــﺪد ﻣــﻦ اﳊــﺮوف اﳌﺘﺘﺎﺑﻌــﺔ‬
‫ﺗﺴــﻤﻰ ‪ .string‬ﻟﺘﺨ ـﺰﻳﻦ ﲨﻠــﺔ ﳚــﺐ أن ﻧﻌــﺮف ﻣﺴــﺒﻘﺎ أﻗﺼــﻰ ﻣــﺎ ﳝﻜــﻦ أن ﲢﻮﻳــﻪ اﳉﻤﻠــﺔ ﻣــﻦ ﺣــﺮوف ﲟــﺎ ﰱ ذﻟــﻚ اﳌﺴــﺎﻓﺎت ﺑــﲔ‬
‫اﻟﻜﻠﻤﺎت و ﻋﻼﻣﺎت اﻟﱰﻗﻴﻢ )اﻟﻔﺎﺻﻠﺔ و اﻟﻨﻘﻄﺔ ‪ .(..‬و ﻣــﻦ ﰒ ﳚــﺐ ﺣﺠــﺰ ﻋــﺪد ﻣــﻦ اﻟﺒﺎﻳــﺖ ﻳﺴــﺎوى أﻗﺼــﻰ ﻋــﺪد ﳑﻜــﻦ زاﺋــﺪ واﺣــﺪ‪.‬‬
‫ﳌﺎذا ﻳﻀﺎف ﻫﺬا اﻟﻮاﺣﺪ؟ اﻷﻣــﺮ ﺑﺴــﻴﻂ‪ ،‬اﻓــﱰض أن أﻗﺼــﻰ ﻃــﻮل ﳑﻜــﻦ ﻟﻠﺠﻤﻠــﺔ ﻛــﺎن ‪ 16‬ﺣﺮﻓــﺎ‪ .‬ﺳــﻨﺤﺠﺰ ‪ 17‬ﻳــﺖ ﻟــﺬﻟﻚ‪ .‬اﳉﻤﻠـﺔ‬
‫اﳌﺮاد ﻛﺘﺎﺑﺘﻬﺎ ﻗﺪ ﲢﻮى ﰱ ﻛــﻞ ﻣــﺮة أى ﻋــﺪد ﻣــﻦ اﳊــﺮوف و ﻟــﻴﻜﻦ أﻧﻨــﺎ ﺑﺼــﺪد ﻛﺘﺎﺑــﺔ ﲨﻠــﺔ ﻣــﻦ ‪ 14‬ﺣﺮﻓــﺎ‪ .‬ﺳــﻨﻤﻸ ال‪ 14‬ﻳــﺖ اﻷوﱃ‬
‫ﺣــﺮف اﳉﻤﻠــﺔ ﰒ ﻧﻀــﻊ ﰱ اﳌﻮﻗــﻊ رﻗــﻢ ‪ 15‬ﺣﺮﻓــﺎ ﺧﺎﺻــﺎ ﻳــﺪل ﻋﻠــﻰ ﺎﻳــﺔ اﳉﻤﻠــﺔ )و ﻳﺮﻣــﺰ ﻟــﻪ ﻟﺮﻣــﺰ ’‪ .(‘\0‬و ﺑــﺬﻟﻚ ﺗﺴــﻬﻞ ﻋﻤﻠﻴــﺔ‬
‫اﺳــﱰﺟﺎع اﳉﻤﻠــﺔ و ﻛﺘﺎﺑﺘﻬــﺎ ﻋﻠــﻰ اﻟﺸﺎﺷــﺔ أو ﻃﺒﺎﻋﺘﻬــﺎ‪ .‬ﻳــﺘﻢ ذﻟــﻚ ﲟﻌﺎﳉــﺔ اﳉﻤﻠــﺔ ﺣﺮﻓــﺎ ﺣﺮﻓــﺎ و إرﺳــﺎﻟﻪ ﻟﻮﺣــﺪة اﳋــﺮوج إﱃ أن ﻧﺼــﻞ‬
‫ﻟﻠﺤﺮف رﻗﻢ ‪) 15‬اﳊﺮف ’‪ (‘\0‬ﻓﻴﻌﺮف اﳊﺎﺳﺐ أﻧﻪ ﳚﺐ أن ﻳﺘﻮﻗﻒ ﻋﻦ اﳌﻌﺎﳉﺔ ﻓﻠﻘﺪ اﻧﺘﻬﺖ اﳉﻤﻠﺔ‪.‬‬

‫‪N‬‬ ‫‪a‬‬ ‫‪g‬‬ ‫‪e‬‬ ‫‪e‬‬ ‫‪b‬‬ ‫‪M a‬‬ ‫‪h‬‬ ‫‪f‬‬ ‫‪o‬‬ ‫‪u‬‬ ‫‪z‬‬ ‫‪\0 x‬‬ ‫‪5‬‬

‫ﺷﻜﻞ ‪ -5.1‬ﲤﺜﻴﻞ اﳉﻤﻠﺔ‬


‫اﻟﺒﻴــﺎ ت اﳌﻨﻄﻘﻴــﺔ ‪ logical data‬ﻫــﻰ ﻧــﻮع ﺧــﺎص ﻣــﻦ اﻟﺒﻴــﺎ ت ﲣﺘﻠــﻒ ﻋــﻦ اﻟﺮﻗﻤﻴــﺔ و اﳊﺮﻓﻴــﺔ‪ .‬ﻫــﺬا اﻟﻨــﻮع ﻣــﻦ اﻟﺒﻴــﺎ ت‬
‫ﻳﺘﻌﻠﻖ ﻟﻜﻤﻴﺎت اﻟﱴ ﳝﻜﻦ ﳍﺎ أن ﺧﺬ أﺣﺪ ﻗﻴﻤﺘﲔ ﻻ ﻟﺚ ﳍﻤــﺎ وﳘــﺎ ﺻــﺤﻴﺢ ‪ True‬أو ﺧﻄــﺄ ‪ .False‬ﳝﻜــﻦ ﲤﺜﻴــﻞ ﻫــﺬﻩ اﻟﻜﻤﻴــﺔ‬
‫ﺳﺘﺨﺪام ﺑﻴﺖ واﺣﺪ ﺣﻴﺚ ﺧﺬ ﻣﺜﻼ اﻟﻘﻴﻤﺔ ‪ 1‬إذا أرد اﻟﺘﻌﺒــﲑ ﻋــﻦ ‪ True‬أو ‪ 0‬إذا أرد اﻟﺘﻌﺒــﲑ ﻋــﻦ ‪ .False‬و ﻟﻜــﻦ ﻷﺳــﺒﺎب‬
‫ﻓﻨﻴﺔ ﻓﺄﻧﻪ ﻛﺜﲑا ﻣﺎ ﳓﺠﺰ ﻳﺖ ﻛﺎﻣﻞ ﻟﺘﺨﺰﻳﻦ ﻫﺬﻩ اﻟﻜﻤﻴﺔ‪ .‬ﻟﺮﻏﻢ ﳑﺎ ﰱ ذﻟﻚ ﻣﻦ إﻫﺪار ﻟﻠﺬاﻛﺮة إﻻ أﻧﻪ ﳛﻘﻖ ﺳــﺮﻋﺔ ﻛﺘﺎﺑــﺔ و اﺳــﱰﺟﺎع‬
‫اﳌﻌﻠﻮﻣﺔ‪ .‬و ﻻ ﻧﻠﺠﺄ ﻻﺳﺘﺨﺪام ﺑﻴﺖ واﺣﺪ ﻓﻘﻂ إﻻ إذا ﻛﺎن ﺣﺠﻢ اﻟﺒﻴﺎ ت ﻛﺒﲑا ﲟﺎ ﻳﻬﺪد ﺑﻌﺪم اﺳﺘﻴﻌﺎب اﻟﺬاﻛﺮة ﻟﻪ‪.‬‬
‫ﳜﺘﻠﻒ أﺳﻠﻮب ﲤﺜﻴﻞ اﻟﺒﻴﺎ ت اﳌﻬﻴﻜﻠﺔ ‪ structured data‬ﺧﺘﻼف ﻃﺒﻴﻌــﺔ اﻟﻌﻼﻗــﺔ اﳌﻨﻄﻘﻴــﺔ ﺑــﲔ أﻓـﺮاد اﳍﻴﻜــﻞ‪ .‬و ﻟــﺬﻟﻚ‬
‫ﻓﺴ ــﻨﺮﺟﺊ اﳊ ــﺪﻳﺚ ﻋ ــﻦ أﺳ ــﻠﻮب اﻟﺘﺨ ـﺰﻳﻦ إﱃ ﻣ ــﺎ ﺑﻌ ــﺪ ﻋ ــﺮض اﳍﻴﺎﻛ ــﻞ اﳌﺨﺘﻠﻔ ــﺔ ﻣ ــﻦ ﻣﺘﺠﻬ ــﺎت ‪ arrays‬أو ﺳ ــﺠﻼت ‪ records‬أو‬
‫ﻣﻠﻔﺎت ‪ .. files‬اﱁ‪.‬‬

‫‪8‬‬
‫‪.1‬ج‪ .‬ﲤﺜﻴﻞ اﻟﻌﻤﻠﻴﺎت ‪Representing operations‬‬
‫إن ﳎﻤﻮﻋﺔ اﻟﻌﻤﻠﻴﺎت اﻷوﻟﻴﺔ اﻟــﱴ ﳝﻜــﻦ أن ﺗﻨﻔــﺬﻫﺎ وﺣــﺪة اﳌﻌﺎﳉــﺔ اﳌﺮﻛﺰﻳــﺔ ‪ CPU‬ﺗﺴــﻤﻰ ﻓﺌــﺔ اﻷواﻣــﺮ ‪.Instruction set‬‬
‫ﲢﻮى ﻫﺬﻩ اﻟﻔﺌﺔ ﻋﺪد ﳏﺪود ﻣﻦ اﻷواﻣﺮ ﺣﻮاﱃ ﻋﺸﺮة أو ﺑﻀﻌﺔ ﻋﺸﺮات ﻗﻠﻴﻠــﺔ‪ .‬أى ﺑــﺮ ﻣﺞ ﲟــﺎ ﰱ ذﻟــﻚ اﻟـﱪاﻣﺞ ﺷــﺪﻳﺪة اﻟﺘﻌﻘﻴــﺪ ﳝﻜــﻦ‬
‫ﲢﻠﻴﻠﻬــﺎ إﱃ ﻋــﺪد ﻛــﱪ أو ﺻــﻐﺮ ﻣــﻦ ﻫــﺬﻩ اﻷواﻣــﺮ‪ .‬ﻟــﻴﺲ ﻣــﻦ اﻟﺼــﻌﺐ ﲣﻴــﻞ ذﻟــﻚ إذا أدرﻛﻨــﺎ أن ﻛــﻞ ﻣــﺎ ﻛﺘــﺐ ﻣــﻦ أدب أو ﻋﻠــﻢ ﻟﻠﻐــﺔ‬
‫اﻟﻌﺮﺑﻴﺔ ﻣﻊ ﺗﻨﻮﻋﻪ اﻟﺸﺪﻳﺪ إﻻ أﻧﻪ ﱂ ﻳﺴﺘﺨﺪم ﺳﻮى ‪ 28‬ﺣﺮﻓﺎ!‬
‫ﺗﻀﻢ ﻓﺌﺔ اﻷواﻣﺮ ﳎﻤﻮﻋﺔ ﻣﻦ اﻷواﻣﺮ ﺗﺘﻌﻠﻖ ﺑﻨﻘﻞ اﻟﺒﻴﺎ ت ﺑﲔ اﻷﺟﺰاء اﳌﺨﺘﻠﻔﺔ ﻟﻠﺤﺎﺳﺐ‪:‬‬
‫‪ -‬ﺗﺒﺎدل اﳌﻌﻠﻮﻣﺎت ﺑﲔ اﻟﺬاﻛﺮة و أدوات اﻹدﺧﺎل و اﻹﺧﺮاج اﳌﺨﺘﻠﻔﺔ‪.‬‬
‫‪ -‬ﺗﺒﺎدل اﳌﻌﻠﻮﻣﺎت ﺑﲔ اﻟﺬاﻛﺮة و ﺳﺠﻼت اﻟﻮﺣﺪة اﳌﺮﻛﺰﻳﺔ ﰱ اﻻﲡﺎﻫﲔ‪.‬‬
‫‪ -‬ﺗﺒﺎدل اﳌﻌﻠﻮﻣﺎت ﺑﲔ اﳌﺨﺰن اﻷوﱃ و اﻟﺜﺎﻧﻮى ﰱ اﻻﲡﺎﻫﲔ‪.‬‬
‫ﻳﻨﺒﻐﻰ أﻳﻀﺎ أن ﲢﻮى ﻓﺌﺔ اﻷواﻣﺮ ﳎﻤﻮﻋﺔ أﺧﺮى ﺗﺘﻌﻠﻖ داء اﻟﻌﻤﻠﻴﺎت اﳊﺴﺎﺑﻴﺔ واﳌﻨﻄﻘﻴﺔ ﻣﺜﻞ‪:‬‬
‫‪ -‬ﲨﻊ ﻋﺪدﻳﻦ ﰱ ﺳﺠﻼت اﻟﻮﺣﺪة اﳌﺮﻛﺰﻳﺔ‬
‫‪ -‬ﺗﻐﻴﲑ إﺷﺎرة ﻋﺪد‬
‫‪ -‬إزاﺣﺔ ﻗﻴﻢ اﻟﺒﻴﺖ ﰱ ﻳﺖ ﰱ اﲡﺎﻩ اﻟﻴﻤﲔ أو اﻟﻴﺴﺎر ‪.shift left or right‬‬
‫‪ -‬ﻣﻘﺎرﻧﺔ ﺑﲔ ﻋﺪدﻳﻦ‬
‫‪ -‬إﺟﺮاء اﻟﻌﻤﻠﻴﺎت اﳌﻨﻄﻘﻴﺔ اﻟﺮﺋﻴﺴﻴﺔ ﻣﺜﻞ ‪.NOT, AND, OR‬‬
‫ﳝﻜﻦ ﲢﻮﻳﻞ اﻟﻌﻤﻠﻴﺎت اﳊﺴﺎﺑﻴﺔ و اﳌﻨﻄﻘﻴﺔ اﻷﺧــﺮى )ﻣﺜــﻞ اﻟﻄــﺮح و اﻟﻀــﺮب ‪..‬اﱁ( إﱃ ﻋــﺪد ﻣــﻦ اﻟﻌﻤﻠﻴــﺎت اﻟﺒﺴــﻴﻄﺔ اﻟـﻮاردة أﻋــﻼﻩ‪ .‬و‬
‫ﻟﻜﻦ ﰱ ﺑﻌﺾ وﺣﺪات اﳌﻌﺎﳉﺔ اﳌﺮﻛﺰﻳﺔ ﲢﻮى ﻓﺌﺔ اﻷواﻣﺮ أواﻣﺮ إﺿﺎﻓﻴﺔ ﺧﺎﺻﺔ ﻹﺟﺮاء ﻫﺬﻩ اﻟﻌﻤﻠﻴﺎت ﻣﺒﺎﺷﺮة ﺗﻮﻓﲑا ﻟﻠﻮﻗﺖ‪.‬‬
‫و ﰱ اﻟﻨﻬﺎﻳﺔ ﻫﻨﺎك أواﻣﺮ ﺗﺘﻌﻠﻖ ﻟﺘﺤﻜﻢ ﰱ ﺳﲑ اﻟﱪ ﻣﺞ ﻣﺜﻞ‪:‬‬
‫‪ -‬اﻟﻌﻤﻠﻴﺔ اﻟﻔﺎرﻏﺔ أو اﻟﻼ ﻋﻤﻠﻴﺔ ‪ No-op‬و ﺗﺴﺘﺨﺪم ﳊﻤﻞ اﳊﺎﺳﺐ ﻋﻠﻰ اﻻﻧﺘﻈﺎر‪.‬‬
‫‪ -‬ﻋﻤﻠﻴﺔ اﻟﺘﻮﻗﻒ و إ ﺎء اﻟﱪ ﻣﺞ‪.‬‬
‫‪ -‬ﻋﻤﻠﻴﺎت اﻟﻘﻔﺰ اﳌﺸﺮوﻃﺔ و ﻏﲑ اﳌﺸﺮوﻃﺔ ﻣﻦ ﻣﻜﺎن ﻣﻌﲔ ﰱ اﻟﱪ ﻣﺞ ﳌﻜﺎن آﺧﺮ‪.‬‬
‫ﻳﺘﻜﻮن اﳍﻴﻜﻞ اﻟﻌﺎم ﻟﻜﻞ أﻣﺮ ‪ instruction‬ﻣﻦ ﻋﺪة ﺣﻘﻮل ‪ .fields‬اﳊﻘﻞ اﻷول ﳛﻮى رﻗﻢ ﻛﻮدى ﻳﻌﱪ ﻋــﻦ ﻧــﻮع اﻷﻣــﺮ‬
‫اﻟﺬى ﳓﻦ ﺑﺼﺪد ﺗﻨﻔﻴﺬﻩ‪ .‬ﻟﻨﻔﱰض ﻋﻠﻰ ﺳﺒﻴﻞ اﳌﺜﺎل أن اﳌﻄﻠﻮب ﺗﻨﻔﻴﺬ اﻷﻣﺮ ‪ MOV‬و ﻫﻮ اﳌﻌﲎ ﺑﻨﻘﻞ ﻣﻌﻠﻮﻣﺔ ﻣــﻦ اﻟــﺬاﻛﺮة إﱃ أﺣــﺪ‬
‫ﺳﺠﻼت اﻟﻮﺣﺪة اﳌﺮﻛﺰﻳﺔ‪ .‬اﳊﻘﻞ اﻷول ﻛﻤﺎ ذﻛﺮ ﳛﻮى اﻟــﺮﻗﻢ اﻟﻜــﻮدى اﳌﻌــﱪ ﻋــﻦ اﻷﻣــﺮ ‪ MOV‬و اﻟــﺬى ﺳــﻨﻔﱰض أﻧــﻪ ‪ .9‬ﻷﻋــﺪاد‬
‫اﻟﺜﻨﺎﺋﻴﺔ ﻓﺈﻧﻪ ﻳﻜﺘﺐ ﻋﻠﻰ اﻟﺼــﻮرة ‪ .001001‬ﻻﺣــﻆ أﻧﻨــﺎ اﺳــﺘﺨﺪﻣﻨﺎ ‪ 6‬ﺑﻴــﺖ ﻟﻜﺘﺎﺑــﺔ اﻟــﺮﻗﻢ اﻟﻜــﻮدى‪ .‬ﻫــﺬا اﻟﻌــﺪد ﻳﻜﻔــﻰ ﻟﻜﺘﺎﺑــﺔ أرﻗــﺎم‬
‫ﻛﻮدﻳﺔ ﺗﱰاوح ﺑﲔ ‪ 0‬و ‪ .63‬أى أن ﻋــﺪد اﻷواﻣــﺮ اﳌﺨﺘﻠﻔــﺔ ﳝﻜــﻦ أن ﻳﺼــﻞ إﱃ ‪ 64‬ﲝــﺪ أﻗﺼــﻰ و ﻫــﻮ رﻗــﻢ ﻛــﺎﰱ ﰱ أﻏﻠــﺐ اﻷﺣـﻮال‪.‬‬
‫اﳊﻘﻞ اﻟﺘﺎﱃ ﳛﻮى رﻗﻢ ﺧﺎﻧﺔ اﻟﺬاﻛﺮة اﻟﱴ ﺳﻨﻨﻘﻞ ﻣﻨﻬﺎ اﳌﻌﻠﻮﻣﺔ‪ .‬إذا ﻛﺎﻧﺖ ذاﻛﺮة اﳊﺎﺳﺐ ﻣﻘﺴﻤﺔ إﱃ ﻛﻠﻤﺎت ﺣﺠﻢ ﻛــﻞ واﺣــﺪة ﻣــﻨﻬﻢ‬
‫‪ 4‬ﻳــﺖ )‪ 32‬ﺑﻴــﺖ( و ﻛــﺎن ﻋــﺪد اﻟﻜﻠﻤــﺎت ﻳﺼــﻞ إﱃ ‪ 1‬ﻣﻴﺠــﺎ ﻛﻠﻤــﺔ ﻓﺄﻧﻨــﺎ ﳓﺘــﺎج ﻟﺘﺨﺼــﻴﺺ ‪ 20‬ﺑﻴــﺖ ﻟﻠﺪﻻﻟــﺔ ﻋﻠــﻰ رﻗــﻢ ﺧﺎﻧــﺔ‬
‫اﻟ ـ ـ ـ ــﺬاﻛﺮة اﳌﻌﻨﻴ ـ ـ ـ ــﺔ‪ .‬اﻓ ـ ـ ـ ــﱰض أن رﻗ ـ ـ ـ ــﻢ ﺧﺎﻧ ـ ـ ـ ــﺔ اﻟ ـ ـ ـ ــﺬاﻛﺮة اﳌﻌﻨﻴ ـ ـ ـ ــﺔ ﻛ ـ ـ ـ ــﺎن ‪ 67‬ﻓﺄﻧ ـ ـ ـ ــﻪ ﻳﻜﺘ ـ ـ ـ ــﺐ ﻷﻋ ـ ـ ـ ــﺪاد اﻟﺜﻨﺎﺋﻴ ـ ـ ـ ــﺔ ﻛﻤ ـ ـ ـ ــﺎ ﻳﻠ ـ ـ ـ ــﻰ‪:‬‬
‫‪ .00000000000001000011‬اﳊﻘﻞ اﻷﺧﲑ ﳛــﻮى رﻗــﻢ اﻟﺴــﺠﻞ اﻟــﺬى ﺳــﻨﻨﻘﻞ إﻟﻴــﻪ اﳌﻌﻠﻮﻣــﺔ‪ .‬إذا ﻛــﺎن ﻋــﺪد اﻟﺴــﺠﻼت ﻻ ﻳﺰﻳــﺪ‬
‫ﻋﻦ ‪ 64‬ﻓﺈﻧﻨﺎ ﳓﺘﺎج ﻟﺘﺨﺼﻴﺺ ‪ 6‬ﺑﻴﺖ ﳍﺬا اﳊﻘــﻞ‪ .‬إذا ﻛــﺎن اﻟﺴــﺠﻞ اﻟــﺬى ﺳــﻨﻨﻘﻞ إﻟﻴــﻪ اﳌﻌﻠﻮﻣــﺔ ﻫــﻮ رﻗــﻢ ‪ 12‬ﻓﺈﻧﻨــﺎ ﻧﻌــﱪ ﻋﻨــﻪ ﻟﻌــﺪد‬
‫اﻟﺜﻨﺎﺋﻰ ‪ .001100‬اﻟﺼﻮرة اﻟﻜﻠﻴﺔ ﻟﻸﻣﺮ ﺗﻨﺘﺞ ﻣﻦ ﲡﻤﻴﻊ اﳊﻘﻮل اﻟﺴﺎﺑﻘﺔ ﻋﻠﻰ اﻟﱰﺗﻴﺐ ﻟﺘﻌﻄﻰ‪:‬‬

‫‪9‬‬
‫‪00100100000000000001000011001100‬‬
‫ﻫــﺬﻩ اﻷرﻗــﺎم ﺗﻌــﱪ ﻋــﻦ أﻣــﺮ ﻣﻜﺘــﻮب ﲟــﺎ ﻳﺴــﻤﻰ ﻟﻐــﺔ اﻵﻟــﺔ ‪ .machine language‬و ﻫــﻰ واﺿــﺤﺔ ﲤﺎﻣــﺎ ﻟﻮﺣــﺪة اﻟــﺘﺤﻜﻢ اﳌﺮﻛﺰﻳــﺔ اﻟــﱴ‬
‫ﺗﺪرك ﺑﺴﻬﻮﻟﺔ ﻣﺎ ﻫﻮ اﳌﻄﻠﻮب ﻋﻤﻠﻪ ﲟﺠﺮد ﻗﺮاءة اﻷﻣﺮ و ﲢﻠﻴﻠﻪ ﻷﺟﺰاﺋﻪ اﻟﺮﺋﻴﺴﻴﺔ‪ .‬ﻣﻦ اﻟﺼﻌﺐ ﻋﻠﻴﻨﺎ ﻛﺒﺸﺮ أن ﻧﻮﺟــﻪ أواﻣــﺮ ﻟﻠﺤﺎﺳــﺐ‬
‫ﺬا اﻷﺳﻠﻮب‪ .‬ﻫﻨﺎك درﺟﺔ اﻛﺜﺮ ﻗﺒــﻮﻻ ﻟﻠﺒﺸــﺮ و ﻫــﻰ اﺳــﺘﻌﻤﺎل ﻟﻐــﺔ اﻟﺘﺠﻤﻴــﻊ ‪ .assembly language‬ﰱ ﻫــﺬﻩ اﻟﻠﻐــﺔ ﻳﻌــﱪ ﻋــﻦ ﻛــﻞ‬
‫أﻣﺮ ﺑﺮﻣﺰ ﻣﻜﻮن ﻋﺎدة ﻣﻦ ‪ 3‬ﺣﺮوف و ﻳﻌﱪ ﻋﻦ ﻛﻞ ﺧﺎﻧﺔ ذاﻛﺮة أو ﺳﺠﻞ ﺳﻢ‪ ،‬ﲝﻴﺚ ﳝﻜﻦ ﻛﺘﺎﺑﺔ اﻷﻣﺮ‪:‬‬
‫‪Assembly‬‬ ‫‪MOV‬‬ ‫‪X‬‬ ‫‪AX‬‬
‫‪Machine Language‬‬ ‫‪00100100000000000001000011001100‬‬
‫‪Move‬‬ ‫‪To register‬‬
‫‪no. 12‬‬
‫‪Contents of memory cell‬‬
‫‪no. 67‬‬
‫ﺷﻜﻞ ‪ -6.1‬ﺗﺮﲨﺔ أﻣﺮ ﻧﻘﻞ اﻟﺒﻴﺎ ت ﺑﻠﻐﺔ اﻵﻟﺔ‬
‫و اﻟﺬى ﻳﻔﻬﻢ‪ :‬اﻧﻘﻞ ﳏﺘﻮى اﻟﺬاﻛﺮة اﳌﺴﻤﺎة ﺑﻴﻨﻨــﺎ "‪ "X‬إﱃ اﻟﺴــﺠﻞ اﳌﺴــﻤﻰ ‪ .AX‬ﳝﻜــﻦ ﺑﺴــﻬﻮﻟﺔ أن ﻳــﱰﺟﻢ اﳊﺎﺳــﺐ ﻫــﺬا‬
‫اﻷﻣﺮ إﱃ ﻧﻈﲑﻩ ﺳﺘﺨﺪام ﻟﻐﺔ اﻵﻟﺔ و ﻫﻰ اﳌﻔﻀﻠﺔ ﻟﺪﻳﻪ ﲤﻬﻴﺪا ﻟﻠﺘﻨﻔﻴﺬ‪.‬‬
‫ﻟﻨﺴﺘﻌﺮض ﻣﻌﺎ ﻛﻴﻒ ﻳﺘﻢ ﺗﻨﻔﻴــﺬ ﺑــﺮ ﻣﺞ ﺑﺴــﻴﻂ ﺑﻮاﺳــﻄﺔ وﺣــﺪة اﳌﻌﺎﳉــﺔ اﳌﺮﻛﺰﻳــﺔ‪ .‬ﺳــﻨﻔﱰض أن اﻟــﱪ ﻣﺞ ﻳﻘـﺮأ رﻗﻤــﲔ ﰒ ﻳﻀــﻴﻒ‬
‫أﻛﱪﳘــﺎ إﱃ رﻗــﻢ ﻟــﺚ و ﻳﻜﺘــﺐ اﻟﻨــﺎﺗﺞ‪ .‬اﻟــﱪ ﻣﺞ ﻣﻜﺘــﻮب ﺑﻠﻐــﺔ اﻟﺘﺠﻤﻴــﻊ و ﳏﻔــﻮظ ﰱ ﺧــﺎ ت اﻟــﺬاﻛﺮة رﻗــﻢ ‪ 21‬إﱃ ‪ .33‬ﻋﻨــﺪ ﺗﺮﲨــﺔ‬
‫اﻟﱪ ﻣﺞ ﻟﻠﻐﺔ اﻵﻟﺔ ﺳﻴﻘﻮم اﳊﺎﺳﺐ ﲝﺠﺰ أﻣﺎﻛﻦ ﰱ اﻟﺬاﻛﺮة ﺗﻨﺎﻇﺮ اﻷﲰﺎء اﻟﱴ ذﻛﺮت ﰱ اﻟﱪ ﻣﺞ‪ .‬ﻧﻔــﱰض أﻧــﻪ ﺳــﻴﺤﺠﺰ اﳋــﺎ ت رﻗــﻢ‬
‫‪ 41‬إﱃ ‪ 44‬ﻟﻸﲰﺎء ‪ X,Y,Z,W‬ﻋﻠﻰ اﻟﱰﺗﻴﺐ‪ .‬إن ﺗﻨﻔﻴﺬ أى ﺑﺮ ﻣﺞ‪ ،‬ﻳﺘﻢ ﺑﻨﺎء ﻋﻠﻰ دورة ﻛﻤﺎ ﻳﻠﻲ‪:‬‬
‫‪ -1‬ﺿﻊ ﻋﻨﻮان ﺧﺎﻧﺔ اﻟﺬاﻛﺮة اﻟﱴ ﲢﻮى أول أﻣﺮ ﰱ اﻟﱪ ﻣﺞ )و ﻟﺘﻜﻦ اﳋﺎﻧﺔ رﻗﻢ ‪ 21‬ﻣــﺜﻼ( ﰱ ﺳــﺠﻞ ﻋﻨـﻮان اﻷﻣــﺮ ) ‪Intruction‬‬
‫‪ address register‬أى ﻋﻨﻮان اﻷﻣﺮ ﳏﻞ اﻟﺘﻨﻔﻴﺬ(‪.‬‬
‫‪ -2‬اﻧﻘــﻞ اﻷﻣــﺮ اﳌﻮﺟــﻮد ﻋﻨﻮاﻧــﻪ ﰱ ذﻟــﻚ اﻟﺴــﺠﻞ إﱃ ﺳــﺠﻞ اﻷواﻣــﺮ )‪ Instruction register‬و ﻫــﻮ ﳛــﻮى اﻷﻣــﺮ اﻟــﺬى ﻧﻘــﻮم‬
‫ﺑﺘﻨﻔﻴﺬﻩ(‪.‬‬
‫‪ -3‬اﺿﻒ اﻟﺮﻗﻢ واﺣﺪ ﻟﺴﺠﻞ ﻋﻨﻮان اﻷﻣﺮ )ﺣﱴ ﳓﺼﻞ ﻋﻠﻰ ﻋﻨﻮان اﻷﻣﺮ اﻟﺘﺎﱃ ﰱ اﻟﺪورة اﻟﺘﺎﻟﻴﺔ(‬
‫‪ -4‬ﺣﻠﻞ اﻷﻣﺮ اﳌﻮﺟﻮد ﰱ ﺳﺠﻞ اﻷواﻣﺮ و ﻧﻔﺬﻩ‪.‬‬
‫‪ -5‬إذا ﻛﺎن اﻷﻣﺮ ﻳﺪل ﻋﻠﻰ ﺎﻳﺔ اﻟﱪ ﻣﺞ أوﻗﻒ اﻟﺪورة‪ ،‬ﻋﺪا ذﻟﻚ ﻛﺮر اﳋﻄﻮات ﺑﺪءا ﻣﻦ ‪.2‬‬
‫ﻓﻠﻨﺘﺎﺑﻊ ﺧﻄﻮات اﻟﺘﻨﻔﻴﺬ ﺑﺪءا ﻣﻦ اﳋﻄﻮة ‪ ،1‬و ﻫــﻰ ﺗﺴــﻤﻰ ﲢﻤﻴــﻞ اﻟــﱪ ﻣﺞ ‪ .Loading‬ﳝﺜــﻞ اﻟﺸــﻜﻞ ‪ 8.1‬ﺣﺎﻟــﺔ اﻟــﺬاﻛﺮة‬
‫و وﺣــﺪة اﻟــﺘﺤﻜﻢ اﳌﺮﻛﺰﻳــﺔ ﻋﻨــﺪ ﺗﻨﻔﻴــﺬ ﺗﻠــﻚ اﳋﻄــﻮة‪ .‬ﻓــﺎﻟﱪ ﻣﺞ ﳐــﺰن ﰱ ﺧــﺎ ت اﻟــﺬاﻛﺮة اﻟــﱴ ﺗﺒــﺪأ ﻣــﻦ ‪ .21‬اﳋــﺎ ت ‪ 41‬و ﻣــﺎ ﻳﻠﻴﻬــﺎ‬
‫ﳏﺠﻮزة ﳌﺘﻐﲑات ﻫﺬا اﻟﱪ ﻣﺞ )أى ﻻ ﳝﻜﻦ ﺷﻐﻠﻬﺎ ﻳﺔ ﻣﻌﻠﻮﻣﺎت أﺧﺮى إﱃ أن ﻳﻨﺘﻬﻰ ﺗﺸﻐﻴﻞ اﻟﱪ ﻣﺞ(‪ .‬و ﺳﺠﻞ اﻷﻣﺮ ﻣﻮﺿــﻮع ﻓﻴــﻪ‬
‫ﻋﻨ ـﻮان ﺑﺪاﻳــﺔ اﻟــﱪ ﻣﺞ‪ ،‬أى ﻋﻨ ـﻮان اﳋﺎﻧــﺔ اﻷوﱃ ﻓﻴــﻪ و ﻫــﻮ ‪ .21‬ﺗﺒــﺪأ اﻟــﺪورة ﻣــﻦ اﳋﻄــﻮة رﻗــﻢ ‪ 2‬ﺣﻴــﺚ ﺗﻘــﻮم وﺣــﺪة اﻟــﺘﺤﻜﻢ اﳌﺮﻛﺰﻳــﺔ‬
‫‪ CCU‬ﺑﻔﺤ ــﺺ ﳏﺘ ــﻮى ﺳ ــﺠﻞ ﻋﻨ ـﻮان اﻷﻣ ــﺮ‪ .‬ﻛﻤ ــﺎ ذﻛ ــﺮ ﻋﺎﻟﻴ ــﻪ ﻓﺄﻧ ــﻪ ﳛ ــﻮى ‪ 21‬و ﻫ ــﻮ رﻗ ــﻢ ﺧﺎﻧ ــﺔ اﻟ ــﺬاﻛﺮة اﻟ ــﱴ ﲢ ــﻮى أول أﻣ ــﺮ ﰱ‬
‫اﻟﱪ ﻣﺞ‪ .‬ﺗﻘﻮم ال‪ CCU‬ﺑﻌﻨﺪ ذﻟﻚ ﺑﻨﻘﻞ اﻷﻣﺮ اﳌﺨﺘﺰن ﰱ اﳋﺎﻧﺔ رﻗﻢ ‪ 21‬إﱃ ﺳﺠﻞ اﻷﻣﺮ‪ .‬اﳋﻄﻮة رﻗﻢ ‪ 3‬ﺗــﺘﻠﺨﺺ ﰱ إﺿــﺎﻓﺔ واﺣــﺪ‬
‫ﻟﺴــﺠﻞ ﻋﻨـﻮان اﻷﻣــﺮ ﻓﻴﺼــﺒﺢ ‪ .22‬ﰱ اﳋﻄــﻮة رﻗــﻢ ‪ 4‬ﻧﺒــﺪأ ﺑﺘﺤﻠﻴــﻞ اﻷﻣــﺮ‪ .‬ﺳــﺠﻞ اﻷﻣــﺮ ﳛــﻮى اﻵن اﻷﻣــﺮ ‪ INP X‬و ﻳﻌــﲎ ﻗـﺮاءة‬
‫ﻣﻌﻠﻮﻣــﺔ ﻣــﻦ وﺣــﺪة اﻹدﺧﺎل)ﻟﻮﺣــﺔ اﳌﻔــﺎﺗﻴﺢ( إﱃ ﺧﺎﻧــﺔ اﻟــﺬاﻛﺮة ‪ X‬أى اﳋﺎﻧــﺔ رﻗــﻢ ‪ .41‬ﻛــﺎن ﻫــﺬا ﻫــﻮ اﻟﺘﺤﻠﻴــﻞ‪ .‬ﺗﻘــﻮم وﺣــﺪة اﻟــﺘﺤﻜﻢ‬
‫اﳌﺮﻛﺰﻳﺔ ﺑﻌﺪ ذﻟﻚ ﻟﺘﻨﻔﻴﺬ و اﳌﺘﺎﺑﻌﺔ‪ .‬اﳌﻘﺼﻮد ﳌﺘﺎﺑﻌﺔ اﻟﺘﺄﻛﺪ ﻣﻦ ﺣﺴــﻦ ﺗﻨﻔﻴــﺬ اﻟﻮﺣــﺪة اﳌﻨﻮﻃــﺔ ﺑﺘﻨﻔﻴــﺬ اﻷﻣــﺮ ﳌــﺎ أوﻛــﻞ إﻟﻴﻬــﺎ‪ .‬ﻓﻤــﺜﻼ إذا‬

‫‪10‬‬
‫ﱂ ﻧﻌــﻂ ﻣﻌﻠﻮﻣــﺎت ﻟﻮﺣــﺪة اﻹدﺧــﺎل ﻟﻜــﻰ ﺗﻨﻘﻠﻬــﺎ ﻟﻠﺨﺎﻧــﺔ ‪ ،41‬ﺳــﺘﺄﻣﺮ ال‪ CCU‬ﻟﺘﻮﻗــﻒ ﻋــﻦ اﻟﻌﻤــﻞ و إرﺳــﺎل رﺳــﺎﻟﺔ ﻋﻠــﻰ اﻟﺸﺎﺷــﺔ‬
‫ﺗﻮﺿــﺢ ﺳــﺒﺐ اﻟﺘﻮﻗــﻒ‪ .‬ﺷــﻜﻞ ‪ 9.1‬ﻳﻮﺿــﺢ ﺣﺎﻟــﺔ اﳊﺎﺳــﺐ ﰱ ﺎﻳــﺔ ﻫــﺬﻩ اﳋﻄــﻮة‪ .‬ﰒ ﺗﻌــﻮد ال ‪ CCU‬اﱃ اﳋﻄــﻮة ‪ 2‬ﰱ اﻟــﺪورة‪.‬‬
‫ﻓﺘﻘﻮم ﺑﻘﺮاءة وﺗﻨﻔﻴﺬ اﻷﻣﺮ اﳌﻮﺟﻮد ﰱ اﳋﺎﻧﺔ ‪ 22‬و ﻫﻮ ﻗﺮاءة ﻣﻌﻠﻮﻣﺔ ﻣﻦ ﻟﻮﺣﺔ اﳌﻔﺎﺗﻴﺢ ووﺿﻌﻬﺎ ﰱ ﺧﺎﻧﺔ اﻟــﺬاﻛﺮة رﻗــﻢ ‪ 42‬ﻛﻤــﺎ ﺳــﺒﻖ‪.‬‬
‫اﻷﻣﺮ اﻟﺜﺎﻟﺚ ﻫﻮ أﻳﻀﺎ إدﺧﺎل ﻣﻌﻠﻮﻣﺔ ﰱ اﳋﺎﻧﺔ رﻗﻢ ‪.43‬‬

‫‪Start‬‬

‫‪Inp‬‬
‫‪X,Y,Z‬‬

‫‪Put X in AX‬‬

‫‪Sub. Y from‬‬
‫‪AX‬‬

‫‪N‬‬ ‫‪Y‬‬
‫?‪AX<0‬‬

‫‪Put X in AX‬‬ ‫‪Put Y in AX‬‬

‫‪Add Z to AX‬‬

‫‪Put AX to W‬‬

‫‪Out W‬‬

‫‪Stop‬‬
‫ﺷﻜﻞ ‪ -7.1‬ﺑﺮ ﻣﺞ ﺑﺴﻴﻂ ﺑﻠﻐﺔ اﻟﺘﺠﻤﻴﻊ‬
‫‪21: INP‬‬ ‫‪X‬‬
‫‪22: INP‬‬ ‫‪Y‬‬
‫‪23: INP‬‬ ‫‪Z‬‬
‫‪24: MOV‬‬ ‫‪X‬‬ ‫‪AX‬‬
‫‪25: SUB‬‬ ‫‪Y‬‬ ‫‪AX‬‬
‫‪26: JBZ‬‬ ‫‪AX‬‬ ‫‪29‬‬
‫‪27: MOV‬‬ ‫‪X‬‬ ‫‪AX‬‬
‫‪28: JMP‬‬ ‫‪30‬‬
‫‪29: MOV‬‬ ‫‪Y‬‬ ‫‪AX‬‬
‫‪30: ADD‬‬ ‫‪Z‬‬ ‫‪AX‬‬
‫‪31: STO‬‬ ‫‪AX‬‬ ‫‪W‬‬
‫‪32: OUT‬‬ ‫‪W‬‬
‫‪33: STP‬‬

‫‪11‬‬
‫‪Memory‬‬

‫‪21‬‬ ‫‪Inp 41‬‬ ‫‪41‬‬

‫‪22‬‬ ‫‪Inp 42‬‬ ‫‪42‬‬

‫‪23‬‬ ‫‪Inp 43‬‬ ‫‪43‬‬

‫‪24‬‬ ‫‪Mov 41 AX‬‬ ‫‪44‬‬

‫‪CPU‬‬
‫‪ALU‬‬
‫‪AX‬‬
‫‪CCU‬‬

‫‪21‬‬
‫‪Instruction‬‬ ‫‪Instruction‬‬
‫‪register‬‬ ‫‪register‬‬
‫‪counter‬‬

‫ﺷﻜﻞ ‪ – 8.1‬ﺣﺎﻟﺔ اﳊﺎﺳﺐ ﻋﻨﺪ ﺑﺪاﻳﺔ ﺗﺸﻐﻴﻞ اﻟﱪ ﻣﺞ‬


‫اﻷﻣــﺮ ‪ 26‬ﻫــﻮ ﻗﻔــﺰ ﻣﺸــﺮوط‪ .‬اﻟﻘﻔــﺰ ﻣﻌﻨــﺎﻩ أن ﻧﻐــﲑ ﳏﺘــﻮى ﺳــﺠﻞ ﻋﻨـﻮان اﻷﻣــﺮ ﻟﻜــﻰ ﺗﻘــﻮم ال‪ CCU‬ﺑﺘﻨﻔﻴــﺬ أﻣــﺮ ﰱ ﻣﻜــﺎن‬
‫آﺧﺮ ﻣﻦ اﻟﱪ ﻣﺞ ﰱ اﳋﻄﻮة اﻟﺘﺎﻟﻴﺔ‪ .‬اﻟﻘﻔﺰ اﳌﺸﺮوط ﻣﻌﻨﺎﻩ أﻻ ﻧﻌﺪل ﳏﺘﻮى ﺳﺠﻞ ﻋﻨﻮان اﻷﻣﺮ إﻻ إذا ﲢﻘــﻖ ﺷــﺮط ﻣﻌـﲔ و ﻫــﻮ ﻫﻨــﺎ أن‬
‫ﻳﻜــﻮن ﳏﺘــﻮى اﻟﺴــﺠﻞ ‪ AX‬ﺳــﺎﻟﺒﺎ )‪ .(JBZ= Jump if Below Zero‬ﻓــﺈذا ﻛﺎﻧــﺖ ﻗــﻴﻢ اﳌــﺪﺧﻼت ﲝﻴــﺚ ‪ X > Y‬ﻓﻠــﻦ ﻳــﺘﻢ‬
‫اﻟﻘﻔﺰ‪ .‬و ﺳﺘﻘﻮم اﻟﻮﺣﺪة اﳌﺮﻛﺰﻳﺔ ﺑﺘﻨﻔﻴﺬ اﻷﻣﺮ ‪ .27‬أﻣﺎ إذا ﻗﻤﻨﺎ ﺑﺘﻨﻔﻴﺬ اﻟــﱪ ﻣﺞ ﰱ ﻣــﺮة أﺧــﺮى ﲝﻴــﺚ ‪ X < Y‬ﻓﺴــﻴﺘﻢ اﻟﻘﻔــﺰ إﱃ اﳋﺎﻧــﺔ‬
‫‪ 29‬ﻛﻤــﺎ ﻫــﻮ ﻣﻮﺿــﺢ ﰱ اﻷﻣــﺮ رﻗــﻢ ‪ .26‬ﰱ اﳊﺎﻟــﺔ اﻷوﱃ )‪ (X>Y‬ﺳــﻨﻨﻔﺬ اﻷﻣــﺮ ‪ 27‬و اﻟــﺬى ﻳﻘﻀــﻰ ﺑﻨﻘــﻞ ﳏﺘــﻮ ت ‪) X‬اﳋﺎﻧــﺔ‬
‫‪ (41‬إﱃ اﻟﺴﺠﻞ ‪ AX‬ﰒ ﻧﻨﻔﺬ اﻷﻣﺮ ‪ 28‬و ﻫﻮ اﻟﻘﻔﺰ ﻏﲑ اﳌﺸﺮوط ﻟﻠﺨﺎﻧﺔ ‪ .30‬أﻣــﺎ ﰱ اﳊﺎﻟــﺔ اﻟﺜﺎﻧﻴــﺔ )‪ (X<Y‬ﻓﺴــﻨﻨﻔﺬ اﻷﻣــﺮ ‪29‬‬
‫و اﻟ ــﺬى ﻳﻘﻀ ــﻰ ﺑﻨﻘ ــﻞ ﳏﺘ ــﻮ ت اﳋﺎﻧ ــﺔ ‪) Y‬اﳋﺎﻧ ــﺔ ‪ (42‬إﱃ اﻟﺴ ــﺠﻞ ‪ .AX‬ﰱ ﲨﻴ ــﻊ اﻷﺣـ ـﻮال ﻧﺼ ــﻞ ﻟﻸﻣ ــﺮ ‪ 30‬و ﻗ ــﺪ وﺿ ــﻌﻨﺎ ﰱ‬
‫اﻟﺴﺠﻞ ‪ AX‬ﻗﻴﻤﺔ ‪ X‬أو ‪ Y‬أﻳﻬﻤﺎ أﻛﱪ‪.‬‬
‫اﻷﻣــﺮ ‪ 24‬ﻫــﻮ ﻧﻘــﻞ ﳏﺘــﻮى اﻟــﺬاﻛﺮة رﻗــﻢ ‪ 41‬إﱃ اﻟﺴــﺠﻞ اﳌﺴــﻤﻰ ‪ .AX‬اﻷﻣــﺮ ‪ 25‬ﻫــﻮ ﻃــﺮح ﳏﺘــﻮى اﻟــﺬاﻛﺮة ‪ 42‬ﻣــﻦ‬
‫اﻟﺴﺠﻞ ‪ .AX‬ﺗﺞ اﻟﻄﺮح ﻳﻈﻞ ﰱ اﻟﺴﺠﻞ ‪ .AX‬ﻻﺣﻆ أن ‪ AX‬ﳛﻮى اﻵن ‪.X-Y‬‬
‫اﻷﻣــﺮ ‪ 30‬ﻳﻘﻀــﻰ ﺿــﺎﻓﺔ ﳏﺘــﻮ ت ‪) Z‬اﳋﺎﻧــﺔ رﻗــﻢ ‪ (43‬إﱃ اﻟﺴــﺠﻞ‪ . AX‬ﺗــﺞ اﳉﻤــﻊ ﻳﻮﺿــﻊ ﰱ اﻟﺴــﺠﻞ‪ .‬و ﺑﻌــﺪ ذﻟــﻚ‬
‫اﻷﻣــﺮ ‪ 31‬ﻳــﺆدى إﱃ ﻧﻘــﻞ ﳏﺘــﻮى اﻟﺴــﺠﻞ إﱃ اﳋﺎﻧــﺔ ‪) W‬اﳋﺎﻧــﺔ رﻗــﻢ ‪ .(44‬اﻷﻣــﺮ ‪ 32‬ﻳﻨــﺘﺞ ﻋﻨــﻪ ﻛﺘﺎﺑــﺔ اﻟﻨــﺎﺗﺞ ﻋﻠــﻰ وﺣــﺪة اﻹﺧـﺮاج‬
‫)اﻟﺸﺎﺷﺔ(‪ .‬و ﰱ اﻟﻨﻬﺎﻳﺔ اﻷﻣﺮ ‪ 33‬ﻳﻘﻀﻰ ﺎء اﻟﻌﻤﻞ ﻟﱪ ﻣﺞ‪.‬‬

‫‪12‬‬
‫‪Memory‬‬

‫‪21‬‬ ‫‪Inp 41‬‬ ‫‪41‬‬

‫‪22‬‬ ‫‪Inp 42‬‬ ‫‪42‬‬

‫‪23‬‬ ‫‪Inp 43‬‬ ‫‪43‬‬

‫‪24‬‬ ‫‪Mov 41 AX‬‬ ‫‪44‬‬

‫‪c‬‬ ‫‪CPU‬‬
‫‪ALU‬‬
‫‪AX‬‬
‫‪CCU‬‬

‫‪a‬‬ ‫‪b‬‬
‫‪INP X‬‬ ‫‪22‬‬

‫‪Instruction‬‬ ‫‪Instruction‬‬
‫‪register‬‬
‫‪register‬‬
‫‪counter‬‬

‫ﺷﻜﻞ ‪ – 9.1‬ﺣﺎﻟﺔ اﳊﺎﺳﺐ ﺑﻌﺪ اﻧﺘﻬﺎء اﳋﻄﻮة ‪ 4‬ﻣﻦ ﺗﻨﻔﻴﺬ اﻷﻣﺮ اﻷول‬
‫ﻛﺎن ﻫﺬا ﻫﻮ ﺷﺮح ﺑﻘﺪر ﻛﺒﲑ ﻣﻦ اﻟﺘﺒﺴﻴﻂ )و ﻟﺘﺎﱃ ﻓﻴﻪ ﺷﺊ ﻣﻦ اﻹﺧﻼل( ﻟﻠﺨﻄﻮات اﻟﱴ ﻳﺘﺒﻌﻬﺎ اﳊﺎﺳﺐ ﻟﺘﻨﻔﻴﺬ ﺑــﺮ ﻣﺞ‪.‬‬
‫ﻟﻴﺲ اﳌﻘﺼﻮد ﻣﻨﻪ ﺳﻮى اﺳﺘﻴﻌﺎب ﺑﻌﺾ اﳌﻔﺎﻫﻴﻢ اﻷﺳﺎﺳﻴﺔ و اﻟﱴ ﻧﻠﺨﺼﻬﺎ ﻓﻴﻤﺎ ﻳﻠﻰ‪:‬‬
‫‪ -1‬ﻳﻮﺿﻊ اﻟﱪ ﻣﺞ ﰱ اﻟﺬاﻛﺮة ﻣﺜﻠﻪ ﻣﺜﻞ اﳋﺎ ت اﻟﱴ ﲢﻮى اﻟﺒﻴﺎ ت‬
‫‪ _2‬ﻳﻜﺘﺐ اﻟﱪ ﻣﺞ اﳌﻌﺪ ﻟﻠﺘﻨﻔﻴﺬ ﺑﻠﻐﺔ اﻵﻟﺔ و ﻫﻰ اﻟﱴ ﳝﻜﻦ أن ﺗﻔﻬﻤﻬﺎ وﺣﺪة اﻟﺘﺤﻜﻢ اﳌﺮﻛﺰﻳﺔ‬
‫‪ -3‬ﺗﺘﻜﻮن ﻟﻐﺔ اﻵﻟﺔ ﻣﻦ ﻋﺪد ﺑﺴﻴﻂ ﻣﻦ اﻷواﻣﺮ اﻟﱴ ﳝﻜﻦ ﺗﻨﻔﻴﺬﻫﺎ ﻣﺒﺎﺷﺮة‬
‫‪ -4‬إذا أرد أن ﻧﻘﻮم ﺑﻌﻤﻠﻴﺔ ﻣﺮﻛﺒﺔ )ﻣﺜﻞ اﳌﻘﺎرﻧﺔ ﺑﲔ ﻋﺪدﻳﻦ ﰱ ﻫﺬا اﳌﺜﺎل( ﻓﻌﻠﻴﻨﺎ أن ﳓﻠﻠﻬﺎ ﻟﻌﺪة أواﻣﺮ ﺑﺴﻴﻄﺔ‬
‫‪ -5‬ﺗﺴﻬﻞ ﻟﻐﺔ اﻟﺘﺠﻤﻴﻊ ﻣﻦ ﻋﻤﻠﻴﺔ ﻛﺘﺎﺑﺔ اﻟﱪاﻣﺞ ) ﳌﻘﺎرﻧﺔ ﺑﻠﻐﺔ اﻵﻟﺔ( و إن ﻛﺎﻧﺖ ﻻ ﺗﻜﻔﻲ ﳌﻦ ﻳﺮﻳﺪ ﻛﺘﺎﺑﺔ ﺑﺮاﻣﺞ ﻣﻌﻘﺪة‪.‬‬
‫إن ﻟﻐﺔ اﻵﻟﺔ و ﻟﻐﺔ اﻟﺘﺠﻤﻴﻊ و أﻳﺔ ﻟﻐــﺔ أﺧــﺮى ﺗﻌﺘﻤــﺪ ﻣﺒﺎﺷــﺮة ﻋﻠــﻰ ﳎﻤﻮﻋــﺔ اﻷواﻣــﺮ اﻷﺳﺎﺳــﻴﺔ ‪basic instruction set‬‬
‫ﺗﺴﻤﻰ ﻟﻐﺔ ﻣﻨﺨﻔﻀﺔ اﳌﺴﺘﻮى ‪ .low level language‬ﻟﻴﺲ ذﻟﻚ ﻟﻠﺘﺤﻘﲑ ﻣــﻦ ﺷــﺄ ﺎ و ﻟﻜــﻦ ﻟﻠﺘﻤﻴﻴــﺰ ﺑﻴﻨﻬــﺎ و ﺑــﲔ اﻟﻠﻐــﺎت ﻣﺮﺗﻔﻌــﺔ‬
‫اﳌﺴﺘﻮى ‪ high level language‬و اﻟﱴ ﲢﻮى ﺗﻨﻮﻋــﺎ أﻛــﱪ ﻣــﻦ اﻷواﻣــﺮ ﲝﻴــﺚ ﺗﻘــﱰب ﺑﻘــﺪر اﻹﻣﻜــﺎن ﻣــﻦ اﻟﻠﻐــﺎت اﻟﻄﺒﻴﻌﻴــﺔ ﻟﻠﺒﺸــﺮ‪.‬‬
‫ﻣﻦ أﻣﺜﻠﺔ اﻟﻠﻐﺎت ﻣﺮﺗﻔﻌﺔ اﳌﺴــﺘﻮى ﻟﻐــﺔ اﻟﻔــﻮرﺗﺮان ‪ FORTRAN‬و ﻟﻐــﺔ اﻟﺒﺎﺳــﻜﺎل ‪ Pascal‬و ﻟﻐــﺔ ال‪ .C‬ﻻ ﳝﻜــﻦ أن ﻳﻘــﻮم اﳊﺎﺳــﺐ‬
‫ﺑﺘﻨﻔﻴﺬ ﺑﺮ ﻣﺞ ﻣﻜﺘﻮب ﺑﻠﻐﺔ ﻣﺮﺗﻔﻌﺔ اﳌﺴﺘﻮى ﻣﺒﺎﺷﺮة‪ ،‬ﻷﻧﻪ ﻻ ﻳﻔﻬﻤﻬﺎ ﻛﻤﺎ ﻻ ﻳﻔﻬــﻢ ﻟﻐــﺔ اﻟﺒﺸــﺮ‪ .‬و ﻟﻜــﻦ ﳚــﺐ ﲢﻮﻳــﻞ اﻟــﱪ ﻣﺞ اﳌﻜﺘــﻮب‬

‫‪13‬‬
‫ﺑﻠﻐــﺔ ﻋﺎﻟﻴــﺔ اﳌﺴــﺘﻮى إﱃ ﺑــﺮ ﻣﺞ ﻣﻜﺘــﻮب ﺑﻠﻐــﺔ اﻵﻟــﺔ ﻛﻤــﺎ ﺳــﻨﺮى ﰱ اﻟﻔﻘـﺮات اﻟﺘﺎﻟﻴــﺔ‪ .‬ﰱ اﻟﺒﻨــﺪ اﻟﺘــﺎﱃ ﺳــﻨﺪرس ﻛﻴــﻒ ﳝﻜــﻦ ﺑﻨــﺎء ﺑـﺮاﻣﺞ‬
‫ﻣﻌﻘﺪة ﺑﺪءا ﻣﻦ ﻣﺮﺣﻠﺔ اﻟﺘﻔﻜﲑ ﰱ أﺳﻠﻮب ﺣﻞ ﻣﺸﻜﻠﺔ إﱃ أن ﻧﺼﻞ ﻟﻠﱪ ﻣﺞ اﳌﻜﺘﻮب ﺑﻠﻐﺔ اﻵﻟﺔ‪.‬‬

‫‪14‬‬
‫‪.1‬د‪ .‬ﺑﻨﺎء اﻟﱪاﻣﺞ ‪Constructing programs‬‬
‫ﰱ ﻫ ــﺬا اﻟﺒﻨ ــﺪ ﺳ ــﻨﺪرس ﻛﻴ ــﻒ ﳝﻜ ــﻦ ﺑﻨ ــﺎء اﻟ ـﱪاﻣﺞ‪ ،‬ﺑ ــﺪءا ﻣ ــﻦ ﻣﺮﺣﻠ ــﺔ إﻧﺸ ــﺎء اﻷﳉ ــﻮرﻳﺘﻢ ‪ Algorithm‬إﱃ اﻟﺘﻨﻔﻴــﺬ‪ .‬ﺳ ــﻨﺒﺪأ‬
‫ﺑﺘﻌﺮﻳﻒ اﻷﳉﻮرﻳﺘﻢ ﰒ ﻧﻨﺘﻘﻞ ﻷﺳﺎﻟﻴﺐ ﺗﻄﻮﻳﺮ اﻟﱪاﻣﺞ‪ .‬ﺳــﻨﺮﺟﺊ ﺷــﺮح ﻣﺮاﺣــﻞ ﺣﻴــﺎة ﺑــﺮ ﻣﺞ ﻣﻨــﺬ اﻟﺘﻔﻜــﲑ ﻓﻴــﻪ إﱃ أن ﻳﺘﻮﻗــﻒ اﻟﻌﻤــﻞ ﺑــﻪ و‬
‫إﺳﺘﺒﺪاﻟﻪ ﺑﱪاﻣﺞ أﺧﺮى ﻟﻔﻘﺮة ﻻﺣﻘﺔ ﰱ اﳌﻨﻬﺞ‪.‬‬

‫‪.1‬د‪ .1.‬اﻷﳉﻮرﻳﺘﻢ ‪Algorithm‬‬


‫اﻷﳉــﻮرﻳﺘﻢ ﻫــﻮ ﳎﻤﻮﻋــﺔ اﳋﻄ ـﻮات اﻟﻼزﻣــﺔ ﳊــﻞ ﻣﺸــﻜﻠﺔ ﻣــﺎ أو ﻷداء ﻣﻬﻤــﺔ ﻣــﺎ‪ .‬ﻳﺸــﱰط ﰱ ﻫــﺬﻩ اﳋﻄ ـﻮات ﻋــﺪم اﻹ ــﺎم و‬
‫اﳌﻮﺿﻮﻋﻴﺔ و اﻟﺘﻜﺮارﻳﺔ و اﶈﺪودﻳﺔ‪ .‬ﺳﻨﻨﺎﻗﺶ ﻓﻴﻤﺎ ﻳﻠﻰ ﻣﻌﲎ ﻫﺬﻩ اﻟﺸﺮوط‪.‬‬
‫ﻋﺪم اﻹ ﺎم ﻳﻌــﲎ أن ﻳﻜــﻮن وﺻــﻒ اﳋﻄـﻮات ﻣــﻦ اﻟﻮﺿــﻮح و اﻟﺘﻔﺼــﻴﻠﻴﺔ ﲟــﺎ ﻻ ﻳﺴــﻤﺢ ﺑﺴــﻮء ﻓﻬــﻢ ﻟﻠﻤﻌــﲎ اﳌﻘﺼــﻮد‪ .‬ﻳﻘﺘﻀــﻰ‬
‫ذﻟ ــﻚ أن ﻳﻜ ــﻮن اﻟﻮﺻ ــﻒ ﺳ ــﺘﺨﺪام ﻋﻤﻠﻴ ــﺎت أوﻟﻴ ــﺔ ﺳ ــﺒﻖ ﺗﻌﺮﻳﻔﻬ ــﺎ ﺑﺪﻗ ــﺔ‪ .‬و ﻟ ــﺬﻟﻚ ﻓ ــﺈن اﻟﻠﻐ ــﺎت اﻟﻄﺒﻴﻌﻴ ــﺔ )اﻟﻌﺮﺑﻴ ــﺔ أو اﻹﳒﻠﻴﺰﻳ ــﺔ أو‬
‫اﻟﻔﺮﻧﺴﻴﺔ ‪..‬اﱁ( وﺳﻴﻂ ﺳﻴﺊ ﻟﺸﺮح اﻷﳉﻮرﻳﺘﻢ‪ .‬ﻷن اﻟﻠﻐﺎت اﻟﻄﺒﻴﻌﻴﺔ ﺗﺸﱰك ﰱ إﻣﻜﺎﻧﻴﺔ ﺑﻨﺎء ﲨﻞ ﲢﺘﻤﻞ أﻛﺜﺮ ﻣﻦ ﻣﻌــﲎ‪ ،‬ﺳـﻮاء ﺑﻘﺼــﺪ‬
‫أو ﺑﻐﲑ ﻗﺼﺪ! ﻫﺬﻩ اﳋﺎﺻﻴﺔ ﳝﻜﻦ أن ﺗﻜﻮن ﳏﺒﺬة ﺣﻴﻨﻤﺎ ﻳﺘﻌﻠﻖ اﻷﻣﺮ ﺑﺘﺒﺎدل اﳌﻌﻠﻮﻣﺎت ﺑﲔ اﻟﺒﺸﺮ )ﻣﺜﻞ ﺑﻌﺾ اﻟﻨﺼﻮص اﻷدﺑﻴــﺔ اﻟــﱴ‬
‫ﲢﻤﻞ ﰱ ﻃﻴﺎ ﺎ أﻛﺜﺮ ﻣﻦ ﻣﻌﲎ( و ﻟﻜﻦ ﻟــﻴﺲ ﻋﻨــﺪﻣﺎ ﻧﺘﻮﺟــﻪ ﻟﻶﻟــﺔ! ﻟﺘﺠــﺎوز ﻫــﺬﻩ اﳌﺸــﻜﻠﺔ اﺧﱰﻋــﺖ ﻟﻐــﺎت اﻟﱪﳎــﺔ و ﻫــﻰ ﻟﻐــﺎت ﲢــﻮى‬
‫ﻋﺪد ﺿﺌﻴﻞ ﺟﺪا ﻣﻦ اﻟﻜﻠﻤﺎت و ﻣﻦ اﻟﻘﻮاﻋــﺪ و اﻟﱰاﻛﻴـﺐ اﻟﻠﻐﻮﻳــﺔ ﳌﻘﺎرﻧــﺔ ﻳــﺔ ﻟﻐــﺔ ﻃﺒﻴﻌﻴــﺔ‪ ،‬و ﻟﻜﻨﻬــﺎ ﲤﺘــﺎز ن أﻳــﺔ ﲨﻠــﺔ ﻻ ﳝﻜــﻦ أن‬
‫ﺗﻨﻄﻮى إﻻ ﻋﻠﻰ ﻣﻌﲎ واﺣﺪ ﻓﻘﻂ‪.‬‬
‫اﳌﻮﺿــﻮﻋﻴﺔ ﺗﻌــﲎ أن ﺗﻨﻔﻴــﺬ اﻷﳉــﻮرﻳﺘﻢ ﻻ ﻳﻨﺒﻐــﻰ أن ﻳﻌﺘﻤــﺪ ﻋﻠــﻰ اﻟﺸــﺨﺺ أو اﻵﻟــﺔ اﻟــﱴ ﺗﻨﻔــﺬﻩ‪ .‬اﻟﻘــﺪرات اﻹﺑﺪاﻋﻴــﺔ ﻟﻠﺒﺸــﺮ ﻻ‬
‫ﻳﻨﺒﻐﻰ أن ﺗﺴﺘﺤﺚ أﺛﻨﺎء ﺗﻨﻔﻴﺬ اﻷﳉﻮرﻳﺘﻢ )اﻹﺑﺪاع ﻳﻜﻮن ﻓﻘﻂ ﰱ ﻣﺮﺣﻠﺔ ﺑﻨﺎء اﻷﳉﻮرﻳﺘﻢ( و إﻻ ﻛﺎن ﺗﻨﻔﻴــﺬ اﻷﳉــﻮرﻳﺘﻢ و ﻟﺘــﺎﱃ ﻧﺘﺎﺋﺠــﻪ‬
‫ﻏﲑ ﻣﻮﺿﻮﻋﻴﺔ‪ .‬ﳝﺜﻞ ذﻟﻚ اﺧﺘﻼﻓﺎ ﺑﲔ ﺗﻌﻠﻴﻤﺎت ﻣﻮﺟﻬﺔ ﻟﺒﺸﺮ ﻳﻔﱰض ﻓﻴﻬﻢ اﻟﻘــﺪرة ﻋﻠــﻰ اﻟﺘﺼــﺮف ﰱ ﻣﻮاﻗــﻒ ﱂ ﻳﺴــﺒﻖ اﻟﺘﻌــﺮض ﳍــﺎ‪ ،‬و‬
‫ﺑﲔ اﻵﻟﺔ اﻟﱴ ﳚﺐ أن ﺗﻌﻄﻰ ﺗﻌﻠﻴﻤﺎت واﺿﺤﺔ ﳉﻤﻴﻊ اﳊﺎﻻت اﳌﻤﻜﻨﺔ‪.‬‬
‫اﻟﺘﻜﺮارﻳﺔ ﺗﻌﲎ أﻧــﻪ إذا ﺗﻜــﺮر ﺗﻨﻔﻴــﺬ اﻷﳉــﻮرﻳﺘﻢ أﻛﺜــﺮ ﻣــﻦ ﻣــﺮة ﻋﻠــﻰ ﻧﻔــﺲ اﻟﺒﻴــﺎ ت ﻓــﻼ ﺑــﺪ أن ﳓﺼــﻞ ﻋﻠــﻰ ﻧﻔــﺲ اﻟﻨﺘــﺎﺋﺞ‪ .‬أى‬
‫إذا ﻛﺎن ﻫﻨﺎك ﻋﻨﺼﺮا ﻋﺸﻮاﺋﻴﺎ ﰱ ﺗﻌﺮﻳﻒ اﳋﻄﻮات اﳌﻜﻮﻧﺔ ﻟﻸﳉﻮرﻳﺘﻢ ﻓﻼ ﺑﺪ أﻻ ﻳﺆﺛﺮ ذﻟﻚ ﻋﻠﻰ اﻟﻨﺘﺎﺋﺞ‪.‬‬
‫و ﰱ اﻟﻨﻬﺎﻳﺔ ﻓﺈن اﶈﺪودﻳﺔ ﺗﻌﲎ أن ﻋﺪد اﳋﻄﻮات اﻟﻼزﻣــﺔ ﳊــﻞ اﳌﺸــﻜﻠﺔ أو ﻷداء اﳌﻬﻤــﺔ ﳚــﺐ أن ﻳﻜــﻮن ﳏــﺪودا‪ ،‬أى ﻟــﻴﺲ‬
‫ﻻ ﺎﺋﻴﺎ‪ .‬و ﻋﻠﻰ ذﻟــﻚ إذا اﺣﺘــﻮى اﻷﳉــﻮرﻳﺘﻢ ﻋﻠــﻰ ﺗﻘﺮﻳــﺐ ﻣﺘﺘــﺎﱃ ﻣــﺜﻼ )ﲡﺮﺑــﺔ و ﺧﻄــﺄ( ﻓــﻼ ﺑــﺪ أن ﻳﻀــﻤﻦ اﻷﳉــﻮرﻳﺘﻢ اﻟﻮﺻــﻮل ﻟﻨﺘﻴﺠــﺔ‬
‫ﺑﻌــﺪ ﻋــﺪد ﺧﻄـﻮات ﻣﻨﺎﺳــﺐ‪ .‬ﻳﻘﺘﻀــﻰ ذﻟــﻚ ﺿــﺮورة اﻻﻗ ـﱰاب ﻣــﻦ اﳊــﻞ اﳌﺮﺟــﻮ ﰱ اﶈــﺎوﻻت اﳌﺘﻌــﺪدة‪ ،‬ﻛﻤــﺎ ﻻ ﺑــﺪ أن ﻳﻌﻄــﻰ اﻟﻔﻴﺼــﻞ‬
‫اﻟﺬى ﳝﻜﻦ ﻋﻨﺪﻩ اﻟﺘﻮﻗﻒ و اﻋﺘﺒﺎر اﻟﻨﺎﺗﺞ ﻫﻮ اﳌﻄﻠﻮب ﺣﺴﺎﺑﻪ ﻟﺪﻗﺔ اﳌﺮﺟﻮة‪.‬‬
‫ﻣــﻦ أﻣﺜﻠــﺔ اﻷﳉﻮرﻳﺘﻤــﺎت ﰱ اﳊﻴــﺎة اﻟﻌﺎﻣــﺔ ﺗﻌﻠﻴﻤــﺎت اﻻﺳــﺘﺨﺪام اﳌﺼــﺎﺣﺒﺔ ﻟﻸﺟﻬــﺰة أو وﺻــﻒ ﻃﺮﻳﻘــﺔ اﻟﻮﺻــﻮل إﱃ ﻣﻜــﺎن أو‬
‫وﺻﻔﺔ ﻃﻬﻰ ﻃﻌﺎم )ﻋﻠﻰ أﻻ ﲢﺘﻮى ﻋﻠﻰ ﲨﻞ ﻣﻦ ﻧﻮع‪ :‬و ﻋﻨﺪﺋــﺬ ﺗﺼــﺮف ﲟﻌﺮﻓﺘــﻚ ﻷﺟــﻞ ﻋﻤــﻞ ﻛــﺬا!( أو ﰱ اﺠﻤﻟــﺎل اﻟﺮ ﺿــﻰ أﺳــﻠﻮب‬
‫ﺣﻞ ﻣﻌﺎدﻟﺔ ﻣﻦ اﻟﺪرﺟﺔ اﻟﺜﺎﻧﻴﺔ‪.‬‬
‫ﻣﻦ اﻟﻀﺮورة ﲟﻜﺎن أن ﻳﻜﻮن اﳌﺮء ﺻﻮرة واﺿﺤﺔ ﰱ ذﻫﻨﻪ ﻋﻦ اﻷﳉﻮرﻳﺘﻢ اﳌﻄﻠﻮب ﺗﻨﻔﻴﺬﻩ ﻋﻠﻰ ﺑﻴــﺎ ت اﳌــﺪﺧﻞ ﻗﺒــﻞ اﻟﺸــﺮوع‬
‫ﰱ ﻛﺘﺎﺑﺔ ﺑﺮ ﻣﺞ‪ .‬ﻓــﺎﻟﱪ ﻣﺞ ﻟــﻴﺲ إﻻ ﺗﺮﲨــﺔ ﻟﻸﳉــﻮرﻳﺘﻢ ﺑﻠﻐــﺔ ﳏــﺪدة ﻣــﻦ ﻟﻐــﺎت اﳊﺎﺳــﺐ‪ .‬ﳝﻜــﻦ داﺋﻤــﺎ إﻋــﺎدة ﻛﺘﺎﺑﺘــﻪ ﻣــﻦ ﻟﻐــﺔ ﻷﺧــﺮى‪ ،‬و‬
‫ﻟﻜــﻦ ﻣــﺎ ﻳﻬــﻢ ﻫــﻰ اﻷﻓﻜــﺎر اﳌﻜﻮﻧــﺔ ﻟﻸﳉــﻮرﻳﺘﻢ‪ .‬ﻫــﺬﻩ اﻷﻓﻜــﺎر ﳝﻜــﻦ وﺻــﻔﻬﺎ ﺳــﺘﺨﺪام وﺻــﻒ ﲣﻄﻴﻄــﻰ ﻟﻠﻌﻤﻠﻴــﺎت ‪flow chart‬أو‬

‫‪15‬‬
‫ﺳــﺘﺨﺪام ﻟﻐــﺔ ﳏﺎﻳــﺪة ﺗﺴــﻤﻰ اﻟﻜــﻮد اﻟﻜــﺎذب ‪ pseudo-code‬و ﻫــﻰ ﻟﻐــﺔ ﻗﺮﻳﺒــﺔ ﺟــﺪا ﻣــﻦ اﻟﻠﻐــﺎت اﻟﻄﺒﻴﻌﻴــﺔ و ﻟﻜــﻦ ﺗﺘﻤﻴــﺰ ﻋﻨﻬــﺎ‬
‫ﻧﻌﺪام اﻹ ﺎم‪ .‬ﻣﻨﻬﺎ ﳝﻜﻦ ﺑﺴﻬﻮﻟﺔ ﺷﺪﻳﺪة ﻛﺘﺎﺑﺔ اﻟﱪ ﻣﺞ اﳌﻨﺎﻇﺮ ﻳﺔ ﻟﻐﺔ ﻣﻦ ﻟﻐﺎت اﻟﱪﳎﺔ‪.‬‬
‫اﻷﳉﻮرﻳﺘﻤﺎت اﳉﻴﺪة )و ﻟﺘﺎﱃ اﻟﱪاﻣﺞ اﳉﻴﺪة( ﻫﻰ اﳌﻜﺘﻮﺑﺔ ﺑﺼﻮرة ﻣﻬﻴﻜﻠﺔ‪ ،‬ﻛﻤﺎ ﺳﻨﺘﻌﺮض ﰱ اﻟﺒﻨﺪ اﻟﺘﺎﱃ‪.‬‬

‫‪.1‬د‪ .2.‬اﻟﱪﳎﺔ اﳍﻴﻜﻠﻴﺔ ‪structured programming‬‬

‫‪Y‬‬ ‫‪N‬‬
‫?‪Is.‬‬
‫‪Sequential‬‬
‫‪block‬‬ ‫‪Conditional‬‬
‫‪block‬‬

‫?‪N1‬‬
‫‪In‬‬ ‫‪N‬‬
‫?‪Is.‬‬
‫‪te‬‬
‫‪ge‬‬ ‫?‪N2‬‬ ‫‪Y‬‬
‫‪r‬‬ ‫?‪Is.‬‬
‫‪ex‬‬ ‫‪Y‬‬
‫‪pr‬‬ ‫?‪N3‬‬ ‫‪N‬‬
‫‪es‬‬
‫‪Loop Test‬‬ ‫‪Loop Test‬‬
‫‪Multiple Choice‬‬ ‫‪at Top‬‬ ‫‪at Bottom‬‬

‫ﺷﻜﻞ ‪ -10.1‬ﺑﻠﻮﻛﺎت اﻟﱪﳎﺔ اﳍﻴﻜﻠﻴﺔ‬


‫اﻟﱪﳎــﺔ اﳍﻴﻜﻠﻴــﺔ ﺗــﺆدى ﻟﺴــﻬﻮﻟﺔ ﺑﻨــﺎء اﻟــﱪ ﻣﺞ ﰒ ﺳــﻬﻮﻟﺔ ﻗﺮاءﺗــﻪ وﺗﻌﺪﻳﻠــﻪ ﻓﻴﻤــﺎ ﺑﻌــﺪ‪ .‬درا ﻣــﺎ ﻧﻜﺘــﺐ اﻟـﱪاﻣﺞ ﻻﺳــﺘﻌﻤﺎﳍﺎ ﻣــﺮة‬
‫واﺣــﺪة ﻓﻘــﻂ‪ .‬ﻛﺜـﲑا ﻣــﺎ ﻳﻌــﻴﺶ ﻣﻌﻨــﺎ اﻟــﱪ ﻣﺞ ﻟﻔـﱰات ﻃﻮﻳﻠــﺔ ﳓﺘــﺎج ﺧﻼﳍــﺎ ﻟﺘﻌﺪﻳﻠــﻪ ﺳـﻮاء ﺑﺘﺼــﺤﻴﺢ ﺑﻌــﺾ اﻷﺧﻄــﺎء أو ﺿــﺎﻓﺔ وﻇــﺎﺋﻒ‬
‫ﺟﺪﻳﺪة‪ .‬ﻟﺘﺴﻬﻴﻞ ﻫﺬﻩ اﻟﺘﻌــﺪﻳﻼت ﳚــﺐ أن ﻳﻜــﻮن اﻟــﱪ ﻣﺞ ﻣﻘﺴــﻤﺎ ﻟﻌﻨﺎﺻــﺮ رﺋﻴﺴــﻴﺔ واﺿــﺤﺔ اﳌﻌــﺎﱂ ﺑــﺪون ﺗــﺪاﺧﻼت ﻓﻴﻤــﺎ ﺑﻴﻨﻬــﺎ‪ .‬ﺣــﱴ‬
‫إذا اﺿــﻄﺮر ﻟﻠﺘــﺪاﺧﻞ ﻓﻴﺠــﺐ أن ﻳﻜــﻮن ذﻟــﻚ ﰱ أﺿــﻴﻖ اﳊــﺪود‪ .‬ﻳﺴــﻤﻰ ﻛــﻞ ﻋﻨﺼــﺮ ﺑﻠــﻮك ‪ .block‬ﻟﻜــﻞ ﺑﻠــﻮك ﻫﻨــﺎك ﻣــﺪﺧﻼت و‬
‫ﳐﺮﺟـﺎت و ﺑﻴﻨﻬﻤــﺎ ﻋﻤﻠﻴــﺎت ﻻ ﺗﻌﺘﻤــﺪ إﻻ ﻋﻠــﻰ اﳌــﺪﺧﻼت و ﻻ ﺗــﺆدى إﱃ ﺗﻐﻴــﲑ أى ﺷــﺊ ﻋــﺪا اﳌﺨﺮﺟــﺎت‪ .‬و ﺑــﺬﻟﻚ ﻓــﺈن ﺗﻌــﺪﻳﻞ أى‬
‫ﺑﻠــﻮك ﻻ ﻳﻨﺒﻐــﻰ أن ﻳﻜــﻮن ﻟــﻪ أدﱏ ﺛــﲑ ﻋﻠــﻰ اﻟﺒﻠﻮﻛــﺎت اﻷﺧــﺮى‪ .‬ﻛــﻞ ﺑﻠــﻮك ﳝﻜــﻦ أن ﻳﻘﺴــﻢ إﱃ ﺑﻠﻮﻛــﺎت ﻓﺮﻋﻴــﺔ و ﻫﻜــﺬا إﱃ أن ﻧﺼــﻞ‬
‫ﻟﺒﻠﻮك ﺻﻐﲑ ﺑﻪ ﻋﺪد ﳏﺪود ﻣﻦ اﻟﻌﻤﻠﻴﺎت ﳝﻜﻦ أن ﻧﻜﺘﺒﻬﺎ و ﻧﻌﺪﳍﺎ ﺑﺴﻬﻮﻟﺔ دون ﺗﻌﺪﻳﻞ اﻟﱪ ﻣﺞ ﻛﻜﻞ‪ .‬ﻛﻤــﺎ ﻻ ﻳﺼــﺢ دﺧــﻮل اﻟﺒﻠــﻮك‬
‫)أى ﺑﺪء ﺗﻨﻔﻴﺬ اﻟﻌﻤﻠﻴﺎت( أو اﳋﺮوج ﻣﻨﻪ )إ ﺎء اﻟﺘﻨﻔﻴﺬ( إﻻ ﰱ ﻧﻘﺎط ﳏــﺪدة ﺣــﱴ ﻻ ﺗﺘــﺪاﺧﻞ اﳋﻄـﻮات ﻣــﻊ اﻟﺒﻠﻮﻛــﺎت اﻷﺧــﺮى‪ .‬ﻏﺎﻟﺒــﺎ‬
‫ﻣﺎ ﻳﻜــﻮن ﻟﻜــﻞ ﺑﻠــﻮك ﻋﻼﻣــﺔ ﻟﺒﺪاﻳﺘــﻪ و أﺧــﺮى ﻟﻨﻬﺎﻳﺘــﻪ‪ .‬ﰱ ﻟﻐــﺔ اﻟﺒﺎﺳــﻜﺎل ‪ Pascal‬ﻣــﺜﻼ ﺗﺴــﺘﺨﺪم اﻟﻜﻠﻤــﺎت ‪ begin ..... end‬و ﰱ‬
‫ﻟﻐﺔ ال ‪ C‬ﺗﺴــﺘﺨﺪم اﻷﻗـﻮاس }‪ .{....‬ﻟــﺮﻏﻢ ﻣــﻦ ﺗـﻮاﻓﺮ أواﻣــﺮ ﻟﻠﻘﻔــﺰ ﰱ ﻛــﻞ اﻟﻠﻐــﺎت )ﻋــﺎدة ﻣــﺎ ﻳﺴــﻤﻰ ذﻟــﻚ ‪ (GOTO‬إﻻ أن اﻟﱪﳎــﺔ‬
‫اﳍﻴﻜﻠﻴﺔ ﲢﻮل دون اﺳﺘﺨﺪاﻣﻨﺎ ﳍﺬا اﻟﻨﻮع ﻣﻦ اﻷواﻣﺮ‪.‬‬

‫‪16‬‬
‫ﺗﻌﺘﻤــﺪ اﻟﺪراﺳــﺔ ﻓﻴﻤــﺎ ﺑﻌــﺪ ﺑﺸــﻜﻞ ﻛﺒــﲑ ﻋﻠــﻰ اﻟﱪﳎــﺔ اﳍﻴﻜﻠﻴــﺔ‪ ،‬و ﻟــﺬﻟﻚ ﻓﺈﻧﻨــﺎ ﺳــﻨﺪرس ﻟﺘﻔﺼــﻴﻞ أﻧـﻮاع اﻟﺒﻠﻮﻛــﺎت اﳌﺨﺘﻠﻔــﺔ و‬
‫اﺳﺘﺨﺪاﻣﺎ ﺎ ﰱ اﻷﺑـﻮاب اﻟﺘﺎﻟﻴــﺔ‪ ،‬وﻛــﺬا ﻛﻴــﻒ ﳝﻜــﻦ ﻛﺘﺎﺑﺘﻬــﺎ و اﺧﺘﺒﺎرﻫــﺎ ﻟﻠﺘﺄﻛــﺪ ﻣــﻦ ﺣﺴــﻦ ﲣﻄﻴﻄﻨــﺎ ﻟﻠــﱪ ﻣﺞ‪ .‬وﻟﻜﻨﻨــﺎ ﺳﻨﺴــﺘﻌﺮض ﻫﻨــﺎ‬
‫ﺑﻌــﺾ أﻧـﻮاع اﻟﺒﻠﻮﻛــﺎت اﻟﺸــﻬﲑة ﻋﻠــﻰ ﺳــﺒﻴﻞ اﳌﺜــﺎل ﻻ اﳊﺼــﺮ ــﺪف إﻋﻄــﺎء اﻟﻘــﺎرئ إﺣﺴﺎﺳــﺎ ﲟــﺎ ﺗﻌﻨﻴــﻪ ﻛﻠﻤــﺔ ﺑﻠــﻮك و ﻷﺧــﺺ ﻧﻘــﺎط‬
‫اﻟﺪﺧﻮل و اﳋﺮوج‪.‬‬
‫أﺑﺴــﻂ ﻧــﻮع ﻣــﻦ اﻟﺒﻠﻮﻛــﺎت اﳌﺴــﺘﺨﺪﻣﺔ ﰱ اﻟﱪﳎــﺔ اﳍﻴﻜﻠﻴــﺔ ﻫــﻮ ﺑﻠــﻮك اﻷواﻣــﺮ اﳌﺘﺘﺎﺑﻌــﺔ ‪ ،sequential block‬و ﻫــﻮ ﻳﺘﻜــﻮن‬
‫أﺳﺎﺳﺎ ﻣﻦ ﻋﺪد ﻣﻦ اﻷواﻣﺮ اﳌﺘﺘﺎﺑﻌﺔ اﻟﱴ ﺗﻨﻔﺬ ﻋﻠﻰ اﻟﱰﺗﻴﺐ‪ .‬ﻓﺈذا دﺧﻠﻨﺎ ﻟﻠﺒﻠﻮك )أى ﺑﺪأ ﺑﺘﻨﻔﻴﺬ أول أﻣﺮ ﻓﻴﻪ( ﻓﻠﻦ ﳔــﺮج ﻣﻨــﻪ إﻻ ﺑﻌــﺪ‬
‫ﺗﻨﻔﻴﺬ أﺧﺮ أﻣﺮ ﻓﻴﻪ‪.‬‬
‫ﻫﻨ ــﺎك أﻳﻀ ــﺎ ﺑﻠ ــﻮك اﻟﺸــﺮط ‪ conditional block‬و ﺳ ــﻨﻜﺘﺐ ﻫﻨ ــﺎ ﺻ ــﻮرﺗﻪ اﻟﻌﺎﻣــﺔ ﺳ ــﺘﺨﺪام ﻟﻐــﺔ اﻟﻔ ــﻮرﺗﺮان )ﺳ ــﻨﺘﻌﻤﺪ‬
‫اﺳﺘﺨﺪام ﻟﻐــﺎت ﳐﺘﻠﻔــﺔ ﰱ ﻫــﺬا اﻟﺒﻨــﺪ ﻟﻠﺘﻮﻛﻴــﺪ ﻋﻠــﻰ ﻛــﻮن اﳌﺒــﺎدئ اﻟــﱴ ﻧﺘﻨﺎوﳍــﺎ ﲞﺼــﻮص اﻟﱪﳎــﺔ اﳍﻴﻜﻠﻴــﺔ ﻫــﻰ ﻣﺒــﺎدئ ﻋﺎﻣــﺔ و ﻻ ﲣــﺘﺺ‬
‫ﺑﻠﻐﺔ ال‪ C‬ﻓﻘﻂ(‪:‬‬
‫‪if (condition) then‬‬
‫‪block1‬‬
‫‪else‬‬
‫‪block2‬‬
‫‪endif‬‬
‫اﻟﻜﻠﻤــﺎت اﳌﻜﺘﻮﺑــﺔ ﲞــﻂ ﲰﻴــﻚ و ﲝــﺮوف آر ل )ﻣﺜــﻞ ﻛﻠﻤــﺔ ‪ if‬ﻋﺎﻟﻴــﻪ( ﳚــﺐ أن ﺗﻜﺘــﺐ ﻛﻤــﺎ ﻫــﻰ‪ .‬أﻣــﺎ اﻟﻜﻠﻤــﺎت اﳌﻜﺘﻮﺑــﺔ‬
‫ﲝﺮوف ﻣﺎﺋﻠﺔ ﻋﺎﻟﻴﻪ ﻓﺘﻌﲎ اﺻﻄﻼﺣﺎ أﻧﻪ ﳚﺐ أن ﻳﻘــﻮم ﻛﺎﺗــﺐ اﻟــﱪ ﻣﺞ ﺣــﻼل ﺷــﺊ ﻣــﺎ ﳏﻠﻬــﺎ‪ .‬ﺗـﺪل اﻟﻜﻠﻤــﺔ ﺣﻴﻨﺌــﺬ ﻋﻠــﻰ وﺻــﻒ ﻫــﺬا‬
‫اﻟﺸــﻰء اﳌﻄﻠــﻮب إﺿــﺎﻓﺘﻪ‪ .‬ﰱ ﺑﻠــﻮك اﻟﺸــﺮط اﳌﻮﺻــﻮف أﻋــﻼﻩ‪ ،‬إذا ﲢﻘــﻖ اﻟﺸــﺮط ‪ condition‬ﻓﺴــﻴﻨﻔﺬ ‪ block1‬أﻣــﺎ إذا ﳌــﺎ ﻳﺘﺤﻘــﻖ‬
‫ﻓﺴﻴﻨﻔﺬ ‪ .block2‬ﳝﻜﻦ أن ﳜﺘﻔﻰ أى ﻣﻦ اﻟﺒﻠﻮﻛﲔ ﺣﺴﺐ اﳊﺎﻟﺔ‪ .‬و ﻟﻜﻦ ﰱ ﲨﻴﻊ اﻷﺣﻮال‪ ،‬إذا وﺻﻠﻨﺎ ﻟﺒﺪاﻳﺔ اﻟﺒﻠﻮك ﻓﻠــﻦ ﳔــﺮج ﻣﻨــﻪ‬
‫إﻻ ﻋﻨﺪ اﻟﻨﻘﻄﺔ ‪ ،end‬و ﻧﻜﻤﻞ ﺗﻨﻔﻴﺬ اﻟﱪ ﻣﺞ ﻣﻦ اﳋﻄﻮة اﻟﺘﺎﻟﻴﺔ ﻣﺒﺎﺷﺮة‪.‬‬
‫ﻫﻨــﺎك أﻳﻀــﺎ ﺑﻠــﻮك اﻻﺧﺘﻴــﺎر اﳌﺘﻌــﺪد ‪ selection block‬و ﻳﺼــﻠﺢ ﻻﺧﺘﻴــﺎر أى ﻣــﻦ اﻟﺒﻠﻮﻛــﺎت اﻟﻔﺮﻋﻴــﺔ ﺗﺒﻌــﺎ ﻟﻠﻘﻴﻤــﺔ اﳌﺨﺘﺰﻧــﺔ‬
‫ﳊﻈﻴــﺎ ﰱ ﺧﺎﻧــﺔ ذاﻛــﺮة ﻣــﺎ‪ .‬ﺗﺴــﻤﻰ ﺧــﺎ ت اﻟــﺬاﻛﺮة اﻟــﱴ ﲢــﻮى ﻗﻴﻤــﺎ ﻗﺎﺑﻠــﺔ ﻟﻠﺘﻐﻴــﲑ ﻣﺘﻐــﲑ ‪ .variable‬و ﻋﻠــﻰ ذﻟــﻚ ﻓــﺈن اﻟﺸــﻜﻞ اﻟﻌــﺎم‬
‫ﻟﻠﺒﻠﻮك ﻳﻜﻮن‬
‫‪case variable‬‬
‫‪begin‬‬
‫‪value1 : block1‬‬
‫‪value2 : block2‬‬
‫‪value3 : block3‬‬
‫‪......................‬‬
‫‪default:‬‬ ‫‪blockn‬‬
‫‪end‬‬
‫ﻓ ــﺈذا اﲣ ــﺬ اﳌﺘﻐ ــﲑ ‪ variable‬اﻟﻘﻴﻤ ــﺔ ‪ value1‬ﻓﺴ ــﻴﻨﻔﺬ ‪ .block1‬أﻣ ــﺎ إذا اﲣ ــﺬ اﻟﻘﻴﻤ ــﺔ ‪ value2‬ﻓﺴ ــﻴﻨﻔﺬ ‪ ،block2‬و‬
‫ﻫﻜﺬا‪ .‬إذا ﱂ ﺗﻜﻦ ﻗﻴﻤﺔ اﳌﺘﻐﲑ ﻣﺴﺎوﻳﺔ ﻷﻳﺔ ﻣﻦ اﻟﻘﻴﻢ اﻟﻮاردة ﻋﺎﻟﻴﻪ‪ ،‬ﻓﺴــﻴﻨﻔﺬ اﻟﺒﻠــﻮك ‪ .blockn‬و ﰱ ﲨﻴــﻊ اﻷﺣـﻮال ﻧﻨﺘﻘــﻞ إﱃ اﻟﻨﻘﻄــﺔ‬
‫‪ end‬ﺑﻌــﺪ اﻧﺘﻬــﺎء ﺗﻨﻔﻴــﺬ اﻟﺒﻠــﻮك اﳌﻌــﲎ‪ ،‬و ﻧﻜﻤــﻞ ﺗﻨﻔﻴــﺬ اﻟــﱪ ﻣﺞ ﻣــﻦ ﻫــﺬﻩ اﻟﻨﻘﻄــﺔ‪ .‬ﻟــﻴﺲ ﻣــﻦ اﻟﻀــﺮورى أن ﺗﻜــﻮن اﳋﺎﻧــﺔ ‪default‬‬
‫ﻣﻮﺟﻮدة‪ ،‬و ﻟﻜﻦ وﺟﻮدﻫﺎ أﺣﻴﺎ ﻣﺎ ﻳﻔﻴﺪ‪.‬‬
‫ﻫﻨــﺎك أﻳﻀــﺎ ﺑﻠﻮﻛــﺎت اﻟﻌﻤﻠﻴــﺎت اﻟﺘﻜﺮارﻳــﺔ ‪ .loop blocks‬و ﻫــﻰ أﻧ ـﻮاع ﻋﺪﻳــﺪة ﻧــﺬﻛﺮ ﻣﻨﻬــﺎ ﻓﻘــﻂ اﻟﺒﻠــﻮك "ﺑﻴﻨﻤــﺎ‪-‬اﻓﻌــﻞ"‬
‫‪ ،while block‬و ﻫﻮ ﻋﻠﻰ اﻟﺼﻮرة‪:‬‬
‫‪17‬‬
‫‪while condition‬‬
‫‪begin‬‬
‫‪block‬‬
‫‪end‬‬
‫ﻋﻨﺪﻣﺎ ﻧﺼﻞ ﻟﺒﺪاﻳﺔ اﻟﺒﻠﻮك )اﻷﻣﺮ ‪ (while‬ﻓــﺈن اﳊﺎﺳــﺐ ﳜﺘــﱪ اﻟﺸــﺮط ‪ .condition‬إذا ﲢﻘــﻖ اﻟﺸــﺮط‪ ،‬ﻓﺈﻧﻨــﺎ ﻧﻨﻔــﺬ اﻟﺒﻠــﻮك‬
‫‪ block‬ﰒ ﻧﻌــﺎود ﻓﺤــﺺ اﻟﺸــﺮط و ﻫﻜــﺬا ﺑﺼــﻮرة ﺗﻜﺮارﻳــﺔ إﱃ أن ﻳﺼــﺒﺢ اﻟﺸــﺮط ﻏــﲑ ﻣﺘﺤﻘــﻖ‪ .‬ﻋﻨﺪﺋــﺬ ﻻ ﻧﻨﻔــﺬ اﻟﺒﻠــﻮك وﻧ ـﻮاﱃ ﺗﻨﻔﻴــﺬ‬
‫اﻟﱪ ﻣﺞ ﺑﻌﺪ اﻟﻨﻘﻄﺔ ‪ .end‬ﻻﺣﻆ أن اﻟﺒﻠﻮك ﻗﺪ ﻻ ﻳﻨﻔﺬ ﳌﺮة إذا ﻛﺎن اﻟﺸﺮط ﻏﲑ ﻣﺘﺤﻘﻖ ﰱ اﻟﺒﺪاﻳﺔ‪.‬‬
‫و ﰱ اﻟﻨﻬﺎﻳﺔ ﻻ ﻳﺴﻌﻨﺎ إﻻ أن ﻧﺸﺪد ﻋﻠﻰ أﳘﻴﺔ ﻋﻤﻞ ﺧﻄﻮﺗﲔ ﻓﻮر اﻻﻧﺘﻬﺎء ﻣﻦ اﻟﱪ ﻣﺞ أو ﻣﻦ أى ﺟﺰء ﻣﻨــﻪ إذا ﻛــﺎن ﻛﺒـﲑا‪.‬‬
‫اﳋﻄــﻮة اﻷوﱃ ﻫــﻰ اﻻﺧﺘﺒــﺎر ‪ testing‬ﻟﻠﺘﺄﻛــﺪ ﻣــﻦ ﻛــﻮن اﻟــﱪ ﻣﺞ ﻳــﺆدى ﺑﺪﻗــﺔ اﳌﻬﻤــﺔ اﳌﻄﻠﻮﺑــﺔ وﻟــﻴﺲ ﺷــﻴﺌﺎ آﺧــﺮ‪ .‬اﳋﻄــﻮة اﻟﺜﺎﻧﻴــﺔ ﻫــﻰ‬
‫إﻋــﺪاد وﺛﻴﻘــﺔ ‪ documentation‬ﺗﺸــﺮح ﻣــﺎ ﻳﻘــﻮم ﺑــﻪ اﻟــﱪ ﻣﺞ )أو ﻫــﺬا اﳉــﺰء( و ﻛﻴﻔﻴــﺔ اﺳــﺘﺨﺪاﻣﻪ‪ .‬ﻗــﺪ ﺗﻜــﻮن ﻫــﺬﻩ اﻟﻮﺛﻴﻘــﺔ ﰱ ﺻــﻮرة‬
‫ﻣﻠــﻒ ﻣﻨﻔﺼــﻞ )ﺳـﻮاء ﰎ اﻻﺣﺘﻔــﺎظ ﺑــﻪ ﰱ اﳊﺎﺳــﺐ أو ﰱ ﺻــﻮرة ورﻗﻴــﺔ(‪ ،‬ﻛﻤــﺎ ﻗــﺪ ﺗﻜــﻮن ﰱ ﺻــﻮرة ﻣﻼﺣﻈــﺎت ‪ comments‬ﺗﻀــﺎف‬
‫ﳉﺴﻢ اﻟــﱪ ﻣﺞ‪ .‬ﺗﻈﻬــﺮ أﳘﻴــﺔ اﻟﺘﻮﺛﻴــﻖ ﻋﻨــﺪﻣﺎ ﻳﻌــﻮد اﳌــﱪﻣﺞ ﻟــﱪ ﻣﺞ ﺳــﺒﻖ ﻛﺘﺎﺑﺘــﻪ ﻣﻨــﺬ زﻣــﻦ ﻣــﺎ ﻓﻴﺠــﺪ ﻣــﻦ اﻟﺼــﻌﻮﺑﺔ ﲟﻜــﺎن أن ﻳﻌــﺮف ﻣــﺎذا‬
‫ﻳﺼﻨﻌﻪ ﻫﺬا اﻟﱪ ﻣﺞ ﲟﺠﺮد ﻗﺮاءة ﺳﻄﻮر اﻟﱪ ﻣﺞ‪ .‬ﻛﻤﺎ ﺗﻈﻬﺮ أﳘﻴــﺔ اﻟﺘﻮﺛﻴــﻖ ﲜــﻼء أﻳﻀــﺎ إذا اﺳــﺘﺨﺪم اﻟــﱪ ﻣﺞ ﺷــﺨﺺ آﺧــﺮ ﻏــﲑ اﻟــﺬى‬
‫ﻛﺘﺒﻪ أو ﻛﺎن اﻟﱪ ﻣﺞ ﻛﺒﲑا ﲝﻴﺚ ﻳﻜﺘﺒﻪ ﻓﺮﻳﻖ ﻣﻦ اﳌﱪﳎﲔ و ﻟﻴﺲ واﺣﺪا‪.‬‬

‫‪.1‬د‪ .3.‬ﻛﺘﺎﺑﺔ اﻟﱪاﻣﺞ ‪Writing programs‬‬


‫ﳝﺮ أى ﺑﺮ ﻣﺞ ﺑﻌﺪد ﻣﻦ اﳌﺮاﺣﻞ ﻣﻨﺬ أن ﻛﺎن ﻓﻜﺮة أو ﻣﻄﻠﺒﺎ ﻟﺪى أﺣــﺪ ﻣﺴــﺘﺨﺪﻣﻰ اﳊﺎﺳــﺐ إﱃ أن ﻳﻜﺘــﺐ ﰒ ﻳﻮﺿــﻊ ﳏــﻞ‬
‫اﻟﺘﻨﻔﻴــﺬ ﰒ ﻳﻌــﺪل ﺗﺒﻌــﺎ ﻟﺘﻌــﺪﻳﻞ اﳌﺘﻄﻠﺒــﺎت ﰒ ﰱ اﻟﻨﻬﺎﻳــﺔ ﻳﺘﻮﻗــﻒ اﻟﺘﻌﺎﻣــﻞ ﻣﻌــﻪ و ﻳﺴــﺘﻌﺎض ﻋﻨــﻪ ﺑــﱪ ﻣﺞ آﺧــﺮ‪ .‬ﺳﻨﺴــﺘﻌﺮض ﺑﻘــﺪر ﻣــﻦ‬
‫اﻟﺘﻔﺼــﻴﻞ رﻳــﺦ ﺣﻴــﺎة اﻟـﱪاﻣﺞ ﻣﻨــﺬ ﻣﻴﻼدﻫــﺎ إﱃ أن ﺗﻘﻀــﻰ اﻟــﻮﺗﺮ ﻣﻨﻬــﺎ ﰱ ﻓﻘــﺮة ﻻﺣﻘــﺔ )اﻟﻔﻘــﺮة اﳋﺎﺻــﺔ ﺑﺘــﺎرﻳﺦ ﺣﻴــﺎة اﻟـﱪاﻣﺞ(‪ .‬و ﻟﻜﻨﻨــﺎ‬
‫ﺳﻨﺮﻛﺰ ﰱ ﻫﺬﻩ اﻟﻔﻘــﺮة ﻋﻠــﻰ ﺟــﺰء ﻣــﻦ ذﻟــﻚ اﻟﺘــﺎرﻳﺦ و ﻫــﻮ اﳋــﺎص ﺑﻜﺘﺎﺑــﺔ اﻟــﱪ ﻣﺞ ‪ ،program development‬أى ﻣﻨــﺬ أن ﻳﻮﺿــﻊ‬
‫اﻷﳉﻮرﻳﺘﻢ إﱃ أن ﲣﺮج ﳊﻴﺰ اﻟﻮﺟﻮد أول ﺻﻴﻐﺔ ‪ version‬ﻟﻠﱪ ﻣﺞ‪.‬‬
‫ﳝﻜــﻦ ﺗﻘﺴــﻴﻢ اﻟ ـﱪاﻣﺞ إﱃ ﻧــﻮﻋﲔ رﺋﻴﺴــﻴﲔ‪ :‬ﺗﻄﺒﻴﻘــﺎت ‪ applications‬و ﻣﺴــﺎﻋﺪات أو أدوات ‪.utilities or tools‬‬
‫اﻟﺘﻄﺒﻴﻘﺎت ﻋﺒﺎرة ﻋﻦ ﺑﺮاﻣﺞ ﻛﺘﺒﺖ ﳊﻞ ﻣﺸﺎﻛﻞ ﻣﻦ اﳊﻴﺎة‪ .‬أﻣﺎ اﳌﺴﺎﻋﺪات ﻓﻬﻰ ﺑﺮاﻣﺞ ﻛﺘﺒﺖ ﻟﺘﺴﻬﻴﻞ اﺳﺘﺨﺪام اﳊﺎﺳﺐ ﲟﺎ ﰱ ذﻟــﻚ‬
‫ﺗﺴﻬﻴﻞ ﻛﺘﺎﺑﺔ اﻟﺘﻄﺒﻴﻘﺎت‪ .‬إﳒﺎز أﻳﺔ ﻣﺮﺣﻠﺔ ﻣﻦ ﻣﺮاﺣﻞ ﻛﺘﺎﺑﺔ اﻟﱪ ﻣﺞ ﻳﻌﺘﻤﺪ ﻋﻠﻰ اﺳﺘﺨﺪام اﻷداة اﳌﺴﺎﻋﺪة اﳌﻨﺎﺳﺒﺔ )ﺷﻜﻞ ‪.(11.1‬‬
‫ﻳﻨﺒﻐــﻰ أوﻻ ﲢﻮﻳــﻞ اﻷﳉــﻮرﻳﺘﻢ اﳌﻮﺿــﻮع ﳊــﻞ اﳌﺸــﻜﻠﺔ ﻣــﻦ أﻳــﺔ ﺻــﻮرة اﺑﺘﺪاﺋﻴــﺔ )ﳐﻄــﻂ ﺑﻴــﺎ ت ‪ flow chart‬أو ﻛــﻮد ﻛــﺎذب‬
‫‪ (pseudocode‬إﱃ ﻟﻐــﺔ ﻣــﻦ ﻟﻐــﺎت اﻟﱪﳎــﺔ ﻣﺮﺗﻔﻌــﺔ اﳌﺴــﺘﻮى ‪ high level language‬اﻟــﱴ ﻳﺘﻌﺎﻣــﻞ ﻣﻌﻬــﺎ اﳊﺎﺳــﺐ ﻣﺜــﻞ اﻟﻔــﻮرﺗﺮان‬
‫‪ FORTRAN‬أو اﻟﺒﺎﺳﻜﺎل ‪ Pascal‬أو ‪ .C‬ﻣﻦ اﻟﺴﻬﻞ ﻟﺘﺄﻛﻴﺪ أن ﻳﻜﺘﺐ اﳌﱪﻣﺞ اﻷﳉــﻮرﻳﺘﻢ و ﻫــﻮ ﻣــﺎ زال ﻓﻜــﺮة ﰱ ذﻫﻨــﻪ ﺣــﺪ‬
‫اﻟﻠﻐﺎت ﻣﺮﺗﻔﻌﺔ اﳌﺴﺘﻮى ﻋﻦ أن ﻳﱰﲨﻪ ﻣﺒﺎﺷﺮة ﻟﻠﻐﺔ اﻵﻟﺔ‪ .‬إن اﻟﻠﻐﺎت ﻣﺮﺗﻔﻌﺔ اﳌﺴﺘﻮى ﻣﻮﺟﻬﺔ ﻟﻠﺘﻌﺎﻣﻞ ﻣﻊ ﻣﺸﺎﻛﻞ اﻟﺒﺸــﺮ ‪problem‬‬
‫‪ oriented‬ﺑﻴﻨﻤﺎ اﻟﻠﻐﺎت ﻣﻨﺨﻔﻀﺔ اﳌﺴﺘﻮى ﻓﻬﻰ ﻣﻮﺟﻬﺔ ﻟﻠﺘﻌﺎﻣــﻞ ﻣــﻊ اﻵﻟــﺔ ‪ machine oriented‬ﲟــﺎ ﻓﻴﻬــﺎ ﻣــﻦ ﻗــﺪرات ﺧﺎﺻــﺔ‪ .‬ﻻ‬
‫ﻳﻨﺒﻐــﻰ أن ﻳﺘﺼــﻮر اﻟﻘــﺎرئ أن اﻟﻠﻐــﺔ اﳌﺮﺗﻔﻌــﺔ أﺻــﻌﺐ ﻣــﻦ اﻟﻠﻐــﺔ اﳌﻨﺨﻔﻀــﺔ‪ ،‬ﺑــﻞ ﻏﺎﻟﺒــﺎ ﻣــﺎ ﻳﻜــﻮن اﻟﻌﻜــﺲ ﻫــﻮ اﻟﺼــﺤﻴﺢ‪ .‬و ﻟﻜــﻦ ﺻــﻔﺔ‬
‫اﻻرﺗﻔﺎع أﻋﻄﻴﺖ ﻟﺘﻜﺮﱘ ﻣﺴﺘﺨﺪم اﻟﻠﻐﺔ )أى اﻹﻧﺴﺎن( ﻣﻘﺎرﻧﺔ ﲟﺴﺘﺨﺪم اﻟﻠﻐﺔ اﳌﻨﺨﻔﻀﺔ )أى اﻵﻟﺔ(‪.‬‬
‫ﻟﻜﺘﺎﺑــﺔ اﻟ ــﱪ ﻣﺞ ﺑﻠﻐ ــﺔ ﻣﺮﺗﻔﻌ ــﺔ اﳌﺴ ــﺘﻮى ﳓﺘ ــﺎج ﶈ ــﺮر ‪ editor‬و ﻫ ــﻮ ﻋﺒ ــﺎرة ﻋ ــﻦ أداة ﻣﺴ ــﺎﻋﺪة )أى ﺑ ــﺮ ﻣﺞ آﺧ ــﺮ ﻣ ــﻦ ﻧ ــﻮع‬
‫‪ (utility‬ﺗﻴﺴــﺮ ﻟﻠﻤﺴــﺘﺨﺪم ﻛﺘﺎﺑــﺔ ﺳــﻄﻮر ﻣﻜﻮﻧــﺔ ﻣــﻦ ﺣــﺮوف ‪ ASCII‬و ﲣـﺰﻳﻦ ﻣــﺎ ﻛﺘــﺐ ﰱ ﻣﻠــﻒ و ﺗﺴــﻬﻴﻞ اﺳــﱰﺟﺎﻋﻪ و ﺗﻌﺪﻳﻠــﻪ‪.‬‬

‫‪18‬‬
‫ﻳﺴﻤﻰ ﻫﺬا اﳌﻠﻒ ﻣﻠﻒ اﳌﺼﺪر ‪ .source file‬إن اﶈﺮرات ﰱ اﻟﻌﺼﻮر اﻷوﱃ ﻟﻠﺤﺎﺳﺐ ﻛﺎﻧــﺖ ﳏــﺮرات ﺳــﻄﻮر ‪ line editors‬أى‬
‫أ ــﺎ ﻛﺎﻧــﺖ ﺗﺘــﻴﺢ رؤﻳــﺔ ﺳــﻄﺮ واﺣــﺪ ﻓﻘــﻂ ﻣــﻦ اﻟــﱪ ﻣﺞ اﳌﻄﻠــﻮب ﻛﺘﺎﺑﺘــﻪ‪ ،‬و ﺗﻌﺪﻳﻠــﻪ إن ﺷــﺌﻨﺎ‪ ،‬ﰒ ﺗﻈﻬــﺮ ﺳــﻄﺮا آﺧــﺮ و ﻫﻜــﺬا‪ .‬اﶈــﺮرات‬
‫اﳊﺎﻟﻴﺔ ﺗﺴﻤﻰ ﳏﺮرات اﻟﺸﺎﺷﺔ اﻟﻜﺎﻣﻠﺔ ‪ full screen editor‬و ﺑﻮﺳﻌﻬﺎ إﻇﻬﺎر ﻛــﻞ اﻟــﱪ ﻣﺞ ﻋﻠــﻰ اﻟﺸﺎﺷــﺔ و ﺗﻌــﺪﻳﻞ أى ﺣــﺮف ﻓﻴــﻪ‬
‫ﻣﺒﺎﺷــﺮة‪ .‬ﻛﻤــﺎ ﺗﺘــﻴﺢ أﻳﻀــﺎ اﻟﺒﺤــﺚ ﻋــﻦ ﻛﻠﻤــﺔ ﰱ اﻟــﱪ ﻣﺞ ﻣــﻊ ﺗﻌــﺪﻳﻠﻬﺎ أوﺗﻮﻣﺎﺗﻴﻜﻴــﺎ ‪ .search/replace‬ﻫﻨــﺎك إﻣﻜﺎﻧﻴــﺎت أﺧــﺮى ﻣﺜــﻞ‬
‫ﻧﻘﻞ ﺟﺰء ﻛﺎﻣﻞ ﻣﻦ اﻟﱪ ﻣﺞ إﱃ ﻣﻜﺎن آﺧﺮ أو إﻟﻐﺎﺋﻪ أو ﻧﺴﺨﻪ أﻳﺔ ﻋﺪد ﻣﻦ اﻟﻨﺴﺦ ﺳﺘﺨﺪام اﻷواﻣﺮ ‪.copy-paste-cut‬‬

‫‪Editor‬‬ ‫‪Compiler‬‬
‫‪Algorithm‬‬ ‫‪Program‬‬ ‫‪Object‬‬

‫‪(Syntax errors,‬‬ ‫‪Linker‬‬


‫‪Unambiguity‬‬ ‫‪Lib.‬‬
‫‪Objectivity‬‬ ‫)‪Warnings‬‬
‫‪Repeatability‬‬ ‫‪Resolve‬‬
‫‪Finiteness‬‬ ‫‪External‬‬

‫‪Executable‬‬

‫‪Loader‬‬

‫‪Debugger No‬‬ ‫‪OK‬‬


‫‪Localize‬‬ ‫‪Test‬‬
‫‪Error‬‬ ‫‪Result‬‬
‫‪Breakpoint‬‬
‫‪Watch‬‬
‫‪Set‬‬
‫ﺷﻜﻞ ‪ -11.1‬ﺧﻄﻮات ﻛﺘﺎﺑﺔ ﺑﺮ ﻣﺞ و اﻷدوات اﳌﺴﺎﻋﺪة اﳌﺴﺘﺨﺪﻣﺔ‬
‫اﳋﻄﻮة اﻟﺘﺎﻟﻴﺔ ﻫﻰ ﺗﺮﲨﺔ ﻣﻠــﻒ اﳌﺼــﺪر ‪ source file‬إﱃ ﻣﻠــﻒ اﳍــﺪف ‪ ،object file‬و ﻫــﻮ ﻣﻠــﻒ ﳛــﻮى ﻧﻔــﺲ اﻟــﱪ ﻣﺞ‬
‫و ﻟﻜﻨﻪ ﻣﻜﺘﻮب ﺑﻠﻐﺔ اﻵﻟﺔ ‪ .machine language‬ﺗﻘﻮم ﻟﱰﲨﺔ أداة ﻣﺴﺎﻋﺪة ‪ utility‬أﺧــﺮى ﺗﺴــﻤﻰ اﳌــﱰﺟﻢ ‪ .compiler‬أﺛﻨــﺎء‬
‫اﻟﱰﲨﺔ ﻓﺈن اﳌﱰﺟﻢ ﻳﻘﻮم ﻟﺘﺄﻛﺪ ﻣﻦ ﺧﻠﻮ اﻟﱪ ﻣﺞ ﻣﻦ اﻷﺧﻄﺎء اﻟﻠﻐﻮﻳﺔ ‪ syntax errors‬ﺗﺒﻌﺎ ﻟﻠﻨﺤــﻮ اﳋــﺎص ﻟﻠﻐــﺔ ﻣﺮﺗﻔﻌــﺔ اﳌﺴــﺘﻮى‬
‫اﳌﺴــﺘﺨﺪﻣﺔ‪ .‬ﺗﻌﺘــﱪ ﻫــﺬﻩ اﻷﺧﻄــﺎء أﺧﻄــﺎء ﺷــﻜﻠﻴﺔ ﺣﻴــﺚ أ ــﺎ ﺗﺘﻌﻠــﻖ ﺑﺸــﻜﻞ اﻷﻣــﺮ و ذﻟــﻚ ﻣﻘﺎرﻧــﺔ ﻷﺧﻄــﺎء اﳌﻮﺿــﻮﻋﻴﺔ ‪semantic‬‬
‫‪ error‬و اﻟﱴ ﺗﺘﻌﻠــﻖ ﳌﻨﻄــﻖ اﻟﻜــﺎﻣﻦ ﰱ اﻟــﱪ ﻣﺞ‪ .‬ﻟﺘﻮﺿــﻴﺢ اﻟﻔــﺮق ﺑــﲔ ﻫــﺬﻳﻦ اﻟﻨــﻮﻋﲔ ﻓﻠﻨﺄﺧــﺬ ﻛﻤﺜــﺎل اﳉﻤﻠــﺔ اﻟﺘﺎﻟﻴــﺔ "ﻳﺸــﺮق اﻟﺸــﻤﺲ‬
‫ﻣــﻦ اﻟﻐــﺮب"‪ .‬ﲢــﻮى ﻫــﺬﻩ اﳉﻤﻠــﺔ ﺧﻄــﺄ ﻟﻐــﻮ ﺣﻴــﺚ أن اﻟﺸــﻤﺲ ﻣﺆﻧﺜــﺔ ﰱ اﻟﻠﻐــﺔ اﻟﻌﺮﺑﻴــﺔ و ﻛــﺎن ﻳﻨﺒﻐــﻰ أن ﻧﻘــﻮل "ﺗﺸــﺮق" ﺑــﺪﻻ ﻣــﻦ‬
‫"ﻳﺸﺮق"‪ .‬ﻓﺈذا ﺻﺤﺤﻨﺎ ﻫﺬا اﳋﻄﺄ أﺻﺒﺤﺖ اﳉﻤﻠــﺔ ﺻــﺤﻴﺤﺔ ﲤﺎﻣــﺎ ﻣــﻦ اﻟﻮﺟﻬــﺔ اﻟﻠﻐﻮﻳــﺔ و ﻟﻜﻨﻬــﺎ ﻟﻄﺒــﻊ ﻣﺎزاﻟــﺖ ﲢــﻮى ﺧﻄــﺄ ﻣﻨﻄﻘﻴــﺎ‬
‫ﰱ ﻛﻠﻤﺔ "اﻟﻐﺮب" ﺑﺪﻻ ﻣﻦ "اﻟﺸﺮق"‪ .‬ﻛﺎن ﻫﺬا ﻣﺜﺎﻻ ﳜﺺ اﻟﻠﻐﺔ اﻟﻌﺮﺑﻴﺔ‪ ،‬أﻣﺎ ﻟﻨﺴــﺒﺔ ﻟﻠﻐــﺎت اﻟﱪﳎــﺔ ﻓــﺄن اﻷﺧﻄــﺎء اﻟﻠﻐﻮﻳــﺔ ﻗــﺪ ﺗﻜــﻮن‬
‫ﰱ ﺻﻮرة اﺳﺘﺨﺪام ﻓﺎﺻﻠﺔ ﺑﺪﻻ ﻣﻦ ﻧﻘﻄﺔ ﻣﺜﻼ أو اﺳــﺘﺨﺪام أﻣــﺮ ﺑــﻪ ﺣــﺮف ﺧﻄــﺄ ﲝﻴــﺚ ﻻ ﻳﻄــﺎﺑﻖ أى ﻣــﻦ اﻷواﻣــﺮ اﻟــﱴ ﻳﻌﺮﻓﻬــﺎ ﻣﺴــﺎﻋﺪ‬
‫اﻟﱰﲨــﺔ ‪ ..‬اﱁ‪ .‬أﻣــﺎ اﻷﺧﻄــﺎء اﳌﻨﻄﻘﻴــﺔ ﻓﻬــﻰ أﺧﻄــﺎء ﺗــﺆدى إﱃ أن ﻳﻘــﻮم اﳊﺎﺳــﺐ ﲝﺴــﺎب ﻗﻴﻤــﺔ ﳐﺘﻠﻔــﺔ ﻋﻤــﺎ ﻛﻨــﺎ ﻧﺒﺤــﺚ ﻋﻨــﻪ‪ .‬ﳝﻜــﻦ‬
‫ﻟﻠﻤــﱰﺟﻢ ‪ compiler‬ﺑﺴــﻬﻮﻟﺔ أن ﻳﻜﺘﺸــﻒ اﻷﺧﻄــﺎء اﻟﻠﻐﻮﻳــﺔ و ﻳﻜﺘــﺐ رﺳــﺎﻟﺔ ﻋﻠــﻰ اﻟﺸﺎﺷــﺔ ﺗﻮﺿــﺢ ﻧــﻮع اﳋﻄــﺄ و ﻣﻮﺿــﻌﻪ ﲟــﺎ ﻳﺴــﻬﻞ‬
‫ﻋﻠﻴﻨــﺎ ﻣﻬﻤــﺔ ﺗﺼــﺤﻴﺢ اﳋﻄــﺄ اﻟﻠﻐــﻮى‪ .‬ﺗﺴــﻤﻰ ﻫــﺬﻩ اﻟﺮﺳــﺎﻟﺔ ﺑﺮﺳــﺎﻟﺔ ﺧﻄــﺄ ‪ .error message‬ﻻ ﳝﻜــﻦ ﻷى ﺑــﺮ ﻣﺞ أن ﻳﻜﺘﺸــﻒ ﻣــﻦ‬
‫ﺗﻠﻘــﺎء ﻧﻔﺴــﻪ اﻷﺧﻄــﺎء اﳌﻨﻄﻘﻴــﺔ ﻓﺎﳊﺎﺳــﺐ ﻟــﻴﺲ ﻟــﻪ أن ﻳﻘــﺮر ﻣــﺎذا ﻧﺮﻳــﺪ أن ﻧﻔﻌــﻞ ﻣــﻦ اﻟــﱪ ﻣﺞ‪ .‬ﻟــﺮﻏﻢ ﻣــﻦ ذﻟــﻚ ﻓﻘــﺪ ﻳﻜﺘﺸــﻒ اﳌــﱰﺟﻢ‬

‫‪19‬‬
‫ﺑﻌــﺾ ﺣــﺎﻻت ﻣﻮﺿــﻊ ﺷــﻚ‪ ،‬ﻳﻌﺘﻘــﺪ أ ــﺎ ﻗــﺪ ﲤﺜــﻞ ﺧﻄــﺄ ﻣﻨﻄﻘﻴــﺎ‪ .‬ﰱ ﻫــﺬﻩ اﳊﺎﻟــﺔ ﻳﺼــﺪر اﳌــﱰﺟﻢ رﺳــﺎﻟﺔ ﲢــﺬﻳﺮ ‪warning message‬‬
‫ﻣﻮﺿﺤﺎ اﻟﺴﺒﺐ‪ .‬و ﻟﻜــﻦ رﺳــﺎﻟﺔ اﻟﺘﺤــﺬﻳﺮ ﻻ ﲤﻨــﻊ ﻣــﻦ اﺳــﺘﻤﺮار اﻟﻌﻤــﻞ و اﻻﻧﺘﻘــﺎل ﻟﻠﻤﺮﺣﻠــﺔ اﻟﺘﺎﻟﻴــﺔ‪ ،‬إﻻ إذا رأى اﳌــﱪﻣﺞ ﻏــﲑ ذﻟــﻚ‪ .‬ﻣــﻦ‬
‫أﻣﺜﻠــﺔ اﳊــﺎﻻت ﻣﻮﺿــﻊ اﻟﺸــﻚ أن ﻧﻘــﻮم ﲝﺴــﺎب ﻛﻤﻴــﺔ ﻣــﺎ و ﻳــﺘﻢ ﲣﺰﻳﻨﻬــﺎ ﰱ ﻣﺘﻐــﲑ ﰒ ﻻ ﻧﺴــﺘﺨﺪﻣﻬﺎ ﰱ ﺣﺴــﺎب أى ﻣﺘﻐــﲑ آﺧــﺮ و ﻻ‬
‫ﻧﻜﺘﺒﻬﺎ ﻋﻠﻰ اﻟﺸﺎﺷﺔ‪.‬‬
‫ﻗﺪ ﳛﺘﻮى ﻣﻠﻒ اﳌﺼﺪر ﻋﻠــﻰ ﺳــﻄﻮر ﺧﺎﺻــﺔ ﺗﺴــﻤﻰ ﺗﻌﻠﻴﻤــﺎت ﻟﻠﻤــﱰﺟﻢ ‪ .compiler directives‬ﻫــﺬﻩ اﻟﺘﻌﻠﻴﻤــﺎت ﻟــﻴﺲ‬
‫اﳌﻄﻠــﻮب ﻣﻨﻬــﺎ أن ﺗــﱰﺟﻢ إﱃ أواﻣــﺮ ﺑﻠﻐــﺔ اﻵﻟــﺔ و ﻟﻜــﻦ اﳌﻘﺼــﻮد ــﺎ ﺗﻮﺟﻴﻬــﺎت ﻟﻠﻤــﱰﺟﻢ ﲞﺼــﻮص أﺳــﻠﻮب اﻟﱰﲨــﺔ‪ .‬ﻓﻌﻠــﻰ ﺳــﺒﻴﻞ اﳌﺜــﺎل‬
‫ﳝﻜﻦ إﺧﻄﺎر اﳌﱰﺟﻢ ﺑﻌﺪم ﺗﺮﲨﺔ ﺟﺰء ﻣﺎ ﻣﻦ اﻟﱪ ﻣﺞ ﻣﺎ ﱂ ﻳﻄﻠــﺐ ذﻟــﻚ ﺻـﺮاﺣﺔ‪ .‬ﳛــﺪث ذﻟــﻚ ﻣــﺜﻼ ﰱ ﺣﺎﻟــﺔ ﻛﺘﺎﺑــﺔ ﺟــﺰء إﺿــﺎﰱ ﻋﻠــﻰ‬
‫اﻟﱪ ﻣﺞ ﻫﺪﻓﻪ ﻓﻘﻂ اﻟﺘﺄﻛﺪ ﻣﻦ ﺻﺤﺔ اﻟﱪﳎﺔ‪ .‬ﻳﻄﻠﺐ ﻣﻦ اﳌﱰﺟﻢ أن ﻳﻘﻮم ﺑﱰﲨﺘﻪ و إﺿﺎﻓﺘﻪ ﻋﻠﻰ اﻟــﱪ ﻣﺞ أﺛﻨــﺎء ﻓــﱰة اﻻﺧﺘﺒــﺎرات ﻓﻘــﻂ‬
‫ﰒ ﻳﻄﻠﺐ ﻣﻨﻪ أن ﳛﺬﻓﻪ ﻋﻨﺪ اﻟﺘﺄﻛﺪ ﻣــﻦ ﺻــﺤﺔ اﻟــﱪ ﻣﺞ و اﺳــﺘﻌﻤﺎﻟﻪ ﺑﺼــﻮرة ﻋﺎدﻳــﺔ‪ .‬ﰱ ﻟﻐــﺔ ال‪ C‬ﻣــﺜﻼ ﻳﻮﺿــﻊ اﳉــﺰء اﻹﺿــﺎﰱ ﺑــﲔ زوج‬
‫ﻣﻦ اﻟﺘﻌﻠﻴﻤﺎت ﻛﺎﻵﺗﻰ‪:‬‬
‫‪#ifdef TEST‬‬
‫‪.....‬‬
‫‪.....‬‬
‫‪#endif‬‬
‫ﺣﻴﺚ ﻳﻮﺿﻊ اﳉﺰء اﻹﺿﺎﰱ ﳏﻞ اﻟﻨﻘﺎط‪.‬‬
‫اﳋﻄــﻮة اﻟﺘﺎﻟﻴــﺔ ﻫــﻰ وﺻــﻞ ‪ link‬ﻣﻠــﻒ اﳍــﺪف )أو ﻣﻠﻔــﺎت اﳍــﺪف إن ﻛــﺎن اﻟــﱪ ﻣﺞ ﻛﺒـﲑا )‪ (object file(s‬ﻟﻌﻤــﻞ ﻣﻠــﻒ‬
‫ﻗﺎﺑﻞ ﻟﻠﺘﻨﻔﻴﺬ ‪ .executable‬ﰱ اﻟﻮاﻗﻊ ﻓﺈن ﻣﻠﻒ اﳍﺪف ﻻ ﳝﻜﻦ ﺗﻨﻔﻴﺬﻩ ﻣﺒﺎﺷﺮة ﻟﺮﻏﻢ ﻣﻦ اﺣﺘﻮاﺋــﻪ أواﻣــﺮ ﻣﻜﺘﻮﺑــﺔ ﺑﻠﻐــﺔ اﻵﻟــﺔ‪ .‬ﻓﻬﻨــﺎك‬
‫ﺑﻌﺾ اﻟﻌﻤﻠﻴﺎت اﻟﻌﺎﻣﺔ و اﳌﺘﻜﺮرة و اﻟﱴ ﳝﻜﻦ أن ﺗﺴﺘﺨﺪم ﰱ ﻋﺪد ﻛﺒﲑ ﻣﻦ اﻟﱪاﻣﺞ اﳌﺨﺘﻠﻔﺔ ﻣﺜﻞ ﺣﺴﺎب اﻟﺪوال اﳋﺎﺻــﺔ )اﳉﻴــﺐ و‬
‫ﺟﻴــﺐ اﻟﺘﻤــﺎم( أو أواﻣــﺮ اﻟﺘﻌﺎﻣــﻞ ﻣــﻊ اﳌﻠﻔــﺎت )ﻓــﺘﺢ ﻣﻠــﻒ و ﻗـﺮاءة ﻣــﺎ ﻓﻴــﻪ و ﺣﻔــﻆ ﺑﻴــﺎ ت ﺟﺪﻳــﺪة ‪..‬اﱁ(‪ .‬ﻻ داﻋــﻰ ﻟﻜﺘﺎﺑــﺔ اﻟﺘﻔﺎﺻــﻴﻞ‬
‫اﳌﺘﻌﻠﻘﺔ ﺬﻩ اﻟﻌﻤﻠﻴﺎت اﻟﻌﺎﻣﺔ ﰱ ﻛﻞ ﺑﺮ ﻣﺞ‪ .‬اﳌﺘﺒﻊ ﻋﺎدة ﻫﻮ أن ﺗﻌﺮف ﺗﻠﻚ اﻟﻌﻤﻠﻴﺎت و ﺗﻮﺻــﻒ وﺻــﻔﺎ ﺗﻔﺼــﻴﻠﻴﺎ ﰱ ﻣﻠﻔــﺎت ﻣﻨﻔﺼــﻠﺔ‬
‫ﳓــﺘﻔﻆ ــﺎ ﰱ اﳌﺨــﺰن اﻟﺜــﺎﻧﻮى‪ ،‬ﺗﺴــﻤﻰ ﻃﺎﺋﻔــﺔ اﳌﻠﻔــﺎت ﻣــﻦ ﻫــﺬا اﻟﻨــﻮع ﳌﻜﺘﺒــﺎت ‪ .Libraries‬ﻋﻨــﺪ ﻇﻬــﻮر اﳊﺎﺟــﺔ ﻷى ﻣــﻦ ﺗﻠــﻚ‬
‫اﻟﻌﻤﻠﻴــﺎت ﰱ اﻟــﱪ ﻣﺞ اﻟــﺬى ﳓــﻦ ﺑﺼــﺪد ﻛﺘﺎﺑﺘــﻪ‪ ،‬ﻳﻜﻔــﻰ اﻹﺷــﺎرة إﱃ ﺗﻠــﻚ اﻟﻌﻤﻠﻴــﺎت ﻻﺳــﻢ ﰱ اﳌﻜــﺎن اﳌـﺮاد اﺳــﺘﺨﺪاﻣﻬﺎ ﻓﻴــﻪ‪ .‬ﻣﻠــﻒ‬
‫اﳍــﺪف اﻟﻨــﺎﺗﺞ ﻋــﻦ اﻟﱰﲨــﺔ‪ ،‬ﺳــﻴﺤﻮى ﺗﺮﲨــﺔ ﻟﻠﻌﻤﻠﻴــﺎت و اﻷواﻣــﺮ اﻟــﱴ ﻛﺘﺒﻨــﺎ وﺻــﻔﻬﺎ ﺗﻔﺼــﻴﻠﻴﺎ ﻹﺿــﺎﻓﺔ ﻟﻺﺷــﺎرة ﻟﻠﻌﻤﻠﻴــﺎت اﻟﻌﺎﻣــﺔ ﰱ‬
‫ﻣﻮاﺿﻌﻬﺎ‪ .‬أﺛﻨﺎء ﻋﻤﻠﻴﺔ اﻟﻮﺻﻞ‪ ،‬ﻳﻘــﻮم ﺑــﺮ ﻣﺞ ﻣﺴــﺎﻋﺪ اﲰــﻪ اﳌﻮﺻــﻞ ‪ linker‬ﺑﻌــﺪة ﻋﻤﻠﻴــﺎت ﻣﻨﻬــﺎ اﻟﺒﺤــﺚ ﻋــﻦ ﺗﻌﺮﻳــﻒ ﲨﻴــﻊ اﻟﻌﻤﻠﻴــﺎت‬
‫اﻟﻌﺎﻣ ـ ــﺔ اﳌﺸ ـ ــﺎر إﻟﻴﻬ ـ ــﺎ و إﺿ ـ ــﺎﻓﺔ اﻟﻮﺻ ـ ــﻒ اﻟﺘﻔﺼ ـ ــﻴﻠﻰ ﻣ ـ ــﻦ اﳌﻜﺘﺒ ـ ــﺔ اﳌﻨﺎﺳ ـ ــﺒﺔ ﻟ ـ ــﱪ ﻣﺞ اﳍ ـ ــﺪف ﻟﻴﺘﺤ ـ ــﻮل ﺑ ـ ــﺬﻟﻚ ﳌﻠ ـ ــﻒ ﻗﺎﺑ ـ ــﻞ ﻟﻠﺘﻨﻔﻴ ـ ــﺬ‬
‫‪ .Executable‬ﻛﻤﺎ أن اﳌﱪﻣﺞ ﳝﻜﻦ أن ﻳﺼﻨﻊ ﻟﻨﻔﺴﻪ ﻣﻜﺘﺒﺔ إﺿﺎﻓﻴﺔ ﻣﻦ اﻟﱪاﻣﺞ اﻟﻔﺮﻋﻴﺔ اﻟﺼﻐﲑة اﻟﱴ ﻳﺴﺘﺨﺪﻣﻬﺎ ﻛﺜـﲑا و ﻳﻀــﻌﻬﺎ ﰱ‬
‫ﻣﻠﻔــﺎت ﺧﺎﺻــﺔ ﻣﱰﲨــﺔ ﻟﻠﻐــﺔ اﻵﻟــﺔ ﻣﺒﺎﺷــﺮة ﲝﻴــﺚ ﺗﻀــﺎف ﻟﻠــﱪ ﻣﺞ اﻷﺻــﻠﻰ ﺧــﻼل أﻣــﺮ اﻟﻮﺻــﻞ‪ .‬ﻓــﺈذا ذﻛــﺮت داﻟــﺔ ﺧﺎﺻــﺔ ﰱ اﻟــﱪ ﻣﺞ‬
‫اﻷﺻــﻠﻰ ﻣﺜــﻞ داﻟــﺔ )‪ bessel(n,x‬ﻣــﺜﻼ ﻓــﺈن ﺑــﺮ ﻣﺞ اﻟﻮﺻــﻞ ﻳﺒﺤــﺚ ﻋــﻦ ﺗﻌﺮﻳــﻒ ﳍــﺬﻩ اﻟﺪاﻟــﺔ ﰱ ﲨﻴــﻊ ﻣﻠﻔــﺎت اﳌﻜﺘﺒــﺎت اﳌﻌﻄــﺎة‪ .‬ﻓــﺈذا‬
‫وﺟﺪﻫﺎ ﻳﻀﻴﻒ ﺗﻌﺮﻳﻔﻬﺎ ﳌﻠﻒ اﳍﺪف‪ ،‬و إذا ﱂ ﳚﺪﻫﺎ ﻓﺈﻧﻪ ﻳﻄﺒﻊ رﺳﺎﻟﺔ ﻗﺪ ﺗﺒﺪو ﻛﺎﻵﺗﻰ‪:‬‬
‫‪Link:‬‬
‫‪error: bessel: unresolved external reference‬‬

‫ﺟﺪﻳﺮ ﻟﺬﻛﺮ أن ﻛﺎﻓﺔ اﻷواﻣــﺮ اﳌﺘﻌﻠﻘــﺔ دﺧــﺎل أو إﺧـﺮاج اﳌﻌﻠﻮﻣــﺎت ﻻ ﻳﻘــﻮم اﻟــﱪ ﻣﺞ اﻷﺻــﻠﻰ ﺑﺘﻌﺮﻳﻔﻬــﺎ ﻣﺒﺎﺷــﺮة ﺑــﻞ ﻳﻜﺘﻔــﻰ‬
‫ﺑﺬﻛﺮ ﻣﺎ ﻧﺮﻳﺪ إدﺧﺎﻟﻪ أو إﺧﺮاﺟﻪ‪ .‬أﻣﺎ ﻛﻴﻔﻴﺔ ﻛﺘﺎﺑﺔ ﺑﻴﺎ ت ﻋﻠﻰ اﻟﺸﺎﺷﺔ أو ﻗﺮاءة ﺑﻴﺎ ت ﻣﻦ ﻟﻮﺣــﺔ اﳌﻔــﺎﺗﻴﺢ ﻓــﺈن ﻫــﺬﻩ اﻟﻌﻤﻠﻴــﺎت ﺗﻌــﺮف‬
‫داﺋﻤــﺎ ﰱ ﻧﻈــﺎم اﻟﺘﺸــﻐﻴﻞ ‪ .operating system‬و ﻟــﺬﻟﻚ ﻓــﺈن ﺑــﺮ ﻣﺞ اﻟﻮﺻــﻞ ﻳﺒﺤــﺚ ﻋــﻦ ﺷــﺮح ﻛﻴﻔﻴــﺔ إدﺧــﺎل و إﺧـﺮاج اﳌﻌﻠﻮﻣــﺎت‬

‫‪20‬‬
‫ﻣﻦ داﺧﻞ ﻧﻈﺎم اﻟﺘﺸﻐﻴﻞ اﳌﺴﺘﺨﺪم‪ .‬و ﳍﺬا ﻓﺈن اﻟﱪ ﻣﺞ اﻟﻘﺎﺑﻞ ﻟﻠﺘﻨﻔﻴﺬ ‪ executable‬اﻟــﺬى ﳜــﺮج ﻣﻨــﻪ ﻳﻜــﻮن داﺋﻤــﺎ ﻗﺎﺑــﻞ ﻟﻠﺘﻨﻔﻴــﺬ ﰱ‬
‫ﻧﻈﺎم اﻟﺘﺸﻐﻴﻞ اﻟﺬى ﰎ ﺑﻨﺎءﻩ ﻋﻠﻴﻪ و ﻻ ﻳﺼﺢ اﺳﺘﺨﺪاﻣﻪ ﻋﻠﻰ أى ﻧﻈﺎم ﺗﺸﻐﻴﻞ آﺧــﺮ‪ .‬ﳜﺘﻠــﻒ اﻷﻣــﺮ ﻟﻨﺴــﺒﺔ ﳌﻠــﻒ اﳌﺼــﺪر ‪source‬‬
‫‪ file‬اﳌﻜﺘــﻮب ﺑﻠﻐــﺔ ﻣﺮﺗﻔﻌــﺔ اﳌﺴــﺘﻮى و اﻟــﺬى ﻏﺎﻟﺒــﺎ ﻣــﺎ ﳝﻜــﻦ ﻧﻘﻠــﻪ ﻛﻤــﺎ ﻫــﻮ ﻣــﻦ ﻧﻈــﺎم ﺗﺸــﻐﻴﻞ ﻟﻨﻈــﺎم آﺧــﺮ ﻣــﻊ ﻣﺮاﻋــﺎة إﻋــﺎدة ﺗﺮﲨﺘــﻪ و‬
‫وﺻﻠﻪ ﻋﻠﻰ ﻧﻈﺎم اﻟﺘﺸﻐﻴﻞ اﳉﺪﻳﺪ ﻗﺒﻞ اﻟﺘﻨﻔﻴﺬ‪ .‬ﺗﺴﻤﻰ ﻗﺎﺑﻠﻴﺔ اﺳﺘﺨﺪام ﺑﻴﺎ ت ﻋﻠــﻰ أﻧﻈﻤــﺔ ﳐﺘﻠﻔــﺔ اﻟﻨﻘﻠﻴــﺔ ‪ portability‬و ﻫــﻰ ﻋــﺎدة‬
‫ﻣﺎ ﺗﺘﺤﻘﻖ ﰱ ﻣﻠﻔﺎت اﳌﺼﺪر و ﻻ ﳝﻜﻦ أن ﺗﺘﺤﻘﻖ ﰱ ﻣﻠﻔﺎت اﻟﺘﻨﻔﻴﺬ‪.‬‬
‫اﳌﺮﺣﻠــﺔ اﻟﺮاﺑﻌــﺔ ﻫــﻰ ﺗﻨﻔﻴــﺬ اﻟــﱪ ﻣﺞ ﻓﻌــﻼ‪ .‬و ﻫــﻰ ﻣــﺎ ﻳﻘــﻮم ﺑــﻪ اﶈﻤــﻞ ‪ loader‬اﻟــﺬى ﻳﻘـﺮأ اﻟــﱪ ﻣﺞ ﻣــﻦ اﳌﺨــﺰن اﻟﺜــﺎﻧﻮى ﻣــﺜﻼ‬
‫وﳛﻤﻠــﻪ ﰱ اﻟــﺬاﻛﺮة‪ .‬ﻳــﺘﻢ ﺗﻨﻔﻴــﺬ ذﻟــﻚ ﲟﺠــﺮد ﻛﺘﺎﺑــﺔ اﺳــﻢ اﻟــﱪ ﻣﺞ اﳌ ـﺮاد ﺗﻨﻔﻴــﺬﻩ ﻋﻠــﻰ اﻟﺸﺎﺷــﺔ‪ .‬أﺣﻴــﺎ ﻣــﺎ ﺗﻀــﺎف ﺑﻴــﺎ ت ﻟﻴــﺔ ﻻﺳــﻢ‬
‫اﻟﱪ ﻣﺞ ﻳﻘﺼﺪ ﺎ أن ﺗﻜﻮن ﺑﻴﺎ ت ﻣﺪﺧﻠﺔ ﻟﻠﱪ ﻣﺞ‪.‬ﺗﺴﻤﻰ ﻫﺬﻩ اﻟﺒﻴﺎ ت ﲟﺪﺧﻼت ﺳﻄﺮ اﻷواﻣﺮ ‪command line program‬‬
‫‪ arguments‬أو اﺧﺘﺼــﺎرا اﳌــﺪﺧﻼت ‪ .arguments‬ﰱ ﻫــﺬﻩ اﳊﺎﻟــﺔ ﻳﻘــﻮم اﶈﻤــﻞ أﻳﻀــﺎ ﺿــﺎﻓﺘﻬﺎ و وﺿــﻌﻬﺎ ﰱ ﻣﻜﺎ ــﺎ اﻟﺴــﻠﻴﻢ ﰱ‬
‫اﻟﺬاﻛﺮة‪ .‬ﻳﻌﺘﱪ اﶈﻤﻞ ﻟﻄﺒﻊ أﺣﺪ اﻟﱪاﻣﺞ اﳌﺴﺎﻋﺪة أﻳﻀﺎ‪.‬‬
‫اﳌﺮﺣﻠ ــﺔ اﳋﺎﻣﺴ ــﺔ ﺗ ــﻰ ﺑﻌ ــﺪ اﻟﺘﻨﻔﻴ ــﺬ و ﻓﺤ ــﺺ اﻟﻨﺘ ــﺎﺋﺞ ﻟﺘﺒ ــﲔ ﻣ ــﺎ إذا ﻛ ــﺎن ــﺎ ﺧﻄ ــﺄ‪ .‬ﻳﻨ ــﺘﺞ ﻫ ــﺬا اﳋﻄ ــﺄ ﻣ ــﻦ ﺧﻄـ ـﺄ ﻣﻨﻄﻘ ــﻰ‬
‫‪ semantic error‬ارﺗﻜﺒﻨــﺎﻩ أﺛﻨــﺎء ﻛﺘﺎﺑــﺔ اﻟــﱪ ﻣﺞ و ﱂ ﻧﻜﺘﺸــﻔﻪ إﻻ اﻵن‪ .‬ﳓﺘــﺎج ﺣﻴﻨﺌــﺬ ﻟــﱪ ﻣﺞ ﻣﺴــﺎﻋﺪ ﺧــﺎص ﻳﺴــﺎﻋﺪ ﻋﻠــﻰ ﺳــﺮﻋﺔ‬
‫اﻟﺘﻮﺻــﻞ ﳌﺼــﺪر اﳋﻄــﺄ و ﻳﺴــﻤﻰ اﳌﻨﻘــﻰ ‪ .debugger‬ﻳﺘــﻴﺢ ﻟﻨــﺎ اﳌﻨﻘــﻰ إﻣﻜﺎﻧﻴــﺔ ﺗﻨﻔﻴــﺬ اﻟــﱪ ﻣﺞ أﻣ ـﺮا أﻣ ـﺮا ﻣــﻊ اﻟﺘﻮﻗــﻒ ﺑﻌــﺪ أى أﻣــﺮ و‬
‫ﻓﺤــﺺ ﳏﺘــﻮى أى ﺧﺎﻧــﺔ ذاﻛــﺮة ﻟﻠﺘﺄﻛــﺪ ﻣــﻦ أن ﻣــﺎ ﲢﻮﻳــﻪ ﻫــﻮ ﻣــﺎ ﻛﻨــﺎ ﻧﺮﻳــﺪﻩ‪ .‬ﻧﺴــﺘﻄﻴﻊ أﻳﻀــﺎ أن ﻧﻌــﺪل ﻣﺆﻗﺘــﺎ ﳏﺘــﻮى أى ﺧﺎﻧــﺔ ذاﻛــﺮة‬
‫ﻟﺪراﺳﺔ و ﺗﺘﺒﻊ اﳋﻄﺄ إﱃ أن ﻧﺼﻞ ﻟﺴﺒﺒﻪ اﻷﺻﻠﻰ‪ .‬ﳝﻜﻦ أﻳﻀــﺎ أن ﻧﻄﻠــﺐ اﻟﻘﻴــﺎم ﺑﺘﻨﻔﻴــﺬ اﻟــﱪ ﻣﺞ ﺑﺼــﻮرة ﻋﺎدﻳــﺔ ﻣــﻊ اﻟﺘﻮﻗــﻒ ﻓﻘــﻂ ﻋﻨــﺪ‬
‫أﻣﺮ ﻣﻌــﲔ ﻧﻌﺘﻘــﺪ أن اﳋﻄــﺄ ﻳﻘــﻊ ﻓﻴــﻪ‪ .‬ﻃﻠــﺐ اﻟﺘﻮﻗــﻒ ﻋﻨــﺪ أﻣـﺮ ﻣــﺎ ﻳﺴــﻤﻰ إﺿــﺎﻓﺔ ﻧﻘﻄــﺔ وﻗــﻮف ‪ .break point‬ﻗــﺪ ﺗﻜــﻮن أﻳﻀــﺎ ﻧﻘﻄــﺔ‬
‫اﻟﻮﻗــﻮف ﻣﺸــﺮوﻃﺔ أى أن ﻧﻘــﻮل ﻟﻠﻤﻨﻘــﻰ ﻗــﻒ ﻋﻨــﺪ اﻷﻣــﺮ اﳌﻮﺟــﻮد ﻋﻨــﺪ اﻟﺴــﻄﺮ رﻗــﻢ ﻛــﺬا إذا ﻛــﺎن ﳏﺘــﻮى اﻟــﺬاﻛﺮة س ﺳــﺎﻟﺒﺎ ﻣــﺜﻼ‪ .‬ﺑﻌــﺪ‬
‫اﻛﺘﺸﺎف اﳋﻄﺄ ﺗﻌﺎد ﺻﻴﺎﻏﺔ ﻣﻠﻒ اﳌﺼﺪر ﻟﺘﺼﺤﻴﺢ اﳋﻄﺄ و ﺗﻌﺎد اﻟﱰﲨﺔ و اﻟﻮﺻﻞ واﻻﺧﺘﺒﺎر إﱃ أن ﻧﺘﺄﻛﺪ ﻣﻦ ﺻﺤﺔ اﻟﱪ ﻣﺞ‪.‬‬
‫ﺑﻌ ــﺾ ﻟﻐ ــﺎت اﻟﱪﳎ ــﺔ ﻣﺜ ــﻞ اﻟﺒﻴ ــﺰك ‪ BASIC‬ﺗﺴ ــﻤﺢ ﺧﺘﺼ ــﺎر ﻛ ــﻞ ﻫ ــﺬﻩ اﳋﻄـ ـﻮات ﲝﻴ ــﺚ ﻳﺘ ــﻮﱃ اﻟﱰﲨ ــﺔ ﻣ ــﱰﺟﻢ ﻣﺒﺎﺷ ــﺮ‬
‫‪ interpreter‬ﻳﻘﻮم ﻟﱰﲨﺔ واﻟﺘﻨﻔﻴﺬ ﺳﻄﺮا ﺑﺴﻄﺮ‪ .‬و ﻟﻜﻦ ذﻟﻚ ﻳﻨﻄﺒــﻖ أﺳﺎﺳــﺎ ﻋﻠــﻰ اﻟﻠﻐــﺎت ﻏــﲑ اﳌﻬﻴﻜﻠــﺔ ﻛﻤــﺎ ﻳﻌﻴﺒــﻪ ﺑــﻂء اﻟﺘﻨﻔﻴــﺬ و‬
‫ﻟﺬﻟﻚ ﻟﻦ ﻧﺘﻌﺎﻣﻞ ﻣﻊ ﻫﺬا اﻷﺳﻠﻮب‪.‬‬
‫ﻫﻨﺎك دورة ﺣﻴﺎة ﻷى ﺑﺮ ﻣﺞ ﺗﺒﺪأ ﻣﻨﺬ ﻧﺸﺄة اﳊﺎﺟﺔ ﻟﻠــﱪ ﻣﺞ‪ .‬ﲤﺘــﺪ ﺑﻌــﺪ ذﻟــﻚ ﻟﻠﺘﺨﻄــﻴﻂ ﻟــﻪ ﰒ ﺗﺼــﻨﻴﻌﻪ‪ .‬ﱂ ﻧﺘﻌــﺮض ﰱ ﻫــﺬﻩ‬
‫اﻟﻔﻘﺮة ﺳﻮى ﻟﺒﻌﺾ ﺟﻮاﻧﺐ ﻣﻦ ﻋﻤﻠﻴﺔ اﻟﺘﺼﻨﻴﻊ‪ .‬ﺗﺸﻤﻞ اﻟﺪورة أﻳﻀﺎ ﺗﻮزﻳﻊ اﻟﱪ ﻣﺞ و ﻣﺘﺎﺑﻌﺔ ﺗﻄﻮﻳﺮﻩ إﱃ أن ﻳﺘﻢ إﺣﻼﻟﻪ ﺑــﱪ ﻣﺞ آﺧــﺮ‪.‬‬
‫ﺳﻨﺪرس دورة اﳊﻴﺎة ﻫﺬﻩ ﺑﻘﺪر ﻣﺎ ﻣﻦ اﻟﺘﻔﺼﻴﻞ ﰱ ﺟﺰء ﻻﺣﻖ ﻣﻦ ﻫﺬا اﳌﻨﻬﺞ‪.‬‬

‫‪21‬‬
‫اﻷﺳﺎﺳﻴﺔ ‪Basic language instructions‬‬ ‫أواﻣﺮ اﻟﻠﻐﺔ‬ ‫‪.2‬‬

‫‪.2‬أ‪ .‬ﻣﻘﺪﻣﺔ ‪Introduction‬‬


‫ﺗﻌﺘﻤﺪ ﲨﻴﻊ ﻟﻐﺎت اﻟﱪﳎﺔ ﻣﺮﺗﻔﻌﺔ اﳌﺴﺘﻮى ﻋﻠﻰ ﻣﻔﺎﻫﻴﻢ أﺳﺎﺳــﻴﺔ ﻣﺘﺸــﺎ ﺔ ﻻ ﲣﺘﻠــﻒ ﺧــﺘﻼف اﻟﻠﻐــﺔ و ﻟﻜــﻦ ﻣــﺎ ﳜﺘﻠــﻒ ﻫــﻮ‬
‫اﻟﺸــﻜﻞ اﻟــﺬى ﺧــﺬﻩ ﻛــﻞ ﻣﻔﻬــﻮم‪ .‬ﳒــﺪ ﻣﺜــﺎﻻ ﺑﺴــﻴﻄﺎ ﻟــﺬﻟﻚ ﰱ اﻟﻠﻐــﺎت اﻟﻄﺒﻴﻌﻴــﺔ‪ .‬ﺣﻴــﺚ ﺗﺸــﱰك ﲨﻴــﻊ ﻫــﺬﻩ اﻟﻠﻐــﺎت ﰱ اﳊــﺪﻳﺚ ﻋــﻦ‬
‫اﻷﻓﻌﺎل و اﻷﲰﺎء و ﻛﺬا اﻟﺘﺼﺎرﻳﻒ ﻣﻦ ﲨﻊ و ﻧﻴﺚ و ﻣﻀﺎرع و أﻣﺮ ‪..‬اﱁ‪ .‬و ﻻ ﲣﺘﻠــﻒ إﻻ ﰱ اﻟﺸــﻜﻞ ﻓــﺎﳉﻤﻊ ﰱ اﻟﻠﻐــﺔ اﻹﳒﻠﻴﺰﻳــﺔ‬
‫ﻳﺘﻢ ﻣﺜﻼ ﺿﺎﻓﺔ ﺣﺮف ‪ s‬و ﻟﻜﻨﻪ ﰱ اﻟﻠﻐــﺔ اﻟﻌﺮﺑﻴــﺔ ﻳــﺘﻢ ﺿــﺎﻓﺔ واو وﻧــﻮن ﰱ ﺣﺎﻟــﺔ اﳌــﺬﻛﺮ اﻟﺴــﺎﱂ إﱃ آﺧــﺮﻩ ﻣــﻦ اﳊــﺎﻻت‪ .‬ﻛــﺬﻟﻚ اﳊــﺎل‬
‫ﻟﻨﺴــﺒﺔ ﻟﻠﻐــﺎت اﻟﱪﳎــﺔ‪ .‬ﻓﻤــﺎ ﺳــﻨﻬﺘﻢ ﻟﱰﻛﻴــﺰ ﻋﻠﻴــﻪ ﻫــﻮ اﳌﻔــﺎﻫﻴﻢ اﻟﻌﺎﻣــﺔ اﻟــﱴ ﳝﻜــﻦ أن ﳒــﺪﻫﺎ ﰱ أﻳــﺔ ﻟﻐــﺔ ﻣــﻦ ﻟﻐــﺎت اﻟﱪﳎــﺔ‪ .‬وإذا ﲤﻜــﻦ‬
‫اﻟﻄﺎﻟﺐ ﻣﻦ إدراك ﺗﻠﻚ اﳌﻔﺎﻫﻴﻢ ﺳﺘﺨﺪام أﻳﺔ ﻟﻐﺔ ﳝﻜﻨــﻪ اﻟﺘﺤــﻮل ﺑﺴــﻬﻮﻟﺔ ﻷﻳــﺔ ﻟﻐـﺔ أﺧــﺮى‪ ،‬ﺧﺎﺻــﺔ و أن ﻋــﺪد ﻣﻔــﺮدات ﻟﻐــﺎت اﻟﱪﳎــﺔ‬
‫ﻗﻠﻴﻞ ﺟﺪا‪.‬‬
‫ﺳ ـ ــﻨﻌﺘﻤﺪ ﻟﻐ ـ ــﺔ ال ‪ C‬ﻛﻤﺜ ـ ــﺎل أﺛﻨ ـ ــﺎء ﺷ ـ ــﺮح ﻫ ـ ــﺬﻩ اﳌﻔ ـ ــﺎﻫﻴﻢ اﻷﺳﺎﺳ ـ ــﻴﺔ و ذﻟ ـ ــﻚ ﻟﻌ ـ ــﺪة أﺳ ـ ــﺒﺎب‪ .‬أوﻻ ﻫ ـ ــﺬﻩ اﻟﻠﻐ ـ ــﺔ ﻫﻴﻜﻠﻴ ـ ــﺔ‬
‫‪ structured‬و ﻫ ـ ــﻮ ﻣ ـ ــﺎ ﻳﺘ ـ ــﻴﺢ اﻟﱪﳎ ـ ــﺔ اﳍﻴﻜﻠﻴ ـ ــﺔ ﲟﺰا ﻫ ـ ــﺎ اﳌﺘﻌ ـ ــﺪدة ﻣ ـ ــﻦ ﺳ ـ ــﻬﻮﻟﺔ ﻛﺘﺎﺑ ـ ــﺔ وﺗﻌ ـ ــﺪﻳﻞ اﻟـ ـ ـﱪاﻣﺞ‪ .‬ﻧﻴ ـ ــﺎ ﲢ ـ ــﻮى ﻫ ـ ــﺬﻩ اﻟﻠﻐ ـ ــﺔ‬
‫أواﻣـ ــﺮ ﺗﻨﺘﻤـ ــﻰ ﻟﻔﺌـ ــﺔ اﻟﻠﻐـ ــﺎت ﻋﺎﻟﻴـ ــﺔ اﳌﺴـ ــﺘﻮى ‪ high level language‬ﻛﻤـ ــﺎ ﲢـ ــﻮى أﻳﻀـ ــﺎ أواﻣـ ــﺮ ﺗﻘـ ــﱰب ﻣـ ــﻦ ﻓﺌـ ــﺔ اﻟﻠﻐـ ــﺎت‬
‫ﻣﻨﺨﻔﻀ ــﺔ اﳌﺴ ــﺘﻮى ‪ .low level‬و ﻟ ــﺬﻟﻚ ﻓﺈ ــﺎ أﺣﻴ ــﺎ ﻣ ــﺎ ﺗﺼ ــﻨﻒ ﻋﻠ ــﻰ أ ــﺎ ﻟﻐ ــﺔ ﻋﻠ ــﻰ ﻣﺴ ــﺘﻮى اﻧﺘﻘ ــﺎﱃ ‪intermediate‬‬
‫‪ .level‬ﺗﺴ ـ ــﻤﺢ ﻫـ ــﺬﻩ اﳋﺎﺻ ـ ــﻴﺔ ﺑﻜﺘﺎﺑ ـ ــﺔ ﺑ ـ ـﺮاﻣﺞ ﻣﺘﻨﻮﻋ ـ ــﺔ ﻋﻠ ـ ــﻰ ﻣﺴ ـ ــﺘﻮى ﻋ ـ ــﺎﱃ ﻣ ـ ــﻦ اﻷداء ﲝﻴ ـ ــﺚ ﳝﻜ ـ ــﻦ ﺧﻠـ ــﻂ أﺟ ـ ـﺰاء ﻣ ـ ــﻦ اﻟ ـ ـﱪاﻣﺞ‬
‫ﻋﻠ ـ ــﻰ ﻣﺴ ـ ــﺘﻮ ت ﳐﺘﻠﻔ ـ ــﺔ و ﺑ ـ ــﺬﻟﻚ ﳝﻜ ـ ــﻦ اﻻﺳ ـ ــﺘﻔﺎدة ﻣ ـ ــﻦ ﻣـ ـ ـﺰا اﳌﺴ ـ ــﺘﻮﻳﲔ‪ .‬ﻓﺒﻴﻨﻤ ـ ــﺎ ﻳﺘ ـ ــﻴﺢ اﳌﺴ ـ ــﺘﻮى اﻟﻌ ـ ــﺎﱃ )اﻟﻘﺮﻳ ـ ــﺐ ﻣ ـ ــﻦ اﻟﺒﺸ ـ ــﺮ(‬
‫ﻛﺘﺎﺑ ـ ــﺔ ﺧﻄـ ـ ـﻮات ﻣﻌﻘ ـ ــﺪة ﺳ ـ ــﻠﻮب ﺳ ـ ــﻬﻞ و واﺿ ـ ــﺢ‪ ،‬ﻓ ـ ــﺈن اﳌﺴ ـ ــﺘﻮى اﳌ ـ ــﻨﺨﻔﺾ )اﻟﻘﺮﻳ ـ ــﺐ ﻣ ـ ــﻦ اﻵﻟ ـ ــﺔ( ﻳﺘ ـ ــﻴﺢ ﻛﺘﺎﺑ ـ ــﺔ أﺟـ ـ ـﺰاء ﳏ ـ ــﺪدة‬
‫ﻣـ ـ ــﻦ اﻟ ـ ـ ـﱪاﻣﺞ ﺳـ ـ ــﻠﻮب ﻳﺴـ ـ ــﻤﺢ ﻻﺳ ـ ــﺘﺨﺪام اﻷﻣﺜـ ـ ــﻞ ﻹﻣﻜﺎﻧﻴـ ـ ــﺎت اﻵﻟـ ـ ــﺔ و ﻟﺘـ ـ ــﺎﱃ ﺳ ـ ــﺮﻋﺔ اﻟﺘﻨﻔﻴـ ـ ــﺬ‪ .‬ﻳﻼﺣـ ـ ــﻆ أن اﻷواﻣـ ـ ــﺮ اﻟﻘﺮﻳﺒـ ـ ــﺔ‬
‫ﻣـ ــﻦ اﻵﻟـ ــﺔ ﻳـ ــﺘﻢ ﺗﻨﻔﻴـ ــﺬﻫﺎ ﻋـ ــﻦ ﻃﺮﻳـ ــﻖ اﺳـ ــﺘﺪﻋﺎء ﻣﻜﺘﺒـ ــﺔ ﻣـ ــﻦ اﻟ ـ ـﱪاﻣﺞ اﳉﺰﺋﻴـ ــﺔ ﲣﺘﻠـ ــﻒ ﻣـ ــﻦ آﻟـ ــﺔ ﻷﺧـ ــﺮى‪ .‬و ﺑـ ــﺬﻟﻚ ﻓـ ــﺈن ﻫﻨـ ــﺎك ﻗﺎﺑﻠﻴـ ــﺔ‬
‫ﻛﺒـ ــﲑة ﻟﻨﻘـ ــﻞ ﺑـ ــﺮ ﻣﺞ ﻣﻜﺘـ ــﻮب ﺑﻠﻐـ ــﺔ ال ‪ C‬ﻣـ ــﻦ آﻟـ ــﺔ ﻷﺧـ ــﺮى ‪ high portability‬ﻟـ ــﺮﻏﻢ ﻣـ ــﻦ اﺣﺘﻮاﺋـ ــﻪ ﻷواﻣـ ــﺮ ﻗﺮﻳﺒـ ــﺔ ﻣـ ــﻦ ﻟﻐـ ــﺔ‬
‫اﻵﻟﺔ‪ .‬ﻷﺟﻞ ﻫﺬﻩ اﻷﺳﺒﺎب ﳎﺘﻤﻌﺔ ﻓﺈن ﻫﺬﻩ اﻟﻠﻐﺔ ﻫﻰ اﻵن اﻷﻛﺜﺮ اﺳﺘﺨﺪاﻣﺎ ﰱ اﻟﺼﻨﺎﻋﺔ‪.‬‬

‫‪.2‬ب‪ .‬أﺳﺎﺳﻴﺎت ﻟﻐﺎت اﻟﱪﳎﺔ‪Basics of programming languages‬‬


‫ﺳﻨﺴــﺘﻌﺮض اﻟﻌﻨﺎﺻــﺮ اﻷﺳﺎﺳــﻴﺔ ﻷﻳــﺔ ﻟﻐــﺔ ﻣــﻦ ﻟﻐــﺎت اﳊﺎﺳــﺐ ﺑــﻨﻔﺲ اﻷﺳــﻠﻮب اﳌﺘﺒــﻊ ﻋــﺎدة ﻣـﻊ اﻟﻠﻐــﺎت اﻟﻄﺒﻴﻌﻴــﺔ ﺑﺘﻘﺴــﻴﻤﻬﺎ‬
‫ﳊــﺮوف و ﻛﻠﻤــﺎت و ﲨــﻞ و ﻓﻘ ـﺮات‪ .‬ﺳــﻴﻜﻮن اﻟﻌــﺮض ﻋﺎﻣــﺎ ﰱ ﻫــﺬا اﻟﻔﺼــﻞ ﻟﻠﺘﻮﻛﻴــﺪ ﻋﻠــﻰ ﻋﻤﻮﻣﻴــﺔ ﻫــﺬﻩ اﳌﻔــﺎﻫﻴﻢ ﰱ ﲨﻴــﻊ اﻟﻠﻐــﺎت‪،‬‬
‫ﻣﺮﺟﺌﲔ اﳊﺪﻳﺚ ﻋﻦ ﻟﻐﺔ ‪ C‬ﻟﻠﻔﺼﻞ اﻟﺘﺎﱃ‪.‬‬

‫‪.2‬ب‪ .1.‬اﳊﺮوف‪Character set :‬‬


‫اﳊﺮوف ﻫﻰ ﳎﻤﻞ اﻟﺮﻣﻮز اﻟﱴ ﳝﻜﻦ أن ﻳﺘﻌﺎﻣﻞ ﻣﻌﻬﺎ ﻣﱰﺟﻢ اﻟﻠﻐﺔ اﳌﻌﻨﻴــﺔ‪ .‬ﻋــﺎدة ﻣــﺎﺗﺘﻜﻮن ﻣــﻦ ﺣــﺮوف اﻷﲜﺪﻳــﺔ و اﻷرﻗــﺎم و‬
‫ﺑﻌﺾ ﻋﻼﻣﺎت اﻟﱰﻗﻴﻢ اﻟﱴ ﲣﺘﻠﻒ ﻣﻦ ﻟﻐﺔ ﻷﺧﺮى‪.‬‬

‫‪22‬‬
‫‪.2‬ب‪ .2.‬اﻟﻜﻠﻤﺎت‪Words :‬‬
‫ﻫﻨﺎك ﺛﻼﺛﺔ أﻧﻮاع أﺳﺎﺳﻴﺔ ﻣﻦ اﻟﻜﻠﻤﺎت ﰱ أﻳــﺔ ﻟﻐــﺔ‪ ،‬ﻹﺿــﺎﻓﺔ ﻟﻠﻔﻮاﺻــﻞ ﺑــﲔ اﻟﻜﻠﻤــﺎت و ﺑﻌﻀــﻬﺎ اﻟــﺒﻌﺾ‪ .‬اﻟﻨــﻮع اﻷول ﻫــﻮ‬
‫ﻣﻔﺮدات اﻟﻠﻐﺔ أى اﻟﻜﻠﻤﺎت اﻟﱴ ﲡﺴــﺪ ﳐﺘﻠــﻒ اﻷواﻣــﺮ ﰱ اﻟﻠﻐــﺔ‪ .‬و ﻫــﻰ ﺗﺴــﻤﻰ اﻟﻜﻠﻤــﺎت اﶈﺠــﻮزة ‪ .reserved keywords‬ﻋــﺪد‬
‫ﻫــﺬﻩ اﻟﻜﻠﻤــﺎت ﰱ أﻳــﺔ ﻟﻐــﺔ ﻗﻠﻴــﻞ ﺟــﺪا‪ ،‬ﻻ ﻳﺘﺠــﺎوز ﺑﻀــﻌﺔ ﻋﺸـﺮات‪ ،‬ﺑﻌﻜــﺲ اﻟﻠﻐــﺎت اﻟﻄﺒﻴﻌﻴــﺔ و اﻟــﱴ ﺗﺘﻜــﻮن ﻣــﻦ ﻋﺸـﺮات اﻷﻟــﻮف ﻣــﻦ‬
‫اﻟﻜﻠﻤــﺎت‪ .‬إن ﻗﻠــﺔ ﻋــﺪد اﻟﻜﻠﻤــﺎت اﶈﺠــﻮزة ﺗﺆﻛــﺪ اﳊﻘﻴﻘــﺔ اﻟــﱴ ﻣﻔﺎدﻫــﺎ أن ﻣــﻦ أﺗﻘــﻦ اﻟﱪﳎــﺔ ﺑﻠﻐــﺔ ﻣــﺎ‪ ،‬ﻳﺴــﺘﻄﻴﻊ أن ﻳﻨﺘﻘــﻞ ﺑﺴــﻬﻮﻟﺔ ﻟﻠﻐــﺔ‬
‫أﺧــﺮى‪ ،‬ﺑﻌــﺪ ﺗﻌﻠــﻢ ﻋــﺪد ﳏــﺪود ﺟــﺪا ﻣــﻦ اﻟﻜﻠﻤــﺎت اﳉﺪﻳــﺪة‪ .‬اﻷﺳــﺎس ﻫــﻮ اﺳــﺘﻴﻌﺎب اﳌﻔــﺎﻫﻴﻢ اﻟﱪﳎﻴــﺔ اﻟــﱴ ﺗﻌﻜﺴــﻬﺎ ﻫــﺬﻩ اﻟﻜﻠﻤــﺎت و‬
‫ﻟ ــﻴﺲ ﻧ ــﺺ اﻟﻜﻠﻤ ــﺔ‪ .‬ﲤﺘ ــﺎز ﻟﻐ ــﺔ ال ‪ C‬ﺣﺘﻮاﺋﻬ ــﺎ ﻋﻠ ــﻰ ﻛﺎﻓ ــﺔ اﳌﻔ ــﺎﻫﻴﻢ اﳌﻮﺟ ــﻮدة ﰱ اﻟﻠﻐ ــﺎت اﻟﺸ ــﻬﲑة اﻷﺧ ــﺮى )ﻣﺜ ــﻞ ‪ FORTAN‬و‬
‫‪ (BASIC‬ﻹﺿﺎﻓﺔ ﳌﻔﺎﻫﻴﻢ ﺟﺪﻳﺪة ﺧﺎﺻﺔ ــﺎ‪ .‬و ﻟــﺬﻟﻚ ﻓــﺈن اﺗﻘــﺎن ﻟﻐــﺔ ال ‪ C‬ﻳﺴــﻬﻞ ﻋﻠــﻰ اﳌــﱪﻣﺞ اﺗﻘــﺎن أﻳــﺔ ﻟﻐــﺔ أﺧــﺮى‪ .‬ﺳــﻨﻌﻄﻰ‬
‫اﻟﻜﻠﻤﺎت اﶈﺠﻮزة ﻟﻠﻐﺔ ال ‪ C‬ﰱ اﻟﻔﺼﻞ اﻟﺘﺎﱃ‪.‬‬
‫أﻣﺎ اﻟﻨﻮع اﻟﺜﺎﱏ ﻣﻦ اﻟﻜﻠﻤﺎت ﻓﻬﻰ أﲰﺎء اﻟﻌﻠﻢ اﻟﱴ ﳜﺘﺎرﻫــﺎ ﻛﺎﺗــﺐ اﻟــﱪ ﻣﺞ ﻟﺘﻌﺮﻳــﻒ أﲰــﺎء اﳌﺘﻐـﲑات أو اﻟــﺪوال ﻳﺴــﺘﺨﺪﻣﻬﺎ‪.‬‬
‫و ﻟــﺬا ﺗﺴــﻤﻰ أﲰــﺎء اﻟﻌﻠــﻢ ﻣﻌﺮﻓــﺎت ‪ identifiers‬و ﳝﻜــﻦ ﻟﻜﺎﺗــﺐ اﻟــﱪ ﻣﺞ أن ﳜﺘﺎرﻫــﺎ ﻛﻤــﺎ ﻳﺸــﺎء ﰱ ﺣــﺪود ﻗﻮاﻋــﺪ ﺑﺴــﻴﻄﺔ‪ .‬اﳌﻘﺼــﻮد‬
‫ﺬﻩ اﻟﻘﻮاﻋﺪ ﻫﻮ ﺗﻔﺎدى اﻹ ﺎم أو اﻟﻠــﺒﺲ‪ ،‬ﺣﻴــﺚ أﻧــﻪ ﰱ ﲨﻴــﻊ اﻟﻠﻐــﺎت ﻻ ﻳﺴــﻤﺢ ن ﳜﺘــﺎر اﳌــﱪﻣﺞ إﲰــﺎ ﳛــﻮى ﻋﻼﻣــﺔ ‪ +‬ﻣــﺜﻼ‪ .‬و إﻻ‬
‫ﻓﻜﻴﻒ ﺳﻴﺴﺘﻄﻴﻊ اﳊﺎﺳﺐ اﻟﺘﻤﻴﻴﺰ ﺑﲔ اﳌﺘﻐﲑ اﻟﺬى أﲰﻪ ‪ x+y‬و ﺑﲔ ﻋﻤﻠﻴﺔ اﳉﻤﻊ ﺑﲔ اﳌﺘﻐﲑﻳﻦ ‪ x‬و ‪.y‬‬
‫اﻟﻨ ــﻮع اﻟﺜﺎﻟ ــﺚ ﻫ ــﻮ اﻟﺜﻮاﺑ ــﺖ ‪ constants‬و ﻫ ــﻰ ﺗﻌ ــﱪ ﻋ ــﻦ ﻗ ــﻴﻢ ﺑﺼ ــﻮرة ﻣﺒﺎﺷ ــﺮة ﻣﺜ ــﻞ اﻟﻌ ــﺪد ‪ 2.35‬أو اﳊ ــﺮوف ﰱ اﳉﻤﻠ ــﺔ‬
‫"‪ ."Ahmed‬ﲣﺘﻠــﻒ اﻟﺼــﻮرة اﻟــﱴ ﻧﻌــﱪ ــﺎ ﻋــﻦ اﻟﺜﻮاﺑــﺖ ﺧــﺘﻼف اﻟﻠﻐــﺎت‪ ،‬و ﻟــﺬا ﺳــﻨﺘﻨﺎول ﺗﻠــﻚ اﳊــﺎﻻت ﻟﺘﻔﺼــﻴﻞ ﻓﻴﻤــﺎ ﺑﻌــﺪ‪.‬ﻻ‬
‫ﳝﻜﻦ أن ﻧــﱰك ﻫــﺬﻩ اﻟﻔﻘــﺮة ﺑــﺪون ﻟﻔــﺖ اﻻﻧﺘﺒــﺎﻩ ﻷﳘﻴــﺔ اﻟﻔﻮاﺻــﻞ ‪ separators‬اﻟــﱴ ﺗﻔﺼــﻞ ﺑــﲔ اﻟﻜﻠﻤــﺎت و ﻫــﻰ ﺗﻌــﺪ ﲟﺜﺎﺑــﺔ ﻋﻼﻣــﺎت‬
‫اﻟﱰﻗﻴﻢ ﰱ اﻟﻠﻐﺔ‪ .‬ﻟﻌــﻞ اﻟﻘــﺎرئ ﻳــﺪرك أن ﺗﻐﻴــﲑ ﻣﻮﺿــﻊ ﻓﺎﺻــﻠﺔ أو ﻧﻘﻄــﺔ ﰱ ﻟﻐــﺎت اﻟﱪﳎــﺔ‪ ،‬ﻛﻤــﺎ ﻫــﻮ اﳊــﺎل أﻳﻀــﺎ ﰱ اﻟﻠﻐــﺎت اﻟﻄﺒﻴﻌﻴــﺔ‪ ،‬ﻗــﺪ‬
‫ﻳﻐﲑ ﲤﺎﻣﺎ ﻣﻦ ﻣﻌﲎ ﲨﻠﺔ‪.‬‬

‫‪.2‬ب‪ .3.‬اﳉﻤﻞ ‪Statements‬‬


‫اﳉﻤﻠــﺔ ﻫــﻰ ﺗﺮﻛﻴﺒــﺔ ﻣــﻦ ﻛﻠﻤــﺎت و ﻓﻮاﺻــﻞ ﺗﺸــﻜﻞ ﻛﻴــﺎ ﻣﺘﻜــﺎﻣﻼ‪ ،‬ﳜﺘﻠــﻒ ﻧﻮﻋــﻪ ﺧــﺘﻼف اﳉﻬــﺔ اﳌﻮﺟــﻪ إﻟﻴﻬــﺎ ﻫــﺬا اﻟﻜﻴــﺎن‪.‬‬
‫ﻫﻨﺎك ﺛﻼﺛﺔ ﺣﺎﻻت‪:‬‬
‫‪ -‬ﲨﻞ ﻣﻮﺟﻬﺔ ﻟﻠﺒﺸﺮ‪ ،‬أى ﺗﻌﻠﻴﻘﺎت ﺗﻀﺎف ﻟﻠﱪ ﻣﺞ ﻟﺘﺴﻬﻴﻞ ﻗﺮاﺋﺘﻪ‪.‬‬
‫‪ -‬ﲨﻞ ﻣﻮﺟﻬﺔ ﻟﻠﻤﱰﺟﻢ‪ ،‬ﻟﺸﺮح أﺳﻠﻮب اﻟﱰﲨﺔ‪.‬‬
‫‪ -‬ﲨﻞ ﻣﻮﺟﻬﺔ ﻟﻮﺣﺪة اﻟﺘﺤﻜﻢ اﳌﺮﻛﺰﻳﺔ و ﲤﺜﻞ أواﻣﺮ اﻟﱪﳎﺔ اﳌﺴﺘﺨﺪﻣﺔ ﰱ اﻟﻠﻐﺔ‪.‬‬
‫ﳛــﻮى أﻳــﺔ ﺑــﺮ ﻣﺞ اﻷﻧ ـﻮاع اﻟﺜﻼﺛــﺔ ﻣــﻦ اﳉﻤــﻞ‪ .‬و ﻟــﺬﻟﻚ ﳚــﺐ أن ﺗﻜــﻮن ﻫﻨــﺎك ﻋﻼﻣــﺎت ﺧﺎﺻــﺔ ﰱ ﺑﺪاﻳــﺔ ﻛــﻞ ﲨﻠــﺔ ﺗﻮﺿــﺢ‬
‫اﳉﻬﺔ اﳌﻘﺼﻮدة‪ .‬ﲢﻮى ﲨﻴﻊ ﻟﻐﺎت اﳊﺎﺳــﺐ اﻷﻧـﻮاع اﻟﺜﻼﺛــﺔ‪ ،‬و ﻻ ﲣﺘﻠــﻒ إﻻ ﰱ ﺷــﻜﻞ اﻟﻌﻼﻣــﺎت اﳌﻤﻴــﺰة ﻟﻜــﻞ ﻧــﻮع‪ .‬ﻟﻨﺴــﺒﺔ ﻟﻠﺠﻤــﻞ‬
‫اﳌﻮﺟﻬــﺔ ﻟﻠﺒﺸــﺮ‪ ،‬ﻓــﺈن اﻟﻘﺎﻋــﺪة ﻫــﻰ أن ﻳﺘﺠﺎﻫﻠﻬــﺎ اﳊﺎﺳــﺐ ﲤﺎﻣــﺎ‪ .‬و ﻟﻜﻨﻨــﺎ ﻧﺸــﺪد ﻋﻠــﻰ أﳘﻴــﺔ أن ﳛﺘــﻮى اﻟــﱪ ﻣﺞ ﻋﻠــﻰ ﻗــﺪر ﻛــﺎﰱ ﻣــﻦ‬
‫اﻟﺘﻌﻠﻴﻘــﺎت ﺣــﱴ ﻳﺴــﻬﻞ ﺗﻌﺪﻳﻠــﻪ و ﺗﻄــﻮﻳﺮﻩ‪ .‬ﻛﻤﺜــﺎل ﻟﻠﺠﻤــﻞ اﳌﻮﺟﻬــﺔ ﻟﻠﻤــﱰﺟﻢ‪ ،‬ﳝﻜــﻦ أن ﻧــﺬﻛﺮ أﻣــﺮ ﺗﻌﺮﻳــﻒ ﻣﻜﺘﺒ ـﺔ اﻟ ـﱪاﻣﺞ اﳌﺴــﺎﻋﺪة‬
‫‪ library‬اﻟﱴ ﲢﻮى دوال ﻣﻔﻴﺪة ﺗﺴﺘﺨﺪم ﰱ ﺑﺮاﻣﺞ ﻣﺘﻌﺪدة و ﻧﺮﻳﺪ أن ﻧﺴﺘﺨﺪﻣﻬﺎ ﰱ ﻫــﺬا اﻟــﱪ ﻣﺞ‪ .‬ﻋﻨــﺪﻣﺎ ﻳــﺮى اﳌــﱰﺟﻢ ﻫــﺬا اﻷﻣــﺮ‪،‬‬
‫ﻳﻘــﻮم ﺳــﺘﺪﻋﺎء اﻟﺘﻌﺮﻳﻔــﺎت اﳌﻨــﺎﻇﺮة ﻹﳊﺎﻗﻬــﺎ ﻟــﱪ ﻣﺞ‪ ،‬و ﻟﻜــﻦ ﻫــﺬا اﻷﻣــﺮ ﺑﺬاﺗــﻪ ﻻ ﳝﺜــﻞ أﻣـﺮا ﻣﻮﺟﻬــﺎ ﻟﻮﺣــﺪة اﻟــﺘﺤﻜﻢ اﳌﺮﻛﺰﻳــﺔ ﻹﺟــﺮاء‬
‫ﻋﻤﻠﻴﺔ ﺣﺴﺎﺑﻴﺔ أو ﻣﻨﻄﻘﻴﺔ ﻣﺜﻼ‪ .‬اﻟﻨﻮع اﻷﺧﲑ ﻣﻦ اﳉﻤﻞ ﻫﻮ ﺻﻠﺐ اﻟﱪ ﻣﺞ‪ ،‬و ﳝﺜﻞ أواﻣﺮ اﻟﱪﳎﺔ‪.‬‬
‫ﻫﻨﺎك ﲬﺲ ﳎﻤﻮﻋﺎت ﻣﻦ أواﻣﺮ اﻟﱪﳎﺔ ﰱ أﻳﺔ ﻟﻐﺔ و ﻫﻰ‪:‬‬

‫‪23‬‬
‫‪ -1‬أواﻣﺮ ﺗﻌﺮﻳﻒ اﻟﺒﻴﺎ ت ‪data definition statements‬‬
‫ﻫﺬﻩ اﺠﻤﻟﻤﻮﻋﺔ ﺗﺘﻌﻠﻖ ﺳﻠﻮب ﺗﻌﺮﻳﻒ اﳊﺎﺳﺐ ﳌﺘﻐﲑات اﻟﱴ ﺳﻨﺘﻌﺎﻣﻞ ﻣﻌﻬﺎ و ﻧﻮﻋﻴﺘﻬﺎ )أﻋﺪاد أو ﺣﺮوف‪ ،‬ﺑﻴﺎ ت ﺑﺴــﻴﻄﺔ‬
‫أو ﻣﺮﻛﺒﺔ اﱁ(‬
‫‪ -2‬أﻣﺮ اﻹﺳﻨﺎد و اﻟﺘﻌﺒﲑات ‪assignment statement and expressions‬‬
‫ﻳﺴﻤﺢ ﻫﺬا اﻷﻣﺮ ﺳﻨﺎد ﻗﻴﻤﺔ ﻣﺎ ﳋﺎﻧﺔ ﻣﻦ ﺧﺎ ت اﻟﺬاﻛﺮة‪ .‬ﻳﺘﻢ ﺣﺴﺎب اﻟﻘﻴﻤــﺔ اﳌـﺮاد إﺳــﻨﺎدﻫﺎ ﺑﻮاﺳــﻄﺔ اﻟﺘﻌﺒـﲑات اﳌﺨﺘﻠﻔــﺔ‬
‫ﻣﻦ ﻋﻤﻠﻴﺎت ﺣﺴﺎﺑﻴﺔ أو ﻣﻨﻄﻘﻴﺔ أو ﻋﻤﻠﻴﺎت ﻋﻠﻰ اﳊﺮوف‪.‬‬
‫‪ -3‬أواﻣﺮ اﻹدﺧﺎل و اﻹﺧﺮاج ‪input / output statements‬‬
‫ﺗﺴﺘﺨﺪم ﻫﺬﻩ اﻷواﻣﺮ ﻟﻘﺮاءة ﺑﻴﺎ ت ﻣﻦ وﺳﺎﺋﻞ اﻹدﺧﺎل اﳌﺨﺘﻠﻔﺔ و ﻛﺬا ﻛﺘﺎﺑﺘﻬﺎ ﻋﻠﻰ وﺳﺎﺋﻂ اﻹﺧﺮاج‪.‬‬
‫‪ – 4‬أواﻣﺮ اﻟﺘﺤﻜﻢ ﰱ ﺳﲑ اﻟﱪ ﻣﺞ ‪program control statements‬‬
‫ﺗﺴــﺘﺨﺪم ﻫــﺬﻩ اﻷواﻣــﺮ ﻟﺘﻌــﺪﻳﻞ ﺳــﲑ اﻟــﱪ ﻣﺞ ﰱ ﺣﺎﻟــﺔ ﲢﻘــﻖ ﺷــﺮوط ﻣﻌﻴﻨــﺔ‪ ،‬ﻛﻤــﺎ ﺗﺴــﻤﺢ أﻳﻀــﺎ ﻟﻘﻴــﺎم ﺑﻌﻤﻠﻴــﺎت ﺗﻜﺮارﻳــﺔ ﻻ‬
‫ﺗﺘﻮﻗﻒ إﻻ إذا ﲢﻘﻖ ﺷﺮط ﻣﺎ‪.‬‬
‫‪ -5‬أﻣﺮ اﻟﱪ ﻣﺞ اﳉﺰﺋﻲ ‪subprogram statement‬‬
‫ﻳﺘﻌﺮض ﻫﺬا اﻷﻣﺮ ﻷﺳﻠﻮب ﺗﻌﺮﻳﻒ اﻟﱪاﻣﺞ اﳉﺰﺋﻴﺔ و ﻋﻼﻗﺘﻬﺎ ﻟﱪ ﻣﺞ اﻟﺮﺋﻴﺴﻰ‪.‬‬
‫ﻧﻈﺮا ﻷﳘﻴﺔ و ﺗﻨﻮع ﺗﻠﻚ اﻷواﻣﺮ‪ ،‬ﺳﻨﻔﺮض ﻓﺼﻼ ﻟﺸﺮح ﻛﻞ ﻧﻮع ﻣﻦ ﻫﺬﻩ اﻷواﻣﺮ ﰱ ﻟﻐﺔ ‪ C‬ﻟﺘﻔﺼﻴﻞ‪.‬‬

‫‪.2‬ب‪ .4.‬اﻟﻔﻘﺮات ‪Blocks‬‬


‫ﻳﺘﻌﻠــﻖ ﻫــﺬا اﳉــﺰء ﺳــﻠﻮب ﻓﺼــﻞ أﻳــﺔ أﻣــﺮ ﻋــﻦ اﻷﻣــﺮ اﻟﺘــﺎﱃ‪ ،‬و أﺳــﻠﻮب ﲡﻤﻴــﻊ ﳎﻤﻮﻋــﺔ أواﻣــﺮ ﰱ ﺑﻠــﻮك )ﺗﺒﻌــﺎ ﻟﻘﻮاﻋــﺪ اﻟﱪﳎــﺔ‬
‫اﳍﻴﻜﻠﻴﺔ( و ﻛﻴﻔﻴﺔ ﲢﺪﻳﺪ ﺑﺪاﻳﺔ و ﺎﻳﺔ اﻟﱪ ﻣﺞ و ﻛﺬا ﺗﺮﺗﻴﺐ اﻷواﻣﺮ ﰱ اﻟﱪ ﻣﺞ‪ .‬أى أﻧﻪ ﻳﺘﻌﻠﻖ ﳍﻴﻜﻞ اﳋﺎرﺟﻰ اﻟﻌﺎم ﻟﻠﱪ ﻣﺞ‪.‬‬

‫‪24‬‬
‫‪.2‬ج‪ .‬أﺳﺎﺳﻴﺎت ﻟﻐﺔ ال ‪Basics of C‬‬
‫ﺳﻨﺴﺘﻌﺮض ﰱ ﻫﺬا اﻟﻔﺼﻞ اﻟﻌﻨﺎﺻﺮ اﻷﺳﺎﺳﻴﺔ ﻟﻠﻐﺔ ‪ C‬ﻋﻠﻰ ﻧﻔﺲ اﳌﻨﻮال اﻟﻌﺎم اﻟﺬى ﰎ ﻋﺮﺿﻪ ﰱ اﻟﻔﺼﻞ اﻟﺴﺎﺑﻖ‪.‬‬

‫‪.2‬ج‪ .1.‬اﳊﺮوف ‪Character set‬‬


‫ﰱ ﻟﻐﺔ ال ‪ C‬ﳝﻜﻦ اﺳﺘﺨﺪام اﳊﺮوف اﻟﺘﺎﻟﻴﺔ ﻓﻘﻂ ﻻ ﻏﲑ‪:‬‬
‫‪A B C ... X Y Z‬‬ ‫‪a b c ... x y z‬‬ ‫‪0 1 2 ... 9‬‬ ‫}{][)(‬
‫?‪+*-/=<>~!&|^ '"\#%.,;:‬‬
‫و ذﻟﻚ ﻹﺿﺎﻓﺔ ﻟﻠﻤﺴﺎﻓﺔ ‘ ‘ و اﻟﺸﺮﻃﺔ اﻟﺴﻔﻠﻴﺔ _ ‪ underscore:‬و اﳊﺮوف اﳋﺎﺻﺔ‪:‬‬
‫‪,‬دق ﺟﺮس ‪\a‬‬ ‫‪,‬ﻋﺪ ﺣﺮﻓﺎ ﻟﻠﺨﻠﻒ ‪\b‬‬
‫‪,‬أﻗﻔﺰ ﻟﻠﺼﻔﺤﺔ اﻟﺘﺎﻟﻴﺔ ‪\f‬‬ ‫‪,‬أﻗﻔﺰ ﻟﻠﺴﻄﺮ اﻟﺘﺎﱃ ‪\n‬‬
‫‪,‬ﻋﺪ ﻟﺒﺪاﻳﺔ اﻟﺴﻄﺮ ‪\r‬‬ ‫‪,‬ﲢﺮك ﻟﻌﻼﻣﺔ اﳉﺪوﻟﺔ اﻟﺘﺎﻟﻴﺔ اﻓﻘﻴﺎ ‪\t‬‬
‫ﲢﺮك ﻟﻌﻼﻣﺔ اﳉﺪوﻟﺔ اﻟﺘﺎﻟﻴﺔ رأﺳﻴﺎ ‪\v‬‬ ‫‪,‬ﻋﻼﻣﺔ اﻟﺘﻨﺼﻴﺺ اﳌﻔﺮدة '\‬
‫‪,‬اﻟﺸﺮﻃﺔ اﳌﺎﺋﻠﺔ ﻟﻠﺨﻠﻒ \\ ‪,‬ﻋﻼﻣﺔ اﻟﺘﻨﺼﻴﺺ اﳌﺰدوﺟﺔ "\‬
‫)‪ (all bits=0‬اﳊﺮف اﳋﺎﱃ ‪\0‬‬

‫‪.2‬ج‪ .2.‬اﻟﻜﻠﻤﺎت ‪Words‬‬


‫اﻟﻜﻠﻤﺎت اﶈﺠﻮزة ﰱ ﻟﻐﺔ ‪ C‬ﺗﻨﺤﺼﺮ ﰱ اﻟﻘﺎﺋﻤﺔ اﻟﺘﺎﻟﻴﺔ اﳌﻜﻮﻧﺔ ﻣﻦ ‪ 32‬ﻛﻠﻤﺔ ﻓﻘﻂ ﻻ ﻏﲑ‪:‬‬
‫‪auto‬‬ ‫‪break‬‬ ‫‪case‬‬ ‫‪char‬‬ ‫‪const‬‬ ‫‪continue‬‬
‫‪default‬‬ ‫‪do‬‬ ‫‪double‬‬ ‫‪else‬‬ ‫‪enum‬‬ ‫‪Extern‬‬
‫‪float‬‬ ‫‪for‬‬ ‫‪goto‬‬ ‫‪if‬‬ ‫‪int‬‬ ‫‪Long‬‬
‫‪register‬‬ ‫‪return‬‬ ‫‪short‬‬ ‫‪signed‬‬ ‫‪sizeof‬‬ ‫‪Static‬‬
‫‪struct‬‬ ‫‪Switch‬‬ ‫‪typedef‬‬ ‫‪union‬‬ ‫‪unsigned‬‬ ‫‪Void‬‬
‫‪volatile‬‬ ‫‪While‬‬

‫ﺳﻴﺘﻢ ﺷﺮح ﻣﻌﲎ ﻛﻞ ﻛﻠﻤﺔ ﻣﻦ ﺧﻼل أواﻣﺮ اﻟﱪﳎﺔ اﳌﺨﺘﻠﻔﺔ ﰱ اﻟﻔﺼﻮل اﻟﺘﺎﻟﻴﺔ‪.‬‬
‫أﻣﺎ اﻷﲰﺎء أو اﳌﻌﺮﻓﺎت ‪ identifiers‬ﻓﺈن ﻗﻮاﻋﺪ اﻟﺘﺴﻤﻴﺔ ﺑﺴﻴﻄﺔ و ﺗﻨﺤﺼﺮ ﰱ اﻟﺘﺎﱃ‪:‬‬
‫‪ -‬ﳝﻜــﻦ اﺳــﺘﺨﺪام ﺣــﺮوف اﻷﲜﺪﻳــﺔ )ﻛﺒــﲑة أو ﺻــﻐﲑة( و اﻷرﻗــﺎم و ﻋﻼﻣــﺔ اﻟﺸـﺮﻃﺔ اﻟﺴــﻔﻠﻴﺔ _ ﻓﻘــﻂ‪ ،‬ﻋﻠــﻰ أن ﻻ‬
‫ﻳﻜﻮن أول ﺣﺮف ﰱ اﻻﺳﻢ رﻗﻤﺎ‪.‬‬
‫‪ -‬ﻟﻐﺔ ال ‪ C‬ﲤﻴﺰ ﺑﲔ اﳊﺮوف اﻟﻜﺒﲑة و اﻟﺼﻐﲑة ‪ ،case sensitive‬أى أﻧﻪ إذا ﻛﺎن اﻟﻘــﺎرق ﺑــﲔ إﲰــﲔ ﻳﻨﺤﺼــﺮ‬
‫ﰱ اﺳﺘﺨﺪام ﺣﺮوف ﻛﺒﲑة ﺑﺪﻻ ﻣﻦ اﻟﺼﻐﲑة‪ ،‬اﻋﺘﱪ اﻹﲰﺎن ﳐﺘﻠﻔﺎن‪.‬‬
‫‪ -‬ﳝﻜﻦ أن ﳛﻮى اﻹﺳﻢ أى ﻋﺪد ﻣﻦ اﳊﺮوف‪ ،‬و ﻟﻜــﻦ اﳌــﱰﺟﻢ ﻻ ﳝﻴــﺰ ﺳــﻮى اﻷﺣــﺮف ال‪ 31‬اﻷوﱃ‪ .‬أى أﻧــﻪ إذا‬
‫اﺗﻔﻖ إﲰﺎن ﰱ اﻷﺣﺮف ال‪ 31‬اﻷوﱃ ﰒ اﺧﺘﻠﻔﺎ ﰱ اﻷﺣﺮف اﻟﺘﺎﻟﻴﺔ‪ ،‬ﻳﻌﺘﱪﻫﻢ اﳌﱰﺟﻢ إﲰﲔ ﻣﺘﻄﺎﺑﻘﲔ‪.‬‬
‫‪ -‬ﻻ ﻳﺼﺢ اﺳﺘﺨﺪام ﻛﻠﻤﺔ ﳏﺠﻮزة‪.‬‬
‫ﻛﻤﺜﺎل‪ ،‬ﳝﻜﻦ أن ﻧﺴﺘﺨﺪم اﻷﲰﺎء اﻟﺘﺎﻟﻴﺔ و ﻛﻠﻬﺎ ﺗﻌﺘﱪ ﳐﺘﻠﻔﺔ‪:‬‬
‫‪Temperature, Volt, volt, Beam_span, I1, x3.‬‬

‫‪25‬‬
‫اﻹﲰﺎن اﻟﺘﺎﻟﻴﺎن ﺻﺤﻴﺤﺎن و ﻟﻜﻨﻬﻤﺎ ﻳﻌﺘﱪا إﲰﺎ واﺣﺪا‪:‬‬
‫‪NumberOfStudentsInComputerDeptSec1‬‬
‫‪NumberOfStudentsInComputerDeptSec2‬‬
‫أﻣﺎ اﻷﲰﺎء اﻟﺘﺎﻟﻴﺔ ﻓﻬﻰ ﳑﻨﻮﻋﺔ‪:‬‬
‫‪1T, z(y, else.‬‬
‫ﺳﻴﺘﻢ ﺷﺮح أﺳﻠﻮب اﻟﺘﻌﺒﲑ ﻋﻦ اﻟﺜﻮاﺑﺖ ﰱ اﻟﻔﺼﻞ اﻟﺘﺎﱃ‬

‫‪.2‬ج‪ .3.‬اﳉﻤﻞ ‪Statements‬‬


‫اﻟﺘﻌﻠﻴﻘــﺎت ‪ comments‬ﰱ ﻟﻐــﺔ ال ‪ C‬ﻳــﺘﻢ وﺿــﻌﻬﺎ ﺑــﲔ اﻟﻌﻼﻣﺘــﲔ‪ /* :‬ﰱ ﺑﺪاﻳــﺔ اﻟﺘﻌﻠﻴــﻖ و ‪ */‬ﰱ ﺎﻳﺘــﻪ‪ .‬ﳝﻜــﻦ ﻟﻠﺘﻌﻠﻴــﻖ‬
‫أن ﻳﻈﻬــﺮ ﰱ أﻳــﺔ ﻣﻜــﺎن ﰱ اﻟــﱪ ﻣﺞ‪ ،‬ﲟــﺎ ﰱ ذﻟــﻚ ﺑــﺪاﺧﻞ أﻣــﺮ ﻣــﻦ أواﻣــﺮ اﻟﱪﳎــﺔ‪ .‬و ﻻ ﻳﻠﺘﻔــﺖ أﻟﻴــﻪ اﳌــﱰﺟﻢ ﰱ ﲨﻴــﻊ اﻷﺣ ـﻮال‪ .‬ﻣﺜــﺎل‬
‫ذﻟﻚ‪:‬‬
‫‪/* This is a comment */‬‬
‫;‪x = y /* This is also a valid comment */ + 5‬‬
‫;‪a = b /* -3 */‬‬
‫ﻻﺣﻆ أن اﳉﺰء ‪ -3‬ﰱ اﻷﻣﺮ اﻷﺧﲑ ﻻ ﻳﻠﺘﻔﺖ إﻟﻴﻪ‪.‬‬
‫‪.2‬ج‪ .4.‬اﻟﻔﻘﺮات ‪Blocks‬‬
‫ﻳﺘﻜــﻮن أى ﺑــﺮ ﻣﺞ ‪ C‬ﻣــﻦ داﻟــﺔ أو أﻛﺜــﺮ‪ ،‬ﺗﻜﺘــﺐ ﺑﺼــﻮرة ﻣﺘﺘﺎﺑﻌــﺔ اﻟﻮاﺣــﺪة ﺗﻠــﻮ اﻷﺧــﺮى‪ .‬ﳝﻜــﻦ وﺿــﻊ اﻟــﺪوال ﻛﻠﻬــﺎ ﰱ ﻣﻠــﻒ‬
‫واﺣــﺪ أو أﻛﺜــﺮ ﻣــﻦ ﻣﻠــﻒ‪ ،‬و ﻟﻜــﻦ ﻻ ﳝﻜــﻦ ﲡﺰﺋــﺔ اﻟﺪاﻟــﺔ اﻟﻮاﺣــﺪة ﺑــﲔ ﻣﻠﻔــﲔ‪ .‬ﻻ ﻳﺼــﺢ أن ﻧﻌــﺮف داﻟــﺔ ﺑــﺪاﺧﻞ داﻟــﺔ أﺧــﺮى ) ‪no‬‬
‫‪ (nesting‬و ﻟﻜﻦ ﳝﻜﻦ ﻟﻄﺒﻊ أن ﻧﺴﺘﺪﻋﻰ داﻟــﺔ ﻣــﻦ داﺧــﻞ داﻟــﺔ أﺧــﺮى‪ .‬ﳚــﺐ أن ﳛــﻮى اﻟــﱪ ﻣﺞ داﻟــﺔ رﺋﻴﺴــﻴﺔ ﺗﺴــﻤﻰ ‪ .main‬ﻻ‬
‫ﳝﻜﻦ أن ﳛﻮى اﻟﱪ ﻣﺞ أﻛﺜﺮ ﻣﻦ داﻟــﺔ ــﺬا اﻹﺳــﻢ‪ .‬ﻳﺒــﺪأ ﺗﻨﻔﻴــﺬ اﻟــﱪ ﻣﺞ ول ﺳــﻄﺮ ﻣــﻦ ﻫــﺬﻩ اﻟﺪاﻟــﺔ‪ .‬ﺑﻌــﺪ ذﻟــﻚ ﳝﻜــﻦ اﺳــﺘﺪﻋﺎء ﻗــﻰ‬
‫اﻟﺪوال واﻣﺮ ﻣﻦ داﺧﻞ اﻟﺪاﻟــﺔ ‪ main‬ﻛﻤــﺎ ﺳــﻨﺮى ﻓﻴﻤــﺎ ﺑﻌــﺪ‪ .‬ﻻﺣــﻆ أن ﻣــﱰﺟﻢ ﻟﻐــﺔ ‪ C‬ﳝﻴــﺰ ﺑــﲔ اﳊــﺮوف اﻟﻜﺒــﲑة و اﻟﺼــﻐﲑة‪ ،‬و ﻋﻠﻴــﻪ‬
‫ﻓﺈن أﺳﻢ اﻟﺪاﻟﺔ اﻟﺮﺋﻴﺴﻴﺔ ‪ main‬ﳚﺐ أن ﻳﻜﺘﺐ ﻛﻤﺎ ﻫﻮ ﻣﻮﺿﺢ ﻋﺎﻟﻴﻪ ﳊﺮوف اﻟﺼﻐﲑة و ﻻ ﻳﺼﺢ ﻛﺘﺎﺑﺔ ‪ Main‬أو ‪.MAIN‬‬

‫ﺗﺘﻜﻮن أﻳﺔ داﻟﺔ )ﲟﺎ ﰱ ذﻟﻚ اﻟﺪاﻟﺔ ‪ (main‬ﻣﻦ‪:‬‬


‫ا‪ -‬اﻹﻋﻼم ﻋﻦ اﻟﺪاﻟﺔ ‪ function declaration‬و ﻫﻮ ﲟﺜﺎﺑــﺔ اﻟﻌﻨـﻮان ﺣﻴــﺚ أﻧــﻪ ﳛــﻮى اﺳــﻢ اﻟﺪاﻟــﺔ ‪ function name‬ﻳﺘﻠــﻮﻩ ﻗﺎﺋﻤــﺔ‬
‫اﳌﺘﻐﲑات اﻟﱴ ﺗﺪﺧﻠﻬﺎ ﻣﻦ اﻟﱪ ﻣﺞ اﻟﺬى اﺳﺘﺪﻋﺎﻫﺎ و ﺗﺴﻤﻰ اﻟﺒﺎراﻣﱰات ‪ parameters‬و ﺗﻮﺿــﻊ ﺑــﲔ أﻗـﻮاس‪ .‬ﻗــﺪ ﻳﺴــﺒﻖ اﺳــﻢ اﻟﺪاﻟــﺔ‬
‫ﺗﻮﺿﻴﺢ ﻟﻨﻮﻋﻴﺔ اﻟﻨﺎﺗﺞ ﻣﻦ ﻫﺬﻩ اﻟﺪاﻟﺔ و ﻳﺴﻤﻰ اﻟﻘﻴﻤﺔ اﳌﺮﺟﻌﺔ ‪.return value‬‬
‫ب‪ -‬ﺗﻌﺮﻳﻒ اﻟﺪاﻟﺔ ‪ function definition‬و ﻳﺸﻤﻞ أﺳﺎﺳــﺎ ﺟﺴــﻢ اﻟﺪاﻟــﺔ اﻟــﺬى ﻳﻮﺿــﻊ ﺑــﲔ أﻗـﻮاس ﻣﻨﺜﻨﻴــﺔ } {‪ .‬ﳛــﻮى ﻫــﺬا اﳉﺴــﻢ‬
‫أوﻻ ﻋﺒــﺎرات ﻟﺘﺤﺪﻳــﺪ ﻧﻮﻋﻴــﺔ اﳌﺘﻐ ـﲑات اﻟــﱴ ﺳﻨﺴــﺘﻌﻤﻠﻬﺎ ﺣــﱴ ﻳــﺘﻢ ﺣﺠــﺰ اﳊﻴــﺰ اﳌﻨﺎﺳــﺐ ﳍــﺎ ﻛﻤــﺎ ﺗﺸــﻤﻞ أواﻣــﺮ أﺧــﺮى ﺳﻨﻔﺼــﻠﻬﺎ ﻓﻴﻤــﺎ‬
‫ﺑﻌــﺪ‪ .‬ﻫﻨــﺎك أواﻣــﺮ ﺑﺴــﻴﻄﺔ و ﻫــﻰ ﲣــﺘﻢ ﺳــﺘﺨﺪام اﻟﻔﺎﺻــﻠﺔ اﳌﻨﻘﻮﻃــﺔ ";" أى ‪ semi-colon‬ﻛﻤــﺎ ﺗﻮﺟــﺪ أواﻣــﺮ ﻣﺮﻛﺒــﺔ ‪compound‬‬
‫‪ statements‬و ﻫــﻰ ﻋﺒــﺎرة ﻋــﻦ ﻋــﺪد ﻣــﻦ اﻷواﻣــﺮ اﻟﺒﺴــﻴﻄﺔ ﲨﻌــﺖ ﻣﻌــﺎ ﺑــﲔ ﻗﻮﺳــﲔ ﻣﺜﻨﻴــﲔ }{ ﻟﺘﺸــﻜﻞ ﺑﻠــﻮك ﻣــﻦ ﺑﻠﻮﻛــﺎت اﻟﱪﳎــﺔ‬
‫اﳍﻴﻜﻠﻴﺔ‪ .‬ﳝﻜــﻦ ﻛﺘﺎﺑــﺔ أﻳــﺔ ﻋــﺪد ﻣــﻦ اﻷواﻣــﺮ ﻋﻠــﻰ ﺳــﻄﺮ واﺣــﺪ وإن ﻛﻨــﺎ ﻻ ﳓﺒــﺬ ذﻟــﻚ ﻣﻄﻠﻘــﺎ ﻟﺘﺴــﻬﻴﻞ ﻗـﺮاءة اﻟــﱪ ﻣﺞ‪ .‬ﻛﻤــﺎ ﳝﻜــﻦ ﻛﺘﺎﺑــﺔ‬
‫اﻷﻣﺮ اﻟﻮاﺣﺪ ﻋﻠﻰ أﻛﺜﺮ ﻣﻦ ﺳﻄﺮ ﺑﺪون أﻳﺔ ﻗﻴﻮد ﺳﻮى أن ﻻ ﻧﻨﺘﻘﻞ ﻟﻠﺴﻄﺮ اﳉﺪﻳﺪ ﰱ ﻣﻨﺘﺼــﻒ ﻛﻠﻤــﺔ‪ .‬ﻓــﺎﻟﻌﱪة ﺑﻨﻬﺎﻳــﺔ أﻣــﺮ وﺑﺪاﻳــﺔ أﻣــﺮ‬
‫ﺟﺪﻳﺪ ﻫﻮ اﻟﻔﺎﺻﻠﺔ اﳌﻨﻘﻮﻃﺔ ";" و ﻟﻴﺲ ﺑﺪاﻳﺔ ﺳﻄﺮ ﺟﺪﻳﺪ‪.‬‬

‫‪26‬‬
‫ﳝﻜﻦ ﻟﻠﺪوال أن ﺗﻈﻬﺮ ى ﺗﺮﺗﻴﺐ و ﻟﻜﻦ ﻻ ﻳﺼﺢ اﺳﺘﺨﺪام )أو اﺳﺘﺪﻋﺎء( داﻟﺔ دون أن ﻳﻜﻮن ﻗﺪ ﺳــﺒﻖ اﻹﻋــﻼن ﻋﻨﻬــﺎ ﻛﻤــﺎ‬
‫ﺳﻨﺮى ﻟﺘﻔﺼﻴﻞ ﰱ اﻟﻔﺼﻞ اﳋﺎص ﻹﻋﻼن ﻋﻦ اﻟﺪوال و ﺗﻌﺮﻳﻔﻬﺎ‪.‬‬

‫ﻛﻤﺜﺎل ﺑﺴﻴﻂ ﳌﺎ ﺳﺒﻖ ﺳﻨﻮرد أول ﺑﺮ ﻣﺞ ﻣﺒﺴﻂ ﻳﻘﻮم ﺑﺴﺆال ﻣﺴﺘﺨﺪم اﻟﱪ ﻣﺞ ﻋﻦ أﲰﻪ ﰒ ﻳﻮﺟﻪ ﻟﻪ اﻟﺘﺤﻴﺔ ﻻﺳﻢ‪:‬‬
‫>‪#include <stdio.h‬‬
‫>‪#include <conio.h‬‬
‫‪/* My first program */‬‬
‫)‪void main(void‬‬
‫{‬
‫;]‪char name[20‬‬
‫;)" ‪printf("Enter your name:‬‬
‫;)‪gets(name‬‬
‫;)‪printf("Hello Mr. %s\n" , name‬‬
‫;)(‪getch‬‬
‫}‬
‫اﻟﺪاﻟﺔ اﻟﺮﺋﻴﺴﻴﺔ ‪ main‬ﻻ ﲢﺘﺎج ﻟﺒﻴﺎ ت ﰱ اﳌﺪﺧﻞ و ﻻ ﺗﻌﻄﻰ ﻧﺘﺎﺋﺞ ﰱ اﳌﺨﺮج و ﻟﺬﻟﻚ اﺳﺘﺨﺪﻣﺖ اﻟﻜﻠﻤﺔ ‪ void‬و ﻫــﻰ ﺗﻌــﲎ "ﻻ‬
‫ﺷﻰء"‪ .‬أﻣﺎ ﺟﺴﻢ اﻟﺪاﻟﺔ ﻓﻴﺒﺪأ ﺑﺘﻌﺮﻳــﻒ ﺧﺎﻧــﺔ اﻟــﺬاﻛﺮة ‪ name‬و اﻟــﱴ ﺳــﺘﺤﻮى اﻻﺳــﻢ اﻟــﺬى ﺳــﻴﺪﺧﻠﻪ ﻣﺴــﺘﺨﺪم اﻟــﱪ ﻣﺞ‪ .‬ﻻﺣــﻆ أﻧﻨــﺎ‬
‫ﻃﻠﺒﻨﺎ أن ﳓﺠﺰ ‪ 20‬ﺧﺎﻧﺔ ﻣﻦ ﻧﻮع ‪ char‬أى ‪ 20‬ﻳﺖ‪ .‬ﻳﺴﻤﺢ ذﻟﻚ ﺑﻜﺘﺎﺑﺔ أى اﺳﻢ ﻻ ﺗﺘﻌﺪى ﺣﺮوﻓﻪ )ﲟﺎ ﰱ ذﻟﻚ اﳌﺴــﺎﻓﺎت ﺑــﲔ‬
‫اﻟﻜﻠﻤﺎت( ‪ 19‬ﺣﺮﻓﺎ‪ ،‬ﻟﻜﻰ ﳝﻜﻦ ﻛﺘﺎﺑﺔ ﺣﺮف ﺎﻳﺔ اﳉﻤﻠــﺔ '‪ .'\0‬اﻟﺴــﻄﺮ اﻟﺘــﺎﱃ ﻳﻜﺘــﺐ ﻋﻠــﻰ اﻟﺸﺎﺷــﺔ اﳉﻤﻠــﺔ اﳌﻮﺿــﻮﻋﺔ ﺑــﲔ ﻋﻼﻣــﺎت‬
‫اﻟﺘﻨﺼﻴﺺ اﳌﺰدوﺟﺔ ﻛﻤﺎ ﻫﻰ‪ .‬اﻟﺴﻄﺮ اﻟﺜﺎﻟﺚ ﰱ ﺟﺴﻢ اﻟﺪاﻟﺔ ﻳﻘﺮأ اﻻﺳﻢ اﻟﺬى ﺳﻴﺪﺧﻠﻪ ﻣﺴﺘﺨﺪم اﻟﱪ ﻣﺞ‪ .‬ﰱ اﻟﺴﻄﺮ اﻟﺘﺎﱃ ﻳــﺘﻢ ﻛﺘﺎﺑــﺔ‬
‫اﻟﻜﻠﻤﺘﲔ "‪ "Hello Mr.‬ﻳﻌﻘﺒﻬﻤﺎ اﻻﺳﻢ اﻟﺬى أدﺧﻠﻨﺎﻩ ﰒ ﻧــﺬﻫﺐ ﻟﺴــﻄﺮ ﺟﺪﻳــﺪ‪ .‬ﻋﻼﻣــﺔ اﻟﻨﺴــﺒﺔ اﳌﺌﻮﻳــﺔ ‪ %‬ﺗﻌــﲎ أﻧــﻪ ﰱ ﻫــﺬا اﳌﻜــﺎن‬
‫ﳚﺐ ﻛﺘﺎﺑﺔ ﳏﺘﻮى ﻣﺘﻐﲑ ﺳــﲑد اﲰــﻪ ﺑﻌــﺪ ﺎﻳــﺔ ﻋﻼﻣــﺔ اﻟﺘﻨﺼــﻴﺺ اﳌﺰدوﺟــﺔ‪ .‬ﻳﻠــﻰ ﻋﻼﻣــﺔ اﻟﻨﺴــﺒﺔ اﳌﺌﻮﻳــﺔ ﺣــﺮف أو أﻛﺜــﺮ ﻟﺘﻮﺿــﻴﺢ أﺳــﻠﻮب‬
‫ﻛﺘﺎﺑﺔ ﳏﺘﻮى اﳌﺘﻐﲑ‪ .‬اﳊﺮف ﻫﻨﺎ ﻫﻮ ﺣﺮف ‪ s‬و ﻳﺮﻣﺰ ﻟﻠﻜﻠﻤﺔ ‪ string‬ﳑﺎ ﻳﻌﲎ ﻛﺘﺎﺑــﺔ ﻣﺘﻐــﲑ ﳛــﻮى ﲨﻠــﺔ‪ .‬أﻣــﺎ اﻟﻌﻼﻣــﺔ ‪ \n‬ﻓﺘﻌــﲎ اذﻫــﺐ‬
‫ﻟﺴﻄﺮ ﺟﺪﻳﺪ‪ .‬اﻟﺴﻄﺮ اﻷﺧﲑ ﰱ ﺟﺴﻢ اﻟﺪاﻟﺔ ﻳﺆدى ﻷن ﻳﺘﻮﻗﻒ اﻟﱪ ﻣﺞ ﳊﻈﻴﺎ ﻟﻜــﻰ ﻧــﺮى ﻣــﺎذا ﺣــﺪث‪ .‬ﻻ ﻳﻌــﻮد اﻟــﱪ ﻣﺞ ﻟﻠﻌﻤــﻞ ﺑﻌــﺪ‬
‫ذﻟﻚ إﻻ إذا ﺿﻐﻄﻨﺎ ﻋﻠﻰ أﻳﺔ ﻣﻔﺘﺎح ﻣﻦ ﻟﻮﺣﺔ اﳌﻔﺎﺗﻴﺢ‪ .‬وﻋﻠﻰ ﻫﺬا ﻓﻌﻨﺪ ﺗﺸﻐﻴﻞ ﻫﺬا اﻟﱪ ﻣﺞ ﺳﻨﺮى ﻋﻠﻰ اﻟﺸﺎﺷﺔ ﻣﺎ ﻳﻠﻰ‪:‬‬
‫‪Enter your name: Aly Hassan‬‬
‫‪Hello Mr. Aly Hassan‬‬

‫ﲞﻼف اﻟﺪوال ﻓﻬﻨﺎك أواﻣــﺮ ﻋﺎﻣــﺔ ﺗﻈﻬــﺮ ﻋــﺎدة ﰱ ﺑﺪاﻳــﺔ اﻟــﱪ ﻣﺞ‪ .‬ﺑﻌــﺾ ﻫــﺬﻩ اﻷواﻣــﺮ ﻟﻴﺴــﺖ أواﻣــﺮ ﻣﻄﻠــﻮب ﺗﺮﲨﺘﻬــﺎ و ﻟﻜﻨﻬــﺎ‬
‫ﰱ اﳊﻘﻴﻘــﺔ ﺗﻌﻠﻴﻤــﺎت ﻣﻮﺟﻬــﺔ ﻟﻠﻤــﱰﺟﻢ ‪ compiler directives‬ﲞﺼــﻮص أﺳــﻠﻮب اﻟﱰﲨــﺔ اﳌﻄﻠــﻮب‪ .‬ﳚــﺐ أن ﺗﺒــﺪأ أﻳــﺔ ﺗﻌﻠﻴﻤــﺔ ﻣــﻦ‬
‫ﻫﺬﻩ اﻟﺘﻌﻠﻴﻤﺎت ﺑﻌﻼﻣﺔ ‪ #‬ﰱ ﺳﻄﺮ ﺟﺪﻳﺪ‪ ،‬و ﻻ ﻳﺼﺢ وﺿــﻊ أﻛﺜــﺮ ﻣــﻦ ﺗﻌﻠﻴﻤــﺔ واﺣــﺪة ﰱ اﻟﺴــﻄﺮ اﻟﻮاﺣــﺪ‪ ،‬ﻛﻤــﺎ ﻻ ﳚــﺐ وﺿــﻊ ﻓﺎﺻــﻠﺔ‬
‫ﻣﻨﻘﻮﻃﺔ ﰱ ﺎﻳﺔ اﻟﺘﻌﻠﻴﻤﺔ‪ .‬ﻣﻦ ﻫﺬﻩ اﻟﺘﻌﻠﻴﻤﺎت ﺗﻌﻠﻴﻤﺔ اﻹﺿﺎﻓﺔ‪:‬‬
‫>‪#include <a_standard_header_file‬‬
‫و ﻫــﻰ ﺗﻌــﲎ أﻧــﻪ ﻣــﻦ اﳌﻄﻠــﻮب إﺿــﺎﻓﺔ اﻟﺴــﻄﻮر اﳌﻮﺟــﻮدة ﰱ اﳌﻠــﻒ ‪ a_standard_header_file‬ﻛﻤــﺎ ﻟــﻮ ﻛﺎﻧــﺖ ﻗــﺪ ﻛﺘﺒــﺖ ﰱ ﻫــﺬا‬
‫اﳌﻮﺿﻊ ﻣﻦ اﻟﱪ ﻣﺞ‪ .‬ﺗﺴﺘﺨﺪم ﻫــﺬﻩ اﻟﺘﻌﻠﻴﻤــﺔ ﻹﳊــﺎق أﺟـﺰاء ﻛﺎﻣﻠــﺔ ﺗﺘﻜــﺮر ﰱ أﻛﺜــﺮ ﻣــﻦ ﻣﻠــﻒ ﺑــﺪون أن ﻧﻜﺘﺒﻬــﺎ ﰱ ﻛــﻞ ﻣــﺮة‪ .‬و اﳍــﺪف‬
‫ﻻ ﻳﻨﺤﺼﺮ ﰱ ﺗﻮﻓﲑ وﻗﺖ اﻟﻜﺘﺎﺑﺔ و ﻟﻜﻦ ﰱ ﺿﻤﺎن أن أﻳﺔ ﺗﻌــﺪﻳﻞ أو ﺗﻄــﻮﻳﺮ ﰱ ﻫــﺬا اﳉــﺰء ﺳــﻮف ﻳﺆﺧــﺬ ﰱ اﻻﻋﺘﺒــﺎر ﻣﺒﺎﺷــﺮة ﰱ ﲨﻴــﻊ‬
‫اﳌﻠﻔﺎت اﻟﱴ ﺗﺴﺘﺨﺪﻣﻪ‪ .‬إذا ﻛﺎن اﳌﻠﻒ اﳌﻀﺎف ﻫﻮ واﺣﺪ ﻣــﻦ ﻣﻠﻔــﺎت اﳌﻜﺘﺒــﺔ اﻷﺳﺎﺳــﻴﺔ اﻟــﱴ ﺗــﻰ ﻣــﻊ ﻣﻜﺘﺒــﺔ ﺑـﺮاﻣﺞ ‪ C‬اﳌﻌﺘــﺎدة ﲰــﻰ‬
‫ﻣﻠــﻒ رأس ﻗﻴﺎﺳــﻰ ‪ .standard_header_file‬ﺗﻮﺿــﻊ ﻫــﺬﻩ اﳌﻠﻔــﺎت ﲢــﺖ اﻟﻔﻬــﺮس ‪ . directory: include‬ﳛــﺐ وﺿــﻊ اﺳــﻢ‬
‫‪27‬‬
‫ﻣﻠﻒ اﻟﺮأس اﻟﻘﻴﺎﺳﻰ ﺑﲔ اﻷﻗﻮاس اﻟﺰاوﻳﺔ >< ﻛﻤﺎ ﻫﻮ ﻣﻮﺿﺢ ﻋﺎﻟﻴﻪ‪ .‬أﻣﺎ إذا ﻛﺎن اﳌﻠﻒ اﳌﻀﺎف ﻗﺪ ﻛﺘﺒﻨﺎﻩ ﻧﻔﺴﻨﺎ ﻓــﻴﻤﻜﻦ أن ﻧﻀــﻌﻪ‬
‫ﰱ أى ﻓﻬﺮس و ﻟﻜﻦ ﰱ ﻫﺬﻩ اﳊﺎﻟﺔ ﳚﺐ وﺿﻊ اﺳﻢ اﳌﻠﻒ ﺑﲔ ﻋﻼﻣﺔ اﻟﺘﻨﺼﻴﺺ اﳌﺰدوﺟﺔ‪:‬‬
‫"‪#include "my_header_file‬‬

‫اﻟﺴـ ــﻄﺮ اﻷول ﰱ اﻟـ ــﱪ ﻣﺞ ﳛـ ــﻮى ﺗﻌﻠﻴﻤـ ــﺔ ﺗﻀـ ــﻴﻒ اﳌﻠـ ــﻒ ‪ stdio.h‬و ﻫ ــﻮ أﺣـ ــﺪ اﳌﻠﻔـ ــﺎت اﻷﺳﺎﺳـ ــﻴﺔ اﻟـ ــﱴ ﺗﻮﺟـ ــﺪ ﰱ ﻓﻬـ ــﺮس‬
‫‪ include‬اﳌﺼــﺎﺣﺐ ﻟﻠﻤــﱰﺟﻢ ‪ .C‬ﳛــﻮى ﻫــﺬا اﳌﻠــﻒ إﻋــﻼن ﻟﻠﺘﻌﺮﻳــﻒ ﺑــﺪوال اﻹدﺧــﺎل واﻹﺧـﺮاج اﻟﺸــﺎﺋﻌﺔ و ﻫــﻰ ﻫﻨــﺎ ) (‪ printf‬و‬
‫) (‪ .gets‬ﺑﺪون ذﻛﺮ ﻫﺬا اﻟﺴﻄﺮ ﺳﻴﺘﻮﻗﻒ اﳌﱰﺟﻢ ﻋﻦ اﻟﱰﲨﺔ ﻋﻨﺪﻣﺎ ﻳﺮى ﻫﺎﺗﲔ اﻟﺪاﻟﺘﲔ ﻣﺼــﺪرا رﺳــﺎﻟﺔ ﺧﻄــﺄ ﺗﻌــﱪ ﻋــﻦ أﻧــﻪ ﻻ ﻳﻌــﺮف‬
‫أى ﺷﺊ ﻋﻨﻬﻤﺎ‪ .‬أﻣــﺎ اﻟﺴــﻄﺮ اﻟﺜــﺎﱏ ﻓﻴــﻨﻢ ﻋــﻦ إﺿــﺎﻓﺔ ﳌﻠــﻒ ‪ conio.h‬و ﳛــﻮى إﻋــﻼن ﻟﻠﺘﻌﺮﻳــﻒ ﺑﺪاﻟــﺔ ) (‪ .getch‬ﺳــﺘﺨﺪام اﳌﺴــﺎﻋﺪ‬
‫‪ help‬ﳝﻜﻦ اﳊﺼﻮل ﻋﻠﻰ ﻗﺎﺋﻤﺔ اﻟﺪوال اﳌﻌﺮﻓﺔ ﰱ ﻫﺬﻩ اﳌﻠﻔﺎت‪.‬‬

‫ﻫﻨﺎك ﺗﻌﻠﻴﻤﺔ أﺧﺮى ﱂ ﺗﺴﺘﺨﺪم ﰱ اﻟﱪ ﻣﺞ ﻋﺎﻟﻴﻪ و ﻫﻰ ﺗﻌﻠﻴﻤﺔ اﻹﺣﻼل و ﻫﻰ ﻋﻠﻰ اﻟﺼﻮرة اﻟﻌﺎﻣﺔ‪:‬‬
‫‪#define symbolic_constant value‬‬
‫و ﻫــﻰ ﺗﻌــﲎ أن ﻳﻘــﻮم اﳌــﱰﺟﻢ ﺣــﻼل اﳊــﺮوف ‪ symbolic_constant‬إذا ﻇﻬــﺮت ﻛﻜﻠﻤــﺔ ﻣﺴــﺘﻘﻠﺔ ﳊــﺮوف ‪ value‬و ذﻟــﻚ ﰱ‬
‫ﻛﻞ اﻟﱪ ﻣﺞ‪ .‬ﻣﻦ اﻷﻣﺜﻠﺔ اﻟﺸﺎﺋﻌﺔ ﻻﺳﺘﺨﺪام ﺗﻌﻠﻴﻤﺔ اﻹﺣﻼل‪:‬‬
‫‪#define PI 3.14159‬‬
‫ﻛﻤﺎ ذﻛﺮ آﻧﻔﺎ ﻓــﺄن ﻣــﱰﺟﻢ ﻟﻐــﺔ ‪ C‬ﳝﻴــﺰ ﺑــﲔ اﳊــﺮوف اﻟﻜﺒــﲑة واﻟﺼــﻐﲑة‪ .‬و ﻋﻠــﻰ ﻫــﺬا ﻓﻠــﻦ ﻳــﺘﻢ إﺣـﻼل اﳊــﺮوف ‪ pi‬ﻣــﺜﻼ ﺑﻮاﺳــﻄﺔ ﻫــﺬﻩ‬
‫اﻟﺘﻌﻠﻴﻤــﺔ‪ .‬ﻛﻤــﺎ ﻟــﻦ ﻳــﺘﻢ إﺣــﻼل أول ﺣــﺮﻓﲔ ﻣــﻦ اﻟﻜﻠﻤــﺔ ‪ PI2‬ﺣﻴــﺚ أن اﻹﺣــﻼل ﻻ ﻳﻜــﻮن إﻻ ﻟﻜﻠﻤــﺔ ﻛﺎﻣﻠــﺔ ﻣﺴــﺘﻘﻠﺔ‪ .‬ﻛﻤــﺎ ﻟــﻦ ﻳــﺘﻢ‬
‫اﻹﺣﻼل ﻟﻠﻜﻠﻤﺎت اﻟﻮاﻗﻌﺔ داﺧﻞ ﻋﻼﻣﺎت اﻟﺘﻨﺼﻴﺺ اﳌﺰدوﺟﺔ ﺣﻴﺚ أ ﺎ ﺗﻌﺘــﱪ ﲨﻠــﺔ ﻳﻜﺘﺒﻬــﺎ اﳊﺎﺳــﺐ ﻛﻤــﺎ ﻫــﻰ و ﻻ ﲢــﻮى ﺛﻮاﺑــﺖ أو‬
‫ﻣﺘﻐﲑات‪.‬‬

‫اﳌﺜــﺎل اﻟﺜــﺎﱏ ﻋﺒــﺎرة ﻋــﻦ ﺑــﺮ ﻣﺞ ‪ C‬ﻳﻘــﻮم ﲝﺴــﺎب اﳉــﺬر اﻟﱰﺑﻴﻌــﻰ ﻟــﺮﻗﻢ ﻳﻌﻄﻴــﻪ اﳌﺴــﺘﺨﺪم‪ .‬ﻫﻨــﺎك داﻟــﺔ ﻣﻌﺮﻓــﺔ ﺳــﻠﻔﺎ ﰱ ﻣﻜﺘﺒــﺔ‬
‫اﻟ ـﱪاﻣﺞ اﻟﺮ ﺿــﻴﺔ اﳌﻠﺤﻘــﺔ ﺑ ـﱪاﻣﺞ ‪ C‬و ﺗﻮﺟ ــﺪ ﰱ ﻣﻠــﻒ >‪ .<math.h‬ﻫــﺬﻩ اﻟﺪاﻟــﺔ اﲰﻬ ــﺎ ) (‪ sqrt‬وﻫــﻰ ﺗﺴــﺘﺨﺪم ﻃﺮﻳﻘــﺔ ﺗﻘﺮﻳﺒﻴ ــﺔ‬
‫ﻟﻠﺤﺴــﺎب‪ .‬ﻟــﻦ ﻧﺴــﺘﺨﺪم ﻫــﺬﻩ اﻟﺪاﻟــﺔ و ﻟﻜﻨﻨــﺎ ﺳﻨﺴــﺘﺨﺪم أﳉــﻮرﻳﺘﻢ ﻟﻠﺘﻘﺮﻳــﺐ اﳌﺘﺘــﺎﱃ وﺿــﻌﻪ اﻟﻌــﺮب ﻣﻨــﺬ ﺳــﻨﲔ ﻃﻮﻳﻠــﺔ و ذﻟــﻚ ﻟﻠﺘــﺪرﻳﺐ‬
‫ﻋﻠﻰ ﺑﻌﺾ اﻷواﻣﺮ اﳉﺪﻳﺪة‪ .‬اﻟﻄﺮﻳﻘﺔ اﻟﱴ وﺿﻌﻬﺎ اﻟﻌﺮب ﳊﺴﺎب ﺟﺬر اﻟﺮﻗﻢ ‪ a‬ﺗﻌﺘﻤﺪ ﻋﻠﻰ اﻷﳉﻮرﻳﺘﻢ اﻟﺘﺎﱃ‪:‬‬
‫ا‪ -‬ﺿﻊ ﻛﺘﻘﺮﻳﺐ أوﱃ ‪ xold‬ﻳﺴﺎوى اﻟﻮﺣﺪة‬
‫ب‪ -‬اﺣﺴﺐ ﺗﻘﺮﻳﺒﺎ أﻓﻀﻞ ‪ xnew‬ﺑﻨﺎء ﻋﻠﻰ اﻟﻌﻼﻗﺔ ‪xnew = (xold + a/xold) / 2‬‬
‫ج‪ -‬إذا ﻛﺎﻧﺖ اﻟﻘﻴﻤﺔ اﳌﻄﻠﻘﺔ ﻟﻠﻔﺮق ﺑﲔ ‪ xnew‬و ‪ xold‬أﻗﻞ ﻣﻦ اﻟﺪﻗﺔ اﳌﻄﻠﻮﺑﺔ ‪ eps‬ﺗﻮﻗﻒ‪.‬‬
‫د‪ -‬اﻋﺘﱪ اﻟﺘﻘﺮﻳﺐ اﳊﺎﱃ ﺗﻘﺮﻳﺒﺎ ﻗﺪﳝﺎ ‪ xold‬و ﻛﺮر اﳋﻄﻮات ﺑﺪءا ﻣﻦ ب‪.‬‬
‫اﻟﱪ ﻣﺞ ﺧﺬ اﻟﺼﻮرة‪:‬‬
‫>‪#include <stdio.h‬‬
‫>‪#include <conio.h‬‬
‫>‪#include <math.h‬‬
‫>‪#include <process.h‬‬
‫‪#define eps 1.0e-4‬‬
‫‪/* Program to calculate square roots by trial and error */‬‬
‫)‪void main(void‬‬
‫{‬
‫‪double a,‬‬ ‫‪/* The input number */‬‬

‫‪28‬‬
‫‪xnew,‬‬ ‫‪/* new iteration */‬‬
‫‪xold,‬‬ ‫‪/* old iteration */‬‬
‫;‪err‬‬ ‫‪/* the error */‬‬
‫;)"‪printf("Program to approximately calculate square roots\n‬‬
‫;)‪printf("Enter the number: "); scanf("%lg",&a‬‬
‫‪/* Test the input number */‬‬
‫)‪if (a <= 0.0‬‬
‫{‬
‫;)"‪printf("Invalid input data\n‬‬
‫;)(‪getch‬‬
‫;)‪exit(7‬‬
‫}‬
‫‪/* Initializations for the iteration loop */‬‬
‫;‪xnew=1.0‬‬
‫‪/* The main loop */‬‬
‫‪do‬‬
‫{‬
‫;‪xold = xnew‬‬
‫;)‪xnew = 0.5*(xold+a/xold‬‬
‫;)‪err = fabs(xnew-xold‬‬
‫)‪} while (err > eps‬‬
‫;)‪printf("The root is: %lg",xnew‬‬
‫;)(‪getch‬‬
‫}‬
‫ﰱ اﻟﺴﻄﺮ اﻷول ﻣﻦ ﻫﺬا اﻟﱪ ﻣﺞ أﺿﻴﻒ اﳌﻠﻒ ‪ math.h‬ﻷﻧﻪ ﻳﻌــﺮف اﻟﺪاﻟــﺔ ) (‪ fabs‬و اﳌﺴــﺘﺨﺪﻣﺔ ﳊﺴــﺎب اﻟﻘﻴﻤــﺔ اﳌﻄﻠﻘــﺔ‬
‫ﻟﻠﺨﻄــﺄ‪ .‬ﻛﻤــﺎ أﺿــﻴﻒ اﳌﻠــﻒ ‪ process.h‬ﰱ اﻟﺴــﻄﺮ اﻟﺜــﺎﱏ ﻷﻧــﻪ ﻳﻌــﺮف اﻟﺪاﻟــﺔ ) (‪ exit‬و اﻟــﱴ ﺗﺴــﺘﺨﺪم ﻟﻠﺨــﺮوج اﳌﺒﻜــﺮ ﻣــﻦ اﻟــﱪ ﻣﺞ‬
‫إذا ﻛﺎﻧﺖ اﻟﺒﻴﺎ ت اﳌﻌﻄﺎة ﻏﲑ ﻣﻨﻄﻘﻴﺔ‪.‬‬

‫اﻟﺴــﻄﺮ اﻟﺜﺎﻟــﺚ ﻳﻌــﺮف اﻟﺜﺎﺑــﺖ اﻟﺮﻣــﺰى ‪ symbolic constant‬اﳌﻌــﱪ ﻋــﻦ اﻟﺪﻗــﺔ اﳌﻄﻠﻮﺑــﺔ و ﻫــﻮ ‪ .eps‬إذا ﻇﻬــﺮت ﻛﻠﻤــﺔ ‪eps‬‬
‫ﰱ أى ﻣﻜﺎن ﰱ اﻟﱪ ﻣﺞ ﻓﺴﻴﻘﻮم اﳌﱰﺟﻢ ﺣﻼﳍﺎ ﻟﻘﻴﻤﺔ ‪.1.0e-4‬‬

‫ﻳﻠﻰ ذﻟﻚ ﺳﻄﺮ ﳛﻮى ﺗﻌﻠﻴﻖ ﻳﻌﱪ ﻋﻤﺎ ﻳﻔﻌﻠﻪ اﻟﱪ ﻣﺞ‪ .‬إن إﺿﺎﻓﺔ ﺗﻌﻠﻴﻘﺎت ﰱ ﻣﻮاﺿﻊ ﻋﺪة ﻣﻦ اﻟﱪ ﻣﺞ ﻫﻰ ﻋﻤﻠﻴــﺔ ﳏﺒــﺬة ﳊــﺪ‬
‫ﺑﻌﻴﺪ ﻟﺴﻬﻮﻟﺔ ﻗﺮاءة و ﺗﻌﺪﻳﻞ اﻟﱪ ﻣﺞ ﰱ أى وﻗﺖ‪.‬‬

‫اﻟﺴﻄﻮر اﻷرﺑﻌﺔ اﻷوﱃ ﻣﻦ ﺟﺴــﻢ اﻟﺪاﻟــﺔ اﻟﺮﺋﻴﺴــﻴﺔ ﲢــﻮى أﻣـﺮا واﺣــﺪا ﻫــﻮ أﻣــﺮ اﻟﺘﻌﺮﻳــﻒ ﳌﺘﻐـﲑات اﻟــﱴ ﺳﻨﺴــﺘﻌﻤﻠﻬﺎ ﰱ اﻟــﱪ ﻣﺞ‪.‬‬
‫ﻛﺘﺒﻨــﺎ اﻷﻣــﺮ ﻋﻠ ــﻰ أرﺑﻌ ــﺔ ﺳــﻄﻮر ﻣ ــﻊ إﺿ ــﺎﻓﺔ ﺗﻌﻠﻴﻘ ــﺎت ﻟﻴﻜــﻮن اﻟ ــﱪ ﻣﺞ أﻛﺜ ــﺮ وﺿ ــﻮﺣﺎ‪ .‬إن وﺿــﻊ ﺗﻌﻠﻴ ــﻖ ﻳﻮﺿــﺢ دور ﲨﻴ ــﻊ اﳌﺘﻐ ـﲑات‬
‫اﳌﺴﺘﺨﺪﻣﺔ ﻳﺴﻤﻰ ﻗﺎﻣﻮس اﳌﺘﻐﲑات ‪ variable dictionnary‬وﻫﻰ ﻋﻤﻠﻴﺔ ﻣﺮﻏﻮﺑــﺔ ﻷﻗﺼــﻰ درﺟــﺔ ﻟﺘﺴــﻬﻴﻞ ﻗـﺮاءة و ﻣﺘﺎﺑﻌــﺔ اﻟـﱪاﻣﺞ‪.‬‬
‫ﻟﻨﻔﺲ اﻟﺴﺒﺐ ﳚﺐ إﻋﻄﺎء أﲰﺎء ﻣﻌﱪة ﻟﻠﻤﺘﻐﲑات‪ ،‬و ﲡﻨﺐ اﻷﲰﺎء ﻣﻦ ﺣﺮف واﺣﺪ اﻟﱴ ﺗﻀﻴﻒ ﻏﻤﻮﺿﺎ ﻏﲑ ﻣﺮﻏﻮب ﻓﻴﻪ‪.‬‬

‫ﺗﻠﻰ ذﻟــﻚ ﻋﻤﻠﻴــﺔ إدﺧــﺎل اﻟــﺮﻗﻢ اﳌﻄﻠــﻮب ﺣﺴــﺎب ﺟــﺬرﻩ‪ .‬ﻻﺣــﻆ أﺳــﻠﻮب اﺳــﺘﺨﺪام اﻟﺪاﻟــﺔ اﳉﺪﻳــﺪة )(‪ scanf‬وذﻟــﻚ ﻹدﺧــﺎل‬
‫اﻟﺒﻴﺎ ت اﻟﺮﻗﻤﻴــﺔ أو اﳊﺮﻓﻴــﺔ اﳌﻔــﺮدة‪ .‬ﺗﻮﺿــﻊ داﺋﻤــﺎ اﻟﻌﻼﻣــﺔ & ﻗﺒــﻞ اﺳــﻢ اﳌﺘﻐــﲑ اﻟــﺬى ﺳــﻴﺤﻮى اﻟﻘﻴﻤــﺔ اﻟــﱴ ﻧﻘﺮأﻫــﺎ و ذﻟــﻚ ﻷﺳــﺒﺎب ﻟــﻦ‬
‫ﻧــﺘﻤﻜﻦ ﻣــﻦ ﺷــﺮﺣﻬﺎ ﻗﺒــﻞ اﻟﺒــﺎب اﳋــﺎص ﳌﺆﺷـﺮات ‪ .pointers‬اﻟﺒﻠــﻮك اﻟﺘــﺎﱃ ﻫــﻮ ﺑﻠــﻮك ﺧﺎﺿــﻊ ﻟﺸــﺮط‪ ،‬ﺣﻴــﺚ أﻧــﻪ ﳝﺤــﺺ اﻟﺒﻴــﺎ ت‬

‫‪29‬‬
‫اﳌﺪﺧﻠﺔ ﻗﺒﻞ ﺑﺪء اﳊﺴﺎب ﻟﻴﺴﺘﺒﻌﺪ اﳊﺎﻻت ﻏﲑ اﳌﻨﻄﻘﻴﺔ‪ .‬ﻓﺈذا ﻛﺎن اﻟﺮﻗﻢ اﳌﻄﻠــﻮب ﺣﺴــﺎب ﺟــﺬرﻩ ﺳــﺎﻟﺒﺎ ﻓﻠــﻴﺲ ﻫﻨــﺎك ﺟــﺬر و ﻟﺘــﺎﱃ‬
‫ﻓــﺈن ﻋﻤﻠﻴــﺔ اﻟﺘﻘﺮﻳــﺐ اﳌﺘﺘــﺎﱃ ﻟــﻦ ﺗﻨﺘﻬــﻰ أﺑــﺪا‪ .‬أﻣــﺎ إذا ﻛــﺎن ﺻــﻔﺮا ﻓــﺈن اﻷﳉــﻮرﻳﺘﻢ ﻗــﺪ ﳜﻠــﻖ ﻣﺸــﺎﻛﻞ ﻧﺘﻴﺠــﺔ ﻟﻌﻤﻠﻴــﺔ اﻟﻘﺴــﻤﺔ ‪ a/x‬و اﻟــﱴ‬
‫ﺳﺘﺼــﺒﺢ ﻋﻤﻠﻴــﺔ ﻏــﲑ ﻣﻌﺮﻓــﺔ ‪ .0/0‬ﲤﺤــﻴﺺ اﻟﺒﻴــﺎ ت اﳌﺪﺧﻠــﺔ ﻗﺒــﻞ ﻣﻌﺎﳉﺘﻬــﺎ و اﺳــﺘﺒﻌﺎد اﳊــﺎﻻت ﻏــﲑ اﳌﻨﻄﻘﻴــﺔ ﻫــﻰ ﻋﻤﻠﻴــﺔ ﳚﺮﻳﻬــﺎ أى‬
‫ﺑــﺮ ﻣﺞ ﻣﻜﺘــﻮب ﺑﻮاﺳــﻄﺔ ﳏــﱰف ﻟﺘﺠﻨــﺐ ﻣﺸــﺎﻛﻞ ﻗــﺪ ﺗﻈﻬــﺮ أﺛﻨــﺎء اﻟﺘﻨﻔﻴــﺬ‪ .‬ﻻﺣــﻆ اﻟﱰﺣﻴــﻞ ﻟﻠﺴــﻄﻮر داﺧــﻞ اﻟﺒﻠــﻮك ﺣﻴــﺚ ﺗﺒــﺪأ ﺑﻌــﺪ‬
‫ﻣﺴﺎﻓﺘﲔ ﻣــﻦ اﻷﻗـﻮاس اﳌﻨﺜﻨﻴــﺔ اﻟــﱴ ﺗﻌﻠــﻦ ﺑﺪاﻳــﺔ و ﺎﻳــﺔ اﻟﺒﻠــﻮك‪ .‬ﻣــﻊ أن ﻫــﺬا اﻟﱰﺣﻴــﻞ ﻟــﻴﺲ ﻟــﻪ أﻳــﺔ أﺛــﺮ ﻋﻠــﻰ اﳌــﱰﺟﻢ إﻻ أﻧــﻪ ﻣــﻦ اﻟﻌــﺎدات‬
‫اﻟــﱴ ﻳﺘﺒﻌﻬــﺎ أى ﻣــﱪﻣﺞ ﳏــﱰف ﺣــﱴ ﻳﺼــﺒﺢ اﻟــﱪ ﻣﺞ واﺿــﺤﺎ‪ .‬و إذا اﺣﺘﺠﻨــﺎ ﻟﻌﻤــﻞ ﺑﻠــﻮك ﻣــﺎ داﺧــﻞ ﺑﻠــﻮك أﻛــﱪ ﻓــﺈن ﺳــﻄﻮر اﻟﺒﻠــﻮك‬
‫اﻟﺪاﺧﻠﻰ ﳚﺐ أن ﺗﺮﺣﻞ ﻣﺴﺎﻓﺔ أﻛﱪ ﻣﻦ ﺗﺮﺣﻴﻞ ﺳﻄﻮر اﻟﺒﻠﻮك اﳋﺎرﺟﻰ ﺣﱴ ﳝﻜﻦ ﲤﻴﻴﺰﻫﺎ‪.‬‬

‫اﻟﺒﻠ ــﻮك اﻷﺧ ــﲑ ﻫ ــﻮ ﺑﻠ ــﻮك ﻋﻤﻠﻴ ــﺔ اﻟﺘﻘﺮﻳ ــﺐ اﳌﺘﺘ ــﺎﱃ‪ .‬أى ﻋﻤﻠﻴ ــﺔ ﺗﻜﺮارﻳ ــﺔ ﻳﻠ ــﺰم ﳍ ــﺎ إﻋ ــﺪاد أوﱃ ‪ initialization‬ﻛﻤ ــﺎ ﺳ ــﻨﺮى‬
‫ﻟﺘﻔﺼﻴﻞ ﻓﻴﻤﺎ ﺑﻌﺪ‪ .‬اﻟﺴﻄﺮ اﻟﺬﻳﻦ ﻧﻌﻄﻰ ﻓﻴﻬﻤﺎ ﻗﻴﻤﺔ اﺑﺘﺪاﺋﻴﺔ ﻟﻠﺘﻘﺮﻳﺐ اﳌﺘﺘﺎﱃ ﳝﺜﻞ اﻹﻋﺪاد اﻟﻼزم ﳍﺬا اﻟﱪ ﻣﺞ‪.‬‬
‫اﻷﻣــﺮ ;)‪ do {…} while(condition‬ﻣﻔــﺎدﻩ أﻧــﻪ ﳚــﺐ أن ﻳــﺆدى اﻟﺒﻠــﻮك اﻟﺘــﺎﱃ )اﶈﺼــﻮر ﺑــﲔ اﻷﻗـﻮاس اﳌﺜﻨﻴــﺔ }{(‬
‫ﻋﺪد ﻣﻦ اﳌﺮات ﻃﺎﳌﺎ أن اﻟﺸﺮط ‪ condition‬ﻣﺘﺤﻘﻖ‪ .‬ﺑﻌﺪ أن ﻳﺆدى اﻟﺒﻠﻮك ﰱ أى ﻣﺮة ﲟــﺎ ﰱ ذﻟــﻚ اﳌـﺮة اﻷوﱃ ﻳﻔﺤــﺺ اﻟﺸــﺮط‪ ،‬إذا‬
‫ﲢﻘﻖ أدﻳﻨﺎ ﳏﺘﻮ ت اﻟﺒﻠﻮك ﻣﺮة أﺧﺮى ﰒ أﻋﺪ ﻓﺤﺺ اﻟﺸﺮط و ﻫﻜﺬا إﱃ أن ﻳﺼﺒﺢ اﻟﺸﺮط ﻏــﲑ ﻣﺘﺤﻘــﻖ‪ ،‬ﺣﻴﻨﺌــﺬ ﻧﻨﺘﻘــﻞ ﻟﻸﻣــﺮ اﻟــﺬى‬
‫ﻳﻠــﻰ اﻟﺒﻠــﻮك ﻣﺒﺎﺷــﺮة‪ .‬ﺑﻌــﺪ أن ﳔــﺮج ﻣــﻦ اﻟﺒﻠــﻮك اﳌﻮﺟــﻮد ﰱ ﻫــﺬا اﻟــﱪ ﻣﺞ ﳛــﻮى اﳌﺘﻐــﲑ اﳌﺴــﻤﻰ ‪ xnew‬ﻗﻴﻤــﺔ اﳉــﺬر اﳌﻄﻠــﻮب و ﻻ ﻳﻌـﺪ‬
‫أﻣﺎﻣﻨﺎ ﺳﻮى أن ﻧﻜﺘﺒﻪ ﻋﻠﻰ اﻟﺸﺎﺷﺔ‪.‬‬
‫ﻫﻨﺎك أواﻣﺮ أﺧﺮى ﻗــﺪ ﺗﻈﻬــﺮ ﰱ ﺑﺪاﻳــﺔ اﻟــﱪ ﻣﺞ و ﻫــﻰ ﺗﺘﻌﻠــﻖ ﺑﺘﻌﺮﻳــﻒ أﳕــﺎط ﻣﺮﻛﺒــﺔ ﻣــﻦ اﻟﺒﻴــﺎ ت ﺳﺘﺴــﺘﺨﺪم ﰱ اﻟــﱪ ﻣﺞ و ﻫــﻮ‬
‫اﻷﻣﺮ ‪ typedef‬ﻛﻤﺎ ﺳﻨﺸﺮح ﻟﺘﻔﺼﻴﻞ ﻓﻴﻤﺎ ﺑﻌﺪ‪.‬‬
‫ﺳﻨﻮرد ﻓﻴﻤﺎ ﻳﻠﻰ ﻗﺎﺋﻤﺔ ﲟﻠﻔﺎت اﻟﺮأس اﻟﻘﻴﺎﺳﻴﺔ اﻷﻛﺜﺮ اﺳﺘﺨﺪاﻣﺎ ﻣﻊ ﺑﻴﺎن ﻣﻮﺟﺰ ﻻﺳﺘﺨﺪاﻣﻬﺎ‪ .‬ﻳﻌﻄﻰ اﳌﺴﺎﻋﺪ ‪ help‬ﻛﺎﻓﺔ‬
‫ﳏﺘﻮ ت ﻫﺬﻩ اﳌﻠﻔﺎت ﻣﻊ ﺷﺮﺣﻬﺎ ﻟﺘﻔﺼﻴﻞ‪.‬‬
‫‪Stdio.h‬‬ ‫)‪(standard input output‬‬
‫‪math.h‬‬ ‫)‪(standard mathematical functions‬‬
‫‪string.h‬‬ ‫)‪(string manipulations‬‬
‫‪malloc.h‬‬ ‫)‪(dynamic memory allocation‬‬
‫)‪graphics.h (standard graphic operations‬‬
‫‪time.h‬‬ ‫)‪(calculating user and system times‬‬
‫‪conio.h‬‬ ‫)‪(consol input output for DOS mainly‬‬
‫)‪process.h (process control for DOS mainly‬‬
‫ﻣﺎذا ﳛﺪث ﻟﻮ ﻋﺮﻓﻨﺎ داﻟﺔ و أﲰﻴﻨﺎﻫﺎ ﺳﻢ ﻣﻄــﺎﺑﻖ ﻹﺳــﻢ داﻟـﺔ ﻣﻮﺟــﻮدة ﰱ أﺧــﺪ ﻣﻠﻔــﺎت اﻟـﺮأس؟ ﻧﻔــﺮض ﻣــﺜﻼ أﻧﻨــﺎ ﻋﺮﻓﻨــﺎ داﻟــﺔ و أﲰﻴﻨﻬــﺎ‬
‫‪ sin‬ﲤﺎﻣﺎ ﻣﺜﻞ داﻟﺔ اﳊﻴﺐ اﳌﻌﺮﻓﺔ ﰱ اﳌﻠﻒ ‪ .math.h‬ﰱ ﻫــﺬﻩ اﳊﺎﻟــﺔ‪ ،‬ﻓــﺈن اﳊﺎﺳــﺐ ﻻ ﻳﻌﺘــﱪ ذﻟــﻚ ﺧﻄــﺄ و ﻟﻜــﻦ اﻟﺪاﻟــﺔ اﻟــﱴ ﻋﺮﻓﻨﺎﻫــﺎ‬
‫ﲢﺠــﺐ اﻟﺪاﻟــﺔ اﻷﺻــﻠﻴﺔ‪ .‬أى أﻧﻨــﺎ إذا ذﻛــﺮ اﻟﺪاﻟــﺔ ‪ sin‬ﰱ أى ﺟــﺰء ﻣــﻦ اﻟــﱪ ﻣﺞ‪ ،‬ﺳــﻴﻌﺘﱪ اﳊﺎﺳــﺐ أﻧﻨــﺎ ﻧﻘﺼــﺪ اﻟﺪاﻟــﺔ اﻟــﱴ ﻋﺮﻓﻨﺎﻫــﺎ و‬
‫ﻟﻴﺲ اﻟﺪاﻟﺔ اﻷﺻﻠﻴﺔ‪ ،‬اﻟﱴ ﻟﻦ ﻧﺘﻤﻜﻦ ﻣﻦ اﺳﺘﺪﻋﺎﺋﻬﺎ ﰱ ﻫﺬا اﻟﱪ ﻣﺞ‪.‬‬

‫‪30‬‬
‫‪Program statements‬‬ ‫أواﻣﺮ اﻟﱪﳎﺔ‬ ‫‪.3‬‬

‫‪.3‬أ‪ .‬أواﻣﺮ ﺗﻌﺮﻳﻒ اﻟﺒﻴﺎ ت ‪Data definition statements‬‬

‫‪.3‬أ‪ .1.‬أﻧﻮاع اﻟﺒﻴﺎ ت ‪Data types‬‬

‫ﻛﻤﺎ ذﻛﺮ آﻧﻔﺎ‪ ،‬ﻓﺈن اﻟﺒﻴﺎ ت اﻟﱴ ﻳﺘﻌﺎﻣﻞ ﻣﻌﻬﺎ اﳊﺎﺳﺐ ﺗﻨﻘﺴﻢ ﻣﻦ ﺣﻴــﺚ ﺗﻜﻮﻳﻨﻬــﺎ إﱃ ﺑﻴــﺎ ت ﺑﺴــﻴﻄﺔ ‪ simple‬و ﺑﻴــﺎ ت ﻣﻬﻴﻜﻠــﺔ‬
‫‪ .structured‬و ﺗﻨﻘﺴــﻢ ﻛــﻞ ﻓﺌــﺔ ﻷﻧـﻮاع ﻣﺘﻌــﺪدة ﻛﻤــﺎ ﻫــﻮ ﻣﻮﺿــﺢ ﻟﺸــﻜﻞ ‪ .1.1‬اﳉــﺪول اﻟﺘــﺎﱃ ﻳﻮﺿــﺢ أﻧـﻮاع اﻟﺒﻴــﺎ ت اﻟﺒﺴــﻴﻄﺔ ﰱ‬
‫ﻟﻐﺔ ‪) C‬ﻋﺪا اﳌﺆﺷﺮ اﻟﺬى ﺳﻨﺪرﺳﻪ ﻓﻴﻤﺎ ﺑﻌﺪ(‪:‬‬
‫‪Type‬‬ ‫‪Length‬‬ ‫‪Range‬‬

‫‪unsigned char... 8 bits‬‬ ‫‪0‬‬ ‫‪to‬‬ ‫‪255‬‬


‫‪char‬‬ ‫‪... 8 bits‬‬ ‫‪-128‬‬ ‫‪to‬‬ ‫‪127‬‬
‫‪enum‬‬ ‫‪. 16 bits‬‬ ‫‪-32 768‬‬ ‫‪to‬‬ ‫‪32 767‬‬
‫‪unsigned int 16 bits‬‬ ‫‪0‬‬ ‫‪to‬‬ ‫‪65 535‬‬
‫‪short int‬‬ ‫‪. 16 bits‬‬ ‫‪-32 768‬‬ ‫‪to‬‬ ‫‪32 767‬‬
‫‪int‬‬ ‫‪.. 16 bits‬‬ ‫‪-32 768‬‬ ‫‪to‬‬ ‫‪32 767‬‬
‫‪unsigned long . 32 bits‬‬ ‫‪0‬‬ ‫‪to‬‬ ‫‪4 294 967 295‬‬
‫‪long‬‬ ‫‪.. 32 bits‬‬ ‫‪-2 147 483 648‬‬ ‫‪to‬‬ ‫‪2 147 483 647‬‬
‫‪float‬‬ ‫‪... 32 bits‬‬ ‫)‪3.4 * (10**-38‬‬ ‫‪to‬‬ ‫)‪3.4 * (10**+38‬‬
‫‪double‬‬ ‫‪... 64 bits‬‬ ‫)‪1.7 * (10**-308‬‬ ‫‪to‬‬ ‫)‪1.7 * (10**+308‬‬
‫‪long double . 80 bits‬‬ ‫)‪3.4*(10**-4932‬‬ ‫‪to‬‬ ‫)‪1.1*(10**+4932‬‬

‫ﻟﻨﺴــﺒﺔ ﻟﻠﺒﻴــﺎ ت اﻟﺼــﺤﻴﺤﺔ ﻓﺘﻨﻘﺴــﻢ ﻟﻨــﻮﻋﲔ أﺳﺎﺳــﻴﲔ و ﳘــﺎ ‪ char‬و ﻳﺘﻜــﻮن ﻣــﻦ ‪ 1‬ﻳــﺖ و ‪ int‬و ﻳﺘﻜــﻮن ﻋــﺎدة ﻣــﻦ ‪2‬‬
‫ﻳﺖ‪ .‬ﳝﻜﻦ ﻷى ﻧﻮع ﻣﻨﻬﻤﺎ أن ﻳﺴﺒﻘﻪ ﻣﺆﻫﻞ ‪ qualifier‬ﻳﻐﲑ ﻣﻦ ﻧﻮﻋﻪ ﻣﺜﻞ اﳌﺆﻫﻞ ‪ unsigned‬و اﻟﺬى ﻳﻌﲎ أﻧﻨﺎ ﻟﻦ ﳔﺼــﺺ أﻳــﺔ‬
‫ﺑﻴ ــﺖ ﳊﻔ ــﻆ اﻹﺷ ــﺎرة ﺣﻴ ــﺚ أن اﻟﻌ ــﺪد اﳌﻄﻠ ــﻮب ﲤﺜﻴﻠ ــﻪ داﺋﻤ ــﺎ ﻣﻮﺟ ــﺐ‪ .‬و ﻫﻨ ــﺎك أﻳﻀ ــﺎ اﳌ ــﺆﻫﻼت ‪ short‬و ‪ long‬و ﺗﻌ ــﲎ ﲣﺼ ــﻴﺺ‬
‫ﻣﺴﺎﺣﺔ أﻛﱪ أو أﺻﻐﺮ ﻣﻦ اﻟﺬاﻛﺮة‪ .‬ﻳﻼﺣﻆ أن ‪ short int‬ﳝﻜﻦ أن ﲣﺘﺼﺮ إﱃ ‪ short‬ﻛﻤــﺎ ﳝﻜــﻦ اﺧﺘﺼــﺎر ‪ long int‬إﱃ ‪.long‬‬
‫و ﳌﺜﻞ ﻓﺈن اﻷﻋﺪاد اﳊﻘﻴﻘﺔ ﳝﻜﻦ أن ﺗﻜﻮن إﻣﺎ ‪ float‬أو ‪ .double‬اﻟﻨﻮع ‪ double‬ﳝﻜﻦ أن ﻳﺴــﺒﻘﻪ اﳌﺆﻫــﻞ ‪ long‬ﻟﻜــﻰ ﳔﺼــﺺ‬
‫ﻋﺪد أﻛﱪ ﻣﻦ اﳋﺎ ت و ﻟﺘﺎﱃ ﺗﺰداد اﻟﺪﻗﺔ و ﻳﺰداد أﻳﻀﺎ اﳌﺪى‪ .‬ﻻﺣﻆ أن اﻟﺪﻗﺔ و اﳌﺪى ﻗﺪ ﲣﺘﻠــﻒ ﻣــﻦ ﻧﻈــﺎم ﺗﺸــﻐﻴﻞ ﻵﺧــﺮ‪ ،‬ﻧﻈـﺮا‬
‫ﻟﺘﻐﲑ ﻋﺪد اﻟﺒﻴﺖ اﳌﺨﺼﺼﺔ ﻟﻜﻞ ﻧــﻮع‪ .‬و ﻟﻜــﻦ اﳌﻬــﻢ ﻣﺮاﻋــﺎة أن اﳌــﺪى ﳏــﺪود ﰱ ﲨﻴــﻊ اﻷﺣـﻮال‪ .‬ﻫــﺬﻩ اﳌﻠﺤﻮﻇــﺔ ﻫﺎﻣــﺔ ﲟﻜــﺎن‪ ،‬ﺣﻴــﺚ‬
‫أﻧﻨﺎ إذا أرد ﻣﺜﻼ أن ﻧﺘﻌﺎﻣﻞ ﻣﻊ ﻋــﺪد ﺻــﺤﻴﺢ ﻛﺒــﲑ‪ ،‬ﻓﻴﺠــﺐ أن ﳔﺘــﺎر اﻟﻌــﺪد اﻟﺼــﺤﻴﺢ اﳌﻨﺎﺳــﺐ )رﲟــﺎ ﻳﻜــﻮن ‪ long‬أو ‪unsigned‬‬
‫‪ .(long‬و ﻟﻜﻦ إذا ﺗﻌﺪى أﻗﺼﻰ ﻗﻴﻤﺔ ﰱ اﳉﺪول‪ ،‬ﻛﻤﺎ ﳛﺪث ﻣﺜﻼ ﰱ ﺣﺎﻟﺔ ﺣﺴﺎب ﻣﻀﺮوب رﻗﻢ ﻛﺒﲑ‪ ،‬ﻓﻘﺪ ﻧﻠﺠــﺄ ﻻﺳــﺘﺨﺪام ﻧــﻮع‬
‫ﻣﻦ أﻧﻮاع اﻷﻋﺪاد اﻟﻜﺴﺮﻳﺔ ﻣﺜﻞ ‪ double‬اﻟﺬى ﻳﺘﻴﺢ ﻛﺘﺎﺑﺔ ﻋﺪد ﻣﻜﻮﻧﻪ ﻣﻦ ﺣﻮاﱃ ‪ 15‬رﻗﻢ‪.‬‬
‫ﻳﻼﺣﻆ أﻧﻨﺎ ﻗﺪ أﻏﻔﻠﻨﺎ ذﻛﺮ ﻃﺎﺋﻔﺔ ﻣﻦ اﻷﻧﻮاع و ﻫﻰ اﻟﺒﻴــﺎ ت اﳌﻨﻄﻘﻴــﺔ‪ .‬ﻻ ﻳﻮﺟــﺪ ﻧــﻮع ﺧــﺎص ﰱ ﻟﻐــﺔ ‪ C‬و ﻟﻜــﻦ ﻫـﺬﻩ اﻟﻠﻐــﺔ‬
‫ﺗﻌﺘــﱪ أﻳــﺔ ﻗﻴﻤــﺔ ﺻــﻔﺮﻳﺔ ﺗﻈﻬــﺮ ﰱ ﻣﻜــﺎن اﳌﻌﻠﻮﻣــﺔ اﳌﻨﻄﻘﻴــﺔ ﻋﻠــﻰ أ ــﺎ ﺗﻌــﲎ ﺧﻄــﺄ ‪ false‬و أﻳــﺔ ﻗﻴﻤــﺔ أﺧــﺮى ﻏــﲑ ﺻــﻔﺮﻳﺔ ﻋﻠــﻰ أ ــﺎ ﺗﻌــﲎ‬
‫ﺻــﺤﻴﺢ ‪ .true‬أﻣــﺎ اﻟﺒﻴــﺎ ت اﳊﺮﻓﻴــﺔ ﻓﻴﺴــﺘﺨﺪم ﳍــﺎ أﺣــﺪ اﻷﻧ ـﻮاع ‪ char‬أو ‪ .unsigned char‬ﺣﻴــﺚ أن ﻟﻜــﻞ ﺣــﺮف رﻗــﻢ ﻛــﻮدى‬

‫‪31‬‬
‫ﻋﺒﺎرة ﻋﻦ ﻋﺪد ﺻﺤﻴﺢ ﻻ ﻳﺰﻳﺪ ﻋﻦ ‪ 255‬ﻓﺈﻧﻪ ﻳﻜﻔﻰ ﲣﺼﻴﺺ واﺣﺪ ﻳﺖ ﻟﺘﺨﺰﻳﻦ ﺣﺮف‪ .‬ﻻﺣﻆ أن ﻟﻐﺔ ‪ C‬ﺗﻌﺎﻣــﻞ اﳊــﺮف ﻛﻤــﺎ ﻟــﻮ‬
‫ﻛــﺎن ﻋــﺪدا ﺻــﺤﻴﺤﺎ‪ .‬ﻻ ﳝﻜــﻦ اﻟﺘﻤﻴﻴــﺰ ﺑــﲔ اﳊــﺮف و اﻟﻌــﺪد اﻟﺼــﺤﻴﺢ اﳌﺨــﺰن ﰱ ‪ 1‬ﻳــﺖ إﻻ ﻣــﻦ ﺧــﻼل أواﻣــﺮ اﻹدﺧــﺎل و اﻹﺧـﺮاج‬
‫ﻛﻤﺎ ﺳﻨﺮى ﰱ اﻟﻔﺼﻞ اﳋﺎص ﺎ‪.‬‬

‫ﺗﻨﻘﺴــﻢ اﻟﺒﻴــﺎ ت أﻳﻀــﺎ ﻣــﻦ ﺣﻴــﺚ إﻣﻜﺎﻧﻴــﺔ ﺗﻐﲑﻫــﺎ إﱃ ﺛﻮاﺑــﺖ و ﻣﺘﻐـﲑات‪ .‬ﻓﺎﻟﺜﻮاﺑــﺖ ﻫــﻰ ﻗــﻴﻢ ﳏــﺪدة ﻣﻌﻄــﺎة )ﻣﺜــﻞ اﻷرﻗــﺎم و‬
‫اﻷﲰﺎء(‪ .‬أﻣﺎ اﳌﺘﻐﲑات ﻓﻬﻰ أﲰﺎء ﺧﺎ ت ذاﻛﺮة ﲢﻮى ﻗﻴﻤﺎ ﻗﺪ ﺗﺘﻐــﲑ أﺛﻨــﺎء ﺗﻨﻔﻴــﺬ اﻟــﱪ ﻣﺞ‪ .‬ﻓﻴﻤــﺎ ﻳﻠــﻰ ﺑﻌــﺾ اﻟﺘﻮﺿــﻴﺤﺎت ﻋــﻦ اﻷﻧـﻮاع‬
‫اﳌﺨﺘﻠﻔﺔ‪.‬‬

‫‪.3‬أ‪ .2.‬اﻟﺜﻮاﺑﺖ ‪constants‬‬

‫اﻟﺜﻮاﺑﺖ ﳝﻜﻦ أن ﺗﻜﻮن ﻣﻦ أﺣﺪ اﻷﻧﻮاع اﻟﺘﺎﻟﻴﺔ‪ :‬ﻋﺪدﻳﺔ )ﺻﺤﻴﺤﺔ أم ﻛﺴﺮﻳﺔ( أو ﺣﺮﻓﻴﺔ )ﺑﺴﻴﻄﺔ أو ﲨﻠﺔ(‪.‬‬
‫ﻟﻨﺒ ــﺪأ ﻟﺜﻮاﺑ ــﺖ اﻟﻌﺪدﻳ ــﺔ اﻟﺼ ــﺤﻴﺤﺔ‪ .‬ﳝﻜ ــﻦ أن ﺗﻜﺘ ــﺐ ﻫ ــﺬﻩ اﻟﺜﻮاﺑ ــﺖ ﻟﻨﻈ ــﺎم اﻟﻌﺸ ــﺮى ‪ decimal‬أو اﻟﺜﻤ ــﺎﱏ ‪ octal‬أو‬
‫اﻟﺴﺎدس ﻋﺸﺮى ‪ .hexadecimal‬ﰱ اﻟﻨﻈﺎم اﻟﻌﺸﺮى ﳝﻜﻦ أن ﳛــﻮى اﻟﺜﺎﺑــﺖ اﻟﺼــﺤﻴﺢ أﻳــﺔ ﺗﺮﻛﻴﺒــﺔ ﻣــﻦ اﻟﺮﻣــﻮز ﻣــﻦ ‪ 0‬إﱃ ‪ 9‬ﻋﻠــﻰ أﻻ‬
‫ﻳﺒﺪأ ﻟﺮﻗﻢ ‪ 0‬ﻋﻠﻰ اﻟﻴﺴﺎر إﻻ إذا ﻛﺎن اﻟﻌﺪد ﺻﻔﺮا‪ .‬ﻛﻤﺎ ﳝﻜﻦ أن ﳛﻮى إﺷﺎرة ﺳﺎﻟﺒﺔ ﺗﻜﺘﺐ ﰱ ﺑﺪاﻳــﺔ اﻟــﺮﻗﻢ‪ .‬ﺗﻌــﱪ اﻷﻋــﺪاد اﻟﺘﺎﻟﻴــﺔ ﻋــﻦ‬
‫ﺛﻮاﺑﺖ ﺻﺤﻴﺤﺔ ﻣﻜﺘﻮﺑﺔ ﻟﻨﻈﺎم اﻟﻌﺸﺮى‪:‬‬
‫‪0‬‬ ‫‪27 143‬‬ ‫‪32767 -534‬‬
‫ﺑﻴﻨﻤﺎ ﻻ ﺗﻌﱪ اﻟﺮﻣﻮز اﻟﺘﺎﻟﻴﺔ ﻋﻦ ﺑﺖ ﺻﺤﻴﺢ ﻋﺸﺮى‪:‬‬
‫‪027‬‬ ‫‪143.0‬‬ ‫‪32,767 10 000 2-11-1998‬‬
‫ﻫﻨ ــﺎك ﺣ ــﺪ أﻗﺼ ــﻰ و ﺣ ــﺪ أدﱏ ﻟﻠﺜﻮاﺑ ــﺖ اﻟﺼ ــﺤﻴﺤﺔ ﳜﺘﻠ ــﻒ ﺧ ــﺘﻼف اﳌ ــﱰﺟﻢ‪ .‬ﻋ ــﺎدة ﻣ ــﺎ ﺗﻜ ــﻮن ﻫ ــﺬﻩ اﳊ ــﺪود ﻣ ــﻦ ‪ –32768‬إﱃ‬
‫‪ .32767‬إذا ﻛﺎن اﻟﺜﺎﺑﺖ ﻻ ﳛﻮى إﺷﺎرة ﻓﻴﻤﻜﻦ أن ﳝﺘــﺪ ﻣــﻦ ‪ 0‬إﱃ ‪ .65535‬ﻟﻠﺘﻌﺒــﲑ ﻋــﻦ ﻋــﺪد ﺑــﺪون إﺷــﺎرة ‪ unsigned‬ﳚــﺐ‬
‫وﺿـ ـ ــﻊ اﳊـ ـ ــﺮف ‪ u‬أو ‪ U‬ﺑﻌـ ـ ــﺪ اﻟـ ـ ــﺮﻗﻢ ﻣﺜـ ـ ــﻞ‪ .2u4533 :‬إذا أرد اﻟﺘﻌﺒـ ـ ــﲑ ﻋـ ـ ــﻦ ﻗـ ـ ــﻴﻢ أﻛـ ـ ــﱪ )ﻏﺎﻟﺒـ ـ ــﺎ ﻣـ ـ ــﻦ ‪ -2147483648‬إﱃ‬
‫‪ (2147483647‬ﻓﻴﺠﺐ وﺿﻊ اﳊﺮف ‪ l‬أو ‪ L‬ﺑﻌﺪ اﻟﺮﻗﻢ ﻛﻨﺎﻳﺔ ﻋﻦ ﻛﻮﻧﻪ ‪ .long‬و ﳝﻜــﻦ أﻳﻀــﺎ أن ﻳﻜــﻮن اﳊــﺮف ﺑــﺪون إﺷــﺎرة و‬
‫ﻃﻮﻳﻞ ﰱ آن واﺣﺪ‪ .‬اﻷﻣﺜﻠﺔ اﻵﺗﻴﺔ ﺗﻮﺿﺢ ﻣﺎ ﺳﺒﻖ‪:‬‬
‫‪50000u 1000000000L 4000000000uL‬‬
‫ﳝﻜﻦ أﻳﻀــﺎ أن ﻧﻜﺘــﺐ اﻟﺜﺎﺑــﺖ اﻟﺼــﺤﻴﺢ ﰱ ﺻــﻮرة ﻋــﺪد ﲦــﺎﱏ‪ .‬ﰱ ﻫــﺬﻩ اﳊﺎﻟــﺔ ﻳﺒــﺪأ ﻟــﺮﻗﻢ ‪ 0‬و ﳛــﻮى ﺑﻌــﺪ ذﻟــﻚ أى ﺗﺮﻛﻴﺒــﺔ ﻣــﻦ اﻟﺮﻣــﻮز‬
‫ﻣﻦ ‪ 0‬إﱃ ‪ 7‬ﻹﺿﺎﻓﺔ ﻟﻺﺷﺎرة اﻟﺴﺎﻟﺒﺔ إن وﺟﺪت ﰱ ﺑﺪاﻳﺘﻪ‪ .‬ﻛﻤﺎ ﳝﻜﻦ أﻳﻀﺎ أن ﻳﻜﻮن ﻃﻮﻳﻼ أو ﺑﺪون إﺷــﺎرة ﻛﻤــﺎ ﺳــﺒﻖ‪ .‬ﻓﻴﻤــﺎ ﻳﻠــﻰ‬
‫أﻣﺜﻠﺔ ﺻﺤﻴﺤﺔ‪:‬‬
‫‪071‬‬ ‫‪0123 0777 01111u 077777L -0123‬‬
‫أﻣــﺎ اﳌﺜــﺎل اﻟﺘــﺎﱃ ﻓﻬــﻮ ﺧﻄــﺄ‪ 0782 :‬ﻷﻧــﻪ ﳛــﻮى ﻛــﻞ ﻣــﻦ اﻟــﺮﻗﻢ ‪ 0‬ﰱ اﻟﺒﺪاﻳــﺔ و اﻟــﺮﻗﻢ ‪ 8‬ﺑﺪاﺧﻠــﻪ‪ .‬و ﰱ اﻟﻨﻬﺎﻳــﺔ ﳝﻜــﻦ أن ﻳﻜﺘــﺐ ﻋﻠــﻰ‬
‫ﺻــﻮرة ﻋــﺪد ﺳــﺎدس ﻋﺸــﺮى و ذﻟــﻚ ﺑﻮﺿــﻊ اﻟﺮﻣــﺰ ‪ 0x‬ﰱ ﺑﺪاﻳﺘــﻪ‪ .‬ﺗﺴــﺘﺨﺪم ﺑﺪاﺧﻠــﻪ اﻟﺮﻣــﻮز ﻣــﻦ ‪ 0‬إﱃ ‪ 9‬ﻹﺿــﺎﻓﺔ ﻟﻠﺮﻣــﻮز ‪A=10,‬‬
‫‪ .B=11, C=12, D=13, E=14, F=15‬ﻓﻴﻤﺎ ﻳﻠﻰ أﻣﺜﻠﺔ ﺻﺤﻴﺤﺔ‪:‬‬
‫‪0x5A‬‬ ‫‪-0xAB 0x8FFFu‬‬ ‫‪0xFFFFFuL‬‬

‫‪32‬‬
‫ﻧﻨﺘﻘﻞ اﻵن ﻟﻠﺜﻮاﺑﺖ اﳊﻘﻴﻘﺔ )أو اﻟﻜﺴﺮﻳﺔ( ذات اﻟﻨﻘﻄﺔ اﳌﺘﺤﺮﻛﺔ ‪ .floating point‬ﺗﺘﻜﻮن ﻫﺬﻩ اﻷرﻗــﺎم ﻣــﻦ اﻷﻋــﺪاد اﻟﻌﺸـﺮﻳﺔ ﻣــﻦ ‪0‬‬
‫إﱃ ‪ 9‬ﻹﺿــﺎﻓﺔ ﻟﻺﺷـﺎرة إن وﺟــﺪت‪ .‬ﻗــﺪ ﳛــﻮى اﻟﻌﻼﻣــﺔ اﻟﻌﺸـﺮﻳﺔ و ﻫــﻰ اﻟﻨﻘﻄــﺔ "‪ ".‬ﻛﻤــﺎ ﻗــﺪ ﳛــﻮى اﻷس و ﻳﺮﻣــﺰ ﻟــﻪ ﳊــﺮف ‪ e‬ﻳﺘﻠــﻮﻩ‬
‫ﻋﺪد ﺻﺤﻴﺢ ﻗﺪ ﻳﻜﻮن ﻣﻮﺟﺒﺎ أو ﺳﺎﻟﺒﺎ ﳝﺜﻞ ﻗﻴﻤﺔ اﻷس‪ .‬ﻳﻌﱪ اﻷس ﻋﻦ ﺿﺮب اﻟﺮﻗﻢ اﻟﺴﺎﺑﻖ ﰱ ‪ 10‬أس ﻗﻴﻤﺔ اﻷس‪ .‬ﻓﻤﺜﻼ‪:‬‬
‫‪0.234e2 (= 0.234*102 = 23.4) 156e-1 (= 156*10-1 = 15.6 ) -0.11‬‬
‫ﻫــﻰ ﺛﻮاﺑــﺖ ﻧﻘﻄــﺔ ﻣﺘﺤﺮﻛــﺔ ﻣﻘﺒﻮﻟــﺔ‪ .‬اﳊــﺪ اﻷدﱏ و اﻷﻗﺼــﻰ ﻋــﺎدة ﻣــﺎ ﻳﻜــﻮن ﻣﺘﻤﺸــﻴﺎ ﻣــﻊ ﺣــﺪود ‪ float‬أﻋــﻼﻩ و أﺣﻴــﺎ ﻣــﻊ ﺣــﺪود‬
‫‪.double‬‬
‫أﻣﺎ اﻟﺜﻮاﺑــﺖ اﳊﺮﻓﻴــﺔ ﻓﻬــﻰ ﺗﺸــﻤﻞ ﻛــﻞ ﺣــﺮوف اﻷﲜﺪﻳــﺔ اﻟﺼــﻐﲑة و اﻟﻜﺒــﲑة ﻹﺿــﺎﻓﺔ ﻟﻠﻌﻼﻣــﺎت اﳋﺎﺻــﺔ ﻋﻠــﻰ أن ﻳﻮﺿــﻊ اﳊــﺮف‬
‫ﺑﲔ ﻋﻼﻣﺎت ﺗﻨﺼﻴﺺ ﻣﻔﺮدة ﻛﺎﻵﺗﻰ‪:‬‬
‫'(' '‪'a' 'A' '0‬‬ ‫‪'.' etc‬‬

‫و ﻟﻜ ــﻦ ﻻ ﻳﺴ ــﻤﺢ ﻣ ــﺜﻼ ﺑﻜﺘﺎﺑ ــﺔ ﺣ ــﺮﻓﲔ ﺑ ــﲔ ﻋﻼﻣ ــﺎت اﻟﺘﻨﺼ ــﻴﺺ اﳌﻔ ــﺮدة ﻣﺜ ــﻞ '‪ .'ab‬ﻫﻨ ــﺎك أﻳﻀ ــﺎ ﻋﻼﻣ ــﺎت ﺧﺎﺻ ــﺔ ﻻ ﳝﻜ ــﻦ ﲤﺜﻴﻠﻬ ــﺎ‬
‫ﳊﺮوف اﳌﻌﺮوﻓﺔ و ﲤﺜﻞ ﲟﺎ ﻳﺴﻤﻰ ﻣﺘﺴﻠﺴﻼت اﳍﺮب ‪ .escape sequences‬و ﻫﻰ ﺗﻜﺘﺐ ﰱ ﺻﻮرة ﺣﺮﻓﲔ أوﳍﻤﺎ اﻟﺸــﺮﻃﺔ اﳌﺎﺋﻠــﺔ‬
‫ﻟﻠﺨﻠــﻒ \ ‪ .backslash‬و ﻟﻜــﻦ ﳛﺴــﺐ ﻋﻠــﻰ أﻧــﻪ ﺣــﺮف واﺣــﺪ ﻟﻄﺒــﻊ‪ .‬ﻓﻴﻤــﺎ ﻳﻠــﻰ ﺑﻴــﺎن ﺑﻘﺎﺋﻤــﺔ ﻣﺘﺴﻠﺴــﻼت اﳍــﺮب اﳌﺴــﻤﻮح ــﺎ و‬
‫ﻣﻌﲎ ﻛﻞ ﻣﻨﻬﺎ‪:‬‬

‫'‪'\a‬‬ ‫‪ring a bell‬‬


‫'‪'\b‬‬ ‫‪return back one character‬‬
‫'‪'\t‬‬ ‫‪horizontal tab‬‬
‫'‪'\v‬‬ ‫‪vertical tab‬‬
‫'‪'\n‬‬ ‫‪line feed‬‬
‫'‪'\f‬‬ ‫‪form feed‬‬
‫'‪'\r‬‬ ‫‪carriage return‬‬
‫'"\'‬ ‫‪double quotes‬‬
‫''\'‬ ‫‪single quotes‬‬
‫'?\'‬ ‫‪interrogation mark‬‬
‫'\\'‬ ‫‪backslash‬‬
‫'‪'\0‬‬ ‫‪null‬‬
‫و ﰱ اﻟﻨﻬﺎﻳــﺔ ﻓــﺈن اﻟﺜﻮاﺑــﺖ ﻣــﻦ ﻧــﻮع اﳉﻤﻠــﺔ ﲤﺜــﻞ ﻋﻠــﻰ أ ــﺎ ﳎﻤﻮﻋــﺔ ﻣــﻦ اﳊــﺮوف ﲟــﺎ ﰱ ذﻟــﻚ ﻣﺘﺴﻠﺴــﻼت اﳍــﺮب ﳛــﺪﻫﺎ ﻣــﻦ‬
‫اﳉﺎﻧﺒﲔ ﻋﻼﻣﺎت ﺗﻨﺼﻴﺺ ﻣﺰدوﺟﺔ‪ .‬ﻓﻴﻤﺎ ﻳﻠﻰ ﺑﻌﺾ اﻷﻣﺜﻠﺔ‪:‬‬
‫"‪"Hello world‬‬ ‫‪means:‬‬ ‫‪Hello world‬‬
‫"‪"Thanks \nGood luck‬‬ ‫‪means:‬‬ ‫‪Thanks‬‬
‫‪Good luck‬‬
‫"‪"Sum \t 124‬‬ ‫‪means:‬‬ ‫‪Sum‬‬ ‫‪124‬‬
‫"‪"He said \"OK\".‬‬ ‫‪means‬‬ ‫‪He said "OK".‬‬

‫‪.3‬أ‪ .3.‬اﳌﺘﻐﲑات ‪variables‬‬

‫ﺧــﺎ ت اﻟــﺬاﻛﺮة اﻟــﱴ ﲢــﻮى ﺑﻴــﺎ ت ﻗــﺪ ﺗﺘﻐــﲑ أﺛﻨــﺎء ﺳــﲑ اﻟــﱪ ﻣﺞ ﺗﺴــﻤﻰ ﻣﺘﻐـﲑات‪ .‬ﻳﻌﻄــﻰ اﺳــﻢ ﻟﻜــﻞ ﺧﺎﻧــﺔ ﺣــﱴ ﳝﻜــﻦ ﲤﻴﻴﺰﻫــﺎ‬
‫ﺑﺼﻮرة أﻓﻀﻞ و أﺑﺴﻂ ﻣﻦ رﻗﻢ اﳋﺎﻧﺔ وﻟﻜﻦ ﻳﻨﺒﻐﻰ ﻟﻠﻘــﺎرئ أن ﻳﻌــﻰ ﺟﻴــﺪا أن ﻛــﻞ اﺳــﻢ ﻻ ﻳﻌــﲎ ﺳــﻮى رﻗــﻢ ﺧﺎﻧــﺔ ذاﻛــﺮة ﻣــﺎ ﻣﻠﺤــﻖ ــﺬا‬
‫اﻻﺳــﻢ‪ .‬ﺳــﺒﻖ أن أوﺿــﺤﻨﺎ ﻗﻮاﻋــﺪ ﺗﺴــﻤﻴﺔ اﳌﺘﻐ ـﲑات ﰱ ﻟﻐــﺔ ‪ C‬أﻋــﻼﻩ‪ .‬ﺗﻨﻄﺒــﻖ ﻗﻮاﻋ ـﺪ اﻟﺘﺴــﻤﻴﺔ أﻳﻀــﺎ ﻋﻠــﻰ أﲰــﺎء اﻟــﺪوال )أو اﻟ ـﱪاﻣﺞ‬

‫‪33‬‬
‫اﳉﺰﺋﻴــﺔ( اﻟــﱴ ﻧﻌﺮﻓﻬــﺎ ﻧﻔﺴــﻨﺎ‪ .‬ﺑﻌــﺾ اﳌﺘﻐ ـﲑات أو اﻟــﺪوال ﳝﻜــﻦ أن ﺗﻌــﺮف ﰱ ﻣﻠــﻒ و ﺗﺴــﺘﺨﺪم ﰱ ﻣﻠﻔــﺎت أﺧــﺮى‪ .‬ﺗﺴــﻤﻰ ﻣﺘﻐ ـﲑات‬
‫ﻋﺎﻣﺔ ‪ .global variables‬ﰱ ﻫﺬﻩ اﳊﺎﻟﺔ ﳚﺐ ﻋﻠﻰ أداة اﻟﻮﺻﻞ ‪ linker‬أن ﺗﺘﻌﺮف ﻋﻠﻰ اﻷﲰﺎء اﳌﻨــﺎﻇﺮة ﺣــﱴ ﻳــﺘﻢ اﻟﻮﺻــﻞ ﺑﺼــﻮرة‬
‫ﺳﻠﻴﻤﺔ‪ .‬و ﻟﻜﻦ أﺣﻴﺎ ﻛﺜﲑة ﻣﺎ ﺗﻜﻮن أداة اﻟﻮﺻﻞ ﻻ ﳝﻜــﻦ أن ﲤﻴــﺰ ﺳــﻮى ﺑــﲔ اﻷﺣــﺮف اﻟﺴــﺘﺔ اﻷوﱃ ﻣــﻦ ﻛــﻞ اﺳــﻢ ﺑــﻞ أ ــﺎ أﺣﻴــﺎ ﻣــﺎ‬
‫ﻻ ﲤﻴــﺰ ﺑــﲔ اﳊــﺮوف اﻟﻜﺒــﲑة و اﳊــﺮوف اﻟﺼــﻐﲑة‪ .‬و ﻟــﺬﻟﻚ ﳚــﺐ اﳊــﺮص ﻋﻨــﺪ اﺳــﺘﺨﺪام ﻣﺘﻐ ـﲑات ﺷــﺎﻣﻠﺔ أن ﻳﻜــﻮن اﻻﺳــﻢ ﻛﺒ ـﲑا ﲟــﺎ‬
‫ﻳﻜﻔﻰ ﻟﺘﻤﻴﻴﺰﻩ و ﻟﻜﻦ ﺑﺪون ﲣﻄﻰ ‪ 6‬ﺣﺮوف ﺑﻘﺪر اﻹﻣﻜﺎن‪.‬‬

‫ﰱ ﺑﺪاﻳﺔ ﻛﻞ داﻟﺔ ﳚﺐ إﻋﻄﺎء ﻗﺎﺋﻤﺔ ﻛﺎﻣﻠﺔ ﲜﻤﻴﻊ اﳌﺘﻐﲑات اﻟﱴ ﺳﺘﺴﺘﺨﺪم ﰱ ﻫــﺬﻩ اﻟﺪاﻟــﺔ و ﻧــﻮع ﻛــﻞ ﻣﻨﻬــﺎ ﺣــﱴ ﳝﻜــﻦ ﺣﺠــﺰ‬
‫اﻷﻣــﺎﻛﻦ اﳌﻨﺎﺳــﺒﺔ‪ .‬ﺗﺴــﻤﻰ ﺗﻠــﻚ اﻟﻌﻤﻠﻴــﺔ اﻹﻋــﻼن ﻋــﻦ اﳌﺘﻐـﲑات ‪ .variable declaration‬ﻳــﺘﻢ ذﻟــﻚ ﺑــﺬﻛﺮ اﺳــﻢ اﻟﻨــﻮع ﻳﻠﻴــﻪ ﻗﺎﺋﻤــﺔ‬
‫ﲜﻤﻴﻊ اﳌﺘﻐﲑات اﻟﱴ ﺗﻨﻀﻮى ﲢﺖ ﻫﺬا اﻟﻨﻮع‪ ،‬ﻋﻠﻰ اﳌﻨﻮال اﻟﺘﺎﱃ‪:‬‬
‫‪variable_type‬‬ ‫; ‪variable_name, ...‬‬
‫ﳝﻜﻦ ﺗﻜﺮار اﺳﻢ اﻟﻨﻮع أﻛﺜﺮ ﻣﻦ ﻣﺮة‪ .‬ﻣﺜﺎل ذﻟﻚ‪:‬‬
‫‪int‬‬ ‫;‪i, j, column_width‬‬
‫‪float‬‬ ‫;‪pressure, z‬‬
‫;‪double density‬‬
‫‪int‬‬ ‫;‪matrix_size‬‬
‫;‪char answer‬‬
‫و اﻟﱴ إذا ﻇﻬــﺮت ﰱ ﺑﺪاﻳــﺔ ﺑــﺮ ﻣﺞ ﻛــﺎن ﻣﻌﻨﺎﻫــﺎ ﻃﻠــﺐ ﺣﺠــﺰ ‪ 2‬ﻳــﺖ ﻟﻜــﻞ ﻣــﻦ اﳌﺘﻐـﲑات ‪،i,j,column_width,matrix_size‬‬
‫ﻛﻤــﺎ ﳚــﺐ ﺣﺠــﺰ ﻋــﺪد ‪ 4‬ﻳــﺖ ﲢــﺖ اﺳــﻢ اﳌﺘﻐ ـﲑات ‪ ،pressure,z‬و ﻋــﺪد ‪ 8‬ﻳــﺖ ﻟﻠﻤﺘﻐــﲑ ‪ density‬و ﻳــﺖ واﺣــﺪ ﻟﻠﻤﺘﻐــﲑ‬
‫‪ .answer‬ﻳﻼﺣــﻆ أن اﳌﺘﻐــﲑ اﻷﺧــﲑ ﻗــﺪ ﳛــﻮى ﺣﺮﻓــﺎ أو رﻗﻤــﺎ ﺻــﺤﻴﺤﺎ ﻳـﱰاوح ﺑــﲔ ‪ -128‬و ‪ .127‬ﻓﻤــﺜﻼ ﳝﻜــﻦ وﺿــﻊ اﻟﻘﻴﻤﺘــﲔ‬
‫اﻵﺗﻴﺘﲔ ﰱ ﻫﺬا اﳌﺘﻐﲑ ﺑﺪون ﲤﻴﻴﺰ و اﻟﻨﺘﻴﺠﺔ واﺣﺪة‪.‬‬
‫;'‪answer='A‬‬ ‫‪or‬‬ ‫‪answer = 65;.‬‬

‫ﳝﻜــﻦ أﻳﻀــﺎ وﺿــﻊ ﻗﻴﻤــﺔ اﺑﺘﺪاﺋﻴــﺔ ﰱ أى ﻣﺘﻐــﲑ أﺛﻨــﺎء اﻹﻋــﻼن ﻋﻨــﻪ ‪ .initialization‬ﻻﺣــﻆ أن اﻹﻋــﻼن ﻋــﻦ اﳌﺘﻐــﲑ ﰱ ﺣــﺪ‬
‫ذاﺗﻪ ﻻ ﻳﻌﲎ ﺳﻮى ﺣﺠﺰ ﻣﻜﺎن ﰱ اﻟﺬاﻛﺮة و ﻟﻜــﻦ ﳏﺘــﻮى ﻫــﺬا اﳌﻜــﺎن ﻻ ﻳﺘــﺄﺛﺮ و ﻳﻈــﻞ ﻋﻠــﻰ ﻣــﺎ ﻫــﻮ ﻋﻠﻴــﻪ ﻗﺒــﻞ اﳊﺠــﺰ‪ .‬و ﻟﻜــﻦ وﺿــﻊ‬
‫ﻗﻴﻤﺔ اﺑﺘﺪاﺋﻴﺔ ﻳﻀﻴﻒ ﻋﻤﻠﻴﺔ أﺧﺮى ﻟﻌﻤﻠﻴﺔ اﳊﺠﺰ و ﺗﺘﻢ ﻛﻤﺎ ﻳﻠﻰ‪:‬‬
‫;‪int x=12, n=24‬‬
‫;‪double y=1.5e-6‬‬
‫و ﻫﻰ ﻋﻤﻠﻴﺎت ﺗﻜﺎﻓﺊ ﲤﺎﻣﺎ اﻟﻌﻤﻠﻴﺎت اﻟﺘﺎﻟﻴﺔ‪:‬‬
‫;‪int x,n‬‬
‫;‪double y‬‬
‫;‪x = 12; n = 24‬‬
‫;‪y = 1.5e-6‬‬
‫ﻋﻨــﺪﻣﺎ ﻧﻌﻠــﻦ ﻋــﻦ ﻣﺘﻐــﲑ ﰱ ﺑﺪاﻳــﺔ أﻳــﺔ داﻟــﺔ‪ ،‬ﻓﺈﻧــﻪ ﻳﺼــﺒﺢ ﻣــﻦ ﺣﻘﻨــﺎ أن ﻧﺴــﺘﺨﺪﻣﻪ ﰱ أى ﻣﻜــﺎن ﺑــﺪاﺧﻞ ﻫــﺬﻩ اﻟﺪاﻟــﺔ‪ ،‬و ﻟﻜــﻦ‬
‫ﻟﻴﺲ ﲞﺎرﺟﻬﺎ‪ .‬ﻳﺴﻤﻰ ﻫﺬا اﻟﻨﻮع ﻣﻦ اﳌﺘﻐﲑات ﳌﻮﺿﻌﻰ ‪ local variable‬ﻟﺘﻤﻴﻴﺰﻩ ﻋﻦ اﳌﺘﻐﲑ اﻟﻌــﺎم ‪ .global variable‬ﰱ اﻟﻮاﻗــﻊ‬
‫ﻓﺈﻧﻨــﺎ ﳝﻜــﻦ أن ﻧﻌــﺮف ﻣﺘﻐــﲑ ﺑــﺪاﺧﻞ أى ﺑﻠــﻮك )أى ﺑــﲔ اﻷﻗـﻮاس اﳌﻨﺜﻨﻴــﺔ } {( ﻋﻠــﻰ أن ﻳﻜــﻮن اﻟﺘﻌﺮﻳــﻒ ﰱ ﺑﺪاﻳــﺔ اﻟﺒﻠــﻮك‪ .‬ﻳﻜــﻮن ﻣــﻦ‬
‫ﺣﻘﻨﺎ ﺣﻴﻨﺌﺬ اﻟﺘﻌﺎﻣﻞ ﻣــﻊ ﻫــﺬا اﳌﺘﻐــﲑ ﺑــﺪاﺧﻞ ﻫــﺬا اﻟﺒﻠــﻮك و ﻫــﺬا اﻟﺒﻠــﻮك ﻓﻘــﻂ ﲟــﺎ ﰱ ذﻟــﻚ اﻟﺒﻠﻮﻛــﺎت اﻟﺪاﺧﻠﻴــﺔ ﻓﻴــﻪ‪ .‬أﻣــﺎ إذا ﻋﺮﻓﻨــﺎ ﻣﺘﻐــﲑ‬
‫ﺧــﺎرج أى ﺑﻠــﻮك )و ﻟﺘــﺎﱃ ﺧــﺎرج أﻳــﺔ داﻟــﺔ( ﻓﺈﻧــﻪ ﻳﺼــﺒﺢ ﻣﺘﻐـﲑا ﻋﺎﻣــﺎ ‪ global‬ﳝﻜــﻦ اﺳــﺘﺨﺪاﻣﻪ ﰱ أى ﻣﻜــﺎن ﰱ اﻟــﱪ ﻣﺞ ﻣﻨــﺬ ﻧﻘﻄــﺔ‬
‫ﺗﻌﺮﻳﻔﻪ و إﱃ ﺎﻳﺔ اﳌﻠﻒ‪ .‬ﻟﺮﻏﻢ ﻣﻦ أن اﺳﺘﺨﺪام اﳌﺘﻐـﲑات اﻟﻌﺎﻣــﺔ ﻗــﺪ ﻳﺒﺴــﻂ ﻣــﻦ ﻛﺘﺎﺑــﺔ ﺑﻌــﺾ اﻟـﱪاﻣﺞ ﻛﻤــﺎ ﺳــﻨﺮى ﰱ اﻟﻔﺼــﻞ اﳋــﺎص‬

‫‪34‬‬
‫ﻟــﺪوال‪ ،‬إﻻ أﻧــﻪ ﻣــﻦ ﻏــﲑ اﳌﻨﺼــﻮح ــﺎ اﻹﻛﺜــﺎر ﻣــﻦ اﺳــﺘﺨﺪاﻣﻬﺎ ﺣﻴــﺚ أ ــﺎ ﻗــﺪ ﺗﺸــﺠﻊ اﳌﺴــﺘﺨﺪم ﻋﻠــﻰ ﺧــﺮق ﻗﻮاﻋــﺪ اﻟﱪﳎــﺔ اﳍﻴﻜﻠﻴــﺔ‪،‬‬
‫ﻹﺿﺎﻓﺔ ﻷن اﻟﺘﻌﺎﻣﻞ ﻣﻊ اﳌﺘﻐﲑات اﳌﻮﺿﻌﻴﺔ ﻳﻜﻮن داﺋﻤﺎ أﺳﺮع ﰱ أﺛﻨﺎء ﺗﻨﻔﻴﺬ اﻟﱪ ﻣﺢ‪.‬‬
‫ﺳــﻨﺘﻨﺎول اﳌﺆﺷ ـﺮات ‪ pointers‬ﰱ ب ﻻﺣــﻖ‪ .‬ﻛﻤــﺎ ﺳﻨﻘﺘﺼــﺮ ﰱ دراﺳــﺘﻨﺎ ﻟﻠﺒﻴــﺎ ت اﳌﻬﻴﻜﻠــﺔ ﻋﻠــﻰ ﺑﻌــﺾ اﳌﻼﻣــﺢ اﻷﺳﺎﺳــﻴﺔ‬
‫ﻟﻠﻤﺘﺠﻬــﺎت أو اﳌﺼــﻔﻮﻓﺎت ‪ arrays‬و اﳉﻤــﻞ ‪.strings‬ﺑﻌــﺪ ﻣﻌﺮﻓــﺔ اﳌﺰﻳــﺪ ﻋــﻦ اﳌﺆﺷ ـﺮات ﺳﻨﺴــﺘﻄﻴﻊ أن ﻧﻌﻄــﻰ ﻣﻌﻠﻮﻣــﺎت أﻛﺜــﺮ ﻋــﻦ‬
‫اﻟﺒﻴﺎ ت اﳌﻬﻴﻜﻠﺔ‪ .‬أﻣﺎ اﳌﻠﻔﺎت ﻓﺴﻨﺸﺮﺣﻬﺎ ﰱ اﻟﻔﺼﻞ اﳋﺎص واﻣﺮ اﻹدﺧﺎل و اﻹﺧﺮاج‪.‬‬

‫‪.3‬أ‪ .4.‬اﳌﺘﺠﻬﺎت أو اﳌﺼﻔﻮﻓﺎت ‪arrays‬‬

‫ﻫــﺬﻩ اﻟﺒﻴــﺎ ت اﳌﻬﻴﻜﻠــﺔ ﻫــﻰ ﻋﺒــﺎرة ﻋــﻦ ﻋــﺪد ﻣــﻦ اﻟﻌﻨﺎﺻــﺮ ‪ n‬اﳌﺘﺸــﺎ ﺔ و اﳌﺮﺗﺒــﺔ ﻣــﻦ ‪ 0‬إﱃ ‪ .n-1‬ﻛــﻞ ﻋﻨﺼــﺮ ﻗــﺪ ﻳﻜــﻮن ﺑﻴــﺎن‬
‫ﺑﺴﻴﻂ )ﻋﺪدى أو ﺣﺮﰱ أو ﻣﺆﺷﺮ( أو ﺑﻴﺎن ﻣﺮﻛﺐ آﺧﺮ‪ .‬اﻟﺼﻮرة اﻟﻌﺎﻣﺔ ﻟﻺﻋﻼن ﻋﻦ ﻣﺘﺠﻪ ﻫﻰ ﻛﺎﻵﺗﻰ‪:‬‬
‫;]‪element_type array_name [number_of_elements‬‬
‫و ﻫ ــﻰ ﺗﻌ ــﲎ أن اﳌﻄﻠ ــﻮب ﺣﺠ ــﺰ ﻋ ــﺪد ﻣ ــﻦ اﻟﻌﻨﺎﺻ ــﺮ ﻳﺴ ــﺎوى ‪ number_of_elements‬ﻛ ــﻞ ﻋﻨﺼ ــﺮ ﻣ ــﻦ ﻧ ــﻮع ‪element_type‬‬
‫ووﺿﻊ ﻛﻞ ﻫﺬﻩ اﻟﻌﻨﺎﺻﺮ ﲢﺖ اﺳﻢ ‪ .array_name‬ﻣﺜﺎل‪:‬‬
‫;]‪double x[5‬‬
‫ﻳﺆدى ﳊﺠﺰ ﻋﺪد ‪ 5‬ﻋﻨﺎﺻﺮ ﻛﻞ ﻋﻨﺼﺮ ﻣــﻦ ﻧــﻮع ‪ double‬ﲢــﺖ اﺳــﻢ ‪ .x‬ﳝﻜــﻦ ﺑﻌــﺪ ذﻟــﻚ اﻟﺘﻌﺎﻣــﻞ ﻣــﻊ أى ﻋﻨﺼــﺮ ﺳــﺘﺨﺪام اﻟــﺪﻟﻴﻞ‬
‫‪ index‬اﳌﻨﺎﺳــﺐ‪ .‬ﻓﺎﻟﻌﻨﺼــﺮ اﻷول ﻫــﻮ ]‪ x[0‬و اﻟﺜــﺎﱏ ﻫــﻮ ]‪ x[1‬و ﻫﻜــﺬا أﻣــﺎ اﻟﻌﻨﺼــﺮ اﻷﺧــﲑ ﻓﻬــﻮ ]‪ .x[4‬ﻻﺣــﻆ أن اﻟﻌﻨﺼــﺮ ]‪x[5‬‬
‫ﻟﻴﺲ ﻣﻮﺟﻮدا ﻛﺠﺰء ﻣﻦ اﳌﺘﺠــﻪ اﻟــﺬى ﰎ ﺣﺠــﺰﻩ‪ .‬أﻏﻠــﺐ اﳌﱪﳎــﲔ ﺗﻌــﻮدوا ﻋﻠــﻰ اﻟﺘﻌﺎﻣــﻞ ﻣــﻊ اﳌﺘﺠﻬــﺎت ﻣــﻦ ‪ 1‬إﱃ ‪ n‬و ﻟــﻴﺲ ﻣــﻦ ‪ 0‬إﱃ‬
‫‪ .n-1‬و ﻟﺬا ﻓﺈ ﻢ ﻛﺜﲑا ﻣﺎ ﻳﻠﺠﺌﻮا ﳊﺠﺰ ﻋﺪد ﻣﻦ اﻷﻣﺎﻛﻦ ﻳﺴﺎوى اﳌﻄﻠﻮب اﻟﺘﻌﺎﻣﻞ ﻣﻌﻪ زاﺋــﺪ واﺣــﺪ‪ ،‬ﻟﻠﺘﻘﻠﻴــﻞ ﻣــﻦ اﺣﺘﻤــﺎل وﻗــﻮع ﻫــﺬا‬
‫اﳋﻄــﺄ‪ .‬ﻓــﺈذا أرد ﻣــﺜﻼ اﻟﺘﻌﺎﻣــﻞ ﻣــﻊ ﲬﺴــﺔ ﻋﻨﺎﺻــﺮ ﻓﺴــﻨﻌﺘﱪﻫﺎ اﻟﻌﻨﺎﺻــﺮ ﻣــﻦ رﻗــﻢ ‪ 1‬إﱃ اﻟــﺮﻗﻢ ‪ 5‬و ﺑــﺬﻟﻚ ﳓﺠــﺰ ﺳــﺘﺔ ﻋﻨﺎﺻــﺮ ﺑﻮاﺳــﻄﺔ‬
‫اﻷﻣﺮ‪:‬‬
‫;]‪double x[6‬‬
‫و ﺑﺬﻟﻚ ﻳﻜﻮن ﻣﻦ اﳌﻤﻜﻦ اﻟﺘﻌﺎﻣﻞ ﻣﻊ اﻟﻌﻨﺎﺻﺮ ﻣﻦ ]‪ x[1‬إﱃ ]‪ x[5‬أﻣﺎ اﻟﻌﻨﺼﺮ ]‪ x[0‬ﻓﺈﻧﻪ ﳛﺠﺰ ﻟﻪ ﻣﻜــﺎن و ﻟﻜــﻦ ﻻ ﻳﺴــﺘﺨﺪم‪ .‬و‬
‫ﻟﺮﻏﻢ ﻣﻦ ﻛﻮن اﻟﺘﻌﺎﻣﻞ ﻣﻊ ﻋﻨﺼﺮ ﻳﺰﻳﺪ رﻗﻤﻪ ﻋﻤــﺎ ﰎ ﺣﺠــﺰﻩ ﻳﻌﺘــﱪ ﺧﻄــﺄ ﺑﺮﳎﻴــﺎ‪ ،‬إﻻ أن ﻣــﱰﺟﻢ ﻟﻐــﺔ ‪ C‬ﻟــﻦ ﻳﻜﺘﺸــﻔﻪ ﺣﻴــﺚ أﻧــﻪ ﻗــﺪ ﻳﻘــﻊ‬
‫ﺑﺼﻮرة ﻏﲑ ﻣﺒﺎﺷﺮة‪ .‬ﲣﻴﻞ ﻣﺜﻼ أﻧﻨﺎ ﳕﻸ ﺑﻴﺎ ت ﻣﺘﺠﻪ ﻣﻦ ﺧﻼل دورة ﺗﺘﻮﻗﻒ ﻋﻨﺪ اﻧﺘﻬﺎء اﻟﺒﻴﺎ ت‪ ،‬ﻛﺎﻟﺘﺎﱃ‪:‬‬
‫) (‪void main‬‬
‫{‬
‫;‪double x[5], y‬‬
‫;‪int n=0‬‬
‫‪while (…..) /* any condition that means data are still coming */‬‬
‫{‬
‫‪/* get the data in the variable y */‬‬
‫;‪x[n]=y‬‬
‫;‪n++‬‬
‫}‬
‫}‬
‫ﻓﺈذا دﺧﻞ ﻋﺪد ﻣــﻦ اﻟﺒﻴــﺎ ت ﻳﺰﻳــﺪ ﻋــﻦ ‪ ،5‬ﺳــﻴﺤﺪث ﺧﻄــﺄ‪ .‬ﻫــﺬا اﻷﻣــﺮ اﳋــﺎﻃﺊ ﺳــﻴﺆدى ﻟﻜﺘﺎﺑــﺔ ﻗﻴﻤــﺔ ‪ y‬ﻋﻠــﻰ ﺧــﺎ ت اﻟــﺬاﻛﺮة اﻟﺘﺎﻟﻴــﺔ‬
‫ﳋﺎ ت اﳌﺘﺠﻪ ‪ x‬ﻣﻔﺴﺪا ﺑﺬﻟﻚ ﳏﺘﻮاﻫﺎ‪ .‬و ﻟﺬﻟﻚ ﻳﻔﻀﻞ إﻋﺎدة ﻛﺘﺎﺑﺔ اﻟﱪ ﻣﺞ اﻟﺴﺎﺑﻖ ﻋﻠﻰ اﻟﺼﻮرة اﻟﺘﺎﻟﻴﺔ ﻟﺘﺠﻨﺐ اﳋﻄﺄ‪:‬‬
‫‪#define SIZ 5‬‬

‫‪35‬‬
‫) (‪void main‬‬
‫{‬
‫;‪double x[SIZ],y‬‬
‫;‪int n=0‬‬
‫)…( ‪while‬‬
‫{‬
‫)‪if (n>=SIZ‬‬
‫;)(‪error_msg‬‬
‫‪/* get the data in the variable y */‬‬
‫;‪x[n]=y‬‬
‫;‪n++‬‬
‫}‬
‫}‬
‫ﳝﻜﻦ أﻳﻀﺎ أن ﻳﻜﻮن ﻧﻮع ﻛﻞ ﻋﻨﺼﺮ أى ﻧﻮع ﻣﻦ اﻷﻧﻮاع اﻟﺒﺴﻴﻄﺔ اﻷﺧﺮى ﻣﺜﻞ‪:‬‬
‫;]‪long marks[85‬‬
‫و ﻫ ـﻮ ﻳﻌــﲎ ﺣﺠــﺰ ﻋــﺪد ‪ 85‬ﻋﻨﺼــﺮ ﻣــﻦ ﻧــﻮع ‪ long‬ﻟﻮﺿــﻊ اﻟــﺪرﺟﺎت ‪ marks‬ل‪ 85‬ﻃﺎﻟــﺐ‪ .‬ﳝﻜــﻦ أﻳﻀــﺎ أن ﻳﻜــﻮن ﻧــﻮع اﻟﻌﻨﺼــﺮ‬
‫ﻣﺘﺠ ــﻪ آﺧ ــﺮ أو أﻳ ــﺔ ﺑﻴ ــﺎن ﻣﺮﻛــﺐ ﻣ ــﻦ اﻟﺒﻴ ــﺎ ت اﻟــﱴ ﺳﻨﺪرﺳ ــﻬﺎ ﻓﻴﻤ ــﺎ ﺑﻌ ــﺪ ﻣﺜ ــﻞ اﳉﻤﻠ ــﺔ ‪ string‬أو اﻟﺘﺴ ــﺠﻴﻞ ‪ .record‬ﻓﻤ ــﺜﻼ ﺗﻌﺘ ــﱪ‬
‫اﳌﺼﻔﻮﻓﺔ ﻣﺘﺠﻪ ﻣﻜﻮن ﻣﻦ ﻋﺪد ﻣﻦ اﳌﺘﺠﻬﺎت‪ .‬ﻓﺈذا أرد أن ﳓﺠﺰ ﻣﺼﻔﻮﻓﺔ ﻣﻜﻮﻧﺔ ﻣﻦ ‪ 4‬ﺻﻔﻮف و ‪ 6‬أﻋﻤﺪة ﻓﻴﻤﻜﻦ ﻛﺘﺎﺑﺔ‪:‬‬
‫;]‪double A[4][6‬‬
‫ﺬا اﻷﻣﺮ ﰎ ﺣﺠﺰ ﻋﺪد ‪ 24‬ﻋﻨﺼﺮ ﻣﻦ ﻧﻮع ‪ .double‬اﻟﻌﻨﺼــﺮ اﻷول ﰱ اﻟﺼــﻒ اﻷول ﻫــﻮ ]‪ A[0][0‬ﰒ ﻳﺘﻠــﻮﻩ ﻋﻠــﻰ ﻧﻔــﺲ اﻟﺼــﻒ‬
‫اﻟﻌﻨﺼﺮ ]‪ A[0][1‬و ﻫﻜﺬا أﻣﺎ اﻟﻌﻨﺼﺮ اﻷول ﰱ اﻟﺼــﻒ اﻟﺜــﺎﱏ ﻓﻬــﻮ ]‪ .A[1][0‬اﻟﻌﻨﺼــﺮ اﻷﺧــﲑ ﰱ اﻟﺼــﻒ اﻷﺧــﲑ ﻫــﻮ ]‪،A[3][5‬‬
‫ﻛﻤﺎ ﻳﻮﺿﺢ اﳉﺪول اﻟﺘﺎﱃ‪:‬‬

‫‪0‬‬ ‫‪1‬‬ ‫‪2‬‬ ‫‪3‬‬ ‫‪4‬‬ ‫‪5‬‬


‫‪0‬‬ ‫]‪A[0][0‬‬ ‫]‪A[0][1‬‬ ‫]‪A[0][2‬‬ ‫]‪A[0][3‬‬ ‫]‪A[0][4‬‬ ‫]‪A[0][5‬‬
‫‪1‬‬ ‫]‪A[1][0‬‬ ‫]‪A[1][1‬‬ ‫]‪A[1][2‬‬ ‫]‪A[1][3‬‬ ‫]‪A[1][4‬‬ ‫]‪A[1][5‬‬
‫‪2‬‬ ‫]‪A[2][0‬‬ ‫]‪A[2][1‬‬ ‫]‪A[2][2‬‬ ‫]‪A[2][3‬‬ ‫]‪A[2][4‬‬ ‫]‪A[2][5‬‬
‫‪3‬‬ ‫]‪A[3][0‬‬ ‫]‪A[3][1‬‬ ‫]‪A[3][2‬‬ ‫]‪A[3][3‬‬ ‫]‪A[3][4‬‬ ‫]‪A[3][5‬‬
‫ﻛﻤﺎ ﺳﺒﻖ ﳝﻜﻦ أﻳﻀﺎ ﺣﺠﺰ ﻣﻜﺎن إﺿﺎﰱ ﻻ ﻳﺴﺘﺨﺪم ﺣﱴ ﳝﻜﻦ اﻟﺘﻘﻠﻴﻞ ﻣﻦ اﺣﺘﻤﺎل اﳋﻄﺄ ﲝﻴﺚ ﳓﺠﺰ ﰱ ﻫﺬﻩ اﳊﺎﻟﺔ‪:‬‬
‫;]‪double A[5][7‬‬
‫ﳑﺎ ﻳﻌﲎ ﺣﺠﺰ ﻋﺪد ‪ 35‬ﻋﻨﺼــﺮ ﻣــﻦ ﻧــﻮع ‪ .double‬ﳝﻜﻨﻨــﺎ ذﻟــﻚ ﻣــﻦ اﻟﺘﻌﺎﻣــﻞ ﻣــﻊ اﻟﻌﻨﺼــﺮ ]‪ A[1][1‬ﻛﻤــﺎ ﻟــﻮ ﻛــﺎن اﻟﻌﻨﺼــﺮ اﻷول ﰱ‬
‫اﻟﺼــﻒ اﻷول و ﻫﻜــﺬا ﺣــﱴ ﻧﺼــﻞ ﻟﻠﻌﻨﺼــﺮ اﻷﺧــﲑ و ﻫــﻮ ]‪ .A[4][6‬أﻣــﺎ اﻟﻌﻨﺎﺻــﺮ اﻟــﱴ ﳍــﺎ دﻟﻴــﻞ ﻳﺴــﺎوى ﺻــﻔﺮا ﺳـﻮاء ﻛﺎﻧــﺖ ﰱ رﻗــﻢ‬
‫اﻟﺼﻒ أو رﻗﻢ اﻟﻌﻤﻮد ﻓﻬﻰ ﺗﺒﻘﻰ ﺑﺪون اﺳﺘﻐﻼل‪ .‬ﳝﻜﻦ إﻋﻄﺎء ﻗﻴﻤﺔ اﺑﺘﺪاﺋﻴﺔ ﻋﻨﺪ اﳊﺠﺰ ﻣﺜﻞ‪:‬‬
‫;}‪int class_num[4] = {18,20,17,15‬‬
‫و ﻫﻮ ﻳﻌﻠﻦ ﻋﻦ ﻣﺘﺠﻪ ﳛﻮى ﻣﺜﻼ ﻋﺪد اﻟﻄﻠﺒﺔ ﰱ ﻋﺪد ﻣﻦ اﻟﻔﺼﻮل )‪ 4‬ﻓﺼﻮل ﰱ ﻫﺬﻩ اﳊﺎﻟﺔ( و ﻹﺿــﺎﻓﺔ ﻟــﺬﻟﻚ ﻳﻌﻄــﻰ ﻋــﺪد اﻟﻄﻠﺒــﺔ‬
‫ﰱ ﻛﻞ ﻓﺼﻞ ﻛﻘﻴﻤﺔ اﺑﺘﺪاﺋﻴﺔ ﻗﺪ ﺗﻌﺪل ﺑﻌﺪ ذﻟﻚ ﺧﻼل اﻟﱪ ﻣﺞ‪ .‬ﳝﻜﻦ أﻳﻀﺎ إﻋﻄﺎء ﻗﻴﻤﺎ اﺑﺘﺪاﺋﻴﺔ ﳉﺰء ﻣﻦ اﳌﺘﺠﻪ ﻓﻘﻂ ﻣﺜﻞ‪:‬‬
‫;}‪int class_num[4] = {17,19‬‬
‫و ﰱ ﻫﺬﻩ اﳊﺎﻟﺔ ﺗﻜﻮن اﻟﻘﻴﻤﺔ اﻻﺑﺘﺪاﺋﻴﺔ ﻟﻠﻌﻨﺎﺻﺮ ﻫﻰ ﻛﻤﺎ ﻳﻠﻰ‪:‬‬
‫‪x[0] = 17‬‬ ‫‪x[1] = 19‬‬ ‫‪x[2] = 0‬‬ ‫‪x[3] = 0‬‬
‫ﳝﻜﻦ أﻳﻀﺎ ﻋﺪم ﲢﺪﻳﺪ اﻟﻌﺪد ﻣﺴﺒﻘﺎ إذا أﻋﻄﻴﺖ ﻗﺎﺋﻤﺔ ﻛﺎﻣﻠﺔ ﻟﻘﻴﻢ اﻻﺑﺘﺪاﺋﻴﺔ ﻣﺜﻞ‪:‬‬
‫;}‪int class_num[ ] = {18,20,17,15‬‬

‫‪36‬‬
‫ ﻹﻋﻄــﺎء ﻗﻴﻤــﺔ اﺑﺘﺪاﺋﻴــﺔ ﳌﺼــﻔﻮﻓﺔ‬.‫ ﺑــﺪاﺧﻞ اﻷﻗـﻮاس اﳌﺮﺑﻌــﺔ‬4 ‫و ﻫﻮ ﻣﻜﺎﻓﺊ ﲤﺎﻣﺎ ﻟﻨﻔﺲ اﻷﻣﺮ اﻷﺳﺒﻖ ﺣﻴﺚ ﻳﻀﻴﻒ اﳌﱰﺟﻢ ﺑﻨﻔﺴﻪ اﻟﺮﻗﻢ‬
:‫ﻧﻜﺘﺐ‬
int A[2][3] = {{1,2,5},{3,7,6}};
.{3,7,6} ‫{ و اﻟﺼﻒ اﻟﺜﺎﱏ‬1,2,3} ‫ﺣﻴﺚ ﳛﻮى اﻟﺼﻒ اﻷول‬
:‫ﻛﻤﺜﺎل ﻋﻠﻰ اﳌﺘﺠﻬﺎت ﺳﻨﺪرس اﻟﱪ ﻣﺞ اﻟﺘﺎﱃ و اﻟﺬى ﻳﻘﻮم ﲝﺴﺎب ﺣﺎﺻﻞ ﺿﺮب ﻣﺼﻔﻮﻓﺔ ﰱ ﻣﺘﺠﻪ‬
#include <stdio.h>
#include <conio.h>
void main(void)
{ /* program to multiply matrix A by vector x to get vector y */
int i, j, n; double temp;
double A[5][5], x[5], y[5];
/* Entering and examining data */
printf("\nEnter matrix size: ");
scanf("%d",&n);
if (i > 4)
{
printf("\nInvalid size, maximum is 4\n");
getch(); exit(5);
}
/* Entering matrix and vector elements */
for (i = 1; i <= n; i++)
{
for (j = 1; j<=n; j++)
{
printf("Enter A[%d][%d]: ",i,j);
scanf("%lg",&A[i][j]);
}
printf("Enter x[%d] : ", i);
scanf("%lg",&x[i]);
}
/* Calculating the product A x = y */
for (i = 1; i <= n; i++)
{
temp = 0.0;
for (j = 1; j<=n; j++)
{
temp += A[i][j] * x[j];
}
y[i] = temp;
printf("y[%d] = %lg \n", i,y[i]);
}
getch();
}

‫ ﻓﺎﻷﻣﺮ‬.index ‫ ﺣﻴﺚ ﻳﺴﻤﺢ ﺑﻌﻤﻞ ﻋﻤﻠﻴﺎت ﺗﻜﺮارﻳﺔ ﺑﻨﺎء ﻋﻠﻰ ﻗﻴﻤﺔ ﻟﻠﺪﻟﻴﻞ‬for ‫ﻇﻬﺮ ﰱ ﻫﺬا اﳌﺜﺎل أﻣﺮ ﺟﺪﻳﺪ و ﻫﻮ‬
for (i = 1; i<= n; i++)
{

37
‫>‪<loop_body‬‬
‫}‬
‫ﻳﻌﲎ أن ﻧﻨﻔﺬ اﻷواﻣﺮ اﳌﻮﺟﻮدة ﺑﺪاﺧﻞ اﻟﺒﻠﻮك اﶈﺪود ﻷﻗﻮاس اﳌﺜﻨﻴﺔ )أى اﻷواﻣﺮ >‪ (<loop_body‬ﻋﺪد ﻣــﻦ اﳌـﺮات ﰱ اﳌــﺮة اﻷوﱃ‬
‫ﻧﻀﻊ ‪ i=1‬ﰒ ﰱ ﻛﻞ ﻣﺮة ﻧﺰﻳﺪ ‪ i‬ﲟﻘﺪار اﻟﻮﺣﺪة و ﻧﻜﺮر ﺗﻨﻔﻴﺬ ﻧﻔﺲ اﻟﺒﻠﻮك ﻃﺎﳌﺎ أن ﻗﻴﻤﺔ ‪ i‬اﺻﻐﺮ ﻣﻦ أو ﺗﺴﺎوى ‪.n‬‬
‫ﻻﺣﻆ أﻳﻀﺎ اﻷﻣﺮ‪:‬‬
‫;]‪temp += A[I][j] * x[j‬‬
‫و ﻫﻮ ﻳﻌﲎ إﺿﺎﻓﺔ ﻗﻴﻤﺔ اﻟﺘﻌﺒﲑ اﳌﻮﺟﻮد ﻋﻠﻰ ﻳﺴﺎر ﻋﻼﻣﺔ اﻟﺘﺴﺎوى ﳌﺎ ﻛﺎن ﻣﻮﺟﻮدا ﰱ ﺧﺎﻧﺔ اﻟﺬاﻛﺮة ‪ temp‬أى أﻧﻪ ﻳﻜﺎﻓﺊ‪:‬‬
‫;]‪temp = temp + A[I][j] * x[j‬‬

‫و ﻛﻤﺜﺎل آﺧﺮ ﻋﻠﻰ إﻋﻄﺎء ﻗﻴﻤﺎ اﺑﺘﺪاﺋﻴﺔ ﻟﻠﻤﺘﻐﲑات‪ ،‬ﻣﺎذا ﺳﻴﻄﺒﻊ اﻟﱪ ﻣﺞ اﻟﺘﺎﱃ‪:‬‬
‫)‪void main (void‬‬
‫{‬
‫;‪int m,n = 12‬‬
‫;}‪double x[4]={2.5,4.5‬‬
‫;}‪double y[]={2.5,4.5‬‬
‫;)‪printf("m=%d n=%d\n",m,n‬‬
‫;)]‪printf("x[2]=%lg y[2]=%lg\n",x[2],y[2‬‬
‫}‬
‫ﰱ اﻟﺴــﻄﺮ اﻷول ﻳﻜﺘــﺐ اﻟــﱪ ﻣﺞ ﻗــﻴﻢ ‪ .m, n‬ﻗﻴﻤــﺔ ‪ n‬ﻣﻌﻄــﺎة و ﻫــﻰ اﻟﻘﻴﻤــﺔ اﻻﺑﺘﺪاﺋﻴــﺔ ‪ .12‬أﻣــﺎ ﻗﻴﻤــﺔ ‪ m‬ﻓﻬــﻰ ﻏــﲑ ﻣﻌﺮﻓــﺔ‪ .‬ﰱ اﻟﻮاﻗــﻊ‬
‫ﻓﺈن أﻣــﺮ ﺗﻌﺮﻳــﻒ اﳌﺘﻐــﲑ ‪ m‬ﻻ ﻳﻨــﺘﺞ ﻋﻨــﻪ ﺳــﻮى ﺣﺠــﺰ ﳋﺎﻧــﺔ ذاﻛــﺮة ﺗﺴــﻤﻰ ﺑــﺬﻟﻚ اﻹﺳــﻢ‪ .‬ﻗـﺪ ﲢــﻮى ﻫــﺬﻩ اﳋﺎﻧــﺔ أﻳــﺔ ﻗﻴﻤــﺔ ﻋﻨــﺪ اﳊﺠــﺰ‪.‬‬
‫ﺣﻴــﺚ أن ﻫــﺬﻩ اﻟﻘﻴﻤــﺔ ﱂ ﺗﻌــﺪل أﺛﻨــﺎء ﺗﻨﻔﻴــﺬ اﻟــﱪ ﻣﺞ‪ ،‬ﻓــﺈن اﻟــﱪ ﻣﺞ ﺳــﻴﻜﺘﺐ ﻗﻴﻤــﺔ ﻏــﲑ ﻣﻌﺮﻓــﺔ ﲤﺜــﻞ اﻟﻘﻴﻤــﺔ اﶈﺘـﻮاة ﰱ اﳌﺘﻐــﲑ ‪ m‬ﳊﻈــﺔ‬
‫اﳊﺠﺰ‪ .‬أﻣﺎ ﻟﻨﺴﺒﺔ ﻟﻠﻤﺘﻐﲑات ‪ ،x, y‬ﻓﺈن ﺳﻄﺮ اﻹﻋﻼن ﻋﻦ ﺗﻠﻚ اﳌﺘﻐﲑات ﻗﺪ وﺿﻊ ﻗﻴﻤﺎ اﺑﺘﺪاﺋﻴــﺔ ﰱ ﺑﻌﻀــﻬﺎ‪ .‬ﻓﻠﻘــﺪ ﻋــﺮف اﳌﺘﻐــﲑ ‪x‬‬
‫ﻋﻠﻰ أﻧﻪ ﻣﺘﺠﻪ ﻣﻦ ‪ 4‬ﻋﻨﺎﺻﺮ و أﻋﻄﻴﺐ ﻗﻴﻤﺎ اﺑﺘﺪاﺋﻴﺔ ﻷول ﻋﻨﺼﺮﻳﻦ ﻓﻴﻪ‪ .‬و ﻟﺘــﺎﱃ ﻓــﺈن ﻗــﻰ اﻟﻌﻨﺎﺻــﺮ ﺧــﺬ اﻟﻘﻴﻤــﺔ ﺻــﻔﺮا‪ .‬و ﻟﺘــﺎﱃ‬
‫ﻓﺈن اﻟﱪ ﻣﺞ ﺳﻴﻜﺘﺐ ‪ .x[2]=0‬أﻣﺎ اﳌﺘﻐﲑ ‪ y‬ﻓﻬﻮ ﻣﺘﺠﻪ ﻣﻜــﻮن ﻣــﻦ ﻋﻨﺼـﺮﻳﻦ ﻓﻘــﻂ ﺣﻴــﺚ أن ﻋــﺪد ﺧــﺎ ت اﳌﺘﺠــﻪ ﻗــﺪ ﻋــﺮف ﺑﺼــﻮرة‬
‫ﺿﻤﻨﻴﺔ اﺳــﺘﻨﺎدا ﻟﻌــﺪد اﻟﻘــﻴﻢ اﻻﺑﺘﺪاﺋﻴــﺔ ﰱ ﺳــﻄﺮ اﻷﻋــﻼن ﻋــﻦ اﳌﺘﻐــﲑ‪ .‬و ﻟﺘــﺎﱃ ﻓــﺄن اﻟﻌﻨﺼــﺮ ]‪ y[2‬ﻟــﻴﺲ ﻋﻨﺼـﺮا ﻣــﻦ ﻋﻨﺎﺻــﺮ اﳌﺘﺠــﻪ‪ .‬و‬
‫ﻟﻜــﻦ اﳊﺎﺳــﺐ ﻟــﻦ ﻳﻌﻄــﻰ رﺳــﺎﻟﺔ ﺧﻄــﺄ! إﻧــﻪ ﺳــﻴﻘﻮم ﻟﺒﺤــﺚ ﻋــﻦ اﻟﻘﻴﻤــﺔ اﳌﻮﺟــﻮدة ﰱ ﺧﺎﻧــﺔ اﻟــﺬاﻛﺮة اﻟــﱴ ﺗﻠــﻰ ﻣﺒﺎﺷــﺮة اﳋﺎﻧــﺔ اﻟﺜﺎﻧﻴــﺔ ﻣــﻦ‬
‫اﳌﺘﺠــﻪ‪ .‬ﻗــﺪ ﻳﻜــﻮن ﻫﻨــﺎك ﻣﺘﻐــﲑ آﺧــﺮ أو أﻣ ـﺮا ﻣــﻦ أواﻣــﺮ ﺑــﺮ ﻣﺞ أو أﻳــﺔ ﻣﻌﻠﻮﻣــﺔ أﺧــﺮى ﳐﺘﺰﻧــﺔ ﰱ ﻫــﺬﻩ اﳋﺎﻧــﺔ‪ .‬ﺳــﻴﻘﻮم اﳊﺎﺳــﺐ ﺑﻜﺘﺎﺑــﺔ‬
‫ﳏﺘﻮاﻫﺎ ﻛﻤﺎ ﻟﻮ ﻛﺎﻧﺖ ﺗﻌﱪ ﻋﻦ ﻋﺪد ﺣﻘﻴﻘﻰ‪.‬‬

‫‪.3‬أ‪ .5.‬اﳉﻤﻠﺔ ‪string‬‬

‫اﳉﻤﻞ ﻫﻰ ﳎﻤﻮﻋﺔ ﻣﻦ اﳊﺮوف‪ ،‬ﺗﻜﻮن ﲨﻠﺔ‪ ،‬ﻣﺮﺗﺒﺔ ﻛﻤﺎ ﻟﻮ ﻛﺎﻧﺖ ﻣﺘﺠﻪ ﻣﻦ اﳊــﺮوف‪ .‬و ﻟﻜــﻦ ﻫﻨــﺎك ﻓــﺎرق وﺣﻴــﺪ ﺑــﲔ اﳉﻤﻠــﺔ‬
‫و ﻣﺘﺠﻪ اﳊﺮوف‪ .‬ﻫــﺬا اﻟﻔــﺎرق ﻳﻜﻤــﻦ ﰱ وﺟــﻮد ﺣــﺮف ﺧــﺎص ﺑﻌــﺪ اﳊــﺮف اﻷﺧــﲑ ﻣــﻦ اﳉﻤﻠــﺔ ﻳﻨﺒﺌﻨــﺎ ﺑﻨﻬﺎﻳــﺔ اﳉﻤﻠــﺔ‪ .‬ﻓــﺈذا ﻋﺮﻓﻨــﺎ اﳉﻤﻠــﺔ‬
‫اﻵﺗﻴﺔ‪:‬‬
‫;]‪char name[20‬‬
‫ﰒ ﻛﺘﺒﻨﺎ ﻓﻴﻬﺎ اﶈﺘﻮى "‪ "Ahmed Aly‬و ذﻟﻚ ﺳﺘﺨﺪام اﻟﺪاﻟﺔ ) (‪ strcpy‬ﻛﺎﻟﺘﺎﱃ‪:‬‬
‫;)"‪strcpy(name,"Ahmed Aly‬‬
‫ﻓــﺈن ]‪ name[0‬ﲢــﻮى اﳊــﺮف '‪ 'A‬ﺑﻴﻨﻤــﺎ ]‪ name[1‬ﲢــﻮى اﳊــﺮف '‪ 'h‬و ﻫﻜــﺬا إﱃ أن ﻧﺼــﻞ إﱃ ]‪ name[8‬اﻟــﱴ ﲢــﻮى اﳊــﺮف‬
‫اﻷﺧــﲑ '‪ .'y‬أﻣــﺎ ]‪ name[9‬ﻓﻬــﻰ ﲢــﻮى اﳊــﺮف اﳋــﺎص '‪ .'\0‬و اﻟــﺬى ﻳﻌــﲎ ﺎﻳــﺔ اﳉﻤﻠــﺔ‪ .‬اﳋــﺎ ت اﻟﺘﺎﻟﻴــﺔ ﲢــﻮى ﺣﺮوﻓــﺎ ﻻ ﻳﻠﺘﻔــﺖ‬

‫‪38‬‬
‫إﻟﻴﻬﺎ‪ .‬ﻳﻼﺣﻆ أن داﻟﺔ ) (‪ strcpy‬ﻳﺘﻢ اﻹﻋــﻼن ﻋﻨﻬــﺎ ﰱ اﳌﻠــﻒ >‪ <string.h‬اﻟــﺬى ﳛــﻮى أﻳﻀــﺎ ﻋــﺪد ﻣــﻦ اﻟــﺪوال اﳋﺎﺻــﺔ ﻟﺘﻌﺎﻣــﻞ‬
‫ﻣــﻊ اﳉﻤــﻞ‪ .‬ﳚــﺐ إﺿــﺎﻓﺘﻪ ﻗﺒــﻞ ﻃﻠــﺐ اﺳــﺘﺨﺪام ﻫــﺬﻩ اﻟﺪاﻟــﺔ‪ .‬ﳝﻜــﻦ أﻳﻀــﺎ إﻋﻄــﺎء ﻗﻴﻤــﺔ اﺑﺘﺪاﺋﻴــﺔ ﻟﻠﺠﻤﻠــﺔ ﻋﻨــﺪ اﳊﺠــﺰ و ﺑــﺬﻟﻚ ﳜﺘﺼــﺮ‬
‫اﻷﻣﺮان اﻟﺴﺎﺑﻘﺎن إﱃ‪:‬‬
‫;"‪char name[20] = "Ahmed Aly‬‬
‫أﻣﺎ إذا أﻏﻔﻠﻨﺎ وﺿﻊ ﻋﺪد اﳊﺮوف اﻹﲨﺎﱃ داﺧﻞ اﻷﻗﻮاس اﳌﺮﺑﻌﺔ ﻣﺜﻞ‪:‬‬
‫;"‪char name[ ] = "Mohamed‬‬
‫ﻓﺴ ــﻴﺘﻢ ﺣﺠ ــﺰ ﻋ ــﺪد ‪ 8‬ﺣ ــﺮوف‪ ،‬ﺗﺴ ــﺘﺨﺪم اﻷﺣــﺮف اﻟﺴ ــﺒﻌﺔ اﻷوﱃ ﻟﻜﺘﺎﺑ ــﺔ ﻛﻠﻤ ــﺔ ‪ Mohamed‬ﰒ ﻳﻮﺿــﻊ اﳊ ــﺮف اﳋ ــﺎص '‪ '\0‬ﺑﻌ ــﺪ‬
‫ذﻟﻚ‪ .‬أى أن ]‪ name[0‬ﳛﻮى '‪ 'M‬و ]‪ name[6‬ﳛﻮى '‪ 'd‬أﻣﺎ ]‪ name[7‬ﻓﻬﻮ ﳛﻮى '‪.'\0‬‬

‫ﺑﻘﻰ أن ﻧﻨﻮﻩ ﻋﻦ اﻷﻣﺮ ‪ .typedef‬ﻳﺴﺘﺨﺪم ﻫﺬا اﻷﻣﺮ ﻟﺘﻌﺮﻳﻒ ﻧﻮع ﺟﺪﻳﺪ ﻣﻦ اﻟﺒﻴﺎ ت‪ ،‬ﻋﺎدة ﻣﺎ ﻳﻜﻮن ﻧﻮﻋﺎ ﻣﺮﻛﺒﺎ ﲝﻴــﺚ‬
‫ﳝﻜﻦ اﺳﺘﺨﺪاﻣﻪ ﺑﻌﺪ ذﻟﻚ ﰱ اﻟﱪ ﻣﺞ ﻣﺜﻞ أى ﻧﻮع آﺧﺮ ﻗﻴﺎﺳﻰ‪ .‬ﻓﻤﺜﻼ‪:‬‬
‫;]‪typedef double mat[5][5‬‬
‫;‪mat A, B, C‬‬
‫;]‪double A[5][5], B[5][5], C[5][5‬‬ ‫ﺗﻜﺎﻓﺊ ﲤﺎﻣﺎ‪:‬‬
‫ﻳﻮﺿــﻊ ﻫــﺬا اﻷﻣــﺮ ﻋــﺎدة ﰱ ﺑﺪاﻳــﺔ اﻟــﱪ ﻣﺞ ﺑﻌــﺪ أواﻣــﺮ إﺿــﺎﻓﺔ اﳌﻠﻔــﺎت و ﻗﺒــﻞ اﻹﻋــﻼن ﻋــﻦ أى داﻟــﺔ ﺣــﱴ ﳝﻜــﻦ اﺳــﺘﺨﺪاﻣﻪ ﰱ ﲨﻴــﻊ‬
‫اﻟﺪوال اﻟﱴ ﺳﺘﻠﻴﻪ‪ .‬اﻟﻘﺎﻋﺪة ﰱ ﻛﺘﺎﺑﺘﻪ ﺑﺴﻴﻄﺔ‪ .‬ﻳﻜﺘﺐ اﻷﻣﺮ أوﻻ ﻛﻤﺎ ﻟﻮ ﻛﻨﺎ ﻧﺮﻳﺪ ﺗﻌﺮﻳﻒ ﻣﺘﻐﲑ‪ ،‬ﰒ ﻧﺒــﺪل اﺳــﻢ اﳌﺘﻐــﲑ ﺳــﻢ ﻧــﻮع اﻟﺒﻴــﺎن‬
‫و ﻧﻀ ــﻴﻒ اﻟﻜﻠﻤ ــﺔ اﶈﺠ ــﻮزة ‪ typedef‬ﰱ ﺑﺪاﻳﺘ ــﻪ‪ .‬ﳝﻜ ــﻦ أﻳﻀ ــﺎ أن ﻳﺴ ــﺘﺨﺪم ﻟﺘﻌﺮﻳ ــﻒ ﺑﻴ ــﺎ ت ﺑﺴ ــﻴﻄﺔ و إن ﻛﺎﻧ ــﺖ ﻓﺎﺋﺪﺗ ــﻪ ﳏ ــﺪودة‬
‫ﻋﻨﺪﺋﺬ‪:‬‬
‫;‪typedef long my_type‬‬
‫;‪my_type n‬‬
‫;‪long n‬‬ ‫و اﻟﱴ ﺗﻜﺎﻓﺊ‪:‬‬
‫ﲤﺮﻳﻦ‪:‬‬
‫اﻟﱪ ﻣﺞ اﻟﺘﺎﱃ ﺑﻪ اﻟﻌﺪﻳﺪ ﻣﻦ اﻷﺧﻄﺎء‪ ،‬ﺑﺮﺟﺎء اﻛﺘﺸﺎﻓﻬﺎ‪ ،‬و اﻹﺟﺎﺑﺔ ﻋﻠﻰ اﻷﺳﺌﻠﺔ اﻟﻮاردة ﺑﺪاﺧﻞ ﺗﻌﻠﻴﻘﺎت ﻓﻴﻪ‪.‬‬
‫>‪# include <stdio.h‬‬
‫>‪#include <math.h> #include <string.h‬‬
‫‪#define PI 3.14159‬‬
‫‪#define 2PI 6.28318‬‬
‫;‪#define QElEC 1.6e-19‬‬

‫)‪int fun1(double x‬‬


‫{‬
‫;‪return (int) x‬‬
‫}‬

‫)‪double fun1(double x‬‬


‫{‬
‫;‪return x*x‬‬
‫}‬

‫)‪int fun2(char a‬‬

‫‪39‬‬
{
int n=1;
long fun3(long m)
{
return 2*m;
}
return a-fun3(n);
}
char a='b';

void Main (void)


{
/* This is a comment /* Is this also?
*/ How about this part? */
int var1, _var2, $var3, var4var5;
double xx, y(y, static, verylongnameofavariable;
char st[] = 'is this a valid string?';
char ch=`x`;
char a='c';
{
char a='d';
printf ("a=%c\n",a);/*What will be printed?*/
}
printf ("a=%c\n",a);/*What will be printed?*/
}
void anyfun()
{
printf ("a=%c\n",a);/*What will be printed?*/
}

40
‫اﻟﺘﻌﺒﲑات & ‪Assignement statement‬‬ ‫‪.3‬ب‪ .‬أﻣﺮ اﻹﺳﻨﺎد و‬
‫‪expressions‬‬

‫‪.3‬ب‪ .1.‬اﻟﺼﻮرة اﻟﻌﺎﻣﺔ‪General form :‬‬

‫ﻳﻮﺿﻊ أﻣﺮ اﻹﺳﻨﺎد ﻋﻠﻰ اﻟﺼﻮرة اﻟﻌﺎﻣﺔ‪:‬‬


‫;‪variable assignment expression‬‬
‫و ﻫــﻮ ﻳــﺆدى أوﻻ ﳊﺴــﺎب ﻗﻴﻤــﺔ اﻟﺘﻌﺒــﲑ ‪ expression‬ﰒ إﺳــﻨﺎد ﺗﻠــﻚ اﻟﻘﻴﻤــﺔ اﻟــﱴ ﳓﺴــﺒﻬﺎ ﻟﻠﻤﺘﻐــﲑ ‪ .variable‬أﻣــﺎ ‪assignment‬‬
‫ﻓﱰﻣﺰ ﻟﻨﻮع اﻹﺳﻨﺎد‪ ،‬أﻧﻈﺮ ﻓﻴﻤﺎ ﺑﻌﺪ‪ .‬ﻛﻤﺜﺎل ﻷﻣﺮ اﻹﺳﻨﺎد‪:‬‬
‫;)‪x = a + 3*sin(b‬‬
‫;)‪accept = (error < 1.0e-6‬‬
‫ﰱ اﳌﺜﺎل اﻷول ﳓﺴﺐ اﻟﺘﻌﺒﲑ اﻟﻌﺪدى ﻋﻠﻰ اﻟﻴﻤﲔ ﰒ ﻧﺴﻨﺪ اﻟﻨﺎﺗﺞ ﻟﻠﻤﺘﻐﲑ ‪ .x‬أﻣﺎ ﰱ اﳌﺜﺎل اﻟﺜﺎﱏ ﻓــﺈن اﻟﺘﻌﺒــﲑ اﳌﻨﻄﻘــﻰ ﳝﻜــﻦ أن ﻳﻨــﺘﺞ‬
‫ﻋﻨﻪ إﻣﺎ اﻟﻘﻴﻤﺔ ﺧﻄﺄ )اﻟﻘﻴﻤﺔ ‪ (0‬أو اﻟﻘﻴﻤﺔ ﺻﻮاب )اﻟﻘﻴﻤﺔ ‪ (1‬و ﻫﻰ اﻟﻘﻴﻤﺔ اﻟﱴ ﺳﺘﺴﻨﺪ ﻟﻠﻤﺘﻐــﲑ ‪ .accept‬ﳚــﺐ أن ﻳﻔﻬــﻢ ﺟﻴــﺪا أن‬
‫ﻫﺬا اﻷﻣﺮ ﻟﻴﺲ ﻣﻌﺎدﻟﺔ ﻳﺘﺴــﺎوى ﻓﻴﻬــﺎ اﻟﻄــﺮف اﻷﳝــﻦ ﻣــﻊ اﻟﻄــﺮف اﻷﻳﺴــﺮ‪ ،‬ﻛﻤــﺎ ﺗــﻮﺣﻰ ﻋﻼﻣــﺔ اﻟﺘﺴــﺎوى "="‪ ،‬و ﻟﻜﻨــﻪ ﻟــﻴﺲ إﻻ وﺳــﻴﻠﺔ‬
‫ﻟﻮﺿــﻊ ﻗﻴﻤــﺔ ﳏﺴــﻮﺑﺔ ﰱ ﻣﺘﻐــﲑ‪ .‬و ﻋﻠــﻰ ذﻟــﻚ ﻓــﺈن اﻷﻣــﺮ‪ i = i + 1 :‬ﻣــﺜﻼ ﻫــﻮ أﻣــﺮ ﺻــﺤﻴﺢ‪ .‬واﺿــﺢ ﲤﺎﻣــﺎ أﻧــﻪ ﻟــﻴﺲ ﻣﻌﺎدﻟــﺔ و ﻟﻜﻨــﻪ‬
‫ﻳﻌﲎ أن ﻧﻀﻊ ﰱ اﳌﺘﻐﲑ ‪ i‬ﻗﻴﻤﺔ ﺟﺪﻳﺪة و ﻫﻰ ﻗﻴﻤﺔ ‪ i‬اﻟﻘﺪﳝﺔ زاﺋﺪ واﺣﺪ‪ .‬ﻟﻨﻔﺲ اﻟﺴــﺒﺐ ﻣــﻦ اﻟﺴــﻬﻞ أن ﻧﻔﻬــﻢ ﳌــﺎذا ﻻ ﳝﻜــﻦ أن ﻳﻈﻬــﺮ‬
‫ﺗﻌﺒﲑ ﻋﻠﻰ ﻳﺴﺎر ﻋﻼﻣﺔ اﻟﺘﺴﺎوى‪:‬‬
‫‪x + 3 = y - 5 /* a wrong statement */ .‬‬

‫ﺗﺘﻜــﻮن اﻟﺘﻌﺒـﲑات ﻣــﻦ ﺛﻮاﺑــﺖ )ﻣﺜــﻞ اﻟــﺮﻗﻢ ‪ 3‬ﰱ اﳌﺜــﺎل اﻷول أﻋــﻼﻩ و ‪ 1.0e-6‬ﰱ اﳌﺜــﺎل اﻟﺜــﺎﱏ( و ﻣﺘﻐـﲑات )ﻣﺜــﻞ ‪a, b,‬‬
‫‪error‬ﰱ ﻧﻔﺲ اﻷﻣﺜﻠﺔ( و دوال )ﻣﺜــﻞ داﻟــﺔ ‪ (sin‬و ﻣــﺆﺛﺮات ‪ operators‬ﺗﻌــﱪ ﻋــﻦ اﻟﻌﻼﻗــﺎت اﳊﺴــﺎﺑﻴﺔ أو اﳌﻨﻄﻘﻴــﺔ )ﻣﺜــﻞ ‪ +‬و * و‬
‫<(‪ .‬ﲣﺘﻠﻒ ﺑﺬﻟﻚ اﻟﺘﻌﺒﲑات ﺗﺒﻌﺎ ﻟﻨﻮع اﻟﺒﻴﺎ ت و اﳌﺆﺛﺮات اﻟﱴ ﺗﺘﻜﻮن ﻣﻨﻬﺎ‪ .‬ﺳﻨﺪرس اﳌﺆﺛﺮات اﻟﱴ ﺗﻈﻬﺮ ﰱ اﻟﻌﻤﻠﻴــﺎت اﳌﺨﺘﻠﻔــﺔ ﺗﺒﻌــﺎ‬
‫ﻟﻨﻮع اﻟﻌﻤﻠﻴﺔ ﺳﻮاء ﻛﺎﻧﺖ ﺣﺴﺎﺑﻴﺔ أو ﻣﻨﻄﻘﻴﺔ أو ﲡﺮى ﻋﻠﻰ ﺑﻴﺖ‪ ،‬ﻣﺮﺟﺌﲔ اﻟﻌﻤﻠﻴﺎت ﻋﻠﻰ اﳌﺆﺷﺮات ﻟﻠﺒﺎب اﳋﺎص ﺎ‪.‬‬

‫‪.3‬ب‪ .2.‬اﻟﻌﻤﻠﻴﺎت اﳊﺴﺎﺑﻴﺔ ‪Arithmetic operations‬‬


‫اﳌﻘﺼﻮد ﺑﺬﻟﻚ اﻟﻌﻤﻠﻴﺎت اﻟﱴ ﲡﺮى ﻋﻠﻰ اﻟﺒﻴﺎ ت اﻟﻌﺪدﻳﺔ‪ .‬اﳌﺆﺛﺮات اﻟﱴ ﺗﻈﻬﺮ ﻓﻴﻬــﺎ ﺗﻨﻘﺴــﻢ أﺳﺎﺳــﺎ ﳌــﺆﺛﺮات أﺣﺎدﻳــﺔ ‪unary‬‬
‫‪) operators‬أى ﺗﺆﺛﺮ ﻋﻠﻰ ﻣﻌﺎﻣﻞ ‪ operand‬واﺣﺪ( و ﻣــﺆﺛﺮات ﺛﻨﺎﺋﻴــﺔ ‪) binary operators‬أى ﺗــﺆﺛﺮ ﻋﻠــﻰ ﻣﻌــﺎﻣﻠﲔ(‪ .‬اﳌــﺆﺛﺮات‬
‫اﻷﺣﺎدﻳﺔ ﺗﺸﻤﻞ أوﻻ اﻟﻌﻼﻣﺎت ‪ +‬و ‪ -‬و ﻫﻰ ﺗﻌﲎ ﻣﻮﺟﺐ أو ﺳــﺎﻟﺐ اﻟﻜﻤﻴــﺔ اﻟــﱴ ﺗــﺆﺛﺮ ﻋﻠﻴﻬــﺎ ﻣﺜــﻞ‪ +3 ,-5 :‬ﻛﻤــﺎ ﻫــﻮ ﻣﺘﻮﻗــﻊ‪ .‬ﻫﻨــﺎك‬
‫أﻳﻀﺎ ﻣﺆﺛﺮات اﻟﺰ دة ‪ Increment ++‬و اﻹﻧﻘﺎص ‪ Decrement --‬اﻟﱴ ﺳﻨﺘﻌﺮض ﳍﺎ ﺑﻌﺪ ﻗﻠﻴﻞ‪.‬‬

‫اﳌﺆﺛﺮات اﻟﺜﻨﺎﺋﻴﺔ ﺗﺸﻤﻞ اﳌﺆﺛﺮات اﳉﻤﻌﻴﺔ ‪ additive‬ﻣﺜــﻞ ‪ +‬و ‪ -‬و اﳌــﺆﺛﺮات اﻟﻀـﺮﺑﻴﺔ ‪ multiplicative‬ﻣﺜــﻞ * و ‪ /‬و ‪.%‬‬
‫ﻛﻞ ﻫﺬﻩ اﳌﺆﺛﺮات ﳝﻜﻦ أن ﺗﺆﺛﺮ ﻋﻠﻰ أﻋﺪاد ﺻﺤﻴﺤﺔ أو ﺣﻘﻴﻘﻴﺔ ﻣﺎ ﻋﺪا اﳌــﺆﺛﺮ اﻷﺧــﲑ ‪ %‬اﻟــﺬى ﻳﺸــﱰط وﺟــﻮد ﻋــﺪدﻳﻦ ﺻــﺤﻴﺤﲔ و‬
‫ﻳﺆدى ﳊﺴﺎب ﻗﻰ ‪ remainder‬ﻗﺴﻤﺔ اﻟﻌﺪد اﻷﻳﺴﺮ ﻋﻠﻰ اﻟﻌﺪد اﻷﳝــﻦ‪ .‬ﻣــﺜﻼ‪ 10 % 3 :‬ﺗﻌﻄــﻰ اﻟﻨــﺎﺗﺞ ‪ .1‬ﻟﻨﺴــﺒﺔ ﳌــﺆﺛﺮ اﻟﻘﺴــﻤﺔ‬
‫ﻓﺈﻧــﻪ ﻳﻌﻤــﻞ ﻟﺼــﻮرة اﻟﻌﺎدﻳــﺔ اﳌﺘﻮﻗﻌــﺔ إذا أﺛــﺮ ﻋﻠــﻰ ﻋــﺪدﻳﻦ أﺣــﺪﳘﺎ ﻋﻠــﻰ اﻷﻗــﻞ ﺣﻘﻴﻘــﻰ‪ .‬أﻣــﺎ إذا ﻛــﺎن اﻟﻌــﺪدان ﺻــﺤﻴﺤﲔ ﻓﺈﻧــﻪ ﻳﻌﻄــﻰ‬

‫‪41‬‬
‫ﺧــﺎرج اﻟﻘﺴــﻤﺔ اﻟﺼــﺤﻴﺤﺔ ‪ integer division‬أى أن ‪ 10.0 / 3‬ﻳﻌﻄــﻰ ‪ 3.333333‬ﺑﻴﻨﻤــﺎ ‪ 10/3‬ﻳﻌﻄــﻰ اﻟﻨــﺎﺗﺞ ‪ .3‬و ﻟــﺬا‬
‫ﻓﻴﺠــﺐ اﳊــﺬر اﻟﺸــﺪﻳﺪ ﻋﻨــﺪ اﺳــﺘﻌﻤﺎل ﻫــﺬا اﳌــﺆﺛﺮ ﻟﻴﻨــﺘﺞ ﻣــﺎ ﻧﺮﻳــﺪﻩ ﻓﻌــﻼ‪ .‬ﻻﺣــﻆ أن إﺷــﺎرة ﺗــﺞ ﻋﻤﻠﻴــﺔ ‪ %‬ﻫــﻰ ﻧﻔــﺲ إﺷــﺎرة اﳌﻌﺎﻣــﻞ‬
‫اﻷﻳﺴﺮ و ذﻟﻚ ﻟﻀﻤﺎن ﺻﺤﺔ اﻟﻌﻼﻗﺔ اﻟﺘﺎﻟﻴﺔ ﰱ ﲨﻴﻊ اﻟﻈﺮوف )ﻃﺎﳌﺎ ﻛﺎﻧﺖ اﳌﺘﻐﲑات ‪ a,b‬ﺻﺤﻴﺤﺔ(‪:‬‬
‫‪a = (a / b) * b + a % b‬‬

‫ﻟﻨﺴﺒﺔ ﳉﻤﻴﻊ اﳌــﺆﺛﺮات اﻟﺜﻨﺎﺋﻴــﺔ‪ ،‬إذا ﻛــﺎن اﳌﻌــﺎﻣﻼن ﺑــﻨﻔﺲ اﻟﻨــﻮع )ﻛﻼﳘــﺎ ‪ int‬ﻣــﺜﻼ( ﻓــﺈن اﻟﻨــﺎﺗﺞ ﻳﻜــﻮن ﻋﻠــﻰ ﻧﻔــﺲ اﻟﻨــﻮع‪ .‬أﻣــﺎ‬
‫إذا اﺧﺘﻠﻒ ﻧﻮع اﳌﻌﺎﻣﻠﲔ ﻓﻴﻜﻮن اﻟﻨﺎﺗﺞ داﺋﻤﺎ ﻋﻠﻰ اﻟﻨــﻮع اﻟــﺬى ﻳﺘــﻴﺢ أﻛــﱪ ﻣــﺪى ﻟﻀــﻤﺎن ﲤﺜﻴــﻞ ﻧﺘﻴﺠــﺔ اﻟﻌﻤﻠﻴــﺔ ﺑﺼــﻮرة ﺻــﺤﻴﺤﺔ ‪ .‬ﻫــﻮ‬
‫ﻣﺎ ﻳﺴﻤﻰ ﺑﻘﺎﻋﺪة اﻟﱰﻗﻴﺔ ‪ .promotion‬ﻓﺈذا ﲨﻊ ‪ char‬ﻣﻊ ‪ int‬ﻳﻜﻮن اﻟﻨﺎﺗﺞ ‪ .int‬و إذا ﲨﻊ ‪ int‬ﻣــﻊ ‪ long‬ﻳﻜــﻮن اﻟﻨــﺎﺗﺞ ‪long‬‬
‫و ﻫﻜــﺬا‪ .‬ﻧﻔــﺲ اﻟﻘﻮاﻋــﺪ ﺗﺘﺒــﻊ ﻣــﻊ اﻷﻋــﺪاد اﳊﻘﻴﻘــﺔ ﻓﻴــﺘﻢ ﺗﺮﻗﻴــﺔ ‪ float‬إﱃ ‪ double‬و ﳌﺜــﻞ ‪ double‬إﱃ ‪ long double‬ﺗﺒﻌــﺎ‬
‫ﻟﻠﻤﻌﺎﻣﻞ ذى اﳌﺪى اﻷﻛﱪ اﳌﺴﺘﺨﺪم‪ .‬أﻣﺎ إذا ﻇﻬﺮ أى ﺑﻴﺎن ﻣﻦ ﻧﻮع ﺻﺤﻴﺢ ﻣﻊ أى ﺑﻴﺎن ﻣﻦ ﻧﻮع ﺣﻘﻴﻘﻰ ﻓﻴﻜﻮن اﻟﻨــﺎﺗﺞ داﺋﻤــﺎ ﻋﻠــﻰ‬
‫ﻧﻔــﺲ ﻧــﻮع اﻟﺒﻴــﺎن اﳊﻘﻴﻘــﻰ‪ .‬ﻣــﺎذا ﳛــﺪث إذا ﻛﺎﻧــﺖ ﻗﻴﻤــﺔ اﻟﻨــﺎﺗﺞ ﻻ ﺗــﺪﺧﻞ ﺿــﻤﻦ ﻧﻄــﺎق اﳌــﺪى اﳌﺴــﻤﻮح ﻟﻨــﻮع اﻟﻨــﺎﺗﺞ؟ ﻣــﺜﻼ ﻧﻌﻠــﻢ أن‬
‫اﻷﻋﺪاد ﻣﻦ ﻧﻮع ‪ float‬ﻳﱰاوح ﻣﺪاﻫﺎ ﻣﻦ ‪ 3.4e-38‬إﱃ ‪ 3.4e+38‬ﻣﺎذا ﺳﻴﺤﺪث ﻟﻮ ﻗﻤﻨﺎ ﻟﻌﻤﻠﻴﺎت‪:‬‬
‫;‪float x,y; x=1.0e30; y=x*x‬‬
‫ﰱ ﺣﺎﻟــﺔ اﻷﻋــﺪاد اﳊﻘﻴﻘــﺔ اﺗﻔــﻖ ﻋﻠــﻰ أن ﻳﺘﻮﻗــﻒ اﻟــﱪ ﻣﺞ ﻋــﻦ اﻟﻌﻤــﻞ ﻣﺼــﺪرا رﺳــﺎﻟﺔ ﺧﻄــﺄ ﲰﻴــﺖ ‪ .overflow‬ﻗــﺪ ﻳﺒــﺪو ﻣــﺎ ﺳــﻴﻠﻰ‬
‫ﻏﺮﻳﺒــﺎ و ﻟﻜﻨــﻪ ﱂ ﻳﺘﻔــﻖ ﻋﻠــﻰ أﺳــﻠﻮب ﻣﻮﺣــﺪ ﳌﻌﺎﳉــﺔ ﺣﺎﻟــﺔ اﳋــﺮوج ﻋــﻦ اﳌــﺪى ﻟﻸﻋــﺪاد اﻟﺼــﺤﻴﺤﺔ‪ .‬أﻏﻠﺒﻴــﺔ اﳌﱰﲨــﺎت ﺳــﺘﺆدى ﻻﺳــﺘﻤﺮار‬
‫اﻟﻌﻤــﻞ ﺑــﺪون أﻳــﺔ رﺳــﺎﻟﺔ ﻟﻠﻤﺴــﺘﺨﺪم ﻣــﻊ اﻻﺣﺘﻔــﺎظ ﻟﻘﻴﻤــﺔ اﳌﻮﺟــﻮدة ﰱ اﳉــﺰء اﻷول ﻣــﻦ اﻟﻌــﺪد اﻟﺜﻨــﺎﺋﻰ‪ ،‬أى اﳉــﺰء اﻟــﺬى ﳛــﻮى اﻷرﻗــﺎم‬
‫اﻟﺜﻨﺎﺋﻴــﺔ ذات اﻟــﻮزن اﻟﺼــﻐﲑ ‪ .least significant bits‬ﻛﻤﺜــﺎل ﺗﻮﺿــﻴﺤﻰ‪ ،‬إذا ﻛــﺎن ﻟــﺪﻳﻨﺎ ﻋــﺪدا ﻣــﻦ ﻧــﻮع ‪ unsigned char‬ﻓــﺈن‬
‫أﻛ ـ ــﱪ ﻋ ـ ــﺪد ﳝﻜ ـ ــﻦ أن ﻳﺴ ـ ــﺘﻮﻋﺒﻪ ﻫ ـ ــﻮ ‪ 111111112‬أى ﻣ ـ ــﺎ ﻳﻨ ـ ــﺎﻇﺮ ‪ .25510‬إذا أﺿ ـ ــﻴﻒ ﻟ ـ ــﻪ اﻟـ ــﺮﻗﻢ ‪ 1‬ﻓﺎﻟﻨﺘﻴﺠ ـ ــﺔ اﳌﻨﻄﻘﻴـ ــﺔ ﻫ ـ ــﻰ‬
‫‪ 1000000002‬و ﻟﻜﻦ ذﻟﻚ ﳛﺘﺎج إﱃ ‪ 9‬ﺑﻴﺖ ﻟﻠﺘﺨﺰﻳﻦ و ﱂ ﳓﺠﺰ ﻟﻠﻌﺪد ﺳﻮى ‪ 8‬ﺑﻴــﺖ‪ .‬ﻧﺘﻴﺠــﺔ ﻟــﺬﻟﻚ ﻓﺴــﻮف ﳓــﺘﻔﻆ ﻷرﻗــﺎم‬
‫اﻟﺜﻤﺎﻧﻴــﺔ اﻷوﱃ ﻋﻠــﻰ اﻟﻴﻤــﲔ ﻟﻜــﻰ ﻳﺼــﺒﺢ اﻟﻨــﺎﺗﺞ ‪ 000000002‬أى ﺻــﻔﺮا ﺑــﺪﻻ ﻣــﻦ ‪ .25610‬ﻣــﻦ اﳌﻤﻜــﻦ أن ﻳﻜــﻮن ذﻟــﻚ ﻣﻔﻴــﺪا‬
‫ﻟﻠﻤــﱪﻣﺞ ﰱ ﺣــﺎﻻت ﺧﺎﺻــﺔ و ﻟﻜــﻦ ﻻ ﳚــﺐ أن ﻧﻌﺘﻤــﺪ ﻋﻠــﻰ ذﻟــﻚ ﰱ ﻛﺘﺎﺑــﺔ اﻟــﱪ ﻣﺞ ﻟﻜــﻰ ﺗﻜــﻮن اﻟ ـﱪاﻣﺞ اﻟــﱴ ﻧﻜﺘﺒﻬــﺎ ﻗﺎﺑﻠــﺔ ﻟﻠﻨﻘــﻞ‬
‫‪ portable‬ﻣﻦ ﻧﻈﺎم ﻵﺧﺮ‪.‬‬
‫ﻧﻔــﺲ اﳌﺸــﻜﻠﺔ ﺗﻈﻬــﺮ ﻋﻨــﺪ إﺳــﻨﺎد ﻧﺘﻴﺠــﺔ ﺗﻌﺒــﲑ ﻣــﻦ ﻧــﻮع ﻣــﺎ إﱃ ﻣﺘﻐــﲑ ﻣــﻦ ﻧــﻮع آﺧــﺮ‪ .‬ﻓــﺈذا ﻛــﺎن ﻧــﻮع اﳌﺘﻐــﲑ اﻟــﺬى ﺳــﻴﺘﻠﻘﻰ‬
‫اﻟﻨﺘﻴﺠﺔ ﻣﺪاﻩ أﻛﱪ ﻣﻦ ﻣﺪى اﻟﺘﻐﲑ اﳌﻨﺎﻇﺮ ﻟﻨﻮع اﻟﺘﻌﺒﲑ ﻓﻠــﻦ ﺗﻜــﻮن ﻫﻨــﺎك ﻣﺸــﻜﻠﺔ‪ .‬أﻣــﺎ ﰱ اﳊﺎﻟــﺔ اﻟﻌﻜﺴــﻴﺔ ﻓﺴــﺘﺤﺪث رﺳــﺎﻟﺔ ﺧﻄــﺄ ﻣــﻦ‬
‫ﻧﻮع ‪ overflow‬ﰱ ﺣﺎﻟﺔ اﳌﺘﻐﲑات اﳊﻘﻴﻘﺔ إذا ﻛﺎن اﻟﻨﺎﺗﺞ ﻻ ﳝﻜﻦ وﺿﻌﻪ ﰱ اﳌﺘﻐﲑ اﳌﺘﻠﻘﻰ‪ .‬أﻣﺎ ﰱ ﺣﺎﻟﺔ اﻷﻋﺪاد اﻟﺼــﺤﻴﺤﺔ ﻓــﺈن رد‬
‫اﻟﻔﻌﻞ ﻳﻌﺘﻤﺪ ﻋﻠﻰ اﳌﱰﺟﻢ‪ .‬ﳝﻜﻦ أﻳﻀﺎ ﲢﻮﻳﻞ ﻧﻮع ﺗﺞ ﻣﺎ ﻟﻨﻮع آﺧﺮ ﺑﺼﻮرة ﺻــﺮﳛﺔ وﻫــﻮ ﻣــﺎ ﻳﺴــﻤﻰ ﺑﻌﻤﻠﻴــﺔ إﻋــﺎدة ﻗﻮﻟﺒــﺔ اﻟﻨــﻮع ‪type‬‬
‫‪ .casting‬إذا ﺳﺒﻖ أى ﺗﻌﺒﲑ اﺳــﻢ ﻟﻨــﻮع ﻣــﻦ اﻟﺒﻴــﺎ ت ﺑــﲔ ﻗﻮﺳــﲔ ﻓــﺈن ﻗﻴﻤــﺔ اﻟﺘﻌﺒــﲑ ﻳﻌــﺎد ﺻــﻴﺎﻏﺘﻬﺎ أو ﻗﻮﻟﺒﺘﻬــﺎ ﻟﺘﻨﺎﺳــﺐ ﻧــﻮع اﻟﺒﻴــﺎ ت‬
‫اﳉﺪﻳﺪ‪ .‬ﻣﺜﻼ‪:‬‬
‫‪(float) 5 gives 5.0 (int) 4.9‬‬ ‫‪gives‬‬ ‫‪4‬‬ ‫‪(int) -5.1 gives -5‬‬
‫ﻳﻼﺣﻆ أﻧﻪ ﻋﻨﺪ إﻋﺎدة ﻗﻮﻟﺒﺔ ﻋﺪد ﺣﻘﻴﻘﻰ ﻟﻌﺪد ﺻﺤﻴﺢ‪ ،‬ﻓــﺈن اﳉــﺰء اﻟﻜﺴــﺮى ﻣــﻦ اﻷﻋــﺪاد اﳊﻘﻴﻘــﺔ ﳜﺘﻔــﻰ ﻣﻬﻤــﺎ ﻛﺎﻧــﺖ ﻗﻴﻤﺘــﻪ و ﻳﺒﻘــﻰ‬
‫اﳉﺰء اﻟﺼﺤﻴﺢ‪ ،‬ﺳﻮاء ﻛﺎن اﻟﺮﻗﻢ ﻣﻮﺟﺒﺎ أو ﺳﺎﻟﺒﺎ‪ .‬أى أن اﻟﺘﺤﻮﻳﻞ ﻳــﺘﻢ داﺋﻤــﺎ ﰱ اﲡــﺎﻩ اﻟﺼــﻔﺮ‪ .‬ﻫﻨــﺎك أﻳﻀــﺎ دوال ﻣﻌﻠــﻦ ﻋﻨﻬــﺎ ﰱ اﳌﻠـﻒ‬
‫‪ math.h‬و ﺗﺴﻤﺢ ﺟﺮاء ﲢﻮﻳﻼت أﺧﺮى‪:‬‬
‫)‪ floor(x‬و ﻫﻰ ﺗﻌﻄﻰ أﻛﱪ ﻋﺪد ﺻﺤﻴﺢ ﻳﻘﻞ ﻋﻦ أو ﻳﺴﺎوى ﻗﻴﻤﺔ ‪x‬‬
‫)‪ ceil(x‬و ﻫﻰ ﺗﻌﻄﻰ أﺻﻐﺮ ﻋﺪد ﺻﺤﻴﺢ ﻳﺰﻳﺪ ﻋﻦ أو ﻳﺴﺎوى ﻗﻴﻤﺔ ‪x‬‬

‫‪42‬‬
‫)ﻣﻠﺤﻮﻇﺔ‪ :‬إذا أردت ﺣﺴﺎب أﻗﺮب ﻋﺪد ﺻﺤﻴﺢ ﻓﻴﻤﻜﻦ اﺳﺘﺨﺪام اﻟﻌﻤﻠﻴﺔ )‪(floor(x+0.5‬‬
‫ﺗﺴﺘﺨﺪم إﻋﺎدة اﻟﻘﻮﻟﺒﺔ ‪ casting‬ﻋﺎدة ﻟﻀﻤﺎن ﺣﺴﻦ ﺗﺮﲨﺔ أواﻣﺮ ﺗﺸﱰط وﺟﻮد ﻣﺘﻐﲑ ﻣﻦ ﻧﻮع ﳐﺎﻟﻒ ﻟﻠﻨﻮع اﻟﺬى ﻧﺮﻳﺪ أن‬
‫ﻧﺴﺘﺨﺪﻣﻪ ﻣﺜﻞ‪:‬‬
‫;‪float x; int j,k; j = (int) x % k‬‬
‫اﻷﻣﺮ اﻟﺴﺎﺑﻖ ﻛﺎن ﺳﻴﻌﻄﻰ رﺳﺎﻟﺔ ﺧﻄﺄ ﰱ اﻟﱰﲨﺔ إذا ﱂ ﻧﻜﻦ ﻗﺪ اﺳﺘﺨﺪﻣﻨﺎ )‪(int‬‬
‫اﳊــﺮص اﻟــﺬى ﳚــﺐ أن ﻧﺘﺒﻌــﻪ ﰱ ﻋﻤﻠﻴــﺔ اﻟﻘﺴــﻤﺔ ﻻ ﻳﻨﺤﺼــﺮ ﰱ ﲤﺤ ـﻴﺺ أﻧ ـﻮاع اﻟﺒﻴــﺎ ت ﻋﻠــﻰ ﺟــﺎﻧﱮ اﻟﻌﻤﻠﻴــﺔ و ﻟﻜــﻦ ﳝﺘــﺪ‬
‫ﻟﻴﺸﻤﻞ ﲤﺤﻴﺺ اﻟﻘﻴﻢ اﶈﺘﻤﻠﺔ ﻟﻠﻤﻘﺎم‪ .‬ﻳﻨﺒﻐﻰ اﻟﺘﺄﻛﺪ أﻧﻪ ﰱ ﲨﻴﻊ اﻷﺣﻮال ﻟﻦ ﻳﻜﻮن اﳌﻘﺎم ﺻﻔﺮا‪ .‬إذا ﻛﺎن ﻫﺬا اﻻﺣﺘﻤــﺎل واردا ﻓﻴﻨﺒﻐــﻰ‬
‫اﻟﻜﺸﻒ ﻋﻦ ﻫﺬﻩ اﳊﺎﻟﺔ ﻗﺒﻞ اﻟﻮﺻــﻮل ﻟﻌﻤﻠﻴــﺔ اﻟﻘﺴــﻤﺔ و ﻛﺘﺎﺑــﺔ ﺟــﺰء ﺧــﺎص ﰱ اﻟــﱪ ﻣﺞ ﳌﻌﺎﳉــﺔ ﻫــﺬﻩ اﳊﺎﻟــﺔ ﲟــﺎ ﻳﺘﻨﺎﺳــﺐ ﻣﻌﻬــﺎ‪ .‬ﻳﻨﻄﺒــﻖ‬
‫ﻫﺬا اﻟﻜﻼم ﻋﻠﻰ ﻛﺎﻓﺔ اﻟﻌﻤﻠﻴﺎت اﳊﺴﺎﺑﻴﺔ اﻟﱴ ﳝﻜﻦ أن ﺗﺼﺒﺢ ﻣﺴﺘﺤﻴﻠﺔ اﻟﺘﻨﻔﻴﺬ ﰱ ﺣــﺎﻻت ﻣــﺎ ﻣﺜــﻞ ﺣﺴــﺎب ﺟــﺬر أو ﻟﻮﻏــﺎرﻳﺘﻢ ﻋــﺪد‬
‫‪a * x*x +‬‬ ‫ﺳﺎﻟﺐ إﱃ آﺧﺮﻩ‪ .‬ﺳﻨﻮﺿﺢ ﻣﺎ ﻧﻌﻨﻴﻪ ﳌﺜﺎل اﻟﺘﺎﱃ و اﳌﻄﻠﻮب ﻓﻴﻪ ﺣﺴﺎب ﺟﺬور اﳌﻌﺎدﻟﺔ اﳉﱪﻳﺔ ﻣﻦ اﻟﺪرﺟﺔ اﻟﺜﺎﻧﻴﺔ‪:‬‬
‫‪b *x + c = 0‬‬
‫‪/* Bad program */‬‬
‫>‪#include <stdio.h‬‬
‫)‪void main(void‬‬
‫{‬
‫‪double a,b,c, /* Coefficients of the algebraic equation*/‬‬
‫‪x1, x2; /* Roots of the algebraic equation */‬‬
‫;)‪printf("Enter coefs. a, b, c : "); scanf ("%lg %lg %lg",&a, &b, &c‬‬
‫;)‪x1 = (-b + sqrt(b*b - 4.0 * a * c)) / (2.0*a‬‬
‫;)‪x2 = (-b - sqrt(b*b - 4.0 * a * c)) / (2.0*a‬‬
‫;)‪printf("\n roots are: %lg %lg\n",x1,x2‬‬
‫}‬
‫اﻟﱪ ﻣﺞ اﳌﻜﺘﻮب أﻋﻼﻩ ﻳﻌﺘﱪ أﳕﻮذﺟﺎ ﺳﻴﺌﺎ ﻟﻠﱪﳎﺔ ﻟﻌﺪة أﺳــﺒﺎب‪ .‬أوﻻ ﳝﻜــﻦ ﶈﺘــﻮى داﻟــﺔ اﳉــﺬر ) (‪ sqrt‬أن ﻳﻜــﻮن ﺳــﺎﻟﺒﺎ ﳑــﺎ ﺳــﻴﺆدى‬
‫ﳌﺸــﺎﻛﻞ ﻋﻨــﺪ اﻟﺘﻨﻔﻴــﺬ‪ .‬ﻛــﺎن ﳚــﺐ أن ﻧﻔﺤــﺺ أوﻻ ﻫــﺬﻩ اﳊﺎﻟــﺔ ﻗﺒــﻞ ﺣﺴــﺎب اﳉــﺬر و ﻧﻌﺎﳉﻬــﺎ ﻷﺳــﻠﻮب اﳌﻨﺎﺳــﺐ و ﻫــﻮ إﻋﻄــﺎء اﳉــﺰء‬
‫اﳊﻘﻴﻘﻰ و اﳉﺰء اﻟﺘﺨﻴﻠﻲ ﻣﻦ اﳉﺬرﻳﻦ اﳌﱰاﻓﻘﲔ‪ .‬ﻻﺣﻆ أﻳﻀــﺎ أن داﻟــﺔ اﳉــﺬر اﺳــﺘﺨﺪﻣﺖ ﻣـﺮﺗﲔ ﳊﺴــﺎب ﻧﻔــﺲ اﻟﺸــﻰء و ﻫــﻮ ﻣﻜﻠــﻒ‬
‫ﺑﻼ داﻋﻰ‪ .‬ﻛــﺎن ﳝﻜــﻦ أن ﻧﻀــﻊ ﺗــﺞ داﻟــﺔ اﳉــﺬر ﰱ ﻣﺘﻐــﲑ ﻣﺆﻗــﺖ و ﻧﺴــﺘﺨﺪﻣﻪ ﰱ اﳌﻌــﺎدﻻت ﺑﻌــﺪ ذﻟــﻚ ﻟﻨــﻮﻓﺮ وﻗــﺖ اﳊﺴــﺎب‪ .‬ﳝﻜــﻦ‬
‫ﺑﺪاﻳﺔ ﲢﺴﲔ اﻟﱪ ﻣﺞ ﻛﻤﺎ ﻳﻠﻰ‪:‬‬
‫‪/* Better program, but still poor */‬‬
‫>‪#include <stdio.h‬‬
‫)‪void main(void‬‬
‫{‬
‫‪double a,b,c, /* Coefficients of the algebraic equation*/‬‬
‫‪x1, x2, /* Roots of the algebraic equation */‬‬
‫;‪det‬‬ ‫‪/* temporary variable */‬‬
‫;)‪printf("Enter coefs. a, b, c : "); scanf ("%lg %lg %lg",&a, &b, &c‬‬
‫;‪det = b * b - 4.0 * a *c‬‬
‫)‪if (det >= 0‬‬
‫{‬
‫;)‪det = sqrt(det‬‬
‫;)‪x1 = (-b + det) / (2.0*a‬‬
‫;)‪x2 = (-b - det) / (2.0*a‬‬
‫;)‪printf("\n roots are: %lg %lg\n",x1,x2‬‬
‫‪} else‬‬

‫‪43‬‬
‫{‬
‫;)‪det = sqrt(-det‬‬
‫;)‪x1 = -b/(2.0*a‬‬
‫;)‪x2 = det / (2.0*a‬‬
‫;)‪printf("\n complex roots: %lg + or - j* %lg\n",x1,x2‬‬
‫}‬
‫}‬
‫ﻣــﺎ زاﻟــﺖ ﻫﻨــﺎك ﺑﻌــﺾ اﳌﺸــﺎﻛﻞ ﰱ اﻟــﱪ ﻣﺞ اﻟﺴــﺎﺑﻖ و ﻫــﻰ اﳋﺎﺻــﺔ ﺑﻌﻤﻠﻴــﺔ اﻟﻘﺴــﻤﺔ‪ .‬ﻣــﺎ اﻟــﺬى ﻳﻀــﻤﻦ أن ﺗﻜــﻮن ﻗﻴﻤــﺔ ‪ a‬ﳐﺘﻠﻔــﺔ ﻋــﻦ‬
‫اﻟﺼﻔﺮ؟‪ .‬ﻣﻌﺎﳉﺔ ﻫﺬﻩ اﳊﺎﻟﺔ ﺗﻌﺘﻤﺪ ﻋﻠــﻰ ﲢﺪﻳــﺪ اﳌﻄﻠــﻮب ﻣــﻦ اﻟــﱪ ﻣﺞ‪ .‬ﻫــﻞ ﻳﻨﺒﻐــﻰ أن ﻧﻌﺘــﱪ ذﻟــﻚ ﺧﻄــﺄ ﰱ اﻟﺒﻴــﺎ ت ﰒ ﻧﻮﻗــﻒ اﻟﺘﻨﻔﻴــﺬ‬
‫أم ﻧﻌﺘــﱪ أن ﻣﻌﻨــﺎﻩ أن ﻣﺴــﺘﺨﺪم اﻟــﱪ ﻣﺞ ﻳﺒﺤــﺚ ﻋــﻦ ﺟــﺬر ﻣﻌﺎدﻟــﺔ ﻣــﻦ اﻟﺪرﺟــﺔ اﻷوﱃ‪ .‬ﰱ ﲨﻴــﻊ اﻷﺣ ـﻮال ﳚــﺐ ﲤﺤــﻴﺺ ﻗﻴﻤــﺔ ‪.a‬‬
‫ﻧﻔﱰض أن اﳌﻄﻠﻮب ﻫﻮ اﻻﺣﺘﻤﺎل اﻷﺧﲑ‪ ،‬ﺳﻨﻌﺪل اﻟﱪ ﻣﺞ ﻟﻴﺼﺒﺢ‪:‬‬

‫‪/* An even Better program, but still can be improved */‬‬


‫>‪#include <stdio.h‬‬
‫)‪void main(void‬‬
‫{‬
‫‪double a,b,c, /* Coefficients of the algebraic equation*/‬‬
‫‪x1, x2, /* Roots of the algebraic equation */‬‬
‫;‪det‬‬ ‫‪/* temporary variable */‬‬
‫;)‪printf("Enter coefs. a, b, c : "); scanf ("%lg %lg %lg",&a, &b, &c‬‬
‫)‪if (a == 0.0‬‬
‫{‬
‫;‪x1 = -b/c‬‬
‫;)‪printf("Equation of 1st degree, root = %lg\n", x1‬‬
‫‪} else‬‬
‫{‬
‫;‪det = b * b - 4.0 * a *c‬‬
‫)‪if (det >= 0‬‬
‫{‬
‫;)‪det = sqrt(det‬‬
‫;)‪x1 = (-b + det) / (2.0*a‬‬
‫;)‪x2 = (-b - det) / (2.0*a‬‬
‫;)‪printf("\n roots are: %lg %lg\n",x1,x2‬‬
‫‪} else‬‬
‫{‬
‫;)‪det = sqrt(-det‬‬
‫;)‪x1 = -b/(2.0*a‬‬
‫;)‪x2 = det / (2.0*a‬‬
‫;)‪printf("\n complex roots: %lg + or - j* %lg\n",x1,x2‬‬
‫}‬
‫}‬
‫}‬
‫ﻣﺎ زاﻟﺖ ﻫﻨﺎك ﲢﺴﻴﻨﺎت ﳑﻜﻨﺔ ﻧﱰﻛﻬﺎ ﻟﻠﻘﺎرئ ﻣﻨﻬﺎ ﻣﺎذا ﳛﺪث إذا ﻛﺎن ﻛﻞ ﻣﻦ ‪ a‬و ‪ b‬ﺻﻔﺮا؟ و ﻫﻨﺎﻟﻚ أﻳﻀــﺎ ﻣﺸــﻜﻠﺔ أﺧــﺮى و ﻫــﻰ‬
‫أن ﻣﻘﺎرﻧــﺔ اﻟﺘﺴــﺎوى ﺑــﲔ ﻋــﺪدﻳﻦ ﺣﻘﻴﻘﻴــﲔ ﳝﻜــﻦ أن ﺗﻌﻄــﻰ ﻧﺘــﺎﺋﺞ ﻏــﲑ ﻣﺘﻮﻗﻌــﺔ‪ .‬ﰱ اﻟﻮاﻗــﻊ ﻓــﺈن اﻷﻋــﺪاد اﳊﻘﻴﻘــﺔ ﲤﺜــﻞ داﺋﻤــﺎ ﺑﺸــﻰء ﻣــﻦ‬
‫اﻟﺘﻘﺮﻳﺐ ﻧﺘﻴﺠﺔ ﺿﺮورة ﺣﺠــﺰ ﻣﻜــﺎن ﳏــﺪود ﻟﺘﻤﺜﻴﻠﻬــﺎ‪ .‬ﻓﻠﻨﻔــﺮض أن ﻟــﺪﻳﻨﺎ ﻋــﺪدﻳﻦ ﺣﻘﻴﻘﻴــﲔ ‪ a,b‬ﰎ ﺣﺴــﺎ ﻤﺎ ﺑﻄــﺮق ﳐﺘﻠﻔــﺔ‪ ،‬و إن ﻛــﺎن‬
‫اﻟﻨﺎﺗﺞ اﳌﺘﻮﻗﻊ ﰱ ﻛﻠﻴﻬﻤﺎ ﻣﺘﻄﺎﺑﻘﺎ‪ .‬ﻧﺘﻴﺠﺔ ﻟﻠﺘﻘﺮﻳﺒﺎت اﳌﺨﺘﻠﻔﺔ اﻟﱴ ﺗﺘﻢ أﺛﻨﺎء اﻟﻌﻤﻠﻴﺎت اﳊﺴﺎﺑﻴﺔ ﻋﻠﻰ اﻷﻋــﺪاد اﳊﻘﻴﻘﻴــﺔ ﻓــﺈن اﻟﻘــﻴﻢ اﻟﻨﺎﲡــﺔ‬

‫‪44‬‬
‫ﻗﺪ ﲣﺘﻠﻒ اﺧﺘﻼﻓﺎ ﺻﻐﲑا ﰱ اﻟﺮﻗﻢ اﻷﺧﲑ ﺑﻌﺪ اﻟﻌﻼﻣــﺔ اﻟﻌﺸـﺮﻳﺔ‪ .‬ﰱ ﻫــﺬﻩ اﳊﺎﻟــﺔ ﺳــﻴﻌﻄﻰ اﺧﺘﺒــﺎر اﻟﺘﺴــﺎوى اﻟﻨــﺎﺗﺞ ﺧﻄــﺄ ﺑﻌﻜــﺲ ﻣــﺎ ﻛﻨــﺎ‬
‫ﻧﺘﻮﻗﻊ‪ .‬ﺳﻨﺘﻨﺎول ﻫﺬﻩ اﳌﺴﺄﻟﺔ ﲟﺰﻳﺪ ﻣﻦ اﻟﺘﻔﺼﻴﻞ ﻓﻴﻤﺎ ﺑﻌﺪ ﻋﻨﺪ دراﺳﺔ اﳋﻄﺄ‪.‬‬

‫ﻛﻤﺜﺎل آﺧﺮ ﻋﻠﻰ ﺿﺮورة اﻟﺘﺄﻛﺪ ﻣﻦ ﺻﺤﺔ أﻣــﺮ اﻹﺳــﻨﺎد‪ ،‬ﻫــﺐ أن ﻟــﺪﻳﻨﺎ ﺑﺮ ﳎــﺎ ﳛﺴــﺐ و ﻳﻜﺘــﺐ ﻗﻴﻤــﺔ زاوﻳــﺔ ﲟﻌﺮﻓــﺔ اﳌﻘﺎﺑــﻞ‬
‫و اﺠﻤﻟﺎور‪.‬‬

‫>‪#include <math.h‬‬
‫)‪void main(void‬‬
‫{‬
‫;‪double PI‬‬
‫;‪double x,y,alfa‬‬
‫;)‪PI = 4.0*atan(1.0‬‬
‫;)‪printf("Enter x, y: "); scanf ("%lg %lg", &x, &y‬‬
‫;)‪alfa = atan(y / x‬‬
‫;)‪pintf ("Alfa = %lg\n", alfa*180/PI‬‬
‫}‬
‫اﻟﺪاﻟــﺔ )‪ atan(d‬ﺗﻌﻄــﻰ ﻗﻴﻤــﺔ اﻟﺰاوﻳــﺔ اﻟــﱴ ﻇﻠﻬــﺎ ‪ d‬و ذﻟــﻚ ﻟﺘﻘــﺪﻳﺮ اﻟــﺪاﺋﺮى‪ ،‬و ﻫــﻰ ﻣﻌﺮﻓــﺔ ﰱ ﻣﻠــﻒ اﻟ ـﺮأس اﻟﻘﻴﺎﺳــﻰ ‪ .math.h‬و‬
‫ﻟــﺬﻟﻚ ﻓﻘــﺪ ﺑــﺪأ ﲝﺴــﺎب ‪ PI‬ﺣﻴــﺚ أن ‪ .tan(PI/4) = 1.0‬ﰒ ﻗـﺮأ ﻗــﻴﻢ ‪ x,y‬و ﻣﻨﻬــﺎ ﺣﺴــﺒﻨﺎ اﻟﺰاوﻳــﺔ ﻟﺘﻘــﺪﻳﺮ اﻟــﺪاﺋﺮى‪ ،‬و ﻛﺘﺒﻨﺎﻫــﺎ‬
‫ﻋﻠﻰ اﻟﺸﺎﺷﺔ ﻟﺪرﺟﺎت‪ .‬اﳌﺸﻜﻠﺔ ﰱ ﻫﺬا اﻟﱪ ﻣﺞ ﻫﻰ ﻋﻤﻠﻴﺔ اﻟﻘﺴﻤﺔ‪ .‬ﺣﻴﺚ أن اﳌﻘﺎم ﻗﺪ ﻳﻜﻮن ﺻﻔﺮا‪ .‬ﻫــﻞ ﻫــﺬﻩ اﳊﺎﻟــﺔ ﻏــﲑ ﳑﻜﻨــﺔ‪،‬‬
‫أى ﻫــﻞ ﳝﺜــﻞ ذﻟــﻚ ﺧﻄــﺄ ﰱ اﻟﺒﻴــﺎ ت؟ ﻟﻄﺒــﻊ ﻻ ﻓﺎﻟﺰاوﻳــﺔ ‪ PI/2‬ﺗﻜــﻮن ﻗﻴﻤــﺔ ‪ x‬ﻓﻴﻬــﺎ ﺻــﻔﺮا‪ ،‬و ﻟﺘــﺎﱃ ﻓــﺈن اﻟﺰاوﻳــﺔ اﻟــﱴ ﻇﻠﻬــﺎ ﻻ ــﺎﺋﻰ‬
‫ﻫــﻰ ﻟﺘﺤﺪﻳــﺪ اﻟﺰاوﻳــﺔ اﻟﻘﺎﺋﻤــﺔ‪ .‬و ﻟﻜــﻦ اﳊﺎﺳــﺐ ﺳــﻴﺘﻮﻗﻒ ﻋــﻦ اﻟﻌﻤــﻞ ﻋﻨــﺪﻣﺎ ﻳــﺮى أن ﻗﻴﻤــﺔ اﳌﻘــﺎم ﺗﺴــﺎوى ﺻــﻔﺮا‪ .‬ﻣــﺎ اﻟﻌﻤــﻞ ﰱ ﻫــﺬﻩ‬
‫اﳊﺎﻟﺔ؟ ﺑﺒﺴﺎﻃﺔ ﺳﻨﻤﺤﺺ ﻗﻴﻤﺔ ‪ x‬ﻗﺒﻞ إﺟﺮاء اﻟﻘﺴﻤﺔ‪ ،‬ﻓﺈذا ﻛﺎﻧﺖ ﻗﺮﻳﺒﺔ ﻣــﻦ اﻟﺼــﻔﺮ‪ ،‬ﺳــﻨﺒﺤﺚ ﻋـﻦ ﻣــﺘﻤﻢ اﻟﺰاوﻳــﺔ ﰒ ﻧﻄﺮﺣــﻪ ﻣــﻦ اﻟﺰاوﻳــﺔ‬
‫اﻟﻘﺎﺋﻤﺔ‪.‬‬
‫>‪#include <math.h‬‬
‫‪#define TINY 1.0e-200‬‬
‫)‪void main(void‬‬
‫{‬
‫;‪double PI‬‬
‫;‪double x,y,alfa‬‬
‫;)‪PI = 4.0*atan(1.0‬‬
‫;)‪printf("Enter x, y: "); scanf ("%lg %lg", &x, &y‬‬
‫)‪if ( (fabs(x) < TINY) && (fabs(y)<TINY‬‬
‫{‬
‫;)"‪printf("Undefined angle\n‬‬
‫))‪} else if (fabs(x) > fabs(y‬‬
‫{‬
‫;)‪alfa = atan(y / x‬‬
‫‪} else‬‬
‫{‬
‫;)‪alfa = PI/2 – atan(x/y‬‬
‫}‬
‫;)‪pintf ("Alfa = %lg\n", alfa*180/PI‬‬
‫}‬

‫‪45‬‬
‫‪.3‬ب‪ .3.‬اﻟﻌﻤﻠﻴﺎت اﳌﻨﻄﻘﻴﺔ ‪logical operations‬‬
‫ﺗﺘﻜﻮن أﺳﺎﺳﺎ ﻣﻦ ﻣﺆﺛﺮات اﳌﻘﺎرﻧﺔ ‪ relational and equality operators‬و ﲢﻮى‪:‬‬

‫‪Less than‬‬ ‫<‬ ‫أﻗﻞ ﻣﻦ‬


‫‪Greater than‬‬ ‫>‬ ‫أﻛﱪ ﻣﻦ‬
‫‪Less than or equal‬‬ ‫=<‬ ‫أﻗﻞ ﻣﻦ أو ﺗﺴﺎوى‬
‫‪Greater than or equal‬‬ ‫=>‬ ‫أﻛﱪ ﻣﻦ أو ﺗﺴﺎوى‬
‫‪Equals‬‬ ‫==‬ ‫ﺗﺴﺎوى‬
‫‪Not equals‬‬ ‫=!‬ ‫ﻻ ﺗﺴﺎوى‬
‫و ﻫﻰ ﺗﺆﺛﺮ ﻋﻠﻰ اﻟﺒﻴﺎ ت اﻟﻌﺪدﻳــﺔ أو اﳊﺮﻓﻴــﺔ اﳌﻔــﺮدة‪ .‬ﰱ ﺣﺎﻟــﺔ اﻟﺒﻴــﺎ ت اﳊﺮﻓﻴــﺔ‪ ،‬ﻓــﺄن اﳌﻘﺎرﻧــﺔ ﺗــﺘﻢ ﻋﻠــﻰ أﺳــﺎس اﻟﻜــﻮد ‪ .ASCII‬ﺗﻨــﺘﺞ‬
‫ﻫﺬﻩ اﻟﻌﻤﻠﻴﺔ ﻧﺘﻴﺠﺔ ﻣﻨﻄﻘﻴﺔ و ﻫﻰ إﻣﺎ ﺻﻮاب و ﻳﻌﱪ ﻋﻨﻬﺎ ﻟﻘﻴﻤﺔ ‪ 1‬و إﻣﺎ ﺧﻄﺄ و ﻳﻌﱪ ﻋﻨﻬﺎ ﻟﻘﻴﻤﺔ ‪.0‬‬
‫ﳝﻜﻦ ﲡﻤﻴﻊ ﺷﺮﻃﲔ ﻟﺘﻜﻮﻳﻦ ﺷﺮط ﻣﺮﻛﺐ ﺳﺘﺨﺪام أﺣﺪ اﳌﺆﺛﺮات اﳌﻨﻄﻘﻴﺔ و ذﻟﻚ ﻋﻠﻰ اﻟﺼﻮرة اﻟﻌﺎﻣﺔ‪:‬‬
‫‪Logical_expression E1‬‬ ‫‪operator‬‬ ‫‪logical_expression E2‬‬

‫‪Operands‬‬ ‫‪Result of operator‬‬


‫‪E1‬‬ ‫‪E1‬‬ ‫&&‬ ‫||‬
‫)‪(Means AND‬‬ ‫)‪(Means OR‬‬
‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬
‫‪0‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪1‬‬
‫‪1‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪1‬‬
‫‪1‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪1‬‬

‫‪Example: For x=11: (x > 5) && (x < 10) gives 0; (x > 5) || (x < 10) gives 1‬‬
‫و ﻫﻨﺎك أﻳﻀﺎ اﳌﺆﺛﺮ اﻷﺣﺎدى ! اﻟﺬى ﻳﻌﱪ ﻋﻦ اﻟﻌﻤﻠﻴﺔ ‪ NOT‬أى ﻋﻜﺲ اﻟﻘﻴﻤﺔ اﳌﻨﻄﻘﻴﺔ اﻟﱴ ﻳﺆﺛﺮ ﻋﻠﻴﻬﺎ‪:‬‬
‫‪! (logical_expression E) gives 0 if E==1 ; gives 1 if E==0‬‬

‫ﺗﺴــﺘﺨﺪم أﻏﻠــﺐ اﳌﱰﲨــﺎت أﺳــﻠﻮب اﳊﺴــﺎب اﳌﺨﺘﺼــﺮ ‪ .short cut evaluation‬ﻓﻤــﺜﻼ ﻋﻨــﺪ ﺣﺴــﺎب‪E1&&E2 :‬ﻓــﺈن‬
‫اﳊﺎﺳﺐ ﻳﺒﺪأ أوﻻ ﲝﺴﺎب ﻗﻴﻤﺔ ‪ ،E1‬ﻓﺈذا ﻛﺎﻧــﺖ ﺧﻄــﺄ ﻻ ﻳﺴــﺘﻤﺮ ﰱ ﺣﺴــﺎب ﻗﻴﻤــﺔ ‪ E2‬ﺣﻴــﺚ أن ﺗــﺞ ﻋﻤﻠﻴــﺔ && ﺳــﻴﻌﻄﻰ ﺧﻄــﺄ‬
‫ﰱ ﲨﻴﻊ اﻷﺣـﻮال‪ .‬و ﰱ ﺣﺎﻟــﺔ ‪ E1 || E2‬إذا ﻛﺎﻧــﺖ ‪ E1‬ﺻـﻮاب ﻓﻠــﻦ ﳓﺴــﺐ ‪ E2‬إذ إن ﺗــﺞ اﻟﻌﻤﻠﻴــﺔ || ﺳــﻴﻜﻮن ﺻــﺤﻴﺤﺎ ﰱ ﲨﻴــﻊ‬
‫اﻷﺣﻮال‪ .‬و ﺑﺬﻟﻚ ﻟﻦ ﺗﻈﻬﺮ ﻣﺸﺎﻛﻞ ﻋﻨﺪ ﺗﻨﻔﻴﺬ اﻷﻣﺮ‪:‬‬
‫} ‪if ( (x > 0.0) && (sqrt(x) < 5.0) ) {...;...‬‬
‫إذا ﻛﺎﻧﺖ ﻗﻴﻤﺔ ‪ x‬ﺳﺎﻟﺒﺔ‪ .‬ﻓﻨﺘﻴﺠﺔ ﻟﻠﺤﺴﺎب اﳌﺨﺘﺼــﺮ ﺳــﻨﺨﺮج ﻗﺒــﻞ ﺣﺴــﺎب ﺟــﺬر اﻟـﺮﻗﻢ اﻟﺴــﺎﻟﺐ‪ .‬ﻷﺟــﻞ اﻟﺘﺄﻛــﺪ ﻣــﻦ اﻟﻨﺘﻴﺠــﺔ و ﻟﻌﻤــﻞ‬
‫ﺑﺮ ﻣﺞ ﺗﺴﻬﻞ ﻗﺮاءﺗﻪ و ﺗﻌﺪﻳﻠﻪ ﻳﻔﻀﻞ ﻛﺘﺎﺑﺔ اﻷﻣﺮ ﻋﻠﻰ اﻟﺼﻮرة اﻟﺘﺎﻟﻴﺔ‪:‬‬
‫} ‪if (x > 0.0) if (sqrt(x)) < 5.0) {...;...‬‬

‫‪46‬‬
‫‪.3‬ب‪ .4.‬اﻟﻌﻤﻠﻴﺎت ﻋﻠﻰ اﻷرﻗﺎم اﻟﺜﻨﺎﺋﻴﺔ ‪bitwise operations‬‬
‫ﻫﻨــﺎك ﻋﻤﻠﻴــﺎت ﲡــﺮى ﻋﻠــﻰ ﻛــﻞ ﺑﻴــﺖ ﻣــﻦ اﳌﻌﺎﻣــﻞ اﻟــﺬى ﺗــﺆﺛﺮ ﻋﻠﻴــﻪ و ﻫــﻰ ﻟﻄﺒــﻊ ﻏــﲑ ﻣﻌﺮﻓــﺔ إﻻ ﻟﻨﺴــﺒﺔ ﻟﻠﺒﻴــﺎ ت اﻟﺼــﺤﻴﺤﺔ‪ .‬ﺗﺸــﻤﻞ‬
‫ﻫﺬﻩ اﻟﻌﻤﻠﻴﺎت‪:‬‬
‫‪bit1 operator bit2‬‬

‫‪Operands‬‬ ‫‪Operator‬‬
‫‪bit1‬‬ ‫‪bit2‬‬ ‫&‬ ‫|‬ ‫^‬
‫‪bitwise AND‬‬ ‫‪bitwise OR‬‬ ‫‪bitwise XOR‬‬
‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬
‫‪0‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪1‬‬
‫‪1‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪1‬‬
‫‪1‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪0‬‬

‫‪Example:‬‬
‫‪01100101‬‬ ‫‪01100101‬‬ ‫‪01100101‬‬
‫‪& 00110011‬‬ ‫‪| 00110011‬‬ ‫‪^ 00110011‬‬
‫‪--------------‬‬ ‫‪--------------‬‬ ‫‪--------------‬‬
‫‪00100001‬‬ ‫‪01110111‬‬ ‫‪01010110‬‬
‫ﻹﺿﺎﻓﺔ ﻟﻠﻤﺆﺛﺮ اﻷﺣﺎدى ~ و اﻟﺬى ﻳﺆدى ﻟﻌﻜﺲ ﻗﻴﻢ ﲨﻴﻊ اﻷرﻗﺎم اﻟﺜﻨﺎﺋﻴﺔ اﳌﻜﻮﻧﺔ ﻟﻠﻌﺪد‪.‬‬
‫ﻫﻨــﺎك أﻳﻀــﺎ ﻣــﺆﺛﺮات اﻹزاﺣــﺔ ﻟﻠﻴﻤــﲔ و ﻟﻠﻴﺴــﺎر )<< ‪ (shift left >>; shift right‬و ﺗﺴــﻔﺮ ﻋــﻦ ﲢﺮﻳــﻚ اﻷرﻗــﺎم اﻟﺜﻨﺎﺋﻴــﺔ‬
‫ﻟﻠﻴﻤﲔ أو ﻟﻠﻴﺴﺎر ﻋﺪد ﻣــﻦ اﳋــﺎ ت ﻣــﻊ ﻣــﻞء اﳋــﺎ ت اﳉﺪﻳــﺪة اﻟــﱴ ﺳــﺘﻈﻬﺮ ﻧﺘﻴﺠــﺔ ﻟﻠﺘﺤﺮﻳــﻚ ﻷﺻــﻔﺎر ﻣﺜــﺎل ذﻟــﻚ اﻟﺘﺤﺮﻳــﻚ ﻟﻠﻴﻤــﲔ‬
‫ﺛﻼث ﺧﺎ ت‪:‬‬
‫‪11010110 >> 3‬‬ ‫‪gives: 00011010‬‬
‫ﻫﻨﺎك ﻋﺪة اﺳﺘﺨﺪاﻣﺎت ﳍﺬﻩ اﻟﻄﺎﺋﻔﺔ ﻣــﻦ اﻟﻌﻤﻠﻴــﺎت ﻣﻨﻬــﺎ ﲣـﺰﻳﻦ و اﺳــﱰﺟﺎع أﻛﺜــﺮ ﻣــﻦ ﻣﻌﻠﻮﻣــﺔ ﲢﺘــﺎج ﻛــﻞ ﻣﻨﻬــﺎ ﻟﻌــﺪد ﻗﻠﻴــﻞ ﻣــﻦ اﻟﺒﻴــﺖ‬
‫)ﺑﻴﺖ واﺣﺪة ﻣﺜﻼ( و ذﻟﻚ ﰱ ﺧﺎﻧﺔ ذاﻛﺮة واﺣﺪة ﺑﺴﻌﺔ ﻳﺖ )أى ﻣﺎ ﻳﻨﺎﻇﺮ ‪ 8‬ﺑﻴﺖ(‪.‬‬

‫‪.3‬ب‪ .5.‬اﻵ ر اﳉﺎﻧﺒﻴﺔ ‪side effects‬‬


‫ﻳﻨﺒﻐﻰ أن ﻧﺪرك أن ﻋﻤﻠﻴﺔ اﻹﺳــﻨﺎد ﺑﺮﻣﺘﻬــﺎ ﳍــﺎ ﻧﺘﻴﺠــﺔ ﰱ ﻟﻐــﺔ ‪ .C‬ﻫــﺬﻩ اﻟﻨﺘﻴﺠــﺔ ﺗﺴــﺎوى اﻟﻘﻴﻤــﺔ اﳌﺴــﻨﺪة ذا ــﺎ و ﳝﻜــﻦ اﺳــﺘﺨﺪام‬
‫ﺗﻠﻚ اﻟﻨﺘﻴﺠﺔ ﰱ ﻋﻤﻠﻴﺎت أﺧﺮى ﰱ ﻧﻔﺲ اﻷﻣﺮ‪ .‬ﻣﺜﺎل ذﻟﻚ‪:‬‬
‫;‪x = y = 3‬‬ ‫;)‪m = 4 + (j=7 % 2‬‬
‫ﰱ اﳌﺜﺎل اﻷول ﻳﺒﺪأ اﳊﺎﺳﺐ ﺳــﻨﺎد اﻟــﺮﻗﻢ ‪ 3‬إﱃ اﳌﺘﻐــﲑ ‪ y‬و ﺗــﺞ ﻫــﺬﻩ اﻟﻌﻤﻠﻴــﺔ )أى اﻟــﺮﻗﻢ ‪ (3‬ﳝﻜــﻦ أن ﻳﺴــﺘﺨﺪم ﺑﻌــﺪ ذﻟــﻚ‬
‫ﰱ ﻋﻤﻠﻴــﺔ اﻹﺳــﻨﺎد اﻟﺘﺎﻟﻴــﺔ و ﺑــﺬﻟﻚ ﺗﺼــﺒﺢ ﻗﻴﻤــﺔ ‪ x‬أﻳﻀــﺎ ‪ .3‬ﳝﻜــﻦ أن ﻧﻜــﺮر ﻋﻤﻠﻴــﺎت اﻹﺳــﻨﺎد اﻟﻮاﺣــﺪة ﺗﻠــﻮ اﻷﺧــﺮى أى ﻋــﺪد ﻣــﻦ‬
‫اﳌﺮات و ﰱ ﲨﻴﻊ اﻷﺣﻮال ﺳــﻴﺒﺪأ اﳊﺎﺳــﺐ ﳒــﺎز اﻟﻌﻤﻠﻴــﺔ ﰱ أﻗﺼــﻰ اﻟﻴﻤــﲔ أوﻻ ﰒ اﻟﻌﻤﻠﻴــﺔ اﻟــﱴ ﺗﻠﻴﻬــﺎ ﻣــﻦ اﻟﻴﺴــﺎر و ﻫﻜــﺬا‪ .‬ﰱ اﳌﺜــﺎل‬
‫اﻟﺜﺎﱏ ﻳﺒﺪأ اﳊﺎﺳﺐ ﻟﻌﻤﻠﻴﺔ ﺑﲔ اﻟﻘﻮﺳــﲔ و ﻫــﻰ ﻋﻤﻠﻴــﺔ إﺳــﻨﺎد ﻟﻠﻘﻴﻤــﺔ ‪) 7%2‬و ﺗﺴــﺎوى ‪ (1‬ﻟﻠﻤﺘﻐــﺮ ‪ .j‬ﰒ ﻳﺴــﺘﺨﺪم ﺑﻌــﺪ ذﻟــﻚ ﺗــﺞ‬
‫ﻋﻤﻠﻴــﺔ اﻹﺳــﻨﺎد )اﻟﻘﻴﻤــﺔ ‪ (1‬ﰱ اﻟﻌﻤﻠﻴــﺔ اﻷﻛــﱪ ﳊﺴــﺎب و إﺳــﻨﺎد ﻗﻴﻤــﺔ ‪ m‬اﻟــﱴ ﺗﺼــﺒﺢ ‪ .5‬ﻻﺣــﻆ أن ﻛــﻞ ﻣــﻦ اﳌﺘﻐــﲑﻳﻦ ‪ x,y‬ﰱ اﳌﺜــﺎل‬
‫اﻷول و ‪ j,m‬ﰱ اﳌﺜﺎل اﻟﺜﺎﱏ ﻗﺪ ﻋﺪﻟﺖ ﻗﻴﻤﻬﻢ ﻧﺘﻴﺠﺔ ﻫﺬا اﻷﻣﺮ و ﻫﻮ ﻣﺎ ﻳﻌﺮف ﻵ ر اﳉﺎﻧﺒﻴﺔ ‪.side effects‬‬
‫ﻫﻨــﺎك أﻳﻀــﺎ ﻣــﺆﺛﺮات ﺧﺎﺻــﺔ ﺑﻠﻐــﺔ ‪ C‬و ﻫــﻰ ﻣــﺆﺛﺮات اﻟــﺰ دة ‪ increment ++‬و اﻹﻧﻘــﺎص ‪ .decrement --‬و ﻫــﻰ ﺗــﺆدى‬
‫ﻟﺘﻌــﺪﻳﻞ ﻗﻴﻤــﺔ اﳌﺘﻐــﲑ اﻟــﺬى ﺗــﺆﺛﺮ ﻋﻠﻴــﻪ ﺑــﺰ دة )أو إﻧﻘــﺎص( واﺣــﺪ ﺻــﺤﻴﺢ‪ .‬ﻓــﺎﻷواﻣﺮ‪ n++; m--;:‬ﺗــﺆدى ﻟﺘﻌــﺪﻳﻞ اﻟﻘﻴﻤــﺔ اﳌﺨﺘﺰﻧــﺔ ﰱ‬

‫‪47‬‬
‫اﳌﺘﻐﲑ ‪ n‬ﺑﺰ د ﺎ واﺣﺪا ﺻﺤﻴﺤﺎ و ﻧﻘﺼﺎن ﻗﻴﻤﺔ اﳌﺘﻐﲑ ‪ m‬ﺑﻨﻔﺲ اﳌﻘﺪار‪ .‬و ﻫــﻰ أواﻣــﺮ ﻗﺎﺋﻤــﺔ ﺑــﺬا ﺎ ﻛﻤــﺎ أﻧـﻪ ﳝﻜــﻦ أن ﺗﻈﻬــﺮ ﺑــﺪاﺧﻞ‬
‫ﻋﻤﻠﻴﺎت أﺧﺮى ﻛﺂ ر ﺟﺎﻧﺒﻴﺔ‪ .‬ﻣﺜﻼ‪:‬‬
‫;‪int i=3,z; z = (i++)*2; gives i=4 and z=6‬‬
‫;‪int i=3,z; z = (++i)*2; gives i=4 and z=8‬‬
‫ﻻﺣﻆ أن ﻇﻬﻮر ﻣﺆﺛﺮ اﻟﺰ دة ﺑﻌﺪ اﳌﺆﺛﺮ ﻋﻠﻴﻪ ﻳﻌﲎ أن ﻧﺴــﺘﺨﺪم اﻟﻘﻴﻤــﺔ اﻟﻘﺪﳝــﺔ ﻛﻨــﺎﺗﺞ ﰱ اﻟﻌﻤﻠﻴــﺔ اﻷﻛــﱪ ﺑﻴﻨﻤــﺎ ﻇﻬــﻮر اﳌـﺆﺛﺮ ﻗﺒــﻞ اﳌــﺆﺛﺮ‬
‫ﻋﻠﻴــﻪ ﻳﻌــﲎ أن ﻧﺴــﺘﺨﺪم اﻟﻘﻴﻤــﺔ اﳉﺪﻳــﺪة ﻛﻨــﺎﺗﺞ ﰱ اﻟﻌﻤﻠﻴــﺔ اﻷﻛــﱪ‪ .‬ﻳﻨﺒﻐــﻰ اﳊــﺮص ﻋﻨــﺪ اﺳــﺘﺨﺪام ﻫــﺬﻩ اﻹﻣﻜﺎﻧﻴــﺎت ﻟﺘﻔــﺎدى ﺗﻜــﻮﻳﻦ‬
‫ﻋﺒﺎرات ﻣﺒﻬﻤﺔ ﻣﺜﻞ‪ i = 5 + (i ++); :‬ﻷﻧﻪ ﻣﻦ اﻟﻌﺴﲑ ﻣﻌﺮﻓﺔ ﻣﱴ ﺳﺘﺘﻢ ﻋﻤﻠﻴــﺔ اﻟــﺰ دة‪ .‬ﻓــﺈذا ﻛﺎﻧــﺖ اﻟﻘﻴﻤــﺔ اﻻﺑﺘﺪاﺋﻴــﺔ ﻟﻠﻤﺘﻐــﲑ ‪ i‬ﻫــﻰ‬
‫ﺻﻔﺮ ﻣﺜﻼ ﳝﻜﻦ أن ﺗﻜﻮن اﻟﻨﺘﻴﺠﺔ اﻟﻨﻬﺎﺋﻴﺔ ‪ 6‬أو ‪.1‬‬
‫إذا ﻛﺎﻧـ ــﺖ اﻟﻌﻤﻠﻴـ ــﺔ‪ i++; :‬ﺗﻨ ــﺎﻇﺮ ﲤﺎﻣ ــﺎ اﻟﻌﻤﻠﻴ ــﺔ‪ i=i+1; :‬ﻓﺈﻧ ــﻪ ﳝﻜ ــﻦ ﺗﻌﻤ ــﻴﻢ ذﻟـ ــﻚ ﺳـ ــﺘﺨﺪام ﻣـ ــﺆﺛﺮات اﻹﺳـ ــﻨﺎد اﳌﺮﻛﺒـ ــﺔ‬
‫‪ compound assignement statements‬ﻣﺜﻞ‪:‬‬
‫;‪x += expression‬‬
‫و اﻟﱴ ﺗﻜﺎﻓﺊ ﲤﺎﻣﺎ ﰱ ﻧﺘﻴﺠﺘﻬﺎ اﻷﻣﺮ‪x = x + expression; :‬‬
‫ﻫﻨﺎك ﻃﺎﺋﻔﺔ ﻛﺎﻣﻠﺔ ﻣﻦ اﻷواﻣﺮ اﳌﺮﻛﺒﺔ ﺗﺸﻤﻞ‪:‬‬
‫=‪+‬‬ ‫=‪-‬‬ ‫=*‬ ‫=‪/‬‬ ‫=‪%‬‬ ‫=<<‬ ‫=>>‬ ‫=&‬ ‫=|‬ ‫=^‬
‫ﺗﻔﻴﺪ ﻫﺬﻩ اﻷواﻣﺮ ﰱ ﻛﺘﺎﺑﺔ ﻋﻤﻠﻴﺎت ﺳﻠﻮب أوﺿﺢ و أﺳﺮع ﻣﻦ اﻷﺳﻠﻮب اﻟﺘﻘﻠﻴﺪى ﻓﺎﻷﻣﺮﻳﻦ‪:‬‬
‫;‪x[2*i+5] = x[2*i+5] - 1.2‬‬ ‫;‪x[2*i-5] -= 1.2‬‬
‫ﻳﺆد ن ﻋﻤﻠﻴﺎ ﻟﻨﻔﺲ اﻟﻨﺎﺗﺞ‪ .‬و ﻟﻜﻦ اﻷﻣــﺮ اﻟﺜــﺎﱏ اﻟــﺬى ﻳﺴــﺘﺨﺪم أﻣــﺮ اﻹﺳــﻨﺎد اﳌﺮﻛــﺐ =‪ -‬أوﺿــﺢ ﰱ ﻗﺮاءﺗــﻪ ﻛﻤــﺎ أﻧــﻪ أﺳــﺮع ﰱ ﺗﻨﻔﻴــﺬﻩ‪.‬‬
‫ﰱ اﻷﻣ ــﺮ اﻷول‪ ،‬ﻳ ــﺘﻢ ﺣﺴ ــﺎب ﻋﻨـ ـﻮان اﳌﺘﻐ ــﲑ اﳌﻄﻠ ــﻮب اﻟﺘﻌﺎﻣ ــﻞ ﻣﻌ ــﻪ ]‪ x[2*i+5‬ﻣـ ـﺮﺗﲔ‪ ،‬ﻣ ــﺮة ﻹﳚ ــﺎد ﺧﺎﻧ ــﺔ اﻟ ــﺬاﻛﺮة اﳌﻄﻠ ــﻮب ﻗـ ـﺮاءة‬
‫اﳌﻌﻠﻮﻣﺎت ﻣﻨﻬﺎ )ﻋﻨــﺪﻣﺎ ﻇﻬــﺮ ﻋﻠــﻰ ﳝــﲔ أﻣــﺮ اﻹﺳــﻨﺎد(‪ ،‬و ﻣــﺮة أﺧــﺮى ﻹﳚــﺎد ﻋﻨـﻮان اﳋﺎﻧــﺔ اﳌﻄﻠــﻮب ﺗﻌــﺪﻳﻠﻬﺎ )ﻋﻨــﺪﻣﺎ ﻇﻬــﺮ ﻋﻠــﻰ ﻳﺴــﺎر‬
‫أﻣــﺮ اﻹﺳــﻨﺎد(‪ .‬أﻣــﺎ ﰱ اﻷﻣــﺮ اﻟﺜــﺎﱏ‪ ،‬ﻳﻔﻬــﻢ اﳌــﱰﺟﻢ ﺑﺴــﻬﻮﻟﺔ )ﻛﻤــﺎ ﻧﻔﻬــﻢ ﳓــﻦ أﻳﻀــﺎ‪ ،‬و إن ﻛــﺎن ﻻ ﻳﺼــﺢ ﻣﻘﺎرﻧﺘﻨــﺎ ﳊﺎﺳــﺐ و اﻟﻌﻴــﺎذ‬
‫ﻪﻠﻟ!( أن اﳋﺎﻧﺘﲔ ﳘﺎ ﺧﺎﻧﺔ واﺣﺪة و ﻟﺘﺎﱃ ﻻ ﳛﺴﺐ ﻋﻨﻮا ﺎ ﻣﺮﺗﲔ‪.‬‬

‫ﻗﺪ ﻳﻘﻊ اﳌﱪﻣﺞ اﳌﺒﺘﺪئ اﻟﺬى ﻻ ﻳﻌﺮف اﻵ ر اﳉﺎﻧﺒﻴﺔ ﰱ اﳋﻄﺄ اﻟﺘﺎﱃ‪ .‬ﻫﺐ أن ﻟﺪﻳﻨﺎ ﺑﺮ ﳎﺎ ﻳﻘﺮأ ﻋﺪدا ﺣﻘﻴﻘﻴﺎ ﰒ ﳛﺴﺐ‬
‫و ﻳﻜﺘﺐ ﻣﻘﻠﻮﺑﻪ‪ .‬اﻟﱪ ﻣﺞ اﻟﺘﺎﱃ ﺑﻪ ﺧﻄﺄ‪:‬‬
‫)‪void main (void‬‬
‫{‬
‫;‪double x‬‬
‫;)‪printf ("Enter x:"); scanf("%lg",&x‬‬
‫)‪if (x=0‬‬ ‫‪/***Wrong!***/‬‬
‫{‬
‫;)"‪printf("Invalid data‬‬
‫‪} else‬‬
‫{‬
‫;)‪printf("The inverse is: %lg\n",1.0/x‬‬
‫}‬
‫}‬
‫و اﳋﻄﺄ ﻳﻜﻤﻦ ﰱ اﻟﺸﺮط‪ .‬ﺣﻴﺚ أﻧﻪ ﻛﺘﺐ ﻛﻌﻤﻠﻴﺔ إﺳﻨﺎد و ﻟﻴﺲ ﻛﻌﻤﻠﻴﺔ ﻣﻘﺎرﻧﺔ‪ .‬و ﻟﺘﺎﱃ ﻓﺈن اﻟﱪ ﻣﺞ ﺳﺘﺘﻢ ﺗﺮﲨﺘﻪ ﺑﻨﺠﺎح‪ ،‬و ﻟﻜﻨــﻪ‬
‫ﺳﻴﺼــﺪر ﺧﻄ ـﺄ ﻋﻨــﺪ اﻟﺘﻨﻔﻴــﺬ ﺑﻐــﺾ اﻟﻨﻈــﺮ ﻋــﻦ ﻗﻴﻤــﺔ ‪ x‬اﳌﻌﻄــﺎة! ﺣﻴــﺚ أن ﻋﻤﻠﻴــﺔ اﻹﺳــﻨﺎد اﻟﻀــﻤﻨﻴﺔ ﺑــﺪاﺧﻞ اﻷﻣــﺮ ‪ if‬ﺳــﺘﺆدى ﻟﻮﺿــﻊ‬

‫‪48‬‬
‫اﻟﻘﻴﻤﺔ ‪ 0‬ﰱ ‪ x‬و ﺣﻴﺚ أن اﻟﻘﻴﻤﺔ اﳌﺴﻨﺪة ﺳﺘﺴﺘﺨﺪم داﺧﻞ اﻷﻣﺮ ‪ if‬ﻛﻘﻴﻤﺔ ﻟﻠﺸﺮط‪ ،‬ﻓﺴﻴﺼﺒﺢ اﻟﺸــﺮط ﻏــﲑ ﻣﺘﺤﻘــﻖ‪ ،‬و ﻟﺘــﺎﱃ ﻳﻘــﻮم‬
‫اﻟﱪ ﻣﺞ ﺑﺘﻨﻔﻴﺬ اﳉﺰء اﳌﺘﻌﻠﻖ ب ‪ else‬و ﻫﻮ ﻣﺎ ﺳﻴﺆدى ﻟﻠﻘﺴﻤﺔ ﻋﻠﻰ ‪ 0‬و ﺗﻮﻗﻒ اﻟﱪ ﻣﺞ ﻋﻦ اﻟﻌﻤﻞ!‬

‫‪.3‬ب‪ .6.‬ﻣﺆﺛﺮات أﺧﺮى ‪Other operators‬‬


‫ﻫﻨﺎك ﻋﺪد ﻣﻦ اﳌﺆﺛﺮات اﻷﺧﺮى اﻟﱴ ﲡﺪر اﻹﺷﺎرة ﺎ ﻣﺜﻞ ‪ sizeof‬و ﻫﻮ ﻳﻌﻄﻰ ﻋﺪد اﻟﺒﺎﻳﺖ اﳌﺴﺘﺨﺪﻣﺔ ﳊﻔــﻆ ﻣﺘﻐــﲑ ﻣــﺎ ﰱ‬
‫اﻟﺬاﻛﺮة أو أى ﻧﻮع ﻣﻦ اﻟﺒﻴﺎ ت‪:‬‬
‫]‪int i; float x; double z; x[3‬‬
‫;‪sizeof i : gives 2; sizeof x : gives 4‬‬
‫‪sizeof z : gives 8; sizeof x gives 24‬‬
‫‪sizeof(char) : gives 1‬‬ ‫‪etc...‬‬
‫ﻻﺣﻆ أن ﰱ ﺣﺎﻟﺔ اﻟﺘﺄﺛﲑ ﻋﻠﻰ ﻧﻮع ﺑﻴﺎ ت ﳚﺐ وﺿﻊ اﻟﻨﻮع ﺑﲔ أﻗﻮاس‪.‬‬
‫ﻫﻨﺎك أﻳﻀﺎ ﻣﺆﺛﺮ ﻋﻼﻣﺔ اﻻﺳﺘﻔﻬﺎم ? و ﻫﻮ ﻳﻜﺘﺐ ﻋﻠﻰ اﻟﺼﻮرة‪:‬‬
‫‪(condition) ? expression1 : expression2‬‬
‫ﳊﺴــﺎب ﻗﻴﻤــﺔ اﻟﺘﻌﺒــﲑ اﻟ ـﻮارد أﻋــﻼﻩ ﻓﺈﻧﻨــﺎ ﻧﺒــﺪأ ﺑﻔﺤــﺺ اﻟﺸــﺮط ﺑــﲔ اﻷﻗ ـﻮاس ‪ .condition‬إذا ﲢﻘــﻖ‪ ،‬ﻛﺎﻧــﺖ ﻗﻴﻤــﺔ اﻟﺘﻌﺒــﲑ ﺑﺮﻣﺘــﻪ ﻫــﻰ‬
‫ﻧﻔﺴﻬﺎ ﻗﻴﻤﺔ اﻟﺘﻌﺒﲑ اﻷول ‪ expression1‬و إن ﱂ ﻳﺘﺤﻘﻖ ﻛﺎﻧﺖ اﻟﻘﻴﻤﺔ ﻫﻰ ﺗﻠﻚ اﳌﻨﺎﻇﺮة ﻟﻠﺘﻌﺒﲑ اﻟﺜﺎﱏ ‪.expression2‬‬
‫ﻣــﺆﺛﺮ اﻟﻔﺎﺻــﻠﺔ ‪ ,‬ﻳﻈﻬــﺮ ﺑــﲔ أﻣ ـﺮﻳﻦ و ﻳﻌــﲎ ﺿــﺮورة اﻋﺘﺒــﺎر ﻫــﺬﻳﻦ اﻷﻣ ـﺮﻳﻦ ﲟﺜﺎﺑــﺔ أﻣــﺮ واﺣــﺪ و ذﻟــﻚ ﰱ اﻷﻣــﺎﻛﻦ اﻟــﱴ ﺗﺸــﱰط‬
‫وﺟﻮد أﻣﺮ واﺣﺪ‪.‬‬

‫‪.3‬ب‪ .7.‬ﻗﻮاﻋﺪ اﻷوﻟﻮﻳﺔ ‪Precedence rules‬‬


‫إذا ﻇﻬــﺮ أﻛﺜــﺮ ﻣــﻦ ﻣــﺆﺛﺮ ﰱ ﺗﻌﺒــﲑ واﺣــﺪ ﻓــﺈن ﺗﺮﺗﻴــﺐ إﺟ ـﺮاء اﻟﻌﻤﻠﻴــﺎت ﻳــﺆﺛﺮ ﻟﻀــﺮورة ﻋﻠــﻰ اﻟﻨــﺎﺗﺞ و ﻟــﺬﻟﻚ وﺿــﻌﺖ ﻗﻮاﻋــﺪ‬
‫ﻷوﻟﻮ ت ﺗﻨﻔﻴﺬ اﳌﺆﺛﺮات اﳌﺨﺘﻠﻔﺔ‪ ،‬ﻣﺜﻼ‪:‬‬
‫‪3 + 5 * 2 is equivalent to 3 + (5 * 2 ) i.e. 13‬‬
‫ﳝﻜﻦ ﻟﻄﺒﻊ ﺗﻌﺪﻳﻞ ﻗﻮاﻋﺪ اﻷوﻟﻴﺔ ﺳﺘﺨﺪام اﻷﻗﻮاس اﻟﺪاﺋﺮﻳﺔ‪ ،‬ﻓﻠﺘﻌﺪﻳﻞ اﻟﺘﻌﺒﲑ اﻟﺴﺎﺑﻖ ﳝﻜﻦ أن ﻧﻜﺘﺐ‪:‬‬
‫‪(3 + 5) * 2‬‬ ‫‪which gives 16‬‬
‫ﻳــﺪل اﳌﺜــﺎل اﻟﺴــﺎﺑﻖ ﻋﻠــﻰ أن ﻋﻤﻠﻴــﺔ اﻟﻀــﺮب ﺗﺴــﺒﻖ داﺋﻤــﺎ ﻋﻤﻠﻴــﺔ اﳉﻤــﻊ ﻣــﺎ ﱂ ﺗــﺬﻛﺮ أﻗـﻮاس ﺻــﺮﳛﺔ ﺗﻌــﺪل ﻣــﻦ ﺗﺮﺗﻴــﺐ إﺟـﺮاء اﻟﻌﻤﻠﻴــﺎت‬
‫ﺣﻴــﺚ أن اﻟﻌﻤﻠﻴــﺎت ﺑــﺪاﺧﻞ اﻷﻗ ـﻮاس ﲡــﺮى داﺋﻤــﺎ ﻗﺒــﻞ اﺳــﺘﺨﺪام ﺗــﺞ اﻟﻘــﻮس ﰱ اﻟﻌﻤﻠﻴــﺔ اﻟﻜﺎﻣﻠــﺔ‪ .‬ﻫﻨــﺎك ‪ 15‬درﺟــﺔ ﻣــﻦ درﺟــﺎت‬
‫اﻷوﻟﻮﻳــﺔ ﻟﻠﻤــﺆﺛﺮات اﳌﺨﺘﻠﻔــﺔ‪ .‬إذا ﻇﻬــﺮ ﰱ ﻧﻔــﺲ اﻟﺘﻌﺒــﲑ ﻣــﺆﺛﺮﻳﻦ ﻣــﻦ ﻧﻔــﺲ درﺟــﺔ اﻷوﻟﻴــﺔ ﻓــﺈن ﺗﺮﺗﻴــﺐ إﺟـﺮاء اﻟﻌﻤﻠﻴــﺎت ﻳــﺘﻢ ﺑﱰﺗﻴــﺐ ورود‬
‫اﻟﺬﻛﺮ ﻣﻦ اﻟﻴﺴﺎر إﱃ اﻟﻴﻤﲔ‪ .‬ﻳﻠﺨﺺ اﳉﺪول اﻟﺘﺎﱃ درﺟﺎت اﻷوﻟﻮﻳﺔ ﳉﻤﻴﻊ اﳌﺆﺛﺮات ﲟﺎ ﰱ ذﻟﻚ ﻣﺎ ﱂ ﺗﺘﻢ دراﺳﺘﻪ ﺑﻌــﺪ و اﻟــﺬى ﻧــﻮردﻩ‬
‫ﻫﻨﺎ ﻟﻠﺤﺼﻮل ﻋﻠﻰ اﳉﺪول اﻟﻜﺎﻣﻞ‪:‬‬
‫)ﳝﻜﻦ اﳊﺼﻮل ﻋﻠﻰ ﻫﺬا اﳉﺪول ﺳﺘﺨﺪام اﳌﺴﺎﻋﺪ ‪ help‬اﳋﺎص ﳌﱰﺟﻢ اﳌﺴﺘﺨﺪم(‬

‫‪49‬‬
1. Highest () Function call
[] Array subscript
2. Unary ! Logical negation (NOT)
~ Bitwise (1's) complement
+ Unary plus
- Unary minus
++ Preincrement or postincrement
-- Predecrement or postdecrement
& Address
* Indirection
sizeof (returns size of operand, in bytes)
3. Multiplicative * Multiply
/ Divide
% Remainder (modulus)
4. Additive + Binary plus
- Binary minus
5. Shift << Shift left
>> Shift right
6. Relational < Less than
<= Less than or equal to
> Greater than
>= Greater than or equal to
7. Equality == Equal to
!= Not equal to
8. & Bitwise AND
9. ^ Bitwise XOR
10. | Bitwise OR
11. && Logical AND
12. || Logical OR
13. Conditional ?: (a ? x : y means "if a then x, else y")
14. Assignment = Simple assignment
*= Assign product
/= Assign quotient
%= Assign remainder (modulus)
+= Assign sum
-= Assign difference
&= Assign bitwise AND
^= Assign bitwise XOR
|= Assign bitwise OR
<<= Assign left shift
>>= Assign right shift
15. Comma

50
‫‪.3‬ج‪ .‬أواﻣﺮ اﻹدﺧﺎل و اﻹﺧﺮاج ‪Input / Output statements‬‬

‫‪.3‬ج‪ .1.‬اﻟﻘﺮاءة و اﻟﻜﺘﺎﺑﺔ اﳌﺸﻜﻠﺔ ‪formated input/output‬‬


‫ﺳﻨﺪرس أوﻻ أواﻣﺮ اﻟﻘﺮاءة اﻟﻌﺎﻣﺔ )ﳎﻤﻮﻋﺔ اﻟﺪوال ) (‪ (scanf‬و اﻟﻜﺘﺎﺑﺔ اﻟﻌﺎﻣﺔ )ﳎﻤﻮﻋﺔ اﻟــﺪوال ) (‪ (printf‬و ﻫــﻰ ﻣﻌﺮﻓــﺔ‬
‫ﰱ ﻣﻠــﻒ اﻟـﺮأس ‪ .stdio.h‬ﺗﺸــﻤﻞ اﺠﻤﻟﻤﻮﻋــﺔ ﻋــﺪة ﻋﻨﺎﺻــﺮ ﺗﺒﻌــﺎ ﻟﻨــﻮع اﻷداة اﻟــﱴ ﻧﻘـﺮأ ﻣﻨﻬــﺎ أو ﻧﻜﺘــﺐ ﻋﻠﻴﻬــﺎ ﻛﻤــﺎ ﻫــﻮ ﻣﻮﺿــﺢ ﳉــﺪول‬
‫اﻟﺘﺎﱃ‪:‬‬
‫ﻟﻠﻘﺮاءة ﻣﻦ ﻟﻮﺣﺔ اﳌﻔﺎﺗﻴﺢ‬ ‫(‪scanf‬‬ ‫)‪format_string, io_list‬‬
‫ﻟﻠﻘﺮاءة ﻣﻦ اﳌﻠﻒ ‪file‬‬ ‫‪fscanf(file‬‬ ‫)‪, format_string, io_list‬‬
‫ﻟﻠﻘﺮاءة ﻣﻦ اﳉﻤﻠﺔ ‪string‬‬ ‫)‪sscanf(string, format_string, io_list‬‬

‫ﻟﻠﻜﺘﺎﺑﺔ ﻋﻠﻰ اﻟﺸﺎﺷﺔ‬ ‫(‪printf‬‬ ‫)‪format_string, io_list‬‬


‫ﻟﻠﻜﺘﺎﺑﺔ ﻋﻠﻰ اﳌﻠﻒ ‪file‬‬ ‫‪fprintf(file‬‬ ‫)‪, format_string, io_list‬‬
‫ﻟﻠﻜﺘﺎﺑﺔ ﻋﻠﻰ اﳉﻤﻠﺔ ‪string‬‬ ‫)‪sprintf(string, format_string, io_list‬‬

‫ﰱ ﲨﻴﻊ اﻷﺣﻮال ﳚﺐ أن ﺗﺸﺘﻤﻞ راﻣﺎﺗﺮات اﻟﺪاﻟﺔ ﻋﻠﻰ ‪ io_list‬و ﻫﻰ ﻗﺎﺋﻤﺔ ﲰــﺎء ﺧــﺎ ت اﻟــﺬاﻛﺮة اﳌﻄﻠــﻮب وﺿــﻊ اﻟﺒﻴــﺎ ت اﻟــﱴ‬
‫ﺗﻘـﺮأ ﻓﻴﻬــﺎ أو أﺧــﺬ اﻟﺒﻴــﺎ ت اﻟــﱴ ﺗﻜﺘــﺐ ﻣﻨﻬــﺎ‪ .‬ﻻﺣــﻆ أن ﺧــﺎ ت اﻟــﺬاﻛﺮة ﳚــﺐ أن ﺗﻜــﻮن ﺑﻴــﺎ ت ﺑﺴــﻴﻄﺔ و ﻟﻴﺴــﺖ ﻣﺮﻛﺒــﺔ‪ .‬اﻻﺳــﺘﺜﻨﺎء‬
‫اﻟﻮﺣﻴﺪ ﻟﺬﻟﻚ ﻫﻮ ﰱ ﻛﺘﺎﺑﺔ اﳉﻤﻞ و ﻫﻮ أﻣﺮ ﻣﻨﻄﻘﻰ ﺣﻴﺚ أن اﳉﻤﻠﺔ ﲣﺘﻠﻒ ﻋﻦ ﻣﺘﺠﻪ اﳊــﺮوف ﰱ ﻛﻮ ــﺎ ﲢــﻮى ﻋﻼﻣــﺔ ﺎﻳــﺔ اﳉﻤﻠــﺔ‪،‬‬
‫و ﻟﺘ ــﺎﱃ ﻳﺴ ــﺘﻄﻴﻊ اﳊﺎﺳـ ــﺐ ﺑﺴ ــﻬﻮﻟﺔ أن ﻳﻜﺘ ــﺐ ﲨﻴ ــﻊ ﳏﺘﻮ ــﺎ ﻣ ــﻦ أول ﺣ ــﺮف ﺣ ــﱴ ﺣ ــﺮف ﺎﻳ ــﺔ اﳉﻤﻠ ــﺔ‪ .‬أﻣ ــﺎ ﲨﻠ ــﺔ اﻟﺘﺸـ ــﻜﻴﻞ‬
‫‪ format_string‬ﻓﻬــﻰ ﲢــﻮى ﺗﻌﻠﻴﻤــﺎت ﻋــﻦ أﺳــﻠﻮب اﻟﻜﺘﺎﺑــﺔ أو اﻟﻘـﺮاءة ﻣﺜــﻞ ﻋــﺪد اﳊـﺮوف أو اﻟﻔﺮاﻏــﺎت اﳌﺴــﺘﺨﺪﻣﺔ و اﻟﺒﺪاﻳــﺔ ﻣــﻦ‬
‫ﺳــﻄﺮ ﺟﺪﻳــﺪ أو اﻟﺒﻘــﺎء ﻋﻨــﺪ ﻧﻔــﺲ اﻟﺴــﻄﺮ ‪...‬اﱁ ﻣــﻦ ﺗﻌﻠﻴﻤــﺎت ﻛﻤــﺎ ﺳــﻨﺮى ﻟﺘﻔﺼــﻴﻞ ﻓﻴﻤــﺎ ﻳﻠــﻰ‪ .‬ﰱ اﻟﻨﻬﺎﻳــﺔ ﻻ ﲣﺘﻠــﻒ ﻫــﺬﻩ اﻟــﺪوال‬
‫اﻟﺴــﺘﺔ ﻋــﻦ ﺑﻌﻀــﻬﺎ اﻟــﺒﻌﺾ ﺳــﻮى ﰱ اﻟﻮﺳــﻴﻂ اﻟــﺬى ﺗﺘﻌﺎﻣــﻞ ﻣﻌــﻪ ﻗ ـﺮاءة أو ﻛﺘﺎﺑــﺔ‪ .‬إن إﺿــﺎﻓﺔ ﺣــﺮف ‪ f‬ﻗﺒــﻞ ‪ scanf, printf‬ﲡﻌــﻞ‬
‫اﻟﻮﺳﻴﻂ ﻫﻮ ﻣﻠﻒ‪ ،‬ﺑﻴﻨﻤﺎ إﺿﺎﻓﺔ ﺣﺮف ‪ s‬ﲡﻌﻞ اﻟﻮﺳﻴﻂ ﻫﻮ ﲨﻠﺔ ﳐﺰﻧﺔ ﰱ اﻟﺬاﻛﺮة‪.‬‬
‫رأﻳﻨﺎ ﻓﻴﻤﺎ ﺳﺒﻖ أﻣﺜﻠﺔ ﺑﺴﻴﻄﺔ ﻋﻠﻰ ﲨﻠﺔ اﻟﺘﺸﻜﻴﻞ ‪ format_string‬ﻧﻮرد ﻫﻨﺎ ﺑﻌﻀﺎ ﻣﻨﻬﺎ ﻟﻠﺘﻮﺿﻴﺢ‪:‬‬
‫‪int‬‬ ‫;‪i,j‬‬
‫‪long‬‬ ‫;‪m,n‬‬
‫‪float‬‬ ‫;‪a‬‬
‫;]‪double x,y,z[6‬‬
‫;]‪char c,name[20‬‬
‫;)‪scanf("%d %d", &i, &j‬‬
‫;)‪printf("The value of i=%3d \t j=%-4d\n",i,j‬‬
‫;)‪scanf("%ld %lg %lf %c %s",&m,&x,&z[3],&c,name‬‬
‫;)‪printf(" a=%f z[%d]=%11.4le \n %s\n",a,,j,z[j],name‬‬
‫ﻻﺣــﻆ أوﻻ أن أﲰــﺎء ﲨﻴــﻊ ﺧــﺎ ت اﻟــﺬاﻛﺮة ﰱ اﻟﻘـﺮاءة ﺗﺴــﺒﻘﻬﺎ ﻋﻼﻣــﺔ & ﻛﻤــﺎ ذﻛــﺮ آﻧﻔــﺎ و ﺳــﻨﺮﺟﺊ ﺷــﺮح اﻟﺴــﺒﺐ ﳌــﺎ ﺑﻌــﺪ ﺗﻌﺮﻳــﻒ‬
‫اﳌﺆﺷﺮات‪ .‬ﻻ ﻳﺴﺘﺜﲎ ﻣﻦ ذﻟﻚ ﺳﻮى اﳌﺘﻐﲑات اﻟﱴ ﲢﻮى ﲨﻠﺔ ﻓﻬﻰ ﺗﻜﺘﺐ ﺑﺪون ﻫﺬﻩ اﻟﻌﻼﻣﺔ‪.‬‬

‫‪51‬‬
‫ﰱ أول أﻣــﺮ ﻗـﺮاءة ﰱ اﳌﺜــﺎل اﻟﺴــﺎﺑﻖ ﻳﻮﺿــﺢ اﻟﺮﻣــﺰ ‪ %d‬أن اﳌﻄﻠــﻮب ﻗـﺮاءة ﻋــﺪد ﺻــﺤﻴﺢ ﻟﻨﻈــﺎم اﻟﻌﺸــﺮى )‪ (d=decimal‬و‬
‫ﻗــﺪ ﺗﻜــﺮر ﻫــﺬا اﻟﺮﻣــﺰ ﻣـﺮﺗﲔ أى ﺑﻌـﺪد اﳌﺘﻐـﲑات اﳌﻄﻠــﻮب ﻗﺮاء ــﺎ )ﰱ ﻫــﺬﻩ اﳊﺎﻟــﺔ ‪ .(i,j‬ﰱ أول أﻣــﺮ ﻟﻠﻜﺘﺎﺑــﺔ ﻇﻬــﺮت أوﻻ ﻛﻠﻤــﺎت ﻣﺜــﻞ‬
‫=‪ The value of i‬و ﻫــﻰ ﺗﻜﺘــﺐ ﻛﻤــﺎ ﻫــﻰ ﻋﻠــﻰ اﻟﺸﺎﺷــﺔ ﰒ ﻳﺘﺒﻌﻬــﺎ ﻣﻌــﺮف ﻷﺳــﻠﻮب ﻛﺘﺎﺑــﺔ اﳌﺘﻐــﲑ ‪ i‬و ﻫــﻮ ﻫﻨــﺎ أﻳﻀــﺎ ﻋــﺪد ﺻــﺤﻴﺢ‬
‫ﻋﺸﺮى و ﻟﻜﻦ أﺿﻴﻒ اﻟﺮﻗﻢ ‪ 3‬ﻟﻠﺪﻻﻟﺔ ﻋﻠﻰ أن اﳌﻄﻠﻮب وﺿــﻊ اﻟــﺮﻗﻢ ﰱ ‪ 3‬ﺧــﺎ ت أﺛﻨــﺎء اﻟﻜﺘﺎﺑــﺔ‪ .‬ﻓــﺈذا ﻛــﺎن ﳏﺘــﻮى ‪ i‬ﻫــﻮ اﻟﻌــﺪد ‪12‬‬
‫ﻣﺜﻼ ﺳﻴﱰك ﻓﺮاغ واﺣﺪ ﻗﺒﻞ ﻛﺘﺎﺑﺘﻪ‪ .‬أﻣﺎ إذا ﻛﺎن ﳏﺘﻮى ‪ i‬ﰱ ﻫﺬﻩ اﻟﻠﺤﻈﺔ ﻫــﻮ ‪ 1027‬ﻓﻠــﻦ ﻳﻠﺘﻔــﺖ ﻟﻠــﺮﻗﻢ ‪ 3‬و ﺳــﻴﻜﺘﺐ ﳏﺘــﻮى اﳌﺘﻐــﲑ‬
‫ﻋﻠﻰ ‪ 4‬ﺧﺎ ت‪ .‬ﻧﻔﺲ اﻟﺸﻰء ﺣﺪث ﻣﻊ اﳌﺘﻐﲑ ‪ j‬و ﻟﻜﻨﻨﺎ ﰱ ﻫﺬﻩ اﳊﺎﻟﺔ ﻃﻠﺒﻨﺎ اﻟﻜﺘﺎﺑﺔ ﻋﻠﻰ ‪ 4‬ﺧﺎ ت ﻋﻠﻰ أن ﻳﺒــﺪأ أول ﺣــﺮف ﻣــﻦ‬
‫اﻟﻴﺴﺎر ﻣﺒﺎﺷﺮة )وذﻟﻚ ﺑﻮاﺳﻄﺔ اﻹﺷﺎرة اﻟﺴﺎﻟﺒﺔ(‪ .‬أى إذا ﻛﺎن اﶈﺘﻮى ﻫﻮ ‪ 5‬ﻣــﺜﻼ ﻓﺴــﻴﻜﺘﺐ اﻟــﺮﻗﻢ ‪ 5‬ﻳﻠﻴــﻪ ‪ 3‬ﻣﺴــﺎﻓﺎت ﻗﺒــﻞ ﻛﺘﺎﺑــﺔ أى‬
‫ﺷــﺊ آﺧــﺮ‪ .‬ﺑــﺪون اﻹﺷــﺎرة اﻟﺴــﺎﻟﺒﺔ ﻛــﺎن ﺳــﻴﺒﺪأ ﺑﻜﺘﺎﺑــﺔ ‪ 3‬ﻣﺴــﺎﻓﺎت ﻗﺒــﻞ ﻛﺘﺎﺑــﺔ اﻟــﺮﻗﻢ ‪ .5‬اﻹﺷــﺎرة اﻟﺴــﺎﻟﺒﺔ ﻫــﻰ واﺣــﺪة ﻣــﻦ ﻣﻌــﺪﻻت‬
‫أﺳﻠﻮب اﻟﻜﺘﺎﺑﺔ اﻟﱴ ﺳﻨﺸﺮﺣﻬﺎ ﰱ اﻟﻔﻘﺮة اﻟﺘﺎﻟﻴﺔ‪ .‬اﻟﻌﻼﻣﺔ ‪ \t‬ﺗﻌــﲎ اﳉﺪوﻟــﺔ ‪ tabulation‬أى اﻟﻘﻔــﺰ إﱃ ﺧﺎﻧــﺔ اﳉﺪوﻟــﺔ اﻟﺘﺎﻟﻴــﺔ‪ .‬ﻋــﺎدة ﻣــﺎ‬
‫ﺗﻜﻮن ﺧﺎ ت اﳉﺪوﻟﺔ ﻣﻌﺮﻓﺔ ﻛﻞ ﲦﺎﻧﻴﺔ ﺣﺮوف ﻋﻠﻰ اﻟﺴــﻄﺮ‪ .‬أﻣــﺎ اﻟﻌﻼﻣــﺔ ‪ \n‬ﻓﺘﻌــﲎ اﻻﻧﺘﻘــﺎل ﻟﺴــﻄﺮ ﺟﺪﻳــﺪ ﺑﻌــﺪ اﻻﻧﺘﻬــﺎء ﻣــﻦ اﻟﻜﺘﺎﺑــﺔ‪.‬‬
‫ﺑــﺪون ﻫــﺬﻩ اﻟﻌﻼﻣــﺔ ﻓﺴــﻴﻨﻔﺬ أﻣــﺮ اﻟﻜﺘﺎﺑــﺔ اﻟﺘــﺎﱃ ﻋﻠــﻰ ﻧﻔــﺲ اﻟﺴــﻄﺮ‪ .‬أﻣــﺮ اﻟﻘ ـﺮاءة اﻟﺜــﺎﱏ أﺿــﺎف ﺑﻌــﺾ اﻟﻌﻼﻣــﺎت اﳉﺪﻳــﺪة ﻣﺜــﻞ ‪%ld‬‬
‫ﻟﻠﺘﻌﺎﻣﻞ ﻣﻊ اﻷﻋﺪاد اﻟﺼﺤﻴﺤﺔ اﻟﻌﺸﺮﻳﺔ اﻟﻄﻮﻳﻠﺔ )ﻣﻦ ﻧﻮع ‪ .(long‬ﻫﻨﺎك ﺣﺮوف أﺧﺮى ﺳــﲑد ذﻛﺮﻫــﺎ ﻟﺘﻔﺼــﻴﻞ ﰱ اﳉــﺪول اﻟﺘــﺎﱃ‪ ،‬ﻣــﺎ‬
‫ﻳﻌﻨﻴﻨﺎ ﻫﻨﺎ ﻫﻮ إﻋﻄﺎء ﺑﻌﺾ اﻷﻣﺜﻠﺔ ﻟﻠﺘﻮﺿﻴﺢ‪ .‬ﻻﺣﻆ أﻧﻨﺎ ﻻ ﳝﻜﻦ أن ﻧﻘﺮأ ﻣﺘﺠﻪ ﻟﻜﺎﻣﻞ و ﻟﻜــﻦ ﳝﻜــﻦ ﻗـﺮاءة ﻋﻨﺼــﺮ ﻣﻨــﻪ ﻣﺜــﻞ ]‪.z[3‬‬
‫و ﰱ أﻣﺮ اﻟﻜﺘﺎﺑﺔ اﻷﺧﲑ ﻻﺣﻆ أﻳﻀﺎ أن اﻟﻌﻼﻣﺔ ‪ \n‬ﻇﻬﺮت ﻣـﺮﺗﲔ‪ .‬اﳌــﺮة اﻷوﱃ ﺑــﺪاﺧﻞ اﻟﺴــﻴﺎق و ﺗــﺆدى ﻟﻼﻧﺘﻘــﺎل ﻟﺴــﻄﺮ ﺟﺪﻳــﺪ ﺑﻌــﺪ‬
‫ﻛﺘﺎﺑــﺔ ﳏﺘــﻮى ]‪ z[j‬و ﻗﺒــﻞ ﻛﺘﺎﺑــﺔ ﳏﺘــﻮى ‪ .name‬ﰱ اﳌــﺮة اﻟﺜﺎﻧﻴــﺔ ﻟﻈﻬــﻮر اﻟﻌﻼﻣــﺔ ‪ \n‬ﻧﻨﺘﻘــﻞ ﻟﺴــﻄﺮ ﺟﺪﻳــﺪ ﺑﻌــﺪ اﻻﻧﺘﻬــﺎء ﻣــﻦ ﺗﻨﻔﻴــﺬ أﻣــﺮ‬
‫اﻟﻜﺘﺎﺑﺔ‪.‬‬

‫‪.3‬ج‪ .2.‬ﻣﻌﺮف أﺳﻠﻮب اﻟﻜﺘﺎﺑﺔ أو اﻟﻘﺮاءة ‪format specifier‬‬


‫أى ﻣﻌﺮف ﻷﺳﻠﻮب اﻟﻜﺘﺎﺑﺔ ‪ printf format specifier‬ﻳﻜﺘﺐ ﻋﻠﻰ اﻟﺼﻮرة اﻟﻌﺎﻣﺔ‪:‬‬
‫‪%«flag»«width»«.prec»«modifier»type_char‬‬
‫)ﺗــﺪل اﻟﻌﻼﻣــﺎت »« ﻋﻠــﻰ أن ﻣــﺎ ﺑــﺪاﺧﻠﻬﺎ ﻟــﻴﺲ إﺟﺒــﺎر ‪ .‬إن وﺿــﻊ ﺷــﻰء ﻣﻜﺎ ــﺎ ﺳــﻴﺆﺧﺬ ﰱ اﻻﻋﺘﺒــﺎر و إن اﺧﺘﻔــﻰ ﻓﺴﻴﻀــﻊ اﳌــﱰﺟﻢ‬
‫ﻣﻜﺎﻧﻪ ﻗﻴﻤﺔ ﻣﻨﺎﺳﺒﺔ(‬
‫ﺣﻴﺚ ‪ flag‬ﳝﻜﻦ أن ﺗﻜﻮن‪:‬‬
‫‪ -‬و ﺗﻌﲎ أﻛﺘﺐ اﶈﺘﻮى ﺑﺪءا ﻣﻦ اﻟﻴﺴﺎر ﰒ أﺗﺮك ﻓﺮاﻏﺎت إن وﺟﺪت ﻋﻠﻰ اﻟﻴﻤﲔ‪.‬‬
‫‪ +‬و ﺗﻌﲎ أﻛﺘﺐ ﻋﻼﻣﺔ ‪ +‬ﻗﺒﻞ اﻷﻋﺪاد اﳌﻮﺟﺒﺔ‬
‫)اﳌﺴﺎﻓﺔ( ﺗﻌﲎ أﻛﺘﺐ ﻣﺴﺎﻓﺔ ﻗﺒﻞ اﻷﻋﺪاد اﳌﻮﺟﺒﺔ‬
‫‪ #‬ﺗﻌﺪل ﻣﻦ أﺳﻠﻮب اﻟﻜﺘﺎﺑﺔ ﲝﻴﺚ ﺗﻀﻊ اﻟﻌﻼﻣﺔ ‪ 0‬ﻗﺒﻞ اﻷرﻗﺎم اﻟﺜﻤﺎﻧﻴﺔ أو ‪ 0x‬ﻗﺒﻞ اﻷﻋﺪاد ﻟﻸﺳﺎس ‪ .16‬أﻣــﺎ ﻟﻨﺴــﺒﺔ ﻟﻸﻋــﺪاد‬
‫اﳊﻘﻴﻘﻴﺔ ﻓﺘﻀﻴﻒ اﻟﻌﻼﻣﺔ اﻟﻌﺸﺮﻳﺔ ﺣﱴ ﻟﻮ ﱂ ﻳﻜﻦ اﻟﻌﺪد ﻛﺴﺮ ‪.‬‬

‫أﻣــﺎ ‪ width‬أو اﻟﻌــﺮض ﻓﻬــﻮ ﻋــﺪد ﺻــﺤﻴﺢ ﻳﻌــﱪ ﻋــﻦ اﳊــﺪ اﻷدﱏ ﻣــﻦ اﳊـﺮوف اﳌﺨﺼﺼــﺔ ﻟﻜﺘﺎﺑــﺔ اﶈﺘــﻮى‪ .‬ﻓــﺈذا ﻛــﺎن اﶈﺘــﻮى أﻛــﱪ ﻣــﻦ‬
‫ذﻟــﻚ ﻳﻜﺘــﺐ ﻛــﺎﻣﻼ ﺑﺼــﺮف اﻟﻨﻈــﺮ ﻋــﻦ ﻗﻴﻤــﺔ ‪ width‬أﻣــﺎ إذا ﻛــﺎن أﺻــﻐﺮ ﻣــﻦ ذﻟــﻚ ﻓﻴﺴــﺘﻜﻤﻞ اﻟﻔــﺎرق ﺑﻔﺮاﻏــﺎت‪ .‬ﳝﻜــﻦ أن ﻳﺴــﺘﻜﻤﻞ‬
‫اﻟﻔﺎرق ﺻﻔﺎر ﻋﻠﻰ اﻟﻴﺴﺎر إذا ﺑﺪأ اﻟﻌﺮض ‪ width‬ﻟﺮﻗﻢ ‪) 0‬ﻣﺜﻼ ‪ .(06‬إذا ﱂ ﻧﻀﻊ ﺷﻴﺌﺎ ﰱ ﻫﺬﻩ اﳋﺎﻧــﺔ ﻓﻬﻨــﺎك داﺋﻤــﺎ ﻋــﺪد ﻣﻌــﺮف‬
‫ﺿﻤﻨﻴﺎ ‪ by default‬ﻳﻀﻌﻪ اﳌﱰﺟﻢ ﻳﻨﺎﺳﺐ ﻛﻞ ﻣﺘﻐﲑ‪.‬‬

‫‪52‬‬
‫‪ prec‬ﺗﻌــﲎ اﻟﺪﻗــﺔ اﳌﻄﻠﻮﺑــﺔ ﰱ إﺧـﺮاج اﻟﻌــﺪد‪ .‬ﻳﺒــﺪأ داﺋﻤــﺎ ﻟﻨﻘﻄــﺔ ﻟﺘﻤﻴﻴــﺰﻩ ﻋــﻦ اﻟﻌــﺪد اﻟﺴــﺎﺑﻖ و اﳌﻌــﱪ ﻋــﻦ ‪ .width‬ﰱ ﺣﺎﻟــﺔ اﻷﻋــﺪاد‬
‫اﳊﻘﻴﻘﺔ ﻓﺈﻧﻪ ﻳﻌﱪ ﻋﻦ ﻋﺪد اﻷرﻗﺎم اﳌﻄﻠﻮب ﻛﺘﺎﺑﺘﻬﺎ ﺑﻌﺪ اﻟﻌﻼﻣﺔ اﻟﻌﺸﺮﻳﺔ‪ .‬ﻓﺈذا ﻛﺘﺒﻨــﺎ ﻣــﺜﻼ ‪ %6.2f‬ﻛــﺎن ذﻟــﻚ ﻳﻌــﲎ أن اﳌﻄﻠــﻮب ﻛﺘﺎﺑــﺔ‬
‫ﻋ ــﺪد ﺣﻘﻴﻘــﻰ ﻋﻠ ــﻰ ‪ 6‬ﺧــﺎ ت ﲝﻴ ــﺚ ﺗﻜ ــﻮن ﻫﻨــﺎك ﺧﺎﻧﺘ ــﺎن ﺑﻌ ــﺪ اﻟﻌﻼﻣــﺔ اﻟﻌﺸ ـﺮﻳﺔ‪ .‬ﳝﻜ ــﻦ أﻳﻀــﺎ ﲢﺪﻳ ــﺪ اﻟﺪﻗ ــﺔ ﺑــﺪون ﲢﺪﻳ ــﺪ اﻟﻄ ــﻮل‬
‫اﻹﲨــﺎﱃ‪ .‬ﰱ ﻫــﺬﻩ اﳊﺎﻟــﺔ ﺧــﺬ اﻟﻌــﺪد ﻃــﻮﻻ ﻣﻌــﺮف ﺿــﻤﻨﻴﺎ ‪ default‬ﻳﻌﺘﻤــﺪ ﻋﻠــﻰ ﻧــﻮع اﻟﻌــﺪد )ﰱ ﺣﺎﻟــﺔ ‪ int‬ﻣــﺜﻼ اﻟﻄــﻮل ‪ 1‬أﻣــﺎ ﰱ‬
‫ﺣﺎﻟﺔ ‪ float‬ﻓﺈﻧﻪ ‪ .(6‬و ﻻ ﻳﺘﻘﻴﺪ اﳌﱰﺟﻢ ﺳــﻮى ﺑﻌــﺪد اﻷرﻗــﺎم ﺑﻌــﺪ اﻟﻌﻼﻣــﺔ اﻟﻌﺸـﺮﻳﺔ اﻟــﺬى ﻧﻌﻄﻴــﻪ ﺻـﺮاﺣﺔ‪ .‬إذا ﱂ ﻧﻮﺿــﺢ ﺷــﻴﺌﺎ ﰱ ﻫــﺬﻩ‬
‫اﳋﺎﻧﺔ ﻓﺴﻴﻘﻮم اﳌﱰﺟﻢ ﺑﻮﺿﻊ ﻗﻴﻤﺔ ﻣﻨﺎﺳﺒﺔ‪.‬‬

‫اﳉﺰء ‪ type_char‬ﻫﻮ اﻟﻮﺣﻴﺪ اﻹﺟﺒﺎرى ﰱ ﲨﻠﺔ اﻟﺘﺸﻜﻴﻞ ﻹﺿﺎﻓﺔ ﻟﻠﻌﻼﻣﺔ ‪ %‬ﰱ ﺑﺪاﻳﺔ اﳉﻤﻠﺔ‪ .‬و ﻫﻮ ﻳﺘﻌﻠﻖ ﺳﻠﻮب ﻛﺘﺎﺑﺔ‬
‫اﻟﻌﺪد ﻛﻤﺎ ﻳﻮﺿﺢ اﳉﺪول اﻟﺘﺎﱃ‪:‬‬
‫‪ d or i‬ﺗﻌﲎ ﻋﺪد ﺻﺤﻴﺢ ﻋﺸﺮى ﻗﺪ ﻳﻜﻮن ﻣﻮﺟﺒﺎ أو ﺳﺎﻟﺒﺎ‬
‫ﺗﻌﲎ ﻋﺪد ﺻﺤﻴﺢ ﻣﻮﺟﺐ ﻟﻸﺳﺎس ‪8‬‬ ‫‪o‬‬
‫ﺗﻌﲎ ﻋﺪد ﺻﺤﻴﺢ ﻣﻮﺟﺐ ﻟﻸﺳﺎس ‪10‬‬ ‫‪u‬‬
‫ﺗﻌﲎ ﻋﺪد ﺻﺤﻴﺢ ﻣﻮﺟﺐ ﻟﻸﺳﺎس ‪ 16‬ﻣﺴﺘﺨﺪﻣﺎ اﻷرﻗﺎم اﻟﻌﺸﺮﻳﺔ ﻹﺿﺎﻓﺔ ﻟﻠﺤﺮوف ‪a,b,c,d,e,f‬‬ ‫‪x‬‬
‫ﺗﻌﲎ ﻋﺪد ﺻﺤﻴﺢ ﻣﻮﺟﺐ ﻟﻸﺳﺎس ‪ 16‬ﻣﺴﺘﺨﺪﻣﺎ اﻷرﻗﺎم اﻟﻌﺸﺮﻳﺔ ﻹﺿﺎﻓﺔ ﻟﻠﺤﺮوف ‪A,B,C,D,E,F‬‬ ‫‪X‬‬
‫ﺗﻌﲎ ﻋﺪد ﺣﻘﻴﻘﻰ ﻣﻜﺘﻮب ﻟﺼﻮرة اﻟﻌﺎدﻳﺔ أى ﻛﺴﺮ ﺑﻌﻼﻣﺔ ﻋﺸﺮﻳﺔ‬ ‫‪f‬‬
‫ﺗﻌﲎ ﻋﺪد ﺣﻘﻴﻘﻰ ﻣﻜﺘﻮب ﰱ ﺻﻮرة ﻋﺪد ﻛﺴﺮى ﻣﻀﺮو ﰱ ‪ 10‬ﻣﺮﻓﻮﻋﺔ ﻷس ﺻﺤﻴﺢ‬ ‫‪e, E‬‬
‫ﺗﻌﲎ ﻋﺪد ﺣﻘﻴﻘﻰ ﻣﻜﺘﻮب ى ﻣﻦ اﻟﺼﻮرﺗﲔ اﻟﺴﺎﺑﻘﺘﲔ أﻳﻬﻤﺎ أﻧﺴﺐ ﻟﻘﻴﻤﺘﻪ‬ ‫‪g, G‬‬
‫ﺗﻌﲎ ﺣﺮﻓﺎ‬ ‫‪c‬‬
‫ﺗﻌﲎ ﲨﻠﺔ‬ ‫‪s‬‬
‫ﺗﻌﲎ ﻛﺘﺎﺑﺔ اﳊﺮف ‪ %‬ﻛﻤﺎ ﻫﻮ‬ ‫‪%‬‬

‫أﻣــﺎ اﳉــﺰء ‪ modifier‬ﻣــﻦ اﻟﺘﻌﺮﻳــﻒ ﻓﻴﺘﻌﻠــﻖ ﻟﺼــﻮرة اﻟــﱴ ﺧــﺰن ﻋﻠﻴﻬــﺎ اﳌﺘﻐــﲑ اﳌﻄﻠــﻮب اﻟﻜﺘﺎﺑــﺔ ﻣﻨــﻪ‪ .‬ﻓــﺈذا وﺿــﻌﻨﺎ ﻓﻴــﻪ اﳊــﺮف ‪ l‬ﻗﺒــﻞ‬
‫اﳊــﺮوف ‪ d, i, o, u, x‬ﻣــﻦ ‪ type_char‬ﻛــﺎن ﻣﻌــﲎ ذﻟــﻚ أﻧﻨــﺎ ﺑﺼــﺪد اﻟﻜﺘﺎﺑــﺔ ﻣــﻦ ﺧﺎﻧــﺔ ذاﻛــﺮة ﻣــﻦ ﻧــﻮع ‪ .long‬أﻣــﺎ اﺧﺘﻔﺎﺋــﻪ ﻓﻴﻌــﲎ‬
‫أﻧﻨﺎ ﺑﺼﺪد اﻟﻜﺘﺎﺑﺔ ﻣﻦ ﺧﺎﻧﺔ ذاﻛﺮة ‪ .int‬ﻧﻔﺲ اﳊﺮف ‪ l‬إذا ﻇﻬـﺮ ﻗﺒــﻞ اﳊــﺮوف ‪ e,E,f,g,G‬ﻣــﻦ ‪ type_char‬ﻓﺈﻧــﻪ ﻳﻌــﲎ أﻧﻨــﺎ ﺑﺼــﺪد‬
‫اﻟﻜﺘﺎﺑﺔ ﻣﻦ ﺧﺎﻧﺔ ذاﻛﺮة ﻣﻦ ﻧﻮع ‪ .double‬أﻣﺎ إذا اﺧﺘﻔﻰ ﻓﻴﻌﲎ أن اﳋﺎﻧﺔ ﻣﻦ ﻧﻮع ‪.float‬‬

‫ﻟﻨﺴﺒﺔ ﳉﻤﻠﺔ اﻟﺘﺸﻜﻴﻞ ﰱ أﻣﺮ اﻟﻘﺮاءة ﻓﻼ ﲣﺘﻠﻒ إﻻ ﺑﺼﻮرة ﻃﻔﻴﻔﺔ ﻋﻦ أﻣﺮ اﻟﻜﺘﺎﺑﺔ‪ ،‬ﺣﻴﺚ ﺗﻈﻬﺮ ﻋﻠﻰ اﻟﺼﻮرة اﻟﻌﺎﻣﺔ‪:‬‬
‫‪%«*»«width»« modifier» type_char‬‬
‫اﳋﺎ ت اﻟﺜﻼﺛﺔ اﻷﺧﲑة ‪ width‬و ‪ modifier‬و ‪ type_char‬ﳍﺎ ﻧﻔﺲ اﳌﻌﲎ اﻟﺴﺎﺑﻖ و ﻻ ﻳﺰﻳﺪ ﻫﻨــﺎ ﺳــﻮى اﻟﻌﻼﻣــﺔ اﳉﺪﻳــﺪة و ﻫــﻰ‬
‫اﻟﻨﺠﻤــﺔ *‪ .‬ﺗﻌــﲎ اﻟﻨﺠﻤــﺔ أن اﳌﻄﻠــﻮب ﻗـﺮاءة ﻣﻌﻠﻮﻣــﺔ ﻣــﻦ وﺳــﻴﻠﺔ اﻹدﺧــﺎل ﺑــﺪون ﻛﺘﺎﺑﺘﻬــﺎ ﰱ أﻳــﺔ ﺧﺎﻧــﺔ ﻣــﻦ ﺧــﺎ ت اﻟــﺬاﻛﺮة‪ .‬ﺗﺴــﺘﺨﺪم‬
‫ﻫﺬﻩ اﻟﻌﻼﻣﺔ إذا ﻛﻨﺎ ﻣﺜﻼ ﻧﺮﻳﺪ أن ﻧﻘﺮأ اﻟﻌﺪد اﻟﺜﺎﱏ ﻓﻘﻂ ﻣــﻦ ﺳــﻄﺮ ﻣــﻦ ﺳــﻄﻮر ﻣﻠــﻒ و ﻻ ﻳﻌﻨﻴﻨــﺎ ﰱ ﺷــﺊ اﻟﻌــﺪد اﻷول‪ .‬ﰱ ﻫــﺬﻩ اﳊﺎﻟــﺔ‬
‫ﳝﻜﻦ أن ﻧﻜﺘﺐ‪:‬‬
‫‪scanf("%*d %d",&j).‬‬
‫‪53‬‬
‫ﻟﻨﺴــﺒﺔ ﻟﻠﺨﺎﻧــﺔ ‪ type_char‬ﻓﻬــﻰ ﳝﻜــﻦ أن ﺗﺘﻜــﻮن ﻣــﻦ ﻧﻔــﺲ اﳊــﺮوف اﻟـﻮاردة أﻋــﻼﻩ و ﺗﻌــﲎ ﻧﻔــﺲ اﳌﻌــﲎ ﻣـﺎ ﻋــﺪا اﳊــﺮف ‪s‬‬
‫اﻟــﺬى ﳜﺘﻠــﻒ ﻣﻌﻨــﺎﻩ ﺑﺼــﻮرة ﻃﻔﻴﻔــﺔ‪ .‬ﻓﺎﳌﻘﺼــﻮد ﻫﻨــﺎ ﻗـﺮاءة ﲨﻠــﺔ ﺗﻨﺘﻬــﻰ ﳌﺴــﺎﻓﺔ ‪ space‬و ﻧﻀــﻊ ﰱ اﳌﺘﻐــﲑ اﻟــﺬى ﻳﺘﻠﻘــﻰ اﳉﻤﻠــﺔ اﳊــﺮف‬
‫'‪ '\0‬ﰱ ﺎﻳــﺔ ﻋﻤﻠﻴــﺔ اﻟﻘـﺮاءة‪ .‬أﻣــﺎ إذا أرد أن ﳔﻄــﺮ اﳊﺎﺳــﺐ أن اﳉﻤﻠــﺔ ﻗــﺪ ﲢــﻮى ﻣﺴــﺎﻓﺎت و ﻟﻜﻨﻬــﺎ ﺗﻨﺘﻬــﻰ ﺑﻈﻬــﻮر أى ﺣــﺮف آﺧــﺮ‬
‫ﻓﻴﻤﻜﻦ ﻋﻤﻞ ذﻟﻚ ﻛﺎﻵﺗﻰ‪ .‬ﻧﻀﻊ ﺑﲔ ﻗﻮﺳﲔ ﻣﺮﺑﻌﲔ ﻗﺎﺋﻤﺔ ﺑﻜﺎﻓﺔ اﳊﺮوف اﻟــﱴ ﳝﻜــﻦ أن ﲢﻮﻳﻬــﺎ اﳉﻤﻠــﺔ اﻟــﱴ ﻧﺮﻳــﺪ أن ﻧﻘﺮأﻫــﺎ‪ .‬ﻓــﺈذا ﻗـﺮأ‬
‫اﳊﺎﺳﺐ أى ﺣﺮف آﺧﺮ ﻏﲑ ﻣﻮﺟﻮد ﻟﻘﺎﺋﻤﺔ اﻋﺘﱪ ذﻟﻚ ﺧﺎﲤﺔ ﻟﻠﺠﻤﻠﺔ‪:‬‬
‫;]‪char phrase[50‬‬
‫;)‪scanf("%[ ABCDEFGHIJKLMNOPQRSTUVWXYZ]",phrase‬‬
‫ﰱ ﻫﺬا اﳌﺜﺎل ﺗﻌﺘﱪ ﻛﻞ اﳊــﺮوف اﻟﻜﺒــﲑة أو اﳌﺴــﺎﻓﺔ ﺟــﺰء ﻣــﻦ اﳉﻤﻠــﺔ و ﻻ ﺗﺘﻮﻗــﻒ اﻟﻘـﺮاءة إﻻ ﻋﻨــﺪ اﻟﻮﺻــﻮل ﳊــﺮف ﻏــﲑ وارد ﰱ اﻟﻘﺎﺋﻤــﺔ‬
‫ﻣﺜﻞ اﳊﺮوف اﻟﺼﻐﲑة أو اﻟﻔﺎﺻﻠﺔ ‪...‬اﱁ‪ .‬ﳝﻜــﻦ أﻳﻀــﺎ ﻛﺘﺎﺑــﺔ اﻟﻘﺎﺋﻤــﺔ ﺑﺼــﻮرة ﻋﻜﺴــﻴﺔ أى ﻗﺎﺋﻤــﺔ اﳊــﺮوف اﻟــﱴ ﻻ ﺗﻨﺘﻤــﻰ ﻟﻠﺠﻤﻠــﺔ و اﻟــﱴ‬
‫ﳚﺐ أن ﺗﺘﻮﻗﻒ ﻋﻨﺪﻫﺎ ﻋﻤﻠﻴﺔ اﻟﻘﺮاءة و ذﻟﻚ ﺳﺘﺨﺪام اﻟﺮﻣﺰ ^‪:‬‬
‫;)‪char phrase[50]; scanf("%[^\n,]",phrase‬‬
‫ﰱ ﻫﺬﻩ اﳊﺎﻟﺔ ﺗﻌﺘﱪ ﲨﻴﻊ اﳊﺮوف اﻟﱴ ﺗﻘﺮأ ﺟﺰء ﻣﻦ اﳉﻤﻠﺔ إﱃ أن ﻧﺼﻞ ﻟﻨﻬﺎﻳﺔ اﻟﺴﻄﺮ أو ﻟﻔﺎﺻﻠﺔ‪.‬‬
‫ﺑﻌــﺪ أن اﺳﺘﻌﺮﺿــﻨﺎ ﻛﻴﻔﻴــﺔ ﲢﺪﻳــﺪ ﺎﻳــﺔ اﻟﺒﻴــﺎ ت اﻟــﱴ ﲣــﺺ ﻣﺘﻐــﲑ ﻣــﻦ ﻧــﻮع اﳉﻤﻠــﺔ ﻓــﺈن ﺣﺎﻟــﺔ اﳌﺘﻐ ـﲑات ذات اﻷﻧ ـﻮاع اﻷﺧــﺮى‬
‫ﺗﻜﻮن أﻳﺴﺮ‪ .‬ﺑﺼﻮرة ﻋﺎﻣﺔ‪ ،‬ﺗﻨﺘﻬﻰ اﻟﺒﻴﺎ ت اﻟﱴ ﺗﺘﻌﻠــﻖ ﲟﺘﻐــﲑ ﻣــﻦ ﻧــﻮع ﻣــﺎ ﺑﻈﻬــﻮر ﺣــﺮف ﰱ اﻟﺒﻴــﺎ ت ﻣــﻦ ﻧــﻮع ﻻ ﻳﻨﺘﻤــﻰ ﻟﻠﺤــﺮوف اﻟــﱴ‬
‫ﳝﻜﻦ أن ﺗﺼﻒ اﳌﺘﻐﲑ‪ .‬ﻣﺜﻼ إذا ﻛﺎن اﳌﺘﻐﲑ اﻟﺬى ﻧﻘﺮأﻩ ﻣﻦ ﻧﻮع ‪ float‬ﻓﺈن ﻇﻬﻮر اﳌﺴﺎﻓﺔ أو ﺣــﺮف ﺎﻳــﺔ ﲨﻠــﺔ أو ﺎﻳــﺔ ﻣﻠــﻒ ﻳــﺆدى‬
‫ﻻﻋﺘﺒﺎر أن اﻟﺒﻴــﺎ ت ﻗــﺪ ﰎ إدﺧﺎﳍــﺎ‪ .‬إذا ﻛــﺎن ﻟــﺪﻳﻨﺎ أﻛﺜــﺮ ﻣــﻦ ﻣﺘﻐــﲑ ﻣﻄﻠــﻮب ﻗـﺮاءة ﳏﺘــﻮ ﻢ ﳝﻜــﻦ أن ﻳﺜــﺎر اﻟﺴـﺆال اﻟﺘــﺎﱃ‪ :‬ﻣــﱴ ﻳﻌــﺮف‬
‫اﳊﺎﺳﺐ أن اﻟﺒﻴﺎ ت اﻟــﱴ ﻧــﺪﺧﻠﻬﺎ ﻟﻘـﺮاءة ﻣﺘﻐــﲑ ﻣــﺎ ﻗــﺪ اﻧﺘﻬــﺖ‪ ،‬و أن اﻟﺒﻴــﺎ ت اﻟﺘﺎﻟﻴــﺔ ﲣــﺺ اﳌﺘﻐــﲑ اﻟﺘــﺎﱃ؟ اﻹﺟﺎﺑــﺔ ﻋﻠــﻰ ﻫــﺬا اﻟﺴـﺆال‬
‫ﺗﻜﻤﻦ ﰱ ﲨﻠﺔ اﻟﺘﺸﻜﻴﻞ ذا ﺎ‪ .‬ﻓﺈذا ﻛﺎﻧﺖ ﻫﻨﺎك ﺣﺮوف ﺗﻔﺼﻞ ﺑﲔ ﻋﻨﺎﺻــﺮ ﲨﻠــﺔ اﻟﺘﺸــﻜﻴﻞ )ﲟــﺎ ﰱ ذﻟــﻚ اﳌﺴــﺎﻓﺔ( ﻓــﺈن اﳊﺎﺳــﺐ ﻳﻘـﺮأ‬
‫ﺑﻴــﺎ ت ﰱ اﳌــﺪﺧﻞ إﱃ أن ﻳﻈﻬــﺮ أﺣــﺪ ﻫــﺬﻩ اﳊــﺮوف ﻓﻴﻌﺘــﱪ ﻋﻨﺪﺋــﺬ أن ﺑﻴــﺎ ت اﳌﺘﻐــﲑ اﻟــﺬى ﻳﻘ ـﺮأﻩ ﻗــﺪ اﻧﺘﻬــﺖ ﻋﻨــﺪ ﻫــﺬا اﳊــﺪ‪ .‬ﻛﻤــﺎ‬
‫ﺗﺘﻮﻗﻒ اﻟﻘﺮاءة أﻳﻀﺎ ﻋﻨﺪ ﻗﺮاءة ﻋﺪد ﻣﻦ اﳊﺮوف ﻳﺴﺎوى >‪ <width‬أو ﻋﻨﺪ اﻟﻮﺻﻮل ﻟﻨﻬﺎﻳﺔ ﻣﻠﻒ‪ .‬ﻛﺄﻣﺜﻠﺔ ﻟﻠﺘﻮﺿﻴﺢ‪:‬‬

‫‪Read statement‬‬ ‫‪input data‬‬ ‫‪result‬‬


‫;)‪scanf("%2d %3d",&j,&k‬‬ ‫;‪123456789 j=12; k=345‬‬
‫;)‪scanf("%2d %3d",&j,&k‬‬ ‫‪1 234567‬‬ ‫;‪j=1; k=234‬‬
‫;)‪scanf("%d %d",&j,&k‬‬ ‫‪1234 6789‬‬ ‫;‪j=1234; k=6789‬‬

‫ﰱ اﳌﺜﺎل اﻷول ﺗﻮﻗﻔﺖ ﻗﺮاءة ﺑﻴﺎ ت ‪ j‬ﻧﺘﻴﺠﺔ إﲤﺎم ﻗﺮاءة ﺣﺮﻓﲔ ﻛﻤــﺎ ﻳﻮﺿــﺢ أﻣــﺮ اﻟﺘﺸــﻜﻴﻞ ذاﺗــﻪ و ﳌﺜــﻞ ﻟﻨﺴــﺒﺔ ﻟﻠﻤﺘﻐــﲑ ‪ .k‬ﰱ اﳌﺜــﺎل‬
‫اﻟﺜﺎﱏ ﺗﻮﻗﻔﺖ ﻗﺮاءة ﺑﻴــﺎ ت ‪ j‬ﺑﻌــﺪ اﳊــﺮف اﻷول ﻋﻨــﺪ ﻗـﺮاءة اﳌﺴــﺎﻓﺔ ﺑﻌــﺪ اﻟــﺮﻗﻢ ‪ 1‬ﻧﺘﻴﺠــﺔ ﻟﻮﺟــﻮد ﻣﺴــﺎﻓﺔ ﰱ ﲨﻠــﺔ اﻟﺘﺸــﻜﻴﻞ ﺑﻌــﺪ اﻟﻌﻨﺼــﺮ‬
‫‪ . %2d‬ﰱ اﳌﺜــﺎل اﻟﺜﺎﻟــﺚ ﻧﻈ ـﺮا ﻟﻌــﺪم ﲢﺪﻳــﺪ ‪ width‬ﰱ ﲨﻠــﺔ اﻟﺘﺸــﻜﻴﻞ ﻓﻠﻘــﺪ اﺳــﺘﻤﺮت اﻟﻘ ـﺮاءة ﻟﻠﻤﺘﻐــﲑ ‪ j‬إﱃ أن وﺻــﻠﻨﺎ ﻟﻠﻤﺴــﺎﻓﺔ ﰒ‬
‫اﺳﺘﻤﺮت اﻟﻘﺮاءة ﻟﻠﻤﺘﻐﲑ ‪ k‬إﱃ أن وﺻﻠﻨﺎ ﻟﻨﻬﺎﻳﺔ اﳌﻠﻒ‪.‬‬

‫‪54‬‬
‫‪.3‬ج‪ .3.‬أواﻣﺮ إدﺧﺎل و إﺧﺮاج اﳊﺮوف ‪Character input/output‬‬
‫‪statements‬‬

‫ﻫﻨــﺎك ﻓﺌــﺔ أﺧــﺮى ﻫﺎﻣــﺔ ﻣــﻦ أواﻣــﺮ اﻹدﺧــﺎل و اﻹﺧ ـﺮاج ﺗﺘﻌﺎﻣــﻞ أﺳﺎﺳــﺎ ﻣــﻊ اﳊــﺮوف‪ .‬ﺗﺸــﻤﻞ ﺗﻠــﻚ اﻟﻔﺌــﺔ ﳎﻤﻮﻋــﺔ اﻟــﺪول ‪get‬‬
‫ﻟﻠﻘـﺮاءة و ‪ put‬ﻟﻠﻜﺘﺎﺑــﺔ‪ .‬ﻳﻨﺘﻬــﻰ اﺳــﻢ اﻟﺪاﻟــﺔ ﲝــﺮف ‪ c‬ﻟﻠﺪﻻﻟــﺔ ﻋﻠــﻰ أن اﳌﻄﻠــﻮب ﻗـﺮاءة أو ﻛﺘﺎﺑــﺔ ﺣــﺮف واﺣــﺪ ) ) (‪.(getc( ), putc‬‬
‫إذا أﻧﺘﻬــﻰ اﺳــﻢ اﻟﺪاﻟــﺔ ﳊــﺮف ‪ s‬ﻓﻴــﺪل ذﻟــﻚ ﻋﻠــﻰ أن اﳌﻄﻠــﻮب ﻗـﺮاءة أو ﻛﺘﺎﺑــﺔ ﲨﻠــﺔ )) (‪ .(gets( ), puts‬ﻗــﺪ ﻳﺴــﺘﻬﻞ اﺳــﻢ اﻟﺪاﻟــﺔ‬
‫ﲝﺮف ‪ f‬ﻟﻠﺪﻻﻟﺔ ﻋﻠــﻰ ﻛــﻮن اﻟﻘـﺮاءة أو اﻟﻜﺘﺎﺑــﺔ ﻣــﻦ ﻣﻠــﻒ )) (‪ .(fgetc( ), fgets( ), fputc( ), fputs‬ﻗــﺪ ﻳﺴــﺘﻬﻞ أﻳﻀــﺎ ﳊــﺮف‬
‫‪ s‬ﻟﻠﺪﻻﻟــﺔ ﻋﻠــﻰ ﻃﻠــﺐ اﻟﻘـﺮاءة ﻣــﻦ أو اﻟﻜﺘﺎﺑــﺔ ﻋﻠــﻰ ﲨﻠــﺔ )) (‪ .(sgetc( ), sputc‬ﳌﻌﺮﻓــﺔ ﺗﻔﺎﺻــﻴﻞ أﺳــﻠﻮب اﺳــﺘﺪﻋﺎء ﻫــﺬﻩ اﻟــﺪوال‬
‫ﻹﺿﺎﻓﺔ ﻟﻠﻌﺪﻳﺪ ﻣﻦ اﻟﺘﻨﻮﻳﻌﺎت ﻋﻠﻴﻬﺎ ﳝﻜﻦ ﻣﺮاﺟﻌﺔ اﳌﺴﺎﻋﺪ ‪.help‬‬

‫‪.3‬ج‪ .4.‬اﻟﺘﻌﺎﻣﻞ ﻣﻊ اﳌﻠﻔﺎت ‪File handling‬‬


‫أواﻣــﺮ اﻟﻘـﺮاءة و اﻟﻜﺘﺎﺑــﺔ اﻟــﱴ ﻇﻬــﺮت ﰱ اﻷﻣﺜﻠــﺔ ﺣــﱴ اﻵن )) (‪ (printf( ), scanf‬ﺗﺘﻌﺎﻣــﻞ ﻣــﻊ ﻟﻮﺣــﺔ اﳌﻔــﺎﺗﻴﺢ و اﻟﺸﺎﺷــﺔ‪.‬‬
‫ﳝﻜﻦ ﺑــﻨﻔﺲ اﻟــﱪ ﻣﺞ اﻟﻘـﺮاءة ﻣــﻦ أو اﻟﻜﺘﺎﺑــﺔ ﰱ ﻣﻠــﻒ ﺳــﺘﺨﺪام اﻷﺳــﻠﻮب اﳌﺴــﻤﻰ ﻋــﺎدة اﻟﺘﻮﺟﻴــﻪ ‪ .redirection‬ﻧﻔــﺮض أن ﻟــﺪﻳﻨﺎ‬
‫ﺑﺮ ﳎــﺎ ﰎ ﺗﺮﲨﺘــﻪ و وﺻــﻠﻪ ﻓﺄﺻــﺒﺢ ﺟــﺎﻫﺰا ﻟﻠﺘﻨﻔﻴــﺬ أﲰــﻪ ‪ .myprog.exe‬و ﻧﻔــﺮض أن ﻫــﺬا اﻟــﱪ ﻣﺞ ﻳﺘﻌﺎﻣــﻞ ﻣــﻊ ﻟﻮﺣــﺔ اﳌﻔــﺎﺗﻴﺢ و‬
‫اﻟﺸﺎﺷﺔ‪ .‬إذا أرد أن ﻳﻘﺮأ اﻟﺒﻴﺎ ت ﻣﻦ اﳌﻠﻒ ‪ input.dat‬ﻣﺜﻼ ﺑﺪﻻ ﻣﻦ ﻟﻮﺣﺔ اﳌﻔﺎﺗﻴﺢ ﳝﻜﻦ أن ﻧﻜﺘﺐ ﻋﻨﺪ اﻟﺘﻨﻔﻴﺬ‪:‬‬
‫‪myprg.exe < input.dat‬‬
‫و ﻟﻜﺘﺎﺑﺔ اﻟﻨﺘﺎﺋﺞ ﻋﻠﻰ اﳌﻠﻒ ‪ output.dat‬ﻣﺜﻼ ﳝﻜﻦ أن ﻧﻜﺘﺐ‪:‬‬
‫‪myprog.exe > output.dat‬‬
‫و ﻟﻄﺒﻊ ﳝﻜﻦ اﳉﻤﻊ ﺑﲔ اﻻﺛﻨﲔ‪:‬‬
‫‪myprog.exe < input.dat >output.dat‬‬
‫ﳝﻜــﻦ أﻳﻀــﺎ أن ﻧﻔــﺘﺢ اﳌﻠــﻒ ﻣــﻦ داﺧــﻞ اﻟــﱪ ﻣﺞ ﻟﻠﻘـﺮاءة أو ﻟﻠﻜﺘﺎﺑـﺔ‪ .‬ﻗﺒــﻞ أﻳــﺔ ﻋﻤﻠﻴــﺔ ﻛﺘﺎﺑــﺔ أو ﻗـﺮاءة ﻳﻨﺒﻐــﻰ أوﻻ "ﻓــﺘﺢ" اﳌﻠــﻒ ﺑﻮاﺳــﻄﺔ‬
‫اﻟﺪاﻟﺔ ) (‪ .fopen‬ﰱ ﻫﺬﻩ اﻟﻌﻤﻠﻴﺔ ﻳﻘــﻮم اﳊﺎﺳــﺐ ﺑﺘﺨﺼــﻴﺺ ﻣﻮﻗــﻊ ﺧــﺎص ﰱ اﻟــﺬاﻛﺮة )ﻳﺴــﻤﻰ أﺣﻴــﺎ ‪ (buffer‬ﲤــﺮ ﻋﻠﻴــﻪ اﳌﻌﻠﻮﻣــﺎت‬
‫ﻟﺘﺤﻔﻆ ﻣﺆﻗﺘﺎ ﻗﺒﻞ اﻧﺘﻘﺎﳍﺎ ﻣﻦ أو إﱃ اﳌﻠﻒ‪ .‬ﳛﻮى ﻫﺬا اﳌﻮﻗﻊ أﻳﻀﺎ ﻛﺎﻓﺔ اﻟﺒﻴﺎ ت ﻋﻦ ﺣﺎﻟﺔ اﳌﻠﻒ‪ :‬ﻧﻮﻋﻪ‪ ،‬ﻣﻜﺎﻧــﻪ ﰱ وﺳــﻴﻂ اﻟﺘﺨـﺰﻳﻦ‪،‬‬
‫اﻟﻨﻘﻄــﺔ اﻟــﱴ وﻗﻔﻨــﺎ ﻋﻨــﺪﻫﺎ ﻣﻨــﺬ آﺧــﺮ ﻋﻤﻠﻴــﺔ ﻗ ـﺮاءة أو ﻛﺘﺎﺑــﺔ‪... ،‬اﱁ‪ .‬ﻓﺎﺋــﺪة وﺟــﻮد ﻣﻮﻗــﻊ اﻧﺘﻘــﺎﱃ ﻫــﻰ اﻹﺳ ـﺮاع ﰱ ﻋﻤﻠﻴــﺎت اﻟﻘ ـﺮاءة و‬
‫اﻟﻜﺘﺎﺑــﺔ‪ .‬ﻓﺎﻹﻋــﺪاد ﻟﻌﻤﻠﻴــﺔ اﻟﻘـﺮاءة أو اﻟﻜﺘﺎﺑــﺔ ﻣــﻦ وﺳــﻴﻂ اﻟﺘﺨـﺰﻳﻦ ﺧــﺬ وﻗﺘــﺎ ﻃــﻮﻳﻼ ﺑﻌــﺪ ذﻟــﻚ ﻳﺴــﺘﻐﺮق ﻗـﺮاءة أو ﻛﺘﺎﺑــﺔ ﺣــﺮف واﺣــﺪ‬
‫ﺗﻘﺮﻳﺒــﺎ ﻧﻔــﺲ اﻟﻮﻗــﺖ اﳌﻄﻠــﻮب ﻟﻘـﺮاءة أو ﻛﺘﺎﺑــﺔ ﺳــﻄﺮ ﻛﻤﻠــﻪ‪ .‬و ﻟﺘــﺎﱃ ﻋﻨــﺪﻣﺎ ﻳﻄﻠــﺐ ﺑــﺮ ﻣﺞ ﻗـﺮاءة ﻋــﺪد ﻗﻠﻴــﻞ ﻣــﻦ اﳊــﺮوف ﻣــﻦ ﻣﻠــﻒ‬
‫ﻓــﺈن اﳊﺎﺳــﺐ ﻳﻘـﺮأ ﻋــﺪدا أﻛــﱪ و ﻳﻀــﻌﻪ ﰱ اﳌﻮﻗــﻊ اﳌﺆﻗــﺖ‪ ،‬اﻋﺘﻘــﺎدا ﻣﻨــﻪ أن اﻟــﱪ ﻣﺞ ﺳــﺮﻋﺎن ﻣــﺎ ﺳــﻴﻄﻠﺐ ﻗـﺮاءة ﺣــﺮوف أﺧــﺮى ﰱ أﻣــﺮ‬
‫ﻻﺣــﻖ‪ .‬و ﺑــﺬﻟﻚ ﻧﺼــﺒﺢ ﺟــﺎﻫﺰﻳﻦ ﻟﺘــﻮﻓﲑ ﻫــﺬﻩ اﳊــﺮوف ﺑﺴــﺮﻋﺔ ﰱ اﻷﻣــﺮ اﻟﺘــﺎﱃ‪ .‬ﻧﻔــﺲ اﻟﻜــﻼم ﻟﻨﺴــﺒﺔ ﻟﻠﻜﺘﺎﺑــﺔ‪ ،‬ﻓﻌﻨــﺪ ﻃﻠــﺐ ﺑــﺮ ﻣﺞ‬
‫ﻟﻜﺘﺎﺑﺔ ﻋﺪد ﻗﻠﻴﻞ ﻣــﻦ اﳊــﺮوف ﻋﻠــﻰ ﻣﻠــﻒ‪ ،‬ﻓــﺈن اﳊﺎﺳــﺐ ﳜﺰ ــﺎ ﻣﺆﻗﺘــﺎ ﰱ اﳌﻮﻗــﻊ و ﻻ ﻳﻜﺘﺒﻬــﺎ ﻓﻌﻠﻴــﺎ اﻧﺘﻈــﺎرا ﻷواﻣــﺮ ﻛﺘﺎﺑــﺔ ﻟﻴــﺔ‪ ،‬إﱃ أن‬
‫ﳝﺘﻠﺊ اﳌﻮﻗﻊ‪ ،‬ﻓﻴﻘﻮم ﻋﻨﺪﺋﺬ ﻟﻜﺘﺎﺑﺔ اﻟﻔﻌﻠﻴﺔ ﻣــﺮة واﺣــﺪة‪ .‬ﻳــﺘﻢ ﺣﺠــﺰ ﻣﻜــﺎن ﳍــﺬا اﳌﻮﻗــﻊ ﰱ اﻟــﺬاﻛﺮة ﻋﻨــﺪ ﻃﻠــﺐ ﻓــﺘﺢ اﳌﻠــﻒ‪ .‬ﻋﻨـﻮان ﺑﺪاﻳــﺔ‬
‫اﳌﻮﻗــﻊ ﻳــﺘﻢ اﻻﺣﺘﻔــﺎظ ﺑــﻪ ﰱ ﻣﺘﻐــﲑ ﻳﺴــﻤﻰ ﻣﻔﺘــﺎح اﳌﻠــﻒ ‪ .file handle‬ﻟﻨﻔــﱰض أﻧﻨــﺎ ﻧﺮﻳــﺪ اﻟﻘـﺮاءة ﻣــﻦ ﻣﻠــﻒ اﲰــﻪ ﰱ وﺳــﻴﻂ اﻟﺘﺨـﺰﻳﻦ‬
‫اﻟﺜ ــﺎﻧﻮى )اﻟﻘ ــﺮص ﻏ ــﲑ اﳌ ــﺮن( ‪ input.dat‬ﰒ اﻟﻜﺘﺎﺑ ــﺔ ﻋﻠ ــﻰ اﳌﻠ ــﻒ ‪ .output.dat‬و ﻧﻔــﺮض إﻧﻨ ــﺎ ﺳﻨﺴ ــﻤﻰ ﻣﻔ ــﺎﺗﻴﺢ اﳌﻠﻔ ــﺎت اﳌﻨ ــﺎﻇﺮة‬
‫‪ infile‬و ‪ outfile‬ﻋﻠﻰ اﻟﱰﺗﻴﺐ‪ .‬ﻓﺄن اﻷواﻣﺮ اﳋﺎﺻﺔ ﺑﻔﺘﺢ اﳌﻠﻔﲔ ﺧﺬ اﻟﺼﻮرة‪:‬‬

‫‪55‬‬
‫;‪FILE * infile‬‬
‫;‪FILE * outfile‬‬
‫;)"‪infile = fopen("input.dat","r‬‬
‫;)"‪outfile = fopen("output.dat","w‬‬
‫ﻳــﺪل أول ﺳــﻄﺮﻳﻦ ﻋﻠــﻰ ﺗﻌﺮﻳــﻒ اﳌﺘﻐــﲑﻳﻦ اﻟــﺬﻳﻦ ﻳﻘﻮﻣــﺎن ﺑــﺪور ﻣﻔﺘــﺎﺣﻰ اﳌﻠﻔــﲔ‪ .‬ﻻﺣــﻆ ﺿــﺮورة وﺿــﻊ اﻟﻨﺠﻤــﺔ * ﻗﺒــﻞ اﺳــﻢ أى ﻣــﻦ‬
‫اﳌﻔﺘﺎﺣﲔ‪ .‬ذﻟﻚ ﻷن ﻫﺬﻳﻦ اﳌﺘﻐﲑﻳﻦ ﻳﻨﺘﻤﻴﺎن ﻟﻄﺎﺋﻔﺔ اﳌﺆﺷﺮات ﻛﻤﺎ ﺳﻨﻮﺿﺢ ﻟﺘﻔﺼﻴﻞ ﰱ اﻟﺒﺎب اﳋــﺎص ﳌﺆﺷـﺮات‪ .‬ﰱ آﺧــﺮ ﺳــﻄﺮﻳﻦ‬
‫ﻧﻘــﻮم ﲝﺠــﺰ ﻣﻮاﻗــﻊ ﰱ اﻟــﺬاﻛﺮة ﻟﻠﺘﻌﺎﻣــﻞ ﻣــﻊ اﳌﻠﻔــﺎت اﳌــﺬﻛﻮرة ﻣــﻊ وﺿــﻊ ﻋﻨـﻮان ﻛــﻞ ﻣﻮﻗــﻊ ﰱ اﳌﻔﺘــﺎح اﳌﻨــﺎﻇﺮ‪ .‬ﻳــﺪل اﳊــﺮف "‪ "r‬ﻋﻠــﻰ أن‬
‫اﳌﻠــﻒ ﻣﻔﺘــﻮح ﻟﻠﻘـﺮاءة أﻣــﺎ اﳊــﺮف "‪ "w‬ﻓﻴــﺪل ﻋﻠــﻰ أﻧــﻪ ﻣﻔﺘــﻮح ﻟﻠﻜﺘﺎﺑــﺔ‪ .‬ﺧــﺬ اﻟــﺬاﻛﺮة اﻟﺼــﻮرة اﳌﻮﺿــﺤﺔ ﰱ اﻟﺸــﻜﻞ اﻟﺘــﺎﱃ ﺑﻌــﺪ إﳒــﺎز‬
‫ﻫﺬﻩ اﻷواﻣﺮ‪.‬‬
‫اﻟﺬاﻛﺮة‬ ‫وﺳﯿﻂ‬
‫اﻟﺘﺨﺰﯾﻦ‬
‫اﻟﺜﺎﻧﻮى‬
‫‪infile‬‬ ‫اﻟﻤﻮﻗﻊ اﻟﻤﺆﻗﺖ ‪buffer‬‬
‫اﻟﺨﺎص ﺑﺎﻟﺘﻌﺎﻣﻞ ﻣﻊ اﻟﻤﻠﻒ‬
‫‪input.dat‬‬

‫اﻟﻤﻮﻗﻊ اﻟﻤﺆﻗﺖ ‪buffer‬‬


‫‪outfile‬‬
‫اﻟﺨﺎص ﺑﺎﻟﺘﻌﺎﻣﻞ ﻣﻊ اﻟﻤﻠﻒ‬
‫‪output.dat‬‬

‫‪x‬‬ ‫‪y‬‬

‫ﻣﺘﻐﯿﺮات أﺧﺮى ﻓﻰ اﻟﺒﺮﻧﺎﻣﺞ‬

‫ﺷﻜﻞ ‪ – 1.3‬ﻋﻤﻠﻴﺔ ﻓﺘﺢ ﻣﻠﻒ‬


‫إذا ﻓﺸﻞ اﻟﱪ ﻣﺞ ﰱ ﻓﺘﺢ اﳌﻠﻒ )اﳌﻠﻒ ﻏﲑ ﻣﻮﺟﻮد ﰱ ﺣﺎﻟﺔ اﻟﻘﺮاءة أو ﱂ ﻳﻌﺪ ﻫﻨﺎك ﻣﺘﺴﻊ ﰱ وﺳﻴﻂ اﻟﺘﺨـﺰﻳﻦ ﳌﻠــﻒ ﺟﺪﻳــﺪ‬
‫ﰱ ﺣﺎﻟﺔ اﻟﻜﺘﺎﺑﺔ ﻣﺜﻼ( ﻓﺈن اﻟﻌﻨﻮان اﻟﺬى ﻳﻮﺿﻊ ﰱ اﳌﻔﺘﺎح ﻳﺴﺎوى ﺻﻔﺮا‪ .‬ﳚﺐ داﺋﻤﺎ إﺗﺒﺎع أﻣــﺮ ﻓــﺘﺢ اﳌﻠــﻒ ﺧﺘﺒــﺎر ﻟﻠﺘﺄﻛــﺪ ﻣــﻦ إﳒــﺎز‬
‫ﻋﻤﻠﻴﺔ اﻟﻔﺘﺢ ﺑﺴﻼﻣﺔ أى أﻧﻨﺎ ﳝﻜﻦ أن ﻧﻀﻴﻒ اﻟﺴﻄﺮﻳﻦ‪:‬‬
‫)‪if ( ! infile‬‬
‫};)‪{ printf("Cannot open input file\n");getch( ); exit(1‬‬
‫)‪if ( ! outfile‬‬
‫};)‪{ printf("Cannot open output file\n");getch( ); exit(2‬‬
‫ﺑﻌﺪ ذﻟﻚ ﳝﻜﻦ اﻟﺘﻌﺎﻣﻞ ﻣﻊ اﳌﻠﻒ ﺑﻮاﺳﻄﺔ أواﻣﺮ اﻟﻘﺮاءة أو اﻟﻜﺘﺎﺑﺔ ﺑﺼــﻮرة ﺷــﺒﻴﻬﺔ ﺳــﻠﻮب اﻟﺘﻌﺎﻣــﻞ ﻣــﻊ ﻟﻮﺣــﺔ اﳌﻔــﺎﺗﻴﺢ أو اﻟﺸﺎﺷــﺔ ﻣــﻊ‬
‫ﺗﻌﺪﻳﻼت ﻃﻔﻴﻔﺔ ﻛﻤﺎ ﰱ اﳌﺜﺎل‪:‬‬
‫;)‪fscanf(infile,"%lg",&x‬‬
‫;)‪fprintf(outfile,"The value of x=%lg\n",x‬‬
‫ﺑﻌﺪ اﻧﺘﻬﺎء ﻋﻤﻠﻴﺎت اﻟﻘﺮاءة أو اﻟﻜﺘﺎﺑﺔ ﳚﺐ "ﻏﻠﻖ" اﳌﻠﻒ و ﺗﺆدى ﻫﺬﻩ اﻟﻌﻤﻠﻴﺔ إﱃ ﺗﺼــﻔﻴﺔ ﻛﺎﻓــﺔ اﳌﻌﻠﻮﻣــﺎت اﳌﺨﺘﺰﻧــﺔ ﺑﺼــﻮرة ﻣﺆﻗﺘــﺔ ﰱ‬
‫اﳌﻮﻗﻊ و وﺿﻌﻬﺎ ﰱ ﻣﻜﺎ ﺎ اﻟﻨﻬﺎﺋﻰ‪ .‬ﻳﺘﻢ ذﻟﻚ ﺑﻮاﺳﻄﺔ اﻷﻣﺮ‪:‬‬
‫;)‪fclose(infile); fclose(outfile‬‬

‫‪56‬‬
‫ﻫﻨﺎك داﻟﺔ أﺧﺮى ﺗﻘﻮم ﺑﺪور ﻫﺎم ﰱ ﻋﻤﻠﻴﺔ ﻗﺮاءة اﳌﻠﻒ وﻫﻰ اﻟﱴ ﲣﻄﺮ إن ﻛﺎن اﳌﻠﻒ ﻗﺪ ﺑﻠﻎ ﺎﻳﺘﻪ أم ﻻ أﺛﻨــﺎء اﻟﻘـﺮاءة‪ .‬ﻫــﺬﻩ‬
‫اﻟﺪاﻟﺔ ﻫﻰ ) (‪ .feof‬ﺗﺴﺘﺨﺪم ﻋﺎدة ﰱ ﺣﺎﻟﺔ اﻟﱪاﻣﺞ اﻟﱴ ﺗﻘﺮأ ﻛﺎﻓﺔ اﻟﻌﻨﺎﺻﺮ اﻟﱴ ﳛﺘﻮﻳﻬﺎ ﻣﻠﻒ و ﲡﺮى ﻧﻔﺲ اﻟﻌﻤﻠﻴﺔ ﻋﻠــﻰ ﻛــﻞ ﻋﻨﺼــﺮ‬
‫ﻓﻴﻪ إﱃ أن ﺗﻨﺘﻬﻰ اﻟﻌﻨﺎﺻﺮ‪:‬‬
‫;‪FILE * inp‬‬
‫;)"‪inp = fopen( "myfile" , "r‬‬
‫) )‪while( ! feof (inp‬‬
‫{‬
‫;)‪fscanf(inp,"%ld", &i‬‬
‫‪...... /* treat the input data */‬‬
‫}‬
‫ﻫﻨﺎك أﻳﻀﺎ دوال أﺧﺮى ﻣﻔﻴﺪة ﻹزاﻟــﺔ ﻣﻠــﻒ ) (‪ remove‬أو ﻹﻋــﺎدة ﺗﺴــﻤﻴﺘﻪ ) (‪ rename‬إﱃ آﺧــﺮﻩ‪ ،‬ﳝﻜــﻦ أن ﳓﺼــﻞ ﻋﻠــﻰ‬
‫ﻣﻌﻠﻮﻣﺎت ﻛﺎﻣﻠﺔ ﻋﻨﻬﺎ ﺳﺘﺨﺪام اﳌﺴﺎﻋﺪ ‪.help‬‬
‫ﻛﻤﺜــﺎل ﺳــﻨﻜﺘﺐ ﺑﺮ ﳎــﺎ ﻳﻘ ـﺮأ ﻛــﻞ اﳊــﺮوف ﰱ ﻣﻠــﻒ ﰒ ﻳﻜﺘــﺐ ﺟــﺪوﻻ ﺑﻌــﺪد ﻣ ـﺮات ﺗﻜ ـﺮار ﻛــﻞ ﺣــﺮف ﰱ ﺣــﺮوف اﻷﲜﺪﻳــﺔ‬
‫)ﻛﺒــﲑة أو ﺻــﻐﲑة( و ﻛــﺬا ﻋــﺪد ﻣـﺮات ﺗﻜـﺮار اﻷرﻗــﺎم اﻟﻌﺸ ـﺮﻳﺔ‪ .‬ﺳﻨﻀــﻊ ﰱ اﳌﺘﺠــﻪ ‪ alpha‬اﳌﻜــﻮن ﻣــﻦ ‪ 26‬ﻋﻨﺼــﺮ ﻋــﺪد ﻣـﺮات ﺗﻜ ـﺮار‬
‫اﳊﺮوف اﻟﺼﻐﲑة )اﻟﻌﻨﺼﺮ ]‪ alpha[0‬ﺑﻪ ﻋﺪد ﻣﺮات ﺗﻜـﺮار اﳊــﺮف ‪ a‬ﰒ ]‪ alpha[1‬ﻋــﺪد ﻣـﺮات ﺗﻜـﺮار اﳊــﺮف ‪ b‬و ﻫﻜــﺬا(‪ .‬اﳌﺘﺠــﻪ‬
‫‪ Alpha‬اﳌﻜﻮن ﻣﻦ ‪ 26‬ﻋﻨﺼﺮ أﻳﻀﺎ ﺑﻪ ﻋــﺪد ﻣـﺮات ﺗﻜـﺮار اﳊــﺮوف اﻟﻜﺒــﲑة ﺑــﻨﻔﺲ اﻷﺳــﻠﻮب‪ ،‬أﻣــﺎ اﳌﺘﺠــﻪ ‪ numer‬اﳌﻜــﻮن ﻣــﻦ ‪10‬‬
‫ﻋﻨﺎﺻﺮ‪ ،‬ﻓﺒﻪ ﻋﺪد ﻣﺮات ﺗﻜﺮار اﻷرﻗﺎم اﻟﻌﺸﺮﻳﺔ‪.‬‬
‫>‪#include <stdio.h‬‬
‫)‪void main(void‬‬
‫{‬
‫;]‪int alpha[26], Alpha[26], numer[10‬‬
‫;‪int I; char c‬‬ ‫;‪FILE * fil‬‬
‫;‪for (I=0;I<26;I++) alpha[I] = Alpha[I] = 0‬‬
‫;‪for (I=0;I<10;I++) numer[I] = 0‬‬
‫;)"‪fil = fopen("c:input.dat","r‬‬
‫)‪while (!feof(fil‬‬
‫{‬
‫;)‪c = fgetc(fil‬‬
‫) )'‪if ( (c>='A') && (c<='Z‬‬
‫{‬
‫;‪Alpha [c-'A'] ++‬‬
‫‪} else‬‬
‫) )'‪if ( (c>='a') && (c<='z‬‬
‫{‬
‫;‪Alpha [c-'z'] ++‬‬
‫‪} else‬‬
‫) )'‪if ( (c>='0') && (c<='9‬‬
‫{‬
‫;‪Alpha [c-'0'] ++‬‬
‫}‬
‫}‬
‫)‪for (I=0; I<29; I++‬‬
‫{‬
‫;)]‪printf("The letter %c is repeated %d times\n”,I+'A',Alpha[I‬‬

‫‪57‬‬
printf("The letter %c is repeated %d times\n”,I+'a',alpha[I]);
}
for (I=0; I<10; I++)
{
printf("The letter %c is repeated %d times\n”,I+'0',numer[I]);
}
}

58
‫‪Program control statements‬‬ ‫‪.3‬د‪ .‬أواﻣﺮ اﻟﺘﺤﻜﻢ ﰱ ﺳﲑ اﻟﱪ ﻣﺞ‬

‫ﺗﻨﻘﺴــﻢ أواﻣــﺮ اﻟــﺘﺤﻜﻢ ﰱ ﺳــﲑ اﻟــﱪ ﻣﺞ أﺳﺎﺳــﺎ ﻟﻔﺌﺘــﲔ‪ .‬اﻟﻔﺌــﺔ اﻷوﱃ ﺗﻌــﱪ ﻋــﻦ ﺗﻔﺮﻳــﻊ اﻟــﱪ ﻣﺞ ‪ branching‬ﻟﻔــﺮﻋﲔ أو أﻛﺜــﺮ‬
‫ﲝﻴــﺚ ﻳﺴــﺘﻜﻤﻞ ﻣﺴــﲑﺗﻪ ﰱ أﺣــﺪ اﻟﻔــﺮوع ﺑﻨــﺎء ﻋﻠــﻰ ﺷــﺮط‪ .‬اﻟﻔﺌــﺔ اﻟﺜﺎﻧﻴــﺔ ﺗﻌــﱪ ﻋــﻦ اﻟﻌﻤﻠﻴــﺎت اﻟﺘﻜﺮارﻳــﺔ ﲝﻴــﺚ ﻳﻨﻔــﺬ اﻟــﱪ ﻣﺞ ﺑﻠــﻮك ﻣــﻦ‬
‫اﻷواﻣــﺮ ﰒ ﻳﻌﻴــﺪ ﺗﻨﻔﻴــﺬﻩ ﻣـﺮات ﻋﺪﻳــﺪة و ﻻ ﻳﺘﻮﻗــﻒ إﻻ إذا ﲢﻘــﻖ ﺷــﺮط ﻣﻌــﲔ‪ .‬ﻷﺳــﺒﺎب رﳜﻴــﺔ‪ ،‬ﻣــﺎزال ﰱ ﻟﻐــﺔ ‪ C‬اﻷﻣــﺮ ‪ GOTO‬و‬
‫ﻟﻜﻨﻨﺎ ﻟﻦ ﻧﺴﺘﺨﺪﻣﻪ ﻷﻧﻪ ﻳﺘﻨﺎﻗﺾ ﻣﻊ ﻣﺒﺪأ اﻟﱪﳎﺔ اﳍﻴﻜﻠﻴﺔ اﻟﺬى ﻧﺴﲑ ﻋﻠﻴﻪ ﰱ ﻫﺬا اﻟﻜﺘﺎب‪.‬‬

‫‪.3‬د‪ .1.‬اﻷﻣﺮ ‪The if Statement - if‬‬


‫اﻟﺼﻮرة اﻟﻌﺎﻣﺔ ﳍﺬا اﻷﻣﺮ ﻫﻰ‪:‬‬
‫)‪if (condition‬‬
‫‪true_block‬‬
‫‪«else‬‬
‫» ‪false_block‬‬
‫ﻳﺒﺪأ ﺑﻔﺤﺺ اﻟﺸﺮط ‪ condition‬و اﻟﺬى ﳚﺐ وﺿــﻌﻪ ﺑــﲔ أﻗـﻮاس داﺋﺮﻳــﺔ ﻛﻤــﺎ ﻫــﻮ ﻣﻮﺿــﺢ أﻋــﻼﻩ‪ .‬إذا ﲢﻘــﻖ اﻟﺸــﺮط ﰎ ﺗﻨﻔﻴــﺬ‬
‫ﺑﻠﻮك اﻷواﻣﺮ ‪ true_block‬أﻣﺎ إذا ﱂ ﻳﺘﺤﻘــﻖ ﻓﻴــﺘﻢ ﺗﻨﻔﻴــﺬ اﻟﺒﻠــﻮك اﻟﺒــﺪﻳﻞ ‪ .false_block‬ﻳﺘﻜــﻮن أى ﻣــﻦ اﻟﺒﻠــﻮﻛﲔ ﻣــﻦ أﻣــﺮ واﺣــﺪ أو‬
‫ﻋــﺪة أواﻣــﺮ‪ .‬إذا ﻛــﺎن أﻣـﺮا واﺣــﺪا ﳚــﺐ أن ﻳﻨﺘﻬــﻰ ﻟﻔﺎﺻــﻠﺔ اﳌﻨﻘﻮﻃــﺔ ";"‪ .‬أﻣــﺎ إذا ﻛــﺎن أﻛﺜــﺮ ﻣــﻦ أﻣــﺮ ﻓﻴﺠــﺐ أن ﻳﻮﺿــﻊ ﺑــﲔ اﻷﻗـﻮاس‬
‫اﳌﻨﺜﻨﻴﺔ } {‪ .‬ﻻﺣﻆ أن ﲨﻠﺔ ‪ else‬و اﻟﺒﻠﻮك اﳌﺼﺎﺣﺐ ﳍﺎ ﻗﺪ ﻻ ﻳﻈﻬﺮا )و ﻟﺬا وﺿﻌﺎ ﺑﲔ اﻟﻌﻼﻣــﺎت » «( ﻋﻨﺪﺋــﺬ ﻻ ﻳﻔﻌــﻞ اﻟــﱪ ﻣﺞ‬
‫أى ﺷﺊ إذا ﳌﺎ ﻳﺘﺤﻘﻖ اﻟﺸﺮط و ﻳﻨﺘﻘﻞ ﻟﻠﺴﻄﺮ اﻟﺘﺎﱃ ﻟﻠﺒﻠــﻮك ‪ true_block‬ﻣﺒﺎﺷــﺮة‪ .‬ﻛﻤﺜــﺎل ﻧﺮﻳــﺪ أن ﻧﻜﺘــﺐ ﺑﺮ ﳎــﺎ ﳊﺴــﺎب ﻣﺴــﺎﺣﺔ‬
‫ﺷﻜﻞ ﻫﻨﺪﺳﻰ ﻗﺪ ﻳﻜﻮن داﺋﺮة أو ﻣﺴﺘﻄﻴﻞ‪:‬‬
‫>‪#include <stdio.h‬‬
‫>‪#include <process.h‬‬
‫‪#define PI 3.14159‬‬
‫)‪void main(void‬‬
‫{‬
‫;‪int i‬‬ ‫‪/* type of figure, i=1 means circle, i=2 means rectangle */‬‬
‫‪double x,y, area; /* dimensions and area of the figure */‬‬
‫;)" ‪printf("Enter figure type: (1=circle, 2=rectangle):‬‬
‫;)‪scanf("%d",&i‬‬
‫) ) ‪if ( (i < 1) || (i >2‬‬
‫{‬
‫;)‪printf("\nInvalid choice\n"); exit(1‬‬
‫}‬
‫)‪if (i = = 1‬‬
‫{‬
‫;)‪printf("Enter diameter: "); scanf("%lg",&x‬‬
‫)‪if (x <= 0.0‬‬
‫};)‪{ printf("Invalid data\n"); exit(2‬‬
‫;‪area = PI * x *x * 0.25‬‬
‫‪} else‬‬
‫{‬
‫;)‪printf("Enter Length and width: "); scanf("%lg %lg",&x,&y‬‬

‫‪59‬‬
‫) )‪if ( (x <= 0.0) || (y <= 0.0‬‬
‫};)‪{ printf("Invalid data\n"); exit(2‬‬
‫;‪area = x * y‬‬
‫}‬
‫;)‪printf("Area is : %lg/n",area‬‬
‫}‬
‫ﻛﻤﺎ ﻳﻮﺿﺢ اﳌﺜــﺎل أﻋــﻼﻩ‪ ،‬ﳝﻜــﻦ أن ﳛــﻮى أى ﻣــﻦ اﻟﺒﻠــﻮﻛﲔ ‪ true_block‬أو ‪ false_block‬ﺑﻠﻮﻛــﺎت أﺧــﺮى ﻗــﺪ ﲢــﻮى أﻳﻀــﺎ أواﻣــﺮ‬
‫ﺷﺮﻃﻴﺔ اﻟﻮاﺣﺪ داﺧﻞ اﻵﺧﺮ أو اﻟﻮاﺣﺪ ﺗﻠﻮ اﻵﺧﺮ ﻓﻴﻤﺎ ﳝﻜــﻦ أن ﻧﺴــﻤﻴﻪ أواﻣــﺮ ﻣﱰاﻛﺒــﺔ ‪ .nested statements‬و ﻟﻜــﻦ ﻻ ﳝﻜــﻦ أن‬
‫ﺗﺘﺪاﺧﻞ اﻷواﻣﺮ اﻟﺸﺮﻃﻴﺔ ﲝﻴﺚ ﻳﻨﺘﻬﻰ ﻣﺜﻼ أﻣﺮ داﺧﻠﻰ ﺧﺎرج ﻧﻄﺎق اﻷﻣﺮ اﳋﺎرﺟﻰ اﻟﺬى ﺑﺪأ ﻓﻴﻪ‪ .‬ﻻﺣﻆ إﺟﺮاءات ﲤﺤــﻴﺺ اﻟﺒﻴــﺎ ت‬
‫اﻟﱴ ﻗﻤﻨﺎ ﺑﻌﻤﻠﻬﺎ ﻋﻠﻰ ﻋﺪة أﺻﻌﺪة و ﻫﻰ ﻛﻤﺎ ذﻛﺮ آﻧﻔﺎ ﻋﺎدة ﻣﺎ ﻳﺘﺒﻌﻬﺎ ﺻﻨﺎع اﻟﱪاﻣﺞ اﶈﱰﻓﲔ‪.‬‬
‫إن أﻣﺮ ‪ if‬ﺑﺒﻠﻮﻛﺎﺗﻪ ﻳﻌﺘﱪ أﻣﺮا واﺣﺪا إذا ﻧﻈﺮ إﻟﻴﻪ ﻣﻦ اﳋﺎرج و ﻋﻠﻴﻪ ﻓﺄﻧﻪ ﰱ اﳌﺜﺎل‪:‬‬
‫)‪if (x > 0.0‬‬
‫)‪if (y < 0.0‬‬
‫;‪z = -1.0‬‬
‫‪else‬‬
‫{‬
‫;‪z = 1.0‬‬
‫;)"‪printf("Both x and y are positive\n‬‬
‫}‬
‫ﲨﻴــﻊ اﻟﺴــﻄﻮر ﻣــﻦ اﻟﺜــﺎﱏ إﱃ اﻷﺧــﲑ ﺗﻌﺘــﱪ أﻣـﺮا واﺣــﺪا و ﻫــﻮ اﻷﻣــﺮ اﻟــﺬى ﺳــﻴﻨﻔﺬ إذا ﲢﻘــﻖ اﻟﺸــﺮط اﻷول ‪ .x > 0.0‬اﻟﻘﺎﻋــﺪة ﻟﻨﺴــﺒﺔ‬
‫ﻟﻌﺒــﺎرة ‪ else‬ﻫــﻰ أ ــﺎ ﺗﻨﻄﺒــﻖ ﻋﻠــﻰ أول أﻣــﺮ ‪ if‬أﻋﻼﻫــﺎ ﱂ ﲢــﺪد ﻟــﻪ ﻋﺒــﺎرة ‪ else‬ﺑﻌــﺪ‪ .‬أى أ ــﺎ ﰱ اﻟــﱪ ﻣﺞ أﻋــﻼﻩ ﺗﺘﻌﻠــﻖ ﺑﻌــﺪم ﲢﻘﻴــﻖ‬
‫اﻟﺸــﺮط اﻟﺜــﺎﱏ ‪ .y < 0.0‬إذا ﻛﻨــﺎ ﻧﺮﻳــﺪ أن ﳒﻌﻠﻬــﺎ ﺗﺘﻌﻠــﻖ ﺑﻌــﺪم ﲢﻘــﻖ اﻟﺸــﺮط اﻷول ﳚــﺐ ﻓﺼــﻞ اﻟﺒﻠﻮﻛــﺎت ﺑﺸــﻜﻞ ﺻـﺮﻳﺢ ﺳــﺘﺨﺪام‬
‫اﻷﻗﻮاس اﳌﻨﺜﻨﻴﺔ‪:‬‬
‫)‪if (x > 0.0‬‬
‫{‬
‫)‪if (y < 0.0‬‬
‫;‪z = -1.0‬‬
‫}‬
‫‪else‬‬
‫{‬
‫;)"‪z = 1.0; printf("x is negative regardeless of the value of y\n‬‬
‫}‬
‫اﻟﺴﻄﺮ اﻟﺬى ﻳﻠﻰ )‪ if(y < 0.0‬ﻫﻮ ﺟﻮاب اﻟﺸﺮط‪ .‬و ﻫﻮ ﻣﻜﺘــﻮب ﺑﺼــﻮرة ﺻــﺤﻴﺤﺔ ﻟﻐــﻮ ﺣﻴــﺚ أن ﺟـﻮاب اﻟﺸــﺮط ﻣﻜــﻮن ﻣــﻦ أﻣــﺮ‬
‫واﺣــﺪ و ﻟــﻴﺲ ﻣــﻦ اﻟﻀــﺮورى إذن أن ﻧﻀــﻌﻪ ﺑــﲔ أﻗ ـﻮاس ﻣﻨﺜﻨﻴــﺔ‪ .‬إﻻ أﻧﻨــﺎ ﻧﻔﻀــﻞ داﺋﻤــﺎ وﺿــﻊ ﻫــﺬﻩ اﻷﻗ ـﻮاس ﻟﺘﺠﻨــﺐ اﻟﻠــﺒﺲ و ﻟﺘﺠﻨــﺐ‬
‫اﳋﻄﺄ إذا أرد أن ﻧﻀﻴﻒ أﻣﺮا ﺟﺪﻳﺪا‪ .‬ﳝﻜﻦ أﻳﻀﺎ أن ﺗﺘﻌﺎﻗﺐ أواﻣﺮ اﻟﺸــﺮط ﻛﺎﻟﺸــﻼل ‪ cascaded if‬ﰱ ﺣﺎﻟــﺔ اﻻﺧﺘﻴــﺎرات اﳌﺘﻌــﺪدة‬
‫ﻣﺜﻞ‪:‬‬
‫)‪if (x < 0.0‬‬
‫;‪operation_1‬‬
‫)‪else if (x < 30.0‬‬
‫;‪operation_2‬‬
‫)‪else if (x < 50.0‬‬
‫;‪operation_3‬‬
‫‪else‬‬
‫;‪operation_4‬‬
‫‪60‬‬
‫ﰱ ﻫــﺬﻩ اﳊﺎﻟــﺔ ﺗﻨﻔــﺬ اﻟﻌﻤﻠﻴــﺔ ‪ operation_1‬إذا ﻛﺎﻧــﺖ ‪ x‬ﺳــﺎﻟﺒﺔ أو اﻟﻌﻤﻠﻴــﺔ ‪ operation_2‬إذا ﻛﺎﻧــﺖ ‪ x‬ﻣﻮﺟﺒــﺔ و ﻟﻜــﻦ أﻗــﻞ ﻣــﻦ‬
‫‪ 30.0‬أو اﻟﻌﻤﻠﻴـ ــﺔ ‪ operation_3‬إذا ﻛﺎﻧـ ــﺖ ‪ x‬أﻛـ ــﱪ ﻣـ ــﻦ أو ﻳﺴـ ــﺎوى ‪ 30.0‬و ﻟﻜـ ــﻦ أﻗـ ــﻞ ﻣـ ــﻦ ‪ 50.0‬أو ﰱ اﻟﻨﻬﺎﻳـ ــﺔ اﻟﻌﻤﻠﻴـ ــﺔ‬
‫‪ operation_4‬إذا ﻛﺎﻧﺖ ‪ x‬أﻛﱪ ﻣﻦ أو ﻳﺴﺎوى ‪.50.0‬‬
‫ﻳﻨﺒﻐﻰ ﲡﻨﺐ ﻛﺘﺎﺑﺔ ﺑﺮاﻣﺞ ﺗﻌﺘﻤﺪ ﻋﻠﻰ ﺷﺮط ﺗﺴﺎوى ﻗﻴﻤﺘﲔ ﺣﻘﻴﻘﻴﺘﲔ‪ .‬أوﻻ ﻷن اﻟﻘﻴﻢ اﳊﻘﻴﻘﻴﺔ ﺗﻜــﻮن ﻣﺸــﻮﺑﺔ داﺋﻤــﺎ ﲞﻄــﺄ ﺗــﺞ‬
‫ﻋــﻦ اﻟﺘﻘﺮﻳــﺐ ﺳـﻮاء ﻷ ــﺎ ﲡــﺔ ﻋــﻦ ﻗﻴــﺎس أو ﻷ ــﺎ ﻋــﺪد ﻏــﲑ ﺟــﺬرى ‪ irrational number‬أو ﻷ ــﺎ ﲡــﺔ ﻋــﻦ ﻋﻤﻠﻴــﺔ ﺣﺴــﺎﺑﻴﺔ و‬
‫ﻟﺘــﺎﱃ ﻻ ﺑــﺪ ﻣــﻦ اﻟﺘﻘﺮﻳــﺐ ﻟﺘﺠﻨــﺐ اﻟﻜﺴــﻮر اﻟﻼ ﺎﺋﻴــﺔ ﻣــﺜﻼ‪ .‬و ﻋﻠــﻰ ذﻟــﻚ ﻓﻘــﺪ ﺗﻜــﻮن اﻟﻜﻤﻴﺘــﺎن ﻣﺘﺴــﺎوﻳﺘﲔ ﰱ اﻷﺻــﻞ و ﻟﻜــﻦ ﻧﺘﻴﺠــﺔ‬
‫ﻟﻠﺘﻘﺮﻳﺒﺎت اﳌﺬﻛﻮرة أﻋﻼﻩ ﺗﺼﺒﺤﺎن ﳐﺘﻠﻔﺘﲔ ﲟﻘﺪار ﺻﻐﲑ ﺟــﺪا و ﻟﻜﻨــﻪ ﻳﻜﻔــﻰ ﳉﻌـﻞ ﺷــﺮط اﻟﺘﺴــﺎوى ﻏــﲑ ﻣﺘﺤﻘــﻖ‪ .‬إذا ﻛــﺎن ﻻ ﺑــﺪ ﻣــﻦ‬
‫ﻋﻤﻞ ﻫﺬا اﻟﺸﺮط ﻓﻴﺠﺐ ﻛﺘﺎﺑﺘﻪ ﻟﺼﻮرة اﻟﺜﺎﻧﻴﺔ أد ﻩ ﺑﺪﻻ ﻣﻦ اﻟﺼﻮرة اﻷوﱃ‪:‬‬
‫;‪double x,y‬‬
‫;‪if ( x == y) ...‬‬ ‫‪/* poor condition */‬‬
‫‪if ( fabs(x-y) < 1.0e-12) ....; /* better formulation */‬‬
‫ﰱ اﻟﻮاﻗــﻊ ﻓــﺈن ﻛﺘﺎﺑــﺔ ﺷــﺮط اﻟﺘﺴــﺎوى ﻋﻠــﻰ ﻋــﺪد ﺣﻘﻴﻘــﻰ ﻫــﻰ ﻋﻤﻠﻴــﺔ ﻏــﲑ ﻣﻨﻄﻘﻴــﺔ و ﻣــﻦ اﻟﺼــﻌﺐ أن ﻳﻜــﻮن ﻫﻨــﺎك ﺗﻄﺒﻴــﻖ ﻋﻤﻠــﻰ ﻳــﺆدى‬
‫إﻟﻴﻬــﺎ‪ .‬ﰱ أﺣــﺪ اﻷﻣﺜﻠــﺔ اﻟﺴــﺎﺑﻘﺔ‪ ،‬أرد أن ﳓﺴــﺐ ﺟــﺬور اﳌﻌﺎدﻟــﺔ اﳉﱪﻳــﺔ ﻣــﻦ اﻟﺪرﺟــﺔ اﻟﺜﺎﻧﻴــﺔ و اﺣﺘﺠﻨــﺎ ﻟﻔﺤــﺺ ﻗﻴﻤــﺔ اﳌﻌﺎﻣــﻞ ‪ a‬و ﻫــﻮ‬
‫ﻣﻌﺎﻣﻞ ‪ .x*x‬إذا ﻛﺎن ﺻــﻔﺮا ﻛــﺎن ذﻟــﻚ ﻣﻌﻨــﺎﻩ أﻧﻨــﺎ ﺑﺼــﺪد ﻣﻌﺎدﻟــﺔ ﻣــﻦ اﻟﺪرﺟــﺔ اﻷوﱃ ﰱ اﻟﻮاﻗــﻊ و ﻛﺘﺒﻨــﺎ ﺧﻄـﻮات ﺧﺎﺻــﺔ ﺑﺘﻠــﻚ اﳊﺎﻟــﺔ‪.‬‬
‫ﻣﺎذا ﺳﻴﺤﺪث إذا ﻛﺎﻧﺖ ﻗﻴﻤﺔ ‪ a‬ﺻﻐﲑة ﺟﺪا و ﻟﻜﻦ ﻟﻴﺴﺖ ﺻﻔﺮا؟ ﰱ ﻫﺬﻩ اﳊﺎﻟﺔ ﻓﺈﻧﻨﺎ ﻣﺎ زﻟﻨﺎ ﺑﺼﺪد ﺣﻞ ﻣﻌﺎدﻟــﺔ ﻣــﻦ اﻟﺪرﺟــﺔ اﻟﺜﺎﻧﻴــﺔ‬
‫و ﻟﻜﻦ ﺧﻄﻮات اﳊﺴﺎب ﺳﺘﺆدى ﳋﻄﺄ ﻛﺒﲑ ﻧﺘﻴﺠــﺔ ﻟﻠﺘﻘﺮﻳــﺐ‪ .‬ﳚــﺐ ﻋﻨﺪﺋــﺬ إﻋــﺎدة ﻛﺘﺎﺑــﺔ ذﻟــﻚ اﳉــﺰء ﻛﻠﻴــﺔ ﲝﻴــﺚ ﻧﺘﺠﻨــﺐ ﻋﻤﻠﻴــﺔ ﻃــﺮح‬
‫ﻋﺪدﻳﻦ ﻛﺒﲑﻳﻦ ﻣﺘﻘﺎرﺑﲔ ﻛﻤﺎ ﺳﻨﺮى ﻓﻴﻤﺎ ﺑﻌﺪ ﻋﻨﺪ دراﺳﺔ اﳋﻄﺄ ﰱ اﻟﻄﺮق اﳊﺴﺎﺑﻴﺔ اﳌﺨﺘﻠﻔﺔ‪.‬‬

‫اﻟﺸــﺮط اﻟــﺬى ﳛﻜــﻢ أﻣــﺮ ‪ if‬ﻗــﺪ ﻳﻜــﻮن ﺷــﺮﻃﺎ ﻣﺮﻛﺒــﺎ )راﺟــﻊ اﳌﻠﺤﻮﻇــﺎت اﻟ ـﻮاردة أﻋــﻼﻩ ﻋــﻦ اﳊﺴــﺎب اﳌﺨﺘﺼــﺮ ‪shortcut‬‬
‫‪ .(evaluation‬ﻗﺪ ﻳﻔﻴﺪ ﰱ ﺗﺒﺴﻴﻂ اﻟﺸﺮوط اﳌﺮﻛﺒﺔ اﺳﺘﺨﺪام اﻟﻨﻈﺮﻳﺔ‪:‬‬
‫) )>‪! ( (<condition1>) && (<condition2‬‬
‫) )>‪( !(<condition1>) || !(<condition2‬‬ ‫ﻫﻰ ﻧﻔﺴﻬﺎ‬
‫) )>‪! ( (<condition1>) || (<condition2‬‬
‫ﻫﻰ ﻧﻔﺴﻬﺎ ) )>‪( !(<condition1>) && !(<condition2‬‬
‫و اﳌﻌﺮوﻓﺔ ﺳﻢ ﻧﻈﺮﻳﺔ ‪ .De Morgan‬و ﻛﻤﺜﺎل ﻋﻠﻰ ذﻟﻚ‪:‬‬
‫)‪! ( (x > 7) || (y==0 ) ) => ( !(x>7) && !(y==0) ) => ( (x<=7) && y‬‬

‫‪61‬‬
‫‪.3‬د‪ .2.‬أﻣﺮ اﻟﺘﻔﺮﻳﻊ اﳌﺘﻌﺪد ‪The switch statement - switch‬‬
‫ﰱ ﺣﺎﻟﺔ اﻟﺘﻔﺮﻳﻊ ﻷﻛﺜﺮ ﻣﻦ ﻓﺮع ﲝﻴﺚ ﻳﻌﺘﻤــﺪ ﺷــﺮط اﻟﺘﻔﺮﻳــﻊ ﻋﻠــﻰ ﻣﺘﻐــﲑ ﻣــﻦ أﺣــﺪ اﻷﻧـﻮاع اﻟﺼــﺤﻴﺤﺔ‪ ،‬ﳝﻜــﻦ ﻟﻄﺒـﻊ ﻛﺘﺎﺑــﺔ ﲨــﻞ‬
‫ﺷــﺮﻃﻴﺔ ﻣﺘﻌﺎﻗﺒــﺔ ﻛﺎﻟﺸــﻼل ‪ cascaded if‬و ﻟﻜــﻦ ﻫﻨــﺎك أﻣــﺮ آﺧــﺮ أﻓﻀــﻞ ﻣﺘــﻮﻓﺮ ﰱ ﻟﻐــﺔ ‪ C‬و ﻫــﻮ أﻣــﺮ اﻟﺘﻔﺮﻳــﻊ اﳌﺘﻌــﺪد ‪.switch‬‬
‫ﻳﻜﺘﺐ ﻫﺬا اﻷﻣﺮ ﻋﻠﻰ اﻟﺼﻮرة اﻟﻌﺎﻣﺔ‪:‬‬
‫)‪switch (integer_expression‬‬
‫{‬
‫‪case value1 : operation1‬‬
‫‪case value2 : operation2‬‬
‫‪.......‬‬
‫» ‪« default : operation_n‬‬
‫}‬
‫ﳝﻜــﻦ أن ﳛــﻮى ﻫــﺬا اﻷﻣــﺮ أى ﻋــﺪد ﻣــﻦ اﻟﻔــﺮوع اﻟــﱴ ﺗﺒــﺪأ ﻟﻜﻠﻤــﺔ ‪ case‬ﻋــﻼوة ﻋﻠــﻰ اﻟﻔــﺮع ﻏــﲑ اﻹﺟﺒــﺎرى اﻟــﺬى ﻳﺒــﺪأ ﺑﻜﻠﻤــﺔ‬
‫‪ .default‬ﻳﺒﺪأ اﻟﱪ ﻣﺞ ﲝﺴﺎب ﻗﻴﻤﺔ اﻟﺘﻌﺒﲑ اﻟﺼﺤﻴﺢ اﳌﻮﺟﻮد ﺑﲔ اﻷﻗﻮاس ﰒ ﻳﺪﺧﻞ ﰱ ﺟﺴﻢ اﻟﺒﻠﻮك ﻋﻨﺪ اﻟﻨﻘﻄﺔ اﻟﱴ ﳚــﺪ ﻋﻨــﺪﻫﺎ‬
‫ﻗﻴﻤ ــﺔ ﻣﺴ ــﺎوﻳﺔ ﻟ ــﻪ‪ .‬أى إذا ﺳ ــﺎوى اﻟﻨ ــﺎﺗﺞ اﻟﻘﻴﻤ ــﺔ ‪ value1‬ﺑ ــﺪأ ﺑﺘﻨﻔﻴ ــﺬ اﻟﺒﻠ ــﻮك ‪ operation1‬ﰒ ﻳﻨﺘﻘ ــﻞ ﺑﻌ ــﺪ ذﻟ ــﻚ ﻟﺘﻨﻔﻴ ــﺬ اﻟﺒﻠ ــﻮك‬
‫‪ operation2‬ﰒ ﻗ ــﻰ اﻷواﻣ ــﺮ ﺗﺒﺎﻋ ــﺎ ﰱ ﺟﺴ ــﻢ اﻟﺒﻠ ــﻮك ‪ switch‬إﱃ أن ﻳﺼ ــﻞ ﻟﻠﺒﻠ ــﻮك ‪ .operation_n‬ﻻﺣ ــﻆ أن أى ﺑﻠ ــﻮك‬
‫)‪ (operation1, operation2, ..‬ﻗــﺪ ﻳﻜــﻮن ﻣﻜــﻮن ﻣــﻦ أﻣــﺮ واﺣــﺪ )ﻳﻨﺘﻬــﻰ ﻟﻔﺎﺻــﻠﺔ اﳌﻨﻘﻮﻃــﺔ( أو أى ﻋــﺪد ﻣــﻦ اﻷواﻣــﺮ‪ .‬أﻣــﺎ إذا‬
‫ﺳﺎوت ﻗﻴﻤﺔ اﻟﺘﻌﺒــﲑ اﻟﺼــﺤﻴﺢ ‪ value2‬ﻓﺈﻧــﻪ ﻳﺒــﺪأ ﻣــﻦ ﻋﻨــﺪ اﻟﺒﻠــﻮك ‪ operation2‬و ﻳـﻮاﱃ ﺗﻨﻔﻴــﺬ ﻗــﻰ اﻷواﻣــﺮ ﻛﻤــﺎ ﺳــﺒﻖ‪ .‬إذا ﱂ ﳚــﺪ‬
‫أﻳ ــﺔ ﻗﻴﻤ ــﺔ ﻣﺴ ــﺎوﻳﺔ ﻟﻘﻴﻤﺘ ــﻪ ﻓﺈﻧ ــﻪ ﻳﺒ ــﺪأ اﻟﺘﻨﻔﻴ ــﺬ ﻣ ــﻦ ﻋﻨ ــﺪ اﻟﻨﻘﻄ ــﺔ اﳌﻨ ــﺎﻇﺮة ل ‪ default‬أى ﻟﺒﻠ ــﻮك ‪ .operation_n‬ﻻﺣ ــﻆ ﺟﻴ ــﺪا‬
‫اﻟﺘﺪاﺧﻞ ﺑﲔ اﻟﺘﻔﺮﻳﻌﺎت اﳌﺨﺘﻠﻔﺔ ﰱ اﲡﺎﻩ ﻣﻌﲔ‪ .‬ﳝﻜﻦ أﻳﻀﺎ أن ﻧﻔﺼــﻞ ﺑــﲔ اﻟﺘﻔﺮﻳﻌــﺎت اﳌﺨﺘﻠﻔــﺔ ﻓﺼــﻼ ﻣــﺎ )و ﻫــﻮ أﻓﻀــﻞ ﺑﺮﳎﻴــﺎ ﻛﻠﻤــﺎ‬
‫أﻣﻜ ــﻦ ذﻟ ــﻚ( ﻋ ــﻦ ﻃﺮﻳ ــﻖ إ ــﺎء ﻛ ــﻞ ﻓ ــﺮع ﻟﻜﻠﻤ ــﺔ اﶈﺠ ــﻮزة ‪ .break‬ﺣﻴﻨﺌ ــﺬ إذا ﺳ ــﺎوى اﻟﺘﻌﺒ ــﲑ ‪ integer_expression‬اﻟﻘﻴﻤ ــﺔ‬
‫‪ value1‬ﻓﺈﻧﻨﺎ ﻧﻨﻔﺬ اﻟﺒﻠﻮك ‪ operation1‬ﻓﻘﻂ ﻻ ﻏﲑ ﰒ ﻧﻨﺘﻘﻞ ﳌﺎ ﺑﻌﺪ ﺑﻠﻮك ‪ switch‬ﺑﺮﻣﺘﻪ‪:‬‬
‫)‪switch (integer_expression‬‬
‫{‬
‫;‪case value1 : operation1 ; break‬‬
‫;‪case value2 : operation2 ; break‬‬
‫‪.......‬‬
‫» ‪« default : operation_n‬‬
‫}‬

‫ﻛﻤﺜﺎل ﻋﻠﻰ اﺳﺘﺨﺪام ﻫﺬا اﻷﻣﺮ ﻧﻔﺮض أن ﻟﺪﻳﻨﺎ ﺑﺮ ﳎﺎ ﳛﺴﺐ ﻣﺴﺎﺣﺎت أﺷﻜﺎل ﳐﺘﻠﻔﺔ و ﻟﻴﻜﻦ ﻣﺜﻼ اﳌﺴــﺘﻄﻴﻞ و اﳌﺮﺑــﻊ و اﻟــﺪاﺋﺮة‪.‬‬
‫ﺑﺪﻻ ﻣﻦ اﺳﺘﺨﺪام ﻋﺪد ﻣﻦ أواﻣﺮ ‪ if‬ﳝﻜﻦ ﻋﻤﻞ اﻵﺗﻰ‪:‬‬
‫>‪#include <stdio.h‬‬
‫‪#define PI 3.14159‬‬
‫)‪void main(void‬‬
‫{‬
‫;‪int choice‬‬
‫;‪double x,y,area‬‬
‫;)"‪printf("You want to calculate the area of:\n‬‬
‫;)" ‪printf("1-Rectangle\n2-Square\n3-Circle\nEnter your choice:‬‬
‫)‪scanf("%d",&choice); switch(choice‬‬
‫{‬

‫‪62‬‬
case 1:
printf("Enter rectangle length and width:");
scanf("%lg %lg",&x,&y);
printf ("The area is: %lg \n", area = x*y);
break;
case 2:
printf("Enter square side:");
scanf("%lg",&x);
printf ("The area is: %lg \n", area = x*x);
break;
case 3:
printf("Enter circle diameter:");
scanf("%lg",&x);
printf ("The area is: %lg \n", area = PI*x*x/4.0);
break;
default : printf("Invalid choice\n");
}
}

‫ و إن ﻛــﺎن ذﻟــﻚ ﻏــﲑ ﳏﺒــﺬ ﳌــﺮة و ﻟﻜﻨﻨــﺎ‬،‫ﳝﻜﻦ أﻳﻀﺎ اﳌﺰج ﺑﲔ اﻟﺘﻔﺮﻳﻌﺎت اﳌﺘﺪاﺧﻠﺔ و اﻟﺘﻔﺮﻳﻌﺎت اﳌﻨﻔﺼﻠﺔ ﰱ اﳌﺜﺎل اﻟﺴﺎﺑﻖ‬
:‫ أى أن اﻟﱪ ﻣﺞ ﻳﺼﺒﺢ‬.switch ‫ﻧﻔﻌﻠﻪ ﻫﻨﺎ ﻟﻨﻮﺿﺢ ﻛﻴﻒ ﻳﻌﻤﻞ اﻷﻣﺮ‬

#include <stdio.h>
#define PI 3.14159
void main(void)
{
int choice;
double x,y,area=1.0;
printf("You want to calculate the area of:\n");
printf("1-Rectangle\n2-Square\n3-Circle\nEnter your choice: ");
scanf("%d",&choice);
switch(choice)
{
case 1:
printf("Enter rectangle length and width:");
scanf("%lg %lg",&x,&y);
printf ("The area is: %lg \n", area = x*y);
break;
case 3:
area = PI / 4.0;
case 2:
printf("Enter dimension:");
scanf("%lg",&x);
area *= x*x;
printf ("The area is: %lg \n", area);
break;
default : printf("Invalid choice\n");
}
}

63
‫ﰱ ﻫﺬﻩ اﻟﱪ ﻣﺞ إذا ﻛﺎن ‪ choice==1‬ﻓﺈﻧﻨﺎ ﺳﻨﻨﻔﺬ اﻷواﻣﺮ اﻟﺜﻼث اﳋﺎﺻﺔ ﳌﺴﺘﻄﻴﻞ )اﻟﱴ ﺗﻠﻰ ‪ (case 1‬ﰒ ﳔﺮج ﲤﺎﻣﺎ ﻣــﻦ اﻟﺒﻠــﻮك‬
‫ﻧﺘﻴﺠــﺔ اﻷﻣــﺮ اﻟﺮاﺑــﻊ ‪ .break‬أﻣــﺎ إذا ﻛــﺎن ‪ choice == 2‬ﻓﺈﻧﻨــﺎ ﺳــﻨﻨﻔﺬ اﻷواﻣــﺮ اﻟــﱴ ﺗﻠــﻰ ‪ case 2‬إﱃ أن ﻧﺼــﻞ ﻟﻸﻣــﺮ ‪break‬‬
‫ﻓﻨﺨﺮج‪ .‬أﻣﺎ إذا ﻛﺎﻧﺖ ‪ choice == 3‬ﻓﺄﻧﻨﺎ ﺳﻨﻨﻔﺬ اﻷﻣﺮ اﻟﺘــﺎﱃ ل ‪ case 3‬ﰒ ﻧﻨﺘﻘــﻞ ﻟﺘﻨﻔﻴــﺬ اﻷواﻣــﺮ اﻟــﱴ ﺗﻠــﻰ ‪ case 2‬و ﳔــﺮج ﻋﻨــﺪ‬
‫أول ‪.break‬‬

‫‪.3‬د‪ .3.‬اﻷﻣﺮ "ﺑﻴﻨﻤﺎ‪-‬اﻓﻌﻞ ‪The while statement - "while‬‬


‫أول أواﻣﺮ اﻟﻌﻤﻠﻴﺎت اﻟﺘﻜﺮارﻳﺔ اﻟﺬى ﺳﻨﺪرﺳﻪ ﻳﻜﺘﺐ ﻋﻠﻰ اﻟﺼﻮرة اﻟﻌﺎﻣﺔ‪:‬‬
‫)‪while(condition‬‬
‫‪operation‬‬
‫و ﻫــﻮ ﻳﺒــﺪأ ﺑﻔﺤــﺺ ﻗﻴﻤــﺔ اﻟﺸــﺮط ‪ condition‬ﻓــﺈذا ﲢﻘــﻖ ﻧﻔــﺬ اﻷﻣــﺮ ‪ operation‬ﰒ أﻋــﺎد ﻓﺤــﺺ اﻟﺸــﺮط و أﻋــﺎد اﻟﺘﻨﻔﻴــﺬ إﱃ أن‬
‫ﻳﺼﺒﺢ اﻟﺸﺮط ﻏــﲑ ﻣﺘﺤﻘــﻖ ﻋﻨﺪﺋــﺬ ﻳﻨﺘﻘــﻞ ﻟﻸﻣــﺮ اﻟﺘــﺎﱃ ﰱ اﻟــﱪ ﻣﺞ‪ .‬اﻟﻌﻤﻠﻴــﺔ ‪ operation‬ﳝﻜــﻦ أن ﺗﻜــﻮن أﻣـﺮا واﺣــﺪا و ﺣﻴﻨﺌــﺬ ﳚــﺐ‬
‫أن ﺗﻨﺘﻬﻰ ﻟﻔﺎﺻﻠﺔ اﳌﻨﻘﻮﻃﺔ ";" أو ﳎﻤﻮﻋﺔ أواﻣﺮ و ﰱ ﻫﺬﻩ اﳊﺎﻟﺔ ﳚﺐ أن ﺗﻮﺿﻊ داﺧﻞ اﻷﻗﻮاس اﳌﻨﺜﻨﻴــﺔ } {‪ .‬ﻳﻌﺘــﱪ اﻷﻣــﺮ ‪while‬‬
‫ﺑﺮﻣﺘــﻪ‪ ،‬ﲟــﺎ ﰱ ذﻟــﻚ اﻟﺒﻠــﻮك اﻟﺘﻜـﺮارى اﻟــﺬى ﻳﻜــﻮن ﺟﺴــﻢ اﻷﻣــﺮ ﻣﻬﻤــﺎ ﻛــﺎن ﺣﺠﻤــﻪ‪ ،‬أﻣـﺮا واﺣــﺪا إذا ﻧﻈــﺮ إﻟﻴــﻪ ﻣــﻦ اﳋــﺎرج و ﳝﻜــﻦ أن‬
‫ﻳﻜﻮن ﺟﻮاب ﻟﺸﺮط ﻣﺜﻼ‪ .‬ﻛﺘﻄﺒﻴﻖ أول ﻋﻠﻰ ﻫﺬا اﻷﻣﺮ ﺳﻨﻜﺘﺐ ﺑﺮ ﳎﺎ ﻳﻘﺮأ أﻃﻮال ﻗﻀﺒﺎن ﳐﺰﻧـﺔ ﰱ اﳌﻠــﻒ "‪ "inp.dat‬ﰒ ﻳﻜﺘــﺐ ﰱ‬
‫اﻟﻨﻬﺎﻳــﺔ ﻋــﺪد اﻟﻘﻀــﺒﺎن اﻟﻘﺼــﲑة )أٌﻗــﻞ ﻣــﻦ ‪ (500mm‬و ﻋــﺪد اﻟﻘﻀــﺒﺎن اﻟﻄﻮﻳﻠــﺔ و ﻋــﺪد اﻟﻘـﺮاءات اﳋﺎﻃﺌــﺔ )ﺳــﺎﻟﺒﺔ أو ﺻــﻔﺮ(‪ .‬ﻳﻜﺘــﺐ‬
‫أﻳﻀﺎ اﻟﱪ ﻣﺞ ﳎﻤﻮع أﻃﻮاﳍﻢ‪.‬‬
‫>‪#include <stdio.h‬‬
‫)‪void main(void‬‬
‫{‬
‫;‪FILE * fil‬‬
‫;‪double length‬‬
‫;‪long count_short=0, count_long=0, total=0‬‬
‫;‪double tot_short=0.0, tot_long=0.0‬‬
‫;)"‪fil = fopen("inp.dat","r‬‬
‫) )‪while ( ! feof(fil‬‬
‫{‬
‫;‪total ++‬‬
‫;)‪fscanf(fil,"%lg ",&length‬‬
‫;‪if (length <= 0.0) continue‬‬
‫)‪if (length < 500.0‬‬
‫{‬
‫;‪count_short++‬‬
‫;‪tot_short += length‬‬
‫}‬
‫‪else‬‬
‫{‬
‫;‪count_long++‬‬
‫;‪tot_long += length‬‬
‫}‬
‫}‬
‫;)‪printf("\nValues read=%ld, Invalid data=%ld\n",total,total-count_short-count_long‬‬
‫;)‪printf("Number of short shafts=%ld Total length =%lg\n", count_short, tot_short‬‬
‫;)‪printf("Number of long shafts=%ld Total length =%lg\n", count_long , tot_long‬‬
‫}‬

‫‪64‬‬
‫اﺳﺘﺨﺪم اﻷﻣﺮ ‪ while‬ﰱ ﻫﺬا اﳌﺜﺎل ﻷﻧﻨﺎ ﻻ ﻧﻌﺮف ﻣﺴﺒﻘﺎ ﻋﺪد اﻟﺒﻴﺎ ت ﰱ اﳌﻠــﻒ‪ .‬و ﻟــﺬﻟﻚ ﻓﺈﻧﻨــﺎ ﻧﺴــﺘﻤﺮ ﰱ اﻟﻘـﺮاءة إﱃ أن ﻳﻨﺘﻬــﻰ‬
‫اﳌﻠﻒ‪ .‬اﻟﺪاﻟﺔ ) (‪ feof‬ﺗﻌﻄﻰ ﺻـﻮاب إذا اﻧﺘﻬــﻰ اﳌﻠــﻒ و ﺧﻄــﺄ ﻃﺎﳌــﺎ ﻣــﺎ زاﻟــﺖ ﻫﻨــﺎك ﻣﻌﻠﻮﻣــﺎت ﻓﻴــﻪ‪ .‬ﰱ ﻛــﻞ دورة ﻣــﻦ دورات اﻟﻌﻤﻠﻴــﺔ‬
‫اﻟﺘﻜﺮارﻳــﺔ ﻧﺰﻳــﺪ اﻟﻌــﺪاد ‪ total‬ﲟﻘــﺪار اﻟﻮﺣــﺪة‪ ،‬ﰒ ﻧﻘ ـﺮأ اﻟﺒﻴــﺎن و ﳕﺤﺼــﻪ‪ .‬إذا ﻛــﺎن ﻏــﲑ ﻣﻨﻄﻘﻴــﺎ )ﺳــﺎﻟﺒﺎ أو ﺻــﻔﺮا( ﻓﺈﻧﻨــﺎ ﻧﺴــﺘﺨﺪم اﻷﻣــﺮ‬
‫‪ continue‬و ﻫ ــﻮ ﻳﻌ ــﲎ ﺗ ــﺮك ﻛﺎﻓ ــﺔ اﻷواﻣ ــﺮ اﳌﺘﺒﻘﻴ ــﺔ ﻣ ــﻦ اﻟﻌﻤﻠﻴ ــﺔ اﻟﺘﻜﺮارﻳ ــﺔ ﰱ ﻫ ــﺬﻩ اﻟ ــﺪورة ﻣ ــﻊ اﻻﺳ ــﺘﻤﺮار ﰱ اﻟﻌﻤﻠﻴ ــﺎت اﻟﺘﻜﺮارﻳ ــﺔ‬
‫ﻟــﺪﺧﻮل ﰱ دورة ﺟﺪﻳــﺪة‪ .‬ﺑﻌــﺪ ذﻟــﻚ ﻧﻔﺤــﺺ اﻟﻄــﻮل و ﻧﺰﻳــﺪ اﻟﻌــﺪاد اﳌﻨﺎﺳــﺐ‪ .‬ﻋﻨــﺪ اﻧﺘﻬــﺎء اﳌﻠــﻒ ﳔــﺮج و ﻧﻜﺘــﺐ ﳏﺘــﻮى اﻟﻌــﺪادات‬
‫اﳌﺨﺘﻠﻔﺔ‪.‬‬

‫ﻫﻨﺎك أﻣﺮان ﳝﻜــﻦ أن ﻳﻌــﺪﻻ ﻣــﻦ ﺳــﲑ اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ "ﺑﻴﻨﻤــﺎ‪-‬اﻓﻌــﻞ" و ﳘــﺎ ‪ continue‬و ‪ .break‬ﻛﻼﳘــﺎ ﻻ ﳝﻜــﻦ أن‬
‫ﻳﺴﺘﺪﻋﻰ إﻻ إذا ﲢﻘﻖ ﺷــﺮط ﻣــﺎ‪ .‬ﻛﻼﳘــﺎ أﻳﻀــﺎ ﻳــﺆدى إﱃ ﺗــﺮك ﻗــﻰ اﻷواﻣــﺮ ﰱ اﻟــﺪورة اﻟــﱴ ﲢﻘــﻖ ﻓﻴﻬــﺎ ﻫــﺬا اﻟﺸــﺮط‪ .‬اﻟﻔــﺎرق ﺑﻴﻨﻬﻤــﺎ أن‬
‫‪ continue‬ﻳﻌ ــﲎ اﻻﺳ ــﺘﻤﺮار ﰱ اﻟﻌﻤﻠﻴ ــﺔ اﻟﺘﻜﺮارﻳ ــﺔ ﻟ ــﺪﺧﻮل ﰱ دورة ﺟﺪﻳ ــﺪة أﻣ ــﺎ ‪ break‬ﻓﻴﻌ ــﲎ ﺗ ــﺮك اﻟﻌﻤﻠﻴ ــﺔ اﻟﺘﻜﺮارﻳ ــﺔ ﻛﻠﻴ ــﺔ و‬
‫اﳋــﺮوج إﱃ اﻷﻣــﺮ اﻟﺘــﺎﱃ ﻟﻠﺒﻠــﻮك‪ .‬ﻛﻤﺜــﺎل ﻋﻠــﻰ اﺳــﺘﺨﺪام اﻷﻣــﺮ ‪ break‬ﺳــﻨﻜﺘﺐ ﺑﺮ ﳎــﺎ ﻳﻔﺤــﺺ ﳏﺘــﻮ ت ﻣﻠــﻒ ﺑــﻪ أﻋــﺪاد ﺻــﺤﻴﺤﺔ‬
‫ﻟﻜﻰ ﻳﺒﺤﺚ ﻋﻦ اﻟﻌﻨﺼﺮ اﻟﺬى ﻳﺴﺎوى ﻗﻴﻤﺔ ﻣﺎ ﻣﻌﻄﺎة و ﻟﺘﻜﻦ ‪ .k‬ﰱ اﻟﻨﻬﺎﻳﺔ ﻳﻜﺘﺐ ﺗﺮﺗﻴﺐ اﻟﻌﻨﺼﺮ ﰱ اﳌﻠﻒ إن وﺟﺪ‪.‬‬
‫>‪#include <stdio.h‬‬
‫)‪void main(void‬‬
‫{‬
‫;‪FILE *fil‬‬
‫;‪int line,,j,k‬‬
‫;)"‪fil = fopen("input.fil", "r‬‬
‫;)" ‪printf("Enter the value you are looking for:‬‬
‫;)‪scanf("%d",&k‬‬
‫;‪line =0‬‬
‫))‪while (!feof(fil‬‬
‫{‬
‫;‪line ++‬‬
‫;)‪fscanf("%d",&j‬‬
‫)‪if (j == k‬‬
‫;‪break‬‬
‫}‬
‫)‪if (j == k‬‬
‫;)‪printf("The file contains this value at the position: %d\n", line‬‬
‫‪else‬‬
‫;)"‪printf("The file does not contain this value\n‬‬
‫}‬

‫ﻫﻨــﺎك ﺛﻼﺛــﺔ ﻋﻨﺎﺻــﺮ أﺳﺎﺳــﻴﺔ ﻻ ﺗﻨﻔﺼــﻞ ﻋــﻦ ﺑﻌﻀــﻬﺎ اﻟــﺒﻌﺾ ﺗﻜــﻮن أﻳــﺔ ﻋﻤﻠﻴــﺔ ﺗﻜﺮارﻳــﺔ‪ ،‬ﺳـﻮاء ﻫﻨــﺎ أو ﰱ اﻷواﻣــﺮ اﻷﺧــﺮى اﻟــﱴ‬
‫ﺳﻨﺪرﺳﻬﺎ ﻓﻴﻤﺎ ﺑﻌﺪ‪ ،‬و ﻫﻰ‪:‬‬
‫ا‪ -‬اﻻﺑﺘﺪاء ‪ initialization‬و ﲣﺘﺺ ﺑﻮﺿﻊ اﻟﻘﻴﻤﺔ اﻻﺑﺘﺪاﺋﻴﺔ ﰱ ﻛﺎﻓﺔ اﳌﺘﻐﲑات اﻟﱴ ﺗﺘﻐﲑ ﺳﺘﻤﺮار ﰱ اﻟﻌﻤﻠﻴﺔ اﻟﺘﻜﺮارﻳﺔ )ﻣﺜﻞ‬
‫اﻟﻌﺪاد أو اﳊﺼﺎﻟﺔ(‪.‬‬
‫ب‪ -‬اﻟﺘﺤﺪﻳﺚ ‪ updating‬و ﺗﻌﲎ ﻋﺎدة ﺣﺴﺎب اﳌﺘﻐﲑات اﻟﱴ ﺗﺘﻐﲑ ﺳﺘﻤﺮار ﻟﻜﻰ ﺧﺬ ﻗﻴﻤﺘﻬﺎ اﳊﺪﻳﺜﺔ ﰱ ﻛﻞ دورة‪.‬‬
‫ج‪ -‬ﺷﺮط اﳋﺮوج ‪ exit condition‬و ﻫﻮ اﻟﺸﺮط )أو اﻟﺸﺮوط( اﻟﱴ إذا ﲢﻘﻖ إﺣﺪاﻫﺎ ﺧﺮﺟﻨﺎ ﻣﻦ اﻟﻌﻤﻠﻴﺔ اﻟﺘﻜﺮارﻳﺔ‪.‬‬

‫‪65‬‬
‫ﰱ اﻷﻣﺜﻠــﺔ اﻟﺴــﺎﺑﻘﺔ رأﻳﻨــﺎ أﻣﺜﻠــﺔ ﻟﻠﻌــﺪاد )اﳌﺘﻐـﲑات ‪ total, count_long, count_short‬ﰱ اﳌﺜــﺎل اﻷول و ‪ line‬ﰱ اﳌﺜــﺎل‬
‫اﻟﺜﺎﱏ( و ﻫﻰ أﻋﺪاد ﺻﺤﻴﺤﺔ ﺗﺰﻳﺪ ﲟﻘﺪار اﻟﻮﺣﺪة ﰱ ﻛﻞ دورة )و أﺣﻴﺎ ﺑﺼﻮرة ﻣﺸﺮوﻃﺔ(‪ .‬أﻣﺎ اﳊﺼﺎﻟﺔ ﻓﻬــﻰ ﻣﺘﻐـﲑات ﳒﻤــﻊ ﻓﻴﻬــﺎ ﻣــﺎ‬
‫ﻗـﺮأ ﻩ ﻣﺜــﻞ اﳌﺘﻐـﲑات ‪ tot_short, tot_long‬ﰱ اﳌﺜــﺎل اﻷول‪ .‬ﻋﻨــﺪ ﻛــﻞ دورة ﳚــﺐ أن ﻧﺘﺄﻛــﺪ أﻧﻨــﺎ ﻋــﺪﻟﻨﺎ ﺑﺼــﻮرة ﺻــﺤﻴﺤﺔ ﳏﺘــﻮ ت‬
‫ﻫﺬﻩ اﳌﺘﻐﲑات‪ ،‬و ﻫﻮ ﻣﺎ ﻳﺴﻤﻰ ﺑﻌﻤﻠﻴــﺔ اﻟﺘﺤــﺪﻳﺚ ‪ .updating‬و ﻟﻜــﻦ ﻷن اﻟﺘﻌــﺪﻳﻞ ﻳﻌﺘﻤــﺪ داﺋﻤــﺎ ﻋﻠــﻰ ﻣــﺎ ﺳــﺒﻖ‪ ،‬ﻓﻴﻨﺒﻐــﻰ أن ﻧﺘﺄﻛــﺪ‬
‫أن اﻟﻘﻴﻤـ ــﺔ اﻻﺑﺘﺪاﺋﻴـ ــﺔ ﰱ ﻫـ ــﺬﻩ اﳌﺘﻐ ـ ـﲑات ﻛﺎﻧـ ــﺖ ﺻـ ــﺤﻴﺤﺔ ﻗﺒـ ــﻞ اﻟـ ــﺪﺧﻮل ﰱ اﻟﻌﻤﻠﻴـ ــﺔ اﻟﺘﻜﺮارﻳـ ــﺔ و ﻫـ ــﻮ ﻣـ ــﺎ ﻳﺴـ ــﻤﻰ ﺑﻌﻤﻠﻴـ ــﺔ اﻻﺑﺘـ ــﺪاء‬
‫‪ .initialization‬أﻣﺎ ﺷﺮط اﳋﺮوج ﻓﺄﳘﻴﺘﻪ واﺿﺤﺔ‪ .‬و ﻟﻜﻦ ﺻﻮرﺗﻪ ﺗﻌﺘﻤﺪ ﻋﻠﻰ اﳌﻜﺎن اﻟﺬى ﻳــﺘﻢ ﻓﻴــﻪ اﻟﺘﺤــﺪﻳﺚ )ﻋــﺎدة ﻣــﺎ ﻳﻜــﻮن ﰱ‬
‫ﺑﺪاﻳﺔ أو ﰱ ﺎﻳﺔ اﻟﻌﻤﻠﻴﺔ ا ﻟﺘﻜﺮارﻳﺔ( و أﻳﻀﺎ ﻋﻠﻰ اﻟﺼﻮرة اﻟﱴ وﺿﻌﺖ ﻋﻠﻴﻬﺎ اﻟﻘﻴﻤﺔ اﻻﺑﺘﺪاﺋﻴﺔ‪ .‬ﻓــﺈذا أرد ﻣــﺜﻼ أن ﻧﻔﺤــﺺ ﻗــﻴﻢ ﻣﺘﺠــﻪ‬
‫ﺑﺪءا ﻣﻦ اﻟﻌﻨﺼﺮ رﻗﻢ ‪ 1‬إﱃ اﻟﻌﻨﺼﺮ رﻗﻢ ‪ n‬ﻓﺈن ﻛﻠﺘﺎ اﻟﺼﻮرﺗﲔ اﻵﺗﻴﺘﲔ ﲢﻘﻖ اﻟﻐﺮض‪:‬‬

‫‪i=0‬‬
‫)‪while(i<n‬‬
‫{‬
‫;‪i++‬‬
‫‪/* loop operations */‬‬
‫}‬
‫‪/* another way */‬‬
‫‪i=1‬‬
‫)‪while (i<=n‬‬
‫{‬
‫‪/* loop operations */‬‬
‫;‪i++‬‬
‫}‬
‫ﻻﺣﻆ أﻳﻀﺎ أن اﻟﻌﻤﻠﻴﺔ اﻟﺘﻜﺮارﻳﺔ ﻗﺪ ﻻ ﺗﻨﺠﺰ و ﻻ ﺣﱴ ﻣــﺮة واﺣــﺪة إذا ﻛــﺎن اﻟﺸــﺮط ﱂ ﻳﺘﺤﻘــﻖ ﻣﻨــﺬ أول ﻓﺤــﺺ‪ .‬ﰱ ﻫــﺬﻩ اﳊﺎﻟــﺔ ﳚــﺐ‬
‫أﻳﻀــﺎ أن ﻧﺘﺄﻛــﺪ أن ﻗــﻰ ﺧﻄ ـﻮات اﻟــﱪ ﻣﺞ ﳝﻜــﻦ أن ﺗﻨﺠــﺰ ﺑﺼــﻮرة ﺻــﺤﻴﺤﺔ‪ .‬أﻣــﺎ إذا ﻛــﺎن اﳋــﺮوج ﻣــﻦ اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ ﳝﻜــﻦ أن‬
‫ﳛــﺪث ﻷﻛﺜــﺮ ﻣــﻦ ﺳــﺒﺐ‪ ،‬ﻓﻴﻨﺒﻐــﻰ داﺋﻤــﺎ ﻋﻤــﻞ اﺧﺘﺒــﺎر ﻟﻠﺴــﺒﺐ اﻟــﺬى أدى ﻟﻠﺨــﺮوج ﺑﻌــﺪ اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ‪ .‬ذﻟــﻚ ﻣــﺎ ﺣــﺪث ﻣــﺜﻼ ﰱ‬
‫اﳌﺜﺎل اﳋﺎص ﻟﺒﺤﺚ ﻋﻦ ﻋﻨﺼﺮ ﰱ ﻣﻠــﻒ‪ .‬ﳝﻜــﻦ أن ﳔــﺮج ﻣــﻦ اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ ﻷﺣــﺪ ﺳــﺒﺒﲔ‪ :‬إﻣــﺎ أن اﳌﻠــﻒ ﻗــﺪ اﻧﺘﻬــﻰ أو ﻷﻧﻨــﺎ ﻗــﺪ‬
‫وﺟﺪ ﻣﺎ ﻧﺒﺤﺚ ﻋﻨﻪ‪ ،‬أو اﻻﺛﻨﲔ ﻣﻌﺎ )اﻻﺣﺘﻤﺎل اﻷﺧﲑ ﻳﺴﺘﺪﻋﻰ اﻟﺪﻗﺔ ﰱ ﻛﺘﺎﺑﺔ اﻟﺸﺮط اﻟﺬى ﻳﻠﻰ اﳋﺮوج ﻣــﻦ اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ(‪ .‬و‬
‫ﻟﺬا ﻟﺰم ﻋﻤﻞ اﻟﺸﺮط ﰱ ﺎﻳﺔ اﻟﱪ ﻣﺞ ﻗﺒﻞ ﻛﺘﺎﺑﺔ اﻟﻨﺎﺗﺞ‪ .‬ﺳﻨﻠﺨﺺ ﻓﻴﻤﺎ ﻳﻠــﻰ اﻷﺳــﺌﻠﺔ اﻟــﱴ ﳚــﺐ أن ﻳﺴــﺄﳍﺎ ﻛﺎﺗــﺐ اﻟــﱪ ﻣﺞ ﻟﻴﺘﺄﻛــﺪ ﻣــﻦ‬
‫ﺣﺴﻦ ﺗﺼﻤﻴﻤﻪ ﻟﻠﻌﻤﻠﻴﺔ اﻟﺘﻜﺮارﻳﺔ‪:‬‬
‫‪ -1‬ﻫــﻞ ﳝﻜــﻦ أﻻ ﲢــﺪث اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ و ﻻ ﻣــﺮة واﺣــﺪة‪ ،‬و ﻣــﺎذا ﺳــﻴﺤﺪث ﻧﺘﻴﺠــﺔ ﻟــﺬﻟﻚ؟ )ﻟﻠﺘﺄﻛــﺪ ﻣــﻦ ﻣﻨﺎﺳــﺒﺔ وﺿــﻊ اﻟﻌﻤﻠﻴــﺔ‬
‫اﻟﺘﻜﺮارﻳﺔ داﺧﻞ اﻟﱪ ﻣﺞ ﻛﻜﻞ(‬
‫‪ -2‬ﻫﻞ ﺳﺘﺘﻢ اﻟﺪورة اﻷوﱃ ﺑﺼﻮرة ﺻﺤﻴﺤﺔ؟ )ﻟﻠﺘﺄﻛﺪ ﻣﻦ ﺣﺴﻦ وﺿﻊ اﻟﻘﻴﻢ اﻻﺑﺘﺪاﺋﻴﺔ(‬
‫‪ -3‬ﻫﻞ ﺳﺘﻨﺘﻬﻰ داﺋﻤﺎ اﻟﻌﻤﻠﻴﺔ اﻟﺘﻜﺮارﻳﺔ ﻳﻮﻣﺎ ﻣﺎ؟ )ﻟﻠﺘﺄﻛﺪ ﻣﻦ ﺣﺴﻦ اﻟﺘﺤﺪﻳﺚ و ﺷﺮط اﳋﺮوج(‬
‫‪ -4‬ﻫﻞ ﺳﺘﺘﻢ اﻟﺪورة اﻷﺧﲑة ﺑﺼﻮرة ﺻﺤﻴﺤﺔ؟ )ﻟﻠﺘﺄﻛﺪ ﻣﻦ ﻣﻨﺎﺳﺒﺔ ﺷﺮط اﳋﺮوج(‬
‫‪ -5‬ﻫﻞ ﻧﻌﺮف داﺋﻤﺎ ﺳﺒﺐ اﳋﺮوج؟ )ﰱ اﻟﻌﻤﻠﻴﺎت اﻟﺘﻜﺮارﻳــﺔ اﻟــﱴ ﳝﻜــﻦ أن ﳔــﺮج ﻣﻨﻬــﺎ ﻟﻌــﺪة أﺳــﺒﺎب ﳐﺘﻠﻔــﺔ ﻟﻠﺘﺄﻛــﺪ ﻣــﻦ وﺿــﻊ اﻟﺸــﺮط‬
‫اﳌﻨﺎﺳﺐ ﻋﻨﺪ اﳋﺮوج(‬

‫‪66‬‬
‫ﺑﻘــﻰ أن ﻧﻨ ــﻮﻩ ﻋــﻦ اﻟﻌﻤﻠﻴ ــﺎت اﻟﺘﻜﺮارﻳــﺔ اﻟ ــﱴ ﻻ ﲢــﻮى أى ﺷ ــﺮط ﺑﻌــﺪ ﻛﻠﻤ ــﺔ ‪ while‬و ﻫــﻰ اﻟ ــﱴ ﺗﺴ ــﻤﻰ اﻟﻌﻤﻠﻴ ــﺎت اﻟﺘﻜﺮارﻳ ــﺔ‬
‫اﻟﻼ ﺎﺋﻴــﺔ ‪ .infinite loops‬إذا أرد ﻣ ـﺜﻼ أن ﻧﻌــﺎﰿ ﻋــﺪد ﻣــﺎ ﻏــﲑ ﻣﻌــﺮوف ﻣﺴــﺒﻘﺎ ﻣــﻦ اﻟﺒﻴــﺎ ت ﻳــﺪﺧﻠﻬﺎ اﳌﺴــﺘﺨﺪم اﻟﻮاﺣــﺪ ﺗﻠــﻮ‬
‫اﻵﺧــﺮ‪ .‬ﻳﻨﺒﻐــﻰ أن ﻳﻌﻠــﻦ اﳌﺴــﺘﺨﺪم ﺑﺼــﻮرة ﻣــﺎ ﻋــﻦ ﻛﻮﻧــﻪ ﻗــﺪ اﻧﺘﻬــﻰ ﻣــﻦ إدﺧــﺎل ﻛﺎﻓــﺔ اﻟﺒﻴــﺎ ت و ﻳﺮﻳــﺪ أن ﻳﻨﻬــﻰ اﻟــﱪ ﻣﺞ أو ﻳﻨﺘﻘــﻞ ﳉــﺰء‬
‫أﺧﺮ ﻣﻨﻪ‪ .‬ﻳﺘﻢ ذﻟﻚ ﻋﻦ ﻃﺮﻳﻖ إدﺧﺎل ﺑﻴــﺎن ﺧــﺎص ﻣﺘﻔــﻖ ﻋﻠﻴــﻪ ﻣﺴــﺒﻘﺎ ﻳﻜــﻮن ﳐﺘﻠﻔــﺎ ﻋــﻦ ﻛــﻞ اﻟﺒﻴــﺎ ت اﻟــﱴ ﳝﻜــﻦ أن ﻳــﺪﺧﻠﻬﺎ و ﻳﻜــﻮن‬
‫رﻣـﺰا ﻟﺮﻏﺒــﺔ اﳌﺴــﺘﺨﺪم ﰱ اﳋــﺮوج ﻣــﻦ اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ‪ .‬ﻳﺴــﻤﻰ ﻫــﺬا اﻟﺒﻴــﺎن اﳋــﺎص ﲝــﺮس اﳊــﺪود ‪ .sentinel‬ﻣــﺜﻼ إذا ﻛــﺎن اﻟــﱪ ﻣﺞ‬
‫ﳛﺴﺐ ﺟﺬور أﻋﺪاد ﳐﺘﻠﻔﺔ ﻓﻴﻤﻜﻦ اﻻﺗﻔﺎق ﻋﻠﻰ أن أى ﻋﺪد ﺳﺎﻟﺐ ﻳﺪﺧﻞ ﻳﻜﻮن ﻛﻨﺎﻳــﺔ ﻋــﻦ اﻟﺮﻏﺒــﺔ ﰱ إ ــﺎء اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ‪ .‬ﻋﻨــﺪ‬
‫اﻻﻧﺘﻬﺎء ﳝﻜﻦ ﻛﺘﺎﺑﺔ ﺑﻴﺎ ت ﻋﺎﻣﺔ ﻣﺜﻞ اﻟﻌﺪد اﻹﲨﺎﱃ ﻟﻸرﻗﺎم اﻟﱴ أدﺧﻠﺖ‪:‬‬
‫>‪#include <stdio.h‬‬
‫>‪#include <math.h‬‬
‫)‪void main(void‬‬
‫{‬
‫;‪long n=0‬‬
‫;‪double x‬‬
‫)‪while (1‬‬
‫{‬
‫;)" ‪printf("Enter the number you need to calculate its square root:‬‬
‫;)‪scanf("%lg",&x‬‬
‫)‪if (x< 0.0‬‬
‫;‪break‬‬
‫;‪n++‬‬
‫;))‪printf("The square root is: %lg\n",sqrt(x‬‬
‫}‬
‫;)‪printf("You entered %ld values\n",n‬‬
‫}‬

‫‪.3‬د‪ .4.‬اﻷﻣﺮ "اﻓﻌﻞ‪-‬ﺑﻴﻨﻤﺎ ‪The do-while statement - "do-while‬‬


‫إن اﻷﻣــﺮ اﻟﺴــﺎﺑﻖ "ﺑﻴﻨﻤــﺎ‪-‬اﻓﻌــﻞ ‪ "while‬ﳝﻜــﻦ أن ﻳــﺆدى أى ﻋــﺪد ﻣــﻦ اﳌـﺮات ﲟــﺎ ﰱ ذﻟــﻚ اﻟﺼــﻔﺮ‪ .‬اﺣﺘﻤــﺎل أﻻ ﻳﻨﻔــﺬ أﺑــﺪا ﻗــﺪ‬
‫ﻳﻜﻮن ﻣﻬﻤــﺎ ﻛﻤــﺎ ﰱ ﺣﺎﻟــﺔ ﻗـﺮاءة ﺑﻴــﺎ ت ﻣــﻦ ﻣﻠــﻒ ﻣــﺜﻼ ﺣﻴــﺚ أن اﳌﻠــﻒ ﻗــﺪ ﻳﻜــﻮن ﺧــﺎو ‪ .‬و ﻟﻜــﻦ أﺣﻴــﺎ ﻣــﺎ ﻧﺮﻳــﺪ أن ﻧﻜﺘــﺐ ﻋﻤﻠﻴــﺔ‬
‫ﺗﻜﺮارﻳــﺔ ﲝﻴــﺚ ﻧﻀــﻤﻦ أن ﺗﻨﻔــﺬ وﻟــﻮ ﻣــﺮة واﺣــﺪة ﻋﻠــﻰ اﻷﻗــﻞ‪ .‬ﺣﻴﻨﺌـﺬ ﳒﻌــﻞ اﻟﺸــﺮط ﻳﻔﺤــﺺ ﰱ ﺎﻳــﺔ اﻟــﺪورة و ﻟــﻴﺲ ﺑــﺪاﻳﺘﻬﺎ و ﺑــﺬﻟﻚ‬
‫ﻧﻀﻤﻦ أن اﻟﺪورة اﻷوﱃ ﺳــﺘﻨﺠﺰ داﺋﻤــﺎ‪ .‬ﳍــﺬا اﻟﺴــﺒﺐ ﻋﻜﺴــﻨﺎ ﻣﻨﻄــﻮق اﻷﻣــﺮ ﻟﻴﺼــﺒﺢ اﻷﻣــﺮ اﳉﺪﻳــﺪ "إﻓﻌــﻞ‪-‬ﺑﻴﻨﻤــﺎ ‪ "do-while‬اﻟﺼــﻮرة‬
‫اﻟﻌﺎﻣﺔ ﻟﻪ ﻫﻰ‪:‬‬
‫‪do‬‬
‫{‬
‫‪operation‬‬
‫;)‪} while(condition‬‬
‫ﻣــﻦ اﻷﻣﺜﻠــﺔ اﻟﺸــﻬﲑة ﻋﻠــﻰ ﻫــﺬا اﻷﻣــﺮ ﻛﺘﺎﺑــﺔ ﻗﺎﺋﻤــﺔ اﺧﺘﻴــﺎرات ﻣﺘﻌــﺪدة ﻳﺘﻠﻮﻫــﺎ ﻃﻠــﺐ ﻟﻠﻤﺴــﺘﺨﺪم ﻟﺘﺤﺪﻳــﺪ اﺧﺘﻴــﺎرﻩ‪ .‬ﻣــﺎذا ﺳــﻴﺤﺪث إذا‬
‫أدﺧــﻞ اﳌﺴــﺘﺨﺪم اﺧﺘﻴــﺎرا ﺧﺎﻃﺌــﺎ؟ ﻟــﻴﺲ ﻣــﻦ اﳌﻔﻀــﻞ أن ﻳﻨﺘﻬــﻰ ﻋﻤــﻞ اﻟــﱪ ﻣﺞ ﻋﻨﺪﺋــﺬ و ﻟﻜــﻦ ﳝﻜــﻦ أن ﳝــﻨﺢ اﳌﺴــﺘﺨﺪم أى ﻋــﺪد ﻣــﻦ‬
‫اﻟﻔﺮص ﻋﻦ ﻃﺮﻳﻖ ﻛﺘﺎﺑﺔ اﻟﻘﺎﺋﻤﺔ ﻣﺮة أﺧﺮى و اﻧﺘﻈﺎر أن ﻳﻌﻄﻰ اﳌﺴﺘﺨﺪم اﺧﺘﻴﺎرا ﻣﻨﺎﺳﺒﺎ‪ .‬ﺣﻴــﺚ أﻧﻨــﺎ ﻻ ﻧﻌــﺮف ﻣﺴــﺒﻘﺎ ﻛــﻢ ﻋــﺪد اﳌـﺮات‬
‫اﻟﱴ ﺳﻴﺪﺧﻞ ﻓﻴﻬﺎ ﻣﺴﺘﺨﺪم اﻟﱪ ﻣﺞ ﻗﻴﻤﺎ ﺧﺎﻃﺌﺔ‪ ،‬ﻧﻜﺘﺐ اﻟﱪ ﻣﺞ ﻛﺎﻟﺘﺎﱃ‪:‬‬
‫>‪#include <stdio.h‬‬
‫)‪void main (void‬‬
‫‪67‬‬
‫{‬
‫;‪int choice‬‬
‫‪do‬‬
‫{‬
‫;)"‪printf("What is the geometric figure you want:\n‬‬
‫;)" ‪printf("1-Rectangle\n2-Square\n3-Circle\n Enter your choicre:‬‬
‫;)‪scanf("%d",&choice‬‬
‫}‬
‫;) )‪while ( (choice < 0) || (choice > 3‬‬
‫)‪switch(i‬‬
‫{‬
‫‪case 1:......‬‬
‫}‬
‫}‬

‫ﻫﻨﺎك أﻳﻀﺎ ﺣﺎﻟﺔ أﺧﺮى و ﻫﻰ ﻋﻨﺪﻣﺎ ﻧﺮﻳﺪ أن ﻧﻘﻮم ﲝــﻞ ﻣﻌﺎدﻟــﺔ ﺳــﺘﺨﺪام اﻟﺘﻘﺮﻳــﺐ اﳌﺘﺘــﺎﱃ ﲝﻴــﺚ ﳔــﺮج إذا ﻛــﺎن اﳋﻄــﺄ أﻗــﻞ ﻣــﻦ ﻗﻴﻤــﺔ‬
‫ﻣﻌﻴﻨــﺔ‪ .‬ﳚــﺐ أوﻻ ﻋﻤــﻞ ﺣﺴــﺒﺔ ﺗﻘﺮﻳﺒﻴــﺔ و ﻟــﻮ واﺣــﺪة ﻗﺒــﻞ أن ﻧﻌــﺮف ﻗﻴﻤــﺔ اﳋﻄــﺄ‪ .‬اﻟــﱪ ﻣﺞ اﻟﺘــﺎﱃ ﳛﺴــﺐ ﺟــﺬر اﳌﻌﺎدﻟــﺔ ‪ x=cos x‬و‬
‫ذﻟﻚ ﺳﺘﺨﺪام اﻟﺘﻘﺮﻳﺐ اﳌﺘﺘﺎﱃ اﻵﺗﻰ‪:‬‬
‫)‪xnew = xold + (cos(xold) - xold)/(sin(xold) + 1.0‬‬
‫و اﻟﺬى ﻳﻨﺘﻬﻰ ﻋﻨﺪﻣﺎ ﻳﺼﺒﺢ اﻟﻔﺎرق ﺻﻐﲑا ﺑﲔ ‪ xnew‬و ‪ .xold‬ﻧﻌﺘﱪ اﻟﺼﻔﺮ ﻫﻮ اﻟﻘﻴﻤﺔ اﻻﺑﺘﺪاﺋﻴﺔ‪:‬‬
‫>‪#include <stdio.h‬‬
‫‪#define eps 1.0e-6‬‬
‫)‪void main(void‬‬
‫{‬
‫;‪double xold,xnew,err‬‬
‫;‪xnew = 0.0‬‬
‫‪do‬‬
‫{‬
‫;‪xold = xnew‬‬
‫;)‪xnew = xold + (cos(xold) - xold)/(sin(xold) + 1.0‬‬
‫;)‪} while (fabs(xnew-xold) > eps‬‬
‫;)‪printf("The root is : %lg\n",xnew‬‬
‫}‬
‫ﻳﻌــﺪ أﻣــﺮ ‪ do-while‬ﺑﺮﻣﺘــﻪ أﻣـﺮا واﺣــﺪا )ﺑﻐــﺾ اﻟﻨﻈــﺮ ﻋــﻦ ﻋــﺪد أواﻣــﺮ اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ ﻓﻴــﻪ( و ﳝﻜــﻦ أن ﻳﻈﻬــﺮ ﻛﺠـﻮاب ﺷــﺮط ﻣــﺜﻼ‬
‫ﺑﺪون اﳊﺎﺟﺔ ﻟﻮﺿﻊ أﻗﻮاس ﻣﻨﺜﻨﻴﺔ‪ .‬ﳝﻜﻦ أﻳﻀﺎ أن ﺗﻈﻬﺮ ﺑﺪاﺧﻞ اﻷواﻣﺮ اﻟﺘﻜﺮارﻳﺔ أى ﻣﻦ اﻷواﻣﺮ ‪ continue‬أو ‪ break‬ﻛﻤﺎ ﺳﺒﻖ‪.‬‬

‫‪.3‬د‪ .5.‬اﻷﻣﺮ "ﻟﻘﻴﻢ‪-‬اﻓﻌﻞ ‪The for statement - "for‬‬


‫إذا ﻛﻨﺎ ﻧﻌﻠﻢ ﻗﺒﻞ اﻟﺪﺧﻮل ﰱ اﻟﻌﻤﻠﻴﺔ اﻟﺘﻜﺮارﻳﺔ ﻛﻢ ﻋﺪد اﳌﺮات اﻟﱴ ﺳﺘﻨﺠﺰ ﻓﻴﻬﺎ ﻫﺬﻩ اﻟﻌﻤﻠﻴــﺔ ﻓــﺎﻷﻣﺮ اﳌﻨﺎﺳــﺐ ﻫــﻮ "ﻟﻘــﻴﻢ‪-‬اﻓﻌــﻞ‬
‫‪ "for‬و ﻫﻮ ﺧﺬ اﻟﺼﻮرة‪:‬‬
‫)‪for (initialization ; while_condition ; incrementing‬‬
‫‪operation‬‬
‫ﺑــﲔ اﻷﻗـﻮاس اﻟــﱴ ﺗﻠــﻰ اﻟﻜﻠﻤــﺔ اﶈﺠــﻮزة ‪ for‬ﳒــﺪ ﺛﻼﺛــﺔ أواﻣــﺮ ﺗﻔﺼــﻠﻬﻢ اﻟﻔﺎﺻــﻠﺔ اﳌﻨﻘﻮﻃــﺔ ";" و ﻫــﻰ ﲢــﻮى اﻟﻌﻨﺎﺻــﺮ اﻟﺜﻼﺛــﺔ اﻷﺳﺎﺳــﻴﺔ‬
‫ﻟﻠﻌﻤﻠﻴﺎت اﻟﺘﻜﺮارﻳﺔ اﳌﺬﻛﻮرة آﻧﻔﺎ‪ .‬اﻟﻌﻨﺼﺮ اﻷول ‪ initialization‬ﻫﻮ أﻣﺮ ﻳﻌﻄــﻰ اﻟﻘﻴﻤــﺔ اﻻﺑﺘﺪاﺋﻴــﺔ‪ .‬اﻟﻌﻨﺼــﺮ اﻟﺜــﺎﱏ ﻟــﻴﺲ أﻣـﺮا و ﻟﻜﻨــﻪ‬

‫‪68‬‬
‫ﲨﻠــﺔ ﺷــﺮﻃﻴﺔ ﺗﻮﺿــﺢ ﺷــﺮط اﻟﺒﻘــﺎء )أى ﻋﻜــﺲ ﺷــﺮط اﳋــﺮوج( ﰱ اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ ‪ .while_condition‬اﻟﻌﻨﺼــﺮ اﻟﺜﺎﻟــﺚ و اﻷﺧــﲑ‬
‫ﻫــﻮ أﻣــﺮ ﻳﻮﺿــﺢ ﻋﻤﻠﻴــﺔ اﻟﺘﺤــﺪﻳﺚ اﻟــﱴ ﳚــﺐ أن ﺗــﺘﻢ أوﺗﻮﻣﺎﺗﻴﻜﻴــﺎ ﰱ ﺎﻳــﺔ ﻛــﻞ دورة ‪ .incrementing‬ﻋﻨــﺪ اﻟــﺪﺧﻮل ﰱ اﻷﻣــﺮ ‪for‬‬
‫ﻧﺒﺪأ ﺑﻮﺿﻊ اﻟﻘﻴﻤﺔ اﻻﺑﺘﺪاﺋﻴﺔ ﻛﻤﺎ ﻫﻮ ﻣﻮﺿﺢ ﺑــﲔ اﻷﻗـﻮاس ﰒ ﻧﻔﺤــﺺ ﺷــﺮط اﻟﺒﻘــﺎء‪ .‬إذا ﱂ ﻳﺘﺤﻘــﻖ اﻟﺸــﺮط ﺧﺮﺟﻨــﺎ ﻣﺒﺎﺷــﺮة و ﺑــﺬﻟﻚ ﻟــﻦ‬
‫ﺗﻨﺠــﺰ اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ وﻻ ﺣــﱴ ﻣــﺮة واﺣــﺪة‪ .‬أﻣــﺎ إذا ﲢﻘــﻖ ﻓﺈﻧﻨــﺎ ﻧﻨﺠــﺰ اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ اﶈﺘ ـﻮاة ﰱ اﻷﻣــﺮ ‪ .operation‬ﳝﻜــﻦ أن‬
‫ﺗﻜﻮن اﻟﻌﻤﻠﻴﺔ اﻟﺘﻜﺮارﻳﺔ ﻣﻜﻮﻧﺔ ﻣﻦ أﻣﺮ واﺣﺪ و ﻋﻠﻰ ﻫﺬا ﳚــﺐ أن ﳜــﺘﻢ ﻟﻔﺎﺻــﻠﺔ اﳌﻨﻘﻮﻃــﺔ ";" أو أﻣـﺮا ﻣﺮﻛﺒــﺎ و ﻋﻠــﻰ ﻫــﺬا ﻓﻴﺠــﺐ أن‬
‫ﻳﻮﺿــﻊ ﺑــﲔ اﻷﻗـﻮاس اﳌﺜﻨﻴــﺔ } {‪ .‬ﺑﻌــﺪ ﺗﻨﻔﻴــﺬ ﻛــﻞ دورة ﻳــﺘﻢ ﲢــﺪﻳﺚ اﳌﺘﻐـﲑات ﻛﻤــﺎ ﻫــﻮ ﻣﻌﻄــﻰ ﰱ اﻟﻌﻨﺼــﺮ اﻟﺜﺎﻟــﺚ واﻷﺧــﲑ ﻣــﻦ ﻋﻨﺎﺻــﺮ‬
‫اﻷﻣﺮ ‪ for‬ﰒ ﻳﻌﺎد ﻓﺤﺺ ﺷﺮط اﻟﺒﻘﺎء و ﻫﻜﺬا إﱃ أن ﳔﺮج ﻋﻨﺪ ﻋــﺪم ﲢﻘــﻖ اﻟﺸــﺮط‪ .‬ﻛﻤﺜــﺎل أوﱃ ﺳــﻨﻜﺘﺐ ﺑــﺮ ﻣﺞ ﳛﺴــﺐ ﻣﻀــﺮوب‬
‫رﻗﻢ ﺻﺤﻴﺢ‪ .‬ﻳﻮﺿﻊ اﻟﻨﺎﺗﺞ ﰱ ‪ double‬ﻧﻈﺮا ﻷن ﻗﻴﻢ اﳌﻀﺮوب ﻗﺪ ﺗﻜﻮن ﻛﺒﲑة ﺟﺪا‪:‬‬
‫>‪#include <stdio.h‬‬
‫)‪void main(void‬‬
‫{‬
‫;‪int i,n‬‬
‫;‪double fact=1.0‬‬
‫;)" ‪printf("Enter the number you want to find its factorial:‬‬
‫;)‪scanf("%d",&n‬‬
‫)‪if (i < 0‬‬
‫{‬
‫;)‪printf("Invalid input data\n"); getch(); exit(1‬‬
‫}‬
‫)‪for (i=1;i<=n;i++‬‬
‫;‪fact *= i‬‬
‫;)‪printf("The factorial of %d is: %9.0lg",n,fact‬‬
‫}‬
‫ﻳﻌــﺪ أﻣــﺮ ‪ for‬ﺑﺮﻣﺘــﻪ أﻣ ـﺮا واﺣــﺪا )ﺑﻐــﺾ اﻟﻨﻈــﺮ ﻋــﻦ ﻋــﺪد أواﻣــﺮ اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ ﻓﻴــﻪ( و ﳝﻜــﻦ أن ﻳﻈﻬــﺮ ﻛﺠ ـﻮاب ﺷــﺮط ﻣــﺜﻼ ﺑــﺪون‬
‫اﳊﺎﺟﺔ ﻟﻮﺿﻊ أﻗﻮاس ﻣﻨﺜﻨﻴﺔ‪ .‬ﳝﻜﻦ أﻳﻀﺎ أن ﺗﻈﻬﺮ ﺑﺪاﺧﻞ اﻷواﻣﺮ اﻟﺘﻜﺮارﻳﺔ أى ﻣﻦ اﻷواﻣﺮ ‪ continue‬أو ‪ break‬ﻛﻤﺎ ﺳﺒﻖ‪.‬‬
‫ﳝﻜ ــﻦ أن ﳜﺘﻔ ــﻰ أى ﻣ ــﻦ اﻟﻌﻨﺎﺻ ــﺮ اﻟﺜﻼﺛ ــﺔ اﳌﻜﻮﻧ ــﺔ ﻟﻸﻣ ــﺮ )و إن ﻛﻨ ــﺎ ﻻ ﻧﻨﺼ ــﺢ ﺑ ــﺬﻟﻚ( و ﻟﻜ ــﻦ ﳚ ــﺐ أن ﺗﺒﻘ ــﻰ اﻟﻔﺼ ــﻼت‬
‫اﳌﻨﻘﻮﻃﺔ ﻟﻜﻰ ﻧﻌﺮف أى ﻣﻦ اﻷﺟﺰاء اﺧﺘﻔﻰ‪ .‬إذا اﺧﺘﻔﻰ ﺟــﺰء اﻟﻘﻴﻤــﺔ اﻻﺑﺘﺪاﺋﻴــﺔ ﻓﻴﻌــﲎ ذﻟــﻚ أن ﻫــﺬﻩ اﻟﻘﻴﻤــﺔ ﻗــﺪ وﺿــﻌﺖ ﰱ ﻣﻜــﺎن ﻣــﺎ‬
‫ﻗﺒﻞ اﻷﻣﺮ ‪ .for‬إذا اﺧﺘﻔــﻰ ﺟــﺰء اﻟﺸــﺮط اﻋﺘــﱪ أن اﻟﺸــﺮط داﺋﻤــﺎ ﻣﺘﺤﻘــﻖ و ﺑــﺬﻟﻚ ﳓﺼــﻞ ﻋﻠــﻰ ﻋﻤﻠﻴــﺔ ﺗﻜﺮارﻳــﺔ ﻻ ﺎﺋﻴــﺔ‪ ،‬اﳌﻔــﱰض أن‬
‫ﺗﻨﺘﻬﻰ ﻟﺪاﺧﻞ ﻋﻦ ﻃﺮﻳﻖ أﻣﺮ ‪ .break‬أﻣﺎ إذا اﺧﺘﻔﻰ اﻟﺘﺤﺪﻳﺚ ﻓﻴﺠﺐ أن ﻳﺘﻢ ذﻟﻚ داﺧﻞ ﺟﺴﻢ اﻟﻌﻤﻠﻴﺎت اﻟﺘﻜﺮارﻳﺔ‪.‬‬

‫ﳝﻜﻦ أن ﻳﻜﻮن اﻟﺘﺤﺪﻳﺚ ﻳــﺔ ﺻــﻮرة‪ .‬ﻛﻤــﺎ ﳝﻜــﻦ أن ﻳﺘﻜــﻮن أى ﻣــﻦ اﻷﺟـﺰاء اﻟﺜﻼﺛــﺔ ﻣــﻦ أﻛﺜــﺮ ﻣــﻦ أﻣــﺮ )ﺗﻔﺼــﻞ ﺑﻴــﻨﻬﻢ ﺣﻴﻨﺌــﺬ‬
‫اﻟﻔﺎﺻﻠﺔ ‪ .(,‬ﻫﺬا ﻣﺎ ﻳﻮﺿﺤﻪ اﳌﺜﺎل اﻟﺘﺎﱃ و اﻟﺬى ﳛﺴﺐ ﳎﻤﻮع ﻣﺘﻮاﻟﻴﺔ ﻫﻨﺪﺳﻴﺔ ﺣﺪﻫﺎ اﻷول ‪ a‬و أﺳﺎﺳﻬﺎ ‪ r‬و ﻋﺪد ﺣﺪودﻫﺎ ‪:n‬‬
‫>‪#include <stdio.h‬‬
‫)‪void main(void‬‬
‫{‬
‫;‪int n,i‬‬
‫;‪double a,r,sum‬‬
‫;)" ‪printf("Enter number of terms, the first term and the ratio:‬‬
‫;)‪scanf("%d %lg %lg",&n,&a,&r‬‬
‫)‪for (sum=0,i=1; i<=n; a*=r,i++‬‬
‫;‪sum += a‬‬
‫;)‪printf("The sum is: %lg\n",sum‬‬

‫‪69‬‬
‫}‬
‫ﰱ ﻫﺬا اﻟﱪ ﻣﺞ ﻧﻘﻮم ﺑﺘﻨﻔﻴﺬ ﻋﻤﻠﻴﺘﲔ ﰱ اﳌﺮﺣﻠﺔ اﻻﺑﺘﺪاﺋﻴﺔ )‪ ،(sum=0, i=1‬ﻛﻤﺎ ﻧﻘﻮم ﺑﺘﻨﻔﻴﺬ ﻋﻤﻠﻴﺘﲔ ﰱ ﺎﻳﺔ ﻛﻞ دورة ﻋﻠﻰ‬
‫ﺳﺒﻴﻞ اﻟﺘﺤﺪﻳﺚ )‪.(a*=r;i++‬‬

‫و ﻛﻤﺜﺎل أﺧﲑ ﻋﻠﻰ اﻟﻌﻤﻠﻴﺔ اﻟﺘﻜﺮارﻳﺔ‪ ،‬ﺳﻨﺪرس ﺑﺮ ﳎﺎ ﳛﺴﺐ ﺣﺪود ﻣﺘﻮاﻟﻴﺔ ﻓﻴﺒﻮ ﺗﺸﻰ‪ .‬ﺗﻌﺮف ﺣﺪود ﻫﺬﻩ اﳌﺘﻮاﻟﻴﺔ‬
‫ﻛﺎﻟﺘﺎﱃ‪:‬‬
‫‪F0 = F1 = 1‬‬
‫‪Fn = Fn-1 + Fn-2‬‬ ‫‪for n>1‬‬
‫اﻟــﱪ ﻣﺞ ﺳــﻴﻘﺮأ ﺗﺮﺗﻴــﺐ اﳊــﺪ اﳌ ـﺮاد ﺣﺴــﺎﺑﻪ‪ ،‬ﰒ ﳛﺴــﺐ و ﻳﻜﺘــﺐ ﻗﻴﻤﺘــﻪ‪ .‬ﺣﻴــﺚ أن ﻛــﻞ ﺣــﺪ ﻣﻌــﺮف ﺑﺪﻻﻟــﺔ اﳊــﺪﻳﻦ اﻟﺴــﺎﺑﻘﲔ‪ ،‬ﻓــﺈن‬
‫ﺣﺴﺎب أى ﺣﺪ ﻣﺜﻞ اﳊﺪ اﻟﺴﺎﺑﻊ ﻣﺜﻼ‪ ،‬ﻳﺴﺘﺘﺒﻊ ﺣﺴﺎب اﳊﺪﻳﻦ اﻟﺴﺎدس و اﳋــﺎﻣﺲ‪ ،‬و ﻛﻼﳘــﺎ ﻳﺴــﺘﺘﺒﻊ ﺣﺴــﺎب ﺣــﺪود ﺳــﺎﺑﻘﺔ ﺣــﱴ‬
‫ﻧﺼــﻞ ﻟﻠﺤــﺪﻳﻦ اﻷول و اﻟﺜــﺎﱏ‪ .‬ﺳــﻴﺘﻢ اﳊﺴــﺎب إذن ﺑــﺪءا ﻣــﻦ اﳊــﺪﻳﻦ اﻷول و اﻟﺜــﺎﱏ ﺻــﺎﻋﺪا ﺣــﱴ ﻧﺼــﻞ ﻟﻠﺤــﺪ اﳌﻄﻠــﻮب‪ .‬ﰱ ﻛــﻞ ﻣــﺮة‬
‫ﳓﺘــﺎج ﳌﺨــﺰن ﻧﻀــﻊ ﻓﻴــﻪ اﳊــﺪ اﻟﺴــﺎﺑﻖ و اﳊــﺪ اﻷﺳــﺒﻖ )ﺳﻨﺴــﻤﻴﻬﻤﺎ ‪ (old, older‬ﰒ ﺧ ـﺰان ﻧﻀــﻊ ﻓﻴــﻪ اﳊ ـﺪ اﳉﺪﻳــﺪ ‪ .term‬و ﻋﻨــﺪ‬
‫ﺣﺴﺎب ذﻟﻚ اﳊــﺪ‪ ،‬ﻧﻘــﻮم ﺑﱰﺣﻴــﻞ اﻟﻘــﻴﻢ ‪ shifting‬ﲝﻴــﺚ ﻧﻀــﻊ ﳏﺘــﻮى اﳊــﺪ اﻟﺴــﺎﺑﻖ ﰱ اﳊــﺪ اﻷﺳــﺒﻖ و ﳏﺘــﻮى اﳊــﺪ اﳉﺪﻳــﺪ ﰱ اﳊــﺪ‬
‫اﻟﺴــﺎﺑﻖ‪ ،‬و ﻧﻜــﺮر اﻟﻌﻤﻠﻴــﺔ ﻟﻠﺤﺼــﻮل ﻋﻠــﻰ ﻗﻴﻤــﺔ اﳊــﺪ اﻟﺘــﺎﱃ‪ ،‬و ﻫﻜــﺬا أﱃ أن ﻧﺼــﻞ ﻟﻠﺤــﺪ اﳌﻄﻠــﻮب‪ .‬و ﻟﻜــﻦ ﺗﻄﺒﻴــﻖ اﻟﻘﻮاﻋــﺪ اﻟﺬﻫﺒﻴــﺔ‬
‫اﳋﻤﺴﺔ ﻻﺧﺘﺒﺎر اﻟﻌﻤﻠﻴﺎت اﻟﺘﻜﺮارﻳﺔ ﺳﻴﻜﺸﻒ ﻟﻨﺎ ﻋﻦ ﻣﻔﺎﺟﺄة ﻗﺪ ﺗﻜﻮن ﻗﺪ ﻏﺎﺑﺖ ﻋﻦ أذﻫﺎﻧﻨﺎ ﻷول وﻫﻠﺔ!‬
‫>‪#include <stdio.h‬‬
‫)‪void main(void‬‬
‫{‬
‫;‪int old,older,term‬‬
‫;‪int I,N‬‬
‫;‪old = older = 1‬‬
‫;)"‪printf("Enter the required Fibonacci term order:‬‬
‫;)‪scanf ("%d",&N‬‬
‫)‪for (I=2;I<=N;I++‬‬
‫{‬
‫;‪term = old + older‬‬
‫;‪older = old‬‬
‫;‪old = term‬‬
‫}‬
‫;)‪printf("The value of the required term is: %d", old‬‬
‫}‬

‫ﻗﺪ ﻳﺪﻫﺶ اﻟﻘﺎرئ ﻟﻜﺘﺎﺑﺔ ﻗﻴﻤﺔ ‪ old‬و ﻟﻴﺲ ‪ ،term‬و ﻟﻜﻦ ﺗﺬﻛﺮ أن اﻟﻌﻤﻠﻴﺔ اﻟﺘﻜﺮارﻳﺔ ﻗﺪ ﻻ ﺗﻨﺠــﺰ أﺑــﺪا! ﺳــﻨﱰك ﲢﻠﻴــﻞ ذﻟـﻚ ﻟﻠﻘــﺎرئ‬
‫ﻛﺘﺪرﻳﺐ‪.‬‬

‫‪70‬‬
‫‪Advanced Data Structures‬‬ ‫ﻫﻴﺎﻛﻞ ﺑﻴﺎ ت ﻣﺘﻘﺪﻣﺔ‬ ‫‪.4‬‬

‫‪.4‬أ‪ .‬اﳌﺆﺷﺮات ‪Pointers‬‬

‫اﳌﺆﺷ ـﺮات ﻫــﻰ ﻧــﻮع ﻣــﻦ اﻟﺒﻴــﺎ ت اﻟﺒﺴــﻴﻄﺔ )أى ﻏــﲑ اﳌﻬﻴﻜﻠــﺔ( اﻟــﱴ اﺳــﺘﺤﺪﺛﺖ ﻛﻤﻔﻬــﻮم ﺑﺮﳎــﻰ ﺣــﺪﻳﺚ ﻧﺴــﺒﻴﺎ ﰱ ﺑﻌــﺾ‬
‫اﻟﻠﻐﺎت‪ ،‬و ﻣﻨﻬﺎ ﻟﻐــﺔ ‪ .C‬ﺗﻴﺴــﺮ اﳌﺆﺷـﺮات اﻟﻌﺪﻳــﺪ ﻣــﻦ اﻟﻌﻤﻠﻴــﺎت اﳌﻌﻘــﺪة ﻛﻤــﺎ ﺗﺴــﻬﻢ ﰱ اﻹﺳـﺮاع ﻣــﻦ ﺗﻨﻔﻴـﺬ ﺑﻌــﺾ ﺧﻄـﻮات اﻟـﱪاﻣﺞ‪ ،‬و‬
‫ﻟﻜﻦ اﻷﻫﻢ ﻣﻦ ﻛﻞ ذﻟﻚ ﻫﻮ أ ﺎ ﺗﻔﺘﺢ آﻓﺎﻗﺎ ﺟﺪﻳﺪة ﻋــﻦ ﻃﺮﻳــﻖ إ ﺣــﺔ أﻧـﻮاع ﺟﺪﻳــﺪة ﻣــﻦ ﻫﻴﺎﻛــﻞ اﻟﺒﻴــﺎ ت ﻣﺜــﻞ اﻟﺴﻼﺳــﻞ و اﻷﺷــﺠﺎر‬
‫ﻛﻤﺎ ﺳﻨﺮى ﻓﻴﻤﺎ ﺑﻌﺪ‪.‬‬

‫‪.4‬ب‪ .‬ﺗﻌﺮﻳﻒ اﳌﺆﺷﺮ ‪Definition of pointers‬‬

‫اﳌﺆﺷﺮ ﻫﻮ ﺧﺎﻧﺔ ذاﻛﺮة ﻻ ﲢﻮى ﺑﻴﺎ ت ﻣﺒﺎﺷﺮة و ﻟﻜﻨﻬﺎ ﲢــﻮى ﻋﻨـﻮان ﺧﺎﻧــﺔ ذاﻛــﺮة أﺧــﺮى ﲢــﻮى ﺑﻴــﺎ ت ﻣﻔﻴــﺪة‪ .‬ﻟﻠﺘﻮﺿــﻴﺢ‪،‬‬
‫ﲣﻴﻞ أﻧﻨﺎ ﻋﺮﻓﻨﺎ ﻣﺘﻐﲑا ﻣﻦ ﻧﻮع ‪ int‬ﻛﺎﻟﺘﺎﱃ‪:‬‬
‫;‪int n‬‬
‫ﻋﻨﺪ ﻛﺘﺎﺑﺔ ذﻟﻚ اﻟﺴﻄﺮ ﻳﻘﻮم اﳊﺎﺳﺐ ﻟﺒﺤﺚ ﻋــﻦ ﺧﺎﻧــﺔ ذاﻛــﺮة ﻏــﲑ ﻣﺴــﺘﺨﺪﻣﺔ ﻣﻜﻮﻧــﺔ ﻣــﻦ ﻋــﺪد ‪ 2‬ﻳــﺖ ﳊﺠﺰﻫــﺎ ﲢــﺖ اﺳــﻢ اﳌﺘﻐــﲑ‬
‫‪ .n‬ﻟﻨﻔﺮض أﻧــﻪ وﺟــﺪ اﳋﺎﻧــﺔ رﻗــﻢ ‪ 112‬و ﻣــﺎ ﻳﻠﻴﻬــﺎ‪ .‬ﺳــﻴﻠﺤﻖ اﳊﺎﺳــﺐ اﻟــﺮﻗﻢ ‪ 112‬ﺳــﻢ اﳌﺘﻐــﲑ ‪ n‬ﲝﻴــﺚ ﻳﻜﺘــﺐ ﰱ أو ﻳﻘـﺮأ ﻣــﻦ ﻫــﺬﻩ‬
‫اﳋﺎﻧﺔ ﻋﻨﺪﻣﺎ ﻳﺮد ذﻛﺮ اﳌﺘﻐﲑ ‪ .n‬إذ ا أرد أن ﻧﻌﺮف ﻋﻨـﻮان اﳋﺎﻧــﺔ اﶈﺠــﻮزة ﲢــﺖ أﺳــﻢ اﳌﺘﻐــﲑ ‪ n‬ﳝﻜــﻦ أن ﻧﻜﺘــﺐ ‪ &n‬و ﺗﻘـﺮأ "ﻋﻨـﻮان‬
‫‪ "n‬و ﻫﻰ ﺗﺴﺎوى ﰱ ﻫﺬﻩ اﳊﺎﻟﺔ اﻟﻌﺪد ‪ .112‬ﻧﻔﺮض اﻵن أﻧﻨﺎ أﻋﻠﻨﻨﺎ ﻋﻦ ﻣﺘﻐﲑ ﻣﻦ ﻧﻮع ﻣﺆﺷﺮ ﻳﺸﲑ إﱃ ‪ int‬ﻛﺎﻟﺘﺎﱃ‪:‬‬
‫;‪int * point‬‬
‫ﻳﻘـﺮأ اﻟﺴــﻄﺮ اﻟﺴــﺎﺑﻖ ﻣــﻦ اﻟﻴﻤــﲔ إﱃ اﻟﻴﺴــﺎر‪ point :‬ﻫــﻮ ﻣﺆﺷــﺮ ﻳﺸــﲑ إﱃ ﺧﺎﻧــﺔ ﻣــﻦ ﻧــﻮع ‪) .int‬اﻟﻌﻼﻣــﺔ * ﺗﻌــﲎ ﻫﻨــﺎ "ﻳﺸــﲑ إﱃ"(‪ .‬و‬
‫ﺑــﺬﻟﻚ ﰎ اﻹﻋــﻼن اﻟــﺬى ﺳــﻴﺤﺠﺰ اﳊﺎﺳــﺐ ﻋﻠــﻰ أﺳﺎﺳــﻪ ﺧﺎﻧــﺔ ذاﻛــﺮة ﺟﺪﻳــﺪة ﲢــﺖ اﺳــﻢ اﳌﺘﻐــﲑ اﳉﺪﻳــﺪ‪ .‬ﻧﻔــﺮض أﻧــﻪ وﺟــﺪ اﳋﺎﻧــﺔ رﻗــﻢ‬
‫‪ .101‬ﻗﺒﻞ أن ﻧﺴــﺘﻌﻤﻞ اﳌﺆﺷــﺮ ﰱ أﻳــﺔ ﻋﻤﻠﻴــﺔ ﻣﻔﻴــﺪة ﻟﻜﺘﺎﺑــﺔ أو ﻗـﺮاءة أو ﺗﻌــﺪﻳﻞ ﺑﻴــﺎ ت ﳚــﺐ أن ﻧﻀــﻊ ﻓﻴــﻪ ﻋﻨـﻮان ﺧﺎﻧــﺔ اﻟــﺬاﻛﺮة اﻟــﱴ‬
‫ﺳﻴﺸﲑ إﻟﻴﻬﺎ و اﻟﱴ ﲢﻮى اﻟﺒﻴﺎ ت اﳌﻔﻴﺪة‪ .‬ﻟﻜﻲ ﳒﻌﻞ ﻫﺬا اﳌﺘﻐﲑ ﻳﺸﲑ إﱄ ‪ n‬ﻳﻜﻔﻰ أن ﻧﻀﻊ ﰲ ‪ point‬ﻋﻨﻮان ‪ n‬ﻛﺎﻟﺘﺎﱃ‪:‬‬
‫;‪point = &n‬‬
‫اﻟﻌﻼﻣﺔ & ﺗﻌﲎ ﻫﻨﺎ "ﻋﻨﻮان" اﳌﺘﻐﲑ اﻟﺬى ﻳﻠﻴﻬﺎ‪ .‬ﳝﻜﻦ ﺑﻌﺪ ذﻟﻚ أن ﻧﻘـﺮأ ﺑﻴــﺎ ت أو ﻧﻜﺘﺒﻬــﺎ ﰲ ﺧﺎﻧــﺔ اﻟــﺬاﻛﺮة ‪ 112‬إﻣــﺎ ﻣﺒﺎﺷــﺮة ﻋــﻦ‬
‫ﻃﺮﻳﻖ اﳌﺘﻐﲑ ‪ n‬أو ﺑﻄﺮﻳﻘﺔ ﻏﲑ ﻣﺒﺎﺷﺮة ﻋﻦ ﻃﺮﻳﻖ اﳌﺘﻐﲑ ‪ .point‬ﻓﺈذا ﻛﺘﺒﻨﺎ ﻣﺜﻼ‪:‬‬
‫;‪*point = 14‬‬
‫‪101‬‬ ‫‪pt‬‬ ‫‪112‬‬ ‫‪n‬‬
‫‪112‬‬ ‫‪14‬‬

‫‪71‬‬
‫ﻓــﺈن ﳏﺘــﻮى اﳋﺎﻧــﺔ اﻟــﱴ ﻳﺸــﲑ إﻟﻴﻬ ـﺎ اﳌﺘﻐــﲑ ‪) point‬أى اﳋﺎﻧــﺔ ‪ 112‬ﰱ ﻫــﺬا اﳌﺜــﺎل( ﺳــﻴﻌﺪل ﻟﻴﺼــﺒﺢ ‪ .14‬اﻟﻨﺠﻤــﺔ ﻗﺒــﻞ ‪ point‬ﰱ‬
‫اﻟﺴــﻄﺮ اﻟﺴــﺎﺑﻖ ﺗﻌــﲎ "ﻣــﺎ ﻳﺸــﲑ إﻟﻴــﻪ"‪ .‬و ﻋﻠﻴــﻪ ﻓــﺈن اﻟﺴــﻄﺮ اﻟﺴــﺎﺑﻖ ﻳﻘ ـﺮأ‪ :‬ﺿــﻊ ‪ 14‬ﰱ ﻣــﺎ ﻳﺸــﲑ إﻟﻴــﻪ ‪ .point‬ﻳﻮﺿــﺢ اﳌﺜــﺎل اﻟﺘــﺎﱃ‬
‫اﺳﺘﺨﺪام اﳌﺆﺷﺮات‪:‬‬
‫>‪#include <stdio.h‬‬
‫)‪void main(void‬‬
‫{‬
‫;‪int n, m‬‬
‫;‪int * pt1, *pt2‬‬
‫;‪pt1 = &n‬‬
‫;‪n = 17‬‬
‫;)‪printf ("value of n = %d ; value pointed to by pt1: %d\n", n , *pt1‬‬
‫‪/* will print 17 twice */‬‬

‫;‪*pt1 = 14‬‬
‫;)‪printf ("value of n = %d ; value pointed to by pt1: %d\n", n , *pt1‬‬
‫‪/* will print 14 twice */‬‬

‫"‪printf("address pointed to=%p ; value= %int ; address of point=%p‬‬


‫;)‪,pt1, *pt1, &pt1‬‬
‫‪/* will print &n (112 say), 14 and &point (101 say) */‬‬

‫;‪pt2 = &m‬‬
‫;‪*pt2 = n + 5‬‬
‫;)‪printf ("m=%d\n",m‬‬
‫‪/* will print 19 */‬‬
‫}‬
‫ﲢﺘ ــﺎج اﳌﺘﻐـ ـﲑات اﻟﻌﺎدﻳ ــﺔ )أى ﲞ ــﻼف اﳌﺆﺷـ ـﺮات( ﳋﻄ ــﻮﺗﲔ ﻗﺒ ــﻞ أن ﺗﺴ ــﺘﺨﺪم ﻷول ﻣ ــﺮة ﰱ اﻟ ــﱪ ﻣﺞ‪ .‬اﳋﻄ ــﻮة اﻷوﱃ ﻫ ــﻰ‬
‫اﻹﻋﻼن ﻣﺜﻞ ‪ int n‬ﰱ اﻟﱪ ﻣﺞ اﻟﺴﺎﺑﻖ‪ .‬اﳋﻄﻮة اﻟﺜﺎﻧﻴﺔ ﻫﻰ إﻋﻄﺎء ﻗﻴﻤﺔ اﺑﺘﺪاﺋﻴــﺔ ‪ initialization‬ﻣﺜــﻞ ‪ .n=17‬ﻟﻨﺴــﺒﺔ ﻟﻠﻤﺆﺷـﺮات‬
‫ﻓﺈﻧﻨﺎ ﳓﺘﺎج ﺑﻌﺪ اﻹﻋــﻼن )اﻷﻣــﺮ ‪ (int *pt1‬ﻷن ﻧﻀــﻊ ﻓﻴــﻪ ﻋﻨـﻮان ﺧﺎﻧــﺔ ذاﻛــﺮة ﻗﺒــﻞ أن ﻧﺘﻌﺎﻣــﻞ ﻣﻌــﻪ ى ﺻــﻮرة ﻛﺎﻧــﺖ‪ .‬ﻻﺣــﻆ اﻟﻔــﺮق‬
‫ﺑﲔ إﻋﻄﺎء ﻗﻴﻤﺔ اﺑﺘﺪاﺋﻴﺔ ﳌﺆﺷﺮ )اﻷﻣﺮ ‪ (pt2 = &m‬و ﺑﲔ إﻋﻄﺎء ﻗﻴﻤﺔ اﺑﺘﺪاﺋﻴﺔ ﳌﺎ ﻳﺸﲑ إﻟﻴﻪ )اﻷﻣﺮ ‪.(*pt2 = n+5‬‬

‫‪.4‬ب‪ .1.‬اﳌﺆﺷﺮات و اﳌﺘﺠﻬﺎت ‪Pointers and vectors‬‬

‫ﻗﺪ ﻳﻌﺠﺐ اﻟﻘﺎرئ ﱂ ﻛﻞ ﻫﺬا اﻟﻠﻒ و اﻟﺪوران؟ إذا ﻛﺎن ﻹﻣﻜــﺎن اﻟﺘﻌﺎﻣــﻞ ﻣــﻊ اﳋﺎﻧــﺔ ‪ 112‬ﺑﻮاﺳــﻄﺔ اﳌﺘﻐــﲑ ‪ n‬ﻣﺒﺎﺷــﺮة ﻓﻤــﺎ‬
‫اﻟﺬي ﻳﻀﻴﻔﻪ اﳌﺆﺷﺮ؟ ﰲ اﻟﻮاﻗﻊ‪ ،‬ﻳﻘﻮم اﳊﺎﺳﺐ داﺧﻠﻴﺎ ﻟﺘﻌﺎﻣﻞ ﻣــﻊ ﻫﻴﺎﻛــﻞ اﻟﺒﻴــﺎ ت )و اﻟــﱴ ﱂ ﻧــﺪرس ﻣﻨﻬــﺎ ﻟــﻶن ﺳــﻮى اﳌﺼــﻔﻮﻓﺎت(‬
‫و ﻛــﺬا ﻣــﻊ اﻟــﺪوال ﻋــﻦ ﻃﺮﻳــﻖ اﳌﺆﺷ ـﺮات‪ ،‬و ﺑﺼــﻮرة ﻣﻜﺜﻔــﺔ‪ .‬ﻻ ﻳﺸــﻌﺮ ﺑــﺬﻟﻚ اﳌﺴــﺘﺨﺪم اﻟﻌــﺎدى ﺧﺎﺻــﺔ ﰱ اﻟﻠﻐــﺎت اﻷﺧــﺮى و ﻓﻴﻬــﺎ‬
‫ﳛــﺘﻔﻆ اﳊﺎﺳــﺐ ﻟﻨﻔﺴــﻪ ﲝــﻖ اﻟﺘﻌﺎﻣــﻞ ﻣــﻊ اﳌﺆﺷـﺮات ﻣﻮﺻــﺪا اﻟﺒــﺎب أﻣــﺎم اﳌﺴــﺘﺨﺪم‪ .‬ﰱ ﻟﻐــﺔ ‪ Pascal‬أدﺧﻠــﺖ اﳌﺆﺷـﺮات و ﻟﻜــﻦ ﻋﻠــﻰ‬
‫اﺳــﺘﺤﻴﺎء ﳌﻘﺎرﻧــﺔ ﻟﻠﻐــﺔ ‪ C‬اﻟــﱴ ﻓﺘﺤــﺖ اﻟﺒــﺎب ﻋﻠــﻰ ﻣﺼـﺮاﻋﻴﻪ ﲝﻴــﺚ أﺻــﺒﺤﺖ اﳌﺆﺷـﺮات ﺟــﺰءا أﺳﺎﺳــﻴﺎ ﻣــﻦ اﻟﻠﻐــﺔ ﻻ ﳝﻜــﻦ اﻟﺘﻐﺎﺿــﻰ‬
‫ﻋﻨﻪ‪ .‬و ﺑﺬﻟﻚ أﻳﻀﺎ ﻳﺼﺪق اﻟﻘﻮل ن ﻟﻐﺔ ‪ C‬ﺗﺘﻴﺢ ﻛﺘﺎﺑﺔ أواﻣﺮ ﻋﻠﻰ ﻣﺴﺘﻮى اﻟﺒﺸﺮ ﻹﺿﺎﻓﺔ ﻟﻸواﻣﺮ ﻋﻠﻰ ﻣﺴﺘﻮى اﻵﻟﺔ‪.‬‬

‫‪72‬‬
‫ﻟﻨﺮى ﻛﻴﻒ ﻳﺘﻌﺎﻣﻞ اﳊﺎﺳﺐ ﻣﻊ اﳌﺘﺠﻬﺎت أو اﳌﺼﻔﻮﻓﺔ ذات اﻟﺒﻌﺪ اﻟﻮاﺣﺪ‪ .‬ﺣﻴﻨﻤﺎ ﻧﻜﺘﺐ‪:‬‬
‫;]‪double x[10‬‬
‫ﻓــﺈن اﳊﺎﺳــﺐ ﻳﻘــﻮم ﲝﺠــﺰ ‪ 10‬ﺧــﺎ ت ﻣﺘﺘﺎﻟﻴــﺔ ﻣــﻦ ﻧــﻮع ‪) double‬أى أن ﻛــﻞ ﺧﺎﻧــﺔ ﺗﺘﻜــﻮن ﻣــﻦ ‪ 8‬ﻳــﺖ( و ﳛــﺘﻔﻆ ﺑﻌﻨ ـﻮان اﳋﺎﻧــﺔ‬
‫اﻷوﱃ ﰱ ﻣﺘﻐــﲑ أﲰــﻪ ‪ .x‬ﻻﺣــﻆ أن ‪ x‬ﳛــﻮى ﻋﻨ ـﻮان ﺷــﺊ ﻣــﺎ‪ ،‬أى أﻧــﻪ ﻳﻌﻤــﻞ ﻛﺎﳌﺆﺷــﺮ ﲤﺎﻣــﺎ ﻋــﺪا أن ﳏﺘ ـﻮاﻩ )أى ﻋﻨ ـﻮان ﺑﺪاﻳــﺔ اﳌﺘﺠــﻪ(‬
‫ﺑــﺖ و ﻻ ﳝﻜــﻦ ﺗﻌﺪﻳﻠــﻪ أﺛﻨــﺎء اﻟــﱪ ﻣﺞ‪ .‬ﻓــﺈذا ﻇﻬــﺮ ﰱ ﺳــﻴﺎق اﻟــﱪ ﻣﺞ ﻓﻴﻤــﺎ ﺑﻌــﺪ ]‪ x[0‬ﻓــﺈن ذﻟــﻚ ﻳﻌــﲎ اﳋﺎﻧــﺔ اﻟــﱴ ﻳﺸــﲑ إﻟﻴﻬــﺎ ‪ x‬و‬
‫ﳝﻜﻦ إﺑﺪال اﻟﺮﻣﺰ اﻟﺴﺎﺑﻖ ﻟﺮﻣﺰ اﻵﺗﻰ ‪ *x‬اﳌﻜﺎﻓﺊ ﲤﺎﻣﺎ ﻟﻪ‪ .‬و ﳌﺜﻞ ﻓﺈن اﻟﺮﻣﺰ ]‪ x[1‬ﻳﺸــﲑ إﱃ اﳋﺎﻧــﺔ اﻟــﱴ ﺗﻠــﻰ ﺗﻠــﻚ اﻟــﱴ ﻳﺸــﲑ إﻟﻴﻬــﺎ‬
‫‪ .x‬ﳝﻜــﻦ اﺳــﺘﺒﺪال اﻟﺮﻣــﺰ اﻟﺴــﺎﺑﻖ ﻟﺮﻣــﺰ )‪ *(x+1‬اﳌﻜــﺎﻓﺊ ﻟــﻪ أﻳﻀــﺎ‪ .‬ﻟﻨﺘﺄﻣــﻞ ذﻟــﻚ اﻟﺮﻣــﺰ ﺗﻔﺼــﻴﻠﻴﺎ‪ .‬إن إﺿــﺎﻓﺔ ‪ 1‬إﱃ ﻣﺆﺷــﺮ ﻳــﺆدى‬
‫ﻟﻺﺷﺎرة إﱃ اﳋﺎﻧﺔ اﻟﺘﺎﻟﻴﺔ أى ﻳﺘﺤﺮك اﳌﺆﺷــﺮ ﻋــﺪد ﻣــﻦ اﻟﺒﺎﻳــﺖ ﻳﺴــﺎوى ﻋــﺮض ﻧــﻮع اﻟﺒﻴــﺎن اﻟــﺬى ﻳﺸــﲑ إﻟﻴــﻪ‪ .‬ﻧــﻮع اﻟﺒﻴــﺎن اﳌﺸــﺎر إﻟﻴــﻪ ﻫﻨــﺎ‬
‫ﻫــﻮ ‪ double‬و ﻟﺘــﺎﱃ ﻳﺸــﲑ ‪ x+1‬إﱃ اﳋﺎﻧــﺔ اﻟــﱴ ﺗﻘــﻊ ﺑﻌــﺪ اﳋﺎﻧــﺔ اﻟــﱴ ﻳﺸــﲑ إﻟﻴﻬــﺎ ‪ x‬ﲟــﺎ ﻣﻘــﺪارﻩ ‪ 8‬ﻳــﺖ‪ .‬أى أﻧــﻪ ﻳﺸــﲑ ﻟﺘﺤﺪﻳــﺪ‬
‫ﻟﻠﻌﻨﺼﺮ اﻟﺜﺎﱏ ﻣﻦ اﳌﺘﺠﻪ‪.‬‬
‫‪x‬‬ ‫‪x+1‬‬

‫ﻳﻮﺿــﺢ اﳌﺜــﺎل اﻟﺘــﺎﱃ ﺑﻌــﺾ اﻟﻌﻤﻠﻴــﺎت اﻟــﱴ ﳝﻜــﻦ أن ﳒﺮﻳﻬــﺎ ﻋﻠــﻰ اﳌﺆﺷ ـﺮات‪ .‬ﺳــﻨﺒﺪأ ﺑﻜﺘﺎﺑــﺔ ﺑــﺮ ﻣﺞ ﺑﺼــﻮرة ﺗﻘﻠﻴﺪﻳــﺔ ﺑــﺪون‬
‫اﺳﺘﺨﺪام اﳌﺆﺷﺮات‪ .‬اﻟﱪ ﻣﺞ ﻳﺒﺪأ ﺑﻮﺿﻊ اﻟﻘﻴﻤﺔ ﺻﻔﺮ ﰱ اﻟﻌﻨﺼﺮ اﻷول ﻣــﻦ اﳌﺘﺠــﻪ‪ .x[0]=0 :‬ﲨﻴــﻊ اﻟﻌﻨﺎﺻــﺮ اﻟﺘﺎﻟﻴــﺔ ﻟﻠﻤﺘﺠــﻪ ﲢﺴــﺐ‬
‫ﲝﻴﺚ ﺗﺰﻳﺪ ﻗﻴﻤﺔ ﻛﻞ ﻋﻨﺼﺮ ﻋﻦ اﻟﻌﻨﺼﺮ اﻟﺴﺎﺑﻖ ﳌﻘﺪار ‪.2‬‬
‫>‪#include <stdio.h‬‬
‫)‪void main(void‬‬
‫{‬
‫;‪int n‬‬
‫;]‪double x[20‬‬
‫;‪x[0] = 0.0‬‬
‫)‪for (n=1; n<=19; n++‬‬
‫{‬
‫‪x[n] = x[n-1] + 2.0‬‬
‫}‬
‫‪/* Subsequent operations …..*/‬‬
‫}‬
‫ﺳﻨﻌﻴﺪ ﻛﺘﺎﺑﺔ اﻟﱪ ﻣﺞ اﻟﺴﺎﺑﻖ ﺳﺘﺨﺪام اﳌﺆﺷﺮات‪ ،‬ﻣﻊ إﺿﺎﻓﺔ ﻋﻤﻠﻴﺎت أﺧﺮى ﺑﻐﺮض ﺗﻮﺿﻴﺢ أﻧﻮاع اﻟﻌﻤﻠﻴﺎت اﳌﺨﺘﻠﻔــﺔ اﻟــﱴ‬
‫ﳝﻜﻦ أن ﳒﺮﻳﻬﺎ ﻋﻠﻰ اﳌﺆﺷﺮات‪ ،‬ﻛﻤﺎ ﻳﻠﻰ‪:‬‬
‫>‪#include <stdio.h‬‬
‫)‪void main(void‬‬
‫{‬
‫;]‪double x[20‬‬
‫;‪double * pt‬‬
‫;‪x[0] = 0.0‬‬
‫)‪for (pt = x + 1; pt <= x+19; pt++‬‬
‫{‬
‫;‪*pt = *(pt – 1) + 2.0‬‬

‫‪73‬‬
‫}‬
‫‪printf("x[4] = %lg\n",x[4]); /* will print 8.0 */‬‬
‫;‪pt = x+10‬‬
‫;)]‪printf ("Second after 10: %lg first before 10: %lg\n",pt[2],pt[-1‬‬
‫‪/* will print 24.0 and 18.0*/‬‬
‫}‬
‫ﰱ اﻷﻣ ــﺮ ‪ for‬ﳒﻌ ــﻞ اﳌﺆﺷــﺮ ‪ pt‬ﻳﺆﺷ ــﺮ ﻋﻠ ــﻰ اﻟﻌﻨﺼ ــﺮ اﻟﺜ ــﺎﱏ ﻣ ــﻦ اﳌﺘﺠ ــﻪ أى اﻟﻌﻨﺼ ــﺮ ]‪ x[1‬ﻛﻘﻴﻤــﺔ اﺑﺘﺪاﺋﻴ ــﺔ‪ .‬ﺷ ــﺮط اﻟﺒﻘ ــﺎء ﰱ اﻟﻌﻤﻠﻴ ــﺔ‬
‫اﻟﺘﻜﺮارﻳــﺔ ﻣﻜﺘــﻮب ﰱ ﺻــﻮرة ﻋﻤﻠﻴــﺔ ﻣﻘﺎرﻧــﺔ ﺑــﲔ ﻣﺆﺷـﺮات و ﻫــﻰ ﻣﺴــﻤﻮح ــﺎ ﻃﺎﳌــﺎ ﻳﺸــﲑ ﻛــﻼ اﳌﺆﺷـﺮﻳﻦ ﻟــﻨﻔﺲ ﻫﻴﻜــﻞ اﻟﺒﻴــﺎ ت‪ .‬ﻳﺸــﲑ‬
‫‪ x+19‬ﻟﻠﻌﻨﺼﺮ اﻷﺧﲑ ﰱ اﳌﺘﺠﻪ و ﻟﺘــﺎﱃ ﻓﺴــﻨﺒﻘﻰ ﺑــﺪاﺧﻞ اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ ﻃﺎﳌــﺎ أن اﳌﺆﺷــﺮ ‪ pt‬ﻳﺸــﲑ إﱃ ﻋﻨﺼــﺮ ﻋﻨﻮاﻧــﻪ ﻳﻘــﻊ داﺧــﻞ‬
‫اﳌﺘﺠ ــﻪ‪ .‬ﻳ ــﺘﻢ اﻟﺘﺤ ــﺪﻳﺚ ﺳ ــﺘﺨﺪام ﻋﻤﻠﻴ ــﺔ ز دة ‪ incrementation‬ﻋﻠ ــﻰ ﻣﺆﺷ ـﺮات و ﻣﻌﻨﺎﻫ ــﺎ واﺿ ــﺢ‪ :‬ﰱ ﺎﻳ ــﺔ ﻛ ــﻞ دورة ﳓ ــﺪث‬
‫اﳌﺆﺷــﺮ ﲝﻴــﺚ ﻳﺸــﲑ ﻟﻠﻌﻨﺼــﺮ اﻟﺘــﺎﱃ ﰱ اﳌﺘﺠــﻪ‪ .‬اﻷﻣــﺮ اﻟﻮﺣﻴــﺪ ﰱ اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ ﻫــﻮ أﻣــﺮ إﺳــﻨﺎد ﻧﺴــﻨﺪ ﻓﻴــﻪ ﻟﻜــﻞ ﻋﻨﺼــﺮ ﻗﻴﻤــﺔ اﻟﻌﻨﺼــﺮ‬
‫اﻟﺴﺎﺑﻖ ﻣﻀﺎﻓﺎ إﻟﻴﻬﺎ ‪.2‬‬
‫اﻷﺳﻠﻮب اﻟﺬى ﻛﺘﺒﺖ ﺑــﻪ اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ ﺳــﺘﺨﺪام اﳌﺆﺷـﺮات ﻳــﺆدى إﱃ ﺳــﺮﻋﺔ ﰱ اﻷداء ﳌﻘﺎرﻧــﺔ ﻷﺳــﻠﻮب اﻟﺘﻘﻠﻴــﺪى‪.‬‬
‫ﻓﻔﻰ اﻷﺳﻠﻮب اﻟﺘﻘﻠﻴﺪى‪ ،‬ﻫﻨﺎك ﻣﺘﻐﲑ إﺿﺎﰱ ‪ n‬ﻳﺘﻢ ﲢﺪﻳﺜﻪ ﰱ ﻛﻞ دورة ‪ .n++‬ﻹﺿﺎﻓﺔ ﻟــﺬﻟﻚ ﳓﺘــﺎج ﻟﻠﺘﻌﺎﻣــﻞ ﻣــﻊ ]‪x[n], x[n-1‬‬
‫ﰱ ﺟﺴــﻢ اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ‪ ،‬و ﻛﻼﳘــﺎ ﳛﺘــﺎج ﻹﺟـﺮاء ﻋﻤﻠﻴــﺔ ﺣﺴــﺎﺑﻴﺔ )اﻟﻌﻤﻠﻴﺘــﲔ ‪ (x+n, x+n-1‬و ذﻟــﻚ ﲞــﻼف ﻋﻤﻠﻴــﺔ اﳉﻤــﻊ ﻋﻠــﻰ‬
‫‪ .2‬ﰱ ﺣﺎﻟــﺔ اﺳــﺘﺨﺪام اﳌﺆﺷ ـﺮات ﻓﺈﻧﻨــﺎ ﳓﺘــﺎج ﻟﺘﺤــﺪﻳﺚ اﳌﺆﺷــﺮ ﻓﻘــﻂ )و ﻫــﻰ ﻋﻤﻠﻴــﺔ ﺧــﺬ وﻗﺘــﺎ أﻗــﻞ ﻗﻠــﻴﻼ ﻣــﻦ ﲢــﺪﻳﺚ اﳌﺘﻐــﲑ ‪ n‬ﰱ‬
‫اﻷﺳﻠﻮب اﻟﺘﻘﻠﻴﺪى(‪ .‬و ﻟﻜﻦ ﻣﺎ ﻧﻜﺴﺒﻪ ﻓﻌﻼ ﻫﻮ ﰱ ﺟﺴﻢ اﻟﻌﻤﻠﻴﺔ اﻟﺘﻜﺮارﻳﺔ ﺣﻴﺚ أﻧﻨــﺎ ﱂ ﳓﺘــﺎج ﳊﺴــﺎب أﻳــﺔ ﻋﻨـﻮان إﺿــﺎﰱ ﺣﻴــﺚ أن‬
‫اﻟﻌﻨﻮان ﻣﻮﺟﻮد ﻣﺒﺎﺷﺮة ﰱ اﳌﺆﺷﺮ ‪.pt‬‬
‫ﻳﻮﺿﺢ أﻣﺮ اﻟﻜﺘﺎﺑــﺔ اﻟــﺬى ﻳﻠــﻰ اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ أن اﻟﻌﻤﻠﻴــﺎت اﻟــﱴ أﺟﺮﻳﻨﺎﻫــﺎ ﻋﻠــﻰ اﳌﺆﺷـﺮات ﺗــﺆدى ﻟﻠﻜﺘﺎﺑــﺔ ﻋﻠــﻰ اﳌﺘﺠــﻪ ‪.x‬‬
‫ﺑﻌــﺪ ذﻟــﻚ وﺿــﻌﻨﺎ اﻟﻌﻨ ـﻮان ‪ x+10‬ﰱ اﳌﺆﺷــﺮ‪ .‬ﻻﺣــﻆ ﻛﻴــﻒ ﲰــﺢ ﻟﻨــﺎ ذﻟــﻚ ﻟﺘﻌﺎﻣــﻞ ﻣــﻊ ‪ pt‬ﻛﻤــﺎ ﻟــﻮ ﻛــﺎن ﻣﺘﺠﻬــﺎ ﻳﺒــﺪأ ﻋﻨــﺪ اﻟﻌﻨﺼــﺮ‬
‫اﳌﻨــﺎﻇﺮ ﻟﻠﻌﻨﺼــﺮ ]‪ .x[10‬و ﻟﺘــﺎﱃ ﻓــﺈن ]‪ pt[2‬ﻫــﻮ ﻧﻔﺴــﻪ ]‪ x[12‬و اﻷدﻫــﻰ ﻣــﻦ ذﻟــﻚ ﻫــﻮ اﻟﻌﻨﺼــﺮ ]‪ pt[-1‬و ﻫــﻮ ﻣــﺎ ﻳﻌــﲎ أﻳﻀــﺎ‬
‫اﻟﻌﻨﺼﺮ ]‪ .x[9‬أى أن اﳌﺘﺠﻪ ‪ pt‬ﻫﻮ اﻵن ﻣﺘﺠﻪ ﻳﺒﺪأ ﻟﻌﻨﺼﺮ رﻗﻢ ‪ –10‬و ﻳﻨﺘﻬﻰ ﻋﻨﺪ اﻟﻌﻨﺼﺮ ‪ .9‬و ﻫﻮ ﻣﺎ ﻳﻴﺴﺮ ﻛﺘﺎﺑﺔ اﻟﱪاﻣﺞ‪.‬‬

‫‪.4‬ب‪ .2.‬اﻟﻌﻤﻠﻴﺎت ﻋﻠﻰ اﳌﺆﺷﺮات ‪Pointer operations‬‬


‫ﻗﺎﺋﻤﺔ اﻟﻌﻤﻠﻴﺎت اﳌﺴﻤﻮح ﺟﺮاﺋﻬﺎ ﻋﻠﻰ اﳌﺆﺷﺮات ﺳﻨﻌﻄﻴﻬﺎ ﻓﻴﻤﺎ ﻳﻠﻰ ﺑﻔﺮض أﻧﻨﺎ ﻛﺘﺒﻨﺎ اﻹﻋﻼ ت اﻟﺘﺎﻟﻴﺔ‪:‬‬
‫;]‪int * p1, *p2, n, v[20‬‬
‫اﻟﻌﻤﻠﻴﺎت اﳌﺴﻤﻮح ﺎ ﻫﻰ‪:‬‬
‫;‪p1 = NULL‬‬ ‫إﺳﻨﺎد اﻟﻘﻴﻤﺔ اﳌﻌﺮﻓﺔ ﺳﻠﻔﺎ ‪ NULL‬و ﺗﺴﺎوى اﻟﺼﻔﺮ‬
‫;‪p1 = v + 5‬‬ ‫إﺳﻨﺎد ﻋﻨﻮان ﻣﻌﺮف ﻋﻠﻰ ﻫﺬﻩ اﻟﺼﻮرة‬
‫;)]‪p2 = &(v[6‬‬ ‫إﺳﻨﺎد ﻋﻨﻮان ﻣﻌﺮف ﻋﻠﻰ ﺻﻮرة أﺧﺮى‬
‫;‪p2 = p1 + 3; p1 = p2 – 1‬‬ ‫إﺿﺎﻓﺔ أو ﻃﺮح ﻋﺪد ﺻﺤﻴﺢ‬
‫;‪p1 ++; p2 --‬‬ ‫اﻟﺰ دة و اﻹﻧﻘﺎص‬
‫ﺣﺴــﺎب اﻟﻔــﺎرق ﺑــﲔ ﻣﺆﺷ ـﺮﻳﻦ و ﻳﻌﻄــﻰ اﻟﻨــﺎﺗﺞ ﻋــﺪد ﺻــﺤﻴﺢ ﻳﺴــﺎوى ﻋــﺪد اﳋــﺎ ت اﻟــﱴ ﺗﻔﺼــﻞ ﺑﻴﻨﻬﻤــﺎ‪) .‬ﻻﺣــﻆ أن ﻫــﺬﻩ‬
‫;‪n = p2–p1‬‬ ‫اﻟﻌﻤﻠﻴﺔ ﻻ ﺗﻌﲎ ﺷﻴﺌﺎ إﻻ إذا أﺷﺎرا ﻟﻨﻔﺲ اﳌﺘﺠﻪ(‬
‫اﳌﻘﺎرﻧﺔ ﺑﲔ ﻣﺆﺷﺮﻳﻦ و ﻻ ﺗﻌﲎ ﺷﻴﺌﺎ إﻻ إذا أﺷﺎرا ﻟﻨﻔﺲ اﳌﺘﺠﻪ;‪if (p2 == p1) ..‬‬

‫‪74‬‬
‫‪if (p2 > p1) ….; ….‬‬
‫اﻟﻌﻤﻠﻴﺎت ﻏﲑ اﳌﺴﻤﻮح ﺎ‪:‬‬
‫‪p2 + p1; /*Forbiden*/‬‬ ‫ﲨﻊ ﻣﺆﺷﺮﻳﻦ ﺣﻴﺚ أن ذﻟﻚ ﻻ ﻳﻌﲎ ﺷﻴﺌﺎ‬
‫إﺳﻨﺎد ﻗﻴﻤﺔ ﳌﺆﺷﺮ ﺑﺖ ﻣﺜﻞ ‪ v‬اﳌﻌﺮف ﻋﺎﻟﻴﻪ ‪&v=p2; &(v[5])=p1/*forbiden*/‬‬
‫ﻳﻨﺒﻐﻰ اﳊﻈﺮ ﻋﻨﺪ ﻛﺘﺎﺑﺔ ﻋﻤﻠﻴــﺎت اﻟــﺰ دة ﻋﻠــﻰ اﳌﺆﺷـﺮات ﻟﻜــﻴﻼ ﳔﻠــﻂ ﺑــﲔ ز دة اﳌﺆﺷــﺮ )أى اﻹﺷــﺎرة ﻟﻠﻌﻨﺼــﺮ اﻟﺘــﺎﱃ( و ﺑــﲔ‬
‫ز دة ﻣﺎ ﻳﺸﲑ إﻟﻴﻪ )أى ز دة اﳌﻘﺪار اﳌﺨﺘﺰن ﰱ اﳋﺎﻧﺔ اﻟﱴ ﻳﺸﲑ إﻟﻴﻬﺎ(‪ .‬ﻛﻤﺎ ﻳﻮﺿﺢ اﳉﺪول اﻟﺘﺎﱃ‪:‬‬

‫ﻣﺎ ﻳﻌﻨﻴﻪ إذا ﻇﻬﺮ ﰱ أى ﺗﻌﺒﲑ‬ ‫اﻟﺮﻣﺰ‬


‫ز دة اﻟﻘﻴﻤﺔ اﻟﱴ ﻳﺸﺎر إﻟﻴﻬﺎ ﻣﻊ إﻋﻄﺎء اﻟﻘﻴﻤﺔ اﳉﺪﻳﺪة ﰱ اﻟﺘﻌﺒﲑ‬ ‫)‪++(*p‬‬
‫;‪Ex: int n,k; int p‬‬
‫‪n=5; p=&n; k=++(*p) + 2; /* n will be assigned 6 , k will be 8*/‬‬
‫إﻋﻄﺎء اﻟﻘﻴﻤﺔ اﻟﱴ ﻳﺸﺎر إﻟﻴﻬﺎ ﺣﺎﻟﻴﺎ و ز د ﺎ ﺑﻌﺪ اﻻﺳﺘﺨﺪام ﰱ اﻟﺘﻌﺒﲑ‬ ‫‪(*p)++‬‬
‫;‪Ex: int n,k; int p‬‬
‫‪n=5; p=&n; k=(*p)++ + 2; /* n will be assigned 6 , k will be 7*/‬‬
‫ز دة ﻋﻨﻮان اﳌﺆﺷﺮ ﰒ إﻋﻄﺎء ﻗﻴﻤﺔ ﻣﺎ ﻳﺸﺎر إﻟﻴﻪ ﺣﺪﻳﺜﺎ‬ ‫)‪*(++p‬‬
‫;‪Ex: double x[11],y; double * p‬‬
‫‪p=x+3; y=*(++p) + 2.5; /* y will be x[4] + 2.5 , p will point to x[4]*/‬‬
‫إﻋﻄﺎء اﻟﻘﻴﻤﺔ اﻟﱴ ﻳﺸﺎر إﻟﻴﻬﺎ ﰒ ز دة اﻟﻌﻨﻮان اﻟﺬى ﻳﺸﺎر إﻟﻴﻪ ﺑﻌﺪ ﺣﺴﺎب اﻟﺘﻌﺒﲑ‬ ‫)‪*(p++‬‬
‫;‪Ex: double x[11],y; double * p‬‬
‫‪p=x+3; y=*(p++) + 2.5; /* y will be x[3] + 2.5 , p will point to x[4]*/‬‬
‫ﻻﺣﻆ أﻳﻀﺎ أﳘﻴﺔ إﻋﻄﺎء ﻧﻮع اﻟﺒﻴﺎ ت اﻟﱴ ﻳﺸﲑ إﻟﻴﻬﺎ اﳌﺆﺷﺮ ﻋﻨﺪ ﺗﻌﺮﻳﻔﻪ ﺣﻴﺚ أن ذﻟــﻚ ﻳــﺆﺛﺮ ﻣﺒﺎﺷــﺮة ﻋﻠــﻰ ﺗــﺞ ﻋﻤﻠﻴــﺎت‬
‫اﻹﺿﺎﻓﺔ أو اﻟﻄﺮح‪ .‬ﻓﺈن إﺿﺎﻓﺔ ‪ 1‬ﳌﺆﺷﺮ ﻳﺸﲑ إﱃ ‪ double‬ﻣــﺜﻼ ﺗﻌــﲎ ﲢﺮﻳــﻚ اﳌﺆﺷــﺮ ﻣﺴــﺎﻓﺔ ‪ 8‬ﻳــﺖ‪ .‬أﻣــﺎ إذا ﻛــﺎن اﳌﺆﺷــﺮ ﻳﺸــﲑ إﱃ‬
‫‪ short‬ﻓﺈن ذﻟﻚ ﻳﺆدى ﻟﺘﺤﺮﻳﻜﻪ ﻣﺴﺎﻓﺔ ‪ 2‬ﻳﺖ ﻓﻘﻂ‪ .‬ﳍﺬا اﻟﺴﺒﺐ ﻻ ﻳﺴﻤﺢ ﺑﻌﻤﻠﻴﺔ ﻛﻬﺬﻩ‪:‬‬
‫;‪int * p1, n; double * p2‬‬
‫‪n = p2 – p1; /* forbiden and meaningless ! */‬‬
‫و ﻟﻜﻦ ﻳﺴﻤﺢ ﻋﺎدة ﻗﻮﻟﺒﺔ ‪ type casting‬ﳌﺎ ﻳﺸﲑ إﻟﻴﻪ ﻣﺆﺷﺮ و ﻫﻰ ﻋﻤﻠﻴﺔ ﲢﺘﺎج ﳊﺮص ﺷﺪﻳﺪ‪.‬‬

‫‪.4‬ب‪ .3.‬اﳊﺠﺰ اﻟﺪﻳﻨﺎﻣﻴﻜﻰ ﻟﻠﺬاﻛﺮة ‪Dynamic memory allocation‬‬


‫رأﻳﻨﺎ ﻓﻴﻤﺎ ﺳﺒﻖ أﻧﻪ ﻷﺟﻞ اﺳﺘﺨﺪام ﻣﺘﺠﻪ ﳚﺐ اﻹﻋﻼن ﻋﻨﻪ ﻣﺴــﺒﻘﺎ ﰱ ﺑﺪاﻳــﺔ اﻟــﱪ ﻣﺞ و ﻳﻌــﲎ ذﻟــﻚ ﺣﺠــﺰ ﻋــﺪد ﺑــﺖ ﻣــﻦ‬
‫اﳋــﺎ ت‪ .‬ﻻ ﳝﻜــﻦ أن ﻧﺆﺟــﻞ اﻹﻋــﻼن ﻋــﻦ اﳌﺘﺠــﻪ ﺣــﱴ ﻧﻌــﺮف ﻋــﺪد اﳋــﺎ ت اﳌﻄﻠﻮﺑــﺔ ﰱ ﺳــﻴﺎق اﻟــﱪ ﻣﺞ‪ .‬ﻛﻤــﺎ ﻻ ﳝﻜــﻦ أن ﻧﻐــﲑ ﰱ‬
‫ﺳــﻴﺎق اﻟــﱪ ﻣﺞ اﻟﻌــﺪد اﶈﺠــﻮز ﰱ ﺑﺪاﻳﺘــﻪ‪ .‬ﻳﻌﺮﺿــﻨﺎ ذﻟــﻚ ﳌﺸــﻜﻠﺔ إذا ﻛﻨــﺎ ﻧﺮﻳــﺪ أن ﻧﻘـﺮأ ﺑﻴــﺎ ت ﻣــﻦ ﻣﻠــﻒ ﻟﻨﻀــﻌﻬﺎ ﰱ ﻣﺘﺠــﻪ‪ .‬ﻓــﻨﺤﻦ ﻻ‬
‫ﻧﻌﺮف ﻋﺪد اﻟﺒﻴﺎ ت ﻣﺴﺒﻘﺎ ﻗﺒﻞ ﻓﺘﺢ ﻣﻠﻒ اﻟﺒﻴﺎ ت و ﻗﺪ ﻳﺘﻐﲑ ﻫﺬا اﻟﻌﺪد ﻣــﻦ ﻣﻠــﻒ ﻵﺧــﺮ‪ .‬ﻟﻘــﺪ واﺟﻬﻨــﺎ ﻫــﺬﻩ اﳌﺸــﻜﻠﺔ ﻓﻴﻤــﺎ ﺳــﺒﻖ و‬
‫ﻋﺎﳉﻨﺎﻫﺎ ﺳﻠﻮب ردىء و ﻫﻮ ﺣﺠﺰ ﻣﻜﺎن ﻛﺒﲑ ﻋﻠﻰ أﻣﻞ أن ﻳﻜﻔﻰ‪ .‬و رﻏــﻢ أﻧﻨــﺎ ﰱ ﻫــﺬﻩ اﳊﺎﻟــﺔ ﻧﻀــﻊ داﺋﻤــﺎ اﺧﺘﺒــﺎر ﻳﻮﻗــﻒ اﻟــﱪ ﻣﺞ‬
‫إذا ﻛﺎن اﻟﻌﺪد اﶈﺠﻮز ﻏﲑ ﻛﺎف إﻻ إن ذﻟﻚ ﻏﲑ ﻣﺮﺿﻰ ﲟﺎ ﻓﻴﻪ اﻟﻜﻔﺎﻳﺔ‪ .‬ﺗﺘﻴﺢ اﳌﺆﺷـﺮات ﻋــﻼج أﻓﻀــﻞ ﳍــﺬﻩ اﳌﺸــﻜﻠﺔ ﻋــﻦ ﻃﺮﻳــﻖ ﻓــﺘﺢ‬
‫إﻣﻜﺎﻧﻴــﺔ ﺣﺠــﺰ ﻣﺘﺠــﻪ أﺛﻨــﺎء اﻟــﱪ ﻣﺞ و ﻟــﻴﺲ ﰱ ﺑﺪاﻳﺘــﻪ‪ .‬ﺗﺴــﻤﻰ ﻫــﺬﻩ اﻟﻌﻤﻠﻴــﺔ ﳊﺠــﺰ اﻟــﺪﻳﻨﺎﻣﻴﻜﻰ ﻟﻠــﺬاﻛﺮة ‪dynamic memory‬‬
‫‪ .allocation‬ﻧﺴــﺘﺨﺪم ﻟــﺬﻟﻚ اﻟﺪاﻟــﺔ ‪ malloc‬و اﳌﻌﺮﻓــﺔ ﰱ ﻣﻠــﻒ اﻟـﺮأس اﻟﻘﻴﺎﺳــﻰ ‪) malloc.h‬ﰱ ﺑﻌــﺾ اﻷﻧﻈﻤــﺔ‪ ،‬ﻳﺴــﻤﻰ ﻣﻠــﻒ‬

‫‪75‬‬
‫اﻟ ـﺮأس اﳌﻨ ــﺎﻇﺮ ‪ .(alloc.h‬ﳝﻜ ــﻦ أن ﺗﺴ ــﺘﺪﻋﻰ ﻫ ــﺬﻩ اﻟﺪاﻟ ــﺔ ﰱ أى ﻣﻜ ــﺎن ﰱ اﻟ ــﱪ ﻣﺞ‪ .‬ﻧ ــﺪﺧﻞ ﳍ ــﺬﻩ اﻟﺪاﻟ ــﺔ ﺳ ــﻌﺔ اﻟ ــﺬاﻛﺮة اﳌﻄﻠ ــﻮب‬
‫ﺣﺠﺰﻫــﺎ ﻣﻘﻮﻣــﺔ ﺑﻌــﺪد اﻟﺒﺎﻳــﺖ‪ ،‬أى ﻋــﺪد ﺧــﺎ ت اﻟــﺬاﻛﺮة اﳌﺘﺘﺎﻟﻴــﺔ اﳌﻄﻠــﻮب ﺣﺠﺰﻫــﺎ ﻣﻀــﺮو ﰱ ﺳــﻌﺔ ﻛــﻞ ﺧﺎﻧــﺔ ﻣﻘﻮﻣــﺔ ﺑﻌــﺪد اﻟﺒﺎﻳــﺖ‪.‬‬
‫ﺗﻘﻮم اﻟﺪاﻟﺔ ﲝﺠــﺰ اﻟــﺬاﻛﺮة اﳌﻄﻠﻮﺑــﺔ‪ ،‬ﲟﻌــﲎ أن اﺳــﺘﺨﺪام ﻫــﺬﻩ اﳋــﺎ ت ﺳﻴﻘﺘﺼــﺮ ﻋﻠــﻰ اﻟــﱪ ﻣﺞ اﻟــﺬى ﻗــﺎم ﳊﺠــﺰ‪ ،‬و ﺗﻌﻴــﺪ إﻟﻴﻨــﺎ ﻋﻨـﻮان‬
‫أول ﺧﺎﻧﺔ ﻓﻴﻬﺎ‪ .‬ﻣﺎ ﻫﻮ ﻧﻮع اﳌﺘﻐﲑ اﻟﺬى ﳝﻜﻦ أن ﳛﺘﻔﻆ ﺬا اﻟﻌﻨـﻮان؟ إﻧــﻪ اﳌﺆﺷــﺮ ﻟﺘﺄﻛﻴــﺪ‪ .‬و ﻟــﺬا ﻻ ﳝﻜــﻦ أن ﺗﺴــﺘﺨﺪم ﻫــﺬﻩ اﻟﺪاﻟــﺔ‬
‫إﻻ ﰱ ﻟﻐﺔ ﺗﺘﻌﺎﻣﻞ ﻣﻊ اﳌﺆﺷﺮات‪ .‬ﻳﻮﺿﺢ اﳌﺜﺎل اﻟﺘﺎﱃ أﺳﻠﻮب اﻻﺳﺘﺨﺪام‪ .‬ﻳﻘﺮأ اﻟﱪ ﻣﺞ ﻣﺘﺠﻬﲔ ﻣــﻦ ﻣﻠــﻒ و ﳛﺴــﺐ ﺣﺎﺻــﻞ ﺿــﺮ ﻤﺎ‬
‫اﻟﻘﻴﺎﺳــﻰ‪ .‬ﻳﺒ ــﺪأ اﻟ ــﱪ ﻣﺞ ﺑﻘ ـﺮاءة ﻋــﺪد اﳋ ــﺎ ت ﰱ اﳌﺘﺠ ــﻪ ﻣ ــﻦ اﳌﻠ ــﻒ ﰒ ﳛﺠ ــﺰ ﻣﺘﺠﻬــﲔ ﻟﻄ ــﻮل اﳌﻄﻠ ــﻮب ﰒ ﻳﻘ ــﺮأ ﺑﻴ ــﺎ ت اﳌﻠ ــﻒ ﰱ‬
‫اﳌﺘﺠﻬﲔ ﻗﺒﻞ أن ﳛﺴﺐ ﺣﺎﺻﻞ اﻟﻀﺮب اﻟﻘﻴﺎﺳﻰ‪:‬‬
‫>‪#include <stdio.h‬‬
‫>‪#include <malloc.h‬‬
‫)‪void main(void‬‬
‫;‪{ double *x, *y‬‬
‫;‪double product‬‬
‫;‪int n,j‬‬
‫;‪FILE * filin‬‬
‫;)"‪filin = fopen("input.dat", "r‬‬
‫;)‪fscanf (filin, "%d", &n‬‬
‫;))‪x = (double *) malloc (sizeof(double) * (n+1‬‬
‫;))‪y = (double *) malloc (sizeof(double) * (n+1‬‬
‫)‪for (j=1; j <=n; j++‬‬
‫;) )]‪fscanf (filin,"%lg %lg", &(x[j]), &(y[j‬‬
‫;)‪fclose (filin‬‬
‫;‪product = 0.0‬‬
‫)‪for (j=1; j<= n; j++‬‬
‫;]‪product += x[j] * y[j‬‬
‫;)‪printf("The scalar product of x.y = %lg\n",product‬‬
‫}‬
‫ﰱ ﻫــﺬا اﳌﺜــﺎل ﺑــﺪأ ﺑﻘـﺮاءة أول ﺳــﻄﺮ ﰱ اﻟــﱪ ﻣﺞ و ﻳﻌﻄــﻰ ﻋــﺪد اﻟﺒﻴــﺎ ت اﻟــﱴ ﳛﺘﻮﻳﻬــﺎ‪ .‬ﺑﻌــﺪ أن وﺿــﻌﻨﺎ ﻫــﺬﻩ اﻟﻘﻴﻤــﺔ ﰱ ‪ n‬ﺷــﺮﻋﻨﺎ ﰱ‬
‫ﺣﺠــﺰ ﻣﺘﺠﻬــﲔ ‪ x, y‬ﳛــﻮى ﻛــﻞ ﻣﻨﻬﻤــﺎ ‪ n+1‬ﻋﻨﺼــﺮ ﻣــﻦ ﻧــﻮع ‪) double‬ﺣــﱴ ﳝﻜــﻦ اﻟﺘﻌﺎﻣــﻞ ﻣــﻊ اﻟﻌﻨﺎﺻــﺮ رﻗــﻢ ‪ 1‬إﱃ ‪ .(n‬ﳊﺴــﺎب‬
‫ﻋﺪد اﻟﺒﺎﻳﺖ اﳌﻄﻠﻮب ﺣﺠﺰﻫﺎ اﺳﺘﺨﺪﻣﻨﺎ اﳌﺆﺛﺮ ‪ sizeof‬و ﻫﻮ ﻳﻌﻄﻰ ﻋﺪد اﻟﺒﺎﻳﺖ اﳌﻨﺎﻇﺮ ﻟﻨﻮع اﻟﺒﻴﺎ ت اﻟــﺬى ﻳﻠــﻰ ذﻛــﺮﻩ ﺑــﲔ أﻗـﻮاس‪.‬‬
‫ﰒ ﺑﻌﺪ أن ﻋﺮﻓﻨﺎ ﻋــﺪد اﻟﺒﺎﻳــﺖ اﳌﻄﻠــﻮب ﺣﺠــﺰﻩ ﳋﺎﻧــﺔ واﺣــﺪة ﻣــﻦ اﳌﺘﺠــﻪ ﺿـﺮﺑﻨﺎﻩ ﰱ ﻋــﺪد ﺧــﺎ ت اﳌﺘﺠــﻪ‪ .‬ﺗﻌﻴــﺪ اﻟﺪاﻟــﺔ ‪ malloc‬ﻋﻨــﻮان‬
‫أول ﺧﺎﻧــﺔ ﰱ ﺻــﻮرة ﻣﺆﺷــﺮ ﻳﺸــﲑ إﱃ اﻟﻨــﻮع اﶈﺎﻳــﺪ ‪ .void‬ﻷﺟــﻞ وﺿــﻊ ﻫــﺬا اﻟﻌﻨ ـﻮان ﰱ اﳌﺆﺷــﺮ ‪ x‬أو ‪ y‬ﻳﻨﺒﻐــﻰ إﻋــﺎدة ﻗﻮﻟﺒﺘــﻪ ﲝﻴــﺚ‬
‫ﻳﺼــﺒﺢ ﻣﺆﺷــﺮ ﻳﺸــﲑ إﱃ اﻟﻨــﻮع اﳌﻌــﲎ‪ .‬ﻳــﺘﻢ ذﻟــﻚ ﺑﻮاﺳــﻄﺔ اﻷﻗ ـﻮاس اﳌﻮﺿــﻮﻋﺔ ﻗﺒــﻞ داﻟــﺔ ‪ malloc‬ﻣﺒﺎﺷــﺮة و ﻫــﻰ إﺟﺒﺎرﻳــﺔ و ﰱ ﺣﺎﻟﺘﻨــﺎ‬
‫ﲢﻮى‪.(double *) :‬‬

‫‪double‬ﻟﻠﺘﻌﺎﻣﻞ ﻣﻊ ﻣﺼﻔﻮﻓﺔ ﳚﺐ أن ﻧﺪرك أ ﺎ ﻋﺒﺎرة ﻋﻦ ﻣﺘﺠﻪ ﻛﻞ ﻋﻨﺼﺮ ﻓﻴﻪ ﻋﺒﺎرة ﻋﻦ ﻣﺘﺠﻪ ﺑﺪورﻩ‪ .‬ﻓﻌﻨــﺪﻣﺎ ﻧﻜﺘــﺐ‪:‬‬
‫;]‪A[4][5‬‬

‫‪76‬‬
‫]‪A[0‬‬ ‫]‪A[1‬‬ ‫]‪A[2‬‬ ‫]‪A[3‬‬

‫]‪A[2][3‬‬

‫ﻓﺈﻧﻨــﺎ ﳓﺠــﺰ أرﺑﻌــﺔ ﻣﺘﺠﻬــﺎت ﻣﺘﺘﺎﻟﻴــﺔ ﻛــﻞ ﻣﻨﻬــﺎ ﻳﺘﻜــﻮن ﻣــﻦ ﲬﺴــﺔ ﻋﻨﺎﺻــﺮ‪ .‬أى أﻧﻨــﺎ ﳓﺠــﺰ ‪ 20‬ﺧﺎﻧــﺔ ﻣﺘﺘﺎﻟﻴــﺔ ﻣــﻦ ﻧــﻮع ‪ .double‬ﳝﻜــﻦ‬
‫اﻋﺘﺒﺎر ﻛﻞ ﻣﺘﺠــﻪ ﺻــﻒ ﰱ ﻣﺼــﻔﻮﻓﺔ ﻳـﱰاوح رﻗﻤــﻪ ﻣــﻦ ‪ 0‬إﱃ ‪ 3‬أﻣــﺎ رﻗــﻢ اﻟﻌﻤــﻮد )و ﻫــﻮ رﻗــﻢ اﻟﻌﻨﺼــﺮ داﺧــﻞ اﳌﺘﺠــﻪ( ﻓﻴـﱰاوح ﺑــﲔ ‪ 0‬و‬
‫‪ .4‬ﲝﻴﺚ ﻳﺮﻣﺰ ]‪ A[2][3‬ﻟﻠﻌﻨﺼﺮ ﰱ اﻟﺼﻒ رﻗﻢ ‪ 2‬و اﻟﻌﻤﻮد رﻗﻢ ‪ .3‬ﻳﻮﺟﺪ ﻫﺬا اﻟﻌﻨﺼﺮ ﰱ اﳋﺎﻧــﺔ رﻗــﻢ ‪ 2*5 + 3 +1 = 14‬ﻣــﻦ‬
‫ﺑﲔ اﳋﺎ ت اﻟﻌﺸﺮﻳﻦ‪ .‬ﻟﺘﻮﺿﻴﺢ أﺳﻠﻮب اﳊﺴﺎب ﺗﺬﻛﺮ أن ﲨﻴﻊ ﻋﻨﺎﺻﺮ اﻟﺼﻒ رﻗﻢ ‪ 2‬ﺗــﻰ ﺑﻌــﺪ ﻋﻨﺎﺻــﺮ اﻟﺼــﻔﲔ رﻗــﻢ ‪ 0‬و ‪ 1‬و ﻟــﺬا‬
‫وﺿــﻌﻨﺎ اﳊــﺪ اﻷول ‪ .2*5‬أﻣــﺎ اﻟﻌﻨﺼــﺮ اﳌﻨــﺎﻇﺮ ﻟﻠﻌﻤــﻮد رﻗــﻢ ‪ 3‬ﰱ ﻫــﺬا اﻟﺼــﻒ ﻓﺈﻧــﻪ ﺗــﻰ ﺑﻌــﺪ اﻟﻌﻨﺎﺻــﺮ ‪ 0‬و ‪ 1‬و ‪ 2‬و ﻟــﺬا أﺿــﻔﻨﺎ رﻗــﻢ‬
‫اﻟﻌﻤﻮد زاﺋﺪ ‪ .1‬ﳝﻜﻦ اﻹﺷﺎرة ﻟﻜﻞ ﺻﻒ ﻋﻠﻰ ﺣﺪى ﻛﻤﺘﺠﻪ ﻣﺴﺘﻘﻞ ﻛﺎﻟﺘﺎﱃ‪:‬‬
‫;]‪double A[4][5‬‬
‫;]‪double *p; p = A[3‬‬
‫‪p[2] = 4.0; /* same as A[3][2] = 4.0 */‬‬
‫أﻋﻠﻨﻨﺎ ﻋﻦ ‪ p‬ﻛﻤﺆﺷــﺮ ل ‪ double‬أى أﻧــﻪ ﳝﻜــﻦ اﻋﺘﺒــﺎرﻩ ﻛﻤﺘﺠــﻪ ‪ double‬أﻳﻀــﺎ‪ .‬أول أﻣــﺮ إﺳــﻨﺎد ﻟﻠﻤﺆﺷــﺮ ﳚﻌﻠــﻪ ﻳﺸــﲑ ﻟﻠﺼــﻒ اﻟﺮاﺑــﻊ‬
‫)‪ (3+1‬ﰱ اﳌﺼــﻔﻮﻓﺔ ﻛﻤــﺎ ﻟــﻮ ﻛــﺎن ﻣﺘﺠﻬــﺎ ﻣﻨﻔﺼــﻼ‪ .‬ﻳﺆﻛــﺪ ذﻟــﻚ أﻣــﺮ اﻹﺳــﻨﺎد اﻟﺘــﺎﱃ ﺣﻴــﺚ ﺗﻌﺎﻣﻠﻨــﺎ ﻣــﻊ اﻟﻌﻨﺼــﺮ اﻟﺜﺎﻟــﺚ )‪ (2+1‬ﰱ‬
‫اﻟﺼــﻒ ﻛﻤــﺎ ﻟــﻮ ﻛــﺎن ﻋﻨﺼـﺮا ﰱ ﻣﺘﺠــﻪ‪ .‬ﻛــﺎن ﻫــﺬا ﻫــﻮ أﺳــﻠﻮب اﻟﺘﻌﺎﻣــﻞ ﻣــﻊ ﻣﺼــﻔﻮﻓﺔ ﻷﺳــﻠﻮب اﻟﺘﻘﻠﻴــﺪى و ﺳــﻨﺮى اﻵن ﻛﻴــﻒ ﳝﻜــﻦ‬
‫ﺣﺠﺰ ﻣﺼﻔﻮﻓﺔ ﺑﺸﻜﻞ دﻳﻨﺎﻣﻴﻜﻰ‪ .‬ﺳﻨﺘﻌﺎﻣﻞ ﻣﻊ اﳌﺼﻔﻮﻓﺔ ﻋﻠﻰ أ ﺎ ﻟﻴﺴﺖ إﻻ ﻣﺘﺠﻬــﺎ ﻛــﻞ ﻋﻨﺼــﺮ ﻓﻴــﻪ ﻋﺒــﺎرة ﻋــﻦ ﻣﺘﺠــﻪ ﳝﺜــﻞ ﺻــﻔﺎ ﻣــﻦ‬
‫ﺻــﻔﻮف اﳌﺼــﻔﻮﻓﺔ‪ .‬ﲣﻴــﻞ أﻧﻨــﺎ ﺣﺠــﺰ ﻋــﺪد ﻣــﻦ اﳌﺘﺠﻬــﺎت ﻳﺴــﺎوى ﻋــﺪد ﺻــﻔﻮف اﳌﺼــﻔﻮﻓﺔ )‪ 4‬ﰱ ﻫــﺬا اﳌﺜــﺎل( ﻛــﻞ ﻣــﻨﻬﻢ ﳛــﻮى ‪5‬‬
‫ﺧﺎ ت‪ .‬ﺣﻴﺚ أن ﻛﻞ ﻣﺘﺠﻪ ﳛﺠﺰ دﻳﻨﺎﻣﻴﻜﻴﺎ‪ ،‬ﻓﺈﻧﻨﺎ ﳓﺘﺎج ﻟﺘﺨﺰﻳﻦ ﻋﻨﺎوﻳﻦ اﳌﺘﺠﻬﺎت اﻷرﺑﻌﺔ ﰱ ﻣﻜﺎن ﻣﺎ‪ ،‬ﺣﱴ ﳝﻜﻦ اﻟﺮﺟــﻮع إﻟــﻴﻬﻢ‪.‬‬
‫ﻫﺬا اﳌﻜﺎن ﳚﺐ أن ﻳﻜﻮن ﻣﺘﺠﻬﺎ ﺑــﺪورﻩ )اﳌﺘﺠــﻪ اﻟﺮأﺳــﻰ ﰱ اﻟﺸــﻜﻞ اﻟﺘــﺎﱃ( ﺣــﱴ ﳝﻜــﻦ أن اﻟﺮﺟــﻮع ﺑﺴــﻬﻮﻟﺔ ﻷى ﺻــﻒ ﲟﺠــﺮد ﲢﺪﻳــﺪ‬
‫رﻗﻤﻪ‪ .‬ﻛﻞ ﻋﻨﺼﺮ ﰱ ﻫﺬا اﳌﺘﺠﻪ ﻟﻴﺲ إﻻ ﻣﺆﺷﺮ ل ‪ double‬و ﳛﻮى ﻋﻨﻮان ﺑﺪاﻳﺔ ﻛﻞ ﺳﻄﺮ‪ .‬ﻣﺘﺠﻪ اﳌﺆﺷـﺮات ﻧﻔﺴــﻪ ﻟــﻴﺲ ﻣﻮﺟــﻮدا ﰱ‬
‫ﺑﺪاﻳﺔ اﻟــﱪ ﻣﺞ و ﳚــﺐ ﺣﺠــﺰﻩ أﻳﻀــﺎ ﺑﺼــﻮرة دﻳﻨﺎﻣﻴﻜﻴــﺔ‪ .‬ﻟــﺬﻟﻚ ﳓﺘــﺎج ﳋﺎﻧــﺔ ذاﻛــﺮة ﲢــﻮى ﻋﻨـﻮان ﺑﺪاﻳــﺔ ﻣﺘﺠــﻪ اﳌﺆﺷـﺮات‪ ،‬اﻟــﺬاﻛﺮة اﳌﻌﻨﻴــﺔ‬
‫ﲢﻮى ﻋﻨـﻮان ﻣﺆﺷـﺮات‪ ،‬أى أ ــﺎ ﻣﺆﺷــﺮ ﳌﺆﺷــﺮ ﻣــﻦ ﻧــﻮع ‪ .double‬ﻟﻄﺒــﻊ ﳚــﺐ أن ﳓﺠــﺰ ﻣﺘﺠــﻪ اﳌﺆﺷـﺮات ﻗﺒــﻞ ﺣﺠــﺰ اﳌﺘﺠﻬــﺎت اﻟــﱴ‬
‫ﲢﻮى ﺻﻔﻮف اﳌﺼﻔﻮﻓﺔ‪ .‬و ﺑﺬﻟﻚ ﻧﺼﻞ ﻟﻠﱪ ﻣﺞ اﻟﺘﺎﱃ‪:‬‬
‫;‪double ** B‬‬
‫;)‪B = (double **) malloc (sizeof (double *) * 4‬‬
‫)‪for (j=0; j<4; j++‬‬
‫;)‪B[j] = (double ) malloc(sizeof(double) * 5‬‬
‫…‬
‫;‪B[1][1] = 2.0‬‬
‫اﳌﺼﻔﻮﻓﺔ ‪ B‬ﻫﻨﺎ ﻫﻰ ﻧﻔﺴﻬﺎ اﳌﺼﻔﻮﻓﺔ ‪ A‬اﻟﻮاردة أﻋﻼﻩ ﻣﻦ ﺣﻴﺚ ﻋﺪد اﻟﺼــﻔﻮف و اﻷﻋﻤــﺪة و ﻟﻜﻨﻬــﺎ ﲣﺘﻠــﻒ ﻋﻨﻬــﺎ ﰱ ﻛﻮ ــﺎ ﳏﺠــﻮزة‬
‫ﺑﺼــﻮرة دﻳﻨﺎﻣﻴﻜﻴــﺔ‪ .‬اﻟﺴــﻄﺮ اﻷول ﰱ اﻟــﱪ ﻣﺞ اﻟﺴــﺎﺑﻖ ﻳﻌﻠــﻦ ﻋــﻦ ‪ B‬ﻋﻠــﻰ أﻧــﻪ ﻣﺆﺷــﺮ ﳌﺆﺷــﺮ ﻟﻠﻨــﻮع ‪ ،double‬أو ﺑﻠﻐــﺔ أﺧــﺮى ﻗــﺪ ﺗﻜــﻮن‬
‫أﻛﺜــﺮ وﺿــﻮﺣﺎ ﻋﻠــﻰ أﻧــﻪ ﻣﺘﺠــﻪ ﻣــﻦ اﳌﺆﺷـﺮات ﻟﻠﻨــﻮع ‪) ،double‬و ﻫــﻮ اﳌﺘﺠــﻪ اﻟﺮأﺳــﻰ ﰱ اﻟﺸــﻜﻞ اﻟﺘــﺎﱃ(‪ .‬ﺑﻴﻨﻤــﺎ ﱂ ﻳﻘــﻢ اﻟﺴــﻄﺮ اﻷول‬
‫ﺳﻮى ﲝﺠﺰ ﺧﺎﻧﺔ ‪ ،B‬ﻓﺈن اﻟﺴﻄﺮ اﻟﺜــﺎﱏ ﻳﻘــﻮم ﺑﻌﻤﻠﻴــﺔ ﺣﺠــﺰ اﳌﺘﺠــﻪ اﻟﺮأﺳــﻰ ﻛﻤﻠــﻪ و ﻫــﻮ ﻣﻜـﻮن ﻣــﻦ أرﺑﻌــﺔ ﺧــﺎ ت ذاﻛــﺮة ﲢــﻮى ﻛــﻞ‬
‫ﻣﻨﻬــﺎ ﻣﺆﺷ ـﺮا ﻳﺸــﲑ إﱃ ﻣﺘﻐــﲑ ﻣــﻦ ﻧــﻮع ‪ .double‬اﳌﺘﻐــﲑ ‪ B‬ﻳﺸــﲑ إﱃ ﻫــﺬﻩ اﳋــﺎ ت اﻷرﺑﻌــﺔ‪ .‬ﰱ اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ اﻟﺘﺎﻟﻴــﺔ ﳓﺠــﺰ ﻋــﺪد‬

‫‪77‬‬
‫أرﺑﻌﺔ ﻣﺘﺠﻬﺎت ﻛــﻞ ﻣﻨﻬــﺎ ﻣﻜــﻮن ﻣــﻦ ﲬﺴــﺔ ﺧــﺎ ت ﻣــﻦ ﻧــﻮع ‪ double‬و ﳒﻌــﻞ ﻛــﻞ ﻣﺆﺷــﺮ ﻣــﻦ اﳌﺆﺷـﺮات اﻷرﺑﻌــﺔ اﶈﺠــﻮزة آﻧﻔــﺎ ﻳﺸـﲑ‬
‫إﱃ واﺣﺪ ﻣﻨﻬﻢ‪.‬‬

‫‪B‬‬

‫اﳌﺜﺎل اﻟﺘــﺎﱃ ﻳﻜﻤــﻞ اﳌﺜــﺎل اﻟﺴــﺎﺑﻖ‪ ،‬ﺣﻴــﺚ ﻧﺮﻏــﺐ ﰱ ﺿــﺮب اﳌﺼــﻔﻮﻓﺔ ‪ B‬اﻟــﱴ ﺣﺠــﺰت دﻳﻨﺎﻣﻴﻜﻴــﺎ أﻋــﻼﻩ ﰱ اﳌﺘﺠــﻪ ‪ x‬ووﺿــﻊ اﻟﻨــﺎﺗﺞ ﰱ‬
‫اﳌﺘﺠﻪ ‪ y‬و ﻛﻼﳘﺎ ﳏﺠﻮز دﻳﻨﺎﻣﻴﻜﻴﺎ أﻳﻀﺎ‪ .‬ﻳﺴﺘﺨﺪم اﻟﱪ ﻣﺞ اﳌﺆﺷﺮات ﺑﻜﻔﺎءة ﲝﻴﺚ ﻳﺘﻢ ﲣﻔﻴﺾ زﻣﻦ اﳊﺴﺎب ﺑﺼﻮرة ﻛﺒﲑة‪.‬‬
‫)(‪void main‬‬
‫;‪{ double ** B; double *x, double *y‬‬
‫;‪double *pmat, *px, sum‬‬
‫;‪int row,col, i,j‬‬
‫;)‪printf ("Enter rows and columns:"); scanf("%d %d",&row,&col‬‬
‫;)‪B = (double **) malloc (sizeof (double *) * row‬‬
‫)‪for (j=0; j<row; j++‬‬
‫;)‪B[j] = (double ) malloc(sizeof(double) * col‬‬
‫;)‪x = (double *) malloc (sizeof (double) * col‬‬
‫;)‪y = (double *) malloc (sizeof (double) * row‬‬
‫‪/* read values of B, x */‬‬
‫)‪for (i=0;i<row;i++‬‬
‫{‬
‫;‪pmat = B[i];px=x; sum = 0‬‬
‫)‪for (j=0;j<col;j++‬‬
‫;)‪{ sum += (*pmat)*(*px‬‬
‫;‪pmat++; px++‬‬
‫}‬
‫;‪y[i] = sum‬‬
‫}‬

‫‪78‬‬
‫‪.4‬ج‪ .‬اﻟﱪاﻣﺞ اﳉﺰﺋﻴﺔ ‪Subprograms‬‬

‫‪.4‬ج‪ .1.‬اﻹﺟﺮاء و اﻟﺪاﻟﺔ ‪procedure and function‬‬


‫ﰱ ﲨﻴــﻊ ﻟﻐــﺎت اﻟﱪﳎــﺔ ﳝﻜــﻦ أن ﻧﺴــﺘﺨﺪم ﺑـﺮاﻣﺞ ﺟﺰﺋﻴــﺔ ﺗﺴــﺘﺪﻋﻰ ﻣــﻦ اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ ﻟﺘﻨﺠــﺰ ﻣﻬﻤــﺔ ﳏــﺪدة‪ .‬ﻓــﺈذا اﺣﺘﺠﻨــﺎ‬
‫ﻹﳒﺎز ﻧﻔﺲ اﳌﻬﻤﺔ ﰱ أﻛﺜﺮ ﻣﻦ ﻣﻮﺿﻊ ﻣﻦ اﻟﱪ ﻣﺞ‪ ،‬ﻳﻜﻔﻰ أن ﻧﺴﺘﺪﻋﻰ اﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ اﳋــﺎص ــﺎ ﰱ ﻛــﻞ ﻣﻮﺿــﻊ‪ ،‬ﺑــﺪﻻ ﻣــﻦ إﻋــﺎدة‬
‫ﻛﺘﺎﺑﺔ ﺗﻔﺎﺻﻴﻞ اﻟﺴﻄﻮر اﳌﺴــﺘﺨﺪﻣﺔ ﳊﺴــﺎب اﳌﻄﻠــﻮب ﰱ ﻛــﻞ ﻣــﺮة‪ .‬أوﺿــﺢ ﻣﺜــﺎل ﻋﻠــﻰ ذﻟــﻚ اﻟــﺪوال اﻟﺮ ﺿــﻴﺔ ﻣﺜــﻞ ‪ sin‬و اﻟــﱴ ﲢﺴــﺐ‬
‫ﺳــﺘﺨﺪام ﻣﻔﻜــﻮك ‪ .Taylor‬ﻗــﺪ ﳓﺘــﺎج ﳊﺴــﺎب )‪ sin(x‬ﰱ ﻣﻜــﺎن ﻣــﺎ ﻣــﻦ اﻟــﱪ ﻣﺞ‪ ،‬ﰒ ﺣﺴــﺎب )‪ sin(2*x‬ﰱ ﻣﻜــﺎن آﺧــﺮ ﰒ‬
‫ﺣﺴ ــﺎب )‪ sin(y‬ﰱ ﻣﻜ ــﺎن ﻟ ــﺚ‪ ،‬و ﰱ ﻛ ــﻞ ﻫ ــﺬﻩ اﳊ ــﺎﻻت ﺗﻜ ــﻮن ﺧﻄـ ـﻮات اﳊﺴ ــﺎب واﺣ ــﺪة و إن اﺧﺘﻠﻔ ــﺖ ﻗ ــﻴﻢ اﳌ ــﺪﺧﻼت و‬
‫اﳌﺨﺮﺟﺎت‪ .‬ﻳﻜﻔﻰ إذن أن ﻧﻌﺮف داﻟــﺔ ‪ sin‬ﻣــﺮة واﺣــﺪة )ﻳــﺘﻢ ذﻟــﻚ ﰱ ﻣﻜﺘﺒــﺔ اﻟـﱪاﻣﺞ اﳉﺰﺋﻴــﺔ اﳌﺼــﺎﺣﺒﺔ ﻟﻠﻤــﱰﺟﻢ ﰱ أﻳــﺔ ﻟﻐــﺔ( و ﻳﻜﻔــﻰ‬
‫اﺳﺘﺪﻋﺎء ﻫﺬا اﻟﱪ ﻣﺞ اﳉﺰﺋﻰ ﰱ اﳌﻜﺎن اﳌﻄﻠﻮب ﲟﺠــﺮد ذﻛــﺮ اﲰــﻪ ﻣــﻊ إﻋﻄــﺎء اﳌــﺪﺧﻼت اﳌﻨﺎﺳــﺒﺔ ﰱ ﻛــﻞ ﻣــﺮة‪ .‬ﳝﻜــﻦ أﻳﻀــﺎ أن ﻳﻜﺘــﺐ‬
‫اﳌﺴﺘﺨﺪم ﺑﺮاﻣﺞ ﺟﺰﺋﻴﺔ إﺿﺎﻓﻴﺔ ﻳﺜﺮى ﺎ ﻣﻜﺘﺒﺘﻪ و ﻫﺬا ﻣﺎ ﻧﺮﻳﺪ ﺗﻌﻠﻤﻪ ﰱ ﻫﺬا اﻟﺒﺎب‪.‬‬

‫ﰱ داﺧــﻞ أى ﺑــﺮ ﻣﺞ ﺟﺰﺋــﻰ ﳝﻜــﻦ أن ﳓﺘــﺎج ﻻﺳــﺘﺪﻋﺎء ﺑــﺮ ﻣﺞ ﺟﺰﺋــﻰ آﺧــﺮ اﻟــﺬى ﻳﺴــﺘﺪﻋﻰ ﺑــﺪورﻩ ﺑــﺮ ﻣﺞ ﺟﺰﺋــﻰ ﻟــﺚ و‬
‫ﻫﻜﺬا ﻷﻳــﺔ ﻋــﺪد ﻣــﻦ اﳌﺴــﺘﻮ ت‪ .‬ﰱ ﲨﻴــﻊ اﳊــﺎﻻت ﻓــﺈن آﻟﻴــﺔ اﻻﺳــﺘﺪﻋﺎء واﺣــﺪة‪ .‬ﻋﻨــﺪﻣﺎ ﳓﺘــﺎج ﻻﺳــﺘﺪﻋﺎء ﺑﺮ ﳎــﺎ ﺟﺰﺋﻴــﺎ ﰱ ﻣﻜــﺎن ﻣــﺎ‬
‫ﻣــﻦ ﺑــﺮ ﻣﺞ داع‪ ،‬ﻓــﺈن اﻟــﱪ ﻣﺞ اﻟــﺪاﻋﻰ ﻳﻜﻔﻴــﻪ ذﻛــﺮ اﺳــﻢ اﻟــﱪ ﻣﺞ اﳌﺴــﺘﺪﻋﻰ ﻣﺸــﻔﻮﻋﺎ ﺑﻘﺎﺋﻤــﺔ اﳌــﺪﺧﻼت ﺑــﲔ أﻗ ـﻮاس‪ .‬ﺣﻴﻨﺌــﺬ ﻳﻨﺘﻘــﻞ‬
‫اﻟﺘﻨﻔﻴﺬ ﻟﻠﱪ ﻣﺞ اﳉﺰﺋﻰ ﺣﱴ ﻳﻨﺘﻬﻰ ﻣﻦ ﺣﺴﺎ ﺗﻪ ﰒ ﻧﻌﻮد ﻟﻠﱪ ﻣﺞ اﻟﺪاﻋﻰ ﻋﻨﺪ ﻧﻔﺲ ﻧﻘﻄﺔ اﻻﺳﺘﺪﻋﺎء ﻟﻨﻌﺎود اﻟﺘﻨﻔﻴﺬ‪.‬‬
‫ﻫﻨﺎك ﻧﻮﻋﺎن ﻣــﻦ اﻟـﱪاﻣﺞ اﳉﺰﺋﻴــﺔ ﰱ أى ﻟﻐــﺔ ﻣــﻦ ﻟﻐــﺎت اﻟﱪﳎــﺔ‪ ،‬و ﳘــﺎ اﻹﺟـﺮاء ‪ procedure‬و اﻟﺪاﻟــﺔ ‪ .function‬اﻟﻔــﺎرق‬
‫اﻟﻮﺣﻴﺪ ﺑﻴﻨﻬﻤﺎ ﻫﻮ أن اﻟﺪاﻟﺔ ﳍﺎ ﻗﻴﻤﺔ )ﺗﺴﻤﻰ اﻟﻘﻴﻤﺔ اﻟﻌﺎﺋﺪة ‪ (return value‬ﺗﻌﻮد ﺎ ﻟﻠﱪ ﻣﺞ اﻟﺪاﻋﻰ و ﳝﻜــﻦ اﺳــﺘﺨﺪاﻣﻬﺎ ﻣﺒﺎﺷــﺮة‬
‫ﺑﺪاﺧﻞ أى ﺗﻌﺒﲑ‪ .‬ﻳﻘــﻮم اﻹﺟـﺮاء ﻋﻠــﻰ اﻟﻌﻜــﺲ ﻣــﻦ ذﻟــﻚ داء ﻣﻬﻤﺘــﻪ ﻓﻘــﻂ ﲝﻴــﺚ ﻳﺴــﺘﺨﺪم ﻛــﺄﻣﺮ ﻣﺴــﺘﻘﻞ و ﻻ ﻳﻌﻄــﻰ ﻗﻴﻤــﺔ ﻋﺎﺋــﺪة و‬
‫ﺑﺬﻟﻚ ﻻ ﳝﻜﻦ أن ﻳﻈﻬﺮ ﺑــﺪاﺧﻞ أى ﺗﻌﺒــﲑ‪ .‬ﻓﺎﻟﺪاﻟــﺔ ﳝﻜــﻦ أن ﺗﻜــﻮن ﻣــﺜﻼ ﺣﺴــﺎب اﳉــﺬر اﻟﱰﺑﻴﻌــﻰ ﻟﻌــﺪد ﻣــﺎ ‪ sqrt‬أو أﻳــﺔ داﻟــﺔ ﻣﺜﻠﺜﻴــﺔ‪،‬‬
‫ﺑﻴﻨﻤﺎ اﻹﺟﺮاء ﳝﻜﻦ أن ﻳﻜﻮن ﻣﺜﻼ رﺳﻢ ﺧﻂ ﻋﻠﻰ اﻟﺸﺎﺷﺔ ﻛﻤﺎ ﻳﺒﲔ اﳌﺜﺎل اﻟﺘﺎﱃ‪:‬‬
‫>‪#include <stdio.h‬‬
‫>‪#include <math.h‬‬
‫;)(‪double get_diameter‬‬
‫;)‪void draw_line(double x1, double y1, double x2, double y2‬‬

‫)‪void main(void‬‬
‫{‬
‫;‪double x, y, r, theta‬‬
‫;) ‪printf("Enter theta:‬‬
‫;)‪scanf("%lg", &theta‬‬
‫;)(‪r = 0.5*get_diameter‬‬
‫;)‪x = r*cos(theta‬‬
‫;)‪y = r*sin(theta‬‬
‫;)‪draw_line(0,0,x,y‬‬
‫}‬

‫‪79‬‬
‫ﰱ ﺟﺴــﻢ اﻟﺪاﻟــﺔ اﻟﺮﺋﻴﺴــﻴﺔ ‪ main‬ﻧﺒــﺪأ ﳊﺼــﻮل ﻋﻠــﻰ اﻹﺣــﺪاﺛﻴﺎت اﻟﻘﻄﺒﻴــﺔ ﻟﻨﻘﻄــﺔ ‪ r, theta‬ﰒ ﳓﻮﳍــﺎ ﻹﺣــﺪاﺛﻴﺎت ﻛﺎرﺗﻴﺰﻳــﺔ ‪ x, y‬ﰒ‬
‫ﻧﺮﺳــﻢ اﳋــﻂ اﻟﻮاﺻــﻞ ﻣــﻦ ﻧﻘﻄــﺔ اﻷﺻــﻞ إﱃ ﻫــﺬﻩ اﻟﻨﻘﻄــﺔ‪ .‬ﻟﻠﺤﺼــﻮل ﻋﻠــﻰ ‪ r‬ﰎ اﺳــﺘﺪﻋﺎء اﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ )(‪ get_diameter‬و اﻟــﺬى‬
‫ﻳﺘﻮﱃ ﻣﻬﻤﺔ اﳊﺼﻮل ﻋﻠﻰ ﻗﻴﻤﺔ ﻗﻄﺮ ﺳﻮاء ﺑﻘﺮاءة اﻟﻘﻴﻤﺔ ﻣــﻦ ﻣﻠــﻒ أو ﺑﺴـﺆال اﳌﺴــﺘﺨﺪم ﻋﻠــﻰ اﻟﺸﺎﺷــﺔ أو ﻛﻨﺘﻴﺠــﺔ ﳊﺴــﺒﺔ ﻣــﺎ ﱂ ﻧﻮﺿــﺢ‬
‫ذﻟﻚ ﺑﻌﺪ و ﻻ ﻳﻬﻢ اﻟﱪ ﻣﺞ اﻟﺮﺋﻴﺴﻰ أن ﻳﻌﺮف ﻛﻴﻒ ﰎ اﳊﺴﺎب‪ .‬ﻏﺎﻳﺔ ﻣﺎ ﻳﻬــﻢ اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ ﻫــﻮ ﻣﻌﺮﻓــﺔ ﻧﺼــﻒ اﻟﻘﻄــﺮ و ﰎ ذﻟــﻚ‬
‫ﻋــﻦ ﻃﺮﻳــﻖ اﺳــﺘﺪﻋﺎء اﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ و اﺳــﺘﺨﺪام ﻗﻴﻤــﺔ اﻟﻨــﺎﺗﺞ ﳊﺴــﺎب ﻧﺼــﻒ اﻟﻘﻄــﺮ ﺑﻀــﺮب اﻟﻨــﺎﺗﺞ ﰱ اﻟﻨﺼــﻒ‪ .‬ﻻﺣــﻆ أن اﻟﺪاﻟــﺔ‬
‫)(‪ get_diameter‬ﳍﺎ ﻗﻴﻤﺔ اﺳﺘﺨﺪﻣﺖ ﺑﺪاﺧﻞ ﺗﻌﺒﲑ‪ ،‬ﲤﺎﻣﺎ ﻛﻤﺎ ﺣــﺪث ﺑﻌــﺪ ذﻟــﻚ ﻣــﻊ اﻟــﺪوال اﳌﺜﻠﺜﻴــﺔ )‪sin(theta), cos(theta‬‬
‫ﰱ اﻟﺴﻄﻮر اﻟﺘﺎﻟﻴﺔ‪ .‬أﻣﺎ اﻟﱪ ﻣﺞ اﳉﺰﺋﻰ )(‪ draw_line‬ﻓﻬﻮ ﻣﻦ ﻧﻮع اﻹﺟﺮاء و ﻳﻘﻮم ﺑﺮﺳــﻢ ﺧــﻂ ﻋﻠــﻰ اﻟﺸﺎﺷـﺔ و ﻟﻴﺴــﺖ ﻟــﻪ أﻳــﺔ ﻗﻴﻤــﺔ‬
‫ﻋﺎﺋﺪة ‪ return value‬ﳝﻜﻦ أن ﺗﺴﺘﺨﺪم ﰱ أﻳﺔ ﺗﻌﺒﲑ ر ﺿﻰ‪.‬‬

‫ﰱ ﻟﻐﺔ ال‪ C‬اﻋﺘﱪ اﻹﺟﺮاء ﺣﺎﻟﺔ ﺧﺎﺻﺔ ﻣﻦ اﻟﺪاﻟﺔ ﺣﻴﺚ أﻧﻪ داﻟﺔ ﻟﻴﺴﺖ ﳍــﺎ ﻗﻴﻤــﺔ ﻋﺎﺋــﺪة أو ﲟﻌــﲎ آﺧــﺮ ﻗﻴﻤﺘﻬــﺎ اﻟﻌﺎﺋــﺪة ﻫــﻰ‬
‫ﻻ ﺷﺊ‪ ،‬اﳌﻌﱪ ﻋﻨﻬﺎ ﰱ ﻟﻐﺔ ال‪ C‬ﻟﻜﻠﻤﺔ ‪ .void‬ﻇﻬﺮ ذﻟﻚ اﻟﻔﺎرق ﰱ اﻟﺴﻄﻮر اﻟﱴ ﺗﺴﺒﻖ اﻟﺪاﻟﺔ اﻟﺮﺋﻴﺴﻴﺔ و اﻟﱴ ﻗﻤﻨــﺎ ﻓﻴﻬــﺎ ﻹﻋــﻼن‬
‫ﻋﻦ اﻟﱪاﻣﺞ اﳉﺰﺋﻴﺔ اﻟﱴ ﺳﲑد ذﻛﺮﻫﺎ ﰱ اﻟﱪ ﻣﺞ اﻟﺮﺋﻴﺴﻰ‪ .‬ﺳﻨﻮﺿﺢ ﰱ اﻟﻔﻘﺮة اﻟﺘﺎﻟﻴﺔ ﻟﺘﻔﺼﻴﻞ أﺳﻠﻮب اﻹﻋﻼن ﻋﻦ اﻟـﱪاﻣﺞ اﳉﺰﺋﻴــﺔ‪ ،‬و‬
‫ﻟﻜــﻦ ﻣــﺎ ﻳﻌﻨﻴﻨــﺎ ﻫﻨــﺎ ﻫــﻮ ﻓﻘــﻂ اﻟﺘﻌــﺮف ﻋﻠــﻰ اﻟﻔــﺎرق ﺑــﲔ اﻟﻨــﻮﻋﲔ اﻟﺮﺋﻴﺴــﻴﲔ ﻣــﻦ اﻟ ـﱪاﻣﺞ اﳉﺰﺋﻴــﺔ أﻻ و ﳘــﺎ اﻟﺪاﻟــﺔ و اﻹﺟ ـﺮاء‪ .‬ﻓﺎﻟﺪاﻟــﺔ‬
‫)(‪ get_diameter‬ﳍﺎ ﻗﻴﻤﺔ ﻋﺎﺋﺪة ﻣﻦ ﻧﻮع ‪ double‬ﻛﻤﺎ ﻳﻮﺿﺢ ﺳﻄﺮ اﻹﻋﻼن اﳋــﺎص ــﺎ أﻣــﺎ اﻹﺟـﺮاء )(‪ draw_line‬ﻓﻠﻴﺴــﺖ‬
‫ﻟﻪ ﻗﻴﻤﺔ ﻋﺎﺋﺪة‪ ،‬أو ﻟﺘﺤﺪﻳﺪ ﻓﺈن ﻗﻴﻤﺘﻪ اﻟﻌﺎﺋﺪة ﻻ ﺷﺊ ‪ void‬ﻛﻤﺎ ﻳﻮﺿﺢ أﻳﻀﺎ ﺳﻄﺮ اﻹﻋــﻼن اﳋــﺎص ﺑــﻪ‪ .‬ﳍــﺬا اﻟﺴــﺒﺐ ﻟــﻦ ﻧﺘﺤـﺪث‬
‫ﻓﻴﻤﺎ ﻳﻠﻰ ﻋﻦ اﻹﺟﺮاء و ﻟﻜﻦ ﺳﻴﻨﺼﺐ ﺣﺪﻳﺜﻨﺎ ﻋﻠﻰ اﻟﺪوال ﺣﻴﺚ أ ﺎ أﻛﺜﺮ ﻋﻤﻮﻣﻴﺔ‪.‬‬

‫اﻟﻘﻴﻤﺔ اﻟﻌﺎﺋﺪة ﻟﻠﺪاﻟﺔ ﳝﻜﻦ أن ﺗﻜﻮن ﻣﻦ أﻳﺔ ﻧﻮع ﻣﻦ أﻧﻮاع اﻟﺒﻴﺎ ت اﻟﺒﺴــﻴﻄﺔ‪ .‬ﻏــﲑ ﻣﺴــﻤﻮح ﻟﻠﺪاﻟــﺔ أن ﺗﻌﻴــﺪ أﻛﺜــﺮ ﻣــﻦ ﻗﻴﻤــﺔ‬
‫ﺑﺴﻴﻄﺔ واﺣﺪة و ﻻ أن ﺗﻌﻴﺪ ﻫﻴﻜﻞ ﺑﻴــﺎ ت ﻣﺜــﻞ اﳌﺘﺠــﻪ أو أى ﻣــﻦ اﳍﻴﺎﻛــﻞ اﻟــﱴ ﺳﻨﺪرﺳــﻬﺎ ﰱ اﻟﻔﺼــﻮل اﻟﺘﺎﻟﻴــﺔ‪ .‬ﳝﻜــﻦ اﻻﻟﺘﻔــﺎف ﺣــﻮل‬
‫ﻫﺬا اﻟﻘﻴﺪ ﺑﺼﻮرة ﻏﲑ ﻣﺒﺎﺷﺮة ﻋﻦ ﻃﺮﻳﻖ اﺳﺘﺨﺪام اﳌﺆﺷﺮات ﻛﻤﺎ ﺳﻨﺮى ﰱ ﺳﻴﺎق ﻫﺬا اﻟﻔﺼﻞ‪.‬‬

‫‪.4‬ج‪ .2.‬إﻋﻼن وﺗﻌﺮﻳﻒ اﻟﺪوال ‪Function declaration and definition‬‬


‫ﻷﺟــﻞ اﺳــﺘﺨﺪام أﻳــﺔ داﻟــﺔ ﰱ اﻟــﱪ ﻣﺞ ﳚــﺐ أن ﻧﻘــﻮم ﺑﻌﻤﻠﻴﺘــﲔ و ﳘــﺎ اﻹﻋــﻼن ﻋـﻦ اﻟﺪاﻟــﺔ ‪ function declaration‬ﰒ‬
‫اﻟﺘﻌﺮﻳــﻒ ــﺎ ‪ .function definition‬ﰱ ﻣﺮﺣﻠــﺔ اﻹﻋــﻼن ﻋــﻦ اﻟﺪاﻟــﺔ ﻧﻘــﻮم ﰱ اﻟﻮاﻗــﻊ ﺧﻄــﺎر اﳌــﱰﺟﻢ ‪ compiler‬ﻧــﻪ ﺳــﲑد ﻓﻴﻤــﺎ‬
‫ﺑﻌﺪ ذﻛﺮ اﺳﻢ ﻫﺬﻩ اﻟﺪاﻟﺔ و ﻫﻰ ﺧﺬ ﻗﺎﺋﻤﺔ ﻣﻦ اﳌﻌﻄﻴﺎت ﳚﺐ ﲢﺪﻳﺪ ﻧﻮﻋﻬﺎ و ﺗﻌﻄﻰ ﺗﺞ ﳚﺐ أﻳﻀﺎ ﲢﺪﻳــﺪ ﻧﻮﻋــﻪ‪ .‬ﻻ ﻳﻬــﻢ اﳌـﱰﺟﻢ‬
‫ﺣﻴﻨﻤﺎ ﻳﻘﻮم ﺑﱰﲨﺔ اﻟﱪ ﻣﺞ اﻟﺮﺋﻴﺴﻰ أن ﻳﻌﺮف أﻛﺜﺮ ﻣﻦ ذﻟﻚ‪ .‬أﻣﺎ اﻟﺘﻌﺮﻳــﻒ ﻟﺪاﻟــﺔ ﻓﻬــﻮ ﻛﺘﺎﺑــﺔ اﻟﺴــﻄﻮر اﻟــﱴ ﺗﻮﺿــﺢ ﻛﻴــﻒ ﺗﻘــﻮم اﻟﺪاﻟــﺔ‬
‫داء اﳌﻬﻤﺔ اﳌﻨﻮﻃﺔ ــﺎ‪ .‬ﻫــﺬﻩ اﻟﺴــﻄﻮر ﺗﻜﺘــﺐ ﺑﻠﻐــﺔ ‪ C‬ﺑﺼــﻮرة ﻋﺎدﻳــﺔ و ﻟﻜــﻦ ﳝﻜــﻦ أن ﺗﻈﻬــﺮ ﰱ ﻣﻠــﻒ آﺧــﺮ أو ﰱ ﻧﻔــﺲ اﳌﻠــﻒ ﺳـﻮاء‬
‫ﻗﺒﻞ أو ﺑﻌﺪ اﻟﺪاﻟﺔ اﻟﺮﺋﻴﺴﻴﺔ‪ .‬ﻻ ﻳﻬﻢ ﻣﻄﻠﻘﺎ أﻳﻦ ﻳﻈﻬﺮ ﺗﻌﺮﻳﻒ اﻟﺪاﻟﺔ )ﻃﺎﳌﺎ ﱂ ﻳﺘﻢ ﺑﺪاﺧﻞ داﻟــﺔ أﺧــﺮى( و ﻟﻜــﻦ ﳚــﺐ أن ﻳﺴــﺒﻖ اﻹﻋــﻼن‬
‫ﻋﻦ اﻟﺪاﻟﺔ أى اﺳﺘﺨﺪام ﳍﺎ ﰱ اﻟﱪ ﻣﺞ‪ .‬ﺑﻌﺪ ﺗﺮﲨﺔ اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ و ﺗﺮﲨــﺔ اﻟــﺪوال اﳌﺼــﺎﺣﺒﺔ ﳓﺼــﻞ ﻋﻠــﻰ ﺑــﺮ ﻣﺞ أو أﻛﺜــﺮ ﻣــﻦ ﻧــﻮع‬
‫‪ object‬ﰒ ﻳــﺘﻢ وﺻــﻞ اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ ﻟ ـﱪاﻣﺞ اﳉﺰﺋﻴــﺔ اﻟــﱴ ﻳﺴــﺘﺨﺪﻣﻬﺎ ﺑﻮاﺳــﻄﺔ اﳌﻮﺻــﻞ ‪ linker‬ﻛﻤــﺎ ذﻛــﺮ آﻧﻔــﺎ ﻟﻨﺤﺼــﻞ ﻋﻠــﻰ‬
‫ﺑﺮ ﻣﺞ ﻗﺎﺑﻞ ﻟﻠﺘﻨﻔﻴﺬ ‪.executable‬‬

‫‪80‬‬
‫ﰱ اﳌﺜﺎل اﻟﺴﺎﺑﻖ ﳝﻜﻦ ﻛﺘﺎﺑﺔ إﻋﻼن اﻟﺪاﻟﺔ و ﺗﻌﺮﻳﻔﻬﺎ ﻋﻠﻰ اﻟﻨﺤﻮ اﻟﺘﺎﱃ‪:‬‬
‫;)(‪double get_diameter‬‬
‫)‪void main (void‬‬
‫{‬
‫……… ;)(‪……..; r = 0.5*get_diameter‬‬
‫}‬
‫)(‪double get_diameter‬‬
‫{‬
‫;‪double D‬‬
‫;)‪printf("Enter diameter‬‬
‫;)‪scanf("%lg",&D‬‬
‫;)‪return(D‬‬
‫}‬
‫ﻻﺣﻆ أن إﻋﻼن اﻟﺪاﻟﺔ ‪ get_diameter‬ورد ﻗﺒﻞ اﻟﺪاﻟﺔ ‪ main‬اﻟﱴ ﺗﺴﺘﺪﻋﻰ ﻓﻴﻬﺎ‪ .‬أﻣﺎ ﺗﻌﺮﻳــﻒ اﻟﺪاﻟــﺔ ﻓﻘــﺪ ورد ﺑﻌــﺪ اﻟﺪاﻟــﺔ ‪.main‬‬
‫ﻻﺣﻆ أﻳﻀﺎ أن ﺳﻄﺮ اﻹﻋﻼن ﻳﻨﺘﻬﻰ ﻟﻔﺎﺻﻠﺔ اﳌﻨﻘﻮﻃﺔ‪ ،‬أﻣﺎ اﻟﺴﻄﺮ اﳌﻨﺎﻇﺮ ﰱ اﻟﺘﻌﺮﻳﻒ ﻓﻼ ﻳﻨﺘﻬــﻰ ﻟﻔﺎﺻــﻠﺔ اﳌﻨﻘﻮﻃــﺔ ﺑــﻞ ﺑﺒﻠــﻮك ﳛــﺪﻩ‬
‫ﻗﻮﺳﺎن ﻣﻨﺜﻨﻴﺎن ﻳﺸﻜﻞ ﺟﺴﻢ اﻟﺪاﻟﺔ ‪ .function body‬ﳝﻜﻦ أن ﻧﺪﻣﺞ اﻹﻋﻼن و اﻟﺘﻌﺮﻳﻒ ﻣﻌﺎ ﰱ ﺧﻄﻮة واﺣﺪة‪ .‬ﻳﺘﻢ ذﻟﻚ ﺑﻜﺘﺎﺑــﺔ‬
‫اﻟﺘﻌﺮﻳﻒ ﻗﺒﻞ أول اﺳﺘﺨﺪام ﻟﻠﺪاﻟﺔ و ﺑﺪون وﺿﻊ ﺳﻄﺮ اﻹﻋﻼن ﺣﻴﺚ أﻧﻪ ﻳﺼﺒﺢ ﻋﻨﺪﺋﺬ ﺗﻜﺮار ﻻ ﻓﺎﺋﺪة ﻣﻨﻪ‪.‬‬
‫)(‪double get_diameter‬‬
‫{‬
‫;‪double D‬‬
‫;)‪printf("Enter diameter‬‬
‫;)‪scanf("%lg",&D‬‬
‫;)‪return(D‬‬
‫}‬
‫)‪void main (void‬‬
‫{‬
‫……… ;)(‪……..; r = 0.5*get_diameter‬‬
‫}‬
‫)ﱂ ﻧﻌــﻂ ﰱ اﳌﺜــﺎل اﻟﺴــﺎﺑﻖ ﺗﻌﺮﻳــﻒ اﻹﺟــﺮاء ‪ draw_line‬و ﻟﻜﻨــﻪ ﳚــﺐ أن ﻳﻌﻄــﻰ ﺳـﻮاء ﰱ ﻫـﺬا اﳌﻠــﻒ أو ﰱ أى ﻣﻠــﻒ آﺧــﺮ و ﳚــﺐ‬
‫أن ﻳﱰﺟﻢ ﻗﺒﻞ أن ﳓﺼﻞ ﻋﻠﻰ ﺑﺮ ﻣﺞ ﻗﺎﺑﻞ ﻟﻠﺘﻨﻔﻴﺬ(‬
‫ﻇﻬــﺮ ﰱ ﺗﻌﺮﻳــﻒ اﻟﺪاﻟــﺔ اﳌﻌﻄــﻰ أﻋــﻼﻩ أﻣــﺮ ﺟﺪﻳــﺪ و ﻫــﻮ اﻷﻣــﺮ ‪ .return‬ﻳــﺆدى ﻫـﺬا اﻷﻣــﺮ ﻟﻠﺨــﺮوج اﻟﻔــﻮرى ﻣــﻦ اﻟﺪاﻟــﺔ ﻣــﻊ‬
‫إﻋﻄﺎء اﻟﻘﻴﻤﺔ اﻟﻌﺎﺋﺪة ﺑــﲔ ﻗﻮﺳــﲔ‪ .‬ﻻ ﻳﻘﺘﺼــﺮ ﻫــﺬا اﻷﻣــﺮ ﻋﻠــﻰ اﻟﻈﻬــﻮر ﰱ ﺎﻳــﺔ اﻟﺪاﻟــﺔ وﻟﻜــﻦ ﳝﻜــﻦ أن ﻳﻈﻬــﺮ ﰱ أﻳــﺔ ﻣﻜــﺎن ﻣــﻦ ﺟﺴــﻢ‬
‫اﻟﺪاﻟﺔ ﺑﻞ و أن ﻳﺘﻜﺮر أﻛﺜــﺮ ﻣــﻦ ﻣــﺮة ﰱ ﻧﻔــﺲ اﻟﺪاﻟــﺔ‪ .‬ﳛــﺪث ذﻟــﻚ ﻛﻠﻤــﺎ رﻏﺒﻨــﺎ ﰱ اﳋــﺮوج ﻣﺒﻜـﺮا ﻣــﻦ اﻟﺪاﻟــﺔ ﻋﻨــﺪ ﲢﻘــﻖ ﺷــﺮط ﻣﻌــﲔ ﰱ‬
‫أى ﻣﻮﺿــﻊ ﻣــﻦ اﻟﺪاﻟــﺔ‪ .‬ﻟﺘﻮﺿــﻴﺢ ذﻟــﻚ ﻧﻔــﺮض أن ﻟــﺪﻳﻨﺎ داﻟــﺔ ﺗﺒﺤــﺚ ﻋــﻦ ﻗﻴﻤــﺔ ﻣــﺎ ‪ value‬ﰱ ﻣﺘﺠــﻪ ‪ ،x‬ﻓــﺈذا وﺟــﺪ ﺎ أﻋﻄــﺖ ﻛﻘﻴﻤــﺔ‬
‫ﻋﺎﺋﺪة رﻗﻢ اﻟﻌﻨﺼﺮ اﻟﺬى ﳛﻮى ﻫﺬﻩ اﻟﻘﻴﻤﺔ و إذا ﱂ ﲡﺪﻫﺎ أﻋﺎدت اﻟﻘﻴﻤﺔ ﺻﻔﺮ‪ .‬ﺗﻜﺘﺐ اﻟﺪاﻟﺔ ‪:‬‬
‫)‪int search( int *x, int value‬‬
‫;‪{ int j‬‬
‫)‪for (j=1; j<= n; j++‬‬
‫)‪{ if (x[j] == value‬‬
‫;)‪return(j‬‬
‫}‬
‫;)‪return(0‬‬
‫}‬

‫‪81‬‬
‫ﰱ ﺣﺎﻟﺔ اﻟﺪوال ﺑﺪون ﻗﻴﻤﺔ ﻋﺎﺋﺪة )أى ﰱ ﺣﺎﻟﺔ اﻹﺟﺮاء( ﻓﺈﻧﻪ ﳝﻜﻦ أﻳﻀﺎ إ ﺎء اﻟﱪ ﻣﺞ اﳉﺰﺋﻰ ﻗﺒﻞ ﺎﻳﺘﻪ اﻟﻄﺒﻴﻌﻴﺔ إذا ﲢﻘﻖ ﺷــﺮط ﻣــﺎ‬
‫ﺳﺘﺨﺪام ذات اﻷﻣﺮ ‪ return‬و ﻟﻜﻦ ﺑﺪون ﻗﻴﻤﺔ ﺑﲔ اﻷﻗﻮاس‪ .‬ﻓﻌﻠﻰ ﺳﺒﻴﻞ اﳌﺜﺎل اﻹﺟـﺮاء اﻟﺘــﺎﱃ ﳛﺴــﺐ و ﻳﻄﺒــﻊ ﺣﻠــﻮل ﻣﻌﺎدﻟــﺔ ﻣــﻦ‬
‫اﻟﺪرﺟﺔ اﻟﺜﺎﻧﻴﺔ ﻋﻠﻰ اﻟﺼﻮرة ‪ ،ax2 + bx + c = 0‬و ﻟﻜﻦ ﳝﻜﻦ اﳋﺮوج ﻣﻦ اﻹﺟﺮاء ﰱ أﻛﺜﺮ ﻣﻦ ﻣﻮﺿﻊ ﺗﺒﻌﺎ ﻟﻘﻴﻢ اﳌﻌﺎﻣﻼت‪:‬‬
‫‪#define TINY 1.0e-14‬‬
‫)‪void solve_print_2(double a, double b, double c‬‬
‫{‬
‫;‪double x1, x2‬‬
‫)‪if (fabs(a) < TINY‬‬
‫{‬
‫)‪if (fabs(b) < TINY‬‬
‫{‬
‫;)"‪printf("Wrong arguments \n‬‬
‫;‪return‬‬
‫}‬
‫;‪x1 = -c / b‬‬
‫;)" ‪printf("First Degree Solution = %lg\n‬‬
‫;‪return‬‬
‫}‬
‫;‪det = b*b – 4.0 * a * c‬‬
‫)‪if (det < 0‬‬
‫{‬
‫;)‪det = -sqrt(det‬‬
‫;‪x1 = - 0.5 * b / a; x2 = 0.5 * det/a‬‬
‫;)‪printf("Real part: %lg, Immaginary part: %lg\n",x1,x2‬‬
‫‪} else‬‬
‫{‬
‫;)‪det = sqrt(det‬‬
‫;‪x1 = 0.5* (-b + det)/ a‬‬
‫;‪x2 = 0.5* (-b - det)/ a‬‬
‫;)‪printf("Solutions are: %lg %lg\n",x1,x2‬‬
‫}‬
‫}‬
‫ﻻ ﻳﺸﱰط وﺿﻊ ‪ return‬ﰱ ﺎﻳﺔ اﻹﺟﺮاء ﻷن ﻧﺘﻬﺎءﻩ ﺳﻨﻌﻮد ﻟﻠﱪ ﻣﺞ اﻟﺪاﻋﻰ ﻋﻠﻰ أﻳﺔ ﺣﺎل‪.‬‬

‫‪.4‬ج‪ .3.‬ﻣﺪﺧﻼت اﻟﺪاﻟﺔ ‪Function arguments‬‬


‫ﲢﺘﺎج ﻋﺎدة اﻟﺪوال ﳌﻌﻄﻴﺎت أو ﻣﺪﺧﻼت‪ ،‬و ﰱ ﻫـﺬﻩ اﳊﺎﻟــﺔ ﳚــﺐ أن ﻧﻔﺼــﺢ ﰱ ﺳــﻄﺮ اﻹﻋــﻼن ﻋــﻦ ﻗﺎﺋﻤــﺔ اﳌــﺪﺧﻼت ﻣــﻊ‬
‫إﻋﻄــﺎء ﻧــﻮع ﻛــﻞ ﻣــﺪﺧﻞ‪ .‬ﻛــﻞ ﻣــﺪﺧﻞ ﺧــﺬ اﲰــﺎ و ﻳﻌﺎﻣــﻞ ﻛﺎﺳــﻢ ﻣﺘﻐــﲑ‪ ،‬و ﻫــﻮ ﻧﻔﺴــﻪ اﺳــﻢ اﳌﺘﻐــﲑ اﻟــﺬى ﻳﻈﻬــﺮ ﰱ ﺟﺴــﻢ اﻟﺪاﻟــﺔ ﺣــﲔ‬
‫ﻧﺴــﺘﺨﺪم اﳌﻌﻄﻴــﺎت‪ .‬ﺣﻴﻨﻤــﺎ ﻧﺴــﺘﺪﻋﻰ اﻟﺪاﻟــﺔ ﳚــﺐ أن ﻧﻌﻄــﻰ ﻗﺎﺋﻤــﺔ ﻟﻘــﻴﻢ اﻟﻔﻌﻠﻴــﺔ ﻟﻠﻤــﺪﺧﻼت‪ .‬ﺗﻌﻄــﻰ ﻫــﺬﻩ اﻟﻘــﻴﻢ ﰱ ﺻــﻮرة ﺗﻌﺒــﲑ ﻗــﺪ‬
‫ﻳﺘﻜــﻮن ﻣــﻦ ﺛﻮاﺑــﺖ أو ﻣﺘﻐـﲑات ﲢــﻮى اﻟﻘﻴﻤــﺔ اﳌﻄﻠﻮﺑــﺔ أو أﻳــﺔ ﺗﺮﻛﻴﺒــﺔ ﻣــﻦ ﻫــﺬﻩ اﻟﻌﻨﺎﺻــﺮ‪ .‬اﺳــﻢ اﳌﺘﻐــﲑ اﻟــﺬى ﻳﻌﻄــﻰ اﻟﻘﻴﻤــﺔ اﻟﻔﻌﻠﻴــﺔ ﻋﻨــﺪ‬
‫اﻻﺳﺘﺪﻋﺎء ﻟﻴﺲ ﻟﻪ أﻳﺔ ﻋﻼﻗﺔ ﺳــﻢ اﳌــﺪﺧﻞ‪ ،‬و ﻟﻜــﻦ ﻳــﺘﻢ ﻧﻘــﻞ اﳌﻌﻠﻮﻣــﺎت ﻣــﻦ اﻟﻘــﻴﻢ اﻟﻔﻌﻠﻴــﺔ إﱃ ﻗﺎﺋﻤــﺔ اﳌــﺪﺧﻼت ﻋﻠــﻰ أﺳــﺎس اﻟﺘﻨــﺎﻇﺮ‬
‫ﺣﻴــﺚ ﺗﻨﻘــﻞ اﻟﻘﻴﻤــﺔ اﻟﻔﻌﻠﻴــﺔ اﻷوﱃ ﻟﻠﻤــﺪﺧﻞ اﻷول و اﻟﻘﻴﻤــﺔ اﻟﻔﻌﻠﻴــﺔ اﻟﺜﺎﻧﻴــﺔ ﻟﻠﻤــﺪﺧﻞ اﻟﺜــﺎﱏ إﱃ آﺧــﺮﻩ‪ .‬ﻓــﺎﻹﺟﺮاء ‪solve_print_2‬‬
‫اﻟﻮارد أﻋﻼﻩ ﳝﻜﻦ أن ﻳﺴﺘﺪﻋﻰ ﻣﻦ اﻟﱪ ﻣﺞ اﻟﺮﺋﻴﺴﻰ ﺑﺴﻄﺮ ﻋﻠﻰ ﻫﺬﻩ اﻟﺼﻮرة ﻣﺜﻼ‪:‬‬

‫‪82‬‬
‫;)‪solve_print_2 (3.0, u, v+2‬‬
‫ﻋﻨﺪﺋــﺬ ﻳــﺘﻢ ﺗﻨﻔﻴــﺬ اﻹﺟـﺮاء ﲝﻴــﺚ ﺧــﺬ ‪ a‬اﻟﻘﻴﻤــﺔ ‪ 3.0‬ﺑﻴﻨﻤــﺎ ﺧــﺬ ‪ b‬ﳏﺘــﻮى اﳌﺘﻐــﲑ ‪ u‬ﻋﻨــﺪ اﻻﺳــﺘﺪﻋﺎء أﻣــﺎ ‪ c‬ﻓﺘﺄﺧــﺬ ﻗﻴﻤــﺔ اﻟﺘﻌﺒــﲑ‬
‫‪ v+2‬ﻋﻨــﺪ اﻻﺳــﺘﺪﻋﺎء‪ .‬ﳝﻜــﻦ ﻟﻄﺒــﻊ اﺳــﺘﺪﻋﺎء اﻟﺪاﻟــﺔ أﻛﺜــﺮ ﻣــﻦ ﻣــﺮة ﰱ اﻟــﱪ ﻣﺞ ﺑﻘــﻴﻢ ﻓﻌﻠﻴــﺔ ﳐﺘﻠﻔــﺔ )وﻫــﻮ اﻟﺴــﺒﺐ اﻟﺮﺋﻴﺴــﻰ اﻟــﺬى ﻣــﻦ‬
‫أﺟﻠﻪ ﻋﺮﻓﺖ اﻟﺪوال( و ﰱ ﻛﻞ ﻣﺮة ﻳﻌﺎد ﺗﻨﻔﻴﺬ اﻟﺪاﻟﺔ ﺳﺘﺨﺪام اﻟﻘﻴﻢ اﻟﻔﻌﻠﻴﺔ ﻋﻨﺪ اﻻﺳﺘﺪﻋﺎء‪.‬‬
‫ﻛﻴــﻒ ﻳــﺘﻢ ﻧﻘــﻞ اﻟﺒﻴــﺎ ت ﻣــﻦ اﻟﻘــﻴﻢ اﻟﻔﻌﻠﻴــﺔ إﱃ ﻗﺎﺋﻤــﺔ اﳌــﺪﺧﻼت؟ ﻫﻨــﺎك أﺳــﻠﻮﺑﲔ أﺳﺎﺳــﻴﲔ ﰱ ﲨﻴــﻊ ﻟﻐــﺎت اﻟﱪﳎــﺔ و ﳘــﺎ‬
‫اﻟﻨﻘﻞ ﻟﻘﻴﻤﺔ ‪ by value‬أو اﻟﻨﻘﻞ ﻟﻌﻨﻮان ‪ by address‬و ﻫﻮ ﻣﺎ ﺳﻨﺘﻌﺮف ﻋﻠﻴﻪ ﰱ ﻫﺬﻩ اﻟﻔﻘﺮة‪.‬‬

‫ﰱ ﺣﺎﻟــﺔ اﻟﻨﻘــﻞ ﻟﻘﻴﻤــﺔ‪ ،‬ﻋﻨــﺪ اﺳــﺘﺪﻋﺎء اﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ ﻳﺒــﺪأ اﳊﺎﺳــﺐ ﲞﻠــﻖ ﺧﺎﻧــﺔ ذاﻛــﺮة ﺟﺪﻳــﺪة ﺧﺎﺻــﺔ ﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ‬
‫ﻟﻜﻞ ﻣﺪﺧﻞ ﻣﻦ اﳌﺪﺧﻼت‪ .‬ﰒ ﻳﻨﻘﻞ اﻟﻘﻴﻤﺔ اﻟﻔﻌﻠﻴﺔ اﳌﻌﻄﺎة ﰱ ﻫﺬﻩ اﳋﺎﻧﺔ و ﻳﺒﺪأ ﺗﻨﻔﻴﺬ اﻟﱪ ﻣﺞ اﳉﺰﺋﻰ ﲝﻴﺚ ﻳﺘﻌﺎﻣــﻞ ﻣــﻊ ﻫــﺬﻩ اﳋﺎﻧــﺔ‬
‫ﻛ ــﺄى ﻣﺘﻐ ــﲑ ﻋ ــﺎدى‪ .‬أى أﻧ ــﻪ ﳝﻜ ــﻦ أن ﻧﻘ ـﺮأ ﻗﻴﻤﺘ ــﻪ ﻛﻤ ــﺎ ﳝﻜ ــﻦ أن ﻧﻌ ــﺪﳍﺎ‪ .‬ﻋﻨــﺪ اﻧﺘﻬ ــﺎء اﻟ ــﱪ ﻣﺞ اﳉﺰﺋ ــﻰ ﻳﻘ ــﻮم اﳊﺎﺳ ــﺐ ﻟﻐ ــﺎء ﻫ ــﺬﻩ‬
‫اﳋﺎ ت‪ .‬أى أن أﻳﺔ ﺗﻌﺪﻳﻞ ﻳﻘﻮم ﺑﻪ اﻟﱪ ﻣﺞ اﳉﺰﺋﻰ ﳍﺬﻩ اﳋﺎ ت ﻻ ﻳﺸﻌﺮ ﺑﻪ اﻟﱪ ﻣﺞ اﻟﺮﺋﻴﺴﻰ‪ .‬ﻣﺜﺎل ذﻟﻚ ﺑﺮ ﻣﺞ اﳌﻀﺮوب اﻟﺘﺎﱃ‪:‬‬
‫)‪double factorial (int n‬‬ ‫)(‪main‬‬ ‫‪n‬‬ ‫‪fac‬‬
‫{‬ ‫‪n‬‬
‫;‪double fact=1‬‬ ‫‪4‬‬
‫)‪while (n>1‬‬ ‫‪fac‬‬
‫;‪{ fact *= n‬‬ ‫)(‪factorial‬‬
‫;‪n --‬‬
‫}‬
‫;)‪return (fact‬‬
‫}‬
‫)‪void main(void‬‬
‫;‪{ double ff‬‬
‫;‪int k‬‬
‫;‪k = 4‬‬
‫;)‪ff = fatorial(k‬‬
‫;)‪printf("%d %10.0f\n",k,ff‬‬
‫‪/* will print 4 24.*/‬‬
‫}‬

‫ﻋﻨــﺪ اﺳــﺘﺪﻋﺎء اﻟﺪاﻟــﺔ ‪ factorial‬ﻣــﻦ اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ ﻛﺎﻧــﺖ اﻟﻘﻴﻤــﺔ اﻟﻔﻌﻠﻴــﺔ ﻫــﻰ ﳏﺘــﻮى اﳌﺘﻐــﲑ ‪ k‬ﻋﻨــﺪ اﻻﺳــﺘﺪﻋﺎء أى اﻟﻘﻴﻤــﺔ ‪.4‬‬
‫ﻋﻨﺪﺋﺬ ﻗــﺎم اﳊﺎﺳــﺐ ﲞﻠــﻖ ﺧﺎﻧــﺔ ذاﻛــﺮة ﺟﺪﻳــﺪة اﲰﻬــﺎ ‪ n‬وﺿــﻊ ﻓﻴﻬــﺎ اﻟﻘﻴﻤــﺔ ‪ 4‬ﰒ دﺧــﻞ ﰱ ﺣﺴــﺎب اﳌﻀــﺮوب‪ .‬اﻷﺳــﻠﻮب اﳌﻜﺘــﻮب ﺑــﻪ‬
‫اﻟﺪاﻟﺔ ﻓﻴﻪ ﺗﻌﺪﻳﻞ ﻟﻘﻴﻤﺔ ‪ n‬داﺧﻞ اﻟﱪ ﻣﺞ اﳉﺰﺋﻰ‪ .‬ﻻ ﻳﺆﺛﺮ ذﻟﻚ اﻟﺒﺘﺔ ﻋﻠﻰ ﳏﺘﻮى اﳌﺘﻐﲑ ‪ k‬اﳌﻌﺮف ﰱ اﻟﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ و اﻟــﺬى ﻳﻮﺟــﺪ‬
‫ﰱ ﻣﻜﺎن آﺧﺮ ﰱ اﻟﺬاﻛﺮة‪ .‬ﻋﻨﺪ اﳋﺮوج ﻳﻮﺿﺢ أﻣﺮ اﻟﻜﺘﺎﺑﺔ ﲜﻼء ذﻟﻚ‪.‬‬
‫اﻷﺳــﻠﻮب اﻵﺧــﺮ ﻫــﻮ اﻟﻨﻘــﻞ ﻟﻌﻨـﻮان‪ .‬ﰱ ﻫــﺬﻩ اﳊﺎﻟــﺔ ﺣــﲔ ﻧﺴــﺘﺪﻋﻰ اﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ ﻓــﺄن اﳊﺎﺳــﺐ ﻳﻮﺣــﺪ ﺑــﲔ اﳌﺘﻐــﲑ اﻟــﺬى‬
‫ﻳﻈﻬــﺮ ﰱ اﻟــﱪ ﻣﺞ اﻟــﺪاﻋﻰ و ﺑــﲔ اﳌﺘﻐــﲑ اﻟــﺬى ﻳﻈﻬــﺮ ﰱ اﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ ﲝﻴــﺚ ﳝﻜــﻦ ﻧﻘــﻞ اﳌﻌﻠﻮﻣــﺎت ﰱ اﻻﲡــﺎﻫﲔ‪ .‬أى ﳝﻜــﻦ أن‬
‫ﻳﺴــﺘﻌﻤﻞ اﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ اﻟﺒﻴــﺎ ت اﳌﺨﺰﻧــﺔ ﰱ اﳌﺘﻐــﲑ‪ ،‬و إذا ﺣــﺪث ﺗﻌــﺪﻳﻞ ﻟﻘﻴﻤــﺔ اﳌﺘﻐــﲑ‪ ،‬ﻓــﺈن اﻟــﱪ ﻣﺞ اﻟــﺪاﻋﻰ ﻳﺸــﻌﺮ ﺑــﺬﻟﻚ ﺣﻴﻨﻤــﺎ‬
‫ﻳﻨﺘﻬــﻰ اﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ ﻣــﻦ أداء ﻣﻬﻤﺘــﻪ‪ .‬ﰱ ﻟﻐــﺔ اﻟﻔــﻮرﺗﺮان ‪ FORTRAN‬ﻳﻮﺟــﺪ اﻟﻨﻮﻋــﺎن )اﻟﻨﻘــﻞ ﻟﻘﻴﻤــﺔ و اﻟﻨﻘــﻞ ﻟﻌﻨـﻮان( و ﻟﻜــﻦ‬
‫ﻳﺼــﻌﺐ اﺧﺘﻴــﺎر اﻟﻨــﻮع اﳌﻄﻠــﻮب!‪ .‬ﰱ ﻟﻐــﺔ اﻟﺒﺎﺳــﻜﺎل ‪ Pascal‬ﳝﻜــﻦ اﺧﺘﻴــﺎر اﻟﻨــﻮع اﳌﻄﻠــﻮب ﺑﺴــﻬﻮﻟﺔ و ﻳﺴــﺮ‪ .‬أﻣــﺎ ﰱ ﻟﻐــﺔ ال‪ C‬ﻓﺈﻧﻨــﺎ‬
‫اﻟﻨﻘــﻞ ﳛــﺎﻛﻰ ﲤﺎﻣــﺎ ﻣــﺎ ﳛــﺪث داﺧﻠﻴــﺎ ﰱ اﻵﻟــﺔ‪ ،‬أى أﻧــﻪ ﰱ ﲨﻴــﻊ اﻷﺣـﻮال ﻳــﺘﻢ اﻟﻨﻘــﻞ ﻟﻘﻴﻤــﺔ‪ ،‬و إذا أرد اﻟﺘــﺄﺛﲑ ﻋﻠــﻰ ﻗﻴﻤــﺔ اﳌﺘﻐــﲑ ﰱ‬

‫‪83‬‬
‫اﻟﱪ ﻣﺞ اﻟﺪاﻋﻰ ﻓﺈﻧﻨﺎ ﻧﻨﻘﻞ ﰱ ﻫﺬﻩ اﳊﺎﻟﺔ ﻋﻨﻮان اﳌﺘﻐﲑ اﻟﺬى ﻧﺮﻳﺪ اﻟﺘﺄﺛﲑ ﻋﻠﻴﻪ‪ .‬أى أﻧﻨﺎ ﻧﺴﺘﺨﺪم ﻣﺆﺷﺮ ﻟﻠﻤﺘﻐــﲑ اﳌﻌــﲎ ﳛــﻮى ﻋﻨﻮاﻧــﻪ و‬
‫ﻳــﺘﻢ ﻧﻘــﻞ ﻗﻴﻤــﺔ اﳌﺆﺷــﺮ )أى ﻋﻨ ـﻮان اﳌﺘﻐــﲑ( ﻣــﻦ اﻟــﱪ ﻣﺞ اﻟــﺪاﻋﻰ إﱃ اﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ‪ ،‬أى أﻧﻨــﺎ ﻧﻨﻘــﻞ ﻟﻘﻴﻤــﺔ ﺷــﻜﻼ و ﻟﻜــﻦ ﻟﻌﻨ ـﻮان‬
‫ﻣﻮﺿﻮﻋﺎ! ﻟﺘﻮﺿﻴﺢ ذﻟﻚ ﺗﺼﻮر أﻧﻨﺎ ﻛﺘﺒﻨﺎ إﺟﺮاء ﻟﻘﺮاءة ﺑﻴﺎ ت و إﻋﺎدة ﻫﺬﻩ اﻟﺒﻴﺎ ت إﱃ اﻟﱪ ﻣﺞ اﻟﺪاﻋﻰ‪ .‬و ﻟﺘﻜﻦ ﻫﺬﻩ اﻟﺒﻴﺎ ت ﻫــﻰ‬
‫‪ r, theta‬ﻛﻤﺎ ﰱ اﳌﺜﺎل اﻷول ﰱ ﻫﺬا اﻟﺒﺎب‪ ،‬و ﻧﻀﻴﻒ ﻋﻠﻴﻬﺎ رﻗﻢ ﻛﻮدى )‪ =1‬اﻗﺮأ ﻣﻦ ﻣﻠﻒ‪ = 0 ،‬اﻗﺮأ ﻣﻦ اﻟﺸﺎﺷــﺔ(‪ .‬ﻓﺄﻧﻨــﺎ ﻧﻜﺘــﺐ‬
‫)أﻧﻈﺮ أﻳﻀﺎ اﻟﺸﻜﻞ اﳌﻮﺿﺢ(‪:‬‬
‫)‪void get_data (int k, double * u, double * v‬‬
‫{‬ ‫;‪FILE * fil‬‬
‫;‪double a,b‬‬
‫)‪if (k‬‬
‫;)"‪{ fil = fopen("input.dat,"r‬‬
‫;)‪fscanf (fil,"%lg %lg",&a,&b‬‬
‫‪} else‬‬
‫;)"‪{ printf ("Enter a,b:‬‬
‫;)‪scanf("%lg &lg",&a,&b‬‬
‫}‬
‫;‪* u = a + 2.0*b‬‬
‫;‪* v = b / a‬‬
‫}‬
‫)‪void main (void‬‬
‫;‪{ double r,theta; int j=1‬‬
‫;)‪get_data(j,&r,&theta‬‬
‫;))‪draw_line(0,0,r*cos(theta),r*sin(theta‬‬
‫}‬

‫ﻋﻨــﺪﻣﺎ ﻧﺴــﺘﺪﻋﻰ اﻟﺪاﻟــﺔ ‪ get_data‬ﻣــﻦ اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ ﻓﺈﻧﻨــﺎ ﻧﻌﻄﻴﻬــﺎ ﻗﻴﻤﺘــﲔ ﻓﻌﻠﻴﺘــﲔ و ﳘــﺎ ﻋﻨ ـﻮا اﳌﺘﻐــﲑﻳﻦ ‪ .r, theta‬ﻳــﺘﻢ ﻧﻘــﻞ‬
‫اﻟﻌﻨﻮاﻧﲔ ﻋﻠﻰ اﳌﺆﺷﺮﻳﻦ ‪ u, v‬ﻋﻠﻰ اﻟﱰﺗﻴﺐ‪ .‬أى أن ﻫﺬﻳﻦ اﳌﺆﺷﺮﻳﻦ ﳛﻮ ن ﻋﻨـﻮاﱏ ﻣﺘﻐــﲑﻳﻦ ﻋﺮﻓــﺎ ﰱ اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ‪ .‬و ﰱ اﻟﺴــﻄﺮﻳﻦ‬
‫اﻷﺧﲑﻳﻦ ﻣﻦ اﻟﱪ ﻣﺞ اﳉﺰﺋﻰ ﻧﻄﻠﺐ وﺿﻊ ﻗﻴﻢ ﻋﺪدﻳﺔ ﻓﻴﻤﺎ ﻳﺸﲑ إﻟﻴﻪ ﻛﻼ اﳌﺆﺷﺮﻳﻦ أى ﰱ اﳌﺘﻐﲑﻳﻦ ‪ r, theta‬ﻣﻦ اﻟﱪ ﻣﺞ اﻟﺮﺋﻴﺴﻰ‪.‬‬

‫ﻟﻌﻞ اﻟﻘﺎرئ ﻳﺴﺘﻄﻴﻊ أن ﻳﺪرك اﻵن ﳌﺎذا ﻛﻨﺎ ﻧﻀﻊ داﺋﻤﺎ اﻟﺮﻣﺰ & أﻣﺎم اﳌﺘﻐﲑات اﳌﻄﻠﻮب ﻗﺮاء ﺎ ﺑﻮاﺳــﻄﺔ اﻟــﺪوال ‪ scanf‬و‬
‫أﺧﻮا ﺎ‪ .‬ﺣﻴﺚ أن ﻫﺬﻩ ﻫﻰ اﻟﻄﺮﻳﻘﺔ اﻟﱴ ﳝﻜﻦ ﺎ أن ﳛﺼــﻞ ﺑــﺮ ﻣﺞ داﻋــﻰ ﻋﻠــﻰ ﺑﻴــﺎ ت ﺟــﺮى اﳊﺼــﻮل ﻋﻠﻴﻬــﺎ ﺑــﺪاﺧﻞ ﺑــﺮ ﻣﺞ ﺟﺰﺋــﻰ‬
‫ﻣﺴﺘﺪﻋﻰ و اﻟﺪاﻟﺔ ‪ scanf‬ﻟﻴﺴﺖ إﻻ ﺑﺮ ﳎﺎ ﺟﺰﺋﻴﺎ ﻳﻨﻄﺒﻖ ﻋﻠﻴﻬﺎ ﻣﺎ ﻳﻨﻄﺒﻖ ﻋﻠﻰ أﻳﺔ داﻟﺔ‪.‬‬

‫أﻣﺎ اﳌﺘﺠﻬﺎت ﻓﻬﻰ ﺗﻨﻘﻞ ﻟﻌﻨﻮان ﺑﺼﻮرة ﻃﺒﻴﻌﻴﺔ ﻣﺜﻞ اﻟﱪ ﻣﺞ اﻟﺘﺎﱃ و اﻟــﺬى ﻳﻘــﻮم ﻓﻴــﻪ اﻹﺟـﺮاء ) (‪ fill_vec‬ﲟــﻞء ﻋﻨﺎﺻــﺮ‬
‫اﳌﺘﺠﻪ ‪ x‬ﻛﺎﻵﺗﻰ‪ :‬ﲨﻴﻊ اﻟﻌﻨﺎﺻﺮ ﻣﻦ ‪ 2‬إﱃ ‪ n‬ﺗﺴﺎوى ﻗﻴﻤﺘﻬﺎ ﻣﺮﺑﻊ رﻗﻢ اﻟﻌﻨﺼﺮ‪ ،‬ﻋﺪا اﻟﻌﻨﺼﺮ اﻷول اﻟﺬى ﻳﻘﺮأ ﻣﻦ اﻟﺸﺎﺷﺔ‪.‬‬

‫‪84‬‬
‫ذاﻛﺮة اﻟﺒﺮﻧﺎﻣﺞ اﻟﺮﺋﯿﺴﻰ‬
‫‪101‬‬ ‫‪j‬‬ ‫‪110‬‬ ‫‪r‬‬ ‫‪123‬‬ ‫‪th‬‬
‫‪1‬‬ ‫‪-‬‬ ‫‪-‬‬

‫اﻟﻨﻘﻞ‬ ‫اﻟﻨﻘﻞ‬
‫ﺑﺎﻟﻘﯿﻤﺔ‬ ‫ﺑﺎﻟﻌﻨﻮان‬

‫‪302‬‬ ‫‪k‬‬ ‫‪315‬‬ ‫‪u‬‬ ‫‪324‬‬ ‫‪v‬‬


‫‪1‬‬ ‫‪110‬‬ ‫‪123‬‬

‫ذاﻛﺮة اﻟﺒﺮﻧﺎﻣﺞ اﻟﺠﺰﺋﻰ‬


‫)‪void fill_vec ( double *x, int n‬‬
‫{‬
‫;‪x += n‬‬
‫)‪while (n > 1‬‬
‫{‬
‫;‪* x = n * n‬‬
‫;‪n--‬‬
‫;‪x --‬‬
‫}‬
‫;)"]‪printf("Enter the value of x[1‬‬
‫;)‪scanf("%lg",x‬‬
‫}‬

‫)‪void main ( void‬‬


‫;‪{ double *x‬‬
‫;‪int n‬‬
‫;)"‪printf ("Enter n:‬‬
‫;)‪scanf("%d",&n‬‬ ‫‪/* Assume the user enters n=10 */‬‬
‫;))‪x = (double *) malloc(sizeof (double) * (n+1‬‬
‫;)‪fill_vec(x,n‬‬
‫;)]‪printf("n=%d, x[n] = %lg\n",n,x[n‬‬
‫‪/* will print n=10, x[n]=100.0*/‬‬
‫}‬
‫اﻟﱪ ﻣﺞ اﻟﺴﺎﺑﻖ ﻋﻠﻰ ﺑﺴﺎﻃﺘﻪ إﻻ أﻧﻪ ﻗﺪ ﻳﺜﲑ ﻟﻠﻘﺎرئ اﳌﺘﺄﱏ اﻟﻌﺪﻳﺪ ﻣﻦ اﻷﺳﺌﻠﺔ‪ .‬أوﻻ ﳚﺐ أن ﻧﺪرك أن اﳌﺘﻐـﲑات ‪ x, n‬اﻟــﱴ ﺗﻈﻬــﺮ ﰱ‬
‫اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ ﻟــﻴﺲ ﳍــﺎ أﻳــﺔ ﻋﻼﻗــﺔ ﳌﺘﻐـﲑات ﺑــﻨﻔﺲ اﻻﺳــﻢ اﻟــﱴ ﺗﻈﻬــﺮ ﰱ اﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ‪ .‬ﻓﺘﺸــﺎﺑﻪ اﻷﲰــﺎء ﻫﻨــﺎ ﻻ ﻳــﺪل ﻋﻠــﻰ أى‬
‫ﺷــﺊ‪ .‬و ﻟﻜــﻦ ﺣﻴــﺚ أﻧﻨــﺎ ﻋﺮﻓﻨــﺎ اﳌﺘﻐــﲑﻳﻦ ‪ x,n‬ﰱ أول ﺳــﻄﺮﻳﻦ ﻣــﻦ اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ ﻛﻤــﺎ ﻋﺮﻓﻨــﺎ ﻣﺘﻐــﲑﻳﻦ ‪ x,n‬ﰱ ﺳــﻄﺮ اﻹﻋــﻼن ﻣــﻦ‬
‫اﻟﱪ ﻣﺞ اﳉﺰﺋﻰ ﻓﺄ ﻤﺎ ﻳﻌﺎﻣﻼ ﻛﻤﺘﻐﲑﻳﻦ ﳐﺘﻠﻔﲔ‪ .‬ﺗﻔﻬــﻢ ﻛــﻞ إﺷــﺎرة ﻟﻠﻤﺘﻐــﲑ ‪ x‬ﰱ اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ ﻋﻠــﻰ أ ــﺎ ﲣــﺺ اﳌﺘﻐــﲑ اﻟــﺬى ﻋــﺮف‬
‫و ﺣﺠﺰ ﻟﻪ ﻋﻨﻮان ﺧﺎﻧﺔ ذاﻛــﺮة ﰱ اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ‪ ،‬ﻛﻤــﺎ ﺗﻔﻬــﻢ ﻛــﻞ إﺷــﺎرة ﻟﻠﻤﺘﻐــﲑ ‪ x‬ﰱ اﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ ﻋﻠــﻰ أ ــﺎ ﲣــﺺ اﳌﺘﻐــﲑ ‪ x‬ﰱ‬
‫اﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ‪ .‬ﻋﻨــﺪ اﺳــﺘﺪﻋﺎء اﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ ﻳﻘــﻮم اﳊﺎﺳــﺐ ﺑﻨﻘــﻞ اﻟﺒﻴــﺎ ت اﳌﻮﺟــﻮدة ﰱ اﳌﺘﻐـﲑات اﳌﻌﺮﻓــﺔ ﰱ اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ إﱃ‬
‫ﻧﻈﲑ ــﺎ ﰱ اﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ‪ .‬ﻳﻌﺘﻤــﺪ اﻟﺘﻨــﺎﻇﺮ ﻋﻠــﻰ ﺗﺮﺗﻴــﺐ ورود اﳌﺘﻐــﲑ ﰱ ﻗﺎﺋﻤــﺔ اﳌــﺪﺧﻼت و ﻟــﻴﺲ ﻋﻠــﻰ ﺗﺸــﺎﺑﻪ اﻷﲰــﺎء‪ .‬ﻋﻨــﺪ ﺑﺪاﻳــﺔ‬

‫‪85‬‬
‫ﺗﺸﻐﻴﻞ اﻟﱪ ﻣﺞ اﳉﺰﺋــﻰ ﳛــﻮى اﳌﺘﻐــﲑ ‪ x‬ﰱ اﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ ﻋﻨـﻮان اﳋﺎﻧــﺔ اﻷوﱃ ﰱ اﳌﺘﺠــﻪ اﻟــﺬى ﰎ ﺣﺠــﺰﻩ ﰱ اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ‪ ،‬ﺑﻴﻨﻤــﺎ‬
‫ﳛﻮى اﳌﺘﻐﲑ ‪ n‬ﻋﺪد ﻋﻨﺎﺻﺮ اﳌﺘﺠﻪ‪ ،‬ﻛﻤﺎ ﻳﻮﺿﺢ اﻟﺸﻜﻞ اﻟﺘﺎﱃ‪:‬‬
‫‪x‬‬ ‫‪n‬‬ ‫ذاﻛﺮة اﻟﺒﺮﻧﺎﻣﺞ اﻟﺮﺋﯿﺴﻰ‬
‫‪1‬‬

‫‪x‬‬ ‫‪n‬‬
‫‪1‬‬ ‫ذاﻛﺮة اﻟﺒﺮﻧﺎﻣﺞ اﻟﺠﺰﺋﻰ‬

‫ﻗﯿﻢ اﻟﻤﺆﺷﺮات ﻋﻨﺪ اﻟﺪﺧﻮل ﻓﻰ اﻟﺒﺮﻧﺎﻣﺞ اﻟﺠﺰﺋﻰ‬


‫ﻗﯿﻢ اﻟﻤﺆﺷﺮات ﺑﻌﺪ ﺗﻨﻔﯿﺬ أول أﻣﺮ ﻓﻰ اﻟﺒﺮﻧﺎﻣﺞ اﻟﺠﺰﺋﻰ‬
‫ﺣﺎﻟﺔ اﻟﺬاﻛﺮة ﻋﻨﺪ اﻟﺪﺧﻮل ﰱ اﻟﱪ ﻣﺞ اﳉﺰﺋﻰ و ﺑﻌﺪ ﺗﻨﻔﻴﺬ أول أﻣﺮ ﻓﻴﻪ‬
‫‪x‬‬ ‫‪n‬‬ ‫ذاﻛﺮة اﻟﺒﺮﻧﺎﻣﺞ اﻟﺮﺋﯿﺴﻰ‬
‫‪1‬‬

‫‪x‬‬ ‫‪n‬‬
‫‪9‬‬ ‫ذاﻛﺮة اﻟﺒﺮﻧﺎﻣﺞ اﻟﺠﺰﺋﻰ‬

‫ﺣﺎﻟﺔ اﻟﺬاﻛﺮة ﺑﻌﺪ ﺗﻨﻔﻴﺬ أول دورة ﰱ اﻟﻌﻤﻠﻴﺔ اﻟﺘﻜﺮارﻳﺔ ﰱ اﻟﱪ ﻣﺞ اﳉﺰﺋﻰ‬
‫ﳝﻜــﻦ أن ﻧﻌــﺪل ﻣــﻦ ﻗــﻴﻢ اﳌﺘﻐ ـﲑات ‪ x, n‬ﰱ اﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ‪ ،‬ﺑــﺪون أن ﻳــﺆﺛﺮ ذﻟــﻚ ﻋﻠــﻰ ﻗــﻴﻢ اﳌﺘﻐ ـﲑات ﺑــﻨﻔﺲ اﻻﺳــﻢ ﰱ‬
‫اﻟﱪ ﻣﺞ اﻟﺮﺋﻴﺴﻰ‪ .‬ﰱ ﺑﺪاﻳﺔ اﻟﱪ ﻣﺞ اﳉﺰﺋﻰ ﺟﻌﻠﻨﺎ ‪ x‬ﻳﺆﺷﺮ ﻋﻠﻰ اﻟﻌﻨﺼﺮ اﻷﺧﲑ ﻣﻦ اﳌﺘﺠﻪ ﻟﻜﻰ ﻧﺒــﺪأ ﰱ ﻣــﻞء ﻋﻨﺎﺻــﺮ اﳌﺘﺠــﻪ ﻟﱰﺗﻴــﺐ‬
‫اﻟﻌﻜﺴــﻰ )ﻣــﻦ اﻷﺧــﲑ إﱃ اﻷول(‪ .‬ﰱ ﻛــﻞ دورة ﻣــﻦ اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ ﻧــﻨﻘﺺ اﻟﻌــﺪاد ﲟﻘــﺪار اﻟﻮﺣــﺪة ﻛﻤــﺎ ﻧــﻨﻘﺺ اﳌﺆﺷــﺮ ‪ x‬ﻟﻴﺸــﲑ إﱃ‬
‫اﻟﻌﻨﺼﺮ اﻟﺴﺎﺑﻖ ﰱ اﳌﺘﺠﻪ و ﻫﻜﺬا إﱃ أن ﻧﺼﻞ ﻟﻠﻌﻨﺼــﺮ اﻷول و اﳌﻄﻠــﻮب ﻣﻠﺌــﻪ ﺑﻮاﺳــﻄﺔ اﻟﻘـﺮاءة‪ .‬ﻻﺣــﻆ أن اﻟﻌﻼﻣــﺔ & ﱂ ﺗﺴــﺒﻖ اﺳــﻢ‬
‫اﳌﺘﻐﲑ ‪ x‬ﺣﻴﺚ أﻧﻪ ﻟﻔﻌﻞ ﻣﺆﺷﺮ أى أﻧــﻪ ﳛــﻮى ﻣﺒﺎﺷــﺮة ﻋﻨـﻮان اﳋﺎﻧــﺔ اﻟــﱴ ﻧﺮﻳــﺪ أن ﳕﻸﻫــﺎ‪ ،‬و ﻻ ﻳﺼــﺢ إذن أن ﻧﻀــﻴﻒ ﻋﻼﻣــﺔ اﻟﻌﻨـﻮان‬
‫& ﻗﺒﻠﻪ‪ .‬ﻋﻨﺪ اﻻﻧﺘﻬﺎء ﻣﻦ أداء اﻟﱪ ﻣﺞ اﳉﺰﺋﻰ ﳛﻮى اﳌﺘﻐـﲑان ‪ x, n‬ﻗــﻴﻢ ﻣﻐــﺎﻳﺮة ﳌــﺎ ﻳﻨﺎﻇﺮﳘــﺎ ﰱ اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ و ﻟﻜــﻦ ﻋﻨــﺪﻣﺎ ﻧﻌــﻮد‬
‫ﻟﻠــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ ﻓــﺄن ﻃﺒﺎﻋــﺔ ]‪ n, x[n‬ﺗﺆﻛــﺪ أن اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ ﱂ ﻳﺘــﺄﺛﺮ ﻟﺘﻌــﺪﻳﻼت اﻟــﱴ ﻃـﺮأت ﻋﻠــﻰ ﻫــﺬﻳﻦ اﳌﺘﻐــﲑﻳﻦ و ﻟﻜــﻦ ﰎ‬
‫ﻣﻞء ﻋﻨﺎﺻﺮ اﳌﺘﺠﻪ ﻛﻤﺎ ﻧﺮﻳﺪ‪.‬‬
‫ﰱ اﳌﺜــﺎل اﻟﺴــﺎﺑﻖ أﻣﻜــﻦ ﲤﺮﻳــﺮ ﻣﺘﺠــﻪ ﻛﻤﻠــﻪ ﻋــﱪ اﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ ﺳــﺘﺨﺪام اﳌﺆﺷــﺮ و ﺑــﺬﻟﻚ أﻣﻜــﻦ اﻻﻟﺘﻔــﺎف ﺣــﻮل اﻟﻘﻴــﺪ‬
‫اﻟــﺬى ﻳﺘﻌﻠــﻖ ﺑﺘﻌﺮﻳــﻒ اﻟــﺪوال و اﻟــﺬى ﻻ ﻳﺴــﻤﺢ ﻟﻨــﺎ أن ﻧﺴــﺘﺨﺪم أﻳــﺔ ﻗﻴﻤــﺔ ﻋﺎﺋــﺪة ﻣﺮﻛﺒــﺔ و ﻟﻜــﻦ ﻣــﻦ ﻧــﻮع ﺑﺴــﻴﻂ ﻓﻘــﻂ‪ .‬ﺳــﺘﺨﺪام‬
‫اﳌﺆﺷﺮات ﳝﻜﻦ إذن أن ﻧﺘﻌﺎﻣﻞ ﻣﻊ أﻳﺔ ﺑﻴﺎ ت ﻫﻴﻜﻠﻴﺔ ﻣﻬﻤﺎ ﻛﺎﻧﺖ درﺟﺔ ﺗﻌﻘﻴﺪﻫﺎ‪ ،‬ﻛﻤﺎ ﺳﻨﺮى ﻓﻴﻤﺎ ﺑﻌﺪ‪.‬‬

‫‪86‬‬
‫‪.4‬ج‪ .4.‬ﻣﺪى ﺗﻌﺮﻳﻒ اﳌﺘﻐﲑات ‪scope of variables‬‬
‫ﳚﺮ اﳊﺪﻳﺚ ﰱ ﺎﻳﺔ اﻟﻔﻘﺮة اﻟﺴﺎﺑﻘﺔ ﻟﺘﻨــﺎول ﻗﻀــﻴﺔ ﻫﺎﻣــﺔ و ﻫــﻰ ﻣــﺪى ﺗﻌﺮﻳــﻒ اﳌﺘﻐـﲑات اﳌﺨﺘﻠﻔــﺔ‪ .‬اﳌﻘﺼــﻮد ــﺬا اﳌــﺪى ﻫــﻮ‬
‫اﳌﻨﻄﻘــﺔ اﻟﻮاﻗﻌــﺔ ﰱ اﻟــﱪ ﻣﺞ اﻟــﱴ ﳝﻜــﻦ أن اﺳــﺘﺨﺪم ﻓﻴﻬــﺎ ﻫــﺬا اﳌﺘﻐــﲑ ﲝﻴــﺚ ﻳﻜــﻮن ﻣﻌﺮﻓــﺎ و ﳐﺘــﺰ ﻷﻳــﺔ ﻗﻴﻤــﺔ أﻛــﻮن ﻗــﺪ أودﻋﺘﻨﻬــﺎ ﻓﻴــﻪ‬
‫ﻣﺴــﺒﻘﺎ‪ .‬اﻟﻘﺎﻋــﺪة اﻟﻌﺎﻣــﺔ ﻫــﻰ ﻛﺎﻟﺘــﺎﱃ‪ :‬ﻳﺒــﺪأ ﻣــﺪى ﺗﻌﺮﻳــﻒ اﳌﺘﻐــﲑ ﻋﻨــﺪ ﻧﻘﻄــﺔ اﻹﻋــﻼن ﻋﻨــﻪ )و اﻟــﺬى ﳚــﺐ أن ﻳﻜــﻮن ﰱ ﺑﺪاﻳــﺔ ﺑﻠــﻮك( و‬
‫ﻳﻨﺘﻬﻰ ﺑﻨﻬﺎﻳﺔ اﻟﺒﻠﻮك اﻟﺬى ﻋﺮف ﻓﻴﻪ‪.‬‬
‫واﺣــﺪ ﻣــﻦ أﻫــﻢ اﻟﺒﻠﻮﻛــﺎت اﻟــﱴ ﺗﻌﺎﻣﻠﻨــﺎ ﻣﻌﻬــﺎ ﻟــﻶن ﻛــﺎن ﺟﺴــﻢ اﻟﺪاﻟــﺔ و ﻫــﻮ اﻟﺒﻠــﻮك اﶈﺼــﻮر ﺑــﲔ أﻗـﻮاس ﻣﻨﺜﻨﻴــﺔ و ﻳﻈﻬــﺮ ﺑﻌــﺪ‬
‫ﺳــﻄﺮ إﻋــﻼن اﻟﺪاﻟــﺔ ﻣﺒﺎﺷــﺮة‪ .‬إذا ﻋــﺮف ﻣﺘﻐــﲑ ﰱ ﺑﺪاﻳــﺔ ﺟﺴــﻢ أى داﻟــﺔ )ﲟــﺎ ﰱ ذﻟــﻚ اﻟﺪاﻟــﺔ اﻟﺮﺋﻴﺴــﻴﺔ ‪ (main‬ﻓــﺈن اﳌﺘﻐــﲑ ﻳﺼــﺒﺢ ﻣﻌﺮﻓــﺎ‬
‫ﰱ ﻛﻞ اﻟﺪاﻟﺔ ﲟﺎ ﰱ ذﻟــﻚ ﲨﻴــﻊ ﺑﻠﻮﻛﺎ ــﺎ اﻟﺪاﺧﻠﻴــﺔ‪ .‬ﳝﻜــﻦ أﻳﻀــﺎ أن ﻳﻌــﺮف ﻣﺘﻐــﲑ ﻣﺆﻗــﺖ ﰱ ﺑﺪاﻳــﺔ ﺑﻠــﻮك ‪ if‬ﻣــﺜﻼ ﻛﻤــﺎ ﰱ اﳌﺜــﺎل اﻟﺘــﺎﱃ و‬
‫اﳌﻄﻠﻮب ﻣﻨﻪ ﳎﺮد ﻗﺮاءة ﻣﺘﻐﲑﻳﻦ و ﻛﺘﺎﺑﺘﻬﻤﺎ ﺑﱰﺗﻴﺐ ﻗﻴﻤﻬﻢ‪.‬‬
‫>‪#include <stdio.h‬‬
‫)‪void main (void‬‬
‫{‬
‫;‪double xmin,xmax‬‬
‫;)"‪printf("Enter two values:‬‬
‫;)‪scanf("%lg %lg",&xmin, &xmax‬‬
‫)‪if (xmin > xmax‬‬
‫{‬
‫;‪double temp‬‬
‫;‪temp = xmin‬‬
‫;‪xmin = xmax‬‬
‫;‪xmax = temp‬‬
‫}‬
‫‪/* At this point the variable temp is no longer defined */‬‬
‫;)‪printf ("The maximum is : %lg The minimum is : %lg\n",xmax,xmin‬‬
‫}‬
‫ﻛﻤــﺎ ﻳﻮﺿــﺢ اﻟﺘﻌﻠﻴــﻖ اﻟ ـﻮارد ﺑﻌــﺪ ﺑﻠــﻮك ‪ if‬ﻓــﺈن اﳌﺘﻐــﲑ اﳌﺆﻗــﺖ ‪ temp‬ﱂ ﻳﻌــﺪ ﻣﻌﺮﻓــﺎ ﲟﺠــﺮد اﳋــﺮوج ﻣــﻦ اﻟﺒﻠــﻮك اﻟــﺬى ﻋــﺮف ﻓﻴــﻪ‪ .‬ﺑﻴﻨﻤــﺎ‬
‫اﳌﺘﻐﲑات ‪ xmin, xmax‬ﻓﻬﻰ ﻣﻌﺮﻓﺔ إﱃ ﺎﻳﺔ اﻟﺪاﻟﺔ‪.‬‬

‫إذا ﰎ ﺑﺪاﺧﻞ ﻣﺪى اﻟﺘﻌﺮﻳﻒ اﺳﺘﺪﻋﺎء ﻟﺪاﻟﺔ ﻣــﺎ‪ ،‬ﻓــﺈن اﳌﺘﻐــﲑ ﻳﻜــﻮن ﻣﻌﺮﻓــﺎ ﻓﻘــﻂ ﰱ ﺳــﻄﺮ اﻻﺳــﺘﺪﻋﺎء و ﻟﻜﻨــﻪ ﻏــﲑ ﻣﻌــﺮف ﰱ‬
‫ﺳــﻄﻮر اﻟﺪاﻟــﺔ اﳌﺴــﺘﺪﻋﺎة ذا ــﺎ‪ .‬ﰱ اﳌﺜــﺎل اﻵﺗــﻰ ﻳﻘـﺮأ اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ ﺛﻼﺛــﺔ ﻣﺘﺠﻬــﺎت ﻣــﻦ ﻣﻠــﻒ ﰒ ﳛﺴــﺐ ﺣﺎﺻــﻞ اﻟﻀــﺮب اﻟﻘﻴﺎﺳــﻰ‬
‫ﳍﻢ ﻣﺜﲎ ﻣﺜﲎ‪.‬‬
‫>‪#include <stdio.h‬‬
‫;)‪void get_data (int *m, double **x, double ** y, double ** z‬‬
‫;)‪double scal_prod (int n,double *x, double *y‬‬

‫)‪void main (void‬‬


‫{‬
‫;‪double *a, *b, *c‬‬
‫;‪double scalar_product‬‬
‫;‪int n‬‬

‫‪87‬‬
‫;)‪get_data (&n , &a, &b, &c‬‬

‫;)‪scalar_product = scal_prod (n, a, b‬‬


‫;)‪printf ("The scalar product of a, b is : %lg\n",scalar_product‬‬

‫;)‪scalar_product = scal_prod (n, b, c‬‬


‫;)‪printf ("The scalar product of b, c is : %lg\n",scalar_product‬‬

‫;)‪scalar_product = scal_prod (n, c, a‬‬


‫;)‪printf ("The scalar product of c, a is : %lg\n",scalar_product‬‬
‫}‬
‫)‪void get_data (int *m, double **x, double ** y, double ** z‬‬
‫{‬
‫;‪FILE * fil‬‬
‫;‪int k‬‬
‫;)"‪fil = fopen ("input.dat","r‬‬
‫;)‪fscanf (fil,"%lg", m‬‬

‫;))‪*x = (double *) malloc (sizeof(double) * (*m + 1‬‬


‫;))‪*y = (double *) malloc (sizeof(double) * (*m + 1‬‬
‫;))‪*z = (double *) malloc (sizeof(double) * (*m + 1‬‬
‫)‪for (k=1;k<= *m;k++‬‬
‫{‬
‫;)]‪fscanf(fil,"%lg %lg %lg", &(*x)[k] , &(*y)[k] , &(*z)[k‬‬
‫}‬
‫}‬
‫)‪double scal_prod (int n,double *x, double *y‬‬
‫{‬
‫;‪int k‬‬
‫;‪double prod = 0.0‬‬
‫)‪for (k=1; k<=n; k++‬‬
‫{‬
‫;]‪prod += x[k]*y[k‬‬
‫}‬
‫;)‪return (prod‬‬
‫}‬
‫ﰱ اﳌﺜﺎل اﻟﺴﺎﺑﻖ ﻓﺈن اﳌﺘﻐﲑات ‪ a,b,c,n‬اﳌﻌﺮﻓﺔ ﺑﺪاﺧﻞ ﻧﻄﺎق اﻟﺪاﻟﺔ اﻟﺮﺋﻴﺴــﻴﺔ ﻻ ﺗﻜــﻮن ﻣﻌﺮﻓــﺔ ﺑــﺪاﺧﻞ اﻟــﺪوال اﳌﺴــﺘﺪﻋﺎة ‪get_data‬‬
‫اﻟــﱴ ﺗﻘـﺮأ ﻃــﻮل اﳌﺘﺠﻬــﺎت و ﻗﻴﻤﻬــﺎ ﻣــﻦ ﻣﻠـﻒ‪ ،‬و ﻻ اﻟﺪاﻟــﺔ ‪ scal_prod‬اﻟــﱴ ﲢﺴــﺐ ﺣﺎﺻــﻞ اﻟﻀــﺮب اﻟﻘﻴﺎﺳــﻰ‪ .‬ﺻــﺤﻴﺢ أن ﻋﻨــﺎوﻳﻦ‬
‫ﻫــﺬﻩ اﳌﺘﻐ ـﲑات ﻗــﺪ ﻧﻘﻠــﺖ إﱃ اﻟــﺪوال اﳌﺴــﺘﺪﻋﺎة ﲝﻴــﺚ ﳝﻜــﻦ اﻟﻜﺘﺎﺑــﺔ ﰱ أو اﻟﻘ ـﺮاءة ﻣــﻦ ﻋﻨﺎﺻــﺮ اﳌﺘﺠﻬــﺎت‪ ،‬و ﻟﻜــﻦ اﳌﺘﻐ ـﲑات ذا ــﺎ‬
‫ﻟﻴﺴﺖ ﻣﻌﺮﻓﺔ‪ .‬أى أﻧﻨﺎ ﻻ ﻧﺴﺘﻄﻴﻊ أن ﻧﻀﻊ ﺑﺪاﺧﻞ ﺳﻄﻮر أى ﻣﻦ اﻟﺪاﻟﺘﲔ ﺳﻄﺮا ﳛﻮى اﻟﺮﻣﺰ ]‪ a[2‬ﻣﺜﻼ‪.‬‬
‫ﻻﺣ ــﻆ وﺿ ــﻊ اﻟﻨﺠﻤ ــﺔ ﰱ ﺳ ــﻄﺮ اﻹﻋ ــﻼن ﰱ داﻟ ــﺔ ‪ .get_data‬اﳌﺘﻐ ــﲑ ‪ m‬ﰱ اﻟ ــﱪ ﻣﺞ اﳉﺰﺋ ــﻰ ﳛ ــﻮى ﻋﻨـ ـﻮان اﳌﺘﻐ ــﲑ ‪ n‬ﰱ‬
‫اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ و ﻟــﺬا ﻟــﺰم وﺿــﻊ ﻋﻼﻣــﺔ & ﻗﺒــﻞ ‪ n‬ﰱ ﺳــﻄﺮ اﻻﺳــﺘﺪﻋﺎء و أﻳﻀــﺎ ﻋﻼﻣــﺔ * ﻗﺒــﻞ ‪ m‬ﰱ ﺳــﻄﺮ اﻹﻋــﻼن‪ .‬ﻫــﺬﻩ ﻫــﻰ‬
‫اﻟﻄﺮﻳﻘﺔ اﻟــﱴ ﺳــﺘﻤﻜﻨﻨﺎ ﻣــﻦ إﻋـﺎدة ﻗﻴﻤــﺔ ﻣــﻦ اﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ إﱃ اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ ﻛﻤــﺎ ذﻛــﺮ آﻧﻔــﺎ‪ .‬و ﳌﺜــﻞ‪ ،‬ﺣﻴــﺚ أﻧﻨــﺎ ﺳــﻨﻘﻮم ﲝﺠــﺰ‬
‫أﻣﺎﻛﻦ ﻟﻠﻤﺘﺠﻬﺎت ﺑﺪاﺧﻞ اﻟﺪاﻟﺔ‪ ،‬ﻓﺈﻧﻨﺎ ﳓﺘﺎج ﻹﻋﺎدة ﻋﻨﻮان ﺑﺪاﻳﺔ ﻛــﻞ ﻣﺘﺠــﻪ ﻟﻠــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ‪ .‬أى أﻧﻨــﺎ ﳓﺘــﺎج ﻹﻋــﺎدة ﳏﺘــﻮى ‪a, b,‬‬

‫‪88‬‬
‫ أﻣﺎ ﰱ ﺳﻄﺮ اﻹﻋﻼن ﻓﻜﻤﺎ أﺿﻔﻨﺎ اﻟﻌﻼﻣﺔ * ﻗﺒــﻞ اﳊــﺮف‬.a, b, c ‫ ﳚﺐ وﺿﻊ ﻧﻔﺲ اﻟﻌﻼﻣﺔ ﻗﺒﻞ‬n ‫ ﻓﻜﻤﺎ وﺿﻌﻨﺎ ﻋﻼﻣﺔ & ﻗﺒﻞ‬.c
.‫ و ﺣﻴﺚ أن اﳌﺘﻐﲑ ﻫﻮ أﺻﻼ ﻣﺆﺷﺮ ﻓﻠﺬﻟﻚ ﻇﻬﺮت اﻟﻨﺠﻤﺔ اﳌﺰدوﺟﺔ‬x, y, z ‫ ﻓﻴﺠﺐ إﺿﺎﻓﺔ ﻧﻔﺲ اﻟﻌﻼﻣﺔ ﻗﺒﻞ اﳊﺮوف‬m
‫ و إن ﻛــﺎن ﳚــﺐ‬global variables ‫ﳝﻜــﻦ اﻟﺘﻐﻠــﺐ ﻋﻠــﻰ ﺻــﻌﻮﺑﺔ ﻗـﺮاءة اﻟــﱪ ﻣﺞ اﻟﺴــﺎﺑﻖ ﺳــﺘﺨﺪام اﳌﺘﻐـﲑات اﻟﺸــﺎﻣﻠﺔ‬
‫ و ﻫــﻰ ﻣﻌﺮﻓــﺔ ﺑــﺪاﺧﻞ‬،‫ اﳌﺘﻐـﲑات اﻟﺸــﺎﻣﻠﺔ ﻫــﻰ ﻣﺘﻐـﲑات أﻋﻠــﻦ ﻋﻨﻬــﺎ ﺧــﺎرج ﻧﻄــﺎق أﻳــﺔ داﻟــﺔ‬.‫اﺳــﺘﺨﺪاﻣﻬﺎ داﺋﻤــﺎ ﰱ أﺿــﻴﻖ ﻧﻄــﺎق ﳑﻜــﻦ‬
:‫ ﰱ ﻫﺬﻩ اﳊﺎﻟﺔ ﳝﻜﻦ إﻋﺎدة ﻛﺘﺎﺑﺔ اﻟﱪ ﻣﺞ اﻟﺴﺎﺑﻖ ﻛﻤﺎ ﻳﻠﻰ‬.‫ﲨﻴﻊ اﻟﺪوال اﻟﱴ ﺗﻈﻬﺮ ﺑﻌﺪ اﻟﻨﻘﻄﺔ اﻟﱴ أﻋﻠﻨﺖ ﻓﻴﻬﺎ و إﱃ ﺎﻳﺔ اﳌﻠﻒ‬
#include <stdio.h>
void get_data (int *m);
double scal_prod (int n,double *x, double *y);
double *a, *b, *c;
void main (void)
{
double scalar_product;
int n;
get_data (&n);
scalar_product = scal_prod (n, a, b);
printf ("The scalar product of a, b is : %lg\n",scalar_product);

scalar_product = scal_prod (n, b, c);


printf ("The scalar product of b, c is : %lg\n",scalar_product);

scalar_product = scal_prod (n, c, a);


printf ("The scalar product of c, a is : %lg\n",scalar_product);
}
void get_data (int *m)
{
FILE * fil;
int k;
fil = fopen ("input.dat","r");
fscanf (fil,"%lg", m);
a = (double *) malloc (sizeof(double) * (*m + 1));
b = (double *) malloc (sizeof(double) * (*m + 1));
c = (double *) malloc (sizeof(double) * (*m + 1));
for (k=1;k<= *m;k++)
{
fscanf(fil,"%lg %lg %lg", &a[k] , &b[k] , &c[k]);
}
}
double scal_prod (int n,double *x, double *y)
{
int k; double prod = 0.0;
for (k=1; k<=n; k++)
{
prod += x[k]*y[k];
}
return (prod);
}

89
‫ﺣﻴﺚ ﺗﻘﻮم اﳌﺘﻐـﲑات ‪ a, b. c‬ﺑــﺪور اﳌﺘﻐـﲑات اﻟﺸــﺎﻣﻠﺔ‪ .‬و ﻫــﻰ ﺑــﺬﻟﻚ ﻣﻌﺮﻓــﺔ ﰱ ﻛــﻞ اﻟــﺪوال ﲟــﺎ ﰱ ذﻟــﻚ اﻟﺪاﻟــﺔ ‪ get_data‬و ﻟﺘــﺎﱃ‬
‫ﳝﻜﻦ اﻟﻜﺘﺎﺑﺔ ﻓﻴﻬﺎ أو اﻟﻘﺮاءة ﻣﻨﻬﺎ ﻣﺒﺎﺷﺮة ﺑﺪون اﳊﺎﺟﺔ ﻟﻨﻘﻞ ﻋﻨﻮان ﺑﺪاﻳﺔ اﳌﺘﺠــﻪ‪ ،‬و ﻫــﻮ ﻣــﺎ ﻳــﱪر اﺧﺘﻔــﺎء ذﻛــﺮﻫﻢ ﰱ ﺳــﻄﺮ اﻹﻋــﻼن ﰱ‬
‫ﻫﺬﻩ اﻟﺪاﻟﺔ‪ .‬ﻣﺎذا ﳛﺪث إذا ﻋﺮﻓﻨﺎ ﻣﺘﻐﲑا ﳏﻠﻴﺎ ‪) local variable‬أى ﺑﺪاﺧﻞ داﻟﺔ( و ﻛﺎن اﲰﻪ ﻣﺼﺎدﻓﺔ ﻫﻮ ﻧﻔﺲ اﺳــﻢ ﻣﺘﻐــﲑ ﺷــﺎﻣﻞ‬
‫آﺧــﺮ؟ ﰱ ﻫــﺬﻩ اﳊﺎﻟــﺔ ﻳﻌﺘــﱪ اﳊﺎﺳــﺐ أن ﻫﻨــﺎك ﻣﺘﻐــﲑﻳﻦ ﳐﺘﻠﻔــﲔ ﲝﻴــﺚ ﻳﻜــﻮن أى ﻇﻬــﻮر ﻻﺳــﻢ اﳌﺘﻐــﲑ ﺑــﺪاﺧﻞ اﻟﺪاﻟــﺔ ﻳﻌــﻮد ﻋﻠــﻰ اﳌﺘﻐــﲑ‬
‫اﶈﻠﻰ ﺑﻴﻨﻤﺎ ﻳﻜﻮن أى ﻃﻬﻮر ﻟﺬات اﻻﺳﻢ ﰱ ﲨﻴــﻊ اﻟــﺪوال اﻷﺧــﺮى ﻳﻌــﻮد ﻋﻠــﻰ اﳌﺘﻐــﲑ اﻟﺸــﺎﻣﻞ‪ .‬ﻧﻘــﻮل ﺣﻴﻨﺌــﺬ أن اﳌﺘﻐــﲑ اﶈﻠــﻰ ﳛﺠــﺐ‬
‫‪ supersedes‬اﳌﺘﻐــﲑ اﻟﺸــﺎﻣﻞ‪ .‬ﻟﻠﺘﻮﺿــﻴﺢ‪ ،‬ﻓﻔــﻰ اﳉــﺰء اﻟﺘــﺎﱃ ﻣــﻦ ﺑــﺮ ﻣﺞ‪ ،‬ﻋﺮﻓــﺖ اﳌﺘﻐـﲑات اﻟﺸــﺎﻣﻠﺔ ‪ x, y‬ﰱ ﺑﺪاﻳــﺔ اﻟــﱪ ﻣﺞ‪ .‬اﻟﺪاﻟــﺔ‬
‫‪ my_function‬ﻋﺮﻓﺖ ﻓﻴﻬﺎ ﻣﺘﻐﲑات ﳏﻠﻴﺔ ﳍﺎ ﻧﻔﺲ اﻷﲰﺎء ﻣﺼﺎدﻓﺔ‪:‬‬
‫>‪#include <stdio.h‬‬
‫;‪double x=3, y=4‬‬

‫)‪void my_function(double x‬‬


‫{‬
‫;‪double y=6‬‬
‫;‪x = 5‬‬
‫;)‪printf("%lg %lg",x,y‬‬
‫}‬
‫)‪void main (void‬‬
‫{‬
‫;)‪printf("%lg %lg",x,y‬‬
‫}‬
‫و ﻟﺬﻟﻚ ﻓﺈن أﻣــﺮ اﻟﻜﺘﺎﺑــﺔ ﰱ اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ ﺳــﻴﻜﺘﺐ ﳏﺘــﻮى اﳌﺘﻐـﲑات اﻟﺸــﺎﻣﻠﺔ ‪ x, y‬و ﻫــﻮ ‪ 3, 4‬ﻋﻠــﻰ اﻟﱰﺗﻴــﺐ ﺑﻴﻨﻤــﺎ ﺳــﻴﻄﺒﻊ أﻣــﺮ‬
‫اﻟﻜﺘﺎﺑــﺔ ﺑــﺪاﺧﻞ اﻟﺪاﻟــﺔ ‪ my_function‬ﻗﻴﻤــﺎ أﺧــﺮى ﻫــﻰ ﳏﺘــﻮى اﳌﺘﻐـﲑات اﶈﻠﻴــﺔ )‪ 5,6‬ﻋﻠــﻰ اﻟﱰﺗﻴــﺐ( و اﻟــﱴ ﺗﺼــﺎدف أن ﳍــﺎ ﻧﻔــﺲ‬
‫اﻻﺳــﻢ‪ .‬ﻻﺣــﻆ أن اﻟﻘــﻴﻢ اﻻﺑﺘﺪاﺋﻴــﺔ اﻟــﱴ ﺗﻌﻄــﻰ ﳌﺘﻐــﲑ ﺷــﺎﻣﻞ ﺗﻜﺘــﺐ ﺑــﺪاﺧﻞ اﳌﺘﻐــﲑ اﻟﺸــﺎﻣﻞ ﻗﺒــﻞ ﺗﻨﻔﻴــﺬ أى ﺳــﻄﺮ ﰱ اﻟــﱪ ﻣﺞ‪ ،‬ﺑﻴﻨﻤــﺎ‬
‫ﺗﻜﺘﺐ اﻟﻘﻴﻢ اﻻﺑﺘﺪاﺋﻴﺔ ﰱ اﳌﺘﻐﲑات اﶈﻠﻴﺔ ﻋﻨﺪﻣﺎ ﺗﻨﻔﺬ اﻟﺪاﻟﺔ اﻟﱴ ﲢﻮﻳﻬﺎ‪.‬‬

‫‪.4‬ج‪ .5.‬اﻟﺪوال ذاﺗﻴﺔ اﻻﺳﺘﺪﻋﺎء ‪recursive functions‬‬


‫رأﻳﻨــﺎ ﻛﻴــﻒ أن أﻳــﺔ داﻟــﺔ ﳝﻜــﻦ أن ﺗﺴــﺘﺪﻋﻰ داﻟــﺔ أﺧــﺮى‪ .‬و ﻟﻜــﻦ ﺣﻴﻨﻤــﺎ ﺗﺴــﺘﺪﻋﻰ اﻟﺪاﻟــﺔ ﻧﻔﺴــﻬﺎ ﻓــﺈن اﻟﺪاﻟــﺔ اﳌﺴــﺘﺪﻋﺎة ﻫــﻰ‬
‫ذات اﻟﺪاﻟــﺔ اﻟﺪاﻋﻴــﺔ و ﻟﺘــﺎﱃ ﻓــﺈن اﻟﺪاﻟــﺔ اﳌﺴــﺘﺪﻋﺎة ﺳﺘﺴــﺘﺪﻋﻰ ﻧﻔﺴــﻬﺎ ﻣــﺮة أﺧــﺮى و ﻫﻜــﺬا إﱃ اﻷﺑــﺪ! ﰱ اﳊﻘﻴﻘــﺔ ﻫﻨــﺎك داﺋﻤــﺎ ﺷــﺮط‬
‫ﳚﺐ وﺿﻌﻪ ﺣﱴ ﺗﺘﻮﻗﻒ ﻋﻤﻠﻴﺔ اﻻﺳﺘﺪﻋﺎء اﻟﺬاﺗﻰ‪ .‬ﺗﺸﺒﻪ ﺗﻠﻚ اﻟﻌﻤﻠﻴﺔ وﺿﻊ ﻣﺮآﺗﲔ اﻟﻮاﺣﺪة أﻣﺎم اﻷﺧﺮى ﻓﺘﻜــﻮن اﻟﺼــﻮرة اﳌﺘﻜﻮﻧــﺔ ﰱ‬
‫ﻣــﺮآة ﻣﻨﻬﻤــﺎ ﻫــﻰ اﻧﻌﻜــﺎس ﻟﻠﺼــﻮرة ﰱ اﳌــﺮآة اﻷﺧــﺮى و اﻟــﱴ ﻫــﻰ ﺑــﺪورﻫﺎ اﻧﻌﻜــﺎس ﻟﻠﺼــﻮرة ﰱ اﳌــﺮآة اﻷوﱃ و ﻫﻜــﺬا إﱃ ﻣــﺎ ﻻ ﺎﻳــﺔ‪.‬‬
‫ﺗﺴــﻤﻰ اﻟــﺪوال اﻟــﱴ ﺗﻌﻤــﻞ ــﺬا اﻷﺳــﻠﻮب ﻟــﺪوال ذاﺗﻴــﺔ اﻻﺳــﺘﺪﻋﺎء ‪ .recursive functions‬ﺗﻔﻴــﺪ ﻫــﺬﻩ اﻹﻣﻜﺎﻧﻴــﺔ ﰱ ﺑﻨــﺎء ﺑـﺮاﻣﺞ‬
‫ﺗﻨﻔﺬ ﻋﻤﻠﻴﺎت ﻣﻌﻘﺪة ﺟﺪا ﻋﻦ ﻃﺮﻳﻖ ﻛﺘﺎﺑﺔ ﺧﻄﻮات ﻗﻠﻴﻠﺔ و ﺑﺴﻴﻄﺔ‪ ،‬ﻛﻤﺎ ﺳﻨﺮى ﰱ اﻷﻣﺜﻠﺔ و ﻟﻜــﻦ ﳚــﺐ اﳊــﺬر اﻟﺸــﺪﻳﺪ ﻋﻨــﺪ اﻟﻜﺘﺎﺑــﺔ‬
‫ﺣﱴ ﻻ ﻧﺪﺧﻞ ﰱ دورة ﻻ ﺎﺋﻴﺔ‪ .‬و ﻟﺬﻟﻚ ﻓﻤﻦ ﻏﲑ اﳌﻨﺼﻮح ﺎ ﻟﻠﻤﱪﻣﺞ اﳌﺒﺘﺪئ‪.‬‬
‫ﻫﻨﺎك ﻣﺜﺎل ﻋﻠﻰ اﻟﺪوال ذاﺗﻴﺔ اﻻﺳﺘﺪﻋﺎء ﻳﻈﻬﺮ ﰱ ﲨﻴﻊ ﻛﺘــﺐ اﻟﱪﳎــﺔ ﻛﻤــﺪﺧﻞ ﳍــﺬا اﳌﻮﺿــﻮع ﻟﺸــﺪة ﺑﺴــﺎﻃﺘﻪ و وﺿــﻮﺣﻪ أﻻ‬
‫و ﻫﻮ ﺣﺴﺎب اﳌﻀﺮوب‪ .‬ﻓﺎﻟﺘﻌﺮﻳﻒ اﻟﻜﺎﻣﻞ ﻟﻠﻤﻀﺮوب ﻫﻮ‪:‬‬
‫!‪Definition of factorial n: n‬‬
‫‪for n < 0 : n! is undefined‬‬
‫‪for n = 0‬‬ ‫‪0! = 1‬‬
‫‪for n > 0‬‬ ‫! )‪n! = n * (n-1‬‬

‫‪90‬‬
‫ﻻﺣــﻆ أن ﰱ اﻟﺴــﻄﺮ اﻷﺧــﲑ ﻣــﻦ اﻟﺘﻌﺮﻳــﻒ اﺳــﺘﺨﺪم ﻣﻀــﺮوب رﻗــﻢ ﻣــﺎ ﰱ ﺗﻌﺮﻳــﻒ ﻣﻀــﺮوب رﻗــﻢ آﺧــﺮ و ﻫــﻮ ﻣــﺎ ﳝﻜــﻦ أن ﻧﺴــﻤﻴﻪ إذن‬
‫ﺗﻌﺮﻳــﻒ ذاﺗــﻰ اﻻﺳــﺘﺪﻋﺎء‪ ،‬و ﻟﺘــﺎﱃ ﻣــﻦ اﻟﻄﺒﻴﻌــﻰ أن ﻧﱪﳎــﻪ ﺳــﺘﺨﺪام داﻟــﺔ ذاﺗﻴــﺔ اﻻﺳــﺘﺪﻋﺎء‪ .‬اﳉﻤﻴــﻞ ﰱ اﻟــﺪوال ذاﺗﻴــﺔ اﻻﺳــﺘﺪﻋﺎء أن‬
‫اﻟﱪﳎﺔ ﻻ ﺗﻌﺪو ﻋﻦ ﻛﻮ ﺎ ﻛﺘﺎﺑﺔ ﻟﻠﺘﻌﺮﻳﻒ ﻛﻤﺎ ﻫﻮ ﺑﻜﻞ ﺑﺴﺎﻃﺔ!‬
‫>‪#include <stdio.h‬‬
‫>‪#include <process.h‬‬

‫)‪double fact (double n‬‬


‫{‬
‫)‪if (n < 0‬‬
‫{‬
‫;)‪printf ("Factorial is undefined\n"); exit(5‬‬
‫}‬
‫)‪if (n == 0.0‬‬
‫{‬
‫;)‪return(1.0‬‬
‫}‬
‫;))‪return (n*fact(n-1‬‬
‫}‬
‫)‪void main(void‬‬
‫{‬
‫;‪double k‬‬
‫;)" ‪printf("Program to calculate factorial, enter number:‬‬
‫;)‪scanf("%lg",&k‬‬
‫;))‪printf("Factorial of %3.0f is %10.0f\n",k,fact(k‬‬
‫}‬
‫وﺿــﻌﻨﺎ اﻷرﻗــﺎم اﻟــﱴ ﻧﺘﻌﺎﻣــﻞ ﻣﻌﻬــﺎ ﰱ ﺻــﻮرة أﻋــﺪاد ﻛﺴـﺮﻳﺔ و ﻟــﻴﺲ ﺻــﺤﻴﺤﺔ ﻷن اﳌﻀــﺮوب ﺗﺼــﻞ ﻗﻴﻤﺘــﻪ ﺣــﺪا ﻛﺒـﲑا ﻻ ﳝﻜــﻦ ﲣﺰﻳﻨــﻪ ﰱ‬
‫ﻣﺘﻐﲑ ﻣﻦ ﻧﻮع ﺻﺤﻴﺢ‪ .‬ﻻﺣﻆ ﻛﻴــﻒ ﻛﺘﺒﻨــﺎ داﻟــﺔ اﳌﻀــﺮوب‪ :‬ﱂ ﻧﻔﻌــﻞ أﻛﺜــﺮ أو اﻗــﻞ ﻣــﻦ إﻋــﺎدة ﻛﺘﺎﺑــﺔ اﻟﺘﻌﺮﻳــﻒ‪ ،‬ﱂ ﻧﻔﻜــﺮ ﰱ ﻛﻴﻔﻴــﺔ ﲢﻮﻳــﻞ‬
‫اﻟﻌﻤﻠﻴﺔ اﳌﻄﻠﻮﺑﺔ ﻟﻌﻤﻠﻴﺔ ﺗﻜﺮارﻳﺔ و ﱂ ﻧﻌﺮف ﺣﺼﺎﻟﺔ أو ﻋﺪاد أو أى ﺷﺊ آﺧﺮ ﻣﻦ اﳊﻴﻞ اﻟﱪﳎﻴﺔ اﳌﻌﺮوﻓﺔ‪ ،‬ﻓﻘﻂ ﻛﺘﺒﻨﺎ اﻟﺘﻌﺮﻳﻒ!‬
‫ﻛﻴــﻒ ﻳــﺘﻢ ﺗﻨﻔﻴــﺬ اﻟــﱪ ﻣﺞ ﻋﺎﻟﻴــﻪ؟ ﻧﻔــﺮض أﻧﻨــﺎ ﺑﺼــﺪد ﺣﺴــﺎب ﻣﻀــﺮوب ‪ .3‬ﺣﻴﻨﻤــﺎ ﻧﺴــﺘﺪﻋﻰ اﻟﺪاﻟــﺔ ‪ fact‬ﻷول ﻣــﺮة ﻓﺈ ــﺎ‬
‫ﲣﻠــﻖ ﺧﺎﻧــﺔ ذاﻛــﺮة ﺟﺪﻳــﺪة اﲰﻬــﺎ ‪ n‬ﺗﻨﻘــﻞ إﻟﻴﻬــﺎ ﳏﺘــﻮ ت ﺧﺎﻧــﺔ اﻟــﺬاﻛﺮة اﳌﻮﺟــﻮدة ﰱ اﻟــﱪ ﻣﺞ اﻟــﺪاﻋﻰ‪ ،‬أى ﳏﺘــﻮ ت ‪ k‬و ﻫــﻰ ﰱ ﻫــﺬﻩ‬
‫اﻟﻠﺤﻈــﺔ ‪ .3‬ﰒ ﺗﺸــﺮع ﰱ ﺗﻨﻔﻴ ــﺬ ﻧﻔﺴــﻬﺎ‪ .‬ﺑﻌ ــﺪ اﳌ ــﺮور ﻋﻠــﻰ اﻟﺸ ــﺮﻃﲔ ﺑﺴــﻼم‪ ،‬ﻧﺼــﻞ ﻟﻸﻣ ــﺮ ‪ .return‬ﰱ ﻫ ــﺬا اﻷﻣــﺮ ﺳ ــﻨﻌﻴﺪ ﻟﻠ ــﱪ ﻣﺞ‬
‫اﻟﺪاﻋﻰ )و اﻟﺬى ﻫــﻮ اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ ﰱ ﻫــﺬﻩ اﻟﻠﺤﻈــﺔ( ﻧﺘﻴﺠــﺔ ﺣﺴــﺎب ﻣــﺎ ﺑــﺪاﺧﻞ اﻷﻗـﻮاس‪ .‬و ﻟﻜــﻦ ﳚــﺐ أوﻻ ﺣﺴــﺎب ﻣــﺎ ﺑــﺪاﺧﻞ‬
‫اﻷﻗﻮاس‪ .‬إﻧﻪ ﺑﺒﺴﺎﻃﺔ ﺣﺎﺻﻞ ﺿﺮب اﻟﻌﺪد ‪ n‬ﰱ داﻟﺔ ﻣﺎ‪ .‬ﳚﺐ إذن أن ﻧﺒﺪأ ﲝﺴﺎب ﻫــﺬﻩ اﻟﺪاﻟــﺔ‪ .‬ﻛــﻮن ﻫــﺬﻩ اﻟﺪاﻟــﺔ ﻫــﻰ ﻧﻔﺴــﻬﺎ داﻟﺘﻨــﺎ‬
‫اﻷﺻﻠﻴﺔ ﻻ ﻳﻐﲑ ﻣﻦ اﻷﻣﺮ ﺷﻴﺌﺎ‪.‬‬

‫‪91‬‬
‫ذاﻛﺮة اﻟﺒﺮﻧﺎﻣﺞ‬ ‫ذاﻛﺮة اﻟﺪاﻟﺔ‬ ‫ذاﻛﺮة اﻟﺪاﻟﺔ‬
‫اﻟﺮﺋﯿﺴﻰ‬ ‫اﺳﺘﺪﻋﺎء‬ ‫)أول اﺳﺘﺪﻋﺎء(‬ ‫اﺳﺘﺪﻋﺎء‬ ‫)ﺛﺎﻧﻰ اﺳﺘﺪﻋﺎء(‬ ‫اﺳﺘﺪﻋﺎء‬
‫ﺑﻘﯿﻤﺔ ‪3‬‬ ‫ﺑﻘﯿﻤﺔ ‪2‬‬ ‫ﺑﻘﯿﻤﺔ ‪1‬‬
‫اﻷواﻣﺮ‬ ‫اﻷواﻣﺮ‬ ‫اﻷواﻣﺮ‬

‫‪6‬‬ ‫اﻟﻘﯿﻤﺔ‬ ‫‪2‬‬ ‫اﻟﻘﯿﻤﺔ‬ ‫‪1‬‬


‫اﻟﻤﺘﻐﯿﺮات‬ ‫اﻟﻤﺘﻐﯿﺮات‬ ‫اﻟﻤﺘﻐﯿﺮات‬
‫اﻟﻌﺎﺋﺪة‬ ‫اﻟﻌﺎﺋﺪة‬
‫‪k‬‬ ‫‪n‬‬ ‫‪n‬‬
‫‪3‬‬ ‫‪3‬‬ ‫‪2‬‬

‫ذاﻛﺮة اﻟﺪاﻟﺔ‬ ‫ذاﻛﺮة اﻟﺪاﻟﺔ‬


‫)راﺑﻊ اﺳﺘﺪﻋﺎء(‬ ‫اﺳﺘﺪﻋﺎء‬ ‫)ﺛﺎﻟﺚ اﺳﺘﺪﻋﺎء(‬
‫ﺑﻘﯿﻤﺔ ‪0‬‬
‫اﻷواﻣﺮ‬ ‫اﻷواﻣﺮ‬

‫اﻟﻤﺘﻐﯿﺮات‬ ‫اﻟﻘﯿﻤﺔ‬ ‫‪1‬‬ ‫اﻟﻘﯿﻤﺔ اﻟﻤﺘﻐﯿﺮات‬


‫اﻟﻌﺎﺋﺪة‬ ‫اﻟﻌﺎﺋﺪة‬
‫‪n‬‬ ‫‪n‬‬
‫‪0‬‬ ‫‪1‬‬

‫ﺧﻄﻮات ﺗﻨﻔﺒﺬ اﻟﺪاﻟﺔ ذاﺗﺒﺔ اﻻﺳﺘﺪﻋﺎء ﳊﺴﺎب اﳌﻀﺮوب‬

‫ﳓــﻦ اﻵن ﺑﺼــﺪد اﺳــﺘﺪﻋﺎء داﻟــﺔ اﳌﻀــﺮوب ﻣــﺮة أﺧــﺮى‪ ،‬و ﻟﺘــﺎﱃ ﺳــﻴﺘﻜﺮر ﻣــﺎ ﺳــﺒﻖ‪ :‬ﲣﻠــﻖ اﻟﺪاﻟــﺔ أوﻻ ﺧﺎﻧــﺔ ذاﻛــﺮة ﺟﺪﻳــﺪة‬
‫ﺗﺴﻤﻴﻬﺎ ‪ ) n‬ﻟﺮﻏﻢ ﻣﻦ ﺗﺸﺎﺑﻪ اﻷﲰﺎء إﻻ أ ــﺎ ﻟــﻴﺲ ﳍــﺎ أى ﻋﻼﻗــﺔ ﲞﺎﻧــﺔ اﻟــﺬاﻛﺮة اﻟــﱴ ﺧﻠﻘــﺖ أول ﻣــﺮة ﺑﻮاﺳــﻄﺔ اﻻﺳــﺘﺪﻋﺎء اﻷول ﻟﺪاﻟــﺔ‬
‫اﳌﻀﺮوب(‪ .‬ﰒ ﻧﻨﻘــﻞ ﳍــﺬﻩ اﳋﺎﻧــﺔ ﳏﺘــﻮ ت ﺗــﻰ ﻣــﻦ ﻗﺒــﻞ اﻟــﱪ ﻣﺞ اﻟــﺪاﻋﻰ ﻫــﺬﻩ اﶈﺘــﻮ ت ﻫــﻰ ﻋﺒــﺎرة ﻋــﻦ ﻗﻴﻤــﺔ ‪ n‬ﰱ اﻟــﱪ ﻣﺞ اﻟــﺪاﻋﻰ‬
‫)أى ‪ (3‬ﻣﻄﺮوﺣــﺎ ﻣﻨﻬــﺎ ‪ .1‬ﺗﺼــﺒﺢ ﻗﻴﻤــﺔ ‪ n‬ﰱ اﻟــﱪ ﻣﺞ اﳌﺴــﺘﺪﻋﻰ إذن ‪ .2‬و ﻧﻜــﺮر ﻣــﺎ ﺳــﺒﻖ ﺣــﱴ ﻧﺼــﻞ ﻟﻠﺴــﻄﺮ اﻷﺧــﲑ‪ .‬ﺣﻴﻨﺌــﺬ ﳒــﺪ‬
‫أﻧﻨ ــﺎ ﻻ ﻧﺴ ــﺘﻄﻴﻊ أن ﻧﻜﻤ ــﻞ اﳊﺴ ــﺎب ﺣ ــﱴ ﳓﺴ ــﺐ ﻣﻀ ــﺮوب ‪ 2-1‬أوﻻ و ﻫﻜ ــﺬا إﱃ أن ﻧﺼ ــﻞ ﳌﻀ ــﺮوب ‪ .0‬إن أول ﻣﻀ ــﺮوب ﻳ ــﺘﻢ‬
‫ﺣﺴﺎﺑﻪ ﻓﻌﻼ ﻫﻮ ﻣﻀﺮوب اﻟﺼــﻔﺮ و ﻫــﻮ ﻳﺴــﺎوى واﺣــﺪ ﻛﻤــﺎ ﻳﻨﺒﺌﻨــﺎ اﻟﺸــﺮط اﻟﺜــﺎﱏ ﰱ ﺟﺴــﻢ داﻟــﺔ اﳌﻀــﺮوب‪ .‬ﺣــﲔ ﳓﺴــﺒﻪ ﻧﻌــﻮد ﻟﻠــﱪ ﻣﺞ‬
‫اﻟﺪاﻋﻰ و اﻟﺬى ﻛﺎن ﻳﺮﻳﺪ ﺣﺴﺎب ﻣﻀﺮوب واﺣﺪ‪ :‬ﻓﻴﺠﺪ أﻧﻪ )‪ 1 * fact(0‬أى ﺑﺒﺴــﺎﻃﺔ واﺣــﺪ أﻳﻀــﺎ‪ .‬ﰒ ﻧﻌﻴــﺪ ﻫــﺬﻩ اﻟﻘﻴﻤــﺔ ﻟﻠــﱪ ﻣﺞ‬
‫اﻟﺪاﻋﻰ و اﻟﺬى ﻛﺎن ﻳﺮﻳﺪ ﺣﺴﺎب ﻣﻀــﺮوب ‪ 2‬ﻓﻴﺠــﺪ أﻧــﻪ ﻳﺴــﺎوى‪ 2 * fact(1) :‬أى أن اﻟﻨــﺎﺗﺞ ﻫــﻮ ‪ .2‬و ﻧﻌﻴــﺪ اﻟﻨــﺎﺗﺞ إﱃ اﻟــﱪ ﻣﺞ‬
‫اﻟﺪاﻋﻰ و ﻫﻮ ﻣــﺎ ﻛــﺎن ﻳﺮﻳــﺪ ﺣﺴــﺎب ﻣﻀــﺮوب ‪ 3‬ﻓﻴﺠــﺪﻩ ﻣﺴــﺎو ﻟﻠﻘﻴﻤــﺔ‪ 3 * fact(2) :‬و ﰱ اﻟﻨﻬﺎﻳــﺔ ﻧﻌــﻮد ﻟﻘﻴﻤــﺔ اﻟﻨﺎﲡــﺔ و ﻫــﻰ ‪6‬‬
‫ﻟﻠﱪ ﻣﺞ اﻟﺮﺋﻴﺴﻰ اﻟﺬى ﻳﻄﺒﻌﻬﺎ‪ .‬ﻛﻞ ﻫﺬا ﺗﻰ ﻣﻦ داﻟﺔ ﺑﺴﻴﻄﺔ ﻛﺘﺒﺖ ﰱ ﺳﻄﺮﻳﻦ؟ ﻟﻠﻌﺠﺐ!‬
‫ﳝﻜﻦ داﺋﻤﺎ ﻛﺘﺎﺑﺔ ﻋﻤﻠﻴﺔ ﺗﻜﺮارﻳﺔ ﲢﻞ ﳏــﻞ داﻟــﺔ ذاﺗﻴــﺔ اﻻﺳــﺘﺪﻋﺎء و ﻟﻜــﻦ ﰱ اﳌﺴــﺎﺋﻞ اﳌﻌﻘــﺪة ﺗﺼــﺒﺢ اﻟﺪاﻟــﺔ ذاﺗﻴــﺔ اﻻﺳــﺘﺪﻋﺎء‬
‫اﺑﺴﻂ ﺑﻜﺜﲑ ﰱ اﻟﻜﺘﺎﺑﺔ‪ ،‬و إن ﻛﺎﻧﺖ ﻟﻀﺮورة أﻗــﻞ ﻛﻔــﺎءة ﰱ اﻷداء‪ .‬ﻳﺮﺟــﻊ ذﻟــﻚ ﻟﻠﺤﺎﺟــﺔ ﻟﺘﺨـﺰﻳﻦ ﻋــﺪد ﻛﺒــﲑ ﻣــﻦ أﻣــﺎﻛﻦ اﻟــﺬاﻛﺮة ﻣــﻊ‬
‫ﻧﻘــﻞ اﳌﻌﻠﻮﻣــﺎت ﻣــﻦ ﺧــﺎ ت ﻷﺧــﺮى ﻋــﺪد ﻣــﻦ اﳌـﺮات ﻏﺎﻟﺒــﺎ ﻣــﺎ ﻳﺰﻳــﺪ ﻋــﻦ ﻋــﺪد اﳌـﺮات اﳌﻄﻠﻮﺑــﺔ ﰱ ﺣﺎﻟــﺔ اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ‪ .‬ﻫﻨــﺎك ﻣﺜــﺎل‬
‫آﺧﺮ و ﻫﻮ ﺣﺴﺎب اﻟﻘﺎﺳﻢ اﳌﺸﱰك اﻷﻋﻈﻢ ﺑﲔ ﻋــﺪدﻳﻦ ﺻــﺤﻴﺤﲔ‪ .‬ﰱ ﻫــﺬﻩ اﳊﺎﻟــﺔ أﻳﻀــﺎ ﻳﻨﺒــﻊ اﻟــﱪ ﻣﺞ اﻟــﺬى ﻳﺴــﺘﺨﺪم اﻟــﺪوال ذاﺗﻴــﺔ‬

‫‪92‬‬
‫اﻻﺳﺘﺪﻋﺎء ﻣﺒﺎﺷﺮة ﻣﻦ اﻟﺘﻌﺮﻳﻒ ﺑﻴﻨﻤﺎ ﲢﻮﻳﻞ اﻟــﱪ ﻣﺞ ﻟﻌﻤﻠﻴــﺔ ﺗﻜﺮارﻳــﺔ ﻻ ﺗﺴــﺘﺨﺪم اﻟــﺪوال ذاﺗﻴــﺔ اﻻﺳــﺘﺪﻋﺎء ﻫــﻮ ﻋﻤﻠﻴــﺔ ﻣﻌﻘــﺪة‪ .‬ﺗﻌﺮﻳــﻒ‬
‫اﻷﳉﻮرﻳﺘﻢ ﻫﻮ‪:‬‬
‫‪Algorithm for the Greatest Common Divisor GCD of 2 numbers N,M:‬‬
‫)‪If (N < M‬‬ ‫)‪Then GCD (N,M) is the same as GCD(M,N‬‬
‫)‪If (M divides N‬‬ ‫‪Then GCD (N,M) is simply M‬‬
‫)‪Else GCD (N, M) is the same as GCD (M, remainder of N/M‬‬
‫وﺑﻨﺎء ﻋﻠﻴﻪ ﻓﺈن اﻟﱪ ﻣﺞ ﻫﻮ‪:‬‬
‫>‪#include <stdio.h‬‬
‫)‪int GCD (int n, int m‬‬
‫;‪{ int k‬‬
‫;))‪if (n < m) return (GCD(m,n‬‬
‫;‪k = n % m‬‬
‫)‪if (k==0‬‬
‫;)‪return (m‬‬
‫‪else‬‬
‫))‪return(GCD(m,k‬‬
‫}‬
‫)‪void main (void‬‬
‫{‬
‫;‪int N,M,G‬‬
‫;)"‪printf("Program to get Greatest Common Divisor; enter N, M:‬‬
‫;)‪scanf("%lg %lg",&N,&M‬‬
‫;)‪G = GCD(N,M‬‬
‫;)‪printf("The greatest common divisor is %d",G‬‬
‫}‬
‫ﻧــﺪﻋﻮ اﻟﻘــﺎرئ ﻟﻜــﻰ ﻳﻜﺘــﺐ أﻣــﺮ ﻃﺒﺎﻋــﺔ ﺑــﺪاﺧﻞ داﻟــﺔ ‪ GCD‬ﻛﻤــﺎ ﻫــﻮ ﻣﻮﺿــﺢ ﰱ اﻟﺘﻌﻠﻴــﻖ‪ ،‬ﻟﻜــﻰ ﻳﻔﻬــﻢ ﻛﻴــﻒ ﺗﻌﻤــﻞ ﻫــﺬﻩ اﻟﺪاﻟــﺔ‪ .‬إذا‬
‫أدﺧﻠﻨﺎ اﻟﻘﻴﻢ ‪ 6, 15‬ﻋﻠﻰ اﻟﱰﺗﻴﺐ ﻣﻊ ﺗﻨﺸﻴﻂ أﻣﺮ اﻟﻄﺒﺎﻋﺔ‪ ،‬ﻓﺴﻨﻘﺮأ‪:‬‬
‫‪Program to get the Greatest Common Divisor, Enter N,M: 6 15‬‬
‫‪Calculating GCD of 6 15‬‬
‫‪Calculating GCD of 15 6‬‬
‫‪Calculating GCD of 6 3‬‬
‫‪The Greatest Common Divisor is 3‬‬
‫ﻫﻨــﺎك ﺗﻄﺒﻴــﻖ أﺧــﲑ ﻳﻮﺿــﺢ ﲜــﻼء ﻛﻴــﻒ ﳝﻜــﻦ ﺑﺴــﻬﻮﻟﺔ ﻛﺘﺎﺑــﺔ داﻟــﺔ ذاﺗﻴــﺔ اﻻﺳــﺘﺪﻋﺎء ﰱ ﺑﻌــﺾ اﳊــﺎﻻت ﺑﻴﻨﻤــﺎ ﺗﻜــﻮن اﻟﻌﻤﻠﻴــﺔ‬
‫اﻟﺘﻜﺮارﻳــﺔ اﳌﻨــﺎﻇﺮة ﺻــﻌﺒﺔ ﻟﻠﻐﺎﻳــﺔ‪ .‬ﲣﻴــﻞ أن ﻟــﺪﻳﻨﺎ ﺟﺴــﻤﺎ ﻣﺴــﺘﻮ ﻣﻜــﻮ ﻣــﻦ أﻣــﺎﻛﻦ ﻣﻮﺻــﻠﺔ ﻟﻠﺤ ـﺮارة و أﺧــﺮى ﻋﺎزﻟــﺔ‪ .‬ﳝﻜــﻦ أن ﻧﻘﺴــﻢ‬
‫ﺳــﻄﺢ اﳉﺴــﻢ ﻣــﺜﻼ ﳌﺮﺑﻌــﺎت ﺻــﻐﲑة ﲝﻴــﺚ ﺗﻜــﻮن اﳌــﺎدة اﳌﻜﻮﻧــﺔ ﻟﻜــﻞ ﻣﺮﺑــﻊ ﻣﺘﺠﺎﻧﺴــﺔ‪ .‬و ﺑــﺬﻟﻚ ﳝﻜــﻦ وﺻــﻒ أى ﺷــﻜﻞ ﰱ ﺻــﻮرة‬
‫ﻣﺼﻔﻮﻓﺔ ‪ A‬ﻣﻦ ‪ N‬ﺻﻒ و ‪ M‬ﻋﻤﻮد و ﻣﻦ ﻧﻮع ‪ char‬ﺣﻴﺚ ﻗﻴﻤﺔ أى ﻋﻨﺼﺮ ﳝﻜﻦ أن ﺗﻜﻮن‪:‬‬
‫‪A[j][k] = 0‬‬ ‫‪means The square at j,k is inexistant‬‬
‫‪A[j][k] = 1‬‬ ‫‪means The square at j,k is insulating materiel‬‬
‫‪A[j][k] = 2‬‬ ‫‪means The square at j,k is conducting material‬‬
‫ﰒ ﻫــﺐ أﻧﻨــﺎ وﺿــﻌﻨﺎ ﻣﺼــﺪرا ﺣ ـﺮار ﰱ ﻧﻘﻄــﺔ ﻣــﺎ إﺣــﺪاﺛﻴﺎ ﺎ ‪ J,K‬ﻓﻤــﺎ ﻫــﻰ ﲨﻴــﻊ اﻟﻨﻘــﺎط اﻷﺧــﺮى اﻟــﱴ ﺳــﺘﺘﺄﺛﺮ ــﺬا اﳌﺼــﺪر؟ اﻹﺟﺎﺑــﺔ‬
‫ﺑﺴﻴﻄﺔ‪ :‬ﻛﻞ ﻧﻘﻄﺔ ﺳﺘﺆﺛﺮ ﻋﻠﻰ ﲨﻴﻊ اﻟﻨﻘﺎط اﺠﻤﻟﺎورة )ﳝﻴﻨﺎ و ﻳﺴﺎرا و أﻋﻠﻰ و أﺳﻔﻞ( ﻃﺎﳌﺎ ﻛﺎﻧﺖ اﻟﻨﻘﻄــﺔ ﻣﻮﺟــﻮدة و ﻣﻮﺻــﻠﺔ‪ .‬و اﳉـﻮار‬
‫ﺳﻴﺆﺛﺮ ﰱ اﳉﻮار و ﻫﻜﺬا‪ .‬ﻫﺬا اﻟﺘﻌﺮﻳﻒ ﺑﻄﺒﻴﻌﺘﻪ ذاﺗﻰ اﻻﺳﺘﺪﻋﺎء‪ ،‬و ﻟﺘﺎﱃ ﳝﻜﻦ أن ﻧﻜﺘﺐ اﻟﱪ ﻣﺞ اﳌﻨﺎﻇﺮ ﺑﻜــﻞ ﺑﺴــﺎﻃﺔ ﺳــﺘﺨﺪام‬
‫اﻟﺪوال ذاﺗﻴﺔ اﻻﺳﺘﺪﻋﺎء‪ .‬ﺳﻨﻀﻴﻒ اﻟﻌﺪد ‪ 10‬ﻋﻠﻰ ﻛﻞ ﻧﻘﻄﺔ ﺗﺘﺄﺛﺮ ﳌﺼﺪر ﻟﻨﻌﱪ ﻋﻦ ﺛﺮﻫﺎ‪ .‬اﻟﺪاﻟﺔ اﳌﻄﻠﻮﺑﺔ ﺗﻜﺘﺐ ﻋﻠﻰ اﻟﺼﻮرة‪:‬‬

‫‪93‬‬
‫)‪void influence(int J, int K‬‬
‫{‬
‫))‪if ((J < 1) || (J > N) || (K < 1) || (k > M‬‬
‫;‪return‬‬ ‫‪/* disregard nodes outside the borders */‬‬
‫) )‪if ( (A[J][K] == 0) || (A[J][K] == 1) || (A[J][K] >=10‬‬
‫‪return; /*skip nodes that are inexistant, insulating, or already seen */‬‬
‫;‪A[j][k] += 10‬‬
‫;)‪influence(J+1,K); influence (J-1,K‬‬
‫;)‪influence(J,K+1); influence (J,K-1‬‬
‫}‬
‫ﻧﺪﻋﻮ اﻟﻘﺎرئ ﻟﺘﺨﻴﻞ ﻛﻴﻔﻴﺔ ﻛﺘﺎﺑﺔ ﻧﻔﺲ اﻟﺪاﻟﺔ و ﻟﻜﻦ ﻟــﻴﺲ ﺑﺼــﻮرة ذاﺗﻴــﺔ اﻻﺳــﺘﺪﻋﺎء‪ ،‬ﻟﻴﻜﺘﺸــﻒ ﺑﻨﻔﺴــﻪ اﻟﻔــﺎرق ﺑــﲔ اﻟﺴــﻬﻮﻟﺔ اﻟــﱴ ﻛﺘﺒﻨــﺎ‬
‫ﺎ اﻟﺪاﻟﺔ أﻋﻼﻩ و اﻟﺼﻌﻮﺑﺔ اﳌﻄﻠﻮﺑﺔ ﻟﻜﺘﺎﺑﺔ اﻟﺪاﻟﺔ ﻏﲑ ذاﺗﻴﺔ اﻻﺳﺘﺪﻋﺎء‪.‬‬
‫ﻫﻨﺎك ﻣﻠﺤﻮﻇﺔ أﺧﺮى ﻫﺎﻣﺔ ﺣﻮل ﻣﻜﺎن اﺳﺘﺪﻋﺎء اﻟﺪوال ذاﺗﻴﺔ اﻻﺳﺘﺪﻋﺎء‪ .‬إن اﻟﺪاﻟﺔ ذاﺗﻴﺔ اﻻﺳــﺘﺪﻋﺎء ﲢــﻮى ﻋﻤﻠﻴــﺎت ﻛﻤــﺎ‬
‫ﲢﻮى اﺳﺘﺪﻋﺎء ﻟﻨﻔﺴــﻬﺎ ﲢــﺖ ﺷــﺮط‪ .‬إذا ﻛﺎﻧــﺖ اﻟﻌﻤﻠﻴــﺎت ﻛﻠﻬــﺎ ﺗــﺘﻢ ﻗﺒــﻞ اﺳــﺘﺪﻋﺎء ﻧﻔﺴــﻬﺎ‪ ،‬ﻓــﺈن اﻟﻌﻤﻠﻴــﺎت ﲡــﺮى ﺑﱰﺗﻴــﺐ ﳜﺘﻠــﻒ ﲤﺎﻣــﺎ‬
‫ﻋــﻦ اﻟﱰﺗﻴــﺐ اﻟــﺬى ﺳــﺘﺘﻢ ﻓﻴــﻪ ﻟــﻮ ﻛﺎﻧــﺖ اﻟﻌﻤﻠﻴــﺎت ﺗﻠــﻰ اﻻﺳــﺘﺪﻋﺎء و اﳌﺜــﺎل اﻟﺘــﺎﱃ ﻳﻮﺿــﺢ اﻟﻔــﺎرق ﻣــﻊ ﻛﺘﺎﺑــﺔ اﻟﻨــﺎﺗﺞ ﰱ ﺣﺎﻟــﺔ اﺳــﺘﺪﻋﺎء‬
‫اﻟﺪاﻟﺔ ‪ func1‬أو ‪ func2‬ﺑﻘﻴﻤﺔ ‪ n‬ﺗﺴﺎوى ‪ 4‬ﰱ اﳊﺎﻟﺘﲔ‪.‬‬
‫)‪void func1(int n‬‬
‫{‬
‫;… ;)‪printf("Processing n=%d",n‬‬
‫;‪if (n==0) return‬‬
‫;)‪func(n-1‬‬
‫}‬
‫‪Processing n = 4‬‬
‫‪Processing n = 3‬‬
‫‪Processing n = 2‬‬
‫‪Processing n = 1‬‬
‫‪Processing n = 0‬‬

‫)‪void func(int n‬‬


‫{‬
‫;‪if (n==0) return‬‬
‫;)‪func(n-1‬‬
‫;… ;)‪printf("Processing n=%d",n‬‬
‫}‬
‫‪Processing n = 1‬‬
‫‪Processing n = 2‬‬
‫‪Processing n = 3‬‬
‫‪Processing n = 4‬‬

‫‪.4‬ج‪ .6.‬ﲤﺮﻳﺮ اﻟﺪوال ﻛﻤﺪﺧﻼت ﻟﺪوال أﺧﺮى ‪Functions as arguments to‬‬


‫‪other functions‬‬
‫ﻫﺐ أﻧﻨﺎ ﻧﺮﻳﺪ أن ﻧﻜﺘﺐ داﻟﺔ ‪ Integrate‬ﲢﺴﺐ ﺗﻜﺎﻣــﻞ أﻳــﺔ داﻟــﺔ أﺧــﺮى )‪ .f(x‬ﺣﻴــﺚ أن اﻟﺪاﻟــﺔ اﳌـﺮاد ﺗﻜﺎﻣﻠﻬــﺎ ﻗــﺪ ﺗﺘﻐــﲑ‬
‫ﻣﻦ ﺣﺎﻟﺔ ﻷﺧــﺮى ﻓــﺈن داﻟــﺔ اﻟﺘﻜﺎﻣــﻞ ‪ Integrate‬ﳚــﺐ أن ﻳﻜــﻮن ﻣــﻦ ﺿــﻤﻦ ﻣــﺪﺧﻼ ﺎ وﺻــﻒ ﻟﻠﺪاﻟــﺔ اﳌـﺮاد ﺗﻜﺎﻣﻠﻬــﺎ‪ .‬ﻛﻴــﻒ ﺳــﻨﻌﻄﻰ‬
‫ﻫــﺬا اﻟﻮﺻــﻒ؟ ﻟﻺﺟﺎﺑــﺔ ﻋﻠــﻰ ﻫــﺬا اﻟﺴـﺆال‪ ،‬ﳚــﺐ أن ﻧﻌــﺮف ﻛﻴــﻒ ﻳﺘﻌﺎﻣــﻞ اﳊﺎﺳــﺐ ﻣــﻊ اﻟــﺪوال‪ .‬ﺣﻴﻨﻤــﺎ ﻳــﱰﺟﻢ اﳊﺎﺳــﺐ أﻳــﺔ داﻟــﺔ ﻣــﻦ‬

‫‪94‬‬
‫اﻟﺪوال اﳌﻜﻮﻧﺔ ﻟﱪ ﻣﺞ ﻣﺎ‪ ،‬ﻓﺈﻧﻪ ﻳﻀﻊ ﻧﺘﻴﺠﺔ اﻟﱰﲨﺔ ﰱ ﻣﻜــﺎن ﻣــﺎ ﰱ اﻟــﺬاﻛﺮة‪ .‬ﻋﻨـﻮان ﺑﺪاﻳــﺔ ﻫــﺬﻩ اﻟﻜﺘﻠــﺔ ﻣــﻦ اﳌﻌﻠﻮﻣــﺎت ﳚــﺐ أن ﳜﺘــﺰن‬
‫ﰱ ﻣﻜﺎن ﻣﺎ ﺣﱴ ﳝﻜﻦ اﻟﺮﺟﻮع إﻟﻴﻬﺎ ﺑﺴــﻬﻮﻟﺔ ﺣــﲔ اﺳــﺘﺪﻋﺎﺋﻬﺎ‪ .‬و ﻟــﺬﻟﻚ ﻳﻘــﻮم اﳊﺎﺳــﺐ ﺑﻮﺿــﻊ ﻫــﺬا اﻟﻌﻨـﻮان ﰱ ﻣﺘﻐــﲑ ﻫــﻮ ﻧﻔﺴــﻪ اﺳــﻢ‬
‫اﻟﺪاﻟــﺔ‪ .‬أى أن اﺳــﻢ اﻟﺪاﻟــﺔ ﲢــﻮل إﱃ ﻣﺘﻐــﲑ ﻣــﻦ ﻧــﻮع ﻣﺆﺷــﺮ ﳛــﻮى ﻋﻨ ـﻮان ﺑﺪاﻳــﺔ اﻟﺪاﻟــﺔ أى ﻳﺸــﲑ إﱃ ﻛﺘﻠــﺔ اﳌﻌﻠﻮﻣــﺎت اﻟــﱴ ﲤﺜــﻞ ﺟﺴــﻢ‬
‫اﻟﺪاﻟﺔ‪ .‬ﳝﻜﻨﻨﺎ إذن أن ﻧﻌﺮف ﻣﺘﻐﲑ إﺿﺎﰱ ﻣﻦ ﻧﻮع ﻣﺆﺷﺮ ﻟﺪاﻟــﺔ ﲝﻴــﺚ ﻧﻀــﻊ ﻓﻴــﻪ ﻋﻨـﻮان اﻟﺪاﻟــﺔ اﳌﻄﻠﻮﺑــﺔ ﰱ ﳊﻈــﺔ ﻣــﺎ ﰒ ﻧﻐــﲑﻩ ﻟﻨﻀــﻊ ﻓﻴــﻪ‬
‫ﻋﻨﻮان داﻟﺔ أﺧﺮى ﰱ وﻗﺖ ﻻﺣــﻖ ﻛﻤــﺎ ﻧﺸــﺎء‪ .‬ﻫــﺬا اﳌﺘﻐــﲑ ﳝﻜــﻦ ﻧﻘﻠــﻪ ﻣــﻦ اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ إﱃ أى ﺑــﺮ ﻣﺞ ﺟﺰﺋــﻰ و ﺑــﺬﻟﻚ ﻳﻜــﻮن ﻗــﺪ‬
‫ﲢﻘﻖ اﻟﻐﺮض‪ .‬ﻗﺒﻞ أن ﻧﻌﻄﻰ اﳌﺜﺎل ﳚﺐ أن ﻧﻮﺿﺢ أﻧﻪ ﻛﻤﺎ ﳜﺘﻠﻒ ﻧﻮع اﳌﺆﺷﺮ ﺧﺘﻼف ﻧــﻮع ﻣــﺎ ﻳﺆﺷــﺮ إﻟﻴــﻪ‪ ،‬ﻓــﺈن ذﻟــﻚ ﻳﻨﻄﺒــﻖ أﻳﻀــﺎ‬
‫ﻋﻠــﻰ اﳌﺆﺷـﺮات اﻟــﱴ ﺗﺸــﲑ إﱃ دوال‪ .‬ﻧــﻮع أى داﻟــﺔ ﻫــﻮ ﻋــﺪد و ﻧﻮﻋﻴــﺔ ﻣــﺪﺧﻼ ﺎ و ﻛــﺬا ﻧــﻮع اﻟﻘﻴﻤــﺔ اﻟﻌﺎﺋــﺪة ﻣﻨﻬــﺎ‪ .‬ﻓــﺈذا ﻛﺎﻧــﺖ اﻟﺪاﻟــﺔ‬
‫اﳌﺮاد اﻹﺷﺎرة إﻟﻴﻬﺎ ﻣﺜﻼ ﻣﻦ ﻧﻮع داﻟﺔ ﺗﻌﺘﻤﺪ ﻋﻠﻰ ﻣﺘﻐﲑ واﺣﺪ ﻣﻦ ﻧﻮع ‪ double‬و ﺗﻌﻄﻰ ﲡﺎ ﻣﻦ ﻧــﻮع ‪ ،int‬ﻓــﺈن ﻧﻮﻋﻬــﺎ ﳜﺘﻠــﻒ ﻋــﻦ‬
‫داﻟﺔ أﺧﺮى ﺗﻌﺘﻤﺪ ﻋﻠﻰ ﻣﺘﻐﲑ ﻣﻦ ﻧﻮع ‪ int‬و ﺗﻌﻄﻰ ﲡﺎ ﻣﻦ ﻧﻮع ‪.double‬‬
‫ﲣﻴ ــﻞ إذن أﻧﻨ ــﺎ ﻧﺮﻳ ــﺪ أن ﻧﻜﺘ ــﺐ اﻟﺪاﻟ ــﺔ ‪ Integrate‬ﲝﻴ ــﺚ ﲢﺴ ــﺐ ﺗﻜﺎﻣ ــﻞ أﻳ ــﺔ داﻟ ــﺔ ﻣ ــﻦ اﻟﻨ ــﻮع اﻵﺗ ــﻰ‪ :‬داﻟ ــﺔ ﺗﻌﺘﻤ ــﺪ ﻋﻠ ــﻰ‬
‫‪ double‬و ﺗﻌﻄﻰ ﲡﺎ ﻣﻦ ﻧﻮع ‪ .double‬ﻫﺬا ﻫﻮ اﻷﺳﻠﻮب اﻟﺬى ﺳﻨﻌﺮف ﺑﻪ ﻧﻮع اﳌﺆﺷﺮ ﳍﺬﻩ اﻟﺪاﻟﺔ‪:‬‬
‫;)‪typedef double (* fun_ptr) (double x‬‬
‫ﺣﻴــﺚ ‪ fun_ptr‬ﻫــﻮ اﻻﺳــﻢ اﻟــﺬى اﺧــﱰ ﻩ ﳍــﺬا اﻟﻨــﻮع ﻣــﻦ اﳌﺆﺷ ـﺮات و ﺑﺴــﺒﺐ اﻷﻗ ـﻮاس ﻓــﺈن اﻟﺴــﻄﺮ اﻟﺴــﺎﺑﻖ ﳚــﺐ أن ﻳﻘ ـﺮأ ﻛﺎﻟﺘــﺎﱃ‪:‬‬
‫‪ fun_ptr‬ﻫﻮ ﻧﻮع ﻣﻦ اﳌﺆﺷﺮات ﻳﺸﲑ إﱃ داﻟﺔ ﺗﻌﺘﻤﺪ ﻋﻠﻰ ﻣﺘﻐــﲑ واﺣــﺪ ﻣــﻦ ﻧــﻮع ‪ double‬و ﺗﻨــﺘﺞ ﻗﻴﻤــﺔ ﻋﺎﺋــﺪة ﻣــﻦ ﻧــﻮع ‪.double‬‬
‫ﻻﺣﻆ وﺟــﻮد اﻷﻗـﻮاس اﻟــﱴ ﺗﻠﻌــﺐ دورا ﻫﺎﻣــﺎ ﻫﻨــﺎ ﻷن اﺧﺘﻔﺎﺋﻬــﺎ ﻛــﺎن ﺳــﻴﺆدى ﺑﻨــﺎ ﻟﺘﻌﺮﻳــﻒ ﳐﺘﻠــﻒ ﲤﺎﻣــﺎ ﺗﺒﻌــﺎ ﻟﻘﻮاﻋــﺪ اﻷوﻟﻮﻳــﺔ‪ .‬ﻓﺎﻟﺴــﻄﺮ‬
‫اﻟﺘﺎﱃ‪:‬‬

‫;)‪typedef double * fun_ptr (double x‬‬

‫ﻳﻌﲎ أﻧﻨﺎ ﻧﻌﺮف ﻧﻮع ﻟﺪاﻟﺔ )وﻟﻴﺲ ﻣﺆﺷﺮ( ﺗﻌﺘﻤﺪ ﻋﻠﻰ ﻣﺘﻐــﲑ واﺣــﺪ ﻣــﻦ ﻧــﻮع ‪ double‬و ﺗﻌﻄــﻰ ﲡــﺎ ﻣــﻦ ﻧــﻮع ﻣﺆﺷــﺮ ل ‪ .double‬و‬
‫ﻫﻮ ﻟﺘﺄﻛﻴﺪ ﻣﺎ ﱂ ﻧﻜﻦ ﻧﺮﻳﺪﻩ‪ .‬ﻧﺴﺘﻄﻴﻊ اﻵن أن ﻧﻜﺘﺐ داﻟﺔ اﻟﺘﻜﺎﻣﻞ ﺳﺘﺨﺪام ﻧﻈﺮﻳﺔ أﺷﺒﺎﻩ اﳌﻨﺤﺮﻓﺎت‪:‬‬
‫;)‪typedef double (* fun_ptr) (double x‬‬
‫‪double Integrate (fun_ptr myfunc,‬‬ ‫‪/* The function pointer */‬‬
‫‪double a, double b,‬‬ ‫‪/* Integration limits */‬‬
‫)‪int n‬‬ ‫‪/* Number of intervals */‬‬
‫{‬
‫‪double h, /* Interval size */‬‬
‫‪x,‬‬ ‫‪/* The independent variable */‬‬
‫‪fold, /* function value at the beginning of the step */‬‬
‫‪fnew,‬‬ ‫‪/* function value at the end of the step */‬‬
‫‪sum, /* result of integration */‬‬
‫;‪h=(b-a)/n‬‬
‫;)‪fnew = myfunc(a‬‬
‫)‪for (sum=0, x=a+h; x<=b; x+=h‬‬
‫;‪{ fold = fnew‬‬
‫;)‪fnew = myfunc(x‬‬
‫;‪sum += h * (fnew + fold) /2.0‬‬
‫}‬
‫;)‪return (sum‬‬
‫}‬

‫‪95‬‬
‫ﻓﺈذا أرد أن ﻧﺴﺘﺪﻋﻰ ﻫﺬﻩ اﻟﺪاﻟﺔ ﳊﺴﺎب ﺗﻜﺎﻣﻞ اﳉﻴﺐ ﻣﺜﻼ ﰱ اﻟﻔﱰة ﻣﻦ ‪ 0.5‬إﱃ ‪ 2.5‬ﳝﻜﻦ اﺳﺘﺪﻋﺎﺋﻬﺎ ﻛﺎﻟﺘﺎﱃ‪:‬‬
‫)‪void main (void‬‬
‫{‬
‫……‬
‫;‪z = 2.0 * Integrate (sin, 0.5, 2.5, 100) + 1.0‬‬
‫‪…..‬‬
‫}‬
‫ﻛﺘﺒﻨــﺎ ﺑــﺮ ﻣﺞ اﻟﺘﻜﺎﻣــﻞ ﺑﺼــﻮرة ﻣﺒﺴــﻄﺔ ﰱ اﻟﺒﺪاﻳــﺔ ﻟﻠﺘﻮﺿــﻴﺢ‪ ،‬و ﻟﻜﻨــﻪ ﻳﻌــﺎﱏ ﻣــﻦ ﺑﻌــﺾ اﻟﻌﻴــﻮب اﻟــﱴ ﺳــﻨﻌﺎﳉﻬﺎ اﻵن‪ .‬أول ﻫــﺬﻩ اﻟﻌﻴــﻮب‬
‫ﻫــﻮ ﰱ ﺷــﺮط اﻟﺒﻘــﺎء ﰱ اﻟﻌﻤﻠﻴــﺔ اﻟﺘﻜﺮارﻳــﺔ ‪ .for‬ﺣﻴــﺚ أن ﺣﺴــﺎب ﻋــﺮض اﻟﺸــﺮﳛﺔ اﻟﺘﻜﺎﻣﻠﻴــﺔ ‪ h‬ﻗــﺪ ﻳــﺪﺧﻞ ﺑﻌــﺾ اﻷﺧﻄــﺎء اﻟﺒﺴــﻴﻄﺔ‬
‫ﲝﻴــﺚ أﻧﻨــﺎ إذا ﲨﻌﻨــﺎ ﻋــﺮض اﻟﺸــﺮﳛﺔ ‪ n‬ﻣــﻦ اﳌـﺮات ﻋﻠــﻰ اﻟﻘﻴﻤــﺔ اﻻﺑﺘﺪاﺋﻴــﺔ ‪ a‬ﻓﻘــﺪ ﻧﺼــﻞ ﰱ اﻟﻨﻬﺎﻳــﺔ ﻟﻘﻴﻤــﺔ ﺎﺋﻴــﺔ ﲣﺘﻠــﻒ اﺧﺘﻼﻓــﺎ ﻃﻔﻴﻔــﺎ‬
‫ﻋﻦ ‪ .b‬ﻓﺈذا ﻛﺎﻧﺖ اﻟﻨﺘﻴﺠﺔ اﻟﻨﻬﺎﺋﻴﺔ ﺗﺰﻳﺪ ﻋﻦ ‪ b‬و ﻟﻮ ﺑﻘﻴﺪ أﳕﻠﺔ ﻓﺈﻧﻨــﺎ ﻟــﻦ ﳓﺴــﺐ اﻟﺸــﺮﳛﺔ اﻷﺧــﲑة ﳑــﺎ ﻳــﺆدى ﳋﻄــﺄ ﳏﺴــﻮس ﰱ اﻟﻨــﺎﺗﺞ‪.‬‬
‫اﻟﻌﻴﺐ اﻟﺜﺎﱏ ﻳﺘﻌﻠﻖ ﺑﺴﺮﻋﺔ اﻟﺘﻨﻔﻴﺬ‪ .‬ﺣﻴﺚ أﻧﻨﺎ ﳒﻤﻊ ﻗﻴﻤﺔ اﻟﺪاﻟﺔ داﺋﻤﺎ ﻣﺮﺗﲔ‪ ،‬ﻣــﺮة ﺣﻴﻨﻤــﺎ ﺗﻜــﻮن ﰱ ﺑﺪاﻳــﺔ اﻟﺸــﺮﳛﺔ و ﻣــﺮة ﺣﻴﻨﻤــﺎ ﺗﻜــﻮن‬
‫ﰱ ﺎﻳﺘﻬﺎ )ﻋﺪا اﻟﻘﻴﻤﺔ ﻋﻨﺪ ‪ (x=a, x=b‬ﻓﺈﻧﻨﺎ ﳝﻜﻦ إﻋﺎدة ﺻﻴﺎﻏﺔ اﻟﱪ ﻣﺞ اﻟﺘﻜﺎﻣﻞ ﻛﺎﻟﺘﺎﱃ‪:‬‬
‫;)‪typedef double (* fun_ptr) (double x‬‬
‫‪#define TINY 1.0e-10‬‬

‫‪double Integrate (fun_ptr myfunc,‬‬ ‫‪/* The function pointer */‬‬


‫‪double a, double b,‬‬ ‫‪/* Integration limits */‬‬
‫)‪int n‬‬ ‫‪/* Number of intervals */‬‬
‫{‬
‫‪double h, /* Interval size */‬‬
‫‪x,‬‬ ‫‪/* The independent variable */‬‬
‫‪sum, /* result of integration */‬‬
‫;‪h=(b-a)/n‬‬
‫;))‪sum = 0.5*h*(myfunc(a) + myfunc(b‬‬
‫)‪for (x=a+h; x<b*(1-TINY); x+=h‬‬
‫;)‪{ sum += h*myfunc(x‬‬
‫}‬
‫;)‪return (sum‬‬
‫}‬

‫ﻻﺣﻆ أﻧﻨﺎ ﻧﻜﺮر اﻟﻀﺮب ﰱ ﻋﺮض اﻟﺸﺮﳛﺔ ﺑﺪاﺧﻞ اﻟﻌﻤﻠﻴﺔ اﻟﺘﻜﺮارﻳﺔ‪ ،‬ﺑﻴﻨﻤﺎ ﻛﺎن ﻣﻦ اﳌﻤﻜﻦ أن ﺧــﺬ ذﻟــﻚ اﻟﻌــﺮض ﻣﻀــﺮوب ﻣﺸــﱰك‬
‫ﲝﻴﺚ ﻧﻀﺮب ﻣﺮة واﺣﺪة ﻓﻘﻂ ﰱ ﻋﺮض اﻟﺸﺮﳛﺔ ﻋﻨﺪ اﳋﺮوج ﻣﻦ اﻟﻌﻤﻠﻴﺔ اﻟﺘﻜﺮارﻳﺔ‪ .‬و ﻟﻜﻨﻨﺎ آﺛــﺮ ﲡﻨــﺐ ذﻟــﻚ ﲢﺴــﺒﺎ ﻟﻠﻮﻗــﻮع ﰱ ﺧﻄــﺄ‬
‫آﺧﺮ و ﻫﻮ أن ﻳﻜﻮن ﳎﻤﻮع اﻟﺪوال ﻛﺒﲑا ﺟﺪا ﲝﻴﺚ ﻳﺘﻌﺪى اﳌﺪى اﳌﺴﻤﻮح ﺑﻪ ﻟﺘﺨﺰﻳﻦ اﳌﺘﻐﲑ ‪.sum‬‬
‫ﳔﺘﺘﻢ ﻫﺬا اﻟﻔﺼﻞ ﲟﻠﺤﻮﻇﺘﲔ‪ .‬أوﳍﻤﺎ ﻫﻮ أﻧﻨﺎ ﺣﻴﻨﻤﺎ ﻧﻌــﺮف اﻟﺪاﻟــﺔ ﲝﻴــﺚ ﻳﻜــﻮن أﺣــﺪ ﻣــﺪﺧﻼ ﺎ ﻣــﺜﻼ ﻣــﻦ ﻧــﻮع ‪ int‬ﺑﻴﻨﻤــﺎ ﰎ‬
‫اﻻﺳﺘﺪﻋﺎء ﲝﻴﺚ ﻛﺎن اﻟﻘﻴﻤﺔ اﻟﻔﻌﻠﻴﺔ ﻣﻦ ﻧﻮع ‪ double‬ﻓﺈن ذﻟﻚ ﻟﻦ ﻳﺆدى إﱃ ﺧﻄﺄ ﻋﻨــﺪ اﻟﱰﲨــﺔ )ﻋــﺎدة ﻣــﺎ ﻳﻜــﻮن ﻫﻨــﺎك إﻧــﺬار ﻋﻠــﻰ‬
‫اﻷﻗــﻞ( و ﻟﻜــﻦ ﻋﻨــﺪ اﻟﺘﻨﻔﻴــﺬ ﻗــﺪ ﳓﺼــﻞ ﻋﻠــﻰ ﻧﺘــﺎﺋﺞ ﲣﺘﻠــﻒ ﻋﻤــﺎ ﻧﺘﻮﻗﻌــﻪ‪ .‬و ﻟــﺬﻟﻚ ﳚــﺐ داﺋﻤــﺎ اﳊــﺮص ﻋﻨــﺪ ﻛﺘﺎﺑــﺔ اﻻﺳــﺘﺪﻋﺎء ﲝﻴــﺚ‬
‫ﳛﺎﻛﻰ ﲤﺎﻣﺎ ﺳﻄﺮ اﻹﻋﻼن ﻣﻦ ﺣﻴﺚ ﻧﻮع ﻛﻞ ﻣﺘﻐﲑ‪ .‬اﳌﻠﺤﻮﻇﺔ اﻟﺜﺎﻧﻴﺔ ﺗﺘﻌﻠﻖ ﻓﻀــﻠﻴﺔ اﺧﺘﻴــﺎر ﻧــﻮع اﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ‪ ،‬أى اﳌﻔﺎﺿــﻠﺔ ﺑــﲔ‬
‫ﻛﺘﺎﺑــﺔ داﻟــﺔ و ﻛﺘﺎﺑــﺔ إﺟ ـﺮاء ﻟﺘﻨﻔﻴــﺬ ﻣﻬﻤــﺔ ﻣــﺎ‪ .‬ﰱ اﳊﻘﻴﻘــﺔ ﳝﻜــﻦ داﺋﻤــﺎ اﺳــﺘﺨﺪام اﻹﺟ ـﺮاء ﳏــﻞ اﻟﺪاﻟــﺔ ﺣﻴــﺚ أﻧﻨــﺎ ﻧﺴــﺘﻌﻴﺾ ﻋــﻦ اﻟﻘﻴﻤــﺔ‬
‫اﻟﻌﺎﺋــﺪة ﻣــﻦ اﻟﺪاﻟــﺔ ﺑﻮاﺳــﻄﺔ ﺗﻌﺮﻳــﻒ ﻣﺘﻐــﲑ ﻣــﻦ اﳌــﺪﺧﻼت ﻛﻤﺆﺷــﺮ و ﺑــﺬﻟﻚ ﻳﺘﺤــﻮل إﱃ ﳐﺮﺟــﺎت‪ .‬و ﻟﻜﻨﻨــﺎ ﻧﻔﻀــﻞ اﻟﺪاﻟــﺔ ﻟﺴــﻬﻮﻟﺘﻬﺎ و‬
‫ﺑﺴﺎﻃﺘﻬﺎ ﺣﻴﻨﻤﺎ ﺗﻜﻮن ﺑﺮ ﳎﺎ ﺟﺰﺋﻴﺎ ﺑﺴﻴﻄﺎ ﻳﺆدى ﻣﻬﻤﺔ ﳏﺪدة )ﺣﺴﺎب ﻗﻴﻤﺔ ﻣﺎ ﳝﻜﻦ أن ﺗﺴﺘﺨﺪم ﺑﺪاﺧﻞ ﺗﻌﺒﲑ( ﺑﺪون آ ر ﺟﺎﻧﺒﻴــﺔ‬

‫‪96‬‬
‫)ﻣﺜﻞ ﻓﺘﺢ ﻣﻠﻒ أو اﻟﻜﺘﺎﺑﺔ ﻋﻠﻰ اﻟﺸﺎﺷﺔ(‪ .‬ﻋﺪا ذﻟﻚ ﻳﻔﻀﻞ داﺋﻤﺎ اﻹﺟﺮاء ﺣﻴــﺚ أﻧﻨــﺎ ﻧﻀــﻤﻦ ﺑــﺬﻟﻚ أﻻ ﻧﻄﻠﺒــﻪ أﻛﺜــﺮ ﻣــﻦ ﻣــﺮة ﺑــﺪاﺧﻞ‬
‫ﺗﻌﺒﲑ واﺣﺪ ﻓﻴﺤﺪث ﺗﺪاﺧﻞ ﺑﲔ اﻵ ر اﳉﺎﻧﺒﻴﺔ اﳌﺨﺘﻠﻔﺔ‪.‬‬

‫‪97‬‬
‫‪.4‬د‪ .‬ﻫﻴﺎﻛﻞ اﻟﺒﻴﺎ ت ‪Data Structures‬‬

‫‪.4‬د‪ .1.‬ﺗﻌﺮﻳﻒ اﳍﻴﻜﻞ ‪structure definition‬‬


‫ﺗﻌﺮﻓﻨﺎ ﰱ اﻷﺑﻮاب اﻟﺴﺎﺑﻘﺔ ﻋﻠﻰ ﻧﻮع واﺣﺪ ﺑﺴﻴﻂ ﻣﻦ اﻟﺒﻴﺎ ت اﳍﻴﻜﻠﻴــﺔ أﻻ و ﻫــﻮ اﳌﺘﺠــﻪ و ﻟﺘــﺎﱃ اﳌﺼــﻔﻮﻓﺔ‪ .‬ﺗﺮﺟــﻊ ﺑﺴــﺎﻃﺔ‬
‫ذﻟﻚ اﻟﻨﻮع إﱃ أن ﲨﻴﻊ ﻋﻨﺎﺻــﺮ اﳍﻴﻜــﻞ ﳚــﺐ أن ﺗﻜــﻮن ﻣــﻦ ﻧﻔــﺲ اﻟﻨــﻮع‪ .‬و ﻟــﺬﻟﻚ ﻓــﻴﻤﻜﻦ ﺑﺴــﻬﻮﻟﺔ ﺗــﺮﻗﻴﻢ اﻟﻌﻨﺎﺻــﺮ و اﻹﺷــﺎرة إﱃ أى‬
‫ﻋﻨﺼﺮ ﲟﺠﺮد إﻋﻄﺎء رﻗﻤﻪ ﻣﺜﻞ ]‪ . x[3‬رأﻳﻨﺎ ﻛﻴﻒ ﻳﺴﺘﻄﻴﻊ اﳊﺎﺳﺐ ﺑﺴﻬﻮﻟﺔ إﳚﺎد ﻣﻮﻗــﻊ ذﻟــﻚ اﻟﻌﻨﺼــﺮ ﻋــﻦ ﻃﺮﻳــﻖ ﺣﺴــﺎب ﻋــﺪد ﳝﺜــﻞ‬
‫ﻋﺮض اﻟﻌﻨﺼــﺮ ﻣﻀــﺮو ﰱ ﻋــﺪد اﻟﻌﻨﺎﺻــﺮ ﻣﻀــﺎﻓﺎ ﻟﻌﻨـﻮان اﻟﻌﻨﺼــﺮ اﻷول‪ .‬ﻛﺜـﲑا ﻣــﺎ ﳓﺘــﺎج ﻟﺘﺠﻤﻴــﻊ ﻣﻌﻠﻮﻣــﺎت ﺑــﺮ ط ﻣﻨﻄﻘــﻰ ﻣــﺎ ﲝﻴــﺚ ﻻ‬
‫ﺗﻜﻮن اﻟﻌﻨﺎﺻﺮ ﻛﻠﻬﺎ ﻣﻦ ﻧﻔﺲ اﻟﻨﻮع‪ .‬اﳌﺜﺎل اﻟﺒﺴﻴﻂ ﻋﻠﻰ ذﻟﻚ ﻫﻮ ﺑﻄﺎﻗﺔ اﻟﺘﻌﺮﻳﻒ ﻟﻄﺎﻟﺐ‪ .‬ﺣﻴــﺚ ﲢــﻮى اﺳــﻢ اﻟﻄﺎﻟــﺐ و رﻗــﻢ ﺟﻠﻮﺳــﻪ‬
‫و اﻟﻘﺴــﻢ و اﻟﺼــﻒ اﻟــﺬى ﻳــﺪرس ﻓﻴــﻪ ﻹﺿــﺎﻓﺔ ﻟﺪرﺟﺎﺗــﻪ و ﺗﻘــﺪﻳﺮﻩ ﰱ ﻛــﻞ ﻣــﺎدة و ﺣﺎﻟﺘــﻪ )ﺣــﺪﻳﺚ أو ﻗــﺪﱘ أو ﻗــﻰ أو ﻣﺘﺨﻠــﻒ إﱃ‬
‫آﺧﺮﻩ(‪ .‬واﺿﺢ أن ﻫﺬﻩ اﻟﺒﻴﺎ ت ﻻ ﳝﻜﻦ أن ﲡﻤﻊ ﰱ ﻣﺘﺠﻪ ﺣﻴﺚ أن ﻧــﻮع ﻛــﻞ ﻋﻨﺼــﺮ ﳐﺘﻠــﻒ ﻋــﻦ اﻵﺧــﺮ‪ .‬و ﰱ اﻟﺘﻄﺒﻴﻘــﺎت اﳍﻨﺪﺳــﻴﺔ‬
‫ﳝﻜﻦ أﻳﻀﺎ أن ﳓﺘﺎج ﳌﺘﻐﲑ ﻳﺼﻒ ﺣﺎﻟﺔ ﻣﺎدة ﻣﺜﻼ ﻣﻦ ﺣﻴﺚ اﻟﻀﻐﻂ و درﺟﺔ اﳊﺮارة و ﻋــﺪد درﺟــﺎت اﳊﺮﻳــﺔ و ﻧــﻮع اﻟﻄــﻮر )ﻏــﺎزى أو‬
‫ﺳﺎﺋﻞ أو ﺻﻠﺐ أو ﺧﻠﻴﻂ ﻣﺘﺠﺎﻧﺲ أو ﻏﲑ ﻣﺘﺠــﺎﻧﺲ إﱃ آﺧــﺮﻩ(‪ .‬ﻫــﺬﻩ اﻟﻌﻨﺎﺻــﺮ أﻳﻀــﺎ رﻏــﻢ وﺟــﻮد راﺑــﻂ ﻣﻨﻄﻘـﻰ واﺿــﺢ ﺑﻴﻨﻬــﺎ إﻻ أ ــﺎ‬
‫ﻟﻴﺴــﺖ ﻣــﻦ ﻧﻔــﺲ اﻟﻨــﻮع‪ .‬و ﻟﻜﻮ ــﺎ ﻣــﻦ ﻧــﻮع ﳐﺘﻠــﻒ ﻻ ﳝﻜــﻦ وﺿــﻌﻬﺎ ﰱ ﻣﺘﺠــﻪ ﺣﻴــﺚ أﻧﻨــﺎ ﻟــﻦ ﻧــﺘﻤﻜﻦ ﻣــﻦ ﺣﺴــﺎب ﻋﻨـﻮان أى ﻋﻨﺼــﺮ‬
‫ﻓﻴﻬﺎ ﺑﻨﻔﺲ اﻷﺳﻠﻮب اﳌﺘﺒﻊ ﻣﻊ اﳌﺘﺠﻬﺎت‪ .‬و ﻟﺘﺎﱃ ﻟﻦ ﻧﺘﻤﻜﻦ ﺑﺴﻬﻮﻟﺔ ﻟﻠﻮﺻﻮل ﻟﻌﻨﺼﺮ ﻓﻴﻬــﺎ ﻗـﺮاءة أو ﻛﺘﺎﺑــﺔ‪ .‬ﻟﻜــﻞ ﻫــﺬﻩ اﻷﺳــﺒﺎب ﰎ‬
‫ﺗﻌﺮﻳــﻒ اﳍﻴﻜــﻞ ‪ structure‬ﻋﻠــﻰ أﻧــﻪ ﲡﻤﻴــﻊ ﻣــﻦ ﺑﻴــﺎ ت ﳐﺘﻠﻔــﺔ‪ ،‬ﻛــﻞ ﺑﻴــﺎن ﻓﻴﻬــﺎ ﻟــﻪ اﺳــﻢ ﳝﻴــﺰﻩ ﻋــﻦ ﻏــﲑﻩ و ﺑــﺬﻟﻚ ﳝﻜــﻦ اﻟﻮﺻــﻮل ﻷى‬
‫ﻋﻨﺼﺮ ﻋﻦ ﻃﺮﻳﻖ ذﻛﺮ اﲰﻪ )ﺑﺪﻻ ﻣﻦ ذﻛﺮ رﻗﻤﻪ ﻛﻤــﺎ ﻛﻨــﺎ ﻧﺘﺒــﻊ ﻣــﻊ اﳌﺘﺠﻬــﺎت(‪ .‬ﻳﻮﺿــﺢ اﳌﺜــﺎل اﻟﺘــﺎﱃ ﻛﻴــﻒ ﻧﻌــﺮف ﻫﻴﻜــﻞ و ﻧﺴــﺘﺨﺪﻣﻪ‬
‫ﰱ ﻟﻐﺔ ال‪ .C‬ﺣﻴﺚ ﻳﻘﻮم اﻟﱪ ﻣﺞ اﻟﺮﺋﻴﺴﻰ ﺑﻮﺿﻊ درﺟﺎت اﻟﻄﺎﻟﺐ و ﻳﻄﻠﺐ ﻣﻦ داﻟﺔ أن ﺗﻘﻮم ﲝﺴﺎب اﺠﻤﻟﻤﻮع‪:‬‬
‫‪typedef struct stud_data‬‬
‫;]‪{ char Name[30‬‬
‫;‪char status‬‬
‫;‪int phys, math, computer, tot‬‬
‫;]‪char Grade[3‬‬
‫;‪} stud_type‬‬
‫;)‪void find_tot(stud_type * stud‬‬
‫)‪void main (void‬‬
‫{‬
‫;‪struct stud_data sudent‬‬

‫;‪student.math = 116‬‬
‫;‪student.phys = 96‬‬
‫;‪student.computer = 99‬‬
‫;)‪find_tot(&student‬‬
‫‪printf ("Student: %s, Total = %d Grade = \n",student.name, student.tot,‬‬ ‫;)‪student.Grade‬‬
‫}‬
‫)‪void find_tot(stud_type * stud‬‬
‫{‬
‫;‪stud->tot = stud ->math + (*stud).phys + stud->computer‬‬
‫}‬

‫‪98‬‬
‫ﰱ اﻟﺴﻄﺮ اﻷول ﻣﻦ اﻟﱪ ﻣﺞ ﻗﻤﻨﺎ ﺑﺘﻌﺮﻳﻒ اﳍﻴﻜﻞ )اﻷﻣﺮ ‪ .(typedef‬ﻋﺮف اﳊﺎﺳﺐ أﻧﻨﺎ ﺑﺼﺪد ﺗﻌﺮﻳﻒ ﻫﻴﻜﻞ ﻟﺘﺤﺪﻳﺪ ﻋﻦ ﻃﺮﻳــﻖ‬
‫اﺳﺘﺨﺪام اﻟﻜﻠﻤﺔ اﶈﺠﻮزة ‪ .struct‬اﻻﺳﻢ اﻟﺬى ﻳﻠﻴﻬﺎ ﻫﻮ اﺳﻢ ﻟﻨﻮع ﻫﺬا اﳍﻴﻜﻞ‪ .‬ﺑﻌﺪ ذﻟﻚ ﳚﺐ وﺿﻊ أﻗﻮاس ﻣﻨﺜﻨﻴــﺔ ﺑــﺪاﺧﻠﻬﺎ ﻗﺎﺋﻤــﺔ‬
‫ﲰــﺎء اﻟﺒﻴــﺎ ت اﻟــﱴ ﳛﺘﻮﻳﻬــﺎ اﳍﻴﻜــﻞ ﻣــﻊ ﺗﻮﺿــﻴﺢ ﻟﻨــﻮع ﻛــﻞ ﻣﻨﻬــﺎ‪ .‬ﻳﺴــﻤﻰ ﻛــﻞ ﻋﻨﺼــﺮ ﰱ اﳍﻴﻜــﻞ ﺣﻘــﻞ ‪ .field‬ﰱ ﻫــﺬا اﳌﺜــﺎل ﻛﺎﻧــﺖ‬
‫اﳊﻘــﻮل ﻫــﻰ اﺳــﻢ اﻟﻄﺎﻟــﺐ )ﻣــﻦ ‪ 29‬ﺣــﺮف ﲝــﺪ أﻗﺼــﻰ( و ﺣﺎﻟﺘــﻪ )ﺣــﺮف ﻛــﻮدى(‪ ،‬و درﺟﺎﺗــﻪ )و ﲨﻴﻌﻬــﺎ ﻣــﻦ ﻧــﻮع ‪ (int‬و ﰱ اﻟﻨﻬﺎﻳــﺔ‬
‫اﻟﺘﻘ ــﺪﻳﺮ و ﻫ ــﻮ ﻣﻜ ــﻮن ﻣ ــﻦ ﺣ ــﺮﻓﲔ‪ .‬ﺑﻌ ــﺪ اﻟﺘﻌﺮﻳ ــﻒ ﳚ ــﺐ وﺿ ــﻊ اﻟﻔﺎﺻ ــﻠﺔ اﳌﻨﻘﻮﻃ ــﺔ و ﳝﻜ ــﻦ أن ﻳﺴ ــﺒﻘﻬﺎ اﺳ ــﻢ ﻛﻤ ــﺎ ﰱ اﳌﺜ ــﺎل ﻋﺎﻟﻴ ــﻪ‪:‬‬
‫‪ .stud_type‬ﻫــﺬا اﻻﺳــﻢ ﻫــﻮ ﳎــﺮد اﺧﺘﺼــﺎر ﻻﺳــﻢ اﻟﻨــﻮع اﳌﻌــﺮف ﰱ اﻟﺒﺪاﻳــﺔ و ﳝﻜــﻦ اﺳــﺘﺨﺪاﻣﻪ ﺑــﺪﻻ ﻣــﻦ اﻟﻜﻠﻤــﺔ اﳌﻄﻮﻟــﺔ ‪struct‬‬
‫‪ stud_data‬ﰱ أى ﻣﻮﺿﻊ ﻣﻦ اﻟﱪ ﻣﺞ‪ .‬ﰱ اﻟﱪ ﻣﺞ اﻟﺮﺋﻴﺴﻰ رأﻳﻨﺎ أوﻻ ﻛﻴﻒ ﻧﻌﺮف اﳌﺘﻐﲑ ‪ student‬ﻣــﻦ ﻧــﻮع ﻫــﺬا اﳍﻴﻜــﻞ‪ ،‬ﰒ رأﻳﻨــﺎ‬
‫ﻛﻴﻒ ﻧﺘﻌﺎﻣﻞ ﻣﻊ أى ﻋﻨﺼﺮ ﻣﻦ ﻋﻨﺎﺻﺮ اﻟﺒﻴﺎ ت ﻓﻴﻪ‪ .‬ﻟﻠﻮﺻﻮل ﻷى ﻋﻨﺼﺮ ﻛﺘﺎﺑﺔ أو ﻗﺮاءة ﻧﺬﻛﺮ اﺳﻢ اﳌﺘﻐﲑ ﻳﺘﻠﻮﻩ ﻧﻘﻄﺔ ﰒ اﺳﻢ اﳊﻘــﻞ‬
‫اﳌﻌﲎ‪ .‬ﺣﻴﻨﻤﺎ ﻃﻠﺒﻨﺎ اﻟﱪ ﻣﺞ اﳉﺰﺋﻰ اﻟﺬى ﳛﺴﺐ اﺠﻤﻟﻤﻮع ﻣﺮر ﻣﺆﺷﺮ ﻟﻠﻤﺘﻐﲑ ‪ student‬ﺣﱴ ﺗﺼﺒﺢ اﻟﺘﻌﺪﻳﻼت اﻟﱴ ﳛــﺪﺛﻬﺎ اﻟــﱪ ﻣﺞ‬
‫اﳉﺰﺋﻰ ﻣﺮﺋﻴﺔ ﰱ اﻟﱪ ﻣﺞ اﻟﺮﺋﻴﺴﻰ‪ .‬ﻻﺣﻆ أﻧﻨﺎ ﺳﺘﺨﺪام ﻣﺆﺷﺮ واﺣﺪ ﻗــﺪ ﻧﻘﻠﻨــﺎ دﻓﻌــﺔ واﺣــﺪة ﻃﺎﺋﻔــﺔ ﻣــﻦ اﻟﺒﻴــﺎ ت‪ ،‬ﻫــﻰ ﺣﻘــﻮل اﳌﺘﻐــﲑ‪،‬‬
‫و ﻟــﻴﺲ ﺑﻴــﺎ واﺣــﺪا‪ .‬اﳌﺘﻐــﲑ ‪ stud‬ﰱ اﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ ﻫــﻮ ﻣﺆﺷــﺮ ﲞــﻼف ‪ student‬ﰱ اﻟــﱪ ﻣﺞ اﻟﺮﺋﻴﺴــﻰ‪ .‬ﻋﻨــﺪ ﻛﺘﺎﺑــﺔ أو ﻗـﺮاءة ﺑﻴــﺎن‬
‫ﺑﻮاﺳــﻄﺔ ﻣﺆﺷــﺮ ﳚــﺐ ﻋﺎﻣــﺔ اﺳــﺘﺨﺪام اﻟﻨﺠﻤــﺔ‪ ،‬و ﻫــﻮ ﻣــﺎ اﺳــﺘﺨﺪﻣﻨﺎﻩ ﻓﻌــﻼ ﻟﻨﺴــﺒﺔ ﻟﻠﺤﻘــﻞ ‪ .phys‬ﺣﻴــﺚ أن ﻋﻤﻠﻴــﺔ ﻛﺘﺎﺑــﺔ أو ﻗ ـﺮاءة‬
‫ﺑﻴــﺎ ت ﰱ ﻫﻴﻜــﻞ ﻋــﻦ ﻃﺮﻳــﻖ ﻣﺆﺷــﺮ ﻳﺸــﲑ إﻟﻴــﻪ ﻫــﻰ ﻋﻤﻠﻴــﺔ ﻣﺘﻜــﺮرة ﻛﺜ ـﲑا ﰱ اﻟﺘﻄﺒﻴﻘــﺎت ﻫﻨــﺎك اﺧﺘﺼــﺎر ﻟﻠﻨﺠﻤــﺔ و اﻷﻗ ـﻮاس و اﻟﻨﻘﻄــﺔ‬
‫ﺑﻮاﺳﻄﺔ اﻻﻛﺘﻔﺎء ﺑﻜﺘﺎﺑﺔ ﺳﻬﻢ ﺑﻌﺪ اﺳﻢ اﳌﺆﺷﺮ ﻳﻠﻴﻪ اﺳﻢ اﳊﻘﻞ ﻣﺒﺎﺷﺮة ﻛﻤﺎ ﻓﻌﻠﻨﺎ ﻣﻊ ﻗﻰ اﳊﻘﻮل ﰱ اﳌﺜﺎل‪ .‬ﻳﻜﺘﺐ اﻟﺴــﻬﻢ ﻋــﻦ ﻃﺮﻳــﻖ‬
‫ﻛﺘﺎﺑﺔ ﻋﻼﻣﺔ اﻟﺴﺎﻟﺐ – و ﺑﻌﺪﻫﺎ ﻋﻼﻣﺔ أﻛﱪ ﻣﻦ> ﻟﺘﺼﺒﺢ >‪.-‬‬

‫ﺗﻌﺮﻳﻒ اﳍﻴﻜﻞ ﻓﻀﻔﺎض إﱃ أﻗﺼﻰ درﺟﺔ ﺣﻴﺚ أﻧــﻪ ﻻ ﺗﻮﺟــﺪ ﻗﻴــﻮد ﻋﻠــﻰ ﻋــﺪد أو ﻧــﻮع اﳊﻘــﻮل اﻟـﻮاردة ﻓﻴــﻪ ﲟــﺎ ﻳﺴــﻤﺢ ﺑﻌﻤــﻞ‬
‫ﺗﻜﻮﻳﻨﺎت ﻛﻤﺎ ﻧﺮﻳﺪ ﻟﻠﻤﺴﺎﻋﺪة ﰱ ﺣﻞ ﻣﺸﺎﻛﻞ ﻣﺘﻨﻮﻋﺔ ﺗﻨﻮﻋﺎ ﺷﺪﻳﺪا‪ ،‬ﺳﻮاء ﻛﺎﻧﺖ ﻋﻠﻤﻴﺔ أو ﲡﺎرﻳﺔ‪ .‬ﳝﻜــﻦ ﻣــﺜﻼ أن ﳛﺘــﻮى اﳍﻴﻜــﻞ أى‬
‫ﺣﻘﻞ ﻣﻬﻴﻜﻞ ﺳﻮاء ﻛﺎن ﻣﺘﺠﻬﺎ أو ﻫﻴﻜﻼ آﺧﺮ‪ .‬اﻟﻘﻴﺪ اﻟﻮﺣﻴﺪ ﻫﻮ أﻻ ﻳﻜﻮن اﳊﻘﻞ ﻫــﻮ ﻧﻔﺴــﻪ اﳍﻴﻜــﻞ اﻷﺻــﻠﻰ ﻷن ذﻟــﻚ ﻳــﺆدى ﳋﻠــﻖ‬
‫ذاﺗﻰ اﻻﺳﺘﺪﻋﺎء ﳍﻴﻜﻞ ﻻ ﺎﺋﻰ! ﻛﻤﺎ ﳝﻜﻦ أﻳﻀﺎ ﻋﻤﻞ ﻣﺘﺠﻪ ﻣﻦ اﳍﻴﺎﻛﻞ‪ .‬ﻟﺘﻮﺿﻴﺢ ﺗﻠﻚ اﻹﻣﻜﺎﻧﻴﺎت ﺳﻨﻌﺪل اﳌﺜﺎل اﻟﺴــﺎﺑﻖ ﻟﻨﺘﻌﺎﻣــﻞ‬
‫ﻣﻊ ﲨﻴﻊ اﻟﻄﻠﺒﺔ ﺑﺪﻻ ﻣﻦ ﻃﺎﻟﺐ واﺣﺪ‪ .‬ﻓﻜﻞ ﻃﺎﻟــﺐ ﺣﻴﻨﺌــﺬ ﺳــﻴﻜﻮن ﻟــﻪ ﻫﻴﻜــﻞ ﳝﺜــﻞ ﻋﻨﺼــﺮ ﻣــﻦ اﳌﺘﺠــﻪ‪ .‬ﻛﻤــﺎ أﻧﻨــﺎ ﺳــﻨﻌﺪل ﻣــﻦ ﺗﻜــﻮﻳﻦ‬
‫اﳍﻴﻜﻞ ﻟﻴﺤﻮى ﻣﺘﺠﻪ ﳝﺜﻞ درﺟﺎت اﻟﻄﺎﻟــﺐ‪ ،‬ﻛﻤــﺎ ﳛــﻮى ﻫــﻴﻜﻼ آﺧــﺮ ﳝﺜــﻞ اﻟﺒﻴــﺎ ت اﻟﺸﺨﺼــﻴﺔ ﻣﺜــﻞ اﻻﺳــﻢ و اﻟــﺮﻗﻢ اﻟﻜــﻮدى‪ .‬ﻓﻴﺼــﺒﺢ‬
‫اﻟﱪ ﻣﺞ‪:‬‬
‫‪typedef struct personal‬‬
‫{‬
‫;]‪char Name [30‬‬
‫;‪long code‬‬
‫;‪} pers_type‬‬

‫‪typedef struct stud_data‬‬


‫{‬
‫;‪pers_type person‬‬ ‫‪/* Personal data: Name, code*/‬‬
‫;‪char status‬‬ ‫‪/* status: fresh, doubler, …*/‬‬
‫‪int no_of_courses,‬‬ ‫‪/* number of courses */‬‬
‫‪marks[11],‬‬ ‫‪/* mark in each course */‬‬
‫;‪tot‬‬
‫;]‪char Grade[3‬‬
‫;‪} stud_typ‬‬

‫‪99‬‬
‫;)‪void find_tot(stud_typ * stud‬‬

‫)‪void main(void‬‬
‫{‬
‫;‪stud_typ * section1‬‬
‫;‪int tot_student, k‬‬
‫‪long code=10000; /* Starting number for student codes */‬‬

‫;)"‪printf("Enter number of students:‬‬


‫;)‪scanf("%d",&tot_student‬‬

‫;))‪section1 = (stud_typ *) malloc (sizeof(stud_typ) * (tot_student+1‬‬

‫)‪for (k=1;k<=tot_student;k++‬‬
‫{‬
‫;)‪printf ("Enter name of student no. %d:",k‬‬
‫;)‪gets(section1[k].person.Name‬‬
‫;‪code ++‬‬
‫;‪section1[k].person.code = code‬‬
‫‪/*** obtain marks for each course ***/‬‬

‫;)]‪find_tot(&section1[k‬‬
‫‪/* print result */‬‬
‫}‬
‫}‬

‫)‪void find_tot(stud_typ * stud‬‬


‫{‬
‫;‪int j, tot=0‬‬
‫)‪for (j=1;j<=stud->no_of_courses;j++‬‬
‫;]‪tot += stud->marks[j‬‬
‫;‪stud->tot = tot‬‬
‫}‬
‫رأﻳﻨــﺎ ﰱ اﳌﺜــﺎل اﻟﺴــﺎﺑﻖ ﻛﻴــﻒ ﳝﻜــﻦ أن ﻧﺘﻌﺎﻣــﻞ ﻣــﻊ اﳌﺘﺠــﻪ ‪ section1‬و ﻫــﻮ ﻣﺘﺠــﻪ ﻣــﻦ اﳍﻴﺎﻛــﻞ ﻣــﻦ ﻧــﻮع ‪ .stud_typ‬و إذا اﺣﺘــﻮى‬
‫اﳍﻴﻜﻞ ﻫﻴﺎﻛﻞ أﺧﺮى )ﻣﺜﻞ اﳍﻴﻜﻞ ‪ pers_type‬ﺑﺪاﺧﻞ اﳍﻴﻜﻞ ‪ (stud_typ‬رأﻳﻨﺎ ﻛﻴﻒ ﳝﻜﻦ اﻟﺘﻌﺎﻣﻞ ﻣﻊ ﻋﻨﺎﺻﺮ اﳍﻴﻜــﻞ اﻟــﺪاﺧﻠﻰ‬
‫ﺳــﺘﺨﺪام اﻟﻨﻘﻄــﺔ ﻣ ـﺮﺗﲔ‪ .‬و رأﻳﻨــﺎ أﻳﻀــﺎ ﻛﻴــﻒ ﳝﻜــﻦ أن ﻧﺘﻌﺎﻣــﻞ ﻣــﻊ ﻣﺘﺠــﻪ ﺑــﺪاﺧﻞ اﳍﻴﻜــﻞ ﻣﺜــﻞ اﳌﺘﺠــﻪ ‪ .marks‬ﻻﺣــﻆ ﰱ اﳌﺜــﺎل‬
‫اﻟﺴﺎﺑﻖ أن اﺳﻢ أى ﺣﻘﻞ ﰱ ﻫﻴﻜﻞ ﻟﻴﺲ ﻟﻪ ﻋﻼﻗﺔ ﺳﻢ ﻣﺘﻐﲑ آﺧﺮ ﺣﱴ و إن ﺗﺸﺎ ﺎ‪ .‬ﻓﺎﳊﺎﺳﺐ ﻻ ﳜﻠﻂ ﻣــﺜﻼ ﺑــﲔ اﳌﺘﻐــﲑ ‪ code‬و‬
‫اﳊﻘ ــﻞ ‪ code‬ﰱ اﳍﻴﻜ ــﻞ ‪ ،person‬ﻛﻤ ــﺎ ﻻ ﳜﻠ ــﻂ ﺑ ــﲔ اﳌﺘﻐ ــﲑ ‪ tot‬و اﳊﻘ ــﻞ ‪ tot‬ﰱ اﳍﻴﻜ ــﻞ ‪ .stud_typ‬ﻓ ــﺎﳌﺘﻐﲑ ﻟ ــﻪ ﺧﺎﻧ ــﺔ ذاﻛ ــﺮة‬
‫ﳏــﺘﻔﻆ ﻓﻴﻬــﺎ ﺑﻴﻨﻤــﺎ اﳊﻘــﻞ ﻟــﻪ ﺧﺎﻧــﺔ أﺧــﺮى ﺑــﺪاﺧﻞ اﳋــﺎ ت اﳌﺴــﺘﺨﺪﻣﺔ ﻟﻠﺤﻘــﻞ‪ .‬ﻻﺣــﻆ ﰱ اﻟﻨﻬﺎﻳــﺔ ﻛﻴــﻒ اﺳــﺘﺨﺪﻣﻨﺎ اﳌــﺆﺛﺮ ‪sizeof‬‬
‫ﳊﺴﺎب ﺳﻌﺔ اﻟﺘﺨﺰﻳﻦ اﳌﻄﻠﻮﺑﺔ ﻋﻨﺪ ﺣﺠﺰ اﳌﺘﺠﻪ ‪.section1‬‬

‫‪100‬‬
‫‪.4‬د‪ .2.‬اﻟﺴﻼﺳﻞ ‪linked lists‬‬
‫ﰱ ﻛﺜﲑ ﻣﻦ اﻟﺘﻄﺒﻴﻘﺎت ﳓﺘﺎج ﻟﻠﺘﻌﺎﻣﻞ ﻣﻊ ﺑﻴﺎ ت ﻣﺘﻌــﺪدة ﻣــﻦ ﻧﻔــﺲ اﻟﻨــﻮع و ﻟﻜــﻦ ﻻ ﻧﺴــﺘﻄﻴﻊ أو ﻳﺼــﻌﺐ اﺳــﺘﺨﺪام اﳌﺘﺠــﻪ‬
‫ﻷﺳ ــﺒﺎب ﺷ ــﱴ‪ .‬ﻣ ــﺜﻼ إذا ﻛ ــﺎن ﻣ ــﻦ ﻏ ــﲑ اﳌﻤﻜ ــﻦ أن ﻧﻌ ــﺮف ﻋــﺪد اﻟﻌﻨﺎﺻ ــﺮ إﻻ ﺑﻌ ــﺪ أن ﻧﻘ ـﺮأ ﲨﻴ ــﻊ ﻫ ــﺬﻩ اﻟﻌﻨﺎﺻ ــﺮ‪ .‬ﻻﺣ ــﻆ أن اﳊﺠ ــﺰ‬
‫اﻟــﺪﻳﻨﺎﻣﻴﻜﻰ اﻟــﺬى ﺗﻌﻠﻤﻨــﺎﻩ ﺳــﺎﺑﻘﺎ ﻟــﻦ ﳚــﺪى ﰱ ﻫــﺬﻩ اﳊﺎﻟــﺔ‪ ،‬ﺻــﺤﻴﺢ أن اﻷﺳــﻠﻮب اﻟــﺬى ﺗﻌﻠﻤﻨــﺎﻩ ﻻ ﻳﺸــﱰط ﻣﻌﺮﻓــﺔ اﻟﻌــﺪد ﻗﺒــﻞ ﺗﻨﻔﻴــﺬ‬
‫اﻟﱪ ﻣﺞ و ﻟﻜﻨﻪ ﻳﺸﱰط ﻣﻌﺮﻓﺔ ﻫﺬا اﻟﻌﺪد ﻗﺒﻞ اﻟﻘﺮاءة‪ .‬ﺗﻈﻬﺮ ﻫــﺬﻩ اﳊﺎﻟــﺔ ﻣــﺜﻼ إذا ﻛــﺎن ﻟــﺪﻳﻨﺎ ﺑﺮ ﳎــﺎ ﺟﺰﺋﻴــﺎ ﳛــﻞ ﻣﻌﺎدﻟــﺔ ﺗﻔﺎﺿــﻠﻴﺔ )ﻣﺜــﻞ‬
‫ﻣﻌﺎدﻟــﺔ ﻛﻼوزﻳــﻮس ﻛﻼﺑــﲑون اﻟــﱴ ﺗ ـﺮﺑﻂ ﺑــﲔ ﺿــﻐﻂ و درﺟــﺔ ﺣ ـﺮارة اﻟﺘﺸــﺒﻊ أو ﻣﻌﺎدﻟــﺔ اﳊﺎﻟــﺔ ﻟــﺪاﺋﺮة ﻛﻬﺮﺑﻴــﺔ ﺗ ـﺮﺑﻂ ﺑــﲔ اﻟــﺰﻣﻦ و اﳉﻬــﺪ‬
‫اﻟﻜﻬﺮﰉ ﰱ ﻧﻘﻄﺔ ﻣﺎ(‪ .‬ﺳﻨﻔﺮض ﻋﻤﻮﻣﺎ أن اﳌﺘﻐﲑ اﳌﺴﺘﻘﻞ ﻫﻮ ‪ x‬و اﻟﺘﺎﺑﻊ ‪ .y‬ﻳﻘﻮم اﻟﱪ ﻣﺞ اﳉﺰﺋﻰ ﲝﺴﺎب ﻗﻴﻤﺔ ‪ y‬اﳌﻨﺎﻇﺮة ﻟﻘﻴﻤــﺔ ﻣــﻦ‬
‫ﻗــﻴﻢ ‪ x‬ﰒ ﳛﺴــﺐ اﻟﻘﻴﻤــﺔ اﻟﺘﺎﻟــﺔ و ﻫﻜــﺬا‪ ،‬و ﻟﻜﻨــﻪ ﻳﻜﺜــﻒ اﻟﻨﻘــﺎط ﻋﻨــﺪ اﳌﻨــﺎﻃﻖ اﻟــﱴ ﺗﺘﻐــﲑ ﻓﻴﻬــﺎ ‪ y‬ﻛﺜ ـﲑا ﻟﻠﺤﻔــﺎظ ﻋﻠــﻰ ﻣﺴــﺘﻮى اﻟﺪﻗــﺔ‬
‫ﺑﺘﺎ‪ .‬ﻻ ﳝﻜﻦ إذن أن ﻧﻌﺮف ﻋﺪد اﻟﻨﻘﺎط ﻣﺴﺒﻘﺎ و ﻟﻜﻦ ﳚــﺐ اﻻﺣﺘﻔــﺎظ ﳊﻠــﻮل ﰱ ﻣﻜــﺎن ﻣــﺎ ﰱ اﻟــﺬاﻛﺮة ﺣــﱴ ﳝﻜــﻦ اﻟﺘﻌﺎﻣــﻞ ﻣﻌﻬــﺎ‬
‫ﻻﺣﻘﺎ‪ .‬ﻫﻨﺎك ﺣﺎﻟﺔ أﺧﺮى و ﻫﻰ ﺑــﺮ ﻣﺞ ﲢﻜــﻢ ﰱ آﻟــﺔ ﻣــﺎ ﻳــﺪار ﺑﻮاﺳــﻄﺔ اﻷﺣــﺪاث ‪ .event driven‬ﰱ ﻫــﺬا اﻟــﱪ ﻣﺞ ﻳﺒــﺪأ اﳊﺎﺳــﺐ‬
‫ﺑﻌﻤــﻞ ﻗﺎﺋﻤــﺔ ﻟﻌﻤﻠﻴــﺎت اﻟــﱴ ﺳــﻴﻘﻮم ــﺎ ﻟﻠــﺘﺤﻜﻢ ﰱ اﻵﻟــﺔ ﻣﺮﺗﺒــﺔ ﺗﺮﺗﻴﺒــﺎ زﻣﻨﻴــﺎ ﻣــﺎ‪ .‬إذا اﻗﺘﺼــﺮ اﻷﻣــﺮ ﻋﻠــﻰ ذﻟــﻚ ﻟﻜــﺎن ﻣــﻦ اﳌﻤﻜــﻦ وﺿــﻊ‬
‫ﻗﺎﺋﻤــﺔ اﻟﻌﻤﻠﻴــﺎت ﰱ ﻣﺘﺠــﻪ‪ .‬و ﻟﻜﻨــﻪ ﻳﺮاﻗــﺐ ﰱ ﻧﻔــﺲ اﻟﻮﻗــﺖ ﺑﻌــﺾ أﺟﻬــﺰة اﻟﻘﻴــﺎس أﺛﻨــﺎء اﻟﺘﺸــﻐﻴﻞ‪ .‬و ﻗــﺪ ﳛــﺪث ﺣــﺪ ﻣــﺎ ﳚﻌﻠــﻪ ﻳﻘــﺮر‬
‫اﻟﻘﻴﺎم ﺑﻌﻤﻠﻴﺔ إﺿﺎﻓﻴﺔ ﰱ زﻣــﻦ ﻻﺣــﻖ ﺑــﲔ ﻋﻤﻠﻴﺘــﲔ ﻣــﻦ اﻟﻌﻤﻠﻴــﺎت اﻟــﱴ ﲤــﺖ ﺑﺮﳎﺘﻬــﺎ ﰱ اﻟﺒﺪاﻳــﺔ‪ .‬ﻋــﺪد اﻟﻌﻤﻠﻴــﺎت و ﻟﺘــﺎﱃ ﻋــﺪد ﻋﻨﺎﺻــﺮ‬
‫اﳌﺘﺠﻪ ﻻ ﳝﻜﻦ أن ﻳﻌﺮف ﰱ ﺑﺪاﻳﺔ اﻟﱪ ﻣﺞ و ﻟﻴﺲ ﻫﺬا ﻓﻘﻂ و ﻟﻜــﻦ إﺿــﺎﻓﺔ ﻋﻨﺼــﺮ ﺟﺪﻳــﺪ ﺑــﲔ ﻋﻨﺎﺻــﺮ ﺳــﺎﺑﻘﺔ ﻳﻌﺘــﱪ ﻣﻜﻠــﻒ إذا ﻗﻤﻨــﺎ‬
‫ﺑﱰﺣﻴﻞ ﻛﻞ اﻟﻌﻨﺎﺻﺮ اﻟﺘﺎﻟﻴﺔ ﰱ ﻛﻞ ﻣﺮة‪.‬‬

‫ﳊــﻞ ﺗﻠــﻚ اﳌﺸــﻜﻠﺔ اﺑﺘﻜــﺮت اﻟﻘـﻮاﺋﻢ اﳌﺘﺼــﻠﺔ أو اﻟﺴﻼﺳــﻞ ‪ .linked lists‬ﰱ ﻫــﺬﻩ اﻟﻄﺮﻳﻘــﺔ ﻧﺒــﺪأ ﺑﺘﺸــﻜﻴﻞ ﻫﻴﻜــﻞ ﺣﻘﻮﻟــﻪ‬
‫ﲢﻮى ﲨﻴﻊ اﻟﺒﻴﺎ ت اﳌﻄﻠﻮب ﺣﻔﻈﻬﺎ ﻋﻦ ﻷى ﻋﻨﺼﺮ ﻣﻦ اﻟﻘﺎﺋﻤﺔ و ﻧﻀﻴﻒ ﻋﻠﻴﻪ ﺣﻘﻼ إﺿﺎﻓﻴﺎ ﻋﺒﺎرة ﻋﻦ ﻣﺆﺷﺮ ﻳﺸﲑ ﻟﻠﻌﻨﺼــﺮ اﻟﺘــﺎﱃ‬
‫ﰱ اﻟﻘﺎﺋﻤﺔ‪ .‬ﺳﻨﻮﺿﺢ ذﻟﻚ ﺳﺘﺨﺪام ﻣﺜﺎل اﳌﻌﺎدﻻت اﻟﺘﻔﺎﺿﻠﻴﺔ‪ .‬ﻧﺒﺪأ ﺑﺘﻌﺮﻳﻒ اﳍﻴﻜﻞ‪:‬‬
‫;‪typedef struct point * pt‬‬
‫‪typedef struct point‬‬
‫{‬
‫;‪double x,y‬‬
‫‪pt‬‬ ‫;‪next‬‬
‫;‪}point_typ‬‬

‫اﳍﻴﻜﻞ ‪ point_typ‬ﳛﻮى ﺣﻘﻠﲔ ﻟﻠﻤﺘﻐﲑ اﳌﺴﺘﻘﻞ و اﻟﺘــﺎﺑﻊ ﻋﻠــﻰ اﻟﱰﺗﻴــﺐ‪ ،‬ﻹﺿــﺎﻓﺔ ﳊﻘــﻞ ﻣــﻦ ﻧــﻮع ﻣﺆﺷــﺮ اﲰــﻪ ‪ next‬ﻳﺸــﲑ ﳍﻴﻜــﻞ‬
‫ﻣﻦ ﻧﻔﺲ اﻟﻨﻮع‪) .‬ﻻﺣﻆ أﻧﻨﺎ ﻋﺮﻓﻨﺎ اﻟﻨﻮع ‪ pt‬ﻛﻤﺆﺷﺮ ﳍﻴﻜﻞ ﱂ ﻳﻜﻦ ﻗﺪ ﻋﺮف ﺑﻌﺪ و ﻟﻜﻦ أﺗﻰ اﻟﺘﻌﺮﻳﻒ ﺑﻌﺪ ذﻟــﻚ و ﻫــﻮ أﻣــﺮ ﻣﺴــﻤﻮح‬
‫ﺑﻪ ﰱ ﻟﻐﺔ ال‪ C‬ﻟﻠﻤﺆﺷﺮات ﻓﻘﻂ ﳊﻞ ﻧﻮع ﻣــﺎ ﻣــﻦ اﳌﺸــﺎﻛﻞ ﺳــﻨﺬﻛﺮﻫﺎ ﰱ ﺣﻴﻨﻬــﺎ(‪ .‬ﺑﻌــﺪ ذﻟــﻚ ﳝﻜــﻦ ﻛﺘﺎﺑــﺔ ﺑــﺮ ﻣﺞ رﺋﻴﺴــﻰ ﻳﻘــﻮم ﻵﺗــﻰ‪.‬‬
‫ﻳﺒــﺪأ ﲝﺠــﺰ ﻫﻴﻜــﻞ ﻣــﻦ ﻧــﻮع ‪ point‬ﻳﻀــﻊ ﻋﻨﻮاﻧــﻪ ﰱ ﻣﺆﺷــﺮ ﺳﻨﺴــﻤﻴﻪ ‪ actual‬ﻟﻨﻀــﻊ ﻓﻴــﻪ اﻟﻘــﻴﻢ اﻻﺑﺘﺪاﺋﻴــﺔ ‪ .initial conditions‬ﰒ‬
‫ﻳﻘــﻮم ﺑﺘﻌﺮﻳــﻒ ﻣﺆﺷــﺮ ﻋــﺎم ﺳﻨﺴــﻤﻴﻪ ‪ first‬ﻳﺸــﲑ ﻷول ﻋﻨﺼــﺮ ﰱ اﻟﺴﻠﺴــﻠﺔ و ﻫــﻮ ﻫﻨــﺎ اﳍﻴﻜــﻞ اﻟــﺬى وﺿــﻌﻨﺎ ﻓﻴــﻪ اﻟﻘﻴﻤــﺔ اﻻﺑﺘﺪاﺋﻴــﺔ‪ .‬ﰒ‬
‫ﻧﻄﻠــﺐ ﻣــﻦ اﻟــﱪ ﻣﺞ اﳉﺰﺋــﻰ اﻟــﺬى ﳛــﻞ اﳌﻌﺎدﻟــﺔ اﻟﺘﻔﺎﺿــﻠﻴﺔ أن ﳛﺴــﺐ اﻟﻨﻘﻄــﺔ اﻟﺘﺎﻟﻴــﺔ‪ ،‬و ﻧ ـﻮاﱃ اﻟﻄﻠــﺐ ﰱ ﻋﻤﻠﻴــﺔ ﺗﻜﺮارﻳــﺔ ﺣــﱴ ﻧﺼــﻞ‬
‫ﻟﻠﻘﻴﻤﺔ اﻟﻨﻬﺎﺋﻴــﺔ ﻟﻠﻤﺘﻐــﲑ اﳌﺴــﺘﻘﻞ اﳌﺮﺟــﻮة ‪ .xfinal‬ﻋﻨــﺪ ﺣﺴــﺎب أﻳــﺔ ﻧﻘﻄــﺔ ﺟﺪﻳــﺪة ﻧﻄﻠــﺐ ﺣﺠــﺰ ﻫﻴﻜــﻞ ﺟﺪﻳــﺪ ﻧﻀــﻊ ﻋﻨﻮاﻧــﻪ ﰱ ﺣﻘــﻞ‬
‫ﻣﻦ ﺣﻘﻮل اﳍﻴﻜﻞ اﻟﺴﺎﺑﻖ و ﻫﻮ اﳊﻘﻞ ‪ .next‬و ﺑﺬﻟﻚ ﺗﺘﻜﻮن اﻟﺴﻠﺴﻠﺔ و ﺗﺼﺒﺢ ﻋﻠﻰ اﻟﺼﻮرة‪:‬‬

‫‪101‬‬
first x x x
y y ... y
next next next NULL

‫ﻋﻨﺪ اﻧﺘﻬﺎء اﻟﻌﻤﻠﻴﺔ اﻟﺘﻜﺮارﻳﺔ ﳝﻜﻦ ﻋﻤﻞ أﻳﺔ ﻋﻤﻠﻴﺔ ﻋﻠﻰ اﻟﻘﻴﻢ اﶈﺴــﻮﺑﺔ ﻣﺜــﻞ ﺣﺴــﺎب ﻣﻨﺤــﲎ ﺗﻘـﺮﻳﱮ ﳝــﺮ أﻗــﺮب ﻣــﺎ ﳝﻜــﻦ ﻣــﻦ‬
‫ ﺳﻨﺨﺘﺎر ﰱ ﻫﺬا اﻟﱪ ﻣﺞ ﻋﻤﻠﻴــﺔ ﺑﺴــﻴﻄﺔ ﻟﻠﺘﻮﺿــﻴﺢ و ﻫــﻰ ﻃﺒﺎﻋــﺔ ﲨﻴــﻊ اﻟﻨﻘــﺎط إذا ﲢﻘــﻖ اﻟﺸــﺮط‬،‫ﲨﻴﻊ اﻟﻨﻘﺎط أو رﺳﻢ اﻟﺪاﻟﺔ إﱃ آﺧﺮﻩ‬
.‫اﻵﺗﻰ و ﻫﻮ أن ﺗﻜﻮن ﻗﻴﻤﺔ اﳌﺘﻐﲑ اﻟﺘﺎﺑﻊ اﻟﻨﻬﺎﺋﻴﺔ أﻗﻞ ﻣﻦ ﻗﻴﻤﺔ ﻋﻈﻤﻰ ﻣﺎ ﺗﻌﻄﻰ ﰱ ﺑﺪاﻳﺔ اﻟﱪ ﻣﺞ‬

void get_next_point ( /* Procedure to get next point*/


double x1, double y1, /* Initial condition */
double *x2, double y2); / * Data for next point */

void main(void)
{
pt first, actual;
double xinit, yinit, xfinal, ymax;
double x,y;

printf ("Enter initial conditions:" );


scanf ("%lg %lg",&xinit,&yinit);
printf ("Enter final x and maximum value of y:");
scanf ("%lg %lg",&xfinal.&ymax);

actual = (pt) malloc(sizeof(point_typ));


actual->x = xinit;
actual->y = yinit;
first = actual;

while(1)
{ get_next_point(actual->x,actual->y,&x,&y);
if (x > xfinal)
{
actual->next = NULL;
break;
}
actual->next = (pt) malloc(sizeof(point_typ));
actual = actual->next;
actual->x = x;
actual->y = y;
}
if (y >= ymax)
{ printf("No value to be printed\n"); exit(1);
}
actual = first;
while (actual)
{ printf("x=%lg \t y=%lg\n",actual->x,actual->y);
actual = actual->next;
}

102
‫}‬
‫ﻣــﻦ أﻧـﻮاع اﻟﺴﻼﺳــﻞ اﻟﺸــﻬﲑة ﻧــﻮﻋﲔ ﻗﺎﺋﻤــﺔ اﻻﻧﺘﻈــﺎر ‪ queue‬و اﳌـﺮاﻛﻢ ‪ .stack‬ﻗﺎﺋﻤــﺔ اﻻﻧﺘﻈــﺎر ﻋﺒــﺎرة ﻋــﻦ ﺳﻠﺴــﻠﺔ ﻋﺎدﻳــﺔ ﻳﻮﺿــﻊ أى‬
‫ﻋﻨﺼــﺮ ﺟﺪﻳــﺪ ﻓﻴﻬــﺎ ﰱ ﺎﻳــﺔ اﻟﺴﻠﺴــﻠﺔ‪ .‬و ﺣﻴﻨﻤــﺎ ﻧﺒــﺪأ ﰱ ﻣﻌﺎﳉــﺔ اﻟﺒﻴــﺎ ت اﳌﺨﺰﻧــﺔ ﻓﺈﻧﻨــﺎ ﻧﺒــﺪأ داﺋﻤــﺎ ول ﻋﻨﺼــﺮ ﰱ اﻟﺴﻠﺴــﻠﺔ‪ .‬أى أﻧﻨــﺎ‬
‫ﻧﻌــﺎﰿ داﺋﻤــﺎ اﻟﻌﻨﺎﺻــﺮ ﺑــﻨﻔﺲ ﺗﺮﺗﻴــﺐ اﻟــﺪﺧﻮل ﺗﺒﻌــﺎ ﻟﻠﻘﺎﻋــﺪة ‪ .FIFO = First In First Out‬اﳌﺜــﺎل اﻟﺴــﺎﺑﻖ ﻣــﻦ ﻫــﺬا اﻟﻨــﻮع‪ .‬ﳝﻜــﻦ‬
‫أﻳﻀﺎ أن ﻳﻌﻤﻞ ﺑﺮ ﻣﺞ اﻟﺘﺤﻜﻢ ﺬا اﻷﺳﻠﻮب ﺣﻴﺚ أﻧﻪ ﻣﻦ اﳌﻤﻜﻦ داﺋﻤﺎ إﺿﺎﻓﺔ ﻋﻨﺼﺮ ﰱ ﻣﻜﺎن ﻣﺘﻮﺳﻂ ﻣﻦ اﻟﺴﻠﺴﻠﺔ )ﻛﻤﺎ ﺳــﻨﺮى‬
‫ﻓﻴﻤــﺎ ﺑﻌــﺪ(‪ .‬أﻣــﺎ اﳌ ـﺮاﻛﻢ ﻓﻬــﻮ أﻳﻀــﺎ ﺳﻠﺴــﻠﺔ ﻋﺎدﻳــﺔ و ﻟﻜﻨــﻪ ﻋﻠــﻰ اﻟﻌﻜــﺲ ﻣــﻦ ﻗﺎﺋﻤــﺔ اﻻﻧﺘﻈــﺎر‪ ،‬ﻧــﺪﺧﻞ ﻛــﻞ ﻋﻨﺼــﺮ ﺟﺪﻳــﺪ ﰱ ﺑﺪاﻳــﺔ‬
‫اﻟﺴﻠﺴﻠﺔ‪ ،‬ﲝﻴﺚ ﻧﺒﺪأ داﺋﻤــﺎ ﲟﻌﺎﳉــﺔ أﺧــﺮ ﻋﻨﺼــﺮ ﰎ إدﺧﺎﻟــﻪ و ﻧﻨﺘﻬــﻰ وﳍــﻢ‪ .‬ﻣــﻦ اﻻﺳــﺘﺨﺪاﻣﺎت اﻟﺸــﻬﲑة ﻟﻠﻤـﺮاﻛﻢ ﺑــﺮ ﻣﺞ ﻳــﺪرس ﺗﻌﺒــﲑ‬
‫ر ﺿــﻰ ﺑــﻪ أﻗ ـﻮاس‪ ،‬ﻓﺤﻴﻨﻤــﺎ ﻧﻐﻠــﻖ ﻗــﻮس ﻳﻨﺒﻐــﻰ أن ﻧﺒﺤــﺚ ﻋــﻦ أﺧــﺮ ﻗــﻮس ﻣﻔﺘــﻮح ﰎ إدﺧﺎﻟــﻪ ﻟﻨﻌــﺎﰿ اﻟﺒﻴــﺎ ت اﻟ ـﻮاردة ﺑﻴﻨﻬﻤ ـﺎ ﰒ ﻧﻨﺘﻈــﺮ‬
‫اﻟﻘﻮس اﳌﻐﻠﻖ اﻟﺘﺎﱃ ﻟﻨﻌﺎﰿ اﻟﻘﻮس اﳌﻔﺘﻮح اﻟﺴﺎﺑﻖ إﱃ آﺧﺮﻩ‪.‬‬
‫ﳝﻜﻦ أن ﳛﺘﻮى اﻟﻌﻨﺼﺮ ﻋﻠﻰ أﻛﺜــﺮ ﻣــﻦ ﻣﺆﺷــﺮ ﻳﺸــﲑ إﱃ أﻛﺜــﺮ ﻣــﻦ ﻋﻨﺼــﺮ ل ﻟــﻪ ﰱ اﻟﱰﺗﻴــﺐ ﲝﻴــﺚ ﳝﻜــﻦ ﻣــﺜﻼ ﺑﻨــﺎء ﺷــﺠﺮة‬
‫ﻣﻦ اﳌﻌﻠﻮﻣﺎت ‪ .tree‬إذا اﻋﺘــﱪ اﻟﺴﻠﺴــﻠﺔ ﻧﻈـﲑا ﻟﻠﻤﺘﺠــﻪ ﻣــﻊ إﻣﻜﺎﻧﻴــﺎت ﺧﺎﺻــﺔ إﺿــﺎﻓﻴﺔ‪ ،‬ﻓــﺈن اﻟﺸــﺠﺮة ﻫــﻰ ﻧﻈــﲑ ﻟﻠﻤﺼــﻔﻮﻓﺔ ﻣــﻊ ﻋﺪﻳــﺪ‬
‫ﻣﻦ اﻹﻣﻜﺎﻧﻴﺎت اﻹﺿﺎﻓﻴﺔ ﻣﻨﻬﺎ إﻣﻜﺎﻧﻴﺔ اﻟﺘﻌﺎﻣــﻞ ﻣــﻊ اﳌﺼــﻔﻮﻓﺎت ﺷــﺒﻪ اﳋﺎوﻳــﺔ ‪ sparse matrices‬و اﻟــﱴ ﺗﻈﻬــﺮ ﰱ أﻏﻠــﺐ ﺗﻄﺒﻴﻘــﺎت‬
‫اﳊﺴﺎب اﻟﻌﻠﻤﻰ و ﻟﻜﻦ ﺷﺮﺣﻬﺎ ﳜﺮج ﻋﻦ ﳎﺎل ﻫﺬﻩ اﻟﺴﻄﻮر‪.‬‬

‫‪.4‬د‪ .3.‬ﻋﻤﻠﻴﺎت أﺳﺎﺳﻴﺔ‬


‫ﻣــﻦ اﻟﻌﻤﻠﻴ ــﺎت اﻷﺳﺎﺳ ــﻴﺔ اﻟ ــﱴ ﺳﻨﻮﺿ ــﺤﻬﺎ ﻋﻤﻠﻴ ــﺔ إﺿــﺎﻓﺔ ﻋﻨﺼ ــﺮ ﻟﺴﻠﺴ ــﻠﺔ ﰱ ﻣﻜ ــﺎن ﻣ ــﺎ ﻟ ــﻴﺲ ﰱ ﺑ ــﺪاﻳﺘﻬﺎ و ﻻ ﺎﻳﺘﻬ ــﺎ‪ ،‬و‬
‫ﺳــﻨﻜﺘﻔﻰ ﻟﺘﻮﺿــﻴﺤﻪ ﻟﺸــﻜﻞ اﳌﺒــﲔ و ﺳــﻄﻮر اﻟﱪﳎــﺔ اﳌﻌــﱪة ﻋﻨــﻪ و اﻟــﱴ ﺗﻔــﱰض أﻧﻨــﺎ ﺑﺼــﺪد إﺿــﺎﻓﺔ ﻋﻨﺼــﺮ ﺟﺪﻳــﺪ ﺳﻨﻀــﻊ ﻋﻨﻮاﻧــﻪ ﰱ‬
‫اﳌﺆﺷﺮ ‪ second‬ﺑﻌﺪ اﻟﻌﻨﺼﺮ اﳌﺨﺘﺰن ﻋﻨﻮاﻧﻪ ﰱ ‪.actual‬‬

‫اﻟﺨﻄﻮة‬ ‫‪actual‬‬ ‫اﻟﺨﻄﻮة‬


‫‪actual‬‬ ‫اﻟﺨﻄﻮة‬ ‫‪actual‬‬
‫اﻟﺜﺎﻧﯿﺔ‬ ‫اﻷوﻟﻰ‬
‫اﻟﺜﺎﻟﺜﺔ‬
‫إدﺧﺎﻟﮫ ﻋﻠﻰ‬
‫ﻟ‬
‫‪x,y‬‬ ‫‪x,y‬‬ ‫‪x,y‬‬ ‫‪x,y‬‬
‫‪x,y‬‬ ‫‪x,y‬‬
‫‪next‬‬ ‫‪next‬‬ ‫‪next‬‬ ‫‪next‬‬
‫‪next‬‬ ‫‪next‬‬

‫‪x,y‬‬ ‫‪second‬‬ ‫‪x,y‬‬


‫‪second‬‬ ‫‪x,y‬‬ ‫‪second‬‬
‫‪next‬‬ ‫‪next‬‬
‫‪next‬‬

‫;‪pt second‬‬
‫;‪…………………..‬‬
‫;))‪second = (pt) malloc(sizeof(point_typ‬‬ ‫‪/* first step */‬‬
‫;‪second->next = actual->next‬‬ ‫‪/* second step */‬‬
‫;‪actual->next = second‬‬ ‫‪/* third step*/‬‬

‫‪103‬‬
:‫أﻣﺎ إزاﻟﺔ ﻋﻨﺼﺮ ﻣﻦ اﻟﺴﻠﺴﻠﺔ ﻓﺴﻴﺘﻢ ﺷﺮﺣﻪ أﻳﻀﺎ ﺳﺘﺨﺪام اﻟﺸﻜﻞ اﻟﺘﺎﱃ و اﻟﱪ ﻣﺞ اﳌﺮاﻓﻖ ﻟﻪ‬
actual
actual ‫اﻟﺧطوة اﻟﺛﺎﻧﯾﺔ‬ actual
actual ‫اﻟﺧطوة اﻷوﻟﻰ‬ actual
actual ‫اﻟﺣﺎﻟﺔ‬
‫اﻟﻣﺳﺢ‬ ‫اﻟﺗﺧطﻰ‬ ‫اﻻﺑﺗداﺋﯾﺔ‬

x,y
x,y x,y
x,y x,y
x,y x,y
x,y x,y
x,y x,y
x,y
next
next next
next next
next next
next next
next next
next

second
second second
second x,y
x,y x,y
x,y
next second
second
next next
next

pt second;
…………………..;
actual->next = second->next; /* first step */
free (second); /* second step*/

.malloc ‫ ﳛﺮر اﻟﺬاﻛﺮة و ﻫﻮ ﻋﻜﺲ اﻷﻣﺮ‬free ‫اﻷﻣﺮ‬

104
‫ ﻣﺴﺎﺋﻞ ﻣﺸﻬﻮرة‬.‫ه‬.4

binary search ‫اﻟﺒﺤﺚ ﻋﻦ ﻋﻨﺼﺮ ﰱ ﻣﺘﺠﻪ ﻣﺮﺗﺐ ﺗﺮﺗﻴﺒﺎ ﺗﺼﺎﻋﺪ‬


#include <stdio.h>
#include <process.h>
#include <conio.h>

void get_vec(int * x,int *n)


{
FILE *fil;
fil=fopen("inp_file.dat","r");
*n=0;
while (!feof(fil))
{
(*n)++;
fscanf(fil,"%d",&x[*n]);
}
}

int bin_search(int *x, /*the vector we are searching in*/


int n, /*its size*/
int xref) /*the value we are looking for*/
{
int first,last,middle;
first= 1;
last = n;
while (first <= last)
{
middle = (first + last) / 2;
if (xref == x[middle])
return(middle);
if (xref < x[middle])
last = middle - 1;
else
first = middle +1;
}
if (xref == x[first])
return first;
if (xref == x[last])
return last;
return 0;
}

void main (void)


{
int x[30];
int n,loc;
int xref;

get_vec(x,&n);
printf("Enter the number you look for : ");
scanf("%d",&xref);
loc= bin_search(x,n,xref);
if (loc)
printf("It is in the location: %d\n",loc);
else printf("Value not found\n");
getch();
}

105
selection sorting ‫إﻋﺎدة ﺗﺮﺗﻴﺐ ﻣﺘﺠﻪ ﺳﺘﺨﺪام ﻃﺮﻳﻘﺔ اﻟﱰﺗﻴﺐ اﻻﻧﺘﻘﺎﺋﻰ‬
#include <stdio.h>
#include <process.h>
#include <conio.h>

void get_vec(int * x,int *n)


{/* see above */}

void sel_sort(int * x, /*the vector we need to sort*/


int n) /*its size*/
{
int i,j, temp;
for (i= 1;i<= n-1; i++)
{
for (j= i+1;j<=n;j++)
{
if (x[j] < x[i])
{
temp = x[i];
x[i] = x[j];
x[j] = temp;
}
}
}
}
void main (void)
{ int x[30]; int n,i;
get_vec(x,&n);
sel_sort(x,n);
for (i=1;i<=n;i++)
printf("%d %d\n",i,x[i]);
getch();
}
‫ و ﻟﻜﻨﻨــﺎ ﺳﻨﺴــﺘﺪﻋﻰ‬،‫ ﻳﺸــﺒﻪ ذﻟــﻚ اﻟــﱪ ﻣﺞ اﻟــﱪ ﻣﺞ اﻟﺴــﺎﺑﻖ‬.bubble sorting ‫إﻋــﺎدة ﺗﺮﺗﻴــﺐ ﻣﺘﺠــﻪ ﺳــﺘﺨﺪام ﻃﺮﻳﻘــﺔ ﺗﺮﺗﻴــﺐ اﻟﻔﻘﺎﻋــﺔ‬
.sel_sort ‫ ﺑﺪﻻ ﻣﻦ اﻟﺪاﻟﺔ اﻟﺴﺎﺑﻘﺔ‬bub_sort ‫اﻟﺪاﻟﺔ اﳉﺪﻳﺪة‬
void bub_sort(int *x, /* the vector we need to sort*/
int n) /*its size*/
{
int i,pass;
int temp;
char modified;
pass = 1;
do
{
modified = 0;
for (i= 1; i<=n-pass; i++)
{
if (x[i] > x[i+1])
{
modified = 1;
temp = x[i]; x[i] = x[i+1]; x[i+1] = temp;
}
}
pass = pass +1;
} while (modified);
}

106
‫ ﻹﻋــﺎدة اﻟﱰﺗﻴــﺐ )ﺑــﺪﻻ ﻣــﻦ‬ins_sort ‫ ﺳﻨﺴــﺘﺪﻋﻰ اﻟﺪاﻟــﺔ‬.insertion sorting ‫إﻋــﺎدة ﺗﺮﺗﻴــﺐ ﻣﺘﺠــﻪ ﺳــﺘﺨﺪام ﻃﺮﻳﻘــﺔ ﺗﺮﺗﻴــﺐ اﻹدراج‬
:‫ و اﻟﱴ ﲢﺘﺎج ﺑﺪورﻫﺎ ﻟﻠﺪاﻟﺔ اﻟﺘﺎﻟﻴﺔ‬،(bub_sort
int shift_vec(int * x,
int NextPos,
int NextVal)
{
while (NextPos > 1)
{
if (x[NextPos-1] > NextVal)
{
x[NextPos] = x[NextPos - 1];
NextPos = NextPos -1;
} else
{ break;
}
}
return NextPos;
}
void ins_sort(int *x, /* the vector we need to sort*/
int n) /*its size*/
{
int NextPos,NewPos;
int NextVal;
for (NextPos= 2;NextPos<=n;NextPos++)
{
NextVal = x[NextPos];
NewPos=shift_vec(x,NextPos,NextVal);
x[NewPos] = NextVal;
}
}
:‫ و اﻟﱴ ﲢﺘﺎج ﺑﺪورﻫﺎ ﻟﻠﺪاﻟﺔ اﻟﺘﺎﻟﻴﺔ‬Heap_sort ‫ ﺳﻨﺴﺘﺪﻋﻰ اﻟﺪاﻟﺔ‬.heap ‫إﻋﺎدة اﻟﱰﺗﻴﺐ ﺳﺘﺨﺪام‬
void AddTop(int *A, int top, int last)
{
int i,j; eletyp x;
i=top; j=2*i; x=A[i];
while (j <= last) What is a heap?
{
if (j < last) Ai < = A2i NB: A1 is the
if (A[j] > A[j+1]) j++;
if (x <= A[j]) break; Ai < = A2i+1 smallest elem.
A[i]=A[j]; i=j; j=2*i;
} A1
A[i]=x; Height
} = log2(n)
void Heap_sort(int *A, int n) A2 A3
{
int top, last; eletyp x;
top = n/2 + 1; last = n;
while (top > 1)
{ top--; AddTop(A,top,last);} A4 A5 A6 A7
while (last > 1)
{
x=A[1];A[1]=A[last];A[last]=x;
last--; AddTop(A,top,last);
}
}

107

Das könnte Ihnen auch gefallen