Cours de C les tableaux, fonctions et passages d’adresses

Les fonctions

● une fonction a un prototype:
– un nom
– des paramètres
– un type de retour
● exemple de définition:
float average(int t[]) {
float sum=0;
int i;
for (i=0;i<N;i++) {
} sum=sum+t[i];
return sum/N;
}
paumier@univ-mlv.fr 10
void
● type spécial:
– en valeur de retour: pas de valeur de retour
void print_sum(int a,int b) {
/* … */
}
– en paramètre: pas de paramètres (facultatif)
char get_upper_char(void) { char get_upper_char() {
/* … */ /* … */
} }

Définition vs déclaration

● définition = code de la fonction
● déclaration = juste son prototype avec ;
● dans les .h
● dans un .c pour une void get_hen(void);
void get_egg(void) {
fonction qu’on ne veut /* … */
get_hen();
pas exporter /* … */
}
void get_hen(void) {
/* … */
get_egg();
/* … */
}
return
● quitte la fonction
● renvoie une valeur si retour ≠ void
● inutile seulement en fin de fonction void:
void print_sum(float a,float b) { printf(« %f+%f=%f\n »,a,b,a+b);
}
int print_sum2(float a,float b) { printf(« %f+%f=%f\n »,a,b,a+b);
}
$>gcc -Wall -ansi function.c function.c: In function `print_sum2′:
function.c:25: warning: control reaches end of non-void function

Valeurs de retour

● on peut ignorer une valeur de retour:
– printf, scanf
● on ne peut pas utiliser une fonction void dans une expression:
void print_sum(float a,float b) {
printf(« %f+%f=%f\n »,a,b,a+b);
}
int main(int argc,char* argv[]) {
float s=print_sum(3.5,1.1);
printf(« sum=%f\n »,s);
$>gcc -Wall -ansi function.c return 0;
}
function.c: In function `main’:
function.c:8: void value not ignored as it ought to be

Le cas de main

● fonction particulière:
– return quitte le programme et
– renvoie le code de retour du programme
● par convention: 0=OK ≠0=erreur
● si main est appelée explicitement par une fonction, return marche normalement

Paramètres de main

● int main(int argc,char* argv[]) {…}
Nombre de paramètres, y compris l’exécutable
int main(int argc,char* argv[]) { int i;
for (i=0;i<argc;i++) {
printf(« arg #%d=%s\n »,i,argv[i]);
}
return 0;
}
Tableau de chaînes contenant les paramètres
$>./a.out AA e « 10 2 » arg #0=./a.out
arg #1=AA arg #2=e arg #3=10 2

Écrire une fonction

● réfléchir à l’utilité de la fonction
● 1 fonction = 1 seule tâche
● on ne mélange pas calcul et affichage!
int minimum(int a,int b) {
int min=(a<b)?a:b;
printf(« minimum=%d\n »,min);
return min;
}
int minimum(int a,int b) { return (a<b)?a:b;
}
int main(int argc,char* argv[]) { int min=minimum(4,5); printf(« min=%d\n »,min); return 0;
}

Les paramètres

● ne pas mettre trop de paramètres!
int get_choice(char a,char c1,
char c2,char c3,
char c4,char c5) {
if (a==c1 || a==c2 || a==c3 ||
a==c4 || a==c5) return a;
return -1;
}
int get_choice2(char a,char c[]) {
int i;
for (i=0;i<N;i++) {
if (a==c[i]) return a;
}
return -1;
}

Définir le prototype

● de quoi la fonction a-t-elle besoin ?
● retourne-t-elle quelque chose ?
● y a-t-il des cas d’erreurs ?
● si oui, 3 solutions:
– mettre un commentaire
– renvoyer un code d’erreur
– afficher un message et quitter le programme

Le commentaire

● utile quand la fonction n’est pas censée être appelée dans certains cas:
/**
* Copies the array ‘src’ into the ‘dst’ one.
* ‘dst’ is supposed to be large enough.
*/
void copy(int src[],int dst[]);
/**
* Returns 1 if ‘w’ is an English word; * 0 otherwise. ‘w’ is not supposed to be * NULL;
*/
int is_english_word(char* w);

Le code d’erreur

● pas de problème si la fonction ne devait rien renvoyer:
int init(int t[],int size) {
if (size<=0) return 0;
int i;
for (i=0;i<size;i++) t[i]=0;
return 1;
}
● sinon, attention à la valeur choisie
– on doit toujours pouvoir distinguer un cas d’erreur d’un cas normal
● attention à la valeur:
int minimum(int t[],int size) { /**
if (size<=0) return -1; * Returns the length of the given
int min=t[0]; * string or -1 if NULL.
int i; */
for (i=1;i<size;i++) { int length(char* s) {
} if (min<t[i]) min=t[i]; if (s==NULL) return -1;
int i;
return min; for (i=0;s[i]!=’\0′;i++);
} return i;
}
-1 : on ne peut pas savoir si on a une erreur ou si le minimum est -1
● si toutes les valeurs possibles sont prises, il faut utiliser un passage par adresse pour le résultat ou pour le code d’erreur
int quotient(int a,int b,int *res) {
if (b==0) return 0;
*res=a/b;
return 1;
}

L’interruption du programme

● à n’utiliser que dans des cas très graves
– plus de mémoire
– erreurs d’entrées-sorties
– mauvais paramètres passés au programme
● message sur stderr + exit(≠0);
List* new_List(int n,List* next) { List* l=(List*)malloc(sizeof(List)); if (l==NULL) {
fprintf(stderr, »Not enough memory !\n »); exit(1);
} /* On met un message parlant */
l->n=n; /* et non pas quelque chose */ l->next=next; /* d’inutile comme « Error » */ return l;
}

Tests d’erreur

● quitter dès que possible en évitant les else inutiles
⇨ améliore la lisibilité
int get_value(char* s) { int get_value(char* s) {
int ret; if (s==NULL) return -1;
if (s==NULL) { if (!isdigit(s[0])) return -1;
ret=-1; int ret=s[0]-‘0’;
} else if (!isdigit(s[0])) { int i=1;
ret=-1; while (isdigit(s[i])) {
} else { ret=ret*10+s[i]-‘0’;
ret=s[0]-‘0’; } i++;
int i=1;
while (isdigit(s[i])) { return ret;
ret=ret*10+s[i]-‘0’; }
i++;
} }
return ret;
}

Esthétique des fonctions

● soigner la présentation:
– commentaires
– noms explicites
– indentation
● regrouper les fonctions de même thème dans des .c

Passage d’adresse

void add_3(int a) {
a=a+3;
}
int main(int argc,char* argv[]) { int foo=14;
add_3(foo);
printf(« foo=%d\n »,foo);
return 0;
}
$>./a.out
foo=14

Cours gratuitTélécharger le cours complet

Télécharger aussi :

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *