PDA

View Full Version : [C] Confrontare elementi array


legolas977
09-01-2009, 23:11
Ho due array di 5 elementi.
Esiste un modo veloce per poter confrontare i due array per appurare che contengano gli stessi valori? Senza dover utilizzare for etc?
Grazie saluti.

variabilepippo
09-01-2009, 23:41
Puoi usare la funzione memcmp (http://www.cplusplus.com/reference/clibrary/cstring/memcmp.html), ma sinceramente non so se sia un modo "veloce" rispetto al for per un array di 5 elementi.

gugoXX
10-01-2009, 10:08
Puoi usare la funzione memcmp (http://www.cplusplus.com/reference/clibrary/cstring/memcmp.html), ma sinceramente non so se sia un modo "veloce" rispetto al for per un array di 5 elementi.

Certo, e' una buona idea, e secondo me e' la piu' veloce (certo, 5 e' proprio pochino... ma oggi una chiamata a funzione e' quasi gratis)

Ma solo se l'array e' fatto direttamente di valori. Se e' fatto di puntatori e si vuole confrontare l'uguaglianza degli elementi contenuti ovviamente non va bene.

legolas977
10-01-2009, 10:58
In pratica vi spiego meglio il mio problema, che si risolva con array o altro è la stessa cosa:
Mi trovo ad avere 5 byte da salvare e riconfrontare.
La prima prova che ho fatto è stata questa:
Solo che oltre il long (4 byte), è un incasino impaccarli, perchè occorre assegnare la variabile double, e quando unisco i 5 byte in questo modo,coi cast il borland impazzisce:
double valore;
double appo_valore

appo_valore=((long)(buffer[1]<<32))+((long)(buffer[2]<<24))+((long)(buffer[3]<<16))+((word)(buffer[4]<<8))+buffer[5];

if (appo_valore==0x1122334455l)
prova_ok;
else
prova_non_ok;
(Fatto nel modo sopra, putroppo ha dei problemoni)


In alternativa allora ho pensato di salvarmi con un for i 5 elementi del buffer all'interno di un mio array di 5 elementi:
char array[5];
char appo_array[5]={11,22,33,44,55};
char appo_array2[5]={22,22,33,44,00};
char appo_array3[5]={33,22,33,44,00};

for (a=0,c=1,c==5;a++,c++)
array[a]=buffer[c];

A questo punto però volevo trovare un modo comodo per confrontare
array con i vari appo_array,per non scrivere tanto codice tutte le volte che andrò ad aggiungere dei nuovi appo_array.

Potete aiutarmi? Grazie mille

cionci
10-01-2009, 20:29
Chiaro che è un casino, stai cercando di mettere 5 byte in un intero che ne contiene 4.

Questo:

buffer[1] << 32

ha come risultato 0.

Il confronto più semplice lo puoi appunto fare con memcmp: http://www.cplusplus.com/reference/clibrary/cstring/memcmp.html

legolas977
11-01-2009, 08:58
Puo andar bene cosi?
Si puo sintetizzare di più?
grazie

char array[5];
char appo_array[5]={11,22,33,44,55};
char appo_array2[5]={22,22,33,44,00};
char appo_array3[5]={33,22,33,44,00};
b,d,e char;


for (a=0,c=1,c==5;a++,c++)
array[a]=buffer[c];

b = memcmp (appo_array, array,5);
if (b)
prova_non_ok;
else
prova_ok;

d = memcmp (appo_array2, array,5);
if (d)
prova_non_ok;
else
prova_ok;

e = memcmp (appo_array3, array,5);
if (e)
prova_non_ok;
else
prova_ok;

cionci
11-01-2009, 09:44
Quel for non è corretto, cosa vuoi fare ?

crick_pitomba
11-01-2009, 10:15
appo_valore=((long)(buffer[1]<<32))+((long)(buffer[2]<<24))+((long)(buffer[3]<<16))+((word)(buffer[4]<<8))+buffer[5];



come giustamente ha notato cionci stai pretendendo un po' troppo da un povero intero a 32 bit...

tuttavia per il confronto il metodo è effettivamente più veloce rispetto al for

col for hai 5 confronti + l'overhead

nel caso di tutti i valori impacchettati in un solo valore hai un solo confronto e se il valore deve essere confrontato più volte vale la pena fare lo sforzo di impacchettare i valori.

provo a suggerirti un'alternativa
impacchetta 4 valori in un long e lasci il quinto nel char

long valore=((long)(buffer[2]<<24))+((long)(buffer[3]<<16))+((word)(buffer[4]<<8))+buffer[5];

e lasci buffer[1] in un char

poi
if (valore == LowLongCONST1) && (buffer[1]==HiByteCONST1)
prova_ok
else
prova_non_ok

LowLongCONST1 contiene i 4 byte meno significativi del valore che devi confrontare e HiByteCONST1 il byte più significativo (o mettili come più ti aggrada... Li ho messi così perchè se ad esempio hai 5 valori di confronto che potrebbero iniziare con lo stesso valore puoi mettere il confronto col byte più significativo in evidenza e saltare 5 confronti in una volta sola se il byte iniziale non è quello atteso)

il vantaggio in questo caso è avere al massimo 2 confronti (se fallisce il primo il secondo non viene effettuato)

per confrontare questa soluzione con memcmp, bisognerebbe sapere memcmp come è implementata

puoi provare a fare qualche decina di migliaia di confronti con questa soluzione e con quella con memcmp prendere i tempi e vedere tra le due quale è più efficiente

cionci
11-01-2009, 10:25
Sicuramente è più efficiente fare il confronto byte a byte che usare memcmp...ma poi non capisco perché tu non voglia usare un for. Nota che memcmp è di fatto implementata con un for.

L'implementazione di memcmp è qualcosa di questo tipo:

for(i = 0; i < n; i++)
{
if(*((char *)ptr1 + i) != *((char *)ptr2 + i))
return *((char *)ptr1 + i) - *((char *)ptr2 + i);
}

return 0

Scrivere esplicitamente:

if(v1[0] == v2[0] && v1[1] == v2[1] && v1[2] == v2[2] && v1[3] == v2[3] && v1[4] == v2[4])
prorva_ok

è probabilmente più veloce di scrivere un for, ma sicuramente, almeno secondo il mio punto di vista, è meno leggibile.

gugoXX
11-01-2009, 10:39
Giocando con i puntatori si possono limitare i confronti ad essere solo 2.

Ma io continuo a votare per la memcmp.
Piu' compatta, meno errori e piu' chiara (almeno per molti)
E forse anche piu' veloce del ciclo for, a meno che al posto dell'indice non si cicli direttamente su puntatori.

Penso che la memcmp lavori con puntatori direttamente al posto degli indici. Almeno, io la scriverei cosi' (non ho provato a compilare ne ovviamente ad eseguire)

for(char* u1=ptr1, char* u2=ptr2, i=0; i<5; i++, u1++, u2++)
{
char val = *u1-*u2;
if (val!=0) return val;
}
return 0;



O, meglio ancora (forse), nell'implementazione sotto intel based userei la REP CMPSB

cionci
11-01-2009, 11:01
Che castroneria ho scritto sopra :muro: :D
Corretto :D

Unrue
11-01-2009, 11:06
Ma solo se l'array e' fatto direttamente di valori. Se e' fatto di puntatori e si vuole confrontare l'uguaglianza degli elementi contenuti ovviamente non va bene.

Perchè?

gugoXX
11-01-2009, 11:14
Perchè?

Intendo, se l'array al posto che contenere direttamente dei valori contenesse elementi complessi, ovvero fosse un puntatore di puntatori, ovviamente confrontare tra loro i puntatori di tali elementi non garantirebbe l'uguaglianza o la diversita' del loro contenuto.

legolas977
11-01-2009, 12:06
""Quel for non è corretto, cosa vuoi fare ?""

Salvo nell'array "array" (nelle posizioni dalla 0 alla 4) valori che mi arrivano su un buffer (dalla posizione 1 alla 5).
Poi dovrei confrontare singolarmente:
"array" con "appo_array",
"array" con "appo_array2",
"array" con "appo_array3"


Ma la sintassi del memcmp è arabo.
Io appunto avevo provato a far cosi:



char array[5];
char appo_array[5]={11,22,33,44,55};
char appo_array2[5]={22,22,33,44,00};
char appo_array3[5]={33,22,33,44,00};
b,d,e char;


for (a=0,c=1,c==5;a++,c++)
array[a]=buffer[c];

b = memcmp (appo_array, array,5);
if (b)
prova_non_ok;
else
prova_ok;

d = memcmp (appo_array2, array,5);
if (d)
prova_non_ok;
else
prova_ok;

e = memcmp (appo_array3, array,5);
if (e)
prova_non_ok;
else
prova_ok;

legolas977
11-01-2009, 12:12
Fatto in alternativa nel modo seguente:

--------
long valore=((long)(buffer[2]<<24))+((long)(buffer[3]<<16))+((word)(buffer[4]<<8))+buffer[5];

e lasci buffer[1] in un char

poi
if (valore == LowLongCONST1) && (buffer[1]==HiByteCONST1)
prova_ok
else
prova_non_ok
-------------
Dovrei dichiarare "LowLongCONST1" come long e "HiByteCONST1" come char e assegnarli i valori per poterli poi utilizzare da confronto?
Ad esempio:

long LowLongCONST1[4] ={11,12,13,14};
char HiByteCONST1[1]={15};

Cosi andrebbe bene crick_pitomba ?
Grazie mille

gugoXX
11-01-2009, 12:14
non e' necessario usare l'array di appoggio, puoi confrontare direttamente su buffer.
Se proprio devi copiare i valori dell'array, userei memcpy, e non il ciclo for.
Per sapere se 3 array diversi contengono gli stessi valori, non e' necessario effettuare 3 cicli di confronti. Per la proprieta' transitiva se A==B e B==C allora A==C per forza.

gugoXX
11-01-2009, 12:18
Fatto in alternativa nel modo seguente:

--------
long valore=((long)(buffer[2]<<24))+((long)(buffer[3]<<16))+((word)(buffer[4]<<8))+buffer[5];

e lasci buffer[1] in un char

poi
if (valore == LowLongCONST1) && (buffer[1]==HiByteCONST1)
prova_ok
else
prova_non_ok
-------------
Dovrei dichiarare "LowLongCONST1" come long e "HiByteCONST1" come char e assegnarli i valori per poterli poi utilizzare da confronto?
Ad esempio:

long LowLongCONST1[4] ={11,12,13,14};
char HiByteCONST1[1]={15};

Cosi andrebbe bene crick_pitomba ?
Grazie mille

Ma perche' questi shift?
Se proprio si dovesse passare da qui, e io non lo farei, basterebbe


long* lp1 = (long*)buffer;

e poi confrontare tra loro i contenuti dei long*

cionci
11-01-2009, 12:24
for (a=0,c=1,c==5;a++,c++)
array[a]=buffer[c];

Ribadisco che la sintassi non è corretta, devi mettere un ; dopo c=1.
Memcmp ritorna 0 se non ci sono differenza. Sulla sintassi...ti ho riportato appositamente il link per leggerla :D

crick_pitomba
11-01-2009, 22:14
Fatto in alternativa nel modo seguente:

--------
long valore=((long)(buffer[2]<<24))+((long)(buffer[3]<<16))+((word)(buffer[4]<<8))+buffer[5];

e lasci buffer[1] in un char

poi
if (valore == LowLongCONST1) && (buffer[1]==HiByteCONST1)
prova_ok
else
prova_non_ok
-------------
Dovrei dichiarare "LowLongCONST1" come long e "HiByteCONST1" come char e assegnarli i valori per poterli poi utilizzare da confronto?
Ad esempio:

long LowLongCONST1[4] ={11,12,13,14};
char HiByteCONST1[1]={15};

Cosi andrebbe bene crick_pitomba ?
Grazie mille

si, l'idea è quella ma dovrebbe essere
long LowLongCONST1 = 0x11121314;
char HiByteCONST1=0x15;

nel modo in cui tu hai indicato avresti 4 long con i valori 11,12,13,14
(giuto cionci? il mio c è irrimediabilmente arrugginito)

mi è piaciuta la soluzione di gugoxx che riduce ulteriormente il costo abolendo anche gli shift... molto elegante, anche se in questo caso sarebbe interessante vedere a basso livello la cosa come funziona: se i byte non sono correttamente allineati quel cast ha comunque un costo in termini di shift.

Indipendentemente da questo c'è sempre un problema molto serio e ti spiego per quale motivo potrebbe essere necessario usare gli shift: su piattaforma intel un cast interpreterebbe il valore come little endian e questo potrebbe creare dei problemi

per ottenere il valore 0x00929190 devo avere un buffer di questo tipo
buffer[4]={0x90,0x91,0x92,0x0};

solo in questo caso il cast *(long *)buffer restituirebbe 0x00929190

era questo il motivo per cui non ho toccato gli shift nella mia risposta iniziale: di solito gli header o alcuni caratteri di controllo di alcuni formati di file usano il sistema big-endian (ad esempio i marker jpg) quindi gli shift ti servono per ricostruire l'header del file in formato little endian.

insomma se non sappiamo esattamente lui cosa deve fare discutere su cosa sia meglio è inutile... la mia soluzione era semplicemente la più vicina al suo codice continuando a non usare i cicli for... e preservando la costruzione del dato

A scatola chiusa, voi tutti potreste avere ragione... ho visto cose nel corso degli anni veramente raccapriccianti.

la soluzione più semplice potrebbe essere scrivere una funzione di confronto esterna da chiamare in questo modo

mycmp(buffer, "app0")
se gli appo sono in formato testuale

oppure
mycmp(buffer, constval)
dove constval è un intero a 64 bit se il compilatore consente questo tipo di variabile

entrambe con un ciclo for all'interno... e l'opportuna "logica" per il confronto

oppure usare come avete correttamente suggerito memcmp

insomma le soluzioni possibili sono infinite per problemi di questo genere bisogna solo sapere uno cosa deve fare.

gugoXX
11-01-2009, 22:59
Indipendentemente da questo c'è sempre un problema molto serio e ti spiego per quale motivo potrebbe essere necessario usare gli shift: su piattaforma intel un cast interpreterebbe il valore come little endian e questo potrebbe creare dei problemi

Quale che sia, little o big endian, se devo confrontare 2 serie da 4 byte e lo faccio mediante un long, non importa la loro codifica. Verranno letti e codificati allo stesso modo, e il confronto sara' corretto.

crick_pitomba
12-01-2009, 10:47
Quale che sia, little o big endian, se devo confrontare 2 serie da 4 byte e lo faccio mediante un long, non importa la loro codifica. Verranno letti e codificati allo stesso modo, e il confronto sara' corretto.

su questo non ci piove... se vengono letti e codificati allo stesso modo non c'è problema!

legolas977
12-01-2009, 20:26
Ho risolto poi cosi:
res = memcmp(appo_array, buffer+1, 5);

Grazie a tutti per i consigli!
Legolas