C++ STRUCTURES – CẤU TRÚC C++ > Iron Hack Việt Nam

1. Cấu trúc C++

Cấu trúc là một tập hợp các biến của các kiểu dữ liệu khác nhau dưới một tên duy nhất. Nó tương tự như một lớp (class) ở chỗ, cả hai đều chứa một tập hợp dữ liệu thuộc các kiểu dữ liệu khác nhau.

Ví dụ:

Khi bạn muốn lưu trữ một số thông tin về một người như: tên, số căn cước, và mức lương của người đó. Bạn có thể dễ dàng tạo các biến khác nhau: name, citNo, salary để lưu trữ riêng lẻ các thông tin này.

Tuy nhiên, trong tương lai, khi bạn muốn lưu trữ thông tin của nhiều người hơn. Bây giờ, bạn cần tạo những biến khác nhau cho mỗi thông tin của mỗi người: name1, citNo1, salary1, name2, citNo2, salary2.

Bạn có thể dễ dàng hình dung ra code sẽ nhiều và lộn xộn như thế nào. Ngoài ra, vì không tồn tại mối quan hệ giữa các biến (thông tin) nên nhiệm vụ này sẽ lại càng khó khăn.

Một cách giải quyết tốt hơn đó là tạo một bộ sưu tập tất cả thông tin liên quan dưới một tên duy nhất là Person và sử dụng nó cho mọi người. Bây giờ, code trông sẽ gọn gàng hơn, dễ đọc và hiệu quả hơn.

Tập hợp tất cả các thông tin liên quan dưới một tên riêng Person gọi là một cấu trúc.

1.1. Cách khai báo cấu trúc trong lập trình C++

Từ khóa struct xác định một kiểu cấu trúc theo sau là một định danh (tên của cấu trúc).

Khi đó, bên trong dấu ngoặc nhọn, bạn có thể khai báo một hoặc nhiều thành phần (khai báo các biến bên trong dấu ngoặc nhọn) của cấu trúc đó. Ví dụ:

struct Person

{

    char name[50];

    int age;

    float salary;

};

Đây là cấu trúc person được xác định với ba thành phần: name, age và salary.

Khi một cấu trúc được tạo, không có bộ nhớ nào được cấp phát.

Định nghĩa cấu trúc chỉ là bản thiết kế để tạo các biến. Bạn có thể hình dung nó như một kiểu dữ liệu. Khi bạn xác định một số nguyên như sau:

int foo;

Int chỉ định rằng, biến foo chỉ có thể chứa phần tử nguyên. Tương tự, định nghĩa cấu trúc chỉ xác định thuộc tính mà một biến cấu trúc giữ khi nó được định nghĩa.

Lưu ý: Hãy nhớ kết thúc khai báo bằng dấu chấm phẩy (;)

1.2. Cách xác định biến cấu trúc

Khi bạn khai báo cấu trúc person như ở trên. Bạn có thể xác định biến cấu trúc như sau:

Person bill;

Ở đây, biến cấu trúc được xác định có cấu trúc kiểu person.

Chỉ khi biến cấu trúc được xác định, bộ nhớ cần thiết mới được trình biên dịch cấp phát.

Nếu bạn có hệ thống 32 bit hoặc 64 bit, bộ nhớ của float là 4 byte, bộ nhớ của int là 4 byte và bộ nhớ của char là 1 byte.

Do đó, 58 byte bộ nhớ sẽ được cấp phát cho biến cấu trúc bill.

1.3. Cách truy cập thành phần của một cấu trúc

Các thành phần của biến cấu trúc được truy cập bằng cách sử dụng toán tử dấu chấm (.).

Giả sử, bạn muốn truy cập độ tuổi của biến cấu trúc bill và gán 50 cho nó. Bạn có thể thực hiện bằng cách sử dụng code sau:

bill.age = 50;

Ví dụ: Chương trình gán dữ liệu cho các thành phần của một biến cấu trúc và hiển thị nó.

#include <iostream>

using namespace std;

 

struct Person

{

    char name[50];

    int age;

    float salary;

};

 

int main()

{

    Person p1;

    

    cout << “Enter Full name: “;

    cin.get(p1.name, 50);

    cout << “Enter age: “;

    cin >> p1.age;

    cout << “Enter salary: “;

    cin >> p1.salary;

 

    cout << “\nDisplaying Information.” << endl;

    cout << “Name: “ << p1.name << endl;

    cout <<“Age: “ << p1.age << endl;

    cout << “Salary: “ << p1.salary;

 

    return 0;

}

Đầu ra

Enter Full name: Magdalena Dankova

Enter age: 27

Enter salary: 1024.4

 

Displaying Information.

Name: Magdalena Dankova

Age: 27

Salary: 1024.4

Ở đây, cấu trúc Person được khai báo có ba thành phần: name, age và salary.

Bên trong hàm main(), một biến cấu trúc p1 được xác định. Sau đó, người dùng được yêu cầu nhập thông tin và dữ liệu do người dùng nhập sẽ được hiển thị.

  1. Cấu trúc và hàm trong C++

Các biến cấu trúc có thể được truyền cho một hàm và được trả về theo cách tương tự như các đối số thông thường.

Truyền cấu trúc cho hàm trong C++

Một biến cấu trúc có thể được truyền cho một hàm theo cách tương tự như đối số bình thường. Hãy xem ví dụ bên dưới:

Ví dụ 1: Cấu trúc và hàm

#include <iostream>

using namespace std;

 

struct Person

{

    char name[50];

    int age;

    float salary;

};

 

void displayData(Person);   // Function declaration

 

int main()

{

    Person p;

 

    cout << “Enter Full name: “;

    cin.get(p.name, 50);

    cout << “Enter age: “;

    cin >> p.age;

    cout << “Enter salary: “;

    cin >> p.salary;

 

    // Function call with structure variable as an argument

    displayData(p);

 

    return 0;

}

 

void displayData(Person p)

{

    cout << “\nDisplaying Information.” << endl;

    cout << “Name: “ << p.name << endl;

    cout <<“Age: “ << p.age << endl;

    cout << “Salary: “ << p.salary;

}

Đầu ra

Enter Full name: Bill Jobs

Enter age: 55

Enter salary: 34233.4

 

Displaying Information.

Name: Bill Jobs

Age: 55

Salary: 34233.4

Trong chương trình này, người dùng được yêu cầu nhập tên, tuổi và lương của một người bên trong hàm main().

Sau đó, biến cấu trúc p được sử dụng bằng cách chuyển cho một hàm.

displayData(p);

Kiểu trả về của displayData() là void và một đối số của cấu trúc kiểu person được truyền vào.

Sau đó, các thành phần của cấu trúc p được hiển thị từ hàm này.

Ví dụ 2: Trả về cấu trúc từ hàm

#include <iostream>

using namespace std;

 

struct Person {

    char name[50];

    int age;

    float salary;

};

 

Person getData(Person); 

void displayData(Person); 

 

int main()

{

 

    Person p;

 

    p = getData(p);   

    displayData(p);

 

    return 0;

}

 

Person getData(Person p) {

 

    cout << “Enter Full name: “;

    cin.get(p.name, 50);

 

    cout << “Enter age: “;

    cin >> p.age;

 

    cout << “Enter salary: “;

    cin >> p.salary;

 

    return p;

}

 

void displayData(Person p)

{

    cout << “\nDisplaying Information.” << endl;

    cout << “Name: “ << p.name << endl;

    cout <<“Age: “ << p.age << endl;

    cout << “Salary: “ << p.salary;

}

Đầu ra của chương trình này cũng giống đầu ra của chương trình trên.

Trong chương trình này, biến cấu trúc p của kiểu cấu trúc person được xác định dưới hàm main().

Biến cấu trúc p được truyền vào hàm getData() để nhận đầu vào từ người dùng sau đó được trả về hàm chính.

p = getData(p);

Lưu ý: Giá trị của tất cả các thành phần của một biến cấu trúc có thể được gán cho một cấu trúc khác, bằng cách sử dụng toán tử gán = nếu cả hai biến cấu trúc cùng kiểu. Bạn không cần phải chỉ định từng thành phần theo cách thủ công.

Sau đó, biến cấu trúc p được chuyển đến hàm displayData(), cũng là hàm hiển thị thông tin.

  1. Từ con trỏ đến cấu trúc trong C++

Một biến con trỏ có thể được tạo ra không chỉ cho các kiểu gốc (như int, float, double v.v…) mà còn có thể được tạo cho các kiểu do người dùng xác định như cấu trúc.

Nếu bạn không biết con trỏ là gì hãy xem con trỏ trong C++.

Đây là cách tạo con trỏ cho các cấu trúc:

#include <iostream>

using namespace std;

 

struct temp {

    int i;

    float f;

};

 

int main() {

    temp *ptr;

    return 0;

}

Chương trình này tạo con trỏ ptr cho kiểu cấu trúc temp.

Ví dụ: 

#include <iostream>

using namespace std;

 

struct Distance

{

    int feet;

    float inch;

};

 

int main()

{

    Distance *ptr, d;

 

    ptr = &d;

    

    cout << “Enter feet: “;

    cin >> (*ptr).feet;

    cout << “Enter inch: “;

    cin >> (*ptr).inch;

 

    cout << “Displaying information.” << endl;

    cout << “Distance = “ << (*ptr).feet << ” feet “ << (*ptr).inch << ” inches”;

 

    return 0;

}

Đầu ra

Enter feet: 4

Enter inch: 3.5

Displaying information.

Distance = 4 feet 3.5 inches

Trong chương trình này, một biến con trỏ ptr và biến bình thường d của cấu trúc distance được xác định.

Địa chỉ của biến d được lưu trữ trong biến con trỏ, tức là ptr đang trỏ tới biến d. Sau đó, hàm thành viên của biên d được truy cập bằng con trỏ.

Lưu ý: vì con trỏ ptr đang trỏ đến biến d trong chương trình này, (*ptr).inch và d.inch chính xác cùng một ô. Tương tự. (*ptr).feet và d.feet là cùng một ô.

Cú pháp để truy cập hàm thành viên bằng cách sử dụng con trỏ là không tốt nhưng có một ký hiệu thay thế phổ biến hơn là -> 

ptr->feet is same as (*ptr).feet

ptr->inch is same as (*ptr).inch

  1. Liệt kê trong C++

Liệt kê là một kiểu dữ liệu do người dùng xác định bao gồm các hằng số tích phân. Trong đó từ khóa enum được sử dụng để xác định một kiểu liệt kê.

enum season { spring, summer, autumn, winter };

Ở đây, tên của phép liệt kê là season. Và spring, summer, autumn và winter là các biến của season.

Theo mặc định, spring là 0, summer là 1, v.v…nhưng  bạn vẫn có thể thay đổi giá trị mặc định của phần tử trong enum khi khai báo (nếu cần).

enum season 

{   spring = 0, 

    summer = 4, 

    autumn = 8,

    winter = 12

};

4.1. Khai báo kiểu liệt kê

Khi bạn tạo kiểu liệt kê, chỉ có bản thiết kế cho biến được tạo. Đây là cách bạn có thể tạo các biến kiểu enum.

enum boolean { false, true };

 

// inside function

enum boolean check;

Ở đây, biến check của kiểu enum boolean được tạo.

Cũng có cách khác để khai báo biến check bằng cách sử dụng cú pháp syntax:

enum boolean 

   false, true

} check;

Ví dụ 1: Kiểu liệt kê

#include <iostream>

using namespace std;

 

enum week { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };

 

int main()

{

    week today;

    today = Wednesday;

    cout << “Day “ << today+1;

    return 0;

}

Đầu ra

Day 4

Ví dụ 2: Thay đổi giá trị mặc định của Enums

#include <iostream>

using namespace std;

 

enum seasons { spring = 34, summer = 4, autumn = 9, winter = 32};

 

int main() {

 

    seasons s;

 

    s = summer;

    cout << “Summer = “ << s << endl;

 

    return 0;

}

Đầu ra

Summer = 4

4.2. Tại sao enums được sử dụng trong lập trình C++

Một biến enum chỉ nhận một giá trí trong số nhiều giá trị có thể có. Ví dụ bên dưới sẽ chứng minh điều đó:

#include <iostream>

using namespace std;

 

enum suit {

    club = 0,

    diamonds = 10,

    hearts = 20,

    spades = 3

} card;

 

int main() 

{

    card = club;

    cout << “Size of enum variable “ << sizeof(card) << ” bytes.”;   

    return 0;

}

Đầu ra

Size of enum variable 4 bytes.

Đó chính là vì kích thước của một số nguyên là 4 byte, làm cho enum trở thành một lựa chọn tốt để làm việc với các flag.

Bạn có thể hoàn thành tác vụ tương tự bằng cách sử dụng cấu trúc C++. Tuy nhiên, làm với enums sẽ mang lại cho bạn hiệu quả và linh hoạt hơn.

4.3. Cách sử dụng enums cho flag

Hãy xem một ví dụ:

enum designFlags {

ITALICS = 1,

BOLD = 2,

UNDERLINE = 4

} button;

Giả sử bạn đang thiết kế một nút cho ứng dụng Windows. Bạn có thể đặt flag ITALICS, BOLD và UNDERLINE để làm với văn bản.

Có một lý do cho câu hỏi tại sao tất cả các hằng số tích phân là lũy thừa của 2 trong các mã giả trên.

// In binary

 

ITALICS = 00000001

BOLD = 00000010

UNDERLINE = 00000100

Vì hằng số tích phân là lũy thừa của 2, bạn có thể kết hợp hai hoặc nhiều flag cùng một lúc mà không chồng chéo bằng cách sử dụng bitwise OR | operator. Nó cho phép bạn chọn 2 hoặc nhiều flag cùng một lúc. Ví dụ:

#include <iostream>

using namespace std;

 

enum designFlags {

    BOLD = 1,

    ITALICS = 2,

    UNDERLINE = 4

};

 

int main() 

{

    int myDesign = BOLD | UNDERLINE; 

 

        //    00000001

        //  | 00000100

        //  ___________

        //    00000101

 

    cout << myDesign;

 

    return 0;

}

Đầu ra

5

Khi đầu ra là 5, bạn luôn biết rằng BOLD và UNDERLINE được sử dụng.

Ngoài ra, bạn có thể thêm flag theo nhu cầu của mình.

if (myDesign & ITALICS) {

    // code for italics

}

Ở đây, tôi đã thêm ITALICS vào thiết kế của mình. Lưu ý rằng chỉ code cho ITALICS được viết bên trong câu lệnh if.

Bạn có thể hoàn thành hầu hết mọi thứ trong lập trình C++ mà không sử dụng phép liệt kê. Tuy nhiên, chúng có thể rất tiện dụng trong một số trường hợp nhất định. Nó thể hiện sự khác biệt giữa những lập trình viên xuất sắc với những lập trình viên giỏi.