PDA

Visualizza la versione completa : [C]Risoluzione tema esame


fedrock
10-07-2014, 14:51
Agli abbonati di un parco divertimenti è stato assegnato un numero identificativo univoco per gestire l'accesso al parco... Gli accessi vengono memorizzati in un file che contiene righe del tipo:
hh:mm:ss C numero

dove hh è un numero tra [0, 23], mm tra [0, 59] e ss tra [0, 59], C è un carattere che vale "I" in caso di ingresso e "U" in caso di uscita e numero è il codice identificativo di ogni cliente.

I dati sono memorizzati in ordine cronologico crescente.
Il file memorizza gli accessi di un solo giorno.
Si scriva un programma che:
a) definisca una struttura struct accesso utile a memorizzare i dati relativi all'accesso di ciascun utente (dovrà contenere sia l'ora di ingresso che quella di uscita);
b) definisca una funzione carica_dati che carichi i dati contenuti in un file avente la struttura descritta;
c)definisca una funzione permanenza che riceve come argomento una struttura di tipo struct accesso e ristituisca il tempo di permanenza nel parco in secondi; questo dato può a sua volta essere memorizzato in un campo della struttura stessa;
d)definisca una funzione media_accesso che restituisca il tempo medio di accesso calcolato su tutti gli accessi della giornata;
e) definisca la funzione tariffa che calcoli quanto dovuto da ciascun cliente, secondo il seguente piano tariffario:
-fino a 3 ore si paga 1€ ogni 15 minuti, arrotondando il tempo al quarto d'ora per eccesso;
-oltre le 3 ore si paga un costo fisso aggiuntivo di 5€;
f) si crei un file output.txt che contenga un riepilogo del tempo di accesso e del prezzo dovuto da ogni utente che è entrato nel parco, ciascuna riga abbia il formato:
numero_utente durata tariffa
(ordinare i dati in senso crescente di durata)

Questo è il file accessi.txt che ho creato usando la funzione rand():



00:05:07 I 03135
00:24:06 U 21530
00:55:23 I 34022
01:00:10 I 97763
01:07:15 U 55736
01:13:23 U 02567
01:35:25 U 84421
01:38:23 U 79802
01:54:04 U 18456
01:58:42 I 33069
02:13:25 I 47793
02:13:45 I 13929
02:14:18 U 66413
02:16:05 U 30886
02:23:27 I 16649
03:23:24 I 83426
03:25:53 U 36915
03:36:29 I 36915
04:02:36 U 34022
04:26:53 U 76229
04:33:04 I 79802
04:45:07 I 84421
04:52:45 U 22862
05:02:50 U 13929
05:29:56 I 44919
05:34:49 I 22862
06:34:45 I 74067
06:47:39 U 23058
06:55:09 I 30886
07:04:32 U 95368
07:20:07 I 05211
07:27:14 I 56429
07:37:07 U 75011
07:42:37 I 64370
08:10:43 I 23058
08:12:03 U 05211
08:21:46 U 98315
08:54:05 U 77373
09:20:32 U 65123
09:51:26 I 89172
10:02:24 U 80540
10:16:41 U 56429
10:20:03 U 64370
10:36:42 I 66413
10:38:44 I 98167
10:43:14 U 89172
10:52:20 I 90027
10:53:52 U 03135
11:03:57 I 75198
11:14:38 I 98315
11:22:22 U 60492
11:24:27 U 83426
11:40:03 U 20059
11:45:04 U 68690
12:13:10 U 94324
12:13:52 I 13926
12:39:51 U 90027
12:41:16 I 95368
13:02:11 U 38335
13:02:16 I 98537
13:23:09 I 38335
13:33:05 I 20059
13:38:48 U 13784
14:27:02 U 92777
14:32:52 U 98167
14:42:23 U 41421
14:45:35 U 97763
15:16:15 I 13784
15:30:01 U 02362
15:38:38 U 74067
15:44:01 U 47793
15:49:05 I 60492
16:21:23 U 33069
16:43:00 I 85386
16:47:07 I 92777
16:55:33 U 65782
16:57:28 U 13926
17:04:52 I 65123
17:13:49 I 76229
17:14:54 I 80540
17:26:26 I 55736
18:04:00 U 85386
18:04:32 I 68690
18:13:30 I 41421
18:21:39 I 77373
18:31:54 U 78042
19:15:58 U 44919
19:23:28 I 78042
19:42:47 I 65782
20:18:21 I 02567
20:26:31 I 18456
20:43:49 I 02362
21:01:14 U 16649
21:22:29 U 61393
21:32:01 I 61393
21:35:35 I 21530
21:39:14 I 94324
22:05:57 U 75198
22:16:34 I 75011
22:35:38 U 98537


Ora stavo cercando di fare il punto b e già mi ritrovo problemi nel procedere... questo è quello che ho scritto:




#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct{
int hh, mm, ss;
char *C;
int user;
}accesso;



void carica_dati(char filename[]){
FILE *f;
char buffer[128];
f = fopen(filename, "r");
if(f==NULL)
{
perror("Errore apertura file");
exit(1);
}
else
{
int z = 0;
while((fgets(buffer, sizeof(buffer), f))!=NULL)
z++;
accesso db[z];
int d;
for(d=0; d<z; d++) {
sscanf(buffer, "%d:%d:%d %s %d", &db[d].hh, &db[d].mm, &db[d].ss, db[d].C, &db[d].user);

}
fclose(f);
}
}




int main(int argc, char *argv[])
{
carica_dati(argv[1]);





return 0;
}


Non da nessun errore nella compilazione ma quando lo eseguo mi salta fuori il famoso segmentation fault :jam:

torn24
10-07-2014, 18:01
Ciao ,



z++;
accesso db[z];


se dichiari un array di struct , non puoi cambiare dimensione , tra l'altro questo array è locale , non visibile all'esterno della funzione , quindi inutile .

dovresti dichiarare un puntatore struct nel main ,passarlo alla funzione e allocare memoria dinamicamente con realloc() .


altro punto , nella struct è dichiarato un puntatore al char* , che utilizzi come char , o allochi spazio per un byte "cosa insensata" o sostituisci il puntatore con un char .

fedrock
10-07-2014, 19:18
Ciao ,



z++;
accesso db[z];


se dichiari un array di struct , non puoi cambiare dimensione , tra l'altro questo array è locale , non visibile all'esterno della funzione , quindi inutile .

dovresti dichiarare un puntatore struct nel main ,passarlo alla funzione e allocare memoria dinamicamente con realloc() .


altro punto , nella struct è dichiarato un puntatore al char* , che utilizzi come char , o allochi spazio per un byte "cosa insensata" o sostituisci il puntatore con un char .

Ciao,
accesso db[z] è fuori dal ciclo, con C se non si mettono le graffe esegue il ciclo solo sulla prima istruzione giusto? quindi perché dici che non può cambiare dimensione :confused:

Per i puntatori e malloc mi sta venendo difficile comprenderli nonostante le guide, finisco di leggerne un'altra e vediamo se capisco quello che avevo sbagliato:facepalm:

oregon
10-07-2014, 20:14
Il problema del seg fault è causato dall'uso di

char *C;

della struttura.

Non puoi usare un semplice puntatore per memorizzare una stringa. Devi prima allocare lo spazio necessario.

Per l'allocazione del vettore ti consiglio di usare la malloc.

fedrock
10-07-2014, 21:15
Il problema del seg fault è causato dall'uso di

char *C;

della struttura.

Non puoi usare un semplice puntatore per memorizzare una stringa. Devi prima allocare lo spazio necessario.

Per l'allocazione del vettore ti consiglio di usare la malloc.

Ciao, ma char C alla fine non deve andare a memorizzare un'intera stringa ma solo il carattere "C" (che vale I oppure U) quindi a che servirebbe allocare spazio se a priori conosco si tratti di un singolo carattere?
L' sscanf non va a separare l'intera riga contenuta nel file e a prendere solo il carattere che sta tra gli spazi e %s e quindi dopo lo mette all'interno della i-esima struttura.C? (db[i])

Scusate se magari faccio domande super-stupide :facepalm:

oregon
10-07-2014, 21:51
Se deve contenere un carattere allora deve essere un char e non un puntatore. Quindi

char C;

e non

char *C;

Quindi non devi usare %s ma %c

fedrock
10-07-2014, 22:17
Se deve contenere un carattere allora deve essere un char e non un puntatore. Quindi

char C;

e non

char *C;

Quindi non devi usare %s ma %c

Ciao, facendo come dici tu funziona, mi ero anche dimenticato dell' &:


#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct{
int hh, mm, ss;
char C;
int user;
}accesso;



void carica_dati(char filename[]){
FILE *f;
char buffer[128];
f = fopen(filename, "r");
if(f==NULL)
{
perror("Errore apertura file");
exit(1);
}
else
{
int z = 0;
while((fgets(buffer, sizeof(buffer), f))!=NULL)
z++;
accesso db[z];
int d;
for(d=0; d<z; d++) {
sscanf(buffer, "%d:%d:%d %c %d", &db[d].hh, &db[d].mm, &db[d].ss, &db[d].C, &db[d].user);
/* printf("%d:%d:%d %c %d\n", db[d].hh, db[d].mm, db[d].ss, db[d].C, db[d].user); */
}
fclose(f);
}
}




int main(int argc, char *argv[])
{
carica_dati(argv[1]);





return 0;
}


Quindi ora ho la mia bella struttura caricata con i dati e dovrei cercare di suddividere gli ingressi con le uscite per poi passare alla richiesta c)
Ho paura che mi farò risentire molto presto :facepalm:

fedrock
10-07-2014, 22:50
A rieccome, mi avete chiamato vero? :biifu:

Ecco come ho pensato di trovare l'ingresso e uscita dell'utente e memorizzarla nella struttura:


#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct{
int hh, mm, ss;
int hhI, mmI, ssI;
int hhU, mmU, ssU;
char C;
int user;
}accesso;



void carica_dati(char filename[]){
FILE *f;
char buffer[128];
f = fopen(filename, "r");
if(f==NULL)
{
perror("Errore apertura file");
exit(1);
}
else
{
int z = 0;
while((fgets(buffer, sizeof(buffer), f))!=NULL)
z++;
accesso db[z];
accesso dbIU[z];
int d, G;
for(d=0; d<z; d++) {
sscanf(buffer, "%d:%d:%d %c %d", &db[d].hh, &db[d].mm, &db[d].ss, &db[d].C, &db[d].user);
for(d=0; d<z; d++) {
G=0;
while(db[d].user!=db[G].user)
G++;
if(db[G].C=='U'){
dbIU[d].hhI = db[d].hh;
dbIU[d].mmI = db[d].mm;
dbIU[d].ssI = db[d].ss;
dbIU[d].hhU = db[G].hh;
dbIU[d].mmU = db[G].mm;
dbIU[d].ssU = db[G].ss;
dbIU[d].user = db[d].user;
}
else
{
dbIU[d].hhI = db[G].hh;
dbIU[d].mmI = db[G].mm;
dbIU[d].ssI = db[G].ss;
dbIU[d].hhU = db[d].hh;
dbIU[d].mmU = db[d].mm;
dbIU[d].ssU = db[d].ss;
dbIU[d].user = db[d].user;
}

/* printf("%d:%d:%d %c %d\n", db[d].hh, db[d].mm, db[d].ss, db[d].C, db[d].user); */
}
for(G=0; G<z; G++)
printf("I%d:%d:%dU%d%d%d %d\n", dbIU[G].hhI, dbIU[G].mmI, dbIU[G].ssI, dbIU[G].hhU, dbIU[G].mmU, dbIU[G].ssU, dbIU[G].user);


fclose(f);
}
}
}



int main(int argc, char *argv[])
{
carica_dati(argv[1]);





return 0;
}


A quanto pare alla compilazione il computer non è esploso e non mi ha dato errori, però eseguendolo la printf spara roba assurda :facepalm: non passerò mai questo esame

torn24
11-07-2014, 07:42
Ciao , invece di aiutarti , perchè ci sono persone competenti che possono farlo in maniera ottimale , vorrei chiederti io di aiutarmi a capire il tuo codice .

Vorrei sapere cosa fa questo spezzone di codice ???



int z =0;
while((fgets(buffer,sizeof(buffer), f))!=NULL)
z++; // QUI CONTI LE RIGHE DEL FILE , MA BUFFER COSA CONTIENE A FINE CICLO ?????
accesso db[z];
int d;
for(d=0; d<z; d++){// QUI ESEGUI SSCANF PER IL NUMERO DI RIGHE FILE , MA BUFFER NON E' LA STESSA STRINGA ??????
sscanf(buffer,"%d:%d:%d %s %d",&db[d].hh,&db[d].mm,&db[d].ss, db[d].C,&db[d].user);

fedrock
11-07-2014, 14:04
Ciao , invece di aiutarti , perchè ci sono persone competenti che possono farlo in maniera ottimale , vorrei chiederti io di aiutarmi a capire il tuo codice .

Vorrei sapere cosa fa questo spezzone di codice ???



int z =0;
while((fgets(buffer,sizeof(buffer), f))!=NULL)
z++; // QUI CONTI LE RIGHE DEL FILE , MA BUFFER COSA CONTIENE A FINE CICLO ?????
accesso db[z];
int d;
for(d=0; d<z; d++){// QUI ESEGUI SSCANF PER IL NUMERO DI RIGHE FILE , MA BUFFER NON E' LA STESSA STRINGA ??????
sscanf(buffer,"%d:%d:%d %s %d",&db[d].hh,&db[d].mm,&db[d].ss, db[d].C,&db[d].user);




Caspita hai ragione, li c'è un errore logico :cry: non me ne ero accorto :facepalm:
Mi serviva il numero delle righe per stabile la dimensione dell'array di strutture accesso ecco perché tutto quel casino...
Quindi il codice giusto dovrebbe essere;


int z =0;
while((fgets(buffer,sizeof(buffer), f))!=NULL) {
z++;
}
accesso db[z];
while((fgets(buffer,sizeof(buffer), f))!=NULL) {
sscanf(buffer,"%d:%d:%d %s %d",&db[d].hh,&db[d].mm,&db[d].ss, db[d].C,&db[d].user);
}

C'è comunque qualcosa che non mi convinge... Non ho usato puntatori (perché non li so usare bene) però mi ricordo che all'esame molti l'hanno fatto con i puntatori (quelli che l'hanno passato) :facepalm:

Loading