I'm trying to convert an std::string into a c string (my real problem is closer to this; I'm trying a workaround).
How does one store an std::string as a character array?
Why do std::string.data() and std::string.c_str() return char [(<anonymous> + 1)] instead of the expected const char*? Or do I have these mixed up, and if so, how do I work with these types?
#include <string>
#include <iostream>
int main()
{
std::string sstring = "I'm an std string!";
char cstring[sstring.size()];
cstring = sstring.c_str();
std::cout << std::string(sstring.c_str());
return 0;
}
Compilation results in
scratch.cpp:10:11: error: incompatible types in assignment of ‘const char*’ to ‘char [(<anonymous> + 1)]’
I wasn't able to find a relevant, preexisting question.
Just use a const char *
std::string sstring = "I'm an std string!";
const char * cstring = sstring.c_str();
std::cout << cstring << std::endl;
As mentioned in the comments, this sound like an XY problem. But if you simply want to copy the string you can do it like so:
char cstring[sstring.size() + 1];
strcpy(cstring, sstring.c_str());
Just be aware that VLAs are not a part of C++ but g++ will 'go with it', see answers here.
A working way to assign your string to a char array is the following:
#include <iostream>
#include <string>
int main(int argc, char **argv) {
std::string s = "HELLO WORLD!";
char *cs = (char *)s.c_str();
std::cout << cs << '\n' << std::string(cs) << '\n';
return 0;
}
OUTPUT:
This works because it casts the const char * to char * and therefore allows the assignment to go through, and although this may not be the best way it is very simple.
Related
I need Ptr to have first character of the string and BufLim to have last character of the string.
#include <iostream>
using namespace std;
int main()
{
const char* Str = "Stackoverflow";
const char* Ptr = Str[0];
const char* BufLim = &Ptr.back(); // pointer pointing to last character of *ptr
cout << Ptr;
cout << BufLim;
return 0;
}
Kindly help me on this.
Prior to c++17, use std::string instead of const char* string literals.
Then you can easily have the pointer to the first and the last char of the string by the help of member functions std::string::front and std::string::back respectively (given that the string is not empty).
#include <string>
using namespace std::string_literals;
std::string Str{ "Stackoverflow"s };
/* const */ char* ptrFirst = &Str.front();
/* const */ char* ptrLast = &Str.back();
std::cout << *ptrFirst << "\n"; // prints S
std::cout << *ptrLast; // prints w
(Alternatively) in c++17, you can use std::string_view, which is basically a wrapper around const char*. Like std::string, it has the same kind of member functions std::string_view::front and std::string_view::back
#include <string_view>
using namespace std::string_view_literals;
std::string_view Str{ "Stackoverflow"sv };
const char* ptrFirst = &Str.front();
const char* ptrLast = &Str.back();
std::cout << *ptrFirst << "\n"; // prints S
std::cout << *ptrLast; // prints w
I've tried to convert an integer to a hex null-terminated (or "C-style") string but I cannot use it with printf or my custom log function. It only works if I convert it to an std::string then use .c_str() when passing it as a parameter, which produces ugly, hard-to-understand code.
It's important to know that using std::string and appending to it with "str +=" does work.
const char* IntToHexString(int nDecimalNumber) {
int nTemp = 0;
char szHex[128] = { 0 };
char hex[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
while (nDecimalNumber > 0) {
nTemp = nDecimalNumber % 16;
sprintf(szHex, "%s%s", hex[nTemp], szHex);
nDecimalNumber = nDecimalNumber / 16;
}
sprintf(szHex, "0x%s", szHex);
return szHex;
}
I've tried to use Visual Studio Debugger but it doesn't show any error messages, because crashes somewhere in a DLL that has no symbols loaded
Your main problem is that you define a variable on the stack, locally in the function, and then return it.
After the function returns, the char* will point to "somewhere", to an undefined position. That is a major bug. You have also other bugs that have been commented on already. Like sprintf(szHex, "0x%s", szHex);, which is undefined behaviour (UB) or sprintf(szHex, "%s%s", hex[nTemp], szHex); which has the same problem + additionally a wrong format string.
The more C++ solution would be, as already shown in many posts:
#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>
std::string toHexString(unsigned int hexValue)
{
std::ostringstream oss;
oss << "0x" << std::hex << hexValue;
return std::string(oss.str());
}
int main()
{
std::cout << toHexString(15) << '\n';
// or directly
std::cout << "0x" << std::hex << 15 << '\n';
return 0;
}
Of course a C-Style solution is also possible.
But all the following I would not recommend:
If you want to stick to C like solution with char *, you could make the char szHex[128] = { 0 }; static. Or, even better, pass in the pointer to a buffer and return its address, like in
#include <stdio.h>
#include <iostream>
char* toHexCharP(unsigned int hexValue, char *outBuffer, const size_t maxSizeOutBuffer)
{
snprintf(outBuffer,maxSizeOutBuffer-1,"0x%X",hexValue);
return outBuffer;
}
constexpr size_t MaxBufSize = 100U;
int main()
{
char buf[MaxBufSize];
std::cout << toHexCharP(15, buf, MaxBufSize) << '\n';
return 0;
}
But as said, I would not recomend. Too dangerous.
Your solution should look as follows:
std::string IntToHexString(int nDecimalNumber) {
std::ostringstream str;
str << std::hex << nDecimalNumber;
return str.str();
}
// ...
std::string transformed = IntToHexString(123);
You can then use transformed.c_str() to get your string as const char*.
Unless you have reasons to do so, you should never work with const char* in modern C++. Use std::string::c_str() if you need to.
I want to change the characters in a string passed by user, converted into a C-style string and passed as an argument to a function with a char * argument:
#include <string>
#include <cstring>
#include <iostream>
#include <stdlib.h>
void functoupper(char *myString)
{
int i=0;
char z;
do {
z= myString[i];
myString[i]=toupper(z);
++i;
} while(myString[i]!=0);
}
int main() {
std::string name;
std::cout << "Please, enter your full name in small caps: ";
std::getline (std::cin,name);
const char *myString = name.c_str();
std::cout << "Hello, " << functoupper(myString) << "!\n";
return 0;
}
I get error error: invalid conversion from 'const char*' to 'char*' [-fpermissive] when calling function functoupper(myString) in main().
The std::string::c_str() method returns a pointer to const char data, but your function expects a pointer to non-const char data. That is why you are getting an error.
You could use const_cast to cast away the const (but that is not really advisable):
char *myString = const_cast<char*>(name.c_str());
functoupper(myString);
std::cout << "Hello, " << name << "!\n";
You could use the non-const std::string::operator[] to access the string's underlying character data (just be careful because prior to C++11, characters were not required to be stored contiguously in memory, but most std::string implementations did):
functoupper(&name[0]);
std::cout << "Hello, " << name << "!\n";
In C++17 and later, you can use the non-const std::string::data() method instead:
functoupper(name.data());
std::cout << "Hello, " << name << "!\n";
That being said, heed this warning when using toupper():
Like all other functions from <cctype>, the behavior of std::toupper is undefined if the argument's value is neither representable as unsigned char nor equal to EOF. To use these functions safely with plain chars (or signed chars), the argument should first be converted to unsigned char ... Similarly, they should not be directly used with standard algorithms when the iterator's value type is char or signed char. Instead, convert the value to unsigned char first
With that said, try something more like this:
#include <string>
#include <iostream>
#include <cctype>
void functoupper(char *myString)
{
for (int i = 0; myString[i] != '\0'; ++i) {
unsigned char z = static_cast<unsigned char>(myString[i]);
myString[i] = static_cast<char>(std::toupper(z));
}
}
int main() {
std::string name;
std::cout << "Please, enter your full name in small caps: ";
std::getline(std::cin, name);
functoupper(&name[0]); // or name.data()
std::cout << "Hello, " << name << "!\n";
return 0;
}
That being said, you should just pass the entire std::string as-is into your function instead, and then you can manipulate it as needed, for instance with the std::transform() algorithm:
#include <string>
#include <iostream>
#include <algorithm>
#include <cctype>
void functoupper(std::string &myString)
{
std::transform(myString.begin(), myString.end(), myString.begin(),
[](unsigned char ch){ return std::toupper(ch); }
);
}
int main() {
std::string name;
std::cout << "Please, enter your full name in small caps: ";
std::getline(std::cin, name);
functoupper(name);
std::cout << "Hello, " << name << "!\n";
return 0;
}
Alternatively:
#include <string>
#include <iostream>
#include <algorithm>
#include <cctype>
std::string functoupper(std::string myString)
{
std::transform(myString.begin(), myString.end(), myString.begin(),
[](unsigned char ch){ return std::toupper(ch); }
);
return myString;
}
int main() {
std::string name;
std::cout << "Please, enter your full name in small caps: ";
std::getline(std::cin, name);
std::cout << "Hello, " << functoupper(name) << "!\n";
return 0;
}
As #Someprogrammerdude and #RemyLebeau comment, why not simply:
std::transform(std::begin(name), std::end(name), std::begin(name),
[](const unsigned char c)
{
return std::toupper(c);
});
But if you must do it via a char*, then you'll need to copy the data over first, something like:
char myString* = new char[name.size() + 1];
strcpy(myString, name.c_str());
EDIT: Thanks to the helpful comments by #RemyLebeau
Better still avoid all the memory management issues with the above by simply coping your std::string into a std::vector:
std::vector<char> myVec(std::begin(name), std::end(name));
myVec.push_back(`\0`);
and then call your char* function with:
functoupper(myVec.data());
Here my problem: I want to write a float with max 2 decimal places into a string and print it without a couple of 0's behind the number.
The way I do it at the moment:
Values Material; // Class 'Values', Object 'Material'
Material.Temp = 15.56; // 'Temp' = float
string ss = to_string(Material.Temp); // Conversion to string
const char* cNumber = ss.c_str(); // Conversion to const char
HPDF_Page_ShowText(page, cNumber);
That prints out: 15.56000000
HPDF_Page_ShowText is a command of the open source library libharu to create PDF-Documents. It expects (page-object, *const char). That is the reason why the string has to be converted into a const char* first.
I really searched in the internet for similar problems, but found none that fit to mine.
Use a std::stringstream and std::setprecision() function in combination with the std::fixed stream manipulator:
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
int main(){
float myfloat = 15.56f;
std::stringstream ss;
ss << std::fixed << std::setprecision(2) << myfloat;
std::string s = ss.str();
std::cout << s;
}
The const char* variable can be obtained via:
const char* c = s.c_str();
Update:
Prefer std::ostringstream since the stream is used only for the output.
I am trying to read data from binary file to an std::string.Here is what I have tried at first.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main(int argc, char const *argv[])
{
fstream file("output.bin" , ios::out | ios::binary | ios::in);
string my_str(5, '\0');
file.read(my_str.c_str(), 5);
cout << "String = " << my_str<< endl ;
}
And the compiler gave the error :
error: invalid conversion from ‘const char*’ to ‘std::basic_istream<char>::char_type* {aka char*}’ [-fpermissive]
file.read(my_str.c_str(), 5);
As far as I understand, c_str() returns a const pointer which cannot be used in read method, so I changed my approach a little bit(which you can see below). Is there a better way to do this ?
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main(int argc, char const *argv[])
{
fstream file("output.bin" , ios::out | ios::binary | ios::in);
string my_str(5, '\0');
char buffer[6];
file.read(buffer, 5);
buffer[5] = '\0';
my_str = string(buffer);
cout << "String = " << my_str<< endl ;
}
ps : forgive me if I could not make myself clear, this is my first time here :)
In C++11, the way to get a non-const pointer to the string's data is:
file.read(&my_str[0], 5);
C++17 will introduce non-const data() for this as well:
file.read(my_str.data(), 5);
another way, using standard algorithms:
#include <iostream>
#include <string>
#include <fstream>
#include <algorithm>
#include <iterator>
using namespace std;
int main(int argc, char const *argv[])
{
fstream file("output.bin" , ios::out | ios::binary | ios::in);
auto my_str = string();
copy_n(istream_iterator<char>(file),
5,
std::back_inserter(my_str));
cout << "String = " << my_str<< endl ;
}
std::string is specially designed to work with strings and with c-style strings as well, so this fact will work against you in this situation. For example your code:
char buffer[6];
file.read(buffer, 5);
buffer[5] = '\0';
my_str = string(buffer);
what is wrong with it? You are reading binary data and who guarantees that there won't be '\0' byte there? You can fix it by:
my_str = string(buffer,5);
but this shows the point - std::string as a buffer is not a good choice. So you better use std::vector<char> or even better std::vector<uint8_t> which has method data() but will not implicitly convert from c-string, output to std::ostream etc.