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()ifree()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
- Declara dos enters i intercanvia els seus valors utilitzant un punter i una funció
swap(int *a, int *b). - Reserva memòria per a un vector de
floatde mida donada per l'usuari, omple'l i mostra la mitjana. - 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.