תרגול מס' 2  העברת פרמטרים לתוכניות ב-C  קלט ופלט ב-C  I/O redirection  זיכרון דינמי  מצביעים  מערכים  גישות לא חוקיות לזיכרון.

Slides:



Advertisements
Similar presentations
ממיבחניםC שאלות ++.
Advertisements

Files 1 יום חמישי 16 אפריל 2015 יום חמישי 16 אפריל 2015 יום חמישי 16 אפריל 2015 יום חמישי 16 אפריל 2015 יום חמישי 16 אפריל 2015 יום חמישי 16 אפריל 2015.
מבוא למדעי המחשב לתעשייה וניהול
קורס תכנות שיעור שנים-עשר: ניהול זיכרון 1. הקצאת זיכרון דינאמית עד עכשיו עשינו "הקצאה סטטית" הגדרנו את משתני התוכנית כבר כשכתבנו אותה הקומפיילר הקצה עבורם.
1 מבוא למדעי המחשב הקצאה דינאמית. 2 הקצאת זיכרון דינאמית  כאשר אנו משתמשים במערכים, אנו מקצים אוטומטית את הזיכרון המקסימלי שנצטרך.  בפועל, אנו משתמשים.
תכנות מונחה עצמים Object Oriented Programming (OOP) אתגר מחזור ב'
רקורסיות נושאי השיעור פתרון משוואות רקורסיביות שיטת ההצבה
1 מבוא למדעי המחשב משתנים. 2  סוגי משתנים בשפת C  ההבדלים בין סוגי המשתנים השונים.
תרגול 5 רקורסיות. רקורסיה קריאה של פונקציה לעצמה –באופן ישיר או באופן עקיף היתרון : תכנות של דברים מסובכים נעשה ברור ונוח יותר, מכיוון שזו למעשה צורת.
שאלות חזרה לבחינה. שאלה דיסקים אופטיים מסוג WORM (write-once-read-many) משמשים חברות לצורך איחסון כמויות גדולות של מידע באופן קבוע ומבלי שניתן לשנותו.
מבוא לשפת C חידות ונקודות חשובות נכתב על-ידי יורי פקלני. © כל הזכויות שמורות לטכניון – מכון טכנולוגי לישראל.
מבוא למדעי המחשב תרגול 8 - מחרוזות שעת קבלה : יום שני 11:00-12:00 דוא " ל :
תרגול 2 העברת פרמטרים לתוכניות ב -C קלט ופלט ב -C I/O redirection זיכרון דינמי מצביעים מערכים גישות לא חוקיות לזיכרון.
תוכנה 1 - חזרה שולי לב יהודי 2 Arrays and Strings מערך - אוסף משתנים בעלי שם משותף. הפנייה לכל איבר נעשית ע ” י אינדקס. ב -C מערך מוגדר.
מבוא למדעי המחשב © אריק פרידמן 1 מצביעים כמערכים דוגמה.
תרגול חזרה. מבנה האובייקט תאר את מבנה האובייקט כולל מבנה טבלאות הפונקציות הוירטואליות עבור התכנית הבאה struct A { int x; virtual void a() {}; }; struct.
חלון הפקודות מיועד לבצע פעולה אחת בכל פעם. כיצד אפשר לבצע רשימת פקודות או אפליקציות מורכבות ?
1 מבוא למדעי המחשב מבנה של תכנית. 2 מבנה של תכנית – חלוקה לקבצים  תכנית בשפת C הינה אוסף של הגדרות של:  משתנים (חיצוניים)  פונקציות  ניתן לפרוש תכנית.
תכנות תרגול 6 שבוע : תרגיל שורש של מספר מחושב לפי הסדרה הבאה : root 0 = 1 root n = root n-1 + a / root n-1 2 כאשר האיבר ה n של הסדרה הוא קירוב.
מבוא למדעי המחשב מחרוזות, מצביעים וכתובות
11 Introduction to Programming in C - Fall 2010 – Erez Sharvit, Amir Menczel 1 Introduction to Programming in C תרגול
תכנות תרגול 6 שבוע : הגדרת פונקציות return-value-type function-name(parameter1, parameter2, …) הגדרת סוג הערכים שהפונקציה מחזירה שם הפונקציהרשימת.
תכנות – שיעור 7. חזרה -מערכים נגדיר בעזרתו קבוצת משתנים כאשר יהיה לנו מספר רב של משתנים זהים נגדיר בעזרתו קבוצת משתנים כאשר יהיה לנו מספר רב של משתנים.
תכנות תרגול 10 שבוע : הקשר בין מערכים למצביעים נרצה לעמוד על הקשר בין מערך למצביע מאחר ומערכים הם הכללה של משתנים הרי שברור שלמערך ולכל אחד מאיבריו.
תהליכים  מהו תהליך ?  מבני הנתונים לניהול תהליכים.  החלפת הקשר.  ניהול תהליכים ע " י מערכת ההפעלה.
מבוא כללי למדעי המחשב תרגול 3. לולאות while לולאות while while (condition) { loop body } במקרה של קיום התנאי מתבצע גוף הלולאה ברגע שהתנאי לא מתקיים נצא.
תרגול 2 העברת פרמטרים לתוכניות ב -C קלט ופלט ב -C I/O redirection זיכרון דינמי מצביעים מערכים גישות לא חוקיות לזיכרון.
קורס תכנות – סימסטר ב ' תשס " ח שיעור שישי: מערכים
תרגול 10: הכרות עם ++C ++C כ- C משופר
1 מבוא למדעי המחשב ארגומנטים לתוכנית בזמן ריצה קבצים הקדם מעבד Preprocessor טיפוסים סדורים Enumerated Types Typedef.
תכנות תרגול 5 שבוע : הגדרת פונקציות return-value-type function-name(parameter1, parameter2, …) הגדרת סוג הערכים שהפונקציה מחזירה שם הפונקציהרשימת.
מערכים עד היום כדי לייצג 20 סטודנטים נאלצנו להגדיר עד היום כדי לייצג 20 סטודנטים נאלצנו להגדיר int grade1, grade2, …, grade20; int grade1, grade2, …, grade20;
עקרון ההכלה וההדחה.
תכנות מונחה עצמים Object Oriented Programming (OOP) אתגר מחזור ב' Templates תבניות.
מבוא למדעי המחשב תרגול 3 שעת קבלה : יום שני 11:00-12:00 דוא " ל :
תוכנה 1 - תרגול שיעור 10 Pointers (2) שולי לב יהודי
מבוא כללי למדעי המחשב הקצאת זיכרון דינאמית
מתמטיקה בדידה תרגול 2.
1 מבוא למדעי המחשב סיבוכיות. 2 סיבוכיות - מוטיבציה סידרת פיבונאצ'י: long fibonacci (int n) { if (n == 1 || n == 2) return 1; else return (fibonacci(n-1)
מבוא למדעי המחשב תרגול 12 – הקצאת זיכרון דינאמית שעת קבלה : יום שני 11:00-12:00 דוא " ל :
11 Introduction to Programming in C - Fall 2010 – Erez Sharvit, Amir Menczel 1 Introduction to Programming in C תרגול
תכנות תרגול 8 שבוע : מערכים עד היום התוכניות שלנו לא ידעו לשמור כמות גדולה של מידע ללא הגדרת כמות גדולה של משתנים. עד היום התוכניות שלנו לא.
Methods public class Demonstrate { public static void main (String argv[]) { public static void main (String argv[]) { int script = 6, acting = 9, directing.
תכנות מכוון עצמים ושפת ++C וויסאם חלילי. TODAY TOPICS: 1. Function Overloading & Default Parameters 2. Arguments By Reference 3. Multiple #include’s 4.
מבנים קרן כליף. ביחידה זו נלמד :  מהו מבנה (struct)  איתחול מבנה  השמת מבנים  השוואת מבנים  העברת מבנה לפונקציה  מבנה בתוך מבנה  מערך של מבנים.
שיתוף PDT בין חוטים PDT Thread A Process Descriptor File Object 1 File Object 2 File 1 File 2 pthread_create Thread B Process Descriptor ה PDT משותף לכל.
עקרונות תכנות מונחה עצמים תרגול 11: OOP in C++. Outline  Where do the objects live ?  Inheritance  Slicing  Overriding vs Shadowing.
מחרוזות – הטיפוס String
Computer Architecture and Assembly Language
מבוא למדעי המחשב סיבוכיות.
מערכים ומצביעים הקצאה דינאמית של מערכים דו-מימדיים
מבוא למדעי המחשב – סמסטר א' תשע"ב
מצביעים קרן כליף.
קורס תכנות – סמסטר ב' תשס"ח
הקצאות דינאמיות קרן כליף.
שיעור שישי: מחרוזות, מצביעים
Introduction to Programming in C
מצביעים קרן כליף.
מבוא כללי למדעי המחשב פונקציות
הקצאת זיכרון דינאמית מבוא כללי למדעי המחשב
מבוא כללי למדעי המחשב תרגול 6
סוגי משתנים קרן כליף.
מחרוזות קרן כליף.
מערכים של מצביעים הקצאה דינאמית
Programming in C תרגול Introduction to C - Fall Amir Menczel.
תוכנה 1 תרגול 13 – סיכום.
מבוא למדעי המחשב מצביעים.
תירגול 8:מצביעים והקצאה דינאמית
Engineering Programming A
Computer Architecture and Assembly Language
Presentation transcript:

תרגול מס' 2  העברת פרמטרים לתוכניות ב-C  קלט ופלט ב-C  I/O redirection  זיכרון דינמי  מצביעים  מערכים  גישות לא חוקיות לזיכרון

Cהעברת פרמטרים לתוכניות ב-  כאשר main נקראת מועברים אליה שני פרמטרים: argc - מספר הארגומנטים בשורת הפקודה (כולל הפקודה עצמה) argc - מספר הארגומנטים בשורת הפקודה (כולל הפקודה עצמה) argv - מצביע למערך של מחרוזות אשר מכילות את הארגומנטים בשורת הפקודה argv - מצביע למערך של מחרוזות אשר מכילות את הארגומנטים בשורת הפקודה  נכתוב תוכנית בשם echo אשר תדפיס את הארגומנטים בשורת הפקודה שלה בשורה אחת עם רווח ביניהם  לדוגמא: > echo hello, world hello, world >  הוחלט ש argv[0] הוא שם התוכנית הנקראת. לכן argc הוא לפחות 1. אם argc הוא 1 אין ארגומנטים אחרי שם התוכנית. בדוגמא לעיל argc הוא 3 ו argv[0], argv[1] ו argv[2] הם "echo", "hello," ו "world" בהתאמה

Cהעברת פרמטרים לתוכניות ב-  הארגומט האופציונלי הראשון יהיה ב argv[1] והאחרון יהיה ב argv[argc-1]. בנוסף הסטנדרט קובע ש argv[argc] יהיה מחרוזת ריקה.  התוכנית echo: #include #include /* echo command-line arguments */ int main (int argc, char* argv[]) { int i; for (i = 1; i < argc; i++) printf ("%s ", argv[i]); printf ("\n"); return 0; } echo\0 hello,\0 World\0 argv argc=3 NULL

Cחזרה על קלט פלט ב-  פונקציות קלט/פלט נמצאות בספריה stdio.h, כלומר צריך לבצע #include #include ניתן בעזרתן לבצע קלט מהמקלדת, פלט למסך וקלט/פלט לקבצים  כדי להשתמש בקובץ יש צורך: 1.לפתוח את הקובץ לקריאה או לכתיבה 2.לקרוא/לכתוב אל הקובץ 3.לסגור את הקובץ  כל הפעולות על קבצים נעשות ע"י משתנה מטיפוס מצביע לFILE- (הטיפוס FILE מוגדר ב stdio.h)  לדוגמא: FILE* fd;/* file descriptor */

פתיחה של קובץ  פתיחת קובץ נעשית ע"י הפונק' fopen: FILE* fopen(const char* filename,const char* mode);  filename - שם הקובץ לפתיחה  mode - המצב בו יש לפתוח את הקובץ: "r" - פתח לקריאה בלבד "w" - פתח לכתיבה בלבד "a" - פתח לכתיבה בסוף הקובץ  הפונקציה מחזירה מצביע לערוץ הפתוח אם הצליחה לפותחו ואחרת מחזירה NULL  לדוגמא: FILE* fd; fd = fopen("hello.c", "r");  אם פותחים קובץ לכתיבה והקובץ לא קיים עדיין, אזי הוא נוצר בעקבות הקריאה לפונקציה fopen. פתיחה לקריאה של קובץ שאינו קיים גורמת לשגיאה

סגירה של קובץ  סגירת קובץ שנפתח ע"י fopen נעשית ע"י הפונק' fclose: int fclose (FILE* fd);  fclose מחזירה 0 אם הצליחה ו EOF אם קרתה שגיאה.  לדוגמא: FILE* fd; fd = fopen("hello.c", "r"); /* Perform input/output on file */ if (fclose(fd) == EOF) printf ("Could not close file!\n"); else printf ("File closed successfuly.\n");  בסיום ריצת תוכנית מערכת ההפעלה דואגת לסגור את כל הקבצים קיימת מגבלה על מספר הקבצים הפתוחים בו-זמנית עבור תוכנית מסויימת קיימת מגבלה על מספר הקבצים הפתוחים בו-זמנית עבור תוכנית מסויימת

ערוצים סטנדרטיים   בC- יש התייחסות אחידה לכל סוגי הקלט והפלט. גם הקלט מהמקלדת והפלט מהמסך נעשים ע"י ערוצים ומצביעים ל FILE   כאשר תוכנית C מתחילה לרוץ מערכת ההפעלה פותחת עבורה בצורה אוטומטית שלושה ערוצים סטנדרטיים: 1.stdin 1.stdin נפתח לקריאה (בד"כ מהמקלדת) 2.stdout 2.stdout נפתח לכתיבה (בד"כ אל המסך) 3.stderr 3.stderr נפתח לכתיבה (בד"כ אל המסך)   stdin, stdout ו stderr הם למעשה שמות משתנים כאשר כולם מטיפוס מצביעים ל FILE.   לדוגמא הפקודה: fclose (stdin); תגרום לכך שלא ניתן יותר לקרוא קלט מהמקלדת הערה: אם תוכנית קוראת נתונים מהמקלדת ורוצים להקליד תו EOF יש להקיש Ctrl-d

ערוצים סטנדרטיים  דוגמא: התוכנית copy  במידה וקבלה שני פרמטרים, מעתיקה את הקובץ אשר שמו הנו הפרמטר הראשון, לקובץ אשר שמו הנו הפרמטר השני  במידה וקיבלה פרמטר יחיד, מעתיקה את הקובץ אשר שמו הנו פרמטר זה לערוץ הפלט הסטנדרטי  במידה ולא התקבלו שמות קבצים כלל, התוכנית מעתיקה את מה שמתקבל בערוץ הקלט הסטנדרטי לערוץ הפלט הסטנדרטי

ערוצים סטנדרטיים #include #define CHUNK_LEN 100 void error(char *msg) { fprintf(stderr, "Error: %s\n", msg); exit(1); } int main(int argc, char *argv[]) { FILE *in = stdin; FILE *out = stdout; char buf[CHUNK_LEN]; if (argc>3) error("Bad Number of parameters"); if (argc>1){ in = fopen(argv[1], "r"); if (in==NULL) error("Can't open input file"); } if (argc>2) { out = fopen(argv[2], "w"); if (out==NULL) error("Can't open output file"); } while(fgets(buf, CHUNK_LEN, in) != NULL) fputs(buf, out); fclose(in); fclose(out); return 0; }

ערוצים סטנדרטיים char* fgets (char* line, int maxline, FILE *fp)   קוראת שורה, כולל '\n’, מקובץ fp לתוך line. לכל היותר maxline-1 תווים יקראו   מחזירה NULL בסוף קובץ וב-error, אחרת מחזירה line int fputs(char* line, FILE *fp)   כותבת את line לקובץ   מחזירה EOF אם יש שגיאה, אפס אחרת char* gets(char* s)   בדומה ל-fgets רק מהקלט הסטנדרטי   מחליף '\n’ ב-‘\0’ int puts(char* s)   בדומה ל-fpus רק אל הפלט הסטנדרטי   מוסיף '\n’

I/O redirection  בכל תוכנית שרצה תחת Unix ערוץ הקלט הסטנדרטי מחובר אל המקלדת, וערוצי הפלט והודעות השגיאה הסטנדרטיים מחוברים אל המסך כברירת מחדל  ב CShell ניתן לכוון מחדש הן את ערוץ הקלט הסטנדרטי והן את ערוצי הפלט והשגיאות הסטנדרטיים אל ומאת קבצים כלשהם. הכיוון מחדש נקרא redirection stdout stdin stderr Program

Input redirection   תגרום ל- program לקבל את הקלט הסטנדרטי שלה מהקובץ filename   לדוגמא: % copy < filename   תגרום ל- copy הנתונה לקחת את הקלט מהקובץ filename   ההפעלה בצורה הנ"ל שקולה (מבחינת התוצאה) עבור התוכנית copy להפעלה: % copy filename   אך מה ההבדל מבחינת התוכנית ?

Output redirection > >   תגרום ל- program לכתוב את הפלט הסטנדרטי שלה לקובץ filename. אם קיים כבר קובץ בשם filename לפני ביצוע הפקודה, הפקודה לא תבוצע % cat myfile line 1 line 2 % cat myfile > out % cat out line 1 line 2 %

Output redirection >> >>   מכוונת את הפלט הסטנדרטי של program לקובץ filename אך משרשרת אותו לסוף הקובץ. אם לא קיים קובץ בשם filename לפני ביצוע הפקודה, הפקודה לא תבוצע % cat yourfile line 3 % cat yourfile >> out % cat out line 1 line 2 line 3 %

Output redirection   ראינו ששתי פקודות כיוון הפלט הקודמות עלולות להיכשל. הראשונה (<) אם הקובץ קיים, והשנייה (<<) אם הקובץ אינו קיים   ניתן להבטיח שהפקודות הנ"ל יצליחו בכל מקרה ע"י הוספת ! לפקודות הכיוון: >! >!   הורסת את הקובץ filename וכותבת עליו את הפלט הסטנדרטי של program בכל מקרה   אם הקובץ filename אינו קיים, אזי מתקבלת אותה התנהגות כשל < >>! > >>!   יוצרת את הקובץ filename אם הוא לא קיים.   אם הקובץ filename קיים, אזי מתקבלת אותה התנהגות כשל <<

Input and output redirection  ניתן להפנות גם את ערוץ הקלט הסטנדרטי של התוכנית וגם את ערוץ הפלט  לדוגמא הפקודות: % cat out % cat ! out גורמת להעתקת קובץ in לקובץ out (מה ההבדל? ) % cat > out % cat >! out גורמת להוספת קובץ in לסוף קובץ out (מה ההבדל?)

Multiple redirection   בנוסף להפנית קלט/פלט סטנדרטיים ניתן להפנות גם את ערוץ השגיאות הסטנדרטי מהמסך אל קבצים >& >&   מפנה הן את הפלט הסטנדרטי והן את ערוץ השגיאות הסטנדרטי לקובץ file % gcc try_input.c -o try_input > out_err try_input.c: In function `main': try_input.c:4: parse error before `printf' *** Error code 1 % more out_err % gcc try_input.c -o try_input >& out_err % more out_err try_input.c: In function `main': try_input.c:4: parse error before `printf' *** Error code 1   הדבר יכול להיות שימושי כאשר נרצה לראות את השגיאות הראשונות שהקומפילר מוציא

Multiple redirection >&! >&!  זהה לפקודה הקודמת אבל עובדת גם אם הקובץ file קיים >>& >>&  פועלת כמו במקרה הקודם, אבל כאן המידע החדש משורשר אל סוף הקובץ. ניתן גם להיעזר ב- ! אם רוצים להבטיח כי הפקודה תתבצע >>&! >>&!  הפקודה > >& ( > ) >&  גורמת לפלט הסטנדרטי להכתב אל הקובץ f1 ואילו להודעות השגיאה להכתב אל קובץ f2

Multiple redirection #include #include int main() { fprintf(stderr, “This is error\n”); printf(“This is stdout\n”); return 0; } > gcc prog.c –o prog > prog This is error This is stdout > prog > out.txt This is error > cat out.txt This is stdout > prog >& errout.txt > cat errout.txt This is error This is stdout > (prog > out) >& err > cat out This is stdout > cat err This is error

Cניהול זיכרון של תוכניות ב-  משתנים ב C נבדלים האחד מהשני בשני אופנים: טיפוס – למשל int, char ו double. שונים האחד מהשני מבחינת הערכים האפשריים עבור כל אחד, אילו פעולות ניתן לבצע על כל אחד מהם, וכמות הזיכרון שנדרשת עבור כל אחד מהם טיפוס – למשל int, char ו double. שונים האחד מהשני מבחינת הערכים האפשריים עבור כל אחד, אילו פעולות ניתן לבצע על כל אחד מהם, וכמות הזיכרון שנדרשת עבור כל אחד מהם אופן ההקצאה אופן ההקצאה  ניתן להקצות משתנים ב 4 אופנים: משתנים גלובלים משתנים גלובלים משתנים לוקאליים משתנים לוקאליים משתנים סטאטיים משתנים סטאטיים משתנים דינמיים משתנים דינמיים

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

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

מבנה הזיכרון  תוכנית המחשב רואה את הזיכרון כמערך גדול, של בתים (bytes) לכל בית יש כתובת ייחודית לו לכל בית יש כתובת ייחודית לו התוכנית יכולה להיעזר בבית אחד או יותר בכדי לשמור משתנים התוכנית יכולה להיעזר בבית אחד או יותר בכדי לשמור משתנים שמות משתנים נדרש בית אחד עבור ערך מסוג char. נדרשים 4 בתים עבור ערך מסוג int. c i ערךכתובת ?( זבל ) 0x200 'a'0x201 ? 0x x x x x206 ? 0x207 ……

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

מצביעים  משתנה מסוג מצביע משתנה שערכו הוא כתובת בזיכרון שבתוכה נמצא נתון כלשהוא * משתנה שערכו הוא כתובת בזיכרון שבתוכה נמצא נתון כלשהוא * המשתנה מיועד להצביע על מקום בזיכרון המכיל משתנה מטפוס המשתנה מיועד להצביע על מקום בזיכרון המכיל משתנה מטפוס int *ptr; ptr הוא משתנה אשר מיועד להצביע על מקום בזיכרון מטפוס int  כתובות נניח שהגדרנו משתנה ע"י int x; הביטוי:&x הוא הכתובת בזיכרון בה שמור תוכנו של x למשל, אם x הוא שלוש ומאוחסן בכתובת 2000 אזי ערכו של הביטוי &x הוא 2000

מצביעים  שימוש במשתנה מסוג מצביע גישה למשתנה בעזרת מצביע לכתובתו   הפקודה האחרונה שקולה ל: x=5.8.   שימו לב כי מצביע הוא משתנה בעצמו ולכן גם הוא נשמר בזיכרון. float x; float* ptr; ptr = &x; *ptr=5.8;

מצביעים ומוצבעים   הגדרת מצביע אינה גורמת ליצירת המקום אשר אליו הוא יצביע int *pi;   pi אינו מצביע למקום בזכרון המכיל integer אלא רק יכול להצביע למקומות בזכרון המכילים int *pi = 0 ;   הצבת 0 למקום אליו מצביע pi עלולה לגרום להעפת התוכנית כיוון שלא ידוע להיכן בזכרון pi מצביע וגישה למקום אליו הוא "מצביע" עלולה להיות גישה לא חוקית לזכרון   לפני גישה למקום בזכרון המוצבע ע"י מצביע יש לוודא כי המצביע מצביע לכתובת חוקית. יש לאתחל מצביעים כך שיכילו את הערך NULL לפני שמוכנסת אליהם כתובת חוקית, בצורה זאת ניתן לבדוק האם הם אינם מצביעים לכתובת חוקית int j ; int *pi ; pi = & j ; *pi = 0;

מצביעים ומערכים  יצירת מערך עם number איברים כאשר ערכי האינדקסים נעים בין 0 ל number-1 [ ] [ ] int x[3];  גישה למקום במערך (חד-ממדי) ע"י: [ ] x[2];  "שם המערך" הנו מצביע אשר לא ניתן לשנות את המקום אליו הוא מצביע. לכן הביטוי x ללא אינדקסים מהווה מצביע אל המקום הראשון במערך! כלומר, *x=3 שקול ל x[0]=3   הגדרת מערך בגודלnumber גוררת הקצאת number אברים מהטפוס המתאים, בעוד שהגדרת מצביע אינה גורמת להקצאת האיבר המוצבע  ניתן להצביע למערך (או איבר במערך) גם ע"י מצביע int *p, *q ; p = x ; /* p points to x[0] */ q = x+2 ; /* q points to x[2] */ p = q-1; /* p points to x[1] */

מצביעים למצביעים  מצביע הנו משתנה, ולכן יש לו כתובת. ניתן להציב את כתובתו במשתנה מטיפוס מצביע למצביע int a, b ; /* a and b are integers */ int *pi = &a ; /* pi is a pointer to integer that points to a */ that points to a */ int** ppi = π /* ppi is a pointer to pointer to integer. It points to pi */ to integer. It points to pi */ pi = &b ; /* pi points to b */ *pi = 5 ; /* b is set to 5 */ *ppi = &a ; /* pi is set to &a, pi points to a now */ *pi = 6 ; /* a is set to 6 */ *(*ppi) = 7; /* a is set to 7 */  (נתעלם בדוגמא ממספר הבתים שנדרשים לכל משתנה( משתנהערךכתובת ppi0x2020x200 'a'0x201 pi0x2050x x203 0x204 a 7 0x205 0x206 b50x207 ……

voidמצביע ל-  ניתן להגדיר מצביע מטפוס void*. במצביע מטפוס זה ניתן לשמור כתובת של טפוס כלשהו  כיוון שלקומפיילר לא ידוע מהו הטפוס המוצבע ע"י על ידי מצביע מסוג void*, בכדי לקבל את הערך המוצבע יש צורך ב cast שימיר את המצביע למצביע לטיפוס ששונה מ void:  מצביע ל void הנו שמושי עבור פונקציות נהול הזיכרון הדינמי אשר מסוגלות להקצות שטח זכרון עבור טפוס כלשהו. שמושים נוספים למצביע מסוג זה נראה בהמשך. void *ptr; int i; double d ; ….. if ( …) ptr = &d ; else ptr = &i; int *pi; int j; pi = (int*) ptr ; j = *((int *) ptr);

מצביעים והקצאות זיכרון דינמיות void* malloc (unsigned nbytes)  אם ההקצאה הצליחה מוחזר מצביע לקטע בזיכרון, אחרת מוחזר הערך NULL  כיוון שהזכרון המוקצה יכול לשמש לשמירת ערכים מטיפוס כלשהו, הטפוס המוחזר ע"י malloc הנו void*  ההגדרות של malloc ו NULL נמצאים ב stdlib.h. לכן, כדי להשתמש בהם יש לבצע: לדוגמא: int *ptr; ptr=(int*)malloc(4); /* allocate 4 bytes */ if (ptr==NULL) /* check if allocated */ error();  כעת ptr מצביע למקום בזיכרון שבו ארבעה בתים פנויים (אם ההקצאה הצליחה)  כיוון ש ptr הנו מטפוס int* ו malloc מחזירה ערך מטפוס void*, יש לבצע casting #include

מצביעים והקצאות זיכרון דינמיות  כדי למנוע את הצורך בשינוי תוכנית בגלל גודל שונה של טיפוסים, במהדרים שונים, ניתן להשתמש באופרטור sizeof sizeof( )  מחזיר את מספר הבתים של הטיפוס במערכת הנוכחית ptr=(int*)malloc(sizeof(int));*ptr=3; כעת ניתן להשתמש ב *ptr כמשתנה מסוג int (אם ההקצאה הצליחה) מה הטעות במיקרה זה? ptr=(int*)malloc(sizeof(int *));

מצביעים והקצאות זיכרון דינמיות free( )  משחרר את בלוק הזיכרון שהוקצה ושמהמשתנה מצביע עליו. יש לשחרר כל בלוק זיכרון שהוקצה, לאחר סיום השימוש בו, כדי למנוע מצב של חוסר זיכרון. דוגמא: ptr=(int *)malloc(sizeof(int)); if (ptr==NULL) error(); /* use ptr */ free (ptr);

גישות לא חוקיות לזיכרון טעויות נפוצות

גישה לא חוקית לזיכרון  מצביע יכול להכיל כל כתובת שהיא זיכרון שלא הוקצה לשימוש זיכרון שלא הוקצה לשימוש זיכרון שמשמש לדברים אחרים זיכרון שמשמש לדברים אחרים  התוכנית עלולה לקרוס –/ Bus error Segmentation Fault  התוכנית עלולה לרוץ כרגיל אבל... ריצה מוצלחת על קלט אחד לא מבטיחה כלום על קלט אחר אבל... ריצה מוצלחת על קלט אחד לא מבטיחה כלום על קלט אחר  כל גישה (קריאה או כתיבה) דרך מצביע שאינו מצביע לכתובת חוקית עלולה לגרום לשגיאה

טעויות נפוצות  הקצאת מחרוזת קצרה מדיי לא לשכוח את ‘\0’ לא לשכוח את ‘\0’ strlen איננה סופרת את ‘\0’ כאשר היא מחזירה אורך של מחרוזת strlen איננה סופרת את ‘\0’ כאשר היא מחזירה אורך של מחרוזת  שימוש שגוי ב-sizeof האופרטור מקבל טיפוס של משתנה האופרטור מקבל טיפוס של משתנה ptr = (int*)malloc(sizeof(int *)); ptr = (int*)malloc(sizeof(int *)); ptr = (int*)malloc(sizeof(int)); ptr = (int*)malloc(sizeof(int));

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

טעויות נפוצות - המשך  שימוש במשתנים לוקליים של פונקציה מחוץ לפונקציה יצירת משתנה לוקלי בפונקציה, והחזרת הכתובת שלו לפונקציה הקוראת יצירת משתנה לוקלי בפונקציה, והחזרת הכתובת שלו לפונקציה הקוראת  ההבדל בין = ל- ==  if(ptr == NULL) printf(“Bad pointer!\n”);  if(ptr = NULL) printf(“Bad pointer!\n”);

דוגמא – חריגה מגבולות המערך #include #define TITLE ("\n\tMemory Corruption: How easy it is\n\n") #define BUF_SIZE (8) int main() { int i; char c[BUF_SIZE], buf[BUF_SIZE]; printf("Type string c[]\n"); gets(c); printf("%s\n",c); printf("Type string buf[]\n"); gets(buf); printf("%s\n",buf); for (i=4; i > -10 ; i--){ c[i] = 'a'; printf("i= %2d, buf = %s c= %s\n", i, buf, c); } return 0; }

\ \0 זבל זבל buf c aa a a a a a a