Phỏng vấn là một phần quan trọng trong quá trình tuyển dụng nhằm đánh giá kiến thức và kỹ năng của ứng viên. Khi bạn tham gia buổi phỏng vấn C/C++, một số câu hỏi phổ biến có thể xuất hiện. Trong bài viết hôm nay, JobsGO đã tổng hợp các câu hỏi phỏng vấn C/C++ thường gặp, giúp bạn chuẩn bị sẵn sàng để ghi điểm khi trả lời những câu hỏi này.

Xem nhanh nội dung

1. Bộ câu hỏi phỏng vấn C/C++ phổ biến kèm gợi ý trả lời

Dưới đây JobsGO sẽ tổng hợp 40+ câu hỏi phỏng vấn lập trình C++ để bạn tham khảo:

1.1. Tại sao bạn sử dụng ngôn ngữ lập trình C++?

Ngôn ngữ lập trình C được sử dụng vì nó có năm ưu điểm quan trọng: tốc độ xử lý cao, tính di động, tính linh hoạt, tính mô-đun và khả năng mở rộng. Khi đặt câu hỏi phỏng vấn C này, nhà tuyển dụng thường muốn biết về khả năng tận dụng những ưu điểm này. Bạn nên nhấn mạnh việc C tiếp cận gần với mã máy, đem lại hiệu quả cao và cung cấp mức độ kiểm soát linh hoạt hơn cho nhà phát triển.

Phỏng vấn C/C++ - image 1

Bộ câu hỏi phỏng vấn C++ kèm gợi ý trả lời

1.2 Điểm khác biệt chính giữa C và C ++ là gì?

C là ngôn ngữ cơ sở và nền tảng cho nhiều ngôn ngữ lập trình khác, trong đó bao gồm C++. Vì vậy, C và C++ có những đặc điểm khác nhau. Điểm khác biệt chính giữa hai ngôn ngữ này là: C là một ngôn ngữ lập trình hướng thủ tục, trong khi C++ là một ngôn ngữ lập trình hướng đối tượng.

1.3. Tại sao nên sử dụng C thay vì Java?

Có một số lợi ích khi sử dụng ngôn ngữ lập trình C thay vì Java. Trước tiên, C thường có hiệu suất tốt hơn so với Java. Thứ hai, C cho phép truy cập và kiểm soát trực tiếp phần cứng của máy tính. Điều này làm cho C phù hợp cho việc phát triển các ứng dụng như trình điều khiển (driver) hoặc phần mềm nhúng (embedded software). Thứ ba, trong một số trường hợp, khi làm việc với các hệ thống có tài nguyên hạn chế, C cho phép kiểm soát tài nguyên một cách cụ thể và hiệu quả hơn. Cuối cùng, C là một ngôn ngữ đa nền tảng, điều này có nghĩa là mã nguồn C có thể được biên dịch và chạy trên nhiều hệ điều hành và kiến trúc khác nhau.

Với câu hỏi phỏng vấn C này, bạn có thể thêm phần lưu ý rằng: “Lựa chọn giữa C và Java phụ thuộc vào yêu cầu cụ thể của dự án và môi trường phát triển. Mỗi ngôn ngữ có ưu điểm riêng và phù hợp cho các tình huống khác nhau”. Khi đưa ra được câu trả lời như vậy, nhà tuyển dụng sẽ đánh giá cao bạn hơn.

1.4. Cách đặt tên cho 5 kiểu dữ liệu cơ bản được liên kết với C

Hiện nay có năm kiểu dữ liệu trong C cơ bản bao gồm là: int, float, double, char và void. Dưới đây là ví dụ về cách khai báo và sử dụng năm kiểu dữ liệu cơ bản trong ngôn ngữ lập trình C:

phỏng vấn c 1

Cách đặt tên cho 5 kiểu dữ liệu cơ bản

Trong ví dụ trên, chúng ta khai báo và khởi tạo biến intNum kiểu int với giá trị là 1, biến floatNum kiểu float với giá trị là 2.2, biến doubleNum kiểu double với giá trị là 2.34, biến charValue kiểu char với giá trị là ‘H’, và khai báo một hàm function không trả về giá trị (kiểu void).

Lưu ý rằng khai báo và sử dụng các biến và hàm này cần tuân thủ các quy tắc cú pháp và ngữ nghĩa của ngôn ngữ lập trình C.

1.5. Hàm printf () là gì và cách sử dụng của nó thế nào?

Đây cũng là một câu hỏi phỏng vấn C tương đối phổ biến. Hàm printf() là một hàm tiêu chuẩn trong ngôn ngữ lập trình C được sử dụng để in các thông điệp hoặc giá trị ra màn hình console. Nó thuộc thư viện stdio.h.

Cú pháp của hàm printf() là:

phỏng vấn c 2

Cú pháp của hàm printf()

Các tham số của printf() bao gồm:

  • format: Một chuỗi định dạng (format string) để xác định cách hiển thị các giá trị. Chuỗi này có thể chứa các ký tự thông thường và các đặc tả định dạng để hiển thị giá trị của các biến.
  • …: Đây là các tham số tùy chọn, có thể là các biến mà bạn muốn hiển thị giá trị tương ứng với các đặc tả định dạng trong chuỗi format.

Ví dụ, để hiển thị một chuỗi và một số nguyên, bạn có thể sử dụng printf() như sau:

phỏng vấn c 3

Ví dụ cụ thể hàm printf()

Kết quả sẽ là:

phỏng vấn c 4

Kết quả hàm printf() trả về

1.6. Làm thế nào để có thể tăng và giảm trong C?

Trong ngôn ngữ lập trình C, bạn có thể tăng và giảm giá trị của một biến bằng cách sử dụng toán tử tăng ++ và toán tử giảm –. Cú pháp của các toán tử này là:

  • Toán tử tăng ++: ++variable hoặc variable++
  • Toán tử giảm –: –variable hoặc variable–

1.7. Void và return thể hiện điều gì trong ngôn ngữ C?

Lập trình ngôn ngữ C có một số từ khóa được gọi là “từ dành riêng” (reserved words) mà không thể sử dụng làm tên biến, hàm hoặc bất kỳ khai báo nào khác. void và return là một số ví dụ về các từ dành riêng trong ngôn ngữ C.

Khi bạn sử dụng những từ này không theo cú pháp đúng, bạn sẽ gặp lỗi cú pháp trong quá trình biên dịch. Để tránh lỗi này, hãy tuân thủ các quy tắc đặt tên biến và hàm trong ngôn ngữ C. Thông thường, bạn nên chọn các tên biến mô tả ý nghĩa của chúng và không sử dụng từ dành riêng hoặc từ khóa đã được định nghĩa trong ngôn ngữ.

1.8. Khái niệm con trỏ treo lơ lửng trong C

Câu hỏi về con trỏ treo lơ lửng là một trong những câu hỏi thường gặp khi phỏng vấn C.

Trong ngôn ngữ lập trình C, “con trỏ treo lơ lửng” (dangling pointer) là một con trỏ trỏ đến một vùng nhớ đã được giải phóng hoặc không còn hợp lệ. Nó xảy ra khi một con trỏ trỏ đến địa chỉ của một biến hoặc vùng nhớ đã được giải phóng, thông qua việc thu hồi bộ nhớ hoặc qua việc gán giá trị khác cho con trỏ đó.

Khi một con trỏ trở thành con trỏ treo lơ lửng, việc sử dụng nó có thể dẫn đến hậu quả không mong muốn. Khi ta cố gắng truy cập vào địa chỉ mà con trỏ đang trỏ, ta có thể gặp lỗi runtime như crash hoặc kết quả không đoán trước được.

1.9. Cách để bạn có thể lấy được dữ liệu người dùng

Để lấy dữ liệu từ người dùng trong ngôn ngữ lập trình C, bạn có thể sử dụng hàm scanf() để đọc các giá trị từ bàn phím. Hàm scanf() được sử dụng để đọc dữ liệu theo các định dạng đã được chỉ định.

Dưới đây là một ví dụ về cách sử dụng hàm scanf() để lấy dữ liệu từ người dùng:

phỏng vấn Fresher C 5

Cách sử dụng hàm scanf()

Trong ví dụ trên, ta khai báo biến num để lưu trữ số nguyên và mảng name để lưu trữ chuỗi ký tự. Sau đó, ta sử dụng hàm printf() để in ra thông báo yêu cầu người dùng nhập giá trị. Tiếp theo, ta sử dụng hàm scanf() để lấy giá trị từ người dùng và lưu trữ vào biến tương ứng (num và name).

1.10. Sự khác biệt giữa a ++ và ++ a là gì?

Bạn hãy tham khảo thông tin dưới đây để có được câu trả lời cho câu hỏi phỏng vấn C này.

Sự khác biệt giữa a++ và ++a nằm trong cách thức thực hiện phép tăng (++) và thứ tự thực hiện phép toán trong ngôn ngữ lập trình C.

  • a++ là toán tử tăng sau (post-increment). Khi ta sử dụng a++, giá trị của a sẽ được sử dụng trước đó và sau đó giá trị của a mới được tăng lên một.
  • ++a là toán tử tăng trước (pre-increment). Khi ta sử dụng ++a, giá trị của a sẽ được tăng lên một trước và sau đó giá trị mới của a được sử dụng.

1.11. Khác biệt giữa = và == là gì?

Sự khác biệt giữa = và == nằm trong vai trò và ý nghĩa của chúng trong ngôn ngữ lập trình C.

  • = là toán tử gán (assignment operator). Nó được sử dụng để gán giá trị của một biểu thức cho một biến. Ví dụ:
phỏng vấn Fresher C 6

= là toán tử gán được sử dụng để gán giá trị của một biểu thức cho một biến

  • == là toán tử so sánh bằng (equality operator). Nó được sử dụng để kiểm tra xem hai giá trị có bằng nhau hay không. Kết quả của phép so sánh bằng là một giá trị boolean, có thể là true (đúng) nếu hai giá trị bằng nhau, hoặc false (sai) nếu hai giá trị khác nhau. Ví dụ:
phỏng vấn Fresher C 7

== là toán tử so sánh bằng

1.12. Bạn sẽ nhận xét mã trong ngôn ngữ C như thế nào?

Với câu hỏi phỏng vấn C này, để nhận xét mã trong ngôn ngữ C, bạn có hai cách sau:

Nhận xét một dòng (Single line comment): Sử dụng dấu hai chấm kép (//) để bắt đầu nhận xét trên một dòng. Bất kỳ mã nào sau dấu // sẽ được coi là nhận xét và sẽ không được thực thi.

//this is a single line comment

Nhận xét nhiều dòng (Multiple lines comment): Sử dụng cặp ký tự /* để bắt đầu và */ để kết thúc nhận xét trên nhiều dòng. Bất kỳ mã nào nằm giữa các cặp ký tự này sẽ được coi là nhận xét và sẽ không được thực thi.

/* This is a multiple
line code comment */

Cả hai cách trên đều giúp bạn có thể giải thích mã, thêm ghi chú hoặc tạm thời vô hiệu hóa các đoạn mã mà bạn không muốn thực thi trong quá trình phát triển và kiểm thử.

1.13. Có thể chuyển đổi một chuỗi thành một số không?

Trong ngôn ngữ C, bạn có thể chuyển đổi một chuỗi thành một số bằng cách sử dụng các hàm có sẵn như atoi() hoặc strtol().

  • Hàm atoi(): Hàm này chuyển đổi một chuỗi thành một số nguyên (integer). Ví dụ:
phỏng vấn Fresher C 8

Ví dụ hàm atoi()

  • Hàm strtol(): Hàm này chuyển đổi một chuỗi thành một số long nguyên (long integer). Nó hữu ích hơn atoi() khi bạn cần xử lý các giá trị lớn hơn và kiểm soát được các lỗi. Ví dụ:
kinh nghiệm phỏng vấn C 9

Ví dụ hàm strtol()

Lưu ý rằng trong cả hai trường hợp, chuỗi đầu vào cần tuân theo định dạng số hợp lệ. Nếu chuỗi không thể chuyển đổi thành số, kết quả có thể không chính xác hoặc không xác định.

1.14. Câu hỏi phỏng vấn C: Global int là gì?

Trong ngôn ngữ lập trình C, “global int” là một biến kiểu số nguyên (integer) được khai báo và định nghĩa trong phạm vi toàn cục (global scope). Điều này có nghĩa là biến được khai báo bên ngoài bất kỳ hàm nào trong chương trình, và nó có thể được truy cập từ bất kỳ hàm nào trong cùng phạm vi đó.

Khi một biến được khai báo là global, nó tồn tại và giữ giá trị trong suốt quá trình thực thi của chương trình, không bị hủy khi thoát khỏi hàm nào đó. Điều này cho phép các hàm khác nhau trong chương trình truy cập và sử dụng giá trị của biến global mà không cần truyền biến đó qua tham số. Tuy nhiên, việc lạm dụng biến toàn cục có thể khiến mã khó quản lý và dễ dàng gây ra lỗi, đặc biệt trong các dự án lớn do nhiều c++ developer cùng làm việc.

1.15. Tại sao bạn nên sử dụng n ++ thay vì dùng n + 1?

Sử dụng n++ thay vì n + 1 có thể tạo ra một sự khác biệt nhỏ về hiệu suất trong một số trường hợp. Tuy nhiên, sự khác biệt này thường không đáng kể và không ảnh hưởng đến hiệu suất tổng thể của ứng dụng.

Trong hầu hết các trường hợp, việc chọn giữa n++ và n + 1 nên dựa trên yêu cầu và sự rõ ràng của mã nguồn. Sử dụng n++ có thể giúp làm cho mã nguồn trở nên gọn hơn và dễ đọc hơn trong nhiều tình huống. Tuy nhiên, nếu sự rõ ràng của mã là yếu tố quan trọng và bạn muốn truyền tải ý nghĩa một cách rõ ràng, thì sử dụng n + 1 cũng là một lựa chọn hợp lý.

1.16. Câu hỏi phỏng vấn C phổ biến: Macro trong C là gì?

Trong ngôn ngữ lập trình C, Macro là một cách để định nghĩa các hằng số hoặc các đoạn mã được thay thế trong quá trình biên dịch. Nó cho phép bạn định nghĩa các macro, tức là các ký hiệu hoặc tên thay thế, và sau đó sử dụng chúng trong mã nguồn của bạn.

Macro trong C được xác định bằng cách sử dụng tiền tố #define. Bạn có thể định nghĩa một macro để thay thế một giá trị cố định. Ngoài ra, bạn cũng có thể định nghĩa macro để thay thế các đoạn mã.

Macro trong C cung cấp khả năng linh hoạt và tiện ích trong việc thay thế các hằng số và đoạn mã, giúp làm cho mã nguồn dễ đọc và dễ bảo trì. Tuy nhiên, khi sử dụng macro, cần cẩn thận để tránh những vấn đề tiềm tàng như việc định nghĩa trùng lặp hoặc thay thế không đúng.

1.17. Bạn lập trình vòng lặp for như thế nào? Cú pháp là gì?

Với câu hỏi phỏng vấn C này, bạn có thể trả lời như sau: Trong ngôn ngữ lập trình C, vòng lặp for được sử dụng để thực hiện một đoạn mã lặp lại một số lần nhất định. Cú pháp của vòng lặp for là:

kinh nghiệm phỏng vấn C 10

Cú pháp vòng lặp for

Ví dụ:

kinh nghiệm phỏng vấn C 11

Ví dụ lập trình vòng lặp for

1.18. Làm cách nào để bạn lập trình một trường hợp chuyển mạch?

Trong ngôn ngữ lập trình C, bạn có thể sử dụng câu lệnh switch để tạo một trường hợp chuyển mạch (switch case). Cú pháp của câu lệnh switch là:

kinh nghiệm phỏng vấn C 12

Cách lập trình một trường hợp chuyển mạch

1.19. Câu hỏi phỏng vấn C: Rò rỉ bộ nhớ là gì?

Rò rỉ bộ nhớ (memory leak) là một vấn đề trong lập trình khi một phần của bộ nhớ đã được cấp phát cho một biến hoặc đối tượng nhưng không được giải phóng sau khi không còn sử dụng nữa. Khi có nhiều rò rỉ bộ nhớ xảy ra trong chương trình, nó có thể dẫn đến tiêu tốn tài nguyên bộ nhớ không cần thiết và gây ra sự suy giảm hiệu suất của ứng dụng.

Rò rỉ bộ nhớ thường xảy ra khi không giải phóng bộ nhớ đã được cấp phát động bằng các hàm như malloc() hoặc new trong C và C++. Điều này có thể xảy ra khi không sử dụng hàm free() hoặc delete để giải phóng bộ nhớ đã được cấp phát tương ứng. Đây là một vấn đề nghiêm trọng mà bất kỳ c++ developer nào cũng phải tránh, đặc biệt trong các ứng dụng backend hoạt động liên tục trong thời gian dài.

1.20. Cách để bạn hủy phân bổ bộ nhớ?

Để hủy phân bổ bộ nhớ đã được cấp phát trong ngôn ngữ lập trình C, chúng ta sử dụng hàm free(). Hàm free() giải phóng bộ nhớ đã được cấp phát trước đó bằng hàm malloc(), calloc(), hoặc realloc(). Cú pháp sử dụng hàm free() như sau:

kinh nghiệm phỏng vấn C 13

Cách hủy phân bổ bộ nhớ

1.21. Sự khác biệt giữa #include “…” và #include <…>?

Trong phỏng vấn C, sự khác biệt giữa #include “…” và #include <…> liên quan đến cách tìm kiếm và đưa vào mã nguồn (header files) trong quá trình biên dịch.

  • #include “…”: Đây là cách để chỉ định tìm kiếm và đưa vào mã nguồn trong các file nguồn của chính dự án của bạn hoặc các file nguồn cùng thư mục. Khi bạn sử dụng #include “…”, trình biên dịch sẽ tìm kiếm file nguồn trong các đường dẫn tương đối liên quan đến file nguồn đang được biên dịch. Nếu file nguồn không được tìm thấy trong các đường dẫn tương đối, trình biên dịch sẽ tiếp tục tìm kiếm trong các thư mục chuẩn.
  • #include <…>: Đây là cách để chỉ định tìm kiếm và đưa vào mã nguồn trong các file nguồn chuẩn, chẳng hạn như các thư viện tiêu chuẩn của ngôn ngữ C. Khi bạn sử dụng #include <…>, trình biên dịch sẽ tìm kiếm file nguồn trong các đường dẫn chuẩn được định nghĩa trước đó cho việc tìm kiếm thư viện.

1.22. C có thể chạy trên tất cả các hệ điều hành không?

Ngôn ngữ lập trình C là một ngôn ngữ rất linh hoạt và có khả năng chạy trên hầu hết các hệ điều hành hiện có, bao gồm Windows, macOS, Linux và các hệ điều hành nhúng như Android và iOS. Điều này làm cho C trở thành một lựa chọn phổ biến cho việc phát triển ứng dụng đa nền tảng và phần mềm nhúng.

1.23 Câu hỏi phỏng vấn C: Nên sử dụng tab hay dấu cách trong C?

Trong ngôn ngữ lập trình C, việc sử dụng tab hoặc dấu cách để thụt đầu dòng là một quy ước định dạng mã nguồn và tuỳ thuộc vào sở thích, cũng như quy ước của từng dự án hoặc nhóm phát triển. Tuy nhiên, quan trọng nhất là duy trì một quy ước định dạng nhất quán trong toàn bộ mã nguồn để dễ đọc và hiểu.

Có hai phương pháp phổ biến để thụt đầu dòng trong C: sử dụng tab hoặc sử dụng dấu cách. Sử dụng tab có thể giúp thụt đầu dòng nhanh chóng và dễ dàng, trong khi sử dụng dấu cách có thể đảm bảo độ nhìn của mã nguồn ổn định trên mọi môi trường.

Quan trọng nhất là chọn một quy ước và tuân thủ nó trong toàn bộ dự án hoặc nhóm phát triển để đảm bảo tính nhất quán và đồng nhất của mã nguồn.

>>> Xem thêm: Làm bài test mbti để xem bạn phù hợp với công việc nào nhất!

1.24. Lớp (class) và đối tượng (object) trong C++ là gì?

Lớp là một kiểu dữ liệu do người dùng định nghĩa, bao gồm các thuộc tính (dữ liệu) và phương thức (hàm) để mô tả một thực thể. Đối tượng là một thực thể cụ thể (instance) được khởi tạo từ lớp đó, có khả năng lưu trữ giá trị thực tế và thực hiện các hành động đã định nghĩa.

1.25. 4 tính chất của OOP trong C++ là gì?

Lập trình hướng đối tượng (OOP) trong C++ bao gồm 4 tính chất cốt lõi: Tính đóng gói (Encapsulation), tính trừu tượng (Abstraction), tính kế thừa (Inheritance) và tính đa hình (Polymorphism).

Phỏng vấn C/C++ - image 15

Câu hỏi về tính chất của OOP trong C++

1.26. Đóng gói (encapsulation) là gì?

Đóng gói là kỹ thuật gói gọn dữ liệu và mã nguồn thao tác trên dữ liệu đó vào một đơn vị duy nhất (lớp). Nó giúp ẩn các chi tiết cài đặt bên trong và bảo vệ dữ liệu khỏi sự truy cập hoặc thay đổi tùy tiện từ bên ngoài thông qua các phạm vi truy cập (public, private, protected).

1.27. Kế thừa (inheritance) trong C++ là gì? Có mấy kiểu kế thừa?

Kế thừa là khả năng một lớp mới (lớp dẫn xuất) tiếp nhận các thuộc tính và phương thức từ một lớp đã có (lớp cơ sở) để tái sử dụng mã nguồn. C++ hỗ trợ các kiểu kế thừa như: kế thừa đơn, đa kế thừa, kế thừa đa cấp, kế thừa phân cấp và kế thừa lai.

1.28. Đa hình (polymorphism) trong C++ là gì?

Đa hình là khả năng một tác vụ đơn lẻ có thể thực hiện theo nhiều cách khác nhau tùy thuộc vào đối tượng đang thực thi nó. Trong C++, đa hình được chia thành hai loại: đa hình thời gian biên dịch (nạp chồng hàm/toán tử) và đa hình thời gian chạy (hàm ảo).

1.29. Phân biệt ghi đè (override) và nạp chồng (overload)?

Nạp chồng (Overload) xảy ra khi nhiều hàm trong cùng một phạm vi có cùng tên nhưng khác nhau về danh sách tham số (số lượng hoặc kiểu). Ghi đè (Override) xảy ra khi lớp dẫn xuất định nghĩa lại một hàm ảo đã có trong lớp cơ sở với cùng tên và chữ ký hàm để thay đổi hành vi thực thi.

1.30. Early binding và Late binding là gì?

Early binding (liên kết sớm) là quá trình trình biên dịch xác định hàm nào sẽ được gọi ngay tại thời điểm biên dịch code. Late binding (liên kết muộn) là quá trình xác định hàm được gọi tại thời điểm chạy chương trình, thường áp dụng khi sử dụng hàm ảo và con trỏ lớp cơ sở.

1.31. Constructor là gì? Có những loại constructor nào?

Constructor (hàm tạo) là một hàm thành viên đặc biệt có cùng tên với lớp, được gọi tự động khi một đối tượng mới được tạo ra. Các loại constructor chính bao gồm: Constructor mặc định (không tham số), Constructor có tham số và Copy Constructor (hàm tạo sao chép).

1.32. Destructor là gì? Destructor có thể nạp chồng không? Vì sao?

Destructor (hàm hủy) là hàm thành viên có tên giống tên lớp nhưng thêm dấu ~ phía trước, được gọi tự động khi đối tượng bị hủy để giải phóng tài nguyên. Destructor không thể bị nạp chồng vì nó không nhận bất kỳ tham số nào, do đó chỉ có duy nhất một hàm hủy cho mỗi lớp.

1.33. Copy constructor là gì? Khi nào được gọi?

Copy constructor là một hàm tạo dùng để khởi tạo một đối tượng mới bằng cách sao chép dữ liệu từ một đối tượng khác cùng lớp đã tồn tại. Nó thường được gọi khi truyền đối tượng vào hàm bằng tham trị, trả về đối tượng từ hàm, hoặc khởi tạo đối tượng mới gán bằng đối tượng cũ.

1.34. Thứ tự gọi constructor và destructor trong kế thừa?

Khi khởi tạo đối tượng của lớp dẫn xuất, Constructor của lớp cơ sở được gọi trước, sau đó mới đến Constructor của lớp dẫn xuất. Ngược lại, khi hủy đối tượng, Destructor của lớp dẫn xuất được gọi trước, sau đó mới đến Destructor của lớp cơ sở.

1.35. Có thể gọi hàm ảo trong constructor không? Vì sao?

Bạn có thể gọi hàm ảo trong constructor, nhưng tính đa hình sẽ không hoạt động tại thời điểm này. Trình biên dịch sẽ gọi hàm của chính lớp đang được khởi tạo chứ không gọi hàm ghi đè ở lớp dẫn xuất, vì lúc đó lớp dẫn xuất chưa được khởi tạo hoàn tất.

1.36. Hàm ảo (virtual function) là gì?

Hàm ảo là một hàm thành viên trong lớp cơ sở được khai báo với từ khóa virtual và có thể được định nghĩa lại (ghi đè) trong lớp dẫn xuất. Nó giúp chương trình xác định đúng hàm cần gọi tại thời điểm chạy (runtime) thông qua con trỏ hoặc tham chiếu.

1.37. Hàm thuần ảo (pure virtual function) là gì?

Hàm thuần ảo là một hàm ảo không có phần cài đặt (body) trong lớp cơ sở và được gán giá trị bằng 0 (ví dụ: virtual void func() = 0;). Lớp dẫn xuất bắt buộc phải định nghĩa lại hàm này nếu muốn tạo đối tượng từ lớp đó.

1.38. Sự khác biệt giữa hàm ảo và hàm thuần ảo?

Hàm ảo có phần thân hàm trong lớp cơ sở và lớp dẫn xuất có thể chọn ghi đè hoặc không. Hàm thuần ảo không có phần thân trong lớp cơ sở và bắt buộc lớp dẫn xuất phải ghi đè nó (trừ khi lớp dẫn xuất cũng là lớp trừu tượng).

Phỏng vấn C/C++ - image 16

Câu hỏi về hàm ảo và hàm thuần ảo trong C++

1.39. Lớp trừu tượng (abstract class) là gì?

Lớp trừu tượng là lớp chứa ít nhất một hàm thuần ảo. Bạn không thể khởi tạo đối tượng trực tiếp từ lớp trừu tượng mà chỉ có thể dùng nó làm lớp cơ sở (khung mẫu) cho các lớp khác kế thừa.

1.40. Const trong C++ dùng như thế nào?

Từ khóa const dùng để khai báo các đối tượng hoặc biến không thể thay đổi giá trị sau khi khởi tạo. Nó cũng dùng cho các hàm thành viên để đảm bảo hàm đó không làm thay đổi trạng thái dữ liệu của đối tượng gọi hàm, hoặc dùng cho tham số hàm để ngăn chặn việc thay đổi giá trị đối số truyền vào.

>>> Xem thêm: Nhóm tính cách ENTJ và những thông tin không thể bỏ qua

2. 100+ câu hỏi phỏng vấn C/ C++

Theo kinh nghiệm phỏng vấn thực tế, ngoài những câu hỏi phỏng vấn C++ phổ biến trên, Nhà tuyển dụng cũng có thể đưa ra các câu hỏi khác liên quan đến chuyên môn hoặc câu hỏi khám phá thái độ ứng viên như sau:

  • C/C++ là gì? Điểm khác nhau giữa C và C++ là gì?
  • Điều gì làm cho C/C++ trở thành ngôn ngữ lập trình phổ biến?
  • Khái niệm về con trỏ trong C/C++. Giải thích sự khác nhau giữa con trỏ và biến.
  • So sánh mảng và con trỏ trong C/C++.
  • Giải thích khái niệm của hàm nạp chồng (function overloading).
  • Sự khác biệt giữa tham chiếu (reference) và con trỏ (pointer) trong C++.
  • Khi nào thì bạn sử dụng con trỏ và khi nào thì bạn sử dụng tham chiếu?
  • Giải thích khái niệm của hàm ảo (virtual function) trong C++.
  • Tại sao chúng ta cần destructor trong một lớp (class) trong C++?
  • So sánh class và struct trong C++.
  • Giải thích khái niệm của hàm inline trong C++.
  • Điều gì xảy ra khi một ngoại lệ (exception) được ném ra và không được bắt?
  • Sự khác biệt giữa biến toàn cục (global variable) và biến cục bộ (local variable).
  • Khái niệm về hàm con (nested function) trong C.
  • So sánh malloc() và calloc() trong C.
  • Giải thích khái niệm của hàm hủy (destructor) trong C++.
  • Sự khác biệt giữa biến static và biến tự động (automatic variable).
  • Điều gì xảy ra khi ta cố gắng giải phóng một con trỏ đã được giải phóng trước đó?
  • Giải thích khái niệm của hàm const trong C++.
  • So sánh hàm malloc() và operator new trong C++.
  • Giải thích sự khác biệt giữa stack và heap trong C/C++.
  • Điều gì là lỗi “segmentation fault” trong C/C++? Tại sao nó xảy ra?
  • Sự khác biệt giữa việc truyền tham số theo giá trị (pass by value) và tham số tham chiếu (pass by reference).
  • Giải thích khái niệm của hàm tĩnh (static function) trong C++.
  • Sự khác biệt giữa union và struct trong C/C++.
  • Khái niệm về hằng số (constants) trong C/C++. Làm thế nào để định nghĩa và sử dụng hằng số?
  • Sự khác biệt giữa toán tử “++i” và “i++” trong C/C++.
  • Giải thích khái niệm của con trỏ hàm (function pointer) trong C/C++.
  • Cách sử dụng câu lệnh điều kiện if-else trong C/C++.
  • Khái niệm về vòng lặp (loop) trong C/C++. So sánh giữa vòng lặp while, do-while và for.
  • Sự khác biệt giữa các phép toán bitwise (bitwise operations) và phép toán logic trong C/C++.
  • Giải thích khái niệm của cấu trúc dữ liệu mảng (array) trong C/C++.
  • Cách sắp xếp mảng theo thứ tự tăng dần trong C/C++.
  • Giải thích khái niệm của cấu trúc dữ liệu danh sách liên kết (linked list) trong C/C++.
  • Cách thêm một phần tử vào danh sách liên kết trong C/C++.
  • Khái niệm về cấu trúc dữ liệu hàng đợi (queue) trong C/C++.
  • Giải thích khái niệm của cấu trúc dữ liệu ngăn xếp (stack) trong C/C++.
  • Cách thực hiện các phép toán cơ bản trên stack trong C/C++.
  • Khái niệm về cấu trúc dữ liệu cây (tree) trong C/C++.
  • Giải thích khái niệm của cấu trúc dữ liệu cây nhị phân (binary tree) trong C/C++.
  • Cách duyệt cây nhị phân theo thứ tự trước (pre-order traversal) trong C/C++.
  • Cách duyệt cây nhị phân theo thứ tự giữa (in-order traversal) trong C/C++.
  • Cách duyệt cây nhị phân theo thứ tự sau (post-order traversal) trong C/C++.
  • Khái niệm về cấu trúc dữ liệu đồ thị (graph) trong C/C++.
  • Cách thực hiện việc tạo và thêm đỉnh (vertex) trong đồ thị trong C/C++.
  • Giải thích khái niệm của cấu trúc dữ liệu hàng đợi ưu tiên (priority queue) trong C/C++.
  • Cách sắp xếp hàng đợi ưu tiên theo thứ tự giảm dần trong C/C++.
  • Khái niệm về cấu trúc dữ liệu bảng băm (hash table) trong C/C++.
  • Giải thích khái niệm của vùng nhớ động (dynamic memory) trong C/C++.
  • Cách cấp phát và giải phóng vùng nhớ động trong C/C++.
  • Sự khác biệt giữa việc sử dụng “delete” và “delete[]” để giải phóng vùng nhớ động trong C++.
  • Khái niệm về đa luồng (multithreading) trong C/C++. Làm thế nào để tạo và quản lý các luồng (threads)?
  • Cách đồng bộ hóa các luồng (thread synchronization) trong C/C++.
  • Sự khác biệt giữa các loại biến đồng bộ (synchronized variables) như mutex, semaphore và critical section trong C/C++.
  • Giải thích khái niệm của lớp trừu tượng (abstract class) trong C++.
  • Sự khác biệt giữa kế thừa đơn (single inheritance) và kế thừa đa (multiple inheritance) trong C++.
  • Cách sử dụng giao diện (interface) trong C++.
  • Giải thích khái niệm của ngoại lệ (exception) trong C++ và cách sử dụng try-catch để xử lý ngoại lệ.
  • Khái niệm về đa hình (polymorphism) trong C++. Làm thế nào để thực hiện đa hình trong C++?
  • Sự khác biệt giữa việc sử dụng “const” và “constexpr” trong C++.
  • Cách sử dụng namespace trong C++.
  • Khái niệm về con trỏ thông minh (smart pointers) trong C++. Làm thế nào để sử dụng con trỏ thông minh để quản lý bộ nhớ?
  • Sự khác biệt giữa con trỏ unique_ptr, shared_ptr và weak_ptr trong C++.
  • Cách sử dụng chuỗi (string) trong C++.
  • Giải thích khái niệm của đa hình tĩnh (static polymorphism) và đa hình động (dynamic polymorphism) trong C++.
  • Sự khác biệt giữa việc sử dụng “new” và “malloc” để cấp phát bộ nhớ trong C/C++.
  • Cách sử dụng tệp tin (file) trong C/C++. Làm thế nào để đọc và ghi dữ liệu vào tệp tin?
  • Sự khác biệt giữa chế độ đọc (read mode) và chế độ ghi (write mode) trong việc mở tệp tin trong C/C++.
  • Khái niệm về con trỏ hàm thành viên (member function pointer) trong C++.
  • Cách sử dụng đa kế thừa (multiple inheritance) trong C++.
  • Sự khác biệt giữa hàm ảo thuần ảo (pure virtual function) và hàm ảo ảo tượng (virtual function) trong C++.
  • Cách sử dụng và quản lý đối tượng (object) trong C++.
  • Khái niệm về việc nạp chồng toán tử (operator overloading) trong C++.
  • Sự khác biệt giữa việc sử dụng “struct” và “class” trong C++.
  • Cách sử dụng và quản lý các đối tượng động (dynamic objects) trong C++.
  • Sự khác biệt giữa việc sử dụng “const” và “volatile” trong C/C++.
  • Cách sử dụng và quản lý đối tượng chuỗi (string objects) trong C++.
  • Sự khác biệt giữa các kiểu dữ liệu nguyên thủy (primitive data types) và kiểu dữ liệu tương tự (derived data types) trong C/C++.
  • Khái niệm về hàm lambda trong C++. Làm thế nào để sử dụng hàm lambda để tạo một hàm nội tuyến?
  • Cách sử dụng và quản lý mảng động (dynamic arrays) trong C++.
  • Sự khác biệt giữa việc sử dụng “endl” và “\n” để xuống dòng trong C++.
  • Cách sử dụng và quản lý đối tượng đệm (buffer objects) trong C++.
  • Sự khác biệt giữa cấu trúc dữ liệu hàng đợi (queue) và ngăn xếp (stack) trong C/C++.
  • Cách sử dụng và quản lý cấu trúc dữ liệu hàng đợi ưu tiên (priority queue) trong C/C++.
  • Sự khác biệt giữa việc sử dụng “struct” và “class” trong C/C++.
  • Cách sử dụng và quản lý danh sách liên kết (linked list) trong C/C++.
  • Sự khác biệt giữa việc sử dụng “struct” và “union” trong C/C++.
  • Cách sử dụng và quản lý cấu trúc dữ liệu cây nhị phân (binary tree) trong C/C++.
  • Sự khác biệt giữa cấu trúc dữ liệu cây nhị phân tìm kiếm (binary search tree) và cây nhị phân cân bằng (balanced binary tree) trong C/C++.
  • Cách sử dụng và quản lý cấu trúc dữ liệu đồ thị (graph) trong C/C++.
  • Sự khác biệt giữa cấu trúc dữ liệu đồ thị có hướng (directed graph) và đồ thị vô hướng (undirected graph) trong C/C++.
  • Cách sử dụng và quản lý cấu trúc dữ liệu bảng băm (hash table) trong C/C++.
  • Sự khác biệt giữa phép toán bitwise (bitwise operations) và phép toán logic (logical operations) trong C/C++.
  • Cách sử dụng và quản lý cấu trúc dữ liệu hàng đợi kép (double-ended queue) trong C/C++.
  • Sự khác biệt giữa cấu trúc dữ liệu cây AVL (AVL tree) và cây đỏ-đen (red-black tree) trong C/C++.
  • Cách sử dụng và quản lý cấu trúc dữ liệu heap trong C/C++.
  • Sự khác biệt giữa việc sử dụng “calloc” và “malloc” để cấp phát bộ nhớ động trong C/C++.
  • Cách sử dụng và quản lý cấu trúc dữ liệu hàng đợi ưu tiên có thứ tự (ordered priority queue) trong C/C++.
  • Bạn có thể cho chúng tôi biết về thái độ làm việc của bạn trong một dự án phức tạp?
  • Làm thế nào bạn xử lý khi gặp khó khăn hoặc thách thức trong công việc?
  • Bạn đã từng gặp xung đột hoặc mâu thuẫn với đồng nghiệp trong quá trình làm việc? Làm thế nào bạn giải quyết tình huống đó?
  • Bạn đã từng đóng góp ý kiến hoặc đề xuất cải tiến trong một dự án? Làm thế nào để bạn thể hiện sự cởi mở và sẵn lòng học hỏi từ ý kiến khác?
  • Làm thế nào để bạn xây dựng mối quan hệ làm việc tốt với đồng nghiệp và cấp trên?
  • Bạn đã từng đối mặt với một tình huống cảm xúc cao trong công việc? Làm thế nào để bạn giữ được sự bình tĩnh và xử lý tình huống đó?
  • Bạn có kinh nghiệm làm việc trong một môi trường đa văn hóa hoặc đội nhóm quốc tế không? Làm thế nào bạn sẽ thích nghi với một môi trường đa văn hóa?
  • Bạn đã từng tham gia vào việc giải quyết xung đột giữa các thành viên trong đội? Hãy cho chúng tôi biết về cách bạn đã giải quyết vấn đề đó và kết quả bạn đạt được.
  • Bạn có thể đặt mục tiêu cá nhân và nghề nghiệp cho bản thân không? Làm thế nào bạn đảm bảo rằng bạn đạt được những mục tiêu đó?
  • Làm thế nào bạn duy trì động lực và cam kết trong công việc hàng ngày?
Phỏng vấn C/C++ - image 17

Câu hỏi phỏng vấn C/C++ về chuyên môn, thái độ làm việc

Phỏng vấn C/C++ không chỉ đánh giá kiến thức kỹ thuật mà còn phản ánh tư duy logic, khả năng giải quyết vấn đề và thái độ làm việc của ứng viên. Việc chuẩn bị kỹ lưỡng, trả lời tự tin và thể hiện tinh thần chủ động, cầu thị sẽ giúp bạn ghi điểm với nhà tuyển dụng, ngay cả khi kinh nghiệm thực tế còn hạn chế. JobsGO hy vọng bộ câu hỏi C/C++ trong bài viết này sẽ là nền tảng giúp bạn sẵn sàng và tự tin hơn trong buổi phỏng vấn.

>>> Xem thêm: Các mẫu cv thực tập chuẩn, gây ấn tượng với nhà tuyển dụng

Câu hỏi thường gặp

1. Phỏng vấn C/C++ thường hỏi những nội dung gì?

Chủ yếu xoay quanh: kiến thức nền tảng C++, con trỏ & bộ nhớ, OOP, STL, và tư duy giải quyết vấn đề.

2. Phỏng vấn C/C++ có khó không?

Không quá khó nếu nắm chắc nền tảng, nhưng dễ “mất điểm” nếu yếu về con trỏ và quản lý bộ nhớ.

3. Fresher cần chuẩn bị gì khi phỏng vấn C/C++?

Hiểu rõ C++ cơ bản, con trỏ, OOP, vector/map, và giải được bài toán logic đơn giản.

4. Junior/Senior C/C++ thường bị hỏi khác gì fresher?

Junior/Senior tập trung nhiều vào STL, design, hiệu năng, xử lý bộ nhớ và kinh nghiệm thực tế.

(Theo JobsGO - Nền tảng tìm việc làm, tuyển dụng, tạo CV xin việc)