[英]realloc of array inside a struct
我正在嘗試編寫一個使用realloc()
來擴展結構實例中指向的數組的函數,但是我似乎無法使其正常工作。
我的代碼的相關部分是:
struct data_t {
int data_size;
uint16_t *data;
};
void extend_data(data_t container, uint16_t value) {
// adds an additional uint16_t to the array of DATA, updates its internal
// variables, and initialises the new uint to VALUE.
int len_data = sizeof(*(container->data)) / sizeof(uint16_t);
printf("LENGTH OF DATA: %d\n", len_data);
container->data = realloc(container->data, sizeof(*(container->data))+sizeof(uint16_t));
container->data_size++;
container->data[container->data_size-1] = value;
len_data = sizeof(*(container->data)) / sizeof(uint16_t);
printf("LENGTH OF DATA: %d\n", len_data);
printf("data_size: %d\n", container->data_size);
return;
}
有人可以看到這是什么問題嗎?
編輯
正如R. Sahu所指出的, container
不是此函數的指針-當您說代碼“不起作用”時,我以為您是在說您不是在擴展數組,但是您在此處編寫的內容不會甚至編譯 。
您確定已正確復制此代碼? 如果是這樣,“不起作用”是否意味着您遇到編譯時錯誤,運行時錯誤或只是意外輸出?
如果您已經復制了編寫的代碼,那么您要做的第一件事就是將函數原型更改為
void extend_data(data_t *container, uint16_t value) {
並確保您傳遞的是指向 data_t
類型的指針 ,否則更新不會反映在調用代碼中。
原版的
在行中
container->data = realloc(container->data, sizeof(*(container->data))+sizeof(uint16_t));
sizeof(*(container->data))
為sizeof (uint16_t)
。 container->data
是uint16_t
的指針 ,而不是uint16_t
的數組; sizeof
將為您提供指針對象的大小,而不是分配的元素數。 您要執行的操作類似於以下內容:
/**
* Don't assign the result of a realloc call back to the original
* pointer - if the call fails, realloc will return NULL and you'll
* lose the reference to your original buffer. Assign the result to
* a temporary, then after making sure the temporary is not NULL,
* assign that back to your original pointer.
*/
uint16_t *tmp = realloc(container-data, sizeof *container->data * (container->data_size + 1) );
if ( tmp )
{
/**
* Only add to container->data and update the value of container->data_size
* if the realloc call succeeded.
*/
container->data = tmp;
container->data[container->data_size++] = value;
}
您沒有正確計算新尺寸。 考慮一下:
typedef struct {
size_t size;
int *data;
} int_array;
#define INT_ARRAY_INIT { 0, NULL}
void int_array_resize(int_array *const array,
const size_t newsize)
{
if (!array) {
fprintf(stderr, "int_array_resize(): NULL int_array.\n");
exit(EXIT_FAILURE);
}
if (!newsize) {
free(array->data);
array->data = 0;
array->size = 0;
} else
if (newsize != array->size) {
void *temp;
temp = realloc(array->data, newsize * sizeof array->data[0]);
if (!temp) {
fprintf(stderr, "int_array_resize(): Out of memory.\n");
exit(EXIT_FAILURE);
}
array->data = temp;
array->size = newsize;
}
}
/* int_array my_array = INT_ARRAY_INIT;
is equivalent to
int_array my_array;
int_array_init(&my_array);
*/
void int_array_init(int_array *const array)
{
if (array) {
array->size = 0;
array->data = NULL;
}
}
void int_array_free(int_array *const array)
{
if (array) {
free(array->data);
array->size = 0;
array->data = NULL;
}
}
關鍵是newsize * sizeof array->data[0]
。 這是array->data[0]
類型的newsize
元素所需的字符數。 malloc()
和realloc()
均以char為單位。
如果使用int_array my_array = INT_ARRAY_INIT;
初始化該類型的新結構int_array my_array = INT_ARRAY_INIT;
您只需調用int_array_resize()
即可調整其大小。 ( realloc(NULL, size)
等效於malloc(size)
; free(NULL)
是安全的,什么也不做。)
int_array_init()
和int_array_free()
只是用於初始化和釋放此類數組的輔助函數。
就個人而言,每當我動態調整數組大小時,我都會保留分配的大小( size
)和使用的大小( used
):
typedef struct {
size_t size; /* Number of elements allocated for */
size_t used; /* Number of elements used */
int *data;
} int_array;
#define INT_ARRAY_INIT { 0, 0, NULL }
因此,確保至少need
添加元素的功能特別有用。 為了避免不必要的重新分配,該函數實現了一個策略,該策略計算要分配的新大小,以“浪費”(已分配但未使用)的內存量與可能會很慢的realloc()
調用次數之間取得平衡:
void int_array_need(int_array *const array,
const size_t need)
{
size_t size;
void *data;
if (!array) {
fprintf(stderr, "int_array_need(): NULL int_array.\n");
exit(EXIT_FAILURE);
}
/* Large enough already? */
if (array->size >= array->used + need)
return;
/* Start with the minimum size. */
size = array->used + need;
/* Apply growth/reallocation policy. This is mine. */
if (size < 256)
size = (size | 15) + 1;
else
if (size < 2097152)
size = (3 * size) / 2;
else
size = (size | 1048575) + 1048577 - 8;
/* TODO: Verify (size * sizeof array->data[0]) does not overflow. */
data = realloc(array->data, size * sizeof array->data[0]);
if (!data) {
/* Fallback: Try minimum allocation. */
size = array->used + need;
data = realloc(array->data, size * sizeof array->data[0]);
}
if (!data) {
fprintf(stderr, "int_array_need(): Out of memory.\n");
exit(EXIT_FAILURE);
}
array->data = data;
array->size = size;
}
對於應該使用哪種重新分配策略,有很多意見,但這實際上取決於用例。
剩下的三件事是: realloc()
調用的數量,因為它們可能是“緩慢的”。 如果增長了不同的數組並需要許多realloc()
調用,則內存碎片; 以及已分配但未使用的內存量。
我上面的政策試圖一次做很多事情。 對於小分配(最多256個元素),它會將大小四舍五入到下一個16的倍數。這是我試圖在用於小數組的內存和不多的realloc()
調用之間取得良好平衡的嘗試。
對於較大的分配,將添加50%的大小。 這減少了realloc()
調用的次數,同時將已分配但未使用/不需要的內存保持在50%以下。
對於非常大的分配,當您有2 21個或更多元素時,大小會四舍五入到2 20的下一個倍數,再減去一些元素。 這將已分配但未使用的元素的數量限制為大約2 21或200萬個元素。
(為什么要減少一些元素?因為它不會損害任何系統,並且在某些系統上可能會有所幫助。某些系統,包括某些操作系統和配置上的x86-64(64位Intel / AMD),支持大型(“巨大”)頁面在某些方面可能比普通頁面更有效。如果使用它們來滿足分配,我想避免這樣一種情況:分配一個超大頁面只是為了滿足C庫的幾個字節內部需要分配元數據。)
void extend_data(data_t container, ...
在函數container
中,指針不是指針,而是值本身傳遞的結構體,因此您不能使用->
運算符。
當您對傳遞的結構的本地副本進行操作時,重新分配的內存將丟失,並且在函數返回時將丟失。
sizeof(*(container.data)) / sizeof(uint16_t)
它將始終為1
因為*(uint16_t *) / sizeof(uint16_t)
始終為1。
原因: data
成員是指向uint16_t
指針。 *data
的類型為uint16_t
sizeof
是在編譯期間(而不是運行時)計算的,並且不會返回malloc
分配的malloc
。
看來您沒有正確使用sizeof
。 在您的結構中,您定義了uint16_t
指針 ,而不是數組。 uint16_t*
數據類型的大小是系統上指針的大小。 如果希望能夠精確調整其大小,則需要將分配的內存的大小與指針一起存儲。 看來您已經有一個具有data_size
的字段。 您的示例可能可以固定為
// I was unsure of the typedef-ing happening with data_t so I made it more explicit in this example
typedef struct {
int data_size;
uint16_t* data;
} data_t;
void extend_data(data_t* container, uint16_t value) {
// adds an additional uint16_t to the array of DATA, updates its internal
// variables, and initialises the new uint to VALUE.
// CURRENT LENGTH OF DATA
int len_data = container->data_size * sizeof(uint16_t);
printf("LENGTH OF DATA: %d\n", len_data);
uint16_t* tmp = realloc(container->data, (container->data_size + 1) * sizeof(uint16_t));
if (tmp) {
// realloc could fail and return false.
// If this is not handled it could overwrite the pointer in `container` and cause a memory leak
container->data = tmp;
container->data_size++;
container->data[container->data_size-1] = value;
} else {
// Handle allocation failure
}
len_data = container->data_size * sizeof(uint16_t);
printf("LENGTH OF DATA: %d\n", len_data);
printf("data_size: %d\n", container->data_size);
return;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.