Nội dung
C++ là xương sống của nhiều ứng dụng doanh nghiệp do sự phổ biến của nó. Cơ hội việc làm ở C++ là rất lớn. Do đó, dưới đây là một số câu hỏi phỏng vấn về C++ mà bạn có thể xem qua sẽ giúp bạn chuẩn bị cho cuộc phỏng vấn C++.
Q1. Tệp Header trong ngôn ngữ C là gì?
- Tệp header là tệp chứa khai báo hàm và định nghĩa macro cho C trong các hàm thư viện được xây dựng.
- Tất cả các hàm thư viện chuẩn C được khai báo trong các tệp header được lưu dưới dạng file_name.h.
- Chúng ta đưa các tệp header này vào chương trình C của mình bằng lệnh “#include” để sử dụng các hàm được khai báo trong tệp header.
- Khi chúng ta đưa tệp header vào chương trình C của mình bằng lệnh “#include”, tất cả mã C của tệp header đều được đưa vào chương trình. Sau đó, chương trình C này được biên dịch bởi trình biên dịch và thực thi.
Q2. Hàm hủy (Destructor) là gì? Nó có thể bị nạp chồng (overloaded) không?
Hàm hủy là hàm thành viên của lớp có cùng tên với tên lớp và được đặt trước bằng ký hiệu (~). Nó được thực thi tự động w.r.t đối tượng ngay sau khi đối tượng mất phạm vi. Nó không thể được nạp chồng và dạng duy nhất là không có tham số.
Q3. Theo mặc định, mọi biến cục bộ của hàm là tự động (auto). Trong hàm dưới đây, cả hai biến ‘i’ và ‘j’ đều là biến tự động
void f()
{
int i;
auto int j;
}
Q4. Các cách khác nhau để truyền tham số cho các hàm là gì? Sử dụng cái nào khi nào?
- Truyền theo giá trị (Pass by value) – Chỉ gửi các giá trị cho hàm dưới dạng tham số. Chúng ta chọn kiểu này nếu không muốn làm thay đổi giá trị của tham số thực tế.
- Truyền theo địa chỉ (Pass by address) – Chỉ gửi địa chỉ của các tham số thực tế thay vì các giá trị. Chọn điều này nếu chúng ta muốn các tham số thực tế được sửa đổi với các tham số chính thức.
- Truyền bằng tham chiếu (Pass by reference) – Các tham số thực tế được nhận với các biến tham chiếu mới C++ làm tham số chính thức. Chọn điều này nếu ta muốn các tham số thực tế được sửa đổi với các tham số chính thức.
Q5. Toán tử số học trong C là gì?
- Các toán tử số học được sử dụng để thực hiện các phép tính toán số học như cộng, trừ, nhân, chia và lấy phần dư trong các chương trình C.
- Các toán tử số học là +, -, *, /,%.
Q6. Tất cả các câu lệnh điều khiển vòng lặp trong C là gì?
Các câu lệnh điều khiển lặp trong C được sử dụng để thực hiện các hoạt động lặp khi điều kiện cho trước là đúng. Khi điều kiện cho trước sai, chương trình sẽ thoát khỏi vòng lặp. Có 3 loại câu lệnh điều khiển vòng lặp trong C là: for, while, do while.
Q7. Sự khác biệt giữa các hàm memcpy() và strcpy() trong C là gì?
- Hàm memcpy() được sử dụng để sao chép một số byte được chỉ định từ bộ nhớ này sang bộ nhớ khác. Trong khi, hàm strcpy() được sử dụng để sao chép nội dung của một chuỗi vào một chuỗi khác.
- Hàm memcpy() hoạt động trên một bộ nhớ thay vì giá trị. Trong khi, hàm strcpy() hoạt động trên giá trị chứ không phải bộ nhớ.
Q8. Dòng mã bên dưới sẽ in ra gì và tại sao?
#include <iostream>
int main(int argc, char **argv)
{
std::cout << 25u – 50;
return 0;
}
Câu trả lời không phải là -25. Thay vào đó, câu trả lời (sẽ khiến nhiều người ngạc nhiên) là 4294967271, giả sử đây là số nguyên 32 bit. Tại sao lại vậy?
Trong C++, nếu kiểu của hai toán hạng khác nhau, thì toán hạng có “kiểu thấp hơn” sẽ được thăng cấp thành kiểu của toán hạng “kiểu cao hơn”, sử dụng hệ thống phân cấp kiểu sau (được liệt kê ở đây từ kiểu cao nhất đến thấp nhất ): long double, double, float, unsigned long int, long int, unsigned int, int (thấp nhất).
Vì vậy, khi hai toán hạng, như trong ví dụ trên, 25u (unsigned int) và 50 (int), 50 cũng được thăng cấp thành số nguyên không dấu (tức là, 50u).
Hơn nữa, kết quả của phép toán sẽ phụ thuộc vào loại của toán hạng. Do đó, kết quả của 25u – 50u cũng sẽ là một số nguyên không dấu. Vì vậy, kết quả của -25 chuyển đổi thành 4294967271 khi được thăng cấp thành một số nguyên không dấu.
Q9. C ++ hỗ trợ đa kế thừa. “Vấn đề kim cương” (diamond problem) có thể xảy ra với đa thừa kế là gì? Cho một ví dụ
Có nghĩa là chúng ta không thể tạo thừa kế lai bằng cách sử dụng kế thừa đa cấp và phân cấp.
Hãy xem xét một ví dụ đơn giản. Một trường đại học có những người liên kết với nó. Một số là sinh viên, một số là giảng viên, một số là quản trị viên, v.v. Vì vậy, một sơ đồ kế thừa đơn giản có thể có nhiều loại người khác nhau trong các vai trò khác nhau, tất cả đều kế thừa từ một lớp “Person” chung. Lớp Person có thể định nghĩa một phương thức getRole() trừu tượng mà sau đó sẽ bị các lớp con của nó ghi đè để trả về kiểu vai trò chính xác.
Nhưng bây giờ điều gì sẽ xảy ra nếu chúng ta muốn mô hình hóa vai trò của một Trợ giảng (TA)? Thông thường, một TA vừa là sinh viên tốt nghiệp vừa là giảng viên. Điều này dẫn đến vấn đề kim cương cổ điển về đa kế thừa và dẫn đến sự mơ hồ liên quan đến phương thức TA’s getRole().
Q10. Lỗi trong đoạn mã dưới đây là gì và nên sửa lỗi đó như thế nào?
my_struct_t *bar;
/* … do stuff, including setting bar to point to a defined my_struct_t object … */
memset(bar, 0, sizeof(bar));
Đối số cuối cùng của memset phải là sizeof(*bar), không phải sizeof (bar). sizeof (bar) tính toán kích thước của bar (tức là chính con trỏ) chứ không phải là kích thước của cấu trúc được trỏ tới bởi bar.
Do đó, mã có thể được sửa bằng cách sử dụng sizeof(*bar) làm đối số cuối cùng trong lệnh gọi tới memset.
Một ứng viên nhạy bén có thể chỉ ra rằng việc sử dụng *bar sẽ gây ra lỗi hủy tham chiếu nếu bar chưa được gán. Do đó, một giải pháp an toàn hơn sẽ là sử dụng sizeof(my_struct_t). Tuy nhiên, một ứng cử viên sắc bén hơn nữa phải biết rằng trong trường hợp này, sử dụng *bar là hoàn toàn an toàn trong lệnh gọi sizeof, ngay cả khi bar chưa được khởi tạo, vì sizeof là được tính trong thời gian biên dịch.
Q11. Giải thích các định tính lưu trữ trong C++
- Const: Biến này có nghĩa là nếu bộ nhớ được khởi tạo một lần, nó sẽ không bị thay đổi bởi một chương trình.
- Volatile: Biến này có nghĩa là giá trị trong vị trí bộ nhớ có thể được thay đổi mặc dù không có gì trong mã chương trình sửa đổi nội dung.
- Mutable: Biến này có nghĩa là một thành viên cụ thể của một struct hoặc lớp có thể được thay đổi ngay cả khi một biến struct cụ thể, lớp hoặc hàm thành viên lớp là không đổi.
Q12. Viết hàm Display() có hai đối số
cout << A[0] << " ";
cout << A[1] << " ";
…..
cout << A[N-1] << " ";
Nói chung: cout << A[i] << ” ” ; trong đó i = 0 đến N-1
void Display( float A[ ], int N )
{
for ( int i = 0; i<= N-1; i++)
cout << A[i] << " ";
cout << endl;
}
Q13. Tìm kiếm là gì? Giải thích tìm kiếm tuyến tính và nhị phân
Việc tìm kiếm vị trí của một phần tử nhất định trong cấu trúc dữ liệu đã cho được gọi là tìm kiếm. Có hai loại tìm kiếm:
1). Tìm kiếm tuyến tính:
Trong đó, phần tử được tìm kiếm được so sánh từng phần tử của danh sách đã cho, bắt đầu với phần tử đầu tiên. Quá trình so sánh vẫn tiếp tục cho đến khi phần tử được tìm thấy hoặc đến khi hết danh sách.
2). Tìm kiếm nhị phân:
Đó là một kỹ thuật khác để tìm kiếm một phần tử trong danh sách nhất định với các phép so sánh tối thiểu có thể. Nhưng để áp dụng tìm kiếm nhị phân, một danh sách cần thỏa trước hai điều kiện:
- Các phần tử của danh sách phải được sắp xếp theo thứ tự tăng dần hoặc giảm dần.
- Danh sách phải có kích thước hữu hạn và phải ở dạng mảng tuyến tính.
Q14. Viết chương trình sử dụng hàm SHIFT_HALF() để chuyển các phần tử của mảng nửa đầu sang nửa sau và ngược lại
swap(A[0], A[mid])
swap(A[1], A[mid+1])
….
swap(A[mid-1], A[N-1])
mid = n/2; i = 0, j = mid; swap( A[i], A[j] ) trong đó i = 0 đến mid-1.
void SHIFT_HALF( float A[], int n )
{
int mid= n/2;
for(int i = 0, j = mid; i<= mid-1; i++,j++)
{
float T = A[i];
A[i] = A[j];
A[j] = T;
}
}
Q15. Giải thích thuật toán sắp xếp bubble.
Trong Sắp xếp bubble, chúng ta phải thực hiện N-1 bước để sắp xếp một mảng tuyến tính.
- Trong lần lặp đầu tiên, chúng ta so sánh A[0] với A[1], A[1] với A[2], …, A[N-2] với A[N-1] và hoán đổi chúng nếu chúng không theo thứ tự mong muốn.
- Trong lần lặp thứ hai, chúng ta so sánh A[0] với A[1], A[1] với A[2], …, A[N-3] với A[N-2] và hoán đổi chúng nếu chúng không theo thứ tự mong muốn.
- Trong lần lặp thứ ba, chúng ta so sánh A[0] với A[1], A[1] với A[2], …, A[N-4] với A[N-3] và hoán đổi chúng nếu chúng không theo thứ tự mong muốn.
- Trong lần lặp cuối cùng, chúng tôi so sánh A[0] với A[1].
Q16. Các tình huống khác nhau khi một hàm tạo bản sao (copy constructor) được gọi là gì?
Các tình huống khác nhau trong đó hàm tạo bản sao được gọi như sau:
- Khi một đối tượng được định nghĩa và khởi tạo với các giá trị của một đối tượng khác cùng kiểu, thì hàm tạo bản sao được gọi.
- Khi một đối tượng được truyền bằng phương thức giá trị, thì hàm tạo bản sao sẽ được gọi để tạo bản sao của đối tượng được truyền cho hàm.
- Khi một hàm trả về một đối tượng, thì hàm tạo bản sao được gọi để tạo một đối tượng tạm thời để giữ giá trị trả về trong bộ nhớ.
Q17. Liệt kê các đặc điểm đặc biệt của hàm tạo
- Một hàm tạo có cùng tên với tên của lớp.
- Nó tự động được gọi khi một đối tượng của lớp được khai báo.
- Hàm tạo tuân theo quy tắc truy cập thông thường. Hàm khởi tạo là private và protected chỉ có thể được truy cập bởi hàm thành viên và hàm bạn của lớp. Hàm tạo là public có sẵn cho tất cả các hàm. Chỉ hàm đó mới có thể tạo đối tượng có quyền truy cập vào hàm tạo.
- Không có kiểu trả về nào được chỉ định cho hàm tạo.
- Chúng không thể được kế thừa nhưng một lớp dẫn xuất có thể gọi hàm tạo của lớp cơ sở.
- Một hàm tạo cũng có thể có các đối số mặc định.
- Một hàm tạo có thể gọi các hàm thành viên.
- Hàm tạo mặc định và hàm tạo bản sao chỉ được cung cấp bởi trình biên dịch nếu chúng không được người lập trình xác định.
Q18. Làm thế nào một phần tử mới có thể được thêm vào hoặc đẩy vào một ngăn xếp?
Đẩy một phần tử vào ngăn xếp:
- Bất cứ khi nào một phần tử được đẩy vào ngăn xếp, TOP sẽ tăng lên 1 và sau đó phần tử được chèn vào mảng tuyến tính ký hiệu là S[] tại vị trí có chỉ số TOP tức là tại S[TOP]. Trong quá trình push(), một công đoạn có thể xảy ra khi TOP trỏ đến vị trí cuối cùng trong mảng S[] tức là nó bằng stksize-1, khi đó không thể đẩy thêm phần tử nào vào ngăn xếp và chúng ta nói rằng tràn ngăn xếp (stackoverflow).
- Thuật toán Push(S,Top, Item)
- Bước 1: If (Top == stksize-1)
then (i) Write “Stack Overflow ”
(ii) Exit - Bước 2: Top = Top + 1
- Bước 3: S[Top] = Item
- Bước 4: Exit
- Bước 1: If (Top == stksize-1)
Q19. Hàm virtual là gì?
Tính đa hình (Polymorphism) cũng đạt được trong C++ bằng cách sử dụng các hàm ảo (virtual). Nếu một hàm có cùng tên tồn tại trong lớp cơ sở cũng như lớp cha, thì con trỏ đến lớp cơ sở sẽ gọi các hàm chỉ được liên kết với lớp cơ sở. Tuy nhiên, nếu hàm được tạo là virtual và con trỏ cơ sở được khởi tạo bằng địa chỉ của lớp dẫn xuất, thì hàm trong lớp con sẽ được gọi.
Q20. Làm thế nào để xử lý lỗi khi thực thi trong C++?
- Các lỗi thời gian chạy trong C++ có thể được xử lý bằng các ngoại lệ.
- Cơ chế xử lý ngoại lệ này trong C++ được phát triển để xử lý các lỗi trong phần mềm được tạo thành từ các thành phần được phát triển độc lập hoạt động trong một quy trình và được kiểm soát đồng bộ.
- Theo C++, bất kỳ routine nào không thực hiện đúng theo hứa hẹn của nó đều có ngoại lệ. Hàn gọi cần biết cách xử lý những trường hợp ngoại lệ này có thể bắt được nó.
Q21. Đáp án nào sau đây truy cập phần tử thứ bảy được lưu trữ trong mảng?
- array[6];
- array[7];
- array(7);
- array;
Câu trả lời là 1.array[6].
Q22. Kết quả của chương trình sau là gì?
#include <stdio.h>
#include <iostream>
using namespace std;
int array1[] = {1200, 200, 2300, 1230, 1543};
int array2[] = {12, 14, 16, 18, 20};
int temp, result = 0;
int main()
{
for (temp = 0; temp < 5; temp++)
{
result += array1[temp];
}
for (temp = 0; temp < 4; temp++)
{
result += array2[temp];
}
cout << result;
return 0;
}
Kết quả là 6533.
Q23. Chỉ số của phần tử cuối cùng của mảng có 9 phần tử là bao nhiêu?
Kết quả là 8 vì phần tử bắt đầu có chỉ số là 0.
Q24. Định nghĩa đúng về mảng là gì?
Mảng là một chuỗi các phần tử cùng kiểu ở các vị trí bộ nhớ liền nhau.
Q25. Đáp án nào sau đây cung cấp địa chỉ bộ nhớ của phần tử đầu tiên trong mảng?
- array[0];
- array[1];
- array(2);
- array;
Đáp án là array. Để lấy địa chỉ của chỉ số thứ i của một mảng, chúng ta sử dụng cú pháp sau (array + i). Vì vậy, khi chúng ta cần địa chỉ của chỉ mục đầu tiên, chúng ta sẽ sử dụng (array + 0) tương đương với array.
Để lại một bình luận