1 00:00:00,000 --> 00:00:02,500 [Powered by Google Translate] [Seção 5 - Mais Confortável] 2 00:00:02,500 --> 00:00:04,690 [Rob Bowden - Harvard University] 3 00:00:04,690 --> 00:00:07,250 [Esta é CS50. - CS50.TV] 4 00:00:08,990 --> 00:00:14,250 >> Como eu disse em meu e-mail, há um monte de coisas que você pode usar 5 00:00:14,250 --> 00:00:17,060 além do aparelho de realmente fazer os conjuntos de problemas. 6 00:00:17,060 --> 00:00:19,910 Nós recomendamos que você faça isso no aparelho apenas porque então nós podemos ajudá-lo com mais facilidade 7 00:00:19,910 --> 00:00:22,070 e sabemos como tudo vai funcionar. 8 00:00:22,070 --> 00:00:26,950 Mas, como um exemplo de onde você pode fazer coisas, digamos, se você não tem acesso 9 00:00:26,950 --> 00:00:31,570 para um aparelho ou você quer trabalhar no porão do Centro de Ciências - 10 00:00:31,570 --> 00:00:33,090 que na verdade eles têm o aparelho também - 11 00:00:33,090 --> 00:00:35,150 se você quer trabalhar em qualquer lugar. 12 00:00:35,150 --> 00:00:42,370 Um exemplo é você já viu / ouviu falar de SSH? 13 00:00:44,380 --> 00:00:47,780 O SSH é basicamente como conectar-se a alguma coisa. 14 00:00:47,780 --> 00:00:51,340 Na verdade, agora eu estou SSHed no aparelho. 15 00:00:51,340 --> 00:00:54,290 Eu nunca trabalhar diretamente no aparelho. 16 00:00:55,930 --> 00:01:01,060 Aqui está o aparelho, e se você olhar para baixo aqui você vê este endereço IP. 17 00:01:01,060 --> 00:01:03,650 Eu nunca trabalhar no próprio aparelho; 18 00:01:03,650 --> 00:01:08,840 Eu sempre vinha de uma janela janela de terminal / iTerm2. 19 00:01:08,840 --> 00:01:15,910 Você pode SSH para que o endereço IP, o ssh jharvard@192.168.129.128. 20 00:01:15,910 --> 00:01:20,390 Lembro-me de que esse número muito facilmente porque é um padrão tão agradável. 21 00:01:20,390 --> 00:01:24,920 Mas isso vai me pedir a minha senha, e agora eu estou no aparelho. 22 00:01:24,920 --> 00:01:33,060 Basicamente, neste momento, se você abriu um terminal dentro do próprio aparelho, 23 00:01:33,060 --> 00:01:36,350 esta interface, porém você usá-lo, é exatamente a mesma 24 00:01:36,350 --> 00:01:40,010 como a interface que estou usando aqui, mas agora você está SSHed. 25 00:01:42,240 --> 00:01:44,920 Você não tem que SSH para o aparelho. 26 00:01:44,920 --> 00:01:52,360 Um exemplo de outro lugar você poderia SSH é que eu tenho certeza que você tem por padrão - 27 00:01:52,360 --> 00:01:55,020 Oh. Maior. 28 00:01:55,020 --> 00:02:01,130 Todos vocês devem ter por contas padrão FAS nos servidores da FAS. 29 00:02:01,130 --> 00:02:06,840 Para mim, eu faria o SSH para rbowden@nice.fas.harvard.edu. 30 00:02:06,840 --> 00:02:11,610 Vai pedir-lhe que da primeira vez, e você diz que sim. 31 00:02:11,610 --> 00:02:15,840 Minha senha é apenas vai ser a minha senha FAS. 32 00:02:15,840 --> 00:02:22,650 E agora, eu estou SSHed aos servidores agradável, e eu posso fazer o que eu quiser aqui. 33 00:02:22,650 --> 00:02:28,560 Um monte de classes que podem ser adotadas, como a 124, vai ter de carregar coisas para aqui 34 00:02:28,560 --> 00:02:30,950 para realmente apresentar seus conjuntos de problemas. 35 00:02:30,950 --> 00:02:34,100 Mas digamos que você não tem acesso ao seu aparelho. 36 00:02:34,100 --> 00:02:37,910 Então você pode fazer coisas, como aqui, ele vai dizer - 37 00:02:37,910 --> 00:02:42,160 Este é apenas nossa seção de perguntas. 38 00:02:42,160 --> 00:02:45,070 Ele vai pedir para você fazer isso no aparelho. 39 00:02:45,070 --> 00:02:47,790 Em vez disso eu vou fazê-lo no servidor. 40 00:02:47,790 --> 00:02:50,560 Eu estou indo para descompactar isso. 41 00:02:50,560 --> 00:02:55,670 O problema vai ser que você está acostumado a usar algo como gedit 42 00:02:55,670 --> 00:02:58,160 ou o que quer no interior do aparelho. 43 00:02:58,160 --> 00:03:01,830 Você não vai ter que no servidor FAS. 44 00:03:01,830 --> 00:03:04,110 É tudo só vai ser esta interface textual. 45 00:03:04,110 --> 00:03:09,180 Então, você poderia um ou outro, tentar aprender um editor de texto que eles têm. 46 00:03:09,180 --> 00:03:12,130 Eles têm Nano. 47 00:03:12,130 --> 00:03:14,990 Nano é normalmente muito fácil de usar. 48 00:03:14,990 --> 00:03:19,470 Você pode usar as suas flechas e digite normalmente. 49 00:03:19,470 --> 00:03:21,250 Então, isso não é difícil. 50 00:03:21,250 --> 00:03:24,720 Se você quiser começar realmente a fantasia que você pode usar o Emacs, 51 00:03:24,720 --> 00:03:29,850 que eu provavelmente não deveria ter aberto, porque eu não sei nem como fechar Emacs. 52 00:03:29,850 --> 00:03:32,760 Controle X, Controle C? Sim. 53 00:03:32,760 --> 00:03:35,310 Ou você pode usar o Vim, que é o que eu uso. 54 00:03:35,310 --> 00:03:37,800 E assim essas são suas opções. 55 00:03:37,800 --> 00:03:43,830 Se você não quiser fazer isso, você também pode, se você olhar para manual.cs50.net - 56 00:03:43,830 --> 00:03:45,410 Oh. 57 00:03:45,410 --> 00:03:49,920 Em um PC, você pode SSH usando PuTTY, 58 00:03:49,920 --> 00:03:51,940 que você vai ter que baixar separadamente. 59 00:03:51,940 --> 00:03:55,460 Em um Mac, você pode apenas pelo terminal de uso padrão ou você pode baixar iTerm2, 60 00:03:55,460 --> 00:03:58,490 que é como um terminal, agradável fantasia. 61 00:03:58,490 --> 00:04:03,780 Se você vai para manual.cs50.net você verá um link para o Notepad + +, 62 00:04:03,780 --> 00:04:07,120 que é o que você pode usar em um PC. 63 00:04:07,120 --> 00:04:13,340 Ele permite que você SFTP de Notepad + +, que é basicamente SSH. 64 00:04:13,340 --> 00:04:17,750 O que isso vai deixar você fazer é editar seus arquivos localmente, 65 00:04:17,750 --> 00:04:20,670 e sempre que você quer salvá-los, ele irá salvar a nice.fas, 66 00:04:20,670 --> 00:04:23,670 onde você pode executá-los. 67 00:04:23,670 --> 00:04:26,880 E o equivalente em um Mac vai ser TextWrangler. 68 00:04:26,880 --> 00:04:28,760 Então, ele permite que você faça a mesma coisa. 69 00:04:28,760 --> 00:04:32,800 Ele permite que você edite arquivos localmente e salvá-los em nice.fas, 70 00:04:32,800 --> 00:04:35,730 onde você pode executá-los. 71 00:04:35,730 --> 00:04:40,400 Então, se você está sempre preso sem um aparelho, você tem estas opções 72 00:04:40,400 --> 00:04:44,230 ainda fazer seus conjuntos de problemas. 73 00:04:44,230 --> 00:04:48,250 O único problema vai ser que você não vai ter a biblioteca CS50 74 00:04:48,250 --> 00:04:51,580 porque nice.fas não por padrão tem isso. 75 00:04:51,580 --> 00:04:55,970 Você pode baixar a biblioteca CS50 - 76 00:04:55,970 --> 00:04:58,470 Eu não acho que eu preciso neste momento. 77 00:04:58,470 --> 00:05:03,270 Você pode baixar a biblioteca CS50 e copie-o para nice.fas, 78 00:05:03,270 --> 00:05:07,450 ou eu acho que neste momento nós não usá-lo mais de qualquer maneira. 79 00:05:07,450 --> 00:05:12,720 Ou se nós, você pode, por enquanto, substituí-lo por 80 00:05:12,720 --> 00:05:18,480 as implementações das funções na biblioteca CS50 de qualquer maneira. 81 00:05:18,480 --> 00:05:21,370 De modo que não deve ser muito de uma restrição. 82 00:05:21,370 --> 00:05:23,710 E é isso. 83 00:05:26,460 --> 00:05:29,820 >> Eu vou voltar para o aparelho agora, nós vamos fazer de tudo no aparelho. 84 00:05:29,820 --> 00:05:37,510 Olhando para nossa seção de perguntas, no início, como eu disse no meu e-mail, 85 00:05:37,510 --> 00:05:43,620 temos que falar sobre o curto você deveria assistir. 86 00:05:43,620 --> 00:05:51,980 Temos o redirecionamento & Pipes e essas três perguntas. 87 00:05:51,980 --> 00:05:56,070 >> Para que fluxo que funciona como printf escrever por padrão? 88 00:05:56,070 --> 00:05:59,130 Então córrego. O que é um fluxo? 89 00:06:06,520 --> 00:06:15,100 Um fluxo é basicamente como se fosse apenas alguns - 90 00:06:15,100 --> 00:06:21,450 Não é mesmo uma fonte de 1s e 0s. 91 00:06:21,450 --> 00:06:24,920 O fluxo é pedir aqui é a padrão. 92 00:06:24,920 --> 00:06:27,250 E de modo padrão é um fluxo que quando você escrever para ele, 93 00:06:27,250 --> 00:06:30,940 ele aparece na tela. 94 00:06:30,940 --> 00:06:36,860 A Standard, por stream, isso significa que você acabou de escrever 1s e 0s a ele, 95 00:06:36,860 --> 00:06:40,220 e a outra extremidade de saída padrão apenas lê a partir desse fluxo. 96 00:06:40,220 --> 00:06:43,540 É apenas uma seqüência de 1s e 0s. 97 00:06:43,540 --> 00:06:45,570 Você pode escrever para córregos ou você pode ler a partir de fluxos 98 00:06:45,570 --> 00:06:47,950 dependendo do que o fluxo é realmente. 99 00:06:47,950 --> 00:06:52,800 Os outros dois fluxos padrão são padrão e erro padrão. 100 00:06:52,800 --> 00:06:57,540 Padrão em é sempre que você GetString, está esperando por você para material de entrada. 101 00:06:57,540 --> 00:07:01,570 Por isso, esperando por você, é realmente à espera de padrão em, 102 00:07:01,570 --> 00:07:04,880 o que é realmente o que você começa quando você digitar no teclado. 103 00:07:04,880 --> 00:07:07,530 Você está digitando em padrão dentro 104 00:07:07,530 --> 00:07:10,050 Erro padrão é basicamente equivalente para a saída padrão, 105 00:07:10,050 --> 00:07:13,280 mas é especializada em que quando você imprimir para o erro padrão, 106 00:07:13,280 --> 00:07:16,770 você deveria apenas imprimir mensagens de erro para que 107 00:07:16,770 --> 00:07:20,200 para que você possa distinguir entre mensagens regulares impressos na tela 108 00:07:20,200 --> 00:07:24,560 contra mensagens de erro, dependendo se eles foram para fora padrão ou erro padrão. 109 00:07:24,560 --> 00:07:28,660 Arquivos também. 110 00:07:28,660 --> 00:07:32,440 Fora padrão, padrão, e erro padrão são fluxos apenas especiais, 111 00:07:32,440 --> 00:07:36,810 mas realmente qualquer arquivo, quando você abre um arquivo, ele torna-se um fluxo de bytes 112 00:07:36,810 --> 00:07:40,740 onde você pode apenas ler esse fluxo. 113 00:07:40,740 --> 00:07:47,770 Você, em sua maior parte, pode apenas pensar em um arquivo como um fluxo de bytes. 114 00:07:47,770 --> 00:07:51,190 Então, o que os fluxos que eles escrevem para por padrão? Saída padrão. 115 00:07:51,190 --> 00:07:56,980 >> Qual é a diferença entre> e? >> 116 00:07:58,140 --> 00:08:03,710 Será que alguém assistir ao vídeo antes? Okay. 117 00:08:03,710 --> 00:08:10,960 > Vai ser como você redirecionar em arquivos, 118 00:08:10,960 --> 00:08:15,240 e >> também vai redirecionar a saída em arquivos, 119 00:08:15,240 --> 00:08:17,820 mas é em vez de ir para anexar o arquivo. 120 00:08:17,820 --> 00:08:23,430 Por exemplo, digamos que eu acontecer de ter dict aqui, 121 00:08:23,430 --> 00:08:27,020 e as coisas só dentro de dict é gato, gato, cachorro, peixe, cão. 122 00:08:27,020 --> 00:08:31,530 Um comando que você tem na linha de comando é gato, 123 00:08:31,530 --> 00:08:34,539 que está indo só para imprimir o que está em um arquivo. 124 00:08:34,539 --> 00:08:40,679 Portanto, quando digo dict gato, que vai imprimir gato, cão, gato, peixe, cão. Isso é tudo o gato faz. 125 00:08:40,679 --> 00:08:46,280 Isso significa que ele impressa para a saída padrão, gato, cão, gato, peixe, cão. 126 00:08:46,280 --> 00:08:53,240 Se eu vez quer redirecionar isso para um arquivo, eu posso usar> e redirecioná-lo para o que é o arquivo. 127 00:08:53,240 --> 00:08:56,460 Eu vou chamar o arquivo de arquivo. 128 00:08:56,460 --> 00:09:00,320 Então agora eu ls, eu vou ver eu tenho um novo arquivo chamado arquivo. 129 00:09:00,320 --> 00:09:05,700 E se eu abri-lo, ele vai ter exatamente o gato colocar na linha de comando. 130 00:09:05,700 --> 00:09:11,040 Portanto, agora se eu fizer isso de novo, então ele vai redirecionar a saída em arquivo, 131 00:09:11,040 --> 00:09:13,930 e eu vou ter exatamente a mesma coisa. 132 00:09:13,930 --> 00:09:17,910 Então, tecnicamente, é completamente anulou o que tínhamos. 133 00:09:17,910 --> 00:09:22,970 E vamos ver se eu mudar dict, eu tirei cão. 134 00:09:22,970 --> 00:09:29,980 Agora, se nós gato dict em arquivo novamente, nós vamos ter a nova versão com o cão removido. 135 00:09:29,980 --> 00:09:32,400 Então é completamente substitui-lo. 136 00:09:32,400 --> 00:09:36,640 Em vez disso, se usarmos >>, que vai anexar o arquivo. 137 00:09:36,640 --> 00:09:40,860 Agora, abrir o arquivo, vemos que temos exatamente a mesma coisa duas vezes impressa 138 00:09:40,860 --> 00:09:44,920 porque ali uma vez, em seguida, adicionado ao original. 139 00:09:44,920 --> 00:09:48,130 Então é isso que> >> e fazer. 140 00:09:48,130 --> 00:09:50,580 Será que a próxima pergunta - Não perguntar sobre isso. 141 00:09:50,580 --> 00:09:59,050 >> O outro que temos é <, que se> redireciona saída padrão, 142 00:09:59,050 --> 00:10:01,970 00:10:12,050 Vamos ver se temos um exemplo. 144 00:10:14,750 --> 00:10:16,930 Eu posso escrever um rápido. 145 00:10:17,870 --> 00:10:25,700 Vamos dar qualquer arquivo, hello.c. 146 00:10:56,060 --> 00:10:59,070 Arquivo relativamente simples. 147 00:10:59,070 --> 00:11:03,570 Eu estou apenas começando uma seqüência e depois imprimir "Olá" qualquer que seja a seqüência de caracteres que acabara de entrar era. 148 00:11:03,570 --> 00:11:07,990 Então faça Olá e depois. / Olá. 149 00:11:07,990 --> 00:11:10,720 Agora ele está me levando para entrar alguma coisa, 150 00:11:10,720 --> 00:11:15,070 o que significa que está esperando as coisas a ser celebrado padrão dentro 151 00:11:15,070 --> 00:11:20,450 Então o que eu quiser entrar em padrão dentro Nós apenas estamos indo para dizer Olá, Rob! 152 00:11:20,450 --> 00:11:23,310 Então está imprimindo para saída padrão Olá, Rob! 153 00:11:23,310 --> 00:11:28,860 Se eu fizer. / Olá e depois redirecionar, 154 00:11:30,740 --> 00:11:34,310 por agora você só pode redirecionar a partir de um arquivo. 155 00:11:34,310 --> 00:11:41,720 Então, se eu colocar em algum arquivo, txt, e eu coloquei Rob, 156 00:11:41,720 --> 00:11:52,300 se eu executar Olá e então redirecionar o arquivo txt em. / Olá, ele vai dizer Olá, Rob! imediatamente. 157 00:11:52,300 --> 00:11:57,160 Quando se chega pela primeira vez GetString e está à espera de padrão em, 158 00:11:57,160 --> 00:12:01,730 padrão em não mais espera no teclado para que os dados se inseridos. 159 00:12:01,730 --> 00:12:05,980 Em vez disso, temos redirecionado padrão para ler o arquivo txt. 160 00:12:05,980 --> 00:12:10,290 E assim ele vai ler o txt, que é apenas o Rob linha, 161 00:12:10,290 --> 00:12:13,380 e, em seguida, ele vai imprimir Olá, Rob! 162 00:12:13,380 --> 00:12:18,180 E se eu quisesse, eu também poderia fazer. / Olá 00:12:21,500 e então o padrão que ele é impressão, o que é Olá, Rob!, 164 00:12:21,500 --> 00:12:24,700 Eu posso redirecionar que em seu próprio arquivo. 165 00:12:24,700 --> 00:12:29,790 Eu vou chamar o arquivo Olá - não, eu não vou, porque esse é o executável - txt2. 166 00:12:29,790 --> 00:12:40,150 Agora, txt2 vai ter a saída do. / Olá 00:12:43,520 >> Perguntas? 168 00:12:45,900 --> 00:12:49,090 >> Okay. Então aqui nós temos pipeline. 169 00:12:49,090 --> 00:12:53,510 Pipes são a última unidade de redirecionamento. 170 00:12:53,510 --> 00:12:58,750 >> Oh. Eu acho que mais uma unidade de redirecionamento é se em vez de> você faz 2>, 171 00:12:58,750 --> 00:13:01,070 que está redirecionando erro padrão. 172 00:13:01,070 --> 00:13:06,280 Então, se alguma coisa deu para o erro padrão, não teria se colocado em txt2. 173 00:13:06,280 --> 00:13:12,480 Mas repare se eu fizer 2>, então ele ainda está imprimindo Olá, Rob! para a linha de comando 174 00:13:12,480 --> 00:13:18,600 porque eu estou apenas redirecionando erro padrão, eu não estou redirecionando a saída padrão. 175 00:13:18,600 --> 00:13:22,210 Erro padrão e saída padrão são diferentes. 176 00:13:24,210 --> 00:13:27,080 Se você quisesse realmente escrever para o erro padrão, 177 00:13:27,080 --> 00:13:35,080 então eu poderia mudar isso para ser fprintf para stderr. 178 00:13:35,080 --> 00:13:37,850 Então printf, por padrão, imprime para a saída padrão. 179 00:13:37,850 --> 00:13:41,720 Se eu quiser imprimir para o erro padrão manualmente, então eu tenho que usar fprintf 180 00:13:41,720 --> 00:13:45,010 e especificar o que deseja imprimir. 181 00:13:45,010 --> 00:13:49,720 Se em vez fiz stdout fprintf, em seguida, que é basicamente equivalente a printf. 182 00:13:49,720 --> 00:13:55,530 Mas fprintf para o erro padrão. 183 00:13:57,790 --> 00:14:03,650 Então, agora, se eu redirecionar isso em txt2, Olá, Rob! ainda está sendo impressas na linha de comando 184 00:14:03,650 --> 00:14:08,270 uma vez que está sendo impressas para o erro padrão e eu só estou redirecionando a saída padrão. 185 00:14:08,270 --> 00:14:16,420 Se eu agora redirecionar o erro padrão, agora não se impresso, e txt2 vai ser Olá, Rob! 186 00:14:16,420 --> 00:14:21,910 Então, agora, você pode imprimir seus erros reais para o erro padrão 187 00:14:21,910 --> 00:14:24,720 e imprimir as suas mensagens regulares para a saída padrão. 188 00:14:24,720 --> 00:14:31,420 E assim, quando você executar o programa, você pode executá-lo como. / Olá, este tipo com o 2> 189 00:14:31,420 --> 00:14:33,800 para que o seu programa vai funcionar normalmente, 190 00:14:33,800 --> 00:14:38,400 mas as mensagens de erro que você começa você pode verificar mais tarde, em seu log de erro, 191 00:14:38,400 --> 00:14:44,500 assim os erros, e depois olhar mais tarde e seu arquivo de erros terá quaisquer erros que aconteceram. 192 00:14:45,200 --> 00:14:47,540 >> Perguntas? 193 00:14:47,540 --> 00:14:58,070 >> A última é a tubulação, que você pode pensar em como tirar a saída padrão de um comando 194 00:14:58,070 --> 00:15:01,210 e tornando-se o padrão do comando seguinte. 195 00:15:01,210 --> 00:15:05,570 Um exemplo aqui é o eco é uma coisa de linha de comando 196 00:15:05,570 --> 00:15:11,840 que é só ir para ecoar o que eu coloquei como seu argumento. Não vou colocar aspas. 197 00:15:11,840 --> 00:15:16,150 Eco blá, blá, blá é só ir para imprimir blá, blá, blá. 198 00:15:16,150 --> 00:15:20,600 Antes, quando eu disse que eu tinha que colocar Rob em um arquivo txt 199 00:15:20,600 --> 00:15:28,830 porque eu só posso redirecionar os arquivos txt, em vez disso, / se eu echo Rob 200 00:15:28,830 --> 00:15:35,520 e depois canalizá-lo em. / Olá, que também vai fazer o mesmo tipo de coisa. 201 00:15:35,520 --> 00:15:39,160 Isto está levando a saída deste comando, eco Rob, 202 00:15:39,160 --> 00:15:43,610 e usá-lo como entrada para. / Olá. 203 00:15:44,790 --> 00:15:49,560 Você pode pensar nisso como primeiro redirecionamento eco Rob em um arquivo 204 00:15:49,560 --> 00:15:54,160 e depois de entrada em. / Olá, esse arquivo que acabou de ser emitidas. 205 00:15:54,160 --> 00:15:57,850 Mas é preciso o arquivo temporário fora do quadro. 206 00:16:01,890 --> 00:16:04,460 >> Perguntas sobre isso? 207 00:16:04,460 --> 00:16:07,150 >> A próxima pergunta vai envolver isso. 208 00:16:07,150 --> 00:16:15,310 O gasoduto você poderia usar para encontrar o número de nomes exclusivos em um arquivo chamado names.txt? 209 00:16:15,310 --> 00:16:24,160 Os comandos que vamos querer usar aqui são únicos, por isso uniq, e wc. 210 00:16:24,160 --> 00:16:28,840 Você pode fazer uniq homem para realmente olhar para o que faz, 211 00:16:28,840 --> 00:16:34,840 e ele só vai para filtrar linhas correspondentes adjacentes a partir da entrada. 212 00:16:34,840 --> 00:16:40,690 E o homem wc vai imprimir a palavra, quebra de linha, e bytes para cada arquivo. 213 00:16:40,690 --> 00:16:43,760 E a última que vamos querer usar é tipo, 214 00:16:43,760 --> 00:16:47,410 que está indo apenas para classificar linhas de um arquivo txt. 215 00:16:47,410 --> 00:16:58,080 Se eu fizer algum arquivo txt, names.txt, e é Rob, Tommy, Joseph, Tommy, Joseph, RJ, Rob, 216 00:16:58,080 --> 00:17:03,910 o que eu quero fazer aqui é encontrar o número de nomes únicos neste arquivo. 217 00:17:03,910 --> 00:17:08,750 Então, o que deve ser a resposta? >> [Aluno] 4. Sim >>. 218 00:17:08,750 --> 00:17:13,780 Deve ser 4, pois Rob, Tommy, Joseph, RJ são os nomes originais só neste arquivo. 219 00:17:13,780 --> 00:17:20,180 O primeiro passo, se eu apenas fazer contagem de palavras na names.txt, 220 00:17:20,180 --> 00:17:24,290 isto é, na verdade, me contando tudo. 221 00:17:24,290 --> 00:17:32,560 Esta é realmente a impressão - Vamos ver, o homem wc - novas linhas, palavras e contagem de bytes. 222 00:17:32,560 --> 00:17:38,270 Se eu só me importo com as linhas, então eu posso apenas fazer wc-l names.txt. 223 00:17:41,730 --> 00:17:44,300 Então esse é um passo. 224 00:17:44,300 --> 00:17:50,510 Mas eu não quero wc-l names.txt porque names.txt apenas contém todos os nomes, 225 00:17:50,510 --> 00:17:54,170 e eu quero filtrar todas as não-originais. 226 00:17:54,170 --> 00:18:01,200 Então, se eu fizer names.txt uniq, que não chega a me dar o que eu quero 227 00:18:01,200 --> 00:18:03,760 porque os nomes duplicados ainda estão lá. 228 00:18:03,760 --> 00:18:07,690 Por que isso? Porque é que não uniq fazendo o que eu quero? 229 00:18:07,690 --> 00:18:10,500 [Aluno] O duplicatas não são [inaudível] >> Yeah. 230 00:18:10,500 --> 00:18:16,370 Lembre-se da página de manual para uniq diz filtrar linhas correspondentes adjacentes. 231 00:18:16,370 --> 00:18:19,680 Eles não são adjacentes, por isso não irá filtrá-los. 232 00:18:19,680 --> 00:18:31,100 Se eu classificá-los em primeiro lugar, names.txt tipo vai colocar todas as linhas duplicadas juntos. 233 00:18:31,100 --> 00:18:34,450 Então agora é que tipo names.txt. 234 00:18:34,450 --> 00:18:40,550 Eu vou querer usar isso como a entrada para uniq, que é | uniq. 235 00:18:40,550 --> 00:18:43,390 Isso dá-me José, RJ, Rob, Tommy, 236 00:18:43,390 --> 00:18:49,260 e eu quero usar isso como a entrada para o wc-l, 237 00:18:49,260 --> 00:18:52,740 que vai me dar 4. 238 00:18:52,740 --> 00:18:56,930 Como diz aqui, o gasoduto poderia usar? 239 00:18:56,930 --> 00:19:01,390 Você pode fazer um monte de coisas como usar uma série de comandos 240 00:19:01,390 --> 00:19:05,130 onde você usa a saída de um comando como entrada para o próximo comando. 241 00:19:05,130 --> 00:19:08,780 Você pode fazer um monte de coisas, um monte de coisas inteligentes. 242 00:19:08,780 --> 00:19:11,440 >> Perguntas? 243 00:19:12,910 --> 00:19:14,600 Okay. 244 00:19:14,600 --> 00:19:17,880 Isso é tudo para tubos e redirecionamento. 245 00:19:18,370 --> 00:19:24,090 >> Agora vamos para a coisa real, o material de codificação. 246 00:19:24,090 --> 00:19:29,100 Dentro deste PDF, você verá este comando, 247 00:19:29,100 --> 00:19:32,950 e você deseja executar este comando no seu aparelho. 248 00:19:36,240 --> 00:19:42,250 wget é o comando para apenas pegar alguma coisa da Internet, basicamente, 249 00:19:42,250 --> 00:19:45,180 assim wget e este URL. 250 00:19:45,180 --> 00:19:49,110 Se você foi para este URL no seu navegador, seria baixar o arquivo. 251 00:19:49,110 --> 00:19:52,510 Eu só clicar sobre ele, por isso o download do arquivo para mim. 252 00:19:52,510 --> 00:19:55,650 Mas escrever wget de que a coisa dentro do terminal 253 00:19:55,650 --> 00:19:58,620 é só ir para baixá-lo em seu terminal. 254 00:19:58,620 --> 00:20:02,750 Eu tenho section5.zip, e você deseja descompactar section5.zip, 255 00:20:02,750 --> 00:20:06,520 que vai dar-lhe uma pasta chamada section5, 256 00:20:06,520 --> 00:20:11,550 que vai ter todos os arquivos que vamos estar usando hoje dentro dele. 257 00:20:33,380 --> 00:20:37,710 Como os nomes destes programas de arquivo sugerir, eles são um pouco buggy, 258 00:20:37,710 --> 00:20:40,990 assim que sua missão é descobrir por que usar gdb. 259 00:20:40,990 --> 00:20:44,560 Será que todos eles têm baixado / saber como obtê-los baixado 260 00:20:44,560 --> 00:20:47,480 em seu aparelho? Okay. 261 00:20:47,480 --> 00:20:56,400 >> Correndo ./buggy1, ele vai dizer Falha de segmentação (núcleo), 262 00:20:56,400 --> 00:21:00,500 que a qualquer momento você começa um segfault, é uma coisa ruim. 263 00:21:00,500 --> 00:21:03,810 Sob que circunstâncias você começa um segfault? 264 00:21:03,810 --> 00:21:08,210 [Aluno] desreferenciação um ponteiro nulo. Sim >>. De modo que é um exemplo. 265 00:21:08,210 --> 00:21:11,580 Dereferencing um ponteiro nulo você está indo para obter um segfault. 266 00:21:11,580 --> 00:21:16,720 O que um segfault significa é que você está tocando memória que você não deve tocar. 267 00:21:16,720 --> 00:21:21,350 Então dereferencing um ponteiro nulo é tocar o endereço 0, 268 00:21:21,350 --> 00:21:28,060 e, basicamente, todos os computadores hoje em dia dizer que 0 endereço é a memória que você não deve tocar. 269 00:21:28,060 --> 00:21:31,920 É por isso que uma dereferencing resultados ponteiro nulo em um segfault. 270 00:21:31,920 --> 00:21:37,210 Quando acontecer de você não inicializar um ponteiro, então ele tem um valor de lixo, 271 00:21:37,210 --> 00:21:41,520 e assim, quando você tenta excluir a referência que, com toda a probabilidade que você está tocando memória 272 00:21:41,520 --> 00:21:43,540 que está no meio do nada. 273 00:21:43,540 --> 00:21:45,650 Se acontecer de você ter sorte e do valor de lixo 274 00:21:45,650 --> 00:21:48,440 aconteceu para apontar para algum lugar na pilha ou algo assim, 275 00:21:48,440 --> 00:21:50,820 então quando você dereference que o ponteiro que você não tenha inicializado, 276 00:21:50,820 --> 00:21:52,730 nada vai dar errado. 277 00:21:52,730 --> 00:21:55,480 Mas se ele está apontando para, digamos, em algum lugar entre a pilha eo heap, 278 00:21:55,480 --> 00:21:59,850 ou está apontando apenas para algum lugar que não tem sido utilizado pelo seu programa, no entanto, 279 00:21:59,850 --> 00:22:02,240 então você está tocando memória que você não deve estar tocando e você segfault. 280 00:22:02,240 --> 00:22:06,370 Quando você escrever uma função recursiva e recurses muitas vezes 281 00:22:06,370 --> 00:22:08,720 e sua pilha cresce muito grande e as colide pilha em coisas 282 00:22:08,720 --> 00:22:12,270 que não deve ser colidindo com, você está tocando memória que você não deve tocar, 283 00:22:12,270 --> 00:22:14,810 assim você segfault. 284 00:22:14,810 --> 00:22:17,010 Isso é que é segfault. 285 00:22:17,010 --> 00:22:21,810 >> É também a mesma razão que se você tiver uma seqüência como - 286 00:22:21,810 --> 00:22:23,930 vamos voltar ao programa anterior. 287 00:22:23,930 --> 00:22:28,530 Em hello.c-estou indo só para fazer outra coisa. 288 00:22:28,530 --> 00:22:33,770 char * s = "Olá mundo!"; 289 00:22:33,770 --> 00:22:42,310 Se eu usar * s = algo ou s [0] = 'X'; 290 00:22:42,310 --> 00:22:47,290 então faça Olá,. / Olá, por que isso segfault? 291 00:22:48,410 --> 00:22:51,250 Por que isso segfault? 292 00:22:55,660 --> 00:22:57,890 O que você espera que aconteça? 293 00:22:57,890 --> 00:23:06,640 Se eu fiz printf ("% s \ n", s), o que você espera para ser impresso? 294 00:23:06,640 --> 00:23:09,930 [Estudante] X Olá. Sim >>. 295 00:23:09,930 --> 00:23:15,140 O problema é que quando você declarar uma seqüência como esta, 296 00:23:15,140 --> 00:23:18,190 s é um ponteiro que está indo para ir para a pilha, 297 00:23:18,190 --> 00:23:25,880 e que s está a destacar é esta corda que está contido na memória só de leitura. 298 00:23:25,880 --> 00:23:30,560 Então, só pela memória o nome, só de leitura, você deve ter a idéia 299 00:23:30,560 --> 00:23:33,010 que se você tentar mudar o que está na memória só de leitura, 300 00:23:33,010 --> 00:23:36,670 você está fazendo algo que você não deveria estar fazendo com a memória e você segfault. 301 00:23:36,670 --> 00:23:45,360 Esta é realmente uma grande diferença entre char * s e s char []. 302 00:23:45,360 --> 00:23:48,790 Então char s [], agora esta cadeia vai ser colocado na pilha, 303 00:23:48,790 --> 00:23:53,960 ea pilha não é somente leitura, o que significa que este deve funcionar perfeitamente bem. 304 00:23:55,500 --> 00:23:57,370 E ele faz. 305 00:23:57,370 --> 00:24:06,250 Lembre-se que quando eu faço char * s = "Olá mundo!", S em si é na pilha 306 00:24:06,250 --> 00:24:10,390 s pontos, mas em outro lugar, em outro lugar e que passa a ser somente leitura. 307 00:24:10,390 --> 00:24:15,640 Mas char s [] é apenas algo sobre a pilha. 308 00:24:17,560 --> 00:24:21,760 Então, isso é um outro exemplo de um segfault acontecendo. 309 00:24:21,760 --> 00:24:27,820 >> Vimos que ./buggy1 resultou em um segfault. 310 00:24:27,820 --> 00:24:31,810 Em teoria, você não deve olhar para buggy1.c imediatamente. 311 00:24:31,810 --> 00:24:35,170 Em vez disso, nós vamos olhar para ele através gdb. 312 00:24:35,170 --> 00:24:37,750 Observe que quando você começa Falha de segmentação (núcleo), 313 00:24:37,750 --> 00:24:40,850 você tem este arquivo sobre o núcleo aqui chamado. 314 00:24:40,850 --> 00:24:45,200 Se ls-l, vamos ver que o núcleo geralmente é um arquivo muito grande. 315 00:24:45,200 --> 00:24:51,580 Este é o número de bytes do arquivo, por isso parece que é 250 e poucos kilobytes. 316 00:24:51,580 --> 00:24:56,120 A razão para isto é que o despejo do núcleo, na verdade, é 317 00:24:56,120 --> 00:25:01,410 é quando suas falhas do programa, o estado da memória de seu programa 318 00:25:01,410 --> 00:25:05,230 apenas é copiado e colado a este arquivo. 319 00:25:05,230 --> 00:25:07,270 Ele é despejada dentro do ficheiro. 320 00:25:07,270 --> 00:25:13,060 Este programa, enquanto ele estava correndo, passou a ter um uso de memória de cerca de 250 kilobytes, 321 00:25:13,060 --> 00:25:17,040 e é isso que tem despejado neste arquivo. 322 00:25:17,040 --> 00:25:23,630 Agora você pode olhar para o arquivo, se fizermos gdb núcleo buggy1. 323 00:25:23,630 --> 00:25:30,130 Podemos apenas fazer o gdb buggy1, e que só vai começar a se gdb regularmente, 324 00:25:30,130 --> 00:25:33,800 usando buggy1 como seu arquivo de entrada. 325 00:25:33,800 --> 00:25:38,260 Mas se você fizer gdb núcleo buggy1, então é especificamente indo para iniciar gdb 326 00:25:38,260 --> 00:25:40,330 olhando o arquivo do núcleo. 327 00:25:40,330 --> 00:25:45,560 E você dizendo buggy1 gdb meio sabe que o arquivo vem de núcleo do programa buggy1. 328 00:25:45,560 --> 00:25:49,580 Então gdb buggy1 núcleo vai trazer-nos imediatamente 329 00:25:49,580 --> 00:25:52,060 para onde o programa passou a terminar. 330 00:25:57,720 --> 00:26:02,340 Vemos aqui programa terminou com sinal de 11, falha de segmentação. 331 00:26:02,340 --> 00:26:10,110 Nós acontecer para ver uma linha de montagem, o que provavelmente não é muito útil. 332 00:26:10,110 --> 00:26:15,360 Mas se você digitar bt ou backtrace, que vai ser a função 333 00:26:15,360 --> 00:26:19,430 que nos dá a lista dos nossos quadros de pilha atuais. 334 00:26:19,430 --> 00:26:23,150 Então backtrace. Parece que só temos dois quadros de pilha. 335 00:26:23,150 --> 00:26:26,310 O primeiro é o nosso quadro de pilha principal, 336 00:26:26,310 --> 00:26:29,810 eo segundo é o quadro de pilha para esta função que acontecer para ser, 337 00:26:29,810 --> 00:26:34,440 que parece que só temos o código de montagem para. 338 00:26:34,440 --> 00:26:38,050 Então, vamos voltar para a nossa função principal, 339 00:26:38,050 --> 00:26:42,300 e para isso nós podemos fazer um quadro, e acho que também pode fazer-se, 340 00:26:42,300 --> 00:26:45,160 mas eu quase nunca para baixo - ou para cima. Sim. 341 00:26:45,160 --> 00:26:50,710 Cima e para baixo. Up leva até um quadro de pilha, para baixo leva a um quadro de pilha. 342 00:26:50,710 --> 00:26:53,240 Tenho tendência a nunca usar isso. 343 00:26:53,240 --> 00:26:59,120 Eu só dizer especificamente o quadro 1, que é voltar para o quadro com o 1. 344 00:26:59,120 --> 00:27:01,750 Quadro 1 vai trazer-nos em quadro de pilha principal, 345 00:27:01,750 --> 00:27:05,570 e ele diz que aqui a linha de código que estejamos menos. 346 00:27:05,570 --> 00:27:07,950 Se quiséssemos linhas mais um par de código, podemos dizer lista, 347 00:27:07,950 --> 00:27:11,280 e que vai nos dar todas as linhas de código ao seu redor. 348 00:27:11,280 --> 00:27:13,360 A linha que foi segfaulted em 6: 349 00:27:13,360 --> 00:27:17,360 if (strcmp ("CS50 rochas", argv [1]) == 0). 350 00:27:17,360 --> 00:27:24,130 Se não é óbvio ainda, você pode obtê-lo diretamente daqui apenas pensando por que segfaulted. 351 00:27:24,130 --> 00:27:28,800 Mas podemos dar um passo mais longe e dizer: "Por que argv [1] segfault?" 352 00:27:28,800 --> 00:27:38,830 Vamos impressão argv [1], e parece que ele é 0x0, que é o ponteiro nulo. 353 00:27:38,830 --> 00:27:44,750 Estamos strcmping CS50 rochas e nulos, e assim que vai segfault. 354 00:27:44,750 --> 00:27:48,280 E por que é argv [1] nulo? 355 00:27:48,640 --> 00:27:51,280 [Aluno] Porque nós não dar quaisquer argumentos de linha de comando. 356 00:27:51,280 --> 00:27:53,390 Sim. Nós não dar quaisquer argumentos de linha de comando. 357 00:27:53,390 --> 00:27:58,460 Então ./buggy1 só vai ter argv [0] ser ./buggy1. 358 00:27:58,460 --> 00:28:02,100 Não vai ter uma argv [1], de modo que vai segfault. 359 00:28:02,100 --> 00:28:07,450 Mas se, em vez disso, eu apenas CS50, ele vai dizer que você começa um D 360 00:28:07,450 --> 00:28:09,950 porque isso é o que é suposto fazer. 361 00:28:09,950 --> 00:28:15,240 Olhando buggy1.c, é suposto para imprimir "Você tem um D" - 362 00:28:15,240 --> 00:28:20,820 Se argv [1] não é "CS50 rochas", "Você tem um D", mais "você ganha um!" 363 00:28:20,820 --> 00:28:25,660 Portanto, se queremos um A, temos isso para comparar como verdadeira, 364 00:28:25,660 --> 00:28:28,710 o que significa que ele compara a 0. 365 00:28:28,710 --> 00:28:31,100 Então, argv [1] precisa ser "CS50 pedras". 366 00:28:31,100 --> 00:28:35,660 Se você quiser fazer isso na linha de comando, você precisa usar \ para escapar do espaço. 367 00:28:35,660 --> 00:28:41,690 Então CS50 \ rochas e você ganha um! 368 00:28:41,690 --> 00:28:44,060 Se você não fizer a barra invertida, porque isto não funciona? 369 00:28:44,060 --> 00:28:47,190 [Estudante] É dois argumentos diferentes. Sim >>. 370 00:28:47,190 --> 00:28:52,540 Argv [1] vai ser CS50, e argv [2] vai ser rochas. Okay. 371 00:28:52,540 --> 00:28:56,470 >> Agora ./buggy2 vai segfault novamente. 372 00:28:56,470 --> 00:29:01,880 Em vez de abri-lo com o seu arquivo de núcleo, vamos abrir buggy2 diretamente, 373 00:29:01,880 --> 00:29:05,000 assim gdb buggy2. 374 00:29:05,000 --> 00:29:09,590 Agora, se nós simplesmente executar o nosso programa, então ele vai dizer Programa recebeu sinal SIGSEGV, 375 00:29:09,590 --> 00:29:15,530 que é o segfault sinal, e este é o lugar onde aconteceu a acontecer. 376 00:29:15,530 --> 00:29:21,250 Olhando para o nosso backtrace, vemos que estávamos no oh_no função, 377 00:29:21,250 --> 00:29:23,900 que foi chamado pelo dinky função, que foi chamado pelo binky função, 378 00:29:23,900 --> 00:29:26,460 que foi chamado por principal. 379 00:29:26,460 --> 00:29:31,680 Nós também podemos ver os argumentos para estas funções. 380 00:29:31,680 --> 00:29:34,680 O argumento para dinky e binky foi 1. 381 00:29:34,680 --> 00:29:44,390 Se listar a função oh_no, vemos que oh_no está apenas fazendo char ** s = NULL; 382 00:29:44,390 --> 00:29:47,410 * S = "BOOM"; 383 00:29:47,410 --> 00:29:50,330 Por que isso não? 384 00:29:54,330 --> 00:29:58,380 [Aluno] Você não pode cancelar o ponteiro nulo? Sim >>. 385 00:29:58,380 --> 00:30:06,090 Este é apenas dizer s é NULL, independentemente se isso acontece de ser um char **, 386 00:30:06,090 --> 00:30:12,070 o que, dependendo da forma como o interpretar, que poderia ser um apontador para um apontador para uma cadeia 387 00:30:12,070 --> 00:30:15,550 ou uma matriz de strings. 388 00:30:15,550 --> 00:30:21,430 É s é NULL, então * s é dereferencing um ponteiro nulo, 389 00:30:21,430 --> 00:30:24,800 e assim é que isto vai funcionar. 390 00:30:24,800 --> 00:30:27,540 Esta é uma das formas mais rápidas que você pode possivelmente segfault. 391 00:30:27,540 --> 00:30:31,300 É só declarar um ponteiro nulo e imediatamente segmento padrão. 392 00:30:31,300 --> 00:30:34,570 Isso é o que está fazendo oh_no. 393 00:30:34,570 --> 00:30:43,400 Se formos até um quadro, então vamos entrar na função que chamou oh_no. 394 00:30:43,400 --> 00:30:44,830 Eu preciso fazer isso para baixo. 395 00:30:44,830 --> 00:30:48,610 Se você não digitar um comando e você apenas pressione Enter novamente, 396 00:30:48,610 --> 00:30:52,350 ele vai apenas repetir o comando anterior que você correu. 397 00:30:52,350 --> 00:30:56,610 Estamos no quadro 1. 398 00:30:56,610 --> 00:31:04,650 Listando este quadro, vemos aqui é a nossa função. 399 00:31:04,650 --> 00:31:08,520 Você pode bater lista novamente, ou você pode fazer lista de 20 e ele irá listar mais. 400 00:31:08,520 --> 00:31:13,640 O dinky função diz que se eu for 1, então vá para a função oh_no, 401 00:31:13,640 --> 00:31:15,960 senão vai para a função furtivo. 402 00:31:15,960 --> 00:31:18,700 E nós sabemos que é um i porque aconteceu de ver-se aqui 403 00:31:18,700 --> 00:31:22,560 dinky que foi chamado com o argumento 1. 404 00:31:22,560 --> 00:31:27,560 Ou você pode simplesmente não imprimir i e ele vai dizer que eu é 1. 405 00:31:27,560 --> 00:31:33,770 Estamos atualmente em dinky, e se subir um outro quadro, sabemos que vai acabar em binky. 406 00:31:33,770 --> 00:31:36,600 Up. Agora estamos em binky. 407 00:31:36,600 --> 00:31:41,340 Listando esta função - a lista de antes de meia me cortou - 408 00:31:41,340 --> 00:31:52,670 ele começou como se eu é 0, então vamos chamá-lo oh_no, senão chamar dinky. 409 00:31:52,670 --> 00:31:57,000 Nós sabemos que eu era um, por isso chamado dinky. 410 00:31:57,000 --> 00:32:05,030 E agora estamos de volta no principal, e principal só vai ser int i = rand ()% 3; 411 00:32:05,030 --> 00:32:08,790 Isso só vai lhe dar um número aleatório que é 0, 1 ou 2. 412 00:32:08,790 --> 00:32:12,780 Vai chamar binky com esse número, e ele irá retornar 0. 413 00:32:12,780 --> 00:32:16,700 Olhando para isso, 414 00:32:16,700 --> 00:32:19,880 apenas andando através do programa manualmente, sem executá-lo imediatamente, 415 00:32:19,880 --> 00:32:25,400 você deve definir um ponto de ruptura na principal, o que significa que, quando executar o programa 416 00:32:25,400 --> 00:32:31,020 seu programa é executado até que atinge um ponto de ruptura. 417 00:32:31,020 --> 00:32:35,450 Assim, a execução do programa, ele será executado e depois ele vai bater a função principal e parar de correr. 418 00:32:35,450 --> 00:32:44,700 Agora estamos dentro da principal, e passo ou a próxima vai trazer-nos para a próxima linha de código. 419 00:32:44,700 --> 00:32:47,050 Você pode fazer o passo ou o próximo. 420 00:32:47,050 --> 00:32:51,800 Bater seguinte, agora eu tenha sido definido para rand () de 3%, de modo que pode imprimir o valor de i, 421 00:32:51,800 --> 00:32:55,280 e ele vai dizer que eu é 1. 422 00:32:55,280 --> 00:32:58,110 Agora, não importa se usamos próximo ou passo. 423 00:32:58,110 --> 00:33:01,000 Eu acho que importava no anterior, mas gostaria de usar em seguida. 424 00:33:01,000 --> 00:33:06,000 Se usarmos passo, o passo para a função, o que significa olhar para a coisa real 425 00:33:06,000 --> 00:33:07,940 que está acontecendo dentro de binky. 426 00:33:07,940 --> 00:33:10,510 Se usarmos seguinte, então isso significa passar por cima da função 427 00:33:10,510 --> 00:33:14,070 e vá para a próxima linha de código na nossa função principal. 428 00:33:14,070 --> 00:33:17,900 Aqui nesta linha, eu estava em onde ele disse rand ()% 3; 429 00:33:17,900 --> 00:33:21,320 se eu passo, ele iria para a implementação de rand 430 00:33:21,320 --> 00:33:25,110 e olhar para o que está acontecendo lá, e eu poderia pisar através da função rand. 431 00:33:25,110 --> 00:33:26,920 Mas eu não me importo com a função rand. 432 00:33:26,920 --> 00:33:30,190 Eu só quero ir para a próxima linha de código na principal, então eu uso seguinte. 433 00:33:30,190 --> 00:33:35,800 Mas agora eu me importo com a função binky, assim que eu quero entrar nisso. 434 00:33:35,800 --> 00:33:37,730 Agora estou em binky. 435 00:33:37,730 --> 00:33:42,040 A primeira linha de código é que vai dizer se (i == 0), eu dou um passo, 436 00:33:42,040 --> 00:33:44,930 vemos que acabar em dinky. 437 00:33:44,930 --> 00:33:51,620 Se as coisas nós da lista, vemos que ela é marcada i = 0. 438 00:33:51,620 --> 00:33:55,470 i não é igual a 0, de modo que foi para a condição mais, 439 00:33:55,470 --> 00:33:59,540 que vai chamar dinky (i). 440 00:33:59,540 --> 00:34:04,030 Você pode ficar confuso. 441 00:34:04,030 --> 00:34:07,380 Se você só olhar para essas linhas diretamente, você pode pensar que se (i == 0), 442 00:34:07,380 --> 00:34:10,800 ok, então eu dei um passo e agora estou em dinky (i), 443 00:34:10,800 --> 00:34:14,120 você pode pensar que deve significar i = 0 ou algo assim. 444 00:34:14,120 --> 00:34:18,980 Não. Significa apenas que ele sabe que pode ficar diretamente ao dinky linha (i). 445 00:34:18,980 --> 00:34:23,300 Porque eu não for 0, o próximo passo não vai terminar no outro. 446 00:34:23,300 --> 00:34:26,239 Else não é uma linha que vai parar. 447 00:34:26,239 --> 00:34:31,570 É só passar para ir para a próxima linha pode realmente executar, o que é atraente (i). 448 00:34:31,570 --> 00:34:36,090 Entrando dinky (i), vamos ver se (i == 1). 449 00:34:36,090 --> 00:34:42,670 Sabemos i = 1, então quando passo, sabemos que vamos acabar em oh_no 450 00:34:42,670 --> 00:34:46,489 porque i = 1 chama o oh_no função, que você pode entrar, 451 00:34:46,489 --> 00:34:52,969 que vai definir char ** s = a NULL e imediatamente "BOOM". 452 00:34:54,270 --> 00:34:59,690 E então, na verdade, olhando para a implementação de buggy2, 453 00:34:59,690 --> 00:35:04,590 isso, eu apenas está obtendo um número aleatório - 0, 1, ou 2 - chamado binky, 454 00:35:04,590 --> 00:35:10,610 que se eu for 0 ela chama oh_no, senão ele chama dinky, que vem até aqui. 455 00:35:10,610 --> 00:35:18,100 Se eu for 1, chamada oh_no, senão chamar slinky, que chegando aqui, 456 00:35:18,100 --> 00:35:20,460 se i é 2, chame oh_no. 457 00:35:20,460 --> 00:35:24,720 Eu nem acho que há um caminho - 458 00:35:24,720 --> 00:35:30,030 Alguém vê uma maneira de fazer isso de um programa que não vai segfault? 459 00:35:30,030 --> 00:35:37,530 Porque a menos que eu estou faltando alguma coisa, se eu for 0, você imediatamente segfault, 460 00:35:37,530 --> 00:35:41,250 outra coisa que você ir a uma função que se i é um que você segfault, 461 00:35:41,250 --> 00:35:44,540 outra coisa que você ir para uma função onde se i é 2, você segfault. 462 00:35:44,540 --> 00:35:46,810 Portanto, não importa o que você faça, você segfault. 463 00:35:46,810 --> 00:35:52,380 >> Eu acho que uma maneira de corrigi-lo seria em vez de fazer char ** s = NULL, 464 00:35:52,380 --> 00:35:55,610 você poderia malloc espaço para essa cadeia. 465 00:35:55,610 --> 00:36:04,230 Nós poderíamos fazer malloc (sizeof) - sizeof o que? 466 00:36:09,910 --> 00:36:15,190 [Aluno] (char) * 5? >> Isto parece certo? 467 00:36:15,190 --> 00:36:21,060 Eu estou supondo que isso vai funcionar se eu realmente ele correu, mas não é o que eu estou procurando. 468 00:36:24,400 --> 00:36:32,940 Olhe para o tipo de s. Vamos adicionar * int, então int * x. 469 00:36:32,940 --> 00:36:35,600 Eu faria malloc (sizeof (int)). 470 00:36:35,600 --> 00:36:40,490 Ou se eu queria um conjunto de cinco, eu faria (sizeof (int) * 5); 471 00:36:40,490 --> 00:36:44,210 E se eu tiver um ** int? 472 00:36:46,260 --> 00:36:49,140 O que eu malloc? 473 00:36:49,140 --> 00:36:53,510 [Estudante] Tamanho do ponteiro. Sim >>. (Sizeof (int *)); 474 00:36:53,510 --> 00:36:56,960 A mesma coisa aqui. 475 00:36:56,960 --> 00:37:01,280 Eu quero (sizeof (char *)); 476 00:37:06,170 --> 00:37:12,840 Isso vai alocar espaço para o ponteiro que aponta para "BOOM". 477 00:37:12,840 --> 00:37:15,330 Eu não preciso alocar espaço para "BOOM" em si 478 00:37:15,330 --> 00:37:17,210 porque este é basicamente equivalente ao que eu disse antes 479 00:37:17,210 --> 00:37:20,870 de char * x = "BOOM". 480 00:37:20,870 --> 00:37:27,950 "BOOM" já existe. Acontece que existe na região de leitura de memória. 481 00:37:27,950 --> 00:37:35,200 Mas ele já existe, o que significa que esta linha de código, se s é um char **, 482 00:37:35,200 --> 00:37:43,900 então * s é um char * e você está definindo este char * para apontar para "BOOM". 483 00:37:43,900 --> 00:37:50,040 Se eu queria copiar "BOOM" em s, então eu teria que alocar espaço para s. 484 00:37:55,170 --> 00:38:03,900 Eu vou fazer * s = malloc (sizeof (char) * 5); 485 00:38:03,900 --> 00:38:06,210 Por 5? 486 00:38:06,210 --> 00:38:10,860 Por que não quatro? Parece que o "boom" é de 4 caracteres. >> [Aluno] O personagem nulo. 487 00:38:10,860 --> 00:38:14,580 Sim. Todas as cordas vão precisar o caractere nulo. 488 00:38:14,580 --> 00:38:23,590 Agora eu posso fazer algo como strcat - Qual é a função para copiar uma string? 489 00:38:23,590 --> 00:38:28,520 [Aluno] cpy? >> Strcpy. 490 00:38:28,520 --> 00:38:32,700 strcpy homem. 491 00:38:36,120 --> 00:38:39,590 Então strcpy ou strncpy. 492 00:38:39,590 --> 00:38:43,410 strncpy é um pouco mais seguro, pois você pode especificar exatamente quantos caracteres, 493 00:38:43,410 --> 00:38:46,190 mas aqui não importa, porque nós sabemos. 494 00:38:46,190 --> 00:38:50,340 Então strcpy e olhar nos argumentos. 495 00:38:50,340 --> 00:38:53,100 O primeiro argumento é o nosso destino. 496 00:38:53,100 --> 00:38:56,770 O segundo argumento é a nossa fonte. 497 00:38:56,770 --> 00:39:10,310 Vamos copiar para o nosso destino * é o ponteiro "BOOM". 498 00:39:10,310 --> 00:39:19,820 Por que você quer fazer isso com um strcpy em vez de apenas o que tínhamos antes 499 00:39:19,820 --> 00:39:22,800 de * s = "BOOM"? 500 00:39:22,800 --> 00:39:28,630 Há uma razão para que você pode querer fazer isso, mas o que é isso? 501 00:39:28,630 --> 00:39:31,940 [Estudante] Se você quer mudar algo em "BOOM". Sim >>. 502 00:39:31,940 --> 00:39:37,950 Agora eu posso fazer algo como s [0] = 'X'; 503 00:39:37,950 --> 00:39:48,190 porque os pontos s para a pilha e que o espaço na pilha que está apontando para s 504 00:39:48,190 --> 00:39:52,320 é um ponteiro para mais espaço na pilha, que está armazenando "BOOM". 505 00:39:52,320 --> 00:39:55,150 Portanto, este exemplar de "BOOM" está sendo armazenado na pilha. 506 00:39:55,150 --> 00:39:58,780 Há tecnicamente duas cópias do "boom" no nosso programa. 507 00:39:58,780 --> 00:40:03,500 Não é o primeiro que é apenas dada por esta constante string "BOOM", 508 00:40:03,500 --> 00:40:09,250 ea segunda cópia de "boom", strcpy criou a cópia de "BOOM". 509 00:40:09,250 --> 00:40:13,100 Mas a cópia de "BOOM" está sendo armazenado na pilha, eo heap você está livre para mudar. 510 00:40:13,100 --> 00:40:17,250 A pilha não é somente leitura, o que significa que s [0] 511 00:40:17,250 --> 00:40:20,500 vai deixar você alterar o valor de "BOOM". 512 00:40:20,500 --> 00:40:23,130 Vai deixá-lo mudar esses personagens. 513 00:40:23,130 --> 00:40:26,640 >> Perguntas? 514 00:40:27,740 --> 00:40:29,290 Okay. 515 00:40:29,290 --> 00:40:35,500 >> Passando para buggy3, gdb vamos buggy3. 516 00:40:35,500 --> 00:40:39,840 Nós apenas executá-lo e vemos temos um segfault. 517 00:40:39,840 --> 00:40:46,550 Se backtrace, existem apenas duas funções. 518 00:40:46,550 --> 00:40:52,970 Se subir em nossa função principal, vemos que segfaulted nesta linha. 519 00:40:52,970 --> 00:41:00,180 Então, só de olhar para esta linha, for (int linha = 0; fgets este material faz NULL não é igual; 520 00:41:00,180 --> 00:41:03,770 linha + +). 521 00:41:03,770 --> 00:41:08,010 Nosso quadro anterior foi chamado _IO_fgets. 522 00:41:08,010 --> 00:41:10,720 Você vai ver que um monte de funções built-in C, 523 00:41:10,720 --> 00:41:15,350 que quando você começa a segfault, haverá nomes de funções realmente enigmáticas 524 00:41:15,350 --> 00:41:18,090 como este _IO_fgets. 525 00:41:18,090 --> 00:41:21,770 Mas que vai se relacionar com esta chamada fgets. 526 00:41:21,770 --> 00:41:25,850 Em algum lugar aqui dentro, estamos segmento padrão. 527 00:41:25,850 --> 00:41:30,340 Se olharmos para os argumentos para fgets, podemos imprimir buffer. 528 00:41:30,340 --> 00:41:41,180 Vamos imprimir como um - Oh, não. 529 00:41:48,980 --> 00:41:51,900 Impressão não vai funcionar exatamente como eu quero que ele. 530 00:41:55,460 --> 00:41:58,000 Vamos olhar para o programa real. 531 00:42:02,200 --> 00:42:09,640 Buffer é uma matriz de caracteres. É uma matriz de caracteres de 128 caracteres. 532 00:42:09,640 --> 00:42:14,980 Portanto, quando digo buffer de impressão, que vai imprimir os 128 caracteres, 533 00:42:14,980 --> 00:42:18,300 Eu acho que é o que se espera. 534 00:42:18,300 --> 00:42:21,390 O que eu estava procurando é imprimir o endereço do buffer, 535 00:42:21,390 --> 00:42:23,680 mas que realmente não me diz muito. 536 00:42:23,680 --> 00:42:30,770 Então, quando acontecer de eu dizer aqui tampão x, ele me mostra 0xbffff090, 537 00:42:30,770 --> 00:42:38,690 que, se você se lembrar de mais cedo ou algum ponto, Oxbffff tende a ser uma região pilha-ish. 538 00:42:38,690 --> 00:42:46,020 A pilha tende a começar em algum lugar apenas sob 0xC000. 539 00:42:46,020 --> 00:42:51,890 Só de ver esse endereço, eu sei que o buffer está acontecendo na pilha. 540 00:42:51,890 --> 00:43:04,500 Reiniciando o meu programa, executado, para cima, o buffer que vimos foi essa seqüência de caracteres 541 00:43:04,500 --> 00:43:06,530 que são muito sentido. 542 00:43:06,530 --> 00:43:12,270 Em seguida, imprimir arquivos, o que arquivo se parece? 543 00:43:15,120 --> 00:43:17,310 [Aluno] nulo. Sim >>. 544 00:43:17,310 --> 00:43:22,610 Arquivo é um do tipo FILE *, por isso é um ponteiro, 545 00:43:22,610 --> 00:43:26,610 e o valor de ponteiro que é nula. 546 00:43:26,610 --> 00:43:33,240 Então fgets vai tentar ler de que o ponteiro de forma indireta, 547 00:43:33,240 --> 00:43:37,320 mas, para acessar esse ponteiro, tem que dereference-lo. 548 00:43:37,320 --> 00:43:40,550 Ou, para acessar o que ele deve estar apontando para, ele dereferences ele. 549 00:43:40,550 --> 00:43:43,810 Então é dereferencing um ponteiro nulo e ele segfaults. 550 00:43:46,600 --> 00:43:48,730 Eu poderia ter reiniciado lá. 551 00:43:48,730 --> 00:43:52,170 Se quebrar no nosso ponto principal e correr, 552 00:43:52,170 --> 00:43:57,320 a primeira linha de código é char * filename = "nonexistent.txt"; 553 00:43:57,320 --> 00:44:00,870 Isso deve dar uma dica muito grande a respeito de porque este programa falhar. 554 00:44:00,870 --> 00:44:06,080 Digitando próxima traz-me para a próxima linha, onde eu abrir este arquivo, 555 00:44:06,080 --> 00:44:11,140 e então eu imediatamente entrar em nossa linha, onde uma vez eu bati seguinte, que vai segfault. 556 00:44:11,140 --> 00:44:16,880 Alguém quer jogar fora uma razão pela qual pode ser segmento padrão? 557 00:44:16,880 --> 00:44:19,130 [Aluno] O arquivo não existe. Sim >>. 558 00:44:19,130 --> 00:44:22,250 Isto é suposto ser uma dica 559 00:44:22,250 --> 00:44:29,570 que sempre que você está abrindo um arquivo que você precisa para verificar se o arquivo realmente existe. 560 00:44:29,570 --> 00:44:31,510 Então, aqui, "nonexistent.txt"; 561 00:44:31,510 --> 00:44:34,700 Quando nome fopen para leitura, então nós precisamos dizer 562 00:44:34,700 --> 00:44:45,870 if (arquivo == NULL) e dizer printf ("O arquivo não existe!" 563 00:44:45,870 --> 00:44:56,340 ou - melhor ainda - filename); return 1; 564 00:44:56,340 --> 00:45:00,300 Então agora vamos verificar para ver se ele é NULL 565 00:45:00,300 --> 00:45:03,930 antes de realmente continuar e tentar ler a partir desse arquivo. 566 00:45:03,930 --> 00:45:08,800 Nós podemos refazê-lo só para ver o que funciona. 567 00:45:11,020 --> 00:45:14,970 Eu pretendia incluir uma nova linha. 568 00:45:21,090 --> 00:45:25,290 Então agora nonexistent.txt não existe. 569 00:45:26,890 --> 00:45:30,040 Você deve sempre verificar se há esse tipo de coisa. 570 00:45:30,040 --> 00:45:33,870 Você deve sempre verificar se fopen retorna NULL. 571 00:45:33,870 --> 00:45:38,170 Você deve sempre verificar para se certificar de que malloc não retorna NULL, 572 00:45:38,170 --> 00:45:41,410 ou então você segfault. 573 00:45:42,200 --> 00:45:45,930 >> Agora buggy4.c. 574 00:45:49,190 --> 00:45:58,440 Execução. Estou descobrindo isso está à espera para entrada ou looping possivelmente infinito. 575 00:45:58,440 --> 00:46:01,870 Sim, é looping infinito. 576 00:46:01,870 --> 00:46:05,560 Então buggy4. Parece que estamos em loop infinito. 577 00:46:05,560 --> 00:46:12,590 Podemos quebrar a principal, executar o nosso programa. 578 00:46:12,590 --> 00:46:20,180 Em gdb, enquanto a abreviatura usada é inequívoca 579 00:46:20,180 --> 00:46:23,420 ou abreviações especiais que eles fornecem para você, 580 00:46:23,420 --> 00:46:29,020 então você pode usar n usar seguinte em vez de ter que digitar lado todo o caminho. 581 00:46:29,020 --> 00:46:33,730 E agora que eu bati n uma vez, posso apenas pressione Enter para continuar próximo 582 00:46:33,730 --> 00:46:36,640 em vez de ter que bater n Enter, n Enter, n Enter. 583 00:46:36,640 --> 00:46:44,630 Parece que eu estou em algum tipo de loop que está assentado matriz [i] a 0. 584 00:46:44,630 --> 00:46:50,510 Parece que eu nunca estou sair deste loop. 585 00:46:50,510 --> 00:46:54,780 Se eu imprimir i, então eu é 2, então eu vou ir. 586 00:46:54,780 --> 00:46:59,250 Vou imprimir i, i é 3, então eu vou ir. 587 00:46:59,250 --> 00:47:05,360 Vou imprimir i e i é 3. Em seguida, imprimir i, i é 4. 588 00:47:05,360 --> 00:47:14,520 Na verdade, a impressão sizeof (array), assim o tamanho da matriz é 20. 589 00:47:16,310 --> 00:47:32,870 Mas parece que há algum comando gdb especial para ir até que algo acontece. 590 00:47:32,870 --> 00:47:37,620 É como definindo uma condição de o valor da variável. Mas eu não me lembro o que é. 591 00:47:37,620 --> 00:47:44,100 Então, se nós continuar - 592 00:47:44,100 --> 00:47:47,120 O que você estava dizendo? O que você traz? 593 00:47:47,120 --> 00:47:50,500 [Aluno] não exibir eu adicionar - >> Yeah. Então exibir eu posso ajudar. 594 00:47:50,500 --> 00:47:54,530 Se nós apenas mostrar i, ele vai colocar-se aqui que o valor de i é 595 00:47:54,530 --> 00:47:56,470 então eu não tenho que imprimi-lo cada vez. 596 00:47:56,470 --> 00:48:02,930 Se só vai manter próximo, vemos 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5. 597 00:48:02,930 --> 00:48:08,530 Alguma coisa está terrivelmente errado, e eu está sendo reposto a 0. 598 00:48:13,330 --> 00:48:22,220 Olhando buggy4.c, vemos tudo o que acontece é matriz int [5]; 599 00:48:22,220 --> 00:48:26,200 for (i = 0; i <= sizeof (array); i + +) 600 00:48:26,200 --> 00:48:28,550 array [i] = 0; 601 00:48:28,550 --> 00:48:31,390 O que vemos que está errado aqui? 602 00:48:31,390 --> 00:48:39,480 Como uma dica, quando eu estava fazendo o gdb buggy4 - vamos quebrar principal, run - 603 00:48:39,480 --> 00:48:45,980 Eu tinha impressão sizeof (array) só para ver o que a condição é onde eu deveria finalmente sair. 604 00:48:47,690 --> 00:48:51,100 Onde eu estou? Será que eu corro? 605 00:48:51,100 --> 00:48:54,280 Eu não declarou ainda. 606 00:48:54,280 --> 00:48:58,680 Assim imprimir sizeof (matriz) e que é 20, 607 00:48:58,680 --> 00:49:06,690 que é esperado desde a minha matriz é de tamanho 5 e é de 5 números inteiros, 608 00:49:06,690 --> 00:49:12,410 assim que a coisa toda deve ser de 5 * sizeof (int) bytes, onde sizeof (int) tende a ser 4. 609 00:49:12,410 --> 00:49:14,780 Então, sizeof (array) é 20. 610 00:49:14,780 --> 00:49:17,420 O que deve ser isso? 611 00:49:17,420 --> 00:49:21,720 [Aluno] Dividido por sizeof (int). >> Sim, / sizeof (int). 612 00:49:21,720 --> 00:49:30,630 Parece que ainda há um problema aqui. Eu acho que isso deve ser apenas < 613 00:49:30,630 --> 00:49:36,960 já que é praticamente sempre 00:49:44,860 Agora vamos pensar sobre por que isso foi realmente quebrado. 615 00:49:44,860 --> 00:49:53,370 Alguém tem palpites por que eu redefinir a 0 através de cada iteração do loop? 616 00:50:01,300 --> 00:50:09,350 A única coisa aqui dentro que está acontecendo é que a matriz [i] está sendo definida como 0. 617 00:50:09,350 --> 00:50:15,350 Então, de alguma forma, esta linha de código está causando a nossa int i a ser definido para 0. 618 00:50:16,730 --> 00:50:23,130 [Aluno] Poderia ser porque ele está substituindo a memória dessa parte do i 619 00:50:23,130 --> 00:50:27,970 quando se pensa que é o próximo elemento da matriz? >> [Bowden] Sim. 620 00:50:27,970 --> 00:50:33,880 Quando vamos para além do final de nossa matriz, 621 00:50:33,880 --> 00:50:39,870 espaço que de alguma forma que estamos substituindo está substituindo o valor de i. 622 00:50:39,870 --> 00:50:48,030 E assim, se olharmos para buggy4, quebrar corrida, principal, 623 00:50:48,030 --> 00:50:53,120 vamos imprimir o endereço de i. 624 00:50:53,120 --> 00:50:57,280 Parece que é bffff124. 625 00:50:57,280 --> 00:51:03,930 Agora vamos imprimir o endereço do array [0]. 110. 626 00:51:03,930 --> 00:51:06,290 E sobre [1]? 114. 627 00:51:06,290 --> 00:51:07,920 [2], 118. 628 00:51:07,920 --> 00:51:14,530 11c, 120. array [5] é bfff124. 629 00:51:14,530 --> 00:51:26,990 Então matriz [5] tem o mesmo endereço como eu, o que significa que a matriz [5] é i. 630 00:51:26,990 --> 00:51:30,720 Se eles têm o mesmo endereço, eles são a mesma coisa. 631 00:51:30,720 --> 00:51:38,410 Então, quando vamos definir matriz [5] a 0, estamos estabelecendo i a 0. 632 00:51:38,410 --> 00:51:46,070 E se você pensar sobre isso em termos de pilha, 633 00:51:46,070 --> 00:51:55,590 int i é declarada primeiro, o que significa que fica um pouco de espaço na pilha. 634 00:51:55,590 --> 00:52:04,730 Então matriz [5] é atribuído, de modo que 20 bytes são alocados na pilha. 635 00:52:04,730 --> 00:52:08,400 Então eu é alocada em primeiro lugar, em seguida, esses 20 bytes ficar alocado. 636 00:52:08,400 --> 00:52:11,400 Então eu acontece antes de a matriz, 637 00:52:11,400 --> 00:52:19,230 e por causa da forma, como eu disse na semana passada, quando tecnicamente a pilha cresce para baixo, 638 00:52:19,230 --> 00:52:28,520 quando o índice de você em uma matriz, temos a garantia de que a posição 0 na matriz 639 00:52:28,520 --> 00:52:31,970 sempre acontece antes da primeira posição na matriz. 640 00:52:31,970 --> 00:52:35,900 Este é o tipo de como eu desenhei na semana passada. 641 00:52:35,900 --> 00:52:42,210 Observe que no fundo temos o endereço 0 e no topo temos Max endereço. 642 00:52:42,210 --> 00:52:44,880 A pilha está sempre crescendo para baixo. 643 00:52:48,100 --> 00:52:53,500 Vamos dizer que alocar i. 644 00:52:53,500 --> 00:52:59,680 Alocamos inteiro i, o que significa que vamos apenas dizer que até aqui inteiro i é alocada. 645 00:52:59,680 --> 00:53:06,420 Em seguida, alocamos nosso array de 5 inteiros, o que significa que, por baixo que, 646 00:53:06,420 --> 00:53:11,230 Visto que a pilha está crescendo para baixo, esses cinco inteiros ficam alocados. 647 00:53:11,230 --> 00:53:15,900 Mas por causa de como matrizes funcionar, está garantido que a primeira posição na matriz 648 00:53:15,900 --> 00:53:22,260 sempre tem um endereço de menos do que o segundo aspecto da matriz. 649 00:53:22,260 --> 00:53:28,270 Assim posição 0 matriz sempre tem que acontecer primeiro na memória, 650 00:53:28,270 --> 00:53:30,700 Considerando que a posição matriz 1 tem que acontecer depois disso 651 00:53:30,700 --> 00:53:33,310 e posição da matriz 2 tem que acontecer depois disso, 652 00:53:33,310 --> 00:53:37,900 o que significa que a posição 0 matriz iria acontecer em algum lugar aqui, 653 00:53:37,900 --> 00:53:40,690 posição matriz 1 que aconteceria acima que 654 00:53:40,690 --> 00:53:45,530 porque mover-se significa endereços mais altos desde que o endereço máxima é aqui. 655 00:53:45,530 --> 00:53:50,490 Então array [0] aqui, array [1] até aqui, array [2] até aqui, matriz [3] até aqui. 656 00:53:50,490 --> 00:53:55,620 Observe como antes alocados inteiro i todo o caminho até aqui, 657 00:53:55,620 --> 00:54:01,040 à medida que avançamos mais e mais em nossa matriz, estamos chegando mais perto e mais perto de nosso inteiro i. 658 00:54:01,040 --> 00:54:07,640 O que acontece é que a matriz [5], que é uma posição além da nossa matriz, 659 00:54:07,640 --> 00:54:13,010 é exatamente onde inteiro i passou a ser alocado. 660 00:54:13,010 --> 00:54:16,920 Então esse é o ponto em que acontecerá a ser bater o espaço na pilha 661 00:54:16,920 --> 00:54:21,680 que foi alocada para o inteiro i, e estamos definindo que a 0. 662 00:54:21,680 --> 00:54:26,160 >> É assim que funciona. Perguntas? Sim. 663 00:54:26,160 --> 00:54:30,710 [Aluno] não importa. Okay. 664 00:54:30,710 --> 00:54:33,090 [Aluno] Como evitar este tipo de erros? 665 00:54:33,090 --> 00:54:41,190 Estes tipos de erros? Não use C como linguagem de programação. 666 00:54:41,190 --> 00:54:45,840 Use uma linguagem que tem limites de matriz de verificação. 667 00:54:45,840 --> 00:54:55,900 Enquanto você estiver atento, você só precisa evitar ir além dos limites de sua matriz. 668 00:54:55,900 --> 00:54:58,300 [Aluno] Então aqui quando fomos passado dos limites de sua matriz - 669 00:54:58,300 --> 00:55:01,840 [Bowden] É aí que as coisas começam a dar errado. >> [Aluno] Ah, ok. 670 00:55:01,840 --> 00:55:05,730 Enquanto você ficar dentro da memória alocada para a matriz, você está bem. 671 00:55:05,730 --> 00:55:12,400 Mas C não faz verificação de erros. Se eu fizer matriz [1000], é de bom grado apenas modificar o que acontece - 672 00:55:12,400 --> 00:55:16,500 Vai para o início da matriz, então ela vai posições 1000 e depois define como 0. 673 00:55:16,500 --> 00:55:20,000 Ele não faz nenhuma verificação de que ah, isso não tem realmente mil coisas nele. 674 00:55:20,000 --> 00:55:22,750 1000 é muito além do que eu deveria estar mudando, 675 00:55:22,750 --> 00:55:26,940 enquanto Java ou algo que você vai ter matriz de índice limites 676 00:55:26,940 --> 00:55:29,820 ou índice de exceção limites. 677 00:55:29,820 --> 00:55:33,950 É por isso que um monte de linguagens de alto nível tem essas coisas 678 00:55:33,950 --> 00:55:37,340 onde se você ir além dos limites da matriz, você não 679 00:55:37,340 --> 00:55:40,070 para que você não pode mudar as coisas de debaixo de você 680 00:55:40,070 --> 00:55:42,590 e depois as coisas vão muito pior do que apenas começando uma exceção 681 00:55:42,590 --> 00:55:44,940 dizendo que você foi além do fim da matriz. 682 00:55:44,940 --> 00:55:50,970 [Aluno] E assim teríamos apenas mudou o <= apenas > [Bowden] Yeah. 683 00:55:50,970 --> 00:55:54,800 Deve ser 00:55:59,560 desde sizeof (array) é de 20, mas só queremos 5. >> [Aluno] Direito. 685 00:55:59,560 --> 00:56:04,060 Mais perguntas? Okay. 686 00:56:04,060 --> 00:56:07,380 >> [Estudante] Eu tenho uma pergunta. Sim >>. 687 00:56:07,380 --> 00:56:16,440 [Aluno] Qual é a variável matriz real? 688 00:56:16,440 --> 00:56:20,000 [Bowden] Como o que é matriz? 689 00:56:20,000 --> 00:56:24,930 Array em si é um símbolo. 690 00:56:24,930 --> 00:56:31,490 É apenas o endereço do início dos 20 bytes que fazem referência. 691 00:56:31,490 --> 00:56:38,070 Você pode pensar nisso como um ponteiro, mas é um ponteiro constante. 692 00:56:38,070 --> 00:56:44,140 Assim que as coisas são compilados, a matriz variável não existe mais. 693 00:56:44,140 --> 00:56:48,210 [Aluno] Então como é que encontrar o tamanho da matriz? 694 00:56:48,210 --> 00:56:54,130 Tamanho da matriz refere-se ao tamanho do bloco, que se refere a esse símbolo. 695 00:56:54,130 --> 00:57:01,240 Quando eu faço algo como printf ("% p \ n", array); 696 00:57:01,240 --> 00:57:05,140 vamos executá-lo. 697 00:57:12,960 --> 00:57:15,530 O que eu acabei de errado? 698 00:57:15,530 --> 00:57:19,220 'Matriz' matriz declarada aqui. 699 00:57:20,820 --> 00:57:23,200 Ah, aqui em cima. 700 00:57:23,200 --> 00:57:31,250 Clang é inteligente, e isso acontece a perceber que eu declarei a matriz como 5 elementos 701 00:57:31,250 --> 00:57:34,540 mas eu estou a indexação na posição 1000. 702 00:57:34,540 --> 00:57:38,450 Ele pode fazer isso porque estes são apenas constantes. 703 00:57:38,450 --> 00:57:43,370 Ela só pode ir tão longe em perceber que eu estou indo além dos limites da matriz. 704 00:57:43,370 --> 00:57:46,880 Mas aviso antes, quando tivemos i ser incorreta, 705 00:57:46,880 --> 00:57:51,040 ela não pode determinar quantos valores eu poderia assumir, 706 00:57:51,040 --> 00:57:55,540 por isso não pode determinar que eu estava indo para além do fim da matriz. 707 00:57:55,540 --> 00:57:59,430 Isso é apenas Clang ser inteligente. 708 00:57:59,430 --> 00:58:03,340 >> Mas agora fazer buggy4. Então o que mais estou fazendo de errado? 709 00:58:03,340 --> 00:58:05,970 Implicitamente declarando função de biblioteca 'printf'. 710 00:58:05,970 --> 00:58:14,960 Eu vou querer # include. 711 00:58:14,960 --> 00:58:18,710 Okay. Agora correndo buggy4. 712 00:58:18,710 --> 00:58:24,840 Imprimir o valor da matriz, como eu fiz aqui, imprimi-lo como um ponteiro 713 00:58:24,840 --> 00:58:30,060 impressões algo que se parece com isso - bfb8805c - que é algum endereço 714 00:58:30,060 --> 00:58:33,450 que é na região pilha-ish. 715 00:58:33,450 --> 00:58:41,820 Matriz em si é como um ponteiro, mas não é um indicador real, 716 00:58:41,820 --> 00:58:45,410 uma vez que um ponteiro normal podemos mudar. 717 00:58:45,410 --> 00:58:54,700 Matriz é apenas uma constante. Os 20 blocos de memória começam em 0xbfb8805c endereço. 718 00:58:54,700 --> 00:59:09,020 Então bfb8805c através deste endereço +20- ou eu acho -20 - 719 00:59:09,020 --> 00:59:17,400 é toda a memória alocada para essa matriz. 720 00:59:17,400 --> 00:59:20,350 Matriz, a variável em si não é armazenada em qualquer lugar. 721 00:59:20,350 --> 00:59:27,660 Quando você está compilando, o compilador - aceno de mão para ele - 722 00:59:27,660 --> 00:59:33,060 mas o compilador só vai usar sabe onde arranjo a ser. 723 00:59:33,060 --> 00:59:36,090 Ele sabe onde começa essa matriz, 724 00:59:36,090 --> 00:59:40,910 e assim ele pode sempre fazer as coisas em termos de compensações de que começo. 725 00:59:40,910 --> 00:59:43,960 Ela não precisa de uma variável em si para representar matriz. 726 00:59:43,960 --> 00:59:53,730 Mas quando eu faço algo como int * p = array; agora p é um ponteiro que aponta para essa matriz, 727 00:59:53,730 --> 00:59:57,830 e agora p realmente existe na pilha. 728 00:59:57,830 --> 01:00:01,950 Eu sou livre para mudar p. Eu posso fazer p = malloc. 729 01:00:01,950 --> 01:00:06,500 Por isso, inicialmente apontou para matriz, agora aponta para algum espaço na pilha. 730 01:00:06,500 --> 01:00:09,620 Eu não posso fazer malloc = array. 731 01:00:09,620 --> 01:00:13,710 Se Clang é inteligente, ele vai gritar comigo logo de cara. 732 01:00:17,000 --> 01:00:21,430 Na verdade, eu tenho certeza que gcc faria isso também. 733 01:00:21,430 --> 01:00:25,010 Assim, o tipo de matriz 'int [5]' não é transferível. 734 01:00:25,010 --> 01:00:28,040 Você não pode atribuir algo a um tipo de matriz 735 01:00:28,040 --> 01:00:30,500 porque matriz é apenas uma constante. 736 01:00:30,500 --> 01:00:34,760 É um símbolo que faz referência a esses 20 bytes. Eu não posso mudar isso. 737 01:00:34,760 --> 01:00:37,690 >> [Aluno] E onde está o tamanho da matriz armazenada? 738 01:00:37,690 --> 01:00:40,670 [Bowden] Não é armazenada em qualquer lugar. É quando ele está compilando. 739 01:00:40,670 --> 01:00:46,310 Então, onde está o tamanho da matriz armazenada? 740 01:00:46,310 --> 01:00:51,870 Você só pode usar sizeof (matriz) dentro da função que a matriz é declarada em si. 741 01:00:51,870 --> 01:01:03,150 Então, se eu fizer alguma função, foo, e eu faço (int array []) 742 01:01:03,150 --> 01:01:10,450 printf ("% d \ n", sizeof (array)); 743 01:01:10,450 --> 01:01:21,330 e aqui eu chamo de foo (matriz); 744 01:01:21,330 --> 01:01:24,840 dentro desta função - vamos executá-lo. 745 01:01:34,200 --> 01:01:36,840 Este é Clang ser inteligente novamente. 746 01:01:36,840 --> 01:01:43,890 Ele está me dizendo que sizeof no parâmetro função de matriz 747 01:01:43,890 --> 01:01:46,690 retornará tamanho de 'int *'. 748 01:01:46,690 --> 01:01:55,150 Isso seria um erro, se não é o que eu queria que acontecesse. 749 01:01:55,150 --> 01:01:58,960 Vamos realmente desligar Werror. 750 01:02:14,950 --> 01:02:17,590 Aviso. Avisos estão bem. 751 01:02:17,590 --> 01:02:19,960 É ainda compilará contanto que tem um aviso. 752 01:02:19,960 --> 01:02:22,910 . / A.out vai imprimir 4. 753 01:02:22,910 --> 01:02:28,650 O aviso que foi gerado é um indicador claro de que deu errado. 754 01:02:28,650 --> 01:02:34,120 Esta matriz int só vai imprimir sizeof (int *). 755 01:02:34,120 --> 01:02:39,790 Mesmo se eu colocar array [5] aqui, ele ainda está indo só para imprimir sizeof (int *). 756 01:02:39,790 --> 01:02:47,440 Assim, logo que você passar para uma função, a distinção entre matrizes e ponteiros 757 01:02:47,440 --> 01:02:49,670 é inexistente. 758 01:02:49,670 --> 01:02:52,640 Isto acontece por ser uma matriz que foi declarado na pilha, 759 01:02:52,640 --> 01:02:58,300 mas assim que passar esse valor, que 0xbf blá, blá, blá para esta função, 760 01:02:58,300 --> 01:03:03,350 então este ponteiro aponta para que a matriz na pilha. 761 01:03:03,350 --> 01:03:08,310 Então isso significa que sizeof só se aplica em função de que a matriz foi declarada, 762 01:03:08,310 --> 01:03:11,230 o que significa que quando você está compilando esta função, 763 01:03:11,230 --> 01:03:17,330 Clang quando passa por esta função, ele vê matriz é um array de int de tamanho 5. 764 01:03:17,330 --> 01:03:20,640 Então ele vê sizeof (array). Bem, isso é 20. 765 01:03:20,640 --> 01:03:26,440 Isso é realmente como sizeof funciona basicamente para quase todos os casos. 766 01:03:26,440 --> 01:03:31,150 Sizeof não é uma função, é um operador. 767 01:03:31,150 --> 01:03:33,570 Você não chama a função sizeof. 768 01:03:33,570 --> 01:03:38,280 Sizeof (int), o compilador só vai traduzir isso para 4. 769 01:03:41,480 --> 01:03:43,700 Entendeu? Okay. 770 01:03:43,700 --> 01:03:47,520 >> [Aluno] Então, qual é a diferença entre sizeof (array) no principal e em foo? 771 01:03:47,520 --> 01:03:52,840 Isso é porque nós estamos dizendo sizeof (array), que é do tipo int *, 772 01:03:52,840 --> 01:03:57,120 enquanto que a matriz aqui em baixo não é do tipo int *, é uma matriz int. 773 01:03:57,120 --> 01:04:04,540 >> [Aluno] Então se você tivesse o parâmetro na matriz [] em vez de matriz int *, 774 01:04:04,540 --> 01:04:09,230 que isso significa que você ainda pode mudar matriz porque agora é um ponteiro? 775 01:04:09,230 --> 01:04:14,250 [Bowden] Gostou? >> [Estudante] Yeah. Você pode mudar matriz dentro da função agora? 776 01:04:14,250 --> 01:04:18,420 [Bowden] Você poderia mudar matriz em ambos os casos. 777 01:04:18,420 --> 01:04:23,130 Em ambos os casos, você é livre para dizer array [4] = 0. 778 01:04:23,130 --> 01:04:26,590 [Aluno] Mas você pode fazer ponto de matriz para algo mais? 779 01:04:26,590 --> 01:04:30,230 [Bowden] Oh. Sim. Em ambos os casos - >> [estudante] Yeah. 780 01:04:30,230 --> 01:04:38,410 [Bowden] A distinção entre array [] e uma matriz int *, não há nenhuma. 781 01:04:38,410 --> 01:04:42,570 Você também pode obter alguns matriz multidimensional aqui 782 01:04:42,570 --> 01:04:47,050 por alguma sintaxe conveniente, mas ainda é apenas um ponteiro. 783 01:04:47,050 --> 01:04:56,400 Isso significa que eu sou livre para fazer o array = malloc (sizeof (int)), e agora apontam para outro lugar. 784 01:04:56,400 --> 01:04:59,610 Mas, assim como a forma como isso funciona sempre e sempre, 785 01:04:59,610 --> 01:05:03,210 mudar essa matriz, tornando-a apontar para algo mais 786 01:05:03,210 --> 01:05:07,570 não mudar essa matriz aqui porque é uma cópia do argumento, 787 01:05:07,570 --> 01:05:10,780 não é um ponteiro para esse argumento. 788 01:05:10,780 --> 01:05:16,070 E, na verdade, apenas como mais uma indicação de que é exatamente o mesmo - 789 01:05:16,070 --> 01:05:21,100 já vimos o que imprime matriz de impressão - 790 01:05:21,100 --> 01:05:31,410 o que se imprime o endereço da matriz ou o endereço do endereço da matriz 791 01:05:31,410 --> 01:05:36,290 a um desses? 792 01:05:41,770 --> 01:05:45,220 Vamos ignorar este. 793 01:05:48,140 --> 01:05:51,660 Okay. Isso é bom. É agora em execução. A.out /. 794 01:05:51,660 --> 01:06:00,220 Matriz de impressão, depois de imprimir o endereço da matriz, são a mesma coisa. 795 01:06:00,220 --> 01:06:02,870 Matriz simplesmente não existe. 796 01:06:02,870 --> 01:06:08,190 Sabe quando você está imprimindo matriz, você está imprimindo o símbolo que se refere a esses 20 bytes. 797 01:06:08,190 --> 01:06:11,940 Imprimir o endereço da matriz, bem, matriz não existe. 798 01:06:11,940 --> 01:06:17,200 Ele não tem um endereço, por isso só imprime o endereço desses 20 bytes. 799 01:06:20,820 --> 01:06:28,150 Assim que você compilar para baixo, como em seu buggy4 compilado. / A.out, 800 01:06:28,150 --> 01:06:30,340 matriz é inexistente. 801 01:06:30,340 --> 01:06:33,640 Ponteiros existe. Matrizes não. 802 01:06:34,300 --> 01:06:38,060 Os blocos de memória que representam a matriz ainda existem, 803 01:06:38,060 --> 01:06:43,270 mas a matriz variável e as variáveis ​​deste tipo não existem. 804 01:06:46,260 --> 01:06:50,270 Aqueles são como as principais diferenças entre matrizes e ponteiros 805 01:06:50,270 --> 01:06:55,590 são assim que fazem chamadas de funções, não há diferença. 806 01:06:55,590 --> 01:07:00,460 Mas dentro da função que a própria matriz é declarada, sizeof funciona de forma diferente 807 01:07:00,460 --> 01:07:05,190 desde que a impressão é o tamanho dos blocos, em vez de o tamanho do tipo, 808 01:07:05,190 --> 01:07:08,950 e você não pode mudar isso, porque é um símbolo. 809 01:07:08,950 --> 01:07:14,370 Impressão da coisa eo endereço da coisa imprime a mesma coisa. 810 01:07:14,370 --> 01:07:18,480 E isso é muito bonito isso. 811 01:07:18,480 --> 01:07:20,820 [Aluno] Poderia dizer que mais uma vez? 812 01:07:21,170 --> 01:07:24,170 Eu poderia ter perdido alguma coisa. 813 01:07:24,170 --> 01:07:29,260 Matriz de impressão e endereço da matriz imprime a mesma coisa, 814 01:07:29,260 --> 01:07:33,180 enquanto que se você imprimir um ponteiro em relação ao endereço do ponteiro, 815 01:07:33,180 --> 01:07:36,010 a única coisa que imprime o endereço do que você está apontando, 816 01:07:36,010 --> 01:07:40,360 o outro imprime o endereço do ponteiro para a pilha. 817 01:07:40,360 --> 01:07:47,040 Você pode alterar um ponteiro, você não pode alterar um símbolo da matriz. 818 01:07:47,740 --> 01:07:53,270 E ponteiro sizeof vai imprimir o tamanho desse tipo de ponteiro. 819 01:07:53,270 --> 01:07:57,470 Então, int * p sizeof (p) vai imprimir 4, 820 01:07:57,470 --> 01:08:04,110 mas int array [5] print sizeof (array) vai imprimir 20. 821 01:08:04,110 --> 01:08:07,480 [Estudante] Então int array [5] irá imprimir 20? Sim >>. 822 01:08:07,480 --> 01:08:13,300 É por isso que dentro de buggy4 quando costumava ser sizeof (array) 823 01:08:13,300 --> 01:08:16,660 este estava fazendo i <20, que não é o que queria. 824 01:08:16,660 --> 01:08:20,880 Queremos i <5. >> [Aluno] Okay. 825 01:08:20,880 --> 01:08:25,569 [Bowden] E então, logo que você começar a passar nas funções, 826 01:08:25,569 --> 01:08:34,340 se fizemos int * p = array; 827 01:08:34,340 --> 01:08:39,779 dentro desta função, podemos basicamente usar p e matriz em exatamente da mesma maneira, 828 01:08:39,779 --> 01:08:43,710 excepto para o problema e sizeof o problema alterando. 829 01:08:43,710 --> 01:08:49,810 Mas p [0] = 1; é o mesmo que dizer array [0] = 1; 830 01:08:49,810 --> 01:08:55,600 E assim como dizemos foo (matriz), ou foo (p); 831 01:08:55,600 --> 01:08:59,760 dentro da função foo, esta é a mesma chamada duas vezes. 832 01:08:59,760 --> 01:09:03,350 Não existe qualquer diferença entre estas duas chamadas. 833 01:09:07,029 --> 01:09:11,080 >> Todos boa sobre isso? Okay. 834 01:09:14,620 --> 01:09:17,950 Temos 10 minutos. 835 01:09:17,950 --> 01:09:28,319 >> Vamos tentar obter através deste programa Typer Hacker, 836 01:09:28,319 --> 01:09:32,350 Neste site, que saiu no ano passado ou algo assim. 837 01:09:34,149 --> 01:09:41,100 É só deveria ser como você digita aleatoriamente e imprime - 838 01:09:41,100 --> 01:09:46,729 Qualquer arquivo que acontece de ter carregado é o que parece que você está digitando. 839 01:09:46,729 --> 01:09:52,069 Parece que algum tipo de código do sistema operacional. 840 01:09:53,760 --> 01:09:56,890 Isso é o que queremos implementar. 841 01:10:08,560 --> 01:10:11,690 Você deve ter um binário executável chamado hacker_typer 842 01:10:11,690 --> 01:10:14,350 que leva em um único argumento, o arquivo para "tipo de hacker." 843 01:10:14,350 --> 01:10:16,480 Executando o executável deve limpar a tela 844 01:10:16,480 --> 01:10:20,850 e depois imprimir um personagem do arquivo passado em cada vez que o usuário pressiona uma tecla. 845 01:10:20,850 --> 01:10:24,990 Então, qualquer tecla pressionada, ele deve jogar fora e em vez imprimir um personagem a partir do arquivo 846 01:10:24,990 --> 01:10:27,810 que é o argumento. 847 01:10:29,880 --> 01:10:34,350 Eu vou muito bem dizer o que as coisas que vamos precisar saber são. 848 01:10:34,350 --> 01:10:36,440 Mas queremos verificar a biblioteca termios. 849 01:10:36,440 --> 01:10:44,840 Eu nunca usei esta biblioteca em toda minha vida, por isso tem propósitos muito mínimas. 850 01:10:44,840 --> 01:10:48,610 Mas isso vai ser a biblioteca que podemos usar para jogar fora o personagem que você bateu 851 01:10:48,610 --> 01:10:52,390 quando você está digitando em padrão dentro 852 01:10:56,970 --> 01:11:05,840 Então hacker_typer.c, e vamos querer # include. 853 01:11:05,840 --> 01:11:12,870 Olhando para a página man para termios - estou supondo que é terminal de OS ou alguma coisa - 854 01:11:12,870 --> 01:11:16,240 Eu não sei como lê-lo. 855 01:11:16,240 --> 01:11:21,040 Olhando para isso, ele diz para incluir esses dois arquivos, então vamos fazer isso. 856 01:11:37,620 --> 01:11:46,820 >> Primeiro de tudo, nós queremos ter em um único argumento, que é o arquivo que deve abrir. 857 01:11:46,820 --> 01:11:52,420 Então, o que eu quero fazer? Como posso verificar para ver que eu tenho um único argumento? 858 01:11:52,420 --> 01:11:56,480 [Estudante] Se argc é igual a ele. >> [Bowden] Yeah. 859 01:11:56,480 --> 01:12:21,250 Então, se (argc = 2!) Printf ("Uso:% s [arquivo para abrir]"). 860 01:12:21,250 --> 01:12:32,750 Portanto, agora se eu executar este sem fornecer um segundo argumento - oh, eu preciso da nova linha - 861 01:12:32,750 --> 01:12:36,240 você verá que ele diz de uso:. / hacker_typer, 862 01:12:36,240 --> 01:12:39,770 e, em seguida, o segundo argumento deverá ser o arquivo que eu quero abrir. 863 01:12:58,430 --> 01:13:01,260 Agora, o que eu faço? 864 01:13:01,260 --> 01:13:08,490 Eu quero ler a partir deste arquivo. Como faço para ler um arquivo? 865 01:13:08,490 --> 01:13:11,920 [Aluno] Você abri-lo primeiro. Sim >>. 866 01:13:11,920 --> 01:13:15,010 Então fopen. O que fopen parece? 867 01:13:15,010 --> 01:13:22,980 [Aluno] Filename. >> [Bowden] Espectacular vai ser argv [1]. 868 01:13:22,980 --> 01:13:26,110 [Aluno] E então o que você quer fazer com ela, então a - >> [Bowden] Yeah. 869 01:13:26,110 --> 01:13:28,740 Então, se você não se lembra, você só poderia fazer fopen homem, 870 01:13:28,740 --> 01:13:32,960 onde ele vai ser um caminho const char *, onde caminho é nome de arquivo, 871 01:13:32,960 --> 01:13:34,970 modo de const char *. 872 01:13:34,970 --> 01:13:38,660 Se acontecer de você não se lembrar do que modo for, então você pode olhar para o modo. 873 01:13:38,660 --> 01:13:44,660 Dentro de páginas de manual, o caractere de barra é o que você pode usar para pesquisar as coisas. 874 01:13:44,660 --> 01:13:49,790 Então eu digitar / modo para procurar modo. 875 01:13:49,790 --> 01:13:57,130 n e N são o que você pode usar para percorrer os jogos de busca. 876 01:13:57,130 --> 01:13:59,800 Aqui diz que os pontos de modo argumento para uma string 877 01:13:59,800 --> 01:14:01,930 começando com uma das seguintes sequências. 878 01:14:01,930 --> 01:14:06,480 Então r, arquivo de texto aberto para leitura. Isso é o que nós queremos fazer. 879 01:14:08,930 --> 01:14:13,210 Para ler, e eu quero guardar isso. 880 01:14:13,210 --> 01:14:18,720 A coisa vai ser um arquivo *. Agora o que eu quero fazer? 881 01:14:18,720 --> 01:14:21,200 Dê-me um segundo. 882 01:14:28,140 --> 01:14:30,430 Okay. Agora o que eu quero fazer? 883 01:14:30,430 --> 01:14:32,940 [Aluno] Verificar se é NULL. >> [Bowden] Yeah. 884 01:14:32,940 --> 01:14:38,690 Toda vez que você abrir um arquivo, certifique-se que você é sucesso capaz de abri-lo. 885 01:14:58,930 --> 01:15:10,460 >> Agora eu quero fazer essas coisas termios onde eu quero primeiro ler minhas configurações atuais 886 01:15:10,460 --> 01:15:14,050 e salvar aqueles em alguma coisa, então eu quero mudar a minha configuração 887 01:15:14,050 --> 01:15:19,420 jogar fora qualquer personagem que eu escreva, 888 01:15:19,420 --> 01:15:22,520 e então eu quero atualizar essas configurações. 889 01:15:22,520 --> 01:15:27,250 E depois, no final do programa, eu quero mudar de volta para as minhas definições originais. 890 01:15:27,250 --> 01:15:32,080 Assim, a estrutura vai ser de termios tipo, e eu vou querer dois deles. 891 01:15:32,080 --> 01:15:35,600 O primeiro vai ser o meu current_settings, 892 01:15:35,600 --> 01:15:42,010 e então eles vão ser meus hacker_settings. 893 01:15:42,010 --> 01:15:48,070 Primeiro, eu vou querer para salvar minhas configurações atuais, 894 01:15:48,070 --> 01:15:53,790 então eu vou querer atualizar hacker_settings, 895 01:15:53,790 --> 01:16:01,570 e forma, no final do meu programa, eu quero reverter para as configurações atuais. 896 01:16:01,570 --> 01:16:08,660 Então salvar as configurações atuais, da maneira que funciona, nós termios homem. 897 01:16:08,660 --> 01:16:15,810 Vemos que temos esse tcsetattr int, int tcgetattr. 898 01:16:15,810 --> 01:16:22,960 Eu passar em um struct termios pelo seu ponteiro. 899 01:16:22,960 --> 01:16:30,640 A forma como isso vai olhar é - eu já esqueceu o que a função foi chamada. 900 01:16:30,640 --> 01:16:34,930 Copie e cole-o. 901 01:16:39,150 --> 01:16:45,500 Então tcgetattr, então eu quero passar na estrutura que eu estou salvando as informações em, 902 01:16:45,500 --> 01:16:49,650 que vai ser current_settings, 903 01:16:49,650 --> 01:16:59,120 eo primeiro argumento é o descritor de arquivo para a coisa que eu quero salvar os atributos de. 904 01:16:59,120 --> 01:17:04,360 O que o descritor de arquivo é é como qualquer vez que você abrir um arquivo, ele recebe um descritor de arquivo. 905 01:17:04,360 --> 01:17:14,560 Quando eu fopen argv [1], torna-se um descritor de arquivo que você está fazendo referência 906 01:17:14,560 --> 01:17:16,730 sempre que você deseja ler ou escrever para ele. 907 01:17:16,730 --> 01:17:19,220 Esse não é o descritor de arquivo que eu quero usar aqui. 908 01:17:19,220 --> 01:17:21,940 Há três descritores de arquivos que você tem por padrão, 909 01:17:21,940 --> 01:17:24,310 que são padrão, saída padrão e erro padrão. 910 01:17:24,310 --> 01:17:29,960 Por padrão, eu acho que é padrão em é 0, fora padrão é 1, e do erro padrão é 2. 911 01:17:29,960 --> 01:17:33,980 Então, o que eu quero mudar as configurações do? 912 01:17:33,980 --> 01:17:37,370 Eu quero mudar as configurações de sempre que eu bati um personagem, 913 01:17:37,370 --> 01:17:41,590 Eu quero que ele jogue o personagem fora em vez de imprimi-lo na tela. 914 01:17:41,590 --> 01:17:45,960 O fluxo - padrão, saída padrão ou erro padrão - 915 01:17:45,960 --> 01:17:52,050 responde às coisas quando eu digitar no teclado? >> [Estudante] Standard dentro >> Yeah. 916 01:17:52,050 --> 01:17:56,450 Então eu pode fazer 0 ou stdin que eu possa fazer. 917 01:17:56,450 --> 01:17:59,380 Estou recebendo o current_settings de padrão dentro 918 01:17:59,380 --> 01:18:01,720 >> Agora eu quero atualizar essas configurações, 919 01:18:01,720 --> 01:18:07,200 Então, primeiro eu vou copiar em hacker_settings que meus current_settings são. 920 01:18:07,200 --> 01:18:10,430 E como o trabalho de estruturas é que vai apenas copiar. 921 01:18:10,430 --> 01:18:14,510 Isso copia todos os campos, como seria de esperar. 922 01:18:14,510 --> 01:18:17,410 >> Agora eu quero atualizar alguns dos campos. 923 01:18:17,410 --> 01:18:21,670 Olhando termios, você tem que ler um monte de presente 924 01:18:21,670 --> 01:18:24,110 só para ver o que você gostaria de procurar, 925 01:18:24,110 --> 01:18:28,210 mas as bandeiras que você vai querer olhar para são eco, 926 01:18:28,210 --> 01:18:33,110 ECHO para caracteres de entrada de eco. 927 01:18:33,110 --> 01:18:37,710 Primeiro quero definir - eu já esqueceu o que os campos são. 928 01:18:45,040 --> 01:18:47,900 Isto é o que a estrutura parece. 929 01:18:47,900 --> 01:18:51,060 Assim, os modos de entrada eu penso que nós queremos mudar. 930 01:18:51,060 --> 01:18:54,210 Nós vamos olhar para a solução para se certificar de que é o que nós queremos mudar. 931 01:19:04,060 --> 01:19:12,610 Queremos mudar lflag, a fim de evitar a necessidade de olhar através de todos estes. 932 01:19:12,610 --> 01:19:14,670 Queremos mudar os modos locais. 933 01:19:14,670 --> 01:19:17,710 Você teria que ler essa coisa toda para entender onde tudo pertence 934 01:19:17,710 --> 01:19:19,320 que queremos mudar. 935 01:19:19,320 --> 01:19:24,120 Mas é dentro de modos locais onde estamos indo querer mudar isso. 936 01:19:27,080 --> 01:19:33,110 Então hacker_settings.cc_lmode é o que é chamado. 937 01:19:39,630 --> 01:19:43,020 c_lflag. 938 01:19:49,060 --> 01:19:52,280 Isto é onde nós entramos operadores bit a bit. 939 01:19:52,280 --> 01:19:54,860 Nós somos o tipo de fora do tempo, mas vamos passar por isso rápido. 940 01:19:54,860 --> 01:19:56,600 Isto é onde nós entramos operadores bit a bit, 941 01:19:56,600 --> 01:19:59,950 onde eu acho que eu disse um tempo atrás que quando você começa a lidar com bandeiras, 942 01:19:59,950 --> 01:20:03,370 você vai estar usando operador bitwise muito. 943 01:20:03,370 --> 01:20:08,240 Cada bit na bandeira corresponde a algum tipo de comportamento. 944 01:20:08,240 --> 01:20:14,090 Então, aqui, esta bandeira tem um monte de coisas diferentes, onde todos eles significam algo diferente. 945 01:20:14,090 --> 01:20:18,690 Mas o que eu quero fazer é simplesmente desligar o pouco que corresponde ao ECHO. 946 01:20:18,690 --> 01:20:25,440 Assim, para desligar isso eu faço & = ¬ ECHO. 947 01:20:25,440 --> 01:20:30,110 Na verdade, eu acho que é como Techo ou algo assim. Eu só vou verificar novamente. 948 01:20:30,110 --> 01:20:34,050 I pode termios lo. É só ECHO. 949 01:20:34,050 --> 01:20:38,440 ECHO vai ser um único bit. 950 01:20:38,440 --> 01:20:44,230 ¬ ECHO vai significar todos os bits são definidos a 1, o que significa que todas as bandeiras são definidas como true 951 01:20:44,230 --> 01:20:47,140 exceto para o pouco ECHO. 952 01:20:47,140 --> 01:20:53,830 Ao acabar com minhas bandeiras locais, com isso, significa que todas as bandeiras que estão atualmente definidos para true 953 01:20:53,830 --> 01:20:56,520 ainda vai ser definido como verdadeiro. 954 01:20:56,520 --> 01:21:03,240 Se a minha bandeira ECHO é definido como verdadeiro, então este é necessariamente definida como false na bandeira ECHO. 955 01:21:03,240 --> 01:21:07,170 Então esta linha de código apenas desliga a bandeira ECHO. 956 01:21:07,170 --> 01:21:16,270 As outras linhas de código, vou copiá-los no interesse de tempo e depois explicá-las. 957 01:21:27,810 --> 01:21:30,180 Na solução, disse ele 0. 958 01:21:30,180 --> 01:21:33,880 Provavelmente é melhor dizer explicitamente stdin. 959 01:21:33,880 --> 01:21:42,100 >> Repare que eu também estou fazendo ECHO | ICANON aqui. 960 01:21:42,100 --> 01:21:46,650 ICANON se refere a algo separado, que significa modo canônico. 961 01:21:46,650 --> 01:21:50,280 O que significa modo canônico é geralmente quando você está digitando a linha de comando, 962 01:21:50,280 --> 01:21:54,670 padrão em não processar nada até que você bata nova linha. 963 01:21:54,670 --> 01:21:58,230 Então, quando você GetString, você digita um monte de coisas, então você atingiu nova linha. 964 01:21:58,230 --> 01:22:00,590 É quando ele é enviado a norma dentro 965 01:22:00,590 --> 01:22:02,680 Esse é o padrão. 966 01:22:02,680 --> 01:22:05,830 Quando eu desligar o modo canônico, agora todos os personagens só você pressionar 967 01:22:05,830 --> 01:22:10,910 é o que é processado, que é geralmente um pouco mal, porque ele é lento para processar essas coisas, 968 01:22:10,910 --> 01:22:14,330 é por isso que é bom para o buffer-lo em linhas inteiras. 969 01:22:14,330 --> 01:22:16,810 Mas eu quero que cada personagem a ser processado 970 01:22:16,810 --> 01:22:18,810 desde que eu não quero isso para me esperar para bater de nova linha 971 01:22:18,810 --> 01:22:21,280 antes de processar todos os personagens que eu estive escrevendo. 972 01:22:21,280 --> 01:22:24,760 Isso transforma o modo canônico. 973 01:22:24,760 --> 01:22:31,320 Este material significa apenas quando ele realmente processa caracteres. 974 01:22:31,320 --> 01:22:35,830 Isto significa processá-los imediatamente; assim que eu estou digitando eles, processá-los. 975 01:22:35,830 --> 01:22:42,510 E esta é a função que está a actualizar as minhas configurações para padrão em, 976 01:22:42,510 --> 01:22:45,480 e meios TCSA fazê-lo agora. 977 01:22:45,480 --> 01:22:50,310 As outras opções são esperar até tudo o que está atualmente no fluxo é processado. 978 01:22:50,310 --> 01:22:52,030 Isso realmente não importa. 979 01:22:52,030 --> 01:22:56,920 Só agora alterar as configurações para ser o que está atualmente em hacker_typer_settings. 980 01:22:56,920 --> 01:23:02,210 Eu acho que o chamou hacker_settings, então vamos mudar isso. 981 01:23:09,610 --> 01:23:13,500 Mudar tudo para hacker_settings. 982 01:23:13,500 --> 01:23:16,870 >> Agora no final do nosso programa vamos querer reverter 983 01:23:16,870 --> 01:23:20,210 para o que existe actualmente no interior de normal_settings, 984 01:23:20,210 --> 01:23:26,560 que vai apenas olhar como e normal_settings. 985 01:23:26,560 --> 01:23:30,650 Repare que eu não mudei nenhum dos meus normal_settings uma vez que originalmente conseguir. 986 01:23:30,650 --> 01:23:34,520 Em seguida, apenas para mudá-los de volta, eu passá-los de volta no final. 987 01:23:34,520 --> 01:23:38,390 Esta foi a atualização. Okay. 988 01:23:38,390 --> 01:23:43,900 >> Agora aqui dentro eu vou explicar o código no interesse de tempo. 989 01:23:43,900 --> 01:23:46,350 Não é que muito código. 990 01:23:50,770 --> 01:24:03,750 Vemos, lemos um personagem a partir do arquivo. Nós o chamamos de f. 991 01:24:03,750 --> 01:24:07,850 Agora você pode fgetc homem, mas como fgetc vai funcionar 992 01:24:07,850 --> 01:24:11,910 é apenas que vai retornar o caractere que você acabou de ler ou EOF, 993 01:24:11,910 --> 01:24:15,680 que corresponde ao fim do ficheiro de algum acontecimento ou de erro. 994 01:24:15,680 --> 01:24:19,900 Estamos looping, continuando a ler um único caractere do arquivo, 995 01:24:19,900 --> 01:24:22,420 até que nós funcionamos fora de caracteres para ler. 996 01:24:22,420 --> 01:24:26,650 E enquanto nós estamos fazendo isso, esperamos em um único caractere de padrão dentro 997 01:24:26,650 --> 01:24:29,090 Cada vez que você digitar algo na linha de comando, 998 01:24:29,090 --> 01:24:32,820 que está lendo em um personagem de padrão dentro 999 01:24:32,820 --> 01:24:38,330 Então putchar só vai colocar o char lemos aqui em cima do arquivo para a saída padrão. 1000 01:24:38,330 --> 01:24:42,890 Você pode putchar homem, mas é só colocar para a saída padrão, é a impressão que o personagem. 1001 01:24:42,890 --> 01:24:51,600 Você também pode apenas fazer printf ("% c", c); mesma idéia. 1002 01:24:53,330 --> 01:24:56,670 Isso vai fazer a maior parte do nosso trabalho. 1003 01:24:56,670 --> 01:25:00,300 >> A última coisa que você vai querer fazer é apenas fclose nosso arquivo. 1004 01:25:00,300 --> 01:25:03,310 Se você não fclose, que é um vazamento de memória. 1005 01:25:03,310 --> 01:25:06,680 Queremos fclose o arquivo que originalmente aberto, e eu acho que é isso. 1006 01:25:06,680 --> 01:25:13,810 Se fizermos isso, eu já tenho problemas. 1007 01:25:13,810 --> 01:25:17,260 Vamos ver. 1008 01:25:17,260 --> 01:25:19,960 O que foi reclamar? 1009 01:25:19,960 --> 01:25:30,220 Esperado 'int' mas o argumento é do tipo 'struct _IO_FILE *'. 1010 01:25:36,850 --> 01:25:39,370 Vamos ver se isso funciona. 1011 01:25:45,210 --> 01:25:53,540 Apenas permitido em C99. Augh. Ok, fazer hacker_typer. 1012 01:25:53,540 --> 01:25:57,760 Agora temos descrições mais úteis. 1013 01:25:57,760 --> 01:25:59,900 Portanto, use de identificador não declarado "normal_settings '. 1014 01:25:59,900 --> 01:26:04,170 Eu não chamá-lo normal_settings. Chamei-current_settings. 1015 01:26:04,170 --> 01:26:12,090 Então, vamos mudar tudo isso. 1016 01:26:17,920 --> 01:26:21,710 Agora passando argumento. 1017 01:26:26,290 --> 01:26:29,500 Eu vou fazer isso 0 para agora. 1018 01:26:29,500 --> 01:26:36,720 Okay. . / Hacker_typer cp.c. 1019 01:26:36,720 --> 01:26:39,590 Eu também não limpar a tela no começo. 1020 01:26:39,590 --> 01:26:42,960 Mas você pode olhar para trás para o conjunto de problemas última para ver como você limpar a tela. 1021 01:26:42,960 --> 01:26:45,160 É só imprimir alguns caracteres 1022 01:26:45,160 --> 01:26:47,210 enquanto isso está fazendo o que eu quero fazer. 1023 01:26:47,210 --> 01:26:48,900 Okay. 1024 01:26:48,900 --> 01:26:55,280 E pensando sobre por que isso precisava ser 0 em vez de stdin, 1025 01:26:55,280 --> 01:27:00,560 que deve ser # define 0, 1026 01:27:00,560 --> 01:27:03,890 este se queixa de que - 1027 01:27:13,150 --> 01:27:19,360 Antes, quando eu disse que não há descritores de arquivos, mas então você também tem o seu FILE *, 1028 01:27:19,360 --> 01:27:23,210 um descritor de arquivo é apenas um único número inteiro, 1029 01:27:23,210 --> 01:27:26,970 enquanto que um FILE * tem um monte de coisas associado a ele. 1030 01:27:26,970 --> 01:27:30,380 A razão que nós precisamos dizer 0 em vez de stdin 1031 01:27:30,380 --> 01:27:37,480 é que stdin é um FILE * que aponta para a coisa que é referência descritor de arquivo 0. 1032 01:27:37,480 --> 01:27:45,070 Assim, mesmo aqui, quando eu faço fopen (argv [1], eu estou ficando um * arquivo de volta. 1033 01:27:45,070 --> 01:27:51,180 Mas em algum lugar que * FILE é uma coisa correspondente ao descritor de arquivo para o arquivo. 1034 01:27:51,180 --> 01:27:57,430 Se você olhar para a página do manual para abrir, então eu acho que você vai ter que fazer o homem aberto 3 - nope - 1035 01:27:57,430 --> 01:27:59,380 homem aberto 2 - sim. 1036 01:27:59,380 --> 01:28:06,250 Se você olhar para a página para aberto, aberto é como um fopen de nível inferior, 1037 01:28:06,250 --> 01:28:09,350 e ele está retornando o descritor de arquivo real. 1038 01:28:09,350 --> 01:28:12,050 fopen faz um monte de coisas em cima de aberto, 1039 01:28:12,050 --> 01:28:17,640 que ao invés de retornar apenas descritor de arquivo que retorna um arquivo inteiro ponteiro * 1040 01:28:17,640 --> 01:28:20,590 dentro do que é o nosso descritor de arquivo pequeno. 1041 01:28:20,590 --> 01:28:25,020 Então padrão em se refere à coisa * FILE, 1042 01:28:25,020 --> 01:28:29,120 Considerando 0 refere-se apenas um padrão descritor do arquivo em si. 1043 01:28:29,120 --> 01:28:32,160 >> Perguntas? 1044 01:28:32,160 --> 01:28:35,930 [Risos] Blew por isso. 1045 01:28:35,930 --> 01:28:39,140 Tudo bem. Estamos a fazer. [Risos] 1046 01:28:39,140 --> 01:28:42,000 >> [CS50.TV]