Lập Trình C Từ Cơ Bản Đến Ứng Dụng Thực Tế
Published: 2023-08-03 03:41:24

**Lịch Sử của Ngôn Ngữ Lập Trình C**

Ngôn ngữ lập trình C được phát triển vào những năm 1970 tại Bell Labs bởi Dennis Ritchie. Ban đầu, nó được tạo ra để phục vụ cho mục đích xây dựng hệ điều hành UNIX. Vào năm 1972, Dennis Ritchie và Ken Thompson viết lại hệ điều hành UNIX bằng ngôn ngữ C, giúp tăng tính di động và dễ mở rộng của hệ điều hành. Ngôn ngữ C nhanh chóng trở thành một công cụ mạnh mẽ để phát triển hệ điều hành và phần mềm hệ thống.

Các ưu điểm của C như hiệu năng cao, cú pháp đơn giản, tính di động và khả năng tiếp cận phần cứng khiến nó trở thành một trong những ngôn ngữ lập trình phổ biến và ảnh hưởng mạnh mẽ trong lịch sử công nghiệp phần mềm.

**Tỉ lệ sử dụng của Ngôn Ngữ C trên Thế Giới**

Mặc dù ngôn ngữ C đã tồn tại hơn 40 năm, nó vẫn đang được sử dụng rộng rãi và duy trì sức hấp dẫn trong cộng đồng lập trình. Tỉ lệ sử dụng của ngôn ngữ C vẫn khá cao do những ưu điểm vượt trội sau:

1. **Hiệu năng cao**: Có khả năng gần với mã máy và tiếp cận trực tiếp phần cứng, giúp tối ưu hóa hiệu suất của chương trình.

2. **Khả năng di động**: Có thể chạy trên nhiều nền tảng khác nhau, từ vi điều khiển nhúng đến máy tính cá nhân và máy chủ.

3. **Phổ biến trong lĩnh vực nhúng**: C được sử dụng rộng rãi trong việc phát triển các hệ thống nhúng, điều khiển công nghiệp, điện tử tiêu dùng và ô tô.

4. **Kho tàng mã nguồn mở**: Có rất nhiều thư viện mã nguồn mở và mã nguồn mở được viết bằng C, giúp cộng đồng lập trình viên chia sẻ và tái sử dụng mã một cách dễ dàng.

5. **Tích hợp trong hệ thống học tập**: C là một trong những ngôn ngữ phổ biến được giảng dạy trong các chương trình đào tạo và khoá học lập trình.

Mặc dù ngôn ngữ C vẫn còn rất phổ biến và đóng vai trò quan trọng trong nhiều lĩnh vực, nhưng cũng có xu hướng phát triển các ngôn ngữ lập trình mới như Python, JavaScript, và Java, đặc biệt trong các ứng dụng web và trí tuệ nhân tạo. Tuy nhiên, C vẫn được coi là một trong những ngôn ngữ cơ bản và quan trọng nhất trong lập trình, và nó vẫn tiếp tục được sử dụng rộng rãi trên toàn thế giới.

Để bắt đầu với ngôn ngữ lập trình, tất cả chúng ta phải đi qua các bước tìm hiểu như sau: 

- Các từ khoá
- Biến
- Hàm
- Kiểu dữ liệu 
- Cấu trúc điều kiện, rẽ nhánh
- Cấu trúc lặp
- Thư viện chuẩn
- Thư viện mở rộng

**1. Từ Khoá:**

Trong ngôn ngữ lập trình C, có một số từ khoá (keywords) được sử dụng để định nghĩa các thành phần trong chương trình. Một số từ khoá quan trọng như `int`, `float`, `char`, `if`, `else`, `for`, `while`, `return`, và nhiều từ khoá khác.

**2. Biến:**

Biến là một vị trí trong bộ nhớ dùng để lưu trữ giá trị dữ liệu. Trong C, bạn phải khai báo biến trước khi sử dụng nó. Ví dụ:

```c
int age; // Khai báo một biến kiểu số nguyên
float salary; // Khai báo một biến kiểu số thực
char initial; // Khai báo một biến kiểu ký tự
```

**3. Hàm:**

Hàm là một khối mã thực hiện một tác vụ cụ thể và có thể được gọi từ các phần khác của chương trình. Một chương trình C bao gồm ít nhất một hàm chính (`main()`) để bắt đầu thực hiện.

```c
#include <stdio.h>

// Hàm chính (main) của chương trình
int main() {
    // Gọi hàm printf để in ra màn hình
    printf("Hello World!\n");
    return 0;
}
```
Tất nhiên, dưới đây là các ví dụ cụ thể với giải thích chi tiết cho người chưa học lập trình bao giờ.

**Ví dụ kết hợp Biến và Hàm:**

```c
#include <stdio.h>

// Hàm tính tổng của hai số nguyên
int sum(int a, int b) {
    int result = a + b; // Khai báo và tính toán biến "result"
    return result; // Trả về giá trị của biến "result"
}

int main() {
    int num1 = 5; // Khai báo biến num1 có giá trị 5
    int num2 = 3; // Khai báo biến num2 có giá trị 3

    int total = sum(num1, num2); // Gọi hàm sum để tính tổng của num1 và num2
    printf("Tổng của %d và %d là %d\n", num1, num2, total); // In ra kết quả

    return 0;
}
```

**Giải thích**: Trong ví dụ này, chúng ta định nghĩa một hàm `sum()` để tính tổng của hai số nguyên. Trong hàm `main()`, chúng ta khai báo và gán giá trị cho hai biến `num1` và `num2`. Sau đó, chúng ta gọi hàm `sum()` và truyền `num1` và `num2` vào để tính tổng. Kết quả được lưu vào biến `total` và in ra màn hình bằng hàm `printf()`.


**4. Kiểu Dữ Liệu Cơ Bản:**

Các kiểu dữ liệu cơ bản trong C bao gồm:
- `int`: kiểu số nguyên.
- `float`: kiểu số thực.
- `char`: kiểu ký tự.

**5. Kiểu Dữ Liệu Tham Chiếu:**

Trong C, ta có thể truyền địa chỉ của biến (tham chiếu) vào hàm thay vì giá trị. Điều này được thực hiện bằng việc sử dụng con trỏ. Tham chiếu cho phép chúng ta thay đổi giá trị của biến bên ngoài hàm.

**6. Kiểu Dữ Liệu Cấu Trúc:**

Kiểu dữ liệu cấu trúc cho phép lưu trữ nhiều kiểu dữ liệu khác nhau trong một biến duy nhất. Đây là một cách tiện lợi để tạo các loại dữ liệu tùy chỉnh trong C.

```c
// Kiểu dữ liệu cấu trúc "Person" có tên và tuổi
struct Person {
    char name[50];
    int age;
};
```

**7. Con Trỏ:**

Con trỏ là một biến đặc biệt chứa địa chỉ của một biến khác. Con trỏ cho phép chúng ta truy cập và thay đổi giá trị của biến bằng cách tham chiếu đến địa chỉ của nó.

```c
int number = 10;
int *ptr; // Khai báo một con trỏ kiểu số nguyên

ptr = &number; // Gán địa chỉ của biến "number" vào con trỏ "ptr"

printf("Giá trị của biến number: %d\n", *ptr); // In ra giá trị của biến bằng con trỏ
```

**8. Cấu trúc Điều Kiện:**

Cấu trúc điều kiện trong C cho phép kiểm tra một điều kiện và thực hiện các hành động khác nhau dựa trên kết quả của điều kiện đó.

```c
int number = 5;
if (number > 0) {
    printf("Số dương\n");
} else if (number < 0) {
    printf("Số âm\n");
} else {
    printf("Số không\n");
}
```
**Ví dụ về Cấu Trúc Điều Kiện:**

```c
#include <stdio.h>

int main() {
    int age;

    printf("Nhập tuổi của bạn: ");
    scanf("%d", &age); // Đọc giá trị nhập vào và lưu vào biến "age"

    if (age >= 18) {
        printf("Bạn đã đủ tuổi trưởng thành.\n");
    } else {
        printf("Bạn chưa đủ tuổi trưởng thành.\n");
    }

    return 0;
}
```

**Giải thích**: Trong ví dụ này, chúng ta sử dụng cấu trúc điều kiện (`if...else`) để kiểm tra tuổi của người dùng. Chúng ta sử dụng hàm `scanf()` để đọc giá trị người dùng nhập vào và lưu vào biến `age`. Sau đó, chúng ta kiểm tra xem nếu `age` lớn hơn hoặc bằng 18, thì in ra thông báo "Bạn đã đủ tuổi trưởng thành." Nếu không, in ra thông báo "Bạn chưa đủ tuổi trưởng thành."


**9. Cấu Trúc Rẽ Nhánh:**

Cấu trúc rẽ nhánh cho phép lựa chọn một trong nhiều khối mã thực hiện tùy thuộc vào giá trị của biến hoặc điều kiện.

```c
int day = 3;
switch (day) {
    case 1:
        printf("Thứ hai\n");
        break;
    case 2:
        printf("Thứ ba\n");
        break;
    // ...
    default:
        printf("Không phải thứ hai hoặc thứ ba\n");
}
```


**10. Cấu Trúc Lặp:**

Cấu trúc lặp trong C cho phép thực hiện một khối mã lặp lại nhiều lần, tùy thuộc vào điều kiện.

```c
int i;
for (i = 0; i < 5; i++) {
    printf("%d ", i);
}
// Output: 0 1 2 3 4

while (i > 0) {
    printf("%d ", i);
    i--;
}
// Output: 4 3 2 1
```
**Ví dụ về Cấu Trúc Lặp (Vòng lặp):**

```c
#include <stdio.h>

int main() {
    int i;

    printf("Các số từ 1 đến 5: ");
    for (i = 1; i <= 5; i++) {
        printf("%d ", i); // In ra các số từ 1 đến 5
    }
    printf("\n");

    return 0;
}
```

**Giải thích**: Trong ví dụ này, chúng ta sử dụng vòng lặp `for` để in ra các số từ 1 đến 5. Biến `i` được khai báo trong phần khởi tạo của vòng lặp và sẽ tăng giá trị từ 1 đến 5 sau mỗi lần lặp. Hàm `printf()` được sử dụng để in ra các số trên cùng một dòng.

**11. Thư Viện Vào/Ra Chuẩn:**

Trong C, chúng ta sử dụng thư viện vào/ra chuẩn (standard input/output) để tương tác với người dùng và máy tính.

```c
#include <stdio.h>

int main() {
    char name[50];
    printf("Nhập tên của bạn: ");
    scanf("%s", name);
    printf("Xin chào, %s!\n", name);
    return 0;
}
```

**12. Các Thư Viện Hỗ Trợ Khác:**

Ngoài thư viện vào/ra chuẩn, C còn hỗ trợ nhiều thư viện khác như thư viện math (`<math.h>`) cho các phép toán số học, thư viện thời

 gian (`<time.h>`) cho xử lý thời gian, và nhiều thư viện khác giúp giải quyết các vấn đề cụ thể.

**13. Ứng Dụng Thực Tế của Ngôn Ngữ Lập Trình C:**

- Phát triển các ứng dụng máy tính.
- Xây dựng hệ điều hành.
- Lập trình nhúng trong vi điều khiển và thiết bị nhúng.
- Phát triển các ứng dụng trò chơi.
- Viết phần mềm ứng dụng kỹ thuật và khoa học.
- Xây dựng các hệ thống nhúng trong ô tô và thiết bị y tế.

**14. So sánh Ngôn Ngữ Lập Trình C và Java:**
**So sánh Ngôn ngữ C với Java**

C và Java là hai ngôn ngữ lập trình phổ biến và có ứng dụng rộng rãi trong ngành công nghiệp phần mềm. Dưới đây là một số điểm so sánh giữa hai ngôn ngữ này:

1. **Độ phổ biến và Ứng dụng:**
   - C: C được phát triển từ những năm đầu của máy tính và vẫn rất phổ biến trong lĩnh vực nhúng, hệ thống nhúng và phát triển hệ thống. Nó phù hợp cho việc làm sâu vào phần cứng và hiệu năng cao.
   - Java: Java được phát triển vào những năm 1990 và trở thành một trong những ngôn ngữ phổ biến nhất trong phát triển ứng dụng, đặc biệt trong các ứng dụng web, di động và đám mây.

2. **Kiểu dữ liệu và Quản lý bộ nhớ:**
   - C: Cung cấp kiểu dữ liệu nguyên thuỷ (int, float, char) và con trỏ để quản lý bộ nhớ. Lập trình viên phải tự quản lý bộ nhớ, điều này dễ dẫn đến lỗi như tràn bộ nhớ (buffer overflow) hoặc lỗi trỏ sai (dangling pointer).
   - Java: Cung cấp hỗ trợ đầy đủ cho quản lý bộ nhớ tự động (garbage collection). Không có con trỏ, do đó ít khả năng gặp lỗi liên quan đến quản lý bộ nhớ.

3. **Khả năng di động và di chuyển:**
   - C: Có thể biên dịch và chạy trên nhiều nền tảng, nhưng yêu cầu biên dịch riêng cho từng hệ điều hành hoặc chip xử lý cụ thể.
   - Java: Được biên dịch thành mã bytecode, giúp chương trình chạy trên nhiều nền tảng mà không cần biên dịch lại. Java Virtual Machine (JVM) giúp đảm bảo tính di động của ứng dụng Java.

4. **Hiệu năng:**
   - C: Hiệu năng cao hơn, gần với mã máy và cho phép truy cập trực tiếp vào phần cứng.
   - Java: Tích hợp JVM khiến hiệu năng của Java chậm hơn so với C, nhưng sự tiện lợi và tích hợp đa nền tảng thường được đánh giá cao hơn.

5. **Độ phức tạp của ngôn ngữ:**
   - C: Ngôn ngữ đơn giản với ít từ khoá và cú pháp đơn giản.
   - Java: Ngôn ngữ phức tạp hơn, có nhiều tính năng và thư viện hỗ trợ.

**Lợi thế khi chuyển từ C sang Java:**

1. **Quản lý bộ nhớ dễ dàng:** Trong Java, không cần phải lo lắng về việc quản lý bộ nhớ như C, nhờ có garbage collection. Điều này giúp giảm thiểu rủi ro gặp lỗi liên quan đến bộ nhớ.

2. **Đa nền tảng và di động:** Java cho phép xây dựng ứng dụng một lần và chạy trên nhiều nền tảng, giúp tiết kiệm thời gian và công sức.

3. **Hỗ trợ mạnh mẽ từ cộng đồng:** Java có cộng đồng lập trình viên rộng lớn, điều này giúp bạn tìm kiếm và sử dụng các thư viện hỗ trợ một cách dễ dàng.

4. **An toàn và bảo mật:** Với JVM và cơ chế kiểm soát bộ nhớ, Java hỗ trợ bảo mật cao khi muốn thao tác sang hệ thống cần quản lý qua máy ảo.

5. **Điểm tương đồng giữa `struct` object:** 

5.1. **Định nghĩa dữ liệu tùy chỉnh:** Cả `struct` trong C và Java object đều cho phép định nghĩa các kiểu dữ liệu tùy chỉnh, tự định nghĩa các thành phần và thuộc tính mà mỗi đối tượng cần lưu trữ.

5.2. **Lưu trữ nhiều dữ liệu liên quan:** Cả `struct` và Java object cho phép bạn lưu trữ nhiều dữ liệu liên quan nhau thành một đơn vị duy nhất. Điều này giúp quản lý dữ liệu và tổ chức mã dễ dàng hơn.

5.3. **Tính đóng gói và ẩn thông tin:** Cả `struct` trong C và Java object đều hỗ trợ tính đóng gói và ẩn thông tin. Trong Java, bạn có thể sử dụng các phạm vi truy cập (public, private, protected) để quản lý quyền truy cập đối tượng. Trong C, thông tin trong `struct` mặc định là public, nhưng bạn có thể sử dụng các kỹ thuật để giới hạn quyền truy cập.

6. **Khác nhau giữa `struct` trong C và Java object:**

6.1. **Hướng đối tượng (OOP):** Trong Java, object là một thể hiện của một lớp, và nó thường được sử dụng trong hướng đối tượng (OOP). Java object có khả năng kế thừa, đa hình và đóng gói. Trong khi đó, `struct` trong C không hỗ trợ các tính năng OOP này.

6.2. **Phương thức và thuộc tính:** Trong Java, object có thể có các phương thức và thuộc tính riêng, trong khi `struct` trong C chỉ định nghĩa các thành phần dữ liệu (data members) mà không thể có phương thức.

Vì vậy, điểm tương đồng giữa `struct` trong C và Java object là cả hai đều dùng để định nghĩa kiểu dữ liệu tùy chỉnh và lưu trữ nhiều dữ liệu liên quan. Tuy nhiên, điểm khác nhau là Java object được sử dụng trong hướng đối tượng và hỗ trợ tính đóng gói, kế thừa và đa hình, trong khi `struct` trong C chỉ đơn thuần là một cấu trúc dữ liệu không hỗ trợ OOP.

> Lập trình C là một trong những ngôn ngữ cơ bản và quan trọng nhất trong lịch sử lập trình máy tính, và nó vẫn được sử dụng rộng rãi trong nhiều lĩnh vực công nghiệp và công việc hiện nay. Nó cũng có thể coi là ngôn ngữ lập trình cơ sở để chúng ta tiếp cận với lập trình và học lên các ngôn ngữ bậc cao hơn.

> còn tiếp ...