1

I searched for a similar question here but I couldn't find it. I am a student in the university and we need to make a function receiving const char *str_arr[], the length of the array, and sorting it by a certain rule (doesn't really matter ATM).

I'm trying to understand how can I sort this array if it's constant? Maybe by modifying the pointers because the constant is only the strings values? But how?

Moreover, I'm not allowed to use any "special" functions, like qsort, etc. I can only use strlen() and strcpy() functions, and the regular libraries.

I'm trying to aim for bubble sort but it just wont pass the complier probably because the const type.

Here are the loops for the sort:

for(int i=0;i<n;i++)
{
    char fixed_str[strlen(str_arr[i])];
    strcpy(fixed_str, str_arr[i]);
    for(int j=0;j<n-1;j++)
    {
        if(compareStr(fixed_str, str_arr[j+1], rule)>0) /*If the current string is bigger then the index string*/
        {
            char temp_str[strlen(str_arr[j+1])];
            strcpy(temp_str, str_arr[j+1]);
            str_arr[j+1]=fixed_str;
            str_arr[i]=temp_str;
        }
    }
}

Thank you very much for replies upfront. And would be much appreciated a detailed reply and not just a quick fix.

7
  • Duplicate the const char type into a simple non-const character array and then try sorting it. Commented Jan 14, 2021 at 16:35
  • I really have no idea how to apply such a move. if you could show me a simple example would be appreciated. Commented Jan 14, 2021 at 16:36
  • Note: qsortowns to the standard library ... Commented Jan 14, 2021 at 16:39
  • I know, it belongs to stdlib.h, cant use it. Commented Jan 14, 2021 at 16:42
  • 1
    Then what exactly is your question? Is you sort function not working? Commented Jan 14, 2021 at 16:51

5 Answers 5

1

(Note: See EDIT below for alternative to qsort.)

You can use the qsort library function and a "qsort/bsearch compare" wrapper around your existing compareStr function to sort the const char *str_arr[] array according to the contents of the strings pointed to by the array elements. This only moves the pointers. The contents of the strings are not moved.

For proper operation of qsort, the return value of your compareStr function (and the wrapper function) needs to return a negative value for "first less than second", zero for "first equals second", or a positive value for "first greater than second".

#include <stdlib.h>  // for qsort
#include <string.h>  // for strcmp example

int compareStr(const char *a, const char *b)
{
    // Your comparison function should return:
    // * a negative value if a compares less than b;
    // * zero if a compares equal to b; or
    // * a positive value if a compares greater than b.
    //

    // strcmp(a, b) is being used as an example here...
    return strcmp(a, b);
}

// 
// This is a qsort comparison wrapper around compareStr(s[i], s[j]),
// called by qsort as qs_compareStr(&s[i], &s[j])
//
static int qs_compareStr(const void *a_, const void *b_)
{
    // Note that const void *a_ and const void *b_ are really pointing to
    // elements of array const char *s[], so they have been  converted from
    // const char * const * to const void *.
    // Convert them back to const char * const * and dereference them to get the
    // element values of type const char *.
    //
    const char *a = *(const char * const *)a_;
    const char *b = *(const char * const *)b_;

    // Return the result of comparing the element values.
    return compareStr(a, b);
}

// Sort const char *str_arr[] using compareStr to compare elements
// (via a qsort comparison wrapper - qs_compareStr).
void sort_str_array(const char *str_arr[], size_t n)
{
    qsort(str_arr, n, sizeof str_arr[0], qs_compareStr);
}

EDIT: Thanks to Adrian Mole for informing me that you are not allowed to use qsort. However, the generic nature of qsort can be used in some other array sorting function using the same parameters.

Here is an insertion sort function using the same parameters as qsort. It is not as efficient as the quicksort algorithm, but is relatively easy to implement.

#include <string.h> // for memcpy and memmove

void insertion_sort(void *base, size_t nel, size_t width,
                    int (*compar)(const void *, const void *))
{
    for (size_t i = 1; i < nel; i++)
    {
        char *b = (char *)base + i * width;
        for (size_t j = 0; j < i; j++)
        {
            char *a = (char *)base + j * width;
            if (compar(a, b) > 0)
            {
                // Rotate right elements j thru i.
                char temp[width];  // temporary space
                memcpy(temp, b, width);
                memmove(a + width, a, b - a);
                memcpy(a, temp, width);
                break;
            }
        }
    }
}

Then it is simply a case of replacing calls to qsort with insertion_sort:

void sort_str_array(const char *str_arr[], size_t n)
{
    insertion_sort(str_arr, n, sizeof str_arr[0], qs_compareStr);
}
Sign up to request clarification or add additional context in comments.

2 Comments

Corrected the code. Apologies for earlier mistakes!
@AdrianMole Thanks, I never spotted that. I've just added an insertion sort function as an alternative, using the same parameters as qsort.
0

Here's a rough idea:

  1. Using strcpy(), copy the main string into a temporary one.

  2. Swap the letters alphabetically to sort it.

  3. Print it.


Explaining it into code (notice comments):

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

#define MAX 128

int main(void) {
    // The main_str type of const char[]
    const char main_str[MAX] = "HELLOWORLD";

    char mod_str[MAX]; // The temporary string
    char temp;

    strcpy(mod_str, main_str); // Copying the main_str into mod_str

    unsigned int n = strlen(mod_str); // Getting size of the string

    for (int i = 0; i < n - 1; i++)
        for (int j = i + 1; j < n; j++)
            if (mod_str[i] > mod_str[j]) {
                temp = mod_str[i];       // swapping the
                mod_str[i] = mod_str[j]; // alphabets
                mod_str[j] = temp;       // to sort
            }

    // outputting the letters of the modifiable variable
    printf("%s\n", mod_str);

    return 0;
}

It gives the successfully sorted output:

DEHLLLOORW

3 Comments

I think OP wants to compare/swap whole strings in an array of strings. If so, then there's no need for any strcpy - all that's required is swapping the pointers.
@AdrianMole do you think OP wants char *mod_str = main_str (when main_str is a type of const char *)?
They say a function receiving const char *str_arr[] and sorting that array.
0

Looking at your code, I can't exactly figure out how your sorting 'algorithm' works (or even if it does). However, that issue notwithstanding, your problem comes from the fact that you are unnecessarily copying strings, rather than just swapping pointers.

So, the actual swap in your 'inner loop' only needs to save a copy of a pointer (in the 'temp' variable); something like this:

    //...
        if(compareStr(fixed_str, str_arr[j+1], rule)>0) /*If the current string is bigger then the index string*/
        {
            const char* temp_str = str_arr[j+1]; // Just save the pointer ...
            str_arr[j+1] = fixed_str;            // ... before overwriting it
            str_arr[i] = temp_str;               // Then put it back!
        }

You should have a similar operation for the fixed_str variable (i.e. don't copy the string, just the pointer):

    const char* fixed_str = str_arr[i]; // Just copy the POINTER
//  strcpy(fixed_str, str_arr[i]); // Not needed.

1 Comment

hmmm i think i understand it now, i lacked the arithmetics in this issue, with the const char type. ty!
0

This declaration of an array

const char *str_arr[]

means that you have an array of pointers to (first characters of ) strings. That is elements of the array are pointers. And to sort the array you need to swap the elements that is pointers that point to strings.

Here is a demonstrative program that shows how such an array can be sorted according to the lexicographical comparisons of strings pointed to by elements of the array.

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

int cmp( const void *a, const void *b )
{
    const char *s1 = a;
    const char *s2 = b;
    
    return strcmp( s1, s2 );
}

void bubble_sort( const char * s[], size_t n, int cmp( const void *, const void * ) )
{
    for ( size_t last = n; !( n < 2 ); n = last )
    {
        for ( size_t i = last = 1; i < n; ++i )
        {
            if ( cmp( s[i], s[i - 1] ) < 0 )
            {
                const char *tmp = s[i];
                s[i] = s[i - 1];
                s[i - 1] = tmp;
                
                last = i;
            }
        }
    }
}

int main(void) 
{
    const char * s[] =
    {
        "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"
    };
    
    const size_t N = sizeof( s ) / sizeof( *s );
    
    for ( size_t i = 0; i < N; i++ )
    {
        printf( "\"%s\" ", s[i] );
    }
    putchar( '\n' );
    
    bubble_sort( s, N, cmp );
    
    for ( size_t i = 0; i < N; i++ )
    {
        printf( "\"%s\" ", s[i] );
    }
    putchar( '\n' );
    
    return 0;
}

The program output is

"zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine" 
"eight" "five" "four" "nine" "one" "seven" "six" "three" "two" "zero" 

Using the comparison function you can specify any criteria of sorting. For example to sort the array by string lengths you can write

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

int cmp( const void *a, const void *b )
{
    size_t n1 = strlen( a );
    size_t n2 = strlen( b );
    
    return ( n2 < n1 ) - ( n1 < n2 );
}

void bubble_sort( const char * s[], size_t n, int cmp( const void *, const void * ) )
{
    for ( size_t last = n; !( n < 2 ); n = last )
    {
        for ( size_t i = last = 1; i < n; ++i )
        {
            if ( cmp( s[i], s[i - 1] ) < 0 )
            {
                const char *tmp = s[i];
                s[i] = s[i - 1];
                s[i - 1] = tmp;
                
                last = i;
            }
        }
    }
}

int main(void) 
{
    const char * s[] =
    {
        "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"
    };
    
    const size_t N = sizeof( s ) / sizeof( *s );
    
    for ( size_t i = 0; i < N; i++ )
    {
        printf( "\"%s\" ", s[i] );
    }
    putchar( '\n' );
    
    bubble_sort( s, N, cmp );
    
    for ( size_t i = 0; i < N; i++ )
    {
        printf( "\"%s\" ", s[i] );
    }
    putchar( '\n' );
    
    return 0;
}

At this time the program output is

"zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine" 
"one" "two" "six" "zero" "four" "five" "nine" "three" "seven" "eight" 

If you want you can simplify the comparison function declaration the following way

int cmp( const char *, const char * )

5 Comments

I think it would be better if bubble_sort used the same interface as qsort. At the moment, I don't see the point in it using void * for the cmp function since it is passing pointers to the strings rather than passing pointers to pointers to the strings.
@IanAbbott I do not think that it is a good idea to make more complicated the sorting function for a student. But the interface of the comparison function can be useful though the function does not accept a pointer to pointer.
That's fine, but why define the parameters of cmp as const void * rather than const char *? Since this cmp function is not currently usable with qsort anyway (at least for sorting arrays of const char *), why use const void *?
@IanAbbott In this case it is easy to change the function bubble_sort to sort arrays of other types.
Thank you for your detailed explanation. much appreciated!
0

If you want to write your own string sort routine, you should create an array of pointers to the strings and then sort that array. You can access the original string from the pointers to compare them. Copying the string in the sort algorithm is horribly inefficient.

Also, you said you had an error due to const, yet the code you posted does not include const. One can only guess what const you are talking about.

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.