0

So, i'm trying to write a program that can read data from a file. The file consists of integers, chars and doubles. And i have to be able to assign them to different variables for further calculation (this is actually just a part of a bigger program). I've searched around the web (here also), and i've seen different solutions. stringstream, vectors and whatnot. The one i got furthest with, was using "skipws" when reading. But i can't seem to read the integers properly.

I would prefer a solution that requires the use of as few methods (streams, gets etc) as possible. But if i need more, i can live with it.

#include <iostream>
#include <fstream>
#include <cstring>

using namespace::std;

int main()
{
    int j = 0, kill = 0, i;
    char initials[10];
    int results[10];
    double avg;

    ifstream read("P1.txt");

    if (!read) //test to see if file can be opened.
    {
        cerr << "Error" << endl;
        exit(1);
    }

    while(kill != 1) //kill = 1 same as eof. Just my weird way of coding. 
    {
        switch (j)
        {
            case 0:     //read the first line of data, which is the chars.
                read >> skipws >> initials;
                j++;
                break;

            case 1: //read the second line of data, which is 10 integers and whitespace
                for (i=0;i<10;i++)
                read >> skipws >> results[i];
                j++;
                break;

            case 2:     //read the last line which is a single double.
                read >> skipws >> avg;
                j++;
                break;

            case 3: //check for end of file. 
                if(read.eof() == 0)
                    kill = 1;
                break;
        }
    }
    //the 3 lines below are just writing the contents of the file to the prompt. 
    //It's to check that values are stored correctly for further use. 
    cout << initials << endl; 
    cout << results << endl;
    cout << avg << endl;

    return 0;
}

I know exactly what y input file, "P1.txt", will look like, because i create it myself in another part of the program. It looks like this:

ccs
2 4 5 3 1 4 6 1 1 1
2.8       

Those 3 lines gives me the initials of a player, his results of 10 games and his average score. In short, the data of one player. In the final program, i need to be able to read values for maybe 10 players.

I'm expecting the 3 cout lines in the end to show this:

ccs
2453146111
2.8

Now, this is as far as i have gotten. If i declare results[10] as char i can get this in my console:

ccs
2453146111ccs
2.8

If i declare it as int i get this

ccs
0x7fff5fbff6c0
2.8

Obviously, i can see that values aren't stored properly and something is out of hand, but i need another persons eyes on this. I'm out of clues.

I know this is a messy way to do it and that it can be done in less space, but i'm new to C++, so this made sense to me, and made it fairly easy for me to locate my mistakes, until now.

I tried to explain it as well as i could. This is my first post here, so please tell me if you need more info.

Thanks in advance!! Chris.

5 Answers5

1

when results is int[10] and you make cout << results << endl it will print the array memory address you should make loop that print result[i] in each iteration.

for(i=0;i<10;i++){
      cout<< result[i]; 
}

and it will give the correct result

Random
  • 467
  • 1
  • 4
  • 9
  • I could swear that i've tried that and it didn't work. I guess that is what happens when you look at the same code for too long. Something like a ')' is missing xD Thanks a lot. Works now! – user3338889 Feb 22 '14 at 16:32
1

I would suggest the following if you are using C++:

  • Create three stringstreams
  • Read each line into one stringstream
  • For each line use (when your stringstream is called ss):
    • ss >> c (with c your character)
    • ss >> i (with i your integer)
    • ss >> d (with d your double)
  • Put the values in a vector when more than one input can be given on a line.

Some code:

    string s[3] = {"ccs",
        "2 4 5 3 1 4 6 1 1 1",
        "2.8"
    };
    stringstream ss[3];

    /*
    Open file, get the first line into s[0], second into s[1] and third into s[2]
    */

    ss[0] << s[0];
    ss[1] << s[1];
    ss[2] << s[2];
    char c;
    int i;
    double d;

    vector<char> initials;
    vector<int> scores;
    vector<double> averages;

    while (ss[0] >> c) {
        cout << c << " ";
        initials.push_back(c);
    }
    cout << endl;
    while (ss[1] >> i) {
        cout << i << " ";
        scores.push_back(i);
    }
    cout << endl;
    while (ss[2] >> d) {
        cout << d << " ";
        averages.push_back(d);
    }
    cout << endl;
Hidde
  • 11,493
  • 8
  • 43
  • 68
1

This problem is made significantly easier by the fact that your data takes a known format. Don't let this go to waste.

string initials;
vector<int> r(NUM_SCORES);
double avg;

Now to get the data:

ifstream infile;
infile.open(...);
while(infile >> initials){ // i.e. "while there's another player"
    for(int i=0; i<r.size(); i++) infile >> r.at(i);
    infile >> avg;
}

Job done.

cout << "Player " << intials << " scored:" << endl;
for(int i=0; i<r.size(); i++) cout << r.at(i);
cout << endl << "giving him an average of " << avg << endl;
OJFord
  • 10,522
  • 8
  • 64
  • 98
  • `int r0,r1,r2,r3,r4,r5,r6,r7,r8,r9` ?!? Why not using a `std::vector` or `std::array` instead? It's possible to use an apprioprate `back_inserter` also. – πάντα ῥεῖ Feb 21 '14 at 22:07
  • That would undoubtedly be more concise. Reasoning just my lack of experience with vectors. Would the while loop not then need some counter, in order to do `infile >> vector.at(counter); counter++;`? – OJFord Feb 21 '14 at 22:14
  • _'Would the while loop ...'_ That's what a [`std::back_inserter`](http://en.cppreference.com/w/cpp/iterator/back_inserter) is supposed to do. – πάντα ῥεῖ Feb 21 '14 at 22:18
  • Okay, but that's just doing the same as manually incrementing a variable. If anything the latter would surely have less overhead. – OJFord Feb 21 '14 at 22:33
  • I have been over a method like yours and it works. The problem is that it is not really compatible with the rest of my program. I really need it in an array or vector. But thanks for the input. – user3338889 Feb 22 '14 at 16:33
  • Okay, as I said you can switch out the individual variables for an array or vector as it makes sense for you. See the comments above for how you can modify this for a vector, I'll edit in to my answer later (on mobile). – OJFord Feb 22 '14 at 16:57
1

Also when you read in a value from a file, it is not an "int" data type. you cannot just push it back to a array of int's and expect it to work, you will probably need to convert it to an int using something like std::stoi

Makka
  • 234
  • 4
  • 13
  • Rubbish, `int i; my_ifstream >> i;`. – OJFord Feb 21 '14 at 22:12
  • Just came back to edit this, opened up an old project to check my logic and it seems my custom class pushes it all back to strings before returning, hence why i have to convert. Disregard my nonsense. – Makka Feb 21 '14 at 22:17
1

Don't re-invent the wheel, you can use Boost::tokenizer to tokenize the string and use Lexical_cast to convert strings to numbers.

If you want to use plain c you can use strtok for tokenizing the string

Community
  • 1
  • 1
srs
  • 516
  • 1
  • 4
  • 20