Ciao a tutti,
leggendo il famoso K&R, al capitolo 5.4 "Aritmetica degli indirizzi", si propone la realizzazione in "proprio" di due funzioni
che consentano una gestione dinamica della memoria.
Sostanzialmente si creano due funzioni alloc(n), dove n sono le locazioni necessarie e afree(char * p) per rilasciare una porzione di memoria detenuta dal puntatore p. La funzione alloc restituisce un puntatore a n locazioni consecutive, ognuna della dimensione di un char. La seconda afree(p) rende libera la memoria occupata dal puntatore p. Lo stesso testo, fcendo comprendere come esse siano rudimentali, ma interessanti per un primo scopo di studio dell'aritmetica dei puntatori fa osservare che le chiamate alla afree dovrebbero devono avvenire nell'ordine inverso delle chiamate alla alloc. In quanto la memoria gestita da alloc e afree è strutturata come una pila, ossia una lista gestita con logica LIFO.
Vengo al dunque, per la alloc non mi pare ci siano particolari dubbi. Mentre mi lascia perplesso l'implementazione della afree.
Nel K&R la alloc è così implementata:
vodi afree(char *p)
{
if(p >= allocbuf && p < allocbuf +ALLOCSIZE)
allocp = p;
}
Ciò che mi lascia perplesso è che l'implementazione proposta verifica che il puntatore passato sia un puntatore che sta all'interno della porzione di memoria che può restituire sottoporzioni di memoria allocabile. Ma questo è del tutto evidente che se passo un puntatore che sta in un punto qualsiasi questo comporterebbe a una compromissione dei dati detenuti dagli altri puntatori ancora attivi e restituiti. Come il libro accenna, la liberazione di memoria deve essere effettuata con logica LIFO, pertanto l'implementazione di afree dovrebbe non solo verificare che il puntatore passato sia all'interno della zona di memoria allocabile ma che esso sia davvero l'ultimo puntatore restituito da alloc.
Forse K&R intendeva che lasciava all'utilizzatore la consapevolezza di passare l'ultimo puntatore ottenuto da alloc?
Di seguito le mie implementazioni e a tal proposito vorrei una vostra interpretazione di K&R e su quanto implementato da me e se concordate.
main.c:
#include <stdio.h>
#include <stdlib.h>
#include "mydynamicsmeory.h"
#include "funzioni_app.h"
/*
* Nel presente esercizio mostriamo le basi rudimentali della gestione della
* memoria in C. Ma soprattutto approfondiremo il legame tra array e puntatori,
* Anzi vedremo quanto siano intimi e vedremo l'aritmetica di puntatori.
* Qui, partendo da le nozioni sull'utilizzo dei puntatori e dell'aritemetica
* dei puntatori implementeremo una rudimentale funzione per alloocare dinamicamente
* la memoria in C. Un funzione fatta "home made". Tale funzione vedremo ha
* delle grosse limitazioni, superate dalle funzioni della libreria standard del
* C (malloc e free)
* Le funzioni rudimentali che implementeremo autonomamente le chiameremo
* alloc e afree
*/
int main(int argc, char** argv) {
char c;
printf("Scegliere 1 per sperimentare le limitazioni delle funzioni create (alloc e afree)\n");
while((c = getchar()) != EOF)
{
switch(c)
case '1':
allocazionrLiFoAlloc();
break;
}
return (EXIT_SUCCESS);
}
void allocazionrLiFoAlloc()
{
/**
* Qui apprendiamo i primi concetti della funzione alloc.
* Il grosso problema di questa prima funzione primitiva è quella
* che la gestione è LiFo quindi le chiamate ad afree devono essere
* fatte inordine inverso alla chiamate di alloc.
* Vedremo in altra funzione come "rudimentalmente" come superare questa gestione
* Si rammenti che alloc(n) restituisce uno spazio memoria grande
* n*sizeof(char). Quindi di n byte di char.
*/
int n1 = 5;
int n2 = 9;
char *p1;
p1 = alloc(n1);
printf("indirizzo p1 %x \n", p1);
char input1[] = {'C','i','a','o','\0'};
int cnt = 0;
while(*(input1+cnt)!='\0')
{
*(p1+cnt) = input1[cnt];
cnt++;
}
p1[cnt] = '\0';
char *p2;
p2 = alloc(n2);
printf("indirizzo p2 %x \n", p2);
char input2[] = {'L','e','o','n', 'a', 'r', 'd' ,'o', '\0'};
cnt = 0;
while(*(input2+cnt)!='\0')
{
*(p2+cnt) = input2[cnt];
cnt++;
}
p2[cnt] = '\0';
printf("Valore p1 %s\n", p1);
printf("Valore p2 %s\n", p2);
afree(p2);
char *p3;
p3 = alloc(7);
char input3[] = {'S','i','l','v', 'i', 'a','\0'};
cnt = 0;
while(*(input3+cnt)!='\0')
{
*(p3+cnt) = input3[cnt];
cnt++;
}
p3[cnt] = '\0';
printf("Valore p2 %s\n", p2);
}
mydynamicsmeory.h (dichiarazione delle funzioni alloc e afree):
#ifndef FUNZIONI_STUDIO_ALLOCAZIONE_MEMORIA_H
#define FUNZIONI_STUDIO_ALLOCAZIONE_MEMORIA_H
#ifdef __cplusplus
extern "C" {
#endif
#define ALLOCSIZE 10000
char* alloc(int n);
void afree(char *p);
#ifdef __cplusplus
}
#endif
#endif /* FUNZIONI_STUDIO_ALLOCAZIONE_MEMORIA_H */
funzionie_app.h sono dichiarate le funzioni di servizio applicative:
#ifndef FUNZIONI_APP_H
#define FUNZIONI_APP_H
#ifdef __cplusplus
extern "C" {
#endif
void allocazionrLiFoAlloc();
#ifdef __cplusplus
}
#endif
#endif /* FUNZIONI_APP_H */
alloc.c (qui la mia implementazione di afree(char *p):
/*
* In alloc.c vengono definite le funzioni fatte "in casa" per l'allocazione
* dinamica della memoria. Funzioni rudimentali, ma che consentono di comprendre
* e applicare puntatori e l'aritmetica dei puntatori
* L'implementazione di fatto è unaa pila la cui alloc(n) restituisce un puntatore
* per n locazioni - ogni locazione della dimensione di un char - all'interno di
* una porzione di memoria consecutiva definita con il puntatore allocbuf
* afree libera il blocco di memoria allocato per un dato puntatore *p restituito
* da alloc.
* Essendo l'implementazione di alloc una PILA di tipo LIFO occorre chiamare
* per prima la afree per l'ultio puntatore restituito. Ovviamente queste
* sono grosse limitazioni che sono superate dalle funzioni della libreria
* standard del C
*/
#include <stdio.h>
#include "mydynamicsmeory.h"
static char allocbuf[ALLOCSIZE]; /** allocbuf è dichiarato static in modo che
* l'array sia visibile soltanto all'interno del
* file alloc.c per ovvie questioni di sicurezza
* l'accesso a allocbuf è pertanto riservato
* alle funzioni alloc e afree
* SI TENGA PRESENTE CHE DA QUESTO MOMENTO
* LA MEMORIA È ALLOCATA
*/
static char *allocp = allocbuf; /** allocp è la posizione corrente già in uso
* all'interno del buffer di memoria allocbuf
* che servirà per capire alle successive
* richieste quali porizioni di meoria (puntatore
* è possibile restituire anche in questo caso
* si dichiara static perché sia un'informazione
* nota solo all'interno del file alloc.c e
* più precismaente alle sole funzioni alloc e
* afree. allocp indica in sostanza qual è la
* prima locazione di memoria utile (libera) */
/**
* Alloca dinamicamente una porizione di memoria
* @param n dimensione di memoria desiderata n*sizeof(char) ovvero n char
* @return puntatore alla locazione desiderata
*/
char* alloc(int n)
{
if((allocp + n) <= (allocbuf + ALLOCSIZE))
{
allocp += n; /** questo è il nuovo indirizzo utile per la prossima
* allocazione */
return allocp - n; /** Tolgo n perché devo dare l'inizio della locazione
* utile
*/
}
else{
/** Non c'è abbastanza spazio */
printf("MEMORIA INSUFFICIENTE...");
return 0;
}
}
/**
* La funzione rilascia lo spazio di memoria occupato dal puntatore p
* restituito da alloc(n). Sostanzialmente faremo retrocedere il puntatore
* alla prima locazione utile (allocp).
* Attenzione come detto posso deallocare soltanto l'ultimo puntatore restituito
* alloc è una pila con logica LiFo
* @param p
*/
void afree(char* p)
{
int i = 0;
while((p[i]) != '\0')
{
i++;
}
if((&p[i])+1 == allocp)
{
allocp = p;
printf("Puntatore alla nuova locazione disponibile: %x\n", allocp);
}
else{
/** Non è stato passato l'ultimo puntare restituito*/
printf("ATTENZIONE IMPOSSIBILE RILASCIARE LA MEMORIA. RILASCIARE L'ULTIMO PUNTATORE RESTITUITO!\n");
}
}
Vi sono grato di un vostro parere. È un "errore/semplificazione" del K&R, assumendo che deve essere l'utente a saper quale puntatore passare ad afree? La mia implementazione pur corretta da un punto di vista applicativo è errata concettualmente, o meglio non ho compreso quanto cercava di esporre il K&R. Insomma la mia implementazione verifica che il puntatore sia davvero l'ultimo restituito per garantire la consistenza dei dati al momento conservati nella pila di memoria.
Un saluto e un grazie a tutti.