Bài kiểm tra

Bộ bài toán 1

Hãy nghiên cứu chương trình sau rồi trả lời các câu hỏi dưới đây. Chúng tôi muốn bạn trả lời các câu hỏi bằng cách chỉ xem mã nguồn, tức là đừng sao chép mã nguồn vào một tệp, hãy biên dịch mã và trả lời các câu hỏi dựa trên việc chạy mã đó. Điều đó sẽ giúp bạn tận hưởng niềm vui hết mình!

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);
}

Câu hỏi 1: Kết quả của chương trình này là gì?

Đáp) 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
D) 1 1
2 4
1 1
1 1
2 4
E) Thao tác này không tạo ra kết quả gì – có lỗi về cú pháp.

Câu hỏi 2: Điều gì sẽ xảy ra nếu chúng ta xoá tuỳ chọn khởi chạy "bộ đếm" trước vòng lặp do-when?

Đáp) Vòng lặp vô hạn – vòng lặp do- while sẽ tạo ra một chuỗi
B) Kết quả đầu ra của chương trình sẽ không thay đổi
C) Vòng lặp do-trong khi kết quả đầu ra là 2 và 4.
D) Vòng lặp do- while sẽ không tạo ra kết quả nào
E) Vòng lặp do-when đầu ra 3 và 9.

Câu hỏi 3: Với chương trình ban đầu ở đầu trang này, giả sử chúng ta đã xoá dòng khởi chạy biến bộ đếm trước vòng lặp trong khi đang thực hiện. Điều gì sẽ xảy ra nếu chúng ta cũng xoá dòng bộ đếm ++ bên trong vòng lặp while như sau?

Đáp) Vòng lặp while không tạo ra kết quả nào.
B) Vòng lặp while cho ra 1 và 1; vòng lặp do- while không có kết quả nào.
C) Kết quả của vòng lặp while giống như khi có cả hai dòng.
D) Hệ thống sẽ xuất ra các số ngẫu nhiên cho đến khi chúng ta tắt máy tính.
E) Vòng lặp while là một vòng lặp Infinite

Câu hỏi 4: Với chương trình ban đầu ở đầu trang này, điều gì sẽ xảy ra nếu vòng lặp while trông như thế này?

counter = first;
while (counter <= last) {
  cout << "\n" << counter;
  if (first % 2 == 0)
    next = counter * counter;
  cout << "  " << next;
  counter++;
}
Đáp) Kết quả của vòng lặp while giống như trong chương trình gốc.
B) Vòng lặp while sẽ không tạo ra kết quả nào
C) Đầu ra của vòng lặp while là 1 1 và 1 4.
D) Kết quả của vòng lặp while là 1 2 và 2 4.
E) Kết quả của vòng lặp while là 1 4 và 2 4.
T) Kết quả của vòng lặp while là 2 4 và 2 4.

Câu hỏi 5: Điều gì sẽ xảy ra nếu biến đầu tiên lớn hơn biến cuối cùng?

Đáp) Vòng lặp while sẽ tạo ra nội dung nào đó, nhưng không tạo ra nội dung nào khác.
B) Vòng lặp do while sẽ tạo ra một giá trị, nhưng không tạo ra bất kỳ giá trị nào khác.
C) Sẽ không có kết quả nào.
D) Chương trình sẽ phân loại lỗi hoặc sự cố
E) Vòng lặp for sẽ tạo ra nội dung nào đó, nhưng không tạo ra nội dung nào khác.

Câu hỏi 6: Chương trình sẽ tạo ra kết quả gì nếu chúng ta khởi tạo biến đầu tiên giống với biến cuối cùng?

Đáp) Vòng lặp do while sẽ tạo ra một giá trị, nhưng không tạo ra bất kỳ giá trị nào khác.
B) Vòng lặp while sẽ tạo ra nội dung nào đó, nhưng không tạo ra nội dung nào khác.
C) Mỗi vòng lặp sẽ cho ra một dòng.
D) Vòng lặp do when sẽ tạo ra 2 dòng và vòng lặp còn lại sẽ tạo ra một dòng.
E) Thao tác này sẽ không tạo ra kết quả nào
T) Vòng lặp for sẽ tạo ra nội dung nào đó, nhưng không tạo ra nội dung nào khác.


Bộ Bài toán 2

Như trong bài toán trước, sau đây là một chương trình mà bạn nên cân nhắc. Vui lòng trả lời các câu hỏi tiếp theo bằng cách chỉ xem mã nguồn.

#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;
}

Câu hỏi 1: Đầu ra của biến Boys trên các dòng được đánh dấu là gì?

Đáp) #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
D) Lớp này không cho ra kết quả vì không biên dịch hoặc chạy.

Câu hỏi 2: Chọn tất cả phương án phù hợp với các dòng sau của chương trình:

void F1(int males, int females);
void F2(int &m, int &f);
Đáp) Các quy tắc C++ nêu rõ rằng chúng ta có thể xoá hai dòng này miễn là các phương thức đã được xác định trước khi sử dụng.
B) Quy tắc C++ nêu rõ rằng tên đối số trong phần khai báo và phần định nghĩa phải giống nhau.
C) Chương trình này sẽ gặp sự cố nếu chúng ta xoá hai dòng này.
D) Việc nêu thông tin khai báo trong phạm vi toàn cục thường phổ biến hơn.
E) Đây được gọi là nội dung khai báo chuyển tiếp.

Câu hỏi 3: Nếu chúng ta di chuyển dòng sau khỏi main() và đặt dòng đó vào phạm vi toàn cục, điều gì sẽ xảy ra?

int Boys = 3, Girls = 5;
Đáp) Kết quả vẫn như cũ.
B) Con trai sẽ = 3 và Con gái sẽ = 5 trong tất cả kết quả
C) Con trai sẽ = 3 và Con gái sẽ = 5 chỉ trong đầu ra từ main()

Câu hỏi 4: Điều gì xảy ra nếu chúng ta thay đổi phần đầu của chương trình thành như sau:

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

void main() {
  //int Boys = 3, Girls = 5;
Đáp) Chương trình sẽ biên dịch nhưng sẽ gặp sự cố khi chúng ta thử và chạy nó.
B) Kết quả sẽ không thay đổi
C) Kết quả sẽ là Bé trai = 3 Bé gái = 5 trong suốt chương trình
D) Kết quả sẽ là Boys = 3 Cô gái = 5 chỉ trong đầu ra từ main()
E) Chương trình có thể sẽ không biên dịch được (tuỳ thuộc vào trình biên dịch).

Câu 5: Dữ liệu được truyền theo giá trị trong F2.

Đáp) Đúng.
B) Sai.


Bộ bài toán 3

Như trong bài toán trước, sau đây là một chương trình mà bạn nên cân nhắc. Vui lòng trả lời các câu hỏi tiếp theo bằng cách chỉ xem mã nguồn.Đoạn mã này thú vị hơn so với hai câu trước – hãy theo dõi mã cẩn thận.

#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;
  }
}

Câu hỏi 1: Chương trình này tạo ra gì với dữ liệu đầu vào là 3 cho hàng và 4 cho cột?

Đáp) 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
D) 1 3 2 4
8 6 7 5
9 11 10 12
E) 1 2 3 4
10 11 12 5
9 8 7 6
G) 9 8 7 6
10 11 12 5
1 2 3 4
C) Nó không tạo ra bất kỳ kết quả nào – logic bị lỗi.
I) Thao tác này không tạo ra kết quả gì – có lỗi cú pháp.
T) Nó không tạo ra bất kỳ kết quả nào – không nên như vậy.
K) Bạn sẽ thấy 12 số đầu tiên trong lúc chờ chạy chương trình.

Câu hỏi 2: Nếu chúng ta thêm dòng sau vào hàm main() thì sao?

MAX_SIZE = 10;
Đáp) Điều này không được cho phép trong C++.
B) Điều này được phép; chương trình sẽ chạy với MAX_SIZE được đặt thành 20
C) Điều này được phép; chương trình sẽ chạy với MAX_SIZE được đặt thành 10.

Câu 3: Xét bốn dòng sau trong chương trình trên:

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) Có thể dùng const trong typedef không?
2) Có thể sử dụng typedef trong phần khai báo trước khi khai báo loại đó không?

Đáp) 1) Có 2) Có
B) 1) Không 2) Không
C) 1) Không 2) Có
D) 1) Có 2) Không

Câu hỏi 4: Chúng tôi có thể sử dụng thành phần sau:

#define MAX_SIZE 20
thay vì:
const int MAX_SIZE = 20;
Đáp) Có, lệnh này sẽ hoạt động và không có vấn đề gì nếu bạn sử dụng #define cho các hằng số trong C++
B) Có, cách này sẽ hoạt động nhưng chúng tôi thường không sử dụng #define cho các hằng số trong C++
C) #define không có sẵn trong C++
D) Bạn không thể làm một trong hai việc này bằng C

Câu hỏi 5: typedef được dùng để tạo biệt hiệu cho tên loại.

Đáp) Đúng.
B) Sai.

Câu hỏi 6: Điều gì sẽ xảy ra nếu chúng ta không khởi tạo mảng là 0 trong hàm Fill()?

Đáp) Mã sẽ chạy nhưng kết quả sẽ là tất cả 12
B) Mã này sẽ chạy tốt và tạo ra kết quả tương tự như thể mảng được khởi tạo ở giá trị 0
C) Chương trình sẽ không chạy hoặc sẽ gặp sự cố
D) Mã sẽ chạy nhưng kết quả đều là 0
E) Thao tác này sẽ chạy nhưng có thể không tạo ra kết quả nào

Câu hỏi 7: Chọn tất cả các câu trả lời phù hợp. Tại sao chúng tôi sử dụng const cho MAX_SIZE trong chương trình này? Việc chỉ nhập "20" thay vì MAX_SIZE ở bất cứ nơi nào cần thiết sẽ dễ dàng hơn sao?

Đáp) MAX_SIZE là giá trị C++ được tích hợp sẵn mà mọi người đều có thể sử dụng. Chỉ cần đặt và sử dụng nó.
B) Bạn nên tránh các biến toàn cục giống như các biến toàn cục
C) Việc sử dụng const giúp chương trình của chúng ta dễ hiểu hơn
D) Các con số thần kỳ trong một chương trình thường được xem là phương pháp hay.
E) Nếu muốn thay đổi MAX_SIZE, chúng ta chỉ cần thay đổi ở một nơi

Câu hỏi 8: Câu lệnh chuyển đổi trong hàm Fill() nên có trường hợp mặc định, vì việc đưa trường hợp này vào được coi là kiểu phù hợp.

Đáp) Đúng.
B) Sai.

Câu 9: Lưu ý trong hàm Fill(), chúng ta khai báo các biến giữa các câu lệnh. Ví dụ: cNum và cRow được khai báo và khởi chạy sau khi vòng lặp for chạy. Phương thức này có hoạt động trong C++ không, hay tất cả các biến phải được khai báo ở đầu hàm?

Đáp) Bạn có thể làm việc này.
B) Tất cả biến phải được khai báo ở đầu hàm.
C) Cả hai cách đều đều sai – C++ không cho phép biến ở bất kỳ vị trí nào trong chương trình.
D) Bạn phải khai báo tất cả biến trong phạm vi toàn cục.

Bộ bài toán 4

Dưới đây là một tập hợp các tệp để xác định và kiểm thử một lớp đơn giản. Như thường lệ, hãy trả lời các câu hỏi tiếp theo bằng cách chỉ tham khảo mã nguồn.

Dưới đây là tệp tiêu đề (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

Dưới đây là tệp .cc được liên kết (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;
}

Và đây là chương trình ứng dụng khách của lớp này (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();
}

Câu hỏi 1: Chương trình này cung cấp thông tin gì?

Đáp) Betsy nói MOO.
betsy nặng 400, là 0 và nói là MOO.
B) Betsy nói MOO.
Betsy nặng 400, màu đen và nói MOO.
C) Betsy nói MOO.
betsy nặng 400, là

Câu hỏi 2: Chúng ta tuyệt đối không đặt mã cho phương thức truy cập và biến thể trong tệp tiêu đề. (Lưu ý rằng trình truy cập là một phương thức trả về một giá trị và trình biến đổi là một phương thức sửa đổi một giá trị.)

Đáp) Đúng.
B) Sai.

Câu hỏi 3: Chúng ta có cần "Cow::" trước mỗi định nghĩa hàm trong cow.cc không?

Đáp) Không – vì có tính năng cow.h
B)

Câu hỏi 4: Vai trò:

#ifndef COW_H
#define COW_H
...
#endif

phát trong tệp tiêu đề?

Hãy chọn tất cả câu trả lời phù hợp:

Đáp) Các thông tin này không phục vụ mục đích nào vì tên của tệp là cow.h không phải COW_H.
B) Nếu không làm như vậy, chúng ta sẽ gặp lỗi thời gian chạy
C) Nếu chúng tôi không làm điều này, chúng tôi có thể thêm tệp đó nhiều lần
D) Chúng không làm gì vì một hoặc nhiều từ khoá bị sai chính tả.
E) Các lớp này không làm gì vì lớp Cow chỉ có một tệp tiêu đề.

Câu hỏi 5: Điều gì sẽ xảy ra nếu chúng ta thêm dòng sau vào cowmain.cc?

cow1.weight_ = 24;
Đáp) Chương trình sẽ chạy và biến trọng lượng sẽ được sửa đổi bằng dòng này.
B) Chương trình sẽ biên dịch và chạy nhưng sẽ gặp sự cố trên dòng đó.
C) C++ không cho phép điều này.
D) Chương trình sẽ biên dịch và chạy, nhưng dòng này không thay đổi biến trọng số.

Câu 6: Khi thực thi dòng sau, hàm khởi tạo trong lớp Cow được gọi:

Cow cow1;

Một số đặc điểm quan trọng của hàm khởi tạo là gì?

Chọn tất cả các câu trả lời phù hợp

Đáp) Phương thức này thường không trả về giá trị nào
B) Nếu chúng ta không cung cấp hàm khởi tạo trong lớp, lớp đó sẽ không biên dịch
C) Hàm khởi tạo trong lớp Cow không điển hình vì hàm này không khởi chạy các biến riêng tư.
D) Các lớp này luôn có cùng tên với lớp
E) Chúng ta có thể có một số hàm khởi tạo trong một lớp miễn là các đối số khác nhau
T) Hàm khởi tạo được gọi khi một lớp được thêm vào.

Câu hỏi 7: Một số đặc điểm quan trọng của hàm khởi tạo là gì?

Đáp) Hàm khởi tạo được gọi khi một đối tượng nằm ngoài phạm vi
B) Hàm khởi tạo có cùng tên với lớp nhưng đứng sau "~"
C) Có lỗi trong hàm khởi tạo trong cow.cc, trong đó hàm này không làm gì cả.
D) Nếu chúng ta không tạo một hàm khởi tạo cho lớp, lớp đó sẽ không biên dịch

Câu 8: Dựa trên cách chương trình ứng dụng sử dụng lớp, hãy xem xét những nội dung sau:

Việc phân chia các thành viên thành công và riêng tư trong lớp Bò là không phù hợp. Tức là nội dung nào đó riêng tư phải ở chế độ công khai hoặc nội dung công khai phải ở chế độ riêng tư.

Đáp) Đúng.
B) Sai.

Câu hỏi 9: Điều gì sẽ xảy ra nếu chúng ta thêm một hàm khởi tạo khác ngoài hàm mà chúng ta phải cow.cc. Hàm khởi tạo mới có dạng như sau

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

Và chúng ta thêm các dòng sau vào main():

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

Chúng tôi có thể làm điều này không?

Chọn tất cả các câu trả lời phù hợp

Đáp) Dòng trong main() nơi chúng ta khởi chạy cow2 sẽ gặp sự cố.
B) Chúng ta chỉ có thể có một hàm khởi tạo.
C) Điều này phổ biến trong C++
D) Có, nhưng đây không phải là cách sử dụng C++ thông thường
E) Mã này sẽ chạy được, nhưng sẽ không tạo ra kết quả nào vì các thuộc tính riêng tư chưa được khởi động.
T) Chúng ta không thể gọi setName(), setColor() và setWeight() từ trong một phương thức của cùng một lớp.


Câu hỏi bổ sung

Câu hỏi 1) Kết quả sau đây là gì?

#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;
}
 

Câu hỏi 2) Hãy xem xét câu lệnh sau, giả sử một lớp Apple đã tồn tại và đã được khởi tạo. Lớp Apple có một biến thực thể color_:

Apple* granny_smith = new Apple; 

Chọn tất cả các câu sau đây:

Đáp) Apple* granny_smith = NULL; nếu (granny_smith == NULL)... Điều này KHÔNG được phép – NULL không phải là một giá trị có thể kiểm tra theo cách này.
B) Apple* granny_smith, fuji; Tệp này khai báo hai con trỏ đến các đối tượng của Apple
C) Biến granny_smith chứa các giá trị biến thực thể được liên kết với một đối tượng Apple
D) Apple* granny_smith = NULL; Không sao cả,
E) Biến granny_smith chứa địa chỉ của một đối tượng Apple
T) string gs_color = *(granny_smith.get_color(); Câu lệnh này trả về màu của đối tượng granny_smith, giả sử đối tượng đó đã được khởi tạo.
G) Bộ nhớ cho đối tượng Apple mới được phân bổ trong vùng nhớ khối xếp
C) Bộ nhớ cho đối tượng Apple mới được phân bổ trên ngăn xếp thời gian chạy
I) int* a = &b; Thao tác này sẽ đặt địa chỉ của b vào a.


Câu hỏi 3) Kết quả của chương trình sau là gì?

#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;
}


Câu trả lời đố vui

Bạn nên cố gắng trả lời tất cả các câu hỏi trên mà không cần xem câu trả lời. Bạn nên nhờ ai đó trợ giúp thay vì chuyển thẳng đến bảng trả lời để được trợ giúp.

Bạn có thể xem câu trả lời cho các vấn đề trên tại đây.