Professional Documents
Culture Documents
Tài Liệu Ngôn Ngữ Lập Trình C - ITIS
Tài Liệu Ngôn Ngữ Lập Trình C - ITIS
MỤC LỤC
I. Những khái niệm cơ bản trong ngôn ngữ lập trình C:................................ 3
1. Cấu trúc cơ bản của một chương trình C:....................................................3
2. Biến và hằng:............................................................................................... 4
a) Biến:....................................................................................................... 4
b) Hằng:...................................................................................................... 6
3. Kiểu dữ liệu:................................................................................................ 7
a) Kiểu dữ liệu số nguyên:..........................................................................8
b) Kiểu dữ liệu số thực:.............................................................................. 8
c) Kiểu dữ liệu ký tự:..................................................................................9
d) Kiểu boolean:....................................................................................... 11
4. Nhập/xuất cơ bản trong C:......................................................................... 11
a) Nhập/xuất chuẩn:.................................................................................. 11
b) Nhập/xuất với file:................................................................................13
5. Comment trong C:..................................................................................... 14
6. Câu lệnh đơn và khối lệnh:........................................................................ 15
7. Toán tử:...................................................................................................... 15
a) Toán tử số học:..................................................................................... 16
b) Toán tử quan hệ:................................................................................... 17
c) Toán tử gán:.......................................................................................... 18
d) Toán tử logic:........................................................................................19
e) Toán tử bitwise:.................................................................................... 20
f) Toán tử con trỏ:..................................................................................... 22
II. Cấu trúc điều khiển:.................................................................................... 23
1. Cấu trúc rẽ nhánh:......................................................................................23
a) Cấu trúc if-else:.................................................................................... 23
b) Cấu trúc switch-case:........................................................................... 25
2. Cấu trúc lặp:...............................................................................................28
a) Vòng lặp while:.................................................................................... 28
b) Vòng lặp do-while:...............................................................................29
c) Vòng lặp for:.........................................................................................30
3. Câu lệnh break và continue:...................................................................... 32
a) Câu lệnh break:.....................................................................................32
b) Câu lệnh continue:................................................................................33
1
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
2
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
+ Các hàm
+ Các biến
+ Các comment
3
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
2. Biến và hằng:
a) Biến:
- Trong lập trình, một biến là một thùng chứa (vùng lưu trữ) để chứa
dữ liệu.
- Để chỉ ra khu vực lưu trữ, mỗi biến phải được đặt một tên duy nhất
(mã định danh). Tên biến chỉ là đại diện tượng trưng của một vị trí
trong bộ nhớ.
- Khai báo biến: <Kiểu dữ liệu> <tên biến>;
- Nếu muốn khai báo 1 danh sách các biến có cùng kiểu dữ liệu, tên các
biến được ngăn cách bởi dấu ‘,’.
4
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
- C là một ngôn ngữ có kiểu dữ liệu mạnh. Điều này có nghĩa là kiểu dữ
liệu của biến không thể thay đổi sau khi nó được khai báo.
- C là một ngôn ngữ phân biệt chữ hoa và chữ thường nên biến a và biến A
là 2 biến khác nhau.
- Một số quy tắc ngầm trong việc đặt tên biến:
+ Sử dụng tên biến có ý nghĩa: Đặt tên biến sao cho nó thể hiện rõ
mục đích và ý nghĩa của biến. Tránh sử dụng các tên biến vô nghĩa
như a, b, x, y.
+ Sử dụng chữ cái viết thường: Đặt tên biến bằng chữ cái viết thường
và sử dụng dấu gạch dưới (_) để phân cách các từ trong tên biến (ví
dụ: my_variable).
+ Sử dụng kiểu camelCase: Trong trường hợp tên biến bao gồm nhiều
từ, sử dụng kiểu camelCase (chữ cái đầu tiên của từ đầu tiên viết
thường, các chữ cái đầu tiên của các từ sau viết hoa, không có dấu
cách hoặc dấu gạch dưới). Ví dụ: myVariable.
+ Tránh sử dụng tên biến quá dài: Tránh đặt tên biến quá dài và phức
tạp, vì nó có thể làm cho code khó đọc và dễ gây nhầm lẫn.
- Phân loại biến: Trong ngôn ngữ lập trình C, có hai loại biến là biến toàn
cục (global variable) và biến cục bộ (local variable).
+ Biến toàn cục: là biến được khai báo bên ngoài bất kỳ hàm nào
trong chương trình và có phạm vi hoạt động trên toàn bộ các hàm
trong cùng một tệp nguồn (file).
+ Biến cục bộ: là biến được khai báo bên trong một khối lệnh, chẳng
hạn như bên trong một hàm, một khối lặp hoặc một khối rẽ nhánh.
5
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
Biến cục bộ chỉ có phạm vi hoạt động và thời gian sống trong khối
lệnh mà nó được khai báo.
b) Hằng:
- Trong ngôn ngữ lập trình C, literal (hằng số) là giá trị cố định được trực
tiếp nhập vào trong mã chương trình. Chúng là các giá trị không thay đổi
và được đại diện bởi các dạng cụ thể, chẳng hạn như số nguyên, số thực,
ký tự và chuỗi.
- Để khai báo một hằng số, ta thêm từ khóa const vào trước kiểu dữ liệu của
biến.
- Ngoài ra, chúng ta cũng có thể định nghĩa hằng số thông qua chỉ thị tiền
xử lý #define.
6
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
- Quy tắc đặt tên cho hằng cũng giống như quy tắc đặt tên cho biến.
- Quy tắc ngầm trong việc đặt tên cho hằng:
+ Sử dụng chữ in hoa: Đặt tên hằng bằng chữ in hoa và sử dụng dấu
gạch dưới (_) để phân cách các từ trong tên hằng (ví dụ:
MAX_VALUE).
+ Sử dụng chữ cái viết hoa: Đặt tên hằng bằng chữ cái viết hoa và sử
dụng dấu gạch dưới (_) để phân cách các từ trong tên hằng (ví dụ:
PI_VALUE).
+ Đặt tên hằng có ý nghĩa: Đặt tên hằng sao cho nó thể hiện rõ mục
đích và ý nghĩa của hằng. Ví dụ, sử dụng tên hằng như
"MAX_LENGTH" hoặc "DEFAULT_VALUE".
+ Đặt tên hằng mô tả loại dữ liệu: Đặt tên hằng sao cho nó mô tả loại
dữ liệu mà hằng đại diện. Ví dụ, sử dụng tên hằng như
"SECONDS_PER_MINUTE" hoặc "MONTHS_IN_YEAR".
3. Kiểu dữ liệu:
* Trong ngôn ngữ lập trình C, các kiểu dữ liệu được sử dụng để khai báo biến.
Điều này xác định kiểu và kích thước dữ liệu liên quan đến các biến.
* Trong C, các kiểu dữ liệu cung cấp thông tin cho trình biên dịch về tính chất
của dữ liệu được lưu trữ, cho phép nó cấp phát đúng lượng bộ nhớ và thực hiện
các phép toán trên dữ liệu.
* Có một số kiểu dữ liệu cơ bản trong C, bao gồm: Kiểu dữ liệu số nguyên, số
thực, ký tự, kiểu mảng, con trỏ, kiểu dữ liệu tự định nghĩa, … Trong phần này,
7
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
chúng ta sẽ tìm hiểu về 3 kiểu dữ liệu cơ bản nhất trong C: Kiểu số nguyên, số
thực và kiểu ký tự.
* Đặc tả: Trong ngôn ngữ lập trình C, format specifier (đặc tả) là một chuỗi ký
tự được sử dụng để xác định kiểu dữ liệu của một giá trị khi hiển thị hoặc đọc từ
đầu vào/đầu ra.
a) Kiểu dữ liệu số nguyên:
- Kiểu số nguyên (Integers): Được sử dụng để biểu diễn số nguyên. Ví dụ:
int, short, long long, char, …
- Thông tin của 3 kiểu dữ liệu số nguyên thường dùng:
8
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
- Kiểu double thường được sử dụng nhiều hơn kiểu float vì nó cung cấp độ
chính xác cao hơn và khả năng lưu trữ các giá trị lớn hơn. Tuy nhiên, kiểu
float vẫn có ứng dụng trong các trường hợp cần tiết kiệm bộ nhớ hoặc yêu
cầu độ chính xác không cao.
- Khi thực hiện các phép toán số học với các biến kiểu float và double, cần
chú ý rằng có thể xảy ra sai số độ chính xác do cách biểu diễn số thực
trong máy tính. Điều này có thể gây ra các hiện tượng như làm tròn, tràn
số hay mất chính xác trong kết quả tính toán.
c) Kiểu dữ liệu ký tự:
- Kiểu ký tự (Characters): Được sử dụng để biểu diễn các ký tự riêng lẻ.
Kiểu dữ liệu char được sử dụng cho mục đích này.
- Bảng mã ASCII (American Standard Code for Information Interchange)
là một bảng mã ký tự tiêu chuẩn được sử dụng để biểu diễn các ký tự
trong ngôn ngữ. Bảng mã ASCII gồm 128 ký tự, bao gồm các chữ cái,
chữ số, ký hiệu và các ký tự đặc biệt.
- Mỗi ký tự trong bảng mã ASCII được đại diện bởi một số nguyên từ 0
đến 127. Ví dụ, ký tự 'A' có giá trị ASCII là 65, 'a' có giá trị ASCII là 97,
và ký tự '@' có giá trị ASCII là 64. Bạn có thể sử dụng giá trị ASCII để
thực hiện các phép toán và so sánh trên các ký tự.
- Ví dụ, để khai báo một biến char và gán giá trị ký tự cho nó, bạn có thể sử
dụng như sau:
9
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
- Bảng mã ASCII cung cấp một cách tiêu chuẩn để biểu diễn các ký tự
trong ngôn ngữ, giúp trao đổi dữ liệu giữa các hệ thống và xử lý các chuỗi
ký tự một cách đồng nhất.
- Trong ngôn ngữ lập trình C, có một số ký tự đặc biệt được gọi là "ký tự
điều khiển" (control characters) được sử dụng để điều khiển luồng và định
dạng dữ liệu. Dưới đây là một số ký tự điều khiển phổ biến trong C:
Ký tự Tác dụng
'\n' Ký tự này được sử dụng để di chuyển con trỏ xuống dòng mới trong một chuỗi
ký tự hoặc tập tin đang được xử lý. Nó thường được sử dụng để in ra một dòng
mới hoặc tạo ra định dạng theo dòng.
'\t' Ký tự này được sử dụng để tạo ra một khoảng cách ngang (tương đương 4
khoảng trống) giữa các ký tự. Nó thường được sử dụng để định dạng và căn lề dữ
liệu.
'\b' Ký tự này được sử dụng để xóa một ký tự ngay trước đó và di chuyển con trỏ về
vị trí trước đó.
'\r' Ký tự này được sử dụng để di chuyển con trỏ về đầu dòng trong một chuỗi ký tự
hoặc tập tin đang được xử lý.
'\”' Ký tự \ được sử dụng để định dạng và biểu diễn một số ký tự đặc biệt khác trong
chuỗi ký tự. Ví dụ: '\”' biểu diễn ký tự ” trong chuỗi, bạn cũng có thể thay ” bằng
các ký tự đặc biệt khác.
10
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
d) Kiểu boolean:
- Trong ngôn ngữ lập trình C, boolean không phải kiểu dữ liệu nguyên thủy.
Tuy nhiên, ngôn ngữ C mặc định giá trị 0 là false và khác 0 là true
(thường là 1).
4. Nhập/xuất cơ bản trong C:
a) Nhập/xuất chuẩn:
- Trong ngôn ngữ lập trình C, stdio.h (stdio: standard input/output) là một
trong những header file chuẩn được cung cấp bởi C Standard Library.
Header file này chứa các định nghĩa và khai báo liên quan đến nhập xuất
chuẩn trong C.
- Hàm printf() là một hàm trong ngôn ngữ lập trình C được định nghĩa
trong header file stdio.h. Nó được sử dụng để in các định dạng được định
trước ra màn hình hoặc ghi vào một luồng xuất chuẩn.
- Cú pháp của hàm printf() như sau:
- Giá trị trả về: Hàm printf() trả về giá trị tương ứng với số ký tự đã được in
thành công. Nếu có lỗi xảy ra trong quá trình in, hàm sẽ trả về một giá trị
âm.
11
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
- Hàm scanf() là một hàm trong ngôn ngữ lập trình C được định nghĩa trong
header file stdio.h. Nó được sử dụng để đọc và gán giá trị từ bàn phím
hoặc từ một luồng nhập chuẩn khác vào các biến.
- Cú pháp của hàm scanf() như sau:
- Lưu ý: Để nhập giá trị cho biến, ta cần truyền vào địa chỉ của biến bằng
cách đặt toán tử & trước tên biến.
- Toán tử & (address-of operator) được sử dụng để lấy địa chỉ của một biến
trong bộ nhớ. Điều này cho phép hàm scanf() ghi giá trị nhập vào trực tiếp
vào địa chỉ của biến x, thay vì tạo một bản sao của biến.
- Chú ý rằng kiểu dữ liệu của biến và đặc tả định dạng trong hàm scanf()
phải khớp nhau. Ví dụ, để nhập một số nguyên, ta sử dụng %d trong
scanf(). Đối với kiểu dữ liệu khác như số thực %f, ký tự %c, hoặc chuỗi
%s, ta cần sử dụng đặc tả định dạng tương ứng.
- Nếu không truyền địa chỉ của biến bằng toán tử &, hàm scanf() sẽ không
biết nơi để ghi giá trị nhập vào và có thể gây ra lỗi không xác định hoặc
thay đổi giá trị của biến khác trong bộ nhớ.
12
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
- Giá trị trả về: Hàm scanf() trả về số lượng thành phần đã được gán giá trị
thành công. Nếu có lỗi xảy ra trong quá trình đọc, hàm sẽ trả về một giá
trị âm. Ta có thể lợi dụng tính chất này để đọc input với số lượng đầu vào
không biết trước:
- Ngoài ra còn rất nhiều cách để nhập/xuất với file khác, nhưng cách
sử dụng hàm freopen() là cách đơn giản và thông dụng nhất.
13
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
5. Comment trong C:
- Comment trong ngôn ngữ lập trình C là một phần của mã nguồn không
được biên dịch hoặc thực thi. Nó được sử dụng để giải thích và ghi chú
cho mã nguồn, để làm cho mã dễ hiểu hơn cho người đọc và để tạm thời
vô hiệu hóa một phần của mã.
- Comment không ảnh hưởng đến việc biên dịch chương trình và không
được thực thi khi chương trình chạy. Nó chỉ là một phần của mã nguồn
dùng để giúp lập trình viên giải thích và ghi chú về mã.
- Có 2 loại comment trong C:
+ Comment trên 1 dòng: Bắt đầu bằng hai dấu gạch chéo ngược //.
Mọi nội dung sau dấu gạch chéo ngược trên cùng một dòng sẽ
được xem là comment.
+ Comment trên nhiều dòng: Bắt đầu bằng /* và kết thúc bằng */. Bất
kỳ nội dung nằm giữa hai cặp ký tự này sẽ được coi là comment.
- Comment giúp lập trình viên ghi chú, giải thích code, và làm cho mã
nguồn dễ đọc và dễ hiểu hơn cho người khác hoặc cho chính người viết
code sau này.
14
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
7. Toán tử:
* Ngôn ngữ lập trình C cung cấp nhiều loại toán tử để thực hiện các phép tính
và thao tác trên dữ liệu.
15
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
* Số ngôi (unary) của toán tử là một thuộc tính miêu tả số lượng toán hạng mà
một toán tử sử dụng. Ví dụ: Toán tử chia (/): a / b ta thấy toán tử chia (/) hoạt
động với 2 toán hạng a và b nên toán tử chia (/) là toán tử 2 ngôi.
a) Toán tử số học:
- Trong ngôn ngữ lập trình C, có các toán tử số học để thực hiện các
phép tính số học trên các giá trị số:
+ Toán tử 2 ngôi cộng (+): Thực hiện phép cộng hai giá trị. Ví
dụ: a + b.
+ Toán tử 2 ngôi trừ (-): Thực hiện phép trừ hai giá trị. Ví dụ:
a - b.
+ Toán tử 2 ngôi nhân (*): Thực hiện phép nhân hai giá trị. Ví
dụ: a * b.
+ Toán tử 2 ngôi chia (/): Thực hiện phép chia hai giá trị, kết
quả sẽ trả về số thực khi và chỉ khi có ít nhất 1 toán hạng là
số thực. Không được thực hiện phép chia cho 0 nếu không
thì chương trình sẽ trả về lỗi thực thi. Ví dụ: a / b.
+ Toán tử 2 ngôi chia lấy phần dư (%): Trả về phần dư của
phép chia hai giá trị Không được thực hiện chia dư cho 0 nếu
không chương trình sẽ trả về lỗi thực thi. Ví dụ: a % b.
+ Toán tử 1 ngôi tăng (++): Tăng giá trị của biến lên một đơn
vị. Ví dụ: a++ hoặc ++a.
+ Toán tử 1 ngôi giảm (--): Giảm giá trị của biến đi một đơn vị.
Ví dụ: a-- hoặc --a.
- So sánh ++a và a++:
+ (++a) (prefix increment): Đây là toán tử tăng giá trị của biến
a trước khi sử dụng giá trị đó trong biểu thức. Nó được gọi là
16
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
prefix vì nó được đặt trước tên biến. Kết quả của ++a là giá
trị mới của biến a sau khi đã tăng.
+ (a++) (postfix increment): Đây là toán tử tăng giá trị của
biến a sau khi đã sử dụng giá trị cũ trong biểu thức. Nó được
gọi là postfix vì nó được đặt sau tên biến. Kết quả của a++ là
giá trị cũ của biến a trước khi tăng.
+ Tóm lại, khác biệt chính giữa ++a và a++ là trong thời điểm
mà giá trị của biến được tăng. ++a tăng giá trị trước khi sử
dụng trong biểu thức, trong khi a++ tăng giá trị sau khi sử
dụng.
- Các toán tử số học này cho phép thực hiện các phép tính số học cơ
bản như cộng, trừ, nhân, chia và lấy phần dư. Chúng có thể được
sử dụng trên các kiểu dữ liệu số như int, float, double để thực hiện
các phép tính và thao tác trên các giá trị số.
b) Toán tử quan hệ:
- Trong ngôn ngữ lập trình C, toán tử quan hệ được sử dụng để so
sánh giữa hai giá trị và trả về kết quả là một giá trị boolean
(true/false).
- Các loại toán tử quan hệ trong C:
+ Toán tử 2 ngôi == (bằng): So sánh hai giá trị có bằng nhau
hay không.
+ Toán tử 2 ngôi != (không bằng): So sánh hai giá trị có khác
nhau hay không.
+ Toán tử 2 ngôi > (lớn hơn): Kiểm tra xem giá trị bên trái có
lớn hơn giá trị bên phải hay không.
+ Toán tử 2 ngôi < (nhỏ hơn): Kiểm tra xem giá trị bên trái có
nhỏ hơn giá trị bên phải hay không.
17
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
+ Toán tử 2 ngôi >= (lớn hơn hoặc bằng): Kiểm tra xem giá trị
bên trái có lớn hơn hoặc bằng giá trị bên phải hay không.
+ Toán tử 2 ngôi <= (nhỏ hơn hoặc bằng): Kiểm tra xem giá trị
bên trái có nhỏ hơn hoặc bằng giá trị bên phải hay không.
- Kết quả của các toán tử quan hệ là một giá trị boolean, có thể là 1
(true) nếu biểu thức so sánh là đúng và 0 (false) nếu biểu thức so
sánh là sai.
- Toán tử quan hệ thường được sử dụng trong các câu lệnh điều
khiển điều kiện như if, while, for để kiểm tra điều kiện và thực hiện
các hành động tương ứng.
c) Toán tử gán:
- Trong ngôn ngữ lập trình C, toán tử gán được sử dụng để gán giá
trị cho một biến. Cú pháp chung của toán tử gán là =.
- Có thể sử dụng các toán tử khác trong kết hợp với toán tử gán để
thực hiện các phép toán và gán giá trị cho biến trong một bước.
- Các loại toán tử gán:
+ Toán tử 2 ngôi = : Gán giá trị từ biểu thức bên phải cho biến
bên trái.
+ Toán tử 2 ngôi += : Cộng giá trị bên phải vào giá trị hiện tại
của biến và gán kết quả cho biến.
+ Toán tử 2 ngôi -= : Trừ giá trị bên phải khỏi giá trị hiện tại
của biến và gán kết quả cho biến.
+ Toán tử 2 ngôi *=: Nhân giá trị bên phải với giá trị hiện tại
của biến và gán kết quả cho biến.
+ Toán tử 2 ngôi /=: Chia giá trị hiện tại của biến cho giá trị
bên phải và gán kết quả cho biến.
18
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
+ Toán tử 2 ngôi %=: Lấy phần dư của giá trị hiện tại của biến
khi chia cho giá trị bên phải và gán kết quả cho biến.
- Toán tử gán là một cách tiện lợi để thực hiện các phép toán và gán
giá trị cho biến trong cùng một biểu thức.
d) Toán tử logic:
- Trong ngôn ngữ lập trình C, toán tử logic được sử dụng để thực
hiện các phép logic trên các biểu thức hoặc giá trị logic. Các toán
tử logic thường được sử dụng để kiểm tra và đánh giá các điều kiện
trong các câu lệnh điều kiện và vòng lặp. Giá trị trả về của biểu
thức sử dụng toán tử logic là boolean (true/false).
- Dưới đây là các toán tử logic phổ biến trong C:
+ Toán tử 2 ngôi && (AND): Trả về giá trị true nếu cả hai biểu
thức bên trái và bên phải đều đúng, ngược lại trả về giá trị
false. Ví dụ: a && b.
+ Toán tử 2 ngôi || (OR): Trả về giá trị true nếu ít nhất một
trong hai biểu thức bên trái và bên phải là đúng, ngược lại trả
về giá trị false. Ví dụ: a || b.
+ Toán tử 1 ngôi ! (NOT): Phủ định giá trị của một biểu thức.
Trả về giá trị true nếu biểu thức là sai, và trả về giá trị false
nếu biểu thức là đúng. Ví dụ: !a.
- Lưu ý rằng các toán tử logic thực hiện theo quy tắc đánh đúng
(short-circuit evaluation). Điều này có nghĩa là nếu kết quả cuối
cùng có thể được xác định từ các biểu thức gần nhất, các biểu thức
xa hơn sẽ không được thực hiện:
+ Quy tắc đánh đúng cho toán tử && (AND): Nếu biểu thức
bên trái của && là sai (giá trị false), thì biểu thức bên phải sẽ
không được đánh giá, vì kết quả cuối cùng sẽ là sai. Tuy
19
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
nhiên, nếu biểu thức bên trái là đúng (giá trị true), thì biểu
thức bên phải sẽ được đánh giá để xác định kết quả cuối
cùng.
+ Quy tắc đánh đúng cho toán tử || (OR): Nếu biểu thức bên
trái của || là đúng (giá trị true), thì biểu thức bên phải sẽ
không được đánh giá, vì kết quả cuối cùng sẽ là đúng. Tuy
nhiên, nếu biểu thức bên trái là sai (giá trị false), thì biểu
thức bên phải sẽ được đánh giá để xác định kết quả cuối
cùng.
- Ngoài ra ta có thể sử dụng biểu thức hoặc hàm có trả về giá trị để
làm toán hạng với toán tử logic:
e) Toán tử bitwise:
- Trong ngôn ngữ lập trình C, toán tử bitwise (bitwise operators)
được sử dụng để thực hiện các phép toán bit trên các giá trị số
nguyên. Các toán tử bitwise hoạt động trực tiếp trên các bit của các
giá trị, từ bit thấp nhất đến bit cao nhất.
- Danh sách các toán tử bitwise trong C:
20
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
21
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
- Các toán tử bitwise cũng có thể kết hợp với toán tử gán để thực
hiện các phép toán bitwise và gán giá trị vào biến. Dưới đây là các
toán tử bitwise kết hợp với toán tử gán trong C:
+ Bitwise AND và gán (&=): Toán tử &= thực hiện phép AND
bitwise giữa hai giá trị và gán kết quả vào biến bên trái. Ví
dụ: a &= b; tương đương với a = a & b;.
+ Bitwise OR và gán (|=): Toán tử |= thực hiện phép OR
bitwise giữa hai giá trị và gán kết quả vào biến bên trái. Ví
dụ: a |= b; tương đương với a = a | b;.
+ Bitwise XOR và gán (^=): Toán tử ^= thực hiện phép XOR
bitwise giữa hai giá trị và gán kết quả vào biến bên trái. Ví
dụ: a ^= b; tương đương với a = a ^ b;.
+ Left shift và gán (<<=): Toán tử <<= thực hiện phép dịch trái
bitwise của giá trị và gán kết quả vào biến bên trái. Ví dụ:
a <<= 1; tương đương với a = a << 1;.
+ Right shift và gán (>>=): Toán tử >>= thực hiện phép dịch
phải bitwise của giá trị và gán kết quả vào biến bên trái. Ví
dụ: a >>= 1; tương đương với a = a >> 1;.
f) Toán tử con trỏ:
- Trong ngôn ngữ lập trình C, toán tử con trỏ được sử dụng để khai
báo con trỏ và thực hiện các phép toán liên quan đến con trỏ.
- Các toàn tử con trỏ thường dùng:
+ Toán tử 1 ngôi * (con trỏ): Được sử dụng để khai báo con trỏ
và truy cập giá trị mà con trỏ đang trỏ tới. Ví dụ: int* ptr;
khai báo một con trỏ kiểu int và *ptr truy cập giá trị của biến
mà con trỏ ptr đang trỏ tới.
22
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
+ Toán tử 1 ngôi & (địa chỉ): Được sử dụng để lấy địa chỉ của
một biến. Ví dụ: int a = 10; int* ptr = &a; gán địa chỉ của
biến a cho con trỏ ptr.
+ Toán tử 2 ngôi -> (truy cập đến giá trị): Được sử dụng để
truy cập thành viên của một biến con trỏ trỏ tới, thường là
thành viên của một cấu trúc.
- Các toán tử con trỏ trong ngôn ngữ C cho phép bạn làm việc với
địa chỉ và giá trị của biến, đồng thời cung cấp khả năng truy cập
các thành viên của cấu trúc thông qua biến con trỏ.
II. Cấu trúc điều khiển:
1. Cấu trúc rẽ nhánh:
* Cấu trúc rẽ nhánh (branching structure) là một phần của ngôn ngữ lập trình
cho phép thực hiện các hành động khác nhau dựa trên điều kiện hoặc giá trị của
biến. Cấu trúc rẽ nhánh cho phép chương trình thực hiện các hành động khác
nhau tùy thuộc vào các điều kiện được đưa ra.
23
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
24
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
25
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
26
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
+ Sau khi thực thi xong khối lệnh của một trường hợp case,
chương trình sẽ thoát khỏi cấu trúc switch-case nếu gặp lệnh
break.
+ Trường hợp default sẽ được thực thi khi không có trường
hợp nào khớp với giá trị của biểu thức.
+ Lệnh break được sử dụng để thoát khỏi cấu trúc switch-case
và ngăn chặn việc thực thi các khối lệnh tiếp theo.
+ Nếu trong một trường hợp case không có lệnh break,
chương trình sẽ tiếp tục thực hiện các khối lệnh của các
trường hợp case tiếp theo mà không kiểm tra điều kiện.
Điều này được gọi là "rơi vào" (fall-through) giữa các
trường hợp case.
+ Khi rơi vào giữa các trường hợp case, các khối lệnh của các
trường hợp case sau nó sẽ được thực thi tuần tự cho đến khi
gặp lệnh break hoặc kết thúc cấu trúc switch-case.
+ Đôi khi việc sử dụng rơi vào giữa các trường hợp case có thể
được sử dụng để thực hiện một loạt các trường hợp có cùng
một khối lệnh hoặc để thực hiện một số logic phức tạp hơn.
Tuy nhiên, cần chú ý rằng việc sử dụng rơi vào có thể làm
cho mã nguồn trở nên khó hiểu và dễ gây nhầm lẫn. Do đó,
nếu không có nhu cầu đặc biệt, nên luôn sử dụng lệnh break
để thoát khỏi cấu trúc switch-case sau khi thực thi xong khối
lệnh của một trường hợp case.
27
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
* Cấu trúc lặp trong ngôn ngữ lập trình C là một cách để thực hiện việc lặp lại
một khối lệnh nhiều lần, dựa trên một điều kiện được xác định. Cấu trúc lặp cho
phép chương trình thực hiện một tác vụ lặp đi lặp lại cho đến khi điều kiện
không còn đúng.
* Cần chú ý điều kiện lặp có điểm dừng để vòng lặp không bị rơi vào tình trạng
lặp vô hạn. Vòng lặp vô hạn (infinite loop) là một loại vòng lặp mà điều kiện để
thoát khỏi vòng lặp không bao giờ trở thành sai. Trong ngôn ngữ lập trình C,
vòng lặp vô hạn thường được tạo ra bằng cách sử dụng một điều kiện luôn luôn
đúng hoặc không có điều kiện thoát khỏi vòng lặp.
28
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
vòng lặp sẽ được thực thi. Nếu điều kiện là sai (trả về giá trị
bằng 0), vòng lặp sẽ dừng và chương trình tiếp tục thực hiện
các câu lệnh sau vòng lặp while.
+ Thực thi khối lệnh: Nếu điều kiện là đúng, khối lệnh bên
trong vòng lặp sẽ được thực thi. Điều này có thể bao gồm
một hoặc nhiều câu lệnh. Khối lệnh này sẽ được lặp lại cho
đến khi điều kiện trở thành sai.
+ Cập nhật điều kiện: Sau khi thực thi khối lệnh, điều kiện
được kiểm tra lại. Nếu điều kiện vẫn là đúng, vòng lặp sẽ
tiếp tục lặp lại từ bước 2. Nếu điều kiện trở thành sai, vòng
lặp sẽ dừng và chương trình tiếp tục thực hiện các câu lệnh
sau vòng lặp while.
- Lưu ý rằng nếu điều kiện ban đầu là sai, vòng lặp while sẽ không
được thực thi và chương trình sẽ bỏ qua khối lệnh bên trong vòng
lặp.
- Vòng lặp while thường được sử dụng khi số lần lặp không xác định
trước hoặc dựa trên một điều kiện cụ thể.
b) Vòng lặp do-while:
- Vòng lặp do-while trong ngôn ngữ lập trình C là một loại vòng lặp
mà khối lệnh sẽ được thực thi ít nhất một lần trước khi kiểm tra
điều kiện để tiếp tục hoặc thoát khỏi vòng lặp. Cấu trúc của vòng
lặp do-while như sau:
29
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
- Đầu tiên, khối lệnh bên trong vòng lặp sẽ được thực thi một lần mà
không cần kiểm tra điều kiện. Sau đó, điều kiện sẽ được kiểm tra.
Nếu điều kiện là đúng, khối lệnh sẽ được thực thi tiếp tục. Nếu
điều kiện là sai, vòng lặp do-while sẽ kết thúc và quá trình thực thi
sẽ tiếp tục với các câu lệnh tiếp theo sau vòng lặp.
- Một điểm quan trọng của vòng lặp do-while là khối lệnh được thực
thi ít nhất một lần, ngay cả khi điều kiện ban đầu đã sai. Điều này
khác với vòng lặp while, trong đó khối lệnh chỉ được thực thi khi
điều kiện ban đầu là đúng.
c) Vòng lặp for:
- Vòng lặp for trong ngôn ngữ lập trình C được sử dụng để thực hiện
một khối lệnh lặp lại một số lần xác định. Cấu trúc chung của vòng
lặp for như sau:
30
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
31
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
+ Bước 3 (Thực thi khối lệnh): Nếu điều kiện kiểm tra là đúng,
khối lệnh bên trong vòng lặp được thực thi. Đây là nơi bạn
đặt các câu lệnh và tác vụ muốn lặp lại một số lần.
+ Bước 4 (Thực hiện biểu thức tăng/giảm): Sau mỗi lần thực
thi khối lệnh, biểu thức tăng/giảm được thực hiện. Điều này
thường được sử dụng để thay đổi giá trị của biến điều khiển
vòng lặp. Sau đó, quá trình kiểm tra điều kiện lại được thực
hiện để quyết định xem vòng lặp có tiếp tục hay kết thúc.
+ Bước 5 (Lặp): Quá trình từ bước 2 đến bước 4 được lặp lại
cho đến khi điều kiện kiểm tra trở thành sai, khi đó vòng lặp
kết thúc.
- Với cấu trúc for, bạn có thể kiểm soát được số lần lặp, giá trị ban
đầu và các bước tăng/giảm của biến điều khiển vòng lặp. Điều này
rất hữu ích khi bạn muốn lặp lại một khối lệnh một số lần cụ thể
hoặc khi bạn muốn lặp qua một loạt giá trị với một biến đếm.
3. Câu lệnh break và continue:
* Câu lệnh break và continue là hai câu lệnh điều khiển được sử dụng trong các
vòng lặp trong ngôn ngữ lập trình C.
* Sử dụng câu lệnh break và continue có thể giúp kiểm soát quá trình lặp và
thay đổi luồng điều khiển trong vòng lặp.
32
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
lệnh trong vòng lặp hoặc khối lệnh switch-case và thoát khỏi nó,
tiếp tục thực hiện các câu lệnh sau vòng lặp hoặc khối lệnh.
- Câu lệnh break thường được sử dụng trong các trường hợp sau:
+ Trong vòng lặp: Khi một điều kiện cụ thể được đáp ứng, ta
có thể sử dụng break để kết thúc vòng lặp sớm. Việc này
giúp tiết kiệm thời gian và ngừng thực hiện các lần lặp còn
lại của vòng lặp.
+ Trong khối lệnh switch-case: Mỗi trường hợp (case) trong
khối lệnh switch-case sẽ thực hiện một chuỗi câu lệnh. Bằng
cách sử dụng break ở cuối mỗi trường hợp, ta có thể kết thúc
khối lệnh switch-case sau khi thực hiện trường hợp tương
ứng và ngăn chặn việc thực hiện các trường hợp tiếp theo.
b) Câu lệnh continue:
- Câu lệnh continue trong ngôn ngữ lập trình C được sử dụng để bỏ
qua các câu lệnh còn lại trong vòng lặp hiện tại và chuyển đến lần
lặp tiếp theo. Khi câu lệnh continue được thực thi, các câu lệnh
trong vòng lặp sau câu lệnh continue sẽ không được thực hiện và
chương trình sẽ tiếp tục với lần lặp kế tiếp.
- Câu lệnh continue thường được sử dụng trong trường hợp: Trong
vòng lặp khi một điều kiện cụ thể được đáp ứng, ta có thể sử dụng
continue để bỏ qua các câu lệnh trong vòng lặp và chuyển đến lần
33
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
lặp tiếp theo. Việc này giúp loại bỏ các lần lặp không cần thiết và
tiếp tục với các lần lặp khác.
- Lưu ý rằng việc sử dụng câu lệnh goto có thể làm cho mã nguồn trở nên
khó hiểu và khó bảo trì, do đó nên sử dụng nó cẩn thận và chỉ khi thực sự
cần thiết.
34
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
35
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
sau phần khai báo. Bạn có thể bỏ qua bước khai báo hàm và có thể
định nghĩa hàm luôn, nhưng điều này dẫn đến bạn không được gọi
hàm trước khi định nghĩa hàm.
+ Định nghĩa hàm: Đầu tiên, bạn cần định nghĩa hàm bằng cách khai
báo kiểu trả về, tên hàm và các tham số (nếu có). Định nghĩa hàm
chứa một khối lệnh thực hiện các công việc cụ thể của hàm.
+ Gọi hàm: Sau khi hàm đã được định nghĩa, bạn có thể gọi hàm
bằng cách sử dụng tên hàm và truyền các đối số cần thiết (nếu có).
Khi gọi hàm, chương trình sẽ thực hiện các công việc trong khối
lệnh của hàm.
- Trong ngôn ngữ lập trình C, bạn có thể định nghĩa cho tham số mặc định
(default parameter) trong định nghĩa hàm. Khi bạn truyền đối số tương
ứng với tham số này, tham số đó sẽ nhận giá trị là đối số tương ứng, còn
nếu không thì tham số đó sẽ nhận giá trị mặc định mà bạn đã định nghĩa
trước đó. Lưu ý: Các tham số mặc định phải được định nghĩa sau cùng!
36
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
- Hàm đệ quy trong ngôn ngữ lập trình C là một hàm mà trong quá trình
thực thi có thể gọi lại chính nó. Kỹ thuật đệ quy rất hữu ích khi cần giải
quyết các bài toán được phân tách thành các bước nhỏ hơn, mỗi bước
tương tự như bài toán gốc. Cấu trúc của một hàm đệ quy bao gồm:
+ Điều kiện dừng: Một điều kiện được xác định để đảm bảo việc gọi
đệ quy sẽ dừng lại và trả về kết quả mong muốn. Điều kiện này
thường được đặt ở đầu hàm đệ quy để kiểm tra và trả về kết quả
ngay khi thỏa mãn điều kiện.
+ Gọi đệ quy: Trong thân hàm, gọi lại chính hàm đó với các giá trị
khác nhau để giải quyết bài toán trong quy mô nhỏ hơn. Các tham
số của hàm đệ quy thường thay đổi để tiến tới điều kiện dừng.
+ Xử lý kết quả: Kết quả từ các lời gọi đệ quy được kết hợp để đạt
được kết quả cuối cùng của bài toán.
+ Phần này tìm hiểu thêm trong tài liệu Cấu trúc dữ liệu và giải thuật
nhé!
2. Hàm trong thư viện chuẩn:
- Thư viện chuẩn C (Standard Library) cung cấp một tập hợp các hàm tiện
ích đã được định nghĩa sẵn mà bạn có thể sử dụng trong chương trình C
của mình. Dưới đây là một số ví dụ về các hàm quan trọng có sẵn trong
thư viện chuẩn C:
+ printf/scanf trong stdio.h: Hàm nhập/xuất chuẩn.
37
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
38
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
* Mảng trong ngôn ngữ lập trình C là một cấu trúc dữ liệu dùng để lưu trữ một
tập hợp các phần tử có cùng kiểu dữ liệu. Mảng được định nghĩa bằng cách khai
báo kiểu dữ liệu của phần tử và kích thước của mảng.
* Trong mảng, các phần tử được lưu trữ liên tiếp trong bộ nhớ và truy cập thông
qua chỉ số của mảng. Chỉ số của mảng bắt đầu từ 0 và kết thúc ở kích thước của
mảng trừ 1.
* Mảng cũng có thể là một 1 chiều, mảng 2 chiều hoặc mảng đa chiều, cho phép
lưu trữ dữ liệu trong một cấu trúc hai hoặc nhiều chiều.
* Lưu ý rằng kích thước của mảng phải là một giá trị cố định được xác định tại
thời điểm biên dịch, không thể thay đổi trong quá trình thực thi chương trình.
39
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
Nếu mảng được khai báo trong hàm và không khởi tạo giá trị cho mảng thì các
phần tử của mảng sẽ mang giá trị ngẫu nhiên (giá trị rác).
1. Mảng 1 chiều:
- Mảng 1 chiều trong ngôn ngữ lập trình C là một cấu trúc dữ liệu được sử
dụng để lưu trữ và quản lý một tập hợp các phần tử có cùng kiểu dữ liệu
và được xếp theo thứ tự.
- Để truy cập các đến phần tử trong mảng ta sử dụng chỉ số của các phần tử
đó. Ví dụ muốn gán giá trị 10 cho phần tử có chỉ số 5 trong mảng a ta làm
như sau: a[5] = 10;
- Các thao tác với mảng 1 chiều:
40
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
2. Mảng đa chiều:
- Mảng đa chiều (Multi-dimensional array) là một mảng của các mảng.
Mảng 2 chiều hay ma trận là mảng đa chiều thường được sử dụng nhất.
Khi đó, mảng 2 chiều là một mảng của các mảng 1 chiều. Mảng 2 chiều
có cách lưu trữ các phần tử giống như một bảng.
- Giả sử mảng 1 chiều có n phần tử nếu mỗi phần tử của mảng là 1 mảng 1
chiều ⇒ Ta có mảng 2 chiều.
- Lưu ý: Mảng 2 chiều có kích thước m x n thì chỉ số của hàng là từ 0 đến
m - 1, của cột là từ 0 đến n - 1.
- Cách truy cập tới phần tử của ma trận cũng giống như với mảng 1 chiều.
Tuy nhiên, chúng ta sẽ có 2 chỉ số khác nhau là chỉ số hàng và chỉ số cột.
Cú pháp như sau: arr[row_index][col_index]. Ví dụ muốn gán giá trị 5
cho phần tử ở hàng 3, cột 4 ta làm như sau: a[2][3] = 5;
41
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
42
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
- Bài toán: Cho mảng a[] = {4, 1, 3, 2, 5}, hãy đưa ra mảng a[] đã được
sắp xếp.
- Cách thực hiện:
+ Bước 1: Đầu tiên, chúng ta sẽ duyệt từ đầu đến cuối mảng, tại mỗi
lần duyệt chúng ta sẽ so sánh phần tử hiện tại với phần tử kế tiếp
nó và đổi chỗ nếu cần thiết, thực hiện liên tục cho đến cuối mảng.
[4 1 3 2 5] ⇨ [1 4 3 2 5] Swap vì 4 > 1.
[1 4 3 2 5] ⇨ [1 3 4 2 5] Swap vì 4 > 3.
[1 3 4 2 5] ⇨ [1 3 2 4 5] Swap vì 4 > 2.
[1 3 2 4 5] ⇨ [1 3 2 4 5] Không swap vì 4 < 5.
+ Bước 2: Kết thúc lần duyệt đầu tiên, thuật toán đã xác định rằng [5]
là số lớn nhất trong mảng và đã được đưa về đúng vị trí (Vị trí cuối
mảng). Thuật toán bây giờ sẽ bắt đầu duyệt lần 2 và bỏ qua vị trí
index = 4 do phần tử lớn nhất đã được đặt đúng vị trí.
[1 3 2 4 5] ⇨ [1 3 2 4 5] Không swap vì 1 < 3.
[1 3 2 4 5] ⇨ [1 2 3 4 5] Swap vì 3 > 2.
[1 2 3 4 5] ⇨ [1 2 3 4 5] Không swap vì 3 < 4.
+ Bước 3: Bây giờ, mảng đã được sắp xếp theo thứ tự tăng dần trước
khi thuật toán hoàn thành, tuy nhiên thuật toán không biết danh
sách đã được sắp xếp hay chưa nên sẽ tiếp tục duyệt 1 lần nữa để
chắc chắn rằng không có bất kỳ 1 lần swap nào trong lần duyệt này.
[1 2 3 4 5] ⇨ [1 2 3 4 5] Không swap vì 1 < 2
[1 2 3 4 5] ⇨ [1 2 3 4 5] Không swap vì 2 < 3
+ Nhận xét: Tại bước này, ta thấy không có bất kỳ 1 lần swap nào tức
là tất cả các phần tử đã đứng đúng vị trí của nó, do đó ta có thể kết
thúc thuật toán tại bước này.
𝑛(𝑛 − 1)
+ Công thức tính số lần so sánh và swap tối đa:
2
43
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
- Code:
44
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
- Để truy cập và thao tác với các phần tử trong xâu ký tự, chúng ta có thể
sử dụng chỉ số của mảng như các mảng thông thường.
45
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
- Cách khai báo và khởi tạo mảng ký tự 2 chiều tương tự mảng số nguyên 2
chiều, chỉ có điều là các phần tử là ký tự và mỗi hàng là 1 xâu ký tự
(chuỗi).
3. Các hàm xử lý ký tự:
- Trước tiên, cần phải biết thư viện chứa các hàm xử lý ký tự: ctype.h
- Các hàm xử lý ký tự thường gặp:
+ Hàm kiểm tra một ký tự có phải là ký tự số hay không?
● Cú pháp: isdigit(<kí tự cần kiểm tra>)
46
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
● Hàm này trả về giá trị boolean: Trả về true nếu ký tự nhập
vào là ký tự nằm trong đoạn từ ‘0’ đến ‘9’ và false trong
trường hợp ngược lại.
+ Hàm kiểm tra một ký tự có phải là ký tự chữ cái hay không?
● Cú pháp: isalpha(<kí tự cần kiểm tra>)
● Hàm này trả về giá trị boolean: Trả về true nếu ký tự nhập
vào là ký tự nằm trong đoạn từ ‘a’ đến ‘z’ hoặc từ ‘A’ đến
‘Z’ và false trong trường hợp ngược lại.
+ Hàm kiểm tra một ký tự có phải là ký tự chữ in thường hay không?
● Cú pháp: islower(<kí tự cần kiểm tra>)
● Hàm này trả về giá trị boolean: Trả về true nếu ký tự nhập
vào là ký tự nằm trong đoạn ‘a’ đến ‘z’ và false trong trường
hợp ngược lại.
+ Hàm kiểm tra một ký tự có phải là ký tự in thường hay không?
● Cú pháp: isupper(<kí tự cần kiểm tra>)
● Hàm này trả về giá trị boolean: Trả về true nếu ký tự nhập
vào là ký tự nằm trong đoạn từ ‘A’ đến ‘Z’ và false trong
trường hợp ngược lại.
+ Hàm kiểm tra một ký tự có phải là ký tự số hoặc chữ cái hay
không?
● Cú pháp: isalnum(<kí tự cần kiểm tra>)
● Hàm này trả về giá trị boolean: Trả về true nếu ký tự nhập
vào là ký tự nằm trong đoạn từ ‘0’ đến ‘9’ hoặc từ ‘a’ đến ‘z’
hoặc từ ‘A’ đến ‘Z’ và false trong trường hợp ngược lại.
+ Hàm chuyển một ký tự chữ cái sang ký tự chữ cái viết hoa:
● Cú pháp: toupper(<kí tự cần chuyển>)
47
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
48
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
● Hàm này sẽ copy chuỗi str2 vào chuỗi str1, lưu ý là chuỗi
str1 phải có kích thước đủ lớn để chứa chuỗi str2 nếu không
sẽ gây tràn bộ nhớ.
+ Hàm so sánh 2 chuỗi str1, str2:
● Cú pháp: strcmp(str1, str2)
● Hàm này sẽ trả về 1 trong 3 giá trị:
★ Một giá trị âm nếu thứ tự từ điển của chuỗi str1 nhỏ
hơn thứ tự từ điển của chuỗi str2.
★ Một giá trị dương nếu thứ tự từ điển của chuỗi str1 lớn
hơn thứ tự từ điển của chuỗi str2.
★ Giá trị 0 nếu thứ tự từ điển của chuỗi str1 bằng thứ tự
từ điển của chuỗi str2 (Tức 2 chuỗi giống y hệt nhau).
5. Tách xâu ký tự:
- Hàm char *strtok (char *str, const char *delim) chia chuỗi str thành
một dãy các token được phân biệt riêng rẽ bởi dấu tách delim (như dấu
phẩy, chấm phẩy …).
- Tham số:
+ str: Nội dung của chuỗi này được sửa đổi và được chia thành các
chuỗi nhỏ hơn (các token).
+ delim: Đây là chuỗi chứa Delimiter (chỉ các dấu phân tách). Chúng
có thể rất đa dạng tùy vào từng lời gọi.
- Giá trị trả về: Hàm này trả về con trỏ trỏ tới token đầu tiên được tìm thấy
trong chuỗi. Một con trỏ NULL được trả về nếu không thu được token
nào.
- strtok() quét chuỗi nhập vào từ trái sang phải. Bất cứ khi nào nó tìm thấy
một dấu phân tách, nó sẽ thay thế dấu phân cách bằng một ký tự kết thúc
NULL (‘\0’) và trả về con trỏ đến token đã trích xuất.
49
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
50
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
nguyên chuỗi ban đầu, hãy sao chép nó vào một chuỗi khác trước khi sử
dụng strtok().
VII. Con trỏ:
1. Biến và địa chỉ:
- Cấu trúc của 1 biến khi được khai báo gồm 3 phần:
+ Tên biến.
+ Giá trị của biến (Trong trường hợp biến chưa được gán giá trị ban
đầu, biến sẽ mang giá trị ngẫu nhiên hay còn gọi là giá trị rác).
+ Địa chỉ của biến.
- Muốn thay đổi giá trị của biến, ta phải thay đổi giá trị tại địa chỉ của biến.
- Muốn nhập giá trị cho biến, ta phải nhập giá trị tại địa chỉ của biến.
2. Con trỏ:
- Con trỏ là biến trỏ tới địa chỉ hay nói cách khác là nó mang giá trị là một
địa chỉ.
- Con trỏ cũng là một biến nên nó cũng có giá trị và địa chỉ của riêng nó.
- Cách khai báo con trỏ: <Kiểu dữ liệu>* <Tên con trỏ>;
- Ví dụ: int* a;
- Vì con trỏ là biến mang giá trị là 1 địa chỉ nên khi gán giá trị cho con trỏ
ta phải gán giá trị cho nó là 1 địa chỉ.
- Để lấy địa chỉ của 1 biến, ta sử dụng toán tử 1 ngôi &.
- Để lấy giá trị tại 1 địa chỉ hay giá trị tại địa chỉ mà con trỏ đang trỏ tới ta
sử dụng toán tử 1 ngôi *.
51
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
- Nếu như thay đổi giá trị tại địa chỉ mà con trỏ đang trỏ tới thì giá trị của
biến cũng thay đổi theo.
- Giá trị của con trỏ: địa chỉ mà con trỏ trỏ đến.
- Địa chỉ của con trỏ: địa chỉ của bản thân biến con trỏ đó.
- Giá trị của biến nơi con trỏ đang trỏ tới.
- Địa chỉ của biến nơi con trỏ đang trỏ tới = giá trị của con trỏ.
3. Mối quan hệ giữa con trỏ và mảng 1 chiều:
- Nhắc lại khái niệm về mảng: “Mảng là một tập hợp tuần tự các phần tử
có cùng kiểu dữ liệu và các phần tử được lưu trữ trong một dãy các ô nhớ
liên tục trên bộ nhớ”.
- Các bạn đặc biệt lưu ý tới tính chất được lưu trên các ô nhớ liên tục, bây
giờ chúng ta sẽ chứng minh tính đúng đắn của nó bằng ví dụ dưới đây:
52
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
- Nhận xét: Địa chỉ của mỗi phần tử cách nhau 4 đơn vị tương ứng với 4
byte của kiểu dữ liệu int. Nên ta chắc chắn các phần tử mảng được xếp
cạnh nhau trong bộ nhớ.
⇒ Như vậy, &arr[0] tương đương &arr và tương đương arr. Điều đó có
được là do biến arr trỏ tới phần tử đầu tiên của mảng.
⇒ Do đó, nếu ta thay đổi giá trị các phần tử của mảng ở ngoài hàm
main() thì giá trị của các phần tử trong hàm main() cũng thay đổi theo!
Theo dõi ví dụ dưới đây:
53
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
54
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
- Lưu ý: Khi dùng toán tử tăng/giảm trên biến con trỏ, nó sẽ nhảy sang ô
nhớ liền kề chứ không phải tăng địa chỉ mà nó đang trỏ lên 1. Do con trỏ
p là kiểu int nên mỗi bước tăng, giá trị của p tăng thêm 4 giá trị. (Lưu ý:
giá trị của con trỏ là địa chỉ mà nó đang trỏ tới).
55
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
- Cách khai báo biến kiểu struct: Việc khai báo biến với struct cũng giống
như cách khai báo biến thông thường, trong đó kiểu dữ liệu là kiểu struct
trong C mà bạn vừa định nghĩa.
- Cách truy xuất các thuộc tính của biến kiểu struct: Để truy xuất các thuộc
tính của 1 biến kiểu struct ta sử dụng toán tử “.”
56
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
- Cấu trúc struct lồng nhau: Trong 1 struct ta có thể định nghĩa 1 thuộc tính
trong struct đó bằng 1 struct khác, tuy nhiên 1 struct không thể định nghĩa
chính nó là 1 thuộc tính.
- Khởi tạo biến kiểu cấu trúc: Ta có thể khởi tạo 1 biến kiểu struct ngay khi
khai báo bằng cách liệt kê các thuộc tính của nó nằm trong cặp {} lần
lượt theo những gì đã định nghĩa trong struct.
57
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
- Câu lệnh gán: Hai biến cấu trúc cùng kiểu thì ta có thể sử dụng toán tử
gán “=” để copy tất cả các thuộc tính của biến cấu trúc này cho biến cấu
trúc kia.
- Mảng kiểu struct: Mảng kiểu struct được khai báo tương tự như mảng
thông thường. Một kiểu struct phải được định nghĩa trước sau đó một
biến mảng có kiểu đó mới được khai báo.
58
Tài liệu ngôn ngữ lập trình C - Nguyễn Mạnh Quân ITIS Study
- Con trỏ kiểu struct: Con trỏ cấu trúc được khai báo bằng cách đặt toán tử
“*” trước tên của 1 biến cấu trúc. Con trỏ cấu trúc được truyền vào hàm
cho phép hàm đó thay đổi các thuộc tính của biến cấu trúc mà nó trỏ đến.
Để truy cập đến các thuộc tính của biến cấu trúc mà con trỏ đang trỏ đến,
ta sử dụng toán tử “->”.
- Ngoài struct, ta còn có kiểu dữ liệu tự định nghĩa nữa là union, cái này
các bạn tự tìm hiểu nhé!
59