Given that you tagged this with the "C" keyword, it is worth saying that the intent in the early days of C was that the return value, as an integer or a pointer, should fit in a processor register, so no memory is allocated to storing the value.
The calling function may need to declare a variable to store the result into, and it is responsible for that allocation. Immediately on return from the function the caller will stash that agreed processor register value into the memory it has reserved. Of course, that may not be necessary if the value is used immediately for some other calculation.
When returning a pointer, what the pointer points to is a problem for the programmer: you. As you have found, if you try to access a value you only declared as a local variable in the called function and returned using a pointer, the local variable space - the function call stack - is heavily reused, and your value will quickly be junked.
Of course, you can return floating point values and structs in modern C and C++, which often needs different handling. Usually the caller function has to reserve space for the called function to store these larger objects into.
Note that the compilers are often able to inline and optimise code to use available registers, rather than repeatedly using the agreed registers, and sometimes even replace small structures with a set of registers.
Tools like godbolt can let you easily see what the compiler has done to your code.