今天來(lái)說(shuō)一下C語(yǔ)言里的結(jié)構(gòu)體(struct)线召、共用體(l聯(lián)合體)union翻翩、枚舉祷安。
歡迎加入嵌入式學(xué)習(xí)群:559601187
(一)結(jié)構(gòu)體:struct
1.1 概念
- 是一種自定義的數(shù)據(jù)類型
- 結(jié)構(gòu)體是構(gòu)造類型的一種
- 不同數(shù)據(jù)類型的集合
- 地址空間連續(xù)疼阔,每次分配最大數(shù)據(jù)類型的寬度
- 占用內(nèi)存為所有變量的總大小(注意字節(jié)對(duì)齊問(wèn)題)
1.2 定義
1.先定義結(jié)構(gòu)體類型耗啦,再說(shuō)明結(jié)構(gòu)體變量
struct stu
{
char *name; //姓名
int num; //學(xué)號(hào)
int age; //年齡
float score; //成績(jī)
};
struct stu student;
上面的程序使用strcuct關(guān)鍵字定義了一個(gè)結(jié)構(gòu)體名為stu的結(jié)構(gòu)體類型纫版。和定義變量一樣床绪,聲明一個(gè)結(jié)構(gòu)體類型變量可以使用:數(shù)據(jù)類型 變量名 的形式。
struct stu student表示定義了一個(gè)變量名為stduent其弊,類型為stu的結(jié)構(gòu)體癞己。該結(jié)構(gòu)體含有4個(gè)成員:name、num梭伐、age痹雅、score
注意大括號(hào)后面的分號(hào);不能少,這是一條完整的語(yǔ)句糊识。
2.定義結(jié)構(gòu)體類型的同時(shí)定義結(jié)構(gòu)體變量
struct stu
{
char *name; //姓名
int num; //學(xué)號(hào)
int age; //年齡
float score; //成績(jī)
}student;
在定義時(shí)直接聲明結(jié)構(gòu)體變量绩社,只需要將結(jié)構(gòu)體變量名放在花括號(hào)后面,并加上分號(hào)即可赂苗。
3.直接說(shuō)明結(jié)構(gòu)體變量
struct
{
char *name; //姓名
int num; //學(xué)號(hào)
int age; //年齡
float score; //成績(jī)
} student;
這種定義方式并不常用愉耙,這樣做書寫雖然簡(jiǎn)單,但是因?yàn)闆](méi)有結(jié)構(gòu)體名拌滋,后面就沒(méi)法用該結(jié)構(gòu)體定義新的變量朴沿。
4.typedef重定義
typedef struct
{
char *name; //姓名
int num; //學(xué)號(hào)
int age; //年齡
float score; //成績(jī)
} STU;
STU student;
這種方式比較常見,我們使用typedef重定義結(jié)構(gòu)體為STU败砂,這里STU就是此結(jié)構(gòu)體類型赌渣,可以用STU去定義結(jié)構(gòu)體變量
1.3 初始化
1.在定義結(jié)構(gòu)體變量的時(shí)候全部初始化
struct stu
{
char *name; //姓名
int num; //學(xué)號(hào)
int age; //年齡
float score; //成績(jī)
}student={“ha”,1234,56,99};
2.定義完結(jié)構(gòu)體變量后,之后只能單個(gè)賦值
struct stu
{
char *name; //姓名
int num; //學(xué)號(hào)
int age; //年齡
float score; //成績(jī)
};
struct stu student;
student.name="ha";
student.num=1234;
student.age=56;
student.score=99;
1.4 調(diào)用
結(jié)構(gòu)體變量.成員
結(jié)構(gòu)體變量名+點(diǎn)('.')+成員就可以調(diào)用了
1.5 結(jié)構(gòu)體指針
當(dāng)一個(gè)指針變量指向結(jié)構(gòu)體時(shí)吠卷,我們就稱它為結(jié)構(gòu)體指針锡垄。C語(yǔ)言結(jié)構(gòu)體指針的定義形式一般為:
struct 結(jié)構(gòu)體名 *變量名;
//結(jié)構(gòu)體
struct stu{
char *name; //姓名
int num; //學(xué)號(hào)
int age; //年齡
float score; //成績(jī)
} stu1 = { "hah", 12, 18, 23, 136.5 };
//結(jié)構(gòu)體指針
struct stu *pstu = &stu1;
注意結(jié)構(gòu)體變量名和數(shù)組名不同,數(shù)組名在表達(dá)式中會(huì)被轉(zhuǎn)換為數(shù)組指針祭隔,而結(jié)構(gòu)體變量名不會(huì)货岭,無(wú)論在任何表達(dá)式中它表示的都是整個(gè)集合本身,要想取得結(jié)構(gòu)體變量的地址疾渴,必須在前面加&千贯,所以給 pstu 賦值只能寫作:
1.6 獲取結(jié)構(gòu)體成員
通過(guò)結(jié)構(gòu)體指針可以獲取結(jié)構(gòu)體成員,一般形式為:
(*pointer).memberName
或者:
pointer->memberName
第一種寫法中搞坝,.的優(yōu)先級(jí)高于搔谴,(pointer)兩邊的括號(hào)不能少。如果去掉括號(hào)寫作pointer.memberName桩撮,那么就等效于(pointer.memberName)敦第,這樣意義就完全不對(duì)了峰弹。
第二種寫法中,->是一個(gè)新的運(yùn)算符芜果,習(xí)慣稱它為“箭頭”鞠呈,有了它,可以通過(guò)結(jié)構(gòu)體指針直接取得結(jié)構(gòu)體成員右钾;這也是->在C語(yǔ)言中的唯一用途蚁吝。
1.7 結(jié)構(gòu)體內(nèi)存分析
注意點(diǎn)
- 給整個(gè)結(jié)構(gòu)體變量分配儲(chǔ)存空間和數(shù)組一樣,從內(nèi)存地址比較大的開始分配
- 給結(jié)構(gòu)體變量中的屬性分配儲(chǔ)存空間也和數(shù)組一樣,從所占內(nèi)存地址比較小的開始分配
- 定義結(jié)構(gòu)體類型不會(huì)分配儲(chǔ)存空間,只有定義結(jié)構(gòu)體變量的時(shí)候才會(huì)分配儲(chǔ)存空間
- 結(jié)構(gòu)體在分配內(nèi)存的時(shí)候,會(huì)做一個(gè)內(nèi)存對(duì)齊的操作
- 會(huì)先獲取所有屬性中占用內(nèi)存最大的屬性的字節(jié)數(shù)
- 然后在開辟出最大屬性字節(jié)的內(nèi)存給第一個(gè)屬性,如果分配給第一個(gè)屬性之后還能繼續(xù)分配給第二個(gè)屬性,那么就繼續(xù)分配給第二個(gè)屬性
- 如果分配給第一個(gè)屬性之后,剩余的內(nèi)存不夠分配給第二個(gè)屬性了,那么會(huì)再次開辟最大屬性的內(nèi)存,再次分配 依次類推
#include <stdio.h>
int main(){
//定義結(jié)構(gòu)體
struct Person
{
char name; // 1 個(gè)節(jié)點(diǎn) //開辟4個(gè)字節(jié) char 占用1個(gè)
int age; // 4個(gè)字節(jié) // 剩余三個(gè) 不夠int 再開辟4個(gè)字節(jié)
int money; // 4個(gè)字節(jié) // 再開辟4個(gè)字節(jié)
};
struct Person p; // 所以p = 4+4+4
printf("sizeof(p) = %i\n",sizeof(p)); // 12個(gè)字節(jié)
return 0;
}
(二)共用體(聯(lián)合體):union
2.1概念
- 所有變量共用一段空間
- 每次分配按最大長(zhǎng)度進(jìn)行分配
- 是一種構(gòu)造數(shù)據(jù)類型
- 同一時(shí)刻只能保存一個(gè)成員的值
- 不能直接引用共用體變量名
2.2定義
它的定義和結(jié)構(gòu)體一樣,分為先定義共用體再說(shuō)明共用體變量舀射、在定義共用體的同時(shí)說(shuō)明共用體變量窘茁、直接說(shuō)明共用體變量
union 共用體名{
成員列表
};
示例:
//先定義共用體再說(shuō)明共用體變量
union data{
int n;
char ch;
double f;
};
union data a, b, c;
2.3 引用
和結(jié)構(gòu)體一樣,通過(guò)共用體變量名 . 成員名
union data{
int n;
char ch;
double f;
} a, b, c;
a.n=3;
關(guān)于共用體的詳細(xì)介紹可以看下這篇文章C語(yǔ)言共用體(C語(yǔ)言u(píng)nion用法)詳解脆烟,講到共用體這里要說(shuō)明一下大小端模式的問(wèn)題山林。
小端模式:低地址存放低字節(jié),高地址存放高字節(jié)
大端模式:低地址存放高字節(jié)浩淘,高地址存放低字節(jié)
(三)枚舉:enum
3.1 概念
- 作用:列舉出所有的可能性捌朴,增強(qiáng)代碼的可閱讀性
- 枚舉成員都是常量
- 不能再對(duì)已經(jīng)定義好的枚舉常量賦值
3.1 定義
enum 枚舉名
{
枚舉變量
};
示例:
enum week
{
Mon, Tues, Wed, Thurs, Fri, Sat, Sun
};
typedef enum
{
Mon, Tues, Wed, Thurs, Fri, Sat, Sun
}Date;
枚舉是一種類型,通過(guò)它可以定義枚舉變量:
Date a,b,c
我們也可以給每個(gè)名字都指定一個(gè)值:
enum week{ Mon = 1, Tues = 2, Wed = 3, Thurs = 4, Fri = 5, Sat = 6, Sun = 7 };
更為簡(jiǎn)單的方法是只給第一個(gè)名字指定值:
enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun };
這樣枚舉值就從 1 開始遞增张抄,跟上面的寫法是等效的砂蔽。
也可以在定義枚舉類型的同時(shí)定義變量:
enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } a, b, c;
有了枚舉變量,就可以把列表中的值賦給它:
enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun };
enum week a = Mon, b = Wed, c = Sat;
或者:
enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } a = Mon, b = Wed, c = Sat;
特點(diǎn):可以在定義枚舉時(shí)給成員賦值署惯,被賦值的成員往后依次增加1左驾,也可以在中間改變某一個(gè)成員的值。
3.1 引用
直接使用就行极谊,需要注意的是**枚舉列表中的數(shù)據(jù)作用范圍是全局的诡右,不能在定義與它們名字相同的白能量;Mon轻猖、Tues帆吻、Wed 等都是常量,不能對(duì)它們賦值咙边,只能將它們的值賦給其他的變量猜煮。
示例:
#include <stdio.h>
int main(){
enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } day;
scanf("%d", &day);
switch(day){
case 1: puts("Monday"); break;
case 2: puts("Tuesday"); break;
case 3: puts("Wednesday"); break;
case 4: puts("Thursday"); break;
case 5: puts("Friday"); break;
case 6: puts("Saturday"); break;
case 7: puts("Sunday"); break;
default: puts("Error!");
}
return 0;
}
Mon、Tues败许、Wed 這些名字都被替換成了對(duì)應(yīng)的數(shù)字王带。這意味著,Mon市殷、Tues愕撰、Wed 等都不是變量,它們不占用數(shù)據(jù)區(qū)(常量區(qū)、全局?jǐn)?shù)據(jù)區(qū)搞挣、棧區(qū)和堆區(qū))的內(nèi)存带迟,而是直接被編譯到命令里面,放到代碼區(qū)囱桨,所以不能用&取得它們的地址邮旷。這就是枚舉的本質(zhì)。
本文章僅供學(xué)習(xí)交流用禁止用作商業(yè)用途蝇摸,文中內(nèi)容來(lái)水枂編輯,如需轉(zhuǎn)載請(qǐng)告知办陷,謝謝合作
微信公眾號(hào):zhjj0729
微博:文藝to青年