Question

i want to build a structure which can hold simple datatypes like integers or arrays of that structure.

the structure looks like that:

typedef struct data_s {
  size_t size;  // size of memory data is pointing to
  void * data;  // pointer to data (array of data_t or simple type)
} data_t;

i have simplified it, normally there are more informations stored in the structure.
i wrote functions to set and get integer values, they work!
now i tried to write functions for creating an array and seting and getting the values, they don't work.
i used gdb to find where it fails. it shows me that my dereferencing doesnt work as i expect. i use following:

((data_t**)(data->data))[i]

and there i got a access violation.

i t would be great if somebody could show me my mistake. here is a working codeexample, i have minimized the code, that you dont have the overhead of my programm (also errorhandling is removed).

the code compiles without any error using gcc -g main.c -o test with gcc 4.8.1 on xubuntu 13.10 with 3.11 kernel

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

typedef struct data_s {
  size_t size;
  void * data;
} data_t;

void set_integer(data_t *data, int value){
  data->size = sizeof(int);
  data->data = malloc(data->size);
  *((int*)(data->data)) = value;
}

void get_integer(data_t *data, int *value){
  (*value) = *((int*)(data->data));
}

void create_array(data_t *data, size_t len){
  data->size = sizeof(data_t) * len;
  data->data = malloc(data->size);
  int i;
  for(i=0; i<data->size; i++){ //initialize array
    ((data_t**)(data->data))[i]->data = NULL;  
    ((data_t**)(data->data))[i]->size = 0;
  }
}

void set_array(data_t *data, int index, data_t *value){
  ((data_t**)(data->data))[index]->data = value->data;
  ((data_t**)(data->data))[index]->size = value->size;
}

void get_array(data_t *data, int index, data_t *value){
  value->data = ((data_t**)(data->data))[index]->data;
  value->size = ((data_t**)(data->data))[index]->size;
}

void free_data(data_t *data, int is_array){
  if(is_array){
    int i;
    for(i=0; i<(data->size / sizeof(data_t)); i++)
      free(((data_t**)(data->data))[i]->data);
  }
  free(data->data);
}

int main(int argc, char**argv){

  data_t data;
  set_integer(&data, 42);
  int val;
  get_integer(&data, &val);
  printf("expect 42; has: %d\n", val);
  free_data(&data, 0);

  data_t element;
  create_array(&data, 3);
  int i;
  for(i=0; i<3; i++){
    set_integer(&element, i*2);
    set_array(&data, i, &element);
  }
  for(i=0; i<3; i++){
    get_array(&data, i, &element);
    get_integer(&element, &val);
    printf("index: %d; value: %d\n", i, val);
  }
  free_data(&data, 1);

  return 0;
}
Was it helpful?

Solution 2

What does data->data point to? Well, the line data->data = malloc(data->size); tells you: it points to a slap of uninitialized memory.

The problem is, that you don't store anything in that memory before trying to dereference a pointer you read from this memory. I. e. (data_t**)data->data is fine, ((data_t**)data->data)[index] yields a data_t* of undefined value, and because that value is undefined, dereferencing the pointer with ((data_t**)data->data)[index]->data is undefined behavior.

If you want to create an array of data_t objects, one indirection suffices, i. e. use

void create_array(data_t *data, size_t len){
  data->size = sizeof(data_t) * len;
  data->data = malloc(data->size);
  int i;
  for(i=0; i<data->size; i++){ //initialize array
    ((data_t*)(data->data))[i].data = NULL;  
    ((data_t*)(data->data))[i].size = 0;
  }
}

OTHER TIPS

((data_t**)(data->data))[i] is used when data->data is an array of pointers, try

((data_t*)(data->data))[i]

EDIT: to access the members, use something like

((data_t*)data->data)[i].data = NULL;
((data_t*)data->data)[i].size = 0;
((data_t**)(data->data))[i];

In the above statement, data->data evaluates to data member of structure variable data (you should use different identifiers) which is of type void *. Now, you want to point data->data to a buffer which is an array of objects of type data_t. This means you must cast data->data to type data_t *, and not data_t **. Therefore, you should change the above statement to

((data_t *)(data->data))[i];

everywhere in your code. Also, note that free takes an argument of type void * and therefore you don't need to cast your pointer before passing it to free.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top