Questions INGINIOUS

  1. Faites l’exercice relatif à printf(3) sur INGINIOUS : https://inginious.info.ucl.ac.be/course/LSINF1252/printf

  2. Un utilisateur peut adapter le comportement d’un programme via les arguments passés en ligne de commande. Ecrivez un programme permettant d’afficher un argument sur deux tel qu’indiqué sur INGINIOUS: https://inginious.info.ucl.ac.be/course/LSINF1252/main_argc

  3. L’an dernier, vous avez écrit un programme permettant de détecter si une chaîne de caractères était un palindrome. Faites de même en C avec l’exercice INGINIOUS https://inginious.info.ucl.ac.be/course/LSINF1252/palindrome

  4. Ecrivez le corps de la fonction swap2 permettant d’échanger les valeurs stockées dans deux variables de type entier. Faites de même lorsque les arguments de cette fonction sont des structures contenant des fractions : https://inginious.info.ucl.ac.be/course/LSINF1252/swap2int

  5. La libraire string(3) implémente un grand nombre de fonctions de manipulation des strings qui vous serons utile lors de différents projets de programmation.

    Ecrivez le code implémentant ces trois fonctions. Pour cela, créez un fichier string.c contenant la définition des fonctions et un fichier string.h avec les déclarations des fonctions. Vous devez aussi fournir un Makefile (cfr Introduction aux Makefiles) qui permet de recompiler facilement votre programme en tapant make. Pensez à implémenter quelques tests pour vos fonctions dans la fonction main et n’incluez pas l’exécutable dans l’archive. Pour la réalisation de ces tests, utilisez une librairie de tests unitaires telle que CUnit

    Lorsque vous considérez que votre programme est correct, testez son bon fonctionnement via l’exercice correspondant sur inginious : https://inginious.info.ucl.ac.be/course/LSINF1252/mini-projet-string

  6. Faites l’exercice swap sur INGInious

  7. Faites les exercices de manipulation de bits sur INGInious. Pour réaliser ces exercices, réfléchissez d’abord sur papier, par exemple sur des blocs de 4 ou 8 bits. Pour la plupart des questions, il faut combiner des décalages à gauche ou à droite avec des opérations AND (&), OR (|) et NOT (~) bit à bit.

Verifiez vos réponses

Questions de discussion

  1. Soit char *ptr = "Test". Itérez sur ce pointeur et affichez avec printf(3) la valeur et l’adresse mémoire où se trouve stocké chaque caractère de deux façons différentes. Regardez la manpage de printf(3) pour savoir comment afficher la valeur d’un pointeur.

  2. Lorsque l’on veut améliorer les performances d’un programme, il est utile de pouvoir mesurer précisément son temps d’exécution. La commande time(1posix) permet d’effectuer cette mesure depuis la ligne de commande. Parfois, on souhaite mesurer le temps de calcul une partie critique d’un code. Une façon simple pour obtenir cette mesure est d’utiliser gettimeofday(2) comme dans l’exemple ci-dessous (/Programmes/s2_perf.c).

    /***********************************************
     * perf.c
     *
     * Mesure de temps de calcul via gettimeofday
     *
     ***********************************************/
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/time.h>
    
    /* Return t2-t1 in microseconds */
    long timeval_diff(struct timeval *t2, struct timeval *t1)
    {
      long diff = (t2->tv_usec + 1000000 * t2->tv_sec) - (t1->tv_usec + 1000000 * t1->tv_sec);
      return (diff);
    }
    // n : number of iterations of the loop
    void compute(int n) {
      // long computation
      double sum=0;
      int i;
      for(i=0;i<n;i++) {
        sum=sum+i;
      }
    }
    
    int main(int argc, char *argv[])
    {
      struct timeval tvStart, tvEnd;
      int err;
      int num; // number of operations for compute
      if(argc!=2)
        exit(EXIT_FAILURE);
      else
        num=atoi(argv[1]);
    
      err=gettimeofday(&tvStart, NULL);
      if(err!=0)
        exit(EXIT_FAILURE);
    
      // long computation
      compute(num);
    
      err=gettimeofday(&tvEnd, NULL);
      if(err!=0)
        exit(EXIT_FAILURE);
    
      printf("Duration : %ld microseconds\n", timeval_diff(&tvEnd, &tvStart));
    
      return(EXIT_SUCCESS);
    }
    
    

    Pour certaines opérations, les performances dépendent du type de données utilisé. Modifiez le programme ci-dessous de façon à utiliser un calcul plus compliqué que la simple addition et comparez sur de longues itérations (\(10^7\) ou plus) les performances de cette opération lorsqu’elle utilise des int, long long, double ou float. Les performances sont-elles identiques ?

Questions de bilan final

  1. La structure suivante foo_t est définie de façon à ce qu’elle contienne un char suivi d’un entier. D’après vous combien de bytes occupe cette structure en mémoire ? Vérifiez ce que vous pensiez en utilisant sizeof. (bonus: expliquez vos résultats.)

    struct foo_t {
            char a;
            int b;
    };
    
  2. Considérez le programme suivant.

    #include <stdlib.h>
    #include <stdio.h>
    #include <stdint.h>
    
    int main() {
    	char strtab[36] = "Coucou!! Je suis un grand string\n";
    	char *str = strtab;
    	int i;
    	for (i = 0; i < 8; i++) {
    		char c = str[i];
    		printf("Char %d, located at %p, is %c\n", i, &str[i], c);
    	}
    	uint32_t *str2 = (uint32_t *) str;
    	for (i = 0; i < 8; i++) {
    		uint32_t ui = str2[i];
    		printf("UInt %d, located at %p, is %u\n", i, &str2[i], ui);
    	}
    	str2[0] = 1801675080;
    	str2[1] = 555836517;
    	for (i = 0; i < 8; i++) {
    		char c = str[i];
    		printf("Char %d, located at %p, is %c\n", i, &str[i], c);
    	}
    	return 0;
    }
    
    • Sans executer le programme, essayez de comprendre son fonctionnement. En particulier, quelles seront les adresses affichées à chaque tour de boucle?
    • Compilez le programme et exécutez le. Expliquez sa sortie et comparez avec vos attentes.
    • (Bonus) Expliquez les valeurs affichées lors de l’exécution de la dernière boucle.