Bài 15 · Vận dụng · 28 phút· Cập nhật 11/06/2026
Dự án cuối khoá: 3 app nhỏ
Biên soạn bởi Nguyễn Anh Tuấn
Ghép mảng, vòng lặp, rẽ nhánh, hàm main và scanf/printf thành 3 app terminal: Todo, Chi tiêu, Bình chọn; dữ liệu lưu trong RAM.
Bạn đã học biến, rẽ nhánh, vòng lặp, hàm, mảng và chuỗi. Giờ là lúc ghép tất cả thành phần mềm thật - ba ứng dụng dòng lệnh nhỏ: Todo, Chi tiêu, và Bình chọn. Cả ba chỉ dùng những gì khoá cơ bản đã dạy: mảng + vòng lặp + rẽ nhánh + hàm main + nhập/xuất - con trỏ và file thì chưa cần, còn struct (Bài 14) được để dành cho bài tập nâng cấp.
- ▸Cả ba app đều là “quản lý một danh sách” bằng mảng + một menu số.
- ▸Phiên bản đầu CỐ Ý dùng MẢNG SONG SONG thay vì struct - để cảm nhận đúng cái khó mà struct giải.
- ▸Chạy trong bộ nhớ (mất khi thoát) - phần lưu file để dành cho khoá C nâng cao.
Một “việc cần làm” có hai thuộc tính: tên và đã xong chưa. Phiên bản mộc này tạm cất struct (Bài 14) sang một bên, dùng hai mảng song song: tieu_de[i] và xong[i] - cùng chỉ số i thì nói về cùng một việc. Thử thêm và đánh dấu xong:
- ▸Mảng song song: nhiều mảng, mỗi mảng một thuộc tính, khớp nhau theo chỉ số i.
- ▸Thêm = đẩy vào TẤT CẢ các mảng cùng lúc (giữ chúng thẳng hàng).
- ▸Điểm yếu: dễ lệch nếu sửa mảng này mà quên mảng kia - đúng cái mà struct (Bài 14) giải.
Toàn bộ app gọn trong một hàm main: hai mảng song song, một vòng do…while hiện menu, và mỗi lựa chọn là một nhánh if:
todo.c - Todo bằng mảng song song, chạy trong bộ nhớ
#include <stdio.h>
#define MAX 100
int main(void) {
char tieu_de[MAX][80]; /* ten tung viec */
int xong[MAX]; /* 0=chua, 1=xong (song song voi tieu_de) */
int n = 0, chon;
do {
printf("\n1=Them 2=Xong 3=In 0=Thoat | Chon: ");
if (scanf("%d", &chon) != 1) break;
if (chon == 1 && n < MAX) {
printf("Ten viec: ");
scanf(" %79[^\n]", tieu_de[n]); /* doc ca dong, gom dau cach */
xong[n] = 0; /* moi them -> chua xong */
n++;
} else if (chon == 2) {
int so = 0;
printf("So thu tu: ");
scanf("%d", &so);
if (so >= 1 && so <= n) xong[so - 1] = 1; /* nguoi dung dem tu 1 */
} else if (chon == 3) {
if (n == 0) printf(" (chua co viec)\n");
for (int i = 0; i < n; i++)
printf(" %d. [%c] %s\n", i + 1, xong[i] ? 'x' : ' ', tieu_de[i]);
}
} while (chon != 0);
return 0;
} Kết quả khi chạy
1=Them 2=Xong 3=In 0=Thoat | Chon: 1 Ten viec: hoc bai C 1=Them 2=Xong 3=In 0=Thoat | Chon: 1 Ten viec: di cho 1=Them 2=Xong 3=In 0=Thoat | Chon: 2 So thu tu: 1 1=Them 2=Xong 3=In 0=Thoat | Chon: 3 1. [x] hoc bai C 2. [ ] di cho 1=Them 2=Xong 3=In 0=Thoat | Chon: 0
Tải app Todo hoàn chỉnh (một file todo.c + Makefile), biên dịch và chạy. Dùng nó làm khung cho hai app sau.
$ make $ ./todo
Xem từng file (3) ↡
- ▸do…while in menu rồi đọc lựa chọn - lặp đến khi chọn 0.
- ▸Mỗi nhánh thao tác trên mảng theo chỉ số; thêm thì tăng n.
- ▸In = một vòng for duyệt 0…n−1, hiện [x]/[ ] theo xong[i].
Cùng khung Todo, chỉ đổi dữ liệu và nghiệp vụ. Dùng hai mảng song song so_tien[] và danh_muc[]; trọng tâm là duyệt mảng cộng dồn để ra tổng:
khai báo + phần bạn tự viết
long long so_tien[100]; /* so tien moi khoan (dong) */
char danh_muc[100][24]; /* nhom chi (song song) */
int n = 0;
/* Menu: 1=Ghi 2=In 3=Tong 0=Thoat */
/* Nghiep vu chinh - tinh TONG (viec cua ban): */
long long tong = 0;
for (int i = 0; i < n; i++)
tong += so_tien[i]; /* cong don tung khoan */
printf("Tong chi: %lld\n", tong); Khung khởi đầu: phần nhập/in đã có; bạn viết vòng lặp tính tổng ở phần TODO trong main.c.
$ make $ ./chi-tieu
Xem từng file (3) ↡
- ▸Dùng long (không dùng float) cho tiền để khỏi sai số làm tròn.
- ▸Tổng = mẫu “duyệt mảng cộng dồn” đã học ở bài Mảng & chuỗi.
- ▸Bonus: tổng theo nhóm - chỉ cộng khi strcmp(danh_muc[i], muc) == 0.
Cũng từ khung đó, dùng ten[] và phieu[]. Bỏ phiếu là phieu[i]++; tìm người dẫn đầu là bài toán tìm lớn nhất kinh điển:
khai báo + phần bạn tự viết
char ten[100][60]; /* ten ung vien */
int phieu[100]; /* so phieu (song song) */
int n = 0;
/* Menu: 1=Them 2=Bau(phieu[so-1]++) 3=Ketqua 0=Thoat */
/* Tim nguoi dan dau - TIM MAX (viec cua ban): */
int dan_dau = (n > 0) ? 0 : -1;
for (int i = 1; i < n; i++)
if (phieu[i] > phieu[dan_dau])
dan_dau = i; /* gap ai nhieu phieu hon thi cap nhat */ Khung khởi đầu: thêm/bỏ phiếu/in đã có; bạn viết phần tìm người dẫn đầu (tìm max) ở phần TODO.
$ make $ ./binh-chon
Xem từng file (3) ↡
- ▸Khởi tạo phieu[n] = 0 ngay khi thêm ứng viên (mảng không tự về 0).
- ▸Tìm max: giả sử phần tử đầu lớn nhất, rồi duyệt phần còn lại cập nhật dần.
- ▸Cùng một khung, ba sản phẩm - chỉ đổi mảng dữ liệu và nghiệp vụ.
Hết khoá C cơ bản 🎉 - và bước tiếp theo
Câu hỏi thường gặp
Là dùng nhiều mảng riêng, mỗi mảng giữ MỘT thuộc tính, và quy ước rằng cùng một chỉ số i thì các mảng nói về cùng một đối tượng. Ví dụ tieu_de[i] là tên việc thứ i, còn xong[i] là trạng thái của đúng việc đó. Đây là cách lưu “một bản ghi nhiều thuộc tính” mộc nhất - Bài 14 đã cho bạn struct làm cùng việc đó gọn hơn.
Vì với người mới, đọc một số bằng scanf("%d", &chon) đơn giản và ít lỗi hơn nhiều so với phân tích một dòng lệnh chữ. Mỗi lựa chọn là một nhánh if - đúng những gì đã học ở bài Rẽ nhánh.
Đọc một chuỗi tới khi gặp ký tự xuống dòng - tức là đọc CẢ DÒNG, gồm cả dấu cách (khác %s chỉ đọc một từ). Dấu cách ở đầu format bỏ qua ký tự xuống dòng còn sót lại từ lần scanf số trước. Số 79 giới hạn không cho tràn mảng char[80].
Vì mảng cục bộ trong C KHÔNG tự khởi tạo về 0 - nếu không gán, ô đó chứa giá trị rác. Đặt 0 ngay khi thêm để trạng thái/đếm bắt đầu đúng.
Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.
Trả lời vài câu để chắc rằng em đã nắm bài.
Mảng song song nghĩa là gì trong bài?
- 1
Hai mảng, một chỉ số
Dùng công cụ ở Bước 2: thêm 3 việc rồi đánh dấu việc thứ 2 là xong.
tieu_de[1]vàxong[1]đang là gì?Hoàn thành khi:
tieu_de[1]là tên việc thứ hai;xong[1] = 1(true). Hai mảng vẫn thẳng hàng theo chỉ số 1. - 2
Dựng Todo
Gõ lại app Todo ở Bước 3, biên dịch và chạy: thêm vài việc, đánh dấu xong, in danh sách.
Hoàn thành khi: Biên dịch sạch (
-Wall -Wextra); lệnh 3 in đúng [x]/[ ] theo trạng thái từng việc. - 3
Lệch một đơn vị
Trong app Todo, vì sao đánh dấu xong dùng
xong[so - 1]chứ không phảixong[so]?Hoàn thành khi: Người dùng nhập số thứ tự đếm từ 1, còn mảng đếm từ 0 → việc số “so” nằm ở chỉ số
so − 1. - 4
Tổng chi
Mở app Chi tiêu (starter), viết vòng lặp tính tổng ở phần TODO. Ghi 50000 + 20000 rồi xem tổng.
Hoàn thành khi: for (i=0..n−1)
tong += so_tien[i];→ Tổng chi: 70000. - 5
Tìm người dẫn đầu
Mở app Bình chọn (starter), viết phần TODO tìm ứng viên nhiều phiếu nhất.
Hoàn thành khi:
dan_dau = 0rồi for i: nếuphieu[i] > phieu[dan_dau]thìdan_dau = i; in đúng người dẫn đầu. - 6
Sản phẩm đầu tay
Hoàn thiện cả ba app và đưa lên GitHub, mỗi app một thư mục kèm hướng dẫn build.
Hoàn thành khi: Ba chương trình chạy được - bộ sản phẩm C cơ bản đầu tiên của bạn.