0

a must be simple question but I couldn't manage to do it.

I have to scan on a struct a text file with entries in this format: {"data1","data2",number1,number2}

And compute first populating a struct.

Text of the exercise: Consider the definition of the following structure

typedef struct {
char teamHome [30];
char teamHost [30];
int goalSquadraHome;
int goalSquadraOspite;
} match;

which is used to represent the result of a football match. Write a function that takes as parameters an array of games and its size e returns a result structure containing the following information: the number of games won by the home team, the number of games won by the visiting team, the number of ties, the name of the team that has scored the most goals in a match. Then write a program that, given the array containing all 380 Serie A 2019/2020 matches, print the information contained in the result.

The code is the following:

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

typedef struct{
        char squadraCasa[30];
        char squadraOspite[30];
        int golSquadraCasa;
        int golSquadraOspite;
} partita;

typedef struct {
        int partite_casa;
        int partite_ospite;
        int pareggi;
        char squad_magg_num_goal[30];
} risultato;

int main(){

FILE *fp;
risultato risultati;
int maxgoal = 0;
risultati.partite_casa = 0;
risultati.partite_ospite = 0;
risultati.pareggi = 0;
partita partite[380];
int i=0;
if((fp = fopen("partiteSerieA1920.txt","rt"))==NULL){
    printf("Errore nell'apertura del file\n");
    exit(1);
}
while(!feof(fp)){
      fscanf(fp,"{\"%s\",\"%s\",%d,%d",partite[i].squadraCasa,partite[i].squadraOspite,partite[i].golSquadraCasa,partite[i].golSquadraOspite);
      i++;
}
for(i=0;i<380;i++){
    if(partite[i].golSquadraCasa>partite[i].golSquadraOspite){
       risultati.partite_casa++;
    }else if(partite[i].golSquadraCasa<partite[i].golSquadraOspite){
       risultati.partite_ospite++;
    }else
       risultati.pareggi++;
    if(partite[i].golSquadraCasa>maxgoal){
       strncpy(partite[i].squadraCasa,risultati.squad_magg_num_goal,30);
       maxgoal = partite[i].golSquadraCasa;
    }
    if(partite[i].golSquadraOspite>maxgoal){
       strncpy(partite[i].squadraOspite, risultati.squad_magg_num_goal,30);
       maxgoal = partite[i].golSquadraOspite;  
    }
}
fclose(fp);
printf("%d %d %d %s\n",risultati.partite_casa,risultati.partite_ospite,&risultati.pareggi,&risultati.squad_magg_num_goal);
return 0;
}

Please let me know how to arrange it properly.

natale
  • 1
  • 1
  • Please describe a specific problem or error that your are facing. What is the expected behaviour vs actual behaviour of the code? One problem: In the `fscanf` you need to use `&` for the `int` fields: `&partite[i].golSquadraCasa, &partite[i].golSquadraOspite` – kaylum Nov 28 '20 at 11:02
  • There is no question in your post. Ask a specific question. – Eric Postpischil Nov 28 '20 at 11:55
  • Could you tell me something correct instead of this: {\"%s\",\"%s\",%d,%d? Thank you – natale Nov 28 '20 at 12:00
  • Note that `typedef struct {} foo` does not actually define a struct. It defines a typedef for an anonymous struct. IMO, you should simplify the code by removing all typedefs. – William Pursell Nov 28 '20 at 12:18
  • You are using `feof` incorrectly: https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong – William Pursell Nov 28 '20 at 12:19
  • Error message belong on stderr and should provide more information. That is: `if((fp = fopen("partiteSerieA1920.txt","rt"))==NULL){ perror("partiteSerieA1920.txt"); exit ...` but, don't repeat yourself: `char *path = "partite..."; if( (fp = fopen(path, "r")) == NULL ){ perror(path); exit(EXIT_FAILURE);}` – William Pursell Nov 28 '20 at 12:20

2 Answers2

0

There may be other issues, but certainly your flow control is wrong. Instead of the incorrect while/feof loop(Why is “while ( !feof (file) )” always wrong?), try something like:

partita *p = partite;
while( 4 == fscanf(fp, "{\"%29s\",\"%29s\",%d,%d",
        p->squadraCasa,
        p->squadraOspite,
        &p->golSquadraCasa,
        &p->golSquadraOspite
    ) ){ 
    p++;
}
William Pursell
  • 204,365
  • 48
  • 270
  • 300
  • it gives wrong results. This is how I modified the code: while( 4 == fscanf(fp, "{\"%30[^,]\",\"%30[^,]\",%d,%d}", p->squadraCasa, p->squadraOspite, &p->golSquadraCasa, &p->golSquadraOspite ) ){ p++; } – natale Nov 28 '20 at 14:21
  • @natale Using `%30[^,]` to read into an array of size 30 is an error. The scanf may write 31 bytes into the array. If you want the strings to be 30 bytes in lentgh, you must declare the buffers to have size (at least) 31 to have space to hold the null terminator. – William Pursell Nov 28 '20 at 17:06
0

Give this a try, its a bit of a different approach:

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

typedef struct
{
    char squadraCasa[30];
    char squadraOspite[30];
    int golSquadraCasa;
    int golSquadraOspite;
} partita;

typedef struct
{
    int partite_casa;
    int partite_ospite;
    int pareggi;
    char squad_magg_num_goal[30];
} risultato;

// solves given problem and stores results in risultato struct
risultato *getResult(partita **playedGames, int size)
{
    risultato *result = malloc(sizeof(risultato));
    result->partite_casa = 0;
    result->partite_ospite = 0;
    result->pareggi = 0;

    int currentHighest = 0;

    for (int i = 0; i < size; i++)
    {
        if (playedGames[i]->golSquadraCasa > playedGames[i]->golSquadraOspite){
            result->partite_casa++;
            if(playedGames[i]->golSquadraCasa > currentHighest ){
                currentHighest = playedGames[i]->golSquadraCasa;
                strcpy(result->squad_magg_num_goal, playedGames[i]->squadraCasa);
            }
        }
        else if (playedGames[i]->golSquadraCasa < playedGames[i]->golSquadraOspite){
            result->partite_ospite++;
            if (playedGames[i]->golSquadraOspite > currentHighest){
                currentHighest = playedGames[i]->golSquadraOspite;
                strcpy(result->squad_magg_num_goal, playedGames[i]->squadraOspite);
            }
        }
        else{
            result->pareggi++;
        }
    }

    return result;
}

// This is a custom parser of a line from the file
// data = {"data1","data2",number1,number2}
// return -> partita struct
partita *newGame(char *data){

    partita *partite = malloc(sizeof(partita));
    char* temp;

    // Get Home Team
    temp = strchr(data, ',') -1;
    temp[0] = '\0';
    strcpy(partite->squadraCasa, data + 2);
    data = temp+1;


    // Get Away Team
    temp = strchr(data+1, ',') -1;
    temp[0] = '\0';
    strcpy(partite->squadraOspite, data + 2);
    data = temp + 1;

    // Get Home Score
    temp = strchr(data + 1, ',');
    temp[0] = '\0';
    partite->golSquadraCasa = atoi(data + 1);
    data = temp + 1;

    // Get Away Score
    temp = strchr(data, '}');
    temp[0] = '\0';
    partite->golSquadraOspite = atoi(data);

        // Return game
    return partite;
}

int main()
{

    FILE *fp;
    partita **partite = malloc(sizeof(partita *)); // list of size one, currently...
    risultato *risultati;
    char linea[50];
    int indice = 0;

    if ((fp = fopen("./partiteSerieA1920.txt", "rt")) == NULL)
    {
        printf("Errore nell'apertura del file\n");
        exit(1);
    }

    // For each linea in the file, load a game into an array.
    while (fgets(linea, 50,fp))
    {
        //chomp the \n
        linea[strlen(linea)-1]='\0';

        // increase size of list
        partite = realloc(partite, sizeof(partita *) * (indice + 1));

        // insert game into array of games
        partite[indice] = newGame(linea);

        indice++;
    }

    risultati = getResult(partite, indice);

    // Print risultato
    printf("\n----RESULT----\nHome Wins: %d\nAway Wins: %d\nTies: %d\nTeam With Most Goals: %s\n\n", risultati->partite_casa, risultati->partite_ospite, risultati->pareggi, risultati->squad_magg_num_goal);

    // free all allocated memory then return
    for (int i = 0; i < indice;i++){
        free(partite[i]);
    }
    free(partite);
    free(risultati);
    fclose(fp);
    return 0;
}

I was trying to run your code but couldnt get it to parse data from the file properly so i made a quick parser for you (This is in the code above already):

partita *newGame(char *data){

    partita *partite = malloc(sizeof(partita));
    char* temp;

    // Get Home Team
    temp = strchr(data, ',') -1;
    temp[0] = '\0';
    strcpy(partite->squadraCasa, data + 2);
    data = temp+1;


    // Get Away Team
    temp = strchr(data+1, ',') -1;
    temp[0] = '\0';
    strcpy(partite->squadraOspite, data + 2);
    data = temp + 1;

    // Get Home Score
    temp = strchr(data + 1, ',');
    temp[0] = '\0';
    partite->golSquadraCasa = atoi(data + 1);
    data = temp + 1;

    // Get Away Score
    temp = strchr(data, '}');
    temp[0] = '\0';
    partite->golSquadraOspite = atoi(data);

        // Return game
    return partite;
}

You can always try to use something similar to this to parse strings or lines that you bring in as I find it is more efficient to just code something that you know works to the specification you want.

Let me know if there is some problem with the code or would like to know more about the functionality of this. I tried to keep as much of this in Italian.

Cheers