Ciao e bentornato.
In questa conferenza, voglio parlare di un concetto chiamato passaggio per riferimento.
Quando abbiamo iniziato a parlare di puntatori, ho menzionato uno dei vantaggi è che
non devi usare tanto le variabili globali.
Perché quando si passa un puntatore a
una funzione, le funzioni possono utilizzare quel parametro. E quando modifica quel parametro, i dati verranno
modificati al di fuori della funzione.
Quindi questo è un concetto prezioso e prezioso.
Ne parleremo. Questo è più un concetto. C in realtà non lo utilizza.
E ti mostrerò come e ti darò alcuni
esempi fondamentalmente come funziona.
Quindi c'è questo concetto di passaggio per valore. Questo ha a che fare con le funzioni.
Abbiamo parlato del passaggio di dati a una funzione, ma come vengono effettivamente
passati in termini di linguaggio nel compilatore.
Quindi c'è un concetto di passaggio per valore. Ed è di questo
che abbiamo parlato fino ad ora. Ogni volta che chiamiamo la funzione
oltre alla funzione scanf, ma ogni altra volta che chiamiamo la funzione,
quando modifichi quei dati all'interno della funzione non sono stati modificati
al di fuori della funzione.
Quindi abbiamo parlato di variabili locali che sono una specie di concetto diverso.
Ma quando si passano i dati a una funzione, ci sono due modi per passarli.
Puoi passarlo per valore, puoi passarlo per riferimento.
C passa esclusivamente per valore e così
fa java,
tutti passano per valore. Ma simula il passaggio per riferimento
perché copi gli indirizzi.
E così anche se questo
concetto passa per riferimento non è specificamente impiegato
da c, lo simula. E quindi per capire cosa significa
passare per riferimento e perché è importante ne parleremo.
Ma passa per valore quando una funzione copia il valore effettivo di un
argomento nel parametro formale della funzione.
Ed è per questo che se hai un intero,
un float o un double e lo passi come argomento a una funzione,
quella variabile effettiva non viene modificata al di fuori della funzione perché viene copiata.
Quindi le modifiche apportate al parametro all'interno della funzione non hanno effetto sull'argomento.
L'argomento passato non viene modificato.
Quindi si comporta quasi come una variabile locale perché è una copia.
Il modo in cui sta effettivamente accadendo sotto il cofano è che viene copiato e passato alla funzione.
Il programma C usa la chiamata per valore per passare gli argomenti.
Tutto è chiamato per valore, passare per valore.
Questi sono usati in modo intercambiabile questi termini.
Quindi ancora una volta questo significa che il codice all'interno di una funzione non può alterare gli argomenti usati per chiamare la funzione.
Non ci sono cambiamenti nei valori sebbene siano stati modificati all'interno della funzione.
Sembra che siano variabili locali.
Ed è per questo che prima, fino
a questo punto, quando dovevi creare dati globali se volevi condividere i dati da una funzione all'altra.
Ed è così che funziona c.
Ma cosa succede quando si passa effettivamente una
copia di un indirizzo. Quindi può imitare il passaggio per riferimento.
Ma ecco un esempio di come abbiamo usato il passaggio per valore, si è dimostrato molto carino qui.
Questa routine di scambio è un caso d'uso spesso per dimostrare il passaggio
per valore perché ciò che fa è creare un temp e scambiare i parametri
che gli argomenti vengono passati.
Quindi, se abbiamo una funzione chiamata swap che accetta due numeri
interi, creiamo una variabile locale temp.
Se assegniamo al parametro x a temp, temp sarà
uguale a x. Se diciamo che x è uguale a
y, ora y sarà uguale a x. Se diciamo che y è uguale a temp,
y sarà uguale a temp.
Ma quando si chiama questa funzione passando quei valori, x
e y saranno locali a questa funzione.
Quelle variabili non verranno modificate al di fuori di questa funzione.
E questa funzione lo dimostra molto utile perché stiamo assegnando
a y e stiamo assegnando a x.
E x e y sono locali per questa funzione perché stiamo passando per valore,
non vengono modificati al di fuori di questa funzione ed è per questo che dobbiamo usare variabili globali.
Ma sono numeri interi. Sono due numeri interi x e y. Non sono indirizzi,
sono numeri interi e questo è significativo.
Quindi se chiamiamo
swap e vediamo che aspetto ha, noterai
che i valori non cambiano.
Quindi se creiamo una variabile chiamata 100 b con
200 e stampiamo le variabili prima di scambiare, 100
e 200 quindi chiamiamo swap, le
variabili non verranno modificate dopo
averle stampate di nuovo.
Quindi diamo un'occhiata a questo nei blocchi di codice e questo mostrerà il passaggio per valore.
Quindi ecco il nostro esempio. Abbiamo la nostra routine di scambio.
Stiamo scambiando i valori dei dati passati x e y.
Lo chiamiamo con 100200.
Stamperemo prima di chiamare la funzione.
Stamperemo dopo.
E quello che noterai è che le variabili aeb non cambiano mai.
E il motivo è perché stiamo passando per valore.
Quindi, se eseguo questo programma, possiamo
vedere che prima dello scambio il valore di a era 100 dopo che hai scambiato il valore di a era
100 e lo stesso per b 200 e 200.
E il motivo è perché siamo passati per valore. Se passassimo per riferimento,
quelle variabili aeb cambierebbero dopo la chiamata a swap.
Ora che ne dici se utilizziamo la stessa tecnica passa per
valore ma copiamo i puntatori, cosa pensi che succederà?
Quindi i puntatori e le funzioni vanno d'accordo abbastanza bene insieme.
Puoi passare un puntatore come argomento a una funzione
e puoi anche fare in modo che una funzione restituisca un puntatore come risultato.
Mostreremo anche come farlo.
Ma passa per riferimento copia l'indirizzo di un argomento nel parametro formale.
L'indirizzo viene utilizzato per accedere all'argomento effettivo utilizzato nella chiamata.
Quindi ciò significa che le modifiche apportate al
parametro all'interno della funzione influenzano l'argomento che si trova nella chiamata.
E così anche se non è tecnicamente sotto il cofano passato per
riferimento, imita o simula il passaggio per riferimento.
Stiamo copiando l'indirizzo. Se copi l'indirizzo, hai
un nuovo indirizzo e memoria per quel valore l'indirizzo.
Ma se provi ad assegnare a quell'indirizzo, verrà assegnato all'indirizzo.
Quindi, anche se viene passato per valore, sta copiando.
E se stai copiando un intero normale, non apporti modifiche. Se stai copiando un indirizzo, l'indirizzo
è in memoria, quindi quando apporti modifiche, apporterai modifiche a quell'indirizzo.
Quindi, per passare il valore per
riferimento, i puntatori agli argomenti vengono passati alle funzioni proprio come qualsiasi altro valore.
È necessario dichiarare i parametri della funzione come tipi di puntatore con l'asterisco.
Le modifiche all'interno della funzione si riflettono anche all'esterno della funzione.
Non devi usare tanto le variabili globali.
A differenza di una chiamata per valore in cui le modifiche non si riflettono all'esterno della funzione.
Stiamo ancora copiando stiamo ancora passando per valore è solo il valore di una copia dell'indirizzo.
Quindi questo è un concetto importante da capire.
Ora, quando creiamo la nostra funzione
di scambio, la creeremo con la dichiarazione all'interno della
funzione come asterisco, stella e stella.
Ciò significa che questa funzione accetta puntatori.
Ora, quando assegniamo all'interno di questa funzione, dobbiamo
effettivamente utilizzare l'operatore di riferimento indiretto per dereferenziare perché
vogliamo assegnare i valori. Assegneremo il valore che
quella x quella x punta alla temp.
Assegneremo il valore di x punti a al valore a
cui y punta e quindi assegneremo il valore a cui y punta, a temp.
Temp è un numero intero, quindi non dobbiamo dereferenziarlo.
Ora, quando
lo invochiamo con a100 e
b200 passando aeb, aeb non sono puntatori, quindi dobbiamo passare
l'indirizzo perché la funzione accetta puntatori.
Ogni volta che hai una funzione che accetta puntatori e non dichiari un
puntatore, devi usare l'indirizzo dell'operatore ed è la stessa cosa di come usiamo scanf.
Ma ora noterai quando lo invochiamo dopo
che la chiamata per scambiare le variabili a e b sta
per essere cambiata, saranno scambiate. A sarà 200 b sarà 100.
Quindi ora diamo un'occhiata a questo esempio con il nostro metodo di scambio che cambia in puntatori nei blocchi di codice.
Siamo in blocchi di codice. Abbiamo modificato la funzione di scambio per prendere i puntatori.
Quindi dobbiamo dereferenziarli quando li assegniamo.
Ora passiamo anche l'indirizzo di aeb perché questi ora sono numeri interi e
lo scambio ora accetta puntatori. Quindi, quando eseguiremo questo, vedremo
che la chiamata e il dopo verranno ora modificati.
Quindi prima di chiamare swap a è uguale a 100 dopo che chiamiamo swap è 200.
Prima di chiamare swap per b, è 200. Successivamente, sono 100.
Quindi siamo in grado di modificare i valori delle variabili all'interno
della funzione perché stiamo facendo una copia dell'indirizzo. Molto, molto importante e uno dei
grandi vantaggi dei puntatori.
Quindi riassumiamo la sintassi. L'ho già fatto, ma passiamo più in dettaglio.
È possibile comunicare due tipi di informazioni su una variabile a una funzione.
È possibile trasmettere il valore di
x e la funzione deve essere dichiarata con lo stesso tipo di x.
Lo sappiamo. Ogni volta che passiamo dati
a una funzione, dobbiamo avere gli stessi tipi quando la chiamiamo.
E qui abbiamo int function1 per invocarlo ed è definito come un int num.
Quindi, quando trasmettiamo il valore di x nella funzione, devono essere dichiarati con lo stesso tipo.
Quindi, se si desidera effettivamente invocare un indirizzo x, è necessario
che la definizione della funzione includa un puntatore al tipo corretto.
Quindi ogni volta che usi i puntatori, devi assicurarti che se stai
passando dei dati e quei dati non sono un puntatore, devi ottenerne l'indirizzo.
Ciò che questo riassume è che se definisci una funzione che non accetta un
puntatore, puoi semplicemente chiamarla e passare i dati.
Assicurati che non sia un puntatore.
Se hai una funzione che accetta un puntatore a
un asterisco, quando
la invochi, devi invocarla con l'operatore add o sub.
Devi passare l'indirizzo.
Questa è la sintassi.
Ora puoi anche qualificare un parametro di funzione utilizzando la parola chiave costante.
Ciò indica che la funzione tratterà l'argomento passato per questo parametro come una costante.
È utile solo quando il parametro è un puntatore.
Perché se stai passando per valore e non stai passando puntatori, non importa perché
non influenzerà il cambiamento all'esterno della funzione, quindi perché
dovresti renderlo una costante, chi se ne frega se lo cambi .
L'unico motivo per cui si rende costante un puntatore è perché non si desidera
che i valori esterni alla funzione cambino.
E così puoi applicare la parola chiave costante a un parametro che è
un puntatore per specificare che la funzione non cambierà il valore a cui punta l'argomento.
Molto importante.
Quindi in questo esempio abbiamo una funzione di invio del messaggio. Ci vuole un puntatore
a messaggio p.
Mettiamo la parola chiave costante prima della stella char.
Quindi questo tipo di messaggio di parametro p è un puntatore a un carattere costante.
È il valore del carattere che è costante, non il suo indirizzo.
Quindi in questo caso quello che stiamo facendo è il puntatore a cui si punta non può cambiare.
Possiamo cambiare l'indirizzo, ma non possiamo cambiare ciò che sta indicando il valore.
La sintassi è simile a quando creiamo costanti su altri puntatori.
La parola chiave costante è che è la prima cosa che viene visualizzata, quindi non è possibile modificare il valore.
Ora puoi specificare che il puntatore stesso è costante,
ma questo ha poco senso perché l'indirizzo viene passato per valore.
Non è possibile modificare il
puntatore di rendering nella funzione chiamante. Quindi questo è solo se provi a fare in modo che l'indirizzo non possa
essere cambiato, qual è il punto perché è passato per valore. Quindi stai effettivamente
creando una nuova posizione di
memoria per contenere quell'indirizzo specifico. Quindi se lo cambi, chi se ne frega non lo cambierà all'esterno.
Vuoi solo essere in grado di rendere il
parametro una costante in modo da non modificare il valore di ciò
a cui punta, non
puoi comunque cambiare il puntatore originale e la funzione chiamante perché è
passato per valore passato per copia.
Il compilatore sa che un argomento che è un puntatore a dati costanti
sarà sicuro, quindi ci sono vantaggi in questo. Non puoi modificare accidentalmente ciò a cui punta il valore.
Quindi potresti farlo di nuovo se non vuoi che le modifiche si riflettano all'esterno della funzione.
Se si passa un puntatore a dati costanti come argomento per
un parametro, il parametro deve essere utilizzato come sopra.
Quando si richiama la funzione e la si passa in costante, è necessario
che anche la dichiarazione della funzione prenda un puntatore a carattere costante, proprio
come i normali puntatori che sono costanti.
Devono essere definiti e le definizioni devono corrispondere al prototipo.
Restituzione di puntatori da una funzione.
Restituire un puntatore da una funzione è una capacità particolarmente potente.
Fornisce un modo per restituire non solo un singolo valore, ma un intero insieme di valori.
Quindi, ancora una volta, uno degli altri vantaggi che
ho menzionato sui puntatori è che ora puoi restituire più dati da una funzione.
In passato, puoi restituire solo un valore.
Ma con un puntatore perché un puntatore potrebbe
puntare a una struttura di cui non abbiamo ancora parlato o anche
ad altre cose puoi restituire
più valori Quindi sappiamo come passare i puntatori alle funzioni, ora
vogliamo parlare della restituzione dei puntatori.
Dovresti dichiarare una funzione che restituisce un puntatore. Quindi la dichiarazione della funzione deve corrispondere.
È molto facile farlo. Devi solo dire usa l'asterisco quando
dichiari la funzione o la definisci e hai il tipo di ritorno per quel puntatore a cui punta.
Quindi fai attenzione anche se ci sono rischi specifici relativi alla restituzione di un puntatore.
Usa le variabili locali per evitare di interferire con la variabile a cui punta l'argomento.
È alquanto problematico quando si restituiscono i puntatori perché se si modifica quel puntatore all'interno della
funzione e poi lo si restituisce, potrebbe
essere qualcosa che non si intende che faccia.
Quindi usa sempre le variabili locali se non vuoi influenzare una variabile a
cui punta il tuo argomento.
E così questa lezione ha
descritto come passare puntatori
a funzioni e come restituire puntatori da funzioni.
E usando questo meccanismo di passaggio di puntatori
a una funzione, dimostra o imita il passaggio per
riferimento perché stai copiando in un indirizzo.
E quando copi un indirizzo se scrivi a quell'indirizzo, aggiorni qualunque cosa
stia puntando a quell'indirizzo,
il che significa effettivamente che stai cambiando il valore dei dati
all'interno della funzione, lo rifletterà al di fuori della funzione.
Usiamo la routine di scambio per dimostrarlo.
Questo è un concetto molto potente. E vuoi imitare il passaggio per riferimento,
puoi usare i puntatori per farlo e vuoi farlo quando vuoi cambiare le cose al di fuori della funzione.
Grazie.