The first chapter, on abstraction and information hiding, is probably the most important. Every programmer should know how to do it. It's one of C's main strengths that it allows abstract data types so easily. ADTs in fact allow better binary compatibility since you only expose pointers as your public API, not structures of different shapes and sizes.

I'm continually surprised by how often people insist on putting struct definitions right in their header files, defeating the whole idea of type abstraction.

I was thinking lately that C is more data-oriented than many. However I'm limited in knowledge mostly to imperative languages.

What I mean is that defining arrays of structs has very light syntax. For example in Python AFAIK you can't easily do this. You have to use dictionaries (which is cumbersome if you have many rows) or some kind of class/module that will make it even less clear. What Suckless [1] guys are doing where you can use C as configuration language is example of it. Like keybindings configuration [2] in dwm [3]:

  static Key keys[] = {
	/* modifier                     key        function        argument */
	{ MODKEY,                       XK_p,      spawn,          {.v = dmenucmd } },
	{ MODKEY|ShiftMask,             XK_Return, spawn,          {.v = termcmd } },
	{ MODKEY,                       XK_b,      togglebar,      {0} },
	{ MODKEY,                       XK_j,      focusstack,     {.i = +1 } },
	{ MODKEY,                       XK_k,      focusstack,     {.i = -1 } },
        /* ... */
  };
When I do something in Python I miss this. C++ most likely will require doing some playing around with constructors.

Also with C99 it's only sweeter. When you need you can use designated initializers [4] - putting names of fields or indices of array in initialization list. You can use compound literals [5] to obviate some need for constructors.

[1] https://suckless.org/

[2] https://git.suckless.org/dwm/tree/config.def.h

[3] https://dwm.suckless.org/

[4] https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html

[5] https://gcc.gnu.org/onlinedocs/gcc/Compound-Literals.html

Take a look at https://github.com/python-attrs/attrs which will let you do something like

    import attr

    @attr.s
    class Key(object):
         modifier = attr.ib()
         key = attr.ib()
         function = attr.ib()
         argument = attr.ib()

    keys = [
        Key(MODKEY,           XK_p,      spawn, {'v': dmenucmd}),
        Key(MODKEY|ShiftMask, XK_Return, spawn, {'v': termcmd}),
        # ...
    ]
which gets you the concise and readable syntax of C structs, while keeping these things as actual attributes as if they were classes (e.g., [key.modifier for key in keys] will work).

And you get designated initializers via Python's usual keyword-argument syntax, the ability to specify attr.ib(default=...), and a few other things.