I have following scenario:
struct MyStruct
{
char name[25];
char address[12];
}
Somewhere::SomeMethod(std::shared_ptr<SomeArgumentClass> args)
{
// GetName() and GetAddress() both return std::strings
::MyStruct newValue = {args->GetName(), args->GetAddress()};
// add newValue to some structure that needs to have chars
}
Error:
error C2440: 'initializing' : cannot convert from 'std::string' to 'char'
error C2440: 'initializing' : cannot convert from 'std::string' to 'char'
I am not able to get my std::string converted to a char.
Thanks a lot!
Firstly, your terminology is incorrect. You don't want to convert to char, which is a single character. I realise that the error message claims you're trying to convert to char, but that's because your incorrect code has confused the compiler into thinking you're trying to initialise individual elements of the array name. Be wary of the specifics of an error message when you write the wrong code, because the compiler cannot read your mind — it can only go off of what you've written!
In reality you want to copy the characters inside your std::string, into the array of char, that is your member.
Like so:
Somewhere::SomeMethod(std::shared_ptr<SomeArgumentClass> args)
{
const auto& name = args->GetName();
const auto& address = args->GetAddress();
::MyStruct newValue;
std::copy(std::begin(name), std::end(name), &newValue.name[0]);
std::copy(std::begin(address), std::end(address), &newValue.address[0]);
// add newValue to some structure that needs to have chars
}
But you need to add bounds checking too. To do that, roughly I might consider replacing each std::copy call with something like:
std::copy_n(
&name[0],
std::min(name.size(), sizeof(newValue.name)),
&newValue.name[0]
);
You'll also need some null termination depending on how many characters were copied.
Generally though the salient point is that you need to actually copy those characters because there is no one-step way to do it. It stems in part from how arrays can't be assigned-to, but also from the fact that their dimensions are part of the type which makes things more complicated.
If this seems like a pain in the arse, that's because it is — ideally you would stick with std::string across the board because it's far superior, and was specifically introduced to make it easier to handle arrays of char. You can still pass a const char* (or char*!) pointing to the string's data into a C API. Of course if ::MyStruct itself is a third-party C type, you have no choice but to do it the hard way.
Related
I tried to use a character Pointer go throw string character (iterate) but I found i can not say the below:
string Name = "Hello";
char *ch = Name;
like the previous statements i am getting error during execution.
However when I am doing like that:
char *ch = "Hello";
the program running without throwing any exception.
Why is that?
I have recently encountered similar problem and the simplest answer is that std::string is a different type from char*, more precisely std::string is an object which contains some characters (your text) and few methods, which allow you to do multiple operations with your text. You can imagine creating a class Integer for storing the value, but also a method allowing you to square and cube the number which is stored in the Ingerer class. Even though they could store the same numerical value, you will not be able to compare them (unless you overload the operator==), as their types are different.
If you wish to use the code you provided, you need to rewrite the second line as
const char *ch = Name.c_str();
it is allowed because std::string contains a method c_str() which "casts" itself to const char*. If you want to learn more about strings, be sure to visit C++ reference about strings.
I am now using C++ to program a robot using PROS. Pros has a print function, which is taking in a const char*. Now, I'm using lvgl to create my own screen, and I want to replicate the print function. Like the printf() functions, I want it to include variadic params to do the %d effect (so it converts all the %? to the corresponding values). The problem now is about the conversions between functions. I wanted to make a convert function to convert a string and the variadic params into a complete string. I need to input is a string which is like "hey" and I'm unsure what the type name should be. I need to be able to get size, search in it for %ds but I need the function to return a const char* to pass onto the lvgl to pring on the screen. I am having a bad time trying to convert a string into an const char* for the out put of the convert function.
Also, I tried using the input type as a char*, and when I input a string like "hello" is says a error [ISO C++11 does not allow conversion from string literal to 'char ' [-Wwritable-strings]]. But instead, when is use a const char, the error disappears. Anyone knows why?
Thanks everyone for your kind help!
char* and const char* are two flavours of the same thing: C-style strings. These are a series of bytes with a NUL terminator (0-byte). To use these you need to use the C library functions like strdup, strlen and so on. These must be used very carefully as missing out on the terminator, which is all too easy to do by accident, can result in huge problems in the form of buffer-overflow bugs.
std::string is how strings are represented in C++. They're a lot more capable, they can support "wide" characters, or variable length character sets like UTF-8. As there's no NUL terminator in these, they can't be overflowed and are really quite safe to use. Memory allocation is handled by the Standard Library without you having to pay much attention to it.
You can convert back and forth as necessary, but it's usually best to stick to std::string inside of C++ as much as you can.
To convert from C++ to C:
std::string cppstring("test");
const char* c_string = cppstring.c_str();
To convert from C to C++:
const char* c_string = "test";
std::string cppstring(c_string);
Note you can convert from char* (mutable) to const char* (immutable) but not in reverse. Sometimes things are flagged const because you're not allowed to change them, or that changing them would cause huge problems.
You don't really have to "convert" though, you just use char* as you would const char*.
std::string A = "hello"; //< assignment from char* to string
const char* const B = A.c_str(); //< call c_str() method to access the C string
std::string C = B; //< assignment works just fine (with allocation though!)
printf("%s", C.c_str()); //< pass to printf via %s & c_str() method
Everything was working fine just five minutes ago when I tapped f5 and got 102 errors:
error: C2440: 'initializing' : cannot convert from 'const char [17]' to 'char *'
Conversion from string literal loses const qualifier (see /Zc:strictStrings)
That specific one is at line 30:
char* hexchars = "0123456789ABCDEF";
I haven't touched the file the errors are in for at least a week. I'd normally say I accidentally changed something in the compile args or something, but I haven't opened settings since much before it started erroring.
Any ideas? I must have absentmindedly changed some setting but I really can't remember thinking "uh oh what did I just do?"
When you use code like this
char *astring2 = "some letters";
C++ (and C) puts that into read only memory. You can not modify the contents of a char pointer initialized with a literal even if it is not const.
Also you can not change the address of the pointer because it will cause a memory leak due to the rule above.
This, however, does not follow that rule UNLESS you make it const:
char astring[] = "some letters that can be changed";
char *ptrToString = astring; //work
astring2 = astring //not work
String literals are of type char const[N] since C++ was first standardized. At this point C didn't support const and a lot of code assigned string literals to char*. As a result a special rule was present in C++ which allowed initialization of char* from string literals. This rule was immediately deprecated.
C99 introduced a const keyword, too. When C++11 was standardized the deprecated rules was pulled and it is no illegal to initialize a char* from a string literal as it should have been right from the stand. The expectation was that C++ compilers warned about the deprecated assignment since years (and all vendors stated they did), i.e., users had years of lead-time to fix their code.
The obvious fix is to initialize a char const* instead of a char* from a string literal.
If you really need a pointer to a mutable array of chars you can create it and get it initialized using
char array[] = "string literal";
This gives the error: cannot convert from 'const char *' to 'char *'.
class Mock
{
public:
...
static void func(char **result)
{
*result = (resultsI++)->c_str();
}
static std::vector<std::string> results;
static std::vector<std::string>::iterator resultsI;
};
std::vector<std::string> Mock::results;
std::vector<std::string>::iterator Mock::resultsI;
How can I validly get rid of this error without changing the interface to the function func? The implementer of this interface:
void (func*)(char **result)
forgot to use const char** in the signature. I can't change it.
Remember this is a mock and I'm only used in my unit tests.
Try:
*result = &(*resultsI++)[0];
Although this isn't guaranteed to work prior to C++11 it is known to be OK on most or all current compilers.
The danger is that if the function tries to change the length of the string, you could get some nasty errors. Changing individual characters should be OK.
In test code, and if you are certain that the user of the interface isn't going to mutate the char*, maybe you could use a const_cast?
That assumes the caller doesn't take ownership of the char *; if that is the case, then you should make a copy.
If you're absolutely certain that the interface function will not modify the string, you can use
*result = const_cast<char *>((resultsI++)->c_str());
to remove constness.
Otherwise, another option is to switch from using std::vector<std::string> to std::vector<std::vector<char>> but then you'll have to make sure you properly null terminate the strings.
I have this code and it's compiling correctly :
char classfname[512] = "classifiers/cabmodel_VOC05motorbikes.xml";
strcpy(classfname,argv[i]);
but when I tried to define an array contains strings from the same size of the above size
and with your all help it didn't work !
std::vector<std::string> classfname = {
"classifiers/cabmodel_VOC05motorbikes.xml",
"classifiers/cabmodel_interm_nst100_VOC06person01train5_orienthistmod.xml" ,
"classifiers/cabmodel_interm_nst40_VOC06cat01train5_trainval_orienthistmod_nopert_facereg.xml",
"classifiers/cabmodel_interm_nst100_VOC06bicycle01train5_trainval_orienthistmod.xml",
"classifiers/cabmodel_VOC06carside.xml",
"classifiers/cabmodel_interm_nst100_VOC06horse01train5_trainval_orienthistmod_randsel0100.xml"
};
char *classfname[6]={-----}
std::vector<std::string> classfname;
classfname.push_back(",,,");
with the function strcpy(classfname,argv[i]);
I got the error:
Error 2 error C2664: 'strcpy' : cannot convert parameter 1 from 'std::string' to 'char *
Converting string literals to a char* is no longer allowed, since it was never safe. Instead, make an array of const char*. (Although I'm not 100% positive this is the cause of your error, but your code doesn't match your error well, I think you changed something to put it on SO). std::string has a constructor from const char*, so this should work fine.
Also, it's good to note that (const::std string & is not right, so we know you changed stuff when you posted it here. Don't do that, or we can't help you much at all. It should be (const std::string&.
Also, MrC64 notes that you should use RAII instead of raw arrays and pointers. It's easier to use, and harder to mess up.
std::vector<std::string> classfname = {
"classifiers/cabmodel_VOC05motorbikes.xml",
"classifiers/cabmodel_interm_nst100_VOC06person01train5_orienthistmod.xml" ,
"classifiers/cabmodel_interm_nst40_VOC06cat01train5_trainval_orienthistmod_nopert_facereg.xml",
"classifiers/cabmodel_interm_nst100_VOC06bicycle01train5_trainval_orienthistmod.xml",
"classifiers/cabmodel_VOC06carside.xml",
"classifiers/cabmodel_interm_nst100_VOC06horse01train5_trainval_orienthistmod_randsel0100.xml"
};
If your compiler can't handle that syntax yet (many can't), use the code that Mr_C64 suggested.
[EDIT] You have changed your question dramatically to be a completely different question. Generally this is bad, because anyone who comes to this page looking for answers will see that our answers don't match your question anymore. If you have additional questions, you should use the search feature, or make a new question page.
Now your code has a std::vector of std::strings. Treat a std::string like you would an int. Just copy it, or pass it around with no worries. You don't have do use a special function to copy a int, so you don't need a special function to copy a string. Just do std::string newstring = classfname[0]; to get a copy of the string at index 0 in the array classfname.
Your "old" code makes an array of chars initialized to a string literal, and over-rights it with the input from argv[i] The best way to do that code is:
std::string classfname = "classifiers/cabmodel_VOC05motorbikes.xml";
classfname = argv[i];
If you just want to make an array of each of the arguments, that's easy:
int main() {int argc, const char** argv) {
std::vector<std::string> classfname(argv, argv+argc);
One solution is to use const char* like this:
const char *classfname[7]={"classifiers/cabmodel_VOC05motorbikes.xml",
"classifiers/cabmodel_interm_nst100_VOC06person01train5_orienthistmod.xml" ,
"classifiers/cabmodel_interm_nst40_VOC06cat01train5_trainval_orienthistmod_nopert_facereg.xml",
"classifiers/cabmodel_interm_nst100_VOC06bicycle01train5_trainval_orienthistmod.xml",
"classifiers/cabmodel_VOC06carside.xml",
"classifiers/cabmodel_interm_nst100_VOC06horse01train5_trainval_orienthistmod_randsel0100.xml",
};
Also if you want to have a std::vector containing these strings use can initialize it with the following statement:
const std::vector<std::string> classfname_vector(classfname, classfname + 7);
One more thing I noticed is that you declared an array with 7 elements but initialized it only with 6 string literals.
I'd just use std::vector<std::string> instead of a "raw" C array:
#include <string>
#include <vector>
std::vector<std::string> classfname;
classfname.push_back("classifiers/cabmodel_VOC05motorbikes.xml");
classfname.push_back("classifiers/cabmodel_interm_nst100_VOC06person01train5_orienthistmod.xml");
...
std::vector overloads operator[], so your call xmlloadmodel(classfname[i],model); should work.