Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Studies

הקצאה דינמית (dynamic allocation)

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

נניח שנרצה מערך בגודל דינמי ונכתוב משהו בסגנון הזה:

#include <stdio.h>
int main(void) {
    int array_length;
    scanf("%d", &array_length);
    int array[array_length];
}

נקבל את השגיאה הבאה:

dyn_alloc_warning.c:5:15: error: variable length array used [-Werror,-Wvla]
    5 |     int array[array_length];
      |               ^~~~~~~~~~~~

מה ביקשנו בעצם מהקומפיילר? תקצה לנו על מחסנית הקריאות מערך באורך array_length. עם זאת, לקומפיילר אין מושג איזה מספר המשתמש יכניס! הוא לא יודע להגיד בזמן הקומפילציה כמה בתים על מחסנית הקריאות צריך לפנות בשביל שיהיה מספיק מקום לכל המערך, ולכן יסרב לקמפל את הקוד שלנו.

Warning

קיימות גרסאות קומפיילרים שתחת הגדרות מסוימות לא יפלטו את השגיאה הזו - יתכן ולא תראו אותה אם תנסו בעצמכם. הסיבה לכך שהיא שבסטנדרטים מסוימים של שפת C הייתה תכונה שנויה במחלוקת בשם variable length arrays שאפשרה הצהרות מסוג זה, אבל היא מאוד לא מקובלת ולא בשימוש כיום מסיבות שלא נכנס אליהן.

ניתן לחשוב שמדובר בבעיה לא קריטית, אבל זו תהיה טעות. נניח שאנחנו כותבים תוכנית שקוראת מקובץ אקסל את הציונים של כל הסטודנטים בקורס ומכניסה אותם למערך בשביל לחשב עליהם סטטיסטיקות. כל סמסטר יש מספר שונה של סטודנטים - איך על התוכנית לפעול? תוכניות שצריכות לבצע פעולות התלויות בקלט הן מהנפוצות ביותר ולכן לא נוכל להסתפק בהקצאת זכרון סטאטית בלבד.

נאפיין את הפתרון שאנחנו רוצים, בדומה לאיך שהקומפיילר עובד עם הקצאות סטאטיות:

  1. אנחנו צריכים דרך בה התוכנית שלנו תקצה גודל מסוים של זכרון שאינו על מחסנית הקריאות - זאת בדומה לדחיפה על מחסנית הקריאות של הקומפיילר.
  2. אנחנו צריכים לקבל מצביע לאותו איזור בזכרון שהקצנו - זאת בדומה להכרזה על מערך סטאטי.
  3. אנחנו צריכים לדעת “לשחרר” את הזכרון אחרי שסיימנו איתו - זאת בדומה לקיפול המחסנית בסוף קריאה לפונקציה.

למעשה, אנחנו רוצים לנהל מעין מחסנית משל עצמנו! ונעשה בדיוק את זה מיד.