C++ features a feature called references, these are implicit pointers — pointers without the pointer syntax. A reference is a guarantee that a pointer is not null, it disables swapping out the pointer inside the code (basically, it's a pointer, not to a const-object, but a pointer, that is const), and only the one object can be accessed (well, not really, but it's absolutely clear that their's only one object, and accessing the next one is awkward).
This is all well and good, but you should need not a reference to declare a pointer as non-null, instead at the very least it should documented, but preferable the language syntax shall declare whether or not the pointer is null, e.g. by appending a question mark to declare that the pointer may be null (which should be strict from the address used for null (usually 0, but that is not guaranteed), so nullptr is actually a good idea, even though that is not the reason it exists). Declaring that a pointer may or may not be null, is also beneficial when it comes to multiobject pointers.
The real problem with references is that they are implicit pointers, all other features it provides is just vitamin enrichment on the vegetable. Implicitly is usually a bad thing, and such is the case also when it comes to pointers. When you have an implicit pointer, it is not obvious when you read the code that you have pointer, you need to keep track of whether an object is a reference or if you have a local copy, are you output to the caller or not (it is common practice to have a reference to a RAII-initialised variable: an output reference, instead of an output pointer. Worse, references and local copies are usually used when the other should be used.
Unlike C++, in C, you avoid aggregate parameters and returns: meaning you you always use a pointer when you a struct, union or array (array parameters are always pointers). This has the advantage that you know that you always have a pointer to the callers object, and if you need to make non-propagating changes, you have to explicitly copy it. This makes it obvious whether or not you intend to modify the callers copy or just your own copy, and if you don't need a copy, you don't get a copy, saving CPU cycles and memory (expect in the very unlikely case that the structure is smaller than an address and the argumment must be passed through the stack). Having a single way declare that you are going to output an aggregate type, or want one as input, stabilises both the API (breaks when switch to or from pointers) and ABI (breaks when switching to or from copies).