1. Khai báo cấu trúc lồng:
Để cho rễ hiểu Tôi khai báo thông qua 1 ví dụ sau: có khai báo
Typedef struct {
int ns;(ngày sinh) int ts;(tháng sinh) int ns;(năm sinh) } ngay;
Typedef struct {
Char họtên[20]; /*mảmg kí tự có 20 kí tự*/ Char quequan[20]; /*t−ơng tự trên*/
ngay ngàysinh; }sinhviên;
Khi đó việc truy nhập tới cấu trúc của tr−ờng ngày nh− sau: (với giả sử biến ds[i] là biến cấu trúc kiểu sinhviên)
ds[i].ngàysinh.ngày
Còn mọi công việc giống hệt nh− cấu trúc không lồng nhaụ Tuy vậy Tôi vẫn lấy ví dụ để bạn tham khảo thêm.
VD: typedef struct { int ngay,thang,nam; }ngsinh; typedef struct { char ht[25]; char qq[25]; ngsinh ns; int tuoi; }hocsinh;
void tim(hocsinh *p,int n); void in(hocsinh p);
void vaosl(hocsinh *p,int n) {
int i;
for(i=0;i<n;i++) {
fflush(stdin);
printf("\n nhap ho ten nguoi thu %d: ",i);fflush(stdin); gets(p[i].ht);
printf("\n nhap que quan:");fflush(stdin); gets(p[i].qq);
printf("\n ngay sinh:");scanf("%d",&p[i].ns.ngay); printf("\n thang sinh:");scanf("%d",&p[i].ns.thang); printf("\n nam sinh:");scanf("%d",&p[i].ns.nam); printf("\n nhap tuoi:");scanf("%d",&p[i].tuoi); }
}
void tim(hocsinh *p,int n) {
int i;
char ht[25],ch; while(1) {
tt:printf("nhap nguoi can tim:");fflush(stdin); gets(ht);
if(ht[0]==0) break; for(i=0;i<n;i++)
if(strcmp(ht,p[i].ht)==0) in(ds[i]); /*lời gọi hàm in(p)*/ ch=getch();
if(ch=='c'||ch=='C')goto tt; }
}
{
printf("*****************Ket qua chay********************\n"); printf("\n Ho ten nguoi thu %d: %s ",i+1,p[i].ht);
printf("\n Que quan: %s ",p[i].qq);
printf("\n Ngay sinh : %d ",p[i].ns.ngay); printf("\n Thang sinh : %d ",p[i].ns.thang); printf("\n Nam sinh : %d ",p[i].ns.nam); printf("\n Tuoi : %d ",p[i].tuoi);
printf("__________________________________________\n"); } main() { hocsinh ds[10]; int i,n; clrscr(); printf(“nhap n:=”);scanf(“%d”,&n); vaosl(ds,n);
printf("*********Ket qua tim**********************\n"); tim(ds,n); for(i=0;i<n;i++) in(ds[i]); getch(); } C. Khai báo động:
Khai báo động cũng là 1 hình thức l−u trữ kế tiếp. Nh−ng nó khác khai báo tĩnh ở trên là ở chỗ cần đến đâu khai báo đến đấy, với mục đích là tiết kiệm bộ nhớ.
Nếu trong khai báo tĩnh là: sinhviên ds[20]; tức là bạn đã ấn định 20 chỗ để l−u trữ 1 danh sách có cấu trúc kiểu sinhviên.
Còn trong khai báo động bạn không làm nh− vậy, mà bạn phải khai báo thêm 1 con trỏ kiểu sinhviên để nhập dữ liệụ
Cú pháp :
Tên con trỏ =(tên kiểu cấu trúc*)malloc(n+1)*sizeof(tên kiểu cấu trúc); trong đó:
- Tên con trỏ : Là tên do bạn đặt nó có kiểu là kiểu cấu trúc. - n : Là số phần tử của cấu trúc do bạn nhập vàọ
- Kiểu cấu trúc : Là kiểu mà bạn đã định nghĩa nó gồm các tr−ờng. VD: Có khai báo: typedef struct { char ht[25]; char qq[25]; int tuổi ; }hocsinh;
Bạn hãy nhập số ng−ời khoảng 5 ng−ời vào và cho hiển thị lên màn hình số ng−ời vừa nhập. #include<stdiọh> #include<coniọh> #include<string.h> #include<alloc.h> typedef struct { char ht[20]; char qq[20]; int tuoi; }sinhvien; main() { int songuoi,i; sinhvien *p; tt:printf("nhap so nguoi:");scanf("%d",&songuoi);
if (songuoi>5) goto tt; /*nếu số ng−ời nhập >5 thì quay lại chỗ tt: để nhập lại*/ p=(sinhvien*)malloc((songuoi+1)*sizeof(sinhvien));
for(i=0;i<songuoi;i++) {
fflush(stdin);
printf("\n nhap ho ten:");gets(p[i].ht); fflush(stdin);
printf("\n nhap que quan:");gets(p[i].qq); printf("\n nhap tuoi:");scanf("%d",&p[i].tuoi); }
for(i=0;i<songuoi;i++) {
printf("\n ho ten:%s",p[i].ht); printf("\n que quan:%s",p[i].qq); printf("\n tuoi:%d",p[i].tuoi); }
getch(); }
Qua ví dụ trên cho thấy khai báo động và khai báo tĩnh chỉ khác nhau hai điểm sau:
- Nhập dữ liệu cho danh sách trong khai báo động bắt buộc phải nhập bằng con trỏ. Còn trong khai báo tĩnh thì có thể là con trỏ hoặc không cần con trỏ.
- Nếu là khai báo động thì có cú pháp khai báo động riêng. Còn sau đó tất cả mọi công việc và cách làm đều nh− nhaụ
Bây giờ Tôi xẽ lấy một ví dụ tổng hợp các công việc để bạn đ−ợc rõ hơn. Nếu bạn ch−a thành thạo việc truyền đối trong lời gọi hàm, thì hãy quan sát thật kĩ việc truyền đối trong ch−ơng trình nàỵ Với một chú ý là tất cả các tham biến ,tham trị trong mỗi hàm là hoàn toàn khác nhau mặc dù chúng có tên giống nhaụ Điển hình là biến con trỏ *p1 trong ch−ơng trình nàỵ
VD:
Nhập vào một danh sách sinh viên có số ng−ời do bạn quyết định. Yêu cầu mỗi sinh viên đ−ợc nhập có đủ các thông tin :họ tên, quê quán và tuổị
Ch−ơng trình : #include<stdiọh> #include<coniọh> #include<string.h> #include<alloc.h> typedef struct { char ht[20]; char qq[20];
int tuoi; }sinhvien;
void nhap(sinhvien *p1,int songuoi); void in(sinhvien p1);
void sxep(sinhvien *p1,int songuoi); void tim(sinhvien *p1,int songuoi); void nhap(sinhvien *p1,int songuoi) {
int i;
for(i=0;i<songuoi;i++) {
fflush(stdin);
printf("\n nhap ho ten:");gets(p1[i].ht); fflush(stdin);
printf("\n nhap que quan:");gets(p1[i].qq); printf("\n nhap tuoi:");scanf("%d",&p1[i].tuoi); }
}
void tim(sinhvien *p1,int songuoi) { int i; char hoten[20]; while(1) { fflush(stdin);
printf("\n nhap ho ten:"); gets(hoten); if(hoten[0]==0) break; for(i=0;i<songuoi;i++) if(strcmp(p1[i].ht,hoten)==0) in(p1[i]); } }
void sxep(sinhvien *p1,int songuoi) {
int i,j; sinhvien tg; for(i=0;i<songuoi-1;i++) for(j=i+1;j<songuoi;j++) if(p1[i].tuoi>p1[j].tuoi) { tg=p1[i]; p1[i]=p1[j]; p1[j]=tg; } } void in(sinhvien p1) { printf("\n ho ten:%s",p1.ht); printf("\n que quan:%s",p1.qq); printf("\n tuoi:%d",p1.tuoi); } main() { clrscr(); int songuoi,i; sinhvien *p; tt:printf("nhap so nguoi:");scanf("%d",&songuoi); if (songuoi>5) goto tt; p=(sinhvien*)malloc((songuoi+1)*sizeof(sinhvien)); nhap(p,songuoi); sxep(p,songuoi); for(i=0;i<songuoi;i++) in(p[i]); tim(p,songuoi); getch(); }
IIỊ Cấu trúc l−u trữ móc nối :
Đây là phần (theo Tôi đánh giá) khó nhất trong ch−ơng trình C vì nó rất phức tạp từ việc khai báo đến sử dụng. Phần này để hiểu đ−ợc yêu cầu bạn phải có một chút kiến thức môn giải thuật, nói vậy không phải để bạn nản lòng bạn phải biết đây là phần cực kì quan trọng và bao giờ nó cũng chiếm 50% số điểm của bài thị Nh−ng không sao chúng ta xẽ cố gắng phơi bày bản chất của nó thông qua lời giải thích và những ví dụ cụ thể.