在一些 C 語言編寫的代碼中,有時可以看到如下定義的結構:
{
char * name;
int length;
char bytes[0];
} user_def_t;
這個 bytes 是什麼意思?我們知道 0 == sizeof(bytes),那麼 bytes 僅僅是爲了定義結構的尾地址嗎?
不是的。這裏的 bytes 是作爲擴展數組用的。請看如下代碼:
{
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;
}
是不是很酷?同樣,也可以把 name 域的值附在結構後面:
{
p = (user_def_t)malloc(sizeof(user_def_t) + strlen(name) + length + 1);
if (NULL == p)
{
return -1;
}
memcpy(p->name, name, strlen(name) + 1); /* 別忘了'/0' */
p->length = length;
memset(p->bytes, 0, length);
return 0;
}
總結:在某一結構末尾如定義類似 char bytes[0] 的零長數組,表示該結構不定長,可通過數組的方式進行擴展。結構中必包含一個長度信息。結構本身類似於一個信息頭。同時,此結構只能通過堆方式分配內存。
========================
1.零長度數組不是所有的c標準都支持,gnu c支持,ansi c不支持,c++不支持。
2.可以把結構體中定義了零長度數組的地方 視爲結構體的結尾,在它之後最好不要再定義任何字段。因爲零長度數組用來動態的添加數據,一旦添加數據後,零長度數組字段之後定義的字段如果之前賦了值,那麼這個值就會被改掉。(結構體的裏面的數據在內存中按順序存儲的。)
3.如何擴展:
可以直接使用數組方式添加信息:
p->bytes[0] = 'a';
p->bytes[1] = 'b';
也可以通過memcpy,strcpy等函數拷貝方式來添加。
4.等價寫法:
typedef struct user_def{
char* name;
int length;
char bytes[];
}user_def_t;
把char bytes[0] 寫成 char bytes[]也可以,但是這樣寫的話在slickedit裏面調試時,查看結構體的成員時是看不到bytes[]這個成員的,寫成bytes[0]的話就可以。
5.注意的問題:
因爲結構體是可以擴展的,所以在給結構體分配內存時必須預先分配足夠的內存,保證後面擴展時不會超過預先分配的內存的大小。比如
02 int a;
03 int buff[0];
04 };
05
06 int main (int argc, char *argv[])
07 {
08 struct arr *ptr;
09 ptr = (struct arr*)malloc(sizeof(struct arr));
10 int* q=(int*)malloc(sizeof(int));
11 int* k=(int*)malloc(sizeof(int));
12
13 printf("%x %x %x /r/n",ptr,q,k);
14 *q = 1;
15 ptr->buff[0] = 2;
16 ptr->buff[1] = 2;
17 ptr->buff[2] = 2;
18 ptr->buff[3] = 2;
19 printf("%d/r/n",*q);
20 }