柔性數組的概念
柔性數組(flexible array member)也叫伸縮性數組成員,這種結構產生與對動態結構體的去求。在平常編程中,有時須要在結構體中存放一個長度是動態的字符串(也多是其餘數據類型),通常的作法,實在結構體中定義一個指針成員,這個指針成員指向該字符串所在的動態內存空間。編程
在一般狀況下,若是想要高效的利用內存,那麼在結構體內部定義靜態的數組是很是浪費的行爲。其實柔性數組的想法和動態數組的想法是同樣的。數組
柔性數組用來在結構體中存放一個長度動態的字符串。網絡
普通的方式
其實不用柔性數組咱們同樣能夠作到:在結構體中定義一個方法,在方法中動態地將指針指向動態數組數據結構
#include <string.h> #include <stdlib.h> typedef struct Test { int a; char *p; } Test; int main() { char *str = (char *)malloc(sizeof(char) * 10); strcpy(str, "hello"); Test *t = (Test *)malloc(sizeof(Test)); t->p = str; printf("%s\n", (t->p)); printf("Address:\n"); printf("t\t %p\n", t); printf("t.a\t %p\n", &(t->a)); printf("t.p\t %p\n", (t->p)); free(t); free(t->p); //還須要顯式的釋放p所指的內存 return 0; }
運行結果:flex
上面的代碼的確是能夠完成咱們想要的結果。咱們看了一下指針p和數組的起始地址。咱們能夠看到動態數組的內存塊和字符串的內存是兩塊不同的內存。spa
可是,咱們在釋放空間時,須要顯式地釋放指針p引用的內存空間,否則會出現內存泄露的狀況。操作系統
使用柔性數組的方式
從C99開始便支持了不完整類型實現柔性數組成員。爲何使用不完整類型呢?指針
int a[] = {10};
看到這個聲明語句,咱們發現a[]其實就是個數組記號,不完整類型,因爲賦值語句,因此在編譯時便肯定了數組的大小,是一個完整的數組類型。
在結構體中便利用不完整類型在運行對動態的數組進行指明。code
C99標準的定義以下blog
struct Test{ int a; char p[]; // 不僅是char類型,其餘類型一樣也是能夠 }
因爲聲明內存連續性的關係,柔性數組成員必須定義在結構體的最後一個,而且不能是惟一的成員。
咱們再來看一看整個結構體(包含數組內存的分佈狀況)
#include <string.h> #include <stdlib.h> typedef struct Test { int a; char p[]; } Test; int main() { Test *t=(Test*)malloc(sizeof(Test)+sizeof(char)*(10+1)); strcpy(t->p,"hello"); printf("%s\n", (t->p)); printf("Address:\n"); printf("t\t %p\n", t); printf("t.a\t %p\n", &(t->a)); printf("t.p\t %p\n", (t->p)); free(t); //只須要釋放一次內存 return 0; }
再運行結果:
由運行結果就能夠看出,整個結構體是連續的,而且釋放結構體的方式也很是簡單直接對結構體指針進行釋放。
【注】因爲這個是C99的標準,在ISO C和C++的規格說明書中是不容許的。在vs下使用0長度的數組可能會獲得一個警告。
然而gcc, clang++預先支持了C99的玩法,因此在Linux下編譯無警告
進一步認識柔性數組
現有一個程序
#include<stdio.h> typedef struct _SoftArray{ int len; int array[]; }SoftArray; int main() { int len = 10; printf("The struct's size is %d\n",sizeof(SoftArray)); }
運行結果:
咱們能夠看出,_SoftArray結構體的大小是4,顯然,在32位操做系統下一個int型變量大小恰好爲4,也就說結構體中的數組沒有佔用內存。爲何會沒有佔用內存,咱們平時用數組時不時都要明確指明數組大小的嗎?但這裏卻能夠編譯經過呢?這就是咱們常說的動態數組,也就是柔性數組。
先不要亂,讓咱們再看一段代碼
#include <stdio.h> #include <malloc.h> typedef struct _SoftArray { int len; int array[]; } SoftArray; int main() { int len = 10; SoftArray *p = (SoftArray *)malloc(sizeof(SoftArray) + sizeof(int) * len); printf("After the malloc function the struct's size is %d\n",sizeof(SoftArray)); return 0; }
運行結果:
是否是有點奇怪,爲何申請了內存後結構體大小仍是4呢?
緣由是:動態申請的內存只是申請給數組拓展所用,從上個程序咱們能夠看出結構體的大小在建立時已經肯定了,array明確來講不算是結構體成員,只是掛羊頭賣狗肉而已。
下面咱們來看看關於柔性數組的資料:
一、什麼是柔性數組?
柔性數組既數組大小待定的數組, C語言中結構體的最後一個元素能夠是大小未知的數組,也就是所謂的0長度,因此咱們能夠用結構體來建立柔性數組。
二、柔性數組有什麼用途 ?
它的主要用途是爲了知足須要變長度的結構體,爲了解決使用數組時內存的冗餘和數組的越界問題。
三、用法:在一個結構體的最後 ,申明一個長度爲空的數組,就可使得這個結構體是可變長的。對於編譯器來講,此時長度爲0的數組並不佔用空間,由於數組名
自己不佔空間,它只是一個偏移量, 數組名這個符號自己代 表了一個不可修改的地址常量 (注意:數組名永遠都不會是指針! ),但對於這個數組的大小,咱們能夠進行動態分配,對於編譯器而言,數組名僅僅是一個符號,它不會佔用任何空間,它在結構體中,只是表明了一個偏移量,表明一個不可修改的地址常量!
對於柔性數組的這個特色,很容易構造出變成結構體,如緩衝區,數據包等等:
typedef struct _SoftArray { Int len; int array[]; }SoftArray;
柔性數組用途
這樣的變長數組經常使用於網絡通訊中構造不定長數據包,不會浪費空間浪費網絡流量,好比我要發送1024字節的數據,若是用定長包,假設定長包的長度爲2048,就會浪費1024個字節的空間,也會形成沒必要要的流量浪費。
其實柔性數組成員在實現跳躍表時有它特別的用法,在Redis的SDS數據結構中和跳躍表的實現上,也使用柔性數組成員。