Search code examples
cpointersstdquicksortqsort

Why does qsort only sorts a maximum of 8 elements


I was writing a code which is using qsort from <stdlib.h>. While my Code is absolutly working fine for 8 elements in of the Array that will be sorted it doesnt for more then 10 elements. I`ve no idea why it doesnt work, I hope you can help me out.

Talking about the Problem: I was trying to sort a float Array with 10 Elements. On the fact this didnt work I tried to make it easier by using only Integers. While i was tesing it I realised that qsort works pretty good by using 8 elements or less for the array. When i was using more then 8 elements it wasnt working at all. Some elements (always the same ones) were sorted others werent. at all they werent listed correct. So I tried other codes to solve the problem but not a single code changed something.

#include <stdio.h>
#include <stdlib.h>

int CompareFloat(const void* pcv1, const void* pcv2);
int CompareIntegers(const void* pcv1, const void* pcv2);

int main()
{
    int aiArr[10] = { 10,9,8,7,5,6,4,2,3,1};
    int aiArr2[8] = { 8,7,6,5,4,2,3,1 };
    float afArr[8] = { 5.0f, 4.611f, 4.61f, 4.1f, 4.0f, 10.0f, 1.9f, 1.8f };
    for (int i = 0; i < 8; i++)
    {
        printf("%f\t", afArr[i]);
    }
    puts("\n");
    for (int i = 0; i < 10; i++)
    {
        printf("%i\t", aiArr[i]);
    }
    puts("\n");
    for (int i = 0; i < 8; i++)
    {
        printf("%i\t", aiArr2[i]);
    }

    qsort(aiArr2, 8, sizeof(int), CompareIntegers);
    qsort(aiArr, 10, sizeof(int), CompareIntegers);
    qsort(afArr, 8, sizeof(float), CompareFloat);
    puts("\n");

    for (int i = 0; i < 8; i++)
    {
        printf("%f\t", afArr[i]);
    }
    puts("\n");
    for (int i = 0; i < 10; i++)
    {
        printf("%i\t", aiArr[i]);
    }
    puts("\n");
    for (int i = 0; i < 8; i++)
    {
        printf("%i\t", aiArr2[i]);
    }

    return 0;
}

int CompareFloat(const void* pcv1, const void* pcv2)
{
    int iRet;

    float* pf1 = (float*)pcv1;
    float* pf2 = (float*)pcv2;

    if (*pf1 < *pf2)
    {
        iRet = -1;
    }
    if (*pf1 > *pf2)
    {
        iRet = 1;
    }
    else
    {
        iRet = 0;
    }

    return iRet;
}
int CompareIntegers(const void* pcv1, const void* pcv2)
{
    int iRet;
    int* pi1 = (int*)pcv1;
    int* pi2 = (int*)pcv2;

    if (*pi1 < *pi2)
    {
        iRet = -1;
    }
    if (*pi1 > *pi2)
    {
        iRet = 1;
    }
    else
    {
        iRet = 0;
    }

    return iRet;

}

Output (cutt some 0):

1.8000  1.9000  4.0000  4.1000  4.6100  4.6110  5.0000       10.0000

1     3     2     4     5     6     7     8     9       10

1     2     3     4     5     6     7     8

Expected Output (cut some 0):

1.8000  1.9000  4.0000  4.1000  4.6100  4.6110  5.0000  10.0000 

1   2   3   4   5   6   7   8   9   10  

1   2   3   4   5   6   7   8

I was reading a lot of code and more informations about qsort but its not working fine. The elemts of the bigger array arent sorted, like they should (I think so).


Solution

  • In your compare functions, you left off else in your second if.

    You have:

        if (*pi1 < *pi2)
            iRet = -1;
        if (*pi1 > *pi2)
            iRet = 1;
        else
            iRet = 0;
    

    Consider what happens when *pi1 < *pi2. The first if is true, so we set iRet = -1. We then go on to the second if (this is the bug). The second if is false, so we set iRet = 0. Thus we end up returning 0 instead of the correct result -1.

    A three-way test should instead look like:

        if (*pi1 < *pi2)
            iRet = -1;
        else if (*pi1 > *pi2) // note else here
            iRet = 1;
        else
            iRet = 0;
    

    so that only one of the branches ever executes.

    Alternatively, use an "early return":

       if (*p1 < *p2)
          return -1;
       if (*p1 > *p2)
          return 1;
       return 0;