This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 9 years ago.
i begin Why the output produce 002?
Thanks for the edit and the answers but I'm still confused.
Here is the code:
#include <stdio.h>
int t[3],i;
int main()
{
for(i=0;i<3;i++)
t[i]=i++;
for(i=0;i<3;i++)
printf("%d",t[i]);
}
002
Can anyone help me understand why it is so?
It's because you incremented your i counter twice in your for-loop (once at t[i] = i++, once at the end statement of your for-loop, i++). That way, the for-loop is executed twice (not three times), once for i = 0 and once for i = 2. Hence your output.
To convince yourself, try adding prints as in
for(i=0;i<3;i++) {
printf("%i ", i);
t[i]=i++;
}
and see how many times your for loop gets executed and for which values of i it does.
Download a copy of the C standard (for example, google for N1570, that will give you the latest freely available version). In that document, look for "sequence point" and read what it says.
In short: Your program is rubbish and could do whatever it likes, for the reasons explained in this document. (Basically, the statement t [i] = i++; invokes undefined behaviour. This is a very special case of a general rule set in the C Standard. C++ and Objective-C have the same rule).
You are incrementing i twice in each iteration. In first iteration i = 0, so t[0] = 0 then you are doing i++ twice. In second iteration i=2 so t[2] = 2 and now loop is ending. t[1] is uninitialized.You are getting 002 because:the first 0 from t[0]the second 0 is garbage value or null value from where t[1] is stored in the memory (in your case it is 0 )and the last 2 from t[2]
Related
This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Order of operations for pre-increment and post-increment in a function argument? [duplicate]
(4 answers)
function parameter evaluation order
(5 answers)
Closed 4 months ago.
I'm new to C and I'm writting some simple stuff to get familiar. I just tried pre-increment on an array index and what I got was really not what I was expecting.
The code in question:
#include <stdio.h>
int main()
{
int array[5] = {1,2,3,4,5};
int i = 0;
printf("%d %d",array[i], array[++i]);
return 0;
}
which should display elements of array[0] and array[1], right?
But it doesn't, as the output is 2 2
What am I missing?
Here's the thing: You can't guarantee what order function arguments are evaluated in.
What this means is, in your printf call, there's no way to tell whether array[i] or array[++i] will be evaluated first. In your case it appears that array[++i] won, so what happens is that you end up printing array[1] twice.
That's not a good use of pre-increment.
If you want to look at array[i] and array[i+1], just do that:
printf("%d %d\n", array[i], array[i+1]);
Remember, i++ does not just take i's old value and add 1 to it. It takes i's old value, and adds 1 to it, and stores the new value back into i. When you were printing array[i] and array[i+1], did you really want to change the value of i?
If you did want to change the value of i — or, in any case, since that mention of array[i++] did change the value of i — you introduced undefined behavior. Once you've got an expression that's modifying the value of i, how do you know what array[i] will print? How do you know that array[i] won't end up using the new value of i? You probably assumed that things are evaluated from left to right, but it turns out that's not necessarily true. So weird, weird things can happen.
Here's an example that helps show how ++ works, and that's well-defined:
#include <stdio.h>
int main()
{
int array[5] = {1,2,3,4,5};
int i = 1;
array[i++] = 22;
array[++i] = 44;
for(i = 0; i < 5; i++)
printf("%d: %d\n", i, array[i]);
return 0;
}
Or, as you suggested in a comment, if you did want to modify i's value, perhaps to advance the variable i along the array, you sometimes have to take care to move the i++ into a separate statement. The simple rule is, if you're applying ++ or -- to a variable, you can only use that variable once in the same statement. So you can't have i++ + i++, since that has two i's in it and they're both modified. But you also can't have i + i++, or f(a[i], a[i++]), since those have a spot where you modify i, and a spot where you use i, and there's no way to know whether you use the old or the new value of i. (And, again, in C there's not a general left-to-right rule that helps you here.)
This question already has answers here:
Array index out of bound behavior
(10 answers)
Closed 7 years ago.
I want ask about define array of pointers in C.
In following code, I define two pointers to char and then I assign each pointer to return from strtok function.
#include<stdio.h>
#include<string.h>
main()
{
char *s[2], string[]="hehe hihi keke kaka huhu hixhix",delimit[]=" ";
int i=0;
s[i]=strtok(string,delimit);
while( s[i]!=NULL )
{
printf("i=%d -> %s \n",i,s[i]);
++i;
s[i]=strtok(NULL,delimit);
}
}
This is output:
i=0 -> hehe
i=1 -> hihi
i=2 -> keke
i=3 -> kaka
i=4 -> huhu
i=5 -> hixhix
So, I just define two pointers but the code run with no error when i is greater then 1.
Why it work well even when I just define less number of pointers than necessary pointers (eg: 6 or greater) ?
thanks for reading!
Sometimes, it is the case that when you are out of the array area you are in fact changing some unhappy neighbor variable, or some return address.
(In your example you are probably destroying "string" after used.)
In this situation "working well" is much worst then a segmentation fault.
The error, the variable changed, will come to you later, with some unpredictable random behavior always in the worst moment, ( similar situations, were detected in some very big disasters )
Using an invalid index of an array will lead to Undefined Behavior which means that anything can happen. It needn't necessarily "work" as expected or not, or make the program crash or format your hard disk. Anything can happen.
This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 9 years ago.
#include<stdio.h>
#include<stdlib.h>
int main() {
int a=3;
//case 1
printf("%d %d %d\n",(--a),(a--),(--a));//output is 0 2 0
printf("%d\n",a);//here the final value of 'a'
//end of case 1
a=3;
//case 2
printf("%d\n",(++a)+(a--)-(--a));//output is 5 value of a is 2
printf("%d\n",a);//here the final value of 'a'
//end of case 2
a=3;
//case 3
printf("%d\n",(++a)*(a--)*(--a));//output is 48 value of a is 2
printf("%d\n",a);//here the final value of 'a'
//end of case 3
//case 4
int i=3,j;
i= ++i * i++ * ++i;
printf("%d\n",i);//output is 81
i=3;
j= ++i * i++ * ++i;
printf("%d\n",j);//output is 80
//end of case 4
return 0;
}
I am clear with how these outputs are coming as I spent nearly 3 hours in it gazing at it , but all I want to know in detail is that why it is being taken or evaluated in this manner.
This was tricky one to judge printf evaluates from right to left so first
--a pushes 2 , next a-- pushes 2 again as it is post then a becomes 1 , then --a makes first a 0 and then pushes that to and all i guessed that the output would be 0 2 2 but to my surprise it was 0 2 0 then i get it that the final value of a=0 is given to all the places where i used pre increment and decrement . Why this happens ?
This i take it as normal evaluation and then printing a is made 4 then in a-- again a is taken as 4 and again in --a a is taken as 3 so 4+4-3=5 done then final value of a happens to be one -1 from the post decrement that was done in the middle so a becomes 2 again Why this is happening ?
This execution is same as above and takes 4 * 4 * 3 = 48 and final a value is 2.
This is not tricky but i want the answer to it in detail what i figured is that first i becomes 4 in ++i and at i++ i becomes 4 and then at ++i i becomes 5 and so then 4*4*5 = 80 in this case i store it in i itself and then so i becomes 80 and then one +1 for the post increment. So i can one clear decision when i store 80 in another variable j and then saw it was 80 and the final i value was 6.
So logically I judged from just printing and viewing things in all these cases and are yet more which are completely based in this to come i can go on posting SO WHAT I WANT IS THAT AT ASSEMBLY LEVEL HOW IT IS HAPPENING AND WHY like IT TAKES POST INCREMENT AS A SEPARATE STATE OR SOMETHING how can different programs like this can be judged generically for each i cannot keep printing and finding the pattern can somebody help me in detail here. And the worst part was that i just executed the code in ideone and gives me completely different output you can even test at ideone if you are interested so why these happens please someone tell me i am breaking my head at this thing for 3 hours help me professionals.And i used gcc compiler.
This is all undefined behavior modifying a variable more than one in between sequence points in this in this case within the same expression is not allowed. So you can not rely on the output of this program at all.
From the c99 draft standard 6.5.2:
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.
it cites the following code examples as being undefined:
i = ++i + 1;
a[i++] = i;
This question already has answers here:
Undefined behavior and sequence points
(5 answers)
Closed 9 years ago.
I am solving a problem that reads a set of text lines and prints the longest.
The problem is from K&R "The C programming language" section 1.9. The book provides a solution but I tried to solve it in my own way. The code below works but before I get it to work, I was getting a problem due to the line longestStr[i++] = tmpStr[j++] as I have previously used longestStr[i++] = tmpStr[i++] thinking that i would be incremented once the assignment was done. But that was not the case. Is this how postfix operator normally works?
#include <stdio.h>
#define MAXLINE 100
main()
{
int lineLength = 0, longestLine = 0;
int c, i, j;
char longestStr[MAXLINE];
char tmpStr[MAXLINE];
while((c = getchar()) != EOF)
{
tmpStr[lineLength++] = c;
if(c == '\n')
{
if( lineLength > longestLine)
{
longestLine = lineLength;
i = 0, j = 0;
while(i < lineLength)
{
longestStr[i++] = tmpStr[j++]; // I tried longestStr[i++] = tmpStr[i++] but it gives wrong result
}
}
lineLength = 0;
}
}
printf("Longest line is - %d long\n", longestLine-1);
for(i = 0; i < longestLine-1; i++)
printf("%c", longestStr[i]);
putchar('\n');
}
The postfix increments or decrements are operators that perform the increment or decrement after the use of the variable, such that if you wish to use a integer value to print out and add it at the same time you would use postfix.
int i = 0;
printf("%d",i++);
//prints out 0
Prefix increment/decrement however works in the opposite manner such that it performs the increment/decrement prior to the use of the variable, such that if you wish to increment/decrement a variable before printing it out, you would use prefix
int i = 0;
printf("%d",++i);
//prints out 1
The problem you have is not related to how the postfix operator works, but rather to what you intend to do in the code line which gives you a problem.
As asked in the comments, what is the meaning of the line as you wrote it initially?
longestStr[i++] = tmpStr[i++];
Because the C standard does not specify it, this line can be interpreted in several ways:
longestStr[i] = tmpStr[i+1];
i += 2;
or
longestStr[i+1] = tmpStr[i];
i += 2;
or
longestStr[i] = tmpStr[i];
i += 2;
In every case, you end up with a counter incremented twice, which will mess up your algorithm.
The correct way is to increment the counter in a separate line, or use the working solution (you are providing), which should be compiled down to the same code with any decent compiler.
Note that you should probably check for the counter not going beyond the maximum allowed line size MAXLINE (unless the problem states that this cannot happen with the input, but even in that case, it would be helpful for situations like yours, where the code wrongly increment the counter twice).
try to understand how post fix increment works.
f(i++) is equivalent to the operation 'call f on the current value of i, then increment i'
For example, when you use i++ twice, and initial value of i = 1, a(i++) = b(i++) means, a(1)=b(2) and the value of i after the operation is i=3.
If you want to eliminate one variable in what you are trying to do, you have to make sure you use increment only once. Do it like, a(i)=(b(i); i++
Whereas the postfix increment operator evaluates the original value, it is understandable to think the actual incrementating doesn't happen until sometime down the road. However this is not the case. You should conceptualize postfix as if the incrementing is happening while the original value is being returned.
The bigger issue though is that your statement increments i twice. This means i will increase by two with each iteration of your loop. Futhermore your index values will be off by one from each other, That's because if a variable changes during one part of statement evaluation, those changes become instantly visible to parts of the statement which have not yet evaluated.
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.