淺談C語言結(jié)構(gòu)體
前言
在C語言中,除了內(nèi)置的許多數(shù)據(jù)類型,C語言還為我們提供了自定義的數(shù)據(jù)類型,其中就包括結(jié)構(gòu)體這一數(shù)據(jù)類型。
今天就讓我們來學(xué)習(xí)一下與結(jié)構(gòu)體相關(guān)的知識吧!

什么是結(jié)構(gòu)體
首先我們要知道,什么是結(jié)構(gòu)體?
在現(xiàn)實生活中,每一個事物都是復(fù)雜的,擁有許多的屬性,為了表示這些屬性,我們不可能用單一的數(shù)據(jù)類型來表示。
例如:一只貓具有的屬性有:年齡、體重、名字、品種等等。
為了描述這只貓的屬性,我們可以用整型變量來記錄年齡、用浮點型變量來記錄體重,用字符數(shù)組來記錄名字和體重等等。
但是,這就需要我們創(chuàng)建多個變量來表示這只貓。就以上面的栗子來說,如果我們只需要表示一只貓的屬性,就需要創(chuàng)建四次變量,這倒也可以接收,但如果我們要表示100只貓呢?我們就不可能每一只貓都單獨的創(chuàng)建四次變量了吧?
我們可以知道,每一次貓的屬性基本上都是相同的,無外乎年齡、體重、名字、品種等等,那么我們可不可把這些屬性抽象出來呢?答案是肯定的,這就是我們的結(jié)構(gòu)體!
結(jié)構(gòu)體類型的聲明
結(jié)構(gòu)體聲明的格式如下:
struct tag
{
member-list;
}variable-list;
代碼演示如下
struct Stu
{
char name[20];//名字
int age;//年齡
char sex[5];//性別
char id[20];//學(xué)號
};//分號不能丟
結(jié)構(gòu)體有時候還可以進(jìn)行特殊的聲明
例如,不完全聲明
//匿名結(jié)構(gòu)體類型
struct
{
int a;
char b;
float c;
}x;
struct
{
int a;
char b;
float c;
}a[20], *p;
上面的兩個結(jié)構(gòu)在聲明的時候省略掉了結(jié)構(gòu)體標(biāo)簽(tag)。
那么,問題來了?
//在上面代碼的基礎(chǔ)上,下面的代碼合法嗎? p = &x;
答案是否定的。
編譯器會把上面的兩個聲明當(dāng)成完全不同的兩個類型。
所以是非法的。
結(jié)構(gòu)的自引用
在結(jié)構(gòu)中包含一個類型為該結(jié)構(gòu)本身的成員是否可以呢?
//代碼1
struct Node
{
int data;
struct Node next;
};
//可行否?
上述代碼是否可行呢?
答案也是否定的,結(jié)構(gòu)體內(nèi)部的成員變量不可包含結(jié)構(gòu)體本身,否則就會無限套娃,死循環(huán)下去了。
當(dāng)我們想要結(jié)構(gòu)體里面還能有一個變量能夠指向一個結(jié)構(gòu)體的話,我們可以利用指針。
正確的自引用方式如下:
//代碼2
struct Node
{
int data;
struct Node* next;
};
結(jié)構(gòu)體變量的定義和初始化
有了結(jié)構(gòu)體類型,那如何定義變量,其實很簡單。
我們可以先聲明結(jié)構(gòu)體類型,然后直接再后面定義結(jié)構(gòu)體。
也可以先聲明結(jié)構(gòu)體類型,然后單獨的定義結(jié)構(gòu)體。
我們可以再定義結(jié)構(gòu)體的同時對其進(jìn)行初始化。
還可以先單獨定義一個結(jié)構(gòu)體,然后再單獨對其初始化。
具體看下面的代碼演示:
struct Point
{
int x;
int y;
}p1; //聲明類型的同時定義變量p1
struct Point p2; //定義結(jié)構(gòu)體變量p2
//初始化:定義變量的同時賦初值。
struct Point p3 = {x, y};
struct Stu //類型聲明
{
char name[15];//名字
int age; //年齡
};
struct Stu s = {"zhangsan", 20};//初始化
struct Node
{
int data;
struct Point p;
struct Node* next;
}n1 = {10, {4,5}, NULL}; //結(jié)構(gòu)體嵌套初始化
struct Node n2 = {20, {5, 6}, NULL};//結(jié)構(gòu)體嵌套初始化
結(jié)構(gòu)體的使用
結(jié)構(gòu)體的使用方法有兩種:一是結(jié)構(gòu)體直接使用成員變量,二是利用結(jié)構(gòu)體指針來引用成員變量。
具體看下面的代碼演示:
struct Stu
{
double sco;//分?jǐn)?shù)
int age;//年齡
char sex;//性別
};//分號不能丟
int main(){
struct Stu s1;
struct Stu* p;
p = &s1;
//結(jié)構(gòu)體直接訪問成員變量
s1.age = 10;
s1.sco = 88.8;
s1.sex = 'N';
//通過結(jié)構(gòu)體指針來訪問
p->age = 20;
p->sco = 95.5;
p->sex = 'W';
return 0;
}
結(jié)構(gòu)體內(nèi)存對齊
在我們已經(jīng)掌握了結(jié)構(gòu)體的基本使用之后,我們來探討一個更加深入的問題。
如何計算結(jié)構(gòu)體的大?。?/p>
struct S1
{
char c1;
int i;
char c2;
};
printf("%d\n", sizeof(struct S1));
小伙伴們你們認(rèn)為上述代碼的結(jié)構(gòu)是多少呢?
如果你簡單的認(rèn)為是:1+4+1 = 6,那么你就錯啦!
這段代碼在VS編譯器的默認(rèn)情況下的運行結(jié)果為:12
為什么會這樣呢?
這是因為,在內(nèi)存中,存在著結(jié)構(gòu)體對齊!
結(jié)構(gòu)體對齊規(guī)則如下:
第一個成員始終在與結(jié)構(gòu)體變量偏移量為0處。其他成員變量要對齊到對齊數(shù)的整數(shù)倍的地址處。對齊數(shù) = 編譯器默認(rèn)的一個對齊數(shù) 與 該成員變量本身大小的較小值。結(jié)構(gòu)體總大小為最大對齊數(shù)(每個成員變量都有一個對齊數(shù))的整數(shù)倍。如果嵌套了結(jié)構(gòu)體的情況,嵌套的結(jié)構(gòu)體對齊到自己的最大對齊數(shù)的整數(shù)倍處,結(jié)構(gòu)體的整體大小就是所有最大對齊數(shù)(含嵌套結(jié)構(gòu)體的對齊數(shù))的整數(shù)倍。
提示:VS編譯器默認(rèn)的對齊數(shù)為8
我們回看上面那段代碼,并畫圖分析。

注意
我們可以修改編譯器的默認(rèn)對齊數(shù),我們只需要加上這樣一句代碼就可以
//這里的數(shù)字就是我們想要修改稱為的大小 //例如這里我們就修改稱為了4 #pragma pack(4)
以上就是結(jié)構(gòu)體對齊的相關(guān)知識,由于這一部分內(nèi)容比較難,所以小伙伴們一定要多加練習(xí)哦!
結(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;
}
上面的 print1 和 print2 函數(shù)哪個好些?
答案顯然是printf2函數(shù)。
原因如下:
函數(shù)傳參的時候,參數(shù)是需要壓棧,會有時間和空間上的系統(tǒng)開銷。如果傳遞一個結(jié)構(gòu)體對象的時候,結(jié)構(gòu)體過大,參數(shù)壓棧的的系統(tǒng)開銷比較大,所以會導(dǎo)致性能的下降。
因此
我們在結(jié)構(gòu)體傳參的時候,需要傳結(jié)構(gòu)體的地址。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
C++實現(xiàn)CreatThread函數(shù)主線程與工作線程交互的方法
這篇文章主要介紹了C++實現(xiàn)CreatThread函數(shù)主線程與工作線程交互的方法,是Windows應(yīng)用程序設(shè)計中非常實用的方法,需要的朋友可以參考下2014-10-10
解析linux 文件和目錄操作的相關(guān)函數(shù)
以下是對linux中文件和目錄操作的相關(guān)函數(shù)進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下2013-08-08

