0

I'd like to ask, how to sort some group of string by it's Character. For instance : "Baba", "Cece" , "Caca" , "Zaza" , "Lala"


i'd like to sort it become like this Baba Caca Cece Lala Zaza

how to sort those words? do we compare it's ASCII Number each word? if it's a number we can just swap it(using insertion sort and so on) do we can also use the same method?

3
  • Each character (a char) has a value between 0-127 (basic ascii values) and can be sorted accordingly. Generally a simple sort routing like qsort can be used without much effort. For short strings you can use just about any sort routine you choose without much loss in efficiency, but for longer strings, (1000's of chars), quicksort, heapsort or a combination with mergesort provide the best performance. (See Ascii Table Values Commented Oct 23, 2015 at 3:36
  • Possible duplicate of How to sort an array of string alphabetically (case sensitive, nonstandard collation) Commented Oct 23, 2015 at 3:40
  • @dietbacon: I think the other question is a more complicated version of this one, but not a duplicate. This question is basically "Help me use qsort in the most basic possible way". Commented Oct 23, 2015 at 4:30

3 Answers 3

2

Sorting chars in a String (sorting strings below)

Following from the comment, you can sort a string the very same way you sort any other type in C. You either use the qsort function provided by the standard library, or you use your own function (e.g. bubble sort, heap sort, etc..)

When using qsort your only task is to write a compare function to pass to the qsort function that tells qsort how to sort your data. The basic declaration for qsort is:

void qsort (void *base, size_t nmemb, size_t size,
           int (*compar)(const void *, const void *));

qsort takes 4 arguments: (1) a pointer to the list/array to be sorted, (2) the number of elements to sort, (3) the type size of each element (e.g. sizeof int), and (4) lastly a pointer to your compare function. Note: your compare function takes 2 generic pointers (void type) as its input.

For sorting characters, you correctly recognize you will sort by the ascii values. Therefore, all your compare function needs to do is return whether of the two characters: (a) one is greater than the other, or (b) they are equal.

An example of the compare function here would be:

int compare_char (const void *a, const void *b) {
    if (*(char *)a != *(char *)b)
        return *(char *)a - *(char *)b;

    return 0;
}

Generally, the only difficult part for new C programers is figuring out how to cast the void type of the arguments to the type you need to compare.

In the compare function, since you are passed a pointer to type void, you need to cast it to your type before you can dereference it to get the value at the pointer address. Here casting the void * to char * is all you need. Then you need to dereference it with '*' before you making the comparison. (for a final cast/dereference of e.g. *(char *)a). Putting it all together in a short example:

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

#define MAXS 32

/* simple compare function for qsort, returns 
   less than 0 if char 'b' is larger than char 'a',
   a positiver number if 'a' is larger than 'b', and
   zero if they are equal (note: you can return 
   'b' - 'a' to sort in reverse order.)
*/
int compare_char (const void *a, const void *b) {
    if (*(char *)a != *(char *)b)
        return *(char *)a - *(char *)b;

    return 0;
}

int main (void) {

    char word[MAXS]   = {0};
    char sorted[MAXS] = {0};

    printf ("\n Enter a string: ");         /* read word from stdin   */
    if (!scanf ("%31[^\n]%*c", word)) {
        printf ("  [ctrl+d] received\n\n");
        return 1;
    }

    /* copy word to sorted before sort */
    strncpy (sorted, word, sizeof word);

    /* sort the chars in sorted[] */
    qsort (sorted, strlen (word), sizeof *word, compare_char);

    /* print results */
    printf ("\n word   : %s\n sorted : %s\n\n", word, sorted);

    return 0;
}

Compile

$ gcc -Wall -Wextra -Ofast -o bin/str_sort_char str_sort_char.c

Use/Output

$ ./bin/str_sort_char

 Enter a string: aghibw

 word   : aghibw
 sorted : abghiw

Sorting The Array of Strings

All the explanation above originally regarding sorting by char's, also applies to sorting an array of strings. This also provides a good look at the way you approach using qsort. Above, in the first example, when we approached using qsort, we had to answer the question: "What type am I sorting?" Above we were sorting each char in a null-terminated array of chars (or string).

How are strings referenced? Through a pointer to the beginning character in the string. So here, instead of sorting each char in an array of chars, we will be sorting strings in an array of strings (or properly an array of pointers to type char *) As far is qsort is concerned, the only difference will be the compare function (and the input...). We need to sort strings, so the compare function must provide a way of comparing strings. In C, the standard string comparison function is strcmp (or strncmp to limit the number of characters compared).

For instance, using strcmp to sort an array of strings, you would use something similar to:

/* string compare function */
int compare_strings (const void *a, const void *b) {
    return strcmp(*(char **)a, *(char **)b);
}

If you look at the comparison within compare_strings, you are simply returning the result of the strcmp function. Basically, changing only the compare function (and the input), you can then use qsort to sort your array of strings, as follows:

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

/* string compare function */
int compare_strings (const void *a, const void *b) {
    return strcmp(*(char **)a, *(char **)b);
}

int main (void) {

    char *strings[] = {"Baba", "Cece" , "Caca" , "Zaza" , "Lala"};
    size_t i;

    /* sort strings */
    qsort (strings, sizeof strings/sizeof *strings, 
           sizeof *strings, compare_strings);

    /* output sorted arrray of strings */
    for (i = 0; i < sizeof strings/sizeof *strings; i++)
        printf (" strings[%2zu] : %s\n", i, strings[i]);

    return 0;
}

Output

$ ./bin/qsort_strings_static
 strings[ 0] : Baba
 strings[ 1] : Caca
 strings[ 2] : Cece
 strings[ 3] : Lala
 strings[ 4] : Zaza
Sign up to request clarification or add additional context in comments.

6 Comments

In your compare_char function, you could just return *a - *b. That will be zero if they're equal, so special-casing that just makes the compiler work harder to optimize away the if.
Peter, I'm not sure I understand what you are saying? You can't just return *a - *b without dereferencing a void. Do I understand you are saying return *(char *)a - *(char *)b; could simply be return *a - *b;?
No, you still need the cast, but you can loose the if. (You could write the function to take const char* args and then cast the function pointer, but that's not what I was saying before.) int compare_char (const void *a, const void *b) { return *(char *)a - *(char *)b; } should return the same value as your version in all cases.
OK, now I understand what you are saying and yes, I agree. The intent was to emphasize that you build the compare function to handle 3 cases (>, <, and =) The simple return *(char *)a - *(char *)b; does just that (and it is what you would normally use), but it brushes over the fact you are handling all 3 cases. Good point.
What if the strings are of different size ? will it still work ?
|
1

Are you asking how to sort a collection of strings? Or how to sort the characters within one string?

Within a single ASCII string, it's dead easy. A string is just an array of bytes, so you sort it using any of the same algorithms you'd use to sort an array of integers. C's char type is a one-byte integer type that can be compared, added, subtracted, etc. (It can be signed or unsigned: implementation-dependent.)

With utf8, a single character can take multiple bytes (chars) to encode, so sorting the bytes will break things.

I wrote this trivial in-place selection-sort function for strings for an anagram-dictionary generator many years ago:

void sort_chars(char *string, int len) // selection sort because words are short
{
   char *end_p, *search, *max_p; // *end_p == last char before '\0'
   char max_val;

   for(end_p = string + len - 1; end_p > string ; end_p--){
      for(search = max_p = string, max_val = *max_p ; search <= end_p ; search++){
         if(*search > max_val){ max_p = search; max_val = *max_p; }
      }
      // max_p now points to largest element, so swap
      *max_p = *end_p;
      *end_p = max_val;
   }

}

All anagrams of a given word have the same characters, and sorted-by-character is a canonical representation of those characters. So you can make an anagram-dictionary storing the sort-by-character representation of every word in /usr/share/dict/words, along with the original word.

You could easily modify this function to sort from start to end, and look for a trailing '\0' (NUL) byte instead of needing an explicit length.

1 Comment

i'm asking how to sort a collection of string
0

you can start off with 2 pointers and a loop,1 pointer pointing at string1 and the other pointing at string2 ,de-reference both and check to see whose character is greater,or if they are equal.and make the swap accordingly.Here is a code that implement this approach.This is a complete function that you can use.

#include <stdio.h>

int s_bubblesort(int argc,char **argv);


int main(void)
{
    char *str[] = { "zzz","zhz","ydc","acb","zzb","zua","abc","zuaaa","xzz" };

    s_bubblesort(9,str);

    for( int n = 0 ; n < 9 ; n++ )
    {
        printf("%s\n",str[n]);
    }
    printf("\n\n");

    char *words[] = {"Baba","Caca" , "Cece","Lala","Babaaaaaa", "L"};

    s_bubblesort(6,words);

    for( int n = 0 ; n < 6 ; n++ )
    {
        printf("%s\n",words[n]);
    }
}

int s_bubblesort(int argc,char **argv)
{
    int i , j = 0;

    char *p_1 , *p_2 , *tmp;

    while( j < argc )
    {
        for( i = 0 ; i < argc - j - 1 ; i++ )
        {
            p_1 = argv[i] , p_2 = argv[i+1];

            while( *p_1 && *p_2 )
            {
                if( *p_1 > *p_2 || ( ! *(p_2 + 1) && ( *p_1 == *p_2 ) ) )
                {
                    tmp = argv[i];

                    argv[i] = argv[i+1];

                    argv[i+1] = tmp;

                    break;
                }
                else if( *p_1 < *p_2 )
                {
                    break;
                }
                p_1++;
                p_2++;
            }
        }
        j++;
    }
    return 0;
}

Comments

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.