2013-04-11 37 views
6

Sau đây là mã của tôi và qsort sản xuất kết quả kỳ lạ:qsort và các vấn đề với nó

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

char values[] = { 0x02,0x04,0x0b,0x16,0x24,0x30,0x48,0x6c}; 

int compare (const void * a, const void * b) 
{ 
    return (*(int*)a - *(int*)b); 
} 

int main() 
{ 

    int i; 

    qsort (values, 8, sizeof(char), compare); 

    for (i = 0; i < 8; i++) 
    { 
     printf ("%0x ",values[ i ]); 
    } 
    return 0; 
} 

Kết quả của việc này là chương trình là:

2 6c 48 30 24 4 b 16

Mặc dù nó phải giống như đầu vào. Ai đó có thể vui lòng giải thích lý do tại sao nó là như vậy và làm thế nào tôi có thể sửa nó?

+3

Tôi không thể tin rằng đây. Một ** hoàn toàn khép kín, ví dụ compilable **! Bạn, thưa bạn, xứng đáng với một * huy chương * cho điều này! 1, và nhiều hơn nữa nếu tôi có thể. – DevSolar

+1

Điểm tốt, @DevSolar, chúng tôi _should_ tặng các câu hỏi như thế này. – paxdiablo

Trả lời

10
return (*(int*)a - *(int*)b); 

Bạn nên không được so sánh int giá trị nếu tiềm ẩn "đối tượng" là char giá trị. Điều này gần như chắc chắn xảy ra là so sánh đang sử dụng bốn byte (tùy thuộc vào sizeof(int)) để so sánh, chẳng hạn như đối tượng đầu tiên là 0x02040b16 (tùy thuộc vào kết thúc của bạn). Điều này sẽ rất nhiều thứ lên quá trình.

Thay đổi nó để:

return (*(char*)a - *(char*)b); 

và thử lại.

Và chỉ cần lưu ý rằng chữ ký số char là sự cố triển khai. Bạn có thể thấy rằng 0x80 kết thúc lên dưới 0x7f. Nếu đó không phải là những gì bạn muốn, hãy sử dụng unsigned char một cách rõ ràng để trích xuất các giá trị, sau đó nâng cấp chúng lên các số nguyên đã ký (với một dàn diễn viên khác) trước khi thực hiện phép trừ.

Thực tế, đối với tính di động, bạn có thể muốn sử dụng signed char một cách rõ ràng cho trường hợp khác.

Chương trình sau đây cho thấy cách thức hoạt động với đúng kiểu dữ liệu cơ bản:

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

signed char values[] = {0x02, 0x04, 0x0b, 0x16, 0x24, 0x30, 0x6c, 0x48}; 

int compare (const void *a, const void *b) { 
    return *(signed char*)a - *(signed char*)b; 
} 

int main (void) { 
    int i; 

    qsort (values, 8, sizeof (char), compare); // char okay here. 
    for (i = 0; i < 8; i++) 
     printf ("%0x ", values[i]); 
    putchar ('\n'); 

    return 0; 
} 

Các ouput của việc này là:

2 4 b 16 24 30 48 6c 

(tôi hoán đổi thứ tự của hai yếu tố cuối cùng trong mã để hiển thị nó đã thực sự sắp xếp thứ gì đó).

+0

"Điều này sẽ rất nhiều thứ lên quá trình." - Yup ... các giá trị đang được sắp xếp thực sự thay đổi trong thời gian sắp xếp! –

+0

Cảm ơn! Nó hoạt động ngay lập tức. – Daylite

+0

Nếu OP sắp xếp các ký tự không dấu, thì 'return * (unsigned char *) a - * (unsigned char *) b' có sai vì phép trừ không bao giờ có thể tạo ra kết quả âm? –

4

Thay đổi chức năng so sánh của bạn để

int compare (const void * a, const void * b) 
{ 
    return (*(char*)a - *(char*)b); 
} 
Các vấn đề liên quan