const char * to char * in my case - c++

Although I know that converting const char * to char * is almost banned in C/C++ because of many problems, I am caught up in a situation where I think I have to convert const char * to char *.
I get a string from a text file as string by using c_str and I want to modify this string. However the problem is that c_str converts string into const char *. So is it a good choice to use strdup in this case or is there any better idea in doing this?

Actually, you can modify the std::string object directly, as illustrated in the little program below:
int main()
{
std::string s("Hello World");
for(char& c : s)
{
c = toupper(c);
}
s[0] = 'h';
s[6] = 'w';
s.resize(12);
s[11] = '!';
std::cout << s;
return 0;
}
I think, it is self-explaining. Although you mentioned that size does not change, I added an example for that case, too, see resize. There are yet other ways to manipulate the string, such as insert. Have a look at the std::string documentation.

Why is using &s[0] better than c_str?
std::basic_string class has data() and c_str(). However, as you know, these function's result type is const CharType*(CharType: char, wchar_t, char16_t, char32_t).
There is two way to get CharType*.
use const_cast. However, this is very dirty and break type system.
use &s[0]. operator[] does not break type system.
#include <string>
#include <type_traits>
int main(){
std::string s1 = "Hello world";
static_assert(std::is_same<char&, decltype(s1[0])>::value, "err");
static_assert(std::is_same<char*, decltype(&s1[0])>::value, "err");
const std::string s2 = "Hello world";
static_assert(std::is_same<const char&, decltype(s2[0])>::value, "err");
static_assert(std::is_same<const char*, decltype(&s2[0])>::value, "err");
}

Related

expression must have class type error c++

So I have this defined:
static char randomstring[128];
Now whenever I mention it somewhere like so:
char *x = randomstring;
It goes fine but whenever I try to do something with its content:
char *x = ranomstring.front();
It doesn't work at all and says expression must have class type..
This problem occurs a LOT for me.
I should also mention I'm a total noob at c++.
You should probably learn the difference betwenn std::string (a class) and c-style string (char* or char[] - array).
//this calls std::string constructor to convert c-style string to std::string:
string mystring = "hello world!";
//std::string has front()
char* front = mystring.front();
//this is old-style string
char oldstring[] = "hello again!";
//you can access it as pointer, not as class
char* first = oldstring;
//but you can iterate both
for(char c : mystring) cout << c;
for(char c : oldstring) cout << c;
//...because it uses std::begin which is specialized for arrays
Arrays in C++ are not classes. They are aggregates. So they have no methods.
Use instead either standard container std::string or standard container std::vector that can dynamically change their sizes and have method front.
For example
#include <string>
//...
std::string randomstring;
//filling the string
char x = randomstring.front();
Change char *x = ranomstring.front();
To char *x = ((string)ranomstring).front();

Is it safe to ever cast the result of string's c_str to a char*?

I'm in c++ and i'm using a c library which has an api which accepts a char *. It doesn't accept a const char *, even though the data in the char * will not be modified.
Is it safe to get the result of c_str() and cast it to a 'char *' for use with this api?
string str = "mydata";
char * cstr = const_cast<char*>(str.c_str());
c_api_lib_func(cstr);
Yes, it's safe as long as the function you're passing it to does not attempt to modify the contents of the string.
You can even avoid the const_cast using
c_api_lib_func(&str[0]);
Note that this is technically not safe with a pre-C++11 compiler because std::string was not required to have contiguous storage for it's internal buffer.
Using &str[0], the function may even modify the contents of the string's internal buffer as long as it leaves the terminating NULL character alone.
As long as you treat is as strictly read-only, it shouldn't do any harm.
it is not safe
this code outputs dydata
#include <iostream>
using namespace std;
int main()
{
string str = "mydata";
char * cstr = const_cast<char*>(str.c_str());
cstr[0] ='d';
cout <<str << endl;
return 0;
}

Why does "auto" declare strings as const char* instead of std::string?

I made a template which adds the data it is given. If I use it like this, the compiler declares in_1 and in_2 as const char *, and the code doesn't compile.
#include <iostream>
using namespace std;
template <class T>
T addstuff(T part_1, T part_2){
return(part_1+part_2);
}
int main(int argc, char const *argv[])
{
auto in_1="Shut ";
auto in_2="up.";
cout<<addstuff(in_1, in_2)<<endl;
return 0;
}
If I declare in_1 and in_2 std::string, it works like a charm.
Why can't (or doesn't) the compiler declare those strings automatically std::string?
The reason you can't "write" to your auto variable is that it's a const char * or const char [1], because that is the type of any string constant.
The point of auto is to resolve to the simplest possible type which "works" for the type of the assignment. The compiler does not "look forward to see what you are doing with the variable", so it doesn't understand that later on you will want to write into this variable, and use it to store a string, so std::string would make more sense.
You code could be made to work in many different ways, here's one that makes some sense:
std::string default_name = "";
auto name = default_name;
cin >> name;
If you use string literals, auto will work as expected.
In C++14, C++17 or C++20, you can place an s after the quotes, and it will create a std::string instead of a const char* string.
This can be used together with auto to create a std::string:
auto hello = "hello"s;
String literals are not enabled by default. One way of enabling string literals is to place the following at the top of the source file:
#include <string>
using namespace std::string_literals;
As an example, this loop works for std::string (with s added to the string literal), but not for const char* type string literals:
for (auto &x : hello) {
std::cout << "letter: " << x << std::endl;
}
Here is the cppreference page for the ""s operator.
Because string literals have type const char[N+1], not std::string.
This is just a fact of the language.
They could have made it so that auto has a special case for string literals, but that would be inconsistent, surprising and of very little benefit.
auto will declare the variable as the compile-time type of the expression you initialize it to.
String literals are of type const char*, not std::string.

std::string to char*

I want to convert a std::string into a char* or char[] data type.
std::string str = "string";
char* chr = str;
Results in: “error: cannot convert ‘std::string’ to ‘char’ ...”.
What methods are there available to do this?
It won't automatically convert (thank god). You'll have to use the method c_str() to get the C string version.
std::string str = "string";
const char *cstr = str.c_str();
Note that it returns a const char *; you aren't allowed to change the C-style string returned by c_str(). If you want to process it you'll have to copy it first:
std::string str = "string";
char *cstr = new char[str.length() + 1];
strcpy(cstr, str.c_str());
// do stuff
delete [] cstr;
Or in modern C++:
std::vector<char> cstr(str.c_str(), str.c_str() + str.size() + 1);
More details here, and here but you can use
string str = "some string" ;
char *cstr = &str[0];
As of C++11, you can also use the str.data() member function, which returns char *
string str = "some string" ;
char *cstr = str.data();
If I'd need a mutable raw copy of a c++'s string contents, then I'd do this:
std::string str = "string";
char* chr = strdup(str.c_str());
and later:
free(chr);
So why don't I fiddle with std::vector or new[] like anyone else? Because when I need a mutable C-style raw char* string, then because I want to call C code which changes the string and C code deallocates stuff with free() and allocates with malloc() (strdup uses malloc). So if I pass my raw string to some function X written in C it might have a constraint on it's argument that it has to allocated on the heap (for example if the function might want to call realloc on the parameter). But it is highly unlikely that it would expect an argument allocated with (some user-redefined) new[]!
(This answer applies to C++98 only.)
Please, don't use a raw char*.
std::string str = "string";
std::vector<char> chars(str.c_str(), str.c_str() + str.size() + 1u);
// use &chars[0] as a char*
If you just want a C-style string representing the same content:
char const* ca = str.c_str();
If you want a C-style string with new contents, one way (given that you don't know the string size at compile-time) is dynamic allocation:
char* ca = new char[str.size()+1];
std::copy(str.begin(), str.end(), ca);
ca[str.size()] = '\0';
Don't forget to delete[] it later.
If you want a statically-allocated, limited-length array instead:
size_t const MAX = 80; // maximum number of chars
char ca[MAX] = {};
std::copy(str.begin(), (str.size() >= MAX ? str.begin() + MAX : str.end()), ca);
std::string doesn't implicitly convert to these types for the simple reason that needing to do this is usually a design smell. Make sure that you really need it.
If you definitely need a char*, the best way is probably:
vector<char> v(str.begin(), str.end());
char* ca = &v[0]; // pointer to start of vector
This would be better as a comment on bobobobo's answer, but I don't have the rep for that. It accomplishes the same thing but with better practices.
Although the other answers are useful, if you ever need to convert std::string to char* explicitly without const, const_cast is your friend.
std::string str = "string";
char* chr = const_cast<char*>(str.c_str());
Note that this will not give you a copy of the data; it will give you a pointer to the string. Thus, if you modify an element of chr, you'll modify str.
Assuming you just need a C-style string to pass as input:
std::string str = "string";
const char* chr = str.c_str();
To obtain a const char * from an std::string use the c_str() member function :
std::string str = "string";
const char* chr = str.c_str();
To obtain a non-const char * from an std::string you can use the data() member function which returns a non-const pointer since C++17 :
std::string str = "string";
char* chr = str.data();
For older versions of the language, you can use range construction to copy the string into a vector from which a non-const pointer can be obtained :
std::string str = "string";
std::vector<char> str_copy(str.c_str(), str.c_str() + str.size() + 1);
char* chr = str_copy.data();
But beware that this won't let you modify the string contained in str, only the copy's data can be changed this way. Note that it's specially important in older versions of the language to use c_str() here because back then std::string wasn't guaranteed to be null terminated until c_str() was called.
To be strictly pedantic, you cannot "convert a std::string into a char* or char[] data type."
As the other answers have shown, you can copy the content of the std::string to a char array, or make a const char* to the content of the std::string so that you can access it in a "C style".
If you're trying to change the content of the std::string, the std::string type has all of the methods to do anything you could possibly need to do to it.
If you're trying to pass it to some function which takes a char*, there's std::string::c_str().
Here is one more robust version from Protocol Buffer
char* string_as_array(string* str)
{
return str->empty() ? NULL : &*str->begin();
}
// test codes
std::string mystr("you are here");
char* pstr = string_as_array(&mystr);
cout << pstr << endl; // you are here
Conversion in OOP style
converter.hpp
class StringConverter {
public: static char * strToChar(std::string str);
};
converter.cpp
char * StringConverter::strToChar(std::string str)
{
return (char*)str.c_str();
}
usage
StringConverter::strToChar("converted string")
For completeness' sake, don't forget std::string::copy().
std::string str = "string";
const size_t MAX = 80;
char chrs[MAX];
str.copy(chrs, MAX);
std::string::copy() doesn't NUL terminate. If you need to ensure a NUL terminator for use in C string functions:
std::string str = "string";
const size_t MAX = 80;
char chrs[MAX];
memset(chrs, '\0', MAX);
str.copy(chrs, MAX-1);
You can make it using iterator.
std::string str = "string";
std::string::iterator p=str.begin();
char* chr = &(*p);
Good luck.
A safe version of orlp's char* answer using unique_ptr:
std::string str = "string";
auto cstr = std::make_unique<char[]>(str.length() + 1);
strcpy(cstr.get(), str.c_str());
char* result = strcpy((char*)malloc(str.length()+1), str.c_str());
Alternatively , you can use vectors to get a writable char* as demonstrated below;
//this handles memory manipulations and is more convenient
string str;
vector <char> writable (str.begin (), str.end) ;
writable .push_back ('\0');
char* cstring = &writable[0] //or &*writable.begin ()
//Goodluck
This will also work
std::string s;
std::cout<<"Enter the String";
std::getline(std::cin, s);
char *a=new char[s.size()+1];
a[s.size()]=0;
memcpy(a,s.c_str(),s.size());
std::cout<<a;
No body ever mentioned sprintf?
std::string s;
char * c;
sprintf(c, "%s", s.c_str());

Best way to create a C String

I'm currently using
char *thisvar = "stringcontenthere";
to declare a string in C.
Is this the best way to declare a string in C?
And how about generating a C-String from C++-Strings?
In C it depends on how you'll use the string:
named constant: your char* str = "string"; method is ok (but should be char const*)
data to be passed to subfunction, but will not not used after the calling function returns:
char str[] = "string";
data that will be used after the function it is declared in exits: char* str = strdup("string");, and make sure it gets freed eventually.
if this doesnt cover it, try adding more detail to your answer.
As other suggested, and I you want to "do it" the C++ way, use a std::string.
If you somehow need a C-string, std::string has a method that gives a const char*.
Here is an example:
#include <iostream>
#include <string>
void dummyFunction(const char* str)
{
// Do something
}
int main(int, char**)
{
std::string str = "hello world!";
dummyFunction(str.c_str());
return EXIT_SUCCESS;
}
const char *thisvar="stringcontenthere";
It depends. For ASCII encoded strings see paragraphs C and C++. For unicode encoded strings see last paragraph.
C:
As David pointed out it depends on how to use the string in C:
as a constant then: const char s[] = "Hello World";
as a string containing variable data then: char s[] = "Hello World";
as a data array char *data; Initialization then should be customized.
Please note in C there are all Strings Null-terminated, that means the definition of e.g. char s[] = "foo"; implicitly includes a NULL character at the end s[3]='\0'.
Also please note the subtile difference between char *s and char s[] which might often behave the same but sometimes not! (see Is an array name a pointer?) for example:
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char* argv[])
{
char s[] = "123456789123456789123456789";
char *t = (char*) malloc( sizeof(char) * 28 );
for( size_t i = 0; i < 28; ++i )
t[ i ] = 'j';
printf( "%lu\n", sizeof(s) );
printf( "%lu\n", sizeof(t) );
printf( "%s\n", s );
printf( "%s\n", t );
return EXIT_SUCCESS;
}
So I recommend to use char arrays whenever you use them as strings and char pointers whenever you use them as data array.
C++:
In C++ there is an own string data type: std::string. If you just need to have a C-String version of a std::string (e.g. using some C-API) just use the c_str() member:
std::string s = "Hello World";
your_c_call( s.c_str(), ... );
Unicode:
I you want to have unicode strings then you should really go with something like
char utf8String[] = u8"Hello World";
and try not to use wchar_t whenever possible. See this excellent article on that issue: http://www.nubaria.com/en/blog/?p=289. Please not that there is also unicode support for C++. But generally I am tempted to say that you should go with normal characters as far as you can. Interesting resource on that: http://www.cprogramming.com/tutorial/unicode.html
Is this C or C++? In C++ you should use std::string:
std::string aString("stringcontenthere");