[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 320
  • Last Modified:

Input files

I dont exactly know what the problem is my program runs but wont output to the console the 1st and 3rd letters . I believe it is reading from the input code fine because if I delete the numbers portion of the code and just leave the words it will do it correctly what is going on with this I dont understand how it wont do it when it is all together

here is my code:

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

using namespace std;

int main()
{

        ifstream inFile;
        ofstream outFile;

      int numbers[5];
      int counter;
      string words[5];

        inFile.open("numbers.txt");
        outFile.open("output.txt");

        cout << "Processing information from numbers file...." << endl;

      for(counter=0; counter < 5; counter++)
      {
            inFile >> numbers[counter];
      }
        cout << "\nInformation stored successfully! "<<endl;

      for(counter = 4; counter >= 0; counter--)
      {
            outFile << numbers[counter] << endl;
      }
     
        cout << "\nProcessing five words already input from file...." << endl;

        inFile.close();
        outFile.close();

        inFile.open("words.txt");

      for(counter = 0; counter < 5; counter++)
      {
            inFile >> words[counter];
      }
     
        words[counter] = "end_of_array";

      counter = 0;

      do
      {
            cout << words[counter].substr(0,1) << words[counter].substr(2,1) << endl;
            counter++;

      }
        
        while(words[counter]!= "end_of_array");

      inFile.close();
     
        return 0;
}
0
jschmuff
Asked:
jschmuff
1 Solution
 
avatar-eCommented:
ifstream inFile; -> ifstream inFile, inFile2; // Because we need another file input

string words[5]; -> string words[6]; // Because we need another slot to "end_of_array"

while(words[counter]!= "end_of_array"); -> while(words[counter].compare("end_of_array")!=0); // Use compare, to compare strings

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

using namespace std;

int main()
{

        ifstream inFile, inFile2;
        ofstream outFile;

      int numbers[5];
      int counter;
      string words[6];

        inFile.open("numbers.txt");
        outFile.open("output.txt");

        cout << "Processing information from numbers file...." << endl;

      for(counter=0; counter < 5; counter++)
      {
            inFile >> numbers[counter];
      }
        cout << "\nInformation stored successfully! "<<endl;

      for(counter = 4; counter >= 0; counter--)
      {
            outFile << numbers[counter] << endl;
      }
     
        cout << "\nProcessing five words already input from file...." << endl;

        inFile.close();
        outFile.close();

        inFile2.open("words.txt");

      for(counter = 0; counter < 5; counter++)
      {
            inFile2 >> words[counter];
      }
     
        words[counter] = "end_of_array";

      counter = 0;

      do
      {
            cout << words[counter].substr(0,1) << words[counter].substr(2,1) << endl;
            counter++;

      }
       
        while(words[counter].compare("end_of_array")!=0);

      inFile2.close();
     
       return 0;
}
0
 
efnCommented:
One problem is here:

      for(counter = 0; counter < 5; counter++)
      {
            inFile >> words[counter];
      }
     
        words[counter] = "end_of_array";

When control exits the for loop, counter will be 5 and the next statement will try to assign to words[counter], which will be words[5].  But words was declared to be an array of 5 strings, so valid subscripts are 0 through 4, so there is no words[5].

Try fixing that and see if it still doesn't work.
0
 
itsmeandnobodyelseCommented:
Some remarks on your prog:

>>>> ifstream inFile;
>>>> ofstream outFile;

You can 'open' the files with the constructor:

     ifstream inFile("input.txt");
     ifstream inFile("output.txt");

There is no advantage in using a separate open statement as the return type of basic_ifstream::open is void.

>>>> int numbers[5];
>>>> string words[5];

Instead of fixed-sized arrays you should consider of using std::vector:

    vector<int> numbers(5);
    vector<string> words(5);

These two statements would create an array of 5 elements same as your definiitions. In case of 'numbers' the items were initiallized with 0. std::vector has the advantage that it will grow dynamically and that you don't have to care for allocation or array boundaries.

    vector<int> numbers;
    vector<string> words;

I would suggest to have empty arrays at begin and let grow them dynamically when reading the values.

>>>> for(counter=0; counter < 5; counter++)

When reading from a file, you should avoid reading a fixed number or items. Better read all items to a dynamically growing array like std::vector *or* read up to a maximum of entries. In any case you should check for read errors and end-of-file.

    const unsigned int maxread = 5;
    counter = 0;
    int num;
    while (number.size() < maxread && inFile >> num)
    {
            numbers.push_back(num);   // add num to vector
    }
    counter = (int)numbers.size();

With that you would only read if the inFile is still valid. Note, the condition 'inFile >> num' tests on the stream status. In case of inFile.eof() and inFile.fail() the condition is false.

If using std::vector you can omit the 'counter' variable cause with numbers.size() you alway can retrieve the count.

>>>> for(counter = 4; counter >= 0; counter--)
That would turn to


    for(counter = (int)numbers.size()-1; counter >= 0; counter--)

>>>> inFile.open("words.txt");

There is no problem in (re)opening a orderly closed inputfile, though I also would choose a second ifstream as avatar-e suggested.

>>>>       for(counter = 0; counter < 5; counter++)

Same thing: when using vector it would turn to

      string word;
      while (words.size() < maxread && inFile >>  word)
             words.push_back(word);  

Note, the 'inFile >> word' would stop 'streaming' if the word contains a space or tab character. If you would like to read a 'line' rather than a 'word', you'll better would use std::getline.

      string line;
      while (words.size() < maxread && getline(inFile, line))
             words.push_back(line);  

>>>> words[counter] = "end_of_array";
As both avatar-e and efn already explained, you are writing beyond the array size of 5 items. But even if you increase the size to 6, it is dangerous to trust that the previous loop has set the counter variable correctly. Assume, you would have got an error with the first read and would have checked for the error and broke the loop at the first entry. Then counter == 0 and string[0] == "end_of_array" but the following do-while never would break cause counter is 1 or higher when checking for the "end_of_array".  If you would have made

   string words[6];
   ...
   words[sizeof(words)/sizeof(words[0]) - 1] = "end_of_array";

you would have been safe, and you could increase the array-size without needing to change all loop-boundaries. Far better would be using vector<string> as the statement simply would be

    words.push_back("end_of_array");

Note, terminating an array with some kind of 'terminator' is not state-of-the-art. Normally only char arrays were terminated with a zero char and all other arrays were managed by size rather than by terminator. If using string instead char arrays, the internal char arrays still have zero termination but that is for providing a const char pointer via string::c_str() only. The string class manages its char array by size as you should do with all other arrays as well.

>>>>      do { ... } while (...);

A do-while has the advantage/disadvantage that the body of the loop was processed at least one time. In your code it is a disadvantage cause it makes no sense to check the loop-size boundary at end of the loop. Then you already might have accessed the arrays with an index that is beyond or equal to the upper boundary. Worse, you might check for a condition that is never true if the initializing

   string[counter] = "end_of_array";

was dropped somehow or if counter was 0 for any reason. Then you'll get an infinite loop! While conditions were dangerous and you should make them absolute safe. Better use for loops or while loops which check for an upper boundary

   while (counter < maxread && ...
     
It even makes sense to increment the loop counter in the while condition to absolutely make sure that the 'counter' was incremented:

   while (++counter <= maxread && ...)   // note the <=

However, you should consider using a for loop in that case cause normally it is better to have the loop counter run from 0 to maxread-1 rather than from 1 to maxread as it would be with the above while.

Regards, Alex

0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now