Comment comparer correctement les chaînes?


183

J'essaie d'obtenir un programme pour permettre à un utilisateur d'entrer un mot ou un caractère, de le stocker, puis de l'imprimer jusqu'à ce que l'utilisateur le saisisse à nouveau, quittant le programme. Mon code ressemble à ceci:

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

Le problème est que je continue à obtenir l'impression de la chaîne d'entrée, même lorsque l'entrée de l'utilisateur (chèque) correspond à l'original (entrée). Est-ce que je compare les deux de manière incorrecte?


13
gets( )a été retiré de la norme. Utilisez fgets( )plutôt.
Edward Karak

1
Notez que cette réponse à Pourquoi strcmp()renvoie zéro lorsque ses entrées sont égales explique comment comparer des chaînes pour l'égalité, l'inégalité, inférieure à, supérieure à, inférieure ou égale et supérieure ou égale. Toutes les comparaisons de chaînes ne sont pas pour l'égalité. Les comparaisons sensibles à la casse sont à nouveau différentes; d'autres comparaisons spéciales (ordre du dictionnaire, par exemple) nécessitent des comparateurs plus spécialisés, et il existe des expressions régulières pour des comparaisons encore plus complexes.
Jonathan Leffler

Notez également qu'il existe une question essentiellement en double. Comment vérifier si une valeur correspond à une chaîne qui a été posée des années auparavant.
Jonathan Leffler

Est-ce que cela répond à votre question? Comment vérifier si une valeur correspond à une chaîne
Andreas

Cette question est bonne, mais l'utilisation de gets()est interdite. Elle a également été supprimée de la norme depuis C11 -> Veuillez lire Pourquoi la fonction gets est-elle si dangereuse qu'elle ne devrait pas être utilisée?
RobertS soutient Monica Cellio

Réponses:


276

Vous ne pouvez pas (utilement) comparer des chaînes en utilisant !=ou ==, vous devez utiliser strcmp:

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

La raison en est que !=et ==ne comparera que les adresses de base de ces chaînes. Pas le contenu des chaînes elles-mêmes.


10
la même chose en java, qui peut simplement se comparer à l'adresse.
Telerik le

29
L'écriture while (strcmp(check, input))est suffisante et est considérée comme une bonne pratique.
Shiva

en savoir plus ... codificare.in/codes/c
chanu panwar

7
Il est plus sûr d'utiliser strncmp! Je ne veux pas de débordement de tampon!
Floam

@Floam Si vous n'avez pas réellement de chaînes, mais des séquences remplies de zéro de caractères différents de zéro de longueur connue, bien sûr, ce serait la bonne incantation. Mais c'est quelque chose de complètement différent!
Deduplicator

33

Ok, quelques trucs: getsest dangereux et doit être remplacé par fgets(input, sizeof(input), stdin)pour ne pas avoir de débordement de tampon.

Ensuite, pour comparer des chaînes, vous devez utiliser strcmp, où une valeur de retour de 0 indique que les deux chaînes correspondent. L'utilisation des opérateurs d'égalité (ie. !=) Compare l'adresse des deux chaînes, par opposition à l'individu chars à l'intérieur.

Et notez également que, bien que dans cet exemple cela ne pose pas de problème, fgetsstocke le caractère de nouvelle ligne, '\n'dans les tampons également; gets()ne fait pas. Si vous comparez l'entrée utilisateur de fgets()à une chaîne littérale telle "abc"qu'elle ne correspondrait jamais (à moins que le tampon ne soit trop petit pour que le '\n'ne tienne pas dedans).


Pouvez-vous clarifier la relation / le problème de "\ n" et de la chaîne littérale? J'obtiens un résultat différent en comparant des chaînes (ligne) d'un fichier avec un autre fichier entier.
incompétent le

@incompetent - si vous lisez une ligne à partir d'un fichier avec fgets(), la chaîne peut être "abc\n"car fgets()conserve la nouvelle ligne. Si vous comparez cela avec "abc", vous obtiendrez «pas égal» en raison de la différence entre un octet nul se terminant "abc"et la nouvelle ligne dans les données lues. Donc, vous devez zapper la nouvelle ligne. La manière fiable de le faire sur une seule ligne est celle buffer[strcspn(buffer, "\n")] = '\0';qui a le mérite de fonctionner correctement, qu'il y ait ou non des données dans la mémoire tampon, ou que ces données se terminent par une nouvelle ligne ou non. D'autres façons de zapper la nouvelle ligne se bloquent facilement.
Jonathan Leffler le

Cette réponse traite les problèmes du code avec précision, tandis que la réponse la plus votée et la plus acceptée ne couvre que le titre de la question. Surtout de mentionner que le dernier paragraphe est super. +1
RobertS soutient Monica Cellio

11

Utilisez strcmp.

Ceci est dans la string.hbibliothèque et est très populaire. strcmprenvoie 0 si les chaînes sont égales. Voir ceci pour une meilleure explication de ce qui strcmprevient.

En gros, vous devez faire:

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

ou

while (!strcmp(check,input))

ou

while (strcmp(check,input))

Vous pouvez vérifier ceci , un tutoriel sur strcmp.


7

Vous ne pouvez pas comparer directement des tableaux comme celui-ci

array1==array2

Vous devriez les comparer caractère par caractère; pour cela, vous pouvez utiliser une fonction et renvoyer une valeur booléenne (True: 1, False: 0). Ensuite, vous pouvez l'utiliser dans la condition de test de la boucle while.

Essaye ça:

#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
Pourriez-vous s'il vous plaît ajouter plus de détails sur votre solution?
abarisone

oui c'est le remplacement de la fonction strcmp et de la solition sans utiliser l'en-tête string.h @Jongware
mugetsu

2
Cela ne fonctionne pas. Lorsqu'il est checkertrouvé '\0'dans l'une des chaînes, il ne recherche pas l'autre chaîne '\0'. La fonction renvoie 1("égal") même si une chaîne n'est que le préfixe de l'autre (par exemple, "foo"et "foobar").
lukasrozs

1
J'utiliserais à la ||place de &&.
lukasrozs

3

Bienvenue dans le concept du pointeur. Des générations de programmeurs débutants ont trouvé le concept insaisissable, mais si vous souhaitez devenir un programmeur compétent, vous devez finalement maîtriser ce concept - et de plus, vous vous posez déjà la bonne question. C'est bon.

Est-ce que c'est clair pour vous ce qu'est une adresse? Voir ce diagramme:

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

Dans le diagramme, l'entier 1 est stocké en mémoire à l' adresse 0x4000. Pourquoi à une adresse? Parce que la mémoire est grande et peut stocker de nombreux nombres entiers, tout comme une ville est grande et peut héberger de nombreuses familles. Chaque entier est stocké dans un emplacement mémoire, car chaque famille réside dans une maison. Chaque emplacement mémoire est identifié par une adresse , chaque maison étant identifiée par une adresse.

Les deux cases du diagramme représentent deux emplacements de mémoire distincts. Vous pouvez les considérer comme des maisons. L'entier 1 réside dans l'emplacement de mémoire à l'adresse 0x4000 (pensez, "4000 Elm St."). L'entier 7 réside dans l'emplacement de mémoire à l'adresse 0x4004 (pensez, "4004 Elm St.").

Vous pensiez que votre programme comparait le 1 au 7, mais ce n'était pas le cas. Il comparait le 0x4000 au 0x4004. Alors, que se passe-t-il lorsque vous avez cette situation?

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

Les deux entiers sont les mêmes mais les adresses diffèrent. Votre programme compare les adresses.


2

Chaque fois que vous essayez de comparer les chaînes, comparez-les par rapport à chaque caractère. Pour cela, vous pouvez utiliser la fonction de chaîne intégrée appelée strcmp (input1, input2); et vous devez utiliser le fichier d'en-tête appelé#include<string.h>

Essayez ce 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");  
} 

0

Comment comparer correctement les chaînes?

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

Creusons plus profondément pour voir pourquoi ce check != inputn'est pas suffisant .

En C, string est une spécification de bibliothèque standard.

Une chaîne est une séquence contiguë de caractères terminée par et incluant le premier caractère nul.
C11 §7.1.1 1

inputci-dessus n'est pas une chaîne . inputest le tableau 40 de char .

Le contenu de inputpeut devenir une chaîne .

Dans la plupart des cas, lorsqu'un tableau est utilisé dans une expression, il est converti en l'adresse de son 1er élément.

Le ci-dessous convertit checket inputà leurs adresses respectives du premier élément, puis ces adresses sont comparées.

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

Pour comparer des chaînes , nous devons utiliser ces adresses, puis examiner les données vers lesquelles elles pointent.
strcmp()fait le travail . §7.23.4.2

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

La strcmpfonction compare la chaîne pointée par s1à la chaîne pointée par s2.

La strcmpfonction renvoie un entier supérieur, égal ou inférieur à zéro, car la chaîne pointée par s1est supérieure, égale ou inférieure à la chaîne pointée par s2.

Non seulement le code peut trouver si les chaînes sont des mêmes données, mais laquelle est supérieure / inférieure lorsqu'elles diffèrent.

Ce qui suit est vrai lorsque la chaîne diffère.

strcmp(check, input) != 0

Pour plus d'informations, voir Créer ma propre strcmp()fonction


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

C'est une solution très simple dans laquelle vous obtiendrez votre sortie comme vous le souhaitez.


2
gets();ne fait pas partie de la norme C depuis C11.
chux

2
strcmp(s1,s2)est UB car le s2contenu n'est pas spécifié au début.
chux

Ce serait formidable si vous pouviez également fournir la sortie de cet extrait de code, sous une forme ou une autre.
not2qubit
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.