PowerPoint Presentation

מסמכים קשורים
PowerPoint Presentation

PowerPoint Presentation

סדנת תכנות ב C/C++

Slide 1

Microsoft Word B

הגשה תוך שבוע בשעת התרגול

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

Slide 1

שאלהIgal : מערכים דו מימדיים רקורסיה:

מבוא למדעי המחשב - חובלים

מספר מחברת: עמוד 1 מתוך 11 ת"ז: תשע"א מועד ב סמסטר א' תאריך: 00:11 שעה: 0 שעות הבחינה: משך כל חומר עזר אסור בשימוש בחינה בקורס: מבוא למדעי ה

Microsoft Word - c_SimA_MoedB2005.doc

פתרון מוצע לבחינת מה"ט ב_שפת c מועד ב אביב תשע"ט, אפריל 2019 מחברת: גב' זהבה לביא, מכללת אורט רחובות שאלה מספר 1 מוגדרת מחרוזת המורכבת מהספרות 0 עד 9.

שאלהIgal : מערכים דו מימדיים רקורסיה:

PowerPoint Presentation

מספר זהות: סמסטר ב' מועד א' תאריך: 11102/4// שעה: 9:22 משך הבחינה: 3 שעות חומר עזר: אין מותר השימוש במחשבון פשוט בחינה בקורס: מבני נתונים מרצה: הדר בי

מבוא למדעי המחשב - חובלים

שאלהIgal : מערכים דו מימדיים רקורסיה:

Slide 1

PowerPoint Presentation

תרגול 1

מבוא למדעי המחשב

מבוא לתכנות ב- JAVA תרגול 11

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

אוניברסיטת חיפה החוג למדעי המחשב מרצה: שולי וינטנר מתרגלים: נעמה טוויטו, מחמוד שריף מבוא למדעי המחשב סמסטר א' תשע"ב בחינת סיום, מועד א', הנחי

Microsoft PowerPoint - lec2.ppt

Slide 1

PowerPoint Presentation

תכנות מונחה עצמים א' – תש"ע

PowerPoint Presentation

מבוא למדעי המחשב

מבוא למדעי המחשב

אוניברסיטת חיפה החוג למדעי המחשב מרצה: שולי וינטנר מתרגלים: נעמה טוויטו, מחמוד שריף מבוא למדעי המחשב סמסטר א' תשע"ב בחינת סיום, מועד א', הנחי

מבוא למדעי המחשב

תרגול 1

Slide 1

Slide 1

הגשה תוך שבוע בשעת התרגול

Slide 1

Microsoft PowerPoint - rec1.ppt

PowerPoint Presentation

Microsoft PowerPoint - rec3.ppt

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

אוניברסיטת חיפה החוג למדעי המחשב.5.6 מבוא למדעי המחשב סמסטר א' תשע"ז בחינה סופית מועד א', מרצה: שולי וינטנר מתרגלים: סמאח אידריס, ראמי עילבו

מבוא לתכנות ב- JAVA תרגול 7

Programming

Microsoft Word - דוגמאות ב

מבחן סוף סמסטר מועד ב 28/10/08 מרצה אחראית: דר שירלי הלוי גינסברג מתרגלים: גלעד קותיאל, גדי אלכסנדרוביץ הוראות: א. בטופס המבחן 6 עמודים (כולל דף זה) ו

PRESENTATION NAME

מבוא למדעי המחשב

Slide 1

מהוא לתכנות ב- JAVA מעבדה 3

מבחן סוף סמסטר מועד א 15/02/08 מרצה אחראית: דר שירלי הלוי גינסברג מתרגלים: גלעד קותיאל, דניאל גנקין הוראות: א. בטופס המבחן 7 עמודים ו 4 דפי נוסחאות. ב

שקופית 1

מצגת של PowerPoint

Microsoft PowerPoint - lec10.ppt

PowerPoint Presentation

מקביליות

יוםראשון, 02 ליולי 2014 סמסטר סוף מבחן )236703( עצמים מונחה תכנות - א' מועד 2014, אביב סמסטר קמחי יחיאל ד"ר מרצה: מסינג מיטל עבדאלקאדר, כרם גלעד, ערן

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

מבוא לאסמבלי

תרגול מס' 4: המתרגם שימוש במחלקות קיימות מחרוזות, קבצים, וקבלת קלט מהמשתמש

פייתון

PowerPoint Presentation

Microsoft Word - c_SimA_MoedA2006.doc

משימה תכנית המתרגמת קטעי טקסט לשפה אחרת הקלט: קובץ המכיל את קטעי הטקסט וכן את השפה אליה רוצים לתרגם תרגול מס' 4: המתרגם שימוש במחלקות קיימות תכנות מתק

פתרון 2000 א. טבלת מעקב אחר ביצוע האלגוריתם הנתון עבור הערכים : פלט num = 37, sif = 7 r האם ספרת האחדות של sif שווה ל- num num 37 sif 7 שורה (1)-(2) (

Slide 1

תורת החישוביות תרגול הכנה לוגיקה ותורת הקבוצות מה יש כאן? בקורס תורת החישוביות נניח ידע בסיסי בתורת הקבוצות ובלוגיקה, והכרות עם מושגים בסיסיים כמו א"ב

מבחן 7002 פרטים כלליים מועד הבחינה: בכל זמן מספר השאלון: 1 משך הבחינה: 3 שעות חומר עזר בשימוש: הכל )ספרים ומחברות( המלצות: קרא המלצות לפני הבחינה ובדי

Microsoft PowerPoint - T-10.ppt [Compatibility Mode]

Tutorial 11

Slide 1

2013/14 אוניברסיטת חיפה מבוא למדעי מחשב, מעבדה מטרת המעבדה: לתרגל את המעבר מאלגוריתם לקוד C כמה שיותר. הוראות:.1.2 ניתן לעבוד ביחידים או בזוגות. (יש מ

תרגול 1

PowerPoint Presentation

תוכן העניינים

Slide 1

תוכן העניינים

Microsoft Word - Ass1Bgu2019b_java docx

שעור 6

מקביליות

234114

מתכונת עיצוב 3013

úåëðä 1 - çæøä

שיעור 1

ex1-bash

Slide 1

PowerPoint Presentation

דוגמאות שהוצגו בהרצאה 10 בקורס יסודות מערכות פתוחות דוגמה 1 דוגמאות של פונקציות ב- awk שמראות שהעברת פרמטרים של משתנים פשוטים היא by value והעברת פרמט

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

Microsoft Word - pitaron222Java_2007.doc

מקביליות

תרגיל בית מספר 1#

תמליל:

חלוקה למודולים Abstract data types טיפוסי נתונים מופשטים ADT של מבני נתונים בחירת מבני נתונים

תכנות מודולארי מודולים ב- C דוגמה: מודול תאריך 2

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

מודול תוכנה מחולק לשני חלקים: הממשק והמימוש ממשק :(interface) מגדיר את הפעולות שניתן לעשות בעזרת המודול חלק זה חשוף למשתמש במודול מימוש :(implementation) מספק את המימוש לפעולות שניתן לבצע דרך ממשק המודול חלק זה אינו חשוף למשתמש למשל, עבור מכונית הגה הוא חלק מהממשק ואילו המנוע הוא חלק מהמימוש 4

h c כדי לכתוב מודולים ב- C ניצור לכל מודל קובץ וקובץ )למשל קודי שגיאה( קובץ ה- h יכיל את ממשק המודול: הכרזות על הפונקציות הגדרות טיפוסים הכרזות על קבועים שיש בהם עניין למשתמש קובץ ה- c יכיל את מימוש המודול: מימושי פונקציות הממשק ופונקציות פנימיות נוספות הגדרות טיפוסים לשימוש פנימי הכרזות על קבועים שאין בהם עניין למשתמש נראה כעת כיצד יוצרים מודול מטיפוס הנתונים עבור תאריך מתרגול 3 5

#ifndef DATE_H_ #define DATE_H_ #include <stdbool.h> #include <stdio.h> הגנה נגד include כפול, מה קורה בלעדיה? #define MIN_DAY 1 #define MAX_DAY 31 #define MONTH_NUM 12 #define DAYS_IN_YEAR 365 #define MONTH_STR_LEN 4 /** * A module for a date datatype */ typedef struct date_t { int day; char month[month_str_len]; int year; Date; 6

/** Possible error codes */ typedef enum { DATE_SUCCESS, DATE_NULL_ARG, DATE_FAIL, DATE_INVALID DateResult; /** writes the date to the stream fd */ DateResult dateprint(date date, FILE* fd); /** Reads a date from the stream fd */ DateResult dateread(date* date, FILE* fd); כדי לאפשר למשתמש שימוש נוח במודול עלינו לספק לו קודי שגיאה מפורטים, לכן נגדיר טיפוס מיוחד למטרה זו ונשתמש בו /** Returns true if both dates are identical */ bool dateequals(date date1, Date date2); /** Returns the number of days between the dates */ int datedifference(date date1, Date date2); /** Checks if the date has valid values */ bool dateisvalid(date date); #endif /* DATE_H_ */ יש לספק תיעוד מפורט יותר של ערכי החזרה והשגיאה. תיעוד זה אינו מסופק כאן מפאת חוסר המקום בשקף 7

#include "date.h" #include <string.h> אין צורך להכריז מחדש על הפונקציות, פשוט כוללים את הממשק בקובץ #define INVALID_MONTH 0 static const char* const months[] = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" ; static int monthtoint(char* month) { for (int i = 0; i < MAX_MONTH; i++) { if (strcmp(month, months[i]) == 0) { return i+1; return INVALID_MONTH; פונקציות עזר פנימיות אינן מעניינות את המשתמש ולכן יש להכריז עליהן כסטטיות static int datetodays(date date) { int month = monthtoint(date.month); return date.day + month*(max_day - MIN_DAY + 1) + DAYS_IN_YEAR * date.year; 8

DateResult dateprint(date date, FILE* fd) { if (!fd) { return DATE_NULL_ARG; fprintf(fd, "%d %s %d\n", date.day, date.month, date.year); return DATE_SUCCESS; DateResult dateread(date* date, FILE* fd) { if (!date!fd) { return DATE_NULL_ARG; if (fscanf(fd, "%d %3s %d", &(date->day), date->month, &(date->year))!= 3) { return DATE_FAIL; return dateisvalid(*date)? DATE_SUCCESS : DATE_INVALID; 9

bool dateisvalid(date date) { if (date.month[month_str_len-1]!= \0 ) return false; return date.day >= MIN_DAY && date.day <= MAX_DAY && monthtoint(date.month)!= INVALID_MONTH; bool dateequals(date date1, Date date2) { return date1.day == date2.day && strcmp(date1.month,date2.month) == 0 && date1.year == date2.year; int datedifference(date date1, Date date2) { int days1 = datetodays(date1); int days2 = datetodays(date2); return days1 - days2; 10

#include "date.h" int main() { Date date1 = { 21, "NOV", 1970 ; Date date2; DateResult result = dateread(&date2, stdin); if (result == DATE_FAIL) { fprintf(stderr,"bad date format\n"); return 0; else if (result == DATE_INVALID) { fprintf(stderr,"invalid date\n"); return 0; dateprint(date1, stdout); dateprint(date2, stdout); if (!dateequals(date1,date2)) { int diff = datedifference(date1,date2); int absolutediff = diff < 0? -diff : diff; printf("the dates are %d days apart\n", absolutediff ); return 0; כעת ניתן להשתמש במודול התאריך בתכניות שונות וגם לעדכן את מודול התאריך בקלות 11

נהוג לחלק את הקוד למודולים כדי לאפשר שימוש חוזר ותחזוקה נוחה מודול מוגדר משני חלקים - ממשק ומימוש הממשק מכיל רק את מה שהמשתמש במודול זקוק לו ב- C מגדירים את ממשק המודול בקובץ h ואת המימוש בקובץ c יש להגן על קבצי h מפני include כפול פונקציות פנימיות של המודול יש להגדיר כ- static 12

הסתרה ADT עבור תאריך 13

int main() { Date date1 = { 21, "NOV", 1970 ; Date date2; printf("enter a day number:"); scanf("%d", &date2.day); //... more code... return 0; משתמש במודול התאריך שלנו כתב את הקוד הבא: מה הבעיה? מה גורם לה? 14

הבעיה בטיפוסי הנתונים שלנו - המימוש חשוף המשתמש עלול לשכפל קוד במקום להשתמש בקוד קיים שינויים עתידיים במודול "ישברו" את הקוד של המשתמש בו הפתרון: נסתיר את המימוש של טיפוס הנתונים מהמשתמש כך שקוד אשר אינו משתמש בממשק לא יתקמפל חשוב לציין - המשתמש יכול להיות כותב המודול בעצמו 15

כדי להסתיר את המימוש מהמשתמש ב- C נשתמש בשיטה הבאה: בקובץ ה- h נכריז על טיפוס מצביע למבנה typedef struct datatype_t* Datetype; בקובץ ה- c נממש את המבנה struct datatype_t { // fields... ; משתמשים במודול לא יוכלו לבצע dereference למצביע משתמשים במודול חייבים להשתמש בו רק דרך הממשק המוגדר 16

#ifndef DATE_H_ #define DATE_H_ #include <stdbool.h> #include <stdio.h> /** * A module for a date */ typedef struct date_t* Date; רק טיפוס המצביע חשוף, עם הגדרה זו לא ניתן לבצע ל- Date dereference typedef enum { DATE_SUCCESS, DATE_NULL_ARG, DATE_FAIL, DATE_INVALID DateResult; 17

/** Allocates a new date */ Date datecreate(int day, int month, int year); /** Allocates a new date which is a copy of the argument */ Date datecopy(date date); /** Frees an existing date object */ void datedestroy(date date); DateResult dateprint(date date, FILE* fd); DateResult dateread(date date, FILE* fd); bool dateequals(date date1, Date date2); int datedifference(date date1, Date date2); bool dateisvalid(date date); #endif /* DATE_H_ */ מאחר והמשתמש לא יכול ליצור עצמים מטיפוס התאריך עלינו לספק לו ממשק לביצוע פעולות אלו 18

#include "date.h" #include <stdlib.h> #include <string.h> #define INVALID_MONTH 0 #define MIN_DAY 1 #define MAX_DAY 31 #define MONTH_NUM 12 #define DAYS_IN_YEAR 365 #define MONTH_STR_LEN 4 המבנה מוגדר בקובץ ה- C ולכן גישה לשדותיו אפשרית רק מיחידת הקומפילציה הזו struct date_t { int day; char month[month_str_len]; int year; ; static const char* const months[] = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" ; 19

static int monthtoint(char* month) { assert(month[month_str_len-1] == \0 ); for (int i = 0; i < MONTH_NUM; i++) { if (strcmp(month, months[i]) == 0) { return i+1; return INVALID_MONTH; static bool isdayvalid(int day) { return day >= MIN_DAY && day <= MAX_DAY; static bool ismonthnumbervalid(int month) { return month >= 1 && month <= MONTH_NUM; static int datetodays(date date) { int month = monthtoint(date->month); return date->day + month*(max_day - MIN_DAY + 1) + DAYS_IN_YEAR * date->year; 20

Date datecreate(int day, int month, int year) { if (!isdayvalid(day)!ismonthnumbervalid(month)) { return NULL; Date date = malloc(sizeof(*date)); if (!date) { return NULL; date->day = day; strcpy(date->month, months[month-1]); date->year = year; return date; 21

Date datecopy(date date) { if (!date) { return NULL; return datecreate(date->day, monthtoint(date->month), date->year); void datedestroy(date date) { free(date); למה בכלל לטרוח? bool dateisvalid(date date) { assert(date!= NULL); return isdayvalid(date->day) && monthtoint(date->month)!= INVALID_MONTH; 22

DateResult dateprint(date date, FILE* fd) { if(!date!fd) { return DATE_NULL_ARG; fprintf(fd, "%d %s %d\n", date->day, date->month, date->year); return DATE_SUCCESS; DateResult dateread(date date, FILE* fd) { if(!date!fd) { return DATE_NULL_ARG; if(fscanf(fd,"%d %3s %d",&(date->day),date->month,&(date->year))!= 3) { return DATE_FAIL; return dateisvalid(date)? DATE_SUCCESS : DATE_INVALID; 23

bool dateequals(date date1, Date date2) { assert(dateisvalid(date1) && dateisvalid(date2)); return date1->day == date2->day && strcmp(date1->month,date2->month) == 0 && date1->year == date2->year; int datedifference(date date1, Date date2) { assert(dateisvalid(date1) && dateisvalid(date2)); int days1 = datetodays(date1); int days2 = datetodays(date2); return days1 - days2; 24

#include <stdlib.h> #include "date.h" int main() { Date date1 = datecreate(21, 11, 1970); Date date2 = datecreate(1,1,0); DateResult result = dateread(date2, stdin); if (result!= DATE_SUCCESS) { fprintf(stderr,"bad input\n"); return 0; if (!dateequals(date1,date2)) { int diff = datedifference(date1,date2); printf("the dates are %d days apart\n", abs(diff)); datedestroy(date1); datedestroy(date2); return 0; צריך לבדוק הצלחה של datecreate() מה הבעיה? לא לשכוח לשחרר! ההקצאות הן דינאמיות! 25

טיפוסי נתונים מופשטים נבדלים מטיפוסי נתונים רגילים בניתוק המימוש מהממשק כדי להסתיר את המימוש של struct את הגדרת המבנה נשים בקובץ C ב- C נשתמש במצביעים למבנה 26

תחביר דוגמאות קוד גנרי 27

מה משותף לשתי הפונקציות הבאות? bool isbigger(int a, int b); bool isbiggerabs(int a, int b); ביצוע קריאה לפונקציות בעלות אותה חתימה נעשה באותה צורה בקוד מכונה השמת המשתנים במקום מוגדר )בד"כ על המחסנית( 1. קפיצה לכתובת תחילת הפונקציה בזיכרון 2. כתיבת ערך החזרה למקום מוסכם 3. קפיצה לכתובת ממנה נקראה הפונקציה 4. שלבים 3 1, ו- 4 זהים לכל שתי פונקציות בעלות אותה חתימה לכן ניתן לקרוא לפונקציות שונות בעזרת קוד דומה 28

ניתן להכריז על מצביע לפונקציה בעלת חתימה מסוימת: <return type> (*<name>)(<parameters>) = <initial value>; למשל הכרזה על מצביע עבור פונקציה המקבלת משתנה יחיד מטיפוס int ומחזירה int המאותחל ל- NULL תיראה כך: int (*ptr)(int) = NULL; מה קורה בלי הסוגריים? ניתן לאחסן במצביע לפונקציה את כתובתה של פונקציה בעלת חתימה זהה לזו שהוגדרה במצביע int square(int n);... ptr = square; // &square also works ניתן לקרוא לפונקציה דרך המצביע: printf("%d", ptr(5)); // (*ptr)(5) also works לא נהוג להשתמש ב-& ו-* עבור מצביעים לפונקציות 29

ברשותנו שתי הפונקציות הבאות: bool isbigger(int a, int b) { return a > b; bool isbiggerabs(int a, int b) { int abs_a = a > 0? a : -a; int abs_b = b > 0? b : -b; return abs_a > abs_b; נכתוב את הפונקציה max המקבלת מצביע לפונקציה ומחזירה את האיבר הגדול מביניהם בהתאם לקריטריון שמועבר לה int max(int a, int b, bool (*compare)(int,int)) { return compare(a,b)? a : b; מה יהיו תוצאות כל אחת מההרצות הבאות של?max max(-7, 5, isbigger); max(-7, 5, isbiggerabs); 30

int main() { bool (*function)(int, int); if (getchar() == '1') { function = isbigger; else { function = isbiggerabs; int a = -5, b = 3; bool c = function(a, b); בעזרת מצביעים לפונקציות ניתן ליצור קוד שבכל הרצה שלו יתנהג אחרת: if (c) { printf("%d",a); else { printf("%d",b); return 0; 31

כתבו פונקציה למיון מערך של מספרים שלמים המאפשרת מיון לפי קריטריון משתנה typedef bool (*CmpFunction)(int, int); void sort(int* array, int n, CmpFunction compare) { assert(array!= NULL && compare!= NULL); for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { if (compare(array[i], array[j])) { int tmp = array[i]; array[i] = array[j]; array[j] = tmp; כדי להימנע מהתחביר הלא נוח של מצביעים לפונקציות ניתן להשתמש ב- typedef 32

int main(){ int arr[] = { 1, -3, 9, -10, -5 ; sort(arr, 5, isbigger); // -10-5 -3 1 9 sort(arr, 5, isbiggerabs); // 1-3 -5 9-10 return 0; דוגמה לשימוש: 33

קוד גנרי הוא קוד המסוגל לעבוד על עצמים מטיפוסים שונים ב- C ניתן לכתוב קוד גנרי בעזרת: מצביעים ל- void כדי לייצג עצמים כלליים מצביעים לפוקציות כדי לייצג את הפעולות על העצמים בשיטה זו נוכל לממש אלגוריתמים פעם אחת בלבד ולמנוע שכפול קוד 34

כתבו פונקציה למיון מערך של עצמים כלשהם המאפשרת מיון לפי קריטריון משתנה typedef bool (*CmpFunction)(void*, void*); void sort(void** array, int n, CmpFunction compare) { assert(array!= NULL && compare!= NULL); for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { if (compare(array[i], array[j])) { void* tmp = array[i]; array[i] = array[j]; array[j] = tmp; 35

כדי למיין באמצעות הפונקציה החדשה עלינו ליצור פונקציות השוואה מתאימות: bool intisbigger(void* a, void* b) { assert(a && b); return ( *(int*) a ) > ( *(int*) b ); bool dateisbigger (void* date1, void* date2) { assert(date1 && date2); int difference = datedifference(date1,date2); return difference > 0; למה לא חייבים המרה מפורשת? 36

int main() { void* dates[3]; dates[0] = datecreate(20, 5, 2010); dates[1] = datecreate(1, 1, 2000); dates[2] = datecreate(2, 2, 2001); int* numbers[3]; numbers[0] = malloc(sizeof(int)); *numbers[0] = 17; numbers[1] = malloc(sizeof(int)); *numbers[1] = 1; numbers[2] = malloc(sizeof(int)); *numbers[2] = 7; 37 sort(dates, 3, dateisbigger); sort((void**)numbers, 3, intisbigger); for (int i = 0; i < 3; i++) { dateprint(dates[i], stdout); printf("\n"); for (int i = 0; i < 3; i++) { printf("%d\n",*numbers[i]); return 0; למה דרושה המרה מפורשת? מה חסר? 1 JAN 2000 2 FEB 2001 20 MAY 2010 1 7 17

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

פתרון בעיה ישירות מבני נתונים מחסנית פתרון הבעיה בעזרת מחסנית 39

נרצה לקלוט 100 מספרים אי שליליים מהקלט ולהדפיס אותם בסדר הפוך בזמן הכנסת הקלט המשתמש יכול להתחרט ולבטל את הכנסת המספר האחרון לצורך כך הוא צריך להכניס 1- פעולת הביטול דומה לפעולת undo בעורכי טקסטים המשתמש undo לבצע יכול כמה פעמים ולבטל כמה מספרים נפתור תחילה את הבעיה הזו ישירות 40

#include <stdio.h> #include <assert.h> #define MAX_SIZE 100 #define UNDO_LAST_COMMAND -1 int main() { int input, size = 0, numbers[max_size]; while (size < MAX_SIZE && scanf("%d", &input) == 1) { if (input!= UNDO_LAST_COMMAND) { assert(size >= 0 && size < MAX_SIZE); numbers[size++] = input; else if (size > 0) { size--; printf("undo\n"); else { printf("cannot undo\n"); while (size > 0) { printf("%d\n", numbers[--size]); assert(size >= 0 && size < MAX_SIZE); return 0; 41

לא ניתן לעשות שימוש חוזר בקוד עבור בעיות דומות קל להכניס באגים?--size או size--?++size או size++?size או >= 0 size > 0?size או < 0 size < 1 הפתרון אינו מתעד את עצמו מוסיפים רק לסוף המערך מורידים מספרים רק מסוף המערך ההדפסה מתבצעת רק בסדר הפוך עבור בעיה גדולה יותר, כבר לא ניתן לשמור על הקוד פשוט כמו במקרה זה 42

מבני נתונים הם טיפוסי נתונים מיוחדים שמטרתם לשמור אוסף של משתנים ולאפשר עליהם פעולות מסוימות Array Get(i) Set(i) Linked List Head() Next(node) InsertAfter(node) RemoveAfter(node) דוגמאות: מערך - הממשק של מערך כולל קריאת איברים לפי אינדקס והשמה לאיברים לפי אינדקס רשימה מקושרת - הממשק של רשימה מקושרת כולל קבלת האיבר הראשון, קבלת האיבר שבא אחרי איבר נתון, והכנסה/הוצאה של איבר אחרי איבר נתון נוח לכתוב מבני נתונים נוספים כטיפוס נתונים ולהשתמש בהם עבור בעיות מתאימות 43

)מבלי מבנה הנתונים מחסנית מוגדר לפי הממשק הבא: - push הוסף איבר בראש המחסנית - pop הוצא את האיבר האחרון שהוכנס למחסנית להחזיר את ערכו( - top החזר את ערכו של האיבר האחרון שהוכנס למחסנית )מבלי להוציאו( מחסנית מאפשרת גישה רק לאיבר האחרון שהוכנס ורק אותו ניתן להוציא ברגע נתון Out) (LIFO - Last In First 44

#ifndef _STACK_H #define _STACK_H /** ADT of Stack of integers */ typedef struct stack_t* Stack; /** possible return values */ typedef enum { STACK_SUCCESS, STACK_BAD_ARGUMENT, STACK_EMPTY, STACK_FULL StackResult; /** creates a Stack with maximal capacity of 'maxsize'. if fails, returns NULL */ Stack stackcreate(int maxsize); /** releases the memory allocated for the stack */ void stackdestroy(stack stack); ערכי שגיאות מוסכמים כדי לאפשר למשתמש להתמודד עם שגיאות איפה המבנה עצמו? מדוע? לא לשכוח הגנה נגד include כפול 45

/** insert a number to the top of the stack. Error Codes: STACK_BAD_ARGUMENT if stack is NULL STACK_FULL if the stack is full. */ StackResult stackpush(stack stack, int number); /** removes the element at the top of the stack. Error codes: STACK_BAD_ARGUMENT if stack is NULL STACK_EMPTY if the stack is empty */ StackResult stackpop(stack stack); /** returns in 'number' the last element that was pushed. Error codes: STACK_BAD_ARGUMENT if stack or number are NULL STACK_EMPTY if the stack is empty */ StackResult stacktop(stack stack, int* number); 46

/** returns a flag indicating whether the stack is full (meaning elements cannot be pushed) stack must not be NULL */ bool stackisfull(stack stack); /** returns a flag indicating whether the stack is empty (meaning elements cannot be popped) stack must not be NULL */ bool stackisempty(stack stack); /** returns the number of elements in the stack. stack must not be NULL */ int stacksize(stack stack); #endif 47

#include <stdio.h> #include <assert.h> #include <stdlib.h> #include "stack.h" #define MAX_INPUT_SIZE 100 #define UNDO_LAST_COMMAND -1 int main() { Stack stack = stackcreate(max_input_size); if (stack == NULL) { fprintf(stderr, "failed to create stack\n"); return -1; int input; while (!stackisfull (stack) && scanf("%d", &input) == 1) { if (input!= UNDO_LAST_COMMAND) { StackResult result = stackpush(stack, input); assert(result == STACK_SUCCESS); continue; StackResult result = stackpop(stack); if (result == STACK_EMPTY) { printf("cannot undo\n"); else { assert(result == STACK_SUCCESS); printf("undo\n"); 48

while (!stackisempty (stack)) { int number; StackResult result = stacktop(stack, &number); StackResult result2 = stackpop(stack); assert (result == STACK_SUCCESS && result2 == STACK_SUCCESS); printf("%d\n", number); stackdestroy(stack); return 0; 49

נבחר לממש את המחסנית בעזרת מערך נשמור שלושה שדות במבנה 5 nextindex מערך בו יישמרו המספרים גודל המחסנית המקסימלי אינדקס המקום הפנוי הבא במערך 2 זהו גם מספר האיברים במבנה 17 איזו דרך נוספת קיימת למימוש מחסנית? 3 50

#include <stdlib.h> #include <assert.h> #include "stack.h" /** The Stack is implemented as an array of integers. * With nextindex as an index to the next available position and * the maximal size is stored in maxsize. */ struct stack_t { int* array; int nextindex; int maxsize; ; 51

Stack stackcreate(int maxsize) { if (maxsize <= 0) { return NULL; Stack stack = malloc(sizeof(*stack)); if (stack == NULL) { return NULL; stack->array = malloc(sizeof(int)*maxsize); if (stack->array == NULL) { free(stack); return NULL; stack->nextindex = 0; stack->maxsize = maxsize; return stack; שימו לב, בשלב זה כבר יש הקצאה שהצליחה 52

StackResult stackpush(stack stack, int number) { if (stack == NULL) { return STACK_BAD_ARGUMENT; if (stack->nextindex >= stack->maxsize) { return STACK_FULL; assert(stack->nextindex >= 0 && stack->nextindex < stack->maxsize); stack->array[stack->nextindex++] = number; return STACK_SUCCESS; StackResult stackpop(stack stack) { if (stack == NULL) { return STACK_BAD_ARGUMENT; if (stack->nextindex < 1) { return STACK_EMPTY; stack->nextindex--; return STACK_SUCCESS; 53

StackResult stacktop(stack stack, int* number) { if (stack == NULL number == NULL) { return STACK_BAD_ARGUMENT; if (stack->nextindex < 1) { return STACK_EMPTY; assert(stack->nextindex > 0 && stack->nextindex <= stack- >maxsize); *number = stack->array[stack->nextindex - 1]; return STACK_SUCCESS; void stackdestroy(stack stack) { if (stack!= NULL) { free(stack->array); free(stack); 54

int stacksize(stack stack) { assert(stack); return stack->nextindex; כיצד ניתן היה לכתוב פונקציות אלו בצורה שונה כך שיחזירו ערכי שגיאה? מה היתרונות והחסרונות של כל שיטה? bool stackisempty(stack stack) { assert(stack); return stacksize(stack) == 0; bool stackisfull(stack stack) { assert(stack); return stacksize(stack) == stack->maxsize; 55

ניתן להגדיר מבני נתונים כ- ADT ע"י פתרון הבעיה עם מבנה המחסנית מתקבל פתרון עם סיכוי קטן יותר לבאגים הפתרון עם המחסנית מתעד את עצמו שימוש במבני נתונים מונע שכפול קוד שימוש במבני נתונים מבטיח את אופן העבודה עם הנתונים שימוש במבני הנתונים מקל על המתכנת בכתיבת קוד 56

בחירת מבני נתונים מבני הנתונים הנלמדים בקורס 57

בקורס זה אנו לומדים את מבני הנתונים הבסיסיים הבאים )כולם נלמדים כ- ADT (: - List רשימה: שומרת אוסף איברים עם סדר ביניהם ומאפשרת הכנסת אותו איבר מספר פעמים - Set קבוצה: מאפשרת הכנסת איבר פעם אחת בלבד ואינה שומרת סדר בין איברי הקבוצה - Stack מחסנית: מאפשרת הכנסה, גישה והוצאה רק מסופה. שומרת על סדר ומאפשרת כפילויות - Graph גרף: שומר קבוצת צמתים וקבוצת קשתות המחברות ביניהם מתאים לבעיות הדורשות אבסטרקציה של רשתות כגון רשת כבישים, רשת מחשבים וכו'..1.2.3.4 58

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

מבני הנתונים הנלמדים בקורס הם Stack,Set,List ו- Graph יש לבחור מבנה נתונים מתאים לבעיה כדי להקל על העבודה 60