/
Inicio :: Foros

 F.A.Q.F.A.Q.                  Conéctese para revisar sus mensajesConéctese para revisar sus mensajes   

Punteros char y archivos

 
      Índice del Foro elrincondelc.com -> Principiantes C/C++
Ver tema anterior :: Ver siguiente tema  
AutorMensaje
Neodivert



Registrado: 20 Ago 2004
Mensajes: 60

MensajePublicado: 31/08/2007 4:53 am
Título: Punteros char y archivos

Lenguaje: C++
Compilador: Dev-C++


Buenas, estaba haciendo un programa para hacer cuestionarios tipo test y otro para leerlos, y al leerlos y ver las preguntas siempre se cortaban a la mitad y con caracteres extraños. Intente hacer una prueba con un programa pequeño.


Si lo hago con cadenas "normales" funciona perfectamente:

Escribe.cpp
Código:
#include<cstring>
#include<fstream>
#include<iostream>
using namespace std;


int main(){
    char Pregunta[10][31];
   
    for(int i=0; i<10; i++){
            strcpy(Pregunta[i], "HOLA CAPULLO");
    }
   
    ofstream Archivo( "Archivo.tc", ios::binary );
   
    for(int i=0; i<10; i++){
            Archivo.write( Pregunta[i], sizeof(Pregunta[i]) );
            Archivo.clear();
    }
   
    Archivo.clear();
    Archivo.close();
   
}


Lee.cpp
Código:
#include<cstring>
#include<fstream>
#include<iostream>
using namespace std;


int main(){
    char Pregunta[10][31];
   
   
    ifstream Archivo( "Archivo.tc", ios::binary );
   
    for(int i=0; i<10; i++){
            Archivo.clear();
            Archivo.read( Pregunta[i], sizeof(Pregunta[i]) );
            cout << "Pregunta[" << i << "]: " << Pregunta[i] << endl;
    }
   
    Archivo.clear();
    Archivo.close();
   
   
   
    cin.get();
}


De esta forma los lee perfectamente, pero a la hora de hacerlo con punteros y reservando memoria para las cadenas, parece que los escribe bien pero luego al leer arroja otros resultados.

Escribe.cpp

Código:

#include<cstring>
#include<fstream>
#include<iostream>
using namespace std;


int main(){
    char **Pregunta = new char *[10];
   
    for(int i=0; i<10; i++){
            Pregunta[i] = new char [31];
            strcpy(Pregunta[i], "HOLA CAPULLO");
    }
   
    ofstream Archivo( "Archivo.tc", ios::binary );
   
    for(int i=0; i<10; i++){
            Archivo.write( Pregunta[i], sizeof(Pregunta[i]) );
            Archivo.clear();
    }
   
    Archivo.clear();
    Archivo.close();
   
    for(int i=0; i<10; i++) delete Pregunta[i];
    delete Pregunta;
   
}


Lee.cpp
Código:
#include<cstring>
#include<fstream>
#include<iostream>
using namespace std;


int main(){
    char **Pregunta = new char *[10];
   
   
    ifstream Archivo( "Archivo.tc", ios::binary );
   
    for(int i=0; i<10; i++){
            Pregunta[i] = new char [31];
            Archivo.clear();           
            Archivo.read( Pregunta[i], sizeof(Pregunta[i]) );
            cout << "Pregunta[" << i << "]: " << Pregunta[i] << endl;
    }
   
    Archivo.clear();
    Archivo.close();
   
    for(int i=0; i<10; i++) delete Pregunta[i];
    delete Pregunta;
   
    cin.get();
}


Los resultados son más o menos así:

Código:
HOLAX(Carita sonriente)=
HOLAX(Carita sonriente)=
HOLAX(Carita sonriente)=
HOLAX(Carita sonriente)=
HOLAP(Figurita)=
HOLAH(Figurita)=
HOLA (Figurita)=


Y no entiendo por que puede ser. ¿No se supone que al guardar el puntero guardo toda la cadena por la equivalencia puntero = array?
:S


P.D. Ésto no tiene nada que ver con el problema del post, pero en el mismo Dev-C++ puedo usar las funciones de la libreria "cstring" sin linkearla y no me dice nada (Aunque siempre la pongo por si acaso), ¿es algo que tengo que configurar en alguna parte?
Volver arriba
rir3760



Registrado: 01 Oct 2004
Mensajes: 3657
Ubicación: Mexico

MensajePublicado: 31/08/2007 7:22 am
Título: Re: Punteros char y archivos

Neodivert escribió:
pero a la hora de hacerlo con punteros y reservando memoria para las cadenas, parece que los escribe bien pero luego al leer arroja otros resultados.

El problema es la forma en que manejas el operador sizeof, este devuelve el tamaño en caracteres de un objeto, en el caso de un array no hay problema pero si, como es el caso con tu programa, intentas utilizarlo con un puntero te devolvera el tamaño del objeto (en este caso el puntero) sin importar a donde apunte este.

Neodivert escribió:
P.D. Ésto no tiene nada que ver con el problema del post, pero en el mismo Dev-C++ puedo usar las funciones de la libreria "cstring" sin linkearla y no me dice nada (Aunque siempre la pongo por si acaso), ¿es algo que tengo que configurar en alguna parte?

La vinculacion depende del compilador que se utilize, por ejemplo en el caso de GCC este requiere que la biblioteca math (C estandar) se vincule explicitamente mediante una opcion de linea de comandos.

Un saludo
_________________
The capacity to learn is a gift;
The ability to learn is a skill;
The willingness to learn is a choice.
--
Rebec of Ginaz
Volver arriba
Neodivert



Registrado: 20 Ago 2004
Mensajes: 60

MensajePublicado: 31/08/2007 8:02 am
Título:

Muchas gracias Wink Very Happy

Por cierto, odio que mi respuesta sea también una "mini-pregunta", pero es solo para asegurarme de que en el futuro lo hago bien.

He sustituido el sizeof en el write y el read de esta forma y ya funciona todo bien.

Código:
Archivo.read( Pregunta[i], sizeof(Pregunta[i])/4*31);


El sizeof para un char * me devuelve 4, pero lo que yo quiero guardar es la cadena, no el puntero, por eso la división, para dejarlo al tamaño de un char (1) y ya lo multiplico por el tamaño de la cadena.

La pregunta es... ¿Está bien hecho así, o debo sumarle 4 para el puntero?
Embarassed
Volver arriba
rir3760



Registrado: 01 Oct 2004
Mensajes: 3657
Ubicación: Mexico

MensajePublicado: 31/08/2007 6:34 pm
Título:

Respuesta corta: si estas aprendiendo C++ utiliza las caracteristicas que este ofrece como las clases string y vector.

Respuesta larga: el tamaño del puntero no importa, en realidad si utilizas un valor fijo (un "magic number") como 4 tu programa no funcionaria correctamente en sistemas donde el tamaño de un "char *" es menor.

Y si lo piensas un poco no es necesario incluir una division cuyo resultado sea uno ya que toda multiplicacion por ese numero arroja como resultado ...

Un saludo
_________________
The capacity to learn is a gift;
The ability to learn is a skill;
The willingness to learn is a choice.
--
Rebec of Ginaz
Volver arriba
Neodivert



Registrado: 20 Ago 2004
Mensajes: 60

MensajePublicado: 02/09/2007 3:31 am
Título:

rir3760 escribió:
Respuesta corta: si estas aprendiendo C++ utiliza las caracteristicas que este ofrece como las clases string y vector.

Respuesta larga: el tamaño del puntero no importa, en realidad si utilizas un valor fijo (un "magic number") como 4 tu programa no funcionaria correctamente en sistemas donde el tamaño de un "char *" es menor.

Y si lo piensas un poco no es necesario incluir una division cuyo resultado sea uno ya que toda multiplicacion por ese numero arroja como resultado ...

Un saludo


owned! Embarassed

Entonces usaré.
Código:
Archivo.read( Pregunta[i], sizeof(char)*31 );



Estudiaré mejor la clase string para mis próximos programas, aunque (Y esto es un poco pijada xD ), he estado viendo que no se puede definir de un tamaño concreto sin tener que declararlo, tipo

Código:
string Cadena(30);


sino

Código:
string Cadena(30, '\000');


xD Bueno, lo dicho, muchas gracias rir3760, salvador de los novatos. Wink Razz
Volver arriba
rir3760



Registrado: 01 Oct 2004
Mensajes: 3657
Ubicación: Mexico

MensajePublicado: 05/09/2007 9:46 am
Título:

Neodivert escribió:
Entonces usaré.
Código:
Archivo.read( Pregunta[i], sizeof(char)*31 );

Tanto en C como en C++ el resultado de sizeof(char) siempre es uno asi que puedes reducir esa sentencia a:
Código:
Archivo.read( Pregunta[i], 31);

Como te comente antes utilizar "magic numbers" como 31 no es una buena idea, en C++ lo apropiado es declarar constantes utilizando la palabra reservada const.

Neodivert escribió:
Estudiaré mejor la clase string para mis próximos programas, aunque (Y esto es un poco pijada xD ), he estado viendo que no se puede definir de un tamaño concreto sin tener que declararlo, tipo

Código:
string Cadena(30);


sino

Código:
string Cadena(30, '\000');

No te entiendo muy bien, el objeto de tipo string lo puedes declarar sin indicar el tamaño y su contenido:
Código:
std::string Cadena;

Y a partir de ese momento te olvidas de ciertas tareas engorrosas que uno debe tener siempre en cuenta en C como es la capacidad del bloque y tener (mediante realloc) que reajustarlo cuando sea necesario.

Un saludo
_________________
The capacity to learn is a gift;
The ability to learn is a skill;
The willingness to learn is a choice.
--
Rebec of Ginaz
Volver arriba
      Índice del Foro elrincondelc.com -> Principiantes C/C++
Página 1 de 1Todas las horas están en GMT - 8 Horas

 
No puede crear mensajes
No puede responder temas
No puede editar sus mensajes
No puede borrar sus mensajes
No puede votar en encuestas

(c) ElRincondelC.com

Un proyecto de UrlanHeat.com