void*, pointer to functions, variadic functions קרן כליף
TRANSCRIPT
void*, pointer to functions, variadic functions
כליף קרן
© Keren Kalif
2
: נלמד זו ביחידה מצביעים תזכורת מצביעים בין המרות המצביעvoid* לפונקציה מצביע מהו לפונקציה במצביע שימושים הפונקציהatexit לפונקציות מצביעים של מערך עם לפונקציה מצביע *voidשילוב הפונקציותqsort - bsearchו Enum מהיVariadic Function - ב va_list, va_start, va_arg, va_endהשימוש
© Keren Kalif
3
מצביעים תזכורתvoid main()}
int x = 4;int* pX = &x;int arr[] = {1,2,3};int* pArr = arr+1;int* pointersArr[] = {&x, pX, arr};int** p2p = &pointersArr[1];
{
1000 ??? int: x
1004 ??? int*: pX
1008 ??? int[]: arr
1012 ???1016 ???1020 ??? int*: pArr
1024 ??? int*: pointersArr
1028 ???1032 ???1036 ??? int**: p2p
1000 4 int: x
1004 ??? int*: pX
1008 ??? int[]: arr
1012 ???1016 ???1020 ??? int*: pArr
1024 ??? int*: pointersArr
1028 ???1032 ???1036 ??? int**: p2p
1000 4 int: x
1004 1000 int*: pX
1008 ??? int[]: arr
1012 ???1016 ???1020 ??? int*: pArr
1024 ??? int*: pointersArr
1028 ???1032 ???1036 ??? int**: p2p
1000 4 int: x
1004 1000 int*: pX
1008 1 int[]: arr
1012 21016 31020 ??? int*: pArr
1024 ??? int*: pointersArr
1028 ???1032 ???1036 ??? int**: p2p
1000 4 int: x
1004 1000 int*: pX
1008 1 int[]: arr
1012 21016 31020 1012 int*: pArr
1024 ??? int*: pointersArr
1028 ???1032 ???1036 ??? int**: p2p
1000 4 int: x
1004 1000 int*: pX
1008 1 int[]: arr
1012 21016 31020 1012 int*: pArr
1024 1000 int*: pointersArr
1028 10001032 10081036 ??? int**: p2p
1000 4 int: x
1004 1000 int*: pX
1008 1 int[]: arr
1012 21016 31020 1012 int*: pArr
1024 1000 int*: pointersArr
1028 10001032 10081036 1028 int**: p2p
© Keren Kalif
4
ומטריצות: מצביעים של אריתמטיקה תזכורת
(arr+i) ≡ &arr[i]*(arr+i) ≡ arr[i]
mat[ i ][ j ] = *(*(mat+i)+j)) במטריצה, כלומר כתובת ההתחלה של iהתוכן של השורה ה-
iהמערך ה-
- ה , iהאיבר השורה כלומר במטריצהiה-
© Keren Kalif
5
במטריצה: בודד לתא מצביע תזכורת1. void main()2. }3. int matrix[][3]={ {1,2,3}, {4,5,6} };4. 5. printf("%d\n", matrix[1][1]);6. printf("%d\n", (*(matrix+1))[1]);7. printf("%d\n", *(matrix[1]+1));8. printf("%d\n", *(*(matrix+1)+1));9. {
1000 1 int[2][3]: matrix
1004 2
1008 3
1012 4
1016 5
1020 6
[ - ה המקום בין במערך[ j[]iההתאמה - היא - מימדי החד למערך מימדי הדו
COLUMNS * i + j :למשלmatrix[1][1] נמצא
4 = 1+1*3במקום
© Keren Kalif
6
*voidמהו מטיפוס משתנה להגדיר * voidניתן
מכל משתנה של כתובת להכיל יכול כזה משתנהטיפוס
- ב פונקציות* voidנשתמש לכתוב נרצה כאשרהנתונים, לטיפוס קשר ללא פעולה המבצעות כלליות
:הפונקציה swapלמשל
© Keren Kalif
7
הפונקציה: swapדוגמא בין להחליף :2כדי הבאה הפונקציה את כותבים היינו שלמים מספרים
void swapInt(int* a, int* b){
int temp = *a;*a = *b;*b = temp
} בין להחליף :2כדי הבאה הפונקציה את כותבים היינו תווים
void swapChar(char* a, char* b){
char temp = *a;*a = *b;*b = temp
}
הטיפוס הוא במימוש היחידי השינוי.השונה
נרצה הקוד את לשכפל במקום לכןשתדע אחת כללית פונקציה לכתוב
טיפוס מאותו משתנים שני בין .להחליף
© Keren Kalif
8
הפונקציה: swap (2)דוגמא של הכללי גודל 2יקבל swapהמימוש ואת כתובות
למשל ) להחליף רוצים אותו עבור int, 1עבור 4המשתנהchar)' וכו
כלשהו משתנה של ההתחלה כתובת הינה כתובת כלבזכרון
המשתנה בין הסדר לפי הבתים כל את תחליף הפונקציהלשני הראשון
:התופס משתנה עבור , 4כלומר את תחליף הפונקציה 4בתיםהמשתנה כתובת מתחילת שברצף הבתים
1000 001001111001 100001101002 000011101003 00000000
2000 101010102001 101010102002 000011102003 00000000
© Keren Kalif
9
- ל גנרי swapמימוש
1. #include <stdio.h>2. 3. #define PRINT_VALUE(x, modifier) \4. printf(#x " = %" #modifier "\n", x);5. 6. void swap(void* a, void* b, int typeSize)7. }
8. int i;9. char temp;10. char* first = (char*)a;11. char* second = (char*)b;12. 13. for (i=0 ; i < typeSize ; i++)14. }15. temp = *(first+i);16. *(first+i) = *(second+i);17. *(second+i) = temp;18. {19. }
20. void main()21. }22. int num1=3, num2=9;23. char ch1 = 'f', ch2 = 'k';24. 25. printf("Before swap:\n");26. PRINT_VALUE(num1, d);27. PRINT_VALUE(num2, d);28. PRINT_VALUE(ch1, c);29. PRINT_VALUE(ch2, c);30. 31. swap(&num1, &num2, sizeof(int));32. swap(&ch1, &ch2, sizeof(char));33. 34. printf("\nAfter swap:\n");35. PRINT_VALUE(num1, d);36. PRINT_VALUE(num2, d);37. PRINT_VALUE(ch1, c);38. PRINT_VALUE(ch2, c);39. {
מקבלת כתובות 2הפונקציה )! גודלו) ואת טיפוס ציון בלישנשלחו האיברים טיפוס של
בפועל
© Keren Kalif
10
- ל גנרי הסברים: swapמימוש הוא לעבוד ניתן שאיתו קטן הכי והטיפוס , charמאחר
עושה לטיפוס* voidלפרמטרי castingהפונקציה שקיבלהchar*
עבור :int 2למשל .1ים' void swap(void* a, void* b, int typeSize)2. }3. int i;4. char temp;5. char* first = (char*)a;6. char* second = (char*)b;7. 8. for ( ; ; )9. }10. temp = *(first+i);11. *(first+i) = *(second+i);12. *(second+i) = temp;13. {14.}
1000 00100111
1001 10000110
1002 00001110
1003 00000000
2000 10101010
2001 10101010
2002 00001110
2003 00000000
3000 1000 void*: a
3004 2000 void*: b
3008 4 int: typeSize
3012 ??? int: i
3016 ??? char: temp
3017 ??? char*: first
3021 ??? char*: second
הפונקציה של swapהזכרון
3000 1000 void*: a
3004 2000 void*: b
3008 4 int: typeSize
3012 ??? int: i
3016 ??? char: temp
3017 1000 char*: first
3021 ??? char*: second
3000 1000 void*: a
3004 2000 void*: b
3008 4 int: typeSize
3012 ??? int: i
3016 ??? char: temp
3017 1000 char*: first
3021 2000 char*: second
i < typeSize i++i=0
3000 1000 void*: a
3004 2000 void*: b
3008 4 int: typeSize
3012 0 int: i
3016 ??? char: temp
3017 1000 char*: first
3021 2000 char*: second
3000 1000 void*: a
3004 2000 void*: b
3008 4 int: typeSize
3012 0 int: i
3016 00100111 char: temp
3017 1000 char*: first
3021 2000 char*: second
3000 1000 void*: a
3004 2000 void*: b
3008 4 int: typeSize
3012 1 int: i
3016 00100111 char: temp
3017 1000 char*: first
3021 2000 char*: second
3000 1000 void*: a
3004 2000 void*: b
3008 4 int: typeSize
3012 1 int: i
3016 10000110 char: temp
3017 1000 char*: first
3021 2000 char*: second
3000 1000 void*: a
3004 2000 void*: b
3008 4 int: typeSize
3012 2 int: i
3016 10000110 char: temp
3017 1000 char*: first
3021 2000 char*: second
3000 1000 void*: a
3004 2000 void*: b
3008 4 int: typeSize
3012 2 int: i
3016 00001110 char: temp
3017 1000 char*: first
3021 2000 char*: second
3000 1000 void*: a
3004 2000 void*: b
3008 4 int: typeSize
3012 3 int: i
3016 00001110 char: temp
3017 1000 char*: first
3021 2000 char*: second
3000 1000 void*: a
3004 2000 void*: b
3008 4 int: typeSize
3012 3 int: i
3016 00000000 char: temp
3017 1000 char*: first
3021 2000 char*: second
3000 1000 void*: a
3004 2000 void*: b
3008 4 int: typeSize
3012 4 int: i
3016 00000000 char: temp
3017 1000 char*: first
3021 2000 char*: second
- ו - firstמאחר הם secondו גדל* charמטיפוס שלהם הקידום
1ב-
00100111
10000110
00001110
00000000
10101010
10101010
00001110
00000000
© Keren Kalif
11
memcpyהפונקציה
void* memcpy(void* destination,
const void* source,
int num );
כלשהי כתובת את destinationמקבלת לתוכה ומעתיקהמכתובת החל שנמצא בתים numבאורך sourceהתוכן
את destinationמחזירהsource - כ אותה constמועברת משנים לא כי : מערכים העתקת אפשרי שימוש
© Keren Kalif
12
דוגמא – memcpyהפונקציה 1. void printArray(int arr[], int size)2. }3. int i;4. for (i=0 ; i < size ; i++)5. printf("%d ", arr[i]);6. printf("\n");7. {8. 9. void main()10. }11. int arr1[] = {5,6,3}, arr2[3];12. 13. printf("Array Before:\n");14. printArray(arr2, 3);15. 16. memcpy(arr2, arr1, 3*sizeof(int));17. printf("Array After:\n");18. printArray(arr2, 3);19. {
© Keren Kalif
13
- ב - memcpyשימוש swapב
1. void genericSwap(void* a, void* b, int typeSize)
2. {
3. char *tmp = (char*)malloc(typeSize);
4.
5. memcpy(tmp, a, typeSize);
6. memcpy(a, b, typeSize);
7. memcpy(b, tmp, typeSize);
8.
9. free(tmp);
10. }
© Keren Kalif
14
משתנה - של הבינארי ערכו להדפסת גנרי מימושפלט
© Keren Kalif
15
משתנה של הבינארי ערכו להדפסת גנרי מימוש1. void printCharAsBinary(char ch)2. }3. …4. {
5. void printInBinary(void* val, 6. int varSize)7. }8. char* p = (char*)val + varSize - 1;9. while(p >= (char*)val)10. }11. printCharAsBinary(*p);12. printf(" ");13. p--;14. {15. printf("\n");16. {
23. void main()24. }25. unsigned short int num1 = 2345; 26. // in binary: 1001 0010100127. unsigned int num2 = 9999999; 28. // in binary: 10011000 10010110 0111111129. char ch = 'a'; // in binary: 0110000130. 31. printf("%d in binary is:\n", num1);32. printInBinary(&num1, sizeof(num1));33.
34. printf("\n\n%d in binary is:\n", num2);35. printInBinary(&num2, sizeof(num2));36. 37. printf("\n\n'%c' in binary is:\n", ch);38. printInBinary(&ch, sizeof(ch));39.
40. printf("\n\n");41. {
© Keren Kalif
16
- ל גנרי הסברים: printInBinaryמימוש בכתובת - 1000התוכן ה כתובת LSBהוא 1003והתוכן
- ה MSBהוא להתחיל נרצה בבינארית המספר את נדפיס כאשר
- מה המסך על - MSBלהדפיס LSBל 1000 00100111
1001 10000110
1002 00001110
1003 00000000
הפונקציה של הזכרוןprintInBinary
3000 1000 void*: val
3004 4 int: varSize
3008 ??? char*: p
3000 1000 void*: val
3004 4 int: varSize
3008 1003 char*: p
00000000
3000 1000 void*: val
3004 4 int: varSize
3008 1002 char*: p
00001110
3000 1000 void*: val
3004 4 int: varSize
3008 1001 char*: p
10000110
3000 1000 void*: val
3004 4 int: varSize
3008 1000 char*: p
00100111
3000 1000 void*: val
3004 4 int: varSize
3008 999 char*: p
1. void printInBinary(void* val, int varSize)2. }3. char* p = (char*)val + varSize - 1;4. while(p >= (char*)val)5. }6. printCharAsBinary(*p);7. printf(" ");8. p--;9. {10. printf("\n");11. {
לפונקציות מצביעים
© Keren Kalif
18
מוטיבציה – לפונקציה מצביע היינו פעם בכל שונה מיון קריטריון לפי מערך למיין כדי
מיון סוג כל עבור נפרדת מיון פונקצית לכתוב צריכים ,או המחרוזת אורך לפי מחרוזות מערך מיון למשל
לקסיקוגרפית , , עליה ההשוואה פעולת רק תמיד זהה המיון אלגוריתם
, פעם בכל שונה המיון מתבסס משכפול להימנע רוצים היינו
הקוד..
© Keren Kalif
19
מחרוזות: מיון .1דוגמא #define MAX_LEN 302. 3. void swapStrings(char* str1, char* str2);4. void sortByLen(char arr[][MAX_LEN], int size);5. void sortLexicographic(char arr[][MAX_LEN], int size);6. void printWords(char words[][MAX_LEN], int size);7. void main()8. }9. char words[][MAX_LEN] = {"hello", "boker tov", "apple", "yes", "car"};10. int numOfWords = sizeof(words)/sizeof(words[0]);11. 12. printf("The words:\n");13. printWords(words, numOfWords);14. 15. printf("The words after sort by len:\n");16. sortByLen(words, numOfWords);17. printWords(words, numOfWords);18. 19. printf("The words after sort lexicographic:\n");20. sortLexicographic(words, numOfWords);21. printWords(words, numOfWords);22. {
© Keren Kalif
20
מחרוזות: ) מיון (2דוגמא
void swapStrings(char* str1, char* str2)}
char temp[MAX_LEN];strcpy(temp, str1);strcpy(str1, str2);strcpy(str2, temp);
{
void sortByLen(char arr[][MAX_LEN], int lines)}
int i, j;for (i=lines-1 ; i > 0 ; i--)} for (j=0 ; j < i ; j++)
if (strlen(arr[j]) > strlen(arr[j+1])) swapStrings(arr[j], arr[j+1]);{
{
void printWords(char words[][MAX_LEN], int lines)}
int i;for (i=0 ; i < lines ; i++)
printf("%s\n", words[i]); {
void sortLexicographic(char arr[][MAX_LEN], int lines)}
int i, j;for (i=lines-1 ; i > 0 ; i--)}
for (j=0 ; j < i ; j++) if (strcmp(arr[j], arr[j+1]) > 0)
swapStrings(arr[j], arr[j+1]);{
{
, זהות המיון פונקציותההשוואה לשורת !פרט
© Keren Kalif
21
לפונקציה מצביע פונקצית לכתוב רוצים , sortהיינו כפרמטר שתקבל כללית
ההשוואה פעולת את לבצע שידע משתנה בשפת להגדיר מצביע " Cניתן הנקרא חדש טיפוס
פונקציה", של חתימה והוא לפונקציה חתימה עם פונקציה כל להיות יכול זה מטיפוס משתנה
אליו זהה , ובתור לפונקציה כפרמטר זה טיפוס להעביר כעת ניתן
המבוקשת הפונקציה שם תשלח הארגומנט
© Keren Kalif
22
כללית sortWordsפונקצית
void sortWords(char arr[][MAX_LEN], int lines, int (*compare)(char*, char*))}
int i, j;for (i=lines-1 ; i > 0 ; i++)}
for (j=0 ; j < i ; j++) if (compare(arr[j], arr[j+1]) > 0)
swapStrings(arr[j], arr[j+1]);{
{
של חתימה שהוא פרמטרפונקציה.
המחזירה פונקציה זה במקרהint 2ומקבלת. מחרוזות
. הפונקציה הפעלתהפונקציה זה במקרה
2ומקבלת intמחזירה מחרוזות.
© Keren Kalif
23
בפונקצית שימושsortWords כללית
1. int compareByLen(char* str1, char* str2)2. {3. int size1 = strlen(str1), size2 = strlen(str2);4. if (size1 < size2) return -1;5. else if (size1 > size2) return 1;6. else return 0;7. {8. 9. void main()10. }11. char words[][MAX_LEN] = {"hello", "boker tov", "apple", "yes", "car"};12. int numOfWords = sizeof(words)/sizeof(words[0]);13. 14. printf("The words:\n");15. printWords(words, numOfWords);16. 17. printf("The words after sort by len:\n");18. sortWords(words, numOfWords, compareByLen);19. printWords(words, numOfWords);20. 21. printf("The words after sort lexicographic:\n");22. sortWords(words, numOfWords, strcmp);23. printWords(words, numOfWords);24. {
לפונקציה קריאהsortWords כאשר
הוא השלישי הארגומנטהמחזירה פונקציה של שם
int 2ומקבלת. מחרוזות
לפונקציה קריאהsortWords כאשר
הוא השלישי הארגומנטפונקציה של שם
2ומקבלת intהמחזירה מחרוזות.
© Keren Kalif
24
filterהפונקציה 1. #include <stdio.h>2. 3. void filter(int arr[], int size, int (*foo)(int))4. }5. int i;6. for (i=0 ; i < size ; i++)7. if (foo(arr[i]) == 1)8. printf("%d ", arr[i]);9. {10. 11. int isOdd(int x) {return x%2 != 0;}12. int isPositive(int x) {return x > 0;}13. 14. void main()15. }16. int arr[] = {-3, 6, -2, 8, 1, -4};17. int size = sizeof(arr)/sizeof(arr[0]);18. 19. printf("All odd numbers are: \n");20. filter(arr, size, isOdd);21. 22. printf(“\nAll positive numbers are:\n ");23. filter(arr, size, isPositive);24. }
כפרמטר filterהפונקציה תקבלהמקבלת פונקציה של intשם
זו, intומחזירה פונקציה ותפעילהמערך מאיברי אחד כל על
© Keren Kalif
25
atexitהפונקציה ברגע תופעל אשר פונקציה התוכנית בתחילת להגדיר ניתן
תקין באופן תסתיים שהתוכנית , קבצים, סגירת כמו היציאה עם משאבים לנקות כדי למשל
מרוכז באופן לפונציה נקרא זאת לעשות כפרמטר atexitכדי המקבלת
המקבלת לפונקציה voidומחזירה voidפוינטר הפונקציה , atexitאם כל אחת מפעם יותר נקראה
אחרי אחת יופעלו כפרמטר אליה שהועברו הפונקציותהקריאה, לסדר הפוך בסדר השניה
- ב להשתמש לעשות atexitכדי - includeצריך stdlib.hל
© Keren Kalif
26
atexit - דוגמא#include <stdio.h>#include <stdlib.h>
void printBye() { printf("Bye!\n");}
void main()}
printf("--> Enter main\n");atexit(printBye);printf("<-- Exit main\n");
{
© Keren Kalif
27
atexit( – 2דוגמא)#include <stdio.h>#include <stdlib.h>
void printBye() { printf("Bye!\n");}
void printHello() { printf(“Hello!\n");}
void main()}
printf("--> Enter main\n");atexit(printBye);atexit(printHello);printf("<-- Exit main\n");
{
© Keren Kalif
28
דוגמא - לפונקציה מצביעים של מערך#include <stdio.h>
void printHello() {printf("Hello!\n");}void printGood() {printf("Good!\n");}void printBye() {printf("Bye!\n");}
void main()}
int i, size;void (*print[])() = {printHello, printGood, printBye};
size = sizeof(print)/sizeof(print[0]);for (i=0 ; i < size ; i++)
print[i]();{
מצביעים של מערך הגדרתהמקבלות voidלפונקציות
voidומחזירות
© Keren Kalif
29
ערך ומחזירה ערך המקבלת לפונקציה מצביע1. #include <stdio.h>2. 3. int add(int num1, int num2) {return num1 + num2;}4. int sub(int num1, int num2) {return num1 - num2;}5. 6. void main()7. }8. int (*calc)(int, int) = NULL;9. int num1, num2, operation;10. 11. printf("Please enter 2 numbers: ");12. scanf("%d%d", &num1, &num2);13. printf("Press 1 to add them, 2 for sub: ");14. scanf("%d", &operation);15. 16. switch(operation)17. }18. case 1: calc = add; break;19. case 2: calc = sub; break;20. default: printf("Invalid choice!\n"); break;21. {22.
23. if (calc != NULL) 24. printf("The result is %d\n", calc(num1, num2));25. }
© Keren Kalif
30
כארגומנט לפונקציה מצביעים של מערך שליחתלפונקציה
1. #include <stdio.h>2. 3. void printAllStyles(void (*print[])(char*), int size, char* str)4. {5. int i;6. for (i=0 ; i < size ; i++)7. print[i](str);8. {9. 10. void printSimple(char* str) {printf("%s\n", str);}11. void printFancy(char* str) {printf("*** %s ***\n", str);}12. 13. void main()14. }15. void (*print[])(char*) = {printSimple, printFancy};16. int size = sizeof(print)/sizeof(print[0]);17. 18. printAllStyles(print, size, "Hi!");19. {
© Keren Kalif
31
בשילוב לפונקציה *voidמצביע הפונקציה את לכתוב ניתן כי באופן swapWordsראינו
שונה יהיה המיון קריטריון פעם שבכל כך כללי מערך לקבל תוכל פעם שבכל כך זו פונקציה להרחיב ניתן
" , שונה קריטריון י עפ ותמיין שונה מטיפוס - ב השימוש את נשלב כך ובמצביעים* voidלשם
לפונקציות
© Keren Kalif
32
סוג מכל מערך להדפסת כללית פונקציה
void printArr(void* arr, int size, int typeSize, void (*print)(void*))
}int i;for (i=0 ; i < size ; i++)
print((char*)arr+i*typeSize);{
של התחלה כתובתכלשהו מטיפוס מערך
כמות האיברים במערך
איבר כל של גודלגודל ) במערך
הטיפוס(
היודעת לפונקציה מצביעאיבר של כתובת לקבל
אותו ולהדפיס
לשלוח צריך איטרציה בכלכתובת את ההדפסה לפונקצית
רוצים אותו האיבר של ההתחלהלהדפיס
© Keren Kalif
33
סוג מכל מערך להדפסת כללית בפונקציה שימוש1. void printArr(void* arr, int size, int typeSize, void (*print)(void*)) {…}2. 3. void printInt(void* num)4. }5. int* n = (int*)num;6. printf("%d ", *n);7. {8. 9. void printPerson(void* person)10. }11. Person* p = (Person*)person;12. printf("Id: %d\tName: %s\n", p->id, p->name);13. {14. 15. void main()16. }17. int numbers[SIZE] = {4,2,-3, 1};18. Person persons[SIZE] = { {333, "gogo"}, {111, "yoyo"}, 19. {444, "momo"}, {222, "koko"} };20. 21. printf("The numbers are: ");22. printArr(numbers, SIZE, sizeof(int), printInt);23. printf("\n\nThe persons are:\n");24. printArr(persons, SIZE, sizeof(Person), printPerson);25. }
, וממירה כללית כתובת המקבלת פונקציהשל התחלה לכתובת בזיכרון intאותה
אותו , ומדפיסה אותה וממירה כללית כתובת המקבלת פונקציהשל התחלה ומדפיסה Personלכתובת בזיכרון
אותו
© Keren Kalif
34
כללית sortפונקצית void swap(void* a, void* b, int typeSize)}
int i;char temp;char* first = (char*)a;char* second = (char*)b;
for (i=0 ; i < typeSize ; i++){
temp = *(first+i);*(first+i) = *(second+i);*(second+i) = temp;
{{
void sort(void* arr, int size, int typeSize, int (*compare)(void*, void*))}
int i, j;
for (i=size-1 ; i > 0 ; i--)for (j=0 ; j < i ; j++) if (compare((char*)arr+j*typeSize, (char*)arr+(j+1)*typeSize) > 0)
swap((char*)arr+j*typeSize, (char*)arr+(j+1)*typeSize, typeSize);{
היודעת לפונקציה מצביעשל כתובות איברים 2לקבל
. הפונקציה בינהם ולהשוותתחזיר:
שווים 10. אם
מהשני- 21. קטן הראשון אם
מהשני 31. גדול הראשון אם
לשלוח צריך איטרציה בכלכתובות את ההשוואה לפונקצית
אותם האיברים של ההתחלהלהשוות רוצים
© Keren Kalif
35
בפונקצית כללית sortשימוש1. #include <stdio.h>2. 3. #define SIZE 44. 5. typedef struct person6. }7. int id;8. char name[20];9. }Person;10. 11. void printArr(void* arr, int size, int typeSize, void (*print)(void*)) { … }12. void printInt(void* num) { … }13. void printPerson(void* person) { … }14. void swap(void* a, void* b, int typeSize) { … }15. void sort(void* arr, int size, int typeSize, int (*compare)(void*, void*)) { … }
© Keren Kalif
36
בפונקצית (2כללית )sortשימוש16. int compareInt(void* num1, void* num2)17. }18. int n1 = *((int*)num1);19. int n2 = *((int*)num2);20. if (n1 < n2) return -1;21. else if (n1 > n2) return 1;22. else return 0;23. {24. 25. int comparePersonById(void* person1, void* person2)26. }27. Person* p1 = (Person*)person1;28. Person* p2 = (Person*)person2;29. if (p1->id < p2->id) return -1;30. else if (p1->id > p2->id) return 1;31. else return 0;32. }33. 34. int comparePersonByName(void* person1, void* person2)35. }36. Person* p1 = (Person*)person1;37. Person* p2 = (Person*)person2;38. return strcmp(p1->name, p2->name);39. {
עם הללו הפונקציות כל , שיתאימו כדי זהה חתימההפרמטר מטיפוס להיותלפונקצית חתימה שהוא
ההשוואה
© Keren Kalif
37
בפונקצית (3כללית )sortשימוש
40. void main()41. }42. int numbers[SIZE] = {4,2,-3, 1};43. Person persons[SIZE] = { {333, "gogo"}, {111, "yoyo"}, 44. {444, "momo"}, {222, "koko"} };45.
46. printf("The sorted numbers are: ");47. sort(numbers, SIZE, sizeof(int), compareInt);48. printArr(numbers, SIZE, sizeof(int), printInt);49. 50. printf("\nThe persons by ID are:\n");51. sort(persons, SIZE, sizeof(Person), comparePersonById);52. printArr(persons, SIZE, sizeof(Person), printPerson);53. 54. printf("\nThe persons by names are:\n");55. sort(persons, SIZE, sizeof(Person), comparePersonByName);56. printArr(persons, SIZE, sizeof(Person), printPerson);57. {
© Keren Kalif
38
qsortהפונקציה - ב הקיימת " stdlib.hפונקציה י עפ מיון ומבצעת
: מסוים קריטריוןvoid qsort ( void * base,
size_t num,
size_t size,
int ( * comparator ) ( const void *, const void * ) );
// כתובת ההתחלה של המערך
// מספר האיברים במערך
// גודלו של כל איבר במערך
משתנים ומחזירה את יחס ההשוואה 2מצביע לפונקציה המקבלת כתובות של // בינהם
© Keren Kalif
39
- ב שימוש qsort (1)דוגמאת1. #include <stdio.h>2. 3. void printArr(int arr[], int size) {…}4. int compareInt(void* a, void* b)5. }6. int num1 = *(int*)a;7. int num2 = *(int*)b;8. 9. if (num1 < num2) return -1;10. else if (num1 > num2) return 1;11. else return 0;12. {13. 14. void main()15. {16. int arr[] = {6,2,8,3,6,1,2};17. int size = sizeof(arr)/sizeof(arr[0]);18.
19. printf("arr before: ");20. printArr(arr, size);21. qsort(arr, size, sizeof(int), compareInt);22. printf("arr after: ");23. printArr(arr, size);24. }
© Keren Kalif
40
- ב שימוש qsort (2)דוגמאת
1. void printArr(char* arr[], int size)2. }3. int i;4. for (i=0 ; i < size ; i++)5. printf("%s\n", arr[i]);6. {
7. int compareWords(const void* a, const void* b)8. }9. const char* str1 = *(char**)a;10. const char* str2 = *(char**)b;11. return strcmp(str1, str2);12. {
13. void main()14. }15. char* words[] = {"CSI", "and", "Friends", "are", "the", "best"};16. int size = sizeof(words)/sizeof(words[0]);17.
18. printf("arr before: \n");19. printArr(words, size);20. qsort(words, size, sizeof(char*), compareWords);21. 22. printf(“\narr after: \n");23. printArr(words, size);24. {
© Keren Kalif
41
bsearchהפונקציה - ב הקיימת " stdlib.hפונקציה י עפ בינארי חיפוש ומבצעת
מסוים קריטריון " זהה חיפוש קריטריון י עפ ממוין להיות צריך המערך
void* bsearch (const void* key,
const void* base,
size_t num,
size_t size,
int (*comparator)(const void*, const void*) );
// כתובת ההתחלה של המערך
// מספר האיברים במערך
// גודלו של כל איבר במערך
משתנים ומחזירה את יחס ההשוואה 2מצביע לפונקציה המקבלת כתובות של // בינהם
כתובת המשתנה המכיל את הערך // לחפוש
© Keren Kalif
42
שימוש bsearch (1)דוגמאת
1. void printArr(int arr[], int size) {…}2. int compareInt(const void* a, const void* b)3. }4. int num1 = *(const int*)a;5. int num2 = *(const int*)b;6. 7. if (num1 < num2) return -1;8. else if (num1 > num2) return 1;9. else return 0;10. {11. 12. void main()13. {14. int arr[] = {6,2,8,3,6,1,2};15. int size = sizeof(arr)/sizeof(arr[0]);16. int lookFor;17. int* found;18.
19. qsort(arr, size, sizeof(int), compareInt);20. lookFor = 8;21. found = (int*)bsearch(&lookFor, arr, size, sizeof(int), compareInt);22. lookFor = 9;23. found = (int*)bsearch(&lookFor, arr, size, sizeof(int), compareInt);24. }
© Keren Kalif
43
1תרגיל ממחרוזת סכום קבלת
הפונקציה את את getAsciiSumכתוב ומחזירה מחרוזת המקבלתשבה התווים של האסקיי ערכי סכום
: הבאה הפונקציה את כתובint sum(char* str[], int size, int (*getSum)(const char*))
, ומצביע אורכו מחרוזות של מערך מקבלת הפונקציהאיבר, כל על שהתקבלה הפונקציה את ומפעילה לפונקציה
התוצאה, את ומחזירה במערך - מה השלישי sumלפונקציה mainקרא הפרמטר כאשר
הפונקציה התוצאה getAsciiSumהוא את והדפס - מה השלישי sumלפונקציה mainקרא הפרמטר כאשר
הפונקציה התוצאה, strlenהוא את והדפס
© Keren Kalif
44
2תרגיל המבנה את , Employeeהגדר שנות ומספר משכורתו העובד שם את המחזיק
שלו הניסיון הפונקציה את של compareEmployeesBySalaryכתוב כתובות 2המקבלת
ומחזירה -1עובדים ו- השני משל נמוכה הראשון של משכורתו , 1אם ההיפך יוחזר שווה ומשכורתם 0במידה
הפונקציה את של compareEmployeesBySeniorityכתוב כתובות המקבלתומחזירה 2 השני- 1עובדים משל קטנה הראשון של הניסיון שנות מספר אם, 1ו- יוחזר שווה ומשכורתם במידה 0ההיפך
כתובmain : עובדים 5הגדר בעזרתqsort הממוין המערך את והצג משכורתם ערך לפי אותם מיין בעזרתqsort הממוין המערך את והצג הניסיון שנות לפי אותם מיין
המקבלת פונקציה ומחזירה 2כתוב , 0עובדים זהה שמם שם- 1אם אם - , ו השני העובד משם לקסיקוגרפית קטן הראשון העובד 1העובד שם אם
השני העובד משם לקסיקוגרפית גדול הראשון - ל - mainהוסף ל (2עבור bsearchקריאה שלא ) ואחד שקיים אחד עובדים
© Keren Kalif
45
enum מוגדרת קבוצה מתוך מספרי ערך שיכיל חדש טיפוס הגדרת
מראש ,לוגי קשר בעלי קבועים אוסף הגדרת כלומר' , , וכד: בוליאנים ערכים צבעים אוסף השבוע ימות למשל:דוגמא
enum boolean {FALSE, TRUE}; של הגדרה , 2זוהי ערך את אטומטי באופן מקבל הראשון זה, 0קבועים
ערך את '.1שאחריו וכו הוא הטיפוס באמצעות enum booleanשם לקצרו :typedefוניתן
typedef enum {FALSE, TRUE} boolean; מטיפוס משתנים בתוכנית להגדיר נוכל להם booleanכעת ולתת
הערכים FALSE/TRUEאת
© Keren Kalif
46
enum - שגוי ערך מתן מטיפוס משתנה של ערכו על בדיבגר מסתכלים כאשר
enum , ערכו את ולא הקבוע שם את רואים - ה מטיפוס למשתנה ניתן שאינו enumאם מספרי ערך
( , לא המספרי הערך את נראה שלו הערכים בקבוצת הוגדר) שגיאה נקבל
typedef enum {FALSE, TRUE} boolean;
void main()
}
boolean b1 = TRUE;
boolean b2 = 3;
printf("b1=%d b2=%d\n", b1, b2);
{
© Keren Kalif
47
של שמו לקבלת enumטריק - ה שמות עם מחרוזות של גלובלי מערך להגדיר ניתן
enum לערכיהם בהתאמה
typedef enum {White, Black, Red, Yellow, Blue} color;
const char* colors[] = {"White", "Black", "Red", "Yellow", "Blue"};
void main()
{
color c = 2;
printf("Selected color is %s\n", colors[c]);
}
© Keren Kalif
48
enum – שונים ערכים מתן לערך עוקב שאינו ערך לתת באוסף ערך לכל ניתן
: " השמה, י ע שלפניו
typedef enum {White=10, Black=20, Red=30, Yellow=40, Blue=50} color;
void main()
{
color c1 = 1, c2 = 10, c3 = 40, c4 = 45;
{
Variadic Functions ) משתנה) פרמטרים מספר המקבלות פונקציות
© Keren Kalif
50
Variadic Function כמות את להגדיר יש הפונקציה בהגדרת כי ראינו היום עד
, זו כמות בדיוק לה לשלוח ויש לקבל שעליה הפרמטריםארגומנטים
Variadic Function מספר לקבל היכולה פונקציה היא : פעם בכל פרמטרים של variable argument listמשתנה
, לה, נעביר ופעם ממוצע המחשבת פונקציה לכתוב נוכל 4למשלופעם, , 8מספרים המשתמש, על להעמיס ובלי קוד אותו עם
המספרים ) כמות הוא הראשון הפרמטר מערך עבורנו לייצרהמועברים(:
calcAverage(4,3,4,7,2);
calcAverage(8,3,4,7,2,8,2,3,4); - ל :Variadic Functionדוגמא מכירים שאנחנו
printf, scanf
© Keren Kalif
51
למימוש Variadic Functionכלים בספריהstdarg.h הנדרשים הבאים המאקרו ישנם
:Variadic Functionלכתיבת va_list – המשתנה הפרמטרים רשימת את שיכיל חדש טיפוס
לפונקציה שהועברהva_start " החל – ל הנ הרשימה את לאתחל שתפקידו מאקרו
מסויים מפרמטר כלVariadic Function אחד פרמטר לפחות לקבל צריכה
va_arg – מהרשימה הבא האיבר את להביא שתפקידו מאקרוva_end - הרשימה איברי את לשחרר שתפקידו מאקרו
" י ע va_listשהוקצתה
© Keren Kalif
52
למימוש דוגמאVariadic Function
1. #include <stdio.h>2. #include <stdarg.h>3. 4. double calcAverage(int count, ...)5. {6. va_list numbers;7. int sum=0, i;8. 9. va_start(numbers, count); 10. for(i=0 ; i < count; i++)11. sum += va_arg(numbers, int);12. va_end(numbers);13. return (float)sum/count;14. {15. 16. void main()17. }18. float avg;19. 20. avg = calcAverage(4,3,4,7,2);21. printf("Average is %.3f\n", avg);22. avg = calcAverage(8,3,4,7,2,8,2,3,4);23. printf("Average is %.3f\n", avg);24. {
משתנה הגדרתרשימת עבורהפרמטרים
הפרמטרים רשימת אתחולהפרמטר אחרי מהפרמטר
count הבא האיבר קבלתמטיפוס וציון מהרשימה
שלוהרשימה שחרור
לבוא יכולה שפה ציוןשל כמות כלארגומנטים
© Keren Kalif
53
משפט – הדפסת נוספת דוגמא1. #include <stdio.h>2. #include <stdarg.h>3. 4. void printSentence(char* word, ...)5. {6. va_list allWords;7. char* currentWord;8. 9. va_start(allWords, word); 10. currentWord = word;11. while (currentWord != NULL)12. {13. printf("%s ", currentWord);14. currentWord = va_arg(allWords, char*);15. {16. printf("\n");17. 18. va_end(allWords);19. {20. 21. void main()22. }23. printSentence("This", "is", "a", "nice", "feature", "in", "C", NULL);24. {
© Keren Kalif
54
שונה מטיפוס פרמטר שכל כך למימוש דוגמא
1. #include <stdio.h>2. #include <stdarg.h>3. 4. void printGrades(char* className, char* name, ...)5. }6. va_list params;7. char* currentName;8. int currentGrade;9. 10. printf("The stuedents' grades in class %s\n", className);11. va_start(params, name); 12. currentName = name;13. while (currentName != NULL)14. }15. currentGrade = va_arg(params, int);16. printf("%-10s -->%d\n", currentName, currentGrade);17. currentName = va_arg(params, char*);18. {19. va_end(params);20. }
21. void main()22. }23. printGrades("Advanced C", "gogo", 100, "momo", 95, "yoyo", 97, NULL);24. {
© Keren Kalif
55
casting נכון לא1. #include <stdio.h>2. #include <stdarg.h>3. 4. void printGrades(char* className, char* name, ...)5. }6. va_list params;7. char* currentName;8. int currentGrade;9. 10. printf("The stuedents' grades in class %s\n", className);11. va_start(params, name); 12. currentName = name;
13. while (currentName != NULL)14. }15. currentGrade = va_arg(params, int);16. printf("%-10s -->%d\n", currentName, currentGrade);17. currentName = va_arg(params, char*);18. {19. va_end(params);20. }
21. void main()22. }23. printGrades("Advanced C", "gogo", 100, "momo", 95.7, "yoyo", 97, NULL);24. {
כי תעוף התוכנית זו בדוגמאאת לקרוא מצליח לא הקומפיילר
ולכן המבוקש מהטיפוס הנתוןבקריאה נכשל
שהציון לב נשים - כ doubleמוגדר
© Keren Kalif
56
של printfהמימוש1. #include <stdio.h>2. #include <stdarg.h>3. 4. #define MAX_DIGITS 105. 6. void myPrints(const char *string);7. void myPrinti(int num);8. void myPrintf(const char *format, ...);
9. void main()10. {11. int num = 12, num2 = -95;12. char ch = 'A';13.
14. myPrintf("%d %c hello %s %d\n", num, ch, "keren", num2);15. {16. 17. void myPrints(const char *string)18. {19. for ( ; *string != '\0' ; ++string) 20. putchar(*string);21. {
© Keren Kalif
57
של printf (2)המימוש
22. void myPrintf(const char *format, ...)23. }24. va_list params;25. va_start(params, format);26. for ( ; *format != '\0' ; ++format) 27. }28. if (*format == '%') 29. }30. ++format;31. 32. switch (*format)33. }34. case 's':35. } 36. char *s = va_arg(params, char*);37. myPrints(s);38. break;39. { 40. case 'd':41. }42. int num = va_arg(params, int);43. myPrinti(num);44. break;45. {46. case 'c':47. }48. char ch = va_arg(params, char);49. putchar(ch);50. break;51. {52. } // case53. {54. else 55. putchar(*format);56. { // for57. va_end(params);58. { // myPrintf59.
© Keren Kalif
58
של printf (3)המימוש62. // print a number to screen without 'printf' command63. void myPrinti(int num)64. }65. char printBuf[MAX_DIGITS];66. char *s;67. int digit, isNegative = 0;68. unsigned int u = num;69. 70. if (num == 0) 71. }72. putchar('0');73. return;74. {75. 76. if (num < 0) 77. }78. isNegative = 1;79. u = -num;80. {81. s = printBuf + MAX_DIGITS - 1; 82. *s = '\0';83. 84. while (u) 85. }86. digit = u % 10;87. *--s = digit + '0';88. u /= 10;89. {90. 91. if (isNegative) 92. *--s = '-';93. 94. myPrints(s);95. {
© Keren Kalif
59
1. #include <stdio.h>2. #include <stdarg.h>3. 4. int add(int count, ...)5. }6. int sum = 0, i;7. va_list numbers;8. va_start(numbers, count);9.
10. for (i=0 ; i < count ; i++)11. sum += va_arg(numbers, int);
12. va_end(numbers);13. return sum;14. {
15. int mult(int count, ...)16. }17. int mult = 1, i;18. va_list numbers;19. va_start(numbers, count);20. 21. for (i=0 ; i < count ; i++)22. mult *= va_arg(numbers, int);
23. va_end(numbers);24. return mult;25. {26. 27. void main()28. }29. int (*func[])(int, ...) = {add, mult};30. int res, i;
31. for (i=0 ; i < 2 ; i++)32. }33. res = func[i](4, 1, 2, 3, 4);34. printf("res = %d\n", res);35. {36. {
בשילוב דוגמאלפונקציות מצביעים
© Keren Kalif
60
בשילוב *voidדוגמא: הבאים הפרמטרים את המקבלת פונקציה כתוב
טיפוס של שם המייצגת (int, char, double)מחרוזתint *מערך של אורך בו תעדכן שהפונקציה . האחרון האיבר שהתקבל מהטיפוס מערכים של ידוע אינו מספר
להיות NULLצריך המערכים מספר באורך חדש מערך תייצר הפונקציה
מהמערך, הראשון האיבר את איבר בכל ותשים שהתקבלוברשימה המתאים
:דוגמאint arr1[]={1,2,3}, arr2[]={6,3,7,8,2}, arr3[]={8,7,6,5};
int* newArr = (int*)createArrayFromFirstElem(
"int", &size, arr1, arr2, arr3, NULL);
מטיפוס מערך : 3עם intיווצר 8, 6, 1איברים
© Keren Kalif
61
1. #include <stdio.h>2. #include <stdarg.h>3. #include <string.h>4. #include <stdlib.h>5. 6. void* createArrayFromFirstElem(7. char* type, int* size, void* arr, ...)8. {9. int i, arrType;10. void* currentArr, *newArr;11. va_list arrays;12.
13. // count number of arrays14. va_start(arrays, arr);15. currentArr = arr;16. *size = 0;17. do18. }19. (*size)++;20. currentArr = va_arg(arrays,
void*);21. } while (currentArr != NULL);
22. va_end(arrays);23. type = strlwr(type);24. va_start(arrays, size);
23. if (strcmp(type, "int") == 0) {24. newArr = (int*)malloc(*size*sizeof(int));25. for (i=0 ; i < *size ; i++)26. ((int*)newArr)[i] = va_arg(arrays, int*)[0];27. }28. else if (strcmp(type, "char") == 0) {29. newArr = (char*)malloc(*size*sizeof(char));30. for (i=0 ; i < *size ; i++)31. ((char*)newArr)[i] = va_arg(arrays, char*)[0];32. }33. else if (strcmp(type, "double") == 0) {34. newArr = (double*)malloc(*size*sizeof(double));35. for (i=0 ; i < *size ; i++)36. ((double*)newArr)[i] = va_arg(arrays, double*)[0];37. }38. else // invalid array type..39. newArr = NULL;
40. va_end(arrays);41. return newArr;42. } // createArrayFromFirstElem
© Keren Kalif
62
תיבות ראשי יצירת73. void main()74. }75. }76. int arr1[]={1,2,3}, arr2[]={6,3,7,8,2}, arr3[]={8,7,6,5};77. int size, i;78. int* newArr = (int*)createArrayFromFirstElem("int", &size, arr1, arr2, arr3, NULL);79. for (i=0 ; i < size ; i++)80. printf("%d ", newArr[i]);81. printf("\n");82. free(newArr);83. { 84. 85. } 86. char str1[]="Gogo", str2[]="Ooops!", str3[]="Orange", str4[]="Ding-Dong!";87. int size, i;88. char* newArr = (char*)createArrayFromFirstElem("char", &size, str1, str2, str3, str4,
NULL);89. for (i=0 ; i < size ; i++)90. printf("%c ", newArr[i]);91. printf("\n");92. free(newArr);93. { 94. {
© Keren Kalif
63
! ?? די, אז נכון שזה נכון אגב
http://programmingpalace.files.wordpress.com/2011/12/smokingwarningforsoftwareengineers.jpg
© Keren Kalif
64
תרגיל , שהתו כך תווים של מספר כל המקבלת פונקציה כתוב
יהיה ’0‘\האחרון
את רק הכוללת חדשה מחרוזת ותחזיר תייצר הפונקציהשהועברו הגדולות האותיות
:דוגמה‘ : התווים ’ a’, ‘G’, ‘b’, ‘c’, ‘O’, ‘G’, ‘d’, ‘O’, ‘e’, ‘f’, ‘\0עבור
המחרוזת ותוחזר GOGOתיוצר
© Keren Kalif
65
: למדנו זו ביחידה מצביעים תזכורת מצביעים בין המרות המצביעvoid* לפונקציה מצביע מהו לפונקציה במצביע שימושים הפונקציהatexit לפונקציות מצביעים של מערך עם לפונקציה מצביע *voidשילוב הפונקציותqsort - bsearchו Enum מהיVariadic Function - ב va_list, va_start, va_arg, va_endהשימוש