Skip to content

C04: Mảng & Vector — Lưu trữ nhiều dữ liệu

Bạn sẽ học được: Mảng tĩnh, vector, duyệt, thao tác cơ bản
Yêu cầu: Đã học C03 (Điều kiện & Vòng lặp)
Thời gian: 60 phút


Tại sao cần mảng & vector?

Analogies: Mảng = Dãy tủ, Vector = Túi co giãn

flowchart LR
    A["Mảng (array)"] -->|"Kích thước cố định"| B["Dãy tủ gỗ"]
    C["Vector"] -->|"Kích thước linh hoạt"| D["Túi co giãn"]
Khái niệm Analogies Ví dụ
Mảng Dãy tủ gỗ (kích thước cố định) int a[5] — 5 ngăn tủ
Vector Túi co giãn (có thể thêm/bớt) vector<int> a(n) — túi có n ngăn
Phần tử Đồ trong tủ a[0] — ngăn đầu tiên
Chỉ số Số thứ tự ngăn a[0], a[1], a[2]...

Khi nào dùng mảng, khi nào dùng vector?

  • Mảng: Khi biết chắc chắn số phần tử, cần tốc độ tối đa
  • Vector: Khi không biết trước số phần tử, hoặc cần thêm/bớt phần tử

Mảng (Array)

Khai báo mảng

// Khai báo mảng 5 phần tử
int a[5];           // Chưa khởi tạo (giá trị rác)

// Khai báo và khởi tạo
int b[5] = {1, 2, 3, 4, 5};  // Khởi tạo sẵn

// Khai báo mảng toàn số 0
int c[5] = {0};     // {0, 0, 0, 0, 0}

// Khai báo mảng toàn số -1
int d[5];
memset(d, -1, sizeof(d));  // {-1, -1, -1, -1, -1}

Truy cập phần tử

1
2
3
4
5
6
7
8
9
int a[5] = {10, 20, 30, 40, 50};

cout << a[0] << endl;  // 10 (phần tử đầu tiên)
cout << a[2] << endl;  // 30 (phần tử thứ 3)
cout << a[4] << endl;  // 50 (phần tử cuối cùng)

// Sửa giá trị
a[0] = 100;
cout << a[0] << endl;  // 100

Chỉ số bắt đầu từ 0

1
2
3
int a[5] = {10, 20, 30, 40, 50};
// a[0] = 10, a[1] = 20, a[2] = 30, a[3] = 40, a[4] = 50
// KHÔNG CÓ a[5]! (truy cập ngoài mảng → lỗi)

Duyệt mảng

int a[5] = {10, 20, 30, 40, 50};

// Cách 1: Dùng for với chỉ số
for (int i = 0; i < 5; i++) {
    cout << a[i] << " ";
}
// Output: 10 20 30 40 50

// Cách 2: Dùng range-based for (C++11)
for (int x : a) {
    cout << x << " ";
}
// Output: 10 20 30 40 50

Mảng 2 chiều (Ma trận)

// Khai báo ma trận 3x3
int a[3][3] = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

// Duyệt ma trận
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        cout << a[i][j] << " ";
    }
    cout << endl;
}

Vector — Mảng động

Tại sao dùng vector?

1
2
3
4
5
6
7
8
9
// ❌ Mảng: Phải biết trước kích thước
int n;
cin >> n;
int a[n];  // Không chuẩn C++, một số compiler cho phép

// ✅ Vector: Linh hoạt
int n;
cin >> n;
vector<int> a(n);  // Tạo vector n phần tử

Khai báo vector

// Vector rỗng
vector<int> a;

// Vector n phần tử (khởi tạo 0)
vector<int> b(n);

// Vector n phần tử, tất cả là giá trị x
vector<int> c(n, x);

// Khởi tạo sẵn
vector<int> d = {1, 2, 3, 4, 5};

Thao tác cơ bản

vector<int> a = {1, 2, 3, 4, 5};

// Truy cập
cout << a[0] << endl;      // 1
cout << a.size() << endl;  // 5

// Thêm phần tử vào cuối
a.push_back(6);            // {1, 2, 3, 4, 5, 6}

// Xóa phần tử cuối
a.pop_back();              // {1, 2, 3, 4, 5}

// Kiểm tra rỗng
if (a.empty()) cout << "Rong";

// Xóa tất cả
a.clear();

Duyệt vector

vector<int> a = {10, 20, 30, 40, 50};

// Cách 1: Dùng chỉ số
for (int i = 0; i < a.size(); i++) {
    cout << a[i] << " ";
}

// Cách 2: Dùng range-based for
for (int x : a) {
    cout << x << " ";
}

// Cách 3: Dùng iterator
for (auto it = a.begin(); it != a.end(); it++) {
    cout << *it << " ";
}

Vector 2 chiều (Ma trận động)

int rows, cols;
cin >> rows >> cols;

// Tạo ma trận rows x cols, khởi tạo 0
vector<vector<int>> a(rows, vector<int>(cols, 0));

// Duyệt
for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
        cin >> a[i][j];
    }
}

Các hàm thường dùng

Với mảng

int a[] = {5, 2, 8, 1, 9, 3};
int n = 6;

// Sắp xếp
sort(a, a + n);  // {1, 2, 3, 5, 8, 9}

// Tìm min/max
int minVal = *min_element(a, a + n);  // 1
int maxVal = *max_element(a, a + n);  // 9

// Đảo ngược
reverse(a, a + n);  // {9, 8, 5, 3, 2, 1}

// Tìm kiếm
bool found = binary_search(a, a + n, 5);  // true (phải sắp xếp trước)

Với vector

vector<int> a = {5, 2, 8, 1, 9, 3};

// Sắp xếp
sort(a.begin(), a.end());  // {1, 2, 3, 5, 8, 9}

// Tìm min/max
int minVal = *min_element(a.begin(), a.end());  // 1
int maxVal = *max_element(a.begin(), a.end());  // 9

// Đảo ngược
reverse(a.begin(), a.end());  // {9, 8, 5, 3, 2, 1}

// Xóa phần tử tại vị trí i
a.erase(a.begin() + i);

// Chèn phần tử tại vị trí i
a.insert(a.begin() + i, x);

// Tìm kiếm
auto it = find(a.begin(), a.end(), 5);
if (it != a.end()) cout << "Tim thay";

Bài toán kinh điển

Bài toán 1: Tìm số lớn nhất

int n;
cin >> n;

vector<int> a(n);
for (int i = 0; i < n; i++) cin >> a[i];

int maxVal = a[0];
for (int i = 1; i < n; i++) {
    if (a[i] > maxVal) maxVal = a[i];
}
cout << maxVal << endl;

Bài toán 2: Đếm số dương

int n;
cin >> n;

vector<int> a(n);
for (int i = 0; i < n; i++) cin >> a[i];

int count = 0;
for (int x : a) {
    if (x > 0) count++;
}
cout << count << endl;

Bài toán 3: Tính tổng mảng

1
2
3
4
5
6
7
8
9
int n;
cin >> n;

vector<int> a(n);
for (int i = 0; i < n; i++) cin >> a[i];

long long sum = 0;
for (int x : a) sum += x;
cout << sum << endl;

Common Mistakes — Lỗi thường gặp

Lỗi 1: Truy cập ngoài mảng

1
2
3
4
5
6
7
int a[5] = {1, 2, 3, 4, 5};

// ❌ SAI: Truy cập a[5] (ngoài mảng)
cout << a[5] << endl;  // Lỗi runtime hoặc giá trị rác!

// ✅ ĐÚNG: Chỉ truy cập a[0] đến a[4]
for (int i = 0; i < 5; i++) cout << a[i] << " ";

Lỗi 2: Quên khởi tạo mảng

1
2
3
4
5
6
// ❌ SAI: Mảng chưa khởi tạo
int a[5];
cout << a[0] << endl;  // Giá trị rác!

// ✅ ĐÚNG: Khởi tạo mảng
int a[5] = {0};  // Tất cả bằng 0

Lỗi 3: Dùng size() kiểu int

1
2
3
4
5
6
7
8
9
vector<int> a = {1, 2, 3, 4, 5};

// ❌ SAI: So sánh int với size_t (unsigned)
for (int i = 0; i < a.size(); i++) { ... }  // Cảnh báo

// ✅ ĐÚNG: Dùng size_t hoặc int cast
for (int i = 0; i < (int)a.size(); i++) { ... }
// hoặc
for (size_t i = 0; i < a.size(); i++) { ... }

Lỗi 4: Xóa phần tử trong vòng lặp

// ❌ SAI: Xóa phần tử trong vòng lặp for thường
vector<int> a = {1, 2, 3, 4, 5};
for (int i = 0; i < a.size(); i++) {
    if (a[i] % 2 == 0) a.erase(a.begin() + i);  // Bỏ qua phần tử!
}

// ✅ ĐÚNG: Dùng iterator hoặc vòng lặp ngược
for (auto it = a.begin(); it != a.end(); ) {
    if (*it % 2 == 0) it = a.erase(it);
    else it++;
}

Bài tập thực hành

Bài 1: Tìm số lớn nhất

Đọc n số nguyên. Tìm số lớn nhất.

Input: 5 3 7 2 9 1
Output: 9

Lời giải
#include <bits/stdc++.h>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; i++) cin >> a[i];

    int maxVal = a[0];
    for (int i = 1; i < n; i++) {
        if (a[i] > maxVal) maxVal = a[i];
    }
    cout << maxVal << endl;
    return 0;
}

Bài 2: Đảo ngược mảng

Đọc n số nguyên. In mảng đảo ngược.

Input: 5 1 2 3 4 5
Output: 5 4 3 2 1

Lời giải
#include <bits/stdc++.h>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; i++) cin >> a[i];

    reverse(a.begin(), a.end());
    for (int x : a) cout << x << " ";
    return 0;
}

Bài 3: Đếm số chẵn

Đọc n số nguyên. Đếm số lượng số chẵn.

Input: 5 1 2 3 4 5
Output: 2

Lời giải
#include <bits/stdc++.h>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; i++) cin >> a[i];

    int count = 0;
    for (int x : a) {
        if (x % 2 == 0) count++;
    }
    cout << count << endl;
    return 0;
}

Tóm tắt bài học

Nội dung Chi tiết
Mảng int a[n] — kích thước cố định
Vector vector<int> a(n) — kích thước linh hoạt
Truy cập a[i] — chỉ số bắt đầu từ 0
Duyệt for (int i = 0; i < n; i++) hoặc for (int x : a)
Thao tác push_back(), pop_back(), size(), empty()
Sắp xếp sort(a.begin(), a.end())

Bài viết liên quan


Bài tiếp theo: C05: String →


💬 Bình luận