I have a function which is expecting a string, I was wanting to concatenate const char * to a string to be returned.
Here is example code to help illustrate this scenario:
void TMain::SomeMethod(std::vector<std::string>* p)
{
p->push_back(TAnotherClass::Cchar1 + "/" + TAnotherClass::Cchar2);
}
and here is the other class these are from:
class TAnotherClass
{
public:
static const char * Cchar1;
static const char * Cchar2;
};
const char * TAnotherClass::Cchar1 = "Home";
const char * TAnotherClass::Cchar2 = "user";
im getting the following error:
invalid operands of types 'const char*' and 'const char*' to binary operator +
Why is this not valid? please help
char const* cannot be used with + operator, as the error says.
What you need to do is this:
p->push_back(std::string(TAnotherClass::Cchar1) + "/" + TAnotherClass::Cchar2);
//^^^^^^^^^^^^ notice this
It creates a temporary object of type std::string, then you can use + with it. It concatenates the strings, creating temporaries all the way, and finally passes the final string to push_back.
Apart from that, as #Konrad noted in the comment, don’t pass a pointer into the method, use a reference instead, as:
void TMain::SomeMethod(std::vector<std::string> & p) //<-- note &
{
p.push_back(std::string(TAnotherClass::Cchar1)+"/"+TAnotherClass::Cchar2);
}
Because you're trying to add two pointers. The + operator can't be overridden for char*.
You can do this:
p->push_back(std::string(TAnotherClass::Cchar1) + "/" + TAnotherClass::Cchar2);
Keep in mind the fact that std::string(...) as used above is a C-style cast using functional notation. It's equivalent, in this case, to static_cast<std::string>(...).
Whether you allow function style casts in your code is up to you. Some policies are against ALL C-style casts. In my previous workplace this particular use of them was allowed, but no other.
Related
I was trying to make a setter for name in some class, but I'm having a problem with this.
void Cats::setName(char* s) {
if (this->name != NULL) {
delete[] name;
name = new char[strlen(s + 1)];
strcpy_s(s, strlen(name) + 1, name);
}
}
That's the setter, and I can't write any name for any Cat of mine.
Cats::Cats() {
setName("NoName"); <----- problem here and in other constructors also.
setWeight(0.6);
setAge(0);
}
argument of type "const char *" is incompatible with parameter of type "char *"
How can I make this happen? What am I missing? An explanation would be great.
"NoName" is a const char*. The const means that no one can modify the characters in it. Your function takes a char*, which is a mutable character array. You can't pass constant data to a function whose signature requires mutable data. If you really don't intend to modify the array, then take a const char*
void Cats::setName(const char* s)
or, even better, as Bathesheba pointed out, use std::string, which will manage the memory for you.
void Cats::setName(std::string s)
Using new and delete directly, in modern C++, is generally a code smell and should be avoided. We have std::string for strings, std::array and std::vector for arrays, and std::unique_ptr and std::shared_ptr for owned heap memory. Let your types speak for themselves, and the compiler will take care of memory management for you.
For starters this statement in the setter
name = new char[strlen(s + 1)];
is incorrect. It should look like
name = new char[strlen(s ) + 1];
Nevertheless the function should be defined at least the following way
void Cats::setName( const char *s ) {
if (this->name != nullptr) delete[] name;
size_t n = strlen( s ) + 1;
name = new char[n];
strcpy_s(s, n, name);
}
You are calling the function passing to it a string literal
Cats::Cats() {
setName("NoName"); <----- problem here and in other constructors also.
setWeight(0.6);
setAge(0);
}
In C++ opposite to C string literals have types of constant character arrays. Thus the parameter of the setter shall be declared like
const char *s
and the constructor should look at least like
Cats::Cats() : name( nullptr ) {
setName("NoName");
setWeight(0.6);
setAge(0);
}
provided that in the class definition the data member name is not initialized explicitly with nullptr.
I am trying to make a new const char* b by adding a new string "hello" to original const char* a:
const char* a = some_code_here;
const char* b = (a + "_hello").c_str();
And the error I get is:
error: invalid operands of types const char* and const char [6] to binary operator+
Is there anything wrong I am doing?
Switch to strings, that is std::string.
Repeat after me, forget about using char or C-style strings.
As you have demonstrated, this is one of many issues.
Did I say switch to std::string?
Your char * is a pointer. Nothing more, nothing less, a pointer. A pointer to a single char; not a structure. The char data type doesn't have methods.
Switch to std::string.
You can add (concatenate) std::string.
Switch to std::string.
The std::string has the c_str() method. Don't use unless you understand the consequences; completely.
You can't arbitrarily add const char* in C++. These objects are just pointers to a contiguous section of memory, so adding them doesn't make sense. Instead, you should use the std::string class:
std::string a = "something";
std::string b = a + "_hello";
The standard C library functions strtof and strtod have the following signatures:
float strtof(const char *str, char **endptr);
double strtod(const char *str, char **endptr);
They each decompose the input string, str, into three parts:
An initial, possibly-empty, sequence of whitespace
A "subject sequence" of characters that represent a floating-point value
A "trailing sequence" of characters that are unrecognized (and which do not affect the conversion).
If endptr is not NULL, then *endptr is set to a pointer to the character immediately following the last character that was part of the conversion (in other words, the start of the trailing sequence).
I am wondering: why is endptr, then, a pointer to a non-const char pointer? Isn't *endptr a pointer into a const char string (the input string str)?
The reason is simply usability. char * can automatically convert to const char *, but char ** cannot automatically convert to const char **, and the actual type of the pointer (whose address gets passed) used by the calling function is much more likely to be char * than const char *. The reason this automatic conversion is not possible is that there is a non-obvious way it can be used to remove the const qualification through several steps, where each step looks perfectly valid and correct in and of itself. Steve Jessop has provided an example in the comments:
if you could automatically convert char** to const char**, then you could do
char *p;
char **pp = &p;
const char** cp = pp;
*cp = (const char*) "hello";
*p = 'j';.
For const-safety, one of those lines must be illegal, and since the others are all perfectly normal operations, it has to be cp = pp;
A much better approach would have been to define these functions to take void * in place of char **. Both char ** and const char ** can automatically convert to void *. (The stricken text was actually a very bad idea; not only does it prevent any type checking, but C actually forbids objects of type char * and const char * to alias.) Alternatively, these functions could have taken a ptrdiff_t * or size_t * argument in which to store the offset of the end, rather than a pointer to it. This is often more useful anyway.
If you like the latter approach, feel free to write such a wrapper around the standard library functions and call your wrapper, so as to keep the rest of your code const-clean and cast-free.
Usability. The str argument is marked as const because the input argument will not be modified. If endptr were const, then that would instruct the caller that he should not change data referenced from endptr on output, but often the caller wants to do just that. For example, I may want to null-terminate a string after getting the float out of it:
float StrToFAndTerminate(char *Text) {
float Num;
Num = strtof(Text, &Text);
*Text = '\0';
return Num;
}
Perfectly reasonable thing to want to do, in some circumstances. Doesn't work if endptr is of type const char **.
Ideally, endptr should be of const-ness matching the actual input const-ness of str, but C provides no way of indicating this through its syntax. (Anders Hejlsberg talks about this when describing why const was left out of C#.)
I have two string declarations:
killerName
victimName
I need to convert these two string values to const* char.
Example of how I use my method:
if (killer.IsRealPlayer) {
killerName = killer.GetName(); -- need to convert to const* char
victimName = victim.GetName(); -- need to convert to const* char
Notice(killerName + "has slain:" + victimName, killer.GetMapIndex(), false);
}
Some error I receive:
Error 111 error C2664: 'Notice' : cannot convert parameter 1 from 'std::basic_string<_Elem,_Traits,_Ax>' to 'const char */
It seems that function Notice have the first parameter of type const char * However the expression passed to it as the first argument
killerName + "has slain:" + victimName
has type std::string
Simply call the function the following way
Notice( ( killerName + "has slain:" + victimName ).c_str(), killer.GetMapIndex(), false);
Notice(string(killerName + "has slain:" + victimName).c_str(), killer.GetMapIndex(), false);
std::string::c_str() gives the const char* to the buffer. I think that's what you want.
See: http://www.cplusplus.com/reference/string/string/c_str/
As others already wrote, the result of killerName + "has slain:" + victimName is of type std::string. So, if your Notice() function expects a const char* as first parameter, you must convert from std::string to const char*, and since there is no implicit conversion defined for std::string, you must call the std::string::c_str() method:
Notice((killerName + "has slain:" + victimName).c_str(), killer.GetMapIndex(), false);
However, I'd like to ask: why do you have Notice() expecting a const char* as first parameter?
Would it be better to just use const std::string&? In general, in modern C++ code, you may want to use string classes like std::string instead of raw char* pointers.
(Another option would be to have two overloads of Notice(): one expecting a const std::string& as first parameter, and the other one expecting a const char*, if for some reason the const char* version does make sense in your particular context; this double overload pattern is used e.g. in the std::fstream constructor.)
I am converting a project written in C++ for windows. Everything is going fine (meaning I clearly see what needs to be changed to make things proper C++) until I hit this, which is my own little routine to find a keyword in along string of keyword=value pairs:
bool GetParameter(const char * haystack, const char *needle) {
char *search, *start;
int len;
len = strlen(needle) + 4; // make my own copy so I can upper case it...
search = (char *) calloc(1,len);
if (search == NULL) return false;
strcpy(search,needle);
strupr(search);
strcat(search,"="); // now it is 'KEYWORD='
start = strstr(haystack,search); <---- ERROR from compiler
g++ is telling me "Invalid conversion from const char * to char * "
(the precise location of the complaint is the argument variable 'search' )
But it would appear that g++ is dyslexic. Because I am actually going the other way. I am passing in a char * to a const char *
(so the conversion is "from char * to const char *" )
The strstr prototype is char * strstr(const char *, const char *)
There is no danger here. Nothing in any const char * is being modified.
Why is it telling me this?
What can I do to fix it?
Thanks for any help.
The background to the problem is that C defines the function strstr as:
char* strstr(const char*, const char*);
This is because C doesn't allow overloaded functions, so to allow you to use strstr with both const and non-const strings it accepts const strings and returns non-const. This introduces a weakness in C's already fragile type-system, because it removes const-ness from a string. It is the C programmer's job to not attempt to write via a pointer returned from strstr if you pased in non-modifiable strings.
In C++ the function is replaced by a pair of overloaded functions, the standard says:
7. The function signature strstr(const char*, const char*) shall be replaced by the two declarations:
const char* strstr(const char* s1, const char* s2);
char* strstr( char* s1, const char* s2);
both of which shall have the same behavior as the original declaration.
This is type-safe, if you pass in a const string you get back a const string. Your code passes in a const string, so G++ is following the standard by returning a const string. You get what you asked for.
Your code compiles on Windows because apparently the standard library you were using on Windows doesn't provide the overloads and only provides the C version. That allows you to pass in const strings and get back a non-const string. G++ provides the C++ versions, as required by the standard. The error is telling you that you're trying to convert the const return value to a non-const char*. The solution is the assign the return value to a const char* instead, which is portable and compiles everywhere.
Error is not regarding the arguments to stsrtr. Compiler is complaining about the conversion of the 'const char *' returned by strstr. You can't assign it to *start which is just char *
You can try one of these:
const char *start;
or
string start(strstr(haystack,search));
Although declaring start as const char* might suffice, what seems more appropriate to me is to use std::string objects instead:
#include <string>
#include <cctype>
#include <algorithm>
bool GetParameter(const char * haystack, const char *needle) {
std::string hstr(haystack), nstr(needle);
std::transform(nstr.begin(), nstr.end(),nstr.begin(), ::toupper);
nstr += "=";
std::size_t found = hstr.find(nstr);
if (found != std::string::npos) {
... // "NEEDLE=" found
}
else {
...
}
...
}
The conversion it is complaining about is from strstr(...) to start. Change the declaration of start to const char* start;
you can use such like:
start = const_cast<char *>(strstr( haystack, static_cast<const char *>(search) ));