Why strtok modifying stl container - c++

In the below code, i am expecting output to be abc#def. But i am getting output as abcdef. It seems strtok is modifying the vector even though i am not directly passing vector to the strtok function. May i know how it is happening inside
std::vector<std::pair<const std::string, int>> x;
std::vector<std::string> z;
int main()
{
char* pch;
x.push_back(std::make_pair("abc#def", 1));
std::string m = x[0].first;
pch = strtok ((char*)(m.c_str()),"#");
while (pch != NULL)
{
z.push_back(pch);
pch =strtok (NULL, "#");
}
cout<<x[0].first<<endl;
return 0;
}

Copied instances of std::string may use the same backing buffer. That is x[0] and m may actually use the same backing buffer.
This is why the c_str() member returns const char * - you are not allowed to modify it.
You are casting away the const by using the C-style cast (char *).
In general, better use C++ casts: static_cast<>/reinterpret_cast<>/dynamic_cast<> and const_cast<> if you really need to strip the const. The latter is only intended to interface old C-code without const qualifiers. You shall not require to use it within normal C++ code.

Instead using of strtok use find_first_of & find_first_not_of methods of string
like this:
using namespace std;
int main () {
string s="abc#def";
string temp = s,res;
while(temp.size()){
size_t st,en;
st = temp.find_first_not_of("#");
en = temp.find_first_of("#",st);
res= temp.substr(st,en);
cout<<res.c_str()<<endl;
temp=(en == string::npos) ? "" : temp.substr(en);
}
return 0;
}

In your implementation, c_str() must be returning a reference to the internal char buffer of the string, without making any copy. From the manpage of glibc strtok:
BUGS
Be cautious when using these functions. If you do use them, note that:
These functions modify their first argument.
so, yes, strtok applied to the pointer returned from c_str() will modify the string buffer.
You should be using std::getline instead of strtok to split string at #:
std::vector<std::pair<const std::string, int>> x;
int main() {
x.push_back(std::make_pair("abc#def", 1));
std::string m = x[0].first;
std::string token;
while(std::getline(m, token, '#')) {
std::cout << token << std::endl;
}
cout<< x[0].first <<endl;
return 0;
}
or, if you really need to use strtok, at least duplicate the buffer returned by c_str() with strdup (and remember to free() it).

Related

C++ string to C string

Consider the following piece of code:
void fun (string &str1, string &str2)
{
const char* cstr;
....
if(strlen(cstr = (str1+str2).c_str()) < 15)
{
// here cstr used
}
}
The condition itself works fine, but in the if-condition body cstr contains garbage. Why?
In this expression:
cstr = (str1+str2).c_str()
you are taking a pointer to the temporary string str1 + str2. This temporary dies at the end of the expression, and so you have undefined behaviour when you try to read from cstr inside the if-body.
I'm assuming the string in your C++ code is std::string.
str1 + str2 produces a temporary std::string object. You invoke the c_str() method on it, and you get a C-style string pointer to the data of this temporary std::string object.
When the temporary std::string goes out of scope and is destroyed, the cstr raw C-style pointer is left dangling, pointing to invalid memory.
If you need to work on the concatenated string str1 + str2, I would suggest you safely store it in a non-temporary std::string object, e.g.:
std::string s = str1 + str2;
// Work with s
if (s.length() < 15) {
// Use s here
...
}
Note also that I invoked the std::string::length() method instead of the C function strlen(). You can use the std::string::size() method, as well.
In general, in C++ code, you should use convenient string classes (like std::string), instead of C-style raw string pointers.

How can I convert const char* to string and then back to char*?

I'm just starting c++ and am having difficulty understanding const char*. I'm trying to convert the input in the method to string, and then change the strings to add hyphens where I want and ultimately take that string and convert it back to char* to return. So far when I try this it gives me a bus error 10.
char* getHyphen(const char* input){
string vowels [12] = {"A","E","I","O","U","Y","a","e","i","o","u","y"};
//convert char* to string
string a;
int i = 0;
while(input != '\0'){
a += input[i];
input++;
i++;
}
//convert a string to char*
return NULL;
}
A: The std::string class has a constructor that takes a char const*, so you simply create an instance to do your conversion.
B: Instances of std::string have a c_str() member function that returns a char const* that you can use to convert back to char const*.
auto my_cstr = "Hello"; // A
std::string s(my_cstr); // A
// ... modify 's' ...
auto back_to_cstr = s.c_str(); // B
First of all, you don't need all of that code to construct a std::string from the input. You can just use:
string a(input);
As far as returning a new char*, you can use:
return strdup(a.c_str()); // strdup is a non-standard function but it
// can be easily implemented if necessary.
Make sure to deallocate the returned value.
It will be better to just return a std::string so the users of your function don't have to worry about memory allocation/deallocation.
std::string getHyphen(const char* input){
Don't use char*. Use std::string, like all other here are telling you. This will eliminate all such problems.
However, for the sake of completeness and because you want to understand the background, let's analyse what is going on.
while(input != '\0'){
You probably mean:
while(*input != '\0') {
Your code compares the input pointer itself to \0, i.e. it checks for a null-pointer, which is due to the unfortunate automatic conversion from a \0 char. If you tried to compare with, say, 'x' or 'a', then you would get a compilation error instead of runtime crashes.
You want to dereference the pointer via *input to get to the char pointed to.
a += input[i];
input++;
i++;
This will also not work. You increment the input pointer, yet with [i] you advance even further. For example, if input has been incremented three times, then input[3] will be the 7th character of the original array passed into the function, not the 4th one. This eventually results in undefined behaviour when you leave the bounds of the array. Undefined behaviour can also be the "bus error 10" you mention.
Replace with:
a += *input;
input++;
i++;
(Actually, now that i is not used any longer, you can remove it altogether.)
And let me repeat it once again: Do not use char*. Use std::string.
Change your function declaration from
char* getHyphen(const char* input)
to
auto hyphenated( string const& input )
-> string
and avoid all the problems of conversion to char const* and back.
That said, you can construct a std::string from a char_const* as follows:
string( "Blah" )
and you get back a temporary char const* by using the c_str method.
Do note that the result of c_str is only valid as long as the original string instance exists and is not modified. For example, applying c_str to a local string and returning that result, yields Undefined Behavior and is not a good idea. If you absolutely must return a char* or char const*, allocate an array with new and copy the string data over with strcpy, like this: return strcpy( new char[s.length()+1], s.c_str() ), where the +1 is to accomodate a terminating zero-byte.

Automatically Concatenate Strings and Int C++

In Lua (apologise, I like working with it the best), the conversion between int and string is done automatically, so
"hi"..2
would result as
"hi2"
In C++ (cause I can't seem to get the default C++11 stoi() and to_string() methods to work) I defined these for myself:
int stoi(string str) {
char* ptr;
strtol(str.c_str(), &ptr, 10);
}
string to_string(int i) {
char* buf;
sprintf(buf, "%d", i);
return buf;
}
which are basically how the default ones are defined anyways.
Then I did this:
string operator+ (string& stuff, int why) {
stuff.append(to_string(why));
}
I tried it on the following code:
void print(string str) {
cout << str << endl;
}
int main() {
cout << stoi("1") + 2 << endl;
print("die" + 1);
return 0;
}
And it outputs
3
ie
Why is this so, and how can I fix it?
EDIT:
Here's what the code looks like now:
using namespace std;
string to_string(int i) {
char* buf;
sprintf(buf, "%d", i);
return buf;
}
string operator+ (string stuff, int why) {
stuff.append(to_string(why));
return stuff;
}
int main() {
cout << string("die") + 2 << endl;
return 0;
}
And it just keeps giving me stackdumps.
Replace print("die" + 1); with cout << std::string("die") + 1;
print() doesn't know what to do with strings. Use std::cout. "die" is a char*, +1 will increment the pointer.
std::string to_string(int i) {
char buf[(sizeof(int)*CHAR_BIT+2)/3+3];
sprintf(buf, "%d", i);
return buf;
}
You need to make an actual buffer to print to. The math is a quick over-estimate of big the largest decimal int is in characters; 3 bits can fit in 1 decimal character, plus null, plus negation, plus rounding, plus 1 for good measure. Hopefully I did not err: do some testing.
Also use snprintf instead of sprintf while you are at it: buffer overflows are not to be toyed with.
The next problem is that "hello" is not a std::string, It is a char const[6] -- an array of 6 char. It can be converted tomstd::string, but +1 will instead convert it to a pointer to the first character, then +1 it to the 2nd character.
Cast it to std::string before.
Finally, it is ambiguous in the standard (really) of pverloading an operator on std::string + int is legal. It is definitely poor practice, as you cannot do it in std legally, and you should overload operators in the type's namespace (so ADL works): these two conflict. On top of that, if std in the future adds such a + your code starts behaving strangely. On top of that, operators are part of a class's interface, and modifying the interface of a class you do not 'own' is rude and a bad habit.
Write your own string class that owns a std::string rather. Or a string view.
Finally, consider telling your compiler to use c++11, you probably just need to pass a flag to it like -std=c++11.
std::string s1("h1");
std::string s2("2");
s1 += s2;
If you are using C++11 compatible compiler you can convert int to string like this:
int i = 2;
std::string s = std::to_string(i);
If you are using Boost library:
#include <boost/lexical_cast.hpp>
int i = 2;
std::string s = boost::lexical_cast<std::string>(i);
Please do not use raw char pointers in C++ for strings.
overloading the operator+ on other than your own types it at best dangerous.
Just use std::to_string in conjunction with operator+ or +=, e.g.
std::string x = "hi";
x += std::to_string(2);
C++14 introduces a user-defined literal that takes a string literal (conversions are applied to make this a pointer) and returns a std::string. In C++11, you can just write your own (this is taken from libstdc++):
inline std::string
operator""_s(const char* str, size_t len)
{
return std::string{str, len};
}
(Note: UDLs without a preceding underscore are reserved names)
And you can use it like this:
// Assumes operator+ is overloaded
print("die"_s + 1);
Demo
"die" is not a std::string. It's a string literal.
Thus when you add 1 to the string literal, it decays to a const char* and the + 1 simply increments that pointer — to next char, 'i'.
Then you call print with the incremented pointer, which causes a std::string to be constructed using that pointer. Since it pointed to the 'i' character, to constructed string is initialized to "ie".
You must first make a std::string out of your string literal to make it call your operator+:
std::cout << std::string("die") + 1;
And then make a few fixes to your operator+:
string operator+ (string stuff, int why) {
return stuff.append(to_string(why));
}
Now it works.

Substitute char array with std::string in an input parameter to a function

Following are two legacy routines. I cannot change the routine declarations.
static bool GetString(char * str); //str is output parameter
static bool IsStringValid(const char * str); //str is input parameter
With call as follows
char inputString[1000];
GetString(inputString);
IsStringValid(inputString);
Instead of using fixed char array, I want to use std::string as the input. I am not able get the semantics right (string::c_str).
With IsEmpty it should not be a problem:
std::string str = "Some text here";
IsEmpty(str.c_str());
Though it's pretty useless if you have a std::string as then you would normally just call str.empty().
The other function though, that's harder. The reason is that it's argument is not const, and std::string doesn't allow you to modify the string using a pointer.
It can be solved, by writing a wrapper-function which takes a string reference, and have an internal array used for the actual GetString call, and uses that array to initialize the passed string reference.
Wrapper examples:
// Function which "creates" a string from scratch
void GetString(std::string& str)
{
char tempstr[4096];
GetString(tempstr);
str = tempstr;
}
// Function which modifies an existing string
void ModifyString(std::string& str)
{
const size_t length = str.size() + 1;
char* tempstr = new char[length];
std::copy_n(str.c_str(), tempstr, length);
ModifyString(tempstr);
str = tempstr;
delete[] tempstr;
}
You can't use c_str for the first function, because it returns a const char*. You can pass a std::string by reference and assign to it. As for is empty, you can call c_str on your string, but you'd be better of calling the member empty().
I think you can use the string container of STL ( Standard template Library ) .
#include <string>
bool isempty ( int x ) {
return ( x == 0 ) ? true : false ;
}
// inside main()
string s ;
cin >> s ; // or getline ( cin , s) ;
bool empty = isEmpty (s.length()) ;
std::string has c_str() which you can use for IsEmpty. There ist no function which gives you a non const pointer. Since std::string's allocation is not guaranteed to be contiguous you cannot do something like &s[0] either. The only thing you can do is to use a temporary char buffer as you do in your example.
std::string s;
char inputString[1000];
std::vector<char> v(1000);
GetString(inputString);
GetString(&v[0]);
s = &v[0];
IsEmpty(s.c_str());

How to convert a char* pointer into a C++ string?

I have a C++ string. I need to pass this string to a function accepting a char* parameter (for example - strchr()).
a) How do I get that pointer?
b) Is there some function equivalent to strschr() that works for C++ strings?
To get the C string equivalent of
the C++ string object use c_str
function.
To locate the first occurence of a
char in a string object use
find_first_of function.
Example:
string s = "abc";
// call to strlen expects char *
cout<<strlen(s.c_str()); // prints 3
// on failure find_first_of return string::npos
if(s.find_first_of('a') != string::npos)
cout<<s<<" has an a"<<endl;
else
cout<<s<<" has no a"<<endl;
Note: I gave the strlen just an example of a function that takes char*.
Surprisingly, std:;string has far, far more capabilities than C-style strings. You probably want the find_first_of() method. In general, if you find yourself using the strxxx() functions on C++ std::strings, you are almost certainly doing something wrong.
Like much of the C++ Standard Library, the string class is a complex beast. To make the most of it, you really need a good reference book. I recommend The C++ Standard Library, by Nicolai Josuttis.
You can't get a char* from a string
string does not allow you free access to its internal buffer.
The closest you can get is a const char* using .c_str() if you want it null terminated or .data() if it doesn't have to be null terminated.
You can then cast the pointer returned by these functions to char* but you do this on your own risk. That being said this is a relatively safe cast to make as long as you make sure you're not changing the string. If you changed it then the pointer you got from c_str() may no longer be valid.
This code:
string str("Hello World!");
char* sp = (char*)str.c_str();
sp[5] = 'K';
is probably ok
However this:
string str("Hello World!");
char* sp = (char*)str.c_str();
str = "Chaged string";
sp[5] = 'K';
is most definitely not ok.
If you just want to assign a string literal to pw, you can do it like
char *pw = "Hello world";
If you have a C++ std::string object, the value of which you want to assign to pw, you can do it like
char *pw = some_string.c_str()
However, the value that pw points to will only be valid for the life time of some_string.
More here :
How to assign a string to char *pw in c++
GoodLUCK!!
std::string yourString("just an example");
char* charPtr = new char[yourString.size()+1];
strcpy(charPtr, yourString.c_str());
If str in your string use str.c_str() method to get the char* inside it.
Perhaps this exmaple will help you
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string str ("Replace the vowels in this sentence by asterisks.");
size_t found;
found=str.find_first_of("aeiou");
while (found!=string::npos)
{
str[found]='*';
found=str.find_first_of("aeiou",found+1);
}
cout << str << endl;
return 0;
}
The C++ Standard provides two member functions of claass std::basic_string that return pointer to the first element of the string. They are c_str() and data(). But the both return const char *, So you may not use them with a function that has parameter of type char *.
As for function strchr then its first parameter is const char *. So you may use c_str() and data() with this function. However it is much better to use member function find()of class sttd::basic_string instead of strchr.