Hướng dẫn cho người mới bắt đầu về Mảng Độ dài Biến thiên trong C

Xin chào các bạnfuture programmers! Hôm nay, chúng ta sẽ bắt đầu một hành trình thú vị vào thế giới của Mảng Độ dài Biến thiên (Variable Length Arrays - VLAs) trong C. Đừng lo lắng nếu bạn mới bắt đầu học lập trình - tôi sẽ là người hướng dẫn thân thiện của bạn, giải thích mọi thứ từng bước. Hãy cùng bắt đầu!

C - Variable Length Arrays

Mảng Độ dài Biến thiên là gì?

Trước khi bắt đầu, hãy hiểu Mảng Độ dài Biến thiên là gì. Hãy tưởng tượng bạn đang lên kế hoạch cho một buổi tiệc, nhưng bạn không chắc chắn sẽ có bao nhiêu khách đến. Liệu có tuyệt vời nếu bạn có thể chuẩn bị một bàn có thể tự động điều chỉnh kích thước dựa trên số lượng khách? Đó chính xác là điều VLAs làm trong lập trình!

Mảng Độ dài Biến thiên là một mảng mà kích thước được xác định tại thời điểm chạy chương trình (runtime) thay vì tại thời điểm biên dịch (compile-time). Tính năng này được giới thiệu trong tiêu chuẩn C99 và cung cấp sự linh hoạt hơn trong việc tạo mảng.

Tạo một Mảng Độ dài Biến thiên

Hãy bắt đầu với một ví dụ đơn giản để tạo một VLA:

#include <stdio.h>

int main() {
int n;
printf("Bạn muốn lưu trữ bao nhiêu số? ");
scanf("%d", &n);

int numbers[n];  // Đây là Mảng Độ dài Biến thiên của chúng ta

printf("Nhập %d số:\n", n);
for (int i = 0; i < n; i++) {
scanf("%d", &numbers[i]);
}

printf("Bạn đã nhập: ");
for (int i = 0; i < n; i++) {
printf("%d ", numbers[i]);
}

return 0;
}

Hãy phân tích này:

  1. Chúng ta hỏi người dùng họ muốn lưu trữ bao nhiêu số.
  2. Chúng ta tạo một mảng numbers với kích thước n mà người dùng đã nhập.
  3. Chúng ta sử dụng một vòng lặp để nhập n số từ người dùng.
  4. Cuối cùng, chúng ta in ra tất cả các số mà người dùng đã nhập.

Đây là vẻ đẹp của VLAs - chúng ta không cần biết kích thước của mảng khi viết mã. Kích thước được xác định khi chương trình chạy!

Mảng Độ dài Biến thiên Hai chiều

Bây giờ, hãy nâng cấp và xem xét mảng hai chiều VLAs. Hãy tưởng tượng bạn đang tạo một bảng chỗ ngồi cho một đám cưới, nhưng bạn không biết sẽ có bao nhiêu bàn hoặc mỗi bàn sẽ có bao nhiêu ghế. Mảng hai chiều VLAs có thể giúp bạn!

Dưới đây là một ví dụ:

#include <stdio.h>

int main() {
int tables, seats;

printf("Bao nhiêu bàn? ");
scanf("%d", &tables);

printf("Bao nhiêu ghế mỗi bàn? ");
scanf("%d", &seats);

int seating[tables][seats];  // Mảng hai chiều Độ dài Biến thiên của chúng ta

// Gán số ghế
for (int i = 0; i < tables; i++) {
for (int j = 0; j < seats; j++) {
seating[i][j] = i * seats + j + 1;
}
}

// In bảng chỗ ngồi
printf("\nBảng chỗ ngồi:\n");
for (int i = 0; i < tables; i++) {
printf("Bàn %d: ", i + 1);
for (int j = 0; j < seats; j++) {
printf("%3d ", seating[i][j]);
}
printf("\n");
}

return 0;
}

Trong ví dụ này:

  1. Chúng ta hỏi người dùng số lượng bàn và số ghế mỗi bàn.
  2. Chúng ta tạo một mảng hai chiều seating với kích thước [tables][seats].
  3. Chúng ta gán số ghế cho từng vị trí.
  4. Cuối cùng, chúng ta in ra bảng chỗ ngồi.

Sự linh hoạt này cho phép chúng ta tạo một bảng chỗ ngồi với bất kỳ kích thước nào, được xác định tại runtime!

Mảng Jagged

Bây giờ, hãy xem xét một điều thực sự thú vị. Giả sử mỗi bàn tại đám cưới của chúng ta có số ghế khác nhau? Hãy gặp mảng Jagged - một mảng của các mảng mà mỗi phụ-array có thể có độ dài khác nhau.

Trong khi C không hỗ trợ mảng Jagged trực tiếp như một số ngôn ngữ khác, chúng ta có thể mô phỏng chúng bằng cách sử dụng VLAs và con trỏ. Dưới đây là cách làm:

#include <stdio.h>
#include <stdlib.h>

int main() {
int tables;
printf("Bao nhiêu bàn? ");
scanf("%d", &tables);

int *seats = malloc(tables * sizeof(int));
int **seating = malloc(tables * sizeof(int*));

// Nhập số ghế cho mỗi bàn
for (int i = 0; i < tables; i++) {
printf("Bao nhiêu ghế tại bàn %d? ", i + 1);
scanf("%d", &seats[i]);
seating[i] = malloc(seats[i] * sizeof(int));
}

// Gán số ghế
for (int i = 0; i < tables; i++) {
for (int j = 0; j < seats[i]; j++) {
seating[i][j] = j + 1;
}
}

// In bảng chỗ ngồi
printf("\nBảng chỗ ngồi:\n");
for (int i = 0; i < tables; i++) {
printf("Bàn %d: ", i + 1);
for (int j = 0; j < seats[i]; j++) {
printf("%3d ", seating[i][j]);
}
printf("\n");
}

// Giải phóng bộ nhớ đã cấp phát
for (int i = 0; i < tables; i++) {
free(seating[i]);
}
free(seating);
free(seats);

return 0;
}

Ví dụ này phức tạp hơn, hãy phân tích nó:

  1. Chúng ta tạo một mảng seats để lưu trữ số ghế cho mỗi bàn.
  2. Chúng ta tạo một con trỏ đến con trỏ seating để mô phỏng mảng Jagged.
  3. Chúng ta cấp phát bộ nhớ động cho mỗi bàn dựa trên số ghế.
  4. Chúng ta gán số ghế và in ra bảng chỗ ngồi như trước.
  5. Cuối cùng, chúng ta giải phóng bộ nhớ đã cấp phát để tránh rò rỉ bộ nhớ.

Phương pháp này cho phép chúng ta có số ghế khác nhau cho mỗi bàn - thực sự linh hoạt!

Bảng phương pháp

Dưới đây là bảng tham khảo nhanh các phương pháp chúng ta đã sử dụng trong các ví dụ:

Phương pháp Mô tả Ví dụ
scanf() Đọc đầu vào đã định dạng từ người dùng scanf("%d", &n);
printf() In đầu ra đã định dạng ra console printf("Xin chào, %s!", name);
malloc() Cấp phát bộ nhớ động int *arr = malloc(n * sizeof(int));
free() Giải phóng bộ nhớ đã cấp phát free(arr);

Nhớ rằng, với quyền lực lớn đi kèm với trách nhiệm lớn. VLAs và cấp phát bộ nhớ động là những công cụ mạnh mẽ, nhưng chúng cần được sử dụng cẩn thận để tránh các vấn đề như tràn stack hoặc rò rỉ bộ nhớ.

Và thế là bạn đã bước những bước đầu tiên vào thế giới của Mảng Độ dài Biến thiên trong C. Hãy nhớ rằng, thực hành là cách tốt nhất để trở thành người thợ giỏi, vì vậy đừng ngần ngại thử nghiệm với các khái niệm này. Chúc các bạn lập trình vui vẻ!

Credits: Image by storyset