How to convert string to char* using stringstream? - c++

I have a function like this:
template <typename T>
void parse_to_T(const std::string& str, T* result) {
std::stringstream ss;
ss << str;
ss >> *result;
}
this function is mean to convert the string to the specified type.
it is work to parse the string to int, float or char.
parse_to_T<int>(...);
parse_to_T<float>(...);
parse_to_T<char>(...);
but when meet char*, segment fault ...
I use the function like this:
int int_val;
string m = "1";
parse_to_T<int>(m, &int_val); // works
char* str_val = NULL;
parse_to_T<char*>(m, &str_val); // segmentfault
How to imply this function to make it work?
(convert the string to specified type like int, double, char, char*)?
Hey, I don't know how to explain my use case, but I will try:
To simple, the question is, given a file, for each line, data may have these types :
int
float
char
char*
an array T[num] (T is int, float, char or char*, or any build_in type.)
imple a parse function to parse this file.
and this problem is an exam ...
thanks and I found the error now.
char* str_val = NULL;
parse_to_T<char*>(m, &str_val); // segmentfault;
char* str_val;
parse_to_T<char*>(m, &str_val); // segmentfault;
char* str_val = new char[256];
parse_to_T<char*>(m, &str_val); // works !!
then the error is I didn't allocate memory to the ptr...

This segfault is because stringstream does not allocate memory to hold the result of the operation when extracting values into a char* array. It tries to put the values into the memory pointed at by the lhs operand. You must allocate memory yourself.
Here is a simple example:
#include <string>
#include <sstream>
#include <iostream>
template <typename T>
void parse_to_T(const std::string& str, T* result) {
std::stringstream ss;
ss << str;
std::cout << ss.str() << std::endl;
ss >> *result;
std::cout << *result << std::endl;
}
int main() {
char* buffer = new char[256];
/* Don't do this in real code. If the input is larger than
the size of the buffer it will end very, very badly.
always have a way of allocating the correct amount
of memory.
*/
int int_val;
std::string m = "1";
parse_to_T<int>(m, &int_val);
char* str_val = NULL;
parse_to_T<char*>(m, &buffer);
delete[] buffer;
return 0;
}
You could include a template specialization for the char* datatype that does the allocation based on the amount of data in the stream (calling stringstream.str().size() should work) but the user would have to free the returned memory.

First, your destination variable str_val has no allocated memory, so it is normal you have a segmentation fault.
On the other hand, it would be better if you use std::string instead. If you need the raw pointer const char* then you can use std::string::c_str for so. If you have to modify it then just create a copy.

Related

How to convert a double variable into a char array?

I'm working on a project for school, and we just found out that outtextxy() (a function from graphics.h, which we must use) requires as the text parameter a char array.
Here is its declaration: void outtextxy (int x, int y, char *textstring)
The issue is that we need to print out a number of type double, including the decimal point. I have previously tried making it work using knowledge from other similar questions, but none has worked.
Here are is my latest attempt, which resulted in a Segmentation Fault:
char *DoubleToString(long double x)
{
char s[256]="\000";
std::ostringstream strs;
strs << x;
string ss = strs.str();
for(int i=0; i < ss.length(); i++)
s[i] = ss[i];
return s;
}
NOTE: I am still somewhat new to programming and I don't exactly know what ostringstream and the bitshift-looking operation are doing, but I tried to copy-paste that part in hopes of it working.
... requires as the text parameter a char array.
Ok, then use a std::string:
std::string DoubleToString(long double x)
{
std::ostringstream strs;
strs << x;
return strs.str();
}
If you need the underlying character array use the strings data() method. It does return a pointer to the first element of the strings character array. For example:
std::string s = DoubleToString(3.141);
function_that_needs_pointer_to_char( s.data() );
Note that before C++17 data returned a const char* (and since C++11 the character array is null-terminated, as one would expect ;).
I know it is undefined behaviour, but it works. And I only need to pass the returned char* to outtextxy(), and not manipulate it later on, since I have the double variable stored in an object.
char *DoubleToString(long double x)
{
char s[256]="\000";
std::ostringstream strs;
strs << x;
string sd = strs.str();
strcpy(s, sd.data());
return s;
}

Filling char pointer correctly

I have a char pointer:
char* s = new char[150];
Now how do i fill it? This:
s="abcdef";
Gives warning about deprecation of conversion between string literal and char*, but generally works.
This:
char* s = new[150]("abcdef");
Does not work, gives an error.
How to do this properly? Note that I want the memory allocation to have 150*sizeof(char) bytes and contain "abcdef". I know about malloc, but is it possible to do with new?
Its for an assignment where i cant use the standard library.
This sequence of statements
char* s = new char[150];
s="abcdef";
results in a memory leak because at first a memory was allocated and its address was assigned to the pointer s and then the pointer was reassigned with the address of the string literal "abcdef". And moreover string literals in C++ (opposite to C) have types of constant character arrays.
If you allocated a memory for a string then you should copy a string in the memory either by using the C standard function strcpy or C standard function strncpy.
For example
char* s = new char[150];
std::strcpy( s, "abcdef" );
Or
const size_t N = 150;
char* s = new char[N];
std::strncpy( s, "abcdef", N );
s[N-1] = '\0';
Or even the following way
#include <iostream>
#include <cstring>
int main()
{
const size_t N = 150;
char *s = new char[N]{ '\0' };
std::strncpy( s, "abcdef", N - 1 );
std::cout << s << '\n';
delete []s;
}
In any case it is better just to use the standard class std::string.
std::string s( "abcdef" );
or for example
std::string s;
s.assign( "abcdef" );
The basic procedure for creating a memory area for a string and then filling it without using the Standard Library in C++ is as follows:
create the appropriate sized memory area with new
use a loop to copy characters from a string into the new area
So the source code would look like:
// function to copy a zero terminated char string to a new char string.
// loop requires a zero terminated char string as the source.
char *strcpyX (char *dest, const char *source)
{
char *destSave = dest; // save copy of the destination address to return
while (*dest++ = *source++); // copy characters up to and including zero terminator.
return destSave; // return destination pointer per standard library strcpy()
}
// somewhere in your code
char *s1 = new char [150];
strcpyX (s1, "abcdef");
Given a character array:
char * s = new char [256];
Here's how to fill the pointer:
std::fill(&s, &s + sizeof(s), 0);
Here's how to fill the array:
std::fill(s, s+256, '\0');
Here's how to assign or copy text into the array:
std::strcpy(s, "Hello");
You could also use std::copy:
static const char text[] = "World";
std::copy(text, text + sizeof(text), s);
Remember that a pointer, array and C-Style string are different concepts and objects.
Edit 1: Prefer std::string
In C++, prefer to use std::string for text rather than character arrays.
std::string s;
s = "abcdef";
std::cout << s << "\n";
Once you've allocated the memory for this string, you could use strcpy to populate it:
strcpy(s, "abcdef");

c++: Storing an adress as string

I'm trying to store the address of a pointer as a string. In other words, I want to insert the content of the bytes that make up the address into a char vector.
What is the best way of doing this?
I need a fully portable method, including for 64 bit system.
To get an array (or vector, if you prefer that) of the actual bytes of the address, this should do the trick:
int foo = 10;
int* bar = &foo;
// Interpret pointer as array of bytes
unsigned char const* b = reinterpret_cast<unsigned char const*>(&bar);
// Copy that array into a std::array
std::array<unsigned char, sizeof(void*)> bytes;
std::copy(b, b + sizeof(void*), bytes.begin());
To get an array containing the hexadecimal representation split up into single characters (whatever sense that makes), I'd use a stringstream - as some of the others already suggested. You can also use snprintf to get a string representation of the address, but that's more the C-style way.
// Turn pointer into string
std::stringstream ss;
ss << bar;
std::string s = ss.str();
// Copy character-wise into a std::array (1 byte = 2 characters)
std::array<char, sizeof(void*) * 2> hex;
std::copy(s.begin(), s.end(), hex.begin());
The simplest way is to do
char buf[sizeof(void*) * 2 + 3];
snprintf(buf, sizeof(buf), "%p", /* the address here */ );
std::string serialized (std::to_string ((intptr_t) ptr));
C++ way to dos this would be to use string streams
#include <string>
#include <sstream>
int main()
{
MyType object;
std::stringstream ss;
std::string result;
ss << &object; // puts the formatted address of object into the stream
result = ss.str(); // gets the stream as a std::string
return 0;
}
void storeAddr(vector<string>& v,void *ptr)
{
stringstream s;
s << (void*)ptr ;
v.push_back(s.str());
}

C++ char* array

When I create something like
char* t = new char[44];
t = strcpy(s,t);
then strlen(t); return some wrong results. how I can change this?
Both strcpy and strlen expect to find the special character NUL or '\0' in the array. An uninitialized array, as the one you've created, may contain anything at all, which means the behavior of your program is undefined when it is passed to strcpy as the source argument.
Assuming the goal was to copy s into t, to make the program behave as expected, try this:
#include <iostream>
#include <cstring>
int main()
{
const char* s = "test string";
char* t = new char[44];
// std::strcpy(t, s); // t is the destination, s is the source!
std::strncpy(t, s, 44); // you know the size of the target, use it
std::cout << "length of the C-string in t is " << std::strlen(t) << '\n';
delete[] t;
}
But keep in mind that in C++, strings are handled as objects of type std::string.
#include <iostream>
#include <string>
int main()
{
const std::string s = "test string";
std::string t = s;
std::cout << "length of the string in t is " << t.size() << '\n';
}
What are you trying to do? Do you want to copy from s to t? If so, the arguments to strcpy are reversed.
char* t = new char[44]; // allocate a buffer
strcpy(t,s); // populate it
Such C-style string processing is a red flag, but that's all I can say given this little information.
This code might be helpful:
char * strcpy (char * destination, const char * source);
t = strcpy(t, s);
You have to initialize the variable t
Do something like this:
char *t = new char[44];
memset(t, 0, 44);
// strlen(t) = 0
The strcpy function is described thus:
#include <string.h>
char *strcpy(char *dest, const char *src);
The strcpy() function copies the string pointed to by src (including the terminating '\0' character) to the array pointed to by dest.
So, if you are trying to fill in your newly allocated array, you should be doing:
strcpy(t, s);
Not the other way around.

how to copy char * into a string and vice-versa

If i pass a char * into a function. I want to then take that char * convert it to a std::string and once I get my result convert it back to char * from a std::string to show the result.
I don't know how to do this for conversion ( I am not talking const char * but just char *)
I am not sure how to manipulate the value of the pointer I send in.
so steps i need to do
take in a char *
convert it into a string.
take the result of that string and put it back in the form of a char *
return the result such that the value should be available outside the function and not get destroyed.
If possible can i see how it could be done via reference vs a pointer (whose address I pass in by value however I can still modify the value that pointer is pointing to. so even though the copy of the pointer address in the function gets destroyed i still see the changed value outside.
thanks!
Converting a char* to a std::string:
char* c = "Hello, world";
std::string s(c);
Converting a std::string to a char*:
std::string s = "Hello, world";
char* c = new char[s.length() + 1];
strcpy(c, s.c_str());
// and then later on, when you are done with the `char*`:
delete[] c;
I prefer to use a std::vector<char> instead of an actual char*; then you don't have to manage your own memory:
std::string s = "Hello, world";
std::vector<char> v(s.begin(), s.end());
v.push_back('\0'); // Make sure we are null-terminated
char* c = &v[0];
You need to watch how you handle the memory from the pointer you return, for example the code below will not work because the memory allocated in the std::string will be released when fn() exits.
const char* fn(const char*psz) {
std::string s(psz);
// do something with s
return s.c_str(); //BAD
}
One solution is to allocate the memory in the function and make sure the caller of the function releases it:
const char* fn(const char*psz) {
std::string s(psz);
// do something with s
char *ret = new char[s.size()]; //memory allocated
strcpy(ret, s.c_str());
return ret;
}
....
const char* p = fn("some text");
//do something with p
delete[] p;// release the array of chars
Alternatively, if you know an upper bound on the size of the string you can create it on the stack yourself and pass in a pointer, e.g.
void fn(const char*in size_t bufsize, char* out) {
std::string s(psz);
// do something with s
strcpy_s(out, bufsize, s.c_str()); //strcpy_s is a microsoft specific safe str copy
}
....
const int BUFSIZE = 100;
char str[BUFSIZE];
fn("some text", BUFSIZE, str);
//ok to use str (memory gets deleted when it goes out of scope)
You can maintain a garbage collector for your library implemented as
std::vector<char*> g_gc; which is accessible in your library 'lib'. Later, you can release all pointers in g_gc at your convenience by calling lib::release_garbage();
char* lib::func(char*pStr)
{
std::string str(pStr);
char *outStr = new char[str.size()+1];
strcpy(outStr, str.c_str());
g_gc.push_back(outStr); // collect garbage
return outStr;
}
release_garbage function will look like:
void lib::release_garbage()
{
for(int i=0;i<g_gc.size();i++)
{
delete g_gc[i];
}
g_gc.clear();
}
In a single threaded model, you can keep this g_gc static. Multi-threaded model would involve locking/unlocking it.