Stroustrup Section 7.10, Exercise 4

Discussion in 'C++' started by arnuld, Nov 5, 2008.

  1. arnuld

    arnuld Guest

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



    --
    www.lispmachine.wordpress.com
    my email is @ the above blog.
    Google Groups is UnBlocked now :)
    arnuld, Nov 5, 2008
    #1
    1. Advertising

  2. 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;
    }



    >
    > ifile.close();
    >
    > return read_success;
    > }
    Michael DOUBEZ, Nov 5, 2008
    #2
    1. Advertising

  3. arnuld

    arnuld Guest

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




    --
    www.lispmachine.wordpress.com
    my email is @ the above blog.
    arnuld, Nov 6, 2008
    #3
  4. arnuld

    arnuld Guest

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



    --
    www.lispmachine.wordpress.com
    my email is @ the above blog.
    arnuld, Nov 6, 2008
    #4
  5. arnuld

    arnuld Guest

    > 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.
    arnuld, Nov 6, 2008
    #5
  6. 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
    Michael DOUBEZ, Nov 6, 2008
    #6
  7. arnuld

    arnuld Guest

    > 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.
    arnuld, Nov 6, 2008
    #7
  8. 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
    Michael DOUBEZ, Nov 6, 2008
    #8
  9. arnuld

    arnuld Guest

    > 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.
    arnuld, Nov 6, 2008
    #9
  10. 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
    Michael DOUBEZ, Nov 6, 2008
    #10
  11. 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
    Erik Wikström, Nov 8, 2008
    #11
    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. arnuld

    Stroustrup 5.9 exercise 6

    arnuld, Nov 8, 2006, in forum: C++
    Replies:
    7
    Views:
    370
    arnuld
    Nov 8, 2006
  2. arnuld
    Replies:
    5
    Views:
    341
    Alf P. Steinbach
    Nov 8, 2006
  3. arnuld
    Replies:
    2
    Views:
    293
    arnuld
    Nov 8, 2006
  4. arnuld
    Replies:
    6
    Views:
    384
    arnuld
    Nov 8, 2006
  5. arnuld

    Stroustrup 5.9 exercise 9

    arnuld, Nov 8, 2006, in forum: C++
    Replies:
    5
    Views:
    388
    Bernd Strieder
    Nov 9, 2006
Loading...

Share This Page