Mảng (Array)
Mảng (array) là một cấu trúc dữ liệu lưu trữ nhiều phần tử cùng kiểu dữ liệu, được sắp xếp liên tiếp trong bộ nhớ. Kích thước của mảng C-style phải được xác định rõ và không thể thay đổi sau khi khai báo.
Khai báo mảng
Phần tiêu đề “Khai báo mảng”#include <iostream>
int main() { int numbers[5]; // Khai báo mảng 5 phần tử int, chưa có giá trị
int scores[5] = {90, 85, 70, 60, 95}; // Khai báo và khởi tạo cùng lúc
int values[] = {1, 2, 3}; // Không cần ghi rõ kích thước, trình biên dịch tự đếm (3 phần tử)
std::cout << scores[0] << std::endl; // 90 return 0;}Truy cập và sửa đổi phần tử
Phần tiêu đề “Truy cập và sửa đổi phần tử”Mỗi phần tử được truy cập thông qua chỉ số (index), bắt đầu từ 0:
int scores[5] = {90, 85, 70, 60, 95};
std::cout << scores[0] << std::endl; // 90 (phần tử đầu tiên)std::cout << scores[4] << std::endl; // 95 (phần tử cuối cùng)
scores[2] = 100; // Sửa giá trị phần tử thứ 3 (chỉ số 2)std::cout << scores[2] << std::endl; // 100Truy cập ngoài phạm vi: nguy hiểm và không báo lỗi!
Phần tiêu đề “Truy cập ngoài phạm vi: nguy hiểm và không báo lỗi!”Đây là một trong những cạm bẫy nguy hiểm nhất của mảng C-style: C++ không kiểm tra chỉ số có hợp lệ hay không. Truy cập ngoài phạm vi là undefined behavior - chương trình có thể chạy sai, crash, hoặc (tệ hơn) chạy “bình thường” với dữ liệu rác:
int scores[5] = {90, 85, 70, 60, 95};// std::cout << scores[10] << std::endl; // NGUY HIỂM! Đọc vùng nhớ không thuộc mảng// scores[10] = 100; // CÀNG NGUY HIỂM HƠN! Ghi đè lên vùng nhớ không thuộc mảngLuôn đảm bảo chỉ số nằm trong khoảng [0, kích_thước - 1].
Kích thước của mảng
Phần tiêu đề “Kích thước của mảng”int numbers[5] = {1, 2, 3, 4, 5};int size = sizeof(numbers) / sizeof(numbers[0]); // Tổng byte của mảng / byte của 1 phần tửstd::cout << size << std::endl; // 5Đây là mẹo phổ biến để lấy số lượng phần tử của mảng C-style (vì mảng không tự “biết” số lượng phần tử của chính nó).
Duyệt qua mảng
Phần tiêu đề “Duyệt qua mảng”int numbers[5] = {10, 20, 30, 40, 50};
// Cách 1: dùng chỉ sốfor (int i = 0; i < 5; i++) { std::cout << numbers[i] << " ";}
// Cách 2: range-based for (C++11)for (int n : numbers) { std::cout << n << " ";}Truyền mảng vào hàm
Phần tiêu đề “Truyền mảng vào hàm”Khi truyền mảng vào hàm, thực chất bạn đang truyền địa chỉ của phần tử đầu tiên (mảng “phân rã” thành con trỏ) - vì vậy cần truyền kèm kích thước mảng:
#include <iostream>
void print_array(int arr[], int size) { for (int i = 0; i < size; i++) { std::cout << arr[i] << " "; } std::cout << std::endl;}
int main() { int numbers[5] = {1, 2, 3, 4, 5}; print_array(numbers, 5); return 0;}Chi tiết về mối quan hệ giữa mảng và con trỏ sẽ được trình bày kỹ ở bài “Con trỏ và mảng”.
Hạn chế của mảng C-style
Phần tiêu đề “Hạn chế của mảng C-style”- Kích thước cố định, không thể thay đổi (thêm/bớt phần tử) sau khi khai báo
- Không tự kiểm tra chỉ số hợp lệ
- Không “biết” kích thước của chính nó khi truyền vào hàm
Vì những hạn chế này, C++ hiện đại khuyến khích dùng std::vector (mảng động, tự quản lý kích thước) thay vì mảng C-style trong hầu hết trường hợp - sẽ được giới thiệu ở bài riêng.
Tổng kết
Phần tiêu đề “Tổng kết”- Mảng lưu trữ nhiều phần tử cùng kiểu, kích thước cố định, truy cập qua chỉ số bắt đầu từ
0 - Truy cập ngoài phạm vi mảng là lỗi nguy hiểm, không được C++ tự động kiểm tra
sizeof(mang) / sizeof(mang[0])là cách lấy số lượng phần tử của mảng C-style- Khi truyền vào hàm, mảng “phân rã” thành con trỏ đến phần tử đầu tiên - cần truyền kèm kích thước