Segmentation Fault ayuda

Iniciado por GominaTilted, 22 Marzo 2020, 17:24 PM

0 Miembros y 2 Visitantes están viendo este tema.

GominaTilted

Buenas, antes de nada pedir perdón por el tocho de código. Tengo que arreglar un segmentation fault en mi programa pero no veo el error. Teóricamente el archivo que contiene el main no se puede modificar, pero creo que el error viene dado por acceder a un std::vector. También sospecho de la función asignValores(), pero no sé por qué podría fallar. Estos son los archivos implicados (acepto cualquier consejo a parte de el propio error).

Persona.h

#ifndef persona_H
#define persona_H
#include <iostream>
#include <string>
using namespace std;
class Persona
{
public:
Persona();
bool asignarValores(string, string, string, char, int, int, int);
bool setID(string);
bool setApellidos(string);
bool setNombre(string);
bool setSexo(char);
bool setEdad(int);
bool setEstatura(int);
bool setPeso(int);
string getID();
string getApellidos();
string getNombre();
char getSexo();
int getEdad();
int getEstatura();
int getPeso();
bool validarSexo(char);
bool validarEdad(int);
bool validarEstatura(int);
bool validarPeso(int);
friend ostream& operator<<(ostream&, Persona);

private:
string id;
string apellidos;
string nombre;
char sexo;
int edad;
int estatura;
int peso;

};

#endif


Persona.cpp

#include "persona.h"
#include <string>
Persona::Persona()
{
setID("Desconocido");
setApellidos("Desconocido");
setNombre("Desconocido");
setSexo('0');
setEdad(0);
setEstatura(0);
setPeso(0);
}

bool Persona :: asignarValores(string nid, string ap, string nom, char s, int e, int h, int w)
{
bool ok = false;

setID(nid);
setApellidos(ap);
setNombre(nom);
setSexo(s);
setEdad(e);
setEstatura(h);
setPeso(w);
ok = true;


return ok;
}

bool Persona :: setID(string nid)
{
id = nid;
return true;
}

bool Persona :: setApellidos(string ap)
{
apellidos = ap;
return true;
}

bool Persona :: setNombre(string nom)
{
nombre = nom;
return true;
}

bool Persona :: setSexo(char s)
{
bool ok = false;

if (validarSexo(s))
{
sexo = s;
ok = true;
}

return ok;
}

bool Persona :: setEdad(int e)
{
bool ok = false;

if(validarEdad(e))
{
edad = e;
ok = true;
}

return ok;
}

bool Persona :: setEstatura(int h)
{
bool ok = false;

if(validarEstatura(h))
{
estatura = h;
ok = true;
}

return ok;
}

bool Persona :: setPeso(int w)
{
bool ok = false;

if(validarPeso(w))
{
peso = w;
ok = true;
}

return ok;
}

string Persona :: getID()
{
return id;
}

string Persona :: getApellidos()
{
return apellidos;
}

string Persona :: getNombre()
{
return nombre;
}

char Persona :: getSexo()
{
return sexo;
}

int Persona :: getEdad()
{
return edad;
}

int Persona :: getEstatura()
{
return estatura;
}

int Persona :: getPeso()
{
return peso;
}

bool Persona :: validarSexo(char s)
{
bool ok = false;

if(s == 'M' || s == 'H' || s == 'O')
ok = true;

return ok;
}

bool Persona :: validarEdad(int e)
{
bool ok = false;

if(e >= 15 && e <= 100)
ok = true;

return ok;
}

bool Persona :: validarEstatura(int h)
{
bool ok = false;

if(h >= 30 && h <= 250)
ok = true;

return ok;
}

bool Persona :: validarPeso(int w)
{
bool ok = false;

if(w >= 25 && w <= 300)
ok = true;

return ok;
}

ostream& operator<<(ostream& out, Persona p)
{
out << p.getID() << ";";
out << p.getApellidos() << ";";
out << p.getNombre() << ";";
out << p.getSexo() << ";";
out << p.getEdad() << ";";
out << p.getEstatura() << ";";
out << p.getPeso() << endl << endl;

return out;
}


Estudiante.h

#ifndef estudiante_H
#define estudiante_H
#include <iostream>
#include <string>
#include "persona.h"
using namespace std;

class Estudiante: public Persona
{
public:
Estudiante();
bool asignarValores(string, string, string, char, int, int, int, string, int);
bool setTitulacion(string);
bool setCurso(int);
bool setID(string);
string getTitulacion();
int getCurso();
friend ostream& operator<<(ostream&, Estudiante);

private:
string titulacion;
int curso;
bool validarID(string);
bool validarCurso(int);
};

#endif


Estudiante.cpp

#include "persona.h"
#include "estudiante.h"
#include <string>

Estudiante :: Estudiante()
{
setID("Desconocido");
setApellidos("Desconocido");
setNombre("Desconocido");
setSexo('0');
setEdad(0);
setEstatura(0);
setPeso(0);
setTitulacion("Desconocido");
setCurso(0);
}

bool Estudiante :: asignarValores (string id2, string ap, string nom, char s, int a, int h, int w, string tit, int c)
{
bool ok = false;

setID(id2);
setApellidos(ap);
setNombre(nom);
setSexo(s);
setEdad(a);
setEstatura(h);
setPeso(w);
setTitulacion(tit);
setCurso(c);
ok = true;

return ok;
}

bool Estudiante :: setTitulacion(string tit)
{
titulacion = tit;

return true;
}

bool Estudiante :: setCurso(int c)
{
bool ok = false;

if (validarCurso(c))
{
setCurso(c);
ok = true;
}

return ok;
}

bool Estudiante :: setID(string id2)
{
bool ok = false;

if (validarID(id2))
{
Persona::setID(id2);
ok = true;
}

return ok;
}

string Estudiante :: getTitulacion()
{
return titulacion;
}

int Estudiante :: getCurso()
{
return curso;
}

ostream& operator<<(ostream& out, Estudiante e)
{
out << e.getID() << ";";
out << e.getApellidos() << ";";
out << e.getNombre() << ";";
out << e.getSexo() << ";";
out << e.getEdad() << ";";
out << e.getEstatura() << ";";
out << e.getPeso() << ";";
out << e.getTitulacion() << ";" << e.getCurso() << endl << endl;

return out;
}

bool Estudiante :: validarID(string id2)
{
bool ok = false;

if (id2[0] >= 'A' && id2[0] <= 'Z' && id2[1] >= 'A' && id2[1] <= 'Z')
ok = true;

return ok;
}

bool Estudiante :: validarCurso(int c)
{
bool ok = false;

if(c <= 4 && c >= 1)
ok = true;

return ok;
}


main.cpp

#include <iostream>
#include <fstream>
#include <vector>
#include "estudiante.h"

using namespace std;

/*
* Prototipos de las funciones empleadas,
* implementadas despues de main()
*/
string ExtraerToken(string&);
bool StrToestudiante (string, Estudiante&);
vector<Estudiante> LeerFichero(string);
Estudiante MasAlto (vector<Estudiante>);
Estudiante MasBajo (vector<Estudiante>);
Estudiante MasJoven (vector<Estudiante>);
Estudiante MasViejo (vector<Estudiante>);
unsigned int NumEstudiantesCurso (vector<Estudiante>, int c);

/*
* Programa principal
*/
int main ()
{
    const string NOMBRE = "personal.dat"; //Nombre del archivo de datos
    vector<Estudiante> misestudiantes; //Vector para almacenar estudiantes leidos
   
    cout << endl << "Leyendo archivo ... ";
    misestudiantes = LeerFichero(NOMBRE);
    cout << "Fin." << endl;
    cout << endl;
    cout << "*** Num. estudiantes correctamente leidos: " << misestudiantes.size() << " ***" << endl;
    cout << endl;
    cout << "1. Estudiante mas ALTO:" << endl;
cout << MasAlto(misestudiantes) << endl;
    cout << endl;
cout << "2. Estudiante mas BAJO:" << endl;
cout << MasBajo(misestudiantes) << endl;
    cout << endl;
    cout << "3. Estudiante mas JOVEN:" << endl;
cout << MasJoven(misestudiantes) << endl;
    cout << endl;
    cout << "4. Estudiante mas VIEJO:" << endl;
cout << MasViejo(misestudiantes) << endl;
    cout << endl;
cout << "5. Estudiantes por curso:" << endl;
for (unsigned int i = 1; i <= 4; i++)
cout << "\tCurso " << i << " = " << NumEstudiantesCurso(misestudiantes,i) << endl;

return 0;
}

/**********************************************************************/ /**
*
*  Extraer 1 token de información de la cadena separada por ';'
*  El token es eliminado de la cadena de entrada
*
*  @param [in,out]  s  Cadena de datos
*
*  @return  string con el token extraido
*
*/ /**********************************************************************/
string ExtraerToken(string & s)
{
    string res="";
    size_t pos;
   
    pos = s.find(";");
    if ( pos != string::npos )
    {
        res = s.substr(0,pos);
        s.erase(0,pos+1);
    }
    else
    {
        res = s;
        s = "";
    }
       
    return res;
}

/**********************************************************************/ /**
*
*  Asignar valores a un objeto Estudiante a partir de
*  una línea de texto con datos separados por ';'
*
*  @param [in]  texto  Linea de texto
*  @param [in,out]  est  Estudiante modificado
*
*  @retval  true   Ha sido posible asignar correctamente valores.
*  @retval  false  No ha sido posible asignar correctamente valores.
*
*/ /**********************************************************************/
bool StrToEstudiante (string texto, Estudiante& est)
{
    string dato;
    unsigned int campo;
    string id, a, n;
    char s;
    int e, h, w;
    string tit;
    int curs;
    bool ok = true;
   
    campo = 0;
    while ( ok && campo < 9 )
    {
        dato = ExtraerToken(texto);
        if ( dato.length() != 0 )
        {
            switch ( campo )
            {
                case 0: id = dato; break;
                case 1: a = dato; break;
                case 2: n = dato; break;
                case 3: s = dato[0]; break;
                case 4: e = stoi(dato); break;
                case 5: h = stoi(dato); break;
                case 6: w = stoi(dato); break;
                case 7: tit = dato; break;
                case 8:
                curs = stoi(dato);
                ok = est.asignarValores(id,a,n,s,e,h,w,tit,curs);
                break;
            }
            campo++;
        }
        else
            ok = false;
    }
    return ok;
}

/**********************************************************************/ /**
*
*  Leer fichero de datos, devuelve vector de Estudiantes
*
*  @param [in]  nom  Nombre del fichero
*
*  @return  vector de Estudiantes
*
*/ /**********************************************************************/
vector<Estudiante> LeerFichero(string nom)
{
    ifstream fich_in;
    vector<Estudiante> v;
    string linea;
   
    fich_in.open (nom);
   
    if (fich_in)
    {
        while ( getline(fich_in, linea) )
        {
            Estudiante e;
            if ( StrToEstudiante(linea,e) )
                v.push_back(e);
        }
           
        fich_in.close ();
    }
    else
    cerr << "LeerFichero: Error al abrir el archivo de datos." << endl;

    return v;
}

/**********************************************************************/ /**
*
*  Determina el estudiante más alto de un vector de Estudiantes
*
*  @param [in]  v  Vector de Estudiantes
*
*  @return  Estudiante de mayor estatura (el primero del vector)
*
*/ /**********************************************************************/
Estudiante MasAlto (vector<Estudiante> v)
{
unsigned int max;
Estudiante e;
if ( v.size() > 0 )
{
max = 0;
for (unsigned int i=0; i < v.size(); i++)
if (v[i].getEstatura() > v[max].getEstatura())
max = i;
e = v[max];
}
return e;
}

/**********************************************************************/ /**
*
*  Determina el estudiante más bajo de un vector de Estudiantes
*
*  @param [in]  v  Vector de Estudiantes
*
*  @return  Estudiante de menor estatura (el primero del vector)
*
*/ /**********************************************************************/
Estudiante MasBajo (vector<Estudiante> v)
{
unsigned int min;
Estudiante e;
if ( v.size() > 0 )
{
min = 0;
for (unsigned int i=0; i < v.size(); i++)
if (v[i].getEstatura() < v[min].getEstatura())
min = i;
e = v[min];
}
return e;
}

/**********************************************************************/ /**
*
*  Determina el estudiante más joven de un vector de Estudiantes
*
*  @param [in]  v  Vector de Estudiantes
*
*  @return  Estudiante de menor edad (el primero del vector)
*
*/ /**********************************************************************/
Estudiante MasJoven (vector<Estudiante> v)
{
unsigned int min;
Estudiante e;
if ( v.size() > 0 )
{
min = 0;
for (unsigned int i=0; i < v.size(); i++)
if (v[i].getEdad() < v[min].getEdad())
min = i;
e = v[min];
}
return e;
}

/**********************************************************************/ /**
*
*  Determina el estudiante más viejo de un vector de Estudiantes
*
*  @param [in]  v  Vector de Estudiantes
*
*  @return  Estudiante de mayor edad (el primero del vector)
*
*/ /**********************************************************************/
Estudiante MasViejo (vector<Estudiante> v)
{
unsigned int max;
Estudiante e;
if ( v.size() > 0 )
{
max = 0;
for (unsigned int i=0; i < v.size(); i++)
if (v[i].getEdad() > v[max].getEdad())
max = i;
e = v[max];
}
return e;
}

/**********************************************************************/ /**
*
*  Determina el nº de estudiantes de un curso de un vector de Estudiantes
*
*  @param [in]  v  Vector de Estudiantes
*  @param [in]  c  Curso a buscar
*
*  @return  número de estudiantes en el curso c
*
*/ /**********************************************************************/
unsigned int NumEstudiantesCurso (vector<Estudiante> v, int c)
{
unsigned int num = 0;

for (unsigned int i=0; i < v.size(); i++)
if ( v[i].getCurso() == c )
num++;
return num;
}

K-YreX

Es mucho código como para buscar en qué parte se produce el error así que una de dos:
Mandas el fichero que estés utilizando tú también para que podamos ejecutarlo.
Lo ejecutas y nos copias el error que te salga para saber por lo menos en que línea o función se está produciendo.

De primeras te diría que el vector de la STL está implementado para que el programador se olvide de trabajar directamente con la memoria por lo que es raro (no digo imposible porque no voy a afirmar algo que desconozco) que el error se produzca por eso.
Yo diría que el error se produzca en algún parámetro que no se esté pasando como debiese o que se esté pasando por referencia y por tanto se esté modificando el contenido original. También puede ser memoria no reservada pero a simple vista no he visto ningún puntero ni reservas de memoria dinámicas.

Como consejos te diría que:
  • Las funciones asignarValores() tienen muchas papeletas para ser constructores parametrizados. Existe la sobrecarga, aprovéchala.
  • Veo cierta afición al bool ok y return ok. No te limites a mantener siempre una misma estructura ya que muchas veces será contraproducente. Las funciones que siempre devuelven true como lo son tus sets() o no devuelven nada porque sabemos que siempre van a ser true o si necesitas que devuelvan algo pon un <return true> directamente para indicar que la función ha llegado a su fin.
    Las funciones que asignan un valor booleano en base a unas condiciones y devuelven ese valor, pueden devolver directamente el resultado de la condición. ¿Cuál te parece mejor?
    Código (cpp) [Seleccionar]

    // Opcion 1
    bool esPositivo(int num){
      bool ok = false;
      if(num >= 0){
        ok = true;
      }
      return ok;
    }

    // Opcion 2
    bool esPositivo(int num){
      return (num >= 0);
    }


  • En los ficheros de cabecera (.h o .hpp) no se recomienda añadir cabeceras que utilizaremos en el fichero .cpp al igual que tampoco se recomienda definir un namespace por defecto. Puede parecer incómodo pero es mejor que en los ficheros de cabecera utilices la nomenglatura std::<lo_que_sea> (por ejemplo: std::string). Además como imagino que es algún tipo de tarea de clase, te recomendaría que incluyeses las cabeceras justas y necesarias. Así haces notar que sabes lo que haces y que no incluyes cabeceras porque sí, por si las moscas.
    Igual me estoy confundiendo y cumples con estas cosas que te digo. Como ya he dicho lo he mirado muy por encima.

    Yo creo que como consejos básicos ya tienes para entretenerte un rato. Y respecto al problema, lo dicho.
    PD: Si utilizas las etiquetas de Código GeSHi específicas para C++ además de disfrutar el espectacular resaltado de sintaxis también te numerará las líneas de tu código por si alguna otra persona quisiera hacer referencia a una línea concreta.
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

GominaTilted

#2
Te comento, asignValores() lo piden así en el enunciado. Lo de las funciones me lo apunto, pero vamos nace de que la tarea es una tontería y la he querido hacer rápido cpy/paste de funciones iguales. El problema se da al leer de fichero en el main. Con un main más sencillo no da error, como este por ejemplo:

Código (cpp) [Seleccionar]

#include "estudiante.h"
#include <iostream>

using namespace std;

int main()
{
Estudiante e;
cout <<  "Soy una persona con estos datos: \n" << (Persona)e << endl;
return 0;
}


Solucioné un segmentation fault que daba en ese main por utilizar los set donde no debía (hacía comprobaciones innecesarias en asignarValores() y daba error). Para no leeros el código, estudiante es una clase hija de persona, y en esta se añaden dos set y se modifica el setID().

El archivo es este

SW106563;EL MASSOUDI MOLNE;LAURA ANTONIA;X;24;163;87;Grado en Geografía y Medio Ambiente;4
KG802920;IBARGUCHI FORNELLS;NOARA;M;24;160;47;Grado en Información y Documentación;1
P65091;SUEIRAS AKALAI;MAYORO;H;37;165;85
U03504;VIQUEIRA BUCATARU;ANGEL SERGIO;H;30;148;64
EM012710;IZETA BELSA;INMACULADA;M;22;178;104;Grado en Negocios Internacionales;1


En realidad es mucho más largo pero son datos con ese formato.

El error concreto es "Segmentation fault (core dumped)"

EDIT: Una duda que me surge, ¿sería más óptimo utilizar los set en el constructor o modificar los atributos privados directamente?

engel lex

para conseguir el error con exactitud, usa el debugger de tu ide, corre el codigo paso a paso y donde veas que te da el error, ya sabes que es la linea que está desbordando la memoria
El problema con la sociedad actualmente radica en que todos creen que tienen el derecho de tener una opinión, y que esa opinión sea validada por todos, cuando lo correcto es que todos tengan derecho a una opinión, siempre y cuando esa opinión pueda ser ignorada, cuestionada, e incluso ser sujeta a burla, particularmente cuando no tiene sentido alguno.

GominaTilted

La verdad es que uso sublimetext y compilo en la consola de linux directamente, pero entraré a dev-c++  ;D

K-YreX

Bueno... encontrado el error, te comento lo que he hecho para que en otra ocasión puedas encontrar el problema tú solo.
Primero he comentado todo el contenido del main() excepto las primeras líneas hasta la llamada a LeerFichero() para ver si el problema estaba en esa función o en las siguientes. El error está ahí así que he ido a LeerFichero(). Una vez aquí, he añadido una línea para ver el contenido en cada iteración:
Código (cpp) [Seleccionar]

while ( getline(fich_in, linea) ){
    cout << "\n#Contenido linea: " << linea << endl;
    Estudiante e;
    if ( StrToEstudiante(linea,e) )
        v.push_back(e);
}

Si compilas y ejecutas verás que sólo se llega a mostrar el contenido de la primera línea del fichero por lo que el error está en la primera iteración. Vamos entonces  a la función StrToEstudiante(). En esta función añadimos otra línea para ver cada token.
Código (cpp) [Seleccionar]

dato = ExtraerToken(texto);
cout << "#Dato extraido: " << dato << endl;
if ( dato.length() != 0 )

Vemos que todos los tokens se extraen correctamente por lo que el problema está en asignarValores(). Comentamos las líneas intermedias y las vamos descomentando una por una y ejecutando el programa con cada cambio. Aquí verás que el problema ocurre al descomentar setCurso() por lo que vamos ahí y... Resulta que estás haciendo una llamada recursiva a setCurso() desde setCurso() por lo que tenemos una recursividad infinita.




Cita de: GominaTilted en 22 Marzo 2020, 21:18 PM
Te comento, asignValores() lo piden así en el enunciado. Lo de las funciones me lo apunto, pero vamos nace de que la tarea es una tontería y la he querido hacer rápido cpy/paste de funciones iguales. El problema se da al leer de fichero en el main. Con un main más sencillo no da error, como este por ejemplo:

EDIT: Una duda que me surge, ¿sería más óptimo utilizar los set en el constructor o modificar los atributos privados directamente?

El tema de copiar funciones que ya tienes al final hace que te limites a un estilo de programación siempre igual que puede resultar en ocasiones ineficiente. Cada situación puede ocasionar una solución mejor.
Y respecto a tu otra duda, diría que sí, es habitual en el constructor modificar directamente los atributos privados. Así generas menos dependencias y un error en un set() no va a hacer que todos tus objetos se creen de forma incorrecta. Además ya habrás visto que al ir llamando funciones dentro de funciones, cuando tienes un problema tienes que empezar a buscar hacia dentro y cuantas más tengas, más laborioso será llegar al final.
PD: Otro tip es que uses siempre nombres de variables significativos. Si otra persona tiene que leer tu código (y nunca sabes cuando puede pasar eso) o tú mismo cuando tengas códigos con mucho tiempo de desarrollo detrás y los veas después de mucho tiempo, siempre será más complicado saber qué es esto:
Código (cpp) [Seleccionar]

string dato;
unsigned int campo;
string id, a, n;
char s;
int e, h, w;
string tit;
int curs;

Que esto:
Código (cpp) [Seleccionar]

string dato;
unsigned int campo;
string id, apellidos, nombre;
char sexo;
int edad, height, weight;
string titulo;
int curso;
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

engel lex

recomendaría usar VS code (funciona en linux al 100%) es ligero, mucho mas potente, similar en muchos aspectos al sublime (nadie me saca de la cabeza que empezo como una copia de) y puedes hacer debug
El problema con la sociedad actualmente radica en que todos creen que tienen el derecho de tener una opinión, y que esa opinión sea validada por todos, cuando lo correcto es que todos tengan derecho a una opinión, siempre y cuando esa opinión pueda ser ignorada, cuestionada, e incluso ser sujeta a burla, particularmente cuando no tiene sentido alguno.

GominaTilted

Ahora probaré, porque en dev-c++ explota todo (literalmente, no va, crashea el dev-c++)

GominaTilted

Cita de: YreX-DwX en 23 Marzo 2020, 01:18 AM
Bueno... encontrado el error, te comento lo que he hecho para que en otra ocasión puedas encontrar el problema tú solo.
Primero he comentado todo el contenido del main() excepto las primeras líneas hasta la llamada a LeerFichero() para ver si el problema estaba en esa función o en las siguientes. El error está ahí así que he ido a LeerFichero(). Una vez aquí, he añadido una línea para ver el contenido en cada iteración:
Código (cpp) [Seleccionar]

while ( getline(fich_in, linea) ){
    cout << "\n#Contenido linea: " << linea << endl;
    Estudiante e;
    if ( StrToEstudiante(linea,e) )
        v.push_back(e);
}

Si compilas y ejecutas verás que sólo se llega a mostrar el contenido de la primera línea del fichero por lo que el error está en la primera iteración. Vamos entonces  a la función StrToEstudiante(). En esta función añadimos otra línea para ver cada token.
Código (cpp) [Seleccionar]

dato = ExtraerToken(texto);
cout << "#Dato extraido: " << dato << endl;
if ( dato.length() != 0 )

Vemos que todos los tokens se extraen correctamente por lo que el problema está en asignarValores(). Comentamos las líneas intermedias y las vamos descomentando una por una y ejecutando el programa con cada cambio. Aquí verás que el problema ocurre al descomentar setCurso() por lo que vamos ahí y... Resulta que estás haciendo una llamada recursiva a setCurso() desde setCurso() por lo que tenemos una recursividad infinita.



El tema de copiar funciones que ya tienes al final hace que te limites a un estilo de programación siempre igual que puede resultar en ocasiones ineficiente. Cada situación puede ocasionar una solución mejor.
Y respecto a tu otra duda, diría que sí, es habitual en el constructor modificar directamente los atributos privados. Así generas menos dependencias y un error en un set() no va a hacer que todos tus objetos se creen de forma incorrecta. Además ya habrás visto que al ir llamando funciones dentro de funciones, cuando tienes un problema tienes que empezar a buscar hacia dentro y cuantas más tengas, más laborioso será llegar al final.
PD: Otro tip es que uses siempre nombres de variables significativos. Si otra persona tiene que leer tu código (y nunca sabes cuando puede pasar eso) o tú mismo cuando tengas códigos con mucho tiempo de desarrollo detrás y los veas después de mucho tiempo, siempre será más complicado saber qué es esto:
Código (cpp) [Seleccionar]

string dato;
unsigned int campo;
string id, a, n;
char s;
int e, h, w;
string tit;
int curs;

Que esto:
Código (cpp) [Seleccionar]

string dato;
unsigned int campo;
string id, apellidos, nombre;
char sexo;
int edad, height, weight;
string titulo;
int curso;


Muchas gracias :). No había visto eso :/