שיעור בתכנות מערכות בשפת C מיום א` (2.11)
Download
Report
Transcript שיעור בתכנות מערכות בשפת C מיום א` (2.11)
מכללת אורט כפר-סבא
תכנות מערכות
בשפת C
מחרוזות
02.11.14
אורי וולטמן
[email protected]
חידה לחימום
נתונות שתי ערימות של קוביות ,כשבכל ערימה מספר הקוביות ההתחלתי
הוא אקראי.
שני שחקנים משחקים משחק של הסרת קוביות מהערימות .כל שחקן ,בתורו,
מסיר כמה קוביות שהוא רוצה (לפחות אחת) מאחת הערימות (שחקן יכול
להסיר קוביות מערימה אחת בתור אחד ומן הערימה השנייה בתור שאחריו).
השחקן שמסיר את הקוביה האחרונה ,מנצח במשחק.
פתחו אלגוריתם המקבל כקלט שני מספרים טבעיים המייצגים את מספר
הקוביות בשתי הערימות.
האלגוריתם יבחר האם ברצונו לשחק ראשון או שני ,וישחק כך שהוא מנצח
תמיד.
חיפוש תו במחרוזת
מאפשרת לחפש תו מסוים בתוך,string.h- המוגדרת ב,strchr הפונקציה התקנית
: כותרת הפונקציה היא.מחרוזת
char *strchr (const char *s, const char c)
NULL או מחזירה,s במחרוזתc הפונקציה מחזירה מצביע למופע הראשון של התו
.אם התו לא מופיע במחרוזת
?מה יהיה הפלט של קטע הקוד הבא
char str[] = “This is a sample string";
char *ptr;
printf(“Looking for the 's' character\n”);
ptr = strchr(str,’s’);
while (ptr != NULL) {
printf("found at %d\n",ptr-str);
ptr = strchr(ptr+1,’s’);
}
חיפוש תו במחרוזת
נממש את הפונקציה :strchr
)char *strchr (const char *s, const char c
{
)while (*s != ‘\0’ && *s != c
;s++
;)return ((*s == c) ? s : NULL
}
סטודנט א' וסטודנט ב' מציעים לעשות שינוי בלולאת ה while-שמופיעה במימוש
הנ"ל.
ההצעה של סטודנט א':
ההצעה של סטודנט ב':
; )while (*s++ != ‘\0’ && *s != c
; )while (*s != ‘\0’ && *s++ != c
האם צריך המרצה לתת ציון שלילי לשני הסטודנטים? או רק לאחד מהם? או לאף
אחד מהם?
חיפוש תת-מחרוזת
הפונקציה התקנית ,strstrהמוגדרת ב ,string.h-מאפשרת לחפש תת-מחרוזת בתוך
מחרוזת מסוימת .כותרת הפונקציה היא:
)char *strstr (const char *haystack, const char *needle
הפונקציה מחזירה מצביע למופע הראשון של needleב ,haystack-או מחזירה
NULLאם needleאינה תת-מחרוזת של .haystackאם needleהיא מחרוזת
ריקה ,הפונקציה מחזירה מצביע לתחילת .haystack
מה יהיה הפלט של קטע התכנית הבא?
;"char s1[] = “This is a sample string
;))”puts(strstr(s1,”is
איזה שינוי יש לערוך בקטע התכנית ,על מנת שהפלט יהיה "?"a sample string
האם יש יותר מתשובה אחת לשאלה הקודמת?
העתקת מחרוזות
לפעמים היינו רוצים להשתמש ב ,strcpy(to,from)-אבל להעתיק רק מספר מסוים
של תווים מ ,from-ולא את fromכולו.
לצורך כך קיימת ב string.h-פונקציה תקנית בשם ,strncpyהמתנהגת כמו ,strcpy
למעט זה שהיא מקבלת פרמטר שלישי ,nהקובע את מספר התווים יועתקו.
כותרת הפונקציה היא:
)char *strncpy (char *to, const char *from, unsigned int n
דוגמא לשימוש בפונקציה:
;"char str[] ="This is a simple string
;)"char *pch = strstr(str,"simple
;)strncpy(pch,"sample",6
;)puts(str
אם fromקצרה מ n-בתים ,אז יועתקו ’-‘\0ים (על מנת להשלים ל n-תווים).
במידה ו to-ו from-נמצאים באזורים חופפים (ולו חלקית) בזיכרון ,אז התנהגות
הפונקציה אינה מוגדרת.
השוואת מחרוזות
הכרנו קודם (ואף מימשנו) את הפונקציה strcmpהמשווה בין שתי
מחרוזות ,שכותרתה:
)int strcmp (const char *s1, const char *s2
הפונקציה מקבלת שתי מחרוזות ,משווה ביניהן ,ומחזירה 0אם שתי
המחרוזות שוות ,מס' שלילי אם ,s2 < s1ומס' חיובי אם .s2 > s1
השוואת מחרוזות נעשית לפי סדר מילוני ):(lexicographic order
משווים בין האות הראשונה של שתי המחרוזות .אם האות הראשונה של s1קודמת
באלפבית לאות הראשונה של ,s2אזי .s1 < s2ואם להיפך – אז .s1 > s2
אם לשתי המחרוזות אותה האות הראשונה ,אז משווים בין האות השנייה ,באופן דומה.
לאחר מכן ,אם עדיין מדובר באותיות שוות ,ממשיכים באותו אופן לאות השלישית ,וכו'.
אם אחת המחרוזות נגמרה ,בשעה שבמחרוזות השנייה עוד יש אותיות – אז המחרוזות
השנייה גדולה מהראשונה.
אם שתי המחרוזות נגמרו באותו זמן ,מבלי שהתהליך נעצר קודם לכן ,אזי המחרוזות
שוות.
השוואת מחרוזות
מה תחזיר הפונקציה strcmpעבור הזימונים הבאים:
< 0
)”strcmp(“hello”,”world
0
)”strcmp(“hello”,”hello
> 0
)”strcmp(“hello”,”Hello
הסיבה שעבור הזימון האחרון לא החזירה הפונקציה
strcmpאת הערך ,0היא שהתו ' 'Hוהתו ' 'hהם שני
תווים שונים לגמרי מבחינתה (הם ממוקמים במקומות
שונים בטבלת .)ASCII
אם נרצה שהפונקציה strcmpתחזיר 0עבור זימון
זה ,כלומר – שהיא לא תהיה רגישה לגודל אות
( ,)case insensitiveנשתמשו במקומה בפונקציה
.stricmp
השוואת מחרוזות
מוגדרת הפונקציה:
)int stricmp (const char *s1, const char *s2
הפונקציה מתנהגת ממש כמו ,strcmpכלומר :היא מקבלת שתי
מחרוזות ,משווה ביניהן ,ומחזירה 0אם שתי המחרוזות שוות ,מס'
שלילי אם ,s2 < s1ומס' חיובי אם .s2 > s1
ההבדל היחיד הוא שהפונקציה אינה מבדילה בין אותיות קטנות
ואותיות גדולות (' 'Aמבחינתה זהה לגמרי ל 'B' ,'a'-זהה ל ,'b'-וכו').
איך נממש את הפונקציה?
נקצה זיכרון (ע"י mallocשב )stdlib.h-לשתי מחרוזות זמניות t1וt2-
נעתיק את s1ל ,t1-ואת s2ל ,t2-אבל נהפוך כל אות לאות קטנה על-ידי
שימוש בפונקציה הסטנדרטית )( ,tolowerהמוגדרת ב.ctype.h-
כעת אנחנו בטוחים ש t1-ו t2-מכילות רק אותיות קטנות.
נחזיר את הערך של ).strcmp(t1,t2
השוואת מחרוזות
int stricmp (const char *s1, const char *s2)
{
char *t1,*t2;
?malloc-ב
'+1' מדוע מופיע
מדוע לא מכפילים את הביטוי שמופיע
?sizeof(char) בביטויmalloc-בתוך ה
t1 = malloc(strlen(s1) + 1);
?איזו שגיאה יש בפונקציה
while (*s1) *t1++ = tolower(*s1++);
*t1 = '\0';
t2 = malloc(strlen(s2) + 1);
while (*s2) *t2++ = tolower(*s2++);
*t2 = '\0';
return strcmp(t1,t2);
}
השוואת מחרוזות
int stricmp (const char *s1, const char *s2)
{
שאנחנו מזמנים כאן את
char *t1,*t2;
אבל מבלי לבדוק האם הקצאת
int returnvalue;
נשים לב
,malloc
הזיכרון הצליחה (אולי הפונקציה
.)? כי אין זיכרון פנויNULL החזירה
t1 = malloc(strlen(s1) + 1);
while (*s1) *t1++ = tolower(*s1++); t2- וt1 המצביעים:יתרה מכך
*t1 = '\0';
ולא על,מצביעים על סוף המחרוזת
t2 = malloc(strlen(s2) + 1); איך ניתן לפתור.תחילתה
while (*s2) *t2++ = tolower(*s2++);
?את הבעיה
*t2 = '\0';
return
strcmp(t1,t2);
returnvalue
= strcmp(t1,t2);
free(t1); free(t2);
return returnvalue;
}
השוואת מחרוזות
פונקציה נוספת המשווה שתי מחרוזות לפי סדר לקסיקוגרפי היא
הפונקציה ,strncmpשכותרתה:
)int strncmp (const char *s1, const char *s2, unsigned n
הפונקציה מקבלת שתי מחרוזות ,ומשווה רק בין nהתווים הראשונים
של כל מחרוזת ,ומחזירה 0אם שתי המחרוזות שוות ,מס' שלילי אם
,s2 < s1ומס' חיובי אם .s2 > s1
אם במחרוזת מסוימת יש פחות מ n-תווים ,אז מתייחסים רק לתווים
שעד ל.null terminator-
אם בשתי המחרוזות יש פחות מ n-תווים ,אין הבדל בין strncmpל-
.strcmp
)strncmp(“helloa”,”hellob”,5
0
< 0
)strncmp(“helloa”,”hellob”,6
< 0
)strncmp(“helloa”,”hellob”,9
השוואת מחרוזות
int strncmp (const char *s1, const char *s2, unsigned int n)
{
char *t1, *t2;
... הפונקציה לא תעבוד כשורה
int returnvalue;
t1 = malloc(strlen(s1) + 1);
strncpy(t1,s1,n);
t1[n] = '\0';
t2 = malloc(strlen(s2) + 1);
strncpy(t2,s2,n);
t2[n] = '\0';
returnvalue = strcmp(t1,t2);
free(t1); free(t2);
return returnvalue;
}
?מה חסר
גם כאן צריך היה לוודא
...שהקצאת הזיכרון הצליחה
חיפוש תווים במחרוזת
ב string.h-מוגדרת הפונקציה התקנית:
)char *strpbrk (const char *str1, const char *str2
הפונקציה מחזירה מצביע למופע הראשון ב str1-של תו
מתוך .str2אם הפונקציה סרקה את ,str1והגיעה עד ל-
,null terminatorמבלי שמצאה אף אחד מהתווים שבתוך
,str2אז היא תחזיר .NULL
#include <stdio.h>
#include <string.h>
חיפוש תווים במחרוזת
int main()
{
char str[] = "This is a sample string";
char key[] = "aeiou";
char *pch;
printf ("Vowels in '%s': ",str);
pch = strpbrk (str, key);
while (pch != NULL) {
printf ("%c " , *pch);
pch = strpbrk (pch+1,key);
}
printf ("\n");
return 0;
}
?מה יהיה הפלט
מציאת רישא מותנית
: היא,string.h-פונקציה המוגדרת גם היא ב
unsigned int strspn (const char *str1, const char *str2)
,str1 ) המקסימלית שלprefix( הפונקציה מחזירה את אורך הרישא
.str2-המורכבת כולה מתווים שנמצאים ב
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = “125th”, cset[] = "1234567890";
int i = strspn (str,cset);
printf ("The length of the number is %d.\n",i);
return 0;
}
.0 אז הפונקציה תחזיר,str2- אינו שייך לstr1 אם התו הראשון של
מציאת רישא מותנית
: היא,string.h- המוגדרת גם היא ב,strspn-פונקציה הפוכה ל
unsigned int strcspn (const char *str1, const char *str2)
,str1 ) המקסימלית שלprefix( הפונקציה מחזירה את אורך הרישא
.str2-המורכבת כולה מתווים שאינם נמצאים ב
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = “fcba73”, cset[] = "1234567890";
int i = strcspn (str,cset);
printf ("The first number is at position %d.\n",i+1);
return 0;
}
אםstr1 ולכן היא תחזיר את האורך של,‘\0’-הפונקציה סורקת גם את ה
.str1- לא נמצאים בstr2 אף אחד מהתווים של