מערך מחזיק מספר קבוע של איברים מטיפוס אחד, שמאוחסנים זה לצד זה בזיכרון. בוחרים את האורך כשיוצרים אותו, קוראים וכותבים איברים לפי אינדקס שמתחיל מאפס, והאורך לא משתנה אחרי זה.
הצהרה על מערך ואתחול
הטיפוס של מערך הוא טיפוס האיבר ואחריו []. יש כמה דרכים ליצור מערך:
פלט:
90, 0, 0, 72
Ben
2 prices, 3 days
new int[4] ממלא כל איבר בערך ברירת המחדל של הטיפוס: 0 למספרים, false ל-bool, null למחרוזות ולטיפוסי הפניה אחרים. הצורה המקוצרת { "Ana", "Ben" } עובדת רק בהצהרה; כשמציבים למשתנה קיים צריך names = new[] { "Dev", "Eli" };.
Length, אינדקסים והאיבר האחרון
האינדקסים רצים מ-0 עד Length - 1. Length הוא מאפיין, ולכן אין לו סוגריים (בניגוד למתודה Count() של LINQ).
פלט:
Count: 5
First: 18
Last: 16
Caught IndexOutOfRangeException
קריאה או כתיבה מחוץ לגבולות זורקות IndexOutOfRangeException בזמן ריצה; הקומפיילר לא תופס את זה. הגורם הרגיל הוא תנאי לולאה שנכתב i <= arr.Length במקום i < arr.Length.
C# 8 ואילך מוסיפות תחביר של אינדקס מהסוף ושל טווחים, שקצר יותר עבור האיבר האחרון ועבור חיתוכים:
int last = temps[^1]; // 16
int[] middle = temps[1..4]; // { 21, 25, 19 }, a new array
לולאה על מערך
לולאת for נותנת את האינדקס; foreach נותנת כל איבר והיא הבחירה הברורה יותר כשרק קוראים.
פלט:
4.95 | 13.20 | 3.58
Total: 21.73
משתנה ה-foreach הוא לקריאה בלבד: p = 0; בתוך הלולאה היא שגיאת קומפילציה. כדי לשנות איברים, השתמשו בלולאה עם אינדקס.
מיון, היפוך וחיפוש
המחלקה הסטטית Array מחזיקה את פונקציות העזר. Array.Sort ממיינת במקום ולא מחזירה כלום, כך שהסדר המקורי אובד.
פלט:
Ascending: 60, 72, 79, 88, 95
Descending: 95, 88, 79, 72, 60
Index of 60: 4
Index of 99: -1
Any above 90: True
First below 75: 72
Ana, ben, chloe
fig, kiwi, banana
Array.IndexOf מחזירה -1 כשהערך חסר. Array.Find מחזירה את ערך ברירת המחדל של הטיפוס (0 כאן) כששום דבר לא תואם, וזה דו-משמעי עבור מספרים; השתמשו ב-Array.FindIndex כשזה חשוב. מיון בסדר יורד בקריאה אחת הוא Array.Sort(scores, (a, b) => b.CompareTo(a)).
אם צריך את התוצאה הממוינת בלי לגעת במקור, LINQ מחזיר מערך חדש: var sorted = scores.OrderBy(s => s).ToArray();. ראו LINQ.
שינוי גודל: מערך לא יכול לגדול
האורך קבוע. Array.Resize יוצרת מערך חדש בגודל המבוקש, מעתיקה את האיברים, ומעדכנת את המשתנה שמעבירים ב-ref.
פלט:
4
2
True
False
כל שינוי גודל מעתיק את כל האיברים. הגדלת מערך באיבר אחד בכל פעם בתוך לולאה היא איטית, וזה בדיוק מה ש-List<T> עושה בשבילכם ביעילות רבה יותר, כשהוא מכפיל את המערך הפנימי שלו.
מערכים הם טיפוסי הפניה: העתקה
הצבת מערך למשתנה אחר מעתיקה את ההפניה, לא את האיברים. אז שני השמות מצביעים על אותו מערך.
פלט:
100
2
0, 100, 2, 3, 0
אותו דבר קורה כשמעבירים מערך למתודה: המתודה יכולה לשנות את האיברים של הקוד הקורא. Clone, Array.Copy, CopyTo ו-ToArray() של LINQ יוצרים כולם עותק רדוד. במערך של אובייקטים, המערך החדש מחזיק הפניות לאותם אובייקטים, כך ששינוי של copy[0].Name עדיין משנה את מה ש-original[0] רואה.
השוואת מערכים עם == משווה הפניות. כדי להשוות תוכן, השתמשו ב-a.SequenceEqual(b) מתוך System.Linq.
מערכים דו-ממדיים (רב-ממדיים)
רשת מלבנית מוצהרת עם פסיק בתוך הסוגריים המרובעים. מאנדקסים אותה עם [row, col].
פלט:
Rows: 2
Cols: 3
Length: 6, Rank: 2
. X .
. . X
Length במערך דו-ממדי הוא מספר האיברים הכולל (6 ברשת של 2 על 3), ולכן לולאות מקוננות משתמשות ב-GetLength(0) וב-GetLength(1). Rank הוא מספר הממדים. שלושה ממדים עובדים באותה דרך: new int[4, 4, 4] ו-cube[x, y, z]. לולאת foreach על מערך דו-ממדי עוברת על כל האיברים שורה אחרי שורה.
מערכים משוננים (מערכים של מערכים)
מערך משונן (jagged array) int[][] הוא מערך שהאיברים שלו הם בעצמם מערכים, ולכל מערך פנימי יכול להיות אורך משלו. הוא מתאים לנתונים כמו "הזמנות לכל לקוח", שבהם השורות שונות בגודלן.
פלט:
Customer 0: 2 orders, 20, 35
Customer 1: 1 orders, 12
Customer 2: 4 orders, 8, 15, 40, 22
True
new int[3][] יוצר רק את המערך החיצוני; כל שורה מתחילה כ-null, ו-orders[0][0] לפני שמציבים שורה זורק NullReferenceException. התחביר new int[3][4] אינו מותר; יוצרים כל שורה בעצמכם.
השתמשו ב-[,] לרשת אמיתית (לוח, מטריצה, פיקסלים) וב-[][] כשלשורות יש אורכים שונים או כשרוצים להחליף שורות שלמות.
מערך מול List
מערך T[] | List<T> | |
|---|---|---|
| גודל | קבוע ביצירה | גדל וקטן |
| ספירה | המאפיין Length | המאפיין Count |
| הוספה או הסרה | לא אפשרי (רק Array.Resize) | Add, Insert, Remove |
| רב-ממדי | [,] ו-[][] | רק רשימות של רשימות |
| שימוש טיפוסי | גודל ידוע, טבלאות חיפוש, buffers | אוספים שמשתנים |
ההמרה היא קריאה אחת לכל כיוון: new List<int>(arr) או arr.ToList(), ו-list.ToArray(). List<T> היא הגרסה שיכולה לגדול.
טעויות נפוצות
i <= arr.Lengthבלולאה. האינדקס התקף האחרון הואLength - 1; זה זורקIndexOutOfRangeException.- הדפסת המערך ישירות.
Console.WriteLine(arr)מדפיסSystem.Int32[]; השתמשו ב-string.Join. - ציפייה ש-
Array.Sortתחזיר את המערך הממוין. היא מחזירהvoidוממיינת במקום. - העתקה עם
=. זה מעתיק את ההפניה; השתמשו ב-Clone()או ב-ToArray(). - שימוש בשורות של מערך משונן לפני שיוצרים אותן. כל שורה של
new T[n][]היאnullעד שמציבים לה ערך. - שימוש ב-
Lengthלמספר השורות של מערך דו-ממדי. הוא סופר את כל האיברים; השתמשו ב-GetLength(0).
שאלות נפוצות
איך מקבלים את האורך של מערך ב-C#?
משתמשים במאפיין Length: scores.Length. זה מאפיין, לא מתודה, ולכן אין סוגריים. במערך דו-ממדי Length הוא המספר הכולל של האיברים; השתמשו ב-GetLength(0) למספר השורות וב-GetLength(1) למספר העמודות.
איך ממיינים מערך ב-C#?
Array.Sort(arr) ממיין את המערך במקום בסדר עולה. לסדר יורד, קראו ל-Array.Reverse(arr) אחרי המיון, או העבירו פונקציית השוואה: Array.Sort(arr, (a, b) => b.CompareTo(a)). כדי לקבל עותק ממוין ולשמור על המקור, השתמשו ב-LINQ: arr.OrderBy(x => x).ToArray().
מה ההבדל בין מערך דו-ממדי למערך משונן ב-C#?
מערך דו-ממדי int[,] הוא בלוק מלבני אחד: בכל שורה יש אותו מספר עמודות, ומאנדקסים אותו כ-grid[row, col]. מערך משונן int[][] הוא מערך של מערכים: כל שורה היא מערך נפרד שיכול להיות לו אורך משלו, ומאנדקסים אותו כ-rows[i][j]. צריך ליצור כל שורה של מערך משונן לפני השימוש, אחרת היא null.
אפשר לשנות את הגודל של מערך ב-C#?
לא. האורך של מערך נקבע כשיוצרים אותו. Array.Resize(ref arr, newSize) נראה כאילו הוא משנה גודל, אבל הוא מקצה מערך חדש, מעתיק את האיברים ומפנה את המשתנה שלכם למערך החדש. אם הגודל משתנה לעיתים קרובות, השתמשו ב-List<T>.
למה הדפסה של מערך מציגה System.Int32[]?
Console.WriteLine(arr) קורא ל-arr.ToString(), ומערכים לא דורסים אותה, אז מקבלים את שם הטיפוס. חברו את האיברים למחרוזת אחת במקום זאת: Console.WriteLine(string.Join(", ", arr)).
כדאי להשתמש במערך או ב-List ב-C#?
השתמשו במערך כשמספר האיברים ידוע וקבוע, כמו 12 החודשים או לוח משחק. השתמשו ב-List<T> כשמוסיפים או מסירים איברים לאורך זמן. בשניהם הגישה לפי אינדקס היא בזמן קבוע, ו-List<T> שומר את האיברים שלו במערך פנימי.