>> [Música tocando]
>> DOUG LLOYD: Ponteiros, aqui estamos nós.
Este é provavelmente vai ser o tema mais difícil
que falamos em CS50.
E se você leu nada sobre ponteiros
antes que você pode ser um pouco intimidador entrar em um vídeo.
É verdade que os ponteiros não permitir-lhe a capacidade
talvez para estragar muito mal quando você está
trabalhar com variáveis, e os dados, e fazendo com que seu programa trave.
Mas eles são realmente muito útil e eles nos realmente uma ótima maneira permitir
para passar dados de volta e para trás entre funções,
que somos de outro modo incapaz de fazer.
>> E assim o que realmente quero fazer aqui é trem
que você tenha uma boa disciplina ponteiro, assim que você pode usar ponteiros de forma eficaz
para fazer seus programas que muito melhor.
Como eu disse ponteiros nos dar uma diferente maneira de passar dados entre funções.
Agora, se você se lembrar de um vídeo anterior, quando
nós estávamos falando sobre escopo de variáveis, eu mencionei
que todos os dados que passam entre funções em C é passado por valor.
E eu não pode ter usado que prazo, o que eu quis dizer lá
foi a de que estamos passando cópias de dados.
Quando passar uma variável para uma função, nós não estamos realmente passando a variável
para a função, certo?
Estamos passando uma cópia do que os dados para a função.
A função faz o que ele vai e calcula algum valor,
e talvez nós usamos esse valor quando dá-lo de volta.
>> Houve uma exceção para esta regra de passar por valor,
e nós vamos voltar para o que é um pouco mais tarde, em um vídeo.
Se usarmos ponteiros vez do uso de variáveis,
ou em vez de utilizar as variáveis si ou cópias das variáveis,
agora podemos passar as variáveis ​​em torno de entre as funções de uma maneira diferente.
Isto significa que se fizermos uma mudança de uma função,
que a mudança vai realmente tomar efeito em uma função diferente.
Novamente, isso é algo que não podíamos fazer antes,
e se você já tentou trocar o valor de duas variáveis ​​em uma função,
você percebeu esse problema tipo de rastejando-se, certo?
>> Se queremos trocar X e Y, e nós passá-las para uma função chamada swap,
dentro da função trocar o variáveis ​​fazer valores de troca.
Um torna-se dois, dois torna-se um, mas nós não, na verdade,
mudar nada no original função, o chamador.
Porque nós não podemos, nós somos somente trabalhar com cópias deles.
Com ponteiros embora, nós podemos realmente passar X e Y para uma função.
Essa função pode fazer algo com eles.
E esses valores variáveis pode realmente mudar.
Então, isso é uma grande mudança em nossa capacidade de trabalhar com dados.
>> Antes de mergulharmos ponteiros, eu acho que vale a pena
Tomar alguns minutos para voltar ao básico aqui.
E ter um olhar em como obras de memória de computador
porque estes dois assuntos vão para realmente ser bastante inter-relacionados.
Como você provavelmente sabe, no seu sistema informático
você tem um disco rígido ou talvez uma unidade de estado sólido,
algum tipo de local de armazenamento de arquivos.
É geralmente em algum lugar no bairro de 250 gigabytes
para talvez um par de terabytes agora.
E é onde todo o seu arquivos, finalmente, viver,
mesmo quando o computador é desligado fora, você pode ligá-lo novamente
e você vai encontrar os seus arquivos estão lá novamente quando você reiniciar o sistema.
Mas as unidades de disco, como uma unidade de disco rígido, um disco rígido ou uma unidade de estado sólido, um SSD,
são apenas o espaço de armazenamento.
>> Nós não podemos realmente fazer alguma coisa com Os dados que está no disco rígido,
ou em uma unidade de estado sólido.
A fim de realmente mudar dados ou movê-lo,
temos de movê-lo para RAM, memória de acesso aleatório.
Agora RAM, você tem um monte menos de em seu computador.
Você pode ter em algum lugar no bairro de 512 megabytes
se você tiver um computador mais antigo, para talvez dois, quatro, oito, 16,
possivelmente até mesmo um pouco mais gigabytes de RAM.
Então, isso é muito menor, mas isso é onde todos os dados voláteis existe.
É aí que podemos mudar as coisas.
Mas quando voltamos nossa computador desligado, todos os dados na memória RAM é destruído.
>> Então é por isso que precisamos ter disco rígido para a localização de mais permanente que,
de modo que ela seria exists- ser muito ruim se cada vez que
virou nosso computador desligado, cada arquivo no nosso sistema foi obliterada.
Por isso, trabalhamos dentro da RAM.
E cada vez que estamos falando memória, praticamente, em CS50,
estamos falando de RAM, disco rígido não.
>> Então, quando nós mudar as coisas na memória, leva-se uma certa quantidade de espaço.
Todos os tipos de dados que temos vindo a trabalhar com
assumir diferentes quantidades de espaço na RAM.
Então, toda vez que você cria um inteiro variáveis, quatro bytes de memória
são postos de lado na memória RAM para que você pode trabalhar com esse inteiro.
Você pode declarar o número inteiro, mudá-lo, associá-la
para um valor de 10 incrementado por um, assim por diante e assim por diante.
Tudo o que precisa acontecer em RAM, e você terá quatro bytes
a trabalhar com para cada inteiro que você cria.
>> Cada personagem que você criar recebe um byte.
Isso é apenas a quantidade de espaço necessários para armazenar um personagem.
Cada float, uma verdadeira número, recebe quatro bytes
a menos que seja um duplo Precisão de ponto flutuante
número, o que lhe permite dígitos tem mais precisas ou mais
depois do ponto decimal sem perder precisão,
que ocupam oito bytes de memória.
Anseia por muito tempo, realmente grandes números inteiros, também ocupam oito bytes de memória.
Quantos bytes de memória não cordas assumir?
Bem, vamos colocar um pino em questão que por agora, mas vamos voltar a ele.
>> Então, de volta a esta ideia de memória como uma grande variedade de células de tamanho de byte.
Isso é realmente tudo o que é, é apenas uma enorme variedade de células,
assim como qualquer outra matriz que você está familiarizado com e ver,
exceto cada elemento é um byte de largura.
E, assim como uma matriz, cada elemento tem um endereço.
Cada elemento de um array tem um índice, e nós
pode usar esse índice de fazer chamada de acesso aleatório na matriz.
Não temos de começar a o início da matriz,
iterar através de cada único elemento do mesmo,
para encontrar o que estamos procurando.
Nós podemos apenas dizer, eu quero chegar ao 15th elemento ou do elemento 100a.
E você pode apenas passar esse número e obter o valor que você está procurando.
>> Da mesma forma cada local na memória tem um endereço.
Portanto, sua memória pode algo parecido com isto.
Aqui está um pequeno pedaço de memória, esta é de 20 bytes de memória.
Os primeiros 20 bytes, porque o meu aborda lá no fundo
são 0, 1, 2, 3, e assim em todo o caminho até a 19.
E quando eu declarar variáveis ​​e quando eu começar a trabalhar com eles,
o sistema vai definir reservar algum espaço para me
nesta memória para trabalhar com meus variáveis.
Então, eu poderia dizer, char c é igual a de capital H. E o que vai acontecer?
Bem, o sistema vai reservado para me um byte.
Neste caso, ele escolheu o número de bytes quatro, o byte no endereço quatro,
e está indo para armazenar o letra H de capital em lá para mim.
Se eu, então, dizer velocidade int limite é igual a 65, é
vai destinar quatro bytes de memória para mim.
E vai para tratar aqueles quatro bytes como uma única unidade
porque o que nós estamos trabalhando é um número inteiro com aqui.
E está indo para armazenar 65 em lá.
>> Agora já estou meio dizendo-lhe um pouco de uma mentira,
direito, porque sabemos que computadores trabalhar em binário.
Eles não entendem necessariamente o que é um capital H
ou o que é um 65, eles só compreender binários, zeros e uns.
E assim, na verdade, o que nós estamos armazenando lá
não é a letra H e o número 65, mas sim as representações binárias
destes, que parecem um pouco algo como isto.
E, em particular no contexto da variável número inteiro,
ele não vai apenas cuspi-lo em, ele não está indo para tratá-lo como um de quatro
byte pedaço necessariamente, ele está realmente acontecendo
tratá-la como um quatro pedaços de byte, o que poderia ser algo como isto.
E mesmo isso não é inteiramente verdade, quer,
por causa de algo chamado uma ordenação, que não estamos
vai entrar agora, mas Se você está curioso para saber,
você pode ler-se em pouco e grande endianness.
Mas por causa desse argumento, por causa deste vídeo,
vamos supor que é, em fato, como o número 65 seria
ser representado em memória em cada sistema,
embora não é inteiramente verdade.
>> Mas vamos realmente apenas obter livrar de todos binário inteiramente,
e só pensar em como H e 65, é muito mais fácil
pensar nisso como que, como um ser humano.
Tudo bem, então também parece talvez um pouco aleatório que I've- meu sistema
não me deu bytes 5, 6, 7, e 8 para armazenar o número inteiro.
Há uma razão para isso, também, que não vamos entrar agora, mas basta
dizer que o que o computador está fazendo aqui
é provavelmente uma boa jogada da sua parte.
Para não me dar a memória que é necessariamente de volta para trás.
Embora ele vai fazê-lo agora se eu quiser obter outra seqüência,
chamado sobrenome, e eu quero para colocar Lloyd lá.
Eu vou precisar para caber um caráter, cada letra do que é
vai exigir um caráter, um byte de memória.
Então, se eu poderia colocar Lloyd em minha matriz assim eu sou muito bom para ir, certo?
O que está a faltar?
>> Lembre-se que cada corda trabalhamos com em C termina com barra invertida zero,
e não podemos omitir que aqui, também.
Precisamos deixar de lado um byte de memória para armazenar que assim nós
saber quando nossa string terminou.
Então, novamente este arranjo de como as coisas
aparecem em poder de memória ser um pouco aleatório,
mas, na verdade, é como a maioria dos sistemas são concebidos.
Para alinhá-los em múltiplos de quatro, por razões de novo
que não precisa entrar agora.
Mas isso, então basta dizer que Depois destas três linhas de código,
este é o que a memória pode parecer.
Se eu precisar de locais de memória 4, 8, e 12 para manter os dados,
isto é o que a minha memória pode parecer.
>> E apenas ser particularmente pedante aqui, quando
estamos falando de memória endereços que costumamos
fazê-lo utilizando notações hexadecimais.
Então, por que não podemos converter todos estes de decimal para notação hexadecimal
só porque isso é geralmente como nos referimos a memória.
Então, ao invés de ser de 0 a 19, o que temos é zero
x zero a zero, três x1.
Esses são os 20 bytes de memória que ter ou nós estamos olhando nesta imagem
aqui mesmo.
>> Então, tudo o que foi dito, vamos se afastar da memória para um segundo
e de volta para ponteiros.
Aqui é o mais importante coisa a lembrar
à medida que começar a trabalhar com ponteiros.
Um ponteiro é nada mais do que um endereço.
Eu vou dizer outra vez porque é tão importante,
um ponteiro não é nada mais do que um endereço.
Os ponteiros são endereços para locais na memória onde variáveis ​​viver.
Sabendo que ela se torna um esperançosamente pouco mais fácil trabalhar com eles.
Outra coisa que eu gosto a fazer é ter sorte
de diagramas visualmente representando o que é acontecendo com várias linhas de código.
E nós vamos fazer isso um par de tempos em ponteiros,
e quando falamos de dinâmica alocação de memória também.
Porque eu acho que estes diagramas pode ser particularmente útil.
>> Então, se eu dizer, por exemplo, int k no meu código, que está acontecendo?
Bem o que está acontecendo é, basicamente, Estou ficando memória reservada para mim,
mas eu não gosto nem de pense nisso como esse, eu
gosto de pensar nisso como uma caixa.
Eu tenho uma caixa e é de cor verde porque eu
pode colocar inteiros em caixas verdes.
Se fosse um personagem que eu pode ter uma caixa azul.
Mas eu sempre digo, se eu estou criando uma caixa que pode conter inteiros
que a caixa é de cor verde.
E eu tomo um marcador permanente e eu k escrever sobre o lado do mesmo.
Então, eu tenho uma caixa chamada k, para que eu possa colocar inteiros.
Portanto, quando digo int k, que é o que acontece na minha cabeça.
Se eu disser que k é igual a cinco, o que estou fazendo?
Bem, eu estou colocando cinco na caixa, certo.
Isto é bastante simples, se Eu digo int k, criar uma caixa chamada k.
Se eu disser que k é igual a 5, colocar cinco na caixa.
Esperemos que isso não é muito de um salto.
Aqui é onde as coisas vão um pouco interessante embora.
Se eu disser int * pk, bem, mesmo se eu não fizer sabe o que isto significa, necessariamente,
é claramente tem algo a ver com um número inteiro.
Então eu vou para colorir esta caixa verde-ish,
Eu sei que tem algo a ver com um número inteiro,
mas não é um número inteiro em si, porque é uma estrela int.
Há algo ligeiramente diferente sobre isso.
Tão envolvido de um número inteiro, mas caso contrário, é
não muito diferente do o que estávamos falando.
É uma caixa, o seu tem um rótulo, ela está vestindo um pk etiqueta,
e é capaz de exploração estrelas int, quaisquer que sejam.
Eles têm algo a ver com números inteiros, de forma clara.
Aqui é a última linha embora.
Se eu disser pk = & k, whoa, o que aconteceu, certo?
Portanto, este número aleatório, aparentemente aleatória número, é jogado na caixa lá.
Tudo o que é, é pk obtém o endereço de k.
Então, eu estou aderindo onde k vive na memória, seu endereço, o endereço de seus bytes.
Tudo o que eu estou fazendo é que eu estou dizendo esse valor é o que eu vou
para colocar dentro da minha caixa chamada pk.
E porque essas coisas são ponteiros, e porque procura
em uma string como nula x oito zero ° C sete quatro oito
dois zero é provavelmente não muito significativa.
Quando nós geralmente visualizar ponteiros, nós realmente fazê-lo como ponteiros.
Pk nos dá a informação precisamos encontrar k na memória.
Então, basicamente pk tem uma seta nela.
E se andarmos o comprimento de que a flecha, imagine
é algo que você pode andar sobre, se nós caminhar ao longo do comprimento da seta,
na ponta de flecha que, nós vai encontrar o local na memória
onde k vive.
E isso é realmente importante porque uma vez que nós sabemos onde k vive,
podemos começar a trabalhar com os dados no interior do referido local de memória.
Embora nós estamos começando um pequenininho pouco à frente de nós mesmos para agora.
>> Então, o que é um ponteiro?
Um ponteiro é um item de dados cujo valor é um endereço de memória.
Isso foi que o zero x oito coisas de zero acontecendo, que era um endereço de memória.
Essa era uma posição na memória.
E do tipo de um ponteiro descreve o tipo
de dados que você vai encontrar no esse endereço de memória.
Portanto, há a parte direita int estrela.
Se eu seguir essa flecha, é vai me levar para um local.
E esse local, o que eu vai encontrar lá no meu exemplo,
é uma caixa de cor verde.
É um inteiro, que é o que eu vai encontrar se eu ir para esse endereço.
O tipo de dados a ponteiro descreve o que
você vai encontrar nesse endereço de memória.
Então aqui está a coisa muito legal embora.
Ponteiros nos permitem passar variáveis ​​entre funções.
E, na verdade, passar variáveis e não passar cópias deles.
Porque se nós sabemos exatamente onde na memória para encontrar uma variável,
nós não precisamos de fazer uma cópia de -lo, podemos apenas ir para esse local
e trabalhar com essa variável.
Assim, em essência ponteiros espécie de fazer um ambiente de computador
muito mais parecido com o mundo real, certa.
>> Então aqui vai uma analogia.
Vamos dizer que eu tenho um notebook, direito, e é cheio de notas.
E eu gostaria que você atualizá-lo.
Você é uma função que atualizações notas, certo.
No caminho nós estivemos funcionando até agora, o que
acontece é que você vai tomar o meu notebook, você ir até a loja de cópia,
você vai fazer uma cópia de Xerox todas as páginas do caderno.
Você vai deixar o meu notebook de volta na minha mesa quando estiver pronto,
você vai passar e riscar coisas na minha notebook que estão desatualizados ou errado,
e então você vai passar de volta para me a pilha de páginas Xerox
que é uma réplica do meu notebook com as mudanças que você fez a ela.
E nesse ponto, cabe a mim como a função de chamada, como o chamador,
para decidir tomar as suas notas e integrá-los de volta para o meu notebook.
Portanto, há uma série de etapas envolvido aqui, certo.
Como não seria melhor se eu apenas dizer, hey, você pode
atualizar o meu notebook para me, entregar-lhe o meu notebook,
e você levar as coisas e literalmente cruzá-los fora
e atualizar as minhas notas no meu caderno.
E, em seguida, dar-me o meu notebook de volta.
Esse é o tipo do que ponteiros nos permitem fazer,
eles fazem este ambiente muito mais como como atuamos na realidade.
>> Tudo bem então é isso que um ponteiro é, vamos falar
ponteiros sobre como trabalhar em C, e como podemos começar a trabalhar com eles.
Portanto, há um ponteiro muito simples em C chamado de ponteiro nulo.
O ponteiro pontos nulos a nada.
Isso provavelmente parece que é na verdade, não é uma coisa muito útil,
mas como nós vamos ver uma pouco mais tarde, o fato
que existe esse ponteiro nulo na verdade, realmente pode vir a calhar.
E sempre que você criar um ponteiro, e você não definir seu valor imediatamente-
um exemplo de configuração o seu valor imediatamente
será um par de lâminas de volta onde eu disse pk k é igual e,
pk recebe o endereço de k, como vamos ver o que isso significa,
vamos ver como codificar que shortly- se não definir o valor para algo
significativa imediatamente, você deve sempre
definir o ponteiro para apontar para null.
Você deve configurá-lo para apontar para nada.
>> Isso é muito diferente do que deixando apenas o valor é tão
e, em seguida, declara uma ponteiro e apenas supondo
é nula porque é isso raramente é verdade.
Então você deve sempre definir o valor de um ponteiro
como nulo se você não definir seu valor para algo significativo imediatamente.
Você pode verificar se o valor de um ponteiro é nulo usando o operador de igualdade
(==), Assim como você comparar qualquer número inteiro valores ou valores de caracteres usando (==)
também.
É um tipo especial de constante valor que você pode usar para testar.
Então essa foi uma forma muito simples ponteiro, o ponteiro nulo.
Outra forma de criar um apontador é para extrair
o endereço de uma variável você já criou,
e você fazer isso usando o & extração endereço operador.
Que já vimos anteriormente no primeiro exemplo diagrama eu mostrei.
Então, se x é uma variável que nós temos já criada do tipo inteiro,
em seguida, & x é um ponteiro para um inteiro.
& x é- me lembro, e vai extrair o endereço do coisa à direita.
E uma vez que um ponteiro é apenas um endereço, que & x é um ponteiro para um inteiro
cujo valor é, onde na memória x vidas.
É o endereço de x.
Assim & X é o endereço de x.
Vamos dar um passo mais e conectar-se a algo
Eu, em alusão a um vídeo anterior.
Se arr é uma matriz de duplas, em seguida, & colchete arr i é um ponteiro
para um casal.
ESTÁ BEM.
arr quadrado suporte i, se arr é uma matriz de duplas,
em seguida, arr colchete i é o elemento i-th dessa matriz,
e & arr colchete i é onde em memória o elemento i-th de arr existe.
>> Então, qual é a implicação aqui?
Um nome de matrizes, a implicação de tudo isso,
é que o nome de uma matriz é na verdade em si um ponteiro.
Você tem trabalhado com ponteiros ao longo de toda
toda vez que você usou uma matriz.
Lembre-se do exemplo escopo de variáveis,
perto do fim do vídeo apresento um exemplo em que temos uma função
chamado int set e uma função chamada matriz set.
E seu desafio para determinar se ou não, ou o que o
valores que nós imprimimos o final da função,
no final do programa principal.
>> Se você se lembrar de que o exemplo ou se você assistiu o vídeo,
você sabe que quando você- a chamada para conjunto int efetivamente não faz nada.
Mas a chamada para definir matriz faz.
E eu meio que encoberto por que era o caso na época.
Eu apenas disse, bem, é um array, é especial, você sabe, há uma razão.
A razão é que uma matriz de nome é realmente apenas um ponteiro,
e há esta especial sintaxe colchete que
tornar as coisas muito mais agradável para trabalhar.
E eles fazem a idéia de um ponteiro muito menos intimidante,
e é por isso que eles são tipo da apresentada dessa forma.
Mas realmente matrizes são apenas apontadores.
E é por isso que quando nós fez uma mudança para a matriz,
quando passamos uma matriz como um parâmetro para uma função ou como um argumento
a uma função, o conteúdo da matriz realmente mudado tanto no receptor
e em que o chamador.
Que para qualquer outro tipo de variável que vimos não foi o caso.
Então, isso é apenas algo para se manter em mente quando você está trabalhando com ponteiros,
que é o nome de um matriz, na verdade, um ponteiro
para o primeiro elemento do array.
>> OK então agora temos todos estes fatos, vamos continuar, certo.
Por que nos preocupamos onde algo vive.
Bem, como eu disse, é muito útil saber onde algo vive
assim você pode ir lá e mudá-lo.
Trabalhar com ele e realmente tem a coisa que você
quer fazer para que entrem em vigor a variável, e não produz efeitos em alguns cópia do mesmo.
Isso é chamado de dereferencing.
Nós vamos para a referência e nós mudamos o valor lá.
Então, se temos um ponteiro e é chamado pc, e ele aponta para um personagem,
então podemos dizer * * pc e pc é o nome do que vamos encontrar, se formos
para o pc endereço.
O que vamos encontrar lá é um personagem e * pc é a forma como nos referimos aos dados a que
localização.
Assim, poderíamos dizer algo como * pc = D ou algo parecido,
e isso significa que qualquer que seja Foi no endereço de memória pc,
qualquer personagem que estava anteriormente lá, é agora D, se dissermos * PC = D.
>> Então, aqui vamos nós de novo com algumas coisas C estranho, certo.
Então nós vimos anteriormente como sendo * de alguma forma parte do tipo de dados,
e agora ele está sendo usado em num contexto ligeiramente diferente
para acessar os dados em um local.
Eu sei que é um pouco confuso e que é, na verdade, parte desse todo
como, por ponteiros têm essa mitologia em torno deles como sendo tão complexo,
é um tipo de problema de sintaxe, honestamente.
Mas * é usado em ambos os contextos, tanto como parte do nome do tipo,
e vamos ver um pouco depois outra coisa, também.
E agora é o operador de remoção de referência.
Por isso, vai para a referência, ele acessa os dados
na localização do ponteiro, e permite que você manipulá-lo à vontade.
>> Agora, este é muito similar ao visitar seu vizinho, certo.
Se você sabe o que o seu vizinho vive, você é
não sair com seu vizinho.
Você sabe que você acontecer sabe onde eles vivem,
mas isso não significa que, por virtude de ter esse conhecimento
você está interagindo com eles.
Se você quiser interagir com eles, você tem que ir para sua casa,
você tem que ir para onde eles vivem.
E uma vez que você fizer isso, em seguida, você pode interagir
com eles apenas como você iria querer.
E da mesma forma com as variáveis, você precisa ir para seu endereço
se você quiser interagir eles, você não pode apenas saber o endereço.
E a maneira como você ir para o endereço é de usar *, o operador de remoção de referência.
O que você acha que acontece se nós tentamos e dereference
um ponteiro cujo valor é nulo?
Lembre-se que o nulo ponteiro aponta para nada.
Então, se você tentar eliminar referência nada ou ir a um endereço de nada,
o que você acha que acontece?
Segmentação Bem, se você adivinhou falha, você estaria certo.
Se você tentar e dereference um ponteiro nulo,
você sofre uma segmentação falha. Mas espera,
não vos digo, que se você não está indo
para definir o valor da sua ponteiro para algo significativo,
você deve definir como nulo?
Eu fiz e, na verdade, a segmentação culpa é uma espécie de bom comportamento.
>> Alguma vez você já declarou uma variável e Não atribuído o valor imediatamente?
Então você acabou de dizer int x; você não faz na verdade, atribuí-lo a nada
e depois, mais tarde, em seu código, imprimir o valor de x,
ainda não ter atribuído a qualquer coisa.
Freqüentemente você vai ter zero, mas às vezes você
pode obter algum número aleatório, e você não tem idéia de onde ele veio.
Da mesma forma pode coisas acontecer com ponteiros.
Quando você declarar um ponteiro int * pk por exemplo,
e você não atribuí-la a um valor, você recebe quatro bytes para memória.
Quaisquer que sejam os quatro bytes de memória do sistema pode
achar que tem algum valor significativo.
E não poderia ter sido algo que já existe
não é mais necessário por outro função, então você apenas tem
todos os dados que estava lá.
>> E se você tentou fazer dereference algum endereço que você não- havia
já bytes e informações lá, que está agora em seu ponteiro.
Se você tentar cancelar a referência desse ponteiro, você pode estar mexendo com alguma memória
que você não tinha a intenção para mexer com tudo.
E na verdade, você poderia fazer algo realmente devastador,
como quebrar outro programa, ou quebrar uma outra função,
ou fazer algo malicioso que você não tinha a intenção de fazer em tudo.
E é por isso que ele é realmente uma boa idéia
para definir os ponteiros como nulo se você não configurá-los para algo significativo.
É provavelmente melhor no final do dia, para o seu programa
a falhar, em seguida, para que ele faça algo que estraga
outro programa ou outra função.
Esse comportamento é provavelmente ainda menos ideal do que apenas deixar de funcionar.
E é por isso que ele é realmente um bom hábito
para entrar para definir os ponteiros como nulo se você não configurá-los
a um valor significativo imediatamente, um valor que você sabe
e que você pode com segurança a eliminar referência.
>> Então, vamos voltar agora e dê uma olhada na sintaxe global da situação.
Se eu disser int * p ;, o que eu acabei de fazer?
O que eu tenho feito é este.
Eu sei o valor de p é um endereço porque todos os ponteiros são apenas
endereços.
Eu posso excluir a referência p utilizando o operador *.
Neste contexto aqui, no próprio top recordar a * é parte do tipo.
Int * é o tipo de dados.
Mas eu posso dereference p usando o operador *,
e se eu fizer isso, se eu ir para esse endereço, o que vou encontrar nesse endereço?
Eu vou encontrar um inteiro.
Assim, int * p é basicamente dizendo: p é um endereço.
Eu posso excluir a referência p e se Eu faço, eu vou encontrar um número inteiro
em que a localização de memória.
>> OK, então eu disse que não havia outra coisa chata com estrelas
e aqui é onde que coisa chata com estrelas é.
Alguma vez você já tentou declarar múltiplas variáveis ​​do mesmo tipo
na mesma linha de código?
Então, por um segundo, fingir que a linha, o código Na verdade, tenho lá em verde
não está lá e ele apenas diz int x, y, z ;.
O que gostaria de fazer é realmente criar três variáveis ​​inteiras para você,
um chamado x, uma chamada y, z e um chamado.
É uma maneira de fazê-lo sem ter que dividir em três linhas.
>> Aqui é onde as estrelas chegar irritante novamente embora,
porque o * é na verdade parte tanto o nome do tipo e parte
do nome da variável.
E por isso, se eu digo int * px, py, pz, o que eu na verdade é um ponteiro para um inteiro
chamado px e dois inteiros, e py pz.
E isso provavelmente não o que é nós queremos, isso não é bom.
>> Então, se eu quiser criar vários ponteiros na mesma linha, do mesmo tipo,
e estrelas, o que eu realmente precisa a fazer é dizer int * pa, * pb, * pc.
Agora, tendo apenas dito que e agora lhe dizendo isso,
você provavelmente nunca vai fazer isso.
E é provavelmente uma coisa boa, honestamente, porque você pode inadvertidamente
omitir uma estrela, algo assim.
É provavelmente o melhor para declarar talvez ponteiros em linhas individuais,
mas é apenas mais um daqueles sintaxe irritante
coisas que fazem com estrelas ponteiros tão difícil de se trabalhar.
Porque é apenas isso sintática bagunça que você tem que trabalhar.
Com a prática que faz realmente se tornar uma segunda natureza.
Eu ainda cometer erros com ele ainda após a programação por 10 anos,
por isso não fique chateado se algo acontecer para você, é muito comum honestamente.
É realmente tipo de uma falha da sintaxe.
>> OK então eu meio que prometeu que gostaríamos de revisitar
o conceito de quão grande é uma string.
Bem, se eu lhe dissesse que um corda, nós temos realmente uma espécie de
mentindo para você o tempo todo.
Não há nenhum tipo de dados chamado corda, e na verdade eu
mencionei isso em um dos nossos primeiros vídeos sobre tipos de dados,
essa seqüência foi um tipo de dados que foi criado para você em CS50.h.
Você tem que # include CS50.h, a fim de usá-lo.
>> Bem string é realmente apenas um alias para algo
chamado de char *, um Ponteiro para um personagem.
Bem ponteiros, recall, são apenas aborda.
Então, qual é o tamanho em bytes de uma seqüência?
Bem, é quatro ou oito.
E a razão de eu dizer quatro ou oito é porque ele realmente
depende do sistema, Se você estiver usando CS50 ide, char * é do tamanho de um char
* É de oito, é um sistema de 64 bits.
Cada endereço na memória é de 64 bits de comprimento.
Se você estiver usando aparelho CS50 ou a utilização de máquinas de 32 bits,
e você já ouviu esse termo 32-bit máquina, o que é uma máquina de 32 bits?
Bem, isso só significa que cada endereço na memória é de 32 bits de comprimento.
E assim 32 bits é de quatro bytes.
Assim, um char * é de quatro ou oito bytes dependendo do seu sistema.
E, de fato qualquer tipo de dados, e um ponteiro para todos os dados
escreva, uma vez que todos os ponteiros são apenas endereços, quatro ou oito bytes.
Então, vamos voltar a esta diagramar e vamos concluir
este vídeo com um pouco de exercício aqui.
Então aqui está o diagrama paramos com no início do vídeo.
Então o que acontece agora, se eu digo * pk = 35?
Então, o que quero dizer quando digo, * pk = 35?
Tome um segundo.
* pk.
No contexto aqui, é * operador de remoção de referência.
Assim, quando o dereference operador é usado,
vamos para o endereço apontado por pk, e nós mudamos o que encontramos.
Assim * pk = 35 eficaz faz isso com a imagem.
Então é basicamente sintaticamente idêntico ao de ter dito k = 35.
>> Mais um.
Se eu disser int m, eu crio uma nova variável chamada m.
Uma nova caixa, é uma caixa verde porque que vai realizar um número inteiro,
e é rotulado m.
Se eu disser que m = 4, eu coloquei um inteiro em que a caixa.
Se digamos pk = & m, como é esta mudança diagrama?
Pk = & m, você se lembra o que o Operador & faz ou é chamado?
Lembre-se que o nome da variável e alguns é o endereço de um nome de variável.
Então, o que nós estamos dizendo é pk obtém o endereço de m.
E assim efetivamente o que acontece no diagrama é que já não pk pontos
para k, mas aponta para m.
>> Novamente ponteiros são muito complicado para trabalhar com
e eles tomam um monte de prática, mas porque
da sua capacidade de permitir que você para transmitir dados entre funções
e realmente tem aqueles alterações entrem em vigor,
recebendo sua cabeça em torno é realmente importante.
É provavelmente o mais complicado tópico que discutimos em CS50,
mas o valor que você começa de usar ponteiros
supera em muito as complicações que vêm de aprendê-las.
Então, eu desejo-lhe o melhor de sorte de aprender sobre ponteiros.
Eu sou Doug Lloyd, este é CS50.