C++/משתנים
משתנה הוא הישות הבסיסית איתה עובדת התוכנית, הוא מרחב בזיכרון המכיל נתונים. כל הנתונים במחשבים מוצגים באמצעות סיביות (במחשבים בינאריים אלה אפסים ואחדות). הסיביות מקובצות לבתים, כאשר ברוב המחשבים הבית מורכב מ-8 סיביות. נפח הזיכרון נמדד בבתים, לכל בית בזיכרון המחשב ישנה כתובת יחודית משלו - זו הסיבה שהתוכנית יכולה לעבוד אך ורק עם בתים וקבוצות שלהם. כדי לשנות רק סיביות מסויימות מתוך הבית, יש להשתמש בפעולות מיוחדות.
טיפוסים
[עריכה]כנאמר, כל משתנה מוצג בזכרון המחשב בתור סדרת אפסים ואחדות. אמנם בעת כתיבת התוכנית חשוב לנו להגדיר את סוג הנתונים שנשמרים במשתנה. סוג המשתנה נקרא גם טיפוס. טיפוסים בסיסיים שמוגדרים בתקן של השפה עצמה, נקראים טיפוסים מובנים. להלן רשימת הטיפוסים המובנים בשפת C++:
שם הטיפוס | גודל[1] | טווח ערכים מינימלי[2] |
---|---|---|
char | 8 ביטים לפחות | 0 ~ 127 |
signed char | שווה ל-char | -128 ~ 127 |
unsigned char | שווה ל-char | 0 ~ 255 |
short signed short short int signed short int |
16 ביטים לפחות גדול או שווה ל-char |
-32768 ~ 32767 |
unsigned short unsigned short int |
שווה ל-short | 0 ~ 65535 |
int signed int signed |
גדול או שווה ל-short | -32768 ~ 32767 |
unsigned unsigned int |
שווה ל-int | 0 ~ 65535 |
long signed long long int signed long int |
32 ביטים לפחות גדול או שווה ל-int |
-2147483648 ~ 2147483647 |
unsigned long unsigned long int |
שווה ל-long | 0 ~ 4294967295 |
float | גדול או שווה ל-char | לא מוגדר |
double | גדול או שווה ל-float | לא מוגדר |
long double | גדול או שווה ל-double | לא מוגדר |
bool | גדול או שווה ל-char קטן או שווה ל-long |
true או false |
wchar_t | גדול או שווה ל-char קטן או שווה ל-long |
הערות
[עריכה][1] התקן לא מגדיר את הגודל המדוייק של הטיפוסים, אלא רק את גודלם המזערי והיחסי. כדי לקבל את טווח הערכים של טיפוס מסויים, יש להשתמש בתבנית numeric_limits שבספריה <limits> התקנית.
[2] טווחי הערכים המובאים בטבלה הינם הערכים שניתנים לייצוג בכל המערכות ללא תלות במערכת. למשל משתנה ה-char יכול להכיל לפחות 256 ערכים שונים. 128 הערכים הנוספים יכולים להיות או בין 127 ל-256 או בין -128 ל-0. שימו לב שהטווח המובא בטבלה עבור משתנים עם סימן שווה עבור ערכים שליליים וחיוביים על אף שברוב המחשבים יש ערך אחד יותר בשליליים. הסיבה היא שברוב המערכות הערכים השליליים מיוצגים בשיטת המשלים ל-2 הנפוצה, אבל קיימות גם שיטות אחרות על אף שהן כמעט ולא בשימוש.
טיפוסים תוויים
[עריכה]הטיפוס char עשוי להכיל תו אחד ויחיד. כיוון ש-char לבדו יכול להיות עם סימן או בלעדיו, בהתאם למערכת, טווח ערכים המובטח הוא בין 0 ל-127. לטווח זה נכנסים כל תווי ה-ASCII. כאשר אתם משתמשים במשתנה תווי זה לשמירת ערכים מספריים, כיתבו האם אתם מתכוונים ל-signed או-unsigned.
wchar_t זהה ל-char מלבד שהוא גדול מספיק כדי להכיל את כל התווים האפשריים במערכת.
טיפוסים שלמים
[עריכה]כל טיפוסי ה-int יכולים להכיל אך ורק מספרים שלמים. ה-int הרגיל הוא הטיפוס השלם המתאים ביותר למכונה שלכם, למשל במחשבי 16 ביט גודלו 16 ביט ואילו במחשבי 32 ביט גודלו 32 ביט. יש להעדיף את ה-int הרגיל על פני שאר הטיפוסים השלמים, אלא אם כן עליכם לחסוך בזיכרון או להרחיב את טווח הערכים.
נקודה צפה
[עריכה]float, double ו-long double שייכים לקטגוריה זו. נקודה צפה היא פורמט המאפשר לשמור מספרים ממשיים (שברים) באמצעות מנטיסה ומעריך. שיטה זו מאפשרת לעבוד עם מספרים גדולים מאוד וקטנים מאוד (בערך המוחלט), כאשר בקירבת האפס הדיוק גדול יותר מאשר רחוק ממנו. לדוגמה נוכל לרשום את המרחק עד לאלפא קנטאורי בצורה: 4.129e+16 (מטרים) ואילו את גודל אטום הליום בצורה: 3.1e-11 (מטרים).
כמו במקרה של הטיפוסים השלמים, גם כאן יש להעדיף את השימוש ב-double אלא אם כן יש צורך לחסוך בזיכרון או להעלות את דיוק החישובים.
טיפוס בוליאני
[עריכה]bool הוא טיפוס בוליאני, כלומר הוא יכול לקבל את הערכים true (אמת) או false (שקר).
sizeof
[עריכה]האופרטור (פעולה) sizeof מחזירה את גודל הטיפוס הנרשם בסוגריים:
cout << "sizeof(int) == " << sizeof(int) << endl;
הטיפוס של הערך שמוחזר על ידי sizeof הוא size_t. טיפוס זה לא נמצא בטבלה שלמעלה, אלא הוא אחד מהטיפוסים השלמים שמובאים שם, תלוי במערכת. שימו לב שהגודל נמדד ב-char-ים, כלומר "כמה משתני char נכנסים למשתנה int". על מנת לקבל את הגודל בסיביות יש להשתמש ב-numeric_limits.
הצהרת משתנים
[עריכה]ב-C++ יש להצהיר על משתנה לפני השימוש הראשון בו. ניתן להצהיר משתנה כמעט בכל מקום בתוכנית, כולל תנאים לוגיים ולולאות. הצהרת המשתנה תראה כך:
int variable;
כאשר נוכל להחליף את int בטיפוס כלשהו ואת variable בשם כלשהו. בדוגמה זו הצהרנו על משתנה בשם variable מטיפוס שלם.
ניתן להצהיר באותה שורה על מספר משתנים מאותו טיפוס ואף לאתחל אותם:
double alphaCentauri = 4.129e+16, radiusOfHelium = 3.1e-11;
לאתחל משתנה זה לשמור ערך בתוך המשתנה ברגע שהוא נוצר. מומלץ לאתחל משתנים ככל היותר מוקדם, רצוי בנקודת ההצהרה. אם נקרא מהמשתנה לפני שנאתחל אותו בערך הגיוני, הערך שיוחזר יהיה "אקראי" והתוכנית עלולה לתפקד באופן לא צפוי ואף לקרוס.
שמות
[עריכה]נוכל לתת למשתנים כל שם שנרצה שיתאים לכללים הבאים:
- השם יתחיל באחת האותיות הלטיניות (a-z, A-Z) או בקו תחתון (_).
- השם לא יתחיל בספרה (0-9) על מנת שהמהדר יוכל להבדיל בין שמות למספרים.
- שאר התווים בשם יהיו אותיות לטיניות, ספרות או קוים תחתונים.
- אסור להשתמש במילים שמורות בתור שמות.
C++ מבדילה בין תווים גדולים לבין תווים קטנים, כך ש-Var, var, vAr ו-vaR אלה ארבעה שמות שונים.
בכל שפת תכנות, גם ב-C++, נהוג לכנות לכל משתנה לפי תפקידו. זו אינה חובה כלל אך הדבר מקל לקרוא, להבין ולכתוב את הקוד.
פלט וקלט
[עריכה]כבר ראינו כיצד ניתן לשלוח מחרוזת או ערך מסויים אל תוך אובייקט ה-std::cout שידפיס את הטקסט על המסך או באמצעי פלט אחר במערכת. באותה דרך נוכל לפלוט גם את ערכו של משתנה:
cout << "The distance to Alpha Centauri is " << alphaCentauri << " meters.\n";
הטקסט שבין הגרשיים יודפס כמו שהוא ואילו הטקסט שלא בגרשיים (alphaCentauri) יחושב ויומר לרצף תווים שיודפסו. כתוצאה יופיע בפלט הטקסט:
The distance to Alpha Centauri is 4.129e+016 meters.
נוכל גם לקלוט ערך לתוך משתנה. לצורך זה משמש אובייקט ה-std::cin ואופרטור הקלט << (קלוט מ-). אובייקט cin זה, בדומה ל-cout, מקבל את הקלט מאיזשהו אמצעי קלט במערכת, לרוב אמצעי זה, כברירת מחדל, הוא המקלדת. לדוגמה נוכל להדפיס בקשה מהמשתמש להזין את גילו ולאחר מכן לקלוט את אשר יקליד לתוך משתנה שלם:
cout << "Enter your age:\n";
int age;
cin >> age;
לאחר ביצוע שורות אלה יימצא בתוך משתנה age המספר שהקליד המשתמש. במקרה והוא יקליד משהו לא מספרי ניתן יהיה לזהות זאת באמצעות בדיקת המצב של האובייקט cin, אומנם בדוגמות שבספר זה נניח לצורך הפשטות את תקינות הקלט.
כנאמר כבר בספר זה, cout לאו דווקא מדפיס את הפלט למסך ו-cin לאו דווקא קולט את הקלט מהמקלדת. לדוגמה אם נריץ את התוכנית בשם ourProg.exe משורת הפקודה תחת Linux או Microsoft Windows בצורה הבאה:
cat input.txt | ourProg.exe > output.txt
(ב-Microsoft Windows יש להשתמש בפקודה type במקום הפקודה cat), אזי כל הקלט מ-cin ייקרא מתוך קובץ בשם input.txt מבלי לחכות עד שהמשתמש יקליד אותו במקלדת, ואילו כל הפלט ל-cout יישמר בקובץ בשם output.txt מבלי להופיע על המסך.
ישנם פרמטרים רבים אצל האובייקטים cout ו-cin (הם מופעי המחלקות ostream ו-istream) שמאפשרים לשלוט במראה הפלט ובאופן הקלט. אנו לא נעסוק בהם במסגרת ספר זה מהסיבה שהם חלק מנושא גדול בפני עצמו: הספרייה התקנית של C++.
ביטויים
[עריכה]"ביטוי" בתכנות דומה ל-"ביטוי" במתמטיקה. בשפות תכנות ישנם כללים ברורים לכתיבת ביטויים, כך שאם נחרוג מכללים אלה המהדר לא יבין את הביטוי ויתן הודעת שגיאה.
כל ביטוי מורכב מפעולות ופרמטרים איתם מתבצעות הפעולות, פעולות אלו נקראות אופרטורים ואילו הפרמטרים איתם עובדים האופרטורים נקראים אופרנדים. האופרטורים מתחלקים ל-3 קטגוריות עיקריות הבאות:
- יונאריים - כאלה שעובדים עם אופרנד אחד. לדוגמה "מינוס":
-x
(הופך את הסימן של המשתנה x). - בינאריים - עובדים עם שני אופרנדים. לדוגמה "פחות":
x - y
(מוצא את ההפרש של x ו-y). - טרנאריים - עובדים עם שלושה אופרנדים. ב-C++ יש אחד כזה, והוא אופרטור ההתניה.
האופרנדים יכולים להיות קבועים (מספרים ומחרוזות) או משתנים שהגדרנו. לדוגמה נוכל לחשב כמה אטומי הליום יש להציב בשורה כדי להגיע עד לאלפא קנטאורי:
double alphaCentauri = 4.129e+16, radiusOfHelium = 3.1e-11;
alphaCentauri / radiusOfHelium;
הביטוי בשורה השנייה מורכב מאופרטור בינארי "חילוק" ושני אופרנדים שהם המשתנים שהגדרנו אותם שורה למעלה.
הביטוי שרשמנו כאן לא שימושי במיוחד, הוא מחשב את המנה אך לא שומר אותה בשום מקום. נוכל לשמור את התוצאה של החישוב במשתנה אחר. תחילה נברר מה אמור להיות הטיפוס של משתנה זה.
טיפוס הביטוי
[עריכה]כל ביטוי מחזיר איזשהי תוצאה, לכל ערך ב-C++ יש טיפוס. הכללים למציאת טיפוס זה די הגיוניים ואינטואיטיביים. הכלל הבסיסי הוא: לקדם את הטיפוסים של האופרנדים אל טיפוס שיוכל להכיל את כל הערכים של הטיפוסים המקוריים ללא איבוד מידע. אם המהדר לא מוצא טיפוס שיתאים אז הוא יתן הודעת שגיאה ונצטרך לעשות המרה בעצמנו.
למשל כאשר אנחנו מחברים שני מספרים שלמים מטיפוס unsigned short, התוצאה תהיה גם היא unsigned short (יתכן שהמהדר ירחיב אותה ל-unsigned int). אך אם נחבר מספר שלם עם נקודה צפה אז התוצאה תהיה נקודה צפה (כי double לרוב יכול להכיל את כל הערכים של int, אבל אף פעם לא להיפך). כאשר נחבר signed ו-unsigned נקבל שגיאה.
לדוגמה, נציב את התוצאה של החילוק מהדוגמה הקודמת למשתנה חדש:
double lengthOfChain = alphaCentauri / radiusOfHelium;
אופרטורים
[עריכה]נסכם בקצרה את האופרטורים הבסיסיים הקיימים ב-C++.
פעולות חשבוניות
[עריכה]ב-C++ נרשום את ארבעת פעולות החשבון הבסיסיות באמצעות הסימנים הרגילים שלהם. כמו כן נוכל לחשב את שארית החילוק השלם (מודולו) באמצעות הסימן "אחוז":
5 + 6; // הסכום הוא 11
10 - 7; // ההפרש הוא 3
3 * 4; // המכפלה היא 12
13 / 3; // המנה היא 4
13 % 3; // השארית היא 1
שימו לב שלא קיים אופרטור "להעלות בחזקה". כמו כן פעולת החילוק מחזירה תוצאה שלמה כאשר האופרנדים מטיפוס שלם.
פעולות השוואה
[עריכה]ב-C++ נוכל להשוות שני ערכים בינהם ולקבל תשובה מטיפוס בוליאני (true או false) על השאלה האם האחד גדול מהשני או האם הם שווים או לא. לביצוע השוואה כזו נשתמש בסימנים הבאים:
5 < 10; // 5 קטן מ-10? תשובה true
10 <= 10; // 10 קטן או שווה ל-10? תשובה true
10 > 10; // 10 גדול מ-10? תשובה false
10 >= a; // 10 גדול או שווה למשתנה a? תשובה תחושב בהתאם למשתנה a
a == b; // המשתנה a שווה למשתנה b?
a != b; // המשתנה a שונה ממשתנה b?
התוצאה של כל השוואה כזאת היא בוליאנית ונוכל לשמור אותה במשתנה מטיפוס בוליאני, אבל לרוב משתמשים בתוצאה זו בתנאים ולולאות שתלמדו עליהם בהמשך.
חשוב לא להתבלבל בין השוואה, '==', לבין השמה, סימן '=' אחד. הדבר גורם לבעיות נסתרות בבדיקת תנאים.
פעולות בוליאניות
[עריכה]פעולות בוליאניות, לעיתים נקראות גם פעולות לוגיות. פעולות אלה מקבלות אופרנדים מטיפוס לוגי (bool) ומחזירות תוצאה בהתאם שגם היא מטיפוס זה. בדרך כלל משתמשים בפעולות אלה כדי לחבר תוצאה של כמה השוואות פשוטות ולהרכיב משפט לוגי מורכב. לדוגמה נוכל לבדוק האם המשתנה a נמצא בין 10 ל-20 כולל באמצעות בדיקת שתי טענות פשוטות יותר: "a גדול או שווה ל-10" וגם "a קטן או שווה ל-20". שימו לב שהשתמשנו במילה "וגם" שמשמעותה היא לאחד את תוצאות שני הביטויים ולהחליט האם הביטוי כולו נכון. להלן הפעולות הבוליאניות הקיימות ב-C++:
- קוניוקציה (וגם, AND) – תסומן בסימן && (שני אמפרסנדים) ותחזיר true אך ורק אם שני האופרנדים שווים ל-true. אם אחד האופרנדים שקרי (שווה ל-false) אז כל הביטוי יהפוך לשקרי. כאשר התוכנית תחשב תוצאה של ביטוי המשתמש באופרטור זה היא תחשב את האופרנדים לפי הסדר שבו הם נרשמו על אף שאין לזה השפעה ישירה על תוצאת הביטוי. במקרה והאופרנד הראשון יהיה יתברר כשקרי התוכנית לא תמשיך לחישוב האופרנד הבא כי תוצאת הביטוי כבר ידועה.
- דיסיונקציה (או, OR) – תסומן בסימן || (שני קווים אנכיים) ותחזיר true אם לפחות אחד משני האופרנדים שווה ל-true. יוחזר false רק כאשר שני האופרנדים מקבלים את הערך false. בדומה לאופרטור && האופרנדים יחושבו לפי סדר כתיבתם וכאשר הראשון יקבל ערך true השני לא יחושב אלה תוחזר התוצאה הכוללת true.
- שלילה (לא, NOT) – תסומן בסימן ! (סימן קריאה) ותחזיר את הפכו של האופרנד היחיד שלה. במילים אחרות: אם תוצאת האופרנד היא true, יוחזר false; אם תוצאת האופרנד היא false, יוחזר true.
לדוגמה:
false || true; // תוצאה true
a == b && a != b; // תוצאה false
!(a > 10 && a < 20); // a לא בין 10 ו-20
a <= 10 || a >= 20; // אותו דבר, a לא בין 10 ו-20
כדאי לדעת: את פעולת ה-XOR הלוגי ניתן לבצע באמצעות אופרטור ההשוואה != (שונה). |
פעולות על סיביות
[עריכה]כנאמר בתחילת הפרק, לתוכניות אין גישה ישירה לסיביות נפרדות מהן מורכבים המשתנים, אך ניתן לגשת אליהם באמצעות פעולות מיוחדות.
השמות
[עריכה]מלבד ההשמה הרגילה אותה הכרנו למעלה קיימים קיצורים לצירופים מהתבנית a = a ■ b כאשר a הוא משתנה מטיפוס מובנה, b הוא ביטוי כלשהו (גם הוא מטיפוס מובנה) ו-■ הוא אחת מפעולות החשבוניות או פעולה על סיביות. נוכל לקצר בצורה הבאה: a ■= b. לדוגמה:
a = 10; // שומרים בתוך משתנה a את המספר 10
a += 3; // מוסיפים לערך של a את המספר 3, התוצאה 13
a -= 4; // עכשיו בתוך a נמצא המספר 9
a *= 4;
a /= 3;
a %= 5;
b &= 0; // מאפסים את b בשיטה של גימום עם 0
b ^= 5; // עכשיו יש פה את המספר 5
b <<= 3;
a |= b;
b >>= 1;
שימו לב שלא קיים אופרטור ■, השתמשנו באופרטור זה בתור הדגמה.
הפרק הקודם: שלום עולם! |
משתנים | הפרק הבא: תנאים |