Newsgroup: it.comp.lang.c
Titolo: ANSI C e sottostringhe

Devo fare quella che in situazioni 'normali' sarebbe una banalità, ovvero 
estrarre da una stringa una sottostringa.
Es.
Dato un record a larghezza fissa che contiene
AAA  BBBBBB  12
Ipotizziamo lo voglia dividere secondo lo schema 5,7,4 e metterlo in tre 
variabili separate.
Per fare ciò con linguaggi 'umani' c'è di tutto di più, mid, substr, 
substring ecc. per non parlare delle espressioni regolari.
Mal che vada anche con left e right si riesce a fare qualcosa.
In Ansi C nulla di tutto questo ci sono 'mezze funzioni' un po esoteriche 
tipo la strncpy.
A questo punto uno dice, scendiamo sul banale, creo una stringa vuota 
(chiamamola blocco) faccio un loop e con la strcat concateno ad una 
stringa il carattere corrispondente al contatore, quando arrivo ad N 
salvo una copia di blocco, azzero blocco e riparto a contare.
Eggià teoricamente la stringa è un po come un vettore con il terminatore 
0 hex tuttavia anche questo passaggio per via dei tipi, dei puntatori e 
tutto il resto è davvero un casino.
Ma possibile che non ci sia un sistema 'umano' per fare una minchiata del 
genere?
(con C++ qualcosa c'è, se non trovo risposte vado con quello, ma vorrei 
proprio averle provate tutte).

 tipo la strncpy.
E.

 tutto il resto è davvero un casino.
Puoi incollare un po' di codice dove vedi casino?

Sulla base del post che gentilmente mi avete dato ho risolto ma poi mi 
sono ritrovato questo 'effetto speciale', chi lo capisce?
char        stringa[80];
char        stringa2[80];
char        blocco1[40];
char        blocco2[10];
char        blocco3[10];
char stringa[]="ABCDEEFGHILMNOPQR123456789";
strcpy(blocco1,"");
strcpy(blocco2,"");
strncpy(blocco1,stringa,5);
strncpy(blocco2,stringa+5,5);
strcat(blocco1,".");
strcat(blocco1,blocco2);
printf("ST1 %s\n",stringa);
printf("%s\n",blocco1);
char stringa2[]="ZZZZZZZZZZZZZZZZZZZZZZZZZZ";
strcpy(blocco1,"");
strcpy(blocco2,"");
strncpy(blocco1,stringa2,5);
strncpy(blocco2,stringa2+5,5);
strcat(blocco1,".");
strcat(blocco1,blocco2);
printf("ST2 %s\n",stringa2);
printf("%s\n",blocco1);
esce
ST1 ABCDEEFGHILMNOPQR123456789
ABCDE.EFGHI
ST2 ZZZZZZZZZZZZZZZZZZZZZZZZZZ
ZZZZZ.EFGHI.ZZZZZ
ma io mi aspettavo su ST2!!!
ST2 ZZZZZZZZZZZZZZZZZZZZZZZZZZ
ZZZZZ.ZZZZZ 

Ragionandoci su, di fondo il problema e che non so come azzerare il char 
blocco1
strcpy(blocco1,"");
non svuota riportando \0 a inizio stringa
non lo fa neppure
strcpy(blocco1,"\0");
ne è riprova il fatto che se faccio
strcpy(blocco1,"      ");
la stringa si azzera (ma il fine stringa è dopo gli spazi).
Non mi torna 

Ciao

per azzerare tutto il contenuto puoi usare
memset ( blocco1, 0, sizeof ( blocco1 ) );

 char stringa[]="ABCDEEFGHILMNOPQR123456789";
Il compilatore te lo fa passare?

 la stringa si azzera
Ma che intendi con la stringa si azzera?
La prova seria è stampare i valori dei chari di blocco1 oppure lanciare 
il debugger e vedere la memoria.
A me sembra che funzioni bene, il problema è che usi strncpy(,,5) che da 
manuale non termina la stringa.
Cioè con
strcpy(blocco1,"");
hai blocco1[0]==0 ma quando chiami
strncpy(blocco1,stringa2,5);
sovrascrivi quel primo terminatore e non ti preoccupi di terminare il 
nuovo blocco che eredita il contenuto, intonso, della manipolazione 
precedente.
Secondo me la prima parte del programma ti restituisce l'output che 
volevi solo perché la memoria degli array è tutta inizializzata a 0 ma 
non bisogna farci affidamento.

 manuale non termina la stringa.
concordo, diciamo che mi aspettavo che spostando il terminatore una volta 
tolto, la parte extra fosse vuota.
In fondo se metto in una stringa un testo, poi la sostituisco non mi 
pongo il problema che il secondo sia più lungo per ricoprire il 
precedente.
Si vede che come dici tu strcpy fa fuori il terminatore e non azzera 
nulla.
Comunque ho capito, grazie

 strncpy(blocco1,stringa2,5);
Visto che strncpy non mette il terminatore (io me l'ero scordato!) la 
cosa da fare è:
strncpy(blocco1,stringa2,5);
blocco1[5]=0;
E.

 precedente.
Il concetto è: una stringa si estende un byte alla volta dall'inizio, 
che specifichi, fino alla prima locazione il cui valore è 0, per gli 
amici '\0'.

 cosa da fare č:
Lo mette se c'e' spazio. Se no non va in undefined behaviour e non lo
mette.
     The strncpy() function copies at most n characters from s2 into s1.
If s2 is less than n char-
     acters long, the remainder of s1 is filled with `\0' characters.
Otherwise, s1 is not termi-
     nated.
-- 
-riko

 genere?
Puoi scriverti una funzione substr come questa (NON TESTATA E MIGLIORABILE):
char *substr(char *str,int from, int to)
{
   int len;
   int newlen;
   char *newstr;
   if (str == NULL) return NULL;
   len =  strlen(str);
   if (len == 0) return NULL;
   if (to > len) to = len -1;
   if (from < 0) from = 0;
   if (from >= len) return NULL;
   if (from > to) return NULL;
   newlen = to-from+1;
   newstr = malloc(newlen+1);
   if (newstr) {
     strncpy(newstr,str+from,newlen);
     newstr[newlen] = '\0';
   }
   return newstr;
}
x = substr("ABCDE",2,3);
ti alloca una nuova stringa e ci mette dentro "CD". Come per la strdup() 
(se ce l'hai nella tua libreria) dovrai fare il free() della nuova 
stringa quando non ti serve piu'.
Nell'esempio ho immaginato di restituire NULL se la sottostringa non 
esiste ma puoi fare in modo che restitusca una stringa vuota se ti serve.
Se sei abituato a linguaggi con garbage collection capisco che sia 
noioso dover fare tutto a "mano".
Remo.D