PDA

Visualizza la versione completa : [C] Ordinare array di puntatori


Smoke666
22-03-2012, 15:06
Ciao a tutti. Ho un grosso problema. Ho definito una struttura dati che ho chiamato scheda, definita come segue:


typedef struct scheda{ int anno;
char nome;
char titolo; }scheda_t;

Il mio array è scheda_t* array[].

La funzione deve ordinare l'array di puntatori a schede a seconda di uno dei tre campi (della scheda) specificato dal tipo enum campo_c, e riceve in input i seguenti parametri, restituendo un int:


int sort_schede(scheda_t* array[], int n, campo_t c)

Ho intenzione di usare la qsort() già implementata nella stdlib.h, utilizzando la "versione" per le stringhe, se si tratta di ordinare i campi costituiti da char, altrimenti la versione "numerica" per gli interi.
Qui sorge il problema, non posso passare a qsort l'array di puntatori a schede, quindi devo accedere ad ogni singola scheda mediante un ciclo sull'array di puntatori, andare a prendere il campo specificato dal parametro c, e ordinare i puntatori in base al campo...Tuttavia non ho la minima idea di come possa fare! Qualcuno ha qualche suggerimento da darmi? Sono 2 giorni che sono bloccato su questa funzione :dhò: :dhò: Grazie in anticipo!

EDIT: dimenticavo, n è il numero di schede, e quindi di puntatori, presenti nell'array.

ramy89
22-03-2012, 15:17
Perché non puoi passare alla qsort l' array di puntatori schede?
Puoi farlo, basta implementare un metodo per fare il confronto tra due puntatori a schede.Ma se vuoi semplicemente ordinarle potresti anche usare un array di schede.Con entrambe i metodi si può fare (ovviamente la funzione compare cambierà).
Però se vuoi essere aiutato sul serio posta il codice intero.

Smoke666
22-03-2012, 15:27
Io devo ordinare le schede puntante dagli elementi dell'array in base al campo, quindi in ordine lessicografico se si tratta di stringhe, o in ordine crescente se si tratta di campi interi. Quindi si tratta di andare a prendere il campo "c" della scheda puntata da array[i], e confrontarlo con il medesimo campo della scheda puntata da array[i+1]. Se il primo è maggiore del secondo, sposto il puntatore, altrimenti procedo con un altro controllo. L'array di schede non lo posso usare, in quanto non posso modificare i parametri che prende in input la funzione. Non so se sono riuscito a spiegarti meglio come dovrei ordinare il tutto...

Smoke666
22-03-2012, 15:40
La domanda principale è: come posso fare a variare la funzione compare nella qsort in base al tipo di campo che mi è richiesto? Se devo ordinare una stringa, avrò un ordinamento lessicografico ottenuto mediante la strcmp, se ho il campo anno, la funzione sarà ovviamente diversa...Ma io non so a priori che campo mi sarà chiesto di ordinare, quindi non riesco a costruire una funzione di compare che mi preveda entrambi i casi...Il codice non l'ho ancora scritto, poichè si tratta giusto dell'ultima funzione di un grosso progetto scritto in C sequenziale...Quale dettaglio in più ti serve?

ramy89
22-03-2012, 15:52
Ma l' hai letta la funzione? :confused:



void qsort ( void * base, size_t num, size_t size, int ( * comparator ) ( const void *, const void * ) );


Gli puoi passare come parametro un array di schede.
Io credevo che gli volevi passare puntatori per qualche necessità particolare, ma in questo caso non c'è bisogno.
Potevi comunque farlo, ma cambiava la funzione compare.
Però non hai ancora postato il codice.

ramy89
22-03-2012, 15:55
Originariamente inviato da Smoke666
La domanda principale è: come posso fare a variare la funzione compare nella qsort in base al tipo di campo che mi è richiesto? Se devo ordinare una stringa, avrò un ordinamento lessicografico ottenuto mediante la strcmp, se ho il campo anno, la funzione sarà ovviamente diversa...Ma io non so a priori che campo mi sarà chiesto di ordinare, quindi non riesco a costruire una funzione di compare che mi preveda entrambi i casi...Il codice non l'ho ancora scritto, poichè si tratta giusto dell'ultima funzione di un grosso progetto scritto in C sequenziale...Quale dettaglio in più ti serve?

Con un puntatore a funzione puoi farlo.
Fai una funzione compare_nome, una compare_cognome, una compare_anni, ecc...
A seconda del campo che viene richiesto, passi il puntatore a funzione giusto.
Ad esempio la funzione compare_nome usa la strcmp sui nomi dell schede.
Posta il codice anche se è kilometrico.

Smoke666
22-03-2012, 16:11
La funzione di compare tra stringhe l'ho realizzata così:



int comparatore_stringhe(const void *p1, const void *p2){
/*
I due parametri sono dei puntatori ai valori dell'array,
ovvero 2 puntatori a stringhe: char **. Prima li
"interpretiamo" con un cast a puntatori a stringhe,
poi li dereferenziamo per ottenere l'effettiva stringa.
*/
char *stringa1 = *(char **)p1;
char *stringa2 = *(char **)p2;
int i;

/*
Confronto alfabetico tra due stringhe.
Se una stringa e' prefisso dell'altra, essa e' minore.
Supponendo non siano ne' identiche ne' prefisso,
allora il primo carattere discordante determina l'ordinamento.
La procedura sotto è equivalente ad una chiamata alla funzione
strcmp(stringa1, stringa2); definita in string.h
*/
for (i=0; stringa1[i] == stringa2[i] && stringa1[i] != '\0'; i++);

if ( stringa1[i] < stringa2[i] )
return -1;
else if ( stringa1[i] == stringa2[i] /* == '\0' */)
return 0;
else return 1;
}


Quella per il confronto tra interi invece è:


int compara_int(const void *a, const void *b)
{
primo=*(int *)a;
secondo= *(int *)b;

if (primo<secondo) return -1;
if(primo>secondo) return 1;

return 0;
}


Ora queste due funzioni le devo passare alla qsort in base al campo che mi viene richiesto: se è un campo di tipo stringa, passo la prima, se è un campo di tipo intero passo la seconda. E' qui che sorge il mio problema..come posso sapere quale delle due "versioni" mi serve, non conoscendo a priori il campo?

Smoke666
22-03-2012, 16:16
Quindi mi suggerisci di invocare la qsort corretta con uno switch?

ramy89
22-03-2012, 16:37
Non è così che funziona la qsort.Se tu hai un array di schede, la qsort internamente farà una cosa del genere:


// in mezzo al codice
scheda s1,s2;
if(compare(s1,s2)>0)
swap(&s1,&s2);


Per cui le funzioni che hai fatto sono sbagliate, semmai:



int compara_nomi (const void *p1, const void *p2)
{
scheda s1 = * ((scheda*)p1);
scheda s2= * ((scheda*)p2);
return strcmp(s1.nome,s2.nome);
}


E questa è la funzione che passerai come argomento alla qsort, usando un array di schede e non un array di puntatori a schede (non sarebbe necessario).
Il cast non è "magico", se quel const void* p1 è un puntatore a un' area di memoria che contiene un dato di tipo scheda, convertendolo in char** non ottieni il puntatore al campo che contiene il nome.



Quindi mi suggerisci di invocare la qsort corretta con uno switch?


Questa è una possibile soluzione.
A seconda della scelta (suppongo ci sia un menù) dell' utente, all' interno dello switch cambi il valore del puntatore a funzione che passerai alla qsort.

Smoke666
23-03-2012, 12:14
Grazie mille per il consiglio, ho quasi finito di implementare la funzione di ordinamento, solo che al momento della compilazione ottengo degli errori. Cercando in rete ho trovato a cosa si riferiscono, ma qualunque "modifica" io faccia non cambia il warning... La riga di codice incriminata è proprio l'invocazione della qsort. Posto quella che ho fatto:


for(i=0;i<n;i++)
for(j=i+1;j<n;j++)
qsort(sarray, n, sizeof(scheda_t), funzione_compara(sarray[i],sarray[j])

Il warning è questo:


warning: passing argument 4 of ‘qsort’ makes pointer from integer without a cast [enabled by default]
/usr/include/stdlib.h:761:13: note: expected ‘__compar_fn_t’ but argument is of type ‘int’


Come posso risolvere? Grazie! :D

Loading