1

I want to fill 2d array of struct with all 0. Firstly, I defined size of 2d array with define macro. As follows:

#define VECLEN 4

I have struct as follows:

struct args
{
  int size;
  int array[VECLEN][VECLEN];
};

However, I want to get the size of my 2d array from user but I couldn't dynamically give the size of 2d array.

I use multithread functionality with pthread_create using 2 threads. I have to call fill function twice with multithread. When I fill the input array with defined size(4), I can easily get desired output as follows:

 0       0       0       0
 0       0       0       0
 0       0       0       0
 0       0       0       0

However, I got weird result, when I want to fill 6*6 array as follows:

     0       0       0       0       0       0
     0       0       0       0       0       0
     0       0       0       0       0       0
     0       0       0       0       0       0
     0       0       0       154148873       537473056       824183088
     537473056       825636144       892483616       825635638       537474100       

Here is my code:

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

#define VECLEN 4
pthread_mutex_t myMutex;

struct args
{
  int size;
  int array[VECLEN][VECLEN];
};

void fill(void *input)
{
   int size = ((struct args *)input)->size;

   for (int j = 0; j < size; j++)
   {
      for (int i = 0; i < size; i++)
      {
        ((struct args *)input)->array[i][j] = 0;
      }
   }
}

int main()
{
  struct args *arguments = (struct args *)malloc(sizeof(struct args));
  int number;
  printf("please enter the size : ");
  scanf("%d", &number);
  arguments->size = number;

  pthread_t threads[2];

  pthread_mutex_init(&myMutex, NULL);

  for (int i = 0; i < 2; i++)
    pthread_create(&threads[i], NULL, fill, (void *)arguments);

  for (int i = 0; i < 2; i++)
    pthread_join(threads[i], NULL);

  pthread_mutex_destroy(&myMutex);

  for (int row = 0; row < number; ++row)
  {
    for (int col = 0; col < number; ++col)
        printf("\t %d", arguments->array[row][col]);
    printf("\n");
  }
}
bedirates
  • 67
  • 4
  • 1
    [don't cast malloc](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) – Barmar May 10 '23 at 19:43
  • `size` has to be less than or equal to `VECLEN`, otherwise you access outside the array. – Barmar May 10 '23 at 19:45
  • 1
    You can't put a variable-length array in a structure. You should change the structure to hold a pointer to a dynamically-allocated array. – Barmar May 10 '23 at 19:46
  • 1
    Your title says "array of struct". You don't have an array of struct, you have an array as a member of the struct. – Barmar May 10 '23 at 19:49
  • https://stackoverflow.com/questions/47746099/how-to-malloc-free-a-struct-with-a-contained-2d-array (classic) or https://stackoverflow.com/questions/38448844/how-to-malloc-array-2d-in-c (current best practice) – Allan Wind May 10 '23 at 19:54

1 Answers1

2

You can use malloc and Variably Modified types as follows (if you support C99 or above but I've also shown below the alternatives as well):

The issue with your code is that you are not allocating enough storage and additionally your array type (specifically the first dimension) is fixed.

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

pthread_mutex_t myMutex;

struct args
{
  int size;
  int array[];
};

void fill(void *input)
{
   int size = ((struct args *)input)->size;

   int (*parray)[size] = ((struct args *)input)->array;

   for (int j = 0; j < size; j++)
   {
      for (int i = 0; i < size; i++)
      {
        parray[i][j] = 0;
      }
   }
}

int main()
{
  struct args *arguments;
  int number;
  printf("please enter the size : ");
  scanf("%d", &number);
  arguments = malloc(sizeof(struct args) + sizeof(int[number][number]));
  arguments->size = number;

  pthread_t threads[2];

  pthread_mutex_init(&myMutex, NULL);

  for (int i = 0; i < 2; i++)
    pthread_create(&threads[i], NULL, fill, (void *)arguments);

  for (int i = 0; i < 2; i++)
    pthread_join(threads[i], NULL);

  pthread_mutex_destroy(&myMutex);

  int (*parray)[number] = arguments->array;

  for (int row = 0; row < number; ++row)
  {
    for (int col = 0; col < number; ++col)
        printf("\t %d", parray[row][col]);
    printf("\n");
  }
}

Variably Modified type dimensions are calculated at runtime. We also use a flexible array member at the end of the structure and add the size of our variably modified array to the malloc call.

The benefit of this approach is that the fill function works as expected without modification. The alternative implementation is as follows:

void fill(void *input)
{
   int size = ((struct args *)input)->size;

   for (int j = 0; j < size; j++)
   {
      for (int i = 0; i < size; i++)
      {
        ((struct args *)input)->array[i * size + j] = 0;
      }
   }
}

As well as the malloc call:

  arguments = malloc(sizeof(struct args) + sizeof(int) * number * number);

For the flexible array member - the alternative approach would be:

struct args
{
  int size;
  int array[1];
};

With the following malloc:

  arguments = malloc(offsetof(struct args, array) + sizeof(int) * number * number);

The above is because of alignment issues present otherwise.

AnArrayOfFunctions
  • 3,452
  • 2
  • 29
  • 66
  • if it's not clear - my first solution uses aforementioned construct - I just gave alternatives after it - including a solution without Flexible member whilst the quoted piece of code is solely demonstrating that Variably modified types can be substituted with a calculation of `sizeof(int)` multiplied by `number` 2 times (and it still assumes the first solution is used - which if you had looked closely uses FMA). Also if you knew how to read - it would helped substantially as well - "For the flexible array member - **the alternative approach would be**:". – AnArrayOfFunctions May 11 '23 at 02:00
  • BTW, good use of `sizeof(int) * number * number` and not `number * number * sizeof(int)`. The 2nd may overflow where the first does not. – chux - Reinstate Monica May 11 '23 at 03:06