1
#include <fstream>
#include <cmath>
#include <iomanip>
#include <iostream>
using namespace std;

int main()
{
    ifstream inData("Text.txt");
    ofstream outData("arrayout.txt");

    int n = 0;
    int num;
    int array[10];

    while (!inData.eof())
    {
        inData >> array[n];
        n++;
    }
    for (int a = 0; a < n; a++)
    {
        cout << array[n];
    }

    inData.close();
    outData.close();
}

My problem is this. This program is supposed to read a data file, read it into an Array, and then print the Array forward and backwards. I have been searching all day for some answers and I have come close but I cannot understand why this code does not print my numbers when I execute it. I get a number line of -858993460 ten times in a row.

The numbers in the text file are: 1-10 entered line by line. Can anyone help me out please? :)

Eduardo Pascual Aseff
  • 1,118
  • 2
  • 9
  • 22
  • In the input file, how are the numbers separated? Do you have one number per line? Or are they all on the same line separated by some deliminater character? Please edit your question to clarify this. – Andreas Wenzel Mar 02 '20 at 00:05
  • Just as a side note: [Why is "using namespace std;" considered bad practice?](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice) – Andreas Wenzel Mar 02 '20 at 00:07
  • I fixed that for you, they are entered line by line. one number per line. – Drewster301 Mar 02 '20 at 00:07
  • Did you verify that both files were opened successfully? Your code does not show any such checks. – Andreas Wenzel Mar 02 '20 at 00:10
  • Yes. I just verified that the file did open successfully. – Drewster301 Mar 02 '20 at 00:12
  • You verified that "the file" opened successfully? Did you do that with BOTH files? – Andreas Wenzel Mar 02 '20 at 00:14
  • Sorry, yes, both files do. The problem lies in why the array prints this long random number. I don't understand why it isn't printing the numbers 1-10. – Drewster301 Mar 02 '20 at 00:15
  • 3
    Duplicate of [Why is iostream::eof inside a loop condition (i.e. \`while (!stream.eof())\`) considered wrong?](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-i-e-while-stream-eof-cons) – walnut Mar 02 '20 at 00:16
  • walnut, so instead of using eof, how can I correctly do this? I am sorry, my teacher never taught me this. – Drewster301 Mar 02 '20 at 00:20
  • @Drewster301 You use `int v; while(inData >> v) { array[n++] = v; }` or `for(int v; inData >> v; array[n++] = v);` instead. See the linked duplicate for other alternatives as well. If you are not being taught this very basic idiom, I suggest that you get yourself a [good book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) and work through that on the side. – walnut Mar 02 '20 at 00:24
  • You should also use `std::vector` and its `push_back` method instead of arrays, because otherwise you will access the array out-of-bounds when there are more than 10 numbers in the file. – walnut Mar 02 '20 at 00:26
  • walnut, I did see that vectors were useful for this, but my teacher required it of me to use an array. Also, I tried implementing what you wrote and I still am thrown the same error. – Drewster301 Mar 02 '20 at 00:27
  • 1
    @Drewster301 Then your file is either not opened correctly or it has more than 10 numbers in it. Please show how you verified that the file is opened. Add `if(!inData) throw "inData not opened";` and `if(!outData) throw "outData not opened";` before `int n = 0` and see whether the program then gives you an error message when you execute it. – walnut Mar 02 '20 at 00:29
  • @Drewster301 Also note that I edited my earlier comment. Initially I made a mistake that would access the array out-of-bounds. Use the version currently in my comment. – walnut Mar 02 '20 at 00:31
  • @walnut No error message was thrown :/ the txt file has 10 lines of numbers 1-10 – Drewster301 Mar 02 '20 at 00:33
  • Add `#include` and `#include` at the beginning of your program. Remove the loops and add in their place `std::cout << std::string(std::istreambuf_iterator{inData}, {}) << std::endl;`. What does the resulting program print to your terminal? Is it *exactly* the ten numbers with line-breaks in-between and nothing else? – walnut Mar 02 '20 at 00:39
  • 1
    @walnut, ok i changed a very very simple part of the code, inside the loop that prints out the numbers now. I simply changed my n inside my for loop to an a. This stuff can be so frustrating... – Drewster301 Mar 02 '20 at 00:40
  • @Drewster301 Oh, right. That was stupid of me not to catch. Sorry for that. The linked duplicate still applies, though. – walnut Mar 02 '20 at 00:42
  • @walnut thank you for the help and such. I am new to this still so that is why I am so novice sounding – Drewster301 Mar 02 '20 at 00:44

4 Answers4

2

The cout << array[n]; causes undefined behaviour since n is past the end of the array. You probably meant cout << array[a];. And some whitespace between output items would be a good idea.

The use of eof is poor, see here for full explanation. The loop could be improved to:

for (n = 0; n < 10 && inData >> array[n]; ++n )
    {}

(there are various ways of formatting such a loop of course), but the exit condition should be read failure and it's important to not go beyond the bounds of the storage .

M.M
  • 130,300
  • 18
  • 171
  • 314
1
  1. You've declared a fixed array with size 10, but the loop checks the end of the file, not the end of an array. What's n doing? Just use std::vector instead. If datafile's size is always 10, it may be typo error in second loop.
  2. Typo on the second loop. Change array[n] to array[a]. array[n] is out of boundary if n=10
김선달
  • 931
  • 3
  • 18
0

Try this:

#include <iostream>
#include <fstream>
#include <vector>
using std::ios;
using std::ifstream;
using std::ofstream;
using std::cout;
using std::cerr;
using std::exit;
using std::vector;

int main() {

    ifstream inData("Text.txt", ios::in);
    ofstream outData("arrayOut.txt", ios::out);

    if (!inData)  // Check for possible file opening errors
    {
        cerr << "The input file could not be opened";
        exit(1);
    }
    inData.seekg(0);  // Just for being sure 
    vector<int> numbers;  // The array where the values will be stored
    int currentNumber;
    int i = 0;
    while(inData >> currentNumber)
    {
        numbers.push_back(currentNumber);
        i++;
    }

    cout << "Printing the array forward:  ";
    for (size_t i = 0; i < numbers.size(); ++i)  // Print array forward
        cout <<numbers.at(i)<<' ';

    cout << "\n\nPrinting the array backwards:  ";
    for (int i = 9; i >= 0; --i)  // Print array backwards
    {
        cout << numbers.at(i) << ' ';
    }

    return 0;
}

Here the program checks if there's any error while opening the ifstream object. Then, the values that were in Text.txt will now be stored in the vector numbers. Finally, the vector is printed forward and backwards. Note: In your code you didn't use the ofstream object.

Beats2019
  • 91
  • 6
-1

You have already learned Why !.eof() inside a loop condition is always wrong. as well as Why is “using namespace std;” considered bad practice? from the comments.

If your professor requires that you use a POA (plain-old array) instead of a container (such as std::vector), then YOU are responsible for all bounds checking to limit your read of elements to no more elements than the array was declared to held, and to keep a valid index of the number of elements read in the event that you read less elements than the container will hold.

So essentially you are being tasked with filling a plain-old C array using C++ iostream for input handling. For starters, don't use Magic-Numbers and don't Hardcode-Filenames. Instead:

 #define ARRSZ 10    /* if you need a constant, #define one (or more) */

And the proper prototype for main() which takes arguments is int main (int argc, char **argv) (or *argv[] if you prefer the array-of-pointers equivalent). You can now pass the filename to read from as the first argument to your program and you don't have to recompile your code just to read from another file. To use the argument as your filename to read, you simply need to validate that a sufficient number of arguments were provided on the command line (the name of the program being run is always the first argument, argv[0], so the first user-argument is argv[1]), e.g.

int main (int argc, char **argv) {

    if (argc < 2) { /* validate at least one argument given for filename */
        std::cerr << "error: insufficient arguments\n"
                     "usage: " << argv[0] << " in-file\n";
        return 1;
    }
    int ndx = 0,                                /* index for array */
        array[ARRSZ] = {0};                     /* array */
    std::ifstream fin (argv[1]);                /* input file stream */

(note: there is no need for a std::ofstream file to be opened if you are simply writing to std::cout)

Now all you need to do is read values from the file into your array while ndx is less than ARRSZ. You always want to control your read-loop with the read function being used so that the stream-state can be used to indicate success/failure of your attempted read. Here you have one other limit to protect -- your array bounds. You only want to attempt to read another value from the file if there is room in your array to store the value. Combining both, you can write your input loop as:

    /* protect plain-old array bounds && validate integer input */
    while (ndx < ARRSZ && fin >> array[ndx])
        ndx++;                                  /* increment index on success */

You have now read ndx elements into your array, so all you need to do is output them both in forward and reverse order. You can do that by looping 0 <= i < ndx for the forward case and then ndx > i >= 0 in the reverse case, e.g.

    std::cout << "forward:\n";
    for (int i = 0; i < ndx; i++)               /* loop outputting each element */
        std::cout << "  array[" << i << "]: " << array[i] << '\n';

    std::cout << "\nreverse:\n";
    for (int i = ndx - 1; i >= 0; i--)          /* loop outputting each element */
        std::cout << "  array[" << i << "]: " << array[i] << '\n';

(note: there is no need to close the file streams -- that occurs automatically as the stream pointer goes out of scope)

Putting it altogether, you could do:

#include <iostream>
#include <fstream>

#define ARRSZ 10    /* if you need a constant, #define one (or more) */

int main (int argc, char **argv) {

    if (argc < 2) { /* validate at least one argument given for filename */
        std::cerr << "error: insufficient arguments\n"
                     "usage: " << argv[0] << " in-file\n";
        return 1;
    }

    int ndx = 0,                                /* index for array */
        array[ARRSZ] = {0};                     /* array */
    std::ifstream fin (argv[1]);                /* input file stream */

    /* protect plain-old array bounds && validate integer input */
    while (ndx < ARRSZ && fin >> array[ndx])
        ndx++;                                  /* increment index on success */

    std::cout << "forward:\n";
    for (int i = 0; i < ndx; i++)               /* loop outputting each element */
        std::cout << "  array[" << i << "]: " << array[i] << '\n';

    std::cout << "\nreverse:\n";
    for (int i = ndx - 1; i >= 0; i--)          /* loop outputting each element */
        std::cout << "  array[" << i << "]: " << array[i] << '\n';
}

(note: iostream and fstream are the only headers required for this limited example. Make a habit of only including the headers required by your source)

Example Input File

Reading 8 integers space separated:

$ cat dat/int8.txt
 15815 9999 6607 32552 1479 1769 20868 6058

Example Use/Output

$ ./bin/rdpoafile dat/int8space.txt
forward:
  array[0]: 15815
  array[1]: 9999
  array[2]: 6607
  array[3]: 32552
  array[4]: 1479
  array[5]: 1769
  array[6]: 20868
  array[7]: 6058

reverse:
  array[7]: 6058
  array[6]: 20868
  array[5]: 1769
  array[4]: 1479
  array[3]: 32552
  array[2]: 6607
  array[1]: 9999
  array[0]: 15815

Example Input File

Or reading integers separated by '\n' makes no difference (space, '\t' and '\n' are all whitespace):

$ cat dat/int10.txt
19243
31875
3191
11369
22478
1783
25723
835
12093
6888

Example Use/Output

$ ./bin/rdpoafile dat/int10.txt
forward:
  array[0]: 19243
  array[1]: 31875
  array[2]: 3191
  array[3]: 11369
  array[4]: 22478
  array[5]: 1783
  array[6]: 25723
  array[7]: 835
  array[8]: 12093
  array[9]: 6888

reverse:
  array[9]: 6888
  array[8]: 12093
  array[7]: 835
  array[6]: 25723
  array[5]: 1783
  array[4]: 22478
  array[3]: 11369
  array[2]: 3191
  array[1]: 31875
  array[0]: 19243

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

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