Some kind of indirection is necessary for complex programs (e.g. recursive or variable-sized data structures). However, it is not necessary to implement this indirection via pointers.
The majority of high-level programming languages (i.e. not Assembly) are fairly memory-safe and disallow unrestricted pointer access. The C family is the odd one here.
C evolved out of B which was a very thin abstraction over raw assembly. B had a single type: the word. The word could be used as an integer or as pointer. Those two are equivalent when the whole memory is viewed as a single contiguous array. C kept this rather flexible approach and continued to support inherently unsafe pointer arithmetic. The whole type system of C is more of an afterthought. This flexibility to memory access made C very suitable for its primary purpose: prototyping the Unix operating system. Of course Unix and C turned out to be quite popular, so that C is also used in applications where this low-level approach to memory is not really needed.
If we look at the programming languages that came before C (e.g. Fortran, Algol dialects incl. Pascal, Cobol, Lisp, …) some of those do support C-like pointers. Notably, the null pointer concept was invented for Algol W in 1965. But none of those languages tried to be a C-like, efficient low-abstraction systems language: Fortran was meant for scientific computing, Algol developed some quite advanced concepts, Lisp was more of a research project than an industry-grade language, and Cobol was focussed on business applications.
Garbage collection existed since the late 50s, i.e. well before C (early 70s). GC requires memory safety to work properly. Languages before and after C used GC as a normal feature. Of course that makes a language much more complicated and possibly slower, which was especially noticeable in the time of mainframes. GC languages tended to be research-oriented (e.g. Lisp, Simula, ML) and/or require powerful workstations (e.g. Smalltalk).
With smaller, more powerful computers computing in general and GC languages specifically did become more popular. For non-real time applications (and sometimes even then) GC is now the preferred approach. But GC algorithms have also been the subject of intense research. As an alternative, better memory safety without GC has also been developed further, especially in the last three decades: notable innovations are RAII and smart pointers in C++ and Rust's lifetime system/borrow checker.
Java did not innovate by being a memory-safe programming language: it basically took the semantics of the GCed, memory safe Smalltalk language and combined them with the syntax and static typing of C++. It was then marketed as a better, simpler C/C++. But it's only superficially a C++ descendant. Java's lack of pointers is owed much more to the Smalltalk object model than to a rejection of the C++ data model.
So “modern” languages like Java, Ruby, and C# should not be interpreted as overcoming the problems of raw pointers like in C, but should be seen as drawing from many traditions – including C, but also from safer languages like Smalltalk, Simula, or Lisp.