Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Garbage value even after initializing members of dynamically allocated struct array

I have a dynamically allocated array of structures, 'buff'. Each element is a structure that has a few integer variables and a pointer 'buffer_ptr' which points to another dynamically allocated array of structures. The size of both arrays is given as command line input.

int buffer_size;
int user_num;
struct tuple
{
  char userID[5];
  char topic[16];
  int weight;
};
struct buff_ctrl    
{
  struct tuple* buffer_ptr;
  int in;
  int out;
  int numItems;
  int done;
};

The arrays are created and initialized in main() as follows:

int main(int argc, char* argv[])
{
  void *status;
  pthread_t mapThd;
  if(argc != 4)
  {
    printf("Input format: ./combiner <buffer_size> <number_of_users> <input_file>\n");
    return -1;
  }
  buffer_size = atoi(argv[1]);
  user_num = atoi(argv[2]);
  struct buff_ctrl *buff = (struct buff_ctrl*)malloc(user_num * sizeof(struct buff_ctrl)); 
  for(int i=0; i<user_num; i++)
  {
    struct buff_ctrl* curr_buff = (buff + (i*sizeof(struct buff_ctrl)));
    struct tuple *ptr = (struct tuple*)malloc(buffer_size * sizeof(struct tuple));
    curr_buff->buffer_ptr = ptr;//points to another array
    curr_buff->in = 8;
    curr_buff->out = 4;
    curr_buff->numItems = 7;
    curr_buff->done = 0;
    printf("%p\n",curr_buff);
  }

Then, I need to pass the 'buff' pointer as an argument when creating thread using pthread_create:

  pthread_create(&mapThd, NULL, mapper, (void*)buff);
  pthread_join(mapThd, &status);
  free(buff);
  /*end of main*/

My function pointer is as follows:

void* mapper(void *buff)
{
  struct buff_ctrl* arr = (struct buff_ctrl *)buff;
  struct buff_ctrl* temp_ptr;
  printf("######################################################\n");
  for(int k=0; k<user_num; k++)
  {
    /*Printing just to check values */
    temp_ptr = arr + (k*sizeof(struct buff_ctrl));
    printf("buffer ptr =  %p\n", temp_ptr->buffer_ptr);
    printf("in =  %d\n", temp_ptr->in);
    printf("out =  %d\n", temp_ptr->out);
    printf("numItems =  %d\n", temp_ptr->numItems);
  }
  printf("######################################################\n");
  pthread_exit((void*)buff);
}

But, when I print the values of 'buffer_ptr' from the created thread (only one), for ODD number of user_num, there is always ONE element of the array 'buff' which gives garbage value after pthread_create statement! When the values are checked in main itself after removing calls to pthread, it runs fine.

like image 394
Kaustubh Bapat Avatar asked Jan 29 '23 17:01

Kaustubh Bapat


1 Answers

This line

struct buff_ctrl* curr_buff = (buff + (i*sizeof(struct buff_ctrl)));

should be

struct buff_ctrl* curr_buff = buff + i;

buff + i is pointer arithmetic and the compiler already takes the size of the object pointed to by buff into consideration. By doing i*sizeof(struct buff_ctrl) you are assigning a pointer that may be after the allocated memory.

As general suggestion:

Don't cast malloc. And instead of using sizeof(<type>), use sizeof *variable, this is more safe, because it's easier to make mistakes when writing sizeof(<type>).

So:

struct buff_ctrl *buff = malloc(user_num * sizeof *buff);

...

struct tuple *ptr = malloc(buffer_size * sizeof *ptr);

And you don't need to declare a separate pointer, you can do:

for(int i=0; i<user_num; i++)
{
    buff[i].buffer_ptr = malloc(buffer_size * sizeof *buff[i].buffer_ptr);
    buff[i].in = 8;
    buff[i].out = 4;
    buff[i].numItems = 7;
    buff[i].done = 0;
}

Also you should always check for the return value of malloc. If it returns NULL, you cannot access that memory.

like image 161
Pablo Avatar answered Mar 29 '23 23:03

Pablo