[Solucionado]Imposible mostrar texto de un txt en C -

Iniciado por Arturo400, 25 Septiembre 2016, 00:10 AM

0 Miembros y 1 Visitante están viendo este tema.

Arturo400

Hola

Tengo un programa en el cual tengo que crear un nuevo tipo de dato struct en el cual voy a tener 3 variables, una que es el documento de la persona, la otra es el nombre de la persona y por ultimo la nacionalidad de la persona.

Al principio lo que tengo que hacer es cargar manualmente el nuevo tipo de dato, la carga va a finalizar cuando el documento sea igual a 0.

Luego va a pasar todo lo cargado a un archivo txt. (Hasta aca, va perfecto todo ;-))

El problema surge cuando tengo que leer el archivo e imprimir el contenido . Lo que sucede es que cuando pongo while(!feof(fd)) la lectura del archivo no termina nunca, siempre me arroja los mismos valores, nunca termina el ciclo y ademas nunca me carga la nacionalidad.

El archivo se va a cargar de la siguiente manera.

38747443,Agustin,Argentina

Es decir que en cada linea del archivo txt voy a tener ese tipo de secuencia.

Este es el codigo que hice

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#define N 5

struct s_datos
{
   int doc;
   char nombre[50];
   char pais[50];

};
typedef struct s_datos dato;

int CARGA(dato charge[N]);
void CREACION(dato charge[N],int);
void IMPRESION();

int main()
{
   int i=0,j=0;
   dato charge[N];
   i=CARGA(charge);  /// i es la cantidad de personas que tengo.
   printf("\nEl valor de i es %d",i);
   for (j=0;j<i;j++)
   {
       printf("\n%d",charge[j].doc);
       printf("\n%s",charge[j].nombre);
       printf("\n%s",charge[j].pais);
   }
CREACION(charge,i);  ///Llamo a la funcion para crear un txt y le paso el nuevo dato struct y la cantidad de personas ingreadas.
printf("\n");
IMPRESION();



   return 0;
}

int CARGA(dato charge[N])
{
  int i=0,j=0,e=0;
  char letra='a';
  charge[i].doc=4;
  while (i<N)
  {
      printf("\nIngrese el numero de documento: ");
      scanf("%d",&charge[i].doc);
          if (charge[i].doc!=0)
          {
              printf("\nIngrese el nombre: ");

                  while(letra!='\r')
                  {
                     letra=getche();
                     charge[i].nombre[j]=letra;
                     j++;
                  }
                  charge[i].nombre[j]='\0';
              j=0;
              letra='a';

              printf("\nIngrese el pais: ");

                  while(letra!='\r')
                  {
                     letra=getche();
                     charge[i].pais[e]=letra;
                     e++;
                  }
                  charge[i].pais[e]='\0';
                  e=0;
              letra='a';
              i++;
          }
      if(charge[i].doc==0)
      {
          return i;
      }
  }
  return i;

}

void CREACION(dato charge[N],int i)
{
   FILE*arch;
   arch=fopen("C:\\Users\\Pablo-PC\\Desktop\\personas.txt","w");
   int j=0;
   while(j<i)
   {
       fprintf(arch,"%d,%s,%s\n",charge[j].doc,charge[j].nombre,charge[j].pais);
       j++;
   }
   fclose(arch);
}

void IMPRESION()
{
   FILE*fd;

   int doc,i=0;
   char nombre[50]={0},pais[50]={0};

   fd=fopen("C:\\Users\\Pablo-PC\\Desktop\\personas.txt","r");

   printf("Documento\tNombre\tPais\n");
   fscanf(fd,"%d,%s,%s\n",&doc,&nombre,&pais);
   while(!feof(fd) && i<4)
   {
       printf("%d\t%s\t%s\n",doc,nombre,pais);
       fscanf(fd,"%d,%s,%s\n",&doc,&nombre,&pais);
       i++;
   }
   fclose(fd);
}



La funcion que funciona mal es IMPRESION y no le veo defecto alguno.

dato000

Reemplaza la función IMPRESION con lo siguiente:


FILE *fd;

    int documento;
    char nombre[50],pais[50];

    fd=fopen("C:\\Users\\Pablo-PC\\Desktop\\personas.txt","r");

    printf("Documento\tNombre\tPais\n");

    while(fscanf(fd,"%d %s %s\n",&documento, &nombre, &pais) == 3)
    {
        printf("%d\t\t%s\t%s\n",documento,nombre,pais);
    }
    fclose(fd);


Al parecer el problema de que no leyera todas las columnas era las comas en el fscanf, las cuales no deben ser utilizadas en un procedimiento de lectura o input pues provocaria volcamiento de memoria.

Y respecto a que solo quedaba en una sola linea dentro del while, es que no se que carajos era ese tipo de ciclo, solo era mandarle el archivo, y en estos casos, el mismo ciclo sabe cuando ha terminado el mismo, por lo que solo es necesario determinarle que tipo de parametros leer, y en que orden imprimirlos.

Fuente:

http://stackoverflow.com/questions/14199155/reading-in-c-using-fscanf-multiple-values



Arturo400

Hola

Pero en ese caso me imprimiria con las comas incluidas en cada columna, como hago para que no me tome las comas?.

dato000

Cita de: Arturo400 en 25 Septiembre 2016, 03:44 AM
Hola

Pero en ese caso me imprimiria con las comas incluidas en cada columna, como hago para que no me tome las comas?.

Una forma seria simplemente borrar las comas en el archivo.

Otra forma seria validar caracter por caracter que solo se imprima con la condición que NO sea un caracter coma.



MAFUS

Muy buenas. Para solucionar tu problema con las comas puedes hacer uso de una funcionalidad un poco más avanzada de fscanf. Impresión queda así:
void IMPRESION()
{
    FILE*fd;

    int doc,i=0;
    char nombre[50]={0},pais[50]={0};

    fd=fopen("C:\\Users\\Pablo-PC\\Desktop\\personas.txt","r");

    printf("Documento\tNombre\tPais\n");
    fscanf(fd,"%d,%[^,],%[^\n]",&doc,nombre,pais);
    while(!feof(fd) && i<N)
    {
        printf("%d,%s,%s\n",doc,nombre,pais);
        fscanf(fd,"%d,%[^,],%[^\n]",&doc,nombre,pais);
        i++;
    }
    fclose(fd);
}


La cadenade control de fscanf ha cambiado un poco.
Tu idea de usar comas separadoras está bien, pues es el mismo formato que scanf va a recibir y va a desechar esas comas. El problema venía que recogías tanto nombre como país con el argumento %s que coge toda la cadena hasta que haya un espacio en blanco (tabulación, nueva línea, etc.) por lo que también te pillaba la coma.
Sin embargo haciendo uso de %[^,] le dices a fscanf: guarda la cadena hasta que encuentres el caracter coma (los corchetes indican los caracteres que debe recoger fscanf, el acento circunflejo al principio indica negación, es decir, que se debe recoger todos los caracteres hasta encontrar uno de esa lista). Así que capturarás toda la cadena hasta que llegues a la coma.
Después te encuentras la coma que vas a desechar y empieza otra captura de cadena hasta que llegue al final de ésta, el caracter de nueva línea, como marca %[^\n].

Arturo400

Cita de: MAFUS en 25 Septiembre 2016, 20:15 PM
Muy buenas. Para solucionar tu problema con las comas puedes hacer uso de una funcionalidad un poco más avanzada de fscanf. Impresión queda así:
void IMPRESION()
{
    FILE*fd;

    int doc,i=0;
    char nombre[50]={0},pais[50]={0};

    fd=fopen("C:\\Users\\Pablo-PC\\Desktop\\personas.txt","r");

    printf("Documento\tNombre\tPais\n");
    fscanf(fd,"%d,%[^,],%[^\n]",&doc,nombre,pais);
    while(!feof(fd) && i<N)
    {
        printf("%d,%s,%s\n",doc,nombre,pais);
        fscanf(fd,"%d,%[^,],%[^\n]",&doc,nombre,pais);
        i++;
    }
    fclose(fd);
}


La cadenade control de fscanf ha cambiado un poco.
Tu idea de usar comas separadoras está bien, pues es el mismo formato que scanf va a recibir y va a desechar esas comas. El problema venía que recogías tanto nombre como país con el argumento %s que coge toda la cadena hasta que haya un espacio en blanco (tabulación, nueva línea, etc.) por lo que también te pillaba la coma.
Sin embargo haciendo uso de %[^,] le dices a fscanf: guarda la cadena hasta que encuentres el caracter coma (los corchetes indican los caracteres que debe recoger fscanf, el acento circunflejo al principio indica negación, es decir, que se debe recoger todos los caracteres hasta encontrar uno de esa lista). Así que capturarás toda la cadena hasta que llegues a la coma.
Después te encuentras la coma que vas a desechar y empieza otra captura de cadena hasta que llegue al final de ésta, el caracter de nueva línea, como marca %[^\n].

Wow, no sabia que se podia hacer eso!. Ahora si lee todo. Te hago una ultima consulta. Como puedo hacer para que me quede la impresion de manera ordenada?.
Porque supongamos que los datos del txt son asi:

39581882,agustin,francia
39149112,Ricardo Lopez,Argentina
41959129,Agustin,Grecia.

Entonces cuando quiero imprimir me queda un poco descordinado la parte de paises y nombres y no me queda del todo prolijo, con los \t no lo pude solucionar

MAFUS

Al igual que scanf, printf tiene su técnica avanzada para formatear el texto.
Verás:
%s sabes que escribe una cadena.
%Ns siendo N un número entero constante hace que la cadena tenga como mínimo N caracteres y se alinee por la derecha. Si la cadena es más corta de lo que marca N los caracteres que faltan se rellenan con espacios.

%-Ns siendo N un número entero constante hace que la cadena tenga como mínimo N caracteres y se alinee por la izquierda. Si la cadena es más corta de lo que marca N los caracteres que faltan se rellenan con espacios.

%.Ms siendo M un número entero constante hace que se tomen de la cadena los M primero caracteres a escribir descartando los demás.

Por supuesto las dos formas se pueden mezclar:
%N.Ms
%-N.Ms

Ejemplos serían:
%5s
%-5s
%10.6s
%-10.6s

scanf y printf tienen aún muchas más opciones avanzadas. Te animo a que busques por internet su documentación y juegues con estas dos funciones. Puedes llegar a hacer muchas cosas con ellas.

Para que juegues con printf y después lo apliques en tu programa te dejo un ejemplo muy sencillo:
#include <stdio.h>

int main() {
    printf("|%15.5s|", "Mi_cadena");
   
    return 0;
}