简体   繁体   中英

Weird qsort behavior, what's wrong?

Why doesn't the code below sort the month names? Base address is correct, number of elements is correct, size of each element is correct, cmp function is correct. gcc -W -Wall -ansi -pedantic doesn't complain a peep.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int by_name(const void *a, const void *b) {
    fprintf(stderr, "%p %p\n", a, b);
    return strcmp((const char *)a, (const char *)b);
}
int main(void) {
    char *months[] = {
        "January",
        "Februar",
        "March",
        "April",
        "May",
        "June",
        "July",
        "August",
        "September",
        "October",
        "November",
        "December"
    };
    unsigned n;

    qsort(months, sizeof months / sizeof *months, sizeof *months,
        by_name);
    for (n = 0; n < sizeof months / sizeof *months; ++n) {
        fprintf(stderr, "%d %p %s\n", n, months[n], months[n]);
    }
    return 0;
}

I've added some code to see what qsort is actually doing, here's the result. We see that the addresses that qsort is passing to the compare function are completely different from where the array data actually is. What's wrong?

I've used qsort many times, mostly to sort structs of all sorts, but never something as primitive as this (I need to decode some really stupid datetime strings).

0x1ffeffffb8 0x1ffeffffc0
0x1ffeffffb0 0x1ffeffffb8
0x1ffeffffd0 0x1ffeffffd8
0x1ffeffffc8 0x1ffeffffd0
0x1ffeffffb0 0x1ffeffffc8
0x1ffeffffb8 0x1ffeffffc8
0x1ffeffffc0 0x1ffeffffc8
0x1ffeffffe8 0x1ffefffff0
0x1ffeffffe0 0x1ffeffffe8
0x1fff000000 0x1fff000008
0x1ffefffff8 0x1fff000000
0x1ffeffffe0 0x1ffefffff8
0x1ffeffffe8 0x1ffefffff8
0x1ffefffff0 0x1ffefffff8
0x1ffeffffb0 0x1ffeffffe0
0x1ffeffffb8 0x1ffeffffe0
0x1ffeffffc0 0x1ffeffffe0
0x1ffeffffc8 0x1ffeffffe0
0x1ffeffffd0 0x1ffeffffe0
0x1ffeffffd8 0x1ffeffffe0
0 0x10a00b January
1 0x10a013 Februar
2 0x10a01b March
3 0x10a021 April
4 0x10a027 May
5 0x10a02b June
6 0x10a030 July
7 0x10a035 August
8 0x10a03c September
9 0x10a046 October
10 0x10a04e November
11 0x10a057 December

Use in the comparison function the following return statement

return strcmp( *(const char ** )a, *(const char **)b );

The comparison function gets pointers to the array elements that in turn have a pointer type.

Also pay attention to that with the unsigned variable n you should use the format conversion specifier %u .

Here is your updated program

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int by_name(const void *a, const void *b) {
    return strcmp(*(const char **)a, *(const char **)b);
}
int main(void) {
    char *months[] = {
        "January",
        "Februar",
        "March",
        "April",
        "May",
        "June",
        "July",
        "August",
        "September",
        "October",
        "November",
        "December"
    };
    unsigned n;

    qsort(months, sizeof months / sizeof *months, sizeof *months,
        by_name);
    for (n = 0; n < sizeof months / sizeof *months; ++n) {
        printf("%u %p %s\n", n, months[n], months[n]);
    }
    return 0;
}

Its output might look like

0 0x56490a5b001a April
1 0x56490a5b002e August
2 0x56490a5b0050 December
3 0x56490a5b000c Februar
4 0x56490a5b0004 January
5 0x56490a5b0029 July
6 0x56490a5b0024 June
7 0x56490a5b0014 March
8 0x56490a5b0020 May
9 0x56490a5b0047 November
10 0x56490a5b003f October
11 0x56490a5b0035 September

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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