user494461
user494461

Reputation:

How to return a float array in c and save it an array of floats to use later?

I have a C++ function which returns a std::vector<float>.

I am interfacing with some C code.

How do I change this C++ function so that it returns some pointer to a float array, and how do I save this returned array so that I can use it in my C code?

Upvotes: 0

Views: 736

Answers (4)

Steve Jessop
Steve Jessop

Reputation: 279325

From a C point of view, vector<float> does two things:

  1. Contain some floats
  2. Automatically free the memory it uses

Since 2 is an alien concept to C (nothing much happens automatically, certainly not freeing memory), there's no simple replacement. Basically you have three options. They are the same as the three options you have when you want functions to "return strings" in C, although here we need to tell the caller both a pointer and a length.

In my opinion, the third option is "the right answer", in the sense that it's the one you try first in your design, and if the design looks OK you stick with it. The first and second can be provided as convenience functions in cases where the calling code will really benefit from them, either wrapped around or alongside the third.

Return allocated memory

size_t c_wrapper(float **pResult) {
    try {
        std::vector<float> vec(cpp_function());
        *pResult= (float*) std::malloc(vec.size() * sizeof(float));
        if (!*pResult) { /* handle the error somehow */ }
        std::copy(vec.begin(), vec.end(), *pResult);
        return vec.size();
    } catch (std::bad_alloc) { /* handle the error somehow */ }
}

Upside: Simple calling code.

Downside: The caller has to free the memory, even if the size is known in advance and the data would happily fit in a local array variable. Might be slow due to memory allocation.

Model: strdup (Posix)

Use shared static-duration resources

See jrok's answer:

size_t c_wrapper(float **pResult) {
    try {
        static std::vector<float> vec;
        vec = cpp_function(); // or cpp_function().swap(vec) in C++03
        *pResult = &vec[0];
        return vec.size();
    } catch (std::bad_alloc) { /* handle the error somehow */ }
}

Upside: Ridiculously simple calling code.

Downside: There is only one instance of save in the program, so the returned pointer only points to the correct data until the next time c_wrapper is called. In particular, this is very thread-unsafe. If the result is very large, then that memory is wasted from the time the caller no longer needs it until the time the function is next called.

Model: strtok, gethostbyname.

Write the data into a buffer provided by the caller

size_t c_wrapper(float *buf, size_t len) {
    try {
        std::vector<float> vec(cpp_function());
        if (vec.size() <= len) {
            std::copy(vec.begin(), vec.end(), buf);
        }
        return vec.size()
    } catch (std::bad_alloc) { /* handle the error somehow */ }
}

Upside: Most flexible.

Downside: The caller has to pass in a big enough buffer (assuming cpp_function behaves consistently, caller can find out the size by calling the function with size 0 and a null pointer, get a big enough buffer from somewhere, then call the function again).

Model: strcpy, snprintf, getaddrinfo.

Upvotes: 1

jrok
jrok

Reputation: 55425

You could save the returned temporary vector in a vector object with static storage duration.

std::vector<float> foo()
{
    return std::vector<float>();
}

float* call_foo_and_get_pointer()
{
    static std::vector<float> save; // this line is executed only at the first
                                    // call to enclosing function
    save = foo();
    return save.data();  // or &data[0]
}

The pointer returned from call_foo_and_get_pointer is guaranteed to stay valid until the next call to it.

Upvotes: 0

Jon
Jon

Reputation: 437574

You can get a pointer to a "raw" array with std::vector::data or &my_vector[0] if C++11 is not available. However, if a vector operation forces the vector to be resized then the raw storage will move around in memory and this pointer will no longer be safe to use. If there is any possibility of this happening, you will need to allocate separate storage (e.g. by creating a copy of the vector) and provide a pointer to that instead.

Update: Woodrow's comment made me notice that you are actually after returning a pointer from a function. You can only return pointers to heap-allocated memory, so you cannot use a local vector (or any other type of stack-allocated memory) to do this.

Upvotes: 5

chlaws
chlaws

Reputation: 30

#include <vector>
#include <iostream>

int main()
{
    std::vector<float> vec;
    vec.push_back(1.23);
    vec.push_back(3.123);
    int len = vec.size();
    float *arr = new float[len];
    std::copy(vec.begin(),vec.end(),arr);
    for(int i = 0; i < sizeof(arr)/sizeof(arr[0]); ++i){
        std::cout << arr[i] << "\n";
    }
    delete [] arr;
    return 0;
}

Upvotes: 0

Related Questions