Để xây dựng những chương trình lớn và phức tạp, chúng ta không thể viết tất cả mã nguồn trong một khối lệnh duy nhất. Việc chia nhỏ mã nguồn thành các Hàm, tổ chức dữ liệu bằng Mảng và xử lý văn bản bằng Chuỗi là những kỹ năng sống còn của một lập trình viên. Bài học này sẽ giúp bạn làm chủ các công cụ đó.
🎯 Mục tiêu học tập
- Hiểu cách định nghĩa hàm và phân biệt 4 loại hàm cơ bản.
- Phân biệt sự khác nhau giữa truyền tham chiếu (Pass by reference) và truyền tham trị (Pass by value).
- Nắm vững cách khởi tạo, truy xuất mảng 1 chiều, 2 chiều và chuỗi ký tự.
- Biết cách xử lý các hàm toán học và hàm xử lý chuỗi thông dụng.
1. Hàm (Functions) – Đóng gói logic chương trình
Hàm là một khối mã thực hiện một nhiệm vụ cụ thể, giúp tái sử dụng mã nguồn và làm chương trình trở nên trong sáng hơn. Ngay cả main() cũng là một hàm đặc biệt – điểm bắt đầu của mọi chương trình C.
Các loại hàm thường gặp
Tùy vào nhu cầu về tham số và kết quả trả về, chúng ta có 4 dạng hàm chính:
- Không tham số, không giá trị trả về: Dùng để in thông tin đơn giản.
- Có trả về giá trị: Dùng để tính toán và lấy kết quả.
- Có tham số: Dùng để xử lý dữ liệu đầu vào linh hoạt.
Truyền Tham chiếu vs. Truyền Tham trị
Đây là khái niệm cực kỳ quan trọng ảnh hưởng đến cách dữ liệu được cập nhật trong bộ nhớ:
- Truyền tham trị (Pass by Value): Hàm tạo ra một bản sao của biến. Mọi thay đổi trong hàm không ảnh hưởng đến biến ban đầu.
- Truyền tham chiếu (Pass by Reference): Truyền địa chỉ của biến vào hàm thông qua con trỏ. Thay đổi trong hàm sẽ cập nhật trực tiếp vào giá trị gốc.
// Ví dụ Truyền tham chiếu để giảm giá trị
void giam1donvi(int *num) {
*num = *num - 1;
}
// Khi gọi: giam1donvi(&x); -> x sẽ bị thay đổi thực sự.
Đệ quy và Bộ nhớ Stack
Đệ quy là kỹ thuật một hàm tự gọi lại chính nó. Tuy nhiên, cần lưu ý Phần cơ sở (điểm dừng) để tránh lỗi tràn bộ nhớ Stack (Stack Overflow) do nguyên lý LIFO (Last In – First Out) của bộ nhớ này.

Bộ nhớ Stack
2. Mảng (Arrays) – Tổ chức dữ liệu tuần tự
Mảng là tập hợp các phần tử có cùng kiểu dữ liệu, nằm liên tục nhau trong bộ nhớ. Các phần tử được truy cập qua “chỉ số” (Index) bắt đầu từ 0 đến N-1.
Mảng một chiều
Khai báo mảng cần xác định rõ số lượng phần tử để Compiler cấp phát bộ nhớ chính xác:
int mang[5] = {9, 5, 6, 7, 2}; // Mảng 5 số nguyên
char ky_tu[] = {'A', 'B', 'C'}; // Compiler tự tính kích thước
Lưu ý: Khi truyền mảng vào hàm, thực chất chúng ta đang truyền địa chỉ của phần tử đầu tiên &mang[0]. Do đó, mảng luôn được truyền theo kiểu tham chiếu.

Truyền mảng và trả về mảng từ hàm
Mảng hai chiều
Được hiểu như một bảng gồm các hàng và cột. Thường dùng để quản lý ma trận hoặc các bảng dữ liệu trong hệ thống.
int matrix[3][4]; // 3 hàng, 4 cột
3. Chuỗi ký tự (Strings)
Trong C, chuỗi thực chất là một mảng kiểu char được kết thúc bởi ký tự đặc biệt \0 (null terminator).
Lưu ý khi nhập xuất chuỗi
scanf("%s", name);: Không đọc được chuỗi có dấu cách (space).
fgets(name, sizeof(name), stdin);: Cách an toàn hơn để đọc cả dòng văn bản.
- Xóa bộ nhớ đệm: Khi chuyển từ nhập số sang nhập chuỗi, hãy sử dụng
fflush(stdin) hoặc getchar() để tránh bị trôi lệnh nhập do ký tự \n còn sót lại.
Các hàm thư viện hữu ích
Sử dụng #include để truy cập các công cụ mạnh mẽ:
strlen(): Lấy độ dài thực tế của chuỗi.
strcpy(): Sao chép nội dung chuỗi.
strcmp(): So sánh hai chuỗi theo thứ tự từ điển.
strcat(): Nối chuỗi này vào sau chuỗi kia.
✍️ Bài tập về nhà
Nhập vào một số nguyên x (1 <= x <= 100,000):
- Kiểm tra x có phải là số nguyên tố không?
- In ra tất cả các số nguyên tố nhỏ hơn x.
- Nâng cao: Thực hiện bằng nhiều cách và so sánh thời gian thực thi (hiệu năng).
📝 Tóm tắt: Hàm giúp module hóa mã nguồn, Mảng giúp lưu trữ dữ liệu lớn, và Chuỗi giúp tương tác văn bản. Hiểu rõ cách bộ nhớ Stack hoạt động với hàm và cách chỉ số mảng vận hành là chìa khóa để bạn tối ưu chương trình nhúng.
Gợi ý bài tiếp theo: Con trỏ (Pointer) và Quy ước trình bày chương trình. Đây là phần kiến thức “khó nhằn” nhất nhưng cũng thú vị nhất trong C!
Người thực hiện: Nguyễn Đình Tuấn
Email: tuannguyen.aiot@gmail.com | Website: aiots.vn