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

Bài 13 · Vận dụng · 22 phút· Cập nhật 11/06/2026

Mảng & chuỗi

Biên soạn bởi Nguyễn Anh Tuấn

Khai báo mảng, duyệt bằng for, hiểu chỉ số 0..n-1; chuỗi là mảng char kết thúc bằng \0 và các lỗi vượt biên.

Mảng (array) lưu nhiều giá trị cùng kiểu dưới một tên, truy cập từng phần tử qua chỉ số trong ngoặc vuông. Chỉ số bắt đầu từ 0. Kéo thanh trượt để xem từng ô - và thử vượt biên:

int diem[5] = { 10, 20, 30, 40, 50 };
[0]
10
[1]
20
[2]
30
[3]
40
[4]
50
diem[0] = 10

Chỉ số bắt đầu từ 0: phần tử đầu là diem[0], phần tử cuối là diem[4] (= n − 1). diem[5] đã vượt biên.

mang.c

#include <stdio.h>

int main() {
    int diem[5] = {10, 20, 30, 40, 50};
    printf("%d\n", diem[0]);  // phan tu DAU
    printf("%d\n", diem[4]);  // phan tu CUOI (n-1)
    return 0;
}

Kết quả khi chạy

10
50
  • Khai báo: kiểu tên[số_phần_tử]; vd int diem[5];
  • Truy cập: tên[chỉ_số] - chỉ số chạy 0 … n−1.
  • Phần tử đầu là a[0], phần tử cuối là a[n−1].

Mảng phát huy tác dụng thật sự khi ghép với vòng lặp (Bài 10): một vòng for chạy chỉ số i từ 0 tới n−1 là duyệt được mọi phần tử - vd cộng dồn để tính tổng:

tong-mang.c

#include <stdio.h>

int main() {
    int diem[5] = {10, 20, 30, 40, 50};
    int tong = 0;
    for (int i = 0; i < 5; i++) {
        tong += diem[i];      // cong don tung phan tu
    }
    printf("Tong = %d\n", tong);
    return 0;
}

Kết quả khi chạy

Tong = 150
  • Mẫu duyệt mảng: for (int i = 0; i < n; i++) … a[i] …
  • Điều kiện i < n (KHÔNG phải i <= n) để không chạm a[n] vượt biên.
  • Tính tổng, đếm, tìm lớn nhất/nhỏ nhất đều theo mẫu này.

Chuỗi (string) trong C không phải kiểu riêng - nó là một mảng char kết thúc bằng ký tự đặc biệt '\0' (mã ASCII 0). Gõ thử một từ để xem nó nằm trong bộ nhớ thế nào:

char ten[] = "Lan";
[0]
L
76
[1]
a
97
[2]
n
110
[3]
\0
0
strlen(ten)
3
số ký tự, KHÔNG tính \0
Số ô bộ nhớ
4
3 ký tự + 1 ô \0

Chuỗi trong C là một mảng char kết thúc bằng ký tự đặc biệt '\0' (mã ASCII 0). Nhờ ô \0 này, các hàm như printf("%s") biết chuỗi dừng ở đâu.

chuoi.c

#include <stdio.h>
#include <string.h>

int main() {
    char ten[] = "Lan";        // {'L','a','n','\0'} - 4 o nho
    printf("%s\n", ten);
    printf("Do dai: %zu\n", strlen(ten)); // 3 (%zu cho size_t), khong tinh '\0'
    return 0;
}

Kết quả khi chạy

Lan
Do dai: 3

Vì sao cần '\0'? Nó cho các hàm biết chuỗi dừng ở đâu. Tự duyệt một chuỗi cũng dựa vào nó - lặp cho tới khi gặp '\0':

duyet-chuoi.c

#include <stdio.h>

int main() {
    char ten[] = "Lan";
    for (int i = 0; ten[i] != '\0'; i++) {  // dung khi gap '\0'
        printf("%c-", ten[i]);
    }
    printf("\n");
    return 0;
}

Kết quả khi chạy

L-a-n-

Đọc chuỗi người dùng nhập

scanf("%s", ten) đọc một từ (dừng ở khoảng trắng); không cần & vì tên mảng đã là địa chỉ. Muốn đọc cả dòng và an toàn hơn với tràn mảng, dùng fgets(ten, sizeof ten, stdin).

Lỗi nguy hiểm nhất với mảng: truy cập ngoài biên. C không kiểm tra - vòng lặp lố một bước là chạm vùng nhớ lạ:

vuot-bien.c

int diem[5] = {10, 20, 30, 40, 50};
for (int i = 0; i <= 5; i++) {   // SAI: i <= 5 cham toi diem[5]
    printf("%d ", diem[i]);      // diem[5] VUOT BIEN (chi co 0..4)
}

Kết quả khi chạy

10 20 30 40 50 <rác> (hành vi không xác định)

Thiếu chỗ cho \0

char ten[3] = "Lan"; trông vừa 3 ký tự, nhưng "Lan" cần 4 ô (3 + '\0') - không còn chỗ cho ký tự kết thúc. C vẫn biên dịch (chỉ cảnh báo), nhưng mảng KHÔNG còn là chuỗi hợp lệ - đưa vào %s/strlen là hành vi không xác định. Khai báo mảng char phải đủ chỗ cho cả \0: chứa từ n ký tự ⇒ cần char[n+1].

Bài tiếp theo

Mảng chỉ chứa các giá trị cùng kiểu. Bài kế, Struct & kiểu tự đặt tên, gom các giá trị KHÁC kiểu thành một bản ghi - mảnh ghép cuối trước dự án cuối khoá.

Câu hỏi thường gặp

Mảng lưu NHIỀU giá trị cùng kiểu dưới một tên, truy cập qua chỉ số. Có 100 điểm thi mà khai báo 100 biến thì không thể duyệt bằng vòng lặp; với mảng chỉ cần diem[i] và một vòng for. Mảng + vòng lặp là cặp đôi kinh điển.

Chỉ số là “khoảng cách” từ đầu mảng: phần tử đầu cách đầu 0 ô nên là a[0]. Mảng n phần tử có chỉ số 0…n−1; phần tử cuối là a[n−1]. Đây là nguồn của vô số lỗi “lệch một đơn vị”.

Trong C, KHÔNG có kiểm tra biên. a[5] với mảng 5 phần tử sẽ đọc/ghi vào vùng nhớ KHÔNG thuộc mảng - chương trình có thể chạy sai âm thầm hoặc sập. Lập trình viên phải tự giữ chỉ số trong 0…n−1.

Là một mảng char kết thúc bằng ký tự đặc biệt \0 (mã ASCII 0, gọi là null terminator). char ten[] = "Lan" thực ra là {'L','a','n','\0'} - 4 ô. Nhờ \0, các hàm chuỗi biết chuỗi dừng ở đâu.

Không. strlen("Lan") = 3 - chỉ đếm ký tự thật, không tính \0. Nhưng bộ nhớ cần 4 ô (3 + \0). Khai báo mảng char phải đủ chỗ cho cả \0: muốn chứa từ n ký tự thì cần char[n+1].

Dùng scanf("%s", ten) - nhưng nó dừng ở khoảng trắng (chỉ đọc MỘT từ) và không kiểm tra tràn mảng. Để đọc cả dòng an toàn hơn, dùng fgets(ten, sizeof ten, stdin). Lưu ý %s không cần & vì tên mảng đã là địa chỉ.

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

Trong một mảng n phần tử, phần tử cuối có chỉ số là bao nhiêu?

  1. 1

    In một phần tử

    Khai báo int a[3] = {7, 8, 9}; rồi in a[1]. Kết quả?

    Hoàn thành khi: 8 - chỉ số 1 là phần tử THỨ HAI (vì đếm từ 0).

  2. 2

    Trung bình cộng

    Với diem[5] = {10,20,30,40,50}, dùng vòng lặp tính tổng rồi chia 5. Trung bình bằng bao nhiêu?

    Hoàn thành khi: 30 - tổng 150 / 5. (for i=0..4: tong += diem[i]; rồi tong/5.)

  3. 3

    Vượt biên

    Dùng công cụ Bước 1: kéo chỉ số tới 5. Vì sao diem[5] báo “ngoài phạm vi” dù mảng có 5 phần tử?

    Hoàn thành khi: 5 phần tử ⇒ chỉ số hợp lệ là 0…4; diem[5] là ô THỨ SÁU, không tồn tại.

  4. 4

    Đếm ô bộ nhớ

    Dùng công cụ Bước 3: gõ "Hoc". strlen ra bao nhiêu? Cần bao nhiêu ô bộ nhớ?

    Hoàn thành khi: strlen = 3; cần 4 ô (3 ký tự + 1 ô \0).

  5. 5

    Duyệt chuỗi

    Cho char ten[] = "AB"; viết vòng lặp in từng ký tự, dừng khi gặp \0. In ra gì nếu mỗi ký tự kèm dấu “-”?

    Hoàn thành khi: A-B- - vòng for (i=0; ten[i] != '\0'; i++) dừng tại \0.

  6. 6

    Vừa đủ chỗ

    Vì sao char ten[5] đủ chứa từ "Toan" nhưng char ten[4] thì KHÔNG?

    Hoàn thành khi: "Toan" = 4 ký tự + \0 = 5 ô. char[5] vừa đủ; char[4] không còn chỗ cho \0.