1

qué tal? Estoy aprendiendo recién pilas con C++ y mi problema radica en el error: violación de segmento('core' generado). A principio hacia el mismo codigo para insertar una pila y ,lo mismo para buscar,pero ahora que quiero modificar la pila me sale ese error.Pues les paso de dónde saqué la idea del algoritmo y el código que escribí yo porque lo estuve leyendo y por lo que vi no hay error.

Curso donde saqué los algoritmos:https://youtu.be/Ydr6-GhMmRg

Código hecho por mí:

    #include <iostream>
    #include <stdlib.h>
    using namespace std;

   //--estructura---
   struct Nodo{
   int dato;
   Nodo *siguiente;
   } *primero;

  //Prototipo de funciones
  void menu();
  void insertarPila();
  void mostrarPila();
  void buscarPila();
  void modificarPila();

  //---MAIN---
  int main(){

main();
return 0;
   }

//---MENU---

void menu(){
int opc = 0;

do{
cout<<"\n\t.MENU.";
cout<<"\n1. Ingresar elemento.";
cout<<"\n2. Mostrar elementos.";
cout<<"\n3. Buscar elemento.";
cout<<"\n4.Modificar pila.";
cout<<"\n5.Salir.";
cout<<"\nOpcion: ";
cin>>opc;

    switch(opc){
        case 1: insertarPila();
            break;
        case 2: cout<<"\nLA PILA QUEDA ASI: ";
                mostrarPila();
            break;
        case 3: buscarPila();
            break;
        case 4: modificarPila();
            break;
        case 5: break;
        default: cout<<"\tEs del 1 al 4 pendejo\n\n";

    }
    system("clear");
}while(opc != 5);
 }
//-----Funciones-----
void insertarPila(){
Nodo *nuevo = new Nodo();
cout<<"Digite el elemento para la pila: ";
cin>>nuevo->dato;

nuevo->siguiente = primero;
primero = nuevo;

cout<<"\n\tElemento ingresado correctamente";
}

void mostrarPila(){
Nodo *actual = new Nodo();
actual = primero;
if(primero != NULL){
    while(actual != NULL){
        cout<<" , "<<actual->dato;
        actual = actual->siguiente;
    }
}
else{
    cout<<"\n\nPila vacia\n\n";
}
}

void buscarPila(){
Nodo *actual = new Nodo();
actual = primero;
int buscar_pila = 0;
bool encontrado = false;

cout<<"Ingrese el elemento a buscar: ";
cin>>buscar_pila;

if(primero != NULL){
    while(actual != NULL && encontrado != true){
     if(actual->dato == buscar_pila){
        cout<<"El elemento buscado fue encontrado correctamente";
        encontrado = true;
     }
     actual = actual->siguiente;
    }
    if (encontrado == false){
        cout<<"El elemento que busca no se encuentra en la pila";
    }
}
else{
    cout<<"\n\nPila vacia\n\n";
}
}

void modificarPila(){
Nodo *actual = new Nodo();
actual = primero;
int buscar_pila = 0;
bool encontrado = false;

cout<<"Ingrese el elemento a buscar para modificar: ";
cin>>buscar_pila;

if(primero != NULL){
    while(actual != NULL && encontrado != true){
     if(actual->dato == buscar_pila){
        cout<<"El elemento buscado fue encontrado correctamente";
        cout<<"Digite el nuevo elemento: ";
        cin>>actual -> dato;
        cout<<"\n\tEl elemento fue modificado";
        encontrado = true;
     }
     actual = actual->siguiente;
    }
    if (!encontrado){
        cout<<"El elemento que busca no se encuentra en la pila";
    }
}
else{
    cout<<"\n\nPila vacia\n\n";
}
}

Cualquier cosa me avisan si necesitan X información y desde ya muchas gracias!

  • 2
    Sin entrar a mirar el código al completo, el programa te fallará nada más arrancar porque en `main` llamas a `main`, creando una llamada recursiva infinita. – PaperBirdMaster Mar 05 '20 at 07:18

2 Answers2

3

Si has redactado tu siguiendo el curso de YouTube que enlazas, te aconsejo que no vuelvas a ver ningún vídeo de ese canal.


Tienes algunas cosas incorrectas, por orden de aparición:

  • No debes incluir la cabecera <stdlib.h> ya que es una cabecera de no de (lee este hilo para saber más). A parte de ser la cabecera incorrecta para el código que estás redactando, esa cabecera da acceso a funciones que no estás usando en tu código.
  • Está explícitamente prohibido llamar a main dentro de main, tal y como recoge el estándar C++ §6.9.3.1 función main en el punto 3: La función main no debe ser usada dentro del programa.
  • Ni siquiera llamas a la función menu, así que es imposible que tu programa hará algo de lo que le pides en el código redactado.
  • Estás generando fugas de memoria en las funciones mostrarPila, buscarPila y modificarPila, ya que lo primero que haces es generar un nuevo Nodo para acto seguido descartar la memoria recién solicitada sobrescribiendo con el puntero primero.
  • C++ dispone de un literal de puntero nulo, es nullptr. Debe ser usado en lugar de la macro NULL.
  • Tienes repetición de código (gran parte de la función de buscar y modificar son iguales), lo cuál hace tu código más difícil de mantener.
  • No has redactado las rutinas de borrado de memoria, generando aún más fugas de memoria.

Si llamo a menu dentro de main he podido comprobar que el código funciona, pero si tuviera un compañero de trabajo que redactase ese código, pediría su despido inmediatamente. ¿Qué deberías hacer para evitar ese trágico destino?

  • Estás programando en C++, usa objetos:

    struct Pila
    {
        struct Nodo
        {
            int dato{};
            Nodo *siguiente{nullptr};
        };
    
        Pila() = default;
        ~Pila();
    
        void insertar(int valor);
        void modificar(int valor);
        Nodo *buscar(int valor);
    
        friend std::ostream &operator <<(std::ostream &, const Pila &);
    private:
        Nodo *primero{nullptr};
    };
    
  • Inicializa las variables que usas.
  • Evita usar punteros en crudo, y si los usas libera la memoria que solicitas.
  • Sigue el principio de responsabilidad única y evita duplicar código.

Con esos consejos, tu código podría quedar así:

int main()
{
    using namespace std;
    Pila p;
    int opc;
    do {
        cout << "\n\t.MENU."
            "\n1. Ingresar elemento."
            "\n2. Mostrar elementos."
            "\n3. Buscar elemento."
            "\n4.Modificar pila."
            "\n5.Salir."
            "\nOpcion: ";

        int valor;
        cin >> opc;

        switch(opc){
            case 1:
                cout << "Valor a insertar: ";
                cin >> valor;
                p.insertar(valor);
                break;
            case 2:
                cout<<"\nLA PILA QUEDA ASI:\n" << p << '\n';
                break;
            case 3:
                cout << "Valor a buscar: ";
                cin >> valor;
                if (p.buscar(valor))
                    cout << "encontrado";
                else
                    cout << "no encontrado";
                break;
            case 4:
                cout << "Valor a modificar: ";
                cin >> valor;
                if (auto n = p.buscar(valor))
                {
                    cout << "nuevo valor: ";
                    cin >> valor;
                    n->dato = valor;
                }
                break;
            case 5:
                break;
            default:
                cout<<"\tOpcion incorrecta\n\n";
                break;
        }
    }while(opc != 5);

    return 0;
}
PaperBirdMaster
  • 44,474
  • 6
  • 44
  • 82
  • Me ha encantado lo de solicitaría su despido. – Alexmaister Mar 05 '20 at 09:39
  • 1
    Buenas Paper,qué tal? Si bien el programa no iniciaba porque había escrito de manera incorrecta la función menu(); , el resto de errores se deben a mi falta de conocimiento y practica puesto que a los punteros los aprendí recién hace 2 días y ayer recién aprendí lo que son las pilas. Ya leí todo lo que me enviaste y aprendí las diferencias de cabecera entre C y C++, como también entendí los conceptos de "fuga de memoria" y "responsabilidad única". El problema ahora radica en que POO hasta el momento no he visto y por ende no sé crear objetos. Sobre la fuga de memoria no se donde va el delete. – Tobi_Emotic Mar 05 '20 at 19:23
  • 1
    Por otra parte, ya aprendí en que debo inicializar cada variable. Ahora también otro tema que hace que falle es no entender eso de: Nodo *nuevo = primero; como tampoco entiendo la lógica de la pila. Por el simple hecho de falta de conocimientos cometo esos errores,más aún que no sé la lógica de pilas y como tal el algoritmo de la misma se me olvida. Desde ya muchas gracias por tu comentario,me ayudó a entender muchas cosas y también muchas gracias por pasarme el código sin los errores que yo he cometido! – Tobi_Emotic Mar 05 '20 at 19:25
  • 1
    @Tobi_Emotic me gusta tu positiva reacción. Y me gustaría que redactaras nuevas preguntas para las nuevas dudas que te surgen. – PaperBirdMaster Mar 06 '20 at 07:17
  • @PaperBirdMaster Muchas gracias Paper! A futuro cuando tenga más dudas las haré. Por otra parte,me busqué diversos documentos en PDF sobre estructura de datos en C++ y encontré uno con un excelente contenido que no sólo me va a hacer introducirme y avanzarme en lo que son pilas,colas,listas y árboles,sino que también me introducirá a la POO así en un futuro luego no se me hace tan tedioso aprender ése nuevo paradigma de la programación. Desde ya muchas gracias y que tengas una bonita tarde! – Tobi_Emotic Mar 06 '20 at 19:11
  • @PaperBirdMaster buenas Paper,qué tal? Estuve leyendo varias cosas acerca de estructura de datos y he mejorado. Acá te paso el nuevo código que hice: https://pastebin.com/umgk1zdv . Pues hice lo que me habías recomendado como también me fijé para que no tenga fuga de memoria y tuve en cuenta el principio de responsabilidad. Un saludo y que tengas un lindo día! – Tobi_Emotic Mar 09 '20 at 19:10
1

Variable no inicializada

struct Nodo{
  int dato;
  Nodo *siguiente;
} *primero; // <<--- AQUI

Si no inicializas el puntero, el mismo apuntará a una dirección aleatoria de memoria, luego cualquier acceso de lectura seguramente provocará que el sistema operativo mate tu programa para preservar la memoria del resto de procesos.

} *primero = nullptr;

Variable no inicializada (2)

Otra variable que no inicalizas es Nodo::siguiente. Para inicializar las variables miembro de un objeto existen los constructores:

// C++11 en adelante
class Nodo
{
  public:
    Nodo()
      : siguiente{nullptr}
    { }
};

// C++03 y anteriores
class Nodo
{
  public:
    Nodo()
      : siguiente(0)
    { }
};

Tabula el código

El código debe estar correctamente tabulado para entenderlo de la mejor forma posible.

Tu código tiene una tabulación bastante mala Variables estáticas

No hay ninguna necesidad de usar variables estáticas en tu código. Es preferible que te acostumbres a usar los parámetros de las funciones ya que no solo es la forma habitual de trabajar sino que es más segura.

Llamadas recursivas a main

En un programa sano no se debe llamar nunca a la función main de forma explícita. Si necesitas ejecutar una porción del código varias veces usa bucles y, de ser necesario, reestructura tu código.

En este caso imagino que lo más probable es que se trate de un error tipográfico y que tu intención real sea llamar a menu:

int main(){
  menu(); // menu y no main
  return 0;
}

Un nodo no es una lista

Este es un tema que se ha discutido varias veces en StackOverflow. Te sugiero buscar otras perguntas basadas en listas y seguro que encuentras muchas similitudes con tu caso.

Fugas de memoria

void mostrarPila(){
  Nodo *actual = new Nodo(); // <<--- AQUI
  actual = primero;
  if(primero != NULL){
    while(actual != NULL){
      cout<<" , "<<actual->dato;
      actual = actual->siguiente;
    }
  }
}

Si te fijas en la primera línea, estás creando un objeto de tipo Nodo, dejando el puntero actual apuntando a dicho objeto... y justo en la siguiente línea haces que el puntero apunte al mismo objeto que primero... acabas de perder la dirección de memoria del primer objeto luego ya no vas a poder liberarlo.

Esto se traduce en lo que se denomina fugas de memoria, que no es otra cosa que objetos que no se borran y se quedan ocupando memoria de forma totalmente innecesaria. Puede parecer algo absurdo... pero la unión hace la fuerza y una acumulación suficientemente grande de objetos sin borrar puede hacer que tu aplicación deje de funcionar por falta de memoria.

En este caso no es necesario llamar a new. Piensa que un puntero se compone de dos elementos:

  • La variable en sí
  • El objeto al que referencia

Un puntero puede existir sin referenciar a ningún objeto y, este caso es un claro ejemplo de ello:

Nodo *actual = 0;
actual = primero;

O, simplificando en una sola línea:

Nodo* actual = primero;
eferion
  • 49,291
  • 5
  • 30
  • 72
  • Buenas eferion,qué tal? Mi problema se debió a llamar la función menu(); en int main de manera incorrecta. Por otro lado ya corregí el final en mi código: Nodo* actual = primero;. Ahora mi problema radica en no entender la lógica de pilas ni entiendo su algoritmo. Por otro lado,punteros lo vi hace 2 días siendo que pilas recién lo empecé a ver ayer. Por el momento POO no he visto y por esa razón no le puedo dar in uso a los objetos ni a las clase,aunque de todas formas agradezco un montón tu código para C++ en las distintas versiones. Luego el puntero *primero ya lo inicialicé igual que vos. – Tobi_Emotic Mar 05 '20 at 19:32
  • En la parte de "Un nodo no es una lista", eso no lo sé puesto que aún listas no he visto. Veo que ambos comentarios se basan en POO. Tengo una duda,se puede aprender POO sin antes haber aprendido pilas,colas,listas y árboles? Desde ya muchas gracias por tu respuesta y por el código corregido ,más aún por la información brindada! – Tobi_Emotic Mar 05 '20 at 19:38
  • @Tobi_Emotic soy 67 xd, recuerda aceptar la pregunta que resolvió tu duda o problema. – Julio Cesar Mar 06 '20 at 02:56
  • Buenas bro,es que ambas solucionaron mi problema ! – Tobi_Emotic Mar 06 '20 at 02:57