C語言 自定義類型全面系統(tǒng)理解
一、結(jié)構(gòu)體
結(jié)構(gòu)體是不同類型變量的集合體
1.結(jié)構(gòu)體的聲明
struct Book
{
char name[20];//名字
int Price;//價(jià)格
char Writer[5];//作者
char Time[20];//日期
}; //注意分號(hào)不能丟
struct為結(jié)構(gòu)體關(guān)鍵字,Book為結(jié)構(gòu)體標(biāo)簽,中間不同類型的變量為結(jié)構(gòu)體的成員。上述現(xiàn)在只是定義了一個(gè)結(jié)構(gòu)體類型struct Book。
局部結(jié)構(gòu)體變量
int main()
{
struct Book B1; // B1為局部結(jié)構(gòu)體變量
return 0;
}
全局結(jié)構(gòu)體變量
struct Book
{
char name[20];
int Price;
char Writer[5];
char Time[20];
}B3,B4,B5; //在結(jié)構(gòu)體類型后可連續(xù)定義多個(gè)全局結(jié)構(gòu)體變量
struct Book B2; //B2為全局結(jié)構(gòu)體變量
int main()
{
return 0;
}
2.特殊聲明
不完全聲明
//匿名結(jié)構(gòu)體類型--沒有結(jié)構(gòu)體標(biāo)簽
struct
{
int a;
char b;
float c;
}x;
//這樣的結(jié)構(gòu)體類型必須緊跟著定義結(jié)構(gòu)體變量
//后面不能定義變量
不完全聲明類型只能在定義使用一次,并且在vs中:
struct
{
int a;
char b;
float c;
}x;
struct
{
int a;
char b;
float c;
}* ps;
int main()
{
ps=&x; //編譯器默認(rèn)兩者類型不兼容 //且是錯(cuò)誤寫法
return 0;
}

因此不完全聲明很少使用,不推薦。?
3.結(jié)構(gòu)體的自引用
這里可以用鏈表的實(shí)現(xiàn)來理解:

struct Node
{
int data;
struct Node* next;
};

這樣就實(shí)現(xiàn)了自己類型的對(duì)象找自己類型對(duì)象的方法,這就是結(jié)構(gòu)體的自引用。?
4.結(jié)構(gòu)體變量的初始化
以上面struct Book為例:
struct Book
{
char name[20];
int Price;
char Writer[5];
char Time[20];
};
int main()
{
struct Book B1={"三腳貓",50,“阿里”,“20081001”};
//初始化要用大括號(hào)
return 0;
}
嵌套結(jié)構(gòu)體的初始化:
struct Data
{
int a;
char b[6];
};
struct Book
{
struct Data D;
char name[20];
int Price;
char Writer[5];
char Time[20];
};
int main()
{
struct Book B1={{4,"haha"},"三腳貓",50,"阿里","20081001"};
//大括號(hào)里加大括號(hào)
return 0;
}
5.結(jié)構(gòu)體內(nèi)存對(duì)齊?
計(jì)算結(jié)構(gòu)體在內(nèi)存中的大小
方法:
1. 第一個(gè)成員為起始,設(shè)從下標(biāo)為0的地址開始向后存儲(chǔ)。
2. 其他成員變量要對(duì)齊到對(duì)齊數(shù)的整數(shù)倍的地址處。 對(duì)齊數(shù) = 編譯器默認(rèn)的一個(gè)對(duì)齊數(shù)與 該成員大小的較小值。 VS中默認(rèn)的值為8
3. 結(jié)構(gòu)體總大小為所有成員對(duì)齊數(shù)中最大對(duì)齊數(shù)的整數(shù)倍。
4. 如果嵌套了結(jié)構(gòu)體的情況,嵌套的結(jié)構(gòu)體對(duì)齊到自己的最大對(duì)齊數(shù)的整數(shù)倍處,結(jié)構(gòu)體的整體大小就是所有最大對(duì)齊數(shù)(含嵌套結(jié)構(gòu)體的對(duì)齊數(shù))的整數(shù)倍。
舉例說明:
#include <stdio.h>
struct S1
{
char c1;
int i;
char c2;
};
struct S2
{
char c1;
char c2;
int i;
};
int main()
{
printf("%d\n", sizeof(struct S1));
printf("%d\n", sizeof(struct S2));
return 0;
}

分析:

嵌套結(jié)構(gòu)體
#include <stdio.h>
struct S1
{
char c1;
int i;
char c2;
};
struct S2
{
char c1;
char c2;
struct S1 s1;
int i;
};
int main()
{
printf("%d\n", sizeof(struct S1));
printf("%d\n", sizeof(struct S2));
return 0;
}

分析:

內(nèi)存對(duì)齊的存在,在平臺(tái)和性能兩方面,可以使訪問空間更加高效,用空間換取時(shí)間。
讓占用空間小的成員盡量集中在一起。
6.修改默認(rèn)對(duì)齊數(shù)
#pragma pack(1) //修改默認(rèn)對(duì)齊數(shù)為1 //一般修改的對(duì)齊數(shù)為2^n
舉例說明:
#include <stdio.h>
#pragma pack(1) //修改為1相當(dāng)于取消了對(duì)齊,沒有優(yōu)化,在實(shí)際應(yīng)用中很少用
struct S1
{
char c1;
int i;
char c2;
};
int main()
{
printf("%d\n", sizeof(struct S1)); // 6
return 0;
}
當(dāng)默認(rèn)對(duì)齊數(shù)被修改后,每個(gè)類型的對(duì)齊數(shù)都變?yōu)?,整體的最大對(duì)齊數(shù)也為1(相當(dāng)于沒有對(duì)齊),整體大小是1的倍數(shù),則1+4+1=6。

7.結(jié)構(gòu)體傳參
當(dāng)一個(gè)函數(shù)涉及到結(jié)構(gòu)體時(shí),最好用傳址調(diào)用:
struct S
{
int data[1000];
int num;
};
struct S s = {{1,2,3,4}, 1000};
//結(jié)構(gòu)體傳參
void print1(struct S s)
{
printf("%d\n", s.num);
}
//結(jié)構(gòu)體地址傳參
void print2(struct S* ps)
{
printf("%d\n", ps->num);
}
int main()
{
print1(s); //傳結(jié)構(gòu)體
print2(&s); //傳地址
return 0;
}
傳址調(diào)用原因:
1.函數(shù)傳參的時(shí)候,參數(shù)是需要壓棧,會(huì)有時(shí)間和空間上的系統(tǒng)開銷。
2.如果傳遞一個(gè)結(jié)構(gòu)體對(duì)象的時(shí)候,結(jié)構(gòu)體過大,參數(shù)壓棧的的系統(tǒng)開銷比較大,所以會(huì)導(dǎo)致性能的下降。
二、位段
位段的聲明和結(jié)構(gòu)是類似的,有兩個(gè)不同:
1.位段的成員必須是整型。
2.位段的成員名后邊有一個(gè)冒號(hào)和一個(gè)數(shù)字。
舉例:
struct S
{
int _a:2;
int _b:5;
int _c:20;
int _d:25;
};
此時(shí)S就是一個(gè)位段類型
他的大小為8
printf("%d\n", sizeof(struct S));

分析:
下面我們來分析位段在內(nèi)存中的存儲(chǔ):

注:若初始化的值大于給其指定的空間,則先會(huì)發(fā)生截?cái)啵〝嘧笕∮遥?,再進(jìn)行存儲(chǔ)

位段是根據(jù)實(shí)際需求來進(jìn)行開辟空間,目的是為了節(jié)省空間提高效率。
跨平臺(tái)問題:
1. int 位段被當(dāng)成有符號(hào)數(shù)還是無符號(hào)數(shù)是不確定的。
2. 位段中最大位的數(shù)目不能確定。(16位機(jī)器最大16,32位機(jī)器最大32,寫成27,在16位機(jī) 器會(huì)出問題。
3. 位段中的成員在內(nèi)存中從左向右分配,還是從右向左分配標(biāo)準(zhǔn)尚未定義。(取決于編譯器)
4. 當(dāng)一個(gè)結(jié)構(gòu)包含兩個(gè)位段,第二個(gè)位段成員比較大,無法容納于第一個(gè)位段剩余的位時(shí),是 舍棄剩余的位還是利用,這是不確定的。
三、枚舉
就是把可能的取值一一列舉
枚舉類型的定義:
例子:
enum Day //星期
{
Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
};
enum Day就是一個(gè)枚舉類型,{}中的內(nèi)容是枚舉類型的可能取值,也叫枚舉常量。
枚舉常量是有值的,默認(rèn)從0開始,依次遞增。
int main()
{
enum Day d=Mon; //定義一個(gè)變量,賦予{}內(nèi)可能的取值。
return 0;
}

在定義的時(shí)候也可以賦初值,后面的常量依次遞增一

枚舉的優(yōu)點(diǎn)?
1. 增加代碼的可讀性和可維護(hù)性
2. 和#define定義的標(biāo)識(shí)符比較枚舉有類型檢查,更加嚴(yán)謹(jǐn)。
3. 防止了命名污染(封裝)
4. 便于調(diào)試
5. 使用方便,一次可以定義多個(gè)常量
注:最好用枚舉常量給枚舉變量賦值,才不會(huì)出現(xiàn)類型上的差異。
舉例:
當(dāng)用cpp來運(yùn)行程序時(shí)會(huì)報(bào)錯(cuò),因?yàn)閏pp對(duì)代碼的格式會(huì)更加嚴(yán)格

而c就可以運(yùn)行過去

養(yǎng)成良好的代碼風(fēng)格,做到認(rèn)真嚴(yán)謹(jǐn)。
四、聯(lián)合
聯(lián)合也是一種特殊的自定義類型
1.聯(lián)合類型的定義
//聯(lián)合類型的聲明
union Un
{
char c;
int i;
};
//聯(lián)合變量的定義
union Un un;
//計(jì)算連個(gè)變量的大小
printf("%d\n", sizeof(un));
2.聯(lián)合的特點(diǎn)?
聯(lián)合的成員是共用同一塊內(nèi)存空間的,這樣一個(gè)聯(lián)合變量的大小,至少是最大成員的大小。
union Un
{
int i;
char c;
};
union Un un;
int main()
{
printf("%d\n", &(un.i));
printf("%d\n", &(un.c));
return 0;
}

共用一塊空間,起始地址相同。
使用案例:
union Un
{
int i;
char c;
};
union Un un;
int main()
{
//printf("%d\n", &(un.i));
//printf("%d\n", &(un.c));
un.i = 0x11223344;
un.c = 0x55;
printf("%x\n", un.i);
return 0;
}

分析:

3.聯(lián)合大小的計(jì)算?
聯(lián)合的大小至少是最大成員的大小。
當(dāng)最大成員大小不是最大對(duì)齊數(shù)的整數(shù)倍的時(shí)候,就要對(duì)齊到最大對(duì)齊數(shù)的整數(shù)倍。
舉例:
union Un1
{
char c[5];
int i;
};
union Un2
{
short c[7];
int i;
};
//下面輸出的結(jié)果是什么?
int main()
{
printf("%d\n", sizeof(union Un1));
printf("%d\n", sizeof(union Un2));
return 0;
}

分析:

到此這篇關(guān)于C語言 自定義類型全面理解的文章就介紹到這了,更多相關(guān)C語言 自定義類型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++函數(shù)的嵌套調(diào)用和遞歸調(diào)用學(xué)習(xí)教程
這篇文章主要介紹了C++函數(shù)的嵌套調(diào)用和遞歸調(diào)用學(xué)習(xí)教程,是C++入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-09-09
C++實(shí)現(xiàn)數(shù)獨(dú)快速求解
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)數(shù)獨(dú)快速求解的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
淺析結(jié)束程序函數(shù)exit, _exit,atexit的區(qū)別
在一個(gè)程序中最多可以用atexit()注冊(cè)32個(gè)處理函數(shù),這些處理函數(shù)的調(diào)用順序與其注冊(cè)的順序相反,也即最先注冊(cè)的最后調(diào)用,最后注冊(cè)的最先調(diào)用2013-09-09
C語言實(shí)現(xiàn)簡(jiǎn)易學(xué)生管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)簡(jiǎn)易學(xué)生管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06
使用C++制作簡(jiǎn)單的web服務(wù)器(續(xù))
本文承接上文《使用C++制作簡(jiǎn)單的web服務(wù)器》,把web服務(wù)器做的功能稍微強(qiáng)大些,主要增加的功能是從文件中讀取網(wǎng)頁并返回給客戶端,而不是把網(wǎng)頁代碼寫死在代碼中,有需要的小伙伴來參考下吧。2015-03-03

