Partage
  • Partager sur Facebook
  • Partager sur Twitter

Exercices pour débutants en C

Au menu : zSommeChiffres (nombres, algo)

3 janvier 2010 à 15:17:28

Hum, disons, que j'avais prévu d'ouvrir un topic spécialement pour Pouet...

Exercices pour avancés en préprocesseur C...
Finalement, j'ai abandonné l'idée!...

Je vais mettre en place un batterie de tests(pas si simple jusqu'à 999999999999), le plus rapidement possible!

Sinon, pour ceux qui envisagent de poster, ne regardez pas le code de Pouet!
L'exercice est faisable sans artifices...

Citation : Adroneus

X macros ;) ils arrivent!! faites gaffe, vous pourrez plus vous en passer x) (hein pouet? )


OMG! Si c'est pour faire ça, non merci! ;)
  • Partager sur Facebook
  • Partager sur Twitter
Zeste de Savoir, le site qui en a dans le citron !
3 janvier 2010 à 15:18:58

Non, là il s'est juste amusé ;) les X-macros sont une manière de programmer, on aime ou on aime pas ;)
  • Partager sur Facebook
  • Partager sur Twitter
3 janvier 2010 à 15:43:34

Citation : Adroneus

X macros ;) ils arrivent!! faites gaffe, vous pourrez plus vous en passer x) (hein pouet? )



Le C actuel limite volontairement l'usage du préprocesseur. Va sur fclc et tu verras ce qu'ils pensent du préprocesseur.

Je te conseille de lire le livre de Kernighan et Pike, "The Practice of programming", c'est un livre vraiment très instructif. Voilà ce qu'ils disent du préprocesseur :

Citation : Kernighan & Pike


With modern machines and compilers, the drawback of functions macros outweigh their benefits. Avoid functions macros.(...). In C, they cause more problems than they solve.

  • Partager sur Facebook
  • Partager sur Twitter
3 janvier 2010 à 15:45:34

Ok, merci a toi, je vais me pencher dessus des que je le peux :D
  • Partager sur Facebook
  • Partager sur Twitter
3 janvier 2010 à 16:25:18

Rofl c'était juste pour m'amuser tapez pas :p
Je ferai une version sans préprocesseur :lol:

Mais bon là je ne génère aucun code en préprocesseur je ne fais que remplir mon tableau de chaînes de caractères donc bon le "they cause more problems than they solve" je ne suis pas d'accord dans mon cas ^^

D'ailleurs l'avantage avec mon code c'est que je n'ai pas besoin de me faire chier avec tous les nombres de 0 à 99 ils sont déjà là, j'ai juste à piocher dedans ^^
Et comme les plus chiants sont ces nombres là bah j'ai résolu le gros du problème :D

Bon on aime ou on aime pas :p
Moi ça m'éclate ^^
  • Partager sur Facebook
  • Partager sur Twitter
3 janvier 2010 à 18:46:04

Citation : Pouet_forever


Mais bon là je ne génère aucun code en préprocesseur



Bien sûr que si, le préprocesseur il te fait grosso modo du copier coller.

Citation : Pouet_forever


je ne fais que remplir mon tableau de chaînes de caractères donc bon le "they cause more problems than they solve" je ne suis pas d'accord dans mon cas ^^



Ça on ne sait pas combien de temps tu as mis pour écrire ton code ni combien de jours ou de semaines pour comprendre comment fonctionne le préprocesseur.


Ton code est complètement illisible (dans le fond comme dans la forme à cause des contraintes de formatage que nécessitent les directives), inmaintenable et indébogable (on ne voit pas les directives sous le débogueur)




Citation : Pouet_forever


D'ailleurs l'avantage avec mon code c'est que je n'ai pas besoin de me faire chier avec tous les nombres de 0 à 99 ils sont déjà là, j'ai juste à piocher dedans ^^



Aucun avantage puisqu'on peut écrire plus facilement le code C gérant l'écriture d'un nombre entre 0 et 99. On pourrait même écrire un code C qui pourrait gérer plusieurs langues (français, anglais, espagnol par exemple).




Citation : Pouet_forever


Et comme les plus chiants sont ces nombres là bah j'ai résolu le gros du problème :D


Non, ce n'est qu'une partie du problème pas plus difficile que le reste. Le fait de l'avoir écrit avec le préprocesseur ne change rien. Et comme tu vas devoir écrire en C le code qui génère les nombres à trois chiffres (à moins que tu veuilles faire écrire un immense tableau contenant l'écriture littérale des nombres entre 0 et 1000), tu introduis une hétérogénéité de traitement dans ton programme.
  • Partager sur Facebook
  • Partager sur Twitter
3 janvier 2010 à 18:53:27

@Pouet_Forever: j'ai regardé ton code(je t'avoue, que ça me faisait froid dans le dos! :p )
Tu ne gères que le nombres inférieurs à 100, et plus génant :
71
71 -> soixante-onze
Process returned 0 (0x0)   execution time : 1.562 s
Press any key to continue.

ou encore
91, non ça c'est correct... :-°

Ca doit être mignon à déboguer ton affaire. :-°
  • Partager sur Facebook
  • Partager sur Twitter
Zeste de Savoir, le site qui en a dans le citron !
3 janvier 2010 à 19:05:14

Citation : candide

Bien sûr que si, le préprocesseur il te fait grosso modo du copier coller.



Oh my god !!
Voilà le résultat du programme de Pouet_forever après un gcc -E (qui a pour effet de faire passer le preprocesseur uniquement, sans compilation) :
char const * const zero_a_99[] = {







 "" "" "zero" "", "" "" "" "un", "" "" "" "deux", "" "" "" "trois", "" "" "" "quatre", "" "" "" "cinq", "" "" "" "six", "" "" "" "sept", "" "" "" "huit", "" "" "" "neuf", "" "dix", "" "onze", "" "douze", "" "treize", "" "quatorze", "" "quinze", "" "seize", "" "dix-sept", "" "dix-huit", "" "dix-neuf", "vingt" "" "" "", "vingt" "" " et " "" "un", "vingt" "" "-" "" "deux", "vingt" "" "-" "" "trois", "vingt" "" "-" "" "quatre", "vingt" "" "-" "" "cinq", "vingt" "" "-" "" "six", "vingt" "" "-" "" "sept", "vingt" "" "-" "" "huit", "vingt" "" "-" "" "neuf", "trente" "" "" "", "trente" "" " et " "" "un", "trente" "" "-" "" "deux", "trente" "" "-" "" "trois", "trente" "" "-" "" "quatre", "trente" "" "-" "" "cinq", "trente" "" "-" "" "six", "trente" "" "-" "" "sept", "trente" "" "-" "" "huit", "trente" "" "-" "" "neuf", "quarante" "" "" "", "quarante" "" " et " "" "un", "quarante" "" "-" "" "deux", "quarante" "" "-" "" "trois", "quarante" "" "-" "" "quatre", "quarante" "" "-" "" "cinq", "quarante" "" "-" "" "six", "quarante" "" "-" "" "sept", "quarante" "" "-" "" "huit", "quarante" "" "-" "" "neuf", "cinquante" "" "" "", "cinquante" "" " et " "" "un", "cinquante" "" "-" "" "deux", "cinquante" "" "-" "" "trois", "cinquante" "" "-" "" "quatre", "cinquante" "" "-" "" "cinq", "cinquante" "" "-" "" "six", "cinquante" "" "-" "" "sept", "cinquante" "" "-" "" "huit", "cinquante" "" "-" "" "neuf", "soixante" "" "" "", "soixante" "" " et " "" "un", "soixante" "" "-" "" "deux", "soixante" "" "-" "" "trois", "soixante" "" "-" "" "quatre", "soixante" "" "-" "" "cinq", "soixante" "" "-" "" "six", "soixante" "" "-" "" "sept", "soixante" "" "-" "" "huit", "soixante" "" "-" "" "neuf", "soixante" "-" "dix", "soixante" "-" "onze", "soixante" "-" "douze", "soixante" "-" "treize", "soixante" "-" "quatorze", "soixante" "-" "quinze", "soixante" "-" "seize", "soixante" "-" "dix-sept", "soixante" "-" "dix-huit", "soixante" "-" "dix-neuf", "quatre-vingt" "s" "" "", "quatre-vingt" "" " " "" "un", "quatre-vingt" "" "-" "" "deux", "quatre-vingt" "" "-" "" "trois", "quatre-vingt" "" "-" "" "quatre", "quatre-vingt" "" "-" "" "cinq", "quatre-vingt" "" "-" "" "six", "quatre-vingt" "" "-" "" "sept", "quatre-vingt" "" "-" "" "huit", "quatre-vingt" "" "-" "" "neuf", "quatre-vingt" "-" "dix", "quatre-vingt" "-" "onze", "quatre-vingt" "-" "douze", "quatre-vingt" "-" "treize", "quatre-vingt" "-" "quatorze", "quatre-vingt" "-" "quinze", "quatre-vingt" "-" "seize", "quatre-vingt" "-" "dix-sept", "quatre-vingt" "-" "dix-huit", "quatre-vingt" "-" "dix-neuf",



};

int main(void) {
 int i;
 scanf("%d", &i);
 printf("%d -> %s", i, zero_a_99[i]);
 return EXIT_SUCCESS;
}


@Pouet : Je te laisse imaginer la taille de ton exécutable si tu implémentes ton prog pour faire jusqu'à 10^9
  • Partager sur Facebook
  • Partager sur Twitter
3 janvier 2010 à 19:33:18

Ok j'ai supprimé mon post on en parle plus ...
  • Partager sur Facebook
  • Partager sur Twitter
3 janvier 2010 à 19:36:59

Citation : Pouet_forever

Ok j'ai supprimé mon post on en parle plus ...


Mais non, pourquoi tu as fait ça ?
C'est intéressant de voir ce qu'on peut faire avec le preprocesseur.
Même si ce n'est pas efficace en terme de mémoire...
En plus dis toi que ton prog est le plus rapide qu'on puisse faire (on ne peut faire mieux en terme de rapidité).
Aucun test, accès mémoire instantané !!
Y a que le coté mémoire qui coince... C'est tout
  • Partager sur Facebook
  • Partager sur Twitter
3 janvier 2010 à 21:00:08

</Coup_de_gueule>

Pour le 91 c'est correct :)
Ya juste le 71 qui n'allait pas :)

#include <stdio.h>
#include <stdlib.h>

#define LES_ZERO( nb , zero , et , trait , s_20 )				\
	X(			, zero	,	 ,		 ,	nb	, s_20	)			\
	X(un		,		, et ,		 ,	nb	,		)			\
	X(deux		,		,	 , trait ,	nb	,		)			\
	X(trois		,		,	 , trait ,	nb	,		)			\
	X(quatre	,		,	 , trait ,	nb	,		)			\
	X(cinq		,		,	 , trait ,	nb	,		)			\
	X(six		,		,	 , trait ,	nb	,		)			\
	X(sept		,		,	 , trait ,	nb	,		)			\
	X(huit		,		,	 , trait ,	nb	,		)			\
	X(neuf		,		,	 , trait ,	nb	,		)

#define LES_DIX( nb , zero , et , trait , s_20 )	\
	X11( dix		,	 , trait , nb ,	)			\
	X11( onze		, et ,		, nb ,	)			\
	X11( douze		,	 , trait , nb ,	)			\
	X11( treize		,	 , trait , nb ,	)			\
	X11( quatorze	,	 , trait , nb ,	)			\
	X11( quinze		,	 , trait , nb ,	)			\
	X11( seize		,	 , trait , nb ,	)			\
	X11( dix-sept	,	 , trait , nb ,	)			\
	X11( dix-huit	,	 , trait , nb ,	)			\
	X11( dix-neuf	,	 , trait , nb ,	)

#define LES_DIXAINES															\
	X10(				, zero	,		 ,		,	,	LES_ZERO	)			\
	X10(				,		,		 ,		,	,	LES_DIX		)			\
	X10( vingt			,		, " et " , "-"	,	,	LES_ZERO	)			\
	X10( trente			,		, " et " , "-"	,	,	LES_ZERO	)			\
	X10( quarante		,		, " et " , "-"	,	,	LES_ZERO	)			\
	X10( cinquante		,		, " et " , "-"	,	,	LES_ZERO	)			\
	X10( soixante		,		, " et " , "-"	,	,	LES_ZERO	)			\
	X10( soixante		,		, " et " , "-"	,	,	LES_DIX		)			\
	X10( quatre-vingt	,		, " "	 , "-"	, s	,	LES_ZERO	)			\
	X10( quatre-vingt	,		, "-"	 , "-"	,	,	LES_DIX		)

char const * const zero_a_99[] = {
	
#define X( nb_lettre , zero , et , trait , nb , s_20 )		#nb #s_20 trait et #zero #nb_lettre,
#define X11( nb_lettre , et , trait , nb , s_20 )			#nb trait et #nb_lettre,
	
#define X10( nb_lettre , zero , et , trait , s_20, _ )		\
	_( nb_lettre , zero , et , trait , s_20 )
	
	LES_DIXAINES
	
#undef X
#undef X10
#undef X11
};

int main(void) {
	int i;
	for (i = 0; i < 100; i++)
		printf("%02d -> %s\n", i, zero_a_99[i]);
	return EXIT_SUCCESS;
}

Pour le déboggage il n'y en a pas !
Une fois que ton tableau est créé tu n'y touche plus :-°
  • Partager sur Facebook
  • Partager sur Twitter
3 janvier 2010 à 21:28:40

Citation : Pouet Forever


Pour le 91 c'est correct :)


Bah oui, je ne sais pas ce que j'ai fait.... c'était juste pour t'embêter... :-° Non ?

Je me suis planté :-°

  • Partager sur Facebook
  • Partager sur Twitter
Zeste de Savoir, le site qui en a dans le citron !
3 janvier 2010 à 21:50:54

Bon, allez, je vais essayer de m'y mettre, je ne sais pas trop si je vais avoir le temps avec les examens blancs :(

Sinon, bon exercice, il m'a l'air intéressant :)

[EDIT] Pis la rentrée demain, quelle galèèère :'(
  • Partager sur Facebook
  • Partager sur Twitter
- Il y a un chemin vers chaque sommet, même le plus haut -
3 janvier 2010 à 21:58:06

Citation : Pouet_forever

Supprimé par la censure ...



La censure ne passera pas ;) :

X(six		,		,	 , trait ,	nb	,		)			\
	X(sept		,		,	 , trait ,	nb	,		)			\
	X(huit		,		,	 , trait ,	nb	,		)			\
	X(neuf		,		,	 , trait ,	nb	,		)

#define LES_DIX( nb , zero , et , trait , s_20 )	\
	X11( dix		,	 , trait , nb ,	)			\
	X11( onze		, et , trait , nb ,	)			\
	X11( douze		,	 , trait , nb ,	)			\
	X11( treize		,	 , trait , nb ,	)			\
	X11( quatorze	,	 , trait , nb ,	)			\
	X11( quinze		,	 , trait , nb ,	)			\
	X11( seize		,	 , trait , nb ,	)			\
	X11( dix-sept	,	 , trait , nb ,	)			\
	X11( dix-huit	,	 , trait , nb ,	)			\
	X11( dix-neuf	,	 , trait , nb ,	)

#define LES_DIXAINES															\
	X10(				, zero	,		 ,		,	,	LES_ZERO	)			\
	X10(				,		,		 ,		,	,	LES_DIX		)			\
	X10( vingt			,		, " et " , "-"	,	,	LES_ZERO	)			\
	X10( trente			,		, " et " , "-"	,	,	LES_ZERO	)			\
	X10( quarante		,		, " et " , "-"	,	,	LES_ZERO	)			\
	X10( cinquante		,		, " et " , "-"	,	,	LES_ZERO	)			\
	X10( soixante		,		, " et " , "-"	,	,	LES_ZERO	)			\
	X10( soixante		,		,		 , "-"	,	,	LES_DIX		)			\
	X10( quatre-vingt	,		, " "	 , "-"	, s	,	LES_ZERO	)			\
	X10( quatre-vingt	,		,		 , "-"	,	,	LES_DIX		)

char const * const zero_a_99[] = {
	
#define X( nb_lettre , zero , et , trait , nb , s_20 )		#nb #s_20 trait et #zero #nb_lettre,
#define X11( nb_lettre , et , trait , nb , s_20 )			#nb trait et #nb_lettre,
	
#define X10( nb_lettre , zero , et , trait , s_20, _ )		\
	_( nb_lettre , zero , et , trait , s_20 )
	
	LES_DIXAINES

#undef X
#undef X11
};

int main(void) {
	int i;
	scanf("%d", &i);
	printf("%d -> %s", i, zero_a_99[i]);
	return EXIT_SUCCESS;
}


EDIT : j'avais pas vu que t'avais remis le code mais bon, je le laisse quand même au cas où tu déciderais à nouveau de nous le censurer ;)
  • Partager sur Facebook
  • Partager sur Twitter
3 janvier 2010 à 23:53:03

Il manque un bout de code :-°
De plus j'ai corrigé un truc suite à la remarque de GurneyH ^^

Edit : Voilà en code "normal" :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* ============ Variables globales ============ */
#pragma mark -
#pragma mark globales

char const * const unites [20] = {
	"zero", "un", "deux", "trois", "quatre", "cinq", "six", "sept", "huit", "neuf",
	"dix", "onze", "douze", "treize", "quatorze", "quinze", "seize", "dix-sept", "dix-huit", "dix-neuf"
};

char const * const dixaines [10] = {
	"", "", "vingt", "trente", "quarante", "cinquante", "soixante", "soixante",
	"quatre-vingt", "quatre-vingt"
};

char const * const centaines [4] = {
	"cent", "mille", "million", "millard"
};

/* ============ Fonctions ============ */
#pragma mark -

void dix(int nb, char *str, int esse, int mil) {
	char tmp[100] = "";
	int unit = nb % 10;
	int disse = nb / 10;
	
	if (nb == 0)
		return;
	
	if (nb == 1 && mil == 1)
		return;
	
	if (nb < 20) {
		strcat(str, unites[nb]);
		strcat(str, " ");
		return;
	}
	if (nb == 80) {
		strcat(str, dixaines[disse]);
		if (esse)
			strcat(str, "s");
		strcat(str, " ");
		return;
	}
	
	strcat(tmp, dixaines[disse]);
	
	if (unit == 1 && disse != 8 && disse != 9)
		strcat(tmp, " et ");
	else
		strcat(tmp, "-");
	
	if (disse == 7 || disse == 9)
		strcat(tmp, unites[unit+10]);
	else if (unit != 0)
		strcat(tmp, unites[unit]);
	
	strcat(str, tmp);
	strcat(str, " ");
}

void cent(int nb, char *str, int esse, int mil) {
	char tmp[100] = "";
	
	if (nb > 99) {
		int mod = nb / 100;
		
		if (mod > 1)
			sprintf(tmp, "%s ", unites[mod]);
		strcat(tmp, centaines[0]);
		
		if (esse && mod > 1 && nb % 100 == 0)
			strcat(tmp, "s");
		strcat(tmp, " ");
	}
	
	dix(nb % 100, tmp, esse, mil);
	
	strcpy(str, tmp);
}

char * z0zero(char const *src) {
	static char res[500];
	char str[500] = "";
	int i, j;
	int len = strlen(src);
	int tmp, mult, esse = 1;
	int mil = 0;
	
	if (strtol(src, NULL, 10) == 0) {
		sprintf(res, "%s", unites[0]);
		return res;
	}
	
	for (j = 0; j < 4; j++) {
		tmp = 0;
		mult = 1;
		*str = '\0';
		if (j == 1)
			mil = 1;
		else
			mil = 0;
		
		for (i = len-1-(3*j); i >= 0 && i >= len-3*(j+1); i--, mult*=10)
			tmp += (src[i] - '0') * mult;
		
		cent(tmp, str, esse, mil);
		
		if (j != 0 && tmp != 0) {
			strcat(str, centaines[j]);
			if (tmp != 1 && j != 1)
				strcat(str, "s ");
			else
				strcat(str, " ");
			strcat(str, res);
		}
		else
			strcat(str, res);
		
		strcpy(res, str);
		
		if (i < 0)
			break;
		
		esse = 0;
	}
	
	return res;
}

/* 999 999 999 999 */

int main(void) {
	char * str = "999999999999";
	
	printf("%s", z0zero(str));
	return EXIT_SUCCESS;
}

Dîtes moi ce que vous en pensez :)
(et si voulez des commentaires :-° )
  • Partager sur Facebook
  • Partager sur Twitter
5 janvier 2010 à 16:30:45

Salut à tous,

Voici mon code pour l'exo z0zéro qui fonctionne pour tous les nombres entre 0 et 999.
J'étendrais à 999 999 999 999 si j'ai le courage, m'enfin je crois qu'en allant jusqu'à 999 on a déjà traité l'essentiel des exceptions.

J'ai essayé de commenter pour que ce soit le plus clair possible.
Si vous avez des remarques, conseils, suggestions, commentaires... :)

main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "restricted.h"

int
main(int argc, char **argv)
{
    char *number;
    char letters[256];

    if (argc != 2) {
        printf("usage: z0zero num\n");
        return 1;
    }

    number = argv[1];

    /* If the number is > 999. */
    if (strlen(number) > 3) {
        printf("error: number too big.\n");
        return 1;
    }

    convert_restricted(number, letters);
    printf("%s\n", letters);

    return 0;
}


restricted.h
#ifndef RESTRICTED__H
#define RESTRICTED__H

char *convert_restricted(const char *src, char *dst);

#endif


restricted.c
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "restricted.h"


static bool remains_only_zeroes(char *s);


static char *up_to_16[] = {
    "",         "un",       "deux",     "trois",    "quatre",   "cinq", 
    "six",      "sept",     "huit",     "neuf",     "dix",      "onze", 
    "douze",    "treize",   "quatorze", "quinze",   "seize"
};

static char *multiples_of_10[] = {
    "", "dix", "vingt", "trente", "quarante", "cinquante", "soixante",
    "", "quatre-vingt", ""
};                

char 
*convert_restricted(const char *src, char *dst)
{    
    int tmp;
    /* The exponent of the greatest power of 10 in the number. */
    int pow = strlen(src) - 1;  

    char *p_dst = dst;  /* Points to the place where we should write next in dst. */
    char *buf = malloc(22 * sizeof(char));
    char *p = malloc(4 * sizeof(char));

    strcpy(p, src);

    /* Skip the leading 0s. */
    while (*p == '0') {
        p++;
        pow--;
    }

    /* Zero is a special case.
     * If src was "0", there remains only the final '\0' since all leading
     * zeroes have been skipped. */
    if (*p == '\0') {
        strcpy(dst, "zero");
    }

    for(; *p; (p++, pow--)) {

        /* If the number is < 10, just look it up. */
        if (pow == 0) {
            tmp = *p - '0';
            sprintf(buf, "%s ", up_to_16[tmp]);
        }

        /* If the number is < 100, there's a whole lot of special cases! */
        else if (pow == 1) { 
            tmp = (*p - '0') * 10 + (*(p+1) - '0'); /* The actual number. */

            /* Numbers <= 16 are especially special. */
            if (tmp <= 16) {
                sprintf(buf, "%s ", up_to_16[tmp]);
                p++;        /* Two characters were just processed. */
            }

            /* 70 - 79 */
            else if (*p == '7') {
                if (*(p+1) == '1') {
                    sprintf(buf, "soixante et onze ");
                    p++;
                } else {
                    sprintf(buf, "soixante-");
                    /* Make the parser believe it is reading "1x" instead of
                     * "7x" */
                    *p = '1'; 
                    p--;   
                    pow++;
                }
            }

            /* "80" takes an 's': "quatre-vingts". */
            else if (tmp == 80) {
                sprintf(buf, "quatre-vingts ");
                p++;
            }

            /* 90 - 99 */
            else if (*p == '9') {
                if (*(p+1) == '1') {
                    sprintf(buf, "quatre-vingt-onze ");
                    p++;
                } else {
                    sprintf(buf, "quatre-vingt-");
                    /* Make the parser believe it is reading "1x" instead of
                     * "9x" */
                    *p = '1';
                    p--;     
                    pow++;
                }
            }
             
            /* There's a dash for all composed numbers < 100 not ending with a
             * '1' (in that case there is an 'et'), plus 81 (and 91, which was 
             * already treated). */
            else if (*(p+1) != '0' && 
                    (*(p+1) != '1' || *p == '8')) {
                sprintf(buf, "%s-%s ", 
                        multiples_of_10[*p - '0'],
                        up_to_16[*(p+1) - '0']);
                p++;
            }

            else if (*(p+1) == '0') {
                sprintf(buf, "%s ", multiples_of_10[*p - '0']);
                p++;
            }

            else if (*(p+1) == '1') {
                sprintf(buf, "%s et un ", multiples_of_10[*p - '0']);
                p++;
            }

        } else {

            /* You don't say "un cent" for "100". */
            if (*p == '1') {
                sprintf(buf, "cent ");
            } else {
                /* If the number is *00, write * cents, otherwise * cent ... */
                if (remains_only_zeroes(p + 1)) {
                    sprintf(buf, "%s cents ",
                            up_to_16[*p - '0']);
                } else {
                    sprintf(buf, "%s cent ", 
                            up_to_16[*p - '0']);
                }
            }
        }

        strcpy(p_dst, buf);
        p_dst += strlen(buf);
    }

    free(p);
    free(buf);

    return dst; 
}

static bool 
remains_only_zeroes(char *s)
{
    char *p = s;
    while (*p == '0') p++;
    return *p == '\0';
}

  • Partager sur Facebook
  • Partager sur Twitter
5 janvier 2010 à 17:22:14

Salut :)

Je pense que tu joues trop avec sprintf pour avoir un nombre "fait du premier coup".
Tu ferais mieux d'utiliser strcat je pense comme ça tu pourras concaténer tes différents nombres sans problèmes (et réduire le nombre de lignes de ton code).
Ce n'est que mon avis hein ;)

Petite erreur ici cependant :

free(p);

Le problème c'est que tu incrémentes p à chaque tour de boucle et à la fin il ne pointe plus sur le début de la zone mémoire allouée, du coup ça va pas ;)
Au lieux d'allouer et de prendre p pourquoi tu ne prends pas tout simplement la chaîne que tu as passée en argument ? ;)
  • Partager sur Facebook
  • Partager sur Twitter
5 janvier 2010 à 17:30:18

Ouh, bien vu pour le free(p); . ;)
Le souci c'est que je modifie la chaîne en cours de route, et que je trouve ça plus propre de laisser la chaîne passée en entrée intacte.

Pour le coup de strcat, c'est vrai que je pourrais concaténer directement sur la destination. M'enfin je suis pas sûr que ça diminue tant que ça le nombre de lignes, parce que ça revient grosso modo à ce que je fais : je stocke dans un buffer que j'écris ensuite sur la destination.

Sinon je viens aussi de me rendre compte qu'il y a un espace en trop à la fin de la destination.
  • Partager sur Facebook
  • Partager sur Twitter
5 janvier 2010 à 17:34:55

Citation : Bad_Wolf

M'enfin je suis pas sûr que ça diminue tant que ça le nombre de lignes, parce que ça revient grosso modo à ce que je fais : je stocke dans un buffer que j'écris ensuite sur la destination.


Regarde mon code juste au dessus du tiens. Je gère tous les nombres de l'exo en 140 lignes de code :)
Convaincu ? :lol:
  • Partager sur Facebook
  • Partager sur Twitter
5 janvier 2010 à 17:40:41

Citation : Bad_Wolf


Si vous avez des remarques, conseils, suggestions, commentaires... :)



J'ai testé, et à l'usage, toutes les exceptions sont bien gérées, nickel. :)

Tout comme Pouet, je trouve que l'utilisation d'allocation dynamique n'est pas utile ici, et te fais faire une bêtise pour le coup.

Citation : Bad_Wolf

Le souci c'est que je modifie la chaîne en cours de route, et que je trouve ça plus propre de laisser la chaîne passée en entrée intacte.


Rien ne t'empèche de faire une copie de la chaîne d'origine...

Pour gérer uniquement les nombres à 3 chiffres, ta fonction
char *convert_restricted(const char *src, char *dst) fait plus de 100 lignes(avec les commentaires, c'est vrai.), je trouve ça un peu long.

Sinon, c'est vraiment plutôt bien. ;)

Merci pour ta participation.

edit: Pouet, je n'avais pas fait attention que tu avais posté un code "normal"! Cool, je vais regarder. :)

:-° Pour les pragmas...
||=== z0Zero_Pouet2, Debug ===|
main.c|6|warning: ignoring #pragma mark |
main.c|7|warning: ignoring #pragma mark globales|
main.c|27|warning: ignoring #pragma mark |
||=== Build finished: 0 errors, 3 warnings ===|
  • Partager sur Facebook
  • Partager sur Twitter
Zeste de Savoir, le site qui en a dans le citron !
5 janvier 2010 à 17:49:44

Citation : GurneyH

:-° Pour les pragmas...

||=== z0Zero_Pouet2, Debug ===|
main.c|6|warning: ignoring #pragma mark |
main.c|7|warning: ignoring #pragma mark globales|
main.c|27|warning: ignoring #pragma mark |
||=== Build finished: 0 errors, 3 warnings ===|

C'est pas grave ça :p
C'est spécial Xcode ça ^^
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
5 janvier 2010 à 20:41:30

Ouep, je confirme, c'est super utile les pragma. Sinon, je posterai si j'ai le temps de faire un code, j'ai pas mal d'algo en ce moment.
  • Partager sur Facebook
  • Partager sur Twitter
5 janvier 2010 à 21:27:03

Citation : Bad_Wolf


Voici mon code pour l'exo z0zéro qui fonctionne pour tous les nombres entre 0 et 999.



Chez moi, rien ne marche :

candide@candide-desktop:~$ cat main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "restricted.h"

int
main(int argc, char **argv)
{
    char *number;
    char letters[256];

    if (argc != 2) {
        printf("usage: z0zero num\n");
        return 1;
    }

    number = argv[1];

    /* If the number is > 999. */
    if (strlen(number) > 3) {
        printf("error: number too big.\n");
        return 1;
    }

    convert_restricted(number, letters);
    printf("%s\n", letters);

    return 0;
}

candide@candide-desktop:~$ cat restricted.h
#ifndef RESTRICTED__H
#define RESTRICTED__H

char *convert_restricted(const char *src, char *dst);

#endif

candide@candide-desktop:~$ cat restricted.c
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "restricted.h"


static bool remains_only_zeroes(char *s);


static char *up_to_16[] = {
    "",         "un",       "deux",     "trois",    "quatre",   "cinq", 
    "six",      "sept",     "huit",     "neuf",     "dix",      "onze", 
    "douze",    "treize",   "quatorze", "quinze",   "seize"
};

static char *multiples_of_10[] = {
    "", "dix", "vingt", "trente", "quarante", "cinquante", "soixante",
    "", "quatre-vingt", ""
};                

char 
*convert_restricted(const char *src, char *dst)
{    
    int tmp;
    /* The exponent of the greatest power of 10 in the number. */
    int pow = strlen(src) - 1;  

    char *p_dst = dst;  /* Points to the place where we should write next in dst. */
    char *buf = malloc(22 * sizeof(char));
    char *p = malloc(4 * sizeof(char));

    strcpy(p, src);

    /* Skip the leading 0s. */
    while (*p == '0') {
        p++;
        pow--;
    }

    /* Zero is a special case.
     * If src was "0", there remains only the final '\0' since all leading
     * zeroes have been skipped. */
    if (*p == '\0') {
        strcpy(dst, "zero");
    }

    for(; *p; (p++, pow--)) {

        /* If the number is < 10, just look it up. */
        if (pow == 0) {
            tmp = *p - '0';
            sprintf(buf, "%s ", up_to_16[tmp]);
        }

        /* If the number is < 100, there's a whole lot of special cases! */
        else if (pow == 1) { 
            tmp = (*p - '0') * 10 + (*(p+1) - '0'); /* The actual number. */

            /* Numbers <= 16 are especially special. */
            if (tmp <= 16) {
                sprintf(buf, "%s ", up_to_16[tmp]);
                p++;        /* Two characters were just processed. */
            }

            /* 70 - 79 */
            else if (*p == '7') {
                if (*(p+1) == '1') {
                    sprintf(buf, "soixante et onze ");
                    p++;
                } else {
                    sprintf(buf, "soixante-");
                    /* Make the parser believe it is reading "1x" instead of
                     * "7x" */
                    *p = '1'; 
                    p--;   
                    pow++;
                }
            }

            /* "80" takes an 's': "quatre-vingts". */
            else if (tmp == 80) {
                sprintf(buf, "quatre-vingts ");
                p++;
            }

            /* 90 - 99 */
            else if (*p == '9') {
                if (*(p+1) == '1') {
                    sprintf(buf, "quatre-vingt-onze ");
                    p++;
                } else {
                    sprintf(buf, "quatre-vingt-");
                    /* Make the parser believe it is reading "1x" instead of
                     * "9x" */
                    *p = '1';
                    p--;     
                    pow++;
                }
            }
             
            /* There's a dash for all composed numbers < 100 not ending with a
             * '1' (in that case there is an 'et'), plus 81 (and 91, which was 
             * already treated). */
            else if (*(p+1) != '0' && 
                    (*(p+1) != '1' || *p == '8')) {
                sprintf(buf, "%s-%s ", 
                        multiples_of_10[*p - '0'],
                        up_to_16[*(p+1) - '0']);
                p++;
            }

            else if (*(p+1) == '0') {
                sprintf(buf, "%s ", multiples_of_10[*p - '0']);
                p++;
            }

            else if (*(p+1) == '1') {
                sprintf(buf, "%s et un ", multiples_of_10[*p - '0']);
                p++;
            }

        } else {

            /* You don't say "un cent" for "100". */
            if (*p == '1') {
                sprintf(buf, "cent ");
            } else {
                /* If the number is *00, write * cents, otherwise * cent ... */
                if (remains_only_zeroes(p + 1)) {
                    sprintf(buf, "%s cents ",
                            up_to_16[*p - '0']);
                } else {
                    sprintf(buf, "%s cent ", 
                            up_to_16[*p - '0']);
                }
            }
        }

        strcpy(p_dst, buf);
        p_dst += strlen(buf);
    }

    free(p);
    free(buf);

    return dst; 
}

static bool 
remains_only_zeroes(char *s)
{
    char *p = s;
    while (*p == '0') p++;
    return *p == '\0';
}

candide@candide-desktop:~$ gcc -O2 -W -Wall -std=c99 -pedantic -o x main.c restricted.c -o z0zero
candide@candide-desktop:~$ ./z0zero 42
*** glibc detected *** ./z0zero: free(): invalid pointer: 0x0804a02a ***
======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6[0xb7ebda85]
/lib/tls/i686/cmov/libc.so.6(cfree+0x90)[0xb7ec14f0]
./z0zero[0x804877f]
./z0zero[0x8048575]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe0)[0xb7e68450]
./z0zero[0x8048471]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:02 2859117    /home/candide/z0zero
08049000-0804a000 rw-p 00000000 08:02 2859117    /home/candide/z0zero
0804a000-0806b000 rw-p 0804a000 00:00 0          [heap]
b7d00000-b7d21000 rw-p b7d00000 00:00 0 
b7d21000-b7e00000 ---p b7d21000 00:00 0 
b7e46000-b7e50000 r-xp 00000000 08:02 4644928    /lib/libgcc_s.so.1
b7e50000-b7e51000 rw-p 0000a000 08:02 4644928    /lib/libgcc_s.so.1
b7e51000-b7e52000 rw-p b7e51000 00:00 0 
b7e52000-b7f9b000 r-xp 00000000 08:02 4662581    /lib/tls/i686/cmov/libc-2.7.so
b7f9b000-b7f9c000 r--p 00149000 08:02 4662581    /lib/tls/i686/cmov/libc-2.7.so
b7f9c000-b7f9e000 rw-p 0014a000 08:02 4662581    /lib/tls/i686/cmov/libc-2.7.so
b7f9e000-b7fa1000 rw-p b7f9e000 00:00 0 
b7fb5000-b7fb7000 rw-p b7fb5000 00:00 0 
b7fb7000-b7fb8000 r-xp b7fb7000 00:00 0          [vdso]
b7fb8000-b7fd2000 r-xp 00000000 08:02 4644883    /lib/ld-2.7.so
b7fd2000-b7fd4000 rw-p 00019000 08:02 4644883    /lib/ld-2.7.so
bfd04000-bfd19000 rw-p bffeb000 00:00 0          [stack]
Abandon
candide@candide-desktop:~$
  • Partager sur Facebook
  • Partager sur Twitter
5 janvier 2010 à 23:59:08

bonsoir,

je suis nouveau sur le site, je suis actuellement en apprentissage sur le langage C, je me suis arrété au tuto " une bête de calcul" car je recherche des exercices simple pour mieux comprendre et digérer l' info, et là je m apperçois qu' il n y a rien...c'est vraiment dommage car ce site et une perle. En attendant que des exercices puissent etre mis à disposition jvais réviser les parties précédente.

bonne soirée.
  • Partager sur Facebook
  • Partager sur Twitter
6 janvier 2010 à 0:05:04

En fait, je ne sais pas comment le debuter cet exo :(
Faut faire une énumeration, avec les dizaines, centaines, etc... ? :-°

@lun@stick:
Ben continue le tuto, après, tu pourra faire les exos ici :)
Sinon, tu regardes sur google, chuis sûr ça peut se trouver :-°
  • Partager sur Facebook
  • Partager sur Twitter
- Il y a un chemin vers chaque sommet, même le plus haut -
6 janvier 2010 à 0:10:26

Moi je suis parti de ça :

char const * const unites [20] = {
	"zero", "un", "deux", "trois", "quatre", "cinq", "six", "sept", "huit", "neuf",
	"dix", "onze", "douze", "treize", "quatorze", "quinze", "seize", "dix-sept", "dix-huit", "dix-neuf"
};

char const * const dixaines [10] = {
	"", "", "vingt", "trente", "quarante", "cinquante", "soixante", "soixante",
	"quatre-vingt", "quatre-vingt"
};

char const * const centaines [4] = {
	"cent", "mille", "million", "millard"
};

Bon les noms sont pas terrible terrible mais j'étais pas inspiré ^^
Tu peux modifier dixaines en mettant "dix" et les enlever de unites si tu veux :)
  • Partager sur Facebook
  • Partager sur Twitter
6 janvier 2010 à 0:23:01

comment déclarer un type d'ensemble de chaine de caracteres
  • Partager sur Facebook
  • Partager sur Twitter
6 janvier 2010 à 0:35:10

Bah comme j'ai fait juste au dessus :)

char *str[2] = { "Salut", "Au revoir" };


Par contre il ne faut pas essayer de modifier les chaînes de caractères !
C'est pour ça que je les ai mis en tant que constantes ;)
  • Partager sur Facebook
  • Partager sur Twitter
6 janvier 2010 à 0:42:20

Citation : artificier59

En fait, je ne sais pas comment le debuter cet exo :(



C'est ce qui fait la difficulté de l'exo. Le mieux est que tu essayes de verbaliser comment, dans la vie courante, tu parviens à lire un nombre donné avec ses chiffres.

Si tu n'y arrives pas, essaye de faire l'exo uniquement pour les nombres à au plus deux chiffres, ce n'est déjà pas si évident de traiter efficacement tous les cas.

Citation : Pouet_forever

Moi je suis parti de ça :

char const * const unites [20] = {
	"zero", "un", "deux", "trois", "quatre", "cinq", "six", "sept", "huit", "neuf",
	"dix", "onze", "douze", "treize", "quatorze", "quinze", "seize", "dix-sept", "dix-huit", "dix-neuf"
};

char const * const dixaines [10] = {
	"", "", "vingt", "trente", "quarante", "cinquante", "soixante", "soixante",
	"quatre-vingt", "quatre-vingt"
};

char const * const centaines [4] = {
	"cent", "mille", "million", "millard"
};


Bon les noms sont pas terrible terrible mais j'étais pas inspiré ^^
Tu peux modifier dixaines en mettant "dix" et les enlever de unites si tu veux :)



Ce que tu lui donnes là n'est pas à même de lui permettre de comprendre comment écrire l'algorithme même si ton découpage me semble correct.

Avec tes const partout, à mon avis, tu embrouilles les débutants et même de plus avancés. Par ailleurs, il n'est pas utile de mentionner la taille des tableaux.

On n'écrit pas dixaine mais dizaine. Dans le tableau des dizaines, la répétition de soixante et quatre-vingt ne me semble pas pertinente. De même, dans
ton tableau de centaines, la présence de "cent" ne me paraît pas pertinente.
  • Partager sur Facebook
  • Partager sur Twitter
6 janvier 2010 à 4:34:46

@lunstick: Il y aura des exercices beaucoup plus simples que celui-ci...
Seulement c'est très compliqué de satisfaire les débutants ainsi que les débutants "avancés"...

Je pense alterner un exercice "difficile" et un autre plus facile. Par contre, il te faudra tout de même avancer encore un peu dans le cours C.
Tu peux trouver des exercices plus accessibles ici

@Artificier59:
N'oublie pas que tu as 15 jours pour résoudre cet exercice. La plupart du temps, même si un exercice est à notre niveau on ne le résout pas instantanément(ou alors c'est que l'exercice est trop simple...)! Il faut souvent plusieurs jours pour trouver un cheminement, et c'est normal.

@candide : Pour le code de Bad_Wolf, c'est l'erreur signalée par Pouet, (pointeur p incrémenté, et free() sur ce pointeur, invalide à la fin de la fonction.).

@Pouet: Effectivement, ton code est très compliqué...
A un moment donné, je pense que c'est important d'écrire du code qui soit lisible et compréhensible par d'autres(même moins avancés.)
Par exemple :
for (i = len-1-(3*j); i >= 0 && i >= len-3*(j+1); i--, mult*=10)

C'est une perle. :p

Sinon à l'usage, je n'ai pas trouvé d'erreurs. :) .
  • Partager sur Facebook
  • Partager sur Twitter
Zeste de Savoir, le site qui en a dans le citron !