>> [RIPRODUZIONE DI BRANI MUSICALI]
>> DOUG LLOYD: puntatori, eccoci qui.
Questo è probabilmente andando a essere l'argomento più difficile
che si parla in CS50.
E se avete letto nulla di puntatori
prima si potrebbe essere un po ' intimidatorio andando in questo video.
E 'vero i puntatori Sei consentire la possibilità
a vite forse fino piuttosto male quando sei
lavorare con variabili e dati, e causando il crash del programma.
Ma sono in realtà davvero utile e ci ha davvero un ottimo modo permettono
per passare i dati avanti e indietro tra le funzioni,
che siamo comunque in grado di fare.
>> E così ciò che realmente vuole fare qui è il treno
di avere un buon indicatore disciplina, così che è possibile utilizzare in modo efficace i puntatori
per rendere i vostri programmi che molto meglio.
Come ho detto puntatori ci danno un diverso modo per passare i dati tra le funzioni.
Ora, se vi ricordate da un video di prima, quando
stavamo parlando portata variabile, ho detto
che tutti i dati che si passa tra funzioni in C sono passati per valore.
E io non ho usato che termine, quello che volevo dire lì
era che stiamo passando copie di dati.
Quando si passa una variabile a una funzione, non stiamo realmente passando la variabile
alla funzione, giusto?
Stiamo passando una copia che i dati alla funzione.
La funzione fa quello che vuole e calcola un valore,
e forse usiamo quel valore quando dà indietro.
>> C'era una sola eccezione a questa regola di passaggio per valore,
e torneremo a quello che è un po 'più avanti in questo video.
Se usiamo puntatori invece di utilizzo di variabili,
o invece di utilizzare le variabili stessi o copie delle variabili,
ora siamo in grado di passare le variabili intorno tra le funzioni in un modo diverso.
Ciò significa che se facciamo un cambiamento in una funzione,
che il cambiamento avrà effettivamente effettuare in una funzione diversa.
Di nuovo, questo è qualcosa che non abbiamo potuto fare in precedenza,
e se avete mai provato a scambiare il valore delle due variabili in una funzione,
hai notato questo problema sorta di strisciante, giusto?
>> Se vogliamo scambiare X e Y, e passarli a una funzione chiamata di swap,
all'interno della funzione scambiare la variabili fanno valori di scambio.
Si diventa due, due diventa uno, ma non lo facciamo davvero
cambiare nulla in originale funzione, con il chiamante.
Perché non possiamo, siamo solo lavorare con copie di essi.
Con i puntatori, però, possiamo in realtà passare X e Y di una funzione.
Tale funzione può fare qualcosa con loro.
E quei valori variabili può effettivamente cambiare.
Ecco, questo è un bel cambiamento di la nostra capacità di lavorare con i dati.
>> Prima di tuffarsi in puntatori, penso che valga la pena
prendendo pochi minuti tornare alle origini qui.
E dare un'occhiata a come lavori di memoria per computer
perché questi due soggetti sono in corso di essere in realtà piuttosto interconnessi.
Come probabilmente sapete, sul vostro sistema informatico
si dispone di un disco rigido o forse un disco a stato solido,
una sorta di percorso di archiviazione di file.
Di solito è in qualche parte del quartiere di 250 gigabyte
per forse un paio di terabyte ora.
Ed è dove tutti i tuoi file in ultima analisi dal vivo,
anche quando il computer è spento disattivata, è possibile riattivarla
e troverete i file sono lì di nuovo quando si riavvia il sistema.
Ma le unità disco, come un disco rigido, un HDD o un disco a stato solido, un SSD,
sono solo lo spazio di archiviazione.
>> Non possiamo effettivamente fare nulla con i dati che sono in hard disk,
o in un disco a stato solido.
Per cambiare effettivamente dati o spostarla,
dobbiamo spostarlo RAM, memoria ad accesso casuale.
Ora RAM, hai un sacco meno di un computer.
Si può avere da qualche parte nel quartiere di 512 megabyte
se si dispone di un vecchio computer, a forse due, quattro, otto, 16,
forse anche un po ' di più, gigabyte di RAM.
Ecco, questo è molto più piccolo, ma questo è dove tutti i dati volatili esiste.
Ecco dove siamo in grado di cambiare le cose.
Ma quando ci rivolgiamo il nostro computer spento, tutti i dati nella RAM viene distrutto.
>> Ecco perché abbiamo bisogno di hard disk per la posizione più permanente di esso,
in modo che exists- sarebbe essere davvero male se ogni volta che
trasformato il nostro computer spento, ogni il file nel nostro sistema è stato cancellato.
Quindi lavoriamo all'interno di RAM.
E ogni volta che stiamo parlando di la memoria, più o meno, a CS50,
stiamo parlando di RAM, disco rigido non.
>> Così, quando ci muoviamo le cose in memoria, occupa un certo spazio.
Tutti i tipi di dati abbiamo lavorato con
prendere diverso quantità di spazio nella RAM.
Così ogni volta che si crea un intero variabili, quattro byte di memoria
sono accantonati in RAM in modo da può lavorare con quello intero.
È possibile dichiarare il numero intero, cambiarlo, assegnarla
ad un valore 10 incrementato per uno, così via e così via.
Tutto ciò che deve accadere in RAM, e si ottiene quattro byte
lavorare per ogni numero intero che si crea.
>> Ogni personaggio si creare ottiene un byte.
Questo è solo la quantità di spazio necessaria per memorizzare un carattere.
Ogni galleggiante, un vero e proprio numero, ottiene quattro byte
a meno che non si tratta di un doppio virgola mobile di precisione
numero, che consente di avere cifre più precise o più
dopo la virgola senza perdere di precisione,
che prendono otto byte di memoria.
Anela lunghe, davvero grande interi, anche prendere otto byte di memoria.
Quanti byte di memoria si stringhe occupano?
Beh diciamo mettere uno spillo a questa domanda per ora, ma torneremo ad esso.
>> Ma torniamo a questa idea della memoria come una grande matrice di celle byte dimensioni.
Questo è davvero tutto ciò che è, è solo una vasta gamma di celle,
proprio come qualsiasi altro array si ha familiarità con e vedere,
salvo ogni elemento è largo un byte.
E proprio come un array, ogni elemento ha un indirizzo.
Ogni elemento di un array ha un indice, e
può utilizzare tale indice per fare cosiddetto accesso casuale sull'array.
Non abbiamo iniziare a l'inizio della matrice,
scorrere ogni unico elemento della stessa,
per trovare quello che stiamo cercando.
Possiamo solo dire, voglio arrivare al 15 ° elemento o l'elemento 100.
E si può solo passare a quel numero e ottenere il valore che stai cercando.
>> Allo stesso modo ogni posizione nella memoria ha un indirizzo.
Così la memoria potrebbe simile a questo.
Ecco un piccolo pezzo di memoria, questo è di 20 byte di memoria.
I primi 20 byte perché il mio affronta lì in fondo
sono 0, 1, 2, 3, e così su tutto il percorso fino a 19.
E quando mi dichiaro variabili e quando inizio a lavorare con loro,
il sistema sta per impostare a parte un pò di spazio per me
in questa memoria di lavoro con le mie variabili.
Quindi potrei dire, char c è uguale a capitale H. E che cosa succederà?
Beh, il sistema sta andando a mettere da parte per me un byte.
In questo caso ha scelto il numero di byte quattro, il byte all'indirizzo quattro,
e sta andando a memorizzare il lettera H maiuscola in là per me.
Se allora io dico velocità int limite uguale 65, è
andando a mettere da parte quattro byte di memoria per me.
E sta andando a trattare quelli quattro byte come una singola unità
perché ciò che stiamo lavorando con è un intero qui.
E sta andando a memorizzare 65 in là.
>> Ora già Sono un po ' che ti dice un po 'di una bugia,
a destra, perché sappiamo che computer lavorano in binario.
Non capiscono necessariamente quello che un capitale H è
o quello che un 65 è, ma solo capire binari, zero e uno.
E così in realtà ciò che stiamo memorizzazione in là
non è la lettera H e il numero 65, ma piuttosto la rappresentazione binaria
dello stesso, che guarda un po 'di qualcosa di simile.
Ed in particolare nel contesto della variabile intera,
non sta andando a sputare solo in, non sta andando a trattarlo come un quattro
Byte pezzo necessariamente, in realtà è in corso
di trattarlo come un quattro blocchi di byte, che potrebbe essere simile a questa.
E anche questo non è tutto vero o,
a causa di qualcosa chiamato un endianness, che non siamo
intenzione di entrare in ora, ma se siete curiosi di sapere,
si può leggere su poco e grande endianness.
Ma per il bene di questo argomento, per il bene di questo video,
facciamo solo supporre che è, in Infatti, come il numero 65 sarebbe
essere rappresentato in memoria su ogni sistema,
anche se non è del tutto vero.
>> Ma andiamo in realtà solo get liberarsi di tutti binario del tutto,
e basta pensare a come H e 65, è molto più facile
a pensarci come che come un essere umano.
Va bene, così sembra anche forse un poco casuali che I've- mio sistema
non mi ha dato byte 5, 6, 7, e 8 per memorizzare il numero intero.
C'è una ragione per questo, anche, che non otterremo in questo momento, ma è sufficiente
per dire che ciò che la computer sta facendo qui
è probabilmente una buona mossa da parte sua.
Per non mi danno la memoria che è necessariamente back to back.
Anche se è intenzione di farlo ora se voglio ottenere un'altra stringa,
Chiamai il cognome, e voglio mettere Lloyd in là.
Ho intenzione di bisogno di montare uno carattere, ogni lettera che è
andare a richiedere un carattere, un byte di memoria.
Quindi, se ho potuto mettere Lloyd nella mia matrice come questo sono abbastanza bravo per andare, giusto?
Cosa manca?
>> Ricordate che ogni corda lavoriamo con in C termina con backslash pari a zero,
e non possiamo omettere che qui, sia.
Abbiamo bisogno di mettere da parte un byte di memoria per contenere che così noi
sapere quando la nostra stringa è terminato.
Quindi, di nuovo questa disposizione di come le cose
comparire in memoria potrebbe essere un po 'casuale,
ma in realtà è come la maggior parte dei sistemi sono progettati.
Per allinearli su multipli di quattro, per ragioni di nuovo
che non abbiamo bisogno di entrare in questo momento.
Ma questo, quindi basti dire che dopo queste tre righe di codice,
questo è ciò che la memoria potrebbe essere simile.
Se ho bisogno di locazioni di memoria 4, 8, e 12 per tenere i miei dati,
questo è ciò che la mia memoria potrebbe essere simile.
>> E proprio essere particolarmente pedante qui, quando
stiamo parlando di memoria indirizzi Noi di solito
farlo utilizzando notazioni esadecimali.
Allora perché non ci si converte tutti questi da decimale in esadecimale
proprio perché è generalmente Come ci si riferisce alla memoria.
Così, invece di essere da 0 a 19, quello che abbiamo è pari a zero
x zero a tre a zero x1.
Questi sono i 20 byte di memoria che abbiamo abbiamo o stiamo guardando in questa immagine
giusto qui.
>> Quindi, tutto ciò che viene detto, cerchiamo di allontanarsi dalla memoria per un secondo
e di nuovo a puntatori.
Qui è il più importante cosa da ricordare
, come si comincia a lavorare con i puntatori.
Un puntatore è nulla più di un indirizzo.
Io dirò di nuovo perché è così importante,
un puntatore è nulla più di un indirizzo.
I puntatori sono indirizzi alle posizioni in memoria in cui le variabili vivono.
Sapendo che diventa spera, un po 'più facile lavorare con loro.
Un'altra cosa che mi piace di fare è di avere sorta
di diagrammi che rappresentano visivamente ciò che è accadendo con varie linee di codice.
E faremo questo un paio di volte in puntatori,
e quando si parla di dinamica allocazione memoria.
Perché penso che questi diagrammi può essere particolarmente utile.
>> Quindi, se io dico, per esempio, int k nel mio codice, cosa sta succedendo?
Beh, quello che sta accadendo è fondamentalmente Sto diventando memoria riservata per me,
ma non ho neanche piace penso così, io
piace pensare a questo proposito come una scatola.
Ho una scatola ed è di colore verde perché io
può mettere interi in scatole verdi.
Se fosse un personaggio che potrebbe avere una scatola blu.
Ma io dico sempre, se sto creando una scatola che può contenere interi
quella casella è colorata di verde.
E mi prendo un pennarello indelebile e scrivo k sul lato di essa.
Così ho un box chiamato k, in cui posso mettere interi.
Quindi, quando dico int k, che è ciò che accade nella mia testa.
Se dico k è uguale a cinque, che cosa sto facendo?
Beh, sto mettendo cinque nella casella, a destra.
Questo è abbastanza semplice, se Dico int k, creare una casella denominata k.
Se dico k è uguale a 5, mettere cinque nella scatola.
Speriamo che non sia troppo di un salto.
Qui è dove le cose vanno un poco interessante però.
Se dico int * pk, bene anche se non lo faccio sa che cosa questo significa necessariamente,
è chiaramente ha qualcosa a che fare con un numero intero.
Quindi ho intenzione di colorare questo scatola verde-ish,
Lo so che ha qualcosa a che fare con un numero intero,
ma non è un numero intero sé, perché è un int stella.
C'è qualcosa di un po ' diverso su di esso.
Così coinvolto di un numero intero, ma per il resto è
non troppo diversa da cosa stavamo parlando.
Si tratta di una scatola, la sua ha una etichetta, si indossa una pk un'etichetta,
ed è capace di partecipazione Stelle INT, qualunque essi siano.
Essi hanno qualcosa a che fare con numeri interi, chiaramente.
Ecco l'ultima riga però.
Se dico pk = & k, whoa, cosa è successo, giusto?
Quindi questo numero casuale, apparentemente casuale numero, si butta nella casella di lì.
Tutto ciò che è, è pk ottiene l'indirizzo di k.
Così sto attaccando dove k vive nella memoria, il suo indirizzo, l'indirizzo della sua byte.
Tutto quello che sto facendo è che sto dicendo tale valore è quello che ho intenzione
a mettere dentro la mia scatola chiamato pk.
E perché queste cose sono puntatori, e perché guardando
in una stringa come pari a zero x otto a zero c sette quattro otto
due zero è probabilmente non molto significativo.
Quando abbiamo generalmente visualizziamo puntatori, abbiamo effettivamente facciamo come puntatori.
Pk ci dà le informazioni abbiamo bisogno di trovare k in memoria.
Quindi, fondamentalmente pk ha una freccia in esso.
E se camminiamo la lunghezza di quella freccia, immaginare
è qualcosa che si può camminare su, se si camminare lungo la lunghezza della freccia,
sulla punta estrema di quella freccia, abbiamo troverà la posizione nella memoria
dove k vive.
E questo è davvero importante perché una volta che sappiamo dove abita k,
possiamo iniziare a lavorare con i dati all'interno di tale posizione di memoria.
Anche se stiamo ottenendo un teeny bit avanti di noi stessi, per ora.
>> Così che cosa è un puntatore?
Un puntatore è un elemento di dati il ​​cui valore è un indirizzo di memoria.
Quello era che lo zero x otto roba a zero in corso, che è stato un indirizzo di memoria.
E 'stata una locazione di memoria.
E il tipo di un puntatore descrive il tipo
dei dati troverai a quell'indirizzo di memoria.
Quindi c'è la parte destra int stella.
Se seguo quella freccia, è andando a mi portano a una posizione.
E quella posizione, quello che ho troveranno lì nel mio esempio,
è una scatola di colore verde.
Si tratta di un numero intero, questo è quello che troveranno se vado a tale indirizzo.
Il tipo di dati di un puntatore descrive cosa
troverete a questo indirizzo di memoria.
Quindi, ecco la cosa veramente interessante comunque.
Puntatori ci permettono di passare variabili tra funzioni.
E in realtà passare variabili e non passare copie di essi.
Perché se sappiamo esattamente dove in memoria per trovare una variabile,
non abbiamo bisogno di fare una copia di esso, possiamo solo andare in quella posizione
e lavorare con quella variabile.
Quindi, in puntatori essenza sorta di rendere un ambiente informatico
molto più simile al mondo reale, a destra.
>> Quindi, ecco un'analogia.
Diciamo che ho un quaderno, a destra, ed è pieno di note.
E mi piacerebbe che aggiorna.
Tu sei una funzione che aggiorna le note, a destra.
Nel modo in cui siamo stati lavorando finora, cosa
succede è si prende il mio notebook, andrai al negozio di copia,
potrai fare una copia di Xerox ogni pagina del notebook.
Lascerai mio notebook schiena sulla mia scrivania quando hai finito,
andrai e attraversare le cose nella mia notebook che non sono aggiornati o sbagliato,
e poi si passa di nuovo a me la pila di pagine Xerox
che è una replica del mio notebook con le modifiche apportate ad esso.
E a quel punto, tocca a me come la funzione di chiamata, come il chiamante,
a decidere di prendere le note e integrarli di nuovo nel mio taccuino.
Quindi c'è un sacco di passi questione qui, a destra.
Come non sarebbe meglio se mi limito a dire, ehi, si può
aggiornare il mio notebook per me, consegno il mio notebook,
e si prendono le cose e letteralmente barrare
e aggiornare i miei appunti sul mio taccuino.
E poi mi danno il mio notebook schiena.
Questo è il genere di cosa puntatori consentono di fare,
rendono questo ambiente un sacco più simile a come operiamo nella realtà.
>> Va bene così questo è quello che un puntatore si, parliamo
di come funzionano i puntatori in C, e come possiamo iniziare a lavorare con loro.
Quindi c'è un semplice puntatore in C chiamata puntatore nullo.
Il puntatore punti nulli a niente.
Questo probabilmente sembra come se fosse in realtà non è una cosa molto utile,
ma come vedremo un poco più tardi, il fatto
che questo puntatore nullo esiste in realtà può davvero tornare utile.
E ogni volta che si crea un puntatore, e non si imposta il suo valore immediatamente:
un esempio di impostazione il suo valore subito
sarà un paio di scivoli indietro dove ho detto pk uguale a & k,
pk ottiene l'indirizzo di k, come vedremo che cosa significa,
vedremo come codificare che shortly- se non fissiamo il suo valore a qualcosa
significativo subito, si dovrebbe sempre
impostare il puntatore per puntare a null.
Si dovrebbe impostare per puntare a nulla.
>> Questo è molto diverso da quello lasciando solo il valore così com'è
e poi dichiarare un puntatore e solo assumendo
è nullo perché è raramente vero.
Per questo si deve sempre impostare il valore di un puntatore
null se non si imposta il suo valore a qualcosa di significativo immediatamente.
È possibile controllare se il valore di un puntatore è nullo utilizzando l'operatore di uguaglianza
(==), Proprio come si confronta qualsiasi intero valori o valori di carattere che utilizzano (==)
anche.
Si tratta di una specie particolare di costante valore che è possibile utilizzare per verificare.
Così che era un molto semplice puntatore, il puntatore nullo.
Un altro modo per creare un puntatore è quello di estrarre
l'indirizzo di una variabile hai già creato,
e si esegue questa operazione utilizzando il & Estrazione indirizzo dell'operatore.
Che abbiamo già visto in precedenza nel primo esempio di schema ho mostrato.
Quindi, se x è una variabile che abbiamo già creato di tipo intero,
allora e x è un puntatore a un numero intero.
& x è- ricordate, e sta per estrarre l'indirizzo della cosa sulla destra.
E poiché un puntatore è solo un indirizzo, di & X è un puntatore ad un intero
il cui valore è dove in memoria di x vite.
E 'l'indirizzo di x.
Così & x è l'indirizzo di x.
Prendiamo questo un passo ulteriormente e connettersi a qualcosa
Ho accennato in un video precedente.
Se arr è un array di double, poi & parentesi quadra arr i è un puntatore
in doppio.
OK.
arr parentesi quadra i, se arr è un array di doppio,
poi arr parentesi quadra i è l'elemento i-esimo di tale matrice,
e & arr parentesi quadra i è dove nel memoria l'elemento i-esimo arr esiste.
>> Allora, qual è l'implicazione qui?
Un nome array, l'implicazione di tutta questa faccenda,
è che il nome di un array è in realtà esso stesso un puntatore.
Hai lavorato con puntatori tutti lungo
ogni volta che avete usato un array.
Ricordate dall'esempio su scope delle variabili,
verso la fine del video che presento un esempio in cui abbiamo una funzione
chiamato int set e un funzione chiamata di matrice set.
E la vostra sfida di determinare o meno, o che il
valori che abbiamo stampato la fine della funzione,
alla fine del programma principale.
>> Se vi ricordate da quell'esempio o se hai guardato il video,
si sa che quando la chiamata a te- set int non fa effettivamente nulla.
Ma la chiamata per impostare matrice fa.
E io sorta di sorvolato perché che era il caso al momento.
Ho appena detto, beh è un array, è speciale, sapete, c'è una ragione.
Il motivo è che una matrice di nome è in realtà solo un puntatore,
e c'è questa speciale sintassi Parentesi quadra che
rendere le cose molto più gradevole per lavorare.
E fanno l'idea di un puntatore molto meno intimidatorio,
ed è per questo che sono specie di presentato in quel modo.
Ma in realtà gli array sono solo puntatori.
Ed è per questo che quando ci fatto un cambiamento alla matrice,
quando siamo passati un array come parametro ad una funzione o come argomento
a una funzione, il contenuto della matrice effettivamente cambiato sia il chiamato
e con il chiamante.
Che per ogni altro tipo di variabili che abbiamo visto non era il caso.
Ecco, questo è solo qualcosa da tenere a mente quando si lavora con i puntatori,
è che il nome di un matrice in realtà un puntatore
al primo elemento di tale matrice.
>> OK, ora abbiamo tutto questi fatti, cerchiamo di andare avanti, a destra.
Perché ci preoccupiamo per dove vive qualcosa.
Beh, come ho detto, è piuttosto utile sapere dove abita qualcosa
in modo da poter andare lì e di modificarlo.
Lavora con esso e in realtà avere la cosa che voi
vuole fare in tal senso prendere variabile, e non ha effetto su alcuni copia di esso.
Questo si chiama dereferencing.
Andiamo al riferimento e cambiamo il valore lì.
Quindi, se abbiamo un puntatore e si chiama pc, e che punti a un personaggio,
allora possiamo dire * * pc e pc è il nome di ciò che troveremo se andiamo
al pc indirizzo.
Che cosa troveremo c'è un personaggio e * pc è come ci si riferisce ai dati in quel
posizione.
Così potremmo dire qualcosa di simile * pc = D o qualcosa del genere,
e ciò significa che qualunque era a indirizzo di memoria del pc,
qualunque personaggio era in precedenza lì, è ora D, se diciamo * PC = D.
>> Quindi qui si va di nuovo con qualche C cose strane, a destra.
Così abbiamo visto in precedenza come * in qualche modo parte del tipo di dati,
e ora è utilizzato in un contesto leggermente diverso
per accedere ai dati in una posizione.
Lo so che è un po 'di confusione e che in realtà è parte di questo tutto
come, perché i puntatori hanno questa mitologia attorno a loro come essere così complessa,
è una specie di un problema di sintassi, onestamente.
Ma * è usato in entrambi i contesti, sia come parte del nome del tipo,
e vedremo un po ' più tardi anche qualcos'altro.
E proprio ora è il operatore dereference.
Così va al riferimento, accede ai dati
in corrispondenza della posizione del puntatore, e consente di manipolare a piacimento.
>> Ora questo è molto simile a visita il tuo vicino di casa, a destra.
Se si sa che cosa il vostro vicino di casa vive, sei
non uscire con il vostro vicino di casa.
Sai che capita di sapere dove vivono,
ma ciò non significa che, virtù di avere quella conoscenza
si interagisce con loro.
Se si vuole interagire con loro, si deve andare a casa loro,
si deve andare a dove vivono.
E una volta fatto questo, allora si può interagire
con loro proprio come si vorrebbe.
E allo stesso modo con le variabili, avete bisogno di andare al loro indirizzo
se si desidera interagire loro, non si può solo conoscere l'indirizzo.
E il modo di andare per l'indirizzo è da usare *, l'operatore dereference.
Cosa ne pensi succede se cerchiamo di risolvere il riferimento
un puntatore il cui valore è nullo?
Ricordiamo che il nulla puntatore punta a nulla.
Quindi, se si cerca di risolvere il riferimento nulla o andare ad un indirizzo nulla,
cosa pensi che succeda?
Segmentazione Beh, se avete indovinato colpa, avreste ragione.
Se si tenta di risolvere il riferimento un puntatore nullo,
si soffre una segmentazione colpa. Ma aspetta,
Non ti ho detto, che se non si sta andando
per impostare il valore della vostra puntatore a qualcosa di significativo,
si dovrebbe impostare a null?
Ho fatto e in realtà la segmentazione colpa è una specie di buon comportamento.
>> Avete mai dichiarato una variabile e non assegnato subito il suo valore?
Quindi hai appena detto int x; non fare in realtà assegnarlo a nulla
e poi in seguito nel codice, di stampare il valore di x,
non avendo ancora assegnato a nulla.
Spesso si otterrà pari a zero, ma a volte si
potrebbe ottenere un po 'di numeri casuali, e non avete idea di dove venisse.
Allo stesso modo è possibile le cose accadere con i puntatori.
Quando si dichiara un puntatore int * pk per esempio,
e non si assegna a un valore, si ottiene quattro byte per la memoria.
Qualunque siano le quattro byte di memoria di sistema può
scoprire che hanno un certo valore significativo.
E ci sarebbe stato qualcosa di già lì che
non è più necessario da un'altra la funzione, quindi basta avere
qualsiasi dato era lì.
>> Che cosa succede se si è tentato di fare dereference qualche indirizzo che non- c'erano
già byte e informazioni lì, che è ora nel tuo puntatore.
Se si tenta di risolvere il riferimento che il puntatore, si potrebbe essere pasticciano con una certa memoria
che non si intendeva a pasticciare con tutto.
E in effetti si poteva fare qualcosa di veramente devastante,
come rompere un altro programma, o rompere un'altra funzione,
o fare qualcosa di dannoso che non hai intenzione di fare a tutti.
Ed ecco perché è in realtà una buona idea
per impostare i puntatori a null se non li impostato su qualcosa di significativo.
E 'probabilmente meglio a fine della giornata per il vostro programma
crash poi per consentirle di operare qualcosa che le viti fino
un altro programma o un'altra funzione.
Questo comportamento è probabilmente ancora meno ideali che solo schiantarsi.
Ed ecco perché è in realtà una buona abitudine
per entrare in per impostare i puntatori null se non li imposta
ad un valore significativo immediatamente, un valore che si sa
e che si può tranquillamente il dereference.
>> Così torniamo ora e dare un'occhiata la sintassi generale della situazione.
Se dico int * p ;, quello che ho appena fatto?
Quello che ho fatto è questo.
Conosco il valore di p è un indirizzo perché tutti i puntatori sono solo
indirizzi.
Posso dereference p utilizzando l'operatore *.
In questo contesto qui, per lo top richiamare il * è parte del tipo.
Int * è il tipo di dati.
Ma posso dereference p utilizzando l'operatore *,
e se lo faccio, se vado a tale indirizzo, quello che posso trovare a questo indirizzo?
Troverò un numero intero.
Così int * p è fondamentalmente dicendo, p è un indirizzo.
Posso dereference p e se Lo faccio, mi troverò un intero
in tale posizione di memoria.
>> OK, ho detto che c'era un altro cosa fastidiosa con le stelle
e qui è dove che cosa fastidiosa con le stelle è.
Avete mai provato a dichiarare più variabili dello stesso tipo
sulla stessa riga di codice?
Così, per un secondo, finta che la linea, il codice che in realtà ci ho in verde
non c'è e si dice solo int x, y, z ;.
Cosa che sarebbe fare è effettivamente creare tre variabili intere per voi,
uno chiamato x, uno chiamato y, e uno chiamato z.
E 'un modo per farlo senza dover spaccare su tre linee.
>> Qui è dove ottengono stelle fastidioso di nuovo, però,
perché il * è in realtà parte sia il nome del tipo e parte
del nome della variabile.
E così, se io dico int * px, py, pz, quello che ho effettivamente ottenere è un puntatore ad un intero
chiamato px e due interi, py e pz.
E questo non è quello che è probabilmente vogliamo, che non va bene.
>> Quindi, se voglio creare più puntatori sulla stessa linea, dello stesso tipo,
e le stelle, quello che ho effettivamente bisogno a fare è dire int * pa, * pb, * pc.
Ora, avendo appena detto che e ora si dice questo,
probabilmente non potrà mai farlo.
Ed è probabilmente una buona cosa onestamente, perché si potrebbe inavvertitamente
omettere una stella, una cosa del genere.
E 'probabilmente meglio a dichiarare forse indicazioni su singole linee,
ma è solo un altro uno di quelli sintassi fastidiosi
le cose con le stelle che fanno puntatori così difficile lavorare con.
Perché è proprio questo sintattico pasticcio si deve lavorare.
Con la pratica si fa davvero diventare una seconda natura.
Ho ancora fare errori con ancora dopo la programmazione per 10 anni,
in modo da non essere turbato se succede qualcosa per te, abbastanza comune onestamente.
E 'davvero tipo di un difetto della sintassi.
>> OK così io il genere di promisi che avremmo rivisitare
il concetto di quanto grande è una stringa.
Beh, se vi dicessi che un stringa, abbiamo davvero tipo di
mentito a voi per tutto il tempo.
Non c'è nessun tipo di dati denominato stringa, e infatti io
menzionato questo in uno dei nostri Video prime sui tipi di dati,
tale stringa è un tipo di dati è stato creato per voi in CS50.h.
Dovete #include CS50.h al fine di utilizzarlo.
>> Beh stringa è in realtà solo un alias per qualcosa
chiamato char *, un puntatore a un carattere.
Beh puntatori, richiamo, sono solo gli indirizzi.
Allora, qual è la dimensione in byte di una stringa?
Beh, è ​​di quattro o otto.
E la ragione dico quattro o otto è perché in realtà
dipende dal sistema, Se stai usando CS50 ide, char * è la dimensione di un char
* È di otto, si tratta di un sistema a 64 bit.
Ogni indirizzo in memoria è di 64 bit.
Se stai usando apparecchio CS50 o utilizzando una macchina a 32 bit,
e avete sentito questo termine a 32 bit la macchina, che cosa è una macchina a 32 bit?
Beh, significa solo che ogni indirizzo in memoria è lungo 32 bit.
E così 32 bit è di quattro byte.
Quindi un char * è di quattro o otto byte a seconda del sistema.
E infatti qualsiasi tipo di dati, e un puntatore a qualsiasi dato
tipo, poiché tutti i puntatori sono solo indirizzi, sono quattro o otto byte.
Quindi cerchiamo di rivisitare questo Diagramma e cerchiamo di concludere
questo video con un po 'di esercizio qui.
Quindi, ecco lo schema abbiamo lasciato con proprio all'inizio del video.
Che cosa succede ora se dico * pk = 35?
Che cosa significa quando dico, * pk = 35?
Prendete un secondo.
* pk.
Nel contesto qui, è * operatore dereference.
Così, quando il dereference operatore viene utilizzato,
andiamo all'indirizzo puntato da PK, e cambiamo ciò che troviamo.
Così * pk = 35 in modo efficace fa questo per l'immagine.
Quindi è fondamentalmente sintatticamente identico al di aver detto k = 35.
>> Uno di più.
Se dico int m, creo una nuova variabile chiamata m.
Una nuova scatola, è una scatola verde perché è andare a tenere un intero,
e è etichettato m.
Se dico m = 4, ho messo un intero in quella scatola.
Se diciamo pk = & m, come fa questo cambiamento schema?
Pk = & m, non ti ricordi quello che il Operatore & fa o si chiama?
Ricorda che e qualche nome di variabile è l'indirizzo di un nome di variabile.
Quindi quello che stiamo dicendo è pk ottiene l'indirizzo di m.
E così efficacemente che cosa succede la diagramma è che pk punti non è più
k, ma punta a m.
>> Ancora puntatori sono molto difficile da lavorare con
e prendono un sacco di pratica, ma perché
della loro capacità di consentire per passare i dati tra le funzioni
e in realtà hanno quelli modifiche hanno effetto,
ottenere la vostra testa intorno è veramente importante.
Probabilmente è il più complicato argomento discutiamo in CS50,
ma il valore che si ottenere da usando puntatori
supera di gran lunga le complicazioni che provengono da loro apprendimento.
Quindi vi auguro buona fortuna conoscere i puntatori.
Sono Doug Lloyd, questo è CS50.