BÀI GIẢNG HỌC PHẦN
KỸ THUẬT LẬP TRÌNH
CHƯƠNG 4: CÁC KIỂU DỮ LIỆU CÓ CẤU TRÚC
Nội dung
2
4.1. Kiểu mảng 4.2. Kiểu xâu ký tự 4.3. Kiểu cấu trúc
4.1. Kiểu mảng
3
• Khái niệm mảng • Khai báo và sử dụng mảng • Các thao tác cơ bản trên mảng • Một số chương trình với mảng
Khái niệm mảng
• Là một kiểu dữ liệu có cấu trúc, bao gồm một tập hữu hạn các phần tử có cùng kiểu dữ liệu, có tên chung, được lưu trữ kế tiếp nhau trong bộ nhớ
• Kích thước của mảng được xác định ngay khi khai
• Các phần tử trong mảng có tên chung là tên của mảng và được phân biệt với nhau thông qua chỉ số của chúng
• Mảng thường được dùng để lưu một dãy giá trị như: dãy số nguyên, dãy số thực, dãy kí tự, ma trận, …
4
báo và là cố định
Khai báo và sử dụng mảng (1)
kiểu_dữ_liệu tên_mảng[N1][N2]…[Nn]
• Khai báo mảng:
trong đó:
- kiểu_dữ_liệu: là kiểu dữ liệu của các phần tử mảng - tên_mảng: tên biến mảng - N1, N2, …, Nn: kích thước các chiều của mảng Số phần tử của mảng: N1 * N2 * … * Nn • Ví dụ:
5
- int a[10], b[20]; - float matran[10][20];
Khai báo và sử dụng mảng (2)
thước các chiều của mảng Ví dụ:
• Có thể sử dụng chỉ thị #define để xác định kích
6
#define N1 20 #define N2 30 int a[N1]; float b[N1][N2];
Khai báo và sử dụng mảng (3)
• Kết hợp khởi tạo giá trị trong khai báo mảng: - Khởi tạo giá trị cho mọi phần tử của mảng
Ví dụ: int a[3] = {4,5,9};
float x[2][3] = {{2,1.5,3}, {1,3,4.25}}; - Khởi tạo giá trị cho một số phần tử đầu mảng
Ví dụ: int b[5] = {2,6,1};
bằng với số lượng giá trị khởi tạo Ví dụ: int c[] = {15,20,36,54};
7
- Khi không khai báo kích thước, kích thước mảng
Khai báo và sử dụng mảng (4)
#define tên_mảng {giá_trị_1, …, giá_trị_n} Không truy cập được vào các phần tử của mảng - Cách 2:
• Khai báo hằng kiểu mảng: - Cách 1:
const kiểu_dữ_liệu tên_mảng[N1] … [Nn] = {giá_trị_1, …, giá_trị_n}
Ví dụ:
8
const int hangmang1[4] = {10,20,25,40}; const float hangmang2[] = {4.5,9.25}; const float hangmang3[5] = {1.5,2,5};
Khai báo và sử dụng mảng (5)
• Lưu trữ dữ liệu kiểu mảng: - Các phần tử của mảng được lưu trữ tại các ô nhớ kế
N1 * N2 * … * Nn * sizeof(kiểu_dữ_liệu) - Các phần tử trong mảng được đánh chỉ số, phần tử đầu tiên có chỉ số là 0, phần tử thứ i có chỉ số là i-1 - Biến mảng lưu trữ địa chỉ của ô nhớ đầu tiên trong
vùng nhớ được cấp phát
9
tiếp nhau trong bộ nhớ - Kích thước bộ nhớ lưu trữ:
Khai báo và sử dụng mảng (6)
• Sử dụng mảng: - Cú pháp truy cập vào các phần tử mảng:
tên_mảng[chỉ_số_1][chỉ_số_2] … [chỉ_số_n]
int a[4];
- Ví dụ:
…
10
Các truy cập hợp lệ: a[0], a[1], a[2], a[3] Các truy cập không hợp lệ: a[-2], a[-1], a[4], a[5],
Khai báo và sử dụng mảng (7)
• Sử dụng mảng: (tiếp) - Lấy địa chỉ của phần tử mảng (áp dụng cho mảng 1
chiều):
Ví dụ: &a[1]
&tên_mảng[chỉ_số];
- Tên mảng biểu thị địa chỉ đầu của mảng, tức là:
11
a = &a[0]
Các thao tác cơ bản trên mảng (1)
• Phép gán mảng: - Không được thực hiện phép gán thông thường cho
một biến mảng
- Chỉ có thể thực hiện phép gán giá trị cho các phần
tử của mảng
- Ví dụ:
int a[3] = {4,5,9},b[3],i;
Phép gán không hợp lệ: b = a; Phép gán hợp lệ:
for(i=0;i<3;i++)
12
b[i] = a[i];
Các thao tác cơ bản trên mảng (2)
Sử dụng hàm scanf để nhập dữ liệu cho từng phần tử của mảng Ví dụ: int a[10];
• Nhập dữ liệu cho mảng từ bàn phím:
Nhập dữ liệu cho phần tử a[1]: scanf("%d",&a[1]); Nhập dữ liệu cho tất cả các phần tử của mảng: sử
dụng cấu trúc lặp for
printf("a[%d] = ",i); scanf("%d",&a[i]);
int i; for(i=0;i<10;i++) {
13
}
Các thao tác cơ bản trên mảng (3)
• Nhập dữ liệu cho mảng từ bàn phím (tiếp):
Lưu ý: Phép lấy địa chỉ không áp dụng cho các phần tử của mảng nhiều chiều (trừ trường hợp mảng 2 chiều gồm các số nguyên) cần sử dụng biến trung gian khi nhập dữ liệu cho mảng nhiều chiều Ví dụ: float a[10][20];
Nhập dữ liệu cho các phần tử của mảng:
int i,j; float x; for(i=0;i<10;i++)
for(j=0;j<20;j++)
{
printf("a[%d][%d] = ",i,j); scanf("%f",&x); a[i][j] = x;
}
14
Các thao tác cơ bản trên mảng (4)
Sử dụng hàm printf để xuất dữ liệu từng phần tử của mảng ra màn hình Ví dụ: int a[10];
• Xuất dữ liệu của mảng ra màn hình:
printf("a[1] = %d",a[1]);
Xuất dữ liệu của phần tử a[1]:
Xuất dữ liệu của tất cả các phần tử mảng sử dụng
cấu trúc lặp for:
printf("a[%d] = %d\n",i,a[i]);
15
int i; for(i=0;i<10;i++) { }
Ví dụ (1)
#include
{ printf("So phan tu khong hop le, hay nhap lai!\n"); goto lap; }
16
• Chương trình nhập/xuất dữ liệu cho mảng:
Ví dụ (2)
for(i=0;i • Chương trình nhập/xuất dữ liệu cho mảng: (tiếp) { } printf("a[%d] = ",i);
scanf("%d",&a[i]); printf("Day so vua nhap la:\n");
for(i=0;i return 0;
} 17 printf("%d ",a[i]); dãy số nguyên a1, a2 , …, an • Viết chương trình tính tổng, trung bình cộng cho • Viết chương trình tìm giá trị lớn nhất, nhỏ nhất của dãy số nguyên a1, a2 , …, an • Viết chương trình tìm phần tử có giá trị là x trong
dãy số nguyên a1, a2 , …, an (số nguyên x nhập từ
bàn phím) • Viết chương trình sắp xếp dãy số nguyên a1, a2 , …, • Viết chương trình nhập vào ma trận số nguyên
(aij)mxn, in lại các giá trị vừa nhập theo dạng ma trận,
tính tổng các phần tử trong ma trận và thông báo kết
quả ra màn hình 18 an theo chiều tăng/giảm dần 19 • Khái niệm xâu ký tự
• Khai báo và sử dụng xâu ký tự
• Các hàm xử lý ký tự
• Các hàm xử lý xâu ký tự
• Một số chương trình với xâu ký tự • Là một kiểu dữ liệu có cấu trúc, bao gồm một dãy
các ký tự liên tiếp, kết thúc bởi ký tự '\0' (null – mã
ASCII là 0) • Mỗi ký tự được lưu trong 1byte
• Độ dài xâu là số ký tự có trong xâu
• Xâu rỗng là xâu không có ký tự nào
• So sánh: 20 - Xâu ký tự & mảng ký tự
- 'A' và "A" • Khai báo xâu ký tự: trong đó: char tên_xâu[n] n = số ký tự tối đa + 1 Ví dụ:
- char hoten[30];
- char s1[50], s2[100]; • Khởi tạo giá trị trong khai báo xâu ký tự: Xét các ví dụ: 21 char s[4] = {'A', 'B', 'C', '\0'};
char hoten[30] = "Luu Thanh Duyen"; #define tên_xâu giá_trị • Khai báo hằng xâu ký tự:
- Cách 1: - Cách 2: const char tên_xâu[n] = giá_trị; Ví dụ: 22 #define s1 "ABC"
const char s2[10] = "ABCDE"; • Lưu trữ dữ liệu kiểu xâu ký tự:
- Các ký tự được lưu trữ tại các byte nhớ kế tiếp nhau trong bộ nhớ - Kích thước bộ nhớ lưu trữ:
Số ký tự tối đa + 1 23 - Tương tự như dữ liệu kiểu mảng, mỗi ký tự trong
xâu được đánh chỉ số, ký tự đầu tiên có chỉ số là 0,
ký tự thứ i có chỉ số là i-1 • Sử dụng xâu ký tự:
- Cú pháp truy cập vào các ký tự trong xâu: tên_xâu[chỉ_số_ký_tự] char s[15] = "Tran Ngoc Anh";
s[0] 'T'
s[3] 'n'
s[5] 'N' 24 - Ví dụ: • Vào/ra xâu ký tự:
- Khai báo tệp tiêu đề: #include gets(tên_xâu);
scanf("%s",&tên_xâu);
- Xuất xâu ký tự ra màn hình: puts(tên_xâu);
printf("%s",tên_xâu); - Không sử dụng hàm scanf() để nhập xâu chứa ký
tự cách
- Trước khi dùng gets() cần dùng hàm fflush(stdin) 25 • Lưu ý: - Không dùng phép gán giá trị cho xâu #include • Khai báo tệp tiêu đề: hoa
Ví dụ: toupper('a') 'A' • Các hàm:
- int toupper(int ch): chuyển ký tự thường thành ký tự - int tolower(int ch): chuyển ký tự hoa thành ký tự 26 thường
Ví dụ: tolower('A') 'a' - int isalpha(int ch): kiểm tra xem ký tự có phải là chữ - int islower(int ch): kiểm tra xem ký tự có phải là cái hay không chữ cái in thường hay không - int isupper(int ch): kiểm tra xem ký tự có phải là - int isdigit(int ch): kiểm tra xem ký tự có phải là chữ chữ cái in hoa hay không số hay không - int iscntrl(int ch): kiểm tra xem ký tự có phải là ký - int isspace(int ch): kiểm tra xem ký tự có phải là ký tự điều khiển hay không (mã ASCII [0,31]) tự dấu cách (mã ASCII là 32) hay không 27 • Các ký tự đặc biệt: xuống dòng ('\n' - 10), đầu dòng
('\r' - 13), tab ngang ('\t' - 9), tab dọc ('\v' – 11), … • Khai báo tệp tiêu đề: #include sao chép toàn bộ xâu_nguồn sang xâu_đích
Để sao chép tối đa n ký tự từ xâu_nguồn sang
xâu_đích, sử dụng hàm:
char[] strncpy(char[] xâu_đích, char[] xâu_nguồn,
int n)
- char[] strcat(char[] xâu_đích, char[] xâu_nguồn): ghép nối xâu_nguồn vào ngay sau xâu_đích 28 - char[] strrev(char[] xâu_nguồn) đảo ngược các ký tự
trong xâu_nguồn, ký tự đầu về cuối, cuối về đầu • Các hàm: (tiếp)
- int strcmp(char[] xâu_1, char[] xâu_2): so sánh 2
xâu (có phân biệt ký tự in hoa – in thường), hàm trả
về giá trị: = 0 nếu 2 xâu bằng nhau
< 0 nếu xâu_1 < xâu_2
> 0 nếu xâu_1 > xâu_2 Nếu muốn so sánh 2 xâu, không phân biệt ký tự in
hoa – in thường thì sử dụng hàm: - char[] strupr(char[] tên_xâu): trả về xâu chữ in hoa int stricmp(char[] xâu_1, char[] xâu_2) tương ứng - char[] strlwr(char[] tên_xâu): trả về xâu chữ in 29 thường tương ứng #include • Khai báo tệp tiêu đề: • Các hàm:
- int atoi(char[] xâu_ký_tự): chuyển một xâu ký tự - int atol(char[] xâu_ký_tự): chuyển một xâu ký tự thành số nguyên tương ứng kiểu int thành số nguyên tương ứng kiểu long - float atof(char[] xâu_ký_tự): chuyển một xâu ký tự • Lưu ý: khi việc chuyển đổi không thành công, cả 3 thành số thực tương ứng 30 hàm trên trả về giá trị 0 Chương trình làm việc với ký tự/xâu ký tự:
#include {
if(isupper(c)) printf("Ky tu vua nhap la ky tu in hoa
'%c', ky tu in thuong tuong ung la '%c'!",c,tolower(c));
else printf("Ky tu vua nhap la ky tu in thuong '%c', ky tu
in hoa tuong ung la '%c'!",c,toupper(c));
} 31 Chương trình làm việc với ký tự/xâu ký tự (tiếp):
else if(isdigit(c)) printf("Ky tu vua nhap la ky tu so '%c'!",c); fflush(stdin);
printf("\nNhap xau ky tu s: ");gets(s);
printf("Do dai thuc cua xau la %d",strlen(s));
printf("\nXau chu in hoa tuong ung la: %s",strupr(s));
printf("\nXau chu in thuong tuong ung la: %s",strlwr(s));
printf("\nXau dao tuong ung la: %s",strrev(s));
return 0;
} 32 • Viết chương trình cho phép người dùng nhập vào
một xâu ký tự s, đếm số ký tự 'A' và 'a' có mặt trong
s, thay thế các ký tự đó bởi ký tự 'B' rồi đưa xâu mới
ra màn hình 33 • Viết chương trình cho phép người dùng nhập vào
một xâu ký tự s. Xây dựng xâu s1 gồm toàn các ký
tự chữ, s2 gồm toàn các ký tự số có trong s, thông
báo kết quả ra màn hình 34 • Định nghĩa kiểu cấu trúc
• Khai báo biến cấu trúc
• Truy nhập đến các thành phần của cấu trúc
• Mảng cấu trúc
• Phép gán cấu trúc • Cú pháp: { struct tên_kiểu_cấu_trúc khai_báo_các_thành_phần_trong_cấu_trúc; - Việc khai báo các thành phần tuân theo quy tắc khai
báo biến thông thường (tên_kiểu tên_thành_phần;)
- Kiểu dữ liệu của thành phần có thể là kiểu bất kỳ
(nguyên, thực, ký tự, mảng, xâu hay kiểu cấu trúc)
Ví dụ: struct ngaythang };
Trong đó: 35 {int ngay;
int thang;
int nam;}; struct tên_kiểu_cấu_trúc tên_biến_cấu_trúc; • Cú pháp: Ví dụ: struct ngaythang ngaysinh; • Khi có nhiều biến cùng kiểu cấu trúc, có thể khai
báo gộp với các tên biến viết ngăn cách bởi dấu ,
Ví dụ: struct ngaythang ngaydi, ngayden; cấu trúc
Ví dụ: • Có thể kết hợp khai báo và khởi tạo giá trị cho biến 36 struct ngaythang ngaysinh = {12,10,1988}; khai báo biến cấu trúc theo cú pháp: • Có thể kết hợp việc định nghĩa kiểu cấu trúc với struct tên_kiểu_cấu_trúc { khai_báo_các_thành_phần_trong_cấu_trúc;
} tên_biến_cấu_trúc1, tên_biến_cấu_trúc2, …; Ví dụ: 37 struct ngaythang
{int ngay;
int thang;
int nam;} ngaydi,ngayden; • Có thể sử dụng cú pháp sau để khai báo các biến cấu trúc: (bỏ tên_kiểu_cấu_trúc)
struct
{ khai_báo_các_thành_phần_trong_cấu_trúc;
} tên_biến_cấu_trúc1, tên_biến_cấu_trúc2, …;
Chỉ khai báo các biến cấu trúc, không định nghĩa kiểu cấu trúc
Ví dụ: {int ngay;
int thang;
int nam;} ngaydi,ngayden; 38 struct • Có thể sử dụng cú pháp typedef để định nghĩa kiểu cấu trúc: { typedef struct khai_báo_các_thành_phần_trong_cấu_trúc; } tên_kiểu_cấu_trúc; Khi đó, cú pháp khai báo biến cấu trúc sẽ là:
tên_kiểu_cấu_trúc tên_biến_cấu_trúc; Ví dụ: typedef struct
{int ngay;
int thang;
int nam;} ngaythang; 39 Khai báo biến ngaysinh: ngaythang ngaysinh; tên_cấu_trúc.tên_thành_phần • Cú pháp: Ví dụ: 40 printf("%d",ngaysinh.ngay);
ngaydi.ngay = ngayden.ngay+2;
ngaydi.thang = 12;
… một kiểu cấu trúc đã được định nghĩa trước đó
Ví dụ: • Có thể khai báo một mảng gồm các phần tử thuộc struct ngaythang ngaythuephong[10]; ngaythuephong là một mảng có 10 phần tử. Mỗi
phần tử là một cấu trúc kiểu ngaythang 41 • Lưu ý: Khi nhập dữ liệu cho mỗi phần tử trong
mảng cấu trúc, cần nhập dữ liệu cho từng thành
phần trong cấu trúc • Khi các biến cấu trúc và các phần tử của mảng cấu
trúc là cùng kiểu với nhau, có thể thực hiện các
phép gán giá trị: - Gán giá trị của biến cấu trúc này cho một biến cấu - Gán giá trị của biến cấu trúc cho phần tử mảng cấu trúc khác trúc và ngược lại - Gán giá trị của phần tử mảng cấu trúc này cho phần Mỗi phép gán cấu trúc tương đương với một dãy tử mảng cấu trúc khác 42 phép gán các thành phần tương ứng cho nhau Khai báo:
struct ngaythang ngay1,ngay2,ngaythue [10],ngaytra[10];
Các phép gán sau đều là hợp lệ: • Ví dụ: 43 ngay1 = ngay2;
ngaythue[0] = ngay1;
ngay2 = ngaytra[0];
ngaythue[0] = ngaytra[0]; • Chương trình nhập/hiển thị danh sách n cán bộ:
#include {
struct canbo char macb[6];
char hoten[30];
char mapb[6]; { struct canbo dscb[50];
int i,n;
printf("Nhap so can bo n = ");scanf("%d",&n); 44 }; for(i=0;i printf("Nhap can bo thu %d\n",i);
fflush(stdin);
printf("Ma can bo: ");gets(dscb[i].macb);
printf("Ho ten: ");gets(dscb[i].hoten);
printf("Ma pb: ");gets(dscb[i].mapb); { } printf("%-6s %-30s %-6s\n", printf("Danh sach can bo vua nhap la:\n");
for(i=0;i dscb[i].macb,dscb[i].hoten,dscb[i].mapb); return 0; 45 }Một số chương trình với mảng
4.2. Kiểu xâu ký tự
Khái niệm xâu ký tự
Khai báo và sử dụng xâu ký tự (1)
Khai báo và sử dụng xâu ký tự (2)
Khai báo và sử dụng xâu ký tự (3)
Khai báo và sử dụng xâu ký tự (4)
Khai báo và sử dụng xâu ký tự (5)
Các hàm xử lý ký tự (1)
Các hàm xử lý ký tự (2)
Các hàm xử lý xâu ký tự (1)
Các hàm xử lý xâu ký tự (2)
Các hàm xử lý xâu ký tự (3)
Ví dụ (1)
Ví dụ (2)
Một số chương trình với xâu ký tự
4.3. Kiểu cấu trúc
Định nghĩa kiểu cấu trúc
Khai báo biến cấu trúc (1)
Khai báo biến cấu trúc (2)
Khai báo biến cấu trúc (3)
Lưu ý
Truy nhập đến các thành phần của cấu trúc
Mảng cấu trúc
Phép gán cấu trúc (1)
Phép gán cấu trúc (2)
Ví dụ (1)
Ví dụ (2)