
\documentclass{article}
\usepackage{alltt}
\usepackage{color}
\usepackage[T1]{fontenc}
\usepackage{amsmath}

\newcommand\datesa{14 janvier}
\newcommand\datesb{21 janvier}
\newcommand\datesc{28 janvier}
\newcommand\datesd{4 février}
\newcommand\datese{11 février}
\newcommand\datesf{18 février}
\newcommand\datesg{25 février}
\newcommand\datesh{11 mars}
\newcommand\datesi{18 mars}
\newcommand\datesj{25 mars}
\newcommand\datesk{1 avril}
\newcommand\datesl{8 avril}
\newcommand\datesm{15 avril}
\newcommand\datesn{22 avril}
\newcommand\dateso{29 avril}

\newcommand\sujet[1]{{\bf Sujet~:~{\color{red} #1}}}
\newcommand\solution{%
{\color{red} Solution~:}\\%
}%
\newcommand\instr[1]{{\color{red}{#1}}}
\newcommand\directive[1]{{\color{blue}{#1}}}
\newcommand\type[1]{{\color[rgb]{0,0.5,1.0}{#1}}}
\newcommand\var[1]{{\color{magenta}{#1}}}
\newcommand\str[1]{{\color[rgb]{0,0.5,0}{#1}}}
\newcommand\fonct[1]{{\color[rgb]{0.5,0,0.7}{#1}}}
\newcommand\semaine[2]{%
\refstepcounter{section}%
\clearpage\hrule\bigskip%
{\bf {\Large Semaine \thesection.} (#2)}%
\sectionmark{#1}\\ \\%
\sujet{#1}\\ \\%
}%
\newcommand\probleme[1]{%
\refstepcounter{subsection}%
{\bigskip \bf Problème \thesubsection~(#1 minutes)}\\%
\subsectionmark{#1}%
}%


\title{Démonstration inf 3135\\Construction et maintenance de logiciel.}
\author{Bruno Malenfant}
\date{janvier 2010}

\begin{document}

\maketitle

\semaine{pas de démo,}{\datesa}

\semaine{Unix, Édition de texte, utilisation de gcc, connection a distance.}{\datesb}

\probleme{10}

Leurs montrer comment se connecter en lab sur leurs compte 'rayon1'.

\probleme{30}

Leurs faire des exemples d'utilisation des commandes suivantes~: ls, cp, mv, touch, mkdir, cd.
(Et toute autre commandes que vous jugez utile.)
Voir la commande 'man' pour montrer les commandes Unix/Linux.

\probleme{20}

Leurs montrer un éditeur de texte de votre choix (par exemple : emacs, xemacs, eclypse,...).
Comme exemple leurs faire écrire un programme (a la 'hello world').
revoir la commande 'man' avec 'printf' cette fois pour montrer que les routines C sont aussi
dans le manuel.

\probleme{20}

Leurs montrer comment utiliser gcc.

\begin{itemize}
\item comment exécuter le résultat a.out (avec le ./)
\item -o : change le nom de l'exécutable
\item -E : pré-compilation seulement, faire des exemples avec \#define, \#ifdef, \#include, sur des petits fichiers.
\item -c : compile sans l'edition de lien
\end{itemize}

Pour cela vous pouvez utiliser les deux fichiers suivants.
Montrez les différence en ne plaçant pas de {\tt \#define PRESENT}, 
en le plaçant avant les {\tt \#include} et après les {\tt \#include}.

\clearpage

exemple, fichier exa.c
\begin{alltt}
#ifdef PRESENT

void f( int x, int y ) \{
  return x + y;
\}

#else

void f( int x, int y ) \{
  return x - y;
\}

#endif
\end{alltt}

exemple fichier main.c
\begin{alltt}
#include "exa.c"
#include <stdio.h>

int main()\{
  printf( "%i\verb+\+n", f( 4, 2 ) );
  return 0;
\}
\end{alltt}

\probleme{10}

Leurs donner une/des technique(s) pour se connecter à distance.

\semaine{Expression, if et boucle.}{\datesc}

\probleme{15}

Écrivez un code qui calcule la somme des nombres de 0 à $n$,
où $n$ est une constante dans le programme.
Cette somme sera ensuite affichée.

\medskip

\solution
\begin{alltt}
#\directive{include} \str{<stdio.h>}

\type{int} \fonct{main}() 
\{
  \type{const int} \var{n} = 10;
  \type{int} \var{i} = 0;
  \type{int} \var{somme} = 0;

  \instr{for}( \var{i} = 1; \var{i} <= \var{n}; \var{i}++ )
  \{
    \var{somme} += \var{i};
  \}

  \fonct{printf}( "resultat : %i\verb+\+n", \var{somme} );
  
  \instr{return} 0;
\}
\end{alltt}

\probleme{10}

Modifiez le code du problème 3.1 de tel sorte que seulement les nombres
pair soient additionnés.

\medskip

\solution
\begin{alltt}
#\directive{include} \str{<stdio.h>}

\type{int} \fonct{main}() 
\{
  \type{const int} \var{n} = 15;
  \type{int} \var{i} = 0;
  \type{int} \var{somme} = 0;

  \instr{for}( \var{i} = 0; \var{i} <= \var{n}; \var{i} += 2 )
  \{
    \var{somme} += \var{i};
  \}

  \fonct{printf}( "resultat : %i\verb+\+n", \var{somme} );
  
  \instr{return} 0;
\}
\end{alltt}

\probleme{15}

Écrivez un programme qui affiche les nombres de 48 à 126.
Un nombre par ligne doit être affiché.

\medskip

\solution
\begin{alltt}
#\directive{include} \str{<stdio.h>}

\type{int} \fonct{main}() 
\{
  \type{int} \var{i} = 0;

  \instr{for}( \var{i} = 48; \var{i} <= 126; \var{i}++ )
  \{
    \fonct{printf}( "%i\verb+\+n", \var{i} );
  \}

  \instr{return} 0;
\}
\end{alltt}

\probleme{10}

Modifiez le programme 3.3 pour qu'il affiche la valeur caractère
et la valeur numérique des nombre de 48 à 126.

\medskip

\solution
\begin{alltt}
#\directive{include} \str{<stdio.h>}

\type{int} \fonct{main}() 
\{
  \type{int} \var{i} = 0;

  \instr{for}( \var{i} = 48; \var{i} <= 126; \var{i}++ )
  \{
    \fonct{printf}( "%i => %c\verb+\+n", \var{i}, \var{i} );
  \}

  \instr{return} 0;
\}
\end{alltt}

\probleme{10}

Modifiez le programme 3.4 pour qu'il n'affiche les caractères que pour les 
valeurs 48 à 57, 65 à 90 et 97 à 122.

\medskip

\solution
\begin{alltt}
#\directive{include} \str{<stdio.h>}

\type{int} \fonct{main}() 
\{
  \type{int} \var{i} = 0;

  \instr{for}( \var{i} = 48; \var{i} <= 126; \var{i}++ )
  \{
    \instr{if}( ( \var{i} >= 48 \&\& \var{i} <= 57 )
         ||
        ( \var{i} >= 65 \&\& \var{i} <= 90 )
         ||
        ( \var{i} >= 97 \&\&  \var{i} <= 122 ) )
    \{
      \fonct{printf}( "%i => %c\verb+\+n", \var{i}, \var{i} );
    \}
  \}

  \instr{return} 0;
\}
\end{alltt}

\semaine{Lisibilité}{\datesd}

\probleme{15}

Leur montrer le fonctionnement de printf : \%s, \%i, \%c, ...

\probleme{10}

Voici plusieurs versions différentes pour le même problème.
Discutez des avantages et désavantage de chacun.

\medskip

Version 1~:

\begin{alltt}
#\directive{include} \str{<stdio.h>}

\type{int} \fonct{main}() 
\{
  \type{int} \var{i} = 0;

  \instr{for}( \var{i} = 48; \var{i} <= 126; \var{i}++ )
  \{
    \instr{if}( ( \var{i} >= 48 && \var{i} <= 57 )
         ||
        ( \var{i} >= 65 && \var{i} <= 90 )
         ||
        ( \var{i} >= 97 && \var{i} <= 122 ) )
    \{
      \fonct{printf}( "%i => %c\verb+\+n", \var{i}, \var{i} );
    \}
  \}

  \instr{return} 0;
\}
\end{alltt}

\medskip

\begin{itemize}
\item Bien écrit, le 'if' est très lisible.
\item Plusieurs itération de boucles inutiles puisqu'il n'affiche pas tout.
\end{itemize}

\medskip

Version 2~:

\begin{alltt}
#\directive{include} \str{<stdio.h>}

\type{int} \fonct{main}() 
\{
  \type{int} \var{i} = 0;

  \instr{for}( \var{i} = 48; \var{i} <= 126; \var{i}++ )
  \{
    \instr{if}( \var{i} >= 48 && \var{i} <= 57 )

    \{
      \fonct{printf}( "%i => %c\verb+\+n", \var{i}, \var{i} );
    \}

    \instr{if}( \var{i} >= 65 && \var{i} <= 90 )
    \{
      \fonct{printf}( "%i => %c\verb+\+n", \var{i}, \var{i} );
    \}

    \instr{if}( \var{i} >= 97 && \var{i} <= 122 )
    \{
      \fonct{printf}( "%i => %c\verb+\+n", \var{i}, \var{i} );
    \}
  \}

  \instr{return} 0;
\}
\end{alltt}

\medskip

\begin{itemize}
\item La pire version des trois.
\item Code répété inutilement.
\item Plusieurs itération de boucles inutiles puisqu'il n'affiche pas tout.
\end{itemize}

\medskip

Version 3~:

\begin{alltt}
#\directive{include} \str{<stdio.h>}

\type{int} \fonct{main}() 
\{
  \type{int} \var{i} = 0;

  \instr{for}( \var{i} = 48; \var{i} <= 57; \var{i}++ )
  \{
    \fonct{printf}( "%i => %c\verb+\+n", \var{i}, \var{i} );
  \}

  \instr{for}( \var{i} = 65; \var{i} <= 90; \var{i}++ )
  \{
    \fonct{printf}( "%i => %c\verb+\+n", \var{i}, \var{i} );
  \}

  \instr{for}( \var{i} = 97; \var{i} <= 122; \var{i}++ )
  \{
    \fonct{printf}( "%i => %c\verb+\+n", \var{i}, \var{i} );
  \}

  \instr{return} 0;
\}
\end{alltt}

\medskip

\begin{itemize}
\item Aucun 'if', aucun tours de boucle inutile.
\item Le code reste très lisible.
\end{itemize}

\probleme{15}

Réécrivez ce code pour qu'il soit plus lisible~:

\begin{alltt}
#\directive{include} \str{<stdio.h>}

\type{int} \fonct{main}()
\{
  \type{double} \var{i} = -40.0;

  \fonct{printf}( "+------------+------------+------------+------------+\verb+\+n" );
  \fonct{printf}( "|  Celsius   |   Kelvin   | Fahrenheit |  Rankine   |\verb+\+n" );
  \fonct{printf}( "+------------+------------+------------+------------+\verb+\+n" );
  \instr{while}( \var{i} <= 40.0 ) \{
    \type{double} \var{f} = \var{i} * 9 / 5 + 32;
    \type{double} \var{r} = \var{i} + 273.15 ;

    \fonct{printf}( "| %10.2f | %10.2f | %10.2f | %10.2f |\verb+\+n", \var{i}, \var{i} + 273.15, \var{f}, \var{r} * 9 / 5 );

    \var{i} += 5.0;
  \}
  \fonct{printf}( "+------------+------------+------------+------------+\verb+\+n" );


  \instr{return} 0;
\}
\end{alltt}

\medskip

\solution
\begin{alltt}
#\directive{include} \str{<stdio.h>}

\type{int} \fonct{main}() \{
  \type{const} \type{double} \var{ZERO_KELVIN} = 273.15;
  \type{const} \type{double} \var{FACTEUR_CONVERSION} = 9.0 / 5.0;
  \type{const} \type{double} \var{ZERO_FAHRENHEIT} = 32.0;
  \type{double} \var{celsius} = 0.0;

  \fonct{printf}( "+------------+------------+------------+------------+\verb+\+n" );
  \fonct{printf}( "|  Celsius   |   Kelvin   | Fahrenheit |  Rankine   |\verb+\+n" );
  \fonct{printf}( "+------------+------------+------------+------------+\verb+\+n" );
  \instr{for}( \var{celsius} = -40.0; \var{celsius} <= 40.0; \var{celsius} += 5.0 ) \{
    \type{double} \var{kelvin} = \var{celsius} + \var{ZERO_KELVIN};
    \type{double} \var{fahrenheit} = \var{celsius} * \var{FACTEUR_CONVERSION} + \var{ZERO_FAHRENHEIT};
    \type{double} \var{rankine} = \var{kelvin} * \var{FACTEUR_CONVERSION};

    \fonct{printf}( "| %10.2f | %10.2f | %10.2f | %10.2f |\verb+\+n", 
            \var{celsius}, \var{kelvin}, \var{fahrenheit}, \var{rankine} );
  \}
  \fonct{printf}( "+------------+------------+------------+------------+\verb+\+n" );

  \instr{return} 0;
\}
\end{alltt}

\probleme{30}

Voici un code C, ce code n'est pas très bien écrit, dites pourquoi.

\medskip

\begin{alltt}
#include <stdio.h>
#include <math.h>

#define TAILLE 20

int main()\{
  double tab[TAILLE] =
    \{ 2, 6, 4, 8, 1, 6, 9, 4, 2, 8, 3, 6, 2, 6, 2, 6, 87, 2, 4, 67 \};
  int i = 0;

  double moyenneArithmetique = 0.0;
  double moyenneGeometrique = 1.0;
  double moyenneHarmonique = 0.0;
  double moyenneQuadratique = 0.0;

  for( i = 0; i < TAILLE; i++ ) \{
    moyenneArithmetique += tab[i];
  \}
  for( i = 0; i < TAILLE; i++ ) \{
    moyenneGeometrique *= tab[i];
  \}
  for( i = 0; i < TAILLE; i++ ) \{
    moyenneHarmonique += ( 1.0 / tab[i] );
  \}
  for( i = 0; i < TAILLE; i++ ) \{
    moyenneQuadratique += ( tab[i] * tab[i] );
  \}

  moyenneArithmetique /= TAILLE;
  moyenneGeometrique = pow( moyenneGeometrique, 1.0 / TAILLE );
  moyenneHarmonique = TAILLE / moyenneHarmonique;
  moyenneQuadratique /= TAILLE;
  moyenneQuadratique = sqrt( moyenneQuadratique );

  printf( "Moyenne arithmetique : %f\verb+\+n", moyenneArithmetique );
  printf( "Moyenne geometrique : %f\verb+\+n", moyenneGeometrique );
  printf( "Moyenne harmonique : %f\verb+\+n", moyenneHarmonique );
  printf( "Moyenne quadratique : %f\verb+\+n", moyenneQuadratique );

  return 0;
\}
\end{alltt}

\medskip

réponse : Ce code contient quatres calcules imbriqué entre eux, cela enlève
de la lisibilité.  Aussi il y a quatres boucles similaires, cela est moins
performant qu'une seule boucles.

Essayez de corrigé le code pour le rendre plus performant~:

\medskip

\begin{alltt}
#include <stdio.h>
#include <math.h>

#define TAILLE 20

int main()\{
  double tab[TAILLE] =
    \{ 2, 6, 4, 8, 1, 6, 9, 4, 2, 8, 3, 6, 2, 6, 2, 6, 87, 2, 4, 67 \};
  int i = 0;

  double moyenneArithmetique = 0.0;
  double moyenneGeometrique = 1.0;
  double moyenneHarmonique = 0.0;
  double moyenneQuadratique = 0.0;

  for( i = 0; i < TAILLE; i++ ) \{
    moyenneArithmetique += tab[i];
    moyenneGeometrique *= tab[i];
    moyenneHarmonique += ( 1.0 / tab[i] );
    moyenneQuadratique += ( tab[i] * tab[i] );
  \}

  moyenneArithmetique /= TAILLE;
  moyenneGeometrique = pow( moyenneGeometrique, 1.0 / TAILLE );
  moyenneHarmonique = TAILLE / moyenneHarmonique;
  moyenneQuadratique /= TAILLE;
  moyenneQuadratique = sqrt( moyenneQuadratique );

  printf( "Moyenne arithmetique : %f\verb+\+n", moyenneArithmetique );
  printf( "Moyenne geometrique : %f\verb+\+n", moyenneGeometrique );
  printf( "Moyenne harmonique : %f\verb+\+n", moyenneHarmonique );
  printf( "Moyenne quadratique : %f\verb+\+n", moyenneQuadratique );

  return 0;
\}
\end{alltt}

\medskip

Dans ce cas bien que le code soit plus performant, il reste illisible.

Faites une version plus lisible.

\medskip

\begin{alltt}
#include <stdio.h>
#include <math.h>

#define TAILLE 20

int main()\{
  double tab[TAILLE] =
    \{ 2, 6, 4, 8, 1, 6, 9, 4, 2, 8, 3, 6, 2, 6, 2, 6, 87, 2, 4, 67 \};
  int i = 0;


  double moyenneArithmetique = 0.0;
  for( i = 0; i < TAILLE; i++ ) \{
    moyenneArithmetique += tab[i];
  \}
  moyenneArithmetique /= TAILLE;
  printf( "Moyenne arithmetique : %f\verb+\+n", moyenneArithmetique );


  double moyenneGeometrique = 1.0;
  for( i = 0; i < TAILLE; i++ ) \{
    moyenneGeometrique *= tab[i];
  \}
  moyenneGeometrique = pow( moyenneGeometrique, 1.0 / TAILLE );
  printf( "Moyenne geometrique : %f\verb+\+n", moyenneGeometrique );


  double moyenneHarmonique = 0.0;
  for( i = 0; i < TAILLE; i++ ) \{
    moyenneHarmonique += ( 1.0 / tab[i] );
  \}
  moyenneHarmonique = TAILLE / moyenneHarmonique;
  printf( "Moyenne harmonique : %f\verb+\+n", moyenneHarmonique );


  double moyenneQuadratique = 0.0;
  for( i = 0; i < TAILLE; i++ ) \{
    moyenneQuadratique += ( tab[i] * tab[i] );
  \}
  moyenneQuadratique /= TAILLE;
  moyenneQuadratique = sqrt( moyenneQuadratique );
  printf( "Moyenne quadratique : %f\verb+\+n", moyenneQuadratique );


  return 0;
\}
\end{alltt}

\medskip

Ici le code est plus lisible, il est facile de voir que nous pouvons 
rendre ce code procédurale en isolant les différentes moyenne, c'est 
un bon indice que le code est mieux divisé.

\probleme{15}

Voici un code C~:

\medskip

\begin{alltt}
#define TAILLE 10

int main() \{
  int tab[TAILLE] = \{4, 6, 8, 3, 9, 4, 6, 2, 6, 7\};
  int i = 0;

  int x = 8;
  int rep = 0;
  for( i = 0; i < TAILLE; i++ )\{
    if( tab[i] > x ) \{
      rep = i;
      i = TAILLE;
    \}
  \}
  if( rep != TAILLE ) \{
    // trouve
  \} else \{
    // non-trouve
  \}
  return 0;
\}
\end{alltt}

\medskip

Ce code utilise une boucle et pour sortir
il place la valeur de l'itérateur plus haut que TAILLE.
Ceci est une très mauvaise technique, réécrivez ce code
pour qu'il soit acceptable.

\begin{alltt}
#define TAILLE 10

int main() \{
  int tab[TAILLE] = \{4, 6, 8, 3, 9, 4, 6, 2, 6, 7\};
  int i = 0;

  int x = 8;
  int rep = 0;

  while( i < TAILLE && tab[i] < x ) \{
    i++;
  \}
  if( rep != TAILLE ) \{
    // trouve
  \} else \{
    // non-trouve
  \}
  return 0;
\}
\end{alltt}


\semaine{Cast, sizeof, tableau, allocation et pointeur.}{\datese}

\probleme{10}

Faire fonctionner le code suivant, pour qu'ils voient l'utilisation de sizeof.

\begin{alltt}
#include <stdio.h>

int main()
\{
  printf("char : %i octet\verb+\+n", sizeof( char ) );
  printf("short : %i octets\verb+\+n", sizeof( short ) );
  printf("int : %i octets\verb+\+n", sizeof( int ) );
  printf("long : %i octets\verb+\+n", sizeof( long ) );
  printf("float : %i octets\verb+\+n", sizeof( float ) );
  printf("double : %i octets\verb+\+n", sizeof( double ) );
  printf("long double : %i octets\verb+\+n", sizeof( long double ) );

  return 0;
\}
\end{alltt}

\probleme{10}

Un autre programme d'exemple pour voir le fonctionnement de sizeof et du cast.

\begin{alltt}
#include <stdio.h>

int main() \{
  short c = 100;
  printf( "sizeof( c ) = %i\verb+\+n", sizeof( c ) );
  printf( "sizeof( (double)c ) = %i\verb+\+n", sizeof( (double)c ) );

  char t1[10];
  int t2[10];
  int t3[] = \{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 \};
  printf( "sizeof( t1 ) = %i\verb+\+n", sizeof( t1 ) );
  printf( "sizeof( t2 ) = %i\verb+\+n", sizeof( t2 ) );
  printf( "sizeof( t3 ) = %i\verb+\+n", sizeof( t3 ) );

  return 0;
\}
\end{alltt}

\probleme{15}

Leurs montrer le code suivant qui contient une allocation dynamique 
d'un tableau.  (leurs expliquer le fonctionnement de malloc.)
(leurs montrer l'acces normal au tableau.)

\begin{alltt}
#include <stdio.h>

int main() {
  const TAILLE_TAB = 20;
  int * tab = (int *)malloc( sizeof( int ) * TAILLE_TAB );
  int i = 0;

  for( i = 0; i < TAILLE_TAB; i ++ ) {
    tab[i] = 5 * i + 2;
  }

  return 0;
}
\end{alltt}

\probleme{20}

Construire une fonction qui recoit un tableau de double
et sa taille en entrées.  Cette routine retourne la moyenne
arithmétique des éléments du tableau.

\probleme{15}

Écrire une procédure qui reçoit deux pointeurs sur des entiers
et échange les valeurs pointées.

\probleme{15}

Écrire une fonction qui reçoit deux pointeurs d'entier représentants
des tableaux et une valeur entière (n).  La procédure copie 'n'
valeur du premier tableau vers le deuxieme.

\probleme{15}

Construire une procédure qui alloue un tableau, l'initialise à 0 et
retourne un pointeur sur le début du tableau.  La procédure reçoit 
une valeur indiquant le nombre de case à allouer.

\semaine{Revision intra}{\datesf}

Voici des questions d'examens, certaines ont déjà des réponses.

\probleme{15}

Que va afficher le code suivant~:

\medskip

\begin{alltt}
#include <stdio.h>

int main() \{
  int u = 1;
  int v = 5;
  char i[6][6];
  char e[] = \{'w','w','a','w','w','w','s','s','s','z','s','s','s','s','s'\};
  int j = 0;
  int k = 0;

  for( j = 0; j < 6; j ++ )\{
    for( k = 0; k < 6; k ++ )\{
      i[j][k] = '.';
    \}
  \}

  for( j = 0; j < 15; j ++ )\{
    i[u][v] = 'O';
    u = u + ((e[j] == 's' && u != 5)?1:0) - ((e[j] == 'a' && u != 0)?1:0);
    v = v + ((e[j] == 'z' && v != 5)?1:0) - ((e[j] == 'w' && v != 0)?1:0);
  \}

  for( j = 0; j < 6; j ++ )\{
    for( k = 0; k < 6; k ++ )\{
      printf( "%c", i[k][j] );
    \}
    printf( "\verb+\+n" );
  \}

  return 0;
\}
\end{alltt}


réponse~:

\begin{alltt}
OOOO..
O..OOO
O.....
OO....
.O....
.O....
\end{alltt}

\probleme{15}

Écrivez une routine qui replace les éléments d'un tableau en ordre {\bf décroissant}.
Vous pouvez utiliser l'algorithme de tri que vous voulez.

\medskip

\begin{alltt}
void trier( int * vecteur, int nbrElement )
\end{alltt}


\probleme{15}

Que va affichez le programme suivant~:

\begin{alltt}
#include <stdio.h>
char p( char * a ) \{
  (*a)++;
  a++;
  return *a;
\}

void r( char * a, char * b ) \{
  *a = *b;
\}

void s( char * a, char c, char i ) \{
  for( i-- ; i >= 0; i-- ) \{
    *(a + i) = c;
  \}
\}

int main( void ) \{
  int i = 0;
  char a = 30;
  char b = 40;
  char c[a];
  char * d = c;
  s( c, b, a );
  p(d);
  p(d);
  d += 2;
  r( d, c );
  p( c );
  r( d - 1, c );
  p( c );
  p( c );
  p( c );
  r( d + 1, c );
  for( i = 0; i < 10; i++ ) \{
    printf( "%i ", c[i] );
  \}
  printf( "\verb+\+n" );
  return 0;
\}
\end{alltt}

réponse~:

46 43 42 46 40 40 40 40 40 40 

\probleme{10}

Expliquez la différence entre cohésion communicationnelle et
cohésion temporelle.

Réponse~: la cohésion communicationnelle utilise une données de
départ qui sert à toutes les tâches.  La cohésion temporelle
n'a pas de données communes aux tâches.

\probleme{10}

Nous avons un module de traitement de {\bf Date}.
Ce module contient une fonction qui calcule si une date est bissextile et
ensuite utilise ce résultat pour calculer le nombre de jours dans l'année.  
Cette fonction retourne le nombre de jour dans l'année.
Proposez un nom pour cette fonction.
Quel est la cohésion de cette routine à l'intérieur du contexte de {\bf Date}.

Réponse~: nombreJoursAnnée, cohésion fonctionnelle. (séquentielle est 
acceptable comme réponse.)

\probleme{20}

Soit les déclarations suivantes~:

\begin{alltt}
struct _date \{
  unsigned short jour;
  unsigned short mois;
  unsigned int annee;
\};

struct _entree \{
  struct _date date;
  char * description;
  int montant_cent;
\};
\end{alltt}

\medskip

Chaque entrée représente la description d'un item.
Cette description contient un maximum de 50 caractères.
Le champs {\tt montant\_cent} indique la somme payée pour cette item en cent.
Le champ {\tt date} indique la date de l'achat.
Une facture est représentée par un tableau d'entrées (struct \_entree *).
Vous devez écrire une procédure qui affiche la facture d'un client.
Cette procédure affiche la facture à raison de un item par ligne.
Une ligne commence par la date affichée selon le format suivant~:
aaaa/mm/jj.
Ensuite vous devez afficher 3 espaces.
La description est affichée après les trois (3) espaces.
Si la description contient moins de 50 caractères alors
des espaces sont affichées jusqu'à ce qu'il y ait 50 caractères
affichés.
Ensuite affichez 5 espaces supplémentaires.
Enfin affichez le montant avec un point séparant les dollars des cents.
Le montant est suivit d'une espace et du caractère '\$'.
Le montant est affiché sur 10 cases.
Le montant doit être aligné à droite.
Après avoir affiché tout les items vous affichez le total.
Le total n'a pas de date.
La description pour le total est 'Total'.
Le total est affiché dans le même format que les montants.
Remarque~: la facture n'a pas d'entrée pour le total,
votre procédure doit le calculer.
Exemple d'affichage~:

\medskip

\begin{alltt}
2007/05/04   Televiseur                                              1299.99 $
2007/05/11   Livre "The Java Language Specification"                   49.99 $
2007/05/13   Imprimante                                                69.99 $
             Total                                                   1419.97 $
\end{alltt}

\medskip

Voici l'entête de la procédure~:

\medskip

\begin{alltt}
void afficher_facture( struct _entree * a_facture, int a_nombreEntree );
\end{alltt}

\semaine{}{\datesg}
\semaine{Chaine de caracteres, arguments du main}{\datesh}

\probleme{20} 

Construire une routine qui parcours une chaîne de caractères
et remplace les majuscules par des minuscules.

\probleme{10}

Nous avons une chaîne de caractères existante (constante)
et vous devez utiliser strlen pour allouer de l'espace afin de faire un
double de la chaîne avec strcpy.

\probleme{30}

Construire une routine de tri (sélection ou insertion) sur un tableau de
chaîne de caractères en utilisant strcmp.

\probleme{10} 

Exécutez le programme suivant avec des arguments sur la ligne de commande~:

\begin{alltt}
#include <stdio.h>

int main( int argc, char * argv[] ) \{
  int i = 0;

  for( i = 0; i < argc; i++ ) {
    printf( "%s\verb+\+", argv[i] );
  }

  return 0;
\}
\end{alltt}

\probleme{10} 

Construire un programme qui tri les arguments reçus en ordre alphabétique
et ensuite les affiche.  (utilisez les programme des derniers numéro.) 


\semaine{Makefile et compilation séparée}{\datesi}

\probleme{30}

Sur mon site il y a un projet complet : 'Petit projet et sa doc'.
telecharger le 'code' et defaire l'archive avec 'gunzip' et 'tar xvf'.

\begin{itemize}
\item Regardez avec comment les .h sont fais (define, ifndef, ...)
\item Regardez aussi la divisions .h/.c, faires remarquer quel fichier contient
 les typedef, struct, ...
\item Regardez le makefile.
\item Faire compiler le projet avec la commande 'make'
\end{itemize}

\probleme{20}

Construire un projet simple : 

\begin{itemize}
\item Un fichier avec le main.
\item 1 module avec sa version .h et .c.  Ajoutez une procedure dans ce
module.  Faire un appel de cette procedure dans le main.
\item Le .c doit inclure le .h, le main doit inclure le .h.
\item Faire une compilation separe du projet sans makefile.
\item Construire le makefile
\end{itemize}

\semaine{Script bash}{\datesj}

\probleme{15}

Écrivez et essayez le script suivant, n'oubliez pas
de rendre le script exécutable.
Ce script demande le nom d'un fichier pour placer le résultat,
n'utilisez pas un fichier existant car il sera effacé par
le script.  Testez ce script dans un répertoire contenant
des fichier de code c.  Puisque vous allez travailler un script
il est important d'utiliser un répertoire contenant du code
auquel vous ne tenez pas. (faites une copie d'un répertoire.)

\medskip

\begin{alltt}
#!/bin/bash

if [ -e$1 ]
then
  \verb+\+rm -f $1
fi

touch $1

for fichier in `ls *.c`
do
  echo >> $1
  echo "/*** fichier $\{fichier\} ***/" >> $1
  cat -b $\{fichier\} >> $1
done

\end{alltt}

\probleme{10}

Modifiez le script précédant pour qu'il ajoute les fichiers .h
dans l'archive.

\probleme{15}

Réécricez le script suivant et étudiez le.

\medskip

\begin{alltt}
#!/bin/bash

if [ -e$1 ]
then
  \verb+\+rm -f $1
fi

touch $1

for fichier in `ls *.[ch]`
do
  echo >> $1
  echo "/*** fichier $\{fichier\} ***/" >> $1
  grep "include" $\{fichier\} >> $1
done

\end{alltt}

\probleme{20}

Réécrivez le script du numéro précédant pour qu'il 
s'appele récursivement dans les sous 
répertoires du répertoire courrant.

\semaine{Programmation défensive~: assert}{\datesk}

\probleme{10} 
Regarder les assertions de la routines additionner (GrandNombres.c)
et son contrat (GrandNombres.h), voir les relations entre les deux.
(dans l'onglet exemple : assertion, erreur, exception.

\probleme{15}
Écrire une fonction qui à la signature suivante~:

{\tt int iemElement( int * tableau, int taille, int index );}

La routine retourne la valeur à la position index du tableau.
Elle s'assure que index est valide (entre 0 et taille) et
que le pointeur de tableau n'est pas NULL, le tout avec
des assertions.

\probleme{20}

Voici la description de deux structures de données~:

\medskip

\begin{alltt}
typedef struct \{
  int exceptionLevee;
  double discriminant;
\} 
ExceptionDiscriminantNegatif;

typedef struct \{
  double premiereValeur;
  double deuxiemeValeur;
\}
PaireDouble;
\end{alltt}

\medskip

Écrivez le code de la routine suivante avec ses erreurs et assertions.

\medskip

\begin{alltt}
/**
 * Cette fonction calcule les zéros de la fonction quadratique
 * ax^2 + bx + c
 * Le pointeur d'exception ne peu pas etre NULL (assertion)
 * Le discriminant est calculé : b^2 - 4ac
 * Si le résultat est négatif alors exceptionLevee de la structure
 *   d'exception est placé à vrai et le champs discriminant prend
 *   la valeur du discriminant.  La routine se termine sans calculer
 *   de résultat.
 * Calculer les deux résultats : 
 *  1 : (-b + discriminant) / (2a)
 *  2 : (-b - discriminant) / (2a)
 * Si 2a donne 0 alors affichez et message d'erreur et quittez avec exit.
 * Placez les résultats dans une structure PaireDouble et la retourner.
 * Remarque : si le discriminant == 0 alors les deux résultats seront égaux.
 */
PaireDouble zeroQuadratique( double a_a, double a_b, double a_c,
                             ExceptionDiscriminantNegatif a_exception );
\end{alltt}

\probleme{20}

Modifiez le code du numéro précédant pour enlever l'exception.
Pour cela la valeur de retour peu avoir trois possibilité~:

\begin{itemize}
  \item 2 valeurs
  \item une seule valeur
  \item exception discriminant négatif
\end{itemize}

Utilisez une Union pour le choix du résultat et un type enuméré pour
identifier le résultat.

\probleme{10}

Pour la fonction zeroQuadratique remplacez l'erreur par une exception
division par zéro.  Vous pouvez travailler sur la version de
votre choix pour cette fonction.

\probleme{10}

Toujours pour la fonction quadratique, ajoutez des assertions
à la fin du programme qui vérifie que les valeurs de retour
sont correcte.  Pour cela utilisez les dans la formule
et vérifiez que cela donne une valeur près de zéro.  
(avec des valeurs point flottant il n'est jamais assuré
qu'après un calcule la valeur garde une précision parfaite.)

\semaine{CVS}{\datesl}

Voir CVS.  

page : http://www.labunix.uqam.ca/~tremblay/INF3135/

document : Gestion de la configuration des logiciels (SCM)

\begin{itemize}
\item intro : p5
\item init : p6
\item CVSROOT : p9
\item import : p10
\item checkout : p11
\item update : p15
\item commit : p17
\item add : p20
\end{itemize}

\semaine{Tests Unitaires}{\datesm}


\probleme{10}

Construire les tests unitaires pour la routine suivante~:

{\tt int iemElement( int * tableau, int taille, int index );}

\medskip

La routine retourne la valeur à la position index du tableau.
Elle s'assure que index est valide (entre 0 et taille),
que le pointeur de tableau n'est pas NULL et
que la taille est plus grande que 0,
 le tout avec
des assertions.

{\bf réponse}

\begin{alltt}
int t1[1] = {5};
int t2[2] = {5, 10};
int t3[5] = {5, 10, 15, 20, 25};

//  taille = 1, index = 0.
assert( 5 == iemElement( t1, 1, 0 ) );

// taille = 2, index = 0.
assert( 5 == iemElement( t2, 2, 0 ) );

// taille = 2, index = 1.
assert( 10 == iemElement( t2, 2, 1 ) );

// taille = 5, index = 0.
assert( 5 == iemElement( t3, 5, 0 ) );

// taille = 5, index = 2.
assert( 15 == iemElement( t3, 5, 2 ) );

// taille = 5, index = 4.
assert( 25 == iemElement( t3, 5, 4 ) );
\end{alltt}

Ne pas tester le cas de pointeur NULL ou d'un tableau de taille 0.
Ces cas ne sont pas permis donc ils ne sont pas testés.

\probleme{60}

Soit le .h suivant~:

\begin{alltt}
#ifndef BANQUE_H
#define BANQUE_H

/**
 * Type de données abstrait contenant la description d'un
 * client.
 */
typedef struct _client Client;

/**
 * Type de données abstrait contenant la description d'un
 * compte.
 */
typedef struct _compte Compte;

/**
 * Fonction de construction d'une structure Client.
 * @param a_nom (char *) une chaine contenant le nom du 
 *  client.
 * @precondition a_nom != NULL
 * @param a_prenom (char *) une chaine contenant le prenom
 *  du client
 * @precondition a_prenom != NULL
 * @param a_noClient (int) un entier identifiant de facon
 *  unique le client.
 * @precondition a_noClient > 0
 * @return Un pointeur sur un Client.  Les chaines 'a_nom'
 *  et 'a_prenom' ont ete copiees dans la structure.
 */
Client * creerClient( char * a_nom, char * a_prenom, int a_noClient );

/**
 * Fonction de construction d'une structure Compte.
 * @param a_noIdentification (int) un numero d'identification
 *  unique pour le compte.
 * @param a_noClient (int) un numero identifiant le proprietaire
 *  du compte.
 * @precondition a_noClient > 0
 * @return Un pointeur sur un Compte.  L'actif du compte
 *  est place a zero (0) lors de la creation.
 */
Compte * creerCompte( int a_noIdentification, int a_noClient );

/**
 * Procedure modifiant l'actif d'un compte pour ajouter
 * de l'argent.
 * @param a_compte (Compte *) le compte a modifier.
 * @precondition a_compte != NULL
 * @param a_montant (long) montant (en cent) du depot.
 * @precondition a_montant > 0
 * @postcondition actif = actif + a_montant
 */
void depot( Compte * a_compte, long a_montant );

/**
 * Procedure modifiant l'actif d'un compte pour soustraire
 * de l'argent.
 * @param a_compte (Compte *) le compte a modifier.
 * @precondition a_compte != NULL
 * @param a_montant (long) montant (en cent) du retrait.
 * @precondition a_montant > 0
 * @exception e_transactionApprouve cette valeur est placee 
 *  a un (1) s'il y avait assez d'argent pour le retrait.
 *  sinon elle est placee a zero (0).
 * @postcondition actif = actif - a_montant
 */
void retrait( Compte * a_compte, long a_montant, int * e_transactionApprouve );

/**
 * Fonction retournant l'actif d'un compte.
 * @param a_compte (Compte *) le compte a consulter.
 * @precondition a_compte != NULL
 * @return l'actif du compte.
 */
long actif( Compte * a_compte );

/**
 * Fonction afin de calculer l'actif total de tout les
 * comptes d'un client.
 * @param a_client (Client *) le client a traiter.
 * @precondition a_client != NULL
 * @param a_comptes (Compte *[]) un tableau de tout les
 *  les comptes du systeme.
 * @precondition a_comptes != NULL
 * @param nombreCompte (int) la taille du tableau a_comptes
 * @return l'avoir total des comptes appartenant au client.
 */
long calculerAvoir( Client * a_client, Compte * a_comptes[], 
		    int a_nombreCompte );

#endif
\end{alltt}

\medskip

a) Construisez les tests unitaires pour les routines suivantes~:
depot, actif.

\begin{alltt}
Compte * c1 = creerCompte( 1, 1 );
Compte * c2 = creerCompte( 2, 2 );

assert( 0 == actif( c1 ) );
depot( c1, 1 );
assert( 1 == actif( c1 ) );
depot( c2, 14649 );
assert( 14649 == actif( c2 ) );
depot( c1, 1 );
assert( 2 == actif( c1 ) );
depot( c2, 111 );
assert( 14760 == actif( c2 ) );
\end{alltt}

Remarque~: puisque ces routines ne tiennent pas compte des débordements il
est impossible de faire des tests sur la borne supérieure.

b) Les constructeurs nous donne des valeurs construites.  Pour réussir
à les tester il faut connaitre le contenue des structures~:

\begin{alltt}
/**
 * structure decrivant un client.
 * @field nom (char *) une chaine de caractere contenant le
 *  nom du client.
 * @invariant nom != NULL
 * @field prenom (char *) une chaine de caractere contenant
 *  le prenom du client.
 * @invariant prenom != NULL
 * @field noClient (int) un numero identifiant le client de
 *  facon unique.
 * @invariant noClient > 0
 */
struct _client {
  char * nom;
  char * prenom;
  int noClient;
};

/**
 * structure decrivant un compte.
 * @field noIdentification (int) un numero identifiant de
 *  facon unique un compte.
 * @field noClient (int) un numero identifiant le proprietaire
 *  du compte.
 * @invariant noClient > 0
 * @field actif (long) le montant d'argent que contient le
 *  compte.  Ce montant est en cent.
 * @invariant actif >= 0
 */
struct _compte {
  int noIdentification;
  int noClient;
  long actif;
};
\end{alltt}

Ensuite vous utilisez la routine et vérifiez le contenue des différents champs.
Écrivez les tests unitaires pour creerCompte et creerClient.

\begin{alltt}
Compte * co = creerCompte( 1, 5 );
assert( 1 == c->noIdentification );
assert( 5 == c->noClient );
assert( 0 == c->actif );

char * prenom = "Bruno";
char * nom = "Malenfant";
Client * cl = creerClient( nom, prenom, 1 );
assert( nom != cl->nom );
assert( 0 == strcmp( nom, c1->nom ) );
assert( prenom != cl->prenom );
assert( 0 == strcmp( prenom, cl->prenom ) );
assert( 1 == cl->noClient );
\end{alltt}

c) La routine retrait utilise une exception.  Il faut lui passer une
variable entrées/sorties pour le retour d'exception.
Faites les testes pour retrait, n'oubliez pas de tester l'exception.

\begin{alltt}
Compte * c1 = creerCompte( 1, 1 );
int exc = 0;

retrait( c1, 1, &exc );
assert( 0 == actif( c1 ) );
assert( exc );

exc = 0;
depot( c1, 1 );
retrait( c1, 1, &exc );
assert( 0 == actif( c1 ) );
assert( ! exc );

depot( c1, 1 );
retrait( c1, 2, &exc );
assert( 1 == actif( c1 ) );
assert( exc );

exc = 0;
depot( c1, 1000 );
retrait( c1, 1, &exc );
assert( 1000 == actif( c1 ) );
assert( ! exc );

retrait( c1, 500, &exc );
assert( 500 == actif( c1 ) );
assert( ! exc );

retrait( c1, 1000, &exc );
assert( 500 == actif( c1 ) );
assert( exc );

exc = 0;
retrait( c1, 500, &exc );
assert( 0 == actif( c1 ) );
assert( ! exc );
\end{alltt}

d) Discutez des méthodes pour tester calculerAvoir. 
(Remplir le tableau de compte)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\semaine{Revision examen}{\datesn}

\probleme{15}

Nous voulons construire un logiciel en utilisant une technique de développement
dirigée par les tests.

a) Quels sont les avantages à avoir une cohésion fonctionnelle pour
nos routines dans un tel type de développement ?

{\bf réponse~:}

cohésion fonctionnelle -> une seule tache simple -> peu de test a faire
-> tres rapide pour revenir au vert.

b) En quoi l'utilisation d'outils tel que Junit peuvent-ils nous
assiter dans un développement dirigé par les tests ?

{\bf réponse~:}

automatisation et classification des tests.
Permet de tester rapidement et souvent.


\probleme{30}

Soit les déclarations suivantes~:

\begin{alltt}
typedef enum \{ LIQUIDE, GRANULE, SOLIDE \} TypeIgredient;
typedef union \{
  float litre;
  unsigned short gramme;
  unsigned char unite;
\} Mesure;
typedef struct \{
  char * nom;
  Mesure quantite;
  TypeIgredient type;
\} Ingredient;
typedef struct \{
  Ingredient * disponible;
  int nbrIngredient;
\} Cuisine;
typedef struct \{
  char * nom;
  Ingredient * demande;
  int nbrIngredient;
\} Recette;
\end{alltt}

La structure {\tt Cuisine} représente les aliments disponibles dans une
cuisine.  Chaque élément du tableau '{\tt disponible}' contient le nom de
l'ingrédient (char *) et la quantité disponible (le nom sert à identifier
l'ingrédient).
Pour un ingrédient de type {\tt LIQUIDE} nous mesurons la quantité en litre.
Pour un ingrédient de type {\tt GRANULE} nous mesurons la quantité en gramme.
Pour un ingrédient de type {\tt SOLIDE} nous mesurons la quantité en nombre
d'unité disponible.

La structure {\tt Recette} représente une recette avec son {\tt nom}, la liste
des ingrédients {\tt demandé} pour la recette et le nombre d'ingrédient dans
le tableau '{\tt demande}'.

Nous voulons écrire une fonction ayant la signature suivante~:

\begin{alltt}
/**
 * Fontion permettant de verifier si nous pouvons faire une 
 * recette.
 * @return Cette fonction retourne true si tout les ingredients
 * de la recette sont disponible en quantite suffisante dans
 * la cuisine.  Elle retourne faux sinon.
 * @param recette : la liste des ingredients d'une recette a faire.
 * @pre recette != NULL.
 * @param cuisine : la liste des ingredients disponible.
 * @pre cuisine != NULL.
 */
int ingredientDisponible( Recette * recette, Cuisine * cuisine );
\end{alltt}

a) Écrivez le code pour cette fonction.  Votre code doit utiliser
les techniques de programmation défensive : verifier les pré-conditions, 
vérifier les accès pouvant causer des problèmes (pointeur, tableau).

{\bf réponse~:}

\begin{alltt}
int ingredientDisponible( Recette * recette, Cuisine * cuisine ) \{
  assert( recette != NULL );
  assert( demande != NULL );
  int resultat = 1;
  int i = 0;
  int j = 0;
  for( i = 0; i < recette->nbrIngredient; i++ ) \{
    int trouve = 0;
    for( j = 0; j < cuisine->nbrIngredient; j ++ ) \{
      assert( 0 <= i && i < recette->nbrIngredient );
      assert( 0 <= j && j < cuisine->nbrIngredient );
      assert( recette->demande[i].nom != NULL );
      assert( cuisine->disponible[j].nom != NULL );
      if( 0 == strcmp( recette->demande[i].nom, cuisine->disponible[j].nom ) ) \{
        trouve = 1;
        switch( recette->demande[i].type ) \{
          case LIQUIDE :
            if( recette->demande[i].quantite.litre > 
                cuisine->disponible[j].quantite.litre ) \{
              resultat = 0;
            \}
            break;
          case GRANULE :
            if( recette->demande[i].quantite.gramme > 
                cuisine->disponible[j].quantite.gramme ) \{
              resultat = 0;
            \}
            break;
          case SOLIDE :
            if( recette->demande[i].quantite.unite > 
                cuisine->disponible[j].quantite.unite ) \{
              resultat = 0;
            \}
            break;
        \}  
      \}
    \}
    if( !trouve ) \{
      resultat = 0;
    \}
  \}
  return resultat;
\}
\end{alltt}


b) Décrivez les cas de test unitaire (boîte noire) complet pour
tester cette fonction.  Cette description doit indiquer chaque test avec 
les arguments utilisés et les résultats attendus.

\probleme{30}

Soit le code suivant~:

\begin{alltt}
 1 Palette * lirePalette( char * a_nomFichier ) \{
 2   Palette * resultat = creerPalette();
 3   FILE * fichierCouleur = fopen( a_nomFichier, "r" );
 4   if( NULL == fichierCouleur ) \{
 5     fprintf( stderr, "erreur lors de louverture du fichier.\verb+\+n" );
 6   \}
 7   do \{
 8     double rouge, vert, bleu;
 9     int n = fscanf( fichierCouleur, "%lf %lf %lf", &rouge, &vert, &bleu );
10     if( 3 == n ) \{
11       Couleur * couleur = ( Couleur * ) malloc( sizeof( Couleur ) );
12       if( NULL == couleur ) \{
13         fprintf( stderr, "erreur d'allocation.\verb+\+n" );
14       \} 
15       couleur->rouge = rouge;
16       couleur->vert  = vert;
17       couleur->bleu  = bleu;
18       couleur->alpha = 1; 
19       ajouterCouleur( resultat, couleur );
20     \} else if ( n != -1 ) \{
21       fprintf( stderr, "erreur de lecture dans le fichier de couleur.\verb+\+n" );
22     \}
23   \} while( ! feof( fichierCouleur ) );
24   return resultat;
25 \}
\end{alltt}

a) Tracez le graphe représentant ce code.


b) Calculez la complexité cyclomatique de ce graphe.

{\bf Réponse~:}
6

c) Donnez les chemins indépendants permettant de faire la 
couverture du graphe.

{\bf Réponse~:}

2-4-7-10-12-15-23-24

2-4-5-7-10-12-15-23-24

2-4-7-10-12-13-15-23-24

2-4-7-10-20-22-23-24

2-4-7-10-20-21-22-23-24

2-4-7-10-12-15-23-7-10-12-15-23-24

\probleme{10}

Quel sont les avantages d'un système d'exception par rapport à 
une technique où un message d'erreur est affiché suivit d'un arrêt du
programme.

{\bf Réponse~:}

Les exceptions permettent la reprise de l'exécution.
Elles permettent aussi à l'utilisateur de corriger l'information qu'il entre.


%\semaine{}{\dateso}

\end{document}

%% FIN 
%% Local Variables:  
%% compile-command: "C:\\Progra~1\\TeXLive\\bin\\win32\\latex.exe demo2010.tex" 
%% End: 
