Tema 6 - Estructures i Fitxers

Struct Medicament

Defineix una struct Medicament amb nom, dosi i preu. Crea 3 medicaments i mostra'ls per pantalla.

#include <stdio.h>  /* Inclou la biblioteca estàndard d'entrada/sortida */
                     /* Necessària per a printf() */
#include <string.h>  /* Inclou la biblioteca per a funcions de cadenes */
                     /* Necessària per a strcpy() */

/* Definició de l'estructura Medicament */
/* Una estructura (struct) agrupa variables de diferents tipus sota un sol nom */
/* Cada variable dins de l'estructura s'anomena "camp" o "membre" */
struct Medicament {  /* 'struct Medicament' és el nom del tipus */
    char nom[50];    /* Camp per al nom del medicament (cadena de fins a 49 caràcters + '\0') */
                     /* Es reserva espai fix dins de l'estructura */
    float dosi;      /* Camp per a la dosi en mg (nombre decimal) */
                     /* float ocupa 4 bytes en memòria */
    float preu;      /* Camp per al preu en euros (nombre decimal) */
};  /* El punt i coma al final és obligatori en la definició d'estructures */

/* Funció auxiliar per mostrar un medicament */
/* Rep un punter a struct Medicament per evitar copiar tota l'estructura */
/* const indica que la funció no modificarà les dades */
void mostrar_medicament(const struct Medicament *med){  /* Paràmetre: punter constant a Medicament */
    printf("  Nom:  %s\n", med->nom);  /* Accedeix al camp 'nom' amb l'operador fletxa (->) */
                                       /* med->nom és equivalent a (*med).nom */
                                       /* L'operador -> s'usa amb punters a estructures */
    printf("  Dosi: %.2f mg\n", med->dosi);  /* Mostra la dosi amb 2 decimals */
    printf("  Preu: %.2f euros\n", med->preu);  /* Mostra el preu amb 2 decimals */
}

int main(){  /* Funció principal del programa */

    /* Declaració i inicialització de 3 medicaments */
    /* Es poden inicialitzar camps en la declaració amb claus {} */
    struct Medicament med1 = {"Paracetamol", 500.0, 3.50};  /* Inicialització completa */
                                                            /* Els valors s'assignen en ordre: nom, dosi, preu */
    struct Medicament med2 = {"Ibuprofen", 600.0, 5.75};    /* Segon medicament */
    struct Medicament med3;  /* Declaració sense inicialitzar */
                             /* Els camps contenen valors indeterminats (escombraries) */

    /* Assignació de valors als camps un per un */
    strcpy(med3.nom, "Amoxicilina");  /* strcpy() copia la cadena al camp nom */
                                      /* No es pot fer med3.nom = "Amoxicilina" perquè és un array */
    med3.dosi = 250.0;   /* Assigna la dosi amb l'operador punt (.) */
                          /* L'operador . s'usa amb variables d'estructura (no punters) */
    med3.preu = 8.20;    /* Assigna el preu */

    /* Mostra els medicaments per pantalla */
    printf("=== FARMACIA - LLISTAT DE MEDICAMENTS ===\n\n");

    printf("Medicament 1:\n");  /* Etiqueta */
    mostrar_medicament(&med1);  /* Passa l'adreça de med1 a la funció */
                                /* &med1 obté el punter a l'estructura */
    printf("\n");

    printf("Medicament 2:\n");
    mostrar_medicament(&med2);  /* Passa l'adreça de med2 */
    printf("\n");

    printf("Medicament 3:\n");
    mostrar_medicament(&med3);  /* Passa l'adreça de med3 */
    printf("\n");

    /* Càlcul del preu total dels 3 medicaments */
    float preu_total = med1.preu + med2.preu + med3.preu;  /* Suma els camps preu */
    printf("Preu total dels 3 medicaments: %.2f euros\n", preu_total);

    /* Mostra la mida de l'estructura en bytes */
    printf("\nInformacio tecnica:\n");
    printf("  Mida de struct Medicament: %d bytes\n", (int)sizeof(struct Medicament));
    /* sizeof() retorna la mida total de l'estructura en bytes */
    /* Inclou possibles bytes de farciment (padding) per alineació */

    return 0;  /* Finalitza el programa amb èxit */
}

Fitxer de pacients

Escriu un programa que guardi en un fitxer de text les dades de 5 pacients (nom, edat, diagnòstic) i després les torni a llegir.

#include <stdio.h>  /* Inclou la biblioteca estàndard d'entrada/sortida */
                     /* Necessària per a printf(), scanf(), fopen(), fprintf(), fscanf(), fclose() */
#include <string.h>  /* Inclou la biblioteca per a funcions de cadenes */

/* Definició de l'estructura Pacient */
struct Pacient {  /* Agrupa les dades d'un pacient */
    char nom[50];       /* Nom del pacient (fins a 49 caràcters) */
    int edat;           /* Edat del pacient (nombre enter) */
    char diagnostic[100]; /* Diagnòstic (fins a 99 caràcters) */
};

/* Funció per escriure les dades dels pacients a un fitxer */
/* Rep un array de pacients i el nombre de pacients */
void escriure_fitxer(struct Pacient pacients[], int n){  /* Array d'estructures i mida */
    /* Obre el fitxer en mode escriptura ("w") */
    FILE *fitxer = fopen("pacients.txt", "w");  /* fopen() obre/crea un fitxer */
                                                /* "pacients.txt": nom del fitxer */
                                                /* "w": mode escriptura (write) */
                                                /* Si el fitxer existeix, es sobreescriu */
                                                /* Si no existeix, es crea */

    if(fitxer == NULL){  /* Verifica que el fitxer s'ha obert correctament */
                         /* fopen() retorna NULL si hi ha error */
        printf("Error: No s'ha pogut crear el fitxer pacients.txt\n");
        return;  /* Surt de la funció sense fer res més */
    }

    printf("Escrivint dades al fitxer...\n");

    /* Escriu una capçalera al fitxer */
    fprintf(fitxer, "=== LLISTAT DE PACIENTS ===\n\n");  /* fprintf() escriu text formatat al fitxer */
                                                         /* Funciona igual que printf() però sobre un fitxer */

    /* Bucle per escriure cada pacient */
    for(int i = 0; i < n; i++){  /* Recorre l'array de pacients */
        /* Escriu les dades del pacient en format estructurat */
        fprintf(fitxer, "Pacient %d:\n", i + 1);  /* Número de pacient */
        fprintf(fitxer, "  Nom: %s\n", pacients[i].nom);  /* Nom */
        fprintf(fitxer, "  Edat: %d anys\n", pacients[i].edat);  /* Edat */
        fprintf(fitxer, "  Diagnostic: %s\n", pacients[i].diagnostic);  /* Diagnòstic */
        fprintf(fitxer, "\n");  /* Línia en blanc entre pacients */
    }

    fclose(fitxer);  /* Tanca el fitxer */
                     /* És MOLT IMPORTANT tancar el fitxer: assegura que les dades s'escriguin al disc */
                     /* Si no es tanca, es poden perdre dades */
    printf("Fitxer 'pacients.txt' creat correctament!\n");
}

/* Funció per llegir les dades dels pacients des del fitxer */
void llegir_fitxer(){  /* No rep paràmetres, llegeix directament del fitxer */
    /* Obre el fitxer en mode lectura ("r") */
    FILE *fitxer = fopen("pacients.txt", "r");  /* "r": mode lectura (read) */
                                                /* El fitxer ha d'existir */

    if(fitxer == NULL){  /* Si el fitxer no es pot obrir (no existeix, permisos, etc.) */
        printf("Error: No s'ha pogut obrir el fitxer pacients.txt\n");
        printf("  Assegura't que el fitxer existeix.\n");
        return;
    }

    printf("\nLlegint dades del fitxer...\n");
    printf("========================================\n");

    char linia[200];  /* Buffer per llegir cada línia del fitxer */
                      /* 200 caràcters és suficient per a una línia */

    /* Bucle per llegir el fitxer línia per línia */
    /* fgets() llegeix una línia completa (fins a newline o final de fitxer) */
    while(fgets(linia, sizeof(linia), fitxer) != NULL){  /* Mentre hi hagi línies per llegir */
                                                          /* fgets() retorna NULL quan arriba al final del fitxer */
                                                          /* sizeof(linia) és la mida màxima a llegir (200) */
        printf("%s", linia);  /* Mostra la línia llegida */
                              /* No cal \n perquè fgets() inclou el salt de línia */
    }

    fclose(fitxer);  /* Tanca el fitxer després de llegir */
    printf("========================================\n");
}

int main(){  /* Funció principal */

    /* Declara i inicialitza un array de 5 pacients */
    struct Pacient pacients[5] = {  /* Array de 5 estructures Pacient */
        {"Anna Garcia",   35, "Hipertensio arterial"},  /* Pacient 0 */
        {"Joan Martinez", 42, "Diabetis tipus 2"},      /* Pacient 1 */
        {"Maria Lopez",   28, "Migranya cronica"},      /* Pacient 2 */
        {"Pere Sanchez",  55, "Artrosi de genoll"},     /* Pacient 3 */
        {"Laura Vidal",   31, "Asma bronquial"}         /* Pacient 4 */
    };

    /* Mostra les dades en memòria */
    printf("=== DADES DELS PACIENTS EN MEMORIA ===\n");
    for(int i = 0; i < 5; i++){
        printf("Pacient %d: %s, %d anys - %s\n", 
               i + 1, pacients[i].nom, pacients[i].edat, pacients[i].diagnostic);
    }

    /* Escriu les dades al fitxer */
    printf("\n");
    escriure_fitxer(pacients, 5);  /* Passa l'array i el nombre d'elements */

    /* Llegeix i mostra el contingut del fitxer */
    llegir_fitxer();  /* No necessita paràmetres, llegeix directament */

    /* Demostració addicional: llegir amb fscanf() (lectura formatada) */
    printf("\n=== LECTURA AMB FSCANF (DEMOSTRACIO) ===\n");
    FILE *fitxer2 = fopen("pacients.txt", "r");
    if(fitxer2 != NULL){
        struct Pacient pacient_llegit;  /* Estructura temporal per llegir */
        char temp[100];  /* Buffer per a text no rellevant */

        /* Llegeix ignorant les línies de capçalera */
        fgets(temp, 100, fitxer2);  /* Línia "=== LLISTAT..." */
        fgets(temp, 100, fitxer2);  /* Línia en blanc */

        /* Intenta llegir 5 pacients amb fscanf() */
        for(int i = 0; i < 5; i++){
            /* fscanf() llegeix dades formatades d'un fitxer */
            /* El format ha de coincidir exactament amb com es va escriure */
            int llegits = fscanf(fitxer2, "Pacient %*d:\n  Nom: %[^\n]\n  Edat: %d anys\n  Diagnostic: %[^\n]\n\n",
                   pacient_llegit.nom, &pacient_llegit.edat, pacient_llegit.diagnostic);
            /* %*d: llegeix un enter però l'ignora (el número de pacient) */
            /* %[^\n]: llegeix tots els caràcters fins a newline (per noms amb espais) */

            if(llegits == 3){  /* Si s'han llegit els 3 camps correctament */
                printf("Llegit: %s, %d anys - %s\n", 
                       pacient_llegit.nom, pacient_llegit.edat, pacient_llegit.diagnostic);
            }
        }
        fclose(fitxer2);
    }

    return 0;  /* Finalitza el programa amb èxit */
}

Percentatge d'aminoàcids hidrofòbics

Amplia l'exemple de proteïnes per calcular també el percentatge d'aminoàcids hidrofòbics (A, V, L, I, P, F, W, M) i guarda el resultat en un fitxer de sortida.

#include <stdio.h>  /* Inclou la biblioteca estàndard d'entrada/sortida */
                     /* Necessària per a printf() i gestió de fitxers */
#include <string.h>  /* Inclou la biblioteca per a funcions de cadenes */
                     /* Necessària per a strlen() */
#include <ctype.h>   /* Inclou la biblioteca per a classificació de caràcters */
                     /* Necessària per a toupper() */

/* Estructura per emmagatzemar informació d'una proteïna */
struct Proteina {  /* Agrupa les dades rellevants d'una proteïna */
    char nom[50];          /* Nom o identificador de la proteïna */
    char sequencia[500];   /* Seqüència d'aminoàcids (fins a 499 caràcters) */
                           /* En una aplicació real, podria ser memòria dinàmica */
    int longitud;          /* Longitud de la seqüència (nombre d'aminoàcids) */
    int hidrofobics;       /* Nombre d'aminoàcids hidrofòbics */
    float pct_hidrofobics; /* Percentatge d'aminoàcids hidrofòbics */
};

/* Funció per comprovar si un aminoàcid és hidrofòbic */
/* Retorna 1 (cert) si ho és, 0 (fals) si no */
int es_hidrofobic(char aa){  /* Rep un caràcter (aminoàcid en codi d'una lletra) */
    /* Converteix a majúscula per fer la comprovació insensible a majúscules/minúscules */
    aa = toupper(aa);  /* toupper() retorna la versió majúscula del caràcter */

    /* Comprova si l'aminoàcid és un dels 8 hidrofòbics */
    /* Aminoàcids hidrofòbics: Alanina(A), Valina(V), Leucina(L), Isoleucina(I),
       Prolina(P), Fenilalanina(F), Triptòfan(W), Metionina(M) */
    if(aa == 'A' || aa == 'V' || aa == 'L' || aa == 'I' ||
       aa == 'P' || aa == 'F' || aa == 'W' || aa == 'M')
        return 1;  /* És hidrofòbic */
    else
        return 0;  /* No és hidrofòbic (és hidrofílic o altre) */
}

/* Funció per analitzar una proteïna i omplir els seus camps calculats */
void analitzar_proteina(struct Proteina *prot){  /* Rep un punter per modificar l'estructura */
    prot->longitud = strlen(prot->sequencia);  /* Calcula la longitud amb strlen() */
                                               /* -> accedeix als camps a través del punter */

    prot->hidrofobics = 0;  /* Inicialitza el comptador a 0 */

    /* Bucle per comptar els aminoàcids hidrofòbics */
    for(int i = 0; i < prot->longitud; i++){  /* Recorre tota la seqüència */
        if(es_hidrofobic(prot->sequencia[i]))  /* Comprova cada aminoàcid */
            prot->hidrofobics++;  /* Incrementa el comptador si és hidrofòbic */
    }

    /* Calcula el percentatge d'hidrofòbics */
    if(prot->longitud > 0)  /* Evita la divisió per zero */
        prot->pct_hidrofobics = (float)prot->hidrofobics / prot->longitud * 100;
    else
        prot->pct_hidrofobics = 0.0;  /* Si no hi ha seqüència, percentatge 0 */
}

/* Funció per mostrar l'anàlisi per pantalla */
void mostrar_analisi(const struct Proteina *prot){  /* const: no modifica l'estructura */
    printf("Proteina: %s\n", prot->nom);
    printf("  Sequencia: %s\n", prot->sequencia);
    printf("  Longitud: %d aminoacids\n", prot->longitud);
    printf("  Hidrofobics: %d (%.1f%%)\n", prot->hidrofobics, prot->pct_hidrofobics);
    printf("  Hidrofilics: %d (%.1f%%)\n", 
           prot->longitud - prot->hidrofobics, 100.0 - prot->pct_hidrofobics);
    /* Els hidrofílics són la resta d'aminoàcids */
}

/* Funció per guardar l'anàlisi en un fitxer */
void guardar_analisi_fitxer(struct Proteina proteines[], int n, const char* nom_fitxer){
    /* Obre el fitxer en mode escriptura */
    FILE *fitxer = fopen(nom_fitxer, "w");  /* El nom del fitxer es rep com a paràmetre */

    if(fitxer == NULL){
        printf("Error: No s'ha pogut crear el fitxer %s\n", nom_fitxer);
        return;
    }

    /* Escriu la capçalera del fitxer */
    fprintf(fitxer, "========================================\n");
    fprintf(fitxer, "  ANALISI D'AMINOACIDS HIDROFOBICS\n");
    fprintf(fitxer, "========================================\n\n");

    /* Escriu un resum tabulat */
    fprintf(fitxer, "%-20s %8s %10s %10s\n", "PROTEINA", "LONGITUD", "HIDROFOBICS", "%HIDROFOB.");
    /* %-20s: cadena de 20 caràcters alineada a l'esquerra */
    /* %8s, %10s: columnes de 8 i 10 caràcters alineades a la dreta */
    fprintf(fitxer, "----------------------------------------\n");

    /* Escriu les dades de cada proteïna */
    for(int i = 0; i < n; i++){
        fprintf(fitxer, "%-20s %8d %10d %9.1f%%\n",
                proteines[i].nom,
                proteines[i].longitud,
                proteines[i].hidrofobics,
                proteines[i].pct_hidrofobics);
    }

    fprintf(fitxer, "----------------------------------------\n\n");

    /* Escriu el detall de cada proteïna */
    for(int i = 0; i < n; i++){
        fprintf(fitxer, "Proteina: %s\n", proteines[i].nom);
        fprintf(fitxer, "  Sequencia: %s\n", proteines[i].sequencia);

        /* Mostra la seqüència marcant els hidrofòbics amb asterisc */
        fprintf(fitxer, "  Marcatge:  ");
        for(int j = 0; j < proteines[i].longitud; j++){
            fprintf(fitxer, "%c", proteines[i].sequencia[j]);
        }
        fprintf(fitxer, "\n  Hidrofob:  ");
        for(int j = 0; j < proteines[i].longitud; j++){
            if(es_hidrofobic(proteines[i].sequencia[j]))
                fprintf(fitxer, "*");  /* Asterisc per als hidrofòbics */
            else
                fprintf(fitxer, " ");  /* Espai per als no hidrofòbics */
        }
        fprintf(fitxer, "\n\n");
    }

    fclose(fitxer);  /* Tanca el fitxer */
    printf("Fitxer '%s' creat correctament!\n", nom_fitxer);
}

int main(){  /* Funció principal */

    /* Declara i inicialitza 3 proteïnes d'exemple */
    struct Proteina proteines[3] = {
        {"Insulina",     "MALWMRLLPLLALLALWGPDPAAAFVNQHLCGSHLVEALYLVCGERGFFYTPKT", 0, 0, 0.0},
        /* Seqüència real de la insulina humana (cadena B + C + A simplificada) */
        {"Hemoglobina_A", "MVLSPADKTNVKAAWGKVGAHAGEYGAEALERMFLSFPTTKTYFPHFDLSHGSAQVKGHGKKVADALTNAVAHVDDMPNALSALSDLHAHKLRVDPVNFKLLSHCLLVTLAAHLPAEFTPAVHASLDKFLASVSTVLTSKYR", 0, 0, 0.0},
        /* Fragment de la cadena alfa de l'hemoglobina */
        {"Colagen",      "GPMGPMGPMGPMGPMGPMGPMGPMGPMGPMGPMGPMGPMGPMGPMGPMGPMGPMGPMGPMGPM", 0, 0, 0.0}
        /* Seqüència repetitiva típica del col·lagen (Gly-Pro-Met) */
    };

    int num_proteines = 3;  /* Nombre de proteïnes a analitzar */

    /* Analitza cada proteïna */
    for(int i = 0; i < num_proteines; i++){
        analitzar_proteina(&proteines[i]);  /* Passa l'adreça per modificar l'estructura */
    }

    /* Mostra els resultats per pantalla */
    printf("=== ANALISI D'AMINOACIDS HIDROFOBICS ===\n\n");
    for(int i = 0; i < num_proteines; i++){
        mostrar_analisi(&proteines[i]);
        printf("\n");
    }

    /* Guarda els resultats al fitxer */
    guardar_analisi_fitxer(proteines, num_proteines, "analisi_hidrofobics.txt");

    /* Llegeix i mostra el contingut del fitxer creat */
    printf("\n=== CONTINGUT DEL FITXER GENERAT ===\n");
    FILE *fitxer = fopen("analisi_hidrofobics.txt", "r");
    if(fitxer != NULL){
        char linia[200];
        while(fgets(linia, sizeof(linia), fitxer) != NULL){
            printf("%s", linia);  /* Mostra cada línia */
        }
        fclose(fitxer);
    }

    return 0;  /* Finalitza el programa amb èxit */
}

Mini Projecte – Lectura automàtica de múltiples proteïnes

Escriu un programa que llegeixi un fitxer FASTA, analitzi múltiples proteïnes i generi un informe.

#include <stdio.h>  /* Inclou la biblioteca estàndard d'entrada/sortida */
                     /* Necessària per a printf(), fopen(), fprintf(), fgets(), fclose() */
#include <stdlib.h>  /* Inclou la biblioteca estàndard */
                     /* Necessària per a malloc(), realloc(), free(), atof() */
#include <string.h>  /* Inclou la biblioteca per a funcions de cadenes */
                     /* Necessària per a strlen(), strcpy(), strcat(), strchr() */
#include <ctype.h>   /* Inclou la biblioteca per a classificació de caràcters */
                     /* Necessària per a toupper(), isspace() */

/* Constants del programa */
#define MAX_PROTEINES 50     /* Nombre màxim de proteïnes a processar */
#define MAX_NOM 100          /* Longitud màxima del nom d'una proteïna */
#define MAX_LINIA 1000       /* Longitud màxima d'una línia del fitxer */

/* Definició de l'estructura Proteina com a tipus global amb typedef */
/* typedef crea un àlies: podem usar 'Proteina' en lloc de 'struct Proteina' */
typedef struct {  /* Estructura per emmagatzemar una proteïna completa */
    char nom[MAX_NOM];         /* Nom o capçalera de la proteïna (sense el '>') */
    char *sequencia;           /* Punter a la seqüència (memòria dinàmica) */
                               /* S'usa memòria dinàmica perquè la longitud pot variar */
    int longitud;              /* Longitud de la seqüència (nombre d'aminoàcids) */
    float pes_molecular;       /* Pes molecular aproximat en Daltons (Da) */
    int carregats;             /* Nombre d'aminoàcids carregats (K, R, D, E) */
    float pct_carregats;       /* Percentatge d'aminoàcids carregats */
    int hidrofobics;           /* Nombre d'aminoàcids hidrofòbics */
    float pct_hidrofobics;     /* Percentatge d'aminoàcids hidrofòbics */
} Proteina;  /* 'Proteina' és ara un nom de tipus vàlid */

/* Array global de proteïnes */
Proteina proteines[MAX_PROTEINES];  /* Array d'estructures Proteina */
int total_proteines = 0;            /* Comptador de proteïnes llegides */

/* Prototips de les funcions principals */
int llegirProteines(const char* nom_fitxer);  /* Llegeix proteïnes d'un fitxer FASTA */
                                              /* Retorna el nombre de proteïnes llegides */
void calcularEstadistiques();                  /* Calcula estadístiques per a cada proteïna */
void escriureInforme(const char* nom_fitxer);  /* Genera el fitxer d'informe */
void alliberarMemoria();                       /* Allibera tota la memòria dinàmica */

/* Funcions auxiliars per al càlcul de propietats */
int es_carregat(char aa);        /* Comprova si un aminoàcid és carregat (K,R,D,E) */
int es_hidrofobic(char aa);      /* Comprova si un aminoàcid és hidrofòbic */
float pes_aminoacid(char aa);    /* Retorna el pes molecular d'un aminoàcid */

int main(){  /* Funció principal del programa */

    char nom_fitxer_entrada[100];  /* Nom del fitxer FASTA a llegir */

    printf("========================================\n");
    printf("  ANALITZADOR DE PROTEINES (FASTA)\n");
    printf("========================================\n\n");

    /* Demana el nom del fitxer d'entrada */
    printf("Nom del fitxer FASTA d'entrada: ");
    scanf("%99s", nom_fitxer_entrada);

    /* Pas 1: Llegir les proteïnes del fitxer */
    printf("\nLlegint proteines de '%s'...\n", nom_fitxer_entrada);
    int llegides = llegirProteines(nom_fitxer_entrada);

    if(llegides == 0){  /* Si no s'ha llegit cap proteïna */
        printf("No s'han trobat proteïnes al fitxer.\n");
        printf("Assegura't que el fitxer existeix i te format FASTA correcte.\n");
        return 1;  /* Surt amb error */
    }

    printf("S'han llegit %d proteines correctament.\n", llegides);

    /* Pas 2: Calcular estadístiques */
    printf("\nCalculant estadistiques...\n");
    calcularEstadistiques();

    /* Mostra un resum per pantalla */
    printf("\n=== RESUM PER PANTALLA ===\n");
    printf("%-20s %8s %10s %10s %10s\n", "PROTEINA", "LONGITUD", "PES (Da)", "%CARREGATS", "%HIDROFOB.");
    printf("------------------------------------------------------------\n");
    for(int i = 0; i < total_proteines; i++){
        printf("%-20s %8d %10.1f %9.1f%% %9.1f%%\n",
               proteines[i].nom,
               proteines[i].longitud,
               proteines[i].pes_molecular,
               proteines[i].pct_carregats,
               proteines[i].pct_hidrofobics);
    }

    /* Pas 3: Generar l'informe */
    printf("\nGenerant informe...\n");
    escriureInforme("resum_proteines.txt");

    /* Allibera la memòria dinàmica */
    alliberarMemoria();
    printf("Memoria alliberada. Programa finalitzat.\n");

    return 0;  /* Finalitza amb èxit */
}

/* Funció per llegir proteïnes d'un fitxer en format FASTA */
int llegirProteines(const char* nom_fitxer){
    /* Obre el fitxer en mode lectura */
    FILE *fitxer = fopen(nom_fitxer, "r");  /* "r": mode lectura */
    if(fitxer == NULL){
        printf("Error: No s'ha pogut obrir el fitxer '%s'.\n", nom_fitxer);
        return 0;  /* Retorna 0 proteïnes llegides */
    }

    char linia[MAX_LINIA];      /* Buffer per a cada línia del fitxer */
    char sequencia_temp[10000]; /* Buffer temporal per construir la seqüència */
                                /* En producció, s'usaria memòria dinàmica incremental */
    int dins_proteina = 0;      /* Bandera: indica si estem processant una proteïna */
                                /* 0 = no, 1 = sí */

    total_proteines = 0;  /* Inicialitza el comptador global */

    /* Bucle de lectura línia per línia */
    while(fgets(linia, MAX_LINIA, fitxer) != NULL && total_proteines < MAX_PROTEINES){
        /* fgets() llegeix fins a newline, final de fitxer o MAX_LINIA-1 caràcters */
        /* Retorna NULL quan arriba al final del fitxer */

        /* Elimina el salt de línia final si existeix */
        int len = strlen(linia);
        if(len > 0 && linia[len-1] == '\n')
            linia[len-1] = '\0';  /* Substitueix '\n' per '\0' */

        /* Comprova si la línia és una capçalera FASTA (comença amb '>') */
        if(linia[0] == '>'){  /* Format FASTA: >nom_de_la_proteina */
            /* Si ja estàvem processant una proteïna, la guardem */
            if(dins_proteina && total_proteines < MAX_PROTEINES){
                /* Reserva memòria exacta per a la seqüència */
                int long_seq = strlen(sequencia_temp);
                proteines[total_proteines].sequencia = (char*)malloc((long_seq + 1) * sizeof(char));
                /* malloc() reserva memòria per a la seqüència + '\0' */

                if(proteines[total_proteines].sequencia != NULL){
                    strcpy(proteines[total_proteines].sequencia, sequencia_temp);
                    /* Copia la seqüència acumulada a la memòria dinàmica */
                }
                total_proteines++;  /* Incrementa el comptador */
            }

            /* Inicia una nova proteïna */
            /* Copia el nom sense el caràcter '>' inicial */
            strcpy(proteines[total_proteines].nom, linia + 1);
            /* linia + 1: punter al segon caràcter (saltant el '>') */

            proteines[total_proteines].sequencia = NULL;  /* Encara no té seqüència */
            proteines[total_proteines].longitud = 0;
            sequencia_temp[0] = '\0';  /* Reinicia el buffer de seqüència */
            dins_proteina = 1;  /* Marca que estem dins d'una proteïna */

        } else if(dins_proteina && strlen(linia) > 0){  /* Línia de seqüència */
            /* Concatena la línia al buffer de seqüència */
            strcat(sequencia_temp, linia);  /* strcat() afegeix al final */
            /* Nota: cal assegurar que sequencia_temp té prou espai */
        }
    }

    /* Guarda l'última proteïna (si n'hi ha) */
    if(dins_proteina && total_proteines < MAX_PROTEINES){
        int long_seq = strlen(sequencia_temp);
        proteines[total_proteines].sequencia = (char*)malloc((long_seq + 1) * sizeof(char));
        if(proteines[total_proteines].sequencia != NULL){
            strcpy(proteines[total_proteines].sequencia, sequencia_temp);
        }
        total_proteines++;
    }

    fclose(fitxer);  /* Tanca el fitxer */
    return total_proteines;  /* Retorna el nombre de proteïnes llegides */
}

/* Funció per calcular estadístiques de totes les proteïnes */
void calcularEstadistiques(){
    for(int i = 0; i < total_proteines; i++){  /* Per a cada proteïna */
        if(proteines[i].sequencia == NULL) continue;  /* Salta si no té seqüència */

        proteines[i].longitud = strlen(proteines[i].sequencia);
        proteines[i].carregats = 0;
        proteines[i].hidrofobics = 0;
        proteines[i].pes_molecular = 0.0;

        /* Analitza cada aminoàcid de la seqüència */
        for(int j = 0; j < proteines[i].longitud; j++){
            char aa = toupper(proteines[i].sequencia[j]);  /* Converteix a majúscula */

            /* Comptatge d'aminoàcids carregats */
            if(es_carregat(aa))
                proteines[i].carregats++;

            /* Comptatge d'aminoàcids hidrofòbics */
            if(es_hidrofobic(aa))
                proteines[i].hidrofobics++;

            /* Acumulació del pes molecular */
            proteines[i].pes_molecular += pes_aminoacid(aa);
        }

        /* Càlcul de percentatges */
        if(proteines[i].longitud > 0){
            proteines[i].pct_carregats = (float)proteines[i].carregats / proteines[i].longitud * 100;
            proteines[i].pct_hidrofobics = (float)proteines[i].hidrofobics / proteines[i].longitud * 100;
        }
    }
}

/* Funció per generar l'informe en un fitxer de text */
void escriureInforme(const char* nom_fitxer){
    FILE *fitxer = fopen(nom_fitxer, "w");  /* Obre en mode escriptura */
    if(fitxer == NULL){
        printf("Error: No s'ha pogut crear el fitxer '%s'.\n", nom_fitxer);
        return;
    }

    /* Capçalera de l'informe */
    fprintf(fitxer, "================================================================\n");
    fprintf(fitxer, "           INFORME D'ANALISI DE PROTEINES\n");
    fprintf(fitxer, "================================================================\n\n");
    fprintf(fitxer, "Data de l'informe: (automatic)\n");
    fprintf(fitxer, "Nombre de proteines analitzades: %d\n\n", total_proteines);

    /* Taula resum */
    fprintf(fitxer, "--- TAULA RESUM ---\n\n");
    fprintf(fitxer, "%-25s %8s %12s %10s %10s %10s\n", 
            "PROTEINA", "LONGITUD", "PES MOLEC.", "%CARREGATS", "%HIDROFOB.", "CARREGA");
    fprintf(fitxer, "%-25s %8s %12s %10s %10s %10s\n", 
            "-------------------------", "--------", "------------", "----------", "----------", "----------");

    for(int i = 0; i < total_proteines; i++){
        /* Determina la càrrega predominant */
        char tipus_carrega[10];
        if(proteines[i].pct_carregats > 20.0)
            strcpy(tipus_carrega, "ALTA");
        else if(proteines[i].pct_carregats > 10.0)
            strcpy(tipus_carrega, "MITJANA");
        else
            strcpy(tipus_carrega, "BAIXA");

        fprintf(fitxer, "%-25s %8d %10.1f Da %9.1f%% %9.1f%% %10s\n",
                proteines[i].nom,
                proteines[i].longitud,
                proteines[i].pes_molecular,
                proteines[i].pct_carregats,
                proteines[i].pct_hidrofobics,
                tipus_carrega);
    }

    /* Detall de cada proteïna */
    fprintf(fitxer, "\n\n--- DETALL PER PROTEINA ---\n\n");

    for(int i = 0; i < total_proteines; i++){
        fprintf(fitxer, "Proteina: %s\n", proteines[i].nom);
        fprintf(fitxer, "  Longitud: %d aminoacids\n", proteines[i].longitud);
        fprintf(fitxer, "  Pes molecular aproximat: %.1f Da\n", proteines[i].pes_molecular);
        fprintf(fitxer, "  Aminoacids carregats (K,R,D,E): %d (%.1f%%)\n", 
                proteines[i].carregats, proteines[i].pct_carregats);
        fprintf(fitxer, "  Aminoacids hidrofobics: %d (%.1f%%)\n", 
                proteines[i].hidrofobics, proteines[i].pct_hidrofobics);

        /* Mostra la seqüència amb marques */
        if(proteines[i].longitud <= 100){  /* Només si és curta */
            fprintf(fitxer, "  Sequencia: %s\n", proteines[i].sequencia);
            fprintf(fitxer, "  Carregats: ");
            for(int j = 0; j < proteines[i].longitud; j++){
                if(es_carregat(toupper(proteines[i].sequencia[j])))
                    fprintf(fitxer, "+");  /* Marca els carregats */
                else
                    fprintf(fitxer, ".");
            }
            fprintf(fitxer, "\n");
        }
        fprintf(fitxer, "\n");
    }

    fclose(fitxer);  /* Tanca el fitxer */
    printf("Informe guardat a '%s'.\n", nom_fitxer);
}

/* Funció per alliberar tota la memòria dinàmica reservada */
void alliberarMemoria(){
    for(int i = 0; i < total_proteines; i++){
        if(proteines[i].sequencia != NULL){  /* Si té seqüència reservada */
            free(proteines[i].sequencia);    /* Allibera la memòria */
            proteines[i].sequencia = NULL;   /* Evita punters penjants */
        }
    }
}

/* Funció auxiliar: comprova si un aminoàcid és carregat */
int es_carregat(char aa){
    /* Aminoàcids carregats: Lisina(K), Arginina(R) -> positius */
    /*                       Aspartat(D), Glutamat(E) -> negatius */
    aa = toupper(aa);
    return (aa == 'K' || aa == 'R' || aa == 'D' || aa == 'E');
}

/* Funció auxiliar: comprova si un aminoàcid és hidrofòbic */
int es_hidrofobic(char aa){
    aa = toupper(aa);
    return (aa == 'A' || aa == 'V' || aa == 'L' || aa == 'I' ||
            aa == 'P' || aa == 'F' || aa == 'W' || aa == 'M');
}

/* Funció auxiliar: retorna el pes molecular d'un aminoàcid */
float pes_aminoacid(char aa){
    /* Pesos moleculars aproximats en Daltons (Da) */
    /* Valors simplificats per a l'exercici */
    switch(toupper(aa)){
        case 'A': return 89.1;   /* Alanina */
        case 'R': return 174.2;  /* Arginina */
        case 'N': return 132.1;  /* Asparagina */
        case 'D': return 133.1;  /* Aspartat */
        case 'C': return 121.2;  /* Cisteina */
        case 'E': return 147.1;  /* Glutamat */
        case 'Q': return 146.2;  /* Glutamina */
        case 'G': return 75.1;   /* Glicina */
        case 'H': return 155.2;  /* Histidina */
        case 'I': return 131.2;  /* Isoleucina */
        case 'L': return 131.2;  /* Leucina */
        case 'K': return 146.2;  /* Lisina */
        case 'M': return 149.2;  /* Metionina */
        case 'F': return 165.2;  /* Fenilalanina */
        case 'P': return 115.1;  /* Prolina */
        case 'S': return 105.1;  /* Serina */
        case 'T': return 119.1;  /* Treonina */
        case 'W': return 204.2;  /* Triptofan */
        case 'Y': return 181.2;  /* Tirosina */
        case 'V': return 117.1;  /* Valina */
        default:  return 110.0;  /* Pes mitjà per a aminoàcids desconeguts */
    }
    /* Nota: el pes molecular real d'una proteïna requereix */
    /* sumar els pesos i restar H2O per cada enllaç peptídic */
}