Come posso confrontare correttamente le stringhe?


183

Sto cercando di ottenere un programma per consentire a un utente di inserire una parola o un carattere, memorizzarlo e quindi stamparlo fino a quando l'utente non lo digita nuovamente, uscendo dal programma. Il mio codice è simile al seguente:

#include <stdio.h>

int main()
{
    char input[40];
    char check[40];
    int i=0;
    printf("Hello!\nPlease enter a word or character:\n");
    gets(input);
    printf("I will now repeat this until you type it back to me.\n");

    while (check != input)
    {
        printf("%s\n", input);
        gets(check); 
    }

    printf("Good bye!");


    return 0;
}

Il problema è che continuo a ottenere la stampa della stringa di input, anche quando l'input dell'utente (controllo) corrisponde all'originale (input). Sto confrontando i due in modo errato?


13
gets( )è stato rimosso dallo standard. Usa fgets( )invece.
Edward Karak,

1
Si noti che questo risposta a Why strcmp()restituisce zero quando i suoi input sono uguali spiega come confrontare stringhe per uguaglianza, disuguaglianza, minore di, maggiore di, minore di o uguale e maggiore di o uguale. Non tutti i confronti di stringhe sono per uguaglianza. I confronti tra maiuscole e minuscole sono di nuovo diversi; altri confronti speciali (ordine del dizionario, ad esempio) richiedono comparatori più specializzati e vi sono regex per confronti ancora più complessi.
Jonathan Leffler,

Si noti inoltre che esiste una domanda sostanzialmente duplicata. Come posso verificare se un valore corrisponde a una stringa che è stata posta anni prima.
Jonathan Leffler,


Questa domanda è buona, ma l'uso di gets()è un no-go. Inoltre è stato rimosso dallo standard dal C11 -> Leggere Perché la funzione gets è così pericolosa che non dovrebbe essere usata?
RobertS supporta Monica Cellio

Risposte:


276

Non puoi (utilmente) confrontare le stringhe usando !=o ==, devi usare strcmp:

while (strcmp(check,input) != 0)

La ragione di ciò è perché !=e ==confronterà solo gli indirizzi di base di quelle stringhe. Non il contenuto delle stringhe stesse.


10
lo stesso in Java, che può solo confrontare con l'indirizzo.
Telerik,

29
La scrittura while (strcmp(check, input))è sufficiente ed è considerata una buona pratica.
Shiva,

per saperne di più ... codificare.in/codes/c/…
chanu panwar,

7
È più sicuro usare strncmp! Non voglio un buffer overflow!
Floam,

@Floam Se in realtà non si dispone di stringhe, ma sequenze con spaziatura zero di caratteri diversi da zero di lunghezza nota, questo sarebbe sicuramente l'incantesimo giusto. Ma è qualcosa di completamente diverso!
Deduplicatore

33

Ok alcune cose: getsnon è sicuro e deve essere sostituito in fgets(input, sizeof(input), stdin)modo da non ottenere un overflow del buffer.

Successivamente, per confrontare le stringhe, è necessario utilizzare strcmp, dove un valore di ritorno pari a 0 indica che le due stringhe corrispondono. L'uso degli operatori di uguaglianza (es. !=) Confronta l'indirizzo delle due stringhe, al contrario delle singole persone charal loro interno.

E nota anche che, mentre in questo esempio non causerà problemi, fgetsmemorizza il carattere di nuova riga, anche '\n'nei buffer; gets()non. Se hai confrontato l'input dell'utente da fgets()una stringa letterale come "abc"questa non corrisponderebbe mai (a meno che il buffer non fosse troppo piccolo in modo che '\n'non si adattasse ad esso).


Potete per favore chiarire la relazione / problema di "\ n" e letterale stringa? Non sto ottenendo un risultato uguale nel confronto delle stringhe (linea) di un file con altri file interi.
incompetente il

@incompetente - se leggi una riga da un file con fgets(), la stringa potrebbe essere "abc\n"perché fgets()mantiene la nuova riga. Se lo confronti con "abc", otterrai "non uguale" a causa della differenza tra un byte null che termina "abc"e la nuova riga nei dati letti. Quindi, devi zapping la nuova riga. Il modo affidabile in una sola riga per farlo è quello buffer[strcspn(buffer, "\n")] = '\0';che ha il merito di funzionare correttamente indipendentemente dal fatto che ci siano dati nel buffer o che tali dati finiscano con una nuova riga o meno. Altri modi per zappare la newline si schiantano facilmente.
Jonathan Leffler il

Questa risposta affronta accuratamente i problemi del codice, mentre la risposta più votata e accettata copre solo la risposta al titolo della domanda. Soprattutto menzionare l'ultimo paragrafo è super. +1
RobertS supporta Monica Cellio

11

Uso strcmp .

Questo è in string.hbiblioteca ed è molto popolare. strcmprestituisce 0 se le stringhe sono uguali. Vedi questo per una migliore spiegazione di cosastrcmp ritorna.

Fondamentalmente, devi fare:

while (strcmp(check,input) != 0)

o

while (!strcmp(check,input))

o

while (strcmp(check,input))

Puoi controllare questo , un tutorial su strcmp.


7

Non è possibile confrontare le matrici direttamente in questo modo

array1==array2

Dovresti confrontarli char-by-char; per questo puoi usare una funzione e restituire un valore booleano (Vero: 1, Falso: 0). Quindi puoi usarlo nelle condizioni di test del ciclo while.

Prova questo:

#include <stdio.h>
int checker(char input[],char check[]);
int main()
{
    char input[40];
    char check[40];
    int i=0;
    printf("Hello!\nPlease enter a word or character:\n");
    scanf("%s",input);
    printf("I will now repeat this until you type it back to me.\n");
    scanf("%s",check);

    while (!checker(input,check))
    {
        printf("%s\n", input);
        scanf("%s",check);
    }

    printf("Good bye!");

    return 0;
}

int checker(char input[],char check[])
{
    int i,result=1;
    for(i=0; input[i]!='\0' || check[i]!='\0'; i++) {
        if(input[i] != check[i]) {
            result=0;
            break;
        }
    }
    return result;
}

1
Potresti aggiungere maggiori dettagli sulla tua soluzione?
Abarisone,

sì, questo è il sostituto della funzione strcmp e della solizione senza usare l'intestazione string.h @Jongware
mugetsu

2
Questo non funziona. Quando checkertrova '\0'in una delle stringhe, non controlla l'altra stringa per '\0'. La funzione restituisce 1("uguale") anche se una stringa è solo prefisso dell'altra (ad esempio, "foo"e "foobar").
Lukasrozs,

1
Vorrei usare ||invece di &&.
lukasrozs,

3

Benvenuti nel concetto del puntatore.Generazioni di programmatori principianti hanno trovato il concetto inafferrabile, ma se desideri diventare un programmatore competente, alla fine devi padroneggiare questo concetto e, inoltre, stai già ponendo la domanda giusta. Quello è buono.

Ti è chiaro quale sia un indirizzo? Vedi questo diagramma:

----------     ----------
| 0x4000 |     | 0x4004 |
|    1   |     |    7   |
----------     ----------

Nel diagramma, l'intero 1 è memorizzato nell'indirizzo 0x4000. Perché a un indirizzo? Perché la memoria è grande e può contenere molti numeri interi, proprio come una città è grande e può ospitare molte famiglie. Ogni numero intero viene archiviato in una posizione di memoria, poiché ogni famiglia risiede in una casa. Ogni posizione di memoria è identificata da un indirizzo , poiché ogni casa è identificata da un indirizzo.

Le due caselle nel diagramma rappresentano due posizioni di memoria distinte. Puoi pensarli come se fossero case. Il numero intero 1 risiede nella posizione di memoria all'indirizzo 0x4000 (si pensi a "4000 Elm St."). Il numero intero 7 risiede nella posizione di memoria all'indirizzo 0x4004 (si pensi a "4004 Elm St.").

Pensavi che il tuo programma stesse confrontando 1 con 7, ma non lo era. Stava confrontando lo 0x4000 con lo 0x4004. Quindi cosa succede quando hai questa situazione?

----------     ----------
| 0x4000 |     | 0x4004 |
|    1   |     |    1   |
----------     ----------

I due numeri interi sono uguali ma gli indirizzi differiscono. Il tuo programma confronta gli indirizzi.


2

Ogni volta che stai provando a confrontare le stringhe, confrontale rispetto a ciascun personaggio. Per questo puoi usare la funzione stringa incorporata chiamata strcmp (input1, input2); e dovresti usare il file header chiamato#include<string.h>

Prova questo codice:

#include<stdio.h> 
#include<stdlib.h> 
#include<string.h>  

int main() 
{ 
    char s[]="STACKOVERFLOW";
    char s1[200];
    printf("Enter the string to be checked\n");//enter the input string
    scanf("%s",s1);
    if(strcmp(s,s1)==0)//compare both the strings  
    {
        printf("Both the Strings match\n"); 
    } 
    else
    {
        printf("Entered String does not match\n");  
    } 
    system("pause");  
} 

0

Come posso confrontare correttamente le stringhe?

char input[40];
char check[40];
strcpy(input, "Hello"); // input assigned somehow
strcpy(check, "Hello"); // check assigned somehow

// insufficient
while (check != input)

// good
while (strcmp(check, input) != 0)
// or 
while (strcmp(check, input))

Scaviamo più a fondo per vedere perché check != inputnon è sufficiente .

In C, string è una specifica di libreria standard.

Una stringa è una sequenza contigua di caratteri terminata da e incluso il primo carattere null.
C11 §7.1.1 1

inputsopra non è una stringa . inputè l' array 40 di char .

Il contenuto di inputpuò diventare una stringa .

Nella maggior parte dei casi, quando una matrice viene utilizzata in un'espressione, viene convertita nell'indirizzo del suo primo elemento.

Il seguente converte checke inputai rispettivi indirizzi del primo elemento, quindi questi indirizzi vengono confrontati.

check != input   // Compare addresses, not the contents of what addresses reference

Per confrontare le stringhe , dobbiamo usare quegli indirizzi e quindi guardare i dati a cui puntano.
strcmp()fa il lavoro . §7.23.4.2

int strcmp(const char *s1, const char *s2);

La strcmpfunzione confronta la stringa puntata da s1con la stringa puntata da s2.

La strcmpfunzione restituisce un numero intero maggiore di, uguale o inferiore a zero, di conseguenza, poiché la stringa puntata da s1è maggiore di, uguale a o inferiore alla stringa puntata da s2.

Non solo il codice può trovare se le stringhe sono degli stessi dati, ma quale è maggiore / minore quando differiscono.

Quanto segue è vero quando la stringa differisce.

strcmp(check, input) != 0

Per informazioni dettagliate, vedere Creazione della mia strcmp()funzione


-2
    #include<stdio.h>
    #include<string.h>
    int main()
    {
        char s1[50],s2[50];
        printf("Enter the character of strings: ");
        gets(s1);
        printf("\nEnter different character of string to repeat: \n");
        while(strcmp(s1,s2))
        {
            printf("%s\n",s1);
            gets(s2);
        }
        return 0;
    }

Questa è una soluzione molto semplice in cui otterrai il risultato desiderato.


2
gets();non fa parte della norma C dal C11.
chux - Ripristina Monica

2
strcmp(s1,s2)è UB poiché i s2contenuti non sono specificati all'inizio.
chux - Ripristina Monica

Sarebbe bello se tu potessi anche fornire l'output di questo snippet, in un modo o nell'altro.
not2qubit
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.