My code counts spaces in string temp, which works fine. Later in the code I have a similar loop that does not end as expected.
Based on my debugging and some research, I’ve determined that the while loop isn’t stopping when it is supposed to the second time around, so an exception is thrown (std::out_of_range)… Why? Both while loops’ conditions are identical, so they should behave the same, right? That is, they should both stop looping when find() didn’t find a space…
First part of the code:
// Just find out how many spaces are in the temp string for now
// Find index (position in the string) of the first space in temp string
_index = temp.find( " " );
// Loop as long as there are still spaces in temp string
while (_index != string::npos) {
// Find the index of the next space
_index = temp.find(" ", _index + 1);
// Keep track of how many spaces are in temp string
count++;
}
Later (don’t mind my debugging code interspersed in there):
// If the amount of spaces is just right, i.e. there are exactly SIZE - 1 spaces
if (count == SIZE - 1) {
cout << "\n\n - Inside the if (count == SIZE - 1) block\n"
<< " - temp = \"" << temp << "\", temp's size = " << temp.length()
<< "\n\n";
// This time, we're removing the spaces from the temp string in order to
// be able to search it for any non-number characters
// Find index of the first space in the temp string
_index = temp.find(" ");
cout << " - The first temp.find(\" \") yields: " << _index << "\n\n";
// Loop as long as there are still spaces in temp string
while (_index != string::npos) {
cout << " - Right before temp.replace() in the loop\n"
<< " - _index = " << _index << "\n\n";
// Remove the space in temp string
temp.replace(_index, 1, "");
// find the index of the next space
_index = input.find(" ", _index + 1);
}
// …
}
Within the second loop you reference a variable input instead of temp.
_index = input.find( " ", _index + 1 );`
Therefore the loop does never terminate. This you don't do within the first while-loop.
Related
So I've written this code and it works until I try implemented a part of my second for loop where I try to print a new line. It is suppose to print a new line after the 8th element being printed. Any help appreciated.
// Construct a for loop that runs backwards through the array,
// starting at the last element and ending at the first.
for (int i = arraySize; i > 0; i--) {
// Inside this for loop, print the ith element of the array
// and a tab, with NO newline characters.
cout << newArray[i-1] << " ";
// If this element is the 8th one on its line, print a
// newline character to advance to the next line.
// Also inside this for loop, add the value of the ith
// element to the current value of the double for the sum
// of elements.
//ISSUE IS HERE
if (newArray[i-8] = newArray[7]) {
cout << "\n";
}
sumOfElements += newArray[i-1];
}
I've only pasted the for loop that has the issue, I don't believe any other information is necessary as I know it works up until this point.
You want comparison (==) not assignment (=). But in any case this
if (newArray[i-8] = newArray[7]) {
cout << "\n";
}
is wrong. For i < 8 you will access negative indices, which is out-of-bounds. To check if you are printing the 8th element from the array you only need to look at the index:
if (i == 7) {
cout << "\n";
}
It you rather want to put a new line after 8 elements have been printed then it is
if (i == arraySize-7) {
cout << "\n";
}
If instead you want to put a new line after each 8 elements that have been printed then it is
if ( (i - arraySize - 1)%8 == 0) {
std::cout << "\n";
}
I was trying out a solution to a question, when I came across this code snippet written in C++:
string s;
cin >> s;
vector<int> r;
for (string t: {"twone", "one", "two"}) {
for (size_t pos = 0; (pos = s.find(t, pos)) != string::npos;) {
s[pos + t.length() / 2] = '?';
r.push_back(pos + t.length() / 2);
}
}
cout << r.size() << endl;
for (auto rr: r)
cout << rr + 1 << " ";
cout << endl;
I am new to the language and was unable to understand what is happening in the second (nested) for loop and the 3rd for loop. Can someone help me to understand?
The first and the third loops are range-based for loops.
The first loop iterates over a container of strings. So t takes successively the value "twone", "one", and "two"
The second loop searches for all the occurences of t in the string s (each search starts from position pos of the previous occurence found). As long as a element is found it does:
s[pos + t.length() / 2] = '?';
r.push_back(pos + t.length() / 2);
The push_back() stores the position of the middle of each occurence found in a vector of integers.
The third loop iterates over this vector of stored positions and prints the elements (the positions count starts at 0, the +1 shifts the printed positions as if the count would start with 1).
One of the main ways to try and understand complex code is to try and simplify it. It also helps to know what the involved functions do, so a reference to std::string::find is helpful to read.
First of all, lets skip the body and concentrate only on the loop itself:
for (size_t pos = 0; (pos = s.find(t, pos)) != string::npos;) {
}
All for loops could be seen as a while loop, and while loops could be somewhat easier to understand and follow, so we convert it to such a while loop:
size_t pos = 0;
while (pos = s.find(t, pos)) != string::npos)
{
}
This might not help so much as it's the condition that is most likely the hard part to understand, so then we simplify that as well:
size_t pos = 0;
pos = s.find(t, pos);
while (pos != string::npos)
{
pos = s.find(t, pos);
}
The initialization of pos could then be further simplified:
size_t pos = s.find(t);
while (pos != string::npos)
{
pos = s.find(t, pos);
}
Now the loop itself is a simple as it could be, and looking at it we see that basically attempt to find the sub-string t inside the string s. The loop continues as long as the sub-string t is found inside s.
Now that we deconstructed the loop itself, let's take a look at the loop-body, and what it does:
s[pos + t.length() / 2] = '?';
r.push_back(pos + t.length() / 2);
First of all lets pull out the common sub-expression into a temporary variable:
auto new_pos = pos + t.length() / 2;
s[new_pos] = '?';
r.push_back(new_pos);
The first statement
s[new_pos] = '?';
replaces the middle character of the sub-string t inside s with the character '?'.
The second statement
r.push_back(new_pos);
pushes the position of the '?' into the vector r.
Now lastly we put the inner loop (explained above) into the context of the outer loop:
for (string t: {"twone", "one", "two"})
This is a range-based for loop which loops over all elements in the container on the right-hand side of the :. That is, the loop will iterate three times, with t being equal to "twone", "one" and "two" in that order.
So loops will search for "twone", "one" and "two" inside the string s, replace the middle character of the sub-strings ("twone", "one" and "two") inside s with a single '?' character, and push the position of that '?' character into the vector r.
For example if the input in s is "someone with the number two" then the result will the the string "someo?e with the number t?o", and the vector r should contain the values 5 and 25 (which will be printed as 6 and 26 because of the + 1).
Here's an example shoing exactly that.
Just run the code inserting in it an output pf intermediate results.
Here is a demonstrative program.
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::string s;
std::cin >> s;
std::vector<int> r;
for ( const std::string &t : { "twone", "one", "two" } )
{
for ( std::string::size_type pos = 0; (pos = s.find( t, pos ) ) != std::string::npos; )
{
s[pos + t.length() / 2] = '?';
std::cout << pos << ": " << s << '\n';
r.push_back( pos + t.length() / 2 );
}
}
std::cout << r.size() << '\n';
for ( const auto &rr: r ) std::cout << rr + 1 << " ";
std::cout << '\n';
}
Let's assume that the user entered string onetwoone. So the inner loop searches in the entered string all occurrences of words "twone", "one", "two" sequentially.
For the given string the word "twone" is not found.
The word "one" is found at position 0. This statement
s[pos + t.length() / 2] = '?';
the middle character of the found word in the entered string by the sign '?'.
Thus this added statement
std::cout << pos << ": " << s << '\n';
outputs
0: o?etwoone
The position of the sign '?' (the number 1) is stored in the vector.
Then within the loop the word "one" is found second time. And again the middle character of the found word is substituted for '?'. So this statement
std::cout << pos << ": " << s << '\n';
outputs
6: o?etwoo?e
The position of the sign '?' (the number 7) is stored in the vector.
So at this moment we have the following output
0: o?etwoone
6: o?etwoo?e
The word "one" is not found any more.
The word "two" is occurred only once in the given string. SO the output is
3: o?et?oo?e
The position of '?' equal to 4 is stored in the vector.
Now at this moment we have the following output
0: o?etwoone
6: o?etwoo?e
3: o?et?oo?e
produced by the inner loop.
So as a result three occurrences of the words are found in the entered string.
Thus these statements
std::cout << r.size() << '\n';
for ( const auto &rr: r ) std::cout << rr + 1 << " ";
output
3
2 8 5
The last values correspond to expressions rr + 1 that is to stored positions of the sign '?' plus 1.
I am attempting to remove all double spaces from my string so that only single spaces remain:
while (doublespace != -1) {
kstring.replace(doublespace, 1, " ") ;
doublespace = kstring.find_first_of(" ") ; }
it finds the first double space, triggering the while statement. It then takes the first space, adds 1 to it and sets the two spaces to one space. Then it checks again.
The problem is that the loop never ends - for example if I put "hello " doubleSpace would never be set to -1.
std::string::find_first_of only searches until it finds one of the characters in the input string, so as you pass it " ", it'll effectively only search for " " - see the documentation here:
Searches the string for the first character that matches any of the characters specified in its arguments.
You should use std::string::find instead, which searches for the first instance of the entire substring:
Notice that unlike member find_first_of, whenever more than one character is being searched for, it is not enough that just one of these characters match, but the entire sequence must match.
You're also replacing only the first space with a space (sString.replace(doubleSpace, 1, " "), which means your output will still contain double spaces. Just use std::string::erase instead, to erase just the first space.
This means your code snippet should look more like:
std::size_t doubleSpace = sString.find(" ");
while (doubleSpace != std::string::npos)
{
sString.erase(doubleSpace, 1);
doubleSpace = sString.find(" ");
}
Here is an alternative take that returns copy with only single spaces in it:
#include <iostream>
#include <string>
int main()
{
std::string str = " hello - h e l l o ";
std::string newstr;
size_t beg = 0;
size_t len = str.length();
while (beg < len)
{
size_t end = str.find_first_of(' ', beg) + 1;
newstr += str.substr(beg, end - beg);
beg = str.find_first_not_of(' ', end);
}
std::cout << newstr << std::endl;
return 0;
}
Result:
hello - h e l l o
As suggested by #hnefatl this approach could also be more efficient (see comment below)
I see two errors in your code. The first is that find_first_of() only searches for one of the characters you supply so, in your case, it will only be looking for single spaces. Secondly you only replace one space, not two.
This should fix both those problems:
std::string& reduce_double_spaces(std::string& s)
{
std::string::size_type pos = s.find(" ");
while (pos != std::string::npos) {
// replace BOTH spaces with one space
s.replace(pos, 2, " ");
// start searching again, where you left off
// rather than going back to the beginning
pos = s.find(" ", pos);
}
return s;
}
NOTE: By beginning the subsequent searches from the place you found your last space, this version should be much more efficient. The longer the string the bigger the savings.
This alternative uses const time operations of back(), pop_back(), push_back(), empty(), and size(),
std::string str = " hello - h e l l o ";
std::string newStr = str; // diag only
std::string Miss; Miss.reserve(str.size());
while ( str.size() > 1 ) // note: str.back() undefined when str.empty()
{
// fetch copy and remove last element
char aKar = str.back(); str.pop_back();
if (! ((' ' == aKar) && // space
( ' ' == str.back()))) // space
{
Miss.push_back(aKar); // not double-space
}
}
assert(1 == str.size()); // optional
while (! Miss.empty() ) // restore str to original order
{
str.push_back (Miss.back()); // copy last element
Miss.pop_back(); // remove last element
}
assert(Miss.empty()); // optional
std::cout << "\n " << __FUNCTION__
<< "\n in: " << newStr
<< "\n out: " << str << std::endl;
This is a bit complicated, but basically I'm making a program and one of my functions is acting a bit strange. The function is fed an array of characters, the first time it's
new_sensor_node SN42 42 3.57 5.0 7.
right now the function just prints out each individual "token" (each set of characters separated by spaces). Then prints a space, and then prints the number of characters in the token. But for some reason, the last token is always printed weird, and 1 character extra is counted.
Here's the function:
int parseCommandLine(char cline[], char *tklist[]){
int i;
int length;
int count = 0; //counts number of tokens
int toklength = 0; //counts the length of each token
length = strlen(cline);
for (i=0; i < length; i++) { //go to first character of each token
if (((cline[i] != ' ' && cline[i-1]==' ') || i == 0)&& cline[i]!= '"') {
while ((cline[i]!=' ')&& (cline[i] != '\0')){
toklength++;
cout << cline[i];
i++;
}
cout << " " << toklength << "\n\n";
cout << "\n";
toklength = 0;
count ++;
}
if (cline[i] == '"') {
do {
i++;
} while (cline[i]!='"');
count++;
}
}
//cout << count << "\n";
return 0;
And here's the output (for that first array):
new_sensor_node 15
SN42 4
42 2
3.57 4
5.0 3
7.
3
Any thoughts on what could be causing this? I suspect it might have to do with how I'm dealing with the null character
It's very likely that the input string actually contains the newline at the end. Depending on how you read the input, it may or may not be in the input. For example, the fgets function reads the newline and leaves it in the buffer.
Especially since you don't actually do any actual tokenization or modification of the input string, you just print character by character, this is a very likely scenario.
I'm just starting out programming but I've had a lot of ideas about how to make my life easier when parsing files by making a program that maps addresses of data when read into memory from a file.
Note: I cut down the wall text here's the problem in a nutshell
How does one parse an array of chars with no null terminator but the words all begin with uppercase letters so Capital can be used as delimiter?
Basically I want to parse text file that is just 'WordWordWord' and send each word to a to it's own separate string variable then be able to write each word to a text file with a newline added.
I wanted to do some more advanced stuff but I was asked to cut the wall of text so that will do for now :)
//pointers and other values like file opening were declared
int len = (int) strlen( words2 );
cout << "\nSize of Words2 is : " << len << " bytes\n";
// Loops through array if uppercase then...
for (int i = 0; i < len; i++)
{
if (isupper(words2[i]))
{
// Output the contents of words2
cout << "\n Words2 is upper : " << words2[i] << "\n";
b1 = &words2[i];
//output the address of b1 and the intvalue of words2[var]
cout << "\nChar address is " << &b1 << " word address is " << (int) words2[i] << "\n";
cout << "\nChar string is " << b1 << " address +1 "<< &b1+1 <<"\n and string is " << b1+1 << "\n";
}
cout << "\nItem I is : i " << i << " and words2 is " << words2[i] << "\n";
}
fin.clear();
fin.close();
fout.close();
Easy. Use Boost.Tokenizer, with char_separator("", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"). "" is the set of dropped separators, and A-Z is the set of kept separators. (If you'd used A-Z as dropped separators, you'd get ord ord ord because you'd drop the W.)
Since you also
wanted to do some more advanced stuff
I would have a look a Boost.Regex from the get go. This is a good library for doing textual manipulations.
vector<char *> parsedStrings;
char * words = "HelloHelloHello";
int stringStartAddress = 0;
for (int i = 0; i <= strlen(words); i++)
{
/* Parses word if current char is uppercase or
if it's the last char and an uppercase char was previously matched */
if (isupper(words[i]) || ((i == strlen(words)) && (stringStartAddress != 0)))
{
// Current char is first uppercase char matched, so don't parse word
if (stringStartAddress == 0)
{
stringStartAddress = ((int)(words + i));
continue;
}
int newStringLength = ((int)(words + i)) - stringStartAddress;
char * newString = new char[newStringLength + 1];
// Copy each char from previous uppercase char up to current char
for (int j = 0; j < newStringLength; j++)
{
// Cast integer address of char to a char pointer and then get the char by dereferencing the pointer
// Increment address to that of the next char
newString[j] = *((char *)stringStartAddress++);
}
newString[newStringLength] = '\0'; // add null-terminator to string
parsedStrings.push_back(newString);
}
}