Partage
  • Partager sur Facebook
  • Partager sur Twitter

[zConvert] Exercice pour débutants

Bonne chance à vous :)

12 juillet 2010 à 22:31:44

Salut à tous,
J'ouvre ce topic pour répondre à l'exercice proposé du mois de ... (osef). Voilà le lien http://www.siteduzero.com/forum-83-504 [...] html#r5179815

Bonne chance. :)
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 5:10:05

Une petite première tentative :) :

#include <stdio.h>

void itos(int n, char str[])
{
    static int i = 0;
    if (n == 0) { str[i] = '0'; return; }
    itos(n/10, str);
    str[i++] = n%10+'0';
}

int main(void)
{
  int n = 0;
  char str[50] = "";

  scanf("%d", &n);
  itos(n, str);
  printf("%s", str);

  return 0;
}
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 9:49:24

Voila le mien, codé il y a longtemps déjà (c'est un exercice d'Epitech j'espère qu'il marche je ne l'ai pas testé :o, Tek0 ne pas regarder ce code est dans votre interet).

static void   dispchar(const char c)
{
  write(1, &c, 1);
}

void    my_zconvert(int nb)
{
  if (nb < 0)
    {
      dispchar('-');
      nb = nb * -1;
    }
  if (nb / 10 != 0)
    my_zconvert(nb / 10);
  dispchar((nb % 10) + '0');
}



J'ai modifié les noms des fonctions pour coller a l'exercice.
J'ai également une version qui gère les bases, une qui stock dans un tableau ... Si ca intéresse, me contacter par mp.
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 10:36:22

voici mon code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void convertir(int n, char* chaine)
{
    char tmp,*tmp1=chaine;
    int reste=n;
    int i=0,j=0;

    while((n)!=0)
    {
        reste%=10;
        *(chaine++)+=reste+'0';
        reste=n/=10;
    }

    *(chaine)++='\0';
    chaine=tmp1;
    j=strlen(chaine)-1;

    while(i<=j)
    {
       tmp=chaine[i];
       chaine[i]=chaine[j];
       chaine[j]=tmp;
       ++i;
       --j;
    }
}

int main(void)
{
    int n;
    char chaine[50] = "";

    scanf("%d", &n);

    convertir(n, chaine);

    printf("%s", chaine);

    return EXIT_SUCCESS;
}
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 12:11:41

Citation : HighTam

#include <stdio.h>

void itos(int n, char str[])
{
    static int i = 0;
    if (n == 0) { str[i] = '0'; return; }
    itos(n/10, str);
    str[i++] = n%10+'0';
}

int main(void)
{
  int n = 0;
  char str[50] = "";

  scanf("%d", &n);
  itos(n, str);
  printf("%s", str);

  return 0;
}

Je trouve cette solution foireuse ... le static sur la variable de boucle c'est trop bizarre.. après 2 ou 3 appel à cette fonction tu écris n'importe où dans la mémoire ! En plus tu mets pas de '\0' dans ta chaine de caractères...
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 12:36:38

Citation : thecoun


le static sur la variable de boucle c'est trop bizarre.



S'il veut procéder récursivement, il a pas le choix pour savoir où écrire le chiffre courant.

Il me semble qu'il faudrait un prototype comme ça pour que ça marche avec une fonction récursive :

void itos(int n, char **p);


ou encore

char *itos(int n, char *p);


Citation : thecoun


après 2 ou 3 appel à cette fonction tu écris n'importe où dans la mémoire !



??

Citation : thecoun


En plus tu mets pas de '\0' dans ta chaine de caractères...



Il a pas besoin, au départ sa chaîne est nulle.

  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 12:44:19

Salut, voici mon code :
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define T (int)floor(log10(n))

char *convert(int n)
{
  int i;
  char *s = malloc(T * sizeof *s);

  while (*s)
    s++;

  *s = '\0';

  for (i = T; i >= 0; i--) {
    s[i] = n % 10 + '0';
    n /= 10;
  }

  return s;
}

int main(void)
{
  int n = 1000;
  char *s = convert(n);

  printf("%s",s);

  return 0;
}
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 13:03:39

Citation : candide


S'il veut procéder récursivement, il a pas le choix pour savoir où écrire le chiffre courant.


Alors là.. non en tout cas il manque quelque chose .. J'ai pris son code et j'ai ajouté une boucle dans le main et voilà le résultat :

1253
1253
123
1253123
123
1253123123
123
1253123123123
123
1253123123123123
123
1253123123123123123
123
1253123123123123123123
123
1253123123123123123123123
123
1253123123123123123123123123
123
1253123123123123123123123123123

Le static est gênant dans cette situation... il faut trouver une solution pour résoudre ce problème !
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 13:05:00

Citation : candide

Citation : thecoun

après 2 ou 3 appel à cette fonction tu écris n'importe où dans la mémoire !


??


La variable i est initialisée à zéro seulement au premier appel à la fonction. La fonction n'est donc utilisable que pour une conversion. On peut dire que c'est une fonction jetable... :-°

Citation : candide

Citation : thecoun

En plus tu mets pas de '\0' dans ta chaine de caractères...


Il a pas besoin, au départ sa chaîne est nulle.


Je dirais plutôt que ce gros bogue a été masqué par le fait qu'il appelle la fonction avec un tableau rempli de '\0' .
Sinon je fais ça comme fonction :
void itos(int n, char str[]) {}
int main()
{
   char t[50] = "123";
   itos(123, t);
}

Je n'ai pas besoin de faire plus, puisque j'appelle la fonction avec "123" . :p


@colb-seton: Tu n'alloues pas assez de bytes avec malloc . Le while après malloc a un comportement indéterminé.

@manrugby: *(chaine++)+=reste+'0'; devrait être *(chaine++)=reste+'0'; . Cela dit, tu utilises inutilement des expressions trop compliquées.
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 13:25:57

@HighTam: Comme l'ont fait remarquer les autres, l'utilisation de 'static' n'est pas forcement une bonne idée. Le but de créer une fonction est de pouvoir l'utiliser plusieurs fois. ^^
Note que si l'utilisateur entre une chaîne non initialisée, il manquera le '\0'. :)

@Nra: Le but c'est de mettre le nombre dans une chaîne, pas uniquement de l'afficher. :)
Plutôt que d'utiliser 1, tu pourrais utiliser les define prévus à cet effet :

#define	 STDIN_FILENO	0	/* standard input file descriptor */
#define	STDOUT_FILENO	1	/* standard output file descriptor */
#define	STDERR_FILENO	2	/* standard error file descriptor */


@manrugby: Mêmes remarques que Marc. :)

@Colb-Seton: Le calcul de la longueur de ton nombre est faux. Il faut rajouter +1. :)
Je ne sais pas ce que tu as voulu faire avec ton while, mais c'est faux. ^^
L'allocation de mémoire est aussi erronée, comme l'a dit marc.

@Marc: J'aime bien ta solution. :lol:
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 13:38:54

Le while, c'était pour mettre '\0' en fin de chaine. Pourquoi comportement indéterminé ?
Pour la longueur, j'avais mis +1 au début, mais je me retrouvé en sortie avec des caractères qui devaient pas être là.
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 13:46:45

Hé bien tu ne sais pas ce que contient la mémoire que tu viens d'allouer, donc faire *s++ est faux. ;)
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 14:00:12

Citation : Marc Mongenet

On peut dire que c'est une fonction jetable... :-°



Exact !

Citation : Marc Mongenet


Je dirais plutôt que ce gros bogue a été masqué par le fait qu'il appelle la fonction avec un tableau rempli de '\0' .



Pourquoi considères-tu que c'est un bogue ? Toutes les fonctions de chaînes par ex dépendent de la présence d'un 0 dans la chaîne, même si là il faut des zéros partout.

De toute façon, le zéro terminal n'est pas un problème, quand son quotient devient nul, il écrit sa sentinelle.
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 14:44:31

Citation : candide


Pourquoi considères-tu que c'est un bogue ? Toutes les fonctions de chaînes par ex dépendent de la présence d'un 0 dans la chaîne, même si là il faut des zéros partout.

De toute façon, le zéro terminal n'est pas un problème, quand son quotient devient nul, il écrit sa sentinelle.


On parle bien de la fonction suivante?
void itos(int n, char str[])
{
    static int i = 0;
    if (n == 0) { str[i] = '0'; return; }
    itos(n/10, str);
    str[i++] = n%10+'0';
}

Outre le problème de la variable statique qui fait que la fonction n'est utilisable qu'une seule fois, cette fonction a comme problèmes:
- elle récurse jusqu'à ce que n vaut 0, et à ce moment elle écrit '0' en str[0] .
- dépilant les récursions, elle écrase le '0' en str[0] en exécutant pour la 1re fois la dernière ligne (elle post-incrémente i ).
- elle ne termine pas ses écritures par '\0' , ce qui fait qu'elle ne crée pas une chaine, contrairement à ce que demande l'énoncé du problème; c'est un bogue majeur.
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 15:10:04

Bon pour conclure sur ce code, il est faux !! Je ne pense pas qu'une solution récursive soit possible (en tout cas plus efficace qu'une solution procedurale)
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 15:21:17

Citation : thecoun

Je ne pense pas qu'une solution récursive soit possible (en tout cas plus efficace qu'une solution procedurale)


Pourquoi non ?

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

void _convertir(int n, char * (*s)) {
  if (n >= 10)
    _convertir(n / 10, s);
  **s = n % 10 + '0';
  (*s)++;
}

void convertir(int n, char * s) {
  _convertir(n, &s);
  *s = '\0';
}

int main(void) {
  char s[50] = "";
  int n;
  
  scanf("%d", &n);
  convertir(n, s);
  puts(s);
  return EXIT_SUCCESS;
}
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 15:29:17

Salut

Rien de nouveau, mais histoire de participer.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

char *zConvert(int n, char *buf)
{
    int len = n ? log10(abs(n)) + 1 : 1;
    char *p = buf;
    int i = len - 1;

    if (n < 0)
    {
        *p++ = '-';
        n = -n;
        len++;
    }

    do
    {
        p[i--] = '0' + n % 10;
        n /= 10;
    }while(n);

    buf[len] = '\0';

    return buf;
}
int main(void)
{
    char buf[50];
    printf("%s\n", zConvert(-101, buf));

    return 0;
}


Elle est sympa ta fonction Pouet. :)
  • Partager sur Facebook
  • Partager sur Twitter
Zeste de Savoir, le site qui en a dans le citron !
13 juillet 2010 à 15:43:28

Citation : Pouet_forever

Pourquoi non ?


Solution de bourrin ^^.. Non c'est vrai ça fonctionne... ;)

Je viens de penser... Personne ne gère le cas des nombres négatifs :o si ?
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 15:50:24

Si, ya GurneyH. Pour ma fonction c'est pas très dur :

void convertir(int n, char * s) {
  if (n < 0) {
    n = -n;
    *s++ = '-';
  }
  _convertir(n, &s);
  *s = '\0';
}
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 16:00:55

Citation : Pouet_forever

Si, ya GurneyH. Pour ma fonction c'est pas très dur


Pour que ça fonctionne aussi avec INT_MIN , c'est un peu plus dur. ;)
#include <limits.h>
#include <stdio.h>

int abs(int a) { return a < 0 ? -a : a; }

int zConvert_r(int x, char *s) {
        int recursions = 0;
        if (x >= 10 || x <= -10)
                recursions = zConvert_r(x / 10, s);
        s[recursions] = abs(x % 10) + '0';
        return recursions + 1;
}

void zConvert(int x, char *s) {
        if (x < 0)
                *s++ = '-';
        s[zConvert_r(x, s)] = '\0';
}

int main(void) {
        int tests[] = { 0, 1, 10, 123, INT_MAX, -1 , -10, -123, INT_MIN };
        char s[16];
        int i;
        
        for (i = 0; i < sizeof tests / sizeof *tests; ++i) {
                zConvert(tests[i], s);
                puts(s);
        }
        return 0;
}
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 16:16:02

Au temps pour moi ! La solution de Pouet_forever est la solution récursive. L'utilisation d'un indice est maladroite !

Par contre :

Citation : Marc Mongenet

- elle récurse jusqu'à ce que n vaut 0, et à ce moment elle écrit '0' en str[0] .
- dépilant les récursions, elle écrase le '0' en str[0] en exécutant pour la 1re fois la dernière ligne (elle post-incrémente i ).


Je ne vois où est le problème ? C'était pour palier au problème de 0 ( Quand n = 0 )
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 16:17:25

Re-voici mon code, qui n'est plus bugué (normalement) :
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define T (int)floor(log10(abs(n+1)))+1 /* n+1 pour traiter le cas où n == 0 */

/* n <= 0 */
char *convert(int n)
{
  int i;
  char *s = malloc(T * sizeof *s);

  if (s == NULL)
    exit(EXIT_FAILURE);

  s[T] = '\0'; /*le caractère de fin de chaîne */

  for (i = T-1; i >= 0; i--) {
    s[i] = n % 10 + '0';
    n /= 10;
  }

  return s;
}

int main(void)
{
  int n = 1463;
  char *s = convert(abs(n));

  printf("%s",s);

  return 0;
}
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 16:55:02

Citation : HighTam

Je ne vois où est le problème ? C'était pour palier au problème de 0 ( Quand n = 0 )


C'est aussi ce qu'il m'avait semblé, mais c'était pour expliquer à Candide, qui me semble avoir confondu cela avec l'écriture de la sentinelle '\0' .
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 16:59:36

Citation : Colb-Seton

Re-voici mon code, qui n'est plus bugué (normalement)


Lol je faire mon chieur :
  • malloc sans free (ici c'est pas gênant mais dans une très grosse application
  • La ligne de preprocesseur #define T (int)floor(log10(abs(n+1)))+1 ne me plais pas car elle utilise 'n' qui dépend d'un contexte précis..
  • Tu alloues T cases et tu place '\0' sur la T + 1 ième case...
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 17:52:58

Citation : Marc Mongenet

mais c'était pour expliquer à Candide, qui me semble avoir confondu cela avec l'écriture de la sentinelle '\0' .



Exact, je n'avais pas examiné le code de HighTam assez en détail.
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 18:13:43

Citation : Marc Mongenet

Pour que ça fonctionne aussi avec INT_MIN , c'est un peu plus dur. ;)


Effectivement. :o
Ya possibilité d'avoir quelques explications stp ? :)
J'ai modifié mon code en me calquant sur le tiens. :-°

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

int abs(int n) {
  return n < 0 ? -n : n;
}

void _convertir(int n, char * (*s)) {
  if (n >= 10 || n <= -10)
    _convertir(n / 10, s);
  **s = abs(n % 10) + '0';
  (*s)++;
}

void convertir(int n, char * s) {
  if (n < 0)
    *s++ = '-';
  _convertir(n, &s);
  *s = '\0';
}

int main(void) {
  char s[50] = "";
  int n = INT_MIN;
  
  /* scanf("%d", &n); */
  convertir(n, s);
  puts(s);
  return EXIT_SUCCESS;
}
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 18:40:42

J'ai le même problème avec INT_MIN,
dans limits.h
#define INT_MAX		2147483647
#define INT_MIN		(-INT_MAX-1)

donc si tu fais -INT_MIN, tu débordes.

Je corrigerai.
  • Partager sur Facebook
  • Partager sur Twitter
Zeste de Savoir, le site qui en a dans le citron !
13 juillet 2010 à 18:51:24

Ma solution :

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

void swap(char *a, char *b)
{
    char c = *a;
    *a = *b;
    *b = c;
}

void reverse(char *str)
{
    unsigned i, n = strlen(str);
    for (i = 0 ; i < n / 2 ; i++)
        swap(str+i, str+n-i-1);
}

void zConvert(int n, char *str)
{
    char *temp = str;
    if (n < 0)
        *str++ = '-', temp++;
    do *str++ = (n%10) < 0 ?  -(n%10)+'0' : (n%10)+'0' ; while ((n /= 10));
    *str = '\0';
    reverse(temp);
}

int main(void)
{
  int n = 0;
  char str[50];

  scanf("%d", &n);
  zConvert(n, str);
  puts(str);

  return 0;
}
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 19:04:42

Citation : Pouet_forever

Citation : Marc Mongenet

Pour que ça fonctionne aussi avec INT_MIN , c'est un peu plus dur. ;)


Ya possibilité d'avoir quelques explications stp ? :)
J'ai modifié mon code en me calquant sur le tiens. :-°


Je ne suis pas absolument certain de mon code.
La norme C99 dit: When integers are divided, the result of the / operator is the algebraic quotient with any
fractional part discarded (This is often called ‘‘truncation toward zero’’.). If the quotient a/b is representable, the expression
(a/b)*b + a%b shall equal a.

Il me semble que ça implique que -9 % 10 = -9, mais je n'en suis pas certain. Je crois que c'est quelque-chose qui a évolué entre C89 et C99.

Edit: D'après http://stackoverflow.com/questions/190 [...] ulo-operation mon code est effectivement OK en C99, mais dépend de l'implementation en C89.
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2010 à 19:18:44

Il me paraît que la notion de reste dans une division euclidienne d'un entier négatif par un entier positif n'est pas claire !
  • Partager sur Facebook
  • Partager sur Twitter