Doing a qsort function to compare strings, case insensitive
Firstly, thank you for providing a test program.  We could make the test even better, if we make it self-checking:
char const *expected[] = {&quot;Alex&quot;, &quot;deacon&quot;, &quot;Onus&quot;, &quot;zebra&quot;};
for (int i = 0;  i &lt; 4;  ++i) {
    if (strcmp(expected[i], strings[i])) {
        return EXIT_FAILURE;
    }
}

We might consider including some non-alphabetic characters, too (&quot;should &quot;A-team&quot; sort before or after &quot;abacus&quot;?).  And we'll want some tests of equal and almost-equal strings; not just ones that differ in the first character.

There were a few errors and warnings to fix up (I compiled with gcc -std=c17 -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds  -Wstrict-prototypes -Wconversion to catch all of these):

We missed a few necessary includes for the comparison function:
#include &lt;ctype.h&gt;
#include &lt;stdint.h&gt;
#include &lt;string.h&gt;

And for the test program:
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;


We're assigning char* pointers using string literals.  Whilst C allows this for historical reasons, it's dangerous, and should be avoided (because assignment through such pointers is UB, and the compiler can't spot that for you).  It's easy to fix that:
const char* strings[4] = {&quot;Onus&quot;, &quot;deacon&quot;, &quot;Alex&quot;, &quot;zebra&quot;};



And one that GCC can't spot:

qsort(strings, 4, 8, scmp);
//               ^^^


We can't assume that a const char* is a particular size on the target platform.  Whilst this value may be correct where you are, it's not true everywhere.  Luckily, C provides the sizeof operator to help:
qsort(strings, 4, sizeof strings[0], scmp);


Looking in detail at the comparison function, it does a lot of extra work to make a copy of each input string (we have to traverse each string up to three times - once to find its length, once to copy and convert case, and once to compare).
Instead of preparing the ground for strcmp(), we could (and should) write a case-insensitive version of strcmp(), so we traverse each string once, and downcase only those characters we actually need for the comparison, as we reach them:
#include &lt;ctype.h&gt;

/* N.B. name not beginning with &quot;str&quot;. */
int ci_strcmp(const char *s1, const char *s2)
{
    while (*s1) {
        if (!*s2) {
            /* s1 is longer */
            return 1;
        }
        int c1 = tolower(*s1);
        int c2 = tolower(*s2);
        if (c1 &lt; c2) {
            return -1;
        }
        if (c2 &lt; c1) {
            return 1;
        }
        ++s1;
        ++s2;
    }
    if (*s2) {
            /* s2 is longer */
            return -1;
    }
    /* compare equal */
    return 0;
}

/* Adapter for qsort */
int scmp(const void *p1, const void *p2)
{
    const char *const *sp1 = p1;
    const char *const *sp2 = p2;
    return ci_strcmp(*sp1, *sp2);
}

We can make the body of the comparer more compact (but functionally identical) with a little cleverness:
int ci_strcmp(const char *s1, const char *s2)
{
    for (;;) {
        int c1 = tolower(*s1++);
        int c2 = tolower(*s2++);
        int result = (c1 &gt; c2) - (c1 &lt; c2);
        if (result || !c1) return result;
    }
}

As mentioned in another answer, we need to use unsigned char with tolower():
int ci_strcmp(const unsigned char *s1, const unsigned char *s2)
{
    for (;;) {
        int c1 = tolower(*s1++);
        int c2 = tolower(*s2++);
        int result = (c1 &gt; c2) - (c1 &lt; c2);
        if (result || !c1) return result;
    }
}

/* Adapter for qsort */
int scmp(const void *p1, const void *p2)
{
    const unsigned char *const *sp1 = p1;
    const unsigned char *const *sp2 = p2;
    return ci_strcmp(*sp1, *sp2);
}