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

Tableau de caracteres et pointeurs

25 réponses
Avatar
bpascal123
Bonjour,
J'apprends le C =E0 partir d'un tutorial en ligne. Je n'arrive pas =E0 un
r=E9sultat pour un exercice dont la solution de l'auteur ne fonctionne
pas non plus. Vous pouvez voir sur l'exercice et la solution que je ne
parviens pas =E0 impl=E9menter sur http://www.ltam.lu/cours-c// ... ex.
9.22.

Voici le code qui ne veut pas tourner alors que =E7a me semble coh=E9rent.
J'y ajoute des fonctions car j'ai d=E9j=E0 parcouru le chapitre fonction
et j'essaie de r=E9soudre les questions de l'allocation dynamique avec
les difficult=E9s du chapitre des fonctions...

/*
Ecrire un programme qui lit 4 mots au clavier (longueur maximale: 10
caract=E8res) et attribue leurs adresses =E0 un tableau de pointeurs pMot.
Copier les mots selon l'ordre lexicographique en une seule 'phrase'
dont l'adresse est affect=E9e =E0 un pointeur pPhr. R=E9server l'espace
n=E9cessaire =E0 la PHRASE avant de copier les mots. Lib=E9rer la m=E9moire
occup=E9e par chaque mot apr=E8s l'avoir copi=E9. Utiliser les fonctions de
<string>.
*/

#include <stdio.h> /* printf fgets */
#include <stdlib.h> /* malloc */
#include <string.h> /* strlen strcpy strcmp strcat */

#define MAXLIG 4 /* nbr de ligne max */
#define MAXLET 10 /* nbr de lettre max */

void ReadPhr(char *fpPhr[], int nmax) ;
void WritePhr(char *fpPhr[], int nmax) ;
void WriteMot(char *fpPhr[], char *fpMot, int nmax) ;
void AlphaPhr(char *fpPhr[], int nmax) ;

int main(void)
{
char *pPhr[MAXLIG] ;
char *pMot =3D 0 ;


ReadPhr(pPhr, MAXLIG) ;
WritePhr(pPhr, MAXLIG) ;
AlphaPhr(pPhr, MAXLIG) ;
WriteMot(pPhr, pMot, MAXLIG) ;

printf("\n\n") ;
return 0 ;
}

void ReadPhr(char *fpPhr[], int nmax)
{
char Intro[MAXLET] ;
int i ;

printf("\n\nEntrez des mots, fin avec [enter] : \n") ;

for ( i =3D 0 ; i < nmax ; i++ )
{
printf("\nEntree %d%s : ", i+1, (i =3D=3D 0) ? "ere" : "eme") ;
fgets(Intro, MAXLET, stdin) ;

*(fpPhr+i) =3D malloc( strlen(Intro)+1) ;

if ( *(fpPhr+i ) )
strcpy( *(fpPhr+i), Intro ) ;
else
{
printf("\nAllocation error\n") ;
exit(-1) ;
}
}
}

void WritePhr(char *fpPhr[], int nmax)
{
int i ;

printf("\n\nAFFICHAGE : \n") ;
for ( i =3D 0 ; i < nmax ; i++ )
printf("\n%s", *(fpPhr+i) ) ;
}

void WriteMot(char *fpPhr[], char *fpMot, int nmax)
{
int i ;
int sz =3D 0 ;

for ( i =3D 0 ; i < nmax ; i++ )
sz +=3D strlen( fpPhr[i] ) ;

printf("\nTaille totale : %d", sz) ;
}

void AlphaPhr( char *fpPhr[], int nmax)
{
void AlphaSwap(char *fpPhr[], int var_i, int var_j) ;
int i, j ;
int pm ;

for ( i =3D 0 ; i < nmax-1 ; i++ )
{
pm =3D i ;
for ( j =3D i+1 ; j < nmax ; j++ )
if ( strcmp( *(fpPhr+pm), *(fpPhr+j) ) > 0 )
pm =3D j ;

AlphaSwap(fpPhr, i, pm) ;
}
}

void AlphaSwap(char *fpPhr[], int var_i, int var_j)
{
char *aide ;

aide =3D fpPhr[var_i] ;
fpPhr[var_i] =3D fpPhr[var_j] ;
fpPhr[var_j] =3D aide ;
}

-0-
Comme je ne comprends pa l'algorithme de tri alphab=E9tique de l'auteur
pour cet exercice, j'ai fait appel au tri par selection du maximum...

Merci,
Pascal

10 réponses

1 2 3
Avatar
bpascal123
voici la fonction WriteMot complète en remplacement de celle plus haut
(même complète, ça ne fonctionne pas) :

void WriteMot(char *fpPhr[], char *fpMot, int nmax)
{
int i ;
int sz = nmax ;

for ( i = 0 ; i < nmax ; i++ )
sz += strlen( fpPhr[i] + 1 ) ;

fpMot = malloc(sz) ;

for ( i = 0 ; i < nmax ; i++ )
strcat( fpMot, fpPhr[i] ) ;

for ( i = 0 ; i < nmax ; i++ )
printf("%c", fpMot) ;
}
Avatar
Alexandre Bacquart
On 07/30/2010 01:37 AM, wrote:
voici la fonction WriteMot complète en remplacement de celle plus haut
(même complète, ça ne fonctionne pas) :

void WriteMot(char *fpPhr[], char *fpMot, int nmax)
{
int i ;
int sz = nmax ;

for ( i = 0 ; i< nmax ; i++ )
sz += strlen( fpPhr[i] + 1 ) ;



Réfléchis bien au sujet de cette expression. A quoi s'applique + 1 ? En
fait, tu ajoutes 1 au pointeur du mot i, ce qui aura pour effet de
calculer sa taille à partir de la 2ème lettre (si elle existe !). Tu
obtiendras donc la taille du mot - 1, soit une perte de 4 (nmax)
caractères par rapport à la taille dont tu as besoin. Les concaténations
déborderont de 4 dans fpMot -> comportement indéfini.

Je suppose que ce que tu voulais vraiment faire, c'était rajouter 1 à la
taille à chaque fois, mais pourquoi ? L'énoncé ne demande pas que les
mots soient séparés par quelque-chose (un espace par exemple serait
bienvenu).

Ca serait pas plutôt :

for ( i = 0 ; i< nmax ; i++ )
sz += strlen( fpPhr[i] ) ;

sz++; /* pour le '' */

...que tu veux faire ?


fpMot = malloc(sz) ;

for ( i = 0 ; i< nmax ; i++ )
strcat( fpMot, fpPhr[i] ) ;

for ( i = 0 ; i< nmax ; i++ )



Supprimer cette boucle, elle fait s'afficher la chaîne 4 fois.

printf("%c", fpMot) ;


^
"%s"

Tu devrais déjà avoir un meilleur résultat.

Remarques :

- tes mots contiennent le 'n' de ta saisie avec fgets(), donc les
strcat() les concatènent avec le reste. Ils n'ont aucune incidence sur
le reste du programme, mais lors de l'affichage des mots, il y a un 'n'
supplémentaire. Aussi lors de l'affichage de la phrase finale, elle fait
plusieurs lignes puisque tu concatènes les mots avec leur 'n'
respectifs. Il faut que tu t'arranges pour ne pas récupérer les 'n'.

- MAXLET est censé contenir le nombre de lettres maximum, mais tu
alloues char[MAXLET]. Et le '' de fin ?

- Libérer la mémoire réservée par les différents malloc() au bon moment
(et de la bonne manière).

- Le franglais genre WriteMot(), c'est limite tu trouves pas ? Bien
choisir ses noms de fonctions fait aussi partie du boulot. Si tu as des
problèmes avec l'anglais, alors nomme tes fonctions en français mais ne
mélange pas.

- si tu définis AlphaSwap() au-dessus de AlphaPhr(), tu n'auras plus
besoin de la déclarer avant de l'utiliser.

- *(pt+i) peut être remplaçé par pt[i].


--
Alex
Avatar
-ed-
On 30 juil, 01:31, ""
wrote:
Bonjour,
J'apprends le C à partir d'un tutorial en ligne. Je n'arrive pas à un
résultat pour un exercice dont la solution de l'auteur ne fonctionne
pas non plus. Vous pouvez voir sur l'exercice et la solution que je ne
parviens pas à implémenter surhttp://www.ltam.lu/cours-c// ... ex.
9.22.



Normal, tu n'affiches pas le tableau trié ...

Ceci fonctionne :

/*
Ecrire un programme qui lit 4 mots au clavier (longueur maximale: 10
caractères) et attribue leurs adresses à un tableau de pointeurs pMot.
Copier les mots selon l'ordre lexicographique en une seule 'phrase'
dont l'adresse est affectée à un pointeur pPhr. Réserver l'espace
nécessaire à la PHRASE avant de copier les mots. Libérer la mémoire
occupée par chaque mot après l'avoir copié. Utiliser les fonctions de
<string>.
*/

#include <stdio.h> /* printf fgets */
#include <stdlib.h> /* malloc */
#include <string.h> /* strlen strcpy strcmp strcat */

#define MAXLIG 4 /* nbr de ligne max */

void ReadPhr (char *fpPhr[], int nmax)
{
char Intro[10];
int i;

printf ("nEntrez des mots, fin avec [enter] : n");

for (i = 0; i < nmax; i++)
{
printf ("Entree %d%s : ", i + 1, (i == 0) ? "ere" : "eme");
fgets (Intro, sizeof Intro, stdin);

*(fpPhr + i) = malloc (strlen (Intro) + 1);

if (*(fpPhr + i))
strcpy (*(fpPhr + i), Intro);
else
{
printf ("nAllocation errorn");
exit (-1);
}
}
}

void WritePhr (char *fpPhr[], int nmax)
{
int i;

printf ("nAFFICHAGE : n");
for (i = 0; i < nmax; i++)
{
printf ("%sn", *(fpPhr + i));
}
}

void WriteMot (char *fpPhr[], int nmax)
{
int i;
int sz = 0;

for (i = 0; i < nmax; i++)
{
sz += strlen (fpPhr[i]);
}

printf ("Taille totale : %dn", sz);

}

void AlphaSwap (char *fpPhr[], int var_i, int var_j)
{
char *tmp = fpPhr[var_i];
fpPhr[var_i] = fpPhr[var_j];
fpPhr[var_j] = tmp;

}

void AlphaPhr (char *fpPhr[], int nmax)
{
int i;
for (i = 0; i < nmax - 1; i++)
{
int pm = i;
int j;
for (j = i + 1; j < nmax; j++)
{
if (strcmp (*(fpPhr + pm), *(fpPhr + j)) > 0)
{
pm = j;
}
}

AlphaSwap (fpPhr, i, pm);
}

}

int main (void)
{
char *pPhr[MAXLIG];

ReadPhr (pPhr, MAXLIG);
WritePhr (pPhr, MAXLIG);
AlphaPhr (pPhr, MAXLIG);
WriteMot (pPhr, MAXLIG);
WritePhr (pPhr, MAXLIG);

printf ("nn");
return 0;

}
Avatar
bpascal123
On 30 juil, 08:21, -ed- wrote:
On 30 juil, 01:31, ""

wrote:
> Bonjour,
> J'apprends le C à partir d'un tutorial en ligne. Je n'arrive pas à un
> résultat pour un exercice dont la solution de l'auteur ne fonctionne
> pas non plus. Vous pouvez voir sur l'exercice et la solution que je ne
> parviens pas à implémenter surhttp://www.ltam.lu/cours-c// ... ex .
> 9.22.

Normal, tu n'affiches pas le tableau trié ...

Ceci fonctionne :



...

Ca fonctionne sans afficher les mots saisis sur une et une seule
phrase :
ex.:

entree 1 : bonjourn
entree 2 : monden

resultat :
"bonjour monde"

je n'arrive pas à obtenir le résultat ci-dessus parmi mais je peux
obtenir les autres affichage (affichage trié...).
Avatar
bpascal123
Alex,

J'ai essayé de refaire l'exercice avec les éléments de ta réponse :

"Réfléchis bien au sujet de cette expression. A quoi s'applique +
1 ?..."

En fait dans la série d'exercices, je reprends la solution de
l'auteur...

/* Lecture d'une phrase */
printf("Phrase %d : ",I);
gets(INTRO);

TEXTE[I] = malloc(strlen(INTRO)+1);

C'est vrai que je ne comprends pas bien la présence de +1. C'est peut-
être parce que la solution de l'auteur fait appel à gets.
Je ne connais pas bien gets mais d'après ce que je sais pour fgets,
fgets lit et renvoie 'n', ce qui fait que strlen renvoie le nombre de
lettre + le caractère invisible n.

Maintenant que tu pointes le doigt sur ça, je comprends que ce n'est
pas cohérent et que ça ajoute des espaces mémoires en plus qui
resteront vide. En plus, je recherche plutôt à enlever l'espace
mémoire qui contient n pour que les mots apparaissent sur une même
ligne.

J'ai refais le code à partir des éléments que tu proposes sans succ ès
apparent.

Merci Alex de m'avoir éclairé et de m'éclairer un peu plus si tu n'es
pas en vacance ou si tu as le temps,

Pascal
Avatar
Benoit Izac
Bonjour,

le 31/07/2010 à 22:02, bpascal a écrit dans le message
:

TEXTE[I] = malloc(strlen(INTRO)+1);

C'est vrai que je ne comprends pas bien la présence de +1.



C'est pour pouvoir stocker le 0 final (le délimiteur de chaîne).

Tu veux mettre "bonjour" dans un char * :

+-+ +-+ +-+ +-+ +-+ +-+ +-+ +--+
|b| |o| |n| |j| |o| |u| |r| ||
+-+ +-+ +-+ +-+ +-+ +-+ +-+ +--+
1 2 3 4 5 6 7 8

strlen("bonjour") renvoie 7 mais tu as besoin de 8 emplacements pour
stocker la chaîne.

char *a = malloc(strlen("bonjour") + 1); /* 8 bytes */
strcpy(a, "bonjour");
maintenant (strlen(a) == 7)

Si tu oublies la place pour le 0 final, strcpy va aller mettre un 0 à
un emplacement que tu n'as pas réservé, il peut arriver n'importe quoi.

--
Benoit Izac
Avatar
Alexandre Bacquart
On 07/31/2010 10:02 PM, wrote:
Alex,

J'ai essayé de refaire l'exercice avec les éléments de ta réponse :

"Réfléchis bien au sujet de cette expression. A quoi s'applique +
1 ?..."



Plus précisément, j'ai dis :

void WriteMot(char *fpPhr[], char *fpMot, int nmax)
{
int i ;
int sz = nmax ;



for ( i = 0 ; i< nmax ; i++ )
sz += strlen( fpPhr[i] + 1 ) ;



Réfléchis bien au sujet de cette expression. A quoi s'applique + 1 ?



Dans ce contexte, + 1 s'applique au pointeur que tu récupères dans
fpPhr[i]. Mes explications suivantes n'ayant visiblement pas suffit, on
va prendre un exemple concret.

Supposons que fpPhr[i] pointe sur une chaîne "test".

strlen(fpPhr[i] + 1)

...renverra 3, car ce que tu envoies à strlen(), c'est un pointeur sur
le 'e' de la chaîne "test". A partir de là, il n'y a que 3 caractères.

C'est donc incorrect et je t'ai donné le code qui corrige cette erreur
de logique. (à savoir que le + 1 ici devrait être appliqué à sz après la
boucle : c'est la taille du tampon destination qui contiendra tous les
mots + le '' de fin). Mais j'ai déjà expliqué tout ça.

En fait dans la série d'exercices, je reprends la solution de
l'auteur...

/* Lecture d'une phrase */
printf("Phrase %d : ",I);
gets(INTRO);



Au moyen âge, on l'aurait probablement écartelé pour moins que ça.


TEXTE[I] = malloc(strlen(INTRO)+1);

C'est vrai que je ne comprends pas bien la présence de +1.



Ici, c'est correct (enfin si on part du principe que le pétard de gets()
est mouillé). Il faut que la mémoire allouée pour la chaîne soit de la
longueur de la chaîne + 1 car, comme tu le sais, une chaîne C doit se
terminer par le caractère ''.

Pour information, je n'ai pas jamais cité les excréments que l'auteur a
donné en guise de solution. Seul l'énoncé nous intéresse ici, et je suis
parti de ton code, plus révélateur de ce qui se passe dans ta tête.

C'est peut-être parce que la solution de l'auteur fait appel à gets.



Non, rien à voir. Ce gars est un mauvais programmeur C. L'exercice en
soi n'est pas dénué d'intérêt, mais ce qu'il nomme solution est un gros
bug en puissance prêt à sauter à la tronche du premier Gaston Lagaffe
venu. Même pas besoin de lire ce qu'il y a autour de son gets(), il
suffit grosso-modo de s'endormir sur le clavier quelques secondes pour
trouver le bug au réveil.

Je te propose un marché : tu ne publies plus jamais de lien sur le(s)
site(s) de cet auteur. Avec un peu de chance, lui et son code seront
engloutis dans les bas-fonds des darknets d'ici 40 ans, deviendront une
légende dans 100 ans et un mythe dans 1000 ans. J'ose croire que gets()
aura officiellement disparu de la norme d'ici là ou que C sera devenu
une langue morte. Ca vaut le coup d'essayer. En échange, je t'aide du
mieux que je peux pour ton exercice.

Je ne connais pas bien gets



Super, ça sera d'autant plus facile de l'oublier :)

mais d'après ce que je sais pour fgets,
fgets lit et renvoie 'n', ce qui fait que strlen renvoie le nombre de
lettre + le caractère invisible n.



Oui. A ceci près que fgets() n'écrit le 'n' que s'il a la place, comme
pour n'importe quel autre caractère. Donc tu n'as pas de garantie que ta
chaîne se termine avec 'n'. Plus grave : fgets() laisse sur stdin ce
qu'il n'a pas écrit dans ton tampon.

Maintenant que tu pointes le doigt sur ça, je comprends que ce n'est
pas cohérent et que ça ajoute des espaces mémoires en plus qui
resteront vide.



Pas du tout. Dans le code de l'auteur, c'est justifié. Ce que tu
appelles un <espace vide> est l'espace nécessaire pour stocker le ''
final au cas où la chaîne ferait la taille maximum qu'il s'est fixé.

Dans ton code (et à l'endroit que j'ai cité), c'est une erreur. strlen()
parcourt la chaîne jusqu'à ce qu'il rencontre '' pour déterminer sa
longueur. Si tu lui donnes un pointeur sur une chaîne + 1, tu lui fait
sauter une étape.

En plus, je recherche plutôt à enlever l'espace
mémoire qui contient n pour que les mots apparaissent sur une même
ligne.



Ta question initiale ne portait pas sur les 'n', je te l'ai juste fait
remarquer.

Le problème ici se situe au niveau de fgets() qui n'est pas fait pour de
la saisie utilisateur. Rien en C ne l'est vraiment d'ailleurs... et le
pire, c'est que fgets() peut être bien plus vicieux quand on fait de la
saisie utilisateur à répétition comme tu le fais (à cause des tampons
clavier dont on t'a déjà parlé il y a peu il me semble).

Quand un tutoriel veut faire croire que la saisie utilisateur est facile
à coups de fgets() ou autres scanf(), tu peux être sûr que c'est du
bluff. Donc, autant faire sa propre routine de saisie avec getchar() et
décortiquer le bidule, au moins on apprend des choses. Mais sans ça,
sans une bonne compréhension du phénomène sous-jacent, c'est trop
difficile d'expliquer pourquoi fgets() n'est pas adapté, ni pourquoi
parfois il semble rajouter 'n' et parfois pas (l'as-tu remarqué ?).

Dans ton programme, essaye de saisir un mot de 15 caractères et tu
devrait commencer à y voir un peu plus clair sur le fait que fgets() ne
fait pas, mais alors pas du tout ce que tu attends de lui.

Voici un ReadPhr() plus robuste à cet égard (et qui supprime tes 'n') :

void ReadPhr(char *fpPhr[], int nmax)
{
char Intro[MAXLET+1] ; // une chaîne C de taille maximum MAXLET
int i ;

printf("nnEntrez des mots, fin avec [enter] : n") ;

for ( i = 0 ; i< nmax ; i++ )
{
printf("nEntree %d%s : ", i+1, (i == 0) ? "ere" : "eme") ;

// saisie utilisateur avec fgets()
fgets(Intro, sizeof(Intro), stdin) ;

// on ne veut pas les 'n' de fgets
size_t lenIntro = strlen(Intro);
if (Intro[lenIntro-1] == 'n') // si fgets() a lu le 'n'
Intro[--lenIntro] = ''; // supprime le 'n' et taille - 1
else // sinon
while(fgetc(stdin) != 'n'); // vide stdin jusqu'au 'n' inclus

*(fpPhr+i) = malloc( lenIntro + 1) ;

if ( *(fpPhr+i ) )
strcpy( *(fpPhr+i), Intro ) ;
else
{
printf("nAllocation errorn") ;
exit(-1) ;
}
}
}

Tu pourrais alors faire un readUserString() qui aurait le comportement
auquel tu t'attends (qui n'est évidement pas celui de fgets()), genre :

size_t ReadUserString(char *buf, size_t n)
{
// saisie utilisateur avec fgets()
fgets(buf, n, stdin) ;

// on ne veut pas les 'n' de fgets
size_t lenBuf = strlen(buf);
if (buf[lenBuf-1] == 'n')
buf[--lenBuf] = '';
else
while(fgetc(stdin) != 'n');

return lenBuf;
}

C'est moche de devoir nettoyer les crottes de fgets(), alors autant
l'oublier et faire directement ce qu'on veut avec getchar() (qui
équivaut à fgetc(stdin)) :

size_t ReadUserString(char *buf, size_t bufSize)
{
char c;
size_t i;
size_t limit = bufSize - 1;
for (i=0; (c = getchar()) != 'n'; i++) {
if (i < limit)
buf[i] = c;
else {
while(getchar() != 'n');
break;
}
}
buf[i] = '';
return i;
}

Il te suffit d'appeler ReadUserString() quand tu demandes un mot (ou une
phrase) à l'utilisateur. Les paramètres sont les mêmes que fgets()
(moins le stdin). Avec ça, non seulement tu simplifies ReadPhr() :

void ReadPhr(char *fpPhr[], int nmax)
{
char Intro[MAXLET+1] ;
int i ;

printf("nnEntrez des mots, fin avec [enter] : n") ;

for ( i = 0 ; i< nmax ; i++ )
{
printf("nEntree %d%s : ", i+1, (i == 0) ? "ere" : "eme") ;
size_t lenIntro = ReadUserString(Intro, sizeof(Intro));

*(fpPhr+i) = malloc( lenIntro + 1) ;
if ( *(fpPhr+i ) )
strcpy( *(fpPhr+i), Intro ) ;
else {
printf("nAllocation errorn") ;
exit(-1) ;
}
}
}

...mais tu as aussi un début de fonction ré-utilisable pour la saisie
utilisateur. Pas de 'n'. Si l'utilisateur saisit quelque-chose de trop
long, c'est tronqué comme on pourrait s'y attendre (le reste est ignoré)
et ça te retourne la taille de la chaîne finale en bonus (pas besoin de
strlen()). Ce n'est toujours pas l'idéal, mais c'est déjà plus
prévisible et contrôlable.

Pour conclure, je note qu'il est très révélateur de constater que la
difficulté de l'exercice ne réside pas dans le fait de trier des chaînes
de caractères et de les concaténer (puisque tu en es globalement venu à
bout sans trop de casse, ce qui mérite une médaille à ton niveau), mais
bel et bien dans la mise en place d'une saisie utilisateur correcte (que
tu as bien foiré, ce qui n'est guère étonnant dans un langage aussi
antipathique envers l'idée de saisie utilisateur + tes références en C).


--
Alex
Avatar
bpascal123
Pour conclure, je note qu'il est très révélateur de constater que l a
difficulté de l'exercice ne réside pas dans le fait de trier des cha înes
de caractères et de les concaténer (puisque tu en es globalement venu à
bout sans trop de casse, ce qui mérite une médaille à ton niveau), mais
bel et bien dans la mise en place d'une saisie utilisateur correcte (que
tu as bien foiré, ce qui n'est guère étonnant dans un langage aussi
antipathique envers l'idée de saisie utilisateur + tes références e n C).

--
Alex



Bonjour,

De cet exercice, je n'ai pas réussi la concaténation :(
J'ai pu avoir un aperçu de malloc, comprendre un peu mieux la relation
entre les tableaux de caractères et les pointeurs sur tableaux de
caractères, le passage par valeur et par adresse dans les fonctions.
Je pense pour être honnête avec moi-même que ce sont des bonnes bases
en C mais que je reste "grand débutant".

La saisie utilisateur me pose quelques difficultés. J'ai bien pris
note de l'emploi de getchar(). Je vais reprendre le code et essayer de
m'habituer à la saisie utilisateur avec getchar(). Je me demandais
pourquoi le K&R fait plus mention de getchar() et putchar() que de
fgets, printf, scanf...? J'ai le sentiment que printf, scanf fgets
sont des extra du langage c.

Par ailleurs, je pense m'orienter d'ici peu vers c++. Je ne sais pas
encore quel niveau je dois approcher en C pour être ne pas avoir eu le
sentiment d'avoir perdu du temps. J'espère que ces connaissances
pourront me servir à mieux comprendre les choses par la suite avec
d'autres langages.

Pour en revenir à ce code, je vais essayer de revoir le tout d'après
tes recommandations qui me semblent pleines de sens.

Merci,
Pascal
Avatar
Alexandre Bacquart
On 08/04/2010 10:22 PM, wrote:
Bonjour,

De cet exercice, je n'ai pas réussi la concaténation :(



Ha bon ? Pourtant je suis parti de ton exemple est je ne me souviens pas
avoir eu à changer quoique ce soit dans la partie concaténation.

Ta sortie stdout, par contre, était un peu maladroite (et avec ces 'n'
qui traînaient, c'était pire). Ca a pu t'induire en erreur.

La saisie utilisateur me pose quelques difficultés. J'ai bien pris
note de l'emploi de getchar(). Je vais reprendre le code et essayer de
m'habituer à la saisie utilisateur avec getchar(). Je me demandais
pourquoi le K&R fait plus mention de getchar() et putchar() que de
fgets, printf, scanf...? J'ai le sentiment que printf, scanf fgets
sont des extra du langage c.



Non, c'est plutôt C qui n'est pas extra pour faire de la saisie :(

La fonction que je t'ai donné (ReadUserString) n'est pas parfaite, mais
ça t'évitera des comportements bizarres si tu l'utilise plusieurs fois
de suite.

Par ailleurs, je pense m'orienter d'ici peu vers c++. Je ne sais pas
encore quel niveau je dois approcher en C pour être ne pas avoir eu le
sentiment d'avoir perdu du temps.



Si ton but est de faire du C++, tu perds un temps fou, parce-que la
saisie stdin en C++ sans bug thermonucléaire, ça donne quelque-chose du
genre :

string str;
cin >> str;

Ca donne envie hein ? Et encore, je te parle pas des concaténations de
chaînes...

J'espère que ces connaissances
pourront me servir à mieux comprendre les choses par la suite avec
d'autres langages.



Certaines, peut-être...


--
Alex
Avatar
bpascal123
On Aug 4, 9:00 pm, Alexandre Bacquart wrote:
On 08/04/2010 10:22 PM, wrote:

> Bonjour,

> De cet exercice, je n'ai pas réussi la concaténation :(

Ha bon ? Pourtant je suis parti de ton exemple est je ne me souviens pas
avoir eu à changer quoique ce soit dans la partie concaténation.

Ta sortie stdout, par contre, était un peu maladroite (et avec ces 'n'
qui traînaient, c'était pire). Ca a pu t'induire en erreur.

> La saisie utilisateur me pose quelques difficultés. J'ai bien pris
> note de l'emploi de getchar(). Je vais reprendre le code et essayer de
> m'habituer à la saisie utilisateur avec getchar(). Je me demandais
> pourquoi le K&R fait plus mention de getchar() et putchar() que de
> fgets, printf, scanf...? J'ai le sentiment que printf, scanf fgets
> sont des extra du langage c.

Non, c'est plutôt C qui n'est pas extra pour faire de la saisie :(

La fonction que je t'ai donné (ReadUserString) n'est pas parfaite, mais
ça t'évitera des comportements bizarres si tu l'utilise plusieurs foi s
de suite.

> Par ailleurs, je pense m'orienter d'ici peu vers c++. Je ne sais pas
> encore quel niveau je dois approcher en C pour être ne pas avoir eu l e
> sentiment d'avoir perdu du temps.

Si ton but est de faire du C++, tu perds un temps fou, parce-que la
saisie stdin en C++ sans bug thermonucléaire, ça donne quelque-chose du
genre :

   string str;
   cin >> str;

Ca donne envie hein ? Et encore, je te parle pas des concaténations de
chaînes...

> J'espère que ces connaissances
> pourront me servir à mieux comprendre les choses par la suite avec
> d'autres langages.

Certaines, peut-être...

--
Alex



Bonjour,

J'ai eu un peu de temps pour étudier et mettre en oeuvre le code que
tu as recommandé. Après quelques modifications, ça fonctionne très
bien. J'ai même été surpris que getchar() soit aussi souple. Je peux
concaténer ou non la saisie par la simple affectation de 'n' ou
'' (dans le code dans A:).

Je trouve ce code intéressant simplement parce que getchar() se
comporte comme c'est prévu. Même si ce sont plus que 10 caractères qu i
sont saisis, l'affichage ne prend pas en compte ce qui dépasse de
MAXLET. Je suppose que c'est bien pour la sécurité. Pour dire vrai, je
ne suis pas capable d'explorer les dépassements de buffer à mon
niveau...

Je le publie dans cette discussion au cas ou il y aurait quelque chose
à revoir. Mais je considère m'en inspirer par la suite.

#include <stdio.h> /* printf getchar */
#include <stdlib.h> /* malloc free */
#include <string.h> /* strcpy strcmp */
#include <stddef.h>

#define MAXLIG 4 /* nbr de ligne max. */
#define MAXLET 10 /* nbr de lettres max. */

void ReadPhr(char *fPhr[], int nmax) ;
size_t ReadUserString(char fBuff[], size_t bufsize) ;
void WriteMot(char *fPhr[], int nmax) ;


int main(void)
{
char *pPhr[MAXLIG] ;

ReadPhr(pPhr, MAXLIG) ;
WriteMot(pPhr, MAXLIG) ;

printf("nn") ;
return 0 ;
}

void ReadPhr(char *fPhr[], int nmax)
{
char Intro[MAXLET] ;
int i ;

printf("nnEntrez un ou des mots qui forment une phrase ou non et
n"
"appuyer sur [ENTER]. n") ;

for ( i = 0 ; i < nmax ; i++ )
{
printf("n%d%s phrase : ", i+1, (i == 0) ? "ere":"eme") ;
size_t lenIntro = ReadUserString(Intro, sizeof(Intro) ) ;

*(fPhr+i) = malloc(lenIntro+1) ;
if ( *(fPhr+i) )
strcpy( *(fPhr+i), Intro) ;
else
{
printf("nnAllocation errorn") ;
exit(-1) ;
}
}
}

size_t ReadUserString(char fBuff[], size_t bufsize)
{
char c ;
int i ;
int limit = bufsize - 1 ;

for ( i = 0 ; (c = getchar()) != 'n' ; i++)
if ( i < limit )
fBuff[i] = c ;
else
{
while ( (getchar()) != 'n' )
;
break ;
}
fBuff[i++] = 'n' ; /* A: version 2 : supprimer cette ligne pour
concatener */
fBuff[i] = '' ;

return i ;
}

void WriteMot(char *fPhr[], int nmax)
{
int i ;

printf("nnAffichage : n") ;

for ( i = 0 ; i < MAXLIG ; i++ )
printf("%s", *(fPhr+i)) ; /* B: version 2 : changer "%s" par "%s "
pour ajouter un espace pour la concatenation resultant de la
modification en A */

printf("nn") ;
}


Parmi les questions de cette discussion, je voudrais simplement
comprendre ce que c'est stdin et le buffer. C'est certain que ça
montre mes lacunes en informatique mais je crois que j'aurais toujours
des lacunes le temps que j'ai décidé d'apprendre le langage C. Je ne
sais pas si je retrouverais stdin et buffer avec d'autres langages...

Comment décrire stdin?
Je crois comprendre que c'est l'entrée standard, en mode terminal,
c'est le clavier, je suppose en mode graphique ou fenêtre, c'est la
souris...
Est-ce que stdin est un fichier sur lequel on peut intervenir? Est-ce
que je peux dire, en mode terminal, que stdin est composé des touches
du clavier que j'ai pressées? Je doute de ce que je dis, car je pense
que c'est au niveau matériel. Mais comme la quasi-totalité du matérie l
est un circuit électronique...

Après stdin, c'est le buffer qui prend le relais? Bien qu'on peut
faire des saisies bufferisées et des saisies non bufferisées. La
plupart du temps, les saisies claviers se trouvent dans le buffer?
C'est pourquoi, on peut faire du dépassement de buffer ou je ne sais
pas si c'est lié mais du cold boot pour récupérer des saisies (mot de
passe etc) quand la mémoire est encore chaude et je pense le buffer
encore exploitable?

Ce sont des concepts qui ne doivent pas être simple à expliquer, c'est
pourquoi mes questions sont un peu vagues.


Merci,
Pascal
1 2 3