2

I am having trouble with the creating a dynArray and adding elements to it. I am not sure how to allocate memory for it. I have only recently started pointers so any help would be much appreciated.

typedef struct{
  doube *darray;
  int size;
}dynArray;//dynArray structure

dynArray *createDynArray(int n);
{
  dynArray *newdynArray;//newdynArray is a pointer to the dynArray structure
  newDynArray->darray=(double*)malloc(n*double);
Eamonn
  • 53
  • 8
  • 1
    You're derefencing an uninitialized variable `newdynArray` in the line with the `malloc()`; that's bad news. You first need to allocate something for the `newdynArray` to point at. Can you use C99 'flexible array members' (FAM)? If so, you do things one way; if not, you have to do things another way. Are you ready to learn about FAM or do you need to take time out learning basic pointers first — which is not unreasonable. – Jonathan Leffler Dec 07 '14 at 17:00
  • 1
    `doube` -> `double` and `malloc(n*double)` -> `malloc(n*sizeof(double))` . More : someone will tell you not to cast the return of `malloc()`. See http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc – francis Dec 07 '14 at 17:01
  • Hi Jonathan I would prefer to get my head around pointers first. I am not sure where I am dereferencing a uninitialized pointer. I thought newdynArray is a pointer to dynArray and from this new pointer I can access darray to allocate memory for it? What is wrong with my logic – Eamonn Dec 07 '14 at 17:19
  • @Eamonn To which dynArray is newdynArray pointing? – 2501 Dec 07 '14 at 17:23
  • newdynArray is pointing to dynArray structure. – Eamonn Dec 07 '14 at 17:25
  • I have added comments to the code, I hope I understood you correctly? – Eamonn Dec 07 '14 at 17:33

4 Answers4

1

You need to allocate space for both the container and the array itself:

typedef struct dynArray {
  double *darray;
  int size;
} dynArray;

dynArray *createDynArray(int n) {
    dynArray *newDynArray = malloc(sizeof(dynArray));
    newDynArray->size = n;
    newDynArray->darray = calloc(n, sizeof(double));
    return newDynArray;
}

void deleteDynArray(dynArray *dynArray) {
    free(dynArray->darray);
    free(dynArray);
}
Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
  • May be worth a short explanation about the use of `calloc` to allocate `darray` to insure all array values are initialized to `0` to protect against, among other things, inadvertent read from uninitialized space. – David C. Rankin Dec 07 '14 at 17:38
  • Hi Bill,thank you very much for your response. I just have one question how do you make sure there is enough memory. Do you need 2 check cases when using malloc and calloc or is there away of avoiding it and just using one. – Eamonn Dec 07 '14 at 17:43
  • @Eamonn: In the code above, I should be verifying that `malloc()` and `calloc()` don't return `NULL`. There is a common trick to reduce this to one allocation, which you can read about here: http://stackoverflow.com/questions/599365/what-is-your-favorite-c-programming-trick/599441#599441 That being said, I would recommend using two allocations right now until you fully understand pointers. – Bill Lynch Dec 07 '14 at 17:44
0

I would include checking for NULL. Just in a case.

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

typedef struct{
    double *darray;
    int size;
}dynArray;

dynArray *createDynArray(int n)
{
    dynArray *newdynArray = malloc(sizeof(dynArray));
    if (newdynArray!=NULL) newdynArray->darray=malloc(n*sizeof(double));
    newdynArray->size = n;
    return newdynArray;
} 

dynArray *deleteDynArray(dynArray *olddynArray) {
    if (olddynArray!=NULL) free(olddynArray->darray);
    free(olddynArray);
    return olddynArray;
}

int main() {
    int i;
    dynArray *my;
    my = createDynArray(10);
    if (my->darray!=NULL) {
        for (i=0; i<my->size; i++)
            my->darray[i] = (float)i;
        for (i=0; i<my->size; i++)
            printf("%lf\t", my->darray[i]);
    }
    deleteDynArray(my);
    return 0;
}
Polakko
  • 788
  • 1
  • 6
  • 12
0

You'd also need a function to do the freeing your allocation style can be made nicer without casts and using

typedef struct{
  double *darray;
  int size;
}dynArray;//dynArray structure

dynArray *createDynArray(int n)
{
  dynArray *newdynArray = malloc(sizeof *newdynArray); // don't cast the return
  // the below is called a compound literal (or composite literal)
  *newdynArray = (dynArray){malloc(n * (sizeof *newdynArray->darray)), n};
  return newdynArray;
}

void freeDynArray(dynArray *self)
{
  free(self->darray);    // free held data
  free(self);            // free the outer structure
}

As for adding elements, you could hide it behind functions, adding safety if you'd like

// return 0 on success, non-zero if error
int set_item(dynArray *self, int index, double e)
{
    if (index >= self->size || index < 0) { //bounds check
       return -1;
    }
    self->darray[index] = e;
    return 0;
}

double get_item(dynArray *self, int index)
{
    if (index >= self->size || index < 0) { //bounds check
        // Note: impossible to distinguish between error and actual 1.0
        return -1.0; 
    }
    return self->darray[index];
}

The bounds checks are of course up to you to decide. If you don't want them then remove them.

Ryan Haining
  • 35,360
  • 15
  • 114
  • 174
0

Another popular way to provide initializers and deinitializers for your structure is to only operate on already allocated memory. This approach is more general as it allows your structure to be used both, stack and heap allocated.

struct dynamic_array
{
  double * data;
  size_t size;
};

int
dynamic_array_init(struct dynamic_array *const dyn_arr_ptr,
                   const size_t size)
{
  if (dyn_arr_ptr == NULL)
    return -1;  /* invalid argument */
  /* Allocate an array initially filled with zeros. */
  dyn_arr_ptr->data = calloc(size, sizeof(double));
  if (dyn_arr_ptr->data == NULL)
    return -1;  /* out of memory */
  dyn_arr_ptr->size = size;
  return 0;  /* success */
}

int
dynamic_array_deinit(struct dynamic_array *const dyn_arr_ptr)
{
  if (dyn_arr_ptr == NULL)
    return 0;  /* nothing to do */
  free(dyn_arr_ptr->data);
  dyn_arr_ptr->data = NULL;
  dyn_arr_ptr->size = 0;
  return 0;
}

It can then be used to initialize a stack-based structure…

struct dynamic_array dyn_arr;
if (dynamic_array_init(&dyn_arr, 42) < 0)
  {
    fprintf(stderr, "error: cannot initialize array\n");
    return EXIT_FAILURE;
  }
/* Use the dynamic array... */
dynamic_array_deinit(&dyn_arr);

… as well as a heap-based one.

struct dynamic_array * dyn_arr_ptr = malloc(sizeof(struct dynamic_array));
if (dynamic_array_init(dyn_arr_ptr, 42) < 0)
  {
    fprintf(stderr, "error: cannot initialize array\n");
    return EXIT_FAILURE;
  }
/* Use the dynamic array... */
dynamic_array_deinit(dyn_arr_ptr);
free(dyn_arr_ptr);

Note that I can pass the result of malloc unchecked to the initializer function because it does a NULL check and handles this case gracefully.

5gon12eder
  • 24,280
  • 5
  • 45
  • 92