Understanding a C++ program [ Bjarne Stroustrup's book ] - c++

i need your precious help for a small question!
I'm reading the Bjarne Stroustrup's book and i found this exemple:
int main()
{
string previous = " ";
string current;
while (cin >> current) {
if(previous == current)
cout << "repeated word: " << current << '\n';
previous = current;
}
return 0;
}
My question is: What does string previous = " "; do?
It initializes previous to the character space (like when you press space). But I thought in C++ it doesn't read it, something about the compiler skipping over whitespace. Why initialize it to that then?
I have tried to write like that: string previous; and the program still work properly... so? What is the differnece? Please enlighten me x)

You seam to be confused on what it means in C++ to ignore whitespace. In C++
std::string the_string = something;
is treated the same as
std::string the_string=something ;
No when you have a string literal the whitespace in the literal is not ignored as it is part of the charcters of the string. So
std::string foo = " ";
Creates a string with one space where as
std::string foo = " ";
Creates a string with 4 spaces in it.

You are right, a whitespace is something you will never get when reading input using std::cin. Therefore, a previous string is initialized with a value that could never (i.e. when reading the first word) possibly match word read into current string.
In this case previous could alsobe initalized to an empty string, because istream::operator>> skips all the whitespace and you would never get an empty like by reading from std::cin that way. However, there are other ways of using std::cin (e.g. together with getline()), which may lead to reading an empty string.
The book explains this example in every detail.

string previous = " ";
assigns a space to the string variable 'previous'.
It may still 'work', but if you were to simply press enter on the first try, the 'repeated word' message should appear.

He could just write :)
string previous;
The idea is that the operator >> can not enter an empty string if by default there is set to skip white spaces.
So any comparison current with an empty string or a string that contains white spaces will yield false.

Related

Building a list of words from a sentence inputted

I am fairly new to programming and would like help with my homework. I have no idea where to even start.
"
1. Have the user input a sentence
2. Print out the individual words in the sentence, along with the word number
So the string "This is a test of our program." should produce:
1. This
2. is
3. a
4. test
5. of
6. our
7. program
This should strip out all spaces, commas, periods, exclamation points."
if you can give me some pointers. thanks.
You will have to use strings and streams from the standard library. You can start by including the following headers
#include <string>
#include <iostream>
A good starting point would be to look at the introduction here
Try some stuff with std::cout. This method allows you to output content to the console. Start with something easy, such as:
std::cout << "Hello World" << endl;
You can also output the content of a variable the same way:
std::string myString = "SomeText";
std::cout << myString << endl;
std::cout does the opposite. It allows you to capture the user input into a variable.
int myNumber;
std::cin >> myNumber;
or
std::string userInputString;
std::getline(std::cin, userInputString)
Notice that in the second case we're using std::getline. This is because std::cin behaves in such a way that it will stop after the first word if you write an entire sentence.
Now that you've captured the user input string, you can remove undesired characters, split the string, etc.. Look at what is available in the string class. Good luck.

split string - multiple delimiter C++

so this user input all in one line string , i need to parse the input into two categories: user age and user name.
for example , the user input -->> [23:Frank] [15:Jack] [45:] [33:sofia] []
in this case i have more than one argument (delimiter, total of 3 ) which are [:] , in addition i need to get user input and stop looping once i encounter the [] at the end.
this is what i was thinking :
string input;
vector<string> age;
vector<string> name;
cin >> input;
while (input != "[]")
{
get age between first [ and :
assign to age variable
get name between : ]
assign to user name variable
................
}
also - what if one of the brackets is missing a name , how can assign a blank name and skip that part in order to process the rest (meaning i will output age with no name next to it).
any suggestions regarding how to get and process the data.
i saw some advance stuff like Toknizing and booster which are advance for my course, that's why i was thinking about straight forward getline and parse functions.
Thank you.
Read in token like you are currently doing with cin
test for [] as you are doing with the while loop
For the inside the loop, here are a few things to help you out:
std::string's front and back functions are perfect for ensuring that input starts with [ and ends with ]
std::string's substr function is perfect for trimming off the [] so you can easily ignore them for the rest of the parsing
std::stringstream allows you to call make a stream that only contains your trimmed input.
std::getline(stream, string, char) will read all characters it finds up to the char parameter or the end of the stream and stuff the results in the string parameter and then discard the char it found so you won't trip over it parsing the rest of the input.
strtoul will convert a string into a number and tell you if it failed. It will not accept negative numbers so you can catch people trying to trick your program.
getline(stream, string) will read the stream until it hits an end of line marker. Perfect for reading the rest of a stream that contains no end of lines.
Using strtoul:
char * endp;
unsigned long agenum strtoul(agestr.c_str(), // turn string into old c-style string
&endp, // will be updated with the end of the char after the last number
10); // base ten numbers
if (endp != '\0') // old c-strings always end on a null (numerical zero). If strtoul
// didn't end on a null, the string wasn't a valid number.
{
//not a number
}
Ok , so THANKS for people who helped or at least tried to help!!
what i end up doing for this part was as follows:
read in each string at once
use the find function in order to locate my delimiters ( which are in this case [ : ] )
return positions per each perimeter based on my argument (each pair will hold either the beginning and the end for age || name)
pass those arguments results to truncate the string by using substr function, then assign into each variables.
while (true)
{
string myInput;
cin >> myInput;
while (myInput != "[]")
{
int age_beg = myInput.find('[') + 1 ;
int age_end = myInput.find(':', age_beg);
string age = myInput.substr(age_beg, (age_end - age_beg));
int name_beg = age_end + 1;
int name_end = myInput.find(']', name_beg);
string name = myInput.substr(name_beg, (name_end - name_beg));
cout << "NAME : " << name << " AGE : " << age << endl;
cin >> myInput;
}
}
Hope this will help others with the same question in the future !!

Simple C++ not reading EOF

I'm having a hard time understanding why while (cin.get(Ch)) doesn't see the EOF. I read in a text file with 3 words, and when I debug my WordCount is at 3 (just what I hoped for). Then it goes back to the while loop and gets stuck. Ch then has no value. I thought that after the newline it would read the EOF and break out. I am not allowed to use <fstream>, I have to use redirection in DOS. Thank you so much.
#include <iostream>
using namespace std;
int main()
{
char Ch = ' ';
int WordCount = 0;
int LetterCount = 0;
cout << "(Reading file...)" << endl;
while (cin.get(Ch))
{
if ((Ch == '\n') || (Ch == ' '))
{
++WordCount;
LetterCount = 0;
}
else
++LetterCount;
}
cout << "Number of words => " << WordCount << endl;
return 0;
}
while (cin >> Ch)
{ // we get in here if, and only if, the >> was successful
if ((Ch == '\n') || (Ch == ' '))
{
++WordCount;
LetterCount = 0;
}
else
++LetterCount;
}
That's the safe, and common, way to rewrite your code safely and with minimal changes.
(Your code is unusual, trying to scan all characters and count whitespace and newlines. I'll give a more general answer to a slightly different question - how to read in all the words.)
The safest way to check if a stream is finished if if(stream). Beware of if(stream.good()) - it doesn't always work as expected and will sometimes quit too early. The last >> into a char will not take us to EOF, but the last >> into an int or string will take us to EOF. This inconsistency can be confusing. Therefore, it is not correct to use good(), or any other test that tests EOF.
string word;
while(cin >> word) {
++word_count;
}
There is an important difference between if(cin) and if(cin.good()). The former is the operator bool conversion. Usually, in this context, you want to test:
"did the last extraction operation succeed or fail?"
This is not the same as:
"are we now at EOF?"
After the last word has been read by cin >> word, the string is at EOF. But the word is still valid and contains the last word.
TLDR: The eof bit is not important. The bad bit is. This tells us that the last extraction was a failure.
The Counting
The program counts newline and space characters as words. In your file contents "this if fun!" I see two spaces and no newline. This is consistent with the observed output indicating two words.
Have you tried looking at your file with a hex editor or something similar to be sure of the exact contents?
You could also change your program to count one more word if the last character read in the loop was a letter. This way you don't have to have newline terminated input files.
Loop Termination
I have no explanation for your loop termination issues. The while-condition looks fine to me. istream::get(char&) returns a stream reference. In a while-condition, depending on the C++ level your compiler implements, operator bool or operator void* will be applied to the reference to indicate if further reading is possible.
Idiom
The standard idiom for reading from a stream is
char c = 0;
while( cin >> c )
process(c);
I do not deviate from it without serious reason.
you input file is
this is fun!{EOF}
two spaces make WordCount increase to 2
and then EOF, exit loop! if you add a new line, you input file is
this is fun!\n{EOF}
I took your program loaded it in to visual studio 2013, changed cin to an fstream object that opened a file called stuff.txt which contains the exact characters "This is fun!/n/r" and the program worked. As previous answers have indicated, be careful because if there's not a /n at the end of the text the program will miss the last word. However, I wasn't able to replicate the application hanging in an infinite loop. The code as written looks correct to me.
cin.get(char) returns a reference to an istream object which then has it's operator bool() called which returns false when any of the error bits are set. There are some better ways to write this code to deal with other error conditions... but this code works for me.
In your case, the correct way to bail out of the loop is:
while (cin.good()) {
char Ch = cin.get();
if (cin.good()) {
// do something with Ch
}
}
That said, there are probably better ways to do what you're trying to do.

cin in a while-loop

#include <iostream>
using namespace std;
int main()
{
string previous;
string current;
while (cin >> current)
{
if(current == previous)
{
cout << "repeated word";
}
previous=current;
}
return 0;
}
my questions are:
When it states while(cin>>current), why is the entire entered string of text not assigned to current? I don't understand how it compares all the words individually.
How does it get a word for previous. How does it know 2 of the same words are adjacent?
EDIT: I think I just understood why. Tell me if I am wrong but I think its because the compiler stops the cin assignment at the space and that first word is assigned to current, then it compares it to the previous word, but since it is the first word, it does not have a previous word so it just assigned the first word to previous and compares the next word in the sentence until there are no more words left. I'm fairly certain this is how it works but I am going to leave this up in case anyone is ever wondering something similar.
The default behavior is to stop on whitespace when reading strings as you are doing. You can change it to read whitespace by saying std::cin >> std::noskipws.
The previous word is always assigned at the end of the loop. Given the answer to part 1, it should be clear why previous works.
If you use std::istream::operator>> with a std::string argument, it reads characters until it finds any whitespace character. This means that it will only read a single "word" if you're entering a sentence. Use std::getline(cin, current); to read an entire line (until a newline character).
You assign current to previous: previous = current. This means that after reading current, you make previous current. So the next time, before you read, you can compare previous with current to see if they're the same thing.
If you want to use string, you must use #include string or std_lib_facilities.h

Line Breaks when reading an input file by character in C++

Ok, just to be up front, this IS homework, but it isn't due for another week, and I'm not entirely sure the final details of the assignment. Long story short, without knowing what concepts he'll introduce in class, I decided to take a crack at the assignment, but I've run into a problem. Part of what I need to do for the homework is read individual characters from an input file, and then, given the character's position within its containing word, repeat the character across the screen. The problem I'm having is, the words in the text file are single words, each on a different line in the file. Since I'm not sure we'll get to use <string> for this assignment, I was wondering if there is any way to identify the end of the line without using <string>.
Right now, I'm using a simple ifstream fin; to pull the chars out. I just can't figure out how to get it to recognize the end of one word and the beginning of another. For the sake of including code, the following is all that I've got so far. I was hoping it would display some sort of endl character, but it just prints all the words out run together style.
ifstream fin;
char charIn;
fin.open("Animals.dat");
fin >> charIn;
while(!fin.eof()){
cout << charIn;
fin >> charIn;
}
A few things I forgot to include originally:
I must process each character as it is input (my loop to print it out needs to run before I read in the next char and increase my counter). Also, the length of the words in 'Animals.dat' vary which keeps me from being able to just set a number of iterations. We also haven't covered fin.get() or .getline() so those are off limits as well.
Honestly, I can't imagine this is impossible, but given the restraints, if it is, I'm not too upset. I mostly thought it was a fun problem to sit on for a while.
Why not use an array of chars? You can try it as follow:
#define MAX_WORD_NUM 20
#define MAX_STR_LEN 40 //I think 40 is big enough to hold one word.
char words[MAX_WROD_NUM][MAX_STR_LEN];
Then you can input a word to the words.
cin >> words[i];
The >> operator ignores whitespace, so you'll never get the newline character. You can use c-strings (arrays of characters) even if the <string> class is not allowed:
ifstream fin;
char animal[64];
fin.open("Animals.dat");
while(fin >> animal) {
cout << animal << endl;
}
When reading characters from a c-string (which is what animal is above), the last character is always 0, sometimes represented '\0' or NULL. This is what you check for when iterating over characters in a word. For example:
c = animal[0];
for(int i = 1; c != 0 && i < 64; i++)
{
// do something with c
c = animal[i];
}