arrayscstringqsortwincc

Cannot loop through array of strings after qsort()


I am slamming my head against the wall with this problem.

To summarize: I need to dynamically add strings to an array, sort them, and then check against another string value.

This needs to work on a SCADA-system that support C as a scripting language, but with limited functionality. I have qsort() available.

However, with the test code I have, I am not able to use qsort on an array, with values that are added dynamically.

To be clear, I can add strings to the array, which works fine. However when I call qsort() on that array, I can no longer print out the indices.

Heres is the code so far (be kind, I'm not very proficient in C):

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

int cstring_cmp (const void *a, const void *b)
{
  // This function is taken from an online example
  const char **ia = (const char **) a;
  const char **ib = (const char **) b;
  return strcmp (*ia, *ib);
}


int main ()
{
  //char *ArchiveKomponents[] = {"R1890L", "F1121D", "F1284Z", "A1238K"};
  // If I do the above commented out, it works as intended
  char ArchiveKomponents[100][20];

  strcpy(ArchiveKomponents[0], "R1890L");
  strcpy(ArchiveKomponents[1], "F1284Z");

  size_t strLen = sizeof (ArchiveKomponents) / sizeof (char *);
  printf ("Len: %zu\n", strLen);

  printf ("Before [0]: %s\n", ArchiveKomponents[0]);
  printf ("Before [1]: %s\n", ArchiveKomponents[1]);

  qsort (ArchiveKomponents, (size_t)strLen, sizeof (char *), cstring_cmp);

  printf ("After [0]: %s\n", ArchiveKomponents[0]);
  printf ("After [1]: %s\n", ArchiveKomponents[1]);
  
  // When run, the "After" prints are not even printed, the program simply halts
  
  return 0;
}

I feel that I have googled the entire internet, in search of an answer on how to do this, with no luck.

Regards


Solution

  • You are comparing incorrect types. The comparison functions treats 4 or 8 characters from the element as a pointer to a string. Dereferencing this pointer triggers Undefined Behavior, likely a crash.

    Note, that the type of a single element is char[20] not char*. Therefore your comparison function could be simply implemented as:

    int cstring_cmp (const void *a, const void *b)
    {
      return strcmp (a, b);
    }
    

    Pointers a and b points to arrays of 20 character. The address of array is the same as an address of its first element. So a and b can be used as pointers to chains of char (aka "c-strings"). Moreover, void* is automatically converted to any pointer type without casting.

    The qsort invocation should be:

    qsort (ArchiveKomponents,           // array to be sorted
           2,                           // number of elements in the array
           sizeof ArchiveKomponents[0], // size of a single element
           cstring_cmp                  // comparison function 
    );