tete du loic

 Loïc YON [KIUX]

  • Enseignant-chercheur
  • Référent Formation Continue
  • Responsable des contrats pros ingénieur
  • Référent entrepreneuriat
  • Responsable de la filière F2 ingénieur
  • Secouriste Sauveteur du Travail
mail
loic.yon@isima.fr
phone
(+33 / 0) 4 73 40 50 42
location_on
ISIMA
  • twitter
  • linkedin
  • viadeo

[C] The last but not the least

Date de première publication : 2014/12/8

Ce dernier TP vise à expérimenter les dernières notions vues en cours...

Fonctions à nombre d'arguments variable

Voici le code donné en cours :


double moyenne(int nombre, ...) {
  double  result = 0; 
  int     nb     = 0;
  va_list liste; 
  
  va_start(liste, nombre);
  while (nombre>0) {
    result += nombre;
    nb     += 1;
    nombre = va_arg(liste, int); 
  } 
  va_end(liste);
  if (nb>0) result /= nb;
  return result;
} 

Compilez-le et exécutez-le, par exemple avec :


printf("%lf", moyenne(-1));
printf("%lf", moyenne(2, 2, 5, -1)); 

À votre avis, que fait le programme suivant :

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
	
int main()
{
	struct dirent * lecture;
	DIR *rep;
	rep = opendir("." );
	while ((lecture = readdir(rep))) {
	    printf("%s\n", lecture->d_name);
	}
	closedir(rep);
}

Créer une fonction à nombre d'arguments variable qui affiche le contenu des répertoires passés en paramètre, soit en spécifiant le nombre de répertoires ou alors en terminant la liste avec une valeur comme NULL.

fonction1(2, "tp1", "tp2");
fonction2("tp1", "tp2", NULL);

Développer un code de tri générique

Compilez le code suivant et exécutez le code suivant :


void print(int t[], int n) {
    for(int i = 0; i< n; ++i)
       printf("%d ", t[i]);
    printf("\n");
}

void tri(int t[], int n) {
  for (int i = 1; i < n; i++) {
    double cle = t[i];
    int j = i - 1;

    while (j >= 0 && t[j] > cle) {
      t[j + 1] = t[j];
      --j; 
    }
    t[j + 1] = cle;
  }
}

int main(){
    int t [] = { 3, 1, 5, 2, 10, 7};
    
    print(t, 6);
    tri(t, 6);
    print(t, 6);
    
    return 0;
}

Si vous compilez avec l'option -S, vous allez obtenir un fichier qui contient l'assembleur de votre programme (vous pouvez aussi utiliser https://godbolt.org/)

On "voit" alors la définition des fonctions print, tri et main et les appels des fonctions print et tri.

Il faut écrire une fonction inferieur et modifier tri pour appeler cette fonction de comparaison.


int inferieur(int a, int b) {
    return a < b;
}

La compilation avec "-S" montre alors la nouvelle fonctioninferieuret que la fonction tri appelle bien la fonction inferieur.

Si l'on compile avec l'option -O2 (moins eau deux), le compilateur optimise notre code et élimine l'appel de la fonction inferieur en remplaçant par le code de la fonction elle-même.

Paramétrer la fonction de comparaison

En ayant explicité la fonction de comparaison, il est maintenant possible de paramétrer l'algorithme de tri. Il faut alors écrire, par exemple, la fonction "inverse" à la fonction inferieur.

Vous avez deux possibilités :

  1. écrire une macro TRI
  2. écrire une fonction tri2

Les trois paramètres sont les mêmes : le nom du tableau, la taille et la fonction de comparaison.


TRI(t, 6, inferieur);
tri2(t, 6, superieur);

Quand la macro est "compliquée", elle peut ressembler à cela :


#define MACRO(A, B, C) \
do { \ 
  // code de la macro \
  // chaque ligne se termine par un slash sauf la derniere \
} while (0) 

Pour tri2, le dernier paramètre est un pointeur de fonction.

Faire abstraction du type à trier

Pour faire abstraction du type à trier, le plus simple est d'écrire une macro dont un des paramètres est le nom du type à trier :


TRI(int, t, 6,  inferieur);
TRI(double, t, 12, superieur_double);

Si vous voulez plutôt utiliser une fonction, il faut manipuler des pointeurs void * dès que possible à l'image de la fonction de comparaison :


int inferieur(void * p1, void * p2) {
  int * i1 = (int *)p1;
  int * i2 = (int *)p2;
  return *i1 < *i2;
}

Dans l'exemple qui est donné, le tableau est du type int [], on peut le voir comme int * puis finalement comme void *

Il reste alors à coder l'affectation entre deux valeurs de même type en utilisant la fonction standard memcpy

Utiliser la fonction qsort()

Vous devez maintenant adapter le code que vous avez fait pour appeler la fonction de tri qsort. Il ne faut pas oublier que la fonction de comparaison est légèrement différente de ce que nous avons fait jusqu'à maintenant. (elle en renvoie pas vrai ou faux mais -1, 0 ou +1)

Annuaire des languages

Fichiers binaires


donnee_t tab[] = { {"Gosling", "Java", 1993}, 
                   {"Van Rossum", "Python", 1991}, 
                   {"Stroustrup", "C++", 1983},
                   {"Ritchie", "C",1972} 
                 };
AuteurLangageAnnée
Backus JohnFORTRAN1957
Goldfarb CharlesGML1969
Wirth NiklausPascal1970
Ritchie DennisC1972
Kernighan BrianC1972
Sussman Gerald JayScheme1975
Steele Guy LScheme1975
Naughton PatrickJava1983
Cox BradObjective C1983
Berners Lee TimWWW~1990
Van Rossum GuidoPython1991
Gosling JamesJava1993
Lerdorf RasmusPHP1994
Heich BrendanJavascript1995
Odersky MartinScala2003
Hoare GraydonRUST2006
Lattner ChrisSwift2014

Tri des données

En utilisant qsort() et les bonnes fonctions de comparaison,

Questions

Que se passe-t-il dans les cas suivants :