Forum Programmation.c++ Traduction d'un programme C++ en C

Posté par  . Licence CC By‑SA.
Étiquettes : aucune
-1
26
déc.
2015

Bonjour à tous,
J'ai un petit souci.
J'aimerais traduire ce programme C++ en C.
Il permet de récupérer dans un fichier une chaîne de caractères en allouant dynamiquement un pointeur sur la chaîne et affiche cette chaîne.

    #include <algorithm>
    #include <iostream>
    #include <vector>
    #include <fstream>


    using Buffer = std::vector< char >;
    void display( Buffer::const_iterator begin, Buffer::const_iterator end )
    {
        std::for_each( begin, end, []( char c )
        {
            std::cout << static_cast< int >( c ) << " ";
        } );
    }

    int main( int argc, char * argv[] )
    {
        //on prend le fichier en entrée du programme, donc on veut au moins 2 arguments.
        if ( argc < 2 )
        {
            std::cerr << "Usage: coin myfile" << std::endl;
            return EXIT_FAILURE;
        }

        // Le fichier, ouvert en lecture
        std::fstream file( argv[1], std::ios::in );

        if ( file.is_open() )
        {
            // Mon buffer 
            Buffer buffer( 20 );

            file.read( buffer.data(), 1 );

            if ( !file.fail() )
            {
                display( buffer.begin(), buffer.begin() + 1 );
            }

            // Tant qu'on n'a pas fini le fichier, on va le lire
            while ( !file.eof() && !file.bad() && !file.fail() && file.rdbuf()->in_avail() )
            {
                // Je lis le fichier, en ne lisant que ce que mon buffer peut contenir
                // Et je récupère le nombre d'octets lus pour plus tard
                auto read = file.readsome( buffer.data(), buffer.size() );

                //je ne vais afficher que ce que j'ai lu
                if ( read && !file.fail() )
                {
                    display( buffer.begin(), buffer.begin() + int( read ) );
                }
            }
            file.close();
            std::cout << std::endl;
        }
        else
        {
            std::cerr << "Couldn't open the file" << std::endl;
        }

        return 0;
    }

Merci d'avance !

  • # Bonjour

    Posté par  . Évalué à 4.

    Il faudrait déjà que tu postes le programme en C que tu as commencé à écrire et on pourra peut-être te dire ce qui ne va pas… ou au moins que tu précises sur quel point tu penses avoir des difficultés…

    Pourquoi veux-tu traduire ce programme en C ?

    • [^] # Re: Bonjour

      Posté par  . Évalué à 2. Dernière modification le 30 décembre 2015 à 08:32.

      Bonjour Marotte,
      Mon problème se situe précisément au niveau de l'allocation dynamique pour le buffer que je n'arrive pas à traduire en C. Je cherche à le faire pour m'exercer. C'est l'exo qui me demande de l'écrire dans les deux langages. Ce que j'ai fait:

              #include <stdio.h>
              #include <stdio.h>
              #include <stdlib.h>
              #include <string.h>
      
               int main(void) {
                      char * pointeur = malloc(20 * sizeof(char));
                      FILE *f = fopen("fichier.txt","r" );
                      if (!f) {
                          printf("Impossible d'ouvrir le fichier\n" );
                          return 1;
                      }
      
                     else
                      {
                       fgets(pointeur,20*sizeof(pointeur), f);
                       int k = 0; 
                       while (pointeur[k]) printf("%d\t", (int) pointeur[k++]);
                       free(pointeur);
                        }
                      fclose(f);
                      return 0;
                  }
      
              while (pointeur[k])
              {
                  printf("%d\t", (int)(pointeur[k]));
                  ++k;
              }

      Merci !

      • [^] # Re: Bonjour

        Posté par  . Évalué à 3.

        1ère remarque, la commande man est ton amie (sur linux, pas sur windows ou elle n'existe pas). C'est facile, je sais, mais à l'école on m'a toujours dis qu'il fallait dire le moins pertinent en premier :)

        2: avec man malloc, tu verras que malloc peut échouer. Du coup, de même que tu as vérifié le retour de fopen il serait de bon ton de vérifier le retour de malloc.

        3: ne pas utiliser de valeurs magiques. Ton fameux 20* qui apparaît à plusieurs reprises, mets-le plutôt dans une constante, comme ça par exemple: const int MAX_READ=20;. Ça te fera gagner du temps quand tu devras te relire, et quand tu t'apercevras que cette valeur est trop faible: un nom qui cause, et un remplacement unique dans l'ensemble de tes fichiers source.

        4: attention au style de codage. Si tu utilises une convention, utilises-la jusqu'au bout, ça t'éviteras pas mal de comportement non souhaités, aussi appelés: bugs. Par exemple, cette ligne: while (pointeur[k]) printf("%d\t", (int) pointeur[k++]); serait sûrement plus claire si coupée. D'ailleurs, un œil exercé pourrait ainsi repérer le copier/coller, et donc envoyer le code dans une fonction dédiée (collage tout à la fin, l'autre boucle while…).

        5: en tant que débutant, évites de combiner les opérateurs d'incrémentation et décrémentation avec d'autres. Selon qu'il s'agisse de post/pré - in/dé crémentation, les résultats peuvent être traîtres.

        6: encore le style de codage: tes indentations, soigne-les. L'indentation est ton amie, si tu la trahis, elle te rendras la même. Je sais, je me répète un peux rapport au point 4, mais il est possible que tu n'aies pas remarqué que tu utilises un pointeur déjà libéré à cause de ça…

        • [^] # Re: Bonjour

          Posté par  . Évalué à 2.

          J'ajouterais aussi que l'utilisation systématique des options de compilations -Wall et autres -pedantic permet de débusquer pas mal de mauvaises utilisations et éviter ainsi de prendre de mauvaises habitudes; d'expérience, clang tend (tendait?) à être plus prolifique sur ce point que gcc.
          Et tant qu'à faire, apprendre à utiliser des outils comme gdb, valgrind/memcheck et les analyseurs statiques, dans l'ordre inverse de difficulté mais aussi d'utilité je trouve ;-).

      • [^] # Re: Bonjour

        Posté par  . Évalué à 2.

        • j'ai l'impression que le deuxième while() n'est pas dans le corps d'un fonction, erreur de copier/coller ?
        • pour le premier while, je te conseille de toujours mettre son corps sur sa propre ligne (surtout si le corps est vide, i.e. dans le cas d'un simple ';'), voir de l'encadrer d'accolades : cela rend ton code plus clair et évite de commettre une erreur par inadvertance.
        • sizeof(char) != sizeof(pointeur) sauf si tu travailles avec une abi qui n'a que 256 octets d'adressage mémoire, ce qui me semble incompatible avec l'utilisation même du C/libc. Bref tu as un gros dépassement de tampon là !
        • tu ne free() pas ton malloc dans tous les chemins d'exécutions -> memory leak. (en C, le seul raii qui existe, c'est 'exit(2)' :p).
        • sinon qu'est-ce qui ne marche pas, spécifiquement ?
        • [^] # Re: Bonjour

          Posté par  . Évalué à 1.

          ps: tu peux utiliser sizeof(pointeur*);

        • [^] # Re: Bonjour

          Posté par  . Évalué à 1.

          Merci benja pour ta réponse.
          Je voulais juste généraliser mon programme au cas ou la taille de la chaine de caractères n'était pas connu à l'avance car là j'ai donné une taille fixe qui est 20. Le code en lui meme marche, il n'y a pas d'erreurs.

          • [^] # Re: Bonjour

            Posté par  . Évalué à 1. Dernière modification le 30 décembre 2015 à 11:28.

            Oui, et c'est justement une bonne idée. Je pointe juste une erreur dans la mise en oeuvre qui fait que actuellement tu autorises un dépassement de 3 à 7 fois (sur x86 32 ou 64 bits) la taille du buffer au lieu de t'en prémunir…

            $ cat t.c ; gcc t.c; ./a.out
            #include <stdio.h>
            int main(void){
            char *pointeur;
            printf("sizeof(pointeur)=%d\n",sizeof(pointeur));
            printf("sizeof(*pointeur)=%d\n",sizeof(*pointeur));
            printf("sizeof(char)=%d\n",sizeof(char));
            return 0;
            }
            
            sizeof(pointeur)=8
            sizeof(*pointeur)=1
            sizeof(char)=1

            Là dans ton appel à fgets c'est comme si tu dis "je t'autorise à écrire dans un tampon qui a de la place pour 20 pointeurs", alors qu'en réalité ton tableau n'a de la place que pour 20 charactères.

            • [^] # Re: Bonjour

              Posté par  . Évalué à 1.

              Et tu auras bien sûr corrigé que c'est sizeof(*ptr_type) qui donne la taille de l'objet pointé à la place de sizeof(type*) qui lui donne justement la taille d'un pointeur (qui aura toujours la même taille, quelle que soit le type de l'objet pointé, soit la taille d'une adresse mémoire).

            • [^] # Re: Bonjour

              Posté par  . Évalué à 1.

              Merci benja pour ta réponse.
              C'est cela l'objet de ma demande d'aide.
              Comment devrais je le modifier dans ce cas mon programme pour remédier à ce problème ?

              • [^] # Re: Bonjour

                Posté par  . Évalué à 2. Dernière modification le 30 décembre 2015 à 11:57.

                Tu dois utiliser la même taille des deux côté. Quelque chose comme:

                const int N_ELEMENTS = 20;
                ...
                malloc(N_ELEMENTS*sizeof(*pointeur));
                fgets(pointeur,N_ELEMENTS*sizeof(*pointeur));
                
                /* Ou encore */
                const int BUFFER_SIZE=20 * sizeof(char); // ou encore 20*sizeof(*pointeur);
                pointeur = malloc(BUFFER_SIZE);
                fgets(pointeur,BUFFERSIZE);

                Ou une n'importe quelle autre combinaison tant que fgets reçoit la même valeur que malloc a reçu. Je préfère la première forme car à chaque utilisation on sait exactement de quoi il s'agit, dans la deuxième forme il reste l'ambiguité : est-ce que buffer_size est exprimé en taille d'octes (= char) ou en nombre d'objet avec le risque de te tromper comme tu l'as justement fait.

                N'oublies pas aussi, comme on te l'a fait remarquer, de vérifier le retour de malloc, i.e. if (0 == pointeur) { return …/exit(1)} par example, et de fgets ! Extrait de la page "man fgets" : fgets() returns s on success, and NULL on error or when end of file occurs while no characters have been read (note: les pages man sont disponibles en traduction française aussi).

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.