结构中的指针到结构C的动态数组

时间:2017-09-05 15:57:57

标签: c pointers multidimensional-array memory-management struct

我对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;

我想创建十个Base_t结构,我希望每个data Base_t中的struct指针指向一个动态增长的Detail_t数组结构

我知道我应该使用malloc()realloc(),但我没有使用这些功能的经验,我对它们如何运作感到困惑。

data指针如何指向动态大小的Detail_t struct数组?

非常感谢。

3 个答案:

答案 0 :(得分: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 *的指针返回给已分配的内存,然后您可以将其转换为您正在使用的类型。

答案 1 :(得分: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

答案 2 :(得分: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;
    }
}

(错误检查已省略。)

注意:细节的定义必须在Base之前。