Weird sprintf behavior

Discussion in 'C Programming' started by Xcriber51, Nov 10, 2007.

  1. Xcriber51

    Xcriber51 Guest

    Hi

    The idiom of updating a value by adding something to it is so common that
    some programming languages support it at the level of strings, such as;

    s = "_";
    s = s + "c"; // s == "_c"
    s = s + "o"; // s == "_co"

    etc.

    C, being more "honest" (or, if you're unable to appreciate that, more
    "cumbersome") on strings, doesn't provide such a facility. So, I'm trying
    to emulate it by using the "sprintf" standard library function. (Original
    idea, I know.) But it isn't behaving as expected.

    Consider the following routine:

    void _concat()
    {
    char *s;

    s = "_";

    sprintf(s,"%s%c",s,'c');
    sprintf(s,"%s%c",s,'o');
    sprintf(s,"%s%c",s,'n');
    sprintf(s,"%s%c",s,'c');
    sprintf(s,"%s%c",s,'a');
    sprintf(s,"%s%c",s,'t');

    printf("%s\n",s);

    s = "t";

    sprintf(s,"%c%s",'a',s);
    sprintf(s,"%c%s",'c',s);
    sprintf(s,"%c%s",'n',s);
    sprintf(s,"%c%s",'o',s);
    sprintf(s,"%c%s",'c',s);
    sprintf(s,"%c%s",'_',s);

    printf("%s\n",s);
    }

    Here, the first round of calls prints "_concat", as expected. The second,
    however, outputs "_______".

    Why?

    Please keep it short, and I'm not interested in suggestions for
    alternatives. Just a technical reply on why switching the place of the
    format specifiers for character and string yields this asymmetrical
    result.

    Thanks!


    -- K

    --
    Message posted using http://www.talkaboutprogramming.com/group/comp.lang.c/
    More information at http://www.talkaboutprogramming.com/faq.html
    Xcriber51, Nov 10, 2007
    #1
    1. Advertising

  2. Xcriber51

    Guest

    On 10 Nov, 18:40, "Xcriber51" <> wrote:
    > void _concat()
    > {
    > char *s;
    >
    > s = "_";
    >
    > sprintf(s,"%s%c",s,'c');
    > sprintf(s,"%s%c",s,'o');
    > sprintf(s,"%s%c",s,'n');
    > sprintf(s,"%s%c",s,'c');
    > sprintf(s,"%s%c",s,'a');
    > sprintf(s,"%s%c",s,'t');
    >
    > printf("%s\n",s);
    >
    > s = "t";
    >
    > sprintf(s,"%c%s",'a',s);
    > sprintf(s,"%c%s",'c',s);
    > sprintf(s,"%c%s",'n',s);
    > sprintf(s,"%c%s",'o',s);
    > sprintf(s,"%c%s",'c',s);
    > sprintf(s,"%c%s",'_',s);
    >
    > printf("%s\n",s);
    >
    > }


    A couple of problems here. Firstly, if you're going to create a string
    you need somewhere to put it. Here, "s" only has space for one
    character. And writing to string constants may go wrong. However,
    neither of these seems to have gone wrong for you yet...

    The second problem is that you are modifying the string while you read
    it, and this seems to be why the second version is going wrong. If s
    contains, for example, "concat", and you modify it by putting a "_" at
    the beginning, followed by the first letter of s, followed by the
    second letter of s, etc etc, then the result will be "_" followed by
    the first character of s (was a "c" but we've just turned it into a
    "_") followed by the second character of s (was an "o" but we've just
    turned that one into a "_" too) followed by ... well, you get the
    idea.

    > Please keep it short, and I'm not interested in


    strcat

    Hope that helps.
    Paul.
    , Nov 10, 2007
    #2
    1. Advertising

  3. Xcriber51 said:

    <snip>

    > sprintf(s,"%c%s",'_',s);
    >
    > printf("%s\n",s);
    > }
    >
    > Here, the first round of calls prints "_concat", as expected. The second,
    > however, outputs "_______".
    >
    > Why?
    >
    > Please keep it short,


    7.19.6.6(2)

    --
    Richard Heathfield <http://www.cpax.org.uk>
    Email: -http://www. +rjh@
    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
    "Usenet is a strange place" - dmr 29 July 1999
    Richard Heathfield, Nov 10, 2007
    #3
  4. Xcriber51

    Xcriber51 Guest

    Xcriber51, Nov 10, 2007
    #4
  5. Richard Heathfield schrieb:

    >> Please keep it short,

    >
    > 7.19.6.6(2)


    Great answer ;-)

    You don't happen to have a link where the whole C99-standard can be
    found? I googled, but found nothing. Maybe the ANSI wants money for that?

    Greetings,
    Johannes

    --
    "PS: Ein Realname wäre nett. Ich selbst nutze nur keinen, weil mich die
    meisten hier bereits mit Namen kennen." -- Markus Gronotte aka "Makus"
    aka "Kosst Amojan" aka "maqqusz" in de.sci.electronics
    <45608268$0$5719$-online.net>
    Johannes Bauer, Nov 10, 2007
    #5
  6. Johannes Bauer said:

    > Richard Heathfield schrieb:
    >
    >>> Please keep it short,

    >>
    >> 7.19.6.6(2)

    >
    > Great answer ;-)
    >
    > You don't happen to have a link where the whole C99-standard can be
    > found? I googled, but found nothing. Maybe the ANSI wants money for that?


    For the "Real Thing" so-called, yes, they want your plastic.

    But the latest full discussion draft, n1256.pdf IIRC, will almost certainly
    serve your needs (provided you don't get into a fight with Chris Hills),
    and can be downloaded for free from
    http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf

    --
    Richard Heathfield <http://www.cpax.org.uk>
    Email: -http://www. +rjh@
    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
    "Usenet is a strange place" - dmr 29 July 1999
    Richard Heathfield, Nov 10, 2007
    #6
  7. Richard Heathfield schrieb:

    > For the "Real Thing" so-called, yes, they want your plastic.


    Thought so... :-/

    > http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf


    ....but this seems pretty sufficient for many interesting questions.

    Thanks a lot,
    Johannes

    --
    "PS: Ein Realname wäre nett. Ich selbst nutze nur keinen, weil mich die
    meisten hier bereits mit Namen kennen." -- Markus Gronotte aka "Makus"
    aka "Kosst Amojan" aka "maqqusz" in de.sci.electronics
    <45608268$0$5719$-online.net>
    Johannes Bauer, Nov 10, 2007
    #7
  8. Xcriber51

    Chris Dollin Guest

    Xcriber51 wrote:

    > Thanks, both. No more replies needed.


    I expect you'll get some, though, propagation delays &co
    being what they are, and people wanting to have their
    say.

    --
    Example Hedgehog
    Notmuchhere: http://www.electrichedgehog.net/
    Chris Dollin, Nov 10, 2007
    #8
  9. Johannes Bauer <> writes:
    > Richard Heathfield schrieb:
    >>> Please keep it short,

    >>
    >> 7.19.6.6(2)

    >
    > Great answer ;-)
    >
    > You don't happen to have a link where the whole C99-standard can be
    > found? I googled, but found nothing. Maybe the ANSI wants money for that?


    Yes, ANSI (or your national standard body, if you're not in the US)
    wants money for the actual standard, which is currently C99. You can
    get a copy of C99 for about $18 (or did it go up?), or a paper copy
    for a couple hundred or so.

    Personally, I find the PDF standard to be well worth the money.

    But the latest draft, which incorporates the C99 standard plus three
    Technical Corrigenda, is a free download at
    <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf>. I
    actually use n1256 rather than the official standard most of the time.
    All changes relative to the standard are marked with change bars.

    The Technical Corrigenda themselves are also available. I think ANSI
    has the first two for free, and I *think* the committee site
    (.../wg14/...) has all three. These are short documents with just the
    changes from C99. In combination with the standard itself, they're
    probably more "offical" than n1256, but considerably more unwieldy.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Looking for software development work in the San Diego area.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Nov 10, 2007
    #9
  10. On Sat, 10 Nov 2007 12:13:12 -0800, Keith Thompson wrote:
    > Yes, ANSI (or your national standard body, if you're not in the US)
    > wants money for the actual standard, which is currently C99. You can
    > get a copy of C99 for about $18 (or did it go up?),


    It did, but at $30 it's still quite a bit cheaper than the alternatives.
    =?iso-2022-kr?q?=1B=24=29CHarald_van_D=0E=29=26=0F, Nov 10, 2007
    #10
  11. Xcriber51

    CBFalconer Guest

    Xcriber51 wrote:
    >

    .... snip ...
    >
    > C, being more "honest" (or, if you're unable to appreciate that,
    > more "cumbersome") on strings, doesn't provide such a facility.
    > So, I'm trying to emulate it by using the "sprintf" standard
    > library function. (Original idea, I know.) But it isn't behaving
    > as expected.
    >
    > Consider the following routine:
    >
    > void _concat()
    > {
    > char *s;
    >
    > s = "_";


    s has been set to point to a constant string. That same constant
    string may be used other places. Therefore it is NOT writable.
    Any attempt to write to it results in undefined behaviour. You
    could use:

    void concat() { /* use of leading _ is forbidden */

    static char s[MAX];

    strcpy(s, "_"); /* to make it writeable */


    --
    Chuck F (cbfalconer at maineline dot net)
    <http://cbfalconer.home.att.net>
    Try the download section.



    --
    Posted via a free Usenet account from http://www.teranews.com
    CBFalconer, Nov 11, 2007
    #11
  12. Xcriber51

    CBFalconer Guest

    Johannes Bauer wrote:
    >
    > You don't happen to have a link where the whole C99-standard can
    > be found? I googled, but found nothing. Maybe the ANSI wants money
    > for that?


    You can get the text version of N869, the last draft before C99 was
    published, slightly reorganized to ease quoting and searching, and
    bzip2 compressed, at:

    <http://cbfalconer.home.att.net/download/n869_txt.bz2>

    --
    Chuck F (cbfalconer at maineline dot net)
    <http://cbfalconer.home.att.net>
    Try the download section.



    --
    Posted via a free Usenet account from http://www.teranews.com
    CBFalconer, Nov 11, 2007
    #12
  13. CBFalconer <> writes:
    > Johannes Bauer wrote:
    >> You don't happen to have a link where the whole C99-standard can
    >> be found? I googled, but found nothing. Maybe the ANSI wants money
    >> for that?

    >
    > You can get the text version of N869, the last draft before C99 was
    > published, slightly reorganized to ease quoting and searching, and
    > bzip2 compressed, at:
    >
    > <http://cbfalconer.home.att.net/download/n869_txt.bz2>


    It has the disadvantage that (a) some of the formatting is lost (in
    particular, terms are shown in italics when they're defined, and the
    plain text version doesn't reflect this), and (b) it's a pre-standard
    draft. The differences betwen n869 and the approved C99 standard
    aren't huge, but there are some.

    Personally, I find the PDF version at least as useful as the
    plain-text version. If you can deal with PDF, I urge you to use
    n1256.pdf, or the actual standard, rather than n869. (This is
    addressed to Johannes Bauer, and/or to anyone else who's reading; I
    don't expect Chuck to change his mind on this point.)

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Looking for software development work in the San Diego area.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Nov 11, 2007
    #13
  14. Xcriber51

    Xcriber51 Guest

    Thanks. You're right, but that was done in a hurry just to throw a simple
    illustration of the problem to this forum, and the leading underscore was
    just to avoid a clash with another concat in that file.

    But anyway, enough about ourselves... :)

    Here's a challenge to all my fellow hackers, then. If I modify that
    illustration as follows...

    void concat()
    {
    char *s, *buff;
    // 8 is arbitrary, nevermind that
    s = (char *) malloc(sizeof(char) * 8);
    buff = (char *) malloc(sizeof(char) * 8);

    strcpy(buff,"t");

    sprintf(s,"%c%s",'a',buff); strcpy(buff,s);
    sprintf(s,"%c%s",'c',buff); strcpy(buff,s);
    sprintf(s,"%c%s",'n',buff); strcpy(buff,s);
    sprintf(s,"%c%s",'o',buff); strcpy(buff,s);
    sprintf(s,"%c%s",'c',buff); strcpy(buff,s);
    sprintf(s,"%c%s",'_',buff); strcpy(buff,s);

    printf("%s\n",s);

    free(s);
    free(buff);
    }

    ...this time, simply because I first copy the sprintf'ed string to a
    buffer everytime, I avoid that problem, and the output is expected.

    I know that a "strcat" exists, but that only concats two strings, not an
    arbitrary (variadic) number of parameters of various types into a string.
    sprintf is so convenient, you can write an "itoa" function in seconds like
    so (don't obsess with efficiency here):

    char *itoa(int n)
    {
    static char buff[15];
    sprintf(buff,"%d",n);

    return buff;
    }

    So I [naively, I realize] thought I could have that convenience any way I
    like. (I later checked an implementation of the function and found this:
    http://tinyurl.com/2r7c27. Apparently, you need a PhD to implement an
    sprintf function :D)

    Here's the challenge:

    Write a "catsprintf" function that avoids this shortcoming -- i.e. even if
    one of the string parameters is the target string itself, you gently copy
    that to a buffer, and then print everything (including that buffer) into
    the target string.

    NOTE: Try to write a version not from the ground up but utilizing the
    standard sprintf. I want to see how you deal with the variadic parameter
    list -- especially when one of the parameters is the destination string
    how you avoid overwriting it.

    (NB: if this is a pointless exercise for you, please avert your eyes and
    avoid adding noise and negativity to the thread.)

    I'm a 40-something, so I'm not asking for you to do my homework or
    anything.

    Thanks

    -- K


    --
    Message posted using http://www.talkaboutprogramming.com/group/comp.lang.c/
    More information at http://www.talkaboutprogramming.com/faq.html
    Xcriber51, Nov 11, 2007
    #14
  15. "Xcriber51" <> writes:

    > Here's the challenge:
    >
    > Write a "catsprintf" function that avoids this shortcoming -- i.e. even if
    > one of the string parameters is the target string itself, you gently copy
    > that to a buffer, and then print everything (including that buffer) into
    > the target string.


    A couple of points. The name is a bit odd since it does not obviously
    "cat" anything ("cat" as in concatenate). It is better to work with
    the new size-limited versions snprintf and vsnprintf since these can
    ensure the target is not over-run. Also, this size-limited way of
    thinking leads to a simpler solution:

    #include <stdarg.h>
    #include <stdio.h>

    int catsnprintf(char *s, size_t n, const char *format, ...)
    {
    char t_string[n];
    va_list alist;
    va_start(alist, format);
    int n_req = vsnprintf(t_string, n, format, alist);
    va_end(alist);
    memcpy(s, t_string, n_req > n ? n : n_req);
    return n_req;
    }

    To avoid using VLAs, a malloc/free pair is required.

    --
    Ben.
    Ben Bacarisse, Nov 11, 2007
    #15
  16. Xcriber51

    Xcriber51 Guest

    Xcriber51, Nov 11, 2007
    #16
    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. Ivan78

    sprintf: anomalous behavior

    Ivan78, May 15, 2006, in forum: C Programming
    Replies:
    15
    Views:
    637
    Marc Thrun
    May 16, 2006
  2. dorayme
    Replies:
    1
    Views:
    602
    richard
    Jan 21, 2011
  3. richard
    Replies:
    0
    Views:
    570
    richard
    Jan 21, 2011
  4. richard
    Replies:
    0
    Views:
    604
    richard
    Jan 21, 2011
  5. Ben Gribaudo

    Unexpected sprintf/String % Behavior

    Ben Gribaudo, Jun 15, 2005, in forum: Ruby
    Replies:
    3
    Views:
    170
    Ben Gribaudo
    Jun 17, 2005
Loading...

Share This Page