Cours C 4 Types structures et allocation dynamique
…
Les structures
struct nom {
type_champ1 nom_champ1;
type_champ2 nom_champ2;
...
};
Les structures
struct nom_type nom_var;
struct complex { double real; double imaginary;
};
int main(int argc,char* argv[]) {
struct complex c;
c.real=1.2;
c.imaginary=6.3;
printf("%f+%f*i\n",c.real,c.imaginary);
return 0;
}
Choix des champs
struct list { int value;
struct list next;
};
$>gcc -Wall -ansi struct.c
struct.c:7: champ « next » a un type incomplet
Structures récursives
connue:
struct list { int value;
struct list* next;
};
Imbrication de structures
pas d'ambiguïté car le type ne s'appelle pas id mais struct id
Imbrication de structures
struct state {
struct transition* t; char final;
};
struct transition { char letter;
struct state* dest;
struct transition* next;
};
Contraintes sur les structures
déclarations: struct foo { int a; char b; float c;
};
int main(int argc,char* argv[]) { struct foo f;
printf("%p < %p < %p\n", &(f.a),&(f.b),&(f.c)); return 0;
}
$>./a.out
0022FF58 < 0022FF5C < 0022FF60
Alignement
– des adresses multiples de la taille des données
– des adresses multiples de la taille des pointeurs
–
000
Alignement
struct ta { int a; char b; char c; char d;
};
struct to { char a; int b; char c; char d;
}; sizeof(to)=12 sizeof(ta)=8
– noms des champs
– sizeof
Alignement
struct ta { int a; char b; char c; char d;
};
struct to { char a; int b; char c; char d;
}; sizeof(to)=12 sizeof(ta)=8
@+0
@+4
@+5
@+6
Initialisation
struct to t={'a',145,'y','u'};
int main(int argc,char* argv[]) {
struct to t;
t={'a',145,'y','u'};
printf("%c %d %c %c\n",t.a,t.b,t.c,t.d);
return 0;
}
$>gcc -Wall -ansi struct.c
struct.c: Dans la fonction « main »:
struct.c:33: erreur d'analyse syntaxique avant le jeton « { »
Opérations
int main(int argc,char* argv[]) {
struct to z={'a',145,'y','u'};
struct to t=z;
printf("%c %d %c %c\n",t.a,t.b,t.c,t.d);
return 0;
}
b à écrire soi-même
Structures en paramètres
– non modifiables
– peuvent occuper beaucoup de place sur la
pile (tableaux)
– temps de recopie
Structures en paramètres
struct array { int t[100000]; int size;
};
void f(struct array* a) { int i;
for (i=0;i<(*a).size;i++) { printf("%d\n",(*a).t[i]);
}
}
attention au parenthésage: (*a).t[i] ≠ *a.t[i]
Structures en paramètres
– gain de temps
– gain d'espace sur la pile
– on peut modifier la structure
void f(struct array* a) { int i;
for (i=0;i<(*a).size;i++) { printf("%d\n",(*a).t[i]); void f(struct array* a) { int i;
for (i=0;isize;i++) { printf("%d\n",a->t[i]);
} }
} }
Retourner une structure
Les unions
typeN nomN;
};
union toto { char a; float b;
};
void foo(union toto* t) { t->a='z';
}
Les unions
union toto { char a;
char s[16];
}; $>./a.out
$oucou
int main(int argc,char* argv[]) {
union toto t;
strcpy(t.s,"coucou");
t.a='$';
printf("%s\n",t.s);
return 0;
}
Les unions
struct student {
char name[256];
union {
char login[16];
int id;
};
};
Unions complexes
union color {
/* RGB representation */
struct {
unsigned char red,blue,green;
};
/* 2 colors: 0=black 1=white */
char BandW;
};
on peut utiliser soit red, blue et green, soit BandW
Quel(s) champ(s) utiliser ?
struct color {
/* 0=RGB 1=black & white */
char type;
union {
/* RGB representation */
struct {
unsigned char red,blue,green;
};
/* 2 colors: 0=black 1=white */
char BandW;
};
};
Les énumérations
elle pourra prendre les valeurs idi
enum gender {male,female};
void init(enum gender *g,char c) { *g=(c=='m')?male:female; }
Les énumérations
Les énumérations
valeur
enum color {
blue=45, BLUE=blue, Blue=blue,
green/* =46 */, GREEN=green, Green=green
};
int main(int argc,char* argv[]) { printf("%d %d %d %d %d %d\n",
blue,BLUE,Blue,green,GREEN,Green); return 0;
}
$>./a.out
45 45 45 46 46 46
Contrôles des valeurs
enum gender {male='m',female='f'}; enum color {blue,red,green};
int main(int argc,char* argv[]) {
enum gender g='z';
enum color c=g;
/* ... */
return 0;
}
Contrôles des valeurs
$>gcc -Wall -ansi enum.c
enum.c: Dans la fonction « foo »:
enum.c:24: AVERTISSEMENT: valeur d'énumération « green » n'est pas traitée dans le switch
enum.c:24: AVERTISSEMENT: valeur d'énumération « yellow » n'est pas traitée dans le switch
Déclaration de constantes
enum {Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday};
char* names[]={"Monday","Tuesday","Wednesday","Thursday","Friday", "Saturday","Sunday"};
void print_day(int day) {
printf("gis\n",names[day]);
}
int main(int argc,char* argv[]) { print_day(Saturday);
return 0;
}
Combinaison union/enum
enum cell_type {EMPTY,BONUS,MALUS,PLAYER,MONSTER};
struct cell {
enum cell type type;
_
union {
Bonus bonus; Malus malus; Player player; Monster monster;
};
};
typedef
typedef signed char sbyte; typedef unsigned char ubyte;
typedef struct cell Cell; typedef enum color Color;
typedef
interchangeables
struct array { int t[N]; int size; };
typedef struct array Array;
int main(int argc,char* argv[]) {
Array a;
struct array b=a;
/* ... */
return 0;
}
typedef
définition:
enum cell_type {EMPTY,BONUS,MALUS,
PLAYER,MONSTER};
typedef enum cell_type CellType;
struct cell {
CellType type; union {
Bonus bonus; Malus malus; Player player; Monster monster;
};
};
typedef struct cell Cell;
typedef enum {EMPTY,BONUS,MALUS, PLAYER,MONSTER} CellType;
typedef struct { CellType type; union {
Bonus bonus; Malus malus; Player player; Monster monster;
};
} Cell;
Les pointeurs
Arithmétique des pointeurs
*t a t[0]
t+3 = t+3*sizeof(type des éléments)
*(t+i) <* t[i]
Arithmétique des pointeurs
x+1 en faisant t++
int copy(char* src,char* dst) {
if (src==NULL || dst==NULL) {
return 0;
}
while ((*dst=*src)!='\0') {
src++;
dst++;
}
return 1;
}
Transtypage
void*
void*
truc* t=(truc*)b;
Exemple
=> voir un int comme un tableau de 4 octets
Exemple 2
void show_bytes(double d) {
unsigned char* t=(unsigned char*)(&d);
int i;
for (i=0;i<sizeof(double);i++) {
printf("%X ",t[i]);
}
printf("\n");
}
$>./a.out 375.57898541
FA 8C 34 86 43 79 77 40
Allocation dynamique
(dans stdlib.h)
par la taille
type (facultatif, mais plus lisible)
Cell* c=(Cell*)malloc(sizeof(Cell)); if (c==HULL) {
/* ... */
}
Allocation de tableaux
d'éléments:
int* create_array(int size) {
int* array;
array=(int*)malloc(size*sizeof(int));
if (array==HULL) {
fprintf(stderr,"Not enough memory!\n");
exit(1);
}
return array;
}
int* create_array(int size) {
int* array;
array=(int*)calloc(size,sizeof(int));
if (array==HULL) {
fprintf(stderr,"Not enough memory!\n");
exit(1);
}
return array;
}
– anciennes données conservées
– ou tronquées si la taille a diminuée
Exemple de réallocation
struct array { int* data; int capacity; int current;
};
/* Adds the given value to the given array,
* enlarging it if needed */
void add_int(struct array* a,int value) {
if (a->current==a->capacity) {
a->capacity=a->capacity*2;
a->data=(int*)realloc(a->data,a->capacity*sizeof(int));
if (a->data==HULL) {
fprintf(stderr,"Not enough memory!\n");
exit(1);
}
}
a->data[a->current]=value;
(a->current)++;
}
Libération de la mémoire
Libération de la mémoire
Libération de la mémoire
Allocation de structures
Utilisation de malloc
int main(int argc,char* argv[]) {
Complex a={2,3};
Complex b={7,4};
Complex* c=mult_Complex(&a,&b);
/* ... */
free_Complex(c);
return 0;
}
Tableaux à 2 dimensions
– allouer le tableau principal
– allouer chacun des sous-tableaux
int** init_array(int X,int Y) {
int** t=(int**)malloc(X*sizeof(int*));
if (t==HULL) { /* ... */ }
int i;
for (i=0;i<X;i++) {
t[i]=(int*)malloc(Y*sizeof(int));
if (t[i]==HULL) { /* ... */ }
}
return t;
}
Tableaux à 2 dimensions
≠ tableaux statiques
int** t de 2x3 contenant la valeur 7
43B2 44F8 4532
4532 44F8 ... 7 7 7 ... 7 7 7
Tableaux à 2 dimensions
– d'abord les sous-tableaux
– puis le tableau principal
Listes chaînées
1) avoir un type récursif
2) avoir un nom de type sans struct
Listes chaînées
3 7 15
FB07 FB42 FBAE
Complexités