I referred this link Pointer expressions: *ptr++, *++ptr and ++*ptr to understand pointer arithmetic.
Why the below code is going to infinite loop?
int main(){
int a[4] ={1,2,3,4};
int *ptr = a;
while (++*ptr){
printf("%d",*ptr);
}
}
Your code does not work for two reasons:
++*ptr increments the number, not the pointer
You are iterating an array instead of a C string
You can iterate a C string using while (*ptr++) expression for the loop condition. This little trick works for C strings because they are null terminated. In order to make it work for arrays you would need to put zero at the end of the array, and agree to not use zeros anywhere else in the array:
int a[4] ={1,2,3,4, 0};
int *ptr = a;
int last;
while (last = *ptr++) {
printf("%d", last);
}
Note that since we are incrementing the pointer in the header of the loop, we should store the last value pointed to by the pointer in a separate variable. Otherwise we'd skip over one array element.
in loop condition value is 0 that time only loop terminated but you just increment the first position of the array value so zero value will not occur.
The issue is in the following line. Your while will break only if the value of ++*ptr is false or 0. But it never becomes 0 or false.
++*ptr
so while(NON ZERO) will result in infinite loop.
The loop is "infinite" because the condition in the while statement is always true until you hit the maximum value int can hold and after that you get undefined behavior.
What happens in the line is:
while (++*ptr)
First the pointer is dereferenced *ptr, obtaining the value of the first element in the array a, then that value is incremented by one. And then that resulting value is evaluated, giving the true result.
The same happens on every loop, the pointer ptr keeps pointing to the same element, the first one ptr == &a[0] , and keeps incrementing the value of that element by one a[0] = a[0]+1.
You are incrementing the value of the corresponding 0th position. So the starting position value of array is incremented. So the loop executing infinitely. Make the while loop as following.
while(*(++ptr))
Related
This question already has answers here:
What is the difference between ++i and i++?
(20 answers)
Closed 4 years ago.
I was solving some multiple choice C codes from a book. Two of the questions involve pre decrementing, post decrementing a char variable initialised at 0. The output for both these is very different. I dont understand whats going on there.
Code 1
char i=0;
do
{
printf("%d ",i);
}while(i--);
return 0;
The output for this snippet is 0.
Code 2
char i=0;
do
{
printf("%d ",i);
}while(--i);
return 0;
The output is for this one is
0,-1,-2,.....-128,127,126,......1 .
Can anyone explain why this is happening?
At both code while loop checking i==0 or not. If i!=0it will keep going on.
At first code value of i initially 0. So after printing 0 it checks i==0 or not. if i==0 it will break the loop or keep going on by decrementing i. So in code 1 post decrementing used. check value first then decrements the value.
At second code value of i initially 0. So after printing 0 it decrements i then it checks if i==0 or not. it is pre decrement. decrement value first then check.
Here, i is char which size is 1 byte and range -128 to 127. So after decrementing value 0 to -1 it keep decrementing until it goes to 0 and exit the loop by printing 0,-1,...,-128,127...1 .
Code 1
char i=0;
do
{
printf("%d ",i); // print o
}while(i--); //check i = 0, means false, loop ends, then increment i
return 0;
Code 2
char i=0;
do
{
printf("%d ",i); //print 0
}while(--i); //decrement i, check i=-1, means true, next cycle, loop until i = 0 which means false
return 0;
Both i-- and --i are expressions. An expression is (part of) a statement that can yield a value. As per definition, the pre-increment version increments first, then yields the value. For the post-increment version it is the other way round.
This is completely independent of whether the expression is used in a while statement or elsewhere. However, when using such expressions, you need to be aware of operator precendence.
Initial value of i is 0.
In Code 1, first while check happens in which the value of i (= 0) is used and then i is decremented because it is postfix decrement. So it exits while after printing 0.
In Code 2, because it is prefix decrement, i is decremented first and its value (= -1) is used when the while check is performed. Here it exits after printing the entire range of values a signed char can hold because it becomes 0 at the end only.
Why exactly is a string literal in an if-condition treated as true?
if("whatiamreturning")
//this is true. I want to know y?
Based on the above, what happens here?
#include<stdio.h>
void main() {
static int i;
for(;;) { //infinite loop
if(i+++"The Matrix")
// what is happening in the above line?
printf("Memento");
else
break;
}
}
if("whatiamreturning")
is equivalent to
if (1)
This is because "whatiamreturning" is a char [] that decays into a non-NULL char const* inside the if(). Any non-NULL pointer evaluates to true in the context of a boolean expression.
The line
if(i+++"The Matrix")
can be simplified to:
if( (i++) + "The Matrix")
In the first iteration of the loop, the value of i is 0. Hence, the (i++) + "The Matrix" evaluates to "The Matrix".
In the second iteration of the loop, the value of i is 1. Hence, the (i++) + "The Matrix" evaluates to "he Matrix".
However, the loop never ends and goes into the territory of undefined behavior since (i++) + "The Matrix" never evaluates to 0 and the value of i keeps on increasing.
Perhaps they meant to use:
if(i++["The Matrix"])
which will allow the expression inside if() it to be 0 after 10 iterations.
Update
If you are following somebody else's code, stay away anything else that they have written. The main function can be cleaned up to:
int main() {
char name[] = "The Matrix";
int i = 0;
for( ; name[i] != '\0'; ++i )
{
printf("Memento\n");
}
}
if(i+++"The Matrix") // what is happening here please help here to understand
This will take the value of i, add the pointer value of the location of the string "The Matrix" in memory and compare it to zero. After that it will increase the value of i by one.
It's not very useful, since the pointer value could be basically any random number (it depends on architecture, OS, etc). And thus the whole program amounts to printing Memento a random number of times (likely the same number each run though).
Perhaps you meant to write if(*(i+++"The Matrix")). That would loop 10 times until it i+"The Matrix" evaluates to the address pointing to the NUL byte at the end of the string, and *(i+"The Matrix") will thus return 0.
Btw, spaces are a nice way to make your code more readable.
It will return the address of first element of the string whatiamreturning.
Basically when you assign a string literal to a char pointer
char *p;
p = "whatiamreturning";
the assignment doesn't copy the the characters in whatiamreturning, instead it makes p point to the first character of the string and that's why string literals can be sub-scripted
char ch = "whatiamreturning"[1];
ch will will have character h now. This worked because compiler treated whatiamreturning as a char * and calculated the base address of the literal.
if(i+++"The Matrix") is equivalent to
if( i++ + "The Matrix")
or it can be rewritten as
if(&("The Matrix"[i++]))
which will be true for every i and results in an infinite loop. Ultimately, the code will suffer from undefined behavior due to integer overflow for variable i.
Why exactly is a string literal in an if-condition treated as true?
if("whatiamreturning")
The string literal "whatiamreturning" is a constant of type char[].
In nearly all contexts, including this one, arrays decay to pointers to their first element.
In a boolean context, like the condition of an if-statement, all non-zero values are true.
As the pointer points to an object, it is not the null-pointer, and thus is true.
Based on the above, what happens here?
#include<stdio.h>
void main() {
The above is your first instance of Undefined Behavior, whatever happens, it is right.
We will now pretend the error is corrected by substituting int for void.
Now, your loop:
static int i;
Static variables are default initialized, so i starts with value 0.
for(;;) { //infinite loop
if(i+++"The Matrix")
// what is happening in the above line?
printf("Memento");
else
break;
}
This loop has Undefined Behavior as well.
The condition takes i and adds it to the string literal "Memento" which decayed to a pointer like in the previous example, interpreting the resultant pointer in a boolean context, and as a side-effect incrementing i.
As long as i is no more than strlen("The Matrix")+1 on entry, everything is ok, the pointer points to an element of the string literal or one past, and the standard guarantees that's not a null pointer.
The moment it is though, all hell breaks loose because calculating such a pointer is Undefined Behavior.
Well, now that we know the loop is UB, let's ignore the loop too.
The rest of the program is:
}
Which is ok, because even though main has a return type of int, there's a special rule which states that if control reaches the end of main without executing a return-statement, an implicit return 0; is added.
Side-note: If an execution of a program encounters Undefined Behavior anywhere, the whole program is undefined, not only from that point on:
Undefined behavior can result in time travel (among other things, but time travel is the funkiest)
Shouldn't the output of the following code be f
I get an output e
#include<stdio.h>
void main(){
char arr[]="Geeks";
char *ptr = arr;
++*ptr++;
printf("%c\n",*ptr);
}
No, it shouldn't. Your code increments the first character and then moves the pointer one forward. The pointer will point to the first e, and depending on your locale/character encoding, the first letter is most probably H. The expression is parsed according to precedence and associativity rules as:
++(*(p++))
Yes expression is parsed as ++*((ptr++)), first ptr++ is calculated but because it is postfix increment the new calculated value doesn't update the old value of ptr until the statement ends (;) . Next ++**( ptr++ ) is calculated on old value of ptr that result , G change to H. Now all work is done, the statement ends and ptr value is updated, that points to next element that is e.
What does the below code do? I'm very confused with its working. Because I thought that the if loop runs till the range of int. But I'm confused when I try to print the value of i. Please help me out with this.
#include<stdio.h>
void main()
{
static int i;
for (;;)
if (i+++”Apple”)
printf(“Banana”);
else
break;
}
It is interpreted as i++ + "Apple". Since i is static and does not have an initializer, i++ yields 0. So the whole expression is 0 + some address or equivalent to if ("Apple").
EDIT
As Jonathan Leffler correctly notes in the comments, what I said above only applies to the first iteration. After that it will keep incrementing i and will keep printing "Banana".
I think at some point, due to overflows (if it doesn't crash) "Apple" + i will yield 0 and the loop will break. Again, I don't really know what a well-meaning compiler should do when one adds a pointer and a large number.
As Eric Postpischil commented, you can only advance the pointer until it points to one-past the allocated space. In your exxample adding 7 will advance the pointer one-past the allocated space ("Apples\0"). Adding more is undefined behavior and technically strange things can happen.
Use int main(void) instead of void main().
The expression i+++"Apple" is parsed as (i++) + "Apple"; the string literal "Apple" is converted from an expression of type "6-element array of char" to "pointer to char", and its value is the address of the first element of the array. The expression i++ evaluates to the current value of i, and as a side effect, the value in i is incremented by 1.
So, we're adding the result of the integer expression i++ to the pointer value resulting from the expression "Apple"; this gives us a new pointer value that's equal or greater than the address of "Apple". So assuming the address of the string literal "Apple" is 0x80123450, then basically we're evaluating the values
0x80123450 + 0
0x80123450 + 1
0x80123450 + 2
...
all of which should evaluate to non-zero, which causes the printf statement to be executed. The question is what happens when i++ results in an integer overflow (the behavior of which is not well defined) or the value of i+++"Apple" results in an overflow for a pointer value. It's not clear that i+++"Apple" will ever result in a 0-valued expression.
This code SHOULD Have been written like this:
char *apple = "Apple";
for(i = 0; apple[i++];)
printf("Banana");
Not only is it clearer than the code posted in the original, it is also clearer to see what it does. But I guess this came from "Look how bizarre we can write things in C". There are lots of things that are possible in C that isn't a great idea.
It is also possible to learn to balance a plate of hot food on your head for the purpose of serving yourself dinner. It doesn't make it a particularly great idea - unless you don't have hands and feet, I suppose... ;)
Edit: Except this is wrong... The equivalent is:
char *apple = "Apple";
for(i = 0; apple+i++ != NULL;)
printf("Banana");
On a 64-bit machine, that will take a while. If it finishes in reasonable time (sending output to /dev/null), I will update. It takes approximitely three minutes on my machine (AMD 3.4GHz Phenom II).
int my_array[] = {1,23,17,4,-5,100};
int *ptr;
int i;
ptr = &my_array[0]; /* point our pointer to the first
element of the array */
printf("\n\nptr = %d\n\n", *ptr);
for (i = 0; i < 6; i++)
{
printf("my_array[%d] = %d ",i,my_array[i]); /*<-- A */
printf("my_array[%d] = %d\n",i, *(ptr++)); /*<-- B */
}
Why does this display the same thing for both line a and b? It just displays all of the values in my_array in order (1, 23, 17, 4, -5, 100). Why does the '++' in line B not point ptr to the next element of the array before it is dereferenced? Even if you change that line to
printf("ptr + %d = %d\n",i, *ptr++); /*<-- B */
the output is the same. Why is this?
ptr++ increments ptr but returns the original value
++ptr increments and returns the new value
Hence the joke about c++ - it's one more than c but you use the original value = c
It seems you are puzzled by the fact that the parenthesis do not change the value returned as you expectd.
Maybe it would be clearer to you if you think it in English:
p++ means take the value of p, increment the value of p, return the initial value of p
so, *p++ would dereference the original value of p.
Considering that the value of (x) is the same as x, the value of (p++) is the same as p++.
Hence, *(p++) will dereference p, exactly as *p++ does.
It is evident from the naming post-increment and pre-increment. Meaning, the variable is incremented post the operation or before the operation.
A post-increment operator creates a temporary variable to store the current value and increments the variable (but returns the temporary variable with current value). In pre-increment operator, there is no temporary variable. The same variable is incremented and returned.
So using post-increment operator in the same statement, means using the current value of the variable and incrementing after this statement. Whereas post-increment operator means incrementing the variable and using it in the current statement.
In C there is a difference between post incrementing p++ and preincrementing ++p
p++ : uses the current value of p and then updates it
++P: updates the value of p and then uses it
hence your code should use ++ptr
There are 2 types of operators : Postfix and Prefix .
*ptr++ is postfix operator means first use and then increase
while ++ptr means prefix operator means first increase and then use.
if you add another printf with printing the value of just *ptr in your existing code you will notice the difference how the things go about.
To avoid this whole issue, write either of these alternatives:
++ptr;
printf("my_array[%d] = %d\n",i, *ptr);
or
printf("my_array[%d] = %d\n",i, *ptr);
++ptr;
This will yield the same number of instructions, but with the following major advantages:
Is now more readable and understandable.
If ptr would be used several times in the printf() statement, you need not worry about the order of evaluation of function parameters or operands, which are unspecified in the C language (with a few rare exceptions). Had you writted printf("%d %d", *++ptr, *++ptr); you can't know the result, as the code would then rely on order of evaluation, i.e. it contains a possibly severe bug.