Confused with error using ofstream

R

rEvolution27

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?
 
J

John Harrison

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
 
A

Alan Johnson

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.
 
R

rEvolution27

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.
 
R

rEvolution27

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.
 
I

Ian Collins

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.
 
R

rEvolution27

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");
 
J

John Harrison

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
 
R

rEvolution27

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.
 
J

John Harrison

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').
 
R

rEvolution27

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
 
J

Jim Langston

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;
 
J

John Harrison

Comments below

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
 
O

Old Wolf

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");
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,141
Latest member
BlissKeto
Top