0

I am using a function to read strings from a normalized file in order to push each string to the top of a stack that is being implemented dynamically using a linked list.

the normalized file is using data like this:

racecar
rotator
rotor
civic

when i call my function i expect my output to look the same after it uses get line to push each string to the stack, however, the actual out put is erasing the first character in the first string in a manner that looks like this:

acecar
rotator
rotor
civic

i have tried to use the ignore(), sync(), and clear functions before each iteration of get line() but i still keep coming up with the same problem.

i need some real help with this one and i hope one of you code masters can help me find the solution since i have yet to be able to get ignore() and the rest of them to ever work correctly!!! :/

here is the code to my function:

void createStack(fstream &normFile, ostream &outFile)
{
    string catchNewString;

    do
    {
        DynStrStk stringStk;

        getline(normFile,catchNewString,'\n');
        stringStk.push(catchNewString);

        //tracer rounds
        cout << endl;
        outFile << catchNewString << endl;
        cout << "test: " << catchNewString << endl;

    } while(!normFile.eof());
}

this is the entirety of my main function:

//

#include <iostream>
#include <fstream>
#include <ostream>
#include <sstream>
#include <string>
#include "DynStrStk.h"

using namespace std;

void processFile();
void parseFile(ifstream&, fstream&);
void createStack(fstream&, ostream&);

int main()
{

    //call function to open file and process
    cout << "processing file" << endl;


    processFile();

    return 0;
}


void processFile()
{
    ifstream inFile;
    fstream normFile;
    ofstream outFile;

    cout << "opening files" << endl;
    // open files
    inFile.open("inFile.txt");
    normFile.open("normFile.txt");
    outFile.open("outFile.txt");

    cout << "parsing file" << endl;
    //parse file for capitalization & punctuation
    parseFile(inFile, normFile);

    //create stack with parsed and normalized normFile
    createStack(normFile, outFile);

    //close files
    outFile.close();
    normFile.close();
    inFile.close();
}

void parseFile(ifstream &inFile, fstream &normFile)
{
    //create and initialize variables
    string newString;;
    int i;

    if(!inFile)
    {
        cout << "ERROR!!! Cannot read file.";
    }
    else
    {
        do
        {
            //read each line in the input file until EOF
            getline(inFile, newString, '\n');

            i = 0;

            //parse each string for punctuation
            while(newString[i])
            {
                if(isalpha(newString[i])) //check each char in each 
                                          //string for punctuation
                {
                    if(isupper(newString[i])) //check each string for 
                                              //capitalization
                    {
                        newString[i] = tolower(newString[i]); //convert 
                                                 //string to lower case
                    }
                    normFile << newString[i]; //output each line tofile
                    cout << newString[i];
                }
                i++;
            }
            normFile << '\n';
            cout << '\n';

        } while(!inFile.eof());
    }
}

void createStack(fstream &normFile, ostream &outFile)
{
    string catchNewString;

    do
    {
        DynStrStk stringStk;

        getline(normFile,catchNewString,'\n');
        stringStk.push(catchNewString);

        //tracer rounds
        cout << endl;
        outFile << catchNewString << endl;
        cout << "test: " << catchNewString << endl;

    } while(!normFile.eof());
}

this is my push function in my header file:

//function that pushes the argument onto the list
void DynStrStk::push(string newString)
{
    StackNode *newNode = nullptr; //Pointer to a node

    //Allocate a new node and store string
    newNode = new StackNode;
    newNode->newString = newString;

    //if there are no nodes in the list make newNode the first node
    if(isEmpty())
    {
        top = newNode;
        newNode->next = nullptr;
    }
    else //otherwise insert NewNode before top
    {
        newNode->next = top;
        top = newNode;
    }
}

this is my header file:

#ifndef DynStrStk_h
#define DynStrStk_h

#include <iostream>
#include <sstream>
#include <string>

using namespace std;

class DynStrStk
{
private:
    //struct stack nodes
    struct StackNode
    {
        string newString; //string held in the node
        StackNode *next; //pointer to the next node
    };

    StackNode *top; //pointer to the top of the stack


public:
    //Constructor
    DynStrStk()
    {top = nullptr;}

    //Destructor
    ~DynStrStk();

    //Stack Operations
    void push(string);
    void pop(string &);
    bool isEmpty();
};

#endif
lopezdp
  • 1,284
  • 16
  • 31
  • side issue: `while(!normFile.eof());` is [most of the time wrong.](http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong) – vsoftco Apr 25 '15 at 20:07
  • replace it with `while(getline(normFile, catchNewString,'\n')) { /* rest of loop */ }` as otherwise you end up "eating" the eof. Aslo no need for '`\n`', getline is by default reading until the next line. – vsoftco Apr 25 '15 at 20:09
  • you want to post your comment as an answer and ill uproot it for you if it works? – lopezdp Apr 25 '15 at 20:11
  • I am not sure how your code works (e.g., you may have a problem in `DynStrStk`), that's why I didn't write an answer, as just by looking at your code we cannot say for sure what's wrong, there is not enough "data" available. – vsoftco Apr 25 '15 at 20:13
  • so i tried your solution, but now, instead of eating up the first letter of the first word, it is eating the ENTIRE first word.... sorry, but no cigar on that one :/ it has something to do with the buffer being full, i know it has something to do with me not clearing the buffer I'm just stuck on how to clear it before get line() – lopezdp Apr 25 '15 at 20:14
  • no, there is no problem with clearing the buffer. You should only care about it when you mix `getline` after `cin`, as `cin` leaves `\n` in the stream. Make sure your `DynStrStk` works as expected. Try "manually" pushing strings into it. Why are you actually having `DynStrStk stringStk;` defined inside the loop? It will cease to exist when the loop ends. – vsoftco Apr 25 '15 at 20:16
  • DynStrStk is a class that holds a structure of nodes that are instantiated with a push method within the same class. everything works "manually" up until i get to get line and for some reason I'm losing the first letter of the first word with my solution and the entire first word with your solution. ill post the push function now along with the class and the main – lopezdp Apr 25 '15 at 20:18

1 Answers1

2

Your code is almost correct, with couple of exceptions.

  1. you should not test for eof as a loop condition, see Why is iostream::eof inside a loop condition considered wrong?

  2. Declaring DynStrStk stringStk; inside the loop seems very fishy, as at the exit from the loop the variable cease to exist.

Here is a very simple program that uses a std::stack<std::string> instead, and which works, so the problem is probably in your DynStrStk implementation. There is no need to use cin.clear or cin.ignore as long as you're not mixing up cin and getline (in this latter case cin leaves a new line in the buffer which may end up "eaten" by `getline" in case you don't clear the stream).

#include <iostream>
#include <stack>
#include <string>
#include <fstream>

int main()
{
    std::stack<std::string> stringStk; // stack of strings 
    std::ifstream normFile("test.txt"); // input file
    std::ofstream output("out.txt"); // output file

    std::string catchNewString;
    while(getline(normFile,catchNewString)) // read and push to stack
    {   
        stringStk.push(catchNewString); // push to stack
    }

    while(!stringStk.empty()) // dump the stack into the file
    {
        output << stringStk.top() << std::endl; // write it
        stringStk.pop(); // remove
    }
}

Again, you are not losing anything with the getline, nothing is lost in the buffer. There is an error probably when you loop over the individual characters in the string, in void parseFile(ifstream &inFile, fstream &normFile). One more thing: you use parseFile(inFile, normFile); then immediately createStack(normFile, outFile);. However, the normFile will have its position at the end (this is done by parseFile()), don't you need to rewind it before invoking createStack()?

try normFile.seekg(0, ios::beg); adter parseFile() and before createStack(). If it's not working, then try moving as much code as possible in independent functions and test each function step by step, or use a debugger and see live what's going on.

Community
  • 1
  • 1
vsoftco
  • 52,188
  • 7
  • 109
  • 221
  • you were right about declaring DynStrStk stringStk inside the while loop... i did include your edits but i am getting same results. i went ahead and added my push implementation and my header file to the original question for you to review. thank you!! – lopezdp Apr 25 '15 at 20:38
  • no panic man... I've tested it all every step of the way and everything has worked perfectly up until get line.... can you tell me how to properly clear the buffer so i can test that first. i never understand how to use ignore() properly.... I'm going back to my original code simply because i am only losing one char from the first string instead of the entire output at this point.... it has to be getting lost in the buffer. nothing else makes any sense... – lopezdp Apr 25 '15 at 20:49
  • the is alpha loop was used to create the normFile.... it works perfectly. my problem is when i open and read the normFile.... my get line() in the createStack() that calls the push() from the DynStrStk class is skipping over the first char in the first string of the normFile most likely because of a left over '\n' still in the buffer when get line() is called in the createStack() function.... i test every line of code after i write it.... this is where i am stuck because it didn't pass the test... let me know if you can help. thanks again and i do appreciate it – lopezdp Apr 25 '15 at 21:01
  • I'm going to play with what you said in your last comment... thanks again – lopezdp Apr 25 '15 at 21:02
  • the statement: normFile.seekg(0, ios::beg); worked in regards to "rewinding" the normFile before i called the createStack() function. my output is correct with the exception that when i test it i get an extra line that looks like this: test: basically in the parseFile() function is adding a '\n' at the end that i believe is being picked up by the createStack() function at the end which reads it as a new string.... got any ideas as to how i can remove that last string so that the top of my stack doesn't get left holding an empty string? thanks!!! – lopezdp Apr 25 '15 at 21:59
  • i love you! thank you for the help. you solved it!!! I'm still very unclear about the EOF problem, but i will look into it further. if you can help me research that with any additional info i would be grateful!!! thanks again!!!! show me some love and gimme a vote up on the question!!! thanks!! – lopezdp Apr 25 '15 at 22:28
  • 1
    @lopezdp look into the link I sent you and you'll see what's going on. The basic idea is the following: your file pointer is pointing at the char before EOF, you read it, the pointer moves to EOF (which is **not yet read**), so the status of the stream is still OK. Then, at the next iteration, you read it, it is now EOF, so you end up using the EOF. The loop will only **after** the read of EOF break. – vsoftco Apr 25 '15 at 22:33