C語言柔性數(shù)組詳解
結(jié)構(gòu)體成員a數(shù)組,它的數(shù)組大小是沒有確定的,將來如果需要可以大也可以小。
有些編譯器支持a[0]這種寫法,有些編譯器支持a[ ]這種寫法,具體取決編譯器。
二、柔性數(shù)組的特點(diǎn)
1.結(jié)構(gòu)體中柔性數(shù)組成員前面必須至少有一個(gè)其他成員
示例如下:
struct st_type
{
int i;
int a[0];//柔性數(shù)組成員,也可以寫int a[];
};
比如上面這段代碼,如果你要?jiǎng)?chuàng)建一個(gè)柔性數(shù)組a,前面必須創(chuàng)建一些別的成員
————————————————
2.sizeof返回的這種結(jié)構(gòu)大小不包括柔性數(shù)組的內(nèi)存
struct st_type { int i;//4字節(jié) int a[0];//柔性數(shù)組成員,也可以寫int a[]; //因?yàn)槭侨嵝詳?shù)組,無法確認(rèn)a占幾個(gè)字節(jié) }; int main() { printf("%d\n", sizeof(struct st_type));//打印4 return 0; }
這里計(jì)算包含柔性數(shù)組的結(jié)構(gòu)體大小,因?yàn)槿嵝詳?shù)組本身是無法確定有幾個(gè)字節(jié)的,所以計(jì)算整體結(jié)構(gòu)體大小時(shí),會(huì)省略柔性數(shù)組的計(jì)算。
3.包含柔性數(shù)組成員的結(jié)構(gòu)用malloc()函數(shù)進(jìn)行內(nèi)存的動(dòng)態(tài)分配,并且分配的內(nèi)存應(yīng)該大于結(jié)構(gòu)的大小,以適應(yīng)柔性數(shù)組的預(yù)期大小
ps:除了malloc函數(shù),realloc、calloc等動(dòng)態(tài)內(nèi)存開辟的函數(shù)也需要類似的操作
比如說我現(xiàn)在要數(shù)組a里面有10個(gè)元素,現(xiàn)在進(jìn)行malloc一下
————————————————
示例如下:
#include<string.h> #include<errno.h> struct st_type { int i;//4字節(jié) int a[0];//柔性數(shù)組成員,也可以寫int a[]; }; int main() { //假設(shè)我現(xiàn)在需要a里有10個(gè)元素 struct st_type*ps=(struct st_type*)malloc(sizeof(struct st_type) + 10 * sizeof(int)); if (ps == NULL)//由于空間可能不夠開辟導(dǎo)致malloc開辟失敗,開辟失敗會(huì)返回空指針 { printf("%s\n", strerror(errno)); return -1;//程序出問題后,跳出程序 } //開辟成功 int j = 0; for (j = 0;j < 10;j++) { ps->a[j] = j; } for (j = 0;j < 10;j++) { printf("%d ", ps->a[j]);//打印0-9 } printf("\n"); //如果想繼續(xù)用柔性數(shù)組a進(jìn)行打印 //比如現(xiàn)在a里只有10個(gè)元素,我用完10個(gè)了,我還要繼續(xù)來10個(gè),用realloc追加 struct st_type*ptr=realloc(ps, sizeof(struct st_type) + 20 * sizeof(int));//ps:realloc第二個(gè)參數(shù)是調(diào)整后的整體大小 if (ptr == NULL) { printf("擴(kuò)容失敗\n"); return -1; } else { ps = ptr; } //擴(kuò)容成功 int k = 0; for (k = 10;k < 20;k++) { ps->a[k] = k; } for (j = 0;j < 20;j++) { printf("%d ", ps->a[j]);//打印0-19 } //釋放空間 free(ps); ps = NULL; return 0; }
我們這里需要數(shù)組a里有10個(gè)元素,那我們malloc的時(shí)候要對(duì)結(jié)構(gòu)體里的整形i先開辟4個(gè)字節(jié),然后為整形數(shù)組a再開辟40個(gè)字節(jié),然后malloc函數(shù)返回開辟空間的起始地址,賦給truct st_type * 類型的ps指針。
malloc(sizeof(struct st_type) + 10 * sizeof(int))這個(gè)操作等價(jià)于struct st_type類型創(chuàng)建一個(gè)變量所占空間,只不過是用malloc來開辟
你改變數(shù)組a大小,追加空間時(shí),realloc(ps, sizeof(struct st_type) + 20 * sizeof(int)),realloc的第一個(gè)參數(shù)仍然是ps,因?yàn)槟惝?dāng)時(shí)是用malloc一次開辟出的一塊空間,你是不能單獨(dú)調(diào)整數(shù)組a的空間的
————————————————
三、柔性數(shù)組的優(yōu)點(diǎn)//用指針也可以做到a指向的空間動(dòng)態(tài)變化 struct st_type { int i;//4字節(jié) int *a;//4字節(jié),這里計(jì)算結(jié)構(gòu)體大小恰好是8字節(jié) }; int main() { struct st_type*ps = (struct st_type*)malloc(sizeof(struct st_type)); ps->i = 100; ps->a = (int*)malloc(10 * sizeof(int));//a指向40個(gè)字節(jié)的空間,該空間由int*進(jìn)行管理 int j = 0; for (j = 0;j < 10;j++) { ps->a[j] = j;//a[j]=*(a+j) } for (j = 0;j < 10;j++) { printf("%d", ps->a[j]); } //a指向的空間不夠了,希望調(diào)整大小 int *ptr = (int*)realloc(ps->a, 20 * sizeof(int)); if (ptr == NULL) { printf("擴(kuò)容失敗"); return -1; } else { ps->a = ptr; } //使用... //釋放 free(ps->a); ps->a = NULL; free(ps); ps = NULL; }
這里需要注意的是,在釋放空間時(shí),你要先釋放指針a指向的空間,然后釋放結(jié)構(gòu)體指針。
如上圖,我們結(jié)構(gòu)體指針ps開辟一塊空間,空間里存放整形i和整形指針a,a又malloc(后續(xù)如果需要還可以realloc追加)一塊空間,如果你先釋放掉ps,a就沒了,你就沒法找到a指向的那塊空間了。
還是那個(gè)生動(dòng)的例子 就比如a是一個(gè)警察頭子,malloc開辟的空間是臥底,只有a知道那個(gè)臥底,你現(xiàn)在警察頭子死了,再也沒法證明臥底是臥底了,也就是說a消失后,沒辦法再對(duì)開辟的空間進(jìn)行釋放,這時(shí)就會(huì)造成內(nèi)存泄露,指針實(shí)現(xiàn)動(dòng)態(tài)內(nèi)存調(diào)整是需要對(duì)指針釋放講解一定的順序性的
————————————————
這里對(duì)比柔性數(shù)組,柔性數(shù)組和上述的指針都可以實(shí)現(xiàn)一塊空間大小的調(diào)整,但是柔性數(shù)組有兩個(gè)好處:
第一個(gè)好處是:方便內(nèi)存釋放
如果我們的代碼是在一個(gè)給別人用的函數(shù)中,你在里面做了二次內(nèi)存分配,并把整個(gè)結(jié)構(gòu)體返回給用戶。用戶調(diào)用free可以釋放結(jié)構(gòu)體,但是用戶并不知道這個(gè)結(jié)構(gòu)體內(nèi)的成員也需要free,所以你不能指望用戶來發(fā)現(xiàn)這個(gè)事。以上,如果我把結(jié)構(gòu)體的內(nèi)存及其成員要的內(nèi)存一次性分配好,并返回給用戶一個(gè)結(jié)構(gòu)體指針,用戶做一次free就可以把所有內(nèi)存都釋放掉,并且不用考慮前面說的釋放的順序。
————————————————
第二個(gè)好處是:加快訪問速度
連續(xù)的內(nèi)存有益于提高訪問速度,也有益于減少內(nèi)存碎片。
ps:內(nèi)存碎片如下圖
*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。