Newsgroup: it.comp.lang.c
Titolo: Letterali stringa

Mi servirebbe qualche argomentazione sulle due modalita' di inizializzare i
due puntatori qui sotto:
#include <stdio.h>
int main(void)
{
  char* pChar;
  char* pChar1="ABC";     // primo
  pChar = "ABC";  // secondo
  return 0;
}
Perche' 'primo' e' consigliato (almeno dalla letteratura piu' diffusa) e il
'secondo' e' a malapena citato?
BC31 e MsVC 6.0 danno lo stesso coodice asm per le due inizializzazioni.
GRAZIE

>   pChar = "ABC";  // secondo
Secondo me non dovrebbe neanche funzionare
--
Alessandro Monti

  return 0;
Secondo fa casini. Tu hai dichiarto il puntatore pchar
ma come noti punta in un'area di memoria "a casaccio".
E' necessario che utilizzi una delle funzione di allocazione
dinamica di memoria ( malloc() calloc() ...)  per assegnare
un valore al puntatore pchar e contemporaneamete un'area di
memoria in cui mettere "abc"
CiaoCiao
LordFelix
------------ disLESSici cr3w member -------------
char I[24]="_beWYX_\\k3W\\f_Xff\\V\\!beZ";main(){
int i=(((3*23))-69);for(;i<24;i++)I[i]=(i<27)?(I[
i]+13):(I[i]&(((53%20-i+27))));printf("%s\n",I);}


Certo che funziona. Assegna a pChar l'indirizzo della stringa "ABC", di
solito dal segmento delle costanti.
Saluti, Alberto.


Non e' necessario usare malloc(), pChar="ABC" e' perfettamente lecito e
assegna a pChar l'indirizzo della costante "ABC". L'unica differenza fra la
prima e seconda forma e' che il puntatore non e' inizializzato e potrebbero
esserci problemi se viene usato prima dell'assegnamento.
Saluti, Alberto.

 GRAZIE
Secondo me sono equivalenti. L' unico dubbio che ho e' se poi i valori
puntati possono essere legalmente modificati o se "ABC" e' da
considerarsi
const char * come classe di memorizzazione. Se si' e' probabile che la
seconda sia sbagliata, in quanto il compilatore non potrebbe garantire
un
successivo uso improprio della mem, ma ti ripeto, non sono certo e al
momento
non posso documentarmi.
Del resto e' sempre possibile scegliere sintassi sicuramente lecite per
cui
il problema non mi si e' mai posto.
ciao.

esserci problemi se viene usato prima dell'assegnamento.
ops... si, hai ragione, "ABC" individua anche l'area di memoria in cui
il compilatore decide di allocare la costante, erroneamente mi
riferivo all'altro problema... faccio ammenda :)


 momento non posso documentarmi.
I due metodi sono equivalenti e producono lo stesso codice. L'unica
differeza e' "quando" viene assegnato il puntatore. Ovviamente nel secondo
caso potrebbe esserci del codice fra la dichiarazione e l'assegnamento che
potrebbe refenziare pChar, non ancora inizializzato (e per questo e'
preferibile la prima).
Eventuali problemi legati alla natura const della stringa sono comuni a
entrambi i metodi. Anche nel primo caso, il compilatore non vieta eventuali
tentativi di modifiche della stringa originaria, a prescindere che run-time
questi vadano a buon fine o meno.
Saluti, Alberto.

 Secondo me non dovrebbe neanche funzionare
E perché? Sta semplicemente assegnando alla varibile puntatore pChar
l'indirizzo della stringa "ABC" .....
Ciao, Giuseppe
---------------------------------------------------------------------------
_Guybrush su IRCNet canale #programmazione
ICQ: 42227764
---------------------------------------------------------------------------

 memoria in cui mettere "abc"
Secondo me quello che dici è sbagliato. Lei non sta facendo uno strcpy della
stringa "ABC" nell'area di memoria puntata da pChar, sta semplicemnte
assegnando a pChar l'indirizzo della stringa "ABC".


 l'indirizzo della stringa "ABC" .....
A me sembra che stia invece assegnando al puntatore l'indirizzo "ABCD", che
tradotto in un numero a 32 bit dà una locazione sconosciuta.
Per carità, il tutto è perfettamente lecito, ma non ne capisco il senso.
Altra cosa se avesse scritto:
    pChar = &"ABCD";
o no?
--
Alessandro Monti

Grazie a tutti.
Susanna

 o no?
No &"ABCD" e' un puntatore a const char[5]. Vedi messagio di Andread Foco
nel thread "Parametri e puntatori"
"ABCD" e' a tutti gli effetti un const char [5] e quindi, come per tutti gli
array in C, un puntatore alla memoria (allocata automaticamente dal
compilatore) che contiene i dati.
Volendi, potresti anche scrivere:
printf("%c", "0123456789ABCDEF"[n]); ottendendo per "magia" la conversione
da intero (0..16) a esadecimale.
Saluti, Alberto.

 Saluti, Alberto.
Faaaaantastico!!!
Sto newsgroup me piace sempre de piu'.
ciao.

o no?
No, decisamente !
Il mio amico DJGPP lo definirebbe un "assignment from incompatible
pointer type" e difatti i tipi restituiti sono del tutto differenti.
"ABCD" restituisce un "pointer to char" 
mentre
&"ABCD" restituisce un "pointer to array of 5 char"
Anche se è probabile che il programma funzioni lo stesso.
--
Andrea Laforgia        (
andrea_...@bigfoot.com
)

No &"ABCD" e' un puntatore a const char[5].
Diciamo comunque che, in generale, non è detto che i caratteri siano
costanti.
--
Andrea Laforgia        (
andrea_...@bigfoot.com
)

 o no?
Tralasciando il fatto che l'espressione &"ABCD" non può essere calcolata
(stai cercando di calcolare l'indirizzo di un elemento che non è una
variabile), assegneresti un char** a un char*.


 nel thread "Parametri e puntatori"
Ok, non lo sapevo, mea culpa.
E se scrivessi:
    char* pchar;
    pchar = (char *) "ABCD";
cosa otterrei? E' questo il modo per convertire un numero a 32 bit espresso
come concatenazione di 4 byte? (ovviamente \0 finale escluso e supponendo
che il tipo puntatore sia mappato con numeri a 32 bit, ecc.)
Ovvero volendo che la locazione puntata da pchar si trovi all'indirizzo 'A'
+ ('B'<<8) + ('C'<<16) + ('D'<<24).
Non che questo sia di qualche utilità pratica, solo per curiosità
--
Alessandro Monti

> Una curiosità: hai lavorato (o lavori) in assembler, vero?
Si, sia per diletto, sia per interfacciarmi a periferiche, ma il tutto
risale ai tempi del DOS, salvo qualche lezioncina a studenti.
Intendo l'assembler 80x86, tanto per precisare, e anche qualcosina
sull'assembler Z8000 :-)
--
Alessandro Monti

+ ('B'<<8) + ('C'<<16) + ('D'<<24).
Credo che tu stia confondendo le cose.
"ABCD" è una semplice concatenazione di caratteri, che non porta con
sè alcuna informazione riferita alla memoria se non il proprio
indirizzo.
--
Andrea Laforgia        (
andrea_...@bigfoot.com
)

variabile)
Ma chi l'ha detto che l'indirizzo di "ABCD" non è calcolabile ???
Credo che questo argomento non sia chiaro a molte persone.
A parte il fatto che, perchè sia calcolabile il suo indirizzo, un
oggetto non deve essere necessariamente una variabile (si può
calcolare l'indirizzo anche di una funzione),
"ABCD" è un OGGETTO presente in memoria e, in quanto tale, è possibile
calcolarne l'indirizzo.
E per dimostrare che le cose stanno così, cioè che l'indirizzo di un
literal si può calcolare e che, inoltre, il tipo restituito è diverso
a seconda dei casi, si consideri il seguente programma perfettamente
lecito in C standard : 
#include <stdio.h>
main()
{
    printf("%p\n", "giuseppe" ) ;
    printf("%p\n", "giuseppe"+1 ) ;
    printf("%p\n", &"giuseppe" ) ;
    printf("%p\n", &"giuseppe"+1) ; /* questo risultato è ben 
                                       diverso da "giuseppe"+1 */
}
--
Andrea Laforgia        (
andrea_...@bigfoot.com
)

 sull'assembler Z8000 :-)
Z8000? non era lo Z80? Comunque te lo chiedevo perchč il tuo punto di vista
(fortemente errato in C/C++) proviene dritto dritto dall'assembler.
stringa db "Pippo"
mov eax, [stringa]
In questo caso il tuo ragionamento č giusto: al registro eax viene assegnato
il valore 'P'<<24 + 'i'<<16 + 'p' <<8 + 'p'. Ma quando in C scrivi
char *stringa = "Pippo";
in asm scrivi questo
stringa db "Pippo"
mov eax, stringa
Eax contiene quindi il puntatore a stringa, non il valore intero contenuto
in stringa. Spero di essere riuscito a convincerti.


 mov eax, [stringa]
Si, questo intendevo. Grazie
Era lo Z8000, o meglio: un suo emulatore che girava su altra macchina in
universitą.
Lo Z80 era quello dell'omonimo home computer di Sinclair, ed era precedente
(lo Z8000 aveva addirittura i registri a 32 bit!).
--
Alessandro Monti

 literal si puň calcolare
Questo perň non č vero in generale. Ad esempio non si puň calcolare
l'indirizzo di un literal numerico:
printf( "%p\n", &123 );     /* Errore! */
EMG

                                        diverso da "giuseppe"+1 */
Che significato ha (già mi stranizza il fatto che compili) il puntatore che
ritorna &"giuseppe"? Che il compilatore crei una varibile nascosta nello
stack e ritorni l'indirizzo di quella?


stack e ritorni l'indirizzo di quella?
"Il fatto che compili" non ti deve "stranizzare" ;)
Chiarito che "giuseppe" è un oggetto (non un indirizzo) presente in
memoria, esso decade nel puntatore al suo primo elemento quando viene
utilizzato come "giuseppe", ma non decade affatto in una espressione
come &"giuseppe".
Il compilatore non crea alcuna variabile nascosta nello stack (perchè
dovrebbe ?), ma semplicemente restituisce l'indirizzo dell'oggetto
"giuseppe" presente in memoria (inteso come array di 9 caratteri).
Un caso analogo si ha con l'operatore sizeof(), infatti se provi a
scrivere : sizeof "giuseppe" ottieni esattamente 9 (cioè la dimensione
dell'oggetto) e non sizeof ( char * ) come ti aspetteresti.
--
Andrea Laforgia        (
andrea_...@bigfoot.com
)

printf( "%p\n", &123 );     /* Errore! */
Non esistono i "literal" numerici !!! >:)
In ogni caso, la questione č diversa, in quanto 123 non č soggetto ad
alcuna trasformazione di tipo, mentre un literal č un oggetto visibile
sotto piů punti di vista, a seconda del tipo associato (se ptr a char
o vettore di caratteri).
--
Andrea Laforgia        (
andrea_...@bigfoot.com
)

 printf( "%p\n", &123 );     /* Errore! */
Ma si chiama ancora "literal" in questo caso? Io credevo fossero solo le
stringhe.
Comunque mi è rimasto un dubbio:
se
    pchar = "ABCD"
assegna a pchar l'indirizzo della stringa,
    *pchar = "ABCD"
assegna ad una locazione sconosciuta (perchè pchar non era inizializzato) il
valore 'A', giusto?
E a questo punto le seguenti istruzioni sono equivalenti?
    pchar = "ABCD";
    pchar = &"ABCD";
    pchar = (&"ABCD")[0];    // questa mi sembra un po' poco plausibile, ma
forse è compilabile
    pchar = (&"ABCD") + 0;
Non oso fare delle prove perchè ho VC++ 5.0 e pare sia poco attendibile,
almeno per questo NG :-)
--
Alessandro Monti
P.S. per EMG
Per la mail che mi hai mandato, non riesco a rispondere.
E' un problema di server oppure sei tu che mandi indirizzi fasulli persino
per le e-mail?

 o vettore di caratteri).
Va bene, ma la tua affermazione mi sembrava troppo generica.
EMG

 per le e-mail?
Mai mandato indirizzi fasulli.
EMG

 Si, questo intendevo. Grazie
Ma questa era la concezione sbagliata......... Il C/C++ non fa cosě,
utilizza il secondo metodo.
Ciao, Giuseppe
PS. Thanks per le info sullo Z80 e lo Z8000


 dell'oggetto) e non sizeof ( char * ) come ti aspetteresti.
Ecco, forse è questo il cardine del nostro dibattimento: "giuseppe" è un
char[9] o un char *? Penso il primo da quello che dici tu...
Ciao, Giuseppe


 -fwritable-strings
[root@fokhouse /tmp]# grep -B 1 "giuseppe" p.s
.LC0:
        .string "giuseppe"
--
.LC2:
        .string "giuseppe"
--
.LC4:
        .string "giuseppe"
--
.LC6:
        .string "giuseppe"
[root@fokhouse /tmp]#
Tu ti riferisci a "giuseppe", che e' un array anonimo. Ma chi ti dice che
il primo "giuseppe" sia lo stesso "giuseppe" delle righe successive ?
Per ipotesi, un compilatore C non potrebbe crearsi quattro "giuseppe" uno 
diverso dall'altro (e' quello che succede con '-fwritable-strings') ?
Qualcuno sa che cosa dice lo Standard ? E' *garantito* che in casi simili
ci si riferisce sempre allo stesso array oppure no ?
Ciao ciao,
Andrea
-- 
"...Unix, MS-DOS, and Windows NT (also known as the Good, the Bad, and 
 the Ugly)."
(by Matt Welsh)

    pchar = (&"ABCD") + 0;
Queste ultime due non sono valide.
--
Andrea Laforgia        (
andrea_...@bigfoot.com
)

ci si riferisce sempre allo stesso array oppure no ?
Non ho ancora letto cosa affermi lo standard (rispondo velocemente),
ma a mio avviso un compilatore ottimizzato dovrebbe conservare una
sola copia del valore.
--
Andrea Laforgia        (
andrea_...@bigfoot.com
)

char[9] o un char *? Penso il primo da quello che dici tu...
"giuseppe" è un char[9] che può decadere in (char *).
Lo Standard non prevede il tipo dei literal quale "array of const
char", infatti afferma : "String literals are specified to be
unmodifiable.  This specification allows implementations to share
copies of strings with
identical text, to place string literals in read-only memory, and
perform certain optimizations.  However, string literals do not
have the type array of const char, in order to avoid the problems of
pointer type checking, particularly with library functions,
since assigning a pointer to const char to a plain pointer to char is
not valid. Those members of the Committee who insisted
that string literals should be modifiable were content to have this
practice designated a common extension"
--
Andrea Laforgia        (
andrea_...@bigfoot.com
)

Va bene, ma la tua affermazione mi sembrava troppo generica.
Perdonate la mancanza di chiarezza.
Io non ho detto che per tutti gli "oggetti" è così, ma che nel caso di
oggetti quali array e funzioni è così.
D'altronde le costanti numeriche, come già precisato in altri
messaggi, è più probabile che siano ricodificate come operandi di
istruzioni macchina.
--
Andrea Laforgia        (
andrea_...@bigfoot.com
)

Queste ultime due non sono valide.
Chiedo scusa, le due forme SONO valide.
--
Andrea Laforgia        (
andrea_...@bigfoot.com
)

 "giuseppe" è un char[9] che può decadere in (char *).
Finalmente abbiamo risolto questo dilemma (almeno per me). Grazie.
Ciao, Giuseppe
PS. Scusa se non ti ho risposto subito, ma in questi giorni sono oberato
dallo studio.
