2

I am coding with c++/cli and I am trying to assign a string from a textbox to an unsigned char array. I have already done the conversion from String^ to std::string.

I know that this is possible

    unsigned char test[] = "abcde";

However, I am trying to pass the string variable into the array. The string variable below is for demonstration purposes. At the same time, I would not know the constant length value for the array

    string str = "abcde";
    unsigned char test[] = str.c_str();

I would require for the type to be unsigned char [6]

enter image description here

Hope someone can find a workaround for this. Thanks

unsigned char [6]

2

2 Answers 2

5

The standard way:

#include <vector>
#include <string>

std::vector<unsigned char> to_vector(std::string const& str)
{
    // don't forget the trailing 0...
    return std::vector<unsigned char>(str.data(), str.data() + str.length() + 1);
}

int main()
{
    std::string str = "abcde";
    
    auto v = to_vector(str);
}

A way that uses variable-length array extensions, available on some compilers:

#include <algorithm>
#include <string>

int main()
{
    std::string str = "abcde";
    
    unsigned char v[str.length() + 1];
    std::copy(str.data(), str.data() + str.length() + 1, v);
}

But note:

main.cpp:14:37: warning: ISO C++ forbids variable length array 'v' [-Wvla]
     unsigned char v[str.length() + 1];
                                     ^

... and here's another way which ensures that we're using a reference to an array. Note that the reference is only valid in the current thread, and only until the next call to to_array(). But note that this is all un-necessary.

#include <vector>
#include <string>
#include <iostream>

unsigned char (& to_array(std::string const& str))[] 
{
    static thread_local std::vector<unsigned char> result;
    result.assign(str.data(), str.data() + str.length() + 1);
    return reinterpret_cast<unsigned char (&)[]>(*result.data());
}

extern "C" void foo(unsigned char p[]) { }

int main()
{
    std::string str = "abcde";

    unsigned char (&v)[] = to_array(str);
    foo(v);  // ok
    foo(reinterpret_cast<unsigned char*>(str.data())); // also ok!
    
}
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for your help, however I need v to be of unsigned char[ ] type
@spn161 why do you think it needs to be of that type?
I'm calling a function from a library which requires that variable to be of that type
@spn161 That doesn't mean you need to create a new array. You can almost certainly give it a pointer to the std::string's buffer (a char*), safely casted to unsigned char* (though be careful to read what this library function does and ensure it's compatible with the constraints placed upon you by std::string). Have you explored this option?
@spn161 added another option. But... really I think you need to check whether the library really does need a reference to an array.
-2

What you essentially want to do is find the address of the "abcde" and pass it to an unsigned char* as a pointer. Then you could access it as an array without a problem.

Luckily if you look at str.c_str() you will see that it already returns a pointer (An address of the abcde). So all you have to do is save it to a variable. Example here:

string str = "abcde";
unsigned char* test = (unsigned char*)str.c_str();

You can work with it as an array without a problem.

for (int i = 0; i < str.size(); i++)
    cout << test[i];

If you want to copy the string, you can do it using the following

unsigned char* test = (unsigned char*)malloc(str.size());
memcpy(test, str.c_str(), str.size());

What we do is allocate memory space where we can copy the the content of the string using malloc. Then we use memcpy to copy to content from address returned by str.c_str() (Which contains the "abcde") and copy it to the address of the newly allocated space we created before using malloc.

8 Comments

You probably would rather make a copy of the string, because the pointer returned by c_str() may be invalidated later when calling methods of str.
That is up to the programmer. If you use the variables inside the scope, it should not be invalidated. If you use them outside the scope, you can use memcpy to get around that.
c_str returns a const-qualified pointer. As of C++17, data returns a non-const-qualified pointer, which feels more appropriate here. And there's no reason to use malloc here, is there? It doesn't offer any advantages in this case over new and at least one distinct disadvantage: malloc makes it more difficult to use the result with the standard library's smart pointer types.
There is no difference in this very specific case between new and malloc. new/delete call the constructor/destructor; new is type safe, malloc is not; new can be overridden by a class. We are not working with classes here but primitives. and the type safety issue is really tiny here (normally you have to cast the void* returned by malloc to the right pointer type to assign it to a typed pointer variable, which may be annoying, but far from "unsafe"). And for the sake of simplicity, i used c_str(), as the result is same and less questions are asked.
If we were to put a breakpoint after your first solution, it returns an unsigned char * under the Type header under the Autos tab. I would need an unsigned char [6] instead as displayed by using the line unsigned char test[] = "abcde"; I would need to call in the test variable in a function. Many Thanks
|

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.