Use of post-increment in recursion [duplicate] - c

This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 6 years ago.
I'm new in this community, and I'm trying to understand why this recursive function not get a stack overflow,when I use the post increment (c++) in the call of the function, this passes a value of 0 (i see that when i debug), but when the next function is called, it have a value of 1.
I dont understand when the post increment is applied, and why if im passing to the function the value of 0 , in the first argument is doing s+1;
#include <stdio.h>
#include <string.h>
#define LARGO 20
char *esta (char s[], int c){
if(strlen(s))
printf("\n %s", esta(s+c,c++));
return s;
}
int main()
{
char cad[LARGO]= {"hello"};
int c=0;
printf("\n %s", esta(cad,c++));
}
P.S. : Sorry if my english is not the best, It isn't my main language and i try to explain as well i could; and if it is something is not clear tell me and i change it.

The order in which arguments are evaluated is undefined, so the compiler can choose any order it wants to. It seems in your case, it's first evaluating c++ to 0, and then s+c evaluates to s+1.

See wikipedia Sequence point. In particular item #4 gives full explanation:
A sequence point defines any point in a computer program's execution at which it is guaranteed that all side effects of previous evaluations will have been performed, and no side effects from subsequent evaluations have yet been performed.
Before a function is entered in a function call. The order in which the arguments are evaluated is not specified, but this sequence point means that all of their side effects are complete before the function is entered.
In the expression f(i++) + g(j++) + h(k++), f is called with a parameter of the original value of i, but i is incremented before entering the body of f.
In other words: compiler is assigned to do a tough job here. It must pass the original value which was there before POST-increment (because it is how POST-increment works) and at the same time perform all side effects BEFORE entering the function esta. Among these side effects is increment the value of c. And, since the order in which the arguments are evaluated is not specified it happens so that your compiler evaluates c++ first, and then does s+c which in this case means s+1. Hence your line is shorter and shorter and eventually strlen(s)==0 when you exit from the recursion and print string remainders at each iteration.

Related

Please explain the output of following C code

Code :
#include<stdio.h>
#include<stdlib.h>
int arr[] = {1, 2, 3, 4};
static int count = 0;
int incr( ) {
++count;
++count;
return count;
}
int main(void)
{
printf("\ncount= %d \n",count);
int i;
arr[count++]=incr( );
for(i=0;i<4;i++)
printf("arr[%d]=%d\n", i,arr[i]);
printf("\nIncremented count= %d \n",count);
return 0;
}
Output
count = 0
arr[0]=2
arr[1]=2
arr[2]=3
arr[3]=4
Incremented count = 1
The final incremented value of global variable count is 1 even though it has been incremented thrice.
When count++ is replaced by count in arr[count++]=incr( ) the final incremented value of count is 2.
This is undefined behaviour from bad sequencing. On this line:
arr[count++]=incr( );
What happens (with your compiler) is:
arr[count] is resolved to arr[0], postfix ++ will be applied at the end of the
statement;
incr() is called, count is now equal to 2, incr() returns 2;
arr[0] gets assigned 2;
postfix ++'s side effect kicks in, and count is now equal to 1. Previous changes to count are lost.
You will find more info on "side effects" and "sequence points" by googling their real name :)
To understand why your code goes wrong, you must first understand undefined behavior and sequence points, which is a rather advanced topic. You also need to understand what undefined behavior is, and what unspecified behavior is, explained here.
If you do something to a variable which counts as a side-effect, such as modifying it, then you are not allowed to access that variable again before the next sequence point, for other purposes than to calculate which value to store in your variable.
For example i = i++ is undefined behavior because there are two side effects on the same variable with no sequence point in between. But i = i+1; is well-defined, because there is only one side effect (the assignment) and the i+1 is only a read access to determine what value to store.
In your case, there is no sequence point between the arr[count++] sub-expression and the incr() sub-expression, so you get undefined behavior.
This is how sequence points appear in functions, C11 6.5.2.2:
There is a sequence point after the evaluations of the function
designator and the actual arguments but before the actual call. Every
evaluation in the calling function (including other function calls)
that is not otherwise specifically sequenced before or after the
execution of the body of the called function is indeterminately
sequenced with respect to the execution of the called function.
This means that the contents of the function aren't sequenced in relation to the rest of the expression. So you are essentially writing an expression identical to arr[count++] = ++count;, except through the function you managed to squeeze in two unsequenced ++count on the right side of the operation, which wouldn't otherwise be possible. Any any rate, it is undefined behavior.
Fix your code by enforcing sequence points between the left hand and the right hand of the expression. However, the order of evaluation of sub-expressions is unspecified behavior, so you need to ensure that your code is safe no matter if the left or right side is evaluated first. This code will fix the problems:
// artificial example, don't write code like this
0,arr[count++] = 0,incr();
since the comma operator introduces a sequence point. But of course, writing nonsense code like that isn't something you should be doing. The real solution is to never use ++ together with other operators in the same expression.
// good code, write code like this
arr[count] = incr();
count++;

C equivalent operator creating confusion

Program 1:
#include<stdio.h>
void main()
{
int i=55;
printf("%d %d %d %d\n",i==55,i=40,i==40,i>=10);
}
Program 2:
#include<stdio.h>
void main(){
int i = 55;
if(i == 55) {
printf("hi");
}
}
First program give output 0 40 0 1 here in the printf i == 55 and output is 0 and in the second program too i ==55 and output is hi. why
In the first example, the operators are evaluated in reverse order because they are pushed like this on the stack. The evaluation order is implementation specific and not defined by the C standard. So the squence is like this:
i=55 initial assignment
i>=10 == true 1
i==40 == false (It's 55) 0
i=40 assignment 40
i==55 == false (It's 40) 0
The second example should be obvious.
There's no guarantee about the order in which arguments to a function are evaluated. There's also no sequence point between evaluating the different arguments to the function.
That means your first call gives undefined behavior, because it both uses the existing value of i and writes a new value to i without a sequence point between the two.
In a typical case, however, each argument to a function will be evaluated as a separate expression, with no interleaving between them. In other words, the compiler will impose some order to the evaluation, even though the standard doesn't require it to do so.
In the specific case of a variadic function, the arguments are typically pushed onto the stack from right to left, so the first argument (the format string) will be at the top of the stack. This makes it easy for printf to find the format string, and then (based on that) retrieve the rest of the arguments from further down the stack.
If (as is fairly typical) the arguments are evaluated immediately prior to being pushed on the stack, this will lead to the arguments being evaluated from right to left as well.
Functions with a fixed number of arguments aren't evaluated from right to left nearly as often, so if (for example) you wrote a small wrapper taking a fixed number of arguments, that then passed those through to printf, there's a greater chance that i would have the value 55 when the first argument to printf is evaluated, so that would produce a 1 instead of a 0.
Note, however, that neither result is guaranteed, nor is any meaningful result guaranteed--since you have undefined behavior, anything is allowed to happen.
The arguments of printf are evaluated from right to left here (this is unspecified behavior, but the behaviour you noticed shows that at least the first argument is evaluated after the second). In your argument list there ist i=40, which sets the value to 40. Therefore the first printed argument is false (0).
The function printf evaluates the expressions in implementation specific manner, in this case from right to left. Hence the output:
i==55(0),i=40(Assignment),i==40(0),i>=10(1)
The reason is that the order in which the arguments to the printf function (actually any function) are evaluated, before being passed to the function, is not defined by the C standard.
The problem is not with your understanding of the == operator.
Edit: Although many authors are pointing out that printf typically evaluates its arguments from right-to-left (which I wasn't aware of), I would say it's probably a bad idea to write code that depends on this, as the language does not guarantee it, and it makes the code much less readable. Nevertheless is is a good factoid to know in case you come across it in the wild.
In the first program: The order of evaluation of the printf() arguments is implimentation defined. So this program doesn't give the same result on different implimentation of printf() So there is no guarantee about what the program will result.
It could output 0 40 0 1 as it could output 1 40 1 1 if the order of evaluation is reversed.

Sequence points in C / function calls

I'm just learning some C, or rather, getting a sense of some of the arcane details. And I was using VTC advanced C programming in which I found that the sequence points are :
Semicolon
Comma
Logical OR / AND
Ternary operator
Function calls (Any expression used as an argument to a function call is finalized the call is made)
are all these correct ?. Regarding the last one I tried:
void foo (int bar) { printf("I received %d\n", bar); }
int main(void)
{
int i = 0;
foo(i++);
return 0;
}
And it didnt print 1, which according to what the VTC's guy said and if I undertood correctly, it should, right ?. Also, are these parens in the function call the same as the grouping parens ? (I mean, their precedence). Maybe it is because parens have higher precedence than ++ but I've also tried foo((i++)); and got the same result. Only doing foo(i = i + 1); yielded 1.
Thank you in advance. Please consider that I'm from South America so if I wasnt clear or nothing makes sense please, oh please, tell me.
Warmest regards,
Sebastian.
Your code is working like it should and it has nothing to do with sequence points. The point is that the postfix ++ operator returns the non-incremented value (but increments the variable by 1 nonetheless).
Basically:
i++ – Increment i by one and return the previous value
++i – Increment i by one and return the value after the increment
The position of the operator gives a slight hint for its semantics.
Sequence means i++ is evaluted before foo is invoked.
Consider this case (I am not printing bar!):
int i = 0;
void foo (int bar) { printf("i = %d\n", i); }
int main(void){
foo(i++);
return 0;
}
i = 1 must be printed.
C implements pass-by-value semantics. First i ++ is evaluated, and the value is kept, then i is modified (this may happen any time between the evaluation and the next sequence point), then the function is entered with the backup value as the argument.
The value passed into a function is always the same as the one you would see if using the argument expression in any other way. Other behavior would be fairly surprising, and make it difficult to refactor common subexpressions into functions.
When you do something like:
int i = 0, j;
j = i++;
the value of i is used first and then incremented. hence in your case the values of i which is 0 is used (hence passed to your function foo) and then incremented. the incremented values of i (now 1) will be available only for main as it is its local variable.
If you want to print 1 the do call foo this way:
foo(++i);
this will print 1. Rest you know, why!

pre and post increment operations on a variable give different output on TC and gcc [duplicate]

This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 5 years ago.
Here is my simple code ...
#include<stdio.h>
int main()
{
int i=5;
printf("%d %d %d %d %d ",i++,i--,++i,--i,i);
return 0;
}
On gcc,it gives output as '4 5 5 5 5'
but on TC,it gives output as '4 5 5 4 5'
what I know that in printf statement,evaluation will be from left to right if it is a single expression but in normal statement,it will be from left to right.
but if printf contain multiple expressions,then evaluation will be on stack,the elements would be pushed onto stack from left to right but popped out from right to left and that justified the TC output
Please correct me where am I wrong ???
C does not specify which order function arguments should be evaluated in, and so it is undefined and a compiler can do it however they choose, including arbitrarily and randomly. Bjarne Stroustrup says this explicitly in "The C++ Programming Language" 3rd edition section 6.2.2
He also gives a reason:
Better code can be generated in the absence of restrictions on expression evaluation order
I think the order in which the arguments of a function call are evaluated is not specified. As wikipedia says in this article on sequence points:
The order in which the arguments are evaluated is not specified
Modifying an object (in this code i) more than one time between the previous and the next sequence point is undefined behavior in C. Here the sequence point occurs at the function call after all arguments have been evaluated.
The two answers at this point in time invoke the unspecifiedness of the evaluation of function arguments. The correct answer is that your program is undefined because of side-effects to the same variable not separated by a sequence point.
Indeed, the evaluation order of function arguments is unspecified. This means that in the statement f(g(), h());, either g() is called before h() or it is called after.
However, unsequenced side-effects (as in your program) invoke undefined behavior, where anything can happen.
Bumping up an old topic but I just found how the gcc and Visual Studio Compiler works on multiple changes on the same variable in a statement so thought of sharing it here.
The compiler as defined here starts to implement stack method on the arguments being passed in printf which is 'i'. It follows these rules:-
1) Now it executes the pre-increments first therefore starting from right normal i then --i and then ++i are executed and the value of i after ++i is 5 so it implements these values (pops) so output is _ _ 5 5 5
2) Then it continues right to left and executes post increments therefore, i-- and then i++ so the value of i in the end is back to 5 but due to i-- it becomes 4 but shows 5 due to it being a post increment therefore the final output is 4 5 5 5 5 and the final value of i is 5
Hope I am able to clear your doubts.
TC doesn't follow this so it adheres to our human logic.

printf and ++ operator [duplicate]

This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 4 years ago.
#include<stdio.h>
main()
{
int a=10;
printf("\n %d %d", a, a++); //11 10
a=10;
printf("\n %d %d", a++, a); //10 11
a=10;
printf("\n %d %d %d ", a, a++,++a); //12 11 12
}
after running this I got the output given in comments. as far as I know first output is expected because execution of printf goes from right to left but could not understand second and third
Nothing goes "from right to left" in function argument evaluation. When function arguments are evaluated, the order of evaluation is unspecified and there are no sequence points between evaluating separate arguments. This means that there's absolutely no temporal ordering in this process. The arguments can be evaluated in any order, and the process of their evaluation can be intertwined in any way.
However, your code suffers from even worse problems. All three statements that call printf produce undefined behavior (UB) because they either make an attempt to modify the same object (a) twice without a sequence point between the modifications (the third call), or they attempt to modify an object and read it for an independent purpose (the first and the second call). So, it is too early to even mention the order of evaluation. Your code's behavior is undefined.
None of the outputs can really qualify as unexpected. All the arguments to a function are evaluated before entry to the function itself -- but the order of their evaluation relative to each other is unspecified, so all of these results are allowed. Officially, your last one (that has two separate instances of incrementing a) has undefined behavior, so it doesn't have to do anything sensible at all.
++a means increment a first, and then return evaluate the expression. (a changes, and the expression evaluates as a + 1)
a++ means evaluate a (so, erm, a), and then increment it. So a is passed, but the value of a is then (ie afterwards) changed to a+1.
You are invoking undefined behaviour by referencing both 'a' and 'a++' in the argument list.
It is not defined which order the arguments are evaluated in. Different compilers may choose different orders. A single compiler can choose different orders at different times.
Do not do it!
Function parameters are not evaluated in a defined order in C. Therefore one cannot tell beforehand if a or a++ will be evaluated first when calling printf.
See Parameter evaluation order before a function calling in C

Resources