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.
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 :
#define
jusqu'à la fin du fichier, et les déclations externes (extern
) qui exportent la déclaration au delà du fichier.
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.
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 :
&
).
out(s,l,f) register char *s,*f; register int l; { static char *CurFont = ""; int neg = 1; ... }
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".
eurodate2
.
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.
void echange (x,y) int x,y; { int temp; temp = x; x = y; y = temp; }
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.
liste
correspondant à des listes d'entiers.
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
.
eurodate
intégrant le code des fonctions eurodate1
et eurodate2
discriminés par une directive de compilation
#ifdef EURODATE
.
}
\newcommand{\addverb}{
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.
lower
qui convertit une majuscule
en minuscule.
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 en entrée et calculant le successeur de cet .
Le but de cet exercice est d'écrire les fonctions de base de manipulation de polynômes.
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));
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
.
it_liste_entier
qui prend un pointeur
de fonctionf
, une graine (entier) r
, une liste d'entiers
l
telle que :
it_liste_entier
(et changer son nom)
pour filtrer les éléments pairs d'une liste.