المصفوفات في البرمجة، Arrays !
السلام عليكم ورحمة الله وبركاته
الفهرس
- المقدمة
- كيفية إنشاء أراي في البرمجة
- فائدة إنشاء الأراي
- كيفية تخزين القيم في الأراي
- إنشاء أراي واسناد لها القيم في نفس الوقت
- اسناد قيم متنوعة في الأراي
- الخروج من حدود الأراي
- الـ string ما هو إلا أراي من الـ char !!
- الأراي ثنائية الأبعاد
- أراي من الـ string هي أراي ثنائية الأبعاد
- ماذا عن الأراي ثلاثية الأبعاد وأكثر ؟
- الختام
المقدمة
انتظر لحظة هل يوجد مصفوفات في البرمجة ؟
نعم يوجد مصفوفات في البرمجة وهي تعتبر من أهم المفاهيم في البرمجة وتسمى Array
وهي عبارة عن مجموعة من العناصر التي يمكن تخزينها في متغير واحد
لكن عندما نطلق لفظ مصفوفة قد يأتي للبعض أنها تقبل أرقام فقط لكن في البرمجة يمكن تخزين أي نوع من البيانات في المصفوفة سواء كانت نصوص أو أرقام أو رموز أو حروف ... الخ
المصفوفة تعني Array
وهذا هو الاسم الشائع لها لذا ستجدني أثناء الشرح أكتب أراي وأعني بها مصفوفة
الأراي هي أول Data Structure
سنتعلمها وهي من أهم هياكل البيانات في البرمجة وأكثرها استخدامًا
بالطبع يوجد غيرها من هياكل البيانات مثل Linked List
و Stack
و Queue
و Tree
و Graph
وغيرها
لكن كل واحدة تحتاج لمقالة أومقالتين خاص بها
على كل حال لنبدأ في شرح الأراي وكيفية استخدامها والتعامل معها
كيفية إنشاء أراي في البرمجة
في الـ C++
يمكنك إنشاء أراي بالطريقة التالية:
int ages[5]; // int تم إنشاء أراي من 5 عناصر من نوع
ماذا يعني هذا السطر؟
هنا كأننا أنشأنا متغير من نوع int
لكن الفرق أننا كتبنا []
بعده ووضعنا رقم يعبر عن عدد العناصر التي تريد تخزينها في الأراي
في ذاكرة الجهاز يتم حجز مساحة تخزينية لـ 5
عناصر من نوع int
ويتم تخزينهم في مكان واحد بجانب بعضهم البعض
memory (RAM)
ذاكرة الجهاز التي تخزن فيها البيانات
+-----------------------------------------------+
| |
| ages = { , , , , } |
| 5 * 4 = 20 bytes |
| |
+-----------------------------------------------+
لاحظ أن قيم الأراي فارغة لأننا لم نقم بتخزين أي قيم فيها بعد
شكل تعريف الأراي قد يختلف من لغة لأخرى فمثلًا في لغة TypeScript
يكون تعريف الأراي كالتالي:
let ages: number[5]; // number تم إنشاء أراي من عناصر من نوع
كما تلاحظ أن الطريقة تختلف من لغة لأخرى لكن تعلمنا أن مهما اختلف الطريق يظل الفكرة العامة هي نفسها
مع بعض المميزات والاختلافات التي تقدمها كل لغى برمجة
فائدة إنشاء الأراي
الأراي تساعدك في تخزين مجموعة من البيانات المترابطة مع بعضها في مكان واحد
فمثلا إذا كنت تريد تخزين أعمار مجموعة من الأشخاص بالطريقة العادية كنت ستقوم بإنشاء متغير لكل شخص وتخزين عمره فيه
int age1 = 12;
int age2 = 16;
int age3 = 24;
int age4 = 25;
int age5 = 28;
لاحظ أنك تحتاج لترقيم المتغيرات وكل متغير له اسم مختلف لا يوجد ترابط أو علاقة بين هذه المتغيرات
متغير يحتاج مساحة تخزينية خاصة به
memory (RAM)
ذاكرة الجهاز التي تخزن فيها البيانات
+-----------------------------------------------+
| age1 = 12 |
| 4 bytes age4 = 25 |
| 4 bytes |
| age5 = 28 |
| 4 bytes |
| age2 = 16 |
| 4 bytes |
| age3 = 24 |
| 4 bytes |
+-----------------------------------------------+
لكن مع الأراي يمكنك تخزين هذه الأعمار في مكان واحد تحت اسم واحد مشترك
int ages[5];
هكذا خزنها مساحة لخمس أعمار في مكان واحد، لكن كيف نسند القيم لها؟
كيفية تخزين القيم في الأراي
لتخزين القيم في الأراي يمكنك استخدام الفهرس index
لكل عنصر في الأراي
الـ index
هو يعبر عن مكان العنصر في الأراي ويبدأ من الصفر
بمعنى أن:
- أول عنصر يكون الـ
index
الخاص به بـ0
- ثاني عنصر يكون الـ
index
الخاص به بـ1
- ثالث عنصر يكون الـ
index
الخاص به بـ2
- ... وهكذا
بالتالي اذا أردت تخزين قيمة في الأراي يمكنك فعل ذلك بالطريقة التالية:
تحدد رقم العنصر وتعرف الـ index
الخاص به ثم تضع القيمة فيه
مثلاً نريد تخزين 12
في العنصر الأول و 16
في العنصر الثاني و 24
في العنصر الثالث وهكذا
يمكنك فعل ذلك بالطريقة التالية:
int ages[5];
ages[0] = 12; // تخزين القيمة 12 في العنصر الأول
ages[1] = 16; // تخزين القيمة 16 في العنصر الثاني
ages[2] = 24; // تخزين القيمة 24 في العنصر الثالث
ages[3] = 25; // تخزين القيمة 25 في العنصر الرابع
ages[4] = 28; // تخزين القيمة 26 في العنصر الخامس
لاحظ أننا لكي نصل لأي عنصر في الأراي نكتب اسم الأراي وبعدها نكتب الـ index
بين []
بالتالي ages[0]
تعني العنصر الأول في الأراي والذي خزنا فيه القيمة 10
ages[1]
تعني العنصر الثاني في الأراي والذي خزنا فيه القيمة 20
memory (RAM)
ذاكرة الجهاز التي تخزن فيها البيانات
+-----------------------------------------------+
| |
| index: [0] [1] [2] [3] [4] |
| ages = {12, 16, 24, 25, 28} |
| 5 * 4 = 20 bytes |
| |
+-----------------------------------------------+
عليك أن تتخذها قاعدة في حياتك دائما الـ index
يبدأ من الصفر
لاحظ أيضًا أن أخر index
في الأراي هو 4
وليس 5
لأن الـ index
يبدأ من الصفر
بالتالي لو لديك أراي من 100
عنصر فيكون index
أو عنصر هو 0
و index
أخر عنصر هو 99
int ages[100];
ages[0] = 12; // العنصر الأول
ages[99] = 75; // العنصر الأخير
إنشاء أراي واسناد لها القيم في نفس الوقت
مثل ما أنت يمكنك إنشاء المتغير واسناد له قيم في نفس الوقت هكذا int x = 5;
يمكنك فعل ذلك مع المصفوفات
int ages[5] = {12, 16, 24, 25, 28};
cout << ages[3] // 25
بهذه الطريقة يتم إنشاء الأراي وتخزين القيم فيها في نفس الوقت
لاحظ هنا نستخدم الـ {}
لتحديد القيم التي نريد تخزينها في الأراي
لكن الأمر قد يختلف من لغة للأخرى
فمثلًا في لغة TypeScript
يكون هكذا بين []
وليس بين {}
:
let ages: number[] = [12, 16, 24, 25, 28];
ولاحظ أننا نحدد النوع وأنها أراي في آن واحد هكذا number[]
لذا عليك أن تعرف كيف يكون شكل وطريقة تعريف الأراي في اللغة التي تتعلمها
وكيفية تخزين القيم فيها
اسناد قيم متنوعة في الأراي
كما ذكرنا في بداية الشرح يمكن تخزين إنشاء أراي من أي نوع من البيانات
يمكنك انشاء أراي نوعها char
أو string
أو float
أو bool
... الخ
char alphabet[5] = {'A', 'B', 'C', 'D', 'E'};
cout << alphabet[3] // D
هنا أنشأنا أراي تدعى alphabet
من نوع char
خزنا فيها بضع حروف كما ترى
لاحظ أن كل عنصر في الأراي يجب أن يكون من نفس النوع الذي حددناه عند إنشاء الأراي
بمعنى أنه لا يمكننا تخزين أي نوع أخر من البيانات عدا التي من نوع char
char alphabet[5];
alphabet[0] = 'A'; // ✅
alphabet[1] = 'B'; // ✅
alphabet[2] = "Hello"; // ❌
alphabet[3] = 67; // it will store the ASCII value of 50 'C'
alphabet[4] = 89.99; // it will store the ASCII value of 89 'Y'
في هذا المثال أنشأنا أراي تدعى alphabet
وحددنا أن نوعها char
فقط
لذاك لا يمكنك تخزين أي شيء فيها غير الحروف والرموز التي من نوع char
لكن لاحظ أننا قمنا بتخزين القيمة 67
في العنصر الـ index
رقم 3
وخزننا القيمة 89.99
في العنصر الـ index
رقم 4
لكن لماذا لم يحدث أي خطأ ؟ بعض اللغات قد تعطيك خطأ عندما تقوم بتخزين قيمة غير متوافقة مع نوع الأراي
لكن بعض اللغات عندما تسند قيمة عددية لمتغير من نوع char
فهو سيحول الرقم إلى رمز
فمثلا هنا في لغة C++
عندما تقوم بتخزين الرقم 67
في متغير من نوع char
فهو سيحوله إلى الحرف C
لأنه يعتمد على جدول يسمى ASCII
وهو جدول به 128
حرف ورمز وكل واحدة يقابلها عدد معين
فمثلا الحرف A
يقابله الرقم 65
والحرف B
يقابله الرقم 66
والحرف C
يقابله الرقم 67
وهكذا
أما الرقم 89.99
فسيتم التخلص من الكسور وسيتم تخزين الرقم 89
فقط وسيقوم بالبحث عن الحرف المقابل له في جدول الـ ASCII
ويقوم بتخزينه وهو الحرف Y
بعض اللغات مثل قد تجعل الـ char
يقبل فقط ما هو موجود في جدول الـ ASCII
ولا يقبل غيره
وعندما تسند له رقم فسيبحث عن الحرف أو الرمز المقابل له في جدول الـ ASCII
ويقوم بتخزينه
char letter = 65; // A سيقوم بتخزين الحرف
يمكنك الاطلاع على جدول الـ ASCII
من هنا
بالطبع كالعادة الأمر يتغير من لغة لأخرى فمثلًا في لغة Python
يمكنك تخزين أي نوع من البيانات في الأراي
anything = [10, 'Hello', 24.99, True]
هنا في لغة Python
أنشأنا أراي تدعى anything
وخزنا فيها أرقام ونصوص وقيم منطقية وأرقام عشرية وأي شيء تريده
نفس الشيء في لغة Typescript
يمكنك تخزين أي شيء في الأراي
let anything: any[] = [10, 'Hello', 24.99, true];
هنا في لغة TypeScript
أنشأنا أراي تدعى anything
وحددنا أن نوعها any
وهو يعني أنها تقبل أي نوع من البيانات
الخروج من حدود الأراي
لاحظ أننا نضع ثابت يعبر عن عدد العناصر التي تريد تخزينها في الأراي عند إنشائها
int ages[5];
هنا قمنا بإنشاء أراي من 5
عناصر
وعرفنا أن أول index
هو 0
والأخير هو 4
ماذا سيحدث إذا حاولنا تخزين قيمة في index
خارج حدود الأراي ؟ مثلا 5
أو -1
int ages[5];
ages[5] = 12; // ❌ Error: Cannot access index 5
ages[-1] = 16; // ❌ Error: Cannot access index -1
هنا حاولنا الوصول للعنصر السادس وهو index
رقم 5
وحاولنا اسناد قيمة له
لكن لم نستطع لأنه خارج حدود الأراي لآن الأراي ages
تحتوي على 5
عناصر فقط و أخر index
هو 4
وليس 5
وكذلك حاولنا الوصول لـ index
برقم سالب مثل -1
وهذا خارج حدود الأراي أيضًا لأن الـ index
يبدأ من الـ 0
لكن انتبه هنا أحيانًا قد تسمح لك بعض اللغات مثل الـ C++
بالوصول للعناصر خارج حدود الأراي دون أن تعاتبك
لكنك هكذا كأنك قمت بسرقة مساحة تخزينية ليست لك وقد تسبب مشاكل لك في البرنامج لاحقًا
كيف ذلك ؟
حسنا لنفترض أننا لدينا أراي من 3
عناصر
وقمنا باسناد قيم فيها
int numbers[3] = {10, 20, 30};
هكذا تبدو الأراي في الذاكرة
memory (RAM)
ذاكرة الجهاز التي تخزن فيها البيانات
+-----------------------------------------------+
| |
| index: [0] [1] [2] |
| numbers = {10, 20, 30} |
| 3 * 4 = 12 bytes |
| |
+-----------------------------------------------+
هنا قام البرنامج بحجز مساحة تخزينية لـ 3
عناصر وقام بتخزين القيم فيها
ركز على هذه الكلمة أنت قمت بحجز مساحة خاصة بك بالتالي لن يقوم أي برنامج بالتعدي على هذه المساحة إلا أنت
بمعنى هل تتخيل مثلا قمت بتخزين قيمة 35
في index
أو في متغير ما ثم لاحقا وجدته فجأة أصبحت قيمته 50
أو A
أو true
أكيد لا فلن يحدث هذا إلا إذا قمت أنت بتغيير قيمته
حسنا الآن ماذا سيحدث عندما تتعدى أنت على مساحة ليست لك ؟
int numbers[3] = {10, 20, 30};
numbers[3] = 40;
هنا قمنا بتخزين قيمة 40
في index
خارج حدود الأراي وهو 3
هل سيحدث خطأ ؟ بعض اللغات تعاتبك وأخرى لك
هل سيحدث مشكلة حقًا أم لا ؟
تخيل شكل الأراي في الذاكرة
memory (RAM)
ذاكرة الجهاز التي تخزن فيها البيانات
+-----------------------------------------------+
| |
| index: [0] [1] [2] [3] |
| numbers = {10, 20, 30} 40 |
| ٨ |
| | |
| مساحة ليست لك |
| |
+-----------------------------------------------+
هنا أنت وصلت للفعل لمساحة في الذاكرة ليست لك وقمت بتخزين قيمة فيها
لذا المشكلة هنا أنها ليست لك بالتالي لا توجد أي ضمانات على أن لا أحد سيعدل عليها
فطالما أنها ليست لك بالتالي قد يقوم برنامج أخر بحجز تلك المساحة والتعديل عليها
أو قد يقوم متغير أخر بحجز تلك المساحة والتعديل فيها
int numbers[3] = {10, 20, 30};
numbers[3] = 40;
int x = 999
cout << numbers[3];
لاحظ هنا أننا قمنا بتخزين قيمة 40
في index
خارج حدود الأراي
ثم قمنا بإنشاء متغير x
وتخزين قيمة 999
فيه
ثم قمنا بطباعة numbers[3]
هل تعتقد أن النتيجة ستكون 40
كما هي ؟
أو ستكون 999
؟
النتيجة ستكون 999
هل تعرف السبب ؟
السبب ببساطة أننا حرامية قمنا بالتعدي على مساحة ليست لنا وقمنا بتخزين قيمة فيها
بالتالي عندما نعرف متغير جديد فغالبًا سيقوم البرنامج بحجز مساحة جديدة له وقد تكون نفس المساحة التي قمنا بالتعدي عليها
لذا المتغير x
غالبًا حجز نفس المساحة التي تعدينا عليها واصبحت له الآن فقام بالتعديل عليها
دعونا نرى شكل الذاكرة بعد ما عرفنا المتغير x
memory (RAM)
ذاكرة الجهاز التي تخزن فيها البيانات
+-----------------------------------------------+
| |
| index: [0] [1] [2] [3] |
| numbers = {10, 20, 30} x = 999 |
| |
+-----------------------------------------------+
ستجد أن المتغير x
قد حجز نفس المساحة التي كنا بتخزين فيها قيمة 40
والتي وصلنا لها عن طريق numbers[3]
وطالما أن هذه المساحة لم تكن محجوزة لأحد فقد قام المتغير x
بحجزها ووضع القيمة 999
فيها
لذا عندما طبعنا numbers[3]
طبع لنا قيمة 999
وليس 40
بعض اللغات تعاتبك عندما تحاول التعدي على مساحة ليست لك أو عندما تخرج خارج حدود الأراي
هناك بعض اللغات ستجدها تستخدم الـ index
السالب للوصول للعناصر من ناحية اليمين
مثلا numbers[-1]
تعني العنصر الأخير في الأراي
و numbers[-2]
تعني العنصر قبل الأخير وهكذا
لكن هذا ليست ميزة متواجدة في جميع اللغات
واحدة من اللغات التي تدعم هذه الميزة بشكل مباشر هي لغة Python
numbers = [12, 16, 24, 25, 28]
print(numbers[-1]) # 28
print(numbers[-2]) # 25
print(numbers[-3]) # 24
print(numbers[-4]) # 16
print(numbers[-5]) # 12
هنا في لغة Python
يمكنك استخدام الـ index
السالب للوصول للعناصر بالعكس
فهنا في حالة أن الأراي تتكون من 5
عناصر
- فالـ
numbers[-1]
تعني العنصر الأول من ناحية اليمين أيnumbers[4]
- والـ
numbers[-2]
تعني العنصر الثاني من ناحية اليمين أيnumbers[3]
- والـ
numbers[-3]
تعني العنصر الثالث من ناحية اليمين أيnumbers[2]
- والـ
numbers[-4]
تعني العنصر الرابع من ناحية اليمين أيnumbers[1]
- والـ
numbers[-5]
تعني العنصر الخامس من ناحية اليمين أيnumbers[0]
باقي اللغات تدعمها لكن عن طريق دوال وسنتعرف عن هذه الدوال في مقالة أخرى
الـ string ما هو إلا أراي من الـ char !!
نعم في بعض اللغات البرمجية خصوصًا القديمة ليس لديها مفهوم الـ string
كنوع بيانات مستقل
بل يعتبر الـ string
مجرد أراي من الـ char
، بمعنى أن الـ string
تم إنشاءه عن طريق أراي من الـ char
مثل لغة C
ليس لديها نوع بيانات string
وكان يتم عمله عن طريق أراي من الـ char
char name[5] = {'A', 'h', 'm', 'e', 'd'};
printf("%s", name); // Ahmed� ^@
هنا قمنا في لغة C
بإنشاء أراي من الـ char
تحتوي على اسم Ahmed
ثم قمنا بطباعتها عن طريق الـ printf
الخاصة بلغة الـ C
ولكن لاحظ أن الناتج لم يكن كما توقعنا
لقد طبع Ahmed� ^@
وليس Ahmed
بسبب أن اللغات القديمة لا تعتبر الـ string
نوع بيانات مستقل بل تعتبره أراي من الـ char
لذا في لغة C
و C++
وبعض اللغات الأخرى يجب أن تضيف في نهاية الأراي شيء يسمى null terminator
وهو اشارة لتعبير عن نهاية الـ string
والـ null terminator
هو الـ \0
وهو يعني null
أي شيء ليس له قيمة أو وجود
وهنا نحن نستخدمه للتعبير عن نهاية الـ string
لا أكثر
إذا لم تضف الـ \0
في نهاية الأراي وحاولت طباعتها فسيقوم البرنامج بطباعة حرف حرف وسيخرج من حدود الأراي
ويظل يطبع كل ما في طريقه حتى يجد الـ \0
ويعتبره نهاية الـ string
لهذا طبع لنا Ahmed� ^@
مع حروف زائدة حصل عليها من الذاكر
يمكننا محاكاة الأمر هكذا
memory (RAM)
ذاكرة الجهاز التي تخزن فيها البيانات
+-----------------------------------------------------+
| |
| داخل حدود الأراي |
| index: [0] [1] [2] [3] [4] خارج حدود الأراي |
| name = {'A', 'h', 'm', 'e', 'd'} � ^@\0 |
| ٨ |
| | |
| عندما وصل لهنا وقف |
| |
+-----------------------------------------------------+
لاحظ أن خرج وظل يطبع حتى صادف الـ \0
وعندما وصل لها توقف
لذا يجب أن نضع الـ \0
في نهاية الأراي ليعرف البرنامج أن هذه نهاية الـ string
char name[6] = {'A', 'h', 'm', 'e', 'd', '\0'};
printf("%s", name); // Ahmed
هنا قمنا بإضافة الـ \0
في نهاية الأراي للتعبير عن نهاية الـ string
وبهذا تم طباعة الـ string
بشكل صحيح
memory (RAM)
ذاكرة الجهاز التي تخزن فيها البيانات
+-----------------------------------------------------+
| |
| index: [0] [1] [2] [3] [4] [5] |
| name = {'A', 'h', 'm', 'e', 'd', '\0'} � ^@\0 |
| ٨ |
| | |
| عندما وصل لهنا وقف |
| |
+-----------------------------------------------------+
في لغة C
يمكنك كتابتها بشكل آخر
char name[6] = "Ahmed";
printf("%s", name); // Ahmed
لاحظ هنا أننا كتبنا الـ string
بشكل مباشر وليس بين الـ {}
ولاحظ أننا هنا لم نحتاج لوضع الـ \0
في نهاية الـ string
لأن اللغة تقوم بذلك تلقائيًا
ولاحظ أن
لكن انتبه أن برغم من كلمة Ahmed
تحتوي على 5
حروف إلا أننا قمنا بإنشاء الأراي بـ 6
خانات
لأننا نحسب حساب الـ \0
وإذا قمنا بجعل الأراي 5
خانات فسيحدث خطأ لأن الـ \0
لن يكون له مكان للتخزين
char name[5] = "Ahmed";
printf("%s", name); // Ahmed� ^@
لذا يجب أن تأخذ في الاعتبار الـ \0
عند إنشاء الـ string
كأراي من الـ char
أو يمكنك عدم كتابة طول الأراي وترك اللغة تقوم بذلك تلقائيًا
char name[] = "Ahmed";
printf("%s", name); // Ahmed
الآن في لغة C++
تم اختصار الأراي من الـ char
وتم انشاء الـ string
لتسهيل الأمر واعطاء مميزات أكثر
وكذلك مع باقي اللغات التي أصبحت تدعم الـ string
كنوع بيانات مستقل
string name = "Ahmed";
cout << name; // Ahmed
لاحظ أننا في لغة C++
لم نحتاج لوضع الـ null terminator
في نهاية الـ string
لأن اللغة تقوم بذلك تلقائيًا
وأيضًا تم توفير العديد من الدوال والميزات لتسهيل التعامل مع الـ string
التي ستتعرفها فيما بعض في مقالة أخرى
لكن تذكر أنه بما أن الـ string
في الواقع أراي من الـ char
فإنه يمكنك الوصول للحروف في الـ string
بنفس الطريقة التي نصل بها للعناصر في الأراي عن طريق الـ index
string name = "Ahmed";
cout << name[0]; // A
cout << name[1]; // h
cout << name[2]; // m
cout << name[3]; // e
cout << name[4]; // d
كما ترى، يمكننا الوصول إلى كل حرف في الـ string
باستخدام الـ index
تمامًا مثل الأراي
ويمكنك التعديل في الـ string
بنفس الطريقة
string name = "Ahmed";
name[0] = 'a';
cout << name; // ahmed
لكن التعديل يكون على مقدار حرف واحد فقط وليس على أكثر من حرف لأنك تتعامل مع كل عنصر كـ Char
string name = "Ahmed";
name[0] = "Kamal"; // ❌ Error
الأراي ثنائية الأبعاد
حتى الآن، تحدثنا عن الأراي ذات البعد الواحد أي صف واحد فقط
لكن في الواقع، يمكنك إنشاء أراي متعددة الأبعاد
يمكنك عمل أراي ثنائية الأبعاد وثلاثية الأبعاد و ... إلخ
الأراي ثنائية الأبعاد في C++
تكون كالتالي
int numbers[2][3] = {
{1, 2, 3},
{4, 5, 6},
};
هنا قمنا بإنشاء أراي ثنائية الأبعاد تحتوي على 2
صف و 3
أعمدة
لاحظ أن الأراي ذات البعد الواحد كانت تكتب هكذا numbers[3]
وكانت كأنها 3
أعمدة في صف واحد
أما في الأراي ثنائية الأبعاد هذا الشكل numbers[2][3]
يعني 2
صف و 3
أعمدة
لاحظ أن المتغير numbers
هو أراي كل عنصر فيها هو أراي آخر
numbers[2][3] = {
{العنصر الأول هو أراي يتكون من ثلاث عناصر},
{العنصر الثاني هو أراي يتكون من ثلاث عناصر},
};
بالتالي عندما تريد هنا الوصول للصف الأول ستكتب numbers[0]
وعندما تريد الوصول للصف الثاني ستكتب numbers[1]
وهكذا
لكن تذكر أن numbers[0]
هو أراي آخر يتكون من 3
عناصر
و numbers[1]
هو أراي آخر يتكون من 3
عناصر
int numbers[2][3] = {
{1, 2, 3},
{4, 5, 6},
};
// numbers[0] = {1, 2, 3}
// numbers[1] = {4, 5, 6}
بالتالي لكي نصل للقيم والعناصر في كل عمود يجب ان نحدد الصف ثم العمود
فلكي نحصل على العنصر الذي في الصف الأول والعمود الأول نكتب numbers[0][0]
ولكي نحصل على العنصر الذي في الصف الأول والعمود الثاني نكتب numbers[0][1]
وهكذا
وتذكر أن الـ index
يبدأ من الـ 0
وليس من الـ 1
كما قلنا
int numbers[2][3] = {
{1, 2, 3},
{4, 5, 6},
};
// طباعة عناصر الصف الأول
cout << numbers[0][0]; // 1
cout << numbers[0][1]; // 2
cout << numbers[0][2]; // 3
// طباعة عناصر الصف الثاني
cout << numbers[1][0]; // 4
cout << numbers[1][1]; // 5
cout << numbers[1][2]; // 6
لاحظ أن الشق الأول من الـ index
يعبر عن الصف والشق الثاني يعبر عن العمود
numbers[الصف][العمود]
بالطبع يمكنك إنشاء أراي ثنائية الأبعاد من أي نوع من البيانات
char alphabet[2][3] = {
{'A', 'B', 'C'},
{'D', 'E', 'F'},
};
cout << alphabet[1][2]; // F
هنا قمنا بإنشاء أراي ثنائية الأبعاد من الـ char
تحتوي على حروف الأبجدية
وبالطبع يمكنك التعديل في الأراي ثنائية الأبعاد
int numbers[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
};
numbers[1][1] = 50;
cout << numbers[1][1]; // 50
هنا قمنا بتغيير قيمة العنصر الذي في الصف الثاني والعمود الثاني من 5
إلى 50
أراي من الـ string هي أراي ثنائية الأبعاد
بما أننا قلنا أن الـ string
هي أراي من الـ char
إذًا أراي من الـ string
هي أراي ثنائية الأبعاد
string names[3] = {
"Ahmed",
"Kamal",
"Mahmoud",
};
هنا قمنا بإنشاء أراي من الـ string
تحتوي على 3
أسماء
لكي نحضر الإسم الأول نقوم بكتابة names[0]
لكي نحضر الإسم الثاني نقوم بكتابة names[1]
وهكذا
string names[3] = {
"Ahmed",
"Kamal",
"Mahmoud",
};
cout << names[0]; // Ahmed
cout << names[1]; // Kamal
cout << names[2]; // Mahmoud
لكي نحضر أول حرف من كل إسم نقوم بكتابة names[0][0]
للإسم الأول والحرف الأول
و names[1][0]
للإسم الثاني والحرف الأول وهكذا
string names[3] = {
"Ahmed",
"Kamal",
"Mahmoud",
};
// الحرف الأول من كل إسم
cout << names[0][0]; // A
cout << names[1][0]; // K
cout << names[2][0]; // M
// الحرف الثاني من كل إسم
cout << names[0][1]; // h
cout << names[1][1]; // a
cout << names[2][1]; // a
ماذا عن الأراي ثلاثية الأبعاد وأكثر ؟
بالطبع يمكنك إنشاء أراي ثلاثية الأبعاد أو رباعية الأبعاد وأكثر
والطريقة تكون كالتالي
int numbers[2][3][4] = {
{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
},
{
{13, 14, 15, 16},
{17, 18, 19, 20},
{21, 22, 23, 24},
},
};
هنا قمنا بإنشاء أراي ثلاثية الأبعاد تحتوي على 2
صف و 3
عمود و 4
عمق
الأمر يكون معقدًا قليلًا لكنه في التخيل أو في انشاءها لكنها عندما تفكر فيها قليلًا ستجدها نفس الشيء
فهي تحتوي على بعد جديد لنسميه العمق
وبالطبع يمكنك الوصول للعناصر في الأراي ثلاثية الأبعاد بنفس الطريقة التي توصلت بها للأراي ثنائية الأبعاد
// numbers[0] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} }
// numbers[0][0] = {1, 2, 3, 4}
// numbers[0][0][0] = 1
cout << numbers[0][0][0]; // 1
cout << numbers[0][0][1]; // 2
cout << numbers[0][0][2]; // 3
cout << numbers[0][0][3]; // 4
لاحظ هنا أن numbers[0]
هي أراي ثنائية الأبعاد بالتالي يمكننا معاملتها كأراي ثنائية الأبعاد اعتيادية
بالتالي لكي نصل للعنصر الذي في الصف الأول والعمود الأول نكتب numbers[0][0][0]
ولكي نصل لعنصر الذي في الصف الأول والعمود الثاني نكتب numbers[0][0][1]
وهكذا
لكن لا تقلق لن تحتاج لأراي ثلاثية الأبعاد أو أكثر في معظم الوقت يمكنك أن تعيش حياتك دون أن تقابلك مسألة تحتاج لأراي ثلاثية الأبعاد أو أكثر
في غالب الوقت تكفيك الأراي ذات البعد الواحد والثنائية الأبعاد
الختام
الأراي هي من أهم الأدوات التي يجب عليك أن تتقنها في البرمجة
فهي تساعدك على تخزين البيانات والعناصر بشكل منظم وسهل
وفيما بعد في المقالات القادمة سنتعرف على العديد من الأدوات والميزات التي تساعدك على التعامل مع الأراي بشكل أفضل
وسنحل مسائل برمجية حقيقية تحتاج لأراي
لذا تأكد من فهمك لها جيدًا
بالطبع توجد تفاصيل أكثر وأكثر عن الأراي والتعامل معها ولكن هذا ما يكفي للبداية
وبالتأكيد ستتعلم المزيد والمزيد كلما تقدمت في البرمجة
وفي المقالات القادمة سنتطرق لها بشكل أعمق