[Powered by Google Translate] [Sección 5: menos cómodo]
[Nate Hardison, Harvard University]
[Esta é CS50.] [CS50.TV]
Entón Benvido de volta, rapaces.
Benvido á sección 5.
Neste punto, completando cuestionario 0 e vendo como fixo,
espero que se sentir realmente ben, porque eu estaba moi impresionado coa puntuación nesta sección.
Para os nosos espectadores en liña, tivemos un par de preguntas
sobre os dous últimos problemas no conxunto de problemas - ou no cuestionario, en vez.
Entón, nós estamos indo ir sobre os moi rapidamente, de xeito que todo o mundo ve o que pasou
e como ir a través da solución real e non só ver a solución en si.
Nós imos pasar por riba o último par de problemas moi rapidamente, 32 e 33.
Así, unha vez máis, para que os espectadores en liña pode ver iso.
>> Se conectar ao seu problema 32, que está na páxina 13,
13 de 16, problema 32 é todo sobre swaps.
Era todo sobre o intercambio de dous enteiros.
É o problema que fora durante un par de veces en charla.
E aquí, o que estabamos pedindo para facer é un trazo de memoria rápida.
Para cubrir os valores das variables que están na pila
como o código pasa por esta función de intercambio.
En particular, o que nós estamos mirando - eu vou poñer este iPad cara abaixo -
en particular, o que estamos vendo é esta liña numerada 6 aquí.
E é numerada 6 por só contiguidade co problema anterior.
O que queremos facer é amosar ou etiquetar o estado da memoria
como é na altura en que se executa este número da liña 6,
que é efectivamente un retorno da nosa función de intercambio aquí.
Se rolar aquí, vimos que os enderezos de todo na memoria foi subministrado por nós.
Iso é moi fundamental, nós imos volver a el en só un momento.
E entón, aquí abaixo, na parte inferior, tivemos un diagrama de pouca memoria que imos referir.
Eu realmente fixen iso no meu iPad.
Entón, eu estou indo a cambiar rapidamente entre o iPad e este código só para referencia.
>> Imos comezar. En primeiro lugar, imos nos centrarse no primeiro par de liñas de inicio aquí.
Para comezar, imos iniciar x e y a 1 a 2.
Polo tanto, temos dúas variables enteiras, ambos están indo para ser colocado na pila.
Nós imos poñer un 1 e un 2 neles.
Entón, se eu virar para o meu iPad, esperamos, imos ver -
Apple espelhamento de TV, e alí imos nós. Okay.
Entón, se eu virar para o meu iPad,
Eu quero iniciar x e y a 1 a 2.
Facemos isto simplemente escribindo un 1 no cadro marcada x
e un 2 na caixa marcada y. Moi sinxelo.
Entón agora imos volver para o portátil, ver o que acontece.
Entón esta liña seguinte é onde as cousas están complicadas.
Nós pasar o enderezo de x e y o enderezo de como os parámetros a e b para a función de cambio.
O enderezo de x é o enderezo de y son cousas que non podemos calcular
sen referirse a estes bala apunta cara á dereita aquí.
E, por sorte, os dous primeiros puntos de bala nos dicir exactamente cales son as respostas.
O enderezo de memoria x 10, e o seu enderezo na memoria y é 14.
Entón eses son os valores que son pasados ​​como a e b enriba da nosa función de intercambio.
Entón, de novo, voltar para o noso diagrama, podo escribir un 10 nun
e 14 un en b.
Agora, este punto é onde nós continuar co cambio.
Entón, lanzando ao seu portátil de novo,
vemos que a forma na que o intercambio funciona é que dereference primeiro unha tenda e o resultado en tmp.
Así, o operador dereference di, "Hey. Tratar o contido dunha variable como un enderezo.
Ir para o que está almacenado naquel enderezo, e cargalo. "
O que leva a fóra da variable que vai ser almacenado na nosa variable tmp.
Lanzando ao seu iPad.
Ou tamén para tratar 10, sabemos que é o enderezo de 10 x varible
porque foi dito polo noso punto de bala que o enderezo de x en memoria é 10.
Entón, podemos ir alí, incorporarse o valor do mesmo, o que é un, como podemos ver no noso iPad,
e cargar isto tmp.
De novo, isto non é o contido final.
Nós imos camiñar e nós imos chegar ao noso estado final do programa no final.
Pero agora temos o valor almacenado nun tmp.
>> E hai unha pregunta rápida aquí.
[Alexander] é o operador dereference - que é só o dereito de estrela na fronte da variable?
Si >>. Así, o operador dereference, como virar de volta para o noso portátil, unha vez máis,
é esta estrela fronte.
Nese sentido, é - vostede comparalos-lo co seu fornecedor de multiplicación
que require dúas cousas: o operador dereference é un operador unário.
Só aplicada a un valor, por oposición a un operador binario,
onde aplica a dous valores distintos.
Entón, iso é o que pasa nesta liña.
Nós cargados o valor 1 e é almacenado no noso variable temporal enteiro.
A seguinte liña, gardados o contido b -
ou, en vez diso, almacenar o contido que B está a apuntar cara o lugar onde un está a apuntar.
Se analizamos este da dereita para a esquerda, imos b dereference,
imos abordar 14, imos pegar o número enteiro que está aí,
e entón nós estamos indo para ir ao enderezo 10,
e imos xogar o resultado da nosa dereference de b en que o espazo.
Lanzando de volta ao noso iPad, onde podemos facelo un pouco máis concreto,
que podería axudar se eu escribir números en todos os enderezos aquí.
Entón, nós sabemos que, y, estamos no enderezo 14, x está no enderezo 10.
Cando comezamos a B, B dereference, imos pegar o valor 2.
Nós imos ir ese valor porque ese é o valor que vive no enderezo 14.
E nós imos poñelas na variable que vive no enderezo 10,
que está alí, correspondente á nosa variable x.
Así, podemos facer un pouco de sobreescribir aquí
onde imos nos librar do noso 1 e en vez diso, escriba unha 2.
Entón está todo ben e bo no mundo, aínda que teñamos x sobres agora.
Temos almacenados valor antigo de x na nosa variable tmp.
Así, podemos completar a cambio a liña seguinte.
Lanzando de novo o noso portátil.
Agora todo o que queda é levar o contido da nosa variable temporal enteiro
e almacena-los na variable que vive no enderezo que B está seguro.
Entón, nós imos efectivamente b dereference para obter acceso á variable
é dicir, no enderezo que b ten nel,
e nós imos encher o valor que tmp está seguro para el.
Lanzando ao seu iPad unha vez.
Eu podo borrar este valor aquí, 2,
e en vez diso imos copiar o dereito un para el.
A continuación, a seguinte liña que executa, por suposto -
se jogarmos ao seu portátil - é este o punto 6,
que é o momento en que nós queriamos ter o noso diagrama completo cuberto.
Entón, lanzando ao seu iPad, unha vez máis, só así pode ver o diagrama completo,
podes ver que temos un 10 nun 14 en un B, a 1 tmp, un 2 en x, e un 1 en y.
Hai algunha dúbida sobre iso?
Será que isto fai máis sentido, tendo orientado por ela?
Facer menos sentido? Esperemos que non. Okay.
>> Os punteiros son un tema moi complicado.
Un dos caras que traballan con ten un dito moi común:
"Para entender os punteiros, ten que primeiro entender os punteiros".
Que eu creo que é moi certo. Fai levar un pouco para acostumar con iso.
Sorteo de fotos, sorteo de diagramas de memoria como esta son moi útil,
e despois de andar por exemplo tras exemplo tras exemplo,
vai comezar a ter sentido un pouco máis e sentido un pouco máis e un pouco máis de sentido.
Finalmente, un día, vai ter todo completamente dominado.
Calquera dúbida, antes de pasar ao seguinte problema? Todo ben.
Entón Xire cara atrás para o portátil.
O seguinte problema que temos é o problema número 33 na lista de I / O.
Zoom sobre iso un pouco.
Problema 33 - Si?
>> [Daniel] Eu só tiña unha pregunta rápida. Esta estrela, ou o asterisco,
é chamado dereferencing cando usa un asterisco antes.
Como se chama cando usa o comercial antes?
>> O comercial antes é o enderezo do operador.
Entón, imos rodar de volta.
Oops. Eu estou no modo de zoom, non podo realmente desprazamento.
Se olharmos para este código realmente rápido aquí,
de novo, a mesma cousa suceder.
Se olharmos para este código aquí, nesta liña onde facemos unha chamada para intercambiar,
o comercial é só dicir "obter o enderezo no que vive a variable x."
Cando o compilador compilar código,
ten que fisicamente marcar un lugar na memoria de todos os seus variables para vivir.
E así que o compilador pode entón facer unha vez que está feita de todo,
el sabe, "Oh, eu coloque no enderezo x 10. coloque y no enderezo 14."
Pode, entón, encher estes valores para ti.
Así, pode entón - pode pasar este e pase & y no ben.
Eses faces obter o enderezo, pero tamén, cando paso-los para a función de intercambio,
este tipo de información, este int * aquí, di o compilador,
"Ok, imos estar interpretando este enderezo como un enderezo dunha variable enteira."
Como un enderezo de un número enteiro, que é distinto do enderezo de unha variable de caracteres
porque un int toma-se en unha máquina de 32 bits, ocupa 4 bytes de espazo,
mentres que un único personaxe ocupa 1 byte de espazo.
Por iso, é importante saber tamén o que é - o que vive, o tipo de valor
está a vivir no enderezo que foi pasado dentro
Ou o que está lidando.
Desta forma, vostede sabe cantos bytes de información para realmente levar a súa memoria RAM.
E entón, si, este operador dereference, como se está preguntando:
vai e accede a información nun enderezo particular.
Por iso, di, con esta variable dun aquí, tratar o contido dun como enderezo,
ir a este enderezo, e tirar, preme no procesador, a carga nun rexistrador
os valores reais ou os contidos que viven aquel enderezo.
Algunha pregunta? Estas son boas preguntas.
É un monte de nova terminoloxía tamén.
É tamén unha especie de funk, vendo & * e en diferentes lugares.
>> Todo ben.
Entón, de volta para o problema de 33, arquivo I / O.
Este foi un dos problemas que eu creo que un par de cousas aconteceu.
Un, é un tema relativamente novo.
El foi presentado pouco antes da proba,
e entón eu creo que foi máis ou menos como un dos problemas de palabras en matemáticas
onde eles dan-lle unha morea de información, pero realmente non acabar tendo que usar unha tonelada do mesmo.
A primeira parte deste problema está describindo o que é un ficheiro CSV.
Agora, un arquivo CSV, de acordo coa descrición, é un arquivo separado por comas valores.
A razón, son en todo interesante, ea razón pola que nunca usalos,
é, pois, como moitos de vostedes xa usou o material como o Excel?
Imaxe maioría de vostedes probablemente, ou vai utilizar nalgún momento da súa vida.
Vai usar algo como o Excel.
Co fin de obter os datos dunha folla de cálculo de Excel ou facer calquera tipo de tratamento con el,
se quería escribir un programa en C ou Python programa, o programa Java,
para xestionar os datos almacenados alí,
unha das formas máis comúns para tiralo está nun ficheiro CSV.
E pode abrir o Excel e cando vai cara á 'Gardar como' o diálogo,
pode saír un arquivo CSV real.
>> Útil para saber como tratar con isto.
O modo como funciona é que é semellante a - Quero dicir, é esencialmente imitando unha folla,
onde, como vemos aquí, na peza máis á esquerda,
temos todos os últimos nomes.
Así, temos Malan, entón Hardison, e, a continuación, Bowden, MacWilliam, e, a continuación, Chan.
Todos os sobrenomes. E entón unha coma separa os apelidos dos primeiros nomes.
David, Nate, Rob, Tommy, e Zamyla.
Eu sempre mesturar Robby e Tom
E, a continuación, finalmente, a terceira columna é o enderezo de e-mail.
Despois de entender iso, o resto do programa é moi sinxelo de implementar.
O que temos feito, a fin de imitar esa mesma estrutura no noso programa C
é que usei unha estrutura.
Imos comezar a xogar con estes un pouco tamén.
Vimo-los para o primeiro bit pouco no conxunto de problemas 3, cando estabamos lidando con os dicionarios.
Pero esa estrutura persoal almacena un último nome, un nome e un correo-e.
Así como o noso arquivo CSV foi gardar.
Polo tanto, esta é só a conversión dun formato a outro.
Temos que converter, neste caso, unha estrutura persoal para unha liña,
unha liña separada por comas, só como aquel.
Isto ten sentido? Vostedes teñen todos levados ao cuestionario,
entón eu imaxino que teña polo menos tivo moito tempo para pensar sobre iso.
>> Na función de aluguer, o problema nos pide para tomar - zoom we'll sobre iso un pouco -
tomar nunha estrutura de persoal, unha estrutura de persoal, co nome de s,
e achegar o seu contido para o noso arquivo staff.csv.
Acontece que iso é moi sinxelo de usar.
Imos tipo de xogar con esas funcións hoxe un pouco máis.
Pero, neste caso, a función fprintf é realmente a clave.
Así, con fprintf, podemos imprimir, así como vostedes teñen benvida a utilizar este termo printf todo.
Pode printf unha liña dun arquivo.
Entón, en vez de só facer unha chamada de costume printf onde lle dá a el a cadea de formato
e despois de substituír todas as variables cos seguintes argumentos,
con fprintf, o seu argumento é moi primeira vez o ficheiro que quere gravar.
Se estivésemos a mirar para iso no aparello, por exemplo, o home fprintf,
podemos ver a diferenza entre o printf e fprintf.
Vou ampliar un pouco aquí.
Así, con printf, dar-lle unha secuencia de formato, e logo os argumentos seguintes
son todas as variables para reposición ou substitución na nosa cadea de formato.
Considerando que, con fprintf, o primeiro argumento é de feito ese * ficheiro chamado un córrego.
>> Voltar aquí para a nosa contratación,
nós xa temos o noso fluxo * ficheiro aberto para nós.
Isto é o que fai esta primeira liña, que abre o ficheiro staff.csv,
abre en modo incremental, e todo o que queda para nós é
escribir a estrutura de persoal para o arquivo.
E, imos ver, eu quero usar o iPad?
Vou usar o iPad. Temos baleiro - imos poñer isto na mesa para que eu poida escribir un pouco mellor -
anular a contratación e que leva, un argumento, unha estrutura de equipo chamado s.
Temos os nosos aparellos, temos a nosa * ficheiro chamado ficheiro,
Nós temos a nosa liña fopen dada a nós,
e eu vou gravala-lo como puntos, unha vez que xa está no pedía.
E entón, na nosa liña seguinte, imos facer unha chamada fprintf
e imos pasar o arquivo que desexa imprimir,
e entón a nosa cadea de formato, que -
Eu vou deixar vostedes me dicir o que parece.
E, Stella? Vostede sabe o que a primeira parte da cadea de formato parece?
[Stella] Eu non estou seguro. Sinto-se a liberdade de >> pedir Jimmy.
Sábese, Jimmy?
[Jimmy] Sería só ser o último? Eu non sei. Eu non estou totalmente seguro.
Ok >>. Que tal, será que alguén recibir este correcta no exame?
Non Todo ben.
Acontece que aquí todo o que temos que facer é que queremos cada parte do noso cadro de persoal
para ser impreso como unha cadea na nosa arquivo.
Nós só usar o personaxe substitución corda tres veces distintas, porque temos un apelido
seguido por coma, un nome seguido dunha coma,
e, finalmente, o seu enderezo de correo-e que é seguido - que non é
encaixando na miña pantalla - pero é seguido por un carácter de nova liña.
Entón eu vou escribir isto só alí en baixo.
E entón, despois da nosa secuencia de formato,
só temos as substitucións, que temos acceso mediante a notación de punto
que vimos no conxunto de problemas 3.
Podemos usar s.last, s.first e s.email
para substituír os tres valores na nosa cadea de formato.
Entón, como foi iso? Ten sentido?
Si? Non? Posiblemente? Okay.
>> A última cousa que facemos despois de que nós impreso e despois abrimos o noso arquivo:
sempre que abriu un arquivo, temos sempre que lembrar pechalo.
Porque, do contrario imos acabar vazando a memoria,
utilizando-se descritores de ficheiros.
Entón, para pecha-lo, que a función que imos usar? Daniel?
[Daniel] fclose? >> Fclose, exactamente.
Así, a última parte deste problema era pechar correctamente o ficheiro usando a función fclose,
que só se parece con isto.
Non é moi tolo.
Cool.
Entón, iso é problema de 33 no cuestionario.
Nós imos ter que arquivo definitivamente máis I / O chegando.
Imos facer un pouco máis en charla hoxe, ou na sección de hoxe,
porque é iso que vai formar a maior parte deste pset próximo.
Imos seguir adiante dende o cuestionario neste momento. Si?
>> [Charlotte]] Por que fclose (arquivo) no canto de fclose (staff.csv)?
Ah >>. Porque sucede que - para a cuestión, que é un gran,
É por iso que, cando escribimos fclose, estamos escribindo fclose estrela variable (arquivo)
en oposición ao nome do ficheiro, staff.csv? Isto é correcta? Si
Entón, imos dar un ollo. Se eu atrás para o meu portátil,
e imos ollar para a función fclose.
Así, a función fclose pecha un córrego e leva no punteiro para o fluxo de que desexa pechar
en oposición ao nome real do ficheiro que desexa pechar.
E isto porque, nos bastidores, cando fai unha chamada para fopen,
cando abrir un ficheiro, está, de feito, a distribución de memoria para almacenar informacións sobre o arquivo.
Entón tes un punteiro do ficheiro que contén información sobre o arquivo,
como é aberto, o seu tamaño, onde está actualmente no arquivo,
de modo que pode facer chamadas de lectura e escritura para aquel lugar especial dentro do arquivo.
Vostede acaba de pechar o punteiro no canto de pechar o nome do ficheiro.
>> Si? [Daniel] Polo tanto, a fin de utilizar de aluguer, diría que - como obter a entrada do usuario?
O fprintf actuar como GetString no sentido de que el só vai esperar a entrada do usuario
e pedir-lle para escribir isto - ou esperar para escribir estas tres cousas?
Ou precisa de usar algo para aplicar aluguer?
Si >>. Entón, nós non somos - a cuestión foi, como é que imos chegar a entrada do usuario
a fin de implementar aluguer? E o que temos aquí é o chamador de aluguer,
pasaron neste struct persoal con todos os datos almacenados na estrutura xa.
Entón fprintf é capaz de escribir só que os datos directamente para o arquivo.
Non hai espera para a entrada do usuario.
O usuario xa está dada a entrada correctamente por poñelas nesa estrutura de persoal.
E as cousas, por suposto, vai romper algún destes punteiros foron nulos,
para que rolar para atrás ata aquí e miramos para a nosa estrutura.
Temos cadea cadea ultimo primeiro, e-mail cadea.
Agora sabemos que todos aqueles realmente, baixo o capo, son variables char *.
Isto pode ou non pode estar apuntando para nulo.
Poden estar apuntando para a memoria na pila,
quizais memoria na pila.
Nós realmente non sei, pero se calquera destes punteiros son nulos ou inválidos,
que iso sempre vai fallar a nosa función de aluguer.
Iso era algo que estaba medio fóra do alcance do exame.
Non está preocupando con iso.
Grande. Okay. Entón pasar do quiz.
>> Imos pechar este cara, e nós estamos indo ollar pset 4.
Entón, se vostedes ollar para a especificación pset, xa que pode acceder a ela, cs50.net/quizzes,
imos pasar por algúns dos problemas de hoxe da sección.
Estou desprazamento cara abaixo - sección de preguntas comeza na terceira páxina da especificación pset.
E a primeira parte pídelle para ir e ver o curta en redirixido e canos.
Que era unha especie de curto legal, mostra-lle algúns trucos novos, frescos mando de liña que pode usar.
E entón temos algunhas preguntas para ti tamén.
Esta primeira pregunta sobre fluxos, para que printf escribe por defecto,
que tipo de tocada en só un pouco de un momento atrás.
Este fprintf que nós estabamos discutindo leva un fluxo de ficheiro * como o seu argumento.
fclose leva un fluxo de ficheiro *, así como,
eo valor de retorno de fopen lle dá un fluxo de ficheiro * tamén.
A razón que nós non vimos antes, cando os que lidou con printf
é porque printf ten un fluxo de patrón.
E o fluxo estándar para o que el escribe
vai descubrir máis sobre a curta.
Entón, en definitiva, dar un ollo.
>> Na sección de hoxe, imos falar un pouco sobre o GDB,
pois canto máis lle está familiarizado con el, máis práctica comeza con el,
o máis capaz será realmente descubrir os erros no seu propio código.
Isto acelera o proceso de depuración se tremendamente.
Entón, usando printf, cada vez que fai que ten que recompilar o código,
ten que executa-lo de novo, ás veces ten que mover a chamada printf redor,
Comentar o código, el só leva un tempo.
O noso obxectivo é intentar convencelo de que, co GDB, pode esencialmente
nada printf en calquera punto do seu código e nunca ten que recopila-lo.
Vostede non ten que iniciar e manter adiviñar onde printf seguinte.
A primeira cousa que facer é copiar esa liña e obter o código da sección fóra da rede.
Estou copiando esta liña de código que di: "http://cdn.cs50.net wget".
Eu estou indo a copia-lo.
Eu estou indo a ir para o meu aparello, zoom out para que poida ver o que eu estou facendo,
cola-lo alí, e cando presione Enter, este comando wget é literalmente unha tea obter.
Vai tirar para abaixo este ficheiro fóra de Internet,
e vai garda-lo para o directorio actual.
Agora, se eu incluír o meu directorio actual, podes ver que eu teño ese arquivo section5.zip ben alí.
O xeito de xestionar este cara é descompactá-lo,
que pode facer na liña de comandos, así como este.
Section5.zip.
Isto vai descompactá-lo, crear o cartafol para min,
inflar todo o contido, poñer-los alí dentro.
Entón agora podo ir ao meu directorio sección 5 usando o comando cd.
Limpar a pantalla usando claro. Entón, limpar a pantalla.
Agora eu teño un terminal limpo agradable de manexar.
>> Agora, se eu incluír todos os ficheiros que eu vexo neste directorio,
vostede ve que eu teño catro arquivos: buggy1, buggy2, buggy3 e buggy4.
Eu tamén teño os arquivos correspondentes. C.
Non imos ollar para os arquivos. C por agora.
En vez diso, imos usalos cando abrimos GDB.
Mantivemos-los en torno de xeito que temos acceso ao código fonte real cando estamos usando GDB,
pero o obxectivo desta parte da sección é de xogar volta co GDB
e ver como podemos usalo para descubrir o que está a suceder de malo con cada un dos catro programas de buggy.
Entón, estamos só indo ao redor da sala moi rapidamente,
e eu vou pedir a alguén para realizar un dos programas de buggy,
e despois imos en grupo mediante GDB, e imos ver o que podemos facer para corrixir estes programas,
ou, polo menos, identificar o que está a suceder de malo en cada un deles.
Imos comezar con Daniel. Vai executar buggy1? Imos ver o que acontece.
[Daniel] El di que hai un fallo de aplicación. Si >>. Exactamente.
Entón, se eu executar buggy1, eu recibín un fallo de seg.
Neste punto, eu podería ir e abrir buggy1.c,
tentar descubrir o que está a suceder de malo,
pero unha das cousas máis irritantes sobre este erro de falla de seg
é que non di en que liña das cousas programa realmente deu mal e rompe.
Vostede medio que ten que ollar para o código
e descubrir usando palpite e marque ou printf para ver o que está a suceder de malo.
Unha das cousas máis legais sobre o GDB é que é moi, moi fácil
para descubrir a liña na que traba o programa.
É totalmente paga a pena usalo, aínda que só por iso.
Entón, para arrincar GDB, eu tecleo GDB, e entón eu dar-lle o camiño para o executable que quero correr.
Aquí eu estou escribindo gdb ./buggy1.
Prema Intro. Me dá toda a información dos dereitos de autor,
e aquí podes ver esta liña que di: "a lectura de símbolos / home /
jharvard/section5/buggy1 ".
E, se todo funcionar ben, vai ver que imprimir unha mensaxe parecida con esta.
El vai ler símbolos, que vai dicir: "Eu estou lendo símbolos do seu arquivo executábel",
e entón el vai ter ese "feito" mensaxe aquí.
Se ves algunha outra variación deste, ou ver que non conseguía atopar os símbolos
ou algo así, o que significa é que simplemente non compilado o executable correctamente.
Cando compilar programas para o seu uso co GDB, temos que usar a bandeira especial-g,
e iso está feito por defecto, se compilar os seus programas, só escribindo facer
ou facer buggy ou facer recuperar, calquera destes.
Pero se está compilando manualmente con Clang, entón vai ter que ir e que inclúen flag-g.
>> Neste punto, agora que temos o noso GDB ventá,
é moi sinxelo de executar o programa.
Nós pode escribir run, ou podemos simplemente escriba r.
A maioría dos comandos de GDB pode ser abreviado.
Normalmente, a só un ou dous cartas, o que é moi agradable.
Entón Saad, se escribir r e prema Intro, o que ocorre?
[Saad] Eu teño SIGSEGV, fallo de segmento, e entón todo este argot.
Si >>.
Como estamos vendo na pantalla, agora, e como Saad dixo,
cando digitamos carreira ou R e presione Enter, aínda recibimos o fallo seg mesmo.
Entón, usando o GDB non resolve o noso problema.
Pero dános algúns gobbledygook, e verifícase que este gobbledygook
De feito, dinos onde está a suceder.
Para analizar iso un pouco, este primeiro bit é a función en que todo está a suceder de malo.
Hai esa __ strcmp_sse4_2, e dinos que está a suceder neste ficheiro
chamado sysdeps/i386, todo iso, de novo, unha especie de confusión - pero a liña 254.
Isto é medio difícil de analizar. Normalmente, cando ve as cousas como esta,
o que significa que está seg falla dunha das bibliotecas de sistema.
Entón, algo que ver con strcmp. Vostedes viron strcmp antes.
Non é moi tolo, pero iso significa que strcmp está roto ou que hai un problema co strcmp?
¿Que pensas, Alexandre?
[Alexander] É que - é de 254 a liña? E o - non binario, pero non é o seu falsos,
e despois hai outra lingua para cada función. É que 254 en que a función ou -?
É >> liña 254. Parece que neste ficheiro s., Por iso, probablemente código de montaxe.
>> Pero, eu creo que a cousa máis urxente é porque temos tido unha falla de seg,
e parece que está a benvida a función strcmp,
iso implica, entón, que strcmp está roto?
Non debería, espero. Entón, só porque ten un fallo de segmento
nunha das funcións do sistema, normalmente significa que simplemente non telo chamado correctamente.
O máis rápido que hai que facer para descubrir o que está realmente a suceder
cando ve algo tolo como este, sempre que ve unha falla seg,
especialmente se ten un programa que está a usar máis que de inicio,
é a utilización dun rexistro de chamadas.
I abreviar backtrace escribindo BT, en oposición á palabra backtrace completo.
Pero Charlotte, o que ocorre cando escribe BT e prema Intro?
[Charlotte] El me amosa dúas liñas, a liña 0 e liña 1.
Si >>. Así liña 0 e liña 1.
Estes son os cadros de pila reais que estaban actualmente no xogo cando o programa deixou de funcionar.
A partir do cadro superior, cadro 0, e indo ao fondo máis, que é unha armazón.
O noso cadro de nivel superior é o cadro strcmp.
Podes pensar niso como semellante ao problema que só estaban facendo no cuestionario cos punteiros,
onde tiñamos intercambiar cadro de pila enriba cadro de pila principal,
e tivemos as variables que cambio estaba usando encima das variables que principal estaba usando.
Aquí a nosa caída produciuse na nosa función strcmp, que foi chamado pola nosa función principal,
backtrace e está nos dando non só as funcións en que as cousas fallaron,
pero tamén está nos dicindo que todo foi chamado.
Entón, se eu rolar un pouco máis á dereita,
podemos ver que, si, que estaban na liña 254 do ficheiro strcmp-sse4.s.
Pero a chamada foi feita en buggy1.c, liña 6.
Entón isto significa que podemos facer - é que podemos só ir comprobar e ver o que estaba acontecendo
en buggy1.c, liña 6.
De novo, hai algunhas formas de facelo. Un deles é para saír do GDB
ou ter o seu código aberto noutra xanela e referencia cruzada.
Iso, por si só, é moi útil, porque agora se está en horario de oficina
e ten un fallo seg eo seu TF está a se pregunta onde todo estaba batendo,
pode só dicir: "Oh, liña 6. que eu non sei o que está a suceder,
pero algo sobre a liña 6 está causando o meu programa para romper ".
A outra forma de facer isto é que pode usar este comando chamada lista en GDB.
Tamén pode abreviar con l.
Entón, se se loita l, o que temos aquí?
Temos unha morea de cousas estrañas.
Este é o código de montaxe real
que está en strcmp_sse4_2.
Isto parece tipo de funky,
ea razón que estamos recibindo é porque agora,
GDB nos ten en cadro 0.
>> Entón, cando nós miramos para as variables, cada vez que ollar para o código fonte,
nós estamos mirando para o código fonte que pertence ao cadro de pila que estamos actualmente dentro
Polo tanto, a fin de obter algo significativo, temos que
moverse para un cadro de pila que fai máis sentido.
Neste caso, o cadro de pila principal tería sentido un pouco máis,
porque ese era realmente o código que escribiu.
Non o código strcmp.
A forma como pode mover-se entre os cadros, neste caso, porque temos dous,
temos 0 e 1,
fai iso con cara arriba e para abaixo comandos.
Se eu subir un cadro,
agora eu estou no cadro de pila principal.
Eu podo mover para abaixo para volver a onde eu estaba,
ir para arriba de novo, ir para abaixo de novo, e ir para arriba de novo.
Se sempre fai o programa no GDB, ten unha caída, comeza a backtrace,
e ve que está en algún arquivo que non sabe o que está a suceder.
Intenta lista, o código non parece familiar para vostede,
dar un ollo nos seus cadros e descubrir onde está.
Probablemente está no cadro de pila incorrecta.
Ou, polo menos está en un cadro de pila que non é o que realmente pode depurar.
Agora que estamos no cadro de pila axeitada, estamos en principal,
agora podemos utilizar o comando lista para descubrir o que a liña estaba.
E pode velo, imprimir lo para nós aquí.
Pero podemos acertar incluír todos o mesmo, e lista dános a impresión agradable
do código fonte real que está a suceder aquí.
>> En particular, podemos ollar para a liña 6.
Podemos ver o que está a suceder aquí.
E parece que nós estamos facendo unha comparación de cadea
entre a cadea "CS50 pedras" e argv [1].
Algo sobre iso foi bater.
Entón Missy, tes algunha opinión sobre o que pode estar a suceder aquí?
[Missy] Eu non sei por que está fallando. >> Vostede non sabe por que está batendo?
Jimmy, todos os pensamentos?
[Jimmy] eu non estou totalmente seguro, pero a última vez que usou cadea de comparar,
ou strcmp, tivemos algo así como tres casos diferentes baixo el.
Nós non temos un ==, eu non creo que, mesmo en que a primeira liña.
En vez diso, foi separada en tres, e unha era == 0,
un foi <0, eu creo, e foi un> 0.
Entón quizais algo así? Si >>. Entón hai esa cuestión
de que estamos facendo a comparación correctamente?
Stella? Todos os pensamentos?
[Stella] Eu non estou seguro. >> Non estou seguro. Daniel? Pensamentos? Okay.
Acontece que o que está a suceder aquí é cando executamos o programa
e temos a culpa seg, cando o programa foi executado por primeira vez, Daniel,
deu a ela os argumentos de liña de comandos?
[Daniel] Non Non >> Neste caso, o que é o valor argv [1]?
>> Non hai ningún valor. >> Dereito.
Ben, non hai valor de secuencia apropiada.
Pero hai algún valor. Cal é o valor que queda almacenado alí?
Un valor >> lixo? >> É tanto un valor de lixo, ou, neste caso,
o final da matriz argv sempre é rematada co null.
Entón, o que realmente foi almacenado alí é nulo.
A outra forma de solucionar isto, en vez de pensar niso,
é intentar mostra-lo.
Este é o lugar onde eu estaba dicindo que o uso de GDB é grande,
porque pode imprimir todas as variables, todos os valores que quere
Usando este práctico-dandy mando p.
Entón, se eu escribir p e escriba o valor dunha variable ou nome dunha variable,
dicir, argc, vexo que argc é 1.
Se eu queira imprimir argv [0], podo facelo así.
E, como vimos, argv [0] é sempre o nome do seu programa,
sempre o nome do executable.
Aquí vese que ten o nome completo do camiño.
Eu tamén pode imprimir argv [1] e ver o que acontece.
>> Aquí temos este tipo de valor místico.
Temos este 0x0.
Teña en conta que, no inicio do mandato, cando falamos de cifras hexadecimais?
Ou que pequena pregunta ao final pset 0 sobre como representar 50 en hexadecimal?
A nosa forma de escribir números hexadecimais no CS, só para non confundir-nos
con números decimais, sempre prefixo-los con 0x.
Polo tanto, este prefixo 0x sempre significa só interpretar o seguinte número como un número hexadecimal,
non como unha cadea, non como un número decimal, non como un número binario.
Unha vez que o número de 5-0 é un número válido en hexadecimal.
E é un número decimal, 50.
Polo tanto, este é só coma nós disambiguate.
Entón 0x0 medios 0 hexadecimal, que tamén é decimal, binario 0 0.
É só o valor 0.
Acontece que iso é o que nulo é, en realidade, na memoria.
Nulo é só 0.
Aquí, o elemento almacenado argv [1] é nulo.
Entón, estamos tentando comparar o noso "CS50 rochas" cadea para unha cadea nula.
Entón dereferencing nulo, intentando acceder cousas ao nulo,
aqueles son normalmente vai causar algún tipo de fallo de segmento ou doutras cousas malas acontezan.
E ocorre que strcmp non comproba
ou non que pasou un valor que é nulo.
En vez diso, el simplemente vai adiante, intenta facer a súa cousa,
e seg defectos, ela seg fallos, e é o seu problema. Ten que ir arranxar.
Moi rapidamente, como podemos solucionar este problema? Charlotte?
[Charlotte] Podes comprobar se a usar.
Entón, se argv [1] é nulo, == 0, a continuación, voltar 1, ou algo [inintelixible].
Si >>. Entón esta é unha boa forma de facelo, como se pode comprobar,
o valor que estamos a piques de pasar ao strcmp, argv [1], non é nulo?
Se é nulo, entón podemos dicir ben, abortar.
>> A forma máis común de facer isto é usar o valor argc.
Podes ver aquí a principios do inicio,
omitimos que primeiro exame que normalmente facemos cando usar argumentos de liña de comandos,
que é para probar se ou non o seu valor argc é o que esperamos.
Neste caso, estamos esperando polo menos dous argumentos,
o nome do programa máis outro.
Porque nós estamos a piques de empregar o segundo argumento aquí.
Entón, ter algún tipo de proba con antelación, antes da nosa chamada strcmp
que as probas ou non argv é polo menos dúas, tamén faría o mesmo tipo de cousas.
Podemos ver se isto funciona, executando o programa de novo.
Sempre pode reiniciar o programa dentro do GDB, que é moi bo.
Pode correr, e cando pasar argumentos para o seu programa,
pasa-los cando chamar executar, non cando arrincar GDB.
Desta forma, pode manter invocando o seu programa con argumentos diferentes cada vez.
Entón execute, ou aínda, podo escribir r, e imos ver o que pasa se escribir "Ola".
Será sempre preguntar se quere inicia-lo desde o inicio de novo.
Normalmente, quere comezar desde o inicio de novo.
E, neste punto, el reinicia-lo novo, el imprime
o programa que estamos correndo, buggy1, co argumento Ola,
e imprime tanto estándar, el di, "Ten un D," fronte triste.
Pero nós non seg culpa. El dixo que o proceso saíu normalmente.
De xeito que parece moi bo.
Ningunha falla máis seg, podemos pasado,
entón parece que ese era realmente o erro culpa seg que estabamos recibindo.
Desafortunadamente, el nos di que estamos comezando un D.
>> Podemos ir cara atrás e ollar para o código e ver o que estaba acontecendo alí
para descubrir o que era - por iso que estaba nos dicindo que temos un D.
Imos ver, aquí foi este printf dicindo que ten un D.
Se tipo de lista, como manter a lista de escribir, el mantén a iteração a través do seu programa,
por iso vai amosar-lle as primeiras liñas do seu programa.
A continuación, vai amosar-lle as próximas liñas, eo anaco seguinte eo seguinte peza.
E vai continuar intentando ir para abaixo.
E agora imos comezar a "liña de número 16 está fóra de alcance."
Porque só ten 15 liñas.
Se chegar a este punto ea súa pregunta: "O que fago?" pode usar o comando de axuda.
Use a axuda e, a continuación, dar-lle o nome dun comando.
E ve o GDB dános todo este tipo de cousas.
Ela di: "Sen argumento, lista dez liñas máis logo ou en torno á listaxe anterior.
Lista - lista as 10 liñas antes - "
Entón, imos tentar usar menos lista.
E que lista as 10 liñas anterior, pode xogar con unha lista pouco.
Podes facer a lista, lista -, pode ata dar incluír un número, como a lista de 8,
e vai incluír as 10 liñas en torno á liña 8.
E podes ver o que está a suceder aquí é que ten un simple, se outra cousa.
Se insire CS50 rochas, ela mostra "Ten un A."
Se non, el imprime "Ten un D."
Cidade chatice. Todo ben. Si?
>> [Daniel] Entón, cando intento facer CS50 rochas sen as comiñas,
el di "Ten un D."
Eu precisaba das aspas para facelo funcionar, por que isto?
Si >>. Acontece que cando - este é outro petisco pouco de diversión -
cando executar o programa, se executa-lo e escribir CS50 rochas,
só como Daniel estaba dicindo que el fixo, e presione Enter,
aínda di que obter un D.
E a pregunta é, por que é isto?
E verifícase que o terminal noso e GDB analizar estes como dous argumentos distintos.
Porque cando hai un espazo que está implícito como
o primeiro argumento rematou, o seguinte argumento está a piques de comezar.
O xeito de combinar os en dous, ou moito, nun argumento,
é utilizar as comiñas.
Entón, agora, se poñelas entre comiñas e executa-lo de novo, temos un A.
Entón, só para recapitular, sen comiñas, CS50 e rochas son analizados como dous argumentos distintos.
Con aspas, é analizado como un argumento completamente.
>> Podemos ver isto con un punto de interrupción.
Ata agora temos sido executado o noso programa, e está sendo executado
ata que seg fallos ou acertos dun erro
ou ata que saíu e todo foi totalmente ben.
Iso non é necesariamente o máis útil, porque ás veces
ten un erro no seu programa, pero el non está causando un fallo de segmento.
Non está causando o seu programa para deixar ou algo así.
O camiño para chegar GDB para pausar o seu programa nun punto
é establecer un punto de interrupción.
Podes facelo a través da creación dun punto de interrupción nun nome de función
ou pode definir un punto de interrupción nunha determinada liña de código.
Eu gusto de definir puntos de interrupción en nomes de función, porque - fácil de lembrar,
e se realmente entrar e cambiar o seu código fonte un pouco,
entón o seu punto de interrupción vai realmente estar no mesmo lugar dentro do seu código.
Considerando que se está a usar números de liña, e os números de liña cambiar
porque engadir ou eliminar algún código, a continuación, os puntos de interrupción están totalmente asneira.
Unha das cousas máis comúns que facer é establecer un punto de interrupción na función principal.
Moitas veces, eu vou arrincar o GDB, eu vou escribir b principal, prema Intro, e que vai establecer un punto de interrupción
sobre a función principal, que só di: "Pause o programa así que comezar a correr",
e de que xeito, cando executar o meu programa con, digamos, CS50 rochas como dous argumentos
e prema Intro, el está coa función principal e para na primeira liña,
dereita antes que avalía a función strcmp.
>> Dende que eu estou unha pausa, agora podo comezar a perder tempo e ver o que está a suceder
con todas as diferentes variables que son pasados ​​para o meu programa.
Aquí podo imprimir argc e ver o que está a suceder.
Mira que argc e 3, porque ten tres valores diferentes nela.
Ten o nome do programa, que ten o primeiro argumento eo segundo argumento.
Podemos imprimir os para fóra, mirando para argv [0], argv [1], e argv [2].
Entón, agora tamén se pode ver por esta chamada strcmp vai fallar,
porque ve que o fixo dividir o CS50 e as rochas en dous argumentos distintos.
Neste punto, unha vez que alcance un punto de interrupción, pode continuar a percorrer o seu programa
liña por liña, en vez de comezar o programa de novo.
Entón, se non quere comezar o seu programa de novo e só continuar a partir de aquí,
pode usar o comando siga e seguir o programa será executado ata o final.
Así como el fixo aquí.
Con todo, se eu reiniciar o programa, CS50 rochas, que bate no meu punto de interrupción de novo,
e esta vez, si eu non quero só ir ata o final o resto do programa,
Podo utilizar o comando seguinte, o que tamén abreviar con n.
E iso vai percorrer o programa liña a liña.
Así, pode ver como as cousas executar, como cambio de variables, como as cousas se actualizado.
O que é moi bo.
A outra cousa legal é, en vez de repetir o mesmo comando máis e máis e máis unha vez,
se só prema Intro - por iso aquí ve que eu non ingresaran nada -
se eu só presione Enter, que vai repetir o mando anterior,
ou o comando GDB anterior que eu só poñer dentro
Podo seguir batendo Intro e vai manter percorrendo o meu código liña por liña.
Quere fomentar vostedes para ir comprobar os programas de buggy outros tamén.
Non temos tempo para pasar por todos eles hoxe en sección.
O código fonte está alí, entón podes tipo de ver o que está a suceder
nos bastidores se queda moi preso,
pero, como mínimo, só a práctica de arrincar GDB,
a execución do programa ata que se rompe en ti,
recibindo o backtrace, descubrir cal a función do accidente estaba,
que liña era en, imprimindo uns valores variables,
só para que vostede unha idea para el, porque iso vai realmente axudar aquí para fronte.
Neste punto, nós estamos indo a saír fóra do GDB, que deixar de usar ou só q.
Se o seu programa está no medio da execución, aínda así, non foi pechado,
sempre preguntar: "Vostede está seguro de que realmente quere saír?"
Pode só bater si.
>> Agora imos ollar para o seguinte problema que temos, que é o programa de gato.
Se asistir a curta en redirixido e tubos, vai ver que Tommy usa este programa
que, basicamente, imprime toda a saída dun arquivo para a pantalla.
Entón, se eu executar gato, este é realmente un programa embutido no aparello,
e se ten Macs pode facelo no seu Mac tamén, se abrir o terminal.
E nós - gato, imos dicir, cp.c, e prema Intro.
O que este fixo, se rolar un pouco e ver onde nós corremos a liña,
ou en que executou a orde gato, literalmente impresa o contido do cp.c a nosa pantalla.
Podemos executar de novo e pode pór en varios arquivos xuntos.
Así pode facer cp.c gato, e entón tamén podemos concatenar o arquivo cat.c,
Que é o programa que estamos a piques de escribir,
e vai imprimir ambos os arquivos de volta para facer a nosa pantalla.
Entón, se rolar un pouco, vemos que, cando rodamos este cp.c gato, cat.c,
primeiro-lo impreso o arquivo CP, e despois a continuación, el imprimiu o arquivo cat.c ben aquí.
Nós imos usar isto para só peirao os pés.
Brinque con impresión sinxela á terminal, ver como é que funciona.
Se vostedes se abre con gedit cat.c, prema Intro,
podes ver o programa que estamos a piques de escribir.
Nós temos esta tarxeta de caldeira nice, polo tanto, non ten que gastar tempo escribindo todo isto.
Tamén comprobar o número de argumentos pasado dentro
Nós imprimir unha mensaxe de uso agradable.
>> Este é o tipo de cousas que, unha vez máis, como vimos falando,
é case como se a memoria muscular.
Só lembre de seguir facendo o mesmo tipo de material
e sempre imprimir algún tipo de mensaxe útil
para que as persoas saiban como realizar o seu programa.
Co gato, é moi sinxelo, só imos pasar por todos os diferentes argumentos
que foron pasadas para o noso programa, e nós estamos indo para imprimir
o seu contido para fóra da pantalla de un de cada vez.
Para imprimir arquivos para a pantalla, imos facer algo moi semellante
ao que fixemos a finais do cuestionario.
Ao final do cuestionario, que contraten programa, tivemos que abrir un arquivo,
e despois tivemos de imprimir nela.
Neste caso, imos abrir un arquivo, e imos le-lo no seu lugar.
Entón nós imos para imprimir, en vez de un arquivo, imos imprimir na pantalla.
Así, a impresión para a pantalla que todos fixemos antes con printf.
Entón, iso non é moi tolo.
Pero a lectura dun arquivo é medio raro.
Nós imos pasar por iso un pouco de cada vez.
Se vostedes volver a ese último problema no seu cuestionario, problema 33,
a primeira liña que nós imos facer aquí, abrir o ficheiro, é moi semellante ao que fixemos alí.
Entón, Stella, o que fai aquel ollar liña como, cando abrir un arquivo?
[Stella] FILE * Capital, arquivo - >> Okay. >> - É igual a fopen. >> Yup.
Que neste caso é? É no comentario.
>> É o comentario? argv [i] e R?
>> Exactamente. Certo. Entón, Stella é totalmente certo.
Isto é o que a liña parece.
Estamos indo para obter unha variable fluxo de ficheiro, almacena-lo nun FILE *, entón todas as tapas,
File, *, eo nome desta variable será de arquivo.
Poderiamos chamalo de todo o que lle gusta. Nós poderiamos chamar iso first_file ou file_i, todo o que quere.
E entón o nome do ficheiro foi pasado na liña de comandos para este programa.
Entón, é almacenado en argv [i] e, a continuación, imos abrir este ficheiro en modo lectura.
Agora que abriu o ficheiro, o que é a cousa que sempre temos que lembrar de facer
sempre que abriu un arquivo? Pecha-lo.
Entón Missy, como é que imos pechar un arquivo?
[Missy] fclose (arquivo) >> fclose (arquivo). Exactamente.
Grande. Okay. Se olharmos para este facer comentario aquí,
el di, "Open argv [i] e imprimir o seu contido á saída."
>> Stdout é un nome estraño. Saída estándar é só unha forma de dicir
queremos imprimir á terminal, queremos imprimir lo para o fluxo de saída estándar.
Podemos realmente se librar deste comentario aquí.
Eu estou indo a copia-lo enteira e pegala, xa que é o que nós fixemos.
Neste punto, agora temos que ler o ficheiro de pouco a pouco.
Nós discutir algunhas formas de lectura de arquivos.
Cales son os seus favoritos ata agora?
Que forma xa viu ou non se lembra, para ler ficheiros?
[Daniel] fread? Fread >>? Entón fread é un deles. Jimmy, coñece algún outro?
[Jimmy] Non >> Okay. Nope. Charlotte? Alexander? Outros? Okay.
Así, os outros son fgetc, é que nós imos usar moito.
Hai tamén fscanf; vostedes ver un estándar aquí?
Todos eles comezan con f. Nada que ver con un arquivo.
Hai fread, fgetc, fscanf. Estas son todas as funcións de lectura.
Para escribir temos fwrite, temos fputc vez de fgetc.
Temos tamén fprintf como vimos no cuestionario.
Unha vez que este é un problema que implica a lectura de un ficheiro,
imos usar unha desas tres funcións.
Nós non estamos indo a usar estas funcións aquí.
Estas funcións son encontradas na biblioteca de E / S por defecto.
Entón, se ollar para arriba do programa,
podes ver que xa incluído o ficheiro de cabeceira para a biblioteca de E / S por defecto.
Se queremos descubrir cal queremos usar,
podemos sempre abrir as páxinas man.
Así, podemos escribir stdio home
e ler todo sobre a entrada stdio e funcións de saída en C.
E xa podemos ver oh, mira. É mencionar fgetc, é mencionar fputc.
Así, pode afondar un pouco e ollar para, digamos, fgetc
e ollar para a súa páxina do home.
Podes ver que vai xunto con unha morea de outras funcións:
fgetc, fgets, getc, getchar, queda, ungetc, ea súa entrada de caracteres e cadeas.
Polo tanto, esta é a forma como lemos en carácteres e cadeas de ficheiros de entrada estándar,
que é, esencialmente, a partir do usuario.
E é así que facemos en C. real
Polo tanto, este non está a usar o GetString e funcións getchar
que foi utilizada dende a biblioteca de CS50.
Nós imos facer este problema nun par de formas
de xeito que se pode ver dúas formas diferentes de facelo.
Tanto a función fread que Daniel mencionado e fgetc son boas maneiras de facelo.
Eu creo que fgetc é un pouco máis fácil, porque só ten, como se ve,
un argumento, o FILE * que estamos intentando ler o personaxe,
eo seu valor de retorno é un int.
E iso é un pouco confuso, non?
>> Porque nós estamos comezando un personaxe, entón por que non o fai un retorno char?
Vostedes teñen algunha idea sobre por que isto non pode voltar un char?
[Respostas Missy, inintelixible] >> si. Entón, Missy é totalmente certo.
Se é ASCII, entón este enteiro podería ser mapeado a un carácter real.
Podería ser un carácter ASCII, e iso é certo.
Isto é exactamente o que está a suceder.
Estamos a usar un int simplemente porque ten máis bits.
É máis grande que un char, o noso carbón só 8 bits, 1 byte que nas nosas máquinas de 32 bits.
E un int ten valor todos os 4 bytes "do espazo.
E ocorre que a forma fgetc funciona,
desprazarse cara abaixo na nosa sinopse nesta páxina do manual un pouco,
percorrer todo o camiño cara a abaixo. Acontece que usan ese valor especial chamado EOF.
É unha constante especial como o valor de retorno da función fgetc
sempre que alcanzou ao final do ficheiro ou se recibir un erro.
E verifícase que para facer estas comparacións con EOF correctamente,
quere ter esa cantidade extra de información que ten un int
en vez de usar unha variable char.
Aínda que fgetc é efectivamente comezar un personaxe dun ficheiro,
quere lembrar que está retornando algo que é do tipo int para ti.
Dito isto, é moi doado de usar.
Vai dar un carácter, por iso todo o que temos que facer é continuar facendo o ficheiro,
"Deixa-me o seguinte personaxe, dáme o seguinte personaxe, dáme o seguinte personaxe",
ata chegar ao final do arquivo.
E que ha puxar un personaxe nun momento do noso arquivo,
e entón podemos facer o que quere con el.
Podemos almacena-lo, podemos engadir lo a unha corda, que pode imprimir lo.
Facer nada diso.
>> Zoom de volta e volver ao noso programa cat.c,
se imos usar fgetc,
como podemos abordar esta próxima liña de código?
Nós imos empregar - fread vai facer algo un pouco diferente.
E, nesta ocasión, imos só para usar fgetc para obter un personaxe de cada vez.
Para procesar un arquivo enteiro, o que podería temos que facer?
Cantos personaxes están aí nun arquivo?
Hai unha gran cantidade. Entón probablemente quere obter un
e despois coller outro e comezar outro e comezar outro.
Que tipo de algoritmo que pensas que pode ter que usar aquí?
Que tipo de -? [Alexander] Un loop for? >> Exactamente.
Algún tipo de lazo.
Un lazo é realmente grande, neste caso.
E como estaba dicindo, parece que quere un lazo sobre o ficheiro,
obtención dun personaxe de cada vez.
Suxestións sobre o que pode parecer?
[Alexander, inintelixible]
>> Ok, dígame en inglés o que estás a facer? [Alexander, inintelixible]
Polo tanto, neste caso, parece que estamos só tentando varrer o ficheiro.
[Alexander] Entón i > O tamaño -?
Eu creo que o tamaño do arquivo, non? O tamaño - nós só escribir así.
Tamaño do ficheiro para o momento, i + +.
Así, verifícase que a forma de facelo empregando fgetc, e iso é novo,
é que non hai ningunha forma fácil de obter só o tamaño dun ficheiro
con este "sizeof" tipo de construción que xa viu antes.
Cando usamos esa función fgetc, estamos introducindo algún tipo de
sintaxe, novo funky para este loop, onde en vez de usar só un contador básico
ir carácter por carácter, imos tirar un personaxe de cada vez,
un personaxe de cada vez, e de maneira que sabemos que estamos no fin
non é cando temos contado un determinado número de caracteres,
pero cando o personaxe que retire é ese fin específico do ficheiro de caracteres.
Así, podemos facer iso - Eu chamo iso de PC, e nós estamos indo para o arrincar
coa nosa primeira chamada para o primeiro carácter fóra do arquivo.
Entón, esa parte aquí, iso vai obter un personaxe fóra do arquivo
e almacena-lo no ch variable.
Nós imos seguir facendo iso ata chegar ao final do arquivo,
o que facemos por medio de probas para o personaxe non ser igual ao que o personaxe EOF especial.
E, a continuación, en vez de facer o ch + +, o que só aumentar o valor,
por iso, se lemos un fóra a do ficheiro, unha capital dun, digamos,
ch + + nos daría b, e entón teriamos C e D.
Isto claramente non é o que queremos. O que queremos aquí
neste último bit é que queremos obter o próximo personaxe a partir do ficheiro.
>> Entón, como podemos obter o seguinte carácter do ficheiro?
Como podemos obter o primeiro carácter do ficheiro?
[Estudante] fgetfile? Fgetc >> ou, desculpe, estaba totalmente seguro.
Eu grafada aí. Entón, si.
Aquí, en vez de facer ch + +,
Nós só estamos indo a chamar fgetc (arquivo) novo
e almacenar o resultado da nosa variable ch mesmo.
[Pregunta do estudante, inintelixible]
>> Este é o lugar onde estes faces ficheiro * son especiais.
A forma de traballar é que - cando abre por primeira vez - cando facer esa chamada fopen,
o FILE * eficazmente serve como un punteiro para o inicio do proceso.
E entón, cada vez que chamar fgetc, move-se un personaxe a través do arquivo.
Así, sempre que chama iso, está incrementando o punteiro do ficheiro por un carácter.
E cando fgetc novo, está movéndose outro personaxe
e outro personaxe e outro personaxe e outro personaxe.
[Pregunta do estudante, inintelixible] >> E isto - si.
É unha especie de esta maxia debaixo do capó.
Simplemente continúa incrementando a través.
Neste punto, vostede é capaz de realmente traballar cun personaxe.
Entón, como podemos imprimir iso para a pantalla, agora?
Podemos usar a mesma cousa printf que usan antes.
Que temos benvida a empregar todo o semestre.
Podemos chamar printf,
e podemos pasar o personaxe así.
Outra forma de facelo é en vez de usar printf e ter que facer esa secuencia de formato,
Tamén podemos utilizar unha das outras funcións.
Podemos usar fputc, que imprime un carácter para a pantalla,
excepto se olharmos para fputc - deixe-me afastar un pouco.
Vemos o que é bo é que leva no carácter que lemos, utilizando fgetc,
pero entón temos que darlle un fluxo para imprimir.
Podemos tamén usar a función putchar, que pode pór directamente saída estándar.
Polo tanto, hai unha morea de opcións diferentes que pode usar para impresión.
Eles están todos na biblioteca de E / S por defecto.
Sempre que quere imprimir - así printf, por defecto, pode imprimir a norma especial saída de fluxo,
que é a saída estándar.
Así, podemos só se refiren a el como unha especie de maxia este valor, saída estándar aquí.
Oops. Pon o punto e coma fóra.
>> Esta é unha gran cantidade de información nova, funk aquí.
Unha gran parte destas é moi idiomática, no sentido de que este é o código
que está escrito desta forma só porque é limpo de ler, fácil de ler.
Hai moitas formas diferentes de facer iso, moitas funcións diferentes que pode usar,
pero nós só tenden a seguir estes mesmos patróns máis e máis.
Polo tanto, non se Sorprende se ves un código coma este está de novo e de novo.
Todo ben. Neste punto, é preciso romper para o día.
Grazas por vir. Grazas por asistir, se está en liña. E nós imos velo na próxima semana.
[CS50.TV]