I am trying to make a function that takes a constant reference of a string as input and returns the string after each character of the string is rotated 1 place to the right. Using references and pointers still confuses me and I am not sure how to obtain the string from the constant reference.
string rotate(const string &str){
string *uno = &str;
string dos = rotate(uno.rbegin(), uno.rbegin() + 1, uno.rend());
return dos;}
This is what I have got so far but it does not compile. Any tips on how to properly get the string from the constant reference will be appreciated.
You can't perform the rotation in-place without violating the const contract on the parameter, so you should copy the input and return a new string:
string rotate(const string &str){
string uno = str;
rotate(uno.rbegin(), uno.rbegin() + 1, uno.rend());
return uno;
}
Another reasonable option would be to use std::rotate_copy
The line
string* uno = string &str;
makes no sense. I think you mean
string* uno = const_cast<string*>(&str);
You might consider this rotate:
// rotate last char to front
std::string rotate(const std::string& str)
{
return(str[str.size()-1] +
str.substr(0,str.size()-1));
}
// 'abcdefghijklmnopqrstuvwxyz'
// 'zabcdefghijklmnopqrstuvwxy'
You could pass in a string to receive the rotated string, thus avoiding return by value copy.
I passed the string in by pointer, as its clearer at the call site that it's intended to be altered, but it could easily be passed by reference if preferred.
#include <string>
#include <iostream>
#include <algorithm>
void rotate(std::string const& str, std::string* out)
{
*out = str;
std::rotate(out->rbegin(), out->rbegin() + 1, out->rend());
}
int main(int, char**)
{
std::string out;
std::string x = "1234567";
std::cout << x << '\n';
::rotate(x, &out);
std::cout << out << '\n';
}
Related
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++.
I have a function in my code called buildPacket that takes some parameters, and converts them into a char* and adds them together using a std::vector<char> and at the end returns the result as a char*. The problem is that after I convert the vector to a char* all characters become a weird character.
I tried using other ways of converting the vector to a char*, like with using reinterpret_cast<char*>. When I print the contents of the vector from inside the function, I get the expected result so the problem is with the conversion.
The function's code:
char* buildPacket (int code, std::string data)
{
char* codeBytes = CAST_TO_BYTES(code);
std::vector<char> packetBytes(codeBytes, codeBytes + sizeof(char));
size_t dataLength = data.size() + 1;
char* dataLengthBytes = CAST_TO_BYTES(dataLength);
packetBytes.insert(packetBytes.end(), dataLengthBytes, dataLengthBytes + sizeof(int));
const char* dataBytes = data.c_str();
packetBytes.insert(packetBytes.end(), dataBytes, dataBytes + dataLength);
return &packetBytes[0];
}
The CAST_TO_BYTES macro:
#define CAST_TO_BYTES(OBJ) static_cast<char*>(static_cast<void*>(&OBJ));
The intent of the function is to take the input and build a packet out of it to send through a socket later on, the packet's format consists of a 1-byte long code, 4-byte long data length and data with variable length.
The input I gave it is code = 101 and data = "{\"password\":\"123456\",\"username\":\"test\"}"
This is the result I am getting when printing the characters: ▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌
EDIT: Thanks for all the help, I've returned a vector<char> at the end as suggested and took a different approach in converting to values to a char*.
You're returning a pointer to something inside of a local variable. You should change your code to have your vector<char> alive outside of your buildPacket function (such as by returning it instead of the char*).
You might try this solution. I thing using STL makes it more clearer what you are trying to achieve. There was also an undefined reference in your code, that could lead to unpredictable crashes.
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
// Better return std::vector<char>
char* buildPacket(int code, const std::string& data)
{
auto result = data;
result.append(1, static_cast<char>(code));
char* ret = new char[data.size() + 2];
ret[data.size() + 1] = '\0';
std::copy(result.begin(), result.end(), ret);
return ret;
}
std::vector<char> buildPacketStl(int code, const std::string& data)
{
std::vector<char> ret;
std::copy(data.begin(), data.end(), std::back_inserter(ret));
ret.push_back(static_cast<char>(code));
return ret;
}
int main() {
std::cout << buildPacket(65, "test") << std::endl;; // 65 -> A
auto stl= buildPacketStl(65, "test"); // 65 -> A
std::copy(stl.begin(), stl.end(), std::ostream_iterator<char>(std::cout, ""));
std::cout << std::endl;
}
I'm very new to C++ and have been fidgeting around with it for awhile. If any insight is available with these errors I would be in great gratitude. The following program should produce the following result:
#include <iostream>
#include <string>
using namespace std;
string Cut(string &strString, int nStart, int nLength)
{
string strCopy;
strString.copy(strCopy, nLength, nStart);
strString.erase(nStart, nLength);
return strCopy;
}
int main()
{
string strHate = "I hate tuna.";
cout << strHate << endl;
string strTuna;
strTuna = Cut(strHate, 8, 4);
cout << strHate << endl;
cout << strTuna << endl;
}
should produce
I hate tuna.
I hate .
tuna
however, instead I get this error message:
9|error: no matching function for call to 'std::basic_string<char>::copy(std::string&, int&, int&)'
Much appreciated,
KleptoKat
As referenced here, the function std::string.copy takes a parameter of type char *, you you've given it a parameter of type string
This is a better solution:
string Cut(string &strString, int nStart, int nLength){
string strCopy (strString, nStart, nLength);
strString.erase(nStart, nLength);
return strCopy;
}
This creates the new string from the old string directly from the constructor, so it's a little more elegant.
Just so you know why the error occurred, the data types of your variables (int, char, string, etc) have to match the data types that the function expects to receive. If you don't know what data types a function expects to receive, you can always look it up on Google.
Also, you need to use:
strTuna = Cut(strHate, 7, 4)
Instead of:
strTuna = Cut(strHate, 8, 4)
This is because the first character of the string has a position of 0 instead of 1.
Using string::substr in your case is probably more appropriate:
string Cut(string &str, int nStart, int nLength)
{
string strCopy = str.substr(nStart, nLength);
str.erase(nStart, nLength);
return strCopy;
}
Below is my sample code. Its just a sample which is similar to the code which i'm using in my applicaiton.
#define STR_SIZE 32
void someThirdPartyFunc(const char* someStr);
void getString(int Num, const char* myStr)
{
char tempStr[] = "MyTempString=";
int size = strlen(tempStr) + 2;
snprintf((char*)myStr, size, "%s%d", tempStr, Num);
}
int main()
{
const char * myStr = new char(STR_SIZE);
getString(1, myStr); // get the formated string by sending the number
someThirdPartyFunc(myStr); // send the string to the thirdpartyFunction
delete myStr;
return 0;
}
I am getting an exception if i use this code. I think the problem is with deleting the "myStr". But delete is really necessary.
Is there any other way to format the string in getString and send it to the ThirdPartyFunc??
Thanks in advance.
you are allocating not an array of chars but one char with this line:
const char * myStr = new char(STR_SIZE);
and that one allocated char is initialized with the value of STR_SIZE, causing a "char overflow" in this case.
if you want an array of size STR_SIZE:
const char * myStr = new char[STR_SIZE];
(note the rectangular [ ]). you have to deallocate such allocated chunk of memory by using the delete[] operator.
personal note: the code you have written above (manually allocated strings etc) is good educational wise; you will do a lot of such mistakes and thus learn about the inner workings of C / C++. for production code you do not want that, for production code you want std::string or other string-containers to avoid repeating string-related mistakes. in general you are not the one who sucessfully reinvent how string-libraries will work. the same is true for other container-types like dynamically-growable-arrays (std::vector) or dictionary-types or whatever. but for educational fiddling around your code above serves a good purpose.
there are other problems in your code snippet (handing over const char* to a function and then modifying the ram, not calculating correctly the size parameter when calling snprintf etc), but these are not related to your segfault-problem.
Re the technical, instead of
const char * myStr = new char(STR_SIZE);
do
char const myStr[STR_SIZE] = "";
Note that both have the problem that the string can’t be modified.
But you only asked about the allocation/deallocation problem.
But then, there's so much wrong at levels above the language-technical.
Here's the original code, complete:
void someThirdPartyFunc(const char* someStr);
void getString(int Num, const char* myStr)
{
char tempStr[] = "MyTempString=";
int size = strlen(tempStr) + 2;
snprintf((char*)myStr, size, "%s%d", tempStr, Num);
}
int main()
{
const char * myStr = new char(STR_SIZE);
getString(1, myStr); // get the formated string by sending the number
someThirdPartyFunc(myStr); // send the string to the thirdpartyFunction
delete myStr;
return 0;
}
Here's how to do that at the C++ level:
#include <string> // std::string
#include <sstream> // std::ostringstream
using namespace std;
void someThirdPartyFunc( char const* ) {}
string getString( int const num )
{
ostringstream stream;
stream << "MyTempString=" << num;
return stream.str();
}
int main()
{
someThirdPartyFunc( getString( 1 ).c_str() );
}
The #define disappeared out of the more natural code, but note that it can very easily lead to undesired text substitutions, even with all uppercase macro names. And shouting all uppercase is an eyesore anyway (which is why it's the macro name convention, as opposed to some other convention). In C++ simply use const instead.
I have a string that I would like to tokenize.
But the C strtok() function requires my string to be a char*.
How can I do this simply?
I tried:
token = strtok(str.c_str(), " ");
which fails because it turns it into a const char*, not a char*
#include <iostream>
#include <string>
#include <sstream>
int main(){
std::string myText("some-text-to-tokenize");
std::istringstream iss(myText);
std::string token;
while (std::getline(iss, token, '-'))
{
std::cout << token << std::endl;
}
return 0;
}
Or, as mentioned, use boost for more flexibility.
Duplicate the string, tokenize it, then free it.
char *dup = strdup(str.c_str());
token = strtok(dup, " ");
free(dup);
If boost is available on your system (I think it's standard on most Linux distros these days), it has a Tokenizer class you can use.
If not, then a quick Google turns up a hand-rolled tokenizer for std::string that you can probably just copy and paste. It's very short.
And, if you don't like either of those, then here's a split() function I wrote to make my life easier. It'll break a string into pieces using any of the chars in "delim" as separators. Pieces are appended to the "parts" vector:
void split(const string& str, const string& delim, vector<string>& parts) {
size_t start, end = 0;
while (end < str.size()) {
start = end;
while (start < str.size() && (delim.find(str[start]) != string::npos)) {
start++; // skip initial whitespace
}
end = start;
while (end < str.size() && (delim.find(str[end]) == string::npos)) {
end++; // skip to end of word
}
if (end-start != 0) { // just ignore zero-length strings.
parts.push_back(string(str, start, end-start));
}
}
}
There is a more elegant solution.
With std::string you can use resize() to allocate a suitably large buffer, and &s[0] to get a pointer to the internal buffer.
At this point many fine folks will jump and yell at the screen. But this is the fact. About 2 years ago
the library working group decided (meeting at Lillehammer) that just like for std::vector, std::string should also formally, not just in practice, have a guaranteed contiguous buffer.
The other concern is does strtok() increases the size of the string. The MSDN documentation says:
Each call to strtok modifies strToken by inserting a null character after the token returned by that call.
But this is not correct. Actually the function replaces the first occurrence of a separator character with \0. No change in the size of the string. If we have this string:
one-two---three--four
we will end up with
one\0two\0--three\0-four
So my solution is very simple:
std::string str("some-text-to-split");
char seps[] = "-";
char *token;
token = strtok( &str[0], seps );
while( token != NULL )
{
/* Do your thing */
token = strtok( NULL, seps );
}
Read the discussion on http://www.archivum.info/comp.lang.c++/2008-05/02889/does_std::string_have_something_like_CString::GetBuffer
With C++17 str::string receives data() overload that returns a pointer to modifieable buffer so string can be used in strtok directly without any hacks:
#include <string>
#include <iostream>
#include <cstring>
#include <cstdlib>
int main()
{
::std::string text{"pop dop rop"};
char const * const psz_delimiter{" "};
char * psz_token{::std::strtok(text.data(), psz_delimiter)};
while(nullptr != psz_token)
{
::std::cout << psz_token << ::std::endl;
psz_token = std::strtok(nullptr, psz_delimiter);
}
return EXIT_SUCCESS;
}
output
pop
dop
rop
EDIT: usage of const cast is only used to demonstrate the effect of strtok() when applied to a pointer returned by string::c_str().
You should not use
strtok() since it modifies the tokenized string which may lead to undesired, if not undefined, behaviour as the C string "belongs" to the string instance.
#include <string>
#include <iostream>
int main(int ac, char **av)
{
std::string theString("hello world");
std::cout << theString << " - " << theString.size() << std::endl;
//--- this cast *only* to illustrate the effect of strtok() on std::string
char *token = strtok(const_cast<char *>(theString.c_str()), " ");
std::cout << theString << " - " << theString.size() << std::endl;
return 0;
}
After the call to strtok(), the space was "removed" from the string, or turned down to a non-printable character, but the length remains unchanged.
>./a.out
hello world - 11
helloworld - 11
Therefore you have to resort to native mechanism, duplication of the string or an third party library as previously mentioned.
I suppose the language is C, or C++...
strtok, IIRC, replace separators with \0. That's what it cannot use a const string.
To workaround that "quickly", if the string isn't huge, you can just strdup() it. Which is wise if you need to keep the string unaltered (what the const suggest...).
On the other hand, you might want to use another tokenizer, perhaps hand rolled, less violent on the given argument.
Assuming that by "string" you're talking about std::string in C++, you might have a look at the Tokenizer package in Boost.
First off I would say use boost tokenizer.
Alternatively if your data is space separated then the string stream library is very useful.
But both the above have already been covered.
So as a third C-Like alternative I propose copying the std::string into a buffer for modification.
std::string data("The data I want to tokenize");
// Create a buffer of the correct length:
std::vector<char> buffer(data.size()+1);
// copy the string into the buffer
strcpy(&buffer[0],data.c_str());
// Tokenize
strtok(&buffer[0]," ");
If you don't mind open source, you could use the subbuffer and subparser classes from https://github.com/EdgeCast/json_parser. The original string is left intact, there is no allocation and no copying of data. I have not compiled the following so there may be errors.
std::string input_string("hello world");
subbuffer input(input_string);
subparser flds(input, ' ', subparser::SKIP_EMPTY);
while (!flds.empty())
{
subbuffer fld = flds.next();
// do something with fld
}
// or if you know it is only two fields
subbuffer fld1 = input.before(' ');
subbuffer fld2 = input.sub(fld1.length() + 1).ltrim(' ');
Typecasting to (char*) got it working for me!
token = strtok((char *)str.c_str(), " ");
Chris's answer is probably fine when using std::string; however in case you want to use std::basic_string<char16_t>, std::getline can't be used. Here is a possible other implementation:
template <class CharT> bool tokenizestring(const std::basic_string<CharT> &input, CharT separator, typename std::basic_string<CharT>::size_type &pos, std::basic_string<CharT> &token) {
if (pos >= input.length()) {
// if input is empty, or ends with a separator, return an empty token when the end has been reached (and return an out-of-bound position so subsequent call won't do it again)
if ((pos == 0) || ((pos > 0) && (pos == input.length()) && (input[pos-1] == separator))) {
token.clear();
pos=input.length()+1;
return true;
}
return false;
}
typename std::basic_string<CharT>::size_type separatorPos=input.find(separator, pos);
if (separatorPos == std::basic_string<CharT>::npos) {
token=input.substr(pos, input.length()-pos);
pos=input.length();
} else {
token=input.substr(pos, separatorPos-pos);
pos=separatorPos+1;
}
return true;
}
Then use it like this:
std::basic_string<char16_t> s;
std::basic_string<char16_t> token;
std::basic_string<char16_t>::size_type tokenPos=0;
while (tokenizestring(s, (char16_t)' ', tokenPos, token)) {
...
}
It fails because str.c_str() returns constant string but char * strtok (char * str, const char * delimiters ) requires volatile string. So you need to use *const_cast< char > inorder to make it voletile.
I am giving you a complete but small program to tokenize the string using C strtok() function.
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
int main() {
string s="20#6 5, 3";
// strtok requires volatile string as it modifies the supplied string in order to tokenize it
char *str=const_cast< char *>(s.c_str());
char *tok;
tok=strtok(str, "#, " );
int arr[4], i=0;
while(tok!=NULL){
arr[i++]=stoi(tok);
tok=strtok(NULL, "#, " );
}
for(int i=0; i<4; i++) cout<<arr[i]<<endl;
return 0;
}
NOTE: strtok may not be suitable in all situation as the string passed to function gets modified by being broken into smaller strings. Pls., ref to get better understanding of strtok functionality.
How strtok works
Added few print statement to better understand the changes happning to string in each call to strtok and how it returns token.
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
int main() {
string s="20#6 5, 3";
char *str=const_cast< char *>(s.c_str());
char *tok;
cout<<"string: "<<s<<endl;
tok=strtok(str, "#, " );
cout<<"String: "<<s<<"\tToken: "<<tok<<endl;
while(tok!=NULL){
tok=strtok(NULL, "#, " );
cout<<"String: "<<s<<"\t\tToken: "<<tok<<endl;
}
return 0;
}
Output:
string: 20#6 5, 3
String: 206 5, 3 Token: 20
String: 2065, 3 Token: 6
String: 2065 3 Token: 5
String: 2065 3 Token: 3
String: 2065 3 Token:
strtok iterate over the string first call find the non delemetor character (2 in this case) and marked it as token start then continues scan for a delimeter and replace it with null charater (# gets replaced in actual string) and return start which points to token start character( i.e., it return token 20 which is terminated by null). In subsequent call it start scaning from the next character and returns token if found else null. subsecuntly it returns token 6, 5, 3.