IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

fonction qui marche avec un caractere mais pas dans une boucle


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre habitué
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Mai 2019
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ariège (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Mai 2019
    Messages : 11
    Par défaut fonction qui marche avec un caractere mais pas dans une boucle
    Bonjour!
    Je suis en train d'apprendre le C, et voici une erreur de programmation de ma part que je ne comprends pas.
    Mon but est de transformer les caractères ascii en binaire. Ma fonction marche plutôt bien quand je lui donne un seul caractère à transformer.
    par contre, si je lui donne deux lettres ou plus elle plante et fait quitter le programme.
    D’après mes tests, il semble que ce soit strcat() qui pose problème, mais pourquoi?
    Ensuite, n'hésitez pas à me donner votre avis sur l'aspect général de ce bout de code. je me doute qu'il doit y avoir plus simple pour transformer un string en binaire, mais je n'ai aucun recul.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
     
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
     
     
     
    void IntToBin(int n, char *Bin)
    {
      // divise par 2 le quotient jusqu'a le mettre a zero
      // on recupere tout les reste et on les mets bout a bout dans un string
     int entier=0;
     char convS[2];
     
     while(n/2!=0){
        // itoa converti un int en string. strcat le demande
        strcat(Bin,itoa(n%2,convS,10));
     
        n=n/2;
        if(n/2==0){
          strcat(Bin,itoa(n%2,convS,10));
          n=-1;
          }
        }
     
    // retourne le resultat qui est noté a l'envers par la partie precedente de la fonction
      char retourne [(strlen(Bin))];
      int x = strlen(Bin)-1 ;
     
        for(int i =0; i<(int)strlen(Bin);i++, x--){
        retourne[x]=Bin[i];
        }
      memcpy(Bin, retourne, strlen(Bin));
    }
     
     
     
    int main (int argc, char* argv[]){
    char binaire;
    char caractere[50];
    errno = 0;
     
    printf(" Caracteres?\n");
    fgets(caractere, 50, stdin);
     
    int x =0;
    while(x<(int)strlen(caractere)-1){
     
    IntToBin(caractere[x],&binaire);
    x=x+1;
    }
     
    system("PAUSE");  /* Pour la console Windows. */
    return 0;
    }

  2. #2
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 599
    Par défaut
    Bonjour,

    Pour convertir en texte binaire, il existe une fonction. A première vue tu la connais, elle s'appelle itoa(), mais elle ne fait pas partie de la bibliothèque standard. Donc on pourrait écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void IntToBin(int n, char *Bin)
    {
      itoa(n, Bin, 2 );
    }
    Mais si tu veux écrire un code qui n'utilise que les fonctions standards il faudra t'en passer.

    Des erreurs de ton code:
    - ligne 17: tu utilise strcat(), mais ça concatène à une chaine. Au premier appel ce que désigne Bin est aléatoire, tu dois rien y concaténer.
    - ligne 27: strlen() retourne la longueur de la chaine sans le terminateur. Il faut donc ajouter 1 pour réserver aussi le terminateur \0.
    - ligne 28: là il ne faut pas le -1.
    - ligne 39: tu prévois un unique caractère pour recevoir en réponse à ton appel toute une chaine, ça ça provoquera un plantage. un caractère en binaire pourra donner jusqu'à 9 char.
    - ligne 47, pas de -1

  3. #3
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 748
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 748
    Par défaut
    Je n'arrive pas à voir dans ton code mais je pense qu'il est foireux

    La concaténation en C n'est pas celle à laquelle tu penses.
    Toutes les fonctions de la librairie standard ne font pas d'allocations et s'appuient soit sur 1 taille soit sur le caractère sentinelle '\0'.

    Documentation cplusplus.com de strcat en anglais .
    La destination doit être suffisamment large pour y mettre destination + source + '\0'. Il n'y a pas d'allocation dynamique pour l'agrandir.
    Et il faut que la destination et la source soient des chaînes de caractères C (avec le caractère sentinelle '\0')

    Il faut passer par 1 log binaire pour avoir le nombre de bits d'1 nombre

    Documentation cplusplus.com de itoa en anglais .
    Documentation cplusplus.com de sprintf anglais : c'est la fonction à utiliser que @dalfab n'a pas mentionnée.

  4. #4
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 801
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 801
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par philippppe Voir le message
    Ma fonction marche plutôt bien quand je lui donne un seul caractère à transformer.
    par contre, si je lui donne deux lettres ou plus elle plante et fait quitter le programme.
    D’après mes tests, il semble que ce soit strcat() qui pose problème, mais pourquoi?
    Ta fonction ne marche pas du tout (même si elle "semble" fonctionner pour un caractère). En effet, ta fonction IntToBin() (un consensus assez généralisé voudrait qu'on la nomme plutôt "int2bin" mais c'est du détail) reçoit en paramètre un char *bin, donc l'adresse d'une zone à priori censée être assez large puisque la fonction y fait du strcat() à répétition (la fonction est obligée d'avoir confiance dans la zone reçue car de toute façon elle ne peut pas déterminer sa taille). Or tu lui passes l'adresse de char Binaire donc l'adresse d'une variable de taille "un char". Donc quoi que tu fasses, ta fonction n'a pas le droit de mettre plus d'un caractère dans cette zone.

    Partant de là, le code tombe en UB (Undefined Behavior), état dans lequel il peut se passer n'importe quoi y compris un semblant de bon fonctionnement. En effet, la programmation en C n'admet aucune erreur car pour aller le plus vite possible il ne fait aucune vérification sur la logique des instructions.

    Citation Envoyé par foetus Voir le message
    Je n'arrive pas à voir dans ton code
    Manque de sommeil (à 1h51 ça semble normal)
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 748
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 748
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Manque de sommeil (à 1h51 ça semble normal)
    Non c'est juste que lorsque j'ai vu son code, je me suis aperçu de sa chaîne à 1 caractère (et que @philippppe s'attendait à 1 concaténation str1 + str2) : j'en parle dans mon message.
    Je n'avais pas envie de compiler () et surtout comme tu l'as dit, tu as 1 comportement indéfini (U.B.) : donc avec des points d'arrêts tu devrais voir/ confirmer le problème rapidement.
    Donc voila, compilation, débogage, réflexion je n'avais trop envie

    Et l'autre truc son algo. J'ai mis 1 petit temps à comprendre ce qu'il voulait faire. Et il m'a cassé le crane concaténation, reverse + recopie juste pour 1 conversion décimale en binaire.
    On peut tout faire sur place sans recopie et sans surplus.
    Après si tu prends l'algo des divisions par 2, je me méfierai parce qu'il ne faut pas te tromper de case à partir de laquelle tu commences
    Je n'ai pas réfléchi/ posé l'algo, mais il n'y a peut-être pas de problème. Ou peut-être, qu'il faut juste faire en premier lieu 1 test si le nombre est pair ou impair (reste de la division par 2)

    Mais pour 1 algo sur place, je prendrai l'algo des soustractions des puissances de 2 : clair et précis
    Il faut vérifier mais voici 1 code qui donne l'idée (il n'y a pas d'allocations dynamiques par exemple) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    #include <stdio.h>
    #include <stdlib.h>
     
     
    size_t ilog2(size_t nb) {
        size_t log = 0;
     
        while (nb >>= 1) {
            log++;
        }
     
        return log;
    }
     
     
    void convert_int_to_bin(size_t nb, char* bin_str) {
        size_t tmp, power, count_array;
     
        tmp         = nb;
        power       = (1 << ilog2(nb)); // powl(2, ilog2(nb)); - math.h
        count_array = 0;
     
        while (power > 1) {
            if (tmp >= power) {
                bin_str[count_array] = '1';
                tmp -= power;
            } else {
                bin_str[count_array] = '0';
            }
     
            power /= 2;
            ++count_array;
        }
     
        bin_str[count_array] = ('0' + tmp);
        bin_str[count_array + 1] = '\0';
    }
     
     
    /*****************************************************************************/
    /***********************************  Main  **********************************/
    /*****************************************************************************/
     
    int main(int argc, char** argv)
    {
        char bin_str[33];
        size_t nb;
     
        for(nb=0; nb < 55; ++nb) {
            convert_int_to_bin(nb, bin_str);
     
            printf("%3lu: %s\n", nb, bin_str);
        }
     
     
        return EXIT_SUCCESS;
    }

  6. #6
    Membre émérite
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Juillet 2020
    Messages
    352
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Juillet 2020
    Messages : 352
    Par défaut
    Si on tient à compter le nombre de bits qu'il faut pour représenter un entier classiquement il faut passer par un log entier en base 2. ilog2 est une fonction qui renvoie le rang (0=LSB) du bit le plus significatif positionné à 1 et 0 pour la valeur 0. Une implémentation en C pourrait être :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    int ilog2(int value)
    {
        int log=0;
        while ( value>>=1 ) log++;
        return log;
    }
    Le nombre de bits nécessaires pour représenter un entier n sera ilog2(n)+1.
    Ensuite on alloue ce qu'il faut, soit la longueur en bit plus 1 caractère pour le zéro terminal, on se met à la fin et on remplit en checkant les bits du nombre.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    char *int2bin(int n)
    {
    	int bitlen=ilog2(n)+1;
    	char *res=malloc(bitlen+1);
     
    	char *cur=res+bitlen;
    	*cur--=0;
    	do {
    		*cur-- = n&1?'1':'0';
    	} while (n>>=1);
     
    	return res;
    }

  7. #7
    Membre Expert

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 582
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 582
    Par défaut Petites modifications
    Bonjour Foetus,

    La fonction ilog2() est erronée, pour 0 elle retourne 0. A défaut d'un hypothétique -oo on peut retourner -1 valeur impossible pour un entier et le tester au retour (même s'il semble plus pertinent de tester la valeur avant d'appeler ilog2).

    Le power = powl(2, ilog2(nb)); pique un peu les yeux. Un truc du type power = 1 << ilog2(nb); fait le même boulot à pas cher.

    Ceci étant, passer par les log pour ensuite calculer une puissance ne paraît pas nécessaire. Il y a la technique d'effacement des bits à 1 qui fonctionne bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
       int pwr2 = 0;
       for(int j = n; j > 0; pwr2 = j) j = j & (j-1);
    • 0 et les valeurs négatives renvoient pwr2 = 0
    • les autres valeurs retournent la valeur approchée par défaut de la puissance de 2 la plus proche de n


    Le code est un peu plus difficile à comprendre mais il est relativement efficace.

    Je sais que je suis un peu maniaque. Oui, beaucoup

    Salut

  8. #8
    Membre habitué
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Mai 2019
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ariège (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Mai 2019
    Messages : 11
    Par défaut
    Citation Envoyé par foetus Voir le message
    pour 1 algo sur place, je prendrai l'algo des soustractions des puissances de 2 : clair et précis
    Il faut vérifier mais voici 1 code qui donne l'idée (il n'y a pas d'allocations dynamiques par exemple) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    #include <stdio.h>
    #include <stdlib.h>
     
     
    size_t ilog2(size_t nb) {
        size_t log = 0;
     
        while (nb >>= 1) {
            log++;
        }
     
        return log;
    }
     
     
    void convert_int_to_bin(size_t nb, char* bin_str) {
        size_t tmp, power, count_array;
     
        tmp         = nb;
        power       = (1 << ilog2(nb)); // powl(2, ilog2(nb)); - math.h
        count_array = 0;
     
        while (power > 1) {
            if (tmp >= power) {
                bin_str[count_array] = '1';
                tmp -= power;
            } else {
                bin_str[count_array] = '0';
            }
     
            power /= 2;
            ++count_array;
        }
     
        bin_str[count_array] = ('0' + tmp);
        bin_str[count_array + 1] = '\0';
    }
     
     
    /*****************************************************************************/
    /***********************************  Main  **********************************/
    /*****************************************************************************/
     
    int main(int argc, char** argv)
    {
        char bin_str[33];
        size_t nb;
     
        for(nb=0; nb < 55; ++nb) {
            convert_int_to_bin(nb, bin_str);
     
            printf("%3lu: %s\n", nb, bin_str);
        }
     
     
        return EXIT_SUCCESS;
    }
    Un peu de temps parci parla pour essayer de comprendre aussi méthodiquement que possible chacune de vos réponses... et voilà que je bloque sur ton code foetus. Pourrais tu me l'expliquer aussi precisement que possible stp?
    j'ai commencé a etre perdu là
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
       while (nb >>= 1) {
            log++;
        }
    puis des le debut de ta fonction convert_int_to_bin

  9. #9
    Membre habitué
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Mai 2019
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ariège (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Mai 2019
    Messages : 11
    Par défaut
    Encore merci pour vos réponses, il va me falloir un peu de temps pour les comprendre et vous peut etre encore vous posez quelques questions.
    En voici dejà une simple:
    Citation Envoyé par dalfab Voir le message
    un caractère en binaire pourra donner jusqu'à 9 char.
    J'avais mis 2 en imaginant recupérer des 0 et des 1. donc un seul caracteres, plus un de securité au pif (désolé c'est très mal je sais ). Pourquoi 9 char? ceci serait un exemple de 9 char? 100100100

  10. #10
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 801
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 801
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par philippppe Voir le message
    Pourquoi 9 char? ceci serait un exemple de 9 char? 100100100
    On parle d'une "représentation binaire". Cette représentation s'intègre donc dans une string. Or une string doit contenir un espace de plus que le nombre de caractères "significatifs" pour pouvoir y stocker le '\0'. C'est pour ça que dans mon code (trop long, avec trop d'actions ) j'ai définit mes strings en mettant "+1" => pour que les autres lecteurs voient que je n'ai pas oublié le '\0'.

    Citation Envoyé par philippppe Voir le message
    J'avais mis 2 en imaginant recupérer des 0 et des 1. donc un seul caracteres
    Tu as confondu "nombres stoclé en mémoire" et "nombre affichable". Le nombre (par exemple) 123 sera codé en binaire 0x7B (1 char) mais sera affiché '1', '2', '3' (3 char). Et si on veut le stocker dans une string C, il faudra alors un char[3+1].
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [11g] Connexion qui marche sans service name mais pas avec @XE
    Par Antoun dans le forum Connexions aux bases de données
    Réponses: 7
    Dernier message: 22/01/2014, 23h39
  2. Réponses: 3
    Dernier message: 21/03/2011, 02h28
  3. Code qui marche sur un poste mais pas sur un autre
    Par TOSCAN dans le forum Langage
    Réponses: 5
    Dernier message: 11/06/2008, 21h09
  4. Réponses: 6
    Dernier message: 30/05/2008, 17h03
  5. Réponses: 8
    Dernier message: 19/05/2008, 09h00

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo