Professional Documents
Culture Documents
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)
• 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++;
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;
}
}
Dùng mảng làm bộ đếm
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>
/**
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 );
printf ("\n");
}
Chuyển đổi cơ số dùng mảng
• (Ư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
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]
b[0][1][2]
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[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;
}
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]={};
// nhập dữ liệu
soLuongDanhGia = nhapDuLieuDanhGia(diemDanhGia);
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
• 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
// Đị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;
// 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 }; (*)
struct dateTime
{
struct date sDate;
struct time sTime;
};
Struct chứa struct
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
• 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
là
(*<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
strcpy(a.masoSV,"BK2456");
strcpy(a.hoten,"Nguyen Van A");
a.diem=7.6;
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);