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.)
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.
This question already has answers here:
Functions with const arguments and Overloading
(3 answers)
Closed 9 years ago.
I am confused why the following code is not producing any error ,because the arguments passed to display are of same type i.e char.Does const really makes difference?
#include<iostream>
using namespace std;
void display(char *p)
{
cout<<p;
}
void display(const char *p)
{
cout<<p;
}
int main()
{
display("Hello");
display("World");
}
EDIT
As per answers,the first display is never called,which is correct and so is the output.
But suppose I do it like :
int main()
{
char *p="Hello";
display(p);//now first display is called.
display("World");
}
Compiler gives a warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings] but then it calls first display.Does it mean that string is now no more taken as constant?
const char* and char * are actually not the same. The later allow for modifying the pointed char, while the first one will prevent that.
Also note that if those were class methods, void display() and void display() const would also be valid overloads. The later would imply that the method must not change the object's state.
Consider this code:
void display(char *s)
{
std::cout << "Display" << std::endl;
}
void display(const char *s)
{
std::cout << "Display with const" << std::endl;
}
int main()
{
char *str = strdup("boap");
const char *str2 = "toto";
/* It is a string literral "bound" as a char *.
Compiler will issue warning, but it still compiles.
Avoid to do that, it's just an exemple */
char *not_safe = "not_safe";
display("llama");
display(str2);
display(str);
display(not_safe);
}
This will print Display with const twice, and then twice Display. See there.
Now, let's see why:
"llama" is a string literal, and then is resolved as a const char *.
str2 is a pointer to a string literal. Since its type is const char*, this also revolves to the const overload.
not_safe is also a pointer to a string literal. However, its type is char *: this is not correct. The memory it points to is read-only, and trying to modifies it will result in a crash. However, the type of the variable is still char *, so this resolve to the non-const overload.
str is a char * pointer, and the string it points to is not read-only. Modifying its content is valid, and since its type is char *, it will resolve to the non-const overload.
The issue is that string literals such as "Hello" and "World" have type const char[6]. This can decay to const char*, but not to char*. So the overload taking const char*,
void display(const char *p);
is the better match. As #JamesKanze points out, it would be possible for a function taking char* to accept a string literal, but attempting to modify the data pointed at would result in undefined behaviour. For this reason, it is unsafe to pass string literals to such functions. With suitable warning settings, GCC produces the following:
warning: deprecated conversion from string constant to ‘char*’
In any case, in the presence of two overloads like the ones you have shown, the one taking const char* wins.
The arguments passed to the two functions are actually not the same.
The first takes a char*: A pointer to a char.
The second takes a const char*: A pointer to a const char.
So you see, the difference here is actually in whether the pointer points to an object which can be changed or not. This is definitely a property on which you want to be able to overload a function.
Whether you can modify an object or not definitely is a useful piece of information depending on which you may want to invoke different behavior! Consider this:
void foo(int * p) { ++(*p); }
void foo(int const * p) { std::cout << *p << '\n'; }
The sizes of the strings "Hello" and "World" are known at compile time and cannot be modified. They are constant, compile-time character arrays.
In C and C++, an array e.g. char a[6] can be referred to using a pointer, i.e. a is actually a char *. Since the arrays for "Hello" and "World" must not be modified at runtime, their type is essentially const char *.
The compiler recognizes this and performs the overload resolution for display correctly, since only one of the functions (display(const char* p)) takes a const char* as an argument. This is why there is no ambiguity in the two functions, and you don't get the error that you expected to get.
"because the arguments passed to display are of same type i.e char."
No here the argument are "const char*". the data type is the but the const qualifier indicate that the literal string you hard coded, is not something that can be change.
"Does const really makes difference?"
Yes the const qualifier make a difference.
in Display(char*) you can update the content of the null-terminate string you passed but not in Display(const char*). That fact allow more optimization by the compiler.
But read that http://www.possibility.com/Cpp/const.html it's a good source to start using const efficiently.
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!
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)
In the following piece of code, to calculate strlen,
int s(const char* str)
{
int count=0;
while(*str++) count++;
return count;
}
You can see that the argument str is const. But, the compiler does not complain when I do a str++. My question is
When passing pointers as arguments to a C function, if is is qualified with const, How can I still perform pointer arithmetic on it? What is const in the above function?
const char* str;
means a non-const pointer to a const data.
char* const str;
means a const pointer to a non-const data.
const char* const str;
means a const pointer to a const data.
The reason for this is that in C++ the variable type declarations are parsed from right to left, which results in that the word "const" always defines the constness of the thing that it's closest to.
It's not declaring the pointer const, it's declaring the thing pointed to as const. Try this:
int s(const char* const str)
With this declaration, you should get a compile error when you modify str.
const char * ch; // non-const pointer to const data
char * const ch; // const pointer to non-constant data.
const char * const ch; // const pointer to const data
Note:
Also
const char * ch;
equals to
char const * ch;
The pointer points to a const char, a read-only character array.