warning: deprecated conversion from string constant to 'char*'' [duplicate] - c++

This question already has an answer here:
C++ warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
(1 answer)
Closed 8 years ago.
I have declared the string array in my code as follows.
char *arr[] ={
"xyz",
"abc",
"pqr",
NULL
};
When compile then got following warning
warning: deprecated conversion from string constant to 'char*''
i know that "xyz" and other string literal are const char and my array is char* so have resolve it by declaring my array const char* arr but i loss the control to point this array in another pointer.
So to resolve above issue have declared array as follows
char *arr[] ={
(char *)"xyz",
(char *)"abc",
(char *)"pqr",
NULL
};
But this type of declaration not fair when need large array (more then 100 string array).
So any one have idea to resolve it by another way.

You don't lose any re-pointing options by making the array a const char* arr[]. Note that there's a huge difference between const char * p (a mutable pointer to an immutable char) and a char * const p (an immutable pointer to a mutable char). This code is perfectly valid:
const char *arr[] = {
"xyz",
"abc",
"pqr",
NULL
};
arr[1] = "ghi";
Live example

There is a difference between a const char* and char *const if your pointer is a const char* you can still point it to another location but you cannot modify the elements it contains. The correct solution in this case is to make the array const char*.

String literals are constant, so you need const pointers to refer to them:
const char *arr[] = {
// whatever
};
Historically, it used to be possible (but dangerous) to convert string literals to non-const char*, for compatibility with ancient code that didn't know about const. This conversion has been deprecated for many years, and finally removed from the language in 2011.

Related

Question about the type of `&"hello"` and `"hello"`

As per the output of this code snippet, the type of &"hello" is const char(*)[6], so char* ptr = &"hello"; is inlegal for char* and const char(*)[6] are different types.
And since char* ptr1 = "hello"; compiles with C++11 and latter, the type of "hello" is char*?
If the type of "hello" is char*, then &"hello" shouldn't be a pointer which points to char*(i.e. char**)?
I used to write char* ptr1 = "hello"; many years, and when I know that "hello" is a prvalue. A question raises that I could acquire the address of the string literal.After I found the type of &"hello" is const char(*)[6], I am totally confued now.
Could anybody shed some light on this matter?
Here is the aforementioned code snippet:
#include<memory>
#include<thread>
#include<iostream>
#include<typeinfo>
int main()
{
char* ptr = &"hello";
char* ptr1 = "hello";
}
Here is what the compiler complains:
<source>: In function 'int main()':
<source>:8:17: error: cannot convert 'const char (*)[6]' to 'char*' in initialization
8 | char* ptr = &"hello";
| ^~~~~~~~
| |
| const char (*)[6]
<source>:9:18: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
9 | char* ptr1 = "hello";
| ^~~~~~~
UPDATE:
Thanks to ShadowRanger's clarification. I realise that type of string literal is const char[6].
"Hello" is a string literal of type const char [6] which decays to const char* due to type decay.
Now let's see what is happening for each of the statements in you program.
Case 1
Here we consider the statement:
char* ptr = &"hello";
As i said, "hello" is of type const char [6]. So, applying the address of operator & on it gives us a const char (*)[6] which is read as a pointer to an array of size 6 with elements of type const char.
This means that there is a mismatch in the type on the right hand side(which is const char (*)[6]) and the left hand side(which is char*). And since there is no implicit conversion from a const char (*)[6] to a char* the compiler gives the mentioned error saying:
cannot convert 'const char (*)[6]' to 'char*'
Case 2
Here we consider the statement:
char* ptr1 = "hello"; //invalid C++
Since "Hello" is of type const char[6] meaning that the char elements inside the array are immutable(or non-changable). As i said, the type const char[6] decays to const char*. Thus on the right hand side we have a const char*. So if we were allowed to write char* ptr1 = "Hello"; then that would mean that we're allowed to change the elements of the array since there is no low-level const on ptr1. Thus, allowing char* ptr1 = "Hello"; would allow changing const marked data, which should not happen(since the data was not supposed to change as it was marked const). This is why the mentioned warning said:
ISO C++ forbids converting a string constant to 'char*'
So to prevent this from happening we have to add a low-level const as shown below:
vvvvv---------------------------> note the low-level const
const char* ptr1 = "Hello"; //valid c++
so that the pointer ptr1 is not allowed to change the const marked data.
By adding the low-level const highlighted above, it is meant that we're not allowed to change the underlying characters of the array.

Pointers confusion char* and int*

I got this confusion while learning c++:
int *a = 8 ;
This gives an error because, as I have understood it, i am trying to set an integer to a pointer which is a memory location. But,
const char *name = "name";
works perfectly fine? I don't get it as name should be an hexadecimal memory location but i am trying to set it to a series of characters.
A string literal, "name" in your case, is of typeconst char[]. An array can decay to a pointer which is what's happening in this case. That pointer will then point to the first element in the array. Note that since C++11 assigning to a char* instead of a const char* (thus needing a conversion) as you are doing is illegal, always use const char* for string literals, or better yet, std::string.
8 is of type int, which has no conversion to a pointer type that an array has.
The rules for int* and char* are the same. However, you compare apples to oranges.
You cannot assign a value of the respective type to its pointer (it doesn’t matter whether there is a const here; I made things const for consistency with the next example where it matters to some extend):
int const* ip = 8; // ERROR
char const* cp = ‘8’; // ERROR
Arrays decay into pointers upon the slightest opportunity. String literals are arrays of type char const[N] where N is the number of chars in the string literal, including the terminating null char.
int ia[] = { 8 };
char ca[] = { ‘8’ };
int const* ip = ia; // OK
char const* cp = ca; // OK
char const* lp = “8”; // OK

What is difference between char* and int* data type to create array of pointers in C++?

While creating an array of pointers for int data type the following code works:
int var[] = {10, 100, 200, 1000};
int *ptr[] = {&var[0], &var[1], &var[2], &var[3]};
While creating an array of pointers for char data type the following is legal:
char *names[] = {"Mathew Emerson", "Bob Jackson"};
But if I create an array of pointers for int data type as follows:
int var[] = {10, 100, 200, 1000};
int *ptr[] = {var[0], var[1], var[2], var[3]};
I get a compiler error. I understand why I am getting a compilation error in the above method of declaration for array of int data type, as var[i] is not a reference to a variable to which a pointer must point to i.e. its address, but shouldn't I also get error by the same logic in the declaration of my char array of pointer.
What is the reason that its is acceptable in char array of pointers?
Is " a string value " an address of something to which a pointer can point to or is it just a const string value.
char *names[] = {"Mathew Emerson", "Bob Jackson"};
Is not legal in C++. A string literal has the type of const char[] so it is illegal to store it as a char* as it violates const-correctness. Some compilers allow this to still compile as a legacy from C since string literals have the type char[] but it is not standard C++. If you turn up the warnings on your compiler you should get something along the lines of
main.cpp: In function 'int main()':
main.cpp:5:53: warning: ISO C++ forbids converting a string constant to 'char*' [-Wpedantic]
char *names[] = {"Mathew Emerson", "Bob Jackson"};
If you want an array of strings then I suggest you use a std::string like
std::string names[] = {"Mathew Emerson", "Bob Jackson"};
The reason
char *names[] = {"Mathew Emerson", "Bob Jackson"};
"works" is that since the string literals are arrays they implicitly decay to pointers so
{"Mathew Emerson", "Bob Jackson"}
Becomes
{ address_of_first_string_literal, address_of_second_string_literal}
and then those are used to initialize the pointers in the array.
int *ptr[] = {var[0], var[1], var[2], var[3]};
Cannot work because var[N] is a reference to the int in the array and not a pointer.
"Mathew Emerson" is of type const char* - it is already a pointer, thus you can directly store it in an array of pointers. The reason you need & for the int case is to "convert" int to int*.
(Ignoring the const-ness problem as mentioned in other answers...)
Each string literal you write ("Mathew Emerson", "Bob Jackson", ...) requires some storage location in the compiled code later.
It is as if you had written somewhere
char const[] MathewEmerson = { 'M', 'a', /*...*/, 'o', 'n', 0 };
So you you could construct your char const* array then as:
char const* names[] = { &MathewEmerson[0], /*...*/ };
As for arrays, the address of the array itself and its first element is the same, and arrays are implicitely converted to pointers, you can write instead
char const* names[] = { MathewEmerson, /*...*/ };
All this is done implicitely for you, if you use string literals.
Similarly, you could have written:
int *ptr[] = {var, &var[1], &var[2], &var[3]};
(note: var, not &var[0] for the first item) and if we go further, even:
int *ptr[] = {var, var + 1, var + 2, var + 3};
The result always would have been the same. Readability, understandability of one variant vs another? Well, another topic...
Your misconception is wrapped up in your interpretation of what is represented by: "Mathew Emerson"
This is an array of characters that will be instantiated in read only memory as part of your program's bootstrapping. This array of characters is called a String Literal, specifically a:
Narrow multibyte string literal. The type of an unprefixed string literal is const char[]
NathanOliver's answer correctly describes that your compiler doesn't have the warning level turned up high enough so it is allowing the, const char[] to decay into a char*. This is very bad because:
Attempting to modify a string literal results in undefined behavior: they may be stored in read-only storage (such as .rodata) or combined with other string literals[1]
It would have been completely legal and logical to do this however: const char *names[] = {"Mathew Emerson", "Bob Jackson"} Hopefully that clarifies for you what's happening well enough for you to understand that working with a String Literal is working with a pointer. Your code: int *ptr[] = {var[0], var[1], var[2], var[3]} is then illegal because, var[0] is an int& not an int*. It would be similarly illegal to do: char* ptr = {names[0][0], names[0][1], names[0][2], names[0][3]} Again the problem here would be that I was working with char&s not char*s.

char pointers, char arrays, and strings in the context of a function call

What is the difference between the line that does not compile and the line that does compile?
The line that does not compile gives this warning: deprecated conversion from string constant to 'char*'
Also, I'm aware casting (char *) on the string being passed in to the function would solve the problem, but I would like to understand why that's even necessary when the 2nd line compiles just fine.
class Student {
public:
Student( char name[] ) {
}
}
int main() {
Student stud( "Kacy" ); //does not compile
char name[20] = "Kacy"; //compiles just fine
}
The char[] signature in the parameter is exactly the same as char*. In C++, it is illegal to convert a string constant char const* (the string "Kacy") to a char* because strings are immutable.
Your second example compiles because the name is an actual array. There is no change to char*.
As a solution, change your parameter to take a const string array:
Student(char const name[]);
which again is the same as
String(char const *name);
though you're better off using std::string:
#include <string>
class String
{
public:
String(std::string name);
};
C++ string literals have type "array of n const char", which decays into const char * in your use case. The implicit conversion to char * (that is, discarding the const) you're trying is deprecated, so there's a warning. Change the type in the constructor's signature or make an explicit const-cast.
From the C++ standard:
An ordinary string literal has type "array of n const char" and static storage duration
The string
"Kacy"
is not an array of characters when the compiler produces the code. Instead, it will stash the string "Kacy" somewhere in memory, and produce a pointer to that place. So what you get is a const char * pointing at the string "Kacy\0".
If you change your constructor to:
Student(const char *nmae)
you can use it both as:
Student stud("Kacy");
and as this:
char name[20] = "Kacy";
Student stud2(name);
Note here that the compiler will generate code to FILL the array name with the characters in "Kacy", which is different from just usinv "Kacy" as an argument to the Student constructor.

C++ deprecated conversion from string constant to 'char*'

I have a class with a private char str[256];
and for it I have an explicit constructor:
explicit myClass(char *func)
{
strcpy(str,func);
}
I call it as:
myClass obj("example");
When I compile this I get the following warning:
deprecated conversion from string constant to 'char*'
Why is this happening?
This is an error message you see whenever you have a situation like the following:
char* pointer_to_nonconst = "string literal";
Why? Well, C and C++ differ in the type of the string literal. In C the type is array of char and in C++ it is constant array of char. In any case, you are not allowed to change the characters of the string literal, so the const in C++ is not really a restriction but more of a type safety thing. A conversion from const char* to char* is generally not possible without an explicit cast for safety reasons. But for backwards compatibility with C the language C++ still allows assigning a string literal to a char* and gives you a warning about this conversion being deprecated.
So, somewhere you are missing one or more consts in your program for const correctness. But the code you showed to us is not the problem as it does not do this kind of deprecated conversion. The warning must have come from some other place.
The warning:
deprecated conversion from string constant to 'char*'
is given because you are doing somewhere (not in the code you posted) something like:
void foo(char* str);
foo("hello");
The problem is that you are trying to convert a string literal (with type const char[]) to char*.
You can convert a const char[] to const char* because the array decays to the pointer, but what you are doing is making a mutable a constant.
This conversion is probably allowed for C compatibility and just gives you the warning mentioned.
As answer no. 2 by fnieto - Fernando Nieto clearly and correctly describes that this warning is given because somewhere in your code you are doing (not in the code you posted) something like:
void foo(char* str);
foo("hello");
However, if you want to keep your code warning-free as well then just make respective change in your code:
void foo(char* str);
foo((char *)"hello");
That is, simply cast the string constant to (char *).
There are 3 solutions:
Solution 1:
const char *x = "foo bar";
Solution 2:
char *x = (char *)"foo bar";
Solution 3:
char* x = (char*) malloc(strlen("foo bar")+1); // +1 for the terminator
strcpy(x,"foo bar");
Arrays also can be used instead of pointers because an array is already a constant pointer.
Update: See the comments for security concerns regarding solution 3.
A reason for this problem (which is even harder to detect than the issue with char* str = "some string" - which others have explained) is when you are using constexpr.
constexpr char* str = "some string";
It seems that it would behave similar to const char* str, and so would not cause a warning, as it occurs before char*, but it instead behaves as char* const str.
Details
Constant pointer, and pointer to a constant. The difference between const char* str, and char* const str can be explained as follows.
const char* str : Declare str to be a pointer to a const char. This means that the data to which this pointer is pointing to it constant. The pointer can be modified, but any attempt to modify the data would throw a compilation error.
str++ ; : VALID. We are modifying the pointer, and not the data being pointed to.
*str = 'a'; : INVALID. We are trying to modify the data being pointed to.
char* const str : Declare str to be a const pointer to char. This means that point is now constant, but the data being pointed too is not. The pointer cannot be modified but we can modify the data using the pointer.
str++ ; : INVALID. We are trying to modify the pointer variable, which is a constant.
*str = 'a'; : VALID. We are trying to modify the data being pointed to. In our case this will not cause a compilation error, but will cause a runtime error, as the string will most probably will go into a read only section of the compiled binary. This statement would make sense if we had dynamically allocated memory, eg. char* const str = new char[5];.
const char* const str : Declare str to be a const pointer to a const char. In this case we can neither modify the pointer, nor the data being pointed to.
str++ ; : INVALID. We are trying to modify the pointer variable, which is a constant.
*str = 'a'; : INVALID. We are trying to modify the data pointed by this pointer, which is also constant.
In my case the issue was that I was expecting constexpr char* str to behave as const char* str, and not char* const str, since visually it seems closer to the former.
Also, the warning generated for constexpr char* str = "some string" is slightly different from char* str = "some string".
Compiler warning for constexpr char* str = "some string": ISO C++11 does not allow conversion from string literal to 'char *const'
Compiler warning for char* str = "some string": ISO C++11 does not allow conversion from string literal to 'char *'.
Tip
You can use C gibberish ↔ English converter to convert C declarations to easily understandable English statements, and vice versa. This is a C only tool, and thus wont support things (like constexpr) which are exclusive to C++.
In fact a string constant literal is neither a const char * nor a char* but a char[]. Its quite strange but written down in the c++ specifications; If you modify it the behavior is undefined because the compiler may store it in the code segment.
Maybe you can try this:
void foo(const char* str)
{
// Do something
}
foo("Hello")
It works for me
I solve this problem by adding this macro in the beginning of the code, somewhere. Or add it in <iostream>, hehe.
#define C_TEXT( text ) ((char*)std::string( text ).c_str())
I also got the same problem. And what I simple did is just adding const char* instead of char*. And the problem solved. As others have mentioned above it is a compatible error. C treats strings as char arrays while C++ treat them as const char arrays.
For what its worth, I find this simple wrapper class to be helpful for converting C++ strings to char *:
class StringWrapper {
std::vector<char> vec;
public:
StringWrapper(const std::string &str) : vec(str.begin(), str.end()) {
}
char *getChars() {
return &vec[0];
}
};
The following illustrates the solution, assign your string to a variable pointer to a constant array of char (a string is a constant pointer to a constant array of char - plus length info):
#include <iostream>
void Swap(const char * & left, const char * & right) {
const char *const temp = left;
left = right;
right = temp;
}
int main() {
const char * x = "Hello"; // These works because you are making a variable
const char * y = "World"; // pointer to a constant string
std::cout << "x = " << x << ", y = " << y << '\n';
Swap(x, y);
std::cout << "x = " << x << ", y = " << y << '\n';
}