1

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

3
  • 1
    you need to compare char[20] not char*. Commented Oct 7, 2021 at 15:32
  • 1
    Why are you trying to sort the entire array? You have only initialized two elements! Commented Oct 7, 2021 at 15:32
  • @MartinJames I could have been more clear, my bad. In this test I only tried with 2 elements, but in the end I may need to do it with up to 100 elements, hence the size of 100 on the array. In the commented out line above the array declaration, you will see 4 elements Commented Oct 8, 2021 at 5:50

1 Answer 1

3

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 
);

Sign up to request clarification or add additional context in comments.

3 Comments

Also mention that strLen is computed incorrectly: instead of size_t strLen = sizeof (ArchiveKomponents) / sizeof (char *);, it should be size_t strLen = sizeof (ArchiveKomponents) / sizeof (ArchiveKomponents[0]); and the same is very confusing. Using the number of active entries is much better anyway.
@chqrlie, right, however the number of valid element in the question is 2
Indeed, using the number of active entries is much better anyway.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.