-1

How can I convert vector of floats into a char*?

I have a collection of floats stored inside std::vector<float> id_list:

0,
0,
0,
0,
0,
1.77636e-15,
2.35099e-38,
-7.10543e-15,
3.06107e-38,
....

and using this code to convert it:

char *ptr = (char*)&id_list[0];
std::string dump_string(ptr, id_list.size() * sizeof(float));

but dump_string.c_str() returns empty, despite having some values stored in my vector. I'm expecting to get all values concatenated into a one, long string, ie.:

0,0,0,0,0,1.77636e-15,2.35099e-38,-7.10543e-15,3.06107e-38........
Mateusz Wójt
  • 109
  • 2
  • 15
  • 1
    Can you give examples of what inputs and according results you expect? – Ulrich Eckhardt Nov 19 '20 at 20:16
  • It's not surprising that `dump_string.c_str()` would return empty, since that just means the first byte in your string is a null byte. The surprising thing would be if `dump_string.size()` returned zero. – john Nov 19 '20 at 20:17
  • Do you know what marks the end of a C-style string, that's returned from `c_str()`. Is the first `float` value, in this vector, happen to be a floating point 0.0 by any chance? – Sam Varshavchik Nov 19 '20 at 20:18
  • Nice to see some values. Now the improtant question is what you are expecting to get out of this conversion? From the values you have given `c_str()` being empty is the correct result, but clearly you are expecting something else. – john Nov 19 '20 at 20:20
  • @UlrichEckhardt I edited the post with the expected input and output. – Mateusz Wójt Nov 19 '20 at 20:21
  • @SamVarshavchik it happens that the first value is actually 0.0 null-terminator ;] – Mateusz Wójt Nov 19 '20 at 20:22
  • @MateuszWójt You are misunderstanding the code you have written. What you are getting with that code is the **byte representation** of your floats in a string. – john Nov 19 '20 at 20:22
  • I don't see any output. As far as the info goes, `char *result = (char*)42;` would be okay. Please read [ask], your question lacks info about the requirements on the results. – Ulrich Eckhardt Nov 19 '20 at 20:22
  • 1
    If you want something like `"000001.77636e-152.35099e-38 ..."` then you need to rewrite your code. Use an `ostringstream` for the conversion. – john Nov 19 '20 at 20:24
  • 4
    You do not convert float values into character representations of those values simply by casting a pointer to a one into a pointer to the other one. This doesn't work for floats, and doesn't work for any other type in C++. C++ does not work this way. You need to convert each value, in the vector, individually, using the appropriate formatting operation. – Sam Varshavchik Nov 19 '20 at 20:29
  • @MateuszWójt -- What you are looking for is more than likely `std::transform`. That should be one of the proper ways to "convert" that vector into a `std::string`. – PaulMcKenzie Nov 19 '20 at 20:31
  • Use a stringstream to insert string versions of the floats into a string: https://onlinegdb.com/H1fZtI4qv – Jerry Jeremiah Nov 19 '20 at 20:39

4 Answers4

3

I'm expecting to get all values concatenated into a one, long string, ie.:

0,0,0,0,0,1.77636e-15,2.35099e-38,-7.10543e-15,3.06107e-38........

You are creating a std::string that simply holds a copy of the raw bytes of the float array. So, if any of the bytes happen to contain a numeric value of 0 (as is the case in your example), you will get a truncated result if you try to treat the std::string as a null-terminated C string.

If you want to actually convert the float values into a human-readable string, you need to format the values individually, such as with std::ostringstream or std::to_string(), eg:

std::ostringstream oss;
if (!id_list.empty()) {
    oss << id_list[0];
    for(size_t i = 1; i < id_list.size(); ++i) {
        oss << "," << id_list[i];
    }
}
std::string dump_string = oss.str();
std::string dump_string;
if (!id_list.empty()) {
    dump_string += std::to_string(id_list[0]);
    for(size_t i = 1; i < id_list.size(); ++i) {
        dump_string += ',';
        dump_string += std::to_string(id_list[i]);
    }
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
2

. I'm expecting to get all values concatenated into a one, long string, ie.:

You could write a small function to do that.

Example:

#include <iostream>
#include <iterator> // std::advance
#include <string>
#include <sstream>  // std::stringstream
#include <vector>

// a function taking two iterators and streaming the content to a stringstream
// then returning a `std::string` using `stringstream::str()`
template<typename Begin, typename End = Begin>
std::string join(Begin begin, End end) {
    std::stringstream retval;
    if(begin != end) {
        retval << *begin;
        for(std::advance(begin, 1); begin != end; std::advance(begin, 1)) {
            retval << ',' << *begin;
        }
    }
    return retval.str();
}

int main()
{
    std::vector<float> id_list {
        0,
        0,
        0,
        0,
        0,
        1.77636e-15,
        2.35099e-38,
        -7.10543e-15,
        3.06107e-38,
    };
    std::cout << join(id_list.begin(), id_list.end());
}

Output:

0,0,0,0,0,1.77636e-15,2.35099e-38,-7.10543e-15,3.06107e-38
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
2

As others note, your approach of using casting is not the right way to go. Also, note that all of the value in your example are probably exactly 0.0 (or -0.0)! Why? Because they're beyond the precision range of float on typical platforms.

Still, you could concatenate the string representation of the float's in an std::vector, using the ranges library, and with no need for any loops:

#include <vector>
#include <string>
#include <iostream>
#include <range/v3/all.hpp>

std::string concat_my_floats(const std::vector<float>& vec) 
{
    std::ostringstream oss;
    auto convert = [&](float x) { oss.str(""); oss << x; return oss.str(); };
    return vec  
        | ranges::views::transform(convert) 
        | ranges::views::cache1 // We need this, see footnote.
        | ranges::views::join(',')
        | ranges::to<std::string>();
}

int main () {
    std::vector<float> id_list = {0, 1.1, -2.2, 3.3};
    std::cout << concat_my_floats(id_list) << std::endl;
}

This will give you:

0,1.1,-2.2,3.3

If you're wondering what's that cache1 business - it has to do with how the transformed range is a range of prvalues, which the ranges library is not willing to join for performance reasons; apparently you need to explicitly allow a caching of the last element, expensive though it may be. See here.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
0

How can I convert vector of floats into a char*?

Here is one way to reinterpret the array of floating point numbers as bytes:

char *ptr = reinterpret_cast<char*>(id_list.data());

Which does exactly what your cast did except it doesn't rely on a C style cast.


but dump_string.c_str() returns empty

This is because dump_string happens to contain an empty null terminated string at the beginning.


I'm expecting to get all values concatenated into a one, long string, ie.:

0,0,0,0,0,1.77636e-15,2.35099e-38,-7.10543e-15,3.06107e-38........

You expectation is misguided. Reinterpreting bytes of floating point numbers is a separate thing from serialising them to readable text. If this is the output you want, then reinterpretation is not the operation that you need.

You can use for example a string stream to convert floating point numbers to text.

eerorika
  • 232,697
  • 12
  • 197
  • 326