In 'fr.comp.lang.c', Eddahbi Karim
wrote:
In 'fr.comp.lang.c', Eddahbi Karim
<non.tu.ne.me.connais.pas.spavrai@Ifrance.paspam.com> wrote:
In 'fr.comp.lang.c', Eddahbi Karim
wrote:
Bonjour, Bonsoir,
Voilà je continue les exercices de mon bouquin de C.
J'en suis au chapitre concernant les structures et ils demandent de créer
une structure contenant le temps et la date. (Puis de calculer l'espace
entre deux temps en minutes).
Ma question est :
Est-il mieux de demander à l'utilisateur de rentrer la date comme ceci :
- mm/jj/aaaa
Puis de prendre les valeurs mm et jj, avec un srtoi (C99) ou un strtod
(Ansi) quit à caster en int après, et de les vérifier. Ou
Bonjour, Bonsoir,
Voilà je continue les exercices de mon bouquin de C.
J'en suis au chapitre concernant les structures et ils demandent de créer
une structure contenant le temps et la date. (Puis de calculer l'espace
entre deux temps en minutes).
Ma question est :
Est-il mieux de demander à l'utilisateur de rentrer la date comme ceci :
- mm/jj/aaaa
Puis de prendre les valeurs mm et jj, avec un srtoi (C99) ou un strtod
(Ansi) quit à caster en int après, et de les vérifier. Ou
Bonjour, Bonsoir,
Voilà je continue les exercices de mon bouquin de C.
J'en suis au chapitre concernant les structures et ils demandent de créer
une structure contenant le temps et la date. (Puis de calculer l'espace
entre deux temps en minutes).
Ma question est :
Est-il mieux de demander à l'utilisateur de rentrer la date comme ceci :
- mm/jj/aaaa
Puis de prendre les valeurs mm et jj, avec un srtoi (C99) ou un strtod
(Ansi) quit à caster en int après, et de les vérifier. Ou
c'est pas pour faire mon enculeur de mouches, mais des fois il y a
"if(send)", d'autres fois "if(send!=NULL)",... Enfin moi je dis ça, je
dis rien...
c'est pas pour faire mon enculeur de mouches, mais des fois il y a
"if(send)", d'autres fois "if(send!=NULL)",... Enfin moi je dis ça, je
dis rien...
c'est pas pour faire mon enculeur de mouches, mais des fois il y a
"if(send)", d'autres fois "if(send!=NULL)",... Enfin moi je dis ça, je
dis rien...
Qu'est ce qui cloche avec strtol?
Tobias.
Qu'est ce qui cloche avec strtol?
Tobias.
Qu'est ce qui cloche avec strtol?
Tobias.
"diviser pour régner", telle devrait etre la devise de tout bon
programmeur !
"diviser pour régner", telle devrait etre la devise de tout bon
programmeur !
"diviser pour régner", telle devrait etre la devise de tout bon
programmeur !
Eddahbi Karim wrote:
C'est vachement tordu d'avoir ton erreur incluse dans la structure. Si
tu penses en termes objets (un petit peu, hein, je veux pas de OOP
masters qui me tombent sur le coin du rable pour me reprendre !), ce qui
correspond a mettre tes elements dans une meme structure, les membres
d'une structure sont les attributs de l'objet represente par cette
structure.
Une date, telle que tu la concois, c'est une annee, un mois et un jour,
ainsi que (pourquoi pas, mais ca peut se discuter) une chaine de
caracteres. Ca se discute dans la mesure ou tu peux recreer la chaine de
caracteres a la volee avec la fonction (methode) adequate. Ce n'est pas
forcement un probleme d'avoir de la redondance dans les infos portees
par tes membres, mais il faut etre sur que tu n'aies pas de problemes
d'inconsistance.
Bref, revenons a nos moutons. Une erreur, ce n'est pas vraiment un
attribut de ta date. Donc l'erreur, elle n'a vraiment rien a faire parmi
les membres de ta structure. AMHA, bien entendu.
static void
wipestring (char const *string)
{
/* We search a 'n' character */
char *p = strchr (string, 'n');
/* We found it, we replace it by ' ' */ if (p)
{
*p = ' ';
}
/* We don't find it, so we get everything pending in stdin */ else
{
int c;
while ((c = getchar ()) != 'n' && c != EOF) {
}
}
}
wipestring, admettons. C'est une maniere de faire. L'autre maniere de
faire, c'est de s'arranger pour recuperer une ligne entiere a chaque
fois (a grands coups de fgets et de realloc). Une bonne (AMHA)
implementation est ggets.
static int
getstring (char *string, size_t size) {
/* If we got a 'n', does he enter something ? */ if ( err = >> EXIT_SUCCESS )
{
/* Wipe useless values */
wipestring (string);
La, je vois pas bien l'interet de l'appel a wipestring. Une fois que tu
as recupere la ligne qui t'interesse (recupere en entier !), le reste
des donnees se trouvant sur stdin appartient a la suite de ton
programme. Ainsi, en imaginant que tu aies, quelque part en chemin un
appel bloquant, qui laisse quelques secondes a ton utilisateur. Il sait
que tu vas demander une autre date. Il n'a pas envie d'attendre le
prompt pour la rentrer. Au contraire, il la rentre pendant que toi tu
fais le reste de ton traitement, avant meme d'arriver a la ligne
ci-dessus. Et toi, boum ! Tu lui vires tout ce qu'il a entre. D'un point
de vue interface utilisateur, c'est pas genial :-/
}
static int
checkdate ( unsigned short int month, unsigned short int day,
unsigned short int year)
C'est un peu dommage. A cause de ce test, tu ne peux pas declarer ton
tableau de jours-par-mois comme static. Je pense que le test de l'annee
bissextile doit se faire ci-dessous au moment ou tu tests si le nombre
de jours dans le mois est correct.
D'un point de vue clarte de l'algorithme, je ne pense pas non plus que
ce soit tres bien de tester d'abord si les jours sont compris entre 1 et
31 et ensuite si les jours sont compris entre 1 et le nombre max de
jours du mois.
/* If the day or the month isn't valid at all, we don't continue */
if ((day < 1 ) || (day > 31) || (month < 1) || (month > 12)) {
fprintf(stderr, "Month or day invalid.n"); err = EXIT_FAILURE;
}
/* If the day is superior to the max in the month entered */ else
if ( day > days_in_month[month] ) {
(void) fprintf(stderr, "Day invalid according to the
month.n"); err = EXIT_FAILURE;
}
Allez, on remplace tout ca:
/* traitement special pour fevrier */ else if (
(2 == month) &&
(year % 4 == 0) &&
(( year % 100 != 0 ) || ( year % 400 == 0 )) && ((day < 1) || (daydays_in_month[month] + 1)))
{
fprintf(stderr, "Invalid day.n");
err = EXIT_FAILURE;
}
}
static date
takedate (date *p_usertime)
{
/* Debug case : The variables MUST be initialized */
Pourquoi ?
/* This is the drawback of the visibility */
Oui, en l'occurence, une autre maniere d'ameliorer la "visibilite" est
d'avoir un nom de variable un peu plus raisonnable, e.g. date ou pdate.
p_usertime->month = month;
p_usertime->year = year;
p_usertime->day = day;
p_usertime->err = err;
return *p_usertime;
Pourquoi ? A quoi ca rime de retourner la structure elle meme ?!?! 1) Ca
enleve l'interet de passer un pointeur. Tant qu'a passer des structures
entieres, autant le faire a l'aller et au retour. 2) Ca n'apporte...
rien !
3) Ca t'empeche de retourner un code d'erreur a la place de la
structure, ce qui t'oblige a inclure le code d'erreur parmis les membres
de la structure, ce qui est une faute de conception, comme j'ai essaye
de l'exppliquer ci-dessus.
Donc non, non, non. Definissons:
static int takedate(date *date)
{
/* on veut pouvoir remplir la structure, donc elle
doit deja pointer quelque part */
assert(NULL != date);
/* etc. */
return r;
}
}
int
main (void)
{
int err;
/* Test */
err = takedate(userdate);
if (EXIT_SUCCESS == err)
{
err = takedate(userdate + 1);
}
return err;}
Merci ;),
De rien.
Eddahbi Karim wrote:
C'est vachement tordu d'avoir ton erreur incluse dans la structure. Si
tu penses en termes objets (un petit peu, hein, je veux pas de OOP
masters qui me tombent sur le coin du rable pour me reprendre !), ce qui
correspond a mettre tes elements dans une meme structure, les membres
d'une structure sont les attributs de l'objet represente par cette
structure.
Une date, telle que tu la concois, c'est une annee, un mois et un jour,
ainsi que (pourquoi pas, mais ca peut se discuter) une chaine de
caracteres. Ca se discute dans la mesure ou tu peux recreer la chaine de
caracteres a la volee avec la fonction (methode) adequate. Ce n'est pas
forcement un probleme d'avoir de la redondance dans les infos portees
par tes membres, mais il faut etre sur que tu n'aies pas de problemes
d'inconsistance.
Bref, revenons a nos moutons. Une erreur, ce n'est pas vraiment un
attribut de ta date. Donc l'erreur, elle n'a vraiment rien a faire parmi
les membres de ta structure. AMHA, bien entendu.
static void
wipestring (char const *string)
{
/* We search a 'n' character */
char *p = strchr (string, 'n');
/* We found it, we replace it by ' ' */ if (p)
{
*p = ' ';
}
/* We don't find it, so we get everything pending in stdin */ else
{
int c;
while ((c = getchar ()) != 'n' && c != EOF) {
}
}
}
wipestring, admettons. C'est une maniere de faire. L'autre maniere de
faire, c'est de s'arranger pour recuperer une ligne entiere a chaque
fois (a grands coups de fgets et de realloc). Une bonne (AMHA)
implementation est ggets.
static int
getstring (char *string, size_t size) {
/* If we got a 'n', does he enter something ? */ if ( err = >> EXIT_SUCCESS )
{
/* Wipe useless values */
wipestring (string);
La, je vois pas bien l'interet de l'appel a wipestring. Une fois que tu
as recupere la ligne qui t'interesse (recupere en entier !), le reste
des donnees se trouvant sur stdin appartient a la suite de ton
programme. Ainsi, en imaginant que tu aies, quelque part en chemin un
appel bloquant, qui laisse quelques secondes a ton utilisateur. Il sait
que tu vas demander une autre date. Il n'a pas envie d'attendre le
prompt pour la rentrer. Au contraire, il la rentre pendant que toi tu
fais le reste de ton traitement, avant meme d'arriver a la ligne
ci-dessus. Et toi, boum ! Tu lui vires tout ce qu'il a entre. D'un point
de vue interface utilisateur, c'est pas genial :-/
}
static int
checkdate ( unsigned short int month, unsigned short int day,
unsigned short int year)
C'est un peu dommage. A cause de ce test, tu ne peux pas declarer ton
tableau de jours-par-mois comme static. Je pense que le test de l'annee
bissextile doit se faire ci-dessous au moment ou tu tests si le nombre
de jours dans le mois est correct.
D'un point de vue clarte de l'algorithme, je ne pense pas non plus que
ce soit tres bien de tester d'abord si les jours sont compris entre 1 et
31 et ensuite si les jours sont compris entre 1 et le nombre max de
jours du mois.
/* If the day or the month isn't valid at all, we don't continue */
if ((day < 1 ) || (day > 31) || (month < 1) || (month > 12)) {
fprintf(stderr, "Month or day invalid.n"); err = EXIT_FAILURE;
}
/* If the day is superior to the max in the month entered */ else
if ( day > days_in_month[month] ) {
(void) fprintf(stderr, "Day invalid according to the
month.n"); err = EXIT_FAILURE;
}
Allez, on remplace tout ca:
/* traitement special pour fevrier */ else if (
(2 == month) &&
(year % 4 == 0) &&
(( year % 100 != 0 ) || ( year % 400 == 0 )) && ((day < 1) || (day
days_in_month[month] + 1)))
{
fprintf(stderr, "Invalid day.n");
err = EXIT_FAILURE;
}
}
static date
takedate (date *p_usertime)
{
/* Debug case : The variables MUST be initialized */
Pourquoi ?
/* This is the drawback of the visibility */
Oui, en l'occurence, une autre maniere d'ameliorer la "visibilite" est
d'avoir un nom de variable un peu plus raisonnable, e.g. date ou pdate.
p_usertime->month = month;
p_usertime->year = year;
p_usertime->day = day;
p_usertime->err = err;
return *p_usertime;
Pourquoi ? A quoi ca rime de retourner la structure elle meme ?!?! 1) Ca
enleve l'interet de passer un pointeur. Tant qu'a passer des structures
entieres, autant le faire a l'aller et au retour. 2) Ca n'apporte...
rien !
3) Ca t'empeche de retourner un code d'erreur a la place de la
structure, ce qui t'oblige a inclure le code d'erreur parmis les membres
de la structure, ce qui est une faute de conception, comme j'ai essaye
de l'exppliquer ci-dessus.
Donc non, non, non. Definissons:
static int takedate(date *date)
{
/* on veut pouvoir remplir la structure, donc elle
doit deja pointer quelque part */
assert(NULL != date);
/* etc. */
return r;
}
}
int
main (void)
{
int err;
/* Test */
err = takedate(userdate);
if (EXIT_SUCCESS == err)
{
err = takedate(userdate + 1);
}
return err;
}
Merci ;),
De rien.
Eddahbi Karim wrote:
C'est vachement tordu d'avoir ton erreur incluse dans la structure. Si
tu penses en termes objets (un petit peu, hein, je veux pas de OOP
masters qui me tombent sur le coin du rable pour me reprendre !), ce qui
correspond a mettre tes elements dans une meme structure, les membres
d'une structure sont les attributs de l'objet represente par cette
structure.
Une date, telle que tu la concois, c'est une annee, un mois et un jour,
ainsi que (pourquoi pas, mais ca peut se discuter) une chaine de
caracteres. Ca se discute dans la mesure ou tu peux recreer la chaine de
caracteres a la volee avec la fonction (methode) adequate. Ce n'est pas
forcement un probleme d'avoir de la redondance dans les infos portees
par tes membres, mais il faut etre sur que tu n'aies pas de problemes
d'inconsistance.
Bref, revenons a nos moutons. Une erreur, ce n'est pas vraiment un
attribut de ta date. Donc l'erreur, elle n'a vraiment rien a faire parmi
les membres de ta structure. AMHA, bien entendu.
static void
wipestring (char const *string)
{
/* We search a 'n' character */
char *p = strchr (string, 'n');
/* We found it, we replace it by ' ' */ if (p)
{
*p = ' ';
}
/* We don't find it, so we get everything pending in stdin */ else
{
int c;
while ((c = getchar ()) != 'n' && c != EOF) {
}
}
}
wipestring, admettons. C'est une maniere de faire. L'autre maniere de
faire, c'est de s'arranger pour recuperer une ligne entiere a chaque
fois (a grands coups de fgets et de realloc). Une bonne (AMHA)
implementation est ggets.
static int
getstring (char *string, size_t size) {
/* If we got a 'n', does he enter something ? */ if ( err = >> EXIT_SUCCESS )
{
/* Wipe useless values */
wipestring (string);
La, je vois pas bien l'interet de l'appel a wipestring. Une fois que tu
as recupere la ligne qui t'interesse (recupere en entier !), le reste
des donnees se trouvant sur stdin appartient a la suite de ton
programme. Ainsi, en imaginant que tu aies, quelque part en chemin un
appel bloquant, qui laisse quelques secondes a ton utilisateur. Il sait
que tu vas demander une autre date. Il n'a pas envie d'attendre le
prompt pour la rentrer. Au contraire, il la rentre pendant que toi tu
fais le reste de ton traitement, avant meme d'arriver a la ligne
ci-dessus. Et toi, boum ! Tu lui vires tout ce qu'il a entre. D'un point
de vue interface utilisateur, c'est pas genial :-/
}
static int
checkdate ( unsigned short int month, unsigned short int day,
unsigned short int year)
C'est un peu dommage. A cause de ce test, tu ne peux pas declarer ton
tableau de jours-par-mois comme static. Je pense que le test de l'annee
bissextile doit se faire ci-dessous au moment ou tu tests si le nombre
de jours dans le mois est correct.
D'un point de vue clarte de l'algorithme, je ne pense pas non plus que
ce soit tres bien de tester d'abord si les jours sont compris entre 1 et
31 et ensuite si les jours sont compris entre 1 et le nombre max de
jours du mois.
/* If the day or the month isn't valid at all, we don't continue */
if ((day < 1 ) || (day > 31) || (month < 1) || (month > 12)) {
fprintf(stderr, "Month or day invalid.n"); err = EXIT_FAILURE;
}
/* If the day is superior to the max in the month entered */ else
if ( day > days_in_month[month] ) {
(void) fprintf(stderr, "Day invalid according to the
month.n"); err = EXIT_FAILURE;
}
Allez, on remplace tout ca:
/* traitement special pour fevrier */ else if (
(2 == month) &&
(year % 4 == 0) &&
(( year % 100 != 0 ) || ( year % 400 == 0 )) && ((day < 1) || (daydays_in_month[month] + 1)))
{
fprintf(stderr, "Invalid day.n");
err = EXIT_FAILURE;
}
}
static date
takedate (date *p_usertime)
{
/* Debug case : The variables MUST be initialized */
Pourquoi ?
/* This is the drawback of the visibility */
Oui, en l'occurence, une autre maniere d'ameliorer la "visibilite" est
d'avoir un nom de variable un peu plus raisonnable, e.g. date ou pdate.
p_usertime->month = month;
p_usertime->year = year;
p_usertime->day = day;
p_usertime->err = err;
return *p_usertime;
Pourquoi ? A quoi ca rime de retourner la structure elle meme ?!?! 1) Ca
enleve l'interet de passer un pointeur. Tant qu'a passer des structures
entieres, autant le faire a l'aller et au retour. 2) Ca n'apporte...
rien !
3) Ca t'empeche de retourner un code d'erreur a la place de la
structure, ce qui t'oblige a inclure le code d'erreur parmis les membres
de la structure, ce qui est une faute de conception, comme j'ai essaye
de l'exppliquer ci-dessus.
Donc non, non, non. Definissons:
static int takedate(date *date)
{
/* on veut pouvoir remplir la structure, donc elle
doit deja pointer quelque part */
assert(NULL != date);
/* etc. */
return r;
}
}
int
main (void)
{
int err;
/* Test */
err = takedate(userdate);
if (EXIT_SUCCESS == err)
{
err = takedate(userdate + 1);
}
return err;}
Merci ;),
De rien.
D'un autre coté, bash exécute ce qui reste dans stdin (je ne sais pas
pourquoi, mais c'est comme ça). Je ne peux pas me permettre un buffer
overflow AVEC un exécution de code arbitraire parce que l'utilisateur n'a
pas voulu attendre 3 secondes :-).
D'un autre coté, bash exécute ce qui reste dans stdin (je ne sais pas
pourquoi, mais c'est comme ça). Je ne peux pas me permettre un buffer
overflow AVEC un exécution de code arbitraire parce que l'utilisateur n'a
pas voulu attendre 3 secondes :-).
D'un autre coté, bash exécute ce qui reste dans stdin (je ne sais pas
pourquoi, mais c'est comme ça). Je ne peux pas me permettre un buffer
overflow AVEC un exécution de code arbitraire parce que l'utilisateur n'a
pas voulu attendre 3 secondes :-).
C'est pour avoir une gestion d'erreur, or comme je ne peux renvoyer qu'une
structure, j'ai mis la gestion d'erreur dans la structure, maintenant, y'a
peut être un autre moyen, mais je ne vois pas lequel.
C'est pour avoir une gestion d'erreur, or comme je ne peux renvoyer qu'une
structure, j'ai mis la gestion d'erreur dans la structure, maintenant, y'a
peut être un autre moyen, mais je ne vois pas lequel.
C'est pour avoir une gestion d'erreur, or comme je ne peux renvoyer qu'une
structure, j'ai mis la gestion d'erreur dans la structure, maintenant, y'a
peut être un autre moyen, mais je ne vois pas lequel.