Newsgroup: it.comp.lang.c++
Titolo: Un novizio con tanta voglia di imparare ;)

Finalmente mi sono deciso ad imparare il C.
Sono uno studente in Ingegneria Elettronica al II anno e con l'esame di
Fondamenti di Informatica mi hanno fatto studiare il PASCAL.
Carino ma molto lontano dalla macchina.
Cosi', fatto l'esame, mi sono deciso e sono passato al C: ho deciso di 
studiarlo su Linux visto che C e Unix vanno perfettamente d'amore
e d'accordo, vero? :))
Mi sono procurato il libro di Ritchie (The C programming Language)
credo una versione molto ma MOLTO vecchia, pero' credo che per
incominciare sia buono.
Probabilmente pero' sono cambiate molte cose nello standard C che sul
libro non ci sono: quali sono le fonti (possibilmente gratuite su
Internet) per aggiornami con le ultime versioni?
Manuali, faq, e cose del genere sul C? Soprattutto la ANSI-C, poi
vedremo di entrare nei dettagli delle varie situazioni.
Ed ecco alcuni problemi che ho subito riscontrato.
E' vero che tutti i parametri che passo ad una funzione sono parametri 
passati per valore e non per indirizzo?
Questa mi sembra una grossa pecca.
Certo c'è il trucco di passare il puntatore alla variabile ma si tratta
di un procedimento artificioso e poco leggibile.
Inoltre pensate a dover passare un puntatore per indirizzo.
Dovrei passare quindi il puntatore ad un puntatore (che casino!!)
Sicuramente esiste qualche altro metodo piu' efficace e semplice: chi me
lo dice?
Un altro problema.
Se ho piu' funzioni scritte su più file: source1.c, source2.c, source3.c
qual e' la procedura più corretta per la compilazione del tutto?
Includere i file nel sorgente del main e quindi scrivere solo
	cc source1.c (almeno in Linux)
oppure scrivere
	cc source1.c source2.c source3.c ???
Qual e' la differenza fra i vari metodi? Qual e' preferebile e quando?
Quando dichiaro una struct, qual e' il suo campo di validita'???
Se la dichiaro nel sorgente del main, essa non mi viene riconosciuta
negli altri moduli.
Come ovviare a cio'???
Grazie a tutti.
-- 
+--------------------------------------+
|    ____   _~o            ,__o        |
|  ____  _-\_<,          _-\_<,        |
|       (*)/'(*)        (*)/'(*)       |
|        Giuseppe Modugno              |
|                Student               |
|         E-mail: G.Mo...@Diana.IT   |
+--------------------------------------+

 +--------------------------------------+
Figurati! Fatti risentire quando vuoi.
Andrea Glorioso Pelliccioni

negli altri moduli.
una dichiarazione e' valida dal punto in cui compare fino alla 
fine del file che la contiene; di solito le dichiarazioni si mettono 
in un file .h che viene poi incluso dai vari moduli che ne hanno bisogno 
--
Marco Danti
remove NOSPAM from my address if you want to reply directly to me; sorry.

fine del file che la contiene; 
se e' dichiarata a livello di file; se e' dichiarata a livello 
di funzione, e' visibile solo all'interno della funzione


 puntatore non lo è).
scusa, quale e' la pericolosita'? Non mi sembra piu' pericoloso
dell'uso dei puntatori


Sacrosanta verit=E0.
E' un concetto tanto banale quanto importante. Sapeste quanto tempo ho
perso a spiegare il C ed il C++ a gente che non riusciva a capire =
questa
fondamentale verit=E0.
Soprattutto quando si passava a parlare degli array =85
Andrea
	-----Original Message-----
	From:	
NOSPAM...@pn.ITnet.it
 (Marco Danti)
[
SMTP:NOSPAM...@pn.ITnet.it
]
	Posted At:	Sunday, July 27, 1997 11:49 PM
	Posted To:	c++
	Conversation:	Un novizio con tanta voglia di imparare ;)
	Subject:	Re: Un novizio con tanta voglia di imparare ;)
	=85
	un puntatore non e' un indirizzo.
	=85

 dell'uso dei puntatori
Effettivamente non è tanto il fatto che il riferimento sia vincolato a
renderlo più pericoloso - secondo me - di un puntatore.Un riferimento è
più pericoloso per chi inizia, soprattutto se si usano classi di altri.
Infatti, la mancanza di necessità di passare esplicitamente un indirizzo
può confondere un novizio: se io ho un prototipo di funzione "void func1
(my_class* arg1)" DEVO passare o un puntatore (ma allora l'ho dichiarato
prima, e gli ho assegnato un indirizzo, e quindi si presuma che io
sappia che quello che passo non è una copia dell'oggetto) oppure
l'indirizzo dell'oggetto stesso, ricordandomi quindi che non si parla di
una copia. Con i riferimenti (ed un prototipo "void func1(my_class&
arg1)" io potrei scrivere semplicemente :
my_class my_object;
func1(my_object);
Se non so esattamente qual e il prototipo della funzione, e non conosco
bene la classe eventuale a cui quella funzione appartiene, io
principiante potrei pensare ingenuamente di stare passando per valore,
mentre così non è.
Si capisce che un programmatore appena appena un po' scafato non si
farebbe trarre in inganno, però tutti quanti abbiamo iniziato da zero...
;-)
Saluti,
Andrea Glorioso Pelliccioni

indirizzi...
Certo che gli passa gli indirizzi.
La differenza che volevo evidenziare e' che puntatori ed indirizzi
hanno una semantica diversa: un puntatore e' una VARIABILE, mentre 
un indirizzo e' per definizione COSTANTE.
Mi spiego meglio con due esempi. In C nessuno mi impedisce
di scrivere una cosa del genere: 
int main() {
 int var1 = 10, var2 = 20;
 do_something( &var2 );  // passo un PUNTATORE che contiene 
                         // l'indirizzo di var2
}
void do_something(int *p) {
  p += 1;             // oops! ora p punta a var1...
  *p = 0;             // azzero var1! 
}
se var2 e' allocata subito dopo var1, all'uscita della funzione ho
var1 = 0 e var2 = 20. Al di la' del fatto che una funzione cosi' non 
ha senso, quello che ho scritto e' perfettamente legale perche' il 
puntatore ha una semantica di VARIABILE: in questo caso, P += 1 
significa 'incrementa il puntatore'.
Vediamo che succede se uso un passaggio per indirizzo vero:
int main() {
 int var1 = 10, var2 = 20;
 do_something( var2 );  // passo l'INDIRIZZO di var2
}
void do_something(int &p) {
  p += 1;             // var2 = 21
  p = 0;              // var2 = 0 
}
Se andassi a vedere il disassemblato i due esempi, probabilmente 
vedrei che in entrambi i casi p1 viene caricato tramite una LEA;
la differenza sta in come viene poi usato, visto che nel secondo caso 
il risultato finale e' ben diverso. 
Infatti stavolta e' cambiata la semantica, che non e' piu' di puntatore
(cioe' variabile) ma di indirizzo (cioe' costante): ora p += 1
significa 'incrementa la locazione che ha indirizzo p'
E' questo che intendevo, dicendo che i puntatori ed indirizzi non
sono la stessa cosa.
Saluti,


ATTENZIONE. Sei partito bene quando qualche tempo fa hai detto che un
puntatore non =E8 un indirizzo. Ora invece stai pisciando fuori di
parecchio.
	La differenza che volevo evidenziare e' che puntatori ed
indirizzi
	hanno una semantica diversa: un puntatore e' una VARIABILE,
mentre=20
	un indirizzo e' per definizione COSTANTE.
Tanto per cominciare tu fai differenza fra variabile e costante dicendo
che un puntatore =E8 una variabile mentre un indirizzo =E8 una =
costante. In
realt=E0 =E8 possibilissomo definire dei puntatori che sono costanti.
L'osservazione giusta sarebbe dire che un puntatore =E8 variabile =
(intesa
come zona di memoria con un nome, indipendentemente dal fatto che poi
sia costante, ovvero read-only) mentre un indirizzo =E8 un valore. =
Ovvero
un pattern di bit. Un possibile contenuto della memoria.
Nel tuo codice scrivi:
	do_something( &var2 );  // passo un PUNTATORE che contiene=20
	                         // l'indirizzo di var2
Abbiamo gi=E0 specificato che un puntatore non =E8 un indirizzo e che =
in C
(e C++) esiste solo il passaggio per valore. Quindi quello che tu stai
passando =E8 il valore dell'indirizzo di var2. E dalto canto non =
sarebbe
nemmeno possibile "passare un puntatore" dato che un puntatore non =E8 =
un
valore e il passaggio dei parametri avviene solo per valore.
Riguardo alla funzione do_something, a parte il fatto che sarebbe stato
meglio dichiararla prima di chiamarla nel main, tu hai detto che il
codice non ha nessun senso, e su questo hai ragione. Per=F2 quello che =
hai
scritto non =E8 affatto legale, come dici tu. E ci sono due motivi. =
Primo
tu sei partito dal presupposto che le due variabili var1 e var2 siano
consecutive in memoria, il che non sta scritto da nessuna parte. =
Inoltre
ha presunto che var2 preceda var1, e anche questo non =E8 affatto =
detto.
Per finire tu hai incrementato di uno un puntatore ad una variabile, il
che, secondo lo standard, ha un risultato indefinito.=20
A parte il fatto che la maggior parte delle implementazioni sarebbe in
grado di compilare il tuo codice e anche di eseguirlo correttamente
durante le fasi dello sviluppo (il che non significa che il codice =E8
legale, ma solo che un comportamento indefinito secondo lo standard ha
spesso riscontro in un comportamento "logico" nelle implementazioni
reali). Nota per=F2 che c'e' una forte possibilit=E0 che il tuo codice =
porti
ad un coredump non appena lo compili in modalit=E0 non debug a causa =
della
possibile cessata allocazione di var1.
---
     Andrea Ferro
SW.AN. Technologies s.a.s.
Merate (Lc)          Italy
	-----Original Message-----
	From:	
NOSPAM...@pn.ITnet.it
 (Marco Danti)
[
SMTP:NOSPAM...@pn.ITnet.it
]
	Posted At:	Sunday, August 03, 1997 10:53 PM
	Posted To:	c++
	Conversation:	Un novizio con tanta voglia di imparare ;)
	Subject:	Re: Un novizio con tanta voglia di imparare ;)
	Ciao Andrea,
	>Da quelle due 'lea' (3 e 4) e da quei due riferimenti alla
memoria (1 e
	>2) io direi che alla funzione do_something sono stati passati
degli
	>indirizzi...
	Certo che gli passa gli indirizzi.
	La differenza che volevo evidenziare e' che puntatori ed
indirizzi
	hanno una semantica diversa: un puntatore e' una VARIABILE,
mentre=20
	un indirizzo e' per definizione COSTANTE.
	Mi spiego meglio con due esempi. In C nessuno mi impedisce
	di scrivere una cosa del genere:=20
	int main() {
	 int var1 =3D 10, var2 =3D 20;
	 do_something( &var2 );  // passo un PUNTATORE che contiene=20
	                         // l'indirizzo di var2
	}
	void do_something(int *p) {
	  p +=3D 1;             // oops! ora p punta a var1...
	  *p =3D 0;             // azzero var1!=20
	}
	se var2 e' allocata subito dopo var1, all'uscita della funzione
ho
	var1 =3D 0 e var2 =3D 20. Al di la' del fatto che una funzione cosi'
non=20
	ha senso, quello che ho scritto e' perfettamente legale perche'
il=20
	puntatore ha una semantica di VARIABILE: in questo caso, P +=3D 1=20
	significa 'incrementa il puntatore'.
	Vediamo che succede se uso un passaggio per indirizzo vero:
	int main() {
	 int var1 =3D 10, var2 =3D 20;
	 do_something( var2 );  // passo l'INDIRIZZO di var2
	}
	void do_something(int &p) {
	  p +=3D 1;             // var2 =3D 21
	  p =3D 0;              // var2 =3D 0=20
	}
	Se andassi a vedere il disassemblato i due esempi, probabilmente
	vedrei che in entrambi i casi p1 viene caricato tramite una LEA;
	la differenza sta in come viene poi usato, visto che nel secondo
caso=20
	il risultato finale e' ben diverso.=20
	Infatti stavolta e' cambiata la semantica, che non e' piu' di
puntatore
	(cioe' variabile) ma di indirizzo (cioe' costante): ora p +=3D 1


dell'esempio che ho riportato, come accade col mio compilatore.
Questo e' piu' che vero. Qual e' il compilatore che alloca qua e la'
le variabili dichiarate consecutivamente? Io ho sottomano VC5,
Watcom10 e Borland C++ Builder. Uso anche ogni tanto il compilatore c
di Linux e nessuno di questi sparpaglia le variabili dove vengono,
soprattutto coi programmini piccoli. Vorrei chiedere ad Andrea se non
gli e' mai capitato di accedere ad un elemento di una matrice
incrementando il puntatore al primo elemento anziche' usando gli
indici... E' la stessa cosa che incrementare il puntatore a una
variabile int quando ce n'e' un'altra subito dopo.
Cordialmente,
Gianni Rondinini, programmer and designer at Pierre s.n.c.
e-mail: 
pie...@mail.asianet.it
homepage: 
http://www.geocities.com/SiliconValley/park/7666
Red Hat Linux 4.1 user since 6/16/97
Windows NT 4.0 Server user since 6/27/97