Black magic when using fopen!?

Discussion in 'C++' started by fdm, Oct 2, 2009.

  1. fdm

    fdm Guest

    In a function I call fopen:



    template<class V, class Dt>
    unsigned int LoadFile(std::string & path) {
    std::cout << "path = " << path << std::endl;
    FILE *fptr = fopen(path.c_str(), "rb");
    if (fptr==NULL) {
    std::cout << "file not found!" << path << std::endl;
    }
    ...
    ...
    }



    When I run it I get this:

    path = /home/fdm/test.h2
    file not found!

    fptr is NULL, meaning that it cannot find the file. I have double checked
    that the file exist in this location.

    Now here comes the wierd part. If I manually set the SAME path in the
    function like:



    template<class V, class Dt>
    unsigned int LoadFile(std::string & path) {
    std::cout << "before = " << path << std::endl;
    path = "/home/fdm/test.h2";
    std::cout << "after = " << path << std::endl;
    FILE *fptr = fopen(path.c_str(), "rb");
    if (fptr==NULL) {
    std::cout << "file not found!" << path << std::endl;
    }
    ...
    ...
    }



    I get this:

    before = /home/fdm/test.h2
    after = /home/fdm/test.h2

    and fptr is not NULL (the file is read successfully). But as can be seen
    from the printed messages there is no difference between 'path' before and
    after updating it! So why does it only work when I update 'path' manually in
    the function??

    I get this error on Ubuntu 9.04. If I run it on windows vista 64 bit in
    visual studio it works fine! Any ideas??
     
    fdm, Oct 2, 2009
    #1
    1. Advertising

  2. fdm

    Guest

    On Oct 2, 5:39 pm, "fdm" <> wrote:
    > In a function I call fopen:
    >
    >     template<class V, class Dt>
    >     unsigned int LoadFile(std::string & path) {
    >       std::cout << "path = " << path << std::endl;
    >       FILE *fptr = fopen(path.c_str(), "rb");
    >       if (fptr==NULL) {
    >         std::cout << "file not found!" << path << std::endl;
    >       }
    >         ...
    >         ...
    >     }
    >
    > When I run it I get this:
    >
    >      path = /home/fdm/test.h2
    >      file not found!
    >
    > fptr is NULL, meaning that it cannot find the file. I have double checked
    > that the file exist in this location.
    >
    > Now here comes the wierd part. If I manually set the SAME path in the
    > function like:
    >
    >     template<class V, class Dt>
    >     unsigned int LoadFile(std::string & path) {
    >          std::cout << "before = " << path << std::endl;
    >          path = "/home/fdm/test.h2";
    >          std::cout << "after = " << path << std::endl;
    >          FILE *fptr = fopen(path.c_str(), "rb");
    >          if (fptr==NULL) {
    >            std::cout << "file not found!" << path << std::endl;
    >          }
    >          ...
    >          ...
    >      }
    >
    > I get this:
    >
    >    before = /home/fdm/test.h2
    >    after = /home/fdm/test.h2
    >
    > and fptr is not NULL (the file is read successfully). But as can be seen
    > from the printed messages there is no difference between 'path' before and
    > after updating it! So why does it only work when I update 'path' manually in
    > the function??
    >
    > I get this error on Ubuntu 9.04. If I run it on windows vista 64 bit in
    > visual studio it works fine! Any ideas??


    Perhaps there are trailing unprintable characters in the path string
    passed to your function? Try printing the size of your string.

    HTH
     
    , Oct 2, 2009
    #2
    1. Advertising

  3. fdm

    fdm Guest

    "" <> wrote in message
    news:...
    On Oct 2, 5:39 pm, "fdm" <> wrote:
    > In a function I call fopen:
    >
    > template<class V, class Dt>
    > unsigned int LoadFile(std::string & path) {
    > std::cout << "path = " << path << std::endl;
    > FILE *fptr = fopen(path.c_str(), "rb");
    > if (fptr==NULL) {
    > std::cout << "file not found!" << path << std::endl;
    > }
    > ...
    > ...
    > }
    >
    > When I run it I get this:
    >
    > path = /home/fdm/test.h2
    > file not found!
    >
    > fptr is NULL, meaning that it cannot find the file. I have double checked
    > that the file exist in this location.
    >
    > Now here comes the wierd part. If I manually set the SAME path in the
    > function like:
    >
    > template<class V, class Dt>
    > unsigned int LoadFile(std::string & path) {
    > std::cout << "before = " << path << std::endl;
    > path = "/home/fdm/test.h2";
    > std::cout << "after = " << path << std::endl;
    > FILE *fptr = fopen(path.c_str(), "rb");
    > if (fptr==NULL) {
    > std::cout << "file not found!" << path << std::endl;
    > }
    > ...
    > ...
    > }
    >
    > I get this:
    >
    > before = /home/fdm/test.h2
    > after = /home/fdm/test.h2
    >
    > and fptr is not NULL (the file is read successfully). But as can be seen
    > from the printed messages there is no difference between 'path' before and
    > after updating it! So why does it only work when I update 'path' manually
    > in
    > the function??
    >
    > I get this error on Ubuntu 9.04. If I run it on windows vista 64 bit in
    > visual studio it works fine! Any ideas??


    Perhaps there are trailing unprintable characters in the path string
    passed to your function? Try printing the size of your string.




    Good point and you are right:


    Before:

    pathB size = 78


    After:

    pathA size = 77

    But how do I find out what the last char is? There is no trim function in
    the stl but I have found:

    void trim2(string& str)
    {
    string::size_type pos = str.find_last_not_of(' ');
    if(pos != string::npos) {
    str.erase(pos + 1);
    pos = str.find_first_not_of(' ');
    if(pos != string::npos) str.erase(0, pos);
    }
    else str.erase(str.begin(), str.end());
    }

    But even if I pass my string to this function it still has size 78
    afterwards! Any ideas?
     
    fdm, Oct 2, 2009
    #3
  4. fdm

    Balog Pal Guest

    "fdm" <>
    > In a function I call fopen:
    >
    >
    >
    > template<class V, class Dt>
    > unsigned int LoadFile(std::string & path) {
    > std::cout << "path = " << path << std::endl;
    > FILE *fptr = fopen(path.c_str(), "rb");
    > if (fptr==NULL) {
    > std::cout << "file not found!" << path << std::endl;
    > }
    > ...
    > ...
    > }
    >
    > When I run it I get this:
    >
    > path = /home/fdm/test.h2
    > file not found!

    ....
    > I get this error on Ubuntu 9.04. If I run it on windows vista 64 bit in
    > visual studio it works fine! Any ideas??


    I'd bet you have undefined behavior in your program elsewhere, so the
    string's state is corrupt in the first place or the environment is. When you
    call c_str() the content is gone... that is not supposed to happen.

    Anyway, as first step you may try to output c_str() instead of the string,
    or walk in debugger to inspect its state and what actually happens in
    c_str() and what arrives to fopen().
     
    Balog Pal, Oct 2, 2009
    #4
  5. fdm

    red floyd Guest

    On Oct 2, 3:32 pm, "fdm" <> wrote:
    > "" <> wrote in message
    >
    > news:...
    > On Oct 2, 5:39 pm, "fdm" <> wrote:
    >
    >
    >
    > > In a function I call fopen:

    >
    > > template<class V, class Dt>
    > > unsigned int LoadFile(std::string & path) {
    > > std::cout << "path = " << path << std::endl;
    > > FILE *fptr = fopen(path.c_str(), "rb");
    > > if (fptr==NULL) {
    > > std::cout << "file not found!" << path << std::endl;
    > > }
    > > ...
    > > ...
    > > }

    >
    > > When I run it I get this:

    >
    > > path = /home/fdm/test.h2
    > > file not found!

    >
    > > fptr is NULL, meaning that it cannot find the file. I have double checked
    > > that the file exist in this location.

    >
    > > Now here comes the wierd part. If I manually set the SAME path in the
    > > function like:

    >
    > > template<class V, class Dt>
    > > unsigned int LoadFile(std::string & path) {
    > > std::cout << "before = " << path << std::endl;
    > > path = "/home/fdm/test.h2";
    > > std::cout << "after = " << path << std::endl;
    > > FILE *fptr = fopen(path.c_str(), "rb");
    > > if (fptr==NULL) {
    > > std::cout << "file not found!" << path << std::endl;
    > > }
    > > ...
    > > ...
    > > }

    >
    > > I get this:

    >
    > > before = /home/fdm/test.h2
    > > after = /home/fdm/test.h2

    >
    > > and fptr is not NULL (the file is read successfully). But as can be seen
    > > from the printed messages there is no difference between 'path' before and
    > > after updating it! So why does it only work when I update 'path' manually
    > > in
    > > the function??

    >
    > > I get this error on Ubuntu 9.04. If I run it on windows vista 64 bit in
    > > visual studio it works fine! Any ideas??

    >
    > Perhaps there are trailing unprintable characters in the path string
    > passed to your function?  Try printing the size of your string.
    >
    > Good point and you are right:
    >
    > Before:
    >
    > pathB size = 78
    >
    > After:
    >
    > pathA size = 77
    >
    > But how do I find out what the last char is? There is no trim function in
    > the stl but I have found:

    [redacted]
    >
    > But even if I pass my string to this function it still has size 78
    > afterwards! Any ideas?


    Delimiters!!!!!!

    std::cout << '"' << path << '"' << std::endl;
     
    red floyd, Oct 3, 2009
    #5
  6. fdm

    fdm Guest

    "red floyd" <> wrote in message
    news:...
    On Oct 2, 3:32 pm, "fdm" <> wrote:
    > "" <> wrote in message
    >
    > news:...
    > On Oct 2, 5:39 pm, "fdm" <> wrote:
    >
    >
    >
    > > In a function I call fopen:

    >
    > > template<class V, class Dt>
    > > unsigned int LoadFile(std::string & path) {
    > > std::cout << "path = " << path << std::endl;
    > > FILE *fptr = fopen(path.c_str(), "rb");
    > > if (fptr==NULL) {
    > > std::cout << "file not found!" << path << std::endl;
    > > }
    > > ...
    > > ...
    > > }

    >
    > > When I run it I get this:

    >
    > > path = /home/fdm/test.h2
    > > file not found!

    >
    > > fptr is NULL, meaning that it cannot find the file. I have double
    > > checked
    > > that the file exist in this location.

    >
    > > Now here comes the wierd part. If I manually set the SAME path in the
    > > function like:

    >
    > > template<class V, class Dt>
    > > unsigned int LoadFile(std::string & path) {
    > > std::cout << "before = " << path << std::endl;
    > > path = "/home/fdm/test.h2";
    > > std::cout << "after = " << path << std::endl;
    > > FILE *fptr = fopen(path.c_str(), "rb");
    > > if (fptr==NULL) {
    > > std::cout << "file not found!" << path << std::endl;
    > > }
    > > ...
    > > ...
    > > }

    >
    > > I get this:

    >
    > > before = /home/fdm/test.h2
    > > after = /home/fdm/test.h2

    >
    > > and fptr is not NULL (the file is read successfully). But as can be seen
    > > from the printed messages there is no difference between 'path' before
    > > and
    > > after updating it! So why does it only work when I update 'path'
    > > manually
    > > in
    > > the function??

    >
    > > I get this error on Ubuntu 9.04. If I run it on windows vista 64 bit in
    > > visual studio it works fine! Any ideas??

    >
    > Perhaps there are trailing unprintable characters in the path string
    > passed to your function? Try printing the size of your string.
    >
    > Good point and you are right:
    >
    > Before:
    >
    > pathB size = 78
    >
    > After:
    >
    > pathA size = 77
    >
    > But how do I find out what the last char is? There is no trim function in
    > the stl but I have found:

    [redacted]
    >
    > But even if I pass my string to this function it still has size 78
    > afterwards! Any ideas?


    Delimiters!!!!!!

    std::cout << '"' << path << '"' << std::endl;




    I don't understand is : -> " <- a delimiter? And I still need to make the
    string identical to the manually typed string somehow.
     
    fdm, Oct 3, 2009
    #6
  7. On 3 Ott, 12:41, "fdm" <> wrote:
    > "red floyd" <> wrote in message
    >
    > news:...
    > On Oct 2, 3:32 pm, "fdm" <> wrote:
    >
    >
    >
    > > "" <> wrote in message

    >
    > >news:....
    > > On Oct 2, 5:39 pm, "fdm" <> wrote:

    >
    > > > In a function I call fopen:

    >
    > > > template<class V, class Dt>
    > > > unsigned int LoadFile(std::string & path) {
    > > > std::cout << "path = " << path << std::endl;
    > > > FILE *fptr = fopen(path.c_str(), "rb");
    > > > if (fptr==NULL) {
    > > > std::cout << "file not found!" << path << std::endl;
    > > > }
    > > > ...
    > > > ...
    > > > }

    >
    > > > When I run it I get this:

    >
    > > > path = /home/fdm/test.h2
    > > > file not found!

    >
    > > > fptr is NULL, meaning that it cannot find the file. I have double
    > > > checked
    > > > that the file exist in this location.

    >
    > > > Now here comes the wierd part. If I manually set the SAME path in the
    > > > function like:

    >
    > > > template<class V, class Dt>
    > > > unsigned int LoadFile(std::string & path) {
    > > > std::cout << "before = " << path << std::endl;
    > > > path = "/home/fdm/test.h2";
    > > > std::cout << "after = " << path << std::endl;
    > > > FILE *fptr = fopen(path.c_str(), "rb");
    > > > if (fptr==NULL) {
    > > > std::cout << "file not found!" << path << std::endl;
    > > > }
    > > > ...
    > > > ...
    > > > }

    >
    > > > I get this:

    >
    > > > before = /home/fdm/test.h2
    > > > after = /home/fdm/test.h2

    >
    > > > and fptr is not NULL (the file is read successfully). But as can be seen
    > > > from the printed messages there is no difference between 'path' before
    > > > and
    > > > after updating it! So why does it only work when I update 'path'
    > > > manually
    > > > in
    > > > the function??

    >
    > > > I get this error on Ubuntu 9.04. If I run it on windows vista 64 bit in
    > > > visual studio it works fine! Any ideas??

    >
    > > Perhaps there are trailing unprintable characters in the path string
    > > passed to your function? Try printing the size of your string.

    >
    > > Good point and you are right:

    >
    > > Before:

    >
    > > pathB size = 78

    >
    > > After:

    >
    > > pathA size = 77

    >
    > > But how do I find out what the last char is? There is no trim function in
    > > the stl but I have found:

    > [redacted]
    >
    > > But even if I pass my string to this function it still has size 78
    > > afterwards! Any ideas?

    >
    > Delimiters!!!!!!
    >
    > std::cout << '"' << path << '"' << std::endl;
    >
    > I don't understand is : ->  "  <- a delimiter?


    Yes, it is.

    std::cout << "[" << path << "]" << std::endl;

    is fine too, the point is checking if you're getting what you're
    expecting or not.

    This output is fine:

    [folder/filename.ext]

    these are not:

    [folder/filename.ext ] <- probably a trailing tab character

    [folder/filename.ext
    ] <- probably a new-line and/or a carriage-return trailing character

    > And I still need to make the
    > string identical to the manually typed string somehow.


    The target is that, but the questions to answer should be: "Why am I
    _not_ getting what I expect? Which part of the program is messing up
    the 'path' string?"

    By the way, your quoting is messed up. Fix it for the future.

    Also, why are you using fopen and not filestreams? Just out of
    curiosity.

    --
    Francesco S. Carta, hobbyist
    http://fscode.altervista.org
     
    Francesco S. Carta, Oct 3, 2009
    #7
  8. On 3 Ott, 13:52, "Francesco S. Carta" <> wrote:
    > On 3 Ott, 12:41, "fdm" <> wrote:


    [snip]

    > > I don't understand is : ->  "  <- a delimiter?

    >
    > Yes, it is.
    >
    > std::cout << "[" << path << "]" << std::endl;
    >
    > is fine too, the point is checking if you're getting what you're
    > expecting or not.
    >
    > This output is fine:
    >
    > [folder/filename.ext]
    >
    > these are not:
    >
    > [folder/filename.ext    ] <- probably a trailing tab character
    >
    > [folder/filename.ext
    > ] <- probably a new-line and/or a carriage-return trailing character
    >
    > >                         And I still need to make the
    > > string identical to the manually typed string somehow.

    >
    > The target is that, but the questions to answer should be: "Why am I
    > _not_ getting what I expect? Which part of the program is messing up
    > the 'path' string?"


    Consider also that you might be having a messed up 'path' string from
    starters.
    How are you filling it in first place?

    --
    Francesco S. Carta, hobbyist
    http://fscode.altervista.org
     
    Francesco S. Carta, Oct 3, 2009
    #8
  9. fdm

    LR Guest

    red floyd wrote:
    > On Oct 2, 3:32 pm, "fdm" <> wrote:
    >> "" <> wrote in message


    >> But how do I find out what the last char is? There is no trim function in
    >> the stl but I have found:

    > [redacted]
    >> But even if I pass my string to this function it still has size 78
    >> afterwards! Any ideas?

    >
    > Delimiters!!!!!!
    >
    > std::cout << '"' << path << '"' << std::endl;


    I think that delimiters can be useful, but are sometimes misleading.
    Better to dump the string as octal, hex or decimal and see what's in it.

    This code may be useful as a point of departure. Please watch for any
    portability issues I missed.

    #include <iostream>
    #include <sstream>
    #include <iomanip>
    #include <string>
    #include <limits.h>

    std::string dump(const std::string &s) {
    std::stringstream o;
    o << (unsigned long int)(s.size()) << std::endl;
    o << "*" << s << "*" << std::endl;

    // if the number of bits in char
    // isn't a multiple of 4, fix this
    static const size_t hexWidth = CHAR_BIT/4;
    for(std::string::const_iterator i=s.begin(); i!=s.end(); i++) {
    o
    << std::hex
    << std::setfill('0')
    << std::setw(hexWidth)
    << int(*i)
    << " "
    << std::dec; // not the best place for this
    }
    return o.str();
    }

    int main() {
    const std::string backspace(1,8); // YMMV, this is for ascii
    const std::string nullchar(1,0);
    const std::string hw("hello world");
    const std::string ick = hw + nullchar + backspace;

    std::cout << "hw\n" << dump(hw) << std::endl;
    std::cout << "ick\n" << dump(ick) << std::endl;
    }
    On my computer the output was:
    hw
    11
    *hello world*
    68 65 6c 6c 6f 20 77 6f 72 6c 64
    ick
    13
    *hello world*
    68 65 6c 6c 6f 20 77 6f 72 6c 64 00 08

    LR
     
    LR, Oct 3, 2009
    #9
  10. "" wrote:
    > Perhaps there are trailing unprintable characters in the path string
    > passed to your function? Try printing the size of your string.


    fdm wrote:
    > Good point and you are right:
    >
    >
    > Before:
    >
    > pathB size = 78
    >
    >
    > After:
    >
    > pathA size = 77
    >
    > But how do I find out what the last char is? There is no trim function
    > in the stl but I have found:
    >
    > void trim2(string& str)
    > {
    > string::size_type pos = str.find_last_not_of(' ');
    > if(pos != string::npos) {
    > str.erase(pos + 1);
    > pos = str.find_first_not_of(' ');
    > if(pos != string::npos) str.erase(0, pos);
    > }
    > else str.erase(str.begin(), str.end());
    > }
    >
    > But even if I pass my string to this function it still has size 78
    > afterwards! Any ideas?


    That depends on how do you construct your string. Show us that code.

    But I guess that you put a C-style string into that std::string, and
    those are delimited by a final '\0' character. The standard way to get
    its size is by strlen. You can resize your string using the resize
    member function to this size:

    void trim_cstring(string& str)
    {
    str.resize( strlen(&str[0]) );
    }

    By the way, it is good style to pass variables you don't want to change
    in a function by const reference:

    unsigned int LoadFile(std::string const& path);

    This way, the user of this function knows that you don't change the
    string and can rely on it. Additionally, you can pass a temporary string
    to the function which you can't if the parameter is a non-const reference.

    --
    Thomas
     
    Thomas J. Gritzan, Oct 3, 2009
    #10
  11. fdm

    Balog Pal Guest

    "Thomas J. Gritzan"

    > But I guess that you put a C-style string into that std::string, and
    > those are delimited by a final '\0' character. The standard way to get
    > its size is by strlen. You can resize your string using the resize
    > member function to this size:
    >
    > void trim_cstring(string& str)
    > {
    > str.resize( strlen(&str[0]) );
    > }


    :-(

    operator[] of std::string is there to access individual elements.
    The thing you write has several problems:

    - if string is empty, it is out of bounds access, undefined behavior
    - nothing states that the storage is continous, and the other bytes are
    stored in the following bytes
    - especially nothing states that the string will hold anything but the
    string content's characters -- without terminating 0 that is required by
    strlen()

    If ypu want to call strlen, do it on str.c_str() that is there exactly to
    provide an old C-compatible string.
     
    Balog Pal, Oct 3, 2009
    #11
  12. Balog Pal schrieb:
    > "Thomas J. Gritzan"
    >
    >> But I guess that you put a C-style string into that std::string, and
    >> those are delimited by a final '\0' character. The standard way to get
    >> its size is by strlen. You can resize your string using the resize
    >> member function to this size:
    >>
    >> void trim_cstring(string& str)
    >> {
    >> str.resize( strlen(&str[0]) );
    >> }

    >
    > :-(
    >
    > operator[] of std::string is there to access individual elements.
    > The thing you write has several problems:
    >
    > - if string is empty, it is out of bounds access, undefined behavior


    Correct, but are you sure that calling c_str on an empty string isn't UB?

    > - nothing states that the storage is continous, and the other bytes are
    > stored in the following bytes


    True, but practically, it is, and the next standard guarantees it.

    > - especially nothing states that the string will hold anything but the
    > string content's characters -- without terminating 0 that is required by
    > strlen()


    My point is that the OP did store a C-style string with terminating 0
    and some trailing bytes in the string, so that strlen would calculate
    the C-style substring up to this terminating 0. But c_str would ensure
    that there really is a '\0' somewhere so that calling strlen is correct
    in any way.

    > If ypu want to call strlen, do it on str.c_str() that is there exactly
    > to provide an old C-compatible string.


    Agreed.

    --
    Thomas
     
    Thomas J. Gritzan, Oct 3, 2009
    #12
  13. On 3 Ott, 22:22, "Thomas J. Gritzan" <> wrote:
    > Balog Pal schrieb:
    >
    >
    >
    > > "Thomas J. Gritzan"

    >
    > >> But I guess that you put a C-style string into that std::string, and
    > >> those are delimited by a final '\0' character. The standard way to get
    > >> its size is by strlen. You can resize your string using the resize
    > >> member function to this size:

    >
    > >> void trim_cstring(string& str)
    > >> {
    > >>   str.resize( strlen(&str[0]) );
    > >> }

    >
    > > :-(

    >
    > > operator[] of std::string is there to access individual elements.
    > > The thing you write has several problems:

    >
    > > - if string is empty, it is out of bounds access, undefined behavior

    >
    > Correct, but are you sure that calling c_str on an empty string isn't UB?


    No, it isn't. You should be using c_str() without any kind of worry.
    When the string is empty, c_str() will return a char[1] array
    containing just the null character.

    --
    Francesco S. Carta, hobbyist
    http://fscode.altervista.org
     
    Francesco S. Carta, Oct 3, 2009
    #13
  14. On 3 Ott, 17:05, LR <> wrote:
    > red floyd wrote:
    > > On Oct 2, 3:32 pm, "fdm" <> wrote:
    > >> "" <> wrote in message
    > >> But how do I find out what the last char is? There is no trim function in
    > >> the stl but I have found:

    > > [redacted]
    > >> But even if I pass my string to this function it still has size 78
    > >> afterwards! Any ideas?

    >
    > > Delimiters!!!!!!

    >
    > > std::cout << '"' << path << '"' << std::endl;

    >
    > I think that delimiters can be useful, but are sometimes misleading.
    > Better to dump the string as octal, hex or decimal and see what's in it.


    Very good advice, I overlooked it. Thanks for pointing it out.

    Reading your code with the CHAR_BIT thingie made me also realize that
    I had a misunderstanding about sizeof(char), and I corrected it,
    thanks a lot.

    --
    Francesco S. Carta, hobbyist
    http://fscode.altervista.org
     
    Francesco S. Carta, Oct 3, 2009
    #14
  15. A somewhat refined / improved version of the facilities suggested so
    far by other posters, used to trim strings at the NULL character and
    to inspect them, in general:

    -------
    #include <iostream>
    #include <string>
    #include <sstream>
    #include <limits>
    #include <iomanip>

    void trim_c_str(std::string* str) {
    size_t pos = str->find('\0');
    if (pos != std::string::npos) str->erase(pos);
    }

    void dump_as_unsigned(std::eek:stream& os,
    const std::string& str,
    size_t w = 0,
    const std::string& lead_sep = " ") {
    for (size_t i = 0, e = str.size(); i < e; ++i) {
    os << lead_sep << std::setw(w) << unsigned(str);
    }
    os << std::endl;
    }

    void dump_chars(std::eek:stream& os, const std::string& str, size_t
    spaces = 0) {
    if (spaces) {
    for (size_t i = 0, e = str.size(); i < e; ++i) {
    os << std::string(spaces, ' ') << str;
    }
    } else {
    os << str;
    }
    os << std::endl;
    }

    std::string string_details(const std::string& str) {
    static std::eek:stringstream oss;
    static size_t w = 0;

    if (!w) {
    oss << std::hex << unsigned(std::numeric_limits<char>::max());
    oss << std::setfill('0') << std::uppercase;
    w = oss.str().size();
    }

    oss.str("");
    oss << "---" << std::endl;
    oss << "As string:" << std::endl;
    oss << " \"" << str << "\", ";
    oss << str.size() << " chars" << std::endl;

    dump_chars(oss, str, w);
    dump_as_unsigned(oss, str, w);

    std::string c_str = str.c_str();

    if (c_str != str) {
    oss << std::endl;
    oss << "As c_str():" << std::endl;
    oss << " \"" << c_str << "\", ";
    oss << c_str.size() << " chars" << std::endl;

    dump_chars(oss, c_str, w);
    dump_as_unsigned(oss, c_str, w);

    } else {
    oss << "[ string == c_str(), no NULL characters ]";
    oss << std::endl;
    }
    oss << "---" << std::endl;
    return oss.str();
    }

    int main() {

    std::string s = std::string("Here ->") + '\0' + "<- is NULL";

    std::cout << "Before trimming:" << std::endl;
    std::cout << string_details(s) << std::endl;

    trim_c_str(&s);

    std::cout << "After trimming:" << std::endl;
    std::cout << string_details(s) << std::endl;
    }
    -------

    Output:

    -------
    Before trimming:
    ---
    As string:
    "Here -> <- is NULL", 12 chars
    H e r e - > < - i s N U L L
    48 65 72 65 20 2D 3E 00 3C 2D 20 69 73 20 4E 55 4C 4C

    As c_str():
    "Here ->", 7 chars
    H e r e - >
    48 65 72 65 20 2D 3E
    ---

    After trimming:
    ---
    As string:
    "Here ->", 7 chars
    H e r e - >
    48 65 72 65 20 2D 3E
    [ string == c_str(), no NULL characters ]
    ---
    -------

    [ posted for portability sake, too ]

    --
    Francesco S. Carta, http://fscode.altervista.org
    First time here? Read the 'Welcome' and the 'FAQ'
    Welcome: http://www.slack.net/~shiva/welcome.txt
    C++ FAQ: http://www.parashift.com/c -faq-lite
     
    Francesco S. Carta, Oct 4, 2009
    #15
  16. On 4 Ott, 12:53, "Francesco S. Carta" <> wrote:

    > void trim_c_str(std::string* str) {
    >     size_t pos = str->find('\0');
    >     if (pos != std::string::npos) str->erase(pos);
    >
    > }


    Uhm... I think this is the right occasion to ask for opinions about
    this.

    Here above I'm using a pointer without checking for it being null or
    not.

    Actually, that wasn't a mistake, I really meant to write that.

    But obviously, if a client passes a nullpointer to that function, the
    program crashes - in my view, the problem would be on the client's
    side, but I wonder what's your opinion and eventually the most widely
    used custom.

    Three options:

    -------
    // #1
    void foo(sometype* ptr) {
    /*
    dereference ptr without checking it for being null,
    blame the client for passing a nullpointer
    */
    }

    // #2
    void foo(sometype* ptr) {
    if(ptr) {
    /*
    dereference ptr only if not null,
    forgive the client when passing a nullpointer
    */
    }
    }

    // #3
    void foo(sometype& ref) {
    /*
    force the client to pass a non-const reference
    */
    }
    -------

    Actually, I dislike both option #2 (buggy client calls won't be
    punished) and #3 (client calls will not make it evident that foo can
    modify the passed object).

    I'll be glad to read others' opinions about these points.

    --
    Francesco S. Carta, http://fscode.altervista.org
    First time here? Read the 'Welcome' and the 'FAQ'
    Welcome: http://www.slack.net/~shiva/welcome.txt
    C++ FAQ: http://www.parashift.com/c -faq-lite
     
    Francesco S. Carta, Oct 4, 2009
    #16
  17. fdm

    Bo Persson Guest

    Francesco S. Carta wrote:
    > On 4 Ott, 12:53, "Francesco S. Carta" <> wrote:
    >
    >> void trim_c_str(std::string* str) {
    >> size_t pos = str->find('\0');
    >> if (pos != std::string::npos) str->erase(pos);
    >>
    >> }

    >
    > Uhm... I think this is the right occasion to ask for opinions about
    > this.
    >
    > Here above I'm using a pointer without checking for it being null or
    > not.
    >
    > Actually, that wasn't a mistake, I really meant to write that.
    >
    > But obviously, if a client passes a nullpointer to that function,
    > the program crashes - in my view, the problem would be on the
    > client's side, but I wonder what's your opinion and eventually the
    > most widely used custom.
    >
    > Three options:
    >
    > -------
    > // #1
    > void foo(sometype* ptr) {
    > /*
    > dereference ptr without checking it for being null,
    > blame the client for passing a nullpointer
    > */
    > }
    >
    > // #2
    > void foo(sometype* ptr) {
    > if(ptr) {
    > /*
    > dereference ptr only if not null,
    > forgive the client when passing a nullpointer
    > */
    > }
    > }
    >
    > // #3
    > void foo(sometype& ref) {
    > /*
    > force the client to pass a non-const reference
    > */
    > }
    > -------
    >
    > Actually, I dislike both option #2 (buggy client calls won't be
    > punished) and #3 (client calls will not make it evident that foo can
    > modify the passed object).
    >


    In this case, option 3 solves the problem at compile time, which is an
    advantage. The client must provide a reference.

    It also IS obvious that the function modifies its parameter, if you
    just don't call it foo. The call

    remove_trailing_stuff_from(filename);

    seems like it could modify filename. :)


    Bo Persson
     
    Bo Persson, Oct 4, 2009
    #17
  18. On 4 Ott, 16:52, "Bo Persson" <> wrote:
    > Francesco S. Carta wrote:
    > > On 4 Ott, 12:53, "Francesco S. Carta" <> wrote:

    >
    > >> void trim_c_str(std::string* str) {
    > >> size_t pos = str->find('\0');
    > >> if (pos != std::string::npos) str->erase(pos);

    >
    > >> }

    >
    > > Uhm... I think this is the right occasion to ask for opinions about
    > > this.

    >
    > > Here above I'm using a pointer without checking for it being null or
    > > not.

    >
    > > Actually, that wasn't a mistake, I really meant to write that.

    >
    > > But obviously, if a client passes a nullpointer to that function,
    > > the program crashes - in my view, the problem would be on the
    > > client's side, but I wonder what's your opinion and eventually the
    > > most widely used custom.

    >
    > > Three options:

    >
    > > -------
    > > // #1
    > > void foo(sometype* ptr) {
    > > /*
    > > dereference ptr without checking it for being null,
    > > blame the client for passing a nullpointer
    > > */
    > > }

    >
    > > // #2
    > > void foo(sometype* ptr) {
    > > if(ptr) {
    > > /*
    > > dereference ptr only if not null,
    > > forgive the client when passing a nullpointer
    > > */
    > > }
    > > }

    >
    > > // #3
    > > void foo(sometype& ref) {
    > > /*
    > > force the client to pass a non-const reference
    > > */
    > > }
    > > -------

    >
    > > Actually, I dislike both option #2 (buggy client calls won't be
    > > punished) and #3 (client calls will not make it evident that foo can
    > > modify the passed object).

    >
    > In this case, option 3 solves the problem at compile time, which is an
    > advantage. The client must provide a reference.
    >
    > It also IS obvious that the function modifies its parameter, if you
    > just don't call it foo. The call
    >
    > remove_trailing_stuff_from(filename);
    >
    > seems like it could modify filename. :)


    Even if I fail to see the dereference of an eventual null pointer as a
    problem of my function - that's still a problem of the caller for me -
    I understand your point of view.

    I really like when program details are primarily conveyed by syntax -
    eventually also by naming convention, when appropriate.

    Naming a function as "foo" is obviously silly - 'twas an example.

    The case you proposed is trivial and obviously fine, passing its
    argument by references.

    Also passing streams by reference seems fine, since it seems to be
    common custom.

    I was thinking about multi-argument, somewhat more complex function
    calls.

    Imagine that I have to move some messages from one queue to two other
    queues, depending on some message's attribute.

    I would declare all arguments as pointers and I would call the
    function in this way:

    -------
    dispatch(&msg_queue, &audio_queue, &video_queue);
    -------

    How would you name that function in order to convey the same meaning
    in the function call, that is, that all passed objects could be
    modified by the function?

    OK, maybe that's a silly example, and the variable names are so
    obvious that...
    -------
    dispatch(msg_queue, audio_queue, video_queue);
    -------
    ....would be equally clear, but having the ampersands there in the
    function call seems to me as the best way to express the function's
    behavior.

    Moreover, I was thinking about functions that modify only some of
    their arguments.

    Whatever. Ten heads, ten hats, that's fine, I realize that all of this
    would be strictly tied to project/team conventions.

    --
    Francesco S. Carta, http://fscode.altervista.org
     
    Francesco S. Carta, Oct 4, 2009
    #18
  19. fdm

    Balog Pal Guest

    "Thomas J. Gritzan"
    >>> void trim_cstring(string& str)
    >>> {
    >>> str.resize( strlen(&str[0]) );
    >>> }

    >>
    >> :-(
    >>
    >> operator[] of std::string is there to access individual elements.
    >> The thing you write has several problems:
    >>
    >> - if string is empty, it is out of bounds access, undefined behavior

    >
    > Correct, but are you sure that calling c_str on an empty string isn't UB?


    Yea.

    >> - nothing states that the storage is continous, and the other bytes are
    >> stored in the following bytes

    >
    > True, but practically, it is, and the next standard guarantees it.


    The next standard possibly evolves in that direction, but it was NOT the
    plan in the first place (unlike for std::vector, where the memory req was
    just forgotten in the first standard text and was fixed in TC1). string was
    supposed to work being split in pieces internally.

    >> - especially nothing states that the string will hold anything but the
    >> string content's characters -- without terminating 0 that is required by
    >> strlen()

    >
    > My point is that the OP did store a C-style string with terminating 0


    Maybe he did, it is a legal action for string and can be done easily through
    its interface -- it's even easy to do by using the range constructor. Once
    in the string it can be checked using the legal interface ways, i.e.
    !str.empty() && '0' == *str.back() or strlen(str.c_str()) == str.size() or
    many others already suggested. Taking address of elements in the string is
    simply bad.
     
    Balog Pal, Oct 5, 2009
    #19
    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. Nonee
    Replies:
    2
    Views:
    2,677
    Neredbojias
    Oct 25, 2005
  2. Jan Burgy
    Replies:
    2
    Views:
    614
    Jan Burgy
    Aug 16, 2004
  3. Michael Spencer

    Black Magic - Currying using __get__

    Michael Spencer, Mar 24, 2005, in forum: Python
    Replies:
    0
    Views:
    398
    Michael Spencer
    Mar 24, 2005
  4. Andrew Robert

    regex/lambda black magic

    Andrew Robert, May 25, 2006, in forum: Python
    Replies:
    5
    Views:
    420
    John Machin
    May 25, 2006
  5. Michel Rouzic
    Replies:
    4
    Views:
    1,844
    Michel Rouzic
    Apr 28, 2008
Loading...

Share This Page