Un file di testo riporta i risultati di una serie di partite di pallacanestro, una partita per ogni riga di testo. Il formato è il seguente:
nome_squadra_1 vs nome_squadra_2 punti1 - punti2
dove
• nome squadra 1 e nome squadra 2 sono stringhe che identificano i nomi delle due squadre; le stringhe non contengono
spazi;
• vs (sta per versus) è il separatore dei due nomi;
• punti1 e punti2 sono rispettivamente il punteggio finale della prima e della seconda squadra; sono numeri interi maggiori
o uguali a zero.
Il numero di righe non è noto a priori, mentre la lunghezza massima di ciascuna stringa è pari a 80 caratteri. Il file contiene
almeno una linea.
Stampare il nome di tutte le squadre che compaiono nel file. Il nome di ogni squadra deve essere stampato una sola volta,
nell’ordine di apparizione della squadra nel file.
Stampare il risultato con il seguente formato:
[SQUADRE]
nome_squadra_1
nome_squadra_2
nome_squadra_3
...
Il suddetto file di testo è il seguente:
Rockets vs Warriors 102 - 91
Lakers vs Pistons 78 - 89
Pistons vs Rockets 90 - 88
Warriors vs Celtics 102 - 90
Clippers vs Warriors 68 - 72
Ora, ecco il codice che ho scritto:
- Codice:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct partita {
char sq1[20];
char sq2[20];
int pt1;
int pt2;
};
int search(int nsq, char *nomisq, char *x)
{
int j=0;
while ((j<nsq) && (strcmp(nomisq[j], x)))
j++;
if (j<nsq) //successo, corrispondenza trovata
return 0;
else //insuccesso, corrispondenza non trovata
return 1;
}
int main (int argc, char *argv[])
{
struct partita *vect;
FILE *infile;
char buf[81];
int npart = 5; //numero di partite nel file (righe da leggere). 5 provvisorio, se necessario rialloco
int i = 0, tok, j; //numero righe lette, numero token convertiti, gestione cicli
if (argc != 2) { //controllo sulla correttezza degli argomenti del main
printf("inserire come unico argomento il nome del file da leggere\n");
return 2;
}
if (!(infile = fopen(argv[1], "r"))) { //apertura del file + controllo
printf("impossibile aprire il file specificato\n");
return -1;
}
if (!(vect = malloc(npart * sizeof(*vect)))) { //allocazione memoria + controllo
printf("impossibile allocare memoria per la creazione delle strutture\n");
return 1;
}
/* Ciclo di lettura */
while (fgets(buf, sizeof(buf), infile)) {
tok = sscanf(buf, "%s vs %s %d - %d", vect[i].sq1, vect[i].sq2, &vect[i].pt1, &vect[i].pt2);
if (tok != 4) { //controllo sul numero di token convertiti
printf("errore scansione token\n");
return -1;
}
if (i+1 >= npart) { //controllo numero di righe lette
npart *= 2;
if (!(vect = realloc(vect, npart * sizeof(*vect)))) {
free(vect);
printf("impossibile riallocare memoria per la creazione delle strutture\n");
return 1;
}
}
i++;
}
vect = realloc(vect, i * sizeof(*vect)); //sapendo ora esattamente quante righe devo leggere, rialloco la memoria una ultima volta per evitare sprechi
/* Ciclo di stampa delle strutture */
printf("STRUTTURE LETTE:\n");
for (j=0; j<i; j++) {
printf("%s v %s: %d - %d\n", vect[j].sq1, vect[j].sq2, vect[j].pt1, vect[j].pt2);
}
printf("******************\n\n");
/* 4) Squadre */
int nsq = (i * 2); //Non conosco a priori il numero di squadre, ma al limite possono essercene due nuove a ogni partita (i è il numero di partite giocate)
char *nomisq[nsq]; //Questo vettore di (puntatori a) stringhe conterrà le diverse squadre. Le prime due le inizializzo io, tanto sono diverse per forza
nomisq[0] = vect[0].sq1;
nomisq[1] = vect[0].sq2;
char *ptr;
ptr = nomisq+2; //ptr punta al terzo elemento di nomisq
for(j=1; j<i; j++) {
if(search(nsq, nomisq, vect[j].sq1)) {
*ptr = vect[j].sq1;
ptr++;
}
if(search(nsq, nomisq, vect[j].sq2)) {
*ptr = vect[j].sq2;
ptr++;
}
}
printf("[SQUADRE]\n");
for(j=1; j<nsq; j++) {
printf("%s\n", nomisq[j]);
}
free(vect);
fclose(infile);
return 0;
}
Sono riuscito a scrivere correttamente il codice per la lettura e l'immagazzinamento dei file in un array di strutture, che infatti vengono stampate a video correttamente così come sono scritte nel file.
Per la stampa dei nomi delle squadre invece, ho pensato di creare un array di stringhe, che viene a mano a mano riempito. I primi due elementi li ho inizializzati a mano, perchè le prime due squadre (della prima partita) sono necessariamente diverse. Poi ho puntato un puntatore al terzo elemento.
Per il resto ho pensato: un ciclo for scansiona una a una tutte le strutture (cioè tutte le partite). Per ogni j-esima partita quindi chiama la funzione search, la quale implementa un semplice algoritmo di ricerca: scansiona tutto il mio array nomisq e confronta ogni elemento con quello passato come argomento (una delle due squadre della j-esima partita): se trova corrispondenza riporta 0, altrimenti 1. Se non viene trovata corrispondenza significa che quella squadra non è ancora presente nel vettore, e quindi va aggiunta: l'elemento puntato da ptr deve allora venire aggiornato, puntando a quella squadra. Poi ptr viene fatto puntare allo slot successivo di nomisq (ptr++). Se invece la search riporta un valore nullo (ovvero c'è già un nome uguale nel vettore), non si fa nulla, ma si passa al prossimo nome.
Ecco il risultato della compilazione:
marco@Marco-VirtualBox:~/Documenti/22-03-2016$ gcc -Wall -o Svolg220316 Svolg220316.c
Svolg220316.c: In function ‘search’:
Svolg220316.c:16:28: warning: passing argument 1 of ‘strcmp’ makes pointer from integer without a cast [-Wint-conversion]
while ((j<nsq) && (strcmp(nomisq[j], x)))
^~~~~~
In file included from Svolg220316.c:3:0:
/usr/include/string.h:140:12: note: expected ‘const char *’ but argument is of type ‘char’
extern int strcmp (const char *__s1, const char *__s2)
^~~~~~
Svolg220316.c: In function ‘main’:
Svolg220316.c:121:6: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
ptr = nomisq+2; //ptr punta al terzo elemento di nomisq
^
Svolg220316.c:124:18: warning: passing argument 2 of ‘search’ from incompatible pointer type [-Wincompatible-pointer-types]
if(search(nsq, nomisq, vect[j].sq1)) {
^~~~~~
Svolg220316.c:12:5: note: expected ‘char *’ but argument is of type ‘char **’
int search(int nsq, char *nomisq, char *x)
^~~~~~
Svolg220316.c:125:9: warning: assignment makes integer from pointer without a cast [-Wint-conversion]
*ptr = vect[j].sq1;
^
Svolg220316.c:128:18: warning: passing argument 2 of ‘search’ from incompatible pointer type [-Wincompatible-pointer-types]
if(search(nsq, nomisq, vect[j].sq2)) {
^~~~~~
Svolg220316.c:12:5: note: expected ‘char *’ but argument is of type ‘char **’
int search(int nsq, char *nomisq, char *x)
^~~~~~
Svolg220316.c:129:9: warning: assignment makes integer from pointer without a cast [-Wint-conversion]
*ptr = vect[j].sq2;
^
Sapreste dirmi cosa sbaglio?