Presentation is loading. Please wait.

Presentation is loading. Please wait.

הרצאה 6: כתובות ומצביעים הקצאה דינמית מחרוזות

Similar presentations


Presentation on theme: "הרצאה 6: כתובות ומצביעים הקצאה דינמית מחרוזות"— Presentation transcript:

1 הרצאה 6: כתובות ומצביעים הקצאה דינמית מחרוזות
מבוא למדעי המחשב הרצאה 6: כתובות ומצביעים הקצאה דינמית מחרוזות מבוסס על שקפים שנערכו ע"י שי ארצי, גיתית רוקנשטיין ז"ל, איתן אביאור, סאהר אסמיר,מיכאל אלעד, רון קימל ודן רביב. עדכון אחרון: יחיאל קמחי ,נובמבר 2014

2 מבוא למדעי המחשב. כל הזכויות שמורות ©
תוכנייה מגבלות בתכנות בעזרת פונקציות מצביעים (Pointers) אופרטור הכתובת & אופרטור הכתובת * אריתמטיקה של מצביעים מערכים כמצביעים הקצאות דינמיות מחרוזות מבוא למדעי המחשב. כל הזכויות שמורות ©

3 העברת פרמטרים לפונקציה by value
בשפת C, פרמטרים מועברים לפונקציות by value, כלומר מועבר לפונקציה ערך הארגומנט. כאשר הביטוי המהווה את הארגומנט הוא משתנה, הפרמטר שמקבלת הפונקציה הוא עותק של אותו משתנה (לפעמים לאחר המרה). אם הפונקציה משנה את העותק שלה, הערך החדש איננו מועתק חזרה למשתנה המקורי בסיום הפונקציה. דוגמה: void swap(int x, int y) { int temp = x; x = y; y = temp; } int main(void) int x = 5, y = 7; swap(x,y); x y temp 5 7 ? 7 5 ? ? 5 מה נעשה? x y 5 7 מבוא למדעי המחשב. כל הזכויות שמורות ©

4 העברת מערך לתוך פונקציה?
#include <stdio.h> #define NUM 10 void ArrayRead(double a[], int); double ArraySum(double [], int); int main(void) { double slries[NUM]; ArrayRead(slries, NUM); double avrg = (double)ArraySum(slries, NUM) / NUM; . . . } void ArrayRead(double a[], int len) { for (int i = 0; i < NUM; ++i) { if (scanf("%lf", &a[i]) < 1) exit(1); return; אבל בפרק הקודם ראינו תוכנית שבה פונקציה קראה נתונים לתוך מערך לא מאותחל ב- main() ואפשרה את חישוב סכום איבריו. מסקנה: מערך אינו עובר by value כארגומנט לפונקציה. מבוא למדעי המחשב. כל הזכויות שמורות ©

5 הוצאת מקבץ ערכים מפונקציה?
#include <stdio.h> double quad_solve(int, int, int); int main(void) { double a=1.,b=4.,c=1.; double x[2] = quad_solve(a,b,c); printf("Roots %d %d\n",x[0],x[1]); return 0; } double[] quad_solve(int a,int b,int c) { double x[2]; ... x[0] = ... x[1] = ... return x; // return x[0],x[1]; נניח כי רצוננו בתוכנית לחישוב שורשיה של משוואה ריבועית, כשאת החישוב אנו מקצים לפונקציה. ישנה בעיה קטנה – זו תוכנית שגויה! לא ניתן להעביר בפקודת return מספר משתנים או מערך. מבוא למדעי המחשב. כל הזכויות שמורות ©

6 מבוא למדעי המחשב. כל הזכויות שמורות ©
סיכום הדברים לפנינו מספר מגבלות מהותיות: חוסר היכולת של פונקציה לשנות ערכי משתנים המועברים אליה לחוסר היכולת להעתיק מערכים לתוך פונקציה (no call by value) יש יתרונות (ההעתקה יקרה) וחסרונות (אפשר לקלקל אותו). חוסר היכולת לקבל מפונקציה תוצאה שאינה סקלרית. הפתרון לכל בעיות אלו זהה – שימוש בכתובות של משתנים כתחליף לשימוש ישיר בהם. אנו נראה שלמערכים מקום מיוחד בהקשר זה. מבוא למדעי המחשב. כל הזכויות שמורות ©

7 תזכורת: כתובות משתנים בזיכרון
הכתובת של x היא: הכתובת של d היא: הכתובת של c היא: לכל משתנה יש כתובת בזיכרון, ואנו נעשה בה שימוש!!! { double x; short d; char c; ... } 1001 1002 1000 1007 1003 1006 1005 1004 1011 1010 1009 1008 x d c מבוא למדעי המחשב. כל הזכויות שמורות ©

8 מבוא למדעי המחשב. כל הזכויות שמורות ©
תוכנייה מגבלות בתכנות בעזרת פונקציות מצביעים (Pointers) אופרטור הכתובת & אופרטור הכתובת * אריתמטיקה של מצביעים מערכים כמצביעים הקצאות דינמיות מחרוזות מבוא למדעי המחשב. כל הזכויות שמורות ©

9 כתובות, מצביעים והאופרטור &
ערך הביטוי a& הוא כתובת המשתנה a בזיכרון. מותר להפעיל את האופרטור & על תאי זיכרון בלבד (&7 אסור). בדוגמה הקודמת - &x=1000, d=1008&, וכן &c=1010. הטיפוס type* מיועד לייצג כתובות של משתנים מטיפוס type. משתנה מטיפוס type* ייקרא מצביע (pointer) ל- type. ההגדרה int* p משמעותה: p מיועד להחזיק כתובות של משתנים מטיפוס int. נאמר ש- "p הוא מצביע ל-int". ניתן לבצע על כתובות פעולות אריתמטיות מסוימות, כגון הוספת קבוע או חיסור שתי כתובות. נושא זה יידון בהרחבה בהמשך. מבוא למדעי המחשב. כל הזכויות שמורות ©

10 דוגמאות להכרזות על מצביעים
תמונת הזיכרון דוגמה 1: ? 1000 p int y; int a = 3; int *p; p = &a; 1000 3 a ? y double *dp, *dq; char c; char *cp1, *cp2 = &c; double x; dp = dq = &x; דוגמה 2: מבוא למדעי המחשב. כל הזכויות שמורות ©

11 מבוא למדעי המחשב. כל הזכויות שמורות ©
מצביעים - המשך אסור לערבב טיפוסי מצביעים: מותר לבצע המרה (אבל מסוכן מאד): קיימים בשפת C גם "מצביעים לפונקציות": משתנים המחזיקים כתובות של פונקציות. לא נעסוק בהם בקורס זה. int *p; double a; p = &a; חוקי אבל מסריח  p = (int*)&a; מבוא למדעי המחשב. כל הזכויות שמורות ©

12 מבוא למדעי המחשב. כל הזכויות שמורות ©
מצביעים והאופרטור * אם p הינו מצביע מטיפוס type*, אזי הביטוי *p שקול למשתנה (מטיפוס type) שכתובתו שמורה ב-p. תמונת הזיכרון int y; int a = 3; int *p; p = &a; y = *p; *p = 7; ? 1000 p 1000 7 3 a 3 ? y מבוא למדעי המחשב. כל הזכויות שמורות ©

13 האופרטורים & ו- * - ביטויים
int i=3, j=5, *p = &i, *q = &j, *r; double x; ביטוי ביטוי שקול ערך p == &i p == (& i) 1 * * & p * (* (& p))) 3 r = & x r = (& x) /* ? */ 7 * * p / * q + 7 ((7 * (*p)) / (*q)) + 7 11 * (r = & j) *= * p (* (r = (& j))) *= (* p) 15 מבוא למדעי המחשב. כל הזכויות שמורות ©

14 העברת כתובות של משתנים לפונקציות
void swap(int* px, int* py) { int temp = *px; *px = *py; *py = temp; } int main(void) int x = 5, y = 7; swap(&x, &y); ... תמונת הזיכרון* *נתעלם מכתובת חזרה וכו' על המחסנית 5 ? temp ? 1004 py 1000 ? px 1004 5 7 y 1000 5 7 x מבוא למדעי המחשב. כל הזכויות שמורות ©

15 עוד על מצביעים כפרמטרים לפונקציות
void swap(int* x, int* y) { int temp = *x; *x = *y; *y = temp; } int main(void) int a, b, c, d; int *p = &c; scanf("%d %d", &a, p); ... swap(&a, &b); swap(p, &d); פונקצית הספרייה scanf אמורה לעדכן ערך תא בזיכרון (לשים בו את הערך הנקלט) ולכן מקבלת כתובת (מצביע): scanf(“%d”,&a); מדוע אין &? מבוא למדעי המחשב. כל הזכויות שמורות ©

16 דוגמה: פונקציה שמצמצמת שבר
נתונים: שני משתנים המייצגים מונה ומכנה של שבר. הדרישה: הפונקציה תעדכן את שני המשתנים הללו כך שייצגו את השבר המצומצם. לדוגמה: החתימה של הפונקציה: הקריאה: דוגמה מלאה (Page4) ועוד רבות ב- void reduce(int *x, int *y); int a, b; ... reduce(&a, &b); מבוא למדעי המחשב. כל הזכויות שמורות ©

17 מבוא למדעי המחשב. כל הזכויות שמורות ©
דוגמה - מימוש int gcd(int, int); /* DO NOT reduce(0,0) */ void reduce(int *p_numerator, int *p_denominator) { int g = gcd(*p_numerator, *p_denominator); *p_numerator /= g; *p_denominator /= g; return; } RUN int gcd(int m,int n) { while(n != 0) { int tmp = n; n = m % n; m = tmp; } return m; int gcd(int m,int n) { while(n != 0) { m %= n; swap(&m, &n); } return m; או מבוא למדעי המחשב. כל הזכויות שמורות ©

18 דוגמה: פונקציה המחברת שני שברים
נתונים: שלושה שברים הדרישה: הפונקציה תעדכן את a,b כך ש: החתימה של הפונקציה: הקריאה: void add(int *a, int *b, int a1, int b1, int a2, int b2); int a, b, a1, b1; ... add(&a, &b, a1, b1, 5, 10); מבוא למדעי המחשב. כל הזכויות שמורות ©

19 דוגמה - מימוש סדר הפעולות שנשלט ע"י הסוגריים נועד למנוע גלישה (כשאפשר)
int gcd(int, int); void reduce(int *x, int *y); int lcm(int, int); // Least common multiplier void add(int *pa, int *pb, int a1, int b1, int a2, int b2) { *pb = lcm(b1, b2); *pa = a1*(*pb / b1) + a2*(*pb / b2); reduce(pa, pb); } int lcm(int m, int n) { return m/gcd(m,n)*n; RUN דוגמה: המכנה המשותף של 15 ו-20 הוא 20·15/5=60 סדר הפעולות שנשלט ע"י הסוגריים נועד למנוע גלישה (כשאפשר) מבוא למדעי המחשב. כל הזכויות שמורות ©

20 מבוא למדעי המחשב. כל הזכויות שמורות ©
הקבוע NULL אף על פי שכתובות אינן נחשבות מטיפוס int מותר לכל משתנה מסוג מצביע לקבל את הערך הקבוע 0. השפה מבטיחה כי 0 לעולם לא יתפרש ככתובת חוקית. לשם הקריאות משתמשים בקבוע NULL המוגדר בקובץ stdio.h וערכו 0. הצבת NULL במשתנה מצביע מסמנת כי מצביע זה אינו מכיל כעת כתובת של משתנה. int *p = NULL; *p = 7; /* what will happen? */ מבוא למדעי המחשב. כל הזכויות שמורות ©

21 מבוא למדעי המחשב. כל הזכויות שמורות ©
הטיפוס void* מצביע מטיפוס void* הינו מצביע גנרי (זהו מצביע לזיכרון אך ללא ציון באשר לסוג המשתנה עליו הוא מצביע). גישה לתוכן המוצבע ע"י void* אפשרית רק אם ממירים את המצביע לסוג המתאים. sizeof(*p1) שקול ל-sizeof(int) בעוד ש-sizeof(*p2) אינו מוגדר. sizeof(p1) ו-sizeof(p2) שקולים, ומציינים את מספר הבתים הנדרש לייצוג כתובת (כלשהי) בזיכרון. int a=5, b, *p1; char c = 'x'; void *p2, *p3 = &c; p1 = &a; p2 = p1; b = *p1 + *(int*)p2; מותר ללא צורך בהמרה חובה לבצע המרה מבוא למדעי המחשב. כל הזכויות שמורות ©

22 מבוא למדעי המחשב. כל הזכויות שמורות ©
תוכנייה מגבלות בתכנות בעזרת פונקציות מצביעים (Pointers) אופרטור הכתובת & אופרטור הכתובת * אריתמטיקה של מצביעים מערכים כמצביעים הקצאות דינמיות מחרוזות מבוא למדעי המחשב. כל הזכויות שמורות ©

23 מבוא למדעי המחשב. כל הזכויות שמורות ©
אריתמטיקה של מצביעים מצביעים ומספרים שלמים אינם אותו דבר. בפרט לא כל פעולה שניתן לבצע על מספר שלם ניתן לבצע על מצביע. כמו כן הסמנטיקה של חלק מהפעולות היא שונה. C מאפשרת לנו לבצע מספר פעולות אריתמטיות על מצביעים. יכולת זו חשובה, במיוחד כאשר נעבור עם מצביעים לאיברים במערך. האריתמטיקה מוגדרת כך: כל תוספת/הפחתה של 1 מקדמת/מחזירה את המצביע במספר בתים כגודל הטיפוס אליו מצביעים. לדוגמה: עבור מצביע double*, תוספת של 1 תקדם אותו 8 בתים בזיכרון (בהנחה שזהו הגודל של double במערכת). עבור מצביע char*, הפחתה של 3 תזיז אותו 3 בתים לאחור בזיכרון. מבוא למדעי המחשב. כל הזכויות שמורות ©

24 אריתמטיקה של מצביעים: מה מותר?
ניתן לקדם ולהחזיר מצביע ב-1 ע"י ++ או --. מותר להוסיף למצביע או לחסר ממצביע ביטוי שערכו מספר שלם. ניתן כמובן להשתמש באופרטורים המקוצרים += -=. ניתן לחסר שני מצביעים זה מזה, בתנאי: שהם מאותו הטיפוס ושייכים לאותו עצם (למשל, אותו מערך). התוצאה מומרת למספר שלם (int) המחזיק את מספר העצמים ביניהם בזכרון. אסור לחבר/להכפיל/לחלק שני מצביעים. נשתמש באריתמטיקת מצביעים כאשר יש לנו בזיכרון מספר איברים רצופים מאותו הטיפוס (למשל מערך). מבוא למדעי המחשב. כל הזכויות שמורות ©

25 אריתמטיקה של מצביעים: דוגמה
נתונות ההגדרות: הנחות: גודל של משתנה מסוג int הינו 4 בתים. המצביע p מחזיק את הכתובת 300 ו-q את הכתובת 400. int *p, *q; ביטוי ערך הביטוי תופעת לוואי p + 1 304 p + 2 308 (char*)p + 2 302 p++ 300 p  304 q – p 25 (char*)q -(char*)p 100 q -(char*)p ??? אסור מבוא למדעי המחשב. כל הזכויות שמורות ©

26 מבוא למדעי המחשב. כל הזכויות שמורות ©
תוכנייה מגבלות בתכנות בעזרת פונקציות מצביעים (Pointers) אופרטור הכתובת & אופרטור הכתובת * אריתמטיקה של מצביעים מערכים כמצביעים הקצאות דינמיות מחרוזות מבוא למדעי המחשב. כל הזכויות שמורות ©

27 מבוא למדעי המחשב. כל הזכויות שמורות ©
מערכים ומצביעים בשפת C שמו של מערך משרת ככתובת האיבר הראשון במערך. (מצביע לאיברו הראשון). מכאן אנו יכולים להפעיל עליו אריתמטיקה של מצביעים: כיצד ניגש לאיבר ה-i (salaries[i]) בעזרת מצביעים? double salaries[3]; &salaries[0] &salaries[1] &salaries[2] &salaries[i] salaries+0 salaries+1 salaries+2 salaries+i *(salaries+i) מבוא למדעי המחשב. כל הזכויות שמורות ©

28 מערכים ומצביעים – דוגמה לתמונת זיכרון
double salaries[3]; double *p = salaries; ++p; p = &salaries[2]; printf("%f", *p); printf("%f", *salaries); if(p == salaries+2) printf("%f", *(p-1)); salaries[] 1000 1008 1016 1032 3.5 19.4 25.1 p salaries salaries+2 salaries+1 מבוא למדעי המחשב. כל הזכויות שמורות ©

29 מערכים ומצביעים – דוגמה לתמונת זיכרון
double salaries[3]; double *p = salaries; ++p; p = &salaries[2]; printf("%f", *p); printf("%f", *salaries); if(p == salaries+2) printf("%f", *(p-1)); salaries[] 1000 1008 1016 1032 3.5 19.4 25.1 p salaries salaries+2 salaries+1 מבוא למדעי המחשב. כל הזכויות שמורות © 29 29

30 מערכים ומצביעים – אותה גברת? כמעט!
על אף הדמיון שראינו בין מערכים למצביעים, קיימים הבדלים חשובים: כאשר מגדירים מערך בגודל K מוקצה זיכרון המספיק ל-K אלמנטים. בעת הגדרת מצביע לא מוקצה זיכרון (מעבר לזה המשמש לאחסון המצביע). הפעלת sizeof: מערך: מספר הבתים שתופס כל המערך מצביע: מספר הבתים שתופס משתנה מסוג מצביע שמו של מערך הוא קבוע. לא ניתן לשנות את הכתובת אליה הוא מצביע. double salaries[3]; double *p; *salaries = 3.5; salaries[2] = 3.5; *p = 3.5; p[2] = 3.5; int a[5], b[5], *p; a = b; // Compilation error! p = a; // Fine! p is a pointer to a[0] מבוא למדעי המחשב. כל הזכויות שמורות ©

31 העברת מערכים כפרמטרים לפונקציה
משימה: לקרוא משכורות לתוך מערך, לחשב ממוצע ומספר משכורות מעל הממוצע. נרצה לחלק את המשימה לתתי-משימה (top-down design). בעיה: כיצד נעביר מערך לפונקציה? נניח שבידינו מערך שהוגדר כך: תזכורת: בשפת C, הביטוי salaries ערכו כתובת האיבר הראשון במערך. double salaries[EMPLOYEES_NUM]; מבוא למדעי המחשב. כל הזכויות שמורות ©

32 העברת מערכים כפרמטרים לפונקציה - המשך
נניח שבדינו פונקציה שקולטת נתונים לתוך מערך וחתימתה היא: בשני המקרים, שהם שקולים לחלוטין, הפונקציה מקבלת מצביע שניתן דרכו לגשת לכל איברי המערך. קריאה לפונקציה עם שם של מערך, תשלח את הכתובת של האיבר הראשון בו ולכן הפונקציה תעבוד עם המערך המקורי ולא עם העתק. מדוע נשלח גודל המערך? כי הגודל אינו ניתן לגילוי מהמצביע לבדו! void read_array(double a[], int n); void read_array(double *a, int n); שקולים double salaries[EMPLOYEES_NUM]; ... read_array(salaries, EMPLOYEES_NUM); מבוא למדעי המחשב. כל הזכויות שמורות ©

33 מבוא למדעי המחשב. כל הזכויות שמורות ©
תוכנייה מגבלות בתכנות בעזרת פונקציות מצביעים (Pointers) אופרטור הכתובת & אופרטור הכתובת * אריתמטיקה של מצביעים מערכים כמצביעים הקצאות דינמיות מחרוזות מערכים רב מימדיים מבוא למדעי המחשב. כל הזכויות שמורות ©

34 מבוא למדעי המחשב. כל הזכויות שמורות ©
תזכורת בהרצאה קודמת הכרנו את המצביעים (pointers) והקשר ביניהם ובין מערכים. בפרט, מערכים מצביעים הגדרה double a[20]; double *a,b; השלכות נקבע מקום ל-20·8Bytes מוקצה בזיכרון מקום לאחסון המערך לאחסון הכתובת. מיקום בזיכרון קבוע ונדרש לדעת אותו לא ידוע. אם ייקבע מראש. למשתנה יחיד (a=&b) מסוכן יהיה לעבור לשכניו - *(a+1). מבוא למדעי המחשב. כל הזכויות שמורות ©

35 מבוא למדעי המחשב. כל הזכויות שמורות ©
הקצאת זיכרון דינאמית תכניות רבות דורשות שטחי זיכרון שגודלם אינו ידוע בזמן הכתיבה. למשל, גודל המערך שנרצה להקצות תלוי בקלט. לפעמים נרצה להקצות בלוקים של זיכרון שאינם מערך. פונקצית הספרייה ()malloc ודומותיה המוכרזות ב- stdlib.h מאפשרות לבקש זיכרון נוסף ממערכת ההפעלה במהלך ריצת התכנית (הקצאה דינאמית). גודל הזיכרון (הרציף) המבוקש מועבר כפרמטר לפונקצית הספרייה. זיכרון זה אינו מוקצה על גבי מחסנית הקריאות ולכן אינו משוחרר אוטומטית ביציאה מהבלוק בו הוקצה. האחריות על שחרור הזיכרון על המתכנת. מבוא למדעי המחשב. כל הזכויות שמורות ©

36 הקצאה ע"י()malloc מבנה הקריאה ל-()malloc:
malloc() מחזירה את כתובת התחלת שטח הזיכרון שהוקצה, (או NULL, אם ההקצאה נכשלה). טיפוס ההחזרה של malloc() הינו void* - מצביע כללי. ניתן להתייחס לכתובת השמורה ב-p כאל כתובת מערך של n משתנים מטיפוס double. double *p; int n; ... // read n from user p = (double*) malloc(n * sizeof(double)); if (p == NULL) return 1; לא הכרחי – ההשמה תדאג להמרה מבוא למדעי המחשב. כל הזכויות שמורות ©

37 מבוא למדעי המחשב. כל הזכויות שמורות ©
שחרור הזיכרון בסיום השימוש בזיכרון שהוקצה, נשחררו באמצעות הפונקציה free(). הפקודה()free מקבלת כתובת תחילת שטח הזיכרון אשר הוקצה על ידי ()malloc (לא נדרש לספק את אורך הזכרון – הוא ידוע למערכת ההפעלה). חשוב להקפיד שכל שטח זיכרון המוקצה דינאמית במהלך התכנית, ישוחרר בהמשכה (מוקדם ככל האפשר). ... for(i = 0; i < n; i++) scanf(“%lf”,&p[i]); free(p); מבוא למדעי המחשב. כל הזכויות שמורות ©

38 דוגמה להקצאה דינאמית עם()malloc
נרצה לקלוט לתחילה את מספר העובדים בחברה. אח"כ נקלוט את המשכורות שלהם לתוך מערך ונבצע חישובים סטטיסטיים. #include<stdio.h> #include”stdlib.h” int main() { double *salaries; int n, i; scanf("%d", &n); salaries = (double*) malloc(n * sizeof(double)); if (salaries == NULL) return 1; for(i = 0; i < n; ++i) scanf("%lf", salaraies+i); // ...compute average, stdev, median, etc... free(salaries); ... מבוא למדעי המחשב. כל הזכויות שמורות ©

39 מבוא למדעי המחשב. כל הזכויות שמורות ©
תוכנייה מגבלות בתכנות בעזרת פונקציות מצביעים (Pointers) אופרטור הכתובת & אופרטור הכתובת * אריתמטיקה של מצביעים מערכים כמצביעים הקצאות דינמיות מחרוזות מבוא למדעי המחשב. כל הזכויות שמורות ©

40 מבוא למדעי המחשב. כל הזכויות שמורות ©
מחרוזות בשפת C אין טיפוס ייעודי לייצוג מחרוזות. מחרוזת מיוצגת פשוט על ידי רצף של תווים שבסופו תו מסיים '\0'. נשתמש במערך char[] לאחסון התווים. התו '\0'הוא תו מיוחד שערכו המספרי נקבע להיות 0 ב-ASCII. רצף תווים שאין בסופו תו זה לא נחשב מחרוזות! הנה תמונת הזיכרון עבור מחרוזת לדוגמה. מחרוזת זו מייצגת את המילה "walla!", היא מורכבת מ-7 תווים ולכן תופסת 7 בתים בזיכרון: 'w' 'a' 'l' '!' '\0' מבוא למדעי המחשב. כל הזכויות שמורות ©

41 מבוא למדעי המחשב. כל הזכויות שמורות ©
הגדרת מחרוזת הגדרת מחרוזת תיעשה באמצעות מערכים של char. דוגמה: הנה הגדרה של מערך בגודל 7 המאותחל עם רצף של 7 תווים שהאחרון שבהם הוא 0\, ולכן הוא יוצר מחרוזת באורך 6 תווים: שם המערךs משמש כמצביע לתחילת המחרוזת. שימו לב, אם היינו מגדירים את s להיות מערך בגודל 10 אזי אורך המחרוזת שבתוכו עדיין היה 6. קיצור שקול לשורה הנ"ל המותר ב- C: char s[] = {'w','a','l','l','a','!','\0'}; char s[] = "walla!"; מבוא למדעי המחשב. כל הזכויות שמורות ©

42 מבוא למדעי המחשב. כל הזכויות שמורות ©
גישה לאיברי מחרוזת ככל מערך, ניתן לגשת ישירות לאיבר כלשהו במחרוזת באמצעות האופרטורים [] או *. לדוגמה, אם נרצה לספור כמה רווחים יש במחרוזת s: ניתן גם לקדם את המצביע עצמו (בתנאי שאינו מסוג מערך): i = 0; counter = 0; while (s[i]) if(s[i++] == ' ') ++counter; i = 0; counter = 0; while (*(s+i)) if(*(s+i++) == ' ') ++counter; RUN while (*p) if(*(p++) == ' ') ++counter; מבוא למדעי המחשב. כל הזכויות שמורות ©

43 מבוא למדעי המחשב. כל הזכויות שמורות ©
עבודה עם מחרוזות קיימת ספריה בשם string.h המכילה מספר רב של פונקציות לטיפול במחרוזות. למשל: עוד על פונקציות אלו ואחרות בתרגול. לצורך קליטת מחרוזות והדפסתן באמצעות scanf ו-printf יש להשתמש בהנחיה %s. מחזירה את אורך המחרוזת. strlen(s) מעתיקה את תוכן המחרוזת s ל-d. strcpy(d,s) משרשרת את תוכן המחרוזת s לסוף המחרוזת d. strcat(d,s) מחזירה 0 אם שתי המחרוזות שוות. מספר חיובי אם הראשונה גדולה יותר (מבחינת סדר מילוני) ושלילי אחרת. strcmp(s1,s2) מבוא למדעי המחשב. כל הזכויות שמורות ©


Download ppt "הרצאה 6: כתובות ומצביעים הקצאה דינמית מחרוזות"

Similar presentations


Ads by Google