String pointer manipulation - c++

I have this assignment at school. A string pointer is passed to the function and returns 2 const strings to a different functions.
The 2 new strings divide the original string into 2 parts based on a space.
Example:
Input
str = 05/12 Hello
Desired output
key = 05/12
satData = Hello
This is the code I wrote but its giving me errors. Please help
void RBapp::processInsert(string &str)
{
string *key = new string();
string *satData = new string();
int i = 0, j =0;
while(str[i]!=" ")
{
key[j] = str[i];
i++;
j++;
}
j = 0;
while(str[i]!='\0')
{
satData[j] = str[i];
i++;
j++;
}
myRBT.rbInsert(key, satData);
}

Using stringstream
void RBapp::processInsert(const std::string &str)
{
std::stringstream ss(str);
std::string key;
std::string satData;
ss >> key;
ss >> satData;
myRBT.rbInsert(key, satData);
}

Your program is subject to undefined behavior since you are accessing memory that is not valid.
When you use:
string *key = new string();
string *satData = new string();
You have two pointers that point to empty strings.
key[j] = str[i];
is wrong if j > 0 since that points to invalid memory.
Based on the description of what you are trying to do, what you need is something along the lines of:
void RBapp::processInsert(string &str)
{
// There is no need to use new string.
// Just use two string objects.
string key;
string satData;
int i = 0;
while(str[i]!=" ")
{
// Add the character to key
key.push_back(str[i]);
i++;
}
// Increment i here if you want the space to be excluded from
// satData. If you want to include the space character in satData,
// then, there is no need to increment i
++i;
while(str[i]!='\0')
{
// Add the character to satData
satData.push_back(str[i]);
i++;
}
myRBT.rbInsert(key, satData);
}

You say you receive a string pointer - what I see is you receive a string. In C++ you would try to avoid hand-written loops as much as possible - std::string has a lot of stuff you need.
void process(const string &str) {
auto firstSpace = str.find_first_of(' ');
auto key = str.substr(0, firstSpace);
auto value = str.substr(firstSpace, string::npos);
myRBT.rbInsert(key, value);
}

Related

std::string returning inappropriate value

I wrote a program which perform string compression using counts of repeated characters. The program in C++ is :
#include<iostream>
#include<cstring>
std::string compressBad(std::string str)
{
std::string mystr = "";
int count = 1;
char last = str[0];
for (int i = 0; i < str.length();++i)
{
if(str[i] == last)
count++;
else
{
std::string lastS = last+"";
std::string countS = std::to_string(count);
mystr.append(lastS);
mystr.append(countS);
//mystr = mystr + last + count;
count = 1;
last = str[i];
}
}
std::string lastS = last+"";
std::string countS = std::to_string(count);
mystr.append(lastS);
mystr.append(countS);
return mystr;
//return mystr+last+count;
}
int main()
{
std::string str;
std::getline(std::cin, str);
std::string str2 = compressBad(str);
std::cout<<str2;
/*if (str.length() < str2.length())
std::cout<<str;
else
std::cout<<str2;*/
std::cout<<std::endl;
return 0;
}
Few example on running this are :
Input : sssaaddddd
Output : ùÿÿ*425
Output it should print : s3a2d5
Second example:
Input : sssaaddd
Output: ùÿÿ*423
Output it should print : s3a2d3
I also implemented the same concept in Java and there it is working fine. The java implementation is here
Why is this problem happening with above code.
There may be other issues in your code, but I think that this line might be to blame:
std::string lastS = last+"";
Here, you're trying to convert the character last to a string by concatenating the empty string to the end. Unfortunately, in C++ this is interpreted to mean "take the numeric value of the character last, then add that to a pointer that points to the empty string, producing a new pointer to a character." This pointer points into random memory, hence the garbage you're seeing. (Notice that this is quite different from how Java works!)
Try changing this line to read
std::string lastS(1, last);
This will initialize lastS to be a string consisting of just the character stored in last.
Another option would be to use an ostringstream:
std::ostringstream myStr;
myStr << last << count;
// ...
return myStr.str();
This eliminates all the calls to .append() and std::to_string and is probably a lot easier to read.
last + "" doesn't do what you think.
just do
mystr.append(1, last);

Program gets "Expression: string subscript out of range"

#include <iostream>
#include <string>
using namespace std;
string Latin(string words)
{
string strWord, strSentence = "";
int length = 0, index = 0;
while (words[index] != '\0')
{
if(words.find(' ', index) != -1)
{
length = words.find(' ', index);
length -= index;
strWord = words.substr(index,length);
strWord.insert(length, "ay");
strWord.insert(length, 1, words[index]);
strWord.erase(0,1);
index += length +1;
}
else
{
strWord = words.substr(index);
length = strWord.length();
strWord.insert(length, "ay");
strWord.insert(length,1,words[index]);
strWord.erase(0,1);
index = words.length();
}
strSentence += (strWord + " ");
}
return strSentence;
}
int main()
{
string str;
getline(cin,str);
str = Latin(str);
cout<<str<<endl;
return 0;
}
I get this error that says
I have no clue what to do. As I am new to this, this is a program that is suppose to ask for user input of a length of words and translate them into pig Latin. Any help would be greatly appreciated.
Unless I really wanted to make my own life difficult, I'd do this quite a bit differently. First, I'd use a std::stringstream to break the input string into words to process. Then, I'd use std::rotate to move the first character of the string to the end. Finally, I'd wrap that all in std::transform to manage applying the function to each word in succession.
std::string line;
std::getline(std::cin, line);
std::stringstream buffer(line);
std::stringstream result;
std::transform(std::istream_iterator<std::string>(buffer),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(result, " "),
[](std::string s) {
std::rotate(s.begin(), s.begin() + 1, s.end());
s += "ay";
return s;
});
Of course, this doesn't know the special rules for things like words that start with vowels or letter pairs like sh or ch, but it looks like that's outside the scope of the task at hand.
For more on std::rotate, I recommend watching some of Sean Parent's videos.

c++ std::string array as function parameter

I'm kind of new to C++. I want to make split function for std::string in c++ like java split function in String class(I don't want to use boost library). so I made custom split function which is..
using namespace std;
void ofApp::split(string ori, string tokens[], string deli){
// calculate the number of tokens
int length = 0;
int curPos = 0;
do{
curPos = ori.find(deli, curPos) + 1;
length++;
}while(ori.find(deli, curPos) != string::npos);
length++;
// to save tokens, initialize tokens array
tokens = new string[length]; // this is the line I'm suspicious about..
int startPos = 0;
int strLength = 0;
int curIndex = 0;
do{
strLength = ori.find(deli, startPos) - startPos;
tokens[curIndex++] = ori.substr(startPos, strLength);
startPos = ori.find(deli, startPos) + 1;
}while(ori.find(deli, startPos) != string::npos);
tokens[curIndex] = ori.substr(startPos, ori.length() - startPos);
}
First, I thought passing parameter as string tokens[] is the way call by reference, so when function is finished, tokens[] array will be full of tokens seperated by deli string. But when i call this function like
string str = "abc,def,10.2,dadd,adsf";
string* tokens;
split(str, tokens, ",");
after this, tokens array is completely empty. On my guess, this happens because of the line
tokens = new string[length];
I think memory space for tokens array as local variable is allocated and when split function is finished, this memory space will be free as block is finished.
when i try to debug, split function itself is working very well as tokens array is full of tokens at least in split function block. I think my guess is right but how can I solve this problem? Any solution? I think this is not only matter of std::string array, this is homework of "call by reference".
Requirement
pass std::string[] type to function parameter (return tokens[] is OK too. But I think this will have same problem)
when function is finished, array must full of tokens
tokens array length must be calculated in split function(if user has to calculate tokens length, it is foolish function). Because of this, memory for tokens array can't be allocated before split function call.
Thank you in advanced for your great answer!
As #chris suggested, something like the following code should work.
Example Code
#include <iostream>
#include <string>
#include <vector>
std::vector<std::string> split(const std::string& delimiter, const std::string& str)
{
std::vector<std::string> result;
std::size_t prevPos = 0;
while (prevPos != std::string::npos)
{
std::size_t currPos = str.find(delimiter, prevPos);
result.push_back(str.substr(prevPos, currPos - prevPos));
prevPos = currPos;
if (prevPos != std::string::npos)
{
// Skip the delimiter
prevPos += delimiter.size();
}
}
return result;
}
int main()
{
std::string str("this,is,a,test");
std::vector<std::string> splitResult = split(",", str);
for (const auto &s : splitResult)
{
std::cout << "'" << s << "'\n";
}
std::cout << "\n";
str = "this - is - a - test";
splitResult = split(" - ", str);
for (const auto &s : splitResult)
{
std::cout << "'" << s << "'\n";
}
return 0;
}
Example Output
'this'
'is'
'a'
'test'
'this'
'is'
'a'
'test'

I am having an issue storing a character in a pointer to a structure.

String* substr(String* str, int start, int end)
{
String* substr = new String;
for(int i = start; i < end; i++)
{
substr = str->text[i];
}
return substr;
}
//the problem is in the substr method. substr is supposed to store a part of a string separated by a delimiter.
Since substr is a pointer to the object of String struct, you should point to that object's array of chars. Something like this:
String* substr(String* str, int start, int end)
{
String* substr = new String;
for(int i = start; i < end; i++)
{
substr->text[i] = str->text[i]; // Now char = char
}
return substr;
}
Depending on the way you handle that array of chars, you might face some further problems with the size of it.

Simple read from text file algorithm doesn't work

I have a text file that contains keys and values like this:
keyOne=1
keyTwo=734
keyThree=22.3
keyFour=5
The keys are just lower-case and upper-case letters like in my example. The values are either integers or floats. Each key and value is separated by an equals sign (=). Now I want to read the values into variables I have in my program.
This is the code I have tried to read the values:
(I omitted the part where I store the values in my program's variables, and just print them out now for demonstration.)
std::fstream file(optionsFile, std::fstream::in);
if (file.good()) {
int begin;
int end;
std::string line;
while(std::getline(file, line)) {
// find the position of the value in the line
for (unsigned int i = 0; i < line.length(); i++) {
if (line.at(i) == '=') {
begin = i + 1;
end = line.length();
break;
}
}
// build the string... it starts at <begin> and ends at <end>
const char *string = "";
for (int i = begin; i < end; i++) {
string += line.at(i);
}
// only gibberish is printed in the following line :(
std::cout << "string=" << string << std::endl;
}
}
I don't understand why it won't print the value.. instead only weird stuff or even nothing is printed
Please help this broke my spirit so hard :(
You are using C-style strings (char arrays) without properly allocated memory, and you are just manipulating with the pointer, so you are not appending characters into your string:
// build the string... it starts at <begin> and ends at <end>
const char *string = "";
for (int i = begin; i < end; i++) {
string += line.at(i);
}
Use std::string instead:
/// build the string... it starts at <begin> and ends at <end>
std::string str;
for (int i = begin; i < end; i++) {
str += line.at(i);
}
Or allocate memory by hand, use the proper indexing, terminate the string with '\0' character and don't forget to delete the string after you don't need it anymore:
char *string = new char[end - begin + 1];
int j = 0;
for (int i = begin; i < end; i++) {
string[j++] = line.at(i);
}
// Don't forget to end the string!
string[j] = '\0';
// Don't forget to delete string afterwards!
delete [] string;
So, just use std::string.
Edit Why did you mix C strings and std::string in the first place?
As was already mentioned, native string types in c/c++ do not support straightforward concatenation since they are essentially pointers to some preallocated memory. You should always use std::string when a string is supposed to be mutable.
Btw, think about the following refactoring:
void process_option (const std::string& a_key, const std::string& a_value)
{
std::cout << a_key << " <-- " << a_value << std::endl;
}
void read_options (std::istream& a_in, const char* a_source)
{
int line_n = 0;
std::string line;
while (std::getline(a_in, line))
{
++ line_n;
std::string::size_type p = line. find('=');
if (p == line. npos)
{
// invalid_entry(a_source, line_n);
continue;
}
process_option(
line. substr(0, p), // key
line. substr(p + 1, line. find_first_of("\t\r\n", p + 1)) // value
);
}
}
void read_options (const char* a_filename)
{
std::ifstream file(a_filename);
if (! file)
{
// read_error(a_filename);
return;
}
read_options(file, a_filename);
file. close();
}
void read_options (const std::string& a_filename)
{
read_options(a_filename. c_str());
}