Doing a qsort function to compare strings, case insensitive How does the following C program look to compare to strings and return a case-insensitive sort? The following is what I have so far:
int main(void)
{
    char* strings[4] = {&quot;Onus&quot;, &quot;deacon&quot;, &quot;Alex&quot;, &quot;zebra&quot;};
    for (int i=0; i&lt;4; i++) printf(&quot;%d. %s\n&quot;, i+1, strings[i]);
    qsort(strings, 4, 8, scmp);
}

int scmp(const void *p1, const void *p2)
{

    // being a string (pointer-to-char)
    const char* s1 = *(char**) p1;
    const char* s2 = *(char**) p2
    size_t len_s1 = strlen(s1);
    size_t len_s2 = strlen(s2);

    // lower-case first string buffer
    char s1_lower[len_s1+1];  // cannot initialize with {[len_s1]=0} in VLA ?
    s1_lower[len_s1] = 0;
    for (int i=0; s1[i] != 0; i++)
        s1_lower[i] = tolower(s1[i]);

    // lower-case second string buffer
    char s2_lower[len_s2+1];
    s2_lower[len_s2] = 0;
    for (int i=0; s2[i] != 0; i++)
        s2_lower[i] = tolower(s2[i]);

    // built-in string compare (strcmp) will return the sort value
    return strcmp(s1_lower, s2_lower);
    /* printf(&quot;%s -- %s\n&quot;, s1_lower, s2_lower); */

}

Another version extracting out the str_lower function would be:
void lower_string(char buffer[], const char* str, size_t len)
{
    char str_lower[len+1];
    str_lower[len] = 0;
    for (int i=0; str[i] != 0; i++)
        str_lower[i] = tolower(str[i]);
}
int scmp(const void *p1, const void *p2)
{
    const char* s1 = *(char**) p1;
    const char* s2 = *(char**) p2;

    char s1_lower[strlen(s1)+1];
    lower_string(s1_lower, s1, strlen(s1));
    
    char s2_lower[strlen(s2)+1];
    lower_string(s2_lower, s2, strlen(s2));

    return strcmp(s1_lower, s2_lower);
}
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);
}