מ"זה מתהדר" ל"אני מבין את זה"
בעמוד הקודם לקחתם קובץ מקור והפכתם אותו לתוכנית רצה בעזרת מהדר. עכשיו נאט ונסתכל על מה בעצם היה בקובץ הזה. כל תוכנית C++ בנויה מאותה חופן של חלקים מבניים, וברגע שתדעו לתת להם שמות, קובץ .cpp לא מוכר יפסיק להיראות כמו רעש.
הנה תוכנית מלאה שאפשר להריץ. קראו אותה פעם אחת, ואז נפרק אותה שורה אחרי שורה.
חמש שורות משמעותיות, וכל אחת מהן עושה עבודה מסוימת. בואו נעבור עליהן.
השורה #include
#include <iostream>
השורה הזו מכניסה את ה-header <iostream>, כדי שתוכלו להשתמש ביכולות קלט/פלט כמו cout. ה-#include הוא הנחיית preprocessor: הוא רץ לפני ההידור האמיתי ובעצם מדביק את התוכן של ה-header הזה לתוך הקובץ שלכם.
שני דברים הופכים שורות #include למיוחדות:
- הן מתחילות ב-
#, שמסמן אותן כהנחיות preprocessor. - הן לא מסתיימות בנקודה-פסיק. זה החריג הנפוץ היחיד להרגל "כל שורה נגמרת ב-
;" שאתם עומדים לפתח.
אם אתם משתמשים ב-cout אבל שוכחים את #include <iostream>, המהדר לא יידע מה זה cout ותקבלו שגיאה כמו 'cout' was not declared in this scope. התיקון הוא כמעט תמיד include חסר.
הפונקציה main
int main() {
// ...
return 0;
}
main היא המקום שבו התוכנית שלכם מתחילה. כשמריצים את התוכנית המהודרת, הביצוע מתחיל בשורה הראשונה בתוך main ונעצר כש-main מחזירה ערך. לכל תוכנית C++ יש בדיוק main אחת, לא יותר ולא פחות.
החלקים:
int:mainמחזירה מספר שלם למערכת ההפעלה. לפי המוסכמה,0אומר "הסתיים בהצלחה".main(): השם, ואחריו סוגריים לפרמטרים שלה (ריקים כאן).{ ... }: הסוגריים המסולסלים עוטפים את הגוף, כלומר את הפקודות שרצות.return 0;: מסיים אתmainומדווח על הצלחה. אם משמיטים אותו, C++ מתייחסת ל-mainכאילו החזירה0בשבילכם, אבל כתיבה מפורשת הופכת את הכוונה שלכם לברורה.
פקודות ונקודה-פסיק
פקודה (statement) היא הוראה שלמה אחת. ב-C++, כל פקודה מסתיימת בנקודה-פסיק:
C++ מתעלמת לגמרי משבירות שורה ומרווחים מיותרים. למהדר לא אכפת אם שמים פקודות בשורה אחת או בעשר: ה-; הוא מה שאומר לו איפה כל פקודה נגמרת. שלושת אלה זהים לגמרי מבחינת המהדר:
int a = 1; int b = 2;
int a = 1;
int b = 2;
int
a
= 1;
החופש הזה מגיע עם המלכודת הנפוצה ביותר של מתחילים: נקודה-פסיק שנשכחה. שימו לב מה קורה כאן.
int x = 5 // <-- אין נקודה-פסיק
int y = 10;
תקבלו שגיאה כמו expected ';' before 'int'. שימו לב למלכודת: המהדר מבין שמשהו לא בסדר רק כשהוא מגיע לשורה הבאה, ולכן מספר השורה שמדווח מצביע לרוב על שורה אחת מתחת לטעות האמיתית. כששגיאה מזכירה ; חסר, בדקו את השורה שמעל זו שבהודעה.
סוגריים מסולסלים מגדירים בלוקים
בעוד ששפות מסוימות משתמשות בהזחה כדי לקבץ קוד, C++ משתמשת בסוגריים מסולסלים { }. כל מה שבין זוג סוגריים תואם הוא בלוק אחד. גופי פונקציות, לולאות ופקודות if משתמשים בהם:
שתי השורות שבתוך הסוגריים של ה-if רצות רק כשהתנאי נכון. ה-cout האחרון נמצא מחוץ לסוגריים, ולכן הוא תמיד רץ.
מכיוון שהסוגריים, ולא ההזחה, מגדירים את המבנה, C++ לא מכריחה אתכם להזיח. אבל כדאי בכל זאת: הזחה היא הדרך שבה בני אדם קוראים את המבנה שהסוגריים מגדירים. באג נפוץ הוא סוגר לא תואם: כל { צריך } סוגר. אם שוכחים אחד, המהדר מדווח בדרך כלל על שגיאה ליד סוף הקובץ (expected '}' at end of input), רחוק מהמקום שבו בעצם טעיתם. ספירת הסוגריים, או לתת לעורך להתאים אותם בשבילכם, חוסכת הרבה בלבול.
פלט עם cout ו-<<
ראיתם את cout כבר כמה פעמים. זה זרם הפלט הסטנדרטי, ושולחים אליו ערכים עם האופרטור << (קראו אותו כ"הכנס את זה לפלט"):
אפשר לשרשר << כדי להדפיס כמה דברים ברצף. endl מסיים את השורה (וגם מרוקן את הבאפר); רצף הבריחה "\n" הוא דרך קלה יותר להדפיס שורה חדשה. בתוכניות פשוטות שתי האפשרויות בסדר.
לגבי ה-using namespace std; שבראש הקובץ: שמות מהספרייה הסטנדרטית נמצאים במרחב השמות std, ולכן השם המלא הוא std::cout. כתיבת using namespace std; פעם אחת מאפשרת לוותר על הקידומת std:: ולכתוב פשוט cout. זה נוח בדוגמאות קצרות, אבל בפרויקטים גדולים יותר צוותים רבים מעדיפים את std::cout המפורש כדי להימנע מהתנגשויות שמות, אז אל תופתעו לראות את זה כתוב בשתי הדרכים.
עכשיו אתם יכולים לקרוא את השלד של כל תוכנית
includes למעלה, פונקציית main כנקודת הכניסה, פקודות שמסתיימות בנקודה-פסיק, סוגריים מסולסלים שמקבצים קוד לבלוקים, ו-cout << לפלט: השלד הזה נמצא כמעט בכל קובץ C++ שתפתחו אי פעם. שאר השפה הוא פרטים שנבנים מעל הצורות הבודדות האלה. כשתוכנית נראית מאיימת, מצאו קודם את main, ואז קראו את הפקודות לפי הסדר; המבנה ידריך אתכם.
הבא בתור: הערות
כרגע כל שורה בתוכניות שלכם היא קוד שהמהדר קורא. בהמשך נוסיף שורות שהוא מתעלם מהן בכוונה, הערות, כדי שתוכלו להשאיר הערות לעצמכם ולקוראים אחרים. תראו את צורת השורה האחת // ואת צורת הבלוק /* ... */, ומתי כל אחת מהן היא הבחירה הנכונה.
שאלות נפוצות
למה כל פקודה ב-C++ צריכה נקודה-פסיק?
C++ מתעלמת משבירות שורה ומרווחים, ולכן היא צריכה סימן מפורש לאיפה פקודה אחת נגמרת והבאה מתחילה. הסימן הזה הוא הנקודה-פסיק ;. נקודה-פסיק חסרה היא שגיאת ההידור הנפוצה ביותר אצל מתחילים, ומספר השורה שמדווח הוא לרוב השורה שאחרי זו שבה שכחתם אותה.
מה עושה int main() ב-C++?
main היא הפונקציה שממנה התוכנית מתחילה לרוץ: הביצוע מתחיל בשורה הראשונה שלה ונגמר כשהיא מחזירה ערך. כל תוכנית C++ צריכה בדיוק main אחת. ה-int אומר שהיא מחזירה קוד סטטוס שלם למערכת ההפעלה, שבו 0 מסמן לפי המוסכמה הצלחה.
האם חייבים לכתוב std:: לפני cout?
או שכותבים std::cout (השם המלא), או שמוסיפים using namespace std; פעם אחת בראש הקובץ ואז כותבים פשוט cout. הצורה המלאה בטוחה יותר בקבצים גדולים; using namespace std; הוא קיצור נפוץ בדוגמאות קטנות ובמדריכים.