DAVID Malan: Todo ben, benvido de volta. Esta é a CS50. Este é o inicio da semana de sete. Entón foi un tempo, entón eu penso que ía facer un paseo turbillón de onde nós parou e cara a onde estamos indo agora. Entón, esa cousa aquí pode ter causou certa angustia en primeiro lugar. Pero espero que, está empezando a aclimatar co que iso denota aquí - estrela que representa un punteiro, o cal é o que, en termos máis laicos? Polo tanto, é un enderezo. Polo tanto, é o enderezo de algo na memoria. E comezamos a pelar as capas un par de semanas atrás, cousas como GetString e outras funcións tales todo este tempo foron retornando enderezos de cousas na memoria, como o enderezo do primeiro carácter algunha secuencia. Entón, nós tamén introduciu Valgrind, que vai comezar a usar a este problema establecido, en particular á seguinte conxunto de problemas tamén. E Valgrind fai o que para nós? El comprobar se hai perdas de memoria, e Tamén comproba a existencia de abuso de memoria. É posible, con certa probabilidade, se detecta seu código tocará de memoria que simplemente non debería. Entón, non necesariamente unha fuga, pero se ir máis alá das fronteiras de algúns array, e realmente executar Valgrind e inducir a que o comportamento mentres Valgrind está en execución no seu programa rodando dentro del, vai ter mensaxes como esta - "válido de escribir tamaño 4 ", que, lembre-se de un par de semanas significaba que eu tiña accidentalmente procura dun int demasiado alén dos límites dun array. E así tamaño 4 significa que aquí o tamaño de que int particular. Entón dea confianza no feito de que saída do Valgrind, o formato do mesmo, é simplemente atroz. É realmente difícil de ver a través da desorde pola información interesante. Entón, o que fixemos aquí é só tramo algúns dos compañeiros de máis liñas interesantes. Pero entendemos que o 80% dos Valgrind de saída vai ser un pouco de distracción. Basta ollar para os patróns como estes - válido dereita, válido ler, 40 bytes e un certo número de bloques son definitivamente perdido, palabras clave como esta. E o que espera ver algunha tipo de vestixio de que a función do erro é realmente dentro Neste caso, aquí, no que a liña de meu código era aparentemente o erro? 26 nun arquivo chamado memory.c, que era o exemplo que estaban a xogar con no momento. Polo tanto, non é, probablemente, en malloc. Foi probabelmente o meu código no seu lugar. Entón, imos ver iso de novo e de novo en pouco tempo. Entón scanf, esta xurdiu nun algunhas formas ata agora. Vimos sscanf brevemente. Era algo que unha serie de lle mergullou na súa preparatorios para o exame. E scanf é realmente o que o CS50 biblioteca está a usar por baixo da capa por algún tempo, a fin para a entrada do usuario. Por exemplo, se eu pasar ao CS50 aparello aquí, déixeme abrir unha exemplo, hoxe, que se chama scanf-0.C E é super sinxelo. É só algunhas liñas de código. Pero el demostra realmente como getInt vén traballando todo este tempo. Neste programa aquí, na liña 16 , Repare que eu declarar un int. Así, non punteiros, nada de máxico alí, só unha int. A continuación, na liña 17, eu levar o usuario a un número, por favor. Así, a finais de 18, eu uso o scanf aquí. E eu especifiquei, tipo como printf, que eu estou esperando Cita unquote por cento i. Así por cento de i, por suposto, denota un int. Pero teña en conta que a segunda argumento de scanf é. Como describiría a segunda argumento despois da vírgula? ¿Que é iso? É o enderezo de x. Entón, iso é útil, porque, que contén scanf co enderezo de x, o que fai que capacitam esta función para facer? Non é só ir alí, senón tamén facer o que? Facer un cambio para ela. Porque pode ir alí, é unha especie de como un mapa para a localización na memoria. E así, sempre que forneza scanf, ou calquera función cun tal mapa, é dicir función pode ir alí, e non só mirar para o valor, pero tamén pode cambiar ese valor, o que é útil cando a propósito na vida de scanf é dixitalizar a entrada do usuario, especialmente desde o teclado. E o f denota formato, así como printf, o f denota unha formato cadea que quere imprimir. Así, en breve, esta liña 18 simplemente di: tente ler un int de usuario do teclado e almacena-lo dentro de x, en calquera enderezo x pasa a vivir. E entón, finalmente, a liña 19 só di: grazas pola int, neste caso. Entón deixe-me ir adiante e facelo. Entón faga scanf 0. Déixeme ir adiante e facer zoom dentro Vou correr con esta puntos cortar scanf 0. Número, por favor? 50. Grazas pola 50. Por iso, é moi sinxelo. Agora, o que é que non está facendo? El non está facendo un grupo enteiro de comprobación de erros. Por exemplo, se eu non cooperar, e eu non escribir un número, pero en vez diso, escribir algo como "Ola", iso é só unha especie de estraño. E así, unha das cousas que o CS50 biblioteca está a facer a nós por algún tempo é que reprompting e reprompting. O novo intento frase foi retirada en cs50.c, e esa é a razón que getInt en a biblioteca CS50 é realmente un conxunto banda de longas filas, porque somos comprobación de cousas estúpidas como esta. Se o usuario non dar nós, en realidade, un int? Será que el ou ela dar algo como unha letra alfabética? Se é así, queremos detectar que e berrar con eles. Pero as cousas están máis interesantes Neste seguinte exemplo. Se eu fose para scanf-1.c, que é o único cousa que cambiou fundamentalmente en Neste seguinte exemplo? Está a usar char *, por suposto, no canto de int. Entón, iso é interesante, porque char *, recordar, é realmente só o mesmo que a cadea. Así, parece que quizais iso sexa un super implementación simple de GetString. Pero eu desmascarado a capa da biblioteca CS50, polo que estou chamando este char * agora. Entón imos ver onde, en calquera lugar, nós erramos. Liña 17 - Volvo a dicir, por favor, me dar algo, neste caso, unha cadea de caracteres. E, a continuación, na liña seguinte, eu chamo scanf, unha vez máis, dándolle un código de formato, pero esta vez por cento s. E, a continuación, esta vez, eu son dándolle tapón. Agora conta, non está a usar o comercial. Pero por que é que, probablemente, OK aquí? Porque o que é xa tapón? Xa é un punteiro. Xa é un enderezo. E imos a palabra "confundir", déixeme basta chamalo s, por exemplo, para sinxeleza. Pero eu chamei-tapón porque en xeral, na programación, se ten un anaco de memoria, que unha secuencia de verdade só é, pode chamalo de un buffer. É un lugar para almacenar información. Semellante a cousas como YouTube, cando están de tamponamento, por así dicir, que significa só que está baixando anacos de Internet e almacena-los nun variedade local, un anaco da memoria local, así que pode ve-lo máis tarde, sen el saltar ou colgado vostede durante a reprodución. Polo tanto, hai un problema aquí, con todo, por que eu digo scanf, esperar un corda do usuario. Aquí está o enderezo do unha peza de memoria. Coloca a corda alí. Por que Bound dar nos problemas, aínda que? ¿Que é iso? Teño permiso para acceder que parte da memoria? Vostede sabe, eu non sei. Porque ten tapón foi inicializar para nada? Non é verdade. E iso é o que estamos chamando un valor de lixo, que non é unha palabra formal. Significa só que nós non temos ningunha idea do que anacos están dentro das catro bytes Teño asignado como buffer. Non chamei malloc. Eu definitivamente non se chama GetString. Entón, quen sabe o que é realmente dentro tapón de? E aínda dicindo scanf cegamente, vai alí e poñer o que o usuario inseriu. Entón, o que é susceptible de provocar no noso código, se executa-lo? Probablemente un segfault. Quizais non, pero probablemente un segfault. E digo quizais porque ás veces non fai, ás veces non ten un segfault. Ás veces só ter sorte, pero é aínda así será un erro no noso programa. Entón deixe-me ir adiante e compilar iso. Vou facer do xeito old school. Entón bumbum trazo 0, scanf-1, scanf-1.c, Intro. Oops, escola moi antiga. Imos ver. Onde é que eu vou? Oh, buffer de char *. Oh, moitas grazas - Gardar, OK - escola moi antiga. Todo ben, iso xa fai un tempo. Entón, eu acabo de gardar o arquivo despois facendo que temporal cambiar de un momento atrás. E agora eu compilar el manualmente con Clang. E agora eu estou indo a ir adiante e realizar scanf-1, Intro. Cordas favor. Vou escribir "Ola". E agora, aquí é onde, francamente, printf pode é un pouco irritante. Non está indo realmente para segfault neste caso. Printf é algo especial, porque é tan super comunmente utilizado, que printf esencialmente fai -Nos un favor e entender, iso non é un punteiro válido. Déixeme levala a min só para imprimir en parénteses nulo, aínda aínda que non sexa necesariamente o que que nos esperaba. Polo tanto, non podemos moi facilmente inducir un segfault con iso, pero claramente esta non é o comportamento que eu quería. Entón, cal é a solución máis simple? Ben, en scanf-2, déixeme propoñer que no canto de realidade, só a asignación dunha char *, deixe-me ser un pouco máis intelixente sobre iso, e déixeme reservar buffer como unha secuencia de 16 caracteres. Entón eu podo facelo de dous xeitos. Eu absolutamente podería usar malloc. Pero eu podo volver a dúas semanas, cando Eu só precisaba unha morea de caracteres. Isto é só unha matriz. Entón déixeme en vez redefinir tapón sendo unha matriz de 16 caracteres. E agora, cando eu pasar tapón in - e iso é algo que non fixo falar en dúas semanas - pero pode tratar unha variedade de pero é un enderezo. Técnicamente, como vimos, son un pouco diferente. Pero scanf non vai importar se pasalo o nome dun array, porque o que Clang fará por nós é esencialmente tratar o nome do array como o dirección do bloque de 16 bytes. Polo tanto, este é mellor. É dicir, que agora que podo esperar faga o seguinte. Déixeme zoom por un momento e fan scanf-2, compilada Aceptar. Agora, deixe-me que teño barra scanf-2. Cordas favor. "Ola". Correo parecía estar a traballar neste momento. Pero alguén pode propoñer un escenario en que non pode aínda funciona? Si? Algo máis que 16 caracteres. E, de feito, podemos ser algo máis precisa. Algo máis entón 15 personaxes, porque realmente necesitamos ter presente que necesitamos que barra invertida de cero implicitamente ao final da cadea, que é un separadamente scanf ha tipicamente coidar para nós. Entón deixe-me facer algo así - Ás veces, podemos só deixalo así. OK, entón agora inducido nosa fallo de segmento. Por que? Porque eu escriba a máis de 15 caracteres, e por iso nós realmente memoria tocado que realmente non debería. Entón, cal é realmente a solución aquí? Ben, e necesitamos unha secuencia máis longa? Ben, quizais facelo 32 bytes. Ben, e se iso non é suficiente? Como preto de 64 bytes? E se isto non é suficiente? Como preto de 128 bytes ou 200? O que é realmente a solución aquí no caso xeral, se non sabe en avanzar o que o usuario vai escribir? É só unha especie de gran dor na bunda, para ser honesto, é por iso que o Biblioteca CS50 ten algunhas decenas de liñas de código que aplicar colectivamente GetString corda dun xeito que non ten que saber con antelación o que o usuario vai escribir. En particular, se ollar cara atrás, cs50.c de dúas semanas, vai ver que realmente fai GetString non empregue scanf deste xeito. Pola contra, el le un carácter de cada vez. Porque a única cousa agradable sobre lectura dun personaxe é o que pudermos nós garante para sempre ter polo menos un carácter. Só podo declarar un char, e logo tomar estes pasos verdadeiramente bebé para só ler un personaxe nun tempo desde o teclado. E entón, o que vai ver GetString fai cada vez é quedar sen, digamos, 16 bytes de memoria, el usa malloc, ou un seu primo, o reservar máis memoria, copiando o antigo memoria para a nova, e, a continuación, rastreando xunto, obtendo un personaxe de cada vez, e cando se executa fóra do que anaco de memoria, xoga fóra, agarra unha porción maior de memoria, copie vello en novos e repite. E é realmente unha dor de verdade aplicar algo tan simple como a entrada dun usuario. Logo, pode usar scanf. Pode utilizar outras funcións semellantes. E unha morea de libros e en liña Exemplos facer, pero todos eles son vulnerable a problemas como este. E, finalmente, ser un segfault é medio chat. Non é bo para o usuario. Pero, no peor dos casos, o que fai fundamentalmente poñer o seu codificar en risco de? Algún tipo de ataque, potencialmente. Nós falamos sobre un tal ataque - rebosar do conxunto. Pero, en xeral, se está autorizado a un estourido de buffer, coma nós fixemos un Algunhas semanas atrás, con só escribir máis que "Ola" na pila, vostede realmente pode asumir, potencialmente, un ordenador, ou polo menos comezar a datos non pertence a vostede. Entón, en suma, é por iso que temos esas Rodas pequenas. Pero, agora, comezan a tiralas, como os nosos programas non precisa máis, necesariamente, a entrada do usuario. Pero, no caso de problema de definir seis anos, súa contribución virá dunha enorme ficheiro de dicionario con 150 uns impares mil palabras. Así, non terá que preocuparse entrada arbitraria do usuario. Imos darlle algunhas suposicións preto de arquivo. Calquera dúbida sobre punteiros ou scanf ou a entrada do usuario en xeral? Todo ben, entón unha rápida ollada entón nun fuga tema de dúas semanas. E que era esa noción dun struct. Non é que - esta noción dun struct, que era o que? Que struct facer por nós? Definir - arrepentido? Axustar un tipo de variable. Entón, máis ou menos. En realidade, estamos combinando dous temas. Así, con typedef, lembre que podemos declarar un tipo de nosa propia, como un sinónimo, como cadea para char *. Pero o uso de typedef e struct, podemos realmente crear as nosas propias estruturas de datos. Por exemplo, se eu volver para o gedit aquí por só un momento, e eu vou adiante e facer algo así, déixeme gardar isto como, digamos, structs.c temporalmente, eu só vou para ir adiante e inclúen standardio.h, int void main. E entón, aquí, imos supor que quero para escribir un programa que almacena varios alumnos de varios vivendas, por exemplo. Entón, é como un registrarial base de datos de calquera tipo. Entón, se eu teño do nome dun estudante, eu podería facer algo así co nome de char *, e eu vou facer algo así - de feito, imos usar a biblioteca CS50 por só un momento para facer deste un pouco máis simple, para que poidamos prestar esas decenas de liñas de código. E imos mantelo simple. Imos mantelo cadea, e agora GetString. Entón eu afirmo agora que eu teño gardado o nome dalgún alumno, ea casa de algún alumno, simplemente usando variables como fixemos e nunha semana. Pero supoño que agora queren apoiar varios alumnos. Moi ben, os meus instintos están facendo corda nome2, queda GetString, corda house2 queda GetString. E entón o noso terceiro estudante, imos facer name3 GetString. Todo ben, entón iso é sorte impresionante como unha especie de idiota, porque este proceso é realmente nunca vai acabar, e ela só vai facer o meu código parece peor e peor e peor. Pero nós resolvemos iso tamén en dúas semanas. Cal foi a nosa solución relativamente limpa cando tivemos múltiples variables do mesmo tipo de datos que están relacionados, pero nós non queremos esa confusión atroz de variables de nome semellante? O que imos facer no seu canto? Entón, eu creo que escoitei nalgúns lugares. Tivemos unha matriz. Se quere varias instancias do algo, por que non imos limpar iso todo e só dicir, darme array chamado nomes? E, polo de agora, imos 3 código duro. E entón me dar outro array chamados casas, e deixar-me por agora ríxido código 3. E eu masivamente limpou o desorde que acaba de crear. Agora eu codificado 3, pero aínda o 3 podería vir dinamicamente a partir da usuario ou argv, ou semellantes. Entón, iso xa é máis limpo. Pero o que é irritante sobre iso é que agora, aínda que o nome é dalgunha forma fundamentalmente ligada á casa dun alumno - é un estudante que realmente quere representar - Agora teño dúas matrices que son paralelas no sentido de que son os mesmo tamaño, e os nomes de soporte 0 presuntamente mapas para vivendas apoio 0, e os nomes de Soporte 1 mapas ás casas soporte 1. Noutras palabras, que o alumno vive aquela casa, e que outro alumno que vive en outra casa. Pero, por suposto, iso se pode feito aínda máis limpa. Ben, isto pode, de feito. E déixeme ir adiante e abrir se structs.h, e vai vexa esta idea aquí. Repare que eu usei typedef, como alusión a un momento atrás, para declarar o noso tipo de datos propio. Pero eu tamén está a usar esoutra contrasinal chamado struct que me dá un novo estrutura de datos. E esa estrutura de datos que afirman que ter dúas cousas no interior da - Unha cadea chamada nome, e unha serie chamada casa. E o nome que eu vou dar para esta estrutura de datos que a ser chamado de estudante. Podería chamalo de calquera cousa que quero, pero semanticamente facer sentido para min na miña mente. Entón, agora, se eu abrir unha versión mellor do programa comece a escribir alí, déixeme ir ata o cumio. E hai máis algunhas liñas de código aquí, pero déixeme concentrarse para o momento en un. Eu xa declarou unha constante chamada estudantes e codificado 3 de momento. Pero agora, teña en conta como limpa meu código empeza a quedarse. Na liña 22, declaro conxunto de alumnos. E noten que o alumno é, ao parecer, agora un tipo de datos. Porque a principios deste arquivo, teña en conta Eu inclúe o arquivo de cabeceira que eu puxei só un momento atrás. E ese ficheiro de cabeceira simplemente tiña esta definición dun estudante. Entón, agora, eu creei meus propios datos personalizados tipo que os autores do C anos atrás non pensar con antelación. Pero non hai problema. Podo facelo só. Polo tanto, esta é unha matriz chamada estudantes, cada un dos membros cuxos é unha estrutura do estudante. E quero que tres deses na matriz. E agora, o que fai o resto deste programa fai? Eu precisaba de algo un pouco arbitraria. Así, a partir liña 24 en diante, Eu iterado de 0 a 3. Eu, entón, pedir ao usuario para o nome do alumno. E entón eu uso GetString como antes. Entón eu pregunto á casa do alumno, e eu uso GetString como antes. Pero aviso - algo novo peza de sintaxe - Aínda podo índice para o i-th estudante, pero como fago para obter os datos específicos campo dentro da estrutura? Ben, o que é, ao parecer, a nova peza de sintaxe? É só o operador punto. Nós non temos realmente ver iso antes. Xa viu iso en pset cinco, se ten dicir xa con arquivos de mapa de bits. Pero o punto significa só dentro deste struct ou varios campos, dar punto nome, ou me dar dot casa. Isto significa ir a dentro da estrutura e obter os campos específicos. O que fai o resto deste programa fai? Non é todo o que sexy. Teña en conta que unha iteración de 0 a 3, de novo, e eu simplemente crear un inglés frase como fulano de tal está en tal e tal casa, pasando en nome de punto de o i-th alumno ea súa casa tamén. E entón, finalmente, agora imos comezar a ter anal con iso, agora que estamos familiarizado co que malloc e outras funcións fosen facendo todo este tempo. Por que eu teño de liberar tanto o nome ea casa, a pesar de eu non chamar malloc? GetString fixo. E ese foi o pequeno segredo sucio para varias semanas, pero ten GetString ser baleirado de memoria en todo o poñer todo o semestre ata o momento. E Valgrand vai finalmente revelar iso para nós. Pero non é un gran negocio, porque sei que podo simplemente liberar o nome ea casa, a pesar de, tecnicamente, a ser super, super seguro, eu debería ser facer algunha comprobación de erros aquí. Cales son os seus instintos dicindo? Que debo estar comprobando antes de liberar o que é un cadea, aka que un char *? Realmente debería estar comprobando se os alumnos soporte i nome dot non igual nulo. A continuación, el vai estar ben para ir adiante e libre ese punteiro, e mesmo ou outro un ben. Se os alumnos soporte i dot casa non é igual a cero, que agora vai protexer contra o canto caso en que GetString devolve algo como nulo. E vimos hai pouco, printf vai protexer-nos aquí só dicindo nulo, o que se ve raro. Pero polo menos non vai segfault, como xa vimos. Ben, deixe-me facer outra cousa aquí. structs-0 é un tipo de programa estúpido porque eu entro todos estes datos e, a continuación, perdeu xa que o programa remata. Pero déixeme ir adiante e facelo. Deixe-me facer a terminal fiestra un pouco maior. Deixe-me facer-estruturas 1, que é unha nova versión deste. Vou ampliar un pouco. E agora déixeme executar dot reducir estruturas-1. Nome do alumno - David Mather, imos facer Rob Kirkland, imos facer Lauren Leverett. O que é interesante é agora aviso - e eu só sei diso porque Eu escribín o programa - hai un arquivo agora na miña actual directorio chamado students.csv. Algúns de vostedes poden ver estes no mundo real. ¿Que é un ficheiro CSV? Os valores separados por comas. É como unha especie de home pobre versión dun arquivo de Excel. É unha táboa de liñas e columnas que pode abrir nun programa como Excel, ou os números en un Mac E se eu abrir o ficheiro aquí en gedit, aviso - e os números non están alí. Isto é só gedit dicindo me os números de liña. Teña en conta a primeira liña deste ficheiro é David e Mather. A seguinte liña é Rob comas Kirkland. E a terceira liña é Lauren comas Leverett. Entón, o que eu creei? Eu xa escribín un programa en C que efectivamente pode xerar follas de cálculo que pode ser aberto nunha programa como Excel. Non todo o que obrigar un conxunto de datos, pero se ten anacos moi grandes de datos que realmente quere manipular e facer gráficos de e como, este é quizais un forma de crear eses datos. Ademais, CSVs son realmente super-común só para almacenar datos simple - Yahoo Finance, por exemplo, se recibe presupostos de accións a través do seu nome API, o servizo gratuíto que permite que estea en stock, up-to-the-data actual citas para as empresas, que dar os datos de volta o Super formato CSV simple. Entón, como imos facelo? Ben notar, a maior parte deste programa de case iguais. Pero teña en conta-se aquí, en vez de impresión estudantes a fóra, na liña 35 á fronte, eu reclamo que estou gardando o estudantes en disco, para gardar un arquivo. Entón, repare que estou declarando un FILE * - Agora, iso é unha especie de anomalía no C. Por algunha razón, o FILE é todas as tapas, o que non é como a maioría dos outros tipos de datos en C. Pero este é un built-in tipo de datos, FILE *. E eu estou declarando un punteiro a un ficheiro, é como pode pensar niso. fopen significa ficheiro aberto. O ficheiro que quere abrir? Quero abrir un arquivo que eu vou arbitrariamente chamar students.csv. Podería chamar iso de calquera cousa que eu queira. E, a continuación, dar un palpite. O que fai o segundo argumento para fopen probablemente significa? Seguro, w para escribir, podería ser r para lectura. Hai unha para achegar se quere engadir liñas e non substituír a cousa toda. Pero eu só quero crear esta imaxe unha vez, polo que vou usar cita unquote w. E sei que só de ler a documentación, ou a páxina de manual. O ficheiro non é nulo - noutras palabras, Se nada deu mal alí - déixeme repetir ao longo do os alumnos de 0 a 3. E agora entende que hai algo sempre así lixeiramente diferente sobre a liña 41 aquí. Non é printf. É fprintf ao arquivo printf. Entón, que vai escribir no ficheiro. Que arquivo? Aquel cuxo punteiro que especifique como o primeiro argumento. Entón nós especifica unha secuencia de formato. Logo, especifique o Barbante queremos plugin para o primeiro por cento s, e logo outra variable ou a segunda por cento s. Despois, peche o ficheiro con fclose. Que liberar a memoria como antes, aínda que Eu debería volver e engadir algunhas comprobacións para null. E é iso. fopen, fprintf, fclose dáme a capacidade de crear arquivos de texto. Agora, vai ver problema en conxunto de cinco, que implica foto que vai empregar ficheiros binarios vez. Pero, fundamentalmente, a idea é a mesma, aínda que as funcións que vai ver é un pouco diferente. Entón rápido tour, pero vai ter moi familiarizado co arquivo I/O-- entrada e saída - con pset cinco. E calquera dúbida sobre a fundamentos iniciais aquí? Si? E se intenta liberar un valor nulo? Eu creo que, a menos que obteña a libre algo máis amigable, pode potencialmente segfault. Pasando-o nulo é malo porque non cren libre preocupa en comprobar a ti, porque sería potencialmente un desperdicio de tempo para que faga a si mesmo para todo o mundo. Boa pregunta, con todo. Todo ben, entón este tipo de queda nos a un tema interesante. O tema do conxunto de problemas cinco é forense. Polo menos esa é a parte do conxunto de problemas. Forensics xeralmente se refire á recuperación de información que poden ou non pode ser eliminado deliberadamente. E entón eu penso que eu ía darlle un rápido gusto do que realmente está a suceder en todos os esta vez baixo o capa de computador. Por exemplo, se ten dentro do seu portátil ou ordenador de mesa a disco duro, ou é un mecánico dispositivo que realmente xira - hai cousas circulares chamados platters parecer moito co que me só tiña na pantalla aquí, aínda que esta é a escola cada vez máis vello. Esta é unha de tres e media polgadas disco duro. E tres centímetros e medio refire-se de coa cousa cando instala-lo nun ordenador. Moitos de vostedes nos seus portátiles agora teñen drives de estado sólido, ou SSD, que non teñen partes móbiles. Son máis como RAM e menos como estes dispositivos mecánicos. Pero as ideas aínda son os mesmos, seguramente como se relacionan ao problema de definir cinco. E se pensar agora un disco duro supón ser un círculo, que Vou debuxar como este aquí. Cando se crea un ficheiro no seu ordenador, se é un SSD, ou en Neste caso, unha antiga escola de disco duro, este ficheiro está composto por varios bits. Digamos que é este 0 e 1, unha morea de 0s e 1s. Polo tanto, este é o meu disco duro enteiro. É dicir, ao parecer, un arquivo moi grande. E está a usar a 0s e 1s na que porción do prato física. Ben, o que é a parte física? Pois ben, resulta que nun disco duro, polo menos deste tipo, non hai esas minúsculas partículas magnéticas. E eles teñen esencialmente norte e polos sur para eles, de xeito que se transformar unha desas partículas magnéticas Deste xeito, pode-se dicir que é representando un 1. E se é de cabeza para baixo ao sur para norte, pódese dicir que é representa un 0. Así, no mundo físico real, que é como pode representar algo en Estado binario de 0 a 1 e un. Entón, iso é todo o que un arquivo é. Hai unha morea de magnético partículas que son deste xeito ou a súa Deste xeito, a creación de estándares de 0s e 1s. Pero resulta que cando salva un ficheiro, unha información son gardadas por separado. Polo tanto, esta é unha pequena mesa, un directorio, por así dicir. E eu vou chamar este nome de columna e Vou chamar a este lugar columna. E eu vou dicir, supoña este é o meu currículo. O meu RESUME.DOC almacénase a localización, imos dicir 123. Sempre vou a ese número. Pero basta dicir que, así como na memoria RAM, pode levar un disco duro iso é un gigabyte ou 200 gigabytes ou un terabytes, e pode número de todos os bytes. Podes enumerar todos os bloques de 8 bits. Entón, imos dicir que este é a localización 123. Polo tanto, este directorio dentro do meu ordenador sistema recorda que o meu currículo é no lugar 123. Pero torna-se interesante cando apaga un arquivo. Así, por exemplo - e, por sorte, a maior parte do mundo ten peguei para iso - o que ocorre cando arrastrar un ficheiro para o seu sistema operativo Mac Trash ou a papeleira de Windows? Cal é o propósito de facelo? É, obviamente, para librarse do ficheiro, pero o que fai o acto de arrastrar e caer no seu lixo ou o seu Lixo facer nun ordenador? Absolutamente nada, en realidade. É como un cartafol. É un cartafol especial, para estar seguro. Pero será que isto realmente eliminar o ficheiro? Ben, non, porque algúns de vostedes probablemente ser, oh caramba, non fixo quero facelo. Así que premer dúas veces o Trash ou papeleira. Vostede cutucou arredor e recuperou o ficheiro só arrastrando o de alí. Entón, claramente, non é necesariamente excluílo. OK, vostede é máis intelixente do que iso. Vostede sabe que só arrastrando-o para o Trash ou papeleira non significa vostede baleirar lixo. Entón vai ata o menú, e dis Baleirar papeleira ou Baleirar papeleira. Entón o que ocorre? Si, por iso é eliminada máis. Pero todo o que pasa é o seguinte. O ordenador se esquece de onde RESUME.DOC era. Pero o que non cambiou, ao parecer, na foto? Os bits, os 0s e 1s que eu afirmo é no lugar dalgún aspecto físico o hardware. Eles aínda están alí. É só o ordenador ten esqueceu o que son. Polo tanto, é esencialmente libre do arquivo bits de xeito que poden ser reutilizados. Pero non ata que cree máis arquivos, e máis arquivos e máis arquivos serán probabilisticamente, os 0s e 1s, aquelas partículas magnéticas, son reutilizados, de cabeza ou do lado dereito cara arriba, outros arquivos, 0s e 1s. Así que ten esta xanela de tempo. E non é de previsible lonxitude, realmente. Depende do tamaño do seu disco unidade e cantos arquivos tes e o; rápido facer novos. Pero hai esta xanela de tempo durante o que o ficheiro aínda é perfectamente recuperable. Entón, se non usar programas como o McAfee ou Norton para intentar recuperar de datos, todo o que estamos facendo é tratar de recuperar este chamado directorio para descubrir onde o arquivo foi. E ás veces Norton e dirá: ficheiro é de 93% recuperable. Ben, o que significa isto? Isto só significa que algún outro arquivo casualmente acabo mediante, por exemplo, eses bits fóra do seu ficheiro orixinal. Entón, o que está realmente involucrado na recuperación de datos? Ben, se non ten algo parecido Norton preinstalado no seu computador, o mellor que ás veces pode facer é ollar en todo o disco duro buscando patróns de bits. E un dos temas do conxunto de problemas cinco é que vai buscar a equivalente a un disco duro, un forense imaxe dun tarxeta de memoria flash compacto dende un cámara dixital, buscando a 0s 1s e que normalmente, con elevada probabelmente, representan o inicio dunha imaxe JPEG. E vostedes poden recuperar aquelas imaxes por supoñendo que, se eu vexo ese patrón de bits na imaxe forense, con elevada probabilidade, que marca o inicio dun JPEG. E se eu ver o mesmo patrón de novo, que probablemente marca o inicio outro JPEG, e outro JPEG, e outro JPEG. E este é tipicamente como recuperación de datos vai funcionar. Que é agradable sobre JPEGs o é formato de ficheiro en si é algo complexo, ao comezo de cada tal ficheiro é realmente moi identificable e sinxela, como podes ver, Se non ten xa. Entón, imos dar un ollo debaixo o capó como a exactamente o que foi pasando, e que estes 0s e 1s son, para darlle un pouco máis dun contexto para este desafío particular. [REPRODUCIÓN] -Onde seu ordenador almacena máis dos seus datos permanentes. Para iso, os datos viaxan de RAM xunto con sinais de software que din o disco duro como almacenar eses datos. Os circuítos do disco duro traducir eses sinais en tensión flutuacións. Estes, á súa vez, controlan o disco duro do partes móbiles, algúns dos poucos partes móbiles deixados no ordenador moderno. Algúns dos sinais de control dun motor que xira bandexas de metal recubertas. Os seus datos son realmente almacenados sobre estas travesas. Outros signos de mover a lectura / escritura cabezas de lectura ou gardar datos sobre os pratos. Esta máquina tan preciso que un ser humano pelo non podería mesmo pasar entre a cabezas e pratos xiratorios. Con todo, todo funciona en velocidades incribles. [FIN reprodución de vídeo] DAVID Malan: Zoom nun pouco máis profunda agora o que está realmente neses pratos. [REPRODUCIÓN] -Vexamos o que acabamos de vin en cámara lenta. Cando un breve pulso de electricidade é enviado a cabeza de lectura / gravación, se vira nunha pequena electromagnética para unha fracción de segundo. O imán crea un campo, que cambia a polaridade dun pequeno, minúsculo parte das partículas metálicas que abrigo de cada superficie do prato. A serie estándar destes pequenos, cobra ata áreas no disco representa un único bit datos no número binario sistema usado polos ordenadores. Agora, se a corrente é enviada unha forma a través da lectura / escritura cabeza, a área é polarizada nunha dirección. Se a corrente é enviada en sentido oposto, o polarización é invertida. Como obter datos fóra do disco duro? Só reverter o proceso. Por iso é que as partículas no disco que obteña a corrente no lectura / escritura cabeza movendo. Xuntos millóns destes rutas magnetizados e ten un arquivo. Agora, as pezas dun único arquivo pode ser espallados por toda a unidade de pratos, como o tipo de desorde de papeis na súa mesa. Así, un arquivo moi especial mantén o control de onde está todo. Non quere ter algo así? [FIN reprodución de vídeo] DAVID Malan: OK, probablemente non. Así como moitos de vostedes Medrei con iso? OK, por iso é cada vez menos mans cada ano. Pero eu estou feliz que estea polo menos familiarizado con eles, porque esta é a nosa propia demostración libro, desgraciadamente, están morrendo moi retardar a morte aquí de familiaridade. Pero iso é o que eu, polo menos, de volta ensino medio, o uso empregado para copias de seguridade. E foi incrible, porque pode almacenar 1,4 megabytes en este disco en particular. E esta foi a versión de alta densidade, indicadas pola alta definición, que ten é dicir, antes de videos de hoxe en HD. Densidade estándar era de 800 kilobytes. E antes diso, había Discos de 400 kilobytes. E antes diso, había 5 e 1/4 discos polgadas, que eran verdadeiramente flexible, e algo máis ancho e máis alto que estas cousas aquí. Pero realmente pode ver o chamado aspecto disquete destes discos. E funcionalmente, son, en realidade, moi semellante ao de discos duros de polo menos deste tipo. Unha vez máis, os SSDs en ordenadores máis novos traballar un pouco diferente. Pero se se move, que guía de metal pouco, realmente pode ver un pouco de biscoito, ou varanda. Non é de metal coma este. Este é realmente un pouco máis barato material plástico. E pode tipo de manobra-lo. E trully só limpou algúns número de bits ou partículas magnéticas dende este disco. Entón, por sorte, non hai nada sobre el. Se esa cousa está no camiño - e cobre os seus ollos e os do seu veciño - pode só tirar este tipo de toda off vaina así. Pero hai unha pequena primavera, que así sexa consciente de que, cos seus ollos. Entón agora ten realmente un disquete. E o que é notable sobre esta é que, na medida en que este é un representación a pequena escala dunha maior disco duro, esas cousas son super, super sinxelo. Se usar a parte inferior do mesmo, agora que que cousa de metal está fóra, e pele las abertas, o único que hai é dúas pezas de feltro e o chamado disquete cunha peza de metal no interior. E alí se vai a metade do contido do meu disco. Aí vai outra metade deles. Pero iso é todo o que estaba xirando dentro do seu ordenador no pasado. E, de novo, para poñer isto en perspectiva, Que grande é a maioría do seu discos duros de hoxe en día? 500 gigabytes, un terabyte, talvez en un ordenador de escritorio, dous terabytes, 3 terabytes, 4 terabytes, non? Este é un megabyte, máis ou menos, que non pode sequera poñer un MP3 típico tecleamos máis algúns días ou unhas arquivo de música similar. Así, unha pequena lembranza para ti hoxe, e tamén para axudar a contextualizar o nós imos tomar para concedida agora no problema establecer cinco. Polo tanto, estas son da súa propiedade. Entón déixeme transición cara a onde se pasar á seguinte pset ben. Entón, nós temos agora configurar esta páxina a - Oh, un par de anuncios de forma rápida. Este venres, se quere unirse a CS50 para o xantar, ir ao lugar de costume, cs50.net/rsvp. Correo proxecto final - entón por que o programa, nos postamos o especificación do proxecto final xa. Entenda que iso non quere dicir que débese especialmente pronto. Está publicado, en realidade, só para obter vostedes a pensar niso. E, de feito, un súper importante porcentaxe de será fronte proxectos finais de material que nin sequera chegou a na clase, pero será xa a próxima semana. Teña en conta, porén, que a especificación require algúns compoñentes distintos do proxecto final. O primeiro, en algunhas semanas é un pre-proposta, un correo-e moi casual para o TF para lle dicir ou o que está pensar para o seu proxecto, con ningún compromiso. Proposta será o seu particular compromiso, dicindo, aquí, iso é o que Gustaríame facer para o meu proxecto. ¿Que pensas? Moi grande? Moi pequena? É viable? E ve a especificación para máis detalles. Dúas semanas despois do que é o estado informe, que é unha forma similar correo casual para o TF para dicir o no; moi lonxe está na súa última implantación do proxecto, seguido por o CS50 hackathon ao cal todos é invitado, que será un evento de 20:00 nunha noite ata 07:00 AM na mañá seguinte. Pizza, como eu xa mencionei a semana cero, Wil ser servido en 09:00, Comida chinesa en 1h00. E se aínda está acordado á 5h00, imos levalo para IHOP no almorzo. Así, o hackathon é un dos máis experiencias memorábeis na clase. A continuación, a implementación é debido, e a continuación, o CS50 Fair clímax. Máis detalles sobre todos estes nas semanas que virán. Pero imos voltar a algo vella escola - outra vez, unha matriz. Así, unha matriz foi bo, porque resolve problemas como vimos só un momento atrás, con estruturas estudantís quedando un pouco fóra de control se quere ter un alumno, estudante dous, estudante tres, estudante dot dot dot, un número arbitrario de alumnos. Entón, matrices, algunhas semanas atrás, mergullou e resolveu todos os nosos problemas de non sabendo de antemán cantas cousas de calquera tipo que pode querer. E vimos que estruturas pode axudarnos aínda organizar noso código e manter variables conceptualmente similares, como a nome e unha casa, en conxunto, de xeito que temos pode tratalos como unha entidade, dentro dos cales hai anacos pequenos. Pero matrices teñen algunhas desvantaxes. Cales son algunhas das desvantaxes atopamos con matrices ata agora? ¿Que é iso? Tamaño fixo - que aínda que pode poder reservar memoria para un matriz, xa que sabe cantos alumnos ten, cantos caracteres ten do usuario, unha vez que teña asignado a matriz, ten tipo de pintado só nun recuncho. Porque non pode introducir novos elementos no medio dunha matriz. Non pode introducir máis elementos ao final dunha matriz. Realmente, ten que recorrer á creación dun Toda nova matriz, como xa discutido, copiando o antigo para o novo. E unha vez máis, que é a dor de cabeza que GetString manexa para ti. Pero, de novo, non se pode inserir algo no medio da matriz se o tipo non está completamente chea. Por exemplo, se esa matriz aquí de tamaño seis ten só cinco cousas nel, Ben, pode só alinhavar algo para o efecto. Pero e se quere inserir algo no medio da matriz, aínda que pode ter cinco dos seis cousas nel? Ben, o que fixemos cando tiñamos todo dos nosos voluntarios humanos no escenario semana pasado? Se quixésemos poñer alguén aquí, tamén esas persoas como mover este xeito, ou eles mesmos como mover este forma, e que se fixo caro. O desprazamento de persoas no interior dun serie acabou sumando e custando nos tempo, polo tanto, moi do noso n ao cadrado veces funciona como un tipo de inserción, por exemplo, no peor dos casos. Así, as matrices son grandes, pero ten que saber de antemán o quão grande quere. Entón, OK, aquí está unha solución. Se eu non saber de antemán cantos os alumnos que eu podería ter, e sei que unha vez Eu decido, con todo, eu estou preso con que moitos estudantes, polo que non sempre reservar o dobre do espazo como eu podería pensar que eu teño? Isto non é unha solución razoable? En realidade, eu non creo que somos Vai ter máis de 50 caza de recreo nunha matriz para unha clase de tamaño medio, entón imos redondear para arriba. Vou facer 100 slots no meu array, só para que poidamos sempre o número de alumnos que esperan ser, dalgunha clase de tamaño medio. Entón por que non reunir e reservar máis memoria, tipicamente, por unha matriz Que pensas que pode incluso ter? ¿Que é iso pushback simple a esa idea? Só está perdendo memoria. Literalmente todos os programas que escribe, a continuación, é quizais a usar o dobre da memoria como realmente precisa. E iso só non se sente como un especialmente solución elegante. Ademais, só diminúe o probabilidade dun problema. Se ocorrer de ter un curso popular un semestre e ten 101 estudantes, o programa aínda é fundamentalmente afrontando o mesmo problema. Entón, por sorte, hai unha solución para Este anuncio todos os nosos problemas, en forma de estruturas de datos que son máis complexos do que os vimos ata agora. Iso, eu afirmo, é unha lista encadeada. Esta é unha lista de números - 9, 17, 22, 26 e 34 - que foron ligadas entre si de forma do que eu deseño como frechas. Noutras palabras, se eu quería representar unha matriz, que eu podería facer algo así. E eu vou poñer isto a sobrecarga en só un momento. Podería facer - Ola, todo ben. Stand by. Novo ordenador aquí, claro - todo ben. Entón, se eu teño eses números en orde - 9, 17, 22, 26, 24 - non necesariamente a escala. Todo ben, iso aquí é a miña matriz - oh meu deus. Todo ben, iso aquí é a miña matriz. Oh meu deus. [Risas] DAVID Malan: Pretend. É moito esforzo para volver e corrixir iso, entón alí - 26. Entón temos ese conxunto de 9, 17, 22, 26, e 34. Para aqueles de vostedes poden ver o erro embaraçoso que acaba de facer, aí está. Entón eu afirmar que esta é unha solución moi eficaz. Eu asignado como moitos ints como Eu teño - un, dous, tres, catro, cinco ou seis - e eu entón almacenados os números interior desta matriz. Pero imos supoñer que, entón, quero introducir un valor como o número 8? Ben, para onde vai? Supoña que queira inserir un número como 20. Ben, para onde vai? Nalgún lugar no medio, ou o número 35 ten que pasar algures no final. Pero eu estou fóra do espazo. E por iso este é un reto fundamental das matrices que non son a solución. Afirmei hai pouco, GetString resolve este problema. Se desexa inserir unha sexto número nesa matriz, o que é, polo menos, un solución que pode volver a caer, con certeza, así como facemos con GetString? ¿Que é iso? Así, facelo máis grande é máis fácil de dicir que facer. Non podemos necesariamente facer a matriz maior, pero o que podemos facer? Fai unha nova matriz que é maior, de tamaño 6, ou que tamaño 10, se queremos para chegar á fronte das cousas, e entón por favor copie o array antigo ao novo, e, a continuación, liberar a antiga matriz. Pero o que é o tempo de execución agora deste proceso? É grande S de n, xa que a copia lle vai custar algunhas unidades de tempo, polo que non é tan ideal, se é preciso reservar unha nova matriz, o que está pasando consumindo o dobre memoria temporal. Pega vello en novo - Quero dicir, é só unha dor de cabeza, que é, unha vez máis, por que escribiu GetString para ti. Entón, o que podemos facer no seu canto? Ben, e se a nosa estrutura de datos en realidade, ten lagoas nel? Supoñamos que eu relaxo meu obxectivo de ter bloques contiguos de memoria, onde 9 é ben próximo a 17, o que é xunto 22, e así por diante. E supoña que 9 pode ser aquí en RAM, e 17 pode ser por aquí na RAM, e 22 pode ser aquí en RAM. Noutras palabras, eu non teño deles mesmo volver atrás máis. Eu só teño que dalgunha forma enfiar unha agulla a través de cada un destes números, ou cada destes nós, como imos chamar o rectángulos como eu deseño a eles, para recordar como chegar ao último tal nó do primeiro. Entón o que é construír a programación vimos hai pouco tempo co que me pode aplicar ese segmento, ou trazada aquí, co cal podo aplicar esas frechas? Punteiros así, non? Se eu non reservar só un int, pero un nó - e por no, eu só quero dicir container. E visual, quero dicir un rectángulo. Así, un nó aparentemente necesita para conter dous valores - o propio int, e entón, como se conclúe da a metade inferior do rectángulo, espazo suficiente para un int. Entón, só tes que pensar no futuro aquí, quão grande é este nodo, este recipiente en cuestión? Cantos bytes ao int? Presuntamente, 4, se é o mesmo que o habitual. E entón cantos bytes ao punteiro? 4. Polo tanto, este recipiente, ou este nodo, é vai ser unha estrutura de 8 bytes. Ah, e iso é unha feliz coincidencia que que acaba de introducir a noción de unha estrutura ou unha estrutura C. Entón, eu afirmo que quero dar un paso para iso máis sofisticado implementación dunha lista de números, un lista encadeada de números, eu teño que facer unha pouco máis o pensamento diante e declarar non só un int, pero un struct que eu ligo, convencionalmente aquí, o nó. Poderiamos chamalo de calquera cousa que queiramos, pero nodo será temática nun monte das cousas que comezar a ollar para o momento. Dentro dese nodo é un int n. E entón esa sintaxe, un pouco estraño a primeira vista - struct node * seguinte. Ben pictoricamente, o que é iso? Esa é a metade inferior da o rectángulo que vimos só un momento atrás. Pero por que digo struct node * no canto de só nodo *? Porque se ese punteiro está a apuntar noutro nodo, é só o enderezo dun nodo. Isto é consistente co que temos discutido sobre punteiros ata o momento. Pero por que, se eu reclamar esta estrutura é chamado nó, que teño que dicir struct nó aquí dentro? Exactamente. É unha especie de unha realidade estúpida C. O typedef, por así dicir, non ten aconteceu aínda. C é super literal. El le o seu código para arriba abaixo, de esquerda a dereita. E ata que chega ese punto e coma no liña de fondo, creo que non funciona existir como un tipo de datos? No, o nó entre comiñas. Pero por mor da máis detallado declaración que fixen na primeira liña - typedef struct node - xa que veu primeiro, antes da chaves, que é unha especie de como pre-educar Clang iso, Sabe, me dea un struct chamado nó struct. Francamente, eu non me gusta de cousas que chaman struct node, struct node todo todo o meu código. Pero eu só vou usalo xa, só dentro, para que eu poida efectivamente crear unha especie de referencia circular, non un punteiro para min mesmo, por si só, pero unha ligazón a outra un do mesmo tipo. Así, verifícase que nunha estrutura de datos así, hai algúns as operacións que se poden de interese para nós. Podemos querer inserir nunha lista como esta. Podemos querer borrar desde unha lista como esta. Podemos querer buscar a lista para unha valor, ou, máis xeralmente, travesía. E transversal é só un xeito elegante de dicindo inicio á esquerda e mover todos o camiño para a dereita. E noten, mesmo con ese algo máis estrutura de datos texto, imos me propor que podemos prestar algúns dos as ideas das últimas dúas semanas e implementar unha función chamada investigación como esta. Devolverá verdadeiro ou false, o que indica, si ou n, n está na lista. O segundo argumento é un punteiro á propia lista, co fin de punteiro para un nó. Todo o que eu vou facer a continuación é declarar unha variable temporal. Imos chamalo de PTR por convención, para punteiro. E eu atribuílo lo igual ao inicio da lista. E agora teña en conta o loop while. Mentres o punteiro non é igual como nulo, vou comprobar. É punteiro de frecha n igual n que foi pasado en? E agarde un minuto - novo peza de sintaxe. Cal é o arco de súpeto? Si? Exactamente. Así, mentres a poucos minutos, usan a notación de punto para acceder algo o interior dunha estrutura, a variable non é o struct si mesmo, pero un punteiro a unha struct, por sorte, un anaco de sintaxe que finalmente ten sentido intuitivo. A frecha significa seguir o punteiro, como as nosas frechas normalmente significa pictoricamente, e ir en campo de datos en interior. Entón frecha é o mesmo que punto, pero usalo cando ten un punteiro. Entón, só para recapitular, entón, se o campo de n dentro da estrutura chamada de punteiro é igual a igual a n, retorna true. En caso contrario, esta liña aquí - punteiro igual punteiro próximo. Entón o que está facendo, o aviso previo, é que se eu actualmente estou apuntando para a estrutura conteñen 9 e 9 non é o número Estou buscando - supoño que eu estou buscando para n igual a 50 - Vou actualizar o meu punteiro temporal para non ligar a este nodo máis, pero punteiro frecha ao lado, que me vai poñer aquí. Agora entender que é un turbillón introdución. O mércores, imos realmente facelo con algúns seres humanos, e cun pouco máis código en un ritmo máis lento. Pero entendo, agora estamos facendo os nosos datos estruturas máis complexas para que o noso algoritmos poden ser máis eficiente, o que será requisito para pset seis, cando premer en, unha vez máis, os 150 mil palabras, pero ten que facelo de forma eficaz e, idealmente, crear un programa que se executa para os nosos usuarios non en lineal, non en n ao cadrado, pero en constante de tempo, de ideal. Vemo-nos o mércores. Palestrante: Na seguinte CS50, David esquece o seu caso base. DAVID Malan: E é así que envía mensaxes de texto con C. Que - [VARIOS mensaxe de texto Sons de notificación]