מרכיבים בסיסיים של תוכנית 

 

 


תוכן הפרק

תוכניות בסיסיות

מבנה בסיסי של תוכנית

תוכנית המדפיסה הודעה על המסך

תוכנית המדפיסה מספר שורות

תוכנית המדפיסה תוצאת חישוב וממתינה להקשת מקש

תוכנית המשתמשת במשתנה

תוכניות המשתמשת בתנאי

מיון שני מספרים

קליטת תו מהמשתמש

מיון 3 מספרים ושימוש במערך

קליטת מילה אחת - לתוך מערך תווים

פתרון של משוואה ריבועית

לולאה פשוטה

משתמשים בלולאת  for כאשר ידוע לפני תחילת הלולאה כמה איטרציות תהינה

לולאת  while משמשת בד"כ למספר בלתי ידוע מראש של איטרציות

פירוט טיפוסיי המשתנים הבסיסיים בשפה

מספרים שלמים  Integral types:  char, short, int, long

טיפוסי מספרים ממשיים או נקודה צפה  -  float, double, long double

טיפוסי תווים   char : characters

טבלת ערכי ascii

Booleanאמת או שקר:  bool

הגדרות של משתנים וקבועים

אופן הגדרה ואתחול

שימוש בקבועים

מפעילים פשוטים   simple operators

מפעילים מספריים    numeric operators

קידום טיפוס במפעילים בינאריים      Type promotion

סדר קדימויות  Priority

מפעילים של קידום והורדה ב 1  ++,  --

מפעיל השמה  =

מפעילי השמה נוספים  +=, -=, *=, /=, %=

מפעילים לוגיים boolean operators

טבלת מפעילים

הוראות  Statements

הוראת הגדרת משתנה  Varaiable dfinition statemens

הוראת ביטוי  Expression Statement

הוראה מורכבת  Compound Statement

איפה חשובים הרווחים - מפרידים ואסימונים  tokens

הוראות בחירה    if  switch

הוראת  if statement

הוראת  if-else statement

בחירת בצוע לפי אפשרויות של ערכים קבועים  switch statement

המפעיל      :  ?

לולאות Loops

הוראת  while

הוראת  do-while

המפעיל  ,  פסיק

לולאת for

הוראות  break, continue  בלולאות

תכנון טוב של לולאות

משחק ניחוש מספרים

מחלקה פשוטה ועצמים פשוטים - שימוש במבנה  struct

מערכים  arrays

הגדרת מערכים

הגדרת גודל ואתחול של מערכים

מחרוזות תווים

שימוש במערך

שימוש הגיוני בהוראת  goto

הגדרת שם חילופי לטיפוס  typedef

 

תוכניות בסיסיות

מבנה בסיסי של תוכנית

שלד בסיסי של תוכנית שאינו מבצע דבר

void main()

{

  . . .

}

 

הקוד שלפנינו הוא המינימום הנמצא בכל תוכנית c++.

·            כל תוכנית חייבת להכיל פעולה ראשית (פונקציה ראשית)  בשם  main().

·            השם  main  מציינת כי זוהי הפעולה הראשית של התוכנית.

·            מה מציינת המילה void  נסביר בהמשך.

·            לאחר מכן בא הגוף  בתוך סוגריים מסולסלים.  { ... }. בתוך הגוף צריכות להופיע סדרת ההוראות שאנו מעוניינים שתבצע התוכנית.

 

במקרה שלנו סדרת ההוראות ריקה ולכן התוכנית אינה מבצעת דבר.

תוכנית המדפיסה הודעה על המסך

נתקדם לתוכנית המדפיסה את השורה  Hello world על מסך המחשב.

 

#include <iostream.h>

void main()

{

    cout << "Hello world";

}

 

------- Output -----------

Hello world

 

·            התוכנית מבצעת הוראה אחת, שהיא להדפיס את המילים   Hello world.

·            הדפסה על המסך (וקליטת נתונים מהמקלדת) מכונות פעולות קלט/פלט.

·            את כל פעולות הקלט/פלט אנו מבצעים, בשפת  C++,  באמצעות שימוש בספריות.

·            ספריה היא אוסף של קטעי תוכניות, הכתובות מראש, שאנו יכולים לשבץ בתוכנית שאנו כותבים.

·            קיימות אלפי פעולות שכבר נמצאות בספריות וזמינות לשימוש לפי הצרכים בתוכנית שלנו. הפעולות מאורגנות לפי נושאים למאות ספריות.

·            בכדי להשתמש בספריה אנו חייבים לכלול קובץ המכיל מידע חיוני לשימוש בספריה. הכללת הקובץ מתבצעת באמצעות ההוראה

  #include <library-name>        כאשר בתוך סוגריים המשולשים מופיע שם של קובץ המכיל את המידע החוץ.

·            Input-Output-Stream השם  iostream  מרמז על ספריה העוסקת בהזרמת נתוני קלט/פלט

·            cout  זהו עצם הפלט התקני (מייצג לרוב את המסך).

·            האופרטור (מפעיל)  <<  פירושו שלח אל עצם הפלט.

·            "Hello world"  מחרוזת של תווים.

·            כל שורת הוראה חייבת להסתיים ב  ;

 

מכאן פירוש שורת ההוראה   cout << "Hello world";       הוא:  שלח את מחרוזת התווים   "Hello world"  אל הפלט התקני (המסך).

 

חזרה להתחלה

תוכנית המדפיסה מספר שורות

#include<iostream.h>

void main()

{

    cout << "L1";

    cout << "L2";

    cout << endl;

    cout << "L3"; 

    cout << endl << "L4" << "L5" << endl << endl;

    cout << "L6"

}

 

------------- Output --------------

L1L2

L3

L4L5

 

L6

          ·          מספר הדפסות המתבצעות אחת אחרי השניה מופיעות על המסך באותה השורה.

          ·          בכדי לרדת שורה במסך אפשר להשתמש ב endl. שליחת endl לפלט פירושו לרדת שורה.
End Line       --  endl.

          ·          אפשר לשלב מספר הדפסות באותה השורה.

 

תוכנית המדפיסה תוצאת חישוב וממתינה להקשת מקש

#include <iostream.h>

void main()

{

    cout << "1 + 2 = ";

    cout << 1 + 2;

    cout << "Press any Key to continue and press Enter...." << endl;

    cin.get();

}

 

---------Output-----------

1 + 2 = 3

Press any Key to continue and press Enter....

 

          ·          התוכנית מדפיסה את ערך תוצאת חישוב הבטוי (1 + 2) שהוא 3.

          ·          + הוא אופרטור החיבור המתבצע על שני אופרנדים: 2  ו  1  ותוצאת פעולתו היא  3.

          ·          עד כה התוכניות הדפיסו על המסך ומייד סיימו עתה התוכנית ממתינה עד שהמשתמש יקיש על מקש וילחץ  Enter.

          ·          cin -- מייצג את עצם הקלט התקני (בדרך כלל מקלדת)  Common Input

          ·          הפעולה get()  המופעלת על עצם הקלט התקני ממתינה עד לקבלת תו אחד מהקלט ולחיצה על מקש  Enter.

          ·          cin.get()  פירושו הפעלת הפעולה  get()     על העצם בשם  cin.

תוכנית המשתמשת במשתנה

          ·          משתנה הוא מקום אחסון עבור ערך יחיד מסוג מסויים.

          ·          לכל משתנה יש שם וכן סוג הנתון שהוא בנוי לאחסן.

          ·          משתנה מסוג  int   בנוי לאחסון מספרים שלמים:   ..., -1, 0, 1, 2, ...

          ·          תוכן המשתנה יכול להשתנות תוך כדי בצוע התוכנית.

          ·          משתמשים במשתנה עבור אחסון תוצאות ביניים בחישוב או מקום לקליטת נתונים מהקלט.

 

/*

    Program sums two numbers

    ========================

*/

#include <iostream.h>

void main()

{

    int a;     // input location for first operand.

    int b;     // input location for second operand.

    int sum;   // result of a + b;

    cin >> a;  // read first operand from keyboard.

    cin >> b;  // read second operand from keyboard.

    sum = a + b;

    cout << "The Sum of " << a << " And " << b <<" Is: ";

    cout << sum << endl;

}

 

---------Example Output-----------

2

3

The Sum of 2 And 3 Is: 5

 

          ·          החל מהסימן  //  ועד לסוף השורה זוהי הערה. עוד סוג של הערות הוא החל מצירוף התווים /*  ועד לצירוף התווים  */  משתמשים        

      בהערה זו להערה בת מספר שורות 

          ·          הערה אינה משפיעה על בצוע התוכנית והיא משמשת אך ורק למידע עבור מתכנת הקורא את קוד התוכנית.

          ·          בתוכני זו אנו מגדירים שלושה משתנים: שניים,  a  ו  b,  כמקום אחסון לנתוני קלט והשלישי   sum לשמירת תוצאת ביניים.

          ·          כל אחד מהמשתנים מיועד להכיל נתון מסוג  int  שהוא מספר שלם  (integer).

          ·          sum = a + b  פירושו חשב את הסכום של a  ו  b   ושים אותו במשתנה  sum.

תוכניות המשתמשת בתנאי

/*  Program prints absolute value of a number

    =========================================

*/

#include <iostream.h>

void main()

{

    int n;   // input number.

    cout << "Enter a number: ";

    cin >> n;   

    if (n < 0)  // if n is negative change

        n = -n;

    cout << n << endl;;

}

 

 

If ( condition)  

הוראה לבצוע במידה והתנאי מתקיים

 

---------Example Output-----------

Enter a number: 4

4

 

---------Example Output-----------

Enter a number: -5

5

          ·           n = -n  הערך הבא במשתנה  n  הוא הערך השלילי של הערך הנוכחי הנמצא בו.

          ·          משפט if בודק את התנאי בסוגריים.  במידה והתנאי מתקיים מתבצעת ההוראה הבאה אחרי if  אחרת מדלגים על ה  if.

/*

    Program test if a number is positive

    ====================================

*/

#include <iostream.h>

void main()

{

    int n;     // input number.

    cout << "Enter a number: ";

    cin >> n;

    cout << "The number " << n << " is ";

    if (n > 0)

        cout << "positive!" << endl;

    else

        cout << "negative!" << endl;

}

---------Example Output-----------

Enter a number: 4

The number 4 is positive!

 

---------Example Output-----------

Enter a number: -5

The number -5 is negative!

 

If ( condition )

הוראה לבצוע במידה והתנאי מתקיים  

else

הוראה לבצוע במקרה והתנאי אינו מתקיים

 

 

 

 

 

          ·          משפט if בודק את התנאי בסוגריים במידה והתנאי מתקיים מתבצעת ההוראה הבאה אחרי if  אחרת מתבצעת ההוראה הבאה אחרי ה  else.

מיון שני מספרים

/*

    Program reads two numbers.

    print the one with low value first

    and then the other one.

    ====================================

*/

#include <iostream.h>

void main()

{

    int a, b;   // input numberes.

    cout << "Enter two numbers: ";

    cin >> a>> b;

    if (a < b)

    {

        int t;  // temporary variable used for swapping two numbers

        t = a;

        a = b;

        b = t;

    }

    cout << "From low to high: " << a << ' ' << b << endl;

}

---------Example Output-----------

Enter two numbers: 1 2

From low to high: 1 2

 

---------Example Output-----------

Enter two numbers: 14 12

From low to high: 12 14

 

במידה ורוצים שתתבצע יותר מהוראה אחת, בעקבות תנאי, אפשר לקבץ בלוק הוראות בתוך סוגריים מסולסלים. אם התנאי ב  if

נכון כל הבלוק מתבצע אחרת מדלגים על כל הבלוק.

בתוך בלוק אפשר להגדיר משתנים חדשים. בדוגמא שלנו משתנה העזר t.

·          לשם החלפת שני מספרים נוהגים להשתמש במשתנה עזר.

תו בודד מייצגים באמצעות גרש תו גרש. לדוגמא: ,'A'  'B'.  זאת בניגוד למחרוזת תווים אותה מייצגים באמצאות מרכאות לדוגמא:  "abc"

 

חזרה להתחלה

קליטת תו מהמשתמש

/*

    Program asks the user a question

    if he type character Y amessage is printed.

    if he type charater N another message is printed

    if he type another charater error message is printed

*/

#include <iostream.h>

void main()

{

    char c; // varaiable used for storing a single character.

    cout << "Would you like to here my message?" << endl;

    cout << "Enter character [Y/N]: " << endl;

    cin  >> c;

    if (c == 'Y' || c == 'y')

    {

        cout << "You are very smart!!" << endl;

        cout << "And know how to choose :-)" << endl;

    }

    else if ( c == 'N' || c == 'n')

    {

        cout << "You are not so bright" << endl;

        cout << "And a loser :-(" << endl;

    }

    else // not Y or N

        cout << "Error: Next time try Y or N" << endl;

    cout << "Press any Key to continue and press Enter...." << endl;

    cin.get();

}

---------Example Output-----------

Would you like to here my message?

Enter character [Y/N]: Y <---- y is different from Y

You are very smart!!

And know how to choose :-)

Press any Key to continue and press Enter....

 

---------Example Output-----------

Would you like to here my message?

Enter character [Y/N]: N

You are not so bright"

And a loser :-(

Press any Key to continue and press Enter....

 

---------Example Output-----------

Would you like to here my message?

Enter character [Y/N]: x     

Error: Next time try Y or N

Press any Key to continue and press Enter....

 

          ·          מציינים תו בודד באמצעות גרשיים, לדוגמא:  'a'  'b'   

          ·          אבל כאשר רוצים לציין מחרוזת של יותר מתן אחד מציינים זרת באמצעות מרכאות, לדוגמא:  "abc".

          ·          ראינו כי כאשר רוצים להציב לתוך משתנה ערך משתמשים באופרטור ההשמה:   c = 'A'  פירושו שמשימים את הערך   'A'

      לתוך המשתנה  c.

          ·          כאשר רוצים לבדוק (ניח בתנאי)  האם הערך של משתנה זהה לערך מסויים משתמשים באופרטור אחר שהוא  ==.

      לדוגמא:   c == 'A'  זוהי שאלה האם הערך במשתנה  c  הוא התו  'A'.

          ·          חשוב לא להתבלבל בין אופרטור ההשמה    =   לבין אופרטור השוואת הערך   ==   !

          ·          האופרטור הלוגי || משמעותו  OR (או)  כלומר מספיק שאחד מהתנאים מתקיים בכדי שהתנאי כולו יתקיים

          ·          אנו משלבים את התנאי   c == 'Y' || c == 'y'  בכדי להבטיח כי אם המשתמש יקיש על המקש y או על  Y  

     נקבל את התשובה כן אחרת רק אות קטנה או גדולה היתה נחשבת לתשובה נכונה.

מיון 3 מספרים ושימוש במערך

/*  Program reads 3 numbers from user

    and prints them in increasing order.

    Algorithm for sorting three numbers:

 1. compare first two - swap values if needed.

 2. compare last two - swap values if needed.

 3. and again compare first two - swap values if needed.

*/

#include <iostream.h>

void main()

{

    // array - sequence of 3 varaibles from type int: a[0], a[1], a[2]

    int a[3];

    int t;    // used for swapping array elements.

 

    // reads three numbers

    cout << "Enter 3 numbers: ";

    cin >> a[0];  // read first int

    cin >> a[1];  // read second int

    cin >> a[2];  // read third int

 

    if (a[0] > a[1])  // compare the first two

    {  t = a[0];

       a[0] = a[1];

       a[1] = t;

    }

    if (a[1] > a[2])  // compare the last two

    {  t = a[1];

       a[1] = a[2];

       a[2] = t;

    }

    if (a[0] > a[1])  // compare the first two

    {  t = a[0];

       a[0] = a[1];

       a[1] = t;

    }

    // print the sorted array elements.

    cout << endl << "Sorted numbers are:" << endl;

    cout << a[0] << ' ' << a[1] << ' ' << a[2] << endl;

}

---------Example Output-----------

Enter 3 numbers: 3 1 4

1 3 4

 

---------Example Output-----------

Enter 3 numbers: 3 2 1

3 2 1

 

---------Example Output-----------

Enter 3 numbers: 123  ? waiting for aditional two numbers

 

          ·          מערך הוא שיטה מקוצרת להגדרת סדרה של משתנים.

          ·          צורת ההגדרה   int a[3];  מגדירה מערך, שהוא סדרה של שלושה משתנים מסוג  int.

          ·          ה  int  הראשון מכונה  a[0]   השני   a[1]   והשלישי   a[2].

          ·          ובאופן כללי     T array[N]    הגדרנו מערך בגודל N איברים כל איבר הוא משתנה מסוג  T.

          ·          המספר  N   הוא מספר קבוע שנקבע בזמן כתיבת התוכנית. וכן אי אפשר לשנות את גודל המערך בזמן ריצת התוכנית.

          ·          אברי המערך ממוספרים החל מאינדקס 0  ועד אינדקס  N-1. 

          ·          אסור לפנות לאינדקסים מחוץ לגבולות שהוגדרו.

          ·          העבודה עם איבר של מערך, לדוגמא  a[1], זהה לצורת העבודה עם כל משתנה רגיל מסוג  int.

קליטת מילה אחת - לתוך מערך תווים

/*

    Program asks the user for his name

    and say "Hi" to him.

*/

#include <iostream.h>

void main()

{

    char OneWord[21]; // for a word with max length of 20 chractes

    cout << "What is your name? (max 20 chracters): ";

    cin >> OneWord;

    cout << "Hi " << OneWord << '!' << endl;

    cout << "Press any Key to continue and press Enter...." << endl;

    cin.get();

}

 

---------Example Output-----------

What is your name? (max 20 chracters): Avi

Hi Avi!

Press any Key to continue and press Enter....

 

---------Example Output-----------

What is your name? (max 20 chracters): Beni Cohen

Hi Beni!

Press any Key to continue and press Enter....

 

          ·          אחסון מחרוזות תווים נעשה במערך תווים.

          ·          הגדרת מקום לאחסון מילה או משפט הוא מערך של תווים.

          ·          הגדרת מערך תווים, באופן כללי:   char array_name[N+1];

          ·          N הוא מספר קבוע המסמל את אורך המילה המירבי הניתן לאחסן במערך תווים. גודל המערך חייב להיות תמיד גדול ב 1  מ  N.

          ·          כאשר מבצעים את השורה   cin >> OneWord  רק מילה אחת (עד הרווח) מוכנסת למערך מהקלט.


פתרון של משוואה ריבועית

/* 

   program solves: a*X*X + b*x + c = 0.

        prints the solution(s) if they exist (are real).

*/

 

#include<iostream.h> // for input/output

#include<math.h>     // for sqrt() function

void main()

{

    cout << "Program solves: a*X*X + b*X + c = 0" << endl;

    cout << "Enter a b c :";

    double a, b, c;

    cin  >> a >> b >> c;

    double delta = b * b - 4 * a * c;

    if (delta > 0)

    {

         double sqrtDelta = sqrt(delta);

         sol   = (-b + sqrtDelta) / (2 * a);

         cout << "First solution : " << sol << endl;

         sol   = (-b - sqrtDelta) / (2 * a);

         cout << "Second solution: " << sol << endl;

     }

     else if (delta == 0)

     {

         sol = -b / (2 * a);

         cout << "Single solution is : " <<  sol << endl;

     }

     else

         cout << "There is no real solution" << endl;

}

---------Example Output-----------

Program solves: a*X*X + b*X + c = 0

Enter a b c :-3 6 9

First solution : -1

Second solution: 3

---------Example Output-----------

Program solves: a*X*X + b*X + c = 0

Enter a b c :1 6 9

Single solution is : -3

---------Example Output-----------

Program solves: a*X*X + b*X + c = 0

Enter a b c : 12 13 14

There is no real solution

 

 

          ·          המשתנים מסוג  int  מתאימים לאחסון ערכים רק מסוג של מספרים שלמים
     
... -1, 0, 1, 2, ...  כאשר אנו זקוקים למשתנים שצריכים להכיל ערכים עם חלק שבר, כגון  3.1415 וכו', אנו חייבים

      להשתמש במשתנים מסוג של נקודה צפה  (floating point) הנפוץ בהם הוא  double.

          ·          מותר להגדיר סדרה של משתנים באותה השורה:

int a;

int b;

int c;

same as:

int a, b, c;

          ·          מותר להגדיר משתנה ולאתחל אותו באותו הזמן:

int a;

a = 2;

same as:

int a = 2;

          ·          האתחול יכול להיות מסובך יותר ולהכיל חישוב:

int a = 2 + 3;

          ·          החישוב המשמש לאתחול משתנה יכול להכיל משתנים אחרים:

int a = 2, b = 3,

int c = 2 * a + b;

          ·          פונקציית הספריה המתמטית  sqrt( )  מקבלת בתוך הסוגריים ערך והיא מחזירה ערך השורש הריבועי שלו.כלומר לאחר שורה            a = sqrt(b)         במשתנה  a  יהיה הערך שהוא שורש ריבועי של ערך  b.

חזרה להתחלה

לולאה פשוטה

/* 

   Program prints the numbers from 1 to 10

      demonstrating while and for loops

       

*/

 

#include<iostream.h> // for input/output

void main()

{

    int i;  // loop variable

   

    i = 1;  // initializing loop counter

    while (i <= 10)

    {

        cout << i << ' ';

        i = i + 1; // incrementing loop counter

    }

    cout << endl;

 

    // Performs exactly the same operation.

    // but initialization and increment of loop counter are

    // performed in firs and third fields of for loop.

    for (i = 1; i <= 10; i = i+1)

        cout << i << ' ';

    cout << endl;

}

   ---------Example Output-----------

1 2 3 4 5 6 7 8 9 10

1 2 3 4 5 6 7 8 9 10

 

 

·          לולאה  - האפשרות לחזור שוב ושוב על פקודה או על מספר פקודות כל עוד מתקיים תנאי כלשהו.

·          לולאת ) תנאיwhile(   בודקת את התנאי ואם התנאי נכון מבצעים את גוף הלולאה.  גוף הלולאה הוא פקודה בודדת או סדרה

     של פקודות בתוך סוגריים מסולסלים.

·          i  הוא משתנה הלולאה - המשתנה שקובע את התנאי האם תתקיים האיטרציה הבאה של הלולאה.

·          אתחול משתנה הלולאה: בתחילה  i  מקבל ערך התחלתי  1.

·          בצוע פקודת הדפסת המספר.

·          קידום משתנה הלולאה: הפקודה   i = i + 1;  מבצעת קידום  ערכו של  i  ב 1.

·          לולאת ) קידום  ;  תנאי ;  אתחול   for(  שקולה לחלוטין ללולאת ה  while  רק שחלק האתחול  והקידום מתבצעים

     בשדות של הפקודה בעצמה ואילו ב  while  האתחול נעשה לפני תחילת הלולאה והקידום בגוף הלולאה.

משתמשים בלולאת  for כאשר ידוע לפני תחילת הלולאה כמה איטרציות תהינה

/*

    program calculates and print the sum and average of 10 numbers.

*/

 

#include <iostream.h>

void main()

{

    cout << "Enter 5 numbers: " << endl;

   

    int n, i = 0, sum = 0; // initialize i and sum to 0.

 

    for(i = 0; i < 5; i++)

    {

        cin >> n;

        sum = sum + n;

    }

   

    cout << "Sum is: " << sum << endl;

    cout << "Average is: " << sum / 5.0 << endl;

}

---------Example Output-----------

Enter 5 numbers:

1 2 3 4 5

Sum is: 15

Average is: 3

·          הלולאה תתבצע בדיוק 5 פעמים ולכן נשתמש בלולאת  for.

לולאת  while משמשת בד"כ למספר בלתי ידוע מראש של איטרציות

בדרך כלל משתמשים בלולאת  while כאשר מספר האיטרציות שתבצע הלולאה אינו ידוע מראש.

 

/*

    program calculates and print the sum and average of a sequence of

      positive numbers. A negative number read indicates end

      of sequence.

*/

 

#include <iostream.h>

void main()

{

    cout << "Enter sequence of non negative numbers" << endl;

    cout << "End the sequence with a negative number " << endl;

    

    int n, i = 0, sum = 0; // initialize i and sum to 0.

 

    cin  >> n;

    while(n >= 0)

    {

        i++;  // same as: i = i + 1;

        sum = sum + n;

        cin >> n;

    }

   

    if (i != 0) // if numers where entered

    {   cout << "Sum is: " << sum << endl;

        cout << "Average is: " << sum / double(i) << endl;

    }

    cin.get();

}

---------Example Output-----------

Enter sequence of non negative numbers

End the sequence with a negative number

1 2 3 4 -1

Sum is: 10

Average is: 2.5

---------Example Output-----------

Enter sequence of non negative numbers

End the sequence with a negative number

-1

·          האופרטור    !=   פירושו שונה בערכו.

 

/*

    program read 5 numbers and print them in the reverse order

*/

 

#include <iostream.h>

 

const int N = 5;  // constant declaration

void main()

{

    cout << "Enter " << N << " numbers" << endl;

    int a[N];

 

    int i;

    for (i = 0; i < N; i++)

        cin >> a[i];

    for (i = N-1; i >= 0; i--)

        cout << a[i] << ' ';

    cout << endl;

 

}

---------Example Output-----------

Enter 5 numbers

1 2 3 4 5

5 4 3 2 1

 

חזרה להתחלה


פירוט טיפוסיי המשתנים הבסיסיים בשפה

כחלק משפת  C++  יש לנו מספר טיפוסי עצמים בסיסיים, המאפשרים למתכנת להגדיר מספרים ותווים (אותיות). עבור טיפוסים בסיסיים אלו מוגדרים אוסף של מפעילים  (operators)  אשר אפשר להפעיל עליהם.

מספרים שלמים  Integral types:  char, short, int, long

                           ·   טיפוסים של ערכים שלמים מייצגים מספרים כמו: -100, -1, 0, 2, 100.

                           ·   יש ארבעה סוגים של מספרים שלמים אשר המבדיל ביניהם הוא השטח שהם תופסים בזיכרון:

             char £ short £ int £ long   

                           ·    יחידת האחסון הבסיסית היא בית (8 סיביות בינאריות). בית יכול לייצג:  28 = 256 ערכים שונים.

                           ·   יש שני אופני שימוש במספרים שלמים: signed (מספרים חיוביים ושליליים),  unsigned (מספרים אי שליליים). טיפוס שמשתמשים בו כ unsigned יכול להכיל מספר חיובי גדול בערך פי שניים לעומת השימוש בו כ- signed.

                           ·   מובטח כי טיפוס גדול יותר מכיל כל מספר שמכיל טיפוס קטן יותר (בתנאי שהשימוש הוא באותה הצורה). הגודל המדויק של כל טיפוס נקבע על ידי היצרן של המהדר וזה תלוי במימוש (implementation).  המרכיב העיקרי בהחלטה הוא מבנה המחשב.

                           ·   לרוב מייצגים מספר שלם על ידי int, כאשר אין סיבה מיוחדת לעשות אחרת (short, long).

                           ·   ערכים קבועים (literals): 12, -10, 0 (בבסיס עשרוני - רגיל)  017, 0777 (מספר המתחיל ב0 הוא בבסיס אוקטלי - בסיס 8)     0x10, 0x1f (מספר המתחיל ב 0x  הוא בבסיס הקסהדצימלי  -  בסיס 16). הטיפוס של קבוע מספרי שלם הוא int. בכדי לשנות זאת אפשר לדוגמא: 123L הוא מטיפוס long,  33U  הוא מטיפוס unsigned  וגם  1UL  הוא מטיפוס unsigned long.

 

תחום ערכים unsigned

תחום ערכים signed

גודל בבתים

טיפוס

0 « 255

-128 « 127

1

char

0 « 65535

-32768 « 32767

2

short

0 « 65535

-32768 « 32767

[1]2

int

0 « 4294976295

-2147483648 « 2147483647

4

long

טבלא 1 טיפוסי מספרים שלמים

טיפוסי מספרים ממשיים או נקודה צפה  -  float, double, long double 

                           ·   טיפוסי נקודה צפה (floating point) מייצגים מספרים העשויים להכיל שבר כגון:    1.2, 0.001, 3.1415926536, -1.1  וכו'.

                           ·   יש לנו שלושה גדלים של טיפוסי נקודה צפה: float, double, long double.

                           ·   לרוב נשתמש בטיפוס double.

                           ·   ערכים קבועים של טיפוסי נקודה צפה, מכילים נקודה עשרונית ו/או סימן חזקה: 1.2, .2, 1e3, 3E5, 2., 2e-4, 1.3e14, 0.0002 וכו'. הטיפוס של קבוע מספרי של טיפוס נקודה צפה הוא double. בכדי לשנות זאת אפשר לדוגמא:  1.2f (float)  או 1e5L (long double)  .

 

 

סה"כ ספרות עשרוניות

תחומי גדלים

גודל בבתים

טיפוס

7

3.4e-38 « 3.4e+38

4

float

16

1.7e+308  «  1.7e-308

8

double

21

 3.4e-4932  «  1.1e+4932

10

[1]

long double

טבלא 2 טיפוסי מספרים ממשיים

טיפוסי תווים   char : characters

                           ·   מיועד להכיל תו:  'a', 'F', '$', '?'.

                           ·   כל תו מיוצג על ידי מספר ('A' מיוצג ע"י 65), אבל שימוש בטיפוס char יבטיח כי נקבל את התרגום המתאים בין מספרים לתווים, למטרות קלט פלט.

                           ·   קבוע תו תחום בתוך מירכאות ויש הבדל בין אותיות קטנות וגדולות.

                           ·   ישנם תווים אשר אין להם צורה קריאה על המסך, ולכן מציגים אותם על ידי escape sequence:

 

 

ממקם את הסמן בתחילת השורה הבאה.

Newline

\n

מזיז את הסמן לנקודת ה tab  הבאה.

Horizontal tab

\t

מזיז את הסמן לנקודת ה tab  האנכי הבאה.

Vertical Tab

\v

מזיז את הסמן מקום אחד אחורה בשורה.

Backspace

\b

מזיז את הסמן לתחילת השורה הנוכחית.

Carriage return

\r

הורדת שורה.

Form Feed

\f

משמיע צפצוף.

Alert

\a

משמש להדפסת התו  '\'.

backslash

\\

סימן שאלה.

Question Mark

\?

גרש.

Single Quote

\'

משמש להדפסת התו  '"'.

Double Quote

\"

ערך 0 מספרי.

NULL

\0

ערך מספרי לפי בסיס אוקטלי (בסיס 8).

Octal Number

\ooo

ערך מספרי לפי בסיס הקסהדצימלי (בסיס 16).

Hex Number

\xhhh

טבלא 3  קבועי תווים

 

·          מחרוזת של תווים תחומה בתוך גרשיים:   "hello, world\n"

·          אם נדפיס למסך מחרוזת כזו ע"י הפקודה:     cout << "hello, world\n"      נקבל גם הורדת הסמן לשורה הבאה  בעקבות הדפסת התו  '\n'.

 

טבלת ערכי ascii

·          טבלת ערכי   ascii  הבאה מגדירה את התו המתאים לערכים בתחום 0..127   בערכים הגבוהים יותר 128..255  ישנם תוים שונים  עבור אותם ערכים (תלוי במערכת ההפעלה).

 

      Booleanאמת או שקר:  bool

הטיפוס bool  מיועד להכיל ערך אמת או ערך שקר:  true, false.

                           ·   הקבוע  true מסמל ערך אמת וערכו המספרי 1.

                           ·   הקבוע  false מסמל ערך שקר וערכו המספרי 0.

 

לתשומת לב:  בשפת  C++  כל ערך שונה מ- 0  נחשב כאמת ורק הערך- 0 נחשב כשקר.

 

חזרה להתחלה

הגדרות של משתנים וקבועים

                           ·   משתנה (variable)הוא מקום אחסון לערך בתוכנית, שערכו אינו ידוע ו/או הערך עשוי להשתנות במהלך בצוע התוכנית.

                           ·   הגדרת משתנה (definition) היא הוראה בקוד התוכנית המגדירה את שם המשתנה, טיפוס הערך שהוא מסוגל

    להכיל, ולפעמים גם ערך התחלתי.

                           ·   חייבים להגדיר משתנה לפני שכותבים קוד המשתמש בו.

                           ·   כל משתמה בזמן ריצה תופש מקום בזכרון בגודל המתאים לטיפוס הנתונים שהוא מכיל.

                           ·   הגדרת משתנה בסיסי (הקצאת שטח עבורו בזיכרון) אינה גורמת למתן ערך התחלתי למשתנה, אלא אם יש אתחול מפורש..

                           ·   משתנה גלובלי מאותחל אוטומטית ל 0.

                           ·   ערך של משתנה (לא גלובלי) לא מאותחל אינו ידוע (זבל  garbage).  

אופן הגדרה ואתחול

                           ·   הגדרת משתנה:

int i;

                           ·   הגדרת מספר משתנים מאותו טיפוס באותה שורת הגדרה:

int j, k, n;

                           ·   השמת ערכים למשתנים:

j = 3;

k = 10;

n = 1E10;

                           ·   אפשר וגם נהוג לאתחל משתנה בזמן הגדרתו:

int i, j = 3, k = 10, n = 1E10;

לגבי האתחול:

                           ·   משתמשים במפעיל ההשמה  '='  (assignment) למתן ערך התחלתי בזמן הגדרת המשתנה.

                           ·   המשתנה i לא אותחל וערכו בהתחלה יכול להיות כל מספר מטיפוס int.

                           ·   רצוי בדרך כלל להגדיר משתנה במקום בו רוצים להשתמש בו ומייד לאתחלו בזמן הגדרתו.

 

שימוש בקבועים  

                           ·   לפעמים אנו מעונינים להגדיר משתנה כך שערכו לא ישתנה במשך ריצת התוכנית.

                           ·   בכדי להגדיר משתנה עם ערך קבוע (constant)  אנו מוסיפים את המילה  const  לפני הגדרת המשתנה, ומאתחלים את הערך הקבוע שלו.

const double PI = 3.1415926535897932385;

 

                           ·   שיפור קריאות התוכנית (readability) ונוחיות הכתיבה:

     לדוגמא:

2 * PI * r     פחות קריא ונוח להקליד מ-  2 * 3.1415926535897932385 * r

 

                           ·   קלות בהכנסת שינויים.
בעיה:  נניח כי כתבנו תוכנית לניהול 5 מחלקות במפעל. המספר 5  מופיע פעמים רבות בתוכנית.  לאחר זמן הוסיפו מחלקה למפעל. הרי אז צריך לעדכן את כל המופעים של המספר 5 שמשמעותו מספר המחלקות    ל 6. דבר זה גורר חיפוש בכל התוכנית אחר המספר 5 והחלפת המספר ב 6 רק כאשר משמעות המספר 5 היא מספר המחלקות ולא 5 ימי עבודה בשבוע.
פתרון:  שימוש בקבוע  
const int departmentsNumber = 5;  יחסוך לנו את החיפוש אחרי המספר 5 ונבצע את ההחלפה של 5 ב 6 רק במקום אחד - בהגדרת הקבוע המתאים.

 

חזרה להתחלה

מפעילים פשוטים   simple operators

בשפת  C++  יש לנו אוסף של מפעילים המאפשרים לנו לבצע פעולות על טיפוסי נתונים בסיסיים.

מפעילים מספריים    numeric operators

ישנם חמישה מפעילים אריתמטיים בינאריים (שני ארגומנטים) פשוטים:

                           ·   +  חיבור

                           ·   -  חיסור

                           ·   *  כפל

                           ·   /   חילוק

                           ·   %  שארית החילוק בין מספרים שלמים  (מוגדר רק לטיפוסים integral)

ישנם זוג מפעילים מספריים אונריים (עם ארגומנט אחד):

                           ·   -   מינוס לפני ערך כגון:  -4, -n

                           ·   +   פלוס לפני ערך כגון:  +4, +n (למעשה אינו משפיע אלא נועד לצורך סימטרייה למפעיל -).

קידום טיפוס במפעילים בינאריים      Type promotion  

  1 + 2 is  3

  1 - 2 is -1

  1 * 2 is  2

  7 / 2 is  3

  7 % 2 is  1

קוצץ ולא מעגל  / /    11 / 4 is 2    

-11 / 4 is -2

 

מפעיל החילוק  /  מתנהג אחרת עבור מספרים שלמים (integer) ואחרת עבור מספרים ממשיים (floating): עבור מספרים שלמים הוא נותן את הערך השלם של החלוקה, ועבור מספרים ממשיים הוא נותן את התוצאה של החלוקה כולל השבר

חלוקה של מספרים שלמים:

1 / 2   is  0    int / int       

חלוקה של מספרים ממשיים:

 1.0 / 2.0 is 0.5           double / double

כאשר הטיפוסים של שני הנפעלים (operands) שונים יש תהליך של הסבה (conversion).

1.0 / 2 is  0.5            double / int --> double / double

סדר קדימויות  Priority

   ·   בשפת  C++  יש סדר קדימויות בין המפעילים, זאת בכדי לקבוע חד משמעית את משמעות החישוב.

 

דוגמא:

כמו במתמטיקה  *  קודם ל   +              לכן  3 + 4 * 5              פירושו  3 + (4 * 5)

 

הקדימות של המפעילים האריתמטיים הוא מהגבוה לנמוך:

   ·   האונריים  -, +

   ·   *, /, %

   ·   הבינאריים  -, +

   ·   תמיד אפשר להשתמש בסוגריים בכדי להשפיע על סדר הפעולות:

     (31 + 8)*(5 - 7)  

   ·   למפעילים יש גם תכונה של תסמוך ימני/שמאלי(left/right associative) . כאשר משתמשים במספר אופרטורים בעלי

 אותה עדיפות כוון התסמוך קובע מי עדיף.

   ·   המפעילים האונריים ומפעיל ההשמה (=) הם בעלי תכונת תסמוך ימני (right associative).

   ·   המפעילים האחרים בעלי תכונת תסמוך שמאלי  (left associative). לדוגמא המפעילים הבינאריים הבאים:       +, -, *, /, %:

3 - 4 + 5   is ((3 - 4) + 5)  and not  (3 - (4 + 5))     

3 / 2 * 3   is ((3 / 2) * 3)  which is 3   and not (3 / (2 * 3))  which is 0   

 

למפעיל '-' האונרי יש קדימות על המפעיל '-' הבינארי:

-5 - 4  is  ((-5) - 4)   and not   -(5 - 4)

   ·   בכל מקרה שיש ספק לגבי משמעות ביטוי, הפתרון הוא הוספת סוגריים '('  ')'.

   ·   לתיאור של כל המפעילים קדימויותיהם והאסוציאטיביות שלהם ראה טבלאת מפעילים בסוף פרק זה.

מפעילים של קידום והורדה ב 1  ++,  --

   ·   לעיתים קרובות מקדמים ערך של משתנה ב- 1, או מורידים ב- 1 ערך של משתנה. הדבר כה נפוץ עד שמצאו לנכון לספק מפעילים מיוחדים למטרות אלו.

   ·   המפעיל  ++  נועד לקדם ב- 1.

   ·   המפעיל  --  נועד להוריד ב- 1.

   ·   יש שני אופני שימוש במפעילים הללו, לפני המשתנה  (prefix), דהינו משמאלו, ואחרי המשתנה (postfix), דהינו מימינו.

בכדי להבין פעולת מפעילים אלו צריכים להבין את המושגים:

  1. הערך שמחזיר המפעיל (expression value).
  2. השפעה צדדית (side effect)- מה קרה לערך המשתנה בעקבות הפעלת המפעיל עליו.

 

++a (prefix)

a++ (postfix)

expression value: a + 1

expression value: a

side effect: add 1 to a

side effect: add 1 to a

 

   ·   המפעיל  --  מתנהג באופן דומה.

 

// for all examples, a starts with value 2,  x starts with value 3

 

the expression:                 values of a  and  x after calculation

a + x++   // is 2 + 3 -> 5                   a is 2,  x is 4

a + ++x   // is 2 + 4 -> 6                   a is 2,  x is 4

--a + x   // is 1 + 3 -> 4                    a is 1,  x is 3

a-- + x-- // is 2 + 3 -> 5                    a is 1,  x is 2

 

 

   ·   lvalue  -   משתנה שמותר לשנות את ערכו.  (כל מה שיכול להופיע באגף שמאל של השמה)

   ·   מפעילים של קידום והורדה משנים את ערך המשתנה שעליו הם מופעלים, לכן חייבים להפעילם רק על  lvalue . אסור להפעילם על קבועים, מספרים, וביטויים.

 

// ERRORS:

++123 ,  --(a + b), ++(--a), --PI

מפעיל השמה  =

   ·   מפעיל השמה קובע את הערך בארגומנט השמאלי שלו להיות התוצאה של החישוב באגף הימני שלו.

   ·   המפעיל אינו מתנהג בצורה סימטרית:

   ·   באגף שמאל שלו מצוין מקום לאחסון הנתון (lvalue).

   ·   באגף ימין ישנו ביטוי שחייב להחזיר ערך (rvalue).

// OK

a = 3 * (b + c); // sets the value of a.

double x = y;    // defines x and sets it to y’s value.

a = b = 5;       // sets both a and b to 5.

y = x++;         // sets y to x’s value and then increments x.

 

// ERROR

a + 2 = b;       // a + 2 isn’t a storage location.

PI = 3;          // constant can’t be modified.

x++ = y;         // x++ isn’t a storage location.

 

a + 2, PI, x++ are not lvalues!

 

   ·   המפעילים  ++  --  פועלים רק על  lvalue,  וכמובן אגף שמאל של המפעיל = חייב להיות  lvalue.

   ·   מפעיל ההשמה הוא מפעיל בינארי רגיל במובנים הבאים:

   ·   מפעיל ההשמה מחזיר את הערך של אגף שמאל לאחר ההשמה.

   ·   למפעיל ההשמה תופעת לואי שהיא שינוי הערך של המשתנה באגף שמאל.

   ·   מפעיל ההשמה הוא right associative:

 

a = b = 5;   is    (a = (b = 5));

   ·   קודם מבצעים את ההשמה ל b.

   ·   הערך של הביטוי (b = 5) הוא הערך של b לאחר ההשמה, ז.א.  5.

   ·   משימים את הערך   5   לתוך a.

   ·   למפעיל ההשמה יש הקדימות הנמוכה ביותר שראינו עד כה. לכן:

a = b + c;  is  (a = (b + c));

מפעילי השמה נוספים  +=, -=, *=, /=, %=

   ·   לשם נוחיות הגדירו מפעילי השמה נוספים אשר עוזרים לקצר את הכתיבה של הביטויים.

 

Operator

Equivalent Expression

v += e;

v = v + e;

v -= e;

v = v - e;

v *= e;

v = v * e;

v /= e;

v = v / e;

v %= e;

v = v % e;

   ·   בשפת C++ יש לרוב מספר דרכים להשיג אותה תוצאה:

n = n + 1;

n += 1;

n++;

++n;

כל אלה דרכים לגרום להשפעה צדדית  על n שהיא קידומו באחד. שים לב כי ערך הביטוי n++  אינו שקול לערך יתר הביטויים.

 

   ·   צריך להבדיל בין מפעיל ההשמה =  לבין מפעיל השוויון  == . (באלגברה הסימן  =  פירושו שוויון, בC++  אין הדבר כך -  לכן יש לשים לב).

מפעילים לוגיים boolean operators

   ·   אנו מעוניינים ביכולת לבדוק האם יחס מסוים מתקיים בין ערכים. אם היחס מתקיים נאמר שהוא אמת (true)  ואם היחס אינו מתקיים נאמר שהוא שקר (false).

   ·   מוגדרים בשפה מספר מפעילים של יחס בין מספרים:

 

Operator

true (returns 1) when

a == b

a is equal to b

a != b

a is not equal to b

a < b

a is less than b

a <= b

a is less than or equal to b

a > b

a is greater than b

a >= b

a is greater than or equal to b

All of these return: 0 (false) or 1 (true)

   ·   מפעילי היחס מחזירים ערך true  ששווה ל 1  במקרה שהיחס מתקיים.

   ·   מפעילי היחס מחזירים ערך false  ששווה ל 0  במקרה שהיחס אינו מתקיים.

לדוגמא:

int a = 1, b = 2, r;

r = a < b;     // r has 1

r = a >= b;    // r has 0

r = a => b;    // Error: operator => doesn't exist

r = b >= -2.0; // r has 1. The value of b is converted to double, b itself is unchanged.

 

bool b1;        // new C++ type

b1 = a < b;     // b has true  (which is 1)

b1 = a >= b;    // b has false (which is 0)

 

   ·   ישנם מקרים בהם רוצים לשלב מספר תנאים לתנאי מורכב. יש לנו מספר מפעילים המשמשים לשילוב תנאים.

Operator

true (returns 1) when

a && b

both a and b are true

a || b

either a or b or both are true

!a 

a is false

All of these return: 0 (false) or 1 (true)


דוגמאות:

int a = 1, b = 2, r;

r = (a < b) && (b >= 2);   // r receives 1

r = (a > b) || (b >= 2);   // r receives 1

 

   ·   בשפת  C++  כל ערך מספרי שונה מ 0 נחשב כ  true, וערך שווה ל 0 נחשב כ  false.

r = 5 && -1;          // r receives 1

r = (a < b) && b    // r receives 1

r = !a + !b;           // r receives 0 + 0 which is 0

r = !!a;                // r receives 1

r = !0;                 // r receives 1         

 

   ·   המפעילים  &&  ||     בעלי מספר תכונות מיוחדות:

   ·   בניגוד לרוב המפעילים (האריתמטיים לדוגמא) במפעילים הללו מוגדר בשפה כי סדר חישוב האופרנדים הוא משמאל לימין. כלומר קודם מחשבים את האופרנד השמאלי ורק לאחר מכן את הימני.

   ·   המפעילים מחשבים את האופרנד השמאלי, ורק אם התנאי לא הוכרע מחשבים גם את האופרנד הימני.

דוגמא:

if ((items > 0) && (sum / items > 90)) // avoiding division by 0.

    grade = 'A';

   ·   אם items שווה ל 0   לא נחשב את החלוקה:    sum / items.

 

כאשר משתמשים במפעיל אריתמטי, מחשבים תמיד את שני האופרנדים:

x = (items > 0) * (sum / items > 90)

 

int j = -1, k;

k = ++j || ++j;  // k receives 1 (true), j receives 1.

k = ++j && ++j;  // k receives 0 (false), j receives 0

                 // (++j on the right was not evaluated).

   ·   סדר החישוב משמאל לימין. מפסיקים את החישוב אם התנאי הוכרע.

 

   ·   פרט למפעילים המיוחדים ('&&' '||' ',' '?:' ) סדר החישוב אינו מוגדר בשפה (זאת בכדי לאפשר למהדר לסדר את הפעולות בצורה הנראית לו יעילה ביותר)

לדוגמא:  אותו חישוב בדיוק במהדרים ובמחשבים שונים נותן ערך אחר. הדבר נובע, כאמור מכך שלא מוגדר בשפה מהוא סדר הפעלת המפעילים וכל מהדר בוחר סדר כרצונו.

int a = 17;

 

expression

VAX GCC

VAX CC

SUN CC

BIRISC CC

SPARK GCC

++a   *   a   +   a   *   a

648

648

648

648

613

  a   * ++a   +   a   *   a

648

648

648

648

613

  a   *   a   + ++a   *   a

613

648

648

648

648

  a   *   a   +   a   * ++a

613

648

648

648

648

  a++ *   a   +   a   *   a

578

630

630

548

595

  a   *   a++ +   a   *   a

578

630

630

548

595

  a   *   a   +   a++ *   a

578

630

659

548

630

  a   *   a   +   a   *   a++

578

630

659

548

630

 

   ·   מכאן אפשר להסיק כי כאשר המפעילים   ++, --   מופעלים על משתנה המופיע יותר מפעם אחת בביטוי ערך הבטוי אינו מוגדר (נכון עבור המפעילים שבהם סדר החישוב אינו מוגדר).


טבלת מפעילים

1

::

::

::

::

scope resolution

scope resolution

global

global

class_name :: member

namespace_name :: member

::name

:: qualified-name

2

.

->

[]

()

()

++

--

typeid

typeid

dynamic_cast

static_cast

reinterparate_cast

const_cast

member selection

member selection

subscripting

function call

value construction

post increment

post decrement

type identification

run-time type identification

run-time checked convertion

compile-time checked convertion

unchecked convertion

const convertion

object.member

pointer->member

pointer[expr]

expr(expr_list)

type(expr_list)

lvalue++

lvalue--

typeid( type )

typeid( expr )

dynamic_cast<type>(expr)

static_cast<type>(expr)

reinterparate_cast<type>(expr)

const_cast<type>(expr)

3

sizeof

sizeof

++

--

~

!

+

-

&

*

new

new

new

new

delete

delete[]

()

size of object

size of type

pre increment

pre decrement

complement

not

unary plus

unary minus

address of

dereference

create (allocate)

create (alloc. and init.)

create (place)

create (place and init.)

destroy (de-allocate)

destroy array

cast (type conversion)

sizeof expr

sizeof (type)

++lvalue

--lvalue

~expr

!expr

+expr

-expr

&lvalue

*expr

new type

new type (expr-list)

new (expr-list) type

new (expr-list)type(expr-list)

delete pointer

delete[] pointer

( type ) expr

4

.*

->*

member selection

member selection

object.*pointer-to-member

pointer.*pointer-to-member

5

*

/

%

multiply

divide

modulo (remainder)

expr * expr

expr / expr

expr % expr

6

+

-

add (plus)

subtract (minus)

expr + expr

expr - expr

7

<<

>>

shift left

shift right

expr << expr

expr >> expr

8

<

<=

>

>=

less than

less than or equal

greater than

greater than or equal

expr < expr

expr <= expr

expr > expr

expr >= expr

9

==

!=

equal

not equal

expr == expr

expr != expr

10

&

bitwise AND

expr & expr

11

^

bitwise exclusive OR (XOR)

expr ^ expr

12

|

bitwise inclusive OR

expr | expr

13

&&

logical AND

expr && expr

14

||

logical inclusive OR

expr || expr

15

? :

conditional expression

expr ? expr : expr

16

=

*=

/=

%=

+=

-=

<<=

>>=

&=

|=

^=

simple assignment

multiply and assign

divide and assign

modulo and assign

add and assign

subtract and assign

shift left and assign

shift right and assign

AND and assign

OR and assign

XOR and assign

lvalue = expr

lvalue *= expr

lvalue /= expr

lvalue %= expr

lvalue += expr

lvalue -= expr

lvalue <<= expr

lvalue >>= expr

lvalue &= expr

lvalue |= expr

lvalue ^= expr

17

throw

throw exception

throw expr

18

,

comma (sequencing)

expr , expr

   ·   מפעילים אונריים ומפעילי השמה הם   right associative.

   ·   כל המפעילים האחרים הם left associative.

כל קופסא מכילה מפעילים באותה העדיפות, קופסא גבוהה יותר מכילה מפעילים בעדיפות גבוהה יותר (עדיפות 1 הגבוהה ביותר).

 

חזרה להתחלה

הוראות  Statements

הוראה (statement)   היא יחידת בצוע בתוכנית. סדר בצוע התוכנית הוא לפי סדר ההוראות המושג הוראה מתייחס לארגון סדר הבצוע ולא לחישובים וערכים.

הוראת הגדרת משתנה  Varaiable dfinition statemens

אי אפשר להשתמש במשתנה לפני שמגדירים אותו. יש לנו מספר דרכים להגדיר משתנים.

 

מבנה הוראות להגדרת משתנים חדשים:

 

 הגדרת משתנה    TypeName identifier, ...;                    //

הגדרת משתנה עם אתחול        / /       TypeName identifier = expression, ...;             

הצהרה על קבוע  const TypeName identifier = expression,...;  //

 

   ·   כל הוראה המגדירה על משתנה מסתיימת בסימן הסיום  ';' .

   ·   ה  ...   מציינות את האפשרות להגדיר עוד משתנים מאותו טיפוס המופרדים ב-  ','

 

int a = 2, b = 3;

int c, d = 3, e = a + b;

const double rate = 0.0072;

   ·   משתנה אפשר לאתחל על ידי ערך שאפשר לחשבו על ידי ערכים (משתנים, קבועים וכו') שהוגדרו קודם.

   ·   קבוע אפשר לאתחל רק בערך קבוע.

   ·   אסור להגדיר שני משתנים (או קבועים) בעלי אותו שם.

הוראת ביטוי  Expression Statement 

   ·   הוראה מסוג ביטוי  (expression) גורמת במהלך הבצוע לחישוב ערך הביטוי וכן לרוב לבצוע השפעה צדדית (כמו קידום של משתנה או השמת ערך למשתנה).

   ·   להוראת ביטוי יש הצורה:           expression;

   ·   כל הוראת ביטוי מסתיימת ב ';'.

 

לגבי הביטוי:

   ·   לכל ביטוי יש טיפוס לתוצאה, הנקבע בזמן כתיבת התוכנית.

   ·   ערך הביטוי נקבע בזמן ריצת התוכנית כאשר מעריכים (evaluate) את הביטוי.

 

נניח כי הגדרנו את המשתנים הבאים:

int i = 2;

float fsum, f1 = 2, f2 = 4;

double d1 = 2, d2, d3;

int i1 = 1, i2 = 2, i3 = 3, i4 = 4;

bool b;

 

expression statements

value of expression at run time 

type of expression value

side effect

i++;

2

int

add 1 to I

5;

5

int

-

f1 + f2;

6

float

-

i1 + d1;

3

double

-

fsum = f1 + f2;

6

float

assign 6 to fsum

d1 += d2 = 3;

5

double

assign 3 to d2 and 5 to d1

b = f1 < f2;

true

bool

assign true to b

d3 = 2 / 5 * 5

0

double

assign 0 to d3

d3 = 2.4 / 5 * 5;

2.4

double

assign 2.4 to d3

הוראה מורכבת  Compound Statement

   ·   ישנם מקרים שאנו מעונינים להתייחס לקבוצה של הוראות כיחידה אחת. עושים זאת על ידי קיבוץ סדרה של הוראות בתוך סוגריים  {     }  . צורה כזו נקראת הוראה מורכבת  (compound statement) או בלוק הוראות (block).  

   ·   כל סוג של statement  יכול להופיע בתוך הוראה מורכבת.

   ·   בסוף הוראה מורכבת לא צריך  ; .

{

    int j = 3;

    double x = 2.01, y = -3.89;

    int k = 2 - j;

    x = 2.4 * (x - y);

}

 
 


{

    statement;

     statement;

    statement;

    statement;

}

 

איפה חשובים הרווחים - מפרידים ואסימונים  tokens

   ·   שפת C++ מתייחסת למרווחים, טאבים, ושורות חדשות כאל מפרידים. לכן אין הבדל בין רווח אחד לעשרה רווחים או לשורה חדשה. לפיכך אפשר לכתוב את התוכנית בצורה חופשית.

 

אפשר לכתוב הוראה מורכבת גם כך, אבל ברור כי קשה מאד לקרא אותה.

 

{int j = 3; double x = 2.01, y = -3.89; int k = 2 - j;  x = 2.4 * (x - y);}

 

   ·   בכדי לשפר משמעותית את קריאות התוכנית יש להקפיד על עימוד של ההוראות. לדוגמא:

   ·   כל ההוראות בבלוק מוכנסות 2 תווים פנימה לעומת עמודת ההתחלה הקודמת.

   ·   כל חישוב יופיע בשורה נפרדת.

   ·   מצהירים על מספר משתנים באותה שורה רק אם יש קשר הגיוני בין המשתנים בתוכנית.

 

 

למרות מה שאמרנו למעלה קיימים מקרים בהם יש חשיבות לרווחים. בכדי להבין מהם מקרים אלו צריך להכיר את השיטה לפיה המהדר מנתח את קוד התוכנית:

   ·   המהדר סורק את קוד התוכנית במטרה למצוא את היחידות הבסיסיות של התוכנית (מזהים, מפעילים, קבועים, מילים שמורות וכו').

   ·   המהדר סורק משמאל לימין. בזמן הסריקה המהדר מנסה למצוא את הרצף הארוך ביותר של תווים המהווה יחידה חוקית בשפה (אסימון   token).  

   ·   רווחים חשובים רק כאשר הם מפרידים בין אסימונים.

a + ++ b    -->  a + (++ b)

a+ ++b      -->  a+ (++ b)

a+++b       -->  (a++)+b

a ++ + + b  -->  (a ++) + (+ b)

a+++ +b     -->  (a++)+(+b)

a++++b      -->  (a++)(++b) ERROR: binary operator is missing!

 

חזרה להתחלה


הוראות בחירה    if  switch

   ·   לעיתים קרובות, אנו מעוניינים שהתוכנית תבצע דברים שונים, עבור ערכים שונים הנקבעים רק בזמן ריצת התוכנית. ב  C++  יש לנו מספר אפשרויות לבחור איזו הוראה לבצע על פי ערכים הנקבעים בזמן ריצת התוכנית.

   ·   control flow statements - הוראות המיועדות לבחור איזו הוראה לבצע לפי תנאי המחושב בזמן ריצה.

if (expression)

{  

    statement1

    statement2

    statement3

}

 
הוראת  if statement

 

if (expression)

    statement1

 

 

 

 

 

 

 

 

 

 

  1.  מחשבים את ערך הבטוי  expression, שהוא יכול להיות מכל טיפוס מספרי (שלמים או ממשי).

  2.  אם הערך נכון (שונה מ 0) מבצעים את ההוראה היחידה או בלוק ההוראות. אם הערך שקרי (שווה 0) אין מבצעים דבר.

דוגמא:

                        ·      בצוע או אי בצוע של הוראה בודדת.

if (a < 0)       // count negatives

    negatives++;

                        ·      בצוע או אי בצוע של בלוק הוראות.

 

if ((n < 0) && (d < 0))  // if both negative change sign.

{

    n = -n;

    d = -d;

}

הוראת  if-else statement

if (expression)

    statement1

else

    statement2

 

 

if (expression)

{

    ...

}

else

{

    ...

}

 

 

if (expression)

{

    ...

}

else

    statement2

 

 

 

 

 

 

 

 

 

 

 

  1.  מחשבים את ערך הבטוי  expression.

  2.  אם הערך נכון מבצעים את ההוראה statement1. אם הערך שקרי מבצעים statement2.

 דוגמא: חלוקה ב 0 הינה טעות חמורה בזמן ריצה ועלולה לגרום לסיום בצוע התוכנית. בכתיבת תוכנית צריך
          להתכונן לגרוע ביותר (אשר בדרך כלל קורה).  תוכנית טובה צריכה לטפל בשגיאות אפשריות!

 

if (numScores == 0)

    cout << "No scores to average";

else

    average = total / numScores;

 

 

 


   ·   ה  statement  בתוך ה  if  יכול להיות מכל סוג, אפילו  if:

if (a > 100)

    if (b <= 0)

        bigAndNeg = 1; // done if a > 100 and b <= 0

    else

        bigAndPos = 1; // done if a > 100 and b > 0

else

    small = 1;         // done if a <= 100 regardless of b

 

   ·   העימוד חשוב ביותר (לקריאות התוכנית, לא למהדר)!  -   נסה להבין מה קורה כאן:

if (a > 100)

if (b <= 0)

x = 1;                 // done if a > 100 and b <= 0

else

y = 1;                 // when would this be done?

 

   ·   אותו הדבר עם עימוד טוב מדגיש את הכלל: ה  else  מוצמד תמיד ל  if  הקרוב ביותר:

if (a > 100)

    if (b <= 0)

        x = 1;         // done if a > 100 and b <= 0

    else

        y = 1;         // done if a > 100 and b > 0

 

   ·   בכדי להצמיד את ה  else ל  if  הראשון אפשר להשתמש בהוראה מורכבת:

if (a > 100)

{

    if (b <= 0)

        x = 1;         // done if a > 100 and b <= 0

}

else

    y = 1;             // done if a <= 100

 

   ·   התנאי הראשון שיתקיים יגרום להשמה לתוך  grade, וכל יתר התנאים לא יבדקו (חיסכון בהשוואות).

if (score >= 90)

    grade = 'A';

else

    if (score >= 80)

        grade = 'B';

    else

        if (score >= 70)

            grade = 'C';

        else

            if (score >= 60)

               grade = 'D';

            else

               grade = 'F';

 

   ·   תנאים מקוננים: צורת עימוד מקובלת יותר (בכדי שתנאי מקונן ארוך לא יצא מהמסך ימינה):

if (score >= 90)

    grade = 'A';

else if (score >= 80)

    grade = 'B';

else if (score >= 70)

    grade = 'C';

else if (score >= 60)

    grade = 'D';

else

    grade = 'F';

חזרה להתחלה


בחירת בצוע לפי אפשרויות של ערכים קבועים  switch statement

switch(expr) {

case const-expr1:

    statement-list1

case const-expr2:

    statement-list2

case const-expr3:

    statement-list3

default:            // optional

    statement-list4

}

ההוראה נועדה  להחליט מה לבצע לפי בדיקת ערך expr.

   ·   expr  וכל ה  const-expr  הם מטיפוס אינטגרלי (מספרים שלמים  char short int long ) 

   ·   const-expr  הם ערכים שלמים, קבועים, שערכיהם ידועים בזמן ההידור.

 

פעולה

   ·   מחשבים את ערך ה expr . אם  ערכו שווה לאחד מה const-expr  מתחילים לבצע את ה statement-list  החל מה  label    case const-expr:  ועד סוף ה   switch block.

   ·   אם ערך ה expr אינו שווה לאף אחד מערכי ה const-expr  מתחילים לבצע  החל  מה default: .   אם לא הגדרנו default:  אין מבצעים דבר.

   ·   אפשר למקם את ה  default:  בכל מקום בתוך הבלוק (לאו דווקא בהתחלה או בסוף). ואז לפעמים החישוב משתנה בעקבות זאת.

   ·   ה const-expr  חייבים להיות שונים.

   ·   statement-list  פירושו  שמותר לכתוב סדרה של הוראות לאחר ה  case const-expr:  ולא מוגבלים ל statement בודד.  כאשר כותבים מספר הוראות אין צורך בהוראה מורכבת ( {..} ).

   ·   אסור להגדיר משתנים בתוך  switch block  אלא רק בתוך בלוק המוגדר בתוך ה switch.

 

 

   ·   בדרך כלל, מעונינים לבצע רק מקרה אחד. אז משתמשים בהוראת  break, גורמת ליציאה מיידית  מתוך הבלוק של ה  switch.

    דוגמא "רגילה":

   ·   בדרך כלל משתמשים ב  switch  במקום  if-ים  מקוננים.

#include <iostream.h>

void main()

{   char c, grade;

    int score;

    cout << "enter your score (0..100): ";

    cin >> score;

    switch(score / 10) {

    case 10:

    case 9:

        grade = 'A';

        break;

    case 8:

        grade = 'B;

        break;

    case 7:

        grade = 'C';

        break;

    case 6:

        grade = 'D';

        break;

    default:

        grade = 'F';

        break;      // Not needed now, but advisable in case we add

    }                   // another mark.

    cout << "Your grade is: " << grade << endl;

}


דוגמא "מיוחדת" (בלי break) לחישוב מס הכנסה:

   ·   דוגמא זו היא שימוש חריג בהוראת  switch.

#include <iostream.h>

// program calculates the income tax for a given salary

void main()

{

    double salary;

    cout << "Enter your salary: "

    cin >> salary;

 

    if (salary < 0) {

        cout << "Error in IncomeTax(): Negative salary.\n";

        return 0;

    }

    double tax = 0;

    int bracket = salary / 1000;

    switch(bracket) {

    default:

        tax  = (salary - 4000) * 0.4;

        salary = 4000;

    case 3:

        tax += (salary - 3000) * 0.3;

        salary = 3000;

    case 2:

        tax += (salary - 2000) * 0.2;

        salary = 2000;

    case 1:

        tax += (salary - 1000) * 0.1;

        salary = 1000;  // used only if we add another

    case 0:             // tax bracket below.

        ;

    }

    cout << "Your tax is: " << tax << endl;

}

המפעיל     :  ?

   ·   ישנם הרבה מקרים בהם רוצים לקבל אחד מבין שני ערכים לפי תנאי מסוים:

expr1  ?  expr2  :  expr3     

   ·   אם   expr1  נכון, אזי ערך כל הבטוי יהיה כערכו של  expr2. אחרת יהיה ערך הביטוי כערכו של  expr3

                           ·   בכל מקרה יחושב  expr1.  אחריו יחושב expr2    או     expr3,    אבל לא שניהם.

                           ·   המפעיל קובע את סדר החישוב :

1.      קודם מחשבים expr1 .

2.      אם התוצאה שונה מ 0  מחשבים expr2  וערכו הוא ערך כל הביטוי.

3.      אם התוצאה שווה ל 0  מחשבים expr3  וערכו הוא ערך כל הביטוי.

                        ·      הטיפוס של כל הבטוי הוא הטיפוס הגבוה מבין  expr2  ו   expr3.

דוג:

void main()

{

    int x = 1, y = 2, r;

    r = x > y ? x : y;    // max of x y

    r = x >= 0 ? x : -x;  // absolute value of x

    r = 1.0 / ( n != 0 ? n : 1); // one over

}

הסוגריים חיוניים אחרת (בגלל סדר קדימויות) משמעות הבטוי היתה:

 ((1.0 / n) != 0) ? n : 1       

 

( 1 ? 2 : 3.0)

זהו ביטוי מטיפוס double  וערכו  2.

x = a++ ? a++ : a++; // x = a+1 

זהו ביטוי שערכו מוגדר היטב כי המפעיל ? :  קובע את סדר החישוב.

ה  side effect  על  a  הוא הוספה של 2.

 

 

חזרה להתחלה

 

לולאות Loops

                        ·      הוראות הלולאה:  while, do-while, for .

                        ·      הנחיות לשימוש יעיל בלולאות.

                        ·      המפעיל ,  וההוראות  continue, break  בלולאות.

 

הוראת  while

                        ·      בדרך כלל משתמשים בהוראת  while  כאשר לא יודעים לפני תחילת בצוע הלולאה כמה איטרציות תתבצענה.

 

while (expression)

    statement

next statement

 

                        ·      מחשבים את הבטוי  expression, שהוא יכול להיות מכל טיפוס מספרי (שלמים או ממשי).

                        ·      אם התנאי נכון (ערכו שונה מ 0) מבצעים את  statement,  וחוזרים לבדוק את התנאי.

                        ·      אם התנאי אינו נכון (ערכו 0) מפסיקים את בצוע הלולאה (לא מבצעים את ה statement) וממשיכים ל next statement.

 

 

 

      ·          לולאה המבקשת מהמשתמש להכניס קלט תקין (בחירת כן/לא).

#include <iostream.h>

void main()

{

    cout << "Want a gift? Please choose [y/n]: ";

    char c;

    int n_err = 0;

 

    cin >> c;

    while(n_err < 3 && c != 'y' && c != 'Y' && c != 'n' && c != 'N')

    {

        cerr << "Sorry, Please choose [y/n]: ";

        cin >> c;

        n_err++;

    }

    if(n_err == 3)

        cerr << "can't get your intention" << endl;

    else if (c != 'y' || c != 'Y')

        cout << "Greedy you :-(" << endl;

    else       // (c != 'n' || c != 'N')

        cout << "Gifts hater will live :-)" << endl;

}

 

      ·          היכן מקודם משתנה הלולאה: שים לב כי בתוך גוף הלולאה  i  כבר התקדם.

#include <iostream.h>

void main()

{

    int i = 1;

    while(i++ < 3)

        cout << i << endl;

}

 

---------Output----------

2

3

 

 

 

 

4.      עוצרים את הלולאה כאשר יש שלשה ערכים עוקבים גדולים מ 200.

int temp, consecutiveHighs = 0;

cin >> temp;

while (consecutiveHighs < 3)

{

    if (temp > 200) consecutiveHighs++;

    else            consecutiveHighs = 0;

    cin >> temp;

}

הוראת  do-while

do

    statement

while (expression);

                        ·      מבצעים את ה  statement.

                        ·      מחשבים את הבטוי  expression, שהוא יכול להיות מכל טיפוס מספרי (שלמים או ממשי).

                        ·      אם התנאי נכון (ערכו שונה מ 0) מבצעים את  statement,  וחוזרים לבדוק את התנאי.

                        ·      אם התנאי אינו נכון (ערכו 0) מפסיקים את בצוע הלולאה (אין מבצעים את ה statement) וממשיכים לבצע את ההוראה הבאה אחרי הלולאה.

 

                        ·      בלולאת  while  קודם בודקים את התנאי ורק אם הוא נכון מבצעים את גוף הלולאה.

                        ·      בלולאת  do-while  תמיד מבצעים את גוף הלולאה בפעם הראשונה ורק לאחר מכן בודקים את התנאי.

 

                        ·      בלולאה, שמוצאת שלושה ערכים עוקבים גדולים מ- 200, האיטרציה הראשונה תמיד מבוצעת ולכן do-while עדיף:

int temp, consecutiveHighs = 0;

do

{

    cin >> temp;

    if (temp > 200) consecutiveHighs++;

    else            consecutiveHighs = 0;

}

while (consecutiveHighs < 3);

 

                        ·      אנו רוצים לחשב סכום של מספר לא ידוע של מספרים חיוביים אשר מכניס המשתמש. נסיים את הלולאה אם המספר שנקרא לא יהיה חיובי. שימוש ב  do-while  אינו מתאים כאן כי הנתון הלא חיובי מתוסף לסכום:

int n, sum = 0;

do

{   cout << "Entry?\n";

    cin >> n;

    sum += n;

} while (n > 0);

cout << "the sum is " << sum;

 

                        ·      סדרת פיבונצ'י מוגדרת: a0=0, a1=1, a2=1, a3=2, a4=3,... ai = ai-1 + ai-2

void main()

{

    int n;

    long f0 = 0, f1 = 1, t;   

    cin >> n;    // read the element number.

    if (n > 0)

    {

        f0 = 0; f1 = 1;

        while (n-- > 1)

        {

            t = f0 + f1;

            f0 = f1;

            f1 = t;

        }

    }

    else

        n = 0;

    cout

       << "the " << n << "'th elemnt of Fibonachi sequence is:

       <<  f1;

}

 

                        ·      מממ  gcd מחלק משותף מירבי (greatest common divisor) של המספרים השלמים A  ו  B  מוגדר להיות המספר הטבעי הגדול ביותר המחלק את  A  וגם את  B  ללא שארית.  אוקלידס המציא את השיטה (האלגוריתם) הבאה:

 

  1.  חלק את במספר הגדול במספר הקטן.  אם שארית החלוקה היא 0 הרי המספר הקטן הוא ה מממ.

  2.  קח את שארית החלוקה להיות המספר הקטן החדש ואת המספר הקטן הישן להיות המספר הגדול החדש. חזור לשלב 1.

void main()

{

    int i, j;

    cin >> i >> j;  // read two numbers

    if (i == 0 || j == 0) // if i or j is zero return the other value.

        cout << "The gcd is: " << i + j;

    else {

        while ((i %= j) != 0)// remainder replaces dividend.

        {                    // but remainder should replace divisor!

            int t = i; // swap dividend and divisor.

            i = j;

            j = t;

        }

        cout << "The gcd is: " << j << endl;

    }

}

המפעיל  ,  פסיק

      ·          המפעיל  ,  מיועד  לסדר בצוע של חישובים:

expr1 , expr2

                        ·      הבטוי  expr1, expr2   מחושב משמאל לימין:  קודם מחשבים את expr1  ולאחר מכן את expr2.

                        ·      ערך הבטוי הוא הערך של  expr2  והטיפוס של הביטוי הוא הטיפוס של  expr2.

                        ·      הקדימות של המפעיל  ,  היא הנמוכה ביותר.

דוגמא:

int x, y, z, w;

x = (1, 2, 3);             // x<-3

x = (y = 1, z = 2, w = 5); // x<-5 and side effects to: y, z, w

 

if (i < 20)

    i++, j = 8, break;  // use to concatenate expressions

לולאת for

 

                        ·      בהרבה מקרים מספר האיטרציות שהלולאה צריכה לבצע נקבע לפי נתונים הידועים לפני תחילת בצוע הלולאה. במצב זה נהוג להשתמש בלולאה מסוג  for. אך אפשר להשתמש בלולאת  for  גם למקרים אחרים.

 

for (initStatement; testExpression; iterationExpression)

    statement

ראינו כי זה שקול ללולאה             

initStatement;

while (testExpression)

{

    statement

    iterationExpression;

}

1.      בתחילה מבצעים initStatement. זהו אתחול הלולאה המתבצע פעם יחידה.

2.      מחשבים את הבטוי  testExpression, שהוא יכול להיות מכל טיפוס מספרי (שלמים או ממשי).

3.      אם הוא נכון מבצעים את גוף הלולאה: statement.

4.      אם התנאי אינו נכון מפסיקים את בצוע הלולאה.

5.      לאחר בצוע ה statement  מבצעים את שלב קידום הלולאה: iterationExpression, ולאחר מכן חוזרים לבדוק את התנאי הלולאה.

 


לדוגמא:

                        ·                        חישוב ממוצע של 100 מספרים

void main()

{

    int n, sum = 0;

    cout << "Enter 100 integers: " << endl;

    for (int i = 1; i <= 100; i++)

    {   cin >> n;

        sum += n;

    }

    cout << "The average is " << double(sum) / 100 << '\n';

}

                        ·                        בדרך כלל נהוג לבצע N איטרציות באופן הבא:

for (int i = 0; i < N; i++)

 

הערה:  אנו מניחים שאין משנים את  i  בתוך האיטרציה עצמה.

 

for(;;) // infinite loop

 

same as:

while(true)

דוגמאות:

for (int i=-20, j=30; i + j ; i+=2, j-=4)

    cout << i+j;

 

output: 10 8 6 4 2

                        ·                        חישוב שונות (מושג מסטטיסטיקה)

 נוסחת השונות:     

  הערך הממוצע של  x :      

פתוח הנוסחא כדי שלא נהיה חיבים לדעת מהו ה x הממוצע מראש:

     

הנוסחא הסופית:

 

 .    

 

 

// calculates the average and variance for a user defined number

// of x's.

void main()

{

    int n;

    cout << "Enter number of x's: ";

    cin >> n;  // get the number of elements

    double sumx = 0;    // sum of x

    double sumSqrx = 0; // sum of x*x

    double x;

    for (int i = 0;i < n; i++)

    {

        cout << "Enter x " << i << " :";

        cin >> x;

        sumx    += x;

        sumSqrx += x * x;

    }

    double avgx     = sumx / n;

    double variance = sumSqrx / n - avgx * avgx;

    cout << "The results for " << n << " x's are: " << endl;

    cout << "Average:  " << avgx     << endl; // endl same as '\n'

    cout << " variance:" << variance << endl;

}


הוראות  break, continue  בלולאות

 

break  

                           ·   יציאה מלולאה או  switch הפנימיים ביותר  שהפקודה נמצאת בה.

                           ·   הפקודה פועלת על:  for, while, do-while, switch

                           ·   השימוש הנפוץ ביותר של פקודת break  הוא בתוך  switch  והמטרה  למנוע בצוע של  ה caseים הבאים.

 

continue

                           ·   עובר לאיטרציה הבאה של הלולאה הפנימית ביותר שנמצאת בה הפקודה:

                           ·   בלולאת for  עובר מיד לחלק הקידום (ומשם לבדיקת התנאי).

                           ·   בלולאת while, do-while  עובר מיד לחלק של בדיקת התנאי.

                           ·   הפקודה מתעלמת לחלוטין מ switch!

 

דוגמאות:

דוגמא זו קוראת מהמשתמש 10 מספרים ומדפיסה את סכום החיוביים מביניהם.

 

// loop to sum positive numbers

const int N = 10;

double sum = 0, x;

for (int j = 0; j < N; j++)

{

    cin >> x;

    if (x < 0)     // skip negative elements

        continue;

    sum += x;      // sum positive elements

}

 

דוגמא לכך שההוראה continue  מתעלמת מההוראה  switch

void main()

{

    int i, j;

 

    for (i = 1; i < 6; i *= 2)  // i takes the values 1, 2, 4.

    {

        switch (i)

        {

        case 1:

            j = 17;

            break;    // 'break' belongs to switch.

        case 2:

            j = 35;

            continue; // 'continue' belongs to for. Hence no printing

        case 4:

            j = 71;

            break;

        default:

            j = 0;

        }

        cout << ' ' << i << ' ' << j << ';';

    }

}

 

OUTPUT: 1 17; 4 71;


תכנון טוב של לולאות

1.      חייבים לדאוג שבכל מקרה יסתיים בצוע הלולאה. בדרך כלל הסיום נגרם על ידי הפיכת תנאי הלולאה להיות שקר. צריך להבטיח שזה יקרה עבור כל האפשרויות של הפעלת הלולאה. אם התוכנית אינה מסתיימת תוך זמן סביר יש לחשוש שהדבר קרה בגלל שהתוכנית מבצעת לולאה אינסופית.

2.      בדרך כלל התנאי נקבע על ידי בדיקת יחס בין ערכים, ובהרבה מקרים היחס הוא בין משתנה וקבוע.

int j;

cin >> j;      

while (--j != 0)

 מה יקרה כאשר קראנו ערך שלילי לתוך j? - "לולאה אינסופית"!  פתרון אפשרי:

cin >> j;      

if (j > 0)

    while (--j != 0)

 

int j = 9;

while (j != 0) 

    j -= 2;

 

במקרה זה j יקבל ערכים אי זוגיים ובכל מקרה ערכו לא יגיע ל 0, שהוא מספר זוגי! - לולאה אינסופית! דרך טובה יותר:

while (j > 0) 

    j -= 2;

 

for (double d = 0; d != 1; d += 0.1)

{

    ...

}   

   ·   מוצגים כאן 13 הערכים הראשונים של  d,  כפי שהתקבלו על מחשב  PC.  שים לב שהערך 1.0 לא התקבל,  ולכן הלולאה לא הסתיימה "כצפוי".

   ·   הסיבה היא שאין ייצוג מדוייק למספר 0.1 אלא רק קרוב אליו.

// values of d

 0.000000000000000000

0.100000000000000006

0.200000000000000011

0.300000000000000044

0.400000000000000022

0.500000000000000000

0.599999999999999978

0.699999999999999956

0.799999999999999933

0.899999999999911

0.999999999999999889

1.099999999999999870

1.199999999999999960

 

פתרון מומלץ הוא:

for (double d = 0; d < 0.99; d += 0.1)

אם d עולה בצעדים של 0.01  אזי כדאי לכתוב:

for (double d = 0; d < 0.999; d += 0.01)

 

3.      שים לב כי בתוך גוף הלולאה ישנן הוראות שצריכות להתבצע בכל איטרציה של הלולאה.

4.      באופן כללי, יש להמנע מהגדרה בתוך גוף הלולאה של משתנים ובמיוחד של עצמים. הסיבה היא הזמן הדרוש להכין מקום בזכרון עבור משתנה ובמיוחד הקריאה ל constructor עבור עצם, בכל איטרציה.

5.      אם גוף הלולאה מכיל הרבה הוראות כך שלא ברור מה נעשה בו, כדאי לשקול להגדיר פונקציות נוספות אשר תבצענה את פרטי החישוב ולקרא להן מגוף הלולאה. במקרה וקיימת בעיה של מהירות ביצוע אפשר לשקול להגדירן כ  inline.

6.      זכור כי ההוראות המופיעות בגוף הלולאה מבוצעות בכל איטרציה של הלולאה. לכן אם יש לנו לולאה בתוך גוף של לולאה אחרת הרי הלולאה הפנימית תתבצע בשלמותה בכל איטרציה של הלולאה החיצונית.

// multiplication table

const int N = 9;

for (int i = 1; i <= N; i++)

{

    for (int ij, j = 1; j <= N; j++) {

        if ((ij = i * j) < 10)

           cout << ‘ ‘;

        cout << ij;

    }

    cout << ‘\n’;

}


משחק ניחוש מספרים

      ·          משחק לניחוש מספר. במשחק זה המחשב בוחר מספר והמשתמש בוחר מספר. המחשב והמשתמש מנסים לנחש את המספר של השני. בכל שלב המשתמש נותן ניחוש למספר שהמחשב בחר ומקבל כתשובה האם המספר גדול/קטן או שזהו בדיוק המספר שבחר המחשב. לאחר מכן המחשב מנסה לנחש את המספר של המשתמש וממתין לתשובה: גדול/קטן/בדיוק.

      ·          הפונקציה  rand()  מחזירה מספר אקראי בין  0..RAND_MAX.  הפונקציה נותנת את אותה סדרה של מספרים אקראיים בכל הרצה (חשוב ל debugging)  אם רוצים סדרת מספרים שונה חייבים, להפעיל את הפונקציה srand(n)  כאשר לכל מספר שלם  n  rand()  תתן סדרה שונה של מספרים. בכדי ש  n  יהיה שונה בכל הרצה  קוראים לפונקציה  time(0)  אשר מחזירה את הזמן כרגע.

#include <iostream.h>

#include <stdlib.h> // srand(), rand(), exit()

#include <time.h>   // time()

void main()

{   cout << "Number-Guessing game" << endl;

    cout << "First one who gusses the others number win" << endl;

    cout << "Write down your number [1..1000]" << endl;

    srand(time(0));// set rand() to a different sequence each run.

    int my_n = 1 + rand() / (RAND_MAX/999);  // choose from: [1..1000]

    cout << "I wrote down my number" << endl;

    int range_l = 1, range_h = 1000;  // computer gussing range

    while (range_l != range_h)

    {

        cout << "Enter your guess [1..1000]: ";

        int users_guess;

        cin >> users_guess;

        if (users_guess == my_n)

        {

             cout << "you won! my number is: " << my_n << endl;

             exit(0);

        }

        if (users_guess > my_n)

            cout << "My number is smaller" << endl;

        else

            cout << "My number is bigger" << endl;

        int my_guess = range_l + rand() % (range_h - range_l + 1);

        cout << "My guess for your number is: " << my_guess << endl;

        cout << "Enter Y-yes B-Bigger S-Smaller: ";

        char c;

        do {

            cin >> c;

            c = toupper(c);

            switch(c)  {

            case 'Y':

                cout << "I wone!!!" << endl;

                exit(0);

            case 'B':

                range_l = my_guess + 1;

                break;

            case 'S':

                range_h = my_guess - 1;

                break;

            default:

                cerr << endl << "Enter Y-yes B-Bigger S-Smaller: ";

            }

        } while(c != 'B' && c != 'S');     

    }

    cout << "I won your number is: " << range_l << endl;

}

 


מחלקה פשוטה ועצמים פשוטים - שימוש במבנה  struct

קיימים מקרים בהם רוצים להתייחס אל גוש נתונים כאל מייצגים מושג אחד. לדוגמא המושג נקודה דו מימדית כולל בתוכו שני נתונים: קורדינטות  x,y.

הגדרת מושג חדש נעשית בשני שלבים:

       1.         הצהרה על המושג החדש.  מכונה הצהרה על מחלקה חדשה.

       2.         הגדרת עצמים (כמו משתנים) מסוג אותה המחלקה החדשה.

       3.         נהוג להצהיר על מחלקות פשוטות באמצעות המילה  struct (ועל מסובכות יותר באמצעות המילה class).

      נראה את ההבדל, הקטן,  בין  class  ל  struct  בהמשך.

 

      ·          כאשר רוצים להגדיר מושג חדש בתוכנית על ידי גוש נתונים, אפשר לעשות זאת באמצעות מבנה.

 

#include <iostream.h>

 

struct p2d {

    int x;

    int y;

};

 

void main()

{

    p2d p1, p2;

    p2d p3 = {1, 4};

    // error: p3 = {5, 6}; - {...} used only in initialization.

 

    cout << p3.x << ' ' << p3.y << endl;

    p1.x = 2;

    p1.y = 3;

    cout << p1.x << ' ' << p1.y << endl;

    p2 = p1;  // copy the entier struct.

    cout << p2.x << ' ' << p2.y << endl;

 

    cout << "Enter x y: ";

    cin >> p1.x >> p1.y;

    cout << "You Entered: " << p1.x << ' ' << p1.y << endl;

    // cin >> p1 - Error - dosn't know the user defined type!

    // cout << p1 - Error - dosn't know the user defined type!

}

------- Output ------------

1 4

2 3

2 3

Enter x y: 7 8 

You Entered: 7 8

      ·          הצהרה על מבנה נעשית באופן הבא:

struct name {

    T1 m1;

    T2 m2;

     ...

};

      ·          name  שם המבנה.

      ·          T1  טיפוס של האיבר(member)  הראשון   m1   שם האיבר הראשון.

      ·          T2  טיפוס של האיבר(member)  השנין   m2   שם האיבר השני., וכו'

      ·          ההצהרה על מבנה היא הגדרת טיפוס חדש. שם המבנה הוא טיפוס חדש שניתן להגדיר משתנים מסוגו.

      ·          אסור להצהיר על מבנה באותו שם פעמיים (אפילו אם ההצהרות זהות).

      ·          מותר לאתחל מבנה עם  {...}  אבל אסור להשתמש בסוגריים מסולסלים בהשמות.

      ·          השמה '='  בין שני מבנים מעתיקה את כל המבנה.

      ·          אופרטור הנקודה מאפשר לגשת לנתון פנימי בתוך עצם מסוג המחלקה.


      ·          מותר להצהיר על מחלקה המורכבת מעצמים מסוג של מחלקות אחרות:

 

#include <iostream.h>

 

struct p2d {

    int x;

    int y;

};

 

struct line2d {

    p2d p1;

    p2d p2;

};

 

void main()

{

    line2d l1, l2 = {{1,2}, {3, 4}};

    l1 = l2;

    

    cout << l1.p1.x << ' ' l1.p1.y

         << ' ' l1.p2.x << ' ' << l1.p2.y << endl;

}

 

---- Output -------

1 2 3 4

 

חזרה להתחלה

מערכים  arrays 

הגדרת מערכים

T name[n];

7.      זוהי הגדרה של מערך בשם  name  המכיל  n  איברים מטיפוס  T.

8.      מספור האיברים מ  0  עד  n-1, ושמותיהם:   name[0], name[1], ..., name[n-1]

 

 

int  numList[2];

char charArray[8];

p2d  points[3];

   0           1       

 
 

 


  numList

 

0     1    2    3     4    5     6    7    

 

 

charArray

 

0                       1                       2          

 

 

   points

 

 

 

9.      תמיד האינדקס מתחיל ב 0.

10.  אפשר להגדיר מערך של איברים מכל טיפוס - גם טיפוס שהגדיר המשתמש (Fraction) .

11.  מותר גם להגדיר מערך שכל איבר שלו הוא מערך בעצמו.

 

int t[2][3];


 

12. 

t[0]                                       t[1]                

 

 

 

 

 

 

 

 

 

 

 
הגדרנו כי  t  הוא מערך של 2 איברים כאשר כל איבר הוא מערך של 3 איברים מטיפוס  int.

 

  t[1][0]  t[1][1]   t[1][2]    

 

t[0][0]   t[0][1]   t[0][2] 

 

 

 

 

 

 


13.  זוהי הצורה בה מסודר המערך בזכרון המחשב (כסדרה של נתונים).

14.  אפשר לחשוב על המערך כעל טבלא בצורה:

0          1          2  

 

 

0

 

 

 

1

 

 

 

 

 

 

 

הגדרת גודל ואתחול של מערכים

15.  גודל המערך חייב להקבע בזמן ההידור. לכן כאשר מגדירים מערך הגודל חייב להיות ערך קבוע הידוע בזמן ההידור.

const int sz   = 10;

      int size = 10;

 

double a1[sz];    // OK

double a2[size];  // Error: size is a variable, not a constant value.

double a[sz * 6]; // OK: still a constant value.

 

16.  אפשר בזמן ההגדרה (רק בהגדרה) לאתחל את המערך.

int  a[3] = {5, 10, 15};

char s[5] = {'a', 'b', 'c', 'd', 'e'};

17.  אתחול מערך של מערכים:

int tbl[2][3] = {{1, 2, 3}, {4, 5, 6}};

מחרוזות תווים

18.  ב  C++  הטיפוס של מחרוזת תווים הוא מערך של תווים.

19.  אנו יכולים לאתחל מערך של תווים על ידי קבוע מחרוזת.

20.  כל מחרוזת מסתיימת בתו מיוחד (null '\0') המסמן את סופה. לכן, כאשר מגדירים גודל של מחרוזת צריך להוסיף תו אחד עבור סימן סוף המחרוזת: '\0'.

 

char st[6] = "hello"; // short version of:

char st[6] = {'h', 'e', 'l', 'l', 'o', '\0'};

 

 


st:

21.  אפשר שהאתחול יקבע את גודל המערך.

 

char st[] = "hello";   // set array size to 6!

int  a[]  = {1, 2, 3}; // set array size to 3.

 

// tbl has two elements! each one is an array of 3 int's.

int tbl[][3] = {{1, 2, 3}, {4, 5, 6}};

 

22.  כאשר מגדירים מערך חייבים להגדיר במפורש את טיפוס האיבר.  במקרה של  tbl  היינו חייבים לציין במפורש שטיפוס כל איבר של  tbl  הוא מערך של שלושה  int.

23.  אם אין מציינים במפורש את טיפוס האיבר (מערך של שלושה  int) מקבלים טעות:

 

int tbl[][] = {{1, 2, 3}, {4, 5, 6}}; // Error!

 

24.  מסקנה: כאשר מגדירים מערך של מערכים מותר לתת לאתחול לקבוע את מספר האיברים רק ברמה הראשונה של המערך (מותר להשאיר רק את הסוגריים השמאליים ביותר ריקים).

 

25.  אתחול חסר מושלם תמיד עם 0 -ים:

int a[4] = {2, 3};

// same as: = {2, 3, 0, 0};

 

int tbl[2][3] = {{1}, {4, 5}};

// same as: = {{1, 0, 0}, {4, 5, 0}};

 

int tbl[][3] = {{1}, {4}};

// same as: = {{1, 0, 0}, {4, 0, 0}};

 

26.  אסור להגדיר מערך בגודל מסוים ולאתחל אותו עם יותר איברים:

int a[3] = {1, 2, 3, 4}; // Error!

שימוש במערך

 

T  arrName[size];  // definition.

 

arrName[integral-expression];  // using array element.

 

27.  הגדרנו מערך בשם  arrName  בגודל  size  וכל איבר מטיפוס  T.

28.  הגישה לאיבר במערך היא על ידי ציון שם המערך ו integral-expression  ערך מטיפוס של מספר שלם בתוך סוגריים  [].

29.  זכור:  אין בדיקה אם ערך האינדקס מצביע על איבר בתוך המערך או שישנה גלישה מגבולות המערך. אין בדיקה לכך, לא בזמן הידור ולא בזמן ריצה! חריגה מגבולות המערך תגרור התנהגות בלתי צפויה של התוכנית. זהו אחד מה bugs  הקשים ביותר לגילוי.  המתכנת הוא האחראי הבלעדי לכך שמשתמשים במערך בצורה נכונה (פתרון אפשרי נמצא בעמוד 92).

 

void main()

{  

    int i = 10;

    int a[3] = {2, 4, 5};  // a[0], a[1], a[2].

    int j = 20;

 

    a[2] = a[1]; // OK

    a[2]++;      // OK

    a[3] = 4;    // runtime silent error: a[3] is not in range, 

                 //        no run time, or compilation time warnings!

                 //  i OR j might receive value of 4!

    a[-20] = a[12]; // runtime silent error!!!

    a[a[0] * a[1] % 3] += 2; // OK: a[2] += 2;

    a[func(a[0], a[2]) % 3] = -10; // OK: function appears in index.

    cin >> a[0] >> a[1] >> a[2]; // read values to array elements.

}


שימוש הגיוני בהוראת  goto

30.  הוראת goto מיועדת להמשיך את הבצוע ממקום מסוים המתואר על ידי תווית  (label).

31.  בדרך כלל זהו רעיון גרוע להשתמש בהוראת  goto,  במיוחד לקפוץ אחורה בבצוע ולדלג על אתחול משתנים.

32.  לעיתים נדירות הוראת  goto  מסייעת לנו לכתוב תוכנית ברורה וטובה יותר.  

 

#include <iostream.h>

 

const int N = 2;

const int M = 3;

const int L = 2;

const int K = 2;

 

// initialize 23 values, last value is zero.

int v[N][M][L][K] = {

    0,1,2,1,0,3,0,0,1,2,3,4,6,7,8,9,0,1,2,3,-6,5,7

};

 

// Using goto in a manner acceptable to some.

void main()

{

    int n,m,l,k;

    for (n = 0; n < N; n++)

        for (m = 0; m < M; m++)

            for (l = 0; l < L; l++)

                for (k = 0; k < K; k++)

                    if (v[n][m][l][k] < 0)

                        goto found;

 

found:

    cout <<"v["<<n<<"]["<<m<<"]["<<l<<"]["<<k<<"]="<< v[n][m][l][k]

         << endl;

}

 

OUTPUT: v[1][2][0][0]=-6

 

 

 

 

 

 

 


v[1][2]

 

 

 

 

 

 

 


33.  המערך הרב מימדי מסודר בזכרון המחשב כרצף של נתונים. לכן אפשר גם לאתחל אותו כרצף.

34.  המערך  v  הוא של שני איברים, כל איבר מכיל שלושה איברים, כל אחד מהם מכיל שני איברים שכל איבר מורכב משני איברים מטיפוס  int.

                        ·      מתוארת כאן הפריסה של המערך בזכרון.


הגדרת שם חילופי לטיפוס  typedef

ישנם שלושה מקרים בהם נשקול להשתמש בהגדרת שם חילופי לטיפוס:

   1.   מתן כינוי משמעותי יותר לטיפוס.

   2.   לתת שם מקוצר לטיפוס שהגדרתו ארוכה.

   3.   להגדיר טיפוס מורכב בשלבים.

 

35.  הצהרת  typedef  נכתבת בדיוק כפי שנכתבת הגדרת משתנה מאותו טיפוס פרט ל:

                          1.  ההצהרה מתחילה במציין  typedef.

                          2.  שם המשתנה הוא השם הנרדף לטיפוס המוצהר.

 

                           ·   מתן כינוי משמעותי:

typedef double dimension;

struct Box {

    dimension length,

              width,

              height;

    double    price;   // price isn't a dimension - use double.

};

36.  הכוונה להדגיש שהמשתנה  width  לדוגמא, מיועד להכיל מידה.

37.  צריך להדגיש שאין מגדירים טיפוס חדש, אלא מגדירים שם חילופי (alias) לטיפוס, שהוא משמעותי יותר למתבונן האנושי. עבור המהדר, משתנה מטיפוס  dimension  הוא משתנה מטיפוס  double!  כלומר עבור המהדר, בכל מקום שמופיע dimension  בעצם מופיע  double.

 

                           ·   מתן כינוי מקוצר

אני משתמש שלוש פעמים במערך של 20 תווים. הייתי מעוניין להגדיר טיפוס של מערך של 20 תווים.

 

typedef char chars20[20];

 

chars20 response;

struct Employee {

    chars20 name;

    chars20 address[3];

};

                           ·   הגדרת טיפוס מורכב בשלבים:

struct Complex {

    double real, imaginary;

};

typedef Complex Cvector[4];  // type: array of 4 Complexes

typedef Cvector Cmatrix[4];  // type: matrix 4´4 Complexes

 

 

חזרה להתחלה

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 



[1] במחשבים מסוימים ל int גודל של 4 בתים.

[2] במחשבים מסוימים ל long double גדלים שונים.