0

I need to work upon a variable number of fixed-size arrays. More specifically, N points in a K-dimensional space, where I know K beforehand, but I don't know N at compile time. So I want to use a pointer to the fixed-size array, and allocate space for N K-dimensional points at runtime.

In C, I can allocate the said pointer with malloc. Example test.c below, where dimension is 3 for simplicity:

#include <stdlib.h>
#include <stdio.h>
#define DIMENSIONS  3

typedef float PointKDimensions[DIMENSIONS];

void do_stuff( int num_points){
  PointKDimensions *points;
  points = malloc(num_points * sizeof(PointKDimensions));
  points[5][0] = 0;    // set value to 6th point, first dimension
  points[5][1] = 1.0;  // to second dimension
  points[5][2] = 3.14; // to third dimension
  return;
}

int main(){
    do_stuff(10); // at run-time I find out I have 10 points to handle
    return 0;
}

I can compile this with gcc test.c without errors, and run without segmentation faults.

However, if I try to achieve the same behavior with C++ mv test.c test.cpp, followed by g++ test.cpp, I get:

test.cpp: In function ‘void do_stuff(int)’:
test.cpp:10:18: error: invalid conversion from ‘void*’ to ‘float (*)[3]’ [-fpermissive]
10 |   points = malloc(num_points * sizeof(float) * DIMENSIONS);
   |            ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   |                  |
   |                  void*

Searching up, I found that C++ does not do implicit conversions for malloc, so I changed the malloc to:

 points = (float*) malloc(num_points * sizeof(float) * DIMENSIONS);

And then the error becomes:

test.cpp: In function ‘void do_stuff(int)’:
test.cpp:10:12: error: cannot convert ‘float*’ to ‘float (*)[3]’ in assignment
   10 |   points = (float*) malloc(num_points * sizeof(float) * DIMENSIONS);
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |            |
      |            float*

But I could not find a way to do the appropriate cast/conversion to solve this error. E.g., (float**) is also not the same as float(*)[3].

Any suggestions on how to allocate space for a pointer to fixed-sized arrays in C++?

1
  • 2
    Don't use malloc in C++. If you want a run time sized array, use a std::vector. Commented Nov 12, 2021 at 17:38

2 Answers 2

2

You need to cast the result of malloc as PointKDimensions* not as a float*:

typedef float PointKDimensions[DIMENSIONS];

void do_stuff( int num_points){
  PointKDimensions *points;
  points = (PointKDimensions*)malloc(num_points * sizeof(PointKDimensions));
  points[5][0] = 0;    // set value to 6th point, first dimension
  points[5][1] = 1.0;  // to second dimension
  points[5][2] = 3.14; // to third dimension
  return;
}

Or better, use C++'s built-in container for dynamically sized arrays, std::vector:

vector<vector<float>> points;

void do_stuff( int num_points){
  points.resize(num_points, vector<float>(k)); // assuming k = number of dimensions.
  points[5][0] = 0;    // set value to 6th point, first dimension
  points[5][1] = 1.0;  // to second dimension
  points[5][2] = 3.14; // to third dimension
  return;
}
Sign up to request clarification or add additional context in comments.

6 Comments

We know the number of dimensions for the inner array, so nested vectors is not appropriate here. Has the potential to slows the program down dramatically.
That was exactly what I was looking for! Also, the point mentioned by @user4581301 is what I was trying to leverage when keeping the information about the known size. I know a bit about std containers, they are more flexible and safe, but my target is a scientific application (forgot to mention), so keeping things as raw as possible was intended. Thanks anyway.
@exepe combine this answer with Erdal's and you'll have a very robust and efficient solution.
@user4581301 I wanted to write something similar. If you want it to be as raw as possible, std::vector as point is not the best choice, std::array is better suited for that. But what you were pointing out all the time, instead of malloc a std::vector is the appropriate container for that, long story short: std::vector<std::array<TYPE, DIM>>
@exepe The goal is to help each other out. As long as nobody gives you a hint, that you did something wrong, don't let that trouble you. Happy coding.
|
2

You could use std:array for that.

e.g.

#include <array>

inline constexpr const size_t DIMENSIONS = 3;
using PointKDimensions = std::array<float, DIMENSIONS>;

6 Comments

While I largely agree with the answer, I suspect the asker has some reason they want to get the storage from the freestore rather than an automatic allocation.
And reading over the question again, I can see what the reason is: num_points is not a fixed value. The answer skips over how to correctly use malloc and a cast, and the answer to that bit is "Don't. Use a std::vector."
@user4581301 std::array is an aggregate type with the same semantics as a struct holding a C-style array T[N] as its only non-static data member. The question at the end is: Any suggestions on how to allocate space for a pointer to fixed-sized arrays in C++? We do have a fixed size array; with the type float, PointKDimensions is trivially copyable, therefore save for malloc, memcpy and co.
@user4581301 One thing i've learned migrating from C to C++ was, pointer and arrays are better wrapped into appropriate classes.
Agree 100%. My point is the asker is little better off when they try to allocate num_points std::arrays than they were trying to allocate num_points float [DIMENSIONS]s. std::vector<PointKDimensions> points(num_points); makes almost all of the dynamic allocation and casting issues go away.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.