I'm working on a software using a home-made report library which takes only (const char *) type as an argument :
ReportInfo(const char* information);
ReportError(const char* error);
[...]
As I'm trying to report value of integers, I'd like to get a representation of those integers in a const char* type.
I can do it that way :
int value = 42;
string temp_value = to_string(value);
const char *final_value= temp_value.c_str();
ReportInfo(final_value);
It would be great if I could do it without instancing the temp_value.
I tried this :
int value = 42;
const char* final_value = to_string(value).c_str();
ReportInfo(final_value);
but final_value is equal to '\0' in that case.
Any idea how to do it ?
You could try
ReportInfo(to_string(value).c_str());
because the temporary will not be destroyed until ReportInfo returns.
to_string(value) returns a temporary, so in your second example its lifetime ends at the end of the expression. so you have dangling pointer.
Related
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
I have a number that I need to convert to a const char * (an API I'm using them requires const char * as input to many of its functions). The following works:
int num = 5;
std::string s = std::to_string(5);
const char * p = s.c_str();
as suggested by answers like those in how to convert from int to char*?, but it involves creating the seemingly unnecessary variable s, so I tried the following, but it doesn't work (p points to an empty string afterwards):
int num = 5;
const char * p = std::to_string(num).c_str();
Is there a clean way I can accomplish this? Why doesn't the second example work? The behavior is very similar to what happens if I made this obvious mistake:
const char * p;
{
std::string tempStr( "hi" );
p = tempStr.c_str( );
// p points to "hi" string.
}
// now p points to "" string.
Which makes me suspect that the issue std::to_string(num) immediately goes out of scope or something similar because it's not used to directly initialize anything.
std::string encapsulates managing dynamic memory (created with new[] and delete[]). Let's break it down.
const char * p = std::to_string(num).c_str();
Create a std::string (with a human-readable representation of num).
Get the new[]ly allocated const char* to the string.
Assign that value to p.
Destroy the std::string → delete[] the allocated const char*.
p points to... deallocated data
If you are using a pointer, the data that the pointer points to must exist throughout the lifetime of that pointer.
So, no, there is no way around this other than new[]ing a copy of the string, which you will have to explicitly delete[] later. And at that point, you've thrown the baby out with the bath and have no need to use std::string.
Create a string that lives at least as long as you want to refer to its internal data.
Just use std::string it does everything you want and everything that you would have to do manually if you don't use it.
When you need to pass a const char* to a const char* function simply use std::string::c_str() like this:
some_api_function(mystring.c_str()); // passes a const char*
What you need is a function which returns a char* which holds your value and can be used to manage its lifetime. The problematic version is broken because the char* points to memory which it does not manage.
For example:
std::unique_ptr<char[]> str(int32_t x)
{
std::unique_ptr<char[]> res(new char[12]);
snprintf(res.get(), 12, "%d", x);
return res;
}
Usestd::string everywhere and don't use const char* when not nessecary. They are basically the same thing. I use const char* only when I'm using a file-path.
Use std::string everywhere and your program should work.
This is probably a very basic question for which I have been searching on google for the last 20 mins. I am not sure if i am phrasing it correctly, but I am not getting an explanation that I understand.
Basically, I have a string object and when I add an integer value x, it shortens the string by x characters.
Here is the code:
#include <iostream>
#include <string>
void Print::print(std::string str)
{
std::cout << str << std::endl;
}
print("formatString:" + 5);
The output is: tString:
Now i realise that the above is incorrect and during my search I have found ways correct the behaviour, but I haven’t found what is actually happening internally for me to get the above result.
Thanks
The answer is simple: Pointer arithmetic.
Your string literal (array of const char including implicit 0-terminator), decays to a const char* on use, which you increment and pass to your print()-function, thus invoking the std::string-constructor for string literals.
So, yes, you start with a string object (0-terminated array of const char), but not a std::string object.
Basically, I have a string object
No, you do not have a string object. "formatString:" is not a std::string, but a "string" literal. It is in fact a const char*. A const char* has a operator + defined that takes an integer and advances the value of the pointer with a number of positions. In your case it's 5.
To get a compiler error you'd have to wrap the literal in a std::string.
print(std::string("formatString:") + 5);
"formatString:" is a string literal that has type const char[14] That is it is an array of const char with size equal to 14 (the array includes the terminating zero).
In expressions like this
"formatString:" + 5
the array is implicitly converted to a pointer to its first element. So if for example const char *p denotes this pointer then the expression looks as
p + 5
The result of the expression is a pointer that points to the element of the array with index 5. That is there is used the pointer arithmetic.
P + 5 points to the first symbol of string "tString"
And this expression is used by the constructor of class std::string.
Examine the following,
#include <iostream>
void print(std::string str)
{
std::cout << str << std::endl;
}
int main(int argc, char* argv[])
{
//following two lines created implicitly by the compiler
const char* pstr = "formatString";
std::string tmp(pstr + 5); //string c-tor: string (const char* s);
// now tmp: --> "tString"
print(tmp);
return 0;
}
pstr is a pointer and you are doing pointer arithmetic when you use + operation.
Note:Compiler may create different internal structure, but it is a instructive way to think the above two lines.
I have a method that receives a char ** as an argument in order to parse and construct a proper inner object.
void build (const char* values[], const int amount=3)
{
//..parse values and create instance of an inner field..
}
It is constant, because I just want to use those values and I don't need to modify them at all. This works pretty much fine.
Now I want to be able to code a method that returns to me a const char ** in a way that I am able to use this returned value in the previously declared method. At first, I got the values needed from the instance of my class, converted them to string and put them in an array and returned it, but it was complaining that I was returning a pointer to a local variable. So I thought of using another field to hold this pointer, I created char ** values. Then I realized that I would need to allocate the memory for the value it points to, so I went trough with it. Currently the method I'm describing looks something like:
const char** getValues()
{
string var;
var = toString(point.zone);
values[0]= new char[var.length()+1]();
strcpy(values[0], var.c_str());
var = toString(point.easting);
values[1]= new char[var.length()+1]();
strcpy(values[1],var.c_str());
var = toString(point.northing);
values[2]= new char[var.length()+1]();
strcpy(values[2],var.c_str());
return values;
}
But at the moment this will complain because char ** values is not constant. But if I make it constant,the strcpy will complain about the opposite. If I dont return it constant then I cant us it in other function. I need help fixing this problem. Any help is deeply appreciated, thanks.
One main point, why are you making your life complicated with char** instead of using std::string or std::vector<std::vector<char>> where appropriate?
I mean, if you're using C++ as your tags seem to indicate, then why not USE C++ and not C.
This will make your life much easier.
Another thing:
A const char** is a pointer to pointer to char that is const. Meaning you cannot alter the char. If you want to alter use char**.
Allocation is another point about your code, how are you allocating memory for your char**?
These are added complexities that you shouldn't need to have in C++, if you just use what I said above.
You got a compilation error because you try to strcpy to a char const* directly.
You should instead strcpy to a char * and assign this pointer back to the values[].
See the modified code below for a simple solution:
const char** getValues()
{
string var;
char* p;
var = toString(point.zone);
p = new char[var.length()+1]();
strcpy(p, var.c_str());
value[0] = p; // now you can assign char* to char const* without compilation error
var = toString(point.easting);
p = new char[var.length()+1]();
strcpy(p, var.c_str());
value[1] = p;
var = toString(point.northing);
p = new char[var.length()+1]();
strcpy(p,var.c_str());
value[2] = p;
return values;
}
You're probably looking for const char* const* const, where not only the data pointed to, but the pointers themselves, are constant.
There is an implicit conversion from char** to const char* const*. The rules of covariance forbid the conversion from char** to const char**, however, because a const char** is writable (you can store a new pointer), and operations which write to a collection are not safe for covariance. Take a look:
const char* a = "a literal"; // ok, literal is read-only, so const char* is good.
char* b;
char* c[] = { &b };
const char** d = c; // this step is illegal under the current rules
*d = &a;
*b = 'A'; // this would write to a string literal, causing an access violation
Notice that if the conversion were allowed, you could write to a const object without breaking type safety, which wouldn't be safe at all.
With const char* const* d = c, the following step (*d = &a) is already illegal, so there is no hole in the type system.
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';
}