[Powered by Google Translate] [Review] [0 Quiz] [Lexi Ross, Tommy MacWilliam, Lucas Freitas, José Ong] [Harvard University] [Esta é CS50.] [CS50.TV] Ei, todo o mundo. Benvido á sesión de revisión para Quiz 0, o que está a ter lugar este mércores. O que imos facer hoxe á noite, eu estou con tres TFS outros, e xuntos imos pasar por unha revisión do que fixemos no curso ata o momento. Non vai ser 100% completo, pero debe darlle unha idea mellor que xa ten para abaixo e que aínda que estudar antes do mércores. E Sinto-se libre para levantar a man con preguntas como estamos indo, pero teña en conta que nós tamén imos ter un pouco de tempo ao final- acabar con uns minutos de sobra para facer preguntas xerais, de modo manter isto presente, e por iso estamos indo para comezar no inicio coa Semana 0. [Cuestionario 0 comentario!] [Parte 0] [Lexi Ross] Pero antes de facelo, imos falar sobre a loxística do quiz. [Loxística] [quiz ocorre o mércores 10/10, en vez dunha charla] [(Vexa http://cdn.cs50.net/2012/fall/quizzes/0/about0.pdf para máis detalles)] e mércores, 10 de outubro. Isto é onte, e vai a este URL aquí, que tamén é accesible desde CS50.net-hai unha ligazón a el- podes ver información sobre onde ir con base en seu sobrenome ou filiación escola, así como fala sobre exactamente o que o exame pode cubrir e os tipos de preguntas que vai conseguir. Teña presente que tamén vai ter a oportunidade de revisar a responder ao exame da sección, para que os seus TFS debe ir sobre algúns problemas da práctica, e esa é outra boa oportunidade de ver onde aínda que estudar para o quiz. Imos comezar no inicio con Bytes 'n' bits. Lembre-se un pouco é só un 0 ou un 1, e un byte é unha colección de oito deses bits. Imos ollar para esta colección de bits aquí. Debemos ser capaces de descubrir cantos bits existen. Onde contamos hai só 8 deles, oito 0 ou 1 unidades. E dende hai 8 bits, que é 1 byte, e imos convertelo en hexadecimal. Hexadecimal é base 16, e é moi fácil de se converter un número en binario, que é o que é, para un número hexadecimal. Todo o que facemos é mirar para grupos de 4, e convertela los para o díxito hexadecimal correspondente. Comezamos co grupo máis á dereita, 4, polo tanto, 0011. Isto vai ser un 1 e un 2 para xuntos, que fai 3. E entón, imos ollar para o outro bloque de 4. 1101. Isto vai ser un 1, un 4 e un 8. Xuntos que vai ser 13, o que fai D. E imos lembrar que en hexadecimal que non só tes que ir de 0 a 9. Imos 0 a F, entón despois de 9, 10 corresponde a A, 11 a B, et cetera, onde F é 15. Aquí 13 é un D, para convertelo-lo para decimal todo o que facemos é realmente tratar cada posición como unha potencia de 2. Isto é un 1, un 2, cero 4s, cero 8s, unha 16, etcétera, e é un pouco difícil de calcular na súa cabeza, pero se somos ao seguinte diapositiva podemos ver a resposta para iso. Esencialmente nós estamos indo en fronte de volta cara á esquerda, e nós estamos multiplicando cada díxito pola potencia correspondente de 2. E lembre, para hexadecimal denotamos estes números con 0x no inicio para que non se confunda con un número decimal. Continuando, esta é unha táboa ASCII, eo que nós usamos ASCII para se situar a partir de caracteres para valores numéricos. Teña en conta que no pset cifrado que fixo uso extensivo da táboa ASCII a fin de utilizar varios métodos de criptografía, o César ea cifra de Vigenère, para converterse letras diferentes nunha cadea de acordo coa clave dada polo usuario. Imos mirar un pouco de matemáticas ASCII. Mirando para 'P' + 1, na forma de carácteres, que sería Q, e lembre que '5 '≠ 5. E como exactamente pode converter entre estas dúas formas? Non é realmente moi difícil. A fin de obter 5 subtraímos '0 ' porque hai cinco prazas entre o '0 'eo '5'. Co fin de ir por outro camiño que acabamos de engadir a 0, por iso é unha especie de como aritmética regular. Basta lembrar que cando algo ten aspas arredor del é un personaxe e, polo tanto, corresponde a un valor na táboa ASCII. Movéndose para temas máis xerais da ciencia de ordenadores. Aprendemos que un algoritmo é e como se usa a programación para aplicar algoritmos. Algúns exemplos de algoritmos son algo realmente simple como comprobar se un número é par ou impar. Para que lembrar que mod o número por 2 e comprobar o resultado é 0. Se é así, é mesmo. Se non é estraño. E iso é un exemplo dun algoritmo moi básico. Un pouco de máis dun implicado é de busca binária, que falaremos sobre máis tarde na sesión de revisión. E a programación é o termo que usan para tomar un algoritmo e convertela-lo para codificar o ordenador poida ler. 2 exemplos de programación Scratch, que é o que nós fixemos a Semana 0. Aínda que realmente non escribir o código é unha forma de implementar Nese algoritmo, o cal está a imprimir os números 1-10, e aquí podemos facer o mesmo na linguaxe de programación C. Estes son funcionalmente equivalentes, só escrito en diferentes linguas ou de sintaxe. A continuación, aprendeu sobre expresións booleanas, e un booleano é un valor que é certo ou falso, e expresións aquí moitas veces booleanos ir dentro de condicións, por iso, se (x ≤ 5), ben, nós xa definido x = 5, de xeito que condición vai avaliar a true. E se é verdade, calquera código que está por debaixo da condición Vai ser avaliada polo ordenador, de xeito que a corda que vai ser impreso para a saída estándar, ea condición prazo refírese a todo o que está dentro dos parénteses da declaración se. Lembre-se de todos os operadores. Lembre-se de && e | | cando estamos intentando combinar dous ou máis condicións, = Non == para comprobar se dúas cousas son iguais. Lembre que é = a asignación mentres == é un operador booleano. ≤, ≥ e despois o final 2 son auto-explicativos. Unha revisión xeral da lóxica booleana aquí. E expresións booleanas tamén son importantes en loops, que nós imos pasar por riba agora. Nós aprendemos sobre tres tipos de loops ata agora en CS50, polo de agora, e facer agora. E é importante saber que, mentres na maioría dos casos podemos realmente usar calquera tipo de loop xeralmente existen certos tipos de propósitos ou patróns comúns na programación que, especificamente, chamar a un destes lazos que fan que o. máis eficiente ou elegante para codifica-lo desa forma Imos falar sobre o que cada un destes ciclos tende a ser usado para máis frecuencia. En un loop que xeralmente xa sabe cantas veces queiramos interactuar. Isto é o que poñemos na condición. Para i = 0, i <10, por exemplo. Nós xa sabemos que queremos facer algo 10 veces. Agora, para un loop while, xeralmente non necesariamente Sabe cantas veces queremos que o lazo sexa executado. Pero sabemos que algún tipo de condición que queremos que sempre certo ou ser sempre falso. Por exemplo, mentres que é definido. Imos dicir que é unha variable booleana. Mentres tanto é verdade que queremos o código para avaliar, así un pouco máis extensible, un pouco máis xeral do que un loop, pero ningún por lazo pode ser convertido a un loop. Finalmente, facer loops while, que pode ser o máis complicado de entender de inmediato, son usados ​​frecuentemente cando queremos avaliar o primeiro código antes da primeira vez que comprobar a condición. Un caso de uso común para un facer loop while é cando quere obter a entrada do usuario, e vostede sabe que quere preguntar ao usuario para a entrada de polo menos unha vez, pero se eles non dan a vostede unha boa entrada de inmediato quere seguir facendo ata que eles dan-lle a boa entrada. Ese é o uso máis común de un loop Do While, e imos ollar para a estrutura real de estes lazos. Eles normalmente sempre tenden a seguir estes patróns. O lazo para dentro de ti ter 3 compoñentes: inicio, tipicamente algo int i = 0, onde i é o contador, condición, onde nós queremos dicir para realizar este ciclo mentres a esa condición aínda permanece, como i <10, e despois, finalmente, actualización, que é como incrementar a variable de contador en cada punto do ciclo. Unha cousa común para ver que hai só i + +, o que significa incrementar i por unha de cada vez. Tamén pode facer algo como i + = 2, o que significa engadir 2 a I Cada vez que pasar polo loop. E entón a facer iso só se refire a calquera código que realmente funciona como parte do ciclo. E para un loop while, esta vez nós realmente temos o arranque fóra do circuíto, así, por exemplo, imos dicir que estamos a tentar facer o mesmo tipo de loop como acaba de describir. Diriamos int i = 0 antes do lazo comeza. Entón poderiamos dicir mentres i <10 facelo, así mesmo bloque de código como antes, e esta vez a parte de actualización do código, por exemplo, i + +, realmente vai dentro do loop. E, finalmente, para un facer agora, é semellante ao do loop while, pero temos que lembrar que o código pode avaliar unha vez antes a condición é posible, por iso fai moito máis sentido se ollar para el, a fin de arriba para abaixo. Nun, facer mentres o código loop avalía antes de ollar para a condición, mentres mentres que un loop while, el verifica primeiro. Demostracións e variables. Cando queremos crear unha nova variable que primeiro quere para o arrincar. Por exemplo, a barra int inicia a barra variable, pero non darlle un valor, entón o que é o valor bar agora? Nós non sabemos. Pode ser un valor de lixo que foi previamente almacenado na memoria de alí, e nós non queremos usar esa variable ata que, en realidade, darlle un valor, para que declara-lo aquí. A continuación, iniciar a ser 42 a continuación. Agora, por suposto, sabemos que isto pode ser feito nunha única liña, bar int = 42. Pero só para quedar claro as distintas etapas que están en curso, a declaración e arranque están a suceder por separado aquí. Isto acontece nunha única etapa, e na próxima, int Baz = bar + 1, esta declaración abaixo, que Baz incrementos para que ao final do bloque de código se fósemos para imprimir o valor Baz sería 44 porque declarar e arrincar que sexa unha barra de>, e entón incrementa-lo unha vez máis co + +. Nós fomos sobre iso brevemente bonito, pero é bo ter un xeneral comprensión do que temas e eventos. Nós principalmente, fixo iso en scratch, para que poida pensar en temas como varias secuencias de código executando ao mesmo tempo. En realidade, probabelmente non está funcionando, ao mesmo tempo, pero unha especie de abstractamente podemos pensar niso desa forma. No Scratch, por exemplo, tivemos os distintos sprites. Podería ser de execución de código diferentes ao mesmo tempo. Un deles podería ser a pé, mentres que o outro está dicindo algo nunha parte diferente da pantalla. Os eventos son unha outra forma de separar a lóxica entre os distintos elementos do seu código, e scratch fomos capaces de simular eventos usando Broadcast, e que é, en realidade, cando eu recibir, non cando escoito, pero, esencialmente, é unha forma de transmitir información a partir dun sprite para o outro. Por exemplo, pode querer transmitir ao longo do xogo, e cando outro sprite recibe ao longo do xogo, el responde dunha certa maneira. É un modelo importante para comprender a programación. Só para ir durante a semana básica 0, o que xa sabemos, ata agora, imos mirar para este programa C simple. O texto pode ser un pouco pequeno, a partir de aquí, pero eu vou pasar por iso moi rápido. Estamos incluíndo dous ficheiros de cabeceira na parte superior, cs50.h e stdio.h. Estamos entón a definición dun límite constante chamado a ser 100. Estamos a continuación, aplicar a nosa función principal. Unha vez que non usar argumentos de liña de comandos aquí, cómpre poñer baleiro como os argumentos para inicio. Vemos int enriba principal. Ese é o tipo de retorno, polo tanto, volver 0 na parte inferior. E estamos usando CS50 función de biblioteca obter int para pedir ao usuario para a entrada, e almacena-lo nesta variable x, Así, declaramos x arriba, e arrincar-lo con x = GetInt. A continuación, comproba que o usuario nos deu unha boa entrada. Se é LÍMITE ≥ queremos voltar un código de erro de 1 e imprimir unha mensaxe de erro. E, finalmente, a entrada o usuario ten nos dado boa imos facer a quadratura do número e imprima o resultado. Só para estar seguro de que os casa hit todos podes ver as etiquetas de diferentes partes do código aquí. Mencionei constantes, arquivos de cabeceira. Oh, int x. Asegúrese de lembrar que é unha variable local. Isto contrasta dunha variable global, o que imos falar sobre un pouco máis tarde na sesión de revisión, e estamos chamando a función de biblioteca printf, Polo tanto, se non había incluído o ficheiro de cabeceira stdio.h non sería capaz de chamar printf. E creo que a frecha que foi cortada aquí está a apuntar cara o% d, que é unha cadea de formato no printf. Di imprimir esa variable como un número% d. E é que para a Semana 0. Agora Lucas vai continuar. Ola, persoal. O meu nome é Lucas. Eu son un estudante de segundo ano da mellor casa no campus, Mather, e eu vou falar un pouco sobre a semana 1 e 2,1. [Semana 1 e 2,1!] [Lucas Freitas] Como Lexi estaba dicindo, cando comezamos a traducir o seu código a partir de cero para C unha das cousas que percibimos é que non pode simplemente escribir o seu código e executa-lo usando unha bandeira verde máis. En realidade, ten que usar algunhas medidas para facer o seu programa C tornar-se un arquivo executábel. Basicamente o que fai cando está escribindo un programa que traducir a súa idea nunha linguaxe que un compilador pode entender, Entón, cando está escribindo un programa en C o que está facendo é realmente escribir algo que o compilador vai entender, e, a continuación, o compilador vai traducir este código en algo que o ordenador vai entender. E a cousa é, o seu ordenador é realmente moi burro. O seu ordenador non pode entender 0s e 1s, Entón, en realidade nos primeiros ordenadores xente xeralmente programados usando 0s e 1s, pero non máis, grazas a Deus. Non temos que memorizar secuencias de 0s e 1s para un loop ou loop de tempo e así por diante. É por iso que temos un compilador. O que un compilador fai é, basicamente, traduce o código C, no noso caso, para unha linguaxe que o ordenador vai entender, Que é o código obxecto, eo compilador que estamos usando chámase bumbum, polo que esta é, en realidade, o símbolo para o bumbum. Cando ten o seu programa, ten que facer dúas cousas. Primeiro, ten que compilar o seu programa, e entón está indo para executar o seu programa. Para compilar o seu programa que ten unha morea de opcións para facelo. O primeiro é facer program.c bumbum en que programa é o nome do seu programa. Neste caso, podes ver que eles están só dicindo "Ola, compilar meu programa". Non está dicindo "Eu quero este nome para o meu programa", ou algo. A segunda opción é dar un nome para o seu programa. Pode dicir clang-o e, a continuación, o nome que quere o arquivo executábel para ser nomeado como e despois program.c. E tamén pode facer facer programa, e ver como nos primeiros dous casos Eu coloque. C, e no terceiro eu só teño programas? Si, realmente non debe poñer. C cando usa facer. En caso contrario, o compilador é, en realidade, vai berrar con vostede. E tamén, eu non sei se vostedes lembran, pero moitas veces tamén usan-lcs50 ou lm. Iso é chamado de conexión. El só informa o compilador que vai usar esas bibliotecas alí, por iso, se quere usar cs50.h realmente ten que escribir clang program.c-lcs50. Se non fai iso, o compilador non vai saber que está a usar estas funcións en cs50.h. E cando quere executar o programa ten dúas opcións. Se fixo program.c clang non dar un nome para o seu programa. Ten que executa-lo usando. A.out /. A.out é un nome estándar que bumbum dá o seu programa se non darlle un nome. Se non, vai facer. Programa / se deu un nome para o seu programa, e tamén se fixo o nome do programa que o programa vai estar xa está indo para ser programado o mesmo nome que o ficheiro c. Entón nós falamos sobre os tipos de datos e datos. Basicamente tipos de datos son a mesma cousa que usan pequenas caixas para almacenar valores, por iso os tipos de datos son, en realidade, só como Pokémons. Eles veñen en todos os tamaños e tipos. Eu non sei se esa analoxía ten sentido. O tamaño dos datos, en realidade, depende da arquitectura da máquina. Todos os tamaños de datos que eu vou amosar aquí son, en realidade, para unha máquina de 32 bits, que é o caso do noso dispositivo, pero se está realmente codificación do seu Mac ou Windows tamén Probablemente vai ter unha máquina de 64 bits, para lembrar que os tamaños de datos que eu vou amosar aquí son para a máquina de 32 bits. O primeiro que vimos foi un int, que é moi sinxelo. Usa int para almacenar un número enteiro. Vimos tamén o carácter, o char. Se quere usar unha carta ou un pequeno símbolo que probablemente vai usar un char. Un char ten 1 byte, o que significa 8 bits, como Lexi dixo. Basicamente, temos unha táboa ASCII que 256 combinacións posibles de 0s e 1s, e entón, cando inserir un carácter que vai traducir o carácter que as entradas un número que ten na táboa ASCII, como Lexi dixo. Temos tamén a boia, que usan para almacenar números decimais. Se queres escoller 3,14, por exemplo, vai empregar un flotador ou unha parella que ten máis precisión. Unha boia ten 4 bytes. O dúo ten 8 bytes, entón a única diferenza é a precisión. Temos tamén unha lonxitude que se usa para enteiros, e podes ver por unha máquina de 32 bits dun int e un long teñen o mesmo tamaño, por iso non fai moito sentido usar un longa nunha máquina de 32 bits. Pero se vostede está a usar un ordenador Mac e 64-bit, en realidade, unha longa ten tamaño 8, por iso realmente depende da arquitectura. Para a máquina de 32 bits, non ten sentido usar un longa de verdade. E, a continuación, un tempo longo, por outro lado, ten 8 bytes, por iso é moi bo se quere ter un número enteiro máis. E, finalmente, temos cadea, que é na verdade un char *, que é un punteiro para unha char. É moi fácil pensar que o tamaño da cadea vai ser como o número de caracteres que ten alí, pero, en realidade, * o char-se ten o tamaño dun punteiro para unha char, que é de 4 bytes. O tamaño dunha char * é 4 bytes. Non importa se ten unha pequena palabra ou unha letra ou algo. Vai ser de 4 bytes. Tamén aprendemos un pouco sobre o reparto, Entón, como podes ver, se ten, por exemplo, un programa que di int x = 3 e, a continuación, printf ("% d", x / 2) vostedes saben o que vai imprimir na pantalla? Alguén? >> [Os alumnos] 2. 1. >> 1, si. Cando fai 3/2 vai obter 1,5, pero xa que estamos usando un enteiro que vai ignorar a parte decimal, e vai ter un. Se non quere que isto ocorre o que podes facer, por exemplo, é declarar un float y = x. Entón x que adoitaban ser tres agora vai ser 3,000 en y. E entón podes imprimir o s / 2. En realidade, eu debería ter un 2. alí. El vai facer 3.00/2.00, e está indo para obter 1,5. E temos esa f 0,2 só para pedir 2 unidades decimais da parte decimal. Se ten 0,3 f que vai ter, en realidade, 1.500. Se é 2, será 1,50. Tamén temos ese caso aquí. Se fai float x = 3,14 e entón x printf está indo para obter 3.14. E se fai x = int X, o que significa tratar x como un int e imprimir x agora vai ter 3,00. Isto ten sentido? Porque é primeiro tratar x como un número enteiro, entón está ignorando a parte decimal, e entón está imprimindo x. E, finalmente, tamén se pode facer iso, int x = 65, e entón declarar un char c = x, e entón se imprimir o c realmente está indo para obter Un, entón basicamente o que está facendo aquí está traducindo o enteiro para o personaxe, así como a táboa ASCII fai. Tamén falamos sobre operadores matemáticos. A maioría deles son moi sinxelo, para +, -, *, /, e tamén falamos sobre mod, que é o resto da división de dous números. Se ten un 10% 3, por exemplo, significa dividir 10 por 3, e que é a parte restante? Vai ser 1, polo que é realmente moi útil para unha morea de programas. Para Vigenère e César eu estou seguro que todos vostedes utilizado mod. Sobre operadores matemáticos, ter moito coidado ao combinar * e /. Por exemplo, se vostede fai (3/2) * 2 o que vai conseguir? [Os alumnos] 2. É, 2, por 3/2 vai ser igual a 1,5, pero unha vez que está facendo operacións entre dous números enteiros en realidade está indo só para considerar un, e 1 * 2 vai ser 2, que debe ter moito coidado ao facer aritmética con enteiros porque pode ter que 2 = 3, nese caso. E tamén ter moito coidado coa precedencia. Normalmente usar parénteses para estar seguro de que sabe o que está facendo. Algúns atallos útiles, por suposto, é un i + + ou i + = 1 ou usando + =. Isto é o mesmo que facer i = i + 1. Tamén pode facer I - ou I - = 1, que é a mesma cousa que i = i -1, algo que vostedes usan unha morea de loops, polo menos. Ademais, para *, se usa * = e se, por exemplo, i * = 2 é o mesmo que dicir i = i * 2, ea mesma cousa para a división. Se fai i / = 2 é a mesma cousa que i = i / 2. Agora sobre funcións. Vostedes aprenderon que funcións son unha estratexia moi boa para salvar código mentres está programando, entón se quere realizar a mesma tarefa no código de novo e de novo, probablemente quere usar unha función só así non tes que copiar e pegar o código unha e outra vez. En realidade, a principal é unha función, e cando amosar-lle o formato dunha función vai ver que é moi evidente. Tamén usamos funcións dalgunhas bibliotecas, por exemplo, printf, Getin, que é a partir da biblioteca de CS50, e outras funcións como toupper. Todas estas funcións son realmente aplicadas noutras bibliotecas, e cando poñer estes arquivos tether no inicio do seu programa está dicindo que pode por favor me dar o código para estas funcións entón eu non teño que aplica-las por min mesmo? E tamén pode escribir as súas propias funcións, entón cando comezar a programar entender que as bibliotecas non teñen todas as funcións que precisa. Para o pset pasado, por exemplo, escribir deseñar, scramble, e de investigación, e é moi, moi importante para ser capaz de escribir funcións porque son útiles, e usalos todo o tempo na programación, e el salva unha morea de código. O formato dunha función é esta. Temos tipo de retorno no inicio. Cal é o tipo de retorno? É só cando a función devolverá. Se vostede ten unha función, por exemplo, factorial, que se vai calcular unha factorial dun número enteiro, probablemente vai voltar un enteiro tamén. A continuación, o tipo de retorno vai ser int. Printf realmente ten un tipo de retorno void porque non está retornando nada. Vostede está só imprimir cousas na pantalla e saír da función despois. Entón tes o nome da función que pode escoller. Debe ser un pouco razoable, como non escoller un nome como xyz ou como X2F. Probe facer-se un nome que ten sentido. Por exemplo, se é factorial, din factorial. Se é unha función que vai deseñar algo, chame-o deseñar. E despois temos os parámetros, que son tamén chamados de argumentos, que son como os recursos que a súa función debe desde o seu código para realizar a súa tarefa. Se queres calcular o factorial dun número probablemente precisa ter un número para calcular un factorial. Un dos argumentos que vai ter é o propio número. E entón el vai facer algo e voltar o valor ao final a menos que sexa unha función void. Imos ver un exemplo. Se eu queira escribir unha función que suma todos os números en un array de enteiros, en primeiro lugar, o tipo de retorno vai ser int porque eu teño un array de enteiros. E entón eu vou ter o nome da función como sumArray, e entón el vai levar o propio array para nums int e entón a lonxitude da matriz, entón eu sei cantos números eu teño que sumar. Entón eu teño que arrincar unha contía variable chamada, por exemplo, para 0, e cada vez que vexo un elemento na matriz Debo engadir que a suma, entón eu fixen un loop. Así como dixo Lexi, vostede int i = 0, i lonxitude 0, entón é positivo. Se é = 0, é 0, e se é <0, entón é negativo. E o outro está facendo if, else if, else. A diferenza entre os dous é que este está indo realmente para comprobar se> 0, <0 = 0 ou tres veces, por iso, se ten o número 2, por exemplo, que vai vir aquí e dicir if (x> 0), e só pode dicir que si, entón eu imprimir positivo. Pero aínda que sei que é> 0 e non vai ser 0 ou <0 Eu aínda vou facer é 0, é <0, entón eu estou indo realmente dentro IFS que eu non tiña que porque eu xa sei que non vai satisfacer calquera destas condicións. Podo utilizar o if, else if, else comunicado. El basicamente di que se x = 0 eu imprimir o positivo. Se non é, eu vou tamén probar isto. Se é 2, non vou facer iso. Basicamente, se eu x = 2, diría if (x> 0), si, para imprimir esta. Agora que sei que é> 0, e que satisfeito o primeiro Eu non estou indo a executar este código. O código é executado máis rápido, en realidade, tres veces máis rápido se usa isto. Tamén soubemos e e ou. Eu non vou pasar por iso porque Lexi xa falamos sobre eles. É só o && e operador | |. O único que eu vou dicir é ter coidado cando ten tres condicións. Use parénteses porque é moi confuso cando ten unha condición e outro, ou outro. Use parénteses só para estar seguro de que as súas condicións de ter sentido porque, nese caso, por exemplo, pode imaxinar que que podería ser a primeira condición e un ou o outro ou as dúas condicións combinadas nunha e ou o terceiro, entón teña coidado. E, finalmente, falamos de opcións. Un switch é moi útil cando ten unha variable. Imos dicir que ten unha variable como n que poden ser 0, 1 ou 2, e para cada un destes casos está indo a executar unha tarefa. Pode dicir cambiar a variable, e indica que o valor é, entón, como valor1 eu vou facer iso, e entón eu romper, o que significa que eu non vou mirar para calquera dos outros casos porque xa convencido de que no caso de e, a continuación, valor2 e así por diante, e tamén pode ter un interruptor estándar. Isto significa que se non satisfai calquera dos casos que eu tiven que eu vou facer outra cousa, pero iso é opcional. Isto é todo para min. Agora imos ter Tommy. Todo ben, isto vai ser Semana 3-ISH. Estes son algúns dos temas que imos cubrindo, cripto, alcance, matrices, etcétera. Só unha palabra rápida sobre criptografía. Nós non estamos indo a martelar esta casa. Fixemos iso en pset 2, pero para o quiz seguro que vostede sabe a diferencia entre a cifra de César ea cifra de Vigenère, como dous traballos cifras e como é para cifrar e descifrar o texto usando estes dous códigos. Lembre, a cifra de César simplemente xira cada personaxe co mesmo valor, asegurarse de mod polo número de letras no alfabeto. E a cifra de Vigenère, por outra banda, cada roda de caracteres por un importe distinto, entón en vez de dicir cada rolda caracteres por 3 Vigenère ha xirar cada personaxe por unha cantidade diferente dependendo de algunha contrasinal onde cada letra da palabra clave representa unha cantidade diferente para xirar o texto claro por. Imos primeiro falar sobre alcance de variables. Existen dous tipos de variables. Temos variables locais, e estes van ser definidos fóra do principal ou fóra de calquera función ou bloque, e estas estarán accesibles en calquera lugar no seu programa. Se vostede ten unha función e que función é un loop while a gran variable global é accesible en calquera lugar. Unha variable local, por outro lado, é delimitado ao lugar onde está definido. Se vostede ten unha función aquí, por exemplo, temos esta función g, e dentro g existe unha variable aquí chamada y, e iso significa que esta é unha variable local. Aínda que esta variable é chamada y e esta variable é chamado Y estas dúas funcións non teño idea do que cada un dos outros locais son variables. Por outra banda, aquí, dicimos int x = 5, e iso está fóra do alcance de calquera función. É fóra do alcance do principal, polo que esta é unha variable global. Isto significa que dentro destas dúas funcións, cando digo - x ou x + + Eu estou accedendo o mesmo x y en que este e este y son variables diferentes. Esa é a diferenza entre unha variable global e unha variable local. Tanto como deseño está en causa, ás veces, pode ser unha idea mellor para manter variables locais sempre que poida xa que ter un monte de variables globais pode ser moi confuso. Se tes unha morea de funcións modificando todo a mesma cousa pode esquecer que esta función accidentalmente modifica este global, e esta outra función non sabe sobre iso, e que o fai ser moi confuso como obtén máis de código. Mantendo variables locais sempre que poida é proxecto só bo. Matrices, lembre, son simplemente as listas de elementos do mesmo tipo. Dentro IC non pode ter unha lista como 1, 2,0, Olá Nós simplemente non pode facelo. Cando declarar unha matriz en C de todos os elementos teñen que ser do mesmo tipo. Aquí eu teño un conxunto de 3 números enteiros. Aquí eu teño a lonxitude da matriz, pero eu estou declarando o nesta sintaxe onde especifica que todos os elementos están tecnicamente eu non teño deste 3. O compilador é intelixente o suficiente para descubrir o quão grande a matriz debe ser. Agora cando desexa ou establecer o valor dunha matriz Esta é a sintaxe para facelo. Isto efectivamente modificar o segundo elemento da matriz porque lembrar, numeración comeza en 0, non en 1. Se quero ler ese valor podo dicir algo así como int x = array [1]. Ou se eu queira definir ese valor, como eu estou facendo aquí, Podo dicir array [1] = 4. Ese tempo acceder elementos polo seu índice ou a súa posición, ou cando eles están na matriz, e que a lista comeza en 0. Tamén podemos ter matrices de matrices, e iso é chamado de matriz multi-dimensional. Cando temos un array multi-dimensional Isto significa que podemos ter algo así como liñas e columnas, e esta é só unha forma de ver iso ou pensar sobre iso. Cando eu teño un array multi-dimensional que significa que eu vou comezar a ter máis que un índice, porque se eu tivera unha reixa só dicindo o que liña está en non nos dá un número. Isto é realmente só vai dar-nos unha lista de números. Imos dicir que eu teño esa matriz aquí. Eu teño unha matriz chamada reixa, e eu estou dicindo que é dúas liñas e tres columnas, e por iso esta é unha forma de ver isto. Cando digo que quero comezar o elemento en [1] [2] Isto significa que, porque estes son liñas e despois columnas Vou saltar para a liña 1 desde que eu dixen un. Entón eu vou vir aquí para a columna 2, e eu estou indo a obter o valor 6. Ten sentido? Arrays multi-dimensional, lembre, son tecnicamente só unha matriz de matrices. Podemos ter matrices de matrices de matrices. Podemos seguir, pero realmente unha forma de pensar como iso está colocado para fóra eo que está a suceder é velo nunha reixa coma este. Cando pasar matrices para funcións, eles van comportarse un pouco diferente do que cando pasar variables para funcións regulares como pasar un int ou float. Cando pasamos nun tipo int ou char ou calquera destes outros datos Nós só deu un ollo a función modifica o valor da variable que o cambio non vai propagar-se para a función de chamada. Cunha matriz, por outra banda, que se celebrará. Se eu pasar un array para algunha función e que función modifica algúns dos elementos, cando volverse para a función que a chamou miña matriz é agora vai ser diferente, e vocabulario para é arrays son pasados ​​por referencia, como veremos máis adiante. Isto está relacionado á forma como o traballo punteiros, onde estes tipos de datos básicos, por outro lado, son pasados ​​por valor. Podemos pensar que, como facer unha copia de algunha variable e despois pasar na copia. Non importa o que facemos con esa variable. A función de chamada non vai ser consciente de que el cambiou. Matrices son só un pouco diferente a este respecto. Por exemplo, como acabamos de ver, a principal é simplemente unha función que pode tomar dous argumentos. O primeiro argumento para a función principal é argc, ou o número de argumentos, eo segundo argumento é chamado argv, e eses son os valores reais tales argumentos. Imos dicir que eu teño un programa chamado this.c, e eu digo iso, e eu estou indo a executar isto na liña de comandos. Agora, para pasar uns argumentos para o meu programa chamado iso, Eu podería dicir algo así como. / Este é cs 50. Isto é o que nós imaxinamos David a facer todos os días no terminal. Pero agora, a función principal no interior do referido programa ten estes valores, así argc e 4. Pode ser un pouco confuso, porque realmente estamos só pasando é cs 50. Isto é só 3. Pero lembre que o primeiro elemento de argv ou o primeiro argumento é o nome da propia función. Entón iso significa que temos catro cousas aquí, eo primeiro elemento é o que vai ser. / iso. E iso vai ser representado como unha cadea. A continuación, o resto dos elementos son o que ingresaran despois do nome do programa. Así como un aparte, coma nós, probablemente, viu en pset 2, Lembre que a secuencia de 50 a 50 ≠ enteiro. Polo tanto, non podemos dicir algo así como, "int x = argv 3. ' Isto só non vai ter sentido, porque esta é unha cadea, e este é un número enteiro. Entón, se quere converter entre o 2, lembre, nós imos teñen esa función máxica chamada atoi. Que recibe unha cadea e retorna o enteiro representado dentro desa secuencia. Entón, iso é un erro fácil de facer no quiz, só de pensar que este será automaticamente o tipo correcto. Pero só sei que estes serán sempre cordas mesmo se a cadea contén só un número enteiro ou un personaxe ou unha boia. Entón, agora imos falar sobre o tempo de execución. Cando temos todos estes algoritmos que facer todas estas cousas tolas, torna-se moi útil para a pregunta: "Canto tempo eles levaron?" Nós representamos que con algo chamado de notación asintótica. Entón iso significa que - ben, imos dicir que dar o noso algoritmo algunha entrada moi, moi, moi grande. Queremos facer a pregunta: "Canto tempo vai levar? Cantas medidas ha tomar o noso algoritmo para realizar como unha función do tamaño da entrada? " Así, a primeira forma que podemos describir o tempo de execución é con gran O. E este é o noso tempo de execución de peor caso. Polo tanto, se queremos clasificar un array, e nós damos o noso algoritmo dunha matriz que está en orde decrescente, cando debería estar en orde ascendente, que vai ser o peor caso. Este é o noso límite superior o tempo máximo de noso algoritmo pode tomar. Por outra banda, este Ω vai describir mellor caso tempo de execución. Entón, se nós damos unha matriz xa clasificados para un algoritmo de clasificación, canto tempo vai levar para solucionar isto? E este, a continuación, describe un límite inferior no tempo de execución. Entón, aquí son só algunhas palabras que describen algunhas veces comúns en execución. Estes son, en orde crecente. O tempo máis rápido en execución que temos é chamado constante. Isto significa que non importa cantos elementos damos o noso algoritmo, non importa quão grande é a nosa matriz, a selección ou facendo o que estamos facendo para a matriz sempre terá a mesma cantidade de tempo. Así, podemos representar que só un 1, o cal é unha constante. Tamén mirou en tempo de execución logarítmica. Polo tanto, algo así como procura binaria é logarítmica, onde imos cortar o problema á metade o tempo e despois as cousas só quedan máis de alí. E se está sempre escribindo un o de calquera algoritmo de factorial, probablemente non debe considerarse este como o seu traballo do día. Ao comparar tempos de execución é importante manter presente esas cousas. Entón, se eu teño un algoritmo que é O (n), e alguén ten un algoritmo de O (2n) estes son realmente assintoticamente equivalente. Entón, se nós imaxinarmos n para ser un número grande como Eleventy millóns: Entón, cando estamos comparando Eleventy millóns para algo así como Eleventy millóns + 3, de súpeto que tres realmente non fai unha gran diferenza máis. É por iso que nós imos comezar a considerar estas cousas equivalentes. Entón, cousas como esas constantes aquí, hai 2 x este, ou a adición de 3, Estes son só constantes, e estes van caer cara arriba. É por iso que todos os 3 destes tempos de execución son o mesmo que dicir que son O (n). Do mesmo xeito, se temos dous tempos de execución doutros, digamos O (n ³ + 2n ²), podemos engadir + N, + 7, e despois temos outro tempo de execución que é só o (n ³). De novo, estes son a mesma cousa, porque estes - estes non son os mesmos. Estas son as mesmas cousas, me desculpe. Entón, eses son os mesmos, porque este ³ n vai dominar este ² 2n. O que non é o mesmo é ter executado tempos como O (n ³) e O (n ²) porque este ³ n é moito maior do que isto n ². Entón, se temos expoñentes, de súpeto, iso comeza coa materia, pero cando estamos lidando só con factores como estamos aquí, entón non vai importar, porque eles están indo só para caer fóra. Imos dar un ollo a algúns dos algoritmos que vimos ata agora e falar sobre o seu tempo de execución. A primeira forma de ollar para un número nunha lista, o que vimos, foi busca lineal. Ea aplicación da busca lineal é super sinxelo. Nós só temos unha lista, e imos mirar para cada elemento da lista ata atopar o número que estamos a buscar. Entón, o que significa que no peor dos casos, este (n). E o peor caso aquí podería ser o elemento o último elemento, a continuación, usando busca lineal, debemos ollar para cada elemento ata chegar ao último, a fin de saber que era realmente na lista. Non podemos simplemente desistir no medio e dicir: "É, probablemente, non existe." Coa busca lineal temos que ollar para a cousa toda. O tempo de traballo mellor caso, por outra banda, é constante porque, no mellor caso, o elemento que estamos a buscar é só o primeiro da lista. Por iso, vai levar exactamente o paso 1, non importa quão grande a lista se nós estamos mirando para o primeiro elemento de cada vez. Entón, cando busca, lembre, non esixe que a nosa lista de ser clasificado. Porque nós estamos indo simplemente para ollar sobre cada elemento, e iso realmente non importa que orde os elementos están dentro Un algoritmo de busca máis intelixente é algo así como investigación binaria. Lembre, a implementación de busca binaria é cando vai manter a ollar para o medio da lista. E porque estamos a ollar para o medio, é necesario que a lista é ordenada ou ben non sabemos onde o medio é, e temos que mirar por riba toda a lista de atopalo, e entón en que punto estamos só perdendo tempo. Entón, se temos unha lista ordenada e atopamos a medio, imos comparar a media ao elemento que estamos a buscar. Se é moi alto, entón podemos esquecer a metade dereita porque sabemos que, se o noso elemento xa é moi alta e todo a dereita deste elemento é aínda maior, entón non necesita mirar máis alá. Onde, por outra banda, o noso elemento é moi baixa, sabemos todo á esquerda do elemento que é tamén moi baixa, por iso realmente non fai sentido mirar para alí, tamén. Desta forma, a cada paso e cada vez que ollar para o punto medio da lista, imos cortar pola metade o noso problema, porque de súpeto sabemos unha morea de números que non poden ser o que estamos a buscar. En pseudocódigo este sería algo coma isto, e porque estamos cortando a lista á metade a cada momento, nosas peor caso de execución de saltos no tempo lineal para logarítmica. Entón, de súpeto, temos log-in pasos para atopar un elemento nunha lista. O tempo de execución de mellor caso, no entanto, aínda é constante porque agora imos só dicir que o elemento que estamos a buscar é sempre medio exacto da lista orixinal. Así, podemos aumentar a nosa lista tan grande como queremos, pero se o elemento que estamos a buscar é no medio, el só vai levar un paso. Entón é por iso que estamos O (log n) e Ω (1) ou constante. Imos executar busca binaria nesta lista. Entón, imos dicir que nós estamos mirando para o elemento 164. O primeiro que imos facer é atopar o punto medio desta lista. O que pasa é que o punto medio vai caer entre estes dous números, entón imos arbitrariamente dicir, toda vez que o punto medio cae entre dous números, imos redondear para arriba. Nós só necesitamos ter seguro de que facemos isto a cada paso do camiño. Entón, imos redondear para arriba, e nós imos dicir que 161 é o medio de lista. Entón, 161 <164, e todos os elementos para a esquerda de 161 tamén é <164, entón sabemos que iso non vai axudar en todo para comezar a ollar para aquí porque o elemento que estamos a buscar non pode estar alí. Entón o que podemos facer é que podemos esquecer que a metade toda esquerda da lista, e agora considerar só a partir da dereita da fronte 161. Entón, de novo, este é o punto medio; imos redondear para arriba. Agora 175 é moi grande. Entón, nós sabemos que non vai axudar-nos a ollar aquí ou aquí, así que podemos só xogar iso fóra, e, finalmente, imos acertar o 164. Calquera dúbida en busca binaria? Imos pasar de busca mediante unha lista xa clasificada para realmente tomar unha lista de números en calquera orde e facer esa lista en orde crecente. O primeiro algoritmo vimos foi chamado Bubble sort. E esta sería máis sinxelo dos algoritmos que vimos. Especie de burbulla, di que cando os dous elementos dentro da lista están fóra do lugar, ou sexa, hai un maior número á esquerda dun número máis baixo, entón nós estamos indo a troca-los, porque iso significa que a lista será "Máis ordenada" do que era antes. E nós só estamos indo para continuar este proceso de novo e de novo e de novo ata que finalmente o tipo elementos de burbulla para o seu ubicación correcta e temos unha lista clasificada. O tempo de execución deste será o (n ²). Por que? Ben, porque no peor dos casos, imos tomar todos os elementos, e imos acabar comparando-a con todos os outros elementos da lista. Pero, no mellor dos casos, temos unha lista xa clasificados, tipo de burbulla só vai pasar por unha vez, dicir "Nope. non facer calquera cambio, así que eu son feito." Entón, nós temos un tempo mellor caso de execución de Ω (n). Imos correr especie de burbulla nunha lista. Ou primeiro, imos ollar para algúns pseudocódigo moi rapidamente. Queremos dicir que queremos seguir, en cada iteração do loop, manter o control da existencia ou non cambiamos todos os elementos. Así, a razón para iso é que nós imos parar cando non trocaron todos os elementos. Entón, a comezos do noso lazo non trocar nada, entón imos dicir que é falso. Agora, imos percorrer a lista e comparar elemento i ó elemento i + 1 e se é o caso en que existe un maior número á esquerda dun número menor, entón nós estamos indo só para trocalos. E entón, imos lembrar que trocamos un elemento. Isto significa que temos que percorrer a lista polo menos unha vez máis porque a condición en que se detivo é cando toda a lista é xa clasificados, o que significa que non teña feito calquera cambio. É por iso que a nosa condición aquí é "mentres algúns elementos foron trocados." Entón, agora imos ollar para esta rodando nunha lista. Eu teño unha lista 5,0,1,6,4. Especie de burbulla vai comezar todo o camiño á esquerda, e vai para comparar os elementos i, de xeito 0 a i + 1, que é o elemento 1. Vai dicir, ben 5> 0, pero agora 5 é a esquerda, entón eu teño cambiar o 5 eo 0. Cando troca-los, de súpeto, eu recibín esta lista diferente. Agora 5> 1, entón nós estamos indo a trocalos. 5 non é> 6, polo tanto, non precisa facer nada aquí. Pero 6> 4, polo que necesitamos cambiar. Unha vez máis, temos que percorrer toda a lista para, finalmente, descubrir que estes están fóra de orde, nós troca-los, e neste momento temos que percorrer a lista unha vez máis para asegurarse de que todo está no seu fin, e neste tipo de burbulla punto de rematar. Un algoritmo diferente para a toma de algúns elementos e clasificalos los é unha especie de selección. A idea detrás tipo de selección é que nós imos construír unha parte clasificada na lista Un elemento de cada vez. E a forma como imos facelo é a través da construción de segmento esquerdo da lista. E, basicamente, cada - en cada etapa, imos levar o menor elemento que nos queda que non sexa resolto aínda, e nós estamos indo a mover para o segmento clasificado. Isto significa que necesitamos continuamente atopar o elemento mínimo indiferenciados e levar ese elemento mínimo e troca-lo co que máis á esquerda elemento que non está clasificada. O tempo de execución deste será o (n ²), porque no peor caso necesitamos comparar cada elemento de calquera outro elemento. Porque nós estamos dicindo que, se comezar na metade esquerda da lista, cómpre que pasar por todo o segmento da dereita para atopar o menor elemento. E entón, unha vez máis, temos que pasar por riba de todo o segmento dereito e continuar máis que unha e outra e outra vez. Isto vai ser ² n. Nós imos ter que un circuíto para dentro doutro loop o que suxire ² n. No pensamento mellor caso, imos dicir que darlle unha lista xa clasificados; Nós realmente non facer mellor que ² n. Porque tipo de selección non ten forma de saber que o elemento mínimo é só a ocorrer de eu estar mirando. El aínda precisa estar seguro de que este é realmente o mínimo. E a única forma de ter seguro de que é o mínimo, usando ese algoritmo, é mirar para cada elemento novo. Entón, realmente, se der a el - se der tipo de selección dunha lista xa clasificados, el non vai facer nada mellor que darlle unha lista que non é clasificado aínda. By the way, se ocorrer de ser o caso de que algo é O (algo) eo omega de algo, podemos dicir de forma máis sucinta que é θ de algo. Entón, se ves que chegar en calquera lugar, iso é o que significa só. Se algo é theta de n ², é tanto grande (n ²) e Ω (n ²). Entón, o mellor caso e peor caso, non fai diferenzas, o algoritmo vai facer a mesma cousa todo o tempo. Entón é iso que pseudocódigo para tipo de selección pode parecer. Estamos basicamente vai dicir que quero iterar sobre a lista de esquerda a dereita, e en cada iteração do loop, eu estou indo a mover o elemento mínimo para esta porción da lista ordenada. E unha vez que eu paso algo alí, eu nunca precisa ollar para este elemento novo. Porque así que eu cambiar un elemento para o segmento esquerdo da lista, está clasificada porque estamos facendo todo en orde crecente, usando mínimos. Entón nós dixemos, todo ben, estamos en posición i, e necesitamos de ollar para todos os elementos á dereita de i, a fin de atopar o mínimo. Así, isto significa que quere ollar de i + 1 para o fin da lista. E agora, o elemento que nós estamos a buscar é a menos que o noso mínimo ata agora, que, lembre, estamos empezando a fóra mínimo a ser só calquera elemento que estamos actualmente, eu vou asumir que é o mínimo. Se eu atopar un elemento que é menor do que iso, entón eu vou dicir, ok, ben, eu atope un novo mínimo. Vou lembrar de onde ese mínimo era. Entón, agora, despois de xa ter pasado por ese segmento dereito indiferenciados, Eu podo dicir que eu vou cambiar o elemento mínimo co elemento que está na posición i. Que vai construír a miña lista, miña porción clasificada na lista da esquerda para a dereita, e non precisa ollar para un elemento novo, xa que é nesa porción. Unha vez que teñamos trocado el. Entón, imos realizar tipo de selección na lista. O elemento de azul aquí vai ser a i, é o elemento vermello vai ser o elemento mínimo. Entón eu comeza todo o camiño á esquerda da lista, para 5. Agora necesitamos atopar o elemento mínimo indiferenciados. Así, dicimos 0 <5, entón 0 é o meu novo mínimo. Pero eu non podo deixar por aí, porque, aínda que poidamos recoñecer que 0 é menor, que necesitamos para realizar a través de todos os outros elementos da lista para estar seguro. Entón, un é grande, 6 é maior, 4 é maior. Isto significa que, despois de ollar para todos estes elementos, xa determinou 0 é o menor. Entón, eu vou cambiar o 5 eo 0. Unha vez eu cambiar iso, eu estou indo a obter unha nova lista, e eu sei que eu nunca precisa ollar para iso 0 novo porque unha vez eu cambie, eu clasificados por el e estamos a facer. Agora resulta que o elemento azul é novo 5, e que ten que ollar para o 1, a 6 e 4 para determinar que un é o menor elemento mínimo, entón imos cambiar o 1 eo 5. Unha vez máis, temos que mirar - comparar a 5 a 6 e 4, e imos cambiar o 4 eo 5, e, finalmente, comparar os números 2 e trocalos ata chegar a nosa lista de clasificados. Calquera dúbida sobre tipo de selección? Okay. Imos pasar ao último tema aquí, e que é a recursividade. Recursão, lembre, é esa cousa meta realmente onde unha función repetidamente chama a si mesmo. Entón, en algún punto, mentres que a nosa fuction é repetidamente chamado-se, é preciso haber algún punto no que paramos de chamar. Porque se nós non facemos iso, entón imos só continuar a facelo para sempre eo noso programa é só non vai rematar. Chamamos esta condición no caso base. É o caso base di, en vez de chamar a unha función de novo, Eu só vou volver algún valor. Polo tanto, unha vez que xa retornou un valor, nós paramos de chamar, eo resto das invitacións que fixemos ata agora tamén pode retornar. O oposto do caso base é o caso recursivo. E isto é cando queremos facer unha outra chamada para a función que estamos actualmente dentro E probablemente, aínda que non sempre, quere usar argumentos diferentes. Entón, se temos unha función chamada f, ef chamado só de tomar un argumento, e nós seguimos chamando f (1), f (1), f (1), e iso só acontece que o argumento cae nun caso recursivo, estamos aínda non vai parar. Mesmo se temos un caso base, necesitamos ter seguro de que, finalmente, imos bater ese caso base. Non só manter permanecer neste caso recursivo. Xeralmente, cando chamamos a nós mesmos, probablemente imos ter un argumento diferente cada vez. Aquí é unha función moi simple recursiva. Entón, iso vai calcular o factorial dun número. Alí enriba, aquí temos o noso caso base. No caso de que n ≤ 1, nós non imos chamar factorial de novo. Nós imos parar, estamos só indo para voltar un valor. Se iso non é verdade, entón nós estamos indo para acertar noso caso recursivo. Nótese aquí que non estamos só chamando factorial (n), porque iso non sería moi útil. Nós imos chamar factorial de outra cousa. E así podes ver, finalmente, pasar un algo factorial (5) ou, imos chamar factorial (4) e así por diante, e, finalmente, imos bater este escenario de base. Polo tanto, este parece ser bo. Imos ver o que acontece cando nós realmente executar este. Esta é a pila, e imos dicir que principal vai chamar esta función cun argumento (4). Polo tanto, unha vez factorial ve e = 4, factorial irá identificar. Agora, de súpeto, temos factorial (3). Entón, estas funcións van continuar crecendo ata finalmente chegar noso caso base. Neste punto, o valor de retorno é o retorno (NX o valor de retorno deste), o valor de retorno é NX valor o retorno deste. Finalmente cómpre acertar algún número. Arriba aquí, dicimos retorno 1. Isto significa que unha vez que volver ese número, podemos pop esta na pila. Polo tanto, este factorial (1) está feito. Cando un regresa, ese factoriais (1) retorna, ese retorno a 1. O valor de retorno a iso, lembre, foi NX o valor de retorno deste. Entón, de súpeto, esa cara sabe que eu quero volver 2. Entón lembre, voltar o valor desta é só NX o valor de retorno aquí. Entón agora podemos dicir 3 x 2, e, finalmente, aquí podemos dicir iso é só vai ser 4 x 3 x 2. E unha vez que retorna, nós descender a un único enteiro dentro da principal. Calquera dúbida sobre recursão? Todo ben. Polo tanto, non hai máis tempo para preguntas, ao final, pero agora Joseph cubrirá os temas restantes. [Joseph Ong] Todo ben. Polo tanto, agora que xa falamos sobre recursões, imos falar un pouco sobre o que é merge sort. Merge sort é basicamente unha outra forma de ordenar unha lista de números. E como funciona é, con merge sort tes unha lista, eo que facemos é dicimos, imos dividir iso en dúas metades. Imos primeiro executar merge sort novo na metade esquerda, Entón imos correr merge sort na metade dereita, e que nos dá agora dúas metades que son clasificados, e agora imos combinar esas metades xuntas. É un pouco difícil de ver sen un exemplo, así que imos percorrer as propostas e ver o que acontece. Entón comeza con esta lista, que dividídelo en dúas metades. Corremos merge sort na metade esquerda primeiro. Entón esta é a metade esquerda, e agora executa-los a través desta lista de novo que é pasado para merge sort, e entón miramos, máis unha vez, na parte esquerda da lista e corremos merge sort sobre el. Agora, temos unha lista de números 2, e agora a metade esquerda é só un elemento de lonxitude, e non podemos dividir unha lista que non é máis que un elemento no medio, de xeito que acabamos de dicir, unha vez que temos 50, que é só un elemento, xa está clasificado. Unha vez que estamos a facer que, podemos ver que podemos pasar a metade dereita da lista, e 3 tamén é clasificado, e agora que as dúas metades desta lista son clasificados podemos xuntar eses números xuntos de novo. Así, analizamos 50 e 3, 3 e menor que 50, de xeito que vai en primeiro lugar e, a continuación, 50 vén dentro Agora, iso está feito, nós volver a esa lista e tipo é media dereita. 42 é o número propio, polo que xa está clasificada. Entón agora nós comparar estes 2 e 3 é menor que 42, de xeito que é posto en primeiro lugar, agora con 42 anos e colocar, e 50 e colocar dentro Agora, que está clasificado, que percorrer todo o camiño de volta ao principio, 1337 e 15. Ben, nós agora ollar para a metade esquerda da lista; 1337 é, por si só por iso é clasificado e mesmo con 15. Entón agora nós combinar eses dous números para ordenar que a lista orixinal, 15 <1,337, así vai en primeiro lugar, entón 1337 vai dentro E agora nós clasificamos as dúas metades da lista orixinal encima. E todo o que temos que facer é combinar estes. Nós miramos para os 2 primeiros números desta lista, 3 <15, entón vai para a matriz de clasificación en primeiro lugar. 15 <42, así que vai dentro Agora, 42 <1337, que vai dentro 50 <1,337, de xeito que vai dentro e entender que só tivo dous números fóra desta lista. Polo tanto, non estamos só alternando entre as dúas listas. Estamos só mirando para o inicio, e nós estamos levando o elemento que é menor e, a continuación, colocar-lo na nosa matriz. Agora mesclou todas as metades e estamos a facer. Calquera dúbida sobre merge sort? Si? [Estudante] Se dividir en grupos distintos, por que non só división lo unha vez e ten 3 e 2 en un grupo? [Resto do inintelixíbel cuestión] A razón - entón a pregunta é, por que non podemos simplemente xuntalas en que o primeiro paso despois de telos? A razón que podemos facelo, inicie os elementos máis á esquerda de ambos os dous lados, e despois tome a menor e poñelas, é que sabemos que eses listas individuais están en ordes clasificados. Entón, se eu estou ollando para os elementos máis á esquerda de ambas as metades, Sei que eles van ser os pequenos elementos desas listas. Para que eu poida poñer-los en puntos menor elemento desta lista grande. Por outra banda, se eu ollar para as dúas listas no segundo nivel por alí, 50, 3, 42, 1337 e 15, os que non están clasificados. Entón, se eu ollar para 50 e 1337, eu vou poñer 50 na miña primeira lista. Pero iso non fai moito sentido, porque 3 é o menor elemento de todos aqueles. Entón, a única razón que podemos facer este paso combinando é porque nosas listas xa están clasificados. É por iso que temos que comezar todo o camiño ata o fondo porque cando temos só un único número, vostede sabe que un único número en si xa é unha lista ordenada. Algunha pregunta? Non? Complexidade? Ben, pode ver que en cada etapa hai números finais, e podemos dividir unha lista en media log n veces, que é onde nós comezamos este rexistro n x n complexidade. E vai ver o mellor caso para merge sort é n log n, e iso só acontece que o peor caso, ou o Ω alí, tamén é n log n. Algo para manter presente. Seguindo adiante, imos ir a algún arquivo de super básica I / O. Se mirou para Scramble, vai notar que tivemos algún tipo de sistema onde podes gravar nun ficheiro de rexistro, se ler o código. Imos ver como pode facelo. Ben, temos fprintf, que pode pensar en como só printf, pero só a impresión a un ficheiro en vez diso, e, polo tanto, o F no inicio. Este tipo de código ata aquí, o que fai é, como ten que ter visto en Scramble, pasa pola súa impresión matriz de 2 dimensións fóra de liña en liña cales son os números. Neste caso, printf imprime ao seu terminal ou o que chamamos a saída estándar de sección. E agora, neste caso, todo o que temos que facer é substituír printf con fprintf, dicir o que arquivo que quere imprimir, e, neste caso, só imprime-lo para o arquivo en vez de mostrala ao seu terminal. Ben, entón, que levanta a cuestión: Onde é que imos conseguir este tipo de ficheiro, non? Pasamos sesión nese fuction fprintf pero non tiñamos idea de onde veu. Ben, ao principio do código, o que houbo foi este anaco de código aquí, que basicamente di que o ficheiro aberto chama log.txt. ¿Que facer despois diso é que temos que estar seguro de que o arquivo está realmente aberto con éxito. Por iso, pode fallar por varias razóns, non ten espazo suficiente no seu ordenador, por exemplo. Por iso é sempre importante antes de facer calquera operación co ficheiro que comprobar que o arquivo foi aberto con éxito. Entón, o que que un, iso é un argumento para fopen, así, podemos abrir un arquivo de moitas maneiras. O que podemos facer é, podemos pasalo w, o que significa substituír o ficheiro, se saír xa, Podemos pasar dun a que engada ao final do ficheiro, no canto de ignore-los, ou podemos especificar r, o que significa, imos abrir o ficheiro como só lectura. Entón, se o programa tenta facer os cambios para o arquivo, berrar con eles e non deixalos facer. Finalmente, unha vez que está feito co arquivo, fixeron que fai operacións sobre ela, necesitamos ter seguro de que peche o ficheiro. E así, ao final do seu programa, que vai paso-los de novo este ficheiro que abriu, e só o peche. Entón iso é algo importante que ten que estar seguro que fai. Entón lembre que pode abrir un arquivo, entón podes escribir o ficheiro, facer operacións no arquivo, pero entón tes que pechar o ficheiro no final. Calquera dúbida sobre arquivo básico I / O? Si? [Pregunta do estudante, inintelixible] Aquí. A cuestión é: onde é que este arquivo log.txt aparecer? Ben, se só darlle log.txt, crea-lo no mesmo directorio que o executábel. Entón, se está - >> [pregunta Estudante, inintelixible] Si Na mesma carpeta, ou no mesmo directorio, como lle chaman. Agora memoria, pila, pila e. Entón, como é a memoria definidos no ordenador? Ben, pode imaxinar a memoria como unha especie de este bloque aquí. E na memoria, temos o que se chama de pila preso alí, ea pila que está alí embaixo. E a pila crece cara abaixo e a pila crece cara arriba. Así como Tommy mencionado - Oh, ben, e nós temos eses outros catro segmentos que eu vou chegar a un segundo - Como Tommy dixo anteriormente, vostede sabe como se chaman as súas funcións e chamar uns ós outros? Constrúense este tipo de cadro de pila. Ben, as chamadas principais foo, foo colócase na pila. Foo chama bar, bar de conseguir poñer na pila, e que é colocado na pila despois. E como eles retornan, cada un retirado da pila. O que cada un destes lugares e memoria soster? Pois ben, a parte superior, que é o segmento de texto, contén o propio programa. Así, o código de máquina, que está aí, unha vez que compilar o seu programa. A continuación, calquera inicializar variables globais. Entón tes variables globais no seu programa, e di así, a = 5, que é colocado no segmento, e debaixo que, ten os datos non inicializados global, que é só un int, pero non dicir que é igual a nada. Entender estes son variables globais, por iso eles están fóra de inicio. Entón iso significa que todas as variables globais que son declarados, pero non son inicializados. Entón, o que está no monte? Memoria alocada usando malloc, que nós imos chegar a algo. E, finalmente, a pila que ten todas as variables locais e todas as funcións que se pode chamar de calquera dos seus parámetros. A última cousa, realmente non ten que saber que as variables de ambiente facer, pero sempre que executar o programa, non é algo asociado, como Este é o nome de usuario da persoa que executou o programa. E iso vai ser unha especie de na parte inferior. En termos de enderezos de memoria, que son valores hexadecimais, os valores no inicio arriba a 0, e van ata o fin para o fondo. Neste caso, se está no sistema de 32 bits, o enderezo na parte inferior vai ser 0x, seguido por af, porque é 32 bits, que é de 8 bytes, e neste caso corresponde a 8 bytes de 8 díxitos hexadecimais. Entón aquí vai ter, como 0xffffff, e ata alí vai ter 0. Entón, o que son punteiros? Algúns de vostedes poden non ter cuberto este na sección anterior. pero podemos pasar por iso na charla, para un punteiro é só un tipo de datos que as tendas, en vez de algún tipo de valor como 50, el almacena o enderezo de algún lugar na memoria. Como a memoria [inintelixible]. Polo tanto, neste caso, o que temos é, temos un punteiro para un enteiro ou un int *, e que contén este enderezo hexadecimal de 0xDEADBEEF. Entón o que temos é, agora, este punteiro apunta nalgún lugar na memoria, e iso é só un, o valor de 50 é neste lugar de memoria. Nalgúns sistemas de 32 bits, en todos os sistemas de 32 bits, os punteiros levar ata 32 anacos ou 4 bytes. Pero, por exemplo, nun sistema de 64 bits, os punteiros son 64 bits. Entón, iso é algo que vai querer manter presente. Entón, en un sistema de punta-bit, un punteiro e bits a longo prazo. Os punteiros son unha cousa difícil de dixerir sen cousas extras, entón imos pasar un exemplo de asignación dinámica de memoria. O distribución dinámica de memoria fai por ti, ou o que chamamos malloc, el permite que reservar algún tipo de datos fóra do set. Polo tanto, este tipo de datos é máis permanente para a duración do programa. Porque, como vostede sabe, se declarar x dentro dunha función, e que retorna de función, xa non ten acceso ós datos que foron gardados en x. O que imos facer punteiros é que imos almacenar valores de memoria ou tenda nun segmento diferente de memoria, ou sexa, a pila. Agora, despois volvemos para fóra da función, dende que temos un punteiro para ese lugar na memoria, entón o que podemos facer é que podemos só ollar para os valores alí. Vexamos un exemplo: Este é o noso esquema de memoria de novo. E nós temos esa función, principal. O que fai é - ben, tan sinxelo, non -? Int x = 5, que é só unha variable na pila na principal. Por outra banda, agora imos declarar un punteiro que chama os giveMeThreeInts función. E agora imos para esa función e crear un novo marco de pila para el. Con todo, neste cadro de pila, nós declaramos tempo * int, que mallocs tres enteiros para nós. Así o tamaño int nos dará cantos bytes int este é, malloc e dános que moitos bytes de espazo na pila. Polo tanto, neste caso, creamos espazo suficiente para tres números enteiros, ea pila é alí enriba, que é por iso que eu tirei máis arriba. Así que está preparado, nós volvemos aquí, só precisa de 3 ints volveu, e retorna o enderezo, no caso de que máis que a memoria é. E nós definir punteiro = interruptor, e ata alí temos só un punteiro outro. Pero o que os retorno de función é empilhado aquí, e desaparece. Entón temporal desaparece, pero tamén manter o enderezo de onde estes tres enteiros están dentro da rede. Polo tanto, neste conxunto, os punteiros son alcance local para o cadro empilhados, pero a memoria a que se refiren é o heap. Isto ten sentido? [Estudante] Pode repetir? >> [Joseph] Si Entón, se eu volver un pouco, ve que temporal asignado algunha memoria na pila alí enriba. Entón, cando esa función, retorna giveMeThreeInts, esta pila aquí vai desaparecer. E con el calquera das variables, neste caso, este punteiro que foi alocado no marco empilhado. Isto vai desaparecer, pero desde que volveu de temperatura e partimos punteiro = tempo, o punteiro agora vai apuntar a mesma memoria de localización como temperatura foi. Entón, agora, a pesar de perder tempo, ese punteiro local, nós tamén manter o enderezo de memoria do que estaba apuntando cara a dentro que o punteiro variable. Preguntas? Isto pode ser unha especie de tema confuso se non ir máis en sección. Podemos, o seu TF vai certamente pasar por iso e por suposto que podemos responder a preguntas ao final da sesión de revisión para este. Pero esta é unha especie de un tema complexo, e eu teño máis exemplos que van aparecer que vai axudar a esclarecer o que realmente son os punteiros. Neste caso, os punteiros son equivalentes ás matrices, entón eu só podo usar ese punteiro como a mesma cousa que unha matriz int. Entón, eu estou indexación en 0, e cambiando o primeiro número enteiro a 1, cambiar o segundo enteiro de 2, e o número enteiro 3 a 3. Entón, máis punteiros. Ben, lembro Binky. Neste caso temos asignado un punteiro ou declaramos un punteiro, pero, inicialmente, cando acababa de declarar un punteiro, non está a apuntar para calquera lugar na memoria. É só valores de lixo no interior da mesma. Entón eu non teño idea de onde este punteiro está apuntando. El ten un enderezo que é só cuberto con 0 e 1, onde foi inicialmente declarado. Eu non podo facer nada con iso ata eu chamar malloc sobre el e entón el me dá un pouco de espazo na pila onde eu poida poñer valores dentro. Entón, de novo, eu non sei o que está dentro desa memoria. Entón o primeiro que teño que facer é comprobar que o sistema tiña suficiente memoria para me dar de volta un número enteiro en primeiro lugar, que é por iso que eu estou facendo esta comprobación. Se o punteiro é nulo, o que significa que non teñen espazo suficiente ou algún outro erro ocorreu, así que eu debería saír do meu programa.  Pero se fixo éxito, agora podo usar ese punteiro eo que fai é punteiro * séguese que o enderezo é onde este valor é, e defínese a igual a 1. Entón, aquí, estamos comprobando a memoria existía. Unha vez que vostede sabe que existe, pode pór nel que o valor que quere poñer nel, neste caso 1. Unha vez que estamos a facer con el, ten que liberar ese punteiro porque necesitamos volver ao sistema que a memoria que solicitou, en primeiro lugar. Como o ordenador non sabe cando estamos a facer con el. Neste caso, estamos explicitamente dicindo que, ben, estamos a facer que a memoria. Se algún outro proceso precisa del, algún outro programa precisa del, Sinto-se libre para ir adiante e leva-la. O que tamén pode facer é que pode obter só o enderezo de variables locais no conxunto. Entón x int e dentro do marco de empilhados principal. E cando usamos este comercial, este operador, o que fai é leva x, e X é só algúns datos da memoria, pero non ten un enderezo. Está situado en algún lugar. Entón, chamando & x, o que isto significa que nos dá o enderezo de x. Ao facelo, estamos facendo punto punteiro onde x é na memoria. Agora só facer algo como * x, imos obter 5 de volta. A estrela é chamada dereferencing-lo. Vostede segue a dirección e terá o valor del alí almacenados. Algunha pregunta? Si? [Estudante] Se non fai a cousa tres puntas, ela aínda compilar? Si Se non fai a cousa de 3 puntos, aínda vai compilar, pero eu vou amosar o que pasa nun segundo, e sen facelo, iso é o que chamamos baleirado de memoria. Non está dando ao sistema apoiar a súa memoria, para despois dun tempo o programa vai acumular memoria que non está a usar, e nada máis pode usalo. Se xa viu o Firefox con 1,5 millóns de kilobytes no seu computador, no xestor de tarefas, é o que está a suceder. Tes un baleirado de memoria no programa que non está seguro. Así como o punteiro traballo aritmética? Ben, a aritmética de punteiro é unha especie de indexación como unha matriz. Neste caso, eu teño un punteiro, e que fago é facer punto punteiro para o primeiro elemento Esta serie de tres números enteiros que alocados. Entón agora o que fago, o punteiro estrela só cambia o primeiro elemento da lista. Estrela punteiro 1 puntos aquí. Entón punteiro está aquí, é un punteiro aquí, punteiro 2 é aquí. Entón, só tes que engadir 1 é a mesma cousa que se move ao longo desta matriz. O que facemos é cando facemos un punteiro de obter o enderezo aquí, e, a fin de obter o valor aquí, coloca unha estrela no de toda a expresión para cancelar a referencia dela. Así, neste caso, eu estou definindo a primeira posición nesta matriz a 1, segundo lugar a 2, e a terceira posición 3. Entón o que eu estou facendo aquí é que eu estou imprimindo noso punteiro 1, que só me dá 2. Agora estou incrementando punteiro, para que o punteiro é igual a un punteiro, que se move cara adiante. E agora, se eu imprimir un punteiro, punteiro 1 é agora 3, que neste caso é impresa 3. E a fin de algo libre, o punteiro que dou debe estar apuntando para o inicio da matriz, que eu volvín do malloc. Así, neste caso, se eu fose chamar tres aquí, iso non sería correcto, porque é no medio da matriz. Eu teño que restar para chegar ao lugar orixinal o punto de inicio antes de que eu poida libertá-lo. Entón, aquí está un exemplo máis complicado. Neste caso, estamos alocando sete caracteres nunha matriz de caracteres. E, neste caso, o que estamos facendo é que estamos looping sobre o 6 primeiro deles, e estamos poñendo a Z. Así, para i = 0, i> 6, i + +, Así, o punteiro + i vai só dar-nos, neste caso, punteiro, punteiro 1, 2 punteiro, punteiro 3, e así por diante e así por diante no circuíto. O que vai facer é que queda ese enderezo, dereferences-lo para obter o valor, e cambia o valor que para un Z. Entón, ao final lembrar que isto é unha cadea, non? Todas as cordas teñen que rematar co caracter nulo de terminación. Entón, o que fago é o punteiro 6 engada o carácter terminador nulo dentro E agora o que estou facendo aquí, basicamente, está a aplicar printf para a cadea, non? Entón, cando é que printf agora, cando atinxir o final dunha cadea? Cando chega o carácter nulo de terminación. Así, neste caso, os meus punteiro puntos orixinais para o inicio desta matriz. Eu imprimir o primeiro carácter fóra. Eu movelo sobre unha. Eu imprimir ese personaxe para fóra. Eu movelo máis. E eu sigo facendo iso ata eu chegar ao final. E agora o punteiro * final será dereference iso e obter o carácter nulo de terminación de volta. E por iso o meu loop while é executado só cando ese valor non é o carácter nulo de terminación. Entón, agora eu saír fóra deste circuíto. E así se eu restar 6 deste punteiro, Eu volver todo o camiño ata o principio. Lembre, eu estou facendo iso porque eu teño que ir ao inicio, a fin de liberalo la. Entón, sei que foi moi. Algunha pregunta? Por favor, si? [Inintelixible cuestión Estudante] Podes dicir que máis alto? Sentímolo. [Estudante] No último slide dereito antes de liberou o punteiro, onde estaba realmente cambiando o valor do punteiro? [Joseph] Entón, aquí. >> [Estudante] Ah, ok. [Joseph] Entón, eu teño un punteiro menos menos, dereito, o que move a cousa de volta un, e entón eu libertá-lo, porque este punteiro debe ser apuntado para o inicio da matriz. [Estudante] Pero iso non sería necesario se tivese parado tras esa liña. [Joseph] Entón, se eu tiña parado despois diso, iso sería considerado un baleirado de memoria, porque eu non executar libre. [Estudante] I [inintelixible] tras as tres primeiras liñas que tiña un punteiro [inintelixible]. [Joseph] Uh-Huh. Entón, cal é a pregunta alí? Sentímolo. Non, non. Vai, vai, por favor. [Estudante] Entón, non está cambiando o valor de punteiros. Non tería que facer punteiro menos de menos. [Joseph] Si, exactamente. Entón, cando fago un punteiro e punteiro 2, Eu non estou facendo un punteiro igual punteiro. Así, o punteiro só permanece apuntando para o inicio da matriz. É só cando fago máis, máis que define o valor de volta para dentro do punteiro, que realmente move este xunto. Todo ben. Máis preguntas? Unha vez máis, se este é o tipo esmagador, este será cuberto na sesión. Pregunta ó seu compañeiro de ensino sobre iso, e podemos responder a preguntas ao final. E, xeralmente, non quere facer esa cousa de menos. Isto ten que esixir-me manter a par de que eu desprazamento na matriz. Polo tanto, en xeral, este é só para explicar como funciona a aritmética de punteiro. Pero o que nós normalmente gusto de facer é que nos gusta de crear unha copia do punteiro, e despois imos utilizar esa copia, cando nos movemos en torno ao fío. Entón, nestes caso, utilizar a copia para imprimir toda a cadea, pero non hai que facer como punteiro menos 6 ou manter o control de canto nos cambiamos tanto, só porque sabemos que o noso punto orixinal aínda sinalou o inicio da lista e todo o que cambiou esta copia. Polo tanto, en xeral, cambiar copias do punteiro orixinal. Non intente a sorte de como - non cambiar copias orixinais. Tentando cambiar só copias do seu orixinal. Entón, entende cando pasamos a cadea en printf non tes que poñer unha estrela na fronte del, como fixemos con todos os dereferences outros, non? Entón, se imprimir o s% toda cadea de espera é un enderezo, e, neste caso, un punteiro ou, neste caso, como un conxunto de caracteres. Caracteres, char * s, e matrices son a mesma cousa. Punteiro é para personaxes, e matrices de carácter son a mesma cousa. E así, todo o que temos que facer é pasar punteiro. Non debemos pasar como punteiro * ou algo así. Entón, matrices e punteiros son a mesma cousa. Cando está facendo algo así como x [s] aquí por unha matriz, o que está facendo baixo o capo é que está dicindo, todo ben, é unha matriz de caracteres por iso é un punteiro. E así X son a mesma cousa, e así o que fai é engadir y para x, que é a mesma cousa que avanzar na memoria moito. E agora x + y dános algún tipo de enderezo, e cancelar o enderezo ou siga a frecha a onde que a localización na memoria é e obtemos o valor que a ubicación na memoria. Entón, así que estes dous son exactamente a mesma cousa. É só un azucre sintático. Eles fan o mesmo. Son só sintática diferentes para cada outro. Entón, o que pode dar mal con punteiros? Como, moito. Okay. Entón, as cousas malas. Algunhas cousas malas que pode facer non está comprobando a súa chamada malloc retorna nulo, non? Neste caso, eu estou pedindo o sistema para me dar - o que é ese número? Como 2 millóns de veces 4, porque o tamaño dun enteiro é 4 bytes. Estou preguntando iso para como 8 mil millóns de bytes. Está claro que o meu ordenador non vai ser capaz de dar iso de volta moita memoria. E nós non comprobar se este é nulo, por iso, cando tentamos eliminar a referencia que alí - siga a frecha cara a onde vai - non temos esa memoria. Isto é o que chamamos dereferencing un punteiro nulo. E iso esencialmente fai que segfault. Esta é unha das formas que pode segfault. Outras cousas malas que pode facer - oh ben. Que foi dereferencing un punteiro nulo. Okay. Outras cousas malas - ben, para fixar que acaba de poñer un cheque alí que comprobar se o punteiro é nulo e saír do programa, se acontece que malloc retorna un punteiro nulo. Ese é o cómico xkcd. As persoas entenden agora. Máis ou menos. Así, memoria. E eu fun por iso. Estamos chamando malloc en un loop, pero cada vez que chamar malloc estamos perdendo a noción de onde este punteiro está apuntando, porque estamos a sobrepasar-lo. Así, a chamada inicial para malloc me dá memoria aquí. Meus punteiros punteiro para este. Agora, eu non libera-lo, entón agora eu chamar malloc novo. Agora apunta aquí. Agora, a miña memoria está a apuntar aquí. Apuntando aquí. Apuntando aquí. Pero eu perdín o control dos enderezos de toda a memoria aquí que eu alocado. E agora eu non teño ningunha referencia a eles máis. Entón, eu non podo liberalo los fora deste circuíto. E así, a fin de corrixir algo como isto, Se esquecer de memoria libre e recibe ese baleirado de memoria, Ten que liberar a memoria dentro deste ciclo, unha vez que fixo con el. Ben, iso é o que pasa. Sei que moitos de vostedes odian iso. Pero agora - yay! Comeza como 44.000 kilobytes. Así, é liberar-lo ao final do ciclo, e que só liberar a memoria de cada vez. Esencialmente, o programa non ten un baleirado de memoria máis. E agora outra cousa que podes facer é liberar memoria que pediu dúas veces. Neste caso, algo malloc, cambia o seu valor. Vostede libertá-lo de novo, porque dixo que estaba feito con el. Pero, entón, liberou-lo de novo. Iso é algo que é moi malo. El non vai inicialmente segfault, pero despois dun tempo o que iso fai é dobre liberación corrompe a súa estrutura de pila, e vai aprender un pouco máis sobre iso, se vostede optar por ter unha aula de como CS61. Pero, esencialmente, despois dun tempo o ordenador vai ficar confuso sobre o que posicións de memoria onde e onde é almacenado - onde os datos son almacenados na memoria. E así liberar un punteiro dúas veces é unha cousa ruín que non quere facer. Outras cousas que poden dar mal non está a usar sizeof. Entón, neste caso, malloc 8 bytes, e iso é o mesmo que dous enteiros, non? Entón, iso é perfectamente seguro, pero é el? Ben, como Lucas falou en diferentes arquitecturas, enteiros son de lonxitudes diferentes. Entón, o aparello que está a usar, enteiros son preto de 4 bytes, pero en algún outro sistema que pode ser de 8 bytes ou poden ser de 16 bytes. Entón, se eu usar este número aquí, este programa pode funcionar no dispositivo, pero non vai reservar suficiente memoria nalgún outro sistema. Neste caso, é iso que o operador sizeof é usado para. Cando chamamos sizeof (int), o que iso fai é  nos dá o tamaño dun enteiro no sistema que o programa está en execución. Así, neste caso, sizeof (int) volverá 4 sobre algo como o aparello, e agora esa vontade 4 * 2, que é de 8, que é só a cantidade de espazo necesario para dous enteiros. Nun sistema diferente, un int é como 16 bytes ou 8 bytes, el só vai voltar máis suficientes para almacenar esa cantidade. E, finalmente, estruturas. Entón, se quere gardar unha tarxeta de sudoku na memoria, como podemos facer iso? Podes pensar como unha variable para o primeiro, unha variable para a segunda cousa, unha variable para a terceira cousa, unha variable para a cuarta cousa - malo, non? Entón, unha mellora que pode facer encima deste é facer un 9 x 9 matriz. Isto é bo, pero o que si quixo asociar outras cousas coa tarxeta de sudoku gusto do que a dificultade do Consello, ou, por exemplo, o que é a súa puntuación, ou canto tempo el é levado para solucionar este foro? Ben, o que pode facer é que pode crear unha estrutura. O que eu estou dicindo basicamente é que eu estou definindo esa estrutura aquí, e estou definindo un bordo sudoku que consiste nunha placa que é de 9 x 9. E o que ten iso ten punteiros para o nome do nivel. Tamén ten X e Y, que son as coordenadas de onde estou agora. Tamén ten o tempo gastado [inintelixible], e ten o número total de xogadas que introducidos ata o momento. E por iso, neste caso, podo agrupar unha morea de datos en só unha estrutura en vez de telo como voar en torno a como as distintas variables que eu realmente non podo seguir. E isto nos permite ter só unha sintaxe agradable para tipo de referenciar cousas distintas dentro desta estrutura. Eu só podo facer board.board, e teño a tarxeta sudoku volta. Board.level, eu recibín como é duro. Board.x e board.y me dar as coordenadas de onde eu podería estar na tarxeta. E así eu estou accedendo o que chamamos campos na estrutura. Isto define sudokuBoard, que é un tipo que eu teño. E agora estamos aquí. Eu teño unha variable chamada "tarxeta" de sudokuBoard tipo. E agora podo acceder todos os campos que compoñen esta estrutura aquí. Calquera dúbida sobre estruturas? Si? [Estudante] Para int x, y, se declarou tanto nunha liña? >> [Joseph] Uh-Huh. [Estudante] Entón, vostede podería só facer iso con todos eles? Gústalle en x, y veces coma que o total? [Joseph] Si, definitivamente podería facelo, pero a razón de eu poñer x e y na mesma liña - ea cuestión é por iso que podemos simplemente facelo na mesma liña? Por que non imos só poñer todos estes na mesma liña é x e y son relacionados uns cos outros, e este é só estilisticamente máis correcto, en certo sentido, porque é a agrupación de dúas cousas na mesma liña este tipo de como se relacionan co mesmo. E eu só dividir estes separados. É só unha cousa de estilo. Funcionalmente, non fai diferenza algunha. Calquera outras preguntas sobre estruturas? Podes establecer unha Pokédex cunha estrutura. Un Pokémon ten un número e ten unha letra, un propietario, un tipo. E entón, se ten unha serie de Pokémon, pode facer unha Pokédex, non? Ok, legal. Así, cuestións sobre estruturas. Esas son relacionadas ás structs. Finalmente, GDB. O que o GDB deixar facer? El permite que depurar o programa. E se non ten usado o GDB, eu sería recomendable asistir o curta e só vai sobre o GDB é, como traballa con el, como pode usalo, e proba-lo en un programa. E así o GDB permite facer é que permite deter a [inintelixible] o seu programa e unha liña de práctica. Por exemplo, quero facer unha pausa durante a execución como a liña 3 do meu programa, E mentres eu estou na liña 3 eu poida imprimir os valores que están alí. E entón o que chamamos como Pausa nunha liña é chamamos iso de poñer un punto de interrupción na liña que e entón podemos imprimir as variables no estado do programa na época. Podemos, entón, a partir de aí percorrer o programa de liña a liña. E entón podemos ollar para o estado da pila no momento. E así, a fin de utilizar o GDB, o que nós facemos é chamar bumbum no arquivo C, pero temos que pasar a bandeira ggdb. E xa que estamos a facer que só executar o gdb no ficheiro de saída resultante. E para que obteña unha masa como texto coma este, pero realmente todo o que precisa facer é escribir ordes no inicio. Romper principal coloca un punto de interrupción na principal. Lista de 400 lista as liñas de código en torno á liña 400. E así, neste caso, pode só ollar ao redor e dicir, oh, Quero establecer un punto de interrupción na liña 397, que é esta liña, e, a continuación, o programa é executado en que paso e que vai romper. Vai parar alí, e pode imprimir, por exemplo, o valor de baixa ou alta. E así hai unha morea de comandos que precisa saber, e este Presentación vai subir na web, por iso, se quere só facer referencia a estes ou como poñer-los nas súas cabulas, Sinto-se a liberdade. Cool. Iso foi Quiz Revisión 0, e imos estar por aquí, se tes algunha dúbida. Todo ben.  [Aplausos] [CS50.TV]