My intention is to create a char[] from the length of a char* I've already created.
I asked myself why this is not valid:
void copyStringsV2() {
const char* source = "this is my string.";
const int length = strlen(source);
const char* dest[length];
}
The compiler gives me this hint:
Severity Code Description Project File Line Suppression State
Warning C4101 'str_b': unreferenced local variable CStrings
xxx\cstrings.cpp 46
Error C2131 expression did not evaluate to a constant CStrings
xxx\cstrings.cpp 161
Error (active) E0028 expression must have a constant value CStrings
xxx\CStrings.cpp 161
May you can help me out here?
You are trying to declare a variable-length array, which is not a standard feature in C++. A fixed-length array must have its length known at compile-time. That is what the compiler error is complaining about.
If you don't know the length until runtime, you will have to allocate the copied string dynamically instead, such as via new[]:
void copyStringsV2()
{
const char* source = "this is my string.";
const int length = strlen(source);
char* dest = new char[length+1];
strcpy(dest, source);
...
delete[] dest;
}
Or std::vector, so you don't need to use new[]/delete[] directly:
#include <vector>
void copyStringsV2()
{
const char* source = "this is my string.";
const int length = strlen(source);
std::vector<char> dest(length+1);
strcpy(dest.data(), source);
...
}
But, in this case, it would be better to use std::string instead:
#include <string>
void copyStringsV2()
{
const char* source = "this is my string.";
std::string dest = source;
...
}
For starters you should use the type size_t instead of the type int in this declaration
const int length = strlen(source);
^^^
This constant is a constant of the run-time. So you may not use it in the declaration
const char* dest[length];
because here is declared a variable length array and variable length arrays (VLA) is not a standard C++ feature.
Also it is unclear why the type of elements of the array is const char * instead const char.
And moreover a constant object shall be initialized.
My intention is to create a char[]
const char* dest[length];
That's not an array of char. That's an array of pointers to const char.
Also, if you want the array to be able to fit the original null termiated string, you must include the null terminator in the length of the array so that its size is length + 1.
I asked myself why this is not valid:
The compiler gives me this hint:
expression did not evaluate to a constant
May you can help me out here?
The size of an array must be a compile time constant. length is not a constant, therefore it cannot be used as length of an array.
Length of a string cannot be calculated at compile time through a pointer to element of the string. However, if you used a reference for example, and if you used a constexpr function to get the length, and used a constexpr (const works too) variable, then you could use it as the size of an array. There is such function in the C++ standard library:
auto& source = "this is my string.";
constexpr auto length = std::char_traits<char>::length(source);
char dest[length + 1];
why this is not compilable
Because this is C++, and C++ provide a wide variety of tools already1. Your best bet will be std::string. Strings can be copied and passed around with no additional code to write.
#include <string>
int main()
{
const std::string source = "this is my string.";
const std::string dest = source;
// do something with dest
}
1) So you don't need variable length arrays, which are not part of C++.
Related
I have a code like this but I keep receiving this error :
A value of type "const char*" cannot be used to initialize an entity of type "char *"
What is going on?
I have read up on the following threads but have not been able to see any result to my answer as all of them are either from char to char* or char* to char:
Value type const char cannot be used to initialize an entity of type char*
Value of type char* cannot be used to initialize an entity of type "char"
#include <iostream>;
using namespace std;
int main() {
int x = 0; //variable x created
int cars (14);//cars is created as a variable with value 14
int debt{ -1000 };//debt created with value 1000
float cash = 2.32;
double credit = 32.32;
char a = 'a';//for char you must use a single quote and not double
char* sandwich = "ham";
return 0;
}
I am using Visual Studio Community 2017
That is correct. Let’s say you had the following code:
const char hello[] = "hello, world!";
char* jello = hello; // Not allowed, because:
jello[0] = 'J'; // Undefined behavior!
Whoops! A const char* is a non-const pointer to const char. If you assign its value to a non-const char*, you’ve lost its const property.
A const pointer to non-const char would be a char* const, and you can initialize a char* from that all day if you want.
You can, if you really want, achieve this with const_cast<char*>(p), and I occasionally have, but it’s usually a sign of a serious design flaw. If you actually get the compiler to emit instructions to write to the memory aliased by a string constant, you get undefined behavior. One of the many things that might go wrong is that some implementations will store the constant in read-only memory and crash. Or the same bytes of memory might be re-used for more than one purpose, because after all, we warned you never to change it.
By the way, the rules in C are different. This is solely for backward-compatibility with early versions of C that did not have the const keyword, and you should never write new code that uses a non-const alias to a string constant.
You need to make your string literal type const because in C++ it is a constant array of char, unlike C where it is just an array of char. You cannot change a string literal, so making it const is preferred in C++ for extra safety. It is the same reason you have to use an explicit cast when going from const char* to char*. It's still technically "allowed" in C++ since it is allowed in C, which is why it's just a warning. It's still bad practice to do so. To fix the warning, make it const.
const char* sandwich = "ham";
Your code (and underlying assumption) is valid pre C++11 standard.
String literals (e.g. "ham") since C++11 are of type const char* (or const char[]) if you will instead of char * they used to be. [Always read specs for breaking changes!!!]
Hence the warning in VS 2017. Change the compiler version to pre C++11 version and you will be amazed.
This has subtle nuances and can cause frustrating debug sessions
// C++11 or later
auto c = "Rowdie";
// c has type const char*, can't use c to modify literal
c[0] = 'H'; // illegal - CTE
// -vs-
char * d = "Rowdie";
d[0] = 'H';
cout << d; // outputs "Howdie"
Also another example is auto return type from functions
auto get_literal() {
// ... function code
return "String Literal";
}
// and using value later
char* lit = get_literal(); // You get same error as const char* cannot be init to char*
char *name[]={"Riyaz","Kapil","mayank","Ankur"};
int len=0;
len=strlen(name[1]);
cout<<"\n String 2 is "; puts(name[1]); cout<<"\n and string 3 is";puts(name[2]);
//exchange now//
char *temp;
temp=name[1];
name[1]=name[2];
name[2]=temp;
len=strlen(name[1]);
cout<<"\nExchanged string is "; puts(name[1]);
return 0;
How can I remove "deprecated conversion from string constant to 'char*'" warning in this code?
I was trying this program on array of pointers actually, so suggest some changes considering that.
Just declare the array like
const char *name[]={"Riyaz","Kapil","mayank","Ankur"};
^^^^^
Opposite to C in C++ string literals have types of constant character arrays that in expressions are converted to pointers to their first elements. Though in the both languages string literals are immutable.
Correspondingly variable temp also must be declared like
const char *temp;
Take into acount that these declarations
const char *name[]={"Riyaz","Kapil","mayank","Ankur"};
and
const char * const name[]={"Riyaz","Kapil","mayank","Ankur"};
differ.
The first array is not a constant array. Its elements can be changed and you do that in your program. While the second array is a constant array. Its elements may not be changed.
As for the program then instead of this code snippet
const char *temp;
temp=name[1];
name[1]=name[2];
name[2]=temp;
you could use standard function std::swap declared in header <utility>. For example
#include <utility>
//...
std::swap( name[1], name[2] );
Since you marked the question as C++ (not C), you may want to use convenient C++ classes to build a string array, like a std::vector<std::string>:
#include <string> // for std::string
#include <vector> // for std::vector
// Old C-style:
// const char *name[]={"Riyaz","Kapil","mayank","Ankur"};
//
// C++ style:
std::vector<std::string> names{ "Name1", "Name2", "Name3", ... };
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.
I am doing it that way:
int argc = 9;
char* argv[argc];
argv[0] = "c:/prog.exe";
but I get notice, that it is deprecated. What is better way?
You have to either make it const:
const char *argv[] = { "Arg1", "Arg2", "..." };
... or not use the constant string literals:
int argc = 9;
char* argv[argc];
char prog_name[] = "c:/prog.exe";
argv[0] = prog_name;
Besides the problem of using something other than a constant expression for your array size...
The thing that has been deprecated is the silent casting of string literals to char*. This used to be OK:
char * hello = "hello";
Now it has to be:
char const* hello = "hello";
This deprecation is actually in an Appendix in C++03.
Let analyze what you are doing here:
// Create an int with value 9.
int argc = 9;
// Create an array of char* pointers of size 9
char* argv[argc];
// Assign the the first pointer to the global data string "C:\prog.exe"
argv[0] = "c:/prog.exe";
My guess is that you are not trying to do what I've described above. Try something like this:
// create an array of characters
char argv[] = "C:/prog.exe";
// argc in now the length of the string
int argc = sizeof argv;
-or -
// create an array of strings
char* argv[] = {"C:/prog.exe"};
// argc is now the number of strings in the array
int argc = 1;
Try using const to indicate that the strings won't be modified.
const char* argv[] = { "c:/prog.exe" };
const int argc = sizeof(argv) / sizeof(argv[0]);
int main()
{
for(int i = 0; i < argc; ++i)
{
::printf("%s\n", argv[i]);
}
}
Here, argc will also be calculated at compile time automatically so there's a lesser chance of error (thanks to Goz for the suggestion).
+1 for Vlad.
Some more explanation from me on what happens here:
You get the "deprecated" warning, because such code:
"asdf"
now has type const char*, not char*. And string literals can be converted to char*, to retain some compatibility with the older conventions when const wasn't that strict. But conversion of a string literal to char* from const char* is deprecated and you should not rely on it.
Why? String literal is a pointer to constant memory, that's why it needs to be const char*.
Other than what everyone else has pointed out about const string literals being assigned to non-const char pointers and the weirdness of declaring argv and argc outside of main()'s parameter list, there is an additional problem with this line here:
char* argv[argc];
You can only use integer constant expressions for array sizes in C++; an integer constant expression being a literal integer in the source of your program (like "5" or "10"), an enumerations value (like "red" from "enum colors {red, green, blue};"), a sizeof expression, or an int variable declared with const:
// can hold 30 ints
int myarray1[30];
// can hold as many ints as myarray1 is wide in bytes
int myarray2[sizeof(myarray1)];
// C++ does not support variable-length arrays like C99 does, so if an int
// variable is used to specify array size, it must be marked const:
const int myarray3_size = 42;
int myarray3[myarray3];
Many C++ compilers implement C99-style variable-length arrays, so you may not get any complaint when you use them, but they are still best avoided if you want to write portable code.
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';
}