Bounds checks are either runtime checks or removed by static analysis. JIT just pushes back the time at which that static analysis is done and increases the amount of context available (largely through inlining).
It's still fundamentally static analysis, just run at JIT time, not at class file generation time. My point is that the JIT-time static analysis in the JVM is heavily optimized for memory accesses typical of Java programs.
Typical C code is drastically different, especially since pointer arithmetic is common in C code. In order to properly statically check an access via pointer arithmetic from a pointer allocated via malloc(), the JIT would need to be operating over a code fragment that included both the malloc call (to know where the base address is relative to the bound) and the memory access site. Lots of C code has way too much code executing between malloc and your pointer arithmetic to reasonably expect that the JIT is going to have all of that code in the execution trace it's currently optimizing.
In the specific case suggested above, just using a giant byte array to represent all of memory, bounds-checking some memory access to an arithmetic-modified pointer gotten from malloc(), the bounds removal would be dependent on the exact address returned by malloc(). In some programs, maybe there's tons of access to a small number of buffers allocated at program start-up time. In that case, current JVMs might do a pretty good job at eliding bounds checks by noticing that the base address is usually one of a small number of values and having a dedicated code path for those common cases. However, if you're doing frequent malloc(), then you're getting tons of different base addresses. In other programs, the malloc() and the access will be close enough together that the JIT'd fragment will include both the malloc and the access, in which case the JVM will have enough context to elide the bounds access. However, it's way too hand-wavy to just say the JVM is good at eliding array bounds checks.
The JVM is very good at eliding array bounds checks typical of Java programs. This is very different from eliding array bounds checks typical in memory-unsafe languages.