Problème pangramme

Résolu/Fermé
Alexoxido Messages postés 5 Date d'inscription mardi 25 décembre 2012 Statut Membre Dernière intervention 6 février 2013 - 25 janv. 2013 à 15:23
mamiemando Messages postés 33161 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 28 juin 2024 - 27 janv. 2013 à 13:19
Bonjour,

Alors voila mon problème: je veux un programme qui fait entré une phrase a un utilisateur puis retournant 1 si cette chaîne est un pangramme et 0 sinon.

ps : un pangramme est une phrase contenant les 26 lettres de l'alphabet

Mais voila mon programme ne me retourne que "0"

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


int main()
{
    char tab[]="";char chaineComparateur[26]="abcdefghijklmpopqrstuvwxyz";
    int i;int longueurPhrase;int compteur;int compteur2=0;int compteur3=0;

    printf("Enter un phrase\n");
    gets(tab);
    printf("\n");
    longueurPhrase = strlen(tab);
    if (longueurPhrase < 26)
        printf("0");
    else
    {
    for(i=longueurPhrase;i >= 0;i--)
    {
        for(compteur2 = 0; compteur2 <= longueurPhrase; compteur2++)
        {
            compteur = strncmp(tab,chaineComparateur,compteur3);
            compteur3++;
        }
    }
    if (compteur == 26)
        printf("1\n");
    else
        printf("0\n");
    }

3 réponses

Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
25 janv. 2013 à 15:59
Salut.
C'est n'importe quoi ! Comment espérer que ça fonctionne ?
déjà, pour commencer, il faudrait faire de tab un tableau de taille correcte ! Tu risque l'erreur de segmentation.
à quoi sert cette double boucle sur i et compteur2 ? a quoi sert compteur3 ? ta boucle peut se résumer en gros à compteur=strncmp(tab,chaineComparateur,longueurPhrase*longueurPhrase);car entre les deux rien n'est modifié.
Tu peux faire beaucoup plus simple en vérifiant juste que pour chaque lettre de l'alphabet elle est bien présente dans ta phrase.
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 838
25 janv. 2013 à 16:47
Voici quelques erreurs à corriger :

char tab[]="";
Cela créé un tableau tab d'une seule case. Il faut que tu indiques la longueur maximale de la phrase. Par exemple : char tab[255];

char chaineComparateur[26]="abcdefghijklmpopqrstuvwxyz"
Je te conseille de laisser de la plage pour mettre un '\0' en fin de chaîne. Donc : char chaineComparateur[27]="a...z"; ou tout simplement : char chaineComparateur[]="a...z";

gets(tab);
A ne pas utiliser ! Utilise plutôt la version fgets()... Et attention, cette fonction stocke le '\n' s'il reste de la place.

compteur = strncmp(tab,chaineComparateur,compteur3);
A revoir.
Il faudrait plutôt mettre : if (strchr(tab,chaineComparateur[...]...)

Tu as oublié : return 0;

Et enfin, je te conseille de créer une fonction spécifique. Et de revoir l'algorithme. Tu peux faire beaucoup plus simple.
L'idée est que : dès lors que tu constates qu'une lettre manque (strchr() renvoie NULL), ta fonction retournera 0. Cela fait une seule boucle for.

Cdlt,
0
mamiemando Messages postés 33161 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 28 juin 2024 7 760
Modifié par mamiemando le 26/01/2013 à 11:35
Il y a d'autres choses qui ne vont pas, tu ne gères absolument pas les histoires de minuscules et de majuscules.

Je te conseille de faire une fonction qui convertit les caractères que tu lis en minuscules (quand c'est possible), par exemple avec la fonction tolower(). Tu peux vérifier que le caractère est une lettre avec la fonction isalpha(). Pour plus de détails sur ces fonctions, tape dans google ou dans un terminal linux :

man isalpha 
man tolower


Si la conversion n'est pas possible tu retournes un caractère particulier (par exemple '\0').

#include <ctype.h> 

char convertir_char(char c) {                              
    if (isalpha(c)) return tolower(c); 
    return '\0'; 
} 


Si le caractère a été converti avec succès tu le convertis en index car on va stocker dans un tableau qu'on a croisé cette lettre. Comme la plage des caractères de 'a' à 'z' correspond à une plage d'entiers consécutifs, on peut facilement convertir 'a' ... 'z' en (respectivement) 0 ... 26 comme ceci :

unsigned char_to_index(char c) { 
    return c - 'a'; 
}


Bon maintenant, réfléchissons à quoi ressemblerait notre fonction is_pangramme. On a besoin de retourner une valeur "vrai" ou "faux", mais le type "bool" n'existe qu'en C++, pas en C. On va donc le définir. Cette fonction prend en paramètre une phrase de longueur indéterminée. C'est donc un "char *". Cette phrase n'est pas altérée par la fonction is_pangramme, donc encore mieux, c'est un "const char *" (ce qui permet d'appeler la fonction is_pangramme aussi bien pour des "char *" que des "const char *").

#define true 1  
#define false 0  
typedef int bool; 

bool is_pangramme(const char *phrase) { 
  // ... 
}


Ok maintenant comme l'a dit char sniper, il suffit de regarder les caractères de la phrase un par un et maintenir un tableau de "booleens" qui mémorise quels caractères ont été croisés. On initialise les 26 cases de ce tableau à "faux".

Pour chaque caractère de la phrase :
- Si la conversion réussi, tu mémorises dans le tableau que tu as croisé cette minuscule (en basculant la case correspondante à "vrai").
- Sinon tu ignores le caractères (c'est par un exemple un espace ou une ponctuation).
Une fois la phrase parcourue, tu regardes si dans ce tableau

Enfin, tu regardes si toutes les cases sont à "vrai" ou non. Dès qu'on rencontre une case à "faux", on sait que ce n'est pas un pangramme.

Ce qui nous mène par exemple à ce code :

#include <ctype.h> 
#include <stdio.h> 

#define true 1  
#define false 0  
typedef int bool; 

char convertir_char(char c) { 
    if (isalpha(c)) return tolower(c); 
    return '\0'; 
} 

unsigned char_to_index(char c) { 
    return c - 'a'; 
} 

bool is_pangramme(const char *phrase) { 
    unsigned i; 
    bool caracteres_vus[26]; 
    char c; 
    const char *pc = phrase; 
    bool res = true; 

    for(i = 0; i < 26; ++i) { 
        caracteres_vus[i] = false; 
    } 

    for(; *pc; ++pc) { 
        c = convertir_char(*pc); 
        if (c) caracteres_vus[char_to_index(c)] = true; 
    } 

    for(i = 0; i < 26; ++i) { 
        if(caracteres_vus[i] == false) { 
            res = false; 
            break; 
        } 
    } 

    return res; 
} 

int main() { 
    const char *phrase = "J'aime les loutres"; 
    printf("is_pangramme(%s) = %d\n", phrase, is_pangramme(phrase)); 
    return 0; 
}


Bon maintenant ce n'est pas encore parfait. Dans le cas général, la phrase peut comporter des caractères accentués. Malheureusement, un char ne permet pas d'encoder un caractère accentué proprement. On peut donc s'en sortir avec des wchar_t. Concrètement un wchar_t (wide char) est un caractère encodé sur 4 octets au lieu de 1 (ce qui permet de régler le problème des caractères accentués).

Du coup il faut adapter un peu le code, en particulier la fonction de conversion. En voici le squelette que je te laisse le soin de compléter.

#include <wchar.h> 

char convertir_wchar(wchar_t c) { 
    if (isalpha(c)) return tolower(c); 
    switch(c) { 
        case L'é': 
        case L'É': 
        case L'ê': 
        case L'Ê': 
        case L'è': 
        case L'È': 
        case L'ë': 
        case L'Ë': 
            return 'e'; 
        //... idem avec a, u, i, o, y 
        default: 
            break; 
    } 
    return '\0'; 
} 

// Exemple : 
// printf("%c\n", convertir_wchar(L'é')); 
// const wchar_t * phrase = L"J'aime les loutres";


Tu noteras que pour indiquer qu'une chaîne ou un caractère sont basés sur des wchar_t, on les précède d'un "L".

Il ne reste plus qu'à corrige également le type du paramètre de is_pangramme (qui devient un const wchar_ *) et de pc (qui devient aussi un const wchar_t *), faire appel à la fonction convertir_wchar au lieu de convertir_char et l'affaire est dans le sac.

Bonne chance
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 838
26 janv. 2013 à 11:51
Juste pour info, le type booléen existe en C depuis la norme C99 (au même titre que les commentaires //, et bien d'autres changements).
0
mamiemando Messages postés 33161 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 28 juin 2024 7 760
26 janv. 2013 à 12:12
Exact, merci pour ta remarque. J'ajouterais qu'il faut alors inclure le header <stdbool.h>.
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 838
26 janv. 2013 à 12:15
oui et utiliser le type _Bool
0
mamiemando Messages postés 33161 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 28 juin 2024 7 760
26 janv. 2013 à 14:03
Je sais pas si ça marche partout mais avec gcc tu peux directement utiliser le type bool

#include <stdbool.h>

int main(){
    bool x = true;
    return 0;
}
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 838
26 janv. 2013 à 22:25
Oui ça marche partout si tu utilises stdbool.h.
Mais ce que je voulais dire c'est que tu peux utiliser le type _Bool sans inclure stdbool.h.
0