Newsgroup: it.comp.lang.c
Titolo: Strani puntatori

Salve a tutti! 
Mi sono ritrovato sottomano questo esempio di codice (poco ortodosso
rispetto a quello che mi hanno insegnato. Ecco perche' ho dei dubbi):
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
	char *prova;
	int *i;
	prova="Ciao\0";
 
	i=45;
	printf("%d %s\n", i, prova);
	return(0);
}	
Non capisco come possa funzionare (a parte un warning: assignment makes
pointer from integer without a cast)... 
I miei dubbi sono:
i e' un puntatore. Per assegnarci un valore dovrei allocare spazio e
usare *i=45 (come ho sempre fatto). Oppure e' solo un caso che il codice
non vada in segfault (quindi in questo caso 45 e' un indirizzo)?
All'uni mi hanno detto che per inizializzare una stringa si deve usare
strcat() o strncat()... In questo caso invece l'inizializzazione della
stringa avviene come un normale assegnamento.
Vi ringrazio in anticipo per l'aiuto!
-- 
       Tremal-Naik -- Ghouls Emperor -- GnuPGid: 0xF093D6AD
E.A. Poe Klingon Translation Project: 
http://web.tiscali.it/tremal
List of my abandonware games: 
http://web.tiscali.it/tremal/abandon
    My miniatures page: 
http://web.tiscali.it/tremal/miniature

stringa avviene come un normale assegnamento.
Sì infatti, ma in questo caso va bene perché tu fai puntare prova ad
una stringa che viene allocata automaticamente dal compilatore.
Attento che non puoi modificare quella stringa.
-- 
Marco Barisione (ICQ 84277092)

 Attento che non puoi modificare quella stringa.
Ahhhhh... Arcano risolto! Pero' con modificare intendi modificare
tramite fgets oppure tramite un'altra assegnazione diretta? Vado a fare
qualche prova!
Grazie per l'aiuto!!


qualche prova!
Devi considerare la stringa costante, anche se con il tuo compilatore
funziona tutto correttamente.
char * s = "pippo";
s[1] = 'x';           // non lo puoi fare!
s = "pluto";          // ok.


 funziona tutto correttamente.
Perfetto! Ti ringrazio ancora per l'aiuto!


 non vada in segfault (quindi in questo caso 45 e' un indirizzo)?
Il programma  e` corretto. Tu non  stai scrivendo su un'area  di memoria
non allocata. Quello che fai e`  una semplice assegnazione tra puntatore
ed  intero. '45'  viene interpretato  come  indirizzo  di memoria  (come
hai  giustamente intuito)  e  il valore  risultante  viene assegnato  al
puntatore. Quello che non potresti fare e` questo:
i = 45;
*i = 123;
Se dereferenzi  il puntatori accedi  ad un'area  di memoria che  non hai
allocato (in teoria potrebbe essere allocata, ma questo e` irrilevante),
risultato: undefined behaviour.
Anche la  seconda assegnazione  e` lecita. "Ciao"  (lo \0  e` superfluo,
viene  messo   automaticamente)  e`  un  array   di  caratteri  allocati
automaticamente  dal  compilatore  (tipicamente in  un'area  di  memoria
a  sola  lettura). L'assegnazione fa  puntare  'prova'  a quest'area  di
memoria. In  questo  caso ricorda  che  *non*  e` lecito  modificare  la
stringa, quindi sarebbe  meglio (quando possibile) usare  un puntatore a
caratteri costanti:
char const *p = "blablabla";
char *q = "foobar";
p[1] = 'x';     /* Errore in fase di compilazione */
q[1] = 'x';     /* Nessun errore, undefined behaviour a runtime */
Nel primo caso  il compilatore previene un uso  scorretto delle stringhe
costanti.
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
"Ci sono le balle , le megaballe e le statistiche".
 Mark Twain

	i=45;
secondo voi alla fine di questa istruzione
i==45 oppure i==(int *) 45 ? 
Il K&R2 mi sembra che non la preveda
Io dico deve essere la seconda i==(int *) 45, voi che dite?
Lo standard che dice?


 Io dico deve essere la seconda i==(int *) 45, voi che dite?
A rigor di standard la  seconda [1]. Un puntatore puo` essere convertito
in un  tipo intero e  viceversa. Il risultato e`  implementation defined
tranne che per il null pointer. In questo caso il valore numerico e` '0'
(che  non  e`  necessariamente  la  rappresentazione  interna  del  null
pointer).
La conversione e` sempre possibile,  ma potrebbe dare risultati inattesi
(dipende tutto da come sono rappresentati internamente i puntatori). Per
evitare problemi di troncamento ci sono i tipi 'intptr_t' e 'uintptr_t',
che sono tipi interi (con e senza segno) che possono contenere il valore
di qualunque puntatore. Se convertiamo un  puntatore in uno dei due tipi
e riconvertiamo  in puntatore siamo  sicuri di ottenere il  puntatore di
partenza (per altri tipi la cosa potrebbe non essere vera).
[1] I 2 confronti  che hai scritto tu sono identici. In  (i == 45) prima
viene  effettuata  la  conversione  [2],  poi  il  confronto. Nell'altro
la   conversione   e`  esplicita. Nel   primo   caso   ho  inteso   come
"rappresentazione binaria in complemento a 2 del numero 45", nel secondo
"rappresentazione  nel formato  specifico della  macchina dell'indirizzo
45"
[2] Il warning del gcc e`  da intendersi come: "Occhio, la cosa potrebbe
non avere senso".
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
Ci sono due cose che l'uomo non puo` nascondere:
essere ubriaco ed essere innamorato.

partenza (per altri tipi la cosa potrebbe non essere vera).
Aggiungo una cosa che Kronos non ha specificato: intptr_t e uintptr_t
li hai a disposizione solo dal C99 in poi (in particolare v. l'header
stdint.h) :)
Se lavori in C89 o usi un configure per scoprire come viene
memorizzato un puntatore oppure speri che ti fada bene :)
-- 
Mox
"Trust the programmer."
"Don't prevent the programmer from doing what needs to be done."
"Keep the language small and simple."
"Provide only one way to do an operation."

 ed  intero.
Capito... Quindi in questo caso i "punta" a 45. Se poi provo a scrivere
qualcosa nell'area definita nel puntatore mi becco un errore a runtime.
Grazie anche a te per la spiegazione!


 memorizzato un puntatore oppure speri che ti fada bene :)
int *p;
unsigned char n[sizeof(int *)];
memcpy(n, &p, sizeof(int *));
sizeof() viene valutata  al momento della compilazione,  quindi anche un
compilatore  C89  non  dovrebbe  lamentarsi per  l'array  di  dimensioni
variabili. Dovrebbe andare, tu che dici?
Hum, pero`  resta il  fatto che  non abbiamo  ancora un  intero... forse
sarebbe meglio  una union, con  il puntatore  ed i vari  tipi interi. Il
campo da cui leggere viene selezionato a runtime tramite sizeof (e se il
compilatore e` abbastanza furbo leva le condizioni che non matchano).
union foo {
        void *p;
        short s;
#if INT_MAX != SHRT_MAX
        int i;
#endif
#if LONG_MAX != INT_MAX && LONG_MAX != SHRT_MAX
        long int l;
#endif
};
[...]
union foo bar;
int *a;
bar.p = a;
if (sizeof(a) == sizeof(short) {
        [...]
}
#if INT_MAX != SHRT_MAX
else if (sizeof(a) == sizeof(int) {
        [...]
}
#endif
#if LONG_MAX != INT_MAX && LONG_MAX != SHRT_MAX
else if (sizeof(a) == sizeof(long int) {
        [...]
}
#endif
Uno schifo insomma. Altre idee?
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
This message will self distruct in 5 seconds.