Presentation is loading. Please wait.

Presentation is loading. Please wait.

מבוא כללי למדעי המחשב הקצאת זיכרון דינאמית www.cs.tau.ac.il/courses/cs4math/09b.

Similar presentations


Presentation on theme: "מבוא כללי למדעי המחשב הקצאת זיכרון דינאמית www.cs.tau.ac.il/courses/cs4math/09b."— Presentation transcript:

1 מבוא כללי למדעי המחשב הקצאת זיכרון דינאמית www.cs.tau.ac.il/courses/cs4math/09b

2 מבנים - תזכורת אפשר להגדיר בשפת C טיפוסי משתנים חדשים, שמתאימים יותר לבעיה שרוצים לפתור. אפשר להגדיר בשפת C טיפוסי משתנים חדשים, שמתאימים יותר לבעיה שרוצים לפתור. למשל: מס' מרוכב, נקודה במישור, מלבן, סטודנט... למשל: מס' מרוכב, נקודה במישור, מלבן, סטודנט... טיפוס חדש כזה נקרא "מבנה". טיפוס חדש כזה נקרא "מבנה". מבנה מוגדר על-ידי אוסף של משתנים מטיפוסים שכבר קיימים ("שדות"). מבנה מוגדר על-ידי אוסף של משתנים מטיפוסים שכבר קיימים ("שדות"). למשל מבנה ליצוג נקודה במישור יכלול שני שדות שהם מספרים ממשיים: קואורדינטת X וקואורדינטת Y. למשל מבנה ליצוג נקודה במישור יכלול שני שדות שהם מספרים ממשיים: קואורדינטת X וקואורדינטת Y. מבנה ליצוג סטודנט יכול לכלול שם, ת.ז., טלפון, וכו'. מבנה ליצוג סטודנט יכול לכלול שם, ת.ז., טלפון, וכו'.

3 תזכורת: דוגמאות שראינו למבנים נקודה במישור: נקודה במישור: struct point { double x; double y; }; מספר מרוכב: מספר מרוכב: struct complex { double real; double img; };

4 תזכורת: עוד דוגמא שראינו מבנה ליצוג סטודנט: מבנה ליצוג סטודנט: struct student{ struct student{ int id; int id; char name[40]; char name[40]; double average; double average;};

5 תזכורת: מבנים – הגדרה וגישה #include<stdio.h> struct point { double x; double y; }; int main() { struct point P1,P2; struct point P1,P2; P1.x = 6; P1.x = 6; P1.y = 7; P1.y = 7; P2.x = 4; P2.x = 4; P2.y = 2; P2.y = 2; printf(“%g\n”, P1.y); printf(“%g\n”, P1.y); return 0; return 0;} P1P2 4 72 6xyxy

6 תזכורת: שם מקוצר לטיפוס משתנה חדש struct point { double x; double y; }; typedef struct point point; זה מאפשר לכתוב point במקום לכתוב struct point. אפשר גם לרשום את זה כך: typedef struct point { double x; double y; } point; שם חדש טיפוס קיים

7 תזכורת: התכונות של מבנים למשתנים מטיפוס חדש (מבנה) יש חלק גדול מהתכונות של משתנים מטיפוסים רגילים: למשתנים מטיפוס חדש (מבנה) יש חלק גדול מהתכונות של משתנים מטיפוסים רגילים: אפשר לבצע השמה בין שני משתנים מאותו טיפוס מבנה p1=p2; אפשר לבצע השמה בין שני משתנים מאותו טיפוס מבנה p1=p2; גם שדה שהוא מערך יועתק אל המשתנה החדש (לא רק כתובת המערך)גם שדה שהוא מערך יועתק אל המשתנה החדש (לא רק כתובת המערך) אפשר להגדיר מערך של מבנים מטיפוס כלשהו (למשל point a[10]). אפשר להגדיר מערך של מבנים מטיפוס כלשהו (למשל point a[10]). אפשר להעביר ולהחזיר מבנה מפונקציה. אפשר להעביר ולהחזיר מבנה מפונקציה. מה שמועבר הוא עותק של המבנה (גם מערכים שנמצאים בתוכו יועתקו).מה שמועבר הוא עותק של המבנה (גם מערכים שנמצאים בתוכו יועתקו). אפשר להגדיר מצביע למשתנה מטיפוס מבנה (למשל complex *). אפשר להגדיר מצביע למשתנה מטיפוס מבנה (למשל complex *). שדה של מבנה יכול להיות מטיפוס שהוא מבנה (אחר). שדה של מבנה יכול להיות מטיפוס שהוא מבנה (אחר). לא ניתן להשתמש בפעולות החשבון וההשוואה הרגילות על מבנים - יש להגדיר פונקציות עבורן בהתאם לצורך. לא ניתן להשתמש בפעולות החשבון וההשוואה הרגילות על מבנים - יש להגדיר פונקציות עבורן בהתאם לצורך.

8 תזכורת: מבנים ומצביעים אפשר להגדיר מצביע גם לטיפוס שהוא מבנה (כתובת ההתחלה של מבנה היא כתובת השדה הראשון שלו). אפשר להגדיר מצביע גם לטיפוס שהוא מבנה (כתובת ההתחלה של מבנה היא כתובת השדה הראשון שלו). נשתמש בזה כדי לשנות מבנה מתוך פונקציה, או כדי לחסוך את העתקת השדות בהעברת המבנה אליה. נשתמש בזה כדי לשנות מבנה מתוך פונקציה, או כדי לחסוך את העתקת השדות בהעברת המבנה אליה. למשל: למשל: struct point P={5,6}; struct point *ptr; ptr = &P ; 5 6 P ptr P.x P.y

9 מצביעים ומבנים – גישה לשדות המבנה כדי להגיע לשדות של P דרך ptr שמצביע על P, אפשר להשתמש ב- * כרגיל: כדי להגיע לשדות של P דרך ptr שמצביע על P, אפשר להשתמש ב- * כרגיל: (*ptr).x = 3; שקול ל- P.x = 3 (*ptr).x = 3; שקול ל- P.x = 3 (*ptr).y = 7; שקול ל- P.y = 7 (*ptr).y = 7; שקול ל- P.y = 7 אבל בדרך-כלל נשתמש לצורך זה בסימון מקוצר: חץ <- אבל בדרך-כלל נשתמש לצורך זה בסימון מקוצר: חץ <- ptr->x = 3; שקול ל- P.x = 3 ptr->x = 3; שקול ל- P.x = 3 ptr->y = 7; שקול ל- P.y = 7 ptr->y = 7; שקול ל- P.y = 7 כלומר משמעות החץ היא גישה לשדה במבנה שמצביעים עליו. כלומר משמעות החץ היא גישה לשדה במבנה שמצביעים עליו. (צריך סוגריים כי אחרת לנקודה יש קדימות) (צריך סוגריים כי אחרת לנקודה יש קדימות)

10 תזכורת: מבנים ומצביעים struct point P={5,6}; struct point *ptr; ptr = &P ; 5 6 P ptr P.x P.y ptr -> y ptr -> x אם השדה x היה בעצמו מטיפוס מצביע למבנה אחר שיש בו שדה a, אז היה אפשר לרשום ptr->x->a אם השדה x היה בעצמו מטיפוס מצביע למבנה אחר שיש בו שדה a, אז היה אפשר לרשום ptr->x->a

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

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

13 הקצאת זיכרון דינאמית לפעמים נירצה להגדיר משתנים נוספים בזמן הריצה, בפרט להגדיר מערך בגודל שתלוי בקלט מהמשתמש (יתכן שלא ידוע מראש חסם-עליון על הגודל). לפעמים נירצה להגדיר משתנים נוספים בזמן הריצה, בפרט להגדיר מערך בגודל שתלוי בקלט מהמשתמש (יתכן שלא ידוע מראש חסם-עליון על הגודל). אפשר לממש דבר כזה ב- C: יש פונקציה בשם malloc, שמקצה מקום בזיכרון תוך כדי ריצת התוכנית (הגודל יכול להיות תלוי בקלט). אפשר לממש דבר כזה ב- C: יש פונקציה בשם malloc, שמקצה מקום בזיכרון תוך כדי ריצת התוכנית (הגודל יכול להיות תלוי בקלט). היא נמצאת בספריה stdlib.h. היא נמצאת בספריה stdlib.h. מעבירים לפונקציה הזאת גודל זיכרון מבוקש (בבתים), והיא מחזירה מצביע לאזור בגודל הזה שהוקצה בזיכרון. מעבירים לפונקציה הזאת גודל זיכרון מבוקש (בבתים), והיא מחזירה מצביע לאזור בגודל הזה שהוקצה בזיכרון. הקצאת זיכרון בזמן הריצה נקראת "הקצאה דינאמית". הקצאת זיכרון בזמן הריצה נקראת "הקצאה דינאמית".

14 הקצאת זיכרון דינאמית – דוגמא int main() int main() { int num, *a; int num, *a; scanf(“%d”, &num); scanf(“%d”, &num); a = (int *) malloc (num * sizeof(int) ) ; a = (int *) malloc (num * sizeof(int) ) ; } המשמעות היא: תקצה בזיכרון מקום רצוף בגודל num משתנים מסוג int, ותחזיר את כתובת ההתחלה של המקום שהוקצה, כמצביע ל- int. ההקצאה מתבצעת בזמן ריצת התוכנית. המשמעות היא: תקצה בזיכרון מקום רצוף בגודל num משתנים מסוג int, ותחזיר את כתובת ההתחלה של המקום שהוקצה, כמצביע ל- int. ההקצאה מתבצעת בזמן ריצת התוכנית. הפונקציה sizeof מחזירה גודל בבתים של משתנה או טיפוס משתנה (int דורש בדרך-כלל 4 בתים). הפונקציה sizeof מחזירה גודל בבתים של משתנה או טיפוס משתנה (int דורש בדרך-כלל 4 בתים). לתוך a תיכנס הכתובת של השטח שהוקצה בזיכרון. לתוך a תיכנס הכתובת של השטח שהוקצה בזיכרון.

15 הקצאת זיכרון דינאמית - פורמלית המצביע = (סוג המצביע) malloc (מס' תאים * גודל תא) ; המצביע = (סוג המצביע) malloc (מס' תאים * גודל תא) ;למשל: a = (int * ) malloc (10 * sizeof(int) ) ; a = (int * ) malloc (10 * sizeof(int) ) ; ה- casting לסוג המצביע המתאים (במקרה הזה int *) נדרש כיוון שהפונקציה מחזירה כתובת של רצף בתים שטיפוסו לא מוגדר (void *). ה- casting לסוג המצביע המתאים (במקרה הזה int *) נדרש כיוון שהפונקציה מחזירה כתובת של רצף בתים שטיפוסו לא מוגדר (void *). צריך להעביר את זה לטיפוס המתאים כדי לוודא שניגש נכון לערכים שנמצאים שם (בהתאם לגודל המשתנה). צריך להעביר את זה לטיפוס המתאים כדי לוודא שניגש נכון לערכים שנמצאים שם (בהתאם לגודל המשתנה). נוכל לגשת לתאי המערך כמו שניגשים אל מערך רגיל, וגם לבצע חשבון עם המצביע הזה (למשל לגשת לכתובת ההתחלה ועוד 1). נוכל לגשת לתאי המערך כמו שניגשים אל מערך רגיל, וגם לבצע חשבון עם המצביע הזה (למשל לגשת לכתובת ההתחלה ועוד 1).

16 דוגמא: הקצאת מערך בגודל משתנה int main() { int *a, size,i; printf(“Enter array size\n”); scanf(“%d”, &size); a = (int *) malloc (size * sizeof(int)); for (i=0; i<size; i++) scanf(“%d”, &a[i]); for (i=0; i<size; i++) printf(“%d”, a[i]); return 0; } קולטים את הגודל הדרוש מקצים מקום עכשיו אפשר למשל לקלוט ערכים ולהדפיס אותם, כמו במערך רגיל (אבל שימו לב ש- a הוא מצביע ולא מערך, לכן ניתן למשל לשנות את ערכו כך שהוא יצביע אחר-כך למקום אחר)

17 הקצאת זיכרון דינאמית אם בקשת הקצאת הזיכרון נכשלת, כלומר אין מספיק זיכרון להקצאה שביקשנו, אז הפונקציה malloc מחזירה NULL. אם בקשת הקצאת הזיכרון נכשלת, כלומר אין מספיק זיכרון להקצאה שביקשנו, אז הפונקציה malloc מחזירה NULL. NULL הוא כזכור קבוע שערכו 0 שמוגדר בספריה stdlib.h. NULL הוא כזכור קבוע שערכו 0 שמוגדר בספריה stdlib.h. אחרי כל בקשת הקצאה אנחנו צריכים לוודא שאכן הזיכרון שביקשנו התקבל. למשל: אחרי כל בקשת הקצאה אנחנו צריכים לוודא שאכן הזיכרון שביקשנו התקבל. למשל: int *a; int *a; a = (int *) malloc (1000 * sizeof(int)); a = (int *) malloc (1000 * sizeof(int)); if (a==NULL) if (a==NULL) { printf(“Out of memory\n”); printf(“Out of memory\n”); exit(1); exit(1); }

18 הקצאת זיכרון דינאמית כל פונקציות ההקצאה הדינאמית נמצאות בספריה stdlib.h כל פונקציות ההקצאה הדינאמית נמצאות בספריה stdlib.h void *malloc(unsigned int size); void *malloc(unsigned int size); מקצה size בתים. כאמור, קריאה מוצלחת תחזיר את כתובת תחילת הזיכרון המוקצה ואחרת יוחזר NULL. מקצה size בתים. כאמור, קריאה מוצלחת תחזיר את כתובת תחילת הזיכרון המוקצה ואחרת יוחזר NULL. פונקציה נוספת דומה מאוד: פונקציה נוספת דומה מאוד: void *calloc(unsigned int n, unsigned int size_el); void *calloc(unsigned int n, unsigned int size_el); מקצה מערך של n איברים, כל איבר בגודל size_el בתים, כל בית מאותחל לאפס. קריאה מוצלחת תחזיר את כתובת תחילת הזיכרון המוקצה ואחרת יוחזר NULL. דוגמת שימוש: ptr=(int *) calloc(10,sizeof(int)); דוגמת שימוש: ptr=(int *) calloc(10,sizeof(int));

19 הקצאת זיכרון דינאמית פונקציה שימושית נוספת: פונקציה שימושית נוספת: void *realloc(void *ptr, unsigned int size); void *realloc(void *ptr, unsigned int size); מקבלת מצביע לשטח בזיכרון שהוקצה דינאמית (אותו מצביע שמחזירות malloc/calloc), ומספר בתים size (שהוא הגודל החדש הדרוש). מקבלת מצביע לשטח בזיכרון שהוקצה דינאמית (אותו מצביע שמחזירות malloc/calloc), ומספר בתים size (שהוא הגודל החדש הדרוש). הפונקציה משנה את גודל ההקצאה בהתאם לדרישה החדשה. אם הדרישה הייתה להגדיל את ההקצאה ואין אפשרות להגדיל את השטח הנוכחי, מוקצה שטח חליפי במקום אחר, והמידע מועתק לשם. הפונקציה משנה את גודל ההקצאה בהתאם לדרישה החדשה. אם הדרישה הייתה להגדיל את ההקצאה ואין אפשרות להגדיל את השטח הנוכחי, מוקצה שטח חליפי במקום אחר, והמידע מועתק לשם. קריאה מוצלחת תחזיר את כתובת תחילת הזיכרון המוקצה (שלא בהכרח השתנתה) ואחרת יוחזר NULL. קריאה מוצלחת תחזיר את כתובת תחילת הזיכרון המוקצה (שלא בהכרח השתנתה) ואחרת יוחזר NULL.

20 הדגמת קטע תוכנית עם realloc int * a; int size, new_size; int size, new_size; scanf(“%d”, &size); scanf(“%d”, &size); a = (int *) malloc ( size * sizeof(int) ) ; ……... ……... …….. …….. scanf(“%d”, &new_size); scanf(“%d”, &new_size); a= (int *) realloc(a, new_size * sizeof(int) ); a= (int *) realloc(a, new_size * sizeof(int) ); ……… ………

21 שחרור זיכרון שהוקצה דינאמית כזכור, אמרנו בעבר שמשתנים שמוגדרים בתוך פונקציה נעלמים אוטומטית עם סיומה. זה נכון רק לגבי משתנים שמוגדרים סטטית. כזכור, אמרנו בעבר שמשתנים שמוגדרים בתוך פונקציה נעלמים אוטומטית עם סיומה. זה נכון רק לגבי משתנים שמוגדרים סטטית. משתנים שמוקצים דינאמית לא נעלמים עם סיום הפונקציה. משתנים שמוקצים דינאמית לא נעלמים עם סיום הפונקציה. באחריותנו לשחרר את ההקצאה הזאת כשנסיים להשתמש בה, כפי שנסביר בשקפים הבאים. באחריותנו לשחרר את ההקצאה הזאת כשנסיים להשתמש בה, כפי שנסביר בשקפים הבאים. int main() int main() {.. f(); f();. } void f() { int *x; x = (int *)malloc(10 * sizeof(int)); …. }

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

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

24 שחרור זיכרון שהוקצה דינאמית הפונקציה free, שנמצאת בספריה stdlib.h, מקבלת מצביע ומשחררת את הזיכרון שהוא מצביע אליו. הגדרתה היא:הפונקציה free, שנמצאת בספריה stdlib.h, מקבלת מצביע ומשחררת את הזיכרון שהוא מצביע אליו. הגדרתה היא: void free(void *ptr) השימוש פשוט ע"י free(x);השימוש פשוט ע"י free(x); המצביע שמועבר ל-free חייב להכיל כתובת-התחלה של זיכרון שהוקצה דינאמית לפני כן (כלומר כתובת שהוחזרה ע"י malloc או calloc או realloc), ואז ההקצאה הזאת מבוטלת.המצביע שמועבר ל-free חייב להכיל כתובת-התחלה של זיכרון שהוקצה דינאמית לפני כן (כלומר כתובת שהוחזרה ע"י malloc או calloc או realloc), ואז ההקצאה הזאת מבוטלת. אם ננסה לשחרר משהו אחר, למשל החל מהמקום השני שהקצינו, או כתובת של משתנה שלא הוקצה דינאמית, אז התוכנית "תעוף".אם ננסה לשחרר משהו אחר, למשל החל מהמקום השני שהקצינו, או כתובת של משתנה שלא הוקצה דינאמית, אז התוכנית "תעוף". לגבי פקודת realloc: אם היא מקצה שטח חדש אז היא משחררת בעצמה את השטח הישן (צריך לשחרר בעצמנו רק את השטח החדש).לגבי פקודת realloc: אם היא מקצה שטח חדש אז היא משחררת בעצמה את השטח הישן (צריך לשחרר בעצמנו רק את השטח החדש).

25 שחרור זיכרון שהוקצה דינאמית - הדגמה void f() { int *x; x = (int *) malloc(10 * sizeof(int)); …. free(x); }

26 החזרת זיכרון שהוקצה דינאמית - הדגמה int *f() { int *x; x = (int *) malloc(10 * sizeof(int)); …. return x; }

27 החזרת זיכרון שהוקצה דינאמית - הדגמה int * allocate_int_array(int size) { int *ptr; ptr = (int *) malloc(size * sizeof(int)); if (ptr==NULL) { printf(“Out of memory”); exit(1); } return ptr; } הפונקציה מקצה דינאמית מערך של מס' שלמים בגודל המבוקש, בודקת שההקצאה הצליחה, ומחזירה את כתובת המערך שהוקצה. אפשר להחזיר את כתובת המערך הזה, שלא משוחרר בסוף הפונקציה כי הוא הוקצה דינאמית, אבל מי שקרא לפונקציה צריך לדאוג לשחררו בסיום השימוש בו.

28 נקודה לתשומת-לב: מצביעים לא מאותחלים חשוב לזכור, שכמו כל משתנה גם מצביעים אינם מאותחלים בהגדרה שלהם, וצריך לתת להם ערך.חשוב לזכור, שכמו כל משתנה גם מצביעים אינם מאותחלים בהגדרה שלהם, וצריך לתת להם ערך. אם ננסה לגשת לכתובת שנמצאת במצביע בלי שנתנו לו ערך התחלתי, התוכנית "תעוף". למשל:אם ננסה לגשת לכתובת שנמצאת במצביע בלי שנתנו לו ערך התחלתי, התוכנית "תעוף". למשל: int *p; *p=10; אפשר לגשת לכתובת שנמצאת במצביע רק אם שמנו בו קודם כתובת של משתנה או של שטח שהוקצה דינאמית. למשל: אפשר לגשת לכתובת שנמצאת במצביע רק אם שמנו בו קודם כתובת של משתנה או של שטח שהוקצה דינאמית. למשל: int i; p=&i;או: p=(int *) malloc (5*sizeof(int)); הכתובת ב- p לא אותחלה

29 נקודה לתשומת-לב: מצביעים לא מאותחלים כזכור, אפשרות נוספת שראינו למתן ערך למצביע היא ע"י הכנסת כתובת של מערך או של מצביע אחר אליו.כזכור, אפשרות נוספת שראינו למתן ערך למצביע היא ע"י הכנסת כתובת של מערך או של מצביע אחר אליו. int a[10]; p=a;

30 עוד נקודה לתשומת-לב: מחרוזת קבועה אם נכניס מחרוזת קבועה למצביע על char בלי לאתחל אותו (לא מחרוזת מהקלט) אז לא תיקרה תעופה, אפילו שלא בוצעה הקצאה כלשהי ואפילו שלא ניתן להעתיק מחרוזות על-ידי השמה.אם נכניס מחרוזת קבועה למצביע על char בלי לאתחל אותו (לא מחרוזת מהקלט) אז לא תיקרה תעופה, אפילו שלא בוצעה הקצאה כלשהי ואפילו שלא ניתן להעתיק מחרוזות על-ידי השמה. זה כיוון שזאת השמה של כתובות: הקומפיילר שומר בזיכרון כל מחרוזת קבועה שהוא מוצא בתוכנית, ולכן למחרוזת הזאת כבר יש איזשהי כתובת בזיכרון שבה היא מאוחסנת. המצביע רק מצביע לשם.זה כיוון שזאת השמה של כתובות: הקומפיילר שומר בזיכרון כל מחרוזת קבועה שהוא מוצא בתוכנית, ולכן למחרוזת הזאת כבר יש איזשהי כתובת בזיכרון שבה היא מאוחסנת. המצביע רק מצביע לשם. למשל אפשר לכתוב: למשל אפשר לכתוב: char *pc, *ps; pc=“Hello!”;ps=“Hello!”; קומפיילרים סטנדרטיים לא יאפשרו לשנות מחרוזת קבועה כזו (כי שינוי ישפיע על כל הופעותיה בתוכנית). קומפיילרים סטנדרטיים לא יאפשרו לשנות מחרוזת קבועה כזו (כי שינוי ישפיע על כל הופעותיה בתוכנית).‘H’‘e’‘l’‘l’‘o’‘!’‘\0’ps pc

31 הקצאת זיכרון דינאמית - סיכום אפשר להקצות מקום בזיכרון בזמן הריצה. בפרט, אפשר ליצור מערך בגודל שתלוי בקלט (גודל שלא ידוע מראש). אפשר להקצות מקום בזיכרון בזמן הריצה. בפרט, אפשר ליצור מערך בגודל שתלוי בקלט (גודל שלא ידוע מראש). בספריה stdlib.h נמצאות הפקודות malloc, calloc, realloc, free. בספריה stdlib.h נמצאות הפקודות malloc, calloc, realloc, free. כשמקצים מקום בזיכרון מוחזרת הכתובת שלו, ונשמור אותה במצביע (בהתאם לסוג המשתנה שנירצה לשמור במקום הזה). אי-אפשר לתת שם למשתנה/מערך החדש, אבל אפשר לגשת אליהם דרך המצביע. כשמקצים מקום בזיכרון מוחזרת הכתובת שלו, ונשמור אותה במצביע (בהתאם לסוג המשתנה שנירצה לשמור במקום הזה). אי-אפשר לתת שם למשתנה/מערך החדש, אבל אפשר לגשת אליהם דרך המצביע. צריך לזכור לשחרר מה שהקצינו כשמסיימים להשתמש בזה. צריך לזכור לשחרר מה שהקצינו כשמסיימים להשתמש בזה. כתיבה לכתובת שנמצאת במצביע לא מאותחל תגרום לתעופה – צריך לזכור לאתחל אותו. כתיבה לכתובת שנמצאת במצביע לא מאותחל תגרום לתעופה – צריך לזכור לאתחל אותו.


Download ppt "מבוא כללי למדעי המחשב הקצאת זיכרון דינאמית www.cs.tau.ac.il/courses/cs4math/09b."

Similar presentations


Ads by Google