Trong bài này chúng ta sẽ học cách sử dụng cấu trúc dữ liệu Struct và định nghĩa lại dữ liệu với Typedef trong lập trình C.
Bài 14 trong serie Học lập trình C từ A tới Z
Cấu trúc dữ liệu là gì
Trong quá trình xây dựng ứng dụng, ngoài các kiểu dữ liệu do ngôn ngữ lập trình C hỗ trợ, thì C còn cho phép các lập trình viên có thể tự định nghĩa các kiểu dữ liệu riêng của mình. Các kiểu dữ liệu này được gọi là kiểu dữ liệu do người dùng định nghĩa “Kiểu dữ liệu người dùng” hay kiểu dữ liệu hướng người dùng.
Cấu trúc dữ liệu là một nhóm các phần tử dữ liệu được nhóm lại với nhau trong một tên. Các phần tử dữ liệu này còn được gọi là các thành viên, có thể là các kiểu dữ liệu khác nhau và độ dài khác nhau.
Ví dụ như SinhVien là một tập dữ liệu bao gồm : Tên, ngày sinh, giới tính và số điện thoại, cân nặng … Các phần tử này có thể khác nhau về mặt dữ liệu, thế nên không thể sử dụng 1 kiểu dữ liệu đơn thuần để lưu được.
Khai báo dữ liệu cấu trúc Struct
Cú pháp khai báo
struct [ten cau truc] { phan dinh nghia thanh vien; phan dinh nghia thanh vien; ... phan dinh nghia thanh vien; } [mot hoac nhieu bien cau truc];
Ví dụ, khai báo kiểu dữ liệu sinh viên, nhưng ko tạo ra biến nào.
struct SinhVien { int maSV; char ho[20]; char ten[20]; bool gioiTinh; char queQuan[100]; };
Để tạo ra 2 biến sinh viên 1 ta làm như sau:
struct SinhVien sv1, sv2;
Hoặc có thể khai báo luôn 2 biến đó, khi khai báo kiểu dữ liệu Struct
struct SinhVien { int maSV; char ho[20]; char ten[20]; bool gioiTinh; char queQuan[100]; }sv1,sv2;
Khởi tạo giá trị ban đầu cho biến Struct
Struct có thể được khởi tạo qua nhiều cách khác nhau, điều này bao gồm cả việc như gán các hằng số giá trị cho các thành phần. Ngoài ra nếu không khởi tạo giá trị thì các biến có kiểu struct cũng sẽ khởi tạo theo kiểu không tường minh.
Ví dụ với các thành phần có kiểu integer và float sẽ tự thiết lập giá trị là 0, với char và string sẽ là ‘\0’.
Cấu trúc:
struct <structure_tag_name> { <data_type member_name1>; <data_type member_name2>; }<structure_variable1> = {constant1,constant2, . .};
Ví dụ:
struct SinhVien { int maSV; char ho[20]; char ten[20]; bool gioiTinh; char queQuan[100]; float chieucao; }sv1 = {1, "Nguyen", "Khue", "Nam", "ABCXYZ", 1,78};
Như trong ví dụ, trình biên dịch sẽ ngầm định giá trị phần từ từ trên xuống dưới tương ứng với giá trị từ trái sang phải. Nghĩa là maSV = 1, Họ = “Nguyen” …..
Ngoài ra chúng ta có thể khởi tạo một cách tường minh hơn đó là gán giá trị cho từng phần tử trong struct.
VD:
struct SinhVien { int maSV; char ho[20]; char ten[20]; bool gioiTinh; char queQuan[100]; float chieucao; }sv1 = {maSV = 1, ho = "Nguyen", ten = "Khue", gioitinh = "Nam", queQuan = "ABCXYZ", chieucao = 1.78};
Truy cập tới từng thành viên của Struct
Truy vấn từng thành viên trong biến bằng toán tử ” . “
Cú pháp:
< structure_variable >.< member_name > ;
VD:
struct myStruct { int a; int b; int c; } s1, s2;
Để truy vấn chúng là sử dụng : s1.a; s1.b
Xét theo kía cạnh lưu trữ trên bố nhớ (Giả sử int lưu trữ 2 bytes “thực tế có thể 4 bytes” và a, b, c được lưu trữ tại các ô nhớ liên tiếp “a, b, c không nhất thiết phải lưu trữ tại các ô nhớ liên tiếp” khi đó hình ảnh thể hiện như sau:
Có thể thiết lập các giá trị cho các thành phần của struct.
s1.b = 12;
Để in giá trị các thành phần thì tùy thuộc vào kiểu dữ liệu của các thành ví dụ chúng ta muốn in thông tin của thành phần b thì chúng ta sử dụng câu lệnh :
printf(“%d”, s1.b);
Các thành phần có kiểu string, kiểu mảng thì chúng ta xử lý tương tự như chúng ta đã làm.
Con trỏ Struct
Một con trỏ trỏ đến cấu trúc hay biến con trỏ có kiểu cấu trúc (struct) chỉ đơn thuần là con trỏ đó trỏ đến địa chỉ của cấu trúc đó. Lưu ý con trỏ có kiểu struct không thể tự biến đổi biến con trỏ đó thành struct được.
Cú pháp:
struct <structure_tag_name > /* Khai báo cấu trúc */ { <data_type member_name_1>; <data_type member_name_2>; . . <data_type member_name_n>; } *ptr;
Để truy vấn đến các thành phần của cấu trúc. Chúng ta sử dụng cú pháp sau :
Cú pháp
(*ptr).member_name;
Hoặc
ptr-> member_name;
Copy và so sánh Struct
Một biến được khai báo có kiểu struct có thể gán cho một biến khác có cùng kiểu struct.
Ví dụ:
struct employee { char grade; int basic; float allowance; };
struct employee nam={‘b’, 6500, 812.5};
struct employee hung;
hung = nam; // Thực hiện phép gán biến hung = nam
Thực chất khi thực hiện phép gán hung = nam đó chính là quá trình sao chép dữ liệu các thành phần tương ứng của nam cho hung.
Phép so sánh cũng tương tự
Từ khóa typedef
Từ khóa typedef cho phép lập trình viên định nghĩa kiểu dữ liệu mới từ kiểu dữ liệu đã có trong chương trình.
Cú pháp
typedef <existing data type> <new data type ,….>;
Trong đó
existing data type
: Kiểu dữ liệu đã tồn tại trong chương trình
new data type
: Kiểu dữ liệu mới
VD:
typedef struct { int maSV; char ho[20]; char ten[20]; bool gioiTinh; char queQuan[100]; }SinhVien;
Khi khai báo, chúng ta sẽ sử dụng.
SinhVien Sv1;
SinhVien Sv2;
Trong lập trình, nhiều khi các bạn sẽ thấy người ta sử dụng kiểu dữ liệu uint8_t, uint16_t, uint32_1, …. đó là kiểu dữ liệu được định nghĩa là từ unsigned int, unsigned long, ….
Bài tập về cấu trúc dữ liệu Struct
Chương trình cộng trừ nhân chia phân số trong C
#include <stdio.h> #include <string.h> #include <math.h> int UCLN(int a, int b) { a = abs(a); b = abs(b); while (a * b != 0) { if (a > b) a %= b; else b %= a; } return a + b; } int BSCNN(int a, int b) { return a * b / UCLN(a, b); } typedef struct PhanSo { int tuso, mauso; } PS; PS rutGon(PS a) { PS c; c.tuso = a.tuso / UCLN(a.tuso, a.mauso); c.mauso = a.mauso / UCLN(a.tuso, a.mauso); return c; } PS cong(PS a, PS b) { PS c; c.tuso = a.tuso * b.mauso + a.mauso * b.tuso; c.mauso = a.mauso * b.mauso; c = rutGon(c); return c; } PS tru(PS a, PS b) { PS c; c.tuso = a.tuso * b.mauso - a.mauso * b.tuso; c.mauso = a.mauso * b.mauso; c = rutGon(c); return c; } PS nhan(PS a, PS b) { PS c; c.tuso = a.tuso * b.tuso; c.mauso = a.mauso * b.mauso; c = rutGon(c); return c; } PS chia(PS a, PS b) { PS c; c.tuso = a.tuso * b.mauso; c.mauso = a.mauso * b.tuso; c = rutGon(c); return c; } void print(PS a) { printf("%d/%d", a.tuso, a.mauso); } int main() { PS a, b, c; printf("\nNhap phan so a : "); scanf("%d%d", &a.tuso, &a.mauso); printf("\nNhap phan so b : "); scanf("%d%d", &b.tuso, &b.mauso); printf("\nToi gian a ta duoc : "); a = rutGon(a); print(a); printf("\nToi gian b ta duoc : "); b = rutGon(b); print(b); printf("\nTong cua hai phan so = "); c = cong(a, b); print(c); printf("\nHieu cua hai phan so = "); c = tru(a, b); print(c); printf("\nTich cua hai phan so = "); c = nhan(a, b); print(c); printf("\nThuong cua hai phan so = "); c = chia(a, b); print(c); }
Kết quả
Quản lý sách
#include <stdio.h> #include <string.h> struct Books { char title[50]; char author[50]; char subject[100]; int book_id; }; int main( ) { struct Books Book1; /* Declare Book1 of type Book */ struct Books Book2; /* Declare Book2 of type Book */ /* book 1 specification */ strcpy( Book1.title, "C Programming"); strcpy( Book1.author, "Nuha Ali"); strcpy( Book1.subject, "C Programming Tutorial"); Book1.book_id = 6495407; /* book 2 specification */ strcpy( Book2.title, "Telecom Billing"); strcpy( Book2.author, "Zara Ali"); strcpy( Book2.subject, "Telecom Billing Tutorial"); Book2.book_id = 6495700; /* print Book1 info */ printf( "Book 1 title : %s\n", Book1.title); printf( "Book 1 author : %s\n", Book1.author); printf( "Book 1 subject : %s\n", Book1.subject); printf( "Book 1 book_id : %d\n", Book1.book_id); /* print Book2 info */ printf( "Book 2 title : %s\n", Book2.title); printf( "Book 2 author : %s\n", Book2.author); printf( "Book 2 subject : %s\n", Book2.subject); printf( "Book 2 book_id : %d\n", Book2.book_id); return 0; }
Kết quả
Book 1 title : C Programming Book 1 author : Nuha Ali Book 1 subject : C Programming Tutorial Book 1 book_id : 6495407 Book 2 title : Telecom Billing Book 2 author : Zara Ali Book 2 subject : Telecom Billing Tutorial Book 2 book_id : 6495700
Quản lý sách bằng con trỏ
#include <stdio.h> #include <string.h> struct Books { char title[50]; char author[50]; char subject[100]; int book_id; }; /* function declaration */ void printBook( struct Books *book ); int main( ) { struct Books Book1; /* Declare Book1 of type Book */ struct Books Book2; /* Declare Book2 of type Book */ /* book 1 specification */ strcpy( Book1.title, "C Programming"); strcpy( Book1.author, "Nuha Ali"); strcpy( Book1.subject, "C Programming Tutorial"); Book1.book_id = 6495407; /* book 2 specification */ strcpy( Book2.title, "Telecom Billing"); strcpy( Book2.author, "Zara Ali"); strcpy( Book2.subject, "Telecom Billing Tutorial"); Book2.book_id = 6495700; /* print Book1 info by passing address of Book1 */ printBook( &Book1 ); /* print Book2 info by passing address of Book2 */ printBook( &Book2 ); return 0; } void printBook( struct Books *book ) { printf( "Book title : %s\n", book->title); printf( "Book author : %s\n", book->author); printf( "Book subject : %s\n", book->subject); printf( "Book book_id : %d\n", book->book_id); }
Kết quả
Book title : C Programming Book author : Nuha Ali Book subject : C Programming Tutorial Book book_id : 6495407 Book title : Telecom Billing Book author : Zara Ali Book subject : Telecom Billing Tutorial Book book_id : 6495700
Kết
Cấu trúc dữ liệu Struct được sử dụng rất nhiều trong lập trình C. Với Struct chúng ta có thể quản lý thông tin một cách đơn giản hơn rất nhiều.
Nếu thấy có ích hãy chia sẻ bài viết và tham gia nhóm Nghiện Lập Trình để giao lưu và học hỏi nhé
cảm ơn bạn rất nhiều ạ