יום שבת, 13 במאי 2017

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

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

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

להקצאת זיכרון עבור משתנה בודד נשתמש באופרטור new כאשר אחריו נרשום את סוג המשתנה.
לדוגמה:
#include <iostream>
using namespace std;
 
void main(){
 int *ptr = new int;
 *ptr = 5;
 cout<<*ptr<<"\n"// ידפיס 5
}

לשחרור זיכרון עבור משתנה בודד נשתמש באופרטור delete.
לדוגמה:
#include <iostream>
using namespace std;
 
void main(){
 int *ptr = new int;
 *ptr = 5;
 cout<<*ptr<<"\n";
 delete ptr;
}





להקצאת מערך בזיכרון הדינמי נשתמש ב [אורך_המערך]סוג new.
לשחרור מערך מהזיכרון הדינמי נשתמש ב []delete.
לדוגמה:
#include <iostream>
using namespace std;
void main(){
 int len;
 cout<<"Enter len: ";
 cin >> len;
 int *array = new int[len];
 for(int i = 0; i < len; i++){
  cout<<i+1<<".  Enter number: ";
  cin >> array[i];
 }
 cout<<array[0]<<"\n";
 delete[] array;
}






שימו לב: הקצאה דינאמית של אובייקט באמצעות new מפעילה את הפונקציה הבונה של אותה מחלקה! (אם יש כזו)
לדוגמה:
#include <iostream>
using namespace std;
class example{
 int a,b,c;
public:
 example(){
  cout<<"example's Constructor is working!\n";
  a=0; b=0; c=0;
 }
};
void main(){
 example *PC = new example//  הפונקציה הבונה מופעלת
 delete PC;
}



הדבר נכון גם בהקצאת מערך של אובייקטים. עבור כל אובייקט תופעל פונקציה בונה.
כמובן שבסוף צריך לשחרר את הזיכרון ע"י []delete(אשר מפעיל את "הפונקציה ההורסת" עבור כל איבר. עליה נלמד בהמשך.)
לדוגמה:
#include <iostream>
using namespace std;
class example{
 int a,b,c;
public:
 example(){
  cout<<"example's Constructor is working!\n";
  a=0; b=0; c=0;
 }
};
void main(){
 example *pe;
 pe = new example[4]; //  הפונקציה הבונה מופעלת 4 פעמים
 delete[] pe;
}





אגב בשפת ++C אפשר להשתמש בפקודות malloc ו free. כמו גם בכל הפקודות שהיו בשפת C.
הדבר אינו מומלץ משום שלא יופעלו הפונקציות הבונות של מחלקות שהוקצו. (וכן לא יופעלו בשחרור ה "פונקציות ההורסות". עליהן נלמד בהמשך.)
אם בכל זאת תעשו בהן שימוש, אסור לשלב יחד איתן את הפקודות new ו delete משפת ++C.






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





אז מה עם שינוי הקצאה? (realloc)
אין כזו פקודה ב ++C!
אם יהיה לנו צורך בשינוי הקצאה, נוכל לכתוב פונקציה משלנו.
לדוגמה:
#include <iostream>
using namespace std;
 
char* my_realloc(char *old_memoryint old_sizeint new_size){
    char *new_memory = new char[new_size];  //  מקצים מקום בגודל החדש
 for(int i=0; i < min(old_sizenew_size); i++){
  new_memory[i] = old_memory[i]; //  מעתיקים מהישן לחדש
 }
    delete[] old_memory;
    return new_memory;
}
 
void main(){
 char *pc = new char[4];
 pc = my_realloc(pc,4,6);  //  מגדילים את המערך מ4 ל6 איברים. אם היו פונקציות בונות הן היו מופעלות 6 פעמים
 pc[4]='h';
 cout <<pc[4]<<"\n";  // אם ההקצאה לא הייתה עובדת זו הייתה שגיאה .h ידפיס
 delete[] pc;
}

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



ראה גם: ויקיספר







שאלות:
 1. הגדר מחלקה אשר תייצג תיק של עובד.
 במחלקה יוגדרו המשתנים הבאים:
    -מספר זהות.
    -שכר לשעה.
    -מספר שעות עבודה רגילות.
    -מספר שעות נוספות.
 בנוסף תוגדר פונקציה בונה לאתחול המשתנים, פונקציה להצגת המשתנים,
 ופונקציה לחישוב משכורת העובד ע"פ הנוסחה הבאה:
 (שכר לשעה * שעות רגילות) + (שכר לשעה * שעות נוספות * 1.5).
 כתוב תוכנית ראשית אשר מקבלת מהמשתמש את מספר העובדים, מקצה מערך של מספר העובדים, מציגה את פרטיהם
 ומחשבת את המשכורת של כל העובדים.

2. הגדר מחלקה אשר מייצגת תלמיד מסוים.
 המחלקה תכיל 4 ציונים ושם התלמיד.
 בנוסף לפונקציה הבונה אשר תקלוט את שם התלמיד והציונים היא מכילה
 פונקציה לחישוב הממוצע. ופונקציה אשר מציגה את שם התלמיד ו4 הציונים לפי הסדר.
 בתוכנית הראשית יש לקלוט את מספר התלמידים, להגדיר מערך של אובייקטים מסוג "תלמיד" בגודל הנחוץ, להציג אותם
 ולהדפיס את השם והממוצע של התלמיד בעל הממוצע הגדול ביותר.








פתרונות:
1.
#include <iostream>
#include <string.h>
using namespace std;
 
class worker {
 char ID[12];
 int PPH;  // שכר לשעה
 double hours, overtime;
public:
 worker() {
  cout<<"Enter ID: ";
  cin>> ID;
  cout<<"Enter price per hour: ";
  cin>> PPH;
  cout<<"Enter hours, overtime:  ";
  cin>>hours>>overtime;
 }
 
 void show(){
  cout<<"\nID: "<<ID << "  PPH: "<<PPH<<"  Hours: "<<hours<<"  Overtime: "<<overtime<<"\n";
 }
 double salary(){
  return PPH*hours + PPH*overtime*1.5;
 }
};
void main() {
 int n;
 cout<<"Enter number of workers: ";
 cin>>n;
 worker *ArryW = new worker[n]; ///  יפעיל את הפונקציה הבונה עבור כל איבר
 for (int i=0; i<n; i++){
  ArryW[i].show();
  cout << "The salary: "<<ArryW[i].salary()<<"\n";
 }
 delete[] ArryW;
}






2.
#include <iostream>
using namespace std;
#include <string.h>
 
class Pupil{
 int score1, score2, score3, score4;
public:
 char name[15];
 Pupil(){
  cout <<"Enter name: ";
  cin>>name;
  cout<<"Enter score1: ";
  cin >>score1;
  cout <<"Enter score2 ";
  cin>>score2;
  cout<<"Enter score3: ";
  cin >>score3;
  cout<<"Enter score4: ";
  cin >>score4;
  cout<<"\n\n";
 }
 void show(){
  cout <<"Name: "<<name<<"\n";
  cout<<"Score1: "<<score1<<"\n";
  cout<<"Score2: "<<score2<<"\n";
  cout<<"Score3: "<<score3<<"\n";
  cout<<"Score4: "<<score4<<"\n\n";
 }
 
 double average (){
  return((score1+score2+score3+score4)/4.0);  // int אם נכתוב 4 ולא 4.0 אז התוצאה תהיה 
 }
};
 
void main(){
 int length, i;
 double best=0;
 char BestName[15];
 cout << "How many pupils are there: ";
 cin >>length;
 Pupil *pupilsArray = new Pupil[length];
 
 for(i=0; i<length; i++){
  pupilsArray[i].show();
  if(pupilsArray[i].average() >= best){
   best = pupilsArray[i].average();
   strcpy(BestName , pupilsArray[i].name);
  }
 }
 
 cout<<"\n\nBest pupil: "<<BestName<<"\n";
 cout<<"Average: "<<best<<"\n";
 delete[] pupilsArray;
}






בהצלחה!


אין תגובות:

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