Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   .NET (https://www.clubdelphi.com/foros/forumdisplay.php?f=17)
-   -   ¿Es posible borrar pila de llamadas? (https://www.clubdelphi.com/foros/showthread.php?t=96827)

REHome 29-08-2024 22:46:31

¿Es posible borrar pila de llamadas?
 
Hola gente:

¿Cómo están todos?

Quiero en C#, cuando entro en un void, al terminar, vuelve a continuar su camino justo donde lo dejó. Entro en un void a() a otro void b(). Todo acaba bien cuando termina void b(), vuelve al void a() y también acaba.

El problema está cuando hago esto. Voy al void a(), dentro de él, salto directamente al b(), sin acabar el void b(), salto al void c(), sin terminar el c(), salto o llamo al a() directamente.

De esa manera la pila se queda almacenada, no se borra hasta que termine todo el código interior de cada void.

¿Hay alguna manera de borrar la pila de llamada cuando salte de un void a otro sin terminar el programa completo?

Ya que estoy haciendo saltitos haciendo pruebas.

Lo suelo hacer cuando se hace mençus co nsubmenús y me da la tabarra.

Ver vídeo.

Gracias.

Casimiro Notevi 30-08-2024 10:56:41

A lo mejor debes dejar sólo el botón "Atrás" y quitar el de "Inicio".

REHome 30-08-2024 17:22:27

Ya se lo que le pasa. Cuando entro a un void, voy a otro que está anidado y no acabo el principal.

REHome 31-08-2024 07:25:33

Se desborda la pila por 5380 veces la pila de llamada, a veces 5376, otras veces por 5375, nunca igual.

Como puedes ver, e() llama a a() sin terminar el proceso e(), se crea la recursividad y por eso nunca acaba hasta que se desborde.

Tengo una pregunta.

Como e() nunca acaba su función porque dentro llama a a(). ¿Hay alguna manera de que termine de forma limpia dicha función e()?

Mi idea es que si llamo a e() y dentro tengo a a(), nunca acabará el e(). Lo malo de la función, que debe terminar el proceso o función antes de empezar otra.

Si uso goto, no tendré problemas de memoria de pila. Lo malo que el goto, crea malas prácticas de programación, por eso mejor no usarlo.

Si domino esto, podré hacer bien programas de consolas como este que puedes ver en el vídeo, llamar ventanas desde otras ventanas sin tener problemas de pila.

Ahí está el dilema.

Ver vídeo.

Código en C#:
Código:

using System;

namespace Pila_de_llamadas_Consola_01
{
    internal class Program
    {
        static void e()
        {
            a();
        }
        static void d()
        { // Aquí.
        }

        static void c()
        {
        }

        static void b()
        {
            c();
            d();
            e();
        }

        static void a()
        {
            b();
        }

        static void Main(string[] args)
        {
            a();
        }
    }
}


Casimiro Notevi 31-08-2024 11:49:00

En lugar de llamar de unas a otras, puedes regresar con un parámetro a la principal e indicando en ese parámetro a cuál debe ir.

REHome 01-09-2024 16:24:29

Hola:

He hecho esto. Porque controla que no haya recursividad sin darme cuenta y funciona.
Código:

using System;

namespace Pila_de_llamadas_Consola_03
{
    internal class Program
    {
        // Contador para controlar la recursividad.
        private static int contador = 0;

        static void e()
        {
            if (contador < 1) // Limita las llamadas recursivas.
            {
                contador++;
                a();
            }
        }
        static void d()
        { // Aquí.
        }

        static void c()
        {
        }

        static void b()
        {
            c();
            d();
            e();
        }

        static void a()
        {
            b();
        }

        static void Main(string[] args)
        {
            a();

            Console.WriteLine("Fin de programa.");

            // Pulse cualquier tecla para salir.
            Console.ReadKey();
        }
    }
}

Funcione para este ejemplo de arriba, pero no para lo que estoy haciendo.

En lo que comentas.
Cita:

En lugar de llamar de unas a otras, puedes regresar con un parámetro a la principal e indicando en ese parámetro a cuál debe ir.
Por lo que veo, no debo llamar a un void a otro void o funciones. Debo terminar ese void o función primero solo para que quite la pila en memoria. Luego como dices, indicar a donde quiero ir, es decir, llamar a otro void, pero este ya estará limpio y no se me queda almacenado sin darme cuenta.

Iba a usar los goto que no usa pila de llamadas en ningún momento, todo el mundo me dicen, prohibido usar goto, porque así evito malas prácticas de programación a cara el futuro.

¿Puedes poner un ejemplo sobre lo que indicas?

Gracias.

delphi.com.ar 02-09-2024 15:49:05

Es importante aclarar que void es el tipo de dato que devuelve la función, las llamadas son a funciones, métodos o procedimento sin resultado, no a void. Lo que estas haciendo es un ciclo sin salida (A>B>E>A), la pila se va a llenar siempre. Para eso debes controlar la recursividad.

Código Delphi [-]
using System;

namespace Pila_de_llamadas_Consola_01
{
    internal class Program
    {
        static void e()
        {
            a(false);
        }
        static void d()
        { // Aquí.
        }

        static void c()
        {
        }

        static void b()
        {
            c();
            d();
            e();
        }

        static void a(bool recursive)
        {
            if (recursive)
               b();
        }

        static void Main(string[] args)
        {
            a(false);
        }
    }
}


Esto es una adaptación rápida, pero no parece tener lógica, es difícil entender lo que quieres lograr.

mamcx 02-09-2024 22:17:08

Hay maneras para evitar un stack overflow:

Usando la ultima forma, porque parece que estas intentando es hacer un 'Navigation Controller` como: https://developer.apple.com/document...tioncontroller, y es muy fácil de esquematizar:


Código Delphi [-]
type
  TView = (Root, ScreenA, ScreenB);


type
  TNavigationStack = class
  private
    FStack: TArray;
  public
    constructor Create;
    procedure Push(View: TView);
    function Pop: TView;
    function Current: TView;
  end;


constructor TNavigationStack.Create;
begin
  SetLength(FStack, 1);
  FStack[0] := Root;  // Start with the root view
end;

procedure TNavigationStack.Push(View: TView);
begin
  SetLength(FStack, Length(FStack) + 1);
  FStack[High(FStack)] := View;
end;

function TNavigationStack.Pop: TView;
begin
  if Length(FStack) > 1 then
  begin
    Result := FStack[High(FStack)];
    SetLength(FStack, Length(FStack) - 1);
  end
  else
    Result := Root;  // Prevent popping the root view
end;

function TNavigationStack.Current: TView;
begin
  Result := FStack[High(FStack)];
end;


La franja horaria es GMT +2. Ahora son las 10:42:16.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi