@TOC
📝前言
本小節,阿森繼續和你一起學習什麼是結構體?結構體類型的聲明和創建,然後就是結構體的初始化,隨即學習結構成員的訪問操作符來更好的打印結構體的數據,當然還有匿名結構體類型,和結構的自引用。文章乾貨滿滿,接下來我們就學習一下結構體吧 😃!
🌠 什麼是結構體?
結構體是一種用户定義的數據類型,它允許用户根據需要組合不同類型的變量。
struct Student
{
char name[20];
int age;
float score;
};
結構體通過struct關鍵字來定義,它允許將多個不同類型的數據元素組合在一起,這些數據元素稱為結構體的成員。
🌅 結構體類型的聲明和創建
- 結構體類型的聲明
struct 結構體類型標籤名
{
成員聲明1;
成員聲明2;
...
};//分號不能丟
例如:
struct Student//此時只是聲明瞭 Student 類型,
{ //但還沒有創建任何 Student 類型的變量。
int id;
char name[20];
float score;
};//分號不能丟
- 創建結構體類型的變量的語法如下:
struct 結構體類型名 變量名;
例如:
創建一個名為student1的學生結構體變量:
struct Student student1;
也可以在聲明結構體類型的同時創建變量:
struct Stu
{
char name[20];//名字
int age;//年齡
char sex[5];//性別
char id[20];//學號
};
struct Stu s1;
struct Stu s2;
3.typedef關鍵字來為結構體類型定義別名,然後創建結構體變量:
// 首先定義一個結構體類型
struct Student
{
int id;
char name[20];
};
int main()
{
// 使用typedef為Student結構體類型定義一個別名StudentType
typedef struct Student StudentType;
// 使用原結構體類型定義變量
struct Student st1;
// 使用新的類型別名定義變量
StudentType st2;
// 訪問結構體成員
st1.id = 1001;
st2.id = 1002;
return 0;
}
typedef struct Student StudentType可以理解使用typedef把 struct Student重新取了一個名字 StudentType ,此時這個 StudentTye 就是一個類型,比如:int a;這個StudentTye就相當於int, StudentType st2 ;當然,這個 struct Student 也可以理解為 int ,所以也可以這麼用 struct Student st1 ;
🌠 結構體變量的初始化
結構體變量的初始化主要有兩種方式:
- 按照默認順序初始化:
默認情況下,結構體成員的初始化順序與它們在結構體定義中的順序相同。
例如:
struct Stu
{
char name[20];//名字
int age;//年齡
char sex[5];//性別
char id[20];//學號
}p1;
struct Stu s1 = { "asenyaozixin",11,"男","2023012018" };
//定義結構體變量s2
- 指定順序初始化:
可以通過在列表中指定成員名來指定成員的初始化順序:
例如:
struct Stu
{
char name[20];//名字
int age;//年齡
char sex[5];//性別
char id[20];//學號
};
struct Stu s2 = { .age = 66,.id = "2023001001",.name = "ahuibuyiban",.sex = "nv" };
完整示例且打印:
struct Stu
{
char name[20];//名字
int age;//年齡
char sex[5];//性別
char id[20];//學號
};
int main()
{
struct Stu s1 = { "asenyaozixin",11,"nan","2023012018" };//按照默認順序初始化
struct Stu s2 = { .age = 66,.id = "2024001001",.name = "ahuibuyiban",.sex = "nv" };//指定順序初始化
printf("%s %d %s %s\n", s1.name, s1.age, s1.sex, s1.id);
printf("%s %d %s %s\n", s2.name, s2.age, s2.sex, s2.id);
return 0;
}
打印結果:
🌅 結構成員訪問操作符
結構成員訪問操作符用於訪問結構體中的成員變量。
結構體成員的直接訪問
- 結構體成員的直接訪問----點操作符(.) 使⽤⽅式:結構體變量.成員名
使用點操作符可以訪問結構的普通成員,例如:
struct Stu
{
char name[20];
int age;
float score;
} s3 = { "熊大", 33, 66.0f }, s4 = {"熊二", 18, 100.0f};//全局變量
int main()
{
struct Stu s1 = {"zhangsan", 20, 95.5f};//局部變量
struct Stu s2 = {"lisi", 18, 87.5f};
struct Stu s5 = {.score= 98.5f, .name="hehe", .age = 18};
//. 結構成員訪問操作符
//結構體變量.成員名
//
printf("%s %d %f\n", s1.name, s1.age, s1.score);
printf("%s %d %f\n", s2.name, s2.age, s2.score);
printf("%s %d %f\n", s3.name, s3.age, s3.score);
printf("%s %d %f\n", s4.name, s4.age, s4.score);
}
輸出:
- 結構體成員的間接訪問----箭頭操作符(->) 使⽤⽅式:結構體指針->成員名
當結構體變量聲明為結構體指針時,使用箭頭操作符訪問其成員:
struct Stu
{
char name[20];
int age;
float score;
} s3 = { "熊大", 33, 66.0f }, s4 = {"熊二", 18, 100.0f};//全局變量
int main()
{
struct Stu s1 = {"zhangsan", 20, 95.5f};//局部變量
struct Stu s2 = {"lisi", 18, 87.5f};
struct Stu s5 = {.score= 98.5f, .name="hehe", .age = 18};
//結構體指針
struct Stu* p1 = &s1;//取出s1的地址
struct Stu* p2 = &s2;//取出s2的地址
struct Stu* p3 = &s3;//取出s3的地址
struct Stu* p4 = &s4;//取出s4的地址
struct Stu* p5 = &s5;//取出s5的地址
printf("%s %d %f\n", p1->name, p1->age, p1->score);
printf("%s %d %f\n", p2->name, p2->age, p2->score);
printf("%s %d %f\n", p3->name, p3->age, p3->score);
printf("%s %d %f\n", p4->name, p4->age, p4->score);
printf("%s %d %f\n", p5->name, p5->age, p5->score);
//結構體指針->成員名
return 0;
}
輸出:
🌠 匿名結構體類型
匿名結構體類型就是沒有給結構體類型起名字的結構體類型。
匿名結構體的定義方式:
struct
{
成員1 數據類型;
成員2 數據類型;
...
} 變量名1, 變量名2, ...;
例如:
struct
{
int a;
char b;
float c;
} x;
匿名結構體的特點是:
- 不需要給結構體起名字,定義時不指定結構體名稱。
- 只能在定義它的代碼塊內使用,不能在其他地方再次使用這個匿名結構體類型。
思考:下⾯的兩個結構在聲明的時候省略掉了結構體標籤(tag),然後主函數裏的p = &x的代碼合法嗎?
struct
{
int a;
char b;
float c;
} x;
struct
{
int a;
char b;
float c;
} *p;
int main()
{
p = &x;//?代碼合法嗎?
return 0;
}
輸出沒問題但有警告:
警告:編譯器會把上⾯的兩個聲明當成完全不同的兩個類型,所以是⾮法的。匿名的結構體類型,如果沒有對結構體類型重命名的話,基本上只能使⽤⼀次。
🌅 結構的⾃引⽤
結構的自引用指的是結構體內部包含自己類型的指針成員,通過這個指針可以實現結構體之間的引用關係。
⾃引⽤⽅式:
struct Node
{
int data;
struct Node *next;
};
// Node結構體包含一個指向Node結構體的指針next
// 通過next可以實現鏈表節點之間的引用關係
- 思考1: 在結構中包含⼀個類型為該結構本⾝的成員是否可以呢? ⽐如,定義⼀個鏈表的節點:
struct Node
{
int data;
struct Node next;
};
上述代碼正確嗎?如果正確,那 sizeof(struct Node) 是多少? 仔細分析,其實是不⾏的,因為⼀個結構體中再包含⼀個同類型的結構體變量,這樣結構體變量的⼤⼩就會⽆窮的⼤,是不合理的。
代碼運行:
圖解分析:
- 思考2: 在結構體⾃引⽤使⽤的過程中,夾雜了 typedef 對匿名結構體類型重命名,也容易引⼊問題,看看下⾯的代碼,可⾏嗎?
typedef struct
{
int data;//存放數據
Node* next;//存放寫一個節點的地址
}Node;
int main()
{
return 0;
}
運行:
分析: 首先使用typedef給前面匿名結構體起了別名Node,還不是類型,但是在typedef語句內,struct定義部分還沒有結束,所以在struct內部使用Node聲明next時,Node類型還未通typedef獲得定義,僅僅是對匿名結構體的一個重命名,就提前使⽤Node類型來創建成員變量。
解決⽅案如下:定義結構體不要使⽤匿名結構體了 如下: 先定義結構體:
struct Node
{
int data;
struct Node* next;
}
再使用typedef給它起別名:
typedef struct Node Node;
或者一步完成:
typedef struct Node
{
int data;
struct Node* next;
} Node;
🚩總結
這次阿森和你一起學習結構體的結構體類型的聲明和創建,初始化,訪問操作符,這是結構體基礎知識,但阿森會慢慢和你一起學習,從基礎到進階。感謝你的收看,如果文章有錯誤,可以指出,我不勝感激,讓我們一起學習交流,如果文章可以給你一個小小幫助,可以給博主點一個小小的贊😘