Confused with error using ofstream

Discussion in 'C++' started by rEvolution27@gmail.com, Mar 3, 2007.

  1. Guest

    I'm a c++ newbie here, trying out some stuff and when I try to compile
    this:

    void create() {
    char name;
    cout << "Creating a new timetable /n Please type a name for this
    timetable";
    cin >> name;
    ofstream editFile;
    editFile.open (name, ios::eek:ut | ios::app);
    editFile << name << endl;
    }

    I get this:
    invalid conversion from `char' to `const char*'

    I kinda understand why i'm getting this since when I change:
    editFile.open (name, ios::eek:ut | ios::app);
    To:
    editFile.open ("Timetable.txt", ios::eek:ut | ios::app); , it compiles
    But how do I get it do do what I want?
     
    , Mar 3, 2007
    #1
    1. Advertising

  2. wrote:
    > I'm a c++ newbie here, trying out some stuff and when I try to compile
    > this:
    >
    > void create() {
    > char name;
    > cout << "Creating a new timetable /n Please type a name for this
    > timetable";
    > cin >> name;
    > ofstream editFile;
    > editFile.open (name, ios::eek:ut | ios::app);
    > editFile << name << endl;
    > }
    >
    > I get this:
    > invalid conversion from `char' to `const char*'
    >
    > I kinda understand why i'm getting this since when I change:
    > editFile.open (name, ios::eek:ut | ios::app);
    > To:
    > editFile.open ("Timetable.txt", ios::eek:ut | ios::app); , it compiles
    > But how do I get it do do what I want?
    >


    char is a single char, a file name is (obviously) multiple chars.

    Put it another way in C++ a char and a string of chars are not the same
    thing.

    The best way in C++ to do what you want is to use the string class. The
    next best way is to use a dynamic array of chars, the worst way is to
    use a static arrays of chars.

    Here's some example code using the string class

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

    void create() {
    string name;
    cout << "Creating a new timetable \n Please type a name for this
    timetable ";
    cin >> name;
    ofstream editFile(name.c_str());
    editFile << name << endl;

    You need the c_str() method to convert a C++ string into what ofstream
    requires.

    char, arrays of chars, dynamic allocation of arrays, strings etc. are a
    big topic which should be covered in great detail in your favourite C++
    book.

    john
     
    John Harrison, Mar 3, 2007
    #2
    1. Advertising

  3. Alan Johnson Guest

    wrote:
    > I'm a c++ newbie here, trying out some stuff and when I try to compile
    > this:
    >
    > void create() {
    > char name;


    In the above line you define 'name' as a char. That is, a single
    character, 1 byte. Probably not what you want.

    > cout << "Creating a new timetable /n Please type a name for this
    > timetable";
    > cin >> name;


    Because, as previously mentioned, name is a char, you read exactly 1
    character here.


    > ofstream editFile;
    > editFile.open (name, ios::eek:ut | ios::app);


    open expects a POINTER to the first character in an null-terminated
    array of characters. If you don't understand pointers and their
    relationship to arrays, now is the appropriate time to drop what you are
    doing and go read about it.


    > editFile << name << endl;
    > }
    >
    > I get this:
    > invalid conversion from `char' to `const char*'


    Given the above explanation, this message might make sense now. 'name'
    is a char, but open wants a pointer to a char.

    >
    > I kinda understand why i'm getting this since when I change:
    > editFile.open (name, ios::eek:ut | ios::app);
    > To:
    > editFile.open ("Timetable.txt", ios::eek:ut | ios::app); , it compiles


    When you use a string literal (e.g. "Timetable.txt"), you create a
    null-terminated array of characters. And arrays can be implicitly
    converted to a pointer to their first element (again, go read about
    pointers and arrays if that is new to you), therefore open is getting
    what it wants, a pointer to a character.

    > But how do I get it do do what I want?
    >


    A number of ways. First, the not particularly safe, but easier to
    understand way:

    // I chose the size 80 arbitrarily. This is unsafe.
    char name[80] ;
    cin >> name ;

    This will read from standard input until it sees white space. If there
    are more than 79 characters (the null-terminator takes 1 character, read
    about C-style strings if this is new to you) available then you have
    your classic buffer-overflow problem.

    A second, more complicated solution, would be to dynamically allocate an
    array, and resize it each time it runs out of space. This is not
    trivial to do correctly, so I won't even bother. Let's move on to the
    third solution.

    Use std::string.

    #include <string>

    ....

    std::string name ;
    cin >> name ;

    ....

    editFile.open(name.c_str(), ios::eek:ut | ios::app) ;


    std::string does any necessary memory allocating and reallocating for
    you. You can get pointer to a null-terminated array of characters using
    the c_str method, as demonstrated above.

    --
    Alan Johnson
     
    Alan Johnson, Mar 3, 2007
    #3
  4. Guest

    Ok, thanks.
    For some reason I thought 'char name' would create a character array
    that matches the size of what's put into it. I guess i'll use strings
    then.
     
    , Mar 3, 2007
    #4
  5. Guest

    How would I make it so that the string can accept more than one word?

    I've got this so far...
    void create() {
    string name;
    cout << "Creating a new timetable"<< endl <<"Type a name for this
    timetable" << endl;
    cin >> name;
    ofstream editFile;
    editFile.open ("timetable.txt", ios::eek:ut | ios::trunc);
    editFile << name << endl;
    }

    But when I open timetable.txt, I only see the first word of what I
    typed for name.
     
    , Mar 3, 2007
    #5
  6. Ian Collins Guest

    wrote:
    > How would I make it so that the string can accept more than one word?
    >
    > I've got this so far...
    > void create() {
    > string name;
    > cout << "Creating a new timetable"<< endl <<"Type a name for this
    > timetable" << endl;
    > cin >> name;
    > ofstream editFile;
    > editFile.open ("timetable.txt", ios::eek:ut | ios::trunc);
    > editFile << name << endl;
    > }
    >
    > But when I open timetable.txt, I only see the first word of what I
    > typed for name.
    >

    That's how std::istream& operator( std::istream& std::string& ) works.
    If you want the full line, use getline.

    --
    Ian Collins.
     
    Ian Collins, Mar 3, 2007
    #6
  7. Guest

    On Mar 3, 6:04 pm, Ian Collins <> wrote:
    > wrote:
    > > How would I make it so that the string can accept more than one word?

    >
    > > I've got this so far...
    > > void create() {
    > > string name;
    > > cout << "Creating a new timetable"<< endl <<"Type a name for this
    > > timetable" << endl;
    > > cin >> name;
    > > ofstream editFile;
    > > editFile.open ("timetable.txt", ios::eek:ut | ios::trunc);
    > > editFile << name << endl;
    > > }

    >
    > > But when I open timetable.txt, I only see the first word of what I
    > > typed for name.

    >
    > That's how std::istream& operator( std::istream& std::string& ) works.
    > If you want the full line, use getline.
    >
    > --
    > Ian Collins.


    You lost me there....
     
    , Mar 3, 2007
    #7
  8. Jim Langston Guest

    <> wrote in message
    news:...
    > On Mar 3, 6:04 pm, Ian Collins <> wrote:
    >> wrote:
    >> > How would I make it so that the string can accept more than one word?

    >>
    >> > I've got this so far...
    >> > void create() {
    >> > string name;
    >> > cout << "Creating a new timetable"<< endl <<"Type a name for this
    >> > timetable" << endl;
    >> > cin >> name;
    >> > ofstream editFile;
    >> > editFile.open ("timetable.txt", ios::eek:ut | ios::trunc);
    >> > editFile << name << endl;
    >> > }

    >>
    >> > But when I open timetable.txt, I only see the first word of what I
    >> > typed for name.

    >>
    >> That's how std::istream& operator( std::istream& std::string& ) works.
    >> If you want the full line, use getline.
    >>
    >> --
    >> Ian Collins.

    >
    > You lost me there....


    std::getline( std::cin, name );
     
    Jim Langston, Mar 3, 2007
    #8
  9. Guest

    The following compiles, but the getline doesn't seem to work... am I
    missing something here?

    void create() {
    string name;
    cout << "Creating a new timetable"<< endl <<"Type a name for this
    timetable" << endl;
    getline(cin,name);
    ofstream editFile;
    editFile.open ("timetable.txt", ios::eek:ut | ios::trunc);
    editFile << name << endl;
    system ("pause");
     
    , Mar 4, 2007
    #9
  10. wrote:
    > The following compiles, but the getline doesn't seem to work... am I
    > missing something here?
    >
    > void create() {
    > string name;
    > cout << "Creating a new timetable"<< endl <<"Type a name for this
    > timetable" << endl;
    > getline(cin,name);
    > ofstream editFile;
    > editFile.open ("timetable.txt", ios::eek:ut | ios::trunc);
    > editFile << name << endl;
    > system ("pause");
    >
    >
    >
    >
    >


    Can't tell from the code you've posted, but possibly you've fallen into
    the well known gotcha described here

    http://www.parashift.com/c -faq-lite/input-output.html#faq-15.6

    In other words getline is working, it's just it is reading the newline
    that was left behind by some previous input.

    john
     
    John Harrison, Mar 4, 2007
    #10
  11. Guest

    On Mar 4, 11:04 am, John Harrison <> wrote:
    > wrote:
    > > The following compiles, but the getline doesn't seem to work... am I
    > > missing something here?

    >
    > > void create() {
    > > string name;
    > > cout << "Creating a new timetable"<< endl <<"Type a name for this
    > > timetable" << endl;
    > > getline(cin,name);
    > > ofstream editFile;
    > > editFile.open ("timetable.txt", ios::eek:ut | ios::trunc);
    > > editFile << name << endl;
    > > system ("pause");

    >
    > Can't tell from the code you've posted, but possibly you've fallen into
    > the well known gotcha described here
    >
    > http://www.parashift.com/c -faq-lite/input-output.html#faq-15.6
    >
    > In other words getline is working, it's just it is reading the newline
    > that was left behind by some previous input.
    >
    > john


    Oh, thanks alot. I actually had a hunch that that was what was
    happening. I fixed it with a cin.ignore(); but it looks like a bug
    that might just happen again and this time be harder to solve. Apart
    from putting a cin.ingnore(); after every cin is there any way to
    solve this?
    Also con someone explain to me how getline works in terms of it's
    arguments... I don't quite understand it.
    My C++ book arrives in a few days, I hope it's as useful as you
    guys.
     
    , Mar 4, 2007
    #11
  12. wrote:
    > On Mar 4, 11:04 am, John Harrison <> wrote:
    >
    >> wrote:
    >>
    >>>The following compiles, but the getline doesn't seem to work... am I
    >>>missing something here?

    >>
    >>>void create() {
    >>>string name;
    >>>cout << "Creating a new timetable"<< endl <<"Type a name for this
    >>>timetable" << endl;
    >>>getline(cin,name);
    >>>ofstream editFile;
    >>>editFile.open ("timetable.txt", ios::eek:ut | ios::trunc);
    >>>editFile << name << endl;
    >>>system ("pause");

    >>
    >>Can't tell from the code you've posted, but possibly you've fallen into
    >>the well known gotcha described here
    >>
    >>http://www.parashift.com/c -faq-lite/input-output.html#faq-15.6
    >>
    >>In other words getline is working, it's just it is reading the newline
    >>that was left behind by some previous input.
    >>
    >>john

    >
    >
    > Oh, thanks alot. I actually had a hunch that that was what was
    > happening. I fixed it with a cin.ignore(); but it looks like a bug
    > that might just happen again and this time be harder to solve. Apart
    > from putting a cin.ingnore(); after every cin is there any way to
    > solve this?


    It depnds on exactly what you are doing, but in a program that reads
    from cin my usual choice would be to make all input operations read
    whole lines, getline does this anyway but cin >> does not. So I would add

    cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

    after each use of cin >>

    You can even write an 'iostream manipulator' to do that for you.

    #include <iostream>
    #include <limits>
    #include <string>

    std::istream& skip_to_eol(std::istream& in)
    {
    in.ignore(std::numeric_limits<int>::max(), '\n');
    return in;
    }

    int main()
    {
    int x, y;
    std::cin >> x >> y >> skip_to_eol;
    std::string z;
    std::getline(std::cin, z);
    std::cout << x << ' ' << y << ' ' << z << '\n';
    }

    See how skip_to_eol is just an easy way to call ignore.

    > Also con someone explain to me how getline works in terms of it's
    > arguments... I don't quite understand it.


    I'm not sure what there is to understand. getline reads characters from
    an input stream (the first argument) until an end of line character is
    read. All characters read (except the end of line character) are
    accumulated into the string that is the second argument. An optional
    third argument specifies the end of line character (by default it is '\n').


    > My C++ book arrives in a few days, I hope it's as useful as you
    > guys.
    >
    >
     
    John Harrison, Mar 4, 2007
    #12
  13. Guest


    > I'm not sure what there is to understand. getline reads characters from
    > an input stream (the first argument) until an end of line character is
    > read. All characters read (except the end of line character) are
    > accumulated into the string that is the second argument. An optional
    > third argument specifies the end of line character (by default it is '\n').


    Ok, the input stream is the first argument, that´s what i needed to
    know.

    Ok, this is the last thing for a while... (hopefully :) )
    I'm going to post all my code so far... I know it ain't alot but I
    have a few questions. Mainly I want to know how to make the functions
    more abstract (I think that's the term).

    // Timetable program, by Evan Skeete
    // Functionality to build:
    // Save timetable to file
    // Create new/delete timetables
    // Edit time tables??
    // Timetable reminders

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

    // This function creates a new txt file to contain a timetable with //
    the name of the timetable as the first line of the file.
    // I'm going to make it so that the variable name will also be the //
    name of the .txt file
    // I'm thinking about removing the inputs and outputs from this
    // function so it's more abstract

    void create() {
    string name;
    cout << "Creating a new timetable"<< endl <<"Type a name for this
    timetable" << endl;
    getline( cin,name );
    ofstream editFile;
    editFile.open ("timetable.txt", ios::eek:ut | ios::trunc);
    editFile << name << endl;
    }

    // This function allows the user to type in one letter commands
    to // make the program do things

    void options() {
    do {
    char choice;
    cin >> choice; // Should I use getline here?
    cin.ignore(); // I want a way to avoid this
    switch (choice) {
    case 'h' :
    cout << "Type 'n' to create a new timetable" << endl;
    break;

    case 'n':
    create();
    break;

    default :
    cout << "Not a valid command";
    }
    } while (choice != 'n') ; //
    }

    // I want to eliminate the do while loop here, or find a better way //
    of doing what it does
    // as it is, i' m going to hove to add a new condition every time I //
    add a new case which I don't want to loop

    int main() {
    cout << "Welcome to the Timetable Program" << endl;
    cout << "For help, type 'h'" << endl;
    void options();
    return 0;
    }

    If you see any improvements I can make please tell me.
    My coding speed is extremely low :( I guess it's because I'm just
    starting...

    Thanks,
    Evan
     
    , Mar 4, 2007
    #13
  14. Jim Langston Guest

    <> wrote in message >
    news:...

    > > I'm not sure what there is to understand. getline reads characters from
    > > an input stream (the first argument) until an end of line character is
    > > read. All characters read (except the end of line character) are
    > > accumulated into the string that is the second argument. An optional
    > > third argument specifies the end of line character (by default it is
    > > '\n').

    >
    > Ok, the input stream is the first argument, that´s what i needed to
    > know.
    >
    > Ok, this is the last thing for a while... (hopefully :) )
    > I'm going to post all my code so far... I know it ain't alot but I
    > have a few questions. Mainly I want to know how to make the functions
    > more abstract (I think that's the term).
    >
    > // Timetable program, by Evan Skeete
    > // Functionality to build:
    > // Save timetable to file
    > // Create new/delete timetables
    > // Edit time tables??
    > // Timetable reminders
    >
    > #include <iostream>
    > #include <fstream>
    > #include <string>
    > using namespace std;
    >
    > // This function creates a new txt file to contain a timetable with //
    > the name of the timetable as the first line of the file.
    > // I'm going to make it so that the variable name will also be the //
    > name of the .txt file
    > // I'm thinking about removing the inputs and outputs from this
    > // function so it's more abstract
    >
    > void create() {
    > string name;
    > cout << "Creating a new timetable"<< endl <<"Type a name for this
    > timetable" << endl;
    > getline( cin,name );
    > ofstream editFile;


    editFile is local to the function create()

    > editFile.open ("timetable.txt", ios::eek:ut | ios::trunc);


    Here you create a file and open it

    > editFile << name << endl;


    At this point you return from the function, editFile is closed since it goes
    out of scope. You wont' be able to use the ofstream outside the function.
    I don't think that's what you wanted.

    > }
    >
    > // This function allows the user to type in one letter commands
    > to // make the program do things
    >
    > void options() {
    > do {
    > char choice;
    > cin >> choice; // Should I use getline here?


    I probably would.

    > cin.ignore(); // I want a way to avoid this


    You can't really. I'm not sure what std::getline( std::cin, choice ); would
    do if they entered more than a single character, but probably not what you
    want.

    > switch (choice) {
    > case 'h' :
    > cout << "Type 'n' to create a new timetable" << endl;
    > break;
    >
    > case 'n':
    > create();
    > break;
    >
    > default :
    > cout << "Not a valid command";
    > }
    > } while (choice != 'n') ; //


    Hmm.. can this while statement even see choice which is declared inside the
    block? I woudl think you would need to declare choice outside the block
    (before your do { ) but I may be wrong.

    > }
    >
    > // I want to eliminate the do while loop here, or find a better way //
    > of doing what it does
    > // as it is, i' m going to hove to add a new condition every time I //
    > add a new case which I don't want to loop


    Normally in this type of program, it's somethign like "Enter a choice, x to
    exit" and your condition is while ( choice != 'x' ) that way you don't have
    to keep changing it. Also, the help is usually given before the user input.
    I.E.

    std::cout << "Type 'n' to create a new timetable, 'x' to exit ";
    std::cin >> choice;

    >
    > int main() {
    > cout << "Welcome to the Timetable Program" << endl;
    > cout << "For help, type 'h'" << endl;
    > void options();
    > return 0;
    > }
    >
    > If you see any improvements I can make please tell me.
    > My coding speed is extremely low :( I guess it's because I'm just
    > starting...
    >
    > Thanks,
    > Evan
    >
     
    Jim Langston, Mar 4, 2007
    #14
  15. Comments below

    wrote:
    >>I'm not sure what there is to understand. getline reads characters from
    >>an input stream (the first argument) until an end of line character is
    >>read. All characters read (except the end of line character) are
    >>accumulated into the string that is the second argument. An optional
    >>third argument specifies the end of line character (by default it is '\n').

    >
    >
    > Ok, the input stream is the first argument, that´s what i needed to
    > know.
    >
    > Ok, this is the last thing for a while... (hopefully :) )
    > I'm going to post all my code so far... I know it ain't alot but I
    > have a few questions. Mainly I want to know how to make the functions
    > more abstract (I think that's the term).
    >
    > // Timetable program, by Evan Skeete
    > // Functionality to build:
    > // Save timetable to file
    > // Create new/delete timetables
    > // Edit time tables??
    > // Timetable reminders
    >
    > #include <iostream>
    > #include <fstream>
    > #include <string>
    > using namespace std;
    >
    > // This function creates a new txt file to contain a timetable with //
    > the name of the timetable as the first line of the file.
    > // I'm going to make it so that the variable name will also be the //
    > name of the .txt file
    > // I'm thinking about removing the inputs and outputs from this
    > // function so it's more abstract


    That's a good idea. By putting the prompts for input into the function
    you are ensuring that the function can be used in only one situation.
    It's a good general princple, seperate the code that does the work from
    the code that is part of the user interface.

    BTW usually this is called making the code generic rather than abstract.

    >
    > void create() {
    > string name;
    > cout << "Creating a new timetable"<< endl <<"Type a name for this
    > timetable" << endl;
    > getline( cin,name );
    > ofstream editFile;
    > editFile.open ("timetable.txt", ios::eek:ut | ios::trunc);
    > editFile << name << endl;
    > }
    >
    > // This function allows the user to type in one letter commands
    > to // make the program do things
    >
    > void options() {
    > do {
    > char choice;
    > cin >> choice; // Should I use getline here?
    > cin.ignore(); // I want a way to avoid this


    First off cin.ignore() is wrong because it ignores one char acter only,
    so if the user type 'n', ' ', '\n' you would have exactly same problem
    you had earlier, the call to ignore would eat up the space but the
    newline would still be there.

    You should use

    cin.ignore(std::numeric_limits<int>::max(), '\n');

    which ignores the rest of the line, however long it is. The skip_to_eol
    manipulator I showed you in my last post is an easy way of doing this

    cin >> choice >> skip_to_eol;


    getline is not a cgood idea here for two reasons. Firslty getline only
    works on strings not on chars, so you'd have to figure out how to get a
    char out of the string you read. Secondly using >> here actually a
    couple of things for you, it skip any whitespace, and it doesn't give up
    until the user has typed something that isn't whitespace. You would have
    to do that work yourself if you used getline.

    > switch (choice) {
    > case 'h' :
    > cout << "Type 'n' to create a new timetable" << endl;
    > break;
    >
    > case 'n':
    > create();
    > break;
    >
    > default :
    > cout << "Not a valid command";
    > }
    > } while (choice != 'n') ; //
    > }
    >
    > // I want to eliminate the do while loop here, or find a better way //
    > of doing what it does
    > // as it is, i' m going to hove to add a new condition every time I //
    > add a new case which I don't want to loop


    Not quite sure I follow that.

    >
    > int main() {
    > cout << "Welcome to the Timetable Program" << endl;
    > cout << "For help, type 'h'" << endl;
    > void options();


    I think you mean

    options();

    > return 0;
    > }
    >
    > If you see any improvements I can make please tell me.
    > My coding speed is extremely low :( I guess it's because I'm just
    > starting...
    >
    > Thanks,
    > Evan
    >


    john
     
    John Harrison, Mar 4, 2007
    #15
  16. Old Wolf Guest

    On Mar 4, 10:01 am, Alan Johnson <> wrote:
    > std::string name ;
    > cin >> name ;
    > editFile.open(name.c_str(), ios::eek:ut | ios::app) ;


    Filenames may contain whitespace. The '>>' operator is for formatted
    input; but for obtaining a filename you probably want to use exactly
    what was entered, e.g.:
    std::getline( std::cin, name );

    Also I think it is worthwhile doing error handling, even when you are
    only learning the language, e.g.:
    if ( ! std::cin.good() )
    throw std::runtime_error("Unable to read filename");
     
    Old Wolf, Mar 4, 2007
    #16
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. steve
    Replies:
    2
    Views:
    739
    Raoul Gough
    Aug 20, 2003
  2. Colum
    Replies:
    2
    Views:
    961
    Rob Williscroft
    Dec 19, 2003
  3. Replies:
    3
    Views:
    8,924
    Peter Julian
    Jun 3, 2005
  4. Squid Seven

    ofstream * vs. ofstream

    Squid Seven, Jul 13, 2005, in forum: C++
    Replies:
    5
    Views:
    625
    Ivan Johansen
    Jul 14, 2005
  5. aaragon
    Replies:
    15
    Views:
    626
    James Kanze
    Sep 28, 2007
Loading...

Share This Page