next up previous
Up: No Title Previous: No Title

Subsections

Types en C

Déclarations

Une déclaration associe à un identificateur un objet C, comme les variables, les fonctions, les types, les marqueurs de type, les composants de structure et d'union, les constantes de type énumeration, les étiquettes d'instructions et les macros de préprocesseur.

1)
Indiquer les différents types d'identificateur des déclarations suivantes :
struct smonome
 {
    int coeff;
    int *exposants;
  };
typedef struct smonome monome;

struct spolynome
{
    struct smonome    mon_dom;
    struct spolynome  *queue;
  };
typedef struct spolynome *polynome;

La portée des identificateurs, limitée au fichier, sont de deux natures principales :

Avec les deux exceptions suivantes : les définitions de macros qui portent de la ligne #define jusqu'à la fin du fichier, et les déclations externes (extern) qui exportent la déclaration au delà du fichier.

2)
Indiquer les portées des identificateurs du programme suivant :
char *french_date(time_t clock)
{
    static char *jour[7] = {
        "Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"
    };
    static char *mois[12] = {
        "janvier", "fevrier", "mars", "avril", "mai", "juin",
        "juillet", "aout", "septembre", "octobre", "novembre", "decembre"
    };
    struct tm *pt;
    static char date[120];

    pt = gmtime(&clock);
    sprintf(date, "%s %d ",jour[pt->tm_wday],pt->tm_mday);
    strcat(date, mois[pt->tm_mon]);
    sprintf(date + strlen(date), " %d %02d:%02d:%02d",
        1900+pt->tm_year,pt->tm_hour,pt->tm_min,pt->tm_sec);
    return date;
}

Un même identificateur peut être associé à plus d'un type d'objet C.

3)
Indiquer les types d'objet de sgttyb et tchars dans le programme suivant :
...

struct  sgttyb {
    char    sg_ispeed;      
    char    sg_ospeed;      
    char    sg_erase;       
    char    sg_kill;        
    short   sg_flags;       
};
struct tchars {
    char    t_intrc;    
    char    t_quitc;    
    char    t_startc;   
    char    t_stopc;    
    char    t_eofc;     
    char    t_brkc;     
};


struct sgttyb sgttyb;           
struct sgttyb rsgttyb;          

struct tchars tchars;           
struct ltchars ltchars;

Lors d'une déclaration de variables ou de types, il est possible de spécifier la classe de mémorisation de l'objet C. Ces classes de mémorisations dépendent du contexte de la déclaration. On trouve les classes suivantes :

4)
Indiquer les classes de mémorisation du programme suivant :
out(s,l,f)
register char *s,*f;
register int l;
{
    static char *CurFont = "";
    int neg = 1;

...
}
5)
Soient les fonctions eurodate1 et eurodate2 suivantes :
char *convtoeurodate1(shortdate)
     char *shortdate;
{
        return shortdate;
}

char *convtoeurodate2(shortdate)
     char *shortdate;
{
        static char tmpdate[SHORTDATELEN];

        strcpy(tmpdate, shortdate);
        tmpdate[0] = shortdate[3];
        tmpdate[1] = shortdate[4];
        tmpdate[3] = shortdate[0];
        tmpdate[4] = shortdate[1];

        return tmpdate;
}
Qu'affichent les appels suivants de eurodate1 :

   printf("du %s au ", convtoeurodate1(firstdate));
   printf("%s",convtoeurodate1(lastdate));
et
   printf("du %s au %s", convtoeurodate1(firstdate),convtoeurodate1(lastdate));
avec firsdate et lastdate des chaînes de format "MM/DD/YY".
6)
Même question pour eurodate2.

Passage de paramètres

C ne permet que le passage de paramètres par valeur. Les valeurs des paramètres d'appel sont copiées dans une zone mémoire locale de la fonction appelée. Il est possible de faire une affectation sur le paramètre formel, mais seule la copie en sera affectée.

1)
Que fait le programme suivant :
void echange (x,y)
  int x,y;
{
   int temp;
   temp = x; x = y; y = temp;
}
C autorise à passer des adresses comme paramètres, en tant que valeurs, ce qui permet d'effectuer des modifications physiques des variables d'appel.

2)
Que fait le programme suivant :
void echange (x, y)
  int *x, *y;
{
  int temp;
  temp = *x; *x = *y; *y = temp;
}

On utilisera dans les questions suivantes les routines d'allocation et de libération mémoire suivantes :

     char *malloc(size)
     unsigned size;

     int free(ptr)
     char *ptr;
malloc alloue une zone mémoire de taille size et free libère une zone localisée par le pointeur passé en argument.

3)
Ecrire un type liste correspondant à des listes d'entiers.
4)
Ecrire une fonction d'affichage d'une liste d'entiers.

5)
Ecrire une fonction (récursive ou itérative) qui construit, à partir d'une liste donnée, cette liste sans les éléments supérieurs ou égaux à un certain entier.

6)
Ecrire une fonction qui élimine d'une liste les éléments supérieurs ou égaux à un certain entier sans créer de nouvelle liste.

Solution de l'exercice

Solution
: elim.c
}
\newcommand{\addverb}{

Préprocesseur

Le préprocesseur /lib/cpp bien qu'indépendant du langage C (il peut être utilisé pour d'autres langages comme Caml ou LATEX) est très largement utilisé pour l'écriture de programme C. Il permet l'inclusion de textes ( \#include nomdefichier), la définition de symboles ( DEFINE nom), associés ou non à une valeur ( \#define nom valeur), la définition de macros (symboles avec arguments : \#define nom (arg1,arg2) corps) et les directives conditionnelles de compilation ( \#ifdef symbole ... \#else ... \#endif .

1.
Ecrire une fonction eurodate intégrant le code des fonctions eurodate1 et eurodate2 discriminés par une directive de compilation #ifdef EURODATE.
2.
Qu'affiche le programme suivant :

}
\newcommand{\addverb}{

solution de l'exercice

exo 1

Solution
: elim.c
}
\newcommand{\addverb}{

exo 2

maya.cicrp.jussieu.fr{chaillou}: ./a.out
PP=3 p0=1 p1=2 p2=4 p3=0
PP=3 p0=1 p1=2 p2=4 p3=4    <-------difference

ibm1:/home/p6ipens/chaillou $ ./a.out
PP=3 p0=1 p1=2 p2=4 p3=0
PP=3 p0=1 p1=2 p2=4 p3=0    <-------venant de l'ordre d'evaluation 
                                    des parametres de =.

Pour bien différencier les macros des fonctions, on utilise des majuscules pour les macros. Ici on aurait EMPILE et DEPILE comme symboles de macros.

Conversions implicites et conversions explicites de types

Une expression C peut changer de type par une opération de conversion explicite avec quelques restrictions. Des conversions implicites peuvent être effectuées sur les opérandes d'opérateurs arithmétiques et d'affectation, sur les paramètres d'appel d'une fonction, sur la valeur de retour d'une fonction.

Les types qui peuvent être convertis en entiers sont les types arithmétiques et les pointeurs. Seuls les types arithmétiques peuvent être convertis en nombres à virgule flottante. Les pointeurs et les entiers sont convertibles en types pointeur. Les tableaux et les fonctions peuvent être convertis en type pointeur. Toute valeur peut être convertie en type void.

1)
Ecrire une fonction qui convertit une chaîne de chiffres en son équivalent entier.
2)
Ecrire une fonction lower qui convertit une majuscule en minuscule.
3)
Les conversions pointeurs vers flottants (float) ne sont pas autorisées en C. Néanmoins Il est possible de manipuler le même paquet de bits de manière différente selon l'usage.
typedef union machin {int x; float y; double *z;} *alpha;

Ecrire trois fonctions prenant un $\alpha$ en entrée et calculant le successeur de cet $\alpha$.

4)
Ecrire un type nombre avec un champ $\alpha$ et un champ de marque (type énuméré) indiquant quel champ de l'union on utilise. Ecrire une fonction successeur pour ce type nombre.

Application sur le calcul des polynômes

Le but de cet exercice est d'écrire les fonctions de base de manipulation de polynômes.

1)
Ecrire un type polynôme à coefficients entiers.
2)
Ecrire une fonction qui calcule la valeur d'un polynôme P pour un x donné : P(x).
3)
Ecrire une fonction qui calcule les racines d'un polynôme de degré 2. De quel type sont les racines?

Pointeurs sur fonctions

La déclaration d'une fonction foo en C crée une constante de même nom dont la valeur est un pointeur sur le code de la déclaration.

int add (int x, int y) {return (x+y);}
int sub (int x, int y) {return (x-y);}
Cette valeur est manipulable dans le langage.

 int (*fn) (int,int);
définit une variable fn de type pointeur sur une fonction dont le résultat est un int à deux arguments entiers.

L'exemple suivant utilise le pointeur de fonction fn prenant la valeur add puis sub.

fn = add;
printf(" fn(3,4)=%d\n",fn(3,4));
fn = sub;
printf(" fn(3,4)=%d\n",fn(3,4));

1.
Ecrire une fonction map (à la manière de caml) qui prend un pointeur de fonction f des entiers vers les entiers, une liste d'entiers l et retourne une nouvelle liste d'entiers de l'application de f à tous les éléments de l.

2.
Ecrire une fonction it_liste_entier qui prend un pointeur de fonctionf, une graine (entier) r, une liste d'entiers l telle que :

\begin{displaymath}
it\_liste\_entier \; f \; r \; l \; =
\left\{ \begin{array}
...
 ...\_liste\_entier \; f \; (
f \; r \; t)\; q\\ \end{array}\right.\end{displaymath}

3.
Utiliser cette fonction pour faire la somme des éléments d'une liste.
4.
Modifier la fonction it_liste_entier (et changer son nom) pour filtrer les éléments pairs d'une liste.

solution de l'exercice

}
\newcommand{\addverb}{


next up previous
Up: No Title Previous: No Title
Emmanuel CHAILLOUX
10/15/1997