Bytes to binary conversion function I created a quick function to convert n bytes into binary for my student.
She is not on that level yet, but I think it would be best for her if my demonstrative functions aren't trash.
void binary (void* p, size_t nBytes)
{
    int iBit    = 0;
    int iByte   = 0;

    putchar('[');

    for(iByte = 0; iByte &lt; nBytes; iByte++)
    {
        for(iBit = 0; iBit &lt; CHAR_BIT; iBit++)
        {
            int bit = ((unsigned char* )p)[iByte] &gt;&gt; iBit;

            putchar((bit &amp; 1) ? '1':'0');
        }

        if(iByte &lt; nBytes-1)
        {
            printf(&quot;]\t[&quot;);
        }
    }

    printf(&quot;]\n&quot;);
}

it goes with a macro for easier use: #define BINARY(x) binary(&amp;x, sizeof x)
and the obvious disadvantage that it expects a variable and not cannot work with literals.

And yes, endianness is explained to her.
It's not terrible as it stands, but I think there are some ways it might be improved.
Include all needed files
The function needs several #include files that are not listed.  Specifically, it needs these:
#include &lt;stddef.h&gt;
#include &lt;stdio.h&gt;
#include &lt;limits.h&gt;

It's important to list those, especially for a beginner.
Be careful with signed and unsigned
In the binary function, the compares an int iByte to a size_t nBytes, but size_t is unsigned and int is signed.  Instead, declare both variables as size_t types, or better, see the next suggestion.
Count down instead of up
If we count down instead of up, not only do many compilers generate more efficient code, but we also avoid the signed/unsigned problem mentioned above.
Declare variables in as small a scope as practical
Putting all definitions at the top of the function is an antique style of C.  In modern C (C99 and later) we declare variables as late as practical, ideally as they are defined, to avoid problems of uninitialized variables.
Use a bitmask directly instead of calculating
I would write the inner loop like this:
for(unsigned char mask = 1U &lt;&lt; (CHAR_BIT-1); mask; mask &gt;&gt;= 1) 

That makes it very clear that we're using a bitmask and how it is calculated and handled.
Use a convenience cast
Rather than casting p every time, I'd be inclined to declare an internal unsigned char * variable and use that instead.
Avoid encoding types in names
C is a statically typed language, so it is neither necessary nor desirable to encode the type within the name.  See NL.5 for more.  (Those are C++ guidelines, but this is equally applicable to C.)
Use pointers
Sooner or later, even beginners are going to need to learn how to use pointers.  They have the considerable advantage here in simplifying the code.
Use const where practical
The function does not and should not modify the pointed-to value, so it's better to make that explicit and declare it const.
Consider separating the function into two
One way to think of this code is that it's printing one or more bytes with additional separators and formatting.  That suggests an alternative which is to separate out the part that just prints the ones and zeroes from the loop.
Results
Here's the slightly refactored code using all of the suggestions above:
#include &lt;stddef.h&gt;
#include &lt;stdio.h&gt;
#include &lt;limits.h&gt;

void toBinary(const unsigned char *ptr) {
    for(unsigned char mask = 1U &lt;&lt; (CHAR_BIT-1); mask; mask &gt;&gt;= 1) {
        putchar(*ptr &amp; mask ? '1' : '0');
    }
}

void binary(const void* p, size_t nBytes) {
    for(const unsigned char* ptr = p; nBytes; --nBytes) {
        putchar('[');
        toBinary(ptr++);
        putchar(']');
        if(nBytes &gt; 1) {
            putchar('\t');
        }
    }
    putchar('\n');
}

#define BINARY(x) binary(&amp;x, sizeof x)

int main(void) {
    char a = 85;
    int b = 0x12345678;
    BINARY(a);
    BINARY(b);
}