← Lập trình C cơ bản

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đã 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]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:

App Todo lưu bằng hai mảng song song: cùng một chỉ số i trỏ tới tên việctrạng thái của nó.
i
tieu_de[i]
xong[i]
(mảng rỗng - thêm việc để xem hai mảng lớn lên cùng nhau)
n = 0 việc còn 0 việc chưa 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
Chạy trên máy bạn - kỹ năng thật cần gõ lệnh thật

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[]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);
Chạy trên máy bạn - kỹ năng thật cần gõ lệnh thật

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[]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 */
Chạy trên máy bạn - kỹ năng thật cần gõ lệnh thật

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

Bạn đã đi trọn: Hello World → biến → nhập/xuất → toán tử → rẽ nhánh → vòng lặp → hàm → mảng & chuỗi → và giờ là ba app chạy được. Bạn để ý hai điểm gợn: dữ liệu mất khi thoát, và mảng song song dễ lệch. Điểm gợn thứ nhì bạn chữa được NGAY: bài tập cuối của Bài 14 là nâng cấp app Todo lên struct. Phần còn lại là động lực của khoá Lập trình C nâng cao: con trỏ & cấp phát động cho mảng lớn tuỳ ý, và file để chương trình “nhớ”. Cùng ba sản phẩm này, bạn sẽ dựng lại sạch hơn nhiều.

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.

Có. Ba app này chạy hoàn toàn trong bộ nhớ (RAM), nên thoát là mất hết. Lưu ra file để “nhớ” qua mỗi lần chạy là kỹ năng của khoá C nâng cao (cùng với con trỏ và cấp phát động).

Không - nó dễ lệch (sửa mảng này quên mảng kia). Nó là phiên bản mộc có chủ đích: làm xong, bạn sẽ thấm vì sao struct (Bài 14) gom mọi thuộc tính vào MỘT bản ghi lại đáng quý đến vậy. Bài tập cuối của Bài 14 chính là nâng cấp app Todo này lên struct.

Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.

Tick những điều em tự tin làm được sau khi học bài này. 0/6

Trả lời vài câu để chắc rằng em đã nắm bài.

Câu 1/3 Điểm: 0

Mảng song song nghĩa là gì trong bài?

  1. 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]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. 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. 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ải xong[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. 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. 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 = 0 rồi for i: nếu phieu[i] > phieu[dan_dau] thì dan_dau = i; in đúng người dẫn đầu.

  6. 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.