0% found this document useful (0 votes)
909 views

Programming PDF

This document is a textbook in Arabic on the basics of computer programming in C language. It covers fundamental concepts such as what is a computer, representing data and operations, constructing programs, basic language instructions in C, program statements like input/output, control flow, advanced data structures, and common problems. The textbook is intended for an introductory programming course at Al-Mansoura University's College of Engineering.

Uploaded by

Mohamed Sameh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
909 views

Programming PDF

This document is a textbook in Arabic on the basics of computer programming in C language. It covers fundamental concepts such as what is a computer, representing data and operations, constructing programs, basic language instructions in C, program statements like input/output, control flow, advanced data structures, and common problems. The textbook is intended for an introductory programming course at Al-Mansoura University's College of Engineering.

Uploaded by

Mohamed Sameh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 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

You might also like