חידון

קבוצת בעיות 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
2 4
B) 1 1
2 4
1 1
2 4
1 1
2 4
C) 1 1
2 4
1 1
2 4
1 1
ד) 1 1
2 4
1 1
1 1
2 4
ה) הוא לא מפיק שום פלט - יש שגיאות בתחביר.

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

א) לולאה אינסופית - לולאת הזמן תייצר פלט של סדרה של
B) פלט התוכנה לא ישתנה
C) לולאת ה-do-זמן יוצרת את הפלטים 2 ו-4.
ד) לולאת ה-"do-זמן" לא תפיק שום פלט
ה) לולאת ה-do-זמן יוצרת את הפלטים 3 ו-9.

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

א) לולאת הזמן לא יוצרת שום פלט.
B) לולאת ה-AI יוצרת פלטים 1 ו-1. לולאת הזמן לא מפיקה שום דבר.
C) הפלט של לולאת הזמן זהה כאשר שתי השורות כלולות.
ד) המערכת תפיק מספרים אקראיים עד שנכבה את המחשב.
ה) לולאת הזמן היא לולאה אינסופית

שאלה 4: בהתאם לתוכנית המקורית שבחלק העליון של הדף הזה, מה היה קורה אם לולאת הזמן הייתה נראית כך?

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

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

א) הלולאה בזמן אמת תפיק משהו, אבל שום דבר אחר לא יפגע.
B) פעולת ה- Do בעת לולאה תפיק משהו, אבל שום דבר אחר לא יקרה.
C) לא יהיה פלט בכלל.
ד) התוכנה תיראה כמו תקלה או קריסה
ה) ה-for-loop יפיק משהו, אבל שום דבר אחר לא יקרה.

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

א) פעולת ה- Do בעת לולאה תפיק משהו, אבל שום דבר אחר לא יקרה.
B) הלולאה בזמן אמת תפיק משהו, אבל שום דבר אחר לא יפגע.
C) כל לולאה תפיק פלט של שורה אחת.
ד) פעולת פונקציית ה-עשה בזמן לולאה תפיק 2 שורות, והשנייה תייצר שורה אחת.
ה) לא יופקו פלט
ו) ה-for-loop יפיק משהו, אבל שום דבר אחר לא יקרה.


קבוצת בעיות 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
B) #1: 6
#2: 3
#3: 11
#4: 3
C) #1: 6
#2: 6
#3: 11
#4: 11
ד) הוא לא מפיק שום דבר כי הוא לא מבצע הידור או מריץ.

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

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

שאלה 3: מה יקרה אם נעביר את השורה הבאה מ-main() ונמקם אותה בהיקף הגלובלי.

int Boys = 3, Girls = 5;
א) הפלט יהיה זהה.
B) בנים = 3 ובנות יהיה = 5 בכל הפלט
C) בנים = 3 ובנות יהיה = 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;
א) התוכנית תעבור הידור, אך היא תקרוס כשננסה להפעיל אותה.
B) הפלט לא ישתנה
C) הפלט יהיה בנים = 3 בנות = 5 במהלך התוכנית
ד) הפלט יהיה Boys = 3 Girls = 5 only בפלט מ-main()
ה) סביר להניח שהתוכנית לא תבצע הידור (בהתאם להדר).

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

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


קבוצת בעיות 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
B) 1 2 3 4
5 6 7 8
9 10 11 12
C) 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
ח) הוא לא מפיק שום דבר – הלוגיקה פגומה.
I) הוא לא מפיק שום פלט – יש שגיאות תחביר.
י) לא מפיקה פלט כלשהו – זה לא אמור ליצור.
K) הוא מפיק את 12 המספרים הראשונים שחושבים עליהם בזמן שאתם ממתינים להפעלת התוכנית.

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

MAX_SIZE = 10;
א) אסור לעשות את זה ב-C++.
B) זה מותר; התוכנית תפעל כאשר MAX_SIZE מוגדרים ל-20
C) זה מותר; התוכנית תפעל כאשר 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) האם ניתן להשתמש ב-קבוע כהגדרת סוג (type)?
2) האם אפשר להשתמש ב-typedef בהצהרה לפני הצהרה על משתנה מהסוג הזה?

א) 1) כן 2) כן
B) 1) לא 2) לא
C) 1) לא 2) כן
ד) 1) כן 2) לא

שאלה 4: האם אפשר להשתמש בזה?

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

Question 5: typedef משמש ליצירת כינוי לשם סוג.

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

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

א) הוא יפעל, אבל הפלט יהיה כל ה-12
B) הוא יפעל בצורה תקינה ותיצור אותו פלט כאילו המערך אותחל ל-0
C) התוכנית לא תפעל או תקרוס
ד) הוא יפעל, אבל הפלט יהיה אפס
ה) היא תפעל אבל לא תהיה אפשרות ליצור פלט

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

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

שאלה 8: להצהרת ההחלפה בפונקציה Fill() צריך להיות תרחיש ברירת מחדל, כי תרחיש כזה נחשב למתאים עבור כוללים.

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

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

א) מותר לעשות זאת.
B) צריך להצהיר על כל המשתנים בחלק העליון של הפונקציה.
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".
גילה היא 400, היא 0 עם הכיתוב 'MOO'.
B) ביסי אומרת "MOO".
גילה היא במשקל 400, היא שחורה עם הכיתוב 'MOO'.
C) ביסי אומרת "MOO".
שיקי היא 400,

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

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

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

א) לא - מכיוון ש'פרה (cow.h) כלול'
B) כן

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

#ifndef COW_H
#define COW_H
...
#endif

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

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

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

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

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

שאלה 6: לאחר ביצוע השורה הבאה, הבנאי במחלקה פרה נקרא:

Cow cow1;

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

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

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

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

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

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

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

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

שאלה 9: מה קורה אם נוסיף עוד בנאי בנוסף לזה שעלינו לבצע 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 תקרוס.
B) יכול להיות לנו רק בנאי אחד.
C) המצב הזה נפוץ ב-C++
ד) כן, אבל זה לא שימוש אופייני ב-C++
ה) הפעולה הזאת תפעל בצורה תקינה, אבל לא תופק פלט בכלל כי פרטי ה-Private לא אותחלו.
ו) אנחנו לא יכולים לקרוא ל-setName(), setColor() ו-set weight() מתוך שיטה של אותה מחלקה.


שאלות בונוס

שאלה 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_ :

Apple* granny_smith = new Apple; 

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

א) Apple* granny_smith = NULL; if (granny_smith == NULL)... זה לא בסדר – NULL אינו ערך שניתן לבדוק באופן הזה.
B) Apple* granny_smith, fuji; הצהרה של שני מצביעים לאובייקטים של Apple
C) המשתנה granny_smith מכיל את הערכים של המשתנים של המופע שמשויכים לאובייקט של Apple.
ד) Apple* granny_smith = NULL; זה בסדר,
ה) המשתנה granny_smith מכיל את הכתובת של אובייקט Apple
ו) string gs_color = *(granny_smith.get_color(); הצהרה זו מחזירה את הצבע של האובייקט granny_smith, בהנחה שהוא אותחל.
ז) האחסון של אובייקט Apple החדש מוקצה ב-heap
ח) האחסון של אובייקט Apple החדש מוקצה לסטאק זמן הריצה
I) 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;
}


תשובות לבוחן

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

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