亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C/C++自定義類型結(jié)構(gòu)體全解析

 更新時間:2025年05月15日 09:45:41   作者:鳳年徐  
c語言有內(nèi)置類型(char?short?int?long?flaot?double?long?double),也有自定義類型—結(jié)構(gòu)體(struct)?枚舉(enum)?聯(lián)合體(union)?本文介紹結(jié)構(gòu)體,感興趣的朋友跟隨小編一起看看吧

前言

集成開發(fā)環(huán)境為vs2022

c語言有內(nèi)置類型(char short int long flaot double long double),也有自定義類型—結(jié)構(gòu)體(struct) 枚舉(enum) 聯(lián)合體(union) 本篇幅介紹結(jié)構(gòu)體

自定義類型:結(jié)構(gòu)體

1.結(jié)構(gòu)體類型的聲明

前?我們在學(xué)習(xí)操作符的時候,已經(jīng)學(xué)習(xí)了結(jié)構(gòu)體的知識,這?稍微復(fù)習(xí)?下。

1.1 結(jié)構(gòu)體回顧

結(jié)構(gòu)是?些值的集合,這些值稱為成員變量。結(jié)構(gòu)的每個成員可以是不同類型的變量。

1.1.1 結(jié)構(gòu)的聲明

struct tag//標(biāo)簽名
{
 member-list;//成員 1個或多個
}variable-list;//變量列表

例如描述?個學(xué)?:

struct Stu
{
 char name[20];//名字 
 int age;//年齡 
 char sex[5];//性別 
 char id[20];//學(xué)號 
}; //分號不能丟 
struct Book b2;//全局變量
int main()
{
 struct Book b1;//局部變量
 return 0;
}

1.1.2 結(jié)構(gòu)體變量的創(chuàng)建和初始化

#include <stdio.h>
struct Stu
{
 char name[20];//名字 
 int age;//年齡 
 char sex[5];//性別 
 char id[20];//學(xué)號 
};
int main()
{
 //按照結(jié)構(gòu)體成員的順序初始化 
 struct Stu s = { "張三", 20, "男", "20230818001" };
 printf("name: %s\n", s.name);
 printf("age : %d\n", s.age);
 printf("sex : %s\n", s.sex);
 printf("id : %s\n", s.id);
 //按照指定的順序初始化 
 struct Stu s2 = { .age = 18, .name = "lisi", .id = "20230818002", .sex = 
"?" };
 printf("name: %s\n", s2.name);
 printf("age : %d\n", s2.age);
 printf("sex : %s\n", s2.sex);
 printf("id : %s\n", s2.id);
 return 0;
}

1.2 結(jié)構(gòu)的特殊聲明

在聲明結(jié)構(gòu)的時候,可以不完全的聲明。

?如:

//匿名結(jié)構(gòu)體類型 
struct//這里不寫名字
{
 int a;
 char b;
 float c;
}s;//可以在這初始化
//}s={'x',100.3.14};
int main()
{
    printf("%c %d %lf",s.c,s.i,s.d);
}

匿名結(jié)構(gòu)體也可以重新命名

typedef struct
{
 char c;
 int i;
 double d;
}s;

上?的兩個結(jié)構(gòu)在聲明的時候省略掉了結(jié)構(gòu)體標(biāo)簽(tag)。 那么問題來了?

//在上?代碼的基礎(chǔ)上,下?的代碼合法嗎? 
p = &x;

警告:

編譯器會把上?的兩個聲明當(dāng)成完全不同的兩個類型,所以是非法的。

匿名的結(jié)構(gòu)體類型,如果沒有對結(jié)構(gòu)體類型重命名的話,基本上只能使??次。

1.3 結(jié)構(gòu)的自引用

在結(jié)構(gòu)中包含?個類型為該結(jié)構(gòu)本?的成員是否可以呢?

?如,定義?個鏈表的節(jié)點

在這之前先講一下鏈表

數(shù)據(jù)結(jié)構(gòu)–其實是數(shù)據(jù)在內(nèi)存中的存儲和組織的結(jié)構(gòu) 數(shù)據(jù)有多種

線性數(shù)據(jù)結(jié)構(gòu):順序表,鏈表,棧,隊列

順序表–數(shù)組

鏈表

//定義一個鏈表節(jié)點
struct Node
{
 int data;
 struct Node next;
};

上述代碼正確嗎?如果正確,那 sizeof(struct Node) 是多少?

仔細(xì)分析,其實是不?的,因為?個結(jié)構(gòu)體中再包含?個同類型的結(jié)構(gòu)體變量,這樣結(jié)構(gòu)體變量的? ?就會?窮的?,是不合理的。

正確的?引??式:

struct Node{
 int data;//數(shù)據(jù)
 struct Node* next;//指針
};

在結(jié)構(gòu)體?引?使?的過程中,夾雜了 typedef 對匿名結(jié)構(gòu)體類型重命名,也容易引?問題,看看 下?的代碼,可?嗎?

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

答案是不?的,因為Node是對前?的匿名結(jié)構(gòu)體類型的重命名產(chǎn)?的,但是在匿名結(jié)構(gòu)體內(nèi)部提前使 ?Node類型來創(chuàng)建成員變量,這是不?的。

匿名結(jié)構(gòu)體類型不能實現(xiàn)結(jié)構(gòu)體的自引用

解決?案如下:定義結(jié)構(gòu)體不要使用匿名結(jié)構(gòu)體了

typedef struct Node
{
 int data;
 struct Node* next;
}Node;
//上述代碼等價于下邊代碼
struct Node
{
 int data;
 struct Node* next;
}
typedef struct Node Node;

2.結(jié)構(gòu)體內(nèi)存對齊

我們已經(jīng)掌握了結(jié)構(gòu)體的基本使?了。

現(xiàn)在我們深?討論?個問題:計算結(jié)構(gòu)體的??。

這也是?個特別熱?的考點: 結(jié)構(gòu)體內(nèi)存對?

2.1 對?規(guī)則

?先得掌握結(jié)構(gòu)體的對?規(guī)則:

1.結(jié)構(gòu)體的第1個成員對?到和結(jié)構(gòu)體變量起始位置偏移量為0的地址處

2.從第2個成員變量開始,都要對?到某個對?數(shù)的整數(shù)倍的地址處。

對?數(shù)=編譯器默認(rèn)的?個對?數(shù)與該成員變量??的較?值

VS 中默認(rèn)的值為 8

Linux中g(shù)cc沒有默認(rèn)對?數(shù),對?數(shù)就是成員??的??

3.結(jié)構(gòu)體總大小為最大對齊數(shù)(結(jié)構(gòu)體中每個成員變量都有?個對?數(shù),所有對?數(shù)中最?的)的 整數(shù)倍。

4.如果嵌套了結(jié)構(gòu)體的情況,嵌套的結(jié)構(gòu)體成員對?到??的成員中最?對?數(shù)的整數(shù)

//練習(xí)1 
struct S1
{       //   默認(rèn)   對齊數(shù)
 char c1;// 1 8     1
 int i;//   4 8     4
 char c2;// 1 8     1
};
printf("%d\n", sizeof(struct S1));
//練習(xí)2 
struct S2
{
 char c1;
 char c2;
 int i;
};
printf("%d\n", sizeof(struct S2));
//練習(xí)3 
struct S3
{
 double d;
 char c;
 int i;
};
printf("%d\n", sizeof(struct S3));
//練習(xí)4-結(jié)構(gòu)體嵌套問題 
struct S4
{
 char c1;
 struct S3 s3;
 double d;
};
printf("%d\n", sizeof(struct S4));

2.2 為什么存在內(nèi)存對齊?

?部分的參考資料都是這樣說的:

1. 平臺原因(移植原因):

不是所有的硬件平臺都能訪問任意地址上的任意數(shù)據(jù)的;某些硬件平臺只能在某些地址處取某些特定 類型的數(shù)據(jù),否則拋出硬件異常。

2.性能原因

數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能地在?然邊界上對?。原因在于,為了訪問未對?的內(nèi)存,處理器需要 作兩次內(nèi)存訪問;?對?的內(nèi)存訪問僅需要?次訪問。假設(shè)?個處理器總是從內(nèi)存中取8個字節(jié),則地 址必須是8的倍數(shù)。如果我們能保證將所有的double類型的數(shù)據(jù)的地址都對?成8的倍數(shù),那么就可以 ??個內(nèi)存操作來讀或者寫值了。否則,我們可能需要執(zhí)?兩次內(nèi)存訪問,因為對象可能被分放在兩 個8字節(jié)內(nèi)存塊中。

總體來說:結(jié)構(gòu)體的內(nèi)存對?是拿空間來換取時間的做法。

例如

struct S
{
  char c;//1
  int i;//4 
};

那在設(shè)計結(jié)構(gòu)體的時候,我們既要滿?對?,?要節(jié)省空間,如何做到:

讓占?空間?的成員盡量集中在?起

//例如: 
struct S1
{
 char c1;
 int i;
 char c2;
};
struct S2
{
 char c1;
 char c2;
 int i;
};

S1 和 S2 類型的成員?模?樣,但是 S1 和 S2 所占空間的??有了?些區(qū)別。

2.3 修改默認(rèn)對?數(shù)

#pragma 這個預(yù)處理指令,可以改變編譯器的默認(rèn)對?數(shù)。

#include <stdio.h>
#pragma pack(1)//設(shè)置默認(rèn)對?數(shù)為1  一般是2的次方數(shù) linux中不能改
struct S
{
 char c1;
 int i;
 char c2;
};
#pragma pack()//取消設(shè)置的對?數(shù),還原為默認(rèn) 
int main()
{
 //輸出的結(jié)果是什么? 6
 printf("%d\n", sizeof(struct S));
 return 0;
}

結(jié)構(gòu)體在對??式不合適的時候,我們可以??更改默認(rèn)對?數(shù)。

3. 結(jié)構(gòu)體傳參

struct S
{
 int data[1000];//4000字節(jié)
 int num;
};
struct S s = {{1,2,3,4}, 1000};
//結(jié)構(gòu)體傳參 
void print1(struct S s)//s先拷貝,占用內(nèi)存很大
{
    //for循環(huán)打印數(shù)組
 printf("%d\n", s.num);
}
//結(jié)構(gòu)體地址傳參 
void print2(const struct S* ps)
{
 printf("%d\n", ps->num);
 printf("%d\n",ps->data[i]);
}
int main()
{
 print1(s); //傳結(jié)構(gòu)體 
 print2(&s); //傳地址 
 return 0;
}

上?的 print1 和 print2 函數(shù)哪個好些?

答案是:首選print2函數(shù)。

原因:

函數(shù)傳參的時候,參數(shù)是需要壓棧,會有時間和空間上的系統(tǒng)開銷。
如果傳遞?個結(jié)構(gòu)體對象的時候,結(jié)構(gòu)體過?,參數(shù)壓棧的的系統(tǒng)開銷?較?,所以會導(dǎo)致性能的下降。
結(jié)論:結(jié)構(gòu)體傳參的時候,要傳結(jié)構(gòu)體的地址。

4.結(jié)構(gòu)體實現(xiàn)位段

4.1 什么是位段

位段的聲明和結(jié)構(gòu)是類似的,有兩個不同:

1.位段的成員必須是 int、unsigned int 或signed int ,在C99中位段成員的類型也可以 選擇其他整型家族類型,?如:char

2.位段的成員名后邊有?個冒號?個數(shù)字。

?如:

struct A
{
 int _a:2;//只占兩個bit位
 int _b:5;
 int _c:10;
 int _d:30;
};
struct s
{
  int _a;//4字節(jié) 32bit 可以節(jié)省30個字節(jié)
  int _b;
  int _c;
  int _d;
    //00   0
    //01   1
    //10   2
    //11   3
}

A就是?個位段類型。

位段是專門用來節(jié)省內(nèi)存的

那位段A所占內(nèi)存的??是多少?

    // %zd            8字節(jié)
printf("%d\n", sizeof(struct A));//

4.2 位段的內(nèi)存分配

1.位段的成員可以是 int unsigned int signed int 或者是 char 等類型

2.位段的空間上是按照需要以**4個字節(jié)( int )或者1個字節(jié)( char )**的?式來開辟的。

3.位段涉及很多不確定因素,位段是不跨平臺的,注重可移植的程序應(yīng)該避免使?位段。

//?個例? 
struct S
{
  char a:3;
  char b:4;
  char c:5;
  char d:4;
};
struct S s = {0};
s.a = 10;//00001010
s.b = 12;//00001100
s.c = 3;//00000011
s.d = 4;//00000100
//空間是如何開辟的? 

在這之前我們先要了解一下內(nèi)存的使用順序

1.申請到的一塊內(nèi)存中,從左向右使用,還是從右向左使用,是不確定的 vs是從右向左

2.剩余空間,不是下一個成員使用的時候,是浪費呢?還是繼續(xù)使用? vs是浪費

4.3 位段的跨平臺問題

  • int位段被當(dāng)成有符號數(shù)還是?符號數(shù)是不確定的。
  • 位段中最?位的數(shù)?不能確定。(16位機器最?16,32位機器最?32,寫成27,在16位機器會出問題。
  • 位段中的成員在內(nèi)存中從左向右分配,還是從右向左分配,標(biāo)準(zhǔn)尚未定義。
  • 當(dāng)?個結(jié)構(gòu)包含兩個位段,第?個位段成員?較?,?法容納于第?個位段剩余的位時,是舍棄剩余的位是利?,這是不確定的。
  • 總結(jié):
  • 跟結(jié)構(gòu)相?,位段可以達(dá)到同樣的效果,并且可以很好的節(jié)省空間,但是有跨平臺的問題存在。

4.4 位段的應(yīng)用

下圖是?絡(luò)協(xié)議中,IP數(shù)據(jù)報的格式,我們可以看到其中很多的屬性只需要?個bit位就能描述,這? 使?位段,能夠?qū)崿F(xiàn)想要的效果,也節(jié)省了空間,這樣?絡(luò)傳輸?shù)臄?shù)據(jù)報??也會較??些,對?絡(luò) 的暢通是有幫助的。

4.5 位段使用的注意事項

**位段的?個成員共有同?個字節(jié),這樣有些成員的起始位置并不是某個字節(jié)的起始位置,那么這些位置處是沒有地址的。內(nèi)存中每個字節(jié)分配?個地址,?個字節(jié)內(nèi)部的bit位是沒有地址的。
以不能對位段的成員使?&操作符,這樣就不能使?scanf直接給位段的成員輸?值,**只能是先輸?放在?個變量中,然后賦值給位段的成員。

一個字節(jié)一個地址

struct A
{
 int _a : 2;
 int _b : 5;
 int _c : 10;
 int _d : 30;
};
int main()
{
 struct A sa = {0};
 scanf("%d", &sa._b);//這是錯誤的 
 //正確的?范 
 int b = 0;
 scanf("%d", &b);
 sa._b = b;
 return 0;
}

到此這篇關(guān)于C/C++自定義類型:結(jié)構(gòu)體的文章就介紹到這了,更多相關(guān)C++結(jié)構(gòu)體內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 構(gòu)建mfc窗體的簡單示例

    構(gòu)建mfc窗體的簡單示例

    這篇文章主要介紹了構(gòu)建mfc窗體的簡單示例,需要的朋友可以參考下
    2014-04-04
  • C++產(chǎn)生隨機數(shù)的實現(xiàn)代碼

    C++產(chǎn)生隨機數(shù)的實現(xiàn)代碼

    本篇文章是對C++中產(chǎn)生隨機數(shù)的實現(xiàn)代碼進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C++ 標(biāo)準(zhǔn)模板庫 STL 順序容器詳解

    C++ 標(biāo)準(zhǔn)模板庫 STL 順序容器詳解

    這篇文章主要介紹了C++ 標(biāo)準(zhǔn)模板庫 STL 順序容器詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-05-05
  • C語言二叉樹層序遍歷

    C語言二叉樹層序遍歷

    這篇文章主要介紹了C語言二叉樹層序遍歷,文章基于C語言的相關(guān)資料展開詳細(xì)的文章內(nèi)容,具有一定的參考價值,需要的小伙伴可以參考一下,希望對你的學(xué)習(xí)有所幫助
    2022-04-04
  • C++中的string庫函數(shù)常見函數(shù)的作用和使用方法

    C++中的string庫函數(shù)常見函數(shù)的作用和使用方法

    這篇文章主要介紹了C++中的string庫函數(shù)常見函數(shù)的作用和使用方法,庫函數(shù)的靈活應(yīng)用是程序員的一大重要技能,本文通過實例實例代碼給大家講解的非常詳細(xì),需要的朋友可以參考下
    2022-04-04
  • C語言實現(xiàn)簡單的停車場管理系統(tǒng)

    C語言實現(xiàn)簡單的停車場管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)簡單的停車場管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • VSCode無法打開源文件及無法打開鏈接庫文件的解決方法

    VSCode無法打開源文件及無法打開鏈接庫文件的解決方法

    本文主要介紹了VSCode無法打開源文件及無法打開鏈接庫文件的解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • C++ DFS算法實現(xiàn)走迷宮自動尋路

    C++ DFS算法實現(xiàn)走迷宮自動尋路

    這篇文章主要為大家詳細(xì)介紹了C++ DFS算法實現(xiàn)走迷宮自動尋路,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-05-05
  • 一文詳解Qt的QObject類

    一文詳解Qt的QObject類

    Qt的QObject類是Qt框架中的基類,它是所有Qt對象的父類,本文主要介紹了Qt的QObject類,具有一定的參考價值,感興趣的可以了解一下
    2023-09-09
  • C++ 單鏈表的基本操作(詳解)

    C++ 單鏈表的基本操作(詳解)

    下面小編就為大家?guī)硪黄狢++ 單鏈表的基本操作(詳解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12

最新評論