博客專欄

        EEPW首頁 > 博客 > C語言柔性數組詳解

        C語言柔性數組詳解

        發布人:電子禪石 時間:2023-02-19 來源:工程師 發布文章
        一、柔性數組是什么?

        C99中,結構體中的最后一個元素允許是未知大小的數組,這就叫作柔性數組,for example:

         struct st_type{
        	int i;
        	int a[0];//柔性數組成員,也可以寫int a[];};

        結構體成員a數組,它的數組大小是沒有確定的,將來如果需要可以大也可以小。
        有些編譯器支持a[0]這種寫法,有些編譯器支持a[ ]這種寫法,具體取決編譯器。


        二、柔性數組的特點

        1.結構體中柔性數組成員前面必須至少有一個其他成員

        示例如下:


         struct st_type

        {

        int i;

        int a[0];//柔性數組成員,也可以寫int a[];

        };


        比如上面這段代碼,如果你要創建一個柔性數組a,前面必須創建一些別的成員

        ————————————————

        2.sizeof返回的這種結構大小不包括柔性數組的內存

         struct st_type
        {
        	int i;//4字節
        	int a[0];//柔性數組成員,也可以寫int a[];
        	//因為是柔性數組,無法確認a占幾個字節
        };
         int main()
         {
        	 printf("%d\n", sizeof(struct st_type));//打印4
        	 return 0;
         }

        這里計算包含柔性數組的結構體大小,因為柔性數組本身是無法確定有幾個字節的,所以計算整體結構體大小時,會省略柔性數組的計算。


        3.包含柔性數組成員的結構用malloc()函數進行內存的動態分配,并且分配的內存應該大于結構的大小,以適應柔性數組的預期大小

        ps:除了malloc函數,realloc、calloc等動態內存開辟的函數也需要類似的操作


        比如說我現在要數組a里面有10個元素,現在進行malloc一下

        ————————————————

        示例如下:

        #include<string.h>
        #include<errno.h>
        struct st_type
        {
        	int i;//4字節
        	int a[0];//柔性數組成員,也可以寫int a[];
        };
        int main()
        {
            //假設我現在需要a里有10個元素
        	struct st_type*ps=(struct st_type*)malloc(sizeof(struct st_type) + 10 * sizeof(int));
        	if (ps == NULL)//由于空間可能不夠開辟導致malloc開辟失敗,開辟失敗會返回空指針
        	{
        		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");
        	//如果想繼續用柔性數組a進行打印
        	//比如現在a里只有10個元素,我用完10個了,我還要繼續來10個,用realloc追加
        	struct st_type*ptr=realloc(ps, sizeof(struct st_type) + 20 * sizeof(int));//ps:realloc第二個參數是調整后的整體大小
        	if (ptr == NULL)
        	{
        		printf("擴容失敗\n");
        		return -1;
        	}
        	else
        	{
        		ps = ptr;
        	}
        	//擴容成功
        	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;
        }

        image.png


        我們這里需要數組a里有10個元素,那我們malloc的時候要對結構體里的整形i先開辟4個字節,然后為整形數組a再開辟40個字節,然后malloc函數返回開辟空間的起始地址,賦給truct st_type * 類型的ps指針。


        malloc(sizeof(struct st_type) + 10 * sizeof(int))這個操作等價于struct st_type類型創建一個變量所占空間,只不過是用malloc來開辟


        你改變數組a大小,追加空間時,realloc(ps, sizeof(struct st_type) + 20 * sizeof(int)),realloc的第一個參數仍然是ps,因為你當時是用malloc一次開辟出的一塊空間,你是不能單獨調整數組a的空間的

        ————————————————

        三、柔性數組的優點

        柔性數組就是對一塊空間實現動態開辟嘛,那我們之前也講過指針來動態內存開辟,我們來看一段代碼來對比一下這兩種方法:

        //用指針也可以做到a指向的空間動態變化
        struct st_type
        {
        	int i;//4字節
        	int *a;//4字節,這里計算結構體大小恰好是8字節
        };
        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個字節的空間,該空間由int*進行管理
        	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指向的空間不夠了,希望調整大小
        	int *ptr = (int*)realloc(ps->a, 20 * sizeof(int));
        	if (ptr == NULL)
        	{
        		printf("擴容失敗");
        		return -1;
        	}
        	else
        	{
        		ps->a = ptr;
        	}
        	//使用...
        	//釋放
        	free(ps->a);
        	ps->a = NULL;
        	free(ps);
        	ps = NULL;
        }

        這里需要注意的是,在釋放空間時,你要先釋放指針a指向的空間,然后釋放結構體指針。


        image.png

        如上圖,我們結構體指針ps開辟一塊空間,空間里存放整形i和整形指針a,a又malloc(后續如果需要還可以realloc追加)一塊空間,如果你先釋放掉ps,a就沒了,你就沒法找到a指向的那塊空間了。

        還是那個生動的例子 就比如a是一個警察頭子,malloc開辟的空間是臥底,只有a知道那個臥底,你現在警察頭子死了,再也沒法證明臥底是臥底了,也就是說a消失后,沒辦法再對開辟的空間進行釋放,這時就會造成內存泄露,指針實現動態內存調整是需要對指針釋放講解一定的順序性的

        ————————————————

        這里對比柔性數組,柔性數組和上述的指針都可以實現一塊空間大小的調整,但是柔性數組有兩個好處:

        第一個好處是:方便內存釋放

        如果我們的代碼是在一個給別人用的函數中,你在里面做了二次內存分配,并把整個結構體返回給用戶。用戶調用free可以釋放結構體,但是用戶并不知道這個結構體內的成員也需要free,所以你不能指望用戶來發現這個事。以上,如果我把結構體的內存及其成員要的內存一次性分配好,并返回給用戶一個結構體指針,用戶做一次free就可以把所有內存都釋放掉,并且不用考慮前面說的釋放的順序。

        ————————————————

        第二個好處是:加快訪問速度
        連續的內存有益于提高訪問速度,也有益于減少內存碎片。
        ps:內存碎片如下圖

        image.png


        總結

        本文介紹了柔性數組的定義、其三個使用特點,及其對比指針實現動態內存的優勢,并對其進行了具體舉例,知識點并不復雜,希望讀者學習完本文后能對柔性數組有更進一步的理解,祝讀者生活愉快!


        *博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。



        關鍵詞: c

        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 丰都县| 洪湖市| 班戈县| 东丰县| 高要市| 报价| 成武县| 遵义市| 涿鹿县| 包头市| 乡宁县| 万荣县| 隆德县| 克什克腾旗| 祁连县| 乡城县| 黔西县| 获嘉县| 绍兴市| 津南区| 郸城县| 屏边| 河池市| 扎兰屯市| 博罗县| 洮南市| 郸城县| 永清县| 南昌市| 德钦县| 宜兰市| 吉林省| 新乡市| 五华县| 皋兰县| 桃园县| 吉隆县| 韩城市| 江孜县| 洛南县| 长寿区|