Categories: MSDN / DotNet / Java / Scripts / Linux / PHP Ask - La ask - La Answer

File I/O stream problem

I am the beginner of writing C++ programme and i have a problem of finding out the number of spaces, number of uppercases characters & number of lines. The requirement of the input file, which is the text file, is only 80 characters in each line. I typed the following source code:

The function of finding out the number of lines works.
The others two don't work.
Do anyone notice the problem in the code?

#include <iostream>
#include <string>
using namespace std;
#include <fstream>
ifstream fin1 ("input.txt");
char ch[1000];
int number_of_lines = 0;
int number_of_spaces = 0;
int number_of_uppercases = 0;
int countspaces ()
{
for (int i=0; i<sizeof(ch); i++)
{
if (ch[i] == ' ')
++number_of_spaces;
}
cout << number_of_spaces;
cout << endl;
return number_of_spaces;
}
int countuppercases ()
{
while (fin1.getline(ch, sizeof(ch)))
{
for (int i = 0; ch[i] != '\0'; i++)
{
if (isupper(*ch))
++number_of_uppercases;
}
++number_of_lines;
}
cout << number_of_uppercases;
cout << endl;
return number_of_uppercases;
}
int countlines ()
{
while (fin1.getline(ch, sizeof(ch)))
{
++number_of_lines;
}
cout << number_of_lines;
cout << endl;
return number_of_lines;
}
int main()
{
if (!fin1)
{
cout << "Cannot open infile: input.txt\n";
}
else
{
cout << "Infile: input.txt opened.\n";
cout << "Number of Spaces: ";
countspaces();
cout << "Number of Upper Cases: ";
countuppercases ();
cout << "Number of lines: ";
countlines();
}
return 0;
}

The content of input.txt
Somebody The Overseas!
Finish what

Many thanks!
Dicky
[2009 byte] By [dickylau] at [2007-11-11 10:13:41]
# 1 Re: File I/O stream problem
Please, read the comments in code.

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

// these globals just spoil your code (this makes me think
// global variables should be introduced at advanced level :)
ifstream fin1 ("input.txt");
char ch[1000];
int number_of_lines = 0;
int number_of_spaces = 0;
int number_of_uppercases = 0;

// these three counting functions have mixed responsibilities,
// and when combined with global variables, they become practicaly
// unusable

int countspaces ()
{
// this functions in current setting does nothing at all
// because you have global array of characters initialized
// with zeros (aka '\0'), so the first character in the ch array will
// be null character, which makes your buffer an empty string
// !!! just look at the main !!!
for (int i=0; i<sizeof(ch); i++)
{
if (ch[i] == ' ')
++number_of_spaces;
}
cout << number_of_spaces;
cout << endl;
return number_of_spaces;
}

int countuppercases ()
{
// OK, this functions counts both newlines and uppercases
// and that makes it only functions that will do any job at all
while (fin1.getline(ch, sizeof(ch)))
{
for (int i = 0; ch[i] != '\0'; i++)
{
if (isupper(*ch))
++number_of_uppercases;
}
++number_of_lines;
}
cout << number_of_uppercases;
cout << endl;
return number_of_uppercases;
}

int countlines ()
{
// when you call this function, your fin1 stream will be
// already in the eof state (check it out if you don't
// believe my word), so there's nothing more to be done here
while (fin1.getline(ch, sizeof(ch)))
{
++number_of_lines;
}
cout << number_of_lines;
cout << endl;
return number_of_lines;
}

int main()
{
if (!fin1)
{
cout << "Cannot open infile: input.txt\n";
}
else
{
cout << "Infile: input.txt opened.\n";
cout << "Number of Spaces: ";
// once again, this functions will do nothing
// because it handles empty array filled with zeros
countspaces();
cout << "Number of Upper Cases: ";
// this functions will count uppercases and newlines, and
// also put fin1 into the eof state
countuppercases ();
cout << "Number of lines: ";
// this functions tries to do something, but it can
// because fin1 is in eof state due to countuppercases call
countlines();
}
return 0;
}

I hope this makes things clear. To clear this mess, you have (at least) two options. You can rewrite your counting functions so that they open file stream every time you call them. In other words, you will only give them path to the file, and they will open it and do with it what ever they're supposed to do.

Second (and more favorable) approach is to simply read the file line by line, count number of lines in main, and for each line read, call other two functions (countspaces and countuppercases) which will have access only to your line buffer. Functions will return whatever they've counted, and you only have to add their return values to local counters defined in main. Here some code:

int main()
{
unsigned int line_counter = 0;
unsigned int space_counter = 0;
unsigned int uppercase_counter = 0;
ifstream iStream( "input.txt" );
char inputBuffer[80];

while ( iStream.getline( inputBuffer, sizeof( inputBuffer ) ) )
{
++line_counter;
space_counter += countspaces( inputBuffer );
uppercase_counter += countuppercases( inputBuffer );
}

// print all the counters
}

As you can see, all the variables are instantiated in main, certainly not as global variables!

Hope this helps.
dcwexter at 2007-11-11 20:59:17 >