8

C programming language, compiled with gcc, terminal bash in WSL

I have written a recursive function, to find the lowest number in an array, which works just fine.

/*01*/    int minimo(int array[], int n)
/*02*/    {
/*03*/      static int min = 0;
/*04*/    
/*05*/      if (n == N)
/*06*/      {
/*07*/          return array[n-1];
/*08*/      }
/*09*/      else
/*10*/      {
/*11*/          min = minimo(array, n+1);
/*12*/          if(array[n]<min){
/*13*/              min = array[n];
/*14*/          }
/*15*/      }
/*16*/    }

The only problem is that it shouldn't work, because it doesn't return "min" to the caller...

int main()
{
    //Var
    int array[N] = {10, 2, 5, 1, 7};
    printf("Min: %d\n", minimo(array, 0));
}

My concern is actually a problem, but not on my machine onto which the function works just fine as it is; it is a problem on my friends' laptops and IDEs, I tried copying to XCode on a friend's Macbook and it wouldn't work if the line "return min;" wasn't added at the end of the function.

Between line 15-16 I have to add return min;

/*15*/      }
            return min;
/*16*/    }

My questions for you are the following:

  1. How can a function return a variable automatically?
  2. Is it possible that it does return the only variable that I created (static int min)?
  3. Or is it a "problem" related to the static attribute that the variable has?
  4. Does it have anything to do with the nature of the function (recursive)?

This is my first post, please be kind if I'm breaking any forum rule.

alk
  • 69,737
  • 10
  • 105
  • 255
lnk3
  • 513
  • 1
  • 4
  • 6
  • Read through SO question: https://stackoverflow.com/q/204476/8339821 and the answers. This will get you to the point what does your `main` function return. – user14063792468 Feb 14 '20 at 10:08
  • At the first sight it seems like a WSL specific thing, not to gcc-specific. It seems that WSL automatically "thinks" for you and correct the code on its own hand. – RobertS supports Monica Cellio Feb 14 '20 at 10:08
  • @ЯрославМашко This is a completely different thing and has nothing to do with this question. The problem isn´t about the return value of `main` it is about the "automatic" return value of a function in a specific implementation. – RobertS supports Monica Cellio Feb 14 '20 at 10:09
  • @RobertSsupportsMonicaCellio Yeah, you are right. I read through the question again and I got that the SO wants to know what does his function _really_ return. I thought that he somehow misses the return from main. Then this answer gives full information on the subject: https://stackoverflow.com/a/1610454/8339821. The main point is in that, that some particular `C` standard returns zero in the absense of a return statement. – user14063792468 Feb 14 '20 at 10:13
  • You should compile you file with a `-Wall` switch and see what does the compiler tells you. – user14063792468 Feb 14 '20 at 10:18
  • Turn on your compiler warnings, and mind them. Any half-decent compiler should warn you about that with the proper flags. – pmg Feb 14 '20 at 10:18
  • Please do have in mind, that, if the supplied answer did answer your question, you should mark it as accepted. This way others, who will find your question, will know that the anser did solve your problem. – user14063792468 Feb 14 '20 at 10:26
  • @Ink3: add `-Werror -Wall -Wextra` to your compiler settings, that should be the first thing you do when you start a new project. It will [prevent](https://godbolt.org/z/nsYWko) things like this from happening. – vgru Feb 14 '20 at 11:30
  • Decompile your code and you'll see that the value of `min` is most likely in the EAX (RAX on x64) register, which is also used to return the value. As others have stated, this is fully undefined behaviour. – Hristo Iliev Feb 14 '20 at 11:31

4 Answers4

5

My concern is actually a problem, but not on my machine onto which the function works just fine as it is; it is a problem on my friends' laptops and IDEs, I tried copying to XCode on a friend's Macbook and it wouldn't work if the line "return min;" wasn't added at the end of the function.

Typical example of undefined behavior. Works on one machine but not another. Works at daytime but not nighttime. Works with one compiler but not another. When you invoke undefined behavior, the C standard imposes no requirements on how the code should behave.

C11 standard 6.9.1.12

If the } that terminates a function is reached, and the value of the function call is used by the caller, the behavior is undefined.

In your code, that is precisely what happens. You invoke undefined behavior when you try to print the return value.

Contrary to what many believes, it IS completely allowed to omit the return statement in a non-void function. It only becomes undefined behavior if you try to use the non-existent return value.

To avoid this, always compile with at least -Wall -Wextra.

klutt
  • 30,332
  • 17
  • 55
  • 95
  • @JonathonReinhart Well, that's the kind of discussion that requires beer. :) – klutt Feb 14 '20 at 13:40
  • 1
    @JonathonReinhart The important thing is to actually care for the warnings. If the coder don't care and is using `-Werror` SO gets a question with "Why does this not compile?" and without it "Why does this behave strange?" While I agree that that parameter is a good thing, it kind of misses the target. – klutt Feb 14 '20 at 13:45
  • 1
    My feeling is that `-Werror` prevents unnecessary SO questions like this one, because the user is *forced* to care about the warnings when they don't have a broken executable to run :-) – Jonathon Reinhart Feb 14 '20 at 14:43
  • 2
    Maybe GCC should, by default, simply present error messages in HTML format with the Stack Overflow theme, and embedded search results – Jonathon Reinhart Feb 14 '20 at 14:45
  • @JonathonReinhart OMG, that would be such a hilarious mod. – klutt Feb 14 '20 at 15:04
2

How can a function return a variable automatically?

It follows the protocol. It knows that the return of the function should find the returned value at some location and an explicit return from that function will fill that location. If you do not call return, some random value will be preserved at the given location.

Is it possible that it does return the only variable that I created (static int min)?

No, it is undefined what it returns. It can be whatever.

Or is it a "problem" related to the static attribute that the variable has?

Again, what it returns is undefined.

Does it have anything to do with the nature of the function (recursive)?

Yes and no. If the function is defined as external the returned value follows another protocol as in the case of static functions.

It can happen anything in the final code, the C language does not impose the way of implementing a function, be it recursive or not. For example, in case the function is recursive and can be precomputed, only the final value can be replaced at the place of call. This is also correct as time as the final result of the program is the expected result, conforming to the operational semantics that defines C in ISO9899.

I quote from the official document:

4 In the abstract machine, all expressions are evaluated as specified by the semantics. An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced (including any caused by calling a function or accessing a volatile object).

It also can replace a call with the value of that call and this is correct.

So at all your questions, the answer is undefined behavior.

alinsoar
  • 15,386
  • 4
  • 57
  • 74
1

How can a function return a variable automatically?

I happens by chance, min variable happens to be in the correct return register for the ABI.

Is it possible that it does return the only variable that I created (static int min)?

I think it is more related to it having being used just before function exit, but I am guessing here: this is not a C language defined behavior, and it worked by chance.

Or is it a "problem" related to the static attribute that the variable has?

Does it have anything to do with the nature of the function (recursive)?

Since this was a chance behavior, could be or not. The difference between random and deterministic is that you have so many variables that you give up explaining.

Community
  • 1
  • 1
lvella
  • 12,754
  • 11
  • 54
  • 106
-3

I suppose you defined N somewhere (probably N=5 in you case).

Most compilers automatically adds "return 0" statement if return statement is missing.

* See comments for more info. Actually it is an Undefined Behavior*

In you recursive function, is better to pass the remaining length of the array and stop when you reach n==0.

Avoid to look at global variables or defines inside functions.

int minimo(int array[], int n)
{
  ...
  if (n == 0)
  ...
            min = minimo(array, n-1);
  ...
}

(other modification required)

Actually you should know the length of array only on main function, so call it as:

printf("Min: %d\n", minimo(array, N));
G. C.
  • 387
  • 2
  • 6
  • 5
    No! Except for `main()` in C99 (or later) implementations *(where a `return 0;` is added in the absence of a previous return statement)*, **failure to `return` is UB**. – pmg Feb 14 '20 at 10:20
  • @pmg somewhere on the SO i've read that wording goes down to `C89`. And that is a minimum I can get today. – user14063792468 Feb 14 '20 at 10:23
  • @ЯрославМашко: [C89](http://port70.net/~nsz/c/c89/c89-draft.html#2.1.2.2) has no mention of default return value; [C99](http://port70.net/~nsz/c/c99/n1256.html#5.1.2.2.3) (and similarly in [C11](http://port70.net/~nsz/c/c11/n1570.html#5.1.2.2.3)): "...reaching the } that terminates **the main function** returns a value of 0." (emphasis is mine) – pmg Feb 14 '20 at 10:31