Download as pdf or txt
Download as pdf or txt
You are on page 1of 4

‫‪Dvir Ben Asuli‬‬ ‫‪17/04/2020‬‬

‫נושא ‪ -3‬מערכים דו מימדיים וארגומנטים לפונקציות‬

‫מערך דו ממדי )מטריצה(‪-‬‬


‫מערך דו ממדי הוא בעצם כמו טבלה‪ -‬מערך שכל אחד מהאיברים שלו הוא מערך אחר שמכיל כמה איברים‬

‫אתחול של מערך שגרתי שכזה יהיה למשל ]𝑚[]𝑛[𝑏 𝑡𝑛𝑖‪ -‬כלומר מטריצה של ‪ Integers‬עם ‪ n‬שורות ו‪ m -‬עמודות ‪,‬‬
‫כך שהאיבר הראשון במערך החיצוני זה השורה הראשונה של המטריצה‪ ,‬האיבר הראשון בו זה האיבר בטור הראשון בשורה‬
‫הראשונה וכך הלאה‪.‬‬
‫נזכור שמבחינת הזיכרון‪ ,‬עדיין מדובר פה ברצף אחד של כתובות בזיכרון שממוקמים אחד ליד השני‪ .‬לכן‪ ,‬ניתן לעשות פעולות‬
‫עם מצביעים על מנת לגשת לאיברים שונים במטריצה‪ .‬למשל אם נגדיר מטריצה של ‪ 3‬שורות ו‪ 5-‬עמודות כמו בדוגמא‪ ,‬יש לנו‬
‫‪ 3‬מערכים רצופים בזיכרון‪ ,‬שכל מערך הוא ‪ 5‬תאים רצופים בזיכרון שמהווים את המערך הפנימי )או השורה של המטריצה(‪.‬‬
‫לכן אם אנחנו מדברים למשל על הביטוי ]‪ ,𝑎[0‬בדומה למה שראינו במערכים רגילים‪ ,‬מדובר בכתובת לתחילת המערך‬
‫הראשון במערך החיצוני‪ ,‬כלומר הכתובת ל"תחילת" השורה הראשונה במטריצה‪.‬‬
‫באופן דומה‪ ,‬אם נכתוב ]𝑖[𝑎‪ ,‬מדובר בכתובת ל"תחילת" השורה ה‪ i-‬במטריצה‪ .‬לכן‪ ,‬אם ניקח את הכתובת ]𝑖[𝑎 ונעשה לה‬
‫𝑗‪ +‬עבור כלשהו מספר ‪ ,j‬אנחנו נתקדם ‪ j‬מקומות רצופים בזיכרון‪ ,‬כלומר במקום להיות בתחילת השורה ה‪ i -‬במטריצה‪,‬‬
‫אנחנו נהיה בכתובת של האיבר ה‪ j-‬בשורה ה‪.i -‬‬
‫במילים אחרות הכתובת 𝑗 ‪ 𝑎[𝑖] +‬תהיה הכתובת לאיבר ה‪j -‬‬
‫בשורה ה‪ .i -‬כלומר‪ ,‬אם נרצה לגשת לאיבר זה‪ ,‬נשתמש במצביע‬
‫)𝑗 ‪.*(𝑎[𝑖] +‬‬
‫ישנם עוד כמה צורות )פחות אינטואיטיביות( לעשות את אותו‬
‫דבר‪.‬‬
‫נשים לב שאם לא נשתמש ספציפית ב‪ I -‬עבור ‪ 𝑎[𝑖 ] + 3‬למשל‬
‫אלא נרשום ‪ ,𝑎 + 3‬אנחנו מדברים על ללכת ‪ 3‬כתובות קדימה מתחילת המטריצה כולה‪ .‬לכן לאיזה איבר נגיע תלוי בכמה‬
‫איברים יש בכל שורה בטבלה‪ -‬פשוט נתקדם ‪ 3‬איברים קדימה בשורה הראשונה‪ ,‬ואם חרגנו מהשורה הראשונה נגיע לתחילת‬
‫השורה השנייה וכך הלאה‪ .‬כך למשל אם נתקדם קדימה כמספר האיברים שיש בכל שורה‪ ,‬נגיע להצבעה על תחילת השורה‬
‫השנייה‪ ,‬וכך הלאה‪.‬‬
‫ע ק ר ו נ ו ת א ל ו ש ל ה פ ו י נ ט ר י ם ו ה כ ת ו ב ו ת א מ נ ם ח ש ו ב ו ת ל ה ב נ ת א ו פ ן ה פ ע ו ל ה ש ל ה ק ו מ פ י י ל ר ת ו ך ק ר י א ת ש פ ת ‪ ,C‬א ב ל ת מ י ד‬
‫אפשר להשתמש בכתיב היותר נוח של ]𝑗[]𝑖[𝑎 על מנת לגשת לאיברים במטריצה‪.‬‬

‫‪1‬‬ ‫‪Tel-Aviv University‬‬


‫‪Dvir Ben Asuli‬‬ ‫‪17/04/2020‬‬
‫אם נרצה להכניס מערך דו מימדי כארגומנט של פונקציה ניתן לעשות זאת באופן רגיל‪ ,‬פשוט להכריז על המערך בתוך‬
‫הסוגריים של הארגומנט והפונקציה תבצע פעולות ממש על המטריצה עצמה‪ ,‬ולא על משהו לוקאלי פנימי )שכן היא עוסקת‬
‫עם כתובות(‪.‬‬

‫מערך של מצביעים‪ -‬ראינו כי ניתן לייצר מערך דו מימדי שמהווה מטריצה‪ ,‬ובה יש מספר מסוים של שורות )מספר האיברים‬
‫בערך החיצוני( ומספר מסוים של טורים )מספר האיברים שיש בכל רשימה פנימית במערך הרשימות(‪ .‬במקרה זה‪ ,‬אם נסתכל‬
‫על רשימת הרשימות החיצונית‪ ,‬כל רשימה פנימית בה תהיה עם אותו מספר של איברים‪.‬‬
‫באופן קצת שונה ניתן להגדיר מערך של מצביעים כך ש ב מ ע ר ך י ש מ ס פ ר מ ס ו י ם ש ל א י ב ר י ם ש כ ל א ח ד‬
‫מצביע לכלשו איבר אחר‪ .‬באופן זה‪ ,‬ניתן לעשות שכל מצביע שכזה ברשימה יצביע על כתובת של מערך‬
‫חד מימדי אחר בגדלים משתנים‪ ,‬ובעצם קיבלנו סוג של רשימה של‬
‫רשימות כך שכל רשימה פנימית היא באורך שונה מהאחרות‪.‬‬

‫הקצאה דינמית של מטריצה‪-‬‬


‫בדומה להקצאות הדינמיות שראינו למערכים חד מימדיים‪ ,‬ניתן להקצות‬
‫באופן דומה מטריצות עם גדלים שתלויים במשתנים הנקבעים רק בזמן הריצה‪.‬‬
‫תחילה נאתחל מצביע 𝑝 ∗ למערך ״רגיל״‪ ,‬ומבציע 𝑎 ∗∗ למערך של מצביעים‪.‬‬
‫נ ר צ ה ש ה מ ע ר ך 𝑝 י ה י ה ה מ ט ר י צ ה ש ל נ ו ‪ ,‬ו ל כ ן נ י ת ן ל ו ג ו ד ל כ ו ל ל ש ל ! 𝑛 תאים‬
‫בזיכרון‪ ,‬על ידי פעולת ‪.calloc‬‬
‫כעת נגדיר את מערך המצביעים 𝑎 בגודל 𝑛 בלבד‪ .‬כל תא במערך 𝑎 יכיל מצביע‬
‫ש מ צ ב י ע ל ת א ה ס פ צ י פ י ב מ ע ר ך ה ג ד ו ל 𝑝 ש מ י י צ ג א ת ת ח י ל ה ה ש ו ר ה ה ‪ .𝑖 -‬ל מ ש ל ‪,‬‬
‫]‪ 𝑎[3‬יכיל מצביע לכתובת 𝑛‪ ,𝑝 + 3‬שזה האינדקס במערך 𝑝 שבו מתחילה‬
‫השורה השלישית‪.‬‬
‫למרות שבפעול 𝑝 יהיה המטריצה‪ ,‬על מנת לגשת לתאים נשתמש במערך העזר 𝑎‪ .‬כך למשל שנרשום ]𝑗[]𝑖[ 𝑎 זה ילך לתא ה‪-‬‬
‫𝑖 של מערך 𝑎‪ ,‬ימצא שם את המצביע לתא ה‪ 𝑖 ⋅ 𝑛-‬של המטריצה 𝑝‪ ,‬ו‪n‬שם הוא יסתכל כבר על האיבר באינדקס ה‪ -𝑗-‬מה‬
‫שרעיונית יביא אותנו בדיוק לתא ה‪ (𝑖, 𝑗) -‬במטריצה‪.‬‬

‫טיפוסים מותאמים אישית )‪-(TypeDef‬‬


‫באמצעות ‪ ,TypeDef‬באופן כללי אנחנו יכולים ליצור טיפוסים כאילו חדשים שהם בעצם מבוססים על טיפוסים רגילים‬
‫שקיימים כבר ב‪.C-‬‬
‫למשל אם נגדיר ‪ TypeDef‬מסוג ‪ int‬ונקרא לו לצור העניין ‪ ,Index‬בעצם מה שעשינו זה ליצור כאילו טיפוס חדש שנקרא‬
‫‪ ,Index‬שבפועל הוא יכיל אובייקטים שהם מסוג ‪ Integer‬אבל תחת מסיכה אחרת‪ .‬עניין זה נעשה בד״כ לצורך קריאות‬
‫ושימוש יותר אינטואיטיבי בשמות של טיפוסים‪.‬‬
‫באופן טיפה יותר מורכב‪ ,‬נוכל ליצור טיפוס מותאם אישי של מערך או של מערך דו מימדי )מטריצה( כמו שתיארנו מקודם‪.‬‬
‫ניתן ל‪ TypeDef-‬שם לבחירתנו‪ ,‬ואת הטיפוס שלו נגדיר כמערך של מספרים למשל‪ -‬ואז הטיפוס החדש שיצרנו הוא יהיה‬
‫טיפוס מסוג מערך של מספרים‪.‬‬

‫‪2‬‬ ‫‪Tel-Aviv University‬‬


‫‪Dvir Ben Asuli‬‬ ‫‪17/04/2020‬‬
‫למשל בדוגמא המובאת פה רצינו שיהיה לנו יותר קל לעבוד במונחים של וקטורים‪ .‬לכן‬
‫הגדרנו טיפוס חדש שהוא בעצם אותו דבר כמו ‪ ,Double‬שיהווה את הסקלרים שיהיו‬
‫״בתוך״ הווקטורים‪.‬‬
‫לאחר מכן הגדרנו טיפוס חדש שיקרא ‪ ,Vector‬שהוא בעצם יהיה מערך באורך ‪n‬‬
‫שמכיל אובייקטים מטיפוס הסקלר שהגדרנו מוקדם יותר‪.‬‬
‫לאחר מכן הראינו איך‪ ,‬בשתי דרכים שונות‪ ,‬ניתן ליצור טיפוס נוסף של מטריצה‪ -‬או‬
‫על ידי הגדרת טיפוס שהוא מערך דו מימדי שמשתמש בסקלרים‪ ,‬או תוך הגדרת טיפוס שהוא מערך חד מימדי של אותם‬
‫וקטורים ממקודם‪.‬‬
‫כעת כשניצור משתנה מסוג ‪ Matrix‬הוא יכיל הצבעה לכתובת של מטריצה שכזו‪.‬‬

‫העברת ארגומנטים לתוכנית‬


‫בדומה למה שראינו בשפת ג׳אווה‪ ,‬על מנת שנוכל להריץ את התוכנית שכתבנו נדרש שתהיה פונקציית ‪ Main‬שתקרא בעצם‬
‫לתוכניות השונות שכתבנו‪.‬‬
‫פונקציה זו צריכה להיות מוגדרת על פי הקונבנציה הבאה‪:‬‬

‫נשים לב שרעיונית פונקציה זו מקבלת ‪ 2‬ארגומנטים‪ -‬הראשונה מספר שיהווה את מספר הארגומנטים שיועברו לפונקציה‬
‫)סוג של( והשנייה מערך של מחרוזות‪ -‬הקלטים עצמם‪.‬‬
‫במידה ואנחנו כותבים תוכנית שלא מעבירים אליה ארגומנטים אז זה לא מעניין אותנו בכלל‪.‬‬
‫במידה ואנחנו כן נרצה להעביר ארגומנטים לפונקציה נתעלם מהחלק של ה‪ Int-‬בקלט ונרשום ביחד עם הקריאה לפונקציה‬
‫את הארגומנטים מסוג מ ח ר ו ז ו ת ) ב ל ב ד ( ש נ ר צ ה ל ה כ נ י ס ל ת ו כ נ י ת ‪.‬‬
‫למשל עבור תוכנית שנקראת ‪ Echo‬זה יראה באופן הבא‪:‬‬
‫השם של התוכנית הוא ‪.Echo‬‬
‫העברנו ‪ 2‬ארגומנטים מחרוזות ‪.Apple, Banana‬‬
‫מערך המחרוזות הכולל מכיל סה״כ ‪ 3‬מחרוזות‪ -‬הקריאה לפונקציה בשמה ושני‬
‫הארגומנטים‪.‬‬
‫המספר ‪ Argc‬שמהווה את מספר הקלטים שיוכנסו לפונקציה הוא ‪ -3‬לא רק ‪2‬‬
‫עבור המחרוזות שהכנסנו אלא אחד נוסף עבור מחרוזת הקריאה לפונקציה‪.‬‬

‫העברת פונקציות כארגומנטים של פונקציה‬


‫כמו שניתן להגדיר פונקציה שמקבלת כקלט כלשהו מספר למשל‪ ,‬נ י ת ן ל ה ג ד י ר פ ו נ ק צ י ה ש מ ה ש ה י א ת ק ב ל כ ק ל ט ה ו א ד ו ו ק א‬
‫פונקציה אחרת‪.‬‬
‫עושים זאת בכתיב הבא‪ ,‬תוך שימוש בסוג של ״מצביעים לפונקציות״‪:‬‬

‫‪3‬‬ ‫‪Tel-Aviv University‬‬


‫‪Dvir Ben Asuli‬‬ ‫‪17/04/2020‬‬

‫בתוך הארגומנט של הפונקציה החיצונית כתבנו )‪ (∗ f‬שזהו כאילו המצביע לפונקציה שנכניס כארגומנט‪ .‬מימינה רשמנו‬
‫‪ ,Double‬כי זה מה שהפונקציה שנכניס אמורה לפלוט וכמו כן הגדרנו שהארגומנט של הפונקציה הפנימית יהיה ‪.Double‬‬
‫כעת כשאנחנו רוצים להשתמש בפונקציה שהכנסנו לפונקציה החיצונית בתוך הבלוק שלה נעשה זאת על ידי כתיב )𝑥()𝑓 ∗(‬
‫כך ש‪ x -‬זה מה שנכניס לפונקציה הפנימית‪.‬‬
‫כעת ניתן להגדיר פונקציות באופן נורמלי לחלוטין‪ ,‬ולהכניס אותם כארגומנטים לפונקציה החיצונית שהגדרנו‪.‬‬

‫‪4‬‬ ‫‪Tel-Aviv University‬‬

You might also like