Wie vergleiche ich Strings richtig?

182

Ich versuche, ein Programm dazu zu bringen, dass ein Benutzer ein Wort oder Zeichen eingibt, es speichert und dann druckt, bis der Benutzer es erneut eingibt und das Programm beendet. Mein Code sieht folgendermaßen aus:

#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;
}

Das Problem ist, dass ich immer wieder den Druck der Eingabezeichenfolge erhalte, auch wenn die Eingabe des Benutzers (Prüfung) mit dem Original (Eingabe) übereinstimmt. Vergleiche ich die beiden falsch?

nmagerko
quelle
13
gets( )wurde aus dem Standard entfernt. Verwenden Sie fgets( )stattdessen.
Edward Karak
1
Beachten Sie, dass diese Antwort auf Warum gibt strcmp()Null zurück, wenn seine Eingaben gleich sind, erklärt, wie Zeichenfolgen auf Gleichheit, Ungleichheit, kleiner als, größer als, kleiner als oder gleich und größer als oder gleich verglichen werden. Nicht alle Zeichenfolgenvergleiche dienen der Gleichheit. Vergleiche zwischen Groß- und Kleinschreibung unterscheiden sich wieder. Andere spezielle Vergleiche (z. B. Wörterbuchreihenfolge) erfordern spezialisiertere Komparatoren, und es gibt reguläre Ausdrücke für noch komplexere Vergleiche.
Jonathan Leffler
Beachten Sie auch, dass es eine im Wesentlichen doppelte Frage gibt. Wie überprüfe ich, ob ein Wert mit einer Zeichenfolge übereinstimmt , die Jahre zuvor gestellt wurde?
Jonathan Leffler
Diese Frage ist gut, aber die Verwendung von gets()ist ein No-Go. Es wurde auch seit C11 aus dem Standard entfernt -> Bitte lesen Sie Warum ist die Funktion gets so gefährlich, dass sie nicht verwendet werden sollte?
RobertS unterstützt Monica Cellio

Antworten:

274

Sie können Zeichenfolgen nicht (sinnvoll) mit !=oder vergleichen ==. Sie müssen Folgendes verwenden strcmp:

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

Der Grund dafür ist , weil !=und ==nur die Basisadressen dieser Strings vergleichen. Nicht der Inhalt der Zeichenfolgen selbst.

Mystisch
quelle
10
das gleiche in Java, das nur mit der Adresse vergleichen kann.
Telerik
29
Schreiben while (strcmp(check, input))ist ausreichend und gilt als gute Praxis.
Shiva
wissen Sie mehr ... codificare.in/codes/c/…
Chanu Panwar
7
Es ist sicherer, strncmp zu verwenden! Ich möchte keinen Pufferüberlauf!
Floam
@Floam Wenn Sie eigentlich keine Zeichenfolgen haben, aber mit Nullen aufgefüllte Sequenzen von Nicht-Null-Zeichen bekannter Länge, dann wäre das sicher die richtige Beschwörung. Aber das ist etwas ganz anderes!
Deduplikator
33

Ok ein paar Dinge: getsist unsicher und sollte durch ersetzt werden, fgets(input, sizeof(input), stdin)damit Sie keinen Pufferüberlauf bekommen.

Als nächstes müssen Sie zum Vergleichen von Zeichenfolgen Folgendes verwenden strcmp, wobei ein Rückgabewert von 0 angibt, dass die beiden Zeichenfolgen übereinstimmen. Die Verwendung der Gleichheitsoperatoren (dh !=) vergleicht die Adresse der beiden Zeichenfolgen im Gegensatz zu den darin enthaltenen Personen char.

Beachten Sie auch, dass in diesem Beispiel zwar kein Problem verursacht wird, fgetsdas Zeilenumbruchzeichen jedoch auch '\n'in den Puffern gespeichert wird . gets()nicht. Wenn Sie die Benutzereingabe von fgets()mit einem Zeichenfolgenliteral vergleichen "abc", würde es niemals übereinstimmen (es sei denn, der Puffer war zu klein, '\n'damit er nicht hineinpasst).

AusCBloke
quelle
Können Sie bitte die Beziehung / das Problem von "\ n" und String-Literal klären? Ich erhalte ein nicht gleiches Ergebnis beim Vergleich von Zeichenfolgen (Zeilen) einer Datei mit anderen ganzen Dateien.
Inkompetent
@incompetent - Wenn Sie eine Zeile aus einer Datei mit lesen fgets(), liegt die Zeichenfolge möglicherweise daran, "abc\n"dass fgets()die neue Zeile beibehalten wird. Wenn Sie dies mit vergleichen "abc", erhalten Sie aufgrund des Unterschieds zwischen einem Null-Byte-Abschluss "abc"und dem Zeilenumbruch in den gelesenen Daten "ungleich" . Sie müssen also die Newline zappen. Der zuverlässige einzeilige Weg, dies zu tun, buffer[strcspn(buffer, "\n")] = '\0';hat den Vorteil, dass er korrekt funktioniert, unabhängig davon, ob sich Daten im Puffer befinden oder ob diese Daten mit einem Zeilenumbruch enden oder nicht. Andere Möglichkeiten zum Zappen der Newline stürzen leicht ab.
Jonathan Leffler
Diese Antwort behandelt die Probleme des Codes genau, während die am besten bewertete und akzeptierte Antwort nur den Titel der Frage beantwortet. Besonders den letzten Absatz zu erwähnen ist super. +1
RobertS unterstützt Monica Cellio
11

Verwenden Sie strcmp.

Dies ist in der string.hBibliothek und ist sehr beliebt. strcmpGeben Sie 0 zurück, wenn die Zeichenfolgen gleich sind. Sehen Sie dies für eine bessere Erklärung dessen, was strcmpzurückkehrt.

Grundsätzlich müssen Sie Folgendes tun:

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

oder

while (!strcmp(check,input))

oder

while (strcmp(check,input))

Sie können überprüfen , dies , ein Tutorial auf strcmp.

Ashish Ahuja
quelle
7

Sie können Arrays nicht direkt so vergleichen

array1==array2

Sie sollten sie char-by-char vergleichen. Dazu können Sie eine Funktion verwenden und einen booleschen Wert (True: 1, False: 0) zurückgeben. Dann können Sie es in der Testbedingung der while-Schleife verwenden.

Versuche dies:

#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;
}
mugetsu
quelle
1
Könnten Sie bitte weitere Details zu Ihrer Lösung hinzufügen?
Abarisone
Ja, dies ist ein Ersatz für die Strcmp-Funktion und die Lösung ohne Verwendung des String.h-Headers @Jongware
Mugetsu
2
Das funktioniert nicht. Wenn checkerFunde '\0'in einer der Saiten, ist es nicht die für eine andere Zeichenfolge zu überprüfen '\0'. Die Funktion gibt zurück 1("gleich"), auch wenn eine Zeichenfolge nur das Präfix der anderen ist (z. B. "foo"und "foobar").
lukasrozs
1
Ich würde ||anstelle von verwenden &&.
lukasrozs
3

Willkommen zum Konzept des Zeigers. Generationen von Programmieranfängern fanden das Konzept schwer fassbar, aber wenn Sie sich zu einem kompetenten Programmierer entwickeln möchten, müssen Sie dieses Konzept schließlich beherrschen - und darüber hinaus stellen Sie bereits die richtige Frage. Das ist gut.

Ist Ihnen klar, was eine Adresse ist? Siehe dieses Diagramm:

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

Im Diagramm wird die Ganzzahl 1 unter der Adresse 0x4000 gespeichert . Warum an einer Adresse? Weil der Speicher groß ist und viele ganze Zahlen speichern kann, so wie eine Stadt groß ist und viele Familien beherbergen kann. Jede Ganzzahl wird an einem Speicherort gespeichert, da jede Familie in einem Haus wohnt. Jeder Speicherort wird durch eine Adresse identifiziert , wie jedes Haus durch eine Adresse identifiziert wird.

Die beiden Felder im Diagramm repräsentieren zwei unterschiedliche Speicherplätze. Sie können sich sie vorstellen, als wären sie Häuser. Die Ganzzahl 1 befindet sich im Speicher unter der Adresse 0x4000 (denken Sie an "4000 Elm St."). Die Ganzzahl 7 befindet sich im Speicher unter der Adresse 0x4004 (denken Sie an "4004 Elm St.").

Sie dachten, dass Ihr Programm die 1 mit der 7 vergleicht, aber das war es nicht. Es wurde der 0x4000 mit dem 0x4004 verglichen. Was passiert also, wenn Sie diese Situation haben?

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

Die beiden Ganzzahlen sind gleich, aber die Adressen unterscheiden sich. Ihr Programm vergleicht die Adressen.

thb
quelle
2

Wenn Sie versuchen, die Zeichenfolgen zu vergleichen, vergleichen Sie sie in Bezug auf jedes Zeichen. Hierfür können Sie die integrierte String-Funktion strcmp (input1, input2) verwenden. und Sie sollten die aufgerufene Header-Datei verwenden#include<string.h>

Versuchen Sie diesen Code:

#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");  
} 
Vishwanath Tallalli
quelle
0

Wie vergleiche ich Strings richtig?

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))

Lassen Sie uns tiefer graben, um zu sehen, warum dies check != inputnicht ausreicht .

In C ist string eine Standardbibliotheksspezifikation.

Eine Zeichenfolge ist eine zusammenhängende Folge von Zeichen, die mit dem ersten Nullzeichen abgeschlossen sind und dieses enthalten.
C11 §7.1.1 1

inputoben ist keine Zeichenfolge . inputist Array 40 von char .

Der Inhalt von inputkann zu einer Zeichenfolge werden .

In den meisten Fällen wird ein Array, wenn es in einem Ausdruck verwendet wird, in die Adresse seines ersten Elements konvertiert.

Das Folgende konvertiert checkund inputzu ihren jeweiligen Adressen des ersten Elements, dann werden diese Adressen verglichen.

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

Um Zeichenfolgen zu vergleichen , müssen wir diese Adressen verwenden und dann die Daten betrachten, auf die sie verweisen.
strcmp()macht den Job . §7.23.4.2

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

Die strcmpFunktion vergleicht die Zeichenfolge, auf die von zeigt, s1mit der Zeichenfolge, auf die von gezeigt wird s2.

Die strcmpFunktion gibt eine Ganzzahl zurück, die größer, gleich oder kleiner als Null ist, da die Zeichenfolge, auf die von s1zeigt, größer, gleich oder kleiner als die Zeichenfolge ist, auf die gezeigt wird s2.

Code kann nicht nur feststellen, ob die Zeichenfolgen dieselben Daten enthalten, sondern auch, welche größer / kleiner ist, wenn sie sich unterscheiden.

Das Folgende gilt, wenn sich die Zeichenfolge unterscheidet.

strcmp(check, input) != 0

Weitere Informationen finden Sie unter Erstellen meiner eigenen strcmp()Funktion

chux - Monica wieder einsetzen
quelle
-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;
    }

Dies ist eine sehr einfache Lösung, bei der Sie Ihre Ausgabe nach Ihren Wünschen erhalten.

Rupani TD
quelle
2
gets();seit C11 nicht mehr Teil von Standard C.
chux
2
strcmp(s1,s2)ist UB, da der s2Inhalt zunächst nicht angegeben wird.
chux
Es wäre großartig, wenn Sie auch die Ausgabe dieses Snippets in irgendeiner Form bereitstellen könnten.
not2qubit