1. Este site usa cookies. Ao continuar a usar este site está a concordar com o nosso uso de cookies. Saber Mais.

[Problema] Ler de ficheiro em C

Discussão em 'Programação' iniciada por Keith, 31 de Outubro de 2007. (Respostas: 19; Visualizações: 1757)

  1. Keith

    Keith Power Member

    Boas.

    Estou com um problema a ler de ficheiros alguns dados.
    Então é o seguinte: tenho um ficheiro com um índice e o nome de pessoas, desta forma:
    Código:
    10
    C01[tabulação]Nome 1
    C02[tabulação]Nome 2
    ...
    , copiando-os para uma struct com a forma:
    Código:
    typedef struct Candidatos
    {
    char ID[4];
    char NomeC[40];
    } Cands;

    A função que os passa do ficheiro é:
    Código:
    void ReadCands()
    {
       int i, NC;
       FILE *CFile;
     
       CFile = fopen(CSeries,"r");
       fscanf(CFile,"%d\n",&NC);
     
       for (i=0;i<NC;i++)
       {
          fgets(C[i].ID,4,CFile);
          fgets(C[i].NomeC,40,CFile);
       }
     
       fclose(CFile);
    }
    A primeira instrução do ciclo for recolhe correctamente a string 'C**'.
    A última instrução recolhe '[tabulação]Nome *\n'

    O que estou a fazer mal? Já tinha pensado em utilizar funções para remover o caracter inicial e o final que estão a mais, mas de certeza que há outra forma de o fazer.

    Alguém me pode ajudar?

    Keith
     
  2. Baderous

    Baderous Banido

    Aquele \n não pode estar ali.
     
  3. Keith

    Keith Power Member

    Mesmo assim, o problema não me parece ser ali.
     
  4. Baderous

    Baderous Banido

    EDIT: Esquece, acho que me enganei.
     
    Última edição: 31 de Outubro de 2007
  5. AragTey

    AragTey Power Member

    Boas, porque não lês linha a linha e usas o sscanf:

    Código:
      for (i=0;i<NC;i++)
      {
        char str[250];
        fgets(xstr , 250 , CFile); // 250 tamanho por deafult
        sscanf(xstr, "%s\t%s", &C[i].ID, &C[i].NomeC);
       }
    
     
  6. Keith

    Keith Power Member

    Obrigado, mas esta função apresenta um problema...

    O problema desta função é que ao ler a segunda parte da linha (correspondente ao nome), pára assim que encontrar o 1º espaço. Por exemplo a linha:

    Código:
    C02    Nome Apelido
    iria resultar as strings:
    - C.ID = "C02"
    - C.NomeC = "Nome"

    e deixa "Apelido" de fora.

    Já tentei umas modificações, mas ainda não consegui nada de apresentável.

    Obrigado,
    Keith
     
  7. good_in_bed

    good_in_bed Power Member

    Sinceramente do que tenho feito a programar em C costumo fazer assim...fazes um gets e depois percorres e vais tirando o que interessa...
    Mas tenta dar uma olhadela na biblioteca string.h que és capaz de arranjar alguma coisa que te ajude...
     
  8. Tyran

    Tyran Power Member



    Tenta usar o código do Aragtey com mais um %s
    cumpzz
     
  9. macacao

    macacao Power Member

    Não testei, mas penso que algo deste género deve dar:

    Código:
    for (i=0;i<NC;i++)
      {
        char str[250];
        char Nome_temp[100];
        char Apelido_temp[100];
        char Nome_Completo_temp[250];
        fgets(xstr , 250 , CFile);
        sscanf(xstr, "%s\t%s %s", &C[i].ID, &Nome_temp, &Apelido_temp);
        Nome_temp = strcat(Nome_temp, " "); //Concatenar nome com espaço
        Nome_completo_temp = strcat(Nome_temp, Apelido_temp); //Concatenar nome com apelido
        strcpy(C[i].NomeC, Nome_Completo_temp);
      }
    
     
  10. Keith

    Keith Power Member

    Agradeço as vossas ajudas, mas penso que vocês estão a resolver este problema para uma determinada situação, que é o nome ter apenas um apelido.
    Existe alguma função em C ou C++ que possa remover os n caracteres iniciais de uma string?
    Isso resolveria o problema.

    Obrigado,
    Keith
     
  11. Consu

    Consu Power Member

    Como falaste em C++, fiz o que acho que pretendias da seguinte forma:

    Código:
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <cctype>
    
    using namespace std;
    
    typedef struct Candidato {
        string id;
        string nomeC;
    } Candidato;
    
    void ReadCand( Candidato* cand, ifstream &fin ) {
        int dec;
        
        fin >> cand->id;
        getline( fin, cand->nomeC );
        
        // Verifica se é necessário remover o último caracter
        dec = ( isalpha( cand->nomeC[(cand->nomeC).size()-1] ) ? 0 : 1 );
        cand->nomeC = (cand->nomeC).substr( 1, (cand->nomeC).size()-dec-1 );
        
        cout << "Candidato: " << cand->id << " -> " << cand->nomeC << endl;
    }
    
    int main() {
        int nc;
        Candidato* candidatos;
        ifstream fin( "file.txt" ); 
        
        if( !fin ) {
            cout << "Não foi possível abrir o ficheiro 'file.txt'" << endl;
            return -1;
        }
        
        fin >> nc;
        
        candidatos = new Candidato[nc];
        for( int i = 0; i < nc; ++i )
            ReadCand( &candidatos[i], fin );
        
        fin.close();
        delete[] candidatos;
        
        return 0;
    }
    
    Fiz uso de strings de C++, embora seja perfeitamente possível fazer em C...
    Considerei que não existem caracteres em branco depois do nome, mas se isso acontecer é só introduzir uma pequena alteração para verificar quantos espaços tem a mais.
     
  12. Keith

    Keith Power Member

    Eu tenho estado a ler uns artigos na net em C++, mas não encontro nada parecido com isso.
    Aliás, tenho estado a tentar fazê-lo em C++, mas quando tento ler a 1ª linha do ficheiro, ele devolve um número enorme e negativo (provavelmente um endereço de memória).

    Nem isto consigo fazer....
     
  13. Consu

    Consu Power Member

    Escrevi e testei esse código e não tive problemas. Será que não tens nenhum caracter especial no meio? Porque se forem espaços ele ignora.
     
  14. Keith

    Keith Power Member

    Já consegui fazer aquilo que queria, mas tem uma pequena batota, que ainda não consegui resolver...

    Código:
    typedef struct Candidatos
    {
       string ID;
       string Nome;
    } Cast;
    
    
    
    void AC_ReadCand()
    {
    int NC, i=0;
    string str;
    ifstream CSeries;
    
       CSeries.open (CDoc, ios::in);
       CSeries >> NC;
       Cast Candids[NC+1];
    
       for (i=0;i<NC+1;i++)
       {
          getline(CSeries,str);
          if (i > 0) { Candids[i].ID = str.substr(0,4);
                       Candids[i].Nome = str.erase(0,5); }
       }
       
       CSeries.close();
       return;
    }
    O problema é que não consigo evitar a leitura da primeira linha do ficheiro (que contém o número de candidatos do ficheiro). Portanto tive de acrescenter +1 posição à estrutura Candids.

    O que posso fazer aqui?
    Perdoem-me todas estas perguntas, mas comecei apenas ontem a aprender C++.
     
    Última edição: 2 de Novembro de 2007
  15. Consu

    Consu Power Member

    Da forma que indiquei não tens esse problema. O que se passa é que o getline lê até encontrar o caracter '\n'. Neste caso, como lês o número de candidatos, o caracter de mudança de linha continua lá. Assim sendo, quando usas pela primeira vez essa função ele vai ler basicamente os espaços e o '\n'.
     
  16. Keith

    Keith Power Member

    OK.
    Desde o meu último post, fiz algumas alterações ao meu código. Deixo-vos aqui:

    Código:
    typedef struct PeopleInfo
    {
       string ID;
       string Nome;
       int NVotos;
    } PInfo;
    
    int NC;
    
    [...]
    
    int main()
    {
    int i;
    string str;
    ifstream InfoFile;
    
    
       InfoFile.open (InfoDoc, ios::in);
       InfoFile >> NC;
       PInfo Candids[NC];
       getline(InfoFile,str);
    
       for (i=0;i<NC;i++)
       {  getline (InfoFile,str);
          Candids[i].ID = str.substr(0,4);
          Candids[i].Nome = str.erase(0,5); }
    
    [...]
    
    
    Neste pedaço de código, gostaria que me ajudassem com uma coisa. Eu já estou farto de procurar e provavelmente estive a procurar termos incorrectos para aquilo que pretendo.

    Ora então, se reparerem no código da função main(), depois de ler um valor inteiro que estava no ficheiro, guardei-o na variavel NC e de seguida criei um array de structs do tipo PInfo. Mas o que eu queria realmente, era que esse array fosse global. Mas como o seu tamanho está dependente do valor que é lido no ficheiro, o seu tamanho deve resultar de uma alocação de memória correspondente ao valor de NC.

    De facto, este código encontra-se na função main(), mas eu pretendo que ele fique numa função auxiliar, de modo a que o código fique mais organizado.
    Eu já encontrei informações relativas a funções de C++, como por exemplo a new, resize, etc., mas não sei o que fazer.

    Podem-me ajudar?

    Obrigado,
    Keith
     
  17. Consu

    Consu Power Member

    Usar o operador new é bastante simples:
    Código:
    #include <iostream>
    
    using namespace std;
    int *ptr;
    
    int main() {
        int nc;
    
        cin >> nc;
        ptr = new int[nc]; [COLOR=DarkGreen]// Alocação Dinâmica[/COLOR]
    
        delete[] ptr; [COLOR=DarkGreen]// Libertar a memória alocada[/COLOR]
        ptr = NULL;  [COLOR=DarkGreen]// Apenas para evitar erros
    [/COLOR]
        return 0;
    }
    
     
  18. Keith

    Keith Power Member

    Usaste o tipo int apenas para um caso genérico, certo?

    É que é a struct Candids que eu quero alocar, mais nada...

    Obrigado,
    Keith
     
  19. Consu

    Consu Power Member

    Exacto. Onde está a int pode estar qualquer tipo de dados. Aproveito para deixar aqui também no caso de não ser apenas um array e ser um elemento:

    Código:
    double *d;
    
    d = new double;
    
    delete d;
    
     
  20. Keith

    Keith Power Member

    OK. Já funciona tal como queria.

    Muito obrigado, Consu.


    Por favor, não encerrem ainda a thread, pois podem surgir ainda algumas dúvidas, e assim aproveito e coloco-as aqui.

    Obrigado mais uma vez,
    Keith
     

Partilhar esta Página