Oppure

Loading
11/07/17 7:00
AldoBaldo
Ah! Il potere del tempo libero! Uno si mette lì e si fa venire delle idee balzane...

Volendo creare in C una funzione che "compatti" aaRRRaay di puntatori di qualsiasi tipo e non potendo usare void**, al netto dei possibili errori che un programmatore disattento potrebbe fare passando parametri non validi, sarebbe plausibile una soluzione come quella che copio/incollo qui sotto?

Dai test che ho fatto sembrerebbe di sì, nessun errore in compilazione e puntatori piazzati esattamente dove uno se li aspetterebbe, però incombe sempre la paranoia dei "comportamenti indefiniti", quelli che danno luogo a codice che funziona in un certo ambiente e non funziona in un altro...

(il codice "incriminato" è quello contenuto tra la riga 39 e la riga 55, tutto il resto è solo contorno)

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

/*==============================================================================
Riceve tramite il parametro array un puntatore ad un array di puntatori di tipo
qualsiasi che contiente la quantita' di elementi indicata dal parametro qEl.
Compatta tutti i puntatori non NULL in testa all'array, spostando in coda tutti
i puntatori NULL.

Occorre fare molta attenzione al dato da passare alla funzione tramite il
parametro array, assicurandosi che sia effettivamente un array di puntatori come
ad esempio...

void esempio( void ) {
    int i, numeri[10];
    int *array[10];
    size_t non_nulli;

    for( i=0; i<10; ++i ) {
        numeri[i] = i+1;
        array[i] = &numeri[i];
    }

    // annulla alcuni puntatori
    array[0] = NULL;
    array[2] = NULL;
    array[4] = NULL;
    array[5] = NULL;
    array[9] = NULL;

    non_nulli = compatta_array_di_puntatori( array, 10 );
}

In caso di successo restituisce la quantita' dei puntatori non NULL presenti
nell'array. In caso di insuccesso restituisce (size_t)-1. L'unica causa di
insuccesso segnalata e' il passaggio di un parametro array nullo.
==============================================================================*/

size_t compatta_array_di_puntatori( void *array, size_t qEl ) {
    if( array ) {
        char **po = (char**) array; /* per scorrere l'array originale */
        char **pm = (char**) array; /* per scorrere l'array modificato */
        size_t i, l = 0; /* l: per la lunghezza dell'array risultante */

        for( i=0; i<qEl; ++i ) { /* per tutti i puntatori dell'array */
            if( *po!=NULL ) { /* se il puntatore corrente non e' NULL */
                ++l; /* copia, quindi l'array modificato si "allunga" */
                *pm++ = *po; /* copia il puntatore corrente */
                *po++ = NULL; /* annulla l'originale del puntatore spostato */
            } else po++; /* avanza di una posizione, senza copiare */
        }

        return l; /* restituisce la lunghezza dell'array modificato */
    } else return (size_t) -1; /* restituire il valore massimo per size_t */
}



/*==============================================================================
QUEL CHE SEGUE E' SOLO UN PROGRAMMA DI PROVA SENZA ALCUNA UTILITA'!
==============================================================================*/

#define Q_EL    10

void inizializza_array( int **array, int *numeri, size_t *annullati );
void visualizza_array( int **array, size_t qEl, size_t non_nulli );

int main( void ) {
    size_t annullati, non_nulli;
    int numeri[Q_EL];
    int *array[Q_EL];

    inizializza_array( array, numeri, &annullati );

    printf( " %s", "Prima del compattamento" );
    visualizza_array( array, Q_EL, Q_EL-annullati );

    non_nulli = compatta_array_di_puntatori( array, Q_EL );

    printf( " %s", "Dopo il compattamento" );
    visualizza_array( array, Q_EL, non_nulli );

    return 0;
}

void inizializza_array( int **array, int *numeri, size_t *annullati ) {
    int i;

    for( i=0; i<Q_EL; ++i ) {
        numeri[i] = i+1;
        array[i] = &numeri[i];
    }

    array[0] = NULL; /* il primo */
    array[2] = NULL;
    array[4] = NULL; /* con questo... */
    array[5] = NULL; /* due consecutivi */
    array[9] = NULL; /* l'ultimo */

    *annullati = 5;
}

void visualizza_array( int **array, size_t qEl, size_t non_nulli ) {
    size_t i;

    printf( " l'array contiene\n %u puntatori"
            " non NULL e %u puntatori NULL:\n\n"
            "\t           |  indirizzo | valore |\n",
            non_nulli, qEl-non_nulli );

    for( i=0; i<qEl; ++i ) {
        if( array[i] ) {
            printf( "\tarray[%02u]: | 0x%08X |   %02d   |\n",
                    i+1, (unsigned int)array[i], *(array[i]) );
        }
        else {
            printf( "\tarray[%02u]: |   (NULL)   |   ??   |\n", i+1 );
        }
    }

    printf( "%s", "\n" );
}


In uscita, il programma di prova mi dà...

 Prima del compattamento l'array contiene
 5 puntatori non NULL e 5 puntatori NULL:

                   |  indirizzo | valore |
        array[01]: |   (NULL)   |   ??   |
        array[02]: | 0x0022FED4 |   02   |
        array[03]: |   (NULL)   |   ??   |
        array[04]: | 0x0022FEDC |   04   |
        array[05]: |   (NULL)   |   ??   |
        array[06]: |   (NULL)   |   ??   |
        array[07]: | 0x0022FEE8 |   07   |
        array[08]: | 0x0022FEEC |   08   |
        array[09]: | 0x0022FEF0 |   09   |
        array[10]: |   (NULL)   |   ??   |

 Dopo il compattamento l'array contiene
 5 puntatori non NULL e 5 puntatori NULL:

                   |  indirizzo | valore |
        array[01]: | 0x0022FED4 |   02   |
        array[02]: | 0x0022FEDC |   04   |
        array[03]: | 0x0022FEE8 |   07   |
        array[04]: | 0x0022FEEC |   08   |
        array[05]: | 0x0022FEF0 |   09   |
        array[06]: |   (NULL)   |   ??   |
        array[07]: |   (NULL)   |   ??   |
        array[08]: |   (NULL)   |   ??   |
        array[09]: |   (NULL)   |   ??   |
        array[10]: |   (NULL)   |   ??   |


Process returned 0 (0x0)   execution time : 0.049 s
Press any key to continue.
Ultima modifica effettuata da AldoBaldo 11/07/17 7:37
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
11/07/17 7:25
Mikelius
Salve,

Scusa l'ignoranza, ma che differenza ci sarebbe con un semplice ordinamento dell'Array?
aaa
11/07/17 7:33
AldoBaldo
L'intenzione non è ordinare l'array, bensì compattarlo, ovvero fare in modo che tutti i "buchi" rappresentanti da puntatori NULL finiscano in coda. L'ordine degli altri puntatori non viene intaccato. Ci sono situazioni nelle quali una funzione del genere mi è stata utile, quel che mi chiedo è: è generalizzabile usando void* a quel modo? si può fare o è un abominio che funziona solo perché uso un certo compilatore in un certo ambiente di sviluppo?
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
11/07/17 7:40
Mikelius
Capito... mi sembrava li volessi anche ordinarli...
un'altra idea :

L'hai presente la funzione per eliminare il doppio spazio di qualche settimana fa?
Se ne usassi una simile per elimirare i NULL??
cioè testi un elemento

Se è NULL e NON e' l'ultimo operi uno shift del resto dell'Array

Non credo importi se il puntatore punti a char, float o granita con panna. dentro avrà sempre 8 bit.se sono 000000000 vuol dire che è NULL (non vorrei sbagliarmi)
altrimenti è un puntatore valito e te lo metti in testa



P.s. guarda che sono più autodidatta di te, quindi le mie sono isee da chi si è svegliato, non sa programmare e deve ancora prendersi un caffè decente XD
Ultima modifica effettuata da Mikelius 11/07/17 7:43
aaa
11/07/17 8:35
AldoBaldo
Sì, infatti più o meno funziona allo stesso modo.

Quel void*, però... cioè, faccio un cast di un puntatore a singola indirezione che punta a un tipo destinato a non contenere nulla per trasformarlo in un puntatore a doppia indirezione che punta a un tipo che potrebbe non essere quello originariamente inteso dal chiamante... ehm...

Tra l'altro, il chiamante potrebbe anche chiamare la funzione con un puntatore a indirezione singola, o tripla, creando potenzialmente disastri a non finire. Ma questo succederebbe solo a chi non si informasse a dovere circa le caratteristiche della funzione prima di usarla. Pessima abitudine quando si "riciclano" funzioni altrui, dunque peggio per lui/lei!
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
12/07/17 17:37
TheDarkJuster
Perché chiami la funzione compatta array? Hai un algoritmo run-length dentro?
Ti faccio questa domanda perché sono da mobile e il codice non è molti leggibile con gli a capo incasinati.
aaa
12/07/17 20:41
AldoBaldo
Per sapere cosa fosse l'algoritmo run-length ho dovuto chiedere aiuto a google. Ora so cos'è, quindi ti posso dire che no, non ha niente a che fare con la compressione dei dati. L'ho chiamata così perché prende dei puntatori "sparsi in un array pieno di buchi" e li raggruppa tutti in testa all'array stesso. T'è venuto in mente qualche nome migliore che vorresti suggerirmi? Non è che io ci sia stato a pensare più di tanto...

P.S. accoda_puntatori_nulli()? raggruppa_puntatori_validi()? assesta_array_puntatori? fammi_una_granita_con_la_panna? (per quest'ultimo, copyright by Mikelius)
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
12/07/17 21:01
TheDarkJuster
Secondo me... Stai sbagliando il concetto.

Tu accetti un void* per fare un cast a char** e controlli se *pm è null, ma ciò non ha molto senso imho...

Dovresti accettare un array di array di puntatori: un void** po. Controllare *(po+n) per ogni n e usare un algoritmo di ordinamento tipo quick sort in cui dai valore 0 ai null e 1 al resto.
aaa