Good methods for converting char array buffers to strings? - c++

I am relatively new to C++. Recent assignments have required that I convert a multitude of char buffers (from structures/sockets, etc.) to strings. I have been using variations on the following but they seem awkward. Is there a better way to do this kind of thing?
#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::endl;
char* bufferToCString(char *buff, int buffSize, char *str)
{
memset(str, '\0', buffSize + 1);
return(strncpy(str, buff, buffSize));
}
string& bufferToString(char* buffer, int bufflen, string& str)
{
char temp[bufflen];
memset(temp, '\0', bufflen + 1);
strncpy(temp, buffer, bufflen);
return(str.assign(temp));
}
int main(int argc, char *argv[])
{
char buff[4] = {'a', 'b', 'c', 'd'};
char str[5];
string str2;
cout << bufferToCString(buff, sizeof(buff), str) << endl;
cout << bufferToString(buff, sizeof(buff), str2) << endl;
}

Given your input strings are not null terminated, you shouldn't use str... functions. You also can't use the popularly used std::string constructors. However, you can use this constructor:
std::string str(buffer, buflen): it takes a char* and a length. (actually const char* and length)
I would avoid the C string version. This would give:
std::string bufferToString(char* buffer, int bufflen)
{
std::string ret(buffer, bufflen);
return ret;
}
If you really must use the C-string version, either drop a 0 at the bufflen position (if you can) or create a buffer of bufflen+1, then memcpy the buffer into it, and drop a 0 at the end (bufflen position).

If the data buffer may have null ('\0') characters in it, you don't want to use the null-terminated operations.
You can either use the constructor that takes char*, length.
char buff[4] = {'a', 'b', 'c', 'd'};
cout << std::string(&buff[0], 4);
Or you can use the constructor that takes a range:
cout << std::string(&buff[0], &buff[4]); // end is last plus one
Do NOT use the std::string(buff) constructor with the buff[] array above, because it is not null-terminated.

std::string to const char*:
my_str.c_str();
char* to std::string:
string my_str1 ("test");
char test[] = "test";
string my_str2 (test);
or even
string my_str3 = "test";

The method needs to know the size of the string. You have to either:
in case of char* pass the length to
method
in case of char* pointing to null
terminating array of characters you can
use everything up to null
character
for char[] you can use templates to
figure out the size of the char[]
1) example - for cases where you're passing the bufflen:
std::string bufferToString(char* buffer, int bufflen)
{
return std::string(buffer, bufflen);
}
2) example - for cases where buffer is points to null terminated array of characters:
std::string bufferToString(char* buffer)
{
return std::string(buffer);
}
3) example - for cases where you pass char[]:
template <typename T, size_t N>
std::string tostr(T (&array)[N])
{
return std::string(array, N);
}
Usage:
char tstr[] = "Test String";
std::string res = tostr(tstr);
std::cout << res << std::endl;
For the first 2 cases you don't actually have to create new method:
std::string(buffer, bufflen);
std::string(buffer);

std::string buf2str(const char* buffer)
{
return std::string(buffer);
}
Or just
std::string mystring(buffer);

Use string constructor that takes the size:
string ( const char * s, size_t n );
Content is initialized to a copy of the string formed by the first n
characters in the array of characters
pointed by s.
cout << std::string(buff, sizeof(buff)) << endl;
http://www.cplusplus.com/reference/string/string/string/
Non-null-terminated buffer to C string:
memcpy(str, buff, buffSize);
str[bufSize] = 0; // not buffSize+1, because C indexes are 0-based.

string value (reinterpret_cast(buffer), length);

Related

Getting char * or const char * data from a string breaks for 16 character strings or longer

I have a function string_to_char() which attempts to give me a form of a string which I can pass into a library I am using, which wants char * (but I think works with const char *, so I've been trying both).
The code I wrote to test my implementation of string_to_char() goes as such:
#include <iostream>
const std::string endl = "\n";
char * string_to_char(std::string str)
{
return (char*) str.c_str();
}
int main()
{
std::string test1 = "Some test strin";
std::string test2 = "Some test string";
char * result1 = string_to_char(test1);
char * result2 = string_to_char(test2);
std::cout << "part1" << endl;
std::cout << result1 << endl;
std::cout << string_to_char(test1) << endl;
std::cout << "part2" << endl;
std::cout << result2 << endl;
std::cout << string_to_char(test2) << endl;
std::cout << "done" << endl;
return 0;
}
This is the output I get:
part1
Some test strin
Some test strin
part2
Some test string
done
So for some reason, string_to_char() only properly works with strings with 15 characters or shorter, and outputs from the function straight to std::cout, but can't seem to store it to a variable for 16 characters or longer.
I am relatively new to C++ so some of the code below may seem a bit strange to more experienced programmers, but here is the code that I have tried in place of return (char*) str.c_str();
#include <vector>
#include <string.h>
char * string_to_char(std::string str)
{
return (char*) str.c_str();
return const_cast<char*>(str.c_str());
std::vector<char> vec(str.begin(), str.end());
char * chr;
vec.push_back('\0');
chr = (char*) &vec[0];
//chr = & (*vec.begin());
return chr; //all outputs from both are empty with this both versions of chr
return &str[0]; //this makes the output from the 15 character string also be empty when put in a
//variable, but the function going directly to std::cout is fine
return strcpy((char *) malloc(str.length() + 1), str.c_str()); //this one works with everything, but
//it looks like it leaks memory without further changes
std::vector<char> copied(str.c_str(), str.c_str() + str.size() + 1);
return copied.data(); //returns "random" characters/undefined behaviour for both outputs in test1 and is empty for both
//outputs in test2
}
Using const instead, and changing char * result1 = string_to_char(test1); to const char * result1 = string_to_char(test1); (as with result2), to see if that works with these other solutions:
#include <vector>
#include <string.h>
const char * string_to_char(std::string str)
{
return (char*) str.c_str();
return str.c_str();
return (const char*) str.c_str();
return str.data();
return const_cast<char*>(str.c_str());
std::vector<char> vec(str.begin(), str.end());
char * chr;
vec.push_back('\0');
chr = (char*) &vec[0];
//chr = & (*vec.begin());
return chr; //completely breaks both
return &str[0]; //both appear empty when given to a variable, but works fine when taken straight to std::cout
return strcpy((char *) malloc(str.length() + 1), str.c_str()); //memory leak, as when not using const
std::vector<char> copied(str.c_str(), str.c_str() + str.size() + 1);
return copied.data(); //same as when not using const
}
I got a lot of the given methods from:
std::string to char*
string.c_str() is const?
How to convert a std::string to const char* or char*?
Converting from std::string to char * in C++
With a bit of reading around the topic for strings and vectors at https://www.cplusplus.com/reference/ and https://en.cppreference.com/w/
The pointer returned from c_str() is only valid as long as the string is alive. You get expected output when you pass a reference:
auto string_to_char(std::string& str)
{
return str.c_str();
}
Because now the pointer returned is into the buffer of the string of the caller. In your code the caller gets a pointer to the functions local string (because you pass a copy).
Though, instead of calling the function you can directly call c_str(). That also mitigates the problem of holding on to the pointer after the string is gone to some extend.
You've overthought this. There is no need two write this function yourself. std::string::data already exists and returns a pointer to the string's null-terminated internal buffer. Assuming you're using C++17 or later, this pointer will be const char* if the std::string object is const-qualified (i.e. read-only), and otherwise will be a modifiable char*.
std::string test1 = "string";
const std::string test2 = "const string";
char* result1 = test1.data();
const char* result2 = test2.data();
This pointer is valid for as long as the std::string object that it came from is alive and is not modified (except for modifying individual elements).
Also note that casting pointers and casting away const-ness is a very easy way to cause Undefined Behaviour without knowing it. You should avoid C-style casts in general (e.g. (char*)str.c_str()) because they're very unsafe. See this Q/A on the proper use of C++ casts for more information.
Live Demo
Documentation
string_to_char() is taking its str parameter by value, so a copy of the caller's input string is made. When the function exits, that copied std::string will be destroyed. Thus, the returned char* pointer will be left dangling, pointing to freed memory, and any use of that pointer to access the data will be undefined behavior.
Pass in the str parameter by reference instead:
char* string_to_char(std::string &str)
{
return const_cast<char*>(str.c_str());
}
Or, in C++17 and later, you can use this instead:
char* string_to_char(std::string &str)
{
return str.data();
}
Which then begs the question of why you need string_to_char() at all and don't just use data() directly, unless you are not using a modern version of C++.

Dynamic array of fixed length strings

How do I create a dynamic array of fixed length strings?
I created class AString which has pointers to struct _str which has fixed-length array data.
How to assign values, and what is wrong?
#include "stdafx.h"
#include <iostream>
struct _str {
char data[20];
};
class AString {
public:
AString();
~AString();
void Add(_str string);
private:
_str *str;
int count;
};
AString::AString() {
std::cout << "Constructor" << std::endl;
str = nullptr;
count = 0;
}
AString::~AString() {
std::cout << "Destructor" << std::endl;
if (str != nullptr) delete[] str;
}
void AString::Add(_str string) {
_str *str2 = new _str[count+1];
for (int i=0;i<count;i++) {
str2[i] = str[i];
}
delete[] str;
str = str2;
count++;
str[count-1] = string;
}
int _tmain(int argc, _TCHAR* argv[])
{
AString astring;
_str str1;
str1.data="0123456789012345678"; // cannot convert from 'const char[20]' to 'char[20]'
astring.Add(str1);
std::cin.get();
return 0;
}
str1.data="0123456789012345678";: cannot convert from 'const char[20]' to 'char[20]'
Want to:
not use _str str1;, and use char str1[20];
As for me, I used this:
strcpy(str1.data, "0123456789012345678");
Here is the main:
int main(int argc, char* argv[])
{
AString astring;
_str str1;
//str1.data=const_cast<char>("0123456789012345678"); // cannot convert from 'const char[20]' to 'char[20]'
strcpy(str1.data, "0123456789012345678");
astring.Add(str1);
std::cout << str1.data;
std::cin.get();
return 0;
}
The result is as follows:
Constructor
0123456789012345678
First of all, I would recomend you yo use std::string or std::array. But if you forced to use char[], I would recomend you to use strncpy instead of operator =, so it would looks like this
strncpy(str1.data,"0123456789012345678", 20); // cannot convert from 'const char[20]' to 'char[20]'
To copy char* or block of memory, it is better to use memcpy!
void* memcpy (void* destination, const void* source, size_t length);
It copies the values of length bytes starting the location pointed to by source directly to the memory block pointed to by destination. Note that, the underlying type of the objects pointed to by both the source and destination pointers dose not matter.
You can also use strncpy.
char* strncpy(char* destination, const char* source, size_t length);
It works properly for your code but if there is/are some 0 valued bytes, the strncpy consider it as null-termination and coping continued with '0' i.e. (pad) until length is satisfied.
try
memcpy(str1.data, "0123456789012345678", 20);
You can't assign to arrays - that's just the way it is.
You could use strncpy in main, or get an assignable array with std::array<char, 20>, but if there was a need to do this by hand, I would add constructors (and hide the implementation details) in order to keep things safe:
class _str {
public:
typedef char base[20];
_str() { data[0] = 0; }
_str(const base& in) { strncpy(data, in, 20); }
const base& get() const { return data; }
private:
base data;
};
and then you can
AString astring;
_str str1 = "01234567890123456789"; // Fine
astring.Add(str1);
std::cout << str1.get();
_str str2 = "012345678901234567890"; // Compilation error
_str str3 = "0"; // Compilation error

Reversing a string in C++ using pointers

void reverse(char[] x) {
char* pStart = x;
char* pEnd = pStart + sizeof(x) - 2;
while(pStart < pEnd) {
char temp = *pStart;
*pStart = *pEnd;
*pEnd = temp;
pStart++;
pEnd--;
}
}
int main() {
char text[] = ['h','e','l','l','o'];
reverse(text);
cout << text << endl;
return 0;
}
I am new to C++ and stack overflow.
I am trying to reverse a string using pointers... I don't quite understand what I did wrong. Please help me out.
Additional question: What is the difference between a string and an array of characters?
sizeof(x) with x being a parameter of type char[] of a function does not give you the number of characters in the string but the size of a char*, probably 8 on a 64 bit system. You need to pass a C-String and use strlen(x) instead. Write char text[] = {'h','e','l','l','o','\0'} or char text[] = "hello" in main.
Note that sizeof() needs to be evaluatable at compile time; this is not possible on arrays with undetermined size like char[]-typed function arguments. When using sizeof on a variables like your char text[] = {'h','e','l','l','o'}, however, sizeof(text) will result in the actual size of the array.
char x[] is the same as char* x and the sizeof(x) is therefore the size of a pointer. So, because you cannot calculate the size of an array outside of the block it is declared in, I would eliminate that part from your function.
It would be much easier to provide the function with pointers to the first and last characters to be replaced:
void reverse(char* pStart, char* pEnd)
{
while (pStart < pEnd)
{
char temp = *pStart;
*pStart = *pEnd;
*pEnd = temp;
pStart++;
pEnd--;
}
}
So now it is quite easy to call this function - take the address (using ampersand &) of the the relevant characters in the array: &text[0] and &text[4].
To display an array of characters, there is a rule, that such "strings" HAVE to have after the last character a NULL character. A NULL character can be written as 0 or '\0'. That is why it has to be added to the array here.
int main()
{
// char text[] = "hello"; // Same like below, also adds 0 at end BUT !!!in read-only memory!!
char text[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
reverse(&text[0], &text[4]);
std::cout << text << std::endl;
return 0;
}

C++ creating a string from char array elements?

I have a char array which is VERY large and I iterate through the array. I look for patterns with logic such as:
if (array[n] == 'x' and array[n+1] == 'y' and array[n+2] == 'z')
{
mystring = array[n+4] + array[n+5];
}
if array[n+4] is '4' and array[n+5] is '5' then mystring = "45"
However, mystring is always "", what am I doing wrong? I don't want to use substring as the array is too large. I just want to cast the chars to strings and then append to mystring.
I suggest so use assign(const char*, len);
no copy constructor is involved
if (array[n] == 'x' and array[n+1] == 'y' and array[n+2] == 'z')
{
mystring.assign(array + n + 4, 2);
}
You're checking for a consecutive "xyz" occurrence , why not simply use std::string ?
std::string s(array);
size_t i =s.find("xyz");
if(i!=std::string::npos && i+5 <= s.size())
{
std::string mystring = std::string(1,array[i + 4]) + array[i + 5];
std::cout<<mystring;
}
You can cast chars to ints and vice versa because they are basic language types. Strings are implemented as a class so you need to invoke the string constructor for both chars then concatenation the two resulting strings into mystring
If you can't use std::string in the first place, as suggested by #P0W (which is a good suggestion), then there is another alternative to do this conversion that does not involve string constructor (I think the solution using string constructor is a great one, but knowing different approaches can give you more flexibility), but relies on std::string::append.
int main ()
{
// create char
char *str1 = new char[6];
strcpy( str1,"hello ");
char *str2 = new char[5];
strcpy(str2, "world" );
// use of append to convert to a string
std::string mystring;
mystring.append(str1);
mystring.append(str2);
std::cout << mystring << std::endl;
}
Check the std::string::append documentation, and you will also see that one of the overloading of this functions is string& append (const char* s, size_t n), which means you can convert just subset of char arrays, as you request it.
Adding characters strings doesn't work like that in C++. The easier way to do this is to create a stringstream and add the characters to the string with the << operator, then recover a string from it using the str() method.
Example:
#include <iostream>
#include <sstream>
using namespace std;
int main(void)
{
char a[] = {'a', 'd', 'c', 'b', 'a' };
stringstream linestream;
linestream << a[0] << a[1];
cout << linestream.str() << endl; // Prints ad
return 0;
}

Convert char* to string C++

I know the starting address of the string(e.g., char* buf) and the max length int l; of the string(i.e., total number of characters is less than or equal to l).
What is the simplest way to get the value of the string from the specified memory segment? In other words, how to implement string retrieveString(char* buf, int l);.
EDIT: The memory is reserved for writing and reading string of variable length. In other words, int l;indicates the size of the memory and not the length of the string.
std::string str(buffer, buffer + length);
Or, if the string already exists:
str.assign(buffer, buffer + length);
Edit: I'm still not completely sure I understand the question. But if it's something like what JoshG is suggesting, that you want up to length characters, or until a null terminator, whichever comes first, then you can use this:
std::string str(buffer, std::find(buffer, buffer + length, '\0'));
char *charPtr = "test string";
cout << charPtr << endl;
string str = charPtr;
cout << str << endl;
Use the string's constructor
basic_string(const charT* s,size_type n, const Allocator& a = Allocator());
EDIT:
OK, then if the C string length is not given explicitly, use the ctor:
basic_string(const charT* s, const Allocator& a = Allocator());
There seems to be a few details left out of your explanation, but I will do my best...
If these are NUL-terminated strings or the memory is pre-zeroed, you can just iterate down the length of the memory segment until you hit a NUL (0) character or the maximum length (whichever comes first). Use the string constructor, passing the buffer and the size determined in the previous step.
string retrieveString( char* buf, int max ) {
size_t len = 0;
while( (len < max) && (buf[ len ] != '\0') ) {
len++;
}
return string( buf, len );
}
If the above is not the case, I'm not sure how you determine where a string ends.
std::string str;
char* const s = "test";
str.assign(s);
string& assign (const char* s); => signature FYR
Reference/s here.
Let,
char* rw="hii"; //This string is readable and writeable
const char* r="hello"; // This string is only readable
we can convert char* or const char* to string with the help of string's constructor.
string string_name(parameter);
This parameter accepts both char* and const char* types .
Examples:
1) string st(rw);
Now string 'st', contains "hii"
2) string st(r);
Now, string 'st' contains "hello".
In both the examples, string 'st' is writable and readable.