Help with file writing please

J

james

Hi,

I'm new to C++, and coming from a dynamically-typed language, I'm
finding the data types difficult. My goal at the moment is to append
a string that is typed as a command line argument into the end of a
file, and I'm wondering if somebody could point me in the right
direction. At the moment, I can open the file and write a hard-coded
string using:

#include <fstream.h>
#include <iostream.h>
#include <cstdlib>
int main()
{
fstream fout("./output.txt",ios::eek:ut);
fout<<"String";
fout.close();
}

I am using the g++ compiler under Debian to compile.

All help is appreciated,

--James.
 
A

Alf P. Steinbach

* (e-mail address removed):
Hi,

I'm new to C++, and coming from a dynamically-typed language, I'm
finding the data types difficult. My goal at the moment is to append
a string that is typed as a command line argument into the end of a
file, and I'm wondering if somebody could point me in the right
direction. At the moment, I can open the file and write a hard-coded
string using:

#include <fstream.h>
#include <iostream.h>

The above are pre-standard headers. Some modern compilers don't provide
them. Instead, use

#include <fstream>
#include <cstdlib>
int main()

Here you can declare arguments:

int main( int nArgs, char* args[] )

The argument strings are non-const because 'main' was inherited from C,
but that doesn't mean you can modify them.

The best thing you can do, as a newbie, is to immediately convert the
'main' arguments to a std::vector of std::string, and call a
C++-oriented main function (I usually call it 'cppMain'):

#include <cstddef> // std::size_t
#include <string> // std::string
#include <vector> // std::vector

// Your additional headers, e.g.
#include <fstream>
#include <iostream>


typedef std::vector<std::string> StringVector;

void cppMain( StringVector const& arguments )
{
using namespace std;

// Your code goes here, e.g.
for( size_t i = 0; i < arguments.size(); ++i )
{
cout << arguments.at( i ) << endl;
}
}

int main( int nArgs, char* args[] )
{
// This can be elaborated on, but as a minimum:
cppMain( StringVector( args, args + nArgs );
}

{
fstream fout("./output.txt",ios::eek:ut);

This code would go in 'cppMain' above.

Since you're trying to append text, it would make sense to use the
append mode.

Also, since you're only writing to the stream, it would probably be
better to use std::eek:fstream instead of the more general std::fstream.

fout<<"String";
fout.close();
}

I am using the g++ compiler under Debian to compile.

All help is appreciated,

Cheers, & hth.,

- Alf
 
J

Juha Nieminen

Alf said:
#include <cstddef> // std::size_t
#include <string> // std::string
#include <vector> // std::vector

// Your additional headers, e.g.
#include <fstream>
#include <iostream>


typedef std::vector<std::string> StringVector;

void cppMain( StringVector const& arguments )
{
using namespace std;

// Your code goes here, e.g.
for( size_t i = 0; i < arguments.size(); ++i )
{
cout << arguments.at( i ) << endl;
}
}

int main( int nArgs, char* args[] )
{
// This can be elaborated on, but as a minimum:
cppMain( StringVector( args, args + nArgs );
}

Or he could just do what he wanted to do, ie. append the first
command-line argument to a file:

#include <fstream>

int main(int argc, char* argv[])
{
if(argc > 1)
{
std::eek:fstream os("file.txt", std::ios::app);
os << argv[1];
}
}
 
A

Alf P. Steinbach

* Juha Nieminen:
Alf said:
#include <cstddef> // std::size_t
#include <string> // std::string
#include <vector> // std::vector

// Your additional headers, e.g.
#include <fstream>
#include <iostream>


typedef std::vector<std::string> StringVector;

void cppMain( StringVector const& arguments )
{
using namespace std;

// Your code goes here, e.g.
for( size_t i = 0; i < arguments.size(); ++i )
{
cout << arguments.at( i ) << endl;
}
}

int main( int nArgs, char* args[] )
{
// This can be elaborated on, but as a minimum:
cppMain( StringVector( args, args + nArgs );
}

Or he could just do what he wanted to do, ie. append the first
command-line argument to a file:

#include <fstream>

int main(int argc, char* argv[])
{
if(argc > 1)
{
std::eek:fstream os("file.txt", std::ios::app);
os << argv[1];
}
}

That's not a good idea. It doesn't help the OP learn anything, it
doesn't help the OP avoid other problems, and it doesn't show that you
know anything (the programming is trivial). It only shows that you
haven't read the "Give a man a fish" quote a sufficient number of times;
I leave finding that quote as an exercice -- for you.


Cheers,

- Alf

"Never underestimate stupidity" - Heinlein
 
J

james

* Juha Nieminen:


Alf said:
#include <cstddef> // std::size_t
#include <string> // std::string
#include <vector> // std::vector
// Your additional headers, e.g.
#include <fstream>
#include <iostream>
typedef std::vector<std::string> StringVector;
void cppMain( StringVector const& arguments )
{
using namespace std;
// Your code goes here, e.g.
for( size_t i = 0; i < arguments.size(); ++i )
{
cout << arguments.at( i ) << endl;
}
}
int main( int nArgs, char* args[] )
{
// This can be elaborated on, but as a minimum:
cppMain( StringVector( args, args + nArgs );
}
Or he could just do what he wanted to do, ie. append the first
command-line argument to a file:
#include <fstream>
int main(int argc, char* argv[])
{
if(argc > 1)
{
std::eek:fstream os("file.txt", std::ios::app);
os << argv[1];
}
}

That's not a good idea. It doesn't help the OP learn anything, it
doesn't help the OP avoid other problems, and it doesn't show that you
know anything (the programming is trivial). It only shows that you
haven't read the "Give a man a fish" quote a sufficient number of times;
I leave finding that quote as an exercice -- for you.

Cheers,

- Alf

"Never underestimate stupidity" - Heinlein

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Thanks for all of your help, everything works fine :)

--James.
 
A

Alf P. Steinbach

* Rolf Magnus:
Alf said:
#include <cstdlib>
int main()
Here you can declare arguments:

int main( int nArgs, char* args[] )

The argument strings are non-const because 'main' was inherited from C,
but that doesn't mean you can modify them.

Actually, I'd say it does mean exactly that.

No. The C standard states explicitly that they can be modified. The
C++ standard includes the description from the C standard (rephrased),
adding a number of requirements on 'main' not present in C, but
/omitting/ the statement that the arguments can be modified.

Short of it: C++ main is functionally different from C main, but has the
same signature; in the C standard that signature alone was not
sufficient to determine that arguments could be modified; in C++ it
isn't sufficient; and the C++ standard omits the statement that the
arguments can be modified.

From a C++ point of view there's therefore no guarantee that they can
be modified.

Cheers,

- Alf
 
R

Rolf Magnus

Alf said:
* Rolf Magnus:
Alf said:
#include <cstdlib>
int main()
Here you can declare arguments:

int main( int nArgs, char* args[] )

The argument strings are non-const because 'main' was inherited from C,
but that doesn't mean you can modify them.

Actually, I'd say it does mean exactly that.

No. The C standard states explicitly that they can be modified. The
C++ standard includes the description from the C standard (rephrased),
adding a number of requirements on 'main' not present in C, but
/omitting/ the statement that the arguments can be modified.

I'm wondering why that was omitted. The C++ standard doesn't say the
arguments can't be modified either. It might just have been forgotten. If
the intent really was just to give no guaranteed, the standard should IMO
mention explicitly that this is implementation-defined.
Modifying argc and argv seems to me to be done quite often in C as well as
in C++.
 
J

James Kanze

Alf said:
* Rolf Magnus:
Alf P. Steinbach wrote:
#include <cstdlib>
int main()
Here you can declare arguments:
int main( int nArgs, char* args[] )

Just curious, but is there any reason for not using the
"traditional" names, argc and argv. (I'm not saying that
they're good names, but they're what most experienced
programmers expect. It's a self perpetuating tradition.)

Which would most logically be interpreted as meaning that you
can modify them.
I'm wondering why that was omitted. The C++ standard doesn't
say the arguments can't be modified either. It might just have
been forgotten. If the intent really was just to give no
guaranteed, the standard should IMO mention explicitly that
this is implementation-defined. Modifying argc and argv seems
to me to be done quite often in C as well as in C++.

A lot of things that are done quite often aren't legal.
According to the C standard, modifying the actual array of
pointers is undefined behavior (although I've also seen it done
a lot). You are allowed to modify the strings themselves,
however. (But about the only time I've seen this done is when
they contained a password. On older Unix systems, anyone
invoking ps could see the contents of your argument vector in
memory, so if it contained a password, you overwrote it as soon
as possible. On modern Unix, there's no point, because what
anyone can see is a copy of the data that was used to invoke the
program. Overwriting no longer hides it.)
 
R

Rolf Magnus

James said:
According to the C standard, modifying the actual array of
pointers is undefined behavior (although I've also seen it done
a lot).

Where does it say that?
 
J

James Kanze

Where does it say that?

§5.1.2.2.1/2, last bullet. It actually says the opposite: that
you can modify the arguments themselves (argc and argv), and the
strings pointed to by the argv array. Which leaves the argv
array itself which you're not supposed to modify. (Strictly
speaking, the standard doesn't say what happens if you modify
it, so the results are undefined behavior.)

The rationale, I believe, is that some implementations need
these values in order to free memory at program end. (I'm not
really convinced, but I seem to recall having read that
somewhere.)
 
R

Rolf Magnus

James said:
§5.1.2.2.1/2, last bullet. It actually says the opposite: that
you can modify the arguments themselves (argc and argv), and the
strings pointed to by the argv array. Which leaves the argv
array itself which you're not supposed to modify. (Strictly
speaking, the standard doesn't say what happens if you modify
it, so the results are undefined behavior.)

Well, I thought that with "argv" it just meant the argv array. I see no
reason to explicitly state that argv itself can be modified. After all,
it's just a function parameter as any other, and it's not const. So why
should it not be modifiable?
However, since the standard also mentions argc, I see that this is really
about the parameters themselves.
 
J

James Kanze

Well, I thought that with "argv" it just meant the argv array. I see no
reason to explicitly state that argv itself can be modified. After all,
it's just a function parameter as any other, and it's not const. So why
should it not be modifiable?
However, since the standard also mentions argc, I see that this is really
about the parameters themselves.

Yeh. I find it sort of wierd myself. As you say, there's no
need to talk about the arguments themselves; they're really
local variables. As for the rest, I'd say that either you can't
modify anything (and the absence of const is due to historical
reasons---the actual declaration should be char const* const*
argv), or you can modify everything (which corresponds to the
actual declaration char**). As it is, the rules correspond to a
declaration char* const*, which seems strange to me.

I might add that the idiom I'd always seen in pre-standard C for
parsing the arguments was something like:

int newCount = 1 ;
for ( int i = 1 ; i < argc ; ++ i ) {
if ( isAnOption( argv[ i ] ) ) {
// set option...
} else {
argv[ newCount ++ ] = argv[ i ] ;
}
}
argc = newCount ;

Which of course, modifies what you're not allowed to modify, and
doesn't modify what you are allowed to modify.
 

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,598
Members
45,144
Latest member
KetoBaseReviews
Top