You are on page 1of 51

Các kiểu dữ liệu nâng cao

Nội dung
• Kiểu dữ liệu mảng
• Kiểu cấu trúc – struct
• Con trỏ
• Bộ nhớ cấp phát động
• Kiểu xâu ký tự
• Kiểu liệt kê – Enum
Kiểu dữ liệu mảng – Array
Kiểu dữ liệu mảng
• Khái niệm cơ bản
• Cách sử dụng mảng
• Khởi tạo mảng bằng nhiều cách
• Mảng nhiều chiều
• Bài tập
Kiểu dữ liệu Array - mảng
• Mảng : là một tập hợp hữu hạn các phần tử có cùng kiểu dữ liệu được lưu trữ kế
tiếp nhau trong bộ nhớ.
• Các phần tử cùng kiểu, nằm kế tiếp nhau trong bộ nhớ
• Được quản lý dưới 1 tên chung duy nhất (tên mảng)
• Các phần tử phân biệt bởi vị trí tương đối so với phần tử đầu mảng
• Xử lý tự động thông qua vòng lặp

<Kiểu_dữ_liệu> <Tên_Mảng>[kích_thước_tối_đa];

Kiểu_dữ_liệu: kiểu của các phần tử trong mảng (nguyên, thực, ký tự, chuỗi, mảng, con trỏ…)
Tên_mảng: tên của mảng
Kích_thước_tối_đa: số phần tử tối đa mà mảng có thể lưu trữ
Kiểu dữ liệu Array - mảng
• VD 1. Mảng lưu trữ điểm bài quiz hàng tuần

float diemQuizHangTuan[200];
• Mảng trên
• Tên mảng diemQuizHangTuan
• Các phần tử trong mảng kiểu float (4 Byte/phần tử)
• Số lượng phần tử tối đa 200 phần tử
• Kích thước biến mảng = <kích thước 1 phần tử> * <số lượng phần tử> = 800 Bytes
• Các phần tử khi khai báo chưa được gán giá trị → nhận giá trị là ngẫu nhiên tùy vào
trạng thái ô nhớ được cấp phát
• Đối xử với các phần tử trong mảng như với các biến đơn cùng kiểu float
Địa chỉ phần tử thứ 4 sẽ là
Kiểu dữ liệu Array - mảng &diemQuizHangTuan[0] =
diemQuizHangTuan + 3*sizeof(float)

• Cách sử dụng mảng


• Trong C/C++, phần tử đầu mảng sẽ là vị trí 0
• Truy cập các phần tử trong mảng qua tên mảng và vị trí tương đối so với đầu
mảng
diemQuizHangTuan[0] → phần tử đầu tiên trong mảng
diemQuizHangTuan[10] → phần tử thứ 11 trong mảng
diemQuizHangTuan[199] → phần tử cuối cùng trong mảng

• Thao tác với các phần tử như biến đơn cùng kiểu!
• Chú ý: C/C++ KHÔNG check truy cập ra ngoại phạm vi mảng
diemQuizHangTuan[-1] → phần tử trước phần tử đầu tiên trong mảng
diemQuizHangTuan[200] → phần tử kế tiếp phần tửcuối cùng trong mảng
Kiểu dữ liệu Array - mảng
• Ví dụ. Nhập điểm quiz hàng tuần của lớp
/*
Hàm nhập vào điểm quiz của các bạn sinh viên
điểm nhập và lưu vào mảng diemQuizHangTuan
số lượng sinh viên cần nhập điểm là size
*/
void nhapDiemQuizTuan(float diemQuizHangTuan[], int size)
{
printf("Nhap diem cua tung ban theo thu tu:\n");
for(int i=0; i<size; i++){
printf("Diem sinh vien thu %d: ",i+1);
scanf("%f",&diemQuizHangTuan[i]);
}
}
Kiểu dữ liệu Array - mảng
• Tại sao không viết hàm với tham số dạng?
void nhapDiemQuizTuan(float diemQuizHangTuan[200])

• Hàm trên chỉ áp dụng cho mảng kiểu float gồm 200 phần tử
• Hàm càng nhiều tham số thì càng linh động và có thể tái sử dụng dễ dàng hơn

//Hàm in ra danh sách điểm của sinh viên trên từng dòng
void inDanhSachDiemQuiz(float diemQuizHangTuan[], int size)
{
printf("Danh sach diem:\n");
for(int i=0; i<size; i++){
printf("%.2f\n",diemQuizHangTuan[i]);
}
}
Kiểu dữ liệu Array - mảng
• Chú ý khi dùng mảng:
• Mảng sau khi đã khai báo sẽ KHÔNG thay đổi kích thước được, vì vậy cần khai báo số
lượng phần tử tối đa >= số lượng thực sự dùng
• Khi khai báo mảng, số lượng tối đa phải là HẰNG số
• KHÔNG được truy cập ra ngoài phạm vi mảng đã khai báo (dẫn tới lỗi logic rất khó debug)
• Các phần tử trong mảng khi mới khai báo cần được khởi tạo giá trị trước khi dùng
• KHÔNG thể gán trực tiếp giá trị 2 mảng cho nhau bằng trực tiếp tên biến mảng
• Để xác định kích thước của mảng và phần tử có thể dùng hàm sizeof(), để copy mảng nên
dùng memcpy() thay vì copy từng phần tử
• Tên mảng là hằng con trỏ chứa địa chỉ của phần tử đầu tiên của mảng
• Các phần tử trong mảng truy cập ngẫu nhiên với thời gian truy cập là bằng nhau
Kiểu dữ liệu Array - mảng
• VD 2. Dùng mảng làm bộ đếm

Để khảo sát chất lượng một sản phẩm mới nhà sản xuất thu thập điểm đánh giá của
khách hàng đã mau hàng trên trang TMDT. Điểm đánh giá sản phẩm theo thang từ 0
đến 5 (0 là không biết, 1 là rất tồi, 2 là tồi, 3 là trung bình, 4 là tốt và 5 là rất tốt).

Hãy xây dựng chương trình thu thập điểm đánh giá và đưa ra kết quả thống kê
chung.
/**
* chương trình minh họa sử dụng mảng như 1 bộ đếm
* Ví dụ đếm và tính điểm trung bình của các khảo sát thu
thập được int nhapDuLieuDanhGia(int ratingCounters[6])
*/ {
// reset giá trị mảng đếm
#include <stdio.h> for (int i = 0; i <= 5; ++i ) ratingCounters[i] = 0;
/* int danhGia,demDanhGia=0,traLoi;
Hàm nhập vào dữ liệu đánh giá của khách hàng cho sản phẩm do{
Hàm sẽ nhập cho đến khi không còn đánh giá nào nữa printf ("Nhap vao danh gia tiep: ");
Các đánh giá sẽ là giá trị từ 0-5 scanf("%d",&danhGia);
Hàm sẽ trả về số lượng đánh giá hợp lệ thu thập được // chỉ xet đánh giá hợp lệ
*/ if( danhGia < 0 || danhGia > 5 ){
printf("Hãy nhập vào đánh giá hợp lệ 0-5!\n");
continue;
}
++ratingCounters[danhGia];
demDanhGia++;

printf("Nhap tiep(1/0)?: ");


scanf("%d",&traLoi);
}
while(traLoi==1);

return demDanhGia;
}
/*
Hàm thống kê kết quả trung bình của các đánh giá
Đầu vào là mảng đánh giá và số lượng đánh giá
*/
void thongKeKetQuaDanhGia(int ratingCounters[6], int soLuongDanhGia)
{
if(soLuongDanhGia==0){
printf("Khong co danh gia nao!\n");
return;
}

// tinh tong diem trung binh


double tongDiemDanhgia=0;
for(int i=0;i<6; i++){
tongDiemDanhgia=tongDiemDanhgia+ratingCounters[i]*i;
}

// in ra ket qua thong kê


printf("Đã có %d đánh giá được thu thập!\n",soLuongDanhGia);
printf("Điểm đánh giá trung bình là %.2lf\n",tongDiemDanhgia/soLuongDanhGia);

}
Dùng mảng làm bộ đếm

int main (void)


{
// mảng thống kê kết quả đánh giá
int ratingCounters[6];

int soLuongDanhGia = nhapDuLieuDanhGia(ratingCounters);


thongKeKetQuaDanhGia(ratingCounters,soLuongDanhGia);

return 0;
}
Kiểu dữ liệu Array - mảng
• VD3. viết chương trình chuyển đổi số hệ 10 sang hệ 2, 8 hoặc 16

Nhận xét:
• Chuyển đổi hệ cơ số từ hệ 10 sang các hệ khác bằng cách chia liên tiếp cho hệ cơ số cần đổi
• Các chữ số sẽ được viết ngược lại theo thứ tự chia
• Các chữ số trong hệ cơ số mà lớn hơn hoặc bằng 10 sẽ được thay bằng các chữ cái như A B
CDEF
• Dùng mảng để lưu các chữ số chuyển đổi được, và cho vòng lặp từ cuối về đầu để in ngược
• Dùng mảng như bản tra khi chuyển đổi các chữ số sang chữ cái
/**
* chương trình chuyển đổi một giá trị số trong hệ 10
* sang các hệ khác như 2, 8 và 16
*/

#include <stdio.h>

const char chuSoCoSo[16] = {


'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

/**
Hàm chuyển đổi hệ cơ số từ số hệ 10 sang hệ cơ số khác
Số cần chuyển soCanChuyen là số hệ 10
heCoSo là hệ cơ số cần chuyển tới
*/
void chuyenDoiCoSo(int soCanChuyen, int heCoSo)
{
int soChuyenDoi[64];//so chuyen doi
int chuSoTiep, index = 0, soBanDau = soCanChuyen;

do {
soChuyenDoi[index] = soCanChuyen % heCoSo;
++index;
soCanChuyen = soCanChuyen / heCoSo;
}
while ( soCanChuyen != 0 );

// Hien thi ket qua the thu tu nguoc


printf ("Số %d trong hệ 10 chuyển sang hệ %d sẽ là: ",soBanDau, heCoSo);
for (--index; index >= 0; --index ) {
chuSoTiep = soChuyenDoi[index];
printf ("%c", chuSoCoSo[chuSoTiep]);
}

printf ("\n");
}
Chuyển đổi cơ số dùng mảng

int main (void)


{
// minh họa sử dụng hàm
chuyenDoiCoSo(15,2);
chuyenDoiCoSo(15,8);
chuyenDoiCoSo(15,16);
return 0;
}
Kiểu dữ liệu Array - mảng
Khởi tạo mảng
• int integers[5] = { 0, 1, 2, 3, 4 };
• int integers[] = { 0, 1, 2, 3, 4 };
• char letters[5] = { 'a', 'b', 'c', 'd', 'e' };
• float sample[5] = {3*c, 3+x, 5.0, 4.6, 8.2};
• float sample_data[500] = { [2] = 500.5, [1] = 300.0, [0] = 100.0 }; (*)
• int a[10] = { [9] = x + 1, [2] = 3, [1] = 2, [0] = 1 }; (*)

(*) Chỉ có trong C99 (devC++,…)


Kiểu dữ liệu Array - mảng
• Mảng có số lượng phần tử biến đổi – Variable Length Array (Chỉ có từ phiên bản C99):
cho phép khai báo mảng với kích thước chỉ được xác định tại thời điểm thực hiện.

• (Ưu điểm: tiết kiệm bộ nhớ hơn khai báo truyền thống)

int n;
printf("nhap vao n: ");
scanf("%d",&n);

int A[n];
for(i=0;i<n;i++) A[i]=i;
Kiểu dữ liệu Array - mảng
• Mở rộng mảng → mảng của mảng hoặc mảng nhiều chiều

<kiểu_dữ_liệu> <Tên_mảng>[Chiều_1] [Chiều_2]… [Chiều_N];

• kiểu_dữ_liệu: Kiểu của mỗi phần tử trong mảng


• Chiều_1, Chiều_2,…Chiều_N: Các hằng số nguyên, cho biết kích thước (số phần
tử) của mỗi chiều
• Mảng gồm: Chiều_1 x Chiều_2 x...x Chiều_N phần tử được lưu trữ trong vùng
nhớ liên tục.

22
Mảng nhiều chiều
int t[3][4] ;
t[0] t[0][0] t[0][1] t[0][2] t[0][3]

t[1] t[1][0] t[1][1] t[1][2] t[1][3]

t[2] t[2][0] t[2][1] t[2][2] t[2][3]

t[1][0] t[1][1] t[1][2] t[1][3]


23
Mảng nhiều chiều
b[2][2][4]
int b[3][4][5]; b[2]
b[1]
b[0]

b[0][1][2]

• Mảng b gồm 3 phần tử b[0], b[1], b[2]


• Mỗi phần tử là mảng hai chiều gồm 4 hàng (hàng 0, 1, 2, 3) và 5 cột (0, 1, 2, 3, 4)
• Mỗi phần tử là một số nguyên có dấu 4 byte

24
Mảng nhiều chiều
• Chú ý:
• Mảng đa chiều (nhiều chiều) các phần tử cùng kiểu
• Về mặt lưu trữ vật lý chỉ có mảng 1 chiều, mảng nhiều chiều sẽ lưu trữ lần
lượt từng chiều theo thứ tự dưới dạng mảng 1 chiều
• VD. Trong C/C++ mảng 2 chiều sẽ được lưu trữ thành mảng 1 chiều theo từng
hàng
int A[3][4]

A[0][0] A[0][1] A[0][3]

A[1][0] A[0][0] A[0][1] A[0][3] A[1][0] A[2][0] A[2][3]

A[2][0] A[2][3]

Địa chỉ phần tử &A[i][j] sẽ được tính theo mảng 1 chiều là A + (i*4+j)*sizeof(int)
Mảng nhiều chiều
Khởi tạo giá trị
int b[2][3]={ {1,2,3}, {4,5,6} };
int t[3][4] = {{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}};

• Số lượng giá trị khởi tạo không được lớn hơn số lượng phần tử trong mảng
– Nếu số lượng này nhỏ hơn, các phần tử còn lại được khởi tạo giá trị 0
int A[3][4] = { {1}, {4,5} };
int A[3][4] = { };Tất cả đều mang giá trị 0

26
STT Nhãn hàng 1 Nhãn hàng 2 Nhãn hàng 3 Nhãn hàng 4 Nhãn hàng 5
#1 0 5 4 1 4
Mảng nhiều chiều ..
#1000 0 5 1 5 5

• VD4. Khảo sát mức độ quan tâm của người dùng xem quảng cáo với các nhãn hàng qua
kênh online. Đánh giá của mỗi người với 5 nhãn hàng phổ biến sẽ được thu thập theo
dạng bảng sau
• Điểm đánh giá của người dùng sẽ là dải điểm tăng 0 → 5
• 0 là KHÔNG quan tâm
• 5 là rất quan tâm
• Hãy xây dựng chương trình
• Đọc vào đánh giá của n người dùng (n<=1000)
• Tìm và in ra xem nhãn hàng nào ít được quan tâm nhất
• Tính và in ra điểm đánh giá trung bình của mỗi nhãn hàng (chỉ tính các nhãn hàng
người dùng có quan tâm, điểm >=1)
• Người dùng ít xem quảng cáo là những người mà có đánh giá 0 từ 3 nhãn hàng trở lên,
hãy tính tỉ lệ người không xem quảng cáo (hoặc chặn quảng cáo)
int nhapDuLieuDanhGia(int diemDanhGia[][5])
/** {
Chương trình minh họa sử dụng mảng hai chiều int danhGia,demDanhGia=0,traLoi;
do{
Dùng mảng 2 chiều thống kê khảo sát độ quan tâm tới quảng printf ("Nhap vao danh gia tiep cho 5 nhan hang: \n");
cáo online for(int i=0; i<5;i++)
Đánh giá và in ra mức độ quan tâm theo nhiều tiêu chí {
// reset mảng giá trị về 0 trước khi dùng
*/
diemDanhGia[demDanhGia][i]=0;
#include <stdio.h>
printf("Nhan hang %d: ",i+1);
/* scanf("%d",&danhGia);
Hàm nhập dữ liệu khảo sát (tối đa 1000) // chỉ xet đánh giá hợp lệ, ngược lại thì bỏ qua để đọc tiếp
Hàm trả về số lượng khảo sát hợp lệ được nhập if( danhGia < 0 || danhGia > 5 ){
*/ printf("Hãy nhập vào đánh giá hợp lệ 0-5!\n");
continue;
}

// ghi nhận lại đánh giá hợp lệ


diemDanhGia[demDanhGia][i] = danhGia;
}
demDanhGia++;

printf("Nhap tiep(1/0)?: ");


scanf("%d",&traLoi);
}
while(traLoi==1);

return demDanhGia;
}
/*Hàm đếm và in ra nhãn hàng ít được quan tâm nhất (điểm đánh giá 0 nhiều nhất) soLuongDanhGia là số lượng đánh giá hiện có trong mảng diemDanhGia */
void inNhanHangItDuocQuanTam(int diemDanhGia[][5], int soLuongDanhGia)
{
// dùng 1 mảng 5 phần tử để đếm số lượng khách hàng ko quan tâm của mỗi nhãn hàng, reset mang dem ve 0 truoc khi dung
int soLuongKhongQuanTam[5]={};

// duyệt từng đánh giá và đếm số lượng không quan tâm


for(int i=0; i<soLuongDanhGia; i++){
for(int j=0; j<5; j++){
if(diemDanhGia[i][j]==0){
soLuongKhongQuanTam[j]++;
}
}
}
// tìm nhãn hàng có nhiều người ko quan tâm nhất
int nhanItDuocQuanTam = 0;
for(int j=1; j<5; j++){
if(soLuongKhongQuanTam[j]>soLuongKhongQuanTam[nhanItDuocQuanTam]){
nhanItDuocQuanTam = j;
}
}

// in ra các nhãn ít được quan tâm


printf("Cac hang it duoc quan tam la: ");
for(int j=0; j<5; j++){
if(soLuongKhongQuanTam[j]==soLuongKhongQuanTam[nhanItDuocQuanTam]){
printf("nhan %d, ", j+1);
}
}
printf("\nSo luong luot khong quan tam la %d\n", soLuongKhongQuanTam[nhanItDuocQuanTam]);
}
/** Hàm tính và in ra màn hình điểm đánh giá trung bình của từng nhãn hàng. Chỉ tính những đánh giá nhãn hàng nào có điểm >=1 */
void inDiemDanhGiaTrungBinh(int diemDanhGia[][5], int tongSoDanhGia)
{
// dùng 1 mảng 5 phần tử để đếm số đánh giá
int soLuongDanhGia[5]={};
int tongDiemDanhGia[5]={};

// duyệt từng đánh giá và đếm số lượng cho từng nhãn


for(int i=0; i< tongSoDanhGia; i++){
for(int j=0; j<5; j++){
if(diemDanhGia[i][j]>0){
soLuongDanhGia[j]++;
tongDiemDanhGia[j]+=diemDanhGia[i][j];
}
}
}
// in ra điểm đánh giá của các nhãn
// chú ý số lượng đánh giá phải lớn hơn 0
printf("Diem danh gia trung binh cua tung nhan:\n");
for(int j=0; j<5; j++){
if(soLuongDanhGia[j]>0){
printf("Nhan %d co diem trung binh %.2lf\n",j+1,tongDiemDanhGia[j]*1.0/soLuongDanhGia[j]);
} else {
printf("Nhan %d KHONG co danh gia nao\n",j+1);
}
}
}
Mảng nhiều chiều
int main()
{
// khai báo mảng đánh giá
int diemDanhGia[1000][5];
int soLuongDanhGia;

// nhập dữ liệu
soLuongDanhGia = nhapDuLieuDanhGia(diemDanhGia);

// goi các hàm xử lý


inNhanHangItDuocQuanTam(diemDanhGia, soLuongDanhGia);
inDiemDanhGiaTrungBinh(diemDanhGia, soLuongDanhGia);

return 0;
}

Viết hàm tìm số lượng người dùng chặn quảng cáo hoặc ít xem quảng cáo
Thao tác cơ bản với mảng
• Nhập/Xuất dữ liệu cho mảng
– Mảng 1 chiều, ma trận
• Bài toán đếm
– Đếm số phần tử thỏa mãn điều kiện cho trước
– Tính toán trên các phần tử..
• Tìm kiếm phần tử
– Lớn nhất/nhỏ nhất/bất kỳ
• Sắp xếp phần tử trong mảng
– Theo thứ tự, theo nguyên tắc
• Chèn thêm phần tử, xóa phần tử
32
Thao tác cơ bản với mảng

• VD5. Phân tích


bảng chỉ số VNIndex
trong 120 ngày gần đây
• Nhập vào giá trị chỉ số vnindex trong 120 ngày gần đây
• Đưa ra giá trị cao nhất và thấp nhất
• Đưa ra chuỗi ngày tăng dài nhất (giảm dài nhất)
• Giá trị MA20 được tính bằng giá trị trung bình của 20 ngày gần nhất với ngày hiện tại. Hãy
tính và đưa ra giá trị MA20 của dữ liệu đã nhập
• Tìm và in ra giá trị tăng/giảm đột biến của 2 ngày liên tiếp
• Đưa ra tỉ lệ biến đổi của chuỗi tăng/giảm lớn nhất (tỉ lệ giữa thời điểm đầu và cuối của chuỗi)
Kiểu dữ liệu cấu trúc - struct
Nội dung
• Khái niệm về Struct
• Khai báo struct
• Truy nhập các trường trong struct
• Phép gán giữa biến kiểu struct
• Con trỏ và struct
Cấu trúc - Struct
• Kiểu dữ liệu cấu trúc (struct)
• Còn được gọi là kiểu dữ liệu người dùng tự định nghĩa
• là kiểu dữ liệu phức hợp bao gồm nhiều thành phần,
• mỗi thành phần có thể thuộc những kiểu dữ liệu khác nhau.
Ví dụ:
• Thông tin lưu trữ về sinh viên sẽ gồm
• họ tên,
• tuổi,
• kết quả học tập…
• Thông tin cơ bản của 1 bài hát gồm
• Thời lượng : tính theo second
• Năm ghi âm
Cấu trúc - Struct
• Mục đích sử dụng của Struct
• Đối tượng gồm nhiều thông tin khác nhau, nếu dùng nhiều biến → nhiều tên, khó
quản lý
• Cấu trúc sẽ giúp gom các thông tin liên quan tới đối tượng lại và đặt dưới 1 tên chung
duy nhất
• Chỉ cần nhớ 1 tên biến duy nhất là biến cấu trúc
• Định nghĩa kiểu dữ liệu cấu trúc:
struct tên_cấu_trúc
{
<Kiểu dữ liệu> <tên trường>;
....
<Kiểu dữ liệu> <tên trường>;
};
Cấu trúc - Struct
// cấu trúc lưu trữ thông tin sinh viên
struct sinh_vien
Ví dụ. Định nghĩa cấu trúc để biểu {
diễn char masoSV[10]; // mã số sinh viên
char hoten[30]; // họ tên
• Thông tin sinh viên float diemTinDC; // điểm thi THDC
• Tọa độ 1 điểm trong không gian 3 };
chiều
// cấu trúc lưu trữ tọa độ 1 điểm
// trong không gian 3 chiều
struct point_3D
{
float x;
float y;
float z;
};
Cấu trúc - Struct
• Khai báo biến kiểu cấu trúc:
struct <tên_cấu_trúc> <tên_biến_cấu_trúc>;

• Ví dụ: struct sinh_vien sv1, sv2;


struct point_3D point1, point2;

• Muốn tránh dùng từ khóa struct → dùng typedef để đặt lại tên kiểu cấu trúc
// cấu trúc điểm trong không gian 3 chiều
typedef struct point_3D
{
float x;
float y;
float z;
} POINT;
POINT x,y; //(thay vì struct point_3D x,y;)
typedef struct point_3D
x
{
Cấu trúc - Struct float x;
float y; y
float z;
} POINT;
z

POINT
Truy nhập các trường dữ liệu của cấu trúc :
• Dữ liệu của một biến cấu trúc bao gồm nhiều trường dữ liệu, và các trường này độc lập
với nhau.
• Muốn thay đổi nội dung dữ liệu bên trong một biến cấu trúc ta cần truy nhập tới từng
trường và thực hiện thao tác cần thiết trên từng trường đó.
tên_biến_cấu_trúc.tên_trường
• “đối xử” tên_biến_cấu_trúc.tên_trường giống như một biến thông thường cùng kiểu
Cấu trúc - Struct
Phép gán giữa các biến cấu trúc
• Phép gán cấu trúc có cú pháp tương tự như phép gán thông thường

biến_cấu_trúc_1 = biến_cấu_trúc_2;
• Câu lệnh trên sẽ gán giá trị của các trường trong biến_cấu_trúc_2 cho các trường
tương ứng trong biến_cấu_trúc_1.
• Chú ý nếu trường cấu trúc có kiểu là con trỏ thì phép gán chỉ là “copy nông”
Một số ví dụ về struct
• Ví dụ. Nhập vào ngày, tháng, năm hiện tại (năm KHÔNG nhuận) và in ra ngày tiếp theo

/** Minh họa việc sử dụng cấu trúc - struct


* Nhập vào ngày tháng, năm hiện tại và in ra ngày mai
*/
#include <stdio.h>

// Định nghĩa cấu trúc lưu thông tin thời điểm hiện tại
struct date{
int month;
int day;
int year;
};

// Mảng lưu các ngày trong tháng (KHÔNG tính năm nhuận)
const int daysPerMonth[12] =
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int main (void)
{
struct date today, tomorrow;

// nhập vào ngày hiện tại


printf ("Enter today's date (mm dd yyyy): ");
scanf ("%i%i%i", &today.month, &today.day, &today.year);

// nếu hôm nay không phải ngày cuối tháng hiện tại
if (today.day != daysPerMonth[today.month - 1]){
tomorrow.day = today.day + 1;
tomorrow.month = today.month;
tomorrow.year = today.year;
}
// nếu là ngày cuối năm
else if (today.month == 12){
tomorrow.day = 1;
tomorrow.month = 1;
tomorrow.year = today.year + 1;
}
else // nếu là cuối tháng
{ // in ra ngày kế tiếp, năm chỉ in ra 2 số cuối
tomorrow.day = 1; printf ("Tomorrow's date is %i/%i/%.2i.\n",
tomorrow.month = today.month + 1; tomorrow.month, tomorrow.day, tomorrow.year % 100);
tomorrow.year = today.year;
} return 0;
}
Khởi tạo biến cấu trúc
Khởi tạo giá trị cho biến kiểu struct
• struct date today = { 7, 2, 2010 };
• struct date today = { 7, 2 };
• struct date today = { .day=7,.year= 2010 }; (*)
• struct date today = { .year = 2011 }; (*)

Lệnh gán cấu trúc


• today = (struct date) { 9, 25, 2004 }; (*)
• today = (struct date) { .month = 9, .day = 25, .year = 2004 }; (*)
(*): chỉ có trong C99 trở lên (dev-C++, MSVC…)
Mảng cấu trúc
• Mảng cấu trúc : mỗi phần tử của mảng là một cấu trúc.
struct date LichHen[3];
LichHen[1].month = 11;
LichHen[1].day=10;
LichHen[1].year=2010;

• Khởi tạo biến mảng cấu trúc


struct date lichHen[3]={{12,11,2010},{11,25,2010},{12,5,2010}};
struct date lichHen[3]={12,11,2010,11,25,2010,12,5,2010};
Thao tác cơ bản với mảng
• VD6. Điểm học phần IT1108 bao gồm
• Điểm giữa kỳ trên lớp 25%
• Điểm trên LAB 25%
• Điểm cuối kỳ 50%
• Hãy viết chương trình
• Nhập vào các điểm thành phần của sinh viên trong lớp (tối đa không quá 300)
• Tính điểm học phần của các sinh viên
• Để qua môn sinh viên cần đạt các điểm >=3 và tổng điểm học phần >=4, hãy đếm
xem có bao nhiêu sinh viên đạt
• Viết hàm đổi điểm số ra điểm chữ F, A ,B, C, D
• Sắp xếp điểm của sinh viên theo thứ tự giảm dần, các bạn không qua ở cuối cùng
Struct chứa struct
struct date struct time
{ {
int month; int hour;
int day; int min;
int year; int sec;
}; };

struct dateTime
{
struct date sDate;
struct time sTime;
};
Struct chứa struct

struct dateTime event = {11,6,2010};


event.sTime.hour =8;
event.sTime.min =0;
event.sTime.sec =0;

printf("%.2i/%.2i/%.2i %.2i:%.2i:%.2i",
event.sDate.month,event.sDate.day,
event.sDate.year%100,event.sTime.hour,
event.sTime.min,event.sTime.sec);
Struct chứa mảng
struct sinhvien
• Struct chứa mảng {
char masoSV[10];
char hoten[30];
float diem;
};

• Truy cập vào từng phần tử của mảng thành phần như với biến mảng thông thường.
struct sinhvien sv;
sv.masoSV[0]='B';
sv.masoSV[1]='K';
sv.masoSV[2]='H';
sv.masoSV[3]='N';
Một số định nghĩa struct dạng khác
• Định nghĩa struct kết hợp khai báo biến
struct sinhvien struct date
{ {
char masoSV[10]; int month;
char hoten[30]; int day;
float diem; int year;
} sv1, sv2; }event = {11,10,2010};

struct
{
int hour;
int min;
int sec;
} Alarm[10];
Cấu trúc - Struct

Con trỏ cấu trúc


• Để khai báo một biến con trỏ cấu trúc ta dùng cú pháp khai báo
<tên cấu trúc> * <tên biến con trỏ cấu trúc> ;

• Có 2 cách truy nhập vào trường dữ liệu của cấu trúc từ biến con trỏ cấu trúc

(*<tên biến con trỏ cấu trúc>).<tên trường dữ liệu>
<tên biến con trỏ cấu trúc>-><tên trường dữ liệu>
Cấu trúc - Struct

struct sinhvien a,b,*c;

strcpy(a.masoSV,"BK2456");
strcpy(a.hoten,"Nguyen Van A");
a.diem=7.6;

printf("Ten : %s MasoSV: % s Diem: %0.2f \n",a.hoten, a.masoSV, a.diem);

b=a;
printf("Ten : %s MasoSV: % s Diem: %0.2f \n",b.hoten, b.masoSV, b.diem);

c=(sinhvien*)malloc(sizeof(sinhvien));
*c = b;
printf("Ten : %s MasoSV: % s Diem: %0.2f \n",c->hoten, c->masoSV, c->diem);

You might also like