2017-09-05 155 views
-1

我很困惑C中的一個常見問題,那就是內存管理和指針。我有三個結構,就像這樣。結構中的指針指向結構的動態數組C

typedef struct { 
    uint8_t uuid[16]; 
} uuid_array; 

typedef struct Detail { 
    int8_t power; 
    uint32_t t1; 
    uint32_t dT; 
} Detail_t; 

typedef struct Base { 
    uuid_array unique_id; 
    Detail_t *data; 
} Base_t; 

我想創建10層Base_t結構,我想data指針在每個Base_tstruct指向的動態增長Detail_t結構數組。

我知道我應該使用malloc()realloc()但我沒有使用這些函數的經驗,我很困惑他們是如何工作的。

data指針如何指向動態大小的數組Detail_tstruct s?

非常感謝。

+0

[閱讀文檔(後http://man7.org/linux/man-pages/man3/malloc .3.html),你到底明白了什麼? –

+0

任何C教材或教程都應該解釋如何使用'malloc'和'realloc'來實現一個動態數組。指針在'struct'中時沒有什麼不同。 – Barmar

+0

在'struct base'中,您將需要添加一個項目'int n_dataItems'來跟蹤數組中有多少項。 –

回答

1

這裏是另一種方式......

#include <stdio.h> 
#include <stdint.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <string.h> 

typedef struct 
    { 
    uint8_t uuid[16]; 
    } uuid_array; 

typedef struct Detail 
    { 
    int8_t power; 
    uint32_t t1; 
    uint32_t dT; 
    } Detail_t; 

typedef struct Base 
    { 
    uuid_array unique_id; 
    Detail_t *data; 
    uint32_t dataItemCnt; /* In struct Base you will want to add an item int ** 
          ** n_dataItems to keep track of how many items  ** 
          ** there are in your array. – Paul Ogilvie   */ 
    } Base_t; 

#define SUCCESS 0 

/********************************************************** 
** Append a Detail_t structure to the data field of the to Base_t structure.. 
*/ 
int AppendData(Base_t *baseT, int8_t power, uint32_t t1, uint32_t dT) 
    { 
    int rCode = SUCCESS; 
    Detail_t *data=NULL; 

    /* Verify that the caller did not pass NULL as the Base_t structure address. */ 
    if(!baseT) 
     { 
     rCode=EINVAL;  /* Invalid Base_t value argument. */ 
     goto CLEANUP; 
     } 

    /* Increase the size of the baseT->data array sufficient for an additional Detail_t structure. */ 
    errno=SUCCESS; 
    data=realloc(baseT->data, (baseT->dataItemCnt + 1) * sizeof(Detail_t)); 
    if(!data) /* Verify that the realloc() succeeded. */ 
     { 
     rCode=errno; 
     goto CLEANUP; 
     } 

    /* Cause the Base_t data array to point to the newly (re-alloced) memory. */ 
    baseT->data = data; 

    /* Initialize the new Detail_t structure values. */ 
    baseT->data[baseT->dataItemCnt].power = power; 
    baseT->data[baseT->dataItemCnt].t1 = t1; 
    baseT->data[baseT->dataItemCnt].dT = dT; 

    /* Increment Base_t->dataItemCnt to reflect the appended Detail_t structure. */ 
    ++baseT->dataItemCnt; 

CLEANUP: 

    return(rCode); 
    } 

/********************************************************** 
** Free a previously allocated Base_t type. 
*/ 
int FreeBaseT(Base_t **baseT) 
    { 
    int rCode = SUCCESS; 

    /* Verify that the caller did not pass in NULL for baseT */ 
    if(!baseT) 
     { 
     rCode=EINVAL;  /* Invalid Base_t value argument. */ 
     goto CLEANUP; 
     } 

    /* verify that the the Base_t structure is not already free. */ 
    if(!*baseT) 
     { 
     rCode=EALREADY; /* The Base_t structure is NULL (Already free). */ 
     goto CLEANUP; 
     } 

    /* If there are Detail_t structures in the data array, free the data array. */ 
    if((*baseT)->data) 
     free((*baseT)->data); 

    /* Free the memory previously allocated to the Base_t structure. */ 
    free(*baseT); 
    *baseT = NULL; /* Eliminate the caller's reference to the freed memory. */ 

CLEANUP: 

    return(rCode); 
    } 

/********************************************************** 
** Allocate a Base_t type. 
*/ 
int AllocBaseT(Base_t **baseT_OUT, uint8_t uuid[16]) 
    { 
    int  rCode = SUCCESS; 
    Base_t *baseT = NULL; 

    /* Allocate memory to the Base_t structure. */ 
    errno=SUCCESS; 
    baseT = malloc(sizeof(Base_t)); 
    if(!baseT) 
     { 
     rCode=errno; 
     goto CLEANUP; 
     } 

    /* Initialize the initial values of the Base_t structure. */ 
    memset(baseT, 0, sizeof(Base_t)); 
    memcpy(&baseT->unique_id.uuid, uuid, 16); 

    /* Ensure that the caller passed a non-NULL address, 
     if so, return the address of the allocated Base_t structure. */ 
    if(baseT_OUT) 
     { 
     *baseT_OUT = baseT; 
     baseT = NULL; 
     } 

CLEANUP: 

    /* If the caller passed-in a NULL for baseT_OUT, 
     free the allocated memory to that the program does not cause a leak. */ 
    if(baseT) 
     { 
     int rc=FreeBaseT(&baseT); 
     if(rc && !rCode) 
     rCode=rc; 
     } 

    return(rCode); 
    } 

/********************************************************** 
** Dump a base_t structure. 
*/ 
int DumpBaseT(Base_t *baseT) 
    { 
    int  rCode = SUCCESS; 
    uint32_t index; 

    if(!baseT) 
     { 
     rCode=EINVAL;  /* Invalid Base_t value argument. */ 
     goto CLEANUP; 
     } 

    /* Print the Base_t->unique_array->uuid */ 
    printf("UUID: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", 
     baseT->unique_id.uuid[0], 
     baseT->unique_id.uuid[1], 
     baseT->unique_id.uuid[2], 
     baseT->unique_id.uuid[3], 
     baseT->unique_id.uuid[4], 
     baseT->unique_id.uuid[5], 
     baseT->unique_id.uuid[6], 
     baseT->unique_id.uuid[7], 
     baseT->unique_id.uuid[8], 
     baseT->unique_id.uuid[9], 
     baseT->unique_id.uuid[10], 
     baseT->unique_id.uuid[11], 
     baseT->unique_id.uuid[12], 
     baseT->unique_id.uuid[13], 
     baseT->unique_id.uuid[14], 
     baseT->unique_id.uuid[15] 
    ); 

    /* Print the Base_t->Detail_t values */ 
    printf("Number of data items: %u\n", baseT->dataItemCnt); 
    for(index=0; index < baseT->dataItemCnt; ++index) 
     { 
     printf(" data[%d] power=%d t1=%d dT=%d\n", 
     index, 
     baseT->data[index].power, 
     baseT->data[index].t1, 
     baseT->data[index].dT 
     ); 
     } 

CLEANUP: 

    return(rCode); 
    } 

/********************************************************** 
** Program start. 
*/ 
int main(int argC, char *argV[]) 
    { 
    int  rCode = SUCCESS; 
    Base_t *baset_A = NULL; 
    uint8_t uuid[16] = 
     { 
     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 
     0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 
     }; 

    /* Allocate memory for a Base_t structure (with no attached data) */ 
    rCode=AllocBaseT(&baset_A, uuid); 
    if(rCode) 
     { 
     fprintf(stderr, "AllocBaseT() reports: %d %s\n", rCode, strerror(rCode)); 
     goto CLEANUP; 
     } 

    /* Allocate some data (Detail_t) to the Base_t structure. */ 
    rCode=AppendData(baset_A, 1, 1000, 1111); 
    if(rCode) 
     { 
     fprintf(stderr, "AppendData() reports: %d %s\n", rCode, strerror(rCode)); 
     goto CLEANUP; 
     } 

    rCode=AppendData(baset_A, 2, 2000, 2222); 
    if(rCode) 
     { 
     fprintf(stderr, "AppendData() reports: %d %s\n", rCode, strerror(rCode)); 
     goto CLEANUP; 
     } 

    rCode=AppendData(baset_A, 3, 3000, 3333); 
    if(rCode) 
     { 
     fprintf(stderr, "AppendData() reports: %d %s\n", rCode, strerror(rCode)); 
     goto CLEANUP; 
     } 

    /* Print out the Base_t structure. */ 
    rCode=DumpBaseT(baset_A); 
    if(rCode) 
     { 
     fprintf(stderr, "DumpBaseT() reports: %d %s\n", rCode, strerror(rCode)); 
     goto CLEANUP; 
     } 

CLEANUP: 

    /* Free the memory allocated to the Base_t structure. */ 
    if(baset_A) 
     { 
     int rc=FreeBaseT(&baset_A); 
     if(rc) 
     fprintf(stderr, "FreeBaseT() reports: %d %s\n", rCode, strerror(rCode)); 
     } 

    return(rCode); 
    } 

輸出:

UUID: 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 
Number of data items: 3 
    data[0] power=1 t1=1000 dT=1111 
    data[1] power=2 t1=2000 dT=2222 
    data[2] power=3 t1=3000 dT=3333 
0

實施例:

typedef struct Base { 
    uuid_array unique_id; 
    int n_dataIems; 
    Detail_t *data; 
} Base_t; 

void example(void) 
{ 
    Base_t t; 
    int i; 
    t.n_dataItems= 0; 
    t.data= 0; 
    for (i=0; i<4; i++) 
    { 
     t.data= realloc(t.data, ++t.n_dataItems * sizeof(Detail_t)); 
     t.data[i].power= i; 
    } 
} 

(錯誤檢查ommitted)

注:詳細的定義必須是基本前。

+0

感謝你的支持,但是你能否很快解釋爲什麼這有用嗎?通過在該循環中遞增「t」,究竟發生了什麼。你只是看着數組中的下一個結構? –

+0

而在我的代碼中,我實際上並不知道「4」(for循環的上限)實際上會是什麼。這將取決於它檢測到的BT設備數量。我需要重新運行這個for循環從0到n在主,每次我檢測到一個BT設備,或者從前n到當前n。謝謝 –

+0

'++ t.n_dataItems'遞增n_dataItems,它只是計算添加的項目。 – pm100

1

下面是一個簡短的代碼來展示你怎麼能去了解它:

#include <stdint.h> 
#include <stdlib.h> 
#include <stdio.h> 

typedef struct { 
    uint8_t uuid[16]; 
} uuid_array; 

typedef struct Detail { 
    int8_t power; 
    uint32_t t1; 
    uint32_t dT; 
} Detail_t; 

typedef struct Base { 
    uuid_array unique_id; 
    Detail_t *data; 
} Base_t; 


int main() { 
    Detail_t data; 
    data.power = data.t1 = data.dT = 1; 
    Detail_t data2; 
    data2.power = data2.t1 = data2.dT = 2; 
    Base_t bases[10];//array of Base_t 
    int size = 1;//initial size of Detail_t array 
    bases[0].data = NULL; 
    bases[0].data = (Detail_t*)realloc(bases[0].data, size * sizeof(Detail_t));//first realloc acts as a malloc because bases[0].data is NULL at first 
    if (bases[0].data != NULL) {//if malloc(realloc) was successful 
    bases[0].data[0] = data;//store data 
    } 
    size = 2;//increase size of Detail_t array by 1 
    bases[0].data = (Detail_t*)realloc(bases[0].data, size * sizeof(Detail_t));//realloc new size 
    if (bases[0].data != NULL) {//if it didn't fail 
    bases[0].data[1] = data2;//store new data 
    } 
    printf("%d\n", bases[0].data[0].power);//print first data power 
    printf("%d", bases[0].data[1].power);//print second data power 
    free(bases[0].data);//free memory 
} 

這是否幫助?我猜混淆初學者的部分是演員。 malloc和realloc會返回一個類型爲void *的指針給分配的內存,然後您可以將其轉換爲您正在使用的類型。