Newsgroup: it.comp.lang.c
Titolo: Stringa dinamica e struttura...

Ciao a tutti,
Stavo pensando a una cosa che non so se sia tecnicamente fattibile (anzi 
dubito ma almeno mi levo il dubbio)...in pratica e' possibile avere un 
campo  "char *stringa" in una struttura in cui alloco dinamicamente una 
stringa durante l'utilizzo del programma e poi ne faccio la fwrite su file?
Se si' come fa il programma a capire la dimensione della stringa quando 
esegue una fread?
Ciao e grazie 1000 come sempre!
Aragorn

 esegue una fread?
Non lo capisce, devi decidere tu il formato. Puoi ad esempio stabilire
che la stringa sia terminata dal newline ('\n'), oppure - se il file è
binario - puoi scrivere su file anche il terminatore di stringa ('\0')
oppure ancora puoi scrivere un paio di byte di header per indicare la
lunghezza della stringa.
Luca
-- 
Home: 
http://kronoz.cjb.net
Non sempre quello che viene dopo e` progresso.
Alessandro Manzoni

 dimensione della struttura.
Sai dirmi dove posso trovare degli esempi ?
Grazie 1000
Aragorn

 ha scritto:

Non compilato:
struct foo {
        int a;
        double b;
        size_t len;
        char c[];
};
struct foo *create_foo(size_t len) {
        struct foo *ret;
        ret = malloc(sizeof(*ret) + len);
        if (ret)
                ret->len = len;
 
        return ret;
}
size_t save_foo(FILE *dst, struct foo *p) {
        return fwrite(p, 1, sizeof(*p) + p->len, dst);
}
struct foo *load_foo(FILE *src) {
        struct foo tmp;
        struct foo *ret;
        /* FIXME: controllo errori */
        fread(&mp, 1, sizeof(tmp), src);
        fseek(src, -sizeof(tmp), SEEK_CUR);
 
        ret = create_foo(tmp.len);
        fread(ret, 1, sizeof(*ret) + tmp.len, src);
 
        return ret;
}
Luca
-- 
Home: 
http://kronoz.cjb.net
The trouble with computers is that they do what you tell them, 
not what you want.
D. Cohen

         fseek(src, -sizeof(tmp), SEEK_CUR);
Non portabile in generale.
Forse ti è sfuggito che -sizeof(tmp) è un valore positivo.
sizeof torna un tipo "unsigned", per la precisione size_t.
fseek vuole "long" come secondo argomento.
Unendo questi due fatti bisogna fare così:
            fseek(src, -(long)sizeof(tmp), SEEK_CUR);
Altrimenti ci possono essere problemi.
Esempio la situazione in cui i long possono
rappresentare i valori di size_t.
In questa condizione il valore -sizeof(tmp) diventa
un grande valore positivo e non è quello che volevi.
--
Giorgio Silvestri
DSP/Embedded/Real Time OS   Software Engineer

 };
Un grazie di cuore a te e a Giorgio! Solo una cosa ma e' possibile che 
con char c[] non compili? Non dovrei utilizzare un char c* ?
Ciao e grazie
Aragorn


Per essere ancora più preciso: -sizeof(tmp) PUO' essere positivo.
E' negativo SOLO SE la integer promotion "promuove" size_t ad int.
Comunque come detto per la massima portabilità bisogna mettere il cast.
-(long)sizeof(tmp)


 ha scritto nel messaggio
news:44e1112c$0$30244$4faf...@reader1.news.tin.it...

Forse non hai un compilatore C99.


 Forse non hai un compilatore C99.
Ciao!
Uso il gcc, in effetti mettendo char c[] come ultimo elemento nella 
struttura tutto procede bene, ma questo e' un caso particolare? Nel 
senso se io avessi una struttura con due stringhe di lunghezza variabile 
del tipo
  struct foo {
         int a;
         double b;
         size_t len;
         char c[];
         char d[];
  };
dovrei farla obbligatoriamente del tipo
  struct foo {
         int a;
         double b;
         size_t len;
         char *c;
         char *d;
  }
o ci sono altre soluzioni possibili?
Ciao e grazie
Enrico

 o ci sono altre soluzioni possibili?
Mah, se proprio vuoi complicarti la vita puoi usare un unico array e poi
usare due puntatori per suddividerlo logicamente:
struct foo *p = malloc(sizeof(*p) + len1 + len2);
p->str1 = p->c;
p->str2 = p->c + len1;
ma IMHO (a meno che non esistano restrizioni particolari
sull'allocatore) la soluzione è inutilmente complessa. E in fase di
caricamento da file dovresti comunque sistemare manualmente i due
puntatori.
Luca
-- 
Home: 
http://kronoz.cjb.net


 puntatori.
Ciao!
Ma quindi per eseguire in maniera "elegante" cio' che mi serve
(ovvero una lista composta essenzialmente da strutture del tipo
  struct foo {
         int a;
         double b;
         size_t len;
         char *c;
         char *d;
  }
)
la via piu' corretta e' quella di utilizzare un output non binario su 
file con dei tag per delimitare inizio e fine  stringhe stile:
file_prova
------------------------------
10 0.0
inizio_stringa1_tag
ma che bella giornata di
sole
fine_stringa1_tag
inizio_stringa2_tag
ma che bella giornata di
sole
fine_stringa2_tag
50 0.0
inizio_stringa1_tag
ma che bella giornata di
sole
fine_stringa1_tag
inizio_stringa2_tag
ma che bella giornata di
sole
fine_stringa2_tag
etc etc
etc...
-------------------------
?
Ciao e grazie 1000!
Aragorn

 fine_stringa2_tag
Visto che le stringhe possono contenere il newline puoi anche usare un
file binario e scrivere anche il terminatore '\0' per delimitare le
stringhe; certo poter leggere e modificare il file con un editor di
testo può semplificare testing e debugging. Bisogna vedere qual'è
l'ambito applicativo; potresti voler utilizzare un file XML in modo da
appoggiarti a librerie solide per l'IO (libxml2 su Linux è lo standard
de facto).
Luca
-- 
Home: 
http://kronoz.cjb.net
Windows NT: Designed for the Internet. The Internet: Designed for Unix.

 de facto).
Ciao! Mi sto informando su libxml (veramente notevole ;) ) , pero' mi 
hai lasciato con una curiosita' (l'ultima davvero poi non ti disturbo 
piu' :)) ...cosa intendi con "puoi anche usare un
file binario e scrivere anche il terminatore '\0' per delimitare le 
stringhe" ?
Ciao e grazie
Aragorn

 terminatore '\0' per delimitare le stringhe" ?
Tu devi scrivere (e poi rileggere) delle stringhe di lunghezza
arbitraria. Per delimitare le stringhe hai due opzioni:
- usi un header dove scrivi la lunghezza della stringa; in fase di
  lettura leggi l'header e quindi leggi il numero di byte indicato.
- scrivi un qualche "terminatore" che indichi in maniera non ambigua la
  fine della stringa; in fase di caricamento continui la lettura fino a
  quando trovi il terminatore. La scelta pi? ovvia per un file di testo
  sarebbe quella di usare '\n' come terminatore; nel tuo caso non ?
  possibile perch? il newline viene usato all'interno delle tue
  stringhe.
  A questo punto puoi rimanere con un file di testo ed usare come
  terminatore un carattere o una sequenza che non possano comparire
  nella stringa da delimitare (e.g. "\n\n", "END", dipende dal campo
  applicativo) oppure usare un file binario e mettere un carattere ('\0')
  che sicuramente non pu? essere presente in un stringa. Praticamente, in
  questo ultimo caso, per salvare la stringa /str/ scrivi su file
  strlen(str) + 1 bytes.
Luca
-- 
Home: 
http://kronoz.cjb.net
"La donna ? coinvolta sessualmente in tutti gli affari della vita. A
 volte perfino nell'amore." -- K. Kraus

   strlen(str) + 1 bytes.
In quest'ultimo caso se ho capito bene dovrei leggere un byte alla volta 
con fread finche' non trovo il mio carattere speciale '\0', e' corretto?
Ciao e grazie
Aragorn

 ha scritto:

E` un dettaglio implementativo. Puoi anche leggere blocchi di dati e
fare il parsing in memoria. 
Luca
-- 
Home: 
http://kronoz.cjb.net
La mia opinione puo` essere cambiata, ma non il fatto che ho ragione.