C/C++

Tema 6 · Structs i fitxers

Introducció

Una struct (estructura) ens permet agrupar variables de diferents tipus sota un mateix nom, ideal per modelar entitats biomèdiques com proteïnes, pacients o fàrmacs. Amb fitxers podem guardar i recuperar dades de forma permanent, llegint grans volums d'informació des de fitxers FASTA, CSV o text pla.

Objectius

  • Definir i utilitzar estructures (struct) amb camps de diferents tipus
  • Crear vectors de structs per gestionar col·leccions de dades
  • Obtenir, llegir i escriure fitxers de text amb fopen(), fprintf(), fscanf()
  • Llegir múltiples proteïnes des d'un fitxer i emmagatzemar-les en un array de structs

Definicions i ús de structs

Una struct per emmagatzemar informació d'una proteïna:

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

struct Proteina {
    char nom[50];
    char sequencia[500];
    int longitud;
    float pes_molecular;
};

int main() {
    struct Proteina p1;

    strcpy(p1.nom, "Hemoglobina");
    strcpy(p1.sequencia, "VLSPADKTNVKAAWGKVGAHAGEYGAEALERMFLSFPTT");
    p1.longitud = strlen(p1.sequencia);
    p1.pes_molecular = p1.longitud * 110.0;  // pes mitjà per aminoàcid

    printf("Proteïna: %s\n", p1.nom);
    printf("Longitud: %d aa\n", p1.longitud);
    printf("Pes molecular aproximat: %.1f Da\n", p1.pes_molecular);

    return 0;
}
Accés als camps amb l'operador punt: p1.nom

Treballant amb vectors de structs i punters:

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

#define MAX_PROTEINES 100

struct Proteina {
    char nom[50];
    char sequencia[500];
    int longitud;
};

int main() {
    struct Proteina llista[MAX_PROTEINES];
    int n = 0;

    // Exemple: afegir dues proteïnes manualment
    strcpy(llista[0].nom, "Insulina");
    strcpy(llista[0].sequencia, "MALWMRLLPLLALLALWGPDPAAA");
    llista[0].longitud = strlen(llista[0].sequencia);

    strcpy(llista[1].nom, "Glucagó");
    strcpy(llista[1].sequencia, "HSQGTFTSDYSKYLDSRRAQDFVQWLMNT");
    llista[1].longitud = strlen(llista[1].sequencia);

    n = 2;

    printf("Llista de proteïnes:\n");
    for (int i = 0; i < n; i++) {
        printf("  %d. %s (%d aa)\n", i+1, llista[i].nom, llista[i].longitud);
    }

    return 0;
}
#define MAX_PROTEINES 100 per limitar la mida de l'array

Fitxers: lectura i escriptura

Per treballar amb fitxers fem servir fopen(), fclose() i funcions d'entrada/eixida com fprintf() i fscanf().

#include <stdio.h>

int main() {
    FILE *fitxer;
    
    // Escriure en un fitxer
    fitxer = fopen("proteines.txt", "w");  // "w" = write (sobreescriu)
    if (fitxer == NULL) {
        printf("Error en obrir el fitxer.\n");
        return 1;
    }

    fprintf(fitxer, "Insulina 51\n");
    fprintf(fitxer, "Glucagó 29\n");
    fprintf(fitxer, "Albúmina 585\n");

    fclose(fitxer);

    // Llegir del fitxer
    fitxer = fopen("proteines.txt", "r");  // "r" = read
    if (fitxer == NULL) {
        printf("Error en obrir el fitxer.\n");
        return 1;
    }

    char nom[50];
    int longitud;
    printf("Dades llegides del fitxer:\n");
    while (fscanf(fitxer, "%s %d", nom, &longitud) == 2) {
        printf("  Proteïna: %s, Longitud: %d aa\n", nom, longitud);
    }

    fclose(fitxer);
    return 0;
}
Modes: "r" lectura, "w" escriptura, "a" afegir al final

Exemple integrat: structs i fitxers

Llegim múltiples proteïnes des d'un fitxer de text i les guardem en un array de structs. Format del fitxer (proteines.txt):

>Hemoglobina
VLSPADKTNVKAAWGKVGAHAGEYGAEALERMFLSFPTT
>Insulina
MALWMRLLPLLALLALWGPDPAAA

Codi per llegir-lo:

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

#define MAX_PROT 100
#define MAX_SEQ 1000

struct Proteina {
    char nom[100];
    char sequencia[MAX_SEQ];
    int longitud;
};

int main() {
    FILE *f = fopen("proteines.txt", "r");
    if (f == NULL) {
        printf("No s'ha trobat el fitxer.\n");
        return 1;
    }

    struct Proteina llista[MAX_PROT];
    int total = 0;
    char linia[MAX_SEQ];

    while (fgets(linia, MAX_SEQ, f) != NULL && total < MAX_PROT) {
        // La línia comença amb '>' → capçalera
        if (linia[0] == '>') {
            linia[strcspn(linia, "\n")] = '\0';  // treure '\n'
            strcpy(llista[total].nom, linia + 1); // saltar el '>'
            llista[total].sequencia[0] = '\0';
            llista[total].longitud = 0;
        } else {
            // És línia de seqüència
            linia[strcspn(linia, "\n")] = '\0';
            strcat(llista[total].sequencia, linia);
            llista[total].longitud = strlen(llista[total].sequencia);
            total++; // cada seqüència completa → següent proteïna
        }
    }
    fclose(f);

    printf("Proteïnes llegides: %d\n\n", total);
    for (int i = 0; i < total; i++) {
        printf("--- %s ---\n", llista[i].nom);
        printf("Seqüència: %s\n", llista[i].sequencia);
        printf("Longitud:  %d aa\n\n", llista[i].longitud);
    }

    return 0;
}
El programa detecta '>' com a inici d'una nova proteïna (format FASTA simplificat)

Exercicis

  1. Defineix una struct Medicament amb nom, dosi i preu. Crea 3 medicaments i mostra'ls per pantalla.
  2. 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.
  3. 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.

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

Escriu un programa que:

  • Llegeixi un fitxer en format FASTA simplificat amb diverses proteïnes (capçalera >nom + seqüència en una o vàries línies).
  • Emmagatzemi cada proteïna en una struct (nom, seqüència, longitud).
  • Calculi per a cada proteïna: longitud, pes molecular aproximat, percentatge d'aminoàcids carregats (K, R, D, E).
  • Generi un fitxer de sortida resum_proteines.txt amb un informe tabulat.
  • Utilitzi funcions separades: llegirProteines(), calcularEstadistiques(), escriureInforme().

Pista: defineix la struct com a tipus global amb typedef struct { ... } Proteina; per simplificar el codi.