JASON HIRSCHHORN: Bem-vindo, todos, a Semana 6. Estou feliz em vê-lo todos vivos e bem depois quiz 0, porque eu sei que foi um pouco difícil. Mas, felizmente, todos vocês fez muito bem. E assim que é maravilhoso. Se você está na minha seção, eu dei mais de você faça seus testes já. Um casal de você, vou me encontrar depois da aula. E se você é um estudante de extensão e você não tiver recebido o questionário de volta ainda, sua TF é provavelmente a trabalhar nele e graduando-o, e vai buscá-la de volta em breve. Então meus alunos de extensão que são assistindo agora - espero viver - Vou começar seus testes Em breve bem. Nossa agenda para hoje é o seguinte. Em primeiro lugar, vamos passar por cima de alguns recursos que CS50 oferece para você. Nós vamos passar por cima de Teste 0 seguinte, e Eu vou responder a quaisquer perguntas ninguém tem sobre problemas particulares. E então, nós estaremos passando por cima arquivo I / O e conjunto de problemas 5. Esses dois últimos tópicos levará se a maior parte da seção de hoje. Coloquei esta lista a cada semana como um lembrete para todos vocês, mas do núcleo seção, temos apenas 90 minutos - nós não são capazes de cobrir tudo o que eu adoraria cobrir para vocês. Mas nós temos uma tonelada de recursos para você desenhe sobre como você começa a conhecer o material e de trabalho através define o seu problema. Um lembrete de que eu tenho um texto on-line box, criado para que você preencha se você tem algum feedback para mim, tanto positivos como construtivo, cerca de seção. Essa URL está localizado aqui. Então, por favor, tome um momento se você tiver qualquer feedback, seja durante a seção, ou depois, ou depois de assistir ao vídeo online, para me dar o seu feedback. Eu realmente aprecio todo e tudo. Então, eu tenho tido pequenas conversas com um monte de minha os alunos durante toda a semana - como eu entrego quizzes atrás, falando sobre o claro, ver como você está fazendo. E um tema surgiu uma e mais em falar sobre - em em particular - conjuntos de problemas. E eu tenho que encapsulado tema na placa agora. Essencialmente, há uma diferença entre transformando em algo que é feito corretamente e algo que é bem feito. A maioria das pessoas têm feito fantástico em termos de correção - 5 de ou 4 da Série de Exercícios em todos. A maioria das pessoas estão ficando os de todos os tempos. No entanto, só porque você fez algo certo, não significa que você tem feito algo tão elegante, ou de forma eficiente, ou tão limpa como você poderia ter feito isso. E é isso que o projeto - e até certo ponto, estilo menor - eixos são para. Então, eu estou empurrando todos vocês, e outros TFs estão empurrando vocês, não só por sua vez, em coisas que são corretas, mas acabam nas coisas que são codificadas também. Não fazer desnecessário para loops, não recalcular variáveis ​​se você não precisa. Por exemplo, olhando para trás para conjunto de problemas 4, quando a colocação dos tijolos no tela, cada linha - cada tijolo em uma determinada linha tem a mesma coordenada y - coordenar a mesma altura. Assim que coordenada y não precisava ser calculada no interior do interior nested loop que você provavelmente usado para colocar os tijolos na tela. Ele só precisa ser calculado a cada vez que você trocou uma linha, ou desceu uma fileira. Então diga se há 10 tijolos em um fileira, cada tijolo pode ter a mesma coordenada y, e que coordenada y só pode ser calculado uma vez por todas desses. Ele não precisa ser calculado 10 vezes, nem essa necessidade cálculo acontecer no real função de chamada - a nova função chamada gracked. Então, se isso foi um pouco confuso para você, mais genericamente, as coisas que não precisa acontecer a cada momento você passar por um loop FOR não deve ser colocar dentro do loop FOR, e não deve acontecer a cada vez que você vai através do laço FOR. Outro exemplo bom projeto, vimos na Semana 3 por 15, você poderia manter pista do zero. Então, quando você inicializar a placa, você salvar - em uma variável global, talvez - x e y-coordenar do zero. E, em seguida, sempre que você - na sua função de movimento, sempre que você fizer um movimento bem sucedido, você atualiza o localização do zero. Isso iria salvá-lo de ter que fazer nested loops para olhar através dos embarcar cada vez na sua função de movimento e encontrar a zero, ou encontrar o azulejo, e, em seguida, verificar o que está ao seu lado. Em vez disso, você tem a localização do zero, você pode apenas olhar acima, abaixo, e para a esquerda e direita da mesma, para encontrar a telha que você estava procurando. Portanto, em termos dos programas que estamos escrevendo, eles nunca são grandes o suficiente que algumas dessas decisões de projeto são realmente vai dificultar o seu programa, ou fazê-lo funcionar mais lentamente, ou talvez até mesmo ficar sem memória. Mas ainda estamos empurrando vocês para escrever tão elegante e código eficiente quanto possível. Então, se você acabar escrevendo coisas que tem uma significativamente maior escopo, que será escrito com boa projectar para além de ser correcta. Assim, um número de que você tem trouxe isso. Isso é algo que estamos procurando - algo que vamos continuar a empurrá-lo caras. Se você tiver alguma dúvida sobre o projeto de seu programa, fique à vontade para chegar a mim, e eu estou feliz percorrer o seu programa com você, e apontar algum do design decisões que você fez, e dar-lhe alguns sugestões sobre como fazer ainda melhores decisões de projeto. Então, vamos seguir em frente para falar sobre Quiz 0. Antes de fazer isso, alguém tem alguma dúvida sobre o que Eu cobri até agora? [Farfalhar] JASON HIRSCHHORN: Sete segundos. OK. Vamos falar sobre Quiz 0 para um bit. A maioria de vocês tem o seu quiz 0 costas. Se não o fizer, espero que Lembra-se um pouco. Mas se você tomou quiz 0, então você também tem acesso ao PDF on-line em as soluções de amostras. Alguém tem alguma dúvida antes saltar para o material da semana sobre um problema particular em Teste 0 - por que a resposta é o que é? Tem alguém confuso sobre alguma coisa? Mesmo se você tem o problema direito, mas apenas gostaria de me explicar isso um pouco mais, eu estou feliz em fazê-lo agora. Então eu pedi que vocês venha preparado com alguma pensamentos sobre Quiz 0. Então, quem gostaria de ter nos começou com uma pergunta ou comentar sobre Quiz 0? [PAPER FURTOS] JASON HIRSCHHORN: Nem todo mundo fez perfeitamente. Então eu sei [risos] tem de haver algumas perguntas sobre Quiz 0. OK. Sim. Ompica. OMPICA: Número 10. JASON HIRSCHHORN: Número 10. Qual era o número 10? OMPICA: A - JASON HIRSCHHORN: I haven't - OMPICA: The incluem - JASON HIRSCHHORN: número 10 tinha oito anos I - a escrita de oito a i? OMPICA: Yeah. JASON HIRSCHHORN: OK. Assim, uma outra pergunta que você pode ter perguntou foi estou presciente? A resposta é sim. Na seção antes do teste, pedi vocês para codificar tanto Sterling e de oito a i. Ambos aconteceu aparecem no quiz. Portanto, esperamos, você paga atenção a isso. E se você tivesse, então você teria que provavelmente bem feito sobre aqueles dois. Mas oito para i, não o fizemos na verdade código lo em sala de aula, mas foi, mais uma vez, perguntado sobre o quiz. Assim, um par de coisas para levar notar quando a codificação de oito a i. A primeira coisa que, por questão, foi que você precisava para verificar se a cadeia foi igual a nulo. Algumas pessoas tentaram verificar mais tarde no programa se s suporte eu era - assim um caráter específico em que string - foi igual a nulo. Mas lembre-se, que é essencialmente nulo - é bom pensar nulo como um ponteiro de zero - um ponteiro para zero - em algum lugar na memória onde você nunca pode acessar. Então, se algo é igual a nulo, você sei que não foi inicializado, ou não há nada lá. Então s é uma estrela char, s suporte de i é um char. Por isso, faz sentido comparar s como nulo, mas o suporte não s i como nulo. Mas mais uma vez - de modo que foi a primeira coisa que você deveria fazer - certifique-se de que você realmente tenho uma corda real. Em seguida, você queria passar por cada caractere na string. E assim, isso seria como um suporte de s Eu, por exemplo, se i é o seu iterador. E tome esse caráter, e obter o seu valor real. Você tê-lo armazenado como um char, mas o valor ASCII para a zero - zero como um personagem - não é, na verdade, o inteiro zero. É algum outro número que você pode olhar para cima na tabela ASCII. Assim, uma maneira de corrigir isso - provavelmente, a melhor maneira de corrigir que - é subtrair o valor do caractere - zero como um personagem. Aspas simples Então negativo, zero, outra aspa simples. Isso vai levar o número que você tem como um char, e obtê-lo igual a o número como um número inteiro real. E isso é muito semelhante à abordagem um monte de gente teve no problema ajustaram 2, com César e Viginere - essas cifras, quando você foram girando-os. Então, depois de tê-lo como um número de de zero a nove, então - dependendo para onde vai o número final - é preciso multiplicá-lo por uma potência de 10. Algumas pessoas se mudaram de trás para a frente, e multiplicou o indivíduo número por uma potência de 10. Algumas pessoas passaram de a frente para trás - e assim teve a maior ordenar os números em primeiro lugar - e iria salvar aqueles em um variável do contador global. E, em seguida, cada vez através do PARA loop, multiplicar esse gigante global combater variável por 10, para fazer espaço para a próxima carvão. Então isso foi um pouco confuso, sem me escrevê-lo no tabuleiro. Mas a solução amostra está disponível para você. Mas essas eram as coisas grandes que estávamos procurando. Também uma verificação para certificar-se de que cada caráter individual era de fato um caráter entre zero e nove anos, e não algum outro personagem, como um A, por exemplo. Essas foram as coisas que estávamos procurando no essa pergunta. Isso responde a sua pergunta? OMPICA: Yeah. JASON HIRSCHHORN: OK. Existem outras questões sobre Quiz 0? E sobre a compilação? Todo mundo compilando certo? Não. Havia um - [Risos] Qualquer dúvida sobre o processo de compilação? Uau. [PAPER FURTOS] JASON HIRSCHHORN: sim. Michael. MICHAEL: É o número 7 - aleatório? JASON HIRSCHHORN: Número 7. Número 7 foi obter um número inteiro aleatório. Excelente. Então, você está dado um inteiro e um a b inteiro, e você quer um aleatório inteiro entre a e b. Nós podemos realmente escrever este em da placa, porque este era uma linha de código - uma maneira de fazê-lo. Então, nós estamos dada drand como função que poderíamos usar. E o que drand - assumindo que foi semeado - o que drand voltar? MICHAEL: A flutuação entre 0,0 e 1,0. JASON HIRSCHHORN: Um número - sim. Um número entre 0 e 1. E assim temos b e a. E então temos o nosso número aleatório entre 0 e 1 dado a nós por drand. Algumas pessoas tentaram colocar b, ou b menos um, ou algo dentro aqueles parênteses. Isso significa que eles são argumentos para esta função. drand não leva nenhum argumento - como getString faz Não tome nenhum argumento. Então é só parêntese aberto, perto paren - e que, em si, é a chamada de função. E isso dá-lhe um número entre 0 e 1. Claro, temos uma gama inteira que números podem ser pol Digamos que, se b é 10 e um é de 5, nós realmente quer um número com um intervalo de 5. Portanto, a próxima coisa que precisamos fazer é multiplique isso pelo menos uma faixa de b. Assim, supondo que é multiplicado. E isso vai nos dar um número dentro de um determinado intervalo. E essa faixa específica sendo o diferença entre b menos um. E, finalmente, que só vai dar-lhe a partir de - dizem que a faixa entre b menos um é 5, que vai nos dar uma número de 0 a 5. Mas se um é de fato 5, precisamos aumentar esta faixa de até onde é na verdade, deveria ser, adicionando um. Assim que recebe o direito de lógica. E então, você teria outra pergunta? MICHAEL: Não. Eu me sinto muito idiota agora. [Risos] JASON HIRSCHHORN: Não. Não se sinta realmente estúpido. Um número de pessoas que lutaram com essa questão. E, em seguida, a outra questão é, drand, você disse, dá-lhe um float - retorna um float. Mas essa função realmente pediu para um inteiro para ser devolvido. Você não precisa de lançar isso explicitamente para um número inteiro, porque estes operações irão tratá-lo como um todo float - como um número de ponto flutuante. Gosta dessa vontade - mesmo que isso é um número inteiro, esta vontade ser multiplicado corretamente. Toda a multiplicação funcionará. Você não precisa lançá-lo aqui. Na verdade, você não deve lançá-lo. Isso seria - se você lançar um número que está entre 0 e 1 - um número aleatório, um ponto flutuante - em seguida, ele será ou só 0 ou 1, de modo você vai perder tudo isso de precisão. Mas no final, quando você voltar, fica automaticamente enviado de volta como um inteiro. Assim você não precisa fazer que lançando-se. Portanto, esta foi a resposta a a essa pergunta, o número 7. Quaisquer outras perguntas sobre quiz 0? Sim, Annie. ANNIE: Quando usamos recursiva - quando é que vamos usar loops iterativos? JASON HIRSCHHORN: Quando você usa recursiva - assim mais geral, a prós e contras de recursão contra uma abordagem iterativa. Alguém pode oferecer um profissional ou um engodo? Por favor? Não pode ninguém. Quem pode oferecer um profissional ou um engodo? [PAPER FURTOS] ALUNO 1: recursiva é menor codificação - menos de digitação? JASON HIRSCHHORN: Então, geralmente, recursão principalmente, uma função - ou um algoritmo como merge tipo - que se presta para uma abordagem recursiva - pode ser mais simples para codificar de forma recursiva. E só fazer mais sentido para fazê-lo de forma recursiva. Então isso seria um profissional para a recursividade. Outros? Sim? ALUNO 2: Con de recursão - Ele usa mais memória. JASON HIRSCHHORN: Então exatamente correto. Uma função recursiva vai continuar a adicionar pilha de quadros para a pilha. Então, se você estiver operando em um monte de números, e tem que chamar esta funcionar muito, então você certamente vai ocupam mais memória, enquanto uma abordagem iterativa só vai colocar um empilhar quadro na pilha, porque tudo acontece dentro de uma função. Quaisquer outros prós e contras? É. ALUNO 3: Prós para recursão. Você não tem que determinar em avançar quantas vezes o código teve que ser repetido. Pode ter um número predeterminado de vezes que você tem que interagir, então recursão é melhor, porque é preciso que o resultado. JASON HIRSCHHORN: Eu acho que isso é verdade. Mas eu acho que em ambos os casos você nunca faria isso - você provavelmente obter algum entrada do usuário. Ou essa função teria alguma entrada que iria determinar quantas vezes ele deve ser executado. Então, geralmente, você não faria código rígido - mesmo em uma abordagem iterativa - como muitas vezes esse ciclo deve ser executado. Será que você tem um outro que estava pensando, Annie? OK. Portanto, estas são provavelmente os dois - o maior pró eo maior con a um recursiva contra uma abordagem iterativa. OK. Qualquer outra coisa em quiz 0? Vamos seguir em frente. File I / O. Há um maravilhoso curta esta semana em arquivo I / O que esperamos você assistiu múltipla vezes, e admirado. Muito trabalho foi para isso, e eu tenho ouvido é insanamente útil. Eu também incluiu o link neste slide, no caso de você não ter tido uma chance de vê-lo 10 vezes. Então, nós estamos indo para ir brevemente sobre o principais passos para abrir e trabalhar com os arquivos, e depois nós vamos mergulhar em um problema de codificação antes examinar o conjunto de problemas. Então, novamente, eu vou colocar isso em a tela, mas eu vou falar para apenas um minuto sobre o que estamos fazendo aqui com o arquivo I/O-- O que isso significa? Isso significa que podemos criar nosso programas e, em seguida, temos nossos programas saída, e não fizeram qualquer impacto sobre o mundo fora do nosso programa. Mas quando começamos a trabalhar com arquivos - tanto lê-los e criar eles - que pode ter algum efeito sobre a mundo fora do nosso programa. Assim como se o Microsoft Word não foi capaz fazer quaisquer documentos do Word, em seguida, uma vez que o Microsoft Word parar, todo o seu trabalho teria ido, e que seria realmente ser inútil. Nós queremos finalmente ser capaz de escrever programas que podem afetar o mundo ao seu redor, tanto pela ingestão de entradas complexas - em termos de arquivos e através de arquivos, e também criar interessantes e saídas convincentes - em termos de diferentes tipos de arquivos. É por isso que estamos começando a aprender a trabalhar com arquivos. Mais especificamente, o o que fazemos é a seguinte. É muito simples. Há apenas um par de passos, e eles são listados aqui neste código. Então vamos passar por este código linha por linha. Primeiro, você vê destaque - quando você está trabalhando com um arquivo, independentemente do tipo de arquivo que é, você precisa abri-lo. E é com uma chamada para fopen - bem aqui. Você incluir o nome do arquivo. Se o arquivo não está em seu diretório, ou a pasta onde este programa vidas, então você também precisa incluir um caminho para onde o arquivo está. Vamos supor que esta arquivo chamado "text.txt" - um documento de texto simples - está no mesma pasta que este programa é. Então, isso é outra coisa a ter em mente - que, se você deseja abrir um arquivo em outro lugar, você realmente precisa para incluir a sua localização. Segundo, você pode passar um argumento para fopen, e é isso que você quer fazer com o arquivo. Existem três principais argumentos que você vai passar para fopen. Quem pode me dar os três? Quem pode me dar um deles? Sim. ESTUDANTE 4: O nome do arquivo? JASON HIRSCHHORN: Desculpe. Três principais argumentos você pode passar como o segundo argumento para fopen. Você está certo - o nome do arquivo é o primeiro argumento. Mas o segundo argumento para fopen são geralmente três cordas, e - sim. Aleja. ALEJA: A para acréscimo. JASON HIRSCHHORN: A, se você quiser anexar um arquivo que já existe. ESTUDANTE 5: R para ler. JASON HIRSCHHORN: R, se quer ler um arquivo. ESTUDANTE 6: W para gravação. JASON HIRSCHHORN: E w, se você quero escrever para um arquivo. Portanto, neste caso, estamos escrevendo para o arquivo, por isso temos w. Você abri-lo, você também tem que salvar o arquivo em algum lugar, e isso é com o codificar para o lado esquerdo da o operador de atribuição - Estou criando um ponteiro para um arquivo chamado, neste caso, de arquivo. Não vamos nos preocupar que essa coisa IMAGEM todas as tampas é. Basta dizer, é um longo fluxo de zeros e uns. E é assim que vamos operá-lo e compreendê-lo. A próxima coisa que precisamos fazer - e Isso é extremamente importante - sempre que você abrir um arquivo - na verdade, sempre que você chamar malloc, por exemplo, e obter alguma memória e tente e salve-o em um ponteiro, você sempre querer verificar para se certificar de que esse função não retornar nulo. Portanto, neste caso, estamos verificando para fazer Certifique-se que realmente abriu a arquivar corretamente, e não havia nenhum erro em nosso programa. Em seguida, uma vez que temos verificado para se certificar que temos um arquivo de trabalho, podemos gravar ou ler a partir de, ou anexar o arquivo. Neste caso, estou simplesmente imprimir uma linha a este arquivo. Como eu sei disso? Bem, eu estou usando esta função chamado fprintf. Todas as funções que você irá utilizar ao gravar ou ler a partir de, ou manipulação de arquivos será semelhante ao funções que você já viu antes, mas começam com a letra F, pé para o arquivo. E fprintf, ao contrário de nossa impressão normal aplicativo, tem um argumento adicional, e que é o arquivo no qual você deseja imprimir esta linha. Eu não tenho nada a o direito de ohai. Eu não tenho o terceiro argumento para printf - ou o segundo argumento para printf, o terceiro argumento para fprintf, porque eu não tem espaços reservados aqui. Eu não estou incluindo quaisquer variáveis. Mas, novamente, fprintf e todos estes arquivos funções que operam com arquivos são geralmente vai precisar do arquivo em que está operando. Finalmente, a última coisa importante a fazer é fechar o arquivo, assim como com - sempre que malloc alguma coisa, queremos libertar alguma coisa, para que não ter um vazamento de memória - queremos para fechar o nosso arquivo. Se este programa saiu sem fechar o arquivo, as probabilidades são nada iria errado, especialmente se era um arquivo pequeno. Mas é certamente um bom código e prática para sempre fechar o arquivo quando você terminar de usá-lo. Então isso é o básico do arquivo I / O. Você provavelmente já viu isso antes, ou assisti-lo nesse fantástico curta. Alguém tem alguma dúvida, antes de nós entramos em alguma codificação prática problemas, cerca de arquivo I / O ou a passos que eu só fui de novo? [DATILOGRAFAM SONS] JASON HIRSCHHORN: Você tenho uma pergunta, Avi? AVI: Não. JASON HIRSCHHORN: OK. Vou esperar mais um sete segundo. [Risos] Essa é uma dica muito boa. Vocês só não gosto fazer perguntas. Isso é bom. OK. Assim, o nosso primeiro problema é prática, estamos vai duplicar a função de uma ferramenta de linha de comando que você, provavelmente, usado antes - cópia - a ferramenta de cópia. Se você digitar cp e, em seguida, passá-lo duas argumentos em seu terminal, você pode copiar um arquivo. E é isso que nós estamos indo para escrever agora. Então, novamente, a leitura fora deste slide, eu que você escreva um programa que tira dois e apenas dois de linha de comando argumentos - um arquivo de origem e um arquivo de destino - e copia o conteúdo da fonte arquivo para o arquivo de destino um byte de cada vez. Então, isso é muito a pedir. Mais uma vez, uma boa abordagem para isso é não ir direto para o código C, mas decompô-lo em um par de passos. Primeiro, pense sobre a lógica - exatamente o que eu estou pedindo para você fazer - e compreender toda a passos para este problema. Não em C, apenas em um pseudocódigo, ou até mesmo um modelo mental de o que está acontecendo. Em seguida, depois de ter o pseudocódigo para baixo, descobrir como o pseudocódigo mapas no ferramentas e coisas que temos aprendeu em uso em C. E, finalmente, uma vez que você tem tudo o que juntos, você pode codificar o problema. Take 5 a 10 minutos para trabalhar sobre este problema. Vou colocar as instruções back-up em um segundo. E então nós vamos passar por cima de o pseudocódigo eo código ele vive como um grupo. Se você tiver alguma dúvida, enquanto você está trabalhando sobre isso, fique à vontade para levantar sua mão, e eu virei volta e respondê-las. ESTUDANTE 7: Posso roubar um pedaço de papel? JASON HIRSCHHORN: O que foi? [DATILOGRAFAM SONS] JASON HIRSCHHORN: OK. Vamos rever o pseudocódigo em primeiro lugar, e então eu vou dar-lhe mais um par minutos para terminar a codificação. Quem gostaria de me começar com a primeira linha de pseudocódigo para esta função? ALUNO 8: Certifique-se de que que lhe foi dada dois arquivos. JASON HIRSCHHORN: OK. E se nós não somos? ALUNO 8: eu iria retornar 0. JASON HIRSCHHORN: Devemos retornar 0? ALUNO 8: Voltar a - supressão. Desculpe. JASON HIRSCHHORN: Yeah. Provavelmente não 0. Porque 0 significa que tudo era bom. OK. Então essa é a primeira linha de pseudocódigo. Quem tem a segunda linha do pseudocódigo? ESTUDANTE 9: Abra os dois arquivos? JASON HIRSCHHORN: Abra os dois arquivos. OK? ALUNO 10: Verifique se o arquivo é NULL? JASON HIRSCHHORN: Verifique certeza não são NULL. Como um aparte - cortar 0 - é que NULL? ALUNO 11: Não. JASON HIRSCHHORN: Isso não é NULL. Isto é chamado o terminador NULL. É realmente escrito com apenas um l. Assim, verificando alguma coisa contra isso - que na verdade é um personagem - assim verificando algo que é contra não o mesmo que a verificação para ver se ele é igual a NULL. E algumas pessoas - em seus testes e seu problema conjuntos - tem o dois deles confuso. Mas os dois desses são de facto diferente. Um termina uma string - é um ponteiro para 0. ALUNO 12: Por que você não verificar para certificar-se de que os arquivos não são NULL antes de abri-los? JASON HIRSCHHORN: Então aberto salva algo nesse arquivo. E se você voltar aqui - assim que esta linha - fopen - vai lhe dar um endereço e loja esse endereço no arquivo se ele funciona. Se isso não funcionar, irá armazenar NULL - ALUNO 12: Oh. OK. Apanhei-te. JASON HIRSCHHORN: No arquivo. Então você não pode verificar a existência de NULL antes de você abri-los. NULL significa algo que não fez funcionar correctamente. OK. Então, certifique-se de não é? Ou são? O que acha? Vamos com isso. ALUNO 13: É. JASON HIRSCHHORN: É? Também não é? ALUNO 13: É. JASON HIRSCHHORN: OK. Parece que temos alguns consenso sobre isso. Nem é NULL. OK, próxima linha de pseudocódigo. Quem não me deu uma linha ainda? Vamos esperar por você. É. ALUNO 14: Você tem que ler desde o primeiro arquivo? JASON HIRSCHHORN: OK. ALUNO 14: Ou nós usamos fscanf ou algo como que o primeiro arquivo? JASON HIRSCHHORN: Então, nós queremos lido a partir do primeiro arquivo e - vamos deixar isso bem aqui. Leia a partir do arquivo de origem. E então, o que vamos fazer depois que lido a partir do arquivo de origem? Alguém mais? ALUNO 15: Escrever em o arquivo de destino? JASON HIRSCHHORN: Nós escrevemos para o arquivo de destino, e - OK. O que mais estamos perdendo? Alguém que não tenha me dado um linha de código ainda - de pseudocódigo. É. ALUNO 16: Talvez você sempre pode verificar se há algo para ler para, como a próxima linha? Isso é como a próxima linha, ver se ele existir. [ELETRÔNICO BEEP] JASON HIRSCHHORN: Oops. Esse é o meu software journaling. Sim? ALUNO 16: Yeah. JASON HIRSCHHORN: Então dê isto para mim mais uma vez. ALUNO 16: Verifique se há ainda a próxima linha do arquivo de origem para ler. JASON HIRSCHHORN: OK. Portanto, não estamos lendo linhas - estavam lendo bytes por aqui - mas você está correto. Queremos ler e escrever até não há mais bytes. OK. E assim, estes devem realmente ser recuado um pouco, porque eles estão lá embaixo. Certo? Até que nós estamos fora de bytes, vamos lido a partir do arquivo de origem e escrever para o arquivo de destino. E então, o que é a última linha de pseudocódigo? Alguém que não é dado me alguma coisa ainda. ALUNO 17: Feche os arquivos? JASON HIRSCHHORN: Exatamente. Feche os arquivos. Portanto, não é o nosso pseudocódigo. Eu vou colocar o pseudocódigo em gedit, e em um par de minutos, codificará isso juntos. OK. Vamos começar como um grupo. Nishant, eu tenho meu novo arquivo. Acabei de abrir isso. Documento Untitled 1. Qual é a primeira coisa que devo fazer? Nishant: Incluir bibliotecas? JASON HIRSCHHORN: OK. O que as bibliotecas? Nishant: Stdio.h, stdlib.h, eu acredito? JASON HIRSCHHORN: OK. O que é stdlib para? Nishant: eu esqueci. JASON HIRSCHHORN: OK. Portanto, incluir stdio. O que devo fazer antes mesmo de Eu começar a programar? Nishant: Escreva um cabeçalho? JASON HIRSCHHORN: Como faço para obtê-lo colorido? [VOZES interpondo] Nishant: Como você conseguiu isso de cor? JASON HIRSCHHORN: Como posso colorir codificação? Nishant: Eu não sei. Oh. Salve. JASON HIRSCHHORN: Salvar. Sim. Eu deveria salvá-lo como um arquivo. C. Então salve-o na área de trabalho como cp.c. Doce. E se eu quiser obter estilo completo pontos, o que devo incluir no topo? Nishant: Você poderia escrever seu nome, nome do programa, eo objetivo do programa também? JASON HIRSCHHORN: Parece bom. Excelente. Então você começou-nos perfeitamente. # Include - nós também vamos escrever - OK. Então, eu acho que estou pronto para ir. Quem tem a primeira linha de código para mim - ou as primeiras linhas de código que que será necessário para satisfazer o nosso primeiro comentar em pseudocódigo? Você. ALUNO 18: Não deveria ser int argc e char * argv? JASON HIRSCHHORN: Eu acho que você está certo. Vamos mudá-lo para int principais, parêntese aberto, int argc, vírgula, char * argv? Assim? ALUNO 18: Suportes. JASON HIRSCHHORN: Suportes. Abrir suporte, perto do suporte, perto do pai. Perfeito. Agora eu posso ter argumentos de linha de comando. OK. Certifique-se de que está dado dois arquivos. Você pode me dar isso também. ALUNO 18: Se argc - este não é igual 3. JASON HIRSCHHORN: Se parêntese aberto O argc não igual a 3? ALUNO 18: Sim, você retornar 1 ou nada. JASON HIRSCHHORN: Desculpe. ALUNO 18: Return 1 ou nada. JASON HIRSCHHORN: Return 1. OK? Grande. Abra os dois arquivos. Quem pode me ajudar a abrir os arquivos? Quem não me deu código ainda? Kurt? KURT: Então, todas as tampas F-I-L-E Fonte estrela. JASON HIRSCHHORN: Eu vou para tirar as vogais. Aqueles são legais. É como Tumblr. ALUNO 18: Igual fopen - JASON HIRSCHHORN: Igual fopen? ALUNO 18: parêntese aberto, argv, suporte aberto. JASON HIRSCHHORN: Espere. Desculpe. Abrir parêntese. OK. ALUNO 18: Yeah. Argv sub 1. JASON HIRSCHHORN: Sub 1? ALUNO 18: Yeah. Argv suporte aberto 1 - Sim. E, em seguida vírgula, e em seguida, abra o dobro citação, r, aspas duplas, paren próximos, ponto e vírgula. JASON HIRSCHHORN: Sweet. E sobre o outro? ALUNO 18: Muito semelhante, mas em vez de S-R-C, você diria que é D-S-T. JASON HIRSCHHORN: Oo! Eu gosto disso. ALUNO 18: Apenas D-S-T. É. E, em seguida, argv, suporte aberto, 2. É. E, em seguida, em vez de w r. É. JASON HIRSCHHORN: Ótimo. Próxima par de linhas. Além disso, se alguém tem coisas a acrescentar ao linhas que fizemos, não hesite em adicione-as também. Verifique se não é NULL. Quem pode me dar o código que eu preciso satisfazer essa linha de pseudocódigo? Archer. ARCHER: Se src igual iguais NULL ou dst iguais iguais NULL, então você voltar - JASON HIRSCHHORN: O quê? ARCHER: Return 2? JASON HIRSCHHORN: Return 2. Então, se parêntese aberto src igual é igual a NULL, ou - seja lá o que thing's - cachimbo? Cachimbo? Vamos chamá-lo de tubulação. Pipe, cachimbo, dst iguais iguais NULL, o retorno 2. OK? Até que nós estamos fora de bytes - nós meio que pulou essa etapa de a parte pseudocódigo para ir para aqui. Mas até que estamos fora de bytes - o que isso parece? Que tipo de estrutura C - mas eu não usar a estrutura da palavra, porque nós vamos começar a usar que em outros casos - mas ferramenta C é que o som como? ALUNO 19: Um laço. JASON HIRSCHHORN: Um loop. Soa como um loop. Então, quem pode me dar a primeira linha do código de loop aqui? Você também pode escolher o tipo de loop que você quer, se você me der esta linha de código. Existem três tipos. Você começa a escolher. Gostaria de sugerir um desses. Avi. Qual deles você quer? AVI: FOR. JASON HIRSCHHORN: FOR. AVI: int i é igual a zero. JASON HIRSCHHORN: OK. AVI: Esta parte eu não tenho certeza. Mas i é menos do que o tamanho de fonte de estrela? Eu não tenho certeza disso. JASON HIRSCHHORN: OK. AVI: Porque você quer a tamanho de um arquivo, certo? JASON HIRSCHHORN: Então, isso provavelmente não vai dá-nos o tamanho do real arquivo em bytes. Então o que mais poderíamos fazer? O que é um outro tipo de loop? Ou devemos ficar com o loop FOR? ALUNO 20: Você poderia fazer um loop WHILE? E então, o que você faria se you'd - porque temos um char * para o arquivo. Então, se nós apenas continuar incrementando que até que gostaria de encontrar o caractere NULL em o fim de tudo? Ou não, é que não como os arquivos de trabalho? JASON HIRSCHHORN: Então podemos manter incrementando o char * até encontrarmos o NULL - ALUNO 20: Essencialmente continuar caractere por caractere até chegarmos o fim do ficheiro. JASON HIRSCHHORN: sim. Então é isso que nós queremos fazer. Queremos manter a leitura, caráter pela personagem, até chegarmos ao o fim do ficheiro. ALUNO 20: Yeah. Encontre - o que é o fim ou sinal de parada no final de um ficheiro de texto. JASON HIRSCHHORN: OK. Assim, quando chegar ao fim do arquivo - como sabemos que chegamos o fim de um arquivo? Se eu estou chamando - então vamos dar um passo atrás. O que é uma função? Vamos para essa linha aqui. Leia a partir do arquivo de origem. Quem pode me dar essa linha de código? ALUNO 21: fscanf? JASON HIRSCHHORN: fscanf. OK. E se eu quiser ler, muito especificamente, um byte? ALUNO 21: Eu não sei. JASON HIRSCHHORN: OK. Mesmo mais simples do que fscanf - o que é um - Eu quero ler a partir de um arquivo de origem? Ler de um arquivo de origem. O que é uma função - sim. ALUNO 22: É fread? JASON HIRSCHHORN: Fread. Eu acho que vamos ficar com que um por agora. Que tipo de argumentos fread não tomar? ALUNO 22: Provavelmente o tipo de arquivo, e localização no arquivo? JASON HIRSCHHORN: O que posso escrever aqui para descobrir qual o tipo de argumentos fread leva? ESTUDANTES múltiplos: Homem fread. JASON HIRSCHHORN: Homem fread e fwrite. Parece que eles saem juntos. Então fread leva quantos argumentos? ALUNO 23: Quatro. JASON HIRSCHHORN: Demora quatro argumentos. É preciso um ponteiro, um tamanho, e que coisa, o que é estranho, e alguns arquivos. OK? Vamos ler sobre isso aqui. "A função fread lê n memb elementos de dados, cada um de tamanho bytes de comprimento, a partir do fluxo apontado por transmitir, armazenando-os no local dada pelo ponteiro ". Então, quatro argumentos. Por que não posso simplesmente copiar isso, e colá-lo aqui. OK. Então, quem pode começar a preencher estes argumentos para mim? Avi. AVI: Retire o vazio. Coloque apenas src. Retire do ponteiro e da estrela. Coloque src. Então - JASON HIRSCHHORN: Então eu vou parar você lá, porque isso é incorreto. Você está certo com o src, mas onde deve src ir? [VOZES interpondo] JASON HIRSCHHORN: deve passar por cima aqui. Esse é o src - nosso src é um tipo. Vamos dar uma olhada aqui. Isso é pedir para um tipo FILE *, nós na verdade, normalmente vê-los assim. Então, isso é pedir para um argumento de tipo de arquivo * chamado córrego que é src. OK? O tamanho das coisas fazer queremos ler? Eu te dei isso no descrição do problema. ALUNO 24: Um byte de cada vez. JASON HIRSCHHORN: Um byte. Qual é o tamanho de um byte? Seu tamanho é em bytes, então o que Eu posso colocar ali? ALUNO 25: Uma. JASON HIRSCHHORN: Uma. Certo. O seu tamanho é de byte unidade, então 1 é um byte. Quantos eu quero ler de uma vez. ALUNO 26: One? JASON HIRSCHHORN: Uma coisa. Quero ler uma coisa do tamanho 1, uma mordida de cada vez. E onde é que eu colocá-lo, uma vez que eu ler? ALUNO 27: Destino? JASON HIRSCHHORN: Então, eu não posso colocar lo em linha reta em destino. ALUNO 28: Você vai colocar lo em um terceiro ponteiro? ALUNO 27: para o destino. JASON HIRSCHHORN: OK. É. ALUNO 29: Você pode declarar algo a actuar como um armazenamento temporário anteriormente. JASON HIRSCHHORN: OK. Dá-me isso. ALUNO 29: Outro arquivo ponteiro, talvez? JASON HIRSCHHORN: OK. Portanto, esta é estrela vazio - é um tipo void estrela, para que ele não tem que ser um ponteiro de arquivo. E se eu estou lendo um byte, onde seria um bom lugar para armazenar um byte? ALUNO 29: Uma matriz? JASON HIRSCHHORN: Uma matriz. OK. E o que mais é algo que é apenas o tamanho de um byte? ALUNO 30: A char *? ALUNO 29: Yeah. JASON HIRSCHHORN: Um char * não é um byte. ALUNO 29: um char. JASON HIRSCHHORN: Um char é um byte. Certo? Então, vamos chamar este buffer é um genérico nome usado para essas coisas para guardar algo temporariamente. Então eu criar um buffer. Certo? Mas é preciso ser um void *. Então, talvez você está certo, que ele deve ser um tampão de tamanho 0. Então, ele armazena um - direita. Porque isso aqui - caractere buffer é um personagem, mas isso leva um void * - um ponteiro. Então, eu poderia fazer isso e agora buffer é um ponteiro. O que mais eu poderia fazer? ALUNO 31: Coloque uma estrela ao lado para char. JASON HIRSCHHORN: eu poderia tê-lo criado char *. OK. O que é outra coisa que eu poderia fazer? Ou vamos com este. Char * buffer, então o que posso colocar aqui? ALUNO 31: Buffer. JASON HIRSCHHORN: Buffer. Buffer é um ponteiro para um char. E nesse local, estamos colocando um byte de algo que li. É. Avi. AVI: Só uma pergunta rápida. Você quer malloc tampão? JASON HIRSCHHORN: Quem pode responder a essa pergunta? ALUNO 32: Bem, não realmente ponto para nada agora, então - JASON HIRSCHHORN: Mas fazer queremos malloc isso? ALUNO 32: Se você tivesse que fazê-lo que maneira, eu acho, sim, porque você precisa algum lugar para ele para apontar para. JASON HIRSCHHORN: Será que tem que malloc isso? ALUNO 33: Se você estiver indo para usá-lo fora do loop. JASON HIRSCHHORN: Será que vamos usá-lo fora do loop? ALUNO 34: Sim. ALUNO 35: Espere. Queremos declará-la no circuito para além? JASON HIRSCHHORN: Então eu acho que nós temos alguns pseudo loop WHILE aqui que estamos tentando descobrir o que nós não tivemos ainda. Nós não precisamos de malloc-lo. Estamos operando em principal, vai apenas para ser usado dentro deste loop. Ele não necessita de existir fora deste. Assim, ele pode ser uma variável local. Você tem um ponteiro para uma variável local. ALUNO 36: Mas não é apontando para qualquer coisa. JASON HIRSCHHORN: Não, não é inicializado para nada. Mas nós não vamos usá-lo também. Vamos colocar algo em que a primeira vez que usá-lo. Assim que parece OK. Então, nós não precisamos de malloc aqui. E eu acho que é OK como está. OK. Temos a linha fread. Vamos fazer a próxima linha. Se queremos gravar em um arquivo, o que é uma boa função para usar para fazer isso? ALUNO 37: fwrite? ALUNO 38: fprintf? JASON HIRSCHHORN: fprintf é um deles. O que é mais uma? ALUNO 39: fwrite. JASON HIRSCHHORN: fwrite. E, para os nossos propósitos, fwrite, que vimos aqui, é provavelmente a melhor escolha. Leva quatro argumentos também. Nishant, você pode dar me os argumentos? Nishant: curso do primeiro um ser apenas tampão. JASON HIRSCHHORN: OK. Nishant: A segunda de só vai ser 1. Terceiro vai ser 1. E o quarto vai ser dst. JASON HIRSCHHORN: Alguém tem qualquer dúvida sobre essa linha? Isso parece bom. OK. Então, agora parece que a única coisa que estamos falta - na verdade, vamos escrever esta última linha. Feche os arquivos. Quem pode concluir-nos a escrita estas duas últimas linhas? Sim. Desculpe, qual é o seu nome? LUCY: Lucy. JASON HIRSCHHORN: Lucy. LUCY: src fclose e depois fclose destino. JASON HIRSCHHORN: fclose, parêntese aberto, src, paren próximos, ponto e vírgula. E fclose - É mesmo? LUCY: Abrir parênteses, dst e, em seguida, ponto e vírgula. JASON HIRSCHHORN: Ótimo. E o que devo incluir no final? LUCY: Return 0. JASON HIRSCHHORN: Return 0. Eu tenho que? Só uma pergunta. Temos que incluir return 0? ESTUDANTES MÚLTIPLAS: Não. JASON HIRSCHHORN: Não. Principal faz isso automaticamente se você chegar ao final. Mas eu acho que é bom incluí-lo explicitamente. Especialmente quando estamos voltando outro as coisas ao longo do programa. OK. Isto é o que está faltando - Enquanto o que? Quem pode pensar em alguma - tem alguma noção do que coisas poderia entrar lá? Mesmo que seja apenas em um pseudocódigo como a linguagem? O que estamos realmente - o que queremos ir até? Sim, Lucy. LUCY: O fim do arquivo. JASON HIRSCHHORN: O fim do arquivo. Então, o que você quer dizer com o fim do arquivo? LUCY: Quando chegar ao final do arquivo, pare. JASON HIRSCHHORN: OK. Assim, uma vez chegamos ao final do arquivo. Como sabemos quando chegamos o fim do ficheiro? ALUNO 40: Eu acho tampão será definido como NULL. ALUNO 41: Buffer é declarado dentro do loop. JASON HIRSCHHORN: Então você acha buffer será definido como NULL. Por que o buffer ser definido como NULL? ALUNO 40: Porque quando você fread, você está tentando colocar nada em buffer. JASON HIRSCHHORN: OK. Então você está pensando fread - quando chegamos ao final do arquivo, o que é fread vai fazer? Acho que essa é a questão temos de descobrir. O que fread fazer? Será que colocar NULL no buffer, ou ele faz outra coisa? Como podemos descobrir o que ele faz? ALUNO 42: Homem. JASON HIRSCHHORN: Homem. Então, vamos olhar para aqui. Valor de retorno. Em caso de sucesso, fread e fwrite retornar a número de itens lidos ou gravados. Este número é igual ao número de bytes transferido apenas quando o tamanho é 1. Se ocorrer um erro, ou o fim do arquivo é alcançado, o valor de retorno é um contagem de itens curto ou 0. Assim, para os nossos propósitos, se alcances fread No final do processo, e lê-se a partir de o fim do arquivo, não há mais nada de ler, o que é que vai voltar? ALUNO 43: Zero? JASON HIRSCHHORN: O quê? ALUNO 43: Zero? JASON HIRSCHHORN: Zero. Vai retornar zero. Então, nós sabemos que fread, quando temos atingiu o fim do ficheiro, vai para voltar a zero. Como podemos usar isso a nosso favor? AVI: Você pode declarar uma variável fora do circuito de chamada de cheque. Se a verificação é igual a - por enquanto - um. JASON HIRSCHHORN: OK. AVI: E então você pode colocar um IF declaração logo após fread dizendo que se fread é igual a zero - nenhum. JASON HIRSCHHORN: Quem pode ajudar Avi fora? AVI: Qual é o valor retornado por fread? JASON HIRSCHHORN: Nós só passou por cima disso. AVI: Como você representá-lo? JASON HIRSCHHORN: Então ele retorna - vamos procurar por aqui - ele retorna um size_t, que é essencialmente um inteiro. Então, ele retorna um inteiro. E no nosso caso, será retornar 1 ou 0 - 1 se ler uma coisa - um byte, e 0, se tiver chegado ao fim. Então, se fread - É mesmo? ALUNO 45: Você não pode simplesmente colocar o pleno fread (tampão, 1, 1, src) na while? JASON HIRSCHHORN: Então você propõe fazendo isso para lá? [VOZES interpondo] JASON HIRSCHHORN: Espere um pouco. Então, nós estamos livrando disso. Então, você está propondo colocar em fread lá? O que devemos também mover se você quer fazer isso? ALUNO 45: O buffer de fora. JASON HIRSCHHORN: Devemos também mover este aqui. ALUNO 45: Mas faz isso constantemente movê-lo para a frente? [VOZES interpondo] JASON HIRSCHHORN: OK. Então é isso que Okshar proposto. Nós criamos o nosso buffer. Nós ENQUANTO fread, então nós fwrite. Pensa sobre isso? ALUNO 46: Minha única pergunta é: seria ele realmente executar o comando fread? JASON HIRSCHHORN: Ótima pergunta. Quando você está colocando uma chamada de função dentro de uma condição, de que faz chamada de função executar? Nós já vimos exemplos disso antes. Certo? ALUNO 46: OK. É. Então ele faz executar. JASON HIRSCHHORN: Temos visto coisas assim antes, onde temos uma chamada de função dentro de uma condição. Será que essa chamada de função executar? Sim. Portanto, a resposta é sim. Esta chamada de função será executada. Mas, novamente, é isso o que queremos? O que é uma maneira que nós poderíamos imaginar se é o que queremos? ESTUDANTES múltiplos: Execute-o? JASON HIRSCHHORN: Podemos executá-lo. Mas antes de fazer isso, poderíamos também raciocinar por isso. Se - dizer que temos um byte em nossa arquivo, nós vamos chegar até aqui, nós vamos chegar a este código. Este será executado. fread retornará um byte e armazená-lo no buffer. E isso vai avaliar para 1, direito, depois que ele retorna 1. Assim, enquanto a 1. Isso significa que o código dentro o loop WHILE será executado? ALUNO 47: Yeah. É verdade. JASON HIRSCHHORN: sim. 1 é verdadeiro. Não é 0. Assim, o código aqui dentro será executado. Então vamos escrever isso. Nós vamos voltar a este linha mais uma vez. Agora temos - estamos no final do nosso arquivo. Lemos a partir do final do nosso arquivo, porque só tinha um byte nela. Fread retorna 0, lojas algo em tampão. Eu honestamente não sei o que ele armazena em buffer. Nós provavelmente poderia olhar para cima para ver o que ele faz. Que eu sinceramente não sei. Nós não sabemos, quem se importa o que ele armazena em tampão? Mas isso não retornar 0. E será que, enquanto 0 executar? ENQUANTO 0 não será executado. Então vamos passar por aqui. Então, vamos começar um show de mãos, se esta é o código que deve ser executado, ou se deve fazer alterações em primeiro lugar. Então, se você pensa - você tem que votar. Se você acha que devemos executar este código como é, por favor, levante a mão. OK. Há um - você tem uma dúvida, preocupação? É. ALUNO 48: Depois de passarmos tampão fora do loop, nós tem que malloc isso? JASON HIRSCHHORN: Ótima pergunta. Depois de passarmos tampão fora do loop, temos que malloc isso? Esta é uma questão de escopo. Se inicializar o buffer fora deste ciclo, vai existir dentro do ciclo? ESTUDANTES múltiplos: Sim. JASON HIRSCHHORN: sim. O seu âmbito de aplicação abrange dentro do loop, e, realmente, qualquer coisa abaixo dele dentro deste código, incluindo a as coisas aqui dentro. Então, nós não precisamos malloc-lo. É uma variável local, e seu escopo ainda inclui o loop. ALUNO 49: Será que precisamos para libertá-la? JASON HIRSCHHORN: Será que precisa buffer livre? ALUNO 49: Sim, se não o fizermos malloc. JASON HIRSCHHORN: Será que precisa buffer livre? Nós não. Novamente, é uma variável local, de modo que não precisamos para libertá-la. OK. Vamos ver o que acontece. Por isso, é não inicializado. Isso foi o que algo que Marcus proposto anteriormente. Portanto, temos que o erro, tampão variável é não inicializado quando usados ​​aqui. Como podemos resolver isso? ALUNO 50: malloc isso? ALUNO 51: Igual a NULL? ALUNO 52: Diga tampão é igual a NULL. JASON HIRSCHHORN: OK. Parece bom. Temos agora. Vamos criar algo para tentar copiar. Então, nós temos o nosso arquivo de texto. Como podemos executar este programa? É. ALUNO 53: Você pode fazer dot cortar cp, teste.txt. E então você pode nomear um outro arquivo que vai armazenar a. JASON HIRSCHHORN: OK. Vamos chamá-lo out.txt. Legal? Seg culpa. Reflexões sobre a falha seg? Isso é ótimo. Como podemos descobrir onde a culpa é seg? O quê? ALUNO 54: Gdb. JASON HIRSCHHORN: Gdb. Corremos gdb escrevendo barra gdb ponto, o nome do nosso programa. Não há argumentos de linha de comando lá. Vamos definir um ponto de interrupção na principal. Se eu quiser começar gdb, o que eu faço? ALUNO 55: R. JASON HIRSCHHORN: R. E depois? ALUNO 55: Os argumentos? Jason HIRSCHHORN: Em seguida, o argumentos de linha de comando. Vamos examinar. N é só me levando linha por linha. Eu estou indo para ir até Recebo minha culpa seg. Não é minha culpa seg. Parece que fread causado minha culpa seg. Eu sei fread causada por minha culpa seg, porque essa era a linha que apenas executado. E a única coisa que era acontecendo nessa linha - duas coisas foram acontecendo. Fread estava indo, e depois fomos fazendo alguns testes WHILE. Eu estou disposto a apostar que o WHILE verificação não estava causando minha culpa seg. Muito provavelmente, fread foi causando minha culpa seg. Eu também vejo alguma coisa aqui, memcopy. Cópia da memória. Soa como se movendo de memória um local para o outro. Soa como algo que iria acontecer em fread, talvez alguma memória mover daqui até aqui. Vamos passar por isso de novo. Como faço para começar de novo e executá-lo novamente? É. ALUNO 56: Você precisa colocar um e comercial antes de tampão? JASON HIRSCHHORN: Então e comercial antes buffer de me dar o endereço de buffer, que é um char *. Vamos percorrer este mais uma vez. Como faço para correr com ele mais uma vez? ALUNO 57: você pode apenas digite correr novamente? JASON HIRSCHHORN: Basta digitar correr novamente. Então, nós não vamos executar esta linha. Então buffer é um ponteiro NULL. Corrija? Ele está apontando para - vamos ver. Se nós temos a nossa - tirar uma foto rápida deste. Toda a gente pode ver se Eu escrevo aqui? Então, na pilha, temos um local de variável e é chamado de buffer, e é um ponteiro para um char. O endereço é esse caractere no? ALUNO 58: 0x0. JASON HIRSCHHORN: Certo. Isso é o que isso é. Em aqui, dentro de buffer, é armazenado 0x0. Isso é o que nós temos - o configuração que temos agora. Então esta linha, fread, coloca algo da fonte onde? Dentro dessa caixa ou esta caixa? Que caixa? Caixa ou caixa direita e esquerda? Esta caixa da direita. Ele segue o ponteiro, e coloca-lo aqui. Quando tentamos e memória toque em localização 0, o que é que vamos chegar? Uma falha de segmentação. Esse é o erro que temos agora. É. ALUNO 59: Você não tem colocar tampão estrela? Ou não? Para fread? JASON HIRSCHHORN: Então fread leva um ponteiro. Assim, ele passa em tampão. E então ele vai de-referência que em algum lugar dentro fread. Mas, novamente, nós vimos, é preciso um ponteiro. Nós não precisamos passá-lo tampão estrela. Isso seria passar que o que está aqui. E que, provavelmente, dar-nos um erro porque estamos des referenciando-lo. Certo? Quando de-referência este ponteiro, quando tentamos acessar este local, estamos recebendo um erro - nossa falha de segmentação. So - oops. Nós vamos sair de gdb. Nossa linha - o nosso problema - é certo aqui nesta linha. E é um problema, porque desta linha. Como podemos criar uma caixa que está acessível em fread. Certo? Precisamos criar uma caixa que é uma byte grande, o tamanho de um caracter. Mas precisamos que a caixa para ser acessível quando esta função é executada. Então, onde - sim. Alguma ideia? ALUNO 60: Basta configurá-lo como qualquer de caracteres aleatórios. Basta fazer iguais char buffer o personagem. E então, quando você tiver buffer de lá - JASON HIRSCHHORN: Espere. Char tampão? Então, nenhuma estrela? ALUNO 60: Yeah. Retire a estrela. Igual a um personagem aleatório. JASON HIRSCHHORN: OK. Então me dê um. ALUNO 60: Como um ou algo assim. E então quando você tem tampão lá, você usa um - ALUNO 61: Star? Ah, não, o E comercial. ALUNO 60: Use o comercial. JASON HIRSCHHORN: OK. E o que dizer em fwrite? ALUNO 60: Use o comercial novamente. JASON HIRSCHHORN: Tudo bem. Portanto, sua idéia é, criamos um char e colocar algo nela, e, em seguida, escrever para esse caractere. ALUNO 60: Yeah. JASON HIRSCHHORN: O que que as pessoas pensam? ALUNO 62: É complicado. JASON HIRSCHHORN: OK. Vamos tirá-la. Então, desta vez, eu vou chamar isso de vermelho na pilha aqui, e então nós terá - ooh! Desculpe. Então, desta vez nós temos uma coisa chamada tampão, e é na pilha. Corrija? E nós estamos salvando em uma, inicialmente. Então nós temos o nosso apelo para fread. O fread faz é que leva um byte de nosso arquivo e coloca-lo em algum lugar. Ela coloca-lo em qualquer que seja o coisa está apontando. Bem, antes que nós tivemos este endereço - 0x0. Agora, o endereço que nós temos? ALUNO 63: Seja qual for tampão endereço é. JASON HIRSCHHORN: Whatever tampão endereço é. Ele provavelmente vai ser algo parecido. Provavelmente vai começar com um b e um f, e depois tem outros seis dígitos hexadecimais. Não importa. Alguns endereço. E nós estamos passando o endereço dentro E nós vamos colocar o nosso único coisa byte naquele endereço. Então, nós vamos colocar o nosso único byte coisa aqui dentro. E então vamos escrever a partir de o que é sempre aqui dentro. Alguém tem alguma dúvida sobre isso? Quem pensa que este código vai funcionar? Levante a mão se você acha este código vai funcionar. Você tem que tomar uma posição. E quem pensa que esse código não vai funcionar? Levante sua mão. Todo mundo deve ser levantando a mão. OK. Michael, onde você está de pé? MICHAEL: Eu não posso decidir. Kind of no meio. JASON HIRSCHHORN: Você é no meio. Escolha um. MICHAEL: Eu vou ter fé e dizer que vai funcionar. JASON HIRSCHHORN: OK. Você vai ter fé e dizem que funciona? O que aconteceu? [VOZES interpondo] JASON HIRSCHHORN: Sem falha seg. Como podemos verificar se duas coisas são iguais? Dois arquivos são iguais. ALUNO 64: Dif. JASON HIRSCHHORN: Dif. Cheques Dif para as diferenças entre dois arquivos, e se ele retorna nada, eles são idênticos. E se abrir, nós temos o nosso arquivo. Então essa foi a solução correta. Vamos olhar para trás, mais uma vez. Na verdade, nem sequer necessário inicializar ele. Ele provavelmente ficaria um pouco mais limpo, se você não colocou algo aleatório lá. O ponto é, você precisava criar algum espaço para guardar algo de fread e tomar alguma coisa de fwrite. E aquela coisa tinha de ser um local de variável na pilha - você poderia ter malloc algum espaço. Então, na verdade, poderia ter malloc escrito aqui, e que teria funcionado. E, então, teria sido o armazenamento nossas coisas em algum lugar na pilha. Mas este é, na verdade, provavelmente, a solução mais elegante. Basta criar algum espaço na pilha por estas coisas para ir. Eu teria dois outros comentários. Se você tivesse que tomar sua vez nesta, e em seguida, se marcou com isso, meus comentários seria da seguinte forma. Estes 1 está aqui, para mim, olhe como números mágicos. Este 1, em termos de fread, faz sentido. Esse é o número de coisas para ler ou escrever. Mas este aqui deveria provavelmente ser outra coisa. Então, o que é uma solução? ALUNO 65: Tamanho de byte. JASON HIRSCHHORN: Assim? ALUNO 65: Tamanho de carvão. JASON HIRSCHHORN: Tamanho de carvão. Sim, byte não é um tipo. Assim, o tamanho das obras de caracteres. Poderíamos tem, na parte superior da o nosso código, # definido que. Chamado algo BYTE e é realmente um char. Na verdade, uma abordagem ainda melhor pode ter sido isso - uint. Alguém sabe o que é isso? Desculpe. Tenho-o para trás. Espere, não. Qual a maneira ele vai? Alguém sabe o que é isso? É. ALUNO 67: Suposto para ajudar a padronizar através de sistemas de coisas que ter - como inteiros sem sinal que tem 8 bytes? JASON HIRSCHHORN: Isso é exatamente correto. Em máquinas diferentes, o tamanho de um char - geralmente não um char. Chars são geralmente um byte. Mas o tamanho de outros tipos de dados são tamanhos diferentes em uma máquina de 32-bit contra uma máquina de 64 bits. Um uint8_t é sempre 8 bits - sempre um byte. E eu preciso incluir esse arquivo de cabeçalho int padrão. Então, agora, este provavelmente teria sido a melhor maneira de escrever este código. Então, para me livrar dos números mágicos. E eu também tenho um mais lógico tipo de buffer. Não é simplesmente um carvão animal, que é um byte, que é o que esperamos que seja. E aqui, nós temos realmente sido um pouco mais robusto. Nós não estamos chamando isso de char, que - talvez, quem sabe - pode ser um diferente tamanho em diferentes máquinas. Na verdade, estamos dizendo que isso é exatamente um byte, sempre, não importa o quê. E se olharmos aqui, fazemos cp. Uh-oh. O que aconteceu? ALUNO 68: Pode ser trocada. JASON HIRSCHHORN: O quê? ALUNO 69: É? ALUNO 70: Você não fez defini-lo como um tipo. ALUNO 71: mas deve ser definidos na norma. ALUNO 72: O que está acontecendo? ALUNO 73: Deve definir se todas as tampas? JASON HIRSCHHORN: Então não é # define. Na verdade, neste caso, eu sou vai usar typedef. Porque nós estamos usando-o como um tipo em um único local. Portanto, neste caso, nós realmente queremos typedef que estamos imprimindo um novo tipo byte, e é, essencialmente, este. É um pouco diferente do que # define. E agora, o nosso código funciona perfeitamente. Então, mais uma vez, # define leva alguma coisa, substitui-lo em todos os lugares com a outra coisa. É apenas uma macro - taquigrafia para se livrar dos números mágicos. Mas neste caso, porque somos usando-a como um tipo - aqui - para que isso funcione, precisamos typedef para tudo o que é byte. E nós estamos definindo-o aqui. Não é um struct, é realmente apenas um inteiro sem sinal. É um byte. Este código estará disponível on-line, e vocês todos devem tê-lo agora. Então nós temos - perfeito - 13 minutos à esquerda para entrar problema ao longo do jogo 5. Eu quero caminhar através copy.c juntos, e depois vamos falar brevemente sobre as outras partes do conjunto de problemas. Então deixe-me puxar para cima copy.c. E o mais legal é que você realmente já escreveu um monte de este código. O código que escrevemos literalmente saiu daqui quando eu era escrevendo isso por conta própria. Mas isso é copy.c, constitui a base para as duas primeiras partes da o conjunto de problema para whodunit.c, que você precisa escrever, e resize.c. Recover.c, que é a terceira e última parte do conjunto de problemas, não é baseado fora deste arquivo. Você está indo a necessidade de escrever esse arquivo, nós damos-lhe um modelo para que arquivo, mas não tem nada a ver com copy.c. Mas porque copy.c é a base para as duas primeiras partes, nós vamos de atravessá-la agora, então você tem uma boa noção do que ele faz. E os comentários dar um pouco dele. Nós já escrevemos um pouco isso. Em primeiro lugar, estamos certificando-se temos três argumentos. Em seguida, vamos lembrar o nome do arquivo. Então, nós saltamos essa etapa quando codificamos nossa coisa - quando nosso cp. Mas aqui, eles estão fazendo um pouco mais limpo. Eles estão verificando se ambos os arquivos são bons, em Além de abri-los. Nós escrevemos todo este código só agora, por isso estou não vou me debruçar sobre este código. Em seguida é alguma coisa que é específico para os tipos de arquivos que estamos usando, o que são arquivos de bitmap. Arquivos de bitmap tem alguns metadados que lhes estão associados. Assim, o primeiro par de bytes informá-lo sobre o arquivo. Eles não são as cores da o pixel na referida imagem. Dizem-lhe sobre o arquivo. E se você ler o conjunto de problemas, você terá muito mais informação sobre quais os tipos de estruturas de metadados estão incluídos com bitmaps. Mas é por isso que temos este primeiro conjunto de - esse código aqui. Estamos lendo os metadados - dois pedaços de metadados - o arquivo cabeçalho eo cabeçalho info. E estamos verificando algumas partes dele para certifique-se que é um arquivo de bitmap verdadeiro antes de continuar. E mais uma vez, estes são detalhes que Não é necessário entrar em agora. Se você ler o conjunto de problemas, você vai entender isso. Para encurtar a história, estes são apenas dizendo, este é um arquivo de bitmap e confirmando que. Em seguida, nós estamos escrevendo os para o arquivo para fora. Vemos que aqui. Estamos escrevendo para o ponteiro para fora. Em seguida, nós estamos determinando estofamento. Então, novamente, como é particularidade com um arquivo de bitmap, algumas linhas de incluir preenchimento no final. E se você ler o conjunto de problemas, você vai aprender mais sobre o preenchimento. Esta é a fórmula para determinar o preenchimento. Importante lembrar - quando você alterar o tamanho de um bitmap arquivo, o enchimento alterações. Quando você muda o tamanho de um arquivo, o enchimento alterações. Isso nunca vai ser superior a 3 - vai ser de 0 a 3, inclusive. Mas quando você alterar o tamanho da alguma coisa, as mudanças de preenchimento. Se eu tiver apenas um pixel nessa linha, eu precisa de três bytes de preenchimento, pois cada linha tem que ser múltiplos de quatro bytes em um arquivo de bitmap. Mas se eu dobrá-lo, para ir de um pixel de dois pixels, cada um dos quais, vamos dizer, é um byte, então eu preciso dois bytes de preenchimento para fazer que igual a quatro. Então, quando eu alterar o tamanho de alguma coisa, Eu preciso alterar a quantidade de preenchimento que eu tenho. Isso faz sentido para todos? Em seguida, iterar sobre cada linha, ou através de todas as linhas. E, então, iterar cada coluna em cada linha. Estamos tratando este como bitmap uma grade, como temos tratado a placa em 15. Como nós tratamos os tijolos quando nós impresso-los na tela. Uma grade de linhas e colunas. Então - vimos isso. Nós, na verdade, apenas codificado esta. Criamos algumas armazenamento temporário. Lemos ali, e, em seguida, nós escrevê-lo. Este é exatamente o que nós fizemos. Em seguida, porque eu disse que cada linha termina em algum estofamento, nós pular que estofamento - o antigo estofamento. E, então, adicioná-lo de volta. Neste caso, estamos criando exatamente o mesmo arquivo. Estamos apenas copiá-lo. Portanto, esta linha é meio bobo. Poderíamos literalmente colocar o preenchimento dentro Mas se você mudar o tamanho do arquivo, você ainda quer essa linha? Então, se nós alterar o tamanho de um arquivo, nós ainda quero pular sobre o antigo estofamento? ALUNO 74: Sim. JASON HIRSCHHORN: Então, o que fazemos. Porque este, mais uma vez, ofertas com o arquivo de origem. Nós não nos importamos sobre o preenchimento do arquivo de origem. Queremos ir para a próxima linha. Mas não basta colocar de volta o velho quantidade de preenchimento. Precisamos colocar de volta o nova quantidade de preenchimento. Então, quando nós estamos mudando o tamanho de uma arquivo, nós ainda queremos pular o preenchimento no arquivo de idade - o que estamos lendo em partir. Mas o que estamos escrevendo para, vamos a necessidade de colocar de volta um pouco diferente número de preenchimento que nós determinado. É. ALUNO 75: A ordem dos dois linhas não importa, certo? Porque você está lidando arquivos diferentes. JASON HIRSCHHORN: Exatamente. A ordem destas duas linhas não importa. Nós escrevemos essa linha. Este é aqui para o arquivo estamos escrevendo. Isso é importante, por isso temos a quantidade certa de estofamento. Isso tem que lidar com o arquivo no formato. Queremos pular sobre o preenchimento. Não quero ler - se estamos a ler um byte de cada vez, nós não se preocupam com esses bytes de preenchimento. Queremos passar para a próxima linha. Finalmente, assim como Lucy deu para nós, vamos fechar os arquivos e retornar 0. Portanto, esta é copy.c. E nós realmente escreveu - que passou a maior parte de seção escrevendo isso, essencialmente. Você fez isso. Portanto, esperamos que você tenha um bom senso do que está acontecendo aqui. A grande diferença, sinceramente, é apenas Nesta primeira parte que lida com peculiaridades de arquivos de bitmap. Então, eu tenho como meu próximo slide, o que precisamos fazer? Bem, vamos pensar em romance policial. E para alguém que ler o conjunto de problemas, o que é que vamos precisa fazer a whodunit? Simply. Aleja. ALEJA: Você pode tirar a parte de cada pixel, que indica a vermelho. E então - espécie de? JASON HIRSCHHORN: OK. Então, retire a parte de cada um pixel que indica vermelho. É perto, mas não tudo isso. ALUNO 76: Bem, não há maneiras diferentes de fazê-lo. JASON HIRSCHHORN: OK. Dê-me uma maneira. ALUNO 76: Retire todo o vermelho, e em seguida, destacar o azul eo verde. JASON HIRSCHHORN: OK. Assim, dado estes dois aspectos - parece que nós dar-lhe um pixel, ele tem um nível de vermelho, azul e verde. Queremos mudar os níveis relativos de o vermelho, azul e verde, dependendo em que o pixel. Onde neste código devemos mudar o parente vermelho, azul e verde os níveis de um dado pixel. Depois que o li - antes de escrevê-lo? Dê-me o número da linha. ESTUDANTES múltiplos: 83. JASON HIRSCHHORN: 83. Então aqui. Para whodunit, o código que você precisa para write todos devem ir para a direita lá. E isso é o único código você precisa escrever. Porque, como ouvimos, tudo que você precisa fazer é mudar estes azul relativa, níveis de vermelho, verde e de cada pixel. Você lê-lo, e agora você está indo para escrevê-lo. Como faço para que - se eu tenho essa coisa chamado triplo, bem aqui, e é de digite RGBTRIPLE - bem, se olhássemos em bmp.h, o que é RGBTRIPLE? ALUNO 77: É um struct. JASON HIRSCHHORN: RGBTRIPLE é um struct. Vemos que bem aqui. E assim se eu queria acesso, por exemplo, o nível vermelho da estrutura, como faço acessar o nível vermelho desta struct? [CLASSE murmura] ALUNO 78: RGBTRIPLE.rgbtred? JASON HIRSCHHORN: Isso está correto? ALUNO 79: Deve ser triplo ponto, em vez de RGBTRIPLE ponto? JASON HIRSCHHORN: Triple. Triplo é a variável local, assim aqui, não há indicadores aqui. Então, é só usar a notação de ponto. Isso vai me dar o nível de vermelho. Se eu quero mudar isso, eu apenas definir que equivalem a algo diferente. Então, novamente, esta linha de código acessa esta variável dentro dessa estrutura, e podemos defini-lo como algo novo. Assim, para whodunit, novamente, isso é, em essência, o que precisamos fazer. Muito simples. Basta alterar alguns níveis relativos, e este é o lugar onde esse código vai. Redimensionar, por outro lado, é um pouco mais complicado. Na verdade, é provavelmente o redimensionamento mais complicada parte deste conjunto de problemas. Temos três minutos para passar por isso. Mas, novamente, nós já escrevemos a maior parte deste código, de modo que deve ser bastante familiar. Quais são algumas das coisas que queremos fazer em redimensionar, se você já leu sobre o conjunto de problemas? Se você lhes der a mim, nós pode falar sobre elas. Quais são algumas das coisas que queremos fazer? ALUNO 80: verticalmente - então você tem que horizontalmente redimensioná-la, mas verticalmente redimensioná-la também? JASON HIRSCHHORN: Então, se nós estamos dando um pixel, e queremos redimensioná-la por um fator de dois, agora precisa ser redimensionadas horizontalmente e redimensionadas verticalmente. Será que isso faz sentido? É. Então, essa é provavelmente a maior desafio. E vamos falar sobre isso em um segundo. É. ALUNO 81: A maneira que eu pensei nisso foi-lhe necessário imprimi-lo - JASON HIRSCHHORN: Espere. Não diga-nos o que você fez. Vamos falar de lógica. ALUNO 81: OK. Qual foi a pergunta? JASON HIRSCHHORN: Você só levantou sua mão. Não havia dúvida. Deixe-me apresentá-lo. Deixe-me discutir isso brevemente. Portanto, temos um pixel, nós queremos replicá-lo, tanto na horizontal como verticalmente. Assim, idealmente o que fazemos aqui é que nós ler em nossa pixels, escrevemos porém muitos dos tempos. Mas, então, nós temos o nosso truque aqui, porque então queremos saltar para o próxima linha e escrevê-lo no no início da próxima linha. Portanto, se queremos replicar tanto horizontalmente e verticalmente, o que é uma boa maneira de fazer isso - um bom embora a fazer isso? Então, nós não precisamos buscar constantemente em torno do nosso arquivo para colocar as coisas. Essa pergunta não pode ter fazia sentido, mas eu acho que um responder a ele vai ajudar. ALUNO 82: Criar uma matriz? JASON HIRSCHHORN: Então, vamos pensar de cada arquivo como uma linha. Vamos pensar em termos de linhas. Se nós temos a nossa primeira linha de nosso pequeno imagem, podemos fazer essa linha em uma grande linha de uma imagem grande, e, em seguida, replicar essa linha no entanto muitas vezes ele precisa ser replicado, ao invés de ir pixel por pixel, que fica confuso quando lidar com arquivos. Porque se nós tivemos - Eu estou ficando sem espaço. Se este é o nosso arquivo, e nós temos que um pixel lá, e queremos colocá-lo ali, ainda temos algumas coisas que necessidade de ir lá quando estamos escrever e criar o nosso novo arquivo - o nosso arquivo que é duas vezes maior. Mas é realmente difícil, com funções de arquivo para saltar em torno de novas linhas assim, e depois voltar aqui e colocar as coisas lá dentro. É quase impossível fazer alguma coisa assim, se isso faz sentido. Então, se pensarmos em termos de linhas, podemos levar a nossa linha e, em seguida, colocá-lo - replicar linhas verticalmente. E é assim que lidamos com o redimensionamento verticalmente em vez de horizontalmente. Isso era uma espécie de rápida, e um pouco confuso. Infelizmente o nosso tempo acabou. Vou ficar de fora para aqueles de vocês aqui quem tiver dúvidas sobre o conjunto de problemas, incluindo a recuperar. Então, vamos adiar por enquanto. E, novamente, se você tiver quaisquer perguntas, podemos conversar lá fora.