Why is this simple program giving a segmentation fault? - c++

I have written a simple C++ program. The idea is, once it sees a non-alphabetic character, then till the time it see a new word (a blank) or the string ends, it keeps on incrementing the iterator.
This generates Segmentation fault, no idea why :(
Please help.
#include <iostream>
using namespace std;
int main()
{
string str("Hello yuio");
string::iterator it=str.begin();
while(it!=str.end())
{
cout << *it << endl;
if(isalpha(*it)==0){
cout << *it << ":Is not an alphabet\n";
while((*it!=' ')||(it!=str.end()))
{
cout << *it << endl;
it++;
}
}
if(it!=str.end()){it++;}
} // while loop ends
} // End of main

while((*it!=' ')||(it!=str.end()))
*it is evaluated before checking if it itself is ok to use. Change to:
while((it!=str.end())&&(*it!=' '))

while((*it!=' ')||(it!=str.end()))
The line above contains two errors.
The condition says that the loop shall go on while the current character is not a space OR end of string is not reached yet. I.e., even when the end is reached but current char is not a space, the loop will proceed.
Once you fixed this error (by replacing || with &&), you still try to dereference the end iterator (because the check for space comes before the check for end of string), which is not allowed. You have to switch the order of conditions:
while((it!=str.end()) && (*it!=' '))

The problem is here:
while((*it!=' ')||(it!=str.end()))
When you reach the end of the string, the first part of the condition is true and so you continue looping and incrementing the iterator.
You need to replace with &&:
while((*it!=' ')&&(it!=str.end()))

Related

Removing starting characters from string using std::string::erase

I am trying to truncate beginning zeros from a string, so I used sequence erase function
string& erase (size_t pos = 0, size_t len = npos);
This is my implementaion:
string str="000010557";
for(char c:str){
cout<<c<<" "<<str<<" "<<"\n";// for debug purpose
if(c=='0')
str.erase(0,1);
else
break;
}
cout<<str;
the output string that I got is 0010557 instead of10557 and debug statements prints:
0 000010557
0 00010557
1 0010557
I read the documentation of erase and this post thinking might there be some iterator invalidation but implementing the code snippet recommended in the accepted answer also gave the same output, please help me understand where is the problem.
I am new to using stl library functions, so please forgive any negligence of mine,Thanks.
Your for loop is incrementing the position from which c is extracted, even if you erase a leading zero. Thus, after two runs of the loop, you have erased the first and third of the leading zeros, then the c value will be the first 1.
Here's an attempt at following what happens in your code:
Start of first loop:
"000010557"
^
c is '0', so erase is called, making the string:
"00010557"
At the end of this first loop, the position is incremented, so...
Start of second loop:
"00010557"
^ (Note that we've skipped a zero!)
c is '0', so erase is called, making the string:
"0010557"
End of loop, position increment, and we skip another zero, so...
Start of third loop:
"0010557"
^
c is not '0', so we break out of the loop.
Instead, you should use a while loop, testing only the first character:
int main()
{
string str = "000010557";
char c;
while ((c = str.at(0)) == '0') {
cout << c << " " << str << " " << "\n";// for debug purpose
str.erase(0, 1);
}
cout << str;
}
Output:
0 000010557
0 00010557
0 0010557
0 010557
10557
Of course, you only need the c variable for your 'debugging' line so, without that, you can just have:
int main()
{
string str = "000010557";
while (str.at(0) == '0') str.erase(0, 1);
cout << str;
}
Even if you get this code to work, it's not a good solution. Removing a single character from the front of a string means moving all of the subsequent characters down one position, and the code does that for every leading zero. Instead, count the leading zeros and remove them all at once:
std::string::size_type non_zero_pos = 0;
while (non_zero_pos < str.size() && str[non_zero_pos] == '0')
++non_zero_pos;
str.erase(0, non_zero_pos);
That way, the (expensive) erase operation is only done once.
Or use iterators:
auto non_zero_it = std::find_first_not_of(std::begin(str), std::end(str), "0");
str.erase(std::begin(str), non_zero_it);
Edit: fixed search for non-0 iterator.

Ignore Spaces Using getline in C++ Palindrome homework

I am trying to skip the spaces in my code using getline();
I think I solved the spacing problem, but I'm trying to make the code check from the beginning of the word and the end of the word at the same time, so that when I type sentences like "ufo tofu" it will come back as a palindrome.
I've tried removing the spaces, but it only causes the system to return me an error.
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
int main() {
string userInput;
int startInput;
int endInput;
bool isPalindrome = true;
startInput = userInput.length();
getline (cin, userInput);
cin.ignore();
for (int i = 0; i<(startInput/2); i++){
if (userInput[i] != userInput[(startInput -1) -i])
isPalindrome = false;
}
if (isPalindrome){
cout << userInput << " is a palindrome" << endl;
}
else {
cout << userInput << " is not a palindrome" << endl;
}
return 0;
}
I am trying to make the output come back as "is not a palindrome" when I submit my code to be graded.
These are the two errors that are coming back;
4: Compare output
0 / 2
Output differs. See highlights below.
Special character legend
Input
statistics
Your output
statistics is a palindrome
Expected output
statistics is not a palindrome
6: Compare output
0 / 2
Output differs. See highlights below.
Special character legend
Input
evil is alive
Your output
evil is alive is a palindrome
Expected output
evil is alive is not a palindrome
string s;
do {
getline(cin, s);
}while(s.empty());
s.erase((remove(s.begin(),s.end(),' ')),s.end());
cout<<s<<endl;
Let's say your string s is ufo tofu. It will after erasing all spaces become ufotofu. That way you can easily check if it's palindrome or not.
How does this thing work ?
Well we declare a string called s. In that string, we will store our ufo tofu input.
We use do-while loop to input our "sentence" into a string. We could use just getline(cin, s);, but if you pressed enter-key once, it would stop your program.
Next thing, we use function combination of functions remove and erase: As the beginning parameter we use function remove, which finds all the spaces in the string, pushes them to the end of the container (in our case string s), and returns beginning iterator of that "pushing", and the second parameter tells us to remove every single element of container from that beginning iterator to the end.
We just print out the string, but now without spaces!
I think this is really simple way to do it, but if it can't be useful to you, I am sorry for wasting your time reading all of this! :)

While loop in C++ (using break)

I'm currently working through the book C++ Primer (recommended on SO book list). An exercise was given that was essentially read through some strings, check if any strings were repeated twice in succession, if a string was repeated print which word and break out of the loop. If no word was repeated, print that. Here is my solution, I'm wondering a) if it's not a good solution and b) is my test condition for no repeated words ok? Because I had to add 1 to the variable to get it to work as expected. Here is my code:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
vector<string> words = {"Cow", "Cat", "Dog", "Dog", "Bird"};
string tempWord;
unsigned int i = 0;
while (i != words.size())
{
if (words[i] == tempWord)
{
cout << "Loop exited as the word " << tempWord << " was repeated.";
break;
}
else
{
tempWord = words[i];
}
// add 1 to i to test equality as i starts at 0
if (i + 1 == words.size())
cout << "No word was repeated.";
++i;
}
return 0;
}
The definition of "good solution" will somewhat depend on the requirements - the most important will always be "does it work" - but then there may be speed and memory requirements on top.
Yours seems to work (unless you have the first string being blank, in which case it'll break); so it's certainly not that bad.
The only suggestion I could make is that you could have a go at writing a version that doesn't keep a copy of one of the strings, because what if they're really really big / lots of them and copying them will be an expensive process?
I would move the test condition outside of the loop, as it seems unnecessary to perform it at every step. For readability I would add a bool:
string tempWord;
unsigned int i = 0;
bool exited = false;
while (i != words.size())
{
if (words[i] == tempWord)
{
cout << "Loop exited as the word " << tempWord << " was repeated.";
exited = true;
break;
}
else
{
tempWord = words[i];
}
++i;
}
// Doing the check afterwards instead
if (!exited)
{
cout << "No word was repeated.";
}
a) if it's not a good solution
For the input specified it is a good solution (it works). However, tempWord is not initialized, so the first time the loop runs it will test against an empty string. Because the input does not contain an empty string, it works. But if your input started with an empty string it would falsely find as repeating.
b) is my test condition for no repeated words ok? Because I had to add 1 to the variable to get it to work as expected.
Yes, and it is simply because the indexing of the array starts from zero, and you are testing it against the count of items in the array. So for example an array with count of 1 will have only one element which will be indexed as zero. So you were right to add 1 to i.
As an answer for the training task your code (after some fixes suggested in other answers) look good. However, if this was a real world problem (and therefore it didn't contain strange restrictions like "use a for loop and break"), then its writer should also consider ways of improving readability.
Usage of default STL algorithm is almost always better than reinventing the wheel, so I would write this code as follows:
auto equal = std::find_adjacent(words.begin(), words.end());
if (equal == words.end())
{
cout << "No word was repeated" << endl;
}
else
{
cout << "Word " << *equal << " was repeated" << endl;
}

c++ counting number of lowercase letters in a user inputted line of text

I have only been doing this for 3 months and currently at a stand still. I am not sure what I'm doing wrong. I would appreciate any help pointing me in the right direction. I am not asking for anyone to do my homework for me. I am supposed to write a program to accept from the user one line of input and then count and output the number of lowercase letters. This is what I have so far but it doesn't do what it is supposed to do.
#include <fstream>
#include <iostream>
#include <cctype>
#include <string>
using namespace std;
int main(){
char text;
int count = 0;
cout << " Enter one line of text: ";
do
{
cin.get(text);
while(text!='\n')
{
if(islower(text))
count++;
}
} while(text!='\n');
cout << count << "\n";
}
The problem was with the input: you input distinct characters, but whitespace would be skipped.
You can use std::getline to get a line of input at once:
#include <algorithm>
#include <iostream>
#include <cctype>
#include <string>
using namespace std;
int main()
{
cout << " Enter one line of text: ";
string s;
if(getline(cin, s))
{
size_t count = count_if(s.begin(), s.end(),
[](unsigned char ch) { return islower(ch); });
cout << count << "\n";
}
}
You create an infinite loop:
while (text != '\n') {
...
}
will continue forever if text (somewhat of a misnomer for a character) ever happens to be something different than '\n'. As a general guideline, whenever you create a loop you need to verify that the body of the loop somehow makes progress towards the end of the loop and that the end of the loop is reached (unless, of course, you intend to create an infinite lop) You probably just want to get rid of this while (...) and just keep the body.
Note that the outer loop should have two conditions to terminate:
It should terminate if you reach the end of a line.
It should terminate if you reach the end of the input: This isn't necessarily terminated by a newline.
If I were to write the loop it would look something like this:
for (std::istreambuf_iterator<char> it(std::cin), end; it != end && *it != '\n'; ++it) {
// do something with the `char` obtained from `*it`
}
It is also worth noting that you need to make sure that a positive value is passed to islower() (or any of the other functions from <cctype>): There are systems where char is signed and, e.g., the ü in my name would convert into a negative value, causing undefined behavior when calling islower('ü'). The way to avoid this problem is to convert the char into an unsigned char before passing it to the <cctype> functions: the bit pattern of static_cast<unsigned char>(c) is identical to the bit pattern of c (assuming that c is of type char).
Sticking with the original approach of a while-loop reading a char, the basic loop would look something like this:
while (std::cin.get(text) && text != '\n') {
if (std::islower(std::static_cast<unsigned char>(text))) {
++count;
}
}
In general, I have found that do ... while-loops rarely don't survive into production code and this isn't an exception: You only want to enter the loop if the char could successfully be read. Since a newline won't be a lower case letter, it can be put into the condition directly as well. For ASCII character std::islower(text) would work but to make the code solid, I have added a cast to unsigned char to make sure things won't break. Finally, the C++ idiom to increment variables is, ironically, preincrement, i.e. ++count rather than count++. The primary use is that preincrement is more efficient if the type to which it is applied is not entirely trivial. Since C++ uses lots of iterators which are incremented, it is conventional to use preincrement.

String subscript out of range. String size is unknown and looping string until null

#include<iostream>
#include<cmath>
#include<iomanip>
#include<string>
using namespace std;
int main()
{
string word;
int j = 0;
cin >> word;
while(word[j]){
cout << "idk";
j++;
}
cout << "nope";
system("pause");
return 0;
}
This is just a little trial program to test this loop out. The program I am working on is about vowels and printing vowels out from a sequence determined by the user. The string isn't defined until the user types in. Thank you for your guys help in advance.
Try this for your loop:
while(j < word.size()){
cout << "idk";
j++;
}
The size of an std::string is not unknown - you can get it using the std::string::size() member function. Also note that unlike C-strings, the std::string class does not have to be null-terminated, so you can't rely on a null-character to terminate a loop.
In fact, it's much nicer to work with std::string because you always know the size. Like all C++ containers, std::string also comes with built-in iterators, which allow you to safely loop over each character in the string. The std::string::begin() member function gives you an iterator pointing to the beginning of the string, and the std::string::end() function gives you an iterator pointing to one past the last character.
I'd recommend becoming comfortable with C++ iterators. A typical loop using iterators to process the string might look like:
for (std::string::iterator it = word.begin(); it != word.end(); ++it)
{
// Do something with the current character by dereferencing the iterator
//
*it = std::toupper(*it); // change each character to uppercase, for example
}