[Música tocando] DAVID J. MALAN: Isto é como um seminário hoje calouro. ESTÁ BEM. Então, muito chuvoso para fora. Isto tende a acontecer às quartas-feiras, mas todos os mais oportunidade para perguntas hoje. Então, vamos começar realmente com o filme em apenas um momento. Mas vamos começar grandiosamente como sempre. Este é CS50, e este é o fim de semana 4. Então, se você já assistiu TV ou um filme em que há alguns especialistas em informática e a polícia, ou FBI, ou alguma agência está tentando pegar alguns adversário, bem, você tem provavelmente já ouviu a expressão "melhorar" em que de alguma forma que técnico magicamente amplia infinitamente zoom para ver os criminosos identidade ou o número da placa no mesmo o brilho de um espelho ou o brilho de olhos de alguém. Então, na verdade, vamos dar uma olhada algumas dessas cenas de Hollywood. [REPRODUÇÃO DE VÍDEO] -OK, Agora vamos dar uma boa olhada em você. -Segure-Lo. Execute isso de volta. -Espere um minuto. Vire a direita. -Não, Que congelar. -Tela cheia. -OK, Que congelar. -Tighten-Se em que, você vai? -vector Em em que cara pela roda traseira. -zoom Em direito aqui neste local. -Com O equipamento certo, a imagem poderia ser ampliada e afiada. -O que é isso? -É Um programa de melhoramento. -Pode-Se claro que qualquer? -Eu não sei. Vamos melhorá-lo. A6 seção -Aprimore. -I Aumentada o detalhe, e- Eu acho que há o suficiente para melhorar, liberá-lo para minha tela. -Eu Reforçada a reflexão em seus olhos. -Vamos Executar este através melhoramento de vídeo. -Edgar, Você pode melhorar isso? -Esperar. -Eu Vindo a trabalhar sobre esta reflexão. A reflexão de -Alguém. -Reflection. -Há Um reflexo do rosto do homem. -O Reflexão. -Há Uma reflexão. -zoom Em no espelho. -Você Pode ver um reflexo. -Pode Você melhorar a imagem a partir daqui? -Pode Você melhorar o bem aqui? -Pode Você melhorá-lo? Você pode melhorá-lo? -Podemos Melhorar isso? -Pode Você melhorá-lo? -Mantenha Um segundo, eu vou melhorar. Em -zoom na porta. -Times 10. -zoom. -move In. -Mais. Espere, pare. -Pare. -pause-Lo. -Rotate Nos 75 graus em torno da vertical, por favor. -Pare. Volte para a parte Sobre a porta, mais uma vez. -Got Um intensificador de imagem que pode bitmap? Ei, talvez possamos usar o Pradeep Sen método para ver nas janelas. Software -Este é o estado da arte. -O Valor próprio é desligado. -Com O direito combinação de algorithm-- Eliminação tomada de -Ele algoritmos para o próximo nível, e eu posso usá-los para melhorar esta fotografia. -Lock Em e ampliar o eixo z. -Aprimore. -Aprimore. -Aprimore. -Freeze E melhorar. [FIM DE REPRODUÇÃO] DAVID J. MALAN: Tudo bem, então todos esses são realmente palavras. Eles só estão amarrados juntos em um forma que não é realmente sensata. E, de fato, CS50 e cursos como ele tende a arruinar um monte de TV e filmes para voce. Porque quando esses especialistas em informática estão despejando termos e dizendo coisas extravagantes como vectores próprios, e o eixo-z, e qualquer número de outros realmente termos mais técnicos, eles realmente estão apenas amarrando palavras juntas com demasiada frequência. É que uma das nossas esperanças é que, como um efeito colateral de cursos tomada como este, será mais pessoas no mundo realmente ser capaz de pesar e apenas muito ligeiramente influenciar o qualidade e precisão desses filmes? Na verdade, vamos dar uma olhada em realidade. Então aqui está a foto da equipe Mary, um dos nossos companheiros de ensino. E suponho que ela é suspeito de alguma coisa. E, no entanto, há um vislumbre de algum pedaço de evidência em seu olho, ou na reflexão de seus óculos. Bem, se fizermos exatamente como os filmes propor, na qual estamos zoom e "melhorar", esta é a quantidade de informação é no rosto de Mary quando você captura uma imagem com essa resolução original. E, de fato, você pode ver esses pontos. E estes são o que são chamados de pixels, P-X-I-E-L-S, que é apenas uma praça tipicamente que é um ponto que compõe uma imagem. E de volta no dia, e, na verdade, até mesmo hoje com algumas das TVs LED de hoje ou TVs LCD, se você tem um no seu quarto ou em casa, se você ir para cima super próximo a ele, e especialmente se for uma TV um pouco mais velho, você provavelmente pode até mesmo ver esses pontos e é isso que compor uma imagem. E não há mais informações do que este. Poderíamos "aprimorar", no sentido de suavização sobre as coisas e tipo de inferindo tipo de, tipo do que cor deve ser próximo aos olhos de Mary para que ele não é realmente tão pixelizada. Mas se eu continuar ampliando, não é o cara mau em seu olho. Como isso é tudo o informação que temos. Você não pode criar informações a partir do nada. Havia apenas um finito número de bits de lá. Assim, no Conjunto de Problemas 4, onde você tem uma oportunidade jogar com este tipo de mundo. Em Conjunto de Problemas 4, você vai explorar o mundo de gráficos e forense, e realmente escrever código que recupera imagens perdidas. Você vai escrever um código que manipula imagens existentes e, finalmente, entender o que é acontecendo debaixo do capô. E, ao que parece, é realmente não tão complicado. Por exemplo, se quiséssemos representam um rosto sorridente onde com esses pixels pretos, ou esses pontos pretos, Bem, nós poderíamos simplesmente representar -los como realmente um bitmap. E se você nunca tinha ouvido falar que expressão bitmap, talvez agora começa a fazer uma pouco mais de sentido hoje. Nós já sabemos o que é um pouco. É 0 ou 1. E um mapa é apenas algo como um pedaço de papel que lhe dá direções e tem talvez uma grade de coordenadas x e y. Então aqui está um mapa de bits. É um mapa de bits em que 1 é um aparentemente vai representar um pixel branco, e um 0 vai representar um pixel preto. Mas nós certamente poderia lançá-lo ao redor. Realmente não importa, Desde que estejamos consistente. E aqui está como, em binary-- dentro de memória de um computador, ou mesmo dentro de um arquivo no seu disco drive-- você pode armazenar a mais simples das imagens da cara do smiley. Mas o que devemos, naturalmente, falta nesta imagem? Cor, certo? É um próximo passo óbvio ou realce para melhorar este com a cor. Então, infelizmente, com apenas um único bit, 0 ou 1, poderíamos representar cores. Isso poderia ser vermelho ou azul, ou preto, ou branco, ou verde, ou cor de rosa, ou qualquer par de cores. Mas, para simplificar, vamos simplesmente assumir preto e branco. Então, o que logicamente que precisamos se nós deseja implementar cor em uma imagem? O que nós temos que fazer? Como se o fator limitante aqui é que, com um pouco você só pode representam dois estados, 0 ou 1, branco ou preto, o que você quer fazer? Audiência: mais dados. DAVID J. MALAN: mais bits, , yeah mais dados, mais bits. E, de fato, isso é exatamente como imagens a cores são representadas. Em vez de usar um único bit, uma 0 ou 1 para cada pixel, cada ponto, você acabou de usar múltipla. Talvez use 8, talvez, mais comumente utilizar 24 e, na verdade, no Conjunto de Problemas 4, você vai jogar com um arquivo formato que usa 24 bits normalmente. Mas a maioria de vocês provavelmente estão familiarizado com JPEGs. Se você já tomadas uma foto em seu telefone, ou enviados ou visto algo sobre Facebook ou Flickr, qualquer número de sites baseados em fotos, você tem provavelmente já viu uma imagem JPEG antes. E ao que parece, este é o arquivo formato que vamos usar em PSet 4, em que você vai ter de recuperar imagens que eu acidentalmente excluídos de um cartão de memória corrompida na câmera, Se você for. E verifica-se que, apesar de JPEG é bastante sophisticated-- é muito mais sofisticado do que os pontos preto e branco vimos há pouco, porque há algoritmos sofisticados que realmente são usados ​​para compactar um arquivo JPEG, de modo que você pode ter um muito bom, qualidade de imagem, mas usando relativamente poucos bits. E nós vamos voltar a compressão antes do tempo. Acontece que o primeiro três bytes de um image-- JPEG não importa o que você tenha tomado uma fotografia de-- são os valores 255, 216, 255. Em outras palavras, se você apenas ver que o padrão de bits, aqui representada como três bytes, ou 24 bits no total, com elevada probabilidade, você pode inferir que você está olhando para ele este três primeiros bytes de um JPEG. E isso é o que é conhecido como a assinatura de um JPEG. Um monte de formatos de arquivo lá fora, tendem a começar com certos padrões de 0s e 1s, para que o Windows e Mac OS, e iOS, Android e saber que tipo de arquivo que eles são, em adição ao ficheiro de chamada extensão que um monte de arquivos têm. Se você tiver .jpg, isso é outra pista para o computador. Então, vamos agora olhar para este um pouco mais tecnicamente. Sabemos que o decimal sistema é de 0 a 9. Sabemos binário é 0 e 1. E se você acha que volta para PSet 0, tivemos você lutar com, para um pouco, algo chamado hexadecimal, onde você tem 16 dígitos, 10, em vez de ou em vez de 2. E esses dígitos, por convenção, são de 0 a 9 e, em seguida, uma através de f, onde f representa o que número decimal, assim como a sanidade rápida Verifica? Então, 15. E um deve representar 10, apenas por natureza da ordem que eu dei. É apenas uma convenção arbitrária, mas é bastante padrão. Portanto, se olharmos para este padrão de três bytes-- vamos basta começar a olhar para ele de uma forma consistente com a forma como cientistas da computação em geral olhar e pensar sobre arquivos. Você certamente pode pensar em arquivos em 0s e 1s, e decimal, mas, na realidade, nós tendemos a usar binário ou, mais tipicamente hexadecimal-- de volta de PSet 0. Então deixe-me propor que 255, 216, e 255 são apenas esses padrões de 0s e 1s. E você pode verificar isso, se você quer fazer a matemática de Semana 0. Mas, por agora, apenas supor que este é realmente correta. Acabei reescrito três decimal números como três valores binários. Agora o que eu vou fazer é basta adicionar algum espaço em branco, apenas pelo amor de legibilidade. E observem, eu só vou para mover as coisas separadas. Portanto, antes de, após, antes, depois. Eu estou fazendo nada mais interessante que apenas se espalhando para fora coisas assim que a notificação de cada conjunto de oito bocados é agora dois conjuntos de quatro bits. Isto é útil porque hexadecimal é particularmente elegante porque cada dígito hexadecimal entre 0 e F, ou, mais especificamente, 0 a 15, pode ser representada com exatamente quatro pedaços. Em outras palavras, se você em hexadecimal quer representar um 0, é apenas 0000, quatro zeros. E se você quer representar 15, é 1111, que é quatro bits. E se você fizer as contas, se este é o lugar queridos, este é o lugar 16s, que vai dar vocę-- sim que está acontecendo a-- muito, em binário, que vai lhe dar 15, queridos lugar, twos lugar, quatro e oitos lugar. Então deixe-me propor que que conjunto de quatro bits na esquerda é o que nós vamos chamar f. É o maior número que pode representar com quatro bits. E já sabemos de hexadecimal, f é o maior dígitos em hexadecimal. Temos outro f lá, mais por lá dois. E por agora, basta ter em fé que eu fiz o direito de matemática e que a metade esquerda desses bits, 1101, é a mesma coisa que d em hexadecimal. E a mão direita, 1000, está apenas a 8. E isso é fácil de ver, certo? A 8 represents-- é certo debaixo daquele lugar oitos. Portanto, temos uma na coluna oitos e nada nos fours, twos queridos ou. Então, agora mais convencional, os seres humanos tendem para escrever dígitos hexadecimais como este, você apenas esmagá-los juntos, e então você prefixar-los com 0x. Isso significa nada mais do que uma pista visual para um human-- aqui vem um value-- hexadecimal porque que não poderiam ser óbvio. O que significa dizer, em última análise, que o padrão de zeros e uns, ou o padrão de hexadecimal dígitos equivalentemente que você é vai começar a procurar no Conjunto de Problemas 4 é isto-- e do Conjunto de Problemas 4 especificação andará -lo através deste em mais detail-- mas percebem como uma espécie de misterioso como este pode parecer à primeira vista, você vai começar a ver muito isso. E, de fato, mesmo em GDB, a depurador nós introduzimos na segunda-feira e Dan introduz no PSet 3, vai muitas vezes para mostrar-lhe valores hexadecimais só porque eles tendem a ser mais convencional do que decimal ou binário no mundo dos computadores. Agora vamos colocar isso em contexto. Muitos de vocês podem recordar este imagem aqui, que veio de uma coisa? Vista, por isso mesmo mais cedo do que que, o Windows XP fez esta estréia. Portanto, esta é uma bela paisagem. E, de fato, se você fuçar online-- Eu acho que é um artigo da Wikipédia, em que alguém muito surpreendentemente saiu encontramos a localização no mundo criado sua câmera em precisamente o direito Place-- e isso hoje parece como-- mas é exatamente a mesma configuração. Esta imagem, porém, é em um arquivo chamado formato de mapa de bits, b-m-p. E nós estamos indo tomar um super- rápido olhar sobre o que isso significa. Mas bitmap é apenas uma maneira diferente de imagens que representam ainda usando pixels em 0s e 1s, em última instância. Mas pelo olhar rápido, ele tem uma assinatura mais interessante no inicio do ficheiro. Não é apenas três bytes, em vez há um monte de padrões de bytes que têm significado predeterminado. Por exemplo, em algum lugar na primeiros bytes de uma imagem bitmap vai ser o tamanho do imagem, a largura da imagem, a altura da imagem, de modo metadados úteis, se você quiser. Informações úteis que o Photoshop ou programar todos os gráficos que você está usando pode realmente se preocupam. Então, mais sobre isso em Problema jogo 4, mas esta é só para dizer que no fim do dia todos os formatos de arquivo que você está usando para arquivos do Microsoft Word anos--, Números arquivos, arquivos do Excel qualquer número de formatos de arquivo que pode ter algum extensão de arquivo conhecidos são apenas 0s e 1s debaixo do capô. E os seres humanos decidiram o que as convenções são, o que padrões de 0s e 1s representam arquivar uma palavra contra um arquivo do Excel, contra qualquer número de outros formatos de arquivo. Assim, em PSet 4, você vai ter um oportunidade de jogar com isso. Mas o que significa ter um struct. Este é realmente um agradável segue agora em C, que tem apenas um par características adicionais de que nós não olhei ainda. É uma linguagem muito pequeno e um dos as características agradáveis ​​sobre C é um struct. Por exemplo, se você queria represent-- vamos diz que queria ter uma variável que representa um aluno em algum programa. Talvez você estivesse escrevendo um curso programa de registro, ou núcleo de compras ferramenta, ou algo parecido. Quais são pedaços de dados relacionados a um estudante que vem à mente? Como um estudante é representado com que valores? Sim? Você tem um nome como um estudante. O que mais faz um típico estudante tem? AUDIÊNCIA: [inaudível] DAVID J. MALAN: Então, desculpe. AUDIÊNCIA: Idade. DAVID J. MALAN: Uma idade ou aniversário equivalentemente, sim. O que mais? AUDIÊNCIA: número de identificação? DAVID J. MALAN: Então um número de identificação, talvez um número de telefone, talvez um dormitório ou casa, ou faculdade, ou algo parecido. Qualquer número de pedaços de dados que você pode ter em sua lista de contatos é o que poderia definir um estudante. Então, se nós queríamos fazer isso, no código, poderíamos fazer algo simples como este. Podemos ter um programa para que tem, digamos, int main (void). E se eu quiser representar um estudante eu poderia ter, por exemplo, uma string chamada nome para esse estudante, uma string chamada dormitório para esse estudante, talvez um int chamado ID para esse estudante. E porque eu estou usando corda, I precisa voltar e colocar-se CS50.h. Talvez eu vou precisar stdio.h. Então deixe-me fazer aqueles preventivamente e eu sou vai chamar este student.c por enquanto e salve este. E agora eu posso fazer alguma coisa com estas variáveis. E nós apenas estamos indo para escrever que, como um comentário no código pseudo, porque não é interessante o que fazemos agora. OK, portanto, este é um programa que de alguma forma armazena um estudante. O que eu quero fazer, se eu deseja armazenar dois estudantes? Então, meu primeiro instinto vai dar tudo certo, espere um minuto, se eu tiver outro aluno por que não eu apenas fazer nome da seqüência 2, seqüência de dormitório 2, int id2. E fizemos gone por isso antes e qual foi a nossa solução para o que parece para ser uma espécie de cópia de pasta hackish trabalho aqui? AUDIÊNCIA: Uma matriz. DAVID J. MALAN: Sim, nós poderíamos usar uma matriz. Por aqui muito rapidamente torna-se difícil. Você tem que classificar de forma arbitrária começar a nomear todas essas variáveis. E você, o humano, tem que manter acompanhar o que corresponde OK NAME2 com dorm2 corresponde com ID2. Ele só se torna uma bagunça. Por isso, é muito mais fácil, lembrar de algumas semanas atrás, apenas para ter de chamados nomes de cadeia e talvez dar-nos três delas. E então talvez nós temos dormitórios cordas e têm três destes, ou com uma constante, int ids e têm três delas. Mas mesmo agora isso se sente um pouco desleixado, certo. Estamos falando de estudantes e ainda Eu realmente estou me deter sobre o nível baixo detalhes de implementação. O estudante é um nome e um dormitório e ID. Por que eu não posso simplesmente declarar uma variável chamado de estudante e chamá-lo s. E se eu quiser um outro estudante, por que não eu apenas chamá-lo t. Ou, se eu quiser um grupo inteiro de estudantes, por que não eu apenas dizer que tenho toda uma classe de estudantes, e é três deles. Em outras palavras, por que não posso vir com meu próprio tipo de dados, chamado Estudantes, dentro dos quais é um nome, é um ID, é um dormitório, é qualquer número de outros campos. E acontece que você pode fazer exatamente isso. Então C tem esse recurso chamado struct. Isso é um recurso de linguagem que nos permite fazer exatamente isso. Eu estou indo para ir em frente e abrir structs.h onde estamos indo para ver o seguinte definição de um estudante. Acontece que - e este é mesmo mais simples do que o que envolveu um ID há um momento atrás. Se você quiser vir para cima com seu tipo de dados caseiro, e para além de Int, e carvão animal e flutuar e todos esses outros que existem, você pode fazê-lo literalmente escrevendo typedef struct, em seguida, algumas chaves, dentro do qual você listar as variáveis ​​que você deseja associar a esta nova dados personalizado digite como um nome e um dormitório, e em seguida, após as chaves você dar um nome para o novo tipo de dados. Assim, por exemplo, estudante. E o que é bom sobre isso agora é que se olharmos para o código correspondente, a convenção, em primeiro lugar de tudo, é colocar este em um arquivo chamado algo dot h, um arquivo de cabeçalho, que não tem começou a utilizar-nos muito. Mas vamos começar usando um pouco agora. E o que podemos fazer com isso, em última análise, nestas poucas linhas de código é declarar exatamente o que tipo de dados, um estudante. E agora vamos usá-lo. Eu vou agora entrar em um arquivo chamado structs1.c. E vamos dar uma olhada em um algumas características aqui. Então, as coisas aqui em cima é principalmente familiar, e nós vamos voltar para o que não é familiarizado em apenas um momento. Isto, obviamente está incluindo a minha própria arquivo de cabeçalho, que é novo, bem como, excepto para PSet 3 onde, recall, temos helpers.h. Então você pode se lembrar helpers.h #include. Por que eu estou usando aspas em vez de colchetes angulares? Quando eu escolho entre eles? Quase sempre eu pareço para usar suportes angulares. E então, de repente, em linha de seis Eu estou usando aspas duplas. Por que poderia ser? Sim? AUDIÊNCIA: [inaudível] DAVID J. MALAN: Isso é um real, o quê? AUDIÊNCIA: É na sua IDE. DAVID J. MALAN: Sim, que está no meu IDE real. E não vamos debruçar sobre o IDE, porque isso é apenas uma ferramenta que eu estou usando. Isso está no meu atual diretório, especificamente. Então structs.h é o meu próprio arquivo não instalado no IDE, no próprio sistema operativo, ao contrário, está no meu diretório atual. Assim, a convenção é se você quiser para incluir seu próprio arquivo de cabeçalho, você acabou de usar aspas duplas. O que nós chamamos essa coisa em linha 8, de um modo geral? Isso é o que? algo # define. Isso representa constantes, certo? Se você quiser ter um valor em seu programa que você use um todo monte de vezes, é boa convenção para incluí-lo para fora, declará-la, com o símbolo de hash definir, em seguida, por convenção, em todos maiúsculas word-- embora não seja estritamente necessário, mas é convenção humana para capitalizar constantes de modo que eles pulam para fora em você visually-- espaço e então o valor que você quer ser equivalente ao que o nome da constante. Sem ponto e vírgula, mas você simplesmente siga esse padrão existe. Então, o que estou fazendo neste código real. Então, vamos dar uma olhada o principal programa aqui. Na linha 12, porque eu incluíram structs.h, Agora tenho magicamente no meu eliminação de um novo tipo de dados. Eu apenas não têm acesso à int, e char, e float, e corda, e azul e outros. Agora tenho acesso a um tipo de dados do aluno. Assim, em linha 12, eu estou combinando dois ideas-- um um tipo de dados personalizado e dois, utilizando uma matriz. E assim, este programa se Eu quero realmente apoiar três estudantes diferentes no meu programa, eu pode simplesmente dizer me dê uma variável chamados alunos, cada um dos quais é de estudantes tipo, que é o meu tipo de dados personalizado. E, especificamente, dá-me três daqueles na minha matriz. Então, agora, o que fazemos neste programa? Aqui é apenas um para a iteração de loop de 0 a 3, que é porque qual é o valor de estudantes é. Eu só estou pedindo ao utilizador dá-me o nome do aluno. E, em seguida, na linha 17, nós ter uma linha na maior parte familiar. Temos o nosso velho amigo GetString à direita. E o pedaço de sintaxe é aparentemente nova, se você nunca programado em C antes, e nunca usou as estruturas? Sim? AUDIÊNCIA: O .name. DAVID J. MALAN: O .name. Mas isso não é muito de um salto, porque agora os alunos adaptador dá-lhe o estudante i-th. E se você quiser mergulhar dentro da referida estrutura, basta usar um único período e em seguida, o nome da variável dentro, ou a propriedade dentro desse Você quer ter acesso. Da mesma forma, em seguida, se eu, em seguida, solicitar que o usuário, dá-me dormitório do aluno, você pode armazenar de forma semelhante que cadeia na variável dormitório dentro de que a estrutura estudante. E agora as coisas ficam um pouco extravagante. E isso está indo olhar talvez em um lote muito em breve. Mas você vai ver isso muito mais em PSet 4, então, basta olhar para ele agora vamos. Acontece que na linha 23 através 38, o que você acha que eu estou fazendo, talvez? Eu removi os comentários para hoje, mas a versão do código online referência tem todos os comentários. O que parece que estou fazendo? AUDIÊNCIA: Salvar o arquivo com todas as informações que o usuário inseriu. DAVID J. MALAN: Sim, exatamente, esta é uma nova forma que estamos vendo dois, Outra característica de C, em que posso criar meus próprios arquivos. Até agora, quase todos os programas você escreveu é apátrida. Assim que ele é feito em execução, é isso. Não há memória ou recordação dele. Não há nenhum arquivo salvo. Mas se você quiser salvar entrada que tem aconteceu, como em um jogo ou um programa como este, ao que parece nós podemos fazê-lo. E você vai ver isso mais em PSet 4 e na Seção. Mas esta linha 23 essencialmente cria um arquivo chamado students.csv. E você pode ter visto isso antes. Mesmo que você nunca tenha estudado CS antes, CSV é variáveis ​​separados por vírgulas. É como um homem muito pobre de versão de um arquivo do Excel, o que significa que ele pode ser aberto em Excel e em Números da Apple, e tem linhas e colunas. Mas não é uma propriedade formato como a Microsoft ou a Apple. É apenas vírgulas que separam o valores que veremos em um momento. E apenas dar um palpite. Na linha 23, no final, o meu segundo argumento a esta nova função chamada f aberto para arquivo aberto é w. O que pode denotar w? Sim? AUDIÊNCIA: Ele permite que você gravar o arquivo? DAVID J. MALAN: Deixa você gravar o arquivo. Portanto, há um par de variantes que podemos ligar aqui. Mas se você só quer ler o arquivo, que é olhar para ele e lê-lo para a memória, você basta usar entre aspas "r". Se você quiser escrever para o arquivo, use entre aspas "w". Há também é acrescentar e um par de outras coisas se você quiser modificar os arquivos existentes. Agora vamos continuar vendo este coisa, então vamos voltar para a linha 24. NULL, ao que parece, é um valor especial que podem ser devolvidos por certas funções se algo foi wrong-- se o arquivo não existir, se você ficar sem memória, ou um monte de outros erros. Mas, por enquanto, vamos apenas supor que essa verificação de erros é apenas convencional. Aqui na linha 26, eu estou iteração 0-3 sobre todos os meus alunos. E este é o tipo de espécie de uma nova função, fprintf, mas apenas dar um palpite. Se printf é apenas impressão uma string formatada, o que fprintf provavelmente significa? AUDIÊNCIA: Imprimir em um arquivo. DAVID J. MALAN: Imprimir um string formatada para um arquivo. Isso é o que a adicional f meios é arquivo. E o novo primeiro argumento tem de ser a variável que representa o arquivo. Então só temos um formato corda assim como printf. E mesmo que esta sintaxe é novo, isso só significa ligar o nome do aluno, plug-in do dormitório estudantil e, em seguida, com fclose, feche o arquivo. E então lastly-- isto é novo e nós vamos voltar a este antes long-- Estou liberando o estudante por razões que aconteceu lá em cima. Mas vamos voltar para que, antes de long-- isso é por causa de como é GetString realmente trabalhando debaixo do capô. Então, vamos dar uma olhada rápida aqui. Se eu digitar ls no meu diretório, notar que eu não faço tem um arquivo chamado students.csv, simplesmente não existe, não existe. Então, se eu agora compilar este programa, fazer structs-1,. / structs-1, e eu estou indo para ir em frente e digitar Andi, que vive em Berkeley na Universidade de Yale. Nós vamos ter que Rob vive em Thayer estes dias. E vamos chegar a onde é, penso eu, Maria está em Mather, se eu ter lembrado corretamente. Portanto, nada parece acontecer. Mas se eu digitar ls agora, há students.csv. Vamos em frente e students.csv aberto. Esta é mais uma vez um muito formato de arquivo leve. Mas eu simplesmente adotou uma convenção que eu tenho duas linhas e colunas aqui. A coluna é primeiro primeiros nomes das pessoas. A segunda coluna é o estudante de dormitório, ou faculdade, ou casa, ou outros enfeites. E agora eu tenho guardado esse permanentemente em um arquivo. Portanto, não é tão interessante. Mas este é apenas um trampolim agora para ser capaz de manter as informações permanentemente. Então vamos ver agora o que mais nós podemos fazer com essas e outras características. Mas, primeiro, alguma pergunta? Isso foi muito, e isso foi rápido. Mas você vai ver um monte mais em PSet 4, bem. Sim? AUDIÊNCIA: Existe uma maneira de continuar a adicionar nomes para esse arquivo? DAVID J. MALAN: Boa pergunta. Existe uma maneira de continuar adicionando nomes para esse arquivo? Sim. E, de fato, se você acabar se re-abrir o arquivo, você usaria Citação unquote "a" por acréscimo, que gostaria apenas de acrescentar uma nova linha, a nova linha de novo e de novo, exatamente. Boa pergunta. Outras perguntas? Sim? Audiência: Se você executou o programa novamente agora, seria continuar a adicionar nomes para o arquivar ou seria abrir um novo arquivo? DAVID J. MALAN: Ah, boa pergunta. Se você executou o programa novamente à direita agora, talvez digitado em novos nomes, seria adicionar ao arquivo ou substituir o arquivo? Este último, porque eu sou não usar o modo de acréscimo. E porque eu sou apenas cegamente abrir o arquivo para escrita, é só ir para substituir o arquivo. Então, eu seria realmente precisa fazer é acrescentar, se eu quiser realmente ter um longo prazo banco de dados. Agora CSV é útil, francamente, mesmo para como se você é writing-- e vamos finalmente ver este no final do semestre, quando usamos CSVs para outros fins. Se você deseja armazenar todas as pessoas que se inscreveram para algum evento, ou se inscreveu para o aluno grupo, ou algo parecido, armazenar os dados neste tipo de formato é super conveniente. Porque, literalmente, se eu foram para o download deste arquivo. Eu poderia double-- e vamos realmente tentar isso se eu tiver Excel ou Numbers aqui. Vou botão direito do mouse ou control-clique meu arquivo. Whoops. Botão direito do mouse ou controle clique com o meu arquivo. Vamos lá, meu mouse não está cooperando. Download-- eu vou baixar todos os arquivos aqui para só assim eu posso pegar este. E vamos ver se isso funciona primeira vez students.csv-- Eu ativada. Agora eles querem ver meus contatos. Agora, eu preciso me registrar. Veja como é fácil usar CSVs? Sim, mantenha-o atualizado. OK, agora estamos prontos para a aula. OK, oh, o que há de novo? OK, fechar. Isso foi mágica. OK, agora temos que atualizar. E agora, ele esqueceu o que arquivar I originalmente inaugurado, mas o que A-- lá vamos nós. OK, então agora temos um arquivo do Excel. Obrigado. OK, então o que eu fiz foi a parte fácil. Claro que eu poderia ter pré-instalado Excel ou Numbers, ou qualquer programa. Mas isso é bom, porque agora eu posso manipular os dados em um formato padrão. Então agora vamos contexto mudar para onde paramos última vez, o que era para começar para tirar rodinhas. Mas, primeiro, você não fez veja este almoço mais cedo está novamente acontecendo aqui no fogo e Gelo em Cambridge, Sitar em New Haven. Registe-se no site o mais rápido possível CS50s para se juntar a estudantes CS50 e funcionários. Por isso, tomou rodinhas na segunda-feira como follows-- corda tenha sido declarada em Biblioteca CS50s durante algum tempo. E é bom, porque permite nós para falar sobre variáveis ​​como sendo palavras e frases completas e mais. Mas acontece cadeia não existe. Isso é apenas um sinônimo, ou um alias, que criamos para algo que na verdade, é um pouco mais técnico chamado um char *. E, de fato, vimos um exemplo de um programa na segunda-feira que não se comportou bem como esperávamos. Este foi o arquivo, comparar-0. E lembrar que comparar-0, se Eu recompilar programa de segunda-feira e executar comparar-0 e digite mãe em minúsculas, e mãe em minúsculas novamente. O programa insistiu I escreva coisas diferentes, mesmo que a mãe, tudo em minúsculas, é idêntica visualmente. Então, qual foi a resposta curta por que o computador pensa essas duas seqüências são diferentes? Sim? AUDIÊNCIA: [inaudível] DAVID J. MALAN: Certo. Então, a mãe, a primeira vez Eu escrevê-la no, está sendo armazenado em algum lugar no meu computador de memória, mas num local diferente que a segunda vez que eu digitar mãe. Agora ele certamente poderia ser otimizado. O computador pode ser inteligente e realizar estas duas cordas, hey, eles são idênticos. Deixe-me não redundantemente armazená-lo. Mas os computadores não fazem isso otimização a menos que você diga a eles para. Então, por padrão, eles são só vai acabar em dois lugares diferentes na memória. E assim, para ser mais claro, quando nós comparamos as duas cordas, O primeiro foi chamado de s, o segundo foi chamado t, o que foi que eu especificamente comparando aqui na linha 13? Sim. AUDIÊNCIA: É o lugar na memória que a variável irá apontar para. DAVID J. MALAN: Exatamente, eu estava comparando o local na memória que essas variáveis ​​apontado. Então, especificamente, se a mãe estava em número de bytes 1 e 2, e 3, 4-- e lembre-se porque a barra invertida 0 precisa ser todo o caminho no final. E a outra instância da mãe, m-o-m, Foi no endereço 10, 11, 12 e 13. Eu estava comparando 1, esse endereço, essa localização na memória, contra 10, que é obviamente, não é o mesmo. 1 não é 10. Portanto, este é agradável em que é bastante simples. Mas é problemático na medida em que parece que não conseguimos para comparar strings. Então fundamentally-- e neste nível baixo, se você queria implementar um programa para comparar duas palavras separadas que o usuário digitou em para a qualidade, fazer eles se alinham para carbonizar char, apenas em termos gerais, o que precisamos fazer, aparentemente? Não é suficiente apenas para olhar para os dois endereços. O que precisamos fazer? Sim? AUDIÊNCIA: Iterar a string [inaudível]. DAVID J. MALAN: Sim, vamos percorrer a string. Vamos usar um loop, um loop while, ou o que você sente mais confortável. E se nós temos duas cordas em algum lugar na memória, vamos olhar para cada um de primeiro caractere, em seguida, cada segundo é personagem, então terceiro e quarto, e quinto, até chegarmos o valor especial sentinela? AUDIÊNCIA: [inaudível] DAVID J. MALAN: Sim, a barra invertida zero, altura em que em qualquer cadeia Podemos decidir que é isso. Temos correspondido cada personagem? Caso contrário, retornará false. Se assim for, return true. E então isso é exatamente o que esta versão do programa comparar-1.c faz. Ele é idêntico ao que nós olhou para segunda-feira, exceto que eu tenho se livrado da palavra string-- embora que não tem impact-- funcional tudo Eu estou fazendo agora está removendo algumas rodinhas visuais, mas para ver claramente que s e t são endereços. E é isso que a estrela, o asterisco, representa é um endereço, também conhecido tecnicamente mais como um ponteiro. Então, quando eu declarar s em linha 9 e dizer char * s, isso não significa dar-me uma corda. Isso significa dar-me uma variável cujo propósito na vida é para armazenar um endereço. Porque eu estou a ponto de colocar o endereço de uma cadeia para ele. E, de fato, GetString, para ser claro, não retorna um string. Ela não retorna mãe barra invertida zero, per se. O que especificamente GetString e precisamente voltar? AUDIÊNCIA: [inaudível] DAVID J. MALAN: um endereço, o endereço do primeiro caractere em alguma corda que tenha chegado. E agora nós estamos vendo uma palavra-chave especial novamente. E, eu aludiu a isso mais cedo. Isso vai ser bom convenção que vamos ver novamente e novamente agora. Estou verificando para certificar-se de que s não é nulo e t não é nulo. Porque com base na minha realmente rápida menção anteriormente, o que pode significar, se não retorna GetString um endereço, mas de N-L-L-L, que é novo, algum valor especial? AUDIÊNCIA: Erro. DAVID J. MALAN: É um erro. Algo deu errado. E o que tipicamente pode acontecer, especialmente com o que pode ser strings-- de comprimento desconhecido em advance-- talvez os computadores dos sem memória, talvez você digitou, de tal longa palavra ou sentença ou colado um grande ensaio tal há não apenas a memória suficiente. E assim GetString não pode retornar o endereço da coisa toda, por isso só retorna nada. E ele diz que um erro aconteceu retornando o valor especial NULL. É o endereço zero, por assim dizer. Agora, descobre-C vem com um função que faz a iteração. Não temos de implementar isso com um loop ou um loop while nós mesmos. Podemos usar uma função, chamado de forma sucinta, agitar comp, ou String de comparação, cuja propósito na vida é fazer exatamente isso. Você dar-lhe dois ponteiros, dois endereços, e ele vai para esses endereços e então comparar carta para letra por letra para a qualidade, parando apenas quando o que é verdade? Quando intuitivamente deve agitar comp parar a iteração, só para ficar claro? Quando ela atinge uma barra invertida 0 em qualquer corda, em que ponto ele pode decidir tem tudo combinado, ou houve uma discrepância? Então, se nós funcionamos este agora e tentar o nosso jogo pouco capitalização, assim que comparar-1, ./compare-1, e escreva mãe em minúsculas ambas as vezes. Agora é a mesma coisa. E se eu fazê-lo novamente com minúsculas e então talvez maiúsculas. Agora é realmente distingue entre maiúsculas e minúsculas. Então, não tão difícil ou mágico, mas ele agora explicar o que está acontecendo debaixo do capô. Então, o que mais podemos extrair a partir deste tipo de lição? Então, vamos dar uma olhada nisso. Eu estou indo para ir em frente e escrever uma programa rápido aqui chamado copy-0. E agora vamos ir em frente e, na verdade, vamos fazer isto-- com cópia-0, Dê uma olhada no que eu tenho aqui. I primeiro informar ao usuário, diga alguma coisa. Então eu recebo uma string e eu armazenado em s. Então eu verificar se s é igual a é igual a NULL, basta retornar 1. Portanto, esta é apenas a verificação de erros padrão. Nada de interessante aconteceu. E, de fato, se nos livrarmos do erro a verificação, esta parece ser uma semana de código no momento. Mas eu comecei a ficar um pouco melhor sobre isso. Agora, na linha 16, uma semana atrás, talvez dia até mesmo um casal ou minutos atrás, pode-se dizer linha 16 é a criação de uma variável chamada t e cópia é para ele. E isso é um perfeitamente takeaway razoável. Mas ser mais preciso agora. O que está acontecendo na linha 16? O que está sendo copiado da direita para a esquerda? Sim? AUDIÊNCIA: É t obter um endereço de s? DAVID J. MALAN: Exatamente, t está recebendo o endereço de s. Assim, para ser claro agora, se eu for de volta a esse exemplo anterior e eu tirar a coisa que eu digitei. E o que eu digitei em-- aqui está s, e aqui é o que eu digitei em algum lugar memória, mãe e, em seguida, uma barra invertida 0 que é adicionado para mim. O que eu armazenados aqui, recordo, este está na posição 1, 2, 3, 4, isso é o que está atualmente em s. Portanto, se na linha 16, eu digo me dê outra variável chamada t e loja em pelo o valor de s, que fica armazenado aqui não vai mom mas sim apenas o número 1. Portanto, se olharmos para o futuro neste programa agora, o que vai acontecer? Então, observe que não há esta função você pode têm utilizado este um tempo atrás para César, ou Vigenere, ou talvez não em todos. Eu reclamo com o meu printf, eu sou vai capitalizar a cópia t. Primeiro na linha 19, sanidade rápida verificação, verificações STRLEN o comprimento de t. Porque eu não quero tentar capitalizar algo se não há nenhuma seqüência de lá. Se o usuário simplesmente pressionar Enter, não há nada para capitalizar. Então eu não quero fazer linha 21. Então linha 21 está capitalizando que carta, aparentemente, em t? AUDIÊNCIA: m? DAVID J. MALAN: Olha como se fosse copiar qual? AUDIÊNCIA: m. DAVID J. MALAN: Uh, m. OK, então a primeira m, porque aviso que estou passando para toupper, que se você nunca viu é apenas uma função para capitalizar como sua entrada. t significa dar suporte de zero me o zero de t. E assim como faz este mudança de imagem, para ser claro? O que precisa ser reescrito ou alterado em relação a s e t e mãe de zero barra invertida. AUDIÊNCIA: [inaudível] DAVID J. MALAN: Sim, por isso este um aqui simplesmente precisa de ter mudado a-- corrigir isto-- precisa ser alterado para um capital m. Mas agora, olhe no final do programa, se eu imprimir s e t como eu limpar aqui, ver o que é vai acontecer imprimir e s t. Então, faça copy-0, ./copy-0. Deixe-me ir em frente e digite na mãe em todas as minúsculas. Observe o original e a cópia ter sido capitalizados. Por quê? Bem, s e t são ambos apontando para, se você, o mesmo pedaço de memória. E, francamente, isso está ficando uninteresting-- realmente o facto que estamos usando o endereço de zero aqui. Quer dizer, eu realmente não me importo onde o material está na memória. Desculpe eu estou apagando um pouco demais. Mas eu realmente não me importo onde as coisas estão na memória. E assim, de fato o que programadores tendem a pensar sobre é que quando você fala sobre um endereço ou um ponteiro, quem se importa onde ele está na memória. Eu não me importo se é em byte um ou um bilhão. Eu só me importo que esta variável é eficazmente apontando para que pedaço de memória. E assim, a partir de agora, ao invés de tergiversar sobre endereços de memória arbitrárias, vamos basta começar a desenhar ponteiros como ponteiros, como flechas. Então, o que s e t realmente são, de acordo com este programa, por causa de como eu criei t, é apenas duas variáveis ​​separadas apontando para o mesmo pedaço de memória. E nós não nos importamos onde eles estão. Assim, podemos abstrair esse detalhe. Então, como faço para corrigir isso? Se eu quiser escrever uma versão da cópia programa que realmente copia a seqüência de caracteres e capitaliza apenas o cópia, apenas de forma intuitiva, o que tem que ser um Ingrediente para a nossa solução? AUDIÊNCIA: [inaudível] DAVID J. MALAN: Precisamos de uma coisa? AUDIÊNCIA: Pedaço de memória. DAVID J. MALAN: Precisamos outro pedaço de memória, certo? Nós não sabemos como fazê-lo ainda, necessariamente. Mas eu meio que precisa que isso aconteça de modo que a mãe original no caso de menor acaba nesse pedaço extra de memória. E então quando eu alterar a cópia, eu Não quero mudar essa cópia aqui. I em vez quiser alterar apenas este cópia do original, de modo que permanece inalterada. Então, vamos ver como podemos fazer isso. Em copy-1, que já tem sido despojado de comentário, mas é comentado online. Nós em vez fazer a estes following-- linhas são idênticos, me uma corda e chamá-lo s. Mas agora vamos olhar para um dos nossos mais complexo mas o último de complexidade por algum tempo, linha 16 faz exatamente isso. Portanto, se seu confortável com o imagem que apenas drew-- dê-me um novo pedaço de memória, copiar tudo para ele, vamos ver como podemos traduzir isso para código. Assim a linha 16, no lado esquerdo, char * t dá-me essa caixa por aqui. Isso é tudo que ele faz. No lado direito, m alloc, ou malloc, é a alocação de memória, super extravagante, uma maneira enigmática de apenas dizer dê-me um pedaço de memória. Quanta memória precisamos? Bem, é uma espécie de grande expressão. Mas vamos ver o que diz aqui. Então, isso, é claro, é dar- me o comprimento da corda de s. Então, a mãe deve ser o que? Então, só três, certo? mãe é de três caracteres. Você não contar com o barra invertida zero quando você falar sobre o comprimento de uma string é na verdade, as letras visíveis humanos. Então mãe, então isso me dá 3. Mas espere um minuto, eu agora estou adicionando 1. Por que eu realmente quero alocar 4 bytes e não apenas 3? Sim? AUDIÊNCIA: Para o valor de sentinela? DAVID J. MALAN: Exatamente, para esse valor de sentinela. Para a barra invertida zero, Preciso total de 4 bytes. Então, eu preciso do comprimento da corda mais uma. E, em seguida, apenas para uma boa measure-- apesar de neste sistema, ele está sempre vai ser 1-- estou dizendo multiplicar este por o tamanho de um carvão animal. Acontece que é sizeof um operador em C que apenas diz-lhe o número de bytes que é requerido para um determinado tipo de dados. Ele não funciona para matrizes, normalmente, às vezes ele faz. Mas, no caso geral, sem. Mas ele vai me dizer quantos bytes um char é, o que acaba é sempre 1. Então, isso é como multiplicar por 1. Linha de olhar tão super enigmático de código. Mas tudo o que ele faz é dá me um pedaço de memória. Mas isso parece estar copiando qualquer coisa em que a memória? Ainda não. E então o que faço na linha 22, e 23, 24, 25, bem, eu simplesmente fazer isso. E este é o tipo de material escolar velho agora. Isto é como PSet 2, onde você está apenas movendo as coisas em torno da memória, ou melhor, em strings. Então, eu estou repetindo de 0 a o comprimento da cadeia s. E eu estou copiando o personagem i-th no s para o personagem i-th em t. E porque eu, o programador, feita Certifique-se de alocar exatamente como muitos bytes como eu preciso, é perfeito um-para-um. E eu copiar mãe em minúsculas para o novo. E então, finalmente, eu faço essa linha. E assim o efeito só é para capitalizar esta t aqui. Então, um monte de absorver, mas se você considerar apenas o que realmente está acontecendo por baixo do capuz é apenas movendo estes bytes em volta, tudo o que é necessária para resolver este problema é apenas para nos dar este pedaço de memória. Agora, com o risco de esmagadora, deixe-me mostrar um outro exemplo que é quase idênticas, exceto para esta linha de código. Portanto, esta é a versão de hackers deste programa, se você quiser. Mas vamos apenas destilar -lo em o que está acontecendo. A linha 24 é utilizado para ser este t suporte de i recebe suporte s i. Agora, eu estou mudando isso para a estrela muito mais enigmática t mais 1 é igual a estrela mais 1 s. Então o que está acontecendo e por quê temos um personagem estrela? Nós vimos a estrela antes, e ele está sendo usado de forma diferente aqui. Nós já vimos char *, agora eu estou vendo Uma estrela no início, e isso é OK. Pois verifica-se que pode tipo de inferir apenas daqueles primeiro princípios que está acontecendo. Então, só para ficar claro, o que é s? Na semana passada, foi uma string. Isso não é suficiente anymore. O que é s, especificamente? AUDIÊNCIA: [inaudível] DAVID J. MALAN: É um ponteiro. É o endereço do primeiro caractere digitado em nós. OK, o que é t? AUDIÊNCIA: [inaudível] David J. MALAN: A endereço do primeiro byte em t, que pedaço de memória realocada. Assim, verifica-se que, quando iteração de 0 diante até a string length-- antes de tudo, i Começa a 0, porque desta antiga escola para coisa loop. Então, só para simplificar, vamos supor que a primeira linha de código é realmente apenas isso, certo. Se I é zero, zero, adicionando a algo presumivelmente não vai ter um efeito. Então, qual é essa palavra? Acontece que a estrela operador neste contexto é o dereference operador, que é apenas uma maneira elegante de dizer ir para o seguinte endereço. Portanto, se s é o endereço do primeiro personagem neste pedaço de memória, * s meios ir para lá. E porque temos desenhada a imagem desta forma, você pode adotar o seguindo o modelo mental. Se esta é s, e você diz * s * s, tipo de como rampas e escadas, se você se lembra do jogo desde a infância, é como seguir esse seta e vá para o endereço. * t é a mesma coisa. Então comece aqui, vá para o seu pedaço. Eu não posso simplesmente desenhar sobre Nesta tela dessa forma. * t significa que ir aqui. E, em seguida, o loop for é apenas dizendo mover esse personagem aqui, mover esse personagem aqui, mover esse personagem aqui. Mas como posso fazer isso incrementação? Eu preciso desfazer o que eu acabei de excluir. Isto é o que geralmente é chamado aritmética de ponteiro, que significa matemática com endereços. Se, neste loop for, Eu continuo incremento i, e s é um endereço de e t é um endereço, se eu simplesmente continuar adicionando 1, isso significa apenas seguir em frente, e para a frente, e para a frente na memória. É como Oxford Street, o rua que o edifício está no CS. Os edifícios do CS é de 33 Oxford Street. Então, se você fosse fazer 33 Oxford Street mais 1, que o leva até 34 Oxford Street, em seguida, 35 Oxford Street, em seguida, 36 Oxford Street, quaisquer que prédios realmente são - se existirem. E assim, isso é tudo que estamos fazendo aqui com a aritmética de ponteiro. Portanto, é uma maneira super arcano de nos expressar. Mas tudo o que está acontecendo debaixo da capa está apenas seguindo esses endereços, como seguir um mapa, se quiserem, ou na sequência de flechas como temos desenhado na tela. OK, um monte de digerir. Qualquer pergunta sobre a sintaxe, conceitos, ponteiros, malloc, ou semelhantes. Sim, aqui em primeiro lugar. AUDIÊNCIA: Então onde isso diz * t é igual a toupper * t, é que vai capitalizar todas as letras ou apenas-- DAVID J. MALAN: Ah, pergunta muito boa. Então nessa linha aqui, 31, é que isto vai capitalizar a primeira letra ou de todas as cartas. Então, vamos responder a isso, indo de volta aos primeiros princípios. E primeiros princípios aqui eu quero dizer basta ir para as definições básicas do que está envolvido. Então toupper é uma função que capitaliza um char. Isso é tudo. * t significa ir para o first-- ir para o endereço em t. Assim, na foto, se este é o pedaço de memória que alocados com malloc, e este é t, * t significa ir aqui. Enquanto isso, você está passando esse valor, minúsculas m para toupper, você está recebendo de volta M maiúsculo, onde você colocá-lo? Você está colocando-o no mesmo local. E assim por que a lógica daqueles definições básicas é só capitalizando a primeira letra a menos que você interagir com i ou um loop ou um loop while, ele não vai para fazer algo mais do que você perguntar isso. Boa pergunta. Sim? AUDIÊNCIA: Por que você use o dereference método, em vez de matriz? DAVID J. MALAN: Ah, boa pergunta. Por que você usaria o dereference método, em vez do método de array? Nenhuma razão em particular, para ser honesto. E, de fato, para este tipo de exemplo, direito, Estou apenas discutindo tornando o programa mais complicado, Mais olhos estão vidrados, as pessoas a visitar a porque este parece super arcano, mas mesmo que ele está fazendo a mesma coisa. E assim, francamente, esta é uma solução desnecessariamente complexo visualmente para o problema. É ainda bom design, cinco de cinco para o projeto, se é na faixa notação ou a notação de ponteiro. Mas-- especialmente quando chegarmos mais tarde no curso em PSet 5 quando implementamos esse dicionário que Eu mencionei um par de vezes-- vamos realmente se preocupam com o endereços de memória de baixo nível que nós realmente entendemos o que está acontecendo. Mas, por agora, verifica-se que este linha de código colchetes aqui quadrados não existem realmente. Eles são o que é chamado açúcar sintático, que é apenas uma maneira estranhamente legal de dizer a compilador converte colchetes ser que a expressão matemática. Portanto, é uma convenção humana para ser capaz de escrever apenas estes suportes muito fácil de usar. Mas o que o compilador, clang, está realmente fazendo qualquer momento você escreve o que está em destaque na linha 24, debaixo da capa é realmente convertê-lo a este. É apenas mais prazeroso como um ser humano a ler e escrever código como linha 24. Mas, eventualmente, aqueles rodinhas também vêm off quando o próprio conforto fica mais forte. Tudo bem, então recordar, em seguida, que este Era o tipo de maior problema Deparamo-nos. E é isso que desencadeou todo este conversa maldita sobre ponteiros, e endereços, e copiando coisas. Foi porque nós tropeçou este problema estúpido, estúpido, pelo qual Eu implementei logically-- com Lauren aqui na demo eo suco de laranja no milk-- um perfeitamente algorithmically função correta para trocar duas variáveis ​​' valores, mas a maldita coisa não têm qualquer persistente, ou permanente, efeito sobre o meu código. E por que isso? Em poucas palavras, por que é isso implementação de troca logicamente correta, mas não tem impacto sobre as variáveis ​​que são passados ​​para ele, como x e y para o principal? Qual era a essência da questão? Sim? AUDIÊNCIA: Porque variável feito cópias da variável no passe através da função. DAVID J. MALAN: Exatamente, quando você passa variáveis ​​em uma função, ou argumentos em uma função, elas são passou por cópia, que significa que você começa um idêntico à procura padrão de bits para ambos os X e Y, chamado aqui a e b. E você pode fazer qualquer coisa você quer com essas cópias, mas eles vão ter nenhum efeito sobre a função de chamada. E, de fato, que nós extraímos imagem na tela, lembre- última vez, em que se realmente pensar sobre o que é acontecendo debaixo do hood-- se esta é a memória do seu computador, e aqui é o pedaço de memória que está sendo usada para o principal, este é o pedaço de memória que está sendo utilizada para swap, e assim mesmo se principal tem duas variáveis, X e Y, de swap pode ter idêntica à procura valores, ambos os quais são 1 e 2, mas eles são completamente diferentes pedaços de memória. Então, precisamos de uma solução para isso. E, francamente, parece que temos agora tem uma solução para este problema, certo. Se agora temos a capacidade de manipular as coisas por meio de endereços e, uma espécie de rampas e escadas estilo, siga estas setas e ir a qualquer lugar que queremos na memória, não poderíamos nós resolver este problema passando de principal de trocar não os valores que queremos swap, mas apenas de forma intuitiva o que poderíamos passar para trocar em vez disso? [Interpondo VOZES] DAVID J. MALAN: Por que nós não apenas passá-lo os endereços, certo? Por que não vamos dar uma troca mapa do tesouro, se quiserem, que leva-o para o reais valores x e y. Vamos swap, realmente mudar esses bits originais, em vez de só de passagem cópias dos bits. E assim, de fato, que é o que é vai ser a solução. Esta versão é aqui claramente ruim e falho. E agora, à primeira vista, ele só olha como nós adicionamos um monte de estrelas aleatoriamente e cruzou os dedos que iria compilar. Mas, seria agora compilar. Mas vamos ver o que significam estas coisas. E, infelizmente, os autores de C poderia ter escolhido outro símbolo para fazer deste um pouco mais clara, mas o operador estrela tem um significado diferente em dois contextos diferentes. E temos visto tanto, mas vamos distinguir. Assim, no topo lá, quando eu mudei a e b de ser int de na ruim versão para int estrelas, a e b, Anteriormente, foram inteiros. O que são a e b agora em o bom, versão verde? Eles são endereços. Endereços de que, para ser claro? Endereços de inteiros. Assim, o fato de que eu sou dizendo meios int estrela este é o endereço de um inteiro, especificamente. Então agora notar nas linhas de código, outra coisa também mudou. tmp permanece o mesmo, porque é apenas o número inteiro temporária, nenhuma mágica memória lá. Mas uma empresa precisa de uma estrela. E, de fato, todos os outra menção de a e b, perceber que tudo o que é mudar de vermelho para verde é que eu estou prefixing as variáveis ​​com estrelas. Porque eu não quero copiar a e b. Porque se eu apenas copiar a e b e swap a e b, o que eu realmente trocar? Apenas endereços, eu quero trocar o que está em esses endereços. Eu quero ir lá. E assim o operador estrela dentro da minha função, não dentro da lista de parâmetros, significa que você ir para esses endereços e realmente mudar esses valores. Então, o que faz a imagem agora olhar como em seu lugar. Bem, se em vez disso eu estou passando por A e B não 1 e 2-- Na verdade, eu preciso adicionar uma outra definição aqui. Então suponho que este pedaço de memória está na posição 10. Esta é a localização 11, mas este é um pouco de uma simplificação, Agora tenho duas escolhas eu passar x e y ou eu passar seus endereços? Se eu passar seus endereços como este, eu apenas Agora precisamos implementar de troca por o código verde de modo que, quando se vê um e quando b vê, não apenas copiar a e b e mover o leite e suco de laranja. O suco de laranja e leite metáfora agora quebra, porque esses são copos de mapas de líquido e não. Nós em vez precisa ir para tratar 10 e nós precisa ir para lidar com 11, e em seguida, executar essa lógica troca. Assim, a lógica é a mesma, mas precisamos de uma maneira ligeiramente diferente de aceder a essas variáveis. E assim, no final, o que o programa tem que olhar como é isso. Em swap.c literalmente copiados e colado a versão verde. Mas eu preciso fazer uma mudança. Não é suficiente apenas para mudar swap. Que outra linha de código eu preciso mudar? Sim? AUDIÊNCIA: Onde leva os argumentos. DAVID J. MALAN: Onde que leva seu argumento. Então, se eu rolar até a Main, I não pode simplesmente passar em x e y, e, eu prometo, o último pedaço de nova sintaxe hoje. Eu preciso passar em não xe y, mas o endereço de X e Y. E ao que parece, o símbolo que os autores do C escolheu é se você usar um e comercial aqui, não para ser confundido com o bit a bit e comercial, se você usar um e comercial aqui e um e comercial aqui, esta figura para fora para você, qual é o endereço de x, talvez é 10, qual é o endereço de y, talvez seja 11, e passa aqueles em vez disso. Assim, uma grande quantidade de absorver toda de uma vez. Mas vamos ver agora rapidamente em nossas restantes quatro minutos onde as coisas podem dar errado. E como um aparte, na verdade, Eu tomei esta imagem, TF tomei esta imagem de um ou dois anos atrás. Então este é o canto de trás de Eliot Refeitório. Os ponteiros são talvez o mais difícil tópico que nós cobrimos em CS50. Então, se você se preocupa o tipo de inclinação é como talvez seja mais de um stick de hóquei assim, perceber nós estamos nos aproximando de um pico em termos de complexidade conceitual. E eu trago este foto, porque eu juro a deus, no outono de 1996, quando eu assumi CS50 com meu companheiro de ensino, Nishat Mehta, ele me sentou-se na canto do Eliot D. Hall durante o almoço, ou jantar, ou algo para tentar para me ajudar a entender ponteiros. E este é o lugar onde eu estava semanas após que foi introduzida em palestra quando Eu finalmente entendi ponteiros. E eu estou esperançoso de que esta vai clicar muito mais cedo para você. Mas perceber isso absolutamente entre os temas mais sofisticados nós olhamos. Mas é entre os mais poderosos. E quando você obtê-lo, é realmente tudo só vai finalmente chegar juntos. Assim, a certeza de que não faz precisamos todos pia hoje. Então aqui está o último programa vamos olhar. E vamos acabar com uma rápidas três minutos de claymation feita pelo nosso amigo, Nick Parlante. Aqui está um programa, que em os dois primeiros linhas declara uma variável x e y. Ambos os quais são endereços de inteiros, ponteiros aka. Nós, então, alocar o suficiente memória para armazenar um int e armazenar o endereço em que a memória de x. Então, é ainda mais simples do que o exemplo anterior. Dê-me quatro bytes de memória, que é o tamanho de um int, e colocar esse endereço em x. Esta linha aqui significa ir para o endereço em x e colocar o significado de vida, o número 42 lá. Mas esta linha me preocupa. Estrelar y significa ir para o endereço em y, e colocar o número 13 azarados lá. Por que é perigoso, neste ponto nas story-- ainda que rapidamente dito em nossas minutos minguantes aqui-- por que é ruim para mim dizer, ir para o endereço em y? AUDIÊNCIA: não Você tem [inaudível]. DAVID J. MALAN: Eu não tenho colocar qualquer coisa em y. Então, qual é o valor de y, neste ponto da história? Nós não temos idéia. É algum valor de lixo e nem sei Binky. Se nós poderíamos terminar com esta nota. [REPRODUÇÃO DE VÍDEO] Ei, Binky, acorde. É hora para o divertimento ponteiro. -O que é isso? Saiba mais sobre ponteiros? Oh, goody. Bem, para começar, eu acho que estamos vai precisar de um par de ponteiros. -ESTÁ BEM. Este código aloca dois ponteiros que pode apontar para números inteiros. -OK, Bem vejo o dois ponteiros, mas eles não parecem estar apontando para qualquer coisa. -Está certo. Inicialmente ponteiros não apontam para nada. As coisas que eles apontam para são chamado pointees e configurá-los é um passo separado. Ah, certo, certo. Eu sabia. Os pointees são separados. Então, como você alocar um pointee? -Ok, Bem este aloca código uma nova pointee inteiro, e isso define Parte X para apontar para ele. Ei, que parece melhor. Assim torná-lo fazer alguma coisa. -OK, Eu vou cancelar o ponteiro x para armazenar o número 42 na sua pointee. Para este truque, vou precisar da minha varinha mágica de dereferencing. -Seu Varinha mágica de dereferencing? Uh, isso, isso é ótimo. -Este É o que o código parece. Eu só vou definir o número e- [POP SOUND] Ei, olha lá vai. Então, fazendo um dereference em x segue a seta para acessar seu pointee. Neste caso, para armazenar 42 em lá. Hey, tente usá-lo para armazenar o número 13 através do outro ponteiro, y. -ESTÁ BEM. Eu só vou passar por cima aqui para y, e obter o número 13 set up. E, em seguida, tomar a varinha de dereferencing e apenas-- [BUZZER SOUND] Oh, hey que não funcionou. Diga, uh, Binky, eu não acho dereferencing y é uma boa idéia, porque a configuração o pointee é um passo separado. E eu não acho que nunca fiz isso. Hmm, bom ponto. -Sim, Alocamos o ponteiro, y, mas nós nunca defini-lo para apontar para um pointee. Hmm, muito observador. Ei, você está procurando boa lá, Binky. Você pode corrigi-lo assim que os pontos y ao mesmo pointee como x. -Claro, Eu uso minha varinha mágica de atribuição de ponteiro. -É Que vai ser um problema, como antes? Não, este não toca nas pointees. Apenas muda um ponteiro para apontar para o mesmo coisa-- [Estalo] --como outro. -Oh, eu vejo. Agora y aponta para o mesmo local que x. Então, espere, agora y é fixo. Tem um pointee. Então você pode tentar a varinha de dereferencing novamente para enviar a 13 over. Ah, OK, aqui vai. Ei, olha isso. Agora dereferencing obras sobre y. E porque os ponteiros estão compartilhando que um pointee, os dois vêem a 13. -Sim, Partilha, uh, qualquer que seja. Então, vamos trocar de lugar agora? -Ah, Olha que estamos fora do tempo. -But-- -Apenas Lembrar as três regras de ponteiro. Número 1, a estrutura básica é que você tem um ponteiro, e aponta até um pointee. Mas o ponteiro e pointee são separados. E o erro comum é a criação de um ponteiro mas para se esqueça de dar-lhe um pointee. Número 2, dereferencing ponteiro começa no ponteiro e segue a sua seta sobre para acessar sua pointee. Como todos sabemos, isso só funciona se houver é um pointee, que tipo de recebe de volta a regra número 1. Número 3, ponteiro atribuição leva um ponteiro e muda-lo para apontar para o pointee mesmo como um outro ponteiro. Assim, após a atribuição, os dois ponteiros irá apontar para o mesmo pointee, Às vezes isso é chamado de partilha. E isso é tudo que existe para ela, realmente. Bye-bye agora. [FIM DE REPRODUÇÃO] DAVID J. MALAN: Isso é tudo para CS50. Graças ao Professor Nick Parlante. Vamos vê-lo na próxima semana. [MÚSICA ELETRÔNICA DE JOGO]