Hi! I am working on a program to count the number of characters and words in a text file. The counting characters portion works, but my countWords function displays '0'. I built the countWords function on the basis of my countChar function, but since it's returning zero I'm not sure whether there's something still stored in the input stream that I need to clear, or maybe I'm not passing the correct information? I realize that after I get a number, I may need to do some +1 or -1 to bridge the relationship between spaces counted and words. Any hint is greatly appreciated.

#include <iostream>
#include <cstring>
#include <fstream>
using namespace std;

void problems(char*);
void countChars(ifstream&, char*);
void countWords(ifstream&, char*);

int main(void)
{
	const char path[]={"D:\\filepath\\"};
	char fileName[32];
	char nameWithPath[81];
	int counter=0;

	cout<<"Enter the input file name: ";
	cin>>fileName;
	strcat(strcpy(nameWithPath,path),fileName); 

	ifstream inFile;
	inFile.open(nameWithPath);
	if (!inFile.good())
		problems(nameWithPath);

	countChars(inFile, nameWithPath);
	countWords(inFile, nameWithPath);
	
	inFile.close();

        return 0;
}

void problems(char* file)
{
	cerr<<"Problems opening file: "<<file<<endl;
	exit(EXIT_FAILURE);
}

void countChars(ifstream& fileName, char* f) 
{
	char c;
	int charCount=0;
	
	while(!fileName.eof())
	{
		c = fileName.get();
		if(c != '\n') 
		++charCount;
	}

	cout<<"Number of characters: "<<charCount<<endl;
}


void countWords(ifstream& fileName, char* i)
{
	char s;
	int wordCount=0;
	
	while(!fileName.eof())
	{
		s = fileName.get();
		if(s == ' ') 
		++wordCount;
	}
	
	cout<<"Number of words: "<<wordCount<<endl;
}

File streams work by using a pointer to keep track of where you are within a file.

File streams have different "states". In order for a filestream to work it has to be in the "good" state. If the file pointer reaches EOF (End Of File) it causes the file stream to go into a failed state until you replace the pointer to point somehere within the file again. You can specify where you want the file pointer to go, or you can close the stream (you may have to "clear" the state before you can close it) and reopen it, in which case the pointer will be repositioned back at the begining of the file again.

You have to pass streams by reference meaning whatever state they end up with in one function will persist in the calling function and will be passed to the next called function.

In your case countChar stops when it attempts to read one more time after finding EOF. But at that point, having found EOF, it is in a failed state when it returns to main() and remains in a failed state when you try to use it in countWords. You have to get it out of the failed state to use it again.

Also, you have to be careful when using the return value of eof() to control a loop in order to avoid a potential bug. In your case your loops are apt to "attempt" to go through the body of the loop one too many times, and may well end up counting one too many char or words. If that happens, then use fin >> c or fin >> s as the loop conditional instead of using fin.gets() within the body loop. If you want to be sure you've read the entire file, then call eof() after completing the loop.

Edited 4 Years Ago by Lerner: n/a

Thanks Lerner! Your explanation makes sense. I'll change my code and see how it goes.

This article has been dead for over six months. Start a new discussion instead.