לוגו אתר Fresh          
 
 
  אפשרות תפריט  ראשי     אפשרות תפריט  צ'אט     אפשרות תפריט  מבזקים     אפשרות תפריט  צור קשר     חץ שמאלה ‎print ‎"Hello World!"; if‎ ‎not rules.‎know ‎then rules.‎read(); חץ ימינה  

לך אחורה   לובי הפורומים > מחשבים > תכנות ובניית אתרים
שמור לעצמך קישור לדף זה באתרי שמירת קישורים חברתיים
תגובה
 
כלי אשכול חפש באשכול זה



  #1  
ישן 20-10-2007, 10:56
  Dark Knight Dark Knight אינו מחובר  
 
חבר מתאריך: 30.07.05
הודעות: 949
שלח הודעה דרך ICQ אל Dark Knight

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

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

אבל מה הוא בעצם מערך?
כמו שאתה בוודאי יודע, מערך הוא גוש זיכרון [חשוב לשים לב שכל המערך יושב כגוש יחיד בזיכרון וכל התאים בו מסודרים בזיכרון כפי שהם מסודרים במערך].
מה שאתה (אולי) לא יודע, הוא שהמימוש של מערך ב-C הוא פשוט מצביע לתחילת המערך.
כשאתה כותב
קוד:
char str[MAX_LEN];

מה שקורה הוא שהמהדר מקצה MAX_LEN תאים של CHAR ברצף על המחסנית, ומגדיר את str להיות (char*).
ואכן לטיפוסי מצביע קיים אופרטור [num] - זה הוא אופרטור בשם "אינדקס" והוא אומר: מהכתובת הנוכחית בזיכרון, תתקדם num גדלים של הטיפוס של המצביע, ותקרא את הערך בנקודה.
זו אגב אחת הסיבות ששימוש במערך הוא מסוכן - אתה יכול לכתוב גם str[3000] וזה לא יתן שגיאת קומפילציה, ואולי אפילו לא שגיאת זמן-ריצה, אבל זה יתן לך לגשת לזיכרון שאין לך מושג מה רשום בו... יתכן שזה ישלח אותך לאיזור בזיכרון שבו רשומות הפקודות שלך, ואתה עלול לדרוס אותן...
לא רעיון טוב

אם מערך הוא בעצם מצביע, אז ניתן להשתמש במצביע כבמערך.
לדוגמא אתה רוצה לקלוט 5 מחרוזות ולהדפיס אותן, בבזבוז מינימאלי של זיכרון. איך תעשה זאת?
נגדיר מחרוזת עזר בגודל 255 שאליה נקלוט כל פעם מחרוזת, לאחר מכן נקצה את הגודל המתאים ונעתיק אותה:
(נניח לצורך פשטות שבתוכנית שלנו, הקצאות זיכרון דינאמיות לא נכשלות)
קוד PHP:
 #include <stdio.h>
#include <string.h>

#define MAX_LEN 256
#define STR_NUM 5

int main(void) {
     
charstrings[STR_NUM]; // פה נשמור את המחרוזות
     
char buffer[MAX_LEN]; // לכאן נקלוט את המחרוזות
     
int i 0;

     for (
0i<STR_NUM; ++i) {
           
printf("Please enter the string: \n"); // הדפסה של הוראה למשתמש
           
scanf("%s"buffer); // קריאה של הקלט לתוך מחרוזת העזר
           
strings[i] = (char*)malloc(strlen(buffer)*sizeof(char) +1); //+1 for the \0 in the end
           // הפקודה למעלה מקצה בדיוק את הזיכרון הדרוש למחרוזת שנקלטה
           
strcpy(bufferstrings[i]);
     }
     for (
0STR_NUM; ++i
           
printf("%d) %s\n"istrings[i]); // Print the strings
   
     // שחרור של משאבי המערכת שהקצאנו
     
for (0STR_NUM; ++ifree(strings[i]);
 
     return 
0;


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

אבל לא רק לצורך דיוק בשימוש במשאבי המערכת ניתן להשתמש בהקצאות זיכרון דינאמיות.
למעשה ניתן להשתמש בהקצאות זיכרון דינאמיות גם כדי לבקש זיכרון נוסף שלא קשור למערכים.
בוא נממש עכשיו שימוש מאד פשוט ברשימה המקושרת שדיברנו עליה קודם:

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

קוד PHP:
 /*
קודם כל, נגדיר את האוסף שנקרא חולייה בשביל הרשימה
*/
typedef struct node_tNode// שים לב שחולייה היא בעצם מצביע!
struct node_t {
     
int number// שים לב שהשימוש פה הוא לא כללי, אלא מסויים לבעיה שלנו
     
Node next// פה אין מה לחשוב, מצביע לחוליה הבאה
}

int main(void) {
     
int buffer 0// משתנה הקלט שלנו. אנחנו קולטים מספרים שלמים
     
Node first NULL// במשתנה הזה אנחנו נזכור את החולייה הראשונה
     
Node help NULL// נשתמש במצביע הזה כדי לעבור על הרשימה וליצור חוליות חדשות.

     
printf("Please Enter a number: \n");
     
scanf("%d", &buffer);
     while (
buffer >= 0) {
            
help = (Node)malloc(sizeof(struct node_t)); // יוצרים חולייה חדשה
            
help->number buffer// מכניסים את המספר לחלק המידע של החולייה
            
help->next first// מכניסים את החולייה החדשה לראש הרשימה
            
first help// ועכשיו תחילת הרשימה מצביעה על החולייה החדשה
            
printf("Please Enter a number: \n");
            
scanf("%d", &buffer);
     }
     
// We get here when the first negative number was read.
     // Now we print the list:
     
help first// מצביע העזר שלנו מסתכל עכשיו על תחילת הרשימה
     
while (help != NULL) { // הרשימה מסתיימת כאשר הגענו ל NULL
            
printf("%d\n"help->number); // Print the number
            
help help->next// תעבור לחולייה הבאה
     
}

     
// Release the allocated memory:
     
help first;
     while (
help != NULL) {
            
help first->next;
            
free(first);
            
first help;
     }
     return 
0;



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

כשהתוכנית שלנו מתחילה, גם FIRST וגם HELP מצביעים ל-NULL (שזה בעצם כלום):
תמונה שהועלתה על ידי גולש באתר ולכן אין אנו יכולים לדעת מה היא מכילה

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

את החולייה החדשה, אנו רוצים לשלב ברשימה שלנו (נניח יש כבר 3 מספרים ברשימה):
תמונה שהועלתה על ידי גולש באתר ולכן אין אנו יכולים לדעת מה היא מכילה
את החולייה החדשה, שמוחזקת כרגע ב-HELP אנו מקשרים לרשימה השלמה שלנו:
את next של החולייה החדשה מכוונים לתחילת הרשימה (חץ כחול) ואז את תחילת הרשימה (FIRST) מכוונים אל החולייה החדשה (חץ אדום).

בסוף התהליך, מתקבלת רשימה עם 4 חוליות:
תמונה שהועלתה על ידי גולש באתר ולכן אין אנו יכולים לדעת מה היא מכילה

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

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

תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
תגובה

כלי אשכול חפש באשכול זה
חפש באשכול זה:

חיפוש מתקדם
מצבי תצוגה דרג אשכול זה
דרג אשכול זה:

מזער את תיבת המידע אפשרויות משלוח הודעות
אתה לא יכול לפתוח אשכולות חדשים
אתה לא יכול להגיב לאשכולות
אתה לא יכול לצרף קבצים
אתה לא יכול לערוך את ההודעות שלך

קוד vB פעיל
קוד [IMG] פעיל
קוד HTML כבוי
מעבר לפורום



כל הזמנים המוצגים בדף זה הם לפי איזור זמן GMT +2. השעה כעת היא 18:08

הדף נוצר ב 0.12 שניות עם 11 שאילתות

הפורום מבוסס על vBulletin, גירסא 3.0.6
כל הזכויות לתוכנת הפורומים שמורות © 2024 - 2000 לחברת Jelsoft Enterprises.
כל הזכויות שמורות ל Fresh.co.il ©

צור קשר | תקנון האתר