零長度數組(柔性數組)的用法

來源:互聯網
上載者:User

   在前面的文章中的dnw原始碼,使用了這樣一個結構體:

struct download_buffer {      uint32_t    load_addr;  /* load address */      uint32_t    size; /* data size */ //size=地址(4位)+大小(4位)+資料+校正(2位)     uint8_t     data[0];//0長度數組,指向資料      /* uint16_t checksum; */ //數組後緊接著的兩位是校正位  };

其中data[0]是一個0長度數組,用於柔性拓展結構體。

分配記憶體空間:

buffer = alloc_buffer(file_stat.st_size);

也就是:

buffer = malloc(data_size + sizeof(struct download_buffer) + 2);

          data_size是結構體成員buffer->data的長度,使用sizeof(struct download_buffer)取得結構體長度時,不計算
data成員的長度,這樣就實現了一個可以動態調節大小的結構體,根據所需要的空間分配給data成員空間。


再來看一個網上的例子:
定義一個結構體

typedef struct user_def{    char * name;    int length;    char bytes[0];} user_def_t;

在這裡我們使用sizeof(bytes)會發現結果等於0,這個bytes就是一個零長度的柔性數組,使用方法如下:

int alloc_user_def_t(user_def_t * p, int length){    p = (user_def_t)malloc(sizeof(user_def_t) + length);    if (NULL == p)    {        return -1;    }    p->name = NULL;    p->length = length;    memset(p->bytes, 0, length);    return 0;}

這樣我們就將length長度的0字元寫進bytes數組,相當與一個附件附在結構體後面,可以通過這個數組訪問。

再看一個網上例子:


#include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>struct helloworld_t{  int num;  char helloworld[0];//主要是用來得到一個數組的地址,再由數組的個數來訪問};int main(){struct helloworld_t *p;unsigned int size = sizeof(struct helloworld_t) + strlen("Hello World!\n") + 1;  p = (struct helloworld_t *) malloc(size);assert(p!=NULL);memcpy(p, "\x01\x00\x00\x00Hello World!\n", size);//\x01\x00\x00\x00四位元組,就是給num賦值//在記憶體中高8位和低8位反一下...//printf("%d\n",p->num);while (p->num--){printf(p->helloworld);}//printf("%d \n", sizeof(helloworld_t));free((void *)p);return 0;}

列印結果是:Hello World!
        
        C99中,結構中的最後一個元素允許是未知大小的數組,這就叫做柔性數群組成員,但結
構中的柔性數群組成員前面必須至少一個其他成員。 柔性數群組成員允許結構中包含一個大小可
變的數組。sizeof返回的這種結構大小不包括柔性數組的記憶體。包含柔性數群組成員的結構用
malloc ()函數進行記憶體的動態分配,並且分配的記憶體應該大於結構的大小,以適應柔性數組
的預期大小。
       在定義這個結構體的時候,結構體的大小就已經確定不包含柔性數組的記憶體大小。
柔性數組只是編外人員,不佔結構體的編製。只是說在使用柔性數組時需要把它當作結
構體的一個成員,僅此而已。再說白點,柔性數組其實與結構體沒什麼關係,只是“掛羊頭
賣狗肉”而已,算不得結構體的正式成員。
       需要說明的是:C89不支援這種東西,C99把它作為一種特例加入了標準。但是,C99所
支援的是 incomplete type,而不是 zero array,形同 int item[0];這種形式是非法的,C99支援
的形式是形同 int item[];只不過有些編譯器把 int item[0];作為非標準擴充來支援,而且在C99
發布之前已經有了這種非標準擴充了,C99發布之後,有些編譯器把兩者合而為一了。當然,上面
既然用 malloc函數分配了記憶體,肯定就需要用free函數來釋放記憶體:
free(p);



舉個例子:

typedef struct st_type{int i;int a[0];}type_a;

GNU的編譯器可以通過編譯,有些編譯器會報錯無法編譯(例如VS系列)可以改成:

typedef struct st_type{int i;int a[];}type_a;

       這樣我們就可以定義一個可變長的結構體,用 sizeof(type_a)得到的只有 4,就是
sizeof(i)=sizeof(int)。那個 0 個元素的數組沒有佔用空間,而後我們可以進行變長操作了。通
過如下運算式給結構體分配記憶體:
type_a *p = (type_a*)malloc(sizeof(type_a)+100*sizeof(int));
這樣我們為結構體指標 p 分配了一塊記憶體。用 p->a[n]就能簡單地訪問可變長元素(p->a[0]~p->[99])。
但是這時候我們再用 sizeof(*p)測試結構體的大小,發現仍然為 4。

    那麼,為什麼不在結構體裡使用指標成員來指向該字串所在的動態記憶體空間呢?
例如:

struct  ptest{     int  a;     double b;     char  *c;};

      指標成員c指向字串。這種方法會造成字串與結構體分離,malloc和free對記憶體管理產生片段,也不利於操作。
如果我們把字串和結構體串連在一起,字串位置緊接著結構體,這樣修改代碼:
char  Str[] = "hello world";
struct ptest *Test = (struct ptest*)malloc(sizeof(struct ptest)+strlen(Str)+1);//+1是因為strlen不計算結束符
strcpy(Test+1,Str)

   (char*)(Test+1)就是字串“hello  world”的地址了。c就成了多餘的東西,可以去掉。然而,直接使用(char*)(Test+1)很不方便。於是,這種既能直接引用字串,還不佔用結構體空間,能靈活分配資料域大小的要求,柔性數組就能夠滿足。

   在這個結構體中,c是柔性數群組成員,如果把Test指向的動態記憶體分配看作一個整體,c就是一個長度可以變化的柔性數組,c在結構體中長度為0,不佔用Test的空間,Test->c就是“hello  world”的首地址。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.