Salve a tutti, oggi cercherò di spiegare come creare una funzione di split per le vostre stringhe in C. Tempo fa cercai su internet qualche fonte esaustiva ma non ho trovato nulla di buono.
Premetto che i requisiti affinchè capiate il tutorial è una buona conoscenza di C e dei puntatori.(Non è mio compito scoraggiare il lettore, ma l’autore fino a dicembre non sapeva nemmeno come si faceva un allocazione dinamica, con un pò di impegno, chiunque può imparare in tempi brevi!).
Finite queste quattro chiacchiere, presenterò nel tutorial 2 files, un file conterrà tutte le funzioni, l’altro invece sarà un programmino di esempio che ne illustrerà l’uso. Cominciamo con il primo file, lo chiameremo split.h, qui ci vanno le nostre funzioni, #define vari, includes…
file split.h
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | #include <string.h> #include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <memory.h> #define KB 1024 // funzioni sulla memoria delle stringhe int getAllocatedElements(char **array) { return _msize(array) / sizeof(char*); } int freeArray(char **array, int prompt) { if(!array) return 0; // altrimenti riazzero tutto gia messo int dim=getAllocatedElements(array); int i=0; int bytesFree=dim*sizeof(char*); if(prompt) printf("\n\n"); for(i; i<dim; i++) { if(prompt) printf("Libero la stringa allocata: %s(%d bytes allocati)\n",array[i],_msize(array[i])); bytesFree+=_msize(array[i]); free(array[i]); } if(prompt) printf("%d Indirizzi da liberare(%d bytes)\n",dim,dim*sizeof(char*)); free(array); return bytesFree; } // Funzioni di stringhe char* Reverse(char* str, char* ptrstr) { int l=strlen(str); int i=0, j=l-1; for(i,j; i<l, j>=0; i++,j--) ptrstr[i]=str[j]; ptrstr[i]='\0'; return &ptrstr[0]; } char* Replace(char src, char newc, char* str) { int l=strlen(str); int i=0; for(i; i<l; i++) if(str[i]==src) str[i]=newc; return &str[0]; } char* ReplaceFirst(char src, char newc, char* str) { int l=strlen(str); int i=0; for(i; i<l; i++) if(str[i]==src){ str[i]=newc; break; } return &str[0]; } int Count(char c, char *str) { int n=0; int i=0; for(i; i< strlen(str); i++) if(str[i]==c) n++; return n; } int CountStrings(char **array) { int dim=getAllocatedElements(array); int i=0; int n=0; for(i ; i<dim; i++) if(strlen(array[i])>0) n++; return n; } void print(char **array, unsigned int max) { int i=0; for(i; i<max; i++) printf("%s\n",array[i]); } void printAll(char **array) { print(array, getAllocatedElements(array) ); } // ----------------------------------------------------------------------------- // SPLIT 2.0 char** Split(char *str, char c, char **array) { if(!array) return NULL; // altrimenti riazzero tutto gia messo int dim=getAllocatedElements(array); int memtoalloc=Count(c,str)-dim; if(memtoalloc) { array=realloc(array, _msize(array) + ( (memtoalloc+1)*sizeof(char*) ) ); if(!array) return NULL; } int z=0; for(z; z<dim; z++) free(array[z]); char buffer[KB]; int i=0,j=0; int n=0; // conto tokens while(i < strlen(str) ) { if(str[i]!=c) { buffer[j]=str[i]; j++; } else { buffer[j]='\0'; array[n]=calloc( strlen(buffer)+1, sizeof(char) ); // alloco un nuovo indirizzo per contenere la stringa stessa if(!array[n]) return NULL; strcpy(array[n],buffer); j=0; n++; // incremento il n di tokens } i++; } if(strlen(buffer)>0) { buffer[j]='\0'; array[n]=calloc( strlen(buffer)+1, sizeof(char) ); // alloco un nuovo indirizzo per contenere la stringa stessa if(!array[n]) return NULL; strcpy(array[n],buffer); j=0; n++; // incremento il n di tokens } return array; } |
E’ ora di utilizzare le funzioni create, passiamo al main:
file main.c
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | #include "strings.h" // Usare split 2.0 int main(void) { int toks=0; // numero di pezzi char **array=calloc(2,sizeof(char*) ); // allocazione di una memoria di base, successivamente verrà adattata if(!array){ printf("Memoria insufficiente"); exit(0); } // un computer degli anni 30 non potra allocare tanta memoria, se non esiste il puntatore termina subito char *str1="Il mio cane e molto cattivo e bambino"; char *str2="uno due#tre quattro#cinque sei#sette otto#nove dieci"; // le stringhe di esempio printf("Prima del primo split, gli indirizzi allocati occupano %d bytes",_msize(array)); printf("\n\nSplit(separatore: spazio) della stringa:\n'%s'\n\n",str1); printf("Puntatore all'array: %p\n",array); array=Split(str1,' ',array); printf("Nuovo puntatore all'array: %p\n\n",array); printf("Numero di stringhe estratte: %d\n\n",CountStrings(array)); printAll(array); printf("\n\nDopo il primo split, gli indirizzi allocati occupano %d bytes",_msize(array)); // Un altro split, riutilizzando la memoria precedente, e rimodellandola dinamicamente printf("\n\nSplit(separatore: #) della stringa:\n'%s'\n\n",str2); printf("Puntatore attuale all'array: %p\n",array); array=Split(str2,'#',array); printf("Puntatore dopo l'ultima modifica: %p\n\n",array); printf("Numero di stringhe estratte: %d\n\n",CountStrings(array)); printAll(array); printf("\n\nDopo il secondo split, gli indirizzi allocati occupano %d bytes",_msize(array)); printf("\n\nMemoria liberata: %d bytes\n\n", freeArray(array,1)); /* necessaria, non usare free(liberera solo gli indirizzi), ricorda di non liberare mai la memoria 2 volte, liberala solo quando non ti serve piu */ system("pause"); // in modalità windows, dove lavoreremo noi, serve ad una pausa return 1; } |
Il tutorial è finito, spero di aver fatto contento qualcuno, segnalatemi errori o suggerimenti, grazie per la lettura al prossimo tutorial!
