7 lỗi thường gặp khi lập trình C++ là chủ đề quan trọng dành cho cả người mới và lập trình viên có kinh nghiệm. Đoạn mô tả này sẽ giúp bạn nắm bắt nhanh các sai lầm phổ biến, bao gồm: quên khai báo con trỏ trước khi sử dụng, lỗi tràn bộ đệm khi thao tác mảng, không giải phóng bộ nhớ động đúng cách, thiếu khởi tạo biến, lẫn lộn phép toán trên con trỏ và mảng, sử dụng sai phạm vi truy cập (scope) và bỏ qua kiểm tra ngoại lệ. Hiểu rõ nguyên nhân và cách khắc phục những lỗi này sẽ cải thiện hiệu suất mã nguồn, giảm thiểu lỗi runtime và tối ưu hóa quy trình phát triển ứng dụng C++. Hãy cùng FPT Aptech tìm hiểu chi tiết qua bài viết dưới đây!

Lập trình C++ là gì?

C và C++ là hai ngôn ngữ phần mềm được sử dụng rộng rãi nhất — đặc biệt là đối với các hệ thống nhúng. Các ngôn ngữ lập trình C và C++ có tính biểu đạt cao và linh hoạt. Nhưng chúng có thể được diễn giải trong ứng dụng.

Điều này có nghĩa là lập trình trong C/C++ thường dễ xảy ra lỗi. Để giúp bạn tránh các lỗi tiềm ẩn trong lập trình C và lập trình C++, hãy xem hướng dẫn sau.

Lỗi trong lập trình C và lập trình C++ là gì?

Lỗi trong lập trình C và lập trình C++ thường xảy ra khi có hành vi không xác định hoặc lỗi của con người. 

Lỗi trong lập trình C và lập trình C++ là gì?
Lỗi trong lập trình C và lập trình C++ là gì?

Xảy ra hành vi không xác định:

  • Khi định nghĩa ngôn ngữ không rõ ràng.
  • Khi chưa có thông số kỹ thuật về kết quả nào được xác định.
  • Khi nhà cung cấp trình biên dịch hoặc thư viện có một số quyền tự do rõ ràng trong việc triển khai.

Nhưng hầu hết lỗi mã hóa đều do các nhà phát triển gây ra. Chúng có thể do bất kỳ nguyên nhân nào, từ giả định mã hóa đáng ngờ đến việc thiếu tầm nhìn xa.

7 Loại Lỗi Trong Lập Trình C Và Lập Trình C++

Sau đây là bảy lỗi thường gặp trong lập trình C và lập trình C++.

1. Khởi tạo

Khởi tạo dữ liệu luôn quan trọng. Và đặc biệt quan trọng với các cấu trúc dữ liệu C++ phức tạp.

Thật dễ quên khởi tạo các thành viên lớp. Sau đây là ví dụ về lỗi khởi tạo trong C++:

class A {
public:
     A () {} // does not init 'm_i'
     int getI () const;

private:
     int m_i;
};

int j = A() .getI ();               // 'm_i' (and subsequently j)
                                    // have indeterminate value

Cách tránh lỗi khởi tạo trong lập trình C

Bạn có thể tránh loại lỗi này bằng quy tắc mã hóa như sau:

Các hàm tạo sẽ khởi tạo (thông qua giá trị ban đầu hoặc lệnh gọi hàm tạo) từng lớp cơ sở và tất cả các thành viên dữ liệu không tĩnh.

2. Ẩn tên

Ẩn tên khai báo là một lỗi đặc biệt khó. Trong lỗi này, định danh ở phạm vi trong cùng ẩn bất kỳ tên trùng khớp nào trong phạm vi ngoài. Điều này có thể là cố ý — hoặc không.

Hãy xem xét ví dụ vòng lặp for C++ này:

void foo (void)
{
	int i = 15
	int MyArray[10] ;

	for (int i=0; i<10; ++i)
	{	
		MyArray[i] = 0;
	}

	. . .
	// whatever was intended . .
	MyArray [i-1] = 1;
	// .. out-of-bounds results
}

 

Cách tránh lỗi ẩn tên trong lập trình C

Bạn có thể tránh lỗi ẩn tên bằng các quy tắc mã hóa phù hợp.

Sau đây là một ví dụ:

Một định danh trong phạm vi bên trong không được ẩn đi một định danh phạm vi bên ngoài.

Điều này giúp tránh được một số hành vi nguy hiểm và có lỗi.

3. Biểu thức Boolean

Phiên bản ISO 1990 của ngôn ngữ C (C90) vẫn được sử dụng rộng rãi cho đến ngày nay. Không có kiểu boolean gốc nào trong phiên bản này. Và các nhà phát triển phải khắc phục nhược điểm này bằng các khái niệm ‘giống boolean’.

Việc thiếu tính an toàn của kiểu có thể dẫn đến một số lỗi tinh vi nhưng nguy hiểm:

x = ( (a > b) & (c > d) );
/* logical rather than      */
/* bitwise AND intended */

y = ( (a + b)  ||  (c-d) );
/* odd: logical OR of two */
/* arithmetic expressions */

Cách tránh lỗi biểu thức Boolean

Những lỗi này có thể được tránh một cách khéo léo bằng quy tắc mã hóa sau.

Cấm trộn lẫn các biểu thức số học và logic (thực chất là Boolean).

4. Lỗi logic

Lỗi logic cũng có thể dẫn đến những lỗi nghiêm trọng.

if (y=x)  { . . . }
// assignment or '==' meant?

Ví dụ, một phép gán trong biểu thức điều kiện. Hoàn toàn hợp lệ. Nhưng lỗi logic này có thể tiết lộ lỗi cú pháp hoặc làm lộ ra các vấn đề logic phức tạp hơn.

Trong ví dụ tiếp theo, có một đánh giá có điều kiện.

if ( ( a == b) || (c = d) ) { . . . }
// conditional side-effect?

Logical Or (||) biểu diễn một điểm tuần tự. Vì vậy, biểu thức bên phải sẽ chỉ được đánh giá (và phép gán được thực hiện) nếu biểu thức bên trái là sai.

5. Mã không thể truy cập được

Mã không thể truy cập là mã sẽ không bao giờ được thực thi. Nó có thể chỉ ra lỗi logic. 

Sau đây là một ví dụ đơn giản:

int func(int a)
{
	int b = a*2;
	return b;

	// Unreachable code
	if (b < 10)
	{
        	b += 10;
	}
	
	return b;
}

Một ví dụ khác là câu lệnh switch. Câu lệnh S là cơ chế điều khiển luồng thanh lịch của ngôn ngữ C. 

Biểu thức switch và case phải cùng kiểu và cùng dấu. Nếu không, bạn có thể gặp phải chuyển đổi ngầm định.

Đây là một ví dụ.

unsigned char c;
. . .
switch ( c )     {
     case -1:
     . . . /* unreachable */
     case 256:
     . . . /* unreachable */

Làm thế nào để tránh mã không thể truy cập được

Áp dụng quy tắc chung rằng một dự án không được chứa mã không thể tiếp cận. Đây là quy tắc không thể quyết định — nghĩa là thuật toán không thể phát hiện tất cả mã không thể tiếp cận với độ chắc chắn tuyệt đối.

Tuy nhiên, các công cụ phân tích tĩnh như Helix QAC có thể đánh dấu các đoạn mã xác định cũng như các đoạn mã có thể không truy cập được.

6. Chuyển đổi kiểu

Tính linh hoạt của hệ thống kiểu vừa là điểm mạnh vừa là điểm yếu của ngôn ngữ C và C++. Nhưng nó thường không được hiểu. Và đôi khi nó bộc lộ những lỗi khó, nhạy cảm với giá trị:

uint16_t u16a = 40000;
uint16_t u16b = 30000;
uint32_t u32a;

u32a = u16a + u16b;
// result value: 70000 or 4464?

Các quy tắc cân bằng và thăng hạng của C/C++ có thể dẫn đến một trong hai giá trị này. Điều này phụ thuộc vào cách định nghĩa hai typedef này. (Kích thước số nguyên là 16 bit có thể gây ra lỗi — ngay cả khi kích thước kết quả được đặt thành loại 32 bit.)

Làm thế nào để tránh chuyển đổi kiểu

Bạn có thể tránh những chuyển đổi kiểu này bằng các quy tắc mã hóa phù hợp, chẳng hạn như:

Quy tắc 10.6 của MISRA C: “Giá trị của biểu thức hợp thành không được gán cho đối tượng có kiểu thiết yếu rộng hơn”

7. Bỏ đi CONST

Việc loại bỏ định danh const của một con trỏ cho phép một chương trình sửa đổi đối tượng được con trỏ tham chiếu. Điều này có thể dẫn đến hành vi không xác định.

// pointer to int:
     int *pi;
// pointer to const int:
     const int *pci;
     . . . 
// constraint error
     pi = pci
// dangerous but permitted
     pi = (int *)pci;

Làm thế nào để tránh bị loại bỏ CONST

Bạn có thể tránh việc loại bỏ CONST bằng quy tắc mã hóa phù hợp, chẳng hạn như:

Không được phép ép kiểu nào loại bỏ tính chất const hoặc tính chất dễ bay hơi khỏi kiểu được con trỏ xử lý.

Làm thế nào để ngăn ngừa lỗi trong lập trình C và lập trình C++?

Đây chỉ là một số lỗi phổ biến nhất trong lập trình C và lập trình C++. Nhưng vẫn còn hàng trăm đến hàng nghìn lỗi tiềm ẩn.

Cách duy nhất để tránh những lỗi này và đảm bảo mã an toàn, bảo mật và đáng tin cậy là sử dụng một tiêu chuẩn mã hóa . Và tốt nhất là áp dụng nó với sự trợ giúp của một trình phân tích mã tĩnh , chẳng hạn như Helix QAC cho C/C++ và Klocwork cho C, C++, C#, Java, JavaScript, Python và Kotlin.

Hệ thống đào tạo lập trình viên quốc tế FPT Aptech tuyển sinh năm 2025

Hệ thống đào tạo lập trình viên quốc tế FPT Aptech tuyển sinh năm 2025
Hệ thống đào tạo lập trình viên quốc tế FPT Aptech tuyển sinh năm 2025

Chương trình đào tạo

Chương trình đào tạo Cử nhân ngành CNTT – Lập trình 2 + 1
Khóa học Lập trình Full-stack (ADSE) – 2 năm 4 học kỳ
Khóa học Lập trình Game Full-stack (ADGD) – 2 năm 4 học kỳ
Khóa học Lập trình Front-end (CPISM) – 6 tháng
Khóa học Lập trình Back-end (DISM) – 1 năm

Đối tượng tuyển sinh

Thí sinh thuộc một trong các đối tượng sau sẽ đủ điều kiện trở thành sinh viên của FPT Aptech:

  • Học sinh THPT/GDTX
  • Sinh viên
  • Người đi làm
  • Bộ đội xuất ngũ & Dân quân tự vệ

Hồ sơ nhập học

  • 01 phiếu đăng ký nhập học theo mẫu của FPT Aptech (Download TẠI ĐÂY)
  • 01 bản photo công chứng Bằng tốt nghiệp THPT hoặc Giấy chứng nhận tốt nghiệp tạm thời
  • 01 bản photo công chứng CMND/CCCD
  • File ảnh 3×4 (chụp không quá 6 tháng gần đây)

FPT Aptech trực thuộc Tổ chức Giáo dục FPT có hơn 25 năm kinh nghiệm đào tạo lập trình viên quốc tế tại Việt Nam, và luôn là sự lựa chọn ưu tiên của các sinh viên và nhà tuyển dụng.
0981578920
icons8-exercise-96