• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

Ziwdon

Trabalho Final: Gestao de Viaturas numa Auto-Estrada

20 mensagens neste tópico

Boas...cá estou mais uma vez.

É o seguinte...tenho de fazer um programa final para a cadeira de C, e o objectivo é fazer um sistema de gestão de viaturas para uma auto-estrada.

Decidi criar um tópico geral para ir postando duvidas/dificuldades que surgam, para não estar sempre a criar novos tópicos.

Neste momento o meu problema é a leitura de dados. Os carros que passam na auto-estrada são lidos através de um ficheiro de dados com a seguinte estrutura:

CÓDIGO RETIRADO!

Nota: "_clean();" e "_pause();" são funções que limpam o ecrâ e esperam por uma tecla respectivamente.

EDIT: Código Actualizado! Ainda assim não está bem. Quando faço o printf para mostrar as informações do carro (ID, classe...), sai tudo marado, com ints negativos e nao sei que...

Questões:

- Quando lemos dados de um ficheiro binário, os dados são "convertidos para linguagem humana" certo? Não permanecem como 0's e 1's pois não?

- Uma vez que o ficheiro contêm inteiros e caracteres, não sei como fazer para guardar os dados. Mas se o ficheiro é binário entao isto nao seria necessário certo? É mesmo necessário guardar os dados, uma vez que estes ficam em memória após o "open"?

- O meu objectivo é organizar os dados por estructuras mas isto do binário confunde-me e não sei como o fazer.

Conclusão: A minha dificuldade está em ler e manipular a informação a partir de um ficheiro binário.

P.S.

Se quiserem mais informações sobre o trabalho podem ver aqui:

- Enunciado (PDF)

- Pacote de dados (ZIP)

- Ficheiros alternativos para manipular ficheiros binários (ZIP)

Agradeço a vossa ajuda

Cumprimentos

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

- Quando lemos dados de um ficheiro binário, os dados são "convertidos para linguagem humana" certo? Não permanecem como 0's e 1's pois não?

Ora... como responder a isto...? Num computador, TUDO são dados binários, ou zeros e uns. O computador é que os interpreta de maneira a ser-nos (humanos) mais fácil ler esses dados. Deves saber que 1101000 em binário é 104 em decimal, certo? Se interpretares isso como um código ASCII, vais obter o caracter 'h'. É só isto que o computador faz.

- Uma vez que o ficheiro contêm inteiros e caracteres, não sei como fazer para guardar os dados. Mas se o ficheiro é binário entao isto nao seria necessário certo? É mesmo necessário guardar os dados, uma vez que estes ficam em memória após o "open"?

No que toca aos ficheiros propriamente ditos, não há ficheiros "não binários". Os ficheiros são todos armazenados como conjuntos de bits (organizados em bytes). Quando são lidos, a interpretação é que muda. Quando escreves num ficheiro de texto, as funções de escrita convertem o '\n' para o formato adequado a cada sistema operativo.

Quanto à parte de ficarem em memória, não sei se percebi muito bem, mas quando terminas o programa tudo o que está em memória vai ao ar.

- O meu objectivo é organizar os dados por estructuras mas isto do binário confunde-me e não sei como o fazer.

Se vais armazenar estruturas de dados num ficheiro, o mais acertado é utilizar o modo binário. Isto porque para guardar uma estrutura (que não contenha apontadores) num ficheiro é tão simples quanto fazer

fwrite(&estrutura, sizeof(ESTRUTURA), 1, ficheiro);

e para ler

fread(&estrutura, sizeof(ESTRUTURA), 1, ficheiro);

onde ESTRUTURA é o typedef da struct, e estrutura é uma "instância" de ESTRUTURA.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Antes de mais obrigado por responderes TheDark. :D

Ora... como responder a isto...? Num computador, TUDO são dados binários, ou zeros e uns. O computador é que os interpreta de maneira a ser-nos (humanos) mais fácil ler esses dados. Deves saber que 1101000 em binário é 104 em decimal, certo? Se interpretares isso como um código ASCII, vais obter o caracter 'h'. É só isto que o computador faz.

O que eu quis dizer, é que se estivermos a ler de um ficheiro .txt, é diferente de estarmos a ler de um ficheiro .dat. A minha dúvida era se ao lermos um ficheiro .dat em binário, se o conteúdo é ou não automaticamente traduzido para código ASCII. É que assim o tratamento dos dados seria diferente certo?

Por exemplo...um ficheiro que contenha uma linha com "1101000". Se eu ler essa linha, puser numa var, e fizer um printf, o que é que me aparece no ecrâ? Aparece  "1101000" ou "h"? Essa era a minha questão :D

No que toca aos ficheiros propriamente ditos, não há ficheiros "não binários". Os ficheiros são todos armazenados como conjuntos de bits (organizados em bytes). Quando são lidos, a interpretação é que muda. Quando escreves num ficheiro de texto, as funções de escrita convertem o '\n' para o formato adequado a cada sistema operativo.

Quanto à parte de ficarem em memória, não sei se percebi muito bem, mas quando terminas o programa tudo o que está em memória vai ao ar.

A minha questão era se eu tinha acesso ao conteúdo lido, apenas através do "fopen" (na memória) ou se era necessário fazer um "fread" (para uma var/estructura). Mas pelo que percebi tenho de meter a informação numa "struct".

Se vais armazenar estruturas de dados num ficheiro, o mais acertado é utilizar o modo binário. Isto porque para guardar uma estrutura (que não contenha apontadores) num ficheiro é tão simples quanto fazer

fwrite(&estrutura, sizeof(ESTRUTURA), 1, ficheiro);

e para ler

fread(&estrutura, sizeof(ESTRUTURA), 1, ficheiro);

onde ESTRUTURA é o typedef da struct, e estrutura é uma "instância" de ESTRUTURA.

Isso é o que eu ando a tentar fazer, mas sem sucesso.

//ESTRUTURA
struct Carro {
int ID;
int classe;
int port_in;
int port_out;
char port_in_time[TIME_LENGHT];
char port_out_time[TIME_LENGHT];
};

struct Carro carro; //"instância"

for (n=0; n<nt; n++) {
fread(&carro, sizeof(carro), 1, fp); //LÊ DADOS
printf("\n\nID: %d \n Classe: %d \n Entrada: %d \n Saída: %d \n Hora de entrada: %s \n Hora de Saída: %s", carro.ID, carro.classe, carro.port_in, carro.port_out, carro.port_in_time, carro.port_out_time);
getchar();
}

Esse é o código que tenho. O que é que acontece? Ele lê linha a linha e mete na estructura no devido lugar (ID, classe...) certo? Então e o separador ou lá o que é? É que o ficheiro antes de apresentar os dados de cada carro tem um "1" antes...excepto no final que tem "0".

1 -> SEPARADOR
123456 -> IDENTIFICADOR VIA VERDE
2 -> CLASSE DA VIATURA
1 -> PORTAGEM DE ENTRADA
2 -> PORTAGEM DE SAÍDA
19h  3m 23s -> HORA DE ENTRADA
19h 41m 52s -> HORA DE SAÍDA

Ou seja...ele deveria ler a 1ª linha e colocá-la em carro.ID, a 2ª linha e colocá-la em carro.classe...e por ai. Certo?

Contudo, quando faço o printf com os dados que estou a meter na estructura aparecem-me números enormes e por vezes negativos (tudo marado ^^).

Isto porque para guardar uma estrutura (que não contenha apontadores) num ficheiro é tão simples quanto fazer

O que queres dizer com isso de não conter apontadores?

E já agora mais uma questão:

- Qual a diferença entre:

typedef struct ESTRUCTURA{
   int algo;
} TYPEDEF_ESTRUCTURA;

e

struct ESTRUCTURA{
   int algo;
};

Obrigado...e desculpem a extensão do post :P

Cumps

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Antes de mais obrigado por responderes TheDark. :D

De nada :D

O que eu quis dizer, é que se estivermos a ler de um ficheiro .txt, é diferente de estarmos a ler de um ficheiro .dat. A minha dúvida era se ao lermos um ficheiro .dat em binário, se o conteúdo é ou não automaticamente traduzido para código ASCII. É que assim o tratamento dos dados seria diferente certo?

Por exemplo...um ficheiro que contenha uma linha com "1101000". Se eu ler essa linha, puser numa var, e fizer um printf, o que é que me aparece no ecrâ? Aparece  "1101000" ou "h"? Essa era a minha questão :D

Se escreveres o caracter 'h' para um ficheiro binário e de seguida abrires esse ficheiro, o que vais ver é 'h', e não "1101000". Se abrires o mesmo ficheiro num editor hexadecimal, vais ver dum lado a sua representação como caracter ('h') e do outro a sua representação em hexa ("68"). Isto é complicado de explicar rapidamente, mas os dados que ficam no ficheiro são exactamente os mesmos, mais uma vez a interpretação é que é diferente.

Se leres o caracter 'h' de um ficheiro para um char c, ao fazeres printf("%c", c); vai ser impresso o caracter 'h'. Se fizeres printf("%X", (int)c); ele vai imprimir "68"; se fizeres  printf("%d", (int)c); ele imprime "104". Tudo depende da interpretação :P

A minha questão era se eu tinha acesso ao conteúdo lido, apenas através do "fopen" (na memória) ou se era necessário fazer um "fread" (para uma var/estructura). Mas pelo que percebi tenho de meter a informação numa "struct".

Pois, tinha percebido mal a pergunta. Não tens que meter numa estrutura, mas quando se trata de um ficheiro em modo binário dá mais jeito!

Isso é o que eu ando a tentar fazer, mas sem sucesso.

//ESTRUTURA
struct Carro {
int ID;
int classe;
int port_in;
int port_out;
char port_in_time[TIME_LENGHT];
char port_out_time[TIME_LENGHT];
};

struct Carro carro; //"instância"

for (n=0; n<nt; n++) {
fread(&carro, sizeof(carro), 1, fp); //LÊ DADOS
printf("\n\nID: %d \n Classe: %d \n Entrada: %d \n Saída: %d \n Hora de entrada: %s \n Hora de Saída: %s", carro.ID, carro.classe, carro.port_in, carro.port_out, carro.port_in_time, carro.port_out_time);
getchar();
}

Esse é o código que tenho. O que é que acontece? Ele lê linha a linha e mete na estructura no devido lugar (ID, classe...) certo? Então e o separador ou lá o que é? É que o ficheiro antes de apresentar os dados de cada carro tem um "1" antes...excepto no final que tem "0".

1 -> SEPARADOR
123456 -> IDENTIFICADOR VIA VERDE
2 -> CLASSE DA VIATURA
1 -> PORTAGEM DE ENTRADA
2 -> PORTAGEM DE SAÍDA
19h  3m 23s -> HORA DE ENTRADA
19h 41m 52s -> HORA DE SAÍDA

Ou seja...ele deveria ler a 1ª linha e colocá-la em carro.ID, a 2ª linha e colocá-la em carro.classe...e por ai. Certo?

Contudo, quando faço o printf com os dados que estou a meter na estructura aparecem-me números enormes e por vezes negativos (tudo marado ^^).

Não tinha visto que tinhas o ficheiro com esse conteúdo. Ou melhor, tinha visto e por alguma razão ignorei :D

Nesse caso, o melhor é abrires o ficheiro em modo texto. Depois tens que ler linha a linha e colocar o conteúdo da mesma em cada um dos campos da estrutura. O fscanf ajuda muito :D

O que queres dizer com isso de não conter apontadores?

No teu caso não faz diferença, porque não tens apontadores na estrutura, e porque não vais guardar em modo binário. Mas no caso de teres char* em vez de char[] para os campos time, terias que arranjar maneira de guardar o texto apontado pelos campos em vez dos endereços de memória, porque depois quando fosses ler irias ler endereços de memória em vez de texto.

E já agora mais uma questão:

- Qual a diferença entre:

typedef struct ESTRUCTURA{
   int algo;
} TYPEDEF_ESTRUCTURA;

e

struct ESTRUCTURA{
   int algo;
};

Com

typedef struct ESTRUCTURA{
   int algo;
} TYPEDEF_ESTRUCTURA;

irias declarar uma variável deste tipo com TYPEDEF_ESTRUCTURA carro; enquanto que da outra maneira irias declarar como declaraste no teu código: struct ESTRUCTURA carro;

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Não tinha visto que tinhas o ficheiro com esse conteúdo. Ou melhor, tinha visto e por alguma razão ignorei :P

Nesse caso, o melhor é abrires o ficheiro em modo texto. Depois tens que ler linha a linha e colocar o conteúdo da mesma em cada um dos campos da estrutura. O fscanf ajuda muito :)

Então mas o facto de a informação estar guardada num ficheiro em modo binário não me obriga a usar o modo de leitura também em binário ('rb')?

Btw...não podes dar um exemplozinho de como é que eu leio para uma estructura?

É que não sei bem como usar o fread...não sei se leia tudo de uma vez se não. Para ler tudo de uma vez tenho de primeiro verificar quantos elementos tem o ficheiro certo?

O mais perto que estive de ler tudo correctamente foi com:

for (n=0; n<nt; n++) {
fread(&carro, sizeof(carro), 1, fp); //LÊ DADOS
printf("\n\nID: %d \n Classe: %d \n Entrada: %d \n Saída: %d \n Hora de entrada: %s \n Hora de Saída: %s", carro.ID, carro.classe, carro.port_in, carro.port_out, carro.port_in_time, carro.port_out_time);
getchar();
}

Em que "nt" é o número total de elementos do ficheiro.

Mas não sei porque, só lê a 1ª linha correctamente...o resto é lixo.

Cumprimentos e mais uma vez muito obrigado por me ajudares e esclareceres as minhas dúvidas :D

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Neste caso não usas o fread, usas o fscanf. E é aconselhável abrires o ficheiro em modo não binário. Fazes

fscanf(fp, " %d\n%d\n%d", &separador, &carro.ID, &carro.classe);

e por aí fora para cada carro.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Bem...afinal o meu problema estava na declaração da estructura :\. Bastava acrescentar lá uns short's e uns unsigned's e prontos. Está a funcionar na perfeição.

Se surgir mais alguma coisa posto aqui :P

Muito obrigado TheDark.

Cumps

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Viva, aproveito a thread para pedir um esclarecimento. Estou a fazer a leitura do ficheiro correctamente. Agora preciso de manipular as strings de tempo entrada e tempo saída, para calcular os tempos de permanência.

Qual será o melhor método para retirar os inteiros das strings do tipo xxH xxM xxS ?

Tenho estado a tentar com a função atoi, mas não acede correctamente ao que quero.

Devo passar a string para um vector e ir la buscar os dados?

obrigado

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Boas mais uma vez

Então é o seguinte...

Questão 1:

Eu tenho um array de caracteres que representa o meu tempo. Algo deste género: "00h 00m 00s".

O que eu preciso é de retirar os valores (inteiros) correspondentes às horas, minutos, e segundos e coloca-los em variaveis.

Eu já o fiz e usei duas funções do 'string.h', a 'atoi' (retira os primeiros digitos duma string) e a 'strtok' (divide uma string em várias).

Contudo queria saber se há alguma maneira mais correcta/fácil para o fazer.

Questão 2:

Como é que eu represento um inteiro com dois digitos? Por exemplo em vez de '1horas' escrever '01horas'.

Obrigado e cumprimentos

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Contudo queria saber se há alguma maneira mais correcta/fácil para o fazer.

sscanf! Se tens por exemplo um array de caracteres assim: char str[]="Sao 10h25m", um sscanf(str, "Sao %dh%dm", &horas, &minutos) faz o que queres.

Como é que eu represento um inteiro com dois digitos? Por exemplo em vez de '1horas' escrever '01horas'.

http://www.cplusplus.com/reference/clibrary/cstdio/printf.html

printf("%05d horas", horas);

No %05d, o 0 diz para preencher o número com zeros, e o 5 diz para no mínimo escrever o número com 5 algarismos.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Contudo queria saber se há alguma maneira mais correcta/fácil para o fazer.

sscanf! Se tens por exemplo uma string com "Sao 10h25m", um sscanf("Sao %dh%dm", &horas, &minutos) faz o que queres.

Como é que eu represento um inteiro com dois digitos? Por exemplo em vez de '1horas' escrever '01horas'.

http://www.cplusplus.com/reference/clibrary/cstdio/printf.html

printf("%05d horas", horas);

No %05d, o 0 diz para preencher o número com zeros, e o 5 diz para no mínimo escrever o número com 5 algarismos.

Esclarecidíssimo!

Só uma questão...como é que eu uso o o sscanf com um variável? É que a minha string está numa array de caracteres.

Muito obrigado TheDark (mais uma vez). :P

Cumprimentos

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Ups. Hehe, enganei-me ali. Com a correcção já deve dar para perceber.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Só para informar que terminei o programa.

Muito obrigado TheDark pela ajuda, paciência, e esclarecimentos.

Aqui fica o resultado final :(

Link

Cumprimentos

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

@Buttpt

Boas... Eu estou a tentar fazer esse trabalho e deparo-me com um problema...

As minhas contas não batem certas, ou seja, quando estou a converter as horas para segundos, o meu tempo médio não bate certo com o tempo médio que o gestaov1 apresenta...

Estou a ler as horas, minutos e segundos, converter tudo para segundos, faço as contas entre o final e o inicial e depois faço a média aritmética da conta entre a variação do tempo a dividir pelo numero de carros numa dada classe.

Tiveste esse problema? Se sim, como o resolveste? Se não, preciso de ideias :) :)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Isso é em que item?

Certifica-te que estás a ler as horas/minutos/segundos da string correctamente. Usa a função sscanf como explicada pelo TheDark, é o método mais simples.

Verifica também se o teu algoritmo de conversão para segundos e vice-versa está correcto. Usámos esse algoritmo no 2º ou no 3º trabalho prático.

Não percebi muito bem isso da média. Estás a calcular a média do que?

Cumps

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

3ª opção do menu...

Estou a ler correctamente os valores e estou a usar sscanf. As conversões para segundos parecem-me correctas mas os meus valores em segundos não coincidem com os valores que o gestaov1 apresenta...

Estou a calcular a parte do tempo médio. Ou seja, somo os tempos que cada carro demorou entre 1e3 e depois divido esse tempo total pelo numero de veiculos...

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

3ª opção do menu...

Estou a ler correctamente os valores e estou a usar sscanf. As conversões para segundos parecem-me correctas mas os meus valores em segundos não coincidem com os valores que o gestaov1 apresenta...

Estou a calcular a parte do tempo médio. Ou seja, somo os tempos que cada carro demorou entre 1e3 e depois divido esse tempo total pelo numero de veiculos...

Então mas como sabes que os teus valores em segundos não coincidem se o gestaov1 apresenta apenas o resultado final em hora/minuto/segundo?

Para esse item, primeiro que tudo, tens de verificar para cada carro, se o seu percurso é a auto-estrada 1-3 ou 3-1.

Depois de o verificares, calculas o tempo de permanencia do veiculo, onde terás então te extrair as horas/minutos/segundos para segundos, e fazer a diferença entre o tempo de saida e o tempo de entrada.

Depois de o verificares, adicionas o tempo de permanencia calculado ao tempo de permanencia geral para essa classe, e tens também de ter uma variavel que conte os carros dessa classe, logo terás de incrementar 1 à mesma.

No final, depois de percorreres os carros todos, fazes a média para cada classe que será o tempo de permanencia total dessa classe a dividir pelo numero de carros da mesma.

Por fim, é so pegares na media e voltares a converter para horas/minutos/segundos.

Apresentas os resultados e voilá!

Cumps

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Obrigado pela disposição.

Mas penso que não seja isso que esteja a procura. Porque para além de ter um vector do tipo Comboios tenho la dentro um vector do tipo STACK (lista ligada) e outra lista ligada.

Obrigado mais uma vez :confused:

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora