Lập trình C: Bài 13 – Kiểu cấu trúc – struct
Nội dung
Cách đơn giản nhất để tiếp cận về kiểu cấu trúc là xét ví dụ sinh viên. Một lớp có 100 sinh viên mỗi sinh viên gồm họ tên và mã sinh viên. Hãy nhập dữ liệu cho lớp đó. Hehe. Bạn nghĩ đến cách dùng 2 mảng: 1 mảng lưu tên, 1 mảng lưu mã sinh viên đúng không. Đúng, cách đó không sai… nhưng hãy xem yêu cầu tiếp theo… Thi học kỳ xong, hãy nhập điểm cho từng sinh viên, mỗi sinh viên gồm 10 môn (Toán, Tin, Hóa, Vật lý,…). Giờ bạn thấy sao nào… Dùng 12 mảng chăng… ồ không nên, hãy dùng kiểu cấu trúc. Với kiểu cấu trúc chỉ cần 1 mảng mà thôi.
1. Kiểu cấu trúc
Đối với mảng, chỉ có thể lưu nhiều thông tin có cùng kiểu dữ liệu. Nhưng với kiểu cấu trúc ta có thể lưu thông tin có nhiều kiểu dữ liệu khác nhau.
1.1 VD mở đầu
//code by nguyenvanquan7826 #include <stdio.h> #include <stdlib.h> // khai bao struct struct sinhvien { char MSV[20]; // ma sinh vien char hoten[30]; // ho ten sinh vien double toan, tin, anh; // cac diem toan, tin, anh }; /* Hay thay tat ca fflush(stdin); thanh __fpurge(stdin) khi ban lam tren linux*/ int main() { /* khai bao 2 bien sv1, sv2 va 1 mang * CNPMK10A gom 100 sinh vien */ struct sinhvien sv1, sv2, CNPMK10A[100]; printf("Nhap du lieu cho sv1:\n"); printf("MSV: "); fflush(stdin); gets(sv1.MSV); printf("Ho ten: "); fflush(stdin); gets(sv1.hoten); printf("Diem toan, tin, anh: "); fflush(stdin); scanf("%lf %lf %lf", &sv1.toan, &sv1.tin, &sv1.anh); printf("Nhap du lieu cho sv2:\n"); printf("MSV: "); fflush(stdin); gets(sv2.MSV); printf("Ho ten: "); fflush(stdin); gets(sv2.hoten); printf("Diem toan, tin, anh: "); fflush(stdin); scanf("%lf %lf %lf", &sv2.toan, &sv2.tin, &sv2.anh); printf("\n --------- Thong tin sinh vien -----\n"); printf("%-20s %-30s %-7s %-7s %-7s\n", "MSV", "Ho ten", "Toan", "Tin", "Anh"); printf("%-20s %-30s %-7.2lf %-7.2lf %-7.2lf\n", sv1.MSV, sv1.hoten, sv1.toan, sv1.tin, sv1.anh); printf("%-20s %-30s %-7.2lf %-7.2lf %-7.2lf\n", sv2.MSV, sv2.hoten, sv2.toan, sv2.tin, sv2.anh); return 0; }
Kết quả:
Nhap du lieu cho sv1: MSV: DTC1 Ho ten: Pham Thi Ha Diem toan, tin, anh: 9 9 8 Nhap du lieu cho sv2: MSV: DTC2 Ho ten: Nguyen Van Quan Diem toan, tin, anh: 9 9 8 --------- Thong tin sinh vien ----- MSV Ho ten Toan Tin Anh DTC1 Pham Thi Ha 9.00 9.00 8.00 DTC2 Nguyen Van Quan 9.00 9.00 8.00
Ở VD mở đầu này, chúng ta có rất nhiều điểu phải bàn 🙂
1.2 Xây dựng kiểu cấu trúc, khai báo biến cấu trúc
Như VD trên, để xây dựng 1 kiểu cấu trúc ta thực hiện theo cú pháp:
struct TenKieuCauTruc { Khai báo các thành phần của kiểu; };
Sau khi có kiểu cấu trúc rồi thì cái kiểu đó nó tương tự như 1 kiểu bình thường (int, float, char,…) và ta chỉ việc khai báo biến nữa là xong. Tuy nhiên khai báo biến thì cần có thêm từ khóa struct ở trước: (Đối với C++ thì không cần).
struct TenKieuCauTruc TenBienCauTruc;
Ngoài ta chúng ta còn một số cách xây dựng kiểu cấu trúc và khai báo biến cấu trúc như sau:
struct TenKieuCauTruc { Khai báo các thành phần của kiểu; } danh sách các biến thuộc kiểu cấu trúc;
Hoặc
struct { Khai báo các thành phần của kiểu; } danh sách các biến thuộc kiểu cấu trúc ;
Với cách khai báo này, ta bắt buộc phải khai báo các biến cấu trúc ở ngay sau cấu trúc vì không có tên kiểu cấu trúc để cho ta khai báo ở các vị trí khác nữa.
Trong phần này ta cần đề cập đến 1 từ khóa quan trọng nữa, đó là typedef. Từ khóa này dùng để định nghĩa 1 kiểu dữ liệu mới.
typedef struct sinhvien { char MSV[20]; // ma sinh vien char hoten[30]; // ho ten sinh vien double toan, tin, anh; // cac diem toan, tin, anh } kieuSinhVien;
Khi này ta có kieuSinhVien là 1 kiểu dữ liệu (như int, double, …) và ta có thể khai báo các biến cấu trúc thông qua nó. Trong này có vài điều các bạn cần chú ý:
- Với sinhvien (kiểu cấu trúc được đặt sau từ khóa struct) thì khi khai báo biến thuộc kiểu này ta vẫn phải có từ struct ở trước nó. (VD: sinhvien svA; -> Sai còn struct sinhvien svA; -> đúng), (chú ý trong C++ thì không cần).
- Với kieuSinhVIen thì khi khai báo biến thuộc kiểu này ta không được có từ struct ở trước nó. (VD: struct kieuSinhVIen svA; -> sai, kieuSinhVIen svA; -> đúng).
Ngoài ra ta còn có thể khai báo kiểu cấu trúc lồng nhau: VD như trong 1 sinh viên có ngày sinh, trong ngày sinh lại có ngày, tháng, năm sinh.
struct ngaysinh { int ngay, thang, nam; } typedef struct sinhvien { char MSV[20]; // ma sinh vien char hoten[30]; // ho ten sinh vien double toan, tin, anh; // cac diem toan, tin, anh struct ngaysinh ns; } kieuSinhVien;
Hoặc ta khai báo ngay trong cấu trúc:
typedef struct sinhvien { char MSV[20]; // ma sinh vien char hoten[30]; // ho ten sinh vien double toan, tin, anh; // cac diem toan, tin, anh struct ngaysinh { int ngay, thang, nam; } ns; } kieuSinhVien;
1.3 Truy cập đên các thành phần của cấu trúc
Để truy nhập đến thành phần của cấu trúc ta sử dụng toán tử chấm (.).
TenBienCauTruc.TenThanhPhan;
Như VD trên ta truy cập như sau:
sv1.hoten; sv1.toan; // truy xuất tới họ tên, điểm toán
sv1.ns.ngay; sv1.ns.thang; // truy xuất tới ngày sinh và tháng sinh.
…
Khi đã truy xuất được tới các thành phần của cấu trúc thì mỗi thành phần đó là 1 biến bình thường và ta gán giá trị hoặc nhập xuất giá trị cho chúng như cách bình thường mà chúng ta vẫn làm.
Ngoài ra nếu thành phần nào đó dài dòng thì ta có thể tránh việc dài dòng này bằng cách sử dụng từ khóa define.
VD thay vì viết:
sv1.ns.thang; sv1.ns.nam;
Ta viết:
#define p sv1.ns p.thang; p.nam;
1.4 Gán các biến có cùng kiểu cấu trúc
//code by nguyenvanquan7826 #include <stdio.h> #include <stdlib.h> struct sinhvien { char MSV[20]; // ma sinh vien char hoten[30]; // ho ten sinh vien double toan, tin, anh; // cac diem toan, tin, anh }; /* Hay thay tat ca fflush(stdin); thanh __fpurge(stdin) khi ban lam tren linux*/ int main() { /* khai bao 2 bien sv1, sv2 va 1 mang * CNPMK10A gom 100 sinh vien */ struct sinhvien sv1, sv2, CNPMK10A[100]; printf("Nhap du lieu cho sv1:\n"); printf("MSV: "); fflush(stdin); gets(sv1.MSV); printf("Ho ten: "); fflush(stdin); gets(sv1.hoten); printf("Diem toan, tin, anh: "); fflush(stdin); scanf("%lf %lf %lf", &sv1.toan, &sv1.tin, &sv1.anh); sv2 = sv1; // gan gia tri cua sv1 cho sv2 printf("\n --------- Thong tin sinh vien -----\n"); printf("%-20s %-30s %-7s %-7s %-7s\n", "MSV", "Ho ten", "Toan", "Tin", "Anh"); printf("%-20s %-30s %-7.2lf %-7.2lf %-7.2lf\n", sv2.MSV, sv2.hoten, sv2.toan, sv2.tin, sv2.anh); return 0; }
Sau khi gán sv2 = sv1 thì mọi thông tin của sv1 có thì sv2 cũng có. Ngoài ra ta còn có thể gán giá trị khởi đầu cho cấu trúc.
struct sinhvien sv1 = {"ABC", "Nguyen Van Quan", 9, 9, 8, {4, 5, 1992}};
Khi đó ta có các dữ liệu ban đầu của sv1 là:
MSV: ABC hoten: Nguyen Van Quan toan: 9 tin: 9 anh: 8 ngày sinh: 4/5/1992.
2. Mảng cấu trúc
Bên trên ta đã tìm hiểu cơ bản về kiểu cấu trúc và một vài ví dụ về cấu trúc sinhvien. Bây giờ ta tìm hiểu cách biểu diễn 1 mảng 50 sinh viên của 1 lớp học có kiểu cấu trúc như trên. Ta xét VD:
//code by nguyenvanquan7826 #include <stdio.h> #include <stdlib.h> struct sinhvien { char MSV[20]; // ma sinh vien char hoten[30]; // ho ten sinh vien double diemTB; // diem trung binh struct ngaysinh { int ngay, thang, nam; } ns; }; int main() { int n = 2, i; struct sinhvien CNPMK10A[n]; for (i = 0; i < n; i++) { #define sv CNPMK10A[i] printf("Nhap du lieu cho sinh vien thu %d:\n", i + 1); printf("MSV: "); fflush(stdin) gets(sv.MSV); printf("Ho ten: "); fflush(stdin); gets(sv.hoten); printf("Diem TB: "); fflush(stdin) scanf("%lf", &sv.diemTB); printf("Ngay sinh: "); scanf("%d/%d/%d", &sv.ns.ngay, &sv.ns.thang, &sv.ns.nam); } printf("\n --------- Thong tin sinh vien -----\n"); printf("%-20s %-30s %-7s %-10s\n", "MSV", "Ho ten", "Diem Tb", "Ngay sinh"); for (i = 0; i < n; i++) { #define sv CNPMK10A[i] printf("%-20s %-30s %-7.2lf %02d/%02d/%4d\n", sv.MSV, sv.hoten, sv.diemTB, sv.ns.ngay, sv.ns.thang, sv.ns.nam); } return 0; }
Kết quả:
Nhap du lieu cho sinh vien thu 1: MSV: DTC1 Ho ten: Pham Thi Ha Diem TB: 9.2 Ngay sinh: 21/01/1993 Nhap du lieu cho sinh vien thu 2: MSV: DTC2 Ho ten: Nguyen Van Quan Diem TB: 9.2 Ngay sinh: 31/12/1992 --------- Thong tin sinh vien ----- MSV Ho ten Diem Tb Ngay sinh DTC1 Pham Thi Ha 9.20 21/01/1993 DTC2 Nguyen Van Quan 9.20 31/12/1992
3. Con trỏ cấu trúc
//code by nguyenvanquan7826 #include <stdio.h> #include <stdlib.h> struct sinhvien { char MSV[20]; // ma sinh vien char hoten[30]; // ho ten sinh vien double diemTB; // diem trung binh struct ngaysinh { int ngay, thang, nam; } ns; }; int main() { int n = 2, i; // cap phat bo nho struct sinhvien *CNPMK10A = (struct sinhvien*) malloc(n * sizeof(struct sinhvien)); for (i = 0; i < n; i++) { printf("Nhap du lieu cho sinh vien thu %d:\n", i + 1); printf("MSV: "); fflush(stdin); gets(CNPMK10A[i].MSV); printf("Ho ten: "); fflush(stdin); gets(CNPMK10A[i].hoten); printf("Diem TB: "); fflush(stdin); scanf("%lf", &(CNPMK10A+i)->diemTB); printf("Ngay sinh: "); scanf("%d/%d/%d", &(CNPMK10A+i)->ns.ngay, &(CNPMK10A+i)->ns.thang, &(CNPMK10A+i)->ns.nam); } printf("\n --------- Thong tin sinh vien -----\n"); printf("%-20s %-30s %-7s %-10s\n", "MSV", "Ho ten", "Diem Tb", "Ngay sinh"); for (i = 0; i < n; i++) { #define ns CNPMK10A[i].ns printf("%-20s %-30s %-7.2lf %02d/%02d/%4d\n", CNPMK10A[i].MSV, (*(CNPMK10A+i)).hoten, (CNPMK10A+i)->diemTB, ns.ngay, ns.thang, ns.nam); } return 0; }
Truy cập các thành phần cấu trúc
Để truy cập để lấy dữ liệu các thành phần của con trỏ cấu trúc ta có 3 cách sau:
- Cách 1: CNPMK10A[i].diemTB;
- Cách 2: (*(CNPMK10A+i)).diemTB;
- Cách 3: (CNPMK10A+i) ->diemTB;
Cả 3 cách trên đều truy cập tới DTB.
Để lấy địa chỉ ta cũng có 2 cách:
- Cách 1: &CNPMK10A[i].DTB;
- Cách 2: &(CNPMK10A+i)->diemTB
anh ơi cho em hỏi là ở đây khi mình cấp phát động để nhập vào dữ liệu cho sinh viên, khi kết thúc trương trình này không giải phóng bộ nhớ động đã cấp phát ra ạ?
Ukm đúng rồi, cái này mình quen thói quên mất, chứ đúng ra là cần phải thêm vào đó.
cảm ơn các bài của anh rất hữu ích cho sinh viên nhập môn như em ạ 😀
ngồi hóng anh làm giải phóng bộ nhớ cho bài 11++ ạ 😀
Giải phóng bộ nhớ bạn chỉ cần free các biến con trỏ sau khi dùng là xong.
vâng. em biết cách giải phóng bộ nhớ cấp phát cái này rồi ạ 😀
A ơi cho e hỏi muốn thêm 1 sinh viên vào thì phải lsao ạ
Bên trên có rồi mà.
a cho em hỏi #define ns CNPMK10A[i].ns có ý nghĩa gì ạ?
Bạn xem lại bên trên nhé. Mình đã nói nó có nghĩa là đặt một biến ns để rút gọn cho NPMK10A[i].ns
dạ! em cám ơn!
A Quân ơi cho em hỏi!!!
printf(“Nhap du lieu cho sv1:\n”);
printf(“MSV: “); fflush(stdin);
gets(sv1.MSV);
printf(“Ho ten: “); fflush(stdin); //fflush(stdin) là gì ạ???
gets(sv1.hoten); //gets(sv1.hoten) là gì ạ??nó có giống scanf(“%s” ,sv1.hoten);?
printf(“Diem toan, tin, anh: “); fflush(stdin);
scanf(“%lf %lf %lf”, &sv1.toan, &sv1.tin, &sv1.anh); //%lf là gì ạ??
fflush và gets đọc mục 4 và 5 ở bài này nhé: https://cachhoc.net/2014/12/04/lap-trinh-c-bai-2-kieu-du-lieu-va-nhap-xuat-trong-c/#4_Nhap_chuoi_trong_C
lf là ký hiệu định dạng kiểu double.
thank anh trai !!!đã hiểu
cho em hỏi như bài này làm sao để tìm trong danh sách trên thông tin về sinh viên có MSSV là X nếu
có. Hiển thị thông tin các sinh viên sinh vào tháng 3, anh chỉ em với, suy nghĩ mãi không ra :((
Đề: Viết chương trình nhập vào 1 danh sách gồm n sinh viên. Mỗi sinh viên là 1
cấu trúc bao gồm: Họ tên, giới tính, nơi sinh, ngày sinh (là 1 cấu trúc gồm ngày,
tháng và năm), MSSV, mã nhóm. Hiển thị thông tin về các sinh viên vừa nhập ra
màn hình. Hãy tìm trong danh sách trên thông tin về sinh viên có MSSV là X nếu
có. Hiển thị thông tin các sinh viên sinh vào tháng 3
Bạn so sánh chuỗi bằng hàm strcmp X với tên là được mà
anh ơi em không hiểu chỗ này :”%-20s %-30s %-7s %-10s”. mấy cái -20,-30 lái cái gì thế ạ?
dành 20.30.7.10 chỗ trống cho hiển thị các giá trị tương ứng và dấu âm là căn trái
anh ơi, ở VD gán 2 biến SV trên, liệu có cần phải gán từng trường của biến không ạ? vì những trường mang kiểu xâu ký tự có hàm gán đặc biệt là strcpy(,)
Không cần đây, cứ sv1 = sv2 là mọi giá trị trong sv2 được đưa sang sv1 hết.
dấu trừ chỗ %-20f là gì ạ
Cái %20f là để 20 khoảng trống cho việc hiển thị số. Vì vậy sẽ có các khoảng trắng đằng trước giá trị được xuất ra. Khi đó coi như ta căn phải. Nếu cho thêm dấu trừ thì ta căn trái nó.
anh có bài viết java cơ bản nào hay ko . up lên cho em tham khảo đc ko ạ
em mới hoc java cơ bản thôi- nên chưa biet gì nhiêu ạ
Ah, Cái này a không viết mấy, chỉ có 2 bài hướng đối tượng thôi
https://www.cachhoc.net/category/lap-trinh/lap-trinh-huong-doi-tuong/
printf(” %-20s %-30s %-10s %-7s \n”,”MSV”,”hoten”,”ngaysinh”,”diem trung binh”);
printf(“%-20s %-30s %-7.2lf %02d/%02d/%4d\n”, sv.MSV, sv.hoten, sv.diemTB, sv.ns.ngay, sv.ns.thang, sv.ns.nam);
những con số %-20s …. có ý nghĩ gì vậy anh. sao khi em đổi lại thành
printf(“%-20s %-30s %-10s %-8s”,”MSSV”,”HO TEN”,”NGAYSINH”,”DIEMTB”);
printf(“%-20s %-30s %d/%d/%d %-8.2f”,sv[i].msv,sv[i].ht,sv[i].ns.ngay,sv[i].ns.thang,sv[i].ns.nam,sv[i].tb);
nó lại in ra kết quả bị lệch hàng so với MSSV,HOTEN,NGAYSINH,DIEMTB
%20s là dành 20 phần trống để in chuỗi nhưng nó sẽ bị căn phải nhìn xấu, do đó dùng %-20s sẽ căn trái giúp bạn.
anh ,làm sao mình có thể canh để cho Mssv,hoten,ngaysinh,diemtb, và kết quả hiển thị tương ứng của chúng có thể cùng nằm trên 1 cột ( không bị lệch cột)…. trong bài viết này có chỗ anh ghi là %-20s %-30s %-10 %-7 v.v..thế tại sao mình phải viết như vậy. mà không phải là %-30 %-30 %-30 lun anh.
Bạn căn dòng tieu đề như nào thì các dòng giá trị làm giống nó là được. Còn cái 20 hay 30 thì tùy bạn ước chừng độ dài của các chuỗi ý mà.
vậy khi mình ước chừng , thì mình ước chừng so với lề (trái) hay là so với chuỗi đứng trước nó
vd như: %-20 rồi tới %-30 là mình ước chừng %-30 so với %-20 hay là %-30 so với lề vậy anh
Không phải thế, VD bạn ước chừng cái tên dài tối đa 50 ký tự thì bạn dùng %50 ấy bạn.
vậy 50 kí tự in ra ấy bao gồm cả phần khoản trống chừa ra + cái tên( như mssv,hoten) đúng ko anh
ukm…
printf(“\n nhap so luong sinh vien \n”);
dấu \n phía trước và phía sau của câu lệnh phía trên khác nhau chỗ nào anh
giong nhau. deu la xuong dong thoi.
dấu \n phía trước là đưa dòng : nhap so luong sinh vien xuống dòng .còn dấu \n phía sau là đưa câu lệnh tiep theo xuong dong phải ko anh
Đúng rồi bạn.
typedef struct sinhvien {
char MSV[20]; // ma sinh vien
char hoten[30]; // ho ten sinh vien
double toan, tin, anh; // cac diem toan, tin, anh
} kieuSinhVien;
chỗ ni mình ko khai báo :” sinhvien” mà khai báo lun “kieuSinhvien” dc ko anh. em thấy khai báo như trên thì kieu cau truc “sinhvien” đâu có dùng anh !
ok, như vậy cũng được bạn ah.
Anh nguyenvanquan cho em hoi:
ở trên anh có nói có 3 cách để lấy dữ liệu các thành phần của con trỏ cấu trúc :
Cách 1: CNPMK10A[i].diemTB;
Cách 2: (*(CNPMK10A+i)).diemTB;
Cách 3: (CNPMK10A+i) ->diemTB;
Em thấy khó hiểu trong cách 1 với phần lấy dịa chỉ con trỏ ở bài con trỏ ma anh viết:
px : Lấy địa chỉ mà nó lưu giữ (trỏ tới)
*px : Lấy giá trị trong vùng nhớ mà nó trỏ tới.
Anh chi giúp em với khó hiểu quá. Em cảm ơn anh.
Khó hiểu là thế nào chứ, đó là nguyên tắc của nó mà.
anh ơi.. thế em muốn tìm tên những sinh viên có điểm toán cao nhất thì làm như thế nào ạ 🙂
Thì so sánh mà tìm, bình thường mình so sánh a > b thì giờ so sánh A.x > B.x là được
C# có struct, vậy trong java có cái gì tương tự như struct k ( k tính đến class ở đây)
thực sự là mình chưa nắm vững về java nên mới hỏi câu này, có gì k phải mong b bỏ qua
Java không có struc bạn ah. Class có thể đảm nhiệm mọi thứ 😉
anh Quân ơi em có 1 thắc mắc nhỏ muốn anh làm sáng tỏ hộ em
đây là đoạn code của em :
/* lap chuong trinh doc vao mot danh sach khong qua 100 sinh vien gom:Ho ten, nam sinh
1, Dua ra DS nhung sinh vien sinh nam 1990
2, dua ra dssv da sap xep theo thu tu ABC */
/* thac mac tai sao khi ta dung phep hoan doi ki tu ma khong dung duoc: temp.ho_ten=danh_sach[i].ho_ten; danh_sach[i].ho_ten=danh_sach[j].hoten; danh_sach[j]=temp.ho_ten; */
#include
#include
#include
typedef struct sinh_vien
{
char ho_ten[20];
int nam;
}SV;
main()
{
int n,i,j,T;
SV danh_sach[100],temp;
do{
printf(“Nhap kich thuoc mang n (0<n<=100):");
scanf("%d",&n);
}while(n100);
printf(“\n Nhap thong tin cho tung sinh vien:\n”);
for(i=0;i<n;i++)
{
printf("\n NHap ten cua sinh vien thu %d: ",i+1);
fflush(stdin); gets(danh_sach[i].ho_ten);
printf("\n nam sinh:");
scanf("%d",&danh_sach[i].nam);
}
printf("\ndanh sach sinh vien khi chua sap xep:");
printf("\nstt Ho va ten nam sinh\n");
for(i=0;i<n;i++){
printf("%-2d %-20s %-4d\n",i+1,danh_sach[i].ho_ten,danh_sach[i].nam);
}
printf("\n danh sach cac sinh vien sinh nam 1990 la:\n");
for(i=0;i<n;i++)
if(danh_sach[i].nam==1990) printf("%-20s\n",danh_sach[i].ho_ten);
for(i=0;i<n-1;i++)
for(j=i+1;j0) {temp=danh_sach[i]; danh_sach[i]=danh_sach[j]; danh_sach[j]=temp;}
}
printf(“Danh sach sau ki da sap xep:\n”);
printf(“\nstt Ho va ten nam sinh\n”);
for(i=0;i<n;i++)
printf("%-2d %-20s %-4d\n",i+1,danh_sach[i].ho_ten,danh_sach[i].nam);
getch();
}
Hoán đổi thì bạn phải hoán đổi cả struc chứ sao lại hoán đổi mỗi tên?
a ơi cho em hỏi: em muôn truyền tham số cho hàm là con trỏ cấu trúc thì ntn vậy? thanks!
Ví dụ có cấu trúc là A thì cứ truyền void ham(A *a)
printf(“%-20s %-30s %-7s %-7s %-7s\n”, “MSV”, “Ho ten”, “Toan”, “Tin”, “Anh”);
printf(“%-20s %-30s %-7.2lf %-7.2lf %-7.2lf\n”, sv1.MSV, sv1.hoten, sv1.toan, sv1.tin, sv1.anh);
printf(“%-20s %-30s %-7.2lf %-7.2lf %-7.2lf\n”, sv2.MSV, sv2.hoten, sv2.toan, sv2.tin, sv2.anh);
giải thích giùm e vs a
Chỉ là lệnh in ra màn hình thôi mà bạn.
anh ơi, cho em hỏi: cách tìm max trong mảng kiểu cấu trúc á anh?…^^
Bạn dùng vòng lặp for rồi so sánh theo trường mà bạn muốn. Vậy thôi
anh cho em hỏi cách sắp xếp sinh viên có điểm thấp dần
em nhập :
Ten diem
a 2
b 1
c 3
Bạn làm như sắp xếp 2 số, chỉ có điều khi đổi mình đổi cả 1 struct sinh viên ý.
anh cho em hỏi cách sắp xếp sinh viên có điểm thấp dần
em nhập :
Ten diem
a 2
b 1
c 3
———
kết qả
Ten diem
a 3
b 2
c 1
điểm thì được ,nhưng sao tên nó không theo điểm của sinh viên đâu a ơi !
giúp em với.
Khi đổi bạn phải đổi cả struct sinh viên chứ.
Sao mình lại phải gán sv2=sv1 hả a ?! e không hiểu rõ chỗ này lắm
Ah thì mình gán kiểu như gân a = b ấy
E xin lỗi nhưng e vẫn chưa hiểu ý anh lắm. gán sv2=sv1 chỉ để chuyển thông tin hay có mục địch khác ?!
ad cho em hỏi,ở trên anh có đề cập là có 3 cách để truy cập để lấy dữ liệu .Vậy anh có thể giải thích giúp em điểm khác giữa 3 cách làm đó k ?(^-^)
Kết quả của nó vẫn giống nhau. Chỉ là khác về cách viết thôi bạn.
ad cho em hỏi cách viết hàm nhập và xuất danh sách sv nhưng ko đc dùng struct ạ
Bạn có thể dùng mảng. VD Sinh viên có tên, tuổi, điểm thì mình làm 3 mảng tên, tuổi, điểm.
ad hướng dẫn kỹ hơn đc ko ạ. em ko hiểu lắm.mà đề nó thế này ạ:
Thông tin thẻ độc giả cần quản lí bao gồm: mã độc giả, họ tên, CMND, ngày tháng
năm sinh, giới tính, email, địa chỉ, ngày lập thẻ và ngày hết hạn của thẻ (48 tháng
kể từ ngày lập thẻ)
Chương trình có các chức năng sau:
1. Quản lí độc giả
a. Xem danh sách độc giả trong thư viện
b. Thêm độc giả
c. Chỉnh sửa thông tin một độc giả
d. Xóa thông tin một độc giả
e. Tìm kiếm độc giả theo CMND
f. Tìm kiếm sách theo họ tên
Thì đó thẻ độc giả có những gì thì em làm cần đó mảng nếu không được dùng struct.
tks anh để em nghiên cứu
viết thế này à ad
#include
#include
void madocgia(int madg[])
{
for (int i = 0; i < 2; i++)
{
printf("Nhap ma doc gia %d: ", i);
scanf_s("%d", &madg[i]);
}
}
void cmnd(int cm[])
{
for (int j = 0; j < 2; j++)
{
printf("Nhap so CMND %d: ",j);
scanf_s("%d", &cm[j]);
}
}
void xuatma(int madg[])
{
for (int i = 0; i < 2; i++)
{
printf("%d", madg[i]);
}
}
void xuatcm(int cm[])
{
for (int j = 0; j < 2; j++)
{
printf("%d", cm[j]);
}
}
void main()
{
int a[100], b[100];
madocgia(a);
cmnd(a);
xuatma(a);
xuatcm(b);
_getch();
}
thuật toán liệt kê tổ hợp trong c++ chỉ xuất được ít trường hợp rồi ghi đè lên nên mình hỏi bạn có cách nào làm cho c++ xuất được hết tất cả các trường hợp ra mà không bị ghi đè lên không? hay có chương trình lập trình nào có thể liệt kê ra được hết các trường hợp của tổ hợp không bạn?
Bạn xem thuật toán của Lê Minh Hoàng nhé. Google là ra
anh quân. em muốn hỏi là em muốn tách ra thành các hàm con như kiểu nhập vào 1 hàm in ra 1 hàm thì làm như thế nào ạ. em thấy anh cho hết vào trong hàm main.
Thì bạn cứ viết tách hàm ra thôi.
printf(“%d”, cm[j]); lam gì anh
Để in ra chứng minh thư của người thứ i.
vd mo dau:
sao nhap msv ko duoc.
msv2 ko nhap duoc
Do bạn bị trôi lệnh. Mình nói bên trên rồi nhé, bạn thay lệnh fflush_stdin(); thành fflush(stdin) khi code trên win nhé. Mình code trong ubuntu nên dùng fflush_stdin();
#include
#include
typedef struct ngaythangnamsinh
{
int ngay,thang,nam;
}date;
typedef struct sinhvien
{
char ten[21];
char ms[11];
char lop[10];
date ns;
float dtb;
}sv;
void nhap1sv(sv &x)
{
printf(“\nnhap ho ten:”);fflush(stdin);gets(x.ten);
printf(“nhap ma so:”);fflush(stdin);gets(x.ms);
printf(“nhap lop:”);fflush(stdin);gets(x.lop);
printf(“nhap ngay thang nam sinh:”);
scanf(“%d%d%d” ,&x.ns.ngay,&x.ns.thang,&x.ns.nam);
printf(“nhap diem trung binh:”);fflush(stdin);scanf(“%f”,&x.dtb);
}
void xuat1sv(sv x)
{
printf(“\n ——— Thong tin sinh vien —–\n”);
printf(“%-20s %-15s %-15s %-15s %-15s\n”, “HoTen”, “MSSV”, “Lop”, “Ngaysinh”, “DTB”);
printf(“%-20s %-15s %-15s %d-%d-%d %15f”,x.ten,x.ms,x.lop,x.ns.ngay,x.ns.thang,x.ns.nam,x.dtb);
}
void nhapdssv(sv a[],int n)
{
printf(“hay nhap dssv”);
for(int i=0;i<n;i++)
{
printf("nhap vao thong tin sinh vien thu %:",i+1),
nhap1sv(a[i]);
}
}
int main()
{
sv x;
sv a[10];
int n;
nhapdssv(a,n);
nhap1sv(x);
xuat1sv(x);
}
aanh cho em hỏi em code không lỗi nhưng sao vòng for nó khong chạy ạ?????
Vì giá trị của n chưa có bạn ah.
dạ được rùi anh !!!cám ơn nhìu!!!
Anh Quan ơi cho em hỏi
hàm timslmax thi ok
hàm xuatspslmax thi báo lỗi!!!
int timslmax(sp a[],int n)
{
int temp=a[0].sl;
for(int i=1;i<n;i++)
{
if(temp<a[i].sl)
temp=a[i].sl;
}return temp;
}
void xuatspslmax(sp a[],int n)
{
int m =timslmax(a,n);
printf("san pham co sl max la:\n");
for(a[i].sl==m)
xuat1sp(a[i]);
}
int main()
{
sp x;
int n;
n=3;
sp a[10];
nhapdssp(a,n);
printf("%-20s %-15s %-15s\n","maso","tensp", "soluong");
xuatdssp(a,n);
xuatspslmax(a,n);
Cấu trúc hàm for(a[i].sl==m) như thế là sai rồi còn gì.
Anh cho em hỏi lỗi này là thế nào ạ mặc dù chương trình vẫn chạy bình thường.
57 2 C:\Users\Admin\Documents\bai2.c [Warning] passing argument 1 of ‘docsv’ from incompatible pointer type [enabled by default]
12 6 C:\Users\Admin\Documents\bai2.c [Note] expected ‘struct SV *’ but argument is of type ‘struct SV **’
#include
#include
typedef struct sinhvien{
char hoten[50];
int dcc;
int dth;
int dck;
double dtb;
char xephang[10];
}SV;
void docsv(SV *sv){
printf(“ho ten:”);
gets(sv->hoten);fflush(stdin);
printf(“\n”);
printf(“diem chuyyen can:”);
scanf(“%d”,&sv->dcc);printf(“\n”);
printf(“diem thuc hanh:”);
scanf(“%d”,&sv->dth);printf(“\n”);
printf(“diem cuoi ki:”);
scanf(“%d”,&sv->dck);printf(“\n”);
}
double DTB(SV *sv){
return sv->dtb=sv->dcc*0.1+sv->dth*0.3+sv->dck*0.06;
}
void insv(const SV *sv){
printf(“—–THONG TIN SINH VIEN—–\n”);
printf(“Ho ten:”);
printf(“%s”,sv->hoten);
printf(“\n”);
printf(“diem chuyen can:”);
printf(“%d”,sv->dcc);
printf(“\n”);
printf(“diem thuc hanh:”);
printf(“%d”,sv->dth);
printf(“\n”);
printf(“diem cuoi ki:”);
printf(“%d”,sv->dck);
printf(“\n”);
printf(“diem trung binh:”);
printf(“%.2lf”,sv->dtb);
printf(“\n”);
printf(“xep hang:”);
if(sv->dcc>=7&&sv->dth>=4&&sv->dck>=40)
printf(“sinh vien DO”);
else printf(“sinh vien TRUOT”);
}
int main(){
SV *sv;
docsv(&sv);
DTB(&sv);
insv(&sv);
}
A nghĩ nó chỉ là cảnh báo (Warning) thôi, ko phải lỗi.
e cảm ơn!!
Rất cho tiết a ạ
Cảm ơn anh nhiều nhé !!!
anh quan oi ham sữa một môn học nào đó làm sao vậy anh
Sửa thì trước tiên cần tìm kiếm cái cần sửa, sau đó nhập lại thông tin cho nó thôi.
cảm ơn anh..
em lam dược rồi..
Bai viet hay qua. Cam on ban rat nhieu
Cảm ơn bạn, chia sẻ cho bạn bè nữa nhé.
A oi, sao hàm chương trình con của e, phần định nghĩa hàm nó bị báo lỗi unknow type of struct.
E dung dev C a.
@@ code như thế nào e?
cho em hoi khai bao con tro trong struct dc khong va muon lay gia tri cua con tro do thi lam the nao a
Được nhé. Bạn xem bài danh sách liên kết ở đây sẽ thấy. https://cachhoc.net/2014/12/21/lap-trinh-c-bai-13-danh-sach-lien-ket-don-cai-bang-con-tro/
Anh cho em hỏi với ạ, ở chổ 2 ví dụ về từ khóa typedef, giữa sinhvien và kieusinhvien thì sinhvien là kiểu cấu trúc do ta định nghĩa, còn kieusinhvien là biến thuộc kiểu cấu trúc sinhvien phải không ạ? em hỏi như vậy vì không hiểu chú ý thứ 2 ạ, nếu nói như chú ý này thì ở đó kieusinhvien là kiểu cấu trúc da ta định nghĩa mất rồi, mong anh giải đáp.
khi dùng từ khoá typdef thì kieusinhvien là 1 kiểu.
VD:
int a // => a là biến
typedef int a //=> a là kiểu giống kiểu int.
Anh Quân cho em hỏi là khi nào trong struct mình sử dụng * ?
Ví dụ như khi mình đọc về phần treap thì cách khai báo struct node ntn :
struct Node
{
int priority;
int sz;
int value;
Node *l,*r;
};
Tại sao cái Node l,r lại phải thêm * vào đằng trước
Dấu * nghĩa là biến đó là con trỏ => Lúc nào cần dùng con trỏ thì dùng *.
Anh Quân ơi em có thắc mắc trong việc đổi chỗ trong struct:
ví dụ: struct SinhVien Sv [n] ; gồm Tên và điểm.
thì ngoài cách đổi lần lượt tên và điểm thì có thể đổi luôn Sv[ i ] với Sv[ i+1 ] được không ạ
Đk nhé.
nhưng làm kiểu gì ạ..!
em tạo thêm struct mới để làm trung gian mà không được
struct SinhVien Sv [n];
struct SinhVien temp = Sv[0] ;
Sv[0] = Sv[3] ;
Sv[3] = temp ;
anh ơi,cho em hỏi đoạn code này e sai chỗ nào đây ạ?.em dùng fflush(stdin) bao nhiêu lần nó vẫn bị cái lỗi trôi lệnh.(đoạn code chỉ đơn giản là nhập thông tin danh bạ thôi ạ).
#include
#include
#include
struct diachi {
char *quan_huyen=(char *)malloc(10*sizeof(char));
char *to=(char*)malloc(10);
};
struct danhba{
int sdt;
char *hoten =(char*)malloc (30);
diachi canhan;
}*danhbadt=(danhba *)malloc(40);
danhba newi(danhba *a){
printf(“so dien thoai moi : “);
scanf(“%d”,&a->sdt);
fflush(stdin);
printf(“ho va ten cua chu so : “);
gets(a->hoten);
fflush(stdin);
printf(“quan huyen : “);
gets(a->canhan.quan_huyen);
fflush(stdin);
printf(“to (phuong) : “);
gets(a->canhan.to);
}
int main(){
int chon;
printf(“__________________________________\n”);
printf(“1. nhap thong tin moi\n”);
printf(“2. Tim so dien thoai\n”);
printf(“3. loc so dien thoai theo dia chi\n”);
scanf(“%d”,&chon);
switch(chon){
case 1: newi(danhbadt);
break;
}
}
Em bị trôi ở lệnh nhập gì? Cứ theo nguyên tắc là sau khi nhập số mà nhập chuỗi thì xóa stdin.
e bị sai ở chỗ nhập “quan_huyen” và nhập “to” ạ. e thử xóa stdin nhiều lần rồi mà vẫn không được.
sai như thế nào bạn? Không nhập được hay nhập được nhưng không xử lý được?
a cho e hỏi có thể tách nhập sinh viên , xuất sinh viên ra 2 hàm riêng biệt dc không a?
Được nhé.
cho hỏi thầy ơi, mình chuyễn qua làm menu dc ko thầy
mình ko hiểu ý bạn.
anh ơi cho em hỏi mình ra một danh sách sau đó muốn chuyển các thành phần mình muốn thì nên làm thế nào ạ
Mình ko hiểu câu hỏi của bạn.
Bài viết của anh rất dễ hiểu, e viết 1 bài đơn giản test thử, mặc dù ko lỗi nhưng ko nhập dc mã sinh viên mà nhảy sang luôn tên sinh viên, a xem hộ e vs:
#include
#include
using namespace std;
struct sv {
char maSv[30], ten[30];
int soMon;
};
void main() {
int n, i;//n là số lượng sinh viên
cout <> n;
struct sv stt[100];//số thứ tự
for (i = 0; i < n; i++) {
#define g stt[i]
cout << "\nNhap thong tin cua sinh vien thu " << i + 1;
cout << "\nMa sinh vien : "; fflush(stdin);// đoạn này ko nhập dc mà nhảy xuống tên sv luôn
fgets(g.maSv, 30, stdin);
cout << "\nTen sinh vien : ";
fflush(stdin);
fgets(g.ten, 30, stdin);
cout <> g.soMon;
}
}
lệnh nhập cout<>n của bạn sai kìa…
a sửa hộ e với, e copy nguyên bài trong máy ra đây, đăng lên thì bị vậy, e code chạy dc rồi mà
Bạn xem lại bài số 2, mục trôi lệnh nhé.
e xem kĩ code rồi, đăng lên bị đổi mất vài chỗ, vd chỗ #include của e đăng lên bị mất phần sau,
cin >> n chuyển thành cout n, cin >> g.soMon chuyển thành cout g.soMon