【问题标题】:Sorting a const char* array of strings in C - Exercise在 C 中对 const char* 字符串数组进行排序 - 练习
【发布时间】:2021-04-19 16:56:16
【问题描述】:

我在这里搜索了一个类似的问题,但找不到。我是大学的学生,我们需要做一个函数接收const char *str_arr[],数组的长度,并按照一定的规则对其进行排序(与ATM无关)。

我试图了解如何对这个数组进行排序,如果它是常数?也许通过修改指针,因为常量只是字符串值?但是怎么做呢?

此外,我不允许使用任何“特殊”函数,例如qsort 等。我只能使用strlen()strcpy() 函数以及常规库。

我正试图以冒泡排序为目标,但它只是不会通过编译器,可能是因为 const 类型。

这是排序的循环:

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

非常感谢您提前回复。非常感谢您提供详细的回复,而不仅仅是快速修复。

【问题讨论】:

  • const char 类型复制到一个简单的非常量字符数组中,然后尝试对其进行排序。
  • 我真的不知道如何应用这样的动作。如果你能告诉我一个简单的例子,将不胜感激。
  • 注意:qsort拥有标准库...
  • 我知道,它属于stdlib.h,不能用。
  • 那你的问题到底是什么?你的排序功能不起作用吗?

标签: arrays c sorting c-strings bubble-sort


【解决方案1】:

(注意:请参阅下面的编辑以替代qsort。)

您可以使用qsort 库函数和围绕现有compareStr 函数的“qsort/bsearch compare”包装器,根据数组元素指向的字符串的内容对const char *str_arr[] 数组进行排序。这只会移动指针。字符串的内容不会移动。

为了正确操作qsortcompareStr 函数(和包装函数)的返回值需要为“第一个小于秒”返回一个负值,为“第一个等于第二个”返回零,或者“第一个大于第二个”的正值。

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

编辑:感谢 Adrian Mole 通知我不允许使用 qsort。但是,qsort 的泛型性质可以用于其他使用相同参数的数组排序函数。

这是一个插入排序函数,使用与qsort相同的参数。它不如快速排序算法高效,但相对容易实现。

#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;
            }
        }
    }
}

那么就是简单的用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);
}

【讨论】:

  • 更正了代码。为之前的错误道歉!
  • @AdrianMole 谢谢,我从来没有发现过。我刚刚添加了一个插入排序函数作为替代,使用与qsort 相同的参数。
【解决方案2】:

这是一个粗略的想法:

  1. 使用strcpy(),将主字符串复制到一个临时字符串中。

  2. 按字母顺序交换字母以对其进行排序。

  3. 打印出来。


将其解释为代码(注意 cmets):

#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;
}

它给出了成功排序的输出:

DEHLLLOORW

【讨论】:

  • 认为 OP 想要比较/交换字符串数组中的整个字符串。如果是这样,那么就不需要任何strcpy - 所需要的只是交换指针。
  • @AdrianMole 你认为 OP 想要char *mod_str = main_str(当main_strconst char * 的一种类型时)?
  • 他们说一个函数接收const char *str_arr[] 并对该数组进行排序。
【解决方案3】:

查看您的代码,我无法完全弄清楚您的排序“算法”是如何工作的(或者即使是这样)。但是,尽管存在这个问题,但您的问题来自于您不必要地复制字符串,而不仅仅是交换指针。

因此,“内部循环”中的实际交换只需要保存一个指针的副本(在“temp”变量中);像这样:

    //...
        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!
        }

您应该对fixed_str 变量进行类似的操作(即不要复制字符串,只复制指针):

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

【讨论】:

  • hmmm 我想我现在明白了,我在这个问题上缺乏算术,使用 const char 类型。太棒了!
【解决方案4】:

这个数组声明

const char *str_arr[]

表示您有一个指向(的第一个字符)字符串的指针数组。那就是数组的元素是指针。并且要对数组进行排序,您需要交换指向字符串的指针元素。

这是一个演示程序,它展示了如何根据数组元素所指向的字符串的字典比较对这样的数组进行排序。

#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;
}

程序输出是

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

使用比较功能,您可以指定任何排序标准。例如,要按字符串长度对数组进行排序,您可以编写

#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;
}

此时程序输出为

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

如果您愿意,可以通过以下方式简化比较函数声明

int cmp( const char *, const char * )

【讨论】:

  • 我觉得bubble_sortqsort使用同一个界面会更好。目前,我没有看到将void * 用于cmp 函数的意义,因为它传递指向字符串的指针而不是传递指向字符串指针的指针。
  • @IanAbbott 我认为让学生的排序功能更复杂不是一个好主意。但是比较函数的接口是有用的,虽然该函数不接受指向指针的指针。
  • 那很好,但是为什么将cmp的参数定义为const void *而不是const char *呢?由于这个cmp 函数目前不能与qsort 一起使用(至少对于const char * 的数组排序),为什么要使用const void *
  • @IanAbbott 在这种情况下,很容易更改函数 bubble_sort 以对其他类型的数组进行排序。
  • 感谢您的详细解释。非常感谢!
【解决方案5】:

如果您想编写自己的字符串排序例程,您应该创建一个指向字符串的指针数组,然后对该数组进行排序。您可以从指针访问原始字符串以比较它们。在排序算法中复制字符串效率非常低。

另外,您说由于const 而出现错误,但您发布的代码不包括const。你只能猜到const你在说什么。

【讨论】:

    猜你喜欢
    • 2012-09-13
    • 1970-01-01
    • 2012-08-31
    • 2011-04-25
    • 2013-09-22
    • 2011-08-14
    • 2010-09-09
    • 2021-08-16
    • 2011-09-04
    相关资源
    最近更新 更多