Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
C/C++ - Uso creativo di void*
Forum - C/C++ - Uso creativo di void*

Pagine: [ 1 2 3 4 ] Precedente | Prossimo
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 9:00
Martedì, 11/07/2017
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)

Codice sorgente - presumibilmente C#

  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. /*==============================================================================
  5. Riceve tramite il parametro array un puntatore ad un array di puntatori di tipo
  6. qualsiasi che contiente la quantita' di elementi indicata dal parametro qEl.
  7. Compatta tutti i puntatori non NULL in testa all'array, spostando in coda tutti
  8. i puntatori NULL.
  9.  
  10. Occorre fare molta attenzione al dato da passare alla funzione tramite il
  11. parametro array, assicurandosi che sia effettivamente un array di puntatori come
  12. ad esempio...
  13.  
  14. void esempio( void ) {
  15.     int i, numeri[10];
  16.     int *array[10];
  17.     size_t non_nulli;
  18.  
  19.     for( i=0; i<10; ++i ) {
  20.         numeri[i] = i+1;
  21.         array[i] = &numeri[i];
  22.     }
  23.  
  24.     // annulla alcuni puntatori
  25.     array[0] = NULL;
  26.     array[2] = NULL;
  27.     array[4] = NULL;
  28.     array[5] = NULL;
  29.     array[9] = NULL;
  30.  
  31.     non_nulli = compatta_array_di_puntatori( array, 10 );
  32. }
  33.  
  34. In caso di successo restituisce la quantita' dei puntatori non NULL presenti
  35. nell'array. In caso di insuccesso restituisce (size_t)-1. L'unica causa di
  36. insuccesso segnalata e' il passaggio di un parametro array nullo.
  37. ==============================================================================*/
  38.  
  39. size_t compatta_array_di_puntatori( void *array, size_t qEl ) {
  40.     if( array ) {
  41.         char **po = (char**) array; /* per scorrere l'array originale */
  42.         char **pm = (char**) array; /* per scorrere l'array modificato */
  43.         size_t i, l = 0; /* l: per la lunghezza dell'array risultante */
  44.  
  45.         for( i=0; i<qEl; ++i ) { /* per tutti i puntatori dell'array */
  46.             if( *po!=NULL ) { /* se il puntatore corrente non e' NULL */
  47.                 ++l; /* copia, quindi l'array modificato si "allunga" */
  48.                 *pm++ = *po; /* copia il puntatore corrente */
  49.                 *po++ = NULL; /* annulla l'originale del puntatore spostato */
  50.             } else po++; /* avanza di una posizione, senza copiare */
  51.         }
  52.  
  53.         return l; /* restituisce la lunghezza dell'array modificato */
  54.     } else return (size_t) -1; /* restituire il valore massimo per size_t */
  55. }
  56.  
  57.  
  58.  
  59. /*==============================================================================
  60. QUEL CHE SEGUE E' SOLO UN PROGRAMMA DI PROVA SENZA ALCUNA UTILITA'!
  61. ==============================================================================*/
  62.  
  63. #define Q_EL    10
  64.  
  65. void inizializza_array( int **array, int *numeri, size_t *annullati );
  66. void visualizza_array( int **array, size_t qEl, size_t non_nulli );
  67.  
  68. int main( void ) {
  69.     size_t annullati, non_nulli;
  70.     int numeri[Q_EL];
  71.     int *array[Q_EL];
  72.  
  73.     inizializza_array( array, numeri, &annullati );
  74.  
  75.     printf( " %s", "Prima del compattamento" );
  76.     visualizza_array( array, Q_EL, Q_EL-annullati );
  77.  
  78.     non_nulli = compatta_array_di_puntatori( array, Q_EL );
  79.  
  80.     printf( " %s", "Dopo il compattamento" );
  81.     visualizza_array( array, Q_EL, non_nulli );
  82.  
  83.     return 0;
  84. }
  85.  
  86. void inizializza_array( int **array, int *numeri, size_t *annullati ) {
  87.     int i;
  88.  
  89.     for( i=0; i<Q_EL; ++i ) {
  90.         numeri[i] = i+1;
  91.         array[i] = &numeri[i];
  92.     }
  93.  
  94.     array[0] = NULL; /* il primo */
  95.     array[2] = NULL;
  96.     array[4] = NULL; /* con questo... */
  97.     array[5] = NULL; /* due consecutivi */
  98.     array[9] = NULL; /* l'ultimo */
  99.  
  100.     *annullati = 5;
  101. }
  102.  
  103. void visualizza_array( int **array, size_t qEl, size_t non_nulli ) {
  104.     size_t i;
  105.  
  106.     printf( " l'array contiene\n %u puntatori"
  107.             " non NULL e %u puntatori NULL:\n\n"
  108.             "\t           |  indirizzo | valore |\n",
  109.             non_nulli, qEl-non_nulli );
  110.  
  111.     for( i=0; i<qEl; ++i ) {
  112.         if( array[i] ) {
  113.             printf( "\tarray[%02u]: | 0x%08X |   %02d   |\n",
  114.                     i+1, (unsigned int)array[i], *(array[i]) );
  115.         }
  116.         else {
  117.             printf( "\tarray[%02u]: |   (NULL)   |   ??   |\n", i+1 );
  118.         }
  119.     }
  120.  
  121.     printf( "%s", "\n" );
  122. }



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

Codice sorgente - presumibilmente C/C++

  1. Prima del compattamento l'array contiene
  2.  5 puntatori non NULL e 5 puntatori NULL:
  3.  
  4.                    |  indirizzo | valore |
  5.         array[01]: |   (NULL)   |   ??   |
  6.         array[02]: | 0x0022FED4 |   02   |
  7.         array[03]: |   (NULL)   |   ??   |
  8.         array[04]: | 0x0022FEDC |   04   |
  9.         array[05]: |   (NULL)   |   ??   |
  10.         array[06]: |   (NULL)   |   ??   |
  11.         array[07]: | 0x0022FEE8 |   07   |
  12.         array[08]: | 0x0022FEEC |   08   |
  13.         array[09]: | 0x0022FEF0 |   09   |
  14.         array[10]: |   (NULL)   |   ??   |
  15.  
  16.  Dopo il compattamento l'array contiene
  17.  5 puntatori non NULL e 5 puntatori NULL:
  18.  
  19.                    |  indirizzo | valore |
  20.         array[01]: | 0x0022FED4 |   02   |
  21.         array[02]: | 0x0022FEDC |   04   |
  22.         array[03]: | 0x0022FEE8 |   07   |
  23.         array[04]: | 0x0022FEEC |   08   |
  24.         array[05]: | 0x0022FEF0 |   09   |
  25.         array[06]: |   (NULL)   |   ??   |
  26.         array[07]: |   (NULL)   |   ??   |
  27.         array[08]: |   (NULL)   |   ??   |
  28.         array[09]: |   (NULL)   |   ??   |
  29.         array[10]: |   (NULL)   |   ??   |
  30.  
  31.  
  32. Process returned 0 (0x0)   execution time : 0.049 s
  33. Press any key to continue.


Ultima modifica effettuata da AldoBaldo il 11/07/2017 alle 9: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.
PM Quote
Avatar
Mikelius (Member)
Expert


Messaggi: 525
Iscritto: 14/04/2017

Segnala al moderatore
Postato alle 9:25
Martedì, 11/07/2017
Salve,

Scusa l'ignoranza, ma che differenza ci sarebbe con un semplice ordinamento dell'Array?

PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 9:33
Martedì, 11/07/2017
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.
PM Quote
Avatar
Mikelius (Member)
Expert


Messaggi: 525
Iscritto: 14/04/2017

Segnala al moderatore
Postato alle 9:40
Martedì, 11/07/2017
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 il 11/07/2017 alle 9:43
PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 10:35
Martedì, 11/07/2017
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.
PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 19:37
Mercoledì, 12/07/2017
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.

PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 22:41
Mercoledì, 12/07/2017
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.
PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 23:01
Mercoledì, 12/07/2017
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.

PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 23:03
Mercoledì, 12/07/2017
Non so bene perché (ho pensato poco) ma il tuo algoritmo mi puzza....

PM Quote
Pagine: [ 1 2 3 4 ] Precedente | Prossimo