About the expression statement(an example)
i = 1;
it is said that after assigning 1 to i the value of entire expression is being discarded. If the value is discarded then how this can be used later in the program,for example
printf("%d",i);
?
I know this is very basic question but I am really confused with discarded.
The value of the expression is indeed discarded, but this expression has a side effect - it changes the value of i. So next time you will access this variable, you will read the new value, which is 1.
The term "discarded" is more helpful when you do things like foo(5); or even simply "hello";. Since the expression "hello" does not have any side effect, and its value is dicarded, it is does absolutely nothing. When a compiler encounters it, as a stand alone statement:
"hello";
It may simply ignore it altogether, as if it does not exist at all. This is what happens when you call functions, or use operators:
4+5;
sin(2.6);
These expressions, too, have no side effect, and their values are ignored. When you do something like
printf("hello");
This is an expression, too. Its value is the total number of characters written. This value is ignored. But the expression must not be comletely ignored, since it has an important side effect: it prints these characters to the standard output.
So let's build a function instead of using the assignment operator (since C has no references, we'll use pointers):
int assign_int(int* var, int value) {
*var = value;
return *var;
}
now, back to your example, you do something like:
assign_int(&i, 1);
the value returned from assign_int is discarded. Just like in the printf() case. But since the function assign_int has a side effect (changing the value of i), it is not ignored by the compiler.
The important point is the i = 1 has two properties.
It changes the value stored in the variable i to be 1
It is an expression and has a value (which is also 1);
That second part is interesting is a case like
if ( (i=1) == 2 ) { // ...
or
y = 3 + (i = 1); // assign 4 to y
The line
the value of entire expression is being discarded.
refers to the value of the expression (my #2), but does not affect assignment to variable i (my #1).
Related
My question pertains to function calls in general, but I thought of it
while I was writing a priority queue using a heap. Just to give some context (not that it matters much) my heap stores items top to bottom left to right and I represent the heap as an array of structures. Upon inserting a new item, I just put it in the last place in the heap and then call the function "fix_up" at the bottom which will move the item to the proper place in the heap. I am wondering if instead of doing...
fix_up(pQueue->heap, pQueue->size);
pQueue->size++;
...I could just do...
fix_up(pQueue->heap, pQueue->size++);
I am unsure as to if this is ok for a few reasons.
1) Since pQueue->size is in the function call, I'm not even sure if it's actually pQueue->size or rather a copy of the integer stored in pQueue->size. If it was a copy then obviously I wouldn't be adding 1 to the actual pQueue->size so there'd be no point in doing this.
2) Since it's a function call, it is going to then go into the function fix_up and execute all the code there. I am wondering if this would have an unintended consequence of maybe when it went to fix_up it would get incremented by 1 and my index would be 1 higher than I intended while executing fix_up? Or would it do what it's supposed to do and wait until after fix_up had finished executing?
3) Even if it is ok, is it considered a good coding practice for C?
Status priority_queue_insert(PRIORITY_QUEUE hQueue, int priority_level, int data_item)
{
Priority_queue *pQueue = (Priority_queue*)hQueue;
Item *temp_heap;
int i;
/*Resize if necessary*/
if (pQueue->size >= pQueue->capacity) {
temp_heap = (Item*)malloc(sizeof(Item) * pQueue->capacity * 2);
if (temp_heap == NULL)
return FAILURE;
for (i = 0; i < pQueue->size; i++)
temp_heap[i] = pQueue->heap[i];
pQueue->capacity *= 2;
}
/*Either resizing was not necessary or it successfully resized*/
pQueue->heap[pQueue->size].key = priority_level;
pQueue->heap[pQueue->size].data = data_item;
/*Now it is placed as the last item in the heap. Fixup as necessary*/
fix_up(pQueue->heap, pQueue->size);
pQueue->size++;
//continue writing function code here
}
Yes you can.
However, you cannot do this:
foo(myStruct->size++, myStruct->size)
The reason is that the C standard does not say in which order the arguments should be evaluated. This would lead to undefined behavior.
1) Since pQueue->size is in the function call, I'm not even sure if it's actually pQueue->size or rather a copy of the integer stored in pQueue->size. If it was a copy then obviously I wouldn't be adding 1 to the actual pQueue->size so there'd be no point in doing this.
Whatever argument you're sending to a function, it will be evaluated before the function starts to execute. So
T var = expr;
foo(var);
is always equivalent to
foo(expr);
2) Since it's a function call, it is going to then go into the function fix_up and execute all the code there. I am wondering if this would have an unintended consequence of maybe when it went to fix_up it would get incremented by 1 and my index would be 1 higher than I intended while executing fix_up? Or would it do what it's supposed to do and wait until after fix_up had finished executing?
See above
3) Even if it is ok, is it considered a good coding practice for C?
Somewhat subjective, and a bit OT for this site, but I'll answer it anyway from my personal view. In general, I would try to avoid it.
Though, the other posts already answer this question, but none of them talk about role of Sequence Point, in this particular case, which can greatly help in clarifying OP's doubt.
From this [emphasis mine]:
There is a sequence point after the evaluation of all function arguments and of the function designator, and before the actual function call.
From this [emphasis mine]:
Increment operators initiate the side-effect of adding the value 1 of appropriate type to the operand. Decrement operators initiate the side-effect of subtracting the value 1 of appropriate type from the operand. As with any other side-effects, these operations complete at or before the next sequence point.
Also, the post increment operator increase the value of operand by 1 but the value of the expression is the operand's original value prior to the increment operation.
So, in this statement:
fix_up(pQueue->heap, pQueue->size++);
the value of pQueue->size will be increased by 1 before the fix_up() function call but the argument value will be the original value prior to the increment operation.
Yes you can use it directly in the expression you pass as argument.
A statement like
fix_up(pQueue->heap, pQueue->size++);
is somewhat equivalent to
{
int old_value = pQueue->size;
pQueue->size = pQueue->size + 1;
fix_up(pQueue->heap, old_value);
}
A note about the "equivalent" example above. Since the order of evaluation of arguments to function calls is not specified, the actual increment of pQueue->size could happen after the call to fix_up. And it also means that using pQueue->size more than once in the same call would lead to undefined behavior.
Yeah you can use it in function calls, but please note that your two examples are not equivalent. The pQueue->heap argument may be evaluated before or after pQueue->size++ and you can't know or rely on the order. Consider this example :
int func (void)
{
static int x = 0;
x++;
return x;
}
printf("%d %d", func(), func());
This will print 1 2 or 2 1 and we can't know which we'll get. The compiler need not evalute the function parameters consistently throughout the program. So if we add a second printf("%d %d", func(), func()); we could get something like 1 2 4 3 as output.
The importance here is to not write code which relies on order of evaluation. Which is the same reason as mixing ++ with other operations or side-effects in the same expression is bad practice. It can even lead to undefined behavior in some cases.
To answer your questions:
1) Since pQueue->size is in the function call, I'm not even sure if it's actually pQueue->size or rather a copy of the integer stored in pQueue->size. If it was a copy then obviously I wouldn't be adding 1 to the actual pQueue->size so there'd be no point in doing this.
The ++ is applied to the variable in the caller, so this isn't an issue. The local copy of the variable happens during function call, independently of the ++. However, the result of a ++ operation is not a so-called "lvalue" (addressable data), so this code is not valid:
void func (int* a);
...
func(&x++);
++ takes precedence and is evaluted first. The result is not an lvalue and cannot have its address taken.
2) Since it's a function call, it is going to then go into the function fix_up and execute all the code there. I am wondering if this would have an unintended consequence of maybe when it went to fix_up it would get incremented by 1 and my index would be 1 higher than I intended while executing fix_up? Or would it do what it's supposed to do and wait until after fix_up had finished executing?
This isn't an issue unless the function modifies the original variable through a global pointer or such. In that case you would have problems. For example
int* ptr;
void func (int a)
{
*ptr = 1;
}
int x=5;
ptr = &x;
func(x++);
This is very questionable code and x will be 1 after the line func(x++); and not 6 as one might have expected. This is because the function call expression is evaluated and finished before the function call.
3) Even if it is ok, is it considered a good coding practice for C?
It will work ok in your case but it is bad practice. Specifically, mixing the ++ or -- operators together with other operators in the same expression is bad (although common) practice, since it has a high potential for bugs and tends to make code less readable.
Your original code with pQueue->size++; on a line of it's own is superior in every way - stick with that. Contrary to popular belief, when writing C, you get no bonus points for "most operators on a single line". You may however get bugs and maintenance problems.
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++;
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.
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!
I found a bug in code (the if statement should have had "==" instad of "=") and I have few questions.
Example code:
int i = 5;
if (i = MyFunction()) // MyFunction() returns an int; this is where bug was made
{
// call A()
}
else
{
// call B()
}
From what I gather it should always call A().
1. Is my assumption correct()?
2. Is this case for all/most compilers (any exceptions)?
No, it will only call A() if the assignment is considered true, i.e. non-zero.
Yes, this is standard. It's not a very good way to write the code since the risk of confusion is large.
Some people flip comparisons, writing the constant to the left, to avoid the risk:
if( 12 == x )
but of course this wouldn't have worked in your case, since it really is an assignment. Most compilers can give you a warning when this code is detected, since it's so often a cause of bugs.
If MyFunction() returns zero (0) it will call B(); otherwise it will call A(). The value of an assignment expression is the value that is assigned to the left hand side; in an if statement 0 is treated as false and all other values as true.
This is perfectly legitimate code, although many compilers will issue a warning. The reason it is valid is that in C and similar languages, assignment is an expression (rather than a statement).
If you intended to assign to i and test the return value you should write if ((i = MyFunction())); the extra parentheses signal to the compiler (and to the reader) that the assignment is intended.
If instead you intend to test against the value of i you should write if (MyFunction() == i); by putting the function call on the left you ensure that if you miss out the double equals sign the code will fail to compile (MyFunction() = i is not usually a valid expression).
This statement is an assignment:
i = MyFunction()
The if statement is in effect checking the value of i. If MyFunction() returns 0, i is assigned 0 and it becomes equivalent to:
if(0)
This evaluates to false, and A() will not be called in this case
It will take the true branch (i.e. call A) if the function return is non-zero. Zero is treated as false so if MyFunction() returns zero it will call B instead.
In practice, yes this is correct for most / all compilers. I think 0=false was just a convention; I wouldn't be surprised if it is now formalised in C99 or later but I don't have a copy handy to refer you to the right section.
Your assumption is incorrect.
The expression in the if-condition is evaluated like any other expression, in your case the result of (i = MyFunction()) is the return value of MyFunction().
You code will evaluate
(i = MyFunction())
and if MyFunction() returns a non zero value, the expression will be evaluated as true and call A(). Otherwise B()