Perché strcmp () restituisce 0 quando i suoi input sono uguali?

Quando faccio una chiamata alla funzione di confronto stringa C in questo modo:

strcmp("time","time")

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.

strcmp restituisce una differenza lessicale (o dovrei chiamarla “comparatore di byte seriale di cortocircuito”? :-)) delle due stringhe che hai fornito 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 tuo valore diverso da zero quando confronti “tempo” e “denaro” che sono ovviamente diversi, anche se si potrebbe dire che il tempo è denaro! 🙂

La cosa bella di un’implementazione come questa è che puoi dire

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

Nota come il confronto con 0 corrisponde esattamente al confronto nell’implicazione.

È comune alle funzioni restituire zero per il comune o per il caso singolo 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, non vi è alcuna ragione per cui è uguale all’infuori delle stringhe che 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.

Puoi anche pensarci in termini di sottrazione:

 return = s1 - s2 

Se s1 è “lessicograficamente” meno, allora darà un valore negativo.

Un’altra ragione per cui strcmp() restituisce i codici che fa è tale da poter essere utilizzata direttamente nella funzione di libreria standard qsort() , che consente di ordinare una matrice di stringhe:

 #include  // for strcmp() #include  // for qsort() #include  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 in modo ASCII (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() restituisce 1 (vero) per stringhe uguali e 0 (falso) per quelle non uguali, sarebbe imansible utilizzarlo per ottenere il grado o la direzione della disuguaglianza (cioè quanto è diverso e quale è più grande) tra i due stringhe, rendendo così imansible utilizzarlo come funzione di ordinamento.

Non so quanto tu sia familiare con C. Il codice sopra riportato usa 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 preoccuparti, ci arriverai in tempo. Fino ad allora, avrai molte domande divertenti da porre su StackOverflow. 😉

Sembra che tu voglia che strcmp funzioni come un (ipotetico)

 int isEqual(const char *, const char *) 

Per essere sicuri che sarebbe vero per l’interpretazione “zero is false” dei risultati interi, ma complicherebbe la logica dell’ordinamento perché, avendo stabilito che le due stringhe non erano le stesse, avresti ancora bisogno di imparare quale è venuto “prima “.

Inoltre, sospetto che assomigli a un’implementazione comune

 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: kinda] elegante in un modo K & R. Il punto importante qui (che è sempre più oscurato ottenendo il codice giusto (evidentemente avrei dovuto lasciarlo abbastanza bene da solo)) è il modo in cui la dichiarazione di ritorno:

  return (*q1 - *q2); 

che fornisce i risultati del confronto naturalmente in termini di valori dei caratteri.

Ci sono tre possibili risultati: la stringa 1 arriva prima della stringa 2, la stringa 1 arriva dopo la stringa 2, la stringa 1 è la stessa della stringa 2. È importante mantenere separati questi tre risultati; 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 desidera una funzione di uguaglianza delle stringhe, restituisce un valore diverso da zero per stringhe uguali e zero per stringhe non uguali, per accompagnare le regole di C su true e false. 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, avere uno strcmp () utile che restituisce true per l’uguaglianza delle stringhe richiederebbe molte modifiche al resto del linguaggio, che semplicemente non si verificheranno.

Suppongo che sia semplicemente per simmetria: -1 se inferiore, 0 se uguale, 1 se di più.