柔性數組
- 1. 什么是柔性數組
- 2. 柔性數組的特點
- 3. 柔性數組的使用
- 4. 柔性數組的優勢
1. 什么是柔性數組
也許你從來沒有聽說過柔性數組這個概念,但是它確實是存在的。
C99中,結構體中的最后?個元素允許是未知大小的數組,這就叫做柔性數組成員。
例如:
struct S
{int i;int arr[];//柔性數組成員
};
2. 柔性數組的特點
- 結構體中的柔性數組成員前面必須至少有一個其他成員。
- sizeof返回的這種結構體大小不包括柔性數組的內存。
- 包含柔性數組成員的結構體用malloc函數進行內存的動態分配,并且分配的內存應該大于結構的大小,以適應柔性數組的預期大小。
例如:
#include <stdio.h>struct S
{int i;int arr[];//柔性數組成員
};int main()
{int sz = sizeof(struct S);printf("%d\n", sz);return 0;
}
輸出結果:
3. 柔性數組的使用
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>struct S
{int i;int arr[];//柔性數組成員
};int main()
{//struct S s;//只申請了4字節空間,柔性數組沒有申請空間struct S* ps=(struct S*)malloc(sizeof(struct S) + 40);//40字節是給柔性數組開辟的if (ps == NULL){printf("%s\n", strerror(errno));return 1;}//使用ps->i = 100;int i = 0;for (i = 0; i < 10; i++){ps->arr[i] = i;}for (i = 0; i < 10; i++){printf("%d ", ps->arr[i]);}//調整空間,柔性數組柔性的體現struct S* ptr = (struct S*)realloc(ps, sizeof(struct S) + 80);if (ptr != NULL){ps = ptr;ptr = NULL;}//……//釋放free(ps);ps = NULL;return 0;
}
當前代碼的內存布局如圖所示:
思考:有人會想到那為什么那為什么不直接讓結構體成員為int* ,然后動態開辟一塊空間給int* 指向呢?
代碼實現如下:
#include <stdio.h>
#include <stdlib.h>struct S
{int n;int* arr;
};int main()
{struct S*ps = (struct S*)malloc(sizeof(struct S));if (ps == NULL){return 1;}ps->n = 100;ps->arr = (int*)malloc(40);if (ps->arr == NULL){return 1;}//使用int i = 0;for (i = 0; i < 10; i++){ps->arr[i] = i;}for (i = 0; i < 10; i++){printf("%d ", ps->arr[i]);}//擴容int* ptr = (int*)realloc(ps->arr, 80);if (ptr != NULL){ps->arr = ptr;}//釋放free(ps->arr);free(ps);ps = NULL;return 0;
}
內存布局如圖所示:
在結構體中這兩種方式都能實現“柔性”的效果(空間可調整),哪一種方式更好呢?我們進行對比:
在方式1中使用柔性數組時,n和arr的空間只要使用一次malloc就可以全部開辟,最后一次free就可以釋放。
而方式2中struct需要一次malloc開辟,arr又需要malloc開辟,最后也要2次free才可以釋放
我們知道使用malloc的次數越多,如果忘記了free,則就越容易造成內存泄漏,其次就是如果在內存中頻繁的進行malloc,則形成的內存碎片也越多,這樣會使內存的利用率更低。
4. 柔性數組的優勢
-
方便內存釋放。
如果我們的代碼是在?個給別人用的函數中,你在里面做了?次內存分配,并把整個結構體返回給用戶。用戶調用free可以釋放結構體,但是用戶并不知道這個結構體內的成員也需要free,所以你不能指望用戶來發現這個事。所以,如果我們把結構體的內存以及其成員要的內存?次性分配好了,并返回給用戶?個結構體指針,用戶做?次free就可以把所有的內存也給釋放掉。 -
這樣有利于訪問速度。
連續的內存有益于提高訪問速度,也有益于減少內存碎片。