A question regarding *s++
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 3 123 LastLast
Results 1 to 15 of 33

Thread: A question regarding *s++

  1. #1
    Join Date
    Jul 2005
    Posts
    894

    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
    Fairfax, VA
    Posts
    10,885

    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
    894

    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,571

    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,276

    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 LITE 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,196

    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
    Jan 2006
    Location
    Singapore
    Posts
    6,196

    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

  10. #10
    Join Date
    May 2007
    Location
    Scotland
    Posts
    1,121

    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.

  11. #11
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,196

    Re: A question regarding *s++

    Quote Originally Posted by PredicateNormative
    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.
    No worries, we need to be pedantic here. Yes, your observation is correct. Consequently, itsmeandnobodyelse's same assertion is correct. However, itsmeandnobodyelse's assertion about there being a problem is wrong, assuming that the implementation follows normal semantics. The reason for my mistake is that I am thinking of the result of p++ being the original p. Therefore, *p will still dereference the value of the original p, unless for some reason postfix operator++ is implemented to return the modified p, which goes against normal semantics.
    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

  12. #12
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,276

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

  13. #13
    Join Date
    May 2007
    Location
    Scotland
    Posts
    1,121

    Re: A question regarding *s++

    Quote Originally Posted by laserlight View Post
    No worries, we need to be pedantic here. Yes, your observation is correct. Consequently, itsmeandnobodyelse's same assertion is correct. However, itsmeandnobodyelse's assertion about there being a problem is wrong, assuming that the implementation follows normal semantics. The reason for my mistake is that I am thinking of the result of p++ being the original p. Therefore, *p will still dereference the value of the original p, unless for some reason postfix operator++ is implemented to return the modified p, which goes against normal semantics.
    It was only that little bit about precedence I highlighted in bold that I disagreed with, I most certainly agree with everything else that you are saying about itsmeandnobodyelse assertion.

    It would seem to me there is something wrong with the post-increment operator implementation in itsmeandnobodyelse's MyString class.

  14. #14
    Join Date
    Jan 2009
    Posts
    1,689

    Re: A question regarding *s++

    Good rule of thumb is unless you absolutely have to have the original value of the value, use preincrement. I really irks me when I see things like this:

    Code:
    for(i = 0; i < 10; i++)
    Grr.
    For primitives it doesn't matter, the compiler will be smart enough to fix it for you, but if you do things like that, you get into the habit of it, and habits are hard to break.

  15. #15
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,571

    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.

Page 1 of 3 123 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
  •  


Azure Activities Information Page

Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center