Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Mensajes - K-YreX

#351
Otra opción posible sería guardar la entrada en un string y a partir de ahí validar esa entrada antes de convertirla al dato que quieres.
Te recomendaría echar un vistazo a la biblioteca <cctype>: http://www.cplusplus.com/reference/cctype/
#352
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;
#353
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.
#354
Mi problema, como dice el asunto es el siguiente: tengo un fichero xml muy sencillo con un dtd interno y quiero pasar su contenido a una tabla de SQL Server. (Estoy utilizando SSMS 2014). Lo primero que había intentado era:
Código (sql) [Seleccionar]

DECLARE @doc xml
SELECT @doc = (cast x as xml) FROM OPENROWSET(BULK 'ruta', SINGLE_BLOB) as T(x)

Pero al intentar ejecutarlo me aparecía el siguiente error:

No se permite analizar XML con DTD de un subconjunto interno. Utilice CONVERT con la opción de estilo 2 para habilitar la compatibilidad limitada con DTD de subconjuntos internos.


Investigué un poco el uso de CONVERT y cambié la sentencia anterior por:
Código (sql) [Seleccionar]

SELECT @doc = CONVERT(xml, x, 2) FROM OPENROWSET(BULK 'ruta', SINGLE_BLOB) as T(x)

Parece que se ejecuta correctamente mostrando el siguiente mensaje:

Se ha quitado del DTD XML uno o más fragmentos XML. Se han omitido los subconjuntos externos existentes.


Pero a la hora de intentar trabajar con la variable @doc me sale el siguiente error:

Debe declarar la variable escalar "@doc".



Ya de paso aprovecho para preguntar si conocéis de alguna guía sobre SQL Server ya que voy buscando información según la voy necesitando pero no llego a consolidar nada de forma teórica. Muchas gracias desde ya.

PD: El documento xml es válido y como es lógico pero por si acaso lo digo: donde he ido poniendo 'ruta' obviamente es la ruta completa de mi fichero xml pero para no copiarla entera...  :-X



EDIT RESUELTO: Vale, problema resuelto. Tengo el día tonto y estaba ejecutando únicamente la última sentencia. He seleccionado desde el DECLARE hasta el final y ya funciona correctamente... :rolleyes: :rolleyes:
#355
La idea más sencilla como te he respondido en el mensaje es la siguiente:

palabras := array de struct (palabra, repeticiones)
palabrasGuardadas := 0

MIENTRAS !finArchivo HACER
  palabra = leerSiguientePalabra()

  // Recorres las palabras que ya has guardado a ver si coincide alguna:
  i := 0
  MIENTRAS i < palabrasGuardadas AND palabra != palabras[i].palabra HACER
    i := i + 1
  FIN MIENTRAS

  // Sales cuando llegas al final (y entonces es nueva) o cuando encuentras la palabra guardada en i:
  SI i == palabrasGuardadas ENTONCES
    palabras[palabrasGuardadas].palabra = palabra
    palabras[palabrasGuardadas].repeticiones = 1
    palabrasGuardadas := palabrasGuardadas + 1
  SINO ENTONCES
    palabras[i].repeticiones := palabras[i].repeticiones + 1
  FIN SI
FIN MIENTRAS


Es mejorable teniendo las palabras ordenadas para hacer las búsquedas más eficientes o usando otras estructuras de datos pero para empezar basta con que consigas implementar este pseudocódigo.
#356
Cuando pongas código utiliza etiquetas de Código GeSHi. Las puedes seleccionar encima del cuadro de texto, en el desplegable que dice exactamente eso: Código GeSHi. Usa las del lenguaje apropiado.

No he revisado si tu código encuentra las ocurrencias correctamente, confiaré en tus dotes de programador.  :xD
Pero vamos que si tienes un array de una struct que almacena (palabra, repeticiones) es muy sencillo mostrarlas:
Código (cpp) [Seleccionar]

for(size_t i = 0; i < longitudArray; i++)
    cout << "La palabra: " << estructura.palabra << " aparece: " << estructura.repeticiones << " veces" << endl;

Tendrás que cambiar el nombre de las variables que he utilizado por las que estás utilizando tú.

Un problema puede ser saber cuántas posiciones del array de struct estás utilizando realmente. Tendrás que llevar un contador que se incremente con cada nueva inserción.
Si estás haciendo esto por mérito propio o es algún ejercicio en el que nadie te limita a lo que puedes o no puedes usar, siempre puedes utilizar algún contenedor de la STL para no tener que manejar directamente la memoria (será más fácil pero por tanto menos gratificante).
#357
Buscando "Thinking Functionally with Haskell pdf" este ha sido el tercer resultado:
https://pdfs.semanticscholar.org/c7e4/e082a1f681a320fd568d2a3ba2edec64a086.pdf

Creo que es lo que estás buscando... :rolleyes:
#358
Para rotar las posiciones de un array necesitas guardar uno de los valores en una variable auxiliar para empezar a guardar los nuevos valores en la posición que has guardado fuera y al final restaurar ese valor que tiene la variable auxiliar. Ahora bien, hay muchas formas de hacerlo.

Una forma visual es hacer una función que rote el array a la derecha 1 vez y hacer un bucle for que llame a dicha funciones n veces siendo n el número de posiciones que se quiere rotar el array a la derecha. No es lo más eficiente pero como te digo es visual.

void rotarDerecha(int *numeros, int size){
  int aux = numeros[size-1];
  for(size_t i = size - 1; i > 0; --i)
    numeros[i] = numeros[i-1];
  numeros[0] = aux;
}

int main(){
  //...
  for(size_t i = 0; i < rotaciones; ++i)
    rotarDerecha(numeros, size);
  //...
}


Para mejorar un poco la eficiencia del código, en vez de repetir el for tantas veces como el valor de rotaciones, podemos hacerlo (rotaciones % size) veces. Así aunque el número de rotaciones sea muy grande, siempre daremos menos de una vuelta completa al array.

Si lo quieres hacer más eficiente puedes trabajar sobre esta versión y utilizar un poco las matemáticas para sacar alguna relación entre las posiciones del array el número de rotaciones. Esta parte te la dejo a ti que te va a ser más satisfactorio que si te lo encuentras hecho.

Y recuerda que si te atascas en alguna parte puedes volver a dejar tu código para que te echemos una mano. Y te recomendaría usar nombres de variables más significativos; sobre todo si el código lo van a tener que leer terceras personas como es el caso... :rolleyes:   Suerte.  :-X
#359
En un principio el programa estaría limitado ya que tendrías que crear algún tipo de directriz para indicar qué son días y qué no. Las dos opciones más rápidas que se me ocurren serían:
  • Buscar números. Esto se podría hacer más complejo localizando también el mes y buscando números que estén entre 1 el último día de dicho mes. Sin embargo esta opción, como puedes ver en tu ejemplo, no es muy eficaz ya que cogería también el 02.
  • Buscar la palabra "día/s" y guardar todos los números que vayan seguidos de dicha palabra.

    Para empezar deberías mirar si la cadena la quieres obtener de la entrada estándar (teclado) o desde un fichero u otra entrada. Cuando tengas clara la entrada, busca cómo trabajar con dicha entrada: si es por teclado, busca cómo almacenar una cadena introducida por teclado; si es desde fichero, busca cómo abrir y recorrer un fichero... Comprueba también el lenguaje que quieres usar ya que C y C++ no son el mismo lenguaje aunque a veces se puedan mezclar funciones de ambos.

    Cuando tengas eso intenta implementar alguna de las opciones anteriores o alguna que se te ocurra a ti. De las opciones anteriores, como es obvio, te recomendaría la segunda aunque puedes empezar por intentar implementar la primera para ir practicando.

    Si llegas a un punto en el que no consigues avanzar es cuando puedes dejar tu código para que te ayudemos pero recuerda que el mayor esfuerzo tiene que salir de ti no de nosotros.
    Suerte :-X
#360
Antes de nada decir que hay un foro propio para Programación C/C++ y que no es necesario que escribas el mensaje en mayúsculas...

Dicho esto y sin conocer en profundidad tu implementación diría que el error puede estar en la línea 23 de la función InsertarArista() ya que en el <while()> continúas avanzando hasta que <aux> es NULL y cuando es NULL, intentas asignar a <sig>, <nueva>. Creo que el bucle debería ser <while(aux->sig != NULL)>