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* - Pagina 3

Pagine: [ 1 2 3 4 ] Precedente | Prossimo
Avatar
lumo (Member)
Expert


Messaggi: 449
Iscritto: 18/04/2010

Segnala al moderatore
Postato alle 1:09
Venerdì, 14/07/2017
Il mio consiglio è di usare il lanciafiamme su codici del genere, però poi mi sono ricordato di quando anche io facevo in one liner e mi divertivo molto, anni fa.

PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 2:23
Venerdì, 14/07/2017
L'ho scritto in fretta, e testato tipo 5 volte, ma sembra funzionare.
Io svolgerei il tuo "esercizio" in questo modo.

Il cuore della soluzione è che c'è il puntatore all'inizio della coda e quello alla fine.
Quello alla fine punta sempre all'ultimo elemento non nullo, e quello all'inizio l'elemento "attuale" (quello da mettere alla fine nel caso sia nullo).
Il ciclo scorre tutti gli elementi dall'inizio fino ad end, mantenendo SEMPRE la proprietà sopra elencata di end (perchè a scambiare un null con null non si risolve niente), e se !(*begin), ovvero l'indirizzo puntato da begin è null lo scambia con l'indirizzo puntato da end.

Codice sorgente - presumibilmente C++

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <time.h>
  4. #include <malloc.h>
  5.  
  6. #define Q_EL 50
  7.  
  8. void move_nulls_to_end(void **pointers, size_t pointersNum) {
  9.     char **begin = (char**)pointers;
  10.     char **end = (char**)pointers + pointersNum;
  11.  
  12.     while ((!(*end)) && (end > begin))
  13.         end--;
  14.  
  15.     while (begin < end) {
  16.         if (!(*begin)) {
  17.             char *temp = *end;
  18.             *end = *begin;
  19.             *begin = temp;
  20.            
  21.             do {
  22.                 end--;
  23.            } while ((!(*end)) && (end > begin));
  24.         }
  25.        
  26.         begin++;
  27.     }
  28. }
  29.  
  30. void init_array(void **pointers, size_t pointersNum) {
  31.     srand(time(NULL));
  32.     char a;
  33.  
  34.     while (pointersNum > 0) {
  35.         *(pointers++) = (rand() % 2) ? &a : NULL;
  36.  
  37.         pointersNum--;
  38.     }  
  39. }
  40.  
  41. void print_array(void **pointers, size_t pointersNum) {
  42.     while (pointersNum > 0) {
  43.         if (*(pointers)) printf("-");
  44.         else printf(".");
  45.    
  46.         pointers++;
  47.         pointersNum--;
  48.     }
  49.     printf("\n");
  50. }
  51.  
  52. int main() {
  53.     char **p = (char**)malloc(sizeof(char*) * Q_EL);
  54.     init_array((void**)p, Q_EL);
  55.     print_array((void**)p, Q_EL);
  56.  
  57.     move_nulls_to_end((void**)p, Q_EL);
  58.     print_array((void**)p, Q_EL);
  59.  
  60.     free((void*)p);
  61.     return 0;
  62. }



Miei output:

test 1:
Codice sorgente - presumibilmente Plain Text

  1. --...-..-..-.--....------.-.-..--.-.--......---..-
  2. ------------------------..........................



test 2:
Codice sorgente - presumibilmente Plain Text

  1. --.--.--..-.---.....-...-.-..-.-.-.--..-..-.--.--.
  2. ------------------------..........................



test 3:
Codice sorgente - presumibilmente Plain Text

  1. -.--....-.--..........-.-..-.--.-.--.--...-..-----
  2. ----------------------............................



test 4:
Codice sorgente - presumibilmente Plain Text

  1. -..--.--...---.-..-.-.....--.--.---.-.---...-....-
  2. ------------------------..........................



Così a spanne direi che funziona..... Ma sai...... L'ho scritto alle 2 di notte in 10 minuti.......
Comunque l'idea di come mi sembra più logico scrivere funzioni del genere te la ho data.

Secondo la mia modesta opinione fare questo cast:
Codice sorgente - presumibilmente C/C++

  1. char **po = (char**) array;



partendo da array di tipo void* è un pugno in un occhio e uno all'aritmetica dei puntatori, se come ho capito (potrei sbagliarmi) l'intento è di "semi-ordinare" un array di puntatori, perchè un array di puntatori va passato come puntatore al primo elemento dell'array, che a sua volta è un puntatore, quindi void**, non void*.

PM Quote
Avatar
lumo (Member)
Expert


Messaggi: 449
Iscritto: 18/04/2010

Segnala al moderatore
Postato alle 11:55
Venerdì, 14/07/2017
Testo quotato

Postato originariamente da TheDarkJuster:

L'ho scritto in fretta, e testato tipo 5 volte, ma sembra funzionare.
Io svolgerei il tuo "esercizio" in questo modo.

Il cuore della soluzione è che c'è il puntatore all'inizio della coda e quello alla fine.
Quello alla fine punta sempre all'ultimo elemento non nullo, e quello all'inizio l'elemento "attuale" (quello da mettere alla fine nel caso sia nullo).
Il ciclo scorre tutti gli elementi dall'inizio fino ad end, mantenendo SEMPRE la proprietà sopra elencata di end (perchè a scambiare un null con null non si risolve niente), e se !(*begin), ovvero l'indirizzo puntato da begin è null lo scambia con l'indirizzo puntato da end.


Ho ritrovato lo stesso algoritmo nel mio esame di dati e algoritmi e in questo caso va quasi bene, ma il codice di AldoBaldo ha una caratteristica in più ovvero mantiene l'ordine relativo dei puntatori non nulli, mentre il tuo algoritmo ne scambia l'ordine tranne nel caso facile in cui sono già separati dai NULL.

Testo quotato


Secondo la mia modesta opinione fare questo cast:
Codice sorgente - presumibilmente C/C++

  1. char **po = (char**) array;



partendo da array di tipo void* è un pugno in un occhio e uno all'aritmetica dei puntatori, se come ho capito (potrei sbagliarmi) l'intento è di "semi-ordinare" un array di puntatori, perchè un array di puntatori va passato come puntatore al primo elemento dell'array, che a sua volta è un puntatore, quindi void**, non void*.


Il problema è che vuoi che la funzione sia generica, e che funzioni su array di puntatori (T**) ma la conversione T** -> void** è undefined.
Quindi l'unica maniera sensata di fare una funzione con interfaccia generica è avere void* come parametro.
All'interno della funzione poi si può usare char** o void** o vattelapesca**, io preferisco void** perché fa capire che non interessa molto il tipo preciso di puntatore quanto il fatto che sia un puntatore.

PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 12:18
Venerdì, 14/07/2017
Testo quotato

Postato originariamente da lumo:

Testo quotato

Postato originariamente da TheDarkJuster:

L'ho scritto in fretta, e testato tipo 5 volte, ma sembra funzionare.
Io svolgerei il tuo "esercizio" in questo modo.

Il cuore della soluzione è che c'è il puntatore all'inizio della coda e quello alla fine.
Quello alla fine punta sempre all'ultimo elemento non nullo, e quello all'inizio l'elemento "attuale" (quello da mettere alla fine nel caso sia nullo).
Il ciclo scorre tutti gli elementi dall'inizio fino ad end, mantenendo SEMPRE la proprietà sopra elencata di end (perchè a scambiare un null con null non si risolve niente), e se !(*begin), ovvero l'indirizzo puntato da begin è null lo scambia con l'indirizzo puntato da end.


Ho ritrovato lo stesso algoritmo nel mio esame di dati e algoritmi e in questo caso va quasi bene, ma il codice di AldoBaldo ha una caratteristica in più ovvero mantiene l'ordine relativo dei puntatori non nulli, mentre il tuo algoritmo ne scambia l'ordine tranne nel caso facile in cui sono già separati dai NULL.

Testo quotato


Secondo la mia modesta opinione fare questo cast:
Codice sorgente - presumibilmente C/C++

  1. char **po = (char**) array;



partendo da array di tipo void* è un pugno in un occhio e uno all'aritmetica dei puntatori, se come ho capito (potrei sbagliarmi) l'intento è di "semi-ordinare" un array di puntatori, perchè un array di puntatori va passato come puntatore al primo elemento dell'array, che a sua volta è un puntatore, quindi void**, non void*.


Il problema è che vuoi che la funzione sia generica, e che funzioni su array di puntatori (T**) ma la conversione T** -> void** è undefined.
Quindi l'unica maniera sensata di fare una funzione con interfaccia generica è avere void* come parametro.
All'interno della funzione poi si può usare char** o void** o vattelapesca**, io preferisco void** perché fa capire che non interessa molto il tipo preciso di puntatore quanto il fatto che sia un puntatore.



Riguardo all'ordine relativo è vero: rovina l'ordine relativo, spero non sia un problema, ero solo concentrato a spostare i null in fondo nel modo più veloce possibile.

PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 14:50
Venerdì, 14/07/2017
Tre risposte che mi richiederanno un tempo di digestione piuttosto lungo. Portate pazienza, sto "elaborando" (cercando di capire). Molto stimolante, devo dire: se ritenete, andate avanti con la discussione, che io incombo nel buio leggendo avidamente tutto quel che avete da dire.


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
soury (Member)
Newbie


Messaggi: 7
Iscritto: 09/12/2015

Segnala al moderatore
Postato alle 17:06
Martedì, 18/07/2017
allora il **void funziona senza problemi non so perché ti sia venuto il dubbio, "non_nulli" è la variabile che contiene il risultato e dal momento che è stato dichiarato nel main poi vedere il risultato fuori dal main.

quello che hai è stato creare un problema e risolverla con un "bubble sort" personale COMPLIMENTI;
il passo successivo come ha gia suggerito qualcuno è eliminare i NULL dal vettore in modo da ottimizzarlo e se è una funzione da utilizzare da qualche parte ti permettera di risparmiare memoria.
hai detto che avevi intenzione anche di ordinarle ma dal codice non mi sembra che vengano ordinate (o forse non sono stato attento) comunque ti consiglio di dare un occhiata all "bubble sort" non ti fara male.

In conclusione come prestazioni non ti consiglio di usare il void in una funzione del genere, sarebbe stato ok se all'interno della funzione popolavi l'array risultato ordina. (ripeto forse non ho letto il codice con abbastanza concentrazione!!!)  

PM Quote
Avatar
lumo (Member)
Expert


Messaggi: 449
Iscritto: 18/04/2010

Segnala al moderatore
Postato alle 18:14
Martedì, 18/07/2017
soury: forse devi rileggere meglio il codice e il resto della conversazione perché il tuo commento è inattinente.

PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 18:15
Martedì, 18/07/2017
Non mi ero mai posto il problema del cast di un doppio puntatore, e non sapevo fosse undefined! Personalmente continuo però a preferire un void** in ingresso a quella funzione, perché è più immediato da capire secondo me.

Hai mai visto l'algoritmo che fa arretrare di 1 tutti gli elementi di un array? Uno scambio a due a due:  array =array[i+1] fino alla fine dell'array. Io te ne propongo uno ottimizzato: all'inizio della funzione metti il puntatore della fine array l'ultimo elemento non nullo. Quando in array hai null esegui l'algoritmo fino al puntatore di fine e poi nel puntatore di fine ci scrivi null e decrementi di uno il puntatore della fine.

Più l'algoritmo è necessario e più l'algoritmo è veloce!

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