CHUN ĐỀ 1: LÀM QUEN VỚI NGƠN NGỮ LẬP TRÌNH C++
1. Hướng dẫn cài đặt
Cài đặt IDE để biên dịch và thực thi C
Có một số IDE có sẵn và miễn phí để biên dịch và thực thi các chương trình C.
Bạn có thể chọn Dev-C++, Code:: Blocks, hoặc Turbo C. Tuy nhiên, lựa chọn
phổ biến nhất và hay được sử dụng nhất là Dev-C++ và các chương trình C
trong loạt bài này cũng được biên dịch và thực thi trong Dev-C++.
Sau khi đã cài đặt xong, để biên dịch và thực thi một chương trình C:
vào File -> New -> Project -> Console Application -> C project, sau đó nhập
tên vào hoặc (b) File -> New -> Source File. Cuối cùng, sao chép và dán
chương trình C vào file bạn vừa tạo. Để biên dịch và thực thi, chọn Execute ->
Compile & Run.
Cài đặt để chạy trên Command Prompt
Nếu bạn muốn cài đặt để biên dịch và chạy trên Command Prompt, thì bạn nên
đọc phần sau đây.
Nếu bạn muốn cài đặt môi trường C++, bạn cần hai phần mềm có sẵn trong
máy sau đây:
Text Editor
Nó sẽ được sử dụng để soạn chương trình của bạn. Ví dụ như Windows
Notepad, OS Edit command, Brief, Epsilon, EMACS và Vim hoặc Vi.
Tên và phiên bản của Text Editor có thể đa dạng trên các hệ điều hành khác
nhau. Ví dụ, Notepad sẽ được sử dụng trên Windows và Vim hoặc Vi có thể
được sử dụng trên Windows cũng như Linux hoặc UNIX.
Các file, mà bạn tạo với editor này, được gọi là các source file và với C++,
chúng được đặt tên với đuôi mở rộng là .cpp, .cp, hoặc .c.
Trước khi bắt đầu lập trình, đảm bảo rằng bạn có một Text editor và bạn có đủ
kinh nghiệm để soạn một chương trình C++.
C++ Compiler:
C++ Compiler được sử dụng để biên dịch source code của bạn thành chương
trình có thể thực thi.
Hầu hết C++ compiler không quan tâm phần đuôi mở rộng bạn cung cấp cho
source code, nhưng nếu bạn không xác định, thì theo mặc định, nó sẽ sử dụng
đi là .cpp.
Compiler được sử dụng thường xuyên nhất là GNU C/C++ compiler, hoặc bạn
có thể sử dụng các Compiler khác từ HP hoặc Solaris nếu bạn có Hệ điều hành
tương ứng.
Cài đặt GNU C/C++ Compiler
Cài đặt trên UNIX/Linux
Nếu bạn đang sử dụng Linux hoặc UNIX, thì kiểm tra xem GCC đã được cài
đặt trên hệ thống chưa bằng việc nhập lệnh sau tại dòng lệnh (command line):
$ g++ -v
Nếu bạn đã cài đặt GCC, thì nó sẽ in thơng báo sau:
Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr .......
Thread model: posix
gcc version 4.1.2 20080704 (Red Hat 4.1.2-46)
Cài đặt trên Mac OS X
Nếu bạn sử dụng Mac OS X, cách đơn giản nhất để cài đặt GCC là tải môi
trường phát triển Xcode từ Website của Applet và theo các chỉ dẫn.
Cài đặt trên Windows
Để cài đặt GCC trên Windows, bạn cần cài đặt MinGW. Tải phiên bản mới nhất
của MinGW, sẽ có tên là MinGW-<version>.exe.
Trong khi cài đặt MinGW, tối thiểu bạn phải cài đặt gcc-core, gcc-g++, binutils,
và MinGW runtime.
Thêm thư mục phụ bin của MinGW tới biến mơi trường PATH, để mà bạn có
thể xác định các tool trên command line bởi các tên đơn giản của chúng.
Khi việc cài đặt hoàn tất, bạn có thể chạy gcc, g++, ar, ranlib, dlltool, và một số
GNU tool khác từ Windows command line.
2. Một số khái niệm cơ bản
Khi chúng ta xem xét một chương trình C++, nó có thể được định nghĩa như là
một tập hợp của các đối tượng, mà giao tiếp thông qua việc triệu hồi các
phương thức của mỗi đối tượng đó. Dưới đây, chúng tôi miêu tả ngắn gọn ý
nghĩa của class (lớp), object (đối tượng), method (phương thức) và các biến đối
tượng:
Đối tượng - Đối tượng có các trạng thái và hành vi. Ví dụ: một đối tượng
dog có các trạng thái là color, name, breed, và các hành vi là wagging, barking,
eating. Một đối tượng là một minh họa của một lớp.
Lớp - Một lớp có thể được định nghĩa như là một template/blueprint, mà
miêu tả hành vi/trạng thái mà đối tượng hỗ trợ.
Phương thức - Về cơ bản, một phương thức là một hành vi. Một lớp có
thể chứa nhiều phương thức. Phương thức là nơi tính logic được viết, dữ liệu
được thao tác và tất cả action được thực thi.
Biến instance - Mỗi đối tượng có tập hợp biến đối tượng duy nhất của nó.
Trạng thái của một đối tượng được tạo ra bởi các giá trị được gán cho các biến
đối tượng của nó.
3. Cấu trúc chương trình C++
Bạn theo dõi một đoạn code đơn giản sẽ in Hello World.
#include <iostream>
using namespace std;
// Ham main() la noi su thuc thi chuong trinh bat dau
int main()
{
cout << "Hello World"; // In dong chu Hello World
return 0;
}
Chương trình trên có các phần sau:
Ngôn ngữ C++ định nghĩa một số header, mà chứa thơng tin cần thiết và
hữu ích cho chương trình của bạn. Với chương trình này, header
là <iostream> là cần thiết.
Dịng using namespace std; nói cho compiler sử dụng std namespace.
Namespce là phần bổ sung gần đây cho C++.
Dòng tiếp theo Ham main() la noi su thuc thi chuong trinh bat dau là
một comment đơn dòng trong C++. Các comment đơn dòng bắt đầu với // và kết
thúc ở cuối dòng.
Dòng int main() là hàm main, tại đây việc thực thi chương trình bắt đầu.
Dịng tiếp theo cout << "Hello World"; để in dịng chữ "Hello World"
trên màn hình.
Dịng tiếp theo return 0; kết thúc hàm main() và làm nó trả về giá trị 0 tới
tiến trình đang gọi.
4. Biên dịch và thực thi chương trình C++
1. Dưới đây là cách lưu file, biên dịch và chạy chương trình với command
prompt. Bạn theo các bước sau:
Mở một text editor và thêm đoạn code trên.
Lưu file với tên: hello.cpp.
Mở một dòng nhắc lệnh (command prompt) và tới thư mục nơi bạn lưu
file đó.
Soạn 'g++ hello.cpp ' và nhấn Enter để biên dịch code trên. Nếu khơng có
lỗi xảy ra trong code của bạn thì dịng nhắc lệnh sẽ đưa bạn tới dịng tiếp theo và
tạo a.out file có thể thực thi.
Bây giờ, bạn soạn 'a.out' để chạy chương trình.
Bạn sẽ thấy 'Hello World' được in trên cửa sổ.
$ g++ hello.cpp
$ ./a.out
Hello World
Bạn chắc chắn rằng g++ là trong path của bạn và bạn đang chạy nó trong thư
mục mà chứa hello.cpp file.
2. Đó là cách biên dịch và thực thi chương trình tại command prompt.
Nếu bạn đang sử dụng Dev-C++, hoặc Microsoft Visual Studio, hoặc Turbo
C++, bạn có thể sao chép ví dụ trên, sau đó:
Mở Dev-C++ chẳng hạn, chọn File -> New Source, sau đó dán ví dụ vào
sourve file này và chọn Execute tab, chọn Complile & Run để thực thi chương
trình. Bạn cũng có thể tạo một Project mới trong tùy chọn New để đặt tên và
lưu cho ví dụ vừa thực hiện.
5. Dấu chấm phẩy và khối (block) trong C++
Trong C++, dấu chấm phảy là ký tự kết thúc lệnh (statement terminator). Nghĩa
là, mỗi lệnh đơn phải kết thúc bởi một dấu chấm phảy. Nó chỉ dẫn sự kết thúc
của một thực thể logic.
Dưới đây là ví dụ về 3 lệnh khác nhau:
x = y;
y = y+1;
add(x, y);
Một khối (block) là một tập hợp các lệnh được kết nối một cách logic, mà được
bao quanh bởi các dấu ngoặc móc mở và đóng. Ví dụ:
{
cout << "VietJack xin chao cac ban!"; // in dong chu VietJack xin chao cac
ban!
return 0;
}
Hai dạng sau là tương đương, C++ không quan tâm bạn đặt bao nhiêu lệnh trên
một dịng. Ví dụ:
x = y;
y = y+1;
add(x, y);
Là giống với:
x = y; y = y+1; add(x, y);
6. Định danh (Identifier) trong C++
Một Định danh (Identifier) trong C++ là một tên được sử dụng để nhận diện
một biến, hàm, lớp, module, hoặc bất kỳ user-defined item nào (người dùng tự
định nghĩa). Một Định danh (Identifier) bắt đầu với một chữ cái từ A tới Z hoặc
từ a tới z hoặc một dấu gạch dưới (_) được theo sau bởi 0 hoặc nhiều chữ cái,
dấu gạch dưới và chữ số (từ 0 tới 9).
C++ không cho phép các ký tự như @, $ và % bên trong các Identifier. C++ là
ngôn ngữ lập trình phân biệt kiểu chữ. Vì thế, Manpower và manpower là hai
Identifier khác nhau trong C++.
Dưới đây là một số ví dụ về Identifier (Định danh) thích hợp:
hoang
nam abc sinh_vien a_123
caogia50 _nhanvien j a23b9
vietJack
7. Từ khóa trong C++
Bảng dưới liệt kê các từ được dự trữ (dành riêng) trong C++. Những từ này
không thể được sử dụng như là constant hoặc biến hoặc bất kỳ tên Identifier
(Định danh) nào.
asm
else
new
this
auto
enum
operator
throw
bool
explicit
private
true
break
export
protected
try
case
extern
public
typedef
catch
false
register
typeid
char
float
reinterpret_cast
typename
class
for
return
union
const
friend
short
unsigned
const_cast
goto
signed
using
continue
if
sizeof
virtual
default
inline
static
void
delete
int
static_cast
volatile
do
long
struct
wchar_t
double
mutable
switch
while
dynamic_cast
namespace
template
8. Trigraph trong C++
Một Trigraph là một dãy 3 ký tự mà biểu diễn một ký tự đơn và dãy này luôn
luôn bắt đầu với 2 dấu hỏi.
Các Trigraph được mở rộng bất cứ nơi đâu chúng xuất hiện, bao gồm bên trong
String literal và Character literal, trong comment, và trong các preprocessor
directive (các directive tiền xử lý).
Dưới đây là các dãy trigraph được sử dụng thường xuyên nhất:
Trigraph
Thay thế cho
??=
#
??/
\
??'
^
??(
[
??)
]
??!
|
??<
{
??>
}
??-
~
Tất cả compiler không hỗ trợ Trigraph và chúng được khun là khơng nên sử
dụng bởi vì tính khó hiểu của nó.
9. Khoảng trắng (Whitespace) trong C++
Một dịng mà chỉ chứa khoảng trắng (Whitespace), có thể là một comment,
được biết đến như là một dịng trống, và C++ hồn tồn bỏ qua nó.
Khoảng trắng (Whitespace) là khái niệm được sử dụng trong C++ để miêu tả
blank, tab, ký tự newline (dòng mới), và comment. Khoảng trắng (Whitespace)
phân biệt các phần của lệnh và giúp compiler nhận diện vị trí một phần tử trong
một lệnh, ví dụ như int, vị trí phần kết thúc và vị trí phần tử tiếp theo bắt đầu.
Do đó, trong lệnh sau:
int diemthi;
Phải có ít nhất một Whitespace (thường là khoảng trống) giữa int và age để
compiler có thể phân biệt chúng. Trong lệnh:
tongLuong = luongCoBan + phuCap; // tinh tong luong
Các ký tự khoảng trắng (Whitespace) giữa luongCoBan và =, hoặc giữa = và
phuCap là không cần thiết; tuy nhiên, để giúp cho code của bạn dễ đọc hơn, bạn
có thể thêm chúng vào.
Comment của chương trình là các lời diễn giải, mà bạn có thể bao trong C/C++
code, và giúp cho bất kỳ ai đọc source code dễ dàng hơn. Tất cả ngơn ngữ lập
trình đều cho phép một số mẫu comment nào đó.
C++ hỗ trợ các comment đơn dịng và đa dịng. Tất cả ký tự có trong comment
được bỏ qua bởi C/C++ compiler.
Comment trong C/C++ bắt đầu với /* và kết thúc với */. Ví dụ:
/* Day la mot comment don dong */
/* C/C++ cung ho tro cac comment
* ma co nhieu dong
*/
Một comment cũng có thể bắt đầu với //, kéo dài tới phần cuối của dịng. Ví dụ:
#include <iostream>
using namespace std;
main()
{
cout << "Hoc C/C++ co ban va nang cao"; // In dong chu Hoc C/C++ co ban
va nang cao
return 0;
}
Khi code trên được biên dịch, nó sẽ bỏ qua // In dong chu Hello World và cuối
cùng cho kết quả sau:
Hello World
Bên trong một comment dạng /* và */, các ký tự // khơng có ý nghĩa đặc biệt gì.
Bên trong một comment dạng //, các ký tự /* và */ khơng có ý nghĩa đặc biệt gì.
Vì thế, bạn có thể "lồng" bất kỳ dạng comment nào bên trong dạng khác. Ví dụ:
/* Comment ve dong lenh in dong chu Hello World:
cout << "xin chao cac ban!"; // in dong chu xin chao cac ban!
*/
10. Kiểu dữ liệu trong C/C++
Trong khi làm việc với bất kỳ ngơn ngữ lập trình nào, bạn cần sử dụng các kiểu
biến đa dạng để lưu giữ thông tin. Các biến, khơng gì khác ngồi các vị trí bộ
nhớ được dành riêng để lưu giá trị. Nghĩa là, khi bạn tạo một biến, bạn dành
riêng một số không gian trong bộ nhớ cho biến đó.
Bạn có thể thích lưu thông tin của các kiểu dữ liệu (Data Type) đa dạng như
Character, Wide Character, integer, floating-point, double floating point,
Boolean, …. Dựa trên kiểu dữ liệu của một biến, hệ thống sẽ cấp phát bộ nhớ
và quyết định những gì có thể được lưu giữ trong bộ nhớ dành riêng đó.
Kiểu dữ liệu nguyên thủy trong C/C++
Tên tiếng Anh là Primitive Type, cịn có thể gọi là kiểu dữ liệu gốc, kiểu dữ liệu
có sẵn trong C/C++. Bên cạnh các kiểu dữ liệu gốc này, C/C++ cũng cung cấp
các kiểu dữ liệu user-defined. Bảng dưới đây liệt kê 7 kiểu dữ liệu cơ bản trong
C/C++:
Kiểu dữ liệu
Từ khóa
Boolean
bool
Ký tự
char
Số nguyên
int
Số thực
float
Số thực dạng Double double
Kiểu khơng có giá trị void
Kiểu Wide character
wchar_t
Một số kiểu cơ bản có thể được sửa đổi bởi sử dụng một hoặc nhiều modifier
này:
signed (kiểu có dấu)
unsigned (kiểu khơng có dấu)
short
long
Bảng sau hiển thị kiểu biến, lượng bộ nhớ nó dùng để lưu giá trị trong bộ nhớ,
và giá trị lớn nhất và nhỏ nhất có thể được lưu giữ với các kiểu biến đó:
Kiểu
Độ rộng bit
Dãy giá trị
char
1 byte
-127 tới 127 hoặc 0 tới 255
unsigned char
1 byte
0 tới 255
signed char
1 byte
-127 tới 127
int
4 byte
-2147483648 tới 2147483647
unsigned int
4 byte
0 tới 4294967295
signed int
4 byte
-2147483648 tới 2147483647
short int
2 byte
-32768 tới 32767
unsigned short int
Range
0 tới 65,535
signed short int
Range
-32768 tới 32767
long int
4 byte
-2,147,483,647 tới
2,147,483,647
signed long int
4 byte
Tương tự như long int
unsigned long int
4 byte
0 tới 4,294,967,295
float
4 byte
+/- 3.4e +/- 38 (~7 chữ số)
double
8 byte
+/- 1.7e +/- 308 (~15 chữ số)
long double
8 byte
+/- 1.7e +/- 308 (~15 chữ số)
wchar_t
2 hoặc 4 byte
1 wide character
Kích cỡ của các biến có thể khác với những gì hiển thị trên bảng, phụ thuộc vào
compiler và máy tính bạn đang sử dụng.
Dưới đây là ví dụ sẽ đưa ra kích cỡ chính xác của các kiểu dữ liệu đa dạng trên
máy tính của bạn.
#include <iostream>
using namespace std;
int main()
{
cout << "Kich co cua char la: " << sizeof(char) << endl;
cout << "Kich co cua int la: " << sizeof(int) << endl;
cout << "Kich co cua short int la: " << sizeof(short int) << endl;
cout << "Kich co cua long int la: " << sizeof(long int) << endl;
cout << "Kich co cua float la: " << sizeof(float) << endl;
cout << "Kich co cua double la: " << sizeof(double) << endl;
cout << "Kich co cua wchar_t la: " << sizeof(wchar_t) << endl;
return 0;
}
Ví dụ này sử dụng endl, mà chèn một ký tự newline (dòng mới) sau mỗi dòng,
và toán tử << được sử dụng để truyền nhiều giá trị tới màn hình. Chúng tơi
cũng sử dụng tốn tử sizeof() để lấy kích cỡ của các kiểu dữ liệu đa dạng.
Khi code trên được biên dịch và thực thi, nó cho kết quả sau (kết quả có thể đa
dạng tùy thuộc vào compiler và máy tính bạn đang sử dụng).
Kich co cua char la: 1
Kich co cua int la: 4
Kich co cua short int la: 2
Kich co cua long int la: 4
Kich co cua float la: 4
Kich co cua double la: 8
Kich co cua wchar_t la: 4
11. Khai báo typedef trong C/C++
Bạn có thể tạo một tên mới cho một kiểu dữ liệu đang tồn tại bởi sử
dụng typedef trong C/C++. Cú pháp đơn giản sau để định nghĩa một kiểu dữ
liệu mới bởi sử dụng typedef:
typedef kieu_du_lieu ten_moi;
Ví dụ sau nói cho compiler rằng sothuc là tên khác của float:
typedef float sothuc;
Bây giờ, khai báo sau là hoàn toàn hợp lệ và sẽ tạo một biến số thực gọi
là vantoc:
sothuc vantoc;
12. Kiểu liệt kê enum trong C/C++
Kiểu liệt kê enum khai báo một tên kiểu tùy ý và một tập hợp của 0 hoặc nhiều
Identifier (Định danh) mà có thể được sử dụng như là các giá trị của kiểu đó.
Mỗi Enumerator là một constant có kiểu là kiểu liệt kê (enumeration).
Để tạo một Enumeration, bạn sử dụng từ khóa enum trong C/C++. Form chung
của kiểu liệt kê enum là:
enum ten_cua_enum { danh sach cac ten } danh_sach_bien;
Tại đây, ten_cua_enum là tên kiểu liệt kê. Danh sách tên được phân biệt bởi dấu
phảy.
Ví dụ, code sau định nghĩa một tên kiểu liệt kê hàng hóa gọi là hanghoa và biến
c là kiểu của hanghoa. Cuối cùng, c được gán giá trị nuocngot.
enum hanghoa { sua, nuocngot, biachai } c;
c = nuocngot;
Theo mặc định, trong danh sách các tên thì giá trị của tên đầu tiên là 0, tên thứ
hai là 1 và tên thứ 3 là 2, …. Nhưng bạn có thể cung cấp cho một tên một giá trị
cụ thể bằng việc thêm một Initializer (giá trị khởi tạo). Ví dụ, trong
enumeration sau, nuocngot sẽ có giá trị là 40:
enum hanghoa { sua, nuocngot=40, biachai };
Ở đây, biachai sẽ có giá trị là 41 bởi vì mỗi tên sẽ có giá trị lớn hơn của tên
trước đó là 1.
13. Kiểu biến trong C/C++
Một biến cung cấp nơi lưu giữ được đặt tên để chúng ta có thể thao tác. Mỗi
biến trong C/C++ có một kiểu cụ thể, mà quyết định: kích cỡ và cách bố trí bộ
nhớ của biến; dãy giá trị có thể được lưu giữ bên trong bộ nhớ đó; và tập hợp
hoạt động có thể được áp dụng cho biến đó.
Tên biến có thể gồm các ký tự, các chữ số, dấu gạch dưới. Nó phải bắt đầu bởi
hoặc một ký tự hoặc một dấu gạch dưới. Các ký tự chữ hoa và chữ thường là
khác nhau bởi C/C++ là ngôn ngữ phân biệt kiểu chữ. Biến có thể trong các
kiểu giá trị đa dạng như kiểu char, int, float, ...
Định nghĩa biến trong C/C++
Định nghĩa biến trong C/C++ nghĩa là nói cho compiler nơi và lượng bộ nhớ
cần tạo để lưu giữ biến đó. Một định nghĩa biến xác định một kiểu dữ liệu, và
chứa danh sách của một hoặc nhiều biến có kiểu đó, như sau:
kieu_gia_tri danh_sach_bien;
Ở đây, kieu_gia_tri phải là một kiểu dữ liệu hợp lệ trong C/C++, gồm char,
w_char, int, float, double, bool hoặc bất kỳ đối tượng nào mà người dùng tự
định nghĩa, … và danh_sach_bien có thể chứa một hoặc nhiều tên Identifier
(Định danh) phân biệt nhau bởi dấu phảy. Sau đây là một số khai báo hợp lệ
trong C/C++:
int j, q, k;
char v, viet;
float x, diemthi;
double luong;
Dòng int j, q, k; vừa khai báo và định nghĩa các biến j, q, k, mà chỉ dẫn
compiler để tạo các biến với tên là j, q, k với kiểu int.
Các biến có thể được khởi tạo (được gán giá trị ban đầu) trong các khai báo.
Initializer (phần khởi tạo) gồm một ký hiệu bằng được theo sau bởi một
Constant Expression (biểu thức hằng số), như sau:
kieu_gia_tri ten_bien = giaTri;
Ví dụ:
extern int d = 3, f = 5; // khai bao bien d va f.
int d = 3, f = 5;
// dinh nghia va khoi tao bien d va f.
byte z = 22;
// dinh nghia va khoi tao bien z.
char x = 'k';
// bien x co gia tri la 'k'.
Với định nghĩa mà khơng có phần khởi tạo: các biến được khởi tạo với NULL
(tất cả byte có giá trị 0); giá trị khởi tạo của tất cả biến khác không được định
nghĩa.
Khai báo biến trong C/C++
Khai báo biến trong C/C++ chắc chắn với compiler rằng có một biến đang tồn
tại với kiểu và tên đã cho, để mà compiler tiếp tục trình biên dịch mà khơng cần
biết đầy đủ chi tiết về biến đó. Một khai báo biến chỉ có ý nghĩa tại thời gian
biên dịch, compiler cần khai báo biến thực sự tại thời điểm kết nối chương
trình.
Khai báo biến là hữu ích khi bạn đang sử dụng nhiều file, và bạn định nghĩa
biến của bạn ở một trong các file đó mà sẽ có sẵn tại thời điểm kết nối chương
trình. Bạn sẽ sử dụng từ khóa extern để khai báo một biến tại bất kỳ đâu. Mặc
dù, bạn có thể khai báo một biến nhiều lần trong chương trình C/C++, nhưng nó
có thể chỉ được định nghĩa một lần trong một file, một hàm, hoặc một khối
code.
Ví dụ
Trong ví dụ sau, một biến được khai báo tại ở phần đầu chương trình, nhưng nó
đã được định nghĩa ở bên trong hàm main.
#include <iostream>
using namespace std;
// Phan khai bao bien:
extern int a, b;
extern int c;
extern float f;
int main ()
{
// Phan dinh ngia bien:
int a, b;
int c;
float f;
// Phan khoi tao bien
a = 10;
b = 20;
c = a + b;
cout << c << endl ;
f = 70.0/3.0;
cout << f << endl ;
return 0;
}
Khi code trên được biên dịch và thực thi, nó cho kết quả sau:
30
23.3333
Giống khái niệm áp dụng trên khai báo hàm, bạn cung cấp tên hàm tại thời
điểm khai báo và định nghĩa thực sự của hàm đó có thể được cung cấp ở bất cứ
đâu. Ví dụ:
// phan khai bao ham
int func();
int main()
{
// phan goi ham
int i = func();
}
// phan dinh nghia ham
int func()
{
return 0;
}
Lvalue và Rvalue trong C/C++
Có hai loại Expression trong C/C++:
lvalue : Đây là expression liên quan tới một vị trí vùng nhớ. Bất kỳ lvalue
có thể xuất hiện ở bên trái hoặc bên phải của một phép gán.
rvalue : Khái niệm này liên quan tới một giá trị dữ liệu mà được lưu giữ
tại một số địa chỉ trong vùng nhớ. Một rvalue là một expression mà khơng thể có
một giá trị được gán tới nó, nghĩa là: rvalue có thể xuất hiện bên phải nhưng
không thể xuất hiện bên trái của một phép gán.
Các biến là lvalue có thể xuất hiện bên trái của phép gán. Các Numeric literal
(hằng số) là rvalue không thể được gán và không thể xuất hiện ở bên trái của
phép gán. Dưới đây là một lệnh hợp lệ trong C/C++:
int t = 10;
Nhưng lệnh sau là không hợp lệ và sẽ cho một compile-time error (lỗi tại thời
điểm biên dịch):
16 = 30;
14. Phạm vi biến trong C++
Một scope (phạm vi) là một khu vực của chương trình nơi biến hoạt động, và
nói chung có thể có 3 khu vực mà biến có thể được khai báo:
Bên trong một hàm hoặc một khối, được gọi là biến cục bộ (local).
Trong định nghĩa của các tham số hàm, được gọi là các tham số chính
thức (formal).
Bên ngồi của tất cả hàm, được gọi là biến toàn cục (global).
Chúng ta sẽ học hàm và các tham số của hàm là gì trong chương tới. Dưới đây
chúng tơi sẽ giải thích khái niệm về biến cục bộ và biến toàn cục.
Biến cục bộ trong C++
Các biến được khai báo bên trong một hàm hoặc khối là các biến cục bộ (local).
Chúng chỉ có thể được sử dụng bởi các lệnh bên trong hàm hoặc khối code đó.
Các biến cục bộ khơng được biết ở bên ngồi hàm đó (tức là chỉ được sử dụng
bên trong hàm hoặc khối code đó). Dưới đây là ví dụ sử dụng các biến cục bộ:
#include <iostream>
using namespace std;
int main ()
{
// phan khai bao bien cuc bo:
int a, b;
int c;
// phan khoi tao bien
a = 10;
b = 20;
c = a + b;
cout << c;
return 0;
}
15. Biến toàn cục trong C++
Biến toàn cục (global) trong C++ được định nghĩa bên ngoài các hàm, thường ở
phần đầu chương trình. Các biến tồn cục giữ giá trị của nó trong suốt vịng đời
chương trình của bạn.
Một biến tồn cục có thể được truy cập bởi bất kỳ hàm nào. Tức là, một biến
toàn cục là có sẵn cho bạn sử dụng trong tồn bộ chương trình sau khi đã khai
báo nó. Dưới đây là ví dụ sử dụng biến toàn cục và biến nội bộ trong C++:
#include <iostream>
using namespace std;
// phan khai bao bien toan cuc:
int g;
int main ()
{
// phan khai bao bien cuc bo:
int a, b;
// phan khoi tao bien
a = 10;
b = 20;
g = a + b;
cout << g;
return 0;
}
Một chương trình có thể có các biến tồn cục và biến cục bộ cùng tên với nhau,
nhưng trong một hàm thì giá trị của biến cục bộ sẽ được ưu tiên. Ví dụ:
#include <iostream>
using namespace std;
// phan khai bao bien toan cuc:
int g = 20;
int main ()
{
// phan khai bao bien cuc bo:
int g = 10;
cout << g;
return 0;
}
Khi code trên được biên dịch và thực thi, nó cho kết quả sau:
10
16. Khởi tạo biến cục bộ và biến toàn cục bởi hệ thống trong C++
Khi một biến cục bộ được định nghĩa, nó khơng được khởi tạo bởi hệ thống,
chính bạn phải khởi tạo nó. Các biến tồn cục được khởi tạo tự động bởi hệ
thống khi bạn định nghĩa chúng, như sau:
Kiểu dữ liệu Giá trị khởi tạo
int
0
char
'\0'
float
0
double
0
pointer
NULL
Khởi tạo biến một cách chính xác là một sự thực hành tốt, nếu không, đôi khi
chương trình sẽ cho kết quả khơng mong đợi.
17. Hằng (Constant/Literal) trong C/C++
Constant liên quan tới các giá trị cố định mà chương trình khơng thể thay đổi và
chúng được gọi là literals.
Constant là một kiểu dữ liệu thay thế cho Literal, cịn Literal thể hiện chính nó.
Trong ví dụ: const PI = 3.14 thì Constant ở đây là PI, cịn Literal là 3.14.
Constant có thể là bất kỳ kiểu dữ liệu cơ bản nào trong C/C++, và có thể được
phân chia thành giá trị hằng số nguyên, hằng số thực, hằng ký tự, hằng chuỗi và
Boolean literal (tạm dịch: hằng logic).
Ngoài ra, constant được đối xử giống như các biến thông thường, ngoại trừ việc
giá trị của chúng là không thể thay đổi sau khi định nghĩa.
Hằng số nguyên trong C/C++
17.1 Hằng số nguyên có thể là decimal (cơ số 10), octal (cơ số 8) hay
hexadecimal (cơ số 16). Giá trị có tiền tố (prefix) là 0 cho octal, là 0x hay 0X
cho hexadecimal và khơng có gì cho decimal.
Một hằng số nguyên cũng có các hậu tố (suffix) U hay L thể hiện kiểu unsigned
hay long. Hậu tố có thể là chữ hoa hoặc chữ thường và có thể trong bất kỳ thứ
tự nào.
Ví dụ về các hằng số nguyên:
212
// Hop le
215u
// Hop le
0xFeeL
// Hop le
048
// Khong hop le: 8 khong phai la mot ky so trong he octal
032UU
// Khong hop le: hau to (suffix) khong the bi lap
Dưới đây là các kiểu hằng số nguyên đa dạng:
85
0213
0x4b
30
30u
30l
30ul
// Hang so dang decimal
// Hang so dang octal
// Hang so dang hexadecimal
// Hang so dang so nguyen (int)
// Hang so dang so nguyen khong dau (unsigned int)
// Hang so dang long
// Hang so dang unsigned long
Hằng số thực trong C/C++
Một hằng số thực bao gồm phần nguyên (integer part), dấu chấm thập phân
(decimal point), phần lẻ (fraction part) và phần mũ (exponent part). Chúng ta có
thể biểu diễn hằng số thực theo dạng decimal hay dạng mũ.
Khi thể hiện dạng decimal phải bao gồm dấu chấm thập phân, phần mũ hoặc cả
hai. Khi thể hiện dạng mũ phải gồm phần nguyên, phần lẻ hoặc cả hai. Dạng
mũ đi kèm với kí tự E hoặc e.
Xét các ví dụ sau:
3.14159
// Hop le
314159E-5L // Hop le
510E
// Khong hop le: pham mu (exponent) con thieu
210f
// Khong hop le: khong co phan thap pha decimal hoac phan mu
exponent
.e55
// Khong hop le: thieu phan nguyen integer hoac phan fraction
Boolean literal trong C/C++
Có hai kiểu Boolean literal và chúng là một phần của các từ khóa C/C++:
Giá trị true
Và giá trị false
Bạn khơng nên đồng nhất giá trị true với 1 và giá trị false với 0.
17.2 Hằng ký tự trong C/C++
Các hằng kí tự trong C/C++ mở đầu và kết thúc bởi dấu nháy đơn. Nếu hằng ký
tự bắt đầu với L (ví dụ L'x') thì nó là kiểu wchar_t. Nếu khơng thì, nó là hằng
ký tự kiểu char, ví dụ như 'x'.
Hằng kí tự có thể là một kí tự (như 'X'), một escape sequence (như '\t') hay một
kí tự mở rộng (như '\u02c0′).
Một số kí tự trong C/C++ khi được đứng trước bởi dấu \ thì chúng sẽ mang một
ý nghĩa đặc biệt như bắt đầu dòng mới '\n' hay tạo một tab '\t'. Chúng được biết
như là escape sequence (dãy thoát). Bảng dưới đây thể hiện một số mã escape
sequence phổ biến:
Escape sequence Ý nghĩa
\\
Ký tự \
\'
Ký tự '
\"
Ký tự "
\?
Ký tự ?
\a
Alert hoặc bell
\b
Backspace
\f
Form feed
\n
Newline
\r
Carriage return
\t
tab ngang
\v
tab dọc
\ooo
Số hệ cơ số 8 của một tới 3 chữ số
\xhh . . .
Số hệ cơ số 16 của một hoặc nhiều chữ số
Dưới đây là ví dụ minh họa một số ký tự escape sequence:
#include <iostream>
using namespace std;
int main()
{
cout << "Hello\tWorld\n\n";
return 0;
}
Khi code trên được biên dịch và thực thi, nó cho kết quả sau:
Hello World
17.3 Hằng chuỗi trong C/C++
Hằng chuỗi chứa trong dấu nháy kép, ví dụ "abc". Một chuỗi sẽ chứa các kí tự
tương tự hằng kí tự, gồm các ký tự thuần, escape sequence, và các ký tự mở
rộng.
Có thể ngắt một dòng dài thành nhiều dòng bởi sử dụng hằng chuỗi và phân
biệt chúng bởi sử dụng khoảng trắng (whitespace).
Xét ví dụ một hằng chuỗi trong C/C++ thể hiện theo 3 cách khác nhau:
"hoc, lap trinh"
"hoc, \
lap trinh"
"hoc, " "lap" "trinh"
17.4 Định nghĩa hằng trong C/C++
Có hai cách định nghĩa hằng trong C/C++ là:
Sử dụng bộ tiền xử lý #define.
Sử dụng từ khóa const.
Sử dụng bộ tiền xử lý #define trong C/C++
Dưới đây là cú pháp để sử dụng tiền xử lý #define để định nghĩa một constant
trong C/C++:
#define identifier value
Ví dụ sau giải thích cú pháp trên:
#include <iostream>
using namespace std;
#define CHIEUDAI 10
#define CHIEURONG 5
#define NEWLINE '\n'
int main()
{
int dientich;
dientich = CHIEUDAI * CHIEURONG;
cout << dientich;
cout << NEWLINE;
return 0;
}
Khi code trên được biên dịch và thực thi, nó cho kết quả sau:
50
17.5 Sử dụng từ khóa const trong C/C++
Bạn có thể sử dụng tiền tố const để định nghĩa hằng trong C/C++ với một kiểu
cụ thể, như sau:
const kieu_gia_tri bien = giaTri;
Ví dụ sau giải thích chi tiết cú pháp trên:
#include <iostream>
using namespace std;
int main()
{
const int CHIEUDAI = 10;
const int CHIEURONG = 5;
const char NEWLINE = '\n';
int area;
dientich = CHIEUDAI * CHIEURONG;
cout << dientich;
cout << NEWLINE;
return 0;
}
Khi code trên được biên dịch và thực thi, nó cho kết quả sau:
50
Ghi chú: Nó là bước thực hành tốt cho bạn khi định nghĩa các hằng ở kiểu chữ
hoa trong C/C++.
C++ cho phép các kiểu dữ liệu char, int và double có các Modifier đặt trước
chúng. Một Modifier được sử dụng để thông báo ý nghĩa của kiểu cơ sở, giúp
cho nó tăng sự chính xác hơn với sự cần thiết của các tình huống đa dạng.
Dưới đây là các Modifier trong C/C++:
signed (có dấu)
unsigned (khơng có dấu)
long
short
Các Modifier là: signed, unsigned, long, và short có thể được áp dụng cho
kiểu integer. Ngoài ra, signed và unsigned có thể được áp dụng cho kiểu char,
và long có thể áp dụng cho kiểu double.
Các Modifier là signed và unsigned cũng có thể được sử dụng như là tiền tố
cho các Modifier là long hoặc short modifiers. Ví dụ: unsigned long int.
C++ cho phép kiểu khai báo tắt để khai báo các unsigned,
short, or long integer. Bạn có thể chỉ đơn giản sử dụng từ unsigned,
short, hoặc long, mà khơng cần int. Ví dụ sau minh họa hai khai báo là hợp lệ
trong C/C++ để khai báo các biến unsigned integer:
unsigned x;
unsigned int y;
Để phân biệt sự khác nhau giữa hai Modifier là signed integer và unsigned
integer được thơng dịch bởi C/C++, bạn nên chạy chương trình sau:
#include <iostream>
using namespace std;
/* Chuong trinh nay chi ra diem khac nhau giua
* cac so nguyen signed va unsigned.
*/
int main()
{
short int i;
// mot so nguyen signed short int
short unsigned int j; // mot so nguyen unsigned short int
j = 32769;
i = j;
cout << i << " " << j;
return 0;
}
Nó sẽ cho kết quả:
-32767 32769
Nếu bạn quay trở lại chương Kiểu dữ liệu trong C/C++, và đọc phần dãy giá
trị của short int và unsigned short int, bạn sẽ nhận ra sự khác nhau khi chạy
chương trình trên với j <= 32767 và với j >= 32767.
Qualifier trong C/C++
Qualifier cung cấp thông tin bổ sung về các biến theo sau nó.
Qualifier Ý nghĩa
const
Đối tượng của kiểu const khơng thể bị thay đổi bởi chương trình
trong khi thực thi
volatile
Modifier này nói cho compiler rằng giá trị của biến có thể được thay
đổi một cách không rõ ràng (không báo trước) bởi chương trình.
restrict
Một con trỏ được đặt là restrict thì có ý nghĩa là đối tượng nó trỏ
đến có thể được truy cập. Restrict được thêm vào trong chuẩn C99.
18. Lớp lưu trữ (Storage Class) trong C/C++
Lớp lưu trữ (Storage Class) định nghĩa phạm vi và vòng đời của biến và/hoặc
các hàm bên trong một chương trình C/C++. Chúng thường đứng trước kiểu dữ
liệu mà chúng tác động. Dưới đây là các lớp lưu trữ có thể được sử dụng trong
C/C++:
auto
register
static
extern
mutable
Lớp lưu trữ auto trong C/C++
Lớp lưu trữ auto trong C/C++ là lớp lưu trữ mặc định cho tất cả biến cục bộ
trong C/C++:
{
int diemthi;
auto int diemthi;
}
Ví dụ trên định nghĩa hai biến với cùng lớp lưu trữ, auto chỉ có thể được sử
dụng bên trong các hàn, ví dụ: cho các biến nội bộ.
18.1: Lớp lưu trữ register trong C/C++
Lớp lưu trữ register trong C/C++ được sử dụng để định nghĩa các biến cục bộ
mà nên được lưu giữ trong một thanh ghi thay vì RAM. Nghĩa là, biến có kích
cỡ tối đa bằng với kích cỡ thanh ghi (thường là 1 từ) và khơng thể có tốn tử
một ngơi '&' được áp dụng tới nó (vì khơng có địa chỉ bộ nhớ).
{
register int hocphi;
}
Lớp lưu trữ register nên chỉ được dùng cho các biến yêu cầu truy cập nhanh
như các biến đếm (counters). Cũng cần chú ý rằng, một biến định nghĩa với
'register' khơng có nghĩa là biến đó được lưu trữ trong thanh ghi. Tức là nó có
thể được lưu trữ trong thanh ghi phụ thuộc vào phần cứng và giới hạn thực thi.
Lớp lưu trữ static trong C/C++
Lớp lưu trữ static trong C/C++ nói với compiler để giữ một biến cục bộ tồn tại
trong toàn bộ thời gian sống của chương trình thay vì tạo và hủy biến mỗi lần
nó vào và ra khỏi phạm vi biến. Vì vậy, các biến có static cho phép nó duy trì
giá trị giữa các lần gọi hàm.
Lớp lưu trữ static cũng có thể được áp dụng cho các biến toàn cục (global). Khi
áp dụng cho biến tồn cục, nó nói với trình biên dịch rằng, phạm vi của biến
toàn cục bị giới hạn trong tập tin mà nó được khai báo.
Trong C/C++, khi static được sử dụng trên thành viên dữ liệu của lớp, nó gây
ra: chỉ có một bản sao của thành viên đó được chia sẻ bởi tất cả đối tượng trong
lớp của nó.
#include <iostream>
// phan khai bao ham
void func(void);
static int biendem = 10; /* Day la bien toan cuc */
main()
{
while(biendem--)
{
func();
}
return 0;
}
// Phan dinh nghia ham
void func( void )
{
static int i = 5; // Day la bien cuc bo dang static
i++;
std::cout << "i co gia tri la " << i ;
std::cout << " va biendem co gia tri la " << biendem << std::endl;
}
Chạy chương trình C/C++ trên sẽ cho kết quả như hình sau:
18.2: Lớp lưu trữ extern trong C/C++
Lớp lưu trữ extern trong C/C++ được dùng để cung cấp một tham chiếu của
một biến tồn cục được nhìn thấy bởi TẤT CẢ các file chương trình. Khi bạn
sử dụng 'extern', biến khơng thể được khởi tạo, khi nó trỏ tới tên biến tại một vị
trí lớp lưu trữ mà đã được định nghĩa trước đó.
Khi bạn có nhiều file và bạn định nghĩa một biến hay hàm toàn cục trong một
file và cũng muốn dùng nó trong các file khác, thì extern được dùng trong file
khác để cung cấp tham chiếu của biến hay hàm được định nghĩa. Cần nhớ
rằng, extern dùng để khai báo một biến hay hàm toàn cục trong file khác.
Lớp lưu trữ extern được dùng phổ biến khi có hai hoặc nhiều file chia sẻ cùng
biến hay hàm tồn cục. Xem ví dụ với hai file sau:
File đầu tiên: extern1.cpp
#include <iostream>
int biendem ;
extern void vidu_extern();
main()
{
biendem = 5;
vidu_extern();
}
File thứ hai: extern2.cpp
#include <iostream>
extern int biendem;
void vidu_extern(void)
{
std::cout << "Gia tri biendem la " << count << std::endl;
}
Ở đây, từ khóa extern đang được sử dụng để khai báo biendem trong file khác.
Bây giờ biên dịch hai file này như sau:
$g++ extern1.cpp extern2.cpp -o write
Nó sẽ tạo chương trình write có thể thực thi, bạn thử thực thi write và kiểm tra
kết quả như sau:
$./write
5
18.3: Lớp lưu trữ mutable trong C/C++
Lớp lưu trữ mutable trong C/C++ chỉ áp dụng cho các đối tượng class, sẽ được
bàn luận trong chương sau. Nó cho phép một thành viên của một đối tượng để
override (ghi đè). Đó là, một thành viên là mutable có thể được sửa đổi bởi một
hàm thành viên const.
19. Toán tử trong C++
Một tốn tử là một biểu tượng, mà nói cho compiler thực hiện các thao tác toán
học và logic cụ thể. C++ cung cấp nhiều tốn tử có sẵn, đó là:
Toán tử số học
Toán tử quan hệ
Toán tử logic
Toán tử so sánh bit
Toán tử gán
Toán tử hỗn hợp
19.1. Toán tử số học trong C++
Bảng dưới liệt kê các toán tử số học được hỗ trợ bởi ngôn ngữ C++:
Giả sử biến A giữ giá trị 10, biến B giữ 20 thì:
Tốn tử
Miêu tả
Ví dụ
+
Cộng hai tốn hạng
A + B kết quả là 30
-
Trừ toán hạng thứ hai từ toán hạng đầu
A - B kết quả là -10
*
Nhân hai toán hạng
A * B kết quả là 200
/
Phép chia
B / A kết quả là 2
%
Phép lấy số dư
B % A kết quả là 0
++
Toán tử tăng, tăng giá trị toán hạng
thêm một đơn vị
A++ kết quả là 11
--
Toán tử giảm, giảm giá trị toán hạng
bớt một đơn vị
A-- kết quả là 9
19.2. Toán tử quan hệ trong C++
Bảng dưới đây liệt kê các toán tử quan hệ được hỗ trợ bởi ngôn ngữ C++:
Giả sử biến A giữ giá trị 10, biến B giữ 20 thì:
Tốn
tử
Miêu tả
Ví dụ
==
Kiểm tra nếu 2 tốn hạng bằng nhau
hay khơng. Nếu bằng thì điều kiện là
true.
(A == B) là khơng đúng
!=
Kiểm tra 2 tốn hạng có giá trị khác
nhau hay khơng. Nếu khơng bằng thì
điều kiện là true.
(A != B) là true
>
Kiểm tra nếu tốn hạng bên trái có giá
trị lớn hơn tốn hạng bên phải hay
khơng. Nếu lớn hơn thì điều kiện là
true.
(A > B) là không đúng
<
Kiểm tra nếu toán hạng bên trái nhỏ
hơn toán hạng bên phải hay khơng.
Nếu nhỏ hơn thì là true.
(A < B) là true
>=
Kiểm tra nếu tốn hạng bên trái có giá
trị lớn hơn hoặc bằng giá trị của tốn
hạng bên phải hay khơng. Nếu đúng là
true.
(A >= B) là không đúng
<=
Kiểm tra nếu tốn hạng bên trái có giá
trị nhỏ hơn hoặc bằng tốn hạng bên
phải hay khơng. Nếu đúng là true.
(A <= B) là true
19.3. Toán tử logic trong C++
Bảng dưới đây chỉ rõ tất cả các toán tử logic được hỗ trợ bởi ngôn ngữ C.