differences

C has

C doesn’t have:

architecture

Java produces bytecode that runs in a Java VM.
C produces machine code that runs in a specific hardware CPU.

One effect of this is that the sizes of the various integer and floating-point types are specifically undefined in C.

The C language is about direct access to the addresses used by the CPU to access memory and other devices. There is no native Java analog to this. If you want or need to write code that is “close to the metal”, then C can be a thrilling experience. Otherwise it’s a bitch.

function calling conventions

Java has a hybrid convention: pass-by-reference for objects, pass-by-value for primitives.
C function arguments are strictly pass-by-value.

types

Java is strongly typed: it is a syntax error to incorrectly interpret the type of an entity.

C has types, but it is easy and common practice to cast an entity as something that it really isn’t. (Everything is just memory to C; types are just a convenient way to refer to it.)

initialization

When a variable is declared in C without an explicit initializer, by default it contains junk, not zero. Failure use a variable before it is initialized is a common source of weird bugs. It is good practice to explicitly initialize all variables when they are declared.

headers

C passes information between related code modules using special header files.