Introduction, source, objet, compilation

TP1 - Correction

Posted by Benoît "badetitou" Verhaeghe on October 3, 2019

TP1 - Introduction, source, objet, compilation

Exercice 1 (TD)

Quelle différence existe-t-il entre un interpréteur et un compilateur ? Citez deux exemples pour chacun d’entre eux.

Solution 1

Un interpréteur (ou interprète) lit les instructions du fichier source ligne par ligne, les analyse puis les exécute tandis qu’un compilateur traduit le fichier source en fichier objet. Interprète (bash, java) ; compilateur (gcc, javac).

Exercice 2 (TD)

Quelles similitudes et quelles différences existe-t-il entre un fichier d’en-tête (toto.h) et une bibliothèque ? Quand les utilise-t-on dans le processus de compilation ? Citez deux exemples pour chacun d’entre eux.

Solution 2

Les fichiers d’en-têtes sont nécessaires afin de déclarer les fonctions de bibliothèques utilisés par les programmes.

  1. Un fichier d’en-tête est un fichier source contenant des déclarations et/ou définitions de fonctions, de variables, de définitions de type. Il doit être inclus (#include) par le préprocesseur avant compilation.
  2. Une bibliothèque est un fichier binaire archivant différents fichiers objets (.o) compilés. Une bibliothèque est utilisée par l’éditeur de liens à la fin du processus de compilation pour construire la fichier binaire exécutable.
  3. exemples : stdio.h est le fichier d’en-tête de la librairie standard (libc.a) concernant les entrées-sorties ; math.h est le fichier d’en-tête correspondant à la bibliothèque libm.a.

Exercice 3 (TD)

Quelle différence entre l’inclusion d’un fichier d’entête standard tel que stdio.h, stdlib.h, ctype.h et un fichier d’entête personnel monprog.h ?

Solution 3

Les fichiers d’entêtes standards sont inclus entre chevrons tandis que les fichiers d’entête personnels sont inclus entre guillemets. Le préprocesseur va chercher ces fichiers dans des répertoires différents :

Exercice 4 (TD)

Comment les paramètres de la ligne de commande sont-ils passés à un programme C ? Comment l’environnement du processus (variables d’environnement telles que PATH, HOME, …) est-il atteignable par un programme C ?

Solution 4

Le prototype de la fonction principale (main) d’un programme C est le suivant : int main(int argc, char *argv[], char *env[]) { body... }

argv[0] monprog
argv[1] toto

Exercice 5 (TD/TP)

On souhaite écrire un programme affichant le nombre de paramètres passés à la ligne de commande, ces paramètres, ainsi que les variables d’environnement.

  1. Ecrire l’algorithme de ce programme.
  2. Ecrire le programme C correspondant.

Solution 5 - Algorithme

afficher argc
    pour (i=0; i<argc; i++)
        afficher argv[i]
    fpour
    i=0
    tq (env[i] != NULL)
        afficher env[i]
        i=i+1
    ftq

Solution 5 - programme argenv.c

#include <stdio.h>


int main(int argc, char *argv[], char *env[]) {
    printf("Nombre d’arguments : %i\n\nListe des arguments :\n",argc);
        for (int i=0;i<argc;i++){
            printf("%s\n",argv[i]);
        }
    printf("\nListe des variables d’environnement :\n");
    int i=0;
    while(env[i]!=NULL){
        printf("%s\n",env[i]);
        i++;
    }
}

Exercice 6 (TP)

A l’aide du programme précédent, testez les possibilités du compilateur gcc en produisant :

Observez ces différents fichiers.

Solution 6

Exercice 7 (TD/TP)

On souhaite réaliser le calcul de la moyenne d’une suite de 5 nombres flottants saisis au clavier.

  1. Ecrire l’algorithme de ce programme.
  2. Ecrire le programme C correspondant.

Solution 7 - Algorithme

afficher "saisir 5 nombres"
m=0
pour (i=0 à 4)
    m=m+lireFlottant()
fpour
afficher m/5

Solution 7 - programme moyenne.c

#include <stdio.h>


int main(int argc, char *argv[], char *env[]) {
    printf("Saisir 5 nombres S.V.P. :\n");
    float f;
    float m=0;
    for (int i=0;i<5;i++){
        printf("%d : ",i+1);
        scanf("%f",&f);
        m+=f;
    }
    printf("\nMoyenne des 5 nombres : %f\n",m/5);
}

Exercice 8 (TD/TP)

En utilisant la fonction atoi qui convertit une chaîne en entier, réaliser le calcul de la moyenne de la suite des paramètres passés à la ligne de commande : moy 5 8 12 3.

  1. Ecrire l’algorithme de ce programme.
  2. Ecrire le programme C correspondant.

Solution 8 - Algorithme

m=0
Pour i=1 à argc-1
    m=m+atoi(argv[i])
fpour
afficher m/(argc-1)

Solution 8 - programme moy.c

#include <stdio.h>

#include <stdlib.h>


int main(int argc, char *argv[], char *env[]) {
    float m=0;
    for (int i=1;i<argc-1;i++){
        m+=atoi(argv[i]);
    }
    printf("\nMoyenne des %d nombres : %.2f\n",argc-1,m/(argc-1));
}

Exercice 9 (TD/TP strsplit)

Dans certains fichiers structurés, les articles sont représentés sur une ligne dont les champs sont séparés par un caractère séparateur (fichiers .csv). On souhaite écrire une fonction qui découpe une chaîne de caractères correspondant à une ligne csv en un tableau de chaînes dynamiques. Par exemple, l’appel strsplit("/bin:/usr/bin:/usr/local/bin",’:’) doit générer le tableau suivant :

0 --> /bin
1 --> /usr/bin
2 --> /usr/local/bin
3 NULL
  1. Ecrire l’algorithme de ce programme.
  2. Ecrire le programme C correspondant.

Solution 9 - Algorithme

char **strsplit(const char *s, const char sep)
    nbsep=0
    pour i=0;s[i]!=’\0’;i++
        if s[i]==sep
            nbsep++
        res=malloc(nbsep+2)
        n=0
        i=0
    Répéter
        int l=0 // lng de la sous-chaîne
        TantQue s[i]!=’\0’ et s[i]!=sep
            l++
            i++
        res[n]=malloc(l+1)
        res[n][l]=’\0’
        strncpy(res[n],s+i-l,l)
        n++
        APRESSEP=FAUX;
        Si s[i]==sep
            i++
            APRESSEP=VRAI
    Tq s[i]!=’\0’
    Si (APRESSEP){ /* sep suivi de fin de chaîne */
        res[n]=malloc(1);
        res[n][0]=’\0’;
        n++;
    res[n]=NULL
    return res

Solution 9 - strsplit.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>


char **strsplit(const char *s, const char sep){
    if(s==NULL)
        return NULL;
    int nbsep=0; /* nb de séparateurs */
    for(int i=0;s[i]!='\0';i++){
        if (s[i]==sep)
            nbsep++;
    }
    //printf("nbsep = %d\n",nbsep);
    char **res=malloc((nbsep+2)*sizeof(char*)); /* allocation du résultat */
    int n=0;
    int i=0;
    int APRESSEP=0; /* faux */
    do{
        int l=0; // lng de la sous-chaîne
        while(s[i]!='\0' && s[i]!=sep){
            l++;
            i++;
        }
        res[n]=malloc(l+1);
        strncpy(res[n], s+i-l, l);
        res[n][l]='\0';
        n++;
        APRESSEP=0;
        if(s[i]==sep){
            i++;
            APRESSEP=1;
        }
    }while(s[i]!='\0');
    if(APRESSEP){ /* sep suivi de fin de chaîne */
        //printf("n=%d ; i=%d\n",n,i);
        res[n]=malloc(1);
        res[n][0]='\0';
        n++;
    }
    res[n]=NULL;
    return res;
}


int main(int argc, char *argv[], char *env[]) {
    if(argc!=3){
        printf("Syntaxe incorrecte : %s abc:12:yyyy :\n",argv[0]);
        return 1;
    }
    char **r=strsplit(argv[1],argv[2][0]);
    while(*r != NULL){
        printf("%s\n",*r);
        r++;
    }
    return 0;
}