fstream and string getline problem

Having something of a problem with an exercise. The program is meant to read in a series of names and donation amount to an array of structures from a text file. First it reads in the number of donors, which works in my programs, however when I try to read in the names to string objects within an array of structures I get nothing. Here's the relevant code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
std::ifstream fin;
fin.open("a.txt");
if (!(fin.is_open()))
   exit(EXIT_FAILURE);

fin >> n_ArraySize;

donor* p_DonArray = new donor[n_ArraySize];

for (int i = 0; i < n_ArraySize; i++)
{
    getline(fin, p_DonArray[i].str_DonName);
    fin >> p_DonArray[i].df_DonAmount;
}


I'm kind of sure that the problem is the way I'm passing the string to the <string> getline function, but from everything I read on getline() it's correct (though I haven't seen anything about inputting to an array of strings, or a string in an array of objects/structs) Thanks!

Edit: Oops, sorry forgot the problem. It compiles fine, and runs. But for output it doesn't show any of the donor names. Basically, the program is supposed to show the names of those that donated more then 10000 under the title "Grand Patron", then show those that donated less under "Patron" Here's the output I get atm:

1
2
3
4
5
6
7
8
9
10
11
Opening file and processing data.

Grand Patrons:

none

Patrons:


Process returned 0 (0x0)   execution time : 0.004 s
Press any key to continue.


It should say "none" under Patrons too. The set of data in the text file includes 2 entries that should show under the Grand Patron list though. So that makes me think it's not even reading anything in after the initial array size value is read in.

Here's the entire program if it helps:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>

struct donor
{
    std::string str_DonName;
    double df_DonAmount;
};


int main()
{
    std::cout << "Opening file and processing data.\n\n";
    int n_ArraySize = 0;

    std::ifstream fin;
    fin.open("a.txt");
    if (!(fin.is_open()))
        exit(EXIT_FAILURE);

    fin >> n_ArraySize;

    donor* p_DonArray = new donor[n_ArraySize];

    for (int i = 0; i < n_ArraySize; i++)
    {
        getline(fin, p_DonArray[i].str_DonName);
        fin >> p_DonArray[i].df_DonAmount;
    }

    std::cout << "Grand Patrons:\n" << std::endl;

    int j = 0;

    for (int i = 0; i < n_ArraySize; i++)
    {
        if (p_DonArray[i].df_DonAmount >= 10000)
        {
            std::cout << p_DonArray[i].str_DonName << std::endl;
            j++;
        }
    }

    if (j == 0)
        std::cout << "none\n";

    std::cout << std::endl;
    int k = 0;

    std::cout << "Patrons:\n" << std::endl;

    for (int i = 0; i < n_ArraySize; i++)
    {
        if (p_DonArray[i].df_DonAmount < 10000)
        {
            std::cout << p_DonArray[i].str_DonName << std::endl;
            k++;
        }
    }

    if (k == 0)
        std::cout << "none\n";


    return 0;
}
Last edited on
And the problem is...? i.e. What error(s) are you getting?
Well, apparently no one has ever read from a file into a string object in an array of structures because I can't find ANYTHING ANYWHERE on the net even close to it. *sigh* Unfortunately, this is EXACTLY what this exercise seems to call for.
No ideas at all from anyone? This is infuriating. Everything I have read said this SHOULD work exactly like this. The book I'm using to learn C++ said except for having to create ifstream object, input from a file is pretty similar to using cin. Then why doesn't this work?
Well, solved this myself. Figuring the problem was on line 29 and that ifstream and std::string getline weren't mixing well, I decided to simply use fin >> to read each part of the name into it's own string, then assign them to the struct array. All works well now. Here's the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>

struct donor
{
    std::string str_DonName;
    double df_DonAmount;
};


int main()
{
    std::cout << "Opening file and processing data.\n\n";
    int n_ArraySize = 0;

    std::ifstream fin;
    fin.open("a.txt");
    if (!(fin.is_open()))
        exit(EXIT_FAILURE);

    fin >> n_ArraySize;
    donor* p_DonArray = new donor[n_ArraySize];

    for (int i = 0; i < n_ArraySize; i++)
    {
        std::string first;
        std::string last;

        fin >> first;
        fin >> last;

        if (!(fin.good()))
        {
            std::cout << "Error reading from file\n";
            break;
        }
        p_DonArray[i].str_DonName = first + ' ' + last;
        fin >> p_DonArray[i].df_DonAmount;
    }

    std::cout << "Grand Patrons:\n" << std::endl;

    int j = 0;

    for (int i = 0; i < n_ArraySize; i++)
    {
        if (p_DonArray[i].df_DonAmount >= 10000)
        {
            std::cout << p_DonArray[i].str_DonName << std::endl;
            j++;
        }
    }

    if (j == 0)
        std::cout << "none\n";

    std::cout << std::endl;
    int k = 0;

    std::cout << "Patrons:\n" << std::endl;

    for (int i = 0; i < n_ArraySize; i++)
    {
        if (p_DonArray[i].df_DonAmount < 10000)
        {
            std::cout << p_DonArray[i].str_DonName << std::endl;
            k++;
        }
    }

    if (k == 0)
        std::cout << "none\n";

    return 0;
}


This feels like a bad hack though. I think the problem with using string's getline() had to do with windows using CR/LF as end of line, but no idea since I'm not that familiar with file input yet. If anyone has any ideas I'd be glad to hear about it since this is a slightly less elegant solution then I was hoping for. Thanks.
Without seeing the input file "a.txt", I was reduced to guesswork.

This worked for me.
Note the only significant changes, lines 25 and 33 inserted to ignore the newline character which is left in the file buffer after reading the number.

For reference, this was my input file, if it's the wrong format then my solution may be irrelevant:
3
fred bloggs
3
mark train
987654
bill bryson
2


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>


struct donor
{
    std::string str_DonName;
    double df_DonAmount;
};


int main()
{
    std::cout << "Opening file and processing data.\n\n";
    int n_ArraySize = 0;

    std::ifstream fin;
    fin.open("..\\..\\input.txt");
    if (!(fin.is_open()))
        return 1;

    fin >> n_ArraySize;
    fin.ignore(100, '\n');

    donor* p_DonArray = new donor[n_ArraySize];

    for (int i = 0; i < n_ArraySize; i++)
    {
        getline(fin, p_DonArray[i].str_DonName);
        fin >> p_DonArray[i].df_DonAmount;
        fin.ignore(100, '\n');
    }

    std::cout << "Grand Patrons:\n" << std::endl;

    int j = 0;

    for (int i = 0; i < n_ArraySize; i++)
    {
        if (p_DonArray[i].df_DonAmount >= 10000)
        {
            std::cout << p_DonArray[i].str_DonName << std::endl;
            j++;
        }
    }

    if (j == 0)
        std::cout << "none\n";

    std::cout << std::endl;
    int k = 0;

    std::cout << "Patrons:\n" << std::endl;

    for (int i = 0; i < n_ArraySize; i++)
    {
        if (p_DonArray[i].df_DonAmount < 10000)
        {
            std::cout << p_DonArray[i].str_DonName << std::endl;
            k++;
        }
    }

    if (k == 0)
        std::cout << "none\n";


    return 0;
}
Last edited on
Yup, that's exactly what my txt file looks like, with the first line being the number of records, then the rest of the ints being the donation amounts. I created it in notepad, which obviously uses CR/LF for EOL.

Dang, now that I read this I realize I was using std::cin.ignore and not fin.ignore when I tried just this solution.... *sigh*. Thanks Chervil.
Topic archived. No new replies allowed.