Given this code:
void group::build(int size, std::string *ips){
/*Build the LL after receiving the
member list from bootstrap*/
head = new member("head");
member *temp1,*temp2;
temp1 = new member(ips[0].data()); // error here
// ....
}
member::member(char *ip){
strcpy_s(this->ip_addr,sizeof(ip),ip);
this->next = NULL;
this->previous = NULL;
}
And a pointer to string defined as:
std::string *ips;
I want to initialize the array, ips with strings but when I try to get the char data from any array member I get the error:
cannot convert parameter from const char * to char *
Why?
The function you are calling expects a pointer to a modifiable buffer, char*. You are passing a pointer to a non-modifiable buffer, const char*.
Since your member function does not modify its input you should change its declaration to receive const char*.
member::member(const char *ip)
Change line
member::member(char *ip)
to
member::member(const char *ip)
and, i'm not sure about your usage of strcpy_s
Well, data() returns a const char*, hence the error. You should change member::member to receive a const char*, as you're copying its value anyway.
Also, note that sizeof(ip) is equal to sizeof(char*), which is just a size of a pointer. You should pass the size of the this->ip_addr buffer instead.
Because member::member is defined to take char * as a parameter, and string.data() is giving a const char * as a value (since it is returning a reference to its own internal memory). You could use const_cast or change member::member method signature.
Change this:
member::member(char *ip)
to this
member::member(const char *ip)
That is, you've to change the parameter type of the constructor.
Alternatively, which is also a better solution, simply make the parameter const std::string &:
member::member(const std::string &)
This approach lets use better interfaces provided by std::string class. These interfaces are much more better than C-string interfaces such as strcpy, strlen, strcat etc.
std::string data has this signature
const char* data() const;
You are trying to call the member c'tor with which expects char * so here is your error.
Change this : member::member(char *ip)
To this : member::member(const char *ip)
Related
I am expecting my function to work just the same as the function "strchr" I am using from the cstring / string.h library.
I understand that I cannot cast a " const char* " variable / array to " char* ". Yet, how is the predefined "strchr" function able to be passed both "const char" and "char" data type arrays and work just fine ? How could I change mine so that it works, too ?
char* my_strchr(char *place_to_find, char what_to_find)
{
for(int i=0;place_to_find[i];i++)
if(what_to_find==place_to_find[i]) return place_to_find+i;
return NULL;
}
...
int main()
{
const char vocals1[]="AEIOUaeiou";
char vocals2[]="AEIOUaeiou";
cout<<strchr(vocals1,'e');
cout<<strchr(vocals2,'e');
cout<<my_strchr(vocals1,'e');
cout<<my_strchr(vocals2,'e');
return 0;
}
As you could probably already tell, my third cout<< does not work.
I am looking for a way to change my function ( I am guessing the first parameter should somehow be typecast ).
How can I make my strchr function take both 'const char' and 'char' arrays as first parameter?
You could change the argument to be const char*. That would allow passing both pointers to char as well as const char.
However, you return a non-const pointer to that array, which you shouldn't do if the pointer is to a const array. So, when passing a const char*, your function should also return const char*
Yet, how is the predefined "strchr" function able to be passed both "const char" and "char" data type arrays and work just fine ?
There are two predefined std::strchr functions. One that accepts and returns char* and another that accepts and returns const char*:
const char* strchr(const char* str, int ch);
char* strchr( char* str, int ch);
If you would wish to return char* in case of char* argument, you need to have a different function for each case, like the standard library has. You can use an overload like the standard library does, or you can use a function template to generate both variations without repetition:
template<class Char>
Char* my_strchr(Char *place_to_find, char what_to_find)
Note that the C version of the function is declared char *strchr(const char *str, int ch). This makes the single function usable in both cases, but is unsafe, since the type system won't be able to prevent the user of the function from modifying though the returned non-const pointer even when a const array was passed as an argument.
Make two overloads, the way it is done in the C++ standard library:
char* my_strchr( char *place_to_find, char what_to_find)
const char* my_strchr(const char *place_to_find, char what_to_find)
Even though in your case only the second overload would be sufficient (demo) you would not be able to support an important use case, when you need to find a character and then replace it:
// This would not work with only one overload:
char *ptr = my_strchr(vocals2,'e');
if (ptr) {
*ptr = 'E';
}
That is why the non-const overload is necessary.
Note: I assume that you are doing this as a learning exercise, because C-style string functions are no longer necessary for new development, having been replaced with std::string functionality.
Short answer: make the type of the place_to_find const char*
The reason for your error is that you cannot implicitly convert a pointer to a const char to a pointer to a non-const char. If you could, then you could change the char that the pointer points to and it would defeat the purpose of having it a const char type in the first place.
You can implicitly convert a pointer to a non-const char to a pointer to a const char because it does not remove any restrictions.
L.E.: Also, the return value should be a const char*, because again, if you don't, it would remove the const restriction which is not allowed. The only problem with that is that you would not be able to modify the array through the pointer returned. If you also want that, then you would have to overload the method on both char and const char.
my private members in my class:
const char arr1[];
const char arr2[];
my constructor:
className(const char a[], const char b[])
:arr1(a), arr2(b)
{
}
The error message from console window is:
In constructor className::className(const char*, const char*):
error: incompatible types in assignment of const char* to const char [0]
Please help, what am I doing wrong?
On a side note, I found a solution...
I used pointers as my private member vars, so *arr1 and *arr2 and that worked. :)
You are declaring your members as const char arr1[]. I am suprised that the compiler is even allowing you to make that declaration, as it should have had a fixed size in that form (like const char arr1[512]).
Depending on what you want to do, you'll either have to:
declare your members as const char* arr1 -- note that this will not copy the strings; or
use a string class (like std::string) and/or allocate memory for the class member, and copy
First of all, you compiler should already choke on declarations of the members:
const char arr1[];
const char arr2[];
That's illegal C++, arrays as class members need to have their size spelled out.
Second, const char p[], when used in function declarations, literaly means const char* p. That is, a pointer to constant char. Arrays are not pointers, don't confuse the two. They decay to a pointer to their first element when passed to functions, though.
assume I have the following function
int watchVar(const char* var, const char* descriptor,
Color (*colorfunc)(const char* var) = yellowColorFunc)
with
Color yellowColorFunc(const void* var){
return Color::yellow();
}
I want to overload watchVar to accept functions whos parameters are char, int, float, etc, but do not want to create a default color function for each type.
g++ gives this error:
xpcc::glcd::Color (*)(const char*)' has type 'xpcc::glcd::Color(const void*)
Is there another way besides declaring colorfunc to take a void pointer and forcing the caller to cast the argument later himself?
Thanks
the function pointer is declared const char * but the yellowColorFunc is declared const void *
Your problem is that your declaring a function pointer taking a const char * but yellowColorFun takes a const void *. If c++11 is available you can use std::function like so:
auto colorFunc = std::function<int(const char *,const char *,std::function<Color(const char*)>)>();
You said in a comment that you wanted to use the function for int,float and others, what your should do in that situation is use a templated function, you really don't wanna use void*'s in c++ very often.
I have an API for the functions, say:
void func (const char** s,const size_t* ss);
I.e. the function gets the const array of null terminated strings [s] and their sizes [ss].
I get the strings during run-time and not aware about their amount.
What I thought to do is to define vector<char*> vS - insert the strings to it and define vector<size_t> vSS - insert the strings sizes to it.
Eventually I should transfer vector<char*> vS to const char**
and vector<size_t> vSS to const size_t*.
I am aware that exists a trick &vS[0] / &vSS[0].The problem is that the above generates char** and size_t* ss respectively.But I am missing const.
How the issue could be solved?
If you are able to fix the API to make it const-correct, then change it to:
void func (const char* const* s,const size_t* ss);
Otherwise, if you don't need to modify the string contents via the vector, then change the vector to:
vector<const char*> vS;
Otherwise, you'll need to do a const_cast and trust the API not to modify anything:
func(const_cast<const char**>(&vS[0]), &vSS[0]);
(If you're interested, the problem with passing char** to a function taking const char** is that the function could modify one of the pointers to point to a const char. The caller would then have a non-const pointer to that const object, with nothing to prevent him trying to modify it. Boom! Undefined behaviour.)
If you are passing params to function (and not trying to pass results back in the arguments), than non-const'ness is not a problem: you may use char * anywhere where cont char * is required.
But you have problems with double pointers - const char **, etc. They are not converted implicitly because it can lead to const violation. You can read an explanation in C++ FAQ Light.
In your case you can just create a vector<const char*>, as #aschepler said.
BTW, const char** is not "const pointer to pointer to char", but "pointer to const pointer to char", you have to add another const if you want to ensure that function doesn't change the outer pointer contents. const char * const * or char const * const *, which is the same - pointer to const pointer to const characters.
(BTW, reading right-to-left relly helps when dealing with multiple consts: try it with the last expression from the previous paragraph. And yes, you can add another const at the end of this exprssion to get "const pointer to const pointer to const char").
Just declare vS as
vector<const char*> vS;
Then &vS[0] is const char**. And size_t* can implicitly convert to const size_t*.
(By the way, func probably should be
void func(const char* const* s, const size_t* ss);
but the above will work either way.)
I was reading though this: const char * const versus const char *?
in string.h, strlen is defined as:
size_t strlen ( const char * str );
If I understand this correctly, strlen expects a pointer to a char that is const. Shouldn't it be:
size_t strlen ( const char* const str );
This would make sure that strlen cannot modify the pointer to point to a different pointer ?
Or, is this the case:
Since str pointer will be passed by value to strlen, any changes to this pointer in the function will not change the source pointer, and hence it's okay..
??
If you really read that discussion, you should understand that the second const has no effect on the external behavior of the function. For you, the user of strlen, It simply doesn't make any difference whether it is declared with const char * or const char *const parameter. As you correctly noted, any modifications that strlen might do to the pointer are only affecting the internal, local copy of the pointer inside strlen. Your argument pointer that you pass to strlen will remain unchanged regardless of whether the parameter is declared with second const or not. (Your argument pointer doesn't even have to be an lvalue.)
The second const will only have effect on the internal behavior of the local parameter variable inside the function, preventing the authors of strlen from modifying that local variable. Whether they want to restrict themselves in that way or not is, informally speaking, their own business. It doesn't concern the users of strlen in any way.
In fact, since top-level const qualifiers have no effect on function type, it is typically possible to declare a function with const char * parameter and then define it with const char *const parameter. The compiler (linker) will still treat these declarations as "matching". It means that if the library authors so desired, they could actually define strlen with const char *const parameter. They are simply not telling you about that, since this is effectively an implementation detail or strlen, i.e. something you don't need to know.
Since str pointer will be passed by value to strlen, any changes to this pointer in the function will not change the source pointer, and hence it's okay..
Yes. It's only a restriction for the functions interior handling.
This would make sure that strlen cannot modify the pointer to point to a different pointer ?
It's not needed, the pointer is passed by value.
size_t strlen ( const char* const str );
This would make sure that strlen cannot modify the pointer to point to a different pointer ?
You explained the reason yourself : strlen cannot modify the pointer....
It unnecessarily imposes restriction on the parameter, which could be used to compute the length while modifying the pointer itself, as:
size_t len = 0;
while(*str)
{
++len;
++str; //error if `const char *const str` is used!
}
See the implementation of strlen() in glibc which modifies the pointer itself: by assigning it to modifiable pointer type.
See also OpenBSD lib implemtation:
size_t strlen(const char *str)
{
const char *s;
for (s = str; *s; ++s)
;
return (s - str);
}
Here s=str would be error if str is const char * const type!