Các bài học trước đã giới thiệu rất nhiều về các thuật ngữ và khái niệm trong C++ nhưng chúng ta chỉ ví dụ từng đoạn chương trình nhỏ. Trong bài học này, chúng ta sẽ hướng dẫn các bạn áp dụng các kiến ​​thức này vào chương trình đơn giản đầu tiên của chúng ta hướng dẫn sau đây.

1. Chương trình Nhân với 2

Đầu tiên, hãy để chúng ta tạo ra một chương trình yêu cầu người dùng nhập một số nguyên, sau đó cho ra một số gấp 2 lần số đó. Chương trình sẽ tạo ra số như sau: (giả sử ta đã nhập 4 làm đầu vào):

Enter an integer: 4
Double that number is: 8

Các lập trình viên mới thường cố gắng viết toàn bộ chương trình cùng một lúc, và sau đó bị choáng ngợp khi nó tạo ra rất nhiều lỗi. Một chiến lược tốt hơn để code là thêm từng phần một, đảm bảo nó biên dịch đúng và kiểm tra nó. Sau đó, khi bạn chắc chắn rằng nó làm việc tốt, hãy chuyển sang phần tiếp theo.

Chúng ta sẽ tận dụng chiến lược đó ở đây. Khi chúng ta thực hiện từng bước, hãy tự code (Đừng copy và paste nhé vì nó sẽ không giúp cho bạn nhớ và hiểu code đâu) từng chương trình vào trình biên dịch của bạn, biên dịch và chạy nó.

Đầu tiên, tạo một dự án giao diện console mới.

Bây giờ hãy bắt đầu với một số dòng cơ bản. Chúng ta biết rằng sẽ cần một hàm main() (vì tất cả C ++ phải có một cái), vì vậy nếu IDE của bạn không tạo ra hàm main() khi bạn tạo một dự án mới thì hãy tự tạo ra một hàm main nó rất quan trọng khi chạy chương trình:

int main()
{
   return 0;
}

Chúng ta biết rằng sẽ cần xuất văn bản ra console và nhận văn bản từ bàn phím người dùng, vì vậy chúng ta cần iostream để truy cập vào std :: cout và std :: cin.

#include <iostream>
 
int main()
{
   return 0;
}

Bây giờ, hãy nói với người dùng rằng chúng ta cần họ nhập số nguyên:

int main()
{
 std::cout << "Enter an integer: ";
 return 0;
}

Tại thời điểm này, chương trình của bạn sẽ tạo ra kết quả sau:

Enter an integer:

và sau đó chấm dứt.

Tiếp theo, chúng ta sẽ lấy đầu vào của người dùng. Chúng ta sẽ sử dụng std :: cin và toán tử >> để có được giá trị đầu vào của người dùng. Nhưng chúng ta cũng cần xác định một biến để lưu trữ giá trị đầu vào đó để sử dụng sau.

#include <iostream>
 
int main()
{
	std::cout << "Enter an integer: ";
 
	int num{ 0 }; // define variable num as an integer variable
	std::cin << num; // get integer value from user's keyboard
 
	return 0;
}

Sau đó biên dịch nó và chạy…

Dưới đây, những gì chúng ta đang có trên Visual Studio 2017:

1>------ Build started: Project: Double, Configuration: Release Win32 ------
1>Double.cpp
1>c:\vcprojects\double\double.cpp(8): error C2678: binary '<<': no operator found which takes a left-hand operand of type 'std::istream' (or there is no acceptable conversion)
1>c:\vcprojects\double\double.cpp: note: could be 'built-in C++ operator<<(bool, int)'
1>c:\vcprojects\double\double.cpp: note: while trying to match the argument list '(std::istream, int)'
1>Done building project "Double.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Chúng ta gặp phải một lỗi biên dịch!

Đầu tiên, vì chương trình được biên dịch trước khi chúng ta thực hiện bản cập nhật mới nhất này và hiện tại cập nhật mới này không được biên dịch, nên lỗi phải nằm trong những dòng code chúng ta vừa thêm (dòng 7 và 8). Điều đó làm giảm đáng kể số lượng code chúng ta phải tìm lỗi. Dòng 7 khá đơn giản (chỉ là định nghĩa một biến), vì vậy lỗi có lẽ không ở đó. Vậy nên dòng số 8 có thể là nguyên nhân gây ra lỗi.

Thứ hai, thông báo lỗi này rất dễ đọc. Nhưng hãy để tách ra một số yếu tố chính: Trình biên dịch đang nói với chúng ta rằng nó đã gặp lỗi trên dòng 8. Điều đó có nghĩa là lỗi thực tế có thể nằm ở dòng 8, hoặc có thể là dòng trước, điều này củng cố cho đánh giá trước đó của chúng ta. Tiếp theo, trình biên dịch sẽ cho bạn biết rằng nó không thể tìm thấy toán tử << có toán hạng bên trái kiểu std :: istream. Nói cách khác, toán tử << không biết phải làm gì với std :: cin, do đó lỗi có thể do sử dụng std :: cin hoặc việc sử dụng toán tử << của chúng ta.

Việc xem hoặc tìm lỗi tại thời điểm này có thể khó với bạn nhưng nếu bạn không thể đọc được các dòng lỗi thì bạn có thể dành một chút thời gian và xem lại từng dòng code của mình đang sai chỗ nào không.

Tại đây, Chương trình sau đây sẽ được sửa như sau:

#include <iostream>
 
int main()
{
	std::cout << "Enter an integer: ";
 
	int num{ 0 };
	std::cin >> num; // std::cin uses operator >>, not operator <<!
 
	return 0;
}

Bây giờ chương trình sẽ biên dịch, và chúng ta có thể kiểm tra nó. Chương trình sẽ đợi bạn nhập số, vì vậy hãy nhập vào 4. Đầu ra sẽ như thế này:

Enter an integer: 4

Sắp đến rồi! Bước cuối cùng là nhân đôi số đã nhập.

Khi chúng ta hoàn thành bước cuối cùng này, chương trình của chúng ta sẽ biên dịch và chạy thành công, tạo ra đầu ra mong muốn.

Có (ít nhất) 3 cách chúng ta có thể làm điều này. Hãy cùng chúng ta đi từ cách xấu nhất đến cách tốt nhất sau đây:

2. Giải pháp không tốt – The not-good solution

#include <iostream>
 
// worst version
int main()
{
	std::cout << "Enter an integer: ";
 
	int num{ 0 };
	std::cin >> num;
 
	num = num * 2; // double num's value, then assign that value back to num
 
	std::cout << "Double that number is: " << num << '\n';
 
	return 0;
}

Trong giải pháp này, chúng ta sử dụng một biểu thức để nhân num với 2 và sau đó gán giá trị đó trở lại num. Từ thời điểm đó trở đi, num sẽ chứa số nhân đôi của chúng ta.

Tại sao đây là một giải pháp tồi:

  • Trước câu lệnh gán, num chứa đầu vào người dùng. Sau khi gán, nó chứa một giá trị khác. Điều đó khó hiểu.
  • Chúng ta ghi đè lên đầu vào của người dùng bằng cách gán một giá trị mới cho biến đầu vào, vì vậy nếu chúng ta muốn mở rộng chương trình của mình để làm một cái gì đó khác với giá trị đầu vào đó sau đó (ví dụ: gấp ba đầu vào của người dùng), vì biến num đã bị thay đổi, nên không dùng được.

3. Giải pháp được cho là tốt

#include <iostream>
 
// less-bad version
int main()
{
	std::cout << "Enter an integer: ";
 
	int num{ 0 };
	std::cin >> num;
 
	int doublenum{ num * 2 }; // define a new variable and initialize it with num * 2
	std::cout << "Double that number is: " << doublenum << '\n'; // then print the value of that variable here
 
	return 0;
}

Giải pháp này khá đơn giản để đọc và hiểu, và giải quyết cả hai vấn đề gặp phải trong giải pháp tồi tệ trên.

Nhược điểm chính ở đây là chúng ta xác định một biến mới (làm tăng thêm độ phức tạp) để lưu trữ một giá trị mà chúng ta chỉ sử dụng một lần. Chúng ta có thể làm tốt hơn như sau.

4. Giải pháp tốt nhất

#include <iostream>
 
// preferred version
int main()
{
	std::cout << "Enter an integer: ";
 
	int num{ 0 };
	std::cin >> num;
 
	std::cout << "Double that number is: " <<  num * 2 << '\n'; // use an expression to multiply num * 2 at the point where we are going to print it
 
	return 0;
}

Đây là giải pháp tốt nhất. Khi std :: cout thực thi, biểu thức num * 2 sẽ được ước tính và kết quả sẽ là giá trị được nhân 2. Giá trị đó sẽ được in ra. Giá trị num sẽ không bị thay đổi, vì vậy chúng ta có thể sử dụng lại sau nếu muốn.

Phiên bản này là giải pháp tham khảo của chúng ta.

Một điều nữa: Có thể bạn đang nghĩ, C ++ có rất nhiều quy tắc và khái niệm. Làm thế nào để tôi nhớ tất cả những thứ này?

Câu trả lời ngắn gọn: Bạn không thể biết hết. Viết C ++ thực chất là sử dụng những gì bạn đã biết và tìm kiếm cách thực hiện phần còn lại trên mạng.

Lời tâm sự:

Khi bạn đọc qua trang cafedev với serise tự học C++ này lần đầu tiên, hãy tập trung ít hơn vào việc ghi nhớ các chi tiết cụ thể mà hãy dành thời gian để hiểu được những gì đang đọc. Về sau, khi bạn có nhu cầu thực hiện một cái gì đó trong một chương trình mà bạn viết, bạn có thể quay lại đây (hoặc đến một trang web tham khảo khác) để thao khảo lại cú pháp hoặc cách làm và viết code với một cách tốt nhất của bạn.

Mục tiêu đầu tiên và chính của lập trình là làm cho chương trình của bạn hoạt động. Một chương trình không hoạt động được thì rất vô ích, bất kể nó viết như thế nào.

Tuy nhiên, có một câu nói mà tôi rất thích: Bạn phải viết một chương trình một lần để biết bạn nên viết nó như thế nào là hợp lý nhất. Điều này nói lên thực tế rằng giải pháp tốt nhất thường không rõ ràng và không phải là giải pháp đầu tiên của chúng ta cho các vấn đề.

Kết quả cuối cùng là các giải pháp ban đầu của chúng ta thường có cấu trúc tốt, mạnh mẽ (chống lỗi), dễ đọc hoặc súc tích. Vì vậy, một khi chương trình của bạn đang hoạt động, công việc của bạn thực sự không được thực hiện (trừ khi chương trình là một lần / bỏ đi). Bước tiếp theo là làm cho code của bạn trở này sạch hơn. Điều này liên quan đến những việc như: xóa (hoặc nhận xét) code tạm thời / gỡ lỗi, thêm nhận xét, xử lý các trường hợp lỗi, định dạng mã của bạn và đảm bảo tuân thủ các thực tiễn tốt nhất. Và thậm chí sau đó, chương trình của bạn có thể không đơn giản như nó có thể – có lẽ có logic dư thừa có thể được hợp nhất, hoặc nhiều câu lệnh có thể được kết hợp, hoặc bỏ các biến không cần thiết, hoặc hàng ngàn thứ nhỏ khác mà có thể được đơn giản hóa. Ngoài việc thường xuyên tối ưu hoá hiệu suất thì họ nên tối ưu hóa cho khả năng bảo trì nữa.

Rất ít giải pháp được trình bày trong các hướng dẫn này lần đầu tiên được cho là tuyệt vời. Thay vào đó, họ là kết quả của việc tinh chỉnh liên tục cho đến khi không có gì khác để cải thiện nó.

Tất cả những điều này thực sự có thể nói là: khi các giải pháp của bạn không được tối ưu và tuyệt vời ngay từ bộ não của bạn. Đó là chuyện bình thường. Sự hoàn hảo trong lập trình là một quá trình lặp đi lặp lại và luyện tập (một yêu cầu lặp đi lặp lại).

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!