giu 01 2009

Split di stringhe in C

Categoria: Programmazione Civan @ 14:23

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!

Tags: , ,

Scrivi un commento