Newsgroup: it.comp.lang.c
Titolo: Dubbi sull'uso delle stringhe

Da poco tempo ho voluto ricominciare a programmare ed ho pensato di
studiare il C.
Ho riscontrato qualche problema nell'assegnazione delle stringhe.
Quando il compilatore incontra una istruzione del tipo:
char s[] = "ciao";
dovrebbe in automatico riservare lo spazio in memoria per contenere un
numero di caratteri pari alla lunghezza della stringa + 1 per
memorizzare il terminatore della stringa ed assegnare a s l'indirizzo
del primo carattere.
Pero' anche l'istruzione:
char *s = "ciao";
dovrebbe fare la stessa cosa.
Solo che ho riscontrato una differenza in un programmino banale usando
la funzione strcpy.
Eccolo:
----------------------------------------------------------------------
#include <stdio.h>
#include <string.h>
int main()
{
   char s1[] = "12345678901234567890";
   char s2[] = "ciao";
 
   puts("Prima della copia");
   printf("Le variabili s1 ed s2 contengono\n\t%s\n\t%s\n", s1, s2);
   strcpy(s1,s2);
   puts("Dopo la copia");
   printf("Le variabili s1 ed s2 contengono\n\t%s\n\t%s\n", s1, s2);
}
----------------------------------------------------------------------
In pratica il programma non fa altro che assegnare alle stringhe s1 e s2
due stringhe alfanumeriche.
Dopo pero' ho voluto sfruttare strcpy per copiare in s1 il contenuto di
s2. Nessun problema l'operazione funziona e le varie operazioni di
stampa confermano la correttezza delle operazioni.
Se al posto delle istruzioni:
   char s1[] = "12345678901234567890";
   char s2[] = "ciao";
utilizzo le istruzioni:
   char *s1 = "12345678901234567890";
   char *s2 = "ciao";
Il programma stampa correttamente il contenuto di s1 e s2 prima dell'uso
di strcpy e poi si interrompe col messaggio "bus error".
Non riesco bene a capire a cosa possa essere dovuto il problema.
s1 punta a uno spazio di memoria che dovrebbe essere sufficientemente
ampio per contenere la stringa 2.
E' come se:
char s[] = "ciao";
e
char *s = "ciao";
fossero due istruzioni non equivalenti.
Qualcuno ha la pazienza di mostrarmi che cosa non ho capito?
Vi ringrazio per l'attenzione.
P.S.
Il programma e' stato compilato con GNU GCC 3.3 su computer Apple
Macintosh con sistema operativo Mac OS X 10.3.6.
Non ho usato alcuna opzione del compilatore se non quella sul nome:
gcc programma.c -o programma
-- 
Ciao da Francesco B.

 di strcpy e poi si interrompe col messaggio "bus error".
Il problema e' questo. (semplificando)
Quando il compilatore trova
char s1[]="gggg";
alloca un array nella memoria di lavoro e ci copia
la stringa "gggg".
Su questo array sara' possibile fare tutte le
operazioni volute.
Se invece scrivi
char *s = "ssssgg";
allora succede questo:
La stringa "ssssgg" e' una stringa costante (esplicita
nel programma) quindi va a finire nella stessa zona
di memoria dove e' contenuto il programma.
La variabile s puntera' a questa stringa.
Fino a che usi s leggendola o stampandola non ci sono
problemi.
Se pero' cerchi di modificarla e' come se tu stessi
cercando di modificare il programma.
Questa spesso e' una cosa che i sistemi operativi
proibiscono perche' e' una cosa potenzialemente
molto pericolosa. Quindi ti viene dato un errore
come se tu stessi accedendo ad una zona di memoria proibita.
(altri ti potranno dare dettagli piu' precisi,
ma il succo e' questo).
Sinceramente non so se accade cosi' con tutti i compilatori.
Per esempio con linux e gcc su una macchina di tipo PC
capita la stessa cosa.
ciao,
e.

Caro Estintore wrote:

Io uso linux e con GCC mi succede la stessa cosa!

 La variabile s puntera' a questa stringa.
Mi sembra piuttosto chiaro.
Grazie.


On Wed, 08 Dec 2004 21:17:56 GMT, 
bfmN...@despammed.com
 (Francesco
B.) wrote:
[CUT]
Perchè "blabla" da sola è una costante stringa (consideata come un
array di char i cui valor non possono essere modificati), ora che
succede:
Quando fai char s[] = "Ciao";  <--- tu allochi spazio per tutta
l'intera frase + il carattere di fine stringa,
Quando fai char *s = "Ciao"; <--- non allochi spazio per l'intera
frase ed s è solo un puntatore alla prima cella dell'array "Ciao" (che
non puo'  essere modificatooo da qui l'errore in strcpy). Non
essendoci spazio allocato vai out.
Da notare che solo il primo parametro deve avere memoria allocata per
contenere tutto ciò che vi è nel secondo parametro.
quindi
char p1[] = "Semplicissimo";
char *p2 = "Esempio";
in questo caso strcpy(p1, p2); non fallirà

 essendoci spazio allocato vai out.
Si ho capito. Pero' effettivamente mi era venuto il dubbio perche' sul
libro dove stavo studiando effettivamente veniva detto che non c'erano
differenze.
Ovviamente poi mi sono scontrato con la realta' del compilatore GCC.
Poi ho voluto cercare qualche altro compilatore ed ho provato quello
della DigitalMars e questo invece va ad allocare memoria anche con la
notazione a puntatori.
A questo punto penso che i vari compilatori interpretino a proprio
piacimento questa operazione.
Data quella che per me la cosa piu' importante e'la portabilita' del
codice, ritengo che operero' la scelta piu' conservativa di considerare
sempre e comunque distinte le due notazioni.
Grazie per le tue osservazioni.


 differenze.
Non vorrei dire cavolate, ma per quanto ne so questo e' _falso_, secondo 
standard. Che poi in pratica la differenza sia sottile (in un caso puoi 
modificare, nell'altro no... diciamo pure "sottile" :P), e' un altro 
discorso.
Quindi: non e' questione di compilatore o ambiente. E' questione di 
standard.
-- 
Mat/tia Belletti - Undergraduate student @ 
cs.unibo.it
ICQ: 33292311    - email: 
mbel...@cs.unibo.it
IRC: RedGlow     - site(s): 
http://mbellett.web.cs.unibo.it/
Jabber: RedGlow  - Linux registered user 299762 @ machine 213003

 sempre e comunque distinte le due notazioni.
Le due "notazioni" non sono distinte solo per la possibilità di scrivere
nell'array. Il puntatore ricavato da un letterale stringa può essere
restituito da una funzione e utilizzato ovunque e in qualsiasi momento,
giacché i letterali stringa hanno lifetime statico. L'array instanziato
localmente, invece, ha lifetime limitato al suo scope.
In generale, per evitare errori, è buona norma assegnare gli indirizzi di
letterali stringa *soltanto* a puntatori di tipo 'const char*' (non
semplici 'char*').
Max

 semplici 'char*').
Interessante. 
Ti ringrazio per le tue indicazioni.
