2

comunidad! Adelanto lo que hace mi codigo en C++ , permite ingresar numeros, se pueden listar los numeros ingresados y se puede "borrar" el ultimo numero y seguir borrandolos hasta que no quede ninguno. Es un programa de turnos en fila, o cola.

Tratando (5 dias)... de hacer este mismo programa para que acepte un nombre, osea un string y no encuentro la forma. No quisiera borrar y empesar de nuevo por que me llevo tiempo hacer esto. mi principal problema parese ser los tipos de datos que al pasar valores, se me estropean completos.

#include "stdafx.h"
#include <iostream>
//#include <string>

using namespace std;
struct nodo
{
    int dato;
    struct nodo* Next;
};

typedef struct nodo *pilaPtr;
pilaPtr Nuevo, Inicio, Aux, P;

pilaPtr getfila(void)
{
    pilaPtr p;
    p = (pilaPtr)malloc(sizeof(struct nodo));
    if (p != 0)
        p->Next = 0;
    return (p);
}

void freepila(pilaPtr p)
{
    free(p);
}

void Imprime()
{
    pilaPtr Aux;
    Aux = Inicio;

    if (Aux != 0)
    {
        do
        {
            cout << Aux->dato << "\t ";
            Aux = Aux->Next;

        } while (Aux != 0);
    }
}

void Agregar(int X)
{
    Nuevo = getfila();
    if (Nuevo != 0)
    {
        Nuevo->Next = Inicio;
        Inicio = Nuevo;
        Inicio->dato = X;
    }
}
void Menu()
{
    system("cls");
    cout << "\n*Ingrese numeros de manera ascendente";
    cout << "\n*Recuerde su numero, espere ser llamado.";  
    cout << "\n                     ";
    cout << "\n                     ";
    cout << "\n1 AGREGAR UN NUMERO A LA FILA ";
    cout << "\n2 ELIMINAR ULTIMO NUMERO EN FILA";
    cout << "\n3 IMPRIMIR NUMEROS ACTIVOS";
    cout << "\n4 SALIR\n\n";
}
int main()
{
    int opcion = 0, X;
    do
    {
        Menu();
        cout << "\n SELECCIONE UNA OPCION: ";
        cin >> opcion;

        switch (opcion)
        {
        case 1:
        {
            cout << "\n INGRESE EL VALOR QUE QUIERA ";
            cin >> X;
            Agregar(X);
            break;
        }
        case 2:
        {
            P = Inicio;
            Inicio = P->Next;
            free(P);

            system("PAUSE");
            break;
        }
        case 3:
            Imprime();

            system("PAUSE");
            break;
        }
    } while (opcion != 4);

    return EXIT_SUCCESS;
}
Harold
  • 23
  • 3

2 Answers2

3

Basta con cambiar la declaración del dato que lees y a continuación creas en la estructura. Me explico:

struct nodo
{
    string dato; // <--------------- cambiar de int a string
    struct nodo* Next;
};

Como es de tipo string el dato que vas a ir leyendo, su declaración dentro del struct debe ser del mísmo.

De igual forma hay que proceder en las funciones relacionadas con este dato. Basta con cambiar su declaración.

void Agregar(string X) // <----------- cambiar de int a string
{
    Nuevo = getfila();
    if (Nuevo != 0)
    {
        Nuevo->Next = Inicio;
        Inicio = Nuevo;
        Inicio->dato = X;
    }
}

Y, por último en el main:

int main()
{
    int opcion = 0 ;
    string X; // <--------------- cambiar de int a string
    do
    {
    ...

Sin olvidar, claro está, incluir la biblioteca string al inicio que en tu caso tienes comentada.

include <string>
3

Siendo la respuesta de Mario Rodríguez válida, su respuesta olvida varias cosas que considero importante mencionar.

Para empezar, todo tu programa tiene fugas de memoria; dado que estás trabajando en C++ podrías seguir el patrón de diseño RAII para ayudarte a gestionar la memoria; bastaría con añadir un destructor a tu objeto nodo:

struct nodo
{
    std::string dato;
    nodo *Next = nullptr;
    // El destructor elimina los recursos dinamicos solicitados.
    ~nodo() { delete Next; }
};

Si te fijas, a diferencia de en tu código, no he añadido la palabra clave struct en la declaración del puntero a nodo además de usar delete en lugar de free. Esto es porque en C++ no es necesario usar struct para declarar objetos relacionados con estructuras y C++ usa el par new/delete en lugar del par alloc/free.

Por otro lado, he añadido una inicialización en el puntero Next, de esta manera el puntero tendrá el valor nullptr (literal de puntero nulo) al construir los objetos nodo; se considera una buena práctica inicializar todos los valores1 siempre que no haya motivos para no hacerlo.

Teniendo en cuenta estas diferencias entre C y C++, tu función getfila debería quedar así:

using pilaPtr = nodo *;

pilaPtr getfila() try
{
    return new nodo;
}
catch (const std::bad_alloc &excepcion)
{
    return nullptr;
}

Una vez más hemos eliminado la palabra struct para declarar objetos relacionados con estructuras y en lugar de usar typedef hemos usado alias de tipo; el código que pusiste en getfila se ha vuelto completamente inútil porque:

  1. No hay que comprobar el retorno de malloc (en C++ se usa new).
  2. No hay que inicializar el miembro nodo::Next ya que le hemos añadido inicializador automático.
  3. No se necesita una variable intermedia para guardar el retorno de malloc, como no debemos comprobarlo podemos devolverlo directamente.
  4. No comprobamos el retorno de new porque esta funcionalidad nunca devuelve valores nulos, por el contrario: si fallase la solicitud de memoria se lanzaría una excepción de tipo std::bad_alloc. Para comprobar si esta excepción se lanza usamos un bloque de try-catch a nivel de función.

Aunque siendo un programa tan sencillo, difícilmente te quedarás sin memoria, si lo consideras conveniente podrías evitar todo el bloque try-catch:

using pilaPtr = nodo *;

pilaPtr getfila()
{
    return new nodo;
}

Fíjate que en ningún caso hemos añadido el tipo de dato void a los paréntesis de la función para indicar que esta función no recibe datos, en C++ no es necesario hacerlo.

Tu función freepila debería quedar así:

void freepila(pilaPtr p)
{
    delete p;
}

Gracias a que hemos añadido un destructor en el objeto nodo, al borrar el puntero se borrarán recursivamente el nodo facilitado y todos sus hijos.

Para acabar, tu función Agregar podría quedar así:

void Agregar(std::string X)
{
    if ((Nuevo = getfila()))
    {
        Nuevo->Next = Inicio;
        Inicio = Nuevo;
        Inicio->dato = X;
    }
}

En C++ (creo que en C también) la comprobación de nulidad del retorno de getfila se puede hacer en la misma instrucción if, esto es porque una asignación es un valor-del-lado-derecho y como tal se puede usar en una instrucción if2, pero hemos comentado que raramente este código devolverá un puntero nulo (considerando la implementación de getfila que puede devolverlo), así que podemos dejar la función Agregar así:

void Agregar(std::string X)
{
    Nuevo = getfila();
    Nuevo->Next = Inicio;
    Inicio = Nuevo;
    Inicio->dato = X;
}

Otras cosas a tener en cuenta.

  1. No mezcles idiomas al programar: Es confuso que estés hablando de nodos (Español) que contienen punteros a Next (Inglés).
  2. La función freepila es inútil (sólo hace una cosa) pero... si la tienes: úsala, en la opción 2 de tu menú llamas a free en lugar de a freepila.
  3. Evita usar using namespace std;, lee este hilo para saber más detalles de el por qué.
  4. Las cabeceras pre-compiladas de "stdafx.h" no te van a ayudar en un programa tan pequeño, no las uses.
  5. Para evitar las fugas de memoria, antes de finalizar main deberás añadir: freepila(Inicio);.
  6. El programa, tal y como está, generará corrupción de memoria ya que intentará borrar punteros que ya han sido borrados; para evitarlo, cada vez que borres un nodo, deberías igualar a puntero nulo (nullptr) todos los punteros que lo apunten.

1El dato del nodo se inicializa automáticamente a cadena vacía.

2Muchos compiladores aconsejan añadir un par extra de paréntesis ( y ) por claridad, no porque sea en realidad necesario.

PaperBirdMaster
  • 44,474
  • 6
  • 44
  • 82