前言:
? ? ? ? c語(yǔ)言?xún)纱笾匾c(diǎn),一個(gè)是指針,另一個(gè)就是結(jié)構(gòu)體啦,這篇文章我將全面的介紹一下結(jié)構(gòu)體,和他的使用,相信大家看完這篇以后定能對(duì)結(jié)構(gòu)體有個(gè)深入的理解,并且會(huì)正確的使用它。
??? ??? ??歡迎來(lái)到小馬學(xué)習(xí)代碼博客?。?!
?現(xiàn)在已經(jīng)入冬了吧,小馬想問(wèn)一下大家那里都下雪了嘛,我們這還沒(méi)有下,但是在家里真的好冷啊,根本不想出門(mén)???
思維導(dǎo)圖:
?
?
目錄
一、結(jié)構(gòu)體的認(rèn)識(shí)
1.1結(jié)構(gòu)體存在的意義:
1.2結(jié)構(gòu)體的聲明和定義:
1.3結(jié)構(gòu)體的特殊聲明:
1.4結(jié)構(gòu)體的訪問(wèn):
1.5結(jié)構(gòu)體的初始化:
1.6結(jié)構(gòu)體的傳參:
2、結(jié)構(gòu)體內(nèi)存對(duì)齊
2.1結(jié)構(gòu)體對(duì)齊的意義:
2.2結(jié)構(gòu)體內(nèi)存對(duì)齊的規(guī)則:
2.3代碼演示:
2.4默認(rèn)對(duì)齊數(shù)的修改:?
3、結(jié)構(gòu)體類(lèi)型
3.1結(jié)構(gòu)體數(shù)組:
3.2結(jié)構(gòu)體指針:
總結(jié):
?
一、結(jié)構(gòu)體的認(rèn)識(shí)
1.1結(jié)構(gòu)體存在的意義:
1.2結(jié)構(gòu)體的聲明和定義:
struct tag
{
member-list;
}variable-list;
struct Student
{
char name[20];//名字
int age;//年齡
char sex[5];//性別
char id[20];//學(xué)號(hào)
}; //分號(hào)不能丟
struct Student stu1; //定義結(jié)構(gòu)體變量
1.2.2聲明的同時(shí)直接定義
struct Student
{
char name[20];//名字
int age;//年齡
char sex[5];//性別
char id[20];//學(xué)號(hào)
}stu1; //分號(hào)不能丟 //聲明的同時(shí)定義
1.3結(jié)構(gòu)體的特殊聲明:
//匿名結(jié)構(gòu)體類(lèi)型
struct
{
int a;
char b;
float c;
}x;
匿名結(jié)構(gòu)體類(lèi)型不好的一點(diǎn)就是定義之后不能在定義新的結(jié)構(gòu)體變量了。
1.4結(jié)構(gòu)體的訪問(wèn):
? ? ? ? 在數(shù)組中我們是通過(guò)數(shù)組的下標(biāo)來(lái)訪問(wèn)的,但是在結(jié)構(gòu)體中,每個(gè)元素的類(lèi)型都不是相同的,所以沒(méi)辦辦法通過(guò)下表的方式來(lái)進(jìn)行訪問(wèn),故通過(guò)結(jié)構(gòu)變量的成員是通過(guò)點(diǎn)操作符(.)訪問(wèn)的。
例如:
struct Student
{
char name[20];//名字
int age;//年齡
char sex[5];//性別
char id[20];//學(xué)號(hào)
}stu1; //分號(hào)不能丟
stu1.name 表示這個(gè)學(xué)生的姓名,stu1.age表示這個(gè)學(xué)生的年齡等等。
要是結(jié)構(gòu)體里面嵌套一個(gè)結(jié)構(gòu)體:
struct Birthday{
int year;
int month;
int day;
};
struct Student{
char name[20];
int age ;
char sex[20];
char id[20];
struct Birthday birthday;
}stu1;
stu1.name.month?表示這個(gè)學(xué)生的生日的月份,stu1.name.year 表示生日的年份
struct Stu
{
char name[20];
int age;
};
void print(struct Stu* ps) {
printf("name = %s ? age = %d\n", (*ps).name, (*ps).age);
? ?//使用結(jié)構(gòu)體指針訪問(wèn)指向?qū)ο蟮某蓡T
printf("name = %s ? age = %d\n", ps->name, ps->age);
}
int main()
{
? ?struct Stu s = {"zhangsan", 20}; //結(jié)構(gòu)體的賦值
? ?print(&s);//結(jié)構(gòu)體地址傳參
? ?return 0;
}
這里是通過(guò)箭頭來(lái)訪問(wèn)的
1.5結(jié)構(gòu)體的初始化:
1.5.1在定義后在進(jìn)行成員逐步賦值:
struct Student
{
char name[20];//名字
int age;//年齡
char sex[5];//性別
char id[20];//學(xué)號(hào)
}; //分號(hào)不能丟
int main()
{
struct Student stu1;
strcpy(stu1.name,"xiaoma"); //strcpy進(jìn)行賦值
stu1.age =18;
strcpy(stu1.sex,"nan");
strcpy(stu1.id,"12345667");
}
1.5.2在定義后進(jìn)行整體賦值:
struct Student{
char name[20];
int age ;
char sex[20];
char id[20];
};
int main()
{
struct Student stu2;
stu2=(struct Student){"xiaoli",18,"nan","1234567"};
//這里要進(jìn)行強(qiáng)制類(lèi)型轉(zhuǎn)換 因?yàn)閿?shù)組的賦值也是用的{},你要把它轉(zhuǎn)換為結(jié)構(gòu)體的賦值
}
1.5.3在定義的同時(shí)進(jìn)行整體賦值 :
struct Student{
char name[20];
int age ;
char sex[20];
char id[20];
}stu1={"xiaoma",18,"nan","12345667"}; //這是一種定義的同時(shí)進(jìn)行賦值
int main()
{
struct Student stu2={"xiaoli",18,"nan","1234567"}; //這是第二種定義后同時(shí)進(jìn)行賦值
}
//要注意賦值的順序要和你聲明的元素順行相同
1.5.4在定義的同時(shí)進(jìn)行部分賦值:
struct Student{
char name[20];
int age ;
char sex[20];
char id[20];
}stu1={.name="xiaoma"};
int main()
{
struct Student stu2={.name="xiaoli"}; //這里只是給姓名進(jìn)行賦值
}
1.5.5通過(guò)結(jié)構(gòu)體進(jìn)行賦值:
struct Student{
char name[20];
int age ;
char sex[20];
char id[20];
}stu1={.name="xiaoma"};
int main()
{
struct Student stu2={.name="xiaoli"};
stu2=stu1;
}
這里是把結(jié)構(gòu)體stu1賦值給結(jié)構(gòu)體stu2(這里只是成員間進(jìn)行賦值,并不改變結(jié)構(gòu)體的地址)
我們分別打印一下結(jié)構(gòu)體的stu1和結(jié)構(gòu)體stu2的地址:
發(fā)現(xiàn)只是將值進(jìn)行的賦值,但地址并沒(méi)有進(jìn)行改變 。
1.6結(jié)構(gòu)體的傳參:
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; }
這里我們有兩種傳參方法,一種是進(jìn)行整體結(jié)構(gòu)體傳參,另一個(gè)是進(jìn)行地址傳參,這兩種哪一種比較好呢?傳地址是比較好的 因?yàn)椋?span style="color:#be191c;">函數(shù)傳參的時(shí)候,參數(shù)是需要壓棧的。 如果傳遞一個(gè)結(jié)構(gòu)體對(duì)象的時(shí)候,結(jié)構(gòu)體過(guò)大,參數(shù)壓棧的的系統(tǒng)開(kāi)銷(xiāo)比較大,所以會(huì)導(dǎo)致性能的下降。
2、結(jié)構(gòu)體內(nèi)存對(duì)齊
2.1結(jié)構(gòu)體對(duì)齊的意義:
? ? ? 內(nèi)存是以字節(jié)為單位編號(hào)的,某些硬件平臺(tái)對(duì)特定類(lèi)型的數(shù)據(jù)的內(nèi)存要求從特定的地址開(kāi)始,如果數(shù)據(jù)的存放不符合其平臺(tái)的要求,就會(huì)影響到訪問(wèn)效率。所以在內(nèi)存中各類(lèi)型的數(shù)據(jù)按照一定的規(guī)則在內(nèi)存中存放,就是對(duì)齊問(wèn)題。而結(jié)構(gòu)體所占用的內(nèi)存空間就是每個(gè)成員對(duì)齊后存放時(shí)所占用的字節(jié)數(shù)之和。
1. 平臺(tái)原因(移植原因):
不是所有的硬件平臺(tái)都能訪問(wèn)任意地址上的任意數(shù)據(jù)的;某些硬件平臺(tái)只能在某些地址處取某些特
2.2結(jié)構(gòu)體內(nèi)存對(duì)齊的規(guī)則:
對(duì)齊數(shù):在編譯器中都存在一個(gè)默認(rèn)對(duì)齊數(shù) VS編譯器的對(duì)齊數(shù)是8 成員大小就是所占字節(jié)的大小例如 int的是4,char是1等等
2.3代碼演示:
struct S1
{
char c1;
int i;
char c2;
};
int main()
{
printf("%lu\n", sizeof(struct S1));
return 0;
}
例如這個(gè)結(jié)構(gòu)體 我們算的他所占字節(jié)是12 而結(jié)構(gòu)體S1中就一個(gè)兩個(gè)char類(lèi)型和一個(gè)int類(lèi)型不應(yīng)該字節(jié)數(shù)為6嗎 這里就是因?yàn)?strong>結(jié)構(gòu)體內(nèi)存對(duì)齊。
這里解釋了為什么是12:
我們也可以進(jìn)行對(duì)偏移量的打印來(lái)確認(rèn)一下
#include<stdio.h>
#include<stddef.h> //運(yùn)用offsetof這個(gè)宏需要引用這個(gè)頭文件
struct S1
{
char c1;
int i;
char c2;
};
int main()
{
printf("%lu\n", sizeof(struct S1));
printf("%lu\n",offsetof(struct S1,c1));
printf("%lu\n",offsetof(struct S1,i));
printf("%lu\n",offsetof(struct S1,c2));
return 0;
}
這里我們打印結(jié)果可以證明內(nèi)存對(duì)齊存在
2.4默認(rèn)對(duì)齊數(shù)的修改:?
#pragma pack(4) //這里把默認(rèn)對(duì)齊數(shù)修改成了4
struct S1
{
char c1;
int i;
char c2;
};
#pragma pack() //這里又回到了最初的默認(rèn)對(duì)齊數(shù)
3、結(jié)構(gòu)體類(lèi)型
3.1結(jié)構(gòu)體數(shù)組:
? ?結(jié)構(gòu)體數(shù)組一般應(yīng)用還比較多 例如:在完成通訊錄的時(shí)候,一個(gè)人員信息用結(jié)構(gòu)體但通訊錄并不是一個(gè)成員,則需要應(yīng)用到結(jié)構(gòu)體數(shù)組,在進(jìn)行同學(xué)信息統(tǒng)計(jì)也需要應(yīng)用結(jié)構(gòu)體數(shù)組。結(jié)構(gòu)體數(shù)組的定義和初始化其實(shí)都和上面差不多
3.1.1進(jìn)行聲明的同時(shí)定義:
struct Student
{
char name[20];//名字
int age;//年齡
char sex[5];//性別
char id[20];//學(xué)號(hào)
}stu[5]; //分號(hào)不能丟
3.1.2聲明后定義:
struct Student
{
char name[20];//名字
int age;//年齡
char sex[5];//性別
char id[20];//學(xué)號(hào)
}; //分號(hào)不能丟
struct Student stu[5];
3.1.3定義結(jié)構(gòu)體數(shù)組同時(shí)進(jìn)行初始化:
struct Student
{
char name[20];//名字
int age;//年齡
}; //分號(hào)不能丟
struct Student stu[2]={{"xiaoma",18},{"xiaoli",18};
3.1.4定義后在進(jìn)行初始化:
struct Student
{
char name[20];//名字
int age;//年齡
}; //分號(hào)不能丟
struct Student stu[2];
stu[1]=(struct Student){"xiaoma",18};
3.1.5將每個(gè)成員逐步初始化:
struct Student
{
char name[20];//名字
int age;//年齡
}; //分號(hào)不能丟
struct Student stu[2];
strcpy(stu[2].name,"xiaoma");
stu[2].age=18;
3.2結(jié)構(gòu)體指針:
結(jié)構(gòu)體指針應(yīng)用在數(shù)據(jù)結(jié)構(gòu)中比較多:例如應(yīng)用在單鏈表,帶頭雙向循環(huán)鏈表中用來(lái)指向下一個(gè)結(jié)構(gòu)體,同時(shí)進(jìn)行結(jié)構(gòu)體傳參的時(shí)候運(yùn)用指針也比較好。例子我就不舉了,大家可以看一下我的單向循環(huán)鏈表,和帶頭雙向循環(huán)鏈表進(jìn)行深入的了解一下結(jié)構(gòu)體指針。
struct Student
{
char name[20];//名字
int age;//年齡
char sex[5];//性別
char id[20];//學(xué)號(hào)
}; //分號(hào)不能丟
struct Student *pstu;
總結(jié):
? ? ? ? 以上就是結(jié)構(gòu)體的全部?jī)?nèi)容了,從結(jié)構(gòu)體的認(rèn)識(shí),結(jié)構(gòu)體存在的意義是什么,他和數(shù)組的區(qū)別,同時(shí)也有結(jié)構(gòu)體的聲明定義和初始化,在之后也講述了結(jié)構(gòu)體內(nèi)存對(duì)齊的原理和為什么要進(jìn)行內(nèi)存對(duì)齊,在之后結(jié)構(gòu)體類(lèi)型中只是講述了結(jié)構(gòu)體數(shù)組,和結(jié)構(gòu)體指針,結(jié)構(gòu)體函數(shù)傳參(在上面),結(jié)構(gòu)體傳參為什么有地址進(jìn)行傳參,而不是整體的進(jìn)行傳他的好處,這里已經(jīng)盡小馬所能把結(jié)構(gòu)體能想到的都給大家全部呈現(xiàn)出來(lái)啦!文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-781981.html
?最后小馬碼文不易,如果覺(jué)得有幫助就多多支持哈?。。?_?^文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-781981.html
到了這里,關(guān)于c語(yǔ)言結(jié)構(gòu)體看這篇文章就夠啦(詳細(xì)介紹結(jié)構(gòu)體)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!