190 likes | 345 Vues
מבוא למדעי המחשב. הקצאת זיכרון דינאמית. הקצאת זיכרון דינאמית. כאשר אנו משתמשים במערכים, במיוחד במערכים דו-ממדיים, אנו מקצים אוטומטית את הזיכרון המקסימלי שנצטרך. בפועל, אנו משתמשים בהרבה פחות זיכרון. זהו אקט בזבזני מבחינת כמות הזיכרון הדרושה ביחס לזו הנצרכת בפועל.
E N D
מבוא למדעי המחשב הקצאת זיכרון דינאמית
הקצאת זיכרון דינאמית • כאשר אנו משתמשים במערכים, במיוחד במערכים דו-ממדיים, אנו מקצים אוטומטית את הזיכרון המקסימלי שנצטרך. • בפועל, אנו משתמשים בהרבה פחות זיכרון. • זהו אקט בזבזני מבחינת כמות הזיכרון הדרושה ביחס לזו הנצרכת בפועל. • הפתרון - הקצאת זיכרון דינאמית ע"י שימוש בפוינטרים.
הקצאת זיכרון דינאמית בזמן ריצה • שימוש בפוינטרים. • הגדרת פוינטר בראשית הפונקציה – תופס רק את מספר הבתים המוקצים למצביע. • קביעת גודל הזיכרון אליו מצביע הפוינטר בזמן ריצה – כאשר ידוע גודל הזיכרון הדרוש. • הקצאת זיכרון ← ע"י הפונקציה malloc. • שחרור הזיכרון ← ע"י הפונקציה free.
הפונקציה malloc • הגדרת הפונקציה: void *malloc (size_t size) • הפונקציה מוגדרת ב- <stdlib.h> • הפונקציה מקצה בלוק בגודל size בתים בזיכרון בזמן ריצת התכנית. אם הקצאת הזיכרון הצליחה הפונקציה מחזירה מצביע לתחילת הבלוק המוקצה. המצביע אשר הפונקציה מחזירה הוא מטיפוס void*, כלומר מצביע מטיפוס לא ידוע, לכן יש לבצע casting (המרה של המצביע לטיפוס הרצוי). • כאשר הקצאת הזיכרון לא מצליחה (אין מספיק זיכרון רציף פנוי בזמן הריצה) הפונקציה מחזירה NULL. לכן, לאחר כל הקצאה דינאמית יש לבדוק שהפונקציה החזירה ערך השונה מ-NULL.
הפונקציה free • הגדרת הפונקציה: void free (void *block) • הפונקציה מוגדרת ב- <stdlib.h> • הפונקציה משחררת את הבלוק המוקצה מן הזיכרון, כך שניתן יהיה להקצותו מחדש. • במידה ולא נפעיל את הפונקציה בסיום השימוש בבלוק, לא נוכל להשתמש בזיכרון שלא שוחרר במשך כל זמן ריצת התכנית. • הזיכרון המוקצה ישוחרר ע"י מערכת ההפעלה בסיום ביצוע התכנית.
תכנית דוגמא /* malloc.c - a program demonstrating memory allocation */ #include <stdio.h> #include <stdlib.h> int SetSize (void); int* CreateArray (int size); void PrintArray(int a[], int size); int main() { int i, len, *array; len=SetSize(); array=CreateArray(len); for (i=0; i< len; i++) array[i]=i; PrintArray(array, len); return 0; }
תכנית דוגמא void PrintArray(int a[], int size) { int i; for (i=0; i< size; i++) printf("%d ",a[i]); printf("\n"); return; }
תכנית דוגמא int SetSize (void) { int size; printf("Please enter array size\n"); if (scanf("%d",&size)!=1){ printf("Error reading array size\n"); exit (1); } if (size<1){ printf("Array size too small\n"); exit (1); } return size; }
תכנית דוגמא int* CreateArray (int size) { int *array; array=(int *) malloc(size*sizeof(int)); if (array==NULL){ printf("Error in memory allocation\n"); exit (1); } return array; }
j 0 1 0 1 row ן col … 0 1 i*col+j תכנית דוגמא (2) – חיבור מטריצות • המטרה: לשנות את התכנית שכתבנו עבור חיבור מטריצות כך שתעבוד עם הקצאה דינאמית. • מעבר ממערך דו-ממדי למערך חד ממדי:
חיבור מטריצות – ללא הקצאה דינאמית int main() { int a[SIZE][SIZE], b[SIZE][SIZE], c[SIZE][SIZE]; int row1, row2, col1, col2; ReadMatrix(a, &row1, &col1); ReadMatrix(b, &row2, &col2); if (add(a,row1,col1,b,row2,col2,c)==FALSE) { printf("Matrices cannot be added\n"); return 0; } else{ printf("The result matrix:\n"); PrintMatrix(c,row1,col1); } return 0; }
חיבור מטריצות – עם הקצאה דינאמית int main() { int*a, *b, *c; int row1, row2, col1, col2; ReadMatrix(&a, &row1, &col1); ReadMatrix(&b, &row2, &col2); if (add(a,row1,col1,b,row2,col2,&c)==FALSE) { printf("Matrices cannot be added\n"); return 0; } else{ printf("The result matrix:\n"); PrintMatrix(c,row1,col1); } return 0; }
/* read a matrix*/ void ReadMatrix (int a[SIZE][SIZE], int *row, int *col) { int i,j; printf("Please enter the number of rows and columns:\n"); if (scanf("%d%d",row,col)!=2){ printf("Input error"); exit (1); } CheckSize (*row); CheckSize (*col); printf("Please enter matrix [%d][%d]\n",*row,*col); for (i=0; i < *row; i++) { for (j=0; j < *col; j++) { if(scanf("%d", &(a[i][j]))!=1){ printf("Input error"); exit (1); } } } PrintMatrix(a, *row, *col); return; } חיבור מטריצות – ללא הקצאה דינאמית
void ReadMatrix (int **a, int *row, int *col) { int i,j,place; printf("Please enter the number of rows and columns:\n"); if (scanf("%d%d",row,col)!=2){ printf("Input error"); exit (1); } CheckSize (*row); CheckSize (*col); *a=CreateArray((*row) * (*col)); printf("Please enter matrix [%d][%d]\n",*row,*col); for (i=0; i < *row; i++) { for (j=0; j < *col; j++) { place=i*(*col)+j; if(scanf("%d", *a+place)!=1){ printf("Input error\n"); exit (1); } } } PrintMatrix(*a, *row, *col); return; } חיבור מטריצות – עם הקצאה דינאמית
חיבור מטריצות – ללא/עם הקצאה דינאמית /* Check a matrix dimension*/ void CheckSize (int size) { if (size<0){ printf(“Matrix dimensions should be positive\n"); exit (1); } return; }
חיבור מטריצות – ללא הקצאה דינאמית /* print a matrix */ void PrintMatrix (int a[SIZE][SIZE], int row, int col) { int i,j; printf("Printing matrix [%d][%d]\n", row, col); for (i=0; i < row; i++) { for (j=0; j < col; j++) { printf("%6d", a[i][j]); } printf("\n"); } }
חיבור מטריצות – עם הקצאה דינאמית /* print a matrix */ void PrintMatrix (int a[], int row, int col) { int i,j,place; printf("Printing matrix [%d][%d]\n", row, col); for (i=0; i < row; i++) { for (j=0; j < col; j++) { place=i*col+j; printf("%6d", a[place]); } printf("\n"); } }
חיבור מטריצות – ללא הקצאה דינאמית /* add two matrices */ int add (int a[SIZE][SIZE], int row1, int col1, int b[SIZE][SIZE], int row2, int col2, int c[SIZE][SIZE]) { int i,j; if ( (col1!=col2) || (row1!=row2) ) return FALSE; for (i=0; i < row1; i++) for (j=0; j < col2; j++) c[i][j]=a[i][j]+b[i][j]; return TRUE; }
חיבור מטריצות – עם הקצאה דינאמית /* add two matrices */ int add (int *a, int row1, int col1, int *b, int row2, int col2, int **c) { int i,j,place; if ( (col1!=col2) || (row1!=row2) ) return FALSE; *c=CreateArray((row1) * (col1)); for (i=0; i < row1; i++){ for (j=0; j < col1; j++){ place=i*col1+j; *(*c+place)=a[place]+b[place]; } } return TRUE; }