420KEL – Intégration de techniques nouvelles en informatique de gestion

Quelques raccourcis :

Ceci est un petit site de support pour le cours 420-KEL-LG – Intégration de techniques nouvelles en informatique de gestion. Il se construira au fil des semaines à partir de ce que nous aurons effectivement fait en classe (j'ai mon plan, mais on restera agiles de manière à être le plus adaptés possible à vos besoins et à votre réalité).

Ce cours, étant en partie intensif, en partie à distance et en partie intercalé avec votre stage, suivra un format atypique. Ceci explique que les dates effectives des séances en classe restent (au moins en partie) à déterminer, et que j'aie choisi d'identifier les séances par Sxx (pour « séance xx ») plutôt que par Txx (théorie) ou Lxx (laboratoire).

De manière générale, vos besoins guideront en partie notre démarche et nos choix de contenu. Les problèmes (techniques) que vous rencontrerez en stage pourront être discutés en classe, et nous chercherons à leur apporter des solutions à la fois élégantes et efficaces.

Certaines de nos séances seront virtuelles (les dates sur le calendrier ci-dessous seront identifiées s/o, donc sans objet). Elles seront constituées d'une mise en situation (idéalement en personne, lors de nos séances in vivo) puis de travail pratique lorsque votre horaire le permettra, alimenté par des échanges électroniques. Lorsque nous nous reverrons, nous mettrons en commun nos approches, nos questionnements, et nous présenterons la matière au prochain défi. J'ai calculé l'équivalent de 30 séances, soit 15 séances « théoriques » et 15 séances « pratiques », mais nos séances seront pour l'essentiel des hybrides. Bien que le cours soit siglé 2-2-2, nous aurons des séances de format variable, tout en essayant de nous en tenir aux 60 heures prévues (incluant le volet « à distance »).

J'aimerais vous proposer quatre volumes de programmation orientée objet (entre autres) plutôt touffus, qui pourront vous être utiles dans le cours comme dans votre carrière, mais étant donné que vous êtes déjà en stage, je comprendrais si vous préfériez ne pas vous les procurer. Ces volumes présentent des exemples et des concepts en C++ (principalement), mais aussi en C#, en Java et en VB.NET.

Pour éviter de faire imprimer un trop grand nombre de copies, je ferai circuler une feuille en classe et je n'en ferai imprimer que pour celles et ceux parmi vous qui en font la demande.

Quand je connaîtrai les identifiants pour obtenir ces volumes à la coop, je mettrai à jour les puces ci-dessous :

Je veux ces volumesJe ne veux pas ces volumes

Jérémy Bélec

Samuel Bonneville

Vincent Couturier

Maxime Charland

Olivier Stephan Demet

Ines Nesrine Cherfaoui

Christian Girard

Alexandre Corbeil

Mathieu Jalbert-Claveau

Antoine Coulombe

Philip Lamothe

Yannick Delaire

Frédéric Leblanc-Graveline

Joaquin Lee-Martinez

Alexis Maher

Jérémie Leroux

Jérémie Valiquette

Mathieu Lussier

Cristofor Vasile Iancu

Jérémie Morin

 

Philippe Ravagnan Paquette

 

 

Détail des séances en classe

Techniquement, vous serez deux groupes de 420KEL cet hiver, soit les groupes (a) et (b). L'horaire sera organisé de manière à alterner les séances d'avant-midi et d'après-midi d'un groupe à l'autre. Soyez donc attentives et attentifs aux variations d'horaire pour éviter de manquer une séance (dans un format intensif, c'est pas vraiment une bonne idée de se lever trop tard).

Date Séance Détails
4 janvier
S00

Groupe (a) :h à 12 h

Groupe (b) : 13 h à 16 h

Cours au P-118. Au menu :

5 janvier S01

Groupe (b) :h à 12 h

Groupe (a) : 13 h à 16 h

Cours au P-118. Au menu :

  • Présentation de l'idiome d'affectation sécuritaire
  • Discussions à propos de la représentation des paramètres culturels à l'aide d'instances de std::locale
  • Réflexions sur la répartition des responsabilités entre un conteneur et son contenu
  • Rôle de la Sainte-Trinité
  • Qu'est-ce qu'un invariant? (survol)
  • Qu'est-ce qu'une précondition? (survol)
  • Qu'est-ce qu'une postcondition? (survol)
  • Qu'est-ce que la complexité algorithmique? (survol)
  • Exercice de rédaction d'une version plus efficace de ListeEntiers, représentant une liste simplement chaînée d'entiers
  • Réflexion sur le problème de la méthode ajouter() de ListeEntiers, dans sa déclinaison initiale
    • discussion de solutions possibles
  • Présentation sommaire de la sémantique de mouvement
  • Survol de la différence entre initialisation avec parenthèses et initialisation avec accolades

Dans les notes de cours :

À faire pour la séance S02, seul(e) ou en équipe de deux :

  • Améliorer la classe ListeEntiers pour que :
    • La méthode taille() soit de complexité
    • La méthode ajouter() soit de complexité
    • Le constructeur de copie et l'affectation deviennent de complexité
    • Vous assurer que les attributs d'instance que vous aurez ajouté pour y arriver soient tenus à jour de manière cohérente dans l'ensemble des méthodes de ListeEntiers
  • Vous aurez droit à un petit bonus si vous ajustez inverser() pour qu'elle n'ait plus à faire d'allocation dynamique de mémoire
  • Remettez votre code dans un seul fichier .cpp par équipe, avec les noms des équipières et des équipiers à la fois dans le nom du .cpp et dans les commentaires au début du fichier
6 janvier S02

Groupe (a) :h à 12 h

Groupe (b) : 13 h à 16 h

Cours au P-118.

Au menu :

  • Petit truc de débogage : la classe Noisy
  • Exercice de rédaction d'une Liste<T>, représentant une liste simplement chaînée générique, en Java ou en C# (à votre choix)
  • Peu importe que votre code de Liste<T> soit écrit en Java ou en C#, cette classe doit offrir au minimum les services suivants :
    • constructeur par défaut, qui crée une liste vide
    • mécanisme pour dupliquer une liste, donc créer une nouvelle liste distincte de l'originale mais équivalente à cette dernière
      • deux listes a et b sont équivalentes si elles ont le même nombre de noeuds, et si les noeuds de ces deux listes ont les mêmes valeurs dans le même ordre
    • mécanisme permettant d'inverser les éléments d'une liste
    • mécanisme permettant d'ajouter un élément à une extrémité de la liste
    • mécanisme permettant d'extraire un élément à l'autre extrémité de la liste
    • mécanisme permettant de connaître le nombre d'éléments dans la liste
    • mécanisme permettant de tester la liste pour savoir si elle est vide ou non
    • mécanisme pour comparer deux listes et savoir si elles sont équivalentes
    • mécanisme pour afficher les éléments d'une liste sur un flux
    • mécanisme pour vider une liste
  • Consignes d'ordre général :
    • visez à respecter les idiomes de votre langage (si vous faites du Java, faut que ça respecte les pratiques du code Java; si vous faites du C#, faut que ça respecte les pratiques du code C#)
    • utilisez les exceptions de manière judicieuse
    • évitez les fuites de ressources
  • Il faut que votre programme de test fasse au minimum les opérations suivantes à l'aide d'instances de votre type Liste<T> :
    • tester chacun des services ci-dessus
    • valider que si une liste est une copie d'une autre liste, les deux peuvent être modifiées indépendamment l'une de l'autre
  • Échanges en classe sur les itérateurs et sur les foncteurs, de même que sur les λ, pour voir des manières contemporaines de solutionner certains des exercices

La classe Liste<T> est à remettre au début de la séance S03.

Dans les notes de cours :

  • Les foncteurs sont décrits dans POO – Volume 02, pp. 152-173
  • Les λ sont décrites dans POO – Volume 02, pp. 179-190
  • Les algorithmes standards sont survolés dans POO – Volume 02, pp. 87-94
10 janvier S03

Groupe (b) :h à 12 h

Groupe (a) : 13 h à 16 h

Notez que c'est aujourd'hui l'anniversaire de Donald E. Knuth

Cours au P-118.

Au menu :

  • Échanges en classe sur les itérateurs et sur les foncteurs, de même que sur les λ, pour voir des manières contemporaines de solutionner certains des exercices
  • Programmer par algorithmes
  • Exercices formatifs d'utilisation d'algorithmes standards
  • Implémenter quelques algorithmes maison :
    • l'algorithme inverser(debut,fin) qui inverse l'ordre des éléments dans la séquence . Testez votre implémentation avec un tableau de float, un vector<int> et une list<string>. Votre algorithme doit fonctionner avec une séquence vide, et doit donner les bons résultats que le nombre d'éléments y soit pair ou impair. Vous avez le droit d'utiliser std::swap()
    • l'algorithme trouver(debut,fin,val) qui retourne un itérateur sur le premier élément de la séquence qui soit égal à val au sens de l'opérateur ==. Testez votre implémentation avec des itérateurs sur un vector<int> et une list<string>. Si aucun élément n'est trouvé, retournez fin
    • l'algorithme trouver_si(debut,fin,pred) qui retourne un itérateur sur le premier élément e de la séquence tel que pred(e) soit vrai. Testez votre implémentation avec des itérateurs sur un vector<int> et une list<string>. Si aucun élément n'est trouvé, retournez fin
  • Pour celles et ceux qui auront terminé, amusez-vous à implémenter :
    • l'algorithme pivoter_gauche(debut, fin) qui pivote tous les éléments de la séquence d'une position vers la gauche (donc une séquence contenant initialement contiendra en fin de parcours
    • l'algorithme pivoter_droite(debut, fin) qui pivote tous les éléments de la séquence d'une position vers la droite (donc une séquence contenant initialement contiendra en fin de parcours

Notez que ces algorithmes sont pour la plupart implémentés dans <algorithm>, mais l'idée de ces exercices est d'essayer de les implémenter vous-mêmes; lorsque vous les aurez implémentés, vous pourrez comparer votre solution avec celle livrée par le standard si le coeur vous en dit.

Dans les notes de cours :

  • Les foncteurs sont décrits dans POO – Volume 02, pp. 152-173
  • Les λ sont décrites dans POO – Volume 02, pp. 179-190
  • Les algorithmes standards sont survolés dans POO – Volume 02, pp. 87-94
11 janvier S04

Groupe (a) :h à 12 h

Groupe (b) : 13 h à 16 h

Cours au P-118. Au menu :

  • Comparatif d'implémentations Java et C# d'une ListeEntiers
    • caractéristiques de l'implémentation Java
    • caractéristiques de l'implémentation C#
  • Survol de l'approche orientée objet, en particulier du principe de substitution de Liskov (ne dériver publiquement une classe d'une autre que si les deux classes ont des invariants mutuellement cohérents)

Ensuite, quelques exercices à réaliser pour S06 :

  • Écrivez l'algorithme trouver_consecutifs(debut,fin,n) qui retournera un itérateur sur le début de la première séquence de n éléments consécutifs de même valeur dans la séquence . Cet algorithme retournera fin si aucune telle séquence n'existe, ou encore si
  • Écrivez l'algorithme plus_longue_sequence(debut,fin), qui retournera une paire (voir std::pair et std::make_pair()) dont le premier élément sera un itérateur sur le début de la plus longue séquence de valeurs consécutives trouvée dans la séquence , et le second élément sera un itérateur sur la fin de cette « sous-séquence ». Veillez à ce que la paire d'itérateurs retournée forme une séquence à demi-ouverte. Si la séquence est vide, alors retournez une paire fin,fin. Si plusieurs séquences distinctes ont la même (plus longue) longueur, alors retournez une paire d'itérateurs sur la première d'entre elles. Vous pouvez vous aider en écrivant des algorithmes auxiliaires. Vous avez le droit d'utiliser std::distance()
  • Écrivez l'algorithme plus_longue_sequence(debut,fin,pred), qui retournera une paire (voir std::pair et std::make_pair()) dont le premier élément sera un itérateur sur le début de la plus longue séquence de valeurs consécutives respectant le prédicat pred trouvée dans la séquence , et le second élément sera un itérateur sur la fin de cette « sous-séquence ». Veillez à ce que la paire d'itérateurs retournée forme une séquence à demi-ouverte. Si la séquence est vide, alors retournez une paire fin,fin. Si plusieurs séquences distinctes ont la même (plus longue) longueur, alors retournez une paire d'itérateurs sur la première d'entre elles. Vous pouvez vous aider en écrivant des algorithmes auxiliaires. Vous avez le droit d'utiliser std::distance()
  • Écrivez l'algorithme inverser_mots(s) qui retourne une chaîne de la même taille que s, mais dont le contenu est l'inverse de l'ordre des mots dans la chaîne s sans toutefois modifier l'ordre et la taille des séquences de blancs dans s. Un caractère c est un blanc si isspace(c,locale{""}). Par exemple :
    • si s est " j'aime   mon prof  ", alors la fonction retournera " prof   mon j'aime  "
    • si s est "yo", alors la fonction retournera "yo"
    • si s est "     yo man", alors la fonction retournera "     man yo"
    • si s est "yo  man", alors la fonction retournera "man  yo"
  • Écrivez l'algorithme inverser_lettres(s) qui retourne une chaîne de la même taille que s, mais dont le contenu est tel que seul l'ordre des symboles dans chacun des mots est inversé. Par exemple :
    • si s est " j'aime   mon prof  ", alors la fonction retournera " emia'j   nom forp  "
    • si s est "yo", alors la fonction retournera "oy"
    • si s est "     yo man", alors la fonction retournera "     oy nam"
    • si s est "yo  man", alors la fonction retournera "oy  nam"

De ces exercices, deux seront recueillis lors de S06 et seront notés au bulletin. Je ne sais malheureusement (!) pas lesquels au moment d'écrire ces lignes, mais je vous les communiquerai au plus tard 48 heures à l'avance.

12 janvier S05

Groupe (b) :h à 12 h

Groupe (a) : 13 h à 16 h

Cours au P-118. Au menu :

Dans les notes de cours :

  • L'idiome RAII est décrit dans POO – Volume 00, Annexe 03 puis dans POO – Volume 01, pp. 206-210
17 janvier S06

Groupe (b) :h à 12 h

Groupe (a) : 13 h à 16 h

Cours au P-118. Au menu :

  • Remise des exercices demandés à la séance S04. Je ramasserai les fonctions suivantes :
    • la fonction inverser_mots()
    • la fonction plus_longue_sequence(debut,fin,pred)
  • Gestion de la vie d'un objet, un tour d'horizon avec C++, Java et C#
  • Cycle de vie
  • Sémantique de valeur
  • Copie
  • Clonage
  • Sémantiques d'accès

Le code utilisé pour la classe Tableau, de même que le test qui met en relief l'impact du mouvement sur la vitesse du programme, suit :

#include <cstddef>
#include <algorithm>

class Tableau {
public:
   using value_type = int;
   using size_type = std::size_t;
private:
   value_type *elems;
   size_type nelems,
             cap;
public:
   size_type size() const noexcept {
      return nelems;
   }
   size_type capacity() const noexcept {
      return cap;
   }
   bool empty() const noexcept {
      return !size();
   }
private:
   bool full() const noexcept {
      return size() == capacity();
   }
public:
   using iterator = value_type*;
   using const_iterator = const value_type*;
   iterator begin() noexcept {
      return elems;
   }
   const_iterator begin() const noexcept {
      return elems;
   }
   const_iterator cbegin() const noexcept {
      return elems;
   }
   iterator end() noexcept {
      return begin() + size();
   }
   const_iterator end() const noexcept {
      return begin() + size();
   }
   const_iterator cend() const noexcept {
      return begin() + size();
   }
   Tableau() noexcept : elems{}, nelems {}, cap{} {
   }
   Tableau(size_type n, const value_type &init)
      : cap{ n }, nelems{ n }, elems{ new value_type[n] } {
      std::fill(begin(), end(), init);
   }
   Tableau(const Tableau &autre)
      : elems{ new value_type[autre.size()] },
        nelems{ autre.size() }, cap{ autre.size() } {
      std::copy(autre.begin(), autre.end(), begin());
   }
   ~Tableau() {
      delete [] elems;
   }
   void swap(Tableau &autre) noexcept {
      using std::swap;
      swap(elems, autre.elems);
      swap(nelems, autre.nelems);
      swap(cap, autre.cap);
   }
   Tableau& operator=(const Tableau &autre) {
      Tableau{ autre }.swap(*this);
      return *this;
   }
   value_type& operator[](size_type n) noexcept {
      return elems[n];
   }
   const value_type& operator[](size_type n) const noexcept {
      return elems[n];
   }
   void push_back(const value_type &val) {
      if (full()) grow();
      elems[size()] = val;
      ++nelems;
   }
private:
   void grow() {
      const size_type new_cap = capacity()? capacity() * 2 : 42; // hum
      auto p = new value_type[new_cap];
      std::copy(begin(), end(), p);
      delete[]elems;
      cap = new_cap;
      elems = p;
   }
public:
   bool operator==(const Tableau &autre) const noexcept {
      return size() == autre.size() &&
             std::equal(begin(), end(), autre.begin());
   }
   bool operator!=(const Tableau &autre) const noexcept {
      return !(*this == autre);
   }
   Tableau(Tableau &&autre) noexcept
      : elems{ autre.elems }, nelems{ autre.nelems }, cap{ autre.cap } {
      autre.elems = {};
      autre.nelems = {};
      autre.cap = {};
   }
   Tableau& operator=(Tableau &&autre) noexcept {
      delete[] elems;
      elems = autre.elems;
      nelems = autre.nelems;
      cap = autre.cap;
      autre.elems = {};
      autre.nelems = {};
      autre.cap = {};
      return *this;
   }
};


#include <vector>
#include <numeric>
#include <chrono>
#include <iostream>
using namespace std;
using namespace std::chrono;

vector<double> f(vector<double> v) {
   transform(begin(v), end(v), begin(v), [](double x) { return sqrt(x); });
   return v;
}

int main() {
   enum { N = 50'000'000 };
   vector<double> v(N);
   iota(begin(v), end(v), 1.0);
   {
      auto w = v;
      auto pre = high_resolution_clock::now();
      w = f(w);
      auto post = high_resolution_clock::now();
      cout << "Ecoule : " << duration_cast<microseconds>(post - pre).count()
           << " us." << endl;
   }
   {
      auto w = v;
      auto pre = high_resolution_clock::now();
      w = f(std::move(w));
      auto post = high_resolution_clock::now();
      cout << "Ecoule : " << duration_cast<microseconds>(post - pre).count()
           << " us." << endl;
   }
}

Dans les notes de cours :

  • Le cycle de vie des objets est discuté dans POO – Volume 00, pp. 91-114
  • Une discussion de l'importance des invariants est offerte dans POO – Volume 03, pp. 18-25
  • Les pointeurs intelligents sont présentés dans POO – Volume 02, pp. 120-135
  • Une réflexion sur les sémantiques d'accès est proposée dans POO – Volume 00, Appendice 00
  • Le clonage est décrit dans POO – Volume 01, pp. 195-205
  • Vous trouverez une réflexion sur le rôle des constantes dans POO – Volume 01, Appendice 01
18 janvier S07

Groupe (a) :h à 12 h

Groupe (b) : 13 h à 16 h

Cours au P-118. Au menu :

Dans le cours, en réponse à des questions d'étudiant(e)s, j'ai offert un petit exemple d'un programme qui compte le nombre d'occurrences des « mots » (au sens de « séquences de caractères délimitées par des blancs », donc pas dans un sens aussi strict que celui du travail pratique proposé aujourd'hui) et affiche chaque mot accompagné de son nombre d'occurrences (dans le désordre), en C++. Le code donné en exemple suit :

#include <string>
#include <map>
#include <fstream>
#include <iostream>
using namespace std;
int main() {
   map<string, int> mots;
   ifstream in { "z.cpp" };
   for (string s ; in >> s ; mots[ s ]++)
      ;
   for (auto & elem : mots)
      cout << "Le mot " << elem.first << " apparait " << elem.second << " fois" << endl;
}

Bon départ en stage; je m'ennuie déjà de vous!

En vue d'une remise à la séance S09S10, je vous propose l'exercice suivant :

  • Écrivez un programme dans le langage de votre choix (Java, C#, C++, autre si vous le souhaitez et si je vous donne mon accord) qui aura pour rôle de générer une page Web contenant une version formatée d'un fichier source
  • Plus précisément, votre programme réalisera la tâche suivante :
    • prendre en paramètre au démarrage (paramètres à main() / Main()) une séquence contenant des options et des noms de fichiers, peu importe l'ordre
    • les options doivent débuter par '-' ou par '/' (supportez les deux formats)
    • les noms de fichiers doivent être des fichiers sources dans un langage de votre choix  – je vous suggère de prendre le même langage que celui dans lequel vous développerez le programme, c'est plus amusant comme ça
    • le programme consommera le contenu du fichier source, le transformera (sans modifier l'original) et écrira le résultat de la transformation dans un fichier portant le même nom que le fichier source, mais avec extension .html
    • les transformations qui seront faites doivent dépendre des options choisies à l'appel du programme. Si aucune option n'est choisie, alors le programme doit générer un fichier identique au fichier source, outre le code html qui fera du fichiers en sortie une page Web légale
  • Un exemple de lancement de votre programme serait :
cpp2web -stats -couleur a.cpp b.cpp c.cpp
  • ... qui générerait les fichiers a.cpp.html, b.cpp.html et c.cpp.html de même qu'un fichier de statistiques sur le travail accompli (nom à votre choix)

Pour un exécutable « exemple », vous pouvez essayer mon cpp2web.exe

  • L'idée est de vous amuser avec des techniques nouvelles de programmation. Conséquemment, je vous recommande de faire le travail à l'aide :
  • Je m'attends à ce que vous supportiez au moins les options suivantes :
    • une option qui permettra de demander à ce que les mots clés du langage de programmation choisi soient mis en relief (vous pouvez utiliser du CSS et des balises <span> pour y arriver, c'est probablement l'option la plus simple)
    • une option qui permettra de tirer des statistiques sur les données traitées. Je vous propose de compter les mots clés, de compter le nombre d'occurrences de chaque mot (ne comptez pas ce qui ne comprend pas au moins un caractère alphanumérique), et de compter le nombre de nombres (les littéraux comme 0, 3.14159 ou 85). Pas besoin de traiter les suffixes comme U, UL ou f (même si vous le pouvez si vous en avez envie)
      • les statistiques devront être générées dans un fichier texte à la fin de l'exécution du programme
      • les paires mot / nombre d'occurrences devront être listées en ordre décroissant de nombre d'occurrences, puis en ordre lexicographique dans le cas où plusieurs mots apparaissent aussi souvent les uns que les autres
    • évidemment, seules les options demandées par l'usager devront être mises en application (ça fait partie du plaisir)
  • Vous pouvez ajouter des options si vous le souhaitez, mais documentez ce que vous faites
  • Peu importe ce que vous choisirez, n'oubliez pas que certains symboles importants en programmation, comme <, > ou &, jouent un rôle spécial en html et devront être remplacés par leur métacaractère équivalent (donc &lt;, &gt; et &amp; respectivement pour ces trois symboles)
  • Profitez-en pour vous amuser et pour expérimenter!

À la séance S08, je vous laisserai travailler sur cet exercice et je répondrai à vos questions. Nous pourrons discuter design, technique et autres trucs qui vous turlupinent. Évidemment, ce cours étant en partie électronique, vous pouvez m'écrire quand vous le souhaitez pour discuter de ces choses. Il se peut que je répondre publiquement (donc au groupe entier) si j'estime que votre question est d'intérêt public.

Vous aurez droit à un bonus si vous traitez correctement les cas suivants :

  • les commentaires débutant par un // et se terminant par un saut de ligne
  • les commentaires débutant par un /* et se terminant par un */
  • les chaînes de caractères sous la forme "abc...def" et celles sous la forme L"abc...def" ou leur équivalent dans le langage que vous aurez choisi
  • les chaînes de caractères sous la forme R"(abc ... def)" ou leur équivalent dans le langage que vous aurez choisi

Attention, c'est plus croustillant, car il y aura des cas comme /*"allo" int i=3 */, "int /* " ou /* // yeah */ qui seront des tenir-compte, alors c'est un petit bonus par cas traité, et ne vous lancez là-dedans que si le programme de base fonctionne

24 janvier
25 janvier
S08

Groupe (a) : 24 janvier le matin, 9 h 50-11 h 35 (on débordera peut-être un peu), au P-152.

Groupe (b) : 25 janvier le matin, 9 h 50-11 h 35 (on débordera peut-être un peu), au P-118.

 Au menu :

Pour vous aider, j'ai donné un petit exemple simple de programme affichant à la console des identifiants légaux en C++, C# ou Java pris d'un fichier source nommé z.cpp :

#include <locale>
#include <iostream>
#include <vector>
#include <string>
#include <iterator>
#include <fstream>
using namespace std;
/*
   Un identifiant dans la plupart des langages débute par une lettre ou un '_', suivi par une séquence
   de zéro ou plus lettres, chiffres ou '_'. Ça donne une expression régulière comme [_a-zA-Z][_a-zA-Z0-9]+
   si on l'écrit « manuellement » (car il existe des raccourcis dans bien des implémentations
   d'expressions régulières pour ce genre de truc)
   
   Le code qui suit n'est pas optimisé du tout; je l'ai écrit pour vous inspirer
*/
//
// retourne true seulement si c peut débuter un identifiant
//
bool peut_debuter_identifiant(char c) {
   return c == '_' || isalpha(c, locale{ "" });
}
//
// retourne true seulement si c peut poursuivre un identifiant (tout symbole
// pouvant occuper une position autre que la première dans un identifiant)
//
bool peut_poursuivre_identifiant(char c) {
   return c == '_' || isalnum(c, locale{ "" });
}
int main() {
   //
   // lire tout le fichier z.cpp dans le vecteur de char nommé texte
   //
   vector<char> texte{
      istreambuf_iterator<char>{ ifstream { "z.cpp" } },
      istreambuf_iterator<char>{}
   };
   for (auto p = begin(texte); p != end(texte); ) {
      //
      // trouver le début du prochain identifiant
      //
      while (p != end(texte) && !peut_debuter_identifiant(*p))
         ++p;
      //
      // lire l'identifiant s'il y a lieu
      //
      if (p != end(texte)) {
         string s;
         s += *p;
         for (++p; p != end(texte) && peut_poursuivre_identifiant(*p); ++p)
            s += *p;
         if (!s.empty())
            cout << "Identifiant trouve : \"" << s << "\"" << endl;
      }
   }
}

 

26 janvier S09

Groupe (b) : 8 h à 9 h 50 au P-152

Groupe (a) : 14 h 25 à 16 h 10 au P-152

Cette séance vous est offerte pour travailler sur la tâche à laquelle vous êtes convié(e)s depuis la fin de S07 et qui doit être complétée pour S09S10. Je vous invite à profiter de ces deux plages horaires si vous souhaiez discuter ou avoir du soutien technique de la part de votre chic prof.

Petit bonbon pour vous. Si vous essayez ce programme (ici, je présume que mon fichier source se nomme z.cpp et que j'applique le programme sur ses propres sources), il se peut que vous le trouviez charmant :

#include <regex>
#include <string>
#include <fstream>
#include <iostream>
#include <set>
#include <algorithm>
#include <iterator>
using namespace std;
int main() {
   set<string> ze_mots{ "string", "if", "for" }; // liste incomplète, pour fins d'illustration
   string pattern = "[_a-zA-Z][_a-zA-Z0-9]*";
   regex re{ pattern };
   ifstream in{ "z.cpp" };
   string texte{
      istreambuf_iterator<char>{ in },
      istreambuf_iterator<char>{}
   };
   auto debut = sregex_iterator{ begin(texte), end(texte), re };
   auto fin = sregex_iterator{};
   cout << "Nombre d'identifiants : " << distance(debut, fin) << endl;
   for_each(debut, fin, [](auto mot) {
      cout << mot.str() << endl;
   });
}

Ça ne tient pas compte des commentaires ou des chaînes de caractères, mais je pense que ça peut vous inspirer.

10 février
17 février
S10

Groupe (a) : 10 février, 8 h 30 à 11 h 30

Groupe (b) : 17 février, 8 h 30 à 11 h 30

Cours au P-116. Au menu :

N'oubliez pas de remettre votre travail pratique entrepris à la fin de la séance S07!

31 mars
7 avril
S11

Groupe (b) : 31 mars, 8 h 30 à 11 h 30

Groupe (a) : 7 avril, 8 h 30 à 11 h 30

Cours au P-116. Au menu :

Dans les notes de cours :

  • La question du choix d'un conteneur est traitée dans POO – Volume 02, pp. 67-80 puis dans POO – Volume 03, pp. 32-42

Travail pratique à remettre à la séance S13 : le problème des boîtes imbriquées. C'est un classique, mais il me semble que c'est le moment de vous proposer un truc comme ceci.

28 avril
5 mai
S12

Groupe (a) : 28 avril, 8 h 30 à 11 h 30

Groupe (b) : 5 mai, 8 h 30 à 11 h 30

Cours au P-116. Au menu :

  • Discussion sur le problème des boîtes imbriquées
  • Suivant une demande spéciale, développement d'un système de mise à jour automatique à l'aide d'une DLL, de deux façons différentes.
  • Petit défi de programmation pour vous :

Par équipe de deux (ou trois, si tous s'impliquent) personnes, définissez une classe petite_chaine représentant une petite chaîne de caractères (susceptible d'être utilisée dans un système embarqué ou dans un jeu vidéo).

Vos contraintes sont les suivantes :

  • Essentiel : sizeof(petite_chaine)==256
  • Essentiel : aucune allocation dynamique de mémoire ne doit être faite dans les méthodes d'une petite_chaine
  • Essentiel : si s est une petite_chaine, alors s.size() retourne sa taille, exprimée en nombre de caractères, est en temps constant (complexité )
  • Invariant : la taille d'une petite_chaine, en nombre de caractères, doit être entre 0 et 255 inclusivement
  • Essentiel : la Sainte-Trinité doit être supportée par votre classe
  • Essentiel : les opérateurs suivants doivent être offerts : opérateurs relationnels (==, !=, <, <=, > et >=), opérateur [] en version const et non-const
  • Essentiel : offrir une méthode empty() retournant true seulement si la petite_chaine est vide et qui s'exécute en temps constant (complexité )
  • Invariant : une petite_chaine est vide si sa taille est zéro
  • Essentiel : un constructeur par défaut de petite_chaine doit construire une chaîne vide
  • Essentiel : offrir un constructeur prenant en paramètre un const char* (chaîne ASCIIZ)
  • Essentiel : offrir un constructeur prenant en paramètre un const std::string&

Quelques questions auxquelles je vous suggère de réfléchir :

  • Doit-on implémenter la Sainte-Trinité pour cette classe? Expliquez votre réponse
  • Doit-on implémenter le mouvement pour cette classe? Expliquez votre réponse
  • Comment gérerez-vous les constructeurs recevant un paramètre susceptible de violer vos invariants (p. ex. : une chaîne de plus de 255 caractères)?
  • Discussion des choix de design
  • Élaborer un code de test correct pour petite_chaine
9 mai
10 mai
S13

Groupe (a) (à peu près) : 9 mai, 13 h à 15 h 30, au P-116

Groupe (b) (à peu près) : 10 mai, 8 h 30 à 11 h, au D-411

Au menu :

Remise du travail pratique le problème des boîtes imbriquées.

11 mai S14

À votre convenance / selon vos besoins, de 9 h à 12 h (priorité à celles et ceux qui prendront rendez-vous au préalable)

Cours au F-314 (mon chic bureau). Au menu :

  • Réponses à vos questions
  • Tutorat
  • Support individuel
17 mai S15

Groupe (b) :h à 12 h

Groupe (a) : 13 h à 16 h

Cours au F-307. Au menu :

  • Chic examen final plein d'amour!

Documents sous forme électronique

Cliquez sur cette cible pour le plan de cours, sous forme électronique

Exercices de révision  : cliquez sur cette cible pour quelques exercices de révision.

Petits coups de pouces

Vous trouverez ici quelques documents, la plupart petits, qui peuvent vous donner un petit coup de pouce occasionnel.

Comment accéder à du code .NET à partir d'un client C++ natif

Introduction aux templates

Introduction aux foncteurs

Introduction aux conteneurs et aux itérateurs

Programmation générique appliquée

Dans la plupart des cas, vous trouverez de l'aide précieuse dans les sections Divers – C++, Au secours Pat et Trucs scouts du site.

Solutionnaires

Les solutionnaires aux exercices auxquels vous avez été confrontés et qui ont déjà été remis sur publiés ci-dessous

Cliquez sur cette cible si vous souhaitez un solutionnaire pour les exercices de révision

Correction

Je corrige les programmes en appliquant des codes de correction. Vous trouverez ici la liste des codes les plus fréquents.

Ma stratégie de correction en tant que telle (pour le code, à tout le moins) est résumée ici.

Résultats des travaux pratiques

Ce qui suit collige les résultats des divers travaux pratiques réalisés au cours de la session. La moyenne est exprimée en pourcentage, peu importe l'échelle d'origine pour la correction des travaux en question. Les absent(e)s sont considéré(e)s avoir eu zéro.

La valeur de exprimée dans le tableau se veut un reflet du nombre de participant(e)s; cette valeur devrait normalement être équivalente au nombre d'étudiant(e)s inscrit(e)s au cours. En pratique, la colonne indique le nombre d'individus ayant remis le travail, alors que la colonne indique le nombre d'individus qui auraient dû remettre le travail. Malheureusement, un travail non remis signifie une note de zéro (il y en a trop souvent).

Travail Consignes Remise

ListeEntiers (optimisation, C++)

S01

S02

Liste<T> (langage au choix entre Java et C#)

S02

S03

Quelques algorithmes génériques (C++)

S04

S06

Coloriage de code source (langage au choix)

S07

S10

Boîtes imbriquées (langage au choix)

S11

S13

Activité synthèse

S00

S17

Valid XHTML 1.0 Transitional

CSS Valide !