[RIPRODUZIONE DI BRANI MUSICALI] DOUG LLOYD: OK così un suggerimento prima di iniziare qui. Se non avete visto il video su Puntatori si potrebbe desiderare di farlo prima. Poiché il video è un altro modo di lavorare con i puntatori. Così sta andando a parlare su alcuni concetti che copriamo nella puntatori video, e siamo andando a sorvolare su di loro ora, partendo dal presupposto che sono già sorta di intesa. Ecco, questo è solo il tuo avvertimento fiera che se stai vedendo questo video e non avete visto la Video puntatori, potrebbe sorta di volare sopra la testa un po '. E così potrebbe essere migliore a guardarlo in questo ordine. Così abbiamo già visto uno modo di lavorare con i puntatori, che è dichiariamo un variabili, e quindi noi dichiarare un'altra variabile, un puntatore variabile, che punta ad esso. Per questo abbiamo creato una variabile con un nome, abbiamo creato una seconda variabile con un nome, e si segnala che seconda variabile a quella prima. Questo tipo di ha un problema, però, perché ci impone di sapere esattamente la quantità di memoria che siamo andando ad avere bisogno del momento il nostro programma è compilato. Come mai? Perché abbiamo bisogno di essere in grado di nominare o identificare tutte le possibili variabili che possiamo incontrare. Potremmo avere una matrice che potrebbe essere in grado di contenere un sacco di informazioni, ma non è ancora esattamente abbastanza preciso. Che cosa succede se non lo sappiamo, E se non abbiamo idea quanto avremo bisogno durante la compilazione? O se il nostro programma sarà correre per un tempo molto lungo, accettando varie utente i dati, e non possiamo davvero stimare se siamo andando a bisogno di 1.000 unità? Non è che possiamo dire dalla riga di comando inserire il numero di elementi si pensi hai bisogno. Beh, cosa succede se questo ipotesi è sbagliato? Allocazione dinamica della memoria sorta di ci permette la via per ovviare a questo particolare problema. E il modo lo fa è quello di utilizzare i puntatori. Possiamo usare i puntatori a ottenere l'accesso a dinamicamente memoria allocata, memoria che è assegnato come programma è in esecuzione. Non è allocata in fase di compilazione. Quando si allocare dinamicamente memoria proviene da un pool di memoria noto come cumulo. In precedenza tutta la memoria che abbiamo lavorato con in corso è stato provenienti da un pool della memoria noto come stack. Un buon modo per genere tenere in regola mind-- e questo non regge sempre vero, ma praticamente quasi tiene sempre true-- è che qualsiasi volta che si dà un nome di variabile che probabilmente vive nello stack. E ogni volta che non lo fanno dare una variabile un nome, che si può fare con la memoria dinamica assegnazione, vive sul mucchio. Ora sto tipo di presentare questo come se ci sono questi due piscine della memoria. Ma potreste aver visto questo diagramma, che è generalmente una rappresentazione di ciò che la memoria sembra, e non stiamo andando a prendersi cura di tutto la roba in alto e in basso. Quello che ci interessa è questo in parte Al centro qui, heap e stack. Come si può vedere da guardando questo diagramma, questi in realtà non sono due piscine separate della memoria. E 'una piscina in comune della memoria dove si inizia, in questa visuale si avvia in basso e iniziare a riempire dal basso con la pila, e avviare in alto e iniziare a riempire dall'alto verso il basso con il mucchio. Ma è davvero la stesso pool, è solo punti diversi, luoghi diversi in memoria che vengono assegnati. E si può esaurire memoria o avere mucchio andare fino in fondo verso il basso, o hanno lo stack andare fino alla cima, o aventi mucchio e lo stack soddisfare una contro l'altra. Tutti questi possono essere condizioni che causano il vostro programma a corto di memoria. Modo da tenere a mente. Quando si parla di l'heap e stack stiamo davvero parlando della stesso pezzo di memoria generale, solo diverse porzioni di quella memoria. Quindi, come possiamo ottenere in modo dinamico memoria allocata in primo luogo? Come fa il nostro programma di arrivare memoria, come è in esecuzione? Beh C offre una funzione chiamata malloc, allocatore di memoria, che si effettua una chiamata a, e si passa quanti byte di memoria che si desidera. Così, se il programma è in esecuzione e si desidera un runtime intero, si potrebbe Mallock quattro byte memoria, malloc parentesi quattro. Mallock passerà attraverso guardando attraverso il mucchio, perché siamo in modo dinamico l'allocazione della memoria, e tornerà a voi un puntatore a tale memoria. Esso non ti dà che memory-- non dà un nome, ti dà un puntatore ad esso. Ed è per questo che ancora una volta ho detto che è importante forse hanno guardato il video puntatori prima di arrivare troppo lontano in questo. Così malloc sta andando a dare indietro un puntatore. Se Mallock non è possibile dare alcuna memoria perché si è a corto, ti do indietro un puntatore nullo. Ti ricordi cosa succede se cercare di dereference un puntatore nullo? Soffriamo un guasto seg, giusto? Che probabilmente non è buono. Così ogni volta che si effettua una chiamata a malloc voi sempre, sempre bisogno di controllare se il puntatore ha dato voi è indietro nulla. Se lo è, è necessario terminare il vostro programma perché se si cerca di risolvere il riferimento il puntatore nullo si sta andando a soffrire un errore di segmentazione e il vostro programma è andare a sbattere comunque. Quindi, come possiamo staticamente ottenere un intero? int x. Probabilmente abbiamo fatto che un sacco di volte, giusto? Questo crea una variabile chiamata x che vive in pila. Come possiamo ottenere dinamicamente un intero? Int stella px uguale malloc 4. O, più appropriatamente diremmo int stelle px uguale formato malloc di int, solo per gettare un po 'meno numeri magici intorno al nostro programma. Questo sta per ottenerci quattro byte di memoria dal mucchio, e il puntatore otteniamo di nuovo esso è chiamato px. E poi basta, come abbiamo fatto in precedenza abbiamo possono dereference px a accedere a tale memoria. Come possiamo ottenere un numero intero da parte dell'utente? Possiamo dire int x è uguale a ottenere int. Questo è abbastanza semplice. Che cosa succede se si vuole creare un array di x galleggianti che vivono nello stack? galleggiare stack_array-- questo è il nome dei nostri array-- parentesi quadre x. Che creerà per noi un array di x galleggianti che vivono in pila. Siamo in grado di creare un array di carri allegorici che vive sul mucchio, anche. La sintassi potrebbe sembrare un poco più ingombrante, ma possiamo dire galleggiante stella heap_array uguale malloc x volte la dimensione del galleggiante. Ho bisogno di spazio sufficiente per contenere x valori in virgola mobile. Così dico ho bisogno di 100 galleggianti, o 1.000 carri allegorici. Quindi, in questo caso sarebbe 400 byte per 100 carri allegorici, o 4.000 byte per 1.000 carri allegorici, perché ogni galleggiante occupa quattro byte di spazio. Dopo aver fatto questo posso usare il sintassi parentesi quadra su heap_array. Proprio come farebbe su stack_array, io può accedere ai suoi elementi singolarmente utilizzando heap_array zero, uno heap_array. Ma ricordare la ragione possiamo farlo è perché il nome di un array in C è davvero un puntatore primo elemento di quella matrice. Quindi il fatto che stiamo dichiarando una gamma di carri sullo stack qui è in realtà un po 'fuorviante. Siamo davvero in seconda riga di codice lì creando anche un puntatore a un pezzo di memoria che allora facciamo un po 'di lavoro con. Ecco il grande problema con allocata dinamicamente la memoria, però, ed è per questo che è davvero importante sviluppare alcune buone abitudini quando si lavora con esso. A differenza staticamente dichiarato la memoria, la memoria Non viene restituito automaticamente sistema quando la funzione è fatto. Quindi, se abbiamo principale, e principale chiama una funzione f, quando f finiture qualunque cosa sta facendo e restituisce il controllo del programma torna alla principale, tutta la memoria che f utilizzata viene restituita. Può essere riutilizzato da qualche altro programma, o qualche altra funzione che viene chiamato in seguito in principale. Si può usare quella stessa memoria di nuovo. Se dinamicamente allocare la memoria se dovete dire esplicitamente il sistema che hai finito con esso. Sarà tenere su di esso per voi, che potrebbe portare a un problema di voi esaurirsi della memoria. E infatti a volte ci riferiamo a questo come una perdita di memoria. E a volte queste perdite di memoria può effettivamente essere davvero devastante per le prestazioni del sistema. Se sei un utente internet frequente si potrebbe utilizzare alcuni browser web, e non voglio fare nomi qui, ma ci sono alcuni browser web là fuori che sono noti per avere effettivamente perdite di memoria che non vengono risolti. E se si lascia il browser aperto per un lungo periodo di tempo, giorni e giorni, o settimane, a volte potrebbe notare che il sistema è in esecuzione molto, molto lentamente. E la ragione di ciò è che il browser ha stanziato la memoria, ma poi non ha detto il sistema che è fatto con esso. E in modo che lascia meno memoria a disposizione di tutti gli altri programmi di dover condividere, perché sei leaking-- che il browser web il programma perde la memoria. Come facciamo a dare memoria indietro quando avremo finito con esso? Beh per fortuna si tratta di un modo molto semplice per farlo. Abbiamo appena liberiamo di esso. C'è una funzione chiamata gratuito, accetta un puntatore alla memoria, e siamo a posto. Quindi diciamo che siamo in centro del nostro programma, vogliamo malloc 50 caratteri. Vogliamo malloc un array che può in grado di contenere 50 caratteri. E quando si ottiene un puntatore torna a che, il nome di quel puntatore è la parola. Facciamo di tutto siamo intenzione di fare con la parola, e poi quando siamo fatto che abbiamo appena liberiamo di esso. E ora siamo ritornati quelli 50 byte di memoria al sistema. Qualche altra funzione può usarli. Noi non dobbiamo preoccuparci di subire un perdita di memoria perché abbiamo liberato la parola. Abbiamo dato la memoria indietro, così abbiamo finito di lavorare con esso. Quindi ci sono tre regole d'oro che dovrebbero essere tenuto a mente ogni volta che sei allocare dinamicamente la memoria con malloc. Ogni blocco di memoria si malloc deve essere liberato prima che il programma termina l'esecuzione. Ora di nuovo, dall'applicazione o nel IDE questo tipo di verifica per voi in ogni caso quando you-- questo accadrà comunque quando il programma è terminato, tutta la memoria verrà rilasciato. Ma è generalmente buona codifica pratica per sempre, quando hai finito, liberare ciò che avete mallocd. Detto questo, solo cose che hai mallocd dovrebbero essere liberati. Se si dichiara un statico integer, int x punto e virgola, che vive sullo stack, è non poi si desidera liberare x. In modo che solo cose che hai mallocd dovrebbe essere liberato. E, infine, non fare qualcosa di gratuito due volte. Che possono portare a un'altra situazione strana. Quindi tutto ciò che hai mallocd deve essere liberato. Solo cose che hai malloc deve essere liberato. E non fare qualcosa di gratuito due volte. Quindi cerchiamo di passare attraverso un esempio qui di ciò che alcuni allocati dinamicamente memoria potrebbe apparire come misto con alcuni memoria statica. Cosa potrebbe accadere qui? Vedi se riesci a seguire lungo e indovinate cosa è succederà come andiamo attraverso tutte queste linee di codice. Così diciamo int m. Che succede qui? Bene, questo è abbastanza semplice. Creo una variabile intera chiamata m. Io colore verde che, perché questo è il colore che uso quando parlo circa variabili intere. Si tratta di una scatola. Si chiama metri, e si può memorizzare numeri interi al suo interno. Che cosa succede se poi dico int stella una? Beh, questo è abbastanza simile. Sto creando una scatola chiamata. E 'in grado di int partecipazione stelle, puntatori a interi. Così sto colorando di verde-ish pure. So che ha qualcosa a che fare con un numero intero, ma essa non è un numero intero. Ma è più o meno la stessa idea. Ho creato una scatola. Entrambi questi giusto ora vivono in pila. Ho dato loro entrambi i nomi. int stella b uguale dimensione malloc di int. Questo potrebbe essere un po 'complicato. Prendete un secondo e pensare a quello che ci si aspetta che accada in questo schema. int stella b uguale dimensione malloc di int. Beh, questo non solo crea una scatola. Questo in realtà crea due caselle. E si lega, stabilisce anche un punto in un rapporto. Abbiamo assegnato un blocco della memoria sul mucchio. Si noti che la casella in alto a destra là non hanno un nome. Noi mallocd esso. Esiste sul mucchio. Ma b ha un nome. E 'una variabile puntatore chiamato b. Che vive in pila. Quindi è un pezzo di memoria che punta a un altro. b contiene l'indirizzo di detto blocco di memoria. Non ha un nome altrimenti. Ma che punti ad esso. Così, quando diciamo int stelle b uguale dimensioni malloc di int, che proprio lì, quella freccia che spuntato sul lato destro lì, che tutta la faccenda, Dovrò apparire ancora una volta, è ciò che accade. Tutto ciò accade in quella singola riga di codice. Ora avremo poco più semplice di nuovo. un uguale commerciale m. Ti ricordi quello che un uguale e commerciale m è? Beh, questa è una ottiene l'indirizzo di m. Oppure mettere più schematicamente, una punta a m. un uguale b. OK, ecco un altro. A è uguale a b. Cosa succederà al diagramma stavolta? Bene ricordare che la opere operatore di assegnazione assegnando il valore sulla diritto al valore a sinistra. Così, invece di una punta a m, un ora punti nello stesso posto che i punti b. un non punta a B, A punti punti in cui b. Se una punta di B, che avrebbe sono stati un uguale commerciale b. Ma invece è uguale a B solo significa che e b sono ora indicando lo stesso indirizzo, perché all'interno di b è solo un indirizzo. E ora all'interno di a è lo stesso indirizzo. m è uguale a 10, probabilmente la cosa più semplice abbiamo fatto in un po '. Mettere il 10 nella casella. Stella b è uguale a più 2 m, da ricordare il nostro video di puntatori quale stella b significa. Stiamo andando a dereference b e put un valore in quella posizione di memoria. In questo caso 12. Così, quando abbiamo dereference un punto di Ricordiamo che abbiamo appena viaggiamo lungo la freccia. Oppure, in altre parole, ci andare a questo indirizzo di memoria e manipolare in qualche modo. Abbiamo messo un certo valore in là. In questo caso stelle b è uguale a m + 2 è solo andare alla variabile puntata da b, andare alla memoria puntata da b, e mettere m più 2 in là, 12. Ora mi libero b. Cosa succede quando mi libero b? Ricordate ciò che ho detto mezzi liberi. Quello che sto dicendo quando mi libero b? Io sono fatto lavorando con esso, giusto? Io do essenzialmente la memoria. Io restituisco al sistema. Non ho bisogno di questo più è quello che li dico, va bene? Ora, se io dico una stella è uguale a 11 si può probabilmente già dire che qualcosa di brutto sta per accadere qui, giusto? E in effetti se ho provato che probabilmente subirebbe un segmentation fault. Perché ora, anche se in precedenza che pezzo di memoria era qualcosa che ho avuto accesso a, a questo punto ora sto accedere alla memoria che Non è legale per me accedi. E come si sarà probabilmente ricordare, quando si accede memoria che non dovremmo toccare, che è la causa più comune di una segmentazione colpa. E così il mio programma potrebbe andare in crash se ho provato a fare questo. Quindi, di nuovo è una buona idea per ottenere un buon pratiche e buone abitudini radicate quando si lavora con malloc e gratuito, in modo che non si soffre la segmentazione difetti, e che si utilizza il tuo allocati dinamicamente la memoria in modo responsabile. Sono Doug Lloyd è CS50.