Trong bài viết trước, chúng ta đã tìm hiểu tổng quan về lập trình ngôn ngữ C, bài viết này hãy cùng mình đi vào tìm hiểu các khái niệm quan trọng mà các bạn cần khi nhớ khi làm việc cùng ngôn ngữ này nhé!
1. Các khái niệm quan trọng trong ngôn ngữ C
1.1 Biến (Variable)
Biến trong ngôn ngữ lập trình C là một định danh được sử dụng để lưu trữ giá trị dữ liệu. Mỗi biến có một kiểu dữ liệu và một tên riêng biệt để xác định nó. Dưới đây là một số khái niệm quan trọng về biến trong C:
1.1.1 Khai báo biến (Variable Declaration)
Để tạo một biến trong C, bạn phải khai báo nó. Khai báo biến bao gồm kiểu dữ liệu và tên biến. Ví dụ:
int age; // Khai báo một biến kiểu int có tên là "age"
Vậy điều gì xảy ra ở dưới khi chúng ta khai báo một biến trong C?
- Không gian bộ nhớ được cấp phát: Khi bạn khai báo một biến, hệ thống cấp phát một phần của bộ nhớ cho biến đó. Kích thước của phần này phụ thuộc vào kiểu dữ liệu của biến. Ví dụ, một biến kiểu
int
thường cấp phát 4 byte (32 bit) trong bộ nhớ. - Địa chỉ bộ nhớ được gán cho biến: Mỗi biến sẽ có một địa chỉ bộ nhớ cụ thể, và bạn sử dụng tên biến để tham chiếu đến địa chỉ này trong mã nguồn của bạn.
1.1.2 Khởi tạo biến (Variable Initialization)
Bạn có thể khai báo và khởi tạo biến cùng một lúc. Ví dụ:
int count = 0; // Khai báo và khởi tạo biến "count" với giá trị ban đầu là 0
Việc khởi tạo biến trong C là không bắt buộc, tuy nhiên nó cũng có một số lợi ích. Dưới đây là một số lý do tại sao bạn nên khởi tạo biến:
- Tránh giá trị rác: Khi bạn khởi tạo một biến, bạn cung cấp một giá trị ban đầu cho nó. Nếu bạn không khởi tạo biến, giá trị của biến có thể chứa giá trị rác từ vùng bộ nhớ trước đó, và điều này có thể dẫn đến lỗi không xác định hoặc hành vi không mong muốn.
- Tạo mã dễ đọc và dễ bảo trì: Khởi tạo biến giúp làm cho mã nguồn dễ đọc hơn. Khi bạn đọc mã, bạn biết giá trị ban đầu của biến là gì, điều này giúp bạn hiểu mã nguồn nhanh hơn.
- Bảo trì tính nhất quán: Khởi tạo biến giúp đảm bảo tính nhất quán trong mã nguồn. Điều này làm cho mã dễ bảo trì hơn bởi vì bạn biết rằng biến luôn có một giá trị ban đầu đã định.
- Tránh lỗi logic: Khởi tạo biến có thể giúp bạn phát hiện và tránh lỗi logic trong mã nguồn. Khi bạn sử dụng một biến mà bạn đã quên khởi tạo, bạn có thể gặp lỗi không mong muốn khi sử dụng giá trị của nó.
1.1.3 Tên biến (Variable Name)
Tên biến là một định danh duy nhất được sử dụng để xác định biến. Tên biến phải tuân theo các quy tắc về cú pháp và không được trùng với từ khóa trong ngôn ngữ C.
Có một số quy tắc cơ bản trong việc đặt tên biến trong C:
- Chỉ sử dụng chữ cái, số và dấu gạch dưới: Tên biến chỉ có thể bắt đầu bằng một chữ cái (a-z hoặc A-Z), một số (0-9) hoặc một dấu gạch dưới (_). Những ký tự sau có thể bao gồm chữ cái, số và dấu gạch dưới.
- Không sử dụng dấu cách: Tên biến không được chứa khoảng trắng hoặc dấu cách. Nếu bạn muốn kết hợp từ hoặc cụm từ, bạn có thể sử dụng dấu gạch dưới hoặc chữ hoa để phân biệt, ví dụ:
my_variable
,myVariable
. - Không sử dụng từ khóa của ngôn ngữ: Tên biến không được trùng với từ khóa hoặc các từ được định nghĩa trước trong ngôn ngữ C, chẳng hạn như
int
,if
,while
,return
, v.v. - Phân biệt chữ hoa và chữ thường: Các biến trong C phân biệt chữ hoa và chữ thường. Ví dụ,
myVariable
vàmyvariable
là hai biến khác nhau. - Chọn tên biến có ý nghĩa: Tên biến nên phản ánh mục đích hoặc nhiệm vụ của biến. Điều này làm cho mã nguồn dễ đọc và dễ bảo trì hơn. Ví dụ, thay vì sử dụng
x
hoặca
, bạn nên sử dụng tên biến mô tả giá trị của nó, chẳng hạnage
,count
,total
, v.v. - Sử dụng kiểu Camel Case hoặc Snake Case: Có hai phong cách phổ biến để đặt tên biến: Camel Case và Snake Case. Trong Camel Case, từ đầu tiên bắt đầu bằng chữ thường, sau đó mỗi từ tiếp theo bắt đầu bằng chữ in hoa, ví dụ:
myVariableName
. Trong Snake Case, các từ được phân tách bằng dấu gạch dưới, ví dụ:my_variable_name
. Cả hai phong cách đều được chấp nhận, nhưng quan trọng là duy nhất trong mã nguồn của bạn. - Giới hạn độ dài tên biến: Tên biến nên ngắn gọn và dễ đọc. Tránh đặt tên biến quá dài hoặc quá ngắn.
1.1.4 Gán giá trị (Assignment)
Để gán một giá trị mới cho biến, bạn sử dụng toán tử gán (=). Ví dụ:
age = 25; // Gán giá trị 25 cho biến "age"
Khi bạn gán giá trị cho một biến trong ngôn ngữ lập trình C, bạn đang thực hiện thao tác gán, tức là bạn đang đặt giá trị mới cho biến. Dưới đây là một số điểm quan trọng về quá trình gán giá trị này:
- Gán giá trị mới: Gán giá trị cho biến có nghĩa là bạn thay đổi giá trị của biến bằng giá trị mới.
- Thay đổi giá trị biến: Gán giá trị mới cho biến thay đổi giá trị của nó và làm cho giá trị trước đó bị mất đi. Giá trị mới được lưu trong biến.
- Kiểu dữ liệu phải phù hợp: Giá trị bạn gán cho biến phải phù hợp với kiểu dữ liệu của biến. Ví dụ, nếu biến là kiểu
int
, bạn chỉ có thể gán giá trị nguyên cho nó. - Gán có thể kết hợp với các biểu thức: Bạn có thể kết hợp gán với các biểu thức, ví dụ:
- Thứ tự trong biểu thức gán: Các ngôn ngữ lập trình xác định một thứ tự cụ thể cho các biểu thức gán. Điều này có thể ảnh hưởng đến kết quả của biểu thức, đặc biệt trong trường hợp của biểu thức phức tạp. Ví dụ:
int x = 10; // Khai báo và khởi tạo biến x với giá trị ban đầu là 10
x = 20; // Gán giá trị mới cho biến x, giờ x = 20
int x = 10;
x = x + 5; // Gán giá trị mới cho biến x bằng cách sử dụng biểu thức
int x = 5;
int y = 10;
x = y = 15; // Điều này gán giá trị 15 cho cả x và y
1.1.5 Phạm vi biến (Variable Scope)
Phạm vi của một biến xác định nơi mà biến có thể được truy cập. Biến cục bộ (local variables) chỉ có thể truy cập trong phạm vi của hàm hoặc khối mã trong đó chúng được khai báo, trong khi biến toàn cục (global variables) có thể truy cập từ mọi nơi trong chương trình.
Biến Cục Bộ (Local Variable):
#include <stdio.h>
int main() {
int x = 10; // Đây là một biến cục bộ trong hàm main
if (x > 5) {
int y = 20; // Đây là một biến cục bộ trong khối mã if
printf("x = %d, y = %d\n", x, y);
}
// Biến y không thể truy cập ở đây vì nó đã vượt ra khỏi phạm vi của khối mã if
printf("x = %d\n", x);
return 0;
}
Trong ví dụ trên, biến x
và y
là biến cục bộ. Biến x
được khai báo trong hàm main
, và biến y
được khai báo trong khối mã của câu lệnh if
. Biến x
có phạm vi trong toàn bộ hàm main
, trong khi biến y
chỉ có phạm vi trong khối mã của câu lệnh if
. Vì vậy, sau khi chương trình rời khỏi khối mã if
, biến y
không còn tồn tại.
Biến Toàn Cục (Global Variable):
#include <stdio.h>
int globalVar = 100; // Đây là biến toàn cục
int main() {
int x = 10; // Đây là biến cục bộ trong hàm main
printf("x = %d, globalVar = %d\n", x, globalVar);
return 0;
}
Trong ví dụ này, biến globalVar
là biến toàn cục, có thể truy cập từ bất kỳ hàm nào trong chương trình. Biến x
là biến cục bộ, chỉ có phạm vi trong hàm main
. Khi bạn muốn sử dụng biến toàn cục, bạn có thể thực hiện điều đó từ bất kỳ hàm nào trong chương trình, như trong ví dụ trên.
1.2 Kiểu dữ liệu (Data Type)
C có một loạt các kiểu dữ liệu mà bạn có thể sử dụng để định nghĩa và lưu trữ dữ liệu. Dưới đây là một số kiểu dữ liệu thường gặp trong C:
- int: Kiểu dữ liệu nguyên (integer) được sử dụng để lưu trữ các số nguyên. Ví dụ:
int x = 10;
- float: Kiểu dữ liệu số thực đơn (floating-point) được sử dụng để lưu trữ các số thập phân. Ví dụ:
float y = 3.14;
- double: Kiểu dữ liệu số thực kép (double-precision floating-point) tương tự như
float
, nhưng có độ chính xác cao hơn. Ví dụ:double z = 3.14159265359;
- char: Kiểu dữ liệu ký tự (character) được sử dụng để lưu trữ một ký tự. Ví dụ:
char ch = 'A';
- long int: Kiểu dữ liệu số nguyên dài (long integer) có kích thước lớn hơn so với
int
. Ví dụ:long int b = 1000L;
- unsigned int: Kiểu dữ liệu số nguyên không dấu (unsigned integer) để lưu trữ các số nguyên không âm (tức là không có dấu). Ví dụ:
unsigned int c = 20;
- unsigned char: Kiểu dữ liệu ký tự không dấu (unsigned character) để lưu trữ ký tự không dấu. Ví dụ:
unsigned char uc = 'B';
1.3 In và đọc dữ liệu
C cung cấp sẵn cho chúng ta 2 hàm là printf
và scanf
dùng để in và đọc dữ liệu.
1.3.1 printf
Được sử dụng để in dữ liệu ra màn hình theo một định dạng cụ thể.'
- Cú pháp
- Ví dụ:
printf("Định dạng chuỗi", tham số1, tham số2, ...);
int age = 30;
float salary = 1000.50;
printf("Tuổi: %d\n", age);
printf("Lương: %.2f\n", salary);
1.3.2 scanf
Được sử dụng để đọc dữ liệu từ bàn phím vào biến theo một định dạng cụ thể.
- Cú pháp
- Ví dụ:
scanf("Định dạng chuỗi", &biến1, &biến2, ...);
int age;
float salary;
printf("Nhập tuổi: ");
scanf("%d", &age);
printf("Nhập lương: ");
scanf("%f", &salary);
Lưu ý rằng trong scanf
, bạn phải sử dụng dấu &
trước tên biến để truyền địa chỉ của biến đó cho scanf
. Điều này là cần thiết để scanf
có thể ghi dữ liệu vào biến được chỉ định.
1.3.3 Định dạng dữ liệu
Các kí hiệu như %d
hay %s
được sử dụng trong printf
với scanf
được gọi là định dạng của dữ liệu. Để định dạng cách in hay đọc dữ liệu, C đã cung cấp sẵn cho chúng ta các loại định dạng sau:
- %c : Ký tự đơn
- %s : Chuỗi
- %d : Số nguyên hệ 10 có dấu
- %f : Số chấm động (VD 7.44 khi in sẽ ra 7.440000)
- %e : Số chấm động (ký hiệu có số mũ)
- %g : Số chấm động (VD 7.44 khi in sẽ in ra 7.44)
- %x : Số nguyên hex không dấu (hệ 16)
- %o : Số nguyên bát phân không dấu (hệ 8)
- %p : Địa chỉ con trỏ
1.4 Hàm (Function)
Trong ngôn ngữ lập trình C, hàm (function) là một khối mã thực hiện một tác vụ cụ thể. Hàm là một phần quan trọng của chương trình C, vì chúng giúp bạn chia nhỏ chương trình thành các phần nhỏ dễ quản lý và sử dụng lại. Dưới đây là cách định nghĩa và sử dụng hàm trong C:
1.4.1 Cú pháp của hàm
Một hàm trong C được định nghĩa bằng cú pháp sau:
kiểu_dữ_liệu tên_hàm(tham_số) {
// Khối mã của hàm
// Thực hiện các công việc ở đây
return giá_trị_trả_về; // Optional
}
kiểu_dữ_liệu
: Đây là kiểu dữ liệu của giá trị mà hàm sẽ trả về. Nếu hàm không trả về giá trị, bạn sử dụngvoid
.tên_hàm
: Đây là tên của hàm, bạn tự đặt tên cho hàm. Tên hàm phải tuân theo quy tắc đặt tên biến.tham_số
: Đây là các tham số (có thể là không có tham số) mà hàm có thể nhận vào. Tham số là các giá trị mà bạn truyền cho hàm để thực hiện các công việc cụ thể.khối mã của hàm
: Đây là nơi bạn đặt mã nguồn của hàm, thực hiện các công việc cụ thể.giá_trị_trả_về
: Nếu hàm trả về một giá trị, bạn sử dụng lệnhreturn
để trả giá trị đó. Nếu hàm không trả về giá trị hoặc chỉ có mục tiêu thực hiện công việc mà không cần trả về giá trị, bạn sử dụngreturn
vớivoid
.
1.4.2 Gọi hàm
Để sử dụng hàm, bạn gọi hàm bằng tên của nó cùng với các đối số (nếu có). Ví dụ:
int sum(int a, int b) {
return a + b;
}
int main() {
int x = 5;
int y = 3;
int result = sum(x, y); // Gọi hàm sum và lưu kết quả vào result
return 0;
}
1.4.3 Hàm có hoặc không có giá trị trả về
Hàm có thể có giá trị trả về hoặc không. Ví dụ:
int multiply(int a, int b) {
return a * b; // Hàm trả về một giá trị kiểu int
}
void greet() {
printf("Hello, World!\n"); // Hàm không trả về giá trị (void)
}
1.4.4 Hàm nguyên mẫu (Function Prototype)
Trước khi sử dụng hàm trong một tệp mã nguồn khác, bạn nên định nghĩa hàm nguyên mẫu (function prototype) ở đầu tệp mã hoặc bao gồm tệp tiêu đề chứa định nghĩa hàm. Hàm nguyên mẫu chỉ ra kiểu dữ liệu trả về của hàm và kiểu dữ liệu của các tham số nó có. Điều này giúp trình biên dịch biết cách gọi hàm và kiểm tra sự phù hợp của đối số và kiểu trả về.
// Hàm nguyên mẫu cho hàm sum
int sum(int a, int b);
int main() {
int x = 5;
int y = 3;
int result = sum(x, y); // Gọi hàm sum và lưu kết quả vào result
return 0;
}
// Định nghĩa hàm sum sau main hoặc trong một tệp mã nguồn khác
int sum(int a, int b) {
return a + b;
}
1.5 Chuỗi (String)
Trong C, chuỗi (string) thường được biểu diễn bằng một mảng các ký tự (char
). Mảng này chứa các ký tự liên tiếp kết thúc bằng một ký tự null ('\0'
) để xác định kết thúc của chuỗi. Dưới đây là cách bạn có thể định nghĩa, khai báo và làm việc với chuỗi trong C:
1.5.1 Định nghĩa chuỗi
Bạn có thể khai báo một mảng ký tự cố định để định nghĩa chuỗi. Độ dài của mảng cố định phải đủ lớn để chứa chuỗi và ký tự null cuối cùng. Ví dụ:
char myString[20] = "Hello, World!";
5.5.2 Làm việc với chuỗi
Có nhiều cách để thao tác và làm việc với chuỗi, dưới đây là một số cách:
- In chuỗi: Để hiển thị một chuỗi trong C lên màn hình chúng ta sẽ dùng kí hiệu
%s
- Sao chép chuỗi: Bạn có thể sử dụng hàm
strcpy
để sao chép một chuỗi vào một chuỗi khác. - Nối chuỗi: Để nối một chuỗi vào cuối chuỗi khác, bạn có thể sử dụng hàm
strcat
. - So sánh chuỗi: Hàm
strcmp
được sử dụng để so sánh hai chuỗi. - Tính độ dài chuỗi: Để tính độ dài của chuỗi, bạn có thể sử dụng hàm
strlen
.
char result = "Hello"
printf("Ket qua la %s", result);
char source[] = "Hello";
char destination[20];
strcpy(destination, source); // Sao chép chuỗi source vào chuỗi destination
char str1[] = "Hello";
char str2[] = ", World!";
strcat(str1, str2); // Kết quả: "Hello, World!"
char str1[] = "apple";
char str2[] = "banana";
int result = strcmp(str1, str2);
// Kết quả: result < 0 (str1 đứng trước str2 trong thứ tự từ điển)
char str[] = "Hello, World!";
int length = strlen(str); // Kết quả: 13
Lưu ý rằng chuỗi kết thúc bằng ký tự null '\0'
, nên khi bạn làm việc với chuỗi, hãy đảm bảo rằng bạn duyệt đến ký tự null để xác định kết thúc của chuỗi.
1.6 Mảng một chiều (Array)
Mảng (array) trong C là một tập hợp các phần tử có cùng kiểu dữ liệu được sắp xếp theo thứ tự. Mảng cho phép bạn lưu trữ nhiều giá trị cùng loại trong một biến duy nhất.
1.6.1 Định nghĩa và Khai báo Mảng
Để định nghĩa một mảng trong C, bạn cần chỉ định kiểu dữ liệu của các phần tử và kích thước của mảng (số lượng phần tử). Cú pháp tổng quan như sau:
kiểu_dữ_liệu tên_mảng[kích_thước];
kiểu_dữ_liệu
: Đây là kiểu dữ liệu của các phần tử trong mảng, ví dụint
,float
,char
, ...tên_mảng
: Đây là tên của mảng.kích_thước
: Số lượng phần tử trong mảng.
Ví dụ:
int numbers[5]; // Định nghĩa mảng numbers với 5 phần tử kiểu int
char letters[10]; // Định nghĩa mảng letters với 10 phần tử kiểu char
1.6.2 Truy cập phần tử trong Mảng
Bạn có thể truy cập các phần tử trong mảng bằng cách sử dụng chỉ mục (index) của phần tử trong dấu ngoặc vuông []
. Chỉ mục bắt đầu từ 0. Ví dụ:
int numbers[5] = {10, 20, 30, 40, 50};
int firstNumber = numbers[0]; // firstNumber = 10
int thirdNumber = numbers[2]; // thirdNumber = 30
1.7 Mảng hai chiều (2D Array)
Mảng hai chiều (2D array) trong ngôn ngữ lập trình C là một cấu trúc dữ liệu cho phép bạn lưu trữ dữ liệu dưới dạng ma trận hoặc lưới có hai chiều (hàng và cột).
1.7.1 Định nghĩa và Khai báo Mảng hai chiều
kiểu_dữ_liệu tên_mảng[số_hàng][số_cột];
kiểu_dữ_liệu
: Đây là kiểu dữ liệu của các phần tử trong mảng 2D, ví dụint
,float
,char
, ...tên_mảng
: Đây là tên của mảng.số_hàng
: Số lượng hàng trong mảng.số_cột
: Số lượng cột trong mảng.
Ví dụ:
int matrix[3][3]; // Định nghĩa mảng 2D với 3 hàng và 3 cột
float data[2][4]; // Định nghĩa mảng 2D với 2 hàng và 4 cột
1.7.2 Truy cập phần tử trong Mảng hai chiều
Bạn có thể truy cập các phần tử trong mảng 2D bằng cách sử dụng chỉ mục của hàng và cột trong dấu ngoặc vuông [][]
. Chỉ mục hàng và cột bắt đầu từ 0. Ví dụ:
int matrix[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
int element = matrix[1][2]; // element = 6
Mảng hai chiều thường được sử dụng để biểu diễn ma trận, hình ảnh, dữ liệu lưới và nhiều loại dữ liệu có cấu trúc tương tự.
1.8 Câu lệnh điều kiện (Conditional Statement)
1.8.1 Câu lệnh if...else
Câu lệnh if...else
cho phép bạn thực hiện một khối mã nguồn nếu điều kiện kiểm tra là đúng (true), và một khối mã nguồn khác nếu điều kiện là sai (false). Cú pháp tổng quan như sau:
if (điều_kiện) {
// Khối mã thực hiện nếu điều_kiện là true
} else {
// Khối mã thực hiện nếu điều_kiện là false
}
Ví dụ:
int x = 3;
printf("x lớn hơn 5.\n");
} else {
printf("x không lớn hơn 5.\n");
}
1.8.2 Câu lệnh if... elseif ...else
Câu lệnh if...else if...else
cho phép bạn kiểm tra nhiều điều kiện liên tiếp và thực hiện các khối mã nguồn tương ứng với điều kiện đúng đầu tiên. Cú pháp tổng quan như sau:
if (điều_kiện_1) {
// Khối mã thực hiện nếu điều_kiện_1 là true
} else if (điều_kiện_2) {
// Khối mã thực hiện nếu điều_kiện_2 là true
} else {
// Khối mã thực hiện nếu không có điều kiện nào là true
}
Ví dụ:
int x = 7;
if (x < 5) {
printf("x nhỏ hơn 5.\n");
} else if (x == 5) {
printf("x bằng 5.\n");
} else {
printf("x lớn hơn 5.\n");
}
1.8.3 Câu lệnh switch
Câu lệnh switch
cho phép bạn kiểm tra một biểu thức hoặc giá trị và thực hiện các tác vụ tương ứng với từng giá trị. Cú pháp tổng quan như sau:
switch (biểu_thức) {
case giá_trị_1:
// Khối mã thực hiện nếu biểu_thức bằng giá_trị_1
break;
case giá_trị_2:
// Khối mã thực hiện nếu biểu_thức bằng giá_trị_2
break;
// Các trường hợp khác
default:
// Khối mã thực hiện nếu không có trường hợp nào khớp
}
Ví dụ:
int choice = 2;
switch (choice) {
case 1:
printf("Bạn đã chọn tùy chọn 1.\n");
break;
case 2:
printf("Bạn đã chọn tùy chọn 2.\n");
break;
default:
printf("Tùy chọn không hợp lệ.\n");
}
1.9 Vòng lặp (Loop)
Trong ngôn ngữ lập trình C, có ba loại vòng lặp chính được sử dụng để lặp qua mã nguồn hoặc thực hiện các tác vụ lặp đi lặp lại. Các loại vòng lặp này là:
1.9.1 Vòng lặp for
Vòng lặp for được sử dụng để lặp qua một khối mã nguồn một số lần xác định. Cú pháp tổng quan như sau:
for (khởi_tạo; điều_kiện; cập_nhật) {
// Khối mã thực hiện trong mỗi vòng lặp
}
Ví dụ:
for (int i = 0; i < 5; i++) {
printf("Giá trị của i: %d\n", i);
}
1.9.2 Vòng lặp while
Vòng lặp while
được sử dụng để lặp qua một khối mã nguồn trong khi một điều kiện là đúng (true). Cú pháp tổng quan như sau:
while (điều_kiện) {
// Khối mã thực hiện trong mỗi vòng lặp
}
Ví dụ:
int x = 0;
while (x < 5) {
printf("Giá trị của x: %d\n", x);
x++;
}
1.9.3 Vòng lặp do...while
:
Vòng lặp do...while
tương tự với while
, nhưng khối mã trong vòng lặp được thực hiện ít nhất một lần trước khi kiểm tra điều kiện. Cú pháp tổng quan như sau:
do {
// Khối mã thực hiện ít nhất một lần
} while (điều_kiện);
Ví dụ:
int y = 0;
do {
printf("Giá trị của y: %d\n", y);
y++;
} while (y < 5);
1.9.4 Sự khác nhau giữa 3 loại vòng lặp
Sự khác nhau chính giữa ba vòng lặp chính trong ngôn ngữ lập trình C (for, while, và do...while) là cách chúng kiểm tra và điều khiển việc lặp. Dưới đây là sự khác nhau giữa chúng và trường hợp nào nên sử dụng mỗi loại vòng lặp:
Vòng lặp for | Vòng lặp while | Vòng lặp do...while | |
---|---|---|---|
Cú pháp | sử dụng một biểu thức khởi tạo, một biểu thức điều kiện, và một biểu thức cập nhật | sử dụng một biểu thức điều kiện | sử dụng một biểu thức điều kiện |
Thứ tự kiểm tra điều kiện | Đầu tiên kiểm tra điều kiện, sau đó thực hiện khối mã nếu điều kiện là true. Sau khi thực hiện khối mã, biểu thức cập nhật được thực hiện và sau đó kiểm tra lại điều kiện. | Đầu tiên kiểm tra điều kiện, sau đó thực hiện khối mã nếu điều kiện là true. Không thực hiện nếu điều kiện là false. | Thực hiện khối mã ít nhất một lần, sau đó kiểm tra điều kiện. Nếu điều kiện là true, thực hiện thêm vòng lặp. |
Thích hợp cho | Sử dụng khi bạn biết trước số lần lặp cụ thể hoặc cần thực hiện một số lần lặp cố định. | Sử dụng khi bạn không biết trước số lần lặp và muốn thực hiện lặp dựa trên điều kiện nào đó. | Sử dụng khi bạn muốn đảm bảo rằng khối mã ít nhất được thực hiện một lần, sau đó kiểm tra điều kiện để quyết định liệu cần tiếp tục lặp hay không. |
1.10 Struct (Cấu trúc)
Struct (cấu trúc) trong ngôn ngữ lập trình C là một cấu trúc dữ liệu cho phép bạn tổng hợp nhiều biến có kiểu dữ liệu khác nhau vào một đối tượng duy nhất. Cấu trúc giúp bạn tạo ra kiểu dữ liệu tùy chỉnh để biểu diễn các thực thể có tính chất phức tạp hơn. Dưới đây là cách bạn định nghĩa và làm việc với cấu trúc trong C:
1.10.1 Định nghĩa cấu trúc
Để định nghĩa cấu trúc trong C, bạn sử dụng từ khóa struct
theo sau là tên cấu trúc và danh sách các biến thành viên (members) trong cấu trúc. Cú pháp tổng quan như sau:
struct TenCauTruc {
kieu_du_lieu1 thanh_vien1;
kieu_du_lieu2 thanh_vien2;
// ...
};
Ví dụ:
struct Person {
char name[50];
int age;
float height;
};
1.10.2 Khai báo biến kiểu struct trong C
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.
struct Person
{
int id;
char firstName[20];
char lastName[20];
int age;
char address[100];
};
int main(){
struct Person ps1, ps2;
// Khai báo mảng
struct Person ps[100];
}
1.10.3 Truy xuất các thuộc tính của struct
C cung cấp cho chúng ta 2 toán tử để truy xuất các thuộc tính của struct:
- Sử dụng
.
=> Truy xuất tới thuộc tính khi khai báo biến bình thường. - Sử dụng
->
=> Truy xuất tới thuộc tính khi biến là con trỏ.
Ví dụ chúng ta muốn truy xuất đến thuộc tính firstName
của Person ta làm như sau:
Person ps;
printf("First name: %s", ps.firstName);
1.11 Enum (Liệt kê)
Enum (liệt kê) trong ngôn ngữ lập trình C là một cấu trúc dữ liệu cho phép bạn xác định một tập hợp các giá trị nguyên có tên. Thông thường, liệt kê được sử dụng để đặt tên cho các hằng số hoặc để tạo các biểu thức nguyên với ý nghĩa dễ đọc. Dưới đây là cách bạn định nghĩa và làm việc với liệt kê trong C:
1.11.1 Định nghĩa enum
Để định nghĩa enum trong C, bạn sử dụng từ khóa enum
sau đó là tên liệt kê và danh sách các giá trị liệt kê trong dấu ngoặc nhọn {}
. Ví dụ:
enum Season {
Spring,
Summer,
Autumn,
Winter
};
Trong ví dụ này, Season
là tên của liệt kê, và Spring
, Summer
, Autumn
, và Winter
là các giá trị liệt kê. Mặc định, giá trị của các trạng thái trong enum là các số nguyên liên tiếp, bắt đầu từ 0. Spring
có giá trị là 0, Summer
là 1, và tiếp tục như vậy.
1.11.2 Gán giá trị tùy chỉnh cho các trạng thái
Bạn có thể gán giá trị tùy chỉnh cho các trạng thái của enum bằng cách chỉ định giá trị sau mỗi trạng thái. Ví dụ:
enum Day {
Monday = 1,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
};
Trong ví dụ này, Monday
có giá trị là 1, và các giá trị tiếp theo sẽ được tự động tăng thêm một đơn vị (2, 3, 4,...).
1.11.3 Sử dụng enum
Sau khi bạn đã định nghĩa enum, bạn có thể sử dụng nó để khai báo biến hoặc trong các biểu thức. Ví dụ:
enum Season currentSeason = Spring;
Ngoài ra bạn có thể sử dụng enum làm tham số cho hàm để biểu thị trạng thái hoặc tùy chọn.
void printDay(enum Day day) {
switch (day) {
case Monday:
printf("Monday");
break;
case Tuesday:
printf("Tuesday");
break;
// ...
}
}
Enum giúp làm cho mã nguồn dễ đọc hơn và giúp tránh sử dụng các số nguyên cứng.
1.12 Thư viện (Library)
Trong ngôn ngữ lập trình C, thư viện (library) là một tập hợp các tệp và hàm được biên dịch sẵn (compiled) mà bạn có thể sử dụng trong các chương trình của mình. Thư viện giúp tái sử dụng mã nguồn, giảm độ phức tạp của chương trình, và tăng hiệu suất trong quá trình phát triển phần mềm. Dưới đây là một số điểm quan trọng về thư viện trong ngôn ngữ C:
- Thư viện tiêu chuẩn (Standard Library): C có một thư viện tiêu chuẩn chứa các hàm và tệp thư viện đã được định nghĩa trước để thực hiện các nhiệm vụ phổ biến. Ví dụ, thư viện
stdio.h
chứa hàm liên quan đến đầu vào và đầu ra, nhưprintf
,scanf
, vàfgets
. Thư viện tiêu chuẩn được cung cấp bởi ngôn ngữ C và có sẵn cho mọi trình biên dịch C. - Thư viện bên ngoài (External Libraries): Bên cạnh thư viện tiêu chuẩn, có nhiều thư viện bên ngoài được tạo ra bởi cộng đồng lập trình C và các nhà sản xuất trình biên dịch. Những thư viện này cung cấp các tính năng đặc biệt và phức tạp hơn cho việc phát triển ứng dụng. Để sử dụng thư viện bên ngoài, bạn cần bao gồm tiêu đề (header) thư viện trong mã nguồn của mình và liên kết (link) với tệp thư viện khi biên dịch.
- Tiêu đề (Header Files): Tiêu đề (header) là tệp văn bản có phần mở rộng
.h
chứa các khai báo hàm, cấu trúc dữ liệu và hằng số mà bạn cần sử dụng từ một thư viện. Để sử dụng thư viện, bạn cần đưa tiêu đề của nó vào mã nguồn của mình bằng cách sử dụng#include
. Ví dụ:#include
. - Liên kết (Linking): Sau khi bạn đã sử dụng các hàm từ thư viện trong mã nguồn của mình, bạn cần liên kết mã nguồn với thư viện khi biên dịch. Điều này đảm bảo rằng trình biên dịch biết nơi tìm các định nghĩa hàm cụ thể. Thông thường, việc liên kết được thực hiện bằng cách sử dụng câu lệnh liên kết hoặc trình biên dịch.
- Tạo thư viện tùy chỉnh (Custom Libraries): Bạn cũng có thể tạo thư viện tùy chỉnh để đóng gói và tái sử dụng mã nguồn của mình. Điều này đặc biệt hữu ích khi bạn muốn chia sẻ mã nguồn với các dự án khác hoặc đảm bảo tính riêng tư và bảo mật của mã nguồn.
Thư viện đóng một vai trò quan trọng trong việc phát triển ứng dụng C và giúp tối ưu hóa quá trình phát triển phần mềm bằng cách sử dụng lại mã nguồn đã có sẵn.
1.13 Con trỏ (Pointer)
Con trỏ (Pointer) trong ngôn ngữ lập trình C là một biến đặc biệt được sử dụng để lưu trữ địa chỉ bộ nhớ của một biến khác. Con trỏ cho phép bạn truy cập và thao tác trực tiếp với bộ nhớ và dữ liệu, và nó là một trong những tính năng quan trọng của C. Dưới đây là các khái niệm và cách sử dụng con trỏ trong C:
Khai báo con trỏ
Để khai báo một con trỏ, bạn sử dụng dấu *
sau kiểu dữ liệu. Ví dụ:
int *ptr; // Con trỏ kiểu int
double *ptr2; // Con trỏ kiểu double
Gán giá trị cho con trỏ
Con trỏ có thể được gán bất kỳ địa chỉ của biến nào cùng kiểu dữ liệu với nó. Điều này được thực hiện bằng cách sử dụng toán tử &
để lấy địa chỉ của biến. Ví dụ:
int x = 10;
int *ptr = &x; // Gán địa chỉ của biến x cho con trỏ ptr
Truy cập giá trị của con trỏ
Để truy cập giá trị mà con trỏ đang trỏ đến, bạn sử dụng toán tử *
. Ví dụ:
int y = *ptr; // Lấy giá trị mà con trỏ ptr đang trỏ đến (giá trị của biến x)
Sử dụng con trỏ để thay đổi giá trị biến
Con trỏ cho phép bạn thay đổi giá trị của biến mà nó đang trỏ đến. Ví dụ:
*ptr = 20; // Thay đổi giá trị của biến x thành 20
Thực hiện các phép tính với con trỏ
Bạn có thể thực hiện các phép tính số học và logic với con trỏ để di chuyển giữa các địa chỉ bộ nhớ và thực hiện các phép tính trên dữ liệu. Ví dụ:
int arr[5] = {10, 20, 30, 40, 50};
int *ptr = arr; // Gán địa chỉ của mảng cho con trỏ
// Di chuyển con trỏ qua các phần tử mảng và in giá trị
for (int i = 0; i < 5; i++) {
printf("Gia tri cua phan tu thu %d: %d\n", i, *ptr);
ptr++; // Di chuyen con tro toi phan tu tiep theo
}
Con trỏ và mảng
Mảng và con trỏ trong C có mối quan hệ mật thiết. Tên mảng một cách tường minh là một con trỏ tới phần tử đầu tiên trong mảng, và bạn có thể sử dụng con trỏ để truy cập các phần tử của mảng.
Dưới đây là một ví dụ về cách sử dụng con trỏ và mảng trong ngôn ngữ lập trình C. Trong ví dụ này, chúng ta sẽ tạo một mảng các số nguyên và sử dụng một con trỏ để truy cập các phần tử của mảng.
#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
// Khai báo một con trỏ kiểu int và gán địa chỉ của mảng cho nó
int *ptr = arr;
// Sử dụng con trỏ để truy cập và in các phần tử của mảng
for (int i = 0; i < 5; i++) {
printf("Gia tri cua phan tu thu %d: %d\n", i, *ptr);
ptr++; // Di chuyển con trỏ tới phần tử tiếp theo trong mảng
}
return 0;
}
- Chúng ta đã khai báo một mảng
arr
có 5 phần tử và khởi tạo nó với các giá trị từ 10 đến 50. - Sau đó, chúng ta đã khai báo một con trỏ kiểu
int
có tênptr
. - Chúng ta gán địa chỉ của mảng
arr
cho con trỏptr
bằng cách sử dụng tên mảng làm con trỏ vào phần tử đầu tiên của mảng. - Trong vòng lặp
for
, chúng ta sử dụng con trỏ để truy cập và in giá trị của từng phần tử của mảng. Sau đó, chúng ta di chuyển con trỏ tới phần tử tiếp theo trong mảng bằng cách sử dụngptr++
.
Kết quả của chương trình sẽ in ra giá trị của các phần tử trong mảng:
Gia tri cua phan tu thu 0: 10
Gia tri cua phan tu thu 1: 20
Gia tri cua phan tu thu 2: 30
Gia tri cua phan tu thu 3: 40
Gia tri cua phan tu thu 4: 50
Con trỏ và chuỗi
Chuỗi trong C thường được biểu diễn bằng một mảng các ký tự và kết thúc bằng ký tự null ('\0'
). Con trỏ thường được sử dụng để xử lý chuỗi, vì chúng cho phép bạn truy cập và thay đổi từng ký tự trong chuỗi một cách dễ dàng.
Dưới đây là một ví dụ về cách sử dụng con trỏ để làm việc với chuỗi (string) trong ngôn ngữ lập trình C:
#include <stdio.h>
int main() {
char greeting[] = "Hello, World!"; // Một mảng ký tự (chuỗi)
char *ptr = greeting; // Con trỏ kiểu char trỏ tới chuỗi
// Sử dụng con trỏ để truy cập và in từng ký tự của chuỗi
while (*ptr != '\0') {
printf("%c", *ptr);
ptr++; // Di chuyển con trỏ tới ký tự tiếp theo
}
return 0;
}
- Chúng ta đã khai báo một mảng ký tự có tên
greeting
và khởi tạo nó với chuỗi "Hello, World!". - Sau đó, chúng ta đã khai báo một con trỏ kiểu
char
có tênptr
. - Chúng ta gán địa chỉ của mảng
greeting
cho con trỏptr
, vì mảng là một chuỗi ký tự và tên mảng chính là con trỏ tới phần tử đầu tiên của chuỗi. - Sử dụng vòng lặp
while
, chúng ta duyệt qua chuỗi bằng cách sử dụng con trỏ. Chúng ta kiểm tra ký tự mỗi lần và in nó ra màn hình, sau đó di chuyển con trỏ tới ký tự tiếp theo trong chuỗi bằng cách sử dụngptr++
. - Chuỗi kết thúc bằng ký tự null
'\0'
, nên chúng ta dừng khi gặp ký tự null.
Kết quả của chương trình sẽ in ra chuỗi "Hello, World!" lên màn hình.
Con trỏ là một tính năng mạnh mẽ trong ngôn ngữ C, nhưng nó cũng đòi hỏi kiểm soát cẩn thận và làm việc chính xác với bộ nhớ để tránh lỗi segmentation fault và rò rỉ bộ nhớ.
1.14 File I/O (Input/Output)
File I/O (Input/Output) trong ngôn ngữ lập trình C là quá trình đọc và ghi dữ liệu từ và vào các tệp (file). Các tệp được sử dụng để lưu trữ và truyền dữ liệu giữa chương trình và hệ thống tệp. Dưới đây là một số ví dụ về cách thực hiện File I/O trong C:
Ghi dữ liệu vào tệp
Để ghi dữ liệu vào một tệp, bạn cần mở tệp để ghi bằng cách sử dụng hàm fopen()
. Sau đó, bạn có thể sử dụng các hàm như fprintf()
hoặc fputc()
để ghi dữ liệu vào tệp. Ví dụ:
#include <stdio.h>
int main() {
FILE *file;
file = fopen("example.txt", "w"); // Mở tệp để ghi
if (file != NULL) {
fprintf(file, "Hello, World!\n");
fclose(file);
} else {
printf("Khong the mo tệp.\n");
}
return 0;
}
Trong ví dụ này, chúng ta mở tệp "example.txt" để ghi (mode "w" - viết tắt của write). Sau đó, chúng ta sử dụng fprintf()
để ghi chuỗi "Hello, World!" vào tệp và đóng tệp sau khi đã hoàn thành.
Đọc dữ liệu từ tệp
Để đọc dữ liệu từ một tệp, bạn cũng cần mở tệp nhưng trong mode đọc bằng fopen()
. Sau đó, bạn có thể sử dụng các hàm như fscanf()
hoặc fgetc()
để đọc dữ liệu từ tệp. Ví dụ:
#include <stdio.h>
int main() {
FILE *file;
char data[100]; // Mảng để lưu dữ liệu từ tệp
file = fopen("example.txt", "r"); // Mở tệp để đọc
if (file != NULL) {
fscanf(file, "%s", data); // Đọc dữ liệu từ tệp vào mảng
printf("Noi dung trong tệp: %s\n", data);
fclose(file);
} else {
printf("Khong the mo tệp.\n");
}
return 0;
}
Trong ví dụ này, chúng ta mở tệp "example.txt" để đọc (mode "r" - viết tắt của read). Sau đó, chúng ta sử dụng fscanf()
để đọc dữ liệu từ tệp vào mảng data
và in ra nội dung đã đọc.
File I/O trong C là một phần quan trọng của việc làm việc với tệp và dữ liệu trên hệ thống tệp. Nó cho phép bạn lưu trữ, đọc, và xử lý dữ liệu từ và vào các tệp theo nhiều cách khác nhau.
2. Tài liệu học ngôn ngữ C
Hiện nay có rất nhiều tài liệu để học ngôn ngữ C, mình có các gợi ý sau đây các bạn có thể tham khảo:
- Sách K&R C: "The C Programming Language" của Brian Kernighan và Dennis Ritchie (K&R C) là một trong những tài liệu cơ bản nhất cho ngôn ngữ C. Cuốn sách này giúp bạn nắm vững cú pháp cơ bản và cách sử dụng C một cách hiệu quả.
- Sách C Programming Absolute Beginner's Guide: Cuốn sách này của Perry và Miller cung cấp một cách tiếp cận dễ hiểu cho người mới học lập trình C. Nó bao gồm nhiều ví dụ thực tế và dự án để thực hành.
- Learn-C.org: Trang web này cung cấp một khóa học trực tuyến miễn phí về ngôn ngữ C. Nó bao gồm các bài giảng và bài tập để bạn thử nghiệm kiến thức.
- GeeksforGeeks C Programming: GeeksforGeeks cung cấp nhiều bài hướng dẫn, ví dụ và bài tập về lập trình C. Đây là nguồn tài liệu tốt để rèn luyện kỹ năng lập trình C.
Nếu quan tâm đến những bài viết khác tại 200Lab, nhớ bấm theo dõi blog 200Lab bạn nhé. Ngoài ra bạn có thể xem các bài viết liên quan đến các ngôn ngữ lập trình khác: