Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Copie de chaine de caracteres sans succes

33 réponses
Avatar
bpascal123
Bonjour,
Ce code ne fonctionne pas et il me semble pas il y a avoir de
difficult=E9s. Je pense avoir fait une erreur quelque part.
Voici:

#include <stdio.h>

int main(void)
{
char Ch1[40] ;
char Suj[80] ;
char FinSuj[60] ;

int i, j, k ;
int OK ;

printf("\n\nEntrez la chaine Ch1 : ") ;
fgets(Ch1, 40, stdin) ;
printf("\nEntrez la chaine Suj. : ") ;
fgets(Suj, 80, stdin) ;

OK =3D 1 ;

for ( i =3D 0 ; OK && Suj[i] ; i++ )
if ( Suj[i] =3D=3D Ch1[0] )
{
for ( j =3D 1 ; Ch1[j] && (Ch1[j] =3D=3D Suj[i+j] ) ; j++ )
;
if ( Ch1[j] =3D=3D '\0' )
OK =3D 0 ;
}

if (!OK)
{
/* copie de la fin de Suj dans FinSuj */
i-- ;
for ( k =3D 0 ; Suj[i+j+k] ; k++ )
FinSuj[k] =3D Suj[i+j+k] ;
FinSuj[k] =3D '\0' ;
}

printf("\n%s", FinSuj) ;

printf("\n\n");

return 0 ;
}

10 réponses

1 2 3 4
Avatar
-ed-
On 2 déc, 23:04, ""
wrote:
Au sujet des E/S, dans une autre discussion, il m'a été conseillé d e
ne pas inclure 'n' à la fin de printf, ex. : "printf("nBonsoirn") ;



Absurde. Qui a bien pu de dire ça ? Tu es sûr que tu as bien compris
ce qu'on t'a dit ?

car le 'n' de fin est pris en compte dans le buffer pour le fgets
suivant.



Délirant ! Il n'y a aucune interaction entre le 'n' en sortie et le
'n' en entrée !

Par conséquent, je me suis mis à coder avec 'n' en début et
pas en fin : "printf("nBonsoir") ;



C'est mal. Le 'n' doit être placé à la fin de la ligne, car c'est
la ... marque de fin de ligne ! De plus, ça permet à printf() de se
comporter correctement et d'une manière portable (les caractères sont
sortis immédiatement). Sinon, on doit ajouter fflush(stdout) pour que
l'effet soit le même.

http://www.bien-programmer.fr/notes.php#fflush_stdout


et ligne suivante (selon
l'affichage pour plus de clarté) printf("nn") afin d'éviter que le
'n' de printf se répercute sur la prochaine saisie. Peine perdue,
j'avais oublié que la saisie côté utilisateur est également prise en
compte.



encore une fois, le 'n' en sortie n'affecte pas la saisie.

Par contre, et c'est peut être ça qui te trouble, tous les caractères
saisis avec fgets() sont 'échoisés' (echoed). En clair, il sont
reproduits sur l'interface de sortie (ecran, fenêtre de console,
télétype etc.) pour pouvoir savoir ce qu'on saisie et éventuellement,
le corriger, comme sur tout entrée interactive). Donc, quand on valide
la saisie avec la touche [ENTER], on entre un 'n' et celui-ci est
affiché, d'où un saut de ligne après la saisie.

Mais encore une fois, pour cet exercice, il est inutile de perdre du
temps à essayer de saisir du texte correctement (les bonnes méthodes
ont déjà été expliquées 3000 fois fgets(), + fclean(), à foncti on
maison à chercher sur le site du zéro ...). Il suffit de travailler
avec 2 chaines initialisées. Ça suffit amplement pour coder et surtout
tester l'algorithme. De plus, tu aurais du indiquer quel est le
comportement attendu, car nous, on a pas l'énoncé. Le code n'est pas
la doc...


Parmi les réponses, une personne soutient que fflush est
indispensable. Je comprends que cette fonction agit comme on tire sur
une chasse d'eau, évacue tout ce qui se trouve en buffer. Il paraît
que ce n'est pas sans inconvénient.



Voir le lien ci dessus pour le rôle de fflush().

Est-ce que tout simplement : while(getchar() != 'n') ne peut pas
suffire à cette situation?



Aucun rapport avec fflush(stdout). Tu mélanges entrée et sortie...
getchar() concerne stdin...


J'arrête là, j'ai une grippe, certainement h1n1, ca sera la 2ème fo is



Impossible (ou alors, c'est une mutation, donc pas H1N1).
Avatar
-ed-
On 3 déc, 13:30, ""
wrote:
> Peux-tu approfondir cette idée ?

C'est en anglais, ça vient des personnes qui postent fréquemement sur
comp.lang.c ;

You mean getchar rather than the second while.  The trouble with using
fflush(stdin) is that it is not portable.  Some systems provide it as
an extension but even if it is permitted, how can you be sure it does
what you want?



Personne ici n'a parlé d'utiliser fflush (stdin), pour les raison
évoquées dans cet article. Ce n'est pas défini par le langage C et le
comportement est donc indéfini.

Ne pas confondre fflush (stdout) qui force la sortie et qui est
parfaitement défini et portable, avec fflush (stdin) qui n'existe pas
vu du C standard (même si certains systèmes supporte cette extension
pour 'vider le flux stdin'). Effectivement, l'alternative portable (et
donc recommandée) est d'utiliser correctement getchar(), par exemple
(la fameuse fonction 'maison' ou 'communautaire' fclean() évoquée plus
haut).
Avatar
bpascal123
Bonjour

Cette question très simple est peut-être à vos yeux loin d'être
compliquée.
Je suis aussi en convalescence de grippe, ça devait pas être h1n1 mais
une grippe reste fatiguante...

En fait, personne n'a évoqué l'emploi de scanf et avec scanf j'obtiens
le bon résultat ???

Merci,
Pascal
Avatar
Alexandre Bacquart
wrote:
En fait, personne n'a évoqué l'emploi de scanf et avec scanf j'obtiens
le bon résultat ???



L'ennui avec scanf, c'est qu'au début, on trouve toujours ça vachement
pratique et on se demande pourquoi personne n'en avait parlé avant.

Dans les faits, un programmeur C expérimenté l'évoque rarement pour
faire de la saisie, voire pas du tout (à part le K&R mais bon, ce
bouquin n'est pas un programmeur C expérimenté). C'est toujours le
débutant qui débarque avec...

Je te conseille vivement de fuir scanf() comme la peste (surtout que
t'as pas encore entamé les pointeurs), même si ça semble marcher pour
l'instant. Pour faire court, scanf() est le pendant de printf() et n'a
un comportement acceptable qu'avec des sorties de printf() redirigées
sur scanf() (par exemple, la sortie stdout d'un programme vers l'entrée
stdin d'un autre). Dans ce cas, c'est pratique, car on peut avoir les
mêmes arguments pour les deux, chaînes de format compris. C'est un peu
comme une interface machine-machine quoi... mais coté saisie
utilisateur, si tu tiens à tes cheveux, fuis !

Si tu n'es pas convaincu, alors ceci devrait t'aider le jour où tu auras
un pépin avec cette horreur :

http://xrenault.developpez.com/tutoriels/c/scanf/


--
Alex
Avatar
espie
In article <4b1d6d7c$0$13113$,
Alexandre Bacquart wrote:
wrote:
En fait, personne n'a évoqué l'emploi de scanf et avec scanf j'obtiens
le bon résultat ???





L'ennui avec scanf, c'est qu'au début, on trouve toujours ça vachement
pratique et on se demande pourquoi personne n'en avait parlé avant.



Dans les faits, un programmeur C expérimenté l'évoque rarement pour
faire de la saisie, voire pas du tout (à part le K&R mais bon, ce
bouquin n'est pas un programmeur C expérimenté). C'est toujours le
débutant qui débarque avec...



Je te conseille vivement de fuir scanf() comme la peste (surtout que
t'as pas encore entamé les pointeurs), même si ça semble marcher pour
l'instant. Pour faire court, scanf() est le pendant de printf() et n'a
un comportement acceptable qu'avec des sorties de printf() redirigées
sur scanf() (par exemple, la sortie stdout d'un programme vers l'entrée
stdin d'un autre). Dans ce cas, c'est pratique, car on peut avoir les
mêmes arguments pour les deux, chaînes de format compris. C'est un peu
comme une interface machine-machine quoi... mais coté saisie
utilisateur, si tu tiens à tes cheveux, fuis !



Si tu n'es pas convaincu, alors ceci devrait t'aider le jour où tu auras
un pépin avec cette horreur :



http://xrenault.developpez.com/tutoriels/c/scanf/



Pour en remettre une couche dans le meme sens.

Je trouve que le plus souvent, l'apprentissage de scanf est une perte
de temps. A part au tout debut, pour permettre aux gens de rentrer des
nombres dans leurs programmes, des qu'on veut faire des trucs un peu
compliques, les particularites de scanf sont complexes a retenir pour
des resultats somme toutes peu interessants. Cote valeurs numeriques, je
joue le plus souvent avec strtod ou strtoul. Et cote chaines, soit ca se
fait a la main, soit j'aurai tres vite besoin d'un vrai moteur de regexps,
ou d'un bon vieux lex/yacc des familles.
Avatar
bpascal123
Bjr/sr ;

Suite à un autre post que j'ai intitulé "bricolage pour blabla", au
sujet de cette discussion, je pense avoir trouvé une solution
temporaire mais qui en tant que débutant me satisfait. Dans le sens ou
je n'ai pas besoin d'aller chercher des fonctions getchar() et fflush
stdin.

Voilà donc le code que je poste ici aussi surtout pour mémoire (pour
le retrouver sur usenet, c'est plus facile que sur mon dd) à moins
qu'une personne avec expérience me déconseille fortement de prendre
l'habitude de ce genre de bricolage. Mais je le répète, dès que je
progresse et trouve quelque chose plus complet, j'apprendrais alors à
m'en servir. En attendant, je fais avec les moyens du bord.


/*
*Ecrire un programme qui supprime la première occurrence
*d'une chaîne de caractères OBJ dans une chaîne de caractères SUJ.
*
*/

#include <stdio.h>

int main(void)
{
char Suj[50] ;
char Obj[30] ;
int i, j ;
int OK ;
int cnt1, cnt2 ;

printf("nnEntrez une chaine de caractere Suj : ") ;
fgets(Suj, 50, stdin) ;

printf("nEntrez une chaine de caractere Obj : ") ;
fgets(Obj, 30, stdin) ;


/* Manip pour enlever 'n' si par exemple j
on entre pour sujet "bonjour" et pour obj "bon"
ds ce cas ca ne marche (en l'absence des 2
boucles qui suivent) pas alors que si on entre
"bon" au lieu de "jour" ça fonctionne...
*/

for ( i = 0 ; Suj[i] ; i++)
;
i = i - 1 ;
Suj[i] = '' ;

for ( i = 0 ; Obj[i] ; i++ )
;
i-- ;
Obj[i] = '' ;

OK = 0 ;
for ( i = 0 ; Suj[i] && !OK ; i++ )
if ( Suj[i] == Obj[0] )
{
for ( j = 1 ; Obj[j] && Suj[i+j] ; j++ )
;
if ( Obj[j] == '' )
OK = 1 ;
}

if ( OK )
{
i-- ;
for ( ; Suj[i+j] ; i++ )
Suj[i] = Suj[i+j] ;
Suj[i] = '' ;
}

printf("nNvelle chaine : %s", Suj) ;

printf("nn") ;

return 0 ;

}

Pascal
Avatar
bpascal123
On Dec 2, 12:14 pm, Richard Delorme wrote:
Le 01/12/2009 17:56, a écrit :

> J'avoue passer beaucoup de temps sur ce code mais d'un point de vu
> implémentation d'un algorithme basique je le trouve intéressant pou r
> me pencher dessus.

> Donc quand j'exécute le code avec par exemple : Ch1 = jour ... Ch2 =
> bonjour ... ça fonctionne, le "trouve!" de la condition if s'affiche.
> Cependant quand j'exécute avec Ch1 = bon ... Ch2 = bonjour  ... rien
> ne s'affiche

[...]
 >   printf("nnEntrez la chaine a rech. Ch1 : ") ;
 >   fgets(Ch1, 40, stdin) ;
 >   printf("nEntrez la chaine Sujet. : ") ;
 >   fgets(Suj, 80, stdin) ;

Dans le premier cas, tu compares "journ" et "bonjourn", dans le second
"bonn", et "bonjourn". C'est le caractère 'n' qui empêche la secon de
comparaison de fonctionner.

--
Richard



Ta réponse simple et concise m'a beaucoup donné à réfléchir et ai dé à
trouver une réponse à mon problème peut-être temporaire mais qui me
convient en tant que débutant.
Merci
Avatar
-ed-
On 16 déc, 03:16, ""
wrote:
        printf("nnEntrez une chaine de caractere Suj : ") ;
        fgets(Suj, 50, stdin) ;

        printf("nEntrez une chaine de caractere Obj : ") ;
        fgets(Obj, 30, stdin) ;

        /* Manip pour enlever 'n' si par exemple j
        on entre pour sujet "bonjour" et pour obj "bon"
        ds ce cas ca ne marche  (en l'absence des 2
        boucles qui suivent) pas alors que si on entre
        "bon" au lieu de "jour" ça fonctionne...
        */

        for ( i = 0  ;  Suj[i]  ;  i++)
                ;
        i = i - 1 ;
        Suj[i] = '' ;

        for ( i = 0  ;  Obj[i]  ;  i++ )
                ;
        i-- ;
        Obj[i] = '' ;



Tu es désespérant. J'ai déjà donné (dans l'autre post) la maniè re
correcte de faire ce travail, et tu continues ton bricolage infâme...
Je ne sais plus quoi faire pour t'aider si tu ne tiens pas compte des
conseils qui te feront progresser, et pas rester dans ta condition
d'éternel débutant...
Avatar
Samuel Devulder
a écrit :

/* Manip pour enlever 'n' si par exemple j
on entre pour sujet "bonjour" et pour obj "bon"
ds ce cas ca ne marche (en l'absence des 2
boucles qui suivent) pas alors que si on entre
"bon" au lieu de "jour" ça fonctionne...
*/

for ( i = 0 ; Suj[i] ; i++)
;
i = i - 1 ;
Suj[i] = '' ;



Tu fais des choses implicitement. Tu supposes que ta chaîne se termine
en 'n'... C'est pas bon. Si tu veux faire un truc précis, alors écris
quelque chose de précis.

Dans la cas présent tu ne veut faire qu'une chose: couper ta chaîne au
1er 'n' rencontré. Dans ce cas, explicitement il te faut un test sur
'n' quelque part. Si tu ne compares rien à 'n' ton code fera autre
chose que tu crois si ce que tu suppose ne se produit pas.

L'avantage d'écrire dans le code ce que tu veux faire plutôt que de
l'écrire dans le commentaire, c'est que tu coup le commentaire est quasi
inutile et ton code assez facilement débuggable sans se prendre la tête
à se demander comment on passe du commentaire au code. Il faut garder
les choses simples simple (c'est la méthode KISS, Keep It Simple,
Stupid).

Dans certain langage on considère qu'un beau code se passe de
commentaire et se lit naturellement comme un texte. Les smalltalkistes
me comprendrons, les autres pardonnez mon abus, mais il y a de l'idée:
si tu a l'intention de virer le 'n', alors fait un code qui vire le
'n' et pas un code qui vire l'avant dernier caractère de la chaîne
accompagné d'un commentaire disant que tu fais cela pour virer le 'n'
final, ce qui est juste faux si justement la chaîne ne se termine pas
sur un 'n'.

Ca donnerait le code suivant qui je trouve est beaucoup plus clair et
n'a pas besoin d'un commentaire expliquant une manip de sioux pour un
truc finalement très simple:


for(i=0; Suj[i]!='' && Suj[i]!='n';) ++i;
Suj[i] = '';

Note: si la chaine ne contient pas de 'n', on écrit '' là ou il y en
a déjà un. C'est pas grave! En l'occurence le mieux est l'ennemi du
bien: si au lieu de Suj[i] = '' on avait écrit:

if(Suj[i] != '') Suj[i] = '';

On aurait inutilement alourdit le code sans changer son fonctionnement.
Toujours méthode KISS: pourquoi faire compliqué quand le truc simple
marche! Les bugs sont plus facilement visible sur un code simple qu'un
code compliqué.

Une autre possibilité est de faire un if dans la boucle for:
for(i=0; Suj[i]; ++i)
if(Suj[i]=='n') {Suj[i] = ''; break;}

Si on aime pas le break, alors on peut être plus royaliste que le roi:
for(i=0; Suj[i];)
if(Suj[i]=='n') Suj[i] = ''; else ++i;

En utilisant le fait que puisqu'on vient d'ecrire '' sur Suj[i], alors
on sortira forcément de la boucle si on incrémente pas i. D'où passage
du "++i" dans la partie "else".

Mais bon vu qu'on fait du C, le royaume du pointeur, l'écriture qui me
semble la plus naturelle pour faire ce que tu veux faire est celle-ci:

// on couple Suj au 1er 'n':
{char *s = Suj; while(*s && *s!='n') ++s; *s = 0;}

C'est petit (1 ligne), précis (ca fait exactement ce qu'on veut),
localisé (pas d'index déclaré super loin et utilisé à deux endroit du
code: ici le pointeur s sert uniquement au découpage et n'est pas
visible ailleurs) et extensible (si on veut couper au 1er 'r' ou ' ' ce
coup ci).

Parfois c'est bien d'utiliser les tableaux surtout si on doit jouer avec
des i+1/i+2/i-1/i+j-1/etc, mais ici comme one ne fait qu'utiliser Suj[i]
ou Suj[j], je pense que les pointeurs sont plus indiqués. Mais c'est
purement une question de goût.

Note: J'aime pas Suj[i] on dirait du pascal.. beurk. Si on veut faire du
C sans pointeur autant franchement apprendre un autre langage. Le gars
qui se présente à moi en prétendant faire du C sans savoir manipuler et
utiliser les pointeurs il ne va pas faire illusion longtemps.

Au final l'idée en utilisant les pointeur est aussi d'alléger le code de
sorte à ce qu'il soit petit (en tout cas pas inutilement long: on est
pas payé à la ligne), précis (il fait *exactement* ce qu'on veut, et
localisé (il ne faut pas être envahissant, c'est plus simple pour
réorganiser le code par la suite).

Ensuite si tu t'aperçois que tu as deux codes similaires qui font la
même chose (l'un sur Suj et l'autre sur Obj), et bien c'est signe qu'il
te faut une procédure ou une fonction. Dans un code élégant, on ne
répète jamais deux fois le même traitement. On utilise une
fonction/procédure à la place!

Bon j'espère que ces quelques conseils te seront utile.

sam.
Avatar
Marc Boyer
Le 16-12-2009, Samuel Devulder a écrit :

Note: J'aime pas Suj[i] on dirait du pascal.. beurk. Si on veut faire du
C sans pointeur autant franchement apprendre un autre langage. Le gars
qui se présente à moi en prétendant faire du C sans savoir manipuler et
utiliser les pointeurs il ne va pas faire illusion longtemps.



On peut connaitre les pointeurs et vouloir que la syntaxe corresponde
à la sémantique et pas à la tambouille.
T'ecris *(i+Suj) ?
Personnellement, j'écris toujours
f(int[])
quand la sémantique est celle d'un tableau et
f(int*)
quand c'est un pointeur sur un int isolé.

Pareil, j'utilise NULL pour initialiser mes pointeurs,
et '' pour mes fins de chaine de caractères, alors que
0 irait aussi bien.

Marc Boyer
--
En prenant aux 10% des francais les plus riches 12% de leurs revenus,
on pourrait doubler les revenus des 10% les plus pauvres.
http://www.inegalites.fr/spip.php?article1&id_mot0
1 2 3 4