Fonction en language C

Fonction en language C - C - Programmation

Marsh Posté le 16-11-2011 à 20:09:00    

Bonjour
 
Je cherche à écrire une fonction qui lis une chaine de caractère et vérifie qu'elle ne contient que les 26 lettres de l'alphabet non accentuée.
 
Après plusieurs essais infructueux, je me tourne vers vous.
 
J'avais pensé à faire une truc du genre :
 
#define VRAI 1
#define FAUX 0
 
int verif(char *chaine)
{
    *chaine=VRAI
    while(*chaine==VRAI)
    {
        while(*chaine!='\0')
        {
            if((*chaine>=97&&*chaine<=122||*chaine>=65&&*chaine<=90)
                *chaine=VRAI
            else
                *chaine=FAUX
        }
    }
 
}
 
 
     

Reply

Marsh Posté le 16-11-2011 à 20:09:00   

Reply

Marsh Posté le 16-11-2011 à 21:27:55    

Le principe du test est correct, a condition de mettre les bonnes parenthèses (car || et && ont la même priorité il me semble).
Ce qui est faux, c'est que tu mélanges tes données avec quelque chose qui n'a rien a voir (un flag qui dit si on a trouvé autre chose dans la chaine), et ça, ça ne peut qu'introduire des problèmes.
Autre détail, on n'avance guère dans ta chaine :whistle:  
A+,

Message cité 1 fois
Message édité par gilou le 16-11-2011 à 21:29:09

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 17-11-2011 à 00:26:13    

Merci pour ton aide !

 

Vu que la base est bonne j'ai travailler toute la soirée dessus...sans succès

 

Voilà ce que j'ai actuellement :

 

int verif(char *chaine)
{
    int i=0;
    *chaine[i]=VRAI;    
    while(*chaine[i]==VRAI)
    {
        while(*chaine[i]!='\0')
        {
            if((*chaine[i]>=97&&*chaine[i]<=122)||(*chaine[i]>=65&&*chaine[i]<=90)
                {
                    *chaine[i]=VRAI;
                    i++;
                }
            else
                *chaine[i]=FAUX;
        }
    }

 

}

 

et dans le main :

 

for(i=0;i<n;i++)
    {
        printf("Introduisez le nom du client %d:\n",i+1);
        gets(source_nom[i]);
        verif(&source_nom[i]);
        //si FAUX demander de réencoder le nom
    }
Quand je compile j'ai "invalid type argument of `unary *" pour *chaine[i]=VRAI;

 

J'ai du mal avec les fonction et les pointeurs  :(


Message édité par Almenor le 17-11-2011 à 00:31:11
Reply

Marsh Posté le 17-11-2011 à 04:22:13    

Code :
  1. int verif(char *chaine)
  2. {
  3.     int i=0;
  4.     *chaine[i]=VRAI;  // Non et non: on ne mélange pas les données (chaine) avec le résultat VRAI ou FAUX   
  5.     while(*chaine[i]==VRAI)
  6.     {
  7.         while(*chaine[i]!='\0')  // c'est faux: c'est soit chaine[i], soit *chaine, il faut choisir. Vu votre code, on va prendre chaine[i]
  8.         {
  9.             if((*chaine[i]>=97&&*chaine[i]<=122)||(*chaine[i]>=65&&*chaine[i]<=90) // manque une parenthèse fermante
  10.                 {
  11.                     *chaine[i]=VRAI;
  12.                     i++;
  13.                 }
  14.             else  // manque une accolade
  15.                 *chaine[i]=FAUX;
  16.         } // et ici, on a une boucle infinie en fin de chaine
  17.     }
  18.            // et on renvoie pas de valeur?
  19. }


 
Ça a pourtant bien progressé par rapport a la version précédente, mais c'est bourré d'erreurs.
 
Une première version

Code :
  1. int verif(char *chaine) {
  2.     int i=0;
  3.     int verifok = 1;    // c'est cette valeur a 1 ou 0 que va retourner la fonction
  4.     while (verifok && (chaine[i]!= 0)) {  // tant que c'est OK et qu'il y a des caractères, on continue
  5. if (  (chaine[i] > = 97 && chaine[i] <= 122)
  6.     ||(chaine[i] > = 65 && chaine[i] <= 90 )) {
  7.     i++;  // c'est OK, on passe au caractère suivant au prochain tour
  8. }
  9. else {
  10.     verifok = 0; // c'est pas OK, on change le flag et ça va arréter la boucle
  11. }
  12.     }
  13.     return verifok;
  14. }


 
Comment ça s'améliore?
déja, on peut remplacer  
(verifok && (chaine[i]!= 0))
par
(verifok && chaine[i])
car dans un test, tester (chaine[i]!= 0) ou tester (chaine[i]) c'est équivalent.
 
On peut aussi tester sur les valeurs explicites des caractères, afin de rendre le code plus compréhensible.
On peut donc écrire une seconde version

Code :
  1. int verif(char *chaine) {
  2.     int i=0;
  3.     int verifok = 1;   
  4.     while (verifok && chaine[i]) {
  5. if (  (chaine[i] > = 'a' && chaine[i] <= 'z')
  6.     ||(chaine[i] > = 'A' && chaine[i] <= 'Z' )) {
  7.     i++;
  8. }
  9. else {
  10.     verifok = 0;
  11. }
  12.     }
  13.     return verifok;
  14. }


 
Enfin, plutôt que d'utiliser un indice de tableau, on peut faire cela avec une notation de pointeur:

Code :
  1. int verif(char *chaine) {
  2.     char *p = chaine;
  3.     int verifok = 1;   
  4.     while (verifok && *p) {
  5. if (  (*p > = 'a' && *p <= 'z')
  6.     ||(*p > = 'A' && *p <= 'Z' )) {
  7.     ++p;
  8. }
  9. else {
  10.     verifok = 0;
  11. }
  12.     }
  13.     return verifok;
  14. }


 
Et en fait, vu qu'on utilise nulle part chaine ailleurs que pour initialiser p, on peut encore simplifier
 

Code :
  1. int verif(char *chaine) {
  2.     int verifok = 1;   
  3.     while (verifok && *chaine) {
  4. if (  (*chaine > = 'a' && *chaine <= 'z')   
  5.     ||(*chaine > = 'A' && *chaine <= 'Z' )) {
  6.     ++chaine;
  7. }
  8. else {
  9.     verifok = 0;
  10. }
  11.     }
  12.     return verifok;
  13. }


 
Il manque plus qu'une chose, vérifier que l'argument passé était valable et qu'on avait le droit de l'utiliser, bref, vérifier que chaine n'était pas le pointeur NULL
Et penser au cas limite ou la chaine ne contient pas de caractère (ici une chaine vide renvoie 1)
 

Code :
  1. int verif(char *chaine) {
  2.     if (!chaine) return 0;
  3.     // if (!*chaine) return 0  // si on veut 0 avec une chaine vide
  4.     int verifok = 1;   
  5.     while (verifok && *chaine) {
  6. if ((*chaine > = 'a' && *chaine <= 'z') || (*chaine > = 'A' && *chaine <= 'Z' )) {
  7.     ++chaine;
  8. }
  9. else {
  10.     verifok = 0;
  11. }
  12.     }
  13.     return verifok;
  14. }


 
La ça commence a être une version utilisable.
 
Ensuite, si on réfléchit un peu plus, on peut virer le flag et aboutir à ceci:
 

Code :
  1. int verif(char *chaine) {
  2.     if (!chaine) return 0;
  3.     // if (!*chaine) return 0  // si on veut 0 avec une chaine vide
  4.     while (*chaine) {
  5.         if ((*chaine > = 'a' && *chaine <= 'z') || (*chaine > = 'A' && *chaine <= 'Z')) {
  6.             ++chaine;
  7.         }
  8.         else {
  9.             return 0;
  10.         }
  11.     }
  12.     return 1;
  13. }


 
 
A+,


Message édité par gilou le 17-11-2011 à 04:46:39

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 17-11-2011 à 10:17:35    

gilou a écrit :

car || et && ont la même priorité il me semble

 

&& est prioritaire sur || et leur priorite est basse, plus basse que les operateurs de comparaison. Leur comportement est donc assez intuitif (si on se souvient que && est comparable a la multiplication et || a l'addition pour retrouver leur priorite relative).

 

Ce qui est piegeux, c'est & et | (et ^) qui ont aussi une priorite plus basse que les operateurs de comparaison, ce qui est peu intuitif. D'autant plus que je ne connais pas de raisons expliquant la priorite relative de ^ par rapport a & et | (il se trouve au milieu, mais j'ai du verifier).

 


Message cité 1 fois
Message édité par Un Programmeur le 17-11-2011 à 10:19:20

---------------
The truth is rarely pure and never simple (Oscar Wilde)
Reply

Marsh Posté le 17-11-2011 à 10:57:47    

Un Programmeur a écrit :

&& est prioritaire sur ||

Merci, c'est le genre de truc que j'ai jamais fait l'effort de retenir, le degré de priorité relative entre || et &&.
 
Chaque fois que j'ai un test mélangeant les deux, je parenthèse.
Ça ne manger pas de pain, et c'est bien plus lisible pour qui relit le code derrière.
 
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 17-11-2011 à 11:13:57    

gilou a écrit :

Merci, c'est le genre de truc que j'ai jamais fait l'effort de retenir, le degré de priorité relative entre || et &&.
 
Chaque fois que j'ai un test mélangeant les deux, je parenthèse.
Ça ne manger pas de pain, et c'est bien plus lisible pour qui relit le code derrière.
 
A+,


 
Je fais comme toi.  Je l'ai retenu parce que je suis passe derriere trop de monde qui ne le faisait pas.


---------------
The truth is rarely pure and never simple (Oscar Wilde)
Reply

Marsh Posté le 18-11-2011 à 01:13:24    

Wow ! Merci Gilou pour cette explication détaillée !
 
Je vais étudier tout en détail dès demain puis je vais laisser macérer 1 jours ou deux dabs ma ptite tête et ensuite j'essayerai de le réécrire dans mon code. Comme ça je verrai si j'ai bien assimilé tout ça!
 
Encore merci  :jap:

Reply

Marsh Posté le 10-12-2011 à 12:06:20    

Vla la fonction que je vais utiliser (il faut qu'elle corresponde à mon niveau (1ere année) )
 

Code :
  1. int verif(char *chaine)//fonction qui vérifie si on encode que des lettres de l'alphabet non accentuées (majuscule ou minuscule)
  2. {
  3.     int i=0;
  4.     int verifok=1; //verifok = vrai
  5.     if(chaine[0]!='\0') //si la chaine n'est pas vide
  6.     {
  7.         while(verifok==1 && chaine[i]!='\0') //tant que verifok est vrai et que l'on est pas au caractère de fin
  8.         {
  9.             if((int)chaine[i]>=97&&(int)chaine[i]<=122 || (int)chaine[i]>=65&&(int)chaine[i]<=90) //si le caractère est une lettre minuscule ou majuscule
  10.                 i++;
  11.             else
  12.                 verifok=0; //verifok = faux
  13.         }
  14.     }
  15.     else
  16.         verifok=0; //verifok = faux
  17.     return verifok;
  18. }


 
J'ai pas réussi à intégrer le fait de ne pas avoir de chaine vide dans le if de la boucle while (ligne 9) j'ai donc ajouté un if avant la boucle qui vérifie que la chaine ne soit pas vide. Est-ce une bonne manière de fonctioner ? (toujours en prenant en compte qu'il s'agit d'un projet de 1ere année)

Reply

Marsh Posté le 10-12-2011 à 12:42:09    

Le "if" ligne 5 ne sert à rien. Si la chaîne est vide il ne rentrera pas dans la boucle.
 
Pas la peine de tester (verifok==1), (verifok) suffit : Vrai si différent de 0.
Idem pour (chaine[i]!='\0')
 
La boucle sert à savoir si le i eme caractère est OK.
Pas besoin de if, on met directement le résultat dans verifok.
 
On compare les caractères de la chaîne  avec un caractère litéral plutôt qu'avec un entier.
Comme çà ton prog fonctionne aussi bien en EBCDIC qu'en ASCII :)
 
Donc :
 

Code :
  1. //fonction qui vérifie si on encode que des lettres de l'alphabet non accentuées (majuscule ou minuscule)
  2. int verif(char *chaine)
  3. {
  4.     int i = 0;
  5.     int verifok = (int)chaine[0]; // Init de verifok : vrai si la chaîne n'est pas vide.
  6.    
  7.     // Tant que verifok est vrai et que l'on est pas au caractère de fin.
  8.     while( verifok && chaine[i] )
  9.     {
  10.        // On cherche la valeur de verifok pour le caractère i :
  11.         verifok = ( chaine[i] >= 'A' && chaine[i]<= 'Z' ) || ( chaine[i] >= 'a' && chaine[i]<='z' )
  12.         i++;
  13.     }
  14.     return verifok;
  15. }


Message édité par Mara's dad le 10-12-2011 à 12:43:34

---------------
Laissez l'Etat dans les toilettes où vous l'avez trouvé.
Reply

Marsh Posté le 10-12-2011 à 12:42:09   

Reply

Marsh Posté le 26-12-2011 à 15:42:45    

re Bonjour.
 
J'ai un autre problème avec une de mes fonction.
 
Cette fois-ci je n'arrive pas à trier un tableau.
 
Voici mes fonctions :
 

Code :
  1. int strcomp(char *chaine1,char *chaine2)//fonction de comparaison des noms
  2. {
  3.     int i=0;
  4.     while(chaine1[i]!='\0'&&chaine2[i]!='\0')//tant que l'on est pas au caractère de fin de la chaine 1 et de la chaine 2
  5.     {
  6.         if((int)chaine1[i]<(int)chaine2[i])//si le caractère de la chaine 1 est plus petit que le caractère de la chaine 2
  7.             return 1;
  8.         else
  9.         {
  10.             if((int)chaine1[i]>(int)chaine2[i])//si le caractère de la chaine 1 est plus grand que le caractère de la chaine 2
  11.                 return -1;
  12.             else
  13.                 i++;
  14.         }
  15.     }
  16.     if(chaine1[i]==chaine2[i])//si le caractère de la chaine 1 est le même que le caractère de la chaine 2
  17.         return 0;
  18.     else
  19.     {
  20.         if(chaine1[1]=='\0')//si on arrive au caractère de fin de chaine de chaine1
  21.             return 1;
  22.         else
  23.             return -1;
  24.     }
  25. }
  26. void tri(char *chaine,int n)//fonction qui trie les chaines de caractère
  27. {
  28.     int i,pasfini=1,limite=n-1,pos;
  29.     char temp;
  30.     while(pasfini==1)//tant que pasfini=1
  31.     {
  32.         pasfini=0;
  33.         for(i=0;i<limite;i++)
  34.         {
  35.             if(strcomp(chaine[i],chaine[i+1])==-1)//si la fonction de comparaison strcomp renvoi -1, c'est donc qu'il faut inverser les chaines de caractères
  36.             {
  37.                 temp=chaine[i];
  38.                 chaine[i]=chaine[i+1];
  39.                 chaine[i+1]=temp;
  40.                 pasfini=1;
  41.                 pos=i;
  42.             }
  43.         }
  44.         limite=pos;
  45.     }
  46. }


 
dans le main j'ai un tableau tri_nom que j'envoi dans la fonction tri :
 

Code :
  1. for(i=0;i<n;i++)
  2.                     tri(tri_nom[i],n);
  3. for(i=0;i<n;i++)
  4.                     printf("%s\n",tri_nom[i]);


 
n étant le nombre de nom que l'utilisateur a choisis d'encoder
 
quand je compile j'ai ce message :
 

Citation :

Compiler: Default compiler
Executing  gcc.exe...
gcc.exe "C:\Users\Marco\Documents\Informatique de gestion\PMP\projetpmp1.c" -o "C:\Users\Marco\Documents\Informatique de gestion\PMP\projetpmp1.exe"    -I"C:\Dev-Cpp\include"   -L"C:\Dev-Cpp\lib"  
C:\Users\Marco\Documents\Informatique de gestion\PMP\projetpmp1.c: In function `tri':
C:\Users\Marco\Documents\Informatique de gestion\PMP\projetpmp1.c:110: warning: passing arg 1 of `strcomp' makes pointer from integer without a cast
C:\Users\Marco\Documents\Informatique de gestion\PMP\projetpmp1.c:110: warning: passing arg 2 of `strcomp' makes pointer from integer without a cast
 
C:\Users\Marco\Documents\Informatique de gestion\PMP\projetpmp1.c: In function `main':
C:\Users\Marco\Documents\Informatique de gestion\PMP\projetpmp1.c:232: error: called object is not a function
 
Execution terminated


 
La ligne 110 correspond ici à la ligne 38 et 232 à la ligne 2
 
Merci d'avance pour le temps que vous prendrez à m'aider :)
 
PS : Je ne demande pas d'écrire le code pour moi (c'est mon projet de fin de cours) mais de m'expliquer quelle est mon erreur.

Reply

Marsh Posté le 26-12-2011 à 17:25:58    

t'es obligé de réinventer la roue ? tu peux pas utiliser strncmp ?

Reply

Marsh Posté le 26-12-2011 à 17:28:21    

La fonction tri(...) ne semble pas être dans le même fichier que celui qui contient le main(...)
Si c'est bien le cas, il faudrait déclarer le prototype de la fonction tri(...) dans le fichier du main(...) par une ligne :

extern void tri(char *chaine, int n);

Reply

Marsh Posté le 27-12-2011 à 01:56:39    

@Tamahome : oui je suis obligé de réinventer la roue, je ne peux pas utiliser la bibliothèque string.h pour ce projet :( .
 
@olivthill : non, tout est bien dans le même fichier, on a pas encore appris à travailler dans des fichiers différents pour le moment (1ere année)

Reply

Marsh Posté le 29-12-2011 à 18:31:14    

Hello, j'ai un ptit peu avancé mais ce n'est pas encore ça...
 
j'ai donc 3 fonctions :
 - une fonction strcopy qui copie une chaine dans une autre
 - une fonction strcomp qui compare les chaines de caractères (renvoi -1 si il faut permuter)
 - et la fonction tri en elle même
 
Alors, très certainement que je m'embrouille dans les pointeurs car je ne maitrise pas encore parfaitement (ou pas du tout... :/)
 J'ai aussi un soucis quand je je copie la chaine lorsqu'il faut inverser, le résultat est....déconcertant  
Poutant ma fonction strcopy fonctionne parfaitement l'ayant tester à part.  
Idem pour la fonction strcomp qui fonctionne parfaitement tester à part.
 
 

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define N 5 //nombre maximum d'entrée
  4. void strcopy(char *chaine1,char *chaine2)//fonction qui copie chaine1 dans chaine2
  5. {
  6.     int i=0;
  7.     while(chaine1[i]!='\0')
  8.     {
  9.         chaine2[i]=chaine1[i];
  10.         i++;
  11.     }
  12.     chaine2[i]='\0';
  13. }
  14. int strcomp(char *chaine1,char *chaine2)//fonction de comparaison des noms
  15. {
  16.     int i=0;
  17.     while(chaine1[i]!='\0'&&chaine2[i]!='\0')//tant que l'on est pas au caractère de fin de la chaine 1 et de la chaine 2
  18.     {
  19.         if((int)chaine1[i]<(int)chaine2[i])//si le caractère de la chaine 1 est plus petit que le caractère de la chaine 2
  20.             return 1;
  21.         else
  22.         {
  23.             if((int)chaine1[i]>(int)chaine2[i])//si le caractère de la chaine 1 est plus grand que le caractère de la chaine 2
  24.                 return -1;
  25.             else
  26.                 i++;
  27.         }
  28.     }
  29.     if(chaine1[i]==chaine2[i])//si le caractère de la chaine 1 est le même que le caractère de la chaine 2
  30.         return 0;
  31.     else
  32.     {
  33.         if(chaine1[1]=='\0')//si on arrive au caractère de fin de chaine de chaine1
  34.             return 1;
  35.         else
  36.             return -1;
  37.     }
  38. }
  39. void tri(char *chaine,int n)//fonction qui trie les chaines de caractère
  40. {
  41.     int i,pasfini=1,limite=n-1,pos;
  42.     char temp[31];
  43.     while(pasfini==1)//tant que pasfini=1
  44.     {
  45.         pasfini=0;
  46.         for(i=0;i<limite;i++)
  47.         {
  48.             if(strcomp(&chaine[i],&chaine[i+1])==-1)//si la fonction de comparaison strcomp renvoi -1, c'est donc qu'il faut inverser les chaines de caractères
  49.             {
  50.                 strcopy(&chaine[i],&temp);
  51.                 strcopy(&chaine[i+1],&chaine[i]);
  52.                 strcopy(&temp,&chaine[i+1]);
  53.                 pasfini=1;
  54.                 pos=i;
  55.             }
  56.         }
  57.         limite=pos;
  58.     }
  59. }
  60. main()
  61. {
  62.     char tab[N][31];
  63.     int i;
  64.     for(i=0;i<N;i++)
  65.                     gets(tab[i]);
  66.     for(i=0;i<N;i++)
  67.                     tri(tab[i],N);
  68.     printf("\n\n" );
  69.     for(i=0;i<N;i++)
  70.                     printf("%s\n",tab[i]);
  71.     system("pause" );
  72. }

Reply

Marsh Posté le 16-01-2012 à 00:40:35    

Bonjour,
Il faut prendre en compte le type du tableau dans le prototype de tri.
 
Les donnees en mémoire sont organisées comme ceci:

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA(31 chars)BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB(etc.)


càd chaque sous-indice à la queue leu leu (N blocs de 31).
 
tab n'est pas un tableau de char* mais un multi-dim, nuance !
 
tri() ne peut pas le savoir si on ne lui indique pas, lorsqu'on écrit tab[i], quel est le pas de chasse.

chaine1\0.......................
^
|---- tab[0]
chaine2\0.......................
^
|---- tab[1]
etc.


Donc le proto ce serait plutôt :

Code :
  1. void tri(char tabchaine[N][31], int n)//fonction qui trie les chaines de caractère


ou bien

Code :
  1. void tri(char tabchaine[][31], int n)//fonction qui trie les chaines de caractère


 
 
et l'appel:

Code :
  1. tri(tab,N);


 
D'autre part le bubblesort m'a l'air suspect, normalement sa complexité est O(n2) et pas O(n).
Il me semble qu'il manque une sous boucle je crois.
Désolé mes souvenirs de C sont hyper lointains ^^
 
Edit: Ah, ok, la boucle se situe au niveau du main().


Message édité par raskt le 16-01-2012 à 00:50:24
Reply

Marsh Posté le 16-01-2012 à 10:31:30    

Merci pour ces explications  :jap:  
 
Ca commence tout doucement à rentrer dans ma ptite tête   :)


Message édité par Almenor le 16-01-2012 à 10:31:39
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed