1

I found the properly way to add a while so I can complete this exercise. However, there are 2 things that require a touch. The file output is displaying twice. The first time properly, and the second time in a single line ( I don't need this line to show up). The second issue is the account ++ function. It has to display the counting of 7 words but it's counting 8 instead. Why? could you help me with this. the issue is in the last while.

 #include<iostream>
    #include<fstream>//step#1
    #include<string>

    using namespace std;
    int main()

    {

        string word, fileName;
        int charcounter = 0, wordcounter = 0;
        char character;

        ifstream inData;// incoming file stream variable

        cout << " Enter filename or type quit to exit: ";
        cin >> fileName;



        //loop to allow for multiple files data reads
        while (fileName != "quit")

        {
            inData.open(fileName.c_str());//open file and bind file to ifstream variable

        //loop for file not found validation
            while (!inData)//filestream is in fail state due to no file
            {
                inData.clear();//clear the fail state 
                cout << "File not found. Enter the correct filename: ";
                cin >> fileName;
                inData.open(fileName.c_str());
            }


            inData >> character;//extract a single character from the file
            cout << "\n*****************************\n";
            while (inData)


            {
                cout << character;
                inData.get(character);//extract the next character and the next character
                charcounter++;

            }
    //Here is the loop that is missing something
    //I was told to close the file 

            inData.close();

    //open up the file again and add the while loop

            inData.open(fileName.c_str());

            while (inData)

            {

                cout << word;
                inData >> word;//extract the next word and the next word
                wordcounter++;
            }



            cout << "\n******************************\n";
            cout << fileName << " has " << wordcounter << " words" << endl;
            inData.close();//close the ifstream conection to the data file


            charcounter = 0; //reset char and word counts
            wordcounter = 0;
                //port for next file or exit
            cout << "Enter a filename or type quit to exit: ";
            cin >> fileName;

        }

        return 0;

    }
Mushroom
  • 11
  • 1
  • You have the same issue in your loops as described [here](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong). – Shawn Mar 18 '19 at 06:26

1 Answers1

0

The reason you are getting redundant output is you are outputting the contents of the file twice, e.g.

lines 39 - 43

        while (inData)


        {
            cout << character;
            ...

lines 57 - 61

        while (inData)

        {

            cout << word;
            ...

Whether you output character-by-character, or word-by-word, you are outputting the contents of the file. Doing it once character-by-character in one loop and then doing it again word-by-word in another results in twice the output.

Further, there is no need to loop over the file twice to count the characters and then words -- do it all in a single loop, e.g.

        int charcounter = 0,
            wordcounter = 0,
            inword = 0;         /* flag indicating reading chars in word */
        ...
        while (inData.get(character)) { /* read each character in file */
            if (isspace (character))    /* if character is whitespace */
                inword = 0;             /* set inword flag zero */
            else {                      /* if non-whitespace */
                if (!inword)            /* if not already in word */
                    wordcounter++;      /* increment wordcounter */
                inword = 1;             /* set inword flag 1 */
            }
            charcounter++;              /* increment charcounter */
        }

The remaining problems you have are just due to the jumbled loop logic you try and employ to be able to open different files until the user types "quit". You only need one outer-loop that will loop continually until the user types "quit". You don't need multiple checks and multiple prompts for the filename. Simply use a single loop, e.g.

    for (;;) {      /* loop continually until "quit" entered as fileName */
        string word, fileName;  /* fileName, character, inData are */
        char character;         /* only needed within loop */
        int charcounter = 0,
            wordcounter = 0,
            inword = 0;         /* flag indicating reading chars in word */
        ifstream inData;

        cout << "\nEnter filename or type quit to exit: ";
        if (!(cin >> fileName)) {       /* validate every read */
            cerr << "(error: fileName)\n";
            return 1;
        }
        if (fileName == "quit")         /* test for quit */
            return 0;

        inData.open (fileName);         /* no need for .c_str() */
        if (!inData.is_open()) {        /* validate file is open */
            cerr << "error: unable to open " << fileName << '\n';
            continue;
        }
        ...  /* the read loop goes here */
        inData.close();   /* closing is fine, but will close at loop end */

        cout << '\n' << fileName << " has " << wordcounter << " words and " 
            << charcounter << " characters\n";
    }

Making those changes cleans up your program flow and makes the loop logic straight-forward. Putting it altogether you could do:

#include <iostream>
#include <fstream>
#include <string>
#include <cctype>

using namespace std;

int main (void) {

    for (;;) {      /* loop continually until "quit" entered as fileName */
        string word, fileName;  /* fileName, character, inData are */
        char character;         /* only needed within loop */
        int charcounter = 0,
            wordcounter = 0,
            inword = 0;         /* flag indicating reading chars in word */
        ifstream inData;

        cout << "\nEnter filename or type quit to exit: ";
        if (!(cin >> fileName)) {       /* validate every read */
            cerr << "(error: fileName)\n";
            return 1;
        }
        if (fileName == "quit")         /* test for quit */
            return 0;

        inData.open (fileName);         /* no need for .c_str() */
        if (!inData.is_open()) {        /* validate file is open */
            cerr << "error: unable to open " << fileName << '\n';
            continue;
        }

        while (inData.get(character)) { /* read each character in file */
            if (isspace (character))    /* if character is whitespace */
                inword = 0;             /* set inword flag zero */
            else {                      /* if non-whitespace */
                if (!inword)            /* if not already in word */
                    wordcounter++;      /* increment wordcounter */
                inword = 1;             /* set inword flag 1 */
            }
            charcounter++;              /* increment charcounter */
        }
        inData.close();   /* closing is fine, but will close at loop end */

        cout << '\n' << fileName << " has " << wordcounter << " words and " 
            << charcounter << " characters\n";
    }
}

Example Input File

$ cat ../dat/captnjack.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.

Example Use/Output

$ ./bin/char_word_count

Enter filename or type quit to exit: ../dat/captnjack.txt

../dat/captnjack.txt has 16 words and 76 characters

Enter filename or type quit to exit: quit

Confirmation with wc

$ wc ../dat/captnjack.txt
 4 16 76 ../dat/captnjack.txt

Look things over and let me know if you have additional questions.

David C. Rankin
  • 69,681
  • 6
  • 44
  • 72