[Powered by Google Translate] [Semana 4, continuação]
[David J. Malan - Harvard University]
[Esta é CS50. - CS50.TV]
>> Este é CS50, e este é o fim da semana 4.
Então, uma notícia boa e uma má notícia.
Não palestra na segunda-feira, não há problema definido na próxima semana. [Alunos aplaudindo]
Você não vai gostar de onde isso vai dar.
Mas nós temos isso em vez próxima quarta-feira,
e há também o currículo por palestra sexta-feira uma próxima sexta-feira, para que possamos permanecer na pista.
Mas tudo vai ser filmado, como de costume, para não se preocupar.
>> E com relação a 0 Quiz o que vamos fazer para o final da semana
é postar em cs50.net do curso homepage uma explicação
de que tipo de expectativas que você deve ter quando se trata do primeiro questionário.
Em geral, será de múltipla escolha, verdadeiro ou falso, resposta curta curtas problemas de codificação.
Você não vai ser esperado para implementar o equivalente
de um problema que você veria em um pset, para que você tenha um computador
e um depurador e similares, mas não haverá pequenos problemas de codificação.
>> E, de fato, o melhor guia para ter uma noção do que são como CS50 quizzes
é ir para cs50.net, ir para o link Quizzes,
e você pode ver os últimos anos no valor de questionários.
Basta perceber que o currículo não tem sido sempre o mesmo ao longo dos anos.
Às vezes, acrescentamos nós, às vezes, subtrair,
então se você ver algum tópico em um daqueles velhos quizzes
que você não tem idéia do que está falando, ela quer que tenha sido abordado
ou que não cobri-lo.
Mas, na forma de comentários, este domingo, segunda e terça-feira
bem como um curso de largura sessão de revisão, na noite de domingo -
horário e local a ser anunciado na página inicial do curso -
que todos tenham a oportunidade de rever com os bolsistas do curso de ensino
o material para este ano, tanto na seção e como uma classe cheia,
e os que serão filmados, como de costume também.
>> Tudo bem. Então, sem mais delongas, um comentário sobre aprovação / reprovação e add / drop.
Você pode ter visto as minhas notas na noite passada, e isso é realmente apenas alguns garantia adicional
que, se você está entre aqueles particularmente menos confortável ou em algum lugar entre
e você está se sentindo um pouco acima da sua cabeça,
perceber que é realmente muito normal, e não há uma estrutura de apoio ampla no lugar,
um dos quais o horário de expediente tinham a intenção de melhorar ainda mais a minha noite por último e-mail,
e perceber também que uma opção como aprovação / reprovação de uma classe como esta
realmente se entende como um mecanismo para tomar a borda fora de um curso como este,
para que novamente se você está gastando os 10, 15, 20 horas
apenas tentando obter alguma pset para trabalhar e você sabe que é 90-95% do caminho
mas você não pode encontrar algum bug maldito, num aprovação / reprovação modelo que é uma espécie de bem.
>> A idéia é que, com esse mecanismo, você pode ir foco em suas outras Série de Exercícios
ou dormir ou o que é que você quer focar.
Então percebe que você tem até esta terça-feira que vem - tecnicamente na segunda-feira 5,
mas é um feriado, para esta terça-feira que vem - para mudar de aprovação / reprovação para graduados ou vice-versa.
E se você está realmente à beira do precipício e está pensando em deixar cair por completo,
por favor me pegar depois de palestra ou mande-me uma nota.
Adoraríamos pelo menos bate-papo antes de despedir.
Tudo bem. Então começamos a retirar as rodinhas da última vez.
Em particular, nós nos concentramos em seqüência.
String é algo que é declarado na biblioteca CS50,
especificamente no arquivo chamado cs50.h que nós vamos começar a olhar para esta semana ea próxima.
Mas cadeia é realmente apenas uma simplificação de algo
que é um pouco mais arcanely descrito como char *.
Char estamos familiarizados. É apenas um único personagem.
Mas * como de segunda-feira denotado o que? >> [Aluno] Um ponteiro.
Um ponteiro. E o que é um ponteiro? >> [Aluno] Um endereço.
>> É como um endereço, um local na memória.
O que é um endereço ou local ou de memória?
Mais uma vez, todos nós temos laptops com um show ou 2 gigabytes de memória RAM provavelmente estes dias,
e isso significa que você tem um bilhão ou 2 bilhões de bytes no valor de memória.
E isso realmente não importa o que fisicamente se parece,
mas assumir a fé que você pode numerar todos os bytes individuais que tem seu próprio laptop -
este é o byte 0, este é um byte, este é byte 2 bilhões -
e isso é exatamente o que um computador faz.
Quando você alocar espaço para um único personagem, por exemplo,
que, obviamente, tem de viver em algum lugar na memória do seu computador,
e talvez seja, no número de bytes 12345,
e que está em algum lugar aqui em memória de seu computador.
E o endereço depois de que o caráter é 12345.
>> Agora, na semana 0 por agora, até agora, não temos realmente se importava
onde na memória as coisas são armazenados porque geralmente utilizam símbolos,
variáveis, e matrizes para realmente obter os nossos dados.
Mas a partir de segunda-feira e ainda mais hoje, você agora vai ter
todos os recursos mais expressivos com programas de escrita
para realmente manipular a memória de um computador, contudo, você vê o ajuste,
tanto para fins bons e ruins,
bugs de ser um resultado muito comum neste ponto em aprender essas coisas.
Mas o que isso realmente significa ser um char *?
Vamos em frente de volta para - e nós vamos voltar a Binky como prometido hoje.
Vamos a um exemplo simples aqui.
Deixe-me salve este arquivo como compare.c, e deixe-me conseguir algum código do modelo aqui
para incluir stdio.h, deixe-me dar-me também incluem cs50.h. Eu vou aumentar o zoom até lá.
Deixe-me começar a escrever int main, main (void), e agora eu quero fazer algo como isto:
printf ("Dê-me uma string:") e depois vou usar string s fica GetString
para obter uma string do usuário, então eu vou pedir para o usuário para outra.
("Dê-me outra string:") e eu vou pedir a eles através GetString para conseguir isso.
Eu vou chamá-lo de t t porque vem depois de s e s é um bom nome para uma string se é muito genérica.
Então GetString, e agora eu só quero fazer um teste de sanidade e eu vou dizer
if (s == t), então eu vou apenas dizer que o usuário printf ("Você digitou a mesma coisa \ n");
mais eu vou imprimir algo como ("Você digitou algo diferente! \ n")
ou qualquer que seja a sentença será. Então, alguma coisa assim.
Em seguida, como de costume, eu vou retornar 0 que apenas significa que nada de ruim aconteceu,
e eu estou indo para ir em frente e compilar e executar este programa.
>> Mas na segunda-feira nós rodamos este programa,
e, na verdade, foram informados de que não é OLÁ OLÁ ADEUS e não é um adeus.
O comportamento que vimos foi um pouco mais como este.
Deixe-me ir para o meu diretório de origem, zoom aqui, e vamos faça comparar.
Compilado bem. Deixa-me correr comparar. Dê-me uma string: OLÁ.
Dê-me outra seqüência: OLÁ.
Você digitou algo diferente!
Bem, deixe-me tentar algo mais simples como 50, 50. Você digitou algo diferente!
oi, oi. Então, claramente, algo está acontecendo aqui.
Mas qual era a explicação para por que?
Aparentemente, a linha 12 é completamente disfuncional.
Qual é o problema fundamental aqui? Sim. >> [Aluno] Ele está comparando os endereços.
Sim, exatamente. É realmente comparando os endereços
em que OLÁ OLÁ e são armazenados.
Ele não está comparando as letras OLÁ novo e de novo,
porque o que realmente aconteceu, todo esse tempo que estamos usando GetString -
Este quadro é mais uma vez a memória do nosso computador,
e digamos que eu chamo GetString depois de declarar uma variável s.
O que a minha memória parece?
Vamos dizer que arbitrariamente s parece com isso. É um quadrado.
E praticamente qualquer tempo eu desenhei um pedaço de memória na tela
se é 32 bits eu tenho desenhado quadrados como este, porque realmente no aparelho,
um ponteiro, um endereço, é de 32 bits. É o mesmo que um int.
Isso pode variar de acordo com sistema de computador.
Aqueles de vocês que são vagamente familiarizado com o fato de que o seu Mac ou PC é de 64 bits,
que, na verdade, indica que o computador está usando ponteiros de 64 bits,
64-bits de endereços, e entre os lados positivos de que é seus computadores
RAM pode ter muito mais do que antigamente.
Longa história curta, de volta ao dia em que os computadores usados ​​apenas 32 bits
para representar os endereços, o maior número de bytes que você poderia representar
nesse caso, foi o que se você tiver 32 bits?
Então 4 bilhões, direito, porque 2 a 32 é de 4 bilhões.
Este número foi recorrente no curso.
>> Então, se você só tem 32 bits, o número mais alto que você pode contar para a cerca de 4 bilhões de dólares.
Mas isso era uma limitação fundamental dos computadores, até alguns anos atrás
porque se você só pode contar além de 4 bilhões,
não importa se você comprar 8 gigabytes de memória RAM ou até 5 gigabytes de RAM;
você não pode contar que a alta, por isso era inútil.
Você poderia acessar apenas os primeiros 3 ou 4 gigabytes de memória do seu computador.
Isso é menos de um problema agora, e você pode comprar MacBook Pros e Dells
com 8 gigabytes de memória RAM ou mesmo mais esses dias.
Mas se eu simplesmente alocar neste programa um ponteiro, um ponteiro chamado s,
pode parecer que esta na tela, pois realmente precisamos descascar essa camada.
Eu continuo dizendo cadeia, mas a partir de segunda-feira, string é realmente * char,
o endereço de algum personagem.
Portanto, vamos ter que roda formação fora mesmo que nós vamos continuar usando GetString para agora.
Então eu s declarada, e este é um pedaço de memória, 32 bits.
O que tem aqui na memória por padrão? >> [Resposta do aluno inaudível]
O que é isso? >> [Aluno] Lixo. Lixo. >> Exatamente.
Se o programador não colocar um valor em uma variável, que sabe o que é?
Às vezes você tem sorte e é 0, que é uma espécie de bom valor padrão, limpo,
mas como vimos segunda-feira, às vezes, é um disparate completo,
um número muito grande positivo ou negativo que veio de onde?
Sim. >> [Estudante] A função antes. Sim >>.
>> Muitas vezes a função que foi chamado antes, porque lembre-se,
como você chama funções na memória, eles ocupam mais espaço e mais de baixo para cima,
e, logo que o retorno da função, que a memória fica reutilizado
pelo próximo cara que é chamado, quem está usando o mesma fatia de memória.
E se você tem lixo deixado lá, os valores anteriores,
podemos confundir s como tendo algum valor quando realmente nós não pusemos nada lá.
Portanto, a nossa memória RAM, neste ponto se parece com isso.
Agora, no lado direito da linha 7 estamos chamando GetString,
que estamos fazendo agora por semanas, mas o que é realmente GetString fazendo?
GetString escrito pela equipe do CS50 é um pouco inteligente
em que, assim que o usuário começa a digitar as teclas e hits Enter,
Figuras GetString fora quantas teclas fizeram o sucesso do usuário,
quantos caracteres eu preciso alocar RAM para.
E onde que a RAM vem, quem sabe?
Está em algum lugar do seu computador 2 gigabytes de memória ou outros enfeites.
Mas vamos supor que o computador encontrou espaço para a palavra OLÁ aqui.
A palavra que eu digitei foi H-E-L-L-O.
E se tirar isso como uma sequência de caracteres, podemos chamar assim.
Mas eu preciso fazer uma coisa extra. O que pertence ao final de qualquer cadeia em C?
O personagem nulo, o que nós escrevemos como \ 0.
É tecnicamente o número 0, mas a barra invertida faz toda mais clara a
que este é literalmente o número 0, o inteiro 0;
não é, por exemplo 0, entre aspas que você pode digitar no teclado.
Portanto, esta é OLÁ.
>> E o que podemos dizer na segunda-feira que uma função como GetString
é, na verdade, voltando todas essas semanas?
Não é devolver uma cadeia de per se, porque isso realmente não tem sentido
porque as cordas não existem. Eles são uma espécie de fabricação na biblioteca CS50.
O que é realmente uma seqüência, mais tecnicamente? >> [Aluno] É o primeiro caractere.
Exatamente. É simplesmente o endereço do primeiro caractere que o usuário digitou dentro
Então, se a minha palavra OLÁ termina-se em 123 o número de bytes e então em número de byte 124,
125, 126, e assim por diante, se eu número apenas meus bytes de 0 em cima,
o que realmente está retornando GetString é literalmente o número 123.
Então, o que é colocado em s é o número 123, e não a letra H, não a palavra OLÁ,
simplesmente o endereço em que eu possa encontrar a primeira letra do OLÁ.
Mas isso não parece ser suficiente. Eu lhe pedi uma string, não um personagem.
Assim como nós ou o computador saber que tipo de ELLO vêm junto com o H?
Qual é o tipo de acordo que temos? Sim.
[Aluno] Ele continua dizendo a si mesma para encontrar mais alguns personagens. >> Exatamente.
>> Há essa convenção humano-computador em que quando você está lidando com cordas,
também conhecido agora como estrelas char, você simplesmente tem que descobrir
onde no final de cada corda na vida é realmente apenas uma iteração sobre isso com um loop,
um loop while, qualquer que seja, de modo que quando você encontrar o final da cadeia
agora você pode inferir que, oh, toda a palavra foi OLÁ.
Aqueles de vocês com experiência anterior em programação pode saber em Java
você pode apenas chamar. comprimento e em outras línguas você pode chamar comprimento ou similar.
Isso porque em um monte de línguas, especialmente coisas chamadas linguagens orientadas a objeto,
o comprimento de algo é uma espécie de encapsulado dentro de um pedaço de dados em si,
muito como nós IDs encapsulados e nomes e casas dentro de um estudante na segunda-feira.
Mas C é o nível mais baixo. Não há objetos ou classes, se você já ouviu esses termos antes.
Tudo que você tem é realmente endereços de memória.
Portanto, esta é uma espécie de maneira antiga de representar estruturas interessantes dados.
Você tem um valor inicial como o endereço do primeiro caractere
e depois é só convenção alguns arbitrária que todos concordam em seguir.
Então, como é implementada comprimento da corda, que propomos?
Strlen, strlen, que alguns de vocês já usado algumas vezes. É muito simples, certo?
É como se duas linhas de código.
É praticamente um laço para de alguma sorte, talvez com uma variável adicional local.
Mas strlen só tem que tomar um ponteiro e, em seguida, começar a olhar para \ 0.
>> E assim que ele encontrar, ele pode retornar o número total de passos que é tomado em que seqüência.
Assim, podemos deduzir o que se passa ao lado.
Suponha então eu declaro t como eu fiz na linha 10.
Trata-se de um valor de lixo. Quem sabe no início?
Mas no lado direito da linha de 10 que eu estou chamando GetString novamente.
Quem sabe onde isso acaba?
Vamos arbitrariamente dizer que o sistema operacional encontrado espaço para ele caminho até aqui.
Acontece que eu coincidentemente tipo H-E-L-L-O de novo,
e assim podemos chamar o mesmo tipo de imagem.
Mas o fato de que eu tenho esta imagem redesenhado é deliberada
porque essa é uma. OLÁ diferente do que esta
Portanto, aqui este pode ser local 456, este é 457, e assim por diante.
Então, o que é colocado onde o ponto de interrogação era uma vez?
Neste caso 456.
Estamos colhendo estes números arbitrariamente porque realmente depois de hoje
nós não vamos importar tanto com o que o endereço de qualquer coisa é.
Tudo o que importa é que podemos descobrir o endereço de algum pedaço de dados como OLÁ.
>> Então, realmente o que a maioria das pessoas em ciência da computação quando se fala de endereços de memória
e falando sobre ponteiros especificamente,
em vez de se preocupar descobrir 123 - quem se importa onde este material realmente é,
apenas sabemos que ele está em algum endereço numérico -
que simplificam o mundo e apenas dizer que s está a apontar para que o personagem
e t está apontando para esse personagem.
E o fato de que é uma seta é bastante intencional
porque agora literalmente s está apontando para H e t está apontando para o outro H
porque no fim do dia, que não importa qual é o endereço é,
mas não importa de que temos a capacidade de expressar esse endereço com algum pedaço de código.
Nós realmente não temos manipulado estes endereços apenas ainda
então vamos ver onde podemos interpor e classificar de fazer as coisas com ponteiros,
mas por agora na linha 12, literalmente, os valores que estamos comparando
de acordo com essa história na linha 12?
Nós estamos dizendo é 123 igual igual a 456? E isso não é definitivamente o caso.
E mesmo conceitualmente, esse ponteiro definitivamente não é o mesmo que este
porque você chamou GetString duas vezes, e GetString não tenta ser super inteligente,
não tente perceber, oh, você digitou OLÁ cinco minutos atrás;
deixe-me dar-lhe o mesmo ponteiro como lhes dei antes,
ele só aloca um novo bloco de memória cada vez que você chamá-lo.
>> Então, como vamos resolver esse problema?
Se nível mais alto Eu quero comparar as cordas Olá e OLÁ -
Eu não me importo com os ponteiros - como eu faço para responder a pergunta,
se o usuário digitar a mesma coisa? O que é necessário aqui? Sim.
[Estudante] Use uma função. >> Eu posso usar uma função fora da caixa.
Eu posso usar uma função chamada strcmp, s-t-r-c-m-p,
apenas a versão abreviada de dizer corda comparar.
E se entrar, por exemplo, comparar dois, que está entre folhetos de hoje,
Eu faço exatamente isso.
Eu mantive tudo mais o mesmo a partir de uma linha para baixo, para 26 ou mais,
e agora perceber esta parte mudou um pouco.
Vamos ignorar a linha 28 por um momento e se concentrar apenas em um presente.
O que nós dizemos segunda-feira que str comparação faz?
Ele lida com o processo de tomar dois ponteiros, s e t, neste caso,
espécie de praticamente colocando o dedo sobre essas duas cartas,
eo que ele deve fazer é algo como um loop while ou um loop for,
e ele diz que são estes os mesmos? Se assim for, move os dedos ou os ponteiros para a frente.
São estes os mesmos, estes mesmos o, estes, o mesmo
estes mesmos o, esses mesmos a? E ooh, eu estou no final da cadeia, tanto s e t.
Não foram encontradas quaisquer contradições. Sim, essas seqüências são as mesmas.
E o que str retorno se comparar duas cordas são os mesmos, aparentemente? Zero.
Então, 0 é bom neste caso, porque se ele retorna -1 ou +1,
isso significa que é só acontece de vir antes de t em ordem alfabética ou depois de t.
E por que isso seria útil ter uma função que lhe diz que a corda vem antes
ou depois de um dicionário?
[Aluno] Pesquisando. >> Pesquisa e classificação.
>> Assim, você pode fazer coisas como busca binária ou espécie de bolha ou merge sort
onde você tem que comparar as coisas.
Até agora, nós meio que cortar alguns cantos e só falou sobre a classificação
no contexto de números, porque é agradável e fácil de falar,
mas certamente você pode comparar strings, maçã e banana,
porque se maçã é conhecido para vir antes da banana, do mesmo modo,
você pode mover cordas em torno da memória como Rob fez com merge sort no vídeo
e nós fizemos aqui no palco com uma espécie de seleção, tipo de inserção, e espécie de bolha.
Então, onde mais podemos levar isso? Vamos tentar isso.
Vamos esquecer que tipo de lição para um momento e tente agora e copiar 1.c para fazer o seguinte.
Na linha 21 eu estou dizendo algo de impressão,
então eu estou recebendo uma string do usuário,
então eu estou verificando isso.
Nós realmente não temos chegado a este hábito ainda, mas vamos fazer isso agora.
Vamos realmente descascar essa camada. Isto é realmente char *. Esse cara é muito char *.
Então, o que significa estar verificando se s == null?
Acontece que quando você chamar uma função como GetString
ou, mais geralmente basta perguntar a um computador para lhe dar um pouco de memória,
algo poderia dar errado.
Você poderia estar louco e pedir ao computador para um terabyte de memória
pedindo trilhões de bytes de memória que simplesmente não existem no computador,
mas funções GetString e outros precisam de alguma forma de gritar com você
se você pediu muito.
E a maneira GetString faz isso é, se você pediu mais memória
que está disponível no computador, mesmo que isso é super, super baixa probabilidade
porque nenhum de nós está indo para digitar um trilhão de caracteres e pressione a tecla Enter,
mas baixa probabilidade que possa ser, eu ainda quero para verificar isso apenas no caso,
eo valor especial que retorna GetString, resposta, e outras funções
se algo deu errado é NULL em todas as tampas.
>> E o que é NULL? NULL só acontece a representar um ponteiro. É 0 endereço de memória.
O mundo decidiu que arbitrariamente, se esta é a memória do meu computador - você sabe o que? -
vamos roubar apenas 1 byte de memória cada computador, e esta é a posição 0.
Nós vamos dar-lhe um apelido de NULL, e vamos prometer
que nós nunca vamos realmente colocar dados reais lá
porque apenas arbitrariamente precisa de um valor especial, 0, NULL aka,
para que possamos gritar com os usuários, se algo der errado.
Caso contrário, você pode não saber é que 0 significa colocar algo aqui
ou significa algo deu errado?
Temos que concordar que não significa nada NULL foi devolvido,
nenhum endereço real foi devolvido.
Agora, aqui estou apenas adotar meu convenção humana de eu voltar uma da principal
se algo der errado.
Isso porque principal convenção de retorno é retornar 0 se bem,
Um ou outro valor se mal.
Mas GetString e qualquer função que se ocupa em memória retorna NULL se algo vai mal.
>> Okay. Então, infelizmente, linha 27, super simples que seja, completamente falha ao copiar a cadeia.
Por quê? Podemos ver isso como se segue.
Eu estou afirmando na linha 27 para ser fazer uma cópia de s e chamando-o de t.
Então eu não estou pedindo ao usuário para 2 cordas desta vez, estou apenas dizendo o valor em s
devem ser colocados em t também.
Então agora só para demonstrar como este é quebrado, na linha 29 em diante o que eu estou fazendo?
Primeiro estou verificando se o comprimento da t é maior que 0.
Há alguma corda lá. O usuário digitou alguma coisa dentro
Qual é a linha 32, fazendo, aparentemente?
[Resposta do aluno inaudível] Direito. >> Você pode tipo de inferir-lo de que eu disse que está fazendo.
Mas, tecnicamente, o que se está fazendo? t [0] representa o que?
[Aluno] O personagem 0. >> [Malan] O personagem 0.
Ou, mais semelhante à humana, o primeiro caractere em t, o que quer que seja, H talvez neste caso.
E toupper faz o que diz. Ele conta o caráter de t 0 e muda-la.
Então isso significa tomar o caráter de t 0, torná-lo maiúsculas,
e colocá-lo de volta no mesmo local.
Então, se eu digitar Olá em letras minúsculas, isso deve mudar a h minúsculas para um H. de capital
Mas o problema é que, em linhas 35 e 36 o que eu estou prestes a fazer é imprimir para nós s e t.
E qual é o seu palpite?
O que eu estou indo realmente para ver se eu digitei Olá em todas as minúsculas?
O que vai ficar impresso? >> [Resposta do aluno inaudível] >> O que é isso?
[Aluno] Big H eo resto pequeno. H >> O grande e pequena para o resto, que, s ou t?
[Aluno] Ambos. Tanto >>. Exatamente. Então, vamos ver o que está acontecendo aqui.
>> Deixe-me ir em frente e compilar este. Este é copy1, para fazer copy1. Tudo bem.
Zoom dentro Deixe-me ir em frente e correr copy1, Enter, dizer algo: Olá em minúsculas.
Ele capitalizados a cópia, mas, aparentemente, capitalizados o original, bem como,
porque o que agora acontece nesta história?
Na linha 27 eu realmente não parecem estar a copiar a cadeia,
mas mesmo que você pode ter a esperança de que intuitivamente ser o caso,
se você pensar sobre esse quadro, o que realmente eu fiz?
Metade do quadro é o mesmo.
Então, vamos reverter a tempo para que t ainda não existe na história.
S pode existir na história, mas vamos minúsculas Olá neste momento.
Então deixe-me corrigir o que eu realmente digitado dentro
Neste caso, temos aqui h-e-l-l-o.
Vamos desenhá-lo como uma seqüência de caracteres, colocar minhas linhas separadoras aqui e meu \ 0.
Portanto, este é o lugar onde estamos, assim como a linha de 1 a 24-ish, mais ou menos, ter executado.
Esta é a imagem da minha memória.
Quando eu chegar à linha 27, o que acontece?
Assim como antes, eu recebo um ponteiro, que eu vou desenhar como esta praça.
É chamado de t. E o que é o seu valor por padrão? Quem sabe? Algum valor lixo.
>> Então eu vou abstrata que fora como um ponto de interrogação.
E, logo que o lado direito da linha 27 executa, o que estou colocando dentro de t?
A mesma coisa que está em s.
Então, se por um momento remover essa abstração da seta e dizemos:
oh, este é o endereço de memória de carga 123, quando você diz que fica t s, ponto e vírgula,
você está literalmente colocando 123 aqui.
Agora, se nós tipo de simplificar o nosso mundo novamente com fotos,
o que você realmente feito é apenas acrescentou uma outra seta para o seu mundo
que está apontando de t para a mesma seqüência exata.
Assim, quando na linha 31 e 32 eu realmente ir sobre a mudança de t [0],
o que é t [0] aparentemente sinônimo de agora? s [0]
Então, isso é tudo o que está acontecendo.
E mesmo que esse tipo de sente um nível um pouco baixo e arcano
e esse tipo de sensação, talvez intuitivamente este deveria ter apenas trabalhado -
Fiz cópias de coisas antes e ele só trabalhou -
se você realmente pensar sobre o que realmente é uma string, é um char *.
Bem, o que é isso? É o endereço de algum personagem.
Então, talvez, faz mais sentido que, quando você tenta fazer algo
Super aparentemente simples como este, tudo o que você está fazendo é copiar o endereço de uma memória.
Você não está realmente fazendo alguma coisa com a seqüência em si.
Assim, mesmo se você não tem idéia de como você poderia resolver este problema no código,
alto nível, conceitualmente, o que nós precisamos fazer a fim de fazer ta cópia fiel da s, aparentemente?
Sim. >> [Aluno] Dê-lhe um novo local? >> Exatamente.
>> Precisamos dar t um local novo.
Precisamos de alguma forma criar um mundo em que temos um novo bloco de memória,
que apenas por uma questão de clareza eu vou desenhar logo abaixo um presente, mas ele não precisa estar lá.
Mas ele precisa ser do mesmo tamanho, então eu vou tirar essas linhas verticais no mesmo lugar.
É bom se tudo isso é lixo inicialmente. Quem sabe o que estava lá?
Mas, passo um vai ter que ser me dar tanta memória quanto eu preciso
para atender a uma cópia do Olá, em seguida, descobrir como copiar o h aqui, o e aqui,
o l, aqui e assim por diante.
Mas isso já deve sentir-se um pouco óbvio, mesmo se alguns dos detalhes ainda são abstratos.
Para copiar essa string para isso, é apenas um loop ou um loop while
ou algo com que você se tornou ainda mais familiar.
Então, vamos tentar isso. Deixe-me ir para copy2.c.
Em copy2.c temos quase o mesmo programa, exceto para a linha 27.
Parece um pouco complexo, mas se decompô-lo peça por peça,
o lado esquerdo é a mesma.
Char * t cria essa coisa na memória, ainda que com um ponto de interrogação
porque não temos idéia do que está lá por padrão.
No lado direito, estamos agora a introduzir uma nova função malloc,
para alocar a memória, dá-me a memória,
e, aparentemente, leva quantos argumentos, quantas coisas dentro de parênteses?
Eu ouvi murmúrios de 1 e 2, mas é apenas uma.
Não há vírgula, o que significa que há apenas uma coisa um dentro dos parênteses.
Mesmo que não haja parênteses outros, deixe-me destacar
o que está dentro dos parênteses ultraperiféricas, e é esta expressão:
(Strlen (s) + 1) * sizeof (char).
Então, se nós realmente pensar nisso, este está dizendo me dar o comprimento de s.
Por que eu sou, porém, adicionando 1 para o comprimento? >> [Resposta do aluno inaudível]
Exatamente. Precisamos de espaço para esse cara na cauda, ​​o sexto caractere que não tem sentido Inglês
mas tem significado programático especial.
>> Então precisamos de um + 1 para que, porque strlen retorna a expectativa humana de comprimento,
Olá ou 5, ele não lhe dá o caráter nulo adicional.
Então eu adicionar manualmente isso com + 1.
E depois disso, tamanho * de (char), não temos visto isso antes.
Este não é, tecnicamente, uma função.
É uma palavra-chave especial que só diz o que o tamanho é de algum tipo de dados em um computador
porque, na realidade, alguns de nós temos computadores de 32 bits.
Eu tenho um computador muito velho em casa, e só usa 32 bits para representar ponteiros.
E assim, se eu fiz tamanho de um tipo de dados, pode ser de 32 bits.
Mas se eu estou usando o meu novo computador fantasia, eu possa voltar um valor de 64 bits
para algo como um endereço.
Portanto, neste caso, apenas para ser seguro super, não vamos a algo rígido código como -
bem, o que é do tamanho de um char de acordo com o que temos dito até agora?
Nós praticamente disse verbalmente que é um byte, e isso é muito bonito verdade através da placa.
Mas, novamente, os pressupostos tendem a ser ruim.
Eles levam a software buggy se as pessoas usam seu software de forma que você não teve a intenção.
Então vamos abstrato esta distância e apenas mais genericamente dizer
Eu preciso disso muitos pedaços de memória
e cada bloco de memória deve ser equivalente ao tamanho de uma personagem,
que é de fato igual a 1 neste caso, mas é uma forma mais genérica de escrevê-lo.
Então, se a palavra é Olá, quantos bytes se malloc aparentemente alocar para Olá?
[Aluno] Six. >> Six. Exatamente como muitos como temos pontos de interrogação na tela.
E depois dar um palpite agora baseada em sua compreensão de GetString
o que malloc provavelmente voltar? >> [Aluno] Um endereço.
Um endereço de quê? Do primeiro pedaço de memória.
>> Nós não temos idéia do que está lá porque alguma outra função
poderia ter sido utilizando a memória anteriormente.
Mas malloc, como GetString, retorna o endereço do primeiro byte de memória
que ele tem reservado para você.
No entanto, o que ele não faz é preencher este vazio com um caractere nulo barra invertida
pois verifica-se que você pode usar malloc para alocar qualquer coisa: ints, strings, arrays,
carros alegóricos, estruturas estudantis.
Você pode usar malloc completamente genericamente.
Ele não se importa ou tem que saber o que você está alocando memória para.
Portanto, seria presunçoso para malloc para colocar um \ 0
no final de cada pedaço de memória que ele está dando a você
porque esta \ 0 coisa é apenas uma convenção para cordas.
Ela não é usada para ints, ela não é usada para carros alegóricos, ela não é usada para os alunos.
E assim a pegadinha com malloc é que o ônus é inteiramente de você o programador
lembrar quantos bytes você alocado e não para nunca usar um laço
ou um loop while e ir além do limite do bloco de memória que você tem dado.
Dito de outra forma, tão logo você alocar memória,
você não pode pedir o sistema operacional, oh, a propósito, o tamanho de um bloco de memória foi isso?
É inteiramente até você se lembrar se você precisa esse valor.
>> Então, vamos ver como eu continuar a usar esta memória.
Na linha 28 e 29, por que estou fazendo isso?
Basta verificar a sanidade total.
Apenas no caso de algo der errado, eu pedir alguma quantidade louca de memória
ou eu tenho tantas coisas em execução no computador que simplesmente não há memória suficiente,
algo assim, eu pelo menos quero para verificar nulo.
Na realidade, a maioria dos computadores vai lhe dar a ilusão de que todos os programas
pode utilizar a totalidade de sua memória RAM,
mas, mesmo assim, se o usuário digita alguma corda louco longa talvez porque é um cara ruim
e eles estão realmente tentando travar o seu programa ou hack para ele,
você quer, pelo menos, verificar o valor de retorno de malloc e se iguala nulo.
E se isso acontecer, vamos parar agora porque eu não sei o que fazer nesse caso.
Como faço para copiar a cadeia? Há algumas maneiras de fazer isso.
Há str copiar funções em C, mas é super simples para nós para fazer isso da maneira old-fashioned.
>> Primeiro deixe-me descobrir o que o comprimento de s é.
Eu poderia ter colocado isso no loop, mas em vez disso, basta colocá-lo aqui para maior clareza.
Então n agora armazena o comprimento da string original, o que aparentemente é 5.
Então, no meu laço para Estou interagindo em 0 até n,
e em cada iteração eu estou colocando s [i] dentro de t [i].
Então é isso que eu implicava com meus dois dedos apontando para as cordas antes.
Como este laço for assim, eu vou estar copiando h em aqui,
e em aqui, eu para aqui porque este é s, este é t.
E então, finalmente, na linha 35, por que estou fazendo isso?
Eu preciso ter certeza de que eu estou terminando o t string.
E eu fiz isso dessa maneira de ser super explícito.
Mas propor, alguém, se você pudesse, uma maneira diferente de fazer isso.
Eu realmente não precisa de linha 35. Há outra maneira de fazer isso.
Sim. >> [Resposta do aluno inaudível] >> Diga mais alto.
[Estudante] Menos do que ou igual a. >> Exatamente.
Poderíamos apenas dizer menos do que ou igual a n, o que em geral tem sido mal
porque quase sempre quando vamos para um igual à coisa estamos contando
vamos um passo longe demais.
Mas lembre-se, quantos bytes que nós alocar?
Alocamos strlen de s, de modo 5 + 1, para um total de 6.
Portanto, neste caso, poderíamos fazer algo assim
de modo que nós estamos copiando não apenas o Olá mas também a 0 \ no final.
Alternativamente, poderíamos usar uma função chamada str cópia, strcpy,
mas isso não seria divertido quase tanto quanto.
Mas isso é tudo que ele faz debaixo do capô.
Então, por fim, fazemos a mesma coisa que antes.
Eu t capitalizar e eu afirmo que o original é assim ea cópia parece assim.
Então, vamos tentar isso agora. Deixe-me ir aqui. Faça copy2. Nós vamos ampliar e executar copy2.
Eu estou indo para digitar Olá em letras minúsculas, e de fato eu fico minúsculas Olá como o original
mas o capital Olá para a cópia.
Mas eu não estou pronto ainda. Eu preciso fazer uma última coisa aqui.
46 e 47 é claramente liberar memória, mas o que isso realmente significa?
O que estou fazendo, você acha que, chamando linha 46 e linha 47?
Qual o efeito que isso tem? Sim.
[Resposta do aluno inaudível] >> Exatamente.
>> Você está apenas dizendo o sistema operacional, hey, obrigado por esta lembrança.
Agora você pode usá-lo para outra pessoa.
E aqui está um exemplo perfeito de valores de lixo.
Acabo de utilizar esta memória para escrever a palavra Olá em 2 lugares,
aqui, aqui, aqui e aqui.
Portanto, este é h-e-l-l-o-\ 0.
Mas, então, eu chamo de linha 46 e linha 47, e você sabe o que acontece lá em termos de imagem?
Na verdade, esperar, esta foto é a antiga.
Uma vez que a cópia, esse cara é realmente apontando aqui,
então vamos remover os números e apenas abstrair como nossas flechas novamente.
O que acontece na foto quando eu chamo livre?
[Resposta do aluno inaudível] >> Nem mesmo.
Se eu ligar gratuitamente em S e T - um tipo de pergunta capciosa - esta imagem não muda em nada
porque chamar s e chamando t apenas diz ao sistema operacional,
hey, você pode usar essa memória de novo, mas isso não muda isso nulo
ou algum caractere especial, não mudar isso,
isso não muda o H ou o e ou o l ou l ou o em qualquer lugar para qualquer outra coisa.
Em termos de imagem, tão logo você ligue grátis mudanças, nada.
E é aí que reside a origem de valores de lixo porque se eu, mais tarde, no programa
pedir ao sistema operacional para mais de memória com GetString ou malloc ou algo parecido
eo sistema operacional, diz, com certeza, eu tenho 12 bytes de memória apenas libertados,
usá-los, o que é que vai ser entregue?
Você vai ser entregue um pedaço de memória que normalmente desenhar
com pontos de interrogação, mas o que são esses pontos de interrogação?
Eles acontecem ser h-e-l-l-o, h-e-l-l-o.
Estes são os nossos valores de lixo novos assim que liberar a memória.
>> Há um mundo real implicação aqui também.
Isso acontece a ver com memória RAM, mas seus computadores
realmente fazer a mesma coisa com o disco.
Nós vamos falar sobre isso em particular com um conjunto de problemas futuros que incide sobre forense.
Mas o que realmente acontece se você tem algum arquivo confidencial financeira em seu desktop
ou algum JPEG esboçado e arrastá-lo para o seu lixo,
o que acontece quando você arrastá-lo para o lixo ou a lixeira?
Você sabia o que eu estava falando. [Risos]
O que acontece quando você arrastou que a evidência em sua lixeira ou lata de lixo?
[Resposta do aluno inaudível]
Bem, então cuidado. O que acontece quando você faz isso?
A resposta curta é nada, certo?
Arquivo esboçado ou sensíveis ainda está apenas sentado em algum lugar no seu disco rígido.
A maioria de nós, pelo menos, ter aprendido da maneira mais difícil que você precisa esvaziar seu lixo
ou a sua lixeira para realmente apagar arquivos.
E, de fato, quando você clique direito ou clique em sua lata de lixo
Lixo ou escolher Arquivo, vazio ou o que quer
e você realmente esvaziar a lata de lixo ou lixeira, o que realmente acontece em seguida, para esta imagem?
Mais nada. Portanto, nada realmente acontece no disco.
>> E se nós apenas temporariamente divagar e escrever - eu só usar a parte de trás do presente.
Então, agora a história está mudando de RAM, que é onde existem programas
enquanto você está executando-os, para o disco, que é onde eles são armazenados a longo prazo
mesmo quando o poder sai, por enquanto - e nós vamos voltar a isso no futuro -
vamos fingir que isto representa o interior do disco rígido do seu computador
porque para trás no dia costumavam ser discos circulares, bem como disquetes.
Então, se você tem algum arquivo do Excel sensível, pode levar até este pedaço de memória
no disco do seu computador, e eu estou apenas desenhando 1s e 0s mesmo arbitrário.
Quando você arrasta o arquivo como que a sua lata de lixo ou lixeira,
literalmente nada acontece porque a Apple ea Microsoft simplesmente decidiu
a lata de lixo e lixeira é realmente apenas um espaço reservado temporário.
Talvez, eventualmente, o sistema operacional irá esvaziá-la para você, mas, normalmente, não faz nada,
pelo menos até que você esteja realmente com pouco espaço.
>> No entanto, quando você vai para o lixo vazio ou lixeira vazia,
da mesma forma, nada acontece com esta imagem.
Tudo o que acontece está em outro lugar no seu computador, existe algum tipo de mesa.
É como uma espécie de folha de fraude pouco que diz que, vamos dizer, RESUME.DOC,
para que o seu currículo em um arquivo do Microsoft Word morava no local 123 no seu disco rígido,
não na memória e não na memória RAM, mas no seu disco rígido,
e suas vidas esboçado JPEG com 456, e seu arquivo de Excel vive em 789 ou em qualquer lugar.
Ao excluir arquivos por realmente esvaziar a lixeira ou a lixeira,
esse quadro não muda. Os 0s e 1s em seu disco rígido não vão a lugar nenhum.
Mas este quadro, este banco de dados pouco de sorte, faz a mudança.
Quando você excluir o seu currículo, é como se o arquivo é apagado em algum sentido,
mas todo o computador faz é esquecer de onde essa coisa vive no seu disco rígido.
Os 0s e 1s que compõem o seu currículo ou qualquer um desses outros arquivos ainda estão intactos.
>> Então, se você fez isso acidentalmente, ainda há uma probabilidade não-zero
que você pode recuperar seus dados usando o Norton Utilities ou algum software comercial
cujo objetivo de vida é encontrar 0s e 1s que tipo de órfãs,
esquecido aqui, mas deixaram aqui, de modo que você pode obter seus dados de volta.
Ou investigadores forenses com a polícia ou o FBI teria realmente ter um disco rígido
e realmente olhar para os padrões de 0s e 1s que olhar como JPEGs, olhar como arquivos do Excel,
e recuperá-los dessa forma, mesmo que o computador tenha esquecido lá.
Então a única maneira realmente para apagar dados, como discutiremos no futuro,
é esfregar ou limpar o arquivo ou disco rígido -
Você realmente não pode se livrar do 0s e 1s
porque senão você ia começar com uma unidade de gigabytes
e você acabar com uma unidade de megabyte difícil se você constantemente se apagar,
literalmente, 0s e 1s.
Então, o que você faria se você realmente queria para cobrir seus rastros
e que o problema fundamental é que ainda há 0s e 1s no disco?
Eu vejo alguém gesticulando que você fisicamente quebrar o dispositivo. Que irá trabalhar.
[Risos] Mas, se esse é o tipo de uma solução cara, o que seria mais razoável?
Sim. >> [Aluno] substituí-los. >> Substituí-los com o quê? >> [Estudante] Outros dados.
Outros dados. Você pode simplesmente substituir o disco com 0s ou 1s ou todos os 0s, todos os 1s.
>> E isso é de fato o que alguns dos softwares faz.
Você pode comprar o software ou até mesmo obter o software livre,
e até mesmo construído no Mac OS estes dias, menos no Windows,
é a capacidade de apagar com segurança.
Na verdade, se você quiser todos os home run hoje, se você tem um Mac e fazer isso,
se você tem alguma coisa na sua lata de lixo, você pode fazer Esvaziamento Seguro do Lixo,
que faz exatamente isso.
Em vez de apagar arquivos apenas aqui, isso não apaga o aqui 0s e 1s,
ao contrário, ela apenas muda todos eles, por exemplo, para 0s e ponto, ponto, ponto.
Então, um de seus futuros Série de Exercícios será realmente intencionalmente recuperar dados -
fotografias que você tirou de pessoas, lugares e coisas no campus
para o qual vamos fazer uma imagem forense de um cartão de memória da câmera digital,
que é a idéia mesma - e você vai ter que ser desafiados a realmente encontrar
os padrões que representam JPEGs em seu disco rígido,
muito parecido com o ex-aluno, cujo e-mail que li há algumas semanas fez
para recuperar fotografias de sua irmã.
Por que não fazemos um intervalo de 5 minutos aqui, e nós vamos reagrupar com mais memória.
Então é aqui que as coisas ficam um pouco alucinante, mas este é um passo muito poderoso
para a compreensão de tudo isso o mais.
Aqui está um programa chamado pointers.c.
É entre código de hoje amostra.
Note que em primeiras linhas, 19 a 22, tudo o que estamos fazendo é algo como GetString
e retornando um endereço, armazenando-o em s.
Doravante para pset mesmo 3 se quiser, mas pset 4 e no
onde você pode começar a tomar essas rodinhas mesmo,
não há razão para fingir que as cordas existe mais.
É certamente bom para apenas começar a dizer * char.
>> Como um aparte, em referências on-line e em livros muitas vezes você pode ver a estrela ao lado da variável.
Você pode até mesmo ver os espaços em torno de ambos os lados.
Todas estas são funcionalmente correcta.
Por enquanto, porém, vamos padronizar essa abordagem para tornar super claro
que char * é como dizer ponteiro personagem.
Isto é o tipo de dados.
E, em seguida, o nome da variável é s no presente caso.
Então, nós temos tido uma corda e nós chamamos ele s.
E então aqui notar que eu estou fazendo, na verdade, um pouco de malandragem.
Isso é chamado de aritmética de ponteiro, que é uma espécie de super simples.
Significa apenas somar e subtrair números para ponteiros.
Mas isso realmente funciona.
Este programa imprime o caráter aparentemente string s 1 por linha de tal forma que o resultado final -
Só assim podemos estragar onde isso vai dar, fazer ponteiros, ponteiros correr, deixe-me fazer zoom in
Agora deixe-me digite algo como OLÁ e digite Enter
e imprime um caráter por linha.
Até um segundo atrás, teria feito isso com a notação de colchete.
Teríamos um loop e nós faríamos printf de s [i] e nós faria isso de novo e de novo e de novo
com a n invertida no fim de cada linha.
Mas este programa é diferente. Este programa está usando, literalmente, aritmética.
Então, o que está acontecendo aqui?
Primeiro de tudo, antes mesmo deste ciclo é executado, o que, só para ficar claro, é realmente s?
S é? >> [Aluno] Um endereço. >> Um endereço.
>> E é o endereço, no caso de Olá, o primeiro caractere em que a palavra, que é h.
Então s é, neste exemplo particular, o endereço de h.
Então, o que isso significa para fazer s + i?
Bem, eu começa em 0 neste loop. Nós fizemos muitas vezes que.
Eu está indo para ir até o comprimento da corda, aparentemente.
Assim, na primeira iteração do loop, i é, obviamente, 0.
Portanto, esta expressão está dizendo s + i - em vez disso, s +0--que é, obviamente, apenas s.
Então, o que é * s aqui?
Agora estamos usando a estrela de uma forma ligeiramente diferente.
Deixe-me ir em frente e se livrar de t, porque estamos falando de t feito e cópias de s.
Agora só quero contar uma história envolvendo s.
E por isso, neste momento, depois de ter tipo string, nosso mundo parece muito como fazia antes
s com apenas armazenar o endereço de h e, mais geralmente apontando para a cadeia Olá.
Se eu agora fazer uma linha como * (s + i), vamos tentar fazer isso.
Então * (s + i). Deixe-me simplificar isso porque este é 0, o que é * (s 0).
Bem, espere um minuto. Simplificar ainda mais. Este é * (s).
Bem, agora os parênteses são uma espécie de idiota, então agora vamos fazer * s.
Assim, na primeira iteração do loop, que a linha que está em destaque, 26,
é muito bonito equivalente a imprimir este.
Qual é o tipo de dados * s?
Neste contexto, uma vez que a estrela passa a ser o lado de si s,
mas, mais especificamente, porque já não estamos declarando s,
não estamos criando uma variável mais, não há nenhuma menção de char * na linha 26,
não há nenhuma menção da string palavra-chave, estamos usando apenas uma variável chamada s,
verifica-se agora a estrela tem um pouco diferente e, reconhecidamente, confundindo significado.
* S, aqui, significa ir para o endereço em s e imprimir o que está lá.
Então s é aqui, * s é - algo como rampas e escadas, siga a seta - aqui.
Portanto, esta é * s.
>> Então, o que é impresso na primeira iteração do loop de que na linha 26?
Eu imprimir% c, que é o espaço reservado para um personagem,
em seguida, um \ n para uma nova linha. * (S + i) onde i é 0 é só isso.
Então, o que de char que eu colocar em para c%? H.
Na próxima iteração do loop - você provavelmente pode ver onde isso vai dar -
a próxima iteração i é, obviamente, um, então isso significa s 1,
e então agora eu preciso dos parênteses porque agora a estrela precisa dizer
ir para o endereço de memória de 1.
O que é s? Vamos reverter no tempo e dizer esta seta agora não está realmente fazendo-nos quaisquer favores.
Vamos, mais especificamente, dizer que este é armazenar o número 123
porque o início desta cadeia Olá, isto é o endereço 123, este é 124, e assim por diante.
Então, na segunda iteração quando eu estou dizendo s 1, que é como dizer que um 123,
também conhecido como 124, então o caractere é impresso na segunda iteração?
E no endereço de memória 124.
Então + novamente, 125, 126, 127, e este laço felizmente parar antes de chegarmos aqui
porque eu estou usando strlen para ter certeza de que eu não conta muito alta.
Então, isso também é isso.
Novamente, isso é como se tivéssemos feito uma semana atrás.
Deixe-me escrever na linha abaixo mesmo que nós não queremos fazer os dois.
Isto é idêntico a este agora.
>> Assim, mesmo que s é uma string, como estamos chamando ele por semanas, s é realmente um char *.
Então, se nós queremos ser anal super, é realmente correta de escrever o carácter específico
no local ith utilizando estes endereços numéricos e este operador estrela,
mas, francamente, este é mais limpo tanta coisa. Então isso não é ruim.
Não há razão para parar de fazer linha 27 aqui, mas 26 é funcionalmente o mesmo,
e é funcionalmente o mesmo para exatamente as razões que estamos discutindo até agora.
E, por último, 29 é prática apenas bom.
Chamando livre s significa que agora você está dando de volta a memória que lhe deu GetString
porque mais uma vez, como mencionei segunda-feira, GetString de semana
foi a introdução de um bug em seu código.
Seu código de semana teve vazamentos de memória
pelo qual você foi perguntando GetString para a memória, mas você nunca foi dando-lhe de volta.
E que foi deliberadamente escolhido por nós pedagogicamente
porque é muito pouco para pensar no início.
Mas agora precisamos de mais simetria.
Se pedir ao computador para a memória, tal como é o caso para GetString,
como é o caso, aparentemente para malloc,
Você deve agora para pset diante 4 também qualquer memória livre tal.
Note que isto é diferente de dizer n int.
Você não precisa liberar isso porque você não chamou GetString
e você não chamar malloc.
>> E mesmo se você chamou GetInt como vai finalmente ver,
GetInt não aloca memória para você, porque você pode realmente passar em torno de números inteiros
e carros alegóricos e chars apenas a forma como temos vindo a fazer para a semana.
Cordas, porém, é especial porque realmente eles são a concatenação de caracteres múltiplos.
Então, eles estão apenas diferente de caracteres e carros alegóricos e ints e similares.
Mas vamos voltar ao que antes do tempo.
Quaisquer perguntas, então neste início de ponteiros? Sim.
[Pergunta estudante inaudível]
Ah, boa pergunta.
Uma das poucas coisas que realmente C faz para você, o que é conveniente,
é ele descobre para você o que é o tamanho do tipo de dados
e depois faz esse tipo de multiplicação para você.
Isso é irrelevante no caso de caracteres, porque quase sempre é char a 1 byte,
então isto funciona.
Mas, por causa da discussão, se você estivesse realmente imprimir inteiros
e você estava tentando imprimir alguns o valor que estava apontando para um número inteiro,
você da mesma forma não teria necessidade de fazer + 4 * i só porque um int é de 4 bytes.
Aritmética de ponteiro significa que o compilador C e fazer toda a matemática que para você.
Tudo que você tem que se preocupar é a contagem em uma espécie de sentido humano. Sim.
[Estudante] Se você declarar uma seqüência dentro de um loop for, você tem que libertá-lo depois?
Boa pergunta.
>> Se você declarou uma corda dentro do loop for, você precisa liberá-lo mais tarde?
Você só precisa de memória livre que você alocar com GetString ou com malloc.
Então, se você acabou de dizer algo como - deixe-me colocar chaves agora assim todo o código está relacionado.
Se você fez alguma coisa, ainda que buggily, como este, char * t = s,
você não precisa de t livres, porque t não envolveu qualquer menção de malloc ou GetString.
Se, pelo contrário você fez isso, GetString, então sim, você precisa t livres.
E, de fato, sua única chance de fazer isso é agora dentro deste laço, para o mesmo problema de âmbito
que temos discutido no passado.
Caso contrário, você seria a alocação de memória, alocação de memória, alocação de memória,
e no final do programa, porque você está fora desse circuito,
t não existe, mas você nunca contou o sistema operacional
que você não precisa mais que a memória.
E em pouco tempo, para pset 4 ou 5 nós vamos equipá-lo com um programa chamado Valgrind,
que é semelhante em espírito a GDB em que ele tem um pouco de uma interface arcano,
mas seu propósito na vida é ajudá-lo.
E Valgrind é um programa que, no futuro, pesquisar seus programas
procurando por vazamentos de memória, seja de GetString ou malloc,
que nós vamos começar a usar tudo o mais que nós parar de usar a biblioteca CS50 tanto.
Finalmente agora temos um tipo do vocabulário e do tipo de modelo mental na teoria
com o qual se resolve este programa quebrado.
>> Portanto, neste programa quebrado, swap funciona dentro de swap,
mas nunca trabalhou realmente no principal porque principal passou em x e y, recall,
e aqueles que foram aprovados em por valores, por assim dizer.
Cópias deles foram dados para trocar.
Até o final de swap, a e b realmente tinha sido trocado,
mas é claro que x e y, como vimos na segunda-feira, não havia sido.
Então proponho em verde aqui que esta é realmente a solução aqui.
E, na verdade, deixe-me passar minhas estrelas apenas para ser coerente
apesar de, novamente, funcionalmente, isso não importa.
Nas semanas futuros vamos explicar quando e por que isso importa.
Então em verde agora é uma solução.
Francamente, parece um monte mais confusa, porque eu tenho todas essas estrelas.
Deixe-me apontar uma única coisa.
A linha de cima aqui onde diz int * a * b e int
é fundamentalmente fazer a mesma coisa que ele sempre tem.
É declarar que dois argumentos ou parâmetros para trocar,
a primeira das quais é um ponteiro int chamado,
a segunda das quais é um ponteiro int chamado b.
A única coisa que há de novo neste ponto é o fato de que há uma estrela lá.
>> O que significa isso? A não é um int, b não é um int.
Um é o endereço de um int e b é o endereço de um int diferente.
Aqui, é aqui que eu admito C fica confuso.
Agora estamos usando uma estrela, mas tem significado diferente neste contexto.
Porque nós não estamos declarar ponteiros como estamos aqui,
aqui estamos dereferencing coisas.
Então, tecnicamente, a estrela neste contexto de primeira linha, segundo e terceiro dentro de swap
é o operador dereference, o que significa apenas ir lá.
Assim como meu dedo seguiu a seta para h,
* Um meio ir para esse endereço e me achar o int que está lá.
* Significa que B vá para o endereço e passar-me o que está lá.
Então, vamos redesenhar a imagem de segunda-feira usando agora uma pilha de quadros,
o fundo do qual vai ser principal,
a superior das quais vai ser de permuta,
para que o nosso mundo olha, assim como segunda-feira, como este.
Aqui é um pedaço da memória principal é que vai usar.
>> Lembre-se de segunda-feira que o programa só tinha duas variáveis,
um chamado x e y um chamado, e eu tinha colocado os números 1 e 2 lá.
Agora, quando eu chamo trocar como eu fiz na segunda-feira,
anteriormente, quando eu usei a versão vermelha deste programa, que se parece com isso,
Eu tenho dois parâmetros, A e B, eo que nós escrevemos aqui e aqui?
Apenas 1 e 2, literalmente copia de x e y.
Hoje nós mudar isso.
Hoje, em vez de passar em ints a e b, vamos passar em dois endereços.
Esses endereços acontecer para apontar para ints, mas esses endereços não são ints si.
Eles são endereços. É como um endereço postal vez.
Então agora precisamos apenas dar a mim mesmo um pouco mais detalhadamente sobre a tela.
Esta é a memória do meu computador como tem sido todos os dias.
Agora precisamos de algum esquema de numeração arbitrária.
Então vamos apenas dizer que, só por acaso, que este é o endereço de memória 123, 124.
Vamos apenas dizer que este é 125, isso é 126, e assim por diante, mas isso é totalmente arbitrário.
Nós só precisamos de algum esquema de numeração em minha memória.
Então agora quando eu realmente passar em x e y, eu não vou passar em x e y;
Vou passar o endereço postal, por assim dizer, de x e de y
de modo que o que fica armazenado aqui e aqui não é 1 e 2,
mas se você pode ver o meu pequeno texto, o que é passado aqui e aqui?
[Resposta do aluno inaudível] >> Exatamente. 123 é colocado aqui e 124 é colocado aqui.
>> Agora, porque eu usei a estrela desta forma primeira linha aqui em cima,
meu programa só sabe que 123 e 124, apesar de serem, obviamente, inteiros
que qualquer humano poderia notar, eles devem ser interpretados como endereços, endereços numéricos.
Eles não são em si mesmas ints, eles são endereços,
e isso é porque eu explicitamente coloca as estrelas lá.
Então agora na minha linha primeiro, segundo e terceiro do código real o que acontece aqui?
Vamos desenhar o resto da imagem.
Tmp é exatamente como era na segunda-feira. Nada de especial sobre tmp.
É apenas um local de 32 bits variável, e dentro do que eu estou aparentemente armazenar o valor de um arquivo *.
Agora, se eu apenas disse tmp = a, o que eu colocar aqui? >> [Aluno] 123.
123. Mas isso não é o que eu estou fazendo.
Eu estou dizendo tmp = * a. Significa estrela ir lá.
Então aqui vai uma, 123. Como posso ir para lá? Fingir que não há uma seta.
Bem, aí está, 1. Então, o que fica armazenado em tmp, aparentemente? Apenas 1.
Portanto, em outras palavras, é tmp * a *, um meio ir para o endereço que está atualmente em uma,
que aparentemente é 123.
>> Ok, aqui estamos na posição 123, eu vejo o número 1,
então eu vou colocar o número 1 lá.
Agora o que eu faço na linha 2, a * = * b?
Este é um pouco mais complicado, porque agora o que é um? É 123.
Então, a * é onde? Exatamente onde eu estava antes. Então, vá lá. Okay.
Agora, finalmente, e então finalmente isso vai começar a fazer sentido, espera-se,
* B significa que está em b? 124. Então eu preciso ir lá, que é 2.
Então, o que faço para colocar onde?
2 entra aqui, porque vai para * b * a. Então, eu vou fazer isso.
E você já pode ver, talvez, de que estamos muito mais perto
para resolver este problema, estúpido simples corretamente pela primeira vez
porque agora nós ainda temos uma lembrança do que foi x,
temos duas cópias, reconhecidamente, de y,
mas a linha 3 agora diz * b.
Então aqui está b. * B meios para lá. Então, onde é o local 124?
É aparentemente aqui. Então o que eu colocar aqui? Obviamente tmp.
Então agora eu faço isso. Então, eu tenho uma aqui e 2 aqui.
E agora o que dizer de tudo isso, o 123, o 124 eo 1?
Assim que retorna de swap, essa memória é tão bom como perdido
porque assim como o retorno de swap, o sistema operacional
é livre para usar a memória novamente no futuro.
Apenas a memória principal, na parte inferior desta pilha de chamada varas em torno.
>> E assim finalmente temos agora uma versão de trabalho.
Deixe-me ir para swap.c, e observe o seguinte.
No topo do programa que eu mudei o meu protótipo para ser int * a * b e int.
Assim, a única coisa que mudou para ir de vermelho, o que foi ruim, para o verde, que é bom,
é que eu adicionei estas estrelas de hoje.
Mas, então, aqui no próprio swap eu tinha que copiar, colar o que era apenas no slide.
Eu tenho uma estrela aqui, estrela aqui - que coincide com o protótipo -
e depois de todas essas coisas agora tem estrelas, exceto para tmp
porque o uso de uma variável temporária, não há nada de novo nisso.
Eu só preciso de armazenamento temporário para um int.
Então, nós não precisamos de uma estrela lá.
Nós só precisamos de uma estrela, para que possamos atravessar esse tipo de limite arbitrário
entre esses dois quadros na memória do meu computador.
Mas uma última coisa que tem de mudar, e você pode ter vislumbrado já.
O que outra linha é obviamente diferente agora? >> [Aluno] & x.
>> Sim, então 25 é a última linha de código que eu preciso mudar para que isso funcione.
Uma semana atrás, e até mesmo na segunda-feira da linha 25 ficou assim, trocar x e y,
e este foi apenas quebrada porque se você diz swap (x, y)
você está dando cópias de X e Y para trocar, então ele está fazendo a sua coisa,
mas você nunca está realmente mudando x e y si.
Assim, mesmo se você nunca viu esse personagem antes com o comercial no código,
apenas dar um palpite. O que faz o comercial fazer, aparentemente?
[Aluno] É de endereço. >> Toma o endereço.
Assim, o comercial está dizendo me dar o endereço de x.
Quem sabe onde é? Ele passa a ser 123. Eu não me importo. Apenas me dê o endereço de x.
& Y significa dar-me o endereço de y.
E nesse ponto a história é perfeitamente consistente com a imagem que desenhou um momento atrás.
>> Então, eu vou admitir ponteiros, certamente para mim, quando eu comecei a aprender isso,
foram definitivamente uma das coisas mais difíceis de envolver minha mente.
Mas perceber, especialmente à medida que continuar a jogar com esses tipos de coisas,
se você decompô-lo para este tipo super simples de intelectualmente desinteressante problemas
de apenas se movendo em torno de números, a resposta a uma grande confusão com ponteiros
realmente pode ser obtido a partir destes mecânica muito básicas.
Aqui está um endereço. Vá com a estrela.
Ou, inversamente, aqui está um e comercial. Descobrir o que o endereço realmente é.
Tudo bem.
Então, onde está toda essa memória vem?
Nós colocamos esta imagem de um par de vezes, e eu continuo promissor vamos voltar a ele,
mas aqui é a representação da memória do seu computador
que é um pouco mais marcado do que o nosso quadro aqui é.
O segmento de texto na parte superior representa o que diz respeito ao seu programa?
[Resposta do aluno inaudível] >> Desculpa? Diga novamente.
[Aluno] O programa real. O programa >> real.
>> Assim, o Clang 0s e 1s que você tenha compilado depois de escrever código C e em seguida, executando
e gerando extremidades 0s e 1s por ficar escondido lá na memória
porque quando você duplo clique em um ícone no seu Mac ou PC
ou executar um comando como mario em seu prompt, seu 0s e 1s do disco
são carregados na memória para que o computador possa manipulá-los
e executá-los mais rapidamente.
Dados para inicializados e os dados não inicializados, não vamos falar muito sobre aqueles,
mas essas são apenas variáveis ​​globais.
Inicializado significa variáveis ​​globais que você deu valores para;
não inicializado significa variáveis ​​globais que você ainda não dão valores para.
Depois, há as variáveis ​​de ambiente que eu vou completamente a minha mão a onda,
mas eles estão lá e que armazena coisas como seu nome de usuário
e outro tipo de detalhes de nível inferior.
Mas os mais suculentos pedaços de layout de sua memória é essa coisa chamada a pilha eo heap.
A pilha de novo, para ser claro, é a memória que é usada sempre que funções são chamadas,
sempre que houver variáveis ​​locais
e sempre que há parâmetros que estão sendo repassados.
Tudo o que acontece na pilha.
A pilha não temos falado, mas dar um palpite que usa a pilha.
Apenas um pedaço diferente de memória.
Ele passa a ser feita aqui em cima, mas isso é uma convenção arbitrária pictórica.
Que aparentemente estava usando a memória da pilha de semana?
É tecnicamente você, mas indiretamente. >> [Aluno] GetString.
GetString e malloc. Então aqui está a diferença fundamental.
>> Você sabe para as últimas semanas que, se você precisa de memória, basta declarar uma variável.
Se você precisa de muita memória, declarar uma matriz direito dentro de sua função.
Mas o problema que nós enfrentamos é mantido se você declarar variáveis ​​locais dentro de funções,
logo que o retorno da função, o que acontece com a memória e aquelas variáveis?
Apenas o tipo de que não é mais seu, certo? Ele simplesmente desaparece tipo de conceitualmente.
Ainda é fisicamente lá, obviamente, mas ele não é mais o seu direito de uso.
Esta é, obviamente, um problema se você quiser escrever funções na vida
que realmente alocar memória e não devolvê-lo imediatamente.
Caso em questão: GetString propósito na vida é não ter idéia de antecedência
como grande de uma corda Eu vou digitar no teclado,
mas ele tem que ser capaz de alocar memória para armazenar David ou Olá
ou ensaio um todo que o usuário pode ter digitado dentro
Então GetString vem usando malloc.
Malloc, portanto, não deve estar usando a pilha;
em vez disso, está usando essa coisa chamada heap.
Não há nada diferente sobre a memória. Não é mais rápido ou mais lento ou qualquer coisa assim.
É apenas fisicamente em um local diferente.
>> Mas a regra é que a memória que está alocada na pilha
nunca ser tirado de você até que você chamar - dar um palpite - livre.
Por outro lado, qualquer memória que você pedir na pilha por apenas declarar uma matriz
ou declarar uma variável como temos vindo a fazer para a semana,
que, por padrão acaba na pilha.
E que funciona 90% grande parte do tempo, mas nessas ocasiões mais raras
onde você quer alocar memória e mantê-lo por perto,
então você precisa usar uma função como malloc.
Ou nós usamos uma função como GetString, que por sua vez usa malloc.
Vamos ver onde isso pode quebrar e, em seguida, dar uma olhada no Binky.
Nós vamos voltar a isso no futuro.
Aqui está um programa super simples que nos primeiros 2 linhas faz o quê?
Em Inglês, o que essas 2 primeiras linhas de código fazer dentro de principal?
[Resposta do aluno inaudível]
Cuidado. Ele não me dá o endereço de x ou y.
[Estudante] dá ponteiros para ints. >> Boa. Dê-me dois ponteiros para inteiros.
Em outras palavras, dá-me dois pedaços de memória que guardo desenho de hoje,
mesmo que eu apaguei-o agora, como quadrados.
Dê-me dois pedaços de memória, um chamado x, y um chamado -
antes eu chamava S e T - e qual é o tipo de que pedaço da memória?
Vai para armazenar um endereço.
É de * tipo int.
>> Assim, o endereço de um int irá eventualmente vivem em x,
o endereço de um int acabará por viver em y,
mas, inicialmente, o que está dentro de X e Y? Quem sabe? Valores de lixo.
Não tem nada a ver com ponteiros.
Se não colocar alguma coisa lá, quem sabe o que realmente está lá?
Agora, x. O que acontece aqui? Isso é legal agora porque x é um ponteiro. É um int *.
Então isso significa que eu posso colocar em x o endereço de algum pedaço de memória.
O que malloc retornar? Perfeito, ele retorna endereços,
o endereço do primeiro byte de um bloco inteiro de memória.
Quantos bytes é o que parece atribuir, por exemplo, no interior do aparelho?
Qual é o tamanho de um int? 4.
Se você acha que volta para uma semana, não é super importante sempre lembrar que,
mas, neste caso, é útil saber, 4 bytes.
Portanto, este é alocar na pilha 4 bytes
e é o endereço de retorno da primeira para me arbitrariamente.
Agora, o que está fazendo x?
A * x = 42 está fazendo o que?
Se neste ponto da história que temos x, que se parece com isso com algum valor de lixo,
este é agora y com algum valor de lixo, agora na linha 3 eu alocados 4 bytes.
Esta imagem essencialmente parecido com este.
Ou, mais especificamente, se esta é arbitrária endereço 123, isso é o que a nossa história agora parece.
* X = 42 agora significa o quê? Isso significa ir para o endereço 123 e colocar o número 42 lá.
Eu não preciso chamar a estas linhas, porque nós não estamos fazendo cordas.
>> Eu deveria ter escrito assim, e apenas por causa da manifestação, o
42 como uma espécie de int ocupa muito espaço, 4 bytes.
Então, isso é o que aconteceu lá, mas há um problema agora.
* Y = 13. O que vai acontecer aqui?
O problema é * y em nosso mundo simplificado significa apenas ir para o endereço em y.
O que está em y? É algum valor lixo.
Então, vamos supor que esse valor de lixo é 5551212, algo louco assim.
Meio * y ir para abordar 5551212.
Isso é como aqui. Não existe, por exemplo.
Então * y recebe 13 significa que eu estou tentando tirar 13 aqui. Ele não existe.
Eu já excedeu o segmento do quadro negro. O que eu ganho?
Essa falha de segmentação enigmática mensagem porque eu estou tentando colocar na memória
um valor como 13 em um lugar que não existe.
O resto do programa pode funcionar bem, mas até que ponto isso não acontece.
Então, vamos tentar contar essa história.
Nós vamos voltar para que, uma vez que falamos de feitiço.
Vamos voltar a este e concluir com essa coisa chamada Binky,
que recall é um professor de Stanford sentado em casa brincando com claymation,
para contar a história exatamente do programa que mesmo.
É apenas cerca de 3 minutos de duração. Aqui temos Binky.
[Orador masculino em vídeo] Hey Binky, acorda. É hora de diversão ponteiro.
[Binky] O que é isso? Saiba mais sobre ponteiros? Ah, bom!
[Orador masculino] Bem, para começar, eu acho que nós vamos precisar de um par de ponteiros.
>> [Binky] Okay. Este código aloca dois ponteiros que podem apontar para números inteiros.
[Orador masculino] Okay. Bem, eu vejo os dois ponteiros, mas eles não parecem estar apontando para qualquer coisa.
[Binky] Isso mesmo. Inicialmente, os ponteiros não apontam para nada.
As coisas que eles apontam são chamados pointees, e configurá-los é um passo separado.
[Orador masculino] Ah, certo, certo. Eu sabia disso. Os pointees são separados.
Er, assim como você alocar um pointee?
[Binky] Okay. Este código aloca um novo pointee inteiro, e esta parte define x para apontar para ele.
[Orador masculino] Ei, isso parece melhor.
Então ele fazer alguma coisa. >> [Binky] Okay.
Vou cancelar o ponteiro x para armazenar o número 42 em sua pointee.
Para este truque eu preciso da minha varinha mágica da dereferencing.
[Orador masculino] Sua varinha mágica de dereferencing? Isso é ótimo.
[Binky] Isto é o que o código parece. Eu só vou definir o número e ... [Estalando som]
[Orador masculino] Ei, olha, lá vai.
Então, fazendo um dereference em x segue a seta para acessar sua pointee,
neste caso para armazenar 42 em ali.
Ei, tente usá-lo para armazenar o número 13 até o outro ponteiro, y.
[Binky] Okay. Eu vou passar por cima aqui para y e obter o número 13 configurar
e depois tome a varinha de dereferencing e só ... [Zumbido] Whoa!
[Orador masculino] Oh, hey, isso não funcionou.
>> Diga, Binky, eu não acho que dereferencing y é uma boa idéia
que a configuração da pointee é uma etapa separada
e eu não acho que já fiz isso.
[Binky] Hmm, bom ponto.
[Orador masculino] Yeah. Alocamos o ponteiro y mas nunca configurá-lo para apontar para uma pointee.
[Binky] Hmm, muito observador.
[Orador masculino] Ei, você está parecendo boa lá, Binky.
Você pode corrigi-lo, de modo que y aponta para o pointee mesmo que x? >> [Binky] Claro.
Eu vou usar a minha varinha mágica da atribuição de ponteiro.
[Orador masculino] é que vai ser um problema como antes?
[Binky] Não, isso não toque nos pointees.
Apenas muda um ponteiro para apontar para a mesma coisa que o outro. [Estalando som]
[Orador masculino] Oh, eu vejo. Agora y aponta para o mesmo lugar que x.
Então, espere. Agora y é fixo. Tem um pointee.
Então você pode tentar a varinha de dereferencing novamente para enviar a mais de 13.
[Binky] Uh, tudo bem. Aqui vai. [Estalando som]
[Orador masculino] Ei, olha isso. Agora dereferencing obras sobre y.
E porque os ponteiros estão a partilhar que pointee um, ambos ver o 13.
[Binky] Sim, partilha. Qualquer que seja.
>> Então, vamos trocar de lugar agora?
[Orador masculino] Oh olha, nós estamos fora do tempo. >> [Binky] Mas -
[Orador masculino] Basta lembrar as três regras de ponteiro.
Número 1, a estrutura básica é que você tem um ponteiro que aponta mais para um pointee.
Mas o ponteiro e pointee são separados, e do erro comum é a criação de um ponteiro
mas esquecer-se de dar-lhe um pointee.
Número 2, dereferencing ponteiro começa no ponteiro e segue sua seta sobre
para acessar sua pointee.
Como todos sabemos, isso só funciona se houver um pointee,
que tipo de voltar a governar o número 1.
Número 3, a atribuição de um ponteiro ponteiro assume e muda-
para apontar para o mesmo pointee outro ponteiro.
Assim, após a atribuição, os dois ponteiros apontam para o pointee mesmo.
Às vezes isso é chamado de partilha.
>> E isso é tudo o que há para realmente. Bye-bye agora.
Este é Binky. Este é CS50. Vamos ver na próxima semana. [Aplausos]
>> [CS50.TV]