יום רביעי, 14 בדצמבר 2016

שפת C - הקצאת זיכרון דינאמי (יום רביעי)

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

נדגים מה הצורך בזיכרון דינאמי:

void main(){   
int n;               
scanf(%d,&n);
int A[n];         

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

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



- הקצאת זיכרון דינאמית היא האפשרות לייצר זיכרון (להקצות) במהלך ביצוע התוכנית.
- יש לעשות שימוש בספרייה  <stdlib.h>


אנחנו נשתמש בפקודות הבאות:

malloc - לבצע הקצאה חדשה
calloc  - לבצע הקצאה חדשה + לאפס אותה
realloc - להגדיל/להקטין זיכרון דינאמי
free     -  לשחרר זיכרון דינאמי



...........
כדאי לדעת: מצביע מסוג void הוא מצביע כללי שיכול להצביע על כל המשתנים. אבל תדרש לשם כך פעולת
המרה לפי סוג המשתנה.


void main(){            
int x = s1;                
void *p;                   
*(int*) p = 17;         
printf ("%d",x);       
...........


malloc

מקבלת מספר שלם (size)
מחפשת size בתים פנויים ברצף, מקצה אותם ומחזירה כתובת הבית הראשון.
במקרה של כישלון הפונקציה תחזיר NULL.

תבנית כללית:
void* malloc (int size);

דוגמה להקצאת 20 בתים ונתינת הכתובת של הבית הראשון למצביע מסוג int:
int *p;                          
p = (int *) malloc (20);




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


#include <stdio.h>
#include <stdlib.h>
 
void main(){
int n,*p,i,sum=0;
printf("Enter n:  ");
scanf("%d",&n);
p = (int*) malloc (n* sizeof(int));
if (p == NULL){
 printf("No enough memory");
 exit(0);
}
for(i=0;i<n;i++){
 printf("Enter number:  ");
 scanf("%d",&p[i]);
}
for(i=0;i<n;i++)
 sum += p[i];
printf("sum %d\n",sum);
 
}



calloc

 void* calloc (int cnt , int size);
cnt - כמות האיברים
size - כמות הבתים הדרושה לכל איבר

מחפשת מקום בגודל של cnt*size בתים פנויים ברצף, היא מקצה ומאפסת את אותם בתים. מחזירה את כתובת
הבית הראשון.
במקרה של כישלון הפונקציה תחזיר NULL.

p = (int*)calloc (n,sizeof(int));


free

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

תבנית כללית:
free (מצביע למערך דינאמי);

לדוגמה (p מצביע):
free (p);







*למידע נוסף*



פתרונות מהשיעור הקודם:

#include <stdio.h>
#include <math.h>
#define N 10
/*
int f1(char *s, char ch) {
 int c = 0;
 for( ; *s ; s++)
  if(ch == *s)
   c++;
 return c;
}
void f2(int *p) {
 int *q , tmp;
 for(q=p+N-1; p < q; p++ , q--) {
  tmp = *p;
  *p = *q;
  *q = tmp;
 }
}
 
void main() {
/* //Exe' No' 1
// char Str[80] , ch;;
// printf("Enter string :\n ");
// gets( Str );
// printf("Enter char: ");
// flushall();
// ch = getchar();
// printf("%d\n",f1(Str , ch) );
 
 //Exe' No' 2
// int A[N] = {10,20,30,40,50,60,70,80,90,100,110} , *p;
// f2( A );
// for(p=A; p <= A+N-1; p++)
//  printf("%d ",*p);
// putchar('\n');
}
 
 
 
//Exe' No' 3
 
void main() {
 int A[N] = {10,2,30,40,-50,60,70,-80,90,32} , *p , sum = 0,*p1 , *p2;
 double avg;
 for(p=A; p <= &A[N-1]; sum += *p++ );
 avg = (double)sum / N;
 printf("Sum: %d   Avg: %.2f\n",sum , avg);
 p1 = p2 = A;
 for(p=A+1; p <= A+N-1; p++){
  if(fabs(avg - *p) < fabs(avg - *p1) )  // closest   //  זה ערך מוחלט fabs 
   p1 = p;
  if(fabs(avg - *p) > fabs(avg - *p2) )  // far..
   p2 = p;
 }
 
 printf("%d  %d\n",*p1,*p2);
 
}
*/
 
 
int f4(char *s) {
 int c = 0;
 for( ; *s ; s++)
  if(*s>='0' && *s<='9' && ! (*(s+1)>='0' && *(s+1)<='9' ) )
   c++;
 return c;
}
 
 
int f5(char *s) {
 int c = 0;
 for( ; *s ; s++)
  if(*s>='0' && *s<='9' )
   c += *s - '0';
 return c;
}
 
int atoi(char *s) {
 int num = 0;
 while( *s ) {
  num *= 10;
  num += *s - '0';
  s++;
 }
 return num;
}
void main() {
 char Str[80] ;
 printf("Enter string :\n ");
 gets( Str );
// printf("%d\n",f2(Str) );
// printf("%d\n",f5(Str) );
 printf("%d\n",atoi(Str) );
}
 





שאלות:

מצבעים והקצאת זיכרון דינמית.
1)  כתוב תוכנית אשר מכילה מערך בגודל 10 מספרים שלמים , התוכנית
     קולטת איברי המערך, ומייצרת שני מערכים נוספים:
     אחד לשמירת כל המספרים הזוגיים של המערך שנקלט , והשני לשמירת כל  
     המספרים האי-זוגיים של המערך.
            ההקצאה תהיה בדיוק ככמות האיברים.
            לדוגמא:
                      עבור המערך: 1,2,3,4,5,6,7,8,9,10   
                      אז תוכן המערכים יהיה:
                     הראשון:  2,4,6,8,10                       
                     השני :   1,3,5,7,9                            


2)  כתוב תוכנית אשר קלטת שני מספרים שלמים n  ו  m.
     התוכנית מקצה מקום לשני מערכים , הראשון בגודל n והשני בגודל m.
     התוכנית קולטת איברי שני המערכים כך שאיברי כל מערך יהיו ממוינים
     בסדר עולה.
    התוכנית מקצה מערך שלישי בגודל m + n   , אליו יוכנסו איברי שני המערכים
    באופן ממוין.
        לדוגמא:    עבור  m = 3  ,  n = 4 
                         ושני המערכים :       1  3  15
                                                    1  2  4  8   
      אז המערך השלישי יהיה בגודל 7 עם האיברים:
                       1  1  2  3  4  8  15              


3)  כתוב תוכנית אשר קולטת מחרוזת.
      התוכנית מקצה מקום ל-4 מחרוזות:
  הראשונה :  לשמירת כל האותיות הקטנות.
  השנייה      :  לשמירת כל האותיות הגדולות.
  השלישית :  לשמירת כל הספרות.
  הרביעית  :  לשמירת כל שאר התווים.













בהצלחה!


אין תגובות:

הוסף רשומת תגובה