[Powered by Google Translate] [Semana 3] [David J. Malan - Harvard University] [Esta é CS50. - CS50.TV] Deixe-me guiar-nos na direção de onde paramos da última vez, que estava começando a pensar um pouco mais do que sobre a sintaxe e tentando pensar um pouco menos sobre todas as minúcias que leva um pouco de tempo para se aclimatar ao até agora em termos de ponto e vírgula e parênteses e chaves, para começar a tomar as coisas um pouco para um nível superior conceitual para que os problemas que agora começam a resolução sobre as próximas semanas vai envolver muito mais problemas conceituais de nível superior e um pouco menos no sintática como você obter seus pés molhados e as mãos sujas com alguma da sintaxe de nas últimas semanas. Então lembrar que na semana passada, introduziu esta noção de uma matriz. E uma matriz em Inglês pode ser descrito como o que? >> [Resposta do aluno inaudível] Desculpe? Uma coleção de? >> [Resposta do aluno inaudível] >> Ok, bom. Uma coleção de itens. Então vimos matrizes em Scratch. Se você passou a usar para pset 0 uma das listas de raspadinhas, que você pode arrastar as coisas como laranjas e bananas, um inventário de tipos, esse é o tipo de como o que é uma matriz. E, em seguida, mais tecnicamente, no contexto de um computador real, uma matriz é simplesmente um pedaço contíguo de memória. Em outras palavras, você tem um byte, então byte outro, depois outro byte, depois outro byte, e se você fosse desenhar os bytes em uma imagem, eles estariam de volta para trás, para trás, para trás. Isso é o que queremos dizer com contíguo. Por isso é o número de bytes 1, depois 2, depois 3. Isso não significa que aqui, aqui, aqui, aqui. Uma matriz é um pedaço contíguo de 0 ou mais bytes. Então, o que eles são úteis para? Lembro que tínhamos esse tipo de exemplo fictício de graus pessoas armazenamento da Quiz em um programa para calcular a média quiz para algum curso, e lembrar que nós poderíamos começar a escrever o programa, declarando um quiz1 variável. Então poderíamos ter outra variável chamada quiz2. Mas então se foram 3 questionários nesta classe, quiz4. Ou se houve um quiz semanal, seria quiz5, quiz6, quiz7. Assim, você teria todas estas variáveis ​​declaradas dentro de main ou em outro lugar no seu programa, eo problema com essa abordagem, embora seja fácil de copiar e colar, É apenas muito rapidamente torna-se difícil. Deus me livre que você realmente tem 30 testes ou 50 testes. Se é como uma escola de teste alto estilo pop diariamente, então você apenas tem uma lista ridiculamente longo de variáveis ​​sendo declarado, e isso só muito rapidamente fica fora de controle. É feio, é difícil manter, é muito mais fácil fazer um erro de digitação se você receber um número digitado errado em algum lugar no seu programa. Assim, introduziu a noção de uma matriz em vez. E lembre que implementou este programa, fazendo um pouco algo como isto. Deixe-me ir para hoje Fonte diretório segunda-feira 3 e abrir matriz, que vimos pela última vez. E mesmo que houvesse um par de novos truques C aqui, entre eles, a noção de uma constante, lembre que declarou várias bóias essencialmente usando a seguinte sintaxe: float, em seguida, o nome da variável, em seguida, utilizou-colchetes realmente pela primeira vez, eo que fizemos dentro dos colchetes foi efetivamente colocar um número. Mas em vez de colocar um número, eu coloquei esta palavra maiúscula, quizzes. E qual foi a motivação para colocar uma palavra em maiúsculas como quizzes e em seguida, usando truque linha 17 aqui para realmente dar um que número? Qual foi a motivação lá? Sim. [Resposta do aluno inaudível] >> Exatamente. Se queremos mudar esse valor 2, só temos que mudá-lo em um lugar , por considerar - Eu nem me lembro o que este programa fez exatamente, mas se você apenas roçar que você vê testes, questionários. Você vê questionários, aqui mais testes. Então, se não tivéssemos essa constante, esse uso de acentuada definir, teríamos digitado 2, depois 2, depois 2, depois 2, o que é bom. Seria também correto. Mas suponha que no próximo ano temos três questionários na CS50. Então, eu tenho que ir e atualizar o código, eu tenho que recompilar, mas o problema é se eu fizer algo estúpido, como se eu esquecer uma menção de 2 e se esqueça de ligar 3, todo o programa poderia muito bem quebrar. Então, estamos apenas pedindo para ter problemas. Assim, a noção de uma constante é tudo sobre fatoração de algum pedaço de dados, se é uma string ou um char ou uma bóia ou qualquer que seja, e declará-lo um lugar para que você possa mais facilmente mudá-lo no futuro. E também é, francamente, um pouco mais fácil de ler, porque se você só pensar nisso agora, é quizzes, ou poderíamos até mudar o nome de algo como NUMBER_OF_QUIZZES ou algo mais explícito. O código só se torna um pouco mais óbvio sobre o que ele está fazendo, e você quer saber um pouco menos que o número 2 pode acontecer a dizer. Assim, a constante não tinha nada a ver fundamentalmente com matrizes. A matriz foi introduzida por meio desses parêntesis rectos. Então, observe que na linha 23 pedimos ao usuário, "Quais foram suas contagens de questionários?" Então só temos esse laço que aparentemente pede ao usuário para suas notas. Como? Ele itera 0-2. E eu digo 2 porque questionários em todas as tampas é atualmente 2. Por isso, itera de 0 a 2 e então ela mostra Quiz # algo de alguma coisa, e, em seguida, ele usa GetFloat para obter um valor do usuário. Então, observe esta é a única outra peça nova sintaxe da última quarta-feira. Se você deseja armazenar algo em um determinado local, em que a matriz, você usar novamente os colchetes. Portanto, há um pouco de dicotomia aqui. A primeira vez que utilizar os colchetes você usá-lo para especificar como grande você quer a matriz para ser. Mas esse contexto próxima aqui onde nós novamente empregar esses colchetes significa que a matriz onde, em que você quer colocar algum valor? E a distinção aqui pode ser inferida a partir do contexto. Note-se aqui que temos um tipo de dados, em seguida, temos o nome de uma variável, em seguida, temos as nossas chaves quadrados com um número dentro, ponto e vírgula. É isso aí. Então, isso é uma declaração. É como se tivéssemos feito algo como bóia classe1; flutuador grade2; mas, novamente, isso muito rapidamente se transforma em cópia demais, colar, assim, em vez que apenas simplificada como tal, o que significa que daqui em diante, temos um grau que pode ser armazenado no suporte de 0, temos uma outra qualidade, que pode ser armazenado a braçadeira 1, mas e se eu goof e, por exemplo, o meu ciclo vai tão longe - por exemplo, I tornam este menos do que ou igual a, que recall foi a origem de um erro anterior - que na prática significa que, em algum acidental terceira iteração deste laço Eu uso o suporte de 2. Efetivamente, o que pode acontecer aqui? Desculpe? [Aluno] Vai ser substituído. >> Será que vai ser substituído? O que seria substituído? Este é literalmente dizendo substituir o que está em localização 2 com o valor de retorno de GetFloat. Mas o problema é o quão grande é a matriz, neste ponto da história? [Resposta do aluno inaudível] >> A matriz ainda é apenas de tamanho 2 porque a matriz, como qualquer outra variável, foi declarada em primeiro lugar, antes que usou, e nós aqui especificado por causa dessa constante que eu tenho duas notas que eu vou colocar. Mas lembre-se, os cientistas da computação começa a contar a partir de 0. Assim, o primeiro local em que a matriz é suporte 0. A localização próxima é 1. Essa coisa é sempre tão pouco longe demais para o lado. Portanto, em outras palavras, se eu realmente tinha essa matriz - e deixe-me ver o quão bem este coopera aqui para nós - se eu tenho uma matriz que eu simplesmente com as seguintes e eu alocado espaço para dois elementos, eu poderia tirar esta como esta na memória onde esta grande tela branca é. É apenas a RAM que eu tenho em meu computador, um giga de RAM, 2 GB de RAM, o que, mas estas duas caixas de agora individualmente, representam uma bóia, 32 bits. Então, se eu colocar um número aqui como 1.0, então eu coloquei outro número aqui como 3,2 mas depois eu suporte 2, que é como colocar algo aqui. E como a imagem sugere, não há nada lá. É uma espécie de como terra de ninguém, porque eu não perguntei o sistema operacional para me dar este quiz terceiro. Se eu queria que teste terceira, eu deveria ter tido a premeditação de pedir ao sistema operacional para ele, declarando QUIZ para não ser 2 mas em vez disso a igualar 3. Portanto, em outras palavras, a imagem que nós efetivamente ter em mãos se parece com isso aqui. Este novo é terra de ninguém. É melhor não tentar escrever valores aqui. Mas, novamente, os cientistas porque o computador contar de 0, quando falamos sobre este local na matriz, que é suposto ser a localização 0, isto é suposto ser um local, e isso não existe mesmo porque nós só perguntou o sistema operacional para dois lugares. Então, aqueles de vocês com experiência anterior em programação de outras línguas poderia saber que este não é sempre o caso com matrizes ou coisas chamados de vetores. Em vez disso, você pode apenas manter acrescentando e acrescentando e acrescentando coisas para matrizes, que, francamente, tivemos essa capacidade em Scratch e ainda assim parecem ter dado aqui porque com C você está programando muito mais explicitamente. É só você eo computador agora, e que o computador só vai fazer o que você diga a ele o que fazer. Então, se você apenas dizer-lhe para lhe dar dois flutuadores por meio de linha 22 aqui, isso é tudo que você vai receber de volta a partir do sistema operacional: espaço para 2. Assim, estão cada vez mais seus programas vai ser ocasionalmente buggy com relação a matrizes. Este é exatamente o tipo da natureza da besta em que todos nós somos falíveis, e em algum momento você irá indexar muito provavelmente além do limite da sua matriz. E isso é apenas uma maneira elegante de dizer que você foi em algo suporte e algo era muito grande de um número. Você foi além dos limites de sua matriz. Mas a cabeça agora é este. O restante deste programa realmente tem nada de fundamentalmente a ver com matrizes. É tudo apenas sobre alguns aritmética simples para médias de computação. Portanto, temos aqui neste loop for aqui primeiro uma quantia variável chamada que inicializar a 0. Então nós iterar de 0 até 2 de novo e acrescentar a essa variável soma o grau i, para suporte 0, suporte 1. E então, como você faria na escola para calcular a média, nós simplesmente tomar essa soma, dividi-lo pelo número total de questionários, e, em seguida, para uma boa medida que nós chamamos uma função aqui chamado rodada. Agora, como um aparte, o que é o negócio com este int entre parênteses na linha 34? Ele poderia ter vindo se já em seção, realmente não conversamos sobre isso formalmente aqui, mas o que é isso int em parens provavelmente fazendo? >> [Resposta do aluno inaudível] Sim, isso se refere ao vazamento ou estereótipo, o que significa assumir um tipo de dados e convertê-lo para outro. Você não pode fazer isso com todos os tipos de dados, porque às vezes seria um pouco estranho. Mas, neste caso, se o valor de retorno e volta é um flutuador porque, afinal, eu estou tendo uma bóia e dividindo-o por um número como 2, Eu vou voltar um float. Mas as pessoas da escola da classe realmente não gosta de saber que sua média foi de 93,4 porque eles vão perceber que eles nunca foram tão perto desse ponto arredondamento 95. Então, nós queremos usar int em vez de arredondar todos para o próximo int, que neste caso vai ser 94 com nenhum ponto depois dela. Então, isso é apenas um pequeno truque matemático. E nós vamos voltar a esta noção de elenco, porque vai ter implicações, se você ainda não descobriram já, por conjunto de problemas 2. Assim, uma matriz, então, você pode pensar - que vai me fazer sorrir todos os dias. Parece que este se você tirar uma foto dele, mas o fundamental é que o tamanho também é selecionado por você quando você solicitar a partir do sistema operacional. Quaisquer perguntas, então em matrizes? Sim. [Pergunta estudante inaudível] Ah, boa pergunta. A questão é o que acontece com o 0 nulo na matriz? Não existe neste contexto. Que só existe no contexto de strings, que estamos prestes a chegar a apenas em um momento. Mas, para uma matriz, como neste caso, tudo o que você recebe é o que você perguntar ao sistema operacional para. E como um aparte, para que esta não ser claro, Eu continuo dizendo que você pedir ao sistema operacional, pedir ao sistema operacional. Um sistema operacional, como você provavelmente sabe, é o Mac OS, Windows, Linux. Quando você está chamando funções como GetFloat ou você está declarando variáveis ​​como notas, no fim do dia você está efetivamente pedindo alguém para dar-lhe de que a memória porque como aspirantes a programadores não tem idéia de como realmente ter acesso físico à memória. Mas alguém faz: o sistema operacional. Assim, além de apresentar-nos com ícones e menus bonitos e pastas e similares que você vê em seu desktop, se um Mac ou PC, sistemas operacionais também fazer as coisas de baixo nível mundano, o material altamente técnico de gestão da gigabyte ou 2 gigabytes de memória que você tem, a gestão do CPU que você tem, e assim por diante. Então, quando você está escrevendo código, você está realmente ligando para o seu sistema operacional nesse sentido. Eu vou ter que minimizar isso. Tudo bem. Outras questões sobre matrizes? Não? Okay. Assim, a transição naturalmente a partir de matrizes é na verdade a um tema que é um pouco familiar. E nós olhamos sempre tão brevemente esta última vez também. Este foi um exemplo de cadeia de quarta-feira. Este exemplo de cadeia era um programa muito simples, e eu realmente simplificou-lo por um par de linhas para fins de hoje. Tudo que faz na linha 19 é obter uma string do usuário, armazena em uma variável chamada s. Então, em frente a linha 22 é aparentemente imprimir essa string um caractere por linha. Mas como ele está fazendo isso? Estamos declarando uma variável i, definindo-o igual a 0, e isso está se tornando hábito velho agora. Não tinha visto isso até quarta-feira, mas você pode tipo de inferir de seu nome strlen retorna apenas que quando dado s? O comprimento da corda. Então, se eu passar uma corda, citação-unquote DAVID, é esperançosamente vai voltar para mim o número 5 porque de Davi. Então esse é o seu propósito na vida é ter uma string, se codificado por você ou neste caso, conectado como uma variável, como um argumento, e ele descobre que o comprimento de corda que é. Então aqui agora estamos emprestando alguma notação do exemplo questionário anterior. Isto não tem nada a ver com carros alegóricos, não tem nada a ver com quizzes, mas acontece que a pequena mentira que estamos dizendo desde a semana 1 é que uma seqüência realmente não existe em C. Uma seqüência no final do dia é realmente apenas uma matriz. É uma matriz de bytes, assim byte, byte, byte, byte, que recall é apenas 8 bits, assim pedaço de memória, pedaço da memória, pedaço da memória, pedaço da memória. E o meio pelo qual uma string é implementado é colocando o primeiro caractere aqui, então aqui, então aqui, então aqui, volta para trás para trás na memória do computador. Então, se você queria para soletrar uma palavra como OLÁ, você iria colocar um personagem H, E depois, então L então L, em seguida, O - 5 caracteres no total - em algum lugar na memória RAM do seu computador. Mas o detalhe chave aqui é que eles vão voltar para trás, para trás, para trás, ao lado um do outro. Quando quando digo s [i], o que em Inglês é esta a dar-me? O que s [i] constituem, neste caso? Sim. [Aluno] O personagem om na cadeia. >> Exatamente. O personagem om na cadeia. Agora, eu vai começar em 0 como por minha loop for aqui, mas isso é bom porque tudo começa a contar a partir de 0. Então s [0] vai representar a letra H em uma palavra como OLÁ, s [1] vai representar uma carta como E em uma palavra como OLÁ, e assim por diante. E o que parecem estar fazendo em cada iteração deste laço é armazenar temporariamente o personagem om em uma variável chamada c, que é apenas um char, e depois vamos imprimir c de modo que, no final do dia, o que este programa faz é o seguinte. Se eu ir para o diretório de origem e eu faço string1 e eu ir em frente e correr string1, e então eu digitar uma palavra como OLÁ, Enter, tudo que faz é imprimir esse personagem um de cada vez. Portanto, há uma oportunidade para o refinamento aqui. Eu sou do tipo de fazer mais trabalho, mesmo que seja mais claro talvez desta forma, que o necessário. Que linha de código aqui posso jogar fora provavelmente por completo? Sim. Linha 24. Na linha 24 eu estou declarando uma variável c. Eu estou armazenando o caráter i de s na mesma, mas então eu estou usando c aqui. Então, eu estou usando c, então eu sinto que não pode apenas jogar linha 24 de distância. [Comentário do estudante inaudível] >> Exatamente. Assim, quando se trata de falar sobre a concepção de programas, perceber isso ligeira simplificação do código, que é tão legível, mas percebe que está é apenas uma variável, seu tipo de dados é um array, então s [i] está indo só para imediatamente voltar para você o personagem om em que seqüência. E se você quiser imprimi-lo, tudo bem. Você apenas tem que usar% c porque você não estiver imprimindo uma string, você estiver imprimindo um caractere em uma seqüência, e isso também tem o efeito de imprimir o caráter i. E lembro que a única diferença realmente da semana passada com o uso de printf é que, enquanto nas últimas semanas que iria fazer algo super simples como espaço reservado% s então o nome de uma seqüência aqui, agora estamos mergulhando em um pouco mais debaixo do capô e dizendo: não imprimir a string; imprimir o único personagem nele. Então nós podemos fazer algo um pouco diferente aqui porque há uma outra - não bug porque este programa é certo, mas eu estou fazendo algo estúpido que eu mencionei brevemente na quarta-feira. Mas pensando, como poderia projeto este programa pode ser melhorado ainda mais? Sim. [Resposta do aluno inaudível] >> Ah, bom. Então, lembro que foi introduzida uma segunda variável chamada n última vez, que parece estar nos contradizendo porque meu objetivo um segundo atrás era só para jogar fora uma variável como desnecessário, mas lembro que na quarta-feira que realmente fez isso. Eu mudei o loop for para realmente ter uma vírgula aqui, então n = strlen, e então aqui eu fiz i > [Resposta do aluno inaudível] >> Exatamente. Eu não estou lembrando strlen de novo e de novo e de novo, porque lembram como a de obras de laço. Mesmo se eles começam a ficar mais complicadas para o futuro, Recordamos que a coisa antes do ponto e vírgula primeira é a inicialização, o que acontece uma vez. A condição, no entanto, está no meio, e isso é verificado cada vez que você passar pelo loop. Então é meio idiota estar se perguntando o computador a mesma pergunta de novo e de novo - Qual é o comprimento da OLÁ? Qual é o comprimento da OLÁ? Qual é o comprimento da OLÁ? - porque como vamos ver hoje e na quarta-feira, este é definitivamente vai levar tempo, e não é um bom uso do tempo, porque para descobrir o comprimento de uma string na verdade, leva um pouco de esforço. Não é instantânea, como é em certas línguas. Então, mudando isto a n, o preço que eu estou pagando é o quê? Estamos vendo um trade-off aqui. Eu posso ganhar tempo não fazendo a mesma pergunta maldita de novo e de novo, mas vai custar-me uma coisa, que é o que? [Aluno] Você perde uma certa quantidade de memória. >> Exatamente. Vai custar-me um pouco de memória. Portanto, neste caso custa-me o quê? Outros 32 bits porque n é apenas um int, como implicado pelo int palavra aqui. Mas tudo bem? Francamente, isso é provavelmente tudo bem, porque se você pensar sobre isso, o mais longo da cadeia é, quanto mais tempo eu vou estar perdendo strlen porque vai ficar chamado novamente e de novo e de novo para cada iteração do loop. E estes dias, o meu Mac tem 2 GB de memória RAM, estes dias 4 GB de RAM, às vezes. Eu acho que eu posso pagar quatro desses bytes para realmente acelerar as coisas. Mas este vai ser um trade-off e um tema muito na programação e na ciência da computação de nunca conseguir nada de graça. Se você quer melhorar algo aqui, você tem que pagar por isso no outro lado de algum modo. Espaço em função do tempo neste caso. Então, tudo isso foi levando-se em direção a algo enigmático como este, que, como você deve ter percebido até agora, realmente diz? [Resposta do aluno inaudível] >> Sim, por isso esta é, Certifique-se de beber o seu Ovomaltine, na verdade, usando um algoritmo chamado ROT13, ROT 1-3, significa apenas que rodar todas as letras 13 lugares, o que significa tomar uma e depois adicionar de 13 a ela e ir do ponto, ponto, ponto todo o caminho para a carta 13 para longe, fazer a mesma coisa para B e de C para D e assim por diante. E assim se realmente converter este aqui, usando um deslocamento de 13 lugares, vamos voltar ao que Ralphie pouco teve, que foi, Certifique-se de beber o seu Ovomaltine. Mas agora para o problema conjunto 2, na edição padrão, pelo menos, você tem que fazer isso tipo de cifragem mesmo, e nós temos que de alguma forma levar em entrada como esta e criptografá-la ou decifrá-lo. Então, qual destes tipo fundamentos de leva-nos a essa oportunidade? Vamos dar uma olhada neste terceiro exemplo aqui. Primeiro de tudo, ele é chamado ASCII. O que ASCII remeter para? American Standard Code Information Interchange, que é uma maneira muito longa de dizer o que? O que é ASCII? [Resposta do aluno inaudível] >> O que é isso? >> [Aluno] Um mapa de caracteres. Mapa >> Um personagem. Ele só mapeia números de letras, porque o mundo tem padronizado o que os números representam o que vai cartas para que todos nós podemos usar computadores e nossos programas são todos compatíveis apenas quando se trata de imprimir coisas na tela. Então, lembro que 65 acontece a representar A, 97 acontece a representar uma minúscula. E assim, este programa simples ASCII aqui está se aproveitando desse fato - que o mundo sabe que o capital Um é de 65 - e é só imprimir o mapeamento. Então, antes de mergulhar neste código, deixe-me em vez abrir uma janela de terminal. Deixe-me ir em frente e fazer ASCII, e depois vamos executar esta coisa apenas para estragar a saída. E ele só faz isso: um gráfico muito grande que só me diz que todos os códigos de vários para todas as várias letras. Assim, um programa super simples, mas eu não precisava código rígido essas 52 linhas de saída: 26 letras maiúsculas, 26 minúsculas. Em vez disso, eu fiz isso programaticamente com um par de loops. Observe o que eu fiz aqui. Eu iterado de i é de 65 em até 65 + 26, porque eu queria imprimir 26 letras no alfabeto Inglês, i + + em cada iteração, e agora perceber isso novamente. É o retorno de nosso amigo typecasting pelo qual você converter um tipo de dados para outro porque o que eu quero fazer neste programa especial? Eu quero contar numericamente porque é assim que eu cresci contagem - 65, 66, 67, e assim por diante - mas eu não quero imprimir apenas os números. Quero imprimir a letra, seguido do número. Quero imprimir A: número, B: número, mas eu posso fazer isso com a mesma variável exata. Então eu imprimir c% como um espaço reservado para um personagem, D% como um espaço reservado para um dígito ou número. Então, o que eu ligar para esses dois espaços reservados? Eu ligar primeiro no equivalente caráter de i, e então eu imprimir i si. Então, observe isso também funciona. Assim como eu pode converter de um flutuador para um int , a fim de ir de um número real para um inteiro, aqui eu posso ir de um int para um char, que é um pouco estranho - não muito mapear para o mundo real - mas em computadores um char é apenas um número por baixo do capô, por isso estamos sendo sempre tão explícita aqui para o computador, dizendo: printf, imprimir não fora eu como 65, imprimi-lo como seu equivalente numérico. E não é que eu tecnicamente não precisa disso. O que eu estava fazendo há pouco é explicitamente lançando especificando que tipo de dados eu quero ir de e para. Mas repare que eu já tenho esse espaço reservado c% e esse outro espaço reservado% c aqui. Mesmo que este não é int, o computador percebe que um char, é apenas um int debaixo do capô. Então, se eu realmente recompilar esses e execute novamente o programa de ASCII, perceber que ainda só funciona porque o computador percebe que há essa correspondência. Agora, é mais importante fazer a conversão explícita no mundo dos carros alegóricos para ints porque na verdade você está fazendo uma decisão calculada: jogue fora tudo que vem depois do ponto decimal. Aqui não há nada para jogar fora porque um personagem é apenas um número, e uma corda é apenas uma matriz de caracteres. Então, quando chega a hora de implementar algumas criptografia ou descriptografia, como é que nós podemos realmente traduzir algo assim absurdo, Certifique-se de beber o seu Ovomaltine? O que se sabe agora - vamos tomar como premissa - que a chave, o número que está rodando todas estas letras por, é o número 13? Então, fomos de a letra B todo o caminho para o No início da frase, Certifique-se de beber o seu Ovomaltine, porque se eu fizer B e então eu vou C, D, E, F, G, H, I, J, K, L, M, N, O, é por isso que a criptografia da letra B torna-se O porque eu adicionei 13 a ele. Então, se eu quiser decifrar isso, eu essencialmente tem que tomar O e depois subtrair 13 a partir dele. Ou, francamente, porque há 26 letras no alfabeto, este é maravilhosamente simétrica, podemos também adicionar 13 e vamos voltar para a letra B. Mas como você vai fazer sobre a implementação de algo como isto em César ou realmente manipulando cordas em geral? Se a letra B é o número? Qual é a letra B? Então é 66, certo? Então, se a letra A é de 65 ea letra B é de 66, para 66, tudo o que tenho a fazer é adicionar 13 para ele, e isso me dá 79. E se formos para a nossa folha de fraude pouco, na verdade 79 mapas no O. Mas há um pouco de um caso de canto aqui. O que é, digamos, a letra Z? Se fizermos 66 + 25 para obter todo o caminho até o fim do alfabeto, estamos em 91. 91 + 13 me dá 104, e adivinhem? 104 não é igual uma letra maiúscula. Vamos voltar a uma cábula pouco aqui. Se eu executar novamente este programa no aparelho, observe que 104, se eu voltar para a janela do terminal, 104 é, aparentemente, o h minúsculo. Então precisamos de algum truque chave aqui, a fim de se certificar de que quando começamos a Z e adicionar 13 a ele que não quer apenas seguir em frente aos números cada vez maiores. O que nós realmente queremos fazer? Você quer envolver. Então não é que, como você viu, provavelmente, na secção de agora ou no conjunto de especificações problema em si percebi que há este outro operador em C, que também é um sinal de porcentagem, mas que nós usamos% aqui para especificar um espaço reservado, sabe que, especialmente para conjunto de problemas 2, há também algo como isto: int x =% y z. Deixe-me apresentar isso como uma forma muito genérica deste. Por cento significa que em uma linguagem de programação? >> [Aluno] Modulo. Modulo, que é uma maneira elegante de dizer o resto. Mesmo que não haja uma ligeira distinção com a definição lá, isso significa dividir y por z, mas não retornam o resultado dessa divisão; em vez disso, devolver o restante. Portanto, se y é 3, e, na verdade, z é realmente 2, 3 dividido por 2 é 1, com um resto de 1, então o que x realmente igual neste cenário? 1. Esse é um simples, a idéia de baixo nível. É preciso um pouco de tempo para obter a sua mente em torno dele porque é provavelmente um tempo desde que você ainda tinha de se preocupar com sobras e realmente usá-los para algo proposital, mas neste caso, o simples fato de que você pode ir de um número grande como 3 a um número relativamente pequeno, como 2, e, em seguida, enrolar em torno eficazmente usando o restante para um valor menor como um vai ser um truque de valor inestimável que podemos usar ambos para algo como César e Vigenère esta outra coisa no conjunto de problemas 2, mas isso vai ser um truque recorrente ao longo do semestre. Esta idéia simples, simples de apenas tomar o restante em geral vai permitir-nos a envolver em torno. E quando começamos a jogar mais com matrizes, como começar a jogar mais com a memória em si, este vai se tornar mais e mais de um truque poderoso. Assim, quaisquer perguntas, então em ASCII ou a representação de strings como arrays? E nós vamos levá-la até um entalhe mais. Sim. [Pergunta estudante inaudível] >> Boa pergunta. O que significa quando uma variável tem um asterisco na frente dele? Deixe-me adiar a resposta de que em qualquer detalhe, mas que se refere a um tópico conhecido como um ponteiro. Ponteiros têm a ver com memória, e na verdade estamos hoje dar o primeiro passo em direção a essa discussão, mas por agora, deixe-me fazer de conta que a estrela não existe e vamos continuar chamando cordas cordas em vez de usar char *, que você provavelmente já viu antes e vou colocar na tela em um momento como um teaser. Então, nós vamos voltar a isso em detalhes muito mais do que muitos de vocês provavelmente vai gostar. Eventualmente, não hoje. Sim. [Pergunta estudante inaudível] Em que contexto você tem que fornecer o sinal para um personagem? >> [Estudante] Yeah. Então, por padrão, quando você não colocar a +, apenas números positivos são assumidos. Então, se basta escrever o número 1, é a 1 positivo. Se você realmente quiser especificar a negação de um valor, você literalmente tem que fazer -1 em seu teclado. Mas isso provavelmente não é a sua pergunta. >> [Resposta do aluno inaudível] Boa pergunta. Okay. Então, isso tem a ver, eu suponho, com algum tipo de bug você correu para porque você estava convertendo um inteiro para um personagem, mas de alguma forma a negatividade se envolveu, e assim o personagem só saiu munged de alguma forma. Então, por agora, deixe-me simplificar um pouco, até que volte a este tipo de assunto. Por agora, pense em coisas desta forma - e esta é uma simplificação exagerada. Mas no mundo de um inteiro, você tem quantos bits à sua disposição? Você tem 32 bits. E, até agora, nós já conversamos sobre o número total de inteiros que você pode, portanto, representam a cerca de 4 bilhões no total, porque você tem 32 bits, de modo que é 2 ao 32, de modo que é cerca de 4 bilhões de dólares. Mas vimos uma semana ou dois atrás, que você realmente não tem um intervalo de números em 0 até 4 bilhões. A faixa vai de vez cerca de 2 bilhões para negativo positivo 2 bilhões. Mas este, em seguida levanta a questão, como você representar a noção de negativo 2000000000 muito menos negativo 1? Por agora, podemos simplificar e dizer que estamos indo para usar o bit mais à esquerda desses 32 bits, e se é um 1 é um número negativo, e se for um 0 é um número positivo. O problema com esta representação simplificada de números negativos é que se você estivesse deliberadamente ser inteligente e tentar converter a partir de um personagem para um número ou vice-versa, não há tal coisa como um caráter negativo. No mundo do ASCII, que utiliza apenas 8 bits, todas as 8 daqueles questão bits, eo bit mais à esquerda não tem nada a ver com a negatividade. E só para ficar claro, quando eu digo bits à esquerda, lembro que quando fizemos a nossa parte relacionados com exemplos na primeira semana Recordamos que traçamos coisas como 1001101, algo como isto. Quando eu digo a pouco mais à esquerda, eu literalmente significar a 1 que você escrever todo o caminho para a esquerda. Assim, no mundo de personagens, não há noção de negatividade, de modo que pouco mais à esquerda, na verdade, tem algo a ver com ASCII, nada a ver com a negatividade. Assim que parece - e fora de contexto, é difícil responder exatamente - mas de alguma forma, seu código foi confuso que pouco mais à esquerda como representando um valor negativo quando ele realmente fazia parte do personagem em questão. E novamente, eu estou simplificando demais, porque os computadores realmente fazer algo um pouco mais sofisticado do que apenas mudar esse bocado mais à esquerda para um 1 para o sinal negativo em relação a 0. Eles em vez disso, se você está curioso para o Google, usar algo tipicamente chamada de complemento de 2, que é um pouco mais sofisticada de uma abordagem mas a idéia é basicamente a mesma. Então, em suma, que tinha a ver com o fato de que você estava massageando um número para um personagem ou vice-versa, mas seu código não estava ciente do fato que um desses bits tinha um significado no mundo numérico. Esse não é o caso no mundo personagem. Mas parece que você fixa, caso em que discutível agora. Outras questões. Okay. Então, até agora, todos os programas que nós escrevemos ter tomado talvez entrada do usuário sob a forma de funções como GetInt, GetString, ou se você estiver lendo à frente em vários livros ou referências on-line, vós mesmos poderiam ter usado funções como scanf que, francamente, que nós usamos na biblioteca CS50. Mas em uma semana ou duas, vamos realmente mostrar-lhe como a biblioteca CS50 é implementado para que possamos tomar as rodinhas completamente. Mas acontece que não há outra forma de obter a entrada de um usuário. Na verdade, nós mesmos temos vindo a utilizar argumentos de linha de comando por um par de semanas. Cada vez que executar Clang ou temos executar o make, nós não apenas digitado bumbum, Enter, que não digitou fazer, Enter. O que nós normalmente escrito após o barulho palavra de nosso terminal prompt do Windows? [Estudante] O nome de arquivo. >> O nome do arquivo, certo? Hello.c ou mario.c ou qualquer que seja o nome do arquivo é relevante. E, nesse sentido, o que você realmente faz é você influenciado o comportamento de Clang porque certamente as pessoas que escreveram Clang não tinha idéia de que pouco velho você ia escrever um programa chamado mario.c anos mais tarde. Então você tinha de alguma forma influenciar o comportamento desse programa, e que Clang programa tinha de ser escrita de tal modo que ele pode aceitar entrada de você pela adição de palavras sobre o aviso antes de os golpes de usuário Enter. Assim, verifica-se que há algum tempo que temos vindo declarando quase todos os nossos programas começar assim - int main (void) - e então temos ido e comecei a escrever o nosso código. E que pode ter alguma afiado inclui, na parte superior do arquivo, mas quase todos os nossos programas, até agora, ter começado com esta mesmo que você pode ter visto em seção, em livros, referências on-line que isso não, na verdade tem que ser nula. Outra forma legítima para se fazer isso é int argc e argv corda []. Então agora o que é que isso implique? Acontece que argc, que é uma convenção humana - você poderia chamar isso de foo, mas que seria apenas muito menos claro para os leitores - argc é apenas um argumento para a função chamada principal que representa o que? O que argc representam para aqueles familiar? [Resposta do aluno inaudível] >> Sim, o número de argumentos ou de contagem de argumento. É tão simples como isso. Quantos argumentos foram passados ​​para este programa? O que significa isso? Se na linha de comando eu tenho que correr algo como isto - clang mario.c - argc quando eu pressione Enter vai assumir um valor, um pouco confusa, 2. Assim, verifica-se que argc é contagem de argumentos, mas, por razões históricas, o nome do próprio programa que está incluído na contagem. Então argc é 2 quando escrevi clang mario.c. O que argv contém? Em primeiro lugar, parece que argv uma cadeia mas não completamente porque a partir de quarta-feira passada e tudo o mais, hoje, estes colchetes denotam o que? Isso é um array. Não há nenhum número na matriz, e que deve fazer sentido intuitivamente porque as pessoas que escreveram anos atrás Clang certamente não tinha idéia pessoas quantas palavras como nós deve digitar no prompt antes de bater Enter. Portanto, neste caso aqui eles declararam que a principal função como tendo uma matriz de argumentos, 0 ou mais argumentos. Eles não sabem de antemão quantos são, por isso não é deliberadamente não dentro número desses colchetes. Mas o fato de que os colchetes estão lá estão dizendo ao computador, esperar uma matriz. Argv é apenas notação abreviada para vetor argumento. Um vetor é uma maneira elegante de dizer matriz, e matriz é uma maneira elegante de dizer uma lista ou coleção. Então isto significa apenas que se você escrever principal como esta em vez de como como temos vindo a fazê-lo para o último par de semanas, seu programa agora tem o poder de aceitar os argumentos da linha de comando de modo que não mais se você tem que escrever mario e pressione a tecla Enter, em seguida, digite um número para quantos blocos de alta da pirâmide você quer ser, em seguida, pressione Enter novamente. Não precisa nem usar GetString mais ou GetInt ou GetFloat para esse assunto. Nós podemos apenas esperar que o usuário digite as palavras no prompt próprio assim como os autores do Clang decidiu que seria um programa muito chato se compilar o código que você clang primeiro digitado, pressione Enter, então nós dissemos para o usuário, por favor digite o nome do arquivo que você deseja compilar, então digitar mario.c e pressione Enter. Mas isso é exatamente o que estamos fazendo para os nossos usuários do casal últimas semanas. Usamos GetString e vamos esperar até que o programa está sendo executado para levá-los para a entrada. Que já não precisa ser o caso. Portanto, neste exemplo aqui, agora temos corda argv, e isso também é uma simplificação, rodinhas que muito em breve sair. Esta é a forma mais adequada de escrever esta declaração alternativa de principal pois verifica-se que o que nós continuar chamando corda tem realmente uma estrela, um asterisco, em sua própria definição, mas isso só parece complicado, é confuso no início, para que simplificar por apenas criar um sinônimo de sorte na biblioteca CS50 que mapeia char * para esta seqüência de palavras mais user-friendly. Então, vamos realmente tentar isso então. Deixe-me ir em frente e abrir gedit aqui. Deixe-me ir em frente e abrir argv de 1. Este programa imprime os argumentos aparentemente, mas em termos de inglês, ao olhar para este código, o que isso faz mais especificamente? Se eu digitar o comando a.out foo bar, o que é impresso em minha janela a preto e branco? A.out foo bar, Enter. Vá em frente. Sim. >> [Resposta do aluno inaudível] Bom. Então a.out, nova linha, foo, nova linha, bar, nova linha. Por que isso? Podemos certamente confirmar em apenas um momento. Este é o tipo de uma linha fofa de código.  Ele só imprime uma nova linha apenas para tornar as coisas mais bonitas na tela. Este é um ciclo que está interagindo em 0 até argc, e isto é incrementado em cada iteração + +. Portanto, este está dizendo agora imprimir uma seqüência, como implícito por este% s. Argv [i] é praticamente a mesma idéia do exemplo anterior. Nós costumávamos chamar a variável s, agora ele é chamado, de forma arbitrária, argv. Isto significa imprimir o argumento om que foi digitado na linha de comando, e depois de tudo isso é feito, apenas para uma boa medida imprimir outra nova linha. Então, vamos ver isso. Deixe-me abrir a janela de terminal. Deixe-me compilar argv de 1, e agora deixe-me correr argv de 1, Enter. Hmm. Okay. Vamos executar foo bar. Interessante. Baz. E se você já se perguntou por que eu escreva isso, isso é apenas uma convenção também ciência estúpido computador. O mundo muitas vezes precisa apenas marcadores verbais para palavras. Então, se você quiser falar sobre alguma corda genérica, cientistas da computação só tendem a dizer foo quando eles precisam de uma palavra aleatória, depois dizem bar se eles precisam de uma segunda palavra aleatória, depois dizem baz se eles precisam de uma terceira palavra, então eles dizem qux se eles precisam de uma palavra quarta, e depois há uma linha de grande debate religioso, como o que vem depois qux, assim você pode Google que, para descobrir o que a outra palavra arbitrária deve ser. Mas estes têm qualquer significado, embora foo bar, se você Google que, que não tem sentido, que faz parte da etimologia aqui. Então, tudo isso está a fazer, então, é a impressão de uma dessas cordas por linha. Então, se eu em vez disso, porém, queria ficar um pouco mais sofisticado, suponha que eu não queria imprimir cada string por linha; Eu queria imprimir cada personagem de cada string por linha. Como eu poderia fazer isso em vez? O que eu preciso para mudar sobre este programa se eu quiser imprimir não cada palavra mas eu quero imprimir cada palavra letra por letra por letra, em seguida, a carta palavra seguinte por letra por letra? Como podemos combinar essas idéias até agora? Sim. [Aluno]% c. >> Tudo bem. Então, em algum lugar precisa de um c%. Bom, porque eu não quero imprimir cadeias inteiras, eu quero imprimir caracteres. O que mais? [Resposta do aluno inaudível] >> interessante. Então precisamos de uma espécie de segunda dimensão aqui agora porque pensar em argv como uma matriz, mas é uma matriz de strings. Mas, como de, tipo, 15 minutos atrás, o que é uma string? É uma matriz de caracteres. Então, realmente, argv é uma matriz de uma matriz de caracteres, uma matriz de matrizes de caracteres. Assim, verifica-se que podemos usar anotações suporte apenas mais quadrados. Então, vamos fazer isso. No topo deste laço na linha 19, eu vou repetir a partir de i até argc, mas então eu vou fazer isso: para - Eu não posso usar i agora. Preciso de outra variável, porque eu quero iterar sobre as palavras mas depois também sobre as letras nas palavras Então eu meio que tem um eixo vertical e um eixo horizontal, tipo de conceitualmente. Então j int recebe 0, então eu quero fazer j enquanto j for menor que - e eu vou limpar isso um pouco. Como eu iterar sobre as letras em uma string? Fizemos isso há um momento. Strlen de argv [i]. Bom. E novamente, eu estou fazendo uma ineficiência pouco aqui, não criando n ou o que seja, mas vamos voltar a isso. Então, agora j + +. Agora eu tenho que recuar mais aqui. O que eu agora quero imprimir em cada iteração? [Resposta do aluno inaudível] >> Então [i] vai me dar a palavra. [I] [j], como uma espécie de matriz. Aqueles de vocês com a matemática y-fundos, somos um tipo de indexação ainda mais fundo nessa matriz ou esta matriz de matrizes, esta estrutura 2-dimensional. Então agora vamos ver o que acontece aqui. Deixe-me abrir a minha janela maior terminal. Deixe-me fazer reprise de argv de 1. E eu estraguei tudo aqui, o que é uma boa lição, porque eu também esqueci de fazer isso. Implicitamente declarando 'strlen' C função de biblioteca com unsigned tipo '- Eu não sei mesmo o que o resto do que isso significa, mas eu já vi isso antes, implicitamente declarando. Sempre que vemos esse erro, o que é que isso geralmente significa? [Resposta do aluno inaudível] >> eu esqueci uma biblioteca em cima. Mas espere um minuto. Normalmente eu estraguei tudo porque eu esqueci a biblioteca CS50, mas que está lá. Normalmente eu estraguei tudo porque esqueci padrão de I / O. E, francamente, eu nem preciso disso. Nós não estamos usando GetString hoje. Então, o que eu estou ausente? Há uma outra biblioteca que agora precisamos usar string.h chamado ocasionalmente, e esta é apenas mais uma biblioteca que tem mais funções que não estão no padrão de I / O. Então, vamos voltar para a minha janela de terminal grande. Okay. Agora, droga, eu acho que eu estava errado. Eu estava usando a biblioteca CS50. Assim, podemos corrigir isso em qualquer uma das duas maneiras. Podemos tomar as rodinhas agora e só fazer isso, ou tipo vamos de manter essa simplificação só para agora, cole este de volta, resolver esse problema, e agora voltar para a janela de terminal. Então, para ser claro, na biblioteca CS50 não é apenas funções, é também a seqüência de palavras-chave, que é por isso que o erro aconteceu. Então, vamos lá. I fixado de ambos os problemas de bibliotecas. Enter. Bom. Argv de 1, foo bar, Enter. Excelente. Portanto, agora temos cada letra de cada palavra impressa uma por linha, o que não faz um programa muito interessante, mas observe agora temos a capacidade de não só iterando palavras mas também sobre as letras individuais em palavras, o que soa muito familiar até mesmo a mais simples das aplicações, como cartas lutando em uma string como esta. Vamos em frente e tomar o nosso intervalo de 5 minutos aqui. E quando voltar, vamos começar a falar sobre a eficiência com a qual podemos fazer essas coisas melhor. Tudo bem. Estamos de volta. Graças a um de nossos TFs que joga um monte de bananagrams, nós realmente temos um monte de caracteres com a gente aqui hoje fisicamente encarnado com estes pequenos pedaços de plástico, e deixe-me propor que esta lousa em branco aqui representa a memória RAM no meu computador - desktop, laptop, o que quer - e não se parece com um monte de que porque se começarmos a cortar-se esta RAM em pequenos pedaços de bytes de tamanho, vamos arbitrariamente dizer que algo desse tamanho e que embaçada representa - lá vamos nós, e vamos afastar um pouco aqui - vamos dizer algo que tamanho representa um único byte. Assim, podemos de fato encaixar um monte de bytes ou caracteres dentro desta memória, tal como sugerido pelo tamanho relativo aqui. Então suponho que agora que o objetivo é alocar memória para uma string. Como é que isso realmente funciona? Nos programas que tenho escrito, nós geralmente usado GetString, mas agora, claramente, há este outro canal através do qual podemos obter a entrada do usuário em argv por meio de argumentos de linha de comando. Mas o que realmente está acontecendo debaixo do capô? Acontece que, se nós chamamos - vamos rolar de volta para GetString - a função GetString na biblioteca CS50, o usuário é solicitado para uma string, o usuário digita uma palavra - vamos chamá-lo OLÁ. E nós temos dito para o último par de semanas que o valor de retorno de GetString é de fato uma corda, como a palavra OLÁ. Mas o que está realmente fazendo GetString? Como o usuário digita em OLÁ, Enter, GetString é descobrir, bem, quantos caracteres é isso? Trata-se de H-E-L-L-S. Então ele precisa alocar, ele precisa pedir ao sistema operacional - Linux neste caso - durante pelo menos 5 bytes para armazenar OLÁ. E o que ele então começa a fazer uma vez que ele recebe de volta os 5 bytes do sistema operacional é estabelecer OLÁ volta para trás para voltar para trás. E então o que está realmente voltou de GetString é um pedaço de dados que se parece com isso. Mas isso é um pouco imprecisa porque verifica-se que não é tão simples como apenas armazenar OLÁ na memória do computador porque acho que o meu programa que eu estou escrevendo em C, então, chama GetString novamente, ea palavra seguinte, o usuário digita é tchau, tchau. Bem, eu preciso de encaixar que BYE palavra em algum lugar na memória. Eu não posso espancar OLÁ. Por exemplo, eu não quero que o computador apenas para começar a substituir como esta a palavra original, porque eu ainda poderia estar usando a palavra OLÁ em uma variável em outro lugar no meu programa. Então B-Y-E tem que acabar em algum outro lugar na memória. Mas a convenção é que normalmente a próxima seqüência de alocar Provavelmente, mas não sempre, vai acabar na próxima posição de memória disponível. E se eu não perguntei o sistema operacional para a memória desde a última vez eu chamei GetString, as probabilidades são a palavra BYE vai acabar logo após a palavra OLÁ na memória. Mas, neste ponto, você pode ver onde talvez um potencial problema surge. Porque os pedaços próximos de memória, os próximos bytes que eram apenas livre - limpar lousa branca - na memória do computador estavam ao lado OLÁ, parece que a primeira corda Pedi pode de repente mudar agora porque eu essencialmente mudou para HELLOBYE em vez de alguma forma, do início do demarcing BYE eo fim da OLÁ. Assim, verifica-se que o que realmente está acontecendo sob o capô, que você pode ter vislumbrado em referências on-line ou seção ou livros ou não em todos apenas ainda é a de que há realmente uma demarcação deliberada entre as palavras na memória de um computador. E, de fato, neste caso aqui, em vez de apenas colocar BYE ao lado OLÁ, em vez disso, o computador coloca um caractere especial, o caráter especial nulo, por assim dizer, o qual é representado com um marcador com barra invertida 0. Então, longa história curta, lembro que os personagens são representados em ASCII. ASCII é apenas um mapeamento entre números e letras, ea maioria dessas cartas começam cerca de 65 para capital de A, mas acontece que você pode certamente representar o número 0 como um inteiro ou em binário, e não é que o mundo resolveu muito, muito tempo atrás: "Você sabe o quê?" "Vamos 0 Número reserva como não representando quaisquer caracteres no teclado - "Sem letras, sem números, sem pontuação. 0 é especial." "Vai ser o caráter especial nulo, e nós estamos indo para escrevê-lo como \ 0". A diferença é se nós apenas escreveu 0, 0 é um personagem. Lembre-se que existem códigos ASCII para 0, para 1, para 2, para 3 porque o 0 carácter é diferente do número 0. E você pode ver que se você olhar para trás de uma semana, quando falou pela primeira vez sobre o ASCII, 0 e 1 e 2 e 3 de todo o caminho até aos 9 tinham os seus próprios códigos ASCII. Eles não são, coincidentemente, de 0 a 9. Eles são muito diferentes. Assim, 0 significa apenas "Eu sou especial", e os \ 0 significa, literalmente, "Eu não sou o personagem 0." "Eu sou este valor especial, o personagem nulo." Então, eu realmente preciso de outro destes já que não posso cometer o mesmo erro duas vezes. Assim, após a palavra BYE também vamos precisar de mais um desses caracteres nulos. Deixe-me pegar minha caneta aqui e deixe-me desenhar outro \ 0 para que depois eu pedi o sistema operacional para duas cordas getString via seguida por outra chamada para GetString, isso é o que é realmente na memória. Então, quando eu voltar uma corda, eu estou realmente ficando para trás que, e quando eu começar a seqüência seguinte, eu estou realmente ficando para trás disso. Então, isso levanta a questão, strlen, antes de tudo, o que deveria voltar? Quando eu chamo strlen na cadeia s e s foi a palavra OLÁ que o usuário digitou, o que é que nós, obviamente, dizer que o comprimento da OLÁ foi há poucos minutos? Foi 5, certo? H-E-L-L-S. E isso é fato, como strlen obras. Ele retorna o que um ser humano normal seria esperar que o comprimento de uma string para ser. Mas, na realidade, quão grande é a matriz de caracteres que está armazenando Olá? É realmente 6. Então strlen não menciona esse fato para você. Mas debaixo do capô o computador está realmente usando 6 bytes para armazenar uma palavra de 5 letras, e isso é verdade, não importa quanto tempo é a palavra. Há sempre vai ser um personagem nulo especial encerra no final da string demarc para o seu comprimento total. Então, se você está agora a pessoa implementação strlen 20, 30 anos atrás, como você vai fazer sobre a implementação de strlen si? Tomamos por certo que ele existe, assim como nós tomamos por certo que printf existe, mas se OLÁ é a palavra em questão eo que eu tenho na memória é algo que se parece com isso, se você tivesse que reimplementar strlen porque lhe foi pedido para ou porque, francamente, você não sabia que existia strlen - você tinha que rolar um presente por conta própria - como você pode implementar strlen quando recebe algo que se parece com isso? Agora que sabemos que uma string é uma matriz, podemos iterar sobre cada um dos personagens individuais usando algo como - Vamos tentar fazer isso em tempo real. Deixe-me ir para dentro do aparelho. Deixe-me criar um novo arquivo, strlen.c. Deixe-me ir em frente agora e não incluem stdio.h para que tenhamos acesso a printf. Deixe-me fazer int (void) principal. Oh. Eu só vou fazer isso no meu próprio para agora então. [Risos] Obrigado. Isto é o que eu estou fazendo. Tudo bem. Então, antes de me virar na tela, eu digitei tudo isso. E agora o que eu vou fazer é o seguinte: printf ("Dê-me uma string:") Isso é só instruções macias. Agora deixe-me fazer GetString string s =. Eu já preciso fazer uma mudança agora. Eu estou usando a biblioteca CS50, de repente, então deixe-me ir em frente e digitar cs50.h. E agora vamos fazer isso: printf ("O comprimento é:% d, strlen [s] - e eu não estou pronto ainda. O que mais tenho a acrescentar a este programa? [Aluno] string.h. >> String.h. Então, por enquanto, estamos usando strlen, então vamos garantir que o compilador sabe onde fica, assim um pouco de sanidade verificar. Estou recebendo uma string na linha 8, e na linha 9 estou imprimindo sua extensão, com d%. Então, vamos em frente e abrir isso. Temos fazer strlen - compila bem - strlen - deixe-me aproximar - Digite, H-E-L-L-O, Enter. O comprimento é de 5. Ok, então strlen parece funcionar, mas o mundo sabia disso. Então, vamos agora implementar strlen-se como segue. Deixe-me tomar esta biblioteca de distância. Nós já não temos acesso a string.h porque eu nem sabia que existia. Mas tudo bem, porque eu posso implementar strlen me e tê-lo tomar uma string chamada de entrada, e agora eu preciso descobrir o comprimento da corda. Então, como posso fazer isso? E se eu fizer - vamos ver como fazer isso - O que você quer fazer? [Resposta do aluno inaudível] >> Okay. Assim, podemos fazer isso em um monte de maneiras. Deixe-me tentar tomar essa atitude. Deixe-me dar-me uma variável int i, para i começa em 0. E deixe-me dizer isto: enquanto a entrada [i] não é igual a que? \ 0. Então não é que, como é o caso com todos os caracteres quando escrever-lhes, literalmente, em um programa, você tem que usar aspas simples, não aspas duplas. Então, se eu estivesse escrevendo a letra, eu faria isso, a letra b, eu faria isso. Este, ao contrário, seria uma string, não caráter de um indivíduo. Então, eu quero \ 0 literalmente. O que eu quero fazer neste loop? Na verdade, eu preciso de outra variável, de modo comprimento int recebe 0. Mesmo se você não estava certo porque nós começamos a maneira como o fez, agora que estamos indo por este caminho, o que eu quero fazer na linha 9? comprimento + + e depois aqui na linha 10, comprimento retorno. Então, como é strlen implementado? É realmente implementado provavelmente como este. Talvez a pessoa usou um laço for, talvez um fazer enquanto loop - quem sabe? Nós realmente temos que olhar debaixo do capô o código fonte real em algum arquivo chamado string.c provavelmente. Mas aqui vamos pensar sobre o que eu estou fazendo. Estou declarando uma variável chamada i, definindo-o igual a 0. Estou em seguida, declarando outro comprimento variável chamada, colocando-a igual a 0. Então eu estou dizendo quando o personagem om na entrada não é igual ao caractere nulo especial, \ 0, incrementar o comprimento. Mas assim como o personagem om é este caráter especial, o que acontece com o loop? É curto-circuitos. Ela pára, o que significa que, em seguida, retornar instantaneamente comprimento. Então, se eu não errar, vamos em frente e voltar para a minha janela de terminal. Deixe-me recompilar. E eu errei. Redeclaração incompatível de biblioteca de função strlen. Então, eu estava tentando fazer demasiado inteligente para o meu próprio bem aqui. O compilador realmente sabe que existe uma função chamada strlen mesmo que não tenha incluído a biblioteca. Isso é bom. Qualquer que seja. Estamos apenas vai cooperar então. Vamos renomear este comprimento. Deixe-me mudar o uso do mesmo com o comprimento aqui, e isso vai fazer Clang mais feliz. Como um aparte, porque algumas dessas funções são tão danado comum - strlen, prinf - eles realmente têm uma espécie de estatuto especial. E assim Clang só sabe um pouco algo especial sobre eles. Isso nem sempre é o caso com a maioria das funções, de modo que é por isso que temos gritado. Deixe-me tentar novamente. Felizmente, deu certo naquele momento. Então, agora deixe-me executar o meu programa strlen própria. Dê-me uma string: H-E-L-L-O, Enter. E eu estraguei tudo. Por quê? >> [Resposta do aluno inaudível] >> Exatamente. Então, eu tenho-me aqui um laço muito bonito infinito porque mesmo que eu estou incrementando comprimento em cada iteração, o que eu claramente não está fazendo? Eu não estou incrementando i. Okay. Reparo fácil. Sim? Okay. Não. Agora nós entrar em conflito com algum outro erro comum onde eu preciso colchetes. E, francamente, este código está começando a olhar feio, então vamos tomar uma facada em limpar isso em um momento. Mas agora eu estou incrementando comprimento e i. Francamente, eu já vejo uma oportunidade de melhoria aqui, mas vamos voltar a isso. Então, agora vamos ter certeza que estamos pelo menos a fazer progressos. Isso aconteceu um pouco de você, e eu esqueci de mencionar isso com antecedência. Quando você tem a infelicidade de um cenário como este, como você corrigir isso curto de reiniciar o aparelho ou o computador ou fechar a janela? É realmente fácil. Controle C vai enviar esta pequena cenoura símbolo C, e que só termina a maioria dos programas. Se você tem um loop infinito muito ruim que está imprimindo vezes coisas infinitas, às vezes você pode ter que acertar C Controle mil vezes para torná-lo realmente ouvi-lo. Então, só agora percebo porque eu não estou imprimindo nada, que foi bastante fácil. E, tecnicamente, uma vez que é suficiente, mas eu fico impaciente e eu costumo bater tantas vezes. Então strlen. Dê-me uma string: OLÁ. Será que vai funcionar desta vez? Okay. Outro erro comum. Tem que recompilar. Isso foi proposital, que um. Tudo bem. Então strlen, H-E-L-L-O, Enter. Excelente. Assim, temos agora um strlen a 5. Portanto, temos que literalmente reimplemented roda. Então agora vamos limpar isto porque este não me faz impressionado com o desenho do meu código. O que podemos eliminar claramente neste programa para limpar isso? [Resposta do aluno inaudível] >> Yeah. Literalmente, estamos tratando i e comprimento de forma idêntica. Então, por que nós não apenas ficar esperto e dizer enquanto o comprimento? Em vez disso, vamos chamá-lo de comprimento, para começar, inicialize-a 0 porque, por padrão a string não tem um comprimento até descobrir o que é. Agora vamos fazer isso, e agora este é um programa muito elegante. Uma variável. Limpei-a, apertou-se. Então agora vamos voltar para a minha janela de terminal. Vamos em frente e executar este. Faça strlen. Parece bom. Executar strlen novamente, Enter. Dê-me uma string: OLÁ, Enter. E isso parece estar funcionando como 5. Agora, para ser claro, se eu não tivesse escrito, por exemplo, em uma corda OLÁ e depois BYE em outro, certamente podemos ter várias palavras. Se a expressão que eu realmente queria escrever não era OLÁ, mas, por exemplo, OLÁ MUNDO, aviso de que o que nós não temos é essa situação aqui, certo? Isso sugeriria que isso é duas cordas. Você certamente pode ter caracteres barra de espaço, por isso, se nós realmente digitou uma frase mais longa como o mundo OLÁ, o que nós realmente temos na memória parece um pouco algo como aquilo lá. Tudo bem. Quaisquer perguntas, então sobre a representação aqui de cordas? Não? Tudo bem. Então, eu disse mais cedo que a chamada strlen novo e de novo como que deliberadamente provavelmente não é a melhor idéia, porque você vai estar fazendo um monte de trabalho de novo e de novo e de novo. Na verdade, o tipo de trabalho é necessário para descobrir o comprimento de uma corda, aparentemente? Você tem que começar no início e, em seguida, olha, olha, olha, olha, olha até que você finalmente ver que o caráter especial, altura em que, ah, agora eu sei o comprimento. Então, no início, quando tínhamos strlen sendo chamado de novo e de novo e de novo, a razão propus que era uma espécie de estúpida é porque mais uma vez, a corda parece assim. Não vai mudar cada vez que você percorrer alguns loop, então você está fazendo um trabalho desnecessário. Ao mesmo tempo, você deve saber, como um aparte, que os compiladores como Clang estes dias foram desenvolvidos ao longo de muitos anos, e escritores de compilador, programadores, são muito inteligentes. E assim acontece que compiladores Clang e outro pode realmente descobrir o que, Ok, sim, você escreveu strlen em sua condição, que tecnicamente significa que chamaríamos isso de novo e de novo e de novo. Mas compiladores inteligentes pode realmente otimizar esses tipos de decisões de usuários pobres de seu código para corrigir as coisas. Então, basta perceber que, por vezes, o compilador é mais inteligente do que nós e tipo de esconder nossos próprios erros. Mas certamente quando se trata de conjuntos de problemas e semelhantes, não estar pensando sobre essas decisões de design fundamentalmente errôneas potencialmente pela simples razão de que nós estaríamos fazendo o trabalho de forma mais do que realmente tem que fazer. Mas quanto mais trabalho? No caso do MUNDO OLÁ, vamos começar a generalizar o tamanho do problema. O que é o comprimento do problema ou a dimensão do problema quando a palavra que o usuário digitou é OLÁ? É, aparentemente, cinco, talvez seis. Mais ou menos 1. Qualquer que seja. É tão perto, vamos chamá-lo apenas 5. Então, qual é o tamanho do problema aqui ao tentar descobrir o comprimento da OLÁ? É 1, 2, 3, 4, 5, 6 e talvez para o último caractere, mas vamos generalizar que como n. Assim, n, n apenas a variável, é o que os cientistas da computação usaria normalmente para descrever o tamanho de um problema, e que o problema em questão é quanto tempo é OLÁ? Quanto tempo strlen tomar? Ela recebe a ordem dos passos de n, em que cada passo significa olhar para um caracter, olhar para um personagem, olhar para um personagem. E nós tivemos essa discussão um tempo atrás, o número de operações algo preciso. O primeiro dia de aula, tinha todos desajeitadamente em pé, e então todos começaram a emparelhar-se com o outro , a fim de realmente contar idealmente quantas pessoas estavam na sala. E também fez outra coisa em que se eu, em vez fez isso da maneira antiga escola de apenas a partir de 1, 2, 3, 4, 5, 6 e assim por diante, isso também, o tamanho desse problema era de tamanho n. Havia pessoas na sala n. Mas eu poderia acelerar isso, certo? Estilo de escola primária que eu poderia começar a contar em 2s. 2, 4, 6, 8, 10, 12. E que se sente muito mais rápido, e de fato é. É literalmente duas vezes mais rápido, mas, novamente, se mais 400 pessoas entraram nesta sala tudo de uma vez, esses algoritmos levaria mais 400 ou talvez 200 passos. Mas por outro lado, se realmente ficar esperto e sim ter todos vocês considerem-se, lembrar como esse algoritmo funcionou. Você todos se levantaram. Deixe-me avançar para isso. Você todos se levantaram, você emparelhados, então metade do que você se sentou, metade de você se sentou, metade de você se sentou, e em cada iteração deste laço de semana 0, metade do problema na mão e foi a n / 2, então n / 4, então n / 8. E a implicação disso é que, se mais 400 pessoas a pé na sala, não é grande coisa, nos levará round 1 mais, não 400 mais rodadas, e não 200 mais rodadas. E assim a história que disse a um tempo atrás tinha que fazer alguma coisa com isso. Esta linha vermelha aqui é linear, é reta, e é classificado como n porque, como o tamanho de um problema cresce, se o seu algoritmo ou programa com o qual você está resolvendo é preciso n passos, podemos traçar-lo como uma linha recta onde ele leva mais tempo a maior dimensão do problema. E a abordagem twosies, contando 2, 4, 6, 8, ainda uma linha reta, apenas um pouco melhor. Leva um pouco de tempo menor, para que a linha amarela é abaixo do ponto de linha vermelha para o ponto. Mas o melhor mesmo era esse santo graal do que chamamos tempo logarítmico onde até mesmo se, novamente, o dobro do número de pessoas na sala, dobramos o tamanho da lista telefónica do primeiro dia de aula, não é grande coisa, é preciso uma lágrima mais página, leva uma sessão mais baixo a fim de resolver um problema que é duas vezes maior. E assim a conversa que começa agora a começar a ter é como é que vamos realmente resolver os problemas de forma eficiente se considerarmos o mais simples de problemas como este? Suponha que temos 8 portas por trás da qual estão alguns números, e cada um desses números não é classificada em qualquer forma, eles são apenas inteiros aleatórios por trás dessas portas, e fazemos a pergunta como você vai encontrar o número - quem sabe - 7 por trás dessas portas? O que você, um ser humano, fazer a fim de encontrar-me o número 7 Se novamente cada um deles são as portas e ver um valor que você tem que abrir uma porta? Qual seria o seu algoritmo de ser, talvez? [Resposta do aluno inaudível] >> Então comece com a esquerda e abrir uma porta, abre uma porta, abrir uma porta. E no pior dos casos, quanto tempo é que vai nos levar a encontrar o número 7? E, novamente, eles não são classificados, por isso não é tão fácil quanto, bem, eu vou abrir a porta 7. Ele poderia nos levar, no máximo, 8 etapas. No pior dos casos, 7 é aleatoriamente no final da linha de portas, assim que nós pode ter que tentar todas as portas n. Então, novamente aqui, parece que temos um algoritmo linear. Na verdade, fizemos isso apenas um par de anos atrás. Um de seus antecessores foi desafiado precisamente com este onde nós não temos uma versão digital, em vez teve um quadro negro com alguns pedaços de papel sobre ela. E o que eu pensei que eu gostaria de fazer é dar uma rápida olhada para trás em como este foi, uma das melhores oportunidades e, talvez mais difíceis no palco de ter uma demonstração aqui na Sanders. Tivemos duas linhas de números. Só vamos olhar para o que acontece aqui com Sean para o topo dessas linhas. A não ser que ninguém nunca mais voluntários em CS50, tivemos a bênção de Sean para manter esta na câmera, então ele sabe que centenas de pessoas foram assistir a este momento por anos. Mas Sean fez um trabalho incrível - ou ele -? De realmente encontrar-nos um determinado número. Então, vamos ver como ele resolveu esse algoritmo de modo que nós vamos retomar essa conversa antes de tempo de como encontrar as coisas de forma eficiente. [Malan em vídeo] eu ter escondido por trás dessas portas o número 7, mas escondido em algumas dessas portas também são outros números não negativos, e seu objetivo é pensar desta linha superior de números como apenas uma matriz ou apenas uma seqüência de pedaços de papel com números por trás deles, e seu objetivo é, apenas usando a matriz superior aqui, encontrar-me o número 7. E estamos indo então para a crítica como você vai fazer sobre isso. >> Tudo bem. [Malan] Encontre-nos o número 7, por favor. [Risos] [Malan] Não. [risos] 5, 19, 13, [risos]. Não é uma pergunta capciosa. 1. [Risos] Neste ponto, sua pontuação não é muito boa, então você pode muito bem continuar. [Risos] 3. Vá em frente. Francamente, eu não posso ajudar, mas pergunto o que você está pensando mesmo. [Risos] Apenas uma linha no topo, então você tem três esquerda. Então, encontrar-me 7. [Estudantes murmurando] [Malan] 17. [Estudantes murmurando] [Malan] 7! [Aplausos] Então, na quarta-feira vamos mergulhar neste e algoritmos mais sofisticados para encontrar coisas. Por agora, vou deixar você com Sean e ver você na quarta-feira. [CS50.TV]