Presentation is loading. Please wait.

Presentation is loading. Please wait.

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

Similar presentations


Presentation on theme: "הקצאת זיכרון דינאמית מבוא כללי למדעי המחשב"— Presentation transcript:

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

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

3 עוד על פונקציות ומצביעים
למשל: int *address_of _the_higher_number(int *a, int*b) { if(*a > *b) return a; return b; }

4 עוד על פונקציות ומצביעים
למשל: int *address_of _the_higher_number(int *a, int*b) { if(*a > *b) return a; return b; } int main() { int *ptr, i=10, j=0; ptr = address_of _the_higher_number(&i, &j); return 0; מוחזרת כתובת המשתנה שמכיל את הערך הגדול יותר מבין השניים והשימוש ניראה כך למשל:

5 עוד על פונקציות ומצביעים
אמרנו שהערך שמוחזר מפונקציה יכול להיות מצביע: int *address_of _the_higher_number(int *a, int*b); אבל החזרת כתובת משתנה שהוגדר בתוך הפונקציה תגרום לשגיאה. כי המשתנים שמוגדרים בתוך הפונקציה נעלמים עם סיומה. למשל הפונקציה הבאה תגרום לשגיאה: int *give_pointer_to_zero() { int i=0; return &i; } i

6 גישה לתאי-מערך לפי הכתובת
אם הגדרנו למשל: int array[10]; int *array_ptr; array_ptr=array; אז אפשר לגשת לתאי-המערך גם לפי הכתובת שלהם, כמו משתנים אחרים. 3 הפעולות הבאות עושות אותו דבר (שמות 100 בתא מס' 5 במערך): array[5]=100; *(array+5)=100; *(array_ptr+5)=100; - המחשב יודע כמה בתים להתקדם כשאנחנו מבקשים להתקדם ב-5 תאים קדימה, כי הגדרנו שטיפוס הערכים הוא int והוא יודע כמה בתים כל int תופס (כאמור, ערכי המערך שמורים בזיכרון ברצף). (מצביע על התא הראשון במערך) גישה לתא שנמצא 5 תאים אחרי התא הראשון

7 גישה למערך לפי כתובת – דוגמא נוספת
נאמר שמוגדרים: int i,array[10]={0}; int *ptr; אז 3 הקטעים הבאים עושים בדיוק אותו דבר (מדפיסים את המערך): for (i=0; i<10; i++) printf(“%d ”, array[i]); printf(“%d ”, *(array+i)); for (ptr=array; ptr <= &array[9]; ptr++) printf(“%d ”, *ptr); 1) הדפסה על-ידי גישה רגילה לתאי המערך 2) הדפסה על-ידי גישה לכל תא לפי הכתובת שלו יחסית לתא הראשון 3) הדפסה ע"י קידום מצביע מכתובת התא הראשון עד כתובת התא האחרון

8 מערכים ופונקציות למשל הפונקציות שהזכרנו על מחרוזות (כמו strcmp, strlen) מוגדרות למעשה עבור מצביעים מסוג char *. באחריותנו להפעיל אותן באמת על מחרוזת (כלומר רצף תווים שמסתיים ב- '0\') ולא סתם על מצביע לתו או מערך של תווים (נקבל תוצאות שגויות אם אין את תו הסיום). כמו-כן, כזכור, אם פונקציה מוגדרת על מערך בגודל מסויים, ניתן להעביר אליה גם מערך בגודל אחר של אותו טיפוס (כי כאמור מה שמועבר זה רק כתובת ההתחלה). שוב, זה באחריותנו שתתבצע בפונקציה פעולה הגיונית ושהיא תדע מה גודל המערך ולא תחרוג ממנו.

9 "מצביע על כלום" לפעמים נירצה לסמן שמצביע לא מצביע לשום משתנה (למשל לפני שהתחלנו להשתמש בו). מקובל לעשות זאת ע"י זה שנכניס אליו את הכתובת 0 (שאיננה כתובת אפשרית של משתנה מטיפוס כתובת). למעשה, במקום לרשום 0 מקובל לרשום NULL. זהו קבוע שערכו 0, שמוגדר ע"י #define בספריה stdlib.h. למשל: #include<stdlib.h> int *ptr=NULL; לא לבלבל בין הכתובת NULL לבין תו סיום מחרוזת ‘\0’

10 דוגמא: חיפוש תו במחרוזת
#include<stdlib.h> char *my_strchr(char *str, char tav) { while((*str != ‘\0’) && (*str != tav)) str++; if (*str == tav) return str; return NULL } מקבלת מצביע לתחילת מחרוזת ותו מתקדמים עד שמצאנו את התו או הגענו לסוף המחרוזת אם מצאנו מוחזר מצביע להופעה הראשונה אם לא מצאנו מחזירים NULL

11 דוגמא: חיפוש תו במחרוזת
#include<stdlib.h> char *my_strchr(char *str, char tav) { while((*str != ‘\0’) && (*str != tav)) str++; if (*str == tav) return str; return NULL } מקבלת מצביע לתחילת מחרוזת ותו מתקדמים עד שמצאנו את התו או הגענו לסוף המחרוזת אם מצאנו מוחזר מצביע להופעה הראשונה אם לא מצאנו מחזירים NULL הדגמת אופן הקריאה לפונקציה הזו int main() { char word[]=“HELLO”, tav=‘L’, *place; place=my_strchr(word, tav); return 0; }

12 מערכים ופונקציות – נקודה לתשומת לב
אם ננסה להחזיר מפונקציה מערך שהגדרנו בתוכה או מצביע על מערך כזה, אז נקבל שגיאה. int * zero_array() { int array[100]={0}; return array; } זה מכיוון שמוחזרת כתובת של המערך, אבל כל מה שהוגדר בתוך הפונקציה נמחק כשהיא מסתיימת.

13 מצביעים ומערכים - סיכום
משתנה מערך הוא סוג של מצביע: הוא מכיל כתובת (של התא הראשון במערך), אבל אי-אפשר לשנות אותה. זו הסיבה שבהעברת מערך לפונקציה המערך המקורי מושפע. אפשר לגשת לתא במערך גם בעזרת חישוב כתובתו יחסית לכתובת התחלת המערך. למשל: *(array+5)=100;

14 נקודה לתשומת-לב: איתחול מה שמוצבע
ככלל, לפני שכותבים ערך לכתובת שנמצאת במצביע, צריך שהמצביע יכיל כתובת של משתנה כלשהו שהגדרנו (אחרת תיקרה תעופה). int *ptr; *ptr=10; בהתאם, בהגדרת מצביע לא ניתן לכתוב ערכים למקום שהוא מצביע עליו. למשל לא ניתן לרשום: int *my_array={1,2,3}; יכתוב לכתובת שנמצאת במצביע לפני שאיתחלנו אותו

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

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

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

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

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

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

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

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

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

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

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

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

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

28 מצביעים ומבנים - דוגמא פונקצית ההשוואה כשמועברים מצביעים:
int equal( struct point *p, struct point *q) { return ((p->x == q->x) && (p->y == q->y)); } (הגישה עם חץ היא לשדה של המבנה שמצביעים עליו) הקריאה לפונקציה ע"י equal(&P1,&P2) int equal(struct point p, struct point q) במקום: { return ( (p.x == q.x) && (p.y == q.y)); } (הגישה עם נקודה היא לשדה של מבנה) הקריאה לפונקציה ע"י equal(P1, P2)

29 מצביעים ומבנים – עוד דוגמא
נחשב את המרחק כשמועברים מצביעים ולא המבנים עצמם: double dist(struct point *p, struct point *q) { double d,dx,dy; dx = p->x - q->x; dy = p->y - q->y; d = dx*dx + dy*dy; return sqrt(d); } איך תיראה הקריאה ב-main? printf(“The distance is %g\n”, dist(&P1,&P2)(;

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

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

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

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

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

35 דוגמא: הקצאת מערך בגודל משתנה
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]); printf(“%d”, a[i]); return 0; } קולטים את הגודל הדרוש מקצים מקום עכשיו אפשר למשל לקלוט ערכים ולהדפיס אותם, כמו במערך רגיל (אבל שימו לב ש- a הוא מצביע ולא מערך, לכן ניתן למשל לשנות את ערכו כך שהוא יצביע אחר-כך למקום אחר)

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

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

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

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

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

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

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

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

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

45 החזרת זיכרון שהוקצה דינאמית - הדגמה
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; הפונקציה מקצה דינאמית מערך של מס' שלמים בגודל המבוקש, בודקת שההקצאה הצליחה, ומחזירה את כתובת המערך שהוקצה. אפשר להחזיר את כתובת המערך הזה, שלא משוחרר בסוף הפונקציה כי הוא הוקצה דינאמית, אבל מי שקרא לפונקציה צריך לדאוג לשחררו בסיום השימוש בו.

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

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

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

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


Download ppt "הקצאת זיכרון דינאמית מבוא כללי למדעי המחשב"

Similar presentations


Ads by Google