A point of confusion may be that C more or less predates modern notions of references and object orientation.
C is... certainly a much higher level than ASM, but it's still not too distantly related to it -- statements can be read as sequences of operations of a virtual machine, which is then implemented (by the compiler) as native ASM. It's very much imperative and procedural. The compiler doesn't much care what you're doing with objects -- the notion of an "object" is very thin, just memory allocations known at compile/link time -- and, as long as what you're doing meets the language standard, the compiler will simply do as told. Want to go munge some kernel memory? No problem! If your platform has memory protection, the OS at least may stop you with a (run time) segmentation fault.
Whereas OOP, very specifically and intentionally does away with pointers -- which are inherently unsafe, as used in C -- and instead object references are handled exclusively by the compiler, and can only be manipulated in certain allowed ways. Thus, in Java for example, about the worst you should be able to do is a nullpointer exception -- which is to say, an uninitialized variable. You can't arbitrarily assign garbage to the reference: that's a type error. You can't place/allocate arrays arbitrarily, or access uninitialized memory as if it were an array; all must be declared, allocated, and initialized. (Under the hood, type is often stored in the object itself, so that, while you can typecast to a lower (inherited) type, like Object -- the VM/runtime can still check what it is, and do certain allowed conversions (like using Java's Integer object as an integer (primitive)).
And OOP can free us from some of the burdens of procedural programming; we can instead describe what we want done, and then let the interpreter/compiler figure out how that should be done by the underlying machine.
So, indeed, when we want to do call-by-reference in C -- it doesn't exist, we must go out of our way to recreate that functionality. We do this by passing pointers, which allow the function to modify the memory underlying those objects. Which is as others have said above.
Under the hood, we know OOP is really doing the same thing -- a reference is a pointer to an object -- but we cannot read or modify that pointer directly, at least not through any intended means. And any such violation is almost certainly a bug in the interpreter -- often an extremely serious one at that, as the language trusts itself by default, so does not usually employ protection between objects or functions or what have you -- an errant pointer, used carefully, likely can pwn the system.
C++ of course is different, having all of these, and more. The tradition for C and immediate relatives tends to be, give you more guns you can possibly handle, and let you foot-gun yourself if you so choose. They can be used quite powerfully, but they also fail in fantastically embarrassing ways; often from quite subtle mistakes.
Mind -- comparisons between C and other paradigms, safety, bugginess and such -- don't take this as a judgement call, that's simply how it is. There are good and bad aspects to everything; we must simply deal with them, how ever they may come.
Tim