חידון

קבוצת בעיות 1

עליכם ללמוד את התוכנית הבאה ולענות על השאלות הבאות. אנו מבקשים שתענו על השאלות על ידי עיון בקוד המקור בלבד. כלומר, אין להעתיק אותו לקובץ, להדר אותו ולענות על השאלות על סמך הרצת הקוד. זה ייקח את כל הכיף!

int main() {
  int counter, first, last, next;
  first = 1; last = 2;

  for (counter = first; counter <= last; counter++) {
    cout << "\n " << counter;
    next = counter * counter;
    cout << " " << next;
  }

  counter = first;
  while (counter <= last) {
    cout << "\n " << counter;
    next = counter * counter;
    cout << " " << next;
    counter++;
  }

  counter = first;
  do {
    cout << "\n " << counter;
    next = counter * counter;
    cout << " " << next;
    counter++;
  } while (counter < last);
}

שאלה 1: מה הפלט של התוכנית הזו?

א) 1 2
2 4
1 2
2 4
1 2
4 2
ב) 1 1
2 4
1 1
2 4
1 1
2 4
ג) 1 1
2 4
1 1
2 4
1 1
ד) 1 1
2 4
1 1
1 1
2 4
ה) הוא לא יפיק שום דבר – יש שגיאות בתחביר.

שאלה 2: מה יקרה אם נסיר את האתחול של 'מונה' לפני לולאת 'לעשות-בזמן'?

א) לולאה אינסופית – לולאת 'Do-while' תפיק סדרה של
ב) הפלט של התוכנית לא ישתנה
ג) לולאת ה-Do-while היא פלט 2 ו-4.
ד) לולאת 'לעשות-בזמן' לא תפיק שום דבר
ה) לולאת ה-Do-while היא פלט 3 ו-9.

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

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

שאלה 4: מה יקרה בהינתן התוכנית המקורית בראש הדף אם לולאת ה-time נראה כך?

counter = first;
while (counter <= last) {
  cout << "\n" << counter;
  if (first % 2 == 0)
    next = counter * counter;
  cout << "  " << next;
  counter++;
}
א) הפלט של לולאת ה-time זהה לפלט של התוכנית המקורית.
ב) לולאת בזמן לא תפיק שום דבר
ג) הפלט של לולאת בזמן הוא 1 1 ו-4.
ד) הפלט של לולאת ה-time הוא 1 2 ו-2 4.
ה) הפלט של לולאת ה-time הוא 1 4 ו-2 4.
ו) הפלט של לולאת ה-time הוא 2 4 ו-2 4.

שאלה 5: מה קורה אם המשתנה הראשון גדול מהמשתנה?

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

שאלה 6: מה יהיה הפלט של התוכנית אם נאתחל את המשתנה הראשון יהיה זהה למשתנה האחרון?

א) ה'לייק' יפיק משהו, אבל שום דבר אחר לא יפיק משהו.
ב) הלולאה בזמן תפיק משהו, אבל שום דבר אחר לא יפיק משהו.
ג) כל לולאה תפיק שורה אחת.
ד) פעולת ה'עשה-בזמן' תפיק 2 שורות והשנייה תציג שורה אחת בלולאה.
ה) לא יישמע כלום
ו) בשביל לופ יפיק משהו, אבל שום דבר אחר לא יפיק משהו.


קבוצת בעיות 2

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

#include <iostream>
using namespace std;

int main() {
  int Boys = 3, Girls = 5;
  void F1(int males, int females);
  void F2(int &m, int &f);

  F1(Boys, Girls);
  cout << "\nAfter calling F1, within main()";
  cout << "\n\tBoys = " << Boys; // #2
  cout << "\n\tGirls = " << Girls;

  F2(Boys, Girls);
  cout << "\nAfter calling F2, within main()";
  cout << "\n\tBoys = " << Boys; // #4
  cout << "\n\tGirls = " << Girls;
}

void F1(int b, int g) {
  b += 3, g += 4;
  cout << "\nF1";
  cout << "\n\tBoys = " << b; // #1
  cout << "\n\tGirls = " << g;
}

void F2(int &b, int &g) {
  b = b + 8, g = g + 5;
  cout << "\nF2";
  cout << "\n\tBoys = " << b; // #3
  cout << "\n\tGirls = " << g;
}

שאלה 1: מה הפלט של משתנה בנים בשורות המסומנות?

א) מס' 1:
6 מס' 2:
3 מס' 3: 11
#4: 11
ב) מס' 1:
6 מס' 2:
3 מס' 3: 11
#4:
3
ג) מס' 1:
6 מס' 2:
6 מס' 3: 11
#4: 11
ד) הוא לא מפיק כלום כי הוא לא מהדר או רץ.

שאלה 2: יש לבחור את כל האפשרויות הרלוונטיות לגבי השורות הבאות בתוכנית:

void F1(int males, int females);
void F2(int &m, int &f);
א) לפי כללי C++ אפשר להסיר את שתי השורות האלה כל עוד השיטות מוגדרות לפני השימוש.
ב) כללי C++ קובעים ששמות הארגומנטים חייבים להיות זהים בין את ההצהרה וההגדרה.
ג) התוכנית הזו תקרוס אם נסיר את שתי השורות האלה.
ד) מקובל שההצהרות מתפרסמות היקף.
ה) הן נקראות הצהרות העברה.

שאלה 3: אם נעביר את השורה הבאה מ-main() ומציבים אותה בשדה מה יקרה?

int Boys = 3, Girls = 5;
א) הפלט יהיה זהה.
ב) בנים = 3 ובנות יהיה 5 בכל הפלט
ג) בנים = 3 ו-Girls = 5 רק בפלט מ-main()

שאלה 4: מה יקרה אם נשנה את תחילת התוכנית כך:

// We have moved moved these to global scope
const int Boys = 3;
const int Girls = 5;

void main() {
  //int Boys = 3, Girls = 5;
א) התוכנה תעבור הידור (compile), אבל היא תקרוס כשננסה להפעיל אותה.
ב) לא יהיו שינויים בפלט
ג) הפלט יהיה בנים = 3 בנות = 5 במהלך התוכנית.
ד) הפלט יהיה בנים = 3 Girls = 5 בלבד בפלט מ-main()
ה) סביר להניח שהתוכנה לא תעבור הידור (בהתאם למהדר).

שאלה 5: הנתונים מועברים באמצעות הערך ב-F2.

א) True.
ב) לא נכון.


קבוצת בעיות 3

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

#include <iostream>
using namespace std;

const int MAX_SIZE = 20;
typedef int ARR2D[MAX_SIZE][MAX_SIZE];

void Print(ARR2D in_array, int rows, int cols);
void Fill(ARR2D in_array, int rows, int cols);

int main() {
  ARR2D matrix;
  int row, col;
  do {
    cout << "Please enter the size of the matrix to generate (rows and cols) :" << endl;
    cin >> row >> col;
  } while (row <= 0 || row > MAX_SIZE || col <= 0 || col > MAX_SIZE);
  Fill(matrix, row, col);
  Print(matrix, row, col);
  return(0);
}

void Print(ARR2D in_array, int rows, int cols) {
  for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++)
      cout << '\t' << in_array[i][j];
    cout << endl;
  }
}

void Fill(ARR2D in_array, int rows, int cols) {
  for(int i = 0; i < rows; i++)
    for (int j = 0; j < cols; j++)
      in_array[i][j] = 0;

  const int limit = rows * cols;
  int cNum = 1;
  int cRow = 0;
  int cCol = 0;
  int cDir = 0;  // 0-north, 1-east, 2-south, 3-west

  while(true) {
    // Place the number.
    in_array[cRow][cCol] = cNum;
    cNum++;
    if (cNum > limit) break;

    int fRow = cRow;
    int fCol = cCol;
    while (true) {
      fRow = cRow;
      fCol = cCol;
      switch(cDir) {
        case 0: fRow--; break;
        case 1: fCol++; break;
        case 2: fRow++; break;
        case 3: fCol--; break;
      }

      if ( fRow >= 0 && fRow < rows && fCol >= 0 && fCol < cols && in_array[fRow][fCol] == 0)
        break;
      cDir = (cDir + 1) % 4;
    }
    cRow = fRow;
    cCol = fCol;
  }
}

שאלה 1: מה הפלט של התוכנית הזו עם קלט של 3 בשורות ו-4 בשביל עמודות?

א) 1 2 3
4 5 6
7 8 9
10 11 12
ב) 1 2 3 4
5 6 7 8
9 10 11 12
ג) 12 11 10 9
8 7 6 5
4 3 2 1
ד) 1 3 2 4
8 6 7 5
9 11 10 12
ה) 1 2 3 4
10 11 12 5
9 8 7 6
ז) 9 8 7 6
10 11 12 5
1 2 3 4
ח) הוא לא מפיק שום דבר – הלוגיקה שגויה.
א) הוא לא יפיק שום דבר – יש שגיאות תחביר.
J) הוא לא מפיק שום דבר – הוא לא אמור לפעול כך.
ק) הפלט של 12 המספרים הראשונים שעולים במהלך ההמתנה להפעלת התוכנית.

שאלה 2: מה קורה אם נוסיף את השורה הבאה לפונקציה Main() ?

MAX_SIZE = 10;
א) פעולה זו אסורה ב-C++.
ב) מותר לעשות זאת; התוכנית תפעל כאשר הגודל המקסימלי של MAX_SIZE הוא 20
ג) מותר לעשות זאת; התוכנית תפעל כאשר הערך של MAX_SIZE מוגדר ל-10.

שאלה 3: נבחן את ארבע השורות הבאות מהתוכנית שלמעלה:

const int MAX_SIZE = 20;
typedef int ARR2D [MAX_SIZE][MAX_SIZE];

void Print  (ARR2D A, int rows, int cols);
void Fill   (ARR2D A, int rows, int cols);

1) האם ניתן להשתמש בקבוע ב-typedef?
2) האם ניתן להשתמש בהצהרה מסוג typedef לפני הצהרה על משתנה מהסוג הזה?

א) 1) כן 2) כן
ב) 1) לא 2) לא
ג) 1) לא 2) כן
ד) 1) כן 2) לא

שאלה 4: האם אפשר להשתמש בניסוח הזה:

#define MAX_SIZE 20
במקום:
const int MAX_SIZE = 20;
א) כן, זה יעבוד ואפשר להשתמש ב- #define עבור קבועים C++
ב) כן, זה יעבוד, אבל בדרך כלל אנחנו לא משתמשים ב- #define כדי לציין קבועים ב-C++
ג) #define לא זמין ב-C++
ד) אי אפשר לבצע את שתי הפעולות האלה בשפת C

שאלה 5: typedef משמש ליצירת כינוי עבור שם של סוג.

א) True.
ב) לא נכון.

שאלה 6: מה היה קורה אם לא נאתחל את המערך ל-0 הפונקציה Fill() ?

א) הוא יפעל אבל הפלט יהיה
ב) היא תפעל בצורה תקינה ותפיק את אותו פלט כאילו המערך אותחל ל-0
ג) התוכנה לא תפעל או תקרוס
ד) הוא יפעל אבל הפלט יהיה 0
ה) הוא יפעל אבל לא יוכל ליצור פלט

שאלה 7: מסמנים את כל האפשרויות המתאימות. למה אנחנו משתמשים בקבוע עבור MAX_SIZE בתוכנית הזו? לא קל יותר להקליד "20"? במקום MAX_SIZE בכל מקום מה נדרש?

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

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

א) True.
ב) לא נכון.

שאלה 9: שימו לב בפונקציה Fill() , אנחנו מצהירים על משתנים בין ההצהרות. לדוגמה, המספרים cNum ו-cRow מוצהרים ומאתחלים אחרי הפעלת for-loop. האם זה יעבוד ב-C++ או שצריך להצהיר על כל המשתנים בחלק העליון של את הפונקציה?

א) מותר לעשות זאת.
ב) צריך להצהיר על כל המשתנים בחלק העליון של הפונקציה.
ג) שתי הדרכים שגויות – C++ לא מאפשר משתנים בשום מקום בתוכנית.
ד) צריך להצהיר על כל המשתנים בהיקף הגלובלי.

קבוצת בעיות 4

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

הנה קובץ הכותרת (cow.h):

#ifndef COW_H
#define COW_H

using namespace std;

typedef enum Color {black, brown, beige, blackandwhite, nocolor};

class Cow {
 public:
  Cow();
  ~Cow();

  // accessors
  double weight() { return weight_; };
  string name() { return name_; };
  Color color() { return color_; };

  // mutators
  void set_name(string inName) { name_ = inName; };
  void set_color(Color inColor) { color_ = inColor; };
  void set_weight(double inWeight) {weight_ = inWeight; };

  void Moo();
  void Properties();

 private:
  Color color_;
  double weight_;
  string name_;
};

#endif

זהו קובץ ה- .cc המשויך (cow.cc):

#include <iostream>
#include "cow.h"

using namespace std;

Cow::Cow() {}

Cow::~Cow() {}

void Cow::Moo() {
  cout << name() << " says MOO." << endl;
}

void Cow::Properties() {
  cout << name() << " weighs " << weight() << ", is "
       << color() << " and says MOO." << endl;
}

והנה תוכנית לקוח לכיתה הזו (cowmain.cc):

#include <iostream>
#include "cow.h"

using namespace std;

int main() {
  Cow cow1;
  cow1.set_name("betsy");
  cow1.set_weight(400.0);
  cow1.set_color(black);

  cow1.Moo();
  cow1.Properties();
}

שאלה 1: מה הפלט של התוכנית הזו?

א) בטסי אומרת "MOO".
atsy שווה 400, היא 0 ואומרת MOO.
ב) בטסי אומרת "MOO".
atsy שווה 400, היא שחורה ואומרת MOO.
ג) בטסי אומרת "MOO".
שווה ל-400,

שאלה 2: אסור אף פעם להציב את הקוד עבור שיטות accessor ו-Mutator בקובץ כותרת. (שימו לב שרכיב accessor הוא שיטה שמחזירה ערך ומשתנה היא שיטה לשינוי ערך).

א) True.
ב) לא נכון.

שאלה 3: האם אנחנו צריכים את השדה "Cow::" לפני כל אחת מהגדרות הפונקציות in cow.cc?

א) לא – כי פרה.
ב) כן

שאלה 4: מה התפקיד של:

#ifndef COW_H
#define COW_H
...
#endif

להפעיל בקובץ הכותרת?

יש לבחור בכל התשובות הרלוונטיות:

א) אין להן מטרה כי שם הקובץ הוא cow.h לא COW_H.
ב) אם לא נעשה את זה, נקבל שגיאת זמן ריצה
ג) אם לא נעשה זאת, ייתכן שנכלול את הקובץ יותר מפעם אחת
ד) הם לא עושים כלום כי יש שגיאות איות באחת או יותר ממילות המפתח.
ה) הם לא עושים כלום כי למחלקה של פרה יש רק קובץ כותרת אחד.

שאלה 5: מה יקרה אם נוסיף את השורה הבאה ל-cowmain.cc?

cow1.weight_ = 24;
א) התוכנית תפעל ומשתנה המשקל ישתנה בשורה הזו.
ב) התוכנה תעבור הידור ותרוץ, אבל היא תקרוס בשורה הזו.
ג) C++ לא מאפשר זאת.
ד) התוכנה תאסוף ותרוץ, אבל משתנה המשקל לא השתנה על ידי השורה הזו.

שאלה 6: כאשר מתבצעת הרצה של השורה הבאה, ה-constructor במחלקה של פרה נקרא:

Cow cow1;

מהם המאפיינים החשובים של בנאים?

צריך לבחור את כל האפשרויות הרלוונטיות

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

שאלה 7: מהם כמה מאפיינים חשובים של כלי נשק?

א) מתבצעת קריאה לכלי הוראה כשאובייקט יוצא מההיקף
ב) למשתמש בונה יש שם זהה למחלקה, אבל לפניו מופיע '~'
ג) ב-cow.cc יש בעיה ב-destructor לא עושה שום דבר.
ד) אם לא תיצרו כלי נשק חם עבור הכיתה שלנו, הכיתה לא להדר

שאלה 8: בהתחשב באופן שבו תוכנית הלקוח משתמשת בכיתה, נסו לחשוב הבאים:

חלוקת החברים בכיתת פרה לציבור ולפרטי היא בלתי הולמת. כלומר, משהו שהוא פרטי צריך להיות ציבורי או משהו שהוא ציבורי צריך להיות פרטי.

א) True.
ב) לא נכון.

שאלה 9: מה קורה אם נוסיף עוד constructor בנוסף לזה אנחנו צריכים cow.cc. ה-constructor החדש נראה כך

Cow::Cow(string inName, double inWeight, Color inColor) {
  set_name(inName);
  set_weight(inWeight);
  set_color(inColor);
}

אנחנו מוסיפים את השורות הבאות ל-main():

Cow cow2("milly", 350.2, brown);
cow2.Moo();
cow2.Properties();

האם זה אפשרי?

צריך לבחור את כל האפשרויות הרלוונטיות

א) השורה ב-main() שבה אנחנו מאתחלים את cow2 תקרוס.
ב) יכול להיות לנו רק constructor אחד.
ג) המצב הזה נפוץ ב-C++
ד) כן, אבל זה לא שימוש רגיל ב-C++
ה) זה יפעל כראוי, אבל לא יפיק שום דבר כי לא מאותחלים.
ו) אנחנו לא יכולים לקרוא ל-setName(), setColor() ו-setweight() מתוך הנתונים שיטה מאותה קטגוריה.


שאלות בונוס

שאלה 1) מה הפלט הבא?

#include <iostream>
using namespace std;

void HelpMe(int *p, int *num, int *q);
void WhereAmI(int *p, int *q, int a);

void HelpMe(int *p, int *num, int *q) {
  int a;

  a = 2;
  q = &a;
  *p = *q + *num;
  num = p;
}


void WhereAmI(int *p, int *q, int a) {
  a = 6;
  *p = a + *p;
  *q = a + 3;
  HelpMe(q, &a, p);
}


int main() {
  int *p;
  int q;
  int *num;
  int a;

  a = 3;
  q = 5;
  p = &a;
  num = &q;

  HelpMe(&a, p, num);
  WhereAmI(&q, p, *num);

  cout << "*p = " << *p << " q = " << q << " *num = " << *num << endl;
}
 

שאלה 2) נבחן את ההצהרה הבאה, בהנחה שמחלקה של Apple קיימת ואותחלה. במחלקה של Apple יש משתנה color_ instance:

Apple* granny_smith = new Apple; 

יש לבחור את כל ההצהרות הבאות שהן נכונות:

א) Apple* granny_smith = NULL; if (granny_smith == NULL)... זה לא בסדר - NULL אינו ערך שניתן לבדוק באופן זה.
ב) Apple* granny_smith, fuji; זוהי הצהרה על שני סמנים לאובייקטים של Apple
ג) המשתנה granny_smith מכיל את ערכי המשתנים של המופע שמשויכים לאובייקט של Apple
ד) Apple* granny_smith = NULL; זה בסדר,
ה) המשתנה granny_smith מכיל את הכתובת של אובייקט Apple
ו) string gs_color = *(granny_smith.get_color()); הצהרה זו מחזירה את הצבע של האובייקט granny_smith, בהנחה שהוא אותחל.
ז) נפח האחסון לאובייקט Apple החדש מוקצה בערימה (heap)
ח) נפח האחסון לאובייקט Apple החדש מוקצה בסטאק זמן הריצה
א) int* a = &b; הפעולה הזו משלבת את הכתובת של b ב-a.


שאלה 3) מה הפלט של התוכנית הבאה?

#include <iostream>
using namespace std;

const int kNumVeggies = 4;

void Grill(int squash, int *mushroom);
int Saute(int onions[], int celery);


void Grill(int squash, int *mushroom) {
  *mushroom = squash/4;
  cout << *mushroom + squash << endl;
}

int Saute(int onions[], int celery) {
  celery *= 2;
  onions[celery]++;
  Grill(onions[0], &onions[3]);
  cout << celery << " " << onions[3] << endl;
  return celery;
}

int main() {
  int broccoli, peppers[kNumVeggies], *zucchini;

  for (broccoli = 0; broccoli < kNumVeggies; broccoli++)
    peppers[broccoli] = kNumVeggies - broccoli;
  zucchini = &peppers[Saute(peppers,1)];
  Grill(*zucchini, zucchini);
  zucchini--;
  cout << peppers[3] + *zucchini + *(zucchini + 1) << endl;
}


תשובות לבחנים

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

כאן תוכלו למצוא את התשובות לבעיות שלמעלה.