0

The output of the below code is 660 44 352 660 . My question is how does the element() function return the value of k without a return statement. Can someone explain the logic behind it

#include <stdio.h>

int k = 9;

int element(int a, int b) {
    k = k + (a * b);
}
    
int main() {
    int a = 12, b = 5, c = 7;
    a = element(c, b);
    b = element(a, c);
    c = element(a, c);
    printf("%d ", k);
    printf("%d ", a);
    printf("%d ", b);
    printf("%d ", c);
}
  • 1
    Please see [Function returns value without return statement](https://stackoverflow.com/questions/4644860/function-returns-value-without-return-statement) – Weather Vane Sep 28 '22 at 11:21
  • In addition to the answers and comments: Your code is wrong at multiple levels: - modifying a global variable in a function (bad coding practice),- no return statement for a non void function (extremely bad coding practice, for me this is plain wrong), - using return values from a non void function without return statement (invokes undefined behaviour) – Jabberwocky Sep 28 '22 at 11:45

2 Answers2

2

These statements

a = element(c,b);
b = element(a,c);
c = element(a,c);

invoke undefined behavior because the function returns nothing but the caller (main) tries to use its value.

From the C Standard (J.2 Undefined behavior)

— The } that terminates a function is reached, and the value of the function call is used by the caller (6.9.1).

On the other hand the function deals with the file scope variable k

int k = 9;
int element (int a,int b){
k = k+(a*b)
}

So this statement in ,main

print("%d ",k);

outputs the current value of the file scope variable k that in general can be indeterminate.

The output can be expected when for example the generated assembler code uses register AX or EAX to load the value of the variable k. This register is used in assembler to return a value from a called function. Nevertheless it's a matter of chance.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 1
    Perhaps re-word for better clarity. "invoke undefined behavior because the function returns nothing" **and** the caller uses the return value. Returning nothing, by itself, is not UB. It was unclear to me that the code and statement made that clear. – chux - Reinstate Monica Sep 28 '22 at 11:36
  • but the value of the variable c and variable k are equal how the value of variable c changes how? – Shiva Surya.S Sep 28 '22 at 11:42
  • @ShivaSurya.S It can be due to the generated assembler code when the function loads the value of the variable k in the register AX or EAX that is usually used to return a value from a function in assembler. – Vlad from Moscow Sep 28 '22 at 11:44
  • @ShivaSurya.S undefined behaviour is undefined. Undefined behaviour includes "apparently working fine". – Jabberwocky Sep 28 '22 at 11:47
  • @ShivaSurya.S it's all there in the link. – Weather Vane Sep 28 '22 at 12:32
1

k is a global variable. It is accessible (and modifiable) from anywhere is the code. In your case, it is modified at each call of the element function.

You actually have an error in your code: the element function is defined as int element (int a,int b), which mean it takes 2 int as arguments, and return an int, but you do not return anything, which is undefined behavior, meaning anything could happens (mostly bad things).

You should use compiler options to raise more warnings and errors to help you. For example with gcc, you can use -Wall to start with.

Fab-B
  • 41
  • 4
  • 1
    IIRC, not returning anything is _not_ UB - still bad coding. It is the caller using the "non"-return value that is UB. Had OP's code been `element(c,b);` and not `a = element(c,b);`, it would be OK. Good idea to enable all warnings. – chux - Reinstate Monica Sep 28 '22 at 11:34
  • 1
    can we predict that undefined behavior without compiling the code? – Shiva Surya.S Sep 28 '22 at 11:36
  • 2
    Sure we can _predict_, but UB is not specified to be consistent - it is _undefined_, so we might be wrong in our prediction. – chux - Reinstate Monica Sep 28 '22 at 11:41
  • 1
    When a function returns a value with a `return` statement, this value is stored in a place where the caller expects to retrieve it. This *place* is determined by the calling convention for your target architecture, a collection of rules called the ABI (application binary interface). In most current systems, the return value of type `int` is passed back to the caller in a specific register (eg: `%eax` for intel processors). In your case, the register happens to contain the updated value of `k`, so the program seems to work as expected, but by pure chance. – chqrlie Sep 28 '22 at 11:57