[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c++

Stroustrup Section 7.10, Exercise 4

arnuld

11/5/2008 11:49:00 AM

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::ostream, 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;
}



--
www.lispmachine.wordpress.com
my email is @ the above blog.
Google Groups is UnBlocked now :)


10 Answers

Michael DOUBEZ

11/5/2008 1:49:00 PM

0

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::ostream, then I am confused whether it
> will open the file for writing or appending ?.

Do you mean std::ofstream ?
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::ostream, you cannot directly open a file with it but
you can use a filebuf:
std::filebuf fbuf;
fbuf.open(filename,ios::out);
std::ostream 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;
}



>
> ifile.close();
>
> return read_success;
> }

arnuld

11/6/2008 7:16:00 AM

0

> On Wed, 05 Nov 2008 14:48:54 +0100, Michael DOUBEZ wrote:


> 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[i] ) )
{
std::cerr << "error reading file: "
<< argv[i]
<< 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::ostream_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;




--
www.lispmachine.wordpress.com
my email is @ the above blog.


arnuld

11/6/2008 7:34:00 AM

0

> On Wed, 05 Nov 2008 14:48:54 +0100, Michael DOUBEZ wrote:

> 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[i] ) )
{
std::cerr << "\n\n-------------------error reading file: "
<< argv[i]
<< " --------------------------------\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::ostream_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 ?



--
www.lispmachine.wordpress.com
my email is @ the above blog.


arnuld

11/6/2008 7:45:00 AM

0

> On Thu, 06 Nov 2008 12:34:06 +0500, arnuld wrote:


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



--
www.lispmachine.wordpress.com
my email is @ the above blog.


Michael DOUBEZ

11/6/2008 8:08:00 AM

0

arnuld a écrit :
>> On Thu, 06 Nov 2008 12:34:06 +0500, arnuld wrote:
>
>
>> 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 ?

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

--
Michael

arnuld

11/6/2008 8:19:00 AM

0

> On Thu, 06 Nov 2008 09:08:07 +0100, Michael DOUBEZ wrote:


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


--
www.lispmachine.wordpress.com
my email is @ the above blog.


Michael DOUBEZ

11/6/2008 8:39:00 AM

0

arnuld a écrit :
>> On Thu, 06 Nov 2008 09:08:07 +0100, Michael DOUBEZ wrote:
>
>
>> 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.

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;

--
Michael

arnuld

11/6/2008 9:49:00 AM

0

> On Thu, 06 Nov 2008 09:38:50 +0100, Michael DOUBEZ wrote:


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




--
www.lispmachine.wordpress.com
my email is @ the above blog.


Michael DOUBEZ

11/6/2008 11:21:00 AM

0

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

--
Michael

Erik Wikström

11/8/2008 1:01:00 PM

0

On 2008-11-05 12:48, arnuld wrote:
> 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] ) )

--
Erik Wikström