最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言中0數(shù)組\柔性數(shù)組的使用詳解

 更新時間:2021年05月10日 12:39:06   作者:良知猶存  
這篇文章主要給大家介紹了關(guān)于C語言中0數(shù)組\柔性數(shù)組使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言:

上次看到一篇面試分享,里面有個朋友說,面試官問了char[0] 相關(guān)問題,但是自己沒有遇到過,就繞過了這個問題。

我自己在這篇文章下面做了一些回復(fù)。

現(xiàn)在我想結(jié)合我自己的理解,解釋一下這個 char[0] C語言柔性數(shù)組的問題。

0數(shù)組和柔性數(shù)組的介紹

0數(shù)組顧名思義,就是數(shù)組長度定義為0,我們一般知道數(shù)組長度定義至少為1才會給它分配實(shí)際的空間,而定義了0的數(shù)組是沒有任何空間,但是如果像上面的結(jié)構(gòu)體一樣在最后一個成員定義為零數(shù)組,雖然零數(shù)組沒有分配的空間,但是它可以當(dāng)作一個偏移量,因?yàn)閿?shù)組名這個符號本身代表了一個不可修改的地址常量。柔性數(shù)組也叫可伸縮性數(shù)組,而0數(shù)組是一種柔性數(shù)組。

因?yàn)樵谠缙跊]引入0長度數(shù)組的時候, 大家是通過定長數(shù)組和指針的方式來解決的, 但是定長數(shù)組定義了一個足夠大的緩沖區(qū), 這樣使用方便, 但是每次都造成空間的浪費(fèi)指針的方式, 要求程序員在釋放空間是必須進(jìn)行多次的free操作, 而我們在使用的過程中往往在函數(shù)中返回了指向緩沖區(qū)的指針, 我們并不能保證每個人都理解并遵從我們的釋放方式所以 GNU 就對其進(jìn)行了0長度數(shù)組的擴(kuò)展. 當(dāng)使用data[0]的時候, 也就是0長度數(shù)組的時候,0長度數(shù)組作為數(shù)組名, 并不占用存儲空間。這樣就可以更加高效的利用內(nèi)存。

在C99之后,也加了類似的擴(kuò)展,只不過用的是 char payload[]這種形式(所以如果你在編譯的時候確實(shí)需要用到-pedantic參數(shù),那么你可以將char payload[0]類型改成char payload[], 這樣就可以編譯通過了,當(dāng)然你的編譯器必須支持C99標(biāo)準(zhǔn)的,如果太古老的編譯器,那可能不支持了。

0數(shù)組的常規(guī)使用

首先我們定義一個結(jié)構(gòu)體,再在一個結(jié)構(gòu)體的最后,定義一個長度為0的數(shù)組,就可以使得這個結(jié)構(gòu)體是可變長的。

如下所示:

//  0長度數(shù)組
struct zero_buffer
{
    int     len;
    char    data[0];
};

這個時候 data[0] 只是個數(shù)組名, 是不占用存儲空間的.

這個結(jié)構(gòu)體的大小用sizeof取長度,實(shí)際就是它的成員int的長度,data[0]不占用空間。(數(shù)組名僅僅是一個符號, 它不會占用任何空間, 它在結(jié)構(gòu)體中, 只是代表了一個偏移量, 代表一個不可修改的地址常量!)

sizeof(struct zero_buffer) = sizeof(int)

printf("zero struct length is:%d int length is:%d\n",sizeof(struct zero_buffer),sizeof(int));

zero struct length is:4 int length is:4

對于0長數(shù)組的這個特點(diǎn),很容易構(gòu)造出我們需要的數(shù)據(jù)結(jié)構(gòu),如緩沖區(qū),數(shù)據(jù)包等等。

結(jié)構(gòu)體定義如上所示

假設(shè)我們需要設(shè)置一條tcp待發(fā)送的數(shù)據(jù),長度是15,數(shù)據(jù)內(nèi)容是"Hello My Friend",這樣我們就可以按照如下去定義了。其中  zbuffer->data 為定義數(shù)據(jù)的地址,len表示數(shù)據(jù)的長度。

開辟空間之后使用

我們使用的時候, 只需要開辟一次空間即可。

#define CURR_LENGTH 15struct zero_buffer  *zbuffer = NULL;//  開辟if ((zbuffer = (struct zero_buffer *)malloc(sizeof(struct zero_buffer) + sizeof(char) * CURR_LENGTH)) != NULL){    zbuffer->len = CURR_LENGTH;    memcpy(zbuffer->data, "Hello My Friend", CURR_LENGTH);    printf("%d, %s\n", zbuffer->len, zbuffer->data);}

使用完釋放空間

釋放空間一次釋放即可

//  銷毀
free(zbuffer);
zero_buffer = NULL;

其他方法實(shí)現(xiàn)一些不定長數(shù)據(jù)的傳輸

除了0數(shù)組之外,還有使用定長數(shù)組和指針數(shù)組實(shí)現(xiàn)柔性數(shù)組的功能。

定長數(shù)組

定長數(shù)組顧名思義,就是在結(jié)構(gòu)體里面有個定長的數(shù)組,這個數(shù)組大小是按照我們定義數(shù)據(jù)最大來進(jìn)行設(shè)置的,為了就是防止數(shù)據(jù)儲存的時候溢出。

定義

//  定長緩沖區(qū)
#define MAX_LENGTH      512
struct max_buffer
{
    int     len;
    char    data[MAX_LENGTH];
};

不過使用過程中,比如我要發(fā)送 512 字節(jié)的數(shù)據(jù), 如果用定長包, 假設(shè)定長包的最大長度 MAX_LENGTH 為 1024, 那么就會浪費(fèi) 512 個字節(jié)的空間, 也會造成不必要的流量浪費(fèi)。如果數(shù)組結(jié)構(gòu)對齊放置(這塊知識詳細(xì)可以看我之前的數(shù)據(jù)對齊的文章) sizeof(struct max_buffer) = sizeof(int)+ sizieof(char) * MAX_LENGTH

數(shù)據(jù)包的構(gòu)造

一般來說, 我們會返回一個指向緩沖區(qū)數(shù)據(jù)結(jié)構(gòu) max_buffer 的指針.

#define CURR_LENGTH 512struct max_buffer   *mbuffer = NULL;if ((mbuffer = (struct max_buffer *)malloc(sizeof(struct max_buffer))) != NULL){    mbuffer->len = CURR_LENGTH;    memcpy(mbuffer->data, "Hello World", CURR_LENGTH);    printf("%d, %s\n", mbuffer->len, mbuffer->data);}

作者:良知猶存
鏈接:https://juejin.cn/post/6960470520831672333
來源:掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。

前部分 4 個字節(jié) p->len, 作為包頭(就是多出來的那部分),這個包頭是用來描述緊接著包頭后面的數(shù)據(jù)部分的長度,這里是 1024, 所以前四個字節(jié)賦值為 1024 (既然我們要構(gòu)造不定長數(shù)據(jù)包,那么這個包到底有多長呢,因此,我們就必須通過一個變量來表明這個數(shù)據(jù)包的長度,這就是len的作用),

而緊接其后的內(nèi)存是真正的數(shù)據(jù)部分, 通過 p->data, 最后, 進(jìn)行一個 memcpy() 內(nèi)存拷貝, 把要發(fā)送的數(shù)據(jù)填入到這段內(nèi)存當(dāng)中

釋放空間

當(dāng)使用完畢釋放數(shù)據(jù)的空間的時候, 直接釋放就可以了

free(mbuffer);
mbuffer = NULL;

使用定長數(shù)組, 作為數(shù)據(jù)緩沖區(qū), 為了避免造成緩沖區(qū)溢出, 數(shù)組的大小一般設(shè)為足夠的空間 MAX_LENGTH, 而實(shí)際使用過程中, 達(dá)到 MAX_LENGTH 長度的數(shù)據(jù)很少, 那么多數(shù)情況下, 緩沖區(qū)的大部分空間都是浪費(fèi)掉的.

但是使用過程很簡單, 數(shù)據(jù)空間的開辟和釋放簡單, 無需程序員考慮額外的操作

指針數(shù)組

它和0數(shù)組的區(qū)別在于,零數(shù)組最后一個結(jié)構(gòu)體元素定義一個data[0],而指針數(shù)組就是結(jié)構(gòu)體中需要定義一個指針數(shù)組,這里面的指針數(shù)組不需要特定在結(jié)構(gòu)體的最后一個元素。

struct point_buffer
{
    char    *data;
    int     len;
};

考慮數(shù)組結(jié)構(gòu)對齊(這塊知識詳細(xì)可以看我之前的[數(shù)據(jù)對齊](http://www.fzitv.net/article/211811.htm)的文章), 那么數(shù)據(jù)結(jié)構(gòu)的大小 sizeof(point_buffer)= sizeof(int) + (補(bǔ)齊int與char * 類型的長度值)+ sizeof(char * ),在我的64位編譯環(huán)境中int類型是4byte,char * 類型為8byte,所以補(bǔ)齊的長度為8-4,最終sizeof(point_buffer) 為16byte。

如果結(jié)構(gòu)體加上  _attribute((packed))  數(shù)據(jù)對齊修飾,則 sizeof(point_buffer)= sizeof(int)  sizeof(char * ),最終計(jì)算為12byte。

空間分配使用

#define CURR_LENGTH 1024 struct point_buffer *pbuffer = NULL;if ((pbuffer = (struct point_buffer *)malloc(sizeof(struct point_buffer))) != NULL){   pbuffer->len = CURR_LENGTH;   if ((pbuffer->data = (char *)malloc(sizeof(char) * CURR_LENGTH)) != NULL)   {       memcpy(pbuffer->data, "Hello World", CURR_LENGTH);       printf("%d, %s\n", pbuffer->len, pbuffer->data);   }}

分配內(nèi)存時,需采用兩步

首先, 需為結(jié)構(gòu)體分配一塊內(nèi)存空間;

其次,再為結(jié)構(gòu)體中的成員變量分配內(nèi)存空間.

這樣兩次分配的內(nèi)存是不連續(xù)的, 需要分別對其進(jìn)行管理. 當(dāng)使用長度為的數(shù)組時, 則是采用一次分配的原則, 一次性將所需的內(nèi)存全部分配給它.

釋放

相反, 釋放時也是一樣的.

free(pbuffer->data);
free(pbuffer);
pbuffer = NULL;

使用指針結(jié)果作為緩沖區(qū), 只多使用了一個指針大小的空間, 無需使用固定長度的數(shù)組, 不會造成空間的大量浪費(fèi).

但那是開辟空間時, 需要額外開辟數(shù)據(jù)域的空間, 施放時候也需要顯示釋放數(shù)據(jù)域的空間, 但是實(shí)際使用過程中, 往往在函數(shù)中開辟空間, 然后返回給使用者指向 struct point_buffer 的指針, 這時候我們并不能假定使用者了解我們開辟的細(xì)節(jié), 并按照約定的操作釋放空間, 因此使用起來多有不便, 甚至造成內(nèi)存泄漏

小結(jié):

定長數(shù)組使用方便, 但是卻浪費(fèi)空間, 指針形式只多使用了一個指針的空間, 不會造成大量空間分浪費(fèi), 但是使用起來需要多次分配, 多次釋放。所以最優(yōu)解

0數(shù)組的優(yōu)劣以及注意事項(xiàng)

優(yōu)點(diǎn) :比起在結(jié)構(gòu)體中聲明一個指針變量、再進(jìn)行動態(tài)分配的辦法,這種方法效率要高。因?yàn)樵谠L問數(shù)組內(nèi)容時,不需要間接訪問,避免了兩次訪存。此外,0數(shù)組也不會像定長數(shù)組會造成一定的內(nèi)存的浪費(fèi)。

缺點(diǎn) :在結(jié)構(gòu)體中,數(shù)組為0的數(shù)組必須在最后聲明,使用上有一定限制。

總結(jié)

到此這篇關(guān)于C語言中0數(shù)組\柔性數(shù)組使用的文章就介紹到這了,更多相關(guān)C語言0數(shù)組\柔性數(shù)組內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++多線程實(shí)現(xiàn)電子詞典

    C++多線程實(shí)現(xiàn)電子詞典

    這篇文章主要為大家詳細(xì)介紹了C++多線程實(shí)現(xiàn)電子詞典,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • C++之構(gòu)造函數(shù)默認(rèn)值設(shè)置方式

    C++之構(gòu)造函數(shù)默認(rèn)值設(shè)置方式

    這篇文章主要介紹了C++之構(gòu)造函數(shù)默認(rèn)值設(shè)置方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • C++結(jié)合QT實(shí)現(xiàn)帶有優(yōu)先級的計(jì)算器功能

    C++結(jié)合QT實(shí)現(xiàn)帶有優(yōu)先級的計(jì)算器功能

    這篇文章主要介紹了C++結(jié)合QT實(shí)現(xiàn)帶有優(yōu)先級的計(jì)算器,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • C++ 刪除字符串的2種方法小結(jié)

    C++ 刪除字符串的2種方法小結(jié)

    這篇文章主要介紹了C++ 刪除字符串的2種方法小結(jié),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • C語言深入探究sizeof與整型數(shù)據(jù)存儲及數(shù)據(jù)類型取值范圍

    C語言深入探究sizeof與整型數(shù)據(jù)存儲及數(shù)據(jù)類型取值范圍

    在main函數(shù)中,sizeof是可以正常工作的,但是在自定義函數(shù)中就不可以了。所以本文將為大家詳細(xì)講解一下關(guān)鍵字sizeof、整型數(shù)據(jù)存儲深入、數(shù)據(jù)類型取值范圍深入
    2022-07-07
  • C++ template用法案例詳解

    C++ template用法案例詳解

    這篇文章主要介紹了C++ template用法案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • 關(guān)于C語言strlen與sizeof區(qū)別詳情

    關(guān)于C語言strlen與sizeof區(qū)別詳情

    對于 strlen 和 sizeof,相信不少程序員會混淆其功能。雖然從表面上看它們都可以求字符串的長度,但二者卻存在著許多不同之處及本質(zhì)區(qū)別,今天得這篇文章我們就來學(xué)習(xí)C語言strlen與sizeof區(qū)別的相關(guān)資料,需要的朋友可以參考一下
    2021-10-10
  • c++ 遞歸鎖的使用示例代碼

    c++ 遞歸鎖的使用示例代碼

    這篇文章主要介紹了c++ 遞歸鎖的使用示例代碼,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-08-08
  • C語言之實(shí)現(xiàn)棧的基礎(chǔ)創(chuàng)建

    C語言之實(shí)現(xiàn)棧的基礎(chǔ)創(chuàng)建

    這篇文章主要介紹了C語言之實(shí)現(xiàn)棧的基礎(chǔ)創(chuàng)建,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C++通過SQLiteSDK增刪改查的實(shí)現(xiàn)示例

    C++通過SQLiteSDK增刪改查的實(shí)現(xiàn)示例

    SQLite是一種輕量級的嵌入式數(shù)據(jù)庫,可以利用SQLiteSDK執(zhí)行數(shù)據(jù)庫的增刪改查操作,本文主要介紹了C++通過SQLiteSDK增刪改查,具有一定的參考價值,感興趣的可以了解一下
    2025-03-03

最新評論

峨山| 普宁市| 文昌市| 靖边县| 潞城市| 织金县| 苗栗市| 木兰县| 仁布县| 富阳市| 简阳市| 鸡泽县| 涞水县| 芮城县| 巴楚县| 漾濞| 丰宁| 炎陵县| 海口市| 龙游县| 乐至县| 虹口区| 泽库县| 青龙| 儋州市| 临沭县| 武乡县| 沙河市| 连平县| 静乐县| 临漳县| 宜兰县| 岱山县| 奎屯市| 偃师市| 白银市| 金昌市| 阿巴嘎旗| 贞丰县| 阿坝| 崇阳县|