Pour sceller notre série sur les chaînes de caractère, je souhaite créer une fonction qui cherche toutes les lettres c dans un mot pour les remplacer par une lettre r.
Alors, je vous montre ce que j'ai fait:
Production:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * cherche_remplace (char c, char r, char * mot, char *newMot);
int main()
{
char mot[] = "la princesse sheherazade", lettreCherchee = 'e', lettreRemplacee = 'i', *newMot;
cherche_remplace(lettreCherchee, lettreRemplacee, mot, newMot);
printf("Si on remplace la lettre %c par la lettre %c dans le mot %s alors le nouveau mot est %s\n", lettreCherchee, lettreRemplacee, mot, newMot);
return 0;
}
char * cherche_remplace (char c, char r, char * mot, char *newMot)
{
int i;
for(i=0; i<strlen(mot); i++)
{
if(mot[i] == c)
{
newMot[i] = r;
}
else
{
newMot[i] = mot[i];
}
}
newMot[strlen(mot)] = '\0';
return *newMot;
}
Le programme fonctionne mais j'ai peur qu'il soit mal écrit.
Pour la ligne 35, je suis pas sûr que j'ai le droit d'écrire strlent(mot) entre crochets.
Mais le plus important- et je ne vous l'ai pas dit- c'est que c'est un exercice académique qui impose le prototype suivant que je n'ai pas respecté:
Je n'ai jamais réussi à faire une fonction *char qui renvoit un *char. Même sur ma fonction "miroir", j'ai ajouté un paramètre pour modifier le mot de départ.
C'est donc tout l'intérêt de l'exercice que je propose: faire une fonction *char qui prend en paramètre un mot[], qui le modifie et le renvoit.
Le programme fonctionne mais j'ai peur qu'il soit mal écrit.
Pas chez moi ! (une fois de plus). Tu as de la chance, car ton pointeur newMot n'est pas initialisé et tu tentes d'écrire à l'adresse où il pointe, c'est à dire n'importe où dans la mémoire. C'est le plantage assuré à un moment où un autre.
Le programme fonctionne mais j'ai peur qu'il soit mal écrit.
Pas chez moi ! (une fois de plus). Tu as de la chance, car ton pointeur newMot n'est pas initialisé et tu tentes d'écrire à l'adresse où il pointe, c'est à dire n'importe où dans la mémoire. C'est le plantage assuré à un moment où un autre.
Très juste! Je viens de modifier.
Correction:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * cherche_remplace (char c, char r, char * mot, char *newMot);
int main()
{
char mot[] = "la princesse sheherazade", lettreCherchee = 'e', lettreRemplacee = 'i', newMot[50] = {0};
cherche_remplace(lettreCherchee, lettreRemplacee, mot, newMot);
printf("Si on remplace la lettre %c par la lettre %c dans le mot %s alors le nouveau mot est %s\n", lettreCherchee, lettreRemplacee, mot, newMot);
printf("%d", newMot[29]); // je voulais juste tester l'initialisation. J'hésitais à écrire newMot[] = "" pour la déclaration du tableau de char newMot
return 0;
}
char * cherche_remplace (char c, char r, char * mot, char *newMot)
{
int i;
for(i=0; i<strlen(mot); i++)
{
if(mot[i] == c)
{
newMot[i] = r;
}
else
{
newMot[i] = mot[i];
}
}
newMot[strlen(mot)] = '\0';
return *newMot;
}
Résultat:
Si on remplace la lettre e par la lettre i dans le mot la princesse sheherazade alors le nouveau mot est la princissi shihirazadi
0
Process returned 0 (0x0) execution time : 1.522 s
Press any key to continue.
magma a écrit:
et ligne 37 ta fonction retourne un char et non un char *
Si, regarde bien ligne 37 du premier code source que j'ai envoyé.
Sauf erreur de ma part, il y a bien écrit: "return *newMot;"
quel est le type de `*newmot` ? quel est le type de la valeur que la fonction doit renvoyer ?
que dit le compilo :
ocr.c:37:13: warning: returning ‘char’ from a function with return type ‘char *’ makes pointer from integer without a cast [-Wint-conversion]
37 | return *newMot;
| ^~~~~~~
'newMot' est de type 'char *' : pointeur de caractères. Souvent, 'newMot' est une chaîne de caractères (à condition de finir par '\0').
'*newMot' est de type 'char'. En fait, il faut savoir que newMot[i] est la même chose que *(newMot + i). En particulier newMot[0] est la même chose que *newMot (et vice versa).
Bref :
return newMot; // retourne une chaîne de caractères
return *newMot; // retourne un caractère (le 1er de la chaîne)
return newMot; // retourne une chaîne de caractères
Plus précisément, retourne l'adresse d'un char. Qui ce trouve être ici l'adresse du premier char du tableau de char newMot qui est utilisé comme chaîne de caractère.
L'exercice imposé suppose l'utilisation de malloc ou des tableaux statiques que tu n'as sans doute pas vus. Tant que ton nouveau mot sera assez long, il n'y aura pas de problème.
Le Tout est souvent plus grand que la somme de ses parties.
'newMot' est de type 'char *' : pointeur de caractères. Souvent, 'newMot' est une chaîne de caractères (à condition de finir par '\0').
'*newMot' est de type 'char'. En fait, il faut savoir que newMot[i] est la même chose que *(newMot + i). En particulier newMot[0] est la même chose que *newMot (et vice versa).
D'accord donc si je fais :
return *Newmot;
la fonction renverra uniquement le premier caractère de la chaîne newMot à savoir 'l' dans mon exemple, c'est bien ça ?
En revanche, si je fais:
return newMot;
Que renverra la fonction ?
Est-ce que ma fonction renverra tous les caractères de la chaîne newMot c'est à dire de newMot[0] jusqu'à newMot[strlen(Mot)-1] ?
Si non, y a-t-il un moyen de renvoyer tous les caractères d'une chaîne ?
'newMot' est de type 'char *' : pointeur de caractères. Souvent, 'newMot' est une chaîne de caractères (à condition de finir par '\0').
'*newMot' est de type 'char'. En fait, il faut savoir que newMot[i] est la même chose que *(newMot + i). En particulier newMot[0] est la même chose que *newMot (et vice versa).
D'accord donc si je fais :
return *Newmot;
la fonction renverra uniquement le premier caractère de la chaîne newMot à savoir 'l' dans mon exemple, c'est bien ça ? --> oui
En revanche, si je fais:
return newMot;
Que renverra la fonction ? --> l'adresse du 1er caractère de newMot
Est-ce que ma fonction renverra tous les caractères de la chaîne newMot c'est à dire de newMot[0] jusqu'à newMot[strlen(Mot)-1] ?
Si non, y a-t-il un moyen de renvoyer tous les caractères d'une chaîne ? --> non - voir la réponse précédente pour la solution
C'est la question la plus importante pour moi
- Edité par edgarjacobs 18 octobre 2021 à 17:58:36
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
la fonction renverra uniquement le premier caractère de la chaîne newMot à savoir 'l' dans mon exemple, c'est bien ça ?
Oui !
RiadOuhibi a écrit:
Est-ce que ma fonction renverra tous les caractères de la chaîne newMot c'est à dire de newMot[0] jusqu'à newMot[strlen(Mot)-1] ?
Si non, y a-t-il un moyen de renvoyer tous les caractères d'une chaîne ?
Non ! Ça renvoi seulement l'adresse du premier caractère du tableau de char newMot.
Il n'est pas possible de renvoyer un tableau en C et par conséquent une chaîne de caractère. (sauf si le tableau est dans une structure. mais ça c'est pour plus tard).
On peut le faire si la chaîne d'entrée est modifiable et si on retourne son adresse de départ: - #include <stdio.h> char *cherche_remplace(char c, char r, char *s) { char *t=s; // je sauve l'adresse de départ while(*s) { if(*s==c) *s=r; s++; } return t; // le début de la chaîne d'entrée } int main(void) { char ami[] = "camarade"; // ne marche pas si je fais char *ami = "camarade"; char *bad = cherche_remplace('a', 'i', ami); printf("'%s'\n", bad); return 0; }
Le Tout est souvent plus grand que la somme de ses parties.
Oui, j'ai fait un abus de langage en parlant de renvoyer la chaîne...
Je pense que tu ne devrais pas chercher à renvoyer une chaîne de caractères (abus de langage : l'adresse d'une chaîne de caractères). Tu sais faire les choses avec deux paramètres : la chaîne d'origine et la nouvelle chaîne. Eh bien c'est ainsi que procèdent pas mal de fonctions de <string.h>.
Par exemple 'strcpy' s'utilise en général (dans le cadre d'un apprentissage au C) de la façon suivante :
strcpy(copie, chaine); // et non copie = strcpy(chaine);
Pareil pour 'strcat' ;
strcat(ch_totale, ss_chaine); // et non ch_totale = strcat(ss_chaine);
c'est toi seul qui décide, en fonction de l'utilisation qui sera faite, de tes propres besoins. Tu peux décider de l'ordre que tu veux pour tes paramètres, tu peux décider de mettre ce que tu veux en paramètre …
Par exemple si tu suis ce qui se retrouve souvent dans la bibliothèque standard tu aurais plutôt un :
Apparamment, on t'a imposé un prototype. Mais est-ce qu'on t'a imposé une façon de procéder? Par exemple, est-ce que le remplacement doit se faire sur place ou dans un autre tableau? Est-ce qu'on t'a dit à quoi pourrait ou devrait servir le pointeur que tu retournes?
Le Tout est souvent plus grand que la somme de ses parties.
Apparamment, on t'a imposé un prototype. Mais est-ce qu'on t'a imposé une façon de procéder? Par exemple, est-ce que le remplacement doit se faire sur place ou dans un autre tableau? Est-ce qu'on t'a dit à quoi pourrait ou devrait servir le pointeur que tu retournes?
Alors, je vais copier/coller l'énoncé comme ça on parlera tous de la même chose:
Chercher/Remplacer
Écrivez une fonction qui recherche dans une chaîne chaque caractère c pour le remplacer par un
Pourquoi utiliser strcpy si tu écris à nouveau dans newMot ?
J'utilise la fonction"strcpy"afin de copier le caractère"\0"dans"newMot". Ca m'évite d'écrire des bêtises comme:newMot[strlen(mot)] = '\0
edgarjacobs a écrit:
RiadOuhibi a écrit:
(....) Qu'en pensez-vous ?
Que tu devrais respecter la consigne. Qu'est ce qui dit que le mot (ou la phrase) ne dépassera pas 49 caractères (taille donnée à newMot) ???? -----> le programme n'est pas destiné à une utilisation professionnel. C'est juste pour moi. En écrivant "abracadabra" ou "la princesse sheherazade", je savais que je n'allais pas avoir besoin de 49 caractères.
Et aussi, choisir: anglais ou français: nouveauMot ou newMot -----> Oui tu as raison.
Disons qu'il n'est pas classique et, comme l'ont noté d'autres participants, bourrés d'imperfections.
Par exemple tu dis que «newMot[strlen(mot)] = '\0'» est une bêtise, mais en fait non. En fait ce qui aurait été plus simple à faire avec ton code est :
for(i=0; i<=strlen(mot); i++) {
...
}
Ce simple changement de < en <= fait que le dernier élément du tableau est pris en compte par ta copie, rendant ton strcpy désormais totalement inutile. Le char '\0' est un char comme un autre que tu peux manipuler … et comme ce n'est pas la lettre cherchée (à moins d'être un peu sado) ce \0 se fera allègrement copier.
Ton code est brouillon et c'est normal car tu es un débutant. Te montrer des codes différents te permettra sans doute d'avoir une autre vision du code C.
Sinon, tu aurais dû suivre le lien de mon message pour contempler l'exécution d'un code (corrigé par rapport à l'extrait donné) pour que tu comprennes ce qui se passe et quand ça se passe.C'est toujours bien de cliquer sur les liens en bleu …
en renvoyant un pointeur sur une nouvelle chaîne allouée par la fonction.
Cela donne ceci, avec un do / while inspiré du code de WhiteCrow, avec en prime des tests unitaires :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
char * cherche_remplace(char c, char r, char * s) {
if (*s == '\0')
return NULL;
char * newstr = malloc(strlen(s) + 1);
if (newstr) {
char * p = newstr;
do {
if (*s == c)
*p++ = r;
else
*p++ = *s;
} while (*s++);
}
return newstr;
}
int main(void) {
char * str;
char * newstr;
char * expectedstr;
/* test empty string */
str = "";
newstr = cherche_remplace('a', 'u', str);
assert(newstr == NULL
&& "test empty string");
free(newstr);
/* test chaîne sans remplacement */
str = "saperlipopette";
expectedstr = "saperlipopette";
newstr = cherche_remplace('u', 'i', str);
assert(strcmp(newstr, expectedstr) == 0
&& "test chaîne sans remplacement");
free(newstr);
/* test abracadabra */
str = "abracadabra";
expectedstr = "ubrucudubru";
newstr = cherche_remplace('a', 'u', str);
assert(strcmp(newstr, expectedstr) == 0
&& "test abracadabra");
free(newstr);
/* test la princesse */
str = "la princesse sheherazade";
expectedstr = "la princissi shihirazadi";
newstr = cherche_remplace('e', 'i', str);
assert(strcmp(newstr, expectedstr) == 0
&& "test la princesse");
free(newstr);
/* tous les tests passent */
printf("tous les tests passent\n");
return 0;
}
On pourrait aussi décider que si la chaîne est vide, on ne renvoie pas un pointeur NULL, mais une autre chaîne vide. A ce moment là le premier test doit tester un comportement identique au 2ème, et les lignes 7 et 8 de la fonction devront être retirées pour que le test passe.
Edit:
Correction de code, la chaîne est terminée dans la boucle do / while
C'est une mauvaise façon de faire pour parcourir une chaîne
A la place, si on tient absolument à utiliser strlen() :
size_t taille = strlen(mot);
for (size_t mot = 0; i <= taille_mot; i++) {
....
}
Pourquoi ? Parce que
le calcul de strlen(mot) se fait en parcourant le mot.
c'est un calcul qui prend un temps proportionnel à la taille du mot
si on le met dans la condition du for(;;) il sera refait à chaque tour, et il nous coûtera un temps proportionnel au carré de la taille. Chaine de taille 1000 => des millions d'opérations.
Rremède : comme c'est une valeur qui ne changera pas au cours de l'exécution de la boucle, normalement (*); on calcule la valeur et on la met dans une variable (caching) avant la boucle. Comme ça c'est fait.
Variante
for (size_t i = 0, taille = strlen(mot); i <= taille; i++) {
....
}
(parce qu'on peut déclarer plusieurs variables en début de for).
(*) sauf si on appelle la fonction en disant de remplacer tel caractère par le caractère nul, ce qui aura pour effet de changer la taille de la chaine, qui s'arrête au premier caractère nul rencontré. Par conséquent, comme ça peut arriver que le caractère de remplacement soit nul, le compilateur ne peut pas décider qu'il va extraire le calcul de strlen() pour optimiser. Ceci dit au cas où me suspecterait de chipoter et de me lancer à micro-optimiser alors que le compilateur sait mieux faire que moi.
Dans le cas fâcheux du caractère nul, il faudrait spécifier plus exactement ce qu'on veut faire : s'arrêter au premier caractère remplacé par nul, ou le faire pour tous ceux qui suivent, qui seront pourtant inaccessibles dans la nouvelle chaîne.
Exemple, en remplacant 'r' par '\0' dans "abracadabra", est-ce que on veut "ab\0cadabra" ou "ab\0cadab\0a" ? Faut choisir ce qu'on veut, camarade.
Ou alors indiquer que le caractère de remplacement n'est pas censé être nul. Hop, notre fonction a un comportement non spécifié dans ce cas, c'est cool, c'est parfaitement assorti avec le langage C.
- Edité par michelbillaud 26 octobre 2021 à 8:31:23
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Plus précisément, retourne l'adresse d'un char. Qui ce trouve être ici l'adresse du premier char du tableau de char newMot qui est utilisé comme chaîne de caractère.
Le Tout est souvent plus grand que la somme de ses parties.
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.