-
Notifications
You must be signed in to change notification settings - Fork 19
/
Chapter_II-6.tex
751 lines (632 loc) · 28.7 KB
/
Chapter_II-6.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
\chapter{أنشئ أنواع متغيرات خاصّة بك}
تسمح لغة \textenglish{C}
بالقيام بشيء يعتبر قويًا جدًا: وهو أن ننشئ أنواعًا خاصة بنا، "أنواع متغيّرات مخصّصة". سنرى نوعين: الهياكل
(\textenglish{Structures})
و التعدادات
(\textenglish{Enumerations}).
إن إنشاء أنواع خاصّة بنا يعتبر أمرًا ضروريا خاصة إذا أردنا إنشاء برامج أكثر تعقيدًا.
الأمر ليس (لحسن الحظّ) بالصعب، لكن ركّز جيّدا لأننا سنستعمل الهياكل كل الوقت انطلاقا من الفصل القادم.\\
يجب أن تعلم أنّ المكتبات تنشئ غالبا أنواعها الخاصّة. لن يمرّ وقت كثير حتّى تستخدم نوعا يدعى "ملف"، وبعده بقليل، أنواع أخرى مثل "نافذة"، "صوت"، "لوحة مفاتيح"، إلخ.
\section{تعريف هيكل}
الهيكل هو تجميع لعدد من المتغيرات التي يمكن لها أن تحمل أنواعا مختلفة. على عكس الجداول التي ترغمنا على استعمال خانات من نفس النوع في كلّ الجدول، بإمكانك تعريف هيكل يحمل الأنواع:
\InlineCode{long}، \InlineCode{char}، \InlineCode{int}
و
\InlineCode{double}
في مرّة واحدة.
الهياكل في أغلب الأحيان معرّفة في ملفات
\InlineCode{.h}
مثلما رأينا مع
\InlineCode{\#define}
و نماذج الدوال. هذا مثال عن هيكل:
\begin{Csource}
struct StructureName
{
int variable1;
int variable2;
int anotherVariable;
double decimalNumber;
};
\end{Csource}
لتعريف هيكل، يجب علينا أن نبدأ بالكلمة المفتاحية
\InlineCode{struct}،
متبوعة باسم الهيكل (مثلا
\InlineCode{File}
أو
\InlineCode{Screen}).
\begin{information}
شخصيّا لديّ عادة في تسمية هياكلي بنفس قواعد تسمية المتغيّرات، باستثناء أنّي أجعل أوّل حرف كبيرا للتفريق. هكذا، عندما أرى الكلمة
\InlineCode{captainAge}
في شفرتي، أعلم أنّها متغيّر لأنّها تبدأ بحرف صغير. عندما أرى
\InlineCode{AudioPart}
فأعلم أنّها هيكل (نوع مخصّص) لأنّها تبدأ بحرف كبير.
\end{information}
بعد ذلك، نفتح حاضنة لنغلقها لاحقًا تماما مثل الدوال.
\begin{critical}
اِحذر، الأمر خاصّ هنا: بالنسبة للهياكل، يجب أن تضع بعد الحاضنة النهائية فاصلة منقوطة. هذا أمر إجباري. إن لم تفعله فستتوقّف الترجمة.
\end{critical}
و الآن، ماذا نضع داخل الحاضنتين؟\\
هذا سهل، سنضع المتغيرات التي يتكون منها الهيكل، وعادة ما يتكون الهيكل من "مُتَغَيِّريْن داخِلِيَيْن" على الأقل، وإلا فلن يحمل معنًى كبيرا.
كما ترى، فإنشاء نوع متغيّرات مخصّص ليس بالأمر الصعب. كلّ الهياكل ماهي إلّا "تجميعات" لمتغيّرات من أنواع قاعديّة مثل
\InlineCode{long}، \InlineCode{int}، \InlineCode{double}،
إلخ. لا توجد معجزة، إنّ نوعا
\InlineCode{File}
مثلًا ما هو إلا مجموعة من الأعداد القاعديّة!
\subsection{مثال عن هيكل}
تخيل أنك تريد إنشاء متغيّر لكي يٌخزّن إحداثيات نقطة في معلم الشاشة. ستحتاج بالتأكيد إلى هيكل كهذا عندما تبدأ في برمجة ألعاب ثنائية الأبعاد في الجزء التالي من الكتاب، هذه إذن فرصة للتقدّم قليلا.
إذا كانت كلمة "علم الهندسة" تُحدث ظهور بُقَع غير مفهومة على كامل وجهك، فالمخطّط التالي سيذكّرك قليلا بأساسيّات الأبعاد الثنائيّة (\textenglish{2D}).
\begin{figure}[H]
\centering
\includegraphics[width=0.4\textwidth]{Chapter_II-6_Axis}
\end{figure}
عندما نعمل في
\textenglish{2D}
لدينا محوران: محور الفواصل (من اليسار إلى اليمين) ومحور التراتيب (من الأسفل إلى الأعلى). من العادة أن نرمز للفواصل بمتغيّر يدعى
\InlineCode{x}
و للتراتيب بـ\InlineCode{y}.
هل يمكنك كتابة هيكل
\InlineCode{Coordinates}
يسمح بتخزين كلّا من الفاصلة
(\InlineCode{x})
و الترتيبة
(\InlineCode{y})
لنقطة ما؟\\
هيّا، هيّا، الأمر ليس صعبا:
\begin{Csource}
struct Coordinates
{
int x; // Abscissas
int y; // Ordinates
};
\end{Csource}
هيكلنا يسمّى
\InlineCode{Coordinates}
و هو متكوّن من متغيرين
\InlineCode{x}
و
\InlineCode{y}
أي الفاصلة
(\textenglish{Abscissa})
و الترتيبة
(\textenglish{Ordinate}).
إن أردنا، يمكننا بسهولة إنشاء هيكل
\InlineCode{Coordinates}
من أجل
\textenglish{3D}:
يكفي فقط إضافة متغيّر ثالث (مثلا
\InlineCode{z})
يدلّ على الارتفاع. بهذا سيكون لدينا هيكل لإدارة النقاط الثلاثيّة الأبعاد في الفضاء!
\subsection{جدول داخل هيكل}
يمكن للهياكل أن تحتوي على جداول. هذا جيّد، إذ يمكننا أن نضع داخلها جداول
\InlineCode{char}،
(سلاسل محرفيّة) بدون أيّة مشاكل.\\
فلنتخيل هيكلًا
\InlineCode{Person}
و الذي يحتوي على معلومات عن شخص:
\begin{Csource}
struct Person
{
char firstName[100];
char lastName[100];
char address[1000];
int age;
int boy; // Boolean : 1 = boy, 0 = girl
};
\end{Csource}
هذا الهيكل متشكّل من 5 متغيرات داخليّة، الثلاث الأولى هي سلاسل محرفيّة لتخزين الاسم، اللقب والعنوان.\\
المتغيران الأخيران يخزّنان عُمر وجنس الشخص. الجنس هو متغيّر منطقي، 1 = صحيح = ولد و0 = خطأ = بنت.
يمكن لهذا الهيكل أن يساعدنا في كتابة برنامج مذكّرة عناوين. يمكنك بالطبع إضافة القدر الذي تريد من المتغيرات داخل الهيكل من أجل إتمامها إذا أردت. لا يوجد حدّ لعدد المتغيّرات في هيكل.
\section{استعمال هيكل}
و الآن، بما أن الهيكل معرّف في ملف
\InlineCode{.h}،
سنتمكّن من استعماله في دالة موجودة بملف
\InlineCode{.c}.\\
أنظر كيف نقوم بإنشاء متغير من نوع
\InlineCode{Coordinates}
(الهيكل الّذي عرّفناه سابقا):
\begin{Csource}
#include "main.h" // Including the files that contains the prototypes and structures
int main(int argc, char *argv[])
{
struct Coordinates point; // Creating a variable "point" of type Coordinates
return 0;
}
\end{Csource}
هكذا نكون قد أنشأنا متغيرًا
\InlineCode{point}
من نوع
\InlineCode{Coordinates}!
هذا المتغير سيحمل داخله مركّبين (متغيرين داخليين):
\InlineCode{x}
و
\InlineCode{y}
(فاصلته وترتيبته).
\begin{question}
هل من اللازم أن نضع الكلمة المفتاحية
\InlineCode{struct}
عند تعريف المتغير؟
\end{question}
نعم، فهذا يسمح للحاسوب بأن يفرّق بين نوع عادي (مثل
\InlineCode{int})
و نوع مخصّص.\\
المبرمجون وجدوا أنه من المتعب جدّا أن يكتبوا في كلّ مرة الكلمة
\InlineCode{struct}
في كلّ تعريف لمتغيّر مخصّص.
لمعالجة هذا المشكل، اخترعوا تعليمة خاصّة: \InlineCode{typedef}.
\subsection{\texttt{typedef}}
لنعد إلى الملف
\InlineCode{.h}
الذي يحمل تعريف هيكلنا من نوع
\InlineCode{Coordinates}.
سنضيف تعليمة اسمها
\InlineCode{typedef}
و الّتي تفيد في إعطاء اسم مستعار
(\textenglish{alias})
لهيكل، أي كتابة شيء مكافئ لكتابة آخر.
إذا، سنضيف سطرا يبدأ بـ\InlineCode{typedef}
قبل تعريف الهيكل مباشرة:
\begin{Csource}
typedef struct Coordinates Coordinates;
struct Coordinates
{
int x;
int y;
};
\end{Csource}
هذا السطر متكون من ثلاثة أجزاء:
\begin{itemize}
\item \InlineCode{typedef}:
تعني أننا سنقوم بإنشاء اسم مستعار لهيكل.
\item \InlineCode{struct Coordinates}:
هو اسم الهيكل الذي سنقوم بإنشاء اسم مستعار له (أي "مكافئ").
\item \InlineCode{Coordinates}:
هو الاسم المكافئ.
\end{itemize}
ببساطة، هذا السطر يقول: "كتابة
\InlineCode{Coordinates}
مكافئ لكتابة
\InlineCode{struct Coordinates}".
بفعل هذا، لن يكون عليك كتابة الكلمة
\InlineCode{struct}
عند كلّ تعريف لمتغيّر من نوع
\InlineCode{Coordinates}.
يمكننا العودة إلى
\InlineCode{main}
و كتابة فقط:
\begin{Csource}
int main(int argc, char *argv[])
{
Coordinates point; // The computer understands that we are talking about "struct Coordinates" thanks to typedef
return 0;
}
\end{Csource}
أنصحك أن تستعمل \InlineCode{typedef}
مثلما فعلت أنا هنا من أجل
\InlineCode{Coordinates}.
أغلب المبرمجين يفعلون هذا. هذا يسمح لهم بعدم كتابة
\InlineCode{struct}
في كلّ مرّة. المبرمج الجيّد هو مبرمج كسول! أي أنه يكتب أقل ما يمكن.
\subsection{تغيير مركّبات هيكل}
و الآن بعدما قمنا بإنشاء متغيّرنا
\InlineCode{point}،
نريد أن نغيّر إحداثيّاته.\\
كيف نصل إلى
\InlineCode{x}
و
\InlineCode{y}
الموجودة في المتغير
\InlineCode{point}؟
هكذا:
\begin{Csource}
int main(int argc, char *argv[])
{
Coordinates point;
point.x = 10;
point.y = 20;
return 0;
}
\end{Csource}
بهذا نكون قد غيّرنا قيمة
\InlineCode{point}،
بإعطائه الفاصلة 10 والترتيبة 20. نقطتنا أصبحت في الوضعية (10؛20) (هذا هو الترميز الرياضياتي للإحداثيّات).
لكي نتمكن من الوصول إلى مُرَكِّب في الهيكل، يجب كتابة:
\begin{Csource}
variable.componentName
\end{Csource}
النقطة هي التي تفرّق بين المتغير والمركّب.
إن أخذنا الهيكل
\InlineCode{Person}
الذي رأيناه منذ قليل ونطلب الاسم واللقب فسنفعل هكذا:
\begin{Csource}
int main(int argc, char *argv[])
{
Person user;
printf("What's your last name ? ");
scanf("%s", user.lastName);
printf("What's your first name ? ");
scanf("%s", user.firstName);
printf("You are %s %s", user.firstName, user.lastName);
return 0;
}
\end{Csource}
\begin{Console}
What's your last name ? Dupont
What's your first name ? Jean
You are Jean Dupont
\end{Console}
نرسل المتغير
\InlineCode{user.lastName}
إلى الدالة
\InlineCode{scanf}،
و التي ستكتب مباشرة في
\InlineCode{user}.\\
نفعل نفس الشيء مع
\InlineCode{firstName}،
يمكننا فعل ذلك أيضا مع العنوان، العمر والجنس، لكنّي لا أرغب بتكرار ذلك (يحب أن أكون مبرمجا!).
يمكن فعل هذا بدون معرفة الهياكل، فقط بإنشاء متغيّر
\InlineCode{lastName}
و آخر
\InlineCode{firstName}.\\
لكن الفائدة هنا هي أنه بهذه الطريقة يمكننا أن ننشئ متغيرا آخر من نوع
\InlineCode{Person}
و يكون لديه هو أيضا اسمه الخاص، لقبه الخاص، إلخ. يمكننا إذن فعل هذا:
\begin{Csource}
Person player1, player2;
\end{Csource}
و هكذا نخزّن معلومات كلّ لاعب. كلّ لاعب سيكون لديه اسمه الخاص، لقبه الخاص، إلخ.
يمكننا أن نفعل ما هو أفضل: يمكننا تعريف جدول من
\InlineCode{Person}!\\
القيام بهذا سهل:
\begin{Csource}
Person players[2];
\end{Csource}
و بعدها يمكننا الوصول إلى لقب اللاعب المتواجد بالخانة الأولى مثلا، هكذا:
\begin{Console}
players[0].lastName
\end{Console}
الفائدة من استعمال الجدول هنا، هو أنها بإمكاننا استعمال حلقة لنقرأ المعلومات الخاصة باللاعب 1 واللاعب 2 بدون الاضطرار إلى إعادة الشفرة مرّتين. يكفي تصفّح الجدول
\InlineCode{players}
و طلب كلّ مرّة اللقب، الاسم، العنوان\dots
\paragraph{تمرين:}
قم بتعريف جدول من نوع
\InlineCode{Person}،
و اقرأ المعلومات الخاصة بكلّ لاعب باستخدام حلقة. ابدأ بجدول ذي خانتين، وإن كان ذلك ممتعا، حاول تكبير العدد لاحقا.\\
في النهاية، عليك بإظهار المعلومات التي أخذتها من كلّ لاعب.
\subsection{تهيئة هيكل}
بالنسبة للهياكل، مثل كلّ المتغيرات، الجداول والمؤشّرات، فنحن نفضّل أن نعطيها قيما ابتدائية كي نضمن أنّها لن تحوي "قيما عشوائية". في الواقع، أعيد تذكيرك، المتغير الّذي يتمّ إنشائه يأخذ القيمة الموجودة في الذاكرة حيث تمّ وضعه. أحيانا تكون هذه القيمة $ 0 $، وأحيانا بقايا برنامج مرّ قبلك، لذلك ستكون قيمته شيئا لا معنى له، مثل
$-84570$.
للتذكير، هكذا نقوم بالتهيئة:
\begin{itemize}
\item المتغير: نعطيه القيمة 0 (الحالة الأبسط).
\item المؤشّر: نجعل قيمته
\InlineCode{NULL}.
بالمناسبة فـ\InlineCode{NULL}
هي
\InlineCode{\#define}
موجود في مكتبة
\InlineCode{stdlib.h}
و هي عادة 0، لكنّنا نستمرّ في استخدام
\InlineCode{NULL}
للمؤشرات لكي نبيّن أنّها مؤشّرات وليست متغيّرات عاديّة.
\item الجدول: نضع كلّ خاناته على القيمة 0.
\end{itemize}
بالنسبة للهياكل، فالتهيئة شبيهة بتلك الخاصّة بالجدول. في الواقع، يمكننا القيام بها عند التصريح عن المتغيّر:
\begin{Csource}
Coordinates point = {0, 0};
\end{Csource}
و هذا يعرّف بالترتيب:
\InlineCode{point.x = 0}
و
\InlineCode{point.y = 0}.
لنعد إلى الهيكل
\InlineCode{Person}
(الذي يحتوي سلاسل محرفيّة). يمكننا أن نعطي قيمة ابتدائية للسلاسل بكتابة فقط
\InlineCode{""}
(لا شيء ببن علامتي الاقتباس). لم أعلمك هذا الشيء في الفصل الخاصّ بالسلاسل، لكنّ الوقت ليس متأخّرا على تعلّمها.
يمكننا إذن تهيئة على الترتيب
\InlineCode{firstName}،
\InlineCode{lastName}،
\InlineCode{address}،
\InlineCode{age}،
و
\InlineCode{boy}
هكذا:
\begin{Csource}
Person user= {"", "", "", 0, 0};
\end{Csource}
رغم ذلك، أنا لا أستخدم هذه التقنيّة كثيرا. أفضّل أن أرسل متغيّري، مثلا
\InlineCode{point}،
إلى دالّة
\InlineCode{initializeCoordinates}
تقوم بالتهيئات من أجلي على متغيري.\\
لفعل هذا، يجب إرسال مؤشّر نحو متغيري. في الواقع، إن أرسلت فقط المتغيّر، سيتم إنشاء نسخة عنه (مثل أيّ متغيّر عادي) وتعديل قيم النسخة لا قيم المتغيّر. راجع الخيط الأحمر من فصل المؤشرات إن نسيت كيف يعمل هذا الأمر.
يجب إذن تعلّم كيفيّة استخدام المؤشرات على الهياكل. الأمور بدأت تصعب قليلا!
\section{مؤشّر نحو هيكل}
المؤشّر على الهيكل يتمّ إنشائه بنفس طريقة إنشاء مؤشّر على
\InlineCode{int}
أو
\InlineCode{double}
أو أيّ نوع قاعديّ آخر:
\begin{Csource}
Coordinates* point = NULL;
\end{Csource}
بهذا نكون قد عرّفنا مؤشّرا نحو
\InlineCode{Coordinates}
اسمه
\InlineCode{point}.\\
و لأن التذكير لن يضرّ أحدا، أعيد إخبارك بأنه من الممكن وضع النجمة أمام اسم المتغيّر، فهذه الكتابة مكافئة تماما للسابقة:
\begin{Csource}
Coordinates *point = NULL;
\end{Csource}
أنا أفعل هكذا كثيرا، لأنه لتعريف عدّة مؤشرات على سطر واحد، سيكون علينا وضع النجمة أمام اسم كل واحد منها:
\begin{Csource}
Coordinates *point1 = NULL, *point2 = NULL;
\end{Csource}
\subsection{إرسال هيكل إلى دالة}
الشيء الذي يهمّنا هنا، هو كيفيّة إرسال مؤشر هيكل إلى دالة كي تقوم هذه الأخيرة بتعديل محتواه.
هذا ما سنقوم به في هذا المثال، سنقوم بإنشاء متغير من نوع
\InlineCode{Coordinates}
في
\InlineCode{main}،
و نرسل عنوانه إلى
\InlineCode{initializeCoordinates}.
دور هذه الدالة هو إعطاء القيمة 0 لعناصر الهيكل.
دالتنا
\InlineCode{initializeCoordinates}
ستأخذ معاملا واحدا: مؤشر نحو هيكل من نوع
\InlineCode{Coordinates}
(أي
\InlineCode{*Coordinates}).
\begin{Csource}
int main(int argc, char *argv[])
{
Coordinates myPoint;
initializeCoordinates(&myPoint);
return 0;
}
void initializeCoordinates(Coordinates* point)
{
// Initializing each member of the structure here
}
\end{Csource}
متغيري
\InlineCode{myPoint}
تم إنشاءه في
\InlineCode{main}.\\
نقوم بإرسال عنوانه إلى الدالة
\InlineCode{initializeCoordinates}
الّتي تسترجعه على شكل متغيّر يسمّى
\InlineCode{point}
(كان بإمكاننا تسميته كما شئنا، هذا الأمر ليس له أيّ تأثير).
الآن بما أنّنا داخل الدالة
\InlineCode{initializeCoordinates}،
سنقوم بتهيئة قيم المتغير
\InlineCode{point}
واحدة بواحدة.\\
يجب عدم نسيان وضع النجمة أمام اسم المؤشر للوصول إلى المتغير. إن لم تفعل، فأنت تخاطر بتغيير العنوان، وليس هذا ما نريد فعله.
و لكن هاهي مشكلة\dots لا يمكننا القيام مباشرة بهذا:
\begin{Csource}
void initializeCoordinates(Coordinates* point)
{
*point.x = 0;
*point.y = 0;
}
\end{Csource}
سيكون ذلك سهلا جدّا\dots لماذا لا يمكننا القيام بهذا؟
لأنّ النقطة تطبّق على
\InlineCode{point}
فقط وليس على
\InlineCode{*point}.
لكنّ ما نريده هو الوصول إلى
\InlineCode{*point}
لتغيير قيمته.\\
لحلّ هذا المشكل، يجب وضع الأقواس حول
\InlineCode{*point}،
هكذا ستطبّق النقطة على
\InlineCode{*point}
و ليس فقط على
\InlineCode{point}:
\begin{Csource}
void initializeCoordinates(Coordinates* point)
{
(*point).x = 0;
(*point).y = 0;
}
\end{Csource}
هذه الشفرة تعمل، يمكنك تجريبها. المتغير من نوع
\InlineCode{Coordinates}
تمّ إرساله إلى الدالة التي هيّأت
\InlineCode{x}
و
\InlineCode{y}
على~0.
\begin{information}
في لغة \textenglish{C}،
نهيّئ عادة هياكلنا بالطريقة الّتي رأيناها سابقا. بالمقابل، في لغة \textenglish{C++}،
التهيئة تكون في الغالب داخل "دوال".
إن لغة
\textenglish{C++}
ليست سوى "تحسين خارق" للهياكل. كثير من الأشياء تبدأ من هذا وأحتاج إلى كتاب كامل لأتحدّث عنها (كلّ شيء في وقته).
\end{information}
\subsection{اختصار عمليّ ومستعمل بكثرة}
سترى أننا سنستعمل كثيرًا مؤشرات نحو هياكل. بصراحة، يجب أن أعترف لك بأنّه
في لغة \textenglish{C}
نستخدم المؤشرات نحو الهياكل أكثر من استعمال الهياكل وحدها. لهذا فعندما أقول لك بأنّ المؤشرات ستظلّ تتبعك حتّى إلى قبرك، فأنا لا أقولها تقريبا من أجل المزاح!
بما أن المؤشرات نحو الهياكل مستعملة بكثرة، نجد أنفسنا نستعمل هذه الكتابة كثيرا:
\begin{Csource}
(*point).x = 0;
\end{Csource}
مرّة أخرى، المبرمجون وجدوا هذه الكتابة طويلة جدّا. الأقواس حول
\InlineCode{*point}،
يا لها من بلوى! إذن، بما أن المبرمجين أشخاص كسالى (لقد قلت هذا سابقا على ما أعتقد)، فقد اخترعوا هذا الاختصار:
\begin{Csource}
point->x = 0;
\end{Csource}
هذا الاختصار يتمّ كتابته بمطّة
\InlineCode{-}
متبوعة بعلامة ترتيب
\InlineCode{>}.
كتابة
\InlineCode{point->x}
هو إذن مكافئ
\underline{تماما}
لكتابة
\InlineCode{(*point).x}.
\begin{warning}
لا تنس أننا لا نستطيع استعمال السهم إلا مع المؤشرات.\\
إن كنت تعمل على المتغير مباشرة، يجب عليك استخدام النقطة كما رأينا في البداية.
\end{warning}
لنعد إلى دالتنا
\InlineCode{initializeCoordinates}
يمكننا كتابتها بالشكل التالي:
\begin{Csource}
void initializingCoordinates(Coordinates* point)
{
point->x = 0;
point->y = 0;
}
\end{Csource}
و تذكّر جيّدا اختصار السهم، سنستعمله كثيرًا من الآن. وخاصّة لا تخلط بين السهم و"النقطة". السهم مخصّص للمؤشّرات، "النقطة" مخصّصة للمتغيّرات. استخدم هذا المثال الصغير للتذكّر:
\begin{Csource}
int main(int argc, char *argv[])
{
Coordinates myPoint;
Coordinates *pointer = &myPoint;
myPoint.x = 10; // We work on a variable, we use the "dot"
pointer->x = 10; // We work on a pointer, we use the arrow
return 0;
}
\end{Csource}
نغيّر قيمة
\InlineCode{x}
إلى 10 بطريقتين مختلفتين، هنا: الطريقة الأولى هي بالعمل مباشرة على المتغير، والطريقة الثانية باستعمال المؤشر.
\section{التعدادات}
التعدادات هي طريقة مختلفة قليلًا لنعرّف نوع متغيرات خاص بنا.
التعداد ليس متكوّنا من "مركّبات" كما هو الحال مع الهياكل. وإنما هو مجموعة من "القيم الممكنة" لمتغيّر. التعداد سيأخذ إذن خانة واحدة في الذاكرة وهذه الخانة تأخذ قيمة واحدة من مجموع القيم التي قمت بتعريفها (واحدة فقط في كلّ مرّة).
هذا مثال عن تعداد:
\begin{Csource}
typedef enum Volume Volume;
enum Volume
{
LOW, MEDIUM, HIGH
};
\end{Csource}
تلاحظ أننا نستعمل
\InlineCode{typedef}
هنا أيضا، مثلما رأينا لحد الآن.
لكي نقوم بتعريف تعداد نستعمل الكلمة المفتاحية
\InlineCode{enum}.
اسم التعداد هنا هو
\InlineCode{Volume}.
إنّه نوع مخصّص قمنا بتعريفه يمكن له أن يأخذ واحدة من الثلاث قيم الّتي وضعناها: إما
\InlineCode{LOW}
أو
\InlineCode{MEDIUM}
أو
\InlineCode{HIGH}.
يمكننا إذن أن نعرّف متغيرا اسمه
\InlineCode{music}
من نوع
\InlineCode{Volume}
لتخزين مستوى صوت الموسيقى.\\
يمكننا تهيئة الموسيقى على المستوى
\InlineCode{MEDIUM}:
\begin{Csource}
Volume music = MEDIUM;
\end{Csource}
يمكننا لاحقًا في الشفرة، أن نغيّر قيمة مستوى الصوت ووضعها إمّا على
\InlineCode{HIGH}
أو على
\InlineCode{LOW}.
\subsection{إرفاق قيم التعداد بأعداد}
قد لاحظت أنّي كتبت القيم الممكنة بأحرف كبيرة. هذا يفترض به أن يذكّرك بالثوابت و
\InlineCode{\#define}،
أليس كذلك؟
في الواقع، إنّ هذا مشابه كثيرا ولكنّه ليس نفس الشيء.\\
المترجم يقوم تلقائيا بإرفاق قيم التعداد بأعداد موافقة لها.
في حالة تعدادنا
\InlineCode{Volume}،
\InlineCode{LOW}
سيتم إرفاقها بالقيمة 0،
\InlineCode{MEDIUM}
بالقيمة 1،
و
\InlineCode{HIGH}
بالقيمة 2.\\
الإرفاق يتمّ تلقائيّا انطلاقا من 0.
خلافا لـ\InlineCode{\#define}،
فالمترجم هو من يرفق
\InlineCode{MEDIUM}
بـ1 مثلا، وليس المعالج القبلي. لكنّ هذا سيكون تقريبا مكافئا له.\\
بطبيعة الحال، عندما هيّئنا المتغيّر
\InlineCode{music}
على
\InlineCode{MEDIUM}،
فإنّنا قد وضعنا القيمة 1 في خانة الذاكرة الموافقة.
\begin{question}
عمليّا، هل يهمّنا أن نعرف أنّ
\InlineCode{MEDIUM}
تساوي 1،
\InlineCode{HIGH}
تساوي 2، إلخ.؟
\end{question}
لا. فهذا حقيقة لا يعنينا. المترجم هو من سيقوم تلقائيّا بإرفاق العدد المناسب إلى كلّ قيمة. بفضل هذا، ليس عليك سوى كتابة:
\begin{Csource}
if (music == MEDIUM)
{
// Play music with medium volume
}
\end{Csource}
لا يهمّ ما هي قيمة
\InlineCode{MEDIUM}،
ستترك المترجم يهتمّ بالأعداد.
الفائدة من كلّ هذا؟ هي أنها تجعل الشفرة قابلة للقراءة جيّدا. في الواقع، أيّ شخص يمكنه بسهولة قراءة
\InlineCode{if}
السابق (نفهم جيّدا أنّ الشرط يعني "إن كانت الموسيقى بمستوى صوت متوسّط").
\subsection{ارفاق قيمة محددة}
حاليّا، كان المترجم هو من يقرّر إرفاق العدد 0 ثم 1، 2، 3
بالترتيب.\\
من الممكن طلب إرفاق قيمة محدّدة لكلّ عنصر من التعداد.
ما الفائدة التي يمكن تحصيلها من هذا؟ حسنا فلنفرض أنّه في حاسوبك، الصوت يتم تحديده بقيمة بين 0 و100 (0 = لا صوت، 100 = 100\%
من الصوت)، فسيكون من الجيد إرفاق قيمة محدّدة بكلّ عنصر:
\begin{Csource}
typedef enum Volume Volume;
enum Volume
{
LOW = 10, MEDIUM = 50, HIGH = 100
};
\end{Csource}
هنا، المستوى
\InlineCode{LOW}
يوافق 10\%
من المستوى، المستوى
\InlineCode{MEDIUM}
يوافق 50\%،
إلخ.\\
يمكننا بسهولة إضافة بعض القيم الأخرى مثل
\InlineCode{MUTE}.
نرفق في هذه الحالة
\InlineCode{MUTE}
بالقيمة\dots 0! لقد فهمت.
\section*{ملخّص}
\begin{itemize}
\item الهيكل هو نوع بيانات مخصّص يمكنك إنشاؤه واستخدامه في برامجك. يجب عليك تعريفه، عكس الأنواع القاعديّة مثل
\InlineCode{int}
و
\InlineCode{double}
الّتي نجدها في كلّ البرامج.
\item الهيكل يتكوّن من "متغيّرات داخليّة" تكون عادة من أنواع قاعديّة مثل
\InlineCode{int}
و
\InlineCode{double}،
و أيضا من الجداول.
\item نستطيع الوصول إلى أحد مركّبات الهيكل بفصل اسم المتغيّر والمركّب بنقطة:
\InlineCode{player.firstName}.
\item إذا كنّا نتعامل مع مؤشر نحو هيكل وأردنا الوصول إلى أحد مركّباته، نستخدم السهم بدل النقطة:\\
\InlineCode{playerPointer->firstName}.
\item التعداد هو نوع مخصّص يمكنه فقط أخذ إحدى القيم المسبقة التعريف:
\InlineCode{LOW}،
\InlineCode{MEDIUM}
أو
\InlineCode{HIGH}
مثلا.
\end{itemize}