Of course it's a huge error, which is why you should never do that. Instead, you pass the addresses of local stack variables to that function as pointer arguments and let that function write its outputs there. Voilà, multiple return values without heap allocations.
That's a bit of a stretch using the word 'return' there. Forgive my exactness, but return implies, well, returning a value from a function.
I'd say that Java has similar semantics to C. One can easily pass object references to a function that sets their data. That looks and behaves almost exactly like C. The fact that the references are allocated on the heap is an implementation detail.
Let me be clear, a pointer to a struct on the stack in C is obviously not the same as a reference to an object allocated on the heap in Java. The point is that from the point of view of what the language induces you to do, Java and C are similar. Anyone that has used older libraries in Java can attest to this; they look and feel remarkably like C.