Click here to Skip to main content
15,919,613 members
Please Sign up or sign in to vote.
3.00/5 (2 votes)
See more:
File in text
C++
Excalibur
150
Throwing Stars
15
Rapier
200
Bow and Arrow
100

My code to read them by text
C++
...
struct Weapon
{
    char name[MAXNAME];
    int strength;
};
...
Weapon wp[WPNUM];
ifstream infile;
...
for (int i = 0; i < WPNUM; i++)
{
    infile.getline(wp[i], MAXNAME, '\n');
    cout << wp[i].name << endl;
    infile >> wp[i].strength;
    cout << wp[i].strength << endl;
}
...

But it doesn't work. Anyone can help? Thanks in advance.

Edit: Changed the title to reflect what the problem really is and got rid of some superfluous stuff.
Posted
Updated 18-May-12 21:32pm
v2
Comments
Mohibur Rashid 18-May-12 21:57pm    
What was it suppose to do?
Aescleal 19-May-12 3:29am    
I gave the question a 5 even though the question was fairly bad in it's presentation 'cause:

- It was pretty easy to see what the questioner was on about
- Problems with extraction operators interacting with getline are pretty common and if it can be answered for one person it can be helpful for loads of people. As most people have their visibility filters set to 3.0 or less this question would become invisible and I didn't want that

There's a couple of problems I can see here:

- you're not checking for the end of the file or something else going wrong with the stream.
- you're using the member version of getline, use the free function version instead
- using an extractor on a stream doesn't remove any white-space after it so getline will be reading an empty string

Use something like:

C++
int read_integer_from_stream( std::istream &from )
{
	int n; from >> n;
	std::string rest_of_line;
	std::getline( from, rest_of_line );
	return n;
}


Oh, and don't use arrays, this isn't 1994. Try using std::vector and std::string - they're far safer. And presuming weapon's actually going to be used for something make it a class.

End of sermon :-)

PS: Actually it's not the end of the sermon... Looking at the previous solution and criticising it for not being C++ but a bastard breed of C and C++ I thought I should put my money where my mouth is and knock up a quick idea of how I'd approach the problem:
C++
#include <sstream>
#include <vector>
#include <iterator>
#include <string>

int read_integer_from_stream( std::istream &from )
{
    int n; from >> n;
    std::string rest_of_line;
    std::getline( from, rest_of_line );
    return n;
}

class weapon
{
    public:
        weapon() : power_( 0 ){}

        weapon( std::istream &initialise_from )
        {
            std::getline( initialise_from, name_ );
            power_ = read_integer_from_stream( initialise_from );
        }

        weapon( weapon &©_me )
        {
            swap( std::move( copy_me ) );
        }

        weapon &operator=( const weapon ©_me )
        {
            weapon w( copy_me );
            swap( std::move( w ) );
            return *this;
        }

        weapon &operator=( weapon &©_me )
        {
            swap( std::move( copy_me ) );
            return *this;
        }

        std::string name() const
        {
            return name_;
        }

        bool is_more_powerful_than( const weapon &compare_against ) const
        {
            return power_ > compare_against.power_;
        }

        void swap( weapon &&swap_with )
        {
            std::swap( swap_with.name_,  name_  );
            std::swap( swap_with.power_, power_ );
        }

        friend std::ostream &operator<<( std::ostream &, const weapon & );
        friend std::ostream &operator>>( std::istream &, const weapon & );

    private:
        std::string name_;
        int power_;
};

std::ostream &operator<<( std::ostream &str, const weapon &w )
{
    return str << w.name_ << '\n' << w.power_ << '\n';
}

std::istream &operator>>( std::istream &str, weapon &to_modify )
{
    weapon w( str );
    to_modify.swap( std::move( w ) );
    return str;
}

void weapon_test( std::ostream &output )
{
    std::istringstream input( "Sword\n87\nAxe\n88\n" );
    std::vector<weapon> weapons;

    typedef std::istream_iterator<weapon> input_iter;
    typedef std::ostream_iterator<weapon> output_iter;
    std::copy( input_iter( input ), input_iter(), std::back_inserter( weapons ) );
    std::copy( begin( weapons ), end( weapons ), output_iter( output, "" ) );
}

There are still some horrible things in here I wouldn't do it real life:

- All the functions are inline
- I'm not permissive enough about the stream format, each weapon has to end with a newline, even the last one
- I'm not using a PIMP
- The test harness is trival and, honestly, crap. Not every behaviour is tested (although they're fairly trivial)
- The class is in the same file as the test
- No non-member swap

Good points are (he says modestly...)

- No manual loops
- Class can cope with most things an intrinsic value can
- Has an exception safe assignment operaor
- Has a move constructor and assignment operator (really important these days)

Numerous Edits: To get rid of tabs and make it look slightly better, fix loads of errors caused by idiot me pasting an old version in
 
Share this answer
 
v10
Comments
enhzflep 19-May-12 4:18am    
A solution and explanation like this works for me!
I'd nearly taken a seat in the high-chair myself and had a 'go' at the code snippet using C & C++, though when I came to using ifstream.getline, found that it needed a char* - had not been aware of the version of the function that existed outside a class & hence repeated the mistake.
Extra points for the comprehensiveness, too. :)
My +5.
To be honest, I've never been a huge fan of c++'s way of extracting formatted info from a stream. As a result, I've never been terribly proficient(nor needed to be) with them. Here's some code that works just fine with your input data:


C++
#include <iostream>
#include <fstream>
#include <stdlib.h>

using namespace std;

const int MAXLINE = 1024;

struct Weapon
{
    string name;
    int strength;
};

int main()
{
    char *szFilename = "test.txt";
    const int numWeapons = 4;
    int i;
    ifstream inputFile(szFilename);
    Weapon wpnRack[numWeapons];
    char lineBuffer[MAXLINE];

    for (i=0; i<4; i++)
    {
        inputFile.getline(lineBuffer, MAXLINE);
        wpnRack[i].name = lineBuffer;

        inputFile.getline(lineBuffer, MAXLINE);
        wpnRack[i].strength = atoi(lineBuffer);

        cout << wpnRack[i].name << endl;
        cout << "\t" << wpnRack[i].strength << endl;
    }
    inputFile.close();

    return 0;
}

Output:
Excalibur
        150
Throwing Stars
        15
Rapier
        200
Bow and Arrow
        100
 
Share this answer
 
v2
Comments
Aescleal 19-May-12 3:35am    
I only gave this a 3 'cause it's 2012, not 1994. Using atoi, character arrays and manually closing streams aren't good practices and shouldn't be encouraged. If the kids of today see this they'll think this is the way C++ is supposed to be. I'll have to put up with yet more badly informed programmers in my workplace and I've got enough of those already.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900