1

I am feeling a bit insecure about passing complicated, asymetrical data types & structure to functions, yet I would like to properly segment some of my source code for reusing. As tradeoff between human readability and performance I went for using a 'suboptimal' data format:

  • one array consisting of <number_of_curves> non-identical curves, the i-th curve being defined in <number_of_points>[i] five-dimensional points.

In pseudo-code it looks so:

int number_of_curves;
int number_of_points[number_of_curves]; //aux. array storing number of points per curve

typedef struct point{
    float x;
    float y;
    float z;
    float v;
    float w;
} point;

point array[number_of_curves][number_of_points[i]]; // 0 < i < number_of_curves

In practice, one cannot predict sizes and statically initialize any of the variables, so the code becomes:

int     num_curves;
int    *num_points;
point **array;

//read num_curves from file...
num_points = calloc(num_curves*sizeof(int)); 

//read the values for num_points[i] from file...
array = (point**)malloc(num_curves*sizeof(point*)); //few compilers doing strange things unless casted
for(int i = 0; i<num_curves; i++)
    array[i] = (point*)malloc(num_points[i]*sizeof(point));

//read the values for array[i][j].x, array[i][j].y etc. from file... 

Having not much experience in passing complicated data types to functions which should access and modify any member of any element in such arrays, change the order of elements, possibly resize the arrays, free and create new ones instead, I'm using the simplest function call:

int error = func1(&array, &num_points, &num_curves);

An apparently working example of a "dummy" func1(), deleting odd members, passed basic functional tests. I'm not sure about causing possible UB, memory leaks and fragmentation, which is difficult to debug. This is what my question is about, I'm not asking for a code review. Logical reasoning and understanding a bit of literature including: Passing multidimensional arrays as function arguments in C make me hope I'm on the right track in learning a safe way... Here's the definition:

int func1 (point ***arrayPtr, int **num_pointsPtr, int *num_curvesPtr)
{
  point **arr;
  int    i, j, k, *pts;
  int    crvs = *num_curvesPtr - (*num_curvesPtr)/2;

  pts  = malloc(crvs*sizeof(int));
  if (pts == NULL) return 1;        

  for (i = 0; i < crvs; i++)
      pts[i] = (*num_pointsPtr)[i+i];

  arr = (point**)malloc(crvs*sizeof(point*));
  if(arr == NULL){
      free(pts);
      return 2;
      }

  for (i = 0; i < crvs; i++){
      arr[i] = (point*)malloc(pts[i]*sizeof(point));
      if (arr[i] == NULL){
          for(k = i-1; k >= 0; k --)
              free(arr[k]);
          free(arr);
          free(pts);
          return 3;    
          }               
      }

  for (i = 0; i < crvs; i++)
      for(j = 0; j < pts[i]; j++){
          arr[i][j].x = (*arrayPtr)[i+i][j].x;
          arr[i][j].y = (*arrayPtr)[i+i][j].y;
          arr[i][j].z = (*arrayPtr)[i+i][j].z;
          arr[i][j].v = (*arrayPtr)[i+i][j].v;
          arr[i][j].w = (*arrayPtr)[i+i][j].w;
          }

  for(i = 0; i < *num_curvesPtr; i++)
     free ((*arrayPtr)[i]);

  free(*arrayPtr);
  free(*num_pointsPtr);

  *arrayPtr      = arr;
  *num_pointsPtr = pts;
  *num_curvesPtr = crvs;
return 0;
}

Thanks for reading. Any hint if this is a valid direction would help me. Please let me know if something isn't clear.

Community
  • 1
  • 1
user3078414
  • 1,942
  • 2
  • 16
  • 24
  • I would make an extra type for `curve`... and perhaps some convenience functions to set the points. – Eugene Sh. May 17 '16 at 17:34
  • 3
    This is a better fit for code review, despite your disclaimer to the contrary. And the compilers that do funny things when you don't cast the return value from `malloc` are C++ compilers. – user3386109 May 17 '16 at 18:19
  • 1
    I'm not 100 percent clear on the question... I would advise always putting your for loops in braces to make your intent obvious. To expand upon Eugene's comment, I'd abstract a lot in this case. Create functions that return allocated memory, create a function that frees, expand your data structure to include size, etc. – Christopher Schneider May 17 '16 at 18:20
  • Thanks for pointing me at possibly ambiguous statements. All I'd need to know is if there are hidden problems (which can generate UB, leaks, etc) which might have skipped my attention. @user3386109 As for `malloc()`, I have to take care for some backward compatibility, but I'll gladly remove the casts from this example if you're sure all modern C compilers can handle such DIY data types and this looks _uneducational_. Thanks for your comments! – user3078414 May 17 '16 at 18:43

0 Answers0