Title Text

Struct

(大量)參考2022竹區第8週投影片

目錄

Struct是什麼

Struct的語法

Nested Struct

struct *ptr

為什麼需要Struct

酷酷的補充

Struct是什麼

C語言中,結構體(struct)指的是一種資料結構,是C語言中複合資料類型(aggregate data type)的一類。結構體可以被聲明為變數指標陣列等,用以實現較複雜的資料結構。結構體同時也是一些元素的集合,這些元素稱為結構體的成員(member),且這些成員可以為不同的類型,成員一般用名字存取。

-by wikipedia

Struct是什麼

簡單來說,struct能幫助我們將一些相關的資料儲存在同一個變數底下!

Struct是什麼

Struct是什麼

char students_name[40][10] ;
int students_ID[40] ;
double students_height[40] ;
bool students_alive[40] ;

好麻煩喔!

來用struct吧!

Struct的語法

Struct的語法-定義

struct student{
    char name[10] ;
    int ID ;
    double height ;
    bool alive ;
} ;
//記得最後面要加分號!
name, ID, height, alive 稱為 student 的屬性
struct student{
    char name[10] ;
    int ID ;
    double height ;
    bool alive ;
} ;

int main() {
    student student_1, student_2 ;
}
student 視為一個新的變數型態

Struct的語法-宣告

struct student{
    char name[10] ;
    int ID ;
    double height ;
    bool alive ;
} ;

int main() {
    //第1種初始化的方法
    student student_1 = {
    	.name = "Alice",
        .ID = 887,
        .height = 190.7,
        .alive = false
    } ;
    //第2種初始化的方法
    student_2 = {"Bob", 112, 185.4, true} ;
}
student 視為一個新的變數型態

Struct的語法-初始化

struct student{
    char name[10] ;
    int ID ;
    double height ;
    bool alive ;
} ;

int main() {
    student student_1 ;
    student_1.name = "Alice" ;
    student_1.ID = 887 ;
    student_1.height = 163.3 ;
    student_1.alive = false ;
}
變數名稱.屬性 = value

Struct的語法-賦值

struct student{
    char name[10] ;
    int ID ;
    double height ;
    bool alive ;
} ;

int main() {
    student student_1 = {"Alice", 887, 163.3, false} ;
    cout << student_1.name << "'s ID : " << student_1.ID ;
    student_1.height += student_1.ID ;
    student_1.alive = true ;
}

Struct的語法-取值

struct student{
    char name[10] ;
    int ID ;
    double height ;
    bool alive ;
} ;

int main() {
    student class_204[40] ;
    for (int i = 0; i < 40; i++) {
    	cin >> class_204[i].name ;
        cin >> class_204[i].ID ;
        cin >> class_204[i].height ;
        cin >> class_204[i].alive ;
    }
}
陣列名稱[k].屬性 = value

Struct的語法-陣列

struct student{
    char name[10] ;
    int ID ;
    double height ;
    bool alive ;
} ;

int main() {
    student class_204[3] = { 
                             {"Alice", 1, 170.3, true} ,
                             {"Bob",   2, 166.9, true} , 
                             {"Carol", 3, 190.7, false} 
                           } ;
}
變數型別 陣列名稱[N] = {{}, {}, {}, ..., {}} 

Struct的語法-陣列初始化(1)

struct student{
    char name[10] ;
    int ID ;
    double height ;
    bool alive ;
} ;

int main() {
    student class_204[2] = 
    { 
    	{
            .name = "Alice",
            .ID = 998,
            .height = 190.0,
            .alive = false
        },
        {
            .name = "Bob",
            .ID = 887,
            .height = 160.0,
            .alive = true
        }
     } ;
}
變數型別 陣列名稱[N] = 
{
 { 
   .a = val_1,
   .b = val_2
 }, 
 { 
   .a = val_3,
   .b = val_4
 }, 
..., 
 { 
   .a = val_101,   
   .b = val_102
 } ;
} 

Struct的語法-陣列初始化(2)

Sprout OJ no.895 
成績統計II

Struct的語法-練習

double girls_average(Student ss[],int size) {
    //do something
}

double boys_average(Student ss[],int size) {
    //do something 
}

void print(Student s) {
    //do something
}

Struct的語法-練習

for i = 0 to size - 1 :
    if (ss[i].gender is female) :
        sum += ss[i].score
        
if (female_num is 0) :
    return -1
else :
    return sum / female_num

Struct的語法-練習

為什麼需要Struct

為什麼需要Struct

Task:
給你3對情侶,他們各自有各自的CE(Combatting Effectiveness),想請你依據女方的CE,由小到大對情侶們進行排序。

為什麼需要Struct

還沒學struct的你:

boys_CE[3] = {
,
,
}
girls_CE[3] = {
,
,
}

為什麼需要Struct

sort:

不是今天的重點,但是C++中有個好用的sort函式:

//記得引入標頭檔
#include <algorithm>
using namespace std ;

int main() {
    int num[6] = {1, 4, 2, 5, 3, 6} ;
    sort(num, num + 6) ;
    // sort 函式的預設是由小排到大
    //所以 num = {1, 2, 3, 4, 5, 6}
}

為什麼需要Struct

sort:

用在我們的情侶身上可能會變成:

//記得引入標頭檔
#include <algorithm>
using namespace std ;

int main() {
    int boys_CE[3] = {33, 9, 50} ;
    int girls_CE[3] = {44, 9999, 4} ;
    sort(girls_CE, girls_CE + 3) ;
}

為什麼需要Struct

交換伴侶!? BAD!

boys_CE[3] = {
girls_CE[3] = {
,
,
,
,
,
,
}
}

為什麼需要Struct

struct couple{
    int female_CE ;
    int male_CE ;
} ;

bool cmp(couple a, couple b) {
	return a.female_CE < b.female_CE ;
}

int main() {
    couple couple_arr[3] = {{44, 33}, {9999, 9}, {4, 50}} ;
    sort(couple_arr, couple_arr + 3, cmp) ;
}

解決方法:Struct!

為什麼需要Struct

,
}
}
{
,
,
}
{
}
,
,
{
{
couple couples[3]=

為什麼需要Struct

其他可能需要用struct的情境:

1.(x, y)座標

2.圖裡面的節點

node

head

node

node

node

NULL

Linked list

Nested Struct

Nested Struct

struct animal{
    char name[10] ;
    int leg_num ;
    double height ;
    bool alive ;
} ;

struct student{
    char name[10] ;
    int ID ;
    double height ;
    bool alive ;
    animal pet ; 
} ;

如果student養了寵物:

Nested Struct

struct animal{
    char name[10] ;
    int leg_num ;
    double height ;
    bool alive ;
} ;

struct student{
    char name[10] ;
    int ID ;
    double height ;
    bool alive ;
    animal pet ; 
} ;

如果student養了寵物:

cout << Bob.pet.name ;
如果今天有一個學生Bob,並且我們想要知道他寵物的名字:
取用student中的屬性pet中的屬性name

Nested Struct

struct animal{
    char name[10] ;
    int leg_num ;
    double weight ;
    double height ;
    bool alive ;
} ;

struct student{
    char name[10] ;
    int ID ;
    double height ;
    bool alive ;
    animal pet[40] ; 
} ;

int main() {
    student class_204[40] ;
}

如果student養了寵物:

如果我們想要知道class_204索引值A的學生索引值B的petheight
(A) class_204[B].height[A].pet

 

(B) class_204[A].height[B].pet

 

(C) class_204[A].pet[B].height

 

(D) class_204.pet[A].height[B]

Nested Struct

struct student{
    char name[10] ;
    int ID ;
    double height ;
    bool alive ;
    student hate ;
} ;

可以這樣嗎?

如果student討厭別的student:

Nested Struct

student

hate

student

student

student

...

student 的屬性hate為student型別,因此hate底下又有hate..

 

不知道要分配給student多少記憶體!

//Compile Error
struct student{
    char name[10] ;
    int ID ;
    double height ;
    bool alive ;
    student hate ;
} ;

hate

hate

hate

Nested Struct

用指標來儲存hate!

struct *ptr

struct *ptr

struct student{
    char name[10] ;
    int ID ;
    double height ;
    bool alive ;
    student *hate ;   //指向這個student討厭的student
} ;

如果student討厭別的student:

student

*hate

student

*hate

student

*hate

student

*hate

struct *ptr

struct student{
    char name[10] ;
    int ID ;
    double height ;
    bool alive ;
    student *hate ;
} ;

取用student_1的屬性:
student_1.height = 190.8 ;
取用student_1討厭的人的屬性:
(*student_1.hate).height = 130.7 ;
             or
student_1.hate -> height = 130.7 ;

struct *ptr

struct node{
    int data ;
    node *next   //指向下一個node
} ;

node

*next

*head

node

*next

node

*next

node

*next

NULL

還記得剛剛提過的linked list 嗎?

只是這是你們第14週的上課內容 可以不用學得太認真XD

酷酷的補充

酷酷的補充-記憶體對齊

struct test1{
    short a ; //2 byte
    short b ; //2 byte
    int c ; //4 byte
} ;
struct test2{
    short a ; //2 byte
    int c ; //4 byte
    short b ; //2 byte
} ;
struct test3{
    int c ; //4 byte
    short a ; //2 byte
    short b ; //2 byte
} ;
test1 t1 ;
test2 t2 ;
test3 t3 ;
cout << "sizeof(t1) : "<< sizeof(t1) << "\n" ;
cout << "sizeof(t2) : "<< sizeof(t2) << "\n" ;
cout << "sizeof(t3) : "<< sizeof(t3) << "\n" ;

三個屬性相同,但定義struct時順序不同的struct:

酷酷的補充-記憶體對齊

test1 t1 ;
test2 t2 ;
test3 t3 ;
cout << "sizeof(t1) : "<< sizeof(t1) << "\n" ;
cout << "sizeof(t2) : "<< sizeof(t2) << "\n" ;
cout << "sizeof(t3) : "<< sizeof(t3) << "\n" ;

WHY?

酷酷的補充-記憶體對齊

電腦的cpu抓資料一次通常是抓4byte的資料(要看電腦的規格,32位元的cpu一次抓4byte的資料,64位元的則是一次抓8byte的資料)

0
1
2
3

做4次存取太慢了!

}

integer
4
5
6
7

酷酷的補充-記憶體對齊

電腦的cpu抓資料一次通常是抓4byte的資料(要看電腦的規格,32位元的cpu一次抓4byte的資料,64位元的則是一次抓8byte的資料)

0
1
2
3

所以就一次存取4byte的資料!

}

integer
4
5
6
7

酷酷的補充-記憶體對齊

0
1
2
3

}

4
5
6
7
integer

這樣要做兩次存取!BAD!

要做記憶體對齊(Alignment)

酷酷的補充-記憶體對齊

記憶體對齊的大原則:

在存取同一個資料的時候,確保我不需要做多餘的存取。

struct test1{
    short a ; //2 byte
    short b ; //2 byte
    int c ; //4 byte
} ;
1
0
2
3
4
5
6
7
struct test3{
    int c ; //4 byte
    short a ; //2 byte
    short b ; //2 byte
} ;
1
0
2
3
4
5
6
7

酷酷的補充-記憶體對齊

記憶體對齊的大原則:

在存取同一個資料的時候,確保我不需要做多餘的存取。

struct test2{
    short a ; //2 byte
    int c ; //4 byte
    short b ; //2 byte
} ;
1
0
2
3
4
5
6
7
8
9
10
11

酷酷的補充-記憶體對齊

想知道細節可以去看這篇:記憶體管理、對齊及硬體特性

Title TextArray

By cswagger

Title TextArray

  • 234