DAVID MALAN: Va bene, bentornato. Questo è CS50. Questo è l'inizio della settimana di sette. Quindi è stato un po ', così ho pensato di fare un giro vorticoso di dove siamo lasciato e dove stiamo andando adesso. Quindi questa cosa qui potrebbe avere causato qualche angoscia in un primo momento. Ma si spera, si sta cominciando a ambientarsi a ciò che questo denota qui - stelle che rappresenta un puntatore, che è proprio quello che, in termini più povere? Quindi si tratta di un indirizzo. Quindi è l'indirizzo del qualcosa in memoria. E abbiamo iniziato a staccare gli strati un paio di settimane fa, le cose come GetString e altre funzioni tutto questo tempo sono state tornando indirizzi delle cose in memoria, come la indirizzo del primo carattere alcuni sequenza. Così abbiamo anche introdotto valgrind, che potrai iniziare a utilizzare per questo problema impostare, in particolare per il successivo problema regolato pure. E valgrind fa ciò per noi? Si verifica la presenza di perdite di memoria, ed è verifica anche per l'abuso di memoria. Si può, con una certa probabilità, di rilevare se il codice sta per toccare la memoria che semplicemente non dovrebbe. Quindi non necessariamente una perdita, ma se si andare oltre i confini di alcuni matrice, e che effettivamente esegue valgrind e indurre comportamenti che mentre valgrind è in esecuzione nel vostro programma è in esecuzione all'interno di esso, si otterrà messaggi come questo - "non valido scrivono di dimensioni 4 ", che, ricordano un paio di settimane fa significava che avevo accidentalmente come su un int troppo al di là dei confini di un array. E così formato 4 significa qui la dimensione di quella particolare int. Quindi prendere rassicurazione nel fatto che Uscita di valgrind, il formato di esso, è semplicemente atroce. E 'davvero difficile da vedere attraverso il disordine per le informazioni interessanti. Quindi quello che abbiamo fatto qui è solo estratto alcune delle coppie di più linee interessanti. Ma rendersi conto che l'80% dei valgrind di uscita sta per essere un po 'un distrazione. Basta cercare modelli come questi - valida ragione, non valida leggere, 40 byte e qualche numero di blocchi sono sicuramente perse, parole chiave come quella. E ciò che si spera, vedi è un po 'di tipo di traccia di quale funzione del errore è in realtà dentro In questo caso qui, in quale linea di il mio codice è stato l'errore pare? 26 in un file denominato memory.c, che era l'esempio stavamo giocando con al tempo. Quindi probabilmente non è in malloc. Probabilmente era nel mio codice, invece. Quindi vedremo di nuovo e di nuovo in breve tempo. Quindi scanf, questo è venuto su in un paio di forme finora. Abbiamo visto brevemente sscanf. Era qualcosa varie si tuffò nel vostro i preparativi per il quiz. E scanf è in realtà ciò che il CS50 biblioteca ha usato sotto la cappa per un bel po 'di tempo per per ottenere input da parte dell'utente. Per esempio, se mi sposto verso il CS50 apparecchio qui, lasciatemi aprire un esempio oggi che si chiama scanf-0.C Ed è super semplice. E 'solo un paio di righe di codice. Ma dimostra veramente come getInt ha lavorato tutto questo tempo. In questo programma, in linea 16 , Si noti che dichiaro un int. Quindi niente puntatori, nulla di magico lì, solo un int. Poi, nella riga 17, i Chiede il all'utente un numero, prego. Poi, verso la fine del 18, io uso scanf qui. E ho specificato, un po 'come printf, che mi aspetto preventivo unquote cento i. Quindi per cento Io, naturalmente, denota un int. Ma notare ciò che la seconda argomento di scanf è. Come descriveresti il ​​secondo argomento dopo la virgola? Che cosa è? E 'l'indirizzo di x. Quindi questo è utile perché fornendo scanf con l'indirizzo di x, che cosa fa che autorizzano tale funzionalità? Non basta andare lì, ma anche fare che cosa? Apportare una modifica ad esso. Perché si può andare lì, è una sorta di come una mappa per una locazione di memoria. E finché si fornisce scanf, o qualsiasi funzione con una tale mappa, che funzione può andare lì, e non solo guardare il valore, ma può anche modificare tale valore, che è utile se lo scopo nella vita è quello di scanf scansione input dall'utente, specificamente dalla tastiera. E la f denota formattato, proprio come printf, il f denota un formattata stringa che si desidera stampare. Così, in breve, la linea 18 dice semplicemente, provare a leggere un int da parte dell'utente del tastiera e conservarlo all'interno di x, a qualunque indirizzo di x si trova a vivere in. E poi, infine, la linea 19 dice solo, grazie per l'int, in questo caso. Così mi permetta di andare avanti e fare questo. Quindi, fare scanf 0. Lasciami andare avanti e lo zoom dentro Vado a correre con questo puntini tagliare scanf 0. Numero, per favore? 50. Grazie per il 50. Quindi è abbastanza semplice. Ora che cosa è che non facendo? Non sta facendo un sacco di controllo degli errori. Per esempio, se non collaboro, e io non digitare un numero, ma invece scrivo qualcosa come "ciao" questo è solo un po 'strano. E così una delle cose che il CS50 biblioteca ha fatto per noi per un po ' tempo è che reprompting e reprompting. Il nuovo tentativo frase richiamo era in cs50.c, e questo è il motivo che getInt in la libreria CS50 è in realtà un intero mucchio di linee lunghe, perché siamo controllando per cose stupide come questa. Forse l'utente non dà noi, infatti, un int? Ci ha lui o lei dare qualcosa come una lettera alfabetica? Se così, vogliamo rilevare che e urlare contro di loro. Ma le cose si fanno più interessanti Nel prossimo esempio. Se vado a scanf-1.c, qual è quello cosa che è cambiato radicalmente in prossimo esempio? Sto utilizzando char *, naturalmente, invece di int. Quindi questo è interessante, perché char *, ricordiamo, è in realtà solo la stessa cosa di stringa. Così ci si sente come forse questo è un super- semplice implementazione di GetString. Ma ho sfogliato lo strato della biblioteca CS50, quindi sono chiamare questo char * ora. Così vediamo dove, se da nessuna parte, abbiamo sbagliato. Linea 17 - Io dico di nuovo, per favore mi dia qualcosa, in questo caso, una stringa. E poi nella riga successiva, chiamo scanf, nuovamente, dando un codice di formato, ma questa volta percento s. E poi questa volta, sono dandogli buffer. Ora notate, non sto usando la e commerciale. Ma il motivo è che probabilmente bene qui? Perché ciò che è già tampone? E 'già un puntatore. E 'già un indirizzo. E diciamo questa parola "confondere", mi permetta basta chiamare s, per esempio, per semplicità. Ma l'ho chiamata tampone, perché in generale, in programmazione, se si dispone di un pezzo di memoria, che una stringa davvero semplicemente è, si potrebbe chiamare un buffer. E 'un posto per memorizzare le informazioni. Simile a cose come YouTube, quando stanno tampone, per così dire, che semplicemente significa che è il download di bit da Internet e la loro memorizzazione in un matrice locale, un pezzo locale di memoria in modo da che si può guardare in un secondo momento senza esso saltare o appeso ti durante la riproduzione. Quindi c'è un problema qui, però, perché ti sto dicendo scanf, si aspettano un stringa dall'utente. Ecco l'indirizzo del un pezzo di memoria. Metti che stringa lì. Perché è quello legato dare noi guai, però? Che cos'è? Sono autorizzato ad accedere quella parte di memoria? Sai, io non lo so. Perché è tampone stato inizializzato a qualcosa? Non proprio. E quindi è quello che abbiamo finora chiamato un valore spazzatura, che non è una parola formale. Significa solo non abbiamo idea di cosa bit sono all'interno dei quattro byte che Ho assegnato come buffer. Non ho chiamato malloc. Non ho assolutamente chiamato GetString. Quindi, chi sa che cosa è in realtà all'interno di tampone? Eppure raccontando scanf alla cieca, andare lì e mettere tutto ciò che l'utente ha digitato. Quindi, ciò che rischia di provocare nel nostro codice, se lo usiamo? Probabilmente un segmentation fault. Forse no, ma probabilmente un segmentation fault. E dico forse no, perché a volte si fa, a volte non si ottiene un segfault. A volte basta avere fortuna, ma sta comunque andando essere un bug nel nostro programma. Quindi, mi permetta di andare avanti e compilare questo. Ho intenzione di farlo nel modo della vecchia scuola. Così clang dash 0, scanf-1, scanf-1.c, Enter. Ops, troppo vecchia scuola. Vediamo. Dove ho? Oh, buffer di char *. Oh, grazie - Salva, OK - molto vecchia scuola. Va bene, e 'passato un po'. Così ho appena salvato il file dopo fare quella temporanea modificare un momento fa. E ora ho compilato la manualmente con Clang. E ora ho intenzione di andare avanti ed eseguire scanf-1, Invio. String per favore. Io digitare "ciao". Ed ora, ecco dove, francamente, printf si è un po 'fastidioso. In realtà non è intenzione di segfault in questo caso. Printf è un po 'speciale, perché è così super comunemente utilizzato che essenzialmente printf sta facendo un favore e realizzando, questo non è un puntatore valido. Mi permetta di prendere su di me per stampare solo in parentesi nullo, anche anche se non è necessariamente quello che noi ci aspettavamo. Quindi non possiamo davvero facilmente indurre una segfault con questo, ma è chiaro che questo non è il comportamento che volevo. Quindi qual è la soluzione più semplice? Beh, in scanf-2, lasciatemi propongo invece che in realtà solo l'assegnazione di un char *, mi permetta di essere un po 'più intelligente questo, e mi permetta di allocare il buffer come una sequenza di 16 caratteri. Così posso fare questo in un paio di modi. Potrei assolutamente usare malloc. Ma posso tornare a due settimane quando Ho solo bisogno di un intero gruppo di personaggi. Questo è solo un array. Così mi permetta, invece ridefinire tampone ad essere un array di 16 caratteri. E ora, quando passo buffer in - e questo è qualcosa che non abbiamo parlare in due settimane - ma si può trattare un array come anche se si tratta di un indirizzo. Tecnicamente, come abbiamo visto, sono un po 'diverso. Ma scanf non mente se si passa il nome di un array, perché ciò che Clang farà per noi è essenzialmente curare il nome di quella matrice come il indirizzo del blocco di 16 byte. Quindi questo è migliore. Questo significa che ora posso spera effettuare le seguenti operazioni. Permettetemi di zoom out per un momento e fare fare scanf-2, compilato OK. Ora vorrei fare avuto barra scanf-2. String per favore. "Ciao." E sembrava funzionare questa volta. Ma qualcuno può proporre uno scenario in cui potrebbe non funzionare ancora? Sì? Qualcosa di più di 16 caratteri. E in realtà, possiamo essere un po 'più precisi. Qualcosa di più poi 15 caratteri, perché in realtà abbiamo bisogno di tenere a mente che abbiamo bisogno che il backslash a zero implicitamente alla fine della stringa, che è una parte scanf volontà tipicamente prendersi cura di per noi. Quindi, mi permetta di fare una cosa del genere - a volte possiamo solo lasciarlo così. OK, ora abbiamo indotto il nostro errore di segmentazione. Perché? Perché ho scritto per più di 15 personaggi, e così abbiamo effettivamente memoria toccato che ho effettivamente non dovrebbe avere. Così che cosa è veramente la soluzione qui? Beh, e se abbiamo bisogno di una stringa più lunga? Bene, noi forse facciamo 32 byte. Beh, e se questo non è abbastanza lungo? Come circa 64 byte? E se questo non è abbastanza lungo? Come circa 128 o 200 byte? Che cosa è davvero la soluzione qui in caso generale, se non sappiamo in anticipare ciò che l'utente sta per digitare? E 'solo una specie di grande dolore nel culo, ad essere onesti, è per questo che la CS50 biblioteca dispone di una dozzina di linee di codice che collettivamente implementare GetString stringa in un modo che noi non sappiamo deve conoscere in anticipo l' utente sta per digitare. In particolare, se si guarda indietro a cs50.c da due settimane fa, si vedrà GetString che realmente fa non usare scanf in questo modo. Piuttosto, si legge un carattere alla volta. Perché l'unica cosa bella di la lettura di un carattere è che possiamo garantire a noi stessi di sempre avere almeno un carattere. Posso solo dichiarare un char, e poi prendere questi passaggi veramente bambino di appena leggere un carattere in in un tempo dalla tastiera. E poi, quello che vedrete GetString fa è ogni volta che si esaurisce, diciamo, 16 byte di memoria, utilizza malloc, o un suo cugino, per allocare più memoria, la copia del vecchio memoria nel nuovo, e poi strisciando lungo, ottenendo un carattere alla volta, e quando si esaurisce di che pezzo di memoria, getta via, palio un pezzo più grande di memoria, copia antica in nuove e ripetizioni. Ed è davvero un dolore da realtà realizzare qualcosa di semplice come ricevendo input da un utente. Così si può usare scanf. È possibile utilizzare le altre funzioni simili. E un sacco di libri di testo e online esempi fanno, ma sono tutti vulnerabili a problemi come questo. E alla fine, ottenendo un segfault è una specie di fastidioso. Non è un bene per l'utente. Ma nel peggiore dei casi, che cosa fa è fondamentalmente mettere il vostro codice a rischio di? Una specie di attacco, potenzialmente. Abbiamo parlato di un attacco del genere - traboccante la pila. Ma in generale, se si è permesso di troppo pieno di un buffer, come abbiamo fatto un paio di settimane fa, con solo la scrittura più di "ciao" in pila, si può infatti assumere, potenzialmente, un computer o almeno avere a dati che non appartiene a voi. Così, in breve, questo è il motivo per cui abbiamo quelle ruote di formazione. Ma ora, cominciamo a toglierli, come i nostri programmi non hanno più bisogno, necessariamente, input dall'utente. Ma nel caso di problema definito sei, il tuo contributo verrà da un enorme file di dizionario con 150 alcuni dispari di mille parole. Così non dovrete preoccuparvi di ingresso arbitrario dell'utente. Vi daremo alcune ipotesi su quel file. Qualsiasi problema puntatori o scanf o l'input dell'utente in generale? Va bene, quindi un rapido sguardo poi in una sola trailing argomento da due settimane fa. E questo era il concetto di una struct. Non che - questa nozione di un struct, che era quello che? Cosa gli struct fare per noi? Definire - scusate? Definire un tipo di variabile. Quindi, più o meno. Stiamo in realtà la combinazione di due argomenti. Quindi, con typedef, ricordare che possiamo dichiarare un tipo di nostro, come un sinonimo, come stringa di char *. Ma usando typedef e struct, possiamo creare davvero le nostre strutture dati. Per esempio, se torno in gedit qui solo per un momento, e vado avanti e di fare qualcosa di simile, mi permetta di risparmiare questo come, diciamo, structs.c temporaneamente, sto solo andando di andare avanti e di includere standardio.h, int void main. E poi qui, suppongo che voglio scrivere un programma che memorizza più studenti provenienti da molteplici case, per esempio. Quindi è come un registrarial banca dati di qualche tipo. Quindi, se ho bisogno del nome di uno studente, ho potrebbe fare qualcosa come char * nome, e farò qualcosa di simile - in realtà, usiamo la libreria CS50 solo per un momento per rendere questo un po 'più semplice, in modo che possiamo prendere in prestito quelle decine di righe di codice. E facciamo solo mantenere le cose semplici. Noi terremo stringa, e ora GetString. Quindi io pretendo ora che ho memorizzato il nome di qualche studente, e la casa di qualche studente, semplicemente usando le variabili come abbiamo fatto noi e in una settimana. Ma suppongo che adesso voglio sostenere studenti più. Va bene, così i miei istinti sono a fare stringa nome2, ottiene GetString, stringa house2 ottiene GetString. E poi il nostro terzo studente, facciamo nome3 GetString. Va bene, quindi questo è sorprendente spera voi come un po 'stupido, perché questo processo è davvero mai andando a finire, e sta solo andando a rendere il mio codice aspetto peggiore e sempre peggio. Ma abbiamo risolto anche questo in due settimane. Qual è stata la nostra soluzione relativamente pulito quando abbiamo avuto più variabili dello stesso tipo di dati, che sono tutti collegati, ma non volevamo questo casino atroce di variabili nome simile? Che cosa abbiamo fatto, invece? Quindi penso che ho sentito un paio di posti. Abbiamo avuto un array. Se si desidera che più istanze di qualcosa, perché non abbiamo pulito tutto questo e basta dire, dammi array chiamato nomi? E per ora, diamo codice duro 3. E poi dammi un altro array chiamato case, e lasciami per codice ora dura 3. E ho massicciamente ripulito l' casino che ho appena creato. Ora, io ho ancora difficile codificato 3, ma anche il 3 potrebbe venire dinamicamente dal utente o argv, o simili. Quindi questo è già più pulito. Ma che cosa è fastidiosa di questo è che ora, anche se un nome è in qualche modo fondamentalmente legata alla casa di uno studente - si tratta di uno studente che ho davvero vuole rappresentare - Ora ho due array paralleli nel senso che sono il stesse dimensioni e nomi staffa 0 presumibilmente mappe a case staffa 0, e nomi di staffa 1 mappe alle case staffa 1. In altre parole, quello degli studenti vive in quella casa, e che altro studente vive in quella casa di altri. Ma sicuramente questo potrebbe essere fatto ancora più pulito. Beh, si può, in effetti. E mi permetta di andare avanti e aprire fino structs.h, e ti vedere questa idea qui. Notate che ho usato typedef, come si accennato poco fa a dichiarare la nostra proprio tipo di dati. Ma sto usando anche questa altra parola chiave chiamata struct che mi dà un nuovo struttura dati. E questa struttura dati rivendico sta avere due cose all'interno esso - una stringa chiamata nome, e una stringa chiamata casa. E il nome che sto per dare a questa struttura dati sta di essere chiamato studente. Potrei chiamare tutto quello che voglio, ma questo rende semanticamente senso per me nella mia mente. Così ora, se apro una versione migliore del programma ho iniziato a scrivere lì, mi permetta di scorrere verso l'alto. E c'è un po 'di più linee di codice qui, ma vorrei concentrarmi per momento su uno. Ho dichiarato un costante cosiddetti studenti e hard coded 3 per ora. Ma ora, notate come pulito il mio codice inizia per arrivare. In linea 22, dichiaro schiera di studenti. E notare che studente è apparentemente ora un tipo di dati. Perché nella parte superiore di questo file, notare Ho incluso il file di intestazione che ho tirato su solo un momento fa. E questo file di intestazione semplicemente aveva questa definizione di uno studente. Così ora, ho creato i miei dati personalizzati tipo quella di C anni gli autori fa non pensare in anticipo. Ma non è un problema. Posso farlo io stesso. Quindi questo è un array chiamato gli studenti, ciascuno dei componenti la cui è una struttura di studente. E voglio che tre di quelli nella matrice. E ora, che cosa fa il resto di questo programma di fare? Avevo bisogno di qualcosa di un po 'arbitraria. Così da linea 24 in poi, I iterazioni da 0 a 3. Ho poi chiedere all'utente di il nome dello studente. E poi io uso GetString come prima. Poi mi chiedo casa dello studente, e io uso GetString come prima. Ma la gara - leggermente nuovo pezzo di sintassi - Posso ancora indice per l'i-esimo studente, ma come faccio ad ottenere i dati specifici campo all'interno della struct? Beh, cosa c'è a quanto pare il nuovo pezzo di sintassi? E 'solo l'operatore punto. Noi non abbiamo veramente visto questo prima. L'hai visto in pset cinque se hai tuffato in già con i file bitmap. Ma il puntino significa solo all'interno di questa struct o più campi, danno dot nome, o darmi casa dot. Ciò significa andare all'interno della struct e ottenere quei particolari settori. Che cosa fa il resto di questo programma? E non è tutto quello sexy. Notate che ho iterazioni da 0 a 3 di nuovo, e io semplicemente creare un inglese frase come così e così è in questo e una casa, passando in nome dot da l'i-esimo degli studenti e il loro casa come bene. E poi, infine, ora inizieremo a ottenere anale su questo, ora che siamo familiarità con ciò che malloc e altre funzioni sono state facendo tutto questo tempo. Perché devo liberare entrambe nome e la casa, anche se io non ha chiamato malloc? GetString fatto. E questo è stato il piccolo sporco segreto per diverse settimane, ma ha GetString state perdite di memoria in tutto il mettere tutto il semestre finora. E Valgrand finalmente rivelare questo a noi. Ma non è un grosso problema, perché so che posso semplicemente liberare il nome e la casa, anche se tecnicamente, per essere super, super sicura, dovrei essere facendo qualche errore di verifica qui. Quali sono il tuo istinto ti dice? Cosa dovrei controllare per prima che io libero Che cosa è un stringa, aka che un char *? Dovrei davvero controllerò se gli studenti Staffa I Nome punto non pari nullo. Poi sarà OK per andare avanti e gratuito tale puntatore, e lo stesso o l'altro uno pure. Se il supporto agli studenti i casa dot non è uguale a null, questo ora vi proteggerà contro la cassa nell'angolo in cui GetString restituisce qualcosa come null. E abbiamo visto un momento fa, printf volontà proteggerci quassù da solo dicendo nullo, il che sta a guardare strano. Ma almeno non sarà segfault, come abbiamo visto. Beh, fammi fare un'altra cosa qui. struct-0 è una specie di stupido programma perché io entro tutti questi dati, e quindi è perso una volta che il programma termina. Ma mi permetta di andare avanti e di fare questo. Permettetemi di fare il terminale finestra un po 'più grande. Permettetemi di fare le struct-1, che è una nuova versione di questo. Io zoomare un po '. E adesso lasciatemi correre dot tagliare le strutture-1. Nome dello studente - David Mather, facciamo Rob Kirkland, facciamo Lauren Leverett. La cosa interessante è ora di gara - e lo so solo questo perché Ho scritto il programma - c'è un file ora sulla mia attuale directory chiamata students.csv. Alcuni di voi potrebbero aver visto questi nel mondo reale. Che cos'è un file CSV? Valori separati da virgole. E 'un po' come un uomo povero di versione di un file Excel. E 'una tabella di righe e colonne che è possibile aprire in un programma come Excel, o numeri su un MAC. E se apro questo file qui su gedit, gara - ed i numeri non ci sono. Questo è solo gedit raccontare mi numeri di riga. Comunicazione relativa alla prima linea di questo file è David e Mather. La prossima linea è Rob virgola Kirkland. E la terza linea è Lauren Leverett virgola. Quindi cosa ho creato? Ora ho scritto un programma in C che effettivamente in grado di generare fogli di calcolo che può essere aperto in programma come Excel. Non tutto ciò che un insieme di dati convincenti, ma se si dispone di molto più grandi blocchi di dati che si vuole realmente manipolare e fare grafici delle e dei come, questo è forse uno modo per creare quei dati. Inoltre, CSV sono in realtà super-comune solo per la memorizzazione di dati semplici - Yahoo Finance, per esempio, se si ottiene quotazioni di borsa tramite la loro cosiddetta API, il servizio gratuito che vi permette di ottenere corrente magazzino up-to-the-date citazioni per le aziende, che di fornire tali dati nel semplice formato super-CSV. Così come abbiamo fatto questo? Ben notare, la maggior parte di questo programma di quasi la stessa. A meno di notare qui, piuttosto che stampa gli studenti fuori, sulla linea 35 poi, io sostengo che sto salvando il studenti su disco, in modo da salvare un file. Così accorgo che sto dichiarando un FILE * - Ora, questo è una specie di un'anomalia in C. Per qualsiasi motivo, FILE è tutto maiuscolo, che non è come la maggior parte di altri tipi di dati in C. Ma questo è un built-in tipo di dati, FILE *. E sto dichiarando un puntatore a un file, è come si può pensare che. fopen significa file aperto. Quale file vuoi aprire? Voglio aprire un file che voglio io arbitrariamente chiamare students.csv. Potrei chiamare che tutto quello che voglio. E poi prendere una supposizione. Che cosa fa il secondo argomento a fopen probabilmente significa? Destra, w per la scrittura, potrebbe essere r per la lettura. C'è una per append se voler aggiungere righe e non sovrascrivere il tutto. Ma voglio solo creare questo file una volta, quindi userò tra virgolette w. E so che da solo dopo aver letto la documentazione, o la pagina man. Se il file non è nullo - in altre parole, se nulla è andato storto lì - mi permetta di scorrere i studenti 0-3. E ora notato che c'è qualcosa sempre in modo leggermente diverso sulla linea 41 qui. Non printf. E 'fprintf per file di printf. Così sta andando a scrivere sul file. Quale file? Quella il cui puntatore si specifica come primo argomento. Poi specifichiamo una stringa di formato. Poi specifichiamo la stringa che vogliamo plug in per cento del primo s, e poi un'altra variabile o la seconda cento s. Allora chiudiamo il file con fclose. Che ho liberare la memoria, come prima, anche se Dovrei tornare indietro e aggiungere alcuni controlli per null. E questo è tutto. fopen, fprintf, fclose mi dà la capacità di creare file di testo. Ora, vedrete in problema insieme a cinque, che coinvolge le immagini, che verrà usato file binari invece. Ma fondamentalmente, l'idea è la stessa, anche se le funzioni di cui avrete bisogno vedere sono un po 'diverso. Così rapido giro, ma si otterrà fin troppo familiare con il file I/O-- ingresso e uscita - con pset cinque. E tutte le domande circa il basi iniziali qui? Sì? Che cosa succede se si tenta di liberare un valore nullo? Credo che, a meno che libero ha ottenuto un po 'più user-friendly, è possibile potenzialmente segfault. Passando NULL è male perché non mi credere gratuito preoccupa di controllare per voi, perché sarebbe potenzialmente uno spreco di tempo per fare per sé tutti nel mondo. Bella domanda, però. Va bene, quindi questo tipo di ottiene noi di un argomento interessante. Il tema del problema insieme cinque è forensics. Almeno questo è una parte del problema proposto. Forensics si riferisce generalmente al recupero di informazioni che possono o Non può essere stato cancellato deliberatamente. E così io ho pensato di dare una rapida assaggio di ciò che sta realmente accadendo tutto questa volta sotto la cofano del vostro computer. Per esempio, se si dispone all'interno della vostra laptop o computer desktop a disco rigido, è sia un meccanico dispositivo che gira in realtà - ci sono cose circolari chiamato piatti che somiglia abbastanza quello che ho appena avuto sullo schermo qui, anche se questo è sempre più vecchia scuola. Si tratta di un tre-e-un-mezzo pollice disco rigido. E tre pollici e mezzo si riferisce di con della cosa quando lo si installa in un computer. Molti di voi ragazzi nel vostro laptop ora avere unità a stato solido, o SSD, che non hanno parti in movimento. Sono più come RAM e meno come questi dispositivi meccanici. Ma le idee sono sempre gli stessi, di certo in quanto si riferiscono al problema di impostare cinque. E se ci pensate ora un disco rigido rappresenta di essere un cerchio, che Io traggo come questo qui. Quando si crea un file sul computer, che si tratti di un SSD, o in questo caso, un vecchio disco rigido scuola, tale file comprende più bit. Diciamo che si tratta di questo 0 e 1, un gruppo intero di 0 e 1. Quindi questo è il mio intero disco rigido. Questo è apparentemente una abbastanza grande file. E utilizza il 0 e 1 in quel porzione del piatto fisico. Beh, che è quella parte fisica? Bene, si scopre che su un disco rigido, almeno di questo tipo, c'è queste minuscole particelle magnetiche. E hanno essenzialmente a nord e poli sud a loro, in modo che se si trasformare una di queste particelle magnetiche questo modo, si potrebbe dire che è rappresenta un 1. E se è a testa in giù a sud di nord, si potrebbe dire che è rappresenta un 0. Così nel mondo fisico reale, che è come si potrebbe rappresentare qualcosa di stato binario di 0 e un 1. Ecco, questo è tutto un file è. C'è un sacco di magnetico particelle che sono loro così o in questo modo, la creazione di modelli di 0 e 1. Ma si scopre quando si salva un file, alcune informazioni vengono salvate separatamente. Quindi questo è un piccolo tavolo, una directory, per così dire. E io chiamo questo il nome della colonna, e Chiamerò questa posizione colonna. E ho intenzione di dire, supponiamo questo è il mio curriculum. Il mio resume.doc viene conservato a posizione, diciamo 123. Vado sempre per quel numero. Ma basti dire che, proprio come in RAM, si può prendere un disco rigido questo è un gigabyte o 200 gigabyte o di un terabyte, e si può numero di tutti i byte. È possibile numerare tutti i blocchi di 8 bit. Quindi diremo che questo è la posizione 123. Quindi questa directory all'interno del mio esercizio sistema si ricorda che la mia curriculum è in posizione 123. Ma si fa interessante quando si elimina un file. Così, per esempio - e per fortuna, la maggior parte del mondo ha catturato su questo - che cosa accade quando si trascina un file per il sistema operativo Mac Cestino o il vostro Cestino di Windows? Qual è lo scopo di fare questo? E ', ovviamente, di sbarazzarsi del file, ma quello che fa il gesto di trascinamento e cadere nel cestino o la vostra Cestino fare su un computer? Assolutamente niente, davvero. E 'proprio come una cartella. E 'una cartella speciale, per essere sicuri. Ma lo fa effettivamente cancellare il file? Beh, no, perché alcuni di voi probabilmente sono stati come, oh accidenti, non l'hai fatto significa per farlo. Così si fa doppio clic sul Trash o Cestino. Hai curiosato e hai recuperato il file semplicemente trascinandolo fuori di lì. Quindi, chiaramente, non è necessariamente eliminarlo. OK, tu sei più intelligente di così. Voi sapete che solo trascinandolo nella Trash o Cestino non significa si sta svuotando il cestino. Così si va fino al menu, e si dice Vuota il Cestino o Svuota cestino. Allora che cosa succede? Sì, così viene eliminato più. Ma tutto ciò che accade è questo. Il computer dimentica dove resume.doc era. Ma ciò che non è cambiato apparentemente nella foto? I bit, lo 0 e 1 che rivendico sono sul sito di qualche aspetto fisico l'hardware. Sono ancora lì. E 'solo il computer ha dimenticato quello che sono. Quindi è essenzialmente liberato del file bit in modo che possano essere riutilizzati. Ma non prima di creare più file, e altri file, e più file di volontà probabilisticamente, quelli 0 e 1, queste particelle magnetiche, vengono riutilizzati, lato testa o fino, per altri file, 0 ed 1. In modo da avere questa finestra di tempo. E non si tratta di prevedibile lunghezza, davvero. Dipende dalla dimensione del disco unità e quanti file avete e quanto velocemente si fanno nuovi. Ma c'è questa finestra di tempo durante il che quel file è ancora perfettamente recuperabile. Quindi, se mai utilizzare programmi come McAfee o Norton per cercare di recuperare dati, tutti stanno facendo sta cercando di recuperare questa cosiddetta directory di capire dove il file è stato. E a volte Norton e dirà: file è il 93% recuperabile. Ebbene, che cosa vuol dire? Questo significa solo che qualche altro file casualmente finito per usare, per esempio, quelle punte dal vostro file originale. Quindi, ciò che è effettivamente coinvolto nel recupero dati? Beh, se non hai qualcosa di simile Norton pre-installato sul computer, il meglio a volte si può fare è guardare in tutto il disco rigido alla ricerca di pattern di bit. E uno dei temi del problema insieme cinque è che si cercherà il equivalente di un disco rigido, un forense immagine di una scheda Compact Flash da un macchina fotografica digitale, alla ricerca della 0s 1s e che tipicamente, con elevata probabilità, rappresentano l' inizio di una immagine JPEG. E voi potete recuperare le immagini da assumendo, se vedo questo modello di bit sul immagine forense, con alta probabilità, che segna l'inizio di un JPEG. E se vedo ancora una volta lo stesso modello, che probabilmente segna l'inizio di un altro JPEG, e un altro JPEG, e un altro JPEG. E questo è in genere come recupero di dati funzionerà. Che cosa è bella di file JPEG è pur il formato di file per sé è piuttosto complesso, all'inizio di ogni tale file è in realtà abbastanza identificabile e semplice, come si vedrà, Se non hai già. Quindi, diamo uno sguardo più da vicino sotto il cofano come esattamente ciò che è stato in corso, e ciò che questi 0 e 1 sono, per darvi un po 'di più di un contesto di questa particolare sfida. [RIPRODUZIONE VIDEO] -Dove il vostro PC memorizza la maggior parte dei suoi dati permanenti. Per fare questo, i dati viaggiano da RAM insieme a segnali software che raccontano il disco rigido come memorizzare i dati. I circuiti del disco rigido traducono tali segnali in tensione fluttuazioni. Questi, a loro volta, controllano il disco rigido del parti mobili, alcuni dei pochi parti mobili lasciati in computer moderno. Alcuni dei segnali di controllo di un motore che gira piatti in metallo rivestite. I vostri dati sono effettivamente memorizzati su questi piatti. Altri segnali muovono la lettura / scrittura testine di lettura o scrivere i dati sui piatti. Questo macchinario così precisa che un essere umano capelli non riusciva nemmeno a passare tra la testine e piatti rotanti. Eppure, tutto funziona a una velocità terrificante. [FINE RIPRODUZIONE VIDEO] DAVID MALAN: Zoom in un piccolo più profonda ora a ciò che è in realtà su quei piatti. [RIPRODUZIONE VIDEO] -Diamo un'occhiata a ciò che abbiamo appena visto al rallentatore. Quando un breve impulso di energia elettrica è inviato alla testina di lettura / scrittura, se lanci su una piccola elettromagnetica per una frazione di secondo. Il magnete crea un campo, che cambia la polarità di un piccolo, piccolo porzione delle particelle metalliche che cappotto ogni superficie del piatto. Una serie di pattern di questi piccoli, aree carico-up sul disco rappresenta un singolo bit di dati del numero binario sistema utilizzato dai computer. Ora, se viene inviato l'attuale senso unico attraverso la testina di lettura / scrittura, l'area è polarizzata in una direzione. Se la corrente viene inviata nella direzione opposta, la polarizzazione è invertita. Come ottenere i dati dal disco rigido? Basta invertire il processo. Quindi è le particelle sul disco che ottengono la corrente nel lettura / scrittura testa mobile. Mettere insieme milioni di queste segmenti magnetizzati, e hai un file. Ora, i pezzi di un singolo file può essere sparsi in tutto un disco di piatti, un po 'come il casino di carte sulla scrivania. Quindi uno speciale extra file tiene traccia di dove tutto è. Non avresti voluto qualcosa di simile? [FINE RIPRODUZIONE VIDEO] DAVID MALAN: OK, probabilmente no. Così come molti di voi ragazzi cresciuto con questi? OK, quindi è sempre meno mani ogni anno. Ma sono contento che tu sia almeno familiare con loro, perché questo e il nostro libro di demo, purtroppo, stanno morendo una molto rallentare la morte qui di familiarità. Ma questo è quello che io, almeno, di nuovo in scuola superiore, uso usato per i backup. Ed è stato incredibile, perché si potrebbe memorizzare 1.4 megabyte su questo disco in particolare. E questa era la versione ad alta densità, come indicato dal HD, che ha significa prima di oggi i video in HD. Densità standard era di 800 kilobyte. E prima ancora, ci sono stati Dischi 400 kilobyte. E prima ancora, ci sono stati 5 e 1/4 dischi pollici, che erano vere floppy, e un po 'più ampia e più alta di queste cose qui. Ma si può effettivamente vedere il cosiddetto aspetto floppy di questi dischi. E funzionale, sono in realtà abbastanza simile ai dischi rigidi di a Almeno questo tipo. Ancora una volta, gli SSD in computer più recenti lavorare un po 'diverso. Ma se si sposta quella linguetta metallica poco, si può effettivamente vedere un po 'di biscotto, o piatto. Non è di metallo come questo. Questo è in realtà un po 'di più economico di materiale plastico. Ed è possibile tipo di muovere esso. E hai trully appena cancellato alcuni numero di bit o particelle magnetiche da questo disco. Quindi per fortuna, non c'è nulla su di esso. Se quella cosa è nel modo in cui - e coprire i tuoi occhi e quelli del tuo vicino di casa - si può solo tipo di tirare questo tutto fuori guaina così. Ma c'è una piccola sorgente, in modo da essere consapevole che con i vostri occhi. Così ora avete veramente un disco floppy. E quel che è notevole di questo è che in quanto questo è un rappresentazione in scala ridotta di un più ampio disco rigido, queste cose sono super, super semplice. Se pizzicare il fondo di esso, ora che che cosa di metallo è fuori, e la buccia aprirli, tutto quello che c'è è di due pezzi di feltro e il cosiddetto disco floppy con un pezzo di metallo all'interno. E non ci va la metà di il contenuto del mio disco. Ci va un altro mezzo di loro. Ma questo è tutto quello che stava filando dentro del computer in tempi passati. E ancora, per mettere questo in prospettiva, quanto grande è la maggior parte del duro spinge in questi giorni? 500 gigabyte, un terabyte forse in un computer desktop, 2 terabyte, 3 terabyte, 4 terabyte, giusto? Questo è un megabyte, prendere o lasciare, che non può nemmeno andare bene un tipico MP3 più in questi giorni, o alcune file musicale simile. Quindi un piccolo souvenir per te oggi, e anche per contribuire a contestualizzare ciò che saremo dare per scontato ora nel problema impostare cinque. Quindi questi sono il vostro da mantenere. Quindi, mi permetta di transizione in cui sarà Passo successivo pset pure. Così ora abbiamo impostato questa pagina - oh, un paio di annunci in modo rapido. Questo Venerdì, se si desidera unirsi CS50 per il pranzo, andare al solito posto, cs50.net/rsvp. E del progetto definitivo - così per il programma, abbiamo pubblicato il specifiche di progetto definitivo già. Rendetevi conto che ciò non significa è dovuto in particolare al più presto. E 'pubblicato, in realtà, solo per ottenere voi ragazzi a pensarci. E, in effetti, un super significativo Percentuale di voi sarà affrontando progetti finali sul materiale che abbiamo non hanno ancora ottenuto per la classe, ma sarà già la prossima settimana. Si noti, però, che la specifica richiede pochi componenti diverse dello progetto finale. Il primo, in poche settimane, è un proposta preliminare, una e-mail abbastanza casuale per il vostro TF di dirgli o che cosa sei pensare per il vostro progetto, con nessun impegno. La proposta sarà la vostra particolare impegno, dicendo: ecco, questo è ciò che Mi piacerebbe fare per il mio progetto. Cosa ne pensi? Troppo grande? Troppo piccolo? E 'gestibile? E vedi le specifiche per maggiori dettagli. Un paio di settimane dopo che è lo stato relazione, che è un modo simile e-mail casuale alla vostra TF dire quanto molto indietro siete nella vostra finale attuazione del progetto, seguito dalla il CS50 Hackathon a cui tutti è invitato, che sarà un evento da 20:00 una sera fino a 07:00 Del mattino successivo. Pizza, come posso aver detto in settimana pari a zero, wil essere servita alle 9:00 PM, Cibo cinese alle 01:00. E se siete ancora svegli alle 5:00, vi porteremo a IHOP per la prima colazione. Quindi la Hackathon è uno dei più esperienze memorabili nella classe. Poi l'implementazione è dovuta e poi il climax CS50 Fiera. Maggiori dettagli su tutte queste nelle settimane a venire. Ma torniamo a qualcosa di vecchia scuola - nuovamente, un array. Quindi un array è stato bello, perché risolve problemi come l'abbiamo visto solo un poco fa con strutture studentesche sempre un po 'fuori controllo, se vogliono avere uno studente, studente di due, studente tre, studente puntini puntini, qualche numero arbitrario di studenti. Così gli array, qualche settimana fa, piombò in e risolto tutti i nostri problemi di non sapendo in anticipo quante cose di un certo tipo che potremmo desiderare. E abbiamo visto che le strutture ci possono aiutare organizzare ulteriormente il nostro codice e mantenere variabili concettualmente simili, come un nome e una casa, insieme, in modo da li può trattare come un'unica entità, all'interno di cui ci sono più piccole parti. Ma array hanno alcuni svantaggi. Quali sono alcuni degli svantaggi abbiamo incontrato con array finora? Che cos'è? Misura fissa - quindi, anche se si potrebbe essere in grado di allocare memoria per una array, una volta che si sa quanti studenti avete, quanti caratteri hai da parte dell'utente, una volta assegnato la matrice, hai sorta di dipinto te in un angolo. Poiché non è possibile inserire nuovi elementi nel bel mezzo di un array. Non è possibile inserire più elementi al termine di un array. Davvero, è necessario ricorrere alla creazione di un tutta una serie nuova, come abbiamo discusso, copiando il vecchio nel nuovo. E di nuovo, questo è il mal di testa che GetString offerte con per voi. Ma ancora una volta, non si può nemmeno inserire qualcosa nel mezzo della matrice se il tasso non è completamente riempita. Per esempio, se questa matrice qui di dimensione sei ha solo cinque cose in esso, Beh, si potrebbe semplicemente virare qualcosa sull'estremità. Ma cosa succede se si vuole inserire qualcosa in mezzo alla matrice, anche se potrebbe avere cinque su sei cose in esso? Ebbene, che cosa abbiamo fatto quando abbiamo avuto tutti dei nostri volontari umani sul palco in ultime settimane? Se volessimo mettere qualcuno qui, sia queste persone come spostare questo modo, o queste persone come spostare questo modo, e che è diventato costoso. Lo spostamento di persone all'interno di un serie finì sommando e costano noi ora, quindi molto del nostro n quadrato tempi di esecuzione come insertion sort, per esempio, nel caso peggiore. Così gli array sono grandi, ma si deve sai in anticipo quanto grande vuoi. Quindi, OK, ecco una soluzione. Se io non so in anticipo quante studenti che potrebbero avere, e so che una volta Decido, però, mi sono bloccato con quella molti studenti, perché non ho sempre allocare il doppio dello spazio come potrei pensare ho bisogno? Non è forse una soluzione ragionevole? Realisticamente, non credo che siamo andando ad avere bisogno di più di 50 slot in una matrice per una classe di medie dimensioni, così facciamo solo Round Up. Farò 100 slot nel mio array, basta in modo che possiamo sicuramente ottenere il numero di studenti che mi aspetto di essere in qualche classe di medie dimensioni. Allora perché non arrotondare e allocare più memoria, tipicamente, per un array di quanto si pensi si potrebbe anche bisogno? Che cos'è questo semplice pushback a questa idea? Stai solo sprecando memoria. Letteralmente ogni programma che si scrive allora è forse utilizzando il doppio della quantità di memoria hai veramente bisogno. E che proprio non sentire come un particolarmente soluzione elegante. Inoltre, diminuisce solo l' probabilità di un problema. Se ti capita di avere un corso popolare un semestre e si hanno 101 studenti, il programma è ancora fondamentalmente di fronte lo stesso problema. Quindi per fortuna, c'è una soluzione per questo annuncio a tutti i nostri problemi in forma di strutture di dati che sono più complessa di quelle che abbiamo visto finora. Questo, io sostengo, è una lista concatenata. Questa è una lista di numeri - 9, 17, 22, 26, e 34 - che sono stati collegati tra loro per mezzo di quello che ho disegnato come frecce. In altre parole, se ho voluto rappresentare un array, ho potuto fare qualcosa di simile a questo. E io ci metto questo sulla testa in un attimo. Potevo fare - ciao, tutto bene. Stand by. Nuovo computer qui, chiaro - tutto bene. Quindi, se ho questi numeri in serie - 9, 17, 22, 26, 24 - non necessariamente in scala. Bene, ecco la mia matrice - oh mio dio. Bene, ecco il mio array. Oh mio dio. [Risata] DAVID MALAN: Pretend. E 'troppo sforzo per tornare indietro e fissare che, quindi non - 26. Quindi abbiamo questa serie di 9, 17, 22, 26, e 34. Per quelli di voi può vedere la imbarazzante errore che ho appena fatto, non vi è. Quindi io sostengo che questo è un soluzione molto efficiente. Ho ripartito come molti interi come Ho bisogno - uno, due, tre, quattro, cinque, o sei - e ho quindi memorizzati i numeri all'interno di questa matrice. Ma supponiamo, allora, voglio inserire un valore come il numero 8? Beh, dove va a finire? Supponiamo che io voglio inserire un numero come 20. Beh, dove va a finire? Da qualche parte lì in mezzo, o il numero 35 deve andare qualche parte alla fine. Ma sono tutti fuori di spazio. E quindi questa è una sfida fondamentale di array che non sono la soluzione. Ho affermato poco fa, GetString risolve questo problema. Se si desidera inserire un sesto numero in questo array, quello che è almeno un soluzione che si può ripiegare su di sicuro, proprio come facciamo con GetString? Che cos'è? Beh, renderlo più grande è più facile a dirsi che a farsi. Non possiamo necessariamente fare la matrice più grande, ma cosa possiamo fare? Fare un nuovo array che è più grande, di dimensioni 6, o forse taglia 10, se vogliamo per andare avanti delle cose, e quindi copiare la vecchia matrice nel nuovo, e poi libera il vecchio array. Ma che cosa è il tempo di esecuzione ora di quel processo? È grande O di n, perché la copiatura sta andando a costare alcune unità di tempo, quindi non così ideale se dobbiamo allocare un nuovo array, che sta di consumare il doppio memoria temporanea. Copiare vecchio in nuovo - Voglio dire, è solo un mal di testa, che è, di nuovo, perché abbiamo scritto GetString per voi. Così che cosa potremmo fare invece? Beh, e se la nostra struttura dati in realtà ha lacune in esso? Suppongo che mi rilasso il mio obiettivo di avere blocchi contigui di memoria, in cui 9 Ubicato accanto a 17, che è accanto a 22, e così via. E supponiamo che 9 può essere qui in RAM, e 17 possono essere qui in RAM, e 22 possono essere qui in RAM. In altre parole, non ho bisogno di loro anche back to back più. Non mi resta che infilare in qualche modo un ago attraverso ciascuno di questi numeri, o ciascun di questi nodi, come chiameremo il rettangoli come li ho disegnati, a ricordare come raggiungere l'ultimo tale nodo dalla prima. Allora, qual è il costrutto di programmazione abbiamo visto poco tempo fa con la quale ho possono implementare quel filo, o disegnato qui, con la quale posso implementare quelle frecce? Puntatori così, giusto? Se non ho allocare solo un int, ma un nodo - e da nodo, mi riferisco solo contenitore. E visivamente, intendo un rettangolo. Così un nodo apparentemente bisogno per contenere due valori - l'int stessa, e quindi, come implica la metà inferiore del rettangolo, abbastanza spazio per un int. Quindi, solo pensando al futuro qui, quanto è grande questo nodo, questo contenitore in questione? Quanti byte per l'int? Presumibilmente 4, se è come al solito. E poi quanti byte per il puntatore? 4. Quindi questo contenitore, o questo nodo, è andando ad essere una struttura di 8 byte. Oh, e questa è una felice coincidenza che abbiamo appena introdotto questo concetto di una struttura o di una struttura C. Quindi io sostengo che voglio fare un passo verso questo più sofisticato attuazione di una lista di numeri, un lista collegata di numeri, ho bisogno di fare un po 'di più il pensiero su fronte e dichiarare non solo un int, ma una struct che chiamerò convenzionalmente qui, nodo. Potremmo chiamare tutto ciò che vogliamo, ma nodo sta per essere tematico in un sacco delle cose iniziamo guardando ora. All'interno di tale nodo è un int n. E poi questa sintassi, un po ' strano a prima vista - struct nodo * prossimo. Beh pittoricamente, che cos'è? Questa è la metà inferiore della il rettangolo che abbiamo visto solo un momento fa. Ma perché dico struct nodo * rispetto a solo nodo *? Perché se tale puntatore punta a un altro nodo, è solo il indirizzo di un nodo. Questo è coerente con quello che abbiamo discusso puntatori finora. Ma perché, se io rivendico questa struttura è chiamato nodo, cosa devo dire struct nodo dentro qui? Esattamente. E 'una sorta di stupida realtà di C. Il typedef, per così dire, non ha ancora successo. C è super letterale. Si legge il codice in alto a basso, da sinistra a destra. E fino a quando colpisce che punto e virgola sulla linea di fondo, indovinate un po 'non esistere come un tipo di dati? Node, nodo unquote preventivo. Ma a causa del più prolisso dichiarazione che ho fatto in prima linea - nodo typedef struct - perché quello avvenne prima, prima della parentesi graffe, che è un po 'come pre-educare Clang che, si sapere che cosa, dammi una struct chiamato nodo struct. Francamente, non mi piacciono le cose di chiamata struct nodo struct nodo tutto tutto il mio codice. Ma io uso solo una volta, appena dentro, in modo che io possa effettivamente creare una sorta di riferimento circolare, non un puntatore a me stesso per sé, ma un puntatore ad un'altra di un'altra identica. Così si scopre che in una struttura dati come questo, ci sono alcune operazioni che potrebbero essere di interesse per noi. Potremmo voler inserire in una lista come questa. Potremmo voler cancellare da una lista come questa. Potremmo voler cercare la lista per un valore, o più in generale poligonale. E traverso è solo un modo elegante di dicendo inizio a sinistra e spostare tutti la strada a destra. E notate, anche con questo un po 'più sofisticata struttura di dati, lasciare Mi propongo di prendere in prestito alcuni dei le idee delle ultime due settimane e implementare una funzione denominata ricerca come questa. E 'intenzione di restituire true o falso, indicando, sì o no, n è nella lista. Il suo secondo argomento è un puntatore alla lista stessa, quindi un puntatore a un nodo. Tutto quello che sto per fare è quindi dichiarare una variabile temporanea. Lo chiameremo PTR per convenzione, per il puntatore. E io la assegno pari al inizio della lista. E ora notare il ciclo while. Finché puntatore non è uguale a nulla, vado a controllare. È freccia puntatore n pari a la n che è stato passato in? E aspetta un attimo - nuovo pezzo di sintassi. Qual è la freccia tutto ad un tratto? Sì? Esattamente. Quindi, mentre a pochi minuti fa, abbiamo usato la notazione del punto per accedere a qualcosa all'interno di una struct, se la variabile si è non è la struct se stessa, ma un puntatore ad una struct, per fortuna, un pezzo di sintassi finalmente ha un senso intuitivo. La freccia significa seguire il puntatore, come le nostre frecce genere significa pittoricamente, e andare a campo dati all'interno. Così freccia è la stessa cosa di punto, ma lo si utilizza quando si dispone di un puntatore. Quindi, solo per ricapitolare poi, se il campo n all'interno della struct chiamata puntatore uguale uguale a n, restituisce vero. In caso contrario, questa linea qui - pointer uguale indicatore accanto. Così che cosa sta facendo questo, si noti, è che se io attualmente sto indicando la struct contenente 9, e 9 non è il numero Sto cercando - suppongo che sto cercando per n uguale a 50 - Ho intenzione di aggiornare il mio puntatore temporaneo a non puntare a questo nodo più, ma il puntatore a freccia accanto, che sta per lasciarmi qui. Ora, che ho capito è un turbine introduzione. Mercoledì scorso, avremo effettivamente fare questo con alcuni esseri umani e con alcuni più codice ad un ritmo più lento. Ma realizzare, ora stiamo facendo i nostri dati strutture più complesse in modo che il nostro algoritmi possono ottenere più efficiente, che sta per essere requisito per pset sei anni, quando si carica in, ancora una volta, quelli 150.000 parole, ma è necessario farlo in modo efficiente, e idealmente, creare un programma che gira per i nostri utenti non in lineare, non in n al quadrato, ma in tempo costante, in ideale. Ci vediamo il Mercoledì. SPEAKER: Al prossimo CS50, David dimentica il suo caso base. DAVID MALAN: Ed è così che si invia messaggi di testo con C. Che - [VARIE MESSAGGIO TESTO Suoni di notifica]