Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

Input from text file

  1. Feb 9, 2016 #1

    ChrisVer

    User Avatar
    Gold Member

    I know this is pretty basic question, but something doesn't seem to work right for me...
    Suppose I have a txt file, with the following input:
    Code (Text):

    x    y
    0.0    0.5
    1.0    1.5
    2.0    4.8
    3.0    4.9
     
    How can I pass those numbers into x and y arrays using a C++ code?
    My code so far is like this:

    Code (C):

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

    int main(){
    //read file
    ifstream finput;
    finput.open("data.txt");

    // part to calculate the dimensionality
    int N=0;
    double temp;
    while(! finput.eof() ){
        finput >>tempp;
        N++;
    }
    N=N/2;


    //part to fill the arrays
    double x[N];
    double y[N];
    int m=0;
    while(! finput.eof() ){
        finput >>x[m]>> y[m];
        m++;
    }

    system("pause");
    return 0;
    }

     
    But it seems that the 2nd loop doesn't put my values for x,y's into the corresponding arrays. The filled elements are extremely small numbers which I didn't even input.
    Any feedback?
     
  2. jcsd
  3. Feb 9, 2016 #2

    Ibix

    User Avatar
    Science Advisor

    Don't you need to rewind the file between loops? Close and reopen for example. I suspect what you've got in the array is just nonsense that happens to be in the (uninitialised) memory that you allocated.

    Easy check - debugger, or add a printf inside the second loop and see if it's being executed at all.

    Edit: I think >> will automatically convert the string read from the file to a double - but it may be worth checking that parsing is happening if the above doesn't fix it.
     
  4. Feb 9, 2016 #3

    ChrisVer

    User Avatar
    Gold Member

    I tried to close/open the file inbetween the loops... it worked after doing it... :confused:confused!
     
  5. Feb 9, 2016 #4

    Ibix

    User Avatar
    Science Advisor

    Is that an "I was confused" or an "I am confused"?

    In case of the latter, your first loop exits when finput.eof() is true. You didn't tell finput to return to the start of the file or anything, so it simply carried on reporting that it was at the end of the file (i.e. finput.eof() remained true) and the second loop exited immediately. Closing and reopening the file moves you back to the beginning. If ifstream has a rewind() method (or something similar) you could use that to achieve the same result.
     
  6. Feb 9, 2016 #5

    jtbell

    User Avatar

    Staff: Mentor

    Try using vectors instead of arrays. You can add data to them so that they automatically grow to the size you need, instead of having the declare the size in advance. You don't have to read the file twice, first to find out how big to make the array, then to read the data. Here's a simple example that reads ints from a file into a vector and then displays the vector's contents:

    Code (C):

    #include <iostream>
    #include <fstream>
    #include <vector>

    using namespace std;

    int main ()
    {
      vector<int> numbers;  // has length zero, initially

      ifstream inputfile ("data.txt");
      if (!inputfile)
      {
        cout << "Couldn't open data.txt!" << endl;
        return 0;
      }

      int n;
      while (inputfile >> n)  // loop terminates at end of file
      {
        numbers.push_back(n);  // append n to the vector and expand
                               // the vector as necessary
      }

      // the size() member function tells you how big the vector is

      cout << "The numbers are:" << endl;
      for (int k = 0; k < numbers.size(); ++k)
      {
        cout << numbers[k] << endl;
      }

      return 0;
    }
     
     
  7. Feb 10, 2016 #6

    jtbell

    User Avatar

    Staff: Mentor

    Here's another problem with your code. Your file begins with a header line containing text ("x y"). When your program tries to read a double from that line, the input stream goes into "fail" status, and you can't read anything further until you reset the stream status. To skip past that header line, read some text instead.

    Code (C):

    #include <string>

    // ......

    string head1, head2;
    cin >> head1 >> head2;   // each '>>' reads one "word" at a time
                             // (sequence of characters delimited by whitespace)

    // Now start reading the doubles
     
     
    Last edited: Feb 10, 2016
  8. Feb 10, 2016 #7

    ChrisVer

    User Avatar
    Gold Member

    Hey, thanks for the replies, they were understandable.
    I would also like to ask a further question:
    How can I feed in the txt file path in the terminal window??
    suppose that I have the following paths:
    [my code's path]/data.txt (I call it default)
    [my code's path]/folder/data.txt (or any other path)

    How can I use a non-default path for this code to run?
    What i've been thinking is for a source code of the form:

    Code (C):

    #include<string>

    int main( int argc, char ** argstr){
        string fpath;
        if (argc==0)  fpath = "data.txt"; // have no command line arguments get the default
        else{
            fpath="";
            for(int i=0; i< argstr.size(); i++){
                fpath += argstr[i];
            }
        }
    }

    //REST OF CODE
     
     
  9. Feb 10, 2016 #8

    jtbell

    User Avatar

    Staff: Mentor

    In the 'open' statement or the fstream constructor (as I did), specify either a relative path starting from your current location (in your example that would be folder/data.txt, with no slash at the beginning), or an absolute path starting from your file system root (which depends on your operating system).
     
  10. Feb 10, 2016 #9

    ChrisVer

    User Avatar
    Gold Member

    Well yes, that would be the manual thing to do, which would require every time I wanted to change the path to enter my source code and change the filename in the fstream's constructor.
    My point however is when I type this in the command line of the terminal:
    ./main
    the code to run with the default path, and process the : "data.txt".
    But when I type:
    ./main /folder1/xydata.txt
    it would run on the txt file in the given path.
     
  11. Feb 10, 2016 #10

    ChrisVer

    User Avatar
    Gold Member

    I don't really understand what this means... sorry if the answer to my question lies on this part of your post.
     
  12. Feb 10, 2016 #11

    jtbell

    User Avatar

    Staff: Mentor

    Under Mac OS, I have a Documents folder, the default location for new files, which has the absolute path /Users/jtbell/Documents. If I have a program in that folder, and a data file data.txt which is also in that folder, I can open the file using either 'data.txt' or '/Users/jtbell/Documents/data.txt'. If the file is actually in a sub-folder named 'folder', I can use either 'folder/data.txt' or '/Users/jtbell/Documents/folder/data.txt'. In both examples, the first path is "relative" and the second path is "absolute."

    But now I see that what you want is to specify the file name when you execute (run) the program, not as part of the source code. To do it like you said in post #9, you need to know how to process command-line arguments in C++. I haven't done this in a long time, so I'm not a good person to ask. I would have to re-learn it. Maybe someone else can contribute an example. Or if you Google for something like "c++ command line arguments" you'll probably find something.
     
  13. Feb 10, 2016 #12

    Mark44

    Staff: Mentor

    @ChrisVer, what OS are you using? Are you running your code from the command line or from inside a debugger?

    As an alternative to passing the path as a command-line argument, you could prompt the user to enter the path to the data file, and then to enter the name of the data file.
     
  14. Feb 10, 2016 #13

    jtbell

    User Avatar

    Staff: Mentor

    ...and then the program reads the name into a string, and you use the string as the argument to finput.open() or the constructor for finput.

    A potential complication here is that finput.open() and the constructor both expect to receive C-style char* "strings" as arguments. If you read the filename into a C++ string, you have to do a conversion.

    Code (C):

    string filename;
    cout << "File name? ";
    cin >> filename;
    ifstream finput;
    finput.open(filename.c_str());
     
    Or you can combine the last two statements into

    Code (C):

    ifstream finput (filename.c_str());
     
     
  15. Feb 10, 2016 #14

    FactChecker

    User Avatar
    Science Advisor
    Gold Member

    Regarding the code in post #7 to get a file name from the command line:

    The command line inputs can be received as an array of strings, argv[0], argv[1], argv[2], ... in the standard way with

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

    argv[0] is the path to the program you are running.
    argv[1] will be a file name that you put on the command line and argc will = 2. You can strcpy argv[1] to a string with a better name, like filename.

    PS. If the path to your text file has a space in it, be sure to put quotes around it. Otherwise, it will be split at the spaces into argv[1], argv[2], etc.

    PPS. The path to the file name will either be relative to where your command terminal is open or absolute. It is NOT relative to the location of the program unless you open the command terminal in the same folder as the program.
     
    Last edited: Feb 11, 2016
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook