Partage

Exercices pour débutants en C

Au menu : zSommeChiffres (nombres, algo)

16 janvier 2010 à 23:09:49

z0zero : Correction



Pour résoudre cet exercice, on peut commencer par traiter les nombres à 1 chiffre, 2 chiffres, 3 chiffres et enfin étendre le principe aux nombres à n chiffres.

Les nombres à 1 et 2 chiffres

Pour les nombres à 1 chiffre, normalement pas de problèmes.
On va créer une fonction qui prend 2 paramètres :
nombre1Chiffre(int n, char * dst);
Ici on va simplement initialiser un tableau de 10 éléments, chaque élément correspondant à la traduction en lettres de son index.

tab[0] = "zero" tab[1] = "un"
On rentre dans le vif du sujet avec les

Nombres à 2 chiffres



Prenons un cas général, 23 par exemple. Naturellement pour avoir sa traduction en lettre, on le lit de gauche à droite et on prononce "vingt trois". C'est un nombre à 2 chiffres, donc le chiffre de gauche représente les dizaines tandis que celui de droite représente les unités.

Maintenant, comment décomposer ce nombre en 2 parties ?

Le nombre 23 peut s'écrire : <math>\(2 * 10 + 3\)</math>
Si on généralise, un nombre à 2 chiffres <math>\(c_1c_2\)</math> peut s'écrire : <math>\(c_1 * 10 + c_2\)</math>
Pour obtenir <math>\(c_1\)</math> et <math>\(c_2\)</math>, on divise notre nombre <math>\(c_1c_2\)</math> par 10. Le quotient de la division entière sera <math>\(c_1\)</math>, et le reste <math>\(c_2\)</math>.

Si le quotient est nul -> pas de dizaines,
si le reste est nul pas d'unités(on n'écrit pas dix zéro... :-°enfin, si parfois dans le cas d'un match de foot)

En suivant le même principe que pour les nombres à 1 chiffre on va écrire la fonction
nombre2chiffres(int n, char *dst);
void nombre2chiffres(int n, char *dst)
{
    char *s_dizaines[] =
    {
        "dix", "vingt", "trente", "quarante", "cinquante", "soixante", "quatre-vingt",
    };
    /* Quotient de la division n / 10 */
    int q = n / 10;
    /* Reste de la division n / 10 */
    int r = n % 10;

    if (q > 0)
    {
        /* Le quotient n'est pas nul, on n'est bien en présence d'un nombre à
         * 2 chiffres, on concatène les dizaines.
         * Ici, l'index 0 correspond à 10, on doit dont soustraire 1 à q pour
         * obtenir le bon index de tableau
         */
        strcat(s, s_dizaines[q - 1]);
        if (r > 0)
        {
            /* Le reste n'est pas nul on concatène les unités */
            nombre1chiffre(s, r);
        }
    }
    else
    {
        /* Le quotient est nul, notre nombre n'a qu'un chiffre */
        nombre1chiffre(s, r);
    }
}


23 -> vingttrois
        
        Process returned 0 (0x0)   execution time : 0.000 s
        Press any key to continue.

Premier constat, le principe fonctionne... Presque.
Il n'y a pas de séparations entre les 2 chiffres, et si vous testez 11, vous obtenez

11 -> dixun

:euh:

De plus cela ne fonctionne pas pour les nombres supérieurs à 70(essayez si vous ne me croyez pas :lol: ...).
Pas de panique, un problème après l'autre!...

Tout d'abord, le problème des nombres dans l'intervalle [10, 19].

On va simplement modifier la fonction pour traiter séparément
  • les nombres dans l'intervalle <math>\([10, 19]\)</math>
  • les nombres dans l'intervalle<math>\([0, 9] U [20, 99]\)</math>

Notre fonction devient
void nombre2chiffres(int n, char *dst)
{
    char *s_dizaines[] =
    {
        "dix", "vingt", "trente", "quarante", "cinquante",
        "soixante", "quatre-vingt",
    };

    /* Nombre entre 11 et 19 */
    char *s_pdizaines[] =
    {
        "dix", "onze", "douze", "treize", "quatorze",
        "quinze", "seize", "dix-sept", "dix-huit", "dix-neuf",
    };

    /* Quotient de la division n / 10 */
    int q = n / 10;
    /* Reste de la division n / 10 */
    int r = n % 10;

    if (n >= 10  && n <= 19)
    {
        /* On est dans l'intervalle [10, 19]
         * r contient correspond à l'index de la traduction
         */
        strcat(dst, s_pdizaines[r]);
    }
    else
    {
        /* On est dans l'intervalle [0, 9] U [20, 99] */
        if (q == 0)
        {
            /* Le quotient est nul.
             * Notre nombre à 2 chiffres est en fait un nombre à 1 chiffre
             */
            nombre1chiffre(r, dst);
        }
        else
        {
            /* Le qutient n'est pas nul, on n'est bien en présence d'un nombre
            * à 2 chiffres, on concatène les dizaines.
            * Ici, l'index 0 correpond à 11, on doit dont soustraire 1 à q pour
            * obtenir le bon index de tableau
            */

            strcat(dst, s_dizaines[q - 1]);
            if (r != 0)
            {
                /* Le reste n'est pas nul on concatène les unités */
                nombre1chiffre(r, dst);
            }
        }
    }
}


Et on obtient bien
11 -> onze

Et c'est ok jusqu'à 69.

Problème suivant,
les nombres dans l'intervalle [70, 79] U [90, 99].

Les nombres de cet ensemble, s'écrivent avec la dizaine précédente auquel on ajoute un nombre dans l'intervalle [10, 19].
73 -> soixante treize
92 -> quatre-vingt douze
On va commencer par faire correspondre l'indice 7 à la chaîne "soixante" et l'indice 9 à la chaîne "quatre-vingt".

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


ensuite il suffit de tester si le quotient est égal à 7 ou 9. Si c'est le cas, on affiche notre dizaine normalement, mais on ajoutera 10 au reste pour avoir un nombre dans l'intervalle[10, 19]

On obtient
void nombre2chiffres(int n, char *dst)
{
    char *s_dizaines[] =
    {
        "vingt", "trente", "quarante", "cinquante",
        "soixante", "soixante", "quatre-vingt", "quatre-vingt"
    };

    /* Nombre entre 11 et 19 */
    char *s_pdizaines[] =
    {
        "dix", "onze", "douze", "treize", "quatorze",
        "quinze", "seize", "dix-sept", "dix-huit", "dix-neuf",
    };

    /* Quotient de la division n / 10 */
    int q = n / 10;
    /* Reste de la division n / 10 */
    int r = n % 10;

    if (n >= 10  && n <= 19)
    {
        /* On est dans l'intervalle [10, 19]
         * r contient correspond à l'index de la traduction
         */
        strcat(dst, s_pdizaines[r]);
    }
    else
    {
        /* On est dans l'interevalle [0, 9] U [20, 99] */
        if (q == 0)
        {
            /* Le quotient est nul.
             * Notre nombre à 2 chiffres est en fait un nombre à 1 chiffre
             */
            nombre1chiffre(r, dst);
        }
        else
        {
            /* Le quotient n'est pas nul, on n'est bien en présence d'un nombre
            * à 2 chiffres, on concatène les dizaines.
            * Ici, l'index 0 correpond à 20, on doit dont soustraire 2 à q pour
            * obtenir le bon index de tableau
            */

            strcat(dst, s_dizaines[q - 2]);
            if (q == 7 || q == 9)
            {
                /* On est dans l'intervalle [70, 79] U [90, 99]
                 * On ajoute 10 au reste.
                 */
                r += 10;

            }
            if (r != 0)
            {
                /* Le reste n'est pas nul on concatène le chiffre de gauche */
                if (r >= 10)
                {
                    /* On est dans l'intervalle [70, 79] U [90, 99] */
                    strcat(dst, s_pdizaines[r - 10]);
                }
                else
                {
                    /* Cas général */
                    nombre1chiffre(r, dst);
                }
            }
        }
    }
}



0 -> zero
        1 -> un
        2 -> deux
        3 -> trois
        4 -> quatre
        5 -> cinq
        6 -> six
        7 -> sept
        8 -> huit
        9 -> neuf
        10 -> dix
        11 -> onze
        12 -> douze
        13 -> treize
        14 -> quatorze
        15 -> quinze
        16 -> seize
        17 -> dix_sept
        18 -> dix_huit
        19 -> dix_neuf
        20 -> vingt
        21 -> vingtun
        22 -> vingtdeux
        23 -> vingttrois
        24 -> vingtquatre
        25 -> vingtcinq
        26 -> vingtsix
        27 -> vingtsept
        28 -> vingthuit
        29 -> vingtneuf
        30 -> trente
        31 -> trenteun
        32 -> trentedeux
        33 -> trentetrois
        34 -> trentequatre
        35 -> trentecinq
        36 -> trentesix
        37 -> trentesept
        38 -> trentehuit
        39 -> trenteneuf
        40 -> quarante
        41 -> quaranteun
        42 -> quarantedeux
        43 -> quarantetrois
        44 -> quarantequatre
        45 -> quarantecinq
        46 -> quarantesix
        47 -> quarantesept
        48 -> quarantehuit
        49 -> quaranteneuf
        50 -> cinquante
        51 -> cinquanteun
        52 -> cinquantedeux
        53 -> cinquantetrois
        54 -> cinquantequatre
        55 -> cinquantecinq
        56 -> cinquantesix
        57 -> cinquantesept
        58 -> cinquantehuit
        59 -> cinquanteneuf
        60 -> soixante
        61 -> soixanteun
        62 -> soixantedeux
        63 -> soixantetrois
        64 -> soixantequatre
        65 -> soixantecinq
        66 -> soixantesix
        67 -> soixantesept
        68 -> soixantehuit
        69 -> soixanteneuf
        70 -> soixantedix
        71 -> soixanteonze
        72 -> soixantedouze
        73 -> soixantetreize
        74 -> soixantequatorze
        75 -> soixantequinze
        76 -> soixanteseize
        77 -> soixantedix_sept
        78 -> soixantedix_huit
        79 -> soixantedix_neuf
        80 -> quatre-vingt
        81 -> quatre-vingtun
        82 -> quatre-vingtdeux
        83 -> quatre-vingttrois
        84 -> quatre-vingtquatre
        85 -> quatre-vingtcinq
        86 -> quatre-vingtsix
        87 -> quatre-vingtsept
        88 -> quatre-vingthuit
        89 -> quatre-vingtneuf
        90 -> quatre-vingtdix
        91 -> quatre-vingtonze
        92 -> quatre-vingtdouze
        93 -> quatre-vingttreize
        94 -> quatre-vingtquatorze
        95 -> quatre-vingtquinze
        96 -> quatre-vingtseize
        97 -> quatre-vingtdix-sept
        98 -> quatre-vingtdix-huit
        99 -> quatre-vingtdix-neuf


Il nous reste à séparer nos 2 chiffres en se rappelant que

Citation : Le conjugueur

Prennent un trait d'union tous les nombres composés inférieurs à 100 ne se terminant pas en 1 sauf 81 et 91 :


Reste également à faire attention au seul cas particulier restant qui concerne l'écriture des nombre à 2 chiffres :

Citation : Le conjugueur

20 et 100 s'accordent quand ils sont multipliés par un nombre sans être suivis par un autre nombre.


  • quatre-vingts
  • quatre-vingt-un

void nombre2chiffres(int n, char *dst)
{
    char *s_dizaines[] =
    {
        "vingt", "trente", "quarante", "cinquante",
        "soixante", "soixante", "quatre-vingt", "quatre-vingt"
    };

    /* Nombre entre 11 et 19 */
    char *s_pdizaines[] =
    {
        "dix", "onze", "douze", "treize", "quatorze",
        "quinze", "seize", "dix-sept", "dix-huit", "dix-neuf",
    };

    /* Quotient de la division n / 10 */
    int q = n / 10;
    /* Reste de la division n / 10 */
    int r = n % 10;

    if (n >= 10  && n <= 19)
    {
        /* On est dans l'intervalle [10, 19]
         * r contient correspond à l'index de la traduction
         */
        strcat(dst, s_pdizaines[r]);
    }
    else
    {
        /* On est dans l'interevalle [0, 9] U [20, 99] */
        if (q == 0)
        {
            /* L' quotient est nul.
             * Notre nombre à 2 chiffres est en fait un nombre à 1 chiffre
             */
            nombre1chiffre(r, dst);
        }
        else
        {
            /* Le quotient n'est pas nul, on n'est bien en présence d'un nombre
            * à 2 chiffres, on concatène les dizaines.
            * Ici, l'index 0 correspond à 20, on doit dont soustraire 2 à q pour
            * obtenir le bon index de tableau
            */

            strcat(dst, s_dizaines[q - 2]);
            if (q == 7 || q == 9)
            {
                /* On est dans l'intervalle [70, 79] U [90, 99]
                 * On ajoute 10 au reste.
                 */
                r += 10;

            }
            if (q == 8 && r == 0)/* if (n == 80) */
            {
                /* On ajoute le s à quatre-vingts */
                strcat(dst, "s");
            }
            if (r != 0)
            {
                /* Le reste n'est pas nul, on ajoute le séparateur approprié*/
                if ((r == 1 || r == 11)
            {
                if (q != 8 && q != 9)
                    {
                        /* ... et un ou ... et onze */
                        strcat(dst, " et ");
                    }
                }
                else
                {
                    /* Dans tous les autres cas, c'est un tiret */
                    strcat(dst, "-");
                }

                if (r >= 10)
            {
                /* On est dans l'intervalle [70, 79] U [90, 99] */
                strcat(dst, s_pdizaines[r - 10]);
                }
                else
                {
                    /* Cas général */
                    nombre1chiffre(r, dst);
                }
            }
        }
    }
}

0 -> zero
        1 -> un
        2 -> deux
        3 -> trois
        4 -> quatre
        5 -> cinq
        6 -> six
        7 -> sept
        8 -> huit
        9 -> neuf
        10 -> dix
        11 -> onze
        12 -> douze
        13 -> treize
        14 -> quatorze
        15 -> quinze
        16 -> seize
        17 -> dix_sept
        18 -> dix_huit
        19 -> dix_neuf
        20 -> vingt
        21 -> vingt et un
        22 -> vingt-deux
        23 -> vingt-trois
        24 -> vingt-quatre
        25 -> vingt-cinq
        26 -> vingt-six
        27 -> vingt-sept
        28 -> vingt-huit
        29 -> vingt-neuf
        30 -> trente
        31 -> trente et un
        32 -> trente-deux
        33 -> trente-trois
        34 -> trente-quatre
        35 -> trente-cinq
        36 -> trente-six
        37 -> trente-sept
        38 -> trente-huit
        39 -> trente-neuf
        40 -> quarante
        41 -> quarante et un
        42 -> quarante-deux
        43 -> quarante-trois
        44 -> quarante-quatre
        45 -> quarante-cinq
        46 -> quarante-six
        47 -> quarante-sept
        48 -> quarante-huit
        49 -> quarante-neuf
        50 -> cinquante
        51 -> cinquante et un
        52 -> cinquante-deux
        53 -> cinquante-trois
        54 -> cinquante-quatre
        55 -> cinquante-cinq
        56 -> cinquante-six
        57 -> cinquante-sept
        58 -> cinquante-huit
        59 -> cinquante-neuf
        60 -> soixante
        61 -> soixante et un
        62 -> soixante-deux
        63 -> soixante-trois
        64 -> soixante-quatre
        65 -> soixante-cinq
        66 -> soixante-six
        67 -> soixante-sept
        68 -> soixante-huit
        69 -> soixante-neuf
        70 -> soixante-dix
        71 -> soixante et onze
        72 -> soixante-douze
        73 -> soixante-treize
        74 -> soixante-quatorze
        75 -> soixante-quinze
        76 -> soixante-seize
        77 -> soixante-dix_sept
        78 -> soixante-dix_huit
        79 -> soixante-dix_neuf
        80 -> quatre-vingts
        81 -> quatre-vingt-un
        82 -> quatre-vingt-deux
        83 -> quatre-vingt-trois
        84 -> quatre-vingt-quatre
        85 -> quatre-vingt-cinq
        86 -> quatre-vingt-six
        87 -> quatre-vingt-sept
        88 -> quatre-vingt-huit
        89 -> quatre-vingt-neuf
        90 -> quatre-vingt-dix
        91 -> quatre-vingt-onze
        92 -> quatre-vingt-douze
        93 -> quatre-vingt-treize
        94 -> quatre-vingt-quatorze
        95 -> quatre-vingt-quinze
        96 -> quatre-vingt-seize
        97 -> quatre-vingt-dix_sept
        98 -> quatre-vingt-dix_huit
        99 -> quatre-vingt-dix_neuf
        
        Process returned 0 (0x0)   execution time : 0.125 s
        Press any key to continue.

Le plus dur est fait !
Après ça,

Les nombres à 3 chiffres

seront une partie de plaisir. :lol:
Un exemple 123. Un nombre à 3 chiffres est... une centaine suivie d'un nombre à 2 chiffres.
Pour isoler cette centaine, même principe que pour un nombre à 2 chiffres, on utilise la division entière :

123 / 100 = 1
123 % 100 = 23

Le seul cas particulier à prendre en compte est l'accord de cent.

Citation : Le conjugueur

20 et 100 s'accordent quand ils sont multipliés par un nombre sans être suivis par un autre nombre.



C'est tout.
On obtient(je donne les 3 fonctions, plus un main de test)

#include <stdio.h>

void nombre1chiffre(int n, char *dst)
{
    char *s_chiffres[] =
    {
        "zero", "un", "deux", "trois", "quatre",
        "cinq", "six", "sept", "huit", "neuf",
    };

    strcat(dst, s_chiffres[n]);
}


void nombre2chiffres(int n, char *dst)
{
    char *s_dizaines[] =
    {
        "vingt", "trente", "quarante", "cinquante",
        "soixante", "soixante", "quatre-vingt", "quatre-vingt"
    };

    /* Nombre entre 11 et 19 */
    char *s_pdizaines[] =
    {
        "dix", "onze", "douze", "treize", "quatorze",
        "quinze", "seize", "dix-sept", "dix-huit", "dix-neuf",
    };

    /* Quotient de la division n / 10 */
    int q = n / 10;
    /* Reste de la division n / 10 */
    int r = n % 10;

    if (n >= 10  && n <= 19)
    {
        /* On est dans l'intervalle [10, 19]
         * r contient correspond à l'index de la traduction
         */
        strcat(dst, s_pdizaines[r]);
    }
    else
    {
        /* On est dans l'interevalle [0, 9] U [20, 99] */
        if (q == 0)
        {
            /* Le quotient est nul.
             * Notre nombre à 2 chiffres est en fait un nombre à 1 chiffre
             */
            nombre1chiffre(r, dst);
        }
        else
        {
            /* Le quotient n'est pas nul, on n'est bien en présence d'un nombre
            * à 2 chiffres, on concatène les dizaines.
            * Ici, l'index 0 correpond à 20, on doit dont soustraire 2 à q pour
            * obtenir le bon index de tableau
            */

            strcat(dst, s_dizaines[q - 2]);
            if (q == 7 || q == 9)
            {
                /* On est dans l'intervalle [70, 79] U [90, 99]
                 * On ajoute 10 au reste.
                 */
                r += 10;

            }
            if (q == 8 && r == 0)
            {
                /* On ajoute le s à quatre-vingts */
                strcat(dst, "s");
            }
            if (r != 0)
            {
                /* Le reste n'est pas nul, on ajoute le séparateur approprié*/
                if ((r == 1 || r == 11) && q != 8 && q != 9)
                {
                    /* ... et un ou ... et onze */
                    strcat(dst, " et ");
                }
                else
                {
                    /* Dans tous les autres cas, c'est un tiret */
                    strcat(dst, "-");
                }
                if (r >= 10)
                {
                    /* On est dans l'intervalle [70, 79] U [90, 99] */
                    strcat(dst, s_pdizaines[r - 10]);
                }
                else
                {
                    /* Cas général */
                    nombre1chiffre(r, dst);
                }
            }
        }
    }
}



void nombre3chiffres(int n, char *dst)
{
    /* Quotient de la division n / 100 */
    int q = n / 100;
    /* Reste de la division n / 100 */
    int r = n % 100;

    if (q == 0)
    {
        /* Pas de centaines, c'est un nombre à 2 chiffres */
        nombre2chiffres(n, dst);
    }
    else
    {
        /* Plusieurs centaines */
        if (q > 1)
        {
            /* On ajoute le nombre de centaines */
            nombre2chiffres(q, dst);
            /* Un espace */
            strcat(dst, " ");
        }

        /* Le mot cent */
        strcat(dst, "cent");

        if (q > 1 && r == 0)
        {
            /* Un s si besoin */
            strcat(dst, "s");
        }
    }
    if (r > 0)
    {
        /* il y a un reste */

        /* On ajoute un espace, suivi des dizaines */
        strcat(dst, " ");
        nombre2chiffres(r, dst);
    }
}



int main(void)
{
    int i;
    for (i = 0; i < 1000; ++i)
    {
        char res[256] = "";
        nombre3chiffres(i, res);
        printf("%d -> %s\n", i, res);
    }
    return 0;
}

Facile, non?
Il ne reste plus qu'à nous occuper des

Nombres à n chiffres

(avec n <= 12)
Le prototype donné pour l'exercice était
char *z0zero(char *src, char *dst);
La principale différence, par rapport aux fonctions précédentes, c'est qu'ici, le nombre est representé sous forme d'une chaîne de caractères.

Prenons un exemple:
"2256":

Notre nombre est un nombre de milliers(2), suivi d'un nombre à 3 chiffres(256).
2256 = 2 * 1000 + 256
Même principe qu'auparavant, on doit séparer notre nombre en 2 parties, les milliers partie gauche, et les centaines, parties droite. Pour un nombre entre 1000 et 999999 :
milliers = nombre / 1000
centaines = nombre % 1000

Pour un nombre >= 1000000
exemple:
"1256512"
1256512 = 1 * 1000000 + 256 * 1000 + 512
millions = nombre / 1000000
milliers = nombre % 1000000

Seulement on travaille sur une chaîne de caractères! Comment faire une division sur une chaîne de caractères? o_O

Tout d'abord, comment connaitre le nombre de chiffres de notre nombre ?
strlen fera très bien l'affaire.

strlen("2256") -> 4, et on obtient bien le nombre de chiffres.

Pour isoler la partie gauche. On divise le nombre de chiffres par 3. 3, car chaque groupe de 3 chiffres isole une puissance de 1000
<math>\(1 000 = 10^3\)</math>
<math>\(1 000 000 = 10^6\)</math>

Ainsi, si le nombre de chiffres / 3 est
  • = 0 on est dans le groupe des centaines
  • = 1 on est dans le groupe des milliers
  • = 2 on est dans le groupe des millions
  • = 3 on est dans le groupe des milliards

Si le reste de la division est nul, le nombre appartient au groupe précédent.

Un exemple:
999 -> nombre de chiffres 3
3 / 3 ->
quotient = 1,
reste = 0,
le reste est nul donc :
groupe = quotient - 1 -> groupe = 0
999 appartient au groupe des centaines.

Pour obtenir le nombre de chiffres du quotient, c'est simple, on multiplie la valeur du groupe par 3 et on soustrait le résultat au nombre de chiffres total.

nombre de chiffre du quotient = nombre de chiffres - groupe * 3

Ce sera surement plus clair avec un exemple:
Toujours avec 2256 :

2256
nombre de chiffres = 4
2256 / 3 = 1 et le reste n'est pas nul, donc on est dans le groupe des milliers.

4 - 1 * 3 = 1
La partie gauche a 1 chiffre -> 2256

On a la méthode, reste à la coder. :pirate:

Les 3 fonctions précédentes ne travaillent pas sur une chaîne de caractères, mais sur un entier.

Il va donc falloir convertir la partie gauche de notre nombre en entier.
Pour ce faire on copie cette partie gauche dans une chaîne temporaire. La partie à convertir à forcément 3 chiffres, donc une taille de 4 caractère(3 chiffres + le '\0'), est suffisante.
Pendant qu'on y est, on convertit également la partie droite du nombre. Ici, je n'utilise pas de variable temporaire, car la partie droite du nombre est terminée par '\0', on est bien en présence d'une chaîne valide.

Pour mieux, comprendre, voici la représentation en mémoire de notre chaîne :
src + 0 src + 1 src + 2 src + 3 src + 4
'1' '2' '3' '4' '\0'

La partie gauche de notre nombre débute à src + 0(src) et à un taille de 1 caractère.
La partie droite de notre nombre débute à src + 1 et se termine au caractère '\0'.

Pour la copie, j'ai utilisé la fonction
char *strncpy (char *dest, const char *src, size_t n);

Citation : <man>

La fonction strncpy() est identique, sauf que seuls les n premiers octets de src sont copiés. Ainsi, s'il n'y a pas de caractère nul dans les n premiers octets de src, la chaîne résultante ne disposera de caractère nul final. Dans le cas où la longueur src est inférieure à n, la fin de dest sera remplie avec des caractères nuls.



Pour la conversion, j'utilise la fonction
long int strtol (const char *nptr, char **endptr, int base);

Citation : <man>

La fonction strtol() convertit la chaîne nptr en un entier long en fonction de l'argument base, qui doit être dans l'intervalle 2 a 36 (bornes comprises), ou avoir la valeur spéciale 0.

.

On a traiteé le cas général, maintenant au tour des
cas particuliers

Citation : Le conjugueur

Mille est toujours invariable
* trois mille * dix mille deux



Citation : Le conjugueur

million et milliard sont des noms et non des adjectifs. Ils ne font pas vraiment partie du nombre et laissent place à l'accord :
* quatre cents millions
* deux cent mille
* deux cents milliers



Et enfin le troisième cas particulier,

Citation

1000 tout comme 100, ne s'écrit pas un mille, mais bel et bien mille!



On va devoir modifier nos premières fonctions pour gérer ses exeptions. En effet,
80000 -> quatre-vingts mille.
1000 -> un mille

On va simplement passer le groupe courant au fonctions qui en ont besoin
Leur prototype devient
void nombre2chiffres(char *s, int n, int p);
	void nombre3chiffres(char *s, int n, int p);


Apparait également la fonction
char *sauterZeros(char *s);
qui sert commer son nom l'indique, à sauter les zéros inutiles en début de nombre :
00001 -> 1
01256 -> 1256

Au final, le programme complet
#include <stdio.h>
#include <string.h> /* pour strlen, strcat, strncpy */
#include <stdlib.h> /* pour strtol() */

char *sauterZeros(char *s)
{
    /* Tant que le caractère actuel est '0' */
    while (*s == '0')
    {
        /* On avance dans la chaîne */
        ++s;
    }
    return s;
}



void nombre1chiffre(int n, char *dst)
{
    char *s_chiffres[] =
    {
        "zero", "un", "deux", "trois", "quatre",
        "cinq", "six", "sept", "huit", "neuf",
    };

    strcat(dst, s_chiffres[n]);
}


void nombre2chiffres(int n, char *dst, int p)
{
    char *s_dizaines[] =
    {
        "vingt", "trente", "quarante", "cinquante",
        "soixante", "soixante", "quatre-vingt", "quatre-vingt"
    };

    /* Nombre entre 11 et 19 */
    char *s_pdizaines[] =
    {
        "dix", "onze", "douze", "treize", "quatorze",
        "quinze", "seize", "dix-sept", "dix-huit", "dix-neuf",
    };

    /* Quotient de la division n / 10 */
    int q = n / 10;
    /* Reste de la division n / 10 */
    int r = n % 10;

    if (n >= 10  && n <= 19)
    {
        /* On est dans l'intervalle [10, 19]
        * r contient correspond à l'index de la traduction
        */
        strcat(dst, s_pdizaines[r]);
    }
    else
    {
        /* On est dans l'interevalle [0, 9] U [20, 99] */
        if (q == 0)
        {
            /* Le quotient est nul.
            * Notre nombre à 2 chiffres est en fait un nombre à 1 chiffre
            */
            nombre1chiffre(r, dst);
        }
        else
        {
            /* Le quotient n'est pas nul, on n'est bien en présence d'un nombre
             * à 2 chiffres, on concatène les dizaines.
             * Ici, l'index 0 correpond à 20, on doit dont soustraire 2 à q pour
             * obtenir le bon index de tableau
             */

            strcat(dst, s_dizaines[q - 2]);
            if (q == 7 || q == 9)
            {
                /* On est dans l'intervalle [70, 79] U [90, 99]
                 * On ajoute 10 au reste.
                 */
                r += 10;

            }
            if (q == 8 && r == 0)
            {
                /* On ajoute le s à quatre-vingts si on ne se trouve pas dans
                 * les milliers.
                 * On n'écris pas quatre-vingts-mille */
                if (p != 1)
                {
                    strcat(dst, "s");
                }
            }
            if (r != 0)
            {
                /* Le reste n'est pas nul, on ajoute le séparateur approprié*/
                if ((r == 1 || r == 11) && q != 8 && q != 9)
                {
                    /* ... et un ou ... et onze */
                    strcat(dst, " et ");
                }
                else
                {
                    /* Dans tous les autres cas, c'est un tiret */
                    strcat(dst, "-");
                }
                if (r >= 10)
                {
                    /* On est dans l'intervalle [70, 79] U [90, 99] */
                    strcat(dst, s_pdizaines[r - 10]);
                }
                else
                {
                    /* Cas général */
                    nombre1chiffre(r, dst);
                }
            }
        }
    }
}



void nombre3chiffres(int n, char *dst, int p)
{
    /* Quotient de la division n / 100 */
    int q = n / 100;
    /* Reste de la division n / 100 */
    int r = n % 100;

    if (q == 0)
    {
        /* Pas de centaines, c'est un nombre à 2 chiffres */

        /* On prend garde à ne pas écrire un mille */
        if (p != 1 || n > 1)
        {
            nombre2chiffres(n, dst, p);
        }
    }
    else
    {
        /* Plusieurs centaines */
        if (q > 1)
        {
            /* On ajoute le nombre de centaines */
            nombre2chiffres(q, dst, p);
            /* Un espace */
            strcat(dst, " ");
        }

        /* Le mot cent */
        strcat(dst, "cent");

        /* Un s si besoin */
        if (q > 1 && r == 0 && p != 1)
        {
            strcat(dst, "s");
        }
        if (r > 0)
        {
            /* il y a un reste */
            /* On ajoute un espace, suivi des dizaines */
            strcat(dst, " ");
            nombre2chiffres(r, dst, p);
        }
    }
}



char *z0zero(char *src, char *dst)
{
    char const *s_p3[] =
    {
        "mille", "million", "milliard"
    };
    int n;

    /* On s'assure que la chaîne des destination débute bien par '\0' */
    dst[0] = '\0';

    /* On saute les zéros inutiles à gauche du nombre */
    src = sauterZeros(src);

    /* Nombre de chiffre de la chaîne source */
    n = strlen(src);
    if (n == 0)
    {
        /* cas particulier du zéro. */
        nombre1chiffre(0, dst);
    }
    else
    {
        int q, r;

        /* Tant que le nombre actuel à plus de trois chiffres */
        while (n > 3)
        {
            /* Nombre de chiffres de la partie gauche */
            int nq;
            /* Groupe courant */
            int p = n / 3;
            /* Chaîne temporaire pour la conversion de la partie gauche
             * en int */
            char s_q[4] = {0};
            if (n % 3 == 0)
                p--;

            nq = n - p * 3;

            /* On copie le groupe courant dans une chaîne temporaire */
            strncpy(s_q, src, nq);
            s_q[nq] = '\0';

            /* On convertit le groupe courant en entier */
            q = strtol(s_q, NULL, 10);
            /* On convertit la partie droite du nombre en entier */
            r = strtol(src + nq, NULL, 10);

            /* On traduit le groupe courant en mot */
            nombre3chiffres(q, dst, p);

            if (q > 1 || p != 1)
            {
                /* On ajoute un espace si le on a terminé le mot pas un s */
                strcat(dst, " ");
            }

            /* On ajoute la traduction de la puissance de 1000 correspondant
             * au groupe actuel
             */
            strcat(dst, s_p3[p - 1]);

            if (p != 1 && q > 1)
            {
                /* Mille est invariable, millions et milliards, non */
                strcat (dst, "s");
            }

            if (r != 0)
            {
                /* La traduction n'est pas terminée, on ajoute un espace */
                strcat(dst, " ");
            }
            /* On saute les zéros a gauche du reste.
             *  Le reste devient le nouveau nombre à traduire.
             */
            src = sauterZeros(src + nq);
            /* Nouvelle longueur de la chaîne */
            n = strlen(src);
        }

        if (n > 0)
        {
            /* On termine par le groupe des centaines */
            nombre3chiffres(strtol(src, NULL, 10), dst, 0);
        }
    }
    return dst;
}

/* Le main de test de candide */
int main (void)
{

    char *x[] =
        { "0", "1", "2", "3", "4", "5", "7", "8", "9", "10", "11", "12", "13",
          "14", "15", "16", "17", "18", "19", "20", "21", "29", "30", "40", "42",
          "51",
          "60", "69", "70", "71", "77", "80", "81", "85", "90", "91", "99", "100",
          "101",
          "110", "130", "173", "196", "200", "205", "217", "223", "256", "268",
          "273",
          "280", "297", "734", "1000", "1001", "1017", "1020", "1032", "1111",
          "2000",
          "2100", "2200", "3003", "3780", "10000", "10005", "10900", "11000",
          "11700",
          "12000", "18805", "61400", "77010", "80000", "80078", "90000", "92002",
          "97459",
          "100000", "100007", "204003", "310857", "700005", "1000000", "2000000",
          "2001001",
          "72424600", "80000000", "79828480", "200000000", "708000000",
          "1000000000", "2000000000",
          "2000500000", "2000780001", "111111111111", "990990990990"
        };
    int i, n = sizeof x / sizeof *x;

    for (i = 0; i < n; i++)
    {
        char NombreEnLettres[256] = {0};

        z0zero(x[i], NombreEnLettres);
        if (NombreEnLettres != NULL)
            printf("%s.\n", NombreEnLettres);

    }

    return 0;
}


Le même sans commentaires :
#include <stdio.h>
#include <string.h> /* pour strlen, strcat, strncpy */
#include <stdlib.h> /* pour strtol() */

char *sauterZeros(char *s)
{
    while (*s == '0')
        ++s;

    return s;
}



void nombre1chiffre(int n, char *dst)
{
    char *s_chiffres[] =
    {
        "zero", "un", "deux", "trois", "quatre",
        "cinq", "six", "sept", "huit", "neuf",
    };

    strcat(dst, s_chiffres[n]);
}


void nombre2chiffres(int n, char *dst, int p)
{
    char *s_dizaines[] =
    {
        "vingt", "trente", "quarante", "cinquante",
        "soixante", "soixante", "quatre-vingt", "quatre-vingt"
    };

    /* Nombre entre 11 et 19 */
    char *s_pdizaines[] =
    {
        "dix", "onze", "douze", "treize", "quatorze",
        "quinze", "seize", "dix-sept", "dix-huit", "dix-neuf",
    };

    int q = n / 10;
    int r = n % 10;

    if (n >= 10  && n <= 19)
        strcat(dst, s_pdizaines[r]);
    else
    {
        if (q == 0)
            nombre1chiffre(r, dst);
        else
        {
            strcat(dst, s_dizaines[q - 2]);
            if (q == 7 || q == 9)
                r += 10;

            if (q == 8 && r == 0)
                if (p != 1)
                    strcat(dst, "s");

            if (r != 0)
            {
                if ((r == 1 || r == 11) && q != 8 && q != 9)
                    strcat(dst, " et ");
                else
                    strcat(dst, "-");

                if (r >= 10)
                    strcat(dst, s_pdizaines[r - 10]);
                else
                    nombre1chiffre(r, dst);

            }
        }
    }
}



void nombre3chiffres(int n, char *dst, int p)
{
    int q = n / 100;
    int r = n % 100;

    if (q == 0)
    {
        if (p != 1 || n > 1)
            nombre2chiffres(n, dst, p);
    }
    else
    {
        if (q > 1)
        {
            nombre2chiffres(q, dst, p);
            strcat(dst, " ");
        }

        strcat(dst, "cent");

        if (q > 1 && r == 0 && p != 1)
            strcat(dst, "s");

        if (r > 0)
        {
            strcat(dst, " ");
            nombre2chiffres(r, dst, p);
        }
    }
}



char *z0zero(char *src, char *dst)
{
    char const *s_p3[] =
    {
        "mille", "million", "milliard"
    };
    int n;


    dst[0] = '\0';

    src = sauterZeros(src);

    n = strlen(src);
    if (n == 0)
        nombre1chiffre(0, dst);
    else
    {
        int q, r;
        while (n > 3)
        {
            int nq;
            int p = n / 3;
            char s_q[4] = {0};
            if (n % 3 == 0)
                p--;

            nq = n - p * 3;
            strncpy(s_q, src, nq);
            s_q[nq] = '\0';

            q = strtol(s_q, NULL, 10);
            r = strtol(src + nq, NULL, 10);

            nombre3chiffres(q, dst, p);

            if (q > 1 || p != 1)
                strcat(dst, " ");

            strcat(dst, s_p3[p - 1]);

            if (p != 1 && q > 1)
                strcat (dst, "s");

            if (r != 0)
                strcat(dst, " ");

            src = sauterZeros(src + nq);

            n = strlen(src);
        }

        if (n > 0)
            nombre3chiffres(strtol(src, NULL, 10), dst, 0);

    }
    return dst;
}

/* Le main de test de candide */
int main (void)
{

    char *x[] =
        { "0", "1", "2", "3", "4", "5", "7", "8", "9", "10", "11", "12", "13",
          "14", "15", "16", "17", "18", "19", "20", "21", "29", "30", "40", "42",
          "51",
          "60", "69", "70", "71", "77", "80", "81", "85", "90", "91", "99", "100",
          "101",
          "110", "130", "173", "196", "200", "205", "217", "223", "256", "268",
          "273",
          "280", "297", "734", "1000", "1001", "1017", "1020", "1032", "1111",
          "2000",
          "2100", "2200", "3003", "3780", "10000", "10005", "10900", "11000",
          "11700",
          "12000", "18805", "61400", "77010", "80000", "80078", "90000", "92002",
          "97459",
          "100000", "100007", "204003", "310857", "700005", "1000000", "2000000",
          "2001001",
          "72424600", "80000000", "79828480", "200000000", "708000000",
          "1000000000", "2000000000",
          "2000500000", "2000780001", "111111111111", "990990990990"
        };
    int i, n = sizeof x / sizeof *x;

    for (i = 0; i < n; i++)
    {
        char NombreEnLettres[256] = {0};

        z0zero(x[i], NombreEnLettres);
        if (NombreEnLettres != NULL)
            printf("%s.\n", NombreEnLettres);

    }

    return 0;
}

Bilan


Cet exercice fait manipuler quelques fonctions standards(strlen, strncpy, strcat, strtol ), des oprérations arithmétiques(division et modulo), des opérateurs logiques(&&, ||, ! ), des chaînes de caractères. Finalement que des notions abordées dans le tuto de Mathéo21.
Il reste pourtant difficile, surtout à cause des multiples exceptions de la langue française concernant l'écriture des nombres.
Une grande partie de cet exercice, ne se résoud pas devant l'écran, mais avec un papier et un crayon, en essayant des exemples à la main.
Si on se limite aux nombres à 2 chiffres, voire 3, il est très accessible.
Un conseil, ne vous limitez pas à cette correction, et regardez les différentes solutions proposées.

Comme déjà dit, le prochain exercice sera beaucoup plus simple.

Merci à ceux qui ont participé à celui-ci.
Zeste de Savoir, le site qui en a dans le citron !
16 janvier 2010 à 23:40:08

Je n'ai pas encore lu la correction en détail, mais chapeau !
16 janvier 2010 à 23:47:46

Citation : GurneyH



je poste tel quel, je corrigerai en relisant!



Ça me paraît bon, il y a juste une coquille pour 17, 18 et 19.

Sinon, ta correction me paraît excellente, en particulier tes fonctions s'enchaînent comme lorsqu'on fait la traduction informelle dans la vie courante.
Perso, j'aurais juste créé une fonction de découpage du nombre en tranches de trois chiffres à partir de la droite mais ça peut se discuter.
16 janvier 2010 à 23:54:51

Je suis en train de remettre en forme(le zCode, c'est plus fort que moi!)
Mais shareman et candide, merci! :)

J'ai corrigé le plus gros! Reste des <secret> un peu partout. Je vois ça demain :-° ...
Les prochaines seront plus propres!


Zeste de Savoir, le site qui en a dans le citron !
17 janvier 2010 à 1:25:03

Merci pour la correction :)

Citation : candide

Perso, j'aurais juste créé une fonction de découpage du nombre en tranches de trois chiffres à partir de la droite mais ça peut se discuter.


C'est ce que j'avais fait dans ma première version :D
Mais bon, c'était pas très clair :euh:
Anonyme
17 janvier 2010 à 1:33:22

Salut, je sais que j'ai jamais vraiment participer ici, car le dernier exo me parraissait un peu trop dur ^^ , mais à quand le prochain exo (j'ai entendu qu'il sera plus simple :-° )
17 janvier 2010 à 4:49:56

Demande l'autorisation de mettre les tutos de se topic (au norme avec les cours du SDZ) sur mon site pour faire un peu d'ordre sur le SDZ
Car il me semble mieux adapté à cette situation si possible que chaque nouvelle exercice soit annoncé sur mon site et que se topic soit bloqué après avoir mit l'adresse de mon site en première page de se même topic
</span></span>
17 janvier 2010 à 9:08:42

Titre : zSommeChiffres
Mois : Second exercice de janvier 2010(durée 15 jours.)
Sujet : Calculer la somme des chiffres d'un nombre donné. Compter le nombre de fois où une somme est présente dans un intervalle donné.
Connaissances requises : Partie 1 : [Théorie] Les bases du débutant

Objectif


Pour tout nombre entier(dans sa représentation décimale), on peut faire la somme de ses chiffres, par exemple :

92538
9 + 2 + 5 + 3 + 8
92538 -> 27


L'exercice consiste à écrire La fonction
int zSommeChiffres(int n);
qui retourne la somme des chiffres d'un entier passé en paramètre.

Je vous propose le template suivante:
#include <stdio.h>

int zSommeChiffres(int n)
{
    ...
    return somme;
}

int main(void)
{
    int n1 = 92538;
    printf("%d -> %d\n", n1 , zSommeChiffres(n1));
    
    return 0;
}

Pour ceux qui sont vraiment allergiques aux fonctions, rien ne vous empêche de faire cet exercice en mettant le code dans la fonction main.

Connaissances requises : Les chaînes de caractères

Votre programme devra réaliser la même chose, mais les nombres seront représentés sous forme de chaine de caractères. Ainsi, votre programme devra être capable de faire la somme des chiffres du nombre :
1459784612340012340123478942651012315647894561230123456789


Le prototype de la fonction devient :

int zSommeChiffresChar(char *src);

Pour aller plus loin

Combien de nombres(en représentation décimale) entre 0 et N ont la somme de leurs chiffres égale à S.
Par exemple entre 0 et 1000000000, combien de nombres ont la somme de leurs chiffres égale à 27 ?
Le problème pourra être résolu avec l'une ou l'autre des fonctions(ou avec les 2 :lol: ).

Bon courage. ;)

edit : reformulation.
Zeste de Savoir, le site qui en a dans le citron !
17 janvier 2010 à 9:36:48

Bonjour :) ,

pour ton exercice, doit on reprendre ton template ou peut-on créer un tableau ?
17 janvier 2010 à 9:44:36

Citation : realmagma


pour ton exercice, doit on reprendre ton template ou peut-on créer un tableau ?



Le template, c'est juste un guide...
Tu utilises, bien sur, la méthode que tu désires.
Zeste de Savoir, le site qui en a dans le citron !
17 janvier 2010 à 10:43:32

@Gurney : Dans ta solution pense bien à rajouter le '\0' final après avoir utilisé strncpy. Car elle ne le rajoute pas automatiquement comme le dit le manuel.

Citation

La fonction strncpy() est identique, sauf que seuls les n premiers octets de src sont copiés. Ainsi, s'il n'y a pas de caractère nul dans les n premiers octets de src, la chaîne résultante ne disposera de caractère nul final. Dans le cas où la longueur src est inférieure à n, la fin de dest sera remplie avec des caractères nuls.

17 janvier 2010 à 11:07:10

Citation : Lithrein


@Gurney : Dans ta solution pense bien à rajouter le '\0' final après avoir utilisé strncpy. Car elle ne le rajoute pas automatiquement comme le dit le manuel.


Sauf erreur, avec une chaine initialisée à 0
char s_q[4] = {0};

Il n'y a pas de problème, si?
Zeste de Savoir, le site qui en a dans le citron !
17 janvier 2010 à 11:11:17

Non, il n'y a aucun problème sauf que cela pourrait introduire des débutants en erreur (s'ils ont survolé la citation du manuel).
De ce fait, je l'aurais mis de manière explicite pour qu'il voit qu'il y a un petit piège.
17 janvier 2010 à 11:13:13

Prem's! Je post mon code :p

/* Petite ébauche de  "zSommeChiffres"
 * Par: --------- Realmagma --------*/

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

int zSommeChiffres(int tableauNombre[], int tailleTableau);
int zSommeChiffresChar(char chaine[]);



int main()
{
    int resultatSomme = 0, resultatChaine = 0;
    int tableauNombre[6] = {1, 2, 3, 9, 5, 4}; /* Un petit tableau =D*/
    char chaine[] = "1234";

    resultatSomme = zSommeChiffres(tableauNombre, 6);
    printf("La somme de mon tableau de nombre vaut %d\n\n", resultatSomme);

    resultatChaine = zSommeChiffresChar(chaine);
    printf("La somme de la suite de nombre vaut %d\n\n", resultatChaine);
    return 0;
}

/*-----------------------------------------------------------------*/

int zSommeChiffres(int tableauNombre[], int tailleTableau)
{
    int somme = 0, i;

    for (i = 0; i < tailleTableau; i++)
        somme = somme + tableauNombre[i];

    return somme;
}

/*-----------------------------------------------------------------*/

int zSommeChiffresChar(char chaine[])
{
    int i = 0, somme = 0;

    for (i = 0; i < strlen(chaine); i++)
    {
        printf("chaine vaut %d\n", chaine[i]);
        somme = somme + chaine[i] %8; /* Un modulo règle ne problème des valeurs en ascii*/

    }
    return somme; /* On retourne la somme*/
}


J'ai quelque problèmes:

1-) Dans ma fonction "zSommeChiffresChar" je calcule la somme de mes chiffres en... ascii :waw:
Au lieu d'obtenir 10, j'ai 202:

49 (->'1') + 50 (->'2') + 51 (->'3') + 52 (->'4') = 202

Comment contourner le problème?
Que pensez-vous de mon code?

P.S: Ce n'est qu'une petite ébauche, j'essaye de ne pas trop me compliquer la vie.

Je vous remercie d'avance les zéros :) .

EDIT: J'ai réussit et corrigé dirrectement dans mon code.
somme = somme + chaine[i] %8;

=> Il manquait le petit modulo :)
Anonyme
17 janvier 2010 à 11:14:26

Ma solution (dépassé de 29 sec, :( ) :
#include <stdio.h>
#include <string.h>

int zSommeStr(const char *), zSommeInt(const long long);
int zMax(const long long, const int);

int main (int argc, const char * argv[]) {
	printf("%d avec zSommeStr\n", zSommeStr("800000"));
	printf("%d avec zSommeInt\n", zSommeInt(800000));
	printf("Nombre de nombres entre 1 et 30 dont "
		   "la somme des chiffres est 3 : %d\n", zMax(30, 3));
    return 0;
}

int zSommeStr(const char * str) {
	int len = strlen(str), res = 0, i;
	for (i = 0; i < len; i++)
		res += str[i]-'0'; /* On enlève '0' pour revenir à la  *
							* valeur du nombre depuis l'ASCII. */
	return res;
}

int zSommeInt(const long long nb) {
	int res = 0;
	long long i;
	for (i = 1; i < nb; i*=10)
		res += (nb%(i*10)-nb%(i))/i; 
	/* On sépare d'abord le chiffre qu'on veut	*
	* (suivi d'un ou plusieurs zéros), et on	*
	* enlève les zéros.							*/
	return res;
}

int zMax(long long nb, int val) {
	long long i, res = 0;
	for (i = 0; i < nb+1; i++)
		if (zSommeInt(i) == val) 
			res++;
	return res;
}
17 janvier 2010 à 11:18:12

Citation : Lithrein

Non, il n'y a aucun problème sauf que cela pourrait introduire des débutants en erreur (s'ils ont survolé la citation du manuel).
De ce fait, je l'aurais mis de manière explicite pour qu'il voit qu'il y a un petit piège.


Tu as raison, je corrige dans la journée...c'est corrigé. ;)

Citation : realmagma


Dans ma fonction "zSommeChiffresChar" je calcule la somme de mes chiffres en... ascii :waw:
Au lieu d'obtenir 10, j'ai 202:

49 (->'1') + 50 (->'2') + 51 (->'3') + 52 (->'4') = 202

Comment contourner le problème?


C'est une des petites astuces. ;)
Zeste de Savoir, le site qui en a dans le citron !
17 janvier 2010 à 12:36:54

Merci GurneyH, pour la correction, elle est vraiment bien faite ;)

Ahh, mais quelle différence entre les deux exercices :lol:

#include <stdio.h>

int zSommeChiffres(int n)
{
    int s = 0;
    for ( ; n ; n /= 10)
        s += n % 10;
    return s;
}

int zSommeChiffresChar(char *src)
{
    int s = 0;
    for ( ; *src ; src++)
        s += *src - '0';
    return s;
}

int main(void)
{
    int n = 4863149;
    char s[] = "4863149";

    printf("%d -> %d\n", n, zSommeChiffres(n));
    printf("%s -> %d\n", s, zSommeChiffresChar(s));

    return 0;
}


Citation : GurneyH

Pour aller plus loin


Combien de nombres entre 0 et N ont la somme de leurs chiffres égale à S.
Par exemple entre 0 et 1000000000, combien de nombres ont la somme de leurs chiffres égale à 27 ?
Le problème pourra être résolu avec l'une ou l'autre des fonctions(ou avec les 2 :lol: ).


Ça c'est bien, je vais voir quand j'aurai du temps :)
17 janvier 2010 à 12:41:53

Tu n'as pas compris quoi ?
Anonyme
17 janvier 2010 à 12:57:17

realmagma > Réfléchis un peu ;) Voici le numéro ASCII des nombres allant de 0 à 9
'0' > 48
'1' > 49
'2' > 50
'3' > 51
'4' > 52
'5' > 53
'6' > 54
'7' > 55
'8' > 56
'9' > 57

A partir de là, comment obtenir un 0 pour '0', un 1 pour '1'...C'est une bête soustraction ;)

Ton code, par contre, ne gère pas les nombres entiers (int).
17 janvier 2010 à 13:25:22

J'ai corrigé en éditant pendant que tu écrivais ;) . (Je n'avais pas vu ton message).
Il fallait rajouter un petit modulo.

Par contre pour la dernière partie, je ne vois absolument pas comment faire. :euh:
17 janvier 2010 à 13:32:45

Citation : realmagma


Par contre pour la dernière partie, je ne vois absolument pas comment faire. :euh:


Prend ton temps! ;) Si tu as la fonction zSommeChiffres, il n'y a pas (peu)de problèmes...
Zeste de Savoir, le site qui en a dans le citron !
17 janvier 2010 à 13:36:22

Une petite astuce plus jolie que le modulo :)
Ne regardez pas avant de chercher ;)

4 = '4' - '0'


Sympa cet exo je m'y met tout de suite :pirate:
Anonyme
17 janvier 2010 à 13:44:12

realmagma > Il manque stdio.h (pour printf).
Dans ta fonction zSommeChiffresChar, tu as :
for (i = 0; i < strlen(chaine); i++)

A chaque tour de boucle, tu recalcules la taille de la chaîne ! Pourquoi ne pas faire une petite condition pour vérifier si l'on est arrivé à la fin de la chaîne ?

Ton modulo par contre ne donne pas le bon résultat : essaye avec la chaîne "123456789".
Une fois de plus, pour l'ASCII, tu veux passer de 48 à 0, de 49 à 1, etc...La solution est toute proche ;)

Pouet_Forever > Mets ce que tu as mis en secret stp, il faut forcer les débutants à réfléchir.
17 janvier 2010 à 14:21:56

Citation de Monsieur_Jaky:

Citation : Monsieur_JaKy

realmagma > Il manque stdio.h (pour printf).
Dans ta fonction zSommeChiffresChar, tu as :

for (i = 0; i < strlen(chaine); i++)


A chaque tour de boucle, tu recalcules la taille de la chaîne ! Pourquoi ne pas faire une petite condition pour vérifier si l'on est arrivé à la fin de la chaîne ?

Ton modulo par contre ne donne pas le bon résultat : essaye avec la chaîne "123456789".
Une fois de plus, pour l'ASCII, tu veux passer de 48 à 0, de 49 à 1, etc...La solution est toute proche ;)

Pouet_Forever > Mais ce que tu as mis en secret stp, il faut forcer les débutants à réfléchir.



Aussitôt dit, aussitôt fait :) .

int zSommeChiffresChar(char chaine[])
{
    int i = 0, somme = 0;

    for (i = 0; i < strlen(chaine); i++)
        somme = somme + chaine[i] - '0'; /* -'0' pour ne pas aditionner leur valeur en ascii*/

    if(chaine[i] == '\0')
        return somme; /* On retourne la somme quand chaine[i] vaut '\0'*/
}


En revanche, je cherche encore pour la dernière partie.
Je vais y arriver vous verrez :diable: .
Anonyme
17 janvier 2010 à 14:35:58

Pourquoi ne places-tu pas ta condition de fin de chaîne dans la boucle for ?
Ton code reboucle toujours autant là, et en plus, ta condition ne se situe même pas dans la boucle, donc elle est totalement inutile...

for (i = 0; /* Condition */ ; i++)
17 janvier 2010 à 14:38:08

@ ttthebest : Ta fonction zSommeInt est inutilement compliquée ! Tu peux largement l'améliorer ;)

@ realmagma :

Citation : realmagma

int zSommeChiffresChar(char chaine[])
{
    int i = 0, somme = 0;

    for (i = 0; i < strlen(chaine); i++)
        somme = somme + chaine[i] - '0'; /* -'0' pour ne pas aditionner leur valeur en ascii*/

    if(chaine[i] == '\0')
        return somme; /* On retourne la somme quand chaine[i] vaut '\0'*/
}



En revanche, je cherche encore pour la dernière partie.
Je vais y arriver vous verrez :diable: .



Crée une variable pour strlen(chaine) ça t'évitera de le calculer à chaque tour de boucle :)
Ta dernière ligne est inutile ! Tu fais ta boucle tant qu'on est inférieur à strlen(chaine) donc après la sortie du for tu sera obligatoirement sur le '\0' ;)
D'ailleurs si je ne m'abuse, ton compilateur devrait te donner un warning parce que tu n'as pas de retour de fonction 'normale'. Le retour ne se fait que dans une condition :)

if(chaine[i] == '\0')
17 janvier 2010 à 14:57:22

Citation

D'ailleurs si je ne m'abuse, ton compilateur devrait te donner un warning parce que tu n'as pas de retour de fonction 'normale'


:euh: Non, il ne me dis rien.

J'ai corrigé pour le strlen, mais pas pour le if. En effet, je ne vois pas comment mettre ma condition dans le for:

for (i = 0; /* Condition */ ; i++)


Je vous redonne mon code (au cas où):
int zSommeChiffresChar(char chaine[])
{
    int i = 0, somme = 0, tailleChaine = 0;

    tailleChaine = strlen(chaine);

    for (i = 0; i < tailleChaine; i++)
        somme = somme + chaine[i] - '0'; /* -'0' pour ne pas aditionner leur valeur en ascii*/

    return somme;


Anonyme
17 janvier 2010 à 15:14:19

Voila, maintenant, c'est bon ;)
Ou pour éviter de calculer la taille de la chaîne :
for (i = 0; s[i] != '\0'; ++i)
17 janvier 2010 à 15:21:42

Bonjour

voici ma réponse :

#include <stdio.h>

int zSommeChiffres(int n);
int zSommeChiffresEgale(int n,int somme);
int zSommeChiffresChar(const char* str);

int main(void)
{
  int n1 = 92538;
  int n2 = 1000000000;
  int somme=27;
  const char *chaine ="1459784612340012340123478942651012315647894561230123456789";

  printf("%d -> %d\n", n1 , zSommeChiffres(n1));
  printf("%s -> %d\n", chaine ,zSommeChiffresChar(chaine));
  printf("entre 0 et %d , il y a %d nombre dont la somme est %d\n", n2 ,zSommeChiffresEgale(n2,somme),somme);

  return 0;
}

int zSommeChiffres(int n)
{
  int somme=n%10;
  if (n==0)
    return 0;//somme;
  return somme+zSommeChiffres(n/10);
}

int zSommeChiffresChar(const char* str)
{
  if (*(str)=='\0')
    {
      return 0;
    }
  int somme=(*(str)-48);
  return somme+zSommeChiffresChar(str+1);
}

int zSommeChiffresEgale(int n,int somme)
{
  int i;
  int nombreSommeEgale=0;
  for (i=0;i<=n;i++)
    {
      if (zSommeChiffres(i)==somme)
        {
          nombreSommeEgale++;
        }
    }
  return nombreSommeEgale;
}



et les résulats
92538 -> 27
1459784612340012340123478942651012315647894561230123456789 -> 228
entre 0 et 1000000000 , il y a 14033305 nombre dont la somme est 27

Process returned 0 (0x0)   execution time : 126.703 s
Press any key to continue.