Pointer Arithmetic Problem

A

arnuld

#include <stdio.h>

int main( void )
{
char arrc[] = { 'a', 'b', 'c', '\0' };
char* pc = arrc;
char** ppc = &pc;

printf("arrc = %s\n", arrc);
printf("------------------------\n");
printf("*pc = %5c\n", *pc);
printf("**ppc = %5c\n", **ppc);
printf("++*pc = %5c, *pc = %5c\n", ++*pc, *pc);
printf("(**ppc)++ = %5c, **ppc = %5c\n", (**ppc)++, **ppc);


return 0;
}


===================== OUTPUT ==========================
[arnuld@dune ztest]$ gcc -ansi -pedantic -Wall -Wextra ok.c
[arnuld@dune ztest]$ ./a.out
arrc = abc
------------------------
*pc = a
**ppc = a
++*pc = b, *pc = a
(**ppc)++ = b, **ppc = b
[arnuld@dune ztest]$


I am little confused at the output. after ++*pc , the *pc should print
'b', not 'a'. Same for **ppc, which is again printing the same element
even after having gone through a ++.
 
J

Joachim Schmitz

arnuld said:
#include <stdio.h>

int main( void )
{
char arrc[] = { 'a', 'b', 'c', '\0' };
char* pc = arrc;
char** ppc = &pc;

printf("arrc = %s\n", arrc);
printf("------------------------\n");
printf("*pc = %5c\n", *pc);
printf("**ppc = %5c\n", **ppc);
printf("++*pc = %5c, *pc = %5c\n", ++*pc, *pc);
printf("(**ppc)++ = %5c, **ppc = %5c\n", (**ppc)++, **ppc);


return 0;
}


===================== OUTPUT ==========================
[arnuld@dune ztest]$ gcc -ansi -pedantic -Wall -Wextra ok.c
[arnuld@dune ztest]$ ./a.out
arrc = abc
------------------------
*pc = a
**ppc = a
++*pc = b, *pc = a
(**ppc)++ = b, **ppc = b
[arnuld@dune ztest]$


I am little confused at the output. after ++*pc , the *pc should print
'b', not 'a'. Same for **ppc, which is again printing the same element
even after having gone through a ++.

Undefined behavoir in the last printf and I think in the 2nd to last too.
You modify ppc and look at it again without a squence point in between.

Bye, Jojo
 
J

jt

arnuld said:
#include <stdio.h>
int main( void )
{
 char arrc[] = { 'a', 'b', 'c', '\0' };
 char* pc = arrc;
 char** ppc = &pc;
 printf("arrc = %s\n", arrc);
 printf("------------------------\n");
 printf("*pc       = %5c\n", *pc);
 printf("**ppc     = %5c\n", **ppc);
 printf("++*pc     = %5c, *pc   = %5c\n", ++*pc, *pc);
 printf("(**ppc)++ = %5c, **ppc = %5c\n", (**ppc)++, **ppc);
 return 0;
}
===================== OUTPUT ==========================
[arnuld@dune ztest]$ gcc -ansi -pedantic -Wall -Wextra ok.c
[arnuld@dune ztest]$ ./a.out
arrc = abc
------------------------
*pc       =     a
**ppc     =     a
++*pc     =     b, *pc   =     a
(**ppc)++ =     b, **ppc =     b
[arnuld@dune ztest]$
I am little confused at the output. after ++*pc , the *pc should print
'b', not 'a'. Same for **ppc, which is again printing the same element
even after having gone through a ++.

Undefined behavoir in the last printf and I think in the 2nd to last too.
You modify ppc and look at it again without a squence point in between.

Bye, Jojo

hii...
after any function call the argumants are pushed on to a stack(i.e.
starting from left)...
and then they evaluated as they are popped..
so here the first argument to be evaluated is <*pc> not <++*pc>
since <++*pc> is pre incrementation <a> gets incremented to <b> in the
same statement...
in the next printf()...
the same thing happens, but since it is post incrementation...you wont
see the effect in this statement....
try adding another statement...maybe..
printf("\n\n **ppc= %c\n",**ppc);
..
..
you'll know the change....
hope this clears your doubt..
 
K

Keith Thompson

jt said:
after any function call the argumants are pushed on to a stack(i.e.
starting from left)...
and then they evaluated as they are popped..

That's one possible implementation. The C standard specifically does
not specify the order in which function arguments are evaluated.
Furthermore, since there's no sequence point between the evaluations
of two arguments in the same call, if both argument evaluations modify
the same object, the behavior is undefined; *anything* could happen.

If you want to control, or even know, the order of evaluation of two
expressions, you need to make sure there's a sequence point between
them. The easiest way to do that is to put them in to separate
statements.
 
B

Ben Bacarisse

Keith Thompson said:
That's one possible implementation. The C standard specifically does
not specify the order in which function arguments are evaluated.
Furthermore, since there's no sequence point between the evaluations
of two arguments in the same call, if both argument evaluations modify
the same object, the behavior is undefined; *anything* could happen.

I'd go further (as did Joachim Schmitz). To paraphrase the code, I
would that:

printf("%d %d\n", x, ++x);

reads "the prior value" for a purpose other than to "determine the
value to be stored" and is thus UB even without double modification.
 
B

Barry Schwarz

#include <stdio.h>

int main( void )
{
char arrc[] = { 'a', 'b', 'c', '\0' };
char* pc = arrc;
char** ppc = &pc;

printf("arrc = %s\n", arrc);
printf("------------------------\n");
printf("*pc = %5c\n", *pc);
printf("**ppc = %5c\n", **ppc);
printf("++*pc = %5c, *pc = %5c\n", ++*pc, *pc);

You don't know the order in which the arguments are evaluated. There
are six possibilities.

Even if the arguments are evaluated from left to right, you don't know
when the side-effect of the ++ occurs.

Finally, the code invokes undefined behavior since between sequence
points *pc is modified but it is evaluated twice and for purposes
other than determining its new value.
printf("(**ppc)++ = %5c, **ppc = %5c\n", (**ppc)++, **ppc);
Ditto.



return 0;
}


===================== OUTPUT ==========================
[arnuld@dune ztest]$ gcc -ansi -pedantic -Wall -Wextra ok.c
[arnuld@dune ztest]$ ./a.out
arrc = abc
------------------------
*pc = a
**ppc = a
++*pc = b, *pc = a
(**ppc)++ = b, **ppc = b
[arnuld@dune ztest]$


I am little confused at the output. after ++*pc , the *pc should print
'b', not 'a'. Same for **ppc, which is again printing the same element
even after having gone through a ++.
 
A

arnuld

... SNIP...
Finally, the code invokes undefined behavior since between sequence
points *pc is modified but it is evaluated twice and for purposes
other than determining its new value.

What you mean by "for purposes other than determining its new value" ?
e.g. do you mean all I can do in single statement is to either print the
value of the variable or increment (or anything else like assigning th
vale to some array element) ?
 
K

Keith Thompson

arnuld said:
What you mean by "for purposes other than determining its new value" ?
e.g. do you mean all I can do in single statement is to either print the
value of the variable or increment (or anything else like assigning th
vale to some array element) ?

Here's what the standard says:

Between the previous and next sequence point an object shall have
its stored value modified at most once by the evaluation of an
expression. Furthermore, the prior value shall be read only to
determine the value to be stored.

A footnote says:

This paragraph renders undefined statement expressions such as
i = ++i + 1;
a[i++] = i;
while allowing
i = i + 1;
a = i;

The point of the second part, "the prior value shall be read only to
determine the value to be stored" is that reading and writing the same
object is ok *if* the value that's read is used to compute the value
to be written, because that imposes an ordering. If the value that's
read isn't used to compute the value to be written, as in the right
hand side of "a[i++] = i;", then no such ordering is imposed, and
there's no single valid result. Rather than requiring a result that's
consistent with one of the valid orderings, the standard renders the
entire behavior undefined; this allows for more aggressive
optimization in some cases.
 
N

Nick Keighley

arnuld wrote:
 char arrc[] = { 'a', 'b', 'c', '\0' };
 char* pc = arrc;
 char** ppc = &pc;
 printf("arrc = %s\n", arrc);
 printf("------------------------\n");
 printf("*pc       = %5c\n", *pc);
 printf("**ppc     = %5c\n", **ppc);
 printf("++*pc     = %5c, *pc   = %5c\n", ++*pc, *pc);
 printf("(**ppc)++ = %5c, **ppc = %5c\n", (**ppc)++, **ppc);
Undefined behavoir in the last printf and I think in the 2nd to last too.
You modify ppc and look at it again without a squence point in between.

after any function call the argumants are pushed on to a stack(i.e.
starting from left)...

As Keith Thompson remarked you are describing a particular
implementation
and *not* what is specified by The Standard.

Actually I don't think you are even describing a sensible
implementation.
The arguments are evaluated *before* the call and may not necessarily
be
evaluated left to right (actually right to left is more common).
Arguments
can be evaluated in any order. Arguments don't have to be on a stack
to be
passed to the function (eg. some RISC processors have a large number
of
registers and most arguments go in the registers)
and then they evaluated as they are popped..

I can't make sense of this. Arguments are evaluated before they are
passed.
If a stack is used they are evaluatewd before they are pushed. They
are discarded from the paramter passing mechanism when the function
returns (eg. popped and discarded)
so here the first argument to be evaluated is <*pc> not <++*pc>
since <++*pc> is pre incrementation <a> gets incremented to <b> in the
same statement...
in the next printf()...
the same thing happens, but since it is post incrementation...you wont
see the effect in this statement....
try adding another statement...maybe..
printf("\n\n **ppc= %c\n",**ppc);
.
.
you'll know the change....
hope this clears your doubt..

I think you've increrased confusion.

As someone (Bohr?) said "you're not right, you're not even wrong."
 
V

Vallabha

#include <stdio.h>

int main( void )
{
char arrc[] = { 'a', 'b', 'c', '\0' };
char* pc = arrc;
char** ppc = &pc;

printf("arrc = %s\n", arrc);
printf("------------------------\n");
printf("*pc = %5c\n", *pc);
printf("**ppc = %5c\n", **ppc);
printf("++*pc = %5c, *pc = %5c\n", ++*pc, *pc);
printf("(**ppc)++ = %5c, **ppc = %5c\n", (**ppc)++, **ppc);

return 0;

}

===================== OUTPUT ==========================
[arnuld@dune ztest]$ gcc -ansi -pedantic -Wall -Wextra ok.c
[arnuld@dune ztest]$ ./a.out
arrc = abc
------------------------
*pc = a
**ppc = a
++*pc = b, *pc = a
(**ppc)++ = b, **ppc = b
[arnuld@dune ztest]$

I am little confused at the output. after ++*pc , the *pc should print
'b', not 'a'. Same for **ppc, which is again printing the same element
even after having gone through a ++.

--www.lispmachine.wordpress.com
my email is @ the above blog.
Gooogle Groups is Blocked. Reason: Excessive Spamming

It depends on in which order the parameters are evaluated. Most of the
time it is evaluated from right to left. A simpler example can make
this more clear:

int main()
{
int a = 10;
printf("%d %d %d\n", a, ++a, a);
return 0;
}

Output will be: 11, 11, 10

HTH,
-Vallabha
S7 Software Solutions
 
K

Keith Thompson

Vallabha said:
It depends on in which order the parameters are evaluated. Most of the
time it is evaluated from right to left. A simpler example can make
this more clear:

int main()
{
int a = 10;
printf("%d %d %d\n", a, ++a, a);
return 0;
}

Output will be: 11, 11, 10

The output could be literally anything, or nothing. Your code
exhibits undefined behavior, even after adding the required
"#include <stdio.h>". (I just tried it on three different systems;
one gave me "11, 11, 10", the others gave me "11, 11, 11".)
 
B

Barry Schwarz

arnuld said:
What you mean by "for purposes other than determining its new value" ?
e.g. do you mean all I can do in single statement is to either print the
value of the variable or increment (or anything else like assigning th
vale to some array element) ?

Here's what the standard says:

Between the previous and next sequence point an object shall have
its stored value modified at most once by the evaluation of an
expression. Furthermore, the prior value shall be read only to
determine the value to be stored.

A footnote says:

This paragraph renders undefined statement expressions such as
i = ++i + 1;
a[i++] = i;
while allowing
i = i + 1;
a = i;

The point of the second part, "the prior value shall be read only to
determine the value to be stored" is that reading and writing the same
object is ok *if* the value that's read is used to compute the value
to be written, because that imposes an ordering. If the value that's
read isn't used to compute the value to be written, as in the right
hand side of "a[i++] = i;", then no such ordering is imposed, and
there's no single valid result. Rather than requiring a result that's
consistent with one of the valid orderings, the standard renders the
entire behavior undefined; this allows for more aggressive
optimization in some cases.


As a point of interest, the quoted section comes from 6.5-2 of n1256.
In n1336, the draft of the next standard (C09?), it has been
completely reworded:

"If a side effect on a scalar object is unsequenced relative to either
a different side effect on the same scalar object or a value
computation using the value of the same scalar object, the behavior is
undefined. If there are multiple allowable orderings of the
subexpressions of an expression, the behavior is undefined if such an
unsequenced side effect occurs in any of the orderings."

The footnote is unchanged.

The corresponding section of J.2 has been reworded in a similar
fashion.
 
B

Barry Schwarz

#include <stdio.h>

int main( void )
{
char arrc[] = { 'a', 'b', 'c', '\0' };
char* pc = arrc;
char** ppc = &pc;

printf("arrc = %s\n", arrc);
printf("------------------------\n");
printf("*pc = %5c\n", *pc);
printf("**ppc = %5c\n", **ppc);
printf("++*pc = %5c, *pc = %5c\n", ++*pc, *pc);
printf("(**ppc)++ = %5c, **ppc = %5c\n", (**ppc)++, **ppc);

return 0;

}

===================== OUTPUT ==========================
[arnuld@dune ztest]$ gcc -ansi -pedantic -Wall -Wextra ok.c
[arnuld@dune ztest]$ ./a.out
arrc = abc
------------------------
*pc = a
**ppc = a
++*pc = b, *pc = a
(**ppc)++ = b, **ppc = b
[arnuld@dune ztest]$

I am little confused at the output. after ++*pc , the *pc should print
'b', not 'a'. Same for **ppc, which is again printing the same element
even after having gone through a ++.

--www.lispmachine.wordpress.com
my email is @ the above blog.
Gooogle Groups is Blocked. Reason: Excessive Spamming

It depends on in which order the parameters are evaluated. Most of the

No it doesn't.
time it is evaluated from right to left. A simpler example can make
this more clear:

The original code and your example below are both specifically defined
in the standard to invoke undefined behavior. See section 6.5-2.
 
A

arnuld

Here's what the standard says:

Between the previous and next sequence point an object shall have
its stored value modified at most once by the evaluation of an
expression. Furthermore, the prior value shall be read only to
determine the value to be stored.

This language feels like the language of High-Court notices to me. I still
don't understand the meaning of it. All I understand is this:


we can modify the value in a single expression, then we must not read
the vale either before or after the modification.


Does it mean that "one can expect a defined behavior, in one single expression, only if" :

1) he does ++*p and does not read its value before or after
this modification.

2) he does not modify at all but only read the value more than
1 time in a single expression.


Hence only these are defined behaviors:

printf("%d\n", ++*p); /* prints the incremented vale of *p */
printf("%d, %d, %d\n", *p, *p, *p);




A footnote says:

This paragraph renders undefined statement expressions such as
i = ++i + 1;
a[i++] = i;

both expressions are undefined. I don't see why standard used 2
expressions when one is enough.

while allowing
i = i + 1;
a = i;

The point of the second part, "the prior value shall be read only to
determine the value to be stored"


but these are 2 different expressions.

is that reading and writing the same
object is ok *if* the value that's read is used to compute the value
to be written, because that imposes an ordering. If the value that's
read isn't used to compute the value to be written, as in the right
hand side of "a[i++] = i;", then no such ordering is imposed, and
there's no single valid result.


I got this one completely :)
 
N

Nick Keighley

Nick Keighley said:

Well, not quite those exact words, but you're thinking of Wolfgang Pauli
(1900-1958).

so it could be said of my statement
'That's not right. It's not even wrong'

and it was indeed Pauli

thanks
 
K

Keith Thompson

arnuld said:
This language feels like the language of High-Court notices to me. I still
don't understand the meaning of it. All I understand is this:


we can modify the value in a single expression, then we must not read
the vale either before or after the modification.

Um, not quite. You can certainly read and then modify the value of an
object with an expression; for example, "i = i + 1;" is ok.
Does it mean that "one can expect a defined behavior, in one single
expression, only if" :

1) he does ++*p and does not read its value before or after
this modification.

2) he does not modify at all but only read the value more than
1 time in a single expression.


Hence only these are defined behaviors:

printf("%d\n", ++*p); /* prints the incremented vale of *p */
printf("%d, %d, %d\n", *p, *p, *p);

I'm not sure I understand the question. Those certainly do have
well-defined behavior, but there are an infinite variety of other
expressions that also have well-defined behavior.
A footnote says:

This paragraph renders undefined statement expressions such as
i = ++i + 1;
a[i++] = i;

both expressions are undefined. I don't see why standard used 2
expressions when one is enough.

Because they demonstrate undefined behavior for two different reasons.
The first modifies the object "i" twice. The second reads and
modifies "i", but it's undefined because it reads i for a purpose
other than computing the value to store in it.
while allowing
i = i + 1;
a = i;

The point of the second part, "the prior value shall be read only to
determine the value to be stored"

but these are 2 different expressions.


Huh? Do you mean that "i = i + 1;" and "a = i;" are two different
expressions? Yes, they are (actually two different expression
statements). What's your point?
is that reading and writing the same
object is ok *if* the value that's read is used to compute the value
to be written, because that imposes an ordering. If the value that's
read isn't used to compute the value to be written, as in the right
hand side of "a[i++] = i;", then no such ordering is imposed, and
there's no single valid result.


I got this one completely :)

Um, ok. Does the smiley mean you didn't get it, or am I just missing
the joke?
 
A

arnuld

Um, not quite. You can certainly read and then modify the value of an
object with an expression; for example, "i = i + 1;" is ok.

That I know, because there is stupidity revolving here like i = i++ + 1.


Huh? Do you mean that "i = i + 1;" and "a = i;" are two different
expressions? Yes, they are (actually two different expression
statements). What's your point?



point is: If we put both of them in one expression, then we will stilll
have well-defined behavior, so why you used 2 expressions:

printf("values are: %d and %d\n", i = i + 1, a = i);

its not UB.


Um, ok. Does the smiley mean you didn't get it, or am I just missing
the joke?

I was happy that I understood full of your paragraph when I don't
understand 50% of them on clc (because of pointer-business)
 
R

Richard Bos

arnuld said:
This language feels like the language of High-Court notices to me.

That may be because, like High Court judgements, they have to be exact,
lest someone notice the loopholes and starts abusing them.
I still don't understand the meaning of it. All I understand is this:

we can modify the value in a single expression, then we must not read
the vale either before or after the modification.

Until we hit the next sequence point. Yes.
Does it mean that "one can expect a defined behavior, in one single expression, only if" :

FSVO "expression", but...
1) he does ++*p and does not read its value before or after
this modification.

2) he does not modify at all but only read the value more than
1 time in a single expression.

....yes, and yes.
Hence only these are defined behaviors:

printf("%d\n", ++*p); /* prints the incremented vale of *p */
printf("%d, %d, %d\n", *p, *p, *p);

Yes. And similar ones, of course.
A footnote says:

This paragraph renders undefined statement expressions such as
i = ++i + 1;
a[i++] = i;

both expressions are undefined. I don't see why standard used 2
expressions when one is enough.

More examples, more clarity. (Up to a reasonable point, of course.)

Richard
 
B

Bart van Ingen Schenau

Huh? Do you mean that "i = i + 1;" and "a = i;" are two different
expressions? Yes, they are (actually two different expression
statements). What's your point?


point is: If we put both of them in one expression, then we will stilll
have well-defined behavior, so why you used 2 expressions:

printf("values are: %d and %d\n", i = i + 1, a = i);

its not UB.


Actually, that printf call *does* cause UB.
In the second argument, you modify the variable i and
in the third argument, you access (read) the variable i for another
reason than to calculate the new value of i.
As there is no sequence point between the evaluation of the two
arguments, the behaviour is undefined.

Bart v Ingen Schenau
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

pointer to pointer 7
using a pointer vs array 12
Find the size of an array 21
Selection-Sort in C 35
Binary Search in C 7
strtoul() behavior 39
insertion sort in C 14
strcpy - my implementation 64

Members online

Forum statistics

Threads
473,756
Messages
2,569,531
Members
45,005
Latest member
MellisaSti

Latest Threads

Top