Foros del Web » Programación para mayores de 30 ;) » C/C++ »

Violación de segmento (`core' generado)

Estas en el tema de Violación de segmento (`core' generado) en el foro de C/C++ en Foros del Web. Buenas tardes, Bueno pues estoy intentando hacer en un programa en C++, que con una opcion guarde una copia de las fichas que tengo y ...
  #1 (permalink)  
Antiguo 13/06/2016, 09:41
 
Fecha de Ingreso: junio-2016
Mensajes: 3
Antigüedad: 7 años, 10 meses
Puntos: 0
Pregunta Violación de segmento (`core' generado)

Buenas tardes,

Bueno pues estoy intentando hacer en un programa en C++, que con una opcion guarde una copia de las fichas que tengo y con otra lo pueda cargar (para que no se me borren una vez cierre y abra)

Para esto estoy utilizando ficheros binarios (ifstream y ofstream) y pues al hacer el db.read me da el error: Violación de segmento (`core' generado)

He intentado de todo y sigo sin saber qué pasa. Sé que es por los strings (al asignarles un valor), pero si los quito se hace todo el bucle, llega al final del módulo y me da el mismo error. Si abro sin cargar la db no pasa nada, funciona bien.

Código:
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <cstring>
#include <vector>
using namespace std;

typedef struct{
  int id;
  string nombre;
  vector<string> abrinfo;
  vector<string> info;
}TFicha;

vector<TFicha> database;
Módulo de cargar la db:
Código:
  typedef struct{
    int id;
    string nombre;
    int infnum;
    vector<string> abrinfo;
    vector<string> info;    
  }LFicha;

  bool stop=false;
  string name="database";
  int cnt=0;
  int temp=-1;
  LFicha dbficha;
  TFicha newficha;
  ifstream db(name.c_str(), ios::binary);
		  
  if(db.is_open()){
    while( db.read((char*)&dbficha, sizeof(LFicha)) && stop==false){
      newficha.id=dbficha.id;
      newficha.nombre=dbficha.nombre;
      cout << "ID: " << newficha.id << " temp: " << temp << endl;
      for(int i=0;i<dbficha.infnum;i++){
	newficha.abrinfo.push_back(dbficha.abrinfo[i]);
	newficha.info.push_back(dbficha.info[i]);
      }
      
      if(temp==newficha.id){
	stop=true;
      }
      
      if(stop==false){
	database.push_back(newficha);
	newficha.abrinfo.clear();
	newficha.info.clear();
	temp=dbficha.id;
	cnt++;
      }
    }
    cout << endl << "DATABASE: Se han leido con exito " << cnt << " fichas."<< endl;
  }else{
    cout << endl << "DATABASE: No se ha podido encontrar el archivo, revise el fichero"<<endl;
  }
  db.close();
Módulo para guardar la db:
Código:
  typedef struct{
    int id;
    string nombre;
    int infnum;
    vector<string> abrinfo;
    vector<string> info;
  }SFicha;

  SFicha tosave;
  string name="database";
  int cnt=0;
  char confirm='n';
  
  cout <<endl<< "DATABASE: Estas seguro de que deseas sobreescribir todo? (y/n): ";
  cin >> confirm;
  
  if(confirm=='y'){
    ofstream db(name.c_str(), ios::binary);
    if(db.is_open()){
      for(int x=0;x<database.size();x++){
	tosave.id= database[x].id;
	cout << "Save id: " <<tosave.id<<endl;
	tosave.nombre= database[x].nombre;
	cout << "Save name: "<< tosave.nombre<<endl;
	tosave.infnum= database[x].info.size();
	
	for(int i=0;i<tosave.infnum;i++){
	  tosave.abrinfo.push_back(database[x].abrinfo[i]);
	  tosave.info.push_back(database[x].info[i]);
	}
	db.write((char*)&tosave, sizeof(SFicha));
	cnt++;
      }
    }else{
      cout << endl << "DATABASE: No se ha podido encontrar el archivo, revise el fichero"<<endl;
    }
    db.close();
    
    cout << "DATABASE: Se han guardado "<<cnt<<" fichas.";
  }
Muchas gracias y saludos.
  #2 (permalink)  
Antiguo 13/06/2016, 16:55
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 2 meses
Puntos: 3
Respuesta: Violación de segmento (`core' generado)

No soy ningún experto y en c++ no estoy muy puesto pero yo diría que el error esta aqui:
Código PHP:
  typedef struct{
    
int id;
    
string nombre;
    
int infnum;
    
vector<stringabrinfo;
    
vector<stringinfo;    
  }
LFicha
Usas vector y lo que almacenas es su dirección ¿quien te dice a ti que en cada ejecución se va a respetar la dirección y que los datos a los que apunta dicha dirección no habrán sido machacados por otro proceso o por este mismo? Yo te diría que uses por ejemplo un archivo para cada vector y que almacenes todos los datos del vector al cerrar y al abrir lees el archivo y rellenas el vector con dichos datos.
  #3 (permalink)  
Antiguo 13/06/2016, 18:21
 
Fecha de Ingreso: junio-2016
Mensajes: 3
Antigüedad: 7 años, 10 meses
Puntos: 0
Respuesta: Violación de segmento (`core' generado)

No entiendo bien a qué te refieres. Antes lo había hecho con un otro typedef struct (y un vector de este tipo) que almacenaba esos dos strings que aparecen como vectores, pero me daba el mismo error.

Además, poniendo el for que carga esos datos como comentario sigue dando el mismo error.
  #4 (permalink)  
Antiguo 14/06/2016, 01:49
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 6 meses
Puntos: 204
Respuesta: Violación de segmento (`core' generado)

Código C++:
Ver original
  1. typedef struct{
  2.     int id;
  3.     string nombre;
  4.     int infnum;
  5.     vector<string> abrinfo;
  6.     vector<string> info;    
  7. }LFicha;

Estamos en C++, no en C, luego ese typedef sobra. Acostúmbrate a usar la sintaxis propia de C++ para conseguir código más legible (no solo para tí sino también para los demás.

El equivalente propio de C++ de la declaración anterior es esta (de hecho podrás comprobar que sustituyendo directamente una por otra el programa compila igual de bien):

Código C++:
Ver original
  1. struct LFicha{
  2.     int id;
  3.     string nombre;
  4.     int infnum;
  5.     vector<string> abrinfo;
  6.     vector<string> info;    
  7. };

Tu error:

Código C++:
Ver original
  1. db.read((char*)&dbficha, sizeof(LFicha))

En C puede ser razonable leer y escribir directamente una estructura accediendo a sus bytes pero en C++ eso no suele funcionar. La razón es que C++ usa clases y una clase puede tranquilamente hacer uso de memoria dinámica sin que tu te des cuenta.

En este caso las clases string y vector hacen uso de memoria dinámica. Es por ello que puedes almacenar una cadena todo lo larga que quieras en un string sin que el programa falle. Lo que sucede es que la clase string tiene un puntero. Simplificando la clase string podría quedar tal que:

Código C++:
Ver original
  1. class string
  2. {
  3.   private:
  4.     char* ptr;
  5.  
  6.   public:
  7.     // ...
  8. };

Si tu copias a nivel de bits lo que vas a almacenar es el contenido del puntero que no es más que una posición de memoria (32 bits) en vez de una cadena de texto. Al leer del fichero lo que haces es actualizar dicho puntero a la fuerza y claro, acaba apuntando a una dirección no válida.

En C++ el guardado binario de la información es más laborioso que en el caso de C ya que tienes que guardar elemento a elemento. O eso o te creas una estructura plana (sin clases) al más puro estilo C, copias los datos en dicha estructura y vuelcas sus bits al fichero:

Código C++:
Ver original
  1. struct FichaPlana
  2. {
  3.     int id;
  4.     char nombre[MAX_LENGTH];
  5.     int infnum;
  6.     char abrinfo[MAX_ITEMS][MAX_LENGTH];
  7.     char info[MAX_ITEMS][MAX_LENGTH];
  8. };
  9.  
  10. for(int x=0;x<database.size();x++)
  11. {
  12.   FichaPlana plana;
  13.   plana.id = database[x].id;
  14.   strcpy(plana.nombre, database[x].nombre);
  15.   // ...
  16.   db.write((char*)&plana, sizeof(plana));
  17. }

Y algo equivalente en la lectura.

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #5 (permalink)  
Antiguo 14/06/2016, 04:31
 
Fecha de Ingreso: junio-2016
Mensajes: 3
Antigüedad: 7 años, 10 meses
Puntos: 0
Respuesta: Violación de segmento (`core' generado)

En primer lugar gracias por tu respuesta.

Ahora probaré a cambiar esos strings por arrays de caracteres. En cuanto al typedef, estoy estudiando Ing. Informática y me han dicho que así se pone en C++ en la asignatura de Programación, por eso lo había puesto.

Saludos y gracias de nuevo.
  #6 (permalink)  
Antiguo 14/06/2016, 05:38
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 6 meses
Puntos: 204
Respuesta: Violación de segmento (`core' generado)

Cita:
Iniciado por pguti Ver Mensaje
Ahora probaré a cambiar esos strings por arrays de caracteres. En cuanto al typedef, estoy estudiando Ing. Informática y me han dicho que así se pone en C++ en la asignatura de Programación, por eso lo había puesto.
Primero la explicación y luego la crítica.

typedef sirve para definir alias. ¿Para qué sirven los alias? Por un lado para facilitar la configuración del programa y por otro para conseguir código más legible.

En C es muy fácil entender el tema de la legibilidad:
Código C:
Ver original
  1. struct _mistruct
  2. {
  3.   ...
  4. };
  5.  
  6. typedef struct _mistruct mistruct;
  7.  
  8. // ¿Qué opción es más legible?
  9. struct _mistruct estructura;
  10. mistruct estructura;
  11.  
  12. // Ahora imagínatelo a la hora de declarar funciones
  13. void func( struct _mistruct* a, struct _otrastruct* b, struct _otramas *c);
  14. void func( mistruct* a, otrastruct* b, otramas *c);

¿Cómo es eso de facilitar la configuración de un programa?

Bueno, imagínate que tienes que hacer un programa que va a funcionar en ARM,Raspberry y "nosecuantas" otras arquitecturas. Imagino que no te agradaría la idea de hacer un programa específico para cada sistema y que prefieres reutilizar la mayor cantidad de código posible.

Si resulta que en una arquitectura el tipo de dato que has de usar para un determinado fin (por ejemplo por temas de rendimiento) es int y en otra arquitectura es short podrías optar por varios caminos, yo te muestro tres opciones:

1. Controlar el tipo con macros

Código C:
Ver original
  1. #ifdef _USAR_INT_
  2. int
  3. #else
  4. short
  5. #endif
  6. func()
  7. { return 4; }

Si está la macro _USAR_INT_ definida, entonces el código quedará tal que:

Código C:
Ver original
  1. int func()
  2. { return 4; }

mientras que si no lo está el programa compilará lo siguiente:

Código C:
Ver original
  1. short func()
  2. { return 4; }

2. Definir el tipo en una macro.
Código C:
Ver original
  1. #ifdef _USAR_INT_
  2. #define MITIPO int
  3. #else
  4. #define MITIPO short
  5. #endif
  6.  
  7. MITIPO func()
  8. { return 4; }

3. Definir un alias
Código C:
Ver original
  1. #ifdef _USAR_INT_
  2. typedef int mitipo
  3. #else
  4. typedef short mitipo
  5. #endif
  6.  
  7. mitipo func()
  8. { return 4; }

Las dos últimas opciones son bastante parecidas. ¿Qué sentido tiene entonces typedef si ya puedo conseguir lo mismo con directivas del preprocesador?

Bueno, resulta que typedef es bastante más potente que el preprocesador para estas cosas. Los mejores ejemplos se encuentran en los templates, donde muchas veces se hace necesario heredar el tipo para conseguir que el código sea compatible.

Código C++:
Ver original
  1. struct TipoInt
  2. {
  3.   typedef int tipo;
  4. };
  5.  
  6. struct TipoShort
  7. {
  8.   typedef short tipo;
  9. };
  10.  
  11. template<class T>
  12. struct mitemplate
  13. {
  14.   // aqui es necesario usar typename para que funcione el programa
  15.   // no es necesario que entiendas el motivo (paso a paso)
  16.   typedef typename T::tipo tipo;
  17.  
  18.   tipo func()
  19.   { return 4; }
  20. };
  21.  
  22. int main()
  23. {
  24.     mitemplate<TipoInt> t1;
  25.     mitemplate<TipoShort> t2;
  26.  
  27.     std::cout << sizeof(t1.func()) << std::endl;
  28.     std::cout << sizeof(t2.func()) << std::endl;
  29. }

Dicho esto queda claro que en C se usa typedef para no tener que escribir struct cada dos por tres, pero en C++ esto no es necesario, luego solo gente que se ha reciclado malamente de C a C++ seguirá usando el diseño que propone tu profesor.

Y bueno, ahora la crítica:

Seguramente tu profesor no tendrá tampoco ni idea de que en lo que llevamos de siglo han salido 3 estándares nuevos del lenguaje (C++03, C++11 y C++14) y que hay otros dos a punto de ver la luz (c++17 y C++20).

Es hasta posible que no entienda demasiado de templates, e incluso que se pierda al hablar de polimorfismo y herencia.

Ser profesor no le otorga a nadie un halo de inmortalidad o de superioridad. No es más que alguien que te intenta inculcar una serie de conocimientos y ya depende de la propia persona que dichos conocimientos sean más o menos fiables.

Yo te recomendaría buscar tutoriales de c++ por Internet y verás como lo que te cuento representa la forma normal de trabajar.

Si realmente te gusta la programación, que un profesor incompetente no te lleve por el mal camino. Una vez se han adquirido malos hábitos es complicado remontar el vuelo.

Una cosa es que en esa clase en cuestión tengas que pasar por el aro para aprobar y otra muy distinta es que seas consciente de que eso que haces no es lo correcto y que hay mucho mundo por recorrer fuera del contenido de las clases.

Un saludo
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.

Última edición por eferion; 14/06/2016 a las 06:52

Etiquetas: core
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 15:54.