欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言?struct結(jié)構(gòu)體超詳細(xì)講解

 更新時(shí)間:2022年04月11日 17:50:44   作者:李逢溪  
C語言中,結(jié)構(gòu)體類型屬于一種構(gòu)造類型(其他的構(gòu)造類型還有:數(shù)組類型,聯(lián)合類型),下面這篇文章主要給大家介紹了關(guān)于C語言結(jié)構(gòu)體(struct)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下

一、本章重點(diǎn)

  • 創(chuàng)建結(jié)構(gòu)體
  • typedef與結(jié)構(gòu)體的淵源
  • 匿名結(jié)構(gòu)體
  • 結(jié)構(gòu)體大小
  • 結(jié)構(gòu)體指針
  • 其他

二、創(chuàng)建結(jié)構(gòu)體

先來個(gè)簡(jiǎn)單的結(jié)構(gòu)體創(chuàng)建

這就是一個(gè)比較標(biāo)準(zhǔn)的結(jié)構(gòu)體

struct people
{
	int age;
	int id;
	char address[10];
	char sex[5];
};//不要少了分號(hào)。

需要注意的是不要少了分號(hào)。

那么這樣創(chuàng)建結(jié)構(gòu)體呢?

struct phone
{
	char brand[10];//品牌
	int price;//價(jià)格
};
 
struct people
{
	int age;
	int id;
	char address[10];
	char sex[5];
	struct phone;
};

很顯然,一個(gè)結(jié)構(gòu)體是能夠嵌套另一個(gè)結(jié)構(gòu)體的。

沒有這樣的設(shè)計(jì),這樣做也行

struct people
{
	int age;
	int id;
	char address[10];
	char sex[5];
	char phone_brand[10];
	int phone_price;
};

但結(jié)構(gòu)體中成員太多了是不利于我們后期的維護(hù)的,試問:假設(shè)有1000個(gè)成員,你能快速的找出你需要的成員嗎?當(dāng)有了分塊的結(jié)構(gòu)體,我們是能夠迅速的定位和查看的。

??結(jié)構(gòu)體能夠嵌套另一結(jié)構(gòu)體,那么結(jié)構(gòu)體能否嵌套自己呢?

struct phone
{
	char brand[10];
	int price;
	struct phone;
};

這樣做之后編譯器會(huì)給你一個(gè)報(bào)錯(cuò)

原因是什么呢?

因?yàn)檫@個(gè)結(jié)構(gòu)體的大小是未定義的,你能算出這個(gè)結(jié)構(gòu)體的大小嗎?這是不可能的!

既然大小不能確定,那么當(dāng)你用這個(gè)結(jié)構(gòu)體去創(chuàng)建變量,編譯器該為這個(gè)變量開辟多大的空間呢?所有編譯器在設(shè)計(jì)之初便杜絕了這種可能。

在提一個(gè)問題,結(jié)構(gòu)體是否可以嵌套自己的結(jié)構(gòu)體指針呢?

struct people
{
	int age;
	int id;
	char address[10];
	char sex[5];
	struct people* son[2];
};

答案是:可以

這里并不存在空間該分配多少的問題,因?yàn)閟truct people*是指針類型,它的大小是確定的,在32位機(jī)器下是4字節(jié),64為機(jī)器是8字節(jié)。

三、typedef與結(jié)構(gòu)體的淵源

先上一段代碼

struct people
{
	int age;
	int id;
}a;//a代表什么?
 
 
int main()
{
	a.age = 20;
	printf("%d\n", a.age);
	return 0;
}

提問:a代表什么?

其實(shí)我們可以這樣去看這個(gè)問題

struct people{int age;int id;} a;
 
 
int main()
{
	a.age = 20;
	printf("%d\n", a.age);
	return 0;
}

對(duì)比int b呢?

int b;
struct people{int age;int id;} a;
 
 
int main()
{
	a.age = 20;
	printf("%d\n", a.age);
	return 0;
}

顯然,struct people{int age;int id;}代表的是結(jié)構(gòu)體類型,就像整形類型一樣去創(chuàng)建變量。

那么這里的a就是結(jié)構(gòu)體創(chuàng)建的變量。

這里也能明白結(jié)構(gòu)體創(chuàng)建的最后為什么要保留分號(hào)。

那我們?cè)倏匆欢未a:

typedef struct people
{
	int age;
	int id;
}a;
 
 
int main()
{
	a.age = 20;
	printf("%d\n", a.age);
	return 0;
}

此時(shí)加上typedef,a還能當(dāng)結(jié)構(gòu)體創(chuàng)建的變量嗎?

顯然不行,此時(shí)編譯器會(huì)報(bào)錯(cuò)。

 理解方式以上述一致。

typedef struct people{int age;int id;} a;

類似于

typedef struct people{int age;int id;} a;
typedef int b;

此時(shí)的a就是struct people{int age;int id;}

typedef的作用是把struct people{int age;int id;}這一類型重命名為a。

不知道你有沒有見過這樣的代碼

typedef struct people
{
	int age;
	int id;
}b,a,*c;
 
int main()
{
	a a1;
	b b1;
	c c1 = &a1;
	a1.age = 5;
	b1.age = 6;
	c1->age = 10;
	printf("%d %d %d\n", a1.age, b1.age, c1->age);
	return 0;
}

你知道運(yùn)行結(jié)果嗎?

這里的b、a、c是什么呢?

這里我就不啰嗦了,a和b都是struct people{int age;int id;}結(jié)構(gòu)體類型,c是struct people{int age;int id;}*  結(jié)構(gòu)體指針類型。

運(yùn)行結(jié)果:

那么再次提升一下

typedef struct people
{
	int age;
	int id;
}b, a, c[20];
這里的b、a、c代表什么呢?

期待著你動(dòng)手解決這一問題。

四、匿名結(jié)構(gòu)體

這就是一個(gè)匿名的結(jié)構(gòu)體

struct
{
	int age;
	int id;
};
 
int main()
{
	struct p1;
	p1.age = 10;
	printf("%d\n", p1.age);
	return 0;
}

匿名結(jié)構(gòu)體能這樣創(chuàng)建結(jié)構(gòu)體變量嗎?

此時(shí)編譯器會(huì)報(bào)錯(cuò)

這樣的匿名結(jié)構(gòu)體只能在創(chuàng)建結(jié)構(gòu)體的時(shí)候定義好變量。

比如這樣

struct
{
	int age;
	int id;
}p1;
 
int main()
{
	p1.age = 10;
	printf("%d\n", p1.age);
	return 0;
}

 接下來我們看下這段代碼

typedef struct
{
	int age;
	int id;
}people;
 
int main()
{
	people p1;
	p1.age = 10;
	printf("%d\n", p1.age);
	return 0;
}

這里我們重命名這個(gè)匿名結(jié)構(gòu)體,即把這個(gè)結(jié)構(gòu)體類型重命名為people。

那么我們自然可以用people類型來創(chuàng)建p1。也可創(chuàng)建p2、p3等等。

運(yùn)行結(jié)果:

以下代碼合法嗎?

//匿名結(jié)構(gòu)體類型
struct
{
 int a;
 char b;
 float c; 
}x;
 
struct
{
 int a;
 char b;
 float c; 
}a[20], *p;
 
int main()
{
    //在上面代碼的基礎(chǔ)上,下面的代碼合法嗎?
    p = &x;
    return 0;
}

警告: 編譯器會(huì)把上面的兩個(gè)聲明當(dāng)成完全不同的兩個(gè)類型。 所以是非法的。

五、結(jié)構(gòu)體大小

如何求結(jié)構(gòu)體類型的大?。?/p>

這需要了解結(jié)構(gòu)體成員在內(nèi)存是怎么存儲(chǔ)的。

你知道下面這段代碼的運(yùn)行結(jié)果嗎?

struct people
{
	char a;
	int b;
	char c;
};
 
int main()
{
	struct people p1;
	printf("%d\n", sizeof(p1));//大小是6嗎?
	return 0;
}

char是一字節(jié)大小

int是四字節(jié)大小

char是一字節(jié)大小

直接相加等于6

那么這個(gè)結(jié)構(gòu)體的大小是6嗎?

但我們發(fā)現(xiàn)答案是12

這是為什么呢?

簡(jiǎn)單來說編譯器為了讀取內(nèi)存時(shí)提升效率和避免讀取出錯(cuò),它做了內(nèi)存對(duì)齊的操作。

什么是內(nèi)存對(duì)齊?

就是讓數(shù)據(jù)安排在合適的位置上所進(jìn)行的對(duì)齊操作。

為什么要內(nèi)存對(duì)齊?

  • 一、移植原因

1.不是所有的硬件平臺(tái)都能訪問任意地址上的任意數(shù)據(jù)的;

2.某些硬件平臺(tái)只能在某些地址處取某些特定類型的數(shù)據(jù),否則拋出硬件異常。

  • 二、性能原因:

為了訪問未對(duì)齊的內(nèi)存,處理器需要作兩次內(nèi)存訪問;而對(duì)齊的內(nèi)存訪問僅需要一次訪問。

對(duì)齊規(guī)則:

Windows中默認(rèn)對(duì)齊數(shù)為8,Linux中默認(rèn)對(duì)齊數(shù)為4

  • 一:第一個(gè)數(shù)據(jù)成員從偏移地址為0的地方開始存放。
  • 二:對(duì)齊數(shù):等于默認(rèn)對(duì)齊數(shù)與與該成員大小的較小值。
  • 三:從第二成員開始,從它對(duì)齊數(shù)的整數(shù)倍的偏移地址開始存放。
  • 四:最后結(jié)構(gòu)體的大小需要調(diào)整為最大對(duì)齊數(shù)的整數(shù)倍。

最大對(duì)齊數(shù):即所有成員對(duì)齊數(shù)中最大的對(duì)齊數(shù)。

struct people
{
	char a;
	int b;
	char c;
};

解析:

第一個(gè)為char,直接放在偏移地址為0的位置處。

第二個(gè)為int,它的自身大小為4,比默認(rèn)對(duì)齊數(shù)小,所以它的對(duì)齊數(shù)是4。

4是4的整數(shù)倍,所以在偏移地址為4處開始放數(shù)據(jù)。

第三個(gè)為char,自身大小為1,比默認(rèn)對(duì)齊數(shù)小,它的對(duì)齊數(shù)是1。

8是1的整數(shù)倍,從偏移地址為8的位置開始放。

總大小為9,不是最大對(duì)齊數(shù)的整數(shù)倍

要浪費(fèi)3個(gè)空間,調(diào)整后為12。

我們?cè)倏纯聪旅孢@段代碼:

將char 和 int成員變量交換位置后,這結(jié)構(gòu)體的大小還是12嗎?

struct people
{
	char a;
	char c;
	int b;
};
 
int main()
{
	struct people p1;
	printf("%d\n", sizeof(p1));//大小是多少呢?
	return 0;
}

解析:

第一個(gè):直接從0處開始放

第二個(gè)是char:對(duì)齊數(shù)是1,1是1的整數(shù)倍,從偏移地址為1的位置開始放。

第二個(gè)是int:對(duì)齊數(shù)是4,4是4的整數(shù)倍,從偏移地址為4的位置開始放。

放好各個(gè)成員變量后,總大小是8,是最大對(duì)齊數(shù)(4)的整數(shù)倍,不需要調(diào)整。

因此這個(gè)結(jié)構(gòu)體的大小是8.

再來看看下面這個(gè)如何?

struct people
{
	char a;
	int b;
	short c[2];
	char d;
};
 
int main()
{
	struct people p1;
	printf("%d\n", sizeof(p1));//大小是6嗎?
	return 0;
}

解析:

第一個(gè)成員是char,直接放再0地址處。

第二個(gè)成員是int,對(duì)齊數(shù)是4,從偏移地址為4的位置處開始存放。

第三個(gè)成員是short[2],關(guān)于數(shù)組,它的對(duì)齊數(shù)是首元素的大小與默認(rèn)對(duì)齊數(shù)的較小值,這里它的對(duì)齊數(shù)是2,然后從偏移地址為8處開始存放4個(gè)字節(jié)。

第四個(gè)成員是char,對(duì)齊數(shù)是1,直接放開12位置處。

總大小是13,最大對(duì)齊數(shù)是4,不是最大對(duì)齊數(shù)的整數(shù)倍,需要對(duì)齊到最大對(duì)齊數(shù)的整數(shù)倍,浪費(fèi)3字節(jié)大小,對(duì)齊到16.

所以這個(gè)結(jié)構(gòu)體的大小是16.

六、結(jié)構(gòu)體指針

先創(chuàng)建一個(gè)結(jié)構(gòu)體

struct people
{
	char a;
	int b;
};

然后用該結(jié)構(gòu)體創(chuàng)建變量,再用結(jié)構(gòu)體指針指向該變量。

int main()
{
	struct people p1;
	struct people* p = &p1;
	return 0;
}

所謂結(jié)構(gòu)體指針,即指向結(jié)構(gòu)體的指針。

正如整形指針,即指向整形的指針。

訪問變量方式1:

int main()
{
	struct people p1;
	struct people* p = &p1;
	p1.a = 'a';
	p1.b = 10;
	printf("%c %d\n", p1.a, p1.b);
	return 0;
}

訪問變量方式2:

int main()
{
	struct people p1;
	struct people* p = &p1;
	p->a = 'a';
	p->b = 10;
	printf("%c %d\n", p->a, p->b);
	return 0;
}

訪問變量方式3:

int main()
{
	struct people p1;
	struct people* p = &p1;
	(*p).a = 'a';
	(*p).b = 10;
	printf("%c %d\n", (*p).a, (*p).b);
	return 0;
}

七、其他

結(jié)構(gòu)體中還有兩個(gè)常見知識(shí)點(diǎn):

一、位端

二、柔性數(shù)組

由于篇幅原因,下期會(huì)細(xì)細(xì)講解這兩個(gè)知識(shí)點(diǎn)

到此這篇關(guān)于C語言 struct關(guān)鍵字超詳細(xì)講解的文章就介紹到這了,更多相關(guān)C語言 struct內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言實(shí)例講解四大循環(huán)語句的使用

    C語言實(shí)例講解四大循環(huán)語句的使用

    C語言有四大循環(huán)語句,他們之間可以進(jìn)行任意轉(zhuǎn)換。本文將首先對(duì)其語法進(jìn)行講解,然后通過一個(gè)實(shí)例用四種循環(huán)來實(shí)現(xiàn)。相信通過本文的學(xué)習(xí),大家都能夠?qū)語言循環(huán)語句有著熟練的掌握
    2022-05-05
  • C語言之復(fù)雜鏈表的復(fù)制方法(圖示詳解)

    C語言之復(fù)雜鏈表的復(fù)制方法(圖示詳解)

    下面小編就為大家?guī)硪黄狢語言之復(fù)雜鏈表的復(fù)制方法(圖示詳解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-07-07
  • C++數(shù)據(jù)結(jié)構(gòu)分析多態(tài)的實(shí)現(xiàn)與原理及抽象類

    C++數(shù)據(jù)結(jié)構(gòu)分析多態(tài)的實(shí)現(xiàn)與原理及抽象類

    繼承就是可以直接使用前輩的屬性和方法。自然界如果沒有繼承,那一切都是處于混沌狀態(tài)。多態(tài)是同一個(gè)行為具有多個(gè)不同表現(xiàn)形式或形態(tài)的能力。多態(tài)就是同一個(gè)接口,使用不同的實(shí)例而執(zhí)行不同操作
    2022-02-02
  • C++中的結(jié)構(gòu)體vector排序問題

    C++中的結(jié)構(gòu)體vector排序問題

    這篇文章主要介紹了C++中的結(jié)構(gòu)體vector排序問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • 用C語言實(shí)現(xiàn)從文本文件中讀取數(shù)據(jù)后進(jìn)行排序的功能

    用C語言實(shí)現(xiàn)從文本文件中讀取數(shù)據(jù)后進(jìn)行排序的功能

    這是一個(gè)十分可靠的程序,這個(gè)程序的查錯(cuò)能力非常強(qiáng)悍。程序包含了文件操作,歸并排序和字符串輸入等多種技術(shù)。對(duì)大家學(xué)習(xí)C語言很有幫助,有需要的一起來看看。
    2016-08-08
  • C/C++?Qt?TreeWidget?單層樹形組件應(yīng)用小結(jié)

    C/C++?Qt?TreeWidget?單層樹形組件應(yīng)用小結(jié)

    TreeWidget?目錄樹組件,該組件適用于創(chuàng)建和管理目錄樹結(jié)構(gòu),在開發(fā)中我們經(jīng)常會(huì)把它當(dāng)作一個(gè)升級(jí)版的ListView組件使用,本文將通過TreeWidget實(shí)現(xiàn)多字段顯示,并增加一個(gè)自定義菜單,通過在指定記錄上右鍵可彈出該菜單并對(duì)指定記錄進(jìn)行操作
    2021-11-11
  • C++使用new和delete進(jìn)行動(dòng)態(tài)內(nèi)存分配與數(shù)組封裝

    C++使用new和delete進(jìn)行動(dòng)態(tài)內(nèi)存分配與數(shù)組封裝

    這篇文章主要介紹了C++使用new和delete進(jìn)行動(dòng)態(tài)內(nèi)存分配與數(shù)組封裝,運(yùn)行期間才能確定所需內(nèi)存大小,此時(shí)應(yīng)該使用new申請(qǐng)內(nèi)存,下面我們就進(jìn)入文章學(xué)習(xí)具體的操作方法,需要的小伙伴可以參考一下
    2022-03-03
  • 史上最強(qiáng)C語言分支和循環(huán)教程詳解

    史上最強(qiáng)C語言分支和循環(huán)教程詳解

    這篇文章主要介紹了史上最強(qiáng)C語言分支和循環(huán)教程詳解,本文通過代碼演示給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-11-11
  • 詳解C++實(shí)現(xiàn)鏈表的排序算法

    詳解C++實(shí)現(xiàn)鏈表的排序算法

    鏈表排序思想和數(shù)組排序類似,區(qū)別就是數(shù)組遍歷容易,數(shù)據(jù)交換也容易;鏈表(單項(xiàng)鏈表)只能一個(gè)方向遍歷,不能逆序遍歷,且不能隨機(jī)訪問,所以排序比較麻煩。本文將詳細(xì)介紹鏈表排序的方式,并且用C++來實(shí)現(xiàn)
    2021-06-06
  • C語言 動(dòng)態(tài)內(nèi)存分配的詳解及實(shí)例

    C語言 動(dòng)態(tài)內(nèi)存分配的詳解及實(shí)例

    這篇文章主要介紹了C語言 動(dòng)態(tài)內(nèi)存分配的詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2016-09-09

最新評(píng)論