Vedi anche:
HomeWork6aa0203,
DomandeHomework6aa0203,
RisultatiHomework6aa0203.
Prima versione
Questo è un PRIMO ABBOZZO della soluzione dell'esercizio 6:
- non l'ho testato a fondo
- fa il sort ma non la gestione degli errori
Sto finendo la versione completa.
#include <stdio.h>
#include <stdlib.h>
/*
ANSI C vuole che tutte le struct abbiano nome
*/
typedef struct {
char nome[31];
char cognome[31];
int g;
int m;
int a;
int hasEmail; /* se TRUE allora c'e' l'email */
union {
struct {
char uname[51];
char domain[51];
} email; /* email */
struct {
int pref_int;
char prefisso[6];
int numero;
} tel; /* telefono */
} et; /* email o telefono */
} Voce;
/* prototipi delle funzioni */
int fine( char riga[]);
int add( char riga[], Voce agenda[], int quanti);
int del( char riga[], Voce agenda[], int quanti);
int print( char riga[], Voce agenda[], int quanti);
int prox( char riga[], Voce agenda[], int quanti);
int sort_nome( char riga[], Voce agenda[], int quanti);
int sort_cognome(char riga[], Voce agenda[], int quanti);
int sort_compl( char riga[], Voce agenda[], int quanti);
void print_voce(Voce * voce);
#define NVOCI 20
#define MAXLINE 201
/*
Programma principale
*/
int main(int argc, char* argv[]) {
char riga[MAXLINE] = { 0 }; /* buffer per l'ultima riga letta */
Voce agenda[NVOCI] = { 0 }; /* vettore di NVOCI (20) voci */
int quanti = 0; /* numero di voci inserite */
/* leggo tutta una riga (al max MAXLINE caratteri) */
scanf("%200[^\n]",riga);
/* continuo finche' non arriva il comando 'fine' */
while (!fine(riga)) {
if (add(riga,agenda,quanti))
if (quanti<NVOCI)
quanti---++;
quanti -= del(riga,agenda,quanti);
prox(riga,agenda,quanti);
print(riga,agenda,quanti);
sort_nome(riga,agenda,quanti);
sort_cognome(riga,agenda,quanti);
sort_compl(riga,agenda,quanti);
scanf("\n%200[^\n]",riga);
}
return 0;
}
/*
Riconosco il comando 'fine'
torno TRUE se l'ho riconosciuto
*/
int fine( char riga[])
{
return (0==strcmp(riga,"fine"));
}
/*
Riconosco ed eseguo i comandi
'add <nome> <cognome> <data> tel <telefono>'
'add <nome> <cognome> <data> email <email>'
torno TRUE se l'ho riconosciuto
*/
int add( char riga[], Voce agenda[], int quanti)
{
Voce nuova = { 0 };
char resto[MAXLINE] = { 0 };
/* prima riconosciamo nome e cognome e data di nascita */
if (6 != sscanf(riga,"add \"%30[^\"\n]\" \"%30[^\"\n]\" %2d-%2d-%4d %[^\n]",
nuova.nome, nuova.cognome, &nuova.g, &nuova.m, &nuova.a, resto))
if (6 != sscanf(riga,"add \"%30[^\"\n]\" %30s %2d-%2d-%4d %[^\n]",
nuova.nome, nuova.cognome, &nuova.g, &nuova.m, &nuova.a, resto))
if (6 != sscanf(riga,"add %30s \"%30[^\"\n]\" %2d-%2d-%4d %[^\n]",
nuova.nome, nuova.cognome, &nuova.g, &nuova.m, &nuova.a, resto))
if (6 != sscanf(riga,"add %30s %30s %2d-%2d-%4d %[^\n]",
nuova.nome, nuova.cognome, &nuova.g, &nuova.m, &nuova.a, resto))
return 0;
/* TODO: gestire gli errori */
/* poi l'email o il telefono */
nuova.hasEmail = 0;
if (2 == sscanf(resto,"email %[^@ \n]@%[^\n ]\n",
nuova.et.email.uname,
nuova.et.email.domain))
nuova.hasEmail = 1;
else if (3 != sscanf(resto,"tel---+%3d-%5[0-9]-%10d\n",
&nuova.et.tel.pref_int,
nuova.et.tel.prefisso,
&nuova.et.tel.numero)) {
printf("email o numero errato\n");
return 0;
}
if (quanti==NVOCI)
printf("piena\n");
else
agenda[quanti] = nuova;
/* trovato */
return 1;
}
/*
Riconosco ed eseguo il comando 'del <nome> <cognome>'
torno il numero di elementi cancellati
*/
int del( char riga[], Voce agenda[], int quanti)
{
char nome[31] = { 0 };
char cognome[31] = { 0 };
int cancellati = 0, i, j;
/* prima riconosciamo nome e cognome e data di nascita */
if (2 != sscanf(riga,"del \"%30[^\"\n]\" \"%30[^\"\n]\"",nome, cognome))
if (2 != sscanf(riga,"del \"%30[^\"\n]\" %30s",nome, cognome))
if (2 != sscanf(riga,"del %30s \"%30[^\"\n]\"",nome, cognome))
if (2 != sscanf(riga,"del %30s %30s",nome, cognome))
return 0;
/* TODO: gestire gli errori */
/* cerco tutte le voci che corrispondono */
for (i=0; i<quanti-cancellati; i---++)
if (0==strcmp(agenda[i].nome, nome) &&
0==strcmp(agenda[i].cognome,cognome)) {
/* ogni voce trovata viene stampata */
print_voce(&agenda[i]);
/* e le successive vengono spostate indietro di un posto */
for (j=i---+1; j<quanti; j++)
agenda[j-1]=agenda[j];
cancellati---++;
}
if (0==cancellati)
printf("nessuna\n");
return cancellati;
}
/*
Riconosco ed eseguo la stampa di tutta la tabella (o di 'nessuna')
torno TRUE se l'ho riconosciuto
*/
int print( char riga[], Voce agenda[], int quanti)
{
int i;
if (0!=strcmp(riga,"print"))
return 0;
for (i=0; i<quanti; i---++)
print_voce(&agenda[i]);
if (0==quanti)
printf("nessuna\n");
return 1;
}
/*
stampa di una singola voce
*/
void print_voce(Voce * v)
{
/* costruisco il valore dell'ultima colonna
dato che non so quanto e' lunga l'email mi tengo largo */
char lastcolumn[101] = { 0 };
if (v == NULL) return; /* tanto per evitare errori */
if (1 == v->hasEmail)
sprintf(lastcolumn,
"%s@%s",
v->et.email.uname,
v->et.email.domain
);
else
sprintf(lastcolumn,
"---+%d-%0.5s-%d",
v->et.tel.pref_int,
v->et.tel.prefisso,
v->et.tel.numero
);
/* stampo la riga della tabella */
printf("|%30.30s|%30.30s|%02d-%02d-%04d|%-50.50s|\n",
v->nome,
v->cognome,
v->g,
v->m,
v->a,
lastcolumn);
}
/*
Riconosco ed eseguo il comando 'prox <giorno> <mese>'
*/
int prox( char riga[], Voce agenda[], int quanti)
{
int g = 0;
int m = 0;
int i, j, trovato=0;
/* prima riconosciamo la data di nascita */
if (2 != sscanf(riga,"prox %2d %2d", &g, &m))
return 0;
/* TODO: gestire gli errori */
/* per fare i conti faccio partire il numero del giorno e del mese da 0 */
g--;
m--;
/* considero i mesi tutti lunghi 31 giorni */
for (i=0;i<12*31 && trovato==0;i---++)
for (j=0; j<quanti; j---++)
if ((agenda[j].g-1)---+(agenda[j].m-1)*31 == (g+m*31+i)%(12*31)) {
trovato = 1;
print_voce(&agenda[j]);
}
if (trovato==0)
printf("nessuna\n");
return 1;
}
/* prototipo di qsort
void qsort(void *base, size_t nmemb, size_t size,
int(*compar)(const void *, const void *));
*/
/*
confronto tra due voci per determinare quale nome viene prima
*/
int name_compare(const void * xx, const void * yy)
{
Voce * x = (Voce *) xx;
Voce * y = (Voce *) yy;
return strcmp(x->nome, y->nome);
}
/*
confronto tra due voci per determinare quale cognome viene prima
*/
int surname_compare(const void * xx, const void * yy)
{
Voce * x = (Voce *) xx;
Voce * y = (Voce *) yy;
return strcmp(x->cognome, y->cognome);
}
/*
confronto tra due voci per determinare quale compleanno viene prima
*/
int birthday_compare(const void * xx, const void * yy)
{
Voce * x = (Voce *) xx;
Voce * y = (Voce *) yy;
if (x->m < y->m)
return -1;
if (x->m > y->m)
return---+1;
if (x->g < y->g)
return -1;
if (x->g > y->g)
return---+1;
return 0;
}
/*
Riconosco ed eseguo il comando 'sort nome'
*/
int sort_nome( char riga[], Voce agenda[], int quanti)
{
if (0!=strcmp(riga,"sort nome"))
return 0;
qsort(agenda, quanti, sizeof(Voce), name_compare);
}
/*
Riconosco ed eseguo il comando 'sort cognome'
*/
int sort_cognome(char riga[], Voce agenda[], int quanti)
{
if (0!=strcmp(riga,"sort cognome"))
return 0;
qsort(agenda, quanti, sizeof(Voce), surname_compare);
}
/*
Riconosco ed eseguo il comando 'sort compleanno'
*/
int sort_compl( char riga[], Voce agenda[], int quanti)
{
if (0!=strcmp(riga,"sort compleanno"))
return 0;
qsort(agenda, quanti, sizeof(Voce), birthday_compare);
}
Seconda versione
Questa versione è quasi completa ma devo finire di testarla sulla gestione degli errori.
Questa è la versione usata per la prima correzione.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
ANSI C vuole che tutte le struct abbiano nome
*/
typedef struct {
char nome[31];
char cognome[31];
int g;
int m;
int a;
int hasEmail; /* se TRUE allora c'e' l'email */
union {
struct {
char uname[51];
char domain[51];
} email; /* email */
struct {
int pref_int;
char prefisso[6];
double numero;
} tel; /* telefono */
} et; /* email o telefono */
} Voce;
/* prototipi delle funzioni */
int fine( char riga[]);
int add( char riga[], Voce agenda[], int * quanti);
int del( char riga[], Voce agenda[], int * quanti);
int print( char riga[], Voce agenda[], int quanti);
int prox( char riga[], Voce agenda[], int quanti);
int sort_nome( char riga[], Voce agenda[], int quanti);
int sort_cognome(char riga[], Voce agenda[], int quanti);
int sort_compl( char riga[], Voce agenda[], int quanti);
void print_voce(Voce * voce);
#define NUMVOCI 20
#define MAXLINE 201
#define FALSE 0
#define TRUE 1
/*
Programma principale
*/
int main(int argc, char* argv[]) {
char riga[MAXLINE] = { 0 }; /* buffer per l'ultima riga letta */
Voce agenda[NUMVOCI] = { 0 }; /* vettore di NVOCI (20) voci */
int quanti = 0; /* numero di voci inserite */
int found = FALSE;
/* leggo tutta una riga (al max MAXLINE caratteri) */
scanf("%200[^\n]",riga);
/* continuo finche' non arriva il comando 'fine' */
while (!fine(riga)) {
found = FALSE;
found |= add(riga,agenda,&quanti);
found |= del(riga,agenda,&quanti);
found |= prox(riga,agenda,quanti);
found |= print(riga,agenda,quanti);
found |= sort_nome(riga,agenda,quanti);
found |= sort_cognome(riga,agenda,quanti);
found |= sort_compl(riga,agenda,quanti);
/*
if (!found)
printf("comando non riconosciuto\n");
*/
scanf("\n%200[^\n]",riga);
}
return FALSE;
}
/*
Riconosco il comando 'fine'
torno TRUE se l'ho riconosciuto
*/
int fine(char riga[])
{
return (0==strcmp(riga,"fine"));
}
/*
Riconosco ed eseguo i comandi
'add <nome> <cognome> <data> tel <telefono>'
'add <nome> <cognome> <data> email <email>'
torno TRUE se l'ho riconosciuto
*/
int add(char riga[], Voce agenda[], int *quanti)
{
Voce nuova = { 0 }; /* nuova voce (variabile locale) */
char * dot = NULL; /* indice dell'ultimo carattere '.' nell'email */
/*
uso due buffer di appoggio per contenere (a turno) la parte della
linea non ancora esaminata
*/
char resto[MAXLINE] = { 0 }; /* resto della linea ancora non esaminata */
char resto1[MAXLINE] = { 0 }; /* resto della linea ancora non esaminata */
/* riconosciamo il comando (seguito da almeno uno spazio) */
if (1 != sscanf(riga,"add%*[ ]%[^\n]", resto))
return FALSE;
/* riconosciamo il nome (seguito da almeno uno spazio) */
if (2 != sscanf(resto,"\"%30[^\"]\"%*[ ]%[^\n]", nuova.nome, resto1) &&
2 != sscanf(resto,"%30[^ ]%*[ ]%[^\n]", nuova.nome, resto1)) {
printf("nome errato\n");
return FALSE;
}
/* riconosciamo il cognome (seguito da almeno uno spazio) */
if (2 != sscanf(resto1,"\"%30[^\"]\"%*[ ]%[^\n]", nuova.cognome, resto) &&
2 != sscanf(resto1,"%30[^ ]%*[ ]%[^\n]", nuova.cognome, resto)) {
printf("cognome errato\n");
return FALSE;
}
/* riconosciamo la data (seguita da almeno uno spazio) */
if (4 != sscanf(resto,"%d-%d-%d%*[ ]%[^\n]",
&nuova.g, &nuova.m, &nuova.a, resto1)) {
printf("data errata\n");
return FALSE;
}
/* controlliamo il valore dei campi della data (tutti mesi da 31 giorni) */
if (nuova.g < 1 || nuova.g > 31 || nuova.m < 1 || nuova.m > 12
|| nuova.a < 0 || nuova.a > 9999) {
printf("data errata\n");
return FALSE;
}
/* poi vediamo se seguira' l'email o il telefono */
if (1 == sscanf(resto1,"email%*[ ]%[^\n]",resto)) {
nuova.hasEmail = TRUE;
/* leggiamo l'email (e non ci aspettiamo altri caratteri dopo) */
if (2 != sscanf(resto,"%46[^@ ]@%48[^@ ]%[^\n]",
nuova.et.email.uname, nuova.et.email.domain, resto1)) {
printf("email errata\n");
return FALSE;
}
/* controllo che non sia troppo lunga */
if (strlen(nuova.et.email.uname)---+strlen(nuova.et.email.domain)+1>50) {
printf("email errata\n");
return FALSE;
}
/* controllo che il 'domain' contenga almeno un punto
preceduto e seguito da qualcosa */
dot = rindex(nuova.et.email.domain,'.'); /* puntatore all'ultimo '.' */
if (dot == NULL || /* se non lo trovo */
dot == nuova.et.email.domain || /* o e' all'inizio */
1 == strlen(dot)) { /* o e' alla fine */
printf("email errata\n");
return FALSE;
}
} else {
if (1 == sscanf(resto1,"tel%*[ ]%[^\n]",resto)) {
nuova.hasEmail = FALSE;
/* leggiamo il telefono (e non ci aspettiamo altri caratteri dopo) */
if (3 != sscanf(resto,"---+%d-%5[0-9]-%d%[^\n]",
&nuova.et.tel.pref_int,
nuova.et.tel.prefisso,
&nuova.et.tel.numero,
resto1)
|| nuova.et.tel.pref_int>999
|| nuova.et.tel.pref_int<=0
|| nuova.et.tel.numero>9999999999.0
|| nuova.et.tel.numero<=0) {
printf("telefono errato\n");
return FALSE;
}
} else {
printf("comando errato\n");
return FALSE;
}
}
if (*quanti == NUMVOCI)
printf("piena\n");
else
agenda[(*quanti)---++] = nuova;
/* trovato */
return TRUE;
}
/*
Riconosco ed eseguo il comando 'del <nome> <cognome>'
torno il numero di elementi cancellati
*/
int del(char riga[], Voce agenda[], int *quanti)
{
char nome[31] = { 0 };
char cognome[31] = { 0 };
int cancellati = 0, i, j;
/*
uso due buffer di appoggio per contenere (a turno) la parte della
linea non ancora esaminata
*/
char resto[MAXLINE] = { 0 }; /* resto della linea ancora non esaminata */
char resto1[MAXLINE] = { 0 }; /* resto della linea ancora non esaminata */
/* riconosciamo il comando (seguito da almeno uno spazio) */
if (1 != sscanf(riga,"del%*[ ]%[^\n]", resto))
return FALSE;
/* riconosciamo il nome (seguito da almeno uno spazio) */
if (2 != sscanf(resto,"\"%30[^\"]\"%*[ ]%[^\n]", nome, resto1) &&
2 != sscanf(resto,"%30[^ ]%*[ ]%[^\n]", nome, resto1)) {
printf("nome errato\n");
return FALSE;
}
/* riconosciamo il cognome (non seguito da altri caratteri) */
if (1 != sscanf(resto1,"\"%30[^\"]\"%[^\n]", cognome, resto) &&
1 != sscanf(resto1,"%30[^ ]%[^\n]", cognome, resto)) {
printf("cognome errato\n");
return FALSE;
}
/* cerco tutte le voci che corrispondono */
for (i=0; i<(*quanti)-cancellati; i---++)
if (0==strcmp(agenda[i].nome, nome) &&
0==strcmp(agenda[i].cognome,cognome)) {
/* ogni voce trovata viene stampata */
/* print_voce(&agenda[i]); */
/* e le successive vengono spostate indietro di un posto */
for (j=i---+1; j<(*quanti); j++)
agenda[j-1]=agenda[j];
cancellati---++;
}
if (0==cancellati)
printf("nessuna\n");
(*quanti) -= cancellati;
return TRUE;
}
/*
Riconosco ed eseguo la stampa di tutta la tabella (o di 'nessuna')
torno TRUE se l'ho riconosciuto
*/
int print(char riga[], Voce agenda[], int quanti)
{
int i;
if (0!=strcmp(riga,"print"))
return FALSE;
for (i=0; i<quanti; i---++)
print_voce(&agenda[i]);
/* if (0==quanti)
printf("nessuna\n");
*/
return TRUE;
}
/*
stampa di una singola voce
*/
void print_voce(Voce * v)
{
/* costruisco il valore dell'ultima colonna in un buffer
dato che non so quanto e' lunga l'email mi tengo largo */
char lastcolumn[MAXLINE] = { 0 };
if (v == NULL) return; /* tanto per evitare errori */
if (1 == v->hasEmail)
sprintf(lastcolumn,
"%s@%s",
v->et.email.uname,
v->et.email.domain
);
else
sprintf(lastcolumn,
"---+%d-%0.5s-%d",
v->et.tel.pref_int,
v->et.tel.prefisso,
v->et.tel.numero
);
/* stampo la riga della tabella */
printf("|%30.30s|%30.30s|%02d-%02d-%04d|%-50.50s|\n",
v->nome,
v->cognome,
v->g,
v->m,
v->a,
lastcolumn);
}
/*
Riconosco ed eseguo il comando 'prox <giorno> <mese>'
*/
int prox( char riga[], Voce agenda[], int quanti)
{
int g = 0;
int m = 0;
int i, j, trovato=0;
/*
uso due buffer di appoggio per contenere (a turno) la parte della
linea non ancora esaminata
*/
char resto[MAXLINE] = { 0 }; /* resto della linea ancora non esaminata */
char resto1[MAXLINE] = { 0 }; /* resto della linea ancora non esaminata */
/* riconosciamo il comando */
if (1 != sscanf(riga,"prox%*[ ]%[^\n]", resto))
return FALSE;
/* riconosciamo la data di nascita */
if (2 != sscanf(resto,"%2d-%2d%[^\n]", &g, &m, resto1)) {
printf("data errata\n");
return FALSE;
}
/* controlliamo i due valori (tutti mesi da 31 giorni) */
if (g < 1 || g > 31 || m < 1 || m > 12 ) {
printf("data errata\n");
return FALSE;
}
/* per fare i conti faccio partire il numero del giorno e del mese da 0 */
g--;
m--;
/* considero i mesi tutti lunghi 31 giorni */
for (i=0;i<12*31 && trovato==0;i---++)
for (j=0; j<quanti; j---++)
if ((agenda[j].g-1)---+(agenda[j].m-1)*31 == (g+m*31+i)%(12*31)) {
trovato = TRUE;
print_voce(&agenda[j]);
}
if (trovato==0)
printf("nessuna\n");
return TRUE;
}
/* prototipo di qsort
void qsort( void *base, // inizio dell'array
size_t nmemb, // numero di elementi
size_t size, // dimensione di un elemento
int(*compar)( // puntatore alla funzione che esegue il confronto
const void *, // elemento da confrontare
const void *)); // elemento da confrontare
*/
/*
confronto tra due voci per determinare quale nome viene prima
*/
int name_compare(const void * xx, const void * yy)
{
Voce * x = (Voce *) xx;
Voce * y = (Voce *) yy;
return strcmp(x->nome, y->nome);
}
/*
confronto tra due voci per determinare quale cognome viene prima
*/
int surname_compare(const void * xx, const void * yy)
{
Voce * x = (Voce *) xx;
Voce * y = (Voce *) yy;
return strcmp(x->cognome, y->cognome);
}
/*
confronto tra due voci per determinare quale compleanno viene prima
*/
int birthday_compare(const void * xx, const void * yy)
{
Voce * x = (Voce *) xx;
Voce * y = (Voce *) yy;
if (x->m < y->m)
return -1;
if (x->m > y->m)
return---+1;
if (x->g < y->g)
return -1;
if (x->g > y->g)
return---+1;
return 0;
}
/*
Riconosco ed eseguo il comando 'sort nome'
*/
int sort_nome( char riga[], Voce agenda[], int quanti)
{
if (0!=strcmp(riga,"sort nome"))
return FALSE;
qsort(agenda, quanti, sizeof(Voce), name_compare);
return TRUE;
}
/*
Riconosco ed eseguo il comando 'sort cognome'
*/
int sort_cognome(char riga[], Voce agenda[], int quanti)
{
if (0!=strcmp(riga,"sort cognome"))
return FALSE;
qsort(agenda, quanti, sizeof(Voce), surname_compare);
return TRUE;
}
/*
Riconosco ed eseguo il comando 'sort compleanno'
*/
int sort_compl( char riga[], Voce agenda[], int quanti)
{
if (0!=strcmp(riga,"sort compleanno"))
return FALSE;
qsort(agenda, quanti, sizeof(Voce), birthday_compare);
return TRUE;
}
/******************************* fine *********************************/
--
AndreaSterbini - 20 Nov 2002