I feel like C exists at a level below such concepts. Simply being able to define a function `void do_stuff(struct mystruct *obj)` opens the door to object-oriented style programming. A lot of people seem to define OOP by the presence of superficial stuff like inheritance, polymorphism etc, but really those are additional concepts that aren't useful for every program. The real difference is mutating state on the heap. So you could say C is an object-oriented language, by default, because it doesn't stop you doing this stuff, unlike a higher-level language like Clojure which simply doesn't have mutation (for the most part). Or you could say C is a functional language because if you don't explicitly pass pointers then you get copies. Really it's both and it's neither. It's whatever you want it to be.
I feel like C exists at a level below such concepts. Simply being able to define a function `void do_stuff(struct mystruct *obj)` opens the door to object-oriented style programming. A lot of people seem to define OOP by the presence of superficial stuff like inheritance, polymorphism etc, but really those are additional concepts that aren't useful for every program. The real difference is mutating state on the heap. So you could say C is an object-oriented language, by default, because it doesn't stop you doing this stuff, unlike a higher-level language like Clojure which simply doesn't have mutation (for the most part). Or you could say C is a functional language because if you don't explicitly pass pointers then you get copies. Really it's both and it's neither. It's whatever you want it to be.