Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Exercices] Venez vous entraîner !

Ce mois: Parseur de fonctions mathématiques

8 juin 2008 à 17:26:39

D'accord, on doit donc utiliser les exceptions que pour les fichiers illisibles ou autre, mais si on passe par exemple "AAA@58@P" à notre fonction de décompression, celle-ci doit faire son boulot sans renvoyer d'erreurs même si le format à la base n'est pas bon. C'est ça ?
  • Partager sur Facebook
  • Partager sur Twitter
8 juin 2008 à 17:29:11

Non, si la chaîne à décompresser n'est pas décompressable, c'est qu'il y a eu une erreur. Il faudrait donc le signaler à l'utilisateur.

On peut par exemple le faire en utilisant une exception. C'est dans ce sens là qu'il fallait lire la donnée.
  • Partager sur Facebook
  • Partager sur Twitter
Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
8 juin 2008 à 17:33:35

D'accord ;)
Merci beaucoup je vais lire ton tuto sur les exceptions
  • Partager sur Facebook
  • Partager sur Twitter
10 juin 2008 à 12:47:29

J'ai une petite question concernant la solution de l'exercice "Le plus grand nombre".

J'ai remarqué que plusieurs fois, tu utilisais des if avec des arguments entiers.
int n;
if(!n){
    // si n est nul
}


Or les structures conditionnelles attendent une expression booléenne et non entière. Le C++ apporte les variables booléennes et il faut les utiliser.
Donc pour être rigoureux avec le langage, il faudrait changer le !n en n==0.
if(n==0){
    // si n est nul
}


Cela facilite la lecture en plus.

Voilà, je trouve que pour une solution à un exercice qui vise à approfondire sa maîtrise du C++, il serait bon d'appuyer aussi sur les bonnes habitudes à prendre pour l'écriture du code et ne surtout pas emprunter les vieilles techniques du C. D'ailleurs, dans d'autres langages comme le Java, c'est strictement interdit d'utiliser une expression entière dans une structure conditionnelle.

Voilà, sinon je salue le fait de proposer des exercices accessibles qui permettent de s'améliorer en C++ et aussi régulièrement :)
  • Partager sur Facebook
  • Partager sur Twitter
10 juin 2008 à 15:38:23

Mmmh,
bonne remarque. Chez moi, ce n'est pas une "vieille haitude du C", car j'en ai jamais fait. Plus je programme, plus j'utilise ce genre de petits raccourcis.
Est-ce que c'est une mauvaise habitude ? Honnêtement, je sais pas. C'est un peu comme pour les transtypages, on devrait utiliser les "static_cast<>" mais personne ne le fait jamais, c'est trop lourd.

Mais tu as raison, je vais corriger ça. Ce sera plus clair pour les débutants qui n'ont pas l'habitude de ce genre de raccourcis.

Merci pour cette remarque.

P.S.: Juste comme ça, c'est pas parce que en JAVA c'est mal que c'est faux en C++. Le JAVA a aussi des choses "ignobles" comparés au C++. :)
  • Partager sur Facebook
  • Partager sur Twitter
Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
10 juin 2008 à 20:22:51

Citation : Nanoc

Juste comme ça, c'est pas parce que en JAVA c'est mal que c'est faux en C++. Le JAVA a aussi des choses "ignobles" comparés au C++. :)


Tout à fait, excuse-moi pour cette comparaison déplacée. :-°

Citation : Nanoc

Plus je programme, plus j'utilise ce genre de petits raccourcis.
Est-ce que c'est une mauvaise habitude ? Honnêtement, je sais pas.


Sans vouloir polluer ce topic (je sais que c'est pas vraiment le sujet), je trouve que personnellement les raccourcis sont à éviter au maximum. Tout dépend des raccourcis utilisés bien sûr mais dans la majorité des cas, ils utilisent une syntaxe peu intuitive pour gagner des lignes de codes et en compromettent la lisibilité. Et de plus, ils se basent souvent sur un certain "laxisme" du langage sur certains points, par exemple ici, le langage qui est peu regardant au niveau des types. Ce qui peut d'ailleurs signifier différentes choses selon le compilateur utilisé vu que ce point n'est pas clairement défini.

Pour moi, ces raccourcis sont à réserver à des codes personnels qu'on ne souhaite pas partager puisque dans un travail collectif, on vise à écrire du code lisible qui puisse être maintenu par quelqu'un d'autre.

Ensuite, je conçois que l'usage d'un entier à la place d'un booléen ne pose pas énormément de problèmes.

En tout cas, merci d'avoir pris compte de ma remarque. ^^
Voilà, donc j'arrêterai là pour ne pas trop polluer ce sujet et laisser les cryptographes à l'oeuvre. :p
  • Partager sur Facebook
  • Partager sur Twitter
11 juin 2008 à 9:27:16

J'ai modifié le corrigé du dernier exercice pour tenir compte des remarques de :

- Youyou, qui vouliat savoir comment différencier [] et at()
- BoudBoulMan, qui critiquait très justement certains raccourcis.

Merci à vous deux.

@Cyprien_ :
Je n'ai pas non-plus tellement le temps de faire cela ces jours. La principale modification est en fait de mettre des nombres jusqu'à 255 dans chaque case si tu utilise un vector<char> comme tableau. Il faut modifier les endroits où il y a un modulo 10 et remplacer par un modulo 256. Le reste ne devrait pas changer sauf pour l'affichage et la construction où il faudra faire la "traduction" base 256 -> base 10 et vice-versa.
  • Partager sur Facebook
  • Partager sur Twitter
Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
13 juin 2008 à 20:07:11

Bonjour ! :)

J'ai pensé a un truc : on peut ne pas utiliser de flag mettre directement le nombre de fois que le caractère est répété converti en caractère ASCII et directement le caractère après.

Par exemple, sachant que 33 a pour caractère ASCII "!", on peut compresser ça :

JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ


en

!J


C'est pratique car ça vire le flag et ça permet de compresser des suites de 255 caractères (max)! ;)
Seulement, c'est toujours pareil, une chaine en francais sera "sous-compressée" ! :p

A+ :)
  • Partager sur Facebook
  • Partager sur Twitter
13 juin 2008 à 20:26:55

Hello,

Ca marche peut-être, mais tu auras des prèblèmes avec les chaînes qui n'ont jamais de caractères consécutifs.
De plus certains caractères ASCII ne peuvent être utilisé (EOF, \n, \t) et si par hasard la chaîne faisait la mauvaise longueur de sorte que ca donne EOF (par exemple), on aurait un sérieux problème.

Bien essayé !
  • Partager sur Facebook
  • Partager sur Twitter
Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
13 juin 2008 à 20:43:22

Salut, :)

Les caractères EOF, \n et \t sont lus comme les autres ! C'est juste l'utilisation que les éditeurs de textes en font après (Retour à la ligne, tabulation, signale la fin d'un fichier ...)
[En plus, il me semble qu'il n'y a pas de EOF en ASCII ... Enfin, j'ai peut être lu trop vite :p ]

A la limite, le caractère qui peut faire foirer, c'est le NUL car il est interprété en C++ par la fin d'un tableau de caractère, ainsi que par la classe string. Mais de toute façon, le NUL n'apparaîtra pas car on n'enregistre pas les chaines de 0 caractère ! :D

Sinon, c'est vrai que ça sert à rien quand les caractères ne sont pas consécutifs ... ;)

A+
  • Partager sur Facebook
  • Partager sur Twitter
13 juin 2008 à 20:55:40

Citation : Carma001

A la limite, le caractère qui peut faire foirer, c'est le NUL car il est interprété en C++ par la fin d'un tableau de caractère, ainsi que par la classe string.


Ce n'est pas vrai. Une std::string peut contenir 0, tu peux concaténer des chaines qui en contiennent etc. Par contre à l'affichage, ou lors des exports vers char*, le 0 est de nouveau interprété par les fonction str*() du C.
  • Partager sur Facebook
  • Partager sur Twitter
C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
13 juin 2008 à 21:06:15

Oui voilà, à l'affichage ou à l'export dans un fichier ! C'est vrai que je me suis mal exprimé ! ;)

Merci ! :)
  • Partager sur Facebook
  • Partager sur Twitter
13 juin 2008 à 21:16:10

Pour l'écriture fichier, tu peux réaliser une écriture binaire (la seule qui a du sens quand il y a des caractères non imprimables) depuis la std::string sans aucun problèmes. -> f.write(str.data(), str.size())
  • Partager sur Facebook
  • Partager sur Twitter
C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
13 juin 2008 à 21:26:19

Oui bien sûr mais il me semble qu'on a dit "pas de binaire" dans l'exercice (à moins que je l'ai rêvé ou que vous ayez changé d'avis entre les pages 9 et 12 que j'ai pas lus ! :D )

;)
  • Partager sur Facebook
  • Partager sur Twitter
13 juin 2008 à 21:32:24

Pourquoi parler du 0 alors? :p
  • Partager sur Facebook
  • Partager sur Twitter
C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
13 juin 2008 à 22:06:38

Oui c'est vrai que ça pose pas de problème en fin de compte ... :D
  • Partager sur Facebook
  • Partager sur Twitter
15 juin 2008 à 15:08:15

ca serait bien de faire 2 exos par mois.
  • Partager sur Facebook
  • Partager sur Twitter
15 juin 2008 à 15:18:54

Tu dis ça, mais j'ai pas encore reçu ta solution, Ô grand maître du C++. :)
  • Partager sur Facebook
  • Partager sur Twitter
15 juin 2008 à 16:06:17

Je l'avais annoncé il y a quelques posts, comme les vacances arrivent (en tout cas pour moi :p ), je vais proposer un exercice supplémentaire au milieu du mois. Les délais de soumission n'ont pas changé.
Les exercices de milieu de mois seront un peu plus difficile mais plus court et axés sur un point technique particulier.

2ème Exercice du mois de juin 2008



Cet exercice est plus difficile que le dernier mais aussi plus technique. Il est par contre beaucoup plus court.


Nom : L'opérateur virgule
Sujet : Surcharge d'opérateurs


Introduction



Quand j'ai débuté en C++, j'ai découvert un truc absolument génial : La surcharge d'opérateurs.

J'ai assez rapidement essayé de surcharger tous les opérateurs surchargeables. (Une liste ici). Ce n'est pas difficile et on arrive rapidement à faire du code particulièrment obscure du type :

a new b, c % 3 || d delete g;

:p Absolument illisible et in-maintebale.

Dans un deuxième temps, je me suis intéressé à faire de la surcharge d'opérateurs dans un but utile. Pour la plus part des opérateurs, c'est très facile de trouver une application concrète.
Sauf pour un opérateur particulier. Celui situé tout en-bas de la liste, l'opérateur virgule.
J'ai finalement trouvé une application et je vous propose ce mois de la coder.

L'exercice



Vous connaissez certainement les tableaux statiques.

int tab[5];   //Un tableau de 5 entiers


et le fait qu'on puisse les initialiser de la manière suivante :

int tab[5] = {0,1,2,3,4};   //Initialisation


Il serait intéressant de pouvoir faire de même avec la classe std::vector !!

Evidemment, vous ne pouvez pas modifier (enfin si mais ne le faites pas) le code de la classe vector. Nous allons donc créer une classe qui hérite de cette classe.

#include <vector>
using namespace std;

class Tableau: public vector<int>
{
public:  
    Tableau(unsigned int n = 0, int valeur=0) //Construit un tableau de longueur n donc les elements valent "valeur"
          :vector<int>(n,valeur)
    {}

    //Autres elements utiles
};


On peut donc écrire tout le code que l'on veut dans cette classe et en particulier ajouter les opérateurs que l'on veut.

Par exemple l'opérateur << qui permet d'afficher le contenu du tableau en console.

ostream& operator<<(ostream& flux,const Tableau& tab)  //Affiche le contenu du tableau
{
    if (!tab.empty())  //Si le tableau n'est pas vide
    {
        for (unsigned int i(0);i<tab.size()-1;++i)
            flux << tab[i] << ",";          //On separe les elements par des virgules
        flux << tab[tab.size()-1];
    }
    return flux;
}


Voilà votre base de travail.

Votre programme



Niveau 1



Vous devrez trouvez un moyen de coder l'opérateur virgule de telle sorte que le code suivant compile :

int main()
{
    Tableau tab(10);

    tab=0,1,2,3,4,5,6,7,8,9;

    cout << tab << endl;

    return 0;
}


et affiche :

0,1,2,3,4,5,6,7,8,9


Pour ce faire, vous avez le droit d'ajouter tout le code que vous désirez à partir de la base suivante :

#include <vector>
#include <iostream>
using namespace std;

class Tableau: public vector<int>
{
public:  
    Tableau(unsigned int n = 0, int valeur=0) //Construit un tableau de longueur n donc les elements valent "valeur"
          :vector<int>(n,valeur)
    {}

    //A vous de jouer !
};

ostream& operator<<(ostream& flux,const Tableau& tab)  //Affiche le contenu du tableau
{
    if (!tab.empty())  //Si le tableau n'est pas vide
    {
        for (unsigned int i(0);i<tab.size()-1;++i)
            flux << tab[i] << ",";          //On separe les elements par des virgules
        flux << tab[tab.size()-1];
    }
    return flux;
}

int main()
{
    Tableau tab(10);

    tab=0,1,2,3,4,5,6,7,8,9;

    cout << tab << endl;

    return 0;
}


Vous pouvez également écrire du code en-dehors de la classe, voir d'autres classes si nécessaires. Les macros sont évidemment interdites.


Niveau 2



Si vous voulez jouer dans cette catégorie, votre programme devra distinguer 3 cas :

1) Le cas du niveau 1
2) Une affectation du type :

tab = 2;


qui elle devra remplir le tableau avec la valeur "2" dans toutes les cases.

3) Une affectation du type (avec un tableau de taille 10)

tab = 2,3;


qui devra signaler une erreur à l'utilisateur sous la forme d'une exception par exemple.

Niveau 3



Pourquoi se limiter aux entiers ? Si voulez vraiment jouer aux gourous, alors attaquez le niveau 2, mais avec des templates, de telle sorte que vous puissiez gérer tous les types que l'on peut mettre dans un vector.

Cela peut vous sembler énorme, mais sachez que le point 2 (et 3) tiennent en 35 lignes de code.



Indications si nécessaire



La surcharge de l'opérateur virgule se fait via la syntaxe :

type_retour operator,(type_a_droite);


pour une fonction memebre et

type_retour operator,(type_a_gauche,type_a_droite);


pour une fonction libre. type_a_droite et type_a_gauche representent respectivement les types situés à gauche et à droite de la virgule.

-------------------------------

Regardez bien la priorité de l'opérateur virgule ainsi que son associativité. Ce sont de précieuses informations.


Il est possible que votre compilateur émette des "Warning" en compilant la classe qui hérite de vector. Ignorez les, ils n'ont aucune importance dans ce cadre.


Vous avez jusqu'au 15 juillet pour soumettre vos réponses à Réponse_Exercices.

Bonne chance à tous !

  • Partager sur Facebook
  • Partager sur Twitter
Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
Anonyme
15 juin 2008 à 18:16:25

boost::assign fournit ce genre de chose et même plus.
  • Partager sur Facebook
  • Partager sur Twitter
15 juin 2008 à 18:43:11

Oui, mais là c'est tricher ! :)
  • Partager sur Facebook
  • Partager sur Twitter
Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
15 juin 2008 à 19:53:56

oula trop complexe et en plus les vector j'ai rien compris.
  • Partager sur Facebook
  • Partager sur Twitter
15 juin 2008 à 19:54:34

et tu veux créer un OS en plus :-°
  • Partager sur Facebook
  • Partager sur Twitter
15 juin 2008 à 21:51:44

Citation : zero ptt

et tu veux créer un OS en plus :-°



moi?
Non j'ai jamais voulu en créer.
Je m'interresse sur certains points du genre la traduction binaire -> transistor et inverse.
  • Partager sur Facebook
  • Partager sur Twitter
16 juin 2008 à 9:30:49

Jaloyan1, je t'ai déjà dit que tu commençais à me taper sur les nerfs.
Je te demanderai de ne plus poster dans ce topic à moins que ce soit en rapport direct avec les exercices.

Pour les autres: désolé de pourrir ce topic avec ce genre de posts.
  • Partager sur Facebook
  • Partager sur Twitter
Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
16 juin 2008 à 20:33:12

Citation : Nanoc

Jaloyan1, je t'ai déjà dit que tu commençais à me taper sur les nerfs.
Je te demanderai de ne plus poster dans ce topic à moins que ce soit en rapport direct avec les exercices.

Pour les autres: désolé de pourrir ce topic avec ce genre de posts.


Ne dramatisons pas pour une embrouille comme celle-là. Je sens que ça allait encore devenir du n'importe quoi.

Exercice très intéressant :) .
Par contre, je ne vois pas trop comment ça peut tenir en 35 lignes :euh: ...
  • Partager sur Facebook
  • Partager sur Twitter
16 juin 2008 à 20:42:33

Je suis pas contre plus de lignes. :)

J'ai mis ça à titre indicatif pour dire que ce serait plus court que BigInt par exemple.
  • Partager sur Facebook
  • Partager sur Twitter
Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
16 juin 2008 à 21:17:04

Je me trompais : j'arrive déjà une partie de l'exercice :-° .
Franchement, ça m'étonne vraiment le nombre de "c'est trop complexe" ou de "j'y arriverais pas". Si on se sert un peu de sa tête ^^ , on y arrive très bien :) .
  • Partager sur Facebook
  • Partager sur Twitter
17 juin 2008 à 20:27:56

Tiens je vais bien m'attaquer au 2ème exercice ^^.

Sinon Nanoc, pourquoi t'engueules Jaloyan1 et pas zero ptt qui a plutôt "cherché" Jaloyan1 ? (j'ai pas trop compris l'histoire moi Oo).
Enfin, j'ai pas envie de m'embrouiller avec les autres membres :/
  • Partager sur Facebook
  • Partager sur Twitter
17 juin 2008 à 20:29:35

Question un peu à part : ca serait possible d'avoir des exercices mais QT ?
  • Partager sur Facebook
  • Partager sur Twitter