1.3. Chương trình đầu tiên của bạn

Bạn đã được giới hiệu về khái niệm lập trình và C++, bạn đã cài đặt một IDE (phần mềm cho phép bạn lập trình) và bây giờ chắc hẳn bạn sẽ tự hỏi: khi nào chúng ta bắt đầu code?

Câu trả lời là ngay bây giờ!

Tất nhiên, bạn đừng nghĩ đến việc lập trình được ngay những thứ phức tạp. Lập trình mạng 3D thời gian thực không phải là thứ chúng ta sẽ làm vào lúc này! Thay vào đó, mục tiêu của bạn trong chương này chỉ đơn giản là hiển thị một dòng chữ ra màn hình.

Và bạn sẽ thấy … việc này cũng đòi hỏi bạn phải lao động một chút!

Thế giới kì diệu của Console

Khi tôi nói với bạn chúng ta sẽ bắt đầu lập trình, chắc hẳn bạn sẽ nói : “Tuyệt, tôi có thể làm cái này, cái này và cái này; và tôi cũng luôn ao ước có thể làm thứ này nữa!”. Nhiệm vụ của tôi lúc này là giúp bạn bình tĩnh lại một chút và giải thích cho bạn những bước mà chúng ta sẽ thực hiện.

Chúng ta sẽ bắt đầu một cách chậm rãi. Dù gì chúng ta cũng k có lựa chọn khác bởi vì các chương trình phức hợp 3D mạng mà bạn tưởng tượng ra có thể cũng cần những kiến thức nền tàng.

Bạn cần biết có 2 kiểu chương trình: các chương trình đồ họa và các chương trình console.

Các chương trình đồ họa

Đó là các chương trình xuất hiện thông qua các cửa sổ. Đây hẳn là các chương trình mà bạn đã quá quen thuộc. Chúng tạo ra các màn hình cửa sổ mà chúng ta có thể mở, đóng, thu nhỏ, phóng to, …

Các lập trình viên gọi đó là GUI (Graphical User Interface).

MS word

Các chương trình Console

Các chương trình console thường xuất hiện ở hệ điều hành Linux hơn là Windows hay MacOS. Chúng được tạo thành từ các dòng văn bản hiện ra trên màn hình, thường là chữ trắng trên nền đen (hình bên dưới).

console

Các chương trình này được vận hành bằng bàn phím. Con chuột không được sửa dụng. Thường thì chúng được chạy tuần tự: các thông báo hiện ra lần lượt, từ trên xuống dưới.

Mục tiêu đầu tiên của chúng ta sẽ là các chương trình console.

Các chương trình console được tạo ra dễ dàng hơn nhiều so với các chương tình đồ họa. Với những người mới bắt đầu như chúng ta, cần phải bắt đầu từ loại chương trình này!

Tất nhiên tôi biết bạn không muốn dừng lại ở đó. Bạn hãy yên tâm: Một phần của giáo trình này dành để tạo các GUI với Qt, một loại mở rộng của C++ cho phép bạn thực hiện kiểu chương trình đồ họa!

Nhưng trước đó, hãy bắt đầu bằng chương trình console!

Khởi tạo và chạy project đầu tiên

Trong chương trước, bạn đã cài đặt IDE, phần mềm này chứa tất cả những gì một lập trình viên cần.

Bạn đã tìm hiểu rằng có rất nhiều IDE (Code::Blocks, Visual C++, Xcode, ...). Tôi cũng đã nói với bạn thực tế tồn tại rất nhiều IDE khác và tôi chỉ giới thiệu với bạn các IDE nổi tiếng nhất.

Như đã nói với bạn, tôi chủ yếu sử dụng Code::Blocks trong giáo trình này. Các giải thích của tôi thường là cho IDE này, nhưng tôi cũng sẽ nhắc đến các IDE khác nếu cần thiết.

May thay, các phần mềm này khá giống nhau và dùng cùng một trường từ vựng, vì thế bạn sẽ không bị mất phương hướng khi chuyển từ IDE này qua một IDE khác.

Tạo một project

Để bắt đầu một chương trình, bước đầu tiên là yêu cầu IDE tạo một project. Việc này gần giống như việc bạn yêu cầu Word tạo một văn bản mới.

Để làm được điều này, bạn hãy chọn File>New>Prọect (hình dưới).

Một cửa sổ hiện ra, chúng ta đã được giới thiệu về việc này trong chương trước. Bạn hãy làm theo chỉ dẫn trong chương trước để tạo một chương trình console C++.

Cuối bước này, chương trình đã được tạo và chứa sẵn một file đầu tiên. Bạn hãy kích vào thanh bên trái để làm xuất hiện file main.cpp và kích đúp vào đó để mở file này. Đây là chương trình mã nguồn đầu tiên và nó đã được viết sẵn (hình bên dưới)!

Code::Blocks đã tạo cho bạn một chương trình đơn giản có nhiệm vụ hiển thị lên màn hình: “Hello world!”.

? Chưa gì tôi đã nhìn thấy cả chục dòng code C++ và tôi không hiểu gì cả!

Đúng thế, điều này có vẻ hơi khó khi bạn lần đầu tiếp xúc với C++, nhưng bạn đừng lo, chúng ta sẽ cùng tìm hiểu trong phần sau ý  nghĩa của đoạn code này.

Chạy một chương trình

Hiện tại, tôi muốn bạn làm một việc đơn giản: thử biên dịch và chạy chương trình này. Bạn còn nhớ cách làm chứ?  Có một nút “Build and run”. Nút này nằm trên thanh công cụ (hình bên dưới).

Việc biên dịch bắt đầu. Bạn sẽ thấy vài thông báo được hiển thị ở phần bên dưới của IDE (trong phần Build log).

x Nếu việc biên dịch không diễn ra và bạn gặp phải lỗi “My-program-Release uses an invalid compiler. Skipping… Nothing to be done.”, điều này nghĩa là bạn đã tải phiên bản Code::Blocks không có mingw (trình biên dịch). Hãy quay lại trang web của Code::Block để tải phiên bản có mingw.

Nếu không có vấn đề gì, một console sẽ xuất hiện với chương trình của chúng ta (hình dưới).

Bạn có thể thấy chương trình hiển thị dòng chữ “Hello world!” rất đẹp trong cửa sổ console. Vậy là bạn vừa biên dịch chương trình đầu tiên!

! Một file biên dịch đã được tạo trên ổ đĩa cứng. Ở windows, nó là file .exe. Bạn có thể tìm thấy nó trong một tiểu thư mục release (hoặc thỉnh thoảng là debug), nằm ở trong thư mục bin của project của bạn.

? Thông báo ở cuối console: Process returned 0 (0*0) execution time : 0.004 s Press any key to continue.” nghĩa là gì?

Một câu hỏi rất hay!

Thông báo này không được viết bởi chương trình của bạn, mà bởi IDE. Ở trong trường hợp này, là Code::Blocks đã hiển thị thông báo để báo cho bạn rằng chương trình đã được chạy xong xuôi không vấn đề gì, và thời gian để chạy chương trình.

Mục địch chỉnh ủa Code::Blocks ở đây là “duy trì” việc cửa sổ console được mở. Trên thực tế, ở trong Windows nói riêng, ngay khi một chương trình console kết thúc, cửa sổ console sẽ đóng lại. Nhưng chương trình vừa rồi của chúng ta chỉ được chạy trong 0.004s, bạn thậm chí không kịp nhìn thông báo hiện trên màn hình!

Vì thế Code::Blocks mời bạn “ấn bất kì phím nào trên bàn phím để tiếp tục”, việc này sẽ ra lệnh đóng cửa sỏ console.

! Khi bạn biên dịch và cho chạy một chương trình console như chương trình vừa rôi với Visual C++, console có xu hướng mở ra và đóng lại tức khắc. Visual C++ không duy trì cửa sổ console mở như Code::Blocks.

Nếu bạn sử dụng Visual C++, giải pháp ở đây là thêm dòng system (“ PAUSE” ); ở trên dòng return 0: của chương trình.

Giái thích đoạn mã nguồn (source code) vừa rồi

Khi Code::Blocks tạo một project mới, nó khởi tạo luôn một file main.cpp chứa đoạn code sau:

#include <iostream>
using namespace std;
int main(){
   cout << "Hello world!" << endl;
   return 0;
}

Tất cả các IDE thường đều cho bạn đoạn code tương tự. Việc này giúp bạn bắt đầu lập trình nhanh hơn.

Bạn có thể thấy 3 dòng đầu (include, using namespace et int main) trong hầu hết tất cả các chương trình C++. Bạn có thể hiểu rằng tất cả các chương trình đều bắt đầu bằng 3 dòng này.

Chúng ta sẽ không đi vào chi tiết (bởi vì việc này có thể hơi phức tạp với những người mới bắt đầu!), tôi sẽ giới thiệu với bạn lần lượt ý nghĩa của mỗi dòng code.

include

Dóng đầu tiền:

#include <iostream>

Người ta gọi nó là một chỉ thị cho preprocessor. Vai trò của nó là tải các tính năng C++ để chúng ta có thể thực hiện một số hành động.

Trên thực tế, C++ là một ngôn ngữ mo-đun. Về bản chất, ngôn ngữ này không làm được gì nhiều (thậm chỉ không thể hiện thị một văn bản ra màn hình). Vì thế chúng ta cần phải tải các mở rộng mà chúng ta gọi là các thư viện, các thư viện này cung cấp cho C++ những khả năng mới.

Ở đây, chúng ta tải file iostream, nó cho phép chúng ta sử dụng thư viện… giúp hiển thị các thông báo lên màn hình, trong một cửa sổ console! Một thứ rất cơ bản, như bạn có thể tháy, nhưng cần đến việc sử dụng một thư viện.

! Việc gọi thư viện iostream trên thực tế cho phép bạn làm nhiều hơn là việc hiển thị thông báo lên màn hình: chúng ta cũng có thể có được những gì mà người dùng đã nhập thông qua bàn phím, chúng ta sẽ thấy ở phần sau. iostream nghĩa là “Input Output Stream”. Trong một máy tính, Input tương ứng với bàn phím và chuột, và Output là màn hình. Việc sử dụng iostream cho phép chúng ta có được phương tiện để trao đôi thông tin với máy tính.

Sau này, chúng ta sẽ tìm hiểu các thư viện khác và chúng ta cần phải thêm vào phần đầu của đoạn mã nguồn các dòng lệnh để gọi các thư viên này. Ví dụ, khi chúng ta tìm hiểu về Qt, cho phép thực hiện các chương trình đồ họa (GUI), chúng ta phải thêm vào một dòng sau đây:

#include <Qt>

Bạn cần biết rằng bạn có thể tải bao nhiêu thư viện tùy thích trong cùng một lần.

using namespace

Dòng:

using namespace std; 

cho phép chỉ ra trong gói tính năng nào file nguồn của chúng ta sẽ được viết.

Nếu bạn tải nhiều thư viện, mỗi thư viện sẽ cung cấp cho bạn nhiều tính năng khác nhau. Thỉnh thoảng, một số tính năng sẽ có cùng tên gọi. Hãy thử tưởng tượng một dòng lệnh “Hiển thị thông báo” có cùng tên như vậy trong iostream và trong Qt! Nếu bạn tải cả hai thư viện này cùng một lúc và bạn gọi “Hiển thị thông báo”, máy tính sẽ không biết phải hiển thị thông báo lên console với iostream hay lên một cửa sổ mới với Qt!

Để tránh vấn đề này, người ta tạo ra các namespaces, là các loại thư mục về tên. Dòng using namespace std; chỉ dẫn rằng bạn sẽ sử dụng namespace std trong phần tiếp theo của file nguồn. Namespace này là một trong các namespace được biết đến nhiều nhất vì nó tương ứng với thư viện standard (std), một thư viện đi kèm mặc định với C++ mà iostream cũng nằm trong đó.

int main()

Phần cốt lõi chính của chương trình bắt đầu ở đây. Các bạn sẽ thấy rằng mọi chương trình được tạo nên chủ yếu từ các "hàm". Mỗi "hàm" thực thi một công việc và có thể gọi các "hàm" khác để thực thi một số hành động.

Tất cả các chương trình đều có chứa một "hàm" tên là main, nghĩa là chính. Chắc hẳn các bạn sẽ đoán ra, đây là hàm chính thực thi hành động chủ yếu mà ta muốn chương trình thực hiện

Một hàm trông giống như sau:

int main(){

}

Dấu ngoặc nhọn mở và đóng dùng để chỉ điểm bắt đầu và kết thúc của hàm. Như các bạn có thể thấy trong mã nguồn ví dụ mà Code::Block tạo ra cho chúng ta, không còn gì khác sau hàm main. Hoàn toàn bình thường vì sau khi kết thúc việc thực hiện hàm main, chương trình sẽ dừng lại! Tất cả mọi chương trình bắt đầu ở đầu hàm main và kết thúc ở cuối của hàm này.

? Vậy có nghĩa là chúng ta sẽ viết toàn bộ chương trình bên trong hàm main  à?

Không! Mặc dù việc này hoàn toàn có thể thực hiện được, việc kiểm tra lại mà nguồn sau đấy sẽ trở nên vô cùng khó khăn, nhất là khi bạn viết những chương trình lớn. Thay vào đó, chúng ta sẽ để hàm main gọi những hàm khác. Những hàm đó sẽ thực hiện một số công việc rồi bản thân chúng lại gọi những hàm khác nữa. Nói chung, chúng ta sẽ "chia để trị" công việc cho nó dễ :D.

Dù vậy, trong thời gian đầu, chúng ta vẫn sẽ làm việc chủ yếu với hàm main vì chương trình của chúng ta vẫn còn khá đơn giản.

cout

Cuối cùng cũng tới dòng lệnh thực thi một hành động cụ thể ! Đây là dòng lệnh đầu tiên trong hàm main, có nghĩa là nó là hành động đầu tiên mà chương trình của chúng ta sẽ được máy tính thực hiện (những câu lệnh trước chỉ nhằm chuẩn bị cho chương trình thôi :-SS).

cout << "Hello world!" << endl;

Chức năng của cout là hiển thị một thông điệp ra màn hình. Đây chính là cái mà chúng ta gọi là câu lệnh. Toàn bộ chương trình của chúng ta được tạo nên từ các câu lệnh như thế này. Chính chúng đưa ra mệnh lênh cho máy tính.

! Lưu ý rằng, mọi câu lệnh đều kết thúc bằng dấu ";"! Đây cũng là thứ giúp chúng ta phân biệt các câu lệnh với những thứ còn lại. Nếu bạn quên 1 dấu ";", chương trình của bạn sẽ không thể được biên dịch thành công và sẽ không chạy được.

Có 3 yếu tố trong dòng lệnh này:

  • cout : lệnh hiển thị thông báo ra màn hình
  • "Hello world!" : Thông điệp sẽ được hiển thì
  • endl : xuống dòng

! Rất tiếc là hầu hết các ngôn ngữ lập trình được viết bằng tiếng anh, vậy nên chúng sẽ không được thân thiện lắm với các dấu trong tiếng Việt. Chúng ta sẽ gặp khá nhiều vấn đề với điều này trên Windows. Trên MacOSX và Linux thì đỡ hơn nhiều nhưng vẫn xảy ra. Tôi khuyến cáo tốt nhất là nên viết không có dấu. Nhưng chương trình GUI sau này chúng ta viết với Qt giải quyết khá tốt vấn đề này.

Chúng ta có thể kết hợp nhiều câu thông điệp trong một một câu lệnh, ví dụ:

cout << "Xin chao cac Tan Binh!" << endl << "Cac ban dao nay the nao?" << endl;

sẽ hiển thị 2 thông điệp trên 2 dòng của màn hình.

Để chắc chắn là các bạn hiểu chuyện gì đang diễn ra. Tôi đề nghị các bạn tự viết 1 ví dụ riêng với các thông điệp mà các bạn có trong đầu. Đừng quên thêm endl mỗi khi bạn muốn xuông dòng và các đoạn văn thì cách nhau bởi <<. Các bạn cũng nên tự hào với chính mình về những những ví dụ đó vì đó là những chương trình đầu tiên mà các bạn viết được mà không sao chép từ bất cứ cuốn sách dạy! Tôi khuyến khích làm việc này trong suốt giáo trình của chúng ta. Mỗi khi bạn thấy một câu lệnh mới, thử thay đổi 1 cái gì đó và xem kết quả cho ra khác nhau như thế nào. Đó là cách hiệu quả nhất để học tập.

Một trong số các bạn khi thực hiện công việc mà tôi nói bên trên có thể đã cố in ra những kí tự đặc biệt như dấu (") - ngoặc kép hoặc (\) - sượt ngược. Nếu bạn nào chưa thử thì bạn có thể thử bây giờ xem:

#include <iostream>
using namespace std;
int main(){
  cout << "Vi du in thu nhung ky tu dac biet :)" << endl;
  cout << ""<< endl;
  cout << "\" << endl;
  return 0;
}

Trình biên dịch không hề yêu thích chương trình của bạn và đưa ra một thông báo lỗi trong khung hiển thị lỗi của Code::Block. Thật ra để in được (") thì bạn phải in (\") còn để in (\) thì cần (\\) cơ. Tôi sẽ giải thích nguyên nhân trong những bài học tới. Dù sao, chương trình cần phải là:

#include <iostream>
using namespace std;
int main(){
  cout << "Vi du in thu nhung ky tu dac biet :)" << endl;
  cout << "\"<< endl;
  cout << "\\" << endl;
  return 0;
}

Các bạn hãy thử để thấy là bây giờ lọi thứ đều đã hoạt động tốt. Bạn có thể viết bất cứ cái gì rồi.

return

 Dòng cuối cùng:

return 0;

Những câu lệnh dạng này thường dùng để kết thúc hàm. Về cơ bản, phần lớn trả về một giá trị (ví dụ như 1 số). Ở đây, hàm main trả về kết quả 0 có nghĩa là mọi thứ hoạt động bình thường (tất cả giá trị khác 0 có nghĩa là đã có lỗi gì đó).

Bạn không cần thay đổi dòng này. Cứ giữ nguyên nó. Bạn sẽ có cơ hội làm nghịch với return cho các hàm sau này!

Comments và cách trình bày mã nguồn

Bên cạnh các câu lệnh dùng để ra lệnh cho máy tính, các bạn cũng có thể thêm vào các comments (lời giải thích) để chỉ ra cách hoạt động của chương trình.

Các comments không có bất cứ ảnh hưởng nào lên hoạt động của chương trình. Trên thực tế, trình biên dịch hoàn toàn bỏ qua những comments này và vì thế, chúng không hề xuất hiện trong chương trình sau biên dịch. Thế nhưng, những comment này rất quan trọng với bản thân các lập trình viên vì chúng giải thích rõ ràng cơ chế hoạt động của một đoạn mã nguồn đã được viết bởi người khác hoặc bởi chính họ nhưng rất lâu về trước !

Khi mà chương trình của bạn bắt đầu trở nên "hơi phức tạp" (sẽ rất nhanh thôi :D), bạn sẽ không thể nhớ được tại sao lúc trước trong một mã nguồn mình lại viết thế. Hơn nữa, nếu bạn muốn gửi đoạn mã đó cho một người bạn để xin tư vấn, người đó sẽ rất khó để hiểu cái bạn muốn làm với đoạn mã đó. Đó chính là lúc các comment thể hiện ra lợi ích của mình.

Các kiểu comment khác nhau

Bạn cần biết là có 2 kiểu comment được phân chia dựa trên độ dài của chúng

Comment ngắn

Các comment ngắn chỉ nằm trên một dòng, nghĩa là bạn không được phép có ký tự xuống dòng trong đó. Những comment này bắt đầu bằng //.

// Day la 1 comment ngan

Bạn thậm chí có thể viết nó ở cuối 1 dòng lệnh để giải thích xem xòng lệnh đó làm gì.

cout << "Xin chao Tan Binh << endl; // Hien thong diep ra man hinh

Comment dài

Các comment dài nằm trên 2 hay nhiều dòng, nghĩa là bạn có thể thoải mái xuống dòng lúc bạn muốn. Vùng comment dài sẽ bắt đầu bằng /* và kết thúc bằng */.

/* Vi comment nay qua dai nen toi
muon xuong dong. That ra thi
toi xuong dong luc nao toi thay
thich. Do la tu do ca nhan.*/

Về cơ bản thì chúng ta cũng không viết cả 1 cuốn tiểu thuyêt ở trong phần comment (dù chúng ta có thể làm được) :D. Chỉ viết dài khi bạn cần phải giải thích rõ ràng 1 điều gì đó.

Quay về với ví dụ của chúng ta, tôi có thể comment đoạn mã đó cho dễ hiểu hơn.

#include <iostream> //Them thu vien iostream 
using namespace std; //Goi tinh nang se duoc su dung
/* 
  Ham main
  Moi chuong trinh deu phai co ham nay
*/
int main(){
   cout << "Hello world!" << endl; // Hien thi thong diep
   return 0; // Tra ve 0 neu moi chuyen dien ra tot dep
}

Nếu bạn chạy lại chương trình này và so sánh, bạn sẽ thấy nó chẳng thay đổi gì so với lúc trước. Như tôi đã nói, trình biên dịch hoàn toàn không để ý đến các comment.

!Trong vi du trên, tôi đã thêm comment vào từng câu lệnh nhưng điều này hoàn toàn là ý muốn chủ quan chứ không phải bắt buộc. Trên thực tế cũng không có ai thêm comment vào tất cả các dòng lệnh làm gì. Nếu dòng lệnh quá dễ hiểu thì việc thêm comment có thể bỏ qua. 1 comment thường mang lại lợi ích lớn nhất nếu giải thích cách hoạt động của một đoạn mã chứ không phải từng câu lệnh riêng lẻ.

Trình bày mã nguồn

Một điều nữa các bạn cần biết là trình biên dịch không hề quan tâm đến các dấu cách và những chỗ xuống dòng trong mã nguồn. Những ký tự đó dùng để giúp lập trình viên có thể dễ dàng đọc lại mã mình đã viết. Về phần trình biên dịch, nó hoàn toàn hài lòng với đoạn mã sau : 

#include <iostream> 
using namespace std; int main(){  cout << "Hello world!" << endl;return 0; }

Bạn có thể chạy thử, đoạn mã hoàn toàn hợp lệ. Tuy nhiên rất khó để nhìn do những câu lệnh được viết liên tiếp nhau, khó tìm ra chỗ bắt đầu và kết thúc chương trình, vv... Vì thế, hãy cố để trình bày 1 cách dễ nhìn.

Trong Code::Block có 1 công cụ hỗ trợ trên thanh công cụ Plugins > Source code formatter (AStyle).  Việc này không ảnh hưởng đến việc biên dịch chương trình mà lại giúp những người làm việc cùng bạn rất nhiều. Bạn sẽ thấy đây là một thói quen tốt khi bạn tiến tới phần sau của giáo trình.

Tóm tắt bài hoc :
  • Có 2 loại chương trình là chương trình có giao diện người dùng GUI và chương trình console.
  • Bắt đầu học với các chương trình console sẽ dễ dàng hơn.
  • Mọi chương trình đều có 1 hàm main. Đây là điểm bắt đầu của chương trình
  • cout cho phép in 1 thông điệp ra màn hình.
  • Có thể thêm các comment vào mã dưới dạng // Comment hoặc /* Comment*/