C was made to make writing a compiler easily.  It does a LOT of stuff based on that one principle.  Pointers only exist to make writing a compiler easier, as do header files.  Many of the things carried over to C++ are based on compatibility with these features implemented to make compiler writing easier.
It's a good idea actually.  When C was created, C and Unix were kind of a pair.  C ported Unix, Unix ran C.  In this way, C and Unix could quickly spread from platform to platform whereas an OS based on assembly had to be completely re-written to be ported.
The concept of specifying an interface in one file and the implementation in another isn't a bad idea at all, but that's not what C header files are.  They are simply a way to limit the number of passes a compiler has to make through your source code and allow some limited abstraction of the contract between files so they can communicate.
These items, pointers, header files, etc... don't really offer any advantage over another system.  By putting more effort into the compiler, you can compile a reference object as easily as a pointer to the exact same object code. This is what C++ does now.
C is a great, simple language.  It had a very limited feature set, and you could write a compiler without much effort.  Porting it is generally trivial!  I'm not trying to say it's a bad language or anything, it's just that C's primary goals when it was created may leave remnants in the language that are more or less unnecessary now, but are going to be kept around for compatibility.
It seems like some people don't really believe that C was written to port Unix, so here: (from)
The first version of UNIX was written
  in assembler language, but Thompson's
  intention was that it would be written
  in a high-level language.
Thompson first tried in 1971 to use
  Fortran on the PDP-7, but gave up
  after the first day. Then he wrote a
  very simple language he called B,
  which he got going on the PDP-7. It
  worked, but there were problems.
  First, because the implementation was
  interpreted, it was always going to be
  slow. Second, the basic notions of B,
  which was based on the word-oriented
  BCPL, just were not right for a
  byte-oriented machine like the new
  PDP-11.
Ritchie used the PDP-11 to add types
  to B, which for a while was called NB
  for "New B," and then he started to
  write a compiler for it. "So that the
  first phase of C was really these two
  phases in short succession of, first,
  some language changes from B, really,
  adding the type structure without too
  much change in the syntax; and doing
  the compiler," Ritchie said.
"The second phase was slower," he said
  of rewriting UNIX in C. Thompson
  started in the summer of 1972 but had
  two problems: figuring out how to run
  the basic co-routines, that is, how to
  switch control from one process to
  another; and the difficulty in getting
  the proper data structure, since the
  original version of C did not have
  structures.
"The combination of the things caused
  Ken to give up over the summer,"
  Ritchie said. "Over the year, I added
  structures and probably made the
  compiler code somewhat better --
  better code -- and so over the next
  summer, that was when we made the
  concerted effort and actually did redo
  the whole operating system in C."
Here is a perfect example of what I mean.  From the comments:
Pointers only exist to make writing a compiler easier? No. Pointers exist because they're the simplest possible abstraction over the idea of indirection. – Adam Rosenfield (an hour ago)
You are right.  In order to implement indirection, pointers are the simplest possible abstraction to implement.  In no way are they the simplest possible to comprehend or use.  Arrays are much easier.
The problem?  To implement arrays as efficiently as pointers you have to pretty much add a HUGE pile of code to your compiler.
There is no reason they couldn't have designed C without pointers, but with code like this:
int i=0;
while(src[++i])
    dest[i]=src[i];
it will take a lot of effort (on the compilers part) to factor out the explicit i+src and i+dest additions and make it create the same code that this would make:
while(*(dest++) = *(src++))
    ;
Factoring out that variable "i" after the fact is HARD.  New compilers can do it, but back then it just wasn't possible, and the OS running on that crappy hardware needed little optimizations like that.
Now few systems need that kind of optimization (I work on one of the slowest platforms around--cable set-top boxes, and most of our stuff is in Java) and in the rare case where you might need it, the new C compilers should be smart enough to make that kind of conversion on its own.