[Powered by Google Translate] [Settimana 4, Continua] [David J. Malan - Harvard University] [Questo è CS50. - CS50.TV] Questo è CS50, e questa è la fine della settimana 4. Quindi una buona notizia e una cattiva notizia. Nessuna lezione di Lunedi, nessun problema impostare la prossima settimana. [Studenti tifo] Non ti piacerà dove questo sta andando. Ma noi abbiamo questo invece Mercoledì prossimo, e c'è anche per la conferenza programma 1 Venerdì Venerdì prossimo in modo da poter rimanere in pista. Ma tutto sarà girato come al solito, quindi non preoccuparti. E per quanto riguarda i quiz 0 quello che faremo verso la fine della settimana è pubblicare sul cs50.net homepage del corso una spiegazione di che tipo di aspettative si dovrebbe avere quando si tratta il primo quiz. In generale, sarà a scelta multipla, vero-falso, risposte brevi, brevi problemi di codifica. Lei non sta andando ad essere tenuti ad attuare l'equivalente di un problema che si vede su un pset, per il quale si dispone di un computer e un debugger e simili, ma ci saranno piccoli problemi di codifica. E in effetti, la migliore guida per ottenere un senso di ciò che CS50 quiz sono come è andare a cs50.net, andare al Quiz link, e si può vedere il passato parecchi anni vale la pena di quiz. Basta rendersi conto che il curriculum non è sempre stata la stessa nel corso degli anni. A volte si aggiunge, a volte sottrarre, quindi se vedete qualche argomento in uno di quei vecchi quiz che non avete idea di cosa si sta parlando, è uno dei due che abbiamo fatto coprire o che non lo riguardano. Ma in forma di recensioni, questa Domenica, Lunedi e Martedì così come un corso a livello sessione di revisione nella notte di Domenica - ora e luogo che saranno annunciati sulla home page del corso - tutti hanno l'opportunità di rivedere con compagni di insegnamento del corso il materiale per quest'anno, sia in sezione e come classe piena, e quelli sarà girato come al solito pure. Bene. Quindi, senza ulteriori indugi, un commento su pass / fail e add / drop. Potreste aver visto le mie note la scorsa notte, e questo è davvero solo un po 'di rassicurazione ulteriore che se siete tra coloro particolarmente comodo o meno una via di mezzo e ti senti solo un po 'in sopra la vostra testa, si rendono conto che è davvero tutto normale, e non c'è una struttura di sostegno ampio in atto, uno dei quali orari di ufficio erano intenti a migliorare ancor più per la mia notte ultima e-mail, e realizzare anche che un'opzione come pass / fail per una classe come questa in realtà è inteso come un meccanismo per eliminare il bordo di un corso come questo, in modo che ancora una volta, se stai spendendo quei 10, 15, 20 ore solo cercando di ottenere qualche pset al lavoro e sai che sei il 90-95% del tragitto ma non riesci a trovare un po 'di bug maledetto, in un pass / fail modello che è una sorta di bene. L'idea è che con tale meccanismo si può quindi andare attenzione per i vostri pset altri o dormire o qualsiasi altra cosa è che si vuole mettere a fuoco. Così si rendono conto che avete tempo fino al il prossimo Martedì - tecnicamente il 5 Lunedi, ma è una vacanza, quindi il prossimo Martedì - per passare dal passo / non versa graduali o viceversa. E se sei davvero sull'orlo del precipizio e stanno pensando di abbandonare del tutto, Si prega di prendere me dopo lezione o mandami una nota. Ci piacerebbe almeno chiacchierata prima di addio. Bene. Così abbiamo iniziato a prendere le rotelle fuori l'ultima volta. In particolare, ci siamo concentrati sulla corda. String è qualcosa che è dichiarata nella libreria CS50, in particolare in quel file chiamato cs50.h che inizieremo a guardare questa settimana e la prossima. Ma stringa è in realtà solo una semplificazione di qualcosa che è un po 'più arcanamente descritto come char *. Char siamo a conoscenza. E 'solo un singolo carattere. Ma * a partire da Lunedi indicato che cosa? >> [Studente] Puntatore. Un puntatore. E che cosa è un puntatore? >> [Studente] Un indirizzo. E 'come un indirizzo, una locazione di memoria. Che cos'è un indirizzo o la posizione o la memoria? Ancora una volta, tutti noi abbiamo laptop con un concerto o 2 gigabyte di RAM molto probabilmente in questi giorni, e questo significa che si dispone di un miliardo o 2 miliardi di byte di memoria vale la pena. E non importa quello che sembra fisicamente come, ma prendere sulla fede che si può numerare tutti i singoli byte che il proprio computer portatile ha - questo è il byte 0, questo è il byte 1, questo è byte 2 miliardi di euro - e questo è esattamente ciò che un computer fa. Quando si allocare spazio per un singolo carattere, per esempio, che ha ovviamente a vivere da qualche parte nella memoria del computer, e forse è al numero di byte 12345, e che da qualche parte qui in memoria del computer. E poi l'indirizzo di quel personaggio è 12345. Ora, nella settimana da 0 a ora finora, non abbiamo veramente a cuore dove in memoria le cose sono memorizzati perché di solito utilizzano simboli, variabili e matrici per ottenere effettivamente i nostri dati. Ma, come di Lunedi e tanto più oggi, si sta ora andando ad avere tutte le funzionalità più espressivi con i programmi di scrittura per manipolare davvero memoria di un computer ma si vede in forma, sia per scopi buoni e cattivi, bug è un risultato molto comune a questo punto imparare questa roba. Ma che cosa significa realmente essere un char *? Andiamo avanti a indietro - e torneremo a Binky come promesso oggi. Andiamo in un semplice esempio qui. Vorrei salvare il file come compare.c, e vorrei solo avere un po 'di codice modello qui in modo da includere stdio.h, mi permetto anche di darmi includono cs50.h. Io zoom lassù. Vorrei iniziare a scrivere int main, main (), e ora voglio fare qualcosa di simile a questa: printf ("Dammi una stringa:") e poi userò stringa s viene GetString per ottenere una stringa da parte dell'utente, quindi ho intenzione di chiedere all'utente per un altro. ("Dammi un'altra stringa:") e ho intenzione di chiedere loro tramite GetString per ottenere che. Io lo chiamo t t perché viene dopo s ed s è un bel nome per una stringa, se è abbastanza generico. Così GetString, e adesso voglio solo fare un controllo di integrità e ho intenzione di dire if (s == t) allora sto solo andando a informare l'utente printf ("Hai digitato la stessa cosa \ n"); altra cosa io vado a stampare qualcosa di simile ("Hai digitato qualcosa di diverso! \ n") o qualsiasi altra cosa la sentenza sarà. Quindi, qualcosa di simile. Poi, come al solito, tornerò 0 che significava solo che nulla di male è accaduto, e ho intenzione di andare avanti e compilare ed eseguire il programma. Ma il Lunedi abbiamo fatto questo programma, e in realtà hanno detto che non è CIAO CIAO CIAO e non è un addio. Il comportamento che abbiamo visto era un po 'più simile a questo. Lasciami andare nella mia directory di origine, zoom in qui, e facciamolo fare confrontare. Compilato bene. Vorrei correre confrontare. Dammi una stringa: CIAO. Dammi un'altra stringa: CIAO. È stato digitato qualcosa di diverso! Beh, mi permetta di provare qualcosa di più semplice come 50, 50. È stato digitato qualcosa di diverso! hi, hi. Quindi, chiaramente, qualcosa sta succedendo qui. Ma qual è stata la spiegazione del perché? A quanto pare, la linea 12 è completamente disfunzionale. Qual è il problema fondamentale qui? Gia '. >> [Studente] E 'confrontando gli indirizzi. Sì, esattamente. In realtà confrontando gli indirizzi in cui CIAO CIAO e sono memorizzati. Non è a confronto le lettere CIAO ancora e ancora, perché quello che è realmente accaduto, tutto questo tempo abbiamo usato GetString - Questa lavagna è ancora una volta la memoria del nostro computer, e diciamo che io chiamo GetString dopo aver dichiarato una variabile s. Cosa fa la mia memoria assomiglia? Facciamo arbitrariamente dire che s assomiglia a questo. Si tratta di un quadrato. E più o meno ogni volta che ho disegnato un pezzo di memoria sullo schermo se è a 32 bit ho disegnare quadrati come questo perché in effetti all'interno dell'apparecchio, un puntatore, un indirizzo, è di 32 bit. E 'la stessa di un int. Che possono variare in base al sistema del computer. Quelli di voi che sono vagamente a conoscenza del fatto che il vostro Mac o PC è a 64 bit, che indica in realtà che il computer utilizza puntatori a 64 bit, Indirizzi a 64 bit, e tra gli aspetti positivi di questo è il vostro computer possono disporre di RAM molto più di un tempo. Per farla breve, nel giorno in cui i computer utilizzati solo 32 bit per rappresentare gli indirizzi, il maggior numero di byte che potrebbe rappresentare in questo caso era quello che se si dispone di 32 bit? Quindi 4 miliardi, giusto, perché da 2 a 32 è di 4 miliardi di euro. Questo numero è stato ricorrenti nel corso. Quindi, se avete solo 32 bit, il numero più alto si può contare fino a è di circa 4 miliardi. Ma quella era una limitazione fondamentale di computer fino a pochi anni fa perché se si può contare solo più in alto come 4 miliardi di euro, non importa se si acquista 8 gigabyte di RAM o anche 5 gigabyte di RAM; non si può contare così in alto, quindi era inutile. Si può accedere solo i primi 3 o 4 gigabyte di memoria del computer. Questo è meno di un problema ora, e si possono acquistare MacBook Pro e Dells con 8 gigabyte di RAM o anche di più in questi giorni. Ma se allocare semplicemente in questo programma un puntatore, un puntatore chiamato s, potrebbe apparire come questo sullo schermo perché in effetti abbiamo bisogno di togliere questo strato. Continuo a dire stringa, ma come di Lunedi, la stringa è davvero char *, l'indirizzo di qualche personaggio. Quindi cerchiamo di prendere la ruota formazione fuori, anche se continueremo a utilizzare GetString per ora. Così ho dichiarato s, e questo è un pezzo di memoria a 32 bit. Cosa c'è qui in memoria di default? >> [Risposta degli studenti incomprensibile] Che cos'è? >> [Studente] Garbage. Garbage >>. Esattamente. Se il programmatore non mettere un valore in una variabile, che sa che cos'è? A volte sei fortunato ed è 0, che è una specie di bello, valore di default pulito, ma come abbiamo visto Lunedi, a volte è assolutamente privi di senso, un numero veramente grande positivo o negativo che è venuto da dove? Gia '. >> [Studente] La funzione prima. Sì >>. Spesso la funzione che ha chiamato prima, perché ricordare, come si chiamano le funzioni in memoria, occupano sempre più spazio dal basso verso l'alto, e non appena la funzione ritorna, che la memoria viene riutilizzata per la persona accanto che viene chiamato, che utilizzano la vostra stessa porzione di memoria. E se hai spazzatura di sinistra, i valori precedenti, potremmo scambiare s come avere un certo valore, quando in realtà non abbiamo messo nulla. Quindi la nostra RAM, a questo punto si presenta così. Ora sul lato destro della linea 7 che stiamo chiamando GetString, che stiamo facendo da settimane, ma ciò che è GetString facendo veramente? GetString scritto dal personale CS50 è un po 'intelligente dal fatto che, non appena l'utente inizia tasti battitura e colpisce Invio, GetString figure quante battute ha fatto il colpo d'uso, il numero di caratteri devo allocata memoria RAM. E dove che la RAM viene, chi lo sa? E 'da qualche parte nel vostro computer o roba del genere 2 gigabyte di memoria. Ma supponiamo che il computer trovato spazio per la parola CIAO proprio qui. La parola che ho scritto era H-E-L-L-O. E se disegnare questo come una sequenza di caratteri, possiamo disegnare come questo. Ma ho bisogno di fare 1 cosa in più. Ciò che appartiene alla fine di una stringa in C? Il carattere nullo, che si scrive come \ 0. E 'tecnicamente il numero 0, ma il backslash rende tutto più chiaro che questo è letteralmente il numero 0, il numero intero 0; non è, ad esempio, quote-unquote 0 che è possibile digitare sulla tastiera. Quindi questo è CIAO. E che cosa abbiamo detto il Lunedi che una funzione come GetString è in realtà tornando tutte queste settimane? Non è restituendo una stringa di per sé in quanto che in realtà non hanno un significato perché le stringhe non esistono. Sono una sorta di fabbricazione nella libreria CS50. Quello che è veramente una stringa, più tecnicamente? >> [Studente] E 'il primo carattere. Esattamente. E 'semplicemente l'indirizzo del primo carattere che l'utente ha digitato trovi Quindi, se la mia parola CIAO finisce a 123 il numero di byte e quindi al numero di byte 124, 125, 126, e così via, se ho solo il mio numero di byte da 0 in su, ciò che realmente sta tornando GetString è letteralmente il numero 123. Quindi, ciò che viene messo in s è il numero 123, non la lettera H, non la parola CIAO, semplicemente l'indirizzo al quale riesco a trovare la prima lettera di CIAO. Ma questo non sembra sufficiente. Ti ho chiesto per una stringa, non un carattere. Quindi, come possiamo o il computer sa che ELLO tipo di venire con la H? Qual è il tipo di accordo che abbiamo? Gia '. [Studente] Si continua a dire se stesso per trovare un po 'di più caratteri. >> Esattamente. C'e 'un uomo-computer convenzione per cui quando hai a che fare con le stringhe, altrimenti noto ora come stelle char, devi semplicemente capire dove alla fine di ogni stringa nella vita è in realtà solo da iterando su di esso con un ciclo for, un ciclo while, qualunque cosa, in modo che quando si trova alla fine della stringa ora si può dedurre da questo, oh, l'intera parola è stata CIAO. Quelli di voi con esperienza di programmazione precedente potrebbe sapere in Java si può chiamare. lunghezza e in altre lingue è possibile chiamare lunghezza o simili. Questo perché in molte lingue, in particolare cose chiamate linguaggi orientati agli oggetti, la lunghezza di qualcosa è una specie di incapsulato all'interno del pezzo dei dati stessi, un po 'come noi ID incapsulati e nomi e le case all'interno di uno studente il Lunedi. Ma C è di livello molto più basso. Non ci sono oggetti o classi, se hai sentito questi termini prima. Tutto quello che è in realtà gli indirizzi di memoria. Quindi questa è una sorta di vecchia maniera di rappresentare strutture di dati interessanti. Si dispone di un valore iniziale come l'indirizzo del primo carattere e poi basta un po 'di convenzione arbitraria che tutti sono d'accordo a seguire. Così come è la lunghezza della stringa attuato, ha proponiamo? Strlen, strlen, che alcuni di voi hanno utilizzato un paio di volte. E 'piuttosto semplice, no? E 'come 2 righe di codice. E 'praticamente un ciclo per di qualche tipo, magari con una variabile aggiuntiva locale. Ma strlen deve solo prendere un puntatore e poi iniziare a cercare \ 0. E non appena lo trova, può restituire il numero totale di passi che è preso in quella stringa. Quindi possiamo dedurre da questo quello che succede dopo. Supponiamo quindi Dichiaro t come ho fatto nella riga 10. Questo è un valore immondizia. Chissà in un primo momento? Ma sul lato destro della linea di 10 Chiamo GetString nuovo. Chi sa dove questo finisce? Facciamo arbitrariamente dire che il sistema operativo trovato spazio per essa fin qui. Mi è capitato di scrivere a caso H-E-L-L-O ancora, e così possiamo trarre lo stesso tipo di immagine. Ma il fatto che ho ridisegnato questa immagine è deliberata perché questo è un altro CIAO di questo. Ecco questo potrebbe essere posizione 456, questo è 457, e così via. Quindi, ciò che viene messo in cui il punto di domanda era una volta? In questo caso 456. Stiamo raccogliendo questi numeri arbitrariamente perché in realtà a partire da oggi non stiamo andando a prendersi cura così tanto su ciò che l'indirizzo di qualsiasi cosa è. Tutto quello che interessa è che siamo in grado di capire l'indirizzo di qualche pezzo di dati come CIAO. Quindi, in realtà ciò che la maggior parte delle persone fanno in informatica quando si parla di indirizzi di memoria e parlando di puntatori in particolare, piuttosto che preoccuparsi di capire 123 - chi se ne frega se questa roba è in realtà, sappiamo solo che è a un certo indirizzo numerico - semplifichiamo il mondo e solo dire che s punta a quel personaggio e t punta a quel personaggio. E il fatto che è una freccia è piuttosto intenzionale perché letteralmente ora s è puntato verso H e t è puntato verso l'altro H perché alla fine della giornata, non importa quanto sia l'indirizzo, ma è importante che abbiamo la capacità di esprimere l'indirizzo con qualche pezzo di codice. Non abbiamo davvero manipolato questi indirizzi appena ancora quindi vedremo dove possiamo intervenire con e ordinare di fare le cose con i puntatori, ma per ora in linea 12 letteralmente quali valori stiamo confrontando in base a questa storia nella riga 12? Stiamo dicendo che è 123 pari pari a 456? E questo non è assolutamente il caso. E anche concettualmente, questo puntatore non è assolutamente la stessa di questa perché hai chiamato GetString due volte, e GetString non cerca di essere super intelligente, non cercare di capire, oh, avete digitato CIAO 5 minuti fa; lasciate che vi dia lo stesso puntatore come ti ho dato prima, assegna solo una nuova porzione di memoria ogni volta che viene chiamata. Quindi, come possiamo risolvere questo problema? Se un livello superiore voglio confrontare le stringhe CIAO CIAO e - Non mi importa delle indicazioni - come posso fare per rispondere alla domanda, ha l'utente digita la stessa cosa? Che cosa è necessario qui? Gia '. [Studente] Utilizzare una funzione. >> Riesco ad usare una funzione, fuori dalla scatola. Riesco ad usare una funzione chiamata strcmp, s-t-r-c-m-p, solo la versione abbreviata di dire stringa confrontare. E se andiamo in, per esempio, confrontare 2, che è tra gli stampati di oggi, Faccio esattamente questo. Ho tenuto tutto il resto lo stesso dalla linea 1 in giù a 26 o giù di lì, e ora notate questa parte è cambiato solo un po '. Ignoriamo linea 28 per un momento e concentrarsi solo su questo. Cosa abbiamo detto Lunedi che str confronto fa? Gestisce il processo di prendere due puntatori, S e T in questo caso, sorta di quasi mettere il dito su quelle 2 lettere, e ciò che deve fare è qualcosa di simile a un ciclo while o un ciclo for, e si dice che sono questi gli stessi? In caso affermativo, si muove le dita o puntatori avanti. Questi sono gli stessi, questi lo stesso, questi lo stesso, questi lo stesso, questi lo stesso? E ooh, io sono alla fine della stringa, sia a s e t. Non ho trovato alcuna contraddizione. Sì, queste stringhe sono uguali. E che cosa str confronta ritorno, se due stringhe sono uguali, a quanto pare? Zero. Quindi 0 è bene in questo caso perché se restituisce -1 o +1, ciò significa che s succede solo a venire prima o dopo la t in ordine alfabetico t. E perché ciò sarebbe utile disporre di una funzione che ti dice quale stringa viene prima o dopo in un dizionario? [Studente] Ricerca. >> Ricerca e l'ordinamento. Così si può fare le cose come ricerca binaria o bubble sort e merge sort dove si deve confrontare cose. Finora abbiamo tipo di tagliare alcune curve e solo parlato di ordinamento nel contesto dei numeri, perché è bello e facile parlare, ma si può certamente confrontare le stringhe, mela e banana, perché se Apple è noto per venire prima banana, allo stesso modo, si può spostare in giro per le stringhe in memoria, proprio come ha fatto con Rob merge sort nel video e lo abbiamo fatto qui sul palco con selection sort, insertion sort e bubble sort. Allora, dove altro possiamo prendere questo? Proviamo questo. Facciamo una specie di lezione dimenticare che per un momento e prova adesso e copiare 1.c effettuare le seguenti operazioni. In linea 21 che sto dicendo qualcosa di stampa, allora sto diventando una stringa da parte dell'utente, allora sto controllando questo. Non abbiamo davvero ottenuto in questa abitudine ancora, ma andiamo ora fare questo. Facciamo in realtà togliere questo strato. Questo è veramente char *. Questo ragazzo è davvero char *. Che cosa vuol dire essere il controllo se s == NULL? Si scopre che quando si chiama una funzione come GetString o più in generale, basta chiedere a un computer di darvi un po 'di memoria, qualcosa potrebbe andare storto. Potresti essere pazzo e chiedere al computer per un terabyte di memoria con la richiesta di migliaia di miliardi di byte di memoria che proprio non esistono nel computer, ma le funzioni GetString e di altri bisogno di un modo di urlare contro di voi se hai chiesto troppo. E il modo GetString fa questo è che se si hanno chiesto più memoria che è disponibile nel computer, anche se è super, super basso probabilità perché nessuno di noi sta andando a digitare mille miliardi di caratteri, quindi premere Invio, ma bassa probabilità per quanto possa essere, ho ancora voglia di verificare la presenza di esso nel caso in cui, e il valore speciale che restituisce GetString, risposta, e altre funzioni se qualcosa è andato storto è NULL in tutte le protezioni. E che cosa è NULL? NULL così succede per rappresentare un puntatore. E 'l'indirizzo 0 della memoria. Il mondo ha deciso che arbitrariamente, se questa è la memoria del mio computer - sai una cosa? - stiamo andando a rubare solo 1 byte di memoria di ogni computer, e questa è la posizione 0. Stiamo per dare un soprannome di NULL, e abbiamo intenzione di promettere che non saremo mai effettivamente messo dati reali ci perché abbiamo bisogno di arbitrariamente un valore speciale, 0, NULL alias, in modo che possiamo urlare agli utenti se qualcosa va storto. In caso contrario si potrebbe non sapere è 0 significa mettere qualcosa qui o significa qualcosa è andato storto? Siamo d'accordo tutti che non significa nulla NULL è stato restituito, nessun indirizzo effettivo è stato restituito. Ora, qui sto solo adottando la mia convenzione umana di torno 1 dal principale se qualcosa va storto. Questo perché il ritorno convenzione principale è quello di restituire 0 se buona, 1 o qualche altro valore se male. Ma GetString e qualsiasi funzione che si occupa di memoria ritorna NULL se qualcosa va male. Va bene. Così, purtroppo, linea 27, super semplice che sia, non riesce completamente a copiare la stringa. Perché? Si può vedere questo come segue. Sto sostenendo in linea 27 da fare una copia di s e t chiamarlo. Quindi non sto chiedendo all'utente per 2 stringhe di questa volta, io sto solo dicendo che il valore in s dovrebbe essere messo in t pure. Così ora solo per dimostrare come questo è rotto, in linea 29 in poi quello che sto facendo? Prima Sto controllando se la lunghezza di t è maggiore di 0. C'è qualche stringa lì. L'utente ha digitato qualcosa trovi Qual è la linea 32 facendo, a quanto pare? [Risposta incomprensibile studente] destra >>. È possibile che tipo di dedurre da ciò che ho detto che sta facendo. Ma tecnicamente, cosa sta facendo questo? t [0] rappresenta ciò? [Studente] Il carattere 0. >> [Malan] Il carattere 0. O, più simile a quella umana, il primo carattere in t, qualunque essa sia, H forse in questo caso. E toupper fa quello che dice. Essa sfrutta il carattere zero della t e lo cambia. Quindi questo significa prendere il carattere zero della t, rendono maiuscolo, e lo rimise in quella stessa posizione. Quindi, se scrivo ciao in caratteri minuscoli, la situazione dovrebbe cambiare la h minuscola a una maiuscola Ma il problema è che nelle linee 35 e 36 quello che sto per fare è stampare per noi s e t. E qual è la tua sensazione? Che cosa sono io in realtà andando a vedere se ho digitato ciao a tutto minuscolo? Che cosa sta per far stampare? >> [Risposta degli studenti incomprensibile] >> Che cos'è? [Studente] Big H e il resto piccolo. >> Il grande H e il resto piccolo per il quale, s o t? [Studente] Entrambi. Entrambi >>. Esattamente. Quindi cerchiamo di vedere quello che sta succedendo qui. Lasciatemi andare avanti e compilare questo. Questo è da Copia1, in modo da rendere Copia1. Bene. Immagine Lasciami andare avanti ed eseguire Copia1, Enter, Inserisci commento: ciao in minuscolo. E 'capitalizzato la copia, ma a quanto pare capitalizzato l'originale pure, perché ciò che accade oggi in questa storia? In linea 27 che in realtà non sembrano essere la copia della stringa, ma anche se si potrebbe avere intuitivamente sperare che sia il caso, se pensi di questo quadro, ciò che veramente ho fatto? Metà del quadro è la stessa. Quindi cerchiamo di rotolare indietro nel tempo in modo che t non esiste ancora nella storia. S può esistere nella storia, ma cerchiamo di minuscole ciao questa volta. Permettetemi quindi di correggere quello che ho effettivamente digitato trovi In questo caso qui abbiamo h-e-l-l-o. Noi lo disegnare come una sequenza di caratteri, mettere le mie linee di separazione qui e la mia \ 0. Quindi questo è dove siamo, non appena la linea da 1 a 24-ish, prendere o lasciare, hanno eseguito. Questo è il quadro della mia memoria. Quando arrivo alla riga 27, che cosa succede? Proprio come prima, ottengo un puntatore, che verrà disegnare come questa piazza. Si chiama t. E qual è il suo valore di default? Chi lo sa? Alcuni rifiuti valore. Quindi mi astratto che via come un punto interrogativo. E non appena il lato destro della linea 27 viene eseguito, quello che sto mettendo dentro di t? La stessa cosa che è in s. Quindi, se per un momento rimuovere questa astrazione della freccia e diciamo, oh, questo è un carico indirizzo di memoria 123, quando si dice t ottiene s, punto e virgola, si sta letteralmente mettendo 123 qui. Ora, se i tipi di semplificare il nostro mondo di nuovo con le immagini, quello che hai fatto veramente è appena aggiunto un'altra freccia al tuo mondo che sta puntando da t per la stessa stringa esatta. Così, quando in linea 31 e 32, io in realtà andare a cambiare t [0], ciò che è t [0] a quanto pare sinonimo di adesso? s [0] Ecco, questo è tutto quello che sta succedendo. E anche se questo tipo di livello si sente un po 'basso e arcano e questo tipo di sente come forse intuitivamente questo dovrebbe essere solo lavorato - Ho fatto copie di cose prima e solo lavorato - se effettivamente pensare a quello che una stringa è in realtà, è un char *. Beh, che cosa è questo? E 'l'indirizzo di qualche personaggio. Allora forse ha più senso che quando si tenta di fare qualcosa Super apparentemente semplice come questo, tutto quello che stai facendo è la copia di un indirizzo di memoria. Lei non sta effettivamente facendo qualcosa con la stringa stessa. Quindi, anche se non avete idea di come si potrebbe risolvere questo problema nel codice, alto livello, concettualmente, che cosa dobbiamo fare per rendere ta copia conforme di s, a quanto pare? Gia '. >> [Studente] Dare una nuova posizione? >> Esattamente. Abbiamo bisogno di dare una nuova posizione del marchio t. Abbiamo bisogno di creare in qualche modo un mondo in cui si ottiene un nuovo blocco di memoria, che solo per motivi di chiarezza io disegnare direttamente al di sotto di questo, ma non ha bisogno di essere lì. Ma deve avere la stessa dimensione, quindi mi disegnare queste linee verticali nello stesso luogo. Va bene se si tratta di tutti i rifiuti inizialmente. Chi sa che cosa c'era? Ma il passaggio 1 sta per essere darmi la quantità di memoria di cui ho bisogno di adattamento di una copia di ciao, quindi capire come copiare il h qui, l'indirizzo qui, L qui e così via. Ma questo già dovrebbe sentire un po 'ovvio, anche se alcuni dettagli sono ancora astratto. Per copiare questa stringa in questo, è solo un ciclo for o un ciclo while o qualcosa con cui sei diventato ancora più familiare. Quindi cerchiamo di provare questo. Lasciami andare in copy2.c. In copy2.c abbiamo quasi lo stesso programma, tranne per la linea 27. Sembra un po 'complessa, ma se lo scomporre pezzo per pezzo, il lato sinistro è la stessa. Char * t crea questa cosa nella memoria, anche se con un punto interrogativo perché non abbiamo idea di quello che c'è di default. Sul lato destro ci stiamo ora introducendo una nuova funzione, malloc, per la memoria allocare, dammi la memoria, e ci vuole a quanto pare il numero di argomenti, quante cose tra parentesi? Ho sentito mormorii di 1 e 2, ma è solo 1. Non c'è una virgola, il che significa che c'è solo 1 cosa all'interno delle parentesi. Anche se ci sono altre parentesi, vorrei sottolineare cosa c'è dentro le parentesi più esterni, ed è questa espressione: (Strlen (s) + 1) * sizeof (char). Quindi, se in realtà credo che questo attraverso, questo sta dicendo darmi la lunghezza di s. Perché io sono, però, aggiungere 1 sulla lunghezza? >> [Risposta degli studenti incomprensibile] Esattamente. Abbiamo bisogno di spazio per questo ragazzo in coda, il sesto carattere che non ha alcun significato inglese ma ha particolare significato programmatico. Quindi abbiamo bisogno di un + 1 per questo, perché strlen restituisce l'attesa umana di lunghezza, ciao o 5, non ti dà il carattere aggiuntivo nullo. Quindi aggiungere manualmente questo con + 1. E poi questo, di dimensioni * (char), non abbiamo mai visto prima. Questo non è tecnicamente una funzione. E 'una parola chiave speciale che dice solo quello che la dimensione è di un certo tipo di dati in un computer perché in realtà, alcuni di noi hanno computer a 32 bit. Ho un computer piuttosto vecchio a casa, e utilizza solo 32 bit per rappresentare i puntatori. E quindi se ho fatto dimensione di un tipo di dati, potrebbe essere a 32 bit. Ma se sto usando il mio nuovo computer fantasia, potrei tornare un valore di 64 bit per qualcosa come un indirizzo. Quindi, in questo caso, giusto per essere sicuri super, non stiamo andando a qualcosa di duro come il codice - bene, qual è la dimensione di un char in base a quello che abbiamo detto finora? Abbiamo più o meno ha detto verbalmente che è 1 byte, e questo è più o meno vero su tutta la linea. Ma ancora una volta, le ipotesi tendono ad essere cattivi. Essi conducono al software bacato se la gente usa il software in modi che non aveva l'intenzione. Quindi cerchiamo di astratto questa via e solo più genericamente dire Ho bisogno di questo molti pezzi di memoria e ciascun blocco di memoria dovrebbe essere equivalente alla dimensione di un carattere, che è infatti pari a 1 in questo caso, ma è un modo più generico di scrittura. Quindi, se la parola è ciao, quanti byte si malloc apparentemente allocare per ciao? [Studente] Six. Six >>. Esattamente come molti come abbiamo punti interrogativi sullo schermo. E poi prendere un indovinare ora in base alla comprensione della GetString cosa malloc probabilmente restituire? >> [Studente] Un indirizzo. Un indirizzo di che cosa? Del primo blocco di memoria. Non abbiamo idea di quello che c'è, perché qualche altra funzione avrebbe potuto usando questa memoria precedentemente. Ma malloc, come GetString, restituisce l'indirizzo del primo byte di memoria che ha messo da parte per te. Tuttavia, ciò che non fare è riempire questo vuoto con un carattere null barra rovesciata perché è venuto fuori è possibile utilizzare malloc per allocare tutto: int, stringhe, array, galleggianti, strutture studenti. È possibile utilizzare malloc completamente genericamente. Non importa o devono sapere cosa si sta per l'allocazione di memoria. Quindi sarebbe presuntuoso per malloc di mettere un \ 0 alla fine di ogni blocco di memoria che sta dando perché questa \ 0 non è solo una convenzione per le stringhe. Non è utilizzato per interi, non è utilizzato per i float, non è utilizzato per gli studenti. E così il Gotcha con malloc è che l'onere è interamente su di voi il programmatore per ricordare il numero di byte che si assegnata e di non utilizzare mai un ciclo for o un ciclo while e andare oltre il bordo del blocco di memoria che è stata data. In altre parole, non appena si alloca la memoria, non si può chiedere al sistema operativo, oh, a proposito, come di un grande pezzo di memoria era questo? E 'interamente a voi di ricordare se avete bisogno di tale valore. Quindi cerchiamo di vedere come procedere ad utilizzare questa memoria. In linea 28 e 29 perchè sto facendo questo? Solo test di consistenza totale. Nel caso in cui qualcosa è andato storto, chiedo per una certa quantità folle di memoria o Ho tante cose in esecuzione sul computer che semplicemente non è sufficiente memoria, qualcosa del genere, io almeno voglio verificare la presenza di null. In realtà, la maggior parte dei computer vi darà l'illusione che ogni programma possono utilizzare la totalità della RAM, ma anche così, se l'utente digita una stringa folle lungo forse perché sono un cattivo ragazzo e stanno in realtà cercando di causare il crash del programma o hack in esso, si desidera controllare almeno il valore di ritorno di malloc e se è uguale a null. E se lo fa, diciamo solo uscire in questo momento perché non so cosa fare in quel caso. Come faccio a copiare la stringa? Ci sono alcuni modi per farlo. Ci sono str copia delle funzioni in C, ma è super semplice per noi per fare questo la vecchia maniera. In primo luogo vorrei capire quale sia la lunghezza di s è. Avrei potuto mettere questo nel ciclo, ma invece ho appena messo qui per chiarezza. Così n memorizza ora la lunghezza della stringa originale, che è apparentemente 5. Poi, nel mio loop per sto iterazione da 0 su un massimo di n, e su ogni iterazione sto mettendo s [i] all'interno del t [i]. Ecco, questo è quello che ho implicita con i miei 2 dita rivolte le corde prima. Dato che questo ciclo for itera come questo, ho intenzione di essere la copia h in questa sede, e in questa sede, l in questa sede perché questo è s, questo è t. E poi, infine, alla riga 35 perché sto facendo questo? Ho bisogno di fare in modo che io la fine della stringa t. E l'ho fatto in questo modo per essere super esplicito. Ma proporre, qualcuno, se si potesse, un modo diverso di fare questo. Non ho davvero bisogno di linea 35. C'è un altro modo per fare questo. Gia '. >> [Risposta degli studenti incomprensibile] >> Dillo più forte. [Studente] Minore o uguale a. >> Esattamente. Potremmo semplicemente dire minore o uguale an, che in generale è stato male perché quasi sempre quando andiamo fino ad un uguale alla cosa che stiamo contando 1 passo andiamo troppo lontano. Ma ricordate, quanti byte abbiamo allocare? Abbiamo assegnato strlen di s, quindi 5 + 1 per un totale di 6. Quindi, in questo caso si potrebbe fare qualcosa di simile in modo che si sta copiando non solo il ciao, ma anche il \ 0 alla fine. In alternativa, si potrebbe utilizzare una funzione chiamata str copia, strcpy, ma che non sarebbe stato divertente così tanto. Ma questo è tutto ciò che fa sotto la cappa. Poi infine, facciamo la stessa cosa di prima. I capitalizzare t e poi affermare che l'originale assomiglia a questo e la copia sembra che. Quindi cerchiamo di provare questo adesso. Lasciami andare qui. Fai copy2. Ci ingrandire ed eseguire copy2. Io vado a digitare ciao in minuscolo, e in effetti ho minuscolo ciao come l'originale Ciao ma il capitale per la copia. Ma non ho finito ancora. Ho bisogno di fare 1 ultima cosa qui. 46 e 47 è chiaramente liberare la memoria, ma che cosa significa in realtà? Cosa sto facendo, pensi che, chiamando la linea 46 e linea 47? Che effetto ha questo? Gia '. [Risposta degli studenti incomprensibile] >> Esattamente. Si sta solo dicendo il sistema operativo, ehi, grazie per questa memoria. È ora possibile utilizzare per qualcun altro. Ed ecco un esempio perfetto di valori spazzatura. Ho appena usato questa memoria per scrivere la parola ciao in 2 posti, qui, qui, qui e qui. Quindi questo è h-e-l-l-o-\ 0. Ma poi io chiamo la linea 46 e linea 47, e sai cosa succede in termini di immagine? A dire il vero, aspetta, questa immagine è quello vecchio. Una volta che facciamo la copia, questo ragazzo è in realtà punta qui, quindi cerchiamo di rimuovere i numeri e solo astrarre come le nostre frecce di nuovo. Che cosa succede in questa foto quando si chiama gratis? [Risposta incomprensibile studente] >> Neanche. Se chiamo gratuito s e t - una specie di domanda trabocchetto - questa immagine non cambia niente perché la chiamata e la chiamata s t dice solo il sistema operativo, hey, è possibile utilizzare questa memoria ancora una volta, ma non cambia questo valore nullo o qualche carattere speciale, non cambia questo, non cambia l'h o l'indirizzo o il l o l o o in altro luogo a qualsiasi altra cosa. In termini di immagine, non appena si chiama gratis, non cambia nulla. E qui sta l'origine dei valori della spazzatura perché se io poi in questo programma chiedere al sistema operativo per più memoria con GetString o malloc o qualcosa del genere e il sistema operativo dice, certo, ho 12 byte di memoria appena liberati, utilizzare questi, che cosa hai intenzione di essere consegnato? Stai andando a consegnare un pezzo di memoria che in genere trarre con punti di domanda, ma quali sono questi punti interrogativi? Essi capita di essere h-e-l-l-o, h-e-l-l-o. Questi sono i nostri valori spazzatura nuovi non appena si liberare la memoria. C'è un mondo reale implicazione anche qui. Questo succede a che fare con la RAM, ma i computer effettivamente fare la stessa cosa con il disco. Parleremo di questo, in particolare, con una serie di problemi futuri che si concentra sulla forense. Ma ciò che effettivamente accade se hai qualche file finanziarie sensibili sul tuo desktop o qualche abbozzato JPEG e si trascina nel cestino, cosa succede quando si trascina nel cestino o nel cestino? Sapevi cosa stavo parlando. [Risate] Che cosa succede quando hai trascinato tali prove nella tua cestino o cestino? [Risposta degli studenti incomprensibile] Beh, così attento. Che cosa succede quando l'hai fatto? La risposta breve è niente, no? File di Sketchy o sensibili è ancora seduto lì da qualche parte nel disco rigido. La maggior parte di noi almeno hanno imparato a proprie spese che è necessario svuotare il cestino o il cestino per eliminare i file in realtà. E infatti, quando si fa clic o controllare clic sul tuo cestino o scegliere File, Vuota il Cestino o qualsiasi altra cosa e in realtà svuotare il cestino o cestino, ciò che effettivamente accade poi a questo quadro? Niente di più. Quindi nulla accade realmente sul disco. E se solo temporaneamente divagare e scrivere - I'Ll basta utilizzare il retro di questo. Così ora la storia sta cambiando da RAM, che è dove esistono programmi mentre li stai eseguendo, su disco, che è dove sono immagazzinati a lungo termine anche quando il potere esce, per ora - e ci torneremo a questo in futuro - facciamo solo finta che questo rappresenta la parte interna del disco rigido del computer perché nel giorno quelli di una volta dischi circolari, proprio come i floppy disk. Quindi, se si dispone di alcuni file di Excel sensibile, potrebbe prendere questo pezzo di memoria sul disco del computer, e sto solo disegnando stesso 1s arbitraria e 0. Quando si trascina il file in quel modo al vostro cestino o nel cestino, letteralmente nulla accade perché Apple e Microsoft hanno appena deciso il cestino e cestino è in realtà solo un segnaposto temporaneo. Forse alla fine il sistema operativo svuotarlo per voi, ma in genere, non fa nulla, almeno fino a quando sei veramente poco spazio. Tuttavia, quando si va al cestino vuoto o Svuota cestino, allo stesso modo, non succede nulla a questo quadro. Tutto ciò che accade è altrove nel computer, c'è una specie di tabella. E 'un po' come un piccolo schema riassuntivo poco che dice che, diciamo, resume.doc, così il vostro curriculum in un file di Microsoft Word abituati a vivere nella posizione 123 sul disco rigido, non in memoria e non in RAM, ma sul disco rigido, e le vostre vite abbozzato JPEG a 456, e il file di Excel vive a 789 o dovunque. Quando si eliminano i file da parte effettivamente svuotare il cestino o il cestino, questa immagine non cambia. La 0 e 1 sul disco rigido non andare da nessuna parte. Ma questa tabella, questo piccolo database di sorta, non cambia. Quando si elimina il tuo curriculum, è come se il file viene eliminato in un certo senso, ma tutto il computer non si dimentica dove quella cosa vive sul disco rigido. La 0 e 1 che compongono il tuo curriculum o uno qualsiasi di questi altri file sono ancora intatte. Quindi, se avete fatto questo errore, c'è ancora una probabilità diversa da zero che è possibile recuperare i vostri dati con Norton Utilities o alcuni software commerciali il cui scopo nella vita è quello di trovare 0 e 1 che sono una sorta di rimasti orfani, dimenticato qui, ma qui a sinistra, in modo da poter ottenere i vostri dati. Oppure investigatori forensi con la polizia o FBI sarebbe in realtà fare un disco rigido e in realtà cercare modelli di 0 e 1 che sembrano JPEG, guarda come i file di Excel, e recuperarli in questo modo, anche se il computer non li ha dimenticati. Quindi l'unico modo veramente per cancellare i dati, come vedremo in futuro, è quello di strofinare o cancellare il file o il disco rigido - Non si può davvero sbarazzarsi del 0 e 1 perché altrimenti ci si avvia con un disco rigido gigabyte e che ci si finisce con un disco rigido megabyte se costantemente sono stati l'eliminazione, letteralmente, 0 e 1. Che cosa faresti se si voleva davvero per coprire le tracce e il problema fondamentale è che c'è ancora 0 e 1 sul disco? Vedo qualcuno che si gesticolando fisicamente rompere il dispositivo. Che funzionerà. [Risate] Ma se questo è una specie di soluzione costosa, ciò che sarebbe più ragionevole? Gia '. >> [Studente] Sovrascrivi loro. Loro >> Sovrascrivere con che cosa? >> [Studente] Altri dati. Altri dati. Si può solo sovrascrivere il disco con 0 o 1 o di tutti 0, tutti 1. E questo è proprio ciò che alcuni dei software fa. È possibile acquistare il software o addirittura ottenere il software libero, e anche integrato in Mac OS in questi giorni, meno in Windows, è la possibilità di cancellare in modo sicuro. In realtà, se si vuole tutti a casa run oggi, se hai un Mac e fare questo, se hai un po 'di roba nel tuo cestino, si può fare Vuota Cestino sicuro, che fa proprio questo. Piuttosto che limitarsi a cancellare i file qui, non cancella la 0 e 1 qui, piuttosto, cambia solo tutti loro, per esempio, a 0 e dot, dot, dot. Così uno dei tuoi futuri pset sarà effettivamente per recuperare i dati intenzionalmente - fotografie che abbiamo preso di persone, luoghi e cose del campus per il quale faremo una immagine forense di scheda di memoria di una fotocamera digitale, che è la stessa idea - e dovrete essere chiamati a trovare effettivamente i modelli che rappresentano JPEG sul disco rigido, molto simile a quella ex studente la cui e-mail ho letto un paio di settimane fa ha fatto per recuperare fotografie della sorella. Perché non facciamo una pausa di 5 minuti qui, e noi provvederemo a riorganizzarsi con più sulla memoria. Quindi, ecco le cose si fanno un po 'mind-bending, ma questo è un passo molto potente verso la comprensione di questa ancora di più. Ecco un programma chiamato pointers.c. E 'tra il codice di esempio di oggi. Si noti che nelle prime righe, da 19 a 22, tutto quello che stiamo facendo è qualcosa di simile GetString e restituendo un indirizzo, depositandolo in s. D'ora in poi per pset anche 3 se si vuole, ma pset 4 e su dove si può iniziare a prendere queste ruote di formazione fuori da soli, non vi è motivo di fingere che le stringhe esistono più. E 'sicuramente a posto per iniziare solo dicendo char *. Per inciso, di riferimenti on-line e nei libri si possono spesso vedere la stella accanto alla variabile. Si potrebbe anche vedere spazi intorno a entrambi i lati di esso. Tutti questi sono funzionalmente corretto. Per ora, però, ci standardizzare su questo approccio per rendere super chiaro che char * è come dire puntatore a carattere. Questo è il tipo di dati. E poi il nome della variabile s è in questo caso. Così abbiamo ottenuto una stringa e l'abbiamo chiamato s. E poi qui notare che sto facendo in realtà un po 'di trucco. Questo si chiama aritmetica dei puntatori, che è una sorta di super semplice. Significa solo sommare e sottrarre numeri ai puntatori. Ma questo funziona realmente. Questo programma stampa apparentemente la stringa s 1 carattere per riga in modo tale che il risultato finale - Solo così siamo in grado di rovinare dove questo sta andando, fare puntatori, puntatori correre, lasciami Immagine Ora mi consentono di digitare qualcosa come CIAO e il tipo di Invio e stampa 1 carattere per riga. Fino a un secondo fa, avremmo fatto con la notazione parentesi quadra. Avremmo un ciclo for e ci piacerebbe fare printf di s [i] e ci piacerebbe farlo di nuovo e ancora e ancora con n backslash alla fine di ogni riga. Ma questo programma è diverso. Questo programma utilizza, letteralmente, l'aritmetica. Così che cosa sta succedendo qui? Prima di tutto, prima di questo ciclo viene eseguito, anche quello, tanto per essere chiari, è s in realtà? S è? >> [Studente] Un indirizzo. Un indirizzo >>. Ed è l'indirizzo, nel caso del ciao, il primo carattere in quella parola, che è h. Quindi s è, in questo particolare esempio, l'indirizzo di h. Che cosa vuol dire fare s + i? Beh, i inizia a 0 in questo ciclo for. Abbiamo fatto molte volte. Mi sta per andare fino alla lunghezza della stringa, a quanto pare. Così la prima iterazione del ciclo, i è ovviamente 0. Quindi questa espressione sta dicendo s + i - piuttosto, s +0-che è, ovviamente, solo s. Allora, qual è * s qui? Ora stiamo usando la stella in un modo leggermente diverso. Lasciatemi andare avanti e di sbarazzarsi di t perché abbiamo finito parlando di t e copie di s. Ora vogliamo solo raccontare una storia che coinvolge s. E così, in questo momento, dopo aver tipo string, il nostro mondo sembra abbastanza come prima con solo s memorizzare l'indirizzo di h e più in generale indicando la stringa ciao. Se ora fare una linea come * (s + i), cerchiamo di provare questo fuori. Quindi * (s + i). Vorrei semplificare questo perché questo è 0, quindi questo è * (s +0). Beh, aspetta un attimo. Semplificare ulteriormente. Questo è * (s). Bene, ora le parentesi sono un po 'stupido, quindi ora limitiamoci a fare * s. Così nella prima iterazione del ciclo, quella linea che è evidenziata, 26, è più o meno equivalente alla stampa di questo. Qual è il tipo di dati di * s? In questo contesto, perché la stella sembra essere vicino alla stessa s, ma più specificamente, perché non siamo più dichiarando s, non stiamo creando una variabile di più, non c'è alcuna menzione di char * in linea 26, non c'è alcuna menzione della stringa parola chiave, ci sono solo utilizzando una variabile chiamata s, si scopre ora la stella è leggermente diverso e, certamente, confondendo significato. * S qui significa aprire l'indirizzo in s e stampa tutto ciò che è lì. Così s è qui, * s è - un po 'come Chutes and Ladders, seguite la freccia - qui. Quindi questo è * s. Quindi, ciò che viene stampato sulla prima iterazione di questo ciclo in linea 26? Ho stampare% c, che è il segnaposto per un carattere, poi un \ n per una nuova linea. * (S + i) dove i è 0 è proprio questo. Allora, cosa char devo posizionare in per c%? H. Nella prossima iterazione del ciclo - probabilmente si può vedere dove questo sta andando - la prossima iterazione i è ovviamente 1, quindi questo significa s +1, e poi ora ho bisogno delle parentesi, perché ora la stella deve dire vai a indirizzo di memoria s +1. Che cosa è s? Facciamo rotolare indietro nel tempo e dire la freccia ora non è in realtà ci fa un favore. Che è più specificamente dire che questa è la memorizzazione del numero 123 poiché l'inizio di questa stringa ciao, questo è l'indirizzo 123, questo è 124, e così via. Così il seconda iterazione quando dico s +1, è come dire 123 +1, altrimenti noto come 124, quindi cosa char viene stampato sulla seconda iterazione? E in indirizzo di memoria 124. Poi di nuovo +, 125, 126, 127, e questo ciclo si ferma per fortuna prima di arrivare qui perché sto utilizzando strlen per assicurarsi che io non conta troppo alto. In modo che esso è troppo. Ancora una volta, questo è come se avessimo fatto una settimana fa. Lascia che te lo scrivi sulla riga sotto, anche se non vogliamo fare entrambe le cose. Questo è identico a questo momento. Così, anche se s è una stringa, come abbiamo chiamando da settimane, s è davvero un char *. Quindi, se vogliamo essere anale super, è davvero giusto per scrivere il carattere specifico nella posizione esima utilizzando questi indirizzi numerici e di questo operatore stelle, ma, francamente, questo è più pulita così tanto. Quindi questo non è male. Non c'è ragione di smettere di fare la linea 27 qui, ma 26 è funzionalmente lo stesso, ed è funzionalmente uguale esattamente per i motivi che abbiamo discusso finora. E, infine, 29 è solo una buona pratica. Chiamare gratis s significa che ora si sta dando indietro la memoria che ti ha dato GetString perché ancora una volta, come ho già detto Lunedi, GetString per settimane ha introdotto un bug nel codice. Il codice per settimane ha avuto perdite di memoria in base al quale si è chiesto GetString per la memoria, ma non sei mai stato dando indietro. E che è stata scelta da noi pedagogicamente perché è davvero troppo per pensare presto. Ma ora abbiamo bisogno di più simmetria. Se si chiede il computer per la memoria, come è il caso per GetString, come nel caso apparentemente per malloc, è necessario ora per pset 4 e successivi anche liberi la memoria del genere. Si noti che questo è diverso dal dire n int. Non è necessario per liberare questo perché tu non abbia chiamato GetString e che non hai chiamato malloc. E anche se si chiama GetInt come vedremo finalmente vedere, GetInt non alloca la memoria per voi, perché si può effettivamente passare in giro interi e carri allegorici e salmerini solo il modo in cui abbiamo fatto per settimane. Strings, però, sono speciali perché in realtà sono la concatenazione di caratteri multipli. Quindi, sono solo diversi da caratteri e carri allegorici e int e simili. Ma torneremo a che tra non molto. Tutte le domande poi su questo inizio di puntatori? Gia '. [Domanda studente incomprensibile] Ah, bella domanda. Una delle poche cose C fa realmente per voi, che è comodo, si capisce che per ciò che si è la dimensione del tipo di dati e poi fa quel tipo di moltiplicazione per voi. Questo non è pertinente nel caso di caratteri perché quasi sempre un char è 1 byte, quindi questo funziona. Ma per il bene della discussione, se si stesse effettivamente stampando interi e si stava tentando di stampare un valore s che stava indicando un numero intero, allo stesso modo non si avrebbe bisogno di fare + 4 * i solo perché un int è di 4 byte. Aritmetica dei puntatori significa che il compilatore C e fare tutto ciò che la matematica per voi. Tutto quello che dovete interessa è il conteggio in una sorta di senso umano. Gia '. [Studente] Se si dichiara una stringa all'interno di un ciclo for, devi liberare in un secondo momento? Bella domanda. Se si dichiara una stringa all'interno del ciclo for, hai bisogno di liberare in un secondo momento? Hai solo bisogno di liberare la memoria che viene allocata con GetString o con malloc. Quindi, se hai appena detto una cosa del genere - mi permetta di mettere le parentesi graffe ora così tutto il codice è associato. Se hai fatto qualcosa, anche se buggily, in questo modo, char * t = s, non c'è bisogno di t t liberi, perché non ha comportato alcuna menzione di malloc o GetString. Se invece avete fatto questo, GetString, allora sì, si avrebbe bisogno di t liberi. E infatti, l'unica possibilità per farlo è ora all'interno di questo ciclo, per lo stesso problema di portata che abbiamo discusso in passato. In caso contrario, si sarebbe l'allocazione di memoria, l'allocazione di memoria, l'allocazione di memoria, e alla fine del programma perché sei fuori di tale ciclo, t non esiste, ma non hai mai detto che il sistema operativo che non hai bisogno di quel ricordo più. E in poco tempo, per pset 4 o 5 ti equipaggiare con un programma chiamato Valgrind, che è simile nello spirito a GDB in quanto è ottenuto un po 'di un'interfaccia arcano, ma il suo scopo nella vita è quello di aiutarvi. E Valgrind è un programma che in futuro la ricerca dei programmi alla ricerca di perdite di memoria, sia da GetString o malloc, che vedremo iniziare a utilizzare sempre più come smettere di usare il CS50 libreria di tanto. Finalmente ora abbiamo una sorta di vocabolario e il tipo di modello mentale in teoria con cui risolvere questo programma danneggiato. Quindi, in questo programma danneggiato, scambio lavora all'interno di swap, ma non è mai effettivamente lavorato in passato principale perché principale di x e y, richiamo, e quelle sono state approvate in dai valori, per così dire. Copie di loro sono stati dati da scambiare. Entro la fine di swap, a e b era stata effettivamente scambiati, ma, naturalmente, x e y, come abbiamo detto il Lunedi, non era stato. Quindi propongo in verde qui che questo è in realtà la soluzione qui. E in realtà, vorrei muovere le stelle solo per essere coerenti anche se, ancora una volta, funzionalmente questo non importa. Nelle settimane successive spiegheremo quando e perché è importante. Quindi, in verde ora è una soluzione. Francamente, sembra un bel po 'incasinato perché ho tutte queste stelle. Vorrei sottolineare una cosa. La riga superiore qui dove dice int * a, int * b è fondamentalmente facendo la stessa cosa come ha sempre fatto. Si dichiara 2 argomenti o parametri di scambiare, il primo dei quali è un puntatore int chiamato, il secondo dei quali è un puntatore int chiamato b. L'unica cosa che c'è di nuovo a questo punto è il fatto che c'è una stella là. Che cosa vuol dire? A non è un int, b non è un int. A è l'indirizzo di un int e b è l'indirizzo di un altro int. Qui sotto, questo è dove devo ammettere C si confonde. Ora stiamo usando una stella, ma ha un significato diverso in questo contesto. Perché non stiamo dichiarare puntatori come noi siamo qui, qui stiamo dereferenziazione cose. Tecnicamente, quindi, la stella in questo contesto della linea di primo, secondo, e il terzo all'interno di swap è l'operatore dereference, che significa semplicemente andare lì. Così come il mio dito seguì la freccia h, * Un mezzo vai a questo indirizzo e trovare me la int che c'è. * Mezzi b aprire l'indirizzo e mi passi quello che c'è. Quindi cerchiamo di ridisegnare l'immagine da Lunedi ora utilizzando una pila di frame, il cui fondo sarà principale, quella superiore del quale sarà swap, in modo che il nostro mondo sembra, proprio come Lunedi, come questo. Ecco un pezzo di memoria che si sta per utilizzare. Ricordiamo dal Lunedi che il programma appena avuto 2 variabili, uno chiamato x e uno chiamato y, e avevo messo i numeri 1 e 2 lì. Ora, quando chiamo scambiare come ho fatto il Lunedi, in precedenza, quando ho usato la versione rossa di questo programma, che si presenta come tale, Ho ottenuto 2 parametri, a e b, e che cosa si scrive qui e qui? Solo 1 e 2, letteralmente copie di x e y. Oggi cambiare questa situazione. Oggi, invece di passare in interi a e b che andremo a passare in 2 indirizzi. Tali indirizzi capita di puntare a int, ma tali indirizzi non si stanno int. Sono indirizzi. E 'come un indirizzo postale, invece. Così ora abbiamo bisogno di dare me stessa dettaglio in più sullo schermo. Questa è la memoria del mio computer come è stato per tutto il giorno. Ora abbiamo bisogno di uno schema di numerazione arbitraria. Quindi, diciamo solo che, per caso, che questo è l'indirizzo di memoria 123, 124. Diciamo solo che questo è 125, questo è 126, e così via, ma questo è del tutto arbitraria. Abbiamo solo bisogno di un po 'di schema di numerazione nella mia memoria. Così ora quando ho effettivamente passano in x e y, io non ho intenzione di passare in x e y; Ho intenzione di passare l'indirizzo postale, per così dire, di x e di y in modo che ciò che viene memorizzato qui e qui non è 1 e 2, ma se si può vedere il mio testo di piccole dimensioni, ciò che viene passato qui e qui? [Risposta degli studenti incomprensibile] >> Esattamente. 123 viene messo qui e 124 viene messo qui. Ora, perché ho usato la stella in questo modo primissima linea qui in alto, il mio programma sa solo che 123 e 124, anche se sono ovviamente numeri interi che un essere umano possa notare, devono essere interpretati come indirizzi, indirizzi numerici. Essi non sono in sé e per sé interi, sono gli indirizzi, e questo perché ho esplicitamente messo le stelle lì. Così ora la mia prima linea, secondo e terzo di codice vero e proprio quello che succede qui? Facciamo disegnare il resto del quadro. Tmp è proprio come è stato il Lunedi. Niente di speciale tmp. E 'solo un locale variabile a 32 bit, e dentro di che sto a quanto pare la memorizzazione del valore di * a. Ora, se ho appena detto tmp = a, che cosa ho messo qui? >> [Studente] 123. 123. Ma non è quello che sto facendo. Sto dicendo tmp = * a. Mezzi Stelle andare lì. Così qui è una, 123. Come ci vado? Finta come se ci fosse una freccia. Beh, eccolo, 1. Quindi, ciò che viene memorizzato in tmp, a quanto pare? Situato a solo 1. In altre parole, è tmp * a *, un mezzo aprire l'indirizzo che è attualmente in uno, che apparentemente è 123. Ok, qui siamo nella posizione 123, vedo il numero 1, così ho intenzione di mettere il numero 1 lì. Ora cosa faccio nella riga 2, * a * b =? Questo è un po 'più complicato perché ora quello che è un? È 123. Quindi * a è dove? Proprio dove ero prima. Quindi, andare lì. Va bene. Ora, infine, e poi finalmente questa inizierà ad avere un senso, si spera, * B significa ciò che è in b? 124. Quindi ho bisogno di andare lì, che è 2. Quindi cosa ho messo dove? 2 va in questa sede in quanto va in * b * a. Quindi lo farò. E si può già vedere, forse, che siamo così molto più vicini per risolvere questo stupido, semplice problema corretto per la prima volta perché ora abbiamo ancora un ricordo di ciò che era x, abbiamo 2 copie, è vero, di y, ma la linea 3 ora dice * b. Quindi, ecco b. * Mezzi b andarci. Allora, dove è la posizione 124? E 'a quanto pare qui. Quindi cosa ho messo qui? Ovviamente, tmp. Così ora lo faccio. Così ho uno qui e 2 qui. E ora che dire di tutto questo, la 123, la 124, e il 1? Non appena ritorna swap, questa memoria è buono come perdita perché non appena ritorni di swap, il sistema operativo è libera di utilizzare la memoria di nuovo in futuro. Solo memoria principale in fondo questo cosiddetto stack di bastoni intorno. E così finalmente abbiamo ora una versione funzionante. Lasciami andare in swap.c, e notare quanto segue. Nella parte superiore del programma che ho cambiato il mio prototipo di essere int * a, int * b. Quindi l'unica cosa che ho cambiato per andare dal rosso, che era male, al verde, che è buono, si ho aggiunto queste stelle oggi. Ma poi qui in sé scambiare ho dovuto copiare, incollare quello che era solo nella diapositiva. Ho qui una stella, stella qui - che corrisponde al prototipo - e poi tutte queste cose hanno ora stelle tranne per tmp perché l'uso di una variabile temporanea, non c'è nulla di nuovo lì. Ho solo bisogno di stoccaggio temporaneo per un int. Quindi non abbiamo bisogno di una stella là. Abbiamo solo bisogno la stella in modo da poter attraversare questo tipo di limite arbitrario tra questi 2 fotogrammi nella memoria del mio computer. Ma un'ultima cosa deve cambiare, e si potrebbe averlo già intravisto. Che altra linea è ovviamente diverso ora? >> [Studente] e x. Si ', quindi 25 è l'ultima riga di codice che ho bisogno di cambiare per far funzionare tutto. Una settimana fa e anche il Lunedi linea 25 si presentava così, scambiare x e y, e questo è stato appena rotto, perché se si dice swap (x, y) si stanno dando copie di x e y per scambiare, poi che sta facendo il suo dovere, ma non si è mai realmente cambiando x e y se stesso. Quindi, anche se non hai mai visto questo personaggio prima con la e commerciale nel codice, basta prendere una supposizione. Cosa fa il commerciale fare, a quanto pare? [Studente] prende l'indirizzo. >> Prende l'indirizzo. Così la e commerciale sta dicendo darmi l'indirizzo di x. Chi sa dove si trova? Capita di essere 123. Non mi interessa. Dammi l'indirizzo di x. & Y significa darmi l'indirizzo di y. E a quel punto la storia è perfettamente coerente con l'immagine che ha un momento fa. Quindi devo ammettere che i puntatori, certamente per me quando ho iniziato a imparare questo, erano sicuramente una delle cose più difficili da avvolgere la mia mente intorno. Ma rendersi conto, tanto più che continuare a giocare con questo tipo di cose, se si scomposizione di questo genere super semplice di intellettualmente interessante problemi di soli numeri in movimento in giro, la risposta a un sacco di confusione con i puntatori davvero può essere derivata da queste meccaniche di base. Ecco un indirizzo. Andateci con la stella. O al contrario, ecco una e commerciale. Capire che cosa è in realtà l'indirizzo. Bene. Allora, dove è tutto di questa memoria viene? Abbiamo disegnato questa immagine un paio di volte, e continuo promettente torneremo ad esso, ma qui è la rappresentazione della memoria del computer che è un po 'più marcato della nostra lavagna è qui. Il segmento di testo in alto rappresenta ciò che in rapporto al tuo programma? [Risposta degli studenti incomprensibile] >> Scusa? Dillo di nuovo. [Studente] Il programma vero e proprio. >> Il programma vero e proprio. Così il Clang 0 e 1 che sono stati compilati dopo la scrittura di codice C e quindi eseguire e generando estremità 0s e 1s sull'ottenere nascosto lì in memoria perché quando si fa doppio clic su un'icona sul vostro Mac o PC o eseguire un comando come mario al tuo prompt, il vostro 0 e 1 dal disco vengono caricati in memoria in modo che il computer possa manipolare e li eseguire più rapidamente. Quindi, i dati inizializzati e dati non inizializzati, non parla molto di quelli, ma questi sono solo variabili globali. Inizializzato significa variabili globali che hanno dato valori; inizializzate le variabili globali significa che non hai ancora dare valori. Poi ci sono queste variabili d'ambiente che verrà completamente agitano la mia mano a, ma ci sono e che le cose grandi come il vostro nome utente ed altro tipo di informazioni di livello inferiore. Ma i più succosi pezzi di layout di memoria è questa cosa chiamata lo stack e l'heap. Lo stack di nuovo, per essere chiari, è la memoria che viene utilizzata ogni volta che le funzioni sono chiamate, quando ci sono le variabili locali e ogni volta che ci sono parametri passati in giro. Tutto questo avviene nella pila. L'heap non abbiamo parlato, ma prendere una congettura che usa l'heap. Solo un pezzo diverso di memoria. Succede da trarre qui in alto, ma questa è una convenzione arbitraria pittorica. Chi apparentemente usando la memoria dal mucchio per settimane? E 'tecnicamente si, ma indirettamente. >> [Studente] GetString. GetString e malloc. Quindi, ecco la differenza fondamentale. Sai per le ultime settimane che, se avete bisogno di memoria, ma soltanto dichiarare una variabile. Se avete bisogno di un sacco di memoria, dichiarare un array proprio all'interno della vostra funzione. Ma il problema che abbiamo di fronte è tenuto, se si dichiarano delle variabili locali all'interno di funzioni, non appena la funzione ritorna, cosa succede alla memoria e quelle variabili? Solo una sorta di non è più tuo, giusto? Scompare appena sorta di concettualmente. E 'ancora fisicamente lì, ovviamente, ma non è più il diritto di usare. Questo è ovviamente un problema se si desidera scrivere funzioni della vita che in realtà allocare la memoria e non restituire immediatamente. Caso in questione: GetString scopo nella vita è di non avere idea in anticipo quanto grande di una stringa ho intenzione di scrivere alla tastiera, ma è avuto modo di essere in grado di allocare memoria per contenere David o ciao o un saggio intero che l'utente potrebbe aver digitato trovi Così GetString ha utilizzato malloc. Malloc quindi deve essere utilizzata non la pila; invece che sta utilizzando questa cosa chiamata heap. Non c'è niente di diverso la memoria. Non è più veloce o più lento o qualcosa di simile. E 'solo fisicamente in una posizione diversa. Ma la regola è che la memoria che viene allocata nell'heap non potrà mai essere portato via da te finché non viene chiamato - prendere una congettura - libero. Al contrario, la memoria si chiede in pila da solo dichiarando un array o la dichiarazione di una variabile come abbiamo fatto per settimane, che di default finisce in pila. E che funziona grande 90% del tempo, ma in quelle occasioni rare in cui si desidera allocare la memoria e tenerlo in giro, allora avete bisogno di usare una funzione come malloc. Oppure, abbiamo utilizzato una funzione come GetString, che a sua volta usa malloc. Vediamo dove questo potrebbe rompersi e quindi dare uno sguardo a Binky. Torneremo a quella del futuro. Ecco un programma super semplice che nelle prime 2 righe fa che cosa? In inglese, che cosa queste prime 2 righe di codice all'interno del principale? [Risposta degli studenti incomprensibile] Attento. Non mi dà l'indirizzo di x o y. [Studente] Dà puntatori a int. Good >>. Dammi due puntatori a interi. In altre parole, mi ha regalato due pezzi di memoria che tengo disegno oggi, anche se l'ho cancellato ora, come quadrati. Dammi due blocchi di memoria, uno chiamato x, uno chiamato y - prima li ho chiamati s e t - e qual è il tipo di quel pezzo di memoria? E 'intenzione di memorizzare un indirizzo. E 'di tipo int *. Quindi, l'indirizzo di un int alla fine vivere in x, l'indirizzo di un int alla fine vivere in y, ma inizialmente, quello che c'è dentro di x e y? Chi lo sa? Garbage valori. Non ha nulla a che fare con i puntatori. Se non abbiamo messo qualcosa lì, chissà cosa c'è in realtà c'è? Ora, x. Quello che succede qui? Questo è legittimo perché ora x è un puntatore. E 'un int *. Questo significa che posso mettere in x l'indirizzo di qualche pezzo di memoria. Cosa fa malloc ritorna? Perfetto, restituisce gli indirizzi, l'indirizzo del primo byte in un pezzo intero di memoria. Quanti byte è questo apparentemente ripartisce, per esempio, nel dispositivo? Qual è la dimensione di un int? 4. Se si pensa di nuovo a settimana 1, non è super importante ricordare sempre che, ma in questo caso è utile sapere, 4 byte. Quindi questo è l'allocazione sul mucchio 4 byte e sta restituendo l'indirizzo del primo che me arbitrariamente. Ora, che cosa sta facendo x? A * x = 42 sta facendo cosa? Se a questo punto della storia si ha x, che si presenta così con un certo valore di spazzatura, questo è ora y con un certo valore di immondizia, ora nella riga 3 ho assegnato 4 byte. Questa foto appare essenzialmente come questo. O, più precisamente, se questo è l'indirizzo arbitrario 123, questo è ciò che la nostra storia appare così. * X = 42, ora che cosa? Questo significa andare a 123 indirizzo e inserire il numero 42 c'è. Non ho bisogno di disegnare queste linee, perché non stiamo facendo le stringhe. Avrei dovuto scritto come questo, e solo per amor di dimostrazione, 42 come di tipo int occupa molto spazio, 4 byte. Ecco, questo è quello che è successo lì, ma c'è un problema ora. * Y = 13. Che cosa sta per succedere qui? Il problema è y * nel nostro mondo semplificato significa semplicemente aprire l'indirizzo in y. Cosa c'è in y? È certo valore immondizia. Quindi supponiamo che tale valore è 5551212 spazzatura, qualcosa di pazzo del genere. * Mezzi y andare ad affrontare 5551212. E 'come qui. Non esiste, per esempio. Così * y diventa 13 mezzi che sto cercando di disegnare 13 qui. Non esiste. Ho superato il segmento della lavagna. Quali sono i vantaggi? Questo messaggio di errore criptico segmentazione perché sto cercando di mettere in memoria un valore come 13 in un luogo che non esiste. Il resto del programma potrebbe funzionare bene, ma fino a quel momento non è così. Quindi, cerchiamo di raccontare questa storia. Torneremo a che una volta che abbiamo parlato di esagono. Torniamo a questa e concludere con questa cosa chiamata Binky, che richiamo è un professore di Stanford seduto a casa a giocare con claymation, per raccontare la storia del proprio questo stesso programma. E 'solo circa 3 minuti. Qui abbiamo Binky. [Altoparlante maschio in video] Hey Binky, svegliati. E 'tempo per il divertimento puntatore. [Binky] Che cos'è? Ulteriori informazioni sui puntatori? Oh, goody! [Altoparlante maschio] Beh, per iniziare, credo che avremo bisogno di un paio di puntatori. [Binky] Ok. Questo codice assegna 2 puntatori che può puntare a numeri interi. [Speaker maschile] Ok. Bene, vedo che i 2 puntatori, ma non sembrano puntare a nulla. [Binky] Proprio così. Inizialmente, i puntatori non indicano nulla. Le cose a cui puntano sono chiamati pointees, e crearle è una fase separata. [Altoparlante maschio] Oh, giusto, giusto. Sapevo che. Le pointees sono separati. Er, così come si fa assegnare un pointee? [Binky] Ok. Questo codice assegna un pointee nuovo intero, e questa parte imposta x per puntare ad esso. [Altoparlante maschio] Ehi, che sembra migliore. Così ne fanno fare qualcosa. >> [Binky] Ok. Torno dereference x il puntatore per memorizzare il numero 42 nella sua pointee. Per questo trucco ho bisogno la mia bacchetta magica di dereferenziazione. [Altoparlante maschio] La tua bacchetta magica di dereferenziazione? E 'fantastico. [Binky] Questo è ciò che il codice sorgente. Mi limiterò a impostare il numero e la ... [Popping sound] [Altoparlante maschio] Ehi, guarda, non ci va. Così facendo una dereference sul x segue la freccia per accedere al suo pointee, in questo caso per memorizzare 42 dentro. Ehi, provare a utilizzare per memorizzare il numero 13 attraverso l'altro puntatore, y. [Binky] Ok. Vado qui a y e di ottenere il numero 13 creato e poi prendere la bacchetta di dereference e solo ... [Ronzio] Whoa! [Maschio altoparlante] Oh, hey, che non ha funzionato. Dire, Binky, non credo che dereferenziazione y è una buona idea Poiché l'installazione di pointee è una fase separata e non credo che abbiamo mai fatto. [Binky] Hmm, buon punto. [Speaker maschile] Si '. Abbiamo assegnato il puntatore y ma non abbiamo mai impostato per puntare a un pointee. [Binky] Hmm, molto attento. [Altoparlante maschio] Ehi, stai cercando bene lì, Binky. Si può risolvere il problema in modo che i punti y al pointee stesso x? >> [Binky] Certo. Userò la mia bacchetta magica di assegnazione puntatore. [Speaker maschile] è che sarà un problema come prima? [Binky] No, questo non tocca i pointees. Cambia solo un puntatore per puntare la stessa cosa di un altro. [Popping sound] [Altoparlante maschio] Oh, capisco. Ora i punti y al posto stesso x. Quindi aspetta. Ora y è fissa. Ha un pointee. Così si può provare la bacchetta di dereference di nuovo per inviare i 13 più. [Binky] Uh, va bene. Qui va. [Popping sound] [Altoparlante maschio] Ehi, guarda un po '. Ora dereferencing opere su y. E poiché i puntatori sono la condivisione che si pointee, entrambi vedere la 13. [Binky] Sì, la condivisione. Qualunque cosa. Quindi, abbiamo intenzione di cambiare posti ora? [Altoparlante maschio] Oh, guarda, siamo fuori tempo. >> [Binky] Ma - [Altoparlante maschio] Basta ricordare le 3 regole del puntatore. Numero 1, la struttura di base è che si dispone di un puntatore che punta verso un pointee. Ma il puntatore e pointee sono separati, e l'errore comune è quello di creare un puntatore ma dimenticare di dare un pointee. Numero 2, dereferenziazione puntatore inizia il puntatore e segue la sua freccia sopra per accedere alla pointee. Come tutti sappiamo, questo funziona solo se c'è un pointee, che tipo di torna alla regola numero 1. Numero 3, l'assegnazione puntatore assume un puntatore e la cambia per puntare alla stessa pointee altro puntatore. Così, dopo l'assegnazione, i 2 puntatori punterà alla pointee stesso. A volte che si chiama condivisione. E questo è tutto ciò che devi fare davvero. Bye-bye adesso. Questo è Binky. Questo è CS50. Ci vediamo la prossima settimana. [Applausi] [CS50.TV]