Stroustrup Section 7.10, Exercise 4

A

arnuld

This one works to seem fine. Can I make this program better ?

1) the use of get(ch) function was inspired from Stroustrup 21.5.1, page
number 638.
2) I see, when you create an object of std::ifstream while passing a
pointer to it, it automatically opens the file.

3) If I open a file using std::eek:stream, then I am confused whether it
will open the file for writing or appending ?.



/* Section 7.10: Exercise 4
*
* Write a program that reads arbitrary number of files (whose names are
* given as command-line arguments) and writes them to one after another
* on std::cout.
*
* My view: It feels like UNIX cat
*
* VERSION: 1.0
*
*/

#include <iostream>
#include <cstdlib>
#include <fstream>
#include <algorithm>
#include <iterator>


int print_file( char* );


int main(int argc, char* argv[] )
{
if( 1 == argc )
{
std::cerr << "No Input File\n";
exit( EXIT_FAILURE );
}


int file_count = (argc - 1);
int idx = 1;
while( file_count-- )
{
if( print_file( argv[idx] ) )
{
std::cerr << "error reading file: "
<< argv[idx]
<< std::endl;
}

++idx;
}


return 0;
}




int print_file( char* pc )
{
const int read_success = 0;
const int read_failure = 1;

std::ifstream ifile(pc);

if( (!ifile) )
{
ifile.close();
return read_failure;
}

char ch;
while( ifile.get(ch) )
{
std::cout << ch;
}

ifile.close();

return read_success;
}
 
M

Michael DOUBEZ

arnuld a écrit :
This one works to seem fine. Can I make this program better ?

1) the use of get(ch) function was inspired from Stroustrup 21.5.1, page
number 638.

You can also use std::copy with istream_ierator/ostream_iterator.
There is also the usage of rdbuf().
2) I see, when you create an object of std::ifstream while passing a
pointer to it, it automatically opens the file.

Yes and since it is in a function you could also omit closing it since
it is closed on destruction.
3) If I open a file using std::eek:stream, then I am confused whether it
will open the file for writing or appending ?.

Do you mean std::eek:fstream ?
Is so, the default is opened in write mode at the beginning of the file;
there is a second parameter you can specify to open in append mode.
There are other flags.

If you mean std::eek:stream, you cannot directly open a file with it but
you can use a filebuf:
std::filebuf fbuf;
fbuf.open(filename,ios::eek:ut);
std::eek:stream os(&fbuf);

//now os will write into the file
/* Section 7.10: Exercise 4
*
* Write a program that reads arbitrary number of files (whose names are
* given as command-line arguments) and writes them to one after another
* on std::cout.
*
* My view: It feels like UNIX cat
*
* VERSION: 1.0
*
*/

#include <iostream>
#include <cstdlib>
#include <fstream>
#include <algorithm>
#include <iterator>


int print_file( char* );

I suppose you don't intend to modify the filename; use const-correctness
specifiers:

int print_file( const char* );
int main(int argc, char* argv[] )
{
if( 1 == argc )
{
std::cerr << "No Input File\n";
exit( EXIT_FAILURE );
}


int file_count = (argc - 1);
int idx = 1;
while( file_count-- )

Decrementing the number of file and incrementing an index looks clumsy
and prone to error. I'd rather use a for loop:
for(int idx=1;idx<argc;++idx)

For clarity, use a constant name:
char const * const filename=argv[idx];

And use this name hereafter instead of argv[idx].
if( print_file( argv[idx] ) )
{
std::cerr << "error reading file: "
<< argv[idx]
<< std::endl;
}

++idx;
}


return 0;

To be consistent with your EXIT_FAILURE:

return EXIT_SUCCESS;

}




int print_file( char* pc )

int print_file( const char* pc )
{
const int read_success = 0;
const int read_failure = 1;

std::ifstream ifile(pc);

if( (!ifile) )
{
ifile.close();
return read_failure;
}

char ch;
while( ifile.get(ch) )
{
std::cout << ch;
}

There is a trick to output a sink into another:

if(!std::cout<<ifile.rdbuf())
{
return read_failure;
}
 
A

arnuld

You can also use std::copy with istream_ierator/ostream_iterator.
There is also the usage of rdbuf().


std::istream_iterator is what I wanted to use but I am getting lots of
garbage gets printed along with the file contents. See here is a file
which contains only one word: comp.lang.c++ and see how much garbage is
getting printed. 2nd, is it a god idea to put a for loop in main ?



/* Section 7.10: Exercise 4
*
* Write a program that reads arbitrary number of files (whose names are
* given as command-line arguments) and writes them to one after another
* on std::cout.
*
* My view: It feels like UNIX cat
*
* VERSION: 1.1
*
*/

#include <iostream>
#include <cstdlib>
#include <fstream>
#include <iterator>

int print_file( const char* );


int main(int argc, char* argv[] )
{
if( 1 == argc )
{
std::cerr << "No Input File\n";
exit( EXIT_FAILURE );
}


for( int i = 0; i != argc; ++i )
{
if( print_file( argv ) )
{
std::cerr << "error reading file: "
<< argv
<< std::endl;
}
}


return 0;
}



int print_file( const char* pc )
{
const int read_success = 0;
const int read_failure = 1;

std::ifstream ifile(pc);

if( (!ifile) ) return read_failure;

copy( std::istream_iterator<char>(ifile), std::istream_iterator<char>(),
std::eek:stream_iterator<char>(std::cout,"") );

// we don't need to close the file because the destructor for ifstream
// will automatically do it.
return read_success;
}


=================== OUTPUT =============================
[arnuld@dune cpp]$ g++4 -ansi -pedantic -Wall -Wextra 07-10_04.cpp
[arnuld@dune cpp]$ ./a.out
No Input File
[arnuld@dune cpp]$ ./a.out test.txt
44QÃ¥td/lib/ld-linux.so.2GNU


^[[?1;2c
)¼Ãð^[[?1;2cAÂEK<ÊHÃgÃORSÙ2¹XLð÷ Û=p

... LOTS OF GARBAGE SNIPPED.....
Ãñÿ
R
ñÿ'À
ºñÿÙ!ñÿ(>ñÿC¹ñÿn}LÅû char_traitsIcEERSt13basic_InitD1Ev@@
^[[?1;2c^[[?1;2c^[[?1;2c^[[?1;2c^[[?1;2c^[[?1;2c[arnuld@dune cpp]$
1;2c1;2c1;2c1;2c1;2c1;2c1;2c1;2c1;2c1;2c1;2c<1;2c1;2c1;2c1;2c1;2c1;2c1;2c1;2c1;2c1;
 
A

arnuld

You can also use std::copy with istream_ierator/ostream_iterator.
There is also the usage of rdbuf().

Here is what I am getting:

/* Section 7.10: Exercise 4
*
* Write a program that reads arbitrary number of files (whose names are
* given as command-line arguments) and writes them to one after another
* on std::cout.
*
* My view: It feels like UNIX cat
*
* VERSION: 1.2
*
*/

#include <iostream>
#include <cstdlib>
#include <fstream>
#include <iterator>

int print_file( const char* );


int main(int argc, char* argv[] )
{
if( 1 == argc )
{
std::cerr << "No Input File\n";
exit( EXIT_FAILURE );
}


for( int i = 1; i <= argc; ++i )
{
if( print_file( argv ) )
{
std::cerr << "\n\n-------------------error reading file: "
<< argv
<< " --------------------------------\n"
<< std::endl;
}
}

return 0;
}


int print_file( const char* pc )
{
const int read_success = 0;
const int read_failure = 1;

std::ifstream ifile(pc);

if( (!ifile) ) return read_failure;

copy( std::istream_iterator<std::string>(ifile), std::istream_iterator<std::string>(),
std::eek:stream_iterator<std::string>(std::cout," ") );

// we don't need to close the file because the destructor for ifstream
// will automatically do it.
return read_success;
}


========================= OUTPUT ===============================
[arnuld@dune cpp]$ g++4 -ansi -pedantic -Wall -Wextra 07-10_04.cpp
[arnuld@dune cpp]$ ./a.out test.txt


-------------------error reading file: comp.alng.c++ [arnuld@dune cpp]$


Why it is printing error reading file always ?


2nd, even if it is printing the error by some program mistake then why
it not full error, why only half error message ?
 
A

arnuld

for( int i = 1; i <= argc; ++i )

This is the source of my all frustration. It should be < not <= :-\ . I
still have one question , using:

std::stream_terator<char>(ifile)

kills the formatting of the output. I mean the original file and output
are different in formatting but with:

while( ifile.get(ch) ) std::cout << ch;

the formatting remains the same. How can I keep formatting same with
istream_iterator ?
 
M

Michael DOUBEZ

arnuld a écrit :
This is the source of my all frustration. It should be < not <= :-\ . I
still have one question , using:

std::stream_terator<char>(ifile)

kills the formatting of the output. I mean the original file and output
are different in formatting but with:

while( ifile.get(ch) ) std::cout << ch;

the formatting remains the same. How can I keep formatting same with
istream_iterator ?

You need to read the white spaces; insert the following before copying:
ifile.unsetf(std::ios_base::skipws);
 
A

arnuld

You need to read the white spaces; insert the following before copying:
ifile.unsetf(std::ios_base::skipws);

skipws means skip the white space (or don't read it) but you say with it
it will read the white space. So I am little confused and what unsetf is ?

Program is working fine though.
 
M

Michael DOUBEZ

arnuld a écrit :
skipws means skip the white space (or don't read it) but you say with it
it will read the white space.

Yes but you unset it; unsetf remove the format flags specified in
parameters. In this case, it will remove the flag telling the stream to
skip whitespaces.
So I am little confused and what unsetf is ?

It is equivalent to:
char c;
ifile>>noskiws>>c;
 
A

arnuld

Yes but you unset it; unsetf remove the format flags specified in
parameters. In this case, it will remove the flag telling the stream to
skip whitespaces.

okay . I understand it now :)

It is equivalent to:
char c;
ifile>>noskiws>>c;


Just a question. Why std::istream_iterator is created with an intention to
skip whitespace . Some specific reason ?
 
M

Michael DOUBEZ

arnuld a écrit :
[snip]
Just a question. Why std::istream_iterator is created with an intention to
skip whitespace . Some specific reason ?

It is not istream_iterator but istream that, by default, skip whitespaces.
The reason is, I guess, that whitespaces usually separate entities
(number, string, ...) and it makes sense to activate it for formatted
input (reading a list of integers by example).
 
E

Erik Wikström

This one works to seem fine. Can I make this program better ?
int print_file( char* pc )
{
const int read_success = 0;
const int read_failure = 1;

I would declare those constants outside the function so that whoever
calls print_file can use them to test for success or not:

if( read_success == print_file( argv[idx] ) )
 

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

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,900
Latest member
Nell636132

Latest Threads

Top