13 זיכרון דינאמי

10
שיעור שלושה- עשר: הקצאת זיכרון דינאמיתonline.shenkar.ac.il/moodle online.shenkar.ac.il/moodle http:// http:// קורס מבוא למדעי המחשב סמסטר א' תשס" ח הקצאת זיכרון דינאמית הקצאת זיכרון דינאמית איזה משתנים יהיו לנו בתוכנית בדיוק עד עכשיו תמיד הגדרנו איזה משתנים יהיו לנו בתוכנית בדיוק עד עכשיו תמיד הגדרנו כבר כשכתבנו אותה כבר כשכתבנו אותה) זה זה נקרא נקרא" " הקצאה סטטית הקצאה סטטית.(" .(" בפרט בפרט, , בהגדרת מערך קבענו את גודלו בהגדרת מערך קבענו את גודלו, , ולא יכולנו לשנות אותו ולא יכולנו לשנות אותו הריצה בזמן הריצה בזמן) אם הגודל לא אם הגודל לא היה היה הנחנו חסם עליון ידוע מראש הנחנו חסם עליון ידוע מראש.( .( למשל למשל: : int int main() main() { int int a[10]; a[10]; } עבור המערך הזה יוקצו עשרה תאים בזיכרון עבור המערך הזה יוקצו עשרה תאים בזיכרון, , ולא נוכל להגדיל אותו תוך ולא נוכל להגדיל אותו תוך כדי הרצת כדי הרצת התוכנית התוכנית.

Upload: yosef-joron

Post on 22-Mar-2016

222 views

Category:

Documents


4 download

DESCRIPTION

C LAN, C LANG

TRANSCRIPT

: עשר-שיעור של ושה

הקצאת זיכרון ד ינאמית

online.shenkar.ac.il/moodleonline.shenkar.ac.il/moodlehttp://http://

קורס מבוא למדעי המחשב

ח"תשס' סמסטר א

הקצאת זיכרון דינאמיתהקצאת זיכרון דינאמית

עד עכש יו תמי ד הג דרנו ב דיוק איזה מש תנ ים י היו ל נו בתוכ ני ת עד עכש יו תמי ד הג דרנו ב דיוק איזה מש תנ ים י היו ל נו בתוכ ני ת ••"). "). הקצאה ס טט י תהקצאה ס טט י ת " "נקראנקראז ה ז ה ((כבר כשכתב נו א ותה כבר כשכתב נו א ותה

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

: : למשללמשל••

intint main()main()

{{

intint a[10];a[10];

}}ולא נוכל להגדיל אותו תוך ולא נוכל להגדיל אותו תוך , , עבור המער ך הזה יוקצו עשרה תאים בזיכרוןעבור המער ך הזה יוקצו עשרה תאים בזיכרון••

..התוכניתהתוכניתכדי הרצת כדי הרצת

הקצאת זיכרון דינאמיתהקצאת זיכרון דינאמית

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

). ). עליון על הגו דל עליון על הגו דל --מראש חסם מראש חסם

שמקצה שמקצה , , mallocmallocיש פונקצי ה ב ש ם יש פונקצי ה ב ש ם : : CC --אפשר לממש דבר כז ה ב אפשר לממש דבר כז ה ב ••. . תוך כד י ריצת ה תוכ נית תוך כד י ריצת ה תוכ נית מקום בז יכרון מקום בז יכרון

..stdlib.hstdlib.hהיא נמצאת בספריה היא נמצאת בספריה ••

והיא והיא , , ))בב תיםבב תים ( ( ג וד ל זיכרו ן מב וקש ג וד ל זיכרו ן מב וקש מעבירים לפו נקציה ה זאת מעבירים לפו נקציה ה זאת ••. . בז י כרון בז י כרוןשהוקצהשהוקצה לאזור בגו דל ה זה לאזור בגו דל ה זה מצב יעמצב יעמחזירה מחזירה

". ". הקצאה די נאמיתהקצאה די נאמית""הקצאת זיכרון בז מן הריצה נקראת הקצאת זיכרון בז מן הריצה נקראת ••

הקצאת זיכרון דינאמית הקצאת זיכרון דינאמית -- דוגמא דוגמא

intint main()main()

{ {

intint * a;* a;

a = a = ((intint * )* ) mallocmalloc (10 * (10 * sizeof(intsizeof(int)) ) ;) ;

}}

מש ת נים מ סוג מש ת נים מ סוג 1010-- מקום רצוף ל מקום רצוף ל תקצה בז יכרוןתקצה בז יכרון: : המשמעו ת ה יאהמשמעו ת ה יא••intint , ,כמצ ביע כמצ ביע , , ותחזיר א ת כתו בת ההתחלה של המקום שהוקצהותחזיר א ת כתו בת ההתחלה של המקום שהוקצה

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

.. בתים בתים4040ים צריך ים צריך intint 1010למער ך של למער ך של ••

.. של השטח שהוקצה בזיכרון של השטח שהוקצה בזיכרוןהכתובתהכתובת תיכנס תיכנס aaלתוך לתוך ••

הקצאת זיכרון דינאמית הקצאת זיכרון דינאמית -- פורמליתפורמלית

((סוג ה מצביע סוג ה מצביע )) = = המצביע המצביע mallocmalloc (( תאים תאים ' ' מסמס ; (; (גודל תא גודל תא * *

: : למשללמשל

a = a = ((intint * )* ) mallocmalloc (10 * (10 * sizeof(intsizeof(int)) ) ;) ;

נדרש כיוון נדרש כיוון ) ) **intintבמקרה הזה במקרה הזה (( לסוג המצביע המתאים לסוג המצביע המתאים castingcasting --הה••).).* void *void((שהפונקציה מחזירה כתובת של רצף בתים שטיפוסו לא מוגדר שהפונקציה מחזירה כתובת של רצף בתים שטיפוסו לא מוגדר

צריך להעביר את זה לטיפוס המתאים כדי לוודא שניגש נכון לערכים צריך להעביר את זה לטיפוס המתאים כדי לוודא שניגש נכון לערכים ••). ). המשתנה המשתנהלגודללגודלבהתאם בהתאם ((שנמצאים שם שנמצאים שם

וגם לבצע חשבון וגם לבצע חשבון , , נוכל לגשת לתאי המערך כמו שניגשים אל מערך רגילנוכל לגשת לתאי המערך כמו שניגשים אל מערך רגיל••).).11 לגשת לכתובת ההתחלה ועוד לגשת לכתובת ההתחלה ועוד למשללמשל((עם המצביע הזה עם המצביע הזה

דוגמאדוגמא: : הקצאת מערך בגודל משתנההקצאת מערך בגודל משתנהintint main() {main() {

intint *a; *a;

intint size, i; size, i;

printf("Enterprintf("Enter array sizearray size\\n");n");

scanf("%dscanf("%d", &size);", &size);

a = a = ((intint *)*) mallocmalloc (size * (size * sizeof(intsizeof(int))););

for (i=0; i<size; i++)for (i=0; i<size; i++)

scanf("%dscanf("%d", &", &a[ia[i]);]);

for (i=0; i<size; i++)for (i=0; i<size; i++)

printf("%dprintf("%d", ", a[ia[i]);]);

return 0;return 0;

}}

דוגמאדוגמא: : הקצאת מערך בגודל משתנההקצאת מערך בגודל משתנהintint main()main()

{{

intint *a, size, i; *a, size, i;

printf("Enterprintf("Enter array sizearray size\\n");n");

scanf("%dscanf("%d", &size);", &size);

a = a = ((intint *)*) mallocmalloc (size * (size * sizeof(intsizeof(int))););

for (i=0; i<size; i++)for (i=0; i<size; i++)

scanf("%dscanf("%d", &", &a[ia[i]);]);

for (i=0; i<size; i++)for (i=0; i<size; i++)

printf("%dprintf("%d", ", a[ia[i]);]);

return 0;return 0;

}}

קולטים את הגו דל ה דרו ש קולטים את הגו דל ה דרו ש

מקצים מקום מקצים מקום

עכשיו אפשר ל משל לק לוט עכשיו אפשר ל משל לק לוט

כמו כמו , , ערכים ולהדפי ס או תםערכים ולהדפי ס או תם

במערך רגילבמערך רגיל

הקצאת זיכרון דינאמיתהקצאת זיכרון דינאמית

כלו מר אין מספיק ז יכרון כלו מר אין מספיק ז יכרון , , אם בקש ת הקצאת ה זיכרון נכשל תאם בקש ת הקצאת ה זיכרון נכשל ת••. . NULLNULL מחזי רה מחזי רה mallocmallocאז הפו נקציה אז הפו נקציה , , להקצאה שב יקש נולהקצאה שב יקש נו

••NULLNULL שמוגדר בספריה שמוגדר בספריה 00 הוא קבוע שערכו הוא קבוע שערכו stdlib.hstdlib.h..

ש אכן הזיכרון ש אכן הזיכרון אחרי כל בקש ת הקצאה אנח נו צריכים ל וו דא אחרי כל בקש ת הקצאה אנח נו צריכים ל וו דא ••: : למ של למ של..שביק ש נו ה תקבל שביק ש נו ה תקבל

intint* a;* a;

a = (a = (intint *) *) mallocmalloc (1000 * (1000 * sizeof(intsizeof(int));));

if (a==if (a==NULLNULL) )

{{

printf("Outprintf("Out of memoryof memory\\n");n");

return return ……

}}

הקצאת זיכרון דינאמיתהקצאת זיכרון דינאמית

stdlib.hstdlib.hכל פונקציו ת ההקצאה ה די נאמי ת נ מצאות בספ ריה כל פונקציו ת ההקצאה ה די נאמי ת נ מצאות בספ ריה ••

•• void *void *malloc(malloc(unsignedunsigned intint sizesize));;

כתובת כתובת קריאה מוצלחת תחזיר את קריאה מוצלחת תחזיר את , , כאמורכאמור. . בתים בתיםsizesize מקצה מקצה

..NULLNULL ואחרת יוחזר ואחרת יוחזר תחילת הזיכרון המוקצהתחילת הזיכרון המוקצה

: : פונקציה נו ספת דומה מאו דפונקציה נו ספת דומה מאו ד••

•• void *void *calloccalloc((unsignedunsigned intint nn,, unsigned unsigned intint size_elsize_el))

כל בית כל בית , , בתים בתיםsize_elsize_elכל איבר בגודל כל איבר בגודל , , איברים איבריםnnמקצה מע רך של מקצה מע רך של

כתובת תחילת הזיכרון כתובת תחילת הזיכרון קריאה מוצלחת תחזיר את קריאה מוצלחת תחזיר את . . מאותחל לאפסמאותחל לאפס

..NULLNULL יוחזריוחזר ואחרת ואחרת המוקצההמוקצה

הקצאת זיכרון דינאמיתהקצאת זיכרון דינאמית

: : פונקציה שימ וש ית נו ספתפונקציה שימ וש ית נו ספת••

•• void *void *realloc(realloc(voidvoid **ptrptr,, unsigned unsigned intint sizesize));;

אותו מצביע שמחזירות אותו מצביע שמחזירות (( לשטח בזיכרון שהוקצה דינאמית לשטח בזיכרון שהוקצה דינאמית מצביעמצביע מקבלת מקבלת

malloc/callocmalloc/calloc(( , , ומספר בתים ומספר בתיםsizesize . .

אם אם . . בהתאם ל דרישה החדשה בהתאם ל דרישה החדשהמשנה את גודל ההקצאהמשנה את גודל ההקצאה הפונקציה הפונקציה

ואין אפשרות להגדיל את השטח ואין אפשרות להגדיל את השטח ההקצאהההקצאההדרישה הייתה להגדיל את הדרישה הייתה להגדיל את

. . והמידע מועתק לשםוהמידע מועתק לשם, , מוקצה שטח חליפי במקום אחרמוקצה שטח חליפי במקום אחר, , הנוכחיהנוכחי

שלא שלא ( (כתובת תחילת הזיכרון המוקצהכתובת תחילת הזיכרון המוקצה קריאה מוצלחת תחזיר את קריאה מוצלחת תחזיר את

..NULLNULL יוחזריוחזרואחרת ואחרת ) ) בהכרח השתנתהבהכרח השתנתה

reallocreallocהדגמת קטע תוכנית עם הדגמת קטע תוכנית עם

intint * a;* a;

intint size,size, new_sizenew_size;;

scanf("%dscanf("%d", &size);", &size);

a = a = ((intint * )* ) mallocmalloc (size* (size* sizeof(intsizeof(int) ) ;) ) ;

…………......

………… ....

scanf("%dscanf("%d", &", &new_sizenew_size););

a= a= ((intint *)*) reallocrealloc((aa, , new_sizenew_size**sizeof(intsizeof(int));));

………………

………………

שחרור זיכרון שהוקצה דינאמיתשחרור זיכרון שהוקצה דינאמית

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

. . סטט יתסטט ית

. . משת נים שמוקצ ים ד ינאמי ת לא נעלמים עם סי ו ם הפונקציהמשת נים שמוקצ ים ד ינאמי ת לא נעלמים עם סי ו ם הפונקציה••

כפי כפי , , באחריות נו להחליט האם ומ תי ל שחרר את ה הקצאה הזאת באחריות נו להחליט האם ומ תי ל שחרר את ה הקצאה הזאת. . שנ סב יר ב שקפים הבא יםשנ סב יר ב שקפים הבא ים

intint main()main()

{{

..

..

f();f();

..

}}

void f()

{

int *x;

x = (int *)malloc(10 * sizeof(int));

….

}

שחרור זיכרון שהוקצה דינאמיתשחרור זיכרון שהוקצה דינאמית, , בזיכרון שהקצנו דינאמית בפונקציהבזיכרון שהקצנו דינאמית בפונקציהלא רוצים להמשיך להשתמש לא רוצים להמשיך להשתמש אם אנחנו אם אנחנו ••

באמצעות באמצעות , , את הזיכרון הזה בפונקציה באופן מפורש את הזיכרון הזה בפונקציה באופן מפורשלשחררלשחרראנחנו צריכים אנחנו צריכים ). ). שתודגם בשקף הבאשתודגם בשקף הבא(( freefreeפקודת פקודת

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

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

אז אנחנו אז אנחנו , , אם לא נשחרר זיכרון שהקצנו וסיימנו להשתמש בו אם לא נשחרר זיכרון שהקצנו וסיימנו להשתמש בו::נשים לבנשים לב•• שלכאורה תפוסים אבל בעצם לא שלכאורה תפוסים אבל בעצם לא באיזוריםבאיזורים המחשב המחשבזיכרוןזיכרוןלמלא את למלא את עלולים עלולים ).). בגלל זה בגלל זההזיכרוןהזיכרוןעלול להיגמר לנו עלול להיגמר לנו ( (""דליפת זיכרוןדליפת זיכרון""מה שנקרא מה שנקרא , , נגישיםנגישים

..בכל מקר ה עד סוף התוכנית צריך לשחרר כל מה שהק צינו דינאמיתבכל מקר ה עד סוף התוכנית צריך לשחרר כל מה שהק צינו דינאמית••

שחרור זיכרון שהוקצה דינאמיתשחרור זיכרון שהוקצה דינאמית

. . מצביע אליו מצביע אליו ptrptr-- ש ש משחררת את הזיכרון משחררת את הזיכרון freefreeהפונקציה הפונקציה ••

void void free(voidfree(void **ptrptr))

;free(xfree(x);) י י ""השימוש פשוט עהשימוש פשוט ע••

••ptrptr ש ל זיכרו ן שה ו קצה לפני כן ש ל זיכרו ן שה ו קצה לפני כןהתחלההתחלה--כתו בת כתו בת צריך להכיל צריך להכיל , ,

). ). reallocrealloc או או calloccallocאו או ( (mallocmallocי י ""כלומר מה שה וחזר עכלומר מה שה וחזר ע

או או , , למשל החל מהמקום השני שהקצינולמשל החל מהמקום השני שהקצינו, , אם ננסה לשחרר משהו אחראם ננסה לשחרר משהו אחר••

..תעוףתעוףאז התוכנית אז התוכנית , , דינאמית דינאמיתהוקצההוקצהכתובת של משתנה שלא כתובת של משתנה שלא

כל הזיכרון שמוקצה דינאמית בתוכנית צריך להיות משוחרר לפני שהיא כל הזיכרון שמוקצה דינאמית בתוכנית צריך להיות משוחרר לפני שהיא ••

).). דואגת לשחרר אם היא מקצה מקום חדש דואגת לשחרר אם היא מקצה מקום חדשreallocreallocפקודת פקודת ((מסתיימת מסתיימת

stdlib.hstdlib.h נמצאת בספריה נמצאת בספריה freefreeגם גם ••

שחרור זיכרון שהוקצה דינאמית שחרור זיכרון שהוקצה דינאמית -- הדגמה הדגמה

void f()

{

int *x;

x = (int *) malloc(10 * sizeof(int));

….

free(x);

}

נקוד ה ל תשומ ת נקוד ה ל תשומ ת --לבלב: : מצביע ים לא מאותח לים מצביע ים לא מאותח לים

שכמו כל מ ש תנה גם מצביע ים אי נם מאותחל ים שכמו כל מ ש תנה גם מצביע ים אי נם מאותחל ים , , חשוב לזכורחשוב לזכור••

. . ערךערךוצריך לת ת להם וצריך לת ת להם , , בהג דרה שלהםבהג דרה שלהם

אם ננ סה לג שת לכתו בת ש נמצאת ב מצביע בלי שנ תנ ו לו ערך אם ננ סה לג שת לכתו בת ש נמצאת ב מצביע בלי שנ תנ ו לו ערך ••

: : למ שללמ של". ". תע וףתע וף""הת וכני ת הת וכני ת , , התחלתי התחלתי

intint *p;*p;

*p=10;*p=10;

רק אם שמנו בו קודם כתובת של רק אם שמנו בו קודם כתובת של אפשר לגשת לכתובת שנמצאת במצביע אפשר לגשת לכתובת שנמצאת במצביע

::למשללמשל).). זה משתנה שהוקצה סטטית או דינאמית זה משתנה שהוקצה סטטית או דינאמיתאםאםלא חשוב לא חשוב ( (משתנהמשתנה

intint i;i;

p=&i;p=&i;

: : אואו

p=(p=(intint *) *) mallocmalloc (5*(5*sizeof(intsizeof(int));));

לא אותחלה לא אותחלה pp --הכתובת בהכתובת ב

נקוד ה ל תשומ ת נקוד ה ל תשומ ת --לבלב: : מצביע ים לא מאותח לים מצביע ים לא מאותח לים

י הכנסת כתובת י הכנסת כתובת ""אפשרות נוספת שראינו למתן ערך למצביע היא עאפשרות נוספת שראינו למתן ערך למצביע היא ע, , כזכורכזכור••

.. אחר אליו אחר אליומצביעמצביעשל מערך או של של מערך או של

intint a[10];a[10];

p=a;p=a;

עוד נקודה לתשומתעוד נקודה לתשומת--לבלב: : מחרוזת קבועהמחרוזת קבועהמחרוזת מחרוזת לאלא(( בלי לאתחל אותו בלי לאתחל אותו charchar למצביע על למצביע על מחרוזת קבועהמחרוזת קבועהאם נכניס אם נכניס ••

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

כל מחרוזת כל מחרוזת הקומפיילר שומר בזיכרון הקומפיילר שומר בזיכרון ::השמה של כתובותהשמה של כתובותזה כיוון שזאת זה כיוון שזאת ••כתובת כתובת איזשהיאיזשהיולכן למחרוזת הזאת כבר יש ולכן למחרוזת הזאת כבר יש , , בתוכניתבתוכנית שהוא מוצא שהוא מוצא קבועהקבועה..המצביע רק מצביע לשםהמצביע רק מצביע לשם. . שבה היא מאוחסנת שבה היא מאוחסנתבזיכרוןבזיכרון

:: למשל אפשר לכתוב למשל אפשר לכתוב

char *pc, *char *pc, *psps;;

pc="Hello!";pc="Hello!";

psps="Hello!";="Hello!";

;'?'=pc[5]='?';pc[5] : : אבל אחרי השורות אבל אחרי השורות

printf("%sprintf("%s\\nn", ", psps););

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

'H''H' 'e''e' 'l''l' 'l''l' 'o''o' '!''!' ''\\0'0'pspspcpc

'?''?'

סיכום סיכום--הקצאת זיכרון דינאמית הקצאת זיכרון דינאמית

זה מאפשר בפרט זה מאפשר בפרט . . אפשר להקצות מק ום ב זיכרון בזמ ן הריצהאפשר להקצות מק ום ב זיכרון בזמ ן הריצה••). ). גו דל שלא י דוע מראש גו דל שלא י דוע מראש ((להגדיר מערך ב גו דל ש תלו י בקל ט להגדיר מערך ב גו דל ש תלו י בקל ט

,malloc,calloc, realloc, malloc,calloc, realloc נמצאו ת הפקו דו ת נמצאו ת הפקו דו ת stdlib.hstdlib.hבספריה בספריה ••freefree..

. . צריך לזכור לשחרר מה ש הקצינ ו כשמ סי ימים ל השתמ ש בזהצריך לזכור לשחרר מה ש הקצינ ו כשמ סי ימים ל השתמ ש בזה••

כתיבה לכתו בת ש נמצאת במצביע לא מאותחל תגרום לתע ופה כתיבה לכתו בת ש נמצאת במצביע לא מאותחל תגרום לתע ופה ••. . צריך לזכור לאתחל אותו צריך לזכור לאתחל אותו––

? ? שאלות נ וספ ותשאלות נ וספ ות

עשרעשר--שיעור שלושהשיעור שלושה –– מבוא למדעי המחשבמבוא למדעי המחשב