簡體   English   中英

qsort()中使用的比較函數是否有任何限制

[英]Is there any restriction about the compare function used in qsort()

我編寫了以下代碼片段,以將字符串數組排序的順序最小化了它們的串聯:

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

int cmpstr(const void* p1, const void* p2){
    int p1l = strlen((const char*)p1);
    int p2l = strlen((const char*)p2);
    int r = strncmp((const char*)p1, (const char*)p2, p1l<p2l?p1l:p2l);
    if(r == 0 && p1l != p2l){
        if(p1l < p2l){
            return cmpstr(p1, (const char*)p2 + p1l);
        }
        return cmpstr((const char*)p1 + p2l, p2);
    }
    return r;
}

int main(){
    const char* arrstr[] = {"93", "936", "15", "152", "946"};
    int num = sizeof(arrstr) / sizeof(char*);
    qsort(arrstr, num, sizeof(char*), cmpstr);
    for(int i = 0; i < num; i++){
        printf("%s\n", arrstr[i]);
    }
}

這些字符串應按15 152 936 93 946的順序排序。 我們希望93936946之間,因為936 93 < 93 93693 946 < 946 93 (為清楚起見,忽略添加的空格)。

但是代碼沒有按預期工作。 盡管我對cmpstr()測試完全符合我的預期,但該數組根本沒有排序。

我怎么了?

我注意到,當我將cmpstr()的演員表部分從*(char* const*)更改為(char*)qsort()也不起作用。 這是為什么?

傳遞給qsort的比較函數接收要比較的兩個數組元素的地址 由於每個數組元素都是char * ,因此每個元素的地址都是char ** 因此,您缺少一種間接性。

您需要將每個參數char * const *轉換為char * const * ,然后取消引用以獲取指向字符串的指針:

int cmpstr(const void* p1p, const void* p2p){
    char *p1 = *(char * const *)p1p;
    char *p2 = *(char * const *)p2p;
    ...
}

編輯:

因為您要遞歸調用此函數,所以您需要在遞歸函數周圍使用非遞歸包裝器函數,因為它們采用的參數不同:

// internal recursive function that takes two strings
static int cmpstr_int(const char* p1, const char* p2){
    int p1l = strlen(p1);
    int p2l = strlen(p2);
    int r = strncmp(p1, p2, p1l<p2l?p1l:p2l);
    if(r == 0 && p1l != p2l){
        if(p1l < p2l){
            return cmpstr_int(p1, p2 + p1l);
        }
        return cmpstr_int(p1 + p2l, p2);
    }
    return r;
}

// comparison function that extracts desired datatype from void * params
// and passes them to recursive function
static int cmpstr(const void* p1p, const void* p2p){
    const char *p1 = *(char * const *)p1p;
    const char *p2 = *(char * const *)p2p;
    return cmpstr_int(p1, p2);
}

您的比較函數接收指向數組元素的指針。 每個元素都是一個指向char的指針,因此您將獲得一個指向char的指針。

比較邏輯也有些復雜。 這是一個工作版本:

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

int cmpstr(const void* a_, const void* b_)
{
    const char *const *a = a_;
    const char *const *b = b_;
    int la = strlen(*a);
    int lb = strlen(*b);

    if (la == lb) {
        /* same length - sort lexicographically */
        return strcmp(*a, *b);
    }

    if (la < lb) {
        /* a is shorter */
        int result = strncmp(*a, *b, la);
        if (!result) {
            /* a is a prefix of b */
            result = strcmp(*a, *b + la);
        }
        return result;
    }

    /* else, b is shorter - re-enter with arguments swapped,
       and negate the result */
    return -cmpstr(b_, a_);
}

int main() {
    const char* arrstr[] = {"93", "936", "15", "152", "946"};
    const size_t num = sizeof arrstr / sizeof *arrstr;
    qsort(arrstr, num, sizeof *arrstr, cmpstr);
    for (size_t i = 0; i < num; i++) {
        printf("%s\n", arrstr[i]);
    }
}

輸出:

15
152
936
93
946

如果您認為我上面的cmpstr()與原始版本有太大cmpstr() ,請考慮一下此侵入性較小的代碼,該代碼使用您想要的遞歸比較,並使用單獨的包裝器使其適合qsort()

int compare_strings(const char *a, const char *b)
{
    int la = strlen(a);
    int lb = strlen(b);
    int r = strncmp(a, b, la<lb?la:lb);
    if (r == 0 && la != lb) {
        if (la < lb) {
            return compare_strings(a, b + la);
        }
        return compare_strings(a + lb, b);
    }
    return r;
}

int compare_strings_qsort(const void* a_, const void* b_)
{
    const char *const *a = a_;
    const char *const *b = b_;
    return compare_strings(*a, *b);
}

我仍然不得不更改您的變量名,因為我發現p1l之類的東西很難讀。 我可以進一步簡化一點,我認為這比原始功能和上面的第一次嘗試都清晰(但可能需要一些注釋):

int compare_strings(const char *a, const char *b)
{
    const int la = strlen(a);
    const int lb = strlen(b);
    const int r = strncmp(a, b, la<lb?la:lb);

    return (la == lb || r)
        ? r
        : (la < lb)
        ? compare_strings(a, b + la)
        : compare_strings(a + lb, b);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM