Ciao e bentornato. In questa conferenza voglio parlare di aritmetica dei punti.
Ora che abbiamo compreso la relazione tra array e
puntatori, questo concetto sarà più facile da capire.
Diciamo aritmetica, ma in realtà non lo facciamo -
tutto ciò che significa veramente è che puoi
fare più o meno o incrementare o decrementare su un puntatore stesso.
Quindi il vero potere dell'uso dei puntatori agli array entra in gioco quando si
desidera sequenziare gli elementi di un array.
Vuoi andare dal primo elemento alla fine, vuoi iterare attraverso di loro.
Questo è il vero punto di forza. Poiché i puntatori puntano
usano indirizzi, ogni elemento nell'array è solo un altro indirizzo.
Quindi puoi semplicemente fare più plus sui puntatori e puoi andare all'indirizzo successivo.
Quindi qui il puntatore a valori può essere utilizzato per accedere al primo
numero intero dell'array di valori.
Può essere utilizzato per accedere a valori inferiori a 0.
Quindi, se ricordi il puntatore a valori è un puntatore che punta
a un array di numeri interi.
E l'abbiamo assegnato al primo elemento dell'array semplicemente assegnando il puntatore al nome dell'array.
Potremmo anche usare l'indirizzo dell'operatore sub-0 se lo volessimo.
Ma quando dereferenziamo il puntatore
ai valori perché punta al primo elemento
dell'array, ti darà il primo numero intero nell'array value sub-0.
Se vuoi fare riferimento al valore sub 3
tramite la variabile pointer, tutto quello che devi fare è aggiungere 3 al puntatore dei valori
e quindi applicare l'operatore di riferimento indiretto per dereferenziarlo.
Quindi potresti fare qualcosa del genere. Puoi dire il puntatore ai valori più 3
e quindi dereferenziarlo con l'asterisco.
E di solito metti l'asterisco fuori dalle virgolette per renderlo chiaro.
Ma ciò che sta facendo è dire puntatore
a valori, che è un indirizzo del primo elemento dell'array, aggiunge 3 ad esso.
E quindi aggiungerà effettivamente per ogni byte per i numeri interi,
moltiplicherà i byte per i numeri interi.
Ma questo essenzialmente punta al sub 3,
il quarto elemento dell'array.
Quindi nell'espressione asterisco puntatore a valori più i che può
essere utilizzato per accedere a qualsiasi valore contenuto in un array di valori.
Quindi, se comprendi questa espressione, puoi aggiungere qualsiasi cosa a i e
ti indicherà uno specifico array di elementi.
Quindi, se vuoi impostare il valore sotto 10 a 27, tutto ciò
che devi fare è se stai usando un puntatore
è dire puntatore ai valori più 10 e poi dereferenziarlo e dire uguale a 27.
Quindi vedi qui la sintassi diversa.
Ancora una volta, è una comodità notazionale ma è anche più efficiente in termini di programma stesso.
Quindi i puntatori poiché sono così strettamente correlati agli array,
puoi accedere facilmente agli elementi semplicemente incrementando i puntatori decrementali
o aggiungendo valori o sottraendo valori da un puntatore.
Molto, molto utile.
Per impostare il puntatore di valori in modo che punti al secondo elemento della matrice
di valori, è possibile applicare l'operatore indirizzo al valore sub 1 e assegnare i risultati al puntatore di valori.
L'abbiamo visto. Questo è solo un altro modo per fare la stessa
cosa che ho menzionato prima se vuoi usare l'operatore secondario address.
Puoi sempre farlo se vuoi,
ma è molto più conveniente fare l'aritmetica dei puntatori.
Se il puntatore a valori punta al valore inferiore
a 0, è possibile impostare il punto di valori di uno semplicemente aggiungendo uno
al valore del puntatore a valori. E questo è davvero ciò che stiamo ottenendo con l'aritmetica dei punti.
Tutto quello che devi fare è dire valori punto o
più è uguale a uno, e ora il puntatore valori punta al secondo elemento dell'array
o al primo indice.
Notazione molto, molto bella, molto facile da fare.
Quindi questa è un'espressione perfettamente valida in c e può essere
utilizzata per puntatori a qualsiasi tipo di dati, sia che si tratti di un
carattere intero o di qualsiasi altra cosa. E probabilmente dovresti pensare a quanto possa essere utile nei personaggi.
Se si dispone di un puntatore a carattere, è ora possibile accedere
a ogni elemento, a ogni carattere in una stringa, semplicemente facendo un segno più su un puntatore.
Gli operatori di incremento e decremento più più e meno meno sono
particolarmente utili quando si ha a che fare con
questi puntatori perché di solito si vorrà passare da un elemento al successivo e così via.
Non è così comune aggiungere 22 o meno 20
perché di solito vai in sequenza.
Quindi l'uso dell'operatore di incremento in un puntatore ha lo stesso effetto dell'aggiunta di uno al puntatore.
L'utilizzo dell'operatore di decremento ha lo stesso effetto della sottrazione di uno dal puntatore.
Quindi dicendo il puntatore più più valori
imposterà il puntatore dei valori che punta al numero intero successivo nell'array dei valori.
Meno meno dovrebbe essere il puntatore dei valori
Imposta il puntatore dei valori che punta all'intero precedente nell'array dei valori.
Ma devi stare attento quando fai il meno
meno perché vuoi assicurarti di essere almeno nell'array e non sei a 0.
E lo stesso vale per i plus plus.
Se sei alla fine dell'array, non vuoi avere errori di fuori limite.
Quindi assicurati che il puntatore a valori se
lo stai diminuendo, inizialmente non puntava all'inizio dell'array di valori.
Un altro esempio qui
in cui sommeremo tutti gli elementi in array, vedrai
che abbiamo una funzione di somma di array
e la funzione accetta un array
e prende anche un numero intero costante come parametri.
All'interno della funzione creeremo un numero intero.
Inizializzeremo quella somma intera a 0 e creeremo un puntatore intero, un
puntatore a di tipo int.
Creeremo anche un puntatore
costante.
Quindi questo significa che non puoi cambiarne l'indirizzo.
Sarà sempre array più n e sarà chiamato array end.
Lo stiamo facendo perché rende il nostro ciclo più efficiente se lo
impostiamo per andare alla fine dell'array e guardiamo solo il puntatore.
Quindi la fine dell'array punta all'indirizzo della fine dell'array.
Possiamo dire array, che è ciò che è passato e quindi n è
la dimensione,
la dimensione dell'array.
Ora il ciclo for inizializzerà il puntatore della variabile di controllo del
ciclo, che è un puntatore all'array. E tutto quello che devi fare
è se vuoi assegnare un puntatore al primo elemento di un array, tutto quello che devi
fare è dire pointer è uguale a array.
E poi la nostra condizione di uscita dal ciclo è se il puntatore è inferiore alla fine dell'array.
Ricorda, un puntatore è un indirizzo e anche l'estremità dell'array è un indirizzo.
Quindi stiamo dicendo che se l'indirizzo al puntatore è minore del puntatore n,
allora vogliamo eseguire il corpo del ciclo.
Il puntatore è solo un numero intero, è un indirizzo esadecimale.
Ogni volta che incrementiamo, va all'indirizzo successivo. Abbiamo l'indirizzo finale, quindi possiamo dire
di seguire il ciclo finché non arriviamo alla fine.
E poi stiamo incrementando il puntatore stesso, che
incrementerà l'indirizzo per andare all'elemento successivo dell'array essenzialmente perché è quello
a cui stiamo puntando.
Quindi abbiamo all'interno del corpo del nostro ciclo, diciamo somma più uguale a puntatore.
Stiamo dereferenziando il puntatore per ottenere il
valore perché ricordiamo che vogliamo ottenere il valore a cui non vogliamo
ottenere l'indirizzo del puntatore o l'indirizzo del puntatore a cui punta.
E poi, alla fine, restituiamo la somma. Quindi questo sommerà tutti
gli elementi in un array.
Noterai che nel main, abbiamo anche fatto una dichiarazione della funzione al
suo interno invece che all'inizio del file. Di solito mi piace metterli all'inizio del file.
Ma principalmente, creiamo un array di 10 elementi, 3 7 negativo 9 e così via.
Quindi passiamo l'array o una somma e specifichiamo
la dimensione come 10.
E quello che noterai è che restituisce il valore che è la somma dell'array.
Quindi è molto, molto bello usare questa aritmetica dei punti per iterare attraverso un
array, possiamo semplicemente
andare al prossimo indirizzo e anche guardare l'indirizzo finale per saltare fuori.
Ciò è più efficiente con il puntatore che guarda l'indirizzo finale rispetto
a un contatore che guarda a meno di n.
E noti anche che li abbiamo creati come costanti perché le costanti non cambiano
e questo è più efficiente con il compilatore.
L'array qui è un puntatore costante che significa che l'indirizzo non può cambiare.
Avresti anche dovuto notare in questo
esempio che per passare un array a una funzione, devi semplicemente specificare il nome dell'array.
Quindi sappiamo come passare al rilancio la funzione. E per produrre un puntatore a un
array, devi solo specificare il nome dell'array.
Lo abbiamo visto quando assegniamo il primo elemento dell'array a un puntatore.
Quindi ciò che ciò implica è che la chiamata alla loro funzione
di somma dell'array, ciò che è stato passato alla funzione, era in realtà un puntatore ai valori dell'array.
E questo ti sta davvero dicendo che array e puntatori sono molto, molto strettamente correlati, che
un array non è altro che un puntatore.
E questo spiega perché sei in grado di modificare gli elementi di un array dall'interno di una funzione.
Perché fino a questo punto, quando si passano i dati a una funzione, quei dati non vengono modificati al
di fuori di quella funzione a meno che non si tratti di un puntatore.
Perché è per questo che dobbiamo passare l'indirizzo per lo scanf.
L'unico modo in cui gli elementi vengono modificati al di fuori di una funzione
è se stai passando i puntatori a una funzione.
E poiché gli elementi vengono modificati all'interno di quella funzione, ciò
implica che stai passando un puntatore.
E questo sta solo dimostrando che quando
matrici e puntatori sono molto, molto simili in quanto matrici sono effettivamente puntatori che usano
solo una sintassi diversa.
Parleremo di come possiamo passare per riferimento o davvero passare una copia di
un riferimento, che ti consentirà di modificare
i dati in una funzione al di fuori di quella funzione.
Se ricordi da una delle nostre precedenti sfide,
ogni volta che volevamo modificare i dati in una funzione, dovevamo
usare una variabile globale.
Perché non abbiamo capito il concetto di
passaggio per riferimento e non abbiamo capito il concetto di puntatori.
Ma ho anche menzionato prima uno dei vantaggi dei puntatori è che
ora puoi modificare i dati all'interno di una funzione e verranno riflessi al di fuori di quella funzione.
Ma questa è un'altra lezione.
Ma quel concetto in sé a causa dell'esempio precedente sta dimostrando come
gli array siano essenzialmente puntatori.
Quindi potresti chiederti perché il parametro formale all'interno della funzione non è dichiarato come un puntatore.
Beh, potrebbe essere. Potremmo semplicemente fare qualcosa del genere, int array sum, int star array.
Non è necessario dichiararlo come array.
È perfettamente valido perché array e puntatori sono gli stessi che possiamo dire int star array.
Abbiamo detto che sono molto strettamente correlati.
Quindi puoi dichiarare un tipo di array come un tipo di array di
int all'interno della funzione di somma dell'array oppure puoi dichiararlo come un puntatore a int.
Ed è per questo che vedi molte funzioni che accettano array come parametri o
come argomenti in cui i parametri sono effettivamente puntatori.
Quindi, se utilizzerai i numeri di indice per fare riferimento agli elementi di un array passato
a una funzione, dichiara il parametro come array.
Ancora una volta la comodità della notazione, è solo un
modo diverso di notazione, usando le parentesi e il pedice o usando un puntatore.
L'array stesso è solitamente più facile da leggere
in termini di manutenzione del programma, riflette più correttamente l'uso dell'array da parte della funzione.
Ma il puntatore è più facile da usare.
E se stai usando un argomento come puntatore all'array, dichiaralo come puntatore di
tipo nel parametro formale.
Quindi ecco un esempio con la notazione del puntatore della funzione
in cui l'esempio precedente utilizzava una notazione di matrice.
Qui diciamo solo int start array
e quello che noterai è che la funzione diventa immediatamente
molto più piccola, perché non dobbiamo assegnare il puntatore all'array al primo
elemento come abbiamo fatto.
Il ciclo diventa anche molto più piccolo perché non
è necessario eseguire quell'assegnazione nella prima istruzione.
Possiamo solo dire fino a quando l'array è inferiore alla fine dell'array
e possiamo incrementare l'array. Quindi è un po 'meno
codice, è ancora molto chiaro cosa sta succedendo, si spera, se si capiscono array e puntatori.
Stiamo passando in int star array
e non dobbiamo più inizializzare quell'array perché lo stiamo passando
nel puntatore, non inizializziamo più il puntatore.
E poi stiamo effettivamente impostando l'indirizzo della fine dell'array
su un puntatore costante,
array end. Lo usiamo per
saltare fuori dal ciclo e diciamo semplicemente somma più uguale
a stella array, usando l'operatore di riferimento indiretto per dereferenziare nuovamente l'array, restituendo la somma.
E poi la funzione principale è esattamente la stessa tranne che la dichiarazione è ora un puntatore anziché un array.
Quindi ecco 2 esempi che utilizzano notazioni diverse ma forniscono la stessa funzionalità ed
è per questo che vedi molti puntatori come parametri all'interno di
un parametro di funzione.
Quindi, per riassumere, ecco alcune cose che sono valide quando usi i puntatori
e cose che non lo sono.
Quindi, se dichiariamo alcune variabili qui, dichiariamo un array chiamato gain e
contiene 3 elementi e quindi dichiariamo 2 puntatori.
Ora su questi suggerimenti, possiamo fare aritmetica. Possiamo dire pointer one plus plus.
Possiamo dire punto o 2 è uguale a punto o uno più 2.
Possiamo anche dire che il puntatore 2 equivale a guadagnare più uno.
È perfettamente valido farlo perché hai puntatori e stai modificando i puntatori in base
all'indirizzo, quindi puoi fare aritmetica dei punti.
Non puoi eseguire operazioni aritmetiche sui punti sugli array. Quindi non puoi dire guadagna più plus.
Non puoi dire il puntatore 2 0. 2 più 0. 1
perché quelli sono indirizzi.
E in realtà non stai indicando nulla
all'interno di un array.
E non puoi moltiplicare per guadagnare punti o uno per ottenere punti o 2.
Quelle non sono valide.
Quindi fai attenzione alla sintassi corretta per l'aritmetica dei puntatori e
comprendi anche che l'aritmetica dei punti può essere applicata solo ai puntatori, non
agli array.
Anche le funzioni che elaborano gli array utilizzano effettivamente i puntatori come argomenti.
È possibile scegliere tra la notazione dell'array e la notazione del puntatore per la
scrittura delle funzioni di elaborazione dell'array.
Quindi, se hai intenzione di elaborare la funzione casuale, è perfettamente corretto utilizzare un puntatore come parametro.
Puoi scegliere quale utilizzare.
Ma l'uso dei puntatori di solito è meno codice ed è più efficiente.
L'uso della notazione di array rende più ovvio che la funzione sta lavorando con gli
array e la notazione di array ha un aspetto più familiare ai programmatori che
hanno un background di programmazione in determinati linguaggi.
Quindi se programmi prima e Fortran e Pascal e così via,
puoi usare la notazione a freccia.
Altri programmatori potrebbero essere più abituati a lavorare con i puntatori e potrebbero trovare la
notazione del puntatore più naturale, semplicemente ha più senso.
È più vicino al linguaggio macchina usando l'aritmetica dei punti
e la notazione del puntatore con alcuni compilatori porta a un codice più efficiente, un
altro motivo per usarlo.
Quindi diamo un'occhiata a questi esempi all'interno di blocchi
di codice.
Quindi ecco il nostro esempio dalle diapositive. Abbiamo la nostra dichiarazione di funzione sulla riga 3.
È una somma di array.
E in questo esempio, useremo la notazione di matrice.
Quindi useremo le parentesi quando useremo gli indici.
E lo chiameremo passando l'array
dei valori e passando la dimensione.
Quindi la funzione di somma dell'array accetta un array intero. Bene, la prima cosa che devi fare
è creare il puntatore che vuoi usare per l'aritmetica dei
punti sulla linea 14. E poi devi assegnare la
fine dell'array all'array degli indirizzi più la dimensione.
Questa è la fine dell'array, che ora puoi usare per uscire dal ciclo.
Ma dobbiamo assegnare il puntatore all'array.
Sappiamo che possiamo assegnare array a puntatori in
modo che puntino al primo elemento semplicemente usando il nome dell'array.
Non dobbiamo usare l'indirizzo dell'agente.
Potremmo, se volessimo, potremmo effettivamente fare qualcosa del genere.
E va bene anche questo.
E poi abbiamo più più il puntatore. Stiamo incrementando il puntatore perché tutto
ciò che sta facendo viene incrementato all'indirizzo successivo. Punta al prossimo elemento dell'array.
E poi sulla riga 18, stiamo dereferenziando il puntatore per calcolare la somma,
somma uguale, somma più il valore del puntatore a cui punta.
Quindi, se lo costruiamo, abbiamo un avviso, che è main non
è un int, vogliamo cambiarlo perché è bene
restituire i valori di errore dal main e
dire solo return 0.
Potresti tornare se ci fosse un errore in
main, ne restituisci uno negativo. Ora che eseguiamo questo, vedrai che esegue solo la somma dei
valori nell'array, che è 3 più 7 più 9 negativo e così via, non è nemmeno
sicuro di cosa sia ma sembra che sia 21.
Ora possiamo facilmente modificare questo parametro dell'array per
prendere un puntatore semplicemente dichiarando l'asterisco prima del puntatore.
Lo chiamiamo allo stesso modo. Ci limitiamo a modificare. Non è più necessario
dichiarare il puntatore. Probabilmente vogliamo cambiare il
nome per renderlo più semplice, ma non abbiamo più bisogno di dichiarare questo puntatore.
Vogliamo ancora ottenere la fine dell'array e non
abbiamo più bisogno di assegnarlo più.
Possiamo solo avere una cosa vuota lì. E potrebbe effettivamente essere più utile avere un ciclo while qui.
Ma se non abbiamo alcun compito possiamo semplicemente mettere lì il punto e virgola.
E adesso siamo a posto. Vogliamo ancora de-referenziarlo e vogliamo ancora restituirlo.
Ma se
lo costruiamo, vogliamo assicurarci
di definire la dichiarazione della funzione come un puntatore poiché l'abbiamo modificata.
E questo può essere qualsiasi nome, ma saremo coerenti.
Ora che costruiamo,
vogliamo assicurarci di utilizzare nuovamente tutte le
variabili che abbiamo modificato.
Quindi ora che abbiamo costruito con successo lo eseguiamo e vedi che
ottieni lo stesso risultato che è 21.
Quindi, comprendi questa differenza tra l'utilizzo dei puntatori come parametri formali negli
array,
puoi usarli in modo intercambiabile. È solo una comodità notazionale.
Ma di solito hai meno codice, quando usi un puntatore.
E puoi manipolarlo di più e puoi fare cose più potenti, di solito
è anche più efficiente in base al compilatore. Grazie.