>> [Música tocando]
>> DAVID J. MALAN: Tudo bem isso é CS50 e este é o início da semana, cinco.
Então, hoje, debaixo de seus assentos, você não vai encontrar nada.
Mas, acima, você deve encontrá-los, um pequeno sinal de nossa gratidão por
todo o trabalho que você colocou no Jogo dos Quinze.
Basta retirar o pequeno círculo no baixo para começar a jogar para o
restante da classe.
>> Então, lembro que, ou saber que problema definido quatro, que saiu este fim de semana,
envolve a escrita de um outro jogo.
Mas, desta vez, envolve a utilização de um interface gráfica do usuário real, e não um
Interface textual como Jogo dos Quinze era.
E o jogo que está à frente de você, Se você ainda não viu esta próxima,
parece um pouco algo como isto.
Eu estou indo para ir em meu terminal janela aqui na GDB.
E eu estou indo para ir em frente e correr o solução pessoal, que você pode acessar
após a execução de atualização de 50 como de costume.
>> Mas eu vou colocá-lo em um pouco modo secreto, um pequeno ovo de Páscoa,
o chamado modo de Deus, por colocando Deus em argv1.
E eu tenho que seguir os meus próprios sentidos, executá-lo em minha própria
problema de definir o diretório.
Então agora você vê uma versão completa do jogo de Breakout.
Na verdade, este é o modo de não-mãos.
Portanto, é na verdade -
empolgou que você pode ser -
bem simples de se implementar o modo Deus no Breakout, ao contrário do jogo dos Quinze,
que alguns de vocês podem ter abordado para a edição de hacker.
>> Em Breakout basta em Deus modo de simplesmente fazer o que,
intuitivamente com a pá?
Apenas torná-lo igual a qualquer que seja o posição horizontal é de bola.
E, desde que você faça isso em sintonia com a bola em movimento este jogo vai
nunca, nunca, nunca perder a bola e você vai ganhar cada vez.
>> Mas, na edição de hackers esta semana há mais do que apenas o modo de Deus.
Há uma série de outros recursos.
Entre eles, os lasers.
Assim que se você realmente ficar impaciente você pode começar a derrubar os tijolos
e alguns outros.
E para aqueles de vocês que gostaria de calibrar padrão contra hackers
edição, eu posso ver que esta semana edição hackers deliberadamente é um
pouco mais factível, por exemplo, do que a Deus modo foi com Game of Quinze.
>> Então, se você está procurando um trecho e você está procurando um pouco de diversão adicional
características fazem do mergulho em caso de interesse.
Agora, mais prático, deixe-me apontar fora uma coisa assim.
GDB, que alguns de vocês podem não ter ainda tocou pessoalmente, o que é bom.
Mas agora é realmente o tempo para se acostumar esta e confortável com esta ferramenta
porque ele vai fazer a sua vida muito mais fácil, realmente.
>> Por palestra de Rob em GDB um casal de semanas atrás, lembre-se
que GDB é um depurador.
É uma ferramenta que permite que você execute o seu programa, mas executá-lo passo a passo, linha
por linha, de modo que você pode picar ao redor, de modo que você vê as coisas acontecendo, então
que você pode imprimir Os valores das variáveis.
Em suma, dá-lhe muito mais energia do que printDef faz.
>> Agora é certo, a interface é muito misterioso.
Interface textual preto e branco na sua maior parte.
Os comandos são um pouco difícil lembrar em primeiro lugar.
Mas mesmo que isso pode levar metade uma hora, uma hora, para colocar esse adiantado
investimento de tempo para ele, confie em mim.
Certamente até o final do semestre vai economizar uma ordem de magnitude mais
tempo que.
>> Então, no início da semana mergulhar dentro
E em termos de Breakout, saiba que você pode fazer isso, desde que você tem
o código de distribuição ou de seu próprio código em andamento no seu diretório Pst4.
Saiba que você pode executar o gdb. / Fuga.
>> Isso vai abrir uma janela como esta.
Deixe-me dar-me mais de uma janela de terminal.
E então o que eu estou indo para ir em frente e fazer, não é só executá-lo.
Eu vou primeiro definir um ponto de ruptura recordação, o que permite que você pause
execução em um lugar particular.
>> Apenas para manter as coisas simples que eu vou para quebrar a linha de um apenas digitando
o número um.
Permitam-me, na verdade, re-abrir esta janela porque está ficando um
pouco pequeno lá.
Então o que eu estou indo agora para fazer aqui é se eu abrir minha janela terminal.
Vamos, lá vamos nós.
>> Portanto, agora se eu voltar para dropbox, Pst4 e execute gdb. / fuga entrar, observe
Eu vou quebrar um para definir um ponto de ruptura na linha um.
E agora eu estou indo para ir frente e tipo de correr.
E quando o faço, notar nada parece acontecer.
>> Não há pop-up.
Não há nenhuma gráfica interface com o usuário ainda.
Mas isso é compreensível, porque eu sou literalmente na linha um no meu programa.
E notem que eu rapidamente encaminhados, especificamente agora para 62, porque todos
as coisas no topo desse arquivo é coisas como comentários e constantes e
desinteressante coisas por agora.
>> Então agora eu estou dentro do principal, ao que parece, na linha 62.
E esta é apenas a distribuição código, recall.
Se eu abrir isso, indo, da mesma forma, em meu diretório caixa suspensa em Pst4,
em breakout.c.
E se eu rolar para baixo e para baixo e para baixo, e deixe-me ir em frente e ligar
meus números de linha.
>> O que eu vou ver se eu rolar para baixo para linha 62, é exatamente a linha que
nós já parou diante.
Portanto, esta linha aqui, 62 anos, é onde estamos prestes a ser.
Então, agora em GDB, se eu ir em frente e escrever agora seguinte, entrar ele vai
executar essa linha.
E pronto, temos a chamada janela g.
Se não estão familiarizados com o que um GWindow é, não se preocupe.
A especificação irá apresentá-lo a ele, como bem como um número de vídeos passo a passo
incorporado na especificação.
>> Mas agora vamos tornar este um pouco mais interessante.
Deixe-me passar essa janela sobre para o lado um pouco.
Deixe-me fazer a janela um pouco maior para que eu possa ver mais.
>> E agora deixe-me ir em frente e fazer em seguida novamente.
E lá estão os meus tijolos.
Se eu digitar junto novamente agora eu vejo a bola.
E se eu digitar em seguida novamente agora vejo o remo.
>> E, felizmente, isso não é gedit realmente cooperando por me mostrar
tudo que eu quero.
Mas agora, se eu fizer na próxima vez, próxima vez, eu sou apenas
declarar algumas variáveis.
E eu posso imprimir qualquer um desses caras.
Imprimir tijolos, gravuras vidas.
>> E agora, se eu continuar a fazer Em seguida, observe que eu vou ser
dentro desse circuito.
Mas o código vai executar exatamente como eu esperava.
Então, quando eu bati esta função, Espere para Click, que vai fazer
literalmente isso.
Então, eu parecia ter perdido o controle sobre o programa.
>> GDB não está me dando outro prompt.
Mas não se preocupe.
Ir para o meu jogo, clique em algum lugar.
>> E pronto, agora ele passa a linha 86.
Então, novamente, é de valor inestimável, em última instância, para problemas de depuração.
Porque você pode, literalmente, percorrer seu código, as coisas imprimir e muito,
muito, muito mais.
Mas por agora, essas ferramentas só deverá fazê-lo muito longe.
>> Então, nós estamos, é claro, dar uma olhada em gráficos, agora, de repente.
E agora o nosso mundo fica um pouco mais interessante.
E você sabe, talvez, de alguns dos vídeos on-line que temos estes
bermuda que você foi assistir como parte de conjuntos de problemas.
>> E eles foram baleados, deliberadamente, contra um fundo branco.
E alguns deles têm o ensino Fellows desenho algum texto na
tela que é sobreposto no lado deles.
Mas, claro, isso não é tudo o que interessante no mundo real.
Esta é apenas uma sala de aula com um grande tela branca e um pano de fundo.
E a nossa incrível equipe de produção tipo de faz tudo parecer bonito
após o fato cortando fora ou sobreposição de qualquer coisa
o que fazemos ou não quer.
>> Agora é só para motivar esta semana e realmente, onde você pode ir, em última instância,
com a ciência da computação.
Não apenas após problema definir quatro.
Mas depois de um outro curso ou um todo currículo é impressionante o que você pode
fazer nos dias de hoje em termos de gráficos, em particular.
>> Alguns de vocês podem ter visto isso flui ao redor online.
Mas eu pensei que eu ia mostrar, por apenas um alguns minutos, um vislumbre do que
informática e que CGI, computação gráfica pode fazer nos dias de hoje
com uma canção familiar e talvez o filme.
>> [MUSIC - LANA DEL RAY, "NOVO E BONITO]
>> COLUNA 1: É um pouco surpreendente, talvez, o quão
onipresente -
>> [Aplausos]
>> COLUNA 1: Eu só baixei.
Mas é realmente incrível, eu acho, apenas como o software onipresente e código e
ferramentas como esta são realmente.
Então, isso é um gosto da direção em que você pode ir.
Oh, não mais Appliance hoje.
Bem, isso é tempo realmente trágico dado o ponto que eu apenas tentei fazer.
>> Tudo bem, então vamos lançar Fusão novamente.
Lembre-me mais tarde.
Tudo bem, e você deve ter conseguido um enviar e-mail como um aparte, se você não obter um
perceber como esse.
Tudo bem, então lembrar que na semana passada começamos a descascar este
mais tarde conhecido como string.
>> cadeia lembra um tipo de dados que é declarados na biblioteca CS50.
E é parte das rodinhas que agora vai começar a decolar.
Era um conceito útil no início.
Mas agora vai ficar mais interessante e mais poderoso para
realmente ver que debaixo do capô, uma string é apenas o que, não podemos dizer?
>> Sim, por isso é um chamado char *.
E o * não denota que não há algum tipo de endereço envolvidos.
E assim, quando você diz char * que você acabou de dizer uma variável cujo tipo de dados é um
ponteiro agora.
O fato de que há a estrela lá Significa apenas que você está declarando uma
assim chamado ponteiro.
E esse ponteiro vai, aparentemente, armazenar o endereço, de
Claro, um char.
>> Agora, por que isso faz sentido?
Bem, o que é uma string debaixo do capô?
Bem, há algum tempo que venho dizendo que uma corda debaixo do capô é
apenas h-p-l-l-o, por exemplo.
>> Mas nós já conversamos sobre isso como sendo, essencialmente, uma matriz.
E uma matriz, então, olhar um pouco mais como este, com cada um desses
ocupando uma mordida.
E então nós dissemos que não há algo especial para cá, o
barra invertida 0, ou terminador nulo.
>> Então todo esse tempo, isso aqui tem sido uma string.
Mas, realmente, uma string é na verdade, um endereço.
E endereços, como veremos, muitas vezes são prefixado com 0x por convenção.
O que 0x denotar?
Alguém sabe?
>> Então, isso significa apenas hexadecimal.
Então, você deve se lembrar, na verdade, a partir de Pst 1, eu acredito, uma das warm-up
questões realmente perguntado sobre notação hexadecimal além
binário e decimal.
E o que é aqui motivação com hexadecimal você tem 16
dígitos à sua disposição.
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, seguido por a, b, c, d, e, f.
>> E se você contar todos aqueles acima, você recebe um total de 16.
Assim, isto está em contraste com decimal, onde temos 10
dígitos, 0 a nove.
É, em contraste com o binário onde temos apenas 0 e 1.
>> Mas no final do dia, você pode apenas representam os mesmos números, mas
um pouco diferente.
E hexadecimal é comum porque, como acontece que - e vamos ver isso
mais tarde no curso - mesmo quando chegarmos a programação web no contexto da
HTML e códigos de cores, hexadecimal é bom.
Como cada dígito, despeja, representa quatro bits perfeitamente.
Por isso, apenas uma espécie de linhas até bem como vamos finalmente ver.
Então, isso pode ser Ox123 ou algo assim, denotando endereço 123
em algum lugar dentro do meu memória do computador.
>> Mas, claro, surgem alguns problemas devido a esta subjacente
implementação.
E lembro que eu levei uma facada implementação de uma função como esta -
comparar traço 0 ponto c na semana passada, que mesmo que parecia que era
direito, ele simplesmente não comparar duas cordas corretamente.
>> Eu joguei fora principal, e eu joguei embora os comentários só para se concentrar em
o código que é de interesse aqui.
E é em vermelho porque é buggy.
Por que razão?
>> Bem, no topo lá quando eu declarei uma corda, o que realmente estava acontecendo
debaixo do capô?
Bem, deixe-me ir para o tela aqui e chamar a isso.
Então eu declarou, mais uma vez, GetString string s.
>> Então, eu estou indo para ir em frente agora e desenhar s para o que ele realmente é.
Vai ser uma praça aqui.
E eu vou reclamar que isto é 32 bits.
Pelo menos é geralmente, pelo menos na CS50
aparelho em um monte de computadores.
Vou chamá-lo s.
>> Mas, agora, lembrar que nós chamado GetString.
Retornos Então GetString, claro, uma string.
Se o usuário digita h-e-l-l-o entrar a string Olá será devolvido.
E essa string, como acabamos de dizer, termina em algum lugar na memória do seu computador
0 com uma barra invertida no final.
Eu vou tirar isso como a matriz - ou bloco contíguo de personagens -
que ele realmente é.
>> E agora, o que é GetString realmente voltando?
Qual tem sido getString retornar todo esse tempo?
Bem, podemos dizer, na semana anterior, ele retorna um string.
Mas, mais tecnicamente, o que faz GetString retorno aparentemente?
>> AUDIÊNCIA: um endereço.
>> COLUNA 1: Um endereço.
Especificamente, ele retorna o endereço de a primeira mordida, seja ele qual for.
Eu continuo usando um, dois, três porque é conveniente.
>> Devolve o endereço do primeiro caractere na seqüência.
E nós dissemos na semana passada que que é suficiente.
Porque sempre podemos descobrir onde o fim da cadeia apenas por
iteração sobre isso, talvez, com a loop ou um loop while ou algo parecido
que, só de olhar para "barra invertida 0", o caráter sentinela especial.
>> E então nós sabemos que a cadeia passa a ser de comprimento -
neste caso -
cinco.
Então, tecnicamente o que faz GetString é ele retorna Ox123 neste caso.
E tecnicamente o que acontece então é que nós guardamos, dentro de s, Ox123.
No final do dia, embora esta é conceito novo, ponteiros, eles são
apenas variáveis.
Mas eles acontecem para armazenar bits que coletivamente representam um endereço.
Então, tecnicamente tudo o que fica armazenado em s é Ox123.
>> Mas nós, como seres humanos -
inclusive hoje em diante -
são realmente não vai se importar, normalmente, qual é o endereço real é
de algum pedaço de memória.
É só para baixo nível de detalhe para ser intelectualmente interessante.
Então, eu estou indo para desfazer isso.
E, ao invés, mais alto nível, basta dizer que quando estamos falando de ponteiros
Eu vou apenas chamar mais seta user-friendly que transmite a
mesma idéia e abstrai os indicação de que o real
endereço subjacente.
>> Agora, se voltar para o código, o que aconteceu na semana passada, se tivermos corda t
igual GetString?
Bem, se eu novamente, digite Olá dessa vez eu vou conseguir
outro pedaço de memória.
h-p-l-l-o invertida 0.
>> Mas porque eu chamei GetString uma segunda vez -
e eu sei que isso de olhar para o código fonte para GetString - mesmo
mas é coincidência que Olá foi digitado duas vezes, GetString não é
vai tentar otimizar e ser inteligente.
Ele só vai pegar outro pedaço de a memória do computador, que está
vai ser em outro endereço.
Vamos apenas dizer arbitrariamente 456.
>> E então o que é que vai voltar?
Vai voltar 456 e armazená-lo em t.
Então, o que realmente está acontecendo, sobre o lado esquerdo é que eu tenho um outro pedaço
de memória de 32 bits normalmente.
E lá está a ir Ox456.
Mas, novamente, eu não estou interessado nestes números específicos digitamos mais.
Eu só vou abstratamente desenhá-lo como uma seta.
>> Portanto, esta é agora uma nova explicação.
Mas é exatamente a mesma idéia que é vem acontecendo todo esse tempo.
E assim, a razão, então, que este primeiro versão de comparação foi buggy
na semana passada, é por quê?
Quando você se s é igual a igual t O que você está verdadeiramente
debaixo do capô comparando?
>> Você está comparando os endereços.
E, assim, intuitivamente, claramente, Ox123 não vai igual Ox456.
Esses números, esses bits são apenas diferentes.
>> E assim, de forma consistente, na semana passada, ele disse você digita coisas diferentes, mesmo que a
palavras foram literalmente o mesmo.
Então vamos corrigir isso.
Em termos leigos, o que era a correção?
>> AUDIÊNCIA: Use uma função.
>> COLUNA 1: Usar uma função.
Ou estrelas estão definitivamente envolvidos, mas usar uma função para fazer o quê?
>> AUDIÊNCIA: Para comparar as cordas.
>> COLUNA 1: Para comparar as cordas.
Assim, o problema fundamental aqui foi que eu estava apenas considerando a
qualidade de cordas a ser definido pela comparação de seus endereços.
E, obviamente, isso é apenas mudo agora uma vez Você entende o que está acontecendo
debaixo do capô.
Para comparar verdadeiramente cordas para ver se eles são iguais na maneira que um ser humano
consideraria duas cordas para ser igual é preciso compará-los caráter para
personagem para personagem.
>> Agora eu poderia ter feito esta muito tedioso.
Mas familiarmente, estamos usando um loop for.
E basta comparar s suporte i contra t suporte i.
s suporte de i + 1 contra t suporte i + 1, e assim por diante, para dentro
uma espécie de loop.
E se eu detectar quaisquer dois personagens que diferentes, ou se eu perceber que ooh, s é
mais curta do que t ou mais que t Posso dizer imediatamente falso,
eles não são a mesma coisa.
>> Mas se eu passar s e t e dizer mesmo, mesmo, mesmo, mesmo, mesmo, o fim de
ambas as cordas, o que posso dizer verdade, elas são iguais.
Bem, felizmente, anos atrás, alguém escreveu que o código para nós.
>> E eles chamavam isso SeqComp para cadeia de comparar.
E mesmo que seja um pouco contra intuitiva, StrComp retorna 0 se os
duas cadeias, s e t são o mesmo.
Mas ele retorna valor negativo se s deve vir antes de t em ordem alfabética ou
valor positivo se deve vir depois de t em ordem alfabética.
>> Então, se você quiser resolver alguma coisa, verifica-se que SeqComp é útil.
Porque não basta dizer sim ou não, iguais ou não.
Ele lhe dá um senso de ordenação como uma força dicionário.
Então SeqComp, s vírgula t é igual a é igual a 0 significa que o
cordas são verdadeiramente iguais.
Porque quem escreveu esta função anos atrás, presumivelmente utilizado um loop
ou um loop while ou algo parecido para integrar mais os personagens novamente
e de novo e de novo.
>> Mas dois problemas surgiram aqui.
Este foi copy0.c.
E os dois está no vermelho porque é falho.
E o que fazemos aqui?
Bem, primeiro eu liguei GetString.
E eu guardei o valor de retorno em s.
Então, isso é praticamente o mesmo que esta parte superior da imagem.
>> Mas o que vem depois disso?
Bem, deixe-me ir em frente e se livrar de um monte de presente.
Vamos voltar no tempo para onde nós apenas tem s, que agora é consistente com
uma linha lá em cima.
>> Eu verifico.
Se s é igual é igual a 0.
Agora, uma nota lateral rápida, quando GetString pode retornar 0?
Não há memória suficiente.
Certo?
>> É raro que isso vai acontecer, certamente em um computador que é
tem centenas de megas ou mesmo GB de RAM.
Mas poderia, em teoria, o retorno 0, especialmente se o
usuário não cooperar.
Há maneiras de fingir que você não tem qualquer coisa digitada e truque
GetString em retornar 0 eficazmente.
>> Então ele vai para procurar isso.
Porque se algum de vocês já começaram a se, já, falhas de segmentação -
que provavelmente tem sido uma fonte de alguma frustração -
esses são quase sempre o resultado de erro relacionada com a memória.
De alguma forma, você estragou tudo no que diz respeito a um ponteiro, mesmo se você não percebeu
houve um ponteiro.
Então você pode ter induzido a segmentação defeitos tão cedo quanto uma semana usando
algo como um loop ou um tempo loop e uma matriz por ir longe demais
além dos limites da matriz que alguns você declarou, em duas semanas, em
particular.
>> Você pode ter feito isso mesmo problema definir quatro com Breakout.
Mesmo que você provavelmente não viu nenhuma estrela no código de distribuição para
Breakout, verifica-se que os GRect e Goval e outras coisas que tais,
esses são realmente os ponteiros debaixo do capô.
>> Mas Stanford, como nós, tipo de peles esse detalhe, pelo menos para as bibliotecas
propósitos, muito parecido com o que fazemos para string e char *.
Mas GRect e Goval e de todos aqueles coisas que vocês estão ou estarão usando
esta semana são em última análise, endereços de memória.
Você simplesmente não sabe.
>> Portanto, não é surpreendente, então, talvez, que você pode tropeçar em algum
falhas de segmentação.
Mas o que é interessante aqui agora, Se depois de verificar 0 que fazemos
corda t fica s.
Bem, deixe-me declarar t.
Vou desenhá-lo como um quadrado, 32 bits, chamá-lo de t.
E então eu vou fazer se s.
>> Bem, o que isso significa?
Bem, é um pouco difícil pensar nisso imaginar sábio.
Mas vamos pensar sobre o que está dentro de x?
O que é, literalmente, dentro dessa variável?
O valor Ox123.
>> Portanto, quando digo corda t fica s, que apenas literalmente significa ter o número
em s, que é Ox123 e colocá-lo Ox123.
Ou pictoricamente, se eu tipo de abstrato longe desse detalhe tem o
efeito de literalmente fazer isso também.
>> Então, agora, acho que volta a semana passada, quando procedeu-se capitalista T. I
fez T suporte 0.
Bem, T suporte 0, mesmo que seja um ponteiro, você pode tratá-lo como se
é uma matriz, com um quadrado notação suporte.
>> Então, onde está T suporte 0?
Bem, é o h.
E assim, quando usamos essa linha de código, dois superior, que está em que c type.h
arquivo de cabeçalho, que é onde ele é declarado.
Você está capitalizando esta H. Mas, Claro, isso é exatamente o mesmo que h é
s no interior de, por assim dizer.
E agora você mudou ou capitalizados tanto o original eo
chamado de cópia.
Porque você não faz uma cópia na forma que um ser humano quer que seja.
>> Então, qual foi a correção aqui, em copy1.c na semana passada?
Funções, para que pudéssemos realmente copiar o string.
E, fundamentalmente, o que precisamos fazer para copiar a seqüência?
>> Bem, nesta versão verde aqui estou vai fazê-lo muito baixo nível.
Na verdade, existem funções eles poderiam ajudar com isso.
Mas o mais básico eo mais um familiar, pelo menos, em breve será
familiar para nós, é o seguinte -
assim um na primeira linha do código em verde agora.
>> Eu só reescreveu s como char *.
Não há nenhum funcional diferença lá.
Eu só joguei fora a biblioteca e CS50 Eu estou chamando-o que é, um char *.
>> Agora, ponto, ponto, ponto, porque não havia verificação de erros que não é
interessante para falar novamente.
Então, agora t é declarada.
Ele também é um char *.
Então eu desenhei uma pequena praça em a tela como antes.
>> Mas, no lado direito, malloc, dissemos é alocar memória.
Então alocar algum pedaço de memória.
E quantos bytes é que vamos realmente pretende atribuir, não parece?
>> Bem, o comprimento da cadeia de s.
Então, se é que é Olá vai ser cinco.
Vamos dizer h-e-l-l-o.
Assim, cinco bytes.
>> Mas, então, mais uma, por 1?
O 0 personagem.
Se não deixar espaço para esse cara que acidentalmente pode criar uma situação
onde a corda é h-e-l-l-o.
E, em seguida, a próxima vez é GetString chamou e eu digitar, por exemplo,
David, D--v-i-d, o computador vai pensar que s é realmente
h-p-l-l-o-d-a-v-i-d, porque há sem pausa entre as palavras.
>> Por isso, precisamos que pausa.
Então, não queremos que cinco.
Queremos seis bytes.
>> E bytes que eu digo.
Mas é o tamanho realmente o tempo do char.
Tecnicamente char é quase sempre um byte.
>> Mas apenas para fazer o nosso código portátil, por assim dizer, de modo que ele funciona em
computadores diferentes, mesmo se eles podem ser um pouco diferente por baixo do
capa, eu vou genericamente dizer o tamanho do char para que
meu código sempre funciona.
E eu não tenho que recompilar apenas porque eu atualizar meu computador ou utilizar
uma plataforma diferente.
>> Então eu tenho seis vezes o tamanho da um char, que passa a ser 1.
Então isso significa que malloc poderia me dê seis bytes.
O que é que realmente está fazendo?
Bem, deixe-me retroceder no tempo aqui onde estamos na história.
>> Então, se eu voltar aqui, eu já declarou um char * chamado t.
Eu já chamado malloc por seis bytes.
E agora eu vou chamar os seis bytes assim como a matriz anterior.
Mas eu realmente não sei o que é dentro dessa matriz.
>> Se você alocar memória verifica-se que você não pode confiar que há algum
valor conhecido ali.
Podia ter sido utilizado por algo outro, uma outra função, alguma outra
linha de código que você escreveu.
Então, vamos chamar estes geralmente lixo valores e desenhá-los, talvez, como
pontos de interrogação, indicando apenas que não sei o que está realmente lá.
E isso não é grande coisa contanto que são inteligentes o suficiente para substituir aqueles
valores de lixo com números ou caracteres que se preocupam.
>> Portanto, neste caso o que eu vou fazer?
Bem, a minha linha de código seguinte, eu tenho quatro.
int i obter 0, n recebe o comprimento da corda de s.
Assim, um familiar para o loop.
I é menor ou igual a n, que é geralmente acima.
>> Mas desta vez é deliberada.
I + +, e então eu simplesmente fazer t suporte i fica s.
Porque a minha imagem se parece com isso a Neste momento, armazenado em que t é o
endereço dessa pedaço aleatório de memória cujos valores são desconhecidos.
Mas assim que eu faço t suporte 0 que me coloca aqui.
>> E o que acaba sendo atraídos para lá?
Nós acabam colocando h.
Porque isso é o que está em s suporte 0.
E, em seguida, a mesma coisa para e e, l, l, e o.
>> n, por que eu vou para cima através igual a n?
Devido ao seu carácter 0.
Então, só para ficar claro, então, se eu realmente apagará tudo o que estes lixo
valores e então realmente atrair o que eu espero, é s faixa 1, 2,
3, 4, além de que é à direita novo personagem.
>> E agora se continuássemos passado do ponto, ponto, ponto nesta versão correta
e capitalizados t suporte 0 eu iria, de Claro, se aproveitando apenas isso
cara aqui e que, conceitualmente, acabou por ser a meta.
Então, isso é tudo o ponteiro está.
>> E você tem de usá-los por semanas Agora, no contexto de cadeias.
Mas debaixo do capô são um pouco mais complexa.
Mas se você pensar sobre eles neste forma pictórica proponho que eles são
provavelmente não é tão assustador como eles primeiro pode parecer à primeira vista,
particularmente com essa nova sintaxe.
Qualquer dúvida sobre ponteiros, cordas, ou chars?
Sim?
>> AUDIÊNCIA: Você pode voltar para o [inaudível]?
>> COLUNA 1: Claro.
>> AUDIÊNCIA: Então como é que em sua última linha, você não tem uma linha de t *
e * s na linha?
Você não tem a referência para o -
>> COLUNA 1: Ah, uma pergunta muito boa.
Por que eu não tenho a * t * e uma s?
Porque brevemente, na semana passada, como no nosso função de trocar, eu disse que quando
você tem um ponteiro o meio pelo que você vai lá, como fizemos
fisicamente no palco, era, na verdade, usar o operador estrela.
>> Acontece que esta de colchetes notação é o que vamos chamar sintática
açúcar, que é apenas uma maneira sexy de dizendo que é notação abreviada para
exatamente o que você está descrevendo.
Mas é um pouco mais intuitivo.
E correndo o risco de fazer isso parecer mais complicado do que precisa ser,
o que realmente está acontecendo aqui é o seguinte -
Se eu disser * t que significa ir para o endereço armazenado em t.
>> Então, literalmente, se t está armazenando o endereço dessa h
Inicialmente, a * t meio aqui.
Agora, o que t suporte 0 significa?
Mesma coisa.
É apenas um pouco mais user amigável para escrever.
>> Mas eu não estou pronto ainda.
Eu não posso simplesmente dizer * t * s fica.
Porque o que eu estaria fazendo então?
Eu estaria colocando h, h, h, h, h toda a coisa toda.
Certo?
>> Porque * t é ir para o endereço em t.
Mas estamos dentro de um loop.
E qual o valor que eu estou incrementando, claro, em cada iteração?
i.
>> Mas há uma oportunidade aqui, certo?
Mesmo que isso parece que está ficando um pouco mais sofisticadas
que a notação de colchetes temos usado por algum tempo -
deixe-me desfazer minha mudança de h lá -
mesmo que isso agora está ficando um pouco extravagante, a idéia básica, se * t
significa aqui e * t é apenas ir para o endereço de t.
>> Mas qual era o endereço no t?
O número que continuar usando?
Como Ox456, vamos trazer isso de volta apenas por uma questão de discussão.
Bem, se eu quiser chegar ao e em t string, eu só quero ir,
essencialmente, 456.
>> Ou melhor, 457.
Eu só preciso adicionar uma.
Mas eu posso fazer isso, certo?
Porque t, apesar de eu manter desenho agora como uma flecha, é apenas um
número, Ox456.
E se eu adicionar um para isso, ou mais geralmente, se eu adicionar I para que eu possa
realmente chegar exatamente onde eu quero.
Então, se eu realmente fazer isso -
e isso é o que é chamado agora ponteiro aritmética -
Eu posso remover essa linha.
Qual é, francamente, eu acho que mais clara e um pouco mais amigável para ler.
Mas isso não é menos correto.
>> Esta linha de código está usando agora aritmética de ponteiro.
Ele está dizendo que ir para o seguinte endereço -
qualquer que seja o início do t é, que t é mais i, que inicialmente
é 0, o que é ótimo.
Porque o que significa o início do t mais 1, mais 2, mais 3, e assim por diante.
E a mesma coisa com s.
>> Então açúcar sintático para isso.
Mas a compreensão do que realmente está acontecendo debaixo do capô, eu diria,
é realmente útil em si mesmo.
Porque isso significa que agora não há muito mais magia acontecendo
debaixo do capô.
Não vão ser muitos mais camadas que podemos descascar para você.
Este é c.
E esta é a programação.
Pergunta muito boa.
>> Tudo bem, então isso foi que de buggy programa que eu estava me referindo anteriormente.
troca foi falho.
Se parecia funcionar.
Lembre-se que, assim como com o leite e o suco de laranja - que eu comecei a
beber manifestação de hoje.
Assim como com o suco de laranja e o leite, que teve de usar uma
variável temporária, tmp, para realizar uma temporariamente, para que pudéssemos então
alterar o seu valor e, em seguida, atualizar b.
>> Mas essa função, como dissemos, ou esta programa no qual essa função é
escrito estava errado e falho, por quê?
Sim?
>> AUDIÊNCIA: [inaudível].
>> COLUNA 1: Exatamente, quando vocês chamam de troca -
ou, mais geralmente, quando chamar mais qualquer função -
se os argumentos para essa função são primitivas, por assim dizer, ints e chars
e duplas e carros alegóricos, as coisas sem estrelas, você está passando uma cópia do
o argumento.
Portanto, se x e y era uma era de 2, um vai a ser 1 e b vai ser 2.
Mas eles vão ser diferentes pedaços de bits, diferentes blocos de
memória que venham a ser armazenando valores idênticos.
>> Portanto, este código é super perfeito em troca de a e b.
Isso não é bom em troca -
no exemplo da semana passada -
x e y.
Porque mais uma vez, eles são no âmbito incorrecto.
>> Agora, como é que nós vamos sobre a fixação isso?
Tivemos que fazer a função olhar um pouco mais feio.
Mas, novamente, considerar o que isto significa apenas.
>> E, na verdade, deixe-me, por coerência, mudar uma coisa assim que é idêntico ao
o que nós fizemos.
Como eu mencionei na semana passada, ele não importa para onde vai.
Na verdade, normalmente você iria colocar o estrela ao lado do nome da variável.
Mas eu acho que seria um pouco mais fácil considerar a * junto da
tipo de dados que significa que é um ponteiro para um int neste caso.
>> Então, o que eu estou fazendo aqui?
Eu estou dizendo que não me dê um int seguido por outro int
chamando-os de a e b.
Dê-me o endereço de um int.
Dê-me o endereço de outro int.
Chame aqueles aborda a e b.
>> E, em seguida, usando a notação * baixo abaixo, vá para cada um desses endereços
conforme necessário para obter qualquer ou definir o seu valor.
Mas há uma exceção aqui.
Por que eu não tenho um * junto tmp?
Por que eu não faço isso, por exemplo?
Parece que eu deveria ir todos fora e corrigir a coisa toda.
Sim?
>> AUDIÊNCIA: [inaudível].
>> COLUNA 1: eu não declarei tmp como uma string.
Portanto, este deve declarar, neste caso, um tmp para ser o endereço de um int.
Mas isso não é bem o que eu quero, por um par de razões.
>> AUDIÊNCIA: Você não quer trocá-los.
>> COLUNA 1: Exatamente, eu não quero trocar nada com tmp. tmp é apenas
-de-semana uma coisa.
Tudo que eu quero é uma variável para armazenar um número.
Eu não me importo sobre endereços neste momento.
>> Eu só preciso de 32 bits ou para armazenar um int.
E eu quero colocar nesses 32 bits tudo o que não está em uma, por assim dizer, mas
o que está em um, apenas para ser mais preciso.
Porque se um é um endereço *, um meio ir lá e obter o valor 1.
Por exemplo, no exemplo da semana passada ou no caso de b, obter o valor de 2.
>> Então, o que está realmente acontecendo?
Deixe-me tirar uma foto aqui que vai apenas desmembrar parte de hoje.
Mas isso vai continuar a aparecer por algum tempo.
>> Isso, eu afirmo, é o do seu computador memória parece que quando você executar um
programa, qualquer programa.
Quando você executa um programa no topo de memória RAM do seu computador - para pensar
este retângulo, verdadeiramente, como seu RAM ou a memória do computador, todos os 101
bilhão de bytes dela, todos de dois bilhões de bytes, todos os dois gigabytes de que,
qualquer que seja a quantidade que você tem é, vamos desenhá-la como um retângulo.
E eu afirmo que quando você executar um programa como o Microsoft Word ou Chrome
ou qualquer coisa assim, os bits que Microsoft ou Google que escreveu -
nos casos dos referidos programas -
são carregados na memória do seu computador onde eles podem ser executados mais
rapidamente e alimentados na CPU, o que é o cérebro do computador.
>> E na TAM eles estão armazenados no próprio topo do seu programa, por assim dizer.
Em outras palavras, se este é um pedaço de memória, quando você clicar duas vezes sobre
Microsoft Word, os bits vir fora do disco rígido.
Eles são carregados na memória RAM.
E nós vamos empurrá-los para cima no topo desse retângulo conceitualmente.
>> Bem, o resto de sua memória é usado para coisas diferentes.
No topo você vê inicializar dados e uninitialize dados.
Isto tem a ver, em grande parte, com a constantes ou variáveis ​​globais
que têm valores.
Mas mais sobre aqueles outra vez.
>> Então você tem a pilha, que vamos voltar.
Mas no fundo é a parte que é particularmente pertinente neste momento.
É o chamado pilha.
Assim como em mais nenhuma sala D aqui na campus, você tem aquelas bandejas que
apenas empilhar uns sobre os outros em que você pode colocar alimentos e outros enfeites.
A pilha num sistema de computador é muito semelhante.
Exceto enquanto a bandeja, como usamos em a sala de jantar, é claro, se entende
para levar as coisas as bandejas ou os quadros -
como vamos chamá-los - em um computador de memória é usado para armazenar
variáveis ​​e valores.
>> Então, o que realmente se passa debaixo do capô?
Bem, deixe-me virar para a tela aqui.
E vamos nos concentrar apenas no parte inferior por um momento.
Se isto é a porção inferior da minha memória do computador acontece quando eu
chamar a função principal - que acontece, francamente,
automaticamente para mim -
Recebo um bloco de memória no fundo da minha memória RAM por assim dizer.
E é aí principal é variáveis ​​locais ir.
É onde argc e argv talvez ir, e todas as variáveis ​​I
declarar dentro do principal.
Eles acabam no fundo de RAM do meu computador.
>> Agora, suponha que o principal chama uma função como swap, como fez na semana passada?
Bem, essencialmente, colocar um novo tabuleiro, um novo quadro, no meu pedaço de memória.
E eu vou descrever isso como pertencentes à função swap.
>> Agora, o que está dentro de swap?
Bem, com base no programa da semana passada e o que acabamos de ver um trecho,
dentro da estrutura de swap, ou troca de bandeja, o que são variáveis?
Bem, a e b.
Porque aqueles eram seus argumentos locais, além de um terço, tmp.
Então, realmente, eu poderia desenhar esse um pouco mais limpa.
Deixe-me ir em frente e desfazer o rótulo.
E deixe-me dizer que você sabe o quê?
>> um provavelmente vai acabar aqui.
B vai acabar aqui.
E tmp vai acabar aqui.
Agora, a ordem pode ser um pouco diferente.
Mas conceitualmente essa é a idéia.
>> E só coletivamente, isto é o que vamos chamá-estrutura de swap, ou
bandeja de refeitório.
E a mesma coisa com o principal.
Mas eu não vou redesenhar isso.
Mas é aí que argc e argv e qualquer das suas variáveis ​​locais, como x e y
Pode ser assim.
>> Então agora considerar o que realmente está acontecendo quando você chama swap.
Quando você chama swap, o código executado como isso, você está passando, no
versão com bugs, a e b como cópias de x e y.
Então, se eu faço agora desenhar esse na tela -
tem que ficar melhor com isso -
assim a história que eu estava dizendo para mim mesmo Foi nesta versão com bugs, quando
chamar trocar passando literalmente a e b como inteiros, o que está realmente acontecendo?
>> Bem, o que está realmente acontecendo é isso.
Deixe-me ir em frente e desfazer apenas para limpar algum espaço aqui.
Portanto, esta é a memória do meu computador.
>> Então, se eu tiver, por exemplo -
na verdade, vamos fazê-lo desta forma -
se eu afirmar que esta é x, armazenando o valor 1, assim como na semana passada.
E isto é y, armazenando o valor 2 assim como na semana passada.
E isso é o principal, quando eu chamo swap, dando-me, assim, o acesso a um e
b e tmp, eu vou afirmar que este é um e este é um.
>> Este é b.
Esta é 2.
Isto é chamado tmp.
>> E, inicialmente, tem algum valor lixo até que eu realmente armazenar nele um,
que é 1.
Então eu vou em frente e mudar a ser o que?
Valor de B.
>> E agora eu tenho dois aqui.
E então nós dissemos b fica tmp.
Mais uma vez, assim como uma verificação de sanidade, o terceiro linha de código aqui é simplesmente isto
um, b fica tmp.
>> E assim, finalmente, o que eu faço?
Eu vou em frente e mudar b para ser o que o valor de TMP é, o que é um.
Eu não toco tmp novamente.
>> Mas agora, o problema é que assim como swap retorna, porque não está entregando
voltar algum valor, não há retorno instrução explicitamente na mesma.
O que está realmente acontecendo?
Bem, essencialmente, tudo isso de memória -
OK, aparentemente, a borracha gosta apenas um dedo de cada vez -
simplesmente desaparece.
>> Agora, na realidade, não é vai a lugar nenhum.
Mas você pode pensar nisso agora, como pontos de interrogação.
Porque ele não é mais realmente em uso.
E nada é feito com esses valores.
>> Assim, no caso da versão verde esse código, que está a ser, em vez
passou para swap?
Então resolve.
Assim, o endereço de xe o endereço do y.
Então, se nós re-contar a história de um passado tempo, e eu realmente chamar a troca novamente,
mas com ponteiros, sendo este um, isto sendo b, e sendo esta tmp, o que é
realmente armazenados em um nesta verde versão do meu código onde eu estou passando
em endereços?
>> Vai ser um ponteiro para x.
Então, eu poderia desenhar uma seta.
Mas vamos usar o mesmo arbitrária exemplo, como antes.
Digamos que este é algo como Ox123.
E isso vai ser Ox127 porque é quatro bytes para longe, porque é uma
Cont, tão Ox127.
>> E novamente, eu estou tomando algumas liberdades com os números.
Eles são muito menores do que seria e, na verdade, ser numa ordem diferente.
Mas é assim que a imagem agora é diferente.
>> Mas quando eu uso esse código verde e eu int tmp conseguir * a.
* Um meio para fazer o seguinte, pegue a resolver isso em um e ir para ele,
que é 1.
E isso é o que eu, em seguida, colocar em tmp.
Enquanto isso, na próxima linha de código aqui, * a recebe b, o que isso significa?
>> Bem, * a, por isso aqui fica * b, o que significa ir para lá.
E isso significa colocar o valor lá.
Finalmente, a última linha de código disse simplesmente * b recebe tmp.
>> Então b diz para ir lá e substituí-lo com tmp que, neste caso, vai
para ser, de novo, 1.
E é por isso que a versão verde de nossas obras de código, enquanto que o vermelho
versão nunca fez.
Tudo isso só se resume à forma como o memória é gerida e onde é
realmente colocado em seu RAM do computador.
E, por enquanto, isso é uma das coisas que a pilha está sendo utilizado.
>> Perguntas sobre o layout?
Em ponteiros?
Ou em swap?
>> Tudo bem, então malloc, aviso, fez algo parecido com isso.
Este foi um super exemplo simples.
E isso foi o que Binky nos apresentou, ainda que bastante
rapidamente, no final da classe.
Droga, lá vamos nós de novo.
>> Então, lembrar que este foi o exemplo que Binky nos apresentou, embora
um tanto rapidamente no fim da classe.
E aqui nós usamos malloc realmente , pela segunda vez.
Porque a primeira vez que é usado para criar RAM suficiente, alocar memória RAM suficiente
para armazenar uma string.
>> Desta vez Binky manteve simples.
Então é para armazenar apenas um int, aparentemente.
E isso é totalmente bom.
É um pouco estranho, francamente, para usar malloc para alocar um int.
Mas o ponto de claymation do Nick foi realmente apenas contar a história do que
acontece ou não acontece quando você maltratar memória.
>> Portanto, neste caso, este programa fiz algumas coisas.
No primeiro caso, aqui, que declara um ponteiro chamado x para um int.
Em seguida, ele declara um ponteiro chamado y para um int.
Em seguida, armazena em x, o quê?
Alguém agora.
O que fica armazenado em x de acordo com a a terceira linha deste programa?
>> AUDIÊNCIA: [inaudível].
>> COLUNA 1: Bem, não exatamente bytes, por assim dizer.
Ser mais preciso agora.
O que fica armazenado em x?
Um endereço, eu acho que ouvi-lo.
>> Então, o que malloc retornar?
malloc aloca comportamentalmente um pedaço de memória.
Mas como isso dá-lhe acesso a ele?
Ele retorna o quê?
O endereço do primeiro byte no pedaço de memória.
>> Agora, isso é super simples.
É apenas um byte, que significa que o abordar estamos ficando para trás é o
endereço da coisa toda.
Então armazenado em x, então, é o endereço desse pedaço de memória.
Enquanto isso, o que acontece?
Então, na verdade, vamos em frente e chamar isso muito rápido.
>> Então, se passar para a tela aqui e vamos jogar isso int * x e y int *
vai fazer o que para mim?
Eu afirmo que ele só vai fazer algo como isso e chamá-lo de x, e
isso e chamá-lo de y.
Enquanto isso, a terceira linha de código é vai afectar o tamanho de um int
que passa a ser - desculpe se eu dissesse um antes que eu quis dizer um int -
quatro bytes em um computador típico.
Pelo menos com o aparelho CS50.
>> Então, isso vai alocar , quem sabe?
Em algum lugar por aqui.
E esta é armazenada em algum endereço de Boi, quem sabe?
Mas o que está acontecendo para se voltou é esse endereço.
Mas vamos tirar isso pictoricamente apenas como uma flecha assim.
>> Agora, na próxima linha * x recebe 42.
O que * x significa em termos leigos?
Basta ir lá.
Vá para esse endereço.
Ou, por outras palavras, a seguir seta e colocar 42 lá.
Mas então algo de ruim aconteceu para Binky, certo?
>> Lembre-se de que a linha cinco aqui, * y recebe 13, na verdade um número de azar,
fez o que para nós?
Bem, * y significa ir até lá.
Bem, este não tem sido dada ainda um valor, certo?
O código não tem y sendo inicializado para nada.
Tínhamos x sendo inicializado para um endereço.
Mas y foi declarado em cima.
Mas, então, um ponto e vírgula, sem valor foi realmente colocar nele.
Portanto, é justo chamar esta um valor de lixo.
Quem sabe o que é?
São os restos de bits que foram utilizados por alguma linha de código anterior em
meu programa.
>> Então, se eu disser que ir lá, isso é como, Eu não tenho nenhuma idéia de onde essa seta é
vai acabar.
E é aí que você normalmente obter uma falha de segmentação.
Se você acidentalmente desreferenciava, por assim falar, ou ir para um endereço que não é
na verdade, um endereço legítimo, coisas ruins acontecem.
>> E isso é exatamente o que aconteceu pensar Binky.
Então, lembrar que a história de que Nick era dizendo aqui foi a mesma idéia que o
Eu desenhei com a ilusão de giz no quadro lá.
X e Y são declarados.
>> Em seguida, atribuído ao tamanho dos um int e armazenado em x.
Em seguida, a próxima linha que fizemos * x.
Esta foi a varinha mágica de Nick de dereferencing.
Que colocou 42 na memória apontado por x.
>> Mas este é o lugar onde as coisas deu terrivelmente errado.
Certo?
Tentamos desreferenciava y.
Mas y tinha algum valor falso, certo?
>> Que a seta no canto inferior esquerdo canto, não é
na verdade, apontando para qualquer coisa.
É uma espécie de fazer o que eu fiz aqui no conselho.
Então, as coisas ruins acontecem, a segmentação falha ou avaria Chupeta, neste caso.
>> Mas se, em seguida, corrigir isso, fazendo x fica y como é que a mudança de história?
Bem, se eu fizer x recebe y, que é efetivamente o mesmo que dizer
o que é isso, Ox-algo vai ser a mesma coisa aqui,
Ox-alguma coisa.
Ou pictoricamente vamos desenhar uma seta.
>> Então, aqui na placa com Binky, com a próxima linha de
código, * y significa ir até lá.
Onde é que há?
Significa aqui.
>> E quando nós atualizamos que ser 13 que envolve apenas indo e
13 escrever aqui agora.
Por isso, talvez não completamente simples à primeira vista.
Mas para recapitular e usar o mesmo jargão que Binky estava usando aqui, então
os dois primeiros alocar os ponteiros, x e y, mas não os pointees.
E pointees não faz geralmente utilizado prazo.
Mas é absolutamente ponteiro.
Mas é o que está sendo apontado no da nomenclatura de Binky.
>> Esta próxima linha, é claro, aloca um pointee int.
Assim, um pedaço de memória - como atraiu mais em o lado direito lá - e um conjunto
x igual a apontar para ele.
Este desreferencia x para armazenar 42 em a memória que ele está apontando.
E depois disso, é claro, era uma coisa ruim.
Porque y não estava apontando em nada ainda.
Isso resolve o problema.
Portanto, este ainda é o programa de buggy.
Só porque estamos soprando através do código linha por linha e dizer: oh bem,
deixá-lo cair lá.
Isso é uma coisa ruim.
As probabilidades são o programa só vai interromper completamente a essa linha.
Mas se você fosse para remover o acidente de linha e substituí-lo com os dois últimos
linhas lá você atribui -
com atribuição de ponteiro - y para apontar para x como ponto de t.
E então você desreferenciava y de uma forma muito segura.
>> Então onde é que isto nos deixa?
Bem, acontece que debaixo do capô na biblioteca CS50, os ponteiros são
utilizado ao longo.
E nós vamos realmente começar a descascar de volta a camada antes do tempo.
Mas acontece também, uma expressão que alguns de vocês podem estar familiarizados com,
particularmente aqueles mais confortável, que é na verdade de uma muito popular
website, ou estouro de pilha, nos dias de hoje.
>> Mas isso realmente não tem muito significado técnico.
Sabemos agora que a pilha é.
É como uma pilha de bandejas dentro de uma sala de jantar.
>> Ou dentro do seu computador de memória its os quadros
que são utilizados por funções.
Bem, acontece que por causa disso muito simples implementação de
memória e dos quadros na chamada empilhar, você pode realmente assumir o controle
de um sistema de computador com bastante facilidade.
Você pode invadir um sistema, se as pessoas como nós não escrevemos o nosso código
particularmente bem.
>> Se pessoas como nós usamos pedaços de memória ou usar matrizes -
ainda mais comumente -
mas às vezes se esqueça de verificar a limites de nossa matriz como você pode
tem-se, por vezes, e reiterou muito longe após o final de um array.
Na melhor das hipóteses, o seu programa só poderia falhar.
Falha de segmentação, tipo constrangedor.
Não é ótimo, mas não é necessariamente uma coisa extremamente ruim.
>> Mas se o seu programa é realmente a verdadeira computadores dos usuários, se ele está funcionando
em um site que as pessoas aleatórias reais na internet estão batendo, deixando
pessoas induzir coisas ruins em seu código é geralmente não é uma coisa boa, porque
isso significa uma oportunidade para tomar o controlo do computador.
E isso vai ficar um pouco enigmática.
Mas eu pensei que eu iria assustá-lo com Neste último exemplo aqui.
>> Aqui está um exemplo de código.
E há uma boa Wikipedia artigo que percorre
isto com mais detalhe.
Tenho principal no chamado fundo foo, passando argv de 1.
E isso é apenas para que você possa executar o programa e passar
uma entrada arbitrária.
>> E então foo é declarado em cima como aceitar uma string, ou mais
precisamente, um char *.
Em seguida, ele declara uma matriz de caracteres.
Chamá-lo de um buffer, de modo mais geral, de tamanho 12.
Então, 12 caracteres pode caber dentro desse array chamado c.
>> E então ele usa essa nova função, que é novo, mas não é difícil
entender, cópia de memória.
Ele copia a memória do bar, que era passado variável n, seja qual for o
usuário digitou em uma argv em c.
Quantos bytes?
O comprimento da corda de bar.
>> Portanto, em outras palavras, se o usuário digita em h-e-l-l-o enter, o comprimento da corda
Olá é de cinco anos.
Então, cinco desses bytes vai ficar copiado para o array chamado c, que
é de tamanho 12.
Mas o que o usuário digita em um tempo muito mais palavra que é de 13 caracteres ou 14
caracteres ou 100 caracteres ou mais?
>> Onde eles estão indo?
Bem, esse quadro, que a bandeja na pilha de refeitório,
eles estão indo para lá.
E isso só vai começar a substituir outras coisas que já está
nessa pilha, transbordando da pilha, por assim dizer.
>> Então, pictoricamente, pense nisso dessa forma.
Esta é apenas uma versão colorida de a imagem que estamos desenhando.
Na parte inferior, digamos, é o principal.
E na parte superior, o que você está vendo agora é o quadro, codificados por cores agora, por um
função chamada foo.
Mas o que é interessante aqui sobre foo é que aqui é o seu quadro.
Então, ele é desenhado como eu fez, mas em azul claro.
E agora esse é o lugar onde c suporte 0 vai.
E é aí que c suporte 11 vai acabar.
>> Em outras palavras, isso acontece ser representado como um quadrado.
Mas se você apenas manter estatelando bytes para baixo - ou caracteres - eles vão acabar
se na posição 0 todo o caminho até a 11 porque é 0 indexado.
>> Mas onde está o caráter 13 vai acabar?
Cadê o 14?
Onde está o caráter 50 vai acabar?
>> Ele vai continuar a descer.
Porque mesmo que tenha desenhado o imagem com a pilha crescendo, o
endereços, verifica-se, ir de pequenas endereços, pequenas
ponteiros, para grandes endereços.
Então, ele simplesmente continua indo para cima e para cima.
>> Portanto, se o usuário digita em Olá, isso é ótimo.
No bug, não há problema, seguro de todos.
Mas se o usuário digita em que vamos chamar o código do contraditório, representado
genericamente como, ataque, ataque, ataque, ataque, o que pode acontecer?
>> Ora, se toda a entrada que o utilizador digitado não é apenas um amigável
ou string ofensiva de caracteres.
É, na verdade, uma sequência de caracteres que se compilou,
ele realmente é um código.
Talvez seja o código que exclui toda a arquivos em seu disco rígido ou envia spams
ou algo assim.
Observe que o que é importante aqui é que se o bandido teve sorte o suficiente para
substituir o pedaço vermelho de memória -
que eu não desenhei na minha imagem, mas esta imagem Wikipedia aqui tem -
seu chamado endereço de retorno.
>> Quando retorna de alimentos, quando retorna de swap, Como o computador sabe que ir de
aqui em cima até aqui em baixo?
Ou no segmento de tecnologia em cima, como ele sabe que vão desde a troca de
código - o 0 e 1 do que compõem troca -
de volta ao principal?
Há um chamado endereço de retorno armazenado no mesmo quadro de pilha, em
a mesma bandeja cafeteria.
>> Então, se o bandido é inteligente o suficiente para colocar um código de ataque, um código de ataque, ataque
código, e ter sorte o suficiente -
muitas vezes através de tentativa e erro - a sobrescrever o endereço de retorno vermelho,
com o endereço eo aviso o topo.
Observe 0835C080.
Está escrito para trás em cima de razões que vamos talvez revisitar.
Este número é o que.
>> Então, se o bandido tem sorte o suficiente ou é inteligente o suficiente para substituir o vermelho
tira de memória com o endereço de código que ele ou ela tem de alguma forma
injetado em seu computador, acho que quem código vai ser devolvido
assim foo é feito de execução?
>> Código do bandido.
Portanto, este código de ataque, AAA, mais uma vez, poder enviar spam, pode apagar todos os arquivos
em seu disco rígido.
Mas isso é o que realmente um estouro de pilha é, ou um estouro de buffer, ou um
ataque de estouro de buffer.
>> E é incrivelmente, incrivelmente comum para este dia com os programas escritos em
C, C + +, e até mesmo algumas outras línguas.
Na mesma nota assustador, vamos termina com uma piada.
>> [Risos]
>> Vejo você na quarta-feira.
Na próxima CS50 -
Então, eu estou fora de lâmpadas disco hoje, mas esperar, livre de gordura do leite, metade do telefone
livro, o suco de laranja que eu bebi hoje.
Cabo USB, uma chave inglesa.
>> [Música tocando]