C/C++

Tema 5 · Punters i memòria dinàmica

Introducció

Un punter és una variable que emmagatzema l'adreça de memòria d'una altra variable. Amb malloc() i free() podem reservar i alliberar memòria dinàmicament en temps d'execució. Això és essencial quan no sabem per endavant la mida de les dades, com en fitxers FASTA de seqüències biològiques.

Objectius

  • Declarar punters i utilitzar els operadors & i *
  • Fer servir malloc() i free() per a memòria dinàmica
  • Treballar amb cadenes de mida variable
  • Llegir seqüències FASTA sense límits fixos

Punters bàsics

Un punter guarda l'adreça d'una variable. Amb * accedim al valor apuntat:

#include <stdio.h>

int main() {
    int valor = 42;
    int *punter = &valor;   // punter guarda l'adreça de 'valor'

    printf("Valor:  %d\n", valor);
    printf("Adreça: %p\n", punter);
    printf("Valor via punter: %d\n", *punter);  // desreferenciar

    *punter = 100;  // canviem valor a través del punter
    printf("Nou valor: %d\n", valor);  // 100

    return 0;
}
& obté l'adreça, * accedeix al valor apuntat

Memòria dinàmica amb malloc() i free()

malloc() (memory allocation) reserva un bloc de memòria de la mida que li indiquem i retorna un punter al seu inici. Sempre hem d'alliberar-la amb free() per evitar fuites de memòria.

#include <stdio.h>
#include <stdlib.h>  // per malloc i free
#include <string.h>

int main() {
    int n;
    printf("Quantes bases té la seqüència? ");
    scanf("%d", &n);
    getchar();  // consumir salt de línia

    // Reservem n+1 chars per al '\0'
    char *adn = (char *)malloc((n + 1) * sizeof(char));
    if (adn == NULL) {
        printf("Error de memòria.\n");
        return 1;
    }

    printf("Introdueix la seqüència: ");
    fgets(adn, n + 1, stdin);
    adn[strcspn(adn, "\n")] = '\0';  // eliminar salt de línia

    printf("Has introduït: %s\n", adn);
    printf("Longitud: %zu\n", strlen(adn));

    free(adn);  // alliberar memòria
    return 0;
}
sizeof(char) és 1 byte, però és bona pràctica mantenir-lo

Vector dinàmic de cadenes

Podem reservar un vector de punters i per a cada punter una cadena de mida adequada. Així gestionem múltiples seqüències de mida variable.

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

int main() {
    int num_seq, i;
    printf("Nombre de seqüències: ");
    scanf("%d", &num_seq);
    getchar();

    // Vector de punters a char
    char **sequencies = (char **)malloc(num_seq * sizeof(char *));
    if (sequencies == NULL) return 1;

    for (i = 0; i < num_seq; i++) {
        char buffer[1000];
        printf("Seqüència %d: ", i + 1);
        fgets(buffer, 1000, stdin);
        buffer[strcspn(buffer, "\n")] = '\0';

        // Reservem just el que necessitem
        sequencies[i] = (char *)malloc((strlen(buffer) + 1) * sizeof(char));
        strcpy(sequencies[i], buffer);
    }

    printf("\n--- Resum ---\n");
    for (i = 0; i < num_seq; i++) {
        printf("%d: %s (%zu bases)\n", i + 1, sequencies[i], strlen(sequencies[i]));
        free(sequencies[i]);  // alliberar cada cadena
    }
    free(sequencies);  // alliberar vector de punters

    return 0;
}
char ** = vector de punters a cadenes

Exercicis

  1. Declara dos enters i intercanvia els seus valors utilitzant un punter i una funció swap(int *a, int *b).
  2. Reserva memòria per a un vector de float de mida donada per l'usuari, omple'l i mostra la mitjana.
  3. Llegeix una seqüència d'ADN amb malloc() i crea una funció que retorni la seva complementària (A↔T, C↔G), també reservant memòria dinàmica.

Mini Projecte – Reserva dinàmica de seqüències FASTA

Escriu un programa que:

  • Pregunti el nombre de seqüències (sense límit fix).
  • Per a cada seqüència demani la capçalera (ex: >proteïna1) i la seqüència (pot tenir fins a milers de bases).
  • Reservi memòria dinàmica exacta per a cada capçalera i seqüència.
  • Calculi i mostri: longitud, percentatge GC i percentatge de cada base.
  • Alliberi tota la memòria en acabar.

Repte: desa els resultats en un fitxer de text amb format de resum.