Tema 5 - Punters i Memòria Dinàmica

Intercanvi (swap)

Escriu una funció swap(int *a, int *b) que intercanviï dos enters mitjançant punters.

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

/* Prototip (declaració) de la funció swap */
/* Els paràmetres són punters a enter (int*) */
/* Un punter és una variable que emmagatzema una adreça de memòria */
void swap(int *a, int *b);  /* Rep dos punters a enters */
                            /* 'void' indica que no retorna cap valor */
                            /* Modificarà els valors a través dels punters */

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

    int x = 10;  /* Declara i inicialitza x amb el valor 10 */
    int y = 25;  /* Declara i inicialitza y amb el valor 25 */

    printf("Abans de l'intercanvi:\n");  /* Títol per a l'estat inicial */
    printf("  x = %d, y = %d\n", x, y);  /* Mostra els valors originals */

    swap(&x, &y);  /* Crida a la funció swap passant les ADRECES de x i y */
                   /* L'operador & obté l'adreça de memòria d'una variable */
                   /* &x és l'adreça on està emmagatzemat x */
                   /* &y és l'adreça on està emmagatzemat y */
                   /* La funció rebrà aquestes adreces i podrà modificar els valors */

    printf("Despres de l'intercanvi:\n");  /* Títol per a l'estat final */
    printf("  x = %d, y = %d\n", x, y);  /* Mostra els valors ja intercanviats */

    /* Demostració addicional per verificar que funciona */
    printf("\nComprovacio:\n");
    if(x == 25 && y == 10)  /* Verifica que els valors s'han intercanviat correctament */
        printf("  Intercanvi realitzat correctament!\n");
    else
        printf("  ERROR: L'intercanvi no ha funcionat.\n");

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

/* Implementació de la funció swap */
void swap(int *a, int *b){  /* Rep dos punters a enters */
                            /* *a i *b són punters: contenen adreces de memòria */
                            /* No retorna res, modifica els valors a través dels punters */

    int temp = *a;  /* Guarda el valor apuntat per 'a' en una variable temporal */
                    /* L'operador * (desreferència) accedeix al valor emmagatzemat a l'adreça */
                    /* *a significa "el valor que hi ha a l'adreça continguda en a" */
                    /* temp rep el valor original de x (10) */

    *a = *b;  /* Assigna al lloc apuntat per 'a' el valor apuntat per 'b' */
              /* *a accedeix a la variable x (a través de l'adreça) */
              /* *b accedeix a la variable y (a través de l'adreça) */
              /* Ara x conté el valor de y (25) */

    *b = temp;  /* Assigna al lloc apuntat per 'b' el valor guardat a temp */
                /* *b accedeix a la variable y */
                /* temp conté el valor original de x (10) */
                /* Ara y conté el valor original de x (10) */

    /* NOTA: Sense punters, una funció swap(x, y) no funcionaria perquè */
    /* C passa els arguments per valor (còpia), no per referència */
    /* Amb punters, passem les adreces i podem modificar els originals */
}

Vector dinàmic

Llegeix un nombre enter n, reserva un vector de float de mida n, omple'l i calcula la mitjana i la desviació estàndard.

#include <stdio.h>  /* Inclou la biblioteca estàndard d'entrada/sortida */
#include <stdlib.h>  /* Inclou la biblioteca estàndard */
                     /* Necessària per a malloc() i free() */
#include <math.h>    /* Inclou la biblioteca matemàtica */
                     /* Necessària per a sqrt() (arrel quadrada) */

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

    int n;  /* Variable per emmagatzemar la mida del vector */

    printf("Quants nombres vols introduir? ");  /* Demana la mida a l'usuari */
    scanf("%d", &n);  /* Llegeix el nombre d'elements */

    /* Validació de l'entrada: la mida ha de ser positiva */
    if(n <= 0){  /* Si n és negatiu o zero */
        printf("Error: la mida ha de ser un nombre positiu.\n");
        return 1;  /* Retorna 1 per indicar error (0 és èxit) */
    }

    /* Reserva de memòria dinàmica amb malloc() */
    /* malloc() demana un bloc de memòria al sistema operatiu */
    float *vector = (float*)malloc(n * sizeof(float));  /* Reserva espai per a n floats */
                                                        /* n * sizeof(float) calcula els bytes necessaris */
                                                        /* sizeof(float) retorna la mida en bytes d'un float (normalment 4) */
                                                        /* (float*) és un cast: converteix el punter void* a float* */
                                                        /* 'vector' és un punter al primer element de l'array reservat */

    /* Verifica que la reserva de memòria ha tingut èxit */
    if(vector == NULL){  /* Si malloc() retorna NULL, ha fallat la reserva */
                         /* NULL és una constant que indica "punter nul" (cap adreça vàlida) */
        printf("Error: no s'ha pogut reservar memoria.\n");
        return 1;  /* Surt amb error */
    }

    /* Bucle per omplir el vector amb dades de l'usuari */
    printf("\nIntrodueix %d nombres:\n", n);  /* Instruccions */
    for(int i = 0; i < n; i++){  /* Itera n vegades */
        printf("  Element %d: ", i + 1);  /* Demana l'element i+1 */
        scanf("%f", &vector[i]);  /* Llegeix un float i l'emmagatzema */
                                  /* vector[i] és equivalent a *(vector + i) */
                                  /* Accedeix a l'element i-èssim de l'array dinàmic */
    }

    /* Càlcul de la mitjana (suma de tots els valors / nombre de valors) */
    float suma = 0.0;  /* Acumulador per a la suma, inicialitzat a 0 */
    for(int i = 0; i < n; i++)  /* Recorre tot el vector */
        suma += vector[i];  /* Acumula cada element: suma = suma + vector[i] */
    float mitjana = suma / n;  /* Calcula la mitjana aritmètica */

    /* Càlcul de la desviació estàndard */
    /* Fórmula: sqrt( sumatori((xi - mitjana)^2) / n ) */
    float suma_quadrats = 0.0;  /* Acumulador per a la suma de diferències al quadrat */
    for(int i = 0; i < n; i++){  /* Recorre tot el vector */
        float diferencia = vector[i] - mitjana;  /* Calcula (xi - mitjana) */
        suma_quadrats += diferencia * diferencia;  /* Acumula (xi - mitjana)^2 */
    }
    float desviacio = sqrt(suma_quadrats / n);  /* Calcula l'arrel quadrada de la variància */
                                                /* sqrt() retorna l'arrel quadrada d'un nombre */

    /* Mostra els resultats */
    printf("\n=== RESULTATS ===\n");
    printf("Valors introduits: ");  /* Etiqueta */
    for(int i = 0; i < n; i++)  /* Recorre el vector */
        printf("%.2f ", vector[i]);  /* Mostra cada valor amb 2 decimals */
    printf("\n");
    printf("Mitjana: %.4f\n", mitjana);  /* Mostra la mitjana amb 4 decimals */
    printf("Desviacio estandard: %.4f\n", desviacio);  /* Mostra la desviació amb 4 decimals */

    /* Allibera la memòria reservada amb free() */
    /* És OBLIGATORI alliberar la memòria dinàmica per evitar fuites de memòria */
    free(vector);  /* Allibera el bloc de memòria apuntat per 'vector' */
                   /* Després de free(), el punter ja no és vàlid */
                   /* La memòria torna a estar disponible per al sistema */

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

Realloc

Crea un programa que llegeixi enters fins que l'usuari introdueixi 0, emmagatzemant-los en un array que creixi amb realloc().

#include <stdio.h>  /* Inclou la biblioteca estàndard d'entrada/sortida */
#include <stdlib.h>  /* Inclou la biblioteca estàndard */
                     /* Necessària per a malloc(), realloc() i free() */

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

    int capacitat = 2;  /* Capacitat inicial de l'array (quants elements hi caben) */
                        /* Comencem amb poc espai per demostrar realloc() */
    int total = 0;  /* Comptador d'elements emmagatzemats (quants elements hi ha) */
    int *array = NULL;  /* Punter a l'array dinàmic, inicialitzat a NULL */
                        /* NULL indica que encara no s'ha reservat memòria */

    printf("Introdueix nombres enters (0 per acabar):\n");  /* Instruccions */

    int nombre;  /* Variable per llegir cada nombre */

    /* Bucle de lectura: continua fins que l'usuari introdueixi 0 */
    do{
        printf("Nombre: ");  /* Demana un nombre */
        scanf("%d", &nombre);  /* Llegeix l'enter */

        if(nombre != 0){  /* Si el nombre no és 0 (el 0 és la condició de sortida) */

            /* Comprova si cal redimensionar l'array */
            if(total >= capacitat){  /* Si ja hem omplert l'espai reservat */
                                     /* total >= capacitat: no hi ha espai per a més elements */

                int nova_capacitat = capacitat * 2;  /* Duplica la capacitat */
                                                     /* Estratègia comuna per créixer eficientment */

                /* realloc() redimensiona un bloc de memòria existent */
                /* Si array és NULL, realloc() es comporta com malloc() */
                int *temp = (int*)realloc(array, nova_capacitat * sizeof(int));
                /* realloc() intenta expandir el bloc actual o moure'l a una altra zona */
                /* nova_capacitat * sizeof(int): nova mida total en bytes */
                /* Es guarda en un punter temporal per si realloc() falla */

                if(temp == NULL){  /* Si realloc() retorna NULL, ha fallat */
                    printf("Error: no s'ha pogut redimensionar l'array.\n");
                    free(array);  /* Allibera la memòria reservada fins ara */
                    return 1;  /* Surt amb error */
                }

                array = temp;  /* Actualitza el punter amb la nova adreça */
                capacitat = nova_capacitat;  /* Actualitza la capacitat */
                printf("  [Array redimensionat a %d elements]\n", capacitat);  /* Informa del canvi */
            }

            array[total] = nombre;  /* Emmagatzema el nombre a la posició actual */
            total++;  /* Incrementa el comptador d'elements */
        }

    } while(nombre != 0);  /* Continua mentre el nombre no sigui 0 */

    /* Mostra el resum dels nombres introduïts */
    printf("\n=== RESUM ===\n");
    printf("Total de nombres introduits: %d\n", total);  /* Mostra quants nombres hi ha */
    printf("Capacitat final de l'array: %d\n", capacitat);  /* Mostra la capacitat reservada */
    printf("Memoria utilitzada: %d bytes\n", total * (int)sizeof(int));  /* Memòria real usada */
    printf("Memoria reservada: %d bytes\n", capacitat * (int)sizeof(int));  /* Memòria total reservada */

    if(total > 0){  /* Si hi ha elements emmagatzemats */
        printf("\nNombres introduits: ");  /* Etiqueta */
        for(int i = 0; i < total; i++)  /* Recorre els elements */
            printf("%d ", array[i]);  /* Mostra cada element */
        printf("\n");

        /* Calcula i mostra la suma dels nombres */
        int suma = 0;  /* Acumulador */
        for(int i = 0; i < total; i++)  /* Recorre l'array */
            suma += array[i];  /* Acumula */
        printf("Suma total: %d\n", suma);  /* Mostra la suma */
    }

    /* Allibera la memòria reservada */
    free(array);  /* Sempre s'ha d'alliberar la memòria dinàmica */
                  /* Evita fuites de memòria (memory leaks) */
                  /* Després de free(), array ja no apunta a memòria vàlida */

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

Inversa complementària (dinàmica)

Fes una funció que retorni la inversa complementària d'una cadena d'ADN (ex: "ATGC" → "GCAT") utilitzant memòria dinàmica.

#include <stdio.h>  /* Inclou la biblioteca estàndard d'entrada/sortida */
#include <stdlib.h>  /* Inclou la biblioteca per a funcions de memòria dinàmica */
                     /* Necessària per a malloc() i free() */
#include <string.h>  /* Inclou la biblioteca per a funcions de cadenes */
                     /* Necessària per a strlen() */

/* Prototip de la funció inversa_complementaria */
/* Retorna un punter a char (cadena dinàmica) */
/* La cadena retornada s'ha d'alliberar amb free() després d'usar-la */
char* inversa_complementaria(const char* adn);  /* const char*: la cadena d'entrada no es modificarà */
                                                /* char*: retorna un punter a la nova cadena dinàmica */

/* Funció auxiliar: retorna la base complementària */
char complement(char base){  /* Rep una base, retorna la seva complementària */
    switch(base){  /* Avalua la base */
        case 'A': return 'T';  /* Adenina -> Timina */
        case 'T': return 'A';  /* Timina -> Adenina */
        case 'C': return 'G';  /* Citosina -> Guanina */
        case 'G': return 'C';  /* Guanina -> Citosina */
        case 'a': return 't';  /* Versió minúscula */
        case 't': return 'a';
        case 'c': return 'g';
        case 'g': return 'c';
        default:  return base;  /* Si no és base, retorna el mateix caràcter */
    }
}

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

    char original[101];  /* Array per a la cadena introduïda per l'usuari */
                          /* Mida fixa a l'stack, fins a 100 caràcters + '\0' */

    printf("Introdueix una sequencia d'ADN: ");  /* Demana la seqüència */
    scanf("%100s", original);  /* Llegeix fins a 100 caràcters */

    /* Crida a la funció que crea la inversa complementària */
    char *resultat = inversa_complementaria(original);  /* La funció retorna memòria dinàmica */
                                                        /* 'resultat' és un punter a la cadena creada */

    if(resultat == NULL){  /* Verifica que la funció ha tingut èxit */
        printf("Error en processar la sequencia.\n");
        return 1;  /* Surt amb error */
    }

    /* Mostra els resultats */
    printf("\nSequencia original:           %s\n", original);  /* Cadena original */
    printf("Inversa complementaria:       %s\n", resultat);  /* Cadena processada */

    /* Verificació pas a pas */
    printf("\nVerificacio pas a pas:\n");
    printf("  Original:     ");
    for(int i = 0; original[i] != '\0'; i++)  /* Mostra caràcter a caràcter */
        printf("%c ", original[i]);
    printf("\n  Complement:   ");
    for(int i = 0; original[i] != '\0'; i++)
        printf("%c ", complement(original[i]));  /* Mostra la complementària directa */
    printf("\n  Inv. Complem: ");
    for(int i = 0; resultat[i] != '\0'; i++)
        printf("%c ", resultat[i]);  /* Mostra la inversa complementària */
    printf("\n");

    /* Allibera la memòria dinàmica creada per la funció */
    free(resultat);  /* Obligatori: la funció ha creat memòria amb malloc() */
                     /* Si no s'allibera, es produeix una fuita de memòria */
    resultat = NULL;  /* Bona pràctica: assignar NULL després de free() */
                      /* Evita l'ús accidental d'un punter alliberat (dangling pointer) */

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

/* Implementació de la funció inversa_complementaria */
char* inversa_complementaria(const char* adn){  /* Rep una cadena constant (no es modifica) */
                                                /* Retorna un punter a char (cadena dinàmica) */

    int longitud = strlen(adn);  /* Calcula la longitud de la cadena d'entrada */
                                 /* strlen() compta fins a '\0' sense incloure'l */

    /* Reserva memòria per a la nova cadena */
    /* longitud + 1: espai per a tots els caràcters + el caràcter nul '\0' */
    char *resultat = (char*)malloc((longitud + 1) * sizeof(char));
    /* malloc() reserva un bloc de memòria de la mida especificada */
    /* sizeof(char) sempre és 1, però s'inclou per claredat */
    /* (char*) converteix el punter void* retornat per malloc() a char* */

    if(resultat == NULL){  /* Si malloc() ha fallat */
        return NULL;  /* Retorna NULL per indicar error */
    }

    /* Bucle per construir la inversa complementària */
    /* Es recorre la cadena original des del final fins al principi */
    for(int i = 0; i < longitud; i++){  /* i recorre la cadena original */
        /* Per a la posició i del resultat, s'agafa la base des del final de l'original */
        char base_original = adn[longitud - 1 - i];  /* Caràcter des del final */
                                                     /* Quan i=0: última base de l'original */
                                                     /* Quan i=1: penúltima base */
        resultat[i] = complement(base_original);  /* Assigna la complementària */
    }

    resultat[longitud] = '\0';  /* Afegeix el caràcter nul al final */
                                /* Sense '\0', no seria una cadena vàlida en C */

    return resultat;  /* Retorna el punter a la nova cadena dinàmica */
                      /* El programador que crida ha de recordar fer free() */
}

Llista de noms

Llegeix noms de pacients fins que l'usuari introdueixi "fi" i emmagatzema'ls en un vector de punters (memòria dinàmica). Després ordena'ls alfabèticament i mostra'ls.

#include <stdio.h>  /* Inclou la biblioteca estàndard d'entrada/sortida */
#include <stdlib.h>  /* Inclou la biblioteca per a memòria dinàmica */
                     /* Necessària per a malloc(), realloc() i free() */
#include <string.h>  /* Inclou la biblioteca per a funcions de cadenes */
                     /* Necessària per a strlen(), strcpy() i strcmp() */

#define MAX_NOM 100  /* Longitud màxima per a cada nom de pacient */
                     /* #define crea una constant simbòlica */

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

    /* Vector de punters a char (cadenes dinàmiques) */
    /* Cada element és un punter que apuntarà a una cadena amb un nom */
    char **noms = NULL;  /* Punter a punter a char, inicialitzat a NULL */
                         /* **noms: array dinàmic de punters a cadenes */
    int capacitat = 0;  /* Capacitat actual del vector de punters */
    int total = 0;  /* Nombre total de noms emmagatzemats */

    char buffer[MAX_NOM];  /* Buffer temporal per llegir cada nom */
                           /* Array a l'stack, no dinàmic */

    printf("Introdueix noms de pacients (escriu 'fi' per acabar):\n");

    /* Bucle de lectura de noms */
    while(1){  /* Bucle infinit: se surt amb break */
        printf("Nom %d: ", total + 1);  /* Mostra el número del pacient */
        scanf("%99s", buffer);  /* Llegeix un nom (fins a 99 caràcters) */

        /* Comprova si és la condició de sortida */
        if(strcmp(buffer, "fi") == 0 || strcmp(buffer, "FI") == 0)
            /* strcmp() compara dues cadenes */
            /* Retorna 0 si són iguals */
            /* Acceptem tant "fi" com "FI" */
            break;  /* Surt del bucle while */

        /* Comprova si cal expandir el vector de punters */
        if(total >= capacitat){  /* Si no hi ha espai per a més punters */
            int nova_cap = (capacitat == 0) ? 2 : capacitat * 2;  /* Nova capacitat */
            /* Operador ternari: si capacitat==0, nova_cap=2; sinó, duplica */

            /* realloc() per expandir el vector de punters */
            char **temp = (char**)realloc(noms, nova_cap * sizeof(char*));
            /* sizeof(char*) és la mida d'un punter (8 bytes en sistemes de 64 bits) */
            /* realloc() manté les dades existents i expandeix l'espai */

            if(temp == NULL){  /* Si realloc() falla */
                printf("Error de memoria.\n");
                /* Allibera la memòria ja reservada abans de sortir */
                for(int i = 0; i < total; i++)
                    free(noms[i]);  /* Allibera cada cadena */
                free(noms);  /* Allibera el vector de punters */
                return 1;
            }

            noms = temp;  /* Actualitza el punter */
            capacitat = nova_cap;  /* Actualitza la capacitat */
        }

        /* Reserva memòria per al nou nom (longitud exacta + 1 per a '\0') */
        noms[total] = (char*)malloc((strlen(buffer) + 1) * sizeof(char));
        /* strlen(buffer) + 1: espai per als caràcters + '\0' */

        if(noms[total] == NULL){  /* Si malloc() falla */
            printf("Error de memoria.\n");
            for(int i = 0; i < total; i++)
                free(noms[i]);
            free(noms);
            return 1;
        }

        strcpy(noms[total], buffer);  /* Copia el nom al nou espai reservat */
                                      /* strcpy() copia la cadena fins a '\0' */
        total++;  /* Incrementa el comptador de noms */
    }

    /* Mostra els noms abans d'ordenar */
    printf("\n=== NOMS INTRODUITS (%d) ===\n", total);
    for(int i = 0; i < total; i++)
        printf("  %d. %s\n", i + 1, noms[i]);

    /* Ordenació alfabètica amb el mètode de bombolla (bubble sort) */
    for(int i = 0; i < total - 1; i++){  /* Passades del bubble sort */
        for(int j = 0; j < total - 1 - i; j++){  /* Comparacions per passada */
            if(strcmp(noms[j], noms[j+1]) > 0){  /* Si noms[j] > noms[j+1] alfabèticament */
                                                  /* strcmp() retorna >0 si la primera és major */
                /* Intercanvia els punters (no les cadenes!) */
                char *temp = noms[j];  /* Guarda el punter temporalment */
                noms[j] = noms[j+1];  /* Assigna el punter de j+1 a j */
                noms[j+1] = temp;  /* Assigna el punter guardat a j+1 */
                /* Avantatge: intercanviar punters és més ràpid que intercanviar cadenes */
            }
        }
    }

    /* Mostra els noms ordenats */
    printf("\n=== NOMS ORDENATS ALFABETICAMENT ===\n");
    for(int i = 0; i < total; i++)
        printf("  %d. %s\n", i + 1, noms[i]);

    /* Allibera tota la memòria reservada */
    for(int i = 0; i < total; i++)
        free(noms[i]);  /* Allibera cada cadena individual */
    free(noms);  /* Allibera el vector de punters */
    noms = NULL;  /* Bona pràctica: evita punters penjants */

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

Mini Projecte – Gestor de seqüències FASTA dinàmic

Crea un programa amb un menú per gestionar seqüències en format FASTA utilitzant memòria dinàmica.

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

/* Estructura per emmagatzemar una seqüència FASTA */
/* Una estructura agrupa dades relacionades sota un mateix nom */
typedef struct {  /* typedef crea un àlies per a l'estructura */
    char *capcalera;  /* Punter a la capçalera (ex: >gen1) */
                      /* Memòria dinàmica: es reserva segons la longitud */
    char *sequencia;  /* Punter a la seqüència d'ADN */
                      /* Memòria dinàmica: es reserva segons la longitud */
    int longitud;     /* Longitud de la seqüència (nombre de bases) */
} Fasta;  /* 'Fasta' és el nom del tipus d'estructura */

/* Variables globals del gestor */
Fasta *sequencies = NULL;  /* Array dinàmic d'estructures Fasta */
                           /* Comença buit (NULL), creix amb realloc() */
int total_seq = 0;  /* Comptador de seqüències emmagatzemades */
int capacitat_seq = 0;  /* Capacitat actual de l'array */

/* Prototips de les funcions del programa */
void afegir_sequencia();       /* Afegeix una nova seqüència */
void llistar_sequencies();     /* Llista totes les seqüències */
void analitzar_sequencia();    /* Analitza una seqüència concreta */
void guardar_fitxer();         /* Desa totes les seqüències a un fitxer FASTA */
void alliberar_memoria();      /* Allibera tota la memòria reservada */

/* Funció auxiliar: calcula el percentatge GC d'una seqüència */
float calcular_gc(const char* seq);  /* Rep la seqüència, retorna el %GC */

/* Funció auxiliar: obté la base complementària */
char complementaria(char base);  /* Rep una base, retorna la complementària */

/* Funció auxiliar: llegeix una línia completa (inclou espais) */
void llegir_línia(char *buffer, int mida);  /* Llegeix fins a newline */

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

    int opcio;  /* Variable per a l'opció del menú */

    printf("========================================\n");
    printf("  GESTOR DE SEQUENCIES FASTA (DINAMIC)\n");
    printf("========================================\n");

    do{  /* Bucle del menú principal */
        printf("\n--- MENU PRINCIPAL ---\n");
        printf("  Sequencies emmagatzemades: %d\n", total_seq);
        printf("  1. Afegir sequencia\n");
        printf("  2. Llistar sequencies\n");
        printf("  3. Analitzar una sequencia\n");
        printf("  4. Guardar a fitxer (output.fasta)\n");
        printf("  0. Sortir\n");
        printf("  Opcio: ");
        scanf("%d", &opcio);
        getchar();  /* Consumeix el '\n' del buffer */

        switch(opcio){
            case 1: afegir_sequencia(); break;
            case 2: llistar_sequencies(); break;
            case 3: analitzar_sequencia(); break;
            case 4: guardar_fitxer(); break;
            case 0: 
                printf("\nAlliberant memoria i sortint...\n");
                alliberar_memoria();  /* Allibera tot abans de sortir */
                printf("Adeu!\n");
                break;
            default:
                printf("Opcio no valida.\n");
        }
    } while(opcio != 0);

    return 0;  /* Finalitza el programa */
}

/* Funció per afegir una nova seqüència FASTA */
void afegir_sequencia(){
    char buffer_cap[200];  /* Buffer per a la capçalera */
    char buffer_seq[1000]; /* Buffer per a la seqüència (pot ser llarga) */

    printf("\n--- AFEGIR SEQUENCIA ---\n");

    /* Llegeix la capçalera */
    printf("Capcalera (ex: >gen1): ");
    llegir_línia(buffer_cap, 200);  /* Llegeix tota la línia */

    /* Verifica que la capçalera comenci amb '>' (format FASTA) */
    if(buffer_cap[0] != '>'){
        printf("Error: la capcalera ha de comencar amb '>'.\n");
        return;
    }

    /* Llegeix la seqüència */
    printf("Sequencia d'ADN: ");
    llegir_línia(buffer_seq, 1000);

    /* Converteix la seqüència a majúscules */
    for(int i = 0; buffer_seq[i] != '\0'; i++)
        buffer_seq[i] = toupper(buffer_seq[i]);

    /* Comprova si cal expandir l'array d'estructures */
    if(total_seq >= capacitat_seq){
        int nova_cap = (capacitat_seq == 0) ? 2 : capacitat_seq * 2;
        Fasta *temp = (Fasta*)realloc(sequencies, nova_cap * sizeof(Fasta));
        /* sizeof(Fasta) és la mida de l'estructura completa */

        if(temp == NULL){
            printf("Error: no s'ha pogut reservar memoria.\n");
            return;
        }
        sequencies = temp;
        capacitat_seq = nova_cap;
    }

    /* Reserva memòria exacta per a la capçalera */
    int len_cap = strlen(buffer_cap) + 1;
    sequencies[total_seq].capcalera = (char*)malloc(len_cap * sizeof(char));

    /* Reserva memòria exacta per a la seqüència */
    int len_seq = strlen(buffer_seq) + 1;
    sequencies[total_seq].sequencia = (char*)malloc(len_seq * sizeof(char));

    /* Verifica que les reserves han tingut èxit */
    if(sequencies[total_seq].capcalera == NULL || 
       sequencies[total_seq].sequencia == NULL){
        printf("Error de memoria.\n");
        /* Allibera el que s'hagi pogut reservar */
        if(sequencies[total_seq].capcalera) free(sequencies[total_seq].capcalera);
        if(sequencies[total_seq].sequencia) free(sequencies[total_seq].sequencia);
        return;
    }

    /* Copia les dades als espais reservats */
    strcpy(sequencies[total_seq].capcalera, buffer_cap);
    strcpy(sequencies[total_seq].sequencia, buffer_seq);
    sequencies[total_seq].longitud = strlen(buffer_seq);  /* Guarda la longitud */

    total_seq++;  /* Incrementa el comptador */
    printf("Sequencia afegida correctament! (%d total)\n", total_seq);
}

/* Funció per llistar totes les seqüències */
void llistar_sequencies(){
    if(total_seq == 0){
        printf("\nNo hi ha sequencies emmagatzemades.\n");
        return;
    }

    printf("\n=== SEQUENCIES EMMAGATZEMADES ===\n");
    for(int i = 0; i < total_seq; i++){
        printf("[%d] %s\n", i, sequencies[i].capcalera);
        printf("    Longitud: %d bases\n", sequencies[i].longitud);
        printf("    %%GC: %.1f%%\n", calcular_gc(sequencies[i].sequencia));
        /* Mostra els primers 50 caràcters de la seqüència */
        printf("    Sequencia: %.50s", sequencies[i].sequencia);
        if(sequencies[i].longitud > 50) printf("...");
        printf("\n\n");
    }
}

/* Funció per analitzar una seqüència concreta */
void analitzar_sequencia(){
    if(total_seq == 0){
        printf("\nNo hi ha sequencies per analitzar.\n");
        return;
    }

    char cerca[200];
    printf("\nIntrodueix la capcalera a analitzar (ex: >gen1): ");
    llegir_línia(cerca, 200);

    /* Busca la capçalera */
    int index = -1;
    for(int i = 0; i < total_seq; i++){
        if(strcmp(sequencies[i].capcalera, cerca) == 0){
            index = i;
            break;
        }
    }

    if(index == -1){
        printf("Capcalera no trobada.\n");
        return;
    }

    /* Anàlisi de la seqüència trobada */
    printf("\n=== ANALISI DE %s ===\n", sequencies[index].capcalera);
    printf("Sequencia: %s\n", sequencies[index].sequencia);
    printf("Longitud: %d bases\n", sequencies[index].longitud);

    /* Comptatge de bases */
    int a=0, c=0, g=0, t=0;
    for(int i = 0; sequencies[index].sequencia[i] != '\0'; i++){
        switch(sequencies[index].sequencia[i]){
            case 'A': a++; break;
            case 'C': c++; break;
            case 'G': g++; break;
            case 'T': t++; break;
        }
    }

    int total_bases = a + c + g + t;
    printf("\nComposicio:\n");
    if(total_bases > 0){
        printf("  A: %d (%.1f%%)\n", a, (float)a/total_bases*100);
        printf("  C: %d (%.1f%%)\n", c, (float)c/total_bases*100);
        printf("  G: %d (%.1f%%)\n", g, (float)g/total_bases*100);
        printf("  T: %d (%.1f%%)\n", t, (float)t/total_bases*100);
    }
    printf("  %%GC: %.1f%%\n", calcular_gc(sequencies[index].sequencia));

    /* Complementària */
    printf("\nComplementaria: ");
    for(int i = 0; sequencies[index].sequencia[i] != '\0'; i++)
        printf("%c", complementaria(sequencies[index].sequencia[i]));
    printf("\n");
}

/* Funció per guardar totes les seqüències a un fitxer FASTA */
void guardar_fitxer(){
    if(total_seq == 0){
        printf("\nNo hi ha sequencies per guardar.\n");
        return;
    }

    /* Obre el fitxer en mode escriptura ("w") */
    FILE *fitxer = fopen("output.fasta", "w");  /* fopen() obre/crea un fitxer */
                                                /* "w": mode escriptura (sobreescriu si existeix) */
    if(fitxer == NULL){  /* Si no s'ha pogut obrir */
        printf("Error: no s'ha pogut crear el fitxer output.fasta.\n");
        return;
    }

    /* Escriu cada seqüència al fitxer en format FASTA */
    for(int i = 0; i < total_seq; i++){
        fprintf(fitxer, "%s\n", sequencies[i].capcalera);  /* Escriu la capçalera */
        /* Per a seqüències llargues, es poden dividir en línies de 60 caràcters */
        int len = sequencies[i].longitud;
        for(int j = 0; j < len; j += 60){  /* 60 caràcters per línia (estàndard FASTA) */
            fprintf(fitxer, "%.60s\n", sequencies[i].sequencia + j);
            /* %.60s imprimeix com a màxim 60 caràcters */
            /* sequencies[i].sequencia + j: punter al caràcter j */
        }
    }

    fclose(fitxer);  /* Tanca el fitxer (important!) */
                     /* fclose() assegura que totes les dades s'escriguin al disc */
    printf("\nFitxer 'output.fasta' creat correctament amb %d sequencies.\n", total_seq);
}

/* Funció per alliberar tota la memòria reservada */
void alliberar_memoria(){
    for(int i = 0; i < total_seq; i++){
        free(sequencies[i].capcalera);  /* Allibera la capçalera */
        free(sequencies[i].sequencia);  /* Allibera la seqüència */
    }
    free(sequencies);  /* Allibera l'array d'estructures */
    sequencies = NULL;  /* Evita punters penjants */
    total_seq = 0;
    capacitat_seq = 0;
}

/* Funció auxiliar: calcula el percentatge GC */
float calcular_gc(const char* seq){
    int gc = 0, total = 0;
    for(int i = 0; seq[i] != '\0'; i++){
        if(seq[i] == 'G' || seq[i] == 'C') gc++;
        if(seq[i] == 'A' || seq[i] == 'C' || seq[i] == 'G' || seq[i] == 'T') total++;
    }
    if(total == 0) return 0.0;
    return (float)gc / total * 100;
}

/* Funció auxiliar: retorna la base complementària */
char complementaria(char base){
    switch(base){
        case 'A': return 'T';
        case 'T': return 'A';
        case 'C': return 'G';
        case 'G': return 'C';
        default: return base;
    }
}

/* Funció auxiliar: llegeix una línia completa (inclou espais) */
void llegir_línia(char *buffer, int mida){
    fgets(buffer, mida, stdin);  /* Llegeix fins a newline o mida-1 */
    /* Elimina el salt de línia final si existeix */
    int len = strlen(buffer);
    if(len > 0 && buffer[len-1] == '\n')
        buffer[len-1] = '\0';  /* Substitueix '\n' per '\0' */
}