Dans ce cas, vous n'avez pas wan pas pour éviter d'utiliser goto
.
En général, l'utilisation de l' goto
devrait être évitée, il existe cependant des exceptions à cette règle, et votre cas est un bon exemple de l'un d'eux.
Nous allons étudier les solutions de rechange:
for (i = 0; i < N; ++i) {
for (j = 0; j < N; j++) {
for (k = 0; k < N; ++k) {
...
if (condition)
break;
...
}
if (condition)
break;
}
if (condition)
break;
}
Ou:
int flag = 0
for (i = 0; (i < N) && !flag; ++i) {
for (j = 0; (j < N) && !flag; j++) {
for (k = 0; (k < N) && !flag; ++k) {
...
if (condition) {
flag = 1
break;
...
}
}
}
Aucune de ces aussi concis ou aussi lisible que l' goto
version.
À l'aide d'un goto
est considéré comme acceptable dans le cas où vous êtes seulement à sauter en avant (pas en arrière) et cela rend votre code plus lisible et compréhensible.
En revanche, si vous utilisez goto
de sauter dans les deux directions, ou de sauter dans un champ d'application qui pourrait contourner l'initialisation d'une variable, qui serait mauvais.
Voici un mauvais exemple de goto
:
int x;
scanf("%d", &x);
if (x==4) goto bad_jump;
{
int y=9;
// jumping here skips the initialization of y
bad_jump:
printf("y=%d\n", y);
}
Un compilateur C++ lèvera une erreur ici parce que l' goto
saute par-dessus l'initialisation de y
. Les compilateurs C cependant la compilation, et le code ci-dessus va invoquer un comportement indéfini lorsque vous tentez d'imprimer y
qui sera initialisée si l' goto
se produit.
Un autre exemple de l'utilisation appropriée de l' goto
est dans la gestion des erreurs:
void f()
{
char *p1 = malloc(10);
if (!p1) {
goto end1;
}
char *p2 = malloc(10);
if (!p2) {
goto end2;
}
char *p3 = malloc(10);
if (!p3) {
goto end3;
}
// do something with p1, p2, and p3
end3:
free(p3);
end2:
free(p2);
end1:
free(p1);
}
Elle effectue tous les de la de nettoyage à la fin de la fonction. Comparez cela à l'alternative:
void f()
{
char *p1 = malloc(10);
if (!p1) {
return;
}
char *p2 = malloc(10);
if (!p2) {
free(p1);
return;
}
char *p3 = malloc(10);
if (!p3) {
free(p2);
free(p1);
return;
}
// do something with p1, p2, and p3
free(p3);
free(p2);
free(p1);
}
Lorsque le nettoyage est effectué en plusieurs endroits. Si vous ajoutez plus de ressources que nécessaire de les nettoyer, vous devez n'oubliez pas d'ajouter le nettoyage dans tous ces endroits, plus le nettoyage de toutes les ressources qui ont été obtenus précédemment.
L'exemple ci-dessus est plus pertinent pour C qu'en C++, car dans le dernier cas, vous pouvez utiliser les classes avec une bonne destructeurs et des pointeurs intelligents pour éviter un nettoyage manuel.