KR Aritmetica degli indirizzi dubbio

di il
4 risposte

KR Aritmetica degli indirizzi dubbio

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.

4 Risposte

  • Re: KR Aritmetica degli indirizzi dubbio

    Ahhh qui ci sta il pippone sullallocazione della memoria, in teoria è in pratica, ma necessaria tastiera fisica
  • Re: KR Aritmetica degli indirizzi dubbio

    +m2+ ha scritto:


    Ahhh qui ci sta il pippone sullallocazione della memoria, in teoria è in pratica, ma necessaria tastiera fisica
    Aiuto +m2+ mi stai sfottendo? Lo dico in senso scherzoso, ci mancherebbe, Ahah! Mi stai dicendo che mi sto facendo un pippone senza senso?
    Aiutoooo

  • Re: KR Aritmetica degli indirizzi dubbio

    Ehhhh abbastanza... Allocazione della memoria è affine ad allocazione di spazio disco, come un filesystem.
    Nessuno vieta di guardare il sorgente di malloc 'vero'.
    Oppure di porsi il problema : come farei un vero malloc free e realloc?
  • Re: KR Aritmetica degli indirizzi dubbio

    +m2+ ha scritto:


    Ehhhh abbastanza... Allocazione della memoria è affine ad allocazione di spazio disco, come un filesystem.
    Nessuno vieta di guardare il sorgente di malloc 'vero'.
    Oppure di porsi il problema : come farei un vero malloc free e realloc?
    Ciao +m2+,
    hai perfettamente ragione, questo lungo un percorso di apprendimento è quanto farei e farò, però prima di poter analizzare la libreria, funzioni di allocazioni dinamiche vere di memoria, occorre aver chiaro a se stessi di aver compresi i concetti fondamentali. Generalmente quando inizio ad apprendere una cosa nuova inizio con molto modesta e con un approccio socratico.

    Pur restando, assolutamente vero, la mia domanda era, forse banale, forse di scarso senso (?), rivolta a verificare che avessi compreso quanto stava dicendo il testo e la teoria. Ovvio, questo lo dice il testo stesso, ma credo che sia chiaro anche a me, che non possono essere certo quelle le modalità di allocazione dinamica per la scrittura di un codice efficiente, flessibilie e realizzabile.

    Tutto qui, comunque l'ironia sana come la tua io l'apprezzo, pure la schiettezza.

    Grazie, sopratutto per dedicare il tuo tempo e le tue considerazioni sempre ogni volta che si scrive.
Devi accedere o registrarti per scrivere nel forum
4 risposte