在平時的開發中,緩衝區數據收發時,若是採用緩衝區定長包,假定大小是 1k,MAX_LENGTH
爲 1024。結構體以下:程序員
// 定長緩衝區
struct max_buffer
{
int len;
char data[MAX_LENGTH];
};
數據結構的大小 >= sizeof(int)
+ sizeof(char) * MAX_LENGTH
爲了防止數據溢出的狀況,data 的長度通常會設置得足夠大,但也正是由於這樣,纔會致使數組的冗餘。編程
假如發送 512 字節的數據, 就會浪費 512 個字節的空間, 平時通訊時,大多數是心跳包,大小遠遠小於 1024,除了浪費空間還消耗不少流量。數組
內存申請:網絡
if ((m_buffer = (struct max_buffer *)malloc(sizeof(struct max_buffer))) != NULL)
{
m_buffer->len = CUR_LENGTH;
memcpy(m_buffer->data, "max_buffer test", CUR_LENGTH);
printf("%d, %s\n", m_buffer->len, m_buffer->data);
}
內存釋放:數據結構
free(m_buffer);
m_buffer = NULL;
爲了不空間上的浪費,咱們能夠將上面的長度爲 MAX_LENGTH
的定長數組換爲指針, 每次使用時動態的開闢 CUR_LENGTH
大小的空間。數據包結構體定義:ide
struct point_buffer
{
int len;
char *data;
};
數據結構大小 >= sizeof(int)
+ sizeof(char *)
但在內存分配時,須要兩步進行:學習
內存申請:flex
if ((p_buffer = (struct point_buffer *)malloc(sizeof(struct point_buffer))) != NULL)
{
p_buffer->len = CUR_LENGTH;
if ((p_buffer->data = (char *)malloc(sizeof(char) * CUR_LENGTH)) != NULL)
{
memcpy(p_buffer->data, "point_buffer test", CUR_LENGTH);
printf("%d, %s\n", p_buffer->len, p_buffer->data);
}
}
內存釋放:this
free(p_buffer->data);
free(p_buffer);
p_buffer = NULL;
雖然這樣可以節約內存,可是兩次分配的內存是不連續的, 須要分別對其進行管理,致使的問題就是須要對結構體和數據分別申請和釋放內存,這樣對於程序員來講無疑是一個災難,由於這樣很容易致使遺忘釋放內存形成內存泄露。指針
有沒有更好的方法呢?那就是今天的主題柔性數組。
柔性數組成員(flexible array member)也叫伸縮性數組成員,這種代碼結構產生於對動態結構體的需求。在平常的編程中,有時候須要在結構體中存放一個長度動態的字符串,鑑於這種代碼結構所產生的重要做用,C99 甚至把它收入了標準中:
As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member.
柔性數組是 C99 標準引入的特性,因此當你的編譯器提示不支持的語法時,請檢查你是否開啓了 C99 選項或更高的版本支持。
C99 標準的定義以下:
struct test {
short len; // 必須至少有一個其它成員
char arr[]; // 柔性數組必須是結構體最後一個成員(也但是其它類型,如:int、double、...)
};
在一個結構體的最後,申明一個長度爲空的數組,就可使得這個結構體是可變長的。對於編譯器來講,此時長度爲 0 的數組並不佔用空間,由於數組名自己不佔空間,它只是一個偏移量,數組名這個符號自己表明了一個不可修改的地址常量,
但對於這個數組的大小,咱們能夠進行動態分配,對於編譯器而言,數組名僅僅是一個符號,它不會佔用任何空間,它在結構體中,只是表明了一個偏移量,表明一個不可修改的地址常量!
對於柔性數組的這個特色,很容易構造出變成結構體,如緩衝區,數據包等等, 其實柔性數組成員在實現跳躍表時有它特別的用法,在Redis的SDS數據結構中和跳躍表的實現上,也使用柔性數組成員。它的主要用途是爲了知足須要變長度的結構體,爲了解決使用數組時內存的冗餘和數組的越界問題
。
//柔性數組
struct soft_buffer
{
int len;
char data[0];
};
數據結構大小 = sizeof(struct soft_buffer)
= sizeof(int)
,這樣的變長數組經常使用於網絡通訊中構造不定長數據包, 不會浪費空間浪費網絡流量。
申請內存:
if ((softbuffer = (struct soft_buffer *)malloc(sizeof(struct soft_buffer) + sizeof(char) * CUR_LENGTH)) != NULL)
{
softbuffer->len = CUR_LENGTH;
memcpy(softbuffer->data, "softbuffer test", CUR_LENGTH);
printf("%d, %s\n", softbuffer->len, softbuffer->data);
}
釋放內存:
free(softbuffer);
softbuffer = NULL;
對比使用指針和柔性數組會發現,使用柔性數組的優勢:
缺點:對結構體格式有要求,必要放在最後,不是惟一成員。
在平常編程中,有時須要在結構體中存放一個長度是動態的字符串(也多是其餘數據類型),可使用柔性數組,柔性數組是一種可以巧妙地解決數組內存的冗餘和數組的越界問題一種方法。很是值得你們學習和借鑑。