<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          哦!數(shù)組還能這么用,學(xué)到了!

          共 2121字,需瀏覽 5分鐘

           ·

          2020-08-06 04:08

          來源:公眾號(hào)【編程珠璣】

          作者:守望先生

          ID:shouwangxiansheng


          這個(gè)問題源于讀者在閱讀redis源碼時(shí)的一個(gè)疑問。

          先看下面的代碼,對(duì)于包含動(dòng)態(tài)字符串成員的兩個(gè)結(jié)構(gòu)體Test0和Test1占用空間分別是多少呢?

          //來源:公眾號(hào)【編程珠璣】
          //作者:守望先生
          #include
          struct?Test0
          {

          ????int?a;
          ????int?b;
          ????char?*c;
          };
          struct?Test1
          {

          ????int?a;
          ????int?b;
          ????char?c[];
          };
          int?main(void)
          {
          ????printf("sizeof(struct?Test0)?=?%zd\n",sizeof(struct?Test0));
          ????printf("sizeof(struct?Test1)?=?%zd\n",sizeof(struct?Test1));
          ????return?0;
          }

          很多讀者一眼就能看出來,在64位系統(tǒng)上,編譯為64位程序,其輸出結(jié)果為:

          16
          8

          對(duì)于Test0的結(jié)果是16,通常沒有什么疑問,畢竟4(int)+4(int)+8(指針)= 16,但是對(duì)于后者的結(jié)構(gòu)體占用空間為8字節(jié),有的讀者可能會(huì)有疑問。(關(guān)于字節(jié)對(duì)齊,參考《字節(jié)對(duì)齊,看這篇就懂了》)

          柔性數(shù)組(flexible array)

          實(shí)際上這是在C99中引入的柔性數(shù)組的特性。即結(jié)構(gòu)體的最后一個(gè)成員,可以不完整類型(一種缺乏足夠的信息去描述一個(gè)完整對(duì)象的類型)的數(shù)組,但它使得整個(gè)結(jié)構(gòu)體的大小就像沒有這個(gè)成員一樣。但是呢,當(dāng)用結(jié)構(gòu)體通過這個(gè)名字訪問這個(gè)成員時(shí),就像訪問一個(gè)普通數(shù)組成員一樣。

          如果數(shù)組最終一個(gè)元素都沒有的話,那么訪問這個(gè)數(shù)組將會(huì)是未定義行為了。

          正如我們前面所看到的:

          struct?Test1
          {

          ????int?a;
          ????int?b;
          ????char?c[];
          };

          成員c是一個(gè)數(shù)組,但是并沒有指定大小,使用sizeof計(jì)算Test1,其占用空間也僅僅是8字節(jié)。

          有什么好處?

          那么使用柔性數(shù)組有什么好處呢?

          內(nèi)存申請(qǐng)和釋放

          假設(shè)分別使用兩種類型的結(jié)構(gòu)體,存儲(chǔ)16字節(jié)的字符數(shù)據(jù),需要申請(qǐng)內(nèi)存。對(duì)于struct Test0:

          strcut?Test0?*t0?=?malloc(sizeof(struct?Test0));//為結(jié)構(gòu)體申請(qǐng)內(nèi)存
          t0->c?=?malloc(sizeof(char)?*?16);//為成員指向的數(shù)據(jù)申請(qǐng)內(nèi)存

          而對(duì)于struct Test1:

          strcut?Test1?*t1?=?malloc(sizeof(struct?Test1)?+?sizeof(char)?*?16);

          看出區(qū)別了嗎?前者需要兩次內(nèi)存申請(qǐng),而后者只需要一次。前者地址不連續(xù)(兩次malloc),后者地址連續(xù)。而你訪問成員c的時(shí)候,只需要下面這樣就可以:

          t1->c,和普通成員無(wú)異。

          要判斷它們的地址是否連續(xù)也非常簡(jiǎn)單,只需要分別打印b和c的地址就可以了。

          和內(nèi)存釋放類似,前面需要單獨(dú)釋放成員c申請(qǐng)的內(nèi)存,而后者可以一起釋放。

          數(shù)據(jù)拷貝

          正由于前面的差別,導(dǎo)致數(shù)據(jù)拷貝時(shí),更有區(qū)別。
          對(duì)于struct Test0:

          //memcpy(t0copy,t0,sizeof(struct Test0));//不可,這樣直接t0copy的c和t0的c指向同一片內(nèi)存區(qū)域。

          t0copy.a?=?t0.a;
          t0copy.b?=?t0.b;
          memcpy(t0copy.c,t0.c,sizeof(char)*16);

          這里無(wú)法一次拷貝,因?yàn)樗某蓡Tc是一個(gè)指針類型,我們需要的是一份完整拷貝,因此必須拷貝它指向的內(nèi)存。(參考《結(jié)構(gòu)體成員賦值到底是深拷貝還是淺拷貝?》)

          但是對(duì)于struct Test1:

          memcpy(t0copy,t0,sizeof(strcut?Test1)?+?sizeof(char)?*?16);

          在這里,由于柔性數(shù)組的內(nèi)存,它的數(shù)據(jù)內(nèi)容和結(jié)構(gòu)體數(shù)據(jù)成員的地址是連續(xù)的,因此可以直接拷貝。

          減少內(nèi)存碎片

          由于結(jié)構(gòu)體的柔性數(shù)組和結(jié)構(gòu)體成員的地址是連續(xù)的,即可一同申請(qǐng)內(nèi)存,因此更大程度地避免了內(nèi)存碎片。另外由于該成員本身不占結(jié)構(gòu)體空間,因此,整體而言,比普通的數(shù)組成員占用空間要會(huì)稍微小點(diǎn)。

          零長(zhǎng)數(shù)組

          與柔性數(shù)組功能類似,還有一個(gè)0長(zhǎng)數(shù)組,不過它并不是標(biāo)準(zhǔn)中的,但是它可以實(shí)現(xiàn)類似的功能,使用方式如下:

          struct?Test1
          {

          ????int?a;
          ????int?b;
          ????char?c[0];
          };

          差別在于使得數(shù)組長(zhǎng)度為0。但是由于它并非C標(biāo)準(zhǔn)中的,因此從可移植性考慮,不建議使用這種方式,除非你還無(wú)法使用C99。

          總結(jié)

          柔性數(shù)組的使用:

          • 位于結(jié)構(gòu)體最后一個(gè)位置

          • 不完整數(shù)組類型

          • 不是唯一成員

          最后,放張圖,看差別:

          普通和柔性數(shù)組

          ?
          推薦閱讀:
          專輯|Linux文章匯總
          專輯|程序人生
          專輯|C語(yǔ)言


          嵌入式Linux
          微信掃描二維碼,關(guān)注我的公眾號(hào)?
          瀏覽 49
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美大黑吊插老女人肛门 | 亚洲熟女一区 | 中文字幕成人网 | 99视频免费在线观看 | 天干夜天干天天天爽 |