Comment supprimer les caractères non chiffre en langage C
Résolu/Fermé
salammans
Messages postés
1
Date d'inscription
mercredi 15 décembre 2021
Statut
Membre
Dernière intervention
15 décembre 2021
-
Modifié le 16 déc. 2021 à 15:18
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 - 16 déc. 2021 à 16:30
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 - 16 déc. 2021 à 16:30
A voir également:
- Supprimer un caractère d'une chaine c
- Caractère ascii - Guide
- Supprimer une page word - Guide
- Caractere speciaux - Guide
- Supprimer compte instagram - Guide
- Caractère spéciaux - Guide
2 réponses
[Dal]
Messages postés
6198
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
13 décembre 2024
1 096
Modifié le 16 déc. 2021 à 15:20
Modifié le 16 déc. 2021 à 15:20
Salut salammans,
Qu'est ce que tu ne comprends pas ?
Dans ce que tu envoies, la fonction
La fonction
Lorsque toute la chaîne est parcourue, la chaîne est terminée par le caractère terminateur de chaîne
Cette fonction
Dal
Qu'est ce que tu ne comprends pas ?
Dans ce que tu envoies, la fonction
est_un_chiffre()n'est pas implémentée, cependant je suppose qu'elle fonctionne de façon similaire à la fonction standard
isdigit().
La fonction
supprime_non_chiffres()parcourt la chaîne avec deux curseurs :
- un qui avance sur tous les caractères de la chaîne à la recherche de chiffres
- l'autre qui avance de un à un seulement lorsqu'un chiffre est trouvé à mesure que les char existants sont écrasés
Lorsque toute la chaîne est parcourue, la chaîne est terminée par le caractère terminateur de chaîne
'\0'.
Cette fonction
supprime_non_chiffres()ne peut être appelée qu'avec une chaîne sous la forme de tableau de
charou avec un pointeur sur
charpointant sur de la mémoire allouée avec
malloc, mais pas avec une constante littérale, puisque la chaîne passée est modifiée sur place.
Dal
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
Modifié le 22 déc. 2021 à 13:24
Modifié le 22 déc. 2021 à 13:24
Bonjour,
Je me permets de compléter la réponse de Dal
Rappels préliminaires sur les chaînes de caractères et les pointeurs en C
Que doit faire ton programme ?
Si celle-ci contient des caractères numériques, la chaîne transformée sera plus courte, et c'est pourquoi il faudra :
Que fait ton corrigé ?
Plutôt que de maintenir une variable
De plus, comme la chaîne à transformer est déjà allouée en mémoire, il n'est pas utile d'allouer un bloc mémoire pour la chaîne transformée. Nous allons maintenant ajouter quelques
Vu que tu n'as pas forcément encore fait le cours sur les allocations mémoires, et même si je prends le soin de tout expliquer, tu peux l'ignorer dans un premier temps si tu as mal à la tête et aller directement à la section "exécution du programme" :-)
Allocations dynamiques,
Cependant il faut savoir que si tu déclare ta chaîne
C'est pourquoi dans le code ci-dessous, je prends le soin d'allouer dynamiquement une copie de
Tu noteras que l'allocation mémoire est faite avec
Ensuite, si tu lis la documentation de
Si l'allocation a marché, on recopie
Qui dit
Exécution du programme
On obtient ceci :
Si tu as besoin de plus de clarifications, n'hésite pas.
Bonne chance
Je me permets de compléter la réponse de Dal
Rappels préliminaires sur les chaînes de caractères et les pointeurs en C
-
chaine
est un pointeur, c'est à dire l'adresse d'un bloc mémoire. - plus précisément,
chaine
est de typechar *
ce qui signifie que ce bloc mémoire peut être vu comme une tableau dont chaque case fait la taille d'unchar
(ça tombe bien, c'est ce qu'on veut pour une chaîne !) - comme le pointeur est typé (ici les cases sont vues comme des
char
), alors les opérateurschaine[i]
,*chaine
, etchaine++
sont bien définis (ce ne serait pas le cas pour un adresse "générique", qui se notevoid *
). Pour ton exercice, seulchaine[i]
nous intéresse. Du point de vue du C, il retourne lei
-ème bloc de taillechar
à partir de l'adresse stockée dans la variablechaine
. De notre point de vue d'être humain, cela revient à récupérer lei
-ème caractère dechaine
. - cependant, rien dans le type
char *
n'indique combien de caractère fait la chaîne. Si on commence à lire caractère par caractère ce bloc, toute la question est donc "quand s'arrêter ?". Pour répondre à ce problème, en C/C++ (et en fait dans tous les langages), en mémoire, une chaîne contient un caractère d'arrêt supplémentaire, par convention'\0'
. - cela signifie que la boucle suivante permet d'afficher un par un les caractère de
s
:
#include <stdio.h> int main(){ const char * s = "Bonjour 123 Au revoir"; int i; while(s[i] != '\0') { printf("%c", s[i]); i++; } return 0; }
- si on veut ignorer les caractères non numériques, on pourrait utiliser comme le dit Dal
isdigit
:
#include <stdio.h> #include <ctype.h> int main(){ const char * s = "Bonjour"; int i; for(i = 0; s[i] != '\0'; i++) { if (isdigit(s[i])) { printf("%c", s[i]); } } return 0; }
- Note enfin que quand on écrit
s = "Bonjour"
, cela signifie implicitement que le bloc"Bonjour\0"
est créé de manière statique (dans l'exécutable). Le'\0'
est implicitement pris en compte.
Que doit faire ton programme ?
Si celle-ci contient des caractères numériques, la chaîne transformée sera plus courte, et c'est pourquoi il faudra :
- "supprimer" les caractères non-numériques ;
- "décaler" de n caractères vers la gauche tous les caractères numériques s'ils sont précédés de n caractères non-numériques ;
- "décaler" de n caractères vers la gauche le caractère d'arrêt
\0
.
Que fait ton corrigé ?
Plutôt que de maintenir une variable
n, ton programme modifie en place la chaîne de caractère. La "tête de lecture" (à la position
i) est toujours en avance par rapport à la "tête d'écriture" (à la position
j), donc c'est effectivement une bonne manière de faire.
De plus, comme la chaîne à transformer est déjà allouée en mémoire, il n'est pas utile d'allouer un bloc mémoire pour la chaîne transformée. Nous allons maintenant ajouter quelques
printfdans le programme pour voir ce qui se passe. Cependant, comme le montre la section suivante, il va y avoir un peu de travail préalable.
Vu que tu n'as pas forcément encore fait le cours sur les allocations mémoires, et même si je prends le soin de tout expliquer, tu peux l'ignorer dans un premier temps si tu as mal à la tête et aller directement à la section "exécution du programme" :-)
Allocations dynamiques,
const char *, et programme minimal
Cependant il faut savoir que si tu déclare ta chaîne
const char * s = "Bonjour 123 Au revoir";tu ne pourras pas la modifier (à cause du
const). On pourrait se dire, pas de problème je vire le
const. Sauf que c'est une mauvaise idée. En réalité, cette chaîne n'est pas modifiable (elle est stockée dans l'exécutable, pas en mémoire), et donc si tu tentes de la modifier, ton programme plantera à cause d'une erreur de segmentation. Dit autrement, si une chaîne est initialisée en dur dans un programme écrit en C, ce devrait toujours être un
const char *(chaîne non modifiable).
C'est pourquoi dans le code ci-dessous, je prends le soin d'allouer dynamiquement une copie de
chaineavec s. Afin de bien séparer ton problème initial et cet aspect là, je sépare maintenant le code en deux : le
mains'occupe de cette allocation, et la fonction
transformest une réécriture de ton corrigé :
#include <stdio.h> #include <ctype.h> #include <string.h> #include <stdlib.h> void transform(char * s) { int i, j = 0; for(i = 0; s[i] != '\0'; i++) { printf("i = %3d j = %3d s = %s\n", i, j, s); if (isdigit(s[i])) { s[j] = s[i]; j++; } } s[j] = '\0'; } int main(){ const char * chaine = "Bonjour 123Au456 revoir"; char * s = (char *) malloc(strlen(chaine) + 1); if (s == NULL) { fprintf(stderr, "Pas assez de mémoire!"); return 1; } strcpy(s, chaine); transform(s); printf("s = %s\n", s); free(s); return 0; }
Tu noteras que l'allocation mémoire est faite avec
malloc(qui retourne une adresse générique de type
void *), donc c'est pour ça qu'on la convertit (cast) en
char *avec l'opérateur unaire de cast
(char *). Ce bloc doit pouvoir contenir autant de caractère que
chaine, donc la longueur de chaine (qu'on obtient avec la fonction standard
strlen) + 1 (pour le
'\0').
Ensuite, si tu lis la documentation de
malloc, tu verras que cette fonction retourne
NULL. Donc ici, on prend le soin de contrôler que l'allocation a fonctionné, et sinon, on écrit un message d'erreur dans la sortie d'erreur standard, puis on quitte le programme avec un code d'exécution non nul pour signifier que le programme a planté.
Si l'allocation a marché, on recopie
chainedans
sà l'aide de
strcpy, puis on fait la transformation. Ça ne fera pas d'erreur de segmentation car on n'opère pas sur un
const char *.
Qui dit
malloc(si celui-ci a fonctionné) dit
free. Donc, quand on n'a plus besoin du bloc mémoire
s, on le désalloue avec la fonction
free. La librairie C sait exactement quel est la taille de ce bloc puisqu'elle en a gardé trace quand tu as fait le
mallocet c'est pourquoi
freene prend en paramètre que l'adresse du bloc à désallouer.
Exécution du programme
On obtient ceci :
(mando@silk) (~) $ gcc -Wall -g toto.c && ./a.out
i = 0 j = 0 s = Bonjour 123Au456 revoir
i = 1 j = 0 s = Bonjour 123Au456 revoir
i = 2 j = 0 s = Bonjour 123Au456 revoir
i = 3 j = 0 s = Bonjour 123Au456 revoir
i = 4 j = 0 s = Bonjour 123Au456 revoir
i = 5 j = 0 s = Bonjour 123Au456 revoir
i = 6 j = 0 s = Bonjour 123Au456 revoir
i = 7 j = 0 s = Bonjour 123Au456 revoir
i = 8 j = 0 s = Bonjour 123Au456 revoir
i = 9 j = 1 s = 1onjour 123Au456 revoir
i = 10 j = 2 s = 12njour 123Au456 revoir
i = 11 j = 3 s = 123jour 123Au456 revoir
i = 12 j = 3 s = 123jour 123Au456 revoir
i = 13 j = 3 s = 123jour 123Au456 revoir
i = 14 j = 4 s = 1234our 123Au456 revoir
i = 15 j = 5 s = 12345ur 123Au456 revoir
i = 16 j = 6 s = 123456r 123Au456 revoir
i = 17 j = 6 s = 123456r 123Au456 revoir
i = 18 j = 6 s = 123456r 123Au456 revoir
i = 19 j = 6 s = 123456r 123Au456 revoir
i = 20 j = 6 s = 123456r 123Au456 revoir
i = 21 j = 6 s = 123456r 123Au456 revoir
i = 22 j = 6 s = 123456r 123Au456 revoir
s = 123456
Si tu as besoin de plus de clarifications, n'hésite pas.
Bonne chance