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++ - Un po' di (in)utilità per stringhe in C
Forum - C/C++ - Un po' di (in)utilità per stringhe in C

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


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 22:25
Venerdì, 19/05/2017
Non so se a qualcuno possa tornare utile questa roba, però ho messo insieme un po' di funzioni di (in)utilità per stringhe dinamiche in C. In caso valga la pena (ditemelo voi) posso aggiungerlo alla sezione "esempi" o "utilità" o chissà quale dell'elenco dei programmi di Pierotofy.

Se intendete leggere sedetevi, perché il codice è un po' lunghetto...

utilita_stringhe_dinamiche.h:

Codice sorgente - presumibilmente VB.NET

  1. #ifndef UTILITA_STRINGHE_DINAMICHE_H_INCLUDED
  2. #define UTILITA_STRINGHE_DINAMICHE_H_INCLUDED
  3.  
  4. /*==============================================================================
  5. duplica_stringa()
  6.  
  7. Riceve il puntatore ad una stringa C, ne effettua una copia in un'area di
  8. memoria dinamica appositamente allocata, restituisce il puntatore alla memoria
  9. allocata (NULL se l'allocazione fallisce).
  10. Spetta al chiamante liberare con libera_buffer() la memoria allocata.
  11. ==============================================================================*/
  12.  
  13. char *duplica_stringa( const char *str );
  14.  
  15.  
  16. /*==============================================================================
  17. dimensiona_stringa()
  18.  
  19. Alloca la quantita' di memoria indicata da dim (dim NON include il carattere
  20. terminatore) e copia la stringa str nello spazio di memoria allocato. Se dim e'
  21. minore della lunghezza corrente della stringa, la stringa viene troncata. Se dim
  22. e' maggiore della lunghezza corrente della stringa, lo spazio eccedente viene
  23. impostato su una serie di zeri. Restituisce il puntatore alla memoria allocata
  24. (NULL se l'allocazione fallisce).
  25. Spetta al chiamante liberare con libera_buffer() la memoria allocata.
  26. ==============================================================================*/
  27.  
  28. char *dimensiona_stringa( const char *str, size_t dim );
  29.  
  30.  
  31. /*==============================================================================
  32. inserisci_stringa()
  33.  
  34. Inserisce la stringa agg nella posizione pos della stringa s. Se pos eccede la
  35. lunghezza della stringa, l'aggiunta viene effettuata in coda alla stringa
  36. stessa. Colloca la stringa risultante in un'area di memoria dinamica
  37. appositamente allocata e restituisce il puntatore alla memoria allocata (NULL se
  38. l'allocazione fallisce).
  39. Spetta al chiamante liberare con libera_buffer() la memoria allocata.
  40. ==============================================================================*/
  41.  
  42. char *inserisci_stringa( const char *str, const char *agg, size_t pos );
  43.  
  44.  
  45. /*==============================================================================
  46. inserisci_intero()
  47.  
  48. Converte in stringa il valore indicato da n, quindi lo inserisce nella posizione
  49. pos della stringa s. Se pos eccede la lunghezza della stringa, l'aggiunta viene
  50. effettuata in coda alla stringa stessa. Colloca la stringa risultante in un'area
  51. di memoria dinamica appositamente allocata e restituisce il puntatore alla
  52. memoria allocata (NULL se l'allocazione fallisce).
  53. Spetta al chiamante liberare con libera_buffer() la memoria allocata.
  54. ==============================================================================*/
  55.  
  56. char *inserisci_intero( const char *str, int n, size_t pos );
  57.  
  58.  
  59. /*==============================================================================
  60. sostituisci_caratteri()
  61.  
  62. Sostituisce nella stringa str tutte le occorrenze dei caratteri indicati nella
  63. stringa orig con i caratteri indicati nelle stesse posizioni nella stringa sost.
  64. Ad esempio, sostituisci_caratteri( "Provetta", "Pt", "Bd" ) da' come esito la
  65. stringa "Brovedda". Colloca la stringa risultante in un'area di memoria dinamica
  66. appositamente allocata e restituisce il puntatore alla memoria allocata (NULL se
  67. l'allocazione fallisce). Spetta al chiamante liberare con libera_buffer() la
  68. memoria allocata.
  69. ==============================================================================*/
  70.  
  71. char *sostituisci_caratteri(
  72.     const char *str, const char *orig, const char *sost );
  73.  
  74.  
  75. /*==============================================================================
  76. sostituisci_frammento()
  77.  
  78. Sostituisce un frammento di l caratteri della stringa s con la stringa sost, a
  79. partire dalla posizione pos (sost puo' anche essere piu' lungo o piu' corto di l
  80. caratteri). Colloca la stringa risultante in un'area di memoria dinamica
  81. appositamente allocata e restituisce il puntatore alla memoria allocata (NULL se
  82. l'allocazione fallisce).
  83. Spetta al chiamante liberare con libera_buffer() la memoria allocata.
  84. ==============================================================================*/
  85.  
  86. char *sostituisci_frammento(
  87.     const char *str, const char *sost, size_t pos, size_t l );
  88.  
  89.  
  90. /*==============================================================================
  91. sostituisci_frammenti()
  92.  
  93. Cerca nella stringa str le ricorrenze della stringa ptrn e le sostituisce con la
  94. stringa sost. Colloca la stringa risultante in un'area di memoria dinamica
  95. appositamente allocata e restituisce il puntatore alla memoria allocata (NULL se
  96. l'allocazione fallisce).
  97. Spetta al chiamante liberare con libera_buffer() la memoria allocata.
  98. ==============================================================================*/
  99.  
  100. char *sostituisci_frammenti(
  101.     const char *str, const char *ptrn, const char *sost );
  102.  
  103.  
  104. /*==============================================================================
  105. sostituisci_segnaposto()
  106.  
  107. Cerca nella stringa str le ricorrenze della stringa ptrn e le sostituisce,
  108. nell'ordine, con le stringhe contenute nell'array di stringhe puntato da sost.
  109. L'array deve contenere la quantita' di stringhe specificata dal parametro qSost.
  110. Se ci sono discrepanze tra la quantita' delle ricorrenze di ptrn in str e il
  111. valore di qSost, prevale la quantita' minore.
  112. Colloca la stringa risultante in un'area di memoria dinamica appositamente
  113. allocata e restituisce il puntatore alla memoria allocata (NULL se l'allocazione
  114. fallisce).
  115. Spetta al chiamante liberare con libera_buffer() la memoria allocata.
  116. ==============================================================================*/
  117.  
  118. char *sostituisci_segnaposto(
  119.     const char *str, const char *ptrn, const char **sost, size_t qSost );
  120.  
  121.  
  122. /*==============================================================================
  123. libera_buffer()
  124.  
  125. Riceve il puntatore ad un puntatore ad una stringa C collocata in un'area di
  126. memoria allocata dinamicamente, libera con free() quella memoria e annulla il
  127. puntatore.
  128. ==============================================================================*/
  129.  
  130. void libera_buffer( char **buffer );
  131.  
  132.  
  133. #endif // UTILITA_STRINGHE_DINAMICHE_H_INCLUDED



utilita_stringhe_dinamiche.c:

Codice sorgente - presumibilmente C++

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4.  
  5. #include "utilita_stringhe_dinamiche.h"
  6.  
  7.  
  8.  
  9. /*==============================================================================
  10. Riceve il puntatore ad una stringa C, ne effettua una copia in un'area di
  11. memoria dinamica appositamente allocata, restituisce il puntatore alla memoria
  12. allocata (NULL se l'allocazione fallisce).
  13. Spetta al chiamante liberare con libera_buffer() la memoria allocata.
  14. ==============================================================================*/
  15.  
  16. char *duplica_stringa( const char *str ) {
  17.     char *tmp = NULL;
  18.  
  19.         if( str ) { // verifica che il parametro s sia una stringa valida
  20.         size_t l = strlen(str)+1; // +1 per includere il terminatore
  21.         if( (tmp=malloc(l)) ) memcpy( tmp, str, l );
  22.     }
  23.  
  24.     return tmp;
  25. }
  26.  
  27.  
  28.  
  29. /*==============================================================================
  30. Alloca la quantita' di memoria indicata da dim (dim NON include il carattere
  31. terminatore) e copia la stringa str nello spazio di memoria allocato. Se dim e'
  32. minore della lunghezza corrente della stringa, la stringa viene troncata. Se dim
  33. e' maggiore della lunghezza corrente della stringa, lo spazio eccedente viene
  34. impostato su una serie di zeri. Restituisce il puntatore alla memoria allocata
  35. (NULL se l'allocazione fallisce).
  36. Spetta al chiamante liberare con libera_buffer() la memoria allocata.
  37. ==============================================================================*/
  38.  
  39. char *dimensiona_stringa( const char *str, size_t dim ) {
  40.     char *tmp = NULL;
  41.  
  42.         if( str ) { // verifica che il parametro s sia una stringa valida
  43.         tmp = calloc( dim+1, sizeof(*tmp) );
  44.  
  45.         if( tmp ) { // allocazione riuscita, copiamo
  46.             size_t l = strlen( str );
  47.             strncpy( tmp, str, l<dim?l:dim );
  48.         }
  49.     }
  50.  
  51.     return tmp;
  52. }
  53.  
  54.  
  55.  
  56. /*==============================================================================
  57. Inserisce la stringa agg nella posizione pos della stringa s. Se pos eccede la
  58. lunghezza della stringa, l'aggiunta viene effettuata in coda alla stringa
  59. stessa. Colloca la stringa risultante in un'area di memoria dinamica
  60. appositamente allocata e restituisce il puntatore alla memoria allocata (NULL se
  61. l'allocazione fallisce).
  62. Spetta al chiamante liberare con libera_buffer() la memoria allocata.
  63. ==============================================================================*/
  64.  
  65. char *inserisci_stringa( const char *str, const char *agg, size_t pos ) {
  66.     char *tmp = NULL;
  67.  
  68.     if( str && agg ) {
  69.         size_t lStr = strlen( str );
  70.         size_t lAgg = strlen( agg );
  71.  
  72.         tmp = malloc( lStr+lAgg+1 );
  73.  
  74.         if( tmp ) { // allocazione riuscita, inseriamo
  75.             if( pos > lStr ) pos = lStr;
  76.             memcpy( tmp, str, pos );
  77.             memcpy( tmp+pos, agg, lAgg );
  78.             memcpy( tmp+pos+lAgg, str+pos, lStr-pos+1 );
  79.         }
  80.     } else if( str ) tmp = duplica_stringa( str );
  81.  
  82.     return tmp;
  83. }
  84.  
  85.  
  86.  
  87. /*==============================================================================
  88. Converte in stringa il valore indicato da n, quindi lo inserisce nella posizione
  89. pos della stringa s. Se pos eccede la lunghezza della stringa, l'aggiunta viene
  90. effettuata in coda alla stringa stessa. Colloca la stringa risultante in un'area
  91. di memoria dinamica appositamente allocata e restituisce il puntatore alla
  92. memoria allocata (NULL se l'allocazione fallisce).
  93. Spetta al chiamante liberare con libera_buffer() la memoria allocata.
  94. ==============================================================================*/
  95.  
  96. char *inserisci_intero( const char *str, int n, size_t pos ) {
  97.     char buff[32];
  98.     sprintf( buff, "%d", n );
  99.     return inserisci_stringa( str, buff, pos );
  100. }
  101.  
  102.  
  103.  
  104. /*==============================================================================
  105. Sostituisce nella stringa str tutte le occorrenze dei caratteri indicati nella
  106. stringa orig con i caratteri indicati nelle stesse posizioni nella stringa sost.
  107. Ad esempio, sostituisci_caratteri( "Provetta", "Pt", "Bd" ) da' come esito la
  108. stringa "Brovedda". Colloca la stringa risultante in un'area di memoria dinamica
  109. appositamente allocata e restituisce il puntatore alla memoria allocata (NULL se
  110. l'allocazione fallisce). Spetta al chiamante liberare con libera_buffer() la
  111. memoria allocata.
  112. ==============================================================================*/
  113.  
  114. char *sostituisci_caratteri(
  115.     const char *str, const char *orig, const char *sost ) {
  116.     char *tmp = NULL;
  117.  
  118.     if( str && orig && sost ) {
  119.         size_t lStr  = strlen( str );
  120.         size_t lOrig = strlen( orig );
  121.         size_t lSost = strlen( sost );
  122.  
  123.         if( lStr && lOrig && lSost && lOrig==lSost ) {
  124.             size_t i, j;
  125.  
  126.             tmp = duplica_stringa( str );
  127.  
  128.             if( tmp ) { // allocazione riuscita, sostituiamo
  129.                 for( i=0; i<lStr; ++i )
  130.                     for( j=0; j<lOrig; ++j )
  131.                         if( tmp[i] == orig[j] )
  132.                             tmp[i] = sost[j];
  133.             }
  134.         }
  135.     } else if( str ) tmp = duplica_stringa( str );
  136.  
  137.     return tmp;
  138. }
  139.  
  140.  
  141.  
  142. /*==============================================================================
  143. Sostituisce un frammento di l caratteri della stringa s con la stringa sost, a
  144. partire dalla posizione pos (sost puo' anche essere piu' lungo o piu' corto di l
  145. caratteri). Colloca la stringa risultante in un'area di memoria dinamica
  146. appositamente allocata e restituisce il puntatore alla memoria allocata (NULL se
  147. l'allocazione fallisce).
  148. Spetta al chiamante liberare con libera_buffer() la memoria allocata.
  149. ==============================================================================*/
  150.  
  151. char *sostituisci_frammento(
  152.     const char *str, const char *sost, size_t pos, size_t l ) {
  153.     char *tmp = NULL;
  154.  
  155.     if( str && sost ) {
  156.         size_t lStr = strlen( str );
  157.         size_t lSost = strlen( sost );
  158.  
  159.         if( pos > lStr ) pos = lStr;
  160.         if( pos+l > lStr ) l = lStr-pos;
  161.  
  162.         tmp = malloc( (lStr-l)+lSost+1 );
  163.  
  164.         if( tmp ) { // allocazione riuscita, sostituiamo
  165.             memcpy( tmp, str, pos );
  166.             memcpy( tmp+pos, sost, lSost );
  167.             memcpy( tmp+pos+lSost, str+pos+l, lStr-pos-l+1 );
  168.         }
  169.     } else if( str ) tmp = duplica_stringa( str );
  170.  
  171.     return tmp;
  172. }
  173.  
  174.  
  175.  
  176. /*==============================================================================
  177. Cerca nella stringa str le ricorrenze della stringa ptrn e le sostituisce con la
  178. stringa sost. Colloca la stringa risultante in un'area di memoria dinamica
  179. appositamente allocata e restituisce il puntatore alla memoria allocata (NULL se
  180. l'allocazione fallisce).
  181. Spetta al chiamante liberare con libera_buffer() la memoria allocata.
  182. ==============================================================================*/
  183.  
  184. char *sostituisci_frammenti(
  185.     const char *str, const char *ptrn, const char *sost ) {
  186.     char *tmp = NULL; // per il buffer dell'esito
  187.  
  188.     if( str && ptrn && sost ) { // verifica la validita' dei parametri
  189.         // quanto e' lungo il pattern da sostituire?
  190.         size_t lPtrn = strlen( ptrn );
  191.  
  192.         if( lPtrn != 0 ) { // il pattern da sostituire non puo' essere vuoto
  193.             // quante volte ptrn ricorre nella stringa?
  194.             size_t qRic; // qRic = quantita' di ricorrenze (del pattern in str)
  195.             const char *pPtrn = strstr( str, ptrn );
  196.             for( qRic=0; pPtrn; ++qRic )
  197.                 pPtrn = strstr( ++pPtrn, ptrn );
  198.  
  199.             if( qRic>0 ) { // il pattern deve essere presente almeno una volta
  200.                 // rileva la lunghezza delle parti "in gioco"
  201.                 size_t lStr  = strlen( str ); // la lunghezza di str
  202.                 size_t lSost = strlen( sost ); // lunghezza delle sostituzioni
  203.  
  204.                 // alloca il buffer per la stringa risultante dalle sostituzioni
  205.                 tmp = malloc( lStr - lPtrn*qRic + lSost*qRic + 1 );
  206.  
  207.                 if( tmp ) { // allocazione riuscita, sostituiamo
  208.                     const char *pOrig; // il punto di str dal quale copiare
  209.                     char *pDest; // punta al punto di tmp nel quale copiare
  210.                     size_t i;
  211.  
  212.                     for( pOrig=str, pDest=tmp, i=0; i<=qRic; ++i ) {
  213.                         if( (pPtrn=strstr(pOrig,ptrn)) ) {
  214.                             memcpy( pDest, pOrig, pPtrn-pOrig );
  215.                             pDest += pPtrn-pOrig;
  216.                             pOrig += pPtrn-pOrig + lPtrn;
  217.                             memcpy( pDest, sost, lSost );
  218.                             pDest += lSost;
  219.                         } else memcpy( pDest, pOrig, lStr-(pOrig-str)+1 );
  220.                     }
  221.                 }
  222.             } else tmp = duplica_stringa( str );
  223.         } else tmp = duplica_stringa( str );
  224.     } else if( str ) tmp = duplica_stringa( str );
  225.  
  226.     return tmp;
  227. }
  228.  
  229.  
  230.  
  231. /*==============================================================================
  232. Cerca nella stringa str le ricorrenze della stringa ptrn e le sostituisce,
  233. nell'ordine, con le stringhe contenute nell'array di stringhe puntato da sost.
  234. L'array deve contenere la quantita' di stringhe specificata dal parametro qSost.
  235. Se ci sono discrepanze tra la quantita' delle ricorrenze di ptrn in str e il
  236. valore di qSost, prevale la quantita' minore.
  237. Colloca la stringa risultante in un'area di memoria dinamica appositamente
  238. allocata e restituisce il puntatore alla memoria allocata (NULL se l'allocazione
  239. fallisce).
  240. Spetta al chiamante liberare con libera_buffer() la memoria allocata.
  241. ==============================================================================*/
  242.  
  243. char *sostituisci_segnaposto(
  244.     const char *str, const char *ptrn, const char **sost, size_t qSost ) {
  245.     size_t *lSost = NULL;
  246.     char *tmp = NULL;
  247.     size_t i;
  248.  
  249.     // verifica la validita' dei parametri
  250.     if( sost ) {
  251.         for( i=0; i<qSost; ++i )
  252.             if( !sost[i] )
  253.                 return duplica_stringa( str );
  254.     } else return duplica_stringa( str );
  255.  
  256.     if( str && ptrn ) { // verifica la validita' dei parametri
  257.         // quant'e' lungo il pattern da sostituire?
  258.         size_t lPtrn = strlen( ptrn );
  259.  
  260.         if( lPtrn != 0 ) { // il pattern da sostituire non puo' essere vuoto
  261.             // quante volte ptrn ricorre nella stringa?
  262.             size_t qRic; // qRic = quantita' di ricorrenze (del pattern in str)
  263.             const char *pPtrn = strstr( str, ptrn ); // la posizione del pattern
  264.             for( qRic=0; pPtrn; ++qRic )
  265.                 pPtrn = strstr( ++pPtrn, ptrn );
  266.             if( qRic > qSost ) qRic = qSost; else qSost = qRic;
  267.  
  268.             // alloca un buffer per la lunghezza delle stringhe sostitutive
  269.             if( (lSost=calloc(qSost,sizeof(*lSost))) == NULL ) return tmp;
  270.  
  271.             if( qRic>0 ) { // il pattern deve essere presente almeno una volta
  272.                 size_t lStr  = strlen( str ); // la lunghezza di str
  273.                 size_t totLSost = 0; // la lunghezza totale delle sostituzioni
  274.  
  275.                 // rileva la lunghezza d'ognuna delle parti sostitutive
  276.                 for( i=0; i<qSost; ++i ) {
  277.                     lSost[i] = strlen( sost[i] );
  278.                     totLSost += lSost[i]; // aggiunge alla somma totale
  279.                 }
  280.  
  281.                 // alloca il buffer per la stringa risultante dalle sostituzioni
  282.                 tmp = malloc( lStr - lPtrn*qRic + totLSost + 1 );
  283.  
  284.                 if( tmp ) { // allocazione riuscita, sostituiamo
  285.                     const char *pOrig; // il punto di str dal quale copiare
  286.                     char *pDest; // punta al punto di tmp nel quale copiare
  287.  
  288.                     for( pOrig=str, pDest=tmp, i=0; i<=qRic; ++i ) {
  289.                         if( (pPtrn=strstr(pOrig,ptrn)) ) {
  290.                             memcpy( pDest, pOrig, pPtrn-pOrig );
  291.                             pDest += pPtrn-pOrig;
  292.                             pOrig += pPtrn-pOrig + lPtrn;
  293.                             memcpy( pDest, sost[i], lSost[i] );
  294.                             pDest += lSost[i];
  295.                         } else memcpy( pDest, pOrig, lStr-(pOrig-str)+1 );
  296.                     }
  297.                 }
  298.             } else tmp = duplica_stringa( str );
  299.         } else tmp = duplica_stringa( str );
  300.     } else if( str ) tmp = duplica_stringa( str );
  301.  
  302.     free( lSost );
  303.     return tmp;
  304. }
  305.  
  306.  
  307.  
  308. /*==============================================================================
  309. Riceve il puntatore ad un puntatore ad una stringa C collocata in un'area di
  310. memoria allocata dinamicamente, libera con free() quella memoria e annulla il
  311. puntatore.
  312. ==============================================================================*/
  313.  
  314. void libera_buffer( char **buffer ) {
  315.     if( buffer ) if( *buffer ) { free( *buffer ); *buffer = NULL; }
  316. }





Lo scopo di tanto lavorio è sempre lo stesso: passare il tempo a far qualcosa di più attivo rispetto a guardare la TV.


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
lumo (Member)
Expert


Messaggi: 449
Iscritto: 18/04/2010

Segnala al moderatore
Postato alle 23:57
Venerdì, 19/05/2017
Ciao Aldo, un po' di commenti

1) duplica_stringa() -> esiste quasi dappertutto strdup che fa esattamente questa cosa, inoltre dovresti a rigor di logica controllare che memcpy copi veramente tutto (visto che segui uno stile molto difensivo :rotfl: )

2) libera_buffer() -> questa secondo me è assolutamente da evitare, se leggi lo standard dovrebbe esserci scritto che free(NULL); può funzionare (quindi quegli if non servono). Il dover settare a NULL il puntatore rimasto non lo vedo come un motivo sufficiente a scrivere una funzione apposita, è una cosa che ci si aspetta in un programma C. Inoltri aggiungendo la doppia indirezione secondo me si fanno più errori e più confusione.

3) inserisci_stringa() -> la funzione è utile ma se fossi chi usa la libreria preferirei un errore se specificassi un indice sbagliato

4) inserisci_intero() -> proprio per il fatto che l'implementazione è solo un mashup di inserisci_stringa non sentirei il bisogno di questa funzione (che solleva la questione del: perché non inserisci_float? double? e così via)

5) sostituisci_* -> queste meritano una discussione un po' approfondita quindi rimando di qualche giorno, ti do un anticipo:
   * una volta implementata sostituisci_frammenti(), tutte le altre potrebbero essere riscritte usando questa.
   * le performance di sostituisci_caratteri() si possono migliorare notevolmente usando una lookup table (nel caso ci siano pochi caratteri, come dovrebbe essere in genere), oppure con un sort stabile
   * il codice è molto contorto, quindi è più facile che ci siano errori (mortali nel caso si maneggi memoria) ed è poco efficiente perché scorre carattere per carattere. Usando funzioni come strchr, strstr, strpbrk e simili per la ricerca dovrebbe le performance dovrebbero migliorare. Migliorerebbero ancora di più con algoritmi di ricerca tipo Knuth-Morris-Pratt, Boyer-Moore e così via. Per farla breve, non mi fiderei ad usare quelle funzioni per motivi di sicurezza e performance. Un modo veloce per migliorare dovrebbe essere quello di utilizzare inserisci_stringa (che te lo sei scritto a fare se poi fai tutto a mano? :P)

Ultima modifica effettuata da lumo il 19/05/2017 alle 23:59
PM Quote
Avatar
Mikelius (Member)
Expert


Messaggi: 525
Iscritto: 14/04/2017

Segnala al moderatore
Postato alle 1:24
Sabato, 20/05/2017
Ciao, anche io volevo fare qualcosa di simile ... ma per ora il tempo lo sto impiegando altrove.

Comunque, prima di tutto una curiosita':
Codice sorgente - presumibilmente C/C++

  1. // Perchè hai usato 2 if invece che 1 if() con dentro un &&?
  2.  
  3. void libera_buffer( char **buffer ) {  
  4.     if( buffer )
  5.         if( *buffer ) {
  6.             free( *buffer );
  7.             *buffer = NULL;
  8.        }
  9. }



Secondo, se potrebbero interessarti le funzioni che volevo inserire (non so se esistono nelle librerie standard):

- string_Maiusc(char *str) // Rende tutti i Caratteri MAIUSCOLI
- string_minusc(char *str) // Rende tutti i Caratteri minuscoli
- string_Title(char *str) // Applica la maiuscola alle prime lettere di ogni parola, il resto minuscole
- delDoubleSpace(char *str) // Cancella i doppi spazi in delle stringhe
- countWord(char *str) // Conta le parole all'interno della stringa
- hideString(char *str) // Genera una stringa con '*' al posto delle lettere: [Ciao mondo -> **** ***** ]

ed forse altre che ora non ricordo











PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 22:20
Sabato, 20/05/2017
Mikelius, ho usato i due if annidati anziché l'unico if con la condizione && perché se un puntatore è NULL il contenuto della memoria puntata non è significativo (e potrebbe creare situazioni imprevedibili). Dunque, PRIMA verifico che il puntatore non sia NULL, solo DOPO essermi assicurato che sia un puntatore valido ne controllo il contenuto. Poi che sia un ragionamento pertinente oppure no non saprei dire -- a me sembra che abbia senso.


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
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 22:35
Sabato, 20/05/2017
Lumo, alcuni dei tuoi commenti mi ispirano delle perplessità e dei dubbi.

1) a. strdup() è standard? non l'ho trovato nella documentazione sul C che son solito usare.
    b. Può davvero capitare che memcpy() "salti" qualcosa? Per me è una novità.
    c. Lo stile difensivo fa sì che i miei programmi non crashino mai!!!
        (evviva l'umiltà :D) è ben vero che son tutti programmi semplici.

2) Mi piace risparmiare una riga di codice perché ho uno schermo con risoluzione limitata e amo avere più codice possibile sott'occhio. Per questo ho predisposto libera_buff(): una riga e via. In altre circostanze uso free() e subito dopo annullo il puntatore sulla stessa riga, per lo stesso scopo. Se ho capito bene la documentazione, free(NULL) semplicemente dovrebbe ritornare senza fare nulla. Forse intendevi suggerire che si può semplicemente liberare comunque la memoria e impostare comunque a zero il puntatore (tanto se è già NULL non succede nulla)?

3) Ci avevo pensato, poi ho optato per questa soluzione perché passando (ad esempio) 0xFFFFFFFF si può usare inserisci_stringa() come se fosse un concatena_stringa(). Pensi che sarebbe dunque il caso di farne due funzioni separate?

4) In effetti inizialmente avevo implementato anche inserisci_double()...

5) Aspetto l'approfondimento.


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
lumo (Member)
Expert


Messaggi: 449
Iscritto: 18/04/2010

Segnala al moderatore
Postato alle 23:27
Sabato, 20/05/2017
Testo quotato

Postato originariamente da AldoBaldo:

Lumo, alcuni dei tuoi commenti mi ispirano delle perplessità e dei dubbi.

1) a. strdup() è standard? non l'ho trovato nella documentazione sul C che son solito usare.
    b. Può davvero capitare che memcpy() "salti" qualcosa? Per me è una novità.
    c. Lo stile difensivo fa sì che i miei programmi non crashino mai!!!
        (evviva l'umiltà :D) è ben vero che son tutti programmi semplici.


In effetti no, ero io che mi fumavo qualcosa, comunque controllare ma non segnalare nessun errore è forse peggio di crashare terribilmente.
Riguardo strdup invece, non è standard, per due motivi: uno che è facile dal implementare, l'altro che se serve un allocatore specializzato (insomma usare qualcosa di diverso da malloc) allora una implementazione standard diventerebbe inutile

Testo quotato


2) Mi piace risparmiare una riga di codice perché ho uno schermo con risoluzione limitata e amo avere più codice possibile sott'occhio. Per questo ho predisposto libera_buff(): una riga e via. In altre circostanze uso free() e subito dopo annullo il puntatore sulla stessa riga, per lo stesso scopo. Se ho capito bene la documentazione, free(NULL) semplicemente dovrebbe ritornare senza fare nulla. Forse intendevi suggerire che si può semplicemente liberare comunque la memoria e impostare comunque a zero il puntatore (tanto se è già NULL non succede nulla)?



Sì, e che gli if non servono a nulla. Anzi, il secondo non serve a nulla, ma il primo serve perché hai messo il doppio puntatore, ecco perché sono ferocemente contrario alla tua funzione :P (comunque compra uno schermo più grande :rotfl: )

Testo quotato


3) Ci avevo pensato, poi ho optato per questa soluzione perché passando (ad esempio) 0xFFFFFFFF si può usare inserisci_stringa() come se fosse un concatena_stringa(). Pensi che sarebbe dunque il caso di farne due funzioni separate?



Si, immaginati uno che vede un inserimento a 0xFFFFFFFF, penserebbe subito che hai commesso uno sbaglio.

Testo quotato


4) In effetti inizialmente avevo implementato anche inserisci_double()...



Via quella funzione :yup:

Testo quotato


5) Aspetto l'approfondimento.  


Giugno si avvicina pericolosamente quindi non so, magari se ho tempo la via più veloce è riscrivere una delle funzioni che mi piace di meno così vedi la differenza tra il tuo modo e il mio.

Rimane il fatto che il C è un linguaggio terribile per la manipolazione delle stringhe, dover usare strlen() ogni volta per saperne la lunghezza necessita lo scorrimento di tutti i caratteri. Di solito le librerie per le stringhe hanno una struttura che incapsula puntatore e lunghezza, oppure altre varianti (tipo sdstring che ti avevo mostrato). Pascal memorizzava la lunghezza della stringa all'inizio della stringa.

Testo quotato


Dunque, PRIMA verifico che il puntatore non sia NULL, solo DOPO essermi assicurato che sia un puntatore valido ne controllo il contenuto. Poi che sia un ragionamento pertinente oppure no non saprei dire -- a me sembra che abbia senso.


Ha senso (problema comunque introdotto inutilmente dal doppio puntatore) ma puoi usare un if solo, perché gli operatori booleani in C sono sempre short-circuit:
Codice sorgente - presumibilmente C/C++

  1. if (buffer != NULL && *buffer != NULL) {
  2.    ...
  3. }


in questo caso se la prima condizione fallisce, è ovvio che anche avendo altre condizioni vere nel resto dell'and l'if sarà falso. Quando si ha il short-circuiting alla prima condizione falsa l'if fallisce e tutte quelle dopo non vengono eseguite, quindi sei al sicuro da indirizzamenti invalidi.

L'or si comporta allo stesso modo ma è duale (alla prima condizione vera l'if è vero).

OT: ma perché non usi tampone invece di buffer, che schifo sto inglese

Ultima modifica effettuata da lumo il 20/05/2017 alle 23:30
PM Quote
Avatar
Mikelius (Member)
Expert


Messaggi: 525
Iscritto: 14/04/2017

Segnala al moderatore
Postato alle 1:29
Domenica, 21/05/2017
Testo quotato

Postato originariamente da AldoBaldo:

Mikelius, ho usato i due if annidati anziché l'unico if con la condizione && perché se un puntatore è NULL il contenuto della memoria puntata non è significativo (e potrebbe creare situazioni imprevedibili). Dunque, PRIMA verifico che il puntatore non sia NULL, solo DOPO essermi assicurato che sia un puntatore valido ne controllo il contenuto. Poi che sia un ragionamento pertinente oppure no non saprei dire -- a me sembra che abbia senso.



Al di là della utilità o meno dei 2 controlli (forse è meglio farne uno in più, che uno in meno), volevo dire quello che ha scritto lumo, ovvero la storia del short-circuit.
Pensavo la conoscessi ...
(Comunque, ti ringrazio. Mi hai involontariamente suggerito di aggiungerlo al mio articolo sulle espressioni booleane XD)
Invece, le altre funzioni t'ispirano?

PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 15:49
Domenica, 21/05/2017
Short-circuit...
Ovviamente mi sono appena documentato (per questo scrivo qui: oltre che per divertirmi, anche per scoprire cose che non so). In effetti il concetto è semplice e molto razionale, ma non ne sapevo proprio nulla! Ovviamente approfondirò ulteriormente, perché mi sa che può semplificare parecchie situazioni. Una cosa, però, devo chiedere: si tratta di una caratteristica "ufficiale", quindi sempre affidabile, o di una ottimizzazione che dipende dall'implementazione e che quindi può essere a volte disponibile e a volte no?

Le altre funzioni...
Cambiare tra maiuscole e minuscole è una cosa non proprio elementare, perché comporta di rimestare con i charset per tenere debito conto degli accenti e di altri segni diacritici. In genere uso le funzioni di sistema di Win32 CharUpperBuff() e CharLowerBuff(). Sono pressoché certo che ogni sistema operativo comune metta a disposizione qualcosa di simile. Certamente potrei scrivere un paio di funzioni di "smistamento" che chiamino a loro volta la funzione di sistema (per concentrare in un unico punto le chiamate al sistema, in caso di cambiamento di piattaforma) ma non so quanto possa essere utile.
Lo stesso discorso si applica alle funzioni che richiedono l'individuazione delle parole, indispensabile per modificare le iniziali e per contare le parole stesse.
La funzione per "mascherare" i caratteri... mah... davvero potrebbe servire? Magari per giocare all'impiccato?
La funzione per cancellare le doppie mi piace! La implementerò in modo che si possa specificare quale carattere (o serie di caratteri) prendere in considerazione. Ovviamente, se si ritiene, spaziatori inclusi. Grazie del suiggerimento.


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
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 15:55
Domenica, 21/05/2017
Seguendo le osservazioni che mi fate, ecco un paio di versioni "mestruali" della funzione deallocatrice:

Codice sorgente - presumibilmente C++

  1. void libera_tampone( char **tampone ) {
  2.     // sfrutta 'sta storia del corto circuito
  3.     if( tampone && *tampone ) { free(*tampone); *tampone=NULL; }
  4. }
  5.  
  6. void libera_tampone( char **tampone ) {
  7.     // NON sfrutta 'sta storia del corto circuito
  8.     if( tampone ) { free(*tampone); *tampone=NULL; }
  9. }



Morte all'invasività dellinglese! :rotfl:

Ultima modifica effettuata da AldoBaldo il 21/05/2017 alle 15:57


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
Pagine: [ 1 2 3 4 ] Precedente | Prossimo