简体   繁体   English

对 C 中的字符串的 const char* 数组进行排序 - 练习

[英]Sorting a const char* array of strings in C - Exercise

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).我是大学的学生,我们需要制作一个 function 接收const char *str_arr[] ,数组的长度,并按照一定的规则对其进行排序(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.此外,我不允许使用任何“特殊”函数,例如qsort等。我只能使用strlen()strcpy()函数以及常规库。

I'm trying to aim for bubble sort but it just wont pass the complier probably because the const type.我试图以冒泡排序为目标,但它可能不会通过编译器,可能是因为const类型。

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.非常感谢您提供详细的答复,而不仅仅是快速修复。

(Note: See EDIT below for alternative to qsort .) (注意:请参阅下面的编辑以替代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.您可以使用qsort库 function 和围绕现有compareStr function 的“qsort/bsearch compare”包装器根据数组元素指向的字符串的内容对const char *str_arr[]数组进行排序。 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".为了正确操作qsort ,您的compareStr function (和包装函数)的返回值需要为“第一个小于第二个”返回一个负值,“第一个等于第二个”返回一个零值,或者“第一个大于”返回一个正值第二”。

#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 .编辑:感谢 Adrian Mole 通知我您不允许使用qsort However, the generic nature of qsort can be used in some other array sorting function using the same parameters.但是, qsort的通用性质可以用于使用相同参数的一些其他数组排序 function。

Here is an insertion sort function using the same parameters as qsort .这是一个插入排序 function ,使用与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 :那么这只是用insertion_sort替换对qsort的调用的一种情况:

void sort_str_array(const char *str_arr[], size_t n)
{
    insertion_sort(str_arr, n, sizeof str_arr[0], qs_compareStr);
}

Here's a rough idea:这是一个粗略的想法:

  1. Using strcpy() , copy the main string into a temporary one.使用strcpy() ,将主字符串复制到临时字符串中。

  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:它给出了成功排序的 output:

DEHLLLOORW

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);因此,“内部循环”中的实际交换只需要保存一个指针的副本(在“temp”变量中); 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 (ie don't copy the string, just the pointer):您应该对fixed_str变量进行类似的操作(即不要复制字符串,只复制指针):

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

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程序 output 是

"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.使用比较 function 您可以指定任何排序标准。 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此时程序output为

"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如果您愿意,可以通过以下方式简化比较 function 声明

int cmp( const char *, const char * )

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 .另外,您说由于const导致错误,但您发布的代码不包含const One can only guess what const you are talking about.只能猜测您在说什么const

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM