|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
קורס:"שפת C"
מתוך הספר: C - מדריך מקצועי
מזהים ( Identifiers)מזהים הם שמות בתכנית המייצגים משתנים, קבועים, טיפוסים, פונקציות וכו'. כללים לקביעת שמות מזהים: 1. מזהה הוא רצף של אותיות, ספרות והתו '_' (underscore) . רצף זה חייב להתחיל באות בשפה האנגלית או בתו '_'. 2. אורך מזהה אינן מוגבל 3. אין להשתמש במילים שמורות כמזהי טיפוסים, משתנים וכו'. 4. קיימת ההבחנה בין אותיות גדולות וקטנות. לדוגמא, המזהים top, Top, TOP הם מזהים שונים. 5. על שמות המזהים להיות משמעותיים. לדוגמא אם נרצה לתת שם למונה בתוכנית ניקרא לו counter.
הערות (Comments)אם נרצה להוסיף לתכנית מלל אשר נרצה שהמהדר יתעלם ממנו (לדוגמא, הסברים על התוכנית או על פקודות מסוימות) נסמנו כהערה. הערה מתחילה בצמד התווים */ ומסתיימת בצמד התווים /*. לדוגמא: /* this is a comment. */ int x = 5 * 2; לא ניתן לבצע קינון הערות - לדוגמא, במבנה ההערה הבא
ההערה מסתיימת כאן. כל הקוד אשר מופיע לאחר סיום ההערה המסומן יחשב כחלק מהתוכנית עבור המהדר. כאשר סימן תחילת או סיום הערה נמצא בתוך מחרוזת, הוא לא יזוהה והמהדר לא יתייחס אליו. מילים שמורות (keywords)מילים שמורות הן מילים בשימושה של השפה ואסורים לשימוש כשמות מזהים. רשימת המילים השמורות בשפת C :
טיפוסי נתוניםהטבלה הבאה מציגה את הטיפוסים הבסיסיים בשפת C :
טיפוסים שלמיםint הוא הטיפוס הבסיסי לייצוג מספר שלם. אופן הגדרת משתנה מסוג שלם:
int i;
i יכול כעת לקבל ערכים שלמים, חיוביים ושליליים לדוגמא: i = 34; i = -2456; קיימים תתי-טיפוסים של שלם:
כמו כן ניתן לציין עבור טיפוס שלם כלשהו שהוא מקבל ערכים חיוביים בלבד ע"י המציין unsigned. דוגמאות: short i1 = - 23; unsigned i2 = 3000; unsigned short i3 = 23; טיפוסים ממשייםfloat הוא הטיפוס הבסיסי לייצוג מספר ממשי. אופן הגדרת משתנה מסוג ממשי:
float f;
f יכול כעת לקבל ערכים ממשיים (ראה/י טבלה להלן): f = 34.56; f = -123.458997; f = 23E+12; קיימים טיפוסים ממשיים בעלי טווח מספרים וערך דיוק גדול יותר:
טיפוסים תווייםתווים מיוצגים במחשב ע"י טבלה הנקראת טבלת ASCII. הטבלה מכילה 256 תווים (0 עד 255) הכוללים ספרות, אותיות (גדולות וקטנות) וסימנים שונים. הטבלה במלואה מופיעה בנספח הספר. דוגמאות לתווים בטבלת ASCII: A 2 % * ! a . ~ ) הטיפוס הקיים בשפת C לייצוג תו בודד הוא char. אופן הגדרת משתנה תווי:
char c;
וכעת c יכול לקבל ערכים מסוג תווי - ערך תווי מסומן ע"י שני גרשים משני צידיו: c = 'a'; c = 'A'; c = '!'; האם char הוא signed או unsigned ?התשובה לשאלה תלויה במערכת עליה עובדים. כלומר הגדרת משתנה מסוג char כגון:
char ch;
אינה חד משמעית בשפת C אלא תלויית מערכת וסביבת פיתוח. דבר זה יכול ליצור הבדלים חדים בהידור והרצת תכניות על מחשבים שונים. לדוגמא, אם נגדיר את המשתנה כך char ch = 255; ערכו של המשתנה השלם x לאחר ההצבה
int x = ch;
יהיה בעל ערך 255 במערכת שבה char הוא unsigned ובעל ערך -1 במערכת שבה הוא signed!!! גדלי הטיפוסיםבשפת C אין הגדרה מדויקת לגודלי הטיפוסים הבסיסיים בשפה, כלומר למספר הבתים המוקצים למשתנה מסוג אותו הטיפוס. גדלי הטיפוסים תלויים במחשב ובמערכת ההפעלה עליה עובדים. לדוגמא, במחשב מבוסס Intel - Pentium, עם מערכת ההפעלה Windows 95 / NT גדלי הטיפוסים הבסיסיים הם:
enumהוראת enum משמשת להגדרת משתנים היכולים לקבל ערכים מתוך תת-תחום מסוים. לדוגמא, אם משתנה מסוים מייצג את היום בשבוע, נוכל להגדיר תת - תחום של ימי השבוע: enum Day { SUN=1, MON=2, TUE=3, WED=4, THU=5, FRI=6, SAT=7}; והגדרת משתנה מסוג ה- enum הנ"ל:
enum Day today;
בדוגמא זו Day הוא שם תג (tag name) . הגדרת המשתנה מצוינת ע"י המילה enum ושם התג (Day) מיד אחריה. תכנית דוגמא: #include <stdio.h> void main() { enum Day { SUN=1, MON=2, TUE=3, WED=4, THU=5, FRI=6, SAT=7}; enum Day day1, day2; day1 = SUN; day2 = THU; } אם לא מצוין ערך של קבוע בתוך הגדרת ה- enum ערכו שווה לערך האיבר הקודם + 1. אם ערכו של האיבר הראשון לא מצוין ערכו הוא 0. לכן ניתן להגדיר את ה- enum הנ"ל בדרך מקוצרת: enum Day { SUN=1, MON, TUE, WED, THU, FRI, SAT};
הגדרת טיפוס חדש ע"י typedefבנוסף לטיפוסים הקיימים בשפת C, קיימת אפשרות להגדיר טיפוסים חדשים ע"י ההוראה typedef. לדוגמא, ניתן להגדיר את ה- enum מהסעיף הקודם כטיפוס ובכך למנוע את הצורך בציון המילה enum בצירוף שם התג: typedef enum { SUN=1, MON, TUE, WED, THU, FRI, SAT} Day; Day today, yesterday, tomorrow; כעת Day הוא טיפוס עצמאי ולא רק שם תג. דוגמא שימושית נוספת - הגדרת טיפוס בוליאני בעל 2 ערכים TRUE ו- FALSE : typedef enum { FALSE=0, TRUE=1 } Boolean; Boolean flag = FALSE; שימוש שכיח בהגדרת טיפוסים חדשים בשפת C הוא לצורך כתיבת תוכנה עבור מחשבים שונים. אחת הבעיות הקשות בהעברת תוכנה ממערכת אחת למערכת שנייה היא בהתייחסות לגדלי הטיפוסים. הואיל ובשפת C אין הגדרה תקנית לגודלי הטיפוסים בשפה, מהדרים הרצים על מערכות שונות יתרגמו אחרת את התכנית. אחת הדרכים להקל על מלאכת הסבת התוכנה היא להגדיר את הטיפוסים הבסיסיים מחדש ע"י typedef . דוגמא להגדרות כאלו: typedef char CHAR; typedef int INT; typedef unsigned UNS; ובתכנית עצמה משתמשים אך ורק בהגדרות אלו: CHAR c1; INT i; כעת, אם נרצה להסב את התוכנה למחשב ומערכת הפעלה בהם הטיפוסים הבסיסיים שונים - למשל אם במערכת המקורית השלם הוא 32 סיביות ובמערכת החדשה הוא 16 סיביות, נבצע שינוי בהגדרת INT כך שגדלו לא ישתנה: typedef long INT; typedef unsigned long UNS; וכעת אם long במערכת החדשה הוא 32 סיביות גדלו של INT יישאר זהה ביחס למערכת הישנה. קבועיםקבועיםקבועים הם שמות של ערכים שאינם משתנים לכל אורך התכנית. כפי שכבר ראינו, ניתן להגדיר קבועים ע"י שימוש במילה const: const int MAX = 28; או ע"י הגדרתם בקדם-מעבד בהוראת #define:
#define MAX 28
מהו ההבדל בין השניים? במקרה הראשון אנחנו מגדירים תא בזיכרון בשם MAX שערכו הוא 28 ושלא ניתן לשנותו. במקרה השני לא מוגדר תא בזיכרון: זוהי הוראה לקדם-מעבד העובר על התכנית ומחליף כל מופע של MAX במספר 28. הבדל נוסף הקיים בין 2 הצורות הוא במרחב השם (namespace) של הקבוע: קבוע המוגדר ע"י הקדם מעבד מוכר בכל קובץ התכנית, החל מהמקום בו הוגדר. קבוע המוגדר ע"י const לעומת זאת הוא בעל מרחב שם מוגבל יותר, עפ"י מקום הגדרתו, כפי שנראה בפרק 6, "פונקציות". ניתן להגדיר בשתי הצורות קבועים מטיפוסים שונים. דוגמאות: #define MIN -34.55 #define STREET "Ben Yehuda" const char STR[] = "hello"; const char C = 'c'; const float NUMBER = 34.88;
ליטרליםליטרלים הם ערכים המופיעים ישירות בקוד התכנית. הם יכולים להיות מטיפוסים שונים - שלם, ממשי, תווי או מחרוזת. טיפוס הליטרל נקבע ע"י המהדר עפ"י הערך. לדוגמא, המספר 390 יובן ע"י המהדר כליטרל מטיפוס שלם, והערך 'f' יובן כליטרל מטיפוס תווי. ליטרלים שלמיםליטרלים שלמים הם מספרים שלמים הנכתבים ישירות בקוד התכנית. לדוגמא, בהוראות int x; x = 34; המספר 34 הוא קבוע מספרי ממשפחת השלמים. מהו טיפוסו המדויק? הטיפוס, אם לא מצוין אחרת הוא int . במידה ורוצים לציין שהוא מסוג long יש להוסיף סיומת "l" או "L" למספר, לדוגמא:
long x;
x = 34L;
ניתן לציין בסיס שונה מהבסיס העשרוני עבור שלמים: קידומת של 0 (אפס) בראש המספר מציינת שהמספר נתון בבסיס אוקטלי (בסיס 8), קידומת 0x מציינת שהוא בבסיס הקסהדצימלי (בסיס 16). לדוגמא, ההוראות הבאות שקולות - בכולן מוצב הערך 34 (דצימלי) ל- x: int x; x = 34; /* decimal */ x = 042; /* octal */ x = 0x22; /* hexa */ ליטרלים ממשייםליטרלים ממשיים, בדומה לליטרלים שלמים, נכתבים ישירות בקוד התכנית. לדוגמא, בהוראות float y; y = 34.55; המספר 34.55 הוא ליטרל מספרי ממשפחת הממשיים. מהו טיפוסו? אם לא צוין אחרת הטיפוס הוא double. מכיוון שהליטרל מוצב למשתנה מסוג float מתבצע קיצוץ, ומהדרים מסוימים יציגו הודעות אזהרה. ניתן לציין שטיפוס הליטרל הממשי הוא float ע"י הוספת סיומת f או F למספר, לדוגמא:
y = 34.55f;
במקרה זה לא תוצג הודעת אזהרה. ליטרלים ממשיים ניתנים לכתיבה בצורה מעריכית ע"י ציון המעריך בתוספת האות e או E. לדוגמא, המספר 34.55 ניתן לרישום כ- 3.455E1 או 3455E-2 או 0.3455E2 . צורת רישום זו מתייחסת לחזקה של בסיס 10:
ליטרלים תווייםליטרלים תוויים מצוינים ע"י התו המיוצג ושני גרשים משני צידיו. לדוגמא, 'x' מציין את ערך ה- ASCII של התו x (טבלת ה- ASCII נתונה בנספח הספר). ליטרלים תוויים שייכים למעשה למשפחת השלמים: הם משמשים בפעולות חשבוניות ולוגיות כמספרים שלמים לכל דבר כשתחום הערכים שלהם מוגבל (בית בודד). קיימים ליטרלים תוויים מיוחדים המשמשים בעיקר בהדפסה. שניים מהתווים המיוחדים הכרנו בפרקים הקודמים: '\n' כתו שורה חדשה, ו- '\t' כטאב בפעולות הדפסה. התו '\' מציין משמעות מיוחדת עבור תווים מסוימים. חלק מתווים אלו נתון בטבלה הבאה (הרשימה המלאה נמצאת בנספח):
לדוגמא, כדי להדפיס את השורות הבאות: First line Second line Third line נכתוב: printf("First\tline\nSecond\tline\nThird\tline"); ואם נרצה להדפיס את התו " (גרשיים) שערך ה- ASCII שלו הוא 34 נוכל לעשות זאת במספר דרכים: putchar('\"'); /* as character with backslash*/ putchar(34); /* direct decimal ASCII value */ putchar('\x22'); /* direct hexadecimal ASCII value */ putchar('\42'); /* direct octal ASCII value */ printf("\""); /* as part of a string, with backslash*/ תרגיל: כיצד יודפס התו '\' עצמו? הצע/י 5 דרכים. אופרטוריםאופרטורים הם סימנים המוצבים ליד ובין נתונים, ומורים למהדר על ביצוע פעולה מסוימת. האופרטורים נחלקים למספר קבוצות:
אופרטורים חשבונייםהאופרטורים החשבוניים פועלים על טיפוסים מספריים שלמים או ממשיים:
האופרטורים מופעלים עפ"י טיפוסי האופרנדים - שלמים או ממשיים. לדוגמא: int i; float f; i = 4 / 5; /* i=0 */ f = 4 / 5; /* f=0.0 */ f = 4.0 / 5.0; /* f=0.8 */ כלומר, תוצאת פעולת החילוק שונה בין שלמים לממשיים: 4/5 הוא חלוקת שלמים שתוצאתה השלם 0. לעומת זאת 4.0/5.0 היא חלוקת ממשיים שתוצאתה ממשית - 0.8. אופרטורי קידום וחיסור: "++" ו- "--"האופרטור ++ מבצע קידום ב- 1 והאופרטור – מבצע חיסור ב- 1 של משתנה שלם. שני האופרטורים יכולים להופיע משני צדי המשתנה, וקיים הבדל בין פירוש 2 הצורות:
int i = 9; int j = i ++; /* è j=9, i=10 */
int i = 9; int j = ++ i ; /* è j=10, i=10 */
תכנית דוגמא: #include <stdio.h> void main ( ) { int i = 5; int j = 0; printf("%d", i++); /* output: 5, i = 6 */ printf("%d", --j); /* output: -1, j = -1 */ printf("%d", j = i++); /* output: 6, j = 6 i=7 */ } אופרטור שארית החלוקה %האופרטור % פועל רק על טיפוסים שלמים, ומבצע פעולת מודולו, כלומר, הוא מחזיר את השארית של תוצאת החלוקה. לדוגמא: int s; s = 10 % 3; /* s = 1 */ s = 8 % 8; /* s = 0 */ s = 8 % 0; /* Error! */ s = 8 % 9; /* s = 8 */ s = -8 % 9; /* s = -8 */ s = 8 % -9; /* s = 8 */ אופרטורים וביטויים לוגייםאופרטורי היחס מרכיבים ביטויים לוגיים שתוצאתם היא אמת או שקר:
ניתן להרכיב ביטויים ממספר ביטויים בסיסיים ע"י האופרטורים הלוגיים הבאים:
דוגמאות:
הביטויים הלוגיים מופיעים בדרך כלל כחלק ממשפטי תנאי, לדוגמא: if(x > y) printf("x is bigger than y"); else if(y > x) printf("y is bigger than x"); else printf("x and y are equals"); טיפוס שלם כתחליף לטיפוס בוליאניתוצאת ביטוי לוגי יכולה להיות אמת (true) או שקר (false). בשפות מסוימות קיים טיפוס בוליאני שאלו שני הערכים היחידים שהוא מקבל. בשפת C לא קיים טיפוס כזה - טיפוס השלם משמש לצורך כך. בשפת C נקבע שערך 0 של משתנה שלם מציין ערך "שקר" בביטוי לוגי, ו- 1 או כל ערך שונה מ- 0 מציין ערך "אמת". לדוגמא: int i; int x=5, y=5; i = (x > y); /* i = 0 */ i = (x == y); /* i = 1 */ וכן ניתן להשתמש בתוצאת הביטוי במשפט תנאי: i = (x == y); if(i) printf("x is equal to y"); מכיוון ששלם מייצג גם טיפוס בוליאני ניתן גם להשתמש במשתנים שלמים בתנאי הלולאה. לדוגמא: #include <stdio.h> void main ( ) { int i = 4; while(i) { i--; printf("i = %d\t",i); } } הפלט: i = 3 i = 2 i = 1 i = 0 משפט תנאי מקוצרהאופרטור "?:" הוא אופרטור טרינרי - כלומר בעל שלושה אופרנדים - המשמש במקרים מסויימים כקיצור למשפט if-else. לדוגמא, המשפט if(x > y) max = x; else max = y; יכול להיכתב בקיצור ע"י max = x > y ? x : y; תחביר האופרטור "?:" : <ביטוי-לוגי> ? <ביטוי 1> : <ביטוי 2> הביטוי הלוגי שמופיע לפני הסימן "?" הוא ביטוי שתוצאתו "אמת" או "שקר". אם התוצאה היא "אמת", תוצאת המשפט היא <ביטוי 1>, אחרת תוצאתו היא <ביטוי 2>. ניתן להשתמש בביטוי זה באופן מקוצר כחלק מהוראות אחרות. לדוגמא, אם נרצה להדפיס את המקסימום מבין 2 המשתנים שלעיל מבלי להשתמש במשתנה הנוסף max נוכל לכתוב: printf("The maximum is = %d", x > y ? x : y); אופרטורים הפועלים על סיביות (bitwise operators)בשפת C קיימים אופרטורים הפועלים על סיביות של טיפוסים שלמים (שלם, שלם קצר/ארוך, תו). קבוצה זו כוללת 6 אופרטורים:
ארבעת האופרטורים הראשונים מבצעים פעולות לוגיות בינריות על סיביות. שני האופרטורים האחרונים מבצעים הזזה של הסיביות במשתנים. פעולות לוגיות על סיביותבפעולות לוגיות בין סיביות מתקיימים הכללים הבאים:
1 & 1 = 1 1 & 0 = 0 0 & 1 = 0 0 & 0 = 0
1 | 1 = 1 1 | 0 = 1 0 | 1 = 1 0 | 0 = 0
1 ^ 1 = 0 1 ^ 0 = 1 0 ^ 1 = 1 0 ^ 0 = 0
~1 = 0 ~0 = 1 נניח שנתון השלם x בבסיס 16: int x = 0x52; במערכת שבה השלם הוא מגודל 4 בתים, כלומר 32 סיביות, המשתנה ייראה כך בזיכרון:
השורה התחתונה מייצגת את הסיביות של המספר, ובשורה העליונה מוצגים הערכים בבתים בייצוג הקסה. נגדיר משתנה נוסף: int y = 0x8472; y ייראה כך בזיכרון:
פעולת AND בין שני המשתנים מסומנת כ- x & y. תוצאתה היא משתנה שלם שבו כל סיבית היא תוצאת הפעולה AND הבינרית בין שתי הסיביות המתאימות ב- x וב- y. לדוגמא, אם נבצע int z = x & y; מה יהיה ערכו של z ?
&
=
כלומר z = 0x52. באופן דומה:
דוגמאות נוספות מובאות בעמ' 74. פעולות הזזהפעולות ההזזה גורמות להזזת כל סיביות הנתון מספר מקומות ימינה או שמאלה תוך מילוי המקומות החדשים ב- 0 או ב- 1. האופרטור >> מבצע הזזה שמאלה, והאופרטור << מבצע הזזה ימינה. צורת הסימון:
לדוגמא, אם x הוא כמו קודם:
אז תוצאת הפעולה x << 2 היא
כלומר התוצאה היא 0x148. פעולה זו זהה להכפלת x ב- 4. כאשר הערך מוזז ימינה, המקומות משמאל ממולאים ב- 0 עבור מספרים חיוביים וב- 1 עבור מספרים שליליים. לדוגמא, אם ערכו של x הוא -4 , הוא מיוצג במחשב בשיטת המשלים ל -2 ע"י:
תוצאת הפעולה x >> 2 היא
כלומר, ערכו יהיה -1 . פעולה זו זהה לחילוק x ב- 4. דוגמאות נוספות מובאות בעמ' 75. אופרטורי הצבההאופרטור "=" הוא אופרטור ההצבה בשפת C. לדוגמא: int x; x = 5; הערך 5 מוצב למשתנה x. ניתן גם להציב ערך למשתנה תוך כדי הגדרתו, לדוגמא: int x=5; double y=6.2, z=1.45E10; אופרטור ההצבה מחזיר את הערך המושם, לכן ניתן להדפיסו או להציבו בשרשרת למשתנה נוסף. דוגמאות: 1. printf("%d", x = y); 2. z = x = y; 3. w = z = x = y; יש להבחין בין אופרטור ההצבה "=" לבין אופרטור השוויון "==". ההוראה x = y; היא הוראת הצבה של הערך של y למשתנה x. לעומת זאת, ההוראה x == y היא ביטוי לוגי שתוצאתו "אמת" או "שקר", עפ"י ערכי המשתנים, שמשמשת בדרך כלל במשפטי תנאי (if) או בלולאות. בעיקר יש לשים לב לכך שמכיוון שביטוי הצבה מחזיר ערך, המהדר עלול שלא להתריע בפני בלבול אפשרי. לדוגמא, במקרה הבא int x=5, y=2; if(x=y) printf("x and y are equal"); לא תתקבל מהמהדר הודעת שגיאה! (מהדרים מסוימים יציגו הודעת אזהרה) זאת מכיוון שביטוי ההצבה מחזיר את ערך ההצבה, וערך זה חוקי כערך בוליאני. כלומר בפועל יבוצע if(2) printf("x and y are equal"); ותודפס הודעת השוויון! ביטויי הצבה מקוצריםניתן לכתוב ביטויי הצבה באופן מקוצר: למשל את הביטוי
x = x + 5;
ניתן לכתוב כך:
x += 5;
קיצור זה אפשרי עבור כל האופרטורים הבאים:
חמשת האופרטורים משמאל הם האופרטורים החשבוניים, וחמשת האופרטורים מימין הם אופרטורים הפועלים על סיביות. דוגמאות: int x=2, y=8, z=0; x += 3; /* x = 5 */ z -= x+y; /* z = -13 */ z /= x; /* z = -13/5 = -2 */ z %= 8; /* z = -2 % 8 = -2 */ z <<= 2; /* z = -8 */ z &= 0; /* z = 0 */ שים/י לב: ההוראה
x = - 3;
אינה הצבה מקוצרת אלא הצבה של הערך -3 למשתנה x. בהצבה מקוצרת מופיע האופרטור משמאל לפעולת ההצבה:
x -= 3;
האופרטורים ב- C עפ"י קדימויותהטבלה שבעמ' 78 מציגה את האופרטורים ב- C עפ"י קדימויות. אופרטורים בשורה נתונה בטבלה הם בעלי קדימות גבוהה מאופרטורים בשורה נמוכה יותר. לדוגמא, הביטוי 3 + 4 * 5 יחושב ע"י הכפלת 4 ב- 5 ואח"כ חיבור ל- 3. הביטוי שקול ל- 3 + (4 * 5) הסוגריים ( ) הם בעלי הקדימות הגבוהה ביותר בטבלה. לכן, אם רוצים לתת קדימות לביטוי מסויים, ניתן להקיפו בסוגריים. לדוגמא: (3 + 4) * 5 העמודה השמאלית קובעת את כוון הפעלת האופרטור. לדוגמא, הביטוי x1 / x2 / x3 יחושב ע"י חילוק x1 ב- x2, ואחר כך חילוק התוצאה ב- x3. כלומר, אם נשתמש בסוגריים לציון הקדימות, הביטוי השקול הוא (x1 / x2) / x3 ולא x1 / (x2 / x3) זאת מכיוון שלאופרטור / סדר ביצוע משמאל לימין. לעומת זאת, הביטוי
x1 = x2 = x3 + 1;
יחושב ע"י הצבת (x3+1) ל- x2, ואחר כך הצבת התוצאה ל- x1. זאת מכיוון שלאופרטור ההצבה "=" סדר ביצוע מימין לשמאל. דוגמאות: #include <stdio.h> void main ( ) { int i = 2, j=6, k=10; int s; s = i + j * k; /* s = 62 */ s = (i + j)* k; /* s = 80 */ s = k / i * j; /* s = 30 */ s = j / i++ ; /* s = 3 */ } בביטוי האחרון, לאופרטור ++ יש עדיפות על פני אופרטור החילוק /, אולם מכיוון שהוא בצורת postfix הוא מבוצע רק לאחר חישוב הביטוי כולו. המרת טיפוסיםהמרה מרומזתניתן לכתוב ביטויים בהם מעורבים משתנים מטיפוסים שונים - במקרה זה מבוצעת המרה אוטומטית לטיפוס המתאים. בדרך כלל נקבל אזהרה מהמהדר על ביצוע המרה כזו. לדוגמא, המרה מרומזת של מספר ממשי לשלם גורמת לקיצוץ חלק השבר ולאיבוד מידע, ולכן גוררת הודעת אזהרה מהמהדר: int i; float f=14.5; i = f; /* i = 14 */ בהמרת שלם לממשי אין איבוד מידע: int i=14; float f; f = i; /* f = 14.0 */ בנוסף לפעולת הצבה, המרה מרומזת יכולה להתרחש במהלך ביטויים חשבוניים: float f; f = 4 / 5; /* f=0.0 */ f = 4.0 / 5; /* f=0.8 */ הסבר: בביטוי הראשון מבוצעת פעולת חילוק שלמים שתוצאתה היא 0. רק לאחר מכן התוצאה מומרת לממשי 0.0. כלומר ההמרה מבוצעת באופרטור ההצבה. בביטוי השני, אופרטור החילוק / נדרש לבצע חילוק של ממשי בשלם - לצורך כך השלם מומר תחילה לממשי ורק אז מתבצעת פעולת החילוק. ככלל, בביטוי מעורב משתנה מטיפוס "נמוך" יותר מומר לטיפוס ה"גבוה". טבלת הקדימויות לצורך המרה:
כיצד מומר משתנה מטיפוס נמוך לטיפוס גבוה? הטבלה הבאה מתארת מה מתבצע בפועל בהמרה:
המרה מפורשת (casting)לפעמים נדרשת המרה מפורשת בתכנית כדי לאלץ פרשנות מסוימת של הביטוי החשבוני. לדוגמא, בתכנית הבאה קיימת בעיה: float f; int i = 5, j=12; f = j / i; /* f = 2.0 */ כדי לאלץ פעולת חילוק בממשיים נכתוב: float f; int i = 5, j=12; f = j / (float) i; /* f = 2.4 */ פעולת המרה יזומה בין טיפוסים מוגדרת כך: ביטוי (טיפוס) תוצאת הביטוי תומר לטיפוס המצוין. האופרטור sizeofהאופרטור sizeof הוא אופרטור אונרי המחזיר את הגודל בבתים (bytes) של ביטוי, טיפוס או משתנה. אופן השימוש: 1) sizeof(ביטוי) 2) sizeof(טיפוס) 3) sizeof(משתנה) אופרטור זה תמיד מחזיר שלם חיובי. לדוגמא, תכנית להדפסת הגדלים של מספר טיפוסים בסיסיים ב- C: #include <stdio.h> void main ( ) { printf("the size of integer is %d\n", sizeof(int)); printf("the size of short is %d\n", sizeof(short)); printf("the size of long is %d\n", sizeof(long)); printf("the size of double is %d\n", sizeof(double)); } פלט התכנית, כפי שהתקבל במערכת הפעלה Windows על מחשב Intel-Pentium : the size of integer is 4 the size of short is 2 the size of long is 4 the size of double is 8 סיכום
תרגילי סיכוםבצע/י את תר' 1-3 שבעמ' 83-84.
|