Programmation en C - Suppression de caractère

Programmation en C - Suppression de caractère - C - Programmation

Marsh Posté le 20-03-2005 à 14:41:52    


Bonjour,  
 
je suis en 1e année de licence maths-info et j'ai un petit problème avec un programme que je dois faire pour mon cours de programmation. (Hem, j'ai des cours de programmation en C depuis la fin du mois de janvier, je suis donc une débutante :D)  
 
Le but du programme est de dire si un mot est un palindrome ou pas. (Un palindrome étant un mot ou une phrase que l'on peut lire de droit à gauche et de gauche à droite, comme 'ici')  
Ce qui me pose problème c'est de supprimer les caractères espace dans la chaine de caractère que je veux tester.  
 
Je m'exlique :  
Je dois faire une fonction 'palindrome' qui a pour argument une chaine de caractère S et qui supprime les éventuels caractères 'espace' de la chaîne S (par exemple 'elu par cette crapule' est un palindrome, faut enlever les espaces...) et retourne ensuite la valeur 1 si S est un palindorme et 0 si ce n'est pas un palindrome.  
 
Pour le palindrome en lui même, je n'ai pas de problème, c'est la suppression des espaces qui me pose un problème. J'ai tenté plusieurs choses, mais chaque fois ça me supprime ce qu'il y a après le 1e espace...  
 
Si jamais vous pouviez m'aider :D  
 
 
Merci  
:)  
 
Emmylou

Reply

Marsh Posté le 20-03-2005 à 14:41:52   

Reply

Marsh Posté le 20-03-2005 à 15:16:05    

Salut,
 
 
Sa fait longtemps que j'ai pas touché au C mais:
ce que tu peux peut etre faire c'est :

  • créer une nouvelle variable qui contiendra la chaine sans espace
  • puis tu parcours tous les caractères du texte saisi (jusqu'a '\n')
  • tu teste le caractère en cours :

   

Code :
  1. j,i=0;
  2.              while(phrase[i]!= '\n')
  3.              {
  4.                    if(phrase[i]!= ' ')
  5.                    {
  6.                      phrase_sans_espace[j] = phrase[i];
  7.                      j++;
  8.                    }
  9.                    i++;
  10.              }

Reply

Marsh Posté le 20-03-2005 à 15:19:03    

pourquoi aller jusque \n et pas jusque la fin de la chaine ??


---------------
Nos estans firs di nosse pitite patreye...
Reply

Marsh Posté le 20-03-2005 à 15:39:27    

Humpf, ça ne marche toujours pas.
A chaque fois, ça ne me teste que le premier mot.
Peut-être que le problème vient d'autre part. Voilà ce que j'ai fait :  
 
#include<stdio.h>
#include<string.h>
 
int palindrome(char S[80])
{
     int i, j, L, test;
     char M[80], sans_espace[80];
     L=strlen (S);
     i=0;  
     j=0;
     while(i<L)  
             {  
                   if(S[i]!= ' ')  
                   {  
                     sans_espace[j] = S[i];  
                     j++;  
                   }  
                   i++;  
             }
      S[80]=sans_espace[80];
      L=strlen (S);
      for (j=0; j<L; j++)
      {
          for (i=L-1; i>=0; i--)
          M[j]=S[i];
      }
      test=0;
      for (i=0; i<L; i++)
      if (M[i]!=S[i])
      test=0;
      else  
      test=1;
return test;
}
int main (void)
{
    char mot[80], rep;
    int a;
    do
    {
         printf ("Entrez le mot \n" );
         scanf ("%s", &mot);
         a=palindrome (mot);
         if (a==1)
         printf ("%s est un palindrome \n", mot);
         if (a==0)
         printf ("%s n'est pas un palindrome \n", mot);
         printf ("Continuer ? o/n  \n" );
do
    {
     rep=getchar();
     }
     while ((rep!='o')&&(rep!='n'));
     }
while (rep=='o');
 
    return 0;
}
           
           
M'ci :)    

Reply

Marsh Posté le 20-03-2005 à 16:16:56    

Ton problème vient du scanf.
 
Pour commencer, en C, un tableau est automatiquement converti en une valeur de type pointeur lorsqu'il est utilisé dans une expression. Le & est donc inutile (mais n'a pas d'effet, la valeur du pointeur restant identique -- mais j'ignore si ce comportement dépend de l'implémentation).
 
Plus important, scanf tel que tu l'utilises ne lit qu'un mot, ce qui n'est pas ce que tu veux.
 
Et encore plus important, il ne faut pas utiliser scanf pour récupérer une chaine de caractère entrée par l'utilisateur : imagine qu'il tape une chaine de caractère de plus de 80 caractères! Le mieux est d'utiliser fgets (n'oublie pas d'enlever le '\n' final).
 
Dernière remarque, les valeurs telles que ton 80 partout dans le code sont à proscrires (imagine ce qu'il se passe si tu veux changer cette valeur dans un fichier de plusieurs milleirs de lignes [:petrus75] ). Utilise plutôt un #define et des sizeof ;)

Reply

Marsh Posté le 20-03-2005 à 16:23:47    


Bon, j'ai compris.
Mais, est-ce que tu pourrais me dire comment utiliser le fgets ? Je le met où ?
 
(Puis, pour le 80, hem, j'suis la seule à utiliser mon programme :D (ui bon, c'est vrai que...))
 
(Re)M'ci  
:)

Reply

Marsh Posté le 20-03-2005 à 16:40:13    

Emmylou a écrit :

Humpf, ça ne marche toujours pas.
A chaque fois, ça ne me teste que le premier mot.
Peut-être que le problème vient d'autre part. Voilà ce que j'ai fait :  


Analyse de ton code :


#include <stdio.h>
#include <string.h>
#include <ctype.h>
 
/* -ed-
 * cet algorithme me parait bien complique.
 * Si il faut que la fonction 'palindrome' travaille sur une chaine
 * sans espaces, autant faire une fonction de nettoyage a part, on
 * y verra plus clair...
 */
#if 0
int palindrome (char S[80])
{
   int i, j, L, test;
   char M[80], sans_espace[80];
   L = strlen (S);
   i = 0;
   j = 0;
   while (i < L)
   {
      if (S[i] != ' ')
      {
         sans_espace[j] = S[i];
         j++;
      }
      i++;
   }
   S[80] = sans_espace[80];
   L = strlen (S);
   for (j = 0; j < L; j++)
   {
      for (i = L - 1; i >= 0; i--)
         M[j] = S[i];
   }
   test = 0;
   for (i = 0; i < L; i++)
      if (M[i] != S[i])
         test = 0;
      else
         test = 1;
   return test;
}
#endif
 
static void remove_spaces (char *s)
{
   char const *pr = s;
   char *pw = s;
 
   while (*pr)
   {
      /* teste tout ce qui est pris comme une espace. */
      if (!isspace (*pr))
      {
         *pw = *pr;
         pw++;
      }
      pr++;
   }
   *pw = *pr;
}
 
 
/* pour tester un palindrome, il faut un index sur le debut,
 * et un index a la fin. Tant que la valeur lue est identique
 * et que les index ne se sont pas croises, on continue.
 * Si il sont egaux, on a un palindrome.
 */
int palindrome (char const *s)
{
   int is_pal = 0;
   char const *p_deb = s;
   char const *p_fin = s + (strlen (s) - 1);
 
   /* a toi de coder ce qu'il faut ici.
    * boucle; condition, test, changements de p_deb et p_fin...
    */
 
   return is_pal;
}
 
static void get_s (char *s, size_t size)
{
   if (fgets (s, (int) size, stdin) != NULL)
   {
      /* search'n ... */
      char *p = strchr (s, '\n');
 
      if (p != NULL)
      {
         /* ... kill */
         *p = 0;
      }
      else
      {
         /* clean */
         int c;
 
         while ((c = getchar ()) != '\n' && c != EOF)
         {
         }
      }
   }
}
 
int main (void)
{
   char mot[80], rep;
   int a;
   do
   {
      printf ("Entrez le mot \n" );
/* -ed-
 
   scanf ("%s", &mot);
 
   * 'mot' est une adresse constante de type char.
   * Le & provoque un comportement indefini (même adresse, mais mauvais type)
   ("%s" attend un 'char *')
   * Si on entre plus de 79 caracteres, le comportement est indefini.
   * scanf() avec "%s" extrait un mot, pas une phrase (mots avec separateurs).
   * Le retour de scanf() devrait être testé. (ici, 1, sinon, erreur)
   *
   * Peu de gens maitrisent cette fonction d'experts.
   * Les autres (moi, le premier) utilisent fgets() ou une fonction maison.
 */
      get_s (mot, sizeof mot);
 
      remove_spaces (mot);
 
      a = palindrome (mot);
      if (a == 1)
         printf ("%s est un palindrome \n", mot);
      if (a == 0)
         printf ("%s n'est pas un palindrome \n", mot);
      printf ("Continuer ? o/n  \n" );
      do
      {
         rep = getchar ();
      }
      while ((rep != 'o') && (rep != 'n'));
   }
   while (rep == 'o');
 
   return 0;
}


Message édité par Emmanuel Delahaye le 20-03-2005 à 16:42:05

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 20-03-2005 à 16:43:31    

Emmylou a écrit :

Mais, est-ce que tu pourrais me dire comment utiliser le fgets ? Je le met où ?


http://mapage.noos.fr/emdel/notes.htm#saisie
 
A la place du scanf().


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 20-03-2005 à 21:00:28    

Emmanuel> pourrais-tu donner un lien, ou un début d'explication, sur l'utilisation en *mode expert* de scanf ?

Reply

Marsh Posté le 20-03-2005 à 21:29:08    

++fab a écrit :

Emmanuel> pourrais-tu donner un lien, ou un début d'explication, sur l'utilisation en *mode expert* de scanf ?


Franchement, je n'en ai pas. Je connais (via le forum Usenet comp.lang.c) un gourou qui est spécialiste de la chose, c'est Dan Pop :
 
Dan.Pop@cern.ch
danpop@mail.cern.ch
danpop@cernapo.cern.ch
danpop@afsmail.cern.ch
 
Si tu veux lui demander de monter un site, bon courage.


Message édité par Emmanuel Delahaye le 20-03-2005 à 21:34:26

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 20-03-2005 à 21:29:08   

Reply

Marsh Posté le 21-03-2005 à 05:52:18    

scanf pas bien.
 
scanf() == read() + aquisition vsnprintf() == lenteur + bufferization de ******
 
Vous devriez franchement vous mettre un minimun au parsing. Tout les gars que je vois sur ce forum utilise ce genre de fonction.
 
En plus dans :
 

Code :
  1. int main (void)
  2. {
  3.    char mot[80], rep;
  4.    int a;
  5.    do
  6.    {
  7.         printf ("Entrez le mot \n" );
  8.         scanf ("%s", &mot);


       
Ya encore un buffer overflow possible #!@.
 
Vous n'allez pas me dire que c'est dure de faire :  
 

Code :
  1. int main (void)
  2. {
  3.    char mot[80], rep;
  4.    int a;
  5.    do
  6.    {
  7.         printf ("Entrez le mot \n" );
  8.         memset(mot, 0x00, sizeof(mot));
  9.          read(1, mot, sizeof(mot)-1);
  10.          // scanf ("%s", &mot); mot est un tableau donc pas de & (reference)


 
Et arretez (notamment Emmanuel D elahay) de dire que read/write etc ne sont pas standard.
 
A la limite vraiment c'est mieux d'utilisé fgets() mais bon.... il y a toujour une histoire de bufferization. Alors que read()/write() sont des appele systemes.


Message édité par plofplof le 21-03-2005 à 06:00:08
Reply

Marsh Posté le 21-03-2005 à 08:40:26    

plofplof a écrit :


Vous n'allez pas me dire que c'est dur de faire :  

Code :
  1. int main (void)
  2. {
  3.     char mot[80], rep;
  4.     int a;
  5.     do
  6.     {
  7.          printf ("Entrez le mot \n" );
  8.          memset(mot, 0x00, sizeof(mot));
  9.          read(1, mot, sizeof(mot)-1);
  10.          // scanf ("%s", &mot); mot est un tableau donc pas de & (reference)


Et arretez (notamment Emmanuel Delahaye) de dire que read/write etc ne sont pas standard.


Désolé, mais je ne suis pas près d'arréter! D'ailleurs, ce que je dis, c'est une évidence, c'est à dire qu'elles ne font pas partie de la norme qui définit le langage C.
 
Pas de 'read()' sur ma plateforme AMX/MRI pour 68000 (Embarqué). Pas ça non plus sous Mac (non OS/X) à ma connaissance.

Citation :


A la limite vraiment c'est mieux d'utilisé fgets() mais bon.... il y a toujour une histoire de bufferization. Alors que read()/write() sont des appele systemes.


La bufferisation est un avantage reconnu en matière de performance (par la réduction du nombre d'appels systèmes, notamment). Autre avantage de fgets(), c'est une fonction standard du langage C assez simple à utiliser et robuste.
 
Désolé d'insister, mais les fonctions systèmes read() / write() etc. sont des fonctions, certes au standard POSIX.1, mais qui ne font pas partie du langage C.
 
Que je sache, rien n'oblige une plateforme à supporter POSIX.1. Ces fonctions ne sont donc pas portables.


Message édité par Emmanuel Delahaye le 21-03-2005 à 17:38:49

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 21-03-2005 à 17:03:35    

Hello,
 

Citation :


Pas de 'read()' sur ma plateforme AMX/MRI pour 68000 (Embarqué). Pas ça non plus sous Mac (non OS/X) à ma connaissance.


 
P-e pour ton AMX pas pour mac os.  
 
descript-mac:~ root# uname -a
Darwin descript-mac.local 7.6.0 Darwin Kernel Version 7.6.0: Sun Oct 10 12:05:27 PDT 2004; root:xnu/xnu-517.9.4.obj~1/RELEASE_PPC  Power Macintosh powerpc
 

Citation :


La bufferisation est un avantage reconnu en matière de performance (par la réduction du nombre d'appels systèmes, notamment). Autre avantage de fgets(), c'est une fonction standard du langage C assez simple à utiliser et robuste.  


 
Un avantage reconnu ? P-e pas quand meme non plus :).
Le gros probleme est la mauvaise syncronisation d'ecriture du message quand tu utilise des thread. Ou aussi quand tu utilise ton propre algo d'allocation.
 
Les fonctions read() / write() utilise des appels systeme linux. 0x3 pour read() et 0x4 pour write(). Un syscall (appele-systeme) est appeler par une interruption (0x80 pour linux).  
 
Par exemple exit() est aussi un syscall :

Code :
  1. mov eax, 0x1
  2. int 0x80


 
A savoir que la lecture / ecriture par des syscall permet (aussi) de s'aligner sur la vitesse de scheduling du kernel (select() / poll() / epoll() / kqueue()).
 
read() & write() ne bufferize pas.  
 
Très franchement c'est meme pas la pene d'essayer de comparer fgets() / fread() par rapport read() en terme de performance.
 
++

Reply

Marsh Posté le 21-03-2005 à 17:36:19    

Citation :

Un avantage reconnu ? P-e pas quand meme non plus :).


 :cry:  
 
read(), write(), c'est pas du C .|

Reply

Marsh Posté le 21-03-2005 à 18:14:10    

c'est pas du C ANSI
mais UNIX et Win 32.
 
allé j'ai pas pu m'empêcher...

Code :
  1. bool isPalindrome(char *phrase, int n)
  2. {
  3.     for(char *debut=phrase,*fin=debut+n-1;debut<=fin;debut++,fin--)
  4.     {
  5.         while(*debut==' ') debut++;
  6.         while(*fin==' ') fin--;
  7.         if(*debut!=*fin) return false;
  8.     }
  9.     return true;
  10. }


Message édité par fra0 le 21-03-2005 à 18:32:29
Reply

Marsh Posté le 21-03-2005 à 20:17:16    

dommage, t'as oublié tout les const :o
 
bon, ça passe en C99 uniquement ton truc.

Reply

Marsh Posté le 21-03-2005 à 20:35:19    

++fab a écrit :

dommage, t'as oublié tout les const :o
 
bon, ça passe en C99 uniquement ton truc.


C90 un peu remanié avec test unitaire :


#include <stdio.h>
#include <string.h>
 
#define NELEM(a) (sizeof(a)/sizeof*(a))
 
typedef enum
{
   false, true
}
bool;
 
bool isPalindrome (char const *phrase)
{
   size_t const n = strlen (phrase);
   char const *debut;
   char const *fin;
 
   for (debut = phrase, fin = debut + n - 1; debut <= fin; debut++, fin--)
   {
      while (*debut == ' ')
      {
         debut++;
      }
      while (*fin == ' ')
      {
         fin--;
      }
 
      if (*debut != *fin)
      {
         return false;
      }
   }
 
   return true;
}
 
 
 
int main (void)
{
   typedef struct
   {
      char const *phrase;
      bool ok;
   }
   test_s;
 
   static const test_s a_test[] =
   {
      {"", 1},
      {"a", 1},
      {"aa", 1},
      {"aba", 1},
      {"abba", 1},
      {"a bba", 1},
      {"ab ba", 1},
      {"abb a", 1},
      {"abba ", 1},
      {"ab", 0},
      {"abb", 0},
   };
 
   size_t i;
 
   for (i = 0; i < NELEM (a_test); i++)
   {
      test_s const *p = a_test + i;
 
      bool ok = isPalindrome (p->phrase);
 
      if (ok != p->ok)
      {
         printf ("error at test %u\n", (unsigned) (i + 1));
         break;
      }
   }
   if (i == NELEM (a_test))
   {
      printf ("P A S S E D\n" );
   }
 
   /* Dev-C++ trick */
   system ("pause" );
   return 0;
}


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 22-03-2005 à 06:03:08    

Les zami
C'est en C++ qu'on met char const *plof.
 
En C c'est const char *.
 
Et son truc passera sur du C89, C90 et C99.

Code :
  1.   size_t const n = strlen (phrase);
  2.   char const *debut;
  3.   char const *fin;


 
j'suis pas dakor meme si ca marche.
 

Code :
  1.   const size_t n = strlen (phrase);
  2.   char *debut;
  3.   char *fin;


 
puis merde c vraiment un truc que de mesure de nivo ici.

Reply

Marsh Posté le 22-03-2005 à 08:06:50    

plofplof a écrit :


C'est en C++ qu'on met char const *plof.
 
En C c'est const char *.
 


Houlala ...   :pt1cable:    :o  
 

Reply

Marsh Posté le 22-03-2005 à 08:39:55    

plofplof a écrit :


C'est en C++ qu'on met char const *plof.
 
En C c'est const char *.


??? Je ne connais pas le C++, mais en C, c'est comme on veut.


const char *p;
char const *p;


Citation :

Et son truc passera sur du C89, C90 et C99.


Quel truc ? Tes commentaires sont assez ésotériques, c'est normal ?
 
En tout cas, ça

for(char *debut=phrase,*fin=debut+n-1;debut<=fin;debut++,fin--)


c'est du C99.

Citation :


Code :
  1. size_t const n = strlen (phrase);
  2.    char const *debut;
  3.    char const *fin;


 
j'suis pas dakor meme si ca marche.


Tu n'est pas d'accord avec quoi (à part l'orthographe) ? Quels sont tes arguments ? En matière technique, je ne me contente pas d'impressions...

Citation :


Code :
  1. const size_t n = strlen (phrase);
  2.    char *debut;
  3.    char *fin;




Etant donné que j'ai modifié le paramètre 'phrase' en 'char const *phrase', les pointeurs sur cet objet doivent aussi être 'const'. C'est logique, et si tu ne le fais pas, ton compilateur se chargera de te le rappeler.

Citation :

puis merde c vraiment un truc que de mesure de nivo ici.


Quel est le sens exact de cette remarque ?


Message édité par Emmanuel Delahaye le 22-03-2005 à 08:42:02

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 22-03-2005 à 09:21:06    

:lol:  
 

Citation :

C'est en C++ qu'on met char const *plof.
En C c'est const char *.


 
pour ton information, le const s'applique toujours à ce qui est placé immédiatement avant lui.
Sauf lorsqu'il n'y a rien avant : dans ce cas la, il s'applique à ce qu'il y a immédiatement après. [:adodonicoco]  
En C++, c'est exactement la même règle.
 

Citation :

j'suis pas dakor meme si ca marche.


t'es pas kador non plus  [:petrus75]

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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