[Problema] Ler de ficheiro em C

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
 
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);
   }
 
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
 
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.

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...
 
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


Tenta usar o código do Aragtey com mais um %s
cumpzz
 
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);
  }
 
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
 
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.
 
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....
 
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.
 
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:
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'.
 
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
 
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;
}
 
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;
 
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
 
Back
Topo