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).
Related
we are currently learning how Pointers work in C.
I have this very short code of a copymethod of Strings in C, that was given to us from a tutor. I tried to explain its function in my own words but I am unsure if I have understood it correctly and would appreciate if somebody could correct my mistakes and answer my questions about it.
void copy ( char ∗ source , char ∗ dest) {
while (∗dest++ = ∗source++);
}
"Copy is a function with 2 Paramaters source and dest, which are both pointers of type char. The function calls a while statement which sets the dereferenced dest, incremented by 1 * sizeof(char), equal to the dereferenced and incremented (by 1*sizeof(char)) source."
What exactly does the while statement do? From my understanding *dest means that I am getting the char which dest points to, is that correct? But why would a while statement only set 2 pointers equal to each other, I don't really get it.
I appreciate any help, thank you!
This is the terse way to write an implementation of strcpy.
It is equivalent to the longer, but easier to follow
while (*dest = *source) {
dest++;
source++;
}
*dest = *source copies one char from the source to the destination. The result is zero if a zero byte was copied, at which time the loop ends.
Adding the increment to the condition is possible because the pointer dereferenced is the pointer value before the increment.
First, you need to start evaluating the expressions from the inner to the outer side. An important thing is to take into consideration that the body of the loop is empty (the ; at the right parenthesis indicates that the loop is executing the null statement --do nothing--, so everything must happen in the test expression).
The expression in the while test is not a test for equity, but an assignment. The equals operator is written doubling the =, as in ==, while = is used to assign the value of the right subexpression to the variable on the left side.
The variable on the left side is *dest++. A bit complicated expression that includes a dereference operator * and an autoincrement operator ++. The ++ takes higher preference, so it is acted first: the pointer is incremented, and the value returned by this subexpression is the value of the pointer before it was incremented. This means that the value of the pointer being used is the one it had before the expression dest++ was evaluated, and the * operator states the char variable pointed to by dest. So the place where the value will be stored in the assignment is the value pointed to by dest, and the pointer will be incremented before the end of the whole expression ends --but after the value is used--. The right side of the assignment show what is going to be assigned. As the expression is the same, I will pass quickly over it. The value assigned is the one pointed to by the source variable. It is incremented once the value is taken, and the value stored in the place of dest is filled with the character of the variable pointed by src. After that, both pointers are incremented, so the next time the test expression is evaluated, the characters involved will be the next source assigned to the next destination character. So, in this point, when the loop will be finished? Well, the value of an assignment expression is precisely the value assigned to the destination target, so in this case is the character copied from source to destination. And the test will fail, when the character copied happens to be zero (or false in C terms). As you see, there's nothing left to be put in the body of the loop.
This sample is famous for being an example of how cryptic C can get to. It appears in the two editions of "The C programming language" of Kernighan & Ritchie, the inventors of the language, and is accompanied by a comment that says something more or less like this: This is a bit obscure but every programmer that is proud of being proficient at C coding must be capable of interpreting this with a bit of care. (indeed the loop variables in the source are one letter s and d, i think)
So i have this main:
#define NUM 5
int main()
{
int a[NUM]={20,-90,450,-37,87};
int *p;
for (p=a; (char *)p < ((char *)a + sizeof(int) * NUM); ) //same meaning: for (p=a; p<a+NUM;)
*p++ = ++*p < 60 ? *p : 0; //same meaning: *(p++)=++(*p)<60?*p:0;
for(p=a; (char *)p < ((char *)a + sizeof(int) * NUM); )
printf("\n %d ", *p++);
return 0;
}
And i need to find what is the output.
So after try to understand without any idea i run it and this is the output:
21
-89
0
-36
0
So i will glad to explanation how to solve this kind of questions (i have exam soon and this type of questions probably i will see..)
EDIT:
at the beginning i want to understand what the first forstatement doing:
This jump 1 integer ? and what this going inside the block ?
And what is the different between *p++ and ++*p
The question is similar to Why are these constructs (using ++) undefined behavior in C? although not an exact duplicate due to the (subtle) sequence point inside the ?: operator.
There is no predictable output since the program contains undefined behavior.
While the sub-expression ++*p is sequenced in a well-defined way compared to *p because of the internal sequence point of the ?: operator, this is not true for the other combinations of sub-expressions. Most notably, the order of evaluation of the operands to = is not specified:
C11 6.5.15/3:
The evaluations of the operands are unsequenced.
*p++ is not sequenced in relation to ++*p. The order of evaluation of the sub-expressions is unspecified, and since there are multiple unsequenced side-effects on the same variable, the behavior is undefined.
Similarly, *p++ is not sequenced in relation to *p. This also leads to undefined behavior.
Summary: the code is broken and full of bugs. Anything can happen. Whoever gave you the assignment is incompetent.
at the beginning i want to understand what the first for statement doing
This is what one would call code obfuscation... The difficult part is obviously this one:
(char *)p < ((char *)a+sizeof(int)*NUM);
OK, we convert p to a pointer to char, then compare it to another pointer retrieved from array a that points to the first element past a: sizeof(int)*NUM is the size of the array - which we could have gotten much more easily by just having sizeof(a), so (char*)p < (char*)a + sizeof(a)
Be aware that comparing pointers other than with (in-)equality is undefined behaviour if the pointers do not point into the same array or one past the end of the latter (they do, in this example, though).
Typically, one would have this comparison as p < a + sizeof(a)/sizeof(*a) (or sizeof(a)/sizeof(a[0]), if you prefer).
*p++ increments the pointer and dereferences it afterwards, it is short for p = p + 1; *p = .... ++*p, on the other hand first dereferences the pointer and increments the value it is pointing to (note the difference to *++p, yet another variant - can you get it yourself?), i. e. it is equivalent to *p = *p + 1.
The entire line *p++ = ++*p<60 ? *p : 0; then shall do the following:
increment the value of *p
if the result is less than 60, use it, otherwise use 0
assign this to *p
increment p
However, this is undefined behaviour as there is no sequence point in between read and write access of p; you do not know if the left or the right side of the assignment is evaluated first, in the former case we would assign a[i] = ++a[i + 1], in the latter case, a[i] = ++a[i]! You might have gotten different output with another compiler!!!
However, these are only the two most likely outputs – actually, if falling into undefined behaviour, anything might happen, the compiler might just to ignore the piece of code in question, decide not to do anything at all (just exit from main right as the first instruction), the program might crash or it could even switch off the sun...
Be aware that one single location with undefined behaviour results in the whole program itself having undefined behaviour!
Short answer: because of this line
*p++ = ++*p<60 ? *p : 0;
it is impossible to say how the program behaves. When we access *p on the right-hand side, does it use the old or the new value of p, that is, before or after the p++ on the left-hand side gets to it? There is no rule in C to tell us. What there is instead is a rule that says that for this reason the code is undefined.
Unfortunately the person setting the question didn't understand this, thinks that "tricky" code line this is something to make a puzzle about, instead of something to be avoided at all costs.
The only way to really understand this kind of stuff (memory management, pointer behaviour, etc.) is to experiment yourself. Anyway, I smell someone is trying to seem clever fooling students, so I will try to clarify a few things.
int a[NUM]={20,-90,450,-37,87};
int *p;
This structure in memory would be something like:
This creates a vector of five int, so far, so good. The obvious move, given that data, is to run over the elements of a using p. You would do the following:
for(p = a; p < (a + NUM); ++p) {
printf("%d ", *p);
}
However, the first change to notice is that both loops convert the pointers to char. So, they would be:
for (p=a;(char *)p<((char *)a+sizeof(int)*NUM); ++p) {
printf("%d ", *p);
}
Instead of pointing to a with a pointer to int the code converts pto a pointer to char. Say your machine is a 32bit one. Then an int will probably occupy four bytes. With p being a pointer to int, when you do ++p then you effectively go to the next element in a, since transparently your compiler will jump four bytes. If you convert the int pointer to a char instead, then you cannot add NUM and assume that you are the end of the array anymore: a char is stored in one byte, so ((char *)p) + 5 will point to the second byte in the second element of a, provided it was pointing at the beginning of a before. That is way you have to call sizeof(int) and multiply it by NUM, in order to get the end of the array.
And finally, the infamous *p++ = ++*p<60 ? *p : 0;. This is something unfair to face students with, since as others have already pointed out, the behaviour of that code is undefined. Lets go expression by expression.
++*p means "access p and add 1 to the result. If p is pointing to the first position of a, then the result would be 21. ++*pnot only returns 21, but also stored 21 in memory in the place where you had 20. If you were only to return 21, you would write; *p + 1.
++*p<60 ? *p : 0 means "if the result of permanently adding 1 to the value pointed by p is less than 60, then return that result, otherwise return 0.
*p++ = x means "store the value of x in the memory address pointed by p, and then increment p. That's why you don't find ++p or p++ in the increment part of the for loop.
Now about the whole instruction (*p++ = ++*p<60 ? *p : 0;), it is undefined behaviour (check #Lundin's answer for more details). In summary, the most obvious problem is that you don't know which part (the left or the right one), around the assignment operator, is going to be evaluated first. You don't even know how the subexpressions in the expression at the right of the assignment operator are going to be evaluated (which order).
How could you fix this? It would be actually be very simple:
for (p=a;(char *)p<((char *)a+sizeof(int)*NUM); ++p) {
*p = (*p + 1) <60 ? (*p + 1) : 0;
}
And much more readable. Even better:
for (p = a; p < (a + NUM); ++p) {
*p = (*p + 1) <60 ? (*p + 1) : 0;
}
Hope this helps.
Why does this code below compiles and executes but doesn't print anything in output,
int i = 0;
printf(i = 0);
but this gives a runtime error,
int i = 0;
printf(i = 1);
int i = 0;
printf(i = 0);
The first argument to printf must be a char* value pointing to a format string. You gave it an int. That's the problem. The difference in behavior between printf(i = 0) and printf(i = 1) is largely irrelevant; both are equally wrong. (It's possible that the first passes a null pointer, and that printf detects and handles null pointers somehow, but that's a distraction from the real problem.)
If you wanted to print the value of i = 0, this is the correct way to do it:
printf("%d\n", i = 0);
You have a side effect in the argument (i = 0 is an assignment, not a comparison), which is legal but poor style.
If you have the required #include <stdio.h>, then your compiler must at least warn you about the type mismatch.
If you don't have #include <stdio.h>, then your compiler will almost certainly warn about calling printf without a declaration. (A C89/C90 compiler isn't strictly required to warn about this, but any decent compiler should, and a C99 or later compiler must.)
Your compiler probably gave you one or more warnings when you compiled your code. You failed to include those warnings in your question. You also failed to show us a complete self-contained program, so we can only guess whether you have the required #include <stdio.h> or not. And if your compiler didn't warn you about this error, you need to find out how to ask it for better diagnostics (we can't help with that without knowing which compiler you're using).
Expressions i = 0 and i = 1 in printf function will be evaluated to 0 and 1 (and i will be initialized to 0 and 1) respectively. So above printf statements after their expression evaluation will be equivalent to
printf(0); // To be clear, the `0` here is not a integer constant expression.
and
printf(1);
respectively.
0 and 1 both will be treated as address in printf statements and it will try to fetch string from these addresses. But, both 0 and 1 are unallocated memory addresses and accessing them will result in undefined behavior.
printf requires a const char * for input, whereas you're giving it an int
printf awaits a format string as its first argument. As strings (char*) are nothing else than pointers, you provide an address as the first parameter.
After an address and an integer are implicitly converted into each other,
printf(i = 0)
is (from the perspective of printf) the same as:
printf( 0 )
which is the same as
printf( NULL ) // no string given at all
If you provide 0 as parameter, printf will gracefully handle that case and don't do anything at all, because 0 is a reserved address meaning nothing at all.
But printf( 1 ) is different: printf now searches for a string at address 1, which is not a valid address for your program and so your program throws a segmentation fault.
[update]
The main reason why this works is a combination of several facts you need to know about how char arrays, pointers, assignments and printf itself work:
Pointers are implicitly convertible to int and vice versa, so the int value 17 for example gets converted to the memory address 0x00000011 (17) without any further notice. This is due to the fact that C is very close to the hardware and allows you to calculate with memory addresses. In fact, internally an int (or more specific: one special type of an integer) and a pointer are the same, just with a different syntax. This leads to a lot of problems when porting code from 32bit to 64bit-architecture, but this is another topic.
Assignments are different from comparations: i = 0 and i == 0 are totally different in meaning. i == 0 returns true when i contains the value 0 while i = 0 returns... 0. Why is that? You can concatenate for example the following variable assignments:
a = b = 3;
At first, b = 3 is executed, returning 3 again, which is then assigned to a. This comes in handy for cases like testing if there is more items in an array:
while( (data = get_Item()) )
This now leads to the next point:
NULL is the same as 0 (which also is the same as false). For the fact that integers and pointers can be converted into each other (or better: are physically the same thing, see my remarks above), there is a reserved value called NULL which means: pointing nowhere. This value is defined to be the virtual address 0x00000000 (32bit). So providing a 0 to a function that expects a pointer, you provide an empty pointer, if you like.
char* is a pointer. Same as char[] (there is a slight logical difference in the behaviour and in the allocation, but internally they are basically the same). printf expects a char*, but you provide an int. This is not a problem, as described above, int will get interpreted as an address. Nearly every (well written) function taking pointers as parameters will do a sanity check on these parameters. printf is no exclusion: If it detects an empty pointer, it will handle that case and return silently. However, when providing something different, there is no way to know if it is not really a valid address, so printf needs to do its job, getting interrupted by the kernel when trying to address the memory at 0x00000001 with a segmentation fault.
This was the long explanation.
And by the way: This only works for 32-bit pointers (so compiled as 32-bit binary). The same would be true for long int and pointers on 64-bit machines. However, this is a matter of the compiler, how it converts the expression you provide (normally, an int value of 0 is implicitly cast to a long int value of 0 and then used as a pointer address when assigned, but vice versa won't work without an explicit cast).
Why does this code below compiles and executes but doesn't print anything in output?
printf(i = 0);
The question embodies a false premise. On any modern C compiler, this clearly-erroneous code generates at least one error.
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)
I do not understand what is the point in the else sentence *nombre=(*nombre)++.
Output shows "fernando" and what i thought it was going to show was "ffsoboep" because of the sum. But it seems that *nombre=(*nombre)+1 is different to *nombre=(*nombre)++;
My question is why is that happening? how does "++" operator works in that case. Thanks.
void recursiva (char * nombre)
{
if (*nombre != '\0')
{
recursiva(nombre+1);
if(*nombre > 'A' && *nombre < 'Z')
{
*nombre=*nombre | 32;
}
else
{
*nombre=(*nombre)++;
printf("%c \n",*nombre);
}
}
}
int main()
{
char nombre[]="Fernando";
recursiva(nombre);
printf("%s",nombre);
}
(*nombre)++
doesn't mean the same thing as
*nombre + 1
It means "return the original value of *nombre, with the side effect of increasing *nombre's value by 1". Note that when exactly the value of *nombre increases is rather vague; while it happens after the value of (*nombre)++ is computed, it might happen before, after, or during the assignment to *nombre, with unpredictable results.
If you want to increase the value of *nombre, you don't need to assign the value of (*nombre)++ back to *nombre, and in fact, trying to do so is undefined behavior. As a first approximation, the program is allowed to do anything, up to and including making demons fly out your nose. Just use ++:
(*nombre)++;
or += 1:
*nombre += 1;
I ran your code and actually got "ffsoboep".
If you see that in other compilers you get "fernando", I believe that the following point is not defined in the standard:
*nombre=(*nombre)++;
This is post increment. The value of (x++) is the value of x before the increment (i.e., x == x++ is true).
The question is when does the increment is done.
If the increment is done immediately or after the evaluation of the right side of the = expression, then you first increment the value, and then re-assign the value of the expression (*nombre)++ (which is the value before the increment) to the already incremented *nombre.
If the increment is done, after all the expression is evaluated, then you first assign the (same) value to *nombre, and only then increment.
I think this is not defined in the standard, and therefore - you might see different behaviours. I encountered similar case in the past.