網(wǎng)站未備案怎么做淘寶客市場(chǎng)營(yíng)銷方案怎么寫(xiě)
個(gè)人主頁(yè)點(diǎn)這里~
結(jié)構(gòu)體
- 一、結(jié)構(gòu)體類型的聲明
- 1、結(jié)構(gòu)的聲明
- 2、結(jié)構(gòu)體變量的創(chuàng)建和初始化
- 3、聲明時(shí)的特殊情況
- 4、自引用
- 二、結(jié)構(gòu)體內(nèi)存對(duì)齊
- 1、對(duì)齊規(guī)則
- 2、存在內(nèi)存對(duì)齊的原因
- 3、修改默認(rèn)對(duì)齊數(shù)
- 三、結(jié)構(gòu)體傳參
- 四、結(jié)構(gòu)體實(shí)現(xiàn)位段
一、結(jié)構(gòu)體類型的聲明
我們?cè)谥羔樈K篇中提到過(guò)結(jié)構(gòu)體的這一部分內(nèi)容(詳情請(qǐng)閱拙作終の指針)現(xiàn)在我們來(lái)整個(gè)展開(kāi)敘述一下
1、結(jié)構(gòu)的聲明
struct tag
{member-list;
}variable-list;
花括號(hào) { } 中放的是成員變量,結(jié)構(gòu)的每個(gè)成員變量都可以是不同的類型,每一個(gè)被定義的結(jié)構(gòu)體中都要有至少一個(gè)成員變量,結(jié)構(gòu)是一些值的集合。
定義一個(gè)人
struct man
{char name[20];//名字int age;//年齡char sex[5];//性別char id[20];//身份證號(hào)
};
2、結(jié)構(gòu)體變量的創(chuàng)建和初始化
#include <stdio.h>
struct Stu
{char name[20];//名字int age;//年齡char sex[5];//性別char id[20];//身份證號(hào)int main(){struct Stu s = { "張三", 18, "男", "111111200602023215" };//結(jié)構(gòu)體順序初始化struct Stu s2 = { .age = 19, .name = "lisi", .id = "111111200502023222", .sex = "?" };//指定順序初始化return 0;
};
3、聲明時(shí)的特殊情況
匿名結(jié)構(gòu)體類型,如果沒(méi)有對(duì)結(jié)構(gòu)體進(jìn)行重命名的話,僅能使用一次
struct
{int a;char b;float c;
}x;
形如上面代碼的結(jié)構(gòu)體未重命名的話,使用這一次便被回收
4、自引用
自引用的正確方法:
struct Node
{int data;struct Node* next;
};
通過(guò)結(jié)構(gòu)體指針的形式來(lái)進(jìn)行自引用
并且結(jié)構(gòu)體自引用是不能用typedef重命名的
像這個(gè):
typedef struct
{int a;Node* next;
}Node;
我們會(huì)在創(chuàng)建Node結(jié)構(gòu)體之前在結(jié)構(gòu)體當(dāng)中使用Node,所以不可取
二、結(jié)構(gòu)體內(nèi)存對(duì)齊
結(jié)構(gòu)體內(nèi)存對(duì)齊是計(jì)算結(jié)構(gòu)體大小的一個(gè)必備條件
1、對(duì)齊規(guī)則
①結(jié)構(gòu)體的第一個(gè)成員對(duì)齊到結(jié)構(gòu)體變量起始位置的地址
②其他成員變量要對(duì)齊到對(duì)齊數(shù)的整數(shù)倍的地址處
對(duì)齊數(shù):編譯器默認(rèn)的對(duì)齊數(shù)與該成員變量大小的較小值(我所使用的vs2022默認(rèn)對(duì)齊數(shù)為8)
③結(jié)構(gòu)體總大小一定為對(duì)齊數(shù)的整數(shù)倍
④如果結(jié)構(gòu)體中嵌套了結(jié)構(gòu)體,嵌套的結(jié)構(gòu)體對(duì)齊到對(duì)齊到自己成員中最大對(duì)齊數(shù)的整數(shù)倍處,結(jié)構(gòu)體的整體大小就是所有最大對(duì)齊數(shù)的整數(shù)倍
我們可以將大小看作一個(gè)數(shù)組,每一個(gè)位置都是一個(gè)字節(jié)
struct S1
{char c1;//1字節(jié),<8,就將1字節(jié)放在0位置處int i;//4字節(jié),<8,因?yàn)?,2,3位置不是4的整數(shù)倍,所以我們直接找到4位置,將4個(gè)字節(jié)放入char c2;//1字節(jié),<8,放在8位置處
};
又因?yàn)楝F(xiàn)在指向9位置處,9不是最大對(duì)齊數(shù)4的整數(shù)倍,所以要指向12處,所以結(jié)構(gòu)體S1的大小為12字節(jié)
printf打印一下:
struct S2
{char c1;//1字節(jié),放到0位置char c2;//1字節(jié),放到1位置int i;//4字節(jié),2不是4的整數(shù)倍,放到4位置
};
最終指向8位置,是4的整數(shù)倍,故S2的大小為8字節(jié)
struct S3
{double d;//8字節(jié),放到0位置處char c;//1字節(jié),放到8位置處int i;//4字節(jié),9不是4的整數(shù)倍,放到12位置處,最終指向16
};
因?yàn)樽畲髮?duì)齊數(shù)為8,16為8的整數(shù)倍,所以結(jié)構(gòu)體S3的大小就是16個(gè)字節(jié)
struct S4
{char c1;//1字節(jié),放到0位置處struct S3 s3;//16字節(jié),以8為對(duì)齊數(shù),放到8位置,最后指向24位置處double d;//8字節(jié),放到24位置,最終指向32位置
};
32是最大對(duì)齊數(shù)8的整數(shù)倍,所以結(jié)構(gòu)體S4的大小就是32個(gè)字節(jié)
2、存在內(nèi)存對(duì)齊的原因
在數(shù)據(jù)訪問(wèn)時(shí),對(duì)齊的內(nèi)存只需要一次訪問(wèn),而不對(duì)齊的內(nèi)存需要兩次訪問(wèn)
結(jié)構(gòu)體的內(nèi)存對(duì)齊是拿空間來(lái)?yè)Q取時(shí)間
我們可以將占用內(nèi)存小的盡量集中在一起來(lái)節(jié)省空間
struct S1
{char c1;int i;char c2;
};
struct S2
{char c1;char c2;int i;
};
3、修改默認(rèn)對(duì)齊數(shù)
#pragma
#include <stdio.h>
#pragma pack(1)//設(shè)置默認(rèn)對(duì)?數(shù)為1
struct S
{char c1;//1字節(jié),存到0位置int i;//4字節(jié),默認(rèn)對(duì)齊數(shù)為1小于4,存到1位置char c2;//1字節(jié),存到5位置,指向6
};
#pragma pack()//取消設(shè)置的對(duì)?數(shù),還原為默認(rèn)
int main()
{printf("%d\n", sizeof(struct S));return 0;
}
三、結(jié)構(gòu)體傳參
struct S
{int data[100];int num;
};
struct S s = { {1,2,3,4}, 1000 };
void print(struct S* ps)
{printf("%d\n", ps->num);
}
int main()
{print(&s);return 0;
}
結(jié)構(gòu)體傳參的時(shí)候最好傳一個(gè)地址,因?yàn)橹苯觽饕粋€(gè)結(jié)構(gòu)體過(guò)去的話會(huì)造成時(shí)間和空間上不必要的開(kāi)銷,導(dǎo)致性能下降
四、結(jié)構(gòu)體實(shí)現(xiàn)位段
位段的成員可以是int , unsigned int , signed int ,char類型的
位段不跨平臺(tái),可移植程序應(yīng)該避免使用位段
struct S
{char a : 3;char b : 4;char c : 5;char d : 4;
};
struct S s = { 0 };
int main()
{s.a = 10;s.b = 12;s.c = 3;s.d = 4;printf("%d\n", s.a);printf("%d\n", s.b);printf("%d\n", s.c);printf("%d\n", s.d);}
這里的a存入了10,由于位段作用,被存入a的二進(jìn)制數(shù)為010,用整數(shù)形式打印,第一位為0,為正數(shù),以第一位補(bǔ)位到32位,即00000000 00000000 00000000 00000010,即為2
這里的b存入了12,由于位段作用,被存入b的二進(jìn)制數(shù)為1100,用整數(shù)形式打印,第一位為1,為負(fù)數(shù),補(bǔ)1到11111111 11111111 11111111 11111100,這是補(bǔ)碼,然后取反加一為原碼,即10000000 00000000 00000000 00000100,即為-4
這里的c存入了3,由于位段作用,被存入c的二進(jìn)制數(shù)為00011,用整數(shù)形式打印,第一位為0,為正數(shù),以第一位補(bǔ)位到32位,即00000000 00000000 00000000 00000011,即為3
這里的d存入了4,由于位段作用,被存入a的二進(jìn)制數(shù)為0100,用整數(shù)形式打印,第一位為0,為正數(shù),以第一位補(bǔ)位到32位,即00000000 00000000 00000000 00000100,即為4
但是它空間的開(kāi)辟是這樣的:
第一個(gè)數(shù)據(jù):二進(jìn)制的01100010,十六進(jìn)制的0x62
第二個(gè)數(shù)據(jù):二進(jìn)制的00000011,十六進(jìn)制的0x03
第三個(gè)數(shù)據(jù):二進(jìn)制的00000100,十六進(jìn)制的0x04
可以看到我們的結(jié)構(gòu)體中存放的數(shù)據(jù)是62 03 04 00,與上述分析相符
跟結(jié)構(gòu)體相比,位段可以達(dá)到同樣的效果,并且可以很好的節(jié)省空間,缺點(diǎn)是有跨平臺(tái)的問(wèn)題存在
因?yàn)榈刂返姆峙涫且宰止?jié)為單位的,位段下的某些數(shù)據(jù)是沒(méi)有地址的,所以位段數(shù)據(jù)不能用指針來(lái)訪問(wèn)
今天的分享就到這了~