Jump to content

Trabalho Final: Gestao de Viaturas numa Auto-Estrada


Carloz

Recommended Posts

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

"Rejoice not against me, O mine enemy: when I fall, I shall arise; when I sit in darkness, the LORD shall be a light unto me." - Micah 7:8 (KJV)

Link to comment
Share on other 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.

Desaparecido.

Link to comment
Share on other sites

Antes de mais obrigado por responderes TheDark. 😄

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 😄

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 😛

Cumps

"Rejoice not against me, O mine enemy: when I fall, I shall arise; when I sit in darkness, the LORD shall be a light unto me." - Micah 7:8 (KJV)

Link to comment
Share on other sites

Antes de mais obrigado por responderes TheDark. 😄

De nada 😄

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 😄

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 😛

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 😄

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 😄

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;

Desaparecido.

Link to comment
Share on other sites

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

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 😄

"Rejoice not against me, O mine enemy: when I fall, I shall arise; when I sit in darkness, the LORD shall be a light unto me." - Micah 7:8 (KJV)

Link to comment
Share on other 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 😛

Muito obrigado TheDark.

Cumps

"Rejoice not against me, O mine enemy: when I fall, I shall arise; when I sit in darkness, the LORD shall be a light unto me." - Micah 7:8 (KJV)

Link to comment
Share on other 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

Link to comment
Share on other 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

"Rejoice not against me, O mine enemy: when I fall, I shall arise; when I sit in darkness, the LORD shall be a light unto me." - Micah 7:8 (KJV)

Link to comment
Share on other 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.

Desaparecido.

Link to comment
Share on other 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). 😛

Cumprimentos

"Rejoice not against me, O mine enemy: when I fall, I shall arise; when I sit in darkness, the LORD shall be a light unto me." - Micah 7:8 (KJV)

Link to comment
Share on other 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 🙂 :)

Link to comment
Share on other 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

"Rejoice not against me, O mine enemy: when I fall, I shall arise; when I sit in darkness, the LORD shall be a light unto me." - Micah 7:8 (KJV)

Link to comment
Share on other 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...

Link to comment
Share on other 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

"Rejoice not against me, O mine enemy: when I fall, I shall arise; when I sit in darkness, the LORD shall be a light unto me." - Micah 7:8 (KJV)

Link to comment
Share on other sites

  • 1 year later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.