【问题标题】:Unexpected behaviour from sorting functions排序函数的意外行为
【发布时间】:2016-04-16 07:51:50
【问题描述】:

作为作业,我编写了这个程序,它应该使用 qsort_r 对控制台输入进行排序(这是我无法更改的一件事,我们需要使用 qsort_r)。我们应该实现三种不同的排序功能; compVal 通常按值对输入进行排序,compOnes 按其位值包含的 1 的数量对输入进行排序,而 compBitSeq 按最长的位序列对它们进行排序(并且排序应该双向工作,因此方向变量)。

正常的排序功能可以正常工作。不过,我无法让 compOnes 和 compBitSeq 工作。我自己尝试了辅助功能 countOnes 和 bitSequence;他们似乎工作得很好,做我期望他们做的事。但是,当我尝试调整程序时,整个程序会给我一个分段错误。

由于我对指针还不是超级安全,因此我无法真正确定这里出了什么问题。我确实假设将函数传递给函数可能存在问题,并且我没有正确传递所有值,但我不确定该怎么做?我尝试将所有内容放在一个函数中,这非常不雅,因为我必须执行相同的循环才能同时找到 acount 和 bcount,但这也没有用。 qsort_r 也降低了我的灵活性,因为我必须坚持函数所需的数据类型。


我现在已经摆脱了分段错误,将函数 strcomp 与 memcmp 互换就可以了!现在我确实得到了一个输出,但它并不如预期的那样,我无法理解这里出了什么问题。我已经用几个值尝试了我的 countOnes 和 bitSeq 函数,输出告诉我正在确定的值是正确的(我在我的代码中对此进行了评论,所以我知道它应该是什么顺序)。但是排序似乎是完全随机的(可能不是,但我真的不知道它是按什么排序的......而且我确实觉得每次输出都不同,即使数字相同,特别是如果我以不同的顺序输入它们),即使是完全正常的排序顺序。

如果这有帮助,我现在修改了我的函数,以便打印他们正在比较的数字,并且......这是一些负数: 数字 a:-41,数字 b:-39,顺序:-2 数字 a:-34,数字 b:-31,顺序:-3 数字 a:-36,数字 b:-34,顺序:-2 数字 a:-41,数字 b:-36,顺序:-5 数字 a:-39,数字 b:-36,顺序:-3 3、15、7、97、32

(显然,数字在输入时就出来了,因为这些值都给出了否定的结果......)

他们来自哪里?显然我传递了一些错误,但我不知道是什么......?也许某些数据类型混乱了,但我不知道是哪一个以及在哪里。我试图改变一些事情,但没有帮助。

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

int compVal (const void *a, const void *b, void *direction) {
    int order = memcmp(a, b, sizeof(char)) * *(int *) direction;
    printf("number a: %d, number b: %d, order: %d\n", *(char *)a, *(char *)b, order);
    if (order > 0) {
        return 1;
    } else if (order < 0) {
        return -1;
    } else {
        return 0;
    }
}

int countOnes (char number) {
    int counter = 0;
    for (int i = 0; i < (8 * sizeof(char)); i++) {
        if (number & 1) {
            counter += 1;
        }
        number = number >> 1;
    }
    return counter;
}

int bitSequence (char number) {
    int bit = number & 1;
    number = number >> 1;
    int current = 1, max = 1;
    for (int i = 1; i < (8 * sizeof(char)); i++) {
        if ((number & 1) == bit) {
            current += 1;
            if (current > max) {
                max = current;
            }
        } else {
            current = 1;
        }
        bit = number & 1;
        number = number >> 1;
    }
    return max;
}

int compOnes (const void *a, const void *b, void *direction) {
    char achar = *(char *) a, bchar = *(char *) b;
    char acount = countOnes(achar);
    char bcount = countOnes(bchar);
    //return memcmp(&acount, &bcount, sizeof(char)) * *(int *) direction;
    printf("ones a: %d, ones b: %d\n", acount, bcount);
    return compVal(&acount, &bcount, &direction);
}

int compBitSeq (const void *a, const void *b, void *direction) {
    char achar = *(char *) a, bchar = *(char *) b;
    char aseq =  bitSequence(achar);
    char bseq = bitSequence(bchar);
    //return memcmp(&aseq, &bseq, sizeof(char)) * *(int *) direction;
    printf("sequence a: %d, sequence b: %d\n", aseq, bseq);
    return compVal(&aseq, &bseq, &direction);
}

int main (int argc, char* argv[]) {

    if (argc < 3) {
        printf("At least 2 values needed for sorting\n");
        return EXIT_FAILURE;
    }

    int direction = 1;

    qsort_r(&argv[1], argc - 1, sizeof(char *), compVal, &direction);           // 3, 7, 15, 32, 97

    //qsort_r(&argv[1], argc - 1, sizeof(char *), compOnes, &direction);        // 32, 3, (7, 97), 15

    //qsort_r(&argv[1], argc - 1, sizeof(char *), compBitSeq, &direction);      // (97, 15), (7, 32), 3

    //char test1 = countOnes(3), test2 = countOnes(7), test3 = countOnes(15), test4 = countOnes(32), test5 = countOnes(97);
    //printf("%d, %d, %d, %d, %d\n", test1, test2, test3, test4, test5);    // 2, 3, 4, 1, 3

    //test1 = bitSequence(3), test2 = bitSequence(7), test3 = bitSequence(15), test4 = bitSequence(32), test5 = bitSequence(97);
    //printf("%d, %d, %d, %d, %d\n", test1, test2, test3, test4, test5);    // 6, 5, 4, 5, 4

    for (int i = 1; i < argc; i++) {
        if (i == argc -1) {
            printf("%s\n", argv[i]);
        } else {
            printf("%s, ", argv[i]);
        }
    }

    return EXIT_SUCCESS;

}

【问题讨论】:

  • argvchar* 的数组,而不是 int*。 this(*(int *) a) 有对齐问题。
  • 比较函数产生的返回值是否必须为-1、0或1才能得到正确的结果?或者它可以是任何正值或负值吗?不知道我是否需要在这里考虑其他任何事情......
  • 这取决于排序功能的实现。
  • 好吧不,也不是这样,显然我比较的数字已经错了……

标签: c sorting segmentation-fault qsort


【解决方案1】:

您将指向int 的指针传递给strcmp(),这会调用未定义的行为,因为strcmp() 需要一个nul 终止的字节序列,而整数不是。

试试

memcmp(a, b, sizeof(int));

同样sizeof(char) 总是1,而CHAR_BIT 不一定是8 所以这个

for (int i = 1; i < 8 * sizeof(char); i++)

可以

for (int i = 1 ; i < CHAR_BIT ; i++)

改为。

【讨论】:

  • 哈哈。那确实摆脱了分段错误,谢谢!然而,我刚刚意识到这些功能并没有做我想要的,毕竟。但这是一个不同的故事......
最近更新 更多