1. 程式人生 > >可變長度的陣列(定義陣列時長度為0)

可變長度的陣列(定義陣列時長度為0)

       在標準C和C++中,長度為0的陣列是被禁止使用的。不過在GNU C中,存在一個非常奇怪的用法,那就是長度為0的陣列,比如Array[0];很多人可能覺得不可思議,長度為0的陣列是沒有什麼意義的,不過在這兒,它表示的完全是另外的一層意思,這個特性是不可移植的,所以,如果你致力於編寫可移植,或者是稍稍需要跨平臺的程式碼,這些伎倆最好還是收起來的好

用途 :長度為0的陣列的主要用途是為了滿足需要變長度 的結構體。

用法 :在一個結構體的最後 ,申明一個長度為0的陣列,就可以使得這個結構體是可變長的。對於 編譯器來說,此時長度為0的陣列並不佔用空間,因為陣列名本身不佔空間,它只是一個偏移量, 陣列名這個符號本身代 表了一個不可修改的地址常量 (注意:陣列名永遠都不會是指標! ),但對於這個陣列的大小,我們可以進行動態分配。例如:

typedef struct
{       

int len;       

char data[0];

}test_t;

int my_length = 10;

test_t *p_test = (test_t *)malloc(sizeof(test_t) + my_length);

p_test->len = my_length;

......

free(p_test); 

之後對於結構體中的陣列可以像一般的陣列一樣進行訪問。

注意 :如果結構體是通過calloc、malloc或 者new等動態分配方式生成,在不需要時要釋放相應的空間。

優點 :比起在結構體中宣告一個指標變數、再進行動態分 配的辦法,這種方法效率要高。因為在訪問陣列內容時,不需要間接訪問,避免了兩次訪存。

缺點 :在結構體中,陣列為0的陣列必須在最後宣告,使 用上有一定限制。

案例

近日在看專案中的框架程式碼時,發現了了一個奇特的語法:長度為0的陣列例如 

 uint8_t buf[0]; 

我從未見過這樣的寫法,所以在網上查了查資料,瞭解並記錄下來.

在標準的C/C++中,長度為0的陣列是不被允許的,它算是一個C/C++擴充套件,如果你的編譯器支援這個擴充套件,你就可以使用它.

VS系列編譯器不完全支援這個擴充套件,如果你這樣定義,多半會在編譯時出現這樣的警告:warning C4200: 使用了非標準擴充套件 : 結構/聯合中的零大小陣列,當 UDT 包含大小為零的陣列時,無法生成複製建構函式或副本賦值運算子

GUN編譯器完全支援這個擴充套件,你可以合法的宣告長度為0的陣列,但這種宣告的最典型的用法就是位於陣列中的最後一項,為了方便記憶體緩衝區的管理,例如:

struct Line{
    uint32_t length;
    char contents[0];
};

 在結構體中,長度為0的陣列不會佔用儲存空間 ,在上述例子中 sizeof(Line)=4

在申請記憶體空間時,緩衝區的空間可以和結構體的空間一起申請,一次操作就可以完成.例如

uint32_t length = 10;
struct Line *pLine = (struct Line *)malloc(sizeof (struct Line) + length);
pLine->length = length;

上述程式碼就動態地為結構體申請了長度(length)為10byte的緩衝區,而且由於是同一次malloc操作,緩衝區與結構體的記憶體地址是連續的,而且可以按照陣列下標訪問緩衝區元素,例如

for(uint32_t i = 0;i < pLine->length;++i)
{
    pLine->contents[i] = i;
}

由於緩衝區與結構體的記憶體地址是連續的,在釋放記憶體的時候,只需要一次free操作.

綜上所述,比起在結構體中定義一個指標指向另一片緩衝區地址的做法,使用長度為0的陣列有以下好處:

1->指標本身需要佔用記憶體,而長度為0的陣列不需要

2->長度為0的陣列定義出的緩衝區可以和結構體處在同一片連續地址中,只要一次malloc操作和free操作.如果用指標,需要分別申請和釋放結構體記憶體和指標指向的記憶體塊,至少需要兩次以上的記憶體操作.

例項:

#include <stdio.h>
#include <stdint.h>
#include <malloc.h>
struct Line{
    uint32_t length;
    uint8_t contents[0];//在結構體中,陣列為0的陣列必須在最後宣告,使 用上有一定限制
};
int32_t main()
{
    uint32_t length = 10, i;
    printf("sizeof(Line)=%d\n", sizeof(struct Line));//列印結構體長度,發現大小為4,說明陣列長度為0不佔用空間
     //申請記憶體
    struct Line *pLine = (struct Line *)malloc(sizeof (struct Line) + length);
    pLine->length = length;
    //向動態陣列中存放數
    for (i = 0; i < pLine->length; ++i)
    {
        pLine->contents[i] = i;
    }
    //列印動態數組裡面的內容
    for (i = 0; i < pLine->length; ++i)
    {
        printf("i=%d,contents[i]=%d\n", i, pLine->contents[i]);
    }
    //釋放記憶體
    free(pLine);
    return 0;
}

結果:

 

 轉載:https://www.cnblogs.com/hwy89289709/p/6840196.html

           https://www.cnblogs.com/tangxin-blog/p/5560699.html