Escolar Documentos
Profissional Documentos
Cultura Documentos
2
00:00:49,370 --> 00:00:53,270
>DAVID MALAN: Tudo bem, esse é o
CS50 e esta é a quarta semana.
3
00:00:53,270 --> 00:00:55,190
>E nas últimas
semanas, tivemos
4
00:00:55,190 --> 00:00:58,217
>uma espécie de treino de iniciação,
ao usar esta linguagem conhecida como C.
5
00:00:58,217 --> 00:01:01,050
>E essas treino de iniciação
na forma da biblioteca CS50.
6
00:01:01,050 --> 00:01:05,580
>E você usa esta biblioteca, é claro,
selecionando e incluindo cs50.h
7
00:01:05,580 --> 00:01:06,650
>sobre o seu código.
8
00:01:06,650 --> 00:01:08,733
>E então, se você pensar
em como o clang funciona,
9
00:01:08,733 --> 00:01:12,080
>você vinculou seu código
via / L CS50.
10
00:01:12,080 --> 00:01:15,290
>Mas tudo isso foi automatizado
para você até agora, usando make.
11
00:01:15,290 --> 00:01:17,900
>Hoje, faremos a transição
do foco da semana passada
12
00:01:17,900 --> 00:01:21,290
>em algoritmos para focar
um pouco mais nas máquinas
13
00:01:21,290 --> 00:01:24,980
>e nas máquinas que agora usamos para
implementar esses algoritmos ainda mais
14
00:01:24,980 --> 00:01:27,410
>poderosamente, quando começamos a
tirar essas treino de iniciação
15
00:01:27,410 --> 00:01:30,840
>e vemos o que está acontecendo
por baixo do capô do seu computador.
16
00:01:30,840 --> 00:01:33,740
>E por mais complicado que alguns
aspectos do C tenham sido,
17
00:01:33,740 --> 00:01:36,320
>já que a programação,
pode ser algo novo para você,
18
00:01:36,320 --> 00:01:39,710
>perceba que não há tanta coisa
acontecendo debaixo do capô
19
00:01:39,710 --> 00:01:42,350
>que precisamos entender
para seguir em frente
20
00:01:42,350 --> 00:01:45,920
>e começar a resolver muito mais
interessantes, mais sofisticados e mais
21
00:01:45,920 --> 00:01:46,820
>problemas divertidos.
22
00:01:46,820 --> 00:01:49,170
>Precisamos apenas de alguns
blocos de construção adicionais.
23
00:01:49,170 --> 00:01:52,340
>E hoje, vamos fazer isso,
primeiro, reaprendendo a contar.
24
00:01:52,340 --> 00:01:55,080
>Aqui, por exemplo, está o que
chamaremos de memória do computador.
25
00:01:55,080 --> 00:01:56,420
>E já vimos essa grade antes.
26
00:01:56,420 --> 00:01:59,420
>E podemos numerar as chamadas de todos
bytes na memória do seu computador.
27
00:01:59,420 --> 00:02:04,550
>Podemos chamar esse byte de número 0, 1,
2, 3, 4, até o byte 15,
28
00:02:04,550 --> 00:02:05,610
>e assim por diante.
29
00:02:05,610 --> 00:02:08,240
>Mas acontece que, ao falar sobre
as memórias dos computadores,
30
00:02:08,240 --> 00:02:10,610
>computadores e cientistas da
computação e programadores
31
00:02:10,610 --> 00:02:13,070
>na verdade, não tendem a usar decimais.
32
00:02:13,070 --> 00:02:15,830
>Eles definitivamente não tendem a
usar binários nesse baixo nível.
33
00:02:15,830 --> 00:02:19,010
>Em vez disso, eles tendem a usar,
por convenção,
34
00:02:19,010 --> 00:02:21,020
>algo chamado hexadecimal.
35
00:02:21,020 --> 00:02:23,210
>Hexadecimal é um sistema
de base diferente que,
36
00:02:23,210 --> 00:02:27,120
>em vez de usar 10 ou
2 dígitos, usa 16.
37
00:02:27,120 --> 00:02:29,360
>E então um cientista da computação,
quando numerar coisas
38
00:02:29,360 --> 00:02:33,980
>como bytes em uma memória de computador,
ainda faria 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.
39
00:02:33,980 --> 00:02:37,350
>Mas depois disso, em vez de prosseguir
com o decimal para, digamos, 10,
40
00:02:37,350 --> 00:02:40,970
>11, 12, 13, 14, 15, em vez
disso, convencionalmente,
41
00:02:40,970 --> 00:02:43,260
>começaria a usar algumas
letras do alfabeto.
42
00:02:43,260 --> 00:02:47,270
>E assim, em hexadecimal, este sistema
de base diferente de base 16,
43
00:02:47,270 --> 00:02:48,980
>você começa a contar em 0 ainda.
44
00:02:48,980 --> 00:02:51,130
>Você conta até e até 9.
45
00:02:51,130 --> 00:02:52,880
>Mas quando você quiser
continuar contando mais alto,
46
00:02:52,880 --> 00:02:57,440
>você então vai para A, B, C, D, E e F.
47
00:02:57,440 --> 00:03:02,630
>E a vantagem disso é que, dentro de
hexadecimal - e esse hex implica 16 -
48
00:03:02,630 --> 00:03:08,630
>você tem 16 dígitos individuais
totais, 0 a 9, e também agora, A a F.
49
00:03:08,630 --> 00:03:12,300
>Portanto, não precisamos introduzir
segundos dígitos apenas para contar até 16.
50
00:03:12,300 --> 00:03:14,480
>Podemos usar dígitos
individuais de 0 a F.
51
00:03:14,480 --> 00:03:18,650
>E podemos continuar contando usando
vários dígitos hexadecimais.
52
00:03:18,650 --> 00:03:21,150
>Mas para chegar lá, vamos
introduzir esse vocabulário.
53
00:03:21,150 --> 00:03:23,540
>Então, em binário, é claro,
usamos 0's e 1's.
54
00:03:23,540 --> 00:03:25,690
>Em decimal, é claro,
usamos 0 a 9's.
55
00:03:25,690 --> 00:03:29,360
>E em hexadecimal, para ser claro,
vamos usar de 0 a F's,
56
00:03:29,360 --> 00:03:30,860
>conhecido como base-16.
57
00:03:30,860 --> 00:03:33,320
>E é uma convenção
que usamos de A a F.
58
00:03:33,320 --> 00:03:35,450
>Nós poderíamos ter usado quaisquer outros seis símbolos.
59
00:03:35,450 --> 00:03:37,560
>Mas isso é o que os humanos escolheram.
60
00:03:37,560 --> 00:03:41,090
>Portanto, o hexadecimal funciona de maneira bastante
semelhante ao nosso sistema decimal.
61
00:03:41,090 --> 00:03:45,110
>E é até familiar, agora, com o que você
conhece como sistema binário, como segue.
62
00:03:45,110 --> 00:03:49,370
>Vamos considerar um valor de dois dígitos
usando hexadecimal em vez de decimal
63
00:03:49,370 --> 00:03:50,600
>e em vez de binário.
64
00:03:50,600 --> 00:03:54,680
>Bem, assim como no mundo
decimal, usamos a base 10,
65
00:03:54,680 --> 00:03:57,080
>ou no mundo do binário,
usamos a base 2.
66
00:03:57,080 --> 00:04:01,170
>Vamos usar, agora,
base-16, logo, hexadecimal.
67
00:04:01,170 --> 00:04:02,360
>Portanto, este é 16 na 1.
68
00:04:02,360 --> 00:04:03,590
>Isso é 16 para o -
69
00:04:03,590 --> 00:04:05,090
>desculpe 16 elevado a 0.
70
00:04:05,090 --> 00:04:06,590
>Este é 16 na 1.
71
00:04:06,590 --> 00:04:09,570
>E, claro, se multiplicarmos
isso, é a coluna de uns
72
00:04:09,570 --> 00:04:11,280
>e agora a 16ª coluna.
73
00:04:11,280 --> 00:04:13,550
>E então, se você quiser
contar em hexadecimal,
74
00:04:13,550 --> 00:04:21,290
>você ainda começa com 0, como de costume, então
01, 02, 03, 04, 05, 06, 07, 08, 09.
75
00:04:21,290 --> 00:04:22,910
>E então as coisas ficam interessantes.
76
00:04:22,910 --> 00:04:26,660
>Agora, você não vai eleva a 01,
porque isso seria incorreto.
77
00:04:26,660 --> 00:04:31,880
>01, neste sistema básico, seria
16 vezes 1 mais 1 vez 0.
78
00:04:31,880 --> 00:04:32,960
>Não é isso que queremos.
79
00:04:32,960 --> 00:04:38,930
>Depois que o número que sabemos ser 9,
agora contamos até A, B, C, D, E, F.
80
00:04:38,930 --> 00:04:40,670
>E agora, as coisas ficam interessantes de novo.
81
00:04:40,670 --> 00:04:43,580
>Mas, assim como no sistema decimal,
quando você conta até 99,
82
00:04:43,580 --> 00:04:46,550
>você tem que começar a carregar o 1,
a mesma coisa aqui.
83
00:04:46,550 --> 00:04:49,820
>Se você quiser contar
além de F, carregue o 1.
84
00:04:49,820 --> 00:04:55,340
>E agora, para representar um
valor maior que F, usamos 01,
85
00:04:55,340 --> 00:04:57,350
>que parece 10, mas não é 10.
86
00:04:57,350 --> 00:04:59,675
>Em hexadecimal, é 01.
87
00:04:59,675 --> 00:05:01,880
>16 vezes 1 nos dá 16.
88
00:05:01,880 --> 00:05:03,680
>1 vez 0 nos dá 0.
89
00:05:03,680 --> 00:05:07,050
>E, claro, isso nos dá o número
decimal que agora sabemos que é 16.
90
00:05:07,050 --> 00:05:09,980
>Portanto, não vamos mais introduzir
mais e mais sistemas básicos.
91
00:05:09,980 --> 00:05:12,607
>Mas deixe-me estipular que
apenas usando essas colunas
92
00:05:12,607 --> 00:05:14,690
>que você aprendeu na escola
primária, provavelmente,
93
00:05:14,690 --> 00:05:16,940
>você pode implementar qualquer sistema básico agora.
94
00:05:16,940 --> 00:05:19,310
>Acontece que, no mundo
dos computadores,
95
00:05:19,310 --> 00:05:22,295
>e hoje no mundo da memória, e
em breve, também arquivos,
96
00:05:22,295 --> 00:05:24,170
>vai ser muito
convencional ser
97
00:05:24,170 --> 00:05:26,990
>capaz de reconhecer e usar hexadecimal.
98
00:05:26,990 --> 00:05:29,530
>E, há uma razão pela qual
os humanos gostam de hexadecimais,
99
00:05:29,530 --> 00:05:30,530
>ou pelo menos alguns humanos.
100
00:05:30,530 --> 00:05:36,827
>Os cientistas da computação lembram
que se contarmos até FF, neste caso,
101
00:05:36,827 --> 00:05:38,160
>ainda faríamos a mesma matemática.
102
00:05:38,160 --> 00:05:44,060
>Então, 16 vezes 15 mais 1 vez
15 vai nos dar, isso,
103
00:05:44,060 --> 00:05:49,210
>ou, claro, 240 mais 15 ou 255.
104
00:05:49,210 --> 00:05:50,460
>E eu fiz isso muito rapidamente.
105
00:05:50,460 --> 00:05:53,000
>Mas esse é o tipo de matemática
do ensino fundamental de multiplicação
106
00:05:53,000 --> 00:05:55,730
>a coluna pelo valor que
está nela, onde novamente,
107
00:05:55,730 --> 00:06:00,140
>cada um desses Fs é como agora
expressamos 15 usando um único dígito.
108
00:06:00,140 --> 00:06:02,480
>Mas lembre-se de que vimos 255 antes.
109
00:06:02,480 --> 00:06:04,610
>Quando falamos sobre binário
há algumas semanas,
110
00:06:04,610 --> 00:06:12,450
>255 também passou a ser o padrão que
vemos aqui, oito bits 1 usando binário.
111
00:06:12,450 --> 00:06:15,278
>E então, a razão pela qual os cientistas
da computação tendem ao hexadecimal,
112
00:06:15,278 --> 00:06:17,570
>é que, em oito bits, há
113
00:06:17,570 --> 00:06:20,000
>dois pares aqui, como quatro à
esquerda, quatro à direita.
114
00:06:20,000 --> 00:06:22,340
>Se dermos um jeito
nessas coisas,
115
00:06:22,340 --> 00:06:25,520
>acontece que, porque
hexadecimal permite
116
00:06:25,520 --> 00:06:28,730
>a você representar
16 valores possíveis, é
117
00:06:28,730 --> 00:06:32,750
>um sistema perfeito para
representar quatro bits por vez.
118
00:06:32,750 --> 00:06:36,980
>Afinal, se você tem quatro bits aqui,
cada um dos quais pode ser 0 ou 1,
119
00:06:36,980 --> 00:06:42,020
>ou seja, 2 vezes 2 vezes 2 vezes 2
valores possíveis para cada um deles,
120
00:06:42,020 --> 00:06:45,740
>ou 16 valores totais, ou seja,
no mundo dos computadores,
121
00:06:45,740 --> 00:06:48,560
>se você quiser falar em
unidades de quatro bits,
122
00:06:48,560 --> 00:06:51,590
>é conveniente
usar hexadecimal em vez disso,
123
00:06:51,590 --> 00:06:56,270
>apenas porque, convenientemente,
um dígito hexadecimal passa a ser
124
00:06:56,270 --> 00:07:00,590
>equivalente a quatro dígitos
binários, 0's e 1's.
125
00:07:00,590 --> 00:07:05,160
>Portanto, 0, 0, 0, 0, todo
o caminho até 1, 1, 1, 1.
126
00:07:05,160 --> 00:07:06,320
>Então, por que os humanos fazem isso?
127
00:07:06,320 --> 00:07:09,240
>Só agora é a convenção humana
por causa dessa conveniência.
128
00:07:09,240 --> 00:07:11,760
>Agora, alguns de vocês podem muito
bem ter visto hexadecimal antes.
129
00:07:11,760 --> 00:07:14,660
>Na verdade, lembre-se de nossa
discussão na semana 0 de RGB,
130
00:07:14,660 --> 00:07:17,660
>onde discutimos a
representação de cores usando
131
00:07:17,660 --> 00:07:19,860
>alguma quantidade de vermelho, verde e azul.
132
00:07:19,860 --> 00:07:21,720
>E na época, usamos este exemplo.
133
00:07:21,720 --> 00:07:24,080
>Pegamos nosso exemplo fora do contexto.
134
00:07:24,080 --> 00:07:27,560
>E em vez de usar oi como
uma string de texto,
135
00:07:27,560 --> 00:07:33,410
>reinterpretamos 72, 73 e
33 como uma sequência de cores.
136
00:07:33,410 --> 00:07:34,550
>Quanto vermelho você quer?
137
00:07:34,550 --> 00:07:35,720
>Quanto verde você quer?
138
00:07:35,720 --> 00:07:36,860
>Quanto azul você quer?
139
00:07:36,860 --> 00:07:37,820
>E isso é bom.
140
00:07:37,820 --> 00:07:41,060
>É perfeitamente normal pensar e
se expressar em termos decimais.
141
00:07:41,060 --> 00:07:44,270
>Mas os cientistas da computação tendem a não
fazer dessa forma no contexto das cores
142
00:07:44,270 --> 00:07:45,790
>e no contexto da memória.
143
00:07:45,790 --> 00:07:49,160
>Em vez disso, eles tendem a
usar algo chamado hexadecimal.
144
00:07:49,160 --> 00:07:51,590
>E hexadecimal, aqui,
seria apenas
145
00:07:51,590 --> 00:07:57,860
>mudar esses valores de 72,
73, 33, para o hexadecimal equivalente
146
00:07:57,860 --> 00:07:58,533
>em representação.
147
00:07:58,533 --> 00:08:00,200
>E não vamos nos incomodar em fazer as contas aqui.
148
00:08:00,200 --> 00:08:04,340
>Mas deixe-me estipular que
72, 73, 33 em decimal
149
00:08:04,340 --> 00:08:10,262
>é a mesma coisa que 48,
49, 21 em hexadecimal.
150
00:08:10,262 --> 00:08:12,470
>Agora, obviamente, se você
olhar para esses três números,
151
00:08:12,470 --> 00:08:15,980
>não é nada óbvio se você está
olhando para dígitos hexadecimais
152
00:08:15,980 --> 00:08:21,080
>ou dígitos decimais, porque eles
usam o mesmo subconjunto, de 0 a 9.
153
00:08:21,080 --> 00:08:23,240
>E então uma convenção também,
no mundo do Computação,
154
00:08:23,240 --> 00:08:25,850
>é que sempre que você representa
dígitos hexadecimais,
155
00:08:25,850 --> 00:08:29,300
>você tende a prefixá-los,
porque sim, com 0x.
156
00:08:29,300 --> 00:08:32,179
>E não há significado
matemático para 0 ou x.
157
00:08:32,179 --> 00:08:35,419
>É apenas um prefixo que você coloca lá
para deixar claro para o visualizador
158
00:08:35,419 --> 00:08:38,299
>que esses são dígitos hexadecimais,
mesmo se pudessem de outra forma
159
00:08:38,299 --> 00:08:40,490
>parecer dígitos decimais.
160
00:08:40,490 --> 00:08:41,940
>Então, aonde vamos com isso?
161
00:08:41,940 --> 00:08:43,857
>Bem, aqueles de vocês que
podem ter experimentado
162
00:08:43,857 --> 00:08:46,850
>no passado, criando suas próprias
páginas da web e tornando-as coloridas,
163
00:08:46,850 --> 00:08:50,450
>ou aqueles de vocês que são artistas e
usaram programas como o Photoshop,
164
00:08:50,450 --> 00:08:53,190
>você já viu esses códigos antes.
165
00:08:53,190 --> 00:08:55,940
>Na verdade, aqui estão algumas
capturas de tela do próprio Photoshop.
166
00:08:55,940 --> 00:08:59,190
>Se você clicar em uma cor no
Photoshop e abrir esta janela,
167
00:08:59,190 --> 00:09:02,300
>você pode mudar a cor que
está desenhando na tela
168
00:09:02,300 --> 00:09:04,970
>qualquer uma das cores do arco-íris.
169
00:09:04,970 --> 00:09:07,470
>Mas de forma mais precisa,
se você olhar aqui embaixo,
170
00:09:07,470 --> 00:09:09,620
>você pode ver
esses códigos hexadecimais,
171
00:09:09,620 --> 00:09:11,990
>porque se tornou uma convenção
humana ao longo dos anos
172
00:09:11,990 --> 00:09:15,630
>usar hexadecimal para representar
diferentes quantidades de vermelho, verde,
173
00:09:15,630 --> 00:09:16,320
>e azul.
174
00:09:16,320 --> 00:09:23,435
>Então, se você não tem vermelho, verde, azul,
representado como 000000,
175
00:09:23,435 --> 00:09:26,060
>bem, isso vai lhe dar a cor que
conhecemos aqui como preto.
176
00:09:26,060 --> 00:09:29,510
>É uma espécie de ausência de qualquer
comprimento de onda de luz ali.
177
00:09:29,510 --> 00:09:33,470
>Se, por outro lado, você alterar
todos esses seis dígitos
178
00:09:33,470 --> 00:09:38,810
>para o maior valor possível, que,
novamente, é F. O intervalo em hexadecimal 0
179
00:09:38,810 --> 00:09:42,890
>a F, em decimal,
sendo 0 a 15, bem,
180
00:09:42,890 --> 00:09:46,800
>com FFFFFF, é muito vermelho,
muito verde, muito azul.
181
00:09:46,800 --> 00:09:48,800
>E quando você combina esses
comprimentos de onda de luz,
182
00:09:48,800 --> 00:09:51,200
>você obtém a cor que vemos aqui como branco.
183
00:09:51,200 --> 00:09:53,480
>E você pode imaginar, agora,
combinando diferentes quantidades
184
00:09:53,480 --> 00:09:54,930
>de vermelho, verde ou azul.
185
00:09:54,930 --> 00:10:00,740
>Então, por exemplo, em hexadecimal,
FF0000, é a cor que conhecemos como vermelho.
186
00:10:00,740 --> 00:10:05,270
>00FF00 é a cor que conhecemos como verde.
187
00:10:05,270 --> 00:10:09,630
>E, finalmente, 0000FF é a cor que
conhecemos como azul, porque, novamente,
188
00:10:09,630 --> 00:10:14,240
>o sistema que os programadores e artistas
frequentemente, mas nem sempre usam, é de fato,
189
00:10:14,240 --> 00:10:17,710
>este sistema de RGB para
vermelho, verde e azul.
190
00:10:17,710 --> 00:10:19,460
>Então, nós introduzimos
isso aqui não porque você
191
00:10:19,460 --> 00:10:21,810
>tem que começar a pensar de forma
diferente, porque, novamente,
192
00:10:21,810 --> 00:10:24,560
>o mecanismo matemático
é o mesmo da semana 0.
193
00:10:24,560 --> 00:10:28,970
>Mas você vai começar a ver números
em exemplos, em programas,
194
00:10:28,970 --> 00:10:32,900
>como apenas aparecendo em hexadecimal
por convenção, em oposição a
195
00:10:32,900 --> 00:10:35,550
>sendo interpretado como decimal.
196
00:10:35,550 --> 00:10:37,880
>Então, se considerarmos, agora,
a memória do nosso computador,
197
00:10:37,880 --> 00:10:40,610
>vamos agora começar a pensar
em toda essa tela de memória,
198
00:10:40,610 --> 00:10:43,010
>todos esses bytes dentro da
memória do nosso computador,
199
00:10:43,010 --> 00:10:46,700
>como sendo inumeráveis como 0,
1, 2, até F.
200
00:10:46,700 --> 00:10:53,750
>E então, se continuarmos contando, podemos
ir para 10, 11, 12, 13, 14, 15, 16, 17, 18,
201
00:10:53,750 --> 00:10:58,850
>19, 1A, 1B, 1C, 1D e assim por diante.
202
00:10:58,850 --> 00:11:00,790
>E tudo bem se não
for tão óbvio,
203
00:11:00,790 --> 00:11:03,670
>quando você olha para essas coisas,
quais são os equivalentes decimais.
204
00:11:03,670 --> 00:11:04,690
>Isso não é um problema.
205
00:11:04,690 --> 00:11:09,130
>É apenas uma maneira diferente de
pensar sobre os locais, neste caso,
206
00:11:09,130 --> 00:11:13,480
>da memória de um computador, ou a
representação de uma cor ou outra.
207
00:11:13,480 --> 00:11:19,480
>Tudo bem, vamos agora usar isso
como um exemplo de oportunidade,
208
00:11:19,480 --> 00:11:22,690
>em vez disso, considerar o que está
sendo armazenado na memória do nosso computador.
209
00:11:22,690 --> 00:11:26,320
>E para ser claro, vou começar a prefixar
todos esses endereços de memória,
210
00:11:26,320 --> 00:11:29,890
>por assim dizer, com 0x, apenas para deixar
claro que agora estamos falando,
211
00:11:29,890 --> 00:11:31,480
>em termos de 0's e 1's.
212
00:11:31,480 --> 00:11:32,980
>Portanto, aqui está uma linha de código simples.
213
00:11:32,980 --> 00:11:35,147
>Fora do contexto, precisaríamos,
na verdade, colocar isso
214
00:11:35,147 --> 00:11:37,910
>no main ou algum outro programa para
fazer qualquer coisa com ele.
215
00:11:37,910 --> 00:11:39,702
>Mas já vimos isso
muitas vezes, agora,
216
00:11:39,702 --> 00:11:42,760
>onde você declara uma variável,
por exemplo, n para número.
217
00:11:42,760 --> 00:11:44,830
>Declare-o como um int para seu tipo.
218
00:11:44,830 --> 00:11:47,170
>E então, talvez,
até mesmo atribua um valor a ele.
219
00:11:47,170 --> 00:11:51,520
>Bem, o que está acontecendo quando
usamos esse tipo de código em nosso computador?
220
00:11:51,520 --> 00:11:54,760
>Bem, vamos prosseguir e transformar
isso em um programa real.
221
00:11:54,760 --> 00:11:57,970
>Vamos criar um arquivo
chamado address.c porque eu
222
00:11:57,970 --> 00:12:01,300
>deseja começar a experimentar alguns
endereços na memória do computador.
223
00:12:01,300 --> 00:12:04,180
>Vou prosseguir e incluir
o padrão io ponto h.
224
00:12:04,180 --> 00:12:06,460
>Vou criar int main void.
225
00:12:06,460 --> 00:12:08,890
>E aqui embaixo, vou prosseguir
e declarar exatamente
226
00:12:08,890 --> 00:12:10,915
>essa variável, int n é igual a 50.
227
00:12:10,915 --> 00:12:15,820
>E então vou prosseguir e imprimir, com
percentual i e uma \ 0,
228
00:12:15,820 --> 00:12:17,230
>o valor de n.
229
00:12:17,230 --> 00:12:19,930
>Então nada de interessante aí,
nada muito complicado.
230
00:12:19,930 --> 00:12:21,790
>Vou seguir em frente e make address.
231
00:12:21,790 --> 00:12:24,123
>E então vou prosseguir e fazer
./ address.
232
00:12:24,123 --> 00:12:26,380
>E, claro, como na primeira
semana, devemos esperar
233
00:12:26,380 --> 00:12:27,930
>apenas o número 50.
234
00:12:27,930 --> 00:12:31,570
>Mas hoje, vamos lhe dar mais algumas
ferramentas com as quais você pode
235
00:12:31,570 --> 00:12:33,880
>vasculhar a
memória do seu computador.
236
00:12:33,880 --> 00:12:35,950
>Mas vamos primeiro considerar
esta linha de código
237
00:12:35,950 --> 00:12:38,240
>no contexto do hardware
do seu computador.
238
00:12:38,240 --> 00:12:41,200
>Então, se você estiver escrevendo um
programa com uma linha de código como esta,
239
00:12:41,200 --> 00:12:44,500
>que n precisa estar em algum lugar
na memória do seu computador.
240
00:12:44,500 --> 00:12:47,870
>Esse 50 precisa ser colocado em algum
lugar na memória do seu computador.
241
00:12:47,870 --> 00:12:51,010
>Então, se nós, novamente, considerarmos
que isso seja apenas parte da
242
00:12:51,010 --> 00:12:55,000
>memória, algumas dezenas de bytes, bem,
suponha que essa variável, n,
243
00:12:55,000 --> 00:12:57,130
>acaba aqui embaixo.
244
00:12:57,130 --> 00:13:01,570
>Eu desenhei deliberadamente n ocupando
quatro bytes, quatro quadrados, porque nós
245
00:13:01,570 --> 00:13:05,830
>chamamos a isso de um número inteiro, normalmente,
pelo menos em CS50 IDE e sistemas modernos,
246
00:13:05,830 --> 00:13:07,370
>tende a ter quatro bytes.
247
00:13:07,370 --> 00:13:10,630
>Então, fiz questão de preencher
quatro caixas completas.
248
00:13:10,630 --> 00:13:13,940
>E então o valor pode ser 50 que
está armazenado lá.
249
00:13:13,940 --> 00:13:17,890
>Bem, acontece que na memória
do seu computador, novamente,
250
00:13:17,890 --> 00:13:20,660
>existem esses endereços que
estão implicitamente lá.
251
00:13:20,660 --> 00:13:23,530
>Portanto, embora, sim, podemos
nos referir a esta variável, n,
252
00:13:23,530 --> 00:13:26,620
>com base no nome da variável
que dei em meu código,
253
00:13:26,620 --> 00:13:30,940
>certamente essa variável existe em
um local específico na memória.
254
00:13:30,940 --> 00:13:32,530
>Não sei de imediato onde está.
255
00:13:32,530 --> 00:13:38,410
>Mas deixe-me apenas propor que talvez
esteja na localização 0x12345678, apenas
256
00:13:38,410 --> 00:13:39,550
>um endereço arbitrário.
257
00:13:39,550 --> 00:13:41,690
>Não tenho ideia, na
verdade, de onde está.
258
00:13:41,690 --> 00:13:44,860
>Mas certamente tem um endereço,
porque cada um desses quadrados
259
00:13:44,860 --> 00:13:49,540
>dentro da memória do seu computador tem um
endereço, um identificador único como 0, 1,
260
00:13:49,540 --> 00:13:50,750
>2, e assim por diante.
261
00:13:50,750 --> 00:13:56,710
>Talvez o 50 tenha terminado no
endereço de memória 0x12345678.
262
00:13:56,710 --> 00:14:01,750
>Bem, isso é o legal sobre C, é que
podemos começar a ver isso,
263
00:14:01,750 --> 00:14:03,020
>sem trocadilhos.
264
00:14:03,020 --> 00:14:05,080
>Então, deixe-me ir em frente
e modificar este programa
265
00:14:05,080 --> 00:14:07,480
>e introduzir um pouco
de nova sintaxe que
266
00:14:07,480 --> 00:14:11,510
>nos permitirá começar a vasculhar o
interior da memória do seu computador
267
00:14:11,510 --> 00:14:14,830
>para que possamos ver o
que está acontecendo por baixo.
268
00:14:14,830 --> 00:14:17,710
>Portanto, vou prosseguir e alterar
este programa para fazer isso.
269
00:14:17,710 --> 00:14:19,585
>Vou prosseguir e
dizer, quer saber?
270
00:14:19,585 --> 00:14:23,590
>Não imprima apenas o valor,
n, que, claro, é 50.
271
00:14:23,590 --> 00:14:28,060
>Vamos ver, apenas por curiosidade,
qual é o endereço real de n.
272
00:14:28,060 --> 00:14:31,300
>E para fazer isso hoje, vamos
apresentar uma nova parte da sintaxe,
273
00:14:31,300 --> 00:14:33,070
>que por acaso é esta aqui.
274
00:14:33,070 --> 00:14:37,360
>Existem dois novos operadores, hoje, em C.
O primeiro é um & - &, que
275
00:14:37,360 --> 00:14:39,580
>não representa um e lógico.
276
00:14:39,580 --> 00:14:42,100
>Lembre-se de algumas semanas
atrás, vimos que se você
277
00:14:42,100 --> 00:14:46,840
>deseja combinar expressões booleanas,
isso e aquilo, você usa dois & - &&.
278
00:14:46,840 --> 00:14:51,040
>É uma coincidência infeliz que
um & comercial, sozinho,
279
00:14:51,040 --> 00:14:52,630
>significará algo diferente hoje.
280
00:14:52,630 --> 00:14:56,830
>Especificamente, esse &
será nosso endereço do operador.
281
00:14:56,830 --> 00:15:02,590
>Simplesmente prefixando qualquer nome de variável
com um &, podemos dizer ao C,
282
00:15:02,590 --> 00:15:06,520
>diga-me em que endereço esta
variável está armazenada.
283
00:15:06,520 --> 00:15:10,180
>E esta asterisco, não deve ser
confundida com multiplicação,
284
00:15:10,180 --> 00:15:12,880
>também tem outro significado
no contexto atual.
285
00:15:12,880 --> 00:15:15,310
>Quando você usa este
asterisco, você pode
286
00:15:15,310 --> 00:15:19,910
>dizer ao seu programa para olhar dentro
de um endereço de memória específico.
287
00:15:19,910 --> 00:15:23,500
>Portanto, o & informa em
que endereço está uma variável.
288
00:15:23,500 --> 00:15:27,310
>O operador asterisco, também conhecido
como operador de desreferência,
289
00:15:27,310 --> 00:15:30,190
>significa, vá para o seguinte endereço.
290
00:15:30,190 --> 00:15:32,050
>Então, meio que são operações reversas.
291
00:15:32,050 --> 00:15:33,400
>Descobre-se o endereço.
292
00:15:33,400 --> 00:15:35,240
>Um vai para o endereço.
293
00:15:35,240 --> 00:15:37,850
>E então vamos ver isso de verdade aqui.
294
00:15:37,850 --> 00:15:43,070
>Vamos prosseguir e alterar meu n em
meu programa aqui para & n.
295
00:15:43,070 --> 00:15:48,980
>Então, eu quero imprimir, não o
número em n, mas o endereço de n.
296
00:15:48,980 --> 00:15:50,870
>E agora, como imprimo um endereço?
297
00:15:50,870 --> 00:15:52,170
>Bem, é um número.
298
00:15:52,170 --> 00:15:56,690
>Mas, na verdade, printf suporta um código
de formato diferente para endereços.
299
00:15:56,690 --> 00:15:59,840
>Você pode fazer % p,
por razões que veremos em breve,
300
00:15:59,840 --> 00:16:02,510
>que diz para imprimir o
endereço desta variável
301
00:16:02,510 --> 00:16:05,375
>e interpretá-lo como hexadecimal,
novamente, por convenção.
302
00:16:05,375 --> 00:16:07,250
>Vou prosseguir e
make address now
303
00:16:07,250 --> 00:16:10,530
>depois de fazer apenas duas
alterações neste arquivo.
304
00:16:10,530 --> 00:16:12,350
>Tudo parece compilar bem.
305
00:16:12,350 --> 00:16:14,150
>Agora, vou prosseguir e
executar o endereço.
306
00:16:14,150 --> 00:16:17,210
>E veremos que, neste
programa específico,
307
00:16:17,210 --> 00:16:21,620
>address.c, por qualquer
motivo, essa variável, n,
308
00:16:21,620 --> 00:16:30,110
>acabou na localização
maluca 0x7ffd80792f7c.
309
00:16:30,110 --> 00:16:31,160
>Agora, isso é útil?
310
00:16:31,160 --> 00:16:32,870
>Não na prática.
311
00:16:32,870 --> 00:16:36,530
>Faremos com que isso se torne útil
aproveitando esses endereços.
312
00:16:36,530 --> 00:16:38,900
>Mas o endereço específico
não é interessante.
313
00:16:38,900 --> 00:16:40,070
>Estou olhando para este número.
314
00:16:40,070 --> 00:16:41,993
>Não tenho ideia do que é
esse número em decimal.
315
00:16:41,993 --> 00:16:44,660
>Eu teria que fazer as contas ou
apenas pesquisar um conversor no Google
316
00:16:44,660 --> 00:16:45,660
>fazendo isso por mim.
317
00:16:45,660 --> 00:16:47,420
>Então, novamente, essa não
é a parte interessante.
318
00:16:47,420 --> 00:16:50,420
>O fato de estar em hexadecimal é
apenas um detalhe de implementação.
319
00:16:50,420 --> 00:16:54,450
>Acontece que representa a
localização desta variável.
320
00:16:54,450 --> 00:16:58,230
>E, novamente, não queremos
fazer isso.
321
00:16:58,230 --> 00:17:00,830
>Mas só para deixar claro
que um desses operadores,
322
00:17:00,830 --> 00:17:02,330
>o & obtém o endereço.
323
00:17:02,330 --> 00:17:05,089
>E o operador asterisco
vai para um endereço.
324
00:17:05,089 --> 00:17:07,160
>Podemos desfazer
os efeitos dessas coisas.
325
00:17:07,160 --> 00:17:13,010
>Por exemplo, se eu imprimir agora, não e
comercial n, mas apenas por curiosidade,
326
00:17:13,010 --> 00:17:18,170
>asterisco & n, posso
desfazer os efeitos desse operador.
327
00:17:18,170 --> 00:17:21,170
>& n dirá,
qual é o endereço de n?
328
00:17:21,170 --> 00:17:25,349
>& asterisco n vai
dizer, vá para esse endereço.
329
00:17:25,349 --> 00:17:29,360
>Portanto, este é um exercício meio inútil,
porque se eu só quero o que está em n,
330
00:17:29,360 --> 00:17:32,120
>Eu posso, obviamente,
imprimir n como começamos.
331
00:17:32,120 --> 00:17:34,560
>Mas, novamente, apenas como
um exercício intelectual,
332
00:17:34,560 --> 00:17:38,750
>se eu prefixo n com o endereço do
operador e, em seguida, uso o asterisco
333
00:17:38,750 --> 00:17:42,830
>e digo, vá para aquele endereço,
é exatamente a mesma coisa
334
00:17:42,830 --> 00:17:44,280
>como apenas imprimir n em si.
335
00:17:44,280 --> 00:17:46,640
>Então, deixe-me mudar
de volta para um inteiro.
336
00:17:46,640 --> 00:17:50,060
>Em vez de % p, deixe-me ir
em frente e make address now,
337
00:17:50,060 --> 00:17:52,100
>parece compilar OK e executar o endereço.
338
00:17:52,100 --> 00:17:53,885
>E pronto, estamos de volta aos 50.
339
00:17:53,885 --> 00:17:57,050
>Por mais estranha que a sintaxe
de hoje possa começar a parecer,
340
00:17:57,050 --> 00:17:59,330
>perceber que esses operadores,
afinal,
341
00:17:59,330 --> 00:18:01,833
>são relativamente simples no que fazem.
342
00:18:01,833 --> 00:18:05,000
>E se você entender que um meio
que desfaz os efeitos do outro,
343
00:18:05,000 --> 00:18:08,360
>podemos começar a construir alguns
programas bastante interessantes com eles.
344
00:18:08,360 --> 00:18:11,870
>E faremos isso aproveitando
um tipo especial de variável,
345
00:18:11,870 --> 00:18:13,910
>uma variável chamada ponteiro.
346
00:18:13,910 --> 00:18:16,670
>E existe aquele p em % p.
347
00:18:16,670 --> 00:18:22,240
>Um ponteiro é uma variável que contém
o endereço de algum outro valor.
348
00:18:22,240 --> 00:18:23,790
>Então, já vimos números inteiros antes.
349
00:18:23,790 --> 00:18:27,770
>Vimos floats, chars, strings
e outros tipos também.
350
00:18:27,770 --> 00:18:31,430
>Ponteiros, agora, são apenas
um tipo diferente de variável
351
00:18:31,430 --> 00:18:34,640
>que armazenam o endereço de algum valor.
352
00:18:34,640 --> 00:18:40,250
>E você pode ter ponteiros para inteiros,
ponteiros para chars, ponteiros para booleanos,
353
00:18:40,250 --> 00:18:41,870
>ou qualquer outro tipo de dados.
354
00:18:41,870 --> 00:18:45,980
>Um ponteiro faz referência
ao tipo específico do valor
355
00:18:45,980 --> 00:18:48,223
>a que se refere.
356
00:18:48,223 --> 00:18:49,640
>Então, vamos ver isso mais concretamente.
357
00:18:49,640 --> 00:18:51,620
>voltando, agora, ao meu programa aqui.
358
00:18:51,620 --> 00:18:53,840
>E deixe-me apresentar
outra variável aqui.
359
00:18:53,840 --> 00:18:58,430
>Em vez de imprimir imediatamente
algo como n, deixe-me prosseguir
360
00:18:58,430 --> 00:19:02,870
>e introduzir uma segunda
variável do tipo int asterisco.
361
00:19:02,870 --> 00:19:06,860
>E isso, devo admitir, é provavelmente
a parte mais confusa da sintaxe C
362
00:19:06,860 --> 00:19:09,860
>que iremos, em geral, ver,
só porque, meu Deus, asterisco é agora
363
00:19:09,860 --> 00:19:13,220
>usado para multiplicação, para ir
para um endereço, e também, agora,
364
00:19:13,220 --> 00:19:14,610
>declarar uma variável.
365
00:19:14,610 --> 00:19:17,120
>Esta não é, sem dúvida, a
melhor decisão de design.
366
00:19:17,120 --> 00:19:18,350
>Mas foi feito há décadas.
367
00:19:18,350 --> 00:19:19,730
>Então é isso que temos.
368
00:19:19,730 --> 00:19:26,240
>Mas se eu fizer int asterisco p é igual a e
comercial n, agora, o que posso fazer aqui,
369
00:19:26,240 --> 00:19:31,770
>é imprimir o endereço de n armazenando-o
temporariamente em uma variável.
370
00:19:31,770 --> 00:19:33,830
>Portanto, não estou fazendo nada novo ainda.
371
00:19:33,830 --> 00:19:36,020
>Ainda estou declarando
na linha 5, um inteiro
372
00:19:36,020 --> 00:19:37,910
>chamado n, atribuindo no valor 50.
373
00:19:37,910 --> 00:19:42,260
>O que há de novo agora na linha 6 é que estou
introduzindo um novo tipo de variável.
374
00:19:42,260 --> 00:19:44,210
>Esse tipo de variável é
conhecida como ponteiro.
375
00:19:44,210 --> 00:19:48,410
>Um ponteiro, novamente, é uma variável
que armazena o endereço de algum valor.
376
00:19:48,410 --> 00:19:53,240
>E a sintaxe, reconhecidamente estranha,
para declarar um ponteiro para um inteiro,
377
00:19:53,240 --> 00:19:57,560
>é literalmente dizer int, porque esse é
o tipo para o qual você está apontando,
378
00:19:57,560 --> 00:20:00,350
>asterisco e, em seguida, o nome
da variável que deseja criar.
379
00:20:00,350 --> 00:20:03,320
>E eu poderia chamar isso de qualquer coisa, mas
vou chamar de p para mantê-lo sucinto.
380
00:20:03,320 --> 00:20:05,120
>E, novamente, do lado
direito do sinal de igual
381
00:20:05,120 --> 00:20:06,620
>é o mesmo operador de antes.
382
00:20:06,620 --> 00:20:10,040
>Se você quiser descobrir qual é o
endereço de n, é & n.
383
00:20:10,040 --> 00:20:14,450
>E para que possamos armazenar esse endereço,
agora, em algum lugar de longo prazo.
384
00:20:14,450 --> 00:20:18,110
>Antes, acabei de passar o
& n e printf fez o que costuma fazer.
385
00:20:18,110 --> 00:20:23,120
>Agora, estou temporariamente, na linha 6,
armazenando esse endereço em uma nova variável
386
00:20:23,120 --> 00:20:24,470
>chamada p.
387
00:20:24,470 --> 00:20:28,910
>E seu tipo é tecnicamente int asterisco,
é o que um programador diria.
388
00:20:28,910 --> 00:20:33,680
>Portanto, seria incorreto dizer que
int p é igual a & n.
389
00:20:33,680 --> 00:20:35,780
>E, nosso compilador,
Clang, não vai gostar disso.
390
00:20:35,780 --> 00:20:38,370
>Provavelmente, não permitirá
que você compile o código.
391
00:20:38,370 --> 00:20:43,160
>E então, em vez disso, pretendo deixar
claro que sei o que estou fazendo.
392
00:20:43,160 --> 00:20:48,450
>Estou armazenando o endereço de um int,
não de um inteiro, por assim dizer.
393
00:20:48,450 --> 00:20:53,040
>Então, se eu for em frente agora e
salvar isso, recompilar com make address.
394
00:20:53,040 --> 00:20:55,530
>E observe, eu mudei uma
linha do código 2 antes.
395
00:20:55,530 --> 00:20:59,400
>Voltei para a % p para
imprimir um ponteiro que é um endereço.
396
00:20:59,400 --> 00:21:02,490
>E estou apontando o valor de
p, não mais o valor de n.
397
00:21:02,490 --> 00:21:07,050
>Se eu agora executar o endereço de barra pontilhada,
voila, há aquele endereço enigmático.
398
00:21:07,050 --> 00:21:09,300
>E esses endereços podem muito
bem mudar com o tempo.
399
00:21:09,300 --> 00:21:11,640
>Dependendo do que está acontecendo
dentro do seu programa
400
00:21:11,640 --> 00:21:15,390
>ou outras coisas no sistema, esses
endereços podem ser diferentes a cada vez.
401
00:21:15,390 --> 00:21:18,060
>E isso é esperado e não algo
em que se possa confiar.
402
00:21:18,060 --> 00:21:20,250
>Mas é claramente algum endereço
criptográfico aleatório,
403
00:21:20,250 --> 00:21:24,400
>semelhante ao meu arbitrário
0x12345678 antes.
404
00:21:24,400 --> 00:21:26,310
>Mas agora, vamos apenas desfazer esta operação.
405
00:21:26,310 --> 00:21:30,120
>Só para que possamos fechar o
círculo aqui, deixe-me propor
406
00:21:30,120 --> 00:21:33,495
>como posso imprimir o valor de n.
407
00:21:33,495 --> 00:21:35,370
>E deixe-me chamar alguém
para isso, se puder.
408
00:21:35,370 --> 00:21:41,640
>Se meu objetivo, agora, na linha 7, não é
mais imprimir o endereço de n, mas imprimir
409
00:21:41,640 --> 00:21:43,972
>o próprio n usando p.
410
00:21:43,972 --> 00:21:45,930
>Vou seguir em frente e
mudar, preventivamente,
411
00:21:45,930 --> 00:21:47,820
>o código de formato em % i.
412
00:21:47,820 --> 00:21:51,660
>E uma notação abreviada seria,
obviamente, basta imprimir n.
413
00:21:51,660 --> 00:21:53,610
>Mas suponha que eu não
queira imprimir n para este
414
00:21:53,610 --> 00:22:02,880
>exercício, como posso agora imprimir o valor
em n referindo-me a ele por meio de p?
415
00:22:02,880 --> 00:22:05,910
>O que devo digitar literalmente
como o segundo argumento de printf
416
00:22:05,910 --> 00:22:12,530
>para imprimir o valor de n usando esta
nova variável, p, de alguma forma.
417
00:22:12,530 --> 00:22:16,290
>Sim, vamos chamar Joshua.
418
00:22:16,290 --> 00:22:19,860
>PÚBLICO: Eu acredito, se você
usar o & antes do p,
419
00:22:19,860 --> 00:22:21,642
>provavelmente fará isso.
420
00:22:21,642 --> 00:22:24,100
>DAVID MALAN: OK, & p,
agora eu vou tentar isso.
421
00:22:24,100 --> 00:22:27,700
>Vamos tentar & p
para imprimir esse valor.
422
00:22:27,700 --> 00:22:30,370
>Portanto, & p,
salvarei o arquivo.
423
00:22:30,370 --> 00:22:32,610
>Vou make address e entrar.
424
00:22:32,610 --> 00:22:34,415
>E não parece ser o caso.
425
00:22:34,415 --> 00:22:35,790
>Observe que estou recebendo um erro.
426
00:22:35,790 --> 00:22:36,720
>É um pouco enigmático.
427
00:22:36,720 --> 00:22:40,920
>O formato especifica o tipo int, mas o
argumento tem o tipo int asterisco asterisco,
428
00:22:40,920 --> 00:22:42,090
>Mais disso em outro momento.
429
00:22:42,090 --> 00:22:43,570
>Acontece que isso estava incorreto.
430
00:22:43,570 --> 00:22:47,430
>Vamos dar uma outra sugestão,
porque o &, lembre-se,
431
00:22:47,430 --> 00:22:49,170
>obtém o endereço de algo.
432
00:22:49,170 --> 00:22:50,880
>Mas p já é um endereço.
433
00:22:50,880 --> 00:22:52,590
>Joshua, o que você
propôs tecnicamente,
434
00:22:52,590 --> 00:22:54,300
>foi me dar o endereço do endereço.
435
00:22:54,300 --> 00:22:56,190
>E essa não é a direção
que queremos ir.
436
00:22:56,190 --> 00:22:58,170
>Queremos ir para o que
está naquele endereço.
437
00:22:58,170 --> 00:23:00,740
>Sofia, o que você acha?
438
00:23:00,740 --> 00:23:02,640
>PÚBLICO: Queremos adicionar um % -
439
00:23:02,640 --> 00:23:06,820
>ou um asterisco p quando o imprimimos.
440
00:23:06,820 --> 00:23:07,570
>DAVID MALAN: Sim.
441
00:23:07,570 --> 00:23:09,380
>Então eu tive um pouco de dificuldade em ouvir você.
442
00:23:09,380 --> 00:23:12,370
>Mas acho que, se não usarmos
o operador &,
443
00:23:12,370 --> 00:23:14,710
>mas o operador asterisco,
isso vai ser,
444
00:23:14,710 --> 00:23:17,170
>na verdade, o operador de desreferência,
o que significa ,
445
00:23:17,170 --> 00:23:19,120
>vá para o valor em p.
446
00:23:19,120 --> 00:23:23,530
>E se o valor em p for um endereço,
eu acho, vamos tentar fazer isso, make address.
447
00:23:23,530 --> 00:23:25,490
>Sim, isso compilou OK desta vez.
448
00:23:25,490 --> 00:23:27,550
>Agora, se eu fizer um ponto e
barra de endereço, espero que eu
449
00:23:27,550 --> 00:23:30,400
>veja agora o número 50.
450
00:23:30,400 --> 00:23:33,010
>Portanto, novamente, não parecemos ter
feito nenhum progresso fundamental.
451
00:23:33,010 --> 00:23:36,070
>no fim das contas, ainda estou
imprimindo o valor de n.
452
00:23:36,070 --> 00:23:39,100
>Mas apresentamos este novo primitivo,
esta nova peça do quebra-cabeça,
453
00:23:39,100 --> 00:23:41,440
>se assim preferir, isso permite
que você, programaticamente,
454
00:23:41,440 --> 00:23:44,390
>descubra o endereço de algo
na memória do computador
455
00:23:44,390 --> 00:23:46,540
>e vá para esse endereço.
456
00:23:46,540 --> 00:23:52,070
>E logo vamos exercitar um controle
mais sofisticado.
457
00:23:52,070 --> 00:23:56,050
>Mas vamos voltar a uma
representação disto
458
00:23:56,050 --> 00:23:59,290
>e considere o que acabamos de fazer
no contexto, agora, deste código.
459
00:23:59,290 --> 00:24:02,080
>Então, dentro do meu main, as
duas linhas interessantes de código,
460
00:24:02,080 --> 00:24:05,320
>essas duas linhas eram as
primeiras, antes de adicionarmos
461
00:24:05,320 --> 00:24:07,990
>a sugestão da Sofia, desreferenciando
p e imprimindo com printf.
462
00:24:07,990 --> 00:24:10,810
>Mas vamos considerar, por um momento,
quais são esses valores agora
463
00:24:10,810 --> 00:24:12,280
>que parecem na memória de um computador.
464
00:24:12,280 --> 00:24:14,440
>E, novamente, a sintaxe
é um pouco enigmática
465
00:24:14,440 --> 00:24:16,475
>porque agora temos uma
asterisco e um &.
466
00:24:16,475 --> 00:24:18,850
>Mas, novamente, isso significa apenas,
agora, vamos começar a pensar
467
00:24:18,850 --> 00:24:20,405
>em termos de memória do computador.
468
00:24:20,405 --> 00:24:23,030
>Por exemplo, aqui está uma grade de
memória dentro do meu computador.
469
00:24:23,030 --> 00:24:26,980
>E talvez, por exemplo, o
50 e o n acabam lá embaixo.
470
00:24:26,980 --> 00:24:29,980
>Eles podem acabar em qualquer lugar,
nem mesmo retratados na tela aqui.
471
00:24:29,980 --> 00:24:34,090
>Eles acabam em algum lugar na memória do
computador, para nossos propósitos até agora.
472
00:24:34,090 --> 00:24:36,100
>Mas tecnicamente estão em um endereço.
473
00:24:36,100 --> 00:24:38,950
>E deixe-me simplificar o endereço
para que seja mais rápido de dizer.
474
00:24:38,950 --> 00:24:42,310
>Este 50, agora, armazenado na
variável n, talvez ele
475
00:24:42,310 --> 00:24:44,590
>esteja no endereço 0x123.
476
00:24:44,590 --> 00:24:46,480
>Não tenho ideia de onde
está, mas claramente
477
00:24:46,480 --> 00:24:50,200
>visto que ele pode estar em um endereço
aparentemente aleatório como aquele.
478
00:24:50,200 --> 00:24:51,640
>Agora, que tal p?
479
00:24:51,640 --> 00:24:54,520
>p é tecnicamente uma variável em si.
480
00:24:54,520 --> 00:24:57,190
>É uma variável que armazena
o endereço de outra coisa.
481
00:24:57,190 --> 00:25:00,190
>Mas ainda é uma variável,
o que significa que, quando você declara p
482
00:25:00,190 --> 00:25:04,660
>com o código anterior, ele
ocupa alguns bytes de memória
483
00:25:04,660 --> 00:25:05,660
>na tela.
484
00:25:05,660 --> 00:25:10,420
>E então agora eu vou
propor que p acabe na memória aqui.
485
00:25:10,420 --> 00:25:13,450
>Agora, p é deliberadamente desenhado
para ser mais longo aqui.
486
00:25:13,450 --> 00:25:15,700
>Estou consumindo oito
bytes no total desta vez,
487
00:25:15,700 --> 00:25:20,470
>porque, ao que parece, em sistemas de
computador modernos, incluindo CS50 IDE,
488
00:25:20,470 --> 00:25:23,500
>os ponteiros tendem a ocupar oito bytes.
489
00:25:23,500 --> 00:25:27,190
>Portanto, não um, não quatro, mas oito bytes,
então eu simplesmente desenhei para ser maior.
490
00:25:27,190 --> 00:25:31,240
>Então, o que é
armazenado na variável p?
491
00:25:31,240 --> 00:25:35,600
>Bem, acontece que, novamente, está apenas
armazenando o endereço de algum valor.
492
00:25:35,600 --> 00:25:42,460
>Portanto, se o inteiro n, que por si só está
armazenando 50, estiver na localização 0x123,
493
00:25:42,460 --> 00:25:47,080
>e o ponteiro p está sendo atribuído
a esse endereço, é como dizer,
494
00:25:47,080 --> 00:25:50,620
>bem, armazenado nesta variável p,
é literalmente apenas um número
495
00:25:50,620 --> 00:25:54,190
>representado aqui em notação
hexadecimal, 0x123.
496
00:25:54,190 --> 00:25:56,650
>Então isso é tudo o que está acontecendo
dentro da memória do computador
497
00:25:56,650 --> 00:25:57,858
>com essas duas linhas de código.
498
00:25:57,858 --> 00:26:00,040
>Não há nada fundamentalmente
novo, exceto o fato
499
00:26:00,040 --> 00:26:04,430
>que temos uma nova sintaxe para nos
referirmos a esses endereços explicitamente.
500
00:26:04,430 --> 00:26:06,100
>Este é o n aqui embaixo.
501
00:26:06,100 --> 00:26:07,720
>Este é o p aqui em cima.
502
00:26:07,720 --> 00:26:12,160
>E o valor de p simplesmente
é um endereço.
503
00:26:12,160 --> 00:26:15,205
>Agora, eu continuo dizendo que esses
endereços são um pouco enigmáticos.
504
00:26:15,205 --> 00:26:16,330
>Eles são um pouco arbitrários.
505
00:26:16,330 --> 00:26:16,872
>E são.
506
00:26:16,872 --> 00:26:20,530
>E honestamente, raramente, ou nunca,
vai ser esclarecedor saber,
507
00:26:20,530 --> 00:26:25,030
>como um humano, em que endereço
este inteiro n está.
508
00:26:25,030 --> 00:26:28,550
>Quem se importa se está em 0x123 ou 0x456?
509
00:26:28,550 --> 00:26:29,800
>Geralmente, não.
510
00:26:29,800 --> 00:26:33,070
>E então os cientistas da computação, ao
falar sobre a memória dos computadores,
511
00:26:33,070 --> 00:26:38,010
>tendem a não falar nesses detalhes de baixo
nível, em termos de números reais.
512
00:26:38,010 --> 00:26:40,600
>Em vez disso, eles tendem
a simplificar a imagem,
513
00:26:40,600 --> 00:26:44,230
>tipo de abstração de todas as outras
memórias, o que francamente, não é
514
00:26:44,230 --> 00:26:46,690
>relevante para a discussão
até agora, e apenas
515
00:26:46,690 --> 00:26:50,290
>quer saber, eu sei que p
está armazenando um endereço.
516
00:26:50,290 --> 00:26:53,740
>E esse endereço é o
de 50 aqui embaixo.
517
00:26:53,740 --> 00:26:56,830
>Mas eu não me importo, na
minha vida diária de programação,
518
00:26:56,830 --> 00:26:58,360
>quais são esses endereços específicos.
519
00:26:58,360 --> 00:26:59,230
>E sabe do que mais?
520
00:26:59,230 --> 00:27:01,730
>Vamos abstrair isso rapidamente.
521
00:27:01,730 --> 00:27:06,250
>E, novamente, abstração é simplificar
os detalhes de nível inferior
522
00:27:06,250 --> 00:27:09,250
>que você pode muito bem precisar
entender, mas não necessariamente
523
00:27:09,250 --> 00:27:10,520
>precisa continuar pensando.
524
00:27:10,520 --> 00:27:11,950
>Você não precisa ficar
pensando neste nível.
525
00:27:11,950 --> 00:27:13,730
>Basta pensar neste nível.
526
00:27:13,730 --> 00:27:16,600
>Então, podemos também desenhar
um ponteiro,
527
00:27:16,600 --> 00:27:20,710
>como apontando para algum valor
e independentemente de qual
528
00:27:20,710 --> 00:27:22,330
>o endereço real é.
529
00:27:22,330 --> 00:27:25,150
>E esse é o caso em
nosso mundo humano.
530
00:27:25,150 --> 00:27:29,200
>Temos convenções muito
semelhantes,
531
00:27:29,200 --> 00:27:31,750
>seja ou não óbvio à
primeira vista, tal
532
00:27:31,750 --> 00:27:37,310
>que podemos muito bem estar usando esses
mesmos mecanismos em nossa vida cotidiana.
533
00:27:37,310 --> 00:27:40,690
>Por exemplo, se acontecer de você ter
uma caixa de correio na rua de sua casa
534
00:27:40,690 --> 00:27:43,768
>ou no porão de Harvard, no
Centro de Ciências,
535
00:27:43,768 --> 00:27:46,810
>pode muito bem se parecer com algo
assim, pelo menos mais residencial.
536
00:27:46,810 --> 00:27:51,100
>E suponha que esta caixa de correio aqui
esteja representando, neste caso, p,
537
00:27:51,100 --> 00:27:51,790
>nessa história.
538
00:27:51,790 --> 00:27:55,490
>É armazenar um ponteiro, ou seja,
o endereço de outra coisa.
539
00:27:55,490 --> 00:27:58,360
>Bem, se houver um monte de
outras caixas de correio na rua,
540
00:27:58,360 --> 00:28:01,510
>bem, podemos colocar o que quisermos
nessas caixas de correio.
541
00:28:01,510 --> 00:28:04,840
>Podemos colocar cartões postais,
cartas, até pacotes.
542
00:28:04,840 --> 00:28:08,250
>E assim como no mundo real,
podemos fazer o mesmo no virtual.
543
00:28:08,250 --> 00:28:12,890
>Posso armazenar caracteres ou inteiros
ou outras coisas, incluindo endereços.
544
00:28:12,890 --> 00:28:17,100
>Brian, por exemplo, acho que você tem sua
própria caixa de correio em outro lugar.
545
00:28:17,100 --> 00:28:20,660
>E Brian, é claro, tem uma caixa de
correio que tem um endereço exclusivo.
546
00:28:20,660 --> 00:28:23,600
>Brian, por exemplo, o
que é o endereço único
547
00:28:23,600 --> 00:28:26,030
>da caixa de correio da sua rua aí?
548
00:28:26,030 --> 00:28:27,600
>BRIAN: Sim, então aqui está minha caixa de correio.
549
00:28:27,600 --> 00:28:28,370
>É rotulada como n.
550
00:28:28,370 --> 00:28:29,750
>E seu endereço está aqui.
551
00:28:29,750 --> 00:28:33,200
>O endereço da minha caixa de
correio parece ser 0x123.
552
00:28:33,200 --> 00:28:35,450
>DAVID MALAN: Sim, minha caixa de
correio também tem um endereço.
553
00:28:35,450 --> 00:28:37,200
>Francamente, novamente, eu
não me importo com isso.
554
00:28:37,200 --> 00:28:39,033
>Então eu nem mesmo coloquei
na caixa de correio aqui.
555
00:28:39,033 --> 00:28:43,070
>Mas se minha caixa de correio representa p,
um ponteiro e a caixa de correio de Brian
556
00:28:43,070 --> 00:28:45,920
>representa n, um
inteiro, bem, deveria
557
00:28:45,920 --> 00:28:49,260
>significa que se eu olhar dentro
do conteúdo do meu ponteiro
558
00:28:49,260 --> 00:28:53,690
>e vejo o valor 0x123,
essa agora é minha pista,
559
00:28:53,690 --> 00:28:57,560
>uma espécie de migalha de pão, que agora me permite
dar uma olhada na caixa de correio de Brian.
560
00:28:57,560 --> 00:29:00,320
>E Brian, se você não se
importasse de fazer isso por nós,
561
00:29:00,320 --> 00:29:02,430
>o que você tem nesse endereço?
562
00:29:02,430 --> 00:29:05,540
>BRIAN: E se eu olhar em minha caixa
de correio no endereço 0x123,
563
00:29:05,540 --> 00:29:07,727
>Tenho o número 50 dentro
desta caixa de correio.
564
00:29:07,727 --> 00:29:08,810
>DAVID MALAN: Sim.
565
00:29:08,810 --> 00:29:10,400
>Portanto, neste caso, ele
está armazenando um int.
566
00:29:10,400 --> 00:29:11,650
>Mas pode ser qualquer outra coisa.
567
00:29:11,650 --> 00:29:14,480
>E, novamente, normalmente não nos
importamos com esses endereços específicos.
568
00:29:14,480 --> 00:29:17,450
>Depois de entender a metáfora,
podemos fazer algo bobo
569
00:29:17,450 --> 00:29:20,630
>e pensar nessa caixa de correio
como armazenando um valor que está
570
00:29:20,630 --> 00:29:23,180
>apontando para a caixa de correio de Brian.
571
00:29:23,180 --> 00:29:26,510
>É algum tipo de direção desenhada
lá, como uma seta,
572
00:29:26,510 --> 00:29:29,000
>aqui como um dedo de espuma bobo.
573
00:29:29,000 --> 00:29:34,750
>Ou, se preferir, um dedo da Yale, feito de espuma,
apontando para a caixa de correio de Brian,
574
00:29:34,750 --> 00:29:38,720
>apenas como uma espécie de trilha de navegação
que nos leva a algum outro valor na tela.
575
00:29:38,720 --> 00:29:41,408
>Então, quando falamos hoje
e além sobre endereços,
576
00:29:41,408 --> 00:29:42,700
>é nisso que falamos.
577
00:29:42,700 --> 00:29:45,790
>Nós, humanos, no mundo real, temos
usado endereços por eras, agora,
578
00:29:45,790 --> 00:29:49,030
>para identificar com exclusividade
nossas casas ou empresas ou semelhantes.
579
00:29:49,030 --> 00:29:51,520
>Os computadores fazem exatamente a
mesma coisa em um nível inferior
580
00:29:51,520 --> 00:29:53,440
>usando a memória do computador.
581
00:29:53,440 --> 00:29:58,330
>Vou fazer uma pausa aqui para ver se
há alguma dúvida sobre ponteiros, variáveis
582
00:29:58,330 --> 00:30:00,760
>que armazenam endereços, ou
nessas novos operadores,
583
00:30:00,760 --> 00:30:02,890
>como o & ou o asterisco, que
584
00:30:02,890 --> 00:30:06,310
>agora tem um novo significado.
585
00:30:06,310 --> 00:30:06,968
>Nada ainda.
586
00:30:06,968 --> 00:30:09,010
>Tudo bem, vamos considerar agora,
587
00:30:09,010 --> 00:30:12,250
>a mesma história no contexto de um
tipo de dados completamente diferente.
588
00:30:12,250 --> 00:30:15,310
>Até agora, jogamos apenas com ints.
589
00:30:15,310 --> 00:30:16,630
>Mas considere strings.
590
00:30:16,630 --> 00:30:20,950
>Gastamos muito tempo com strings,
usando criptografia com elas
591
00:30:20,950 --> 00:30:25,880
>e resolvendo a implementação de algoritmos
eleitorais usando a entrada do usuário.
592
00:30:25,880 --> 00:30:27,940
>Então, vamos considerar um dado
fundamentalmente diferente
593
00:30:27,940 --> 00:30:31,940
>que armazena, não inteiros individuais,
mas strings de texto.
594
00:30:31,940 --> 00:30:34,150
>Então, por exemplo, em qualquer
programa envolvendo uma string,
595
00:30:34,150 --> 00:30:38,245
>você pode ter uma linha de código semelhante
a esta. string s é igual a, aspas
596
00:30:38,245 --> 00:30:40,090
>"HI!"
597
00:30:40,090 --> 00:30:41,852
>em maiúsculas com um ponto de exclamação.
598
00:30:41,852 --> 00:30:44,560
>Portanto, essa pode muito bem ser uma
linha de código que vimos até agora.
599
00:30:44,560 --> 00:30:46,935
>O que está acontecendo
dentro da memória do computador?
600
00:30:46,935 --> 00:30:51,340
>Bem, deixe-me sugerir que, quando você digitar
"HI!" em um computador,
601
00:30:51,340 --> 00:30:53,780
>ele acaba em algum lugar na
memória do seu computador.
602
00:30:53,780 --> 00:30:58,840
>Então, HI!, mais, como vimos semana
passada, uma \ 0-- ou duas semanas atrás,
603
00:30:58,840 --> 00:31:04,040
>uma \ 0, que é como um
computador representa o final dessa string.
604
00:31:04,040 --> 00:31:06,100
>Mas vamos olhar um pouco
mais cuidadosamente
605
00:31:06,100 --> 00:31:08,350
>o que está acontecendo
debaixo deste capô aqui.
606
00:31:08,350 --> 00:31:12,190
>Tecnicamente falando, eu poderia
abordar esses caracteres individuais
607
00:31:12,190 --> 00:31:16,280
>como vimos a partir da segunda semana, usando a
notação de colchetes como o colchete 0,
608
00:31:16,280 --> 00:31:18,910
>s colchete 1, s colchete 2 e
s colchete 3
609
00:31:18,910 --> 00:31:22,427
>Usamos a notação de colchetes
para tratar uma string
610
00:31:22,427 --> 00:31:24,010
>como se fosse um array de caracteres.
611
00:31:24,010 --> 00:31:26,900
>E é, foi e ainda é.
612
00:31:26,900 --> 00:31:32,230
>Mas acontece que as strings também podem
ser manipuladas por meio de seus endereços
613
00:31:32,230 --> 00:31:32,960
>também.
614
00:31:32,960 --> 00:31:36,640
>E então, por exemplo, talvez
esta mesma string exata, HI,
615
00:31:36,640 --> 00:31:43,480
>armazenada no endereço de memória
0x123 e então 0x124, 0x125 e 0x126.
616
00:31:43,480 --> 00:31:46,150
>Observe que são
deliberadamente contíguos
617
00:31:46,150 --> 00:31:47,560
>os endereços, de ponta a ponta.
618
00:31:47,560 --> 00:31:50,870
>E estão separados por apenas um byte,
porque cada um desses chars, é claro,
619
00:31:50,870 --> 00:31:53,140
>são apenas um byte em C.
620
00:31:53,140 --> 00:31:56,920
>Portanto, esses números não são
importantes, especificamente.
621
00:31:56,920 --> 00:31:59,530
>Mas o fato de eles estarem
separados um do outro
622
00:31:59,530 --> 00:32:02,350
>é importante, porque essa é
a definição de uma string,
623
00:32:02,350 --> 00:32:05,470
>e, um array,
ter memória consecutiva.
624
00:32:05,470 --> 00:32:08,140
>Agora, o que exatamente é S?
625
00:32:08,140 --> 00:32:11,530
>S era o nome da variável que dei um momento
atrás para ir para essa linha de código,
626
00:32:11,530 --> 00:32:13,840
>string S igual "HI."
627
00:32:13,840 --> 00:32:14,710
>bem, o que é S?
628
00:32:14,710 --> 00:32:18,950
>S é uma variável que precisa ir para
algum lugar na memória do computador.
629
00:32:18,950 --> 00:32:24,880
>E suponha que S seja,
HI com um ponto de exclamação.
630
00:32:24,880 --> 00:32:28,600
>E acontece que o HI
fica neste local aqui.
631
00:32:28,600 --> 00:32:31,390
>Você sabe o que você pode
pensar de S como sendo agora,
632
00:32:31,390 --> 00:32:34,840
>não é, em um nível alto, uma
string, mas em um nível inferior,
633
00:32:34,840 --> 00:32:37,300
>é o endereço de uma string.
634
00:32:37,300 --> 00:32:40,780
>Mais especificamente, vamos
começar a pensar em uma string
635
00:32:40,780 --> 00:32:46,297
>como sendo tecnicamente apenas o endereço
do primeiro caractere na string.
636
00:32:46,297 --> 00:32:48,130
>Agora, isso pode fazer
você parar por um momento,
637
00:32:48,130 --> 00:32:49,810
>por que o primeiro caractere?
638
00:32:49,810 --> 00:32:53,710
>Como você vai se lembrar disso, espere um
minuto, esta string não está apenas
639
00:32:53,710 --> 00:32:54,940
>em 0x123.
640
00:32:54,940 --> 00:33:00,110
>Também continua em
0x124, 0x125 e assim por diante.
641
00:33:00,110 --> 00:33:02,950
>Mas deixe-me fazer uma pausa e
perguntar ao grupo aqui, por que
642
00:33:02,950 --> 00:33:06,110
>pode muito bem ser suficiente
para um computador
643
00:33:06,110 --> 00:33:12,550
>e nós, programadores, pensemos
apenas em strings em termos de ser
644
00:33:12,550 --> 00:33:15,460
>o endereço do primeiro byte.
645
00:33:15,460 --> 00:33:18,220
>Tipo, por que é suficiente,
não importa quanto tempo
646
00:33:18,220 --> 00:33:20,830
>a string é, mesmo que seja um
parágrafo inteiro de texto,
647
00:33:20,830 --> 00:33:25,360
>por que é muito habilmente suficiente
pensar em uma string como S
648
00:33:25,360 --> 00:33:31,420
>como sendo idêntica ao
endereço do primeiro byte?
649
00:33:31,420 --> 00:33:33,718
>Ginni, não é?
650
00:33:33,718 --> 00:33:37,480
>PÚBLICO: Possivelmente porque acontece que
as strings, sempre que estamos definindo
651
00:33:37,480 --> 00:33:39,490
>uma nova string, isso é tudo.
652
00:33:39,490 --> 00:33:44,410
>Suponha que, se estou escrevendo meu nome, Ginni,
então será G-I-N-N-I.
653
00:33:44,410 --> 00:33:46,810
>Portanto, será suficiente
se algo for apontado
654
00:33:46,810 --> 00:33:50,560
>para apenas o primeiro caractere do
meu nome, para que eu possa apenas
655
00:33:50,560 --> 00:33:55,895
>seguir para o primeiro caractere e, em
seguida, obter todos os caracteres.
656
00:33:55,895 --> 00:33:56,770
>DAVID MALAN: Perfeito.
657
00:33:56,770 --> 00:33:59,800
>Todas essas definições básicas
que tivemos nas últimas semanas
658
00:33:59,800 --> 00:34:00,790
>agora se juntaram.
659
00:34:00,790 --> 00:34:02,812
>Se uma string é um
array de caracteres -
660
00:34:02,812 --> 00:34:05,020
>e por definição de array,
esses caracteres estão
661
00:34:05,020 --> 00:34:09,280
>de ponta a ponta e, duas semanas atrás, cada string
662
00:34:09,280 --> 00:34:13,300
>termina com este caractere de barra
invertida convencional zero ou nulo.
663
00:34:13,300 --> 00:34:15,550
>Tudo o que você precisa fazer
ao pensar em uma string
664
00:34:15,550 --> 00:34:17,530
>é saber onde
a string começa,
665
00:34:17,530 --> 00:34:19,719
>porque você pode usar um
loop for ou um loop while
666
00:34:19,719 --> 00:34:22,540
>ou alguma outra heurística com uma
condição e uma expressão booleana
667
00:34:22,540 --> 00:34:25,929
>para descobrir onde a string
termina, mesmo sem saber,
668
00:34:25,929 --> 00:34:27,710
>antecipadamente, seu comprimento.
669
00:34:27,710 --> 00:34:30,159
>Quer dizer, vamos
começar, por enquanto,
670
00:34:30,159 --> 00:34:32,679
>pensando em strings como
sendo simplesmente
671
00:34:32,679 --> 00:34:37,969
>apenas o endereço do
primeiro caractere na string.
672
00:34:37,969 --> 00:34:40,989
>E se tomarmos isso como um
fato, vamos em frente, agora,
673
00:34:40,989 --> 00:34:43,989
>e começar a brincar com um programa que não
usa números inteiros, mas em vez disso,
674
00:34:43,989 --> 00:34:46,570
>strings usadas, usando
este primitivo básico.
675
00:34:46,570 --> 00:34:49,929
>Então, agora eu vou deletar o
código que escrevi antes, um adddress.c.
676
00:34:49,929 --> 00:34:54,580
>Vou mudar para uma string igual a
ponto-e-vírgula "HI".
677
00:34:54,580 --> 00:34:57,700
>E observe, eu não estou digitando
manualmente nenhum 0 de \.
678
00:34:57,700 --> 00:34:59,560
>C faz isso para nós automaticamente.
679
00:34:59,560 --> 00:35:02,260
>Quando você fecha a aspas,
o compilador cuida
680
00:35:02,260 --> 00:35:04,158
>de adicionar a \ 0 para você.
681
00:35:04,158 --> 00:35:05,950
>Agora, vou em frente
na próxima linha
682
00:35:05,950 --> 00:35:10,042
>e imprima %
s \ vírgula s,
683
00:35:10,042 --> 00:35:11,500
>se eu quiser imprimir essa string.
684
00:35:11,500 --> 00:35:13,968
>Agora, este programa não
é mais interessante.
685
00:35:13,968 --> 00:35:15,760
>Na primeira semana,
escrevemos algo como -
686
00:35:15,760 --> 00:35:18,730
>OK, sim, é interessante
porque eu estraguei tudo.
687
00:35:18,730 --> 00:35:19,780
>Então, cinco erros.
688
00:35:19,780 --> 00:35:22,450
>Escrevi sete linhas de
código e cinco erros.
689
00:35:22,450 --> 00:35:24,070
>E vamos ver o que está acontecendo.
690
00:35:24,070 --> 00:35:27,430
>Como sempre, vá sempre para o topo,
porque as probabilidades são,
691
00:35:27,430 --> 00:35:29,650
>de haver um efeito
em cascata confuso.
692
00:35:29,650 --> 00:35:34,090
>O primeiro erro que vejo é o uso de
string de identificador não declarado.
693
00:35:34,090 --> 00:35:35,230
>Eu quis dizer padrão n?
694
00:35:35,230 --> 00:35:37,900
>Eu não quis dizer padrão n,
string, string, string.
695
00:35:37,900 --> 00:35:40,780
>Então, eu poderia rodar help50 como
minha fronteira, mas, honestamente, eu
696
00:35:40,780 --> 00:35:43,150
>cometo esse erro com frequência
suficiente para que eu saiba agora
697
00:35:43,150 --> 00:35:46,690
>que esqueci de incluir cs50.h.
698
00:35:46,690 --> 00:35:49,960
>E, se eu fizer isso
e recompilar make address -
699
00:35:49,960 --> 00:35:53,080
>OK, todos os cinco erros são eliminados
apenas por aquela mudança simples.
700
00:35:53,080 --> 00:35:56,200
>E se eu executar o endereço agora,
ele simplesmente vai dizer HI.
701
00:35:56,200 --> 00:35:59,020
>Mas agora vamos começar a
considerar o que está acontecendo
702
00:35:59,020 --> 00:36:00,650
>por baixo do capô deste programa.
703
00:36:00,650 --> 00:36:06,040
>Suponha que eu esteja curioso e
queira imprimir o que é
704
00:36:06,040 --> 00:36:08,170
>o endereço em que esta string reside.
705
00:36:08,170 --> 00:36:09,520
>Bem, acontece -
706
00:36:09,520 --> 00:36:10,690
>deixe-me ser inteligente aqui.
707
00:36:10,690 --> 00:36:14,830
>Vamos imprimir, não um código de
% s, mas % p.
708
00:36:14,830 --> 00:36:18,290
>Mostre-me esta mesma string como um endereço.
709
00:36:18,290 --> 00:36:22,060
>Eu vou recompilar,
make address, parece compilar OK.
710
00:36:22,060 --> 00:36:23,560
>Vamos executar
./ address.
711
00:36:23,560 --> 00:36:26,350
>E novamente, ainda estou imprimindo
s, mas estou pedindo printf
712
00:36:26,350 --> 00:36:30,260
>para apresentá-lo como se fosse um ponteiro.
713
00:36:30,260 --> 00:36:32,430
>E interessante, não
é o mesmo de antes.
714
00:36:32,430 --> 00:36:35,060
>Mas, novamente, isso é razoável
porque os endereços de memória
715
00:36:35,060 --> 00:36:36,540
>não serão sempre os mesmos.
716
00:36:36,540 --> 00:36:37,940
>Mas não importa o que seja.
717
00:36:37,940 --> 00:36:39,232
>Mas isso é interessante.
718
00:36:39,232 --> 00:36:41,750
>Todo esse tempo, sempre que
você estiver usando strings,
719
00:36:41,750 --> 00:36:44,300
>você tinha acabado de mudar seu
%s para % p,
720
00:36:44,300 --> 00:36:48,290
>você poderia ter visto onde, na
memória, essa string começa.
721
00:36:48,290 --> 00:36:50,780
>Ainda não é funcionalmente
útil para nós.
722
00:36:50,780 --> 00:36:52,700
>Mas está lá o tempo todo.
723
00:36:52,700 --> 00:36:54,800
>Agora eu vou
fazer o seguinte.
724
00:36:54,800 --> 00:36:58,950
>Suponha que eu fique um pouco
mais curioso e faça printf.
725
00:36:58,950 --> 00:37:02,390
>Eu vou imprimir outro
endereço seguido por uma nova linha.
726
00:37:02,390 --> 00:37:07,035
>Agora eu vou imprimir
o endereço do primeiro caractere.
727
00:37:07,035 --> 00:37:08,660
>Então, novamente, isso é um pouco estranho de se fazer.
728
00:37:08,660 --> 00:37:10,220
>E normalmente não faríamos
isso com tanta frequência.
729
00:37:10,220 --> 00:37:13,430
>Mas, novamente, apenas para deixar claro que
esses operadores nos fornecem muito simples
730
00:37:13,430 --> 00:37:16,850
>respostas a perguntas como,
qual é o endereço dessa coisa?
731
00:37:16,850 --> 00:37:23,960
>Se s colchete i, a partir da segunda semana em CS50,
representou o segundo caractere em s,
732
00:37:23,960 --> 00:37:28,190
>porque o índice 0 significa s colchete 0
é o primeiro, s colchete 1 é o segundo.
733
00:37:28,190 --> 00:37:30,410
>Se eu brincar com o
novo operador de hoje,
734
00:37:30,410 --> 00:37:36,020
>este &, aposto que posso ver
o endereço desse segundo caractere.
735
00:37:36,020 --> 00:37:38,390
>E, deixe-me ir em
frente e ser mais explícito.
736
00:37:38,390 --> 00:37:43,160
>Vou mudar este primeiro s para o
colchete 0 e colocar um & aqui.
737
00:37:43,160 --> 00:37:46,430
>E deixe-me ir em frente, agora, e
fazer este programa, make address.
738
00:37:46,430 --> 00:37:48,170
>OK, um pouco esquisito -
739
00:37:48,170 --> 00:37:49,680
>Acabei de perder um ponto e vírgula.
740
00:37:49,680 --> 00:37:51,060
>Tão fácil consertar.
741
00:37:51,060 --> 00:37:53,600
>Vamos prosseguir e
recompilar com make address.
742
00:37:53,600 --> 00:37:55,880
>Vamos prosseguir e executar
./ endereço.
743
00:37:55,880 --> 00:37:58,970
>E interessante, bem, talvez -
744
00:37:58,970 --> 00:38:00,320
>interessante para mim.
745
00:38:00,320 --> 00:38:02,780
>Então você vê, agora, dois
endereços, o primeiro dos quais
746
00:38:02,780 --> 00:38:08,900
>é 0x4006a4, que aparentemente é o
endereço do primeiro caractere em s.
747
00:38:08,900 --> 00:38:10,880
>Mas observe o que há
de curioso no próximo.
748
00:38:10,880 --> 00:38:15,720
>É quase o mesmo, exceto que o
byte está um mais distante.
749
00:38:15,720 --> 00:38:18,380
>E eu aposto que se eu fizer
isso, não apenas para "h" e "i",
750
00:38:18,380 --> 00:38:20,330
>mas também o ponto de
exclamação - deixe-me fazer
751
00:38:20,330 --> 00:38:23,210
>mais uma linha de código
quase idêntica, apenas
752
00:38:23,210 --> 00:38:26,240
>para deixar claro que todo
esse tempo é,
753
00:38:26,240 --> 00:38:30,560
>é o caso em que todos os caracteres
em uma string estão consecutivos.
754
00:38:30,560 --> 00:38:32,540
>E agora você pode vê-lo em código.
755
00:38:32,540 --> 00:38:37,610
>b4, b5, b6 estão separados por apenas um byte.
756
00:38:37,610 --> 00:38:40,940
>Então, vemos alguma confirmação visual,
agora, essas strings são de fato
757
00:38:40,940 --> 00:38:42,990
>colocadas na memória assim.
758
00:38:42,990 --> 00:38:46,130
>Agora, novamente, este não é um
exercício programático muito útil
759
00:38:46,130 --> 00:38:48,500
>ver o endereço de
caracteres individuais.
760
00:38:48,500 --> 00:38:51,350
>Mas, novamente, isso é para
enfatizar que, por baixo do capô,
761
00:38:51,350 --> 00:38:53,960
>algumas operações relativamente
simples estão sendo
762
00:38:53,960 --> 00:38:58,562
>habilitadas por meio deste novo &,
e por sua vez, operador asterisco.
763
00:38:58,562 --> 00:39:00,770
>Então, vamos considerar por um
momento o que isso parece
764
00:39:00,770 --> 00:39:02,390
>dentro da memória do computador.
765
00:39:02,390 --> 00:39:05,660
>Em um baixo nível, sim, s é
tecnicamente um endereço.
766
00:39:05,660 --> 00:39:08,540
>E sim, é tecnicamente o
endereço do primeiro byte,
767
00:39:08,540 --> 00:39:10,880
>que no computador real,
parecia diferente.
768
00:39:10,880 --> 00:39:13,100
>Mas no meu slide aqui, eu
apenas propus arbitrariamente
769
00:39:13,100 --> 00:39:17,210
>que está em 0x123, 0x124, 0x125.
770
00:39:17,210 --> 00:39:20,300
>Mas, novamente, não vamos nos
importar com esse nível de detalhe.
771
00:39:20,300 --> 00:39:23,210
>Vamos abstrair esses endereços
772
00:39:23,210 --> 00:39:30,950
>e agora comece a pensar em s, que é uma
string, como tecnicamente apenas sendo
773
00:39:30,950 --> 00:39:32,450
>um ponteiro.
774
00:39:32,450 --> 00:39:33,260
>Um ponteiro.
775
00:39:33,260 --> 00:39:36,463
>Acontece que, embora seja
muito útil e muito comum
776
00:39:36,463 --> 00:39:39,380
>pensar em strings como, obviamente,
sendo apenas sequências de caracteres.
777
00:39:39,380 --> 00:39:41,240
>E isso é verdade desde a primeira semana.
778
00:39:41,240 --> 00:39:43,130
>E você também pode pensar
nelas como arrays,
779
00:39:43,130 --> 00:39:44,990
>sequências consecutivas de caracteres.
780
00:39:44,990 --> 00:39:47,330
>Você também pode, ao que
parece, a partir de hoje,
781
00:39:47,330 --> 00:39:51,290
>pensar nelas como apenas
ponteiros, ou seja,
782
00:39:51,290 --> 00:39:54,900
>o endereço de um caractere em algum
lugar na memória do computador.
783
00:39:54,900 --> 00:39:58,550
>E como Ginni observa, porque todos
os caracteres em uma string
784
00:39:58,550 --> 00:40:00,770
>são, por definição,
de ponta a ponta,
785
00:40:00,770 --> 00:40:05,720
>porque, por definição, todas as strings
terminam com uma \ 0, que
786
00:40:05,720 --> 00:40:08,750
>é literalmente a menor e única
quantidade de informação
787
00:40:08,750 --> 00:40:12,920
>que você precisa manter um computador para
saber onde estão todas as suas strings.
788
00:40:12,920 --> 00:40:16,340
>Basta lembrar o endereço
do primeiro caractere
789
00:40:16,340 --> 00:40:19,430
>porque você pode encontrar
seu caminho até o fim
790
00:40:19,430 --> 00:40:24,320
>lembrando que esta \ 0 é,
na verdade, apenas oito 0
791
00:40:24,320 --> 00:40:27,080
>bits, representada
como \ 0.
792
00:40:27,080 --> 00:40:29,617
>E então certamente poderíamos
ter uma condição if,
793
00:40:29,617 --> 00:40:31,700
>muito parecida com o que fizemos há
duas semanas, quando brincávamos
794
00:40:31,700 --> 00:40:36,230
>com o comprimento das strings, que nos
permite verificar precisamente isso.
795
00:40:36,230 --> 00:40:41,030
>E então, quando digo que vamos
remover as muletas, aqui está.
796
00:40:41,030 --> 00:40:44,330
>Até agora, estamos usando,
novamente, a biblioteca CS50,
797
00:40:44,330 --> 00:40:47,470
>o que nos dá, convenientemente,
funções como get string e get int
798
00:40:47,470 --> 00:40:49,650
>e get float e assim por diante.
799
00:40:49,650 --> 00:40:54,650
>Mas todo esse tempo, a biblioteca CS50,
especificamente o arquivo, cs50.h,
800
00:40:54,650 --> 00:40:58,070
>teve um pouco de simplificação
pedagógica.
801
00:40:58,070 --> 00:41:02,510
>Lembre-se da semana passada, que você pode definir
seus próprios tipos de dados personalizados.
802
00:41:02,510 --> 00:41:06,955
>Bem, acontece que todo esse tempo,
temos afirmado que existem strings
803
00:41:06,955 --> 00:41:09,080
>e são algo que você
pode usar em seus programas.
804
00:41:09,080 --> 00:41:14,420
>E strings existem em C. Elas existem
em Python, em Java Script, em Java,
805
00:41:14,420 --> 00:41:16,980
>e C, em muitas, muitas, muitas outras linguagens.
806
00:41:16,980 --> 00:41:18,860
>Este não é um termo CS50.
807
00:41:18,860 --> 00:41:25,190
>Mas string, tecnicamente, não existe como
um tipo de dados em C. Em vez disso,
808
00:41:25,190 --> 00:41:31,180
>é mais cripticamente e de nível mais
baixo conhecido como char*.
809
00:41:31,180 --> 00:41:33,080
>Asterisco char,
agora o que isso significa?
810
00:41:33,080 --> 00:41:37,180
>Bem, char*, muito parecida com nosso
asterisco int de alguns minutos atrás,
811
00:41:37,180 --> 00:41:40,840
>apenas representa o endereço de
um caractere, bem como int asterisco
812
00:41:40,840 --> 00:41:43,210
>representa o endereço de um int.
813
00:41:43,210 --> 00:41:46,210
>E se, novamente, você meio
que concorda comigo agora,
814
00:41:46,210 --> 00:41:49,450
>que você pode pensar em strings
como sequências de caracteres,
815
00:41:49,450 --> 00:41:52,660
>ou mais especificamente, arrays de
caracteres ou, mais especificamente,
816
00:41:52,660 --> 00:41:56,920
>a partir de hoje, o endereço
apenas do primeiro caractere,
817
00:41:56,920 --> 00:41:59,680
>então é, o caso
de que agora podemos
818
00:41:59,680 --> 00:42:02,800
>aplicar esta nova terminologia,
hoje, de ponteiro,
819
00:42:02,800 --> 00:42:06,040
>para nossas velhas amigas,
as strings.
820
00:42:06,040 --> 00:42:10,690
>String é a mesma coisa que um sinônimo,
se assim preferir, de char*.
821
00:42:10,690 --> 00:42:14,200
>E é na biblioteca CS50 que
temos uma linha de código
822
00:42:14,200 --> 00:42:18,348
>que simplifica ou abstrai asterisco
char, que honestamente, ninguém quer
823
00:42:18,348 --> 00:42:20,890
>pensar ou ter essa dificuldade na
primeira semana de aula,
824
00:42:20,890 --> 00:42:23,260
>muito menos as primeiras duas
ou três semanas de aula.
825
00:42:23,260 --> 00:42:28,475
>É uma simplificação, um tipo de dado
customizado, que chamamos de string,
826
00:42:28,475 --> 00:42:30,850
>só para você não ter que
pensar, o que é esse asterisco?
827
00:42:30,850 --> 00:42:32,017
>O que isso significa para o caractere?
828
00:42:32,017 --> 00:42:33,100
>Sobre qual é o endereço?
829
00:42:33,100 --> 00:42:37,450
>Mas hoje podemos remover essas rodas de
treinamento e revelar isso, todo esse tempo,
830
00:42:37,450 --> 00:42:40,720
>você manipulou caracteres
em endereços específicos.
831
00:42:40,720 --> 00:42:43,180
>E usamos esse tipo
de técnica antes,
832
00:42:43,180 --> 00:42:45,550
>abstraindo esses detalhes
de nível inferior.
833
00:42:45,550 --> 00:42:48,310
>Por exemplo, lembre-se na semana
passada, que introduzimos
834
00:42:48,310 --> 00:42:52,630
>essa noção de uma estrutura, um tipo de dados
que você pode personalizar.
835
00:42:52,630 --> 00:42:56,200
>Nós implementamos uma melhor
lista telefônica, envolvendo
836
00:42:56,200 --> 00:42:58,630
>um nome e um número dentro de
um tipo de dados personalizado,
837
00:42:58,630 --> 00:43:01,960
>encapsulando-os se assim preferir,
dentro de algo que chamamos de pessoa.
838
00:43:01,960 --> 00:43:05,650
>E toda pessoa que afirmamos
ter uma estrutura
839
00:43:05,650 --> 00:43:07,580
>que contém um nome e um número.
840
00:43:07,580 --> 00:43:11,410
>E pelo caminho dessa característica do C,
typedef, podemos definir um novo tipo.
841
00:43:11,410 --> 00:43:15,200
>E o nome desse na semana passada,
era apenas uma pessoa.
842
00:43:15,200 --> 00:43:18,100
>Então, já estamos usando e
temos estado secretamente
843
00:43:18,100 --> 00:43:22,750
>usando desde a primeira semana do C,
uma linha de código que
844
00:43:22,750 --> 00:43:24,020
>se parece com isso.
845
00:43:24,020 --> 00:43:28,090
>E esta é, uma das linhas
de código dentro de cs50.h.
846
00:43:28,090 --> 00:43:31,000
>Diz typedef, o que significa
me dê um tipo personalizado.
847
00:43:31,000 --> 00:43:35,770
>E cria um sinônimo para
char* chamado string.
848
00:43:35,770 --> 00:43:39,700
>E é uma maneira de
esconder a char*.
849
00:43:39,700 --> 00:43:42,070
>Podemos ocultar o asterisco,
em particular, o que não
850
00:43:42,070 --> 00:43:43,990
>seria divertido de brincar
nos primeiros dias,
851
00:43:43,990 --> 00:43:47,200
>sem alterar a definição
do que é uma string.
852
00:43:47,200 --> 00:43:51,850
>Portanto, strings existem em C. Mas não há
nenhum tipo de dado chamado string em C
853
00:43:51,850 --> 00:43:56,020
>até usar uma biblioteca como
CS50's, que o faz existir
854
00:43:56,020 --> 00:43:58,930
>por meio desse tipo de definição.
855
00:43:58,930 --> 00:44:01,450
>Tudo bem, deixe-me fazer uma
pausa aqui para ver se há
856
00:44:01,450 --> 00:44:03,760
>qualquer dúvida, então,
sobre o que são strings
857
00:44:03,760 --> 00:44:09,360
>ou essas novas formas
de pensar sobre elas.
858
00:44:09,360 --> 00:44:13,390
>Alguma dúvida sobre strings
ou char*s?
859
00:44:13,390 --> 00:44:15,140
>Tudo bem, bem, se não houver
perguntas aqui, por que
860
00:44:15,140 --> 00:44:17,515
>não vamos em frente e fazemos uma
pausa de 5 minutos aqui primeiro.
861
00:44:17,515 --> 00:44:19,790
>E estaremos de volta em 5
e daremos outra olhada
862
00:44:19,790 --> 00:44:22,040
>no que podemos fazer agora
com esses novos primitivos.
863
00:44:22,040 --> 00:44:23,480
>Tudo bem, estamos de volta.
864
00:44:23,480 --> 00:44:27,680
>E temos, agora, essa capacidade no código
de obter o endereço de alguma variável
865
00:44:27,680 --> 00:44:30,140
>e também para ir a um
endereço usando &
866
00:44:30,140 --> 00:44:31,850
>e o asterisco, respectivamente.
867
00:44:31,850 --> 00:44:36,530
>Nós pensamos em strings como sendo
não apenas sequências contíguas
868
00:44:36,530 --> 00:44:38,150
>de caracteres, mas também arrays.
869
00:44:38,150 --> 00:44:42,477
>E então, é claro, a partir
de hoje, endereços reais,
870
00:44:42,477 --> 00:44:44,810
>o endereço do primeiro
caractere e, a partir daí,
871
00:44:44,810 --> 00:44:46,940
>podemos encontrar nosso caminho,
programaticamente, até o fim,
872
00:44:46,940 --> 00:44:48,380
>graças a esse caractere nul.
873
00:44:48,380 --> 00:44:52,220
>Mas acontece que há outra coisa que
podemos fazer com esses endereços
874
00:44:52,220 --> 00:44:53,840
>ou com ponteiros de forma mais geral.
875
00:44:53,840 --> 00:44:55,550
>E isso é conhecido como operação matemática de ponteiro.
876
00:44:55,550 --> 00:44:58,577
>Então, qualquer coisa que seja um número,
claro, podemos fazer matemática.
877
00:44:58,577 --> 00:45:00,410
>E a matemática não
vai ser complicada,
878
00:45:00,410 --> 00:45:03,390
>mas vai ser poderoso
para nós aqui.
879
00:45:03,390 --> 00:45:07,040
>Portanto, vou voltar ao meu
mais recente estado de address.c.
880
00:45:07,040 --> 00:45:11,480
>E deixe-me ir em frente, agora,
e reiterar que podemos imprimir
881
00:45:11,480 --> 00:45:15,800
>os caracteres individuais em uma string,
assim como fizemos na segunda semana,
882
00:45:15,800 --> 00:45:18,270
>usando nossa notação de colchetes.
883
00:45:18,270 --> 00:45:21,170
>Portanto, estou me livrando de todas as
evidências desses endereços por enquanto.
884
00:45:21,170 --> 00:45:23,420
>Estou recompilando este
programa como make address.
885
00:45:23,420 --> 00:45:25,650
>E então vou executar o
./address agora.
886
00:45:25,650 --> 00:45:29,690
>E vejo HI!,
um caractere por linha.
887
00:45:29,690 --> 00:45:34,290
>Mas agora, considere que não precisa
haver um tipo de dados de string.
888
00:45:34,290 --> 00:45:36,320
>Na verdade, podemos tirar
essa roda de treinamento.
889
00:45:36,320 --> 00:45:38,690
>E embora possa parecer um pouco
desconfortável no início,
890
00:45:38,690 --> 00:45:42,620
>se eu excluir esta primeira linha completamente,
como eu acidentalmente omiti de qualquer maneira
891
00:45:42,620 --> 00:45:45,660
>às vezes, não preciso ficar
chamando as coisas de strings.
892
00:45:45,660 --> 00:45:47,570
>Posso descrever como strings verbalmente.
893
00:45:47,570 --> 00:45:49,790
>Posso pensar nelas como
strings, porque strings
894
00:45:49,790 --> 00:45:53,150
>são uma coisa em muitas linguagens
de programação diferentes.
895
00:45:53,150 --> 00:45:56,070
>Mas, por padrão, em C,
simplesmente não existe como um tipo.
896
00:45:56,070 --> 00:45:59,750
>Em vez disso, o tipo tem um nome
um tanto enigmático, char*.
897
00:45:59,750 --> 00:46:02,840
>Mas, novamente, tudo o que isso significa
é que o asterisco está
898
00:46:02,840 --> 00:46:04,010
>marcando o endereço de algo.
899
00:46:04,010 --> 00:46:06,140
>Char significa que é o endereço de um char.
900
00:46:06,140 --> 00:46:09,950
>Então char* dá a você
uma variável de ponteiro
901
00:46:09,950 --> 00:46:12,720
>isso vai apontar para um caractere.
902
00:46:12,720 --> 00:46:16,080
>Então agora, se s é isso,
posso tratar da mesma forma.
903
00:46:16,080 --> 00:46:20,960
>Não há motivo para eu não poder continuar usando
s como uma string estava na segunda semana,
904
00:46:20,960 --> 00:46:22,400
>usando nossa notação de colchetes.
905
00:46:22,400 --> 00:46:24,770
>E posso continuar imprimindo
o HI!
906
00:46:24,770 --> 00:46:27,320
>usando a mesma sintaxe de colchetes.
907
00:46:27,320 --> 00:46:30,170
>Mas há uma outra maneira de fazer isso.
908
00:46:30,170 --> 00:46:35,150
>Se agora eu sei que s
é um endereço,
909
00:46:35,150 --> 00:46:37,760
>Posso me livrar dessa
notação de colchetes.
910
00:46:37,760 --> 00:46:42,860
>E eu posso apenas fazer s*,
porque lembre-se daquele asterisco, além disso
911
00:46:42,860 --> 00:46:47,270
>para ser o novo símbolo que usamos
ao declarar um ponteiro aqui,
912
00:46:47,270 --> 00:46:50,990
>também é o mesmo símbolo,
confuso, admito,
913
00:46:50,990 --> 00:46:53,310
>que costumávamos usar para ir a um endereço.
914
00:46:53,310 --> 00:46:57,650
>Então, se s está armazenando um endereço,
que é por definição um ponteiro,
915
00:46:57,650 --> 00:46:59,900
>s* significa ir para aquele endereço.
916
00:46:59,900 --> 00:47:02,000
>E de acordo com minha
foto anterior, parece
917
00:47:02,000 --> 00:47:08,060
>para ser o caso em que s provavelmente
está em um endereço que começa em 0x123.
918
00:47:08,060 --> 00:47:10,250
>Não será o mesmo em
meu IDE real aqui.
919
00:47:10,250 --> 00:47:12,167
>Será tudo o que o
computador ordenar.
920
00:47:12,167 --> 00:47:14,610
>Mas vai ser exatamente
a mesma ideia.
921
00:47:14,610 --> 00:47:17,150
>Então, agora eu vou ir para as s*.
922
00:47:17,150 --> 00:47:20,130
>E só por diversão, vou
deixar apenas uma linha.
923
00:47:20,130 --> 00:47:23,870
>Então, vou executar
novamente como make address.
924
00:47:23,870 --> 00:47:25,470
>Tudo bem, e agora ./address.
925
00:47:25,470 --> 00:47:30,710
>Devo ver, com sorte,
H e apenas um H. Mas observe isso.
926
00:47:30,710 --> 00:47:34,400
>Se eu sei que s, uma string, é
tecnicamente apenas um endereço,
927
00:47:34,400 --> 00:47:35,960
>na verdade, agora posso fazer cálculos.
928
00:47:35,960 --> 00:47:39,470
>E posso imprimir outro
caractere, seguido por uma nova linha.
929
00:47:39,470 --> 00:47:44,090
>E eu posso ir para, não s,
mas que tal s mais 1.
930
00:47:44,090 --> 00:47:47,600
>Posso fazer uma operação matemática muito simples,
se assim preferir, nesse ponteiro.
931
00:47:47,600 --> 00:47:49,920
>Agora eu vou
recompilar isso.
932
00:47:49,920 --> 00:47:54,800
>Então make address, compila
OK, ./address.
933
00:47:54,800 --> 00:47:56,570
>E eu deveria ver o HI.
934
00:47:56,570 --> 00:48:01,790
>E se eu fizer mais uma linha de código como
esta, printf, % c, \ n,
935
00:48:01,790 --> 00:48:07,130
>s* + 2, agora
posso ir para o caractere
936
00:48:07,130 --> 00:48:10,770
>que está a dois bytes de
distância de qualquer s,
937
00:48:10,770 --> 00:48:12,480
>que, novamente, é o início da string.
938
00:48:12,480 --> 00:48:15,890
>Então, agora, reimprimi HI com o
ponto de exclamação,
939
00:48:15,890 --> 00:48:19,280
>caractere por caractere, mas não
usando este colchete sofisticado
940
00:48:19,280 --> 00:48:24,710
>apenas no sentido de que
era uma espécie de abstração para nós,
941
00:48:24,710 --> 00:48:25,670
>se preferir assim.
942
00:48:25,670 --> 00:48:28,885
>Em vez disso, estou manipulando s pelo que
é, que é um endereço.
943
00:48:28,885 --> 00:48:31,010
>E aqui também, e já
usei essa frase antes,
944
00:48:31,010 --> 00:48:33,710
>aquela notação de colchetes que
introduzimos na semana dois,
945
00:48:33,710 --> 00:48:36,410
>é tecnicamente apenas syntatic sugar.
946
00:48:36,410 --> 00:48:39,500
>Não está fazendo nada
fundamentalmente diferente
947
00:48:39,500 --> 00:48:42,770
>a partir desses asteriscos
e desses endereços.
948
00:48:42,770 --> 00:48:45,440
>está apenas fazendo isso, honestamente,
de uma forma muito mais amigável.
949
00:48:45,440 --> 00:48:49,160
>Eu ainda prefiro, pessoalmente, a
notação de colchetes da segunda semana.
950
00:48:49,160 --> 00:48:54,680
>Mas é a mesma coisa que usar *
e fazer as contas você mesmo.
951
00:48:54,680 --> 00:48:57,020
>Então, C está apenas nos
fornecendo esse recurso útil
952
00:48:57,020 --> 00:49:00,200
>de usar colchetes que fazem
todo esse ponteiro
953
00:49:00,200 --> 00:49:02,360
>aritmético para você.
954
00:49:02,360 --> 00:49:04,290
>Mas, novamente, vamos para
esse baixo nível apenas
955
00:49:04,290 --> 00:49:10,310
>para enfatizar o que está
acontecendo por baixo do capô aqui.
956
00:49:10,310 --> 00:49:13,070
>Tudo bem, deixe-me pausar
aqui para qualquer dúvida.
957
00:49:13,070 --> 00:49:17,290
>E Brian, por favor, sinta-se livre
para verbalizar qualquer coisa de sua parte.
958
00:49:17,290 --> 00:49:19,790
>Brian: Eu vejo uma pergunta que
surgiu sobre o que aconteceria
959
00:49:19,790 --> 00:49:22,233
>se você tentasse imprimir s* + 3.
960
00:49:22,233 --> 00:49:25,400
>David Malan: Então, tenho certeza que
isso vai imprimir o caractere nul.
961
00:49:25,400 --> 00:49:27,233
>Mas vamos em frente e
confirmar aqui,
962
00:49:27,233 --> 00:49:31,760
>%c \n s* + 3.
963
00:49:31,760 --> 00:49:35,120
>Tudo bem, estou me aventurando um pouco
964
00:49:35,120 --> 00:49:38,060
>ao olhar para as coisas que talvez não
deveria estar olhando, porque isso é
965
00:49:38,060 --> 00:49:39,545
>um detalhe de implementação de baixo nível.
966
00:49:39,545 --> 00:49:40,670
>Mas vamos ver o que acontece.
967
00:49:40,670 --> 00:49:43,130
>Ele compila ok, ./address.
968
00:49:43,130 --> 00:49:44,780
>E parece estar em branco.
969
00:49:44,780 --> 00:49:46,730
>Agora, talvez esse seja o caractere Nul.
970
00:49:46,730 --> 00:49:48,980
>Honestamente, não é para ser
um caractere imprimível.
971
00:49:48,980 --> 00:49:52,770
>É este valor sentinela especial
que indica o fim da string.
972
00:49:52,770 --> 00:49:54,020
>Mas eu poderia fazer isso.
973
00:49:54,020 --> 00:49:57,170
>Eu sei desde a segunda semana
que os chars são inteiros,
974
00:49:57,170 --> 00:49:59,670
>e inteiros são chars se eu
quiser pensar neles dessa forma.
975
00:49:59,670 --> 00:50:01,880
>Então, deixe-me mudar
apenas o último caractere
976
00:50:01,880 --> 00:50:03,950
>para usar o formato de código %i.
977
00:50:03,950 --> 00:50:05,690
>Vamos recompilar meu código.
978
00:50:05,690 --> 00:50:07,940
>Eu vou executar o endereço.
979
00:50:07,940 --> 00:50:11,540
>E pronto, HI exclamação 0.
980
00:50:11,540 --> 00:50:16,400
>E há todos os bits 0 representados aqui
como um único dígito decimal, graças a
981
00:50:16,400 --> 00:50:17,570
> % i.
982
00:50:17,570 --> 00:50:19,970
>Agora, posso ficar louco aqui.
983
00:50:19,970 --> 00:50:23,420
>E por que não vamos em frente e
imprimimos não apenas quais caracteres
984
00:50:23,420 --> 00:50:28,580
>estão logo após esta sequência, HI!,
caractere nul,
985
00:50:28,580 --> 00:50:33,770
>por que não vamos - que tal
endereçarmos a 1.000 bytes de distância,
986
00:50:33,770 --> 00:50:35,990
>e com estilo vamos para
dentro do meu computador?
987
00:50:35,990 --> 00:50:38,450
>Vamos recompilar esse ./address.
988
00:50:38,450 --> 00:50:40,460
>OK, nada acontecendo aqui.
989
00:50:40,460 --> 00:50:42,620
>Que tal cerca de 10.000 bytes de distância?
990
00:50:42,620 --> 00:50:44,270
>Eu vou make address.
991
00:50:44,270 --> 00:50:47,990
>Vamos prosseguir e executar essa
falha de segmentação. Tudo bem
992
00:50:47,990 --> 00:50:49,010
>isso não está bom.
993
00:50:49,010 --> 00:50:53,030
>E você pode estar entre os poucos
afortunados que viram esse erro antes
994
00:50:53,030 --> 00:50:54,440
>ao tocar a memória que não deveria.
995
00:50:54,440 --> 00:50:56,607
>E vamos considerar isso
deliberadamente hoje.
996
00:50:56,607 --> 00:50:59,540
>Mas uma falha de segmentação,
significa que você fez algo
997
00:50:59,540 --> 00:51:01,430
>errado em algum lugar do seu código.
998
00:51:01,430 --> 00:51:04,000
>E isso tende a significar que
você tocou um segmento de memória
999
00:51:04,000 --> 00:51:05,000
>que você não deveria ter tocado.
1000
00:51:05,000 --> 00:51:08,750
>Eu não me interesso, honestamente,
em olhar 10.000 bytes de distância
1001
00:51:08,750 --> 00:51:11,420
>da memória que sei
que pertence à string.
1002
00:51:11,420 --> 00:51:14,670
>Isso é como olhar arbitrariamente em
qualquer lugar na memória do seu computador,
1003
00:51:14,670 --> 00:51:16,890
>que provavelmente, ao que parece,
não é uma boa ideia.
1004
00:51:16,890 --> 00:51:19,000
>Mais sobre esse assunto daqui a pouco.
1005
00:51:19,000 --> 00:51:21,470
>Então, vamos considerar, agora,
algumas das implicações
1006
00:51:21,470 --> 00:51:25,130
>desses detalhes de
implementação subjacentes
1007
00:51:25,130 --> 00:51:28,580
>e considere, agora, a partir da semana passada,
porque fizemos algumas coisas do jeito
1008
00:51:28,580 --> 00:51:30,590
>que fizemos nas últimas semanas, na verdade.
1009
00:51:30,590 --> 00:51:32,360
>Então string é um char*.
1010
00:51:32,360 --> 00:51:33,860
>E vamos, agora, considerar um exemplo.
1011
00:51:33,860 --> 00:51:37,260
>Vamos diminuir o zoom na minha memória,
apenas para que eu possa incluir mais de uma vez.
1012
00:51:37,260 --> 00:51:39,620
>Vamos considerar um exemplo
onde eu poderia querer escrever
1013
00:51:39,620 --> 00:51:42,570
>um programa que compara duas strings.
1014
00:51:42,570 --> 00:51:45,830
>Vamos prosseguir e escrever um novo
código aqui em um novo arquivo desta vez,
1015
00:51:45,830 --> 00:51:48,350
>chamado, por exemplo, compare.c.
1016
00:51:48,350 --> 00:51:50,480
>Meu objetivo com este
programa, simplesmente, é
1017
00:51:50,480 --> 00:51:55,580
>ser imprimir o conteúdo
de - ou melhor, comparar
1018
00:51:55,580 --> 00:51:57,590
>duas strings que o usuário pode inserir.
1019
00:51:57,590 --> 00:52:00,040
>Vou prosseguir e
incluir cs59.h,
1020
00:52:00,040 --> 00:52:02,810
>não porque eu continue querendo a
string, digamos,
1021
00:52:02,810 --> 00:52:05,750
>mas porque eu quero usar get string
apenas por conveniência.
1022
00:52:05,750 --> 00:52:08,180
>Mas também tiraremos essa roda
de treinamento daqui a pouco.
1023
00:52:08,180 --> 00:52:10,520
>E neste programa, vou
em frente e primeiro
1024
00:52:10,520 --> 00:52:11,690
>vou usar isso,
e não get string ainda.
1025
00:52:11,690 --> 00:52:14,450
>Vamos prosseguir e manter as
coisas simples e começar com get int.
1026
00:52:14,450 --> 00:52:16,910
>E vou pedir ao usuário uma variável i.
1027
00:52:16,910 --> 00:52:19,340
>E deixe-me fazer outro desses
get int e perguntar
1028
00:52:19,340 --> 00:52:21,270
>ao usuário por um valor para j.
1029
00:52:21,270 --> 00:52:24,665
>E então agora eu vou
simplesmente dizer, se i é igual a j,
1030
00:52:24,665 --> 00:52:28,790
>então vá em frente e imprima o mesmo.
1031
00:52:28,790 --> 00:52:31,770
>Eu vou imprimir de forma diferente.
1032
00:52:31,770 --> 00:52:35,930
>Então, esta é a primeira semana, onde
estou usando algumas variáveis.
1033
00:52:35,930 --> 00:52:38,300
>Estou usando uma condição com
duas ramificações e estou
1034
00:52:38,300 --> 00:52:42,990
>usando printf para imprimir se essas
duas variáveis, i e j, são as mesmas.
1035
00:52:42,990 --> 00:52:44,930
>Então, vamos compilar isso.
1036
00:52:44,930 --> 00:52:45,950
>Tudo está bem.
1037
00:52:45,950 --> 00:52:49,310
>Execute compare e deixe-me
dar os dígitos 1 e 2.
1038
00:52:49,310 --> 00:52:50,630
>E, são diferentes.
1039
00:52:50,630 --> 00:52:53,400
>Agora eu vou dar
1 e 1, e são iguais.
1040
00:52:53,400 --> 00:52:56,270
>Então eu acho, logicamente, prova
por exemplo, se preferir,
1041
00:52:56,270 --> 00:52:57,860
>este programa parece correto.
1042
00:52:57,860 --> 00:53:02,630
>Mas deixe-me torná-lo aparentemente
incorreto, não usando números inteiros.
1043
00:53:02,630 --> 00:53:05,840
>Mas que tal usar strings em vez disso.
1044
00:53:05,840 --> 00:53:07,988
>vou continuar
e criar uma string.
1045
00:53:07,988 --> 00:53:10,280
>Embora, não, eu não precise mais
daquela roda de treinamento.
1046
00:53:10,280 --> 00:53:15,300
>Vamos fazer char* s igual a get string de s.
1047
00:53:15,300 --> 00:53:17,300
>Mas, novamente, embora
eu esteja chamando de char*,
1048
00:53:17,300 --> 00:53:19,580
>ainda é uma string como
se fosse semanas atrás.
1049
00:53:19,580 --> 00:53:23,510
>Vou criar outra string chamada t,
apenas para manter o nome curto.
1050
00:53:23,510 --> 00:53:25,100
>E vai obter -
1051
00:53:25,100 --> 00:53:26,730
>t obterá esse valor.
1052
00:53:26,730 --> 00:53:30,140
>E deixe-me apenas, muito
ingenuamente, mas razoavelmente,
1053
00:53:30,140 --> 00:53:34,310
>dizer que se s é igual a t, vamos
prosseguir e imprimir o mesmo.
1054
00:53:34,310 --> 00:53:38,000
>E caso contrário, vamos
prosseguir e imprimir diferente.
1055
00:53:38,000 --> 00:53:41,240
>Portanto, o mesmo código exato, apenas
diferentes tipos de dados, e usando
1056
00:53:41,240 --> 00:53:42,830
>get string em vez de get int.
1057
00:53:42,830 --> 00:53:47,360
>Eu vou fazer make compare,
parece compilar OK, ./compare.
1058
00:53:47,360 --> 00:53:51,770
>Vamos prosseguir e digitar HI! -
1059
00:53:51,770 --> 00:53:53,570
>woops, HI !.
1060
00:53:53,570 --> 00:53:55,220
>Vamos prosseguir e digitar HI! novamente.
1061
00:53:55,220 --> 00:53:57,500
>E voila, diferente.
1062
00:53:57,500 --> 00:54:01,010
>E esqueci minha \, mas esse
parece ser o menor dos meus problemas.
1063
00:54:01,010 --> 00:54:05,240
>Vamos recompilar isso, make compare,
e agora, deixe-me executá-lo novamente.
1064
00:54:05,240 --> 00:54:07,130
>Que tal fazer um teste rápido.
1065
00:54:07,130 --> 00:54:09,010
>David, Brian, esses são
definitivamente diferentes.
1066
00:54:09,010 --> 00:54:09,580
>Tudo bem.
1067
00:54:09,580 --> 00:54:11,240
>Portanto, o programa parece funcionar.
1068
00:54:11,240 --> 00:54:13,150
>Que tal David, David?
1069
00:54:13,150 --> 00:54:14,140
>Também diferente.
1070
00:54:14,140 --> 00:54:15,370
>Huh, deixe-me tentar novamente.
1071
00:54:15,370 --> 00:54:18,600
>Brian, Brian, também diferentes.
1072
00:54:18,600 --> 00:54:21,570
>Mas tenho certeza de que
essas strings são as mesmas.
1073
00:54:21,570 --> 00:54:24,180
>Por que este programa pode ter falhas?
1074
00:54:24,180 --> 00:54:28,582
>O que há de errado com
este programa agora?
1075
00:54:28,582 --> 00:54:30,290
>BRIAN: Algumas pessoas
no chat estão
1076
00:54:30,290 --> 00:54:32,750
>dizendo que não estamos
comparando os caracteres,
1077
00:54:32,750 --> 00:54:34,370
>estamos comparando os endereços.
1078
00:54:34,370 --> 00:54:37,377
>DAVID MALAN: Sim, essa é a
conclusão lógica de hoje
1079
00:54:37,377 --> 00:54:38,960
>na definição do que uma string é.
1080
00:54:38,960 --> 00:54:41,750
>Se uma string é o endereço
de seu primeiro caractere,
1081
00:54:41,750 --> 00:54:44,450
>então, se você estiver
literalmente fazendo s igual a t,
1082
00:54:44,450 --> 00:54:46,697
>você está comparando esses dois endereços.
1083
00:54:46,697 --> 00:54:48,530
>E provavelmente
serão diferentes,
1084
00:54:48,530 --> 00:54:50,990
>mesmo se eu digitar a mesma
coisa, porque toda vez que
1085
00:54:50,990 --> 00:54:55,010
>chamei get int ou get string, meio que
inseriu na entrada do usuário
1086
00:54:55,010 --> 00:54:56,750
>em algum lugar da memória do meu computador.
1087
00:54:56,750 --> 00:55:00,560
>Mas agora temos as ferramentas, honestamente,
para responder ou examinar esta resposta
1088
00:55:00,560 --> 00:55:01,130
>nós mesmos.
1089
00:55:01,130 --> 00:55:03,230
>Vamos simplificar
este programa.
1090
00:55:03,230 --> 00:55:06,050
>E vamos, apenas para uma rápida
verificação, imprimir s.
1091
00:55:06,050 --> 00:55:10,610
>E vamos prosseguir e imprimir
usando uma nova linha após cada,
1092
00:55:10,610 --> 00:55:12,350
>só para vermos quais são as strings.
1093
00:55:12,350 --> 00:55:16,830
>Então, agora eu vou fazer isso de novo,
make compare, compila OK, ./
1094
00:55:16,830 --> 00:55:17,330
>compare.
1095
00:55:17,330 --> 00:55:19,310
>Vamos digitar HI, HI.
1096
00:55:19,310 --> 00:55:21,710
>E eles parecem ser visualmente iguais.
1097
00:55:21,710 --> 00:55:24,770
>Mas lembre-se que, agora, eu tenho
esse outro código de formato,
1098
00:55:24,770 --> 00:55:27,080
>de modo que agora posso
começar a tratar strings
1099
00:55:27,080 --> 00:55:29,330
>como os endereços que são tecnicamente.
1100
00:55:29,330 --> 00:55:33,140
>Então, deixe-me mudar a % s
para a % p em ambos os lugares.
1101
00:55:33,140 --> 00:55:37,610
>Vamos então recompilar o programa, e agora,
execute-o novamente e compare com HI e HI
1102
00:55:37,610 --> 00:55:38,690
>digitados de forma idêntica.
1103
00:55:38,690 --> 00:55:43,100
>Mas observe, eles acabaram em locais
de memória ligeiramente diferentes.
1104
00:55:43,100 --> 00:55:46,820
>Mesmo que eu tenha coincidentemente
digitado a mesma coisa, C e meu computador
1105
00:55:46,820 --> 00:55:52,097
>não serão tão presunçosos a ponto de usar
os mesmos bytes para ambas as strings.
1106
00:55:52,097 --> 00:55:53,930
>Isso não vai me dar
muita flexibilidade
1107
00:55:53,930 --> 00:55:55,490
>se eu quiser mudar um ou outro.
1108
00:55:55,490 --> 00:55:58,490
>Isso vai colocar, de forma muito
simplista, incluir um pedaço neste pedaço de memória
1109
00:55:58,490 --> 00:56:00,240
>e o outro neste pedaço de memória.
1110
00:56:00,240 --> 00:56:03,680
>E, esses endereços são
respectivamente, mas arbitrariamente,
1111
00:56:03,680 --> 00:56:07,220
>0x22fe670 e 0x22fe6b0.
1112
00:56:09,770 --> 00:56:12,500
>Portanto, estão separados a alguma distância.
1113
00:56:12,500 --> 00:56:15,810
>Mas, novamente, cabe ao computador
decidir onde colocá-los.
1114
00:56:15,810 --> 00:56:18,310
>Então, o que está acontecendo
dentro da memória do computador?
1115
00:56:18,310 --> 00:56:22,010
>Bem, vamos considerar se, por exemplo,
este é s, meu ponteiro, ou ,
1116
00:56:22,010 --> 00:56:22,640
>minha string.
1117
00:56:22,640 --> 00:56:23,810
>Mas agora é um ponteiro.
1118
00:56:23,810 --> 00:56:25,060
>É o endereço de algo.
1119
00:56:25,060 --> 00:56:28,250
>Observe que eu o desenhei
como ocupando oito quadrados,
1120
00:56:28,250 --> 00:56:31,680
>porque, novamente, um ponteiro em
sistemas modernos tem oito bytes.
1121
00:56:31,680 --> 00:56:33,320
>É por isso que essa coisa é tão grande.
1122
00:56:33,320 --> 00:56:37,100
>Enquanto isso, quando eu digito algo
como HI!,
1123
00:56:37,100 --> 00:56:38,720
>então acaba em algum lugar na memória.
1124
00:56:38,720 --> 00:56:40,440
>Nós não sabemos ou não
nos importamos onde está.
1125
00:56:40,440 --> 00:56:42,773
>Então, vamos simplesmente dizer
que acaba ficando ali
1126
00:56:42,773 --> 00:56:43,850
>na memória do meu computador.
1127
00:56:43,850 --> 00:56:46,730
>Agora, cada um desses bytes,
claro, tem um endereço.
1128
00:56:46,730 --> 00:56:48,950
>Eu não necessariamente sei ou
me importo com o que são.
1129
00:56:48,950 --> 00:56:52,040
>Mas para fins de explicação, vamos
numerá-los novamente como antes,
1130
00:56:52,040 --> 00:56:56,810
>0x123, 0x124, 0x125, 0x126.
1131
00:56:56,810 --> 00:57:02,960
>Quando eu atribuo s à esquerda o
valor de get string à direita,
1132
00:57:02,960 --> 00:57:04,670
>get string, o que vai fazer?
1133
00:57:04,670 --> 00:57:07,640
>Bem, todo esse tempo desde a primeira
semana, desde que você o tem usado,
1134
00:57:07,640 --> 00:57:11,970
>obtém uma string e devolve
a você como um valor de retorno.
1135
00:57:11,970 --> 00:57:13,680
>Mas o que isso significa?
1136
00:57:13,680 --> 00:57:18,200
>Bem, se uma string é um endereço,
o valor de retorno de uma função
1137
00:57:18,200 --> 00:57:23,030
>como get string é para retornar,
não a string em si, porque isso é
1138
00:57:23,030 --> 00:57:24,740
>um tipo de conceito de alto nível.
1139
00:57:24,740 --> 00:57:27,050
>O que get string
sempre fez por nós
1140
00:57:27,050 --> 00:57:29,810
>é retornar o endereço
da string, ou mais
1141
00:57:29,810 --> 00:57:33,410
>especificamente, o endereço do
primeiro caractere na string.
1142
00:57:33,410 --> 00:57:39,740
>E então o que é tecnicamente armazenado em s,
para ser claro, é esse endereço, 0x123.
1143
00:57:39,740 --> 00:57:43,400
>Não está retornando a string inteira,
o H, o I, o ponto de exclamação.
1144
00:57:43,400 --> 00:57:46,040
>Em vez disso, está retornando
apenas um valor para você.
1145
00:57:46,040 --> 00:57:50,990
>está retornando apenas para você o
endereço do primeiro caractere daquela string.
1146
00:57:50,990 --> 00:57:54,500
>Mas, novamente, tudo isso é
muito bom para apenas s.
1147
00:57:54,500 --> 00:57:55,880
>O que está acontecendo com t?
1148
00:57:55,880 --> 00:57:58,910
>t é mais ou menos a mesma história, porque
estou chamando get string novamente.
1149
00:57:58,910 --> 00:58:02,390
>t vai ser atribuído ao endereço
do primeiro caractere
1150
00:58:02,390 --> 00:58:03,500
>desta versão do HI.
1151
00:58:03,500 --> 00:58:13,160
>E vamos apenas dizer que está
em 0x456, 0x457, 0x458 e 0x459.
1152
00:58:13,160 --> 00:58:16,873
>E neste ponto, t vai
assumir o valor de 0x456.
1153
00:58:16,873 --> 00:58:19,790
>E agora, neste ponto, honestamente,
estamos entrando nas minúcias.
1154
00:58:19,790 --> 00:58:21,665
>Vamos começar
a abstrair tudo isso
1155
00:58:21,665 --> 00:58:23,870
>e usar setas para apontar para os valores.
1156
00:58:23,870 --> 00:58:26,720
>E, essas setas
representam apenas ponteiros
1157
00:58:26,720 --> 00:58:29,190
>quando paramos de nos preocupar
com os endereços específicos.
1158
00:58:29,190 --> 00:58:32,300
>Então s é um
ponteiro, uma variável que aponta
1159
00:58:32,300 --> 00:58:34,070
>no primeiro caractere de HI aqui.
1160
00:58:34,070 --> 00:58:38,490
>t é uma variável apontando
para o primeiro caractere de HI ali.
1161
00:58:38,490 --> 00:58:41,540
>E então, quando você está
comparando duas strings
1162
00:58:41,540 --> 00:58:45,440
>como eu estava antes na versão
anterior do meu programa,
1163
00:58:45,440 --> 00:58:53,540
>onde eu estava verificando se s é igual a t,
eu estava, comparando s e t.
1164
00:58:53,540 --> 00:58:55,130
>O que são s e t?
1165
00:58:55,130 --> 00:59:01,640
>s e t, respectivamente,
são 0x123 e 0x456,
1166
00:59:01,640 --> 00:59:03,770
>ou quaisquer que sejam
os valores reais,
1167
00:59:03,770 --> 00:59:06,320
>que não vão ser os
mesmos porque acabam por
1168
00:59:06,320 --> 00:59:09,920
>apontar para diferentes blocos de memória.
1169
00:59:09,920 --> 00:59:12,110
>Tudo bem, quem se importa?
1170
00:59:12,110 --> 00:59:14,630
>Isso tudo é um bom
exercício intelectual.
1171
00:59:14,630 --> 00:59:15,512
>Mas quem se importa?
1172
00:59:15,512 --> 00:59:16,970
>Bem, como podemos resolver este problema?
1173
00:59:16,970 --> 00:59:20,480
>Vamos considerar o que eu
fiz em uma demonstração anterior.
1174
00:59:20,480 --> 00:59:23,955
>Eu meio que mencionei preventivamente que
existe esta função, comparação de strings,
1175
00:59:23,955 --> 00:59:25,580
>que permite que você compare duas strings.
1176
00:59:25,580 --> 00:59:28,040
>E eu prometi que
explicaríamos
1177
00:59:28,040 --> 00:59:31,573
>porque usamos str compare ao invés de
apenas usar o sinal de igual igual.
1178
00:59:31,573 --> 00:59:33,740
>Bem, para usar esta função,
vou precisar adicionar
1179
00:59:33,740 --> 00:59:37,910
>string.h até aqui pela última vez.
1180
00:59:37,910 --> 00:59:40,790
>Mas se string compare s t,
vou recompilar isso,
1181
00:59:40,790 --> 00:59:43,160
>compare ./compare
1182
00:59:43,160 --> 00:59:45,710
>Agora, deixe-me digitar HI!
e HI! identicamente.
1183
00:59:45,710 --> 00:59:47,870
>Agora, eles ainda parecem ser diferentes.
1184
00:59:47,870 --> 00:59:51,680
>E caramba, cometi o mesmo
erro estúpido da última vez.
1185
00:59:51,680 --> 00:59:57,170
>Alguém sabe que erro cometi
ao comparar duas strings?
1186
00:59:57,170 --> 01:00:00,590
>De alguma forma, pareço ser
muito bom em cometer esse erro.
1187
01:00:00,590 --> 01:00:03,440
>BRIAN: Ibrahim está sugerindo que
você adicione um igual igual a zero.
1188
01:00:03,440 --> 01:00:04,398
>DAVID MALAN: Obrigado.
1189
01:00:04,398 --> 01:00:05,390
>Ibrahim está certo.
1190
01:00:05,390 --> 01:00:08,000
>O valor de retorno,
lembrem, de str compare,
1191
01:00:08,000 --> 01:00:13,040
>é retornar 0 se forem iguais,
um número negativo se um vier
1192
01:00:13,040 --> 01:00:16,430
>antes do outro, e um número positivo
se um vier depois do outro,
1193
01:00:16,430 --> 01:00:18,600
>como na ordem ASCIIbética.
1194
01:00:18,600 --> 01:00:21,440
>Então o que eu deveria ter feito,
da última vez e desta vez,
1195
01:00:21,440 --> 01:00:23,600
>a verificação de igualdade com 0.
1196
01:00:23,600 --> 01:00:26,220
>Eu vou
recompilar este programa.
1197
01:00:26,220 --> 01:00:27,050
>Tudo bem.
1198
01:00:27,050 --> 01:00:29,090
>Agora, deixe-me executar novamente este programa com o HI!
1199
01:00:29,090 --> 01:00:30,230
>duas vezes.
1200
01:00:30,230 --> 01:00:31,940
>Voila, são iguais.
1201
01:00:31,940 --> 01:00:34,580
>E só para ter certeza,
deixe-me fazer outra verificação.
1202
01:00:34,580 --> 01:00:38,810
>Vou fazer David e Brian, o
que deve ser, diferente.
1203
01:00:38,810 --> 01:00:42,050
>Então agora, novamente, eu
não fiz nada diferente da última vez.
1204
01:00:42,050 --> 01:00:47,420
>Mas agora estou pensando nessas strings
como sendo fundamentalmente apenas
1205
01:00:47,420 --> 01:00:48,173
>seus endereços.
1206
01:00:48,173 --> 01:00:50,090
>E então, agora, vamos tornar
isso pertinente.
1207
01:00:50,090 --> 01:00:52,160
>Vamos prosseguir e
criar um novo arquivo.
1208
01:00:52,160 --> 01:00:56,590
>E vamos, razoavelmente, tentar copiar
uma string e fazer alterações nela.
1209
01:00:56,590 --> 01:00:57,840
>Então, vou prosseguir aqui.
1210
01:00:57,840 --> 01:01:00,230
>E apenas por conveniência, ainda
vou usar a biblioteca CS50,
1211
01:01:00,230 --> 01:01:02,300
>não para o tipo de dados
string, mas apenas para o
1212
01:01:02,300 --> 01:01:06,200
>get string function, que veremos é
mais útil do que outras coisas -
1213
01:01:06,200 --> 01:01:07,790
>do que outras maneiras de fazer as coisas.
1214
01:01:07,790 --> 01:01:11,630
>E vou prosseguir e incluir
include standard io ponto h.
1215
01:01:11,630 --> 01:01:17,450
>E vou prosseguir e incluir,
que tal, string.h.
1216
01:01:17,450 --> 01:01:20,000
>Eu vou fazer
int main void.
1217
01:01:20,000 --> 01:01:22,790
>E deixe-me ir em frente, neste programa,
e criar uma string.
1218
01:01:22,790 --> 01:01:24,540
>Mas observe, não vamos
chamar mais de string.
1219
01:01:24,540 --> 01:01:26,030
>Vamos chamar de char*.
1220
01:01:26,030 --> 01:01:28,380
>Então, novamente, comece a
tirar a roda de treinamento.
1221
01:01:28,380 --> 01:01:31,312
>E vou prosseguir e obter
uma string chamada s.
1222
01:01:31,312 --> 01:01:33,020
>E então vou pegar
outra string.
1223
01:01:33,020 --> 01:01:34,062
>Mas não vou chamar assim.
1224
01:01:34,062 --> 01:01:36,230
>Vou chamar de char* t.
1225
01:01:36,230 --> 01:01:37,400
>E eu quero copiar s.
1226
01:01:37,400 --> 01:01:40,790
>E então você pode pensar, com base na semana
um, semana dois, e desde então, que OK,
1227
01:01:40,790 --> 01:01:42,890
>se você quiser copiar uma
variável, basta fazê-lo.
1228
01:01:42,890 --> 01:01:44,690
>Quer dizer, usamos o
operador de atribuição
1229
01:01:44,690 --> 01:01:48,530
>para copiar uma variável da direita para
a esquerda para inteiros, para chars,
1230
01:01:48,530 --> 01:01:50,600
>e para outros tipos de dados, talvez também.
1231
01:01:50,600 --> 01:01:54,690
>Vou prosseguir, agora, e fazer uma
alteração na string original.
1232
01:01:54,690 --> 01:01:56,270
>Então, agora eu vou fazer isso.
1233
01:01:56,270 --> 01:02:01,280
>Vamos continuar e dizer, vamos
mudar o primeiro caractere de t
1234
01:02:01,280 --> 01:02:02,780
>em maiúsculas.
1235
01:02:02,780 --> 01:02:04,940
>Lembre-se de que existe
esta função, to upper,
1236
01:02:04,940 --> 01:02:09,170
>que leva, como entrada, um caractere,
como o primeiro caractere em t,
1237
01:02:09,170 --> 01:02:11,120
>e retorna a versão em maiúsculas.
1238
01:02:11,120 --> 01:02:14,240
>Agora, para usar o to upper, preciso
de outro arquivo de cabeçalho,
1239
01:02:14,240 --> 01:02:17,990
>que pelo que me lembro, de algumas
semanas atrás, é o ctype.h.
1240
01:02:17,990 --> 01:02:20,750
>Então, volto
e coloco isso lá.
1241
01:02:20,750 --> 01:02:23,280
>E agora, deixe-me ir em frente
e imprimir essas duas strings.
1242
01:02:23,280 --> 01:02:27,500
>Eu vou imprimir
s como sendo % s.
1243
01:02:27,500 --> 01:02:33,990
>Agora eu vou imprimir o
valor de t com % s como segue.
1244
01:02:33,990 --> 01:02:36,680
>Então, novamente, o que estou fazendo
é recebendo uma string do usuário.
1245
01:02:36,680 --> 01:02:40,490
>E a única coisa nova aqui é char
asterisco hoje, que é sinônimo de string.
1246
01:02:40,490 --> 01:02:44,270
>Na linha 10 aqui, estou copiando a
string da direita para a esquerda.
1247
01:02:44,270 --> 01:02:47,330
>E então estou colocando em
maiúscula apenas a primeira letra
1248
01:02:47,330 --> 01:02:49,640
>na cópia, também conhecida como t.
1249
01:02:49,640 --> 01:02:51,140
>E então estou imprimindo ambas.
1250
01:02:51,140 --> 01:02:54,290
>Então agora eu vou
fazer uma cópia, compila OK.
1251
01:02:54,290 --> 01:02:56,510
>Faça copy-- cópia ponto-barra.
1252
01:02:56,510 --> 01:03:00,020
>Vamos prosseguir e digitar hi!
em minúsculas, todas em minúsculas,
1253
01:03:00,020 --> 01:03:00,920
>e, em seguida, entre.
1254
01:03:00,920 --> 01:03:03,830
>E voila.
1255
01:03:03,830 --> 01:03:10,760
>Parece que de alguma forma eu coloquei
S e T em maiúscula, embora eu apenas
1256
01:03:10,760 --> 01:03:17,080
>chamado to upper em T.
Brian, alguma ideia
1257
01:03:17,080 --> 01:03:24,820
>do grupo sobre por que eu acidentalmente
e erroneamente converti em maiúscula
1258
01:03:24,820 --> 01:03:26,260
>ambas, de alguma forma?
1259
01:03:26,260 --> 01:03:29,735
>BRIAN: Algumas pessoas estão dizendo
que t é um pseudônimo de s.
1260
01:03:29,735 --> 01:03:32,860
>DAVID MALAN: Apenas um pseudônimo de s, essa
é uma maneira razoável de pensar nisso,
1261
01:03:32,860 --> 01:03:33,360
>certo.
1262
01:03:33,360 --> 01:03:38,320
>E, mais precisamente, algum outro pensamento sobre
por que isso está incorreto de alguma forma?
1263
01:03:38,320 --> 01:03:41,540
>BRIAN: Peter agora está sugerindo
que tenham o mesmo endereço.
1264
01:03:41,540 --> 01:03:45,880
>DAVID MALAN: Sim, mais especificamente,
tudo o que fiz foi copiar s para t.
1265
01:03:45,880 --> 01:03:48,040
>Mas, de novo, o que é "s" hoje?
1266
01:03:48,040 --> 01:03:49,390
>É apenas um endereço.
1267
01:03:49,390 --> 01:03:51,040
>Então, sim, copiei o s.
1268
01:03:51,040 --> 01:03:54,820
>Mas eu copiei o que
significa copiar seu endereço, 0x123,
1269
01:03:54,820 --> 01:03:55,820
>ou seja o que for.
1270
01:03:55,820 --> 01:04:01,180
>E então na linha 12, observe que
estou mudando t colocando-o em letras maiúsculas.
1271
01:04:01,180 --> 01:04:04,130
>Mas t está no mesmo endereço de s.
1272
01:04:04,130 --> 01:04:08,130
>Então, estou
mudando um na mesma string.
1273
01:04:08,130 --> 01:04:10,630
>Então, se pensarmos nisso em
termos de memória do computador,
1274
01:04:10,630 --> 01:04:12,088
>vamos considerar o que acabei de fazer.
1275
01:04:12,088 --> 01:04:13,570
>Vamos limpar a memória do computador.
1276
01:04:13,570 --> 01:04:15,290
>Vamos tratar o "s", como fizemos antes.
1277
01:04:15,290 --> 01:04:18,250
>Deixa eu colocar hi! para baixo como antes,
mas todas em minúsculas desta vez.
1278
01:04:18,250 --> 01:04:23,320
>E lembre-se de que podem ser os
endereços 0x123, 124, 125 e 126.
1279
01:04:23,320 --> 01:04:26,350
>E agora, se considerarmos
que tecnicamente
1280
01:04:26,350 --> 01:04:29,740
>contém o endereço do
primeiro caractere, 0x123,
1281
01:04:29,740 --> 01:04:34,960
>e eu continuo criando uma nova variável,
t, e atribuo t o valor de s,
1282
01:04:34,960 --> 01:04:36,970
>eu tenho que interpretar essa afirmação literalmente.
1283
01:04:36,970 --> 01:04:39,670
>Estou literalmente colocando 0x123 aqui.
1284
01:04:39,670 --> 01:04:41,770
>E se agora abstrairmos
esses detalhes apenas
1285
01:04:41,770 --> 01:04:44,020
>para deixar mais claro visualmente
o que está acontecendo,
1286
01:04:44,020 --> 01:04:48,070
>isso é quase como dizer
que ambos os pontos s e t
1287
01:04:48,070 --> 01:04:49,750
>estão no mesmo local na memória.
1288
01:04:49,750 --> 01:04:52,297
>Então, sim, nesse sentido, t
é um apelido para s,
1289
01:04:52,297 --> 01:04:54,130
>que é uma maneira razoável
de pensar nisso.
1290
01:04:54,130 --> 01:04:56,920
>Mas, na verdade, t é idêntico a s.
1291
01:04:56,920 --> 01:04:59,110
>Então, quando você usa
a notação de colchetes
1292
01:04:59,110 --> 01:05:02,290
>para ir para o primeiro caractere
de t, você está, equivalentemente,
1293
01:05:02,290 --> 01:05:04,750
>indo para o primeiro caractere em s.
1294
01:05:04,750 --> 01:05:06,200
>São o mesmo.
1295
01:05:06,200 --> 01:05:10,390
>Então, quando eu chamo to upper, estou
chamando esse caractere, que é claro, é
1296
01:05:10,390 --> 01:05:12,970
>o único h na história.
1297
01:05:12,970 --> 01:05:16,240
>E quando eu print s e
print t, printf é
1298
01:05:16,240 --> 01:05:18,610
>seguindo essas mesmas migalhas
de pão, se preferir,
1299
01:05:18,610 --> 01:05:24,070
>e, finalmente, exibindo o mesmo
valor como tendo sido alterado.
1300
01:05:24,070 --> 01:05:27,220
>Portanto, parece que precisamos
repensar fundamentalmente
1301
01:05:27,220 --> 01:05:28,990
>como estamos copiando strings.
1302
01:05:28,990 --> 01:05:34,300
>E deixe-me perguntar, se esta é a maneira
errada de copiar uma string na outra, qual
1303
01:05:34,300 --> 01:05:35,350
>é o caminho certo?
1304
01:05:35,350 --> 01:05:39,340
>Mesmo que você não tenha as funções
em mente ou o vocabulário certo,
1305
01:05:39,340 --> 01:05:43,750
>apenas intuitivamente, se quisermos copiar
uma string da maneira que um humano faria
1306
01:05:43,750 --> 01:05:50,020
>pense em copiar uma no outra,
como uma fotografia ou fotocópia,
1307
01:05:50,020 --> 01:05:52,610
>como podemos fazer isso?
1308
01:05:52,610 --> 01:05:54,460
>Alguma ideia, Brian?
1309
01:05:54,460 --> 01:05:57,430
>BRIAN: Sim, Sofia sugeriu fazer
um loop de alguma forma
1310
01:05:57,430 --> 01:05:59,948
>com elementos em s e colocá-los em t.
1311
01:05:59,948 --> 01:06:01,240
>DAVID MALAN: Sim, gosto disso.
1312
01:06:01,240 --> 01:06:04,120
>Então, faça um loop sobre os
elementos de s e coloque-os em t.
1313
01:06:04,120 --> 01:06:05,800
>Portanto, parece mais trabalho.
1314
01:06:05,800 --> 01:06:07,660
>Mas isso é, novamente,
o que vamos ter
1315
01:06:07,660 --> 01:06:09,582
>que fazer se quisermos pensar nisso -
1316
01:06:09,582 --> 01:06:12,790
>se quisermos aceitar o fato de que essas
coisas, s e t, são apenas endereços,
1317
01:06:12,790 --> 01:06:15,550
>agora vamos ter que seguir
essas migalhas de pão.
1318
01:06:15,550 --> 01:06:18,790
>Portanto, vamos prosseguir e considerar
uma variante deste programa.
1319
01:06:18,790 --> 01:06:24,520
>Vou continuar aqui e mudar isso para
que eu ainda esteja recebendo uma string s.
1320
01:06:24,520 --> 01:06:28,390
>Mas agora, deixe-me ir em frente
e propor exatamente isso,
1321
01:06:28,390 --> 01:06:30,340
>que copiemos os caracteres individuais.
1322
01:06:30,340 --> 01:06:32,320
>Mas preciso copiá-los em algum lugar.
1323
01:06:32,320 --> 01:06:35,200
>Então, eu sinto como se mais uma
etapa neste processo de copiar uma string
1324
01:06:35,200 --> 01:06:37,750
>precisa me retornar
alguma memória adicional.
1325
01:06:37,750 --> 01:06:40,840
>Se eu tiver Hi!
em caráter nulo,
1326
01:06:40,840 --> 01:06:43,150
>eu preciso, agora, de alguma forma,
assumir o controle desta situação
1327
01:06:43,150 --> 01:06:48,320
>e dizer ao computador, de alguma forma, em
código, me dê mais quatro bytes de memória
1328
01:06:48,320 --> 01:06:53,390
>para que eu tenha um local para t
no qual copiar esses caracteres.
1329
01:06:53,390 --> 01:06:55,360
>Então, aqui está uma nova função hoje.
1330
01:06:55,360 --> 01:06:59,470
>Se eu quiser criar uma string t,
também conhecido hoje como char*,
1331
01:06:59,470 --> 01:07:02,680
>há uma nova função que podemos
usar chamada malloc, que
1332
01:07:02,680 --> 01:07:04,720
>representa a alocação de memória.
1333
01:07:04,720 --> 01:07:08,200
>Esta é uma função muito sofisticada que,
felizmente, é muito simples de usar.
1334
01:07:08,200 --> 01:07:10,390
>Leva, como entrada, apenas um número.
1335
01:07:10,390 --> 01:07:14,480
>Quantos bytes de memória você
deseja solicitar ao computador?
1336
01:07:14,480 --> 01:07:16,000
>Então, como faço isso?
1337
01:07:16,000 --> 01:07:20,110
>Bem, HI! .\0,
eu poderia literalmente dizer apenas quatro.
1338
01:07:20,110 --> 01:07:21,850
>Mas isso não parece muito dinâmico.
1339
01:07:21,850 --> 01:07:26,410
>Acho que posso implementar isso programaticamente
com um pouco mais de elegância.
1340
01:07:26,410 --> 01:07:30,370
>Eu vou dizer,
me dê tantos bytes
1341
01:07:30,370 --> 01:07:35,200
>quanto houver de caracteres em s mais 1.
1342
01:07:35,200 --> 01:07:37,090
>Mais 1, por que estou fazendo isso?
1343
01:07:37,090 --> 01:07:40,773
>Bem, HI! nul é, tecnicamente
1344
01:07:40,773 --> 01:07:42,190
>o que está armazenado embaixo do capô.
1345
01:07:42,190 --> 01:07:45,250
>Mas, qual é a duração do Hi! ?
1346
01:07:45,250 --> 01:07:48,070
>Bem, as probabilidades são, no mundo
humano, é HI!.
1347
01:07:48,070 --> 01:07:50,710
>E quem se importa com esse detalhe
de baixo nível, esse terminador nul.
1348
01:07:50,710 --> 01:07:53,800
>Você não inclui isso no comprimento de uma
palavra em inglês ou de qualquer palavra.
1349
01:07:53,800 --> 01:07:56,290
>Você só pensa nos caracteres
reais que pode ver.
1350
01:07:56,290 --> 01:08:00,580
>Portanto, o comprimento de H, i,
ponto de exclamação, é 3.
1351
01:08:00,580 --> 01:08:08,110
>Mas eu preciso habilmente adicionar mais um bite,
um quarto, para o caractere nulo,
1352
01:08:08,110 --> 01:08:10,580
>porque terei que
copiá-lo também.
1353
01:08:10,580 --> 01:08:13,270
>Caso contrário, se eu não tiver
um caractere nul idêntico,
1354
01:08:13,270 --> 01:08:15,830
>não vai ter um
final óbvio.
1355
01:08:15,830 --> 01:08:17,872
>Então, como faço para copiar, agora,
uma string na outra?
1356
01:08:17,872 --> 01:08:20,538
>Bem, agora eu vou recorrer ao
nosso velho amigo, o loop for,
1357
01:08:20,538 --> 01:08:21,380
>da primeira semana.
1358
01:08:21,380 --> 01:08:24,050
>E digamos, for i = 0 -
1359
01:08:24,050 --> 01:08:26,810
>que tal, na verdade, n é igual
ao comprimento da string de s.
1360
01:08:26,810 --> 01:08:28,279
>Já fizemos esse truque antes.
1361
01:08:28,279 --> 01:08:33,080
>i é menor que n, i ++.
1362
01:08:33,080 --> 01:08:38,689
>Eu vou, simplesmente,
dizer t [i] gets s[i].
1363
01:08:38,689 --> 01:08:43,939
>Então, isso irá copiar de s,
cada um dos caracteres, um de cada vez
1364
01:08:43,939 --> 01:08:45,020
>em t.
1365
01:08:45,020 --> 01:08:46,640
>Mas preciso ser um pouco mais esperto agora.
1366
01:08:46,640 --> 01:08:49,130
>Embora quase sempre
façamos i<n,
1367
01:08:49,130 --> 01:08:55,660
>na verdade, vou dizer de forma muito
agressiva i <= n.
1368
01:08:55,660 --> 01:08:56,830
>Por quê?
1369
01:08:56,830 --> 01:09:00,250
>Por que vou um passo além
do que normalmente considero
1370
01:09:00,250 --> 01:09:03,310
>fazer ao iterar sobre strings,
e um passo além do que você
1371
01:09:03,310 --> 01:09:07,149
>provavelmente faria ao iterar sobre
uma cifra de césar ou uma string
1372
01:09:07,149 --> 01:09:09,130
>nesse contexto?
1373
01:09:09,130 --> 01:09:10,939
>Brian, alguma ideia aqui?
1374
01:09:10,939 --> 01:09:16,569
>Por que vou de i menor ou igual
a n, mais ou menos pela primeira vez aqui?
1375
01:09:16,569 --> 01:09:19,779
>BRIAN: Celina está sugerindo que
precisamos incluir o caractere nul.
1376
01:09:19,779 --> 01:09:22,843
>DAVID MALAN: Sim, então se eu-- e agora
eu entendo como as strings funcionam.
1377
01:09:22,843 --> 01:09:25,510
>Portanto, não é suficiente apenas
copiar H,I,!
1378
01:09:25,510 --> 01:09:29,020
>Preciso dar um passo adiante, mais
um do que o comprimento da string.
1379
01:09:29,020 --> 01:09:32,290
>E a maneira mais fácil de fazer
isso seria menor ou igual a n.
1380
01:09:32,290 --> 01:09:34,450
>Ou eu poderia simplesmente fazer um +1 ali.
1381
01:09:34,450 --> 01:09:35,950
>Ou posso fazer isso de várias maneiras.
1382
01:09:35,950 --> 01:09:37,399
>Não importa como você faz isso.
1383
01:09:37,399 --> 01:09:40,899
>Mas acho que menor ou igual a é uma
maneira razoável de fazer isso.
1384
01:09:40,899 --> 01:09:43,540
>E agora, vamos descer ao
fundo aqui e agora
1385
01:09:43,540 --> 01:09:44,590
>faço esta conversão em maiúscula.
1386
01:09:44,590 --> 01:09:47,710
>Vamos agora mudar o
primeiro caractere em t
1387
01:09:47,710 --> 01:09:52,750
>para ser o resultado de to upper
do primeiro caractere de t.
1388
01:09:52,750 --> 01:09:56,770
>E então, como antes, vamos
imprimir o que quer que seja.
1389
01:09:56,770 --> 01:09:59,080
>E como antes, vamos
prosseguir e imprimir
1390
01:09:59,080 --> 01:10:05,110
>seja o que t for e espero que agora
t tenha sido convertido em maiúscula.
1391
01:10:05,110 --> 01:10:07,330
>Mas preciso fazer uma mudança agora.
1392
01:10:07,330 --> 01:10:10,690
>Acontece que esta
função, malloc, vem
1393
01:10:10,690 --> 01:10:12,897
>em um arquivo denominado lib ponto h, padrão.
1394
01:10:12,897 --> 01:10:15,730
>E, novamente, esse é o tipo de
coisa que você pode anotar.
1395
01:10:15,730 --> 01:10:17,563
>Você sempre pode pesquisar
esse tipo de coisa no Google.
1396
01:10:17,563 --> 01:10:20,740
>Até eu esqueço em quais arquivos de cabeçalho
essas funções às vezes são declaradas.
1397
01:10:20,740 --> 01:10:24,310
>Mas acontece de ser um novo chamado
lib padrão para biblioteca
1398
01:10:24,310 --> 01:10:26,110
>que dá acesso ao malloc.
1399
01:10:26,110 --> 01:10:29,800
>Então deixe-me ir em frente,
agora, fazer make compare.
1400
01:10:29,800 --> 01:10:31,210
>Tudo bem, até agora tudo bem.
1401
01:10:31,210 --> 01:10:34,360
>./compare - desculpe,
isso não é compare.
1402
01:10:34,360 --> 01:10:35,680
>O programa antigo funciona bem.
1403
01:10:35,680 --> 01:10:38,630
>Make copy - oh meu Deus, sete erros.
1404
01:10:38,630 --> 01:10:40,460
>O que eu fiz de errado aqui?
1405
01:10:40,460 --> 01:10:44,560
>Oh, parece que esqueci
o tipo de i e n.
1406
01:10:44,560 --> 01:10:47,440
>Então, deixe-me entrar em meu
loop for e adicionar o int.
1407
01:10:47,440 --> 01:10:49,870
>Isso foi minha culpa.
Vamos fazer uma cópia novamente.
1408
01:10:49,870 --> 01:10:51,910
>OK, todos os sete erros,
felizmente, sumiram.
1409
01:10:51,910 --> 01:10:56,710
>Make copy, vamos digitar hi!
em minúsculas e pressionar Enter.
1410
01:10:56,710 --> 01:11:02,860
>E pronto, agora coloquei em maiúscula
apenas a cópia de s, também conhecida como
1411
01:11:02,860 --> 01:11:03,580
>t.
1412
01:11:03,580 --> 01:11:06,010
>E só para ficar claro, eu
meio que regredi de volta
1413
01:11:06,010 --> 01:11:09,140
>à minha notação de colchetes, honestamente,
porque é perfeitamente aceitável.
1414
01:11:09,140 --> 01:11:10,360
>É muito legível.
1415
01:11:10,360 --> 01:11:12,640
>Mas observe, se eu
quero me exibir,
1416
01:11:12,640 --> 01:11:19,190
>eu poderia dizer algo como,
bem, vá para o local de t + i.
1417
01:11:19,190 --> 01:11:23,078
>E então faça isso, o que, novamente, não
necessariamente recomendo, para facilitar a leitura.
1418
01:11:23,078 --> 01:11:24,620
>Mas, novamente, existe essa equivalência.
1419
01:11:24,620 --> 01:11:28,640
>A notação de colchetes é a mesma
coisa que a operação matemática de ponteiro.
1420
01:11:28,640 --> 01:11:34,160
>Então, se você quiser ir para o endereço
em t mais o que for i para se compensar
1421
01:11:34,160 --> 01:11:36,570
>um ou mais bytes, você pode
fazer isso sem problemas.
1422
01:11:36,570 --> 01:11:39,920
>E se eu quiser ser sofisticado,
eu posso descer aqui e dizer,
1423
01:11:39,920 --> 01:11:45,350
>vá para o primeiro caractere
em t e coloque-o em maiúscula.
1424
01:11:45,350 --> 01:11:48,170
>Mas, novamente, eu diria que, embora,
sim, você seja muito inteligente
1425
01:11:48,170 --> 01:11:50,420
>e que você entende as dicas
e endereços neste momento
1426
01:11:50,420 --> 01:11:51,795
>se você estiver escrevendo um código assim.
1427
01:11:51,795 --> 01:11:53,990
>Honestamente, não é
necessariamente legível.
1428
01:11:53,990 --> 01:11:57,800
>Então, continuando com a sintaxe da semana
dois da notação de colchetes, totalmente
1429
01:11:57,800 --> 01:12:03,110
>razoável, totalmente correto, totalmente
bem projetado e talvez preferível,
1430
01:12:03,110 --> 01:12:04,890
>embora eu deva ter cuidado aqui.
1431
01:12:04,890 --> 01:12:07,550
>Esta linha de código é um
pouco arriscada para mim
1432
01:12:07,550 --> 01:12:10,310
>porque e se o usuário apenas
clicar em Enter e não digitar hi
1433
01:12:10,310 --> 01:12:11,540
>ou David ou Brian.
1434
01:12:11,540 --> 01:12:13,580
>E se não digitarem nada, exceto Enter?
1435
01:12:13,580 --> 01:12:16,130
>Nesse caso, o comprimento
da string pode ser 0.
1436
01:12:16,130 --> 01:12:19,220
>E então eu provavelmente não deveria
colocar o primeiro caractere em maiúscula
1437
01:12:19,220 --> 01:12:22,230
>em uma string que
nem existe.
1438
01:12:22,230 --> 01:12:25,250
>Então, provavelmente devo ter
alguma verificação de erros,
1439
01:12:25,250 --> 01:12:32,450
>como se, por exemplo, o comprimento da
string de t for pelo menos maior que 0,
1440
01:12:32,450 --> 01:12:34,960
>então vá em frente e faça isso com segurança.
1441
01:12:34,960 --> 01:12:37,550
>Mas, novamente, este é um
exemplo de algum erro adicional
1442
01:12:37,550 --> 01:12:39,200
>verificando se posso adicionar ao programa.
1443
01:12:39,200 --> 01:12:41,300
>Na verdade, há mais uma
verificação de erro
1444
01:12:41,300 --> 01:12:43,520
>que eu deveria fazer em
um programa totalmente correto,
1445
01:12:43,520 --> 01:12:45,170
>como você deve fazer em conjuntos de problemas.
1446
01:12:45,170 --> 01:12:47,010
>Às vezes, as coisas podem dar errado.
1447
01:12:47,010 --> 01:12:50,270
>E se o seu programa for tão grande,
tão extravagante, e tão faminto por memória
1448
01:12:50,270 --> 01:12:52,187
>que você está usando o comando malloc
e usando muita e muita memória,
1449
01:12:52,187 --> 01:12:54,062
>que você não fará no
programa tão pequeno,
1450
01:12:54,062 --> 01:12:56,270
>mas com o tempo você pode
precisar de mais e mais memória,
1451
01:12:56,270 --> 01:13:01,490
>também devemos ter certeza de que t
tem um endereço válido.
1452
01:13:01,490 --> 01:13:04,670
>Acontece que malloc,
na maioria das vezes,
1453
01:13:04,670 --> 01:13:08,090
>vai devolver para você o
endereço de um pedaço de memória
1454
01:13:08,090 --> 01:13:09,470
>alocado para você.
1455
01:13:09,470 --> 01:13:11,300
>Assim como get string,
vai voltar para você
1456
01:13:11,300 --> 01:13:14,900
>o endereço do primeiro
byte do pedaço de memória
1457
01:13:14,900 --> 01:13:16,820
>para o qual encontrou espaço.
1458
01:13:16,820 --> 01:13:18,740
>No entanto, às vezes as coisas podem dar errado.
1459
01:13:18,740 --> 01:13:20,630
>Às vezes, seu computador
pode estar sem memória.
1460
01:13:20,630 --> 01:13:24,320
>Você provavelmente já viu seu Mac ou
O PC congelar, travar ou reiniciar sozinho.
1461
01:13:24,320 --> 01:13:26,910
>Isso geralmente é o resultado
de erros de memória.
1462
01:13:26,910 --> 01:13:29,000
>Portanto, devemos
verificar algo assim.
1463
01:13:29,000 --> 01:13:32,570
>Se t for igual a este
valor especial nul,
1464
01:13:32,570 --> 01:13:35,360
>então vou
apenas pular e devolver um,
1465
01:13:35,360 --> 01:13:37,280
>e sair,
vamos sair do programa.
1466
01:13:37,280 --> 01:13:38,760
>Não vai funcionar.
1467
01:13:38,760 --> 01:13:41,610
>Isso pode acontecer apenas
uma em um milhão de vezes.
1468
01:13:41,610 --> 01:13:44,220
>Mas é mais correto verificar se há nul.
1469
01:13:44,220 --> 01:13:48,350
>Agora, infelizmente, os designers de
C meio que usaram - ou programadores
1470
01:13:48,350 --> 01:13:53,210
>mais geralmente, esta palavra,
que é quase o mesmo que N-U-L,
1471
01:13:53,210 --> 01:13:54,980
>também conhecida como \0.
1472
01:13:54,980 --> 01:13:57,290
>Infelizmente, esse é
um valor diferente.
1473
01:13:57,290 --> 01:14:01,370
>N-U-L-L representa um ponteiro nul.
1474
01:14:01,370 --> 01:14:02,870
>É um endereço falso.
1475
01:14:02,870 --> 01:14:04,580
>É a ausência de endereço.
1476
01:14:04,580 --> 01:14:06,950
>Tecnicamente, seu endereço é 0.
1477
01:14:06,950 --> 01:14:09,230
>É diferente de \ 0.
1478
01:14:09,230 --> 01:14:14,000
>Você usa N-U-L-L no contexto de
ponteiros, como estamos fazendo hoje.
1479
01:14:14,000 --> 01:14:17,390
>Você usa \ 0,
de outra forma conhecido verbalmente,
1480
01:14:17,390 --> 01:14:21,210
>como um N-U-L, ou nul, no
contexto de caracteres.
1481
01:14:21,210 --> 01:14:23,810
>Portanto, a \ 0 é para caracteres.
1482
01:14:23,810 --> 01:14:26,750
>N-U-L-L em maiúsculas é para ponteiros.
1483
01:14:26,750 --> 01:14:29,750
>E é um novo símbolo que
estamos apresentando hoje
1484
01:14:29,750 --> 01:14:34,520
>que vem com este arquivo
lib ponto h padrão.
1485
01:14:34,520 --> 01:14:38,190
>Tudo bem, então parece, honestamente,
que eu não preciso fazer parte desse trabalho.
1486
01:14:38,190 --> 01:14:41,610
>Acontece que se eu quiser
copiar uma string para outra,
1487
01:14:41,610 --> 01:14:43,170
>existe uma função para isso.
1488
01:14:43,170 --> 01:14:45,920
>E cada vez mais, você não terá que
escrever tantas linhas de código
1489
01:14:45,920 --> 01:14:49,520
>como você fez anteriormente, porque
se você olhar nas páginas de manual
1490
01:14:49,520 --> 01:14:52,730
>ou você ouviu falar ou descobriu
online que há outra função, como uma
1491
01:14:52,730 --> 01:14:56,790
>chamada strcpy, você pode, na verdade,
mais simplesmente, fazer algo assim.
1492
01:14:56,790 --> 01:15:00,410
>Embora eu tenha gostado da ideia,
e foi correto usar um loop for
1493
01:15:00,410 --> 01:15:04,950
>para copiar todos os caracteres de
s para t, há uma função para isso.
1494
01:15:04,950 --> 01:15:06,200
>É chamada de strcpy.
1495
01:15:06,200 --> 01:15:09,830
>Leva dois argumentos, o
destino seguido pela fonte.
1496
01:15:09,830 --> 01:15:12,200
>E vai lidar
com todo o looping
1497
01:15:12,200 --> 01:15:15,890
>para nós, todas as cópias para nós,
incluindo \ 0,
1498
01:15:15,890 --> 01:15:18,830
>para que eu possa me concentrar no
que quero fazer, que, neste caso,
1499
01:15:18,830 --> 01:15:21,300
>é, na verdade, converter em maiúscula as coisas.
1500
01:15:21,300 --> 01:15:26,497
>Então, se considerarmos, agora, este exemplo,
no contexto da memória do meu computador,
1501
01:15:26,497 --> 01:15:28,580
>veremos que é um
pouco diferente.
1502
01:15:28,580 --> 01:15:31,050
>Mas há mais um bug
que eu quero consertar primeiro.
1503
01:15:31,050 --> 01:15:33,230
>E isso é algo que ainda
não tivemos que fazer.
1504
01:15:33,230 --> 01:15:37,850
>Acontece que sempre que você
aloca memória com malloc,
1505
01:15:37,850 --> 01:15:41,330
>você pede memória ao computador,
a responsabilidade recai sobre você, o programador,
1506
01:15:41,330 --> 01:15:43,160
>para, eventualmente, devolvê-la.
1507
01:15:43,160 --> 01:15:46,070
>E com isso, quero dizer que
se você alocar quatro bytes,
1508
01:15:46,070 --> 01:15:49,430
>ou quem sabe, quatro milhões de bytes de
memória para um programa ainda maior,
1509
01:15:49,430 --> 01:15:52,160
>é melhor devolver o espaço ao computador,
mais especificamente,
1510
01:15:52,160 --> 01:15:55,252
>ao sistema operacional, seja
Linux ou Mac OS ou Windows,
1511
01:15:55,252 --> 01:15:57,710
>para que seu computador
não fique sem memória.
1512
01:15:57,710 --> 01:16:00,418
>Se tudo o que você faz é pedir
mais memória e mais memória,
1513
01:16:00,418 --> 01:16:03,710
>é lógico que, eventualmente, seu
computador ficará sem, porque ele apenas
1514
01:16:03,710 --> 01:16:05,370
>tem uma quantidade finita de memória.
1515
01:16:05,370 --> 01:16:07,910
>Ele tem uma quantidade finita
de hardware.
1516
01:16:07,910 --> 01:16:11,780
>Então, quando você terminar de usar
a memória, deve ser sua melhor prática
1517
01:16:11,780 --> 01:16:14,970
>liberá-la depois também.
1518
01:16:14,970 --> 01:16:18,950
>E o oposto de malloc é uma
função chamada free, que leva,
1519
01:16:18,950 --> 01:16:22,040
>como sua entrada, qualquer
que seja a saída de malloc.
1520
01:16:22,040 --> 01:16:25,070
>E lembre-se de que a saída de malloc,
o valor de retorno de malloc,
1521
01:16:25,070 --> 01:16:30,210
>é o endereço do primeiro byte
de memória que ele alocou para você.
1522
01:16:30,210 --> 01:16:34,010
>Então, se você pedir quatro bytes, como
eu fiz algumas linhas atrás com malloc,
1523
01:16:34,010 --> 01:16:37,100
>você receberá de volta o endereço
do primeiro desses bytes.
1524
01:16:37,100 --> 01:16:41,150
>E cabe a você lembrar
quantos bytes você pediu.
1525
01:16:41,150 --> 01:16:43,760
>No caso de free,
tudo o que tem a fazer é
1526
01:16:43,760 --> 01:16:49,820
>dizer free, por meio de sua entrada,
o endereço que o malloc lhe forneceu.
1527
01:16:49,820 --> 01:16:53,210
>Então, se você armazenou esse endereço como
eu fiz, nesta variável chamada t,
1528
01:16:53,210 --> 01:16:58,190
>é suficiente quando você termine
aquela memória com a chamada t free.
1529
01:16:58,190 --> 01:17:02,360
>E o computador irá liberar
essa memória para você.
1530
01:17:02,360 --> 01:17:04,880
>E você pode muito bem
recuperá-la mais tarde.
1531
01:17:04,880 --> 01:17:07,400
>Mas pelo menos o seu computador
não ficará sem memória
1532
01:17:07,400 --> 01:17:13,490
>tão rapidamente, porque agora ele pode
reutilizar esse espaço para outra coisa.
1533
01:17:13,490 --> 01:17:15,410
>Tudo bem, deixe-me ir em
frente, então, e propor
1534
01:17:15,410 --> 01:17:17,870
>que desenhemos uma imagem disso -
1535
01:17:17,870 --> 01:17:20,942
>agora a memória do novo programa,
onde copiamos as coisas.
1536
01:17:20,942 --> 01:17:23,900
>Então, lembre-se, foi aqui que paramos
antes ao comparar duas strings.
1537
01:17:23,900 --> 01:17:29,010
>Se este fosse s, apontando para
h, i, !, em minúsculas,
1538
01:17:29,010 --> 01:17:32,510
>esta nova versão do meu
código em copy.c, veja só,
1539
01:17:32,510 --> 01:17:34,550
>ainda me dá outro ponteiro chamado t.
1540
01:17:34,550 --> 01:17:36,530
>Portanto, essa parte
da história não mudou.
1541
01:17:36,530 --> 01:17:37,970
>Mas eu chamo malloc agora.
1542
01:17:37,970 --> 01:17:40,790
>E malloc vai me devolver
um novo pedaço de memória.
1543
01:17:40,790 --> 01:17:42,440
>Não sei de antemão onde está.
1544
01:17:42,440 --> 01:17:45,740
>Mas o valor de retorno de
malloc será o endereço
1545
01:17:45,740 --> 01:17:47,920
>do primeiro bite dessa memória.
1546
01:17:47,920 --> 01:17:51,050
>Então, por exemplo, 0x456
ou seja o que for.
1547
01:17:51,050 --> 01:17:54,230
>E os bytes subsequentes
vão aumentar em um
1548
01:17:54,230 --> 01:17:59,630
>byte de cada vez, 0x457, 0x458, 0x459.
1549
01:17:59,630 --> 01:18:03,800
>Então, o que é, em última análise, armazenado em t quando
eu atribuo a ele o valor de retorno de malloc?
1550
01:18:03,800 --> 01:18:05,570
>É o que quer que seja esse endereço.
1551
01:18:05,570 --> 01:18:07,980
>Novamente, eu poderia escrever
tecnicamente 0x456 aqui.
1552
01:18:07,980 --> 01:18:09,800
>Mas, novamente, já superamos isso.
1553
01:18:09,800 --> 01:18:10,970
>Isso foi há 30 minutos.
1554
01:18:10,970 --> 01:18:14,300
>Agora vamos nos concentrar apenas
na abstração que é um ponteiro.
1555
01:18:14,300 --> 01:18:17,690
>Um ponteiro é uma seta
apontando a partir da variável
1556
01:18:17,690 --> 01:18:19,980
>para o local real na memória.
1557
01:18:19,980 --> 01:18:26,720
>Então agora, se eu for copiar s para t
usando strcpy, ou mais manualmente,
1558
01:18:26,720 --> 01:18:28,670
>usando meu loop for, o que acontece?
1559
01:18:28,670 --> 01:18:31,610
>Bem, estou copiando
h de s para t.
1560
01:18:31,610 --> 01:18:36,110
>Estou copiando o i de s para t,
o ponto de exclamação de s para t.
1561
01:18:36,110 --> 01:18:40,530
>E, por último, o caractere nul
de terminação de s para t.
1562
01:18:40,530 --> 01:18:42,740
>Portanto, a imagem agora é
fundamentalmente diferente.
1563
01:18:42,740 --> 01:18:45,020
>t não está apontando para a mesma coisa.
1564
01:18:45,020 --> 01:18:50,570
>Está apontando para seu próprio pedaço
de memória que agora, um passo de cada vez,
1565
01:18:50,570 --> 01:18:56,210
>duplicando tudo o que
estava no endereço s.
1566
01:18:56,210 --> 01:18:59,600
>E isso é o que você e eu, como humanos,
consideraríamos, presumivelmente,
1567
01:18:59,600 --> 01:19:04,080
>ser uma cópia adequada do programa.
1568
01:19:04,080 --> 01:19:09,660
>Alguma dúvida, então, sobre o que acabamos de
fazer com a introdução do malloc e do free?
1569
01:19:09,660 --> 01:19:11,910
>O primeiro deles aloca
memória e dá a você
1570
01:19:11,910 --> 01:19:15,750
>o endereço do primeiro byte de
memória que você pode usar agora,
1571
01:19:15,750 --> 01:19:19,260
>o último o devolve ao seu
sistema operacional e diz:
1572
01:19:19,260 --> 01:19:20,700
>terminei com isso.
1573
01:19:20,700 --> 01:19:24,360
>Agora pode ser reutilizado para
outra coisa, alguma outra variável,
1574
01:19:24,360 --> 01:19:27,090
>talvez, no futuro, se nosso
programa fosse mais longo.
1575
01:19:27,090 --> 01:19:31,530
>Brian, alguma dúvida ou
confusão em que posso ajudar?
1576
01:19:31,530 --> 01:19:33,870
>BRIAN: Alguém perguntou, mesmo
se você estiver usando strcpy
1577
01:19:33,870 --> 01:19:37,470
>para copiar a string em vez de copiar
os caracteres um de cada vez,
1578
01:19:37,470 --> 01:19:39,420
>você ainda precisa liberar a memória?
1579
01:19:39,420 --> 01:19:40,545
>DAVID MALAN: Boa pergunta.
1580
01:19:40,545 --> 01:19:43,320
>Mesmo se você estiver usando strcpy,
você ainda precisa usar free.
1581
01:19:43,320 --> 01:19:48,120
>Sim, a partir de agora, sempre que você
usar o malloc, deverá usar free.
1582
01:19:48,120 --> 01:19:52,470
>Sempre que usar malloc, você deve
usar free para liberar essa memória.
1583
01:19:52,470 --> 01:19:56,370
>strcpy está copiando o conteúdo de
um pedaço de memória para o outro.
1584
01:19:56,370 --> 01:19:59,220
>Ele não está alocando ou gerenciando
essa memória para você.
1585
01:19:59,220 --> 01:20:02,520
>Está apenas implementando,
isso para loop.
1586
01:20:02,520 --> 01:20:05,520
>E talvez seja a hora de tirar
outra roda de treinamento
1587
01:20:05,520 --> 01:20:06,020
>verbalmente.
1588
01:20:06,020 --> 01:20:10,410
>Acontece que get string,
todo esse tempo, é meio mágico.
1589
01:20:10,410 --> 01:20:13,470
>Uma das coisas que get string
faz a partir da biblioteca CS50
1590
01:20:13,470 --> 01:20:16,080
>é que ele próprio usa malloc.
1591
01:20:16,080 --> 01:20:19,800
>Considere, afinal, quando nós, o staff,
escrevemos get string anos atrás,
1592
01:20:19,800 --> 01:20:22,830
>não tínhamos ideia de quanto tempo
seus nomes vão durar este ano.
1593
01:20:22,830 --> 01:20:24,690
>Não temos ideia de quais
frases você está falando
1594
01:20:24,690 --> 01:20:28,350
>para digitar, quais parágrafos você vai
digitar, que texto você vai analisar
1595
01:20:28,350 --> 01:20:30,240
>para um programa como readability.
1596
01:20:30,240 --> 01:20:32,610
>Então, tivemos que implementar
get string de tal forma
1597
01:20:32,610 --> 01:20:35,730
>que você pode digitar poucos ou
tantos caracteres em seu teclado
1598
01:20:35,730 --> 01:20:36,420
>como você quiser.
1599
01:20:36,420 --> 01:20:40,150
>E vamos garantir que haja memória
suficiente para essa string.
1600
01:20:40,150 --> 01:20:43,530
>Então, get string, por baixo do capô,
se você olhar para o código, nós, o staff,
1601
01:20:43,530 --> 01:20:46,530
>escrevemos algum dia, você
verá que usamos malloc.
1602
01:20:46,530 --> 01:20:51,390
>E chamamos malloc para obter memória
suficiente para caber nessa string.
1603
01:20:51,390 --> 01:20:54,600
>E então, o que a biblioteca CS50
também está secretamente fazendo,
1604
01:20:54,600 --> 01:20:57,060
>é que também está chamando free para você.
1605
01:20:57,060 --> 01:20:59,130
>Há um jeito sofisticado onde você
1606
01:20:59,130 --> 01:21:03,690
>pode escrever um programa que, assim que o
main estiver prestes a sair ou retornar
1607
01:21:03,690 --> 01:21:06,480
>para o seu prompt piscando,
algum código especial
1608
01:21:06,480 --> 01:21:10,860
>nós escrevemos swoops naquele momento
final, liberando qualquer parte da memória
1609
01:21:10,860 --> 01:21:14,130
>que nós, a biblioteca,
alocamos para que você
1610
01:21:14,130 --> 01:21:17,190
>não fique sem memória por nossa causa.
1611
01:21:17,190 --> 01:21:19,590
>Mas todos vocês, ao
usar malloc, terão
1612
01:21:19,590 --> 01:21:23,700
>que chamar free, porque a
biblioteca não vai fazer isso por você.
1613
01:21:23,700 --> 01:21:26,400
>E, a meta de hoje
e da próxima semana e além
1614
01:21:26,400 --> 01:21:30,833
>é parar de usar a biblioteca CS50,
em última análise, por completo.
1615
01:21:30,833 --> 01:21:33,000
>Tudo bem, vamos-- seria
injusto, eu acho,
1616
01:21:33,000 --> 01:21:36,000
>se introduzirmos todas essas novas técnicas
sofisticadas, mas não necessariamente
1617
01:21:36,000 --> 01:21:40,620
>fornecemos a você qualquer tipo de ferramenta
para determinar a perseguição de bugs
1618
01:21:40,620 --> 01:21:43,245
>em seu novo código sofisticado
ou resolução de problemas, agora,
1619
01:21:43,245 --> 01:21:44,370
>que estão relacionados à memória.
1620
01:21:44,370 --> 01:21:46,860
>E, felizmente, existem
programas por meio dos quais
1621
01:21:46,860 --> 01:21:49,560
>você pode perseguir bugs relacionados à memória.
1622
01:21:49,560 --> 01:21:52,080
>Isso é além de printf,
1623
01:21:52,080 --> 01:21:56,550
>e help50 e check50 e debug50 e
depuradores de forma mais geral.
1624
01:21:56,550 --> 01:21:59,940
>Este programa - e é a última das
novas ferramentas que apresentaremos a você
1625
01:21:59,940 --> 01:22:01,920
>em C-- é chamado valgrind.
1626
01:22:01,920 --> 01:22:04,830
>E este é um programa que
existe no CS50 IDE.
1627
01:22:04,830 --> 01:22:07,620
>Mas existe em Macs e
PCs e Linux
1628
01:22:07,620 --> 01:22:10,050
>em qualquer lugar, onde você pode
executá-lo em seu código
1629
01:22:10,050 --> 01:22:12,870
>para detectar se você está fazendo
algo errado com a memória.
1630
01:22:12,870 --> 01:22:14,370
>O que você pode fazer de errado com a memória?
1631
01:22:14,370 --> 01:22:17,037
>Bem, antes, lembre-se, eu acionei
essa falha de segmentação.
1632
01:22:17,037 --> 01:22:19,320
>Toquei a memória que não deveria.
1633
01:22:19,320 --> 01:22:22,080
>Valgrind é uma ferramenta que
pode ajudá-lo a descobrir,
1634
01:22:22,080 --> 01:22:25,000
>onde você tocou na
memória que não deveria,
1635
01:22:25,000 --> 01:22:27,960
>de modo a focar sua própria atenção
humana em quaisquer linhas de código
1636
01:22:27,960 --> 01:22:28,830
>que pode estar cheio de erros.
1637
01:22:28,830 --> 01:22:32,610
>Valgrind grant também pode detectar se
você esquecer de chamar free.
1638
01:22:32,610 --> 01:22:36,240
>Se você chamar malloc uma ou
mais vezes, mas não chamar free
1639
01:22:36,240 --> 01:22:38,280
>um número correspondente
de vezes, valgrind
1640
01:22:38,280 --> 01:22:40,890
>é um programa que pode perceber
isso e dizer que você tem
1641
01:22:40,890 --> 01:22:42,580
>o que é chamado de vazamento de memória.
1642
01:22:42,580 --> 01:22:44,760
>E, isso é pertinente
aos nossos próprios Macs e PCs.
1643
01:22:44,760 --> 01:22:47,100
>Novamente, se você tem usado
o seu Mac ou PC ou às vezes
1644
01:22:47,100 --> 01:22:50,070
>até mesmo seu telefone por
muito, muito tempo, e talvez
1645
01:22:50,070 --> 01:22:53,340
>executando muitos programas diferentes ao
mesmo tempo, muitas guias do navegador
1646
01:22:53,340 --> 01:22:55,680
>abertas, muitos programas
diferentes abertos ao mesmo tempo,
1647
01:22:55,680 --> 01:22:59,370
>seu Mac ou PC pode muito bem
ter começado a ficar lento.
1648
01:22:59,370 --> 01:23:01,920
>Pode ser irritante, se
não impossível de usar,
1649
01:23:01,920 --> 01:23:03,960
>porque tudo é muito lento.
1650
01:23:03,960 --> 01:23:07,920
>Isso pode muito bem ser porque um ou
mais dos programas que você está usando
1651
01:23:07,920 --> 01:23:12,480
>tem algum bug em que um programador
ficava alocando memória
1652
01:23:12,480 --> 01:23:15,210
>e nunca chamou free.
1653
01:23:15,210 --> 01:23:17,273
>Talvez seja um bug, talvez
tenha sido deliberado,
1654
01:23:17,273 --> 01:23:19,440
>não esperavam que você
tivesse tantas janelas abertas.
1655
01:23:19,440 --> 01:23:21,360
>Mas o valgrind pode
detectar erros como esse.
1656
01:23:21,360 --> 01:23:23,730
>E honestamente, alguns de
vocês, se forem como eu,
1657
01:23:23,730 --> 01:23:29,370
>você pode muito bem ter 10, 20, 50 guias
diferentes do navegador abertas ao mesmo tempo,
1658
01:23:29,370 --> 01:23:32,910
>pensando "eu vou voltar a isso algum dia",
embora nunca o façamos.
1659
01:23:32,910 --> 01:23:34,950
>Cada uma dessas guias ocupa memória.
1660
01:23:34,950 --> 01:23:37,320
>Literalmente, sempre que você abrir
uma guia do navegador, pense nisso,
1661
01:23:37,320 --> 01:23:41,580
>como Chrome ou Edge ou Firefox
ou qualquer outro
1662
01:23:41,580 --> 01:23:43,920
>que você está usando, por
baixo do capô, estão
1663
01:23:43,920 --> 01:23:46,320
>provavelmente chamando uma
função no Mac OS ou Windows
1664
01:23:46,320 --> 01:23:50,670
>como malloc para lhe dar mais memória para
conter o conteúdo dessa página da web
1665
01:23:50,670 --> 01:23:51,480
>temporariamente.
1666
01:23:51,480 --> 01:23:54,310
>E se você continuar abrindo
mais e mais guias do navegador,
1667
01:23:54,310 --> 01:23:56,190
>é como chamar malloc,
malloc, malloc.
1668
01:23:56,190 --> 01:23:57,840
>Eventualmente, você vai ficar sem recursos.
1669
01:23:57,840 --> 01:23:59,700
>E os computadores podem ser
inteligentes hoje em dia.
1670
01:23:59,700 --> 01:24:03,060
>Eles podem remover coisas temporariamente
da memória para liberar espaço.
1671
01:24:03,060 --> 01:24:04,477
>Isso é chamado de memória virtual.
1672
01:24:04,477 --> 01:24:06,310
>Mas, eventualmente,
algo vai sair mal.
1673
01:24:06,310 --> 01:24:08,520
>E pode muito bem ser sua
experiência de usuário
1674
01:24:08,520 --> 01:24:11,700
>quando as coisas ficam tão lentas que você
literalmente tem que sair do programa
1675
01:24:11,700 --> 01:24:14,140
>ou talvez até reiniciar o seu computador.
1676
01:24:14,140 --> 01:24:15,240
>Então, como usamos valgrind?
1677
01:24:15,240 --> 01:24:17,430
>Bem, vou escrever um pequeno programa
1678
01:24:17,430 --> 01:24:20,040
>que não faz nada de útil,
mas demonstra
1679
01:24:20,040 --> 01:24:22,080
>vários erros relacionados à memória.
1680
01:24:22,080 --> 01:24:24,060
>Vou chamar esse arquivo de memory.c.
1681
01:24:24,060 --> 01:24:27,550
>Vou prosseguir e abrir
o arquivo memory.c
1682
01:24:27,550 --> 01:24:30,842
>e incluir no topo o
padrão io ponto h.
1683
01:24:30,842 --> 01:24:32,550
>E então eu irei também,
preventivamente,
1684
01:24:32,550 --> 01:24:37,290
>incluir lib ponto h padrão, que
lembra de malloc, int main void.
1685
01:24:37,290 --> 01:24:39,070
>E vou manter tudo bem simples.
1686
01:24:39,070 --> 01:24:42,370
>Eu vou seguir em frente e criar
um monte de números inteiros.
1687
01:24:42,370 --> 01:24:43,810
>Então isso é legal.
1688
01:24:43,810 --> 01:24:46,480
>Acontece que--
1689
01:24:46,480 --> 01:24:47,880
>bem, vamos em frente.
1690
01:24:47,880 --> 01:24:48,910
>Sim, posso fazer isso.
1691
01:24:48,910 --> 01:24:50,035
>Vamos fazer isso.
1692
01:24:50,035 --> 01:24:52,650
>Char s* gets malloc.
1693
01:24:52,650 --> 01:24:57,630
>Agora eu vou criar, que tal três desses.
1694
01:24:57,630 --> 01:25:01,050
>Vou alocar espaço
para três caracteres.
1695
01:25:01,050 --> 01:25:03,640
>Ou, na verdade, vamos criar quatro,
como antes.
1696
01:25:03,640 --> 01:25:08,340
>Agora, vou prosseguir e dizer
que s colchete 0 é igual a 72.
1697
01:25:08,340 --> 01:25:12,220
>s colchete 1-- na verdade,
vou apenas fazer isso manualmente.
1698
01:25:12,220 --> 01:25:14,160
>Vamos fazer h.
1699
01:25:14,160 --> 01:25:16,350
>Vamos fazer i.
1700
01:25:16,350 --> 01:25:19,960
>Vamos fazer nosso ponto de exclamação usual.
1701
01:25:19,960 --> 01:25:22,170
>E então, apenas para garantir,
s colchete 3 gets
1702
01:25:22,170 --> 01:25:24,120
>"\ 0".
1703
01:25:24,120 --> 01:25:29,340
>Esta é a maneira muito
manual de -
1704
01:25:29,340 --> 01:25:32,430
>esta é a maneira muito manual de
construir uma string.
1705
01:25:32,430 --> 01:25:34,060
>Mas deixe-me apresentar um erro.
1706
01:25:34,060 --> 01:25:37,320
>Vamos alocar acidentalmente
apenas três bytes,
1707
01:25:37,320 --> 01:25:40,440
>embora eu claramente precise de um quarto
para aquele caractere nul final.
1708
01:25:40,440 --> 01:25:42,510
>E observe também a ausência de free.
1709
01:25:42,510 --> 01:25:45,720
>Eu vou, muito descuidadamente,
não me preocupar em chamar free.
1710
01:25:45,720 --> 01:25:49,590
>Agora, vou compilar este
programa, make memory.
1711
01:25:49,590 --> 01:25:53,430
>OK, ele compila OK, então isso
é bom, ./memory
1712
01:25:53,430 --> 01:25:55,413
>OK, nada acontece,
mas isso faz
1713
01:25:55,413 --> 01:25:57,330
>sentido porque eu não disse
a ele para fazer nada.
1714
01:25:57,330 --> 01:26:01,360
>Só por diversão, vamos imprimir
essa string como sempre fazemos.
1715
01:26:01,360 --> 01:26:04,500
>Vamos recompilar a memória,
ainda compila.
1716
01:26:04,500 --> 01:26:06,360
>Vamos executar ./memory.
1717
01:26:06,360 --> 01:26:07,570
>OK, parece funcionar.
1718
01:26:07,570 --> 01:26:10,000
>Portanto, à primeira vista, você pode
estar muito orgulhoso de si mesmo.
1719
01:26:10,000 --> 01:26:12,910
>Você escreveu outro programa correto,
parece passar no check50.
1720
01:26:12,910 --> 01:26:13,410
>Você submete.
1721
01:26:13,410 --> 01:26:14,327
>Você continua seu dia.
1722
01:26:14,327 --> 01:26:16,380
>E você fica muito desapontado
alguns dias depois
1723
01:26:16,380 --> 01:26:19,920
>quando você percebe, caramba, eu não
recebi todo o crédito nisso porque há
1724
01:26:19,920 --> 01:26:21,780
>na verdade, um bug evidente.
1725
01:26:21,780 --> 01:26:24,780
>Então, às vezes,
existem bugs no seu código
1726
01:26:24,780 --> 01:26:27,420
>que você não necessariamente vê,
visualmente, você não necessariamente
1727
01:26:27,420 --> 01:26:30,990
>experiencia ao executá-lo sozinho,
mas, eventualmente,
1728
01:26:30,990 --> 01:26:33,443
>pode aparecer um erro ao
executá-lo várias vezes.
1729
01:26:33,443 --> 01:26:36,360
>Eventualmente, um computador pode perceber
que você está fazendo algo errado.
1730
01:26:36,360 --> 01:26:38,460
>E, felizmente, existem
ferramentas como valgrind,
1731
01:26:38,460 --> 01:26:40,098
>que pode permitir que você detecte isso.
1732
01:26:40,098 --> 01:26:43,140
>Eu vou aumentar o tamanho
da janela do meu terminal aqui.
1733
01:26:43,140 --> 01:26:48,090
>Agora eu vou executar
o valgrind em ./memory.
1734
01:26:48,090 --> 01:26:49,290
>Portanto, é como debug50.
1735
01:26:49,290 --> 01:26:53,040
>Em vez de executar debug50 e, em seguida,
./ seja qual for o programa,
1736
01:26:53,040 --> 01:26:55,813
>você executa valgrind ./ memory.
1737
01:26:55,813 --> 01:26:58,230
>Esta, infelizmente, é uma
interface de linha de comando.
1738
01:26:58,230 --> 01:27:00,480
>Não há interface gráfica
do usuário como debug50.
1739
01:27:00,480 --> 01:27:04,530
>E, honestamente, é uma
sequência horrível de saída.
1740
01:27:04,530 --> 01:27:06,630
>Isso deve surpreendê-lo
à primeira vista.
1741
01:27:06,630 --> 01:27:08,190
>Há um visual codificado muito ruim.
1742
01:27:08,190 --> 01:27:09,690
>Não é o programa mais bem projetado.
1743
01:27:09,690 --> 01:27:12,520
>Foi feito para as
pessoas mais adaptadas à programação.
1744
01:27:12,520 --> 01:27:15,180
>Mas existem algumas dicas úteis
que podemos tirar disso.
1745
01:27:15,180 --> 01:27:17,490
>Como sempre, deixe-me mostrar
todo o caminho até o topo
1746
01:27:17,490 --> 01:27:19,260
>para a primeira linha de saída.
1747
01:27:19,260 --> 01:27:21,600
>E vou chamar sua atenção
para algumas coisas
1748
01:27:21,600 --> 01:27:23,070
>que vão começar a saltar aos
olhos para você.
1749
01:27:23,070 --> 01:27:24,960
>E help50 pode ajudá-lo com isso.
1750
01:27:24,960 --> 01:27:28,020
>Se você está confuso com a saída
de valgrind, execute-o novamente.
1751
01:27:28,020 --> 01:27:29,520
>Mas coloque help50 no início.
1752
01:27:29,520 --> 01:27:32,120
>E assim como farei agora
verbalmente, help50
1753
01:27:32,120 --> 01:27:36,510
>vai ajudá-lo a perceber as coisas importantes
nesta bagunça maluca de saída.
1754
01:27:36,510 --> 01:27:37,770
>Isso é preocupante.
1755
01:27:37,770 --> 01:27:41,880
>Valgrind está observando nesta linha
aqui, direito inválido de tamanho 1.
1756
01:27:41,880 --> 01:27:44,370
>E isso está na linha 10 de memory.c.
1757
01:27:44,370 --> 01:27:46,510
>Então, veremos isso em um momento.
1758
01:27:46,510 --> 01:27:50,530
>Se eu rolar mais para baixo,
leitura inválida de tamanho 1.
1759
01:27:50,530 --> 01:27:55,810
>E isso também parece estar aqui,
parece, na linha 11 de memory.c.
1760
01:27:55,810 --> 01:27:59,070
>E então, se eu continuar rolando,
continue rolando, continue rolando,
1761
01:27:59,070 --> 01:28:00,990
>Eu não estou gostando disso.
1762
01:28:00,990 --> 01:28:05,910
>3 bytes em 1 bloco são definitivamente perdidos
no registro de perda, seja ele qual for.
1763
01:28:05,910 --> 01:28:10,170
>Mas três bytes em 1 bloco estão
definitivamente perdidos.
1764
01:28:10,170 --> 01:28:15,240
>E então aqui embaixo, resumo do vazamento,
definitivamente perdido, 3 bytes em 1 blocos.
1765
01:28:15,240 --> 01:28:17,703
>Aliás, 1 blocos,
obviamente não é a gramática certa.
1766
01:28:17,703 --> 01:28:19,620
>Isso é o que acontece
quando seu programa não
1767
01:28:19,620 --> 01:28:24,210
>tem uma condição if que verifica
se o número é 1 ou positivo ou 0.
1768
01:28:24,210 --> 01:28:27,300
>Você poderia corrigir isso, gramaticalmente,
honestamente, com uma condição if simples.
1769
01:28:27,300 --> 01:28:29,770
>Eles não o fizeram quando escreveram
este programa anos atrás.
1770
01:28:29,770 --> 01:28:32,110
>Portanto, há dois ou três erros aqui.
1771
01:28:32,110 --> 01:28:34,620
>Um é algum tipo de leitura
ou gravação inválida.
1772
01:28:34,620 --> 01:28:35,953
>E outro é esse vazamento.
1773
01:28:35,953 --> 01:28:36,870
>Bem, o que é uma escrita?
1774
01:28:36,870 --> 01:28:38,940
>Uma gravação refere-se apenas à alteração de um valor.
1775
01:28:38,940 --> 01:28:43,150
>Uma leitura refere-se apenas à
leitura, uso ou impressão de um valor.
1776
01:28:43,150 --> 01:28:44,730
>Então, vamos nos concentrar na linha 10.
1777
01:28:44,730 --> 01:28:48,060
>Se eu rolar de volta para o meu
código e olhar a linha 10,
1778
01:28:48,060 --> 01:28:51,760
>esta foi uma gravação
inválida, gravação inválida.
1779
01:28:51,760 --> 01:28:52,950
>Bem, por que é inválido?
1780
01:28:52,950 --> 01:28:57,180
>Bem, pela definição de hoje,
se você estiver alocando 3 bytes,
1781
01:28:57,180 --> 01:29:01,710
>você pode tocar no primeiro byte,
o segundo byte e o terceiro byte.
1782
01:29:01,710 --> 01:29:04,500
>Mas você não tem que
tocar no quarto byte
1783
01:29:04,500 --> 01:29:06,420
>se você pediu apenas três.
1784
01:29:06,420 --> 01:29:11,070
>Isso é como uma versão em pequena escala
do muito aventureiro e inapropriado
1785
01:29:11,070 --> 01:29:14,100
>modo em que entrei, bisbilhotando,
quando olhei para 10.000 bytes adiante.
1786
01:29:14,100 --> 01:29:16,680
>Mesmo olhar a um byte de
distância é um bug em potencial
1787
01:29:16,680 --> 01:29:18,780
>e pode causar o travamento de um programa.
1788
01:29:18,780 --> 01:29:21,720
>Enquanto isso, a linha 11
também é problemática, o que
1789
01:29:21,720 --> 01:29:25,470
>é uma leitura inválida, porque agora,
você está dizendo para imprimir esta string.
1790
01:29:25,470 --> 01:29:28,043
>Mas essa string contém
um endereço de memória
1791
01:29:28,043 --> 01:29:30,210
>que você não deveria ter
tocado em primeiro lugar.
1792
01:29:30,210 --> 01:29:34,080
>E o vazamento de memória, o
terceiro problema, decorre do fato
1793
01:29:34,080 --> 01:29:36,520
>que não liberei essa memória.
1794
01:29:36,520 --> 01:29:40,380
>Então, novamente, vai precisar de alguma
prática e experiência, alguns erros seus,
1795
01:29:40,380 --> 01:29:42,480
>para perceber e entender esses bugs.
1796
01:29:42,480 --> 01:29:44,670
>Mas deixe-me corrigir os dois primeiros assim.
1797
01:29:44,670 --> 01:29:46,530
>Vou criar quatro bytes.
1798
01:29:46,530 --> 01:29:48,990
>E deixe-me consertar o
segundo ou o terceiro,
1799
01:29:48,990 --> 01:29:53,820
>ao liberar s bem no final,
porque, novamente, sempre que você usa malloc
1800
01:29:53,820 --> 01:29:55,590
>você deve usar free.
1801
01:29:55,590 --> 01:29:59,310
>Eu vou recompilar
a memória, parece compilar.
1802
01:29:59,310 --> 01:30:02,130
>Vamos executá-lo novamente, ainda
funciona da mesma forma, visualmente.
1803
01:30:02,130 --> 01:30:05,670
>Mas agora, vamos executar novamente o
valgrind nele e ver se há algum erro agora,
1804
01:30:05,670 --> 01:30:08,710
>então valgrind ./ memory, Enter.
1805
01:30:08,710 --> 01:30:10,710
>A saída ainda parecerá
muito enigmática.
1806
01:30:10,710 --> 01:30:15,300
>Mas observe que todos os blocos de heap foram
liberados, seja lá o que isso signifique.
1807
01:30:15,300 --> 01:30:16,217
>Nenhum vazamento é possível.
1808
01:30:16,217 --> 01:30:18,133
>Na verdade, não fica mais
explícito do que isso.
1809
01:30:18,133 --> 01:30:19,090
>Isso é uma coisa boa.
1810
01:30:19,090 --> 01:30:23,100
>E se eu rolar para cima, não vejo nenhuma
menção a essas leituras ou gravações inválidas.
1811
01:30:23,100 --> 01:30:26,168
>Então, começando com os problemas desta
semana e os da próxima semana em C,
1812
01:30:26,168 --> 01:30:27,960
>você não só vai querer
usar ferramentas
1813
01:30:27,960 --> 01:30:31,590
>como help50 e printf
e debug50 e check50,
1814
01:30:31,590 --> 01:30:35,710
>mas mesmo se você achar que seu código
está certo, a saída parece certa,
1815
01:30:35,710 --> 01:30:37,050
>você pode ter um bug latente.
1816
01:30:37,050 --> 01:30:40,200
>E mesmo quando seus programas são pequenos,
não travando o computador,
1817
01:30:40,200 --> 01:30:43,500
>Sem causar essa falha de
segmentação, eventualmente, eles vão.
1818
01:30:43,500 --> 01:30:47,850
>E é melhor usar ferramentas como
esta para perseguir esses erros.
1819
01:30:47,850 --> 01:30:50,460
>Caso contrário, coisas ruins podem acontecer.
1820
01:30:50,460 --> 01:30:51,600
>E o que pode acontecer?
1821
01:30:51,600 --> 01:30:54,900
>Bem, deixe-me ir em frente
e revelar um exemplo aqui
1822
01:30:54,900 --> 01:30:57,840
>que apresenta algum código
que é um pouco perigoso.
1823
01:30:57,840 --> 01:31:00,600
>Então aqui, por exemplo,
é um exemplo onde
1824
01:31:00,600 --> 01:31:05,202
>estou declarando no topo da
função, int asterisco x e int asterisco y.
1825
01:31:05,202 --> 01:31:06,160
>Então, o que isso significa?
1826
01:31:06,160 --> 01:31:08,700
>Bem, pela linguagem de hoje,
isso significa apenas me dê
1827
01:31:08,700 --> 01:31:11,550
>um ponteiro para um inteiro chamado x.
1828
01:31:11,550 --> 01:31:13,800
>Dê-me um ponteiro para
um inteiro chamado y.
1829
01:31:13,800 --> 01:31:16,650
>Dito de outra forma, dê-me uma
variável chamada x que eu
1830
01:31:16,650 --> 01:31:18,900
>possa armazenar o endereço de um int.
1831
01:31:18,900 --> 01:31:23,640
>Dê-me uma variável chamada y na qual
posso armazenar o endereço de outro int.
1832
01:31:23,640 --> 01:31:27,880
>Mas observe o que não estou fazendo
nessas duas primeiras linhas.
1833
01:31:27,880 --> 01:31:31,950
>Na verdade, não estou atribuindo
a elas um valor até a linha 3.
1834
01:31:31,950 --> 01:31:36,000
>Na linha 3, embora isso seja estranho -
não é assim que alocamos espaço
1835
01:31:36,000 --> 01:31:37,530
>para inteiros antes -
1836
01:31:37,530 --> 01:31:41,130
>não há razão para que você
não possa usar malloc
1837
01:31:41,130 --> 01:31:45,550
>e diga, dê-me espaço suficiente
para o tamanho de um inteiro.
1838
01:31:45,550 --> 01:31:46,370
>sizeof é novo.
1839
01:31:46,370 --> 01:31:50,150
>É apenas um operador em C que informa
o tamanho de um tipo de dados,
1840
01:31:50,150 --> 01:31:51,500
>como o tamanho de um int.
1841
01:31:51,500 --> 01:31:53,480
>Então, talvez você tenha esquecido que um int é 4.
1842
01:31:53,480 --> 01:31:56,450
>E, um int é geralmente 4,
mas nem sempre 4 em todos os sistemas.
1843
01:31:56,450 --> 01:32:00,020
>Portanto, o tamanho de int só garante
que sempre fornecerá a resposta certa,
1844
01:32:00,020 --> 01:32:02,630
>se você está usando um
computador moderno ou antigo.
1845
01:32:02,630 --> 01:32:07,190
>Então, isso significa, alocar
4 bytes para mim em um sistema moderno.
1846
01:32:07,190 --> 01:32:11,370
>E armazena o endereço
do primeiro byte em x.
1847
01:32:11,370 --> 01:32:15,360
>Alguém se importaria de traduzir
para termos leigos, o que
1848
01:32:15,360 --> 01:32:18,480
>asterisco x igual a 42 está fazendo?
1849
01:32:18,480 --> 01:32:20,880
>Asterisco, novamente, é o
operador de desreferência.
1850
01:32:20,880 --> 01:32:23,430
>Significa ir para o endereço.
1851
01:32:23,430 --> 01:32:24,375
>E fazer o que?
1852
01:32:24,375 --> 01:32:27,510
>Como você descreveria,
com um comentário verbal,
1853
01:32:27,510 --> 01:32:30,450
>o que asterisco x igual a 42 está fazendo?
1854
01:32:30,450 --> 01:32:33,630
>Brian, você se importaria de
verbalizar algum pensamento?
1855
01:32:33,630 --> 01:32:37,555
>BRIAN: Sim, então Sofia sugeriu que
nesse endereço, colocaremos o 42.
1856
01:32:37,555 --> 01:32:38,430
>DAVID MALAN: Perfeito.
1857
01:32:38,430 --> 01:32:40,080
>Nesse endereço, coloque 42.
1858
01:32:40,080 --> 01:32:44,640
>Equivalentemente, vá para aquele
endereço em x e coloque o número 42 lá.
1859
01:32:44,640 --> 01:32:48,870
>É como ir à caixa de correio de Brian e
colocar o 42 em sua caixa de correio,
1860
01:32:48,870 --> 01:32:52,035
>em vez do que tínhamos
anteriormente, que era o número 50.
1861
01:32:52,035 --> 01:32:57,180
>Que tal esta próxima quinta
linha, asterisco y é igual a 13?
1862
01:32:57,180 --> 01:32:59,670
>Brian, você poderia verbalizar outra pessoa?
1863
01:32:59,670 --> 01:33:03,500
>O que asterisco y igual a 13 faz por nós?
1864
01:33:03,500 --> 01:33:07,850
>E não é por acaso que
13 tende a ser azarado.
1865
01:33:07,850 --> 01:33:10,530
>BRIAN: Peter diz, coloque
13 no endereço y.
1866
01:33:10,530 --> 01:33:12,710
>DAVID MALAN: Bom, coloque
13 no endereço em y.
1867
01:33:12,710 --> 01:33:16,860
>Ou dito de outra forma, vá para o
endereço em y e coloque 13 lá.
1868
01:33:16,860 --> 01:33:19,070
>Mas há um problema lógico aqui.
1869
01:33:19,070 --> 01:33:20,870
>O que está em y?
1870
01:33:20,870 --> 01:33:24,860
>Se eu retroceder, nunca
atribuo um valor a y.
1871
01:33:24,860 --> 01:33:27,050
>Eu não faço inicialmente, e
eu não faço eventualmente.
1872
01:33:27,050 --> 01:33:30,500
>Pelo menos com x, embora eu não tenha
dado um valor ao declará-lo aqui
1873
01:33:30,500 --> 01:33:34,850
>como uma variável, acabei
armazenando nela o endereço real.
1874
01:33:34,850 --> 01:33:38,060
>Agora, apenas para ser minucioso,
eu provavelmente deveria, neste programa,
1875
01:33:38,060 --> 01:33:40,495
>verificar em nul
caso algo dê errado.
1876
01:33:40,495 --> 01:33:41,870
>Mas esse é um problema totalmente diferente.
1877
01:33:41,870 --> 01:33:46,470
>É um problema mais terrível que
eu sequer dei um valor a y.
1878
01:33:46,470 --> 01:33:49,610
>E é aqui que podemos revelar outro
detalhe sobre um computador.
1879
01:33:49,610 --> 01:33:53,750
>Até agora, consideramos que você
e eu quase sempre inicializamos
1880
01:33:53,750 --> 01:33:54,360
>nossa memória.
1881
01:33:54,360 --> 01:33:56,900
>Se quisermos nos dar um
char, um int, uma string,
1882
01:33:56,900 --> 01:33:59,900
>nós literalmente
digitamos no programa
1883
01:33:59,900 --> 01:34:02,150
>para que esteja
lá quando quisermos.
1884
01:34:02,150 --> 01:34:04,070
>Mas se considerarmos
esta imagem aqui, que
1885
01:34:04,070 --> 01:34:07,370
>agora é uma encarnação física de
alguns dos conteúdos da memória
1886
01:34:07,370 --> 01:34:11,750
>do seu computador, divertidamente rotulada
com muito Oscars,
1887
01:34:11,750 --> 01:34:16,250
>isso é porque você nunca deve confiar no
conteúdo da memória do seu computador
1888
01:34:16,250 --> 01:34:18,500
>se você mesmo não
colocou algo lá.
1889
01:34:18,500 --> 01:34:21,560
>Existe um termo técnico em
programação chamado valores de lixo.
1890
01:34:21,560 --> 01:34:26,180
>Se você mesmo não colocou um
valor em algum lugar da memória,
1891
01:34:26,180 --> 01:34:30,210
>você deve assumir, para estar seguro, que
é "valor de lixo".
1892
01:34:30,210 --> 01:34:31,440
>Não é um valor estranho.
1893
01:34:31,440 --> 01:34:34,580
>É apenas 1, 2, um A, a B, o C, você apenas
1894
01:34:34,580 --> 01:34:38,510
>não sabe o que é, porque se o seu
programa está rodando
1895
01:34:38,510 --> 01:34:40,890
>e você está chamando funções
e funções estão retornando.
1896
01:34:40,890 --> 01:34:43,348
>Você está chamando outras funções
e as funções estão retornando.
1897
01:34:43,348 --> 01:34:46,970
>Esses valores na memória do seu
computador estão mudando constantemente,
1898
01:34:46,970 --> 01:34:48,740
>e sua memória é reutilizada.
1899
01:34:48,740 --> 01:34:53,180
>Quando você libera memória, isso não a apaga
ou define tudo de volta para zero ou define
1900
01:34:53,180 --> 01:34:53,990
>tudo de volta para 1's.
1901
01:34:53,990 --> 01:34:56,600
>Ele apenas deixa estar
para que você possa reutilizar
1902
01:34:56,600 --> 01:34:59,810
>isso, o que significa com o tempo,
seu computador contém resquícios
1903
01:34:59,810 --> 01:35:03,960
>de todas as variáveis que você já
usou em seu programa aqui, aqui,
1904
01:35:03,960 --> 01:35:04,730
>e lá.
1905
01:35:04,730 --> 01:35:10,850
>E dessa forma, em um programa assim, onde
você não inicializou explicitamente y
1906
01:35:10,850 --> 01:35:14,000
>a qualquer coisa, você deve presumir
que Oscar, por assim dizer,
1907
01:35:14,000 --> 01:35:15,020
>está nesse local.
1908
01:35:15,020 --> 01:35:20,570
>É um valor lixo que se parece com um
endereço, mas não é um endereço válido.
1909
01:35:20,570 --> 01:35:25,040
>E então, quando você diz asterisco y é igual a
13, isso significa ir para esse endereço.
1910
01:35:25,040 --> 01:35:28,910
>Mas, vá para aquele
endereço falso e coloque algo lá.
1911
01:35:28,910 --> 01:35:31,850
>E as chances são de que
seu programa irá falhar.
1912
01:35:31,850 --> 01:35:33,650
>Você vai ter uma falha
de segmentação,
1913
01:35:33,650 --> 01:35:37,562
>porque indo para algum endereço
de valor de lixo arbitrário,
1914
01:35:37,562 --> 01:35:40,520
>seria como pegar um pedaço de
papel aleatório com um número
1915
01:35:40,520 --> 01:35:42,030
>e então indo para essa caixa de correio.
1916
01:35:42,030 --> 01:35:42,530
>Por quê?
1917
01:35:42,530 --> 01:35:44,300
>Isso pertence a você.
1918
01:35:44,300 --> 01:35:47,930
>Se você tentar cancelar a referência
de uma variável não inicializada,
1919
01:35:47,930 --> 01:35:49,850
>seu programa pode muito bem travar.
1920
01:35:49,850 --> 01:35:51,890
>E isso é, talvez,
não melhor apresentado
1921
01:35:51,890 --> 01:35:55,970
>do que por alguns de nossos amigos, Nick
Parlante, um professor em Stanford
1922
01:35:55,970 --> 01:36:02,510
>Universidade que dá vida a um caractere
em claymation conhecido como Binky.
1923
01:36:02,510 --> 01:36:06,140
>Temos um clipe de 2 minutos disso
que mostra o quadro das coisas ruins
1924
01:36:06,140 --> 01:36:09,020
>acontecendo quando você
toca a memória que você não deveria.
1925
01:36:09,020 --> 01:36:13,340
>Felizmente, um lembrete útil sobre o que
fazer e o que não fazer com os ponteiros.
1926
01:36:13,340 --> 01:36:14,790
>Aqui vamos nós.
1927
01:36:14,790 --> 01:36:16,610
>[REPRODUÇÃO DE VÍDEO]
1928
01:36:16,610 --> 01:36:17,540
>- Ei, Binky.
1929
01:36:17,540 --> 01:36:20,890
>Acorde, é hora de se divertir com o ponteiro.
1930
01:36:20,890 --> 01:36:22,060
>- O que é aquilo?
1931
01:36:22,060 --> 01:36:23,620
>Aprender sobre ponteiros?
1932
01:36:23,620 --> 01:36:25,390
>Oh, que bom!
1933
01:36:25,390 --> 01:36:28,430
>- Bem, para começar, acho que
vamos precisar de algumas dicas.
1934
01:36:28,430 --> 01:36:32,940
>- OK, este código aloca dois ponteiros
que podem apontar para inteiros.
1935
01:36:32,940 --> 01:36:35,042
>- OK, bem, vejo as duas dicas.
1936
01:36:35,042 --> 01:36:37,000
>Mas eles não parecem estar
apontando para nada.
1937
01:36:37,000 --> 01:36:37,780
>- Isso está certo.
1938
01:36:37,780 --> 01:36:39,970
>Inicialmente, os ponteiros
não apontam para nada.
1939
01:36:39,970 --> 01:36:42,190
>As coisas para as quais eles
apontam são chamadas de pontas.
1940
01:36:42,190 --> 01:36:44,110
>E configurá-las é uma etapa separada.
1941
01:36:44,110 --> 01:36:45,100
>- Oh, certo, certo.
1942
01:36:45,100 --> 01:36:45,790
>Eu sabia.
1943
01:36:45,790 --> 01:36:47,750
>As pontas são separadas.
1944
01:36:47,750 --> 01:36:50,050
>Então, como você aloca uma ponta?
1945
01:36:50,050 --> 01:36:53,800
>- OK, bem, este código aloca
uma nova ponta inteira.
1946
01:36:53,800 --> 01:36:56,880
>E esta parte define x para apontar para ele.
1947
01:36:56,880 --> 01:36:58,180
>- Ei, isso parece melhor.
1948
01:36:58,180 --> 01:36:59,700
>Então faça algo.
1949
01:36:59,700 --> 01:37:05,460
>- OK, vou desreferenciar o ponteiro x
para armazenar o número 42 em sua ponta.
1950
01:37:05,460 --> 01:37:08,970
>Para este truque, vou precisar da minha
varinha mágica de desreferenciação.
1951
01:37:08,970 --> 01:37:12,660
>- Sua varinha mágica de desreferenciação?
1952
01:37:12,660 --> 01:37:14,170
>Isso é ótimo.
1953
01:37:14,170 --> 01:37:15,910
>- É assim que o código se parece.
1954
01:37:15,910 --> 01:37:17,800
>Vou apenas configurar o número e -
1955
01:37:18,900 --> 01:37:21,000
>- Ei, olha, aí vai.
1956
01:37:21,000 --> 01:37:25,830
>Portanto, fazer uma desreferenciação em
x segue a seta para acessar sua ponta.
1957
01:37:25,830 --> 01:37:28,020
>Nesse caso, para armazenar 42 ali.
1958
01:37:28,020 --> 01:37:32,450
>Ei, tente usá-lo para armazenar o número
13 por meio do outro ponteiro, y.
1959
01:37:32,450 --> 01:37:33,570
>- OK.
1960
01:37:33,570 --> 01:37:38,100
>Vou apenas ir aqui para y e
obter o número 13 configurado
1961
01:37:38,100 --> 01:37:41,970
>e, em seguida, pegar a varinha
de desreferenciação e apenas -
1962
01:37:41,970 --> 01:37:43,580
> uau!
1963
01:37:43,580 --> 01:37:45,930
>- Oh, ei, isso não funcionou.
1964
01:37:45,930 --> 01:37:51,370
>Diga, Binky, não acho que desreferenciar
y seja uma boa ideia, porque configurar
1965
01:37:51,370 --> 01:37:52,840
>a ponta é uma etapa separada.
1966
01:37:52,840 --> 01:37:54,815
>E acho que nunca fizemos isso.
1967
01:37:54,815 --> 01:37:56,430
>- Hmm, bom ponto.
1968
01:37:56,430 --> 01:37:58,800
>- Sim, alocamos o ponteiro y.
1969
01:37:58,800 --> 01:38:01,570
>Mas nunca o definimos para
apontar para uma ponta.
1970
01:38:01,570 --> 01:38:03,480
>- Hmm, muito observador.
1971
01:38:03,480 --> 01:38:05,310
>- Ei, você está bem aí, Binky.
1972
01:38:05,310 --> 01:38:08,250
>Você pode corrigi-lo de forma que
y aponte para a mesma ponta de x?
1973
01:38:08,250 --> 01:38:11,620
>- Claro, vou usar minha varinha
mágica de atribuição de ponteiro.
1974
01:38:11,620 --> 01:38:13,800
>- Isso vai ser um
problema como antes?
1975
01:38:13,800 --> 01:38:15,630
>- Não, isso não toca nas pontas.
1976
01:38:15,630 --> 01:38:19,170
>Ele apenas muda um ponteiro para
apontar para a mesma coisa que outro.
1977
01:38:19,170 --> 01:38:20,310
>- Oh, entendi.
1978
01:38:20,310 --> 01:38:23,040
>Agora, y aponta para o mesmo lugar que x.
1979
01:38:23,040 --> 01:38:24,840
>Então espere, agora y está consertado.
1980
01:38:24,840 --> 01:38:25,950
>Tem uma ponta.
1981
01:38:25,950 --> 01:38:29,760
>Portanto, você pode tentar a varinha de
desreferenciação novamente para enviar o 13.
1982
01:38:29,760 --> 01:38:31,093
>- Ah ok.
1983
01:38:31,093 --> 01:38:31,635
>Aqui vai.
1984
01:38:32,900 --> 01:38:34,160
>- Ei, olha isso.
1985
01:38:34,160 --> 01:38:35,870
>Agora, o desreferenciação funciona em y.
1986
01:38:35,870 --> 01:38:39,980
>porque os ponteiros estão compartilhando
aquele ponto, ambos veem o 13.
1987
01:38:39,980 --> 01:38:41,720
>- Sim, compartilhando, tanto faz.
1988
01:38:41,720 --> 01:38:43,610
>Então, vamos trocar de lugar agora?
1989
01:38:43,610 --> 01:38:45,270
>- Oh, olhe, estamos sem tempo.
1990
01:38:45,270 --> 01:38:45,770
>- Mas--
1991
01:38:45,770 --> 01:38:46,040
>[FIM DA REPRODUÇÃO]
1992
01:38:46,040 --> 01:38:47,570
>DAVID MALAN: Tudo bem, então
não estamos muito sem tempo.
1993
01:38:47,570 --> 01:38:50,028
>Mas vamos prosseguir e fazer nosso
segundo intervalo de 5 minutos aqui.
1994
01:38:50,028 --> 01:38:52,910
>E quando voltarmos, daremos uma olhada
mais de perto do Oscar e muito mais.
1995
01:38:52,910 --> 01:38:54,260
>De volta em 5.
1996
01:38:54,260 --> 01:38:57,380
>Tudo bem, então eu afirmo
que há todo esse lixo
1997
01:38:57,380 --> 01:38:58,950
>de valores na memória do seu computador.
1998
01:38:58,950 --> 01:39:00,860
>Mas como você pode vê-los?
1999
01:39:00,860 --> 01:39:04,400
>O que Binky fez foi, claro,
tentar cancelar a deferência de um valor de lixo
2000
01:39:04,400 --> 01:39:05,817
>quando coisas ruins acontecem.
2001
01:39:05,817 --> 01:39:07,900
>Mas podemos ver isso
com nosso próprio código.
2002
01:39:07,900 --> 01:39:10,970
>Então, agora eu vou
preparar um pequeno programa aqui,
2003
01:39:10,970 --> 01:39:15,290
>como algo que fizemos na
primeira ou segunda semana,
2004
01:39:15,290 --> 01:39:17,090
>mas sem fazer muito bem.
2005
01:39:17,090 --> 01:39:21,410
>Eu vou incluir o padrão io
ponto h, como de costume, int main void.
2006
01:39:21,410 --> 01:39:24,290
>E então agora eu vou dar a
mim mesmo uma série de scores.
2007
01:39:24,290 --> 01:39:26,000
>Que tal uma série de três scores?
2008
01:39:26,000 --> 01:39:28,715
>E já fizemos isso antes, quando
coletamos as scores de um usuário.
2009
01:39:28,715 --> 01:39:30,590
>Mas desta vez, vou
fazer deliberadamente
2010
01:39:30,590 --> 01:39:33,170
>o erro de não inicializar
essas scores
2011
01:39:33,170 --> 01:39:35,450
>ou mesmo pedindo ao humano
por essas scores.
2012
01:39:35,450 --> 01:39:41,060
>Vou continuar repetindo
cegamente de i igual a 0 até 3.
2013
01:39:41,060 --> 01:39:46,070
>E em cada iteração, vou imprimir
presunçosamente o que quer que seja
2014
01:39:46,070 --> 01:39:49,220
>naquele local na faixa de score i.
2015
01:39:49,220 --> 01:39:52,430
>Então, logicamente, meu código está
correto no que está tentando fazer,
2016
01:39:52,430 --> 01:39:54,230
>imprimir os valores em scores.
2017
01:39:54,230 --> 01:39:57,170
>Mas note que eu deliberadamente
não inicializei nenhuma
2018
01:39:57,170 --> 01:40:00,147
>das scores 1, 2, 3 nesse array.
2019
01:40:00,147 --> 01:40:01,730
>Então, quem sabe o que vai estar lá?
2020
01:40:01,730 --> 01:40:04,650
>Na verdade, devem ser valores
de lixo de algum tipo
2021
01:40:04,650 --> 01:40:06,650
>que não poderíamos necessariamente
prever antes.
2022
01:40:06,650 --> 01:40:10,050
>Então, agora eu vou fazer
lixo, uma vez que este programa
2023
01:40:10,050 --> 01:40:11,300
>está em um arquivo chamado garbage.c.
2024
01:40:11,300 --> 01:40:15,140
>Compila OK, mas quando
eu agora rodo garbage, nós
2025
01:40:15,140 --> 01:40:21,230
>devemos ver três scores, que são
cripticamente negativas, 833060864.
2026
01:40:21,230 --> 01:40:23,780
>Outro é 32765.
2027
01:40:23,780 --> 01:40:25,760
>E o terceiro simplesmente é 0.
2028
01:40:25,760 --> 01:40:28,490
>Então, existem esses valores de lixo,
porque novamente, o computador
2029
01:40:28,490 --> 01:40:31,800
>não inicializará nenhum
desses valores para você.
2030
01:40:31,800 --> 01:40:33,570
>Agora, existem exceções.
2031
01:40:33,570 --> 01:40:36,320
>Temos, na ocasião,
usou uma variável global,
2032
01:40:36,320 --> 01:40:40,490
>uma constante que está fora do contexto de
principal e de todas as minhas outras funções.
2033
01:40:40,490 --> 01:40:42,860
>Variáveis globais, se
você não defini-las,
2034
01:40:42,860 --> 01:40:47,210
>são inicializados convencionalmente
como 0 ou nul para você.
2035
01:40:47,210 --> 01:40:50,000
>Mas você geralmente não deve confiar
nesse tipo de comportamento.
2036
01:40:50,000 --> 01:40:53,120
>Seu instinto deve ser
sempre inicializar valores
2037
01:40:53,120 --> 01:40:56,630
>antes de pensar em
tocá-los ou lê-los
2038
01:40:56,630 --> 01:40:59,030
>como via printf ou algum outro mecanismo.
2039
01:40:59,030 --> 01:41:02,720
>Tudo bem, vamos ver como esse
entendimento, agora, de memória,
2040
01:41:02,720 --> 01:41:06,350
>pode nos levar a resolver problemas, mas
também encontrar novos tipos de problemas,
2041
01:41:06,350 --> 01:41:08,960
>mas problemas que agora
podemos entender.
2042
01:41:08,960 --> 01:41:11,250
>Vou prosseguir e criar
um novo programa aqui.
2043
01:41:11,250 --> 01:41:14,390
>E lembre-se da semana
passada que era muito comum
2044
01:41:14,390 --> 01:41:15,890
>querermos trocar valores.
2045
01:41:15,890 --> 01:41:19,010
>Quando Brian estava fazendo nossa
classificação por nós, fosse seleção ou bubble sort
2046
01:41:19,010 --> 01:41:21,710
>havia muitas
trocas acontecendo.
2047
01:41:21,710 --> 01:41:24,440
>Mesmo assim, não escrevemos nenhum
código para esses algoritmos.
2048
01:41:24,440 --> 01:41:25,232
>E isso é bom.
2049
01:41:25,232 --> 01:41:27,440
>Mas vamos considerar aquele
primitivo muito simples de apenas
2050
01:41:27,440 --> 01:41:30,440
>trocar dois valores, por
exemplo, trocando dois inteiros.
2051
01:41:30,440 --> 01:41:34,160
>Vamos prosseguir e iniciar
um programa e swap.c aqui.
2052
01:41:34,160 --> 01:41:38,630
>Vou incluir o padrão io
ponto h, int main void.
2053
01:41:38,630 --> 01:41:41,370
>E dentro do principal, vou
me dar dois inteiros.
2054
01:41:41,370 --> 01:41:44,960
>Vou criar um int chamado x
e atribuir a ele 1, um int chamado y
2055
01:41:44,960 --> 01:41:46,140
>e atribuir 2.
2056
01:41:46,140 --> 01:41:48,890
>E então agora eu vou
imprimir quais são esses valores.
2057
01:41:48,890 --> 01:41:55,520
>Direi apenas, x é percentual i
vírgula y é percentual i \ n.
2058
01:41:55,520 --> 01:41:59,490
>E então prosseguirei e imprimirei
x vírgula y, respectivamente.
2059
01:41:59,490 --> 01:42:02,930
>E então, eventualmente, irei
escrever uma função chamada
2060
01:42:02,930 --> 01:42:04,613
>swap que troca x e y.
2061
01:42:04,613 --> 01:42:06,530
>Mas vamos supor, por
enquanto, que exista.
2062
01:42:06,530 --> 01:42:08,870
>Não existe, porque o que
então eu quero fazer o certo
2063
01:42:08,870 --> 01:42:13,340
>depois disso, é reimprimir a
mesma coisa, x agora é % i,
2064
01:42:13,340 --> 01:42:17,690
>y é % i, minha suposição
é que os valores de x e y
2065
01:42:17,690 --> 01:42:18,870
>serão trocados.
2066
01:42:18,870 --> 01:42:20,480
>Então, como posso trocar esses dois valores?
2067
01:42:20,480 --> 01:42:23,120
>Bem, deixe-me seguir em frente e
implementar minha própria função.
2068
01:42:23,120 --> 01:42:25,110
>Não acho que precise
retornar nada,
2069
01:42:25,110 --> 01:42:27,110
>então direi void é
o tipo de retorno.
2070
01:42:27,110 --> 01:42:28,340
>Vou chamar de swap.
2071
01:42:28,340 --> 01:42:30,830
>Terá dois argumentos
como entrada.
2072
01:42:30,830 --> 01:42:33,320
>Vamos chamar de a e b, ambos inteiros.
2073
01:42:33,320 --> 01:42:34,820
>Mas eu poderia chamar do que eu quiser.
2074
01:42:34,820 --> 01:42:36,800
>Mas a e b parecem razoáveis.
2075
01:42:36,800 --> 01:42:39,350
>E agora, quero ir em frente
e trocar dois valores.
2076
01:42:39,350 --> 01:42:42,140
>Agora, Brian estava fazendo isso com
as duas mãos na semana passada.
2077
01:42:42,140 --> 01:42:45,830
>E isso é bom, mas provavelmente devemos
considerar isso um pouco mais de perto.
2078
01:42:45,830 --> 01:42:48,050
>Na verdade, Brian, em
vez de números, vamos
2079
01:42:48,050 --> 01:42:49,920
>faça algo um pouco mais do mundo real.
2080
01:42:49,920 --> 01:42:53,080
>Acho que você tem algumas
bebidas na sua frente.
2081
01:42:53,080 --> 01:42:53,580
>BRIAN: Sim.
2082
01:42:53,580 --> 01:42:56,220
>Então, bem aqui, eu tenho um
vidro vermelho e um vidro azul,
2083
01:42:56,220 --> 01:42:58,970
>que acho que podemos usar para
representar duas variáveis, por exemplo.
2084
01:42:58,970 --> 01:42:59,180
>DAVID MALAN: Sim.
2085
01:42:59,180 --> 01:43:00,198
>Agora, deixe-me supor -
2086
01:43:00,198 --> 01:43:01,490
>Eu gostaria de ter contado a você antes.
2087
01:43:01,490 --> 01:43:03,920
>Na verdade, prefiro que
o líquido vermelho seja
2088
01:43:03,920 --> 01:43:07,050
>no vidro azul e o líquido
azul no vidro vermelho.
2089
01:43:07,050 --> 01:43:08,780
>Então você se importa em
trocar esses dois valores,
2090
01:43:08,780 --> 01:43:11,310
>assim como você trocou de números na semana passada?
2091
01:43:11,310 --> 01:43:12,060
>BRIAN: Sim, claro.
2092
01:43:12,060 --> 01:43:14,810
>Então, posso apenas pegar os dois copos,
e posso trocar de lugar.
2093
01:43:14,810 --> 01:43:17,717
>DAVID MALAN: OK, espere,
OK, isso não é exatamente -
2094
01:43:17,717 --> 01:43:18,800
>você me interpretou muito literalmente.
2095
01:43:18,800 --> 01:43:22,760
>Acho que aqui, se pensarmos no copos,
agora, como locais específicos
2096
01:43:22,760 --> 01:43:24,980
>na memória, você não pode
apenas mover fisicamente
2097
01:43:24,980 --> 01:43:27,540
>os chips de memória dentro do seu
computador para trocar coisas.
2098
01:43:27,540 --> 01:43:30,410
>Acho que literalmente preciso
que você mova o líquido azul
2099
01:43:30,410 --> 01:43:33,350
>no vidro vermelho e o líquido
vermelho no vidro azul
2100
01:43:33,350 --> 01:43:36,100
>para que seja mais como a
memória de um computador.
2101
01:43:36,100 --> 01:43:37,657
>BRIAN: OK, posso tentar fazer isso.
2102
01:43:37,657 --> 01:43:40,240
>Estou um pouco nervoso, no entanto,
porque eu sinto que não posso simplesmente
2103
01:43:40,240 --> 01:43:43,270
>despejar o líquido azul no vidro vermelho,
porque o líquido vermelho já está
2104
01:43:43,270 --> 01:43:43,640
>lá.
2105
01:43:43,640 --> 01:43:45,730
>DAVID MALAN: Sim, então isso
provavelmente não termina bem,
2106
01:43:45,730 --> 01:43:48,220
>se ele tem que fazer algum tipo
de troca entre os dois copos.
2107
01:43:48,220 --> 01:43:49,240
>Então, alguma ideia aqui?
2108
01:43:49,240 --> 01:43:54,100
>Como qual é a solução do mundo real para
este problema estranho, mas real, onde
2109
01:43:54,100 --> 01:43:57,490
>queremos trocar o conteúdo
desses dois locais,
2110
01:43:57,490 --> 01:44:01,180
>assim como Brian estava trocando o
conteúdo de dois locais de memória
2111
01:44:01,180 --> 01:44:02,290
>na semana anterior?
2112
01:44:02,290 --> 01:44:04,900
>Brian, se você estiver de
olho no chat em paralelo,
2113
01:44:04,900 --> 01:44:08,480
>alguém poderia ter ideias sobre como
poderíamos trocar esses dois líquidos?
2114
01:44:08,480 --> 01:44:11,620
>BRIAN: Sim, algumas pessoas estão dizendo
que preciso de um terceiro copo.
2115
01:44:11,620 --> 01:44:13,370
>DAVID MALAN: Tudo bem,
bem Brian, você
2116
01:44:13,370 --> 01:44:16,370
>por acaso tem um terceiro
copo com você atrás do palco?
2117
01:44:16,370 --> 01:44:18,040
>BRIAN: Na verdade, acho que sim.
2118
01:44:18,040 --> 01:44:21,190
>Então, eu tenho um terceiro copo
aqui que por acaso está vazio.
2119
01:44:21,190 --> 01:44:22,100
>DAVID MALAN: OK.
2120
01:44:22,100 --> 01:44:25,610
>E como você faria para
trocar essas duas coisas?
2121
01:44:25,610 --> 01:44:28,870
>BRIAN: Tudo bem, então eu quero colocar
o líquido azul dentro do copo vermelho.
2122
01:44:28,870 --> 01:44:30,578
>Então, a primeira coisa que
preciso fazer, eu acho,
2123
01:44:30,578 --> 01:44:34,040
>é esvaziar o copo vermelho
para dar espaço ao líquido azul.
2124
01:44:34,040 --> 01:44:36,310
>Vou pegar o líquido
vermelho e só
2125
01:44:36,310 --> 01:44:38,470
>vou despejá-lo neste copo extra.
2126
01:44:38,470 --> 01:44:39,520
>DAVID MALAN: Mas temporariamente, certo?
2127
01:44:39,520 --> 01:44:39,870
>BRIAN: Temporariamente, sim.
2128
01:44:39,870 --> 01:44:40,570
>DAVID MALAN: OK.
2129
01:44:40,570 --> 01:44:42,620
>BRIAN: Só para guardar aí.
2130
01:44:42,620 --> 01:44:45,100
>E agora, acho que posso apenas
derramar o líquido azul
2131
01:44:45,100 --> 01:44:48,942
>no vidro vermelho original,
porque agora estou livre para fazer isso.
2132
01:44:48,942 --> 01:44:50,400
>Então, vou derramar o líquido azul ali.
2133
01:44:53,230 --> 01:44:56,220
>E acho que a última coisa que preciso
fazer agora é, agora este azul -
2134
01:44:56,220 --> 01:44:59,680
>este copo que originalmente continha
o líquido azul agora está vazio.
2135
01:44:59,680 --> 01:45:03,130
>Então, o líquido vermelho, que estava
dentro deste vidro temporário aqui,
2136
01:45:03,130 --> 01:45:07,350
>Posso pegar o líquido vermelho e
apenas despejá-lo neste copo aqui.
2137
01:45:07,350 --> 01:45:10,290
>E agora, não troquei as
posições dos copos.
2138
01:45:10,290 --> 01:45:12,390
>Mas os líquidos
trocaram de lugar.
2139
01:45:12,390 --> 01:45:15,355
>Agora, o líquido azul está à esquerda
e o líquido vermelho está à direita.
2140
01:45:15,355 --> 01:45:16,230
>DAVID MALAN: Incrível.
2141
01:45:16,230 --> 01:45:18,660
>Sim, acho que é uma
implementação mais literal
2142
01:45:18,660 --> 01:45:21,150
>do que você estava fazendo e dando
como certo na semana passada,
2143
01:45:21,150 --> 01:45:24,182
>trocando os dois valores
em dois locais separados.
2144
01:45:24,182 --> 01:45:25,640
>Portanto, parece muito simples.
2145
01:45:25,640 --> 01:45:27,210
>Só preciso de um pouco mais de espaço.
2146
01:45:27,210 --> 01:45:29,670
>Preciso de uma variável
temporária no código.
2147
01:45:29,670 --> 01:45:31,545
>E parece que preciso de três etapas.
2148
01:45:31,545 --> 01:45:34,670
>Eu preciso derramar um, despejar o
outro fora, despejar o outro de volta.
2149
01:45:34,670 --> 01:45:37,122
>Então, acho que posso
traduzir isso em código aqui.
2150
01:45:37,122 --> 01:45:39,330
>Eu vou me
dar uma variável temporária,
2151
01:45:39,330 --> 01:45:40,840
>como um copo, como Brian fez.
2152
01:45:40,840 --> 01:45:43,650
>E vou chamar de tmp, T-M-P,
o que é bem convencional quando
2153
01:45:43,650 --> 01:45:45,180
>é melhor trocar duas coisas no código.
2154
01:45:45,180 --> 01:45:47,850
>E eu vou assinar,
temporariamente, o valor de a.
2155
01:45:47,850 --> 01:45:51,550
>Vou então alterar o conteúdo de a para
igual a qualquer que seja o conteúdo de B
2156
01:45:52,050 --> 01:45:56,010
>E então vou mudar b para ser qualquer
que fosse o conteúdo de tmp.
2157
01:45:56,010 --> 01:45:58,650
>Isso parece bastante
razoável e correto,
2158
01:45:58,650 --> 01:46:01,230
>porque é uma
tradução literal em código,
2159
01:46:01,230 --> 01:46:03,700
>agora, do que Brian
fez no mundo real.
2160
01:46:03,700 --> 01:46:05,610
>E acho que isso vai compilar.
2161
01:46:05,610 --> 01:46:08,040
>Então, vamos começar por aí, fazer a troca.
2162
01:46:08,040 --> 01:46:09,690
>Ele -- não compila.
2163
01:46:09,690 --> 01:46:13,410
>OK, declaração implícita anterior,
tantos erros, meu Deus.
2164
01:46:13,410 --> 01:46:15,687
>Declaração implícita de troca de função -
2165
01:46:15,687 --> 01:46:16,270
>espere um minuto.
2166
01:46:16,270 --> 01:46:17,230
>Eu já vi isso antes.
2167
01:46:17,230 --> 01:46:18,480
>Já cometi esse erro antes.
2168
01:46:18,480 --> 01:46:20,050
>Você também pode ter cometido.
2169
01:46:20,050 --> 01:46:23,293
>Sempre que vir isso, lembre-se de
que está faltando seu protótipo.
2170
01:46:23,293 --> 01:46:25,710
>Lembre-se de que o compilador
irá interpretá-lo literalmente.
2171
01:46:25,710 --> 01:46:28,500
>E se ele não souber que a palavra
troca existe quando a vir,
2172
01:46:28,500 --> 01:46:30,310
>não vai ser compilado com sucesso.
2173
01:46:30,310 --> 01:46:33,030
>Portanto, precisamos incluir meu
protótipo no topo do meu arquivo.
2174
01:46:33,030 --> 01:46:35,460
>Agora, deixe-me tentar novamente, make swap.
2175
01:46:35,460 --> 01:46:36,780
>OK, isso compila.
2176
01:46:36,780 --> 01:46:40,950
>Vou continuar agora e executar o
swap e relembrar que, em geral, o que eu fiz
2177
01:46:40,950 --> 01:46:43,380
>foi inicializado x para 1, y para 2.
2178
01:46:43,380 --> 01:46:45,900
>Em seguida, imprimo o
que é x e o que é y.
2179
01:46:45,900 --> 01:46:50,040
>Eu chamo swap e imprimo
o que é x e y novamente.
2180
01:46:50,040 --> 01:46:52,770
>Devo ver 1, 2 e 2, 1.
2181
01:46:52,770 --> 01:46:55,430
>Então, vamos apertar Enter.
2182
01:46:55,430 --> 01:46:58,800
>Huh, não parece estar funcionando.
2183
01:46:58,800 --> 01:47:01,740
>Bem, vamos tentar novamente, apenas no caso -
2184
01:47:01,740 --> 01:47:04,020
>não, não está funcionando.
2185
01:47:04,020 --> 01:47:05,530
>Bem, deixe-me tentar isso.
2186
01:47:05,530 --> 01:47:07,590
>Vamos adicionar alguns-- printf é meu amigo.
2187
01:47:07,590 --> 01:47:10,971
>Vamos prosseguir e dizer que a é % i.
2188
01:47:10,971 --> 01:47:14,460
>b é a % i \ n, a, b.
2189
01:47:14,460 --> 01:47:15,510
>Então, vamos imprimir isso.
2190
01:47:15,510 --> 01:47:16,650
>E vamos imprimir isso duas vezes.
2191
01:47:16,650 --> 01:47:18,480
>Portanto, esta seria uma
técnica de depuração razoável.
2192
01:47:18,480 --> 01:47:21,605
>Se você quiser saber o que está acontecendo
por baixo do capô, adicione alguns printf's.
2193
01:47:21,605 --> 01:47:23,760
>Eu vou fazer make swap.
2194
01:47:23,760 --> 01:47:26,520
>Isso compila, ./swap.
2195
01:47:26,520 --> 01:47:32,880
>E vamos ver, a é 1,
b é 2, a é 2, b é 1.
2196
01:47:32,880 --> 01:47:35,470
>Mas então x e y permanecem inalterados.
2197
01:47:35,470 --> 01:47:37,170
>Então eu sinto que minha lógica está certa.
2198
01:47:37,170 --> 01:47:38,550
>Está trocando a e b.
2199
01:47:38,550 --> 01:47:41,490
>Mas, na verdade, não está trocando x e y.
2200
01:47:41,490 --> 01:47:43,340
>E eu poderia confirmar isso, certo?
2201
01:47:43,340 --> 01:47:45,510
>A maneira mais poderosa
de depurar isso seria
2202
01:47:45,510 --> 01:47:49,890
>executar debug50, definir um ponto
de interrupção, por exemplo, na linha 17,
2203
01:47:49,890 --> 01:47:54,270
>percorrer meu código, passo a passo,
entrando na função swap.
2204
01:47:54,270 --> 01:47:57,030
>Mas, por enquanto, parece
claro que a troca funciona.
2205
01:47:57,030 --> 01:48:00,250
>Mas o main não está
vendo esses resultados.
2206
01:48:00,250 --> 01:48:01,450
>Então, o que está acontecendo?
2207
01:48:01,450 --> 01:48:04,170
>Bem, vamos considerar esta encarnação
do mundo real do que minha memória é
2208
01:48:04,170 --> 01:48:05,712
>para que eu possa mover as coisas.
2209
01:48:05,712 --> 01:48:08,820
>E tudo isso graças aos nossos amigos na
loja de acessórios do teatro nos fundos.
2210
01:48:08,820 --> 01:48:10,830
>Se pensarmos nisso como a
memória do meu computador,
2211
01:48:10,830 --> 01:48:12,540
>inicialmente, são todos valores de lixo.
2212
01:48:12,540 --> 01:48:16,080
>Mas posso usar isso como uma tela para
começar a projetar as coisas na memória.
2213
01:48:16,080 --> 01:48:19,020
>Mas chamar funções é algo que
achamos ser algo fácil e tranquilo, até aqui.
2214
01:48:19,020 --> 01:48:22,200
>E acontece que, quando você chama
funções, o computador, por padrão,
2215
01:48:22,200 --> 01:48:25,500
>usa essa memória de
uma forma padrão.
2216
01:48:25,500 --> 01:48:29,850
>Na verdade, agora eu vou
fazer um desenho mais gráfico.
2217
01:48:29,850 --> 01:48:33,440
>Vamos desenhar uma imagem mais literal aqui,
se assim preferir, da memória do computador
2218
01:48:33,440 --> 01:48:33,940
>novamente.
2219
01:48:33,940 --> 01:48:36,660
>Então, se esta for a memória do computador
e fizermos zoom em um dos chips,
2220
01:48:36,660 --> 01:48:39,120
>e pensamos no chip como tendo
um monte de bytes assim.
2221
01:48:39,120 --> 01:48:42,390
>Vamos abstrair o hardware real
e pensar nele como sempre foi.
2222
01:48:42,390 --> 01:48:45,720
>É apenas esta grande região retangular da
memória, não muito diferente de todos aqueles
2223
01:48:45,720 --> 01:48:47,520
>Oscars de um momento atrás.
2224
01:48:47,520 --> 01:48:51,150
>Mas, por convenção, seu computador
não fica apenas inserindo coisas
2225
01:48:51,150 --> 01:48:52,710
>em locais aleatórios na memória.
2226
01:48:52,710 --> 01:48:55,710
>Ele segue certas
regras básicas.
2227
01:48:55,710 --> 01:48:59,460
>Em particular, ele trata diferentes
partes da memória do seu computador
2228
01:48:59,460 --> 01:49:00,330
>de maneiras diferentes.
2229
01:49:00,330 --> 01:49:03,570
>Ele o usa de uma maneira padrão para
que não seja completamente aleatório.
2230
01:49:03,570 --> 01:49:08,910
>Por exemplo, quando você executa um programa
fazendo alguma ./ no IDE CS50
2231
01:49:08,910 --> 01:49:12,270
>ou no Linux de forma mais geral, ou você
clica duas vezes em um ícone no Mac OS
2232
01:49:12,270 --> 01:49:16,590
>ou Windows, que
aciona o computador -
2233
01:49:16,590 --> 01:49:21,030
>os 0's e 1's do programa armazenados no seu
disco rígido para serem carregados aqui,
2234
01:49:21,030 --> 01:49:23,742
>ao que chamaremos de código de máquina,
que, novamente, são os 0's e 1's.
2235
01:49:23,742 --> 01:49:25,950
>Então, se você pensar novamente,
metaforicamente, como sua memória
2236
01:49:25,950 --> 01:49:29,730
>é esta região retangular,
então o código de máquina,
2237
01:49:29,730 --> 01:49:35,732
>os 0's e 1's que compõem seu programa são
carregados na parte superior da memória.
2238
01:49:35,732 --> 01:49:38,940
>E, novamente, superior, inferior, esquerda, direita,
não tem nenhum significado técnico fundamental.
2239
01:49:38,940 --> 01:49:40,470
>É apenas uma representação técnica.
2240
01:49:40,470 --> 01:49:42,960
>Mas ele vai para um local padrão.
2241
01:49:42,960 --> 01:49:45,700
>Abaixo disso estão todas
as suas variáveis globais.
2242
01:49:45,700 --> 01:49:48,250
>O mesmo ocorre com as constantes que
você coloca fora de suas funções.
2243
01:49:48,250 --> 01:49:50,500
>Isso vai acabar logo abaixo
do código de máquina,
2244
01:49:50,500 --> 01:49:53,340
>novamente, no topo da
memória do seu computador.
2245
01:49:53,340 --> 01:49:55,200
>Abaixo disso está o que é chamado de heap.
2246
01:49:55,200 --> 01:49:56,940
>E este é um termo técnico.
2247
01:49:56,940 --> 01:50:00,780
>E se refere a um grande
pedaço de memória que malloc
2248
01:50:00,780 --> 01:50:03,640
>usa para obter alguma memória sobressalente.
2249
01:50:03,640 --> 01:50:09,270
>Sempre que você chamar malloc, você recebe
o endereço de algum pedaço de memória
2250
01:50:09,270 --> 01:50:13,200
>sobre nesta região, abaixo do código de
máquina, abaixo de suas variáveis globais.
2251
01:50:13,200 --> 01:50:15,270
>E é uma zona grande.
2252
01:50:15,270 --> 01:50:19,120
>Mas o problema é que outras partes da sua
memória são usadas de maneira diferente.
2253
01:50:19,120 --> 01:50:24,570
>Na verdade, embora a pilha seja
considerada aqui embaixo, um pouco
2254
01:50:24,570 --> 01:50:28,830
>preocupantemente, a pilha é
considerada aqui para cima.
2255
01:50:28,830 --> 01:50:32,070
>Ou seja, quando você chama
malloc e pede memória,
2256
01:50:32,070 --> 01:50:35,670
>que é alocado aqui.
2257
01:50:35,670 --> 01:50:39,540
>Quando você chama uma função,
embora, essas funções
2258
01:50:39,540 --> 01:50:42,900
>usem o que é chamado de espaço de
pilha em vez de espaço de pilha.
2259
01:50:42,900 --> 01:50:48,450
>Então, sempre que você chamar uma função, main
ou swap ou strlang ou string compare
2260
01:50:48,450 --> 01:50:51,330
>ou qualquer uma das funções
que você usou até agora,
2261
01:50:51,330 --> 01:50:54,150
>seu computador irá armazenar
automaticamente qualquer
2262
01:50:54,150 --> 01:50:58,860
>das variáveis locais ou
parâmetros dessas funções aqui.
2263
01:50:58,860 --> 01:51:00,840
>Agora, este não é necessariamente
o melhor design,
2264
01:51:00,840 --> 01:51:02,550
>porque você pode ver as duas
setas apontando para uma
2265
01:51:02,550 --> 01:51:05,383
>outra - é como dois trens correndo
pelos trilhos um contra o outro.
2266
01:51:05,383 --> 01:51:07,268
>Coisas ruins podem acontecer.
2267
01:51:07,268 --> 01:51:09,060
>Felizmente, normalmente
temos memória suficiente
2268
01:51:09,060 --> 01:51:12,370
>para que essas duas coisas não colidam,
mas mais nisso daqui a pouco.
2269
01:51:12,370 --> 01:51:15,570
>Então, novamente, quando você chama funções,
a memória aqui embaixo é usada.
2270
01:51:15,570 --> 01:51:17,710
>Quando você usa malloc,
a memória aqui é usada.
2271
01:51:17,710 --> 01:51:19,710
>Agora, para minha função swap,
eu não estou usando malloc.
2272
01:51:19,710 --> 01:51:21,690
>Então eu não acho que tenho
que me preocupar com a pilha.
2273
01:51:21,690 --> 01:51:23,283
>E eu não tenho nenhuma variável global.
2274
01:51:23,283 --> 01:51:25,200
>E eu não me importo
com meu código de máquina.
2275
01:51:25,200 --> 01:51:27,240
>Eu só preciso saber se está
armazenado em algum lugar.
2276
01:51:27,240 --> 01:51:30,210
>Mas vamos considerar, então,
do que se trata a pilha.
2277
01:51:30,210 --> 01:51:32,670
>A pilha, é esse
tipo de lugar dinâmico
2278
01:51:32,670 --> 01:51:34,860
>onde a memória continua
sendo usada e reutilizada.
2279
01:51:34,860 --> 01:51:40,440
>Então, por exemplo, quando você chama main,
como você faria quando swap roda,
2280
01:51:40,440 --> 01:51:45,010
>main usa uma porção de memória na
parte inferior da imagem, se preferir.
2281
01:51:45,010 --> 01:51:47,910
>Portanto, as variáveis locais
principais, como x e y,
2282
01:51:47,910 --> 01:51:49,920
>acabam nesta parte inferior da memória.
2283
01:51:49,920 --> 01:51:53,790
>Quando você chama o swap, o swap usa um
pedaço de memória logo acima do principal,
2284
01:51:53,790 --> 01:51:58,350
>neste diagrama,
como as variáveis a e b e temp,
2285
01:51:58,350 --> 01:51:59,410
>para essa ação.
2286
01:51:59,410 --> 01:52:04,680
>E então, uma vez que o swap retorna e termina
a execução, aquele pedaço de memória
2287
01:52:04,680 --> 01:52:06,010
>vai embora.
2288
01:52:06,010 --> 01:52:07,230
>Agora, ele não desaparece.
2289
01:52:07,230 --> 01:52:09,610
>Obviamente, ainda há
memória física lá.
2290
01:52:09,610 --> 01:52:12,810
>Mas é aí que entramos na discussão
dos valores lixo novamente.
2291
01:52:12,810 --> 01:52:15,540
>Eles ainda são como Oscar
por toda parte.
2292
01:52:15,540 --> 01:52:18,600
>Você simplesmente não sabe, ou neste
ponto nem se importa, quais são os valores.
2293
01:52:18,600 --> 01:52:20,010
>Mas existem valores aí.
2294
01:52:20,010 --> 01:52:23,640
>E é por isso que, um momento atrás, quando
imprimi aquele array scores não inicializado,
2295
01:52:23,640 --> 01:52:26,970
>eu vi alguns valores
falsos, porque ainda
2296
01:52:26,970 --> 01:52:30,510
>vai haver 0's e 1's que
sobraram de antes.
2297
01:52:30,510 --> 01:52:31,750
>O problema, porém, é este.
2298
01:52:31,750 --> 01:52:35,070
>Vamos passar para esta
encarnação física de nossa memória
2299
01:52:35,070 --> 01:52:38,010
>e considero isso como sendo nossa
pilha, por isso está crescendo.
2300
01:52:38,010 --> 01:52:42,060
>E, se eu quiser ter duas
variáveis locais como eu faço, x e y,
2301
01:52:42,060 --> 01:52:47,400
>vamos prosseguir e pensar nesta linha
de memória aqui como sendo main,
2302
01:52:47,400 --> 01:52:48,870
>por exemplo, aqui.
2303
01:52:48,870 --> 01:52:51,630
>E vou prosseguir e substituir
todos esses valores de lixo
2304
01:52:51,630 --> 01:52:53,790
>com um valor real pelo qual me preocupo.
2305
01:52:53,790 --> 01:52:57,660
>E os valores reais que me interessam,
vamos chamar x e y, assim como
2306
01:52:57,660 --> 01:52:58,480
>antes.
2307
01:52:58,480 --> 01:53:01,020
>Portanto, cada um desses
Oscars tem um byte.
2308
01:53:01,020 --> 01:53:02,068
>Mas um int tem 4 bytes.
2309
01:53:02,068 --> 01:53:04,110
>Felizmente, de nossos
amigos da loja de presentes,
2310
01:53:04,110 --> 01:53:06,178
>temos esses blocos maiores
de tamanho inteiro.
2311
01:53:06,178 --> 01:53:08,220
>E vou prosseguir e
inserir isso aqui.
2312
01:53:08,220 --> 01:53:10,740
>E vamos pensar nisso,
em um momento, como x.
2313
01:53:10,740 --> 01:53:14,340
>E, vou prosseguir e
chamar esse x com um marcador.
2314
01:53:14,340 --> 01:53:17,760
>E então vou criar
outro número inteiro, um tamanho 4,
2315
01:53:17,760 --> 01:53:19,300
>e colocar aqui.
2316
01:53:19,300 --> 01:53:21,300
>E vamos pensar nisso como y.
2317
01:53:21,300 --> 01:53:23,940
>E lembre-se, como eu
inicializo esses valores?
2318
01:53:23,940 --> 01:53:27,690
>Bem, o valor 1,
inicialmente, e o valor 2.
2319
01:53:27,690 --> 01:53:29,370
>Mas então chamei a função swap.
2320
01:53:29,370 --> 01:53:32,160
>E a função swap tem
dois argumentos, a e b.
2321
01:53:32,160 --> 01:53:38,400
>E esses, por design, tornam-se cópias
de x e y, porque passei x vírgula y.
2322
01:53:38,400 --> 01:53:41,280
>E eu defini troca como uma vírgula b.
2323
01:53:41,280 --> 01:53:44,970
>Acho que o que preciso fazer,
fisicamente aqui, e agora
2324
01:53:44,970 --> 01:53:50,170
>pense nesta segunda linha de memória como
agora pertencente à função swap,
2325
01:53:50,170 --> 01:53:51,210
>não para main.
2326
01:53:51,210 --> 01:53:54,090
>E dentro desta segunda
linha de memória, eu irei
2327
01:53:54,090 --> 01:53:57,540
>pensar nisso como pertencendo a uma troca.
2328
01:53:57,540 --> 01:54:02,100
>E dentro da linha de troca, terei
outro inteiro de tamanho 4.
2329
01:54:02,100 --> 01:54:07,500
>E vamos chamar
este aqui de a.
2330
01:54:07,500 --> 01:54:10,350
>E então terei outro
pedaço de tamanho 4.
2331
01:54:10,350 --> 01:54:12,600
>E vamos chamar isso de b.
2332
01:54:12,600 --> 01:54:16,050
>E, novamente, porque esses são apenas os
argumentos, x vírgula y, caso contrário
2333
01:54:16,050 --> 01:54:20,760
>agora conhecido como vírgula b, copio
1 e 2 nesses valores.
2334
01:54:20,760 --> 01:54:22,770
>Mas swap tem uma terceira variável.
2335
01:54:22,770 --> 01:54:24,730
>Brian propôs uma variável temporária.
2336
01:54:24,730 --> 01:54:27,480
>Vou criar
mais quatro bytes,
2337
01:54:27,480 --> 01:54:30,210
>assim, livrando-se de qualquer
valor de lixo que esteja lá
2338
01:54:30,210 --> 01:54:34,260
>e configurá-la para uma chamada
de número inteiro tmp.
2339
01:54:34,260 --> 01:54:39,030
>Portanto, vou prosseguir e
chamar isso de tmp, T-M-P.
2340
01:54:39,030 --> 01:54:40,440
>E o que eu fiz primeiro?
2341
01:54:40,440 --> 01:54:43,845
>Defino tmp igual a a.
2342
01:54:43,845 --> 01:54:45,120
>Portanto, tmp é igual a a.
2343
01:54:45,120 --> 01:54:47,520
>Portanto, se a for 1, tmp será 1.
2344
01:54:47,520 --> 01:54:48,750
>Então o que eu fiz?
2345
01:54:48,750 --> 01:54:51,780
>Então fiz a é igual a b.
2346
01:54:51,780 --> 01:54:55,150
>Portanto, b é 2.
2347
01:54:55,150 --> 01:54:57,800
>a também é 2.
2348
01:54:57,800 --> 01:55:00,030
>E então, por último, o que eu fiz?
2349
01:55:00,030 --> 01:55:02,145
>Eu fiz b get tmp.
2350
01:55:02,145 --> 01:55:05,020
>Então eu tenho que ir em frente e
mudar isso para qualquer valor de tmp,
2351
01:55:05,020 --> 01:55:07,630
>que agora é o número 1.
2352
01:55:07,630 --> 01:55:10,150
>Então você pode ver que a troca
está correta na medida em que
2353
01:55:10,150 --> 01:55:12,655
> está trocando os valores de a e b.
2354
01:55:12,655 --> 01:55:16,690
>Mas no momento em que o swap
retorna, estes retornam
2355
01:55:16,690 --> 01:55:19,000
>a ser pensados como valores de lixo.
2356
01:55:19,000 --> 01:55:20,860
>Main ainda está no meio da execução.
2357
01:55:20,860 --> 01:55:22,300
>A troca não está mais em execução.
2358
01:55:22,300 --> 01:55:23,743
>Mas esses valores permanecem lá.
2359
01:55:23,743 --> 01:55:24,910
>Portanto, esses são valores de lixo.
2360
01:55:24,910 --> 01:55:27,850
>Acontece que sabemos o que são,
mas eles não são mais válidos,
2361
01:55:27,850 --> 01:55:32,560
>porque quando vou imprimir x e y
pela segunda vez, o que são x e y?
2362
01:55:32,560 --> 01:55:33,820
>Eles ainda são os mesmos.
2363
01:55:33,820 --> 01:55:37,870
>E isso quer dizer, quando você
escreve um código que leva argumentos
2364
01:55:37,870 --> 01:55:40,750
>e você passa argumentos
de uma função para outra,
2365
01:55:40,750 --> 01:55:43,930
>esses argumentos são copiados
de uma função para outra.
2366
01:55:43,930 --> 01:55:47,140
>E, x e y são
copiados em a e b.
2367
01:55:47,140 --> 01:55:51,670
>Portanto, seu código pode muito bem parecer
correto por estar alternando corretamente.
2368
01:55:51,670 --> 01:55:55,750
>Mas só está trocando corretamente
no contexto de troca,
2369
01:55:55,750 --> 01:55:58,370
>não tocar nos valores originais.
2370
01:55:58,370 --> 01:56:00,730
>Então, o que acho que precisamos
fazer, fundamentalmente,
2371
01:56:00,730 --> 01:56:06,130
>é reimplementar a troca
de forma que
2372
01:56:06,130 --> 01:56:10,450
>altere os valores de x e y.
2373
01:56:10,450 --> 01:56:11,500
>Mas como podemos fazer isso?
2374
01:56:11,500 --> 01:56:13,810
>Brian, se pudéssemos chamar alguém aqui.
2375
01:56:13,810 --> 01:56:18,340
>Como eu poderia mudar conceitualmente
minha implementação de swap
2376
01:56:18,340 --> 01:56:26,110
>para que de alguma forma me capacite a
alterar x e y, não alterar cópias de x e y?
2377
01:56:26,110 --> 01:56:28,570
>O que eu poderia passar para swap, Brian?
2378
01:56:28,570 --> 01:56:31,150
>BRIAN: Igor está sugerindo que
usemos ponteiros em seu lugar.
2379
01:56:31,150 --> 01:56:33,733
>DAVID MALAN: Sim, talvez a
questão principal aqui hoje.
2380
01:56:33,733 --> 01:56:36,010
>Mas as dicas parecem
nos dar uma solução.
2381
01:56:36,010 --> 01:56:38,170
>Se os ponteiros são
como um mapa do tesouro
2382
01:56:38,170 --> 01:56:41,500
>apontando para um endereço específico na memória
do seu computador, o que eu deveria
2383
01:56:41,500 --> 01:56:45,940
>fazer a partir do main para swap
é passar não x e y literalmente,
2384
01:56:45,940 --> 01:56:49,630
>mas por que não passo o
endereço de x e o endereço de y,
2385
01:56:49,630 --> 01:56:53,230
>para que a troca agora possa
ir para esses endereços
2386
01:56:53,230 --> 01:56:57,460
>e fazer o tipo de troca
que Brian fez pessoalmente.
2387
01:56:57,460 --> 01:57:02,050
>Então, dê à função uma espécie de mapa para
esses valores, ponteiros para esses valores,
2388
01:57:02,050 --> 01:57:03,560
>e depois vá para esses valores.
2389
01:57:03,560 --> 01:57:04,580
>Então, como posso fazer isso?
2390
01:57:04,580 --> 01:57:06,580
>Bem, o código tem que ser
um pouco diferente agora.
2391
01:57:06,580 --> 01:57:09,640
>Quando eu chamo swap desta vez,
o que eu preciso fazer
2392
01:57:09,640 --> 01:57:12,710
>é passar os endereços
dessas duas variáveis.
2393
01:57:12,710 --> 01:57:14,950
>Portanto, não sei necessariamente
quais são esses endereços.
2394
01:57:14,950 --> 01:57:16,900
>Mas pelo bem da história,
podemos apenas
2395
01:57:16,900 --> 01:57:21,340
>supor que este endereço,
por exemplo, é como 0x123.
2396
01:57:21,340 --> 01:57:25,142
>E então quatro bytes de distância
disso podem ser 0x127, por exemplo.
2397
01:57:25,142 --> 01:57:27,100
>Mas, novamente,
não importa o que seja.
2398
01:57:27,100 --> 01:57:29,440
>Mas têm endereços, x e y.
2399
01:57:29,440 --> 01:57:31,562
>Portanto, uma chamada de ponteiro
tende a ser muito grande.
2400
01:57:31,562 --> 01:57:33,520
>Então, precisávamos pegar
um pedaço maior de madeira,
2401
01:57:33,520 --> 01:57:35,590
>oito bytes que representam um ponteiro.
2402
01:57:35,590 --> 01:57:38,830
>E, na verdade, preciso usar um pouco
mais de memória no swap agora.
2403
01:57:38,830 --> 01:57:42,490
>Se eu declarar que a é,
não um número inteiro,
2404
01:57:42,490 --> 01:57:47,020
>mas um ponteiro para um int,
essa é uma variável int*,
2405
01:57:47,020 --> 01:57:49,330
>Eu poderia chamar isso de agora.
2406
01:57:49,330 --> 01:57:54,340
>E eu poderia armazenar, nela,
o endereço de x, como 0x123.
2407
01:57:54,340 --> 01:57:57,640
>Se eu mudar a definição
de b para ser
2408
01:57:57,640 --> 01:58:01,390
>não um inteiro, mas um
ponteiro para um inteiro,
2409
01:58:01,390 --> 01:58:04,810
>essa é outra int*, que
por acaso tem oito bytes.
2410
01:58:04,810 --> 01:58:07,780
>Vou usar um pouco mais de memória
para isso, mas tudo bem.
2411
01:58:07,780 --> 01:58:10,030
>E seu nome vai ser b agora.
2412
01:58:10,030 --> 01:58:13,600
>E vai conter 0x127.
2413
01:58:13,600 --> 01:58:15,820
>Ainda preciso de uma variável temporária.
2414
01:58:15,820 --> 01:58:18,650
>Ainda preciso de uma variável
temporária, mas tudo bem.
2415
01:58:18,650 --> 01:58:20,980
>Eu só preciso de quatro bytes
para isso, porque a variável
2416
01:58:20,980 --> 01:58:25,990
>em si só precisa armazenar um int, como
Brian o guardou temporariamente em um copo.
2417
01:58:25,990 --> 01:58:29,260
>Então, eu só preciso de quatro bytes
adicionais, como antes, para isso.
2418
01:58:29,260 --> 01:58:31,720
>E agora, vamos apenas considerar a lógica.
2419
01:58:31,720 --> 01:58:32,710
>Aqui está o main.
2420
01:58:32,710 --> 01:58:34,990
>E o swap agora está usando essas 3 -
2421
01:58:34,990 --> 01:58:36,550
>2 e 1/2 linhas de memória.
2422
01:58:36,550 --> 01:58:37,240
>E isso é bom.
2423
01:58:37,240 --> 01:58:39,640
>Está crescendo conforme eu propus.
2424
01:58:39,640 --> 01:58:41,860
>X está no endereço 0x123.
2425
01:58:41,860 --> 01:58:44,560
>y está no endereço 0x127.
2426
01:58:44,560 --> 01:58:48,370
>Portanto, a e b, proponho
conceitualmente, como Igor propôs,
2427
01:58:48,370 --> 01:58:52,280
>armazene os endereços de
a, x e y, respectivamente.
2428
01:58:52,280 --> 01:58:55,060
>E agora meu código, eu
acho, precisa dizer isso.
2429
01:58:55,060 --> 01:59:00,025
>Vá e armazene, na variável tmp, o
que quer que esteja no endereço a.
2430
01:59:00,025 --> 01:59:02,650
>Então você pode pensar nisso
como uma flecha aqui embaixo.
2431
01:59:02,650 --> 01:59:03,910
>Siga a seta, OK.
2432
01:59:03,910 --> 01:59:06,010
>O que está no endereço 0x123?
2433
01:59:06,010 --> 01:59:06,910
>O número 1.
2434
01:59:06,910 --> 01:59:09,250
>Então colocamos um no tmp, assim como antes.
2435
01:59:09,250 --> 01:59:10,310
>Então o que vamos fazer?
2436
01:59:10,310 --> 01:59:13,540
>Bem, agora, vou prosseguir e
mudar, não o valor de um,
2437
01:59:13,540 --> 01:59:18,010
>mas vou mudar o que
está no local para ser
2438
01:59:18,010 --> 01:59:24,790
>o que quer que esteja no local em b, que é
uma seta apontando para baixo aqui, 0x127.
2439
01:59:24,790 --> 01:59:27,850
>Vou mudar este 1,
agora, para um 2.
2440
01:59:27,850 --> 01:59:30,910
>E a terceira e última etapa,
lembre-se, é para mim, agora,
2441
01:59:30,910 --> 01:59:37,150
>ir, não para b, mas para ir para
onde b aponta, que por acaso é y,
2442
01:59:37,150 --> 01:59:42,440
>e mudar para o valor de tmp, que
é claro, está aqui em cima.
2443
01:59:42,440 --> 01:59:45,430
>E neste ponto da história,
ainda são apenas três linhas de código.
2444
01:59:45,430 --> 01:59:47,380
>São diferentes tipos
de linhas de código.
2445
01:59:47,380 --> 01:59:48,950
>São três linhas de código.
2446
01:59:48,950 --> 01:59:52,180
>Mas quando swap termina a execução,
observe o que fizemos.
2447
01:59:52,180 --> 01:59:55,190
>Trocamos x e y com
sucesso, permitindo
2448
01:59:55,190 --> 01:59:59,270
>que swap vá para esses endereços em
vez de apenas obter ingenuamente
2449
01:59:59,270 --> 02:00:02,180
>cópias dos valores nele contidos.
2450
02:00:02,180 --> 02:00:05,150
>Agora, embora este código
pareça um pouco enigmático,
2451
02:00:05,150 --> 02:00:10,820
>é uma aplicação
da lógica que vimos até agora.
2452
02:00:10,820 --> 02:00:13,860
>Vou prosseguir e voltar para a
minha versão antiga com erros.
2453
02:00:13,860 --> 02:00:15,860
>E vou mudar a
definição de swap
2454
02:00:15,860 --> 02:00:19,190
>para dizer que não são necessários
dois inteiros, a e b, mas dois
2455
02:00:19,190 --> 02:00:20,810
>ponteiros para inteiros a e b.
2456
02:00:20,810 --> 02:00:24,080
>E a forma como você declara um ponteiro, lembre,
é o tipo de variável
2457
02:00:24,080 --> 02:00:26,767
>que você aponta para, seguida por um
asterisco e então o nome dela.
2458
02:00:26,767 --> 02:00:28,850
>E nós não vimos isso,
reconhecidamente, no contexto
2459
02:00:28,850 --> 02:00:31,550
>de uma função que leva parâmetros ainda.
2460
02:00:31,550 --> 02:00:33,170
>Mas é simplesmente isso.
2461
02:00:33,170 --> 02:00:34,610
>Eu adicionei os asteriscos.
2462
02:00:34,610 --> 02:00:40,040
>Aqui embaixo, preciso dizer,
armazenar em tmp, o que quer que esteja em a.
2463
02:00:40,040 --> 02:00:41,870
>Como faço para expressar "vá para a"?
2464
02:00:41,870 --> 02:00:43,520
>Basta adicionar uma asterisco aqui.
2465
02:00:43,520 --> 02:00:46,880
>Como expresso "vá para a" e coloco
o que quer que esteja em b?
2466
02:00:46,880 --> 02:00:48,500
>Eu adiciono asteriscos lá.
2467
02:00:48,500 --> 02:00:51,560
>Como posso dizer para ir para b e
armazenar o que quer que esteja em tmp?
2468
02:00:51,560 --> 02:00:53,190
>Eu adiciono uma asterisco aqui.
2469
02:00:53,190 --> 02:00:55,520
>Portanto, tmp é um número inteiro simples.
2470
02:00:55,520 --> 02:00:57,380
>É apenas um copo vazio como o de Brian.
2471
02:00:57,380 --> 02:00:58,620
>Não há nada sofisticado aí.
2472
02:00:58,620 --> 02:01:00,650
>Portanto, não precisamos de asteriscos em torno de tmp.
2473
02:01:00,650 --> 02:01:04,970
>Mas agora preciso mudar a forma
como estou usando a e b,
2474
02:01:04,970 --> 02:01:08,330
>porque agora são endereços
aonde eu quero ir.
2475
02:01:08,330 --> 02:01:12,140
>Não há necessidade de endereço
do operador neste contexto.
2476
02:01:12,140 --> 02:01:14,330
>Mas aqui em cima, vou
precisar fazer uma mudança.
2477
02:01:14,330 --> 02:01:16,380
>Eu preciso mudar o protótipo
para corresponder.
2478
02:01:16,380 --> 02:01:18,200
>Então isso é copiar e colar.
2479
02:01:18,200 --> 02:01:23,120
>Mas aposto que você pode imaginar
o que, por último, precisa mudar.
2480
02:01:23,120 --> 02:01:26,750
>Ao chamar swap, não quero passar
ingenuamente x e y, porque, novamente,
2481
02:01:26,750 --> 02:01:27,980
> serão copiadas.
2482
02:01:27,980 --> 02:01:32,000
>Eu quero passar o endereço
de x e o endereço de y,
2483
02:01:32,000 --> 02:01:35,690
>então essa troca agora tem uma
espécie de acesso especial
2484
02:01:35,690 --> 02:01:38,750
>para o conteúdo desses
locais na memória
2485
02:01:38,750 --> 02:01:42,740
>para que possa
fazer algumas alterações.
2486
02:01:42,740 --> 02:01:47,780
>E que, se eu recompilar este
programa agora, make swap, e eu
2487
02:01:47,780 --> 02:01:50,390
>.swap, e cruzo meus dedos.
Voila.
2488
02:01:50,390 --> 02:01:53,855
>Agora, eu troquei com sucesso
as linhas de código.
2489
02:01:53,855 --> 02:01:55,730
>Então, na semana passada, se você
estivesse se perguntando, talvez,
2490
02:01:55,730 --> 02:01:58,250
>por que não mostramos como
fazer a troca, poderíamos ter feito.
2491
02:01:58,250 --> 02:01:59,900
>E não precisamos de uma função especial.
2492
02:01:59,900 --> 02:02:03,200
>Você não precisa necessariamente de
ponteiros se fizermos tudo isso no main.
2493
02:02:03,200 --> 02:02:06,470
>Mas estou tentando introduzir
uma abstração, esta função que
2494
02:02:06,470 --> 02:02:09,740
>troca exatamente como o Brian
trocou os copos por nós.
2495
02:02:09,740 --> 02:02:12,650
>E para passar valores de
uma função para outra,
2496
02:02:12,650 --> 02:02:15,990
>você precisa entender o que está
acontecendo na memória do seu computador
2497
02:02:15,990 --> 02:02:18,830
>para que você possa passar
pequenas migalhas de pão novamente,
2498
02:02:18,830 --> 02:02:23,330
>mapas do tesouro para esses locais e memórias,
mais uma vez, graças a essas coisas
2499
02:02:23,330 --> 02:02:25,100
>chamadas ponteiros.
2500
02:02:25,100 --> 02:02:27,770
>Tudo bem, deixe-me
propor e enfatizar,
2501
02:02:27,770 --> 02:02:30,770
>então, que este desenho
da pilha estando no topo,
2502
02:02:30,770 --> 02:02:33,200
>onde malloc usa memória
e a pilha sendo
2503
02:02:33,200 --> 02:02:35,540
>na parte inferior, onde suas
próprias funções usam memória,
2504
02:02:35,540 --> 02:02:37,730
>este é um problema claramente
esperando para acontecer.
2505
02:02:37,730 --> 02:02:39,460
>E esses problemas têm nomes.
2506
02:02:39,460 --> 02:02:41,210
>E alguns de vocês que
já programaram antes
2507
02:02:41,210 --> 02:02:45,230
>pode conhecer alguns desses termos,
heap overflow, estouro de pilha ou stack overflow.
2508
02:02:45,230 --> 02:02:48,650
>E, muitos de vocês devem conhecer
stackoverflow.com apenas como um site.
2509
02:02:48,650 --> 02:02:50,840
>Bem, há uma história
de origem em seu nome.
2510
02:02:50,840 --> 02:02:56,240
>Um estouro de pilha se refere ao processo
de chamar uma função tantas vezes
2511
02:02:56,240 --> 02:02:58,550
>que transborda a pilha.
2512
02:02:58,550 --> 02:03:00,320
>Ou seja, toda vez que
você chama a função,
2513
02:03:00,320 --> 02:03:04,950
>como eu fiz aqui, você usa cada vez mais
linhas, por assim dizer, de memória.
2514
02:03:04,950 --> 02:03:07,730
>E se você chamar tantas
funções de novo e de novo,
2515
02:03:07,730 --> 02:03:11,690
>eventualmente, você pode muito bem correr
sobre a área da memória chamada heap.
2516
02:03:11,690 --> 02:03:14,090
>E nesse ponto, seu
programa irá travar.
2517
02:03:14,090 --> 02:03:18,950
>Não há solução fundamental para esse
problema além de não fazer isso.
2518
02:03:18,950 --> 02:03:20,420
>Não use muita memória.
2519
02:03:20,420 --> 02:03:21,680
>Mas isso pode ser difícil de fazer.
2520
02:03:21,680 --> 02:03:24,138
>E, esse é um dos
perigos da programação hoje.
2521
02:03:24,138 --> 02:03:27,800
>E podemos induzir isso um
pouco deliberadamente.
2522
02:03:27,800 --> 02:03:30,620
>E, na verdade, pensei que
poderíamos revisitar, por exemplo,
2523
02:03:30,620 --> 02:03:34,220
>onde paramos com o Mario da última
vez, que foi essa foto aqui.
2524
02:03:34,220 --> 02:03:37,580
>Lembre-se de que esta era
uma pirâmide, é claro,
2525
02:03:37,580 --> 02:03:40,400
>mais simples do que aquela com a qual
você pode ter brincado nos problemas da semana 0.
2526
02:03:40,400 --> 02:03:44,360
>Mas é uma pirâmide recursiva em que você
pode definir uma pirâmide de altura 4,
2527
02:03:44,360 --> 02:03:47,690
>em termos de uma pirâmide de altura 3,
em termos de uma pirâmide de altura 2
2528
02:03:47,690 --> 02:03:48,380
>e uma altura 1.
2529
02:03:48,380 --> 02:03:52,580
>E, eu construí isso na semana
passada usando esses mesmos blocos.
2530
02:03:52,580 --> 02:03:56,180
>Bem, você pode implementar
a pirâmide do Mário assim
2531
02:03:56,180 --> 02:03:57,660
>de algumas maneiras diferentes.
2532
02:03:57,660 --> 02:04:01,160
>Uma deles é usar apenas a iteração
de estilo da semana um, usando um loop.
2533
02:04:01,160 --> 02:04:03,890
>E, na verdade, deixe-me ir em frente
e criar uma solução rápida que
2534
02:04:03,890 --> 02:04:05,340
>faz exatamente isso.
2535
02:04:05,340 --> 02:04:07,730
>Eu vou chamar isso de mario.c.
2536
02:04:07,730 --> 02:04:10,610
>E vou prosseguir e
incluir cs50.h.
2537
02:04:10,610 --> 02:04:12,290
>Portanto, podemos usar uma de nossas funções get.
2538
02:04:12,290 --> 02:04:14,300
>Vou usar o padrão io ponto h.
2539
02:04:14,300 --> 02:04:16,160
>E vou fazer o main void.
2540
02:04:16,160 --> 02:04:18,590
>E tudo que eu quero fazer
é imprimir esta pirâmide.
2541
02:04:18,590 --> 02:04:20,340
>Mas quero perguntar
ao usuário a altura.
2542
02:04:20,340 --> 02:04:23,090
>Portanto, vou dizer que int
height é igual a get int.
2543
02:04:23,090 --> 02:04:26,870
>E pediremos ao usuário a altura,
assim como você fez para o conjunto de problemas 1.
2544
02:04:26,870 --> 02:04:30,000
>E então vou seguir em frente e
desenhar uma pirâmide dessa altura.
2545
02:04:30,000 --> 02:04:31,340
>Agora, o desenho não existe.
2546
02:04:31,340 --> 02:04:32,030
>Mas tudo bem.
2547
02:04:32,030 --> 02:04:34,735
>Vou seguir em frente e desenhar isso
agora, implementar o desenho sozinho.
2548
02:04:34,735 --> 02:04:36,860
>Não precisa retornar um
valor, porque estou apenas
2549
02:04:36,860 --> 02:04:38,273
>imprimindo coisas na tela.
2550
02:04:38,273 --> 02:04:40,190
>A função é chamada de draw,
e vai pegar
2551
02:04:40,190 --> 02:04:42,710
>uma entrada chamada h, por
exemplo. h para altura,
2552
02:04:42,710 --> 02:04:45,080
>mas eu poderia chamar seu
argumento do que eu quiser.
2553
02:04:45,080 --> 02:04:48,650
>E então eu vou apenas fazer
isso, para int eu recebo 1,
2554
02:04:48,650 --> 02:04:52,850
>i menor ou igual a h, i++.
2555
02:04:52,850 --> 02:04:56,170
>E, dentro disso, é aqui que você deve se
lembrar, do conjunto de problemas um,
2556
02:04:56,170 --> 02:04:58,700
>descobriu que um loop aninhado é útil.
2557
02:04:58,700 --> 02:05:04,150
>Vou fazer int j gets 1,
j menor ou igual a i, j++.
2558
02:05:04,150 --> 02:05:08,178
>Isso será semelhante, mas não
idêntico a mais confortável
2559
02:05:08,178 --> 02:05:09,970
>versão de
Mario do passado,
2560
02:05:09,970 --> 02:05:13,240
>porque esta pirâmide é moldada
em uma direção diferente.
2561
02:05:13,240 --> 02:05:15,610
>Agora, você imprime um hash.
2562
02:05:15,610 --> 02:05:17,830
>E então agora eu vou
imprimir uma nova linha aqui.
2563
02:05:17,830 --> 02:05:19,570
>Então eu fiz isso super rápido.
2564
02:05:19,570 --> 02:05:21,880
>Mas logicamente, o que
estou fazendo está iterando
2565
02:05:21,880 --> 02:05:29,710
>em todas as linhas, de 1 a h, portanto,
linhas 1, 2, 3, 4, por exemplo.
2566
02:05:29,710 --> 02:05:34,210
>E então, em cada linha, estou
deliberadamente iterando de 1 a i.
2567
02:05:34,210 --> 02:05:37,870
>Então, imprimo 1, 2, 3 e 4.
2568
02:05:37,870 --> 02:05:39,640
>E, novamente, posso zerar o índice.
2569
02:05:39,640 --> 02:05:44,170
>Acho que, neste contexto, é mais amigável,
mais inteligível para mim
2570
02:05:44,170 --> 02:05:46,660
>indexar de 1, totalmente
razoável se você pensar
2571
02:05:46,660 --> 02:05:48,310
>que há um argumento de design atraente.
2572
02:05:48,310 --> 02:05:50,030
>Então agora eu vou fazer make Mario.
2573
02:05:50,030 --> 02:05:51,520
>Ah, droga.
2574
02:05:51,520 --> 02:05:53,980
>Oh, eu perdi meu protótipo.
2575
02:05:53,980 --> 02:05:55,870
>Então observe, não está entendendo
draw.
2576
02:05:55,870 --> 02:05:58,900
>Então, a solução para isso
é mover toda a função
2577
02:05:58,900 --> 02:06:02,980
>ou, como já pregamos, apenas
colocar seu protótipo no topo.
2578
02:06:02,980 --> 02:06:05,050
>Vamos recompilar Mario.
2579
02:06:05,050 --> 02:06:06,430
>OK, agora com sucesso.
2580
02:06:06,430 --> 02:06:08,710
>Mario, vamos fazer uma
altura de 4 e voila.
2581
02:06:08,710 --> 02:06:11,350
>Agora, eu consegui, relativamente
simples - embora eu certamente
2582
02:06:11,350 --> 02:06:13,600
>fiz isso mais rápido do que
você faria sem alguma prática -
2583
02:06:13,600 --> 02:06:15,760
>na implementação da pirâmide do Mário.
2584
02:06:15,760 --> 02:06:17,980
>Mas é aqui que as coisas
ficam mais legais.
2585
02:06:17,980 --> 02:06:20,800
>Vamos estipular que essa é uma
solução iterativa correta, mesmo
2586
02:06:20,800 --> 02:06:24,970
>se isso pode exigir um certo número
de etapas ou tentativa e erro
2587
02:06:24,970 --> 02:06:28,180
>para obter esse código baseado
em loop iterativo correto.
2588
02:06:28,180 --> 02:06:30,580
>Vou mudar isso,
agora, para ser recursivo.
2589
02:06:30,580 --> 02:06:34,510
>E lembre-se, uma função recursiva
é aquela que chama a si mesma.
2590
02:06:34,510 --> 02:06:37,660
>Como você imprime uma pirâmide de altura h?
2591
02:06:37,660 --> 02:06:41,980
>Bem, lembre-se de que você imprime
uma pirâmide de altura h menos 1,
2592
02:06:41,980 --> 02:06:45,340
>e, em seguida, você imprime
mais uma linha de blocos.
2593
02:06:45,340 --> 02:06:48,970
>Então, deixe-me interpretar literalmente.
para int, eu chego a zero.
2594
02:06:48,970 --> 02:06:51,550
>i é menor que h, i++.
2595
02:06:51,550 --> 02:06:54,550
>Eu vou imprimir
essa linha extra de tijolos
2596
02:06:54,550 --> 02:06:58,480
>assim, seguido por uma nova linha.
2597
02:06:58,480 --> 02:07:00,260
>Então agora, eu fiz isso meio rápido.
2598
02:07:00,260 --> 02:07:01,340
>Mas o que estou fazendo aqui?
2599
02:07:01,340 --> 02:07:06,520
>Bem, se a altura for igual a 1,
quero que este loop itere uma vez.
2600
02:07:06,520 --> 02:07:10,760
>Se a altura fosse igual a 2, eu queria
iterar duas vezes, 3 e assim por diante.
2601
02:07:10,760 --> 02:07:14,260
>Então eu acho que, usando minha técnica de
indexação zero aqui, isso vai funcionar também.
2602
02:07:14,260 --> 02:07:17,080
>Mas se você preferir, eu certamente
poderia mudar isso para 1
2603
02:07:17,080 --> 02:07:18,638
>e alterar este 2.
2604
02:07:18,638 --> 02:07:19,930
>Mas vou ...
2605
02:07:19,930 --> 02:07:20,500
>não.
2606
02:07:20,500 --> 02:07:23,350
>Neste caso, quero deixar
assim, índice zero,
2607
02:07:23,350 --> 02:07:25,450
>exatamente como fazemos normalmente.
2608
02:07:25,450 --> 02:07:29,200
>Tudo bem, deixe-me compilar
isso, make Mario.
2609
02:07:29,200 --> 02:07:31,870
>OK, oops, interessante.
2610
02:07:31,870 --> 02:07:34,940
>Todos os caminhos por meio dessa
função serão chamados a si próprios.
2611
02:07:34,940 --> 02:07:37,780
>Então o clang é ser inteligente
aqui, por meio do qual,
2612
02:07:37,780 --> 02:07:42,260
>vejo que em minha função draw,
estou chamando minha função draw.
2613
02:07:42,260 --> 02:07:44,358
>E esse é um processo que nunca muda.
2614
02:07:44,358 --> 02:07:46,150
>Na verdade, deixe-me ver se
eu posso substituir isso.
2615
02:07:46,150 --> 02:07:51,310
>Vamos usar o clang manualmente e compilar
um programa chamado mario usando mario.c.
2616
02:07:51,310 --> 02:07:53,140
>Agora eu vou criar um link no cs50.
2617
02:07:53,140 --> 02:07:55,960
>Portanto, estou usando nossa sintaxe
old school da segunda semana.
2618
02:07:55,960 --> 02:07:56,980
>OK, compilado.
2619
02:07:56,980 --> 02:07:58,270
>E por que isso compilou?
2620
02:07:58,270 --> 02:08:01,872
>Bem, make é, novamente, um programa
que usa o clang do compilador.
2621
02:08:01,872 --> 02:08:05,080
>E configuramos o make para ser um
pouco mais amigável e um pouco mais
2622
02:08:05,080 --> 02:08:07,450
>protetor, ativando recursos especiais
2623
02:08:07,450 --> 02:08:09,250
>onde detectamos problemas como esse.
2624
02:08:09,250 --> 02:08:12,730
>Ao usar o clang diretamente agora, estou
desativando essas verificações especiais.
2625
02:08:12,730 --> 02:08:16,840
>E veja o que acontece quando eu rodo o Mario
agora para a altura de 4, por exemplo.
2626
02:08:16,840 --> 02:08:18,730
>E é isso, travou.
2627
02:08:18,730 --> 02:08:20,500
>Nem mesmo imprimiu nada.
2628
02:08:20,500 --> 02:08:21,953
>Ele travou muito rapidamente.
2629
02:08:21,953 --> 02:08:25,120
>E, novamente, uma falha de segmentação significa
que você tocou na memória que não deveria.
2630
02:08:25,120 --> 02:08:26,200
>Então, o que está acontecendo?
2631
02:08:26,200 --> 02:08:30,302
>Bem, se você pensar nesta memória como uma
representação de parada principal, mas então desenhar,
2632
02:08:30,302 --> 02:08:33,610
>desenhar, desenhar, desenhar, desenhar, desenhar.
2633
02:08:33,610 --> 02:08:37,540
>Se todas as suas chamadas para draw
chamam draw de novo,
2634
02:08:37,540 --> 02:08:39,070
>por que isso iria parar?
2635
02:08:39,070 --> 02:08:41,590
>Não pareceria parar aqui.
2636
02:08:41,590 --> 02:08:45,070
>Portanto, parece que está faltando um detalhe
importante em minha versão recursiva.
2637
02:08:45,070 --> 02:08:45,670
>Você sabe o que é?
2638
02:08:45,670 --> 02:08:51,130
>Se não houver nada para desenhar, se a altura
for igual a 0, deixe-me continuar, então,
2639
02:08:51,130 --> 02:08:54,260
>e voltar imediatamente.
2640
02:08:54,260 --> 02:08:57,250
>Caso contrário, vou seguir em
frente e desenhar parte da pirâmide
2641
02:08:57,250 --> 02:08:59,260
>e, em seguida, adicionar a nova linha.
2642
02:08:59,260 --> 02:09:02,110
>Então, você precisa desse chamado
caso básico, que você literalmente
2643
02:09:02,110 --> 02:09:05,410
>escolhe igualar a algum valor simples,
como altura de 0, altura de 1,
2644
02:09:05,410 --> 02:09:10,880
>qualquer valor codificado permanentemente, de modo
que, eventualmente, draw não chame a si mesmo.
2645
02:09:10,880 --> 02:09:15,040
>Então, deixe-me recompilar
isso com clang ou make.
2646
02:09:15,040 --> 02:09:18,430
>Vamos executá-lo novamente, altura de 4 e voila.
2647
02:09:18,430 --> 02:09:20,680
>Ainda está funcionando
como a versão interna,
2648
02:09:20,680 --> 02:09:22,340
>mas agora está usando recursão.
2649
02:09:22,340 --> 02:09:24,250
>Então aqui está um tipo de questão de design.
2650
02:09:24,250 --> 02:09:26,020
>A iteração é melhor do que a recursão?
2651
02:09:26,020 --> 02:09:26,680
>Depende.
2652
02:09:26,680 --> 02:09:28,270
>A iteração sempre funcionará.
2653
02:09:28,270 --> 02:09:32,290
>Ao usar a versão iterativa,
eu nunca vou estourar a pilha
2654
02:09:32,290 --> 02:09:33,140
>e acertar heap.
2655
02:09:33,140 --> 02:09:33,640
>Por quê?
2656
02:09:33,640 --> 02:09:35,723
>Porque não estou chamando
funções de novo e de novo.
2657
02:09:35,723 --> 02:09:38,410
>Há apenas main e
uma invocação de draw.
2658
02:09:38,410 --> 02:09:42,550
>Mas com a versão recursiva,
é uma forma legal e poderosa
2659
02:09:42,550 --> 02:09:43,270
>para fazer coisas.
2660
02:09:43,270 --> 02:09:45,610
>Tipo, eu posso desenhar para
você uma pirâmide de altura h.
2661
02:09:45,610 --> 02:09:48,370
>Vamos desenhar uma
pirâmide de altura h menos 1,
2662
02:09:48,370 --> 02:09:49,750
>e então adicionarei uma linha.
2663
02:09:49,750 --> 02:09:54,950
>É um tipo de argumento inteligente e cíclico
que funciona de maneira muito elegante.
2664
02:09:54,950 --> 02:09:56,150
>Mas existe um perigo.
2665
02:09:56,150 --> 02:10:00,830
>E, embora este caso básico
garanta que não durará eternamente,
2666
02:10:00,830 --> 02:10:05,180
>poderia demorar muito - talvez
vamos tentar 10.000 invocações.
2667
02:10:05,180 --> 02:10:06,290
>Então funcionou bem.
2668
02:10:06,290 --> 02:10:07,820
>É um pouco lento.
2669
02:10:07,820 --> 02:10:09,320
>Estou perdendo o controle do meu teclado.
2670
02:10:09,320 --> 02:10:10,730
>Portanto, o Ctrl C é seu amigo.
2671
02:10:10,730 --> 02:10:12,050
>Vamos tentar mais uma vez.
2672
02:10:12,050 --> 02:10:16,700
>Eu vou fazer algo
como 2 bilhões para ver se funciona.
2673
02:10:16,700 --> 02:10:17,540
>Explodiu.
2674
02:10:17,540 --> 02:10:19,110
>Portanto, mesmo isso não funciona.
2675
02:10:19,110 --> 02:10:21,710
>Portanto, há esse perigo inerente
com a recursão, por meio da qual,
2676
02:10:21,710 --> 02:10:25,010
>embora tenha nos capacitado na semana passada para
resolver um problema de forma ainda mais eficiente
2677
02:10:25,010 --> 02:10:29,810
>com o merge sort, meio que tivemos sorte,
em que não estávamos tentando coisas insanamente
2678
02:10:29,810 --> 02:10:33,080
>grandes na prateleira de Brian, porque
parece que se você usar recursão
2679
02:10:33,080 --> 02:10:35,330
>e chamar a si mesmo de novo e
de novo e de novo e de novo,
2680
02:10:35,330 --> 02:10:40,340
>mesmo que finitamente, mas muitas vezes, você pode
tocar na memória que não deveria.
2681
02:10:40,340 --> 02:10:42,290
>E qual é a solução aqui?
2682
02:10:42,290 --> 02:10:44,510
>Infelizmente, é "Não faça isso".
2683
02:10:44,510 --> 02:10:48,020
>Projete seus algoritmos, escolha
suas entradas de tal forma
2684
02:10:48,020 --> 02:10:49,560
>que simplesmente não exista esse risco.
2685
02:10:49,560 --> 02:10:51,800
>E usaremos a recursão
novamente em algumas semanas
2686
02:10:51,800 --> 02:10:54,800
>no momento em que olhamos para estruturas
de dados mais sofisticadas.
2687
02:10:54,800 --> 02:10:56,600
>Mas, novamente,
sempre há essa troca.
2688
02:10:56,600 --> 02:10:58,725
>Só porque você pode criar
algo um pouco mais
2689
02:10:58,725 --> 02:11:03,120
>elegantemente não significa necessariamente
que sempre funcionará para você.
2690
02:11:03,120 --> 02:11:06,560
>Mas, mais comumente, você provavelmente
terá outros problemas também?
2691
02:11:06,560 --> 02:11:08,540
>Existe algo chamado
estouro de buffer.
2692
02:11:08,540 --> 02:11:10,880
>E você certamente tropeçará
nisso nas próximas semanas.
2693
02:11:10,880 --> 02:11:13,610
>Um estouro de buffer é
quando você aloca um array
2694
02:11:13,610 --> 02:11:15,590
>e vai muito além do fim.
2695
02:11:15,590 --> 02:11:18,650
>Ou você usa malloc e,
no entanto, vai mais longe
2696
02:11:18,650 --> 02:11:21,020
>do que o final do pedaço de
memória que você alocou.
2697
02:11:21,020 --> 02:11:25,010
>Um buffer é um pedaço de memória,
por assim dizer, que você pode usar
2698
02:11:25,010 --> 02:11:25,550
>enquanto couber.
2699
02:11:25,550 --> 02:11:30,230
>O estouro do buffer significa ir
além dos limites desse array.
2700
02:11:30,230 --> 02:11:32,930
>Você pode usar-- você está
usando, agora, vídeo.
2701
02:11:32,930 --> 02:11:35,125
>Você deve conhecer a frase
buffering de vídeos,
2702
02:11:35,125 --> 02:11:37,250
>como o buffer
irritante da Netflix,
2703
02:11:37,250 --> 02:11:39,050
>porque há um ícone
giratório ou algo assim.
2704
02:11:39,050 --> 02:11:40,700
>Bem, isso significa exatamente isso.
2705
02:11:40,700 --> 02:11:44,090
>Um buffer, no contexto de
YouTube ou Zoom ou Netflix,
2706
02:11:44,090 --> 02:11:46,910
>significa algum pedaço de
memória que foi recuperado
2707
02:11:46,910 --> 02:11:49,880
>via malloc ou alguma ferramenta
semelhante que é preenchida
2708
02:11:49,880 --> 02:11:52,580
>com bytes compreendendo seu vídeo.
2709
02:11:52,580 --> 02:11:56,210
>E é finito, por isso você só
pode armazenar alguns segundos
2710
02:11:56,210 --> 02:11:59,520
>ou minutos de vídeo antes,
eventualmente, se você estiver offline,
2711
02:11:59,520 --> 02:12:01,220
>você fica sem conteúdo de vídeo para assistir.
2712
02:12:01,220 --> 02:12:02,930
>E o ícone idiota aparece, e você pode
2713
02:12:02,930 --> 02:12:07,680
>não ver mais nada, porque um buffer é um
pedaço de memória, um array de memória.
2714
02:12:07,680 --> 02:12:12,830
>E se a Netflix, o Google ou outros
implementassem seus códigos de maneira insegura,
2715
02:12:12,830 --> 02:12:16,740
>eles poderiam muito bem ir muito
além dessa fronteira.
2716
02:12:16,740 --> 02:12:22,070
>Com tudo isso dito, vamos considerar,
em alguns de nossos minutos finais
2717
02:12:22,070 --> 02:12:26,000
>aqui hoje, apenas o que mais
recebemos dessas treino de iniciação,
2718
02:12:26,000 --> 02:12:28,830
>porque queremos retirá-las
na maioria para você andar sozinho.
2719
02:12:28,830 --> 02:12:30,890
>Portanto, a biblioteca
CS50 não fornece apenas
2720
02:12:30,890 --> 02:12:33,855
>esta abstração de um tipo
de string, que novamente,
2721
02:12:33,855 --> 02:12:35,480
>não oferece nenhuma nova funcionalidade.
2722
02:12:35,480 --> 02:12:38,600
>Strings em C existem,
apenas não por esse nome.
2723
02:12:38,600 --> 02:12:40,850
>Eles são conhecidas mais
apropriadamente como char*.
2724
02:12:40,850 --> 02:12:43,730
>Mas todas essas funções
na biblioteca CS50
2725
02:12:43,730 --> 02:12:49,490
>podem ser implementadas com outras
funções C que não eram do CS50,
2726
02:12:49,490 --> 02:12:51,740
>ou seja, usando um chamado scanf.
2727
02:12:51,740 --> 02:12:54,260
>Mas você vai ver,
imediatamente, alguns dos perigos
2728
02:12:54,260 --> 02:12:57,980
>de usar algo como scanf,
que é uma função old school.
2729
02:12:57,980 --> 02:13:01,280
>Não foi projetada para ser autodefensivo
como a biblioteca do CS50.
2730
02:13:01,280 --> 02:13:03,510
>E assim é muito fácil cometer erros.
2731
02:13:03,510 --> 02:13:06,650
>vou continuar, por
exemplo, e criar um arquivo
2732
02:13:06,650 --> 02:13:09,860
>chamado scanf.c, apenas para
demonstrar esta função.
2733
02:13:09,860 --> 02:13:13,200
>Não vou usar a biblioteca CS50,
apenas o padrão io ponto h.
2734
02:13:13,200 --> 02:13:15,470
>E vou criar
int main void.
2735
02:13:15,470 --> 02:13:18,110
>Vou criar uma variável x.
2736
02:13:18,110 --> 02:13:21,260
>E vou prosseguir e imprimir
"x:"
2737
02:13:21,260 --> 02:13:24,060
>assim como a função get int do CS50.
2738
02:13:24,060 --> 02:13:25,940
>E então vou chamar o scanf.
2739
02:13:25,940 --> 02:13:30,170
>E vou prosseguir e dizer, digitalize, no
teclado do usuário, um número inteiro,
2740
02:13:30,170 --> 02:13:33,708
>e armazene-o no local de x.
2741
02:13:33,708 --> 02:13:35,750
>Então, vou prosseguir e
imprimir, novamente,
2742
02:13:35,750 --> 02:13:40,340
>x, e dois pontos e uma \ %i \n.
2743
02:13:40,340 --> 02:13:41,420
>E vou imprimir x.
2744
02:13:41,420 --> 02:13:42,830
>Então, o que está acontecendo aqui?
2745
02:13:42,830 --> 02:13:46,580
>Na linha 5, estou declarando uma variável
chamada x, assim como na primeira semana.
2746
02:13:46,580 --> 02:13:49,220
>Linha 6, apenas usando printf,
como na primeira semana.
2747
02:13:49,220 --> 02:13:52,460
>O interessante parece
estar na linha 7.
2748
02:13:52,460 --> 02:13:56,870
>Scanf é uma função que recebe a entrada
do usuário, assim como get int,
2749
02:13:56,870 --> 02:13:58,500
>get string, get float e assim por diante.
2750
02:13:58,500 --> 02:14:02,630
>Mas isso só acontece quando
você precisa entender os ponteiros,
2751
02:14:02,630 --> 02:14:07,790
>porque lembre-se de nosso exemplo de swap,
se você quiser ter uma função,
2752
02:14:07,790 --> 02:14:12,110
>alterar o conteúdo de uma
variável, como fizemos com a e b
2753
02:14:12,110 --> 02:14:15,920
>e x e y, você tem que passar
o endereço da variável, cujo
2754
02:14:15,920 --> 02:14:17,060
>valor deseja alterar.
2755
02:14:17,060 --> 02:14:19,200
>Você não pode simplesmente passar o próprio x.
2756
02:14:19,200 --> 02:14:22,263
>Então, se não usássemos a
Biblioteca CS50 na primeira semana,
2757
02:14:22,263 --> 02:14:25,430
>você teria escrito código assim
apenas para obter um int do usuário.
2758
02:14:25,430 --> 02:14:27,347
>E você teria que
entender os ponteiros.
2759
02:14:27,347 --> 02:14:30,170
>E você teria que entender & e *
e assim por diante.
2760
02:14:30,170 --> 02:14:32,712
>É demais, quando tudo o que nos
preocupamos nas primeiras semanas
2761
02:14:32,712 --> 02:14:35,990
>foram loops e variáveis e condições
e tipos dos fundamentos.
2762
02:14:35,990 --> 02:14:39,230
>Mas aqui, agora temos a capacidade
de chamar a SCANF, contar
2763
02:14:39,230 --> 02:14:41,150
>para digitalizar do teclado
do usuário, por assim dizer,
2764
02:14:41,150 --> 02:14:45,380
>um inteiro ou % F nos daria
um float ou outros códigos,
2765
02:14:45,380 --> 02:14:49,040
>e passar no endereço de x para que
a SCANF possa ir a esse endereço
2766
02:14:49,040 --> 02:14:51,440
>e colocar o inteiro do
teclado do usuário.
2767
02:14:51,440 --> 02:14:53,030
>A linha 8 parece coisa da semana 1 .
2768
02:14:53,030 --> 02:14:54,680
>Eu estou apenas imprimindo o valor.
2769
02:14:54,680 --> 02:14:55,950
>E isso é bem seguro.
2770
02:14:55,950 --> 02:14:57,800
>vou continuar e fazer a SCANF.
2771
02:14:57,800 --> 02:14:58,495
>Compila ok.
2772
02:14:58,495 --> 02:14:59,870
>Vou prosseguir e executá-lo.
2773
02:14:59,870 --> 02:15:00,980
>Vou digitar 50.
2774
02:15:00,980 --> 02:15:03,180
>E pronto, ele imprime um 50.
2775
02:15:03,180 --> 02:15:06,920
>Mas há algumas estranhezas,
porque se você executar este programa também
2776
02:15:06,920 --> 02:15:09,410
>e digitar cat, então x é 0.
2777
02:15:09,410 --> 02:15:10,940
>E não há verificação de erros.
2778
02:15:10,940 --> 02:15:12,767
>Então, imediatamente,
você deve lembrar
2779
02:15:12,767 --> 02:15:14,600
>das características da
Biblioteca CS50, lembre-se,
2780
02:15:14,600 --> 02:15:17,630
>que continuamos avisando o usuário
repetidamente, se ele não estiver
2781
02:15:17,630 --> 02:15:19,310
>cooperando e dando a você um int.
2782
02:15:19,310 --> 02:15:21,740
>Esse é um recurso que
você obtém da biblioteca.
2783
02:15:21,740 --> 02:15:26,120
>Mas acontece que get string
é ainda mais poderoso,
2784
02:15:26,120 --> 02:15:29,000
>porque se eu for e mudar este programa
agora, não para obter um int,
2785
02:15:29,000 --> 02:15:30,710
>mas algo mais sofisticado como uma string -
2786
02:15:30,710 --> 02:15:33,223
>ou espere, estamos chamando de char* agora.
2787
02:15:33,223 --> 02:15:35,390
>Vou prosseguir e fazer
algo muito semelhante.
2788
02:15:35,390 --> 02:15:37,640
>Vou solicitar ao
usuário a string s.
2789
02:15:37,640 --> 02:15:39,020
>E vou usar o scanf.
2790
02:15:39,020 --> 02:15:42,320
>E vou usar % s,
assim como printf usa % s.
2791
02:15:42,320 --> 02:15:44,510
>E vou passar um s.
2792
02:15:44,510 --> 02:15:48,890
>Agora, para ficar claro, não
preciso fazer o & aqui,
2793
02:15:48,890 --> 02:15:53,010
>porque agora, todos nós sabemos que
s é fundamentalmente um endereço.
2794
02:15:53,010 --> 02:15:56,270
>Portanto, basta passar o
endereço que você já possui.
2795
02:15:56,270 --> 02:16:01,280
>Agora, vou prosseguir e imprimir os dois
pontos, a \ de % s,
2796
02:16:01,280 --> 02:16:02,930
>e imprimir s.
2797
02:16:02,930 --> 02:16:07,730
>Mas quando eu compilo isso,
make scanf, ele não gosta
2798
02:16:07,730 --> 02:16:10,970
>quando eu compilo a variável s não
inicializada quando usada aqui.
2799
02:16:10,970 --> 02:16:14,390
>Tudo bem, se eu quero
ser uma espécie de aventureiro,
2800
02:16:14,390 --> 02:16:16,350
>posso anular as proteções do make.
2801
02:16:16,350 --> 02:16:19,880
>E posso apenas compilar
manualmente usando scanf -
2802
02:16:19,880 --> 02:16:21,260
>usando clang diretamente.
2803
02:16:21,260 --> 02:16:23,600
>Isso funcionou, ./ scanf.
2804
02:16:23,600 --> 02:16:26,870
>Vamos prosseguir e
digitar, por exemplo, "HI!"
2805
02:16:26,870 --> 02:16:29,000
>e você vê estranheza, nul.
2806
02:16:29,000 --> 02:16:31,190
>Bem, felizmente,
make, e por sua vez clang,
2807
02:16:31,190 --> 02:16:33,830
>estavam nos ajudando a
ajudar a nós mesmos.
2808
02:16:33,830 --> 02:16:35,840
>Ele estava apontando que você declarou s.
2809
02:16:35,840 --> 02:16:38,660
>Você declarou
8 bytes para um ponteiro.
2810
02:16:38,660 --> 02:16:39,860
>Mas não há nada lá.
2811
02:16:39,860 --> 02:16:41,459
>É um valor de lixo.
2812
02:16:41,459 --> 02:16:43,170
>E então não há onde colocar isso.
2813
02:16:43,170 --> 02:16:45,889
>E, felizmente, printf e scanf estão
sendo inteligentes o suficiente
2814
02:16:45,889 --> 02:16:48,870
>por não apenas ir cegamente
lá e colocar H, I,
2815
02:16:48,870 --> 02:16:50,760
>ponto de exclamação em um caractere nulo.
2816
02:16:50,760 --> 02:16:52,010
>Eles estão apenas deixando para lá.
2817
02:16:52,010 --> 02:16:55,910
>E esse nul entre parênteses é um recurso
do printf que diz, você estragou tudo.
2818
02:16:55,910 --> 02:16:58,100
>Se você vir nul, significa
que fez algo errado.
2819
02:16:58,100 --> 02:17:00,830
>Está sendo generoso para evitar travar.
2820
02:17:00,830 --> 02:17:04,879
>Se eu quiser obter a entrada do
usuário, preciso ser mais esperto do que isso.
2821
02:17:04,879 --> 02:17:10,040
>E eu preciso me alocar
4 bytes, como fizemos mais cedo hoje.
2822
02:17:10,040 --> 02:17:14,209
>Ou eu poderia voltar às coisas da segunda
semana e dizer algo como, dê-me 4 bytes.
2823
02:17:14,209 --> 02:17:18,830
>Isso, porém, me dá 4 bytes
na pilha em algum lugar
2824
02:17:18,830 --> 02:17:21,410
>aqui embaixo no quadro principal, por assim dizer.
2825
02:17:21,410 --> 02:17:23,270
>Essas linhas são chamadas de quadros.
2826
02:17:23,270 --> 02:17:27,260
>Se eu usar malloc, em vez disso,
vem da chamada pilha,
2827
02:17:27,260 --> 02:17:29,780
>que não é retratada,
está mais ou menos aqui.
2828
02:17:29,780 --> 02:17:34,309
>E a única diferença é que se
estou usando o malloc, tenho que usar free.
2829
02:17:34,309 --> 02:17:38,930
>Se estou usando a pilha, como fiz na
semana dois, não preciso usar free.
2830
02:17:38,930 --> 02:17:40,730
>Gerencia-se automaticamente para mim.
2831
02:17:40,730 --> 02:17:42,590
>Francamente, há muitas
coisas novas hoje.
2832
02:17:42,590 --> 02:17:46,280
>Eu gosto da ideia de ficar com
as arrays old school.
2833
02:17:46,280 --> 02:17:51,379
>Agora, porém, se eu for em frente e fizer
make scanf, agora compilará com make.
2834
02:17:51,379 --> 02:17:55,610
>Se eu executar o scanf e digitar,
HI!, voila, parece funcionar.
2835
02:17:55,610 --> 02:17:58,549
>Mas isso é porque eu era
inteligente e previ que H-I,
2836
02:17:58,549 --> 02:17:59,660
>OK, quatro caracteres.
2837
02:17:59,660 --> 02:18:00,980
>Eu me dei 4 bytes.
2838
02:18:00,980 --> 02:18:06,110
>Mas e se o usuário digitar,
AQUI, DAVID, COMO ESTÁ?
2839
02:18:06,110 --> 02:18:08,059
>Claramente, mais de quatro bytes.
2840
02:18:08,059 --> 02:18:11,959
>E eu apertei Enter agora,
algo estranho aconteceu.
2841
02:18:11,959 --> 02:18:13,790
>O resto está perdido.
2842
02:18:13,790 --> 02:18:16,670
>E isso seria
irritante e muito frustrante
2843
02:18:16,670 --> 02:18:19,520
>se você - tentando obter a opinião do
usuário na primeira semana de aula.
2844
02:18:19,520 --> 02:18:21,500
>Get string evita isso para você.
2845
02:18:21,500 --> 02:18:23,719
>Get string chama malloc para você.
2846
02:18:23,719 --> 02:18:27,200
>E exige um pedaço de memória
tão grande quanto a string
2847
02:18:27,200 --> 02:18:28,070
>que os humanos digitam.
2848
02:18:28,070 --> 02:18:30,980
>Resumindo, nós meio que observamos
o que estão digitando
2849
02:18:30,980 --> 02:18:32,209
> caractere por caractere.
2850
02:18:32,209 --> 02:18:34,340
>E nos certificamos de
alocar ou realocar
2851
02:18:34,340 --> 02:18:38,879
>apenas memória suficiente para caber o
que quer que o humano tenha digitado.
2852
02:18:38,879 --> 02:18:42,107
>Então scanf é, uma
função como a biblioteca CS50
2853
02:18:42,107 --> 02:18:43,190
>e funciona sob o capô.
2854
02:18:43,190 --> 02:18:46,650
>Mas está fazendo tudo isso por você.
2855
02:18:46,650 --> 02:18:49,549
>E assim que você tira rodinhas
como essa, ou francamente,
2856
02:18:49,549 --> 02:18:52,469
>bibliotecas assim.
2857
02:18:52,469 --> 02:18:53,719
>Não é uma ferramenta de ensino.
2858
02:18:53,719 --> 02:18:55,070
>É uma biblioteca útil.
2859
02:18:55,070 --> 02:18:58,469
>Você mesmo precisa começar a implementar
mais dessas coisas de baixo nível.
2860
02:18:58,469 --> 02:18:59,810
>Então, novamente, há uma troca.
2861
02:18:59,810 --> 02:19:02,727
>Se você não quiser usar algo como
a biblioteca CS50, tudo bem.
2862
02:19:02,727 --> 02:19:08,400
>Agora, a responsabilidade recai sobre você para
evitar todas essas possíveis condições de erro.
2863
02:19:08,400 --> 02:19:11,209
>Tudo bem, com isso dito,
nós temos um recurso final
2864
02:19:11,209 --> 02:19:14,270
>para lhe dar a fim de motivar os
problemas desta semana, em que
2865
02:19:14,270 --> 02:19:18,230
>você explorará, manipulará e
escreverá código para alterar arquivos.
2866
02:19:18,230 --> 02:19:22,790
>E para isso, precisamos de um tópico final
de I / O de arquivo. File I/O
2867
02:19:22,790 --> 02:19:27,350
>é o termo técnico que descreve a
obtenção de entrada e saída de arquivos.
2868
02:19:27,350 --> 02:19:30,980
>Quase todos os programas que escrevemos
até agora usam apenas memória, assim
2869
02:19:30,980 --> 02:19:32,924
>aqui, por meio do qual, você
pode colocar coisas na memória.
2870
02:19:32,924 --> 02:19:34,549
>Mas assim que seu programa terminar, bum!
2871
02:19:34,549 --> 02:19:35,330
>Já se foi.
2872
02:19:35,330 --> 02:19:37,070
>O conteúdo da memória se foi.
2873
02:19:37,070 --> 02:19:39,770
>Os arquivos, é claro, estão onde
você e eu no mundo do Computação
2874
02:19:39,770 --> 02:19:42,020
>salvamos nossos artigos,
documentos e currículos
2875
02:19:42,020 --> 02:19:44,629
>e tudo isso permanentemente
no seu computador.
2876
02:19:44,629 --> 02:19:48,590
>Em C, você tem a habilidade,
certamente, para escrever você mesmo um código que
2877
02:19:48,590 --> 02:19:50,730
>salva arquivos a longo prazo.
2878
02:19:50,730 --> 02:19:53,450
>Por exemplo, vou
escrever meu próprio programa aqui,
2879
02:19:53,450 --> 02:19:59,260
>um programa de lista telefônica que
armazena nomes e números em um arquivo.
2880
02:19:59,260 --> 02:20:02,380
>Vou prosseguir e incluir,
apenas por conveniência, a biblioteca CS50
2881
02:20:02,380 --> 02:20:04,480
>de novo, porque não
quero lidar com scanf.
2882
02:20:04,480 --> 02:20:08,200
>Vou prosseguir e salvar isso,
aliás, como phonebook.c.
2883
02:20:08,200 --> 02:20:12,370
>Vou prosseguir e incluir não apenas
a biblioteca CS50, mas o io padrão.
2884
02:20:12,370 --> 02:20:18,373
>E preventivamente, irei prosseguir
e incluir string.h também.
2885
02:20:18,373 --> 02:20:20,290
>E vou prosseguir na
minha função main.
2886
02:20:20,290 --> 02:20:23,990
>E vou usar algumas novas funções
que veremos brevemente aqui.
2887
02:20:23,990 --> 02:20:27,260
>Mas no próximo conjunto de problemas,
você os explorará com mais detalhes.
2888
02:20:27,260 --> 02:20:29,980
>Vou criar uma indicação
para um arquivo.
2889
02:20:29,980 --> 02:20:33,820
>Acontece que, estranhamente,
que em maiúsculas, FILE,
2890
02:20:33,820 --> 02:20:38,540
>este é um novo tipo de dados que vem
com C que representa um arquivo.
2891
02:20:38,540 --> 02:20:42,383
>Vou seguir em frente e criar
uma indicação para um arquivo,
2892
02:20:42,383 --> 02:20:43,300
>o endereço de um arquivo.
2893
02:20:43,300 --> 02:20:44,800
>E vou chamar o arquivo variável.
2894
02:20:44,800 --> 02:20:46,300
>Eu poderia chamar f, poderia chamar de x.
2895
02:20:46,300 --> 02:20:49,130
>Vou chamar de arquivo em letras
minúsculas, só para ficar claro.
2896
02:20:49,130 --> 02:20:52,180
>E vou usar uma nova função chamada f
open, que significa abrir arquivo.
2897
02:20:52,180 --> 02:20:54,077
>E a abertura do arquivo leva dois argumentos.
2898
02:20:54,077 --> 02:20:57,160
>Recebe o primeiro argumento, que é o nome
de um arquivo que deseja abrir.
2899
02:20:57,160 --> 02:20:59,638
>Vou abrir um arquivo
chamado phonebook.csv.
2900
02:20:59,638 --> 02:21:02,680
>E então vou prosseguir e abri-lo,
especificamente, no modo anexar.
2901
02:21:02,680 --> 02:21:05,050
>Resumindo, você pode abrir
arquivos de diferentes maneiras,
2902
02:21:05,050 --> 02:21:08,450
>lê-los, isto é, basta olhar para
o seu conteúdo, escrevê-los,
2903
02:21:08,450 --> 02:21:10,780
>que é mudar seu
conteúdo completamente,
2904
02:21:10,780 --> 02:21:15,730
>ou para anexar a eles, a, que significa
adicionar linha por linha a eles,
2905
02:21:15,730 --> 02:21:18,370
>para continuar a fornecer
mais informações.
2906
02:21:18,370 --> 02:21:20,210
>Vou continuar e,
só para ficar seguro,
2907
02:21:20,210 --> 02:21:23,650
>vou dizer que se o
arquivo é igual a nul,
2908
02:21:23,650 --> 02:21:26,180
>porque lembre-se de que nul
significa que algo deu errado,
2909
02:21:26,180 --> 02:21:27,280
>vamos retornar agora.
2910
02:21:27,280 --> 02:21:28,960
>Talvez eu tenha digitado incorretamente o nome do arquivo.
2911
02:21:28,960 --> 02:21:29,950
>Talvez não exista.
2912
02:21:29,950 --> 02:21:31,420
>Algo deu errado, provavelmente.
2913
02:21:31,420 --> 02:21:34,660
>Vou verificar isso dizendo:
se o arquivo for igual a nul, apenas
2914
02:21:34,660 --> 02:21:36,178
>saia do programa agora.
2915
02:21:36,178 --> 02:21:38,470
>Mas depois disso, vou prosseguir
e obter uma string.
2916
02:21:38,470 --> 02:21:41,920
>Mas podemos chamar de char*
agora, chamada de name.
2917
02:21:41,920 --> 02:21:44,440
>E vou pedir um
nome ao usuário.
2918
02:21:44,440 --> 02:21:45,820
>E já fizemos isso antes.
2919
02:21:45,820 --> 02:21:48,610
>Vou pedir a eles um número,
um número de telefone.
2920
02:21:48,610 --> 02:21:49,970
>E já fizemos isso antes.
2921
02:21:49,970 --> 02:21:52,690
>A única diferença, agora, é
estou chamando string char*.
2922
02:21:52,690 --> 02:21:54,400
>E agora, aqui está a parte legal.
2923
02:21:54,400 --> 02:21:56,830
>Acontece que, se eu quiser
salvar este nome e número
2924
02:21:56,830 --> 02:21:58,990
>a esse arquivo permanentemente em um CSV -
2925
02:21:58,990 --> 02:22:02,170
>se desconhecido, popular no mundo
da consultoria, o mundo analítico.
2926
02:22:02,170 --> 02:22:04,900
>É apenas uma planilha,
um valor separado por vírgula
2927
02:22:04,900 --> 02:22:08,470
>arquivo que você pode abrir no Excel
ou planilha do Google.
2928
02:22:08,470 --> 02:22:13,660
>Vou prosseguir e, não printf,
mas fprintf para esse arquivo,
2929
02:22:13,660 --> 02:22:18,580
>uma string seguida por uma vírgula, seguida
por uma string, seguida por uma nova linha,
2930
02:22:18,580 --> 02:22:21,070
>conectando o nome e o número.
2931
02:22:21,070 --> 02:22:25,280
>E então, aqui embaixo,
fecharei o arquivo.
2932
02:22:25,280 --> 02:22:28,570
>Então, isso é novo. fprintf não
é printf, que imprime na tela.
2933
02:22:28,570 --> 02:22:30,307
>fprintf imprime em um arquivo.
2934
02:22:30,307 --> 02:22:32,890
>Então você tem que passar mais
um argumento, o primeiro, que
2935
02:22:32,890 --> 02:22:37,150
>é o ponteiro para o arquivo para o qual
é deseja enviar essas novas strings.
2936
02:22:37,150 --> 02:22:40,180
>Então você ainda fornece uma string
de formato, que diz, hey fprintf,
2937
02:22:40,180 --> 02:22:43,060
>este é o tipo de dados que
desejo imprimir no arquivo.
2938
02:22:43,060 --> 02:22:46,930
>E então você conecta as variáveis,
assim como sempre fizemos com printf.
2939
02:22:46,930 --> 02:22:49,610
>E, por último, fechamos o arquivo.
2940
02:22:49,610 --> 02:22:53,200
>Resumindo, este programa parece solicitar
a um humano um nome e um número.
2941
02:22:53,200 --> 02:22:55,420
>E então vai seguir em frente
e escrever esses nomes
2942
02:22:55,420 --> 02:22:56,990
>e números para o arquivo.
2943
02:22:56,990 --> 02:22:59,035
>Então agora eu vou fazer a lista telefônica.
2944
02:22:59,035 --> 02:23:07,810
>OK, nenhum erro até agora, lista
telefônica ./, David, 949-468-2750.
2945
02:23:07,810 --> 02:23:11,140
>OK, deixe-me executá-lo mais uma vez,
embora nada pareça ter acontecido.
2946
02:23:11,140 --> 02:23:15,730
>Brian, que tal 617-495-1000, Enter.
2947
02:23:15,730 --> 02:23:17,950
>Vamos verificar meu explorador de arquivos aqui.
2948
02:23:17,950 --> 02:23:22,240
>Observe, todos os arquivos que criamos
hoje, incluindo, se eu aumentar o zoom,
2949
02:23:22,240 --> 02:23:25,390
>não apenas phonebook.c, mas phonebook.csv.
2950
02:23:25,390 --> 02:23:29,290
>E se eu clicar duas vezes nisso,
observe o que está dentro disso.
2951
02:23:29,290 --> 02:23:33,700
>Voila, o nome de David, o nome de
Brian e cada um dos nossos números.
2952
02:23:33,700 --> 02:23:36,280
>E ainda mais legal do que isso,
agora eu vou encerrar isso.
2953
02:23:36,280 --> 02:23:40,213
>Vamos prosseguir e baixar
este arquivo usando o IDE.
2954
02:23:40,213 --> 02:23:42,380
>E isso vai colocá-lo na
minha pasta Downloads.
2955
02:23:42,380 --> 02:23:43,420
>Eu vou clicar nele.
2956
02:23:43,420 --> 02:23:45,545
>E vai abrir
Excel ou Numbers ou qualquer outra coisa
2957
02:23:45,545 --> 02:23:47,470
>que você tem no seu Mac ou PC.
2958
02:23:47,470 --> 02:23:50,740
>Vou prosseguir.
2959
02:23:50,740 --> 02:23:54,400
>E voila, parece um pouco
estúpido nesta formatação aqui.
2960
02:23:54,400 --> 02:23:57,160
>Mas eu abri uma planilha
que eu mesmo gerei
2961
02:23:57,160 --> 02:24:01,390
>usando fopen, fprintf e fclose.
2962
02:24:01,390 --> 02:24:04,180
>Então, agora que temos
ponteiros à nossa disposição,
2963
02:24:04,180 --> 02:24:08,292
>podemos manipular coisas
como arquivos, o que é muito legal.
2964
02:24:08,292 --> 02:24:10,000
>Mas vamos fazer isso
esta semana, não
2965
02:24:10,000 --> 02:24:12,940
>com texto, mas com tipos
específicos reais de arquivos.
2966
02:24:12,940 --> 02:24:16,840
>E, lembre-se desse
tipo de pensamento aqui.
2967
02:24:16,840 --> 02:24:19,150
>Se você olhar para isso,
provavelmente é muito enigmático.
2968
02:24:19,150 --> 02:24:21,400
>Parece um código de
máquina, mas não é.
2969
02:24:21,400 --> 02:24:24,070
>Esta é, talvez, a
representação mais simples
2970
02:24:24,070 --> 02:24:26,410
>de um rosto sorridente dentro de um arquivo.
2971
02:24:26,410 --> 02:24:31,000
>Se você tiver um arquivo de bitmap, um mapa
de bits, uma grade de bits, esses bits,
2972
02:24:31,000 --> 02:24:33,130
>muito simplesmente, podem ser
literalmente 0's e 1's.
2973
02:24:33,130 --> 02:24:37,240
>E se você atribuir a cor preta
a 0 e a cor branca a 1,
2974
02:24:37,240 --> 02:24:40,660
>você poderia pensar nesta
mesma grade de 0 e 1 representando,
2975
02:24:40,660 --> 02:24:41,930
>na verdade, um rosto sorridente.
2976
02:24:41,930 --> 02:24:43,690
>Em outras palavras, aqui estão alguns pixels.
2977
02:24:43,690 --> 02:24:45,520
>Falamos sobre pixels na semana zero.
2978
02:24:45,520 --> 02:24:49,567
>Pixels são apenas os pontos que compõem
um arquivo gráfico em seu computador.
2979
02:24:49,567 --> 02:24:50,650
>E os pixels estão por toda parte.
2980
02:24:50,650 --> 02:24:53,320
>Todos nós, agora, sintonizando ao vivo
via Zoom ou YouTube ou similares,
2981
02:24:53,320 --> 02:24:56,800
>estamos assistindo a fluxos de pixels,
que compõem várias imagens e várias
2982
02:24:56,800 --> 02:25:02,290
>imagens compondo vídeos que parecem
estar se movendo em 20 ou 30
2983
02:25:02,290 --> 02:25:04,670
>quadros por segundo.
2984
02:25:04,670 --> 02:25:08,530
>Agora, é claro, há um limite de
fidelidade nesse tipo de imagem.
2985
02:25:08,530 --> 02:25:11,097
>E é bastante comum no
caso da TV e do cinema,
2986
02:25:11,097 --> 02:25:13,930
>se houver algum bandido que foi
pego em alguma gravação de vigilância,
2987
02:25:13,930 --> 02:25:17,050
>ou similares, invariavelmente,
o staff do Direito
2988
02:25:17,050 --> 02:25:19,930
>pode melhorar o vídeo e aumentar, para ver
2989
02:25:19,930 --> 02:25:24,710
>exatamente a pessoa
que cometeu tal crime.
2990
02:25:24,710 --> 02:25:26,140
>Bem, isso tudo é um absurdo.
2991
02:25:26,140 --> 02:25:29,367
>E deriva de alguns dos primitivos
que introduzimos na semana zero.
2992
02:25:29,367 --> 02:25:31,450
>Na verdade, só para brincar com
isso, deixe-me ir em frente
2993
02:25:31,450 --> 02:25:34,990
>e passar alguns segundos desse
programa de TV aqui nos EUA
2994
02:25:34,990 --> 02:25:39,670
>chamado CSI, apenas para lhe dar uma
noção de quão comum esse tipo de lógica
2995
02:25:39,670 --> 02:25:40,180
>é.
2996
02:25:40,180 --> 02:25:41,140
>[REPRODUÇÃO DE VÍDEO]
2997
02:25:41,140 --> 02:25:43,330
>- Nós sabemos.
2998
02:25:43,330 --> 02:25:46,930
>- Isso às 9:15, Ray
Santoya estava no caixa eletrônico.
2999
02:25:46,930 --> 02:25:50,380
>- Então a questão é,
o que ele estava fazendo às 9:16?
3000
02:25:50,380 --> 02:25:53,180
>- Atirando com sua 9 milímetros
em alguma coisa.
3001
02:25:53,180 --> 02:25:54,820
>Talvez ele tenha visto o atirador.
3002
02:25:54,820 --> 02:25:56,920
>- Ou estava trabalhando com ele.
3003
02:25:56,920 --> 02:25:59,490
>- Espere, volte um.
3004
02:25:59,490 --> 02:26:00,481
>- O que você vê?
3005
02:26:00,481 --> 02:26:05,291
>[CLICANDO]
3006
02:26:07,700 --> 02:26:11,420
>- Traga o rosto para cima, tela inteira.
3007
02:26:11,420 --> 02:26:12,530
>- Os óculos dele.
3008
02:26:12,530 --> 02:26:13,982
>- Há um reflexo.
3009
02:26:13,982 --> 02:26:17,426
>[DIGITANDO]
3010
02:26:23,840 --> 02:26:25,620
>- Esse é o time de beisebol, Neuvitas.
3011
02:26:25,620 --> 02:26:26,630
>Esse é o logotipo deles.
3012
02:26:26,630 --> 02:26:29,075
>- E está falando com quem
está vestindo essa jaqueta.
3013
02:26:29,075 --> 02:26:31,160
>- Podemos ter uma testemunha.
3014
02:26:31,160 --> 02:26:32,700
>- Para ambos os tiroteios.
3015
02:26:32,700 --> 02:26:33,283
>[FIM DA REPRODUÇÃO]
3016
02:26:33,283 --> 02:26:36,408
>DAVID MALAN: Então, infelizmente,
hoje vamos estragar muitos filmes e séries
3017
02:26:36,408 --> 02:26:38,650
>para você, porque você não pode
simplesmente aumentar o zoom infinitamente
3018
02:26:38,650 --> 02:26:41,250
>e ver mais informações se essas
informações não estiverem lá.
3019
02:26:41,250 --> 02:26:43,750
>no fim das contas, há apenas
um número finito de bits.
3020
02:26:43,750 --> 02:26:46,120
>E, caso em questão, aqui está
uma fotografia de Brian.
3021
02:26:46,120 --> 02:26:48,580
>E você pode ver que,
há um brilho em seus olhos.
3022
02:26:48,580 --> 02:26:50,930
>Vamos ver o que estava
refletido no olho dele ali.
3023
02:26:50,930 --> 02:26:53,410
>E se dermos um zoom
nesta imagem de Brian,
3024
02:26:53,410 --> 02:26:57,730
>e talvez possamos ampliar um pouco mais,
isso é tudo o que existe.
3025
02:26:57,730 --> 02:27:00,160
>Você não pode simplesmente clicar
no botão aprimorar e ver mais,
3026
02:27:00,160 --> 02:27:02,368
>porque no fim das contas,
são apenas pixels.
3027
02:27:02,368 --> 02:27:06,310
>E pixels, como visto na semana zero, são apenas
0's e 1's, finitamente.
3028
02:27:06,310 --> 02:27:08,470
>Então, o que você vê é o que você obtém.
3029
02:27:08,470 --> 02:27:12,190
>Agora, com isso dito - e na verdade,
podemos zombar disso também, aqui.
3030
02:27:12,190 --> 02:27:14,830
>Vamos reproduzir um outro
clipe curto de Futurama,
3031
02:27:14,830 --> 02:27:18,423
>que mostra esse ponto também,
mas de forma mais divertida.
3032
02:27:18,423 --> 02:27:19,090
>[REPRODUÇÃO DE VÍDEO]
3033
02:27:19,090 --> 02:27:23,250
>- Aumente a velocidade da morte.
3034
02:27:23,250 --> 02:27:24,770
>Por que ainda está borrado?
3035
02:27:24,770 --> 02:27:26,710
>- Essa é toda a resolução que temos.
3036
02:27:26,710 --> 02:27:29,050
>Aumentar o zoom não o
torna mais claro.
3037
02:27:29,050 --> 02:27:31,220
>- Fazem isso no CSI: Miami.
3038
02:27:31,220 --> 02:27:32,020
>- [SUSPIRAR]
3039
02:27:32,020 --> 02:27:32,170
>[FIM DA REPRODUÇÃO]
3040
02:27:32,170 --> 02:27:35,212
>DAVID MALAN: Então, temos dois clipes
conversando, na verdade, um com o outro.
3041
02:27:35,212 --> 02:27:37,330
>Mas tenho que atualizar as coisas para 2020.
3042
02:27:37,330 --> 02:27:41,972
>Você não pode pegar a internet
hoje em dia ou a revista hoje em dia,
3043
02:27:41,972 --> 02:27:43,930
>que de alguma forma não mencione
3044
02:27:43,930 --> 02:27:45,850
>aprendizado de máquina e
inteligência artificial
3045
02:27:45,850 --> 02:27:48,005
>e algoritmos sofisticados por meio
dos quais você pode fazer coisas
3046
02:27:48,005 --> 02:27:49,630
>que anteriormente não era possível.
3047
02:27:49,630 --> 02:27:51,460
>E isso é meio
que o caso.
3048
02:27:51,460 --> 02:27:56,290
>Você deve se lembrar da semana zero,
que encontramos esta bela aquarela
3049
02:27:56,290 --> 02:28:00,250
>de pintura nos arquivos de Harvard que tem
apenas cerca de 11 polegadas de altura total.
3050
02:28:00,250 --> 02:28:03,700
>E ainda assim, de alguma forma, tem
13 pés de altura aqui atrás de mim.
3051
02:28:03,700 --> 02:28:06,533
>Agora, normalmente, se você fosse apenas
realçar esta pintura em aquarela,
3052
02:28:06,533 --> 02:28:08,658
>começaria a parecer muito
estúpido muito rapidamente
3053
02:28:08,658 --> 02:28:10,570
>com muita e muita
pixelização, mesmo se você
3054
02:28:10,570 --> 02:28:12,940
>usar uma câmera muito sofisticada,
como costumam fazer,
3055
02:28:12,940 --> 02:28:14,440
>para capturar a imagem original.
3056
02:28:14,440 --> 02:28:16,810
>Mas queríamos aumentar
para 4 metros de altura
3057
02:28:16,810 --> 02:28:21,110
>para que ficasse em alta
qualidade o tempo todo.
3058
02:28:21,110 --> 02:28:24,790
>E aí, usamos o
aprimoramento, de certa forma.
3059
02:28:24,790 --> 02:28:28,640
>Então, usando, para encurtar a longa história, algoritmos
mais sofisticados do que os da semana passada,
3060
02:28:28,640 --> 02:28:31,690
>você pode usar inteligência
artificial, aprendizado de máquina,
3061
02:28:31,690 --> 02:28:36,130
>para analisar os dados e
encontrar padrões onde não havia -
3062
02:28:36,130 --> 02:28:38,280
>que não são necessariamente
visíveis ao olho humano.
3063
02:28:38,280 --> 02:28:41,590
>Por exemplo, se pegarmos o original
aqui e começarmos a aumentar o zoom,
3064
02:28:41,590 --> 02:28:43,600
>parece muito bom nesta resolução.
3065
02:28:43,600 --> 02:28:44,720
>Mas é muito bom.
3066
02:28:44,720 --> 02:28:48,730
>Você não vê o fato de que
isso era tinta em uma tela real.
3067
02:28:48,730 --> 02:28:50,707
>Então, isso foi apenas
um zoom no Photoshop.
3068
02:28:50,707 --> 02:28:52,540
>Mas quando você
executa uma imagem como esta
3069
02:28:52,540 --> 02:28:55,990
>por meio de software sofisticado baseado em
aprendizado de máquina, inteligência artificial,
3070
02:28:55,990 --> 02:28:58,570
>você pode começar a
melhorá-la e ver,
3071
02:28:58,570 --> 02:29:01,390
>não apenas esta janela do
topo de um dos edifícios, que
3072
02:29:01,390 --> 02:29:03,520
>é bem borrado
aqui no Photoshop,
3073
02:29:03,520 --> 02:29:05,480
>mas você pode começar a ver mais detalhes.
3074
02:29:05,480 --> 02:29:08,750
>Então, isso é literalmente o antes,
apenas ampliando no Photoshop.
3075
02:29:08,750 --> 02:29:12,572
>Isso é depois de aplicar algoritmos
sofisticados de inteligência artificial
3076
02:29:12,572 --> 02:29:15,280
>que vemos, espere um minuto,
há uma pequena descoloração ali.
3077
02:29:15,280 --> 02:29:17,072
>Espere, há um pouco
de descoloração aí.
3078
02:29:17,072 --> 02:29:20,830
>E hoje em dia, o aprimoramento está
cada vez mais se tornando uma realidade.
3079
02:29:20,830 --> 02:29:22,450
>Ainda está melhorando.
3080
02:29:22,450 --> 02:29:25,270
>Não é ressuscitar informações
que necessariamente existiam.
3081
02:29:25,270 --> 02:29:28,240
>Mas sim acertar mais, algoritmicamente,
3082
02:29:28,240 --> 02:29:30,487
>para reconstruir o que a
imagem era.
3083
02:29:30,487 --> 02:29:32,320
>E se ampliarmos ainda
mais, você pode, talvez,
3084
02:29:32,320 --> 02:29:35,440
>ver que isso está começando a ficar
borrado se você usar apenas o Photoshop
3085
02:29:35,440 --> 02:29:36,578
>e continuar ampliando.
3086
02:29:36,578 --> 02:29:38,620
>Mas se você executar por meio de
algoritmos sofisticados o suficiente
3087
02:29:38,620 --> 02:29:40,780
>e começar a notar pequenas
descolorações que
3088
02:29:40,780 --> 02:29:44,920
>não são super visíveis para o olho
humano, podemos melhorar ainda mais.
3089
02:29:44,920 --> 02:29:46,540
>E você não pode fazer isso infinitamente.
3090
02:29:46,540 --> 02:29:48,550
>E, de certa forma, estamos
criando informações
3091
02:29:48,550 --> 02:29:51,282
>onde não há necessariamente
essa informação lá.
3092
02:29:51,282 --> 02:29:54,490
>Então, se esses tipos de coisas se
mantêm no tribunal é outra questão.
3093
02:29:54,490 --> 02:29:56,920
>Mas pode melhorar a fidelidade
de imagens como esta.
3094
02:29:56,920 --> 02:30:02,570
>E, isso nos permitiu
ampliar de 11 polegadas a 13 pés.
3095
02:30:02,570 --> 02:30:05,920
>Então, quando se trata de manipular
imagens, em última análise, nós
3096
02:30:05,920 --> 02:30:10,030
>temos algumas capacidades programáticas,
incluindo este ponteiro de arquivo,
3097
02:30:10,030 --> 02:30:13,280
>como acabamos de ver, e também,
algumas outras funções.
3098
02:30:13,280 --> 02:30:15,550
>E nossos exemplos finais,
aqui, vão colocar a fundação
3099
02:30:15,550 --> 02:30:17,380
>pelo que você fará
esta semana, que
3100
02:30:17,380 --> 02:30:21,250
>é manipular seus próprios arquivos
gráficos com um novo entendimento
3101
02:30:21,250 --> 02:30:25,270
>de ponteiros e endereços e agora
arquivos e entrada e saída.
3102
02:30:25,270 --> 02:30:30,010
>Por exemplo, vou prosseguir e
abrir um programa aqui chamado -
3103
02:30:30,010 --> 02:30:32,110
>me dê apenas um segundo.
3104
02:30:32,110 --> 02:30:37,660
>Vou abrir um programa
aqui chamado jpeg.c.
3105
02:30:37,660 --> 02:30:40,610
>E este programa, jpeg.c,
que escrevi antes,
3106
02:30:40,610 --> 02:30:43,400
>que está no site do
curso, faz o seguinte.
3107
02:30:43,400 --> 02:30:46,510
>Primeiro, ele declara um tipo chamado byte.
3108
02:30:46,510 --> 02:30:49,990
>Acontece que, em C, não há uma
definição comum do que é um byte.
3109
02:30:49,990 --> 02:30:51,610
>Um bite, como conhecemos, é um pedaço.
3110
02:30:51,610 --> 02:30:53,680
>E acontece que a maneira
mais simples de criar
3111
02:30:53,680 --> 02:30:57,250
>um byte é definir o nosso pedaço,
assim como definimos uma string,
3112
02:30:57,250 --> 02:31:01,840
>assim como definimos outros tipos
também, como um estudante, a fim -
3113
02:31:01,840 --> 02:31:04,640
>de que uma pessoa possa
nos fornecer um byte.
3114
02:31:04,640 --> 02:31:07,210
>Portanto, esta primeira linha de
código apenas declara um tipo de dados
3115
02:31:07,210 --> 02:31:11,830
>chamado byte, usando outro tipo de dados mais
misterioso chamado u int a sublinhado t.
3116
02:31:11,830 --> 02:31:13,330
>Mas mais disso no conjunto de problemas.
3117
02:31:13,330 --> 02:31:15,820
>Acabamos de inventar
algo chamado byte.
3118
02:31:15,820 --> 02:31:17,928
>Observe, neste programa,
estou ressuscitando a ideia
3119
02:31:17,928 --> 02:31:21,220
>da segunda semana de argumentos de linha de comando,
onde podemos obter a entrada do usuário.
3120
02:31:21,220 --> 02:31:23,860
>Observe que estou verificando se o
usuário digitou dois argumentos.
3121
02:31:23,860 --> 02:31:27,520
>E s não, estou devolvendo um
imediatamente para significar erro.
3122
02:31:27,520 --> 02:31:30,490
>Na linha 17, estou usando minha nova técnica.
3123
02:31:30,490 --> 02:31:34,210
>Estou abrindo um arquivo
usando o nome do arquivo
3124
02:31:34,210 --> 02:31:36,050
>que o humano digitou
na linha de comando.
3125
02:31:36,050 --> 02:31:40,270
>E, desta vez, estou abrindo para ler
"r" em vez de a.
3126
02:31:40,270 --> 02:31:41,660
>Mas se não houver um arquivo -
3127
02:31:41,660 --> 02:31:44,920
>então, se o arquivo bang, isto é,
se arquivo de ponto de exclamação,
3128
02:31:44,920 --> 02:31:47,990
>ou se o arquivo for igual a NULL,
significam a mesma coisa.
3129
02:31:47,990 --> 02:31:51,040
>Posso prosseguir e devolver
um, significando um erro.
3130
02:31:51,040 --> 02:31:53,710
>Aqui embaixo, estou fazendo
algo um pouco inteligente.
3131
02:31:53,710 --> 02:31:56,890
>Acontece que com uma
probabilidade muito alta,
3132
02:31:56,890 --> 02:32:01,640
>você pode determinar se algum arquivo é um
jpeg olhando apenas para os três primeiros
3133
02:32:01,640 --> 02:32:02,140
>bytes.
3134
02:32:02,140 --> 02:32:04,720
>Muitos formatos de arquivo têm o
que chamamos de números mágicos
3135
02:32:04,720 --> 02:32:06,350
>no início de seus arquivos.
3136
02:32:06,350 --> 02:32:10,990
>E esses são números padrão da
indústria, 1 ou 2 ou 3 ou mais deles,
3137
02:32:10,990 --> 02:32:13,910
>que normalmente se espera que
esteja no início de um arquivo,
3138
02:32:13,910 --> 02:32:16,240
>para que um programa possa verificar
rapidamente, isso é um jpeg?
3139
02:32:16,240 --> 02:32:16,960
>Isso é um GIF?
3140
02:32:16,960 --> 02:32:18,070
>Este é um documento do Word?
3141
02:32:18,070 --> 02:32:19,300
>Este é um arquivo Excel?
3142
02:32:19,300 --> 02:32:21,910
>Eles tendem a ter esses
números no início deles.
3143
02:32:21,910 --> 02:32:26,020
>E os JPEGs têm uma sequência de
bytes que estamos prestes a ver.
3144
02:32:26,020 --> 02:32:29,770
>Esta linha de código 24 aqui, como você
verá no próximo conjunto de problemas,
3145
02:32:29,770 --> 02:32:33,070
>é como você pode dar a si mesmo um
buffer de bytes, especificamente
3146
02:32:33,070 --> 02:32:35,320
>um array de três bytes.
3147
02:32:35,320 --> 02:32:38,380
>A próxima linha de código, como você verá
na próxima semana, é chamada de fread.
3148
02:32:38,380 --> 02:32:40,720
>fread, como o nome
sugere, lê um arquivo.
3149
02:32:40,720 --> 02:32:42,940
>Ou seja, ele pega bytes de um arquivo.
3150
02:32:42,940 --> 02:32:45,790
>E é um pouco sofisticado de usar,
mas você ficará mais confortável
3151
02:32:45,790 --> 02:32:47,140
>com isso ao longo do tempo.
3152
02:32:47,140 --> 02:32:52,060
>Ele lê neste buffer, seu primeiro
argumento, o tamanho deste tipo de dados,
3153
02:32:52,060 --> 02:32:53,050
>o tamanho de um byte.
3154
02:32:53,050 --> 02:32:58,250
>E ele lê muitos desses tipos
de dados deste arquivo.
3155
02:32:58,250 --> 02:33:01,480
>Então, novamente, é para argumentos,
o que é muito pelo que vimos.
3156
02:33:01,480 --> 02:33:08,230
>Mas ele lê a partir deste arquivo,
três bytes nesse array,
3157
02:33:08,230 --> 02:33:09,770
>buffer também conhecido como, denominado bytes.
3158
02:33:09,770 --> 02:33:13,460
>Então é assim que você escreve código
que não coloca dados em um arquivo,
3159
02:33:13,460 --> 02:33:14,650
>mas lê a partir dele.
3160
02:33:14,650 --> 02:33:16,700
>E então aqui, observe nosso hexadecimal.
3161
02:33:16,700 --> 02:33:18,190
>Então, fechamos o círculo.
3162
02:33:18,190 --> 02:33:23,110
>Se bytes, colchete 0 é
igual a 0xff e bytes
3163
02:33:23,110 --> 02:33:27,080
>colchete 1 é igual a 0xd8 e bytes
colchete 2 é igual a 0xff,
3164
02:33:27,080 --> 02:33:28,960
>isso definitivamente parece enigmático para você.
3165
02:33:28,960 --> 02:33:31,570
>Mas isso é só porque eu
procurei no manual de jpegs,
3166
02:33:31,570 --> 02:33:34,900
>e acontece que quase
qualquer JPEG, ao contrário,
3167
02:33:34,900 --> 02:33:39,430
>deve começar com 0xff, 0xd8, 0xff.
3168
02:33:39,430 --> 02:33:43,450
>Esses são os primeiros três bytes de
qualquer jpeg em seu Mac, seu PC,
3169
02:33:43,450 --> 02:33:44,350
>na internet.
3170
02:33:44,350 --> 02:33:46,300
>Sempre existem esses três bytes.
3171
02:33:46,300 --> 02:33:50,500
>Acontece que o quarto byte
ainda decide se
3172
02:33:50,500 --> 02:33:51,730
>um arquivo é, na verdade, um jpeg.
3173
02:33:51,730 --> 02:33:54,640
>Mas o algoritmo para isso é um pouco
mais elaborado, então mantive-o simples.
3174
02:33:54,640 --> 02:33:59,020
>Se os primeiros três bytes de um arquivo
forem esses, talvez você tem um jpeg.
3175
02:33:59,020 --> 02:34:01,150
>Mas se você não tiver
exatamente esses três bytes,
3176
02:34:01,150 --> 02:34:02,920
>você definitivamente não tem um JPEG.
3177
02:34:02,920 --> 02:34:05,270
>E então o que posso fazer,
aqui, é o seguinte.
3178
02:34:05,270 --> 02:34:09,700
>No código de hoje - deixe-me prosseguir
e pegar dois outros arquivos
3179
02:34:09,700 --> 02:34:11,620
>que eu trouxe comigo.
3180
02:34:11,620 --> 02:34:16,210
>E acontece que é uma
fotografia novamente.
3181
02:34:16,210 --> 02:34:18,160
>Dê-me um segundo.
3182
02:34:18,160 --> 02:34:24,010
>Eu trouxe comigo alguns arquivos,
um dos quais é chamado brian.jpeg,
3183
02:34:24,010 --> 02:34:25,870
>que é a mesma foto de Brian.
3184
02:34:25,870 --> 02:34:28,030
>E então eu tenho um gif,
o que é claro, não é
3185
02:34:28,030 --> 02:34:31,210
>um jpeg, que é esse gato digitando aqui.
3186
02:34:31,210 --> 02:34:33,250
>E o que eu, efetivamente,
tem na minha frente agora
3187
02:34:33,250 --> 02:34:37,870
>é um programa que, se eu fizer make jpeg,
porque este arquivo é jpeg.c,
3188
02:34:37,870 --> 02:34:43,360
>e executo o ./ jpeg,
posso digitar algo como cat.gif
3189
02:34:43,360 --> 02:34:46,990
>na linha de comando como um argumento,
Enter, e eu não verei nenhum.
3190
02:34:46,990 --> 02:34:51,550
>Por outro lado, se eu passar o JPEG de Brian
na linha de comando como um argumento,
3191
02:34:51,550 --> 02:34:52,630
>Eu vejo talvez.
3192
02:34:52,630 --> 02:34:54,430
>E novamente, talvez
apenas porque o algoritmo
3193
02:34:54,430 --> 02:34:56,638
>para julgar
se algo é um JPEG
3194
02:34:56,638 --> 02:34:58,550
>é um pouco mais complicado do que isso.
3195
02:34:58,550 --> 02:35:02,590
>Mas, agora posso acessar os bytes
individuais e, portanto, os pixels,
3196
02:35:02,590 --> 02:35:06,310
>ao que parece, de um arquivo de imagem.
3197
02:35:06,310 --> 02:35:08,575
>E, podemos até fazer isso.
3198
02:35:08,575 --> 02:35:10,450
>Eu vou
mostrar um último programa
3199
02:35:10,450 --> 02:35:13,960
>que escrevemos deliberadamente antes,
apenas para lhe dar um gostinho do que está
3200
02:35:13,960 --> 02:35:15,790
>vindo com o próximo conjunto de problemas.
3201
02:35:15,790 --> 02:35:19,480
>Este programa é uma reimplementação
do programa que você provavelmente
3202
02:35:19,480 --> 02:35:21,820
>deve ter usado uma ou mais vezes chamado de CP.
3203
02:35:21,820 --> 02:35:25,570
>Lembre-se de que o CP é um
programa no IDE e no Linux,
3204
02:35:25,570 --> 02:35:27,730
>de forma mais geral, isso permite
que você copie um arquivo.
3205
02:35:27,730 --> 02:35:31,660
>Você faz CP, espaço, nome do arquivo,
espaço, o novo nome de arquivo.
3206
02:35:31,660 --> 02:35:32,650
>Como é que isso funciona?
3207
02:35:32,650 --> 02:35:37,090
>Agora tenho todos os blocos de construção
com os quais posso copiar arquivos sozinho.
3208
02:35:37,090 --> 02:35:39,100
>Então, novamente, estou definindo um byte aqui.
3209
02:35:39,100 --> 02:35:41,930
>Estou definindo main como aceitando
argumentos de linha de comando aqui.
3210
02:35:41,930 --> 02:35:43,000
>E observe uma mudança.
3211
02:35:43,000 --> 02:35:44,800
>Não estou usando a biblioteca CS50.
3212
02:35:44,800 --> 02:35:52,090
>Então, mesmo o que antes era string
na semana dois agora é char*.
3213
02:35:52,090 --> 02:35:55,450
>Mesmo aqui para argv, estou
garantindo que os tipos humanos
3214
02:35:55,450 --> 02:36:00,580
>em três palavras, o nome do programa
e o arquivo de origem e o arquivo
3215
02:36:00,580 --> 02:36:01,180
>de destino.
3216
02:36:01,180 --> 02:36:02,410
>Estou usando o fopen novamente.
3217
02:36:02,410 --> 02:36:06,100
>Estou abrindo o arquivo
de origem aqui do argv1.
3218
02:36:06,100 --> 02:36:07,358
>Estou garantindo que não seja nulo.
3219
02:36:07,358 --> 02:36:08,650
>E então estou desistindo, se for.
3220
02:36:08,650 --> 02:36:13,030
>Eu estou então - aqui está algo novo,
abrindo o arquivo de destino aqui, também
3221
02:36:13,030 --> 02:36:13,870
>com fopen.
3222
02:36:13,870 --> 02:36:15,700
>Mas estou usando "w."
3223
02:36:15,700 --> 02:36:19,630
>Estou abrindo um arquivo com r, um
arquivo para w, porque quero ler de um
3224
02:36:19,630 --> 02:36:21,160
>e escrever para o outro.
3225
02:36:21,160 --> 02:36:25,360
>E aqui embaixo, este loop
é uma maneira inteligente
3226
02:36:25,360 --> 02:36:27,370
>de copiar um arquivo para outro.
3227
02:36:27,370 --> 02:36:30,790
>Estou me dando um buffer de um byte,
então apenas uma variável temporária, apenas
3228
02:36:30,790 --> 02:36:33,090
>como a temperatura de Brian ou o copo vazio.
3229
02:36:33,090 --> 02:36:35,160
>E estou usando essa função, fread.
3230
02:36:35,160 --> 02:36:39,750
>Estou lendo naquele buffer por meio de
seu endereço, do tamanho de um byte,
3231
02:36:39,750 --> 02:36:42,870
>especificamente um byte
do arquivo de origem.
3232
02:36:42,870 --> 02:36:47,940
>E então, nesse mesmo loop, estou escrevendo
desse buffer, do tamanho de um byte,
3233
02:36:47,940 --> 02:36:50,950
>especificamente um byte,
para o destino.
3234
02:36:50,950 --> 02:36:53,760
>Então, o programa CP
que você deve ter me visto usar
3235
02:36:53,760 --> 02:36:57,090
>ou você mesmo usou para copiar arquivos,
está literalmente fazendo isso.
3236
02:36:57,090 --> 02:36:59,790
>está abrindo um arquivo,
iterando sobre todos os seus bytes,
3237
02:36:59,790 --> 02:37:02,010
>e copiando da
origem ao destino.
3238
02:37:02,010 --> 02:37:04,260
>E por último, está fechando o arquivo.
3239
02:37:04,260 --> 02:37:06,360
>E esses dois últimos exemplos
deliberadamente rápidos,
3240
02:37:06,360 --> 02:37:11,130
>porque toda esta semana será gasta
mergulhando em I/O de arquivos e imagens
3241
02:37:11,130 --> 02:37:11,890
>como esses.
3242
02:37:11,890 --> 02:37:16,560
>Mas tudo o que fizemos foi usar esses
fread, fopen e fwrite e f close,
3243
02:37:16,560 --> 02:37:18,610
>para manipular esses mesmos arquivos.
3244
02:37:18,610 --> 02:37:21,975
>Então, por exemplo, se eu fizer
isso agora, deixe-me fazer make cp.
3245
02:37:21,975 --> 02:37:25,800
>OK, parece compilar,
./ cp, brian.jpeg.
3246
02:37:25,800 --> 02:37:27,750
>Que tal brian2.jpeg?
3247
02:37:27,750 --> 02:37:28,680
>E Enter.
3248
02:37:28,680 --> 02:37:29,880
>Parece que nada aconteceu.
3249
02:37:29,880 --> 02:37:33,240
>Mas se eu entrar aqui e
clicar duas vezes em brian2,
3250
02:37:33,240 --> 02:37:37,420
>vemos que temos uma segunda
cópia do arquivo real de Brian.
3251
02:37:37,420 --> 02:37:41,560
>Portanto, na próxima semana, você experimentará
vários formatos de arquivo para imagens.
3252
02:37:41,560 --> 02:37:42,580
>O primeiro é jpeg.
3253
02:37:42,580 --> 02:37:45,000
>E nós daremos a você a
chamada imagem forense
3254
02:37:45,000 --> 02:37:47,938
>de um monte de fotos de um
cartão de memória digital.
3255
02:37:47,938 --> 02:37:50,730
>Na verdade, é muito comum hoje em
dia, certamente na aplicação do Direito,
3256
02:37:50,730 --> 02:37:53,580
>fazer cópias forenses de discos
rígidos, de dispositivos de mídia,
3257
02:37:53,580 --> 02:37:55,920
>de telefones e outros dispositivos,
e então analisá-los
3258
02:37:55,920 --> 02:37:58,650
>em busca de dados perdidos,
corrompidos ou excluídos.
3259
02:37:58,650 --> 02:38:01,980
>Faremos exatamente isso, onde,
você vai escrever um programa que recupera
3260
02:38:01,980 --> 02:38:05,850
>JPEGs que foram excluídos acidentalmente
de um cartão de memória digital.
3261
02:38:05,850 --> 02:38:08,100
>E nós daremos a você todas as
cópias desse cartão de memória
3262
02:38:08,100 --> 02:38:11,220
>fazendo uma imagem forense disso,
que está copiando todos os 0's e 1's
3263
02:38:11,220 --> 02:38:13,710
>de uma câmera e entregando
a você em um arquivo
3264
02:38:13,710 --> 02:38:16,710
>que você pode abrir e escrever.
3265
02:38:16,710 --> 02:38:18,930
>Também apresentaremos
os arquivos de bitmap,
3266
02:38:18,930 --> 02:38:22,290
>BMP's, popularizado pelo
funcionamento do Windows
3267
02:38:22,290 --> 02:38:24,160
>com uso principal em papéis de parede
e similares.
3268
02:38:24,160 --> 02:38:28,470
>Mas vamos usá-los para implementar
usando ponteiros e I/O de arquivo,
3269
02:38:28,470 --> 02:38:30,550
>seu próprio filtro semelhante ao do Instagram.
3270
02:38:30,550 --> 02:38:33,540
>Então, vamos tirar esta foto,
aqui, da passarela do Weeks
3271
02:38:33,540 --> 02:38:35,578
>aqui em Cambridge,
Massachusetts - Harvard.
3272
02:38:35,578 --> 02:38:37,620
>E vamos implementar
uma série de filtros,
3273
02:38:37,620 --> 02:38:39,328
>tomando esta imagem
original, por exemplo,
3274
02:38:39,328 --> 02:38:41,910
>e dessaturando-a,
tornando-a preto e branco,
3275
02:38:41,910 --> 02:38:45,210
>iterando sobre todos os pixels de cima
para baixo, da esquerda para a direita,
3276
02:38:45,210 --> 02:38:49,350
>e reconhecendo todas as cores, como vermelho,
verde, azul ou qualquer coisa intermediária,
3277
02:38:49,350 --> 02:38:53,467
>e mudá-las para algum tom de
cinza, fazendo um filtro sépia,
3278
02:38:53,467 --> 02:38:55,800
>fazendo as coisas parecerem antigas,
como esta foto tirada
3279
02:38:55,800 --> 02:39:00,810
>muitos anos atrás, aplicando da mesma forma
uma heurística que altera as cores de todos
3280
02:39:00,810 --> 02:39:02,345
>os pixels nesta imagem.
3281
02:39:02,345 --> 02:39:05,220
>Vamos fazer com que você vire
para colocar esse pixel aqui
3282
02:39:05,220 --> 02:39:06,630
>e este pixel ali.
3283
02:39:06,630 --> 02:39:09,690
>E você apreciará exatamente como
os arquivos são implementados
3284
02:39:09,690 --> 02:39:12,180
>dentro de seu próprio disco rígido e telefone.
3285
02:39:12,180 --> 02:39:17,580
>E você vai até implementar, por exemplo,
um filtro de desfoque, que não por acaso,
3286
02:39:17,580 --> 02:39:20,010
>torna mais difícil ver o
que está acontecendo aqui,
3287
02:39:20,010 --> 02:39:23,700
>porque você está começando a, agora,
calcular a média dos pixels que estão próximos
3288
02:39:23,700 --> 02:39:27,090
>uns aos outros para encobrir
as coisas e deliberadamente
3289
02:39:27,090 --> 02:39:28,990
>tornar mais difícil ver aqui.
3290
02:39:28,990 --> 02:39:30,733
>E então nós ainda, se
você quiser, teremos
3291
02:39:30,733 --> 02:39:33,150
>você implementando detecção de borda,
se ficar melhor para você,
3292
02:39:33,150 --> 02:39:37,020
>onde você encontrará bordas de todos
os objetos físicos nessas imagens,
3293
02:39:37,020 --> 02:39:43,350
>a fim de detectá-las no código
e criar uma arte visual como esta.
3294
02:39:43,350 --> 02:39:44,220
>Agora, isso é muita coisa.
3295
02:39:44,220 --> 02:39:45,960
>E eu sei que os ponteiros
são geralmente considerados
3296
02:39:45,960 --> 02:39:47,820
>estar entre os recursos
mais desafiadores do C,
3297
02:39:47,820 --> 02:39:49,403
>e certamente, programação em geral.
3298
02:39:49,403 --> 02:39:52,140
>Então, se você está sentindo
que já viu muita coisa, foi isso mesmo.
3299
02:39:52,140 --> 02:39:55,290
>Mas agora você tem a
habilidade, tanto hoje
3300
02:39:55,290 --> 02:39:59,040
>ou em um prazo muito próximo, para entender
até mesmo quadrinhos XKCD como a maioria
3301
02:39:59,040 --> 02:40:00,990
>dos cientistas
da computação.
3302
02:40:00,990 --> 02:40:05,130
>Então, nosso look final para você,
hoje, está essa brincadeira aqui.
3303
02:40:05,130 --> 02:40:10,050
>E mesmo que eu não possa
necessariamente ouvir você de longe,
3304
02:40:10,050 --> 02:40:12,690
>vou apenas assumir, em nossos
momentos finais de hoje,
3305
02:40:12,690 --> 02:40:16,650
>que todo mundo está explodindo
em uma gargalhada muito nerd.
3306
02:40:16,650 --> 02:40:19,530
>E vejo alguns sorrisos, pelo
menos, o que é reconfortante.
3307
02:40:19,530 --> 02:40:21,480
>Este foi, então, o CS50.
3308
02:40:21,480 --> 02:40:23,010
>Nos vemos na próxima.
3309
02:40:23,010 --> 02:40:26,360
>[MÚSICA, TOCANDO]