Presentation is loading. Please wait.

Presentation is loading. Please wait.

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

Similar presentations


Presentation on theme: "מבוא למדעי המחשב מצביעים."— Presentation transcript:

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

2 מצביעים (pointers) מצביע הוא משתנה המכיל כתובת של משתנה.
אם p הוא מצביע ל- c, אזי תוכן המשתנה p הוא הכתובת של c, כלומר, מצביע על התא ששמו הוא c. c p

3 מצביעים - תחביר האופרטור האונארי & מחזיר את הכתובת של האובייקט בזיכרון. אובייקט ← משתנה, תא של מערך. לא קבוע ולא ביטוי. האופרטור האונארי * (dereference) לוקח מצביע ומחזיר את הערך (תוכן התא) שעליו מצביע המצביע. דוגמא: char c; char *p; p=&c; שימו לב: ב- C אין טיפוס למצביעים. בדוגמא הנ"ל p הוא מצביע ל- char, הוא אינו char. char תופס בדיוק בית אחד בזיכרון. לא כך הדבר לגבי מצביע ל- char.

4 מצביעים - דוגמא int x= 1, y=2, *ip, z[10]; x ip y z 1 2 int pointer

5 מצביעים - דוגמא int x= 1, y=2, *ip, z[10]; : ip=&x; x ip y z 1 1 2 2
int pointer

6 מצביעים - דוגמא int x= 1, y=2, *ip, z[10]; : ip=&x; y=*ip; x ip y z 1

7 מצביעים - דוגמא int x= 1, y=2, *ip, z[10]; : ip=&x; y=*ip; *ip=0; x ip
1

8 מצביעים - דוגמא int x= 1, y=2, *ip, z[10]; : ip=&x; y=*ip; *ip=0;
1

9 מצביעים - דוגמאות int *ip; *ip הוא מטיפוס int (ip הוא מצביע ל- int)
double *fp; *fp הוא מטיפוס double (fp הוא מצביע ל- double) double func( char *); הצהרה על הפונקציה func, שמקבלת מצביע ל- char ומחזירה double.

10 אם ip ו- iq שניהם מצביעים ל- int
כל מצביע מצביע לערכים מטיפוס מסוים ולהם בלבד. פוינטר לערכים מטיפוס מסוים לא יכול להצביע על ערכים מטיפוס אחר. המקום שאותו מצביע תופס בזכרון הוא זהה לכל המצביעים והוא תלוי מערכת הפעלה. הוא לא תלוי בגודל הערך שאליו מצביע הפוינטר. אם ip מצביע ל- x, אזי *ip יכול להופיע בכל מקום שבו יכול להופיע x: *ip+=10; *ip=*ip*2; ++*ip; ip=iq אם ip ו- iq שניהם מצביעים ל- int

11 העברת פרמטרים בשפת C העברת פרמטרים לפונקציות היא by value בלבד.
פונקציה לא יכולה באופן ישיר להשפיע על ערכים בסביבה שקראה לה. תזכורת: /* swap: WRONG!!! */ void swap(int a, int b) { int temp; temp=a; a=b; b=temp; return; }

12 העברת פרמטרים באמצעות פוינטרים אפשר להעביר כתובות של משתנים מהסביבה הקוראת אל הפונקציה. /* swap: CORRECT */ void swap(int *px, int *py) { int temp; temp= *px; *px = *py; *py =temp; return; } סביבה קוראת: int a,b; a=7; b=3; swap(&a,&b); a b px py מפת הזיכרון: בפונקציה בסביבה הקוראת

13 פוינטרים ומערכים … בשפת C ישנו קשר הדוק בין מצביעים ומערכים:
כל פעולה שקשורה להשגת ערך ממערך ניתן לבצע באמצעות מצביעים. החיסרון: פחות ברור. ערכו של ביטוי מטיפוס מערך הוא כתובת האיבר הראשון ([0]) של המערך. דוגמא: int a[10]; int *pa; pa=&(a[0]); x=*pa; x=*(pa+2); 1 2 9 a: לאחר ההשמה ל- pa ול- a יש ערך זהה. לכן, ניתן לכתוב גם pa=a;

14 פוינטרים ומערכים באופן כללי: אם pa מצביע לתוך התא ה- i של a , אזי pa+j מצביע לתוך התא ה- i+j של a. לכן *(a+i) שקול ל- a[i] . כמו כן, &a[i] שקול ל- (a+i). פעולות כאלו על מצביעים אפשריות ללא תלות בטיפוס או בגודל של אברי המערך! i i+j a: pa: pa+j

15 מערכים ופוינטרים שימו לב: יש הבדל בין שם של מערך ובין מצביע:
מצביע הוא משתנה, לכן ניתן לבצע pa++; או pa=a; שם של מערך אינו משתנה, לכן a=pa; וגם a++; אינם חוקיים.

16 אריתמטיקה של פוינטרים אם p ו-q שני מצביעים המצביעים לאותו מערך ניתן להשוות ביניהם: < , <= , != , == , … p < q אם התא ש- p מצביע עליו נמצא לפני התא ש- q מצביע עליו. הוספה והחסרה של שלם: p+2 ← p + פעמיים הטיפוס ש- p מצביע עליו. כנ"ל לגבי p-1 , p++ וכו' השמה של מצביעים מאותו טיפוס: p=q רק אם p,q מצביעים לאותו טיפוס. אסור להציב int לתוך מצביע. הערך השלם היחיד שניתן להציב לתוך מצביע הוא אפס. משמעות האיפוס היא שהמצביע מאותחל, אך הוא אינו מצביע על שום תא בזיכרון. ניתן לרשום באופן שקול p=NULL;

17 העברת מערכים לפונקציות
בכותרת הפונקציה יש להצהיר על טיפוס המערך ושמו הפורמלי, ללא אורך. בסביבה הקוראת יצוין שם המערך. int mystrlen (char s[ ]) { int n; for (n=0; s[n]!=‘\0’; n++); return n; }

18 העברת מערכים לפונקציות
בכותרת הפונקציה יש להצהיר על טיפוס המערך ושמו הפורמלי, ללא אורך. בסביבה הקוראת יצוין שם המערך. הערך האקטואלי שיועבר לפונקציה הוא כתובת התחלת המערך. בתוך הפונקציה, הארגומנט הוא למעשה משתנה פנימי מאותחל, ולפיכך ניתן להתייחס אליו כאל מצביע. int mystrlen (char s[ ]) { int n; for (n=0; *s!=‘\0’; s++) n++; return n; } s מועבר by value ולכן ניתן להגדיל אותו ללא השפעה על הסביבה הקוראת!

19 העברת מערכים לפונקציות
#include<stdio.h> int mystrlen (char s[ ]) { int n; for (n=0; *s!=‘\0’; s++) n++; return n; } int main() char array[10]=“hello”; char *ptr; printf(“%d\n”, mystrlen(“hello world”(); printf(“%d\n”, mystrlen(array)(; ptr=array; ptr[0]=‘a’; ptr[1]=‘b’; ptr[2]=‘c’; ptr[3]=‘\0’; printf(“%d\n”, mystrlen(ptr)(; return 0; ניתן לכתוב באופן שקול: int mystrlen (char *s)

20 העברת מערכים לפונקציות
כשפונקציה מקבלת מערך כפרמטר היא יכולה להתייחס אליו כאל מערך או כאל מצביע או בשני האופנים. ניתן להעביר חלק ממערך כפרמטר לפונקציה: strlen(&array[2]) strlen(array+2)

21 מערכים ↔ מצביעים int main() { char str[]=“hello"; char *ptr="hello";
printf("%s\n",str); printf("%s\n",ptr); ptr++; strcpy(str,"vv"); return 0; } מוקצה מקום למצביע והוא מאותחל להצביע אל קבוע. ניתן לשנות את המצביע אך לא את הקבוע. לא ניתן לבצע str++; לא ניתן לבצע strcpy(ptr,"vv");

22 strcpy – גרסאות שונות לאותה פונקציה
/* strcpy: copy a string from t to s */ void strcpy(char *s, char *t) { int i=0; while ((s[i] = t[i]) != '\0') i++; } האלגוריתם הנאיבי void strcpy(char *s, char *t) { while ((*s = *t) != '\0') { s++; t++; } מצביעים במקום מערכים

23 strcpy – גרסאות שונות לאותה פונקציה
void strcpy(char *s, char *t) { while ((*s = *t) != '\0') { s++; t++; } מצביעים במקום מערכים void strcpy(char *s, char *t) { while ((*s++ = *t++) != '\0') ; } קיצור כתיבה

24 strcpy – גרסאות שונות לאותה פונקציה
void strcpy(char *s, char *t) { while ((*s++ = *t++) != '\0') ; } קיצור כתיבה void strcpy(char *s, char *t) { while (*s++ = *t++) ; } ההשוואה ל- ‘\0’ מיותרת

25 מערכים דו-ממדיים – דוגמא (1)
נרצה לכתוב תכנית המבצעת המרה מיום בחודש ליום בשנה ולהיפך. למשל: ה- 1 במרץ הוא היום ה- 60 בשנה רגילה והיום ה- 61 בשנה מעוברת. לכן, עבור הקלט: יום 60 בשנת 2005 נקבל את הפלט: 1 במרץ עבור הקלט: יום 60 בשנת 2000 נקבל את הפלט: 29 בפברואר (*) תזכורת: שנה היא מעוברת אם היא מתחלקת ב- 4 אך לא ב- 100, או לחלופין אם היא מתחלקת ב- 400.

26 מערכים דו-ממדיים – דוגמא (1)
/* day_of_year.c -- K&R page 111 */ #include <stdio.h> int daytable[2][13] = { {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} }; /* day_of_year: set day of year from month and day */ int day_of_year (int year, int month, int day) { int i, leap; leap = (((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0); for (i=1; i<month; i++) day += daytable[leap][i]; return day; }

27 מערכים דו-ממדיים – דוגמא (1)
#include <stdio.h> int daytable[2][13] = { {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} }; /* month_day: set month, day from day of year */ void month_day (int year, int yearday) { int i, leap; leap = (((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0); for (i=1; yearday>daytable[leap][i]; i++) yearday -= daytable[leap][i]; return ??? }

28 מערכים דו-ממדיים – דוגמא (1)
#include <stdio.h> int daytable[2][13] = { {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} }; /* month_day: set month, day from day of year */ void month_day(int year, int yearday, int *pmonth, int *pday) { int i, leap; leap = (((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0); for (i=1; yearday>daytable[leap][i]; i++) yearday -= daytable[leap][i]; *pmonth=i; *pday=yearday; return; }

29 חיבור מטריצות - תזכורת #include <stdio.h>
#include <stdlib.h> #define SIZE 10 #define FALSE 0 #define TRUE 1 void ReadMatrix (int a[SIZE][SIZE], int row, int col); void CheckSize (int size); int add (int a[SIZE][SIZE], int row1, int col1, int b[SIZE][SIZE], int row2, int col2, int c[SIZE][SIZE]); void PrintMatrix (int a[SIZE][SIZE], int row, int col);

30 חיבור מטריצות - תזכורת int main() {
int a[SIZE][SIZE], b[SIZE][SIZE], c[SIZE][SIZE]; int row1, row2, col1, col2; printf("Enter the number of rows and columns of the first matrix and the second matrix\n"); if (scanf("%d%d%d%d",&row1, &col1, &row2, &col2)!=4){ printf("Input error\n"); return 1; } CheckSize(row1); CheckSize(col1); CheckSize(row2); CheckSize(col2); ReadMatrix(a,row1,col1); ReadMatrix(b,row2,col2); if (add(a,row1,col1,b,row2,col2,c)==FALSE) { printf("Matrices cannot be added\n"); return 0; else{ printf("The result matrix:\n"); PrintMatrix(c,row1,col1);

31 חיבור מטריצות - שיפור int main() {
int a[SIZE][SIZE], b[SIZE][SIZE], c[SIZE][SIZE]; int row1, row2, col1, col2; ReadMatrix(a, &row1, &col1); ReadMatrix(b, &row2, &col2); if (add(a,row1,col1,b,row2,col2,c)==FALSE) { printf("Matrices cannot be added\n"); return 0; } else{ printf("The result matrix:\n"); PrintMatrix(c,row1,col1);

32 חיבור מטריצות - שיפור #include <stdio.h>
#include <stdlib.h> #define SIZE 10 #define FALSE 0 #define TRUE 1 void ReadMatrix (int a[SIZE][SIZE], int *row, int *col); void CheckSize (int size); int add (int a[SIZE][SIZE], int row1, int col1, int b[SIZE][SIZE], int row2, int col2, int c[SIZE][SIZE]); void PrintMatrix (int a[SIZE][SIZE], int row, int col);

33 חיבור מטריצות - שיפור /* read a matrix*/
void ReadMatrix (int a[SIZE][SIZE], int *row, int *col) { int i,j; printf("Please enter the number of rows and columns:\n"); if (scanf("%d%d",row,col)!=2){ printf("Input error"); exit (1); } CheckSize (*row); CheckSize (*col); printf("Please enter matrix [%d][%d]\n",*row,*col); for (i=0; i < *row; i++) { for (j=0; j < *col; j++) { if(scanf("%d", &(a[i][j]))!=1){ PrintMatrix(a, *row, *col); return;


Download ppt "מבוא למדעי המחשב מצביעים."

Similar presentations


Ads by Google