CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 33

Hybrid View

  1. #1
    Join Date
    Jul 2005
    Posts
    1,030

    A question regarding *s++

    Suppose I define char* s, then I call *s++. I guess it should do ++ first and then dereference. But look at a very typical code,
    Code:
                    char* s = "Hello";
    
    	char* s2 = new char[100];
    
    	char* p = s2;
    
    	while(*s)
    	{
    		*p++ = *s++;
    	}
    
    	*p = '\0';
    Look at the statement *p++ = *s++, obviously p is deferenced first and then it is incremented. Is there anything I missed here? Thanks.

  2. #2
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: A question regarding *s++

    It is actually incremented first. However, note that the postfix version of ++ is used, which means that while s itself is incremented, the return value of the operator is the old value of s.

    That is,
    Code:
    char *s = "Hello";
    // *s == 'H'
    char *t = s++;
    // *t == 'H', *s == 'e'
    *t = 'h'
    // now t points to "hello". Well, it doesn't, since modifying a string literal will probably crash the program, but it would if the Hello array had been in modifiable memory to begin with.
    This behavior is the reason why prefix increment, ++s, should be preferred unless you have a specific need for the postfix version. It's not only less confusing, it can in some cases be more efficient.

  3. #3
    Join Date
    Jul 2005
    Posts
    1,030

    Re: A question regarding *s++

    Thanks for your explainations.
    Quote Originally Posted by Lindley View Post
    It is actually incremented first. However, note that the postfix version of ++ is used, which means that while s itself is incremented, the return value of the operator is the old value of s.

    That is,
    Code:
    char *s = "Hello";
    // *s == 'H'
    char *t = s++;
    // *t == 'H', *s == 'e'
    *t = 'h'
    // now t points to "hello". Well, it doesn't, since modifying a string literal will probably crash the program, but it would if the Hello array had been in modifiable memory to begin with.
    This behavior is the reason why prefix increment, ++s, should be preferred unless you have a specific need for the postfix version. It's not only less confusing, it can in some cases be more efficient.

  4. #4
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,675

    Re: A question regarding *s++

    Quote Originally Posted by Lindley View Post
    This behavior is the reason why prefix increment, ++s, should be preferred unless you have a specific need for the postfix version. It's not only less confusing, it can in some cases be more efficient.
    Ok, now that we have a thread about that specific topic, I can ask this...

    From plain old C I'm used to prefer the post-increment version unless it is specifically required otherwise, simply because it looks more familiar to me.

    Am I right to assume that it wouldn't make a difference in terms of efficiency in C++ as long as it's about POD types?

    It looks reasonable to me that I get a performance penalty if I use post-increment on non-POD types and I somehow process the result of that operation, because it is likely to require creation of a temporary object. But does it really make any difference if I don't use the result of the increment operation in further processing?

  5. #5
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: A question regarding *s++

    Quote Originally Posted by Eri523 View Post
    Ok, now that we have a thread about that specific topic, I can ask this...

    From plain old C I'm used to prefer the post-increment version unless it is specifically required otherwise, simply because it looks more familiar to me.

    Am I right to assume that it wouldn't make a difference in terms of efficiency in C++ as long as it's about POD types?

    It looks reasonable to me that I get a performance penalty if I use post-increment on non-POD types and I somehow process the result of that operation, because it is likely to require creation of a temporary object. But does it really make any difference if I don't use the result of the increment operation in further processing?
    In a single sentence, "postfix is never faster, and sometimes slower".

    Under these conditions, there really is no reason to use postfix unless you need to.

    As for your question of taste ("prefering postfix over prefix"), if you start getting experience in C++, or work with people who have a C++ back ground, you will notice that prefix is the preferred way, and postfix will start looking weird.

    PS: The compiler may or may not optimize away and performance penalty, but why take the chance?
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  6. #6
    Join Date
    Oct 2009
    Posts
    577

    Smile Re: A question regarding *s++

    Quote Originally Posted by Eri523 View Post
    Ok, now that we have a thread about that specific topic, I can ask this...

    From plain old C I'm used to prefer the post-increment version unless it is specifically required otherwise, simply because it looks more familiar to me.

    Am I right to assume that it wouldn't make a difference in terms of efficiency in C++ as long as it's about POD types?

    It looks reasonable to me that I get a performance penalty if I use post-increment on non-POD types and I somehow process the result of that operation, because it is likely to require creation of a temporary object. But does it really make any difference if I don't use the result of the increment operation in further processing?
    The main argument for me to not using post-increment on class types isn't the possible lack of efficiency but that the behavior is different to that on POD types. Look at the following code (which was a C sample code in Stroustrup's Annotated C++ Reference)

    Code:
          while (*p++ = *q++);
    When p and q are char arrays the above is a perfect strcpy. When p and q are class types there is no way to let the post-increment on the right-hand happen after the assignment.

    If you then see that increment operation on class types mainly is done for containers and their iterators you probably will decide for prefix increment same as me and I promise that it will look 'more familiar' to you within a very short period ;-)

    Regards, Alex

  7. #7
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: A question regarding *s++

    Quote Originally Posted by itsmeandnobodyelse
    When p and q are class types there is no way to let the post-increment on the right-hand happen after the assignment.
    Sorry, but I do not quite understand the problem that you are presenting. Now, order of evaluation is implementation defined, but here it seems quite clear that the dereference of q must happen before its post-increment. Therefore, how does it matter if the assignment happens before or after the post-increment? With the normally expected semantics, the net effect should be the same, i.e., similiar to "a perfect strcpy".
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  8. #8
    Join Date
    Oct 2009
    Posts
    577

    Smile Re: A question regarding *s++

    Quote Originally Posted by laserlight View Post
    Sorry, but I do not quite understand the problem that you are presenting. Now, order of evaluation is implementation defined, but here it seems quite clear that the dereference of q must happen before its post-increment. Therefore, how does it matter if the assignment happens before or after the post-increment? With the normally expected semantics, the net effect should be the same, i.e., similiar to "a perfect strcpy".
    Assume

    Code:
    char p[20] = { '\0' };
    char * q = "Hello";
    while (*p++ = *q++);
    The above does:

    Code:
       p[0] = 'H'; 
       p[1] = 'e'; 
       p[2] = 'l';
       p[3] = 'l';
       p[4] = 'o';
       p[5] = '\0';
    If you do the same with a string class

    Code:
    MyString q = "Hello";
    while (*p++ = *q++);
    which has pointer semantics and overloaded operators for derefence, assignment and post-increment

    Code:
       p[0] = 'e'; 
       p[1] = 'l'; 
       p[2] = 'l';
       p[3] = 'o';
       p[4]= '\0';
    There is no way to happen the assigmnent *p = *q prior to the post-increment operation of q++.

    Regards, Alex

  9. #9
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: A question regarding *s++

    Quote Originally Posted by itsmeandnobodyelse View Post
    There is no way to happen the assigmnent *p = *q prior to the post-increment operation of q++.

    Regards, Alex
    Maybe you are confusing evaluation order?

    Regardless of type, when you write:

    Code:
    *p++ = *q++
    Both p++ and q++ are evaluated first (but in undefined relative order).

    Once this is done, operator= is called on the return values of p++ and q++, ie, the old values of p and q. (making it look like the assignment took place before increment)

    There is no special magic or rules that applies only to PODs that do the assignments first, and then increments the values of p or q.

    ...

    Either that, or I seem to not understand what you are saying. Your example (rewritten since incomplete) seems to work correctly:

    Code:
    #include <iostream>
    #include <string>
    
    int main()
    {
        char pArray[20] = { '\0' };
        char* p = pArray;
        std::string helloStr = "Hello";
    
        //force the null terminator into string //Undefined behavior, but defined in practice
        helloStr.c_str();
    
        std::string::iterator q = helloStr.begin();
        while (*p++ = *q++); //note that this reads string.end(), but should point '\0'. May crash in ranged debug
    
        std::cout << pArray << std::endl;
    }
    Code:
    output: Hello
    Was this your full example?

    Regards,
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  10. #10
    Join Date
    Oct 2009
    Posts
    577

    Smile Re: A question regarding *s++

    Quote Originally Posted by monarch_dodra View Post
    Maybe you are confusing evaluation order?

    Regardless of type, when you write:

    Code:
    *p++ = *q++
    Both p++ and q++ are evaluated first (but in undefined relative order).

    Once this is done, operator= is called on the return values of p++ and q++, ie, the old values of p and q. (making it look like the assignment took place before increment)

    There is no special magic or rules that applies only to PODs that do the assignments first, and then increments the values of p or q.

    ...

    Either that, or I seem to not understand what you are saying. Your example (rewritten since incomplete) seems to work correctly:

    Code:
    #include <iostream>
    #include <string>
    
    int main()
    {
        char pArray[20] = { '\0' };
        char* p = pArray;
        std::string helloStr = "Hello";
    
        //force the null terminator into string //Undefined behavior, but defined in practice
        helloStr.c_str();
    
        std::string::iterator q = helloStr.begin();
        while (*p++ = *q++); //note that this reads string.end(), but should point '\0'. May crash in ranged debug
    
        std::cout << pArray << std::endl;
    }
    Code:
    output: Hello
    Was this your full example?

    Regards,
    No, it was from my memories ;-)

    Here is the code that compiles:

    Code:
    #include <iostream>
    int main()
    {
        char * q = "Hello";
        char buf[20] = { '\0' };
        char * p = buf;
        while (*p++ = *q++);
        std::cout << buf << std::endl;
        return 0;
    }
    If incrementation would happen before assignment the p[0] would not be set correctly.

    I will add the string class example soonly.

    Regards, Alex

  11. #11
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: A question regarding *s++

    Quote Originally Posted by itsmeandnobodyelse View Post
    If incrementation would happen before assignment the p[0] would not be set correctly.
    Sure it would, given the post-increment semantics which are at the heart of what we're discussing.

  12. #12
    Join Date
    Oct 2009
    Posts
    577

    Smile Re: A question regarding *s++

    Here the full sample

    Code:
    #include<iostream>
    
    class String
    {
        char * ps;
        int    siz;
        int    len;
    public:
        String(const char * psz)
        {
           siz = strlen(psz)+1;
           ps = new char[siz];
           strcpy(ps, psz);
        }
        ~String() { delete []ps; }
        const char * c_str() { return ps; }
        friend class StringIterator;
    };
    
    class StringIterator
    {
        int pos;
        String * s;
    public:
        StringIterator(String & str) : s(&str), pos(0) {}
        char & operator*() { return s->ps[pos]; }
        StringIterator& operator++(int)
        {
            pos++;
            return *this;
        }
    };
    int main()
    {
        char * q = "Hello";
        char buf[20] = { '\0' };
        char * p = buf;
        while (*p++ = *q++);
        std::cout << buf << std::endl;
    
        String s("World");
        String t("              ");
        StringIterator i(s);
        StringIterator j(t);
        while (*j++ = *i++);
    
        std::cout << t.c_str() << std::endl;
        return 0;
    }
    And output is

    Hello
    orld

    Regards, Alex

    P.S.
    I don't think the above is a real problem. However, it was that what invoked me to not using post-increment on class types anymore.

  13. #13
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,675

    Re: A question regarding *s++

    Quote Originally Posted by itsmeandnobodyelse View Post
    Assume

    Code:
    char p[20] = { '\0' };
    char * q = "Hello";
    while (*p++ = *q++);
    I doubt that this would even compile: You are trying to increment an array.

  14. #14
    Join Date
    May 2007
    Location
    Scotland
    Posts
    1,164

    Re: A question regarding *s++

    Quote Originally Posted by laserlight View Post
    Sorry, but I do not quite understand the problem that you are presenting. Now, order of evaluation is implementation defined, but here it seems quite clear that the dereference of q must happen before its post-increment. Therefore, how does it matter if the assignment happens before or after the post-increment? With the normally expected semantics, the net effect should be the same, i.e., similiar to "a perfect strcpy".
    I'm being pedantic, but since you rarely make a mistake, I thought I'd chip in here... the part in bold is not correct. The precedence of the post increment and post decrement operators is higher than the precedence of the dereference operator. Therefore for an ISO Standard compliant compiler the post increment must happen before the dereference.

  15. #15
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: A question regarding *s++

    itsmeandnobodyelse: please provide the smallest and simplest compilable program that demonstrates what you claim.

    EDIT:
    This program appears to contradict your claims:
    Code:
    #include <iostream>
    #include <deque>
    
    class X
    {
    public:
        explicit X(int n) : n(n) {}
    
        // Sorry, I'm too lazy to use safe bool idiom,
        // and explicit conversion functions might not yet be available to you.
        operator bool() const
        {
            return n != 0;
        }
    
        int get() const
        {
            return n;
        }
    private:
        int n;
    };
    
    int main()
    {
        using namespace std;
    
        deque<X> one;
        for (int i = 1; i <= 10; ++i)
        {
            one.push_back(X(i));
        }
        one.push_back(X(0));
    
        deque<X> two(one.size(), X(-1));
    
        deque<X>::iterator p = two.begin();
        deque<X>::iterator q = one.begin();
    
        while (*p++ = *q++);
    
        for (deque<X>::size_type i = 0, size = two.size(); i < size; ++i)
        {
            cout << two[i].get() << endl;
        }
    }
    The output I get is:
    Code:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    0
    Last edited by laserlight; August 3rd, 2010 at 04:11 AM.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured