Partage

Exercices pour débutants en C (suite)

Venez vous entrainer!

4 juillet 2010 à 19:22:10

Pas con meteor2 fallait y penser, mais es-ce réellement mieux ?

Bon je viens de finir mon zMath :P.

Citation : zMath

Expression à évaluer : 31 92 + 4 * 6 / 2 -
31 + 92 = 123
123 * 4 = 492
492 / 6 = 82
82 - 2 = 80
Résultat : 80



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

void	*xmalloc(size_t	size);
int	calcul(char	*expr);
int	is_numeric(int	n);
int	is_operator(int	operator);
size_t	needed_size(char *expr);
size_t	notvalid_expr(char *expr);

void	*xmalloc(size_t size)
{
	void *ptr;

	if ((ptr = malloc(size)) == NULL)
		{
			fprintf(stderr, "Virtual memory exhausted\n");
			exit(EXIT_FAILURE);
		}
	return (ptr);
}

int	operate(int a, int b, int operator)
{
	int value;

	value = 0;
	if (operator == '+')
		value = (a + b);
	else if (operator == '-')
		value = (a - b);
	else if (operator == '*')
		value = (a * b);
	else if (operator == '/')
		value = (a / b);

	printf("%d %c %d = %d\n", a, operator, b, value);

	return (value);
}

int	calcul(char *expr)
{
	int *pile;
	int i;
	int p;
	int pow;

	i = p = 0;
	pow = 1;
	pile = malloc((needed_size(expr)) * sizeof(int));
	while (expr[i])
		{
			if (is_numeric(expr[i]))
				{
					expr[i] -= 48;
					if (pow > 1)
						{
							--p;
							pile[p] *= pow;
							pile[p] += expr[i];
						}
					else
							pile[p] = (expr[i - 1] == '-') ? expr[i] * pow * -1 : expr[i] * pow;
					pow *= 10;
					++p;
				}
			else if (is_operator(expr[i]) && !is_numeric(expr[i + 1]))
				{
					pile[p - 2] = operate(pile[p - 2], pile[p - 1], expr[i]);
					p -= 1;
				}
			else
				pow = 1;

			++i;
		}
	return (pile[--p]);
}

int	is_numeric(int	n)
{
	return (n >= '0' && n <= '9');
}

int	is_operator(int	operator)
{
	return (operator == '+'
		|| operator == '-'
		|| operator == '*'
		|| operator == '/');
}

size_t	needed_size(char *expr)
{
	size_t	i;
	size_t	size;

	i = size = 0;
	while (expr[i])
		{
			if (expr[i] != ' ')
				++size;
			++i;
		}
	return (size);
}

size_t	notvalid_expr(char *expr)
{
	size_t	notvalid;
	size_t	i;

	i = notvalid = 0;
	while (expr[i])
		{
			if (expr[i] != ' ' && !is_numeric(expr[i])
			&& !is_operator(expr[i]))
				{
					notvalid = expr[i];
					break;
				}
			++i;
		}
	return (notvalid);	
}

int	main(void)
{
	char expr[] = "31 92 + 4 * 6 / 2 -";
	char notvalid;

	printf("Expression à évaluer : %s\n", expr);
	if ((notvalid = notvalid_expr(expr)))
		printf("Le caractere \"%c\" n'est pas autorisé\n", notvalid);
	else
		printf("Résultat : %d\n", calcul(expr));

    return (0);
}
4 juillet 2010 à 20:09:02

J'ai juste parcouru.

value = 0;
	if (operator == '+')
		value = (a + b);
	else if (operator == '-')
		value = (a - b);
	else if (operator == '*')
		value = (a * b);
	else if (operator == '/')
		value = (a / b);

un switch serait plus adapté, non? tu te l'interdit?

Sinon, toujours pareil
int	is_numeric(int	n)
{
	return (n >= 48 && n <= 57);
}

C'est pas le plus lisible.

Sinon, j'ai pas regardé plus en détail

edit: une gestion d'erreur minimale peut-être, au moins pour gérer la division par zéro?

Zeste de Savoir, le site qui en a dans le citron !
4 juillet 2010 à 20:10:28

Citation

Pas con meteor2 fallait y penser, mais es-ce réellement mieux ?

Pas vraiment, ce n'est pas vraiment clair...de toute façon en "vrai" on utilise ctype qui a l'avantage d'être portable.


J'ai regardé vite fait tes deux codes, et c'est franchement pas mal du tout! Je n'ai pas vu d'erreur. Le seul petit truc qui m'a tilté c'est
pile = malloc((needed_size(expr) + 1) * sizeof(int)); // tu alloues trop de mémoire, mais bon osef

Et pour certains passages, j'aurai un petit peu raccourci le code, et j'aurai utilisé les fonctions standards. Par exemple la fonction
size_t	notvalid_expr(char *expr)
{
	size_t	notvalid;
	size_t	i;

	i = 0;
	notvalid = 0;
	while (expr[i])
		{
			if (expr[i] != ' ' && !is_numeric(expr[i])
			&& !is_operator(expr[i]))
				{
					notvalid = expr[i];
					break;
				}
			++i;
		}
	return notvalid;	
}

ça aurait pu donner
char notvalid_expr(char *expr)
{
	while(*expr)
	{
	    if(!isdigit(*expr) && !strchr("+-*/", *expr) && *expr != ' ')
               return *expr;
	    expr++;
	}
	return 0;
}

4 juillet 2010 à 20:11:12

Citation : GurneyH

un switch serait plus adapté, non? tu te l'interdit?


Suivre la norme EPITECH c'est bien hein ? t'as juste le droit de pondre un code tout moche et incompréhensible. :)
4 juillet 2010 à 20:12:44

Oui je suis la norme epitech, le code est peut-être pas très beau, mais bon, pas moi qui l'es inventé, et vu que à la prochaine rentrée je vais devoir faire avec, j'essai de m'y habitué.

Sinon pour is_numeric oui c'est pas des plus lisible, mais c'est une très petite fonction, je pense quelle reste quand même assez lisible.

EDIT : J'alloue trop de mémoire ?
Toute les cases allouées sont pourtant utilisé non ?
Ha oui 1 de trop, l'habitude pour le \0 xD.

A et oui avec strchr, mais j'y pense jamais xD.
4 juillet 2010 à 20:30:58

Il a pas le choix --' je le bizute jusqu'a la rentree ^^ . Et Pouet, si tu veux faire debat sur la norme, viens sur le topic pitek, on en a fait un de 5 pages \o_
4 juillet 2010 à 21:28:12

bestpig > En fait, j'ai voulu faire l'exo zMaths moi aussi. Les résultats de ton code ne sont pas les même que les miens (qui me semblent justes), donc je pense que ça vient du tien. Mon code :

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

int pile[1000];
int sommet;

int main(void)
{
    char t_expr[] = "31  21 98+  - 56 78 -* ", *expr = t_expr, prec = 0;

    while(*expr)
    {
        if(isdigit(*expr))
            pile[sommet] = pile[sommet]*10 + (*expr - '0');
        else if(isdigit(prec))
            sommet++;

        if(strchr("+-*/", *expr))
        {
            switch(*expr)
            {
                case '+' : pile[sommet-2] += pile[sommet-1]; break;
                case '-' : pile[sommet-2] -= pile[sommet-1]; break;
                case '*' : pile[sommet-2] *= pile[sommet-1]; break;
                case '/' : pile[sommet-2] /= pile[sommet-1]; break;
            }
            pile[--sommet] = 0;
        }
        prec = *expr++;
    }

    printf("%s = %d", t_expr, pile[0]);

    return (0);
}


Citation : Pouet_forever

Citation : GurneyH

un switch serait plus adapté, non? tu te l'interdit?


Suivre la norme EPITECH c'est bien hein ? t'as juste le droit de pondre un code tout moche et incompréhensible. :)

+1
4 juillet 2010 à 21:30:03

Citation : Adroneus

Il a pas le choix --' je le bizute jusqu'a la rentree ^^ . Et Pouet, si tu veux faire debat sur la norme, viens sur le topic pitek, on en a fait un de 5 pages \o_


Y a pas à débattre c'est moche. ;)
M'enfin, c'est sur qu'il faut une norme où tout le monde code pareil. Même si ça pique les yeux...
Zeste de Savoir, le site qui en a dans le citron !
4 juillet 2010 à 21:42:33

J'ai debattu en pronant le fait que c'etait moche justement ^^
4 juillet 2010 à 21:55:04

@bestpig:
Encore rapidement, tu as un problème
un expressions
3 5 +

tu rencontrer l'oprérareur '+' tu dépiles 5, tu dépiles 3.
à l'arrivée 5 + 3, ça roule.

dans le cas d'une soustraction ou d'une division
3 5 -

tu dépiles 5 tu dépiles 3

à l'arrivée
5 - 3
c'est pas le bon résultat.

Toutes les opérations ne sont pas commutatives.
Je pense qu'il y a erreur sur ce point.
Zeste de Savoir, le site qui en a dans le citron !
4 juillet 2010 à 22:02:57

Citation : meteor2

bestpig > En fait, j'ai voulu faire l'exo zMaths moi aussi. Les résultats de ton code ne sont pas les même que les miens (qui me semblent justes), donc je pense que ça vient du tien.



Oui je confirme, c'est le principe de pile que j'avais pas percuté, bon ba je doit refaire xD.
Problème corriger :D, merci de l'avoir signalé, enfaite j'avais mal compris le principe de NPI ;)

EDIT : meteor2 ton code est foireux si on utilise des nombres négatifs.
Par exemple "3 -1 +"
Il confond la négation (qui est devant un chiffre) et l'opérateur
5 juillet 2010 à 16:52:17

Citation : bestpig

EDIT : meteor2 ton code est foireux si on utilise des nombres négatifs.
Par exemple "3 -1 +"
Il confond la négation (qui est devant un chiffre) et l'opérateur

Oui, il n'est pas prévu pour gérer les nombres négatifs.
5 juillet 2010 à 16:54:57

Ha ben dommage ^^.
Vu que ça m'a bien plus cette histoire de NPI, je travaille pour convertir une expression algébrique en forme NPI, c'est fun aussi xD.
12 juillet 2010 à 22:29:20

Titre: zConvert
Mois: Juillet
Sujet: Manipulation de nombres et de chaînes de caractères

zConvert



Comme cette question revient assez souvent, je me suis dit qu'il serait bien de le proposer en exercice.
Le but de cet exercice est très simple, récupérer un nombre entier entré par l'utilisateur et le convertir en chaîne de caractères (et afficher la chaîne :p ).
Le plus simple est de prendre un tableau de taille fixe, par exemple 50 (bien que ce soit grand).

*) Dans un premier temps on ne gérera que les nombres positifs,
*) Pour ceux qui ont réussis, vous pourrez vous attaquer aux nombres négatifs.

Pour ceux qui se sentent à l'aise, vous pourrez essayer de vous attaquer aux nombres à virgules. :)

Voilà un début de code pour ceux qui veulent :

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

void convertir(int n, char chaine[]) {
  /* Le code ici */
}

int main(void) {
  int n;
  char chaine[50] = "";
  
  scanf("%d", &n);
  
  convertir(n, chaine);
  
  printf("%s", chaine);
  
  return EXIT_SUCCESS;
}


Bon courage !

Un topic à été créé pour cet exercice : http://www.siteduzero.com/forum-83-539 [...] ebutants.html
12 juillet 2010 à 22:45:31

Ah un exercice!
Il colle très bien au langage C, je trouve, et peu de blabla!
C'est bien...


Zeste de Savoir, le site qui en a dans le citron !
17 juillet 2010 à 14:32:41

zChance - Correction



À la poursuite du vendredi 13

Il était demandé dans cet exercice d'écrire un programme en C qui devait donner la date du prochain vendredi 13 en français. Plusieurs pistes étaient possibles, certaines étaient relativement simples tandis que d'autres étaient un peu plus difficiles à trouver.


La solution naïve (SOLUTION_NAIVE)



La solution la plus naïve qui soit consistait à choisir un jour quelconque du calendrier assez proche du jour d'aujourd'hui pour être sûr de tomber sur le prochain vendredi 13 et non sur un autre (le mieux étant de choisir la date d'aujourd'hui) puis de parcourir le calendrier (à partir de ce jour) de jour en jour jusqu'à trouver un vendredi 13.
La seule difficulté est de parcourir le calendrier correctement en tenant compte du nombre de jours des mois et de l'exception du mois de février.

Une solution un peu plus élaborée (SOLUTION_NON_NAIVE)



Ici, plutôt que de choisir un jour quelconque du calendrier, choisissons le 13 du mois en cours (ou du mois précédent si aujourd'hui est avant le 13 du mois) puis au lieu d'avancer de jour en jour, avançons de mois en mois, on vérifie donc le 13 de chaque mois plutôt que chaque jour de l'année. Ainsi au lieu de vérifier 366 jours (dans le pire des cas) on ne vérifie que 12 jours (dans le pire des cas) soit un par mois.
Remarque : Cette démarche est généralement la notre lorsque l'on cherche le prochain vendredi 13 à l'aide d'un calendrier.

Une solution qui utilise les propriétés du calendrier grégorien (SOLUTION_NON_NAIVE_1)



Cette solution très semblable à la précédente consiste à calculer le jour de la semaine du 13 du mois. Pour plus de détail vous pouvez jeter un œil ici.

Une solution conforme POSIX (SOLUTION_POSIX)



Elle ne mettra pas tout le monde d'accord (en raison des normes) mais elle permet de voir une autre manière d'aborder le problème avec les fonctions de l'entête time.h. Elle fait la même chose que la solution naïve n°2 (elle ne vérifie que les treize du mois).
Attention au bug de l'an 2038 :-° . (cf Wikipédia - Bug de l'an 2038)

La solution complète


Si vous trouvez la solution illisible en raison des "defines" dites-le, je découperai alors le code.

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

/** #define SOLUTION_POSIX **/
/** #define SOLUTION_NAIVE **/
/** #define SOLUTION_NON_NAIVE **/
/**/ #define SOLUTION_NON_NAIVE_1 /**/

/** #define AVEC_TIME_H **/

#if !defined AVEC_TIME_H && defined SOLUTION_POSIX
#define AVEC_TIME_H
#endif

#ifdef AVEC_TIME_H
#include <time.h>
#endif

#define NB_MOIS                 (12)
#define VENDREDI                (5)
#define JOUR_VOULU              (13)

/* Nota : A leap year = Une année bissextile */
#define IS_LEAP(year)          ((year) % 400 == 0) || ((year) % 100 != 0 && (year) % 4 == 0)

#if defined SOLUTION_NAIVE || defined SOLUTION_NON_NAIVE
typedef struct date_s {
    int sjour; /* Jour de la semaine : 0..6 Dimanche..Lundi */
    int mjour; /* Jour du mois : 1..31 */
    int mois; /* Numero du mois : 0..11 */
    int annee; /* Numero de l'annee */
} date_t;
#endif

#ifdef SOLUTION_POSIX
time_t
vendredi_13 (void) {
    time_t tmp = 0;
    struct tm date;
    int mois[2][NB_MOIS] =
        {
            {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
            {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, /* Bissextile */
        };

    tmp = time(NULL);
    date = *localtime(&tmp);

     /* On se place sur le 13 du mois en cours
        et s'il est déjà passé sur celui du mois suivant */
    if (date.tm_mday < JOUR_VOULU)
        date.tm_mday += JOUR_VOULU - date.tm_mday;
    else if (date.tm_mday > JOUR_VOULU)
        date.tm_mday += (mois[IS_LEAP(1900 + date.tm_year)][date.tm_mon] - date.tm_mday + JOUR_VOULU);
    else
        date.tm_mday += mois[IS_LEAP(1900 + date.tm_year)][date.tm_mon];

    tmp = mktime(&date);

     /* On vérifie si le 13e jour de mois en cours de vérification est un vendredi */
    while (date.tm_wday != VENDREDI || date.tm_mday != 13) {
        date.tm_mday += mois[IS_LEAP(1900 + date.tm_year)][date.tm_mon];
        tmp = mktime(&date);
    }

    return tmp;
}
#endif

#ifdef SOLUTION_NAIVE
date_t
vendredi_13 (void) {
#ifdef AVEC_TIME_H
    time_t timestamp = time(NULL);
    struct tm * jour_actuel = localtime(&timestamp);
#endif
    date_t date;
    int mois[2][NB_MOIS] =
        {
            {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
            {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, /* Bissextile */
        };

#ifdef AVEC_TIME_H
    date.sjour = jour_actuel->tm_wday;
    date.mjour = jour_actuel->tm_mday;
    date.mois = jour_actuel->tm_mon;
    date.annee = 1900 + jour_actuel->tm_year;
#else
    /* /!\       Mettre à jour regulierement       /!\ *
     * On choisit le jour le plus proche d'aujourd'hui */
    date.sjour = 6; /* Samedi */
    date.mjour = 17;
    date.mois = 6; /* Juillet */
    date.annee = 2010;
#endif

    do {
        if (date.mjour < mois[IS_LEAP(date.annee)][date.mois]) {
            ++date.mjour;
            ++date.sjour;
        }
        else {
            ++date.mois;
            ++date.sjour;
            date.mjour = 1;
        }

        if (date.mois == 12) {
            ++date.annee;
            date.mois = 0;
        }
    } while (date.sjour % 7 != VENDREDI || date.mjour != 13);

    return date;

}
#endif

#ifdef SOLUTION_NON_NAIVE
date_t
vendredi_13 (void) {
#ifdef AVEC_TIME_H
    time_t timestamp = time(NULL);
    struct tm * jour_actuel = localtime(&timestamp);
#endif
    date_t date;
    int mois[2][NB_MOIS] =
        {
            {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
            {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, /* Bissextile */
        };

#ifdef AVEC_TIME_H
    if (jour_actuel->tm_mday > 13) {
         /* On se replace sur le 13 */
        date.mjour = 13;
        date.sjour = abs(jour_actuel->tm_wday - (jour_actuel->tm_mday - 13) % 7);
        date.mois = jour_actuel->tm_mon;
        date.annee = 1900 + jour_actuel->tm_year;
    } else if (jour_actuel->tm_mday < 13) {
        /* On se place sur celui du mois precedant */
        date.mois = jour_actuel->tm_mon - 1;
        date.annee = (date.mois < 0) ? 1900 + jour_actuel->tm_year-1 : 1900 + jour_actuel->tm_year;
        date.sjour = abs(jour_actuel->tm_wday - (mois[IS_LEAP(date.annee)][date.mois] + (jour_actuel->tm_mday - 13)) % 7);
        date.mjour = 13;
    } else {
        date.sjour = jour_actuel->tm_wday;
        date.mjour = jour_actuel->tm_mday;
        date.mois = jour_actuel->tm_mon;
        date.annee = 1900 + jour_actuel->tm_year;
    }
#else
    /* /!\            Mettre à jour regulierement            /!\ *
     * On choisit le 13e jour du mois s'il est passe ou en cours */
    date.sjour = 2; /* Mardi */
    date.mjour = 13;
    date.mois = 6; /* Juillet */
    date.annee = 2010;
#endif

    do {
        date.sjour += mois[IS_LEAP(date.annee)][date.mois++];

        if (date.mois == 12) {
            ++date.annee;
            date.mois = 0;
        }
    } while (date.sjour % 7 != VENDREDI || date.mjour != 13);

    return date;

}
#endif

#ifdef SOLUTION_NON_NAIVE_1
int
vendredi_13 (int jour, int mois, int annee) {
    int a = (14 - mois) / 12;
    int y = annee - a;
    int m = mois + 12*a - 2;

    return (jour + y + y/4 - y/100 + y/400 + (31*m)/12) % 7;
}
#endif

int
main (void) {
    char const * const mois[] = {"Janvier", "Fevrier", "Mars", "Avril", "Mai", "Juin", "Juillet", "Aout", "Septembre", "Octobre", "Novembre", "Decembre"};
#ifdef SOLUTION_POSIX
    time_t vendredi = vendredi_13();
    struct tm date = *localtime(&vendredi);

    printf("Vendredi %02d %-9s %d\n", date.tm_mday, mois[date.tm_mon], 1900+date.tm_year);
#endif

#ifdef SOLUTION_NAIVE
    date_t vendredi = vendredi_13();
    printf("Vendredi %02d %-9s %d\n", vendredi.mjour, mois[vendredi.mois], vendredi.annee);
#endif

#ifdef SOLUTION_NON_NAIVE
    date_t vendredi = vendredi_13();
    printf("Vendredi %02d %-9s %d\n", vendredi.mjour, mois[vendredi.mois], vendredi.annee);
#endif

#ifdef SOLUTION_NON_NAIVE_1
    int a, m, s;
    for (a = 2010, s = 0; a <= 2011 && !s; a++)
        for (m = 7; m <= 12 && !s; m++)
	    if (vendredi_13(13, m, a) == 5) {
		printf("Vendredi %02d %-9s %d\n", 13, mois[m-1], a);
		s = 1;
	    }
#endif

    return EXIT_SUCCESS;
}


Améliorations possibles


* Ne pas se limiter à un vendredi mais en afficher autant que l'utilisateur veut.
* Trouver le prochain vendredi à partir d'une date
17 juillet 2010 à 22:08:24

Deja, je te remercie du temps que tu passes sur les exos et sur les corrections, je suis entrain de la lire et je vais mettre juste une ou deux petites choses anodines que je lis au fur et a mesure ^^

Premiere remarque : tu inclue stdlib.h, dans ce cas pourquoi recoder une fonction valeur absolue alors qu'il y a la fonction labs ?

précédaent (solution non naive), étaient, sorry mais celles la m'ont saute aux yeux :-°

Ensuite je crois, si j'ai bien compris que tu as fait une erreur dans tes commentaires de la solution POSIX

Perso, les defines me genent pas, mais apres comme ce topic s'oriente topic pour debutants, j'sais pas si le code est tres lisible, a voir..

(je vais editer si besoin)

Moi j'ai rien d'autre a redire, n'ayant pas de compilo sous la main je pourrai pas tester d'ici 2~3 jours. Mais comme d'hab, j'aime beaucoup ta maniere de coder ^^

vala, c'tout ;)
17 juillet 2010 à 23:45:07

Tout d'abord, merci pour tes encouragements Adroneus ainsi que pour tes remarques.

Pour la fonction `abs' il me semblait qu'elle était définie dans math.h, j'aurais du vérifier :-° .

Ensuite, je te remercie pour les fautes d'orthographes que tu as relevée par contre pour "étaient" je ne vois pas où est le problème, enfin pour l'erreur dans les commentaires de la solution POSIX je ne vois pas (à part l'erreur de frappe sur "vendredi").
18 juillet 2010 à 2:50:56

Bon bah un autre encouragement. :)
Lithrein, tu passes du temps, et tu mets beaucoup de soin, à tes exos et à tes corrections.

Merci pour ça, en attendant le prochain!
Zeste de Savoir, le site qui en a dans le citron !
18 juillet 2010 à 14:25:34

Citation

Plusieurs pistes était possibles


;)

Et pour le commentaire : on ne se place pas sur le vendredi 13 du mois en cours mais sur le 13 du mois en cours, rien ne te dit que le 13 est un vendredi.. enfin c'est comme ca que j'ai compris ta solution x) apres je me gourre peut etre

Edit : de rien pour les comments & encouragements, je pense que c'est le minimum qu'on puisse faire quand on voit le boulot fourni
18 juillet 2010 à 15:08:47

Serieux, arrete ton flood avec ta pub alakon, t'es lourd la..
30 août 2010 à 22:30:55

zConvert - Correction



L'exercice n'était pas très difficile en soit, le seul hic était de gérer le cas où n == INT_MIN.
Pour calculer un modulo il suffit de faire : m % n = m - (m / n) * n
Si le résultat est négatif, on prend la valeur absolue du nombre (on 'transforme' le nombre en nombre positif).
Pour la solution itérative, il fallait simplement trouver le nombre de chiffres à mettre dans la chaîne puis faire une suite de modulos 10 pour arriver jusque 0.
Voilà la solution :

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

void convertir(int n, char * s) {
  int i, nb_de_chiffres, tmp;
  
  /* Si le nombre est négatif, on mets un signe '-' */
  if (n < 0)
  /* J'incrémente le pointeur, on aurait aussi pu faire :
   s[0] = '-';
   nb_de_chiffres = 1;
   */
    *s++ = '-';
  
  tmp = n;
  nb_de_chiffres = 0;
  /* On calcule le nombre de chiffres qu'il y a */
  do {
    tmp /= 10;
    nb_de_chiffres++;
  } while (tmp != 0);
  
  /* On mets les chiffres dans la chaîne */
  /* On part de nb_de_chiffres-1 nb_de_chiffresusqu'à 0 */
  for (i = nb_de_chiffres-1; i >= 0; i--) {
    /* Une valeur absolue pour gérer le modulo négatif */
    s[i] = abs(n - ((n / 10) * 10)) + '0';
    n /= 10;
  }
  
  /* On met le '\0' terminal */
  s[nb_de_chiffres] = '\0';
}

int main(void) {
  char s[50] = "";
  int n = 0;
  
  scanf("%d", &n);
  convertir(n, s);
  puts(s);
  return EXIT_SUCCESS;
}


En récursif, c'est différent, on a pas besoin de calculer le nombre de chiffres à mettre. La récursion sert à ça. On appelle la fonction tant que le nombre est différent de 0 et ensuite on rempli la chaîne. On peut soit se balader un indice pour mettre dans la chaîne, soit utiliser le pointeur directement.
La solution utilise le pointeur :

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

void _convertir(int n, char * (*s)) {
  /* On appelle tant que cette conditon n'est pas remplie : -10 <= n <= 10 */
  if (n >= 10 || n <= -10)
    _convertir(n / 10, s);
  /* On déférence le pointeur 2 fois (pointeur sur pointeur) */
  **s = abs(n - ((n / 10) * 10)) + '0';
  /* On incrémente le pointeur seul (pas **s) */
  (*s)++;
}

void convertir(int n, char * s) {
  if (n < 0)
    *s++ = '-';
  /* On envoie l'adresse du pointeur pour pouvoir le modifier
   * directement dans la fonction */
  _convertir(n, &s);
  *s = '\0';
}

int main(void) {
  char s[50] = "";
  int n = 0;
  
  scanf("%d", &n);
  convertir(n, s);
  puts(s);
  return EXIT_SUCCESS;
}


Merci aux participants. :)

PS : Si vous voulez plus de détails, dites le moi. :-°

Je trouve ça dommage que sur un exercice qui revient aussi souvent que celui-là on ait pas eu plus de participants, c'est vraiment démoralisant. :(
31 août 2010 à 14:03:38

Tout d'abord, merci pour ta correction. Mais, j'aurais deux, trois remarques :
* Bien que la fonction valeur absolue soit simple à implémenter, stdlib.h la fournie déjà, donc pas besoin de s'embêter
* Le nom de tes variables n'est pas toujours très explicite. j pour le nombre de chiffres du nombre, par exemple.

Autrement, j'aime bien, c'est simple.
31 août 2010 à 14:12:44

Si je me souviens bien Marc a dit que dans les versions anterieures au C99, le resultat du modulo de nombres negatif dependait de l'implementation.. Sinon, ben +1 Lithrein ^^
31 août 2010 à 14:22:27

Lithrein, tu t'occupes toujours des exos?

J'espère! ;)

edit: j'espère également que le post va rester en post it!
Egalement, qu'en postant, ce topic va apparaitre dans les discussions du forums C.
2 hypothèses...
Le SDZ est maintenu par des gens avec des moufles(possible)...
seconde hypothèse, la disparition est voulue(probable)! :-°
Zeste de Savoir, le site qui en a dans le citron !
31 août 2010 à 16:58:27

@Gurney : Oui, je m'occupe toujours des exos. J'attendais juste que Pouet clôture son exercice.
<hs>J'ai pas compris tes hypothèses surtout le rapport avec les moufles :-° </hs>
31 août 2010 à 18:12:13

Etant donne que des modos vont passer sur ce topic, on s'abstiendra d'expliquer la theorie de GurneyH ^^
31 août 2010 à 18:51:44

Citation : Lithrein

* Bien que la fonction valeur absolue soit simple à implémenter, stdlib.h la fournie déjà, donc pas besoin de s'embêter
* Le nom de tes variables n'est pas toujours très explicite. j pour le nombre de chiffres du nombre, par exemple.


Citation : Adroneus

Si je me souviens bien Marc a dit que dans les versions anterieures au C99, le resultat du modulo de nombres negatif dependait de l'implementation..


Fix'd. ;)

@Lithrein : Fallait me le dire, je l'aurais clôturé depuis longtemps. :-°
31 août 2010 à 20:25:30

zCalc - 1er Septembre - 30 Septembre



Depuis longtemps (toujours ?) faire une calculatrice est un exercice assez courant pour les débutants. Mais leurs fonctionnalités sont un peu limitée pour être appelée calculatrice. Ce serait plus des calculettes.

Niveau débutant



Vous devez faire une calculatrice qui propose 4 opérations (+, -, *, /) sur un nombre de nombres indéfini. Pour remettre à 0 la calculatrice tapez c. Pour quitter le programme tapez q.

** zCalc (niv. 1) **

Entrez un nombre : 15.
Quelle opération (+, -, *, /, c, q) : 15 +
Entrez un nombre : 15
Quelle opération (+, -, *, /, c, q) : 30 *
Entrez un nombre : 2
Quelle opération (+, -, *, /, c, q) : 60 c
Entrez un nombre : 0
Quelle opération (+, -, *, /, c, q) : 0 q


Les lignes avec qui demande l'opération ont cette syntaxe : 'Quelle opération (+, -, *, /, q, e) : resultat_du_calcul '. Le symbole de l'opération doit apparaître sur cette ligne.

Niveau intermédiaire



Dans cette partie, votre calculatrice soit parser une expression mathématique qui utilise la notation infixe (soit la forme habituelle).
Les opérateurs à implémenter sont : les parenthèses, +, -, *, /.
La commande c a pour effet de vider la variable /ans/, et la commande q permet dequitter le programme.
Le dernier résultat doit être accessible via la variable /ans/(qui est l'abréviation de answer)


** zCalc (niv. 2) **

>> (2+3)*(2-3)
-5
>> ans/ans
1
>> -9*ans
-9
>> c
>> ans
0
>> q


Allez plus loin



* Ajouter d'autres opérateurs : l'opérateur puissance ^, racine carré noté sqrt.
* Ajouter d'autres fonctions : ln, log de base b noté logb, cos, sin, tan, acos, ...
* Permettre à l'utilisateur d'utiliser des variables (pour commencer les lettres de l'alphabet puis permettre l'utilisation de variables de plusieurs lettres (Attention ans est un 'mot clé' de votre calculatrice il ne doit pas pouvoir être un nom de variable)).
* etc.

Bonne chance.
8 septembre 2010 à 12:28:46

Vous ne créez plus de topics pour les réponses ?

Exercices pour débutants en C (suite)

× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
  • Editeur
  • Markdown