2013-04-11 15 views
6

Il seguente è il mio codice e qsort produce strano risultato:qsort e problemi con esso

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

L'output di questo è il programma è il seguente:

2 6c 48 30 24 4 b 16

Anche se avrebbe dovuto essere lo stesso dell'input. Qualcuno può spiegare il motivo per cui è così e come posso correggerlo?

+3

Non posso crederci. Un ** esempio compilabile e completamente autonomo **! Lei, signore, meriti una * medaglia * per questo! +1 e più se potessi. – DevSolar

+1

Buon punto, @DevSolar, dobbiamo _should_ premiare domande come questa. – paxdiablo

risposta

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

Dovresti non essere confrontando int valori se i sottostanti "oggetti" sono char valori.

Ciò che quasi sicuramente accade è che il confronto utilizza i quattro byte (a seconda di sizeof(int)) per fare il confronto, come il primo oggetto che è 0x02040b16 (a seconda delle endianità ovviamente). Ciò riempirà notevolmente il processo.

modificarla in:

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

e riprovare.

E sappiate solo che la firma di char è un problema di implementazione. Potresti scoprire che 0x80 finisce per essere inferiore a 0x7f. Se questo non è ciò che desideri, utilizza unsigned char esplicitamente su estratto i valori, quindi esegui l'upgrade agli interi con segno (con un altro cast) prima di eseguire la sottrazione.

In effetti, per la portabilità, è possibile utilizzare anche signed char per l'altro caso.

Il seguente programma mostra come funziona con sottostante, tipo di dati corretto:

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

L'output di questo è:

2 4 b 16 24 30 48 6c 

(ho scambiato l'ordine degli ultimi due elementi della codice in modo da mostrare che stava effettivamente ordinando qualcosa).

+0

"Ciò riempirà notevolmente il processo." - Sì ... i valori che vengono ordinati cambiano effettivamente durante l'ordinamento! –

+0

Grazie! Ha funzionato subito. – Daylite

+0

Se OP stava ordinando caratteri non firmati, sarebbe 'return * (unsigned char *) a - * (unsigned char *) b' essere errato perché la sottrazione non potrebbe mai produrre un risultato negativo? –

4

Cambia la funzione di confronto per

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