2009-02-27 5 views
11

quando faccio una chiamata alla stringa C confrontare funzione come questa:Perché lo strcmp() restituisce 0 quando i suoi ingressi sono uguali?

strcmp("time","time")

Esso restituisce 0, il che implica che le stringhe non sono uguali.

Qualcuno può dirmi perché le implementazioni C sembrano farlo? Penserei che restituirebbe un valore diverso da zero se uguale. Sono curioso delle ragioni per cui vedo questo comportamento.

+0

Tempo! = Denaro direttamente - è necessario utilizzare prima una conversione unità. –

+4

complimenti a chiunque abbia rielaborato questa domanda di spam in qualcosa di potenzialmente utile per i neofiti. Non sono ancora disposto a votare per questo, per non incoraggiare il PO a postare nuovamente questa trippa. – rmeador

+3

@remeador: Grazie, ma non insultare l'OP. – GEOCHET

risposta

22

strcmp restituisce una differenza lessicale (o dovrei chiamarla "comparatore di byte seriale di cortocircuito"? :-)) delle due stringhe fornite come parametri. 0 significa che entrambe le stringhe sono uguali

Un valore positivo significa che s1 sarebbe dopo s2 in un dizionario.

Un valore negativo significa che s1 sarebbe prima di s2 in un dizionario.

Da qui il valore diverso da zero quando si confrontano "tempi" e "soldi" che sono ovviamente diversi, anche se si potrebbe dire che il tempo è denaro! :-)

+2

strcmp() non fare un confronto lessicale, si è limitata a confronto il valore di ogni personaggio fino a quando v'è una differenza o entrambe le stringhe terminare. – Ferruccio

+0

Potrei giurare che ho letto documenti che dicevano che strcmp() fa un paragone lessicale, ma alcuni quick googling suggeriscono che Ferruccio è corretto ...potrebbe essere cambiato ad un certo punto? – rmeador

+0

No. Sempre così :-) – Ferruccio

3

È sembrano voler strcmp a lavorare come una (ipotetica)

int isEqual(const char *, const char *) 

per essere sicuri che sarebbe vero l'interpretazione "zero è falso" dei risultati interi, ma sarebbe complicare la logica di smistamento perché, avendo stabilito che le due stringhe non erano le stesse, avresti ancora bisogno di imparare quale è venuto "prima".

Inoltre, ho il sospetto che un'implementazione comune assomiglia

int strcmp(const char *s1, const char *s2){ 
    const unsigned char *q1=s1, *q2=s2; 
    while ((*q1 == *q2) && *q1){ 
     ++q1; ++q2; 
    }; 
    return (*q1 - *q2); 
} 

che è [edit: po] elegante in un K & R tipo di strada. Il punto importante qui (che è sempre più oscurato da ottenere il codice giusto (evidentemente avrei dovuto lasciare abbastanza bene da solo)) è il modo in cui l'istruzione return:

return (*q1 - *q2); 

che dà i risultati del confronto, naturalmente, in termini di i valori del personaggio.

+0

Non sarebbe quella "implementazione comune" uscire dal buffer (dopo la terminazione nulla?) Non vedo come sarebbe mai tornato 0 ... –

+0

Penso che dovrò terminare il ciclo se vieni a \ 0 :) devi anche controllare i flussi in entrata in * s1 - * s2 quindi s1 = -127, s2 = 2 => oops :) –

+0

@Daniel: Uh. Sì. Momento mentre aggiusto questo ... – dmckee

5

È comune alle funzioni restituire zero per il comune o per il caso unico e non zero per i casi speciali. Prendi la funzione principale, che per convenzione restituisce zero in caso di successo e qualche valore diverso da zero per errore. Il preciso valore diverso da zero indica cosa è andato storto. Ad esempio: memoria esaurita, nessun diritto di accesso o qualcos'altro.

Nel tuo caso, se la stringa è uguale, allora non c'è alcun motivo perché è diverso da quello che le stringhe contengono gli stessi caratteri. Ma se non sono uguali, allora il primo può essere più piccolo o il secondo può essere più piccolo. Avendolo restituire 1 per uguale, 0 per minori e 2 per maggiori sarebbe in qualche modo strano penso.

È possibile anche pensate in termini di sottrazione:

return = s1 - s2 

Se s1 è "in ordine alfabetico" di meno, allora sarà dare è un valore negativo.

+0

Sono abbastanza sicuro che è necessario dereferenziare il tuo ... – dmckee

+0

Intendevo che fosse simbolico uno pseudo codice. –

+0

Ah. Ritiro il suggerimento – dmckee

0

immagino è semplicemente per simmetria: -1 se meno, 0 se uguale, 1 se più.

10

La cosa bella di un'implementazione come questo è che si può dire

if(strcmp(<stringA>, <stringB>) > 0) // Implies stringA > stringB 
if(strcmp(<stringA>, <stringB>) == 0) // Implies stringA == stringB 
if(strcmp(<stringA>, <stringB>) < 0) // Implies stringA < stringB 
if(strcmp(<stringA>, <stringB>) >= 0) // Implies stringA >= stringB 
if(strcmp(<stringA>, <stringB>) <= 0) // Implies stringA <= stringB 
if(strcmp(<stringA>, <stringB>) != 0) // Implies stringA != stringB 

Si noti come il confronto con 0 corrisponde esattamente al confronto nella implicazione.

+1

C'è una meravigliosa/orribile macro dalle FAQ di comp.lang.c che implementa quasi esattamente questo comportamento di stringa. '#define StrTest (str1, op, str2) (strcmp (str1, str2) op 0)' Con esso dovresti scrivere 'if (StrTest (stringA, ==, stringB))' e gli amici. Sono in bilico sul fatto che sia un'idea orribile o un'idea meravigliosa. –

2

Ci sono tre risultati possibili: stringa 1 viene prima corda 2, corda 1 viene dopo corda 2, corda 1 è la stessa stringa di 2. E 'importante mantenere queste tre risultati separata; un uso di strcmp() è per ordinare le stringhe. La domanda è come si desidera assegnare valori a questi tre risultati e come mantenere le cose più o meno coerenti. Si potrebbero anche osservare i parametri per qsort() e bsearch(), che richiedono funzioni di confronto molto simili a strcmp().

Se si voleva una funzione di uguaglianza di stringa, sarebbe ritorno diverso da zero per archi uguali e pari a zero per i non-uguali corde, di andare avanti con le regole di C sul vero e il falso. Ciò significa che non ci sarebbe modo di distinguere se la stringa 1 è venuta prima o dopo la stringa 2. Esistono più valori veri per un int o qualsiasi altro tipo di dati C che si desidera assegnare, ma solo uno falso.

Pertanto, avendo uno strcmp utile() che ha restituito vero per l'uguaglianza di stringa richiederebbe un sacco di modifiche al resto della lingua, che semplicemente non stanno per accadere.

4

Un altro motivo strcmp() restituisce i codici lo fa è in modo che possa essere utilizzato direttamente nella funzione di libreria standard qsort(), che consente di ordinare un array di stringhe:

#include <string.h> // for strcmp() 
#include <stdlib.h> // for qsort() 
#include <stdio.h> 

int sort_func(const void *a, const void *b) 
{ 
    const char **s1 = (const char **)a; 
    const char **s2 = (const char **)b; 
    return strcmp(*s1, *s2); 
} 

int main(int argc, char **argv) 
{ 
    int i; 
    printf("Pre-sort:\n"); 
    for(i = 1; i < argc; i++) 
     printf("Argument %i is %s\n", i, argv[i]); 
    qsort((void *)(argv + 1), argc - 1, sizeof(char *), sort_func); 
    printf("Post-sort:\n"); 
    for(i = 1; i < argc; i++) 
     printf("Argument %i is %s\n", i, argv[i]); 
    return 0; 
} 

Questo piccolo programma di esempio ordina i suoi argomenti ASCIIbeticamente (ciò che alcuni chiamerebbero lessicalmente). Lookie:

$ gcc -o sort sort.c 
$ ./sort hi there little fella 
Pre-sort: 
Argument 1 is hi 
Argument 2 is there 
Argument 3 is little 
Argument 4 is fella 
Post-sort: 
Argument 1 is fella 
Argument 2 is hi 
Argument 3 is little 
Argument 4 is there 

Se strcmp() restituito 1 (true) per archi uguali e 0 (false) per quelli inequal, sarebbe impossibile da utilizzare per ottenere il grado o direzione di disuguaglianza (cioè quanto diverso, e quale è più grande) tra le due stringhe, rendendo quindi impossibile utilizzarlo come funzione di ordinamento.

Non so quanto tu sia familiare con C. Il codice precedente utilizza alcuni dei concetti più confusionari di C: aritmetica del puntatore, rifusione puntatore e puntatori di funzione, quindi se non capisci un po 'di quel codice, non Non ti preoccupare, ci arriverai in tempo. Fino ad allora, avrai molte domande divertenti da porre su StackOverflow. ;)

Problemi correlati