Problème de comparaison de chaine de caractères [Fermé]

Signaler
Messages postés
856
Date d'inscription
dimanche 1 novembre 2015
Statut
Membre
Dernière intervention
22 juin 2020
-
Messages postés
5387
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
15 juillet 2020
-
Bonjour,

Voici mon tout petit code :
#include <stdio.h>
void main()
{
char mot[3]="non";
if (mot=="non")
printf("Bonjour");
}


J'ai lu quelques topics et j'ai cru comprendre qu'il faudrait mettre plutôt
mot[4]="non\0"
pour montrer la fin de la suite de caractères.
Mais même voir ce changement le Bonjour ne s'affiche pas.
Que faire s'il vous plaît?

Merci :)

2 réponses

Messages postés
542
Date d'inscription
mercredi 9 mars 2016
Statut
Membre
Dernière intervention
8 mars 2018
84
google, "c comparaison chaine", premier lien :

https://fr.wikibooks.org/wiki/Programmation_C/Cha%C3%AEnes_de_caract%C3%A8res

int strcmp(const char * chaine1, const char * chaine2);


Compare les chaînes chaine1 et chaine2 et renvoie un entier :

négatif, si chaine1 est inférieure à chaine2 (avant dans l'ordre alphabétique) ;
nul, si chaine1 est égale à chaine2 (.i.e. chaine1 et chaine2 sont identiques) ;
positif, si chaine1 est supérieur à chaine2 (après dans l'ordre alphabétique) .
Messages postés
856
Date d'inscription
dimanche 1 novembre 2015
Statut
Membre
Dernière intervention
22 juin 2020
85
Mais ici je ne peux pas utiliser cette fonction puisque "non" écrit à la main ne peux être pointé à l'aide d'une pointeur.
Je ne suis pas en train de comparer deux chaines de caractères déclarées, seulement la première l'est.
Messages postés
5387
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
15 juillet 2020
885
En C le "non" est considéré par le compilateur comme une chaîne littérale, le compilateur allouant un espace mémoire pour cette chaîne, qui est donc désigné par un pointeur.

Par conséquent, cela ne pose strictement aucun problème d'écrire, en C :

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

int main(void) {
    char mot[] = "non";

    if (strcmp(mot, "non") == 0) {
        printf("c'est non\n");
    }
                                                                                
    return 0;
}

note la déclaration de mot, qui ne nécessite pas que tu mentionnes la taille, le compilateur calculant cela tout seul (de plus, ton
char mot[3]="non";
était erroné, car il manquait un byte. Pour une chaîne de 3 lettres on a besoin d'au moins 4 char, le 4ème étant pour le '\0' terminant la chaîne.

https://www.commentcamarche.net/contents/118-langage-c-les-chaines-de-caracteres
Messages postés
856
Date d'inscription
dimanche 1 novembre 2015
Statut
Membre
Dernière intervention
22 juin 2020
85 >
Messages postés
5387
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
15 juillet 2020

Merci pour cette réponse complète et claire !
C'est rigolo de voir que le compilateur alloue de la mémoire pour le "non" alors qu'on en l'a pas déclaré avec le char.
Oui j'ai conscience du fait que l'on peut ne pas spécifier la taille de la chaîne sauf que si on veut demander la taille de la chaîne à l'utilisateur je vais donc le programmer avec char mot[n+1]="..." où n sera demandé grâce à un scanf.
Je pense que ce n'est pas du tout utilisé par les programmeurs mais je suis débutant O:)
Messages postés
5387
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
15 juillet 2020
885
Effectivement, il est rare que l'on demande à l'utilisateur d'indiquer quelle est la taille de la chaîne (qu'on va lui demander de saisir) : en général, le programme fixe cette limite, et devrait en informer l'utilisateur d'une façon ou d'une autre (sur l'interface utilisateur, dans la documentation, etc.)... cela dit, pourquoi pas :-)

Par contre, le programme ne devrait pas faire confiance à l'utilisateur et vérifier, en tout état de cause (que la limite soit fixée d'avance ou non), que la chaîne saisie grâce à un scanf ou un fgets, ne dépasse pas l'espace mémoire alloué.

Pour allouer l'espace, tu devrais utiliser un
malloc()
(et un
free()
quand tu n'en as plus besoin), plutôt qu'un
char mot[n+1];
, si tu veux que ton code reste compatible avec le C89.

quant à
char mot[n+1]="..."
, je ne sais pas trop ce que tu voudrais faire. Ce n'est pas très cohérent de mettre un littéral à droite (qui a donc une taille fixe), alors qu'à gauche tu aurais une déclaration avec un espace mémoire dépendant de "n", qui, si j'ai bien compris serait déterminé par l'utilisateur... il y a un petit problème là. Je ne crois pas que cela donne rien de bon en C.


Dal
Messages postés
856
Date d'inscription
dimanche 1 novembre 2015
Statut
Membre
Dernière intervention
22 juin 2020
85 >
Messages postés
5387
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
15 juillet 2020

Oui je sais très bien que ce code et TRES limité car cela oblige par exemple l'utilisateur à compter le nombre de caractères dans son pseudo (peu pertinent). Je n'ai pas pensé à rajouter une limite car j'avais pensé à l'optimisation de la mémoire vive ^^ Imaginons que l'on mette 20 caractères au plus alors que l'utilisateur en rentre que 2 ^^
Mais bon à mon niveau je ne devrait pas encore parler d'optimisation, j'en suis assez loin ^^
Vous parlez de norme 89 mais avez vous une page décrivant chaque norme s'il vous plait? Pour une petite comparaison O:)
Messages postés
3644
Date d'inscription
dimanche 18 mars 2001
Statut
Modérateur
Dernière intervention
15 janvier 2017
884
Utilise fgets et strncmp
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
const int SIZE = 10;
int main(void) {
    char mot[] = "non";
    char buffer[SIZE];

    printf("%s", "buffer ? ");
    fgets(buffer, SIZE, stdin);
    puts(buffer);
    
    if (strncmp(mot, buffer, strlen(mot)) == 0) {
        printf("c'est non\n");
    }
                                                                                
    return 0;
}


Compilation et exécution:
johand@bata:~/src/CCM/C$ gcc -o test_strcmp test_strcmp.c
johand@bata:~/src/CCM/C$ ./test_strcmp
buffer ? 0123456789012345
012345678
johand@bata:~/src/CCM/C$ ./test_strcmp
buffer ? non
non

c'est non

https://linux.die.net/man/3/strcmp
https://linux.die.net/man/3/fgets
Messages postés
856
Date d'inscription
dimanche 1 novembre 2015
Statut
Membre
Dernière intervention
22 juin 2020
85
Merci je vais étudier ce code, en particulier les nouvelles commandes ^^
Messages postés
5387
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
15 juillet 2020
885
je ne suis pas sûr que cela soit ce que tu veuilles faire

en utilisant
strncmp()
, jisisv limite la comparaison à 3 caractères saisis, alors qu'il en stocke jusqu'à 9 en raison de la taille du buffer.

ainsi, si tu saisis "nonne", le test passera quand même (essaye)

il faudrait utiliser
strcmp()
, pour vraiment tester ce qui a été saisi. Mais comme fgets inclue le '
\n'
tapé (le retour à la ligne est inclus avant le
'\0'
à moins que tu aies tapé exactement le nombre de caractères tenant dans le buffer), tu verras que pour que la comparaison fonctionne, il faut que tu le supprimes.

pour t'en convaincre, change la ligne 11 avec le puts et au lieu de cela mets
printf("vous avez tapé : >%s<\n", buffer);
et répond "non" à la question, tu verras que ce qui a été stocké dans buffer contient le retour à la ligne, cela affiche :

$ ./a.out 
buffer ? non
vous avez tapé : >non
<

et la comparaison échoue aussi.

donc, pour n'avoir que ce que l'on veut, avec fgets, il faut supprimer le retour à la ligne s'il existe, et cela se fait comme cela :

    char * p;
    if ((p = strchr(buffer, '\n')) != NULL)
        *p = '\0';

insére cela avant le printf, et désormais, tu auras :
$ ./a.out 
buffer ? non
vous avez tapé : >non<
c'est non

au final, cela donne :

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

int main(void) {
    const int SIZE = 10;
    char mot[] = "non";
    char buffer[SIZE];

    printf("%s", "buffer ? ");
    fgets(buffer, SIZE, stdin);
    char * p;
    if ((p = strchr(buffer, '\n')) != NULL)
        *p = '\0';
    printf("vous avez tapé : >%s<\n", buffer);

    if (strcmp(mot, buffer) == 0) {
        printf("c'est non\n");
    }

    return 0;
}

avec scanf on a d'autres types de problèmes :-) mais, cela suffit pour ce soir.


Dal
Messages postés
856
Date d'inscription
dimanche 1 novembre 2015
Statut
Membre
Dernière intervention
22 juin 2020
85 >
Messages postés
5387
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
15 juillet 2020

J'ai toujours droit à des explications bien détaillés, sympa ;)
Mais je vais rester sur la première proposition , elle semble plus légère ^^
Messages postés
5387
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
15 juillet 2020
885
quelle première explication ?