Saltar al contenido

Salir de un bucle desde dentro de una función llamada en ese bucle

Ten en cuenta que en las ciencias cualquier problema casi siempere suele tener más de una resoluciones, así que aquí mostraremos lo más óptimo y mejor.

Solución:

No se puede usar break; de esta manera, debe aparecer dentro del cuerpo del for círculo.

Hay varias formas de hacer esto, pero no se recomienda ninguna:

  • puede salir del programa con el exit() función. Dado que el bucle se ejecuta desde main() y no haces nada después de eso, es posible lograr lo que quieres de esta manera, pero como un caso especial.

  • Puede establecer una variable global en la función y probarla en el for bucle después de la llamada a la función. El uso de variables globales generalmente no es una práctica recomendada.

  • puedes usar setjmp() y longjmp(), pero es como intentar aplastar una mosca con un martillo, puede romper otras cosas y perder la mosca por completo. No recomendaría este enfoque. Además, requiere un jmpbuf que tendrás que pasar a la función o acceder como variable global.

Una alternativa aceptable es pasar la dirección de un status variable como argumento adicional: la función puede configurarla para indicar la necesidad de salir del bucle.

Pero, con mucho, el mejor enfoque en C es devolver un valor para probar la continuación, es el más legible.

Según sus explicaciones, no tiene el código fuente para foo() pero puede detectar algunas condiciones en una función que puede modificar llamada directa o indirectamente por foo(): longjmp() saltará desde su ubicación, en lo profundo de las entrañas de foo(), posiblemente muchos niveles por debajo de la pila de llamadas, hasta el setjmp() ubicación, omitiendo el código de salida de función regular para todas las llamadas intermediarias. Si eso es precisamente lo que debe hacer para evitar un accidente, setjmp() / longjmp() es una solución, pero puede causar otros problemas como pérdida de recursos, inicialización faltante, estado inconsistente y otras fuentes de comportamiento indefinido.

Tenga en cuenta que su for el bucle iterará 101 veces porque usas el <= operador. El idiomático for usos del bucle for (int i = 0; i < 100; i++) para iterar exactamente el número de veces que aparece como límite superior (excluido).

break, me gusta goto, solo puede saltar localmente dentro de la misma función, pero si es absolutamente necesario, puede usar setjmp y longjmp:

#include 
#include 

jmp_buf jump_target;

void foo(void)

    printf("Inside foo!n");
    longjmp(jump_target, 1);
    printf("Still inside foo!n");


int main(void) 
    if (setjmp(jump_target) == 0)
        foo();
    else
        printf("Jumped out!n");
    return 0;

La llamada a longjmp causará un salto de regreso a la setjmp llamar. El valor de retorno de setjmp muestra si regresa después de establecer el objetivo del salto, o si regresa de un salto.

Producción:

Inside foo!
Jumped out!

Los saltos no locales son seguros cuando se usan correctamente, pero hay varias cosas en las que pensar detenidamente:

  • Ya que longjmp salta "a través" de todas las activaciones de funciones entre el setjmp llamar y el longjmp call, si alguna de esas funciones espera poder realizar trabajo adicional después del lugar actual en ejecución, ese trabajo simplemente no se realizará.
  • Si la activación de la función que llamó setjmp ha terminado, el comportamiento no está definido. Cualquier cosa puede suceder.
  • Si setjmp aún no ha sido llamado, entonces jump_target no está configurado y el comportamiento no está definido.
  • Variables locales en la función que llamó setjmp puede, en determinadas condiciones, tener valores indefinidos.
  • Una palabra: hilos.
  • Otras cosas, como que los indicadores de estado de punto flotante pueden no conservarse y que existen restricciones sobre dónde puede colocar los setjmp llamar.

La mayoría de estos se siguen de forma natural si tiene una buena comprensión de lo que hace un salto no local en el nivel de las instrucciones de la máquina y los registros de la CPU, pero a menos que tenga eso, y Si he leído lo que el estándar C garantiza y no garantiza, le aconsejaría algo de precaución.

(Nota: la pregunta ha sido editada desde que escribí esto originalmente)

Debido a la forma en que se compila C, debe saber dónde ir cuando se llama a la función. Dado que puede llamarlo desde cualquier lugar, o incluso en algún lugar, un descanso no tiene sentido, no puede tener un break; declaración en su función y haga que funcione así.

Otras respuestas han sugerido soluciones terribles, como establecer una variable global, usar una #define o saltos largos (!) fuera de la función. Estas son soluciones extremadamente pobres. En su lugar, debe usar la solución que descartó erróneamente en su párrafo de apertura y devolver un valor de su función que indique el estado en el que desea activar una break en este caso y haga algo como esto:

#include 

bool checkAndDisplay(int n)

    printf("%dn", n);
    return (n == 14);


int main(void) 
    for (int i = 0; i <= 100; i++) 
        if (checkAndDisplay(i))
            break;
    
    return 0;

Tratar de encontrar formas oscuras de lograr cosas como esta en lugar de utilizar la forma correcta para lograr el mismo resultado final es una forma segura de generar código de calidad terrible que es una pesadilla de mantener y depurar.

Mencionas, oculto en un comentario, que debes usar un void return, esto no es un problema, simplemente pase el parámetro break como un puntero:

#include 

void checkAndDisplay(int n, bool* wantBreak)

    printf("%dn", n);
    if (n == 14)
        wantBreak = true;


int main(void) 
    bool wantBreak = false;
    for (int i = 0; i <= 100; i++) 
        checkAndDisplay(i, &wantBreak);
        if (wantBreak)
            break;
    
    return 0;

Dado que sus parámetros son de tipo fijo, le sugiero que use una conversión para pasar el puntero a uno de los parámetros, por ejemplo foo(a, b, (long)&out);

Eres capaz de estimular nuestro trabajo fijando un comentario y dejando una valoración te damos la bienvenida.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *