Why do most arduino function return a -1 instead of a 0
I cannot assert anything for sure, as I was not involved in the design
of the Arduino APIs. However, just like Elliot Alderson, I suspect this
was inspired by the traditional C APIs. The manual page for getchar(),
which is a very old function from the standard C library, states:


  fgetc(),  getc() and getchar() return the character read
  as an unsigned char cast to an int or EOF on end of file or
  error.


Given that EOF is usually defined as -1, this is consistent with the
behavior of Serial.read().

Being beginner-friendly is also a major goal of the API. Pointers are
known to be a huge difficulty for beginners.

There may also be some efficiency considerations involved. Arduino
started on the AVR platform. This is a RISC architecture, with a large
number of generic CPU registers (namely 32). The compiler usually
manages to allocate most local variables to registers. The calling
convention ensures that in most cases function parameters and return
values also go through CPU registers. This means we can avoid many RAM
accesses, which are inherently much slower than register access. Using a
return-by-pointer convention defeats these optimizations.

Lastly, it is a good thing that simple things are easy to write. For
example, an interpreter for single-character commands can be very easily
written as:

switch (Serial.read()) {
case 'a':
    do_command_a();
    break;
case 'b':
    do_command_b();
    break;
// etc...
}


with no need to explicitly test for the serial buffer not being empty.
Obviously, a more complex command language will need a full-blown
interpreter, but the focus of Arduino has always been on simple
programs being easy to write.