Write a function definition that counts the number of words in a line from your text source.
I tried two different codes and got two different results
countwords()
{
ifstream file("notes.txt");
int count=0;
char B[80];
file>>B;
While (!file.eof())
{
cout<<B<<endl;
file>>B;
count++;
}
}
This gives the desired answer.
The other way around :
countwords()
{
ifstream file("notes.txt");
char B[80];
int count=0;
While (!file.eof())
{
file>>B;
cout<<B<<endl;
count++;
}
}
But this gives an answer which is 1 more than the actual number of words.
Can someone please explain the working of the eof() function and the difference in these two loops?
The second version of your answer will always loop one extra time.
Think about this: what happens if file >> B fails? You'll still increment count.
Also, do not loop on eof() because you'll typically loop one too many times. (Why is iostream::eof inside a loop condition considered wrong?)
Instead, do the following:
while(file >> B)
{
std::cout << B << std::endl;
++count;
}
Because your filestream has an implicit conversion to bool that checks the state of it, and returns false if it's not good.
The problem is not EOF however to see its working Read this.
Talking about your code, note the file>>B; in first code. Since file>>B; fails in last execution of second code, you get one less the correct answer.
The reason for outputting 1 more than the actual number of words: In the 2nd version you output B before reading it for the first time. This is a usage of an uninitialized variable and can result in outputting what will look like garbage, or an empty line. Unreliable code.
Also I would suggest using an std::string instead of char[80] as the type for your variable B.
Related
So recently I've learned that using .eof can be considered a kind of big no no and I want to start moving away from it. One of the main substitutions I have seen is using
while(inFile >> num)
{
}
However, when I do this using arrays it only stores the first input and nothing else. Any tips?
Example:
while(inMovie >> title[x])
{
inMovie >> income[x];
x++;
}
What you really want to be doing is:
while ((inMovie >> title[x]) && (inMovie >> income[x]))
{
x++;
}
Or, more succinctly:
while (inMovie >> title[x] >> income[x])
{
x++;
}
This way, both input operations have to "succeed" in order for you to continue.
That being said, there is nothing inherently broken with your attempt, and there is no reason for it to "only store the first input" as long as the input is correct.
Check your input.
I'm also concerned that you may not be using arrays properly. Does your array have enough space for all these elements? Or are you expecting title and income to expand automatically? Because they won't do that. In that case, your program has undefined behaviour (which may produce all sorts of weird results!) and you should consider using a vector instead.
I am kinda new to programming, so pardon me for any stupid questions :P, i noticed that when i write this
int main()
{
string s;
s[0]='a';
cout<<s.size();
cout<<s<<" ";
cout<<s[0];
return 0;
}
The output is 0 a , firstly why is the size 0? and why didn't anything get printed when i write cout<<s; but it gives a for cout<<s[0]. if i use push_back it gives normal out put.
int main()
{
string s;
s.push_back('a');
cout<<s.size();
cout<<s<<" ";
cout<<s[0];
return 0;
}
output :- 1a a
I might have overlooked something but i would be really appreciate if some could point out the cause.
Thank you.
EDIT: Such fast replies! thanks for your answers, i couldn't figues out how to reply to comments so edited the question body(first time using stackoverflow),
(any help on this would be appreciated as well), one more thing so when i use cout<<s[0] does it give a because a was stored on the next address of string
s?
and once again thanks for clearing that up!
What you've overlooked is that in C++ strings don't automatically grow when you assign characters to them. So
string s;
s[0]='a';
is an error because the s has size zero so there is no 'room' for the character 'a'. The correct way to add a character to a string is to use push_back which is why your second example works.
Because of the error your first example has what's called undefined behaviour (UB for short). This means the output of your program is not predictable at all, and it's more or less a waste of time asking why it outputs what it does. It could just as easily crash.
This:
string s;
creates a string containing no characters. Then this:
s[0]='a';
attempts to make a change to one of those non-existent characters. The result of this is undefined behaviour - your program goes into an unknown state.
If you would like to make your compiler warn you about this problem, you can use the at() member function of string:
s.at(0) = 'a';
Now your program will throw an std::out_of_range exception when you try to change that non-existant character.
Containers don't automatically allocate storage, so you are writing outside the allocated storage. In other words, that's a bug in your program. One advise: Many C++ implementations have a way to activate diagnostics for debugging programs, those would have caught this error.
when I write this
string s;
s[0]='a';
the output is 0, firstly why is the size 0?
The output is zero because operator[i] assumes that the string has sufficient space to store i+1 characters. In your case, string's size is zero, so accessing element at index 0 is undefined behavior.
and why didn't anything get printed when I write to cout
The same thing reason applies: after undefined behavior the program could output anything, but it happens to output nothing.
int main()
{
string s;
s='a';
cout<<s.size();
cout<<s<<" ";
cout<<s[0];
return 0;
}
Just take off [0] after s in initialisation because s is of type string not type char.
Just write s and it will work.
I am learning data file handling basics in c++ (and am working in the compiler turbo C++).
So I wanted to create a text file , write some data onto it and then read it.
So I wrote this: -
int main()
{
fstream fin;
fin.open("textfile.txt",ios::in|ios::out);
for(int i=0;i<3;i++)
{
char x;
cin>>x;
fin<<x;
}
fin.seekg(0,ios::beg); //I added this and also tried seekp() when I didn't get the desired output
//but to no use
while(!fin.eof())
{
char v;
fin>>v;
cout<<v;
}
fin.close();
getch();
return 0;
}
But instead of outputting only the 3 characters which I input, it outputs 4 characters.
I tried removing the loops and taking input and giving outputs one by one like this (among other things):
...
char x,y,z;
cin>>x>>y>>z;
fin<<x<<y<<z;
fin.seekg(0,ios::beg);
char q,w,e;
fin>>q>>w>>e;
cout<<q<<w<<e;
...
But it still didn't work.
I think it has something to do with file pointers and their location but don''t know what. I tried finding a similar question on the net but to no avail.
So I want to know what is wrong with what I did and how to I improve this to actually write and read in a file sequentially using the same file object (if it is even possible). And is seekg() even necessary here?
Thanks.
The problem you face is a general problem. Your input code is right and there is no error in that. The problem is your ouput code and to be more specific the line while(!fin.eof()). eof(end-of-file) works on a end of file mark whose numeric value is generally -1. But this function goes false only when the end character is encountered and traversed. To remove this error just replace this statement with a read statement that is move this line fin>>v from loop statements to the conditional statements. In this false will be when it encounters a end character.
I gave an answer which I wanted to check the validity of stream each time through a loop here.
My original code used good and looked similar to this:
ifstream foo("foo.txt");
while (foo.good()){
string bar;
getline(foo, bar);
cout << bar << endl;
}
I was immediately pointed here and told to never test good. Clearly this is something I haven't understood but I want to be doing my file I/O correctly.
I tested my code out with several examples and couldn't make the good-testing code fail.
First (this printed correctly, ending with a new line):
bleck 1
blee 1 2
blah
ends in new line
Second (this printed correctly, ending in with the last line):
bleck 1
blee 1 2
blah
this doesn't end in a new line
Third was an empty file (this printed correctly, a single newline.)
Fourth was a missing file (this correctly printed nothing.)
Can someone help me with an example that demonstrates why good-testing shouldn't be done?
They were wrong. The mantra is 'never test .eof()'.
Why is iostream::eof inside a loop condition considered wrong?
Even that mantra is overboard, because both are useful to diagnose the state of the stream after an extraction failed.
So the mantra should be more like
Don't use good() or eof() to detect eof before you try to read any further
Same for fail(), and bad()
Of course stream.good can be usefully employed before using a stream (e.g. in case the stream is a filestream which has not been successfully opened)
However, both are very very very often abused to detect the end of input, and that's not how it works.
A canonical example of why you shouldn't use this method:
std::istringstream stream("a");
char ch;
if (stream >> ch) {
std::cout << "At eof? " << std::boolalpha << stream.eof() << "\n";
std::cout << "good? " << std::boolalpha << stream.good() << "\n";
}
Prints
false
true
See it Live On Coliru
This is already covered in other answers, but I'll go over it briefly for completeness. The only functional difference with
while(foo.good()) { // effectively same as while(foo) {
getline(foo, bar);
consume(bar); // consume() represents any operation that uses bar
}
And
while(getline(foo, bar)){
consume(bar);
}
Is that the former will do an extra loop when there are no lines in the file, making that case indistinguishable from the case of one empty line. I would argue that this is not typically desired behaviour. But I suppose that's matter of opinion.
As sehe says, the mantra is overboard. It's a simplification. What really is the point is that you must not consume() the result of reading the stream before you test for failure or at least EOF (and any test before the read is irrelevant). Which is what people easily do when they test good() in the loop condition.
However, the thing about getline(), is that it tests EOF internally, for you and returns an empty string even if only EOF is read. Therefore, the former version could maybe be roughly the similar to following pseudo c++:
while(foo.good()) {
// inside getline
bar = ""; // Reset bar to empty
string sentry;
if(read_until_newline(foo, sentry)) {
// The streams state is tested implicitly inside getline
// after the value is read. Good
bar = sentry // The read value is used only if it's valid.
// ... // Otherwise, bar is empty.
consume(bar);
}
I hope that illustrates what I'm trying to say. One could say that there is a "correct" version of the read loop inside getline(). This is why the rule is at least partially satisfied by the use of readline even if the outer loop doesn't conform.
But, for other methods of reading, breaking the rule hurts more. Consider:
while(foo.good()) {
int bar;
foo >> bar;
consume(bar);
}
Not only do you always get the extra iteration, the bar in that iteration is uninitialized!
So, in short, while(foo.good()) is OK in your case, because getline() unlike certain other reading functions, leaves the output in a valid state after reading EOF bit. and because you don't care or even do expect the extra iteration when the file is empty.
both good() and eof() will both give you an extra line in your code. If you have a blank file and run this:
std::ifstream foo1("foo1.txt");
std::string line;
int lineNum = 1;
std::cout << "foo1.txt Controlled With good():\n";
while (foo1.good())
{
std::getline(foo1, line);
std::cout << lineNum++ << line << std::endl;
}
foo1.close();
foo1.open("foo1.txt");
lineNum = 1;
std::cout << "\n\nfoo1.txt Controlled With getline():\n";
while (std::getline(foo1, line))
{
std::cout << line << std::endl;
}
The output you will get is
foo1.txt Controlled With good():
1
foo1.txt Controlled With getline():
This proves that it isn't working correctly since a blank file should never be read. The only way to know that is to use a read condition since the stream will always be good the first time it reads.
Using foo.good() just tells you that the previous read operation worked just fine and that the next one might as well work. .good() checks the state of the stream at a given point. It does not check if the end of the file is reached. Lets say something happened while the file was being read (network error, os error, ...) good will fail. That does not mean the end of the file was reached. Nevertheless .good() fails when end of file is reached because the stream is not able to read anymore.
On the other hand, .eof() checks if the end of file was truly reached.
So, .good() might fail while the end of file was not reached.
Hope this helps you understand why using .good() to check end of file is a bad habit.
Let me clearly say that sehe's answer is the correct one.
But the option proposed by, Nathan Oliver, Neil Kirk, and user2079303 is to use readline as the loop condition rather than good. Needs to be addressed for the sake of posterity.
We will compare the loop in the question to the following loop:
string bar;
while (getline(foo, bar)){
cout << bar << endl;
}
Because getline returns the istream passed as the first argument, and because when an istream is cast to bool it returns !(fail() || bad()), and since reading the EOF character will set both the failbit and the eofbit this makes getline a valid loop condition.
The behavior does change however when using getline as a condition because if a line containing only an EOF character is read the loop will exit preventing that line from being outputted. This doesn't occur in Examples 2 and 4. But Example 1:
bleck 1
blee 1 2
blah
ends in new line
Prints this with the good loop condition:
bleck 1
blee 1 2
blah
ends in new line
But chops the last line with the getline loop condition:
bleck 1
blee 1 2
blah
ends in new line
Example 3 is an empty file:
Prints this with the good condition:
Prints nothing with the getline condition.
Neither of these behaviors are wrong. But that last line can make a difference in code. Hopefully this answer will be helpful to you when deciding between the two for coding purposes.
I'm a little new to using file input/output so bear with me.
I've got a function called RunList(filename), that takes the name of the file as input and returns nothing. The file will have the format of having one line that is useless and I plan on using ignore() on and then the next line which is important has the format
"i 1 2 3 4 5 ...."
where the numbers go on for a very long way, about 250000 or so.
So what I want to do is to open this file, ignore the first line, and then for each number in the file I want to use the function void insert(x, p) which is a function I have defined to insert x after the current iterator position p. The end result is that I want to have my list contain all of the numbers in the file after the "i" and be in the same order. I have also defined the functions ListItr find(x) and ListItr first() which will return the iterator to the position that views x and to the first potion respectively.
Could anyone provide me with a means of doing this? I was thinking of using a for() loop and taking in each word at a time from the file and using my function to insert each element, but I'm a little lost as to how to do this, as I said I'm very new to using file input/output.
So, my RunList function currently looks something like this, although obviously its not finished nor does it really work, hence me needing some help on it.
void Runlist(filename){
ifstream in;
in.open(filename);
in.ignore(1000, '\n'); //this is me trying to ignore the first line
for (int i, i < 250000, i++){
int number;
in >> number
void insert(number, i)
}
}
But the plan was, I select the file, ignore the first line, then set up a for loop where i can use my void insert(number, i) to insert each number, but then i don't really understand how to read in each word at a time, or to preserve the order because if I just kept using the function on each number over and over then the list would have the numbers in the reverse order I believe.
There are several issues in your code:
You do not specify void for the return type of the function.
Instead of ignore, you could just drop the first line when reading by using getline once.
Your for loop usage is also pretty invalid: commas instead of semi-colons
No initialization of i, and so on.
insert is not shown, but you could probably use append anyway since that is what you seem to be doing.
i is not an "iterator" either, so probably you meant index.
You are having a function declaration in the middle of the function rather than calling it.
This pseudo code should get you going about understanding the input file stream class and its usage for this in C++:
void Runlist(filename)
{
ifstream in(filename, ifstream::in);
in.getline(0, 1024);
int number;
while (in >> number)
append(number);
in.close();
}
Disclaimer: this pseudo code is missing proper error checking, and so on.