Ngôn ngữ lập trình C/C++ cung cấp cấu trúc dữ liệu gọi là mảng, được lưu trữ trong một tập hợp các dữ liệu cùng kiểu với độ dài cố định. Một mảng được sử dụng để lưu trữ tập hợp dữ liệu, nhưng nó rất hữu dụng nếu bạn nghĩ về một mảng các biến với cùng một kiểu.
Thay vì khai báo biến một cách rời rạc, như biến so0, so1,… và so99, bạn có thể khai báo một mảng các giá trị như so[0], so[1] và … so[99] để biểu diễn các giá trị riêng biệt. Một thành viên cụ thể của mảng có thể được truy cập qua index (chỉ số).
Tất cả mảng đều bao gồm các vị trí nhớ liền kề nhau. Địa chỉ thấp nhất tương ứng với thành viên đầu tiền và địa chỉ cao nhất tương ứng với thành viên cuối cùng của mảng.
Khai báo mảng trong C/C++
Để khai báo một mảng trong ngôn ngữ C/C++, bạn xác định kiểu của biến và số lượng các phần tử được yêu cầu bởi biến đó như sau:
Kieu Ten_mang [ Kich_co_mang ];
Đây là mảng một chiều. Kich_co_mang phải là một số nguyên lớn hơn 0 và Kieu phải hợp lệ trong ngôn ngữ C/C++. Ví dụ, khai báo một mảng 10 phần tử gọi là balance với kiểu double, sử dụng câu lệnh sau đây:
char sinhvien[10];
Khởi tạo mảng trong C/C++
Bạn có thể khởi tạo mảng trong C/C++ hoặc từng phần tử một hoặc sử dụng một câu lệnh như dưới đây:
int hanghoa[5] = {45, 34, 29, 67, 49};
Số lượng các giá trị trong dấu ngoặc kép {} không được lớn hơn số lượng phần tử khai báo trong dấu ngoặc vuông [].
Nếu bạn bỏ sót kích cỡ mảng thì mảng đó đủ lớn để giữ các giá trị được khởi tạo: Bạn sẽ tạo chính xác một chuỗi có giá trị giống hệt chuỗi bên trên bằng cách gán từng phần tử một. Dưới đây là một ví dụ khi gán giá trị cho một phần tử của mảng:
int hanghoa[] = {45, 34, 29, 67, 49};
Bạn có thể tạo ra cùng một mảng giống như đã làm trong ví dụ trước.
hanghoa[4] = 50;
Câu lệnh bên trên gán giá trị thứ 5 của mảng giá trị 50.0. Tất cả các mảng đều có chỉ số (index) đầu tiên bằng 0, đây được gọi là chỉ số cơ bản và phần tử cuối cùng của mảng có chỉ số bằng độ lớn của mảng trừ đi 1. Dưới đây là cách biểu diễn hình họa cho chuỗi khai báo bên trên thông qua chỉ số:
Truy cập các phần tử mảng trong C/C++
Một mảng được truy cập bởi cách đánh chỉ số trong tên của mảng. Dưới đây là một cách truy cập một giá trị của mảng:
int hocphi = hocphik60[55];
Câu lệnh trên lấy phần tử thứ 56 của mảng và gán giá trị này cho biến hocphi. Dưới đây là một ví dụ về việc sử dụng với tất cả mô tả bên trên:
#include <iostream> using namespace std; #include <iomanip> using std::setw; int main () { int n[ 10 ]; // n la mot mang gom 10 so nguyen // khoi tao gia tri cac phan tu cua mang n la 0 for ( int i = 0; i < 10; i++ ) { n[ i ] = i + 100; // thiet lap phan tu tai vi tri i la i + 100 } cout << "Phan tu thu:" << setw( 13 ) << "Gia tri la:" << endl; // hien thi gia tri cua moi phan tu for ( int j = 0; j < 10; j++ ) { cout << setw( 7 )<< j << setw( 13 ) << n[ j ] << endl; } return 0; }
Chương trình này sử dụng hàm setw(so_nguyen) trong C/C++ để định dạng output. Tại đây, tham số so_nguyen là một số chỉ độ rộng của kết quả mà bạn muốn hiển thị. Chẳng hạn, với so_nguyen là 3 tức là bạn dành 3 vị trí để in kết quả, nếu kết quả cần hiển thị là thừa thì nó sẽ bị cắt bớt, nếu thiếu thì chèn thêm khoảng trống vào. Hàm setw() được dùng cho cả cout và cin.
Chạy chương trình C/C++ trên sẽ cho kết quả như hình sau:
Chi tiết về mảng trong C/C++
Mảng là một phần rất quan trọng trong ngôn ngữ C/C++. Dưới đây là những định nghĩa quan trọng liên quan đến một mảng cụ thể mà được trình bày rõ ràng hơn cho các lập trình viên C/C++:
Khái niệm | Miêu tả |
---|---|
Mảng đa chiều trong C/C++ | C/C++ hỗ trợ các mảng đa chiều. Mẫu đơn giản nhất của mảng này là mảng hai chiều |
Con trỏ tới một mảng trong C/C++ | Bạn có thể trỏ tới phần tử đầu tiên của mảng một cách đơn giản chỉ bởi xác định tên mảng đó, chứ không phải một chỉ số |
Truyền mảng tới hàm như là tham số trong C/C++ | Bạn có thể truyền tới hàm một điểm trỏ chỉ tới một mảng bởi xác định tên mảng chứ không phải là một chỉ số |
Trả về mảng từ hàm trong C/C++ | C/C++ cho phép một hàm có thể trả về một mảng |
Mảng đa chiều trong C/C++
C++ hỗ trợ các mảng đa chiều. Dưới đây là mẫu chung của một khai báo mảng đa chiều:
kieu_du_lieu ten_mang[kich_co_1][kich_co_2]...[kich_co_N];
Ví dụ, khai báo sau tạo một mảng số nguyên 3 chiều: 5. 10. 4:
int hocphi[5][10][4];
Mảng hai chiều trong C++ Mẫu đơn giản nhất của mảng đa chiều là mảng hai chiều. Một mảng hai chiều về bản chất là danh sách của các mảng một chiều. Để khai báo một mảng hai chiều integer với kích cỡ x, y, bạn nên viết như sau:
kieu_du_lieu ten_mang [ x ][ y ];
Ở đây, kieu_du_lieu có thể là bất kỳ kiểu dữ liệu có hiệu lực nào và ten_mang sẽ là một định danh C++ có hiệu lực.
Một mảng hai chiều có thể như là một bảng mà có x hàng và y cột. Một mảng hai chiều a chứa 3 hàng và 4 cột có thể được hiển thị như sau:
Như vậy, mỗi phần tử trong mảng a được định danh bởi một tên phần tử trong kiểu mẫu a[i][j], với a là tên mảng và i, j là các subscript – chỉ số được xác định duy nhất mỗi phần tử trong a.
Khởi tạo mảng hai chiều trong C++
Các mảng đa chiều có thể được khởi tạo bởi xác định các giá trị trong dấu móc vuông cho mỗi hàng. Sau đây là một hàng với 3 hàng và mỗi hàng chứa 4 cột.
int a[3][4] = { {0, 1, 2, 3} , /* khoi tao gia tri cho hang ma co chi muc la 0 */ {4, 5, 6, 7} , /* khoi tao gia tri cho hang ma co chi muc la 1 */ {8, 9, 10, 11} /* khoi tao gia tri cho hang ma co chi muc la 2 */ };
Các dấu ngoặc ôm, mà chỉ các hàng giá trị là tùy ý. Khởi tạo sau là tương đương với ví dụ trên:
int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
Truy cập các phần tử của mảng hai chiều trong C++
Các phần tử mảng hai chiều được truy cập bởi sử dụng các chỉ số, ví dụ chỉ số hàng và chỉ số cột. Ví dụ:
int val = a[2][3];
Lệnh trên sẽ truy cập vào phần tử thứ 4 từ hàng thứ 3 của mảng. Bạn có thể kiểm tra lại nó trong sơ đồ trên. Bây giờ chúng ta xem xét ví dụ dưới đây, chúng tôi đã sử dụng các vòng lặp lồng vào nhau để xử lý một mảng hai chiều:
#include <iostream> using namespace std; int main () { // mang sau co 5 hang va 2 cot. int a[5][2] = { {0,0}, {1,2}, {2,4}, {3,6},{4,8}}; // hien thi gia tri cua cac phan tu trong mang for ( int i = 0; i < 5; i++ ) for ( int j = 0; j < 2; j++ ) { cout << "Gia tri cua a[" << i << "][" << j << "] la: "; cout << a[i][j]<< endl; } return 0; }
Chạy chương trình C++ trên sẽ cho kết quả như hình sau:
Như phần trên đã giải thích, bạn có thể có các mảng với số chiều bất kỳ, nhưng hầu hết các mảng bạn tạo ra sẽ là một hoặc hai chiều.
Con trỏ tới một mảng trong C/C++
Có thể bạn sẽ không hiểu chương này tới khi bạn đã đọc qua chương về Con trỏ trong C++.
Vì thế giả sử rằng bạn đã hiểu biết chút nào đó về con trỏ trong C++, vậy chúng ta cùng bắt đầu: Một tên mảng là một con trỏ hằng số tới phần tử đầu tiên của mảng. Vì thế, trong khai báo:
double phithuebao[50];
phithuebao là một con trỏ tới &phithuebao[0], mà là địa chỉ của phần tử đầu tiên của mảng phithuebao. Do vậy, đoạn chương trình sau gán p địa chỉ của phần tử đầu tiên của phithuebao:
double *p; double phithuebao[10]; p = phithuebao;
Sử dụng các tên mảng như là các con trỏ hằng số là hợp lệ, và ngược lại. Vì thế, *(phithuebao + 4) là cách chính thống để truy cập dữ liệu tại phithuebao[4].
Một khi bạn lưu địa chỉ của phần tử đầu tiên trong p, bạn có thể truy cập các phần tử mảng bởi sử dụng *p, *(p+1), *(p+2), …. Dưới đây là ví dụ để chỉ tất cả các khái niệm được đề cập ở trên:
#include <iostream> using namespace std; int main () { // mang sau co 5 phan tu. double phithuebao[5] = {1000.0, 2.0, 3.4, 17.0, 50.0}; double *p; p = phithuebao; // hien thi gia tri cac phan tu trong mang cout << "Hien thi gia tri mang boi su dung con tro!" << endl; for ( int i = 0; i < 5; i++ ) { cout << "Gia tri cua *(p + " << i << ") la: "; cout << *(p + i) << endl; } cout << "Hien thi gia tri mang boi su dung phithuebao lam dia chi!" << endl; for ( int i = 0; i < 5; i++ ) { cout << "*Gia tri cua (phithuebao + " << i << ") la: "; cout << *(phithuebao + i) << endl; } return 0; }
Chạy chương trình C++ trên sẽ cho kết quả như hình sau:
Trong ví dụ trên, p là một con trỏ tới double, mà có nghĩa là nó có thể lưu giữ địa chỉ của một biến kiểu double. Một khi chúng ta có địa chỉ trong p, thì sau đó *p sẽ cung cấp giá trị có sẵn tại địa chỉ được lưu trong p, như chúng tôi đã chỉ trong ví dụ trên.
Truyền mảng tới hàm như là tham số trong C/C++
Trả về mảng từ hàm trong C/C++
C++ không cho phép bạn trả về toàn bộ một mảng như là một tham số tới một hàm. Tuy nhiên, bạn có thể trả về một con trỏ tới một mảng bởi xác định tên mảng đó mà không phải là một chỉ số. Bạn sẽ học về con trỏ trong chương tới, vì thế bạn có thể bỏ qua chương này tới khi bạn hiểu khái niệm về Con trỏ trong C++.
Nếu bạn muốn trả về một mảng một chiều từ một hàm, bạn sẽ phải khai báo một hàm trả về một con trỏ như trong ví dụ sau:
int * tenHam()
{
.
.
.
}
Điểm thứ hai cần nhớ là C++ không ủng hộ việc trả về địa chỉ của biến cục bộ tới bên ngoài hàm, vì thế bạn sẽ phải định nghĩa biến cục bộ như là biến Static.
Bây giờ, giả sử hàm sau sẽ tạo 10 số ngẫu nhiên và trả chúng về bởi sử dụng một mảng và gọi hàm này như sau:
#include <iostream> #include <ctime> #include <stdlib.h> /* thu vien cho ham srand, rand */ using namespace std; // phan dinh nghia cua ham de tao va tra ve cac so ngau nhien. int * soNgauNhien( ) { static int r[10]; srand( (unsigned)time( NULL ) ); for (int i = 0; i < 10; ++i) { r[i] = rand(); cout << r[i] << endl; } return r; } // ham main de goi phan dinh nghia ham tren. int main () { // mot con tro tro toi mot so nguyen. int *p; p = soNgauNhien(); for ( int i = 0; i < 10; i++ ) { cout << "Gia tri cua *(p + " << i << ") la: "; cout << *(p + i) << endl; } return 0; }
Chạy chương trình C++ trên sẽ cho kết quả như hình sau: