first of all this is not duplicate one because same error Question
asked before but in different context
1
code
#include<iostream>
#include<cstring>
int main()
{
const char *s1;
const char *s2="bonapart";
s1=new char[strlen(s2)+1];
strcpy(s1,s2);
std::cout<<s1;
}
Output
[Error] invalid conversion from 'const char*' to 'char*' [-fpermissive]
Why such error ?
If I replace const char *s1 by char *s1 compile fine. But I think this const only saying that s1 is pointing to constant string means we can't modify that string whom it is pointing. It does not mean that s1 is constant ptr. please put some light on this.
Why such error ?
Look at the declaration of strcpy:
char* strcpy( char* dest, const char* src );
Pay particular attention to the first parameter. And very particular attention to the type of the first parameter: char*. It isn't const char*.
Now, look at the type of the argument that you pass.
const char *s1;
It's not char*. It's const char*. You cannot pass a const char* into a function that accepts char* because former is not convertible to the latter, as the diagnostic message explains.
But I think this const only saying that s1 is pointing to constant string means we can't modify that string whom it is pointing.
That's exactly what const bchar* means. So, how do you expect strcpy to modify the content of the pointed string when you know that it cannot be modified? Technically in this case the pointed string isn't const, it's just pointed by a pointer-to-const
As you say, const char *s1; means that the string pointed at by s1 is not modifyable.
On the other hand, strcpy(s1,s2); will modify the string pointed at by s1.
This is against the condition "the string pointed at by s1 is not modifyable".
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.
Definition of method is:
void setArgument(char *);
And i call that method with this code:
setArgument("argument");
But my VisualStudio compiler gets me the next error:
cannot convert argument 1 from 'const char [10]' to 'char *'
Is it possible to send arguments like this or I must change arguments type in the method?
Also, VS show me next note in output: note: Conversion from string literal loses const qualifier (see /Zc:strictStrings)
The problem is that string literals are arrays of constant characters.
While the array could easily decay to a pointer to its first element, the type of that pointer is const char *. Which needs to be the type of the argument for your functions.
And if you need to modify the string you pass, then you should create your own non-constant array:
char argument[] = "argument";
setArgument(argument);
Of course, since you're programming in C++ you should stop using char pointers and arrays and instead use std::string.
It's possible, just if you really need the argument to be mutable (char* and not char const*), you need to allocate a new storage in the mutable memory and clone the contents of the constant memory to there, if that fits into your definition of "convert".
auto const len = strlen(input);
auto const buf = std::unique_ptr<char[]>(new char[len + 1]);
memcpy(buf, input, len + 1);
If you actually need char const* and if you are C++17 or later, you can possibly change the signature to setArgument(std::string_view arg), making it misuse-proof.
When I compile the given code it doesn't produce any error or warnings. My question here is shouldn't the compiler produce error when compiling the following line *err = "Error message"; because we are dereferencing a pointer to pointer to constant char and assigning a string to it.
Is it allowable to assign anything inside a pointer anything other than address and exactly what is happening in this given scenario?
#include <stdio.h>
void set_error(const char**);
int main(int argc, const char* argv[])
{
const char* err;
set_error(&err);
printf("%s",err);
return 0;
}
void set_error(const char** err1)
{
*err1 = "Error message";
}
const char** err1
That's a pointer to a non-constant pointer to a constant object. Dereferencing it gives a non-constant pointer (to a constant object), which can be assigned to.
To prevent assigning to the const char*, that would also have to be const:
const char * const * err1
"Error message" is not a std::string. It's a const char[]. All string literals in C++ are const char[]. In C, they're char[].
Is it allowable to assign anything inside a pointer anything other than address and exactly what is happening in this given scenario?
You can assign pointer to a pointer. You think about pointer as an address, that's fine to understand concept, but do not mix it with data type. Data type is a pointer, not address. For example to assign address in memory to a pointer you need to cast it to a pointer:
char *pointer = reinterpret_cast<char *>( 0xA000000 );
You may ask how this would compile?
int array[10];
int *ptr = array;
That comes from C - array can be implicitly converted to a pointer to the first element. So it is pointer to pointer assignment again. Now about string literal with double quotes. It is an array as well:
const char str[] = "str";
const char str[] = { 's', 't', 'r', '\0' };
These 2 statements are pretty much the same. And as array can be implicitly converted to pointer to the first element it is fine to assign it to const char *
void test3(char * &p){
strcpy( p, "aaaaaaaaaaaaaaaaaaaaaaaaaa");
}
char c[] = "123";
test3(c);
the code above is compiled failed:
initialization of non-const reference of type 'char*&' from a temporary of type 'char*'
why char c[] can't be referenced by the argument p?
Because the type of c is char[4], i.e. an aray of four chars. Your reference needs a char*, i.e. a pointer to char.
Arrays are not pointers. In most cases, they decay to a pointer to first element when used, but that decay-produced pointer is temporary. As such, it cannot bind to a non-const reference.
Why is your function taking a reference in the first place? It would be perfectly fine taking char*.
You may modify your code by taking an intermediate variable as:
char c[] = "123";
char* tmp = c;
test3(tmp);
And as you are trying to copy a relatively longer string than the length, you may corrupt the variable.
You may modify your code by adding a modifier, "const",
promisng that you won't change the address of c :
void test3(char * const &p){
strcpy( p, "aaaaaaaaaaaaaaaaaaaaaaaaaa");
}
char c[] = "123";
test3(c);
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.