Archived

This topic is now archived and is closed to further replies.

Real Simple For You, Real Confusing For Me

This topic is 5151 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I''ve been banging my hand against a wall trying to figure out what is wrong with this program and I can''t do it. All my books are no help on this matter. (FYI this is problem 7 from Chapter 7 of Malik''s C++ Programming: From Problem Analysis to Program Design. I''d ask my teacher, but I''m teaching myself. The assignment is to open up a text file, read the contents of it (while counting the number of words, lines, and paragraphs) and then output the text into another document along with the relevant counts at the end of the file. Two problems: 1. It runs in an infinite loop (printing the very last character) unless there is a newline character at the very end of the input file. 2. It won''t copy over the spaces or newline characters. So it just prints a string of letters. So, the file: The dog ran into the street. The cat is blue.\n Get''s returned as: Thedogranintothestreet.Thecatisblue. Total number of words: 1. Total number of lines: 1. Total number of paragraphs: 9. Again, if there isn''t that newline character, it gives me an endless string of periods. Feel free to bust on me for the code. But I''d really appreciate knowing why the blanks aren''t copying and why it goes into an infinite loops. Thanks in advance.

#include<fstream>
#include<iostream>

using namespace std;

void initialize(int& x, int&y, int& z, int&w);
void processBlank(ifstream& in, ofstream& out, char& ch, int& w);
void copyText(ifstream& in, ofstream& out, char& ch);
void updateCount(int& wordsLine, int& wordsTotal, int& linesTotal, int& paraTotal);
void printTotal(int& wordsTotal, int& linesTotal, int& paraTotal, ofstream& y);

int main()
{
	int wordsLine = 0;
	int wordsTotal;
	int linesTotal;
	int paraTotal;
	char letter;

	ifstream inData;
	ofstream outData;

	inData.open("E:inData.txt");
	outData.open("E:outData.dat");

	initialize(wordsLine, wordsTotal, linesTotal, paraTotal);

	
	inData.get(letter);

	if ((letter != '' '') && ((letter != ''\n'') && (letter != ''\t'')))
		++wordsLine;


	while (inData)
	{
		processBlank(inData, outData, letter, wordsTotal);
		copyText(inData, outData, letter);
		updateCount(wordsLine, linesTotal, paraTotal, wordsTotal);
		inData.get(letter);
	}

	printTotal(wordsTotal, linesTotal, paraTotal, outData);

	inData.close();
	outData.close();

	cout << endl;
	return 0;
}

void initialize(int& x, int&y, int& z, int& w)
{
	x = 0;
	y = 0;
	z = 0;
	w = 0;
	return;
}

void processBlank(ifstream& in, ofstream& out, char& ch, int& w)
{

	while ((ch == '' '') || (ch == ''\t''))
	{
		out.put(ch);
		in.get(ch);

		if ((ch != '' '') && ((ch != ''\n'') && (ch != ''\t'')))
			++w;
	} 
	
	return;
}


void copyText(ifstream& in, ofstream& out, char& ch)
{
	while ((ch != '' '') && ((ch != ''\n'') && (ch != ''\t'')))
	{
		out.put(ch);
		in.get(ch);
	}
	return;
}

void updateCount(int& wordsLine, int& linesTotal, int& paraTotal, int& wordsTotal)
{
	wordsTotal += wordsLine;
	if(wordsLine == 0)
		++paraTotal;
	else
		++linesTotal;
	wordsLine = 0;
	return;
}

void printTotal(int& wordsTotal, int& linesTotal, int& paraTotal, ofstream& y)
{
	y << endl << "Total number of words: " << wordsTotal << ".";
	y << endl << "Total number of lines: " << linesTotal << ".";
	y << endl << "Total number of paragraphs: " << paraTotal << ".";
	return;
}

Share this post


Link to post
Share on other sites
I think you''re losing a blank character in CopyText (reading a space breaks the loop, but that character is not sent to the output).

You get into an infinite loop in copyText, because you''re not checking for the EOF character.

Share this post


Link to post
Share on other sites
You''re right about the copying the variable. The last line in the while loop in main enters in a new character, so the whitespaces get deleted before they get back to the processBlank function.

Thanks.

However, if I delete the line that gets the next character, then I get back into an infinite loop. I switched the condition on the while loop of main over to (!inData.eof()) but that doesn''t fix it.

Do you have any other ideas?

Share this post


Link to post
Share on other sites
OldGuy,
Thanks for the help. I kept at it thinking about the points that you raised and now it is working fine.

I set up a second character variable and used it with peek to have it test for the end of the file. It''s working fine now.

Share this post


Link to post
Share on other sites
What are you compiling this under? I copied your code and compiled it under g++ and it didn't infinitely loop.

EDIT: I should also add, I mean that it did not loop when I had just "The dog ran into the street.
The cat is blue." in the file.

[edited by - suikio on November 6, 2003 12:49:24 AM]

Share this post


Link to post
Share on other sites
It doesn''t see you''re reaching enf-of-file since you''re not checking for it.

while (instream) does not check for end-of-line. In fact, I''m surprised your compiler doesn''t bitch and moan about it - you''re downcasting a stream to a boolean expression.

Try while(!instream.eof()) instead...

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
quote:
Original post by groby
It doesn''t see you''re reaching enf-of-file since you''re not checking for it.

while (instream) does not check for end-of-line. In fact, I''m surprised your compiler doesn''t bitch and moan about it - you''re downcasting a stream to a boolean expression.

Try while(!instream.eof()) instead...


http://www.research.att.com/~bs/bs_faq2.html

Share this post


Link to post
Share on other sites
quote:
Original post by groby
It doesn''t see you''re reaching enf-of-file since you''re not checking for it.

while (instream) does not check for end-of-line. In fact, I''m surprised your compiler doesn''t bitch and moan about it - you''re downcasting a stream to a boolean expression.

Try while(!instream.eof()) instead...


One of the base classes of ifstream, the basic_ios class, defines two operators the void* operator() and the bool operator!(). The fist operator returns a null pointer if the function fail() returns false, that is if rdstate or failbit is set. That happens if eof is true. So using while(instream) is perfectly legal. Don''t ask me why they decided to use a void pointer instead of bool though.

The other operator (bool operator!()) returns true if the stream is not bad, again using fail().

Share this post


Link to post
Share on other sites
Thanks for all the responses.

Groby, thanks for the point on while(instream) not checking for the end of the file. However, I had originally include (!inData.eof()) as the condition on that while loop and I still had the same problem.

Anonymous Poster, thank you for that link. Now I have a good place to go before I clog up the forum with uninteresting questions.

fredizzimo, I''m only seven chapters into a baby-C++ book. I haven''t done any work with classes yet. I would really appreciate it if you could dumb it down a bit.

Again, thanks.

Share this post


Link to post
Share on other sites
quote:
Original post by Mr McKnowNothing
fredizzimo, I''m only seven chapters into a baby-C++ book. I haven''t done any work with classes yet. I would really appreciate it if you could dumb it down a bit.



Yes, I know, it was a bit technical, but I wasn''t answering your question. I was correcting groby, because, what he said was wrong. But you don''t need to worry about it, continue testing for eof like you currently do. Both methods will work however.

And I will answer your question now. Oldguy has the correct answer, and you don''t need any extra variables, to fix it.

In copyText the line
while ((ch != '' '') && ((ch != ''\n'') && (ch != ''\t'')))
needs to check for EOF so change it to
while ((ch != '' '') && (ch != ''\n'') && (ch != ''\t'') && in)

I removed a redundant parentesis, actually the other parentesis are redundant too, execpt the outermost, but it can look a bit cleaner this way. processBlank needs to be changed in a similar way.

Share this post


Link to post
Share on other sites
Thanks for the advice, fredizzimo,
I fixed the program relative to your comments. Now it works perfectly (though not exactly the way the book wanted it to).
For my fellow ultra-noobs out there, here's a simple program that copies text from one file to another, counting the words, lines, and paragraphs (where paragraph splits are marked by a line with no words on it).


#include<fstream>
#include<iostream>

using namespace std;

void initialize(int&y, int& z, int&w);
void processBlank(ifstream& in, ofstream& out, char& ch, int& linesTotal, int& paraTotal);
void copyText(ifstream& in, ofstream& out, char& ch, int& w);
void printTotal(int& wordsTotal, int& linesTotal, int& paraTotal, ofstream& y);

int main()
{

int wordsTotal;
int linesTotal;
int paraTotal;
char letter;


ifstream inData;
ofstream outData;

inData.open("E:inData.txt");
outData.open("E:outData.dat");

initialize(wordsTotal, linesTotal, paraTotal);


inData.get(letter);

while (!inData.eof())
{
processBlank(inData, outData, letter, linesTotal, paraTotal);
copyText(inData, outData, letter, wordsTotal);
}

printTotal(wordsTotal, linesTotal, paraTotal, outData);

inData.close();
outData.close();

cout << endl;
return 0;
}
////////////////////////////////////////////////////////////////////////

//part of the assignment

/////////////////////////////////////////


void initialize(int&y, int& z, int& w)
{

y = 0;
z = 0;
w = 0;
return;
}


///////////////////////////////////////////////////////////////////////////

//processBlanks is used to cout the end of lines and new paragraphs,

//new paragraphs are indicated as a line with nothing on it.

///////////////////////////////////////////////////////////////////////////

void processBlank(ifstream& in, ofstream& out, char& ch, int& linesTotal, int& paraTotal)
{

char peeker;

while ((ch == ' ') || (ch == '\t') || (ch == '\n'))
{

peeker = in.peek();

if((ch == '\n') && (peeker == '\n'))
++paraTotal;

if (ch == '\n')
++linesTotal;
out << ch;
in.get(ch);
}

return;
}

//////////////////////////////////////////////////////////////////////////////

//copyText counts words

////////////////////////////////////////////////////////////////////


void copyText(ifstream& in, ofstream& out, char& ch, int& w)
{
if ((ch != ' ') && (ch != '\n') && (ch != '\t'))
++w;

while ((ch != ' ') && (ch != '\n') && (ch != '\t') && in)
{
out << ch;
in.get(ch);
}

return;
}


//////////////////////////////////////////////////////////

///printTotal reports the results of the previous functions

///////////////////////////////////////////////////////////


void printTotal(int& wordsTotal, int& linesTotal, int& paraTotal, ofstream& y)
{
y << endl << "Total number of words: " << wordsTotal << ".";
y << endl << "Total number of lines: " << linesTotal << ".";
y << endl << "Total number of paragraphs: " << paraTotal << ".";
return;
}


[edited by - Mr McKnowNothing on November 8, 2003 7:17:18 PM]

[edited by - Mr McKnowNothing on November 8, 2003 7:18:31 PM]

Share this post


Link to post
Share on other sites
The program looks a bit more complicated then it needs to be
What you can do is just read your input file in char by char and send it to your output file. To decided on whether you should increase the counter check the last char you read in if it''s a space, tab, newline etc. Keep doing till input eof and just appended the counted info to the end of the output file.

So the code would look something like this:


char letter;
//if it''s not eof() you know there''s got to be at least

//one more char to process

while(!inData.eof())
{
//do char by char copy from one file to other

inData.get(letter);
outData<<letter;

//check letter and increment counters as needed

switch(letter)
{
case '' '':
wordTotal++;
break;
case ''\n'':
lineTotal++;
break;
case ''\t'':
paraTotal++;
}//switch

}//while

printTotal(wordTotal, lineTotal, paraTotal, outData);






--{You fight like a dairy farmer!}

Share this post


Link to post
Share on other sites
Fredizzimo -

Thanks for the info. I knew about the operator!() part, but missed the cast operator. It''s probably a result of the fact that I avoid C++ streams like the plague

(MrMcKnowNothing - that doesn''t imply they''re bad and you shouldn''t use them. It just means *I* cannot stand them and have my own streams. And yes, there are some good reasons for it - but nothing you''ll encounter any time soon. So don''t let me distract you.)

- Robert

Share this post


Link to post
Share on other sites