Les opsines són proteïnes transmembrana que actuen com a fotoreceptors. S'uneixen a un cromòfor (retinal) per formar pigments visuals (rodopsina, fotopsines). Estan presents en bastons i cons de la retina, i són essencials per a la visió en animals.
Tipus principals:
Implementa la funció crear_proteina() que reservi memòria dinàmica per a una nova proteïna i inicialitzi tots els seus camps.
#include <stdio.h> /* Biblioteca estàndard d'entrada/sortida */
#include <stdlib.h> /* Biblioteca per a memòria dinàmica: malloc(), free() */
#include <string.h> /* Biblioteca per a funcions de cadenes: strlen(), strcpy() */
/* ============================================ */
/* DEFINICIÓ DE L'ESTRUCTURA PRINCIPAL */
/* ============================================ */
/* Estructura que representa una proteïna completa */
/* Agrupa totes les dades rellevants d'una seqüència biològica */
typedef struct {
char *nom; /* Punter al nom/identificador (memòria dinàmica) */
/* Ex: "Rodopsina", "OPN1SW", etc. */
char *capcalera; /* Punter a la capçalera FASTA completa (memòria dinàmica) */
/* Ex: ">sp|P08100|OPSD_HUMAN Rodopsina" */
char *sequencia_adn; /* Punter a la seqüència d'ADN original (memòria dinàmica) */
/* Emmagatzemada en majúscules */
int longitud_adn; /* Longitud de la seqüència d'ADN en nucleòtids */
char *sequencia_aa; /* Punter a la seqüència d'aminoàcids traduïda (memòria dinàmica) */
/* Resultat de la traducció de l'ORF més llarg */
int longitud_aa; /* Longitud de la seqüència d'aminoàcids */
float pes_molecular; /* Pes molecular aproximat en Daltons (Da) */
/* Calculat sumant els pesos de cada aminoàcid */
float pct_gc; /* Percentatge GC de la seqüència d'ADN */
int composicio_aa[26]; /* Array per comptar cada aminoàcid (índex 0='A', 1='C', etc.) */
/* Mida 26: un comptador per a cada lletra de l'alfabet */
/* Permet calcular la composició aminoacídica */
} Proteina; /* 'Proteina' és ara un nom de tipus vàlid gràcies a typedef */
/* ============================================ */
/* FUNCIÓ: crear_proteina() */
/* ============================================ */
/**
* Crea una nova proteïna reservant memòria dinàmica
* i inicialitzant tots els seus camps a valors per defecte.
*
* @return Punter a la nova Proteina creada, o NULL si error de memòria
*
* Nota: El programador és responsable d'alliberar la memòria
* amb la funció alliberar_proteina() quan ja no es necessiti.
*/
Proteina* crear_proteina(void){ /* 'void' indica que no rep paràmetres */
/* Retorna un punter a Proteina (Proteina*) */
/* Reserva memòria per a l'estructura Proteina */
Proteina *prot = (Proteina*)malloc(sizeof(Proteina));
/* malloc() demana un bloc de memòria al sistema operatiu */
/* sizeof(Proteina) calcula la mida total de l'estructura en bytes */
/* (Proteina*) converteix el punter genèric void* al tipus correcte */
/* Verifica que la reserva de memòria ha tingut èxit */
if(prot == NULL){ /* Si malloc() retorna NULL, no hi ha memòria disponible */
printf("ERROR: No s'ha pogut reservar memoria per a la proteina.\n");
return NULL; /* Retorna NULL per indicar error al programador que crida */
}
/* Inicialitza TOTS els punters a NULL */
/* NULL indica "no apunta a cap adreça vàlida" */
/* Això evita punters salvatges (wild pointers) que podrien causar errors */
prot->nom = NULL; /* El nom encara no s'ha assignat */
prot->capcalera = NULL; /* La capçalera FASTA no s'ha llegit */
prot->sequencia_adn = NULL; /* La seqüència d'ADN no s'ha carregat */
prot->sequencia_aa = NULL; /* La seqüència d'AA no s'ha calculat */
/* Inicialitza els valors numèrics a 0 */
prot->longitud_adn = 0; /* Encara no hi ha seqüència d'ADN */
prot->longitud_aa = 0; /* Encara no hi ha seqüència d'AA */
prot->pes_molecular = 0.0f; /* Pes molecular a 0 (la 'f' indica float) */
prot->pct_gc = 0.0f; /* Percentatge GC a 0 */
/* Inicialitza l'array de composició aminoacídica a zeros */
for(int i = 0; i < 26; i++){ /* Recorre les 26 posicions (A-Z) */
prot->composicio_aa[i] = 0; /* Cada comptador comença a 0 */
}
return prot; /* Retorna el punter a la proteïna creada i inicialitzada */
}
/* ============================================ */
/* FUNCIÓ: alliberar_proteina() */
/* ============================================ */
/**
* Allibera tota la memòria dinàmica associada a una proteïna.
*
* @param prot Punter a la Proteina a alliberar
*
* Nota: Després de cridar aquesta funció, el punter 'prot'
* ja no és vàlid i no s'ha d'utilitzar.
*/
void alliberar_proteina(Proteina *prot){ /* Rep un punter a Proteina */
/* 'void' indica que no retorna res */
if(prot == NULL) /* Verifica que el punter no sigui NULL */
return; /* Si és NULL, no hi ha res a alliberar */
/* Allibera cada camp de memòria dinàmica individualment */
/* free() allibera la memòria reservada amb malloc() */
/* És segur cridar free(NULL): no fa res */
free(prot->nom); /* Allibera la memòria del nom */
prot->nom = NULL; /* Assigna NULL per evitar punters penjants */
free(prot->capcalera); /* Allibera la capçalera FASTA */
prot->capcalera = NULL;
free(prot->sequencia_adn); /* Allibera la seqüència d'ADN */
prot->sequencia_adn = NULL;
free(prot->sequencia_aa); /* Allibera la seqüència d'aminoàcids */
prot->sequencia_aa = NULL;
/* Finalment, allibera la pròpia estructura */
free(prot); /* Allibera la memòria de l'estructura Proteina */
/* Nota: prot ja no és vàlid després d'aquesta línia */
}
/* ============================================ */
/* FUNCIÓ PRINCIPAL DE DEMOSTRACIÓ */
/* ============================================ */
int main(){ /* Punt d'entrada del programa */
printf("========================================\n");
printf(" DEMOSTRACIO: crear_proteina()\n");
printf("========================================\n\n");
/* Crea una nova proteïna */
printf("Creant una nova proteina...\n");
Proteina *opsina = crear_proteina(); /* Crida a la funció */
/* 'opsina' és un punter a Proteina */
/* Verifica que s'ha creat correctament */
if(opsina == NULL){ /* Si la funció ha retornat NULL */
printf("Error en crear la proteina. Finalitzant.\n");
return 1; /* Retorna 1 per indicar error */
}
/* Mostra l'estat inicial de la proteïna */
printf("Proteina creada correctament!\n\n");
printf("--- ESTAT INICIAL DE LA PROTEINA ---\n");
printf(" Nom: %s\n", opsina->nom ? opsina->nom : "(no assignat)");
/* Operador ternari: si opsina->nom és NULL, mostra "(no assignat)" */
printf(" Capcalera: %s\n", opsina->capcalera ? opsina->capcalera : "(no assignada)");
printf(" Sequencia ADN: %s\n", opsina->sequencia_adn ? opsina->sequencia_adn : "(no assignada)");
printf(" Longitud ADN: %d\n", opsina->longitud_adn);
printf(" Sequencia AA: %s\n", opsina->sequencia_aa ? opsina->sequencia_aa : "(no assignada)");
printf(" Longitud AA: %d\n", opsina->longitud_aa);
printf(" Pes molecular: %.2f Da\n", opsina->pes_molecular);
printf(" %%GC: %.2f%%\n", opsina->pct_gc);
printf(" Composicio AA: (buida)\n\n");
/* Demostració: assignar valors a la proteïna */
printf("--- ASSIGNANT VALORS D'EXEMPLE ---\n");
/* Assigna el nom (reservant memòria) */
opsina->nom = (char*)malloc(50 * sizeof(char)); /* Reserva 50 bytes */
if(opsina->nom != NULL)
strcpy(opsina->nom, "Rodopsina"); /* Copia el nom */
/* Assigna la capçalera FASTA */
opsina->capcalera = (char*)malloc(100 * sizeof(char));
if(opsina->capcalera != NULL)
strcpy(opsina->capcalera, ">sp|P08100|OPSD_HUMAN Rodopsina OS=Homo sapiens");
/* Assigna una seqüència d'ADN d'exemple */
opsina->sequencia_adn = (char*)malloc(200 * sizeof(char));
if(opsina->sequencia_adn != NULL){
strcpy(opsina->sequencia_adn, "ATGAATGGCACAGAAGGCCCTAACTTCTACGTCCCCTTCTCCAATAAAACCGGTGTGGTG");
opsina->longitud_adn = strlen(opsina->sequencia_adn);
}
/* Mostra l'estat actualitzat */
printf("Valors assignats correctament!\n\n");
printf("--- ESTAT ACTUALITZAT ---\n");
printf(" Nom: %s\n", opsina->nom);
printf(" Capcalera: %s\n", opsina->capcalera);
printf(" Sequencia ADN: %.50s...\n", opsina->sequencia_adn); /* Primers 50 caràcters */
printf(" Longitud ADN: %d nucleotids\n", opsina->longitud_adn);
/* Allibera la memòria */
printf("\nAlliberant memoria...\n");
alliberar_proteina(opsina); /* Allibera tota la memòria */
printf("Memoria alliberada correctament. Programa finalitzat.\n");
return 0; /* Finalitza amb èxit */
}
Escriu el mòdul analisi.c amb funcions per calcular GC, freqüències i traduir ADN a proteïna utilitzant una taula completa del codi genètic.
/* ============================================ */
/* FITXER: analisi.h - Capçalera del mòdul */
/* ============================================ */
#ifndef ANALISI_H /* Guarda d'inclusió: evita múltiples inclusions */
#define ANALISI_H /* Defineix la macro per a la guarda */
#include "proteina.h" /* Inclou la definició de l'estructura Proteina */
/* Prototips de les funcions del mòdul d'anàlisi */
/**
* Calcula el percentatge GC d'una seqüència d'ADN.
* @param adn Cadena amb la seqüència d'ADN
* @return Percentatge GC (0.0 a 100.0)
*/
float calcular_gc(const char *adn);
/**
* Compta la freqüència de cada nucleòtid en una seqüència d'ADN.
* @param adn Cadena amb la seqüència d'ADN
* @param a Punter per emmagatzemar el comptador d'A
* @param c Punter per emmagatzemar el comptador de C
* @param g Punter per emmagatzemar el comptador de G
* @param t Punter per emmagatzemar el comptador de T
*/
void comptar_nucleotids(const char *adn, int *a, int *c, int *g, int *t);
/**
* Tradueix una seqüència d'ADN a proteïna en un marc de lectura específic.
* @param adn Seqüència d'ADN a traduir
* @param marc Marc de lectura (0, 1 o 2)
* @return Punter a la seqüència d'aminoàcids traduïda (memòria dinàmica),
* o NULL si error. El programador ha d'alliberar amb free().
*/
char* traduir_adn_a_proteina(const char *adn, int marc);
/**
* Troba l'ORF (Open Reading Frame) més llarg en una seqüència d'ADN.
* Un ORF comença amb ATG i acaba amb un codó STOP (TAA, TAG, TGA).
* @param adn Seqüència d'ADN
* @param marc Punter per emmagatzemar el marc de lectura (0,1,2)
* @param inici Punter per emmagatzemar la posició d'inici (0-based)
* @param longitud Punter per emmagatzemar la longitud en nucleòtids
* @return Punter a la seqüència d'aminoàcids de l'ORF més llarg,
* o NULL si no es troba cap ORF
*/
char* trobar_orf_mes_llarg(const char *adn, int *marc, int *inici, int *longitud);
/**
* Calcula el pes molecular aproximat d'una seqüència d'aminoàcids.
* @param aa Seqüència d'aminoàcids (codi d'una lletra)
* @return Pes molecular en Daltons (Da)
*/
float calcular_pes_molecular(const char *aa);
/**
* Compta la composició aminoacídica d'una seqüència.
* @param aa Seqüència d'aminoàcids
* @param composicio Array de 26 posicions a omplir amb els comptatges
*/
void comptar_aminoacids(const char *aa, int composicio[26]);
/**
* Calcula totes les estadístiques d'una proteïna.
* @param prot Punter a la Proteina a analitzar (es modifiquen els seus camps)
*/
void calcular_estadistiques(Proteina *prot);
#endif /* ANALISI_H */
/* ============================================ */
/* FITXER: analisi.c - Implementació del mòdul */
/* ============================================ */
#include <stdio.h> /* Per a printf() */
#include <stdlib.h> /* Per a malloc(), free() */
#include <string.h> /* Per a strlen(), strcpy(), strncpy(), strcmp() */
#include <ctype.h> /* Per a toupper() */
#include "analisi.h" /* La nostra capçalera */
/* ============================================ */
/* TAULA COMPLETA DEL CODI GENÈTIC */
/* ============================================ */
/* Estructura per a una entrada de la taula genètica */
typedef struct {
char codo[4]; /* El triplet de nucleòtids (3 + '\0') */
char aminoacid; /* L'aminoàcid en codi d'una lletra */
const char *nom; /* Nom complet de l'aminoàcid */
} EntradaCodiGenetic;
/* Taula completa del codi genètic (64 codons) */
/* Inclou TOTS els codons possibles */
static const EntradaCodiGenetic TAULA_GENETICA[] = {
/* Codons que codifiquen per aminoàcids (61 codons) */
{"GCA", 'A', "Alanina"}, {"GCC", 'A', "Alanina"},
{"GCG", 'A', "Alanina"}, {"GCT", 'A', "Alanina"},
{"TGC", 'C', "Cisteina"}, {"TGT", 'C', "Cisteina"},
{"GAC", 'D', "Aspartat"}, {"GAT", 'D', "Aspartat"},
{"GAA", 'E', "Glutamat"}, {"GAG", 'E', "Glutamat"},
{"TTC", 'F', "Fenilalanina"}, {"TTT", 'F', "Fenilalanina"},
{"GGA", 'G', "Glicina"}, {"GGC", 'G', "Glicina"},
{"GGG", 'G', "Glicina"}, {"GGT", 'G', "Glicina"},
{"CAC", 'H', "Histidina"}, {"CAT", 'H', "Histidina"},
{"ATA", 'I', "Isoleucina"}, {"ATC", 'I', "Isoleucina"}, {"ATT", 'I', "Isoleucina"},
{"AAA", 'K', "Lisina"}, {"AAG", 'K', "Lisina"},
{"TTA", 'L', "Leucina"}, {"TTG", 'L', "Leucina"},
{"CTA", 'L', "Leucina"}, {"CTC", 'L', "Leucina"},
{"CTG", 'L', "Leucina"}, {"CTT", 'L', "Leucina"},
{"ATG", 'M', "Metionina"},
{"AAC", 'N', "Asparagina"}, {"AAT", 'N', "Asparagina"},
{"CCA", 'P', "Prolina"}, {"CCC", 'P', "Prolina"},
{"CCG", 'P', "Prolina"}, {"CCT", 'P', "Prolina"},
{"CAA", 'Q', "Glutamina"}, {"CAG", 'Q', "Glutamina"},
{"AGA", 'R', "Arginina"}, {"AGG", 'R', "Arginina"},
{"CGA", 'R', "Arginina"}, {"CGC", 'R', "Arginina"},
{"CGG", 'R', "Arginina"}, {"CGT", 'R', "Arginina"},
{"TCA", 'S', "Serina"}, {"TCC", 'S', "Serina"}, {"TCG", 'S', "Serina"}, {"TCT", 'S', "Serina"},
{"AGC", 'S', "Serina"}, {"AGT", 'S', "Serina"},
{"ACA", 'T', "Treonina"}, {"ACC", 'T', "Treonina"},
{"ACG", 'T', "Treonina"}, {"ACT", 'T', "Treonina"},
{"GTA", 'V', "Valina"}, {"GTC", 'V', "Valina"},
{"GTG", 'V', "Valina"}, {"GTT", 'V', "Valina"},
{"TGG", 'W', "Triptofan"},
{"TAC", 'Y', "Tirosina"}, {"TAT", 'Y', "Tirosina"},
/* Codons de parada (STOP) - 3 codons */
{"TAA", '*', "STOP (Ocre)"},
{"TAG", '*', "STOP (Ambre)"},
{"TGA", '*', "STOP (Opal)"}
};
/* Nombre d'entrades a la taula */
#define NUM_CODONS (sizeof(TAULA_GENETICA) / sizeof(TAULA_GENETICA[0]))
/* ============================================ */
/* IMPLEMENTACIÓ DE LES FUNCIONS */
/* ============================================ */
float calcular_gc(const char *adn){
if(adn == NULL) return 0.0f; /* Verifica que el punter no sigui NULL */
int gc = 0; /* Comptador de G + C */
int total = 0; /* Comptador de bases vàlides */
for(int i = 0; adn[i] != '\0'; i++){ /* Recorre la seqüència */
char base = toupper(adn[i]); /* Converteix a majúscula */
if(base == 'G' || base == 'C'){
gc++; /* Incrementa GC */
total++; /* Incrementa total */
} else if(base == 'A' || base == 'T'){
total++; /* Només incrementa total */
}
}
if(total == 0) return 0.0f; /* Evita divisió per zero */
return (float)gc / total * 100.0f; /* Calcula percentatge */
}
void comptar_nucleotids(const char *adn, int *a, int *c, int *g, int *t){
/* Inicialitza els comptadors a 0 */
*a = 0; *c = 0; *g = 0; *t = 0; /* Desreferencia els punters per modificar els valors */
if(adn == NULL) return; /* Si no hi ha seqüència, surt */
for(int i = 0; adn[i] != '\0'; i++){ /* Recorre la seqüència */
switch(toupper(adn[i])){ /* Avalua cada nucleòtid en majúscula */
case 'A': (*a)++; break; /* Incrementa A */
case 'C': (*c)++; break; /* Incrementa C */
case 'G': (*g)++; break; /* Incrementa G */
case 'T': (*t)++; break; /* Incrementa T */
}
}
}
/**
* Busca un codó a la taula genètica i retorna l'aminoàcid corresponent.
* @param codo Cadena de 3 caràcters amb el codó
* @return L'aminoàcid (codi d'una lletra) o 'X' si no es troba
*/
static char buscar_aminoacid(const char *codo){ /* 'static' limita l'àmbit a aquest fitxer */
for(int i = 0; i < NUM_CODONS; i++){ /* Cerca lineal a la taula */
if(strcmp(codo, TAULA_GENETICA[i].codo) == 0) /* Compara triplets */
return TAULA_GENETICA[i].aminoacid; /* Retorna l'aminoàcid */
}
return 'X'; /* 'X' per a codons no reconeguts */
}
char* traduir_adn_a_proteina(const char *adn, int marc){
if(adn == NULL || marc < 0 || marc > 2) return NULL; /* Validació de paràmetres */
int len = strlen(adn);
/* Calcula quants codons complets hi ha en aquest marc */
int num_codons = (len - marc) / 3;
if(num_codons <= 0) return NULL; /* Si no hi ha cap codó complet */
/* Reserva memòria per a la seqüència d'aminoàcids */
char *proteina = (char*)malloc((num_codons + 1) * sizeof(char));
/* +1 per al caràcter nul '\0' */
if(proteina == NULL) return NULL; /* Error de memòria */
int aa_idx = 0; /* Índex per a la seqüència d'aminoàcids */
char codo[4]; /* Buffer per al codó actual */
codo[3] = '\0'; /* El caràcter nul sempre al final */
/* Tradueix codó a codó */
for(int i = marc; i + 2 < len; i += 3){ /* Avança de 3 en 3 */
/* Extreu el codó actual */
codo[0] = toupper(adn[i]);
codo[1] = toupper(adn[i+1]);
codo[2] = toupper(adn[i+2]);
char aa = buscar_aminoacid(codo); /* Tradueix el codó */
proteina[aa_idx++] = aa; /* Afegeix l'aminoàcid a la seqüència */
if(aa == '*') break; /* Si és STOP, acaba la traducció */
}
proteina[aa_idx] = '\0'; /* Finalitza la cadena */
/* Si la seqüència és molt curta, considera que no és vàlida */
if(aa_idx < 10){ /* Mínim 10 aminoàcids */
free(proteina);
return NULL;
}
return proteina; /* Retorna la seqüència traduïda */
}
char* trobar_orf_mes_llarg(const char *adn, int *marc, int *inici, int *longitud){
if(adn == NULL) return NULL;
int len = strlen(adn);
char *millor_aa = NULL; /* Millor seqüència trobada fins ara */
int millor_longitud = 0; /* Longitud del millor ORF */
int millor_marc = -1; /* Marc del millor ORF */
int millor_inici = -1; /* Posició d'inici del millor ORF */
/* Prova els 3 marcs de lectura */
for(int m = 0; m < 3; m++){
int pos = m; /* Comença a la posició del marc */
while(pos + 5 < len){ /* Necessitem almenys ATG + 3 bases + STOP */
char codo_inici[4];
codo_inici[0] = toupper(adn[pos]);
codo_inici[1] = toupper(adn[pos+1]);
codo_inici[2] = toupper(adn[pos+2]);
codo_inici[3] = '\0';
/* Si no és ATG, avança 3 posicions */
if(strcmp(codo_inici, "ATG") != 0){
pos += 3;
continue; /* Torna a l'inici del bucle while */
}
/* Ha trobat un ATG: busca el STOP */
int pos_stop = -1;
for(int j = pos + 3; j + 2 < len; j += 3){
char codo_stop[4];
codo_stop[0] = toupper(adn[j]);
codo_stop[1] = toupper(adn[j+1]);
codo_stop[2] = toupper(adn[j+2]);
codo_stop[3] = '\0';
if(strcmp(codo_stop, "TAA") == 0 ||
strcmp(codo_stop, "TAG") == 0 ||
strcmp(codo_stop, "TGA") == 0){
pos_stop = j; /* Ha trobat un STOP */
break;
}
}
/* Si ha trobat un STOP, calcula la longitud de l'ORF */
if(pos_stop != -1){
int long_orf = pos_stop - pos + 3; /* Inclou el codó STOP */
/* Si és l'ORF més llarg trobat, el guarda */
if(long_orf > millor_longitud){
/* Allibera la seqüència anterior si n'hi havia */
free(millor_aa);
/* Tradueix aquest ORF */
char *temp_adn = (char*)malloc(long_orf + 1);
if(temp_adn){
strncpy(temp_adn, adn + pos, long_orf);
temp_adn[long_orf] = '\0';
millor_aa = traduir_adn_a_proteina(temp_adn, 0);
free(temp_adn);
}
millor_longitud = long_orf;
millor_marc = m;
millor_inici = pos;
}
pos = pos_stop + 3; /* Continua després del STOP */
} else {
pos += 3; /* No ha trobat STOP, avança */
}
}
}
/* Retorna els resultats a través dels punters */
if(marc) *marc = millor_marc;
if(inici) *inici = millor_inici;
if(longitud) *longitud = millor_longitud;
return millor_aa; /* Retorna la millor seqüència (o NULL si no n'hi ha cap) */
}
float calcular_pes_molecular(const char *aa){
if(aa == NULL) return 0.0f;
/* Pesos moleculars dels 20 aminoàcids estàndard (en Daltons) */
static const float pesos[26] = {
['A'-'A'] = 89.1f, /* Alanina */
['C'-'A'] = 121.2f, /* Cisteina */
['D'-'A'] = 133.1f, /* Aspartat */
['E'-'A'] = 147.1f, /* Glutamat */
['F'-'A'] = 165.2f, /* Fenilalanina */
['G'-'A'] = 75.1f, /* Glicina */
['H'-'A'] = 155.2f, /* Histidina */
['I'-'A'] = 131.2f, /* Isoleucina */
['K'-'A'] = 146.2f, /* Lisina */
['L'-'A'] = 131.2f, /* Leucina */
['M'-'A'] = 149.2f, /* Metionina */
['N'-'A'] = 132.1f, /* Asparagina */
['P'-'A'] = 115.1f, /* Prolina */
['Q'-'A'] = 146.2f, /* Glutamina */
['R'-'A'] = 174.2f, /* Arginina */
['S'-'A'] = 105.1f, /* Serina */
['T'-'A'] = 119.1f, /* Treonina */
['V'-'A'] = 117.1f, /* Valina */
['W'-'A'] = 204.2f, /* Triptòfan */
['Y'-'A'] = 181.2f, /* Tirosina */
};
/* Inicialització designada: pesos['C'-'A'] = pesos[2] */
float pes = 0.0f;
for(int i = 0; aa[i] != '\0'; i++){
if(aa[i] == '*') break; /* STOP no contribueix al pes */
int idx = toupper(aa[i]) - 'A'; /* Converteix lletra a índex (0-25) */
if(idx >= 0 && idx < 26){
pes += pesos[idx]; /* Suma el pes de l'aminoàcid */
}
}
/* Resta aigua per cada enllaç peptídic (18.015 Da per enllaç) */
int num_enllacos = strlen(aa) - 1;
if(num_enllacos > 0)
pes -= num_enllacos * 18.015f;
return pes;
}
void comptar_aminoacids(const char *aa, int composicio[26]){
/* Inicialitza l'array a zeros */
for(int i = 0; i < 26; i++)
composicio[i] = 0;
if(aa == NULL) return;
for(int i = 0; aa[i] != '\0'; i++){
if(aa[i] == '*') break; /* No compta STOP */
int idx = toupper(aa[i]) - 'A'; /* Converteix a índex */
if(idx >= 0 && idx < 26)
composicio[idx]++; /* Incrementa el comptador */
}
}
void calcular_estadistiques(Proteina *prot){
if(prot == NULL || prot->sequencia_adn == NULL) return;
/* Calcula el percentatge GC */
prot->pct_gc = calcular_gc(prot->sequencia_adn);
/* Troba l'ORF més llarg i el tradueix */
int marc, inici, long_orf;
char *millor_aa = trobar_orf_mes_llarg(prot->sequencia_adn, &marc, &inici, &long_orf);
if(millor_aa != NULL){
/* Allibera la seqüència anterior si n'hi havia */
free(prot->sequencia_aa);
/* Assigna la nova seqüència */
prot->sequencia_aa = millor_aa;
prot->longitud_aa = strlen(millor_aa);
/* Calcula el pes molecular */
prot->pes_molecular = calcular_pes_molecular(millor_aa);
/* Compta la composició aminoacídica */
comptar_aminoacids(millor_aa, prot->composicio_aa);
}
}
Dissenya el format de l'informe de sortida: quines dades ha d'incloure i en quin ordre.
/*
* ============================================
* FORMAT DE L'INFORME DE SORTIDA
* ============================================
*
* L'informe es genera en format text pla i segueix
* l'estructura següent:
*
* 1. CAPÇALERA
* - Títol: "MINISUITE BIOINFORMÀTICA - INFORME D'ANÀLISI"
* - Data i hora de generació
* - Família gènica analitzada: Opsines
* - Nombre de seqüències processades
*
* 2. RESUM GENERAL
* - Taula amb: nom, longitud ADN, longitud AA, %GC, pes molecular
*
* 3. DETALL PER SEQÜÈNCIA (per a cada proteïna)
* 3.1. Informació general
* - Nom i capçalera FASTA
* - Longitud de la seqüència d'ADN
* - Longitud de la proteïna traduïda
*
* 3.2. Composició nucleotídica
* - Taula: A, C, G, T amb recomptes i percentatges
* - Percentatge GC
*
* 3.3. Seqüència traduïda
* - ORF més llarg (marc de lectura, posició inicial)
* - Seqüència d'aminoàcids en blocs de 60
*
* 3.4. Composició aminoacídica
* - Taula amb tots els aminoàcids trobats
* - Recompte i percentatge de cada un
* - Classificació: hidrofòbics, polars, carregats
*
* 3.5. Pes molecular
* - Pes molecular calculat en Daltons (Da)
* - Pes en kiloDaltons (kDa)
*
* 4. COMPARACIÓ DE SEQÜÈNCIES (si n'hi ha més d'una)
* 4.1. Matriu d'identitat
* - Taula NxN amb percentatges d'identitat
*
* 4.2. Per a cada parella comparada:
* - Percentatge d'identitat
* - Percentatge de similitud
* - Alineament visual (primers 100 aminoàcids)
* - Llista de mutacions/diferències
*
* 5. PEU D'INFORME
* - Resum final
* - Llegenda de símbols
*
* EXEMPLE DE FORMAT:
*
* ========================================
* MINISUITE BIOINFORMÀTICA - INFORME
* Família: Opsines
* Data: 2024-01-15 14:30:00
* Seqüències analitzades: 5
* ========================================
*
* --- RESUM GENERAL ---
* NOM LONG_ADN LONG_AA %GC PES_MOLEC
* Rodopsina 1047 348 52.3 39245.67 Da
* Opsina_blau 1044 347 48.9 38901.23 Da
* ...
*
* --- DETALL: Rodopsina ---
* Capçalera: >sp|P08100|OPSD_HUMAN
* Longitud ADN: 1047 nt
* Longitud AA: 348 aa
*
* Composició nucleotídica:
* A: 250 (23.9%) C: 298 (28.5%) G: 250 (23.9%) T: 249 (23.8%)
* %GC: 52.3%
*
* ORF més llarg: marc 0, posició 0, longitud 1047 nt
* Seqüència AA:
* MNGTEGPNFYVPFSNKTGVVRSPFEYPQYYLAEPWQFSMLAAYMFLLIVLGFP
* INFLTLYVTVQHKKLRTPLNYILLNLAVADLFMVLGGFTSTLYTSLHGYFVFG
* ...
*
* Composició aminoacídica:
* A:12 C:8 D:10 E:15 F:22 G:18 H:6 I:14 K:10 L:35
* M:10 N:10 P:12 Q:8 R:12 S:25 T:18 V:28 W:5 Y:14
* Hidrofòbics: 156 (44.8%)
* Polars: 98 (28.2%)
* Carregats: 47 (13.5%)
*
* Pes molecular: 39245.67 Da (39.25 kDa)
*
* ========================================
*/
Construeix la suite completa amb tots els requisits.
/* ============================================ */
/* FITXER: proteina.h - Estructura de dades */
/* ============================================ */
#ifndef PROTEINA_H
#define PROTEINA_H
/* Estructura principal per a una proteïna */
typedef struct {
char *nom; /* Nom de la proteïna */
char *capcalera; /* Capçalera FASTA completa */
char *sequencia_adn; /* Seqüència d'ADN */
int longitud_adn; /* Longitud de l'ADN */
char *sequencia_aa; /* Seqüència d'aminoàcids */
int longitud_aa; /* Longitud d'aminoàcids */
float pes_molecular; /* Pes molecular (Da) */
float pct_gc; /* Percentatge GC */
int composicio_aa[26]; /* Composició aminoacídica */
} Proteina;
/* Funcions de gestió de proteïnes */
Proteina* crear_proteina(void);
void alliberar_proteina(Proteina *prot);
#endif
/* ============================================ */
/* FITXER: main.c - Programa principal */
/* MiniSuite Bioinformàtica - Família Opsines */
/* ============================================ */
#include <stdio.h> /* Entrada/sortida estàndard */
#include <stdlib.h> /* Memòria dinàmica */
#include <string.h> /* Funcions de cadenes */
#include <ctype.h> /* Classificació de caràcters */
#include <time.h> /* Per a data i hora */
#include "proteina.h" /* Estructura Proteina */
#include "analisi.h" /* Funcions d'anàlisi */
/* Constants del programa */
#define MAX_SEQ 5000 /* Longitud màxima de seqüència */
#define MAX_LINIA 2000 /* Longitud màxima de línia */
#define MAX_PROTEINES 50 /* Nombre màxim de proteïnes */
#define MAX_NOM 200 /* Longitud màxima del nom */
/* Variables globals */
Proteina *proteines[MAX_PROTEINES]; /* Array de punters a proteïnes */
int total_proteines = 0; /* Comptador de proteïnes carregades */
/* Prototips de funcions */
void mostrar_menu(void);
void importar_fasta(const char *nom_fitxer);
void mostrar_estadistiques(void);
void mostrar_traduccio(void);
void comparar_proteines(void);
void exportar_informe(const char *nom_fitxer);
void alliberar_totes(void);
/* Funció per crear un fitxer d'exemple d'opsines */
void crear_fitxer_exemple(const char *nom_fitxer){
FILE *f = fopen(nom_fitxer, "w");
if(f == NULL) return;
fprintf(f, ">Rodopsina|OPSD_HUMAN|Homo_sapiens\n");
fprintf(f, "ATGAATGGCACAGAAGGCCCTAACTTCTACGTCCCCTTCTCCAATAAAACCGGTGTGGTG\n");
fprintf(f, "CGCAGCCCCTTCGAGTACCCACAGTACTACCTGGCTGAGCCATGGCAGTTCTCCATGCTG\n");
fprintf(f, "GCCGCCTACATGTTCCTGCTGATCGTGCTGGGCTTCCCCATCAACTTCCTCACGCTCTAC\n");
fprintf(f, "GTCACCGTCCAGCACAAGAAGCTGCGCACGCCTCTCAACTACATCCTGCTCAACCTAGCC\n");
fprintf(f, "GTGGCTGACCTCTTCATGGTCCTAGGTGGCTTCACCAGCACCCTCTACACCTCTCTGCAT\n");
fprintf(f, "GGATACTTCGTCTTCGGGCCCACAGGATGCAATTTGGAGGGCTTCTTTGCCACCCTGGGC\n");
fprintf(f, "GGTGAAATTGCCCTGTGGTCCTTGGTGGTCCTGGCCATCGAGCGGTACGTGGTGGTGTGT\n");
fprintf(f, "AAGCCCATGAGCAACTTCCGCTTCGGGGAGAACCATGCCATCATGGGCGTTGCCTTCACC\n");
fprintf(f, "TGGGTCATGGCGCTGGCCTGCGCCCCACCCCTCGTCGGCTGGTCCAGGTACATCCCGGAG\n");
fprintf(f, "GGCATGCAGTGCTCGTGTGGAGCCATCTACTACACGCTCAAGCCGGAGATCAACAACGAG\n");
fprintf(f, "TCTTTCGTCATCTACATGTTCGTGGTCCACTTCACCATCCCCATGATTATCATCTTTTTC\n");
fprintf(f, "TGCTATGGGCAGCTCGTCTTCACCGTCAAGGAGGCGGCTGCCCAGCAGCAGGAGTCAGCC\n");
fprintf(f, "ACCACCCAGAAGGCAGAGAAGGAGGTGACCCGCATGGTCATCATCATGGTCATCGCTTTC\n");
fprintf(f, "CTGATCTGCTGGGTGCCCTACGCCAGCGTGGCGTTCTACATCTTCACCCACCAGGGCAGC\n");
fprintf(f, "GACTTCGGCCCGGTGTTCATGACCATCCCAGCGTTCTTTGCCAAGACCTCGGCGGTCTAC\n");
fprintf(f, "AACCCCGTCATCTATATCATGATGAACAAGCAGTTCCGGAACTGCATGCTCACCACCATC\n");
fprintf(f, "TGCTGCGGCAAGAACCCGCTGGGTGACGACGAGGCCTCTGCCACCGTGTCCAAGACGGAG\n");
fprintf(f, "ACGTCCCAGGTGGCCCCGGCGTAG\n");
fprintf(f, ">Opsina_blau|OPSB_HUMAN|Homo_sapiens\n");
fprintf(f, "ATGCGGGCCCTGTGGAGCCGGAAGAGCTGGCTGTTCCTGTCCCAGCTGCTGGGGCTGGGG\n");
fprintf(f, "GTGGTGGGCAGCTCCAGCATCTTCATGAGCCGCCGCGAGGAGAACACGCTGCCCATCCGC\n");
fprintf(f, "CACGTCCGCGACCTGATGGCCGAGATGCGGCAGCCCGCGGAGGCCAGCGCCGCGGCCGCC\n");
fprintf(f, "GTGGCCGCGGCCAACACCCTGGTGGCCGGCGGCATCACCAGCGTGGTGCCGTTCGCCGCC\n");
fprintf(f, "GCCGCCAGCCACTACGCCTTCGAGTACACGCTGGCCAAGGTCCCCGCCTTCGAGATCCTG\n");
fprintf(f, "TTCATGGTGTTTGCCACCCTGGTGGGCCTCAACGCGGTCTGGCTGCGCATGTACGCCGAG\n");
fprintf(f, "AGCTACCTGAAGCCCTTCTTCGACACCAACTGCCTGCTGAAGCTGGCCGTGGCCGACTGG\n");
fprintf(f, "GGCACCTTCTACTACGCCAACTGCGACGTGCTGCGCTTCGTGGTGGCCGTGCTCTACTAC\n");
fprintf(f, "GCCCTGTGCTTCACCTACGCCTTCGCCGCCGCCATGGCCGCCACCGTGGCCGCCATCGCC\n");
fprintf(f, "GCCTACCTGGGCGAGTTCTGCTCCAAGATGCGCTTCCCGCAGTTCTCCATCGTGGTGTTC\n");
fprintf(f, "TACTACAAGCTGTTCGCCTGCTTCCCCGTCACCTTCCTGGTGGCCGCCTACGCCTTCCTC\n");
fprintf(f, "TACGCCGCCTACGCCTGCGCCGCCTTCGCCGCCGCCTTCGCCGCCGCCTGGTCCGCCGCC\n");
fprintf(f, "TGGGCCTCCGCCTGGGTGCCCGCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCC\n");
fprintf(f, "GCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCC\n");
fprintf(f, "GCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCC\n");
fprintf(f, "GCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCC\n");
fprintf(f, "GCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCC\n");
fprintf(f, "GCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTCCGCCTAG\n");
fclose(f);
}
int main(int argc, char *argv[]){
int opcio;
char nom_fitxer[200] = "opsines.fasta";
printf("========================================\n");
printf(" MINISUITE BIOINFORMÀTICA\n");
printf(" Família gènica: OPSINES\n");
printf("========================================\n\n");
/* Si s'ha passat un fitxer com a argument, l'utilitza */
if(argc > 1)
strcpy(nom_fitxer, argv[1]);
/* Crea fitxer d'exemple si no existeix */
FILE *test = fopen(nom_fitxer, "r");
if(test == NULL){
printf("No s'ha trobat '%s'. Creant fitxer d'exemple...\n", nom_fitxer);
crear_fitxer_exemple(nom_fitxer);
} else {
fclose(test);
}
do{
mostrar_menu();
printf(" Opcio: ");
scanf("%d", &opcio);
getchar();
switch(opcio){
case 1:
importar_fasta(nom_fitxer);
break;
case 2:
mostrar_estadistiques();
break;
case 3:
mostrar_traduccio();
break;
case 4:
comparar_proteines();
break;
case 5:
exportar_informe("informe_opsines.txt");
break;
case 6:
printf("Fitxer a importar: ");
scanf("%199s", nom_fitxer);
getchar();
importar_fasta(nom_fitxer);
break;
case 0:
printf("\nAlliberant memoria i sortint...\n");
alliberar_totes();
printf("Adeu!\n");
break;
default:
printf("Opcio no valida.\n");
}
} while(opcio != 0);
return 0;
}
void mostrar_menu(void){
printf("\n--- MENU PRINCIPAL ---\n");
printf(" Proteines carregades: %d\n", total_proteines);
printf(" 1. Importar fitxer FASTA (opsines.fasta)\n");
printf(" 2. Mostrar estadistiques de totes les opsines\n");
printf(" 3. Mostrar traduccio (ORF mes llarg)\n");
printf(" 4. Comparar dues proteines\n");
printf(" 5. Exportar informe complet\n");
printf(" 6. Canviar fitxer d'entrada\n");
printf(" 0. Sortir\n");
}
void importar_fasta(const char *nom_fitxer){
FILE *f = fopen(nom_fitxer, "r");
if(f == NULL){
printf("ERROR: No s'ha pogut obrir '%s'.\n", nom_fitxer);
return;
}
/* Allibera proteïnes anteriors */
alliberar_totes();
char linia[MAX_LINIA];
char seq_temp[MAX_SEQ] = "";
char capcalera_temp[MAX_NOM] = "";
int dins_seq = 0;
printf("Llegint fitxer '%s'...\n", nom_fitxer);
while(fgets(linia, MAX_LINIA, f) != NULL){
int len = strlen(linia);
if(len > 0 && linia[len-1] == '\n') linia[len-1] = '\0';
if(linia[0] == '>'){
/* Guarda la proteïna anterior si existeix */
if(dins_seq && strlen(seq_temp) > 0 && total_proteines < MAX_PROTEINES){
Proteina *prot = crear_proteina();
if(prot){
prot->capcalera = (char*)malloc(strlen(capcalera_temp) + 1);
strcpy(prot->capcalera, capcalera_temp);
/* Extreu el nom (text fins al primer '|' o espai) */
char *nom = capcalera_temp + 1;
char *sep = strchr(nom, '|');
if(sep) *sep = '\0';
prot->nom = (char*)malloc(strlen(nom) + 1);
strcpy(prot->nom, nom);
prot->sequencia_adn = (char*)malloc(strlen(seq_temp) + 1);
strcpy(prot->sequencia_adn, seq_temp);
prot->longitud_adn = strlen(seq_temp);
/* Calcula estadístiques */
calcular_estadistiques(prot);
proteines[total_proteines++] = prot;
}
}
/* Nova proteïna */
strcpy(capcalera_temp, linia);
seq_temp[0] = '\0';
dins_seq = 1;
} else if(dins_seq){
/* Converteix a majúscules i afegeix */
for(int i = 0; linia[i]; i++)
linia[i] = toupper(linia[i]);
/* Filtra només bases vàlides */
char filtra[MAX_SEQ] = "";
int j = 0;
for(int i = 0; linia[i]; i++)
if(strchr("ACGT", linia[i])) filtra[j++] = linia[i];
filtra[j] = '\0';
strcat(seq_temp, filtra);
}
}
/* Guarda l'última proteïna */
if(dins_seq && strlen(seq_temp) > 0 && total_proteines < MAX_PROTEINES){
Proteina *prot = crear_proteina();
if(prot){
prot->capcalera = (char*)malloc(strlen(capcalera_temp) + 1);
strcpy(prot->capcalera, capcalera_temp);
char *nom = capcalera_temp + 1;
char *sep = strchr(nom, '|');
if(sep) *sep = '\0';
prot->nom = (char*)malloc(strlen(nom) + 1);
strcpy(prot->nom, nom);
prot->sequencia_adn = (char*)malloc(strlen(seq_temp) + 1);
strcpy(prot->sequencia_adn, seq_temp);
prot->longitud_adn = strlen(seq_temp);
calcular_estadistiques(prot);
proteines[total_proteines++] = prot;
}
}
fclose(f);
printf("Carregades %d proteines (opsines).\n", total_proteines);
}
void mostrar_estadistiques(void){
if(total_proteines == 0){
printf("No hi ha proteines carregades. Importa un fitxer FASTA primer.\n");
return;
}
printf("\n=== ESTADISTIQUES DE LES OPSINES ===\n\n");
printf("%-20s %8s %8s %8s %12s\n", "NOM", "LONG_ADN", "LONG_AA", "%GC", "PES (Da)");
printf("--------------------------------------------------------------\n");
for(int i = 0; i < total_proteines; i++){
Proteina *p = proteines[i];
printf("%-20s %8d %8d %7.1f%% %10.1f\n",
p->nom, p->longitud_adn, p->longitud_aa, p->pct_gc, p->pes_molecular);
}
/* Mostra composició aminoacídica de la primera opsina */
if(total_proteines > 0 && proteines[0]->sequencia_aa){
printf("\n--- Composicio aminoacidica de %s ---\n", proteines[0]->nom);
printf("Aminoacids: ");
for(int i = 0; i < 26; i++){
if(proteines[0]->composicio_aa[i] > 0)
printf("%c:%d ", 'A' + i, proteines[0]->composicio_aa[i]);
}
printf("\n");
}
}
void mostrar_traduccio(void){
if(total_proteines == 0){
printf("No hi ha proteines carregades.\n");
return;
}
printf("\n=== TRADUCCIO (ORF MES LLARG) ===\n\n");
for(int i = 0; i < total_proteines; i++){
Proteina *p = proteines[i];
printf("--- %s ---\n", p->nom);
printf("Longitud ADN: %d nt\n", p->longitud_adn);
if(p->sequencia_aa){
printf("Longitud AA: %d aa\n", p->longitud_aa);
printf("Pes molecular: %.1f Da (%.1f kDa)\n", p->pes_molecular, p->pes_molecular/1000);
printf("Sequencia AA (primers 100 aa):\n ");
for(int j = 0; j < p->longitud_aa && j < 100; j++){
printf("%c", p->sequencia_aa[j]);
if((j + 1) % 60 == 0) printf("\n ");
}
printf("\n");
} else {
printf("No s'ha pogut traduir (no s'ha trobat ORF valid).\n");
}
printf("\n");
}
}
void comparar_proteines(void){
if(total_proteines < 2){
printf("Es necessiten almenys 2 proteines per comparar.\n");
return;
}
printf("\nProteines disponibles:\n");
for(int i = 0; i < total_proteines; i++)
printf(" %d. %s\n", i + 1, proteines[i]->nom);
int i1, i2;
printf("Selecciona la primera proteina (1-%d): ", total_proteines);
scanf("%d", &i1);
printf("Selecciona la segona proteina (1-%d): ", total_proteines);
scanf("%d", &i2);
getchar();
if(i1 < 1 || i1 > total_proteines || i2 < 1 || i2 > total_proteines){
printf("Indexs no valids.\n");
return;
}
Proteina *p1 = proteines[i1 - 1];
Proteina *p2 = proteines[i2 - 1];
printf("\n=== COMPARACIO: %s vs %s ===\n\n", p1->nom, p2->nom);
if(p1->sequencia_aa && p2->sequencia_aa){
int len1 = p1->longitud_aa;
int len2 = p2->longitud_aa;
int min_len = (len1 < len2) ? len1 : len2;
int max_len = (len1 > len2) ? len1 : len2;
int identiques = 0;
for(int i = 0; i < min_len; i++)
if(p1->sequencia_aa[i] == p2->sequencia_aa[i])
identiques++;
printf("Longitud: %s=%d aa, %s=%d aa\n", p1->nom, len1, p2->nom, len2);
printf("Identitat: %d/%d (%.1f%%)\n", identiques, max_len,
(float)identiques/max_len*100);
/* Alineament visual */
printf("\nAlineament (primers 100 aa):\n");
printf("%-10s ", p1->nom);
for(int i = 0; i < min_len && i < 100; i++)
printf("%c", p1->sequencia_aa[i]);
printf("\n ");
for(int i = 0; i < min_len && i < 100; i++)
printf("%c", (p1->sequencia_aa[i] == p2->sequencia_aa[i]) ? '|' : ' ');
printf("\n%-10s ", p2->nom);
for(int i = 0; i < min_len && i < 100; i++)
printf("%c", p2->sequencia_aa[i]);
printf("\n");
/* Llista de diferències */
printf("\nDiferencies (primeres 20):\n");
int difs = 0;
for(int i = 0; i < min_len && difs < 20; i++){
if(p1->sequencia_aa[i] != p2->sequencia_aa[i]){
printf(" Pos %d: %c -> %c\n", i + 1, p1->sequencia_aa[i], p2->sequencia_aa[i]);
difs++;
}
}
}
}
void exportar_informe(const char *nom_fitxer){
if(total_proteines == 0){
printf("No hi ha dades per exportar.\n");
return;
}
FILE *f = fopen(nom_fitxer, "w");
if(f == NULL){
printf("ERROR: No s'ha pogut crear '%s'.\n", nom_fitxer);
return;
}
time_t t = time(NULL);
fprintf(f, "========================================\n");
fprintf(f, " MINISUITE BIOINFORMATICA - INFORME\n");
fprintf(f, " Familia: Opsines\n");
fprintf(f, " Data: %s", ctime(&t));
fprintf(f, " Sequencies analitzades: %d\n", total_proteines);
fprintf(f, "========================================\n\n");
/* Resum */
fprintf(f, "--- RESUM GENERAL ---\n");
fprintf(f, "%-20s %8s %8s %8s %12s\n", "NOM", "LONG_ADN", "LONG_AA", "%%GC", "PES (Da)");
fprintf(f, "--------------------------------------------------------------\n");
for(int i = 0; i < total_proteines; i++){
Proteina *p = proteines[i];
fprintf(f, "%-20s %8d %8d %7.1f %10.1f\n",
p->nom, p->longitud_adn, p->longitud_aa, p->pct_gc, p->pes_molecular);
}
/* Detall per proteïna */
for(int i = 0; i < total_proteines; i++){
Proteina *p = proteines[i];
fprintf(f, "\n--- DETALL: %s ---\n", p->nom);
fprintf(f, "Capcalera: %s\n", p->capcalera);
fprintf(f, "Longitud ADN: %d nt\n", p->longitud_adn);
fprintf(f, "Longitud AA: %d aa\n", p->longitud_aa);
fprintf(f, "%%GC: %.1f%%\n", p->pct_gc);
fprintf(f, "Pes molecular: %.1f Da (%.1f kDa)\n", p->pes_molecular, p->pes_molecular/1000);
if(p->sequencia_aa){
fprintf(f, "Sequencia AA:\n ");
for(int j = 0; j < p->longitud_aa; j++){
fprintf(f, "%c", p->sequencia_aa[j]);
if((j + 1) % 60 == 0) fprintf(f, "\n ");
}
fprintf(f, "\n");
}
}
fclose(f);
printf("Informe exportat a '%s'.\n", nom_fitxer);
}
void alliberar_totes(void){
for(int i = 0; i < total_proteines; i++)
alliberar_proteina(proteines[i]);
total_proteines = 0;
}