Presentation is loading. Please wait.

Presentation is loading. Please wait.

תוכנה 1 - חזרה שולי לב יהודי 2 Arrays and Strings מערך - אוסף משתנים בעלי שם משותף. הפנייה לכל איבר נעשית ע ” י אינדקס. ב -C מערך מוגדר.

Similar presentations


Presentation on theme: "תוכנה 1 - חזרה שולי לב יהודי 2 Arrays and Strings מערך - אוסף משתנים בעלי שם משותף. הפנייה לכל איבר נעשית ע ” י אינדקס. ב -C מערך מוגדר."— Presentation transcript:

1 תוכנה 1 - חזרה שולי לב יהודי shulyl@tau.ac.il

2 2 Arrays and Strings מערך - אוסף משתנים בעלי שם משותף. הפנייה לכל איבר נעשית ע ” י אינדקס. ב -C מערך מוגדר בזיכרון רציף. האיבר הראשון נמצא בכתובת הנמוכה. לדוגמא, אם a מוגדר החל מכתובת 1000: char a[6]; Element a[0] a[1] a[2] a[3] a[4] a[5] Address 1007 1008 1009 1010 1011 1012

3 3 Single-Dimension Arrays type var_name[size]; double balance[100]; האינדקס של האיבר הראשון הוא 0. לדוגמא : char p[10]; מגדיר מערך של characters עם 10 אלמנטים [0]p עד [9]p. השטח שמוגדר עבור מערך : total bytes = sizeof(base type) * size of array

4 4 Single-Dimension Arrays (cont.)  אין בדיקה של גבולות המערך ! ניתן לכתוב מעבר לגבולות ללא שגיאת קומפילציה : int count[10], i; /* this causes count to be overrun */ for (i=0; i < 100; i++) count[i] = i;

5 5 Generating a Pointer to an Array שם המערך ללא ציון אינדקס הוא מצביע למערך : int sample[10]; int *p; p = sample; p יקבל את כתובת האיבר הראשון של sample.

6 6 Passing Single-Dimension Arrays to Functions לא ניתן להעביר תוכן של מערך שלם כארגומנט לפונקציה. ניתן להעביר מצביע לתחילת המערך : void main(void) { int i[10]; func1(i); } בפונקציה, ניתן להגדיר את הפרמטר באחד מ -3 אופנים :

7 7 Passing Single-Dimension Arrays to Functions void func1(int *x) /* pointer */ {... } void func1(int x[10]) /* sized array */ {... } void func1(int x[]) /* unsized array */ {... } גם זה יעבוד - יעבור מצביע - לא יוצר 32 איברים : void func1(int x[32]) /* sized array */

8 8 Return an Array from a Function int main(void) { char *mystr; mystr = getstr(); printf("%s\n", mystr); return 0; } char *getstr() { char str[20]; str[0] = 'a'; str[1] = 'b'; str[2] = '\0'; return(str); } ביציאה מהפונקציה השטח של str משוחרר ולכן ב - main יודפס " זבל ". צריך להקצות את str דינמית ע " י : char *str = malloc(20);

9 9 Strings String הוא מערך של characters המסתיים ב -null שמצוין ע ” י ` 0 \`. לכן גודל המערך צריך להיות גדול ב - 1 מאורך המחרוזת. למשל למחרוזת באורך 10: char str[11]; ניתן להגדיר קבוע מחרוזת ע ” י גרשיים : ”hello there” בקבוע אין צורך להוסיף null.

10 10 String Manipulation Functions NameFunctions strcpy(s1,s2) Copies s2 into s1 strcat(s1,s2) Concatenates s2 onto the end of s1 strlen(s1) Returns the length of s1 strcmp(s1,s2) Returns 0 if s1 and s2 are the same; less than 0 if s1 s2 strcmp מחזירה false אם המחרוזות שוות. לכן כדי לבדוק שוויון : if (!strcmp(s1,s2)) printf(“equal strings\n”); כדי להשתמש בפונקציות : <include <string.h#

11 11 Arrays of Strings מוגדר ע ” י מערך דו - מימדי : char str_array[30][80]; מגדיר מערך עם 30 מחרוזות, כל אחת באורך של עד 79 תווים. כדי לגשת למחרוזת אחת : gets(str_array[2]); שקול ל : gets(&str_array[2][0]); אך צורת הכתיבה הראשונה מקובלת יותר.

12 12 Indexing Pointers שם מערך ללא אינדקס הוא מצביע לאיבר הראשון במערך. לכן, הביטוי הבא הוא true: p == &p[0] באותו אופן, ניתן להוסיף אינדקס למצביע, כאילו שהוגדר כמערך : int *p, i[10]; p = i; p[5] = 100; /* assign using index */ *(p+5) = 100; /* assign using pointer arithmetic */ שתי הפקודות מציבות 100 באיבר השישי של i.

13 13 Array Initialization int i[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; [0]i יקבל את הערך 1 והלאה עד [9]i שיקבל את הערך 10. איתחול מערך של characters: char str[15] = “I like the sea”; זה שקול ל : char str[15] = {‘I’, ‘ ‘, ‘l’, ‘i’, ‘k’, ‘e’, ‘ ‘, ‘t’, ‘h’, ‘e’, ‘ ‘, ‘s’, ‘e’, ‘a’, ‘\0’};

14 14 Pointers מה זה Pointer? משתנה המכיל כתובת של משתנה אחר 1003 1000 1001 1002 1003 1004 1005 Variable in memory Memory address

15 15 Pointer Variable משתנה שצריך להכיל ערך של מצביע צריך להיות מוגדר כך : type *name; type מציין את סוג המשתנים שה - pointer יכול להצביע עליהם. כל מצביע יכול להצביע לכל משתנה מסוג כלשהו, אולם pointer arithmetic נעשה לפי ה - base type.

16 16 The Pointer Operators & מחזיר את הכתובת של משתנה בזיכרון : m = &count;  שם ב -m את הכתובת של count. אין כל קשר לערך של המשתנה count! * מחזיר את הערך שנמצא בכתובת שמופיעה אחריו. הוא המשלים של &. לדוגמא : q = *m; ישים את הערך של count בתוך q. כלומר, את הערך ש - m מצביע עליו.

17 17 The Pointer Operators(cont.)  ל א להתבלבל עם כפל - * ועם bitwise AND - &.  האופרטורים * ו -& ( של מצביעים ) קודמים לכל האופרטורים האריתמטיים, למעט מינוס אונרי ( 5 -) שהוא בעל קדימות זהה.  צריך לדאוג שהמצביע אכן תמיד מצביע לערך מסוג מתאים. אם הגדרנו מצביע ל - int, ה - compiler מניח שכל כתובת שהוא יכיל היא כתובת של ערך מסוג int.

18 18 The Pointer Operators(cont.) void main(void) { double x, y; int *p; /* The next statement causes p (which is an integer pointer) to point to a double. */ p = &x; /* The next statement does not operate as expected */ y = *p; } לא תהייה השמה של ערך x ל -y. כיוון ש -p מוגדר כמצביע ל - int, רק 4 בתים יועברו ל -y ולא 8 בתים שמכילים מספר floating point. ב - ++C אי אפשר לבצע השמה כזו ללא casting ( שגיאת קומפילציה ).

19 19 Pointer Expressions  Pointer Assignments void main(void) { int x; int *p1, *p2; p1 = &x; p2 = p1; printf(“ %p”, p2); /* print the address of x, not x ’s value */ }

20 20 Pointer Expressions (cont.)  Pointer Arithmetic 2 פעולות אפשריות : חיבור וחיסור. דוגמא : p1 מצביע ל -int וערכו 2000. נניח ש -int הוא באורך 4 בתים. אחרי הפעולה ++p1, p1 יכיל 2004 ולא 2001. בכל פעם ש - p1 מקודם, הוא יצביע ל -integer הבא. ניתן לחבר ערך כלשהו, למשל : ; p1 = p1+12 p1 יצביע לאלמנט ה - 12 ( מהסוג של p1 ) אחרי זה שהוא מצביע כעת. ניתן להחסיר ערך של מצביע מערך של מצביע אחר כדי למצוא את מספר האלמנטים ( מה -base type שלהם ) הנמצאים ביניהם.  לא ניתן : לכפול, לחלק, לחבר שני מצביעים, לבצע פעולות לוגיות (bitwise), לחבר או לחסר ערכי float או double.

21 21 Pointer Expressions (cont.)  Pointer Arithmetic - example: ch ch +1 ch+2 ch+3 ch+4 ch+5 3000 3001 3002 3003 3004 3005 char *ch = 3000; short *i = 3000; i i + 1 i + 2 כל פעולות האריתמטיקה על מצביע נעשות בהתאם ל -base type שלו

22 22 Pointer Expressions (cont.)  Pointer Comparisons Example: if (p < q) printf(“p points to lower memory than q\n”); בד ” כ שימושי כאשר מספר מצביעים מצביעים לאובייקטים משותפים, כמו במערך. דוגמא - מחסנית stack:  רשימת איברים שהגישה אליהם היא בשיטת Last-in, First- out (LIFO).  2 פעולות : ()push - מכניסה ערך למחסנית ()pop - מוציאה ערך מהמחסנית  בדוגמא, הערכים שהמשתמש מקליד, מוכנסים למחסנית. אם הוקלד 0, מוציאים ערך מהמחסנית (pop). התכנית מסתיימת כשמתקבל ערך 1-.

23 23 Pointer Expressions (cont.) Stack example: #include #include #define SIZE 50 void push(int i); void pop(void); int *tos, *p1, stack[SIZE]; void main(void) { int value; tos = stack; /* tos points to the top of the stack */ p1 = stack; /* initialize p1 */ do { printf(“Enter value: “); scanf(“%d”, &value); if (value != 0) push(value); else printf(“ value on top is%d\n”, pop()); } while (value != -1); } void push(int i) { p1++; if (p1 == (tos + SIZE)) { printf(“Stack overflow”); exit(1); } *p1 = i; }

24 24 Pointer Expressions (cont.) Stack example (cont.): pop(void) { if (p1 == tos) { printf(“Stack underflow”); exit(1); } p1--; return *(p1 + 1); } הערה : בפקודת ה - return הסוגריים הכרחיים. בלעדיהם היה : return *p1 + 1 ; הערך שהיה חוזר הוא הערך שבכתובת p1 ועוד 1, ולא הערך בכתובת p1+1 ( שהיא 4 בתים אחרי p1).

25 25 Arrays of Pointers מערך של 10 מצביעים ל -int: int *x[10] הכנסת כתובת המשתנה var לאיבר השלישי במערך : x[2] = &var; למציאת הערך של var : *x[2] העברת מערך של מצביעים לפונקציה - קריאה לפונקציה עם שם המערך ללא אינדקס. למשל, פונקציה המקבלת מערך x תראה כך :

26 26 Arrays of Pointers (cont.) void display_array(int *q[ ]) { int t; for (t=0; t < 10; t++) printf (“%d “, *q[t]); } q אינו מצביע ל -integers, אלא מצביע למערך של מצביעים ל -integers.

27 27 Arrays of Pointers (cont.) שימוש נפוץ במערך של מצביעים הוא להחזקת מצביעים ל - strings. לדוגמא, פונקציה המקבלת קוד שגיאה ומדפיסה הודעה מתאימה : void syntax_error(int num) { static char *err[] = { “Cannot open file\n”, “Read error\n”, “Write error\n”, “Media Failure\n” }; printf (“%s”, err[num]); }

28 28 Using Structures Pointers מציאת כתובת ה - structure ע ” י & לפני שם המשתנה : struct bal { float balance; char name[80]; } person; struct bal *p; /* declare a structure pointer */ p = &person; ואז שם את כתובת person במצביע p. גישה לשדה ב - structure נעשית ע ” י האופרטור ->: p- >balance האופרטור. (dot) משמש כדי לגשת לשדה כאשר פועלים ישירות על ה - structure ( ולא ע ” י מצביע ). העברת כתובת של שדה תעשה כך : func(&person.x); func2(person.name); func3(&person.name[2])

29 29 The Operator -> An Example: display a timer struct my_time { int hours; int minutes; int seconds; }; void main(void) { struct my_time systime; systime.hours = 0; systime.minutes = 0; systime.seconds = 0; for ( ; ; ) { update(&systime); display(&systime); } } void update(struct my_time *t) { t->seconds++; if (t->seconds == 60) { t->seconds = 0; t->minutes++; }. } void display(struct my_time *t) { printf(“%02d:”, t->hours); printf(“%02d:”, t->minutes); printf(“%02d:”, t->seconds); }

30 30 Multiple Indirection (Pointers to Pointers) addressvalue address value Pointer Variable Pointer Variable Single Indirection Multiple Indirection

31 31 Multiple Indirection (cont.) הגדרת מצביע למצביע : ; float **newbalance  newbalance אינו מצביע למספר floating-point אלא מצביע למצביע ל - float. כדי לגשת לערך עצמו יש להפעיל את אופרטור ה -* פעמיים : int x, *p, **q; x = 10; p = &x; q = &p; printf(“%d”, **q); /* print the value of x */

32 32 Initializing Pointers אחרי שמצביע הוגדר אך לפני שהושם לו ערך, הוא מכיל ערך לא ידוע (“ זבל ”).  אם ננסה להשתמש במצביע לפני שיש לו ערך “ חוקי ”, סביר שהתכנית תעוף ( וכנראה גם מערכת ההפעלה )! מוסכמה : מצביע שכרגע אינו מצביע למיקום בר - תוקף בזיכרון, מאותחל ל - null ( שהוא 0). מצביע שערכו null אינו מצביע לכלום. נשתמש בערך null כדי לציין למשל, סוף של מערך של מצביעים.

33 33 Initializing Pointers (cont.) Search (char *p[], char *name) { register int i; for (i=0; p[i]; ++i) if (!strcmp(p[i], name)) return; return -1; } כאן, ערך null מציין את סוף המערך. הלולאה רצה כל עוד לא נמצא name ולא הגענו למצביע שערכו null.

34 34 Initializing Pointers (cont.) ניתן לאתחל מצביע ל - char במחרוזת כאילו שהוא מערך : char *p = “hello world”; ה - compiler שומר את כל קבועי המחרוזות ב - string table ולכן הפקודה תכניס ל -p את הכתובת של הקבוע “hello world” כפי שהוא מאוחסן ב - string table.

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

36 36 Pointers to Functions (cont.) void check (char *a, char *b, int (*cmp)(const char *, const char *)); void main(void) { char s1[80], s2[80]; int (*p)(const char *, const char *); p = strcmp; gets(s1); gets(s2); check(s1, s2, p); } void check (char *a, char *b, int (*cmp)(const char *, const char *)) { printf(“testing for equality\n”); if (!(*cmp)(a,b)) printf(“equal”); else printf(“not equal”); } הביטוי (cmp)(a,b*) קורא ל -strcmp. ניתן לקרוא ל -check גם כך : check(s1, s2, strcmp);

37 37 Dynamic Allocation Functions ה קצאה דינמית - הקצאת שטח בזמן ריצה. זיכרון דינמי מוקצה על ה - heap - שטח הנמצא בין התכנית והשטח הקבוע שלה (data), לבין ה - stack. פונקציות עיקריות : malloc - מקצה שטח, free - משחררת. צריך את השורה : include stdlib.h # prototype: void *malloc(size_t number_of_bytes); מחזירה מצביע ל - void שפרושו שניתן לשים את הערך החוזר במצביע מכל סוג שהוא.

38 38 Dynamic Allocation Functions (cont.) בהצלחה - מוחזר מצביע ל - byte הראשון בשטח שהוקצה. בכשלון - כאשר אין מספיק מקום - מוחזר null. לדוגמא : ; char *p p = malloc(1000);  אין צורך ב - cast, הערך מוסב אוטומטית לפי ה -type בצד שמאל ( ב -++C לא נעשית הסבה אוטומטית !). הקצאת 50 integers. ה -sizeof נחוץ ל -portability: int *p; p = malloc(50 * sizeof(int));

39 39 Dynamic Allocation Functions (cont.)  יש לבדוק האם הערך החוזר אינו null! free מחזירה למערכת שטח שהוקצה קודם. prototype: void free(void *p); p הוא מצביע לשטח שהוקצה קודם.  חשוב לא לקרוא ל - free עם ארגומנט לא נכון !

40 40 Problems with Pointers שימוש בערך לא טוב של מצביע יכול לגרום לכתיבה לשטח אחר. טעויות נפוצות :  uninitialized pointer: /* this program is wrong */ void main(void) { int x, *p; x = 10; *p = x; } p לא אותחל ולכן הערך 10 נכתב במקום לא ידוע בזיכרון. הבעיה משמעותית בתכנית גדולה.

41 41 Problems with Pointers (cont.)  Misunderstanding of how to use a pointer: /* this program is wrong */ void main(void) { int x, *p; x = 10; p = x; printf(“%d”, *p); } printf לא תדפיס את הערך 10 אלא ערך כלשהו אחר. לתיקון יש לכתוב : p = &x;

42 42 Problems with Pointers (cont.)  Incorrect assumptions about variables locations: אי אפשר לדעת היכן המשתנים ממוקמים בזיכרון. לכן אם ננסה להשוות בין מצביעים שאינם מצביעים לאובייקט משותף, נקבל תוצאה לא צפויה : char s[80], y[80]; char *p1, *p2; p1 = s; p2 = y; if (p1 < p2)... לא נכון להניח ש - s ו -y מוקצים ברצף.

43 43 Problems with Pointers (cont.) באותו אופן לא נכון לאתחל את המערכים first ו - second במספרים 0 עד 19 ( למרות שבחלק מה - compilers זה יעבוד ): int first[10], second[10]; int *p, i; p = first; for (i=0; i < 20; i++) *p++ = i;

44 44 argc and argv – Arguments to main() מעבירים ערכים ל - main() ע " י ה - command line arguments: program_name command_line_arguments argc ו - argv מוגדרים built-in ובהם מתקבלים הארגומנטים. argc מכיל את מספר הארגומנטים והוא int, ערכו תמיד לפחות 1 כיוון ששם התכנית הוא הארגומנט הראשון. argv הוא מצביע למערך של מצביעים ל - character, כל איבר במערך מצביע לארגומנט. כל הארגומנטים הם strings – התכנית צריכה להמיר מספרים ל -format המתאים.

45 45 argc, argv /* The name of the program is “name” */ void main(int argc, char *argv[ ]) { if (argc != 2) { printf (“You forgot to type your name.\n”); exit(1); } printf(“Hello %s”, argv[1]); } > name Tom > Hello Tom

46 46 argc, argv ברוב סביבות העבודה הארגומנטים מופרדים ע " י רווח או tab. פסיק, נקודה - פסיק אינם נחשבים מפרידים. לדוגמא : אלו הן 3 מחרוזות : run Spot, run וזוהי מחרוזת אחת : Herb,Rick,Fred וגם זו : “Alon Ronit”

47 47 argc, argv - Example /* countdown – the program counts down from a starting value (which is specified on the command line) and beeps when it reachs 0. */ #include #include #include #include void main(int argc, char *argv[ ]) { int disp, count; if (argc < 2) { printf(“You must enter the length of the count.\n”); exit(1); }

48 48 argc, argv – Example (cont.) /* if the string “display” is the second argument, the countdown will also be displayed on the screen. */ if (argc == 3 && !strcmp(argv[2], “display”)) disp = 1; else disp = 0; for (count=atoi(argv[1]); count; --count) if (disp) printf(“%d\n”, count); putchar(‘\a’); /* this will ring the bell in most computers */ printf (“Done\n”); }

49 49 What Does main() Return? הפונקציה main() מחזירה int לתהליך שקורא לה שהוא בד " כ מערכת ההפעלה. החזרת ערך מ - main() שקולה לקריאה ל - exit() עם אותו ערך אם לא מוחזר ערך הערך שחוזר לתהליך הקורא אינו מוגדר ( רוב ה -compilers יחזירו 0, אך לא תמיד ). ניתן להגדיר את main() כ -void אם איננה מחזירה ערך, אולם אם פונקציה איננה מחזירה ערך וגם לא מוגדרת כ - void יתקבל warning.

50 50 Files קובץ יכול להיות כל מדיה החל מקובץ על הדיסק, מסך ועד מדפסת. פקודת ה - open מקשרת stream עם קובץ ספציפי. stream הוא קובץ לוגי - מהווה interface אחיד. לא לכל הקבצים יש אותן אפשרויות גישה, למשל : לקובץ בדיסק ניתן לגשת בצורה אקראית ול - modem port - לא. בפתיחת קובץ, ה - position indicator מצביע לתחילתו. עם כל תו שנקרא / נכתב הוא מקודם. בסגירת קובץ פלט, התוכן מה - buffer שמקושר ל - stream נכתב לקובץ החיצוני - flushing.

51 51 Files(cont.) כאשר התכנית מסתיימת באופן נורמלי, כל הקבצים נסגרים אוטומטית. אולם, כאשר היא עפה - הקבצים אינם נסגרים. לכל stream, המקושר עם קובץ, יש file control structure מסוג FILE ( מוגדר ב -stdio.h). אל תעדכנו אותו !

52 52 File System Functions Function fopen() fclose() putc()/fputc() getc()/fgetc() fseek() fprintf() fscanf() feof() ferror() rewind() fflush() Operation Opens a file Closes a file. Writes a character to a file. Reads a character from a file. Seeks to a specific byte in a file (random access). Writes formatted data to a file. Read formatted data from a file. Returns true if end-of-file is reached. Returns true if an error has occurred. Resets the file position indicator to the beginning. Flushes a file.

53 53 Stdio.h Prototypes to I/O functions 3 types: size_t (variety of unsigned int), fpos_t (variety of unsigned int), FILE. Macros: NULL defines a null pointer EOF -1 is the value returned when an input function tries to read past the end of the file. FOPEN_MAX the number of files that can be open at any one time. Others macros used with fseek().

54 54 fread() and fwrite() מאפשרות לקרוא ולכתוב בלוק בגודל כלשהו : size_t fread(void *buffer, size_t num_bytes, size_t count, FILE *fp); size_t fwrite(const void *buffer, size_t num_bytes, size_t count, FILE *fp); יש לפתוח את הקובץ ב -binary mode struct struct_type { דוגמא : float balance; char name[80]; } cust; fwrite(&cust, sizeof(struct struct_type), 1, fp);

55 55 fread() and fwrite() /* write some non-character data to a disk file and read it back */ void main(void) { FILE *fp; double d = 12.23; int i = 241; long l = 123023L; if ((fp = fopen(“test”, “wb+”)) == NULL) { printf (“cannot open file.\n”); exit(1); }

56 56 fread() and fwrite() fwrite (&d, sizeof(double), 1, fp); fwrite (&i, sizeof(int), 1, fp); fwrite (&l, sizeof(long), 1, fp); rewind(fp); fread (&d, sizeof(double), 1, fp); fread (&i, sizeof(int), 1, fp); fread (&l, sizeof(long), 1, fp); printf(“%f %d %ld”, d, i, l); fclose(fp); }

57 57 Example /*return for each one of the code sections: 1. if it is not legal 2. legal - but not working right 3.legal and working */ typedef struct complex { float real, img; } complex;

58 58 Example (cont.) complex * complex_init (float _real, float _img) { complex c; c.real = _real; c.img=_img; return &c; } complex * complex_init1 (complex c, float _real, float _img) { c.real = _real; c.img=_img; return &c; }

59 59 Example (cont.) complex * complex_init2(complex *p_c, float _real, float _img) { p_c->real = _real; p_c->img = _img; return p_c; } complex * complex_init3(float _real, float _img) { complex c; c.real = _real; c.img = _img; return c; }

60 60 Example (cont.) struct complex complex_init4(complex *p_c,float _real,float _img) { struct complex c; c.real = _real; c.img = _img; return c; } complex complex_init5(float _real,float _img) { complex c = {_real,_img}; return *(&c); }


Download ppt "תוכנה 1 - חזרה שולי לב יהודי 2 Arrays and Strings מערך - אוסף משתנים בעלי שם משותף. הפנייה לכל איבר נעשית ע ” י אינדקס. ב -C מערך מוגדר."

Similar presentations


Ads by Google