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.
Related
I've been reading a book for self study (http://www.amazon.com/gp/product/0321992784) and I'm on chapter 17 doing the exercises. One of them I solved, but I'm not satisfied and would like some help. Thank you in advanced.
The Exercise: Write a program that reads characters from cin into an array that you allocate on the free store. Read indvidual characters until an exclamation mark(!) is entered. Do not use std::string. Do not worry about memory exhaustion.
What I did:
char* append(const char* str, char ch); // Add a character to the string and return a duplicate
char* loadCstr(); // Read characters from cin into an array of characters
int main()
{
char* str{ loadCstr() };
std::cout << str << '\n';
return 0;
}
I made 2 functions, 1 to create a new string with a size 1 larger than the old and add a character at the end.
char* append(const char* str, char ch)
/*
Create a new string with a size 1 greater than the old
insert old string into new
add character into new string
*/
{
char* newstr{ nullptr };
int i{ 0 };
if (str)
newstr = new char [ sizeof(str) + 2 ];
else
newstr = new char [ 2 ];
if(str)
while (str [ i ] != '\0')
newstr [ i ] = str [ i++ ]; // Put character into new string, then increment the index
newstr [ i++ ] = ch; // Add character and increment the index
newstr [ i ] = '\0'; // Trailing 0
return newstr;
}
This is the function for the exercise using the append function I created, It works, but from what I understand each time I call append, there is a memory leak because I create a new character array and didn't delete the old.
char* loadCstr()
/*
get a character from cin, append it to str until !
*/
{
char* str{ nullptr };
for (char ch; std::cin >> ch && ch != '!';)
str = append(str, ch);
return str;
}
I tried adding another pointer to hold the old array and delete it after making a new one, but after about 6 calls in this loop I get a runtime error that I think tells me I'm deleting something I shouldn't? which is where I got confused.
This is the old one that doesn't work beyond 6 characters:
char* loadCstr()
/*
get a character from cin, append it to str until !
*/
{
char* str{ nullptr };
for (char ch; std::cin >> ch && ch != '!';) {
char* temp{ append(str, ch) };
if (str)
delete str;
str = temp;
}
return str;
}
So I want to know how I can fix this function so there are no memory leaks. Thank you again. (Also please note, I do know these functions already exist and using std::string handles all the free store stuff for me, I just want to understand it and this is a learning exercise.)
You have to use standard C function std::strlen instead of the sizeof operator because in case of your function the sizeof operator returns the size of pointer instead of the length of the string.
Also you need to delete already allocated array.
The function can look the following way
char* append(const char* str, char ch)
/*
Create a new string with a size 1 greater than the old
insert old string into new
add character into new string
*/
{
size_t n = 0;
if ( str ) n = std::strlen( str );
char *newstr = new char[ n + 2 ];
for ( size_t i = 0; i < n; i++ ) newstr[i] = str[i];
delete [] str;
newstr[n] = ch;
newstr[n+1] = '\0';
return newstr;
}
And in the function loadCstr it can be called like
str = append( str, ch );
Also instead of the loop to copy the string you could use standard algorithm std::copy
Is the point to learn about memory management, or about how string operations work internally?
For the second (learning about string operations), you should use std::unique_ptr<char[]> which will automatically free the attached array when the pointer dies. You'll still need to calculate string length, copy between strings, append -- all the things you are doing now. But std::unique_ptr<char[]> will handle the deallocation.
For the first case, you're better off writing an RAII class (custom version of std::unique_ptr<T>) and learning how to free memory in a destructor, than scattering delete [] statements all over your code. Writing delete [] everywhere is actually a bad habit, learning it will move your ability to program C++ backwards.
After trying for about 1 hour, my code didn't work because of this:
void s_s(string const& s, char data[10])
{
for (int i = 0; i < 10; i++)
data[i] = s[i];
}
int main()
{
string ss = "1234567890";
char data[10];
s_s("1234567890", data);
cout << data << endl;//why junk
}
I simply don't understand why the cout displays junk after the char array. Can someone please explain why and how to solve it?
You need to null terminate your char array.
std::cout.operator<<(char*) uses \0 to know where to stop.
Your char[] decays to char* by the way.
Look here.
As already mentioned you want to NUL terminate your array, but here's something else to consider:
If s is your source string, then you want to loop to s.size(), so that you don't loop past the size of your source string.
void s_s(std::string const& s, char data[20])
{
for (unsigned int i = 0; i < s.size(); i++)
data[i] = s[i];
data[s.size()] = '\0';
}
Alternatively, you can try this:
std::copy(ss.begin(), ss.begin()+ss.size(),
data);
data[ss.size()] = '\0';
std::cout << data << std::endl;
You have ONLY allocated 10 bytes for data
The string is actually 11 bytes since there is an implied '\0' at the end
At a minimum you should increase the size of data to 11, and change your loop to copy the '\0' as well
The function std::ostream::operator<< that you are trying to use in the last line of the main will take your char array as a pointer and will print every char until the null sentinel character is found (the character is \0).
This sentinel character is generally generated for you in statements where a C-string literal is defined:
char s[] = "123";
In the above example sizeof(s) is 4 because the actual characters stored are:
'1', '2', '3', '\0'
The last character is fundamental in tasks that require to loop on every char of a const char* string, because the condition for the loop to terminate, is that the \0 must be read.
In your example the "junk" that you see are the bytes following the 0 char byte in the memory (interpreted as char). This behavior is clearly undefined and can potentially lead the program to crash.
One solution is to obviously add the \0 char at the end of the char array (of course fixing the size).
The best solution, though, is to never use const char* for strings at all. You are correctly using std::string in your example, which will prevent this kind of problems and many others.
If you ever need a const char* (for C APIs for example) you can always use std::string::c_str and retrieve the C string version of the std::string.
Your example could be rewritten to:
int main(int, char*[]) {
std::string ss = "1234567890";
const char* data = ss.c_str();
std::cout << data << std::endl;
}
(in this particular instance, a version of std::ostream::operator<< that takes a std::string is already defined, so you don't even need data at all)
This question already has answers here:
convert a char* to std::string
(13 answers)
Closed 6 years ago.
What is the correct/best/simplest way to convert a c-style string to a std::string.
The conversion should accept a max_length, and terminate the string at the first \0 char, if this occur before max_length charter.
This page on string::string gives two potential constructors that would do what you want:
string ( const char * s, size_t n );
string ( const string& str, size_t pos, size_t n = npos );
Example:
#include<cstdlib>
#include<cstring>
#include<string>
#include<iostream>
using namespace std;
int main(){
char* p= (char*)calloc(30, sizeof(char));
strcpy(p, "Hello world");
string s(p, 15);
cout << s.size() << ":[" << s << "]" << endl;
string t(p, 0, 15);
cout << t.size() << ":[" << t << "]" << endl;
free(p);
return 0;
}
Output:
15:[Hello world]
11:[Hello world]
The first form considers p to be a simple array, and so will create (in our case) a string of length 15, which however prints as a 11-character null-terminated string with cout << .... Probably not what you're looking for.
The second form will implicitly convert the char* to a string, and then keep the maximum between its length and the n you specify. I think this is the simplest solution, in terms of what you have to write.
std::string str(c_str, strnlen(c_str, max_length));
At Christian Rau's request:
strnlen is specified in POSIX.1-2008 and available in GNU's glibc and the Microsoft run-time library. It is not yet found in some other systems; you may fall back to Gnulib's substitute.
std::string the_string(c_string);
if(the_string.size() > max_length)
the_string.resize(max_length);
This is actually trickier than it looks, because you can't call strlen
unless the string is actually nul terminated. In fact, without some
additional constraints, the problem practically requires inventing a new
function, a version of strlen which never goes beyond the a certain
length. However:
If the buffer containing the c-style string is guaranteed to be at least
max_length char's (although perhaps with a '\0' before the end),
then you can use the address-length constructor of std::string, and
trim afterwards:
std::string result( c_string, max_length );
result.erase( std::find( result.begin(), result.end(), '\0' ), result.end() );
and if you know that c_string is a nul terminated string (but perhaps
longer than max_length, you can use strlen:
std::string result( c_string, std::min( strlen( c_string ), max_length ) );
There is a constructor accepting two pointer parameters, so the code is simply
std::string cppstr(cstr, cstr + min(max_length, strlen(cstr)));
this is also going to be as efficient as std::string cppstr(cstr) if the length is smaller than max_length.
What you want is this constructor:
std::string ( const string& str, size_t pos, size_t n = npos ), passing pos as 0. Your const char* c-style string will get implicitly cast to const string for the first parameter.
const char *c_style = "012abd";
std::string cpp_style = std::string(c_style, 0, 10);
UPDATE: removed the "new" from the cpp_style initialization
I have an array of chars and I need to extract subsets of this array and store them in std::strings. I am trying to split the array into lines, based on finding the \n character. What is the best way to approach this?
int size = 4096;
char* buffer = new char[size];
// ...Array gets filled
std::string line;
// Find the chars up to the next newline, and store them in "line"
ProcessLine(line);
Probably need some kind of interface like this:
std::string line = GetSubstring(char* src, int begin, int end);
I'd create the std::string as the first step, as splitting the result will be far easier.
int size = 4096;
char* buffer = new char[size];
// ... Array gets filled
// make sure it's null-terminated
std::string lines(buffer);
// Tokenize on '\n' and process individually
std::istringstream split(lines);
for (std::string line; std::getline(split, line, '\n'); ) {
ProcessLine(line);
}
You can use the std::string(const char *s, size_t n) constructor to build a std::string from the substring of a C string. The pointer you pass in can be to the middle of the C string; it doesn't need to be to the very first character.
If you need more than that, please update your question to detail exactly where your stumbling block is.
I didn't realize you only wanted to process each line one at a time, but just in case you need all the lines at once, you can also do this:
std::vector<std::string> lines;
char *s = buffer;
char *head = s;
while (*s) {
if (*s == '\n') { // Line break found
*s = '\0'; // Change it to a null character
lines.push_back(head); // Add this line to our vector
head = ++s;
} else s++; //
}
lines.push_back(head); // Add the last line
std::vector<std::string>::iterator it;
for (it = lines.begin(); it != lines.end(); it++) {
// You can process each line here if you want
ProcessLine(*it);
}
// Or you can process all the lines in a separate function:
ProcessLines(lines);
// Cleanup
lines.erase(lines.begin(), lines.end());
I've modified the buffer in place, and the vector.push_back() method generates std::string objects from each of the resulting C substrings automatically.
your best bet (best meaning easiest) is using strtok and convert the tokens to std::string via the constructor. (just note that pure strtok is not reentrant, for that you need to use the non standard strtok_r).
void ProcessTextBlock(char* str)
{
std::vector<std::string> v;
char* tok = strtok(str,"\n");
while(tok != NULL)
{
ProcessLine(std::string(tok));
tok = strtok(tok,"\n");
}
}
You can turn a substring of char* to std::string with a std::string's constructor:
template< class InputIterator >
basic_string( InputIterator first, InputIterator last, const Allocator& alloc = Allocator() );
Just do something like:
char *cstr = "abcd";
std::string str(cstr + 1, cstr + 3);
In that case str would be "bc".
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);