[Powered by Google Translate] [SECCIÓN 5: menos cómoda]
[Nate Hardison, Harvard University]
[Esta es CS50.] [CS50.TV]
Así que bienvenidos de nuevo, chicos.
Bienvenidos a la sección 5.
En este punto, después de haber completado prueba 0 y después de haber visto cómo se ha hecho,
esperamos que pueda sentir realmente bien porque yo estaba muy impresionado por los resultados en esta sección.
Para nuestros espectadores en línea, hemos tenido un par de preguntas
sobre los dos últimos problemas en el conjunto de problemas - o en el examen, más bien.
Así que vamos a repasar aquellos muy rápido para que todo el mundo ve lo que pasó
y la forma de ir a través de la solución real en lugar de sólo visualización de la propia solución.
Vamos a ir en el último par de problemas muy rápido, 32 y 33.
Así, de nuevo, de modo que los espectadores en línea se puede ver esto.
>> Si gira a su problema 32, que está en la página 13,
13 de los 16, 32 problema tiene que ver con swaps.
Se trataba de canje de dos números enteros.
Es el problema que habíamos ido un par de veces en la conferencia.
Y aquí, lo que estábamos pidiendo que hagan es una huella de memoria rápida.
Para rellenar los valores de las variables como lo son en la pila
ya que el código pasa a través de esta función swap.
En particular, lo que estamos viendo - Voy a poner esto iPad abajo -
en particular, lo que estamos viendo es la línea número 6 aquí.
Y es el número 6 por sólo contigüidad con el problema anterior.
Lo que quiero hacer es mostrar la etiqueta o el estado de la memoria
como lo es en el momento cuando se ejecuta este número de línea 6,
que es efectivamente un retorno de nuestra función de intercambio aquí.
Si nos desplazamos hasta aquí, hemos visto que las direcciones de todo en la memoria se ha provisto para nosotros.
Esto es muy clave, vamos a volver a ella en un momento.
Y luego aquí abajo en la parte inferior hay un diagrama de poca memoria que nos vamos a referir.
De hecho, he hecho esto en mi iPad.
Así que voy a alternar ida y vuelta entre el iPad y el código esta apenas para la referencia.
>> Vamos a empezar. En primer lugar, vamos a centrarnos en las dos primeras líneas del principal aquí.
Para empezar, vamos a inicializar x e y a 1 a 2.
Así que tenemos dos variables enteras, son a la vez va a ser colocado en la pila.
Vamos a poner un 1 y un 2 en las mismas.
Así que si le doy la vuelta a mi iPad, es de esperar, vamos a ver -
Apple TV mirroring, y ahí vamos. Bien.
Así que si le doy la vuelta a mi iPad,
Quiero inicializar x e y a 1 a 2.
Lo hacemos simplemente escribiendo un 1 en la casilla x
y un 2 en la casilla marcada y. Bastante simple.
Así que ahora vamos a volver a la computadora portátil, a ver qué sucede después.
Así que esta siguiente línea es donde las cosas se ponen difíciles.
Pasamos la dirección de x y de y la dirección como los parámetros a y b para la función swap.
La dirección de xy la dirección de y son cosas que no podemos calcular
sin hacer referencia a estos puntos de bala justo aquí abajo.
Y por suerte, los dos primeros puntos de la bala decirnos exactamente cuáles son las respuestas.
La dirección de x en la memoria es 10, y la dirección de y en la memoria es 14.
Así que estos son los valores que se transmiten en como A y B en lo alto en nuestra función de intercambio.
Así que de nuevo, volviendo a nuestro diagrama, puedo escribir un 10 en una
y un 14 en b.
Ahora, este punto es donde se procede con el canje.
Así que voltear de nuevo a la computadora portátil de nuevo,
vemos que la forma en que el intercambio de obras es que deshacer antes la referencia a y almacenar el resultado en tmp.
De modo que el operador de indirección dice: "Hey. Tratar el contenido de una variable como una dirección.
Ir a lo que está almacenado en esa dirección, y lo cargará. "
¿Qué se carga de la variable que va a ser almacenado en nuestra variable tmp.
Mover de un tirón de nuevo a la iPad.
Si vamos a abordar 10, se sabe que 10 es la dirección x varible
porque nos dijeron que nuestro punto de bala que la dirección de x en la memoria es de 10.
Así que podemos ir allí, obtener el valor de la misma, que es 1, como podemos ver en nuestro iPad,
y cargar eso en tmp.
Una vez más, esto no es el contenido final.
Vamos a caminar a través y vamos a llegar a nuestro estado final del programa al final.
Pero en este momento, tenemos el valor almacenado en una tmp.
>> Y hay una pregunta rápida por aquí.
[Alexander] Es el operador de indirección - eso es sólo el derecho asterisco al principio de la variable?
Sí >>. De modo que el operador de indirección, ya que voltear hacia atrás para nuestro portátil, una vez más,
es esta estrella justo en frente.
En ese sentido, es - lo que contrasta con el operador de multiplicación
que requiere dos cosas: el operador de indirección es un operador unario.
Sólo se aplica a un valor en lugar de un operador binario,
donde se aplica a dos valores diferentes.
Así que eso es lo que sucede en esta línea.
Cargamos el valor 1 y se almacena en la variable temporal entero.
La siguiente línea, se almacena el contenido de b en -
o, más bien, guardamos los contenidos que se señalan a b en el lugar donde una está apuntando.
Si analizamos este de derecha a izquierda, vamos a eliminar la referencia b,
vamos a abordar 14, vamos a agarrar el entero que está allí,
y luego vamos a ir a la dirección 10,
y vamos a lanzar el resultado de eliminar la referencia de b en ese espacio.
Volteando a nuestro iPad, donde podemos hacer esto un poco más concreto,
puede ser que ayude si escribo números en todas las direcciones aquí.
Así que sabemos que en y, estamos en la dirección 14, x está en la dirección 10.
Cuando empezamos a b, b dereference, vamos a tomar el valor 2.
Vamos a coger este valor debido a que es el valor que vive en la dirección 14.
Y vamos a ponerlo en la variable que vive en la dirección 10,
que está ahí, que corresponde a nuestros variable x.
Así que podemos hacer un poco de sobrescribir aquí
donde nos deshacemos de nuestra 1 y en su lugar escribir un 2.
Así que todo está bien y es bueno en el mundo, a pesar de que hemos x sobrescritos ahora.
Hemos almacenado antiguo valor de x en la variable tmp.
Así podemos completar el intercambio con la línea siguiente.
Mover de un tirón de nuevo a nuestro portátil.
Ahora todo lo que queda es tomar el contenido de nuestra variable entera temporal
y los almacena en la variable que vive en la dirección que b está sosteniendo.
Así que vamos a eliminar la referencia b eficaz para conseguir el acceso a la variable
es decir, en la dirección que b tiene en él,
y vamos a meter el valor que está llevando a cabo tmp en ella.
Voltear de nuevo al iPad una vez más.
Puedo borrar este valor aquí, 2,
y en su lugar vamos a copiar la derecha 1 en él.
A continuación, la siguiente línea que se ejecuta, por supuesto -
si tiramos de nuevo a la computadora portátil - es este el punto 6,
que es el punto en el que queríamos tener nuestro diagrama llenada completamente.
Así que voltear de nuevo al iPad una vez más, sólo para que pueda ver el diagrama completo,
se puede ver que tenemos un 10 en una, un 14 en b, a 1 en tmp, un 2 en x, y un 1 en y.
¿Hay alguna pregunta acerca de esto?
¿Esto tiene más sentido, de haber caminado a través de él?
Hacer menos sentido? Esperemos que no. Bien.
>> Los punteros son un tema muy delicado.
Uno de los chicos con los que trabajamos tiene un dicho muy común:
"Para entender los punteros, primero hay que entender punteros".
Lo que creo que es muy cierto. Sin embargo, toma algún tiempo para acostumbrarse a ella.
Dibujo muchas fotos, sorteo de diagramas de memoria como ésta son muy útiles,
y después de caminar a través del ejemplo tras ejemplo tras ejemplo,
que va a empezar a tener sentido un poco más y un poco más de sentido y un poco más de sentido.
Finalmente, un día, tendrás todo completamente dominado.
Cualquier pregunta antes de pasar al siguiente problema? Está bien.
Así que dar la vuelta de nuevo a la computadora portátil.
El siguiente problema que tenemos es el problema número 33 en el archivo I / O.
Zoom sobre esto un poco.
Problema 33 - ¿Sí?
>> [Daniel] Acabo de tener una pregunta rápida. Esta estrella, o el asterisco,
se llama eliminación de referencias cuando se utiliza un asterisco antes.
¿Cómo se llama cuando se utiliza el signo & antes?
>> El signo & antes es el operador de dirección.
Así que vamos a pasar de regreso.
Oops. Estoy en el modo de zoom, así que no puede desplazarse.
Si nos fijamos en el código muy rápido aquí,
de nuevo, lo mismo sucedía.
Si nos fijamos en el código aquí mismo, en esta línea donde hacemos el llamado a cambiar,
el signo es sólo decir "obtener la dirección en que vive la variable x."
Cuando el compilador compila el código,
tiene que físicamente marcar un lugar en la memoria para todas sus variables para vivir.
Y así, lo que el compilador puede hacer una vez que se compila todo,
lo sabe "Oh, puse x en la dirección 10. Pongo y en la dirección 14."
A continuación, puede rellenar estos valores para usted.
Así que usted puede - puede entonces pasar esto y pass & y adentro también.
Estos chicos obtener la dirección, sino que también, cuando se pasa a la función de intercambio,
este tipo de información, esta * int aquí, le dice al compilador,
"Está bien, vamos a estar interpretando esta dirección como una dirección de una variable entera".
Como una dirección de un entero, que es diferente de la dirección de una variable de carácter
porque un int ocupa, en una máquina de 32-bit, toma hasta 4 bytes de espacio,
mientras que un personaje sólo ocupa 1 byte de espacio.
Así que es importante saber también lo que es - lo que vive, qué tipo de valor
vive en la dirección que he pasado pulg
O la dirección que usted está tratando.
De esa manera, usted sabe cuántos bytes de información para cargar realidad de la memoria RAM.
Y entonces, sí, este operador para deshacer referencias, como si estuvieras pidiendo,
va y se accede a la información en una dirección particular.
Por lo que dice, con esta variable a aquí, tratar los contenidos de una como dirección,
ir a esa dirección, y extraer, cargar en el procesador, la carga en un registro
los valores reales o de los contenidos que viven en ese domicilio.
Algo más preguntas? Estas son buenas preguntas.
Es un montón de nueva terminología también.
Es también una especie de funky, y viendo * y en diferentes lugares.
>> Está bien.
Así que volvemos al problema de 33 años, presentar I / O.
Este fue uno de esos problemas que creo que un par de cosas sucedieron.
Uno, que es un tema bastante nuevo.
Se presentó muy pronto antes de la prueba,
y entonces yo creo que fue algo así como uno de esos problemas verbales de matemáticas
donde te dan un montón de información, pero en realidad no terminan encima de tener que usar un montón de él.
La primera parte de este problema se describe qué es un archivo CSV.
Ahora, un archivo CSV, de acuerdo con la descripción, es un archivo de valores separados por comas.
La razón de que estos son para nada interesante, y la razón por la que nunca los utilizan,
Es decir, porque, ¿cuántos de ustedes han utilizado alguna vez cosas como Excel?
Figura mayoría de ustedes, probablemente, o va a utilizar en algún momento de su vida.
Vamos a usar algo como Excel.
Con el fin de obtener los datos de una hoja de cálculo de Excel o hacer cualquier tipo de tratamiento efectuado con ella,
si quieres escribir un programa en C o programa en Python, un programa Java,
para hacer frente a los datos que haya almacenado ahí,
una de las formas más comunes para sacarlo está en un archivo CSV.
Y usted puede abrir Excel y cuando vas a la opción 'Guardar como' diálogo,
usted puede salir un archivo CSV real.
>> Es útil saber cómo lidiar con estas cosas.
La forma en que funciona es que es similar a - Quiero decir, es esencialmente imitando una hoja de cálculo,
donde, como vemos aquí, en la parte más a la izquierda,
tenemos todos los apellidos.
Así que tenemos Malan, a continuación, Hardison, y luego Bowden, MacWilliam, y luego Chan.
Todos los apellidos. Y luego una coma separa los apellidos de los nombres de pila.
David, Nate, Rob, Tommy, y Zamyla.
Siempre mezclar Robby y Tom.
Y entonces, por fin, la tercera columna es la dirección de correo electrónico.
Una vez que entiendas eso, el resto del programa es bastante sencillo de implementar.
Lo que hemos hecho con el fin de imitar la estructura misma de nuestro programa en C
es que hemos utilizado una estructura.
Vamos a empezar a jugar con ellos un poco más también.
Los vimos en el primer pedacito pequeño problema en el conjunto 3, cuando se trataba de los diccionarios.
Pero esta estructura personal almacena un apellido, un nombre, y un correo electrónico.
Al igual que nuestro archivo CSV estaba almacenando.
Así que esto es sólo la conversión de un formato a otro.
Tenemos que convertir, en este caso, una estructura personal en una línea,
una línea separada por comas, así como así.
¿Eso tiene sentido? Ustedes han tomado el examen,
así que me imagino que por lo menos han tenido tiempo para pensar en esto.
>> En la función de contratación, el problema pide que tomemos en - nos volveremos a ampliar esto un poco poco -
tomar en una estructura de personal, una estructura de personal, con el nombre de s,
y añadir su contenido a nuestro archivo staff.csv.
Resulta que este es bastante sencillo de usar.
Vamos a clase de jugar con estas funciones un poco más hoy en día.
Pero en este caso, la función fprintf es realmente la clave.
Así que con fprintf, podemos imprimir, al igual que ustedes han estado usando printf este término entero.
Puede printf una línea en un archivo.
Así que en lugar de sólo hacer la llamada printf habitual donde se le da la cadena de formato
y luego cambia todas las variables con los siguientes argumentos,
con fprintf, su primer argumento es en cambio el archivo que desea escribir.
Si fuéramos a ver esto en el aparato, por ejemplo, el hombre fprintf,
podemos ver la diferencia entre printf y fprintf.
Voy a ampliar aquí un poco.
Así que con printf, le damos una cadena de formato y, a continuación los argumentos posteriores
son todas las variables para el reemplazo o sustitución en nuestra cadena de formato.
Mientras que con fprintf, el primer argumento es precisamente esta * archivo llamado un arroyo.
>> Volviendo aquí a nuestros contratos de alquiler,
ya tenemos nuestro flujo * archivo abierto para nosotros.
Eso es lo primero que hace esta línea, se abre el archivo staff.csv,
lo abre en modo append, y es todo lo que nos queda por hacer
escribir la estructura de la plantilla en el archivo.
Y, vamos a ver, ¿me quieres usar el iPad?
Voy a utilizar el iPad. Tenemos vacío - Vamos a poner esto sobre la mesa para que yo pueda escribir un poco mejor -
anular el alquiler y que se necesita en un argumento, una estructura de personal llamado s.
Got nuestras llaves, tenemos nuestro archivo llamado * archivo,
tenemos nuestra línea fopen dado a nosotros,
y yo sólo voy a escribir en forma de puntos, ya que ya está en el pedia.
Y luego, en nuestra línea siguiente, vamos a hacer una llamada a fprintf
y vamos a pasar en el archivo que desea imprimir,
y luego nuestro formato de cadena, que -
Voy a dejar que ustedes me dicen lo que parece.
¿Y tú, Stella? ¿Sabes lo que la primera parte de la cadena de formato se parece?
[Stella] Yo no estoy seguro. >> No dude en preguntar Jimmy.
¿Sabe usted, Jimmy?
[Jimmy] ¿Podría ser sólo pasado? No se. No estoy del todo seguro.
>> Okay. ¿Qué tal, ¿alguien obtener esta correcto en el examen?
No. Está bien.
Resulta que aquí lo único que tenemos que hacer es que queremos que cada parte de nuestra estructura de personal
para ser impreso como una cadena en nuestro archivo.
Nos limitamos a usar el personaje de sustitución de cadenas en tres ocasiones diferentes, porque tenemos un apellido
seguido de coma, luego de un primer nombre seguido de una coma,
y, finalmente, la dirección de correo electrónico que es seguido - que no es
montar en mi pantalla - pero es seguido por un carácter de nueva línea.
Así que voy a escribir justo ahí abajo.
Y luego, después de nuestra cadena de formato,
sólo tenemos las sustituciones, que se accede mediante la notación de puntos
que vimos en el boletín de problemas 3.
Podemos utilizar s.last, s.first y s.email
para sustituir en esos tres valores en nuestra cadena de formato.
Entonces, ¿cómo te fue? Tiene sentido?
¿Sí? No? Posiblemente? Bien.
>> La última cosa que hacemos después de haber impreso y después de que hemos abierto nuestro archivo:
cada vez que hemos abierto un archivo, siempre tenemos que recordar para cerrarla.
Porque de lo contrario vamos a terminar la filtración de la memoria,
utilizando hasta descriptores de fichero.
Así que para cerrar, que funcionan usamos? Daniel?
[Daniel] fclose? >> Fclose, exactamente.
Así que la última parte de este problema consistía en cerrar correctamente el archivo, utilizando la función fclose,
que sólo se parece a eso.
No está loco.
Cool.
Así que eso es problema 33 en el concurso.
Tendremos archivo definitivamente más I / O viene.
Vamos a hacer un poco más en la conferencia de hoy, o en la sección de hoy,
porque eso es lo que va a constituir la mayor parte de este conjunto de procesadores próximo.
Vamos a pasar de la prueba en este punto. ¿Sí?
>> [Charlotte]] ¿Por qué fclose (archivo) en vez de fclose (staff.csv)?
>> Ah. Porque resulta que - por lo que la pregunta, que es un grande,
Por eso, cuando escribimos fclose, ¿estamos escribiendo fclose (archivo) estrella variable
en contraposición al nombre de archivo, staff.csv? ¿Es eso correcto? Si.
Así que vamos a echar un vistazo. Si vuelvo a mi ordenador portátil,
y echemos un vistazo a la función fclose.
Así que la función fclose cierra un arroyo y que se necesita en el puntero al flujo que queremos cerrar,
en comparación con el nombre real del archivo que desea cerrar.
Y es que detrás de las escenas, cuando usted hace una llamada a fopen,
cuando se abre un archivo, en realidad estás asignación de memoria para almacenar la información sobre el archivo.
Así que tienes puntero del archivo que contiene información sobre el archivo,
tal como está abierto, su tamaño, en la que se encuentran actualmente en el archivo,
de modo que usted puede hacer que la lectura y la escritura llamadas a ese lugar en particular dentro del archivo.
Se termina de cerrar el puntero en lugar de cerrar el nombre del archivo.
>> ¿Sí? [Daniel] Así que con el fin de utilizar de alquiler, ¿diría usted - ¿cómo obtener la entrada del usuario?
¿Tiene fprintf actuar como GetString en el sentido de que sólo voy a esperar a que la entrada del usuario
y le pedirá que escriba esto - o esperar a que escriba estas tres cosas?
¿O es necesario utilizar algo de implementar alquiler?
Sí >>. Así que no estamos - la pregunta fue, ¿cómo hacemos para que la entrada del usuario
con el fin de implementar alquiler? Y lo que tenemos aquí es el llamador de alquiler,
aprobada en esta estructura personal con todos los datos almacenados en la estructura ya.
Así fprintf es capaz de escribir sólo los datos directamente en el archivo.
No es necesario esperar a que el usuario.
El usuario ya está dado por la entrada correctamente poniendo en esta estructura de personal.
Y las cosas, por supuesto, se rompería si alguno de los punteros eran nulas,
por lo que desplazarse de nuevo hasta aquí y nos fijamos en nuestra estructura.
Tenemos string apellido, nombre, dirección de correo electrónico cadena.
Ahora sabemos que todos los que en realidad, bajo el capó, son variables char *.
Que puede o no puede estar apuntando a null.
Pueden estar apuntando a la memoria en el montón,
tal memoria en la pila.
Realmente no lo sé, pero, si alguno de estos indicadores es nulo o no válido
que que definitivamente va a estrellar nuestra función de contratación.
Eso era algo que estaba un poco más allá del alcance del examen.
No vamos a tener que preocuparse por eso.
Grande. Bien. Así que pasar de la prueba.
>> Vamos a cerrar este tipo, y vamos a ver pset 4.
Así que si ustedes mirar las especificaciones conjunto de procesadores, una vez que se puede acceder a ella, cs50.net/quizzes,
vamos a ir a través de algunos de los problemas de la sección actual.
Estoy desplazamiento hacia abajo - sección de preguntas comienza en la tercera página de la especificación de conjunto de procesadores.
Y lo primero que pide para ir a ver el corto en la reorientación y tuberías.
Lo cual era una especie de fresco a corto, te muestra algunos trucos nuevos, frescos línea de comandos que se pueden utilizar.
Y luego tenemos algunas preguntas para usted también.
Esta primera pregunta acerca de los arroyos, para que printf escribe de forma predeterminada,
que tipo de tocado un poco hace un momento.
Esta fprintf que estábamos discutiendo toma en un arroyo archivo * como argumento.
fclose toma en un flujo de archivo *, así,
y el valor devuelto por fopen le da una corriente * archivo también.
La razón por la que no hemos visto antes, cuando los hemos tratado con printf
es porque printf tiene una secuencia predeterminada.
Y la corriente de defecto a los que se escribe
podrás conocer en el corto plazo.
Así que definitivamente echar un vistazo.
>> En la sección de hoy, vamos a hablar un poco acerca de GDB,
ya que cuanto más familiarizado esté con él, la práctica más que se obtiene con ella,
el mejor preparado estará para cazar a los insectos en realidad en su propio código.
Esto acelera el proceso de depuración tremendamente.
Así mediante el uso de printf, cada vez que haces eso tienes que volver a compilar el código,
tienes que correr de nuevo, a veces hay que mover la llamada printf alrededor,
comentar código, sólo se necesita un tiempo.
Nuestro objetivo es tratar de convencerlos de que con GDB, usted puede esencialmente
printf nada en cualquier punto de su código y usted nunca tendrá que volver a compilar.
Usted nunca tiene que iniciar y mantener adivinando dónde printf siguiente.
Lo primero que debe hacer es copiar esta línea y obtener el código de sección de la web.
Estoy copiando esta línea de código que dice: "http://cdn.cs50.net wget".
Yo lo voy a copiar.
Voy a ir a mi aparato, alejar para que pueda ver lo que estoy haciendo,
pegarlo allí, y cuando pulse la tecla Enter, este comando wget literalmente es una web conseguirlo.
Va a bajar el archivo fuera de la Internet,
y va a guardarlo en el directorio actual.
Ahora bien, si enumero mi directorio actual se puede ver que tengo el archivo section5.zip bien ahí.
La manera de tratar con ese tipo es que descomprimirlo,
que se puede hacer en la línea de comandos, al igual que este.
Section5.zip.
Eso lo descomprima, cree la carpeta para mí,
inflar todo el contenido, los puso allí.
Así que ahora puedo ir a mi sección 5 directorio con el comando cd.
Limpiar la pantalla con clara. Así que limpiar la pantalla.
Ahora tengo un terminal limpio y agradable de manejar.
>> Ahora bien, si una lista de todos los archivos que aparecen en este directorio,
veis que yo tengo cuatro archivos: buggy1, buggy2, buggy3 y buggy4.
También tengo los archivos de C correspondiente..
No vamos a mirar los archivos. C por ahora.
En su lugar, vamos a usarlas cuando abrimos GDB.
Nos hemos mantenido en torno a lo que tenemos acceso al código fuente real cuando estamos usando GDB,
pero el objetivo de esta parte de la sección es juguetear un poco con GDB
y ver cómo podemos utilizarlo para averiguar lo que va mal con cada uno de estos cuatro programas con errores.
Así que sólo vamos a por el cuarto muy rápido,
y yo voy a pedir a alguien para ejecutar uno de los programas con errores,
y luego vamos a ir como un grupo a través del BGF, y vamos a ver qué podemos hacer para arreglar estos programas,
o identificar al menos lo que va mal en cada uno de ellos.
Vamos a empezar por aquí con Daniel. ¿Va a correr buggy1? Vamos a ver qué pasa.
[Daniel] Se dice que hay un error de aplicación. Sí >>. Exactamente.
Así que si me quedo buggy1, me sale un error seg.
En este punto, yo podría ir y abrir buggy1.c,
tratar de averiguar lo que va mal,
pero una de las cosas más desagradables acerca de este error de errores seg
es que no te dice en qué línea del programa de las cosas realmente salió mal y se rompió.
De alguna manera tenemos que mirar el código
y averiguar mediante conjeturas y comprobar o printf para ver lo que va mal.
Una de las mejores cosas acerca de GDB es que es muy, muy fácil
para averiguar la línea a la que el programa se bloquea.
Está totalmente digno de él para usarlo, aunque sólo sea por eso.
Así que para arrancar GDB, tipo I GDB, y luego le doy la ruta de acceso al archivo ejecutable que desea ejecutar.
Aquí estoy escribiendo gdb ./buggy1.
Pulse Enter. Me da toda esta información de derechos de autor,
y aquí usted verá esta línea que dice: "Lectura de símbolos / home /
jharvard/section5/buggy1 ".
Y si todo va bien, verás que imprima un mensaje parecido a éste.
Se va a leer los símbolos, que va a decir "Estoy leyendo los símbolos de su archivo ejecutable"
y entonces tendrá este "hecho" mensaje aquí.
Si ves alguna otra variante de esto, o ver que no podía encontrar los símbolos
o algo por el estilo, lo que quiere decir es que usted no haya compilado su ejecutable correctamente.
Al compilar programas para su uso con GDB, tenemos que usar esa bandera especial-g,
y eso se hace por defecto si compila los programas, simplemente tecleando make
o hacer buggy o hacer recuperar, nada de eso.
Pero si estás compilando manualmente con Clang, entonces usted tendrá que ir y que incluyen-g.
>> En este punto, ahora que tenemos nuestro GDB del sistema,
que es muy simple de ejecutar el programa.
Podemos escribir run, o simplemente podemos escribir r.
La mayoría de los comandos de GDB puede ser abreviado.
Por lo general, a sólo una o unas letras de un par, lo cual es bastante agradable.
Así Saad, si escribe r y presione Enter, ¿qué pasa?
[Saad] Tengo SIGSEGV, fallo de segmentación, y entonces todo este galimatías.
Sí >>.
Como estamos viendo en la pantalla en este momento, y como dijo Saad,
cuando tecleamos carrera o r y pulse la tecla Enter, se sigue recibiendo el mismo error seg.
Así que usando GDB no resuelve nuestro problema.
Pero nos da una jerigonza, y resulta que esta jerigonza
en realidad nos dice dónde está sucediendo.
Para analizar esto un poco, este primer bit es la función en la que todo va mal.
Hay un __ strcmp_sse4_2, y nos dice que está sucediendo en este archivo
llamado sysdeps/i386, todo esto, de nuevo, una especie de desastre - pero la línea 254.
Eso es un poco difícil de analizar. Normalmente, cuando ves cosas como esta,
que significa que está seg con error en una de las bibliotecas del sistema.
Así que algo que ver con strcmp. Ustedes han visto strcmp antes.
No está loco, pero ¿significa esto que strcmp está roto o que hay un problema con strcmp?
¿Qué te parece, Alejandro?
[Alexander] ¿Es que - es de 254 la línea? Y - no el binario, pero no es sus techos,
y luego hay otro idioma para cada función. ¿Eso es 254 en esa función, o -?
>> Es la línea 254. Parece que en este archivo. S, por lo que es probable que el código ensamblador.
>> Sin embargo, creo que la cosa más urgente es, porque hemos conseguido un fallo seg,
y parece como si viniera de la función strcmp,
Qué implica esto, entonces, que strcmp se rompe?
No debería, esperanzado. Así que sólo porque usted tiene un fallo de segmentación
en una de las funciones del sistema, por lo general eso significa que no lo han llamado correctamente.
La forma más rápida que se puede hacer para averiguar lo que realmente está pasando
cuando ves algo loco como este, cada vez que vea una falla seg,
especialmente si usted tiene un programa que está utilizando más que principal,
es utilizar un backtrace.
I abreviar backtrace por escrito bt, en oposición a la palabra traza completa.
Pero Charlotte, lo que ocurre cuando se escribe bt y pulse Enter?
[Charlotte] Me muestra dos líneas, la línea 0 y la línea 1.
Sí >>. Así que la línea 0 y la línea 1.
Estos son los marcos de pila reales que están actualmente en juego cuando el programa se estrelló.
A partir del marco superior, el marco 0, e ir a la parte inferior más, que es el cuadro 1.
Nuestro marco superior es el marco strcmp.
Usted puede pensar en esto como similar al problema que estábamos haciendo en el concurso con los punteros,
donde habíamos intercambiar marco de pila en la parte superior del marco de pila principal,
y tuvimos las variables que se utilizan swaps en la parte superior de las variables que se utilizan principal.
Aquí nuestro accidente ocurrió en nuestra función strcmp, que fue llamado por nuestra función principal,
y backtrace nos está dando no sólo las funciones en que las cosas fallidas,
pero también se nos dice que todo fue llamado.
Así que si me desplazo en un poco más a la derecha,
podemos ver que sí, que estábamos en la línea 254 de este archivo strcmp-sse4.s.
Pero la llamada se hizo en buggy1.c, línea 6.
Así que eso significa que podemos hacer - es simplemente podemos ir a ver hacia fuera y ver lo que estaba pasando
en buggy1.c, línea 6.
Una vez más, hay un par de maneras de hacer esto. Uno es para salir del GDB
o tiene su código abierto en otra ventana y referencia cruzada.
Eso, en sí mismo, es bastante útil porque ahora si usted está en horario de oficina
y usted tiene una falla seg y su TF está preguntando donde todo se rompía,
usted puede decir: "Oh, la línea 6. No sé lo que está pasando,
pero algo en la línea 6 está causando mi programa de romper. "
La otra manera de hacerlo es que usted puede utilizar este comando llamado de lista en GDB.
También se puede abreviar con l.
Así que si llegamos a l, ¿qué hacemos aquí?
Tenemos un montón de cosas raras.
Este es el código ensamblador real
que es en strcmp_sse4_2.
Esto parece un poco funky,
y la razón por la que estamos recibiendo es porque en este momento,
GDB nos tiene en el marco 0.
>> Así que en cualquier momento nos fijamos en las variables, en cualquier momento nos fijamos en el código fuente,
estamos viendo el código fuente que pertenece al marco de pila que se encuentra,
Así que para conseguir algo significativo, tenemos que
pasar a un marco de pila que tiene más sentido.
En este caso, el marco de pila principal tendría sentido un poco más,
porque ese era realmente el código que nosotros escribimos.
No es el código strcmp.
La forma en que se puede mover entre los cuadros, en este caso, porque tenemos dos,
tenemos 0 y 1,
lo hace con el arriba y abajo los comandos.
Si me mudo a un fotograma,
ahora estoy en el marco de la pila principal.
Me puedo mover hacia abajo para volver a donde estaba,
subir de nuevo, volver a bajar, y subir de nuevo.
Si vuelves a hacer su programa en GDB, se obtiene un accidente, se obtiene la traza de depuración,
y se ve que está en algún archivo que usted no sabe lo que está pasando.
Intenta lista, el código no se ve familiar,
echar un vistazo a sus cuadros y averiguar dónde se encuentra.
Usted está probablemente en el marco de pila incorrecta.
O por lo menos usted está en un marco de pila que no es la que realmente se puede depurar.
Ahora que estamos en el marco de pila apropiado, estamos en el principal,
Ahora podemos usar el comando list para averiguar lo que la línea era.
Y usted puede ver, sino que lo imprimió para nosotros aquí.
Pero podemos llegar a una lista de todo lo mismo, y la lista nos da esta impresión agradable
del código fuente real que está pasando aquí.
>> En particular, podemos mirar a la línea 6.
Podemos ver lo que está pasando aquí.
Y parece que estamos haciendo una comparación de cadenas
entre la cadena "CS50" y rocas argv [1].
Algo de esto se caiga.
Así Missy, ¿tiene usted alguna idea sobre lo que podría estar pasando aquí?
[Missy] No sé por qué está fallando. >> No sé por qué está rompiendo?
Jimmy, alguna idea?
[Jimmy] No estoy del todo seguro, pero comparar la última vez que se utilizó cadena,
o strcmp, teníamos como tres casos diferentes bajo el mismo.
No teníamos un ==, no creo que, justo en esa primera línea.
En su lugar, se dividió en tres, y uno era == 0,
uno era <0, creo, y uno fue> 0.
Así que tal vez algo así? Sí >>. Así que esta cuestión
de que estamos haciendo la comparación correcta?
Stella? ¿Alguna idea?
[Stella] Yo no estoy seguro. >> No estoy seguro. Daniel? Pensamientos? Bien.
Resulta que lo que está sucediendo aquí es cuando nos encontramos con el programa
y nos dieron la culpa seg, al ejecutar el programa por primera vez, Daniel,
se le dan los argumentos de línea de comandos?
[Daniel] >> No. No. En ese caso, ¿cuál es el valor de argv [1]?
>> No hay ningún valor. >> Derecho.
Bueno, no hay ningún valor de cadena apropiado.
Pero hay algo de valor. ¿Cuál es el valor que se almacena allí?
>> Un valor basura? >> Es un valor basura o, en este caso,
el final de la matriz argv siempre termina con null.
Entonces, ¿qué he guardado allí es nulo.
La otra manera de resolver esto, en lugar de pensar a través,
es tratar de imprimir.
Aquí es donde me estaba diciendo que el uso de GDB es grande,
porque usted puede imprimir todas las variables, todos los valores que desea
utilizar este comando práctico-excelente p.
Así que si teclea p y luego escriba el valor de una variable o el nombre de una variable,
decir, argc, veo que argc es 1.
Si desea imprimir argv [0], puedo hacerlo sin más.
Y como hemos visto, argv [0] es siempre el nombre de su programa,
siempre el nombre del ejecutable.
Aquí se ve que tiene el nombre de ruta completo.
También puede imprimir argv [1] y ver qué pasa.
>> Aquí tenemos a este tipo de valor místico.
Conseguimos este 0x0.
Recuerde que al comienzo de la legislatura, cuando hablamos de números hexadecimales?
O que pocas dudas al final del conjunto de procesadores 0 sobre cómo representar 50 en hexadecimal?
La forma de escribir los números hexadecimales de CS, no sólo a nosotros mismos confundir
con números decimales, es que siempre les prefijo 0x.
Así que este prefijo 0x siempre sólo significa interpretar el siguiente número como un número hexadecimal,
no como una cadena, no como un número decimal, no como un número binario.
Puesto que el número 5-0 es un número válido en hexadecimal.
Y es un número en decimal, 50.
Así que esto es sólo la forma en que eliminar la ambigüedad.
Así 0x0 medio hexadecimal 0, lo cual también es decimal, binario 0 0.
Es sólo el valor 0.
Resulta que esto es lo nula es, en realidad, en la memoria.
Null es 0.
Aquí, el elemento almacenado en argv [1] es nulo.
Así que estamos tratando de comparar nuestro "CS50 rocks" cadena en una cadena nula.
Así desreferencia nula, intentando tener acceso a las cosas en null,
los que normalmente se va a producir algún tipo de fallo de segmentación o de otras cosas malas sucedan.
Y resulta que strcmp no comprueba para ver
si usted ha pasado en un valor que es nulo.
Por el contrario, sólo sigue adelante, trata de hacer lo suyo,
y si seg faltas, seg faltas, y es tu problema. Tienes que ir a arreglarlo.
Muy rápidamente, ¿cómo podemos solucionar este problema? Charlotte?
[Charlotte] Puede comprobar si el uso.
Así que si argv [1] es nulo, == 0, entonces devolver 1, o algo así [ininteligible].
Sí >>. Así que esa es una buena manera de hacerlo, como podemos comprobar,
el valor que está a punto de pasar a strcmp, argv [1], se lo nulo?
Si es nulo, entonces podemos decir que está bien, abortar.
>> Una forma más común de hacer esto es utilizar el valor de argc.
Se puede ver aquí en el comienzo de principal,
omitimos que la primera prueba que solemos hacer cuando usamos argumentos de línea de comandos,
que es para probar si nuestro valor de argc es lo que esperamos.
En este caso, estamos esperando por lo menos dos argumentos,
el nombre del programa más el otro.
Debido a que estamos a punto de usar el segundo argumento aquí.
Así que tener algún tipo de prueba de antemano, antes de nuestra llamada strcmp
que las pruebas sean o no argv es al menos 2, también podría hacer el mismo tipo de cosas.
Podemos ver si eso funciona, ejecute el programa de nuevo.
Siempre se puede reiniciar el programa dentro de GDB, que es realmente bonita.
Se puede correr, y cuando se pasa argumentos a su programa,
los pases en cuando se llama a correr, no al arrancar GDB.
De esa manera usted puede mantener invocando el programa con argumentos diferentes cada vez.
Corred de tal manera o otra vez, puedo escribir r, y vamos a ver qué pasa si escribimos "hola".
Siempre se te preguntará si quieres empezar desde el principio otra vez.
Por lo general, lo quiero empezar desde el principio otra vez.
Y en este punto, se reinicia de nuevo, imprime
el programa que se está ejecutando, buggy1, con el argumento hola,
e imprime esta salida estándar, sino que dice: "Usted recibe una D," cara triste.
Pero no nos falla seg. Se dijo que el proceso terminó normalmente.
Así que se ve muy bien.
No más culpa seg, lo hemos hecho pasado,
por lo que parece que era de hecho el error seg culpa que nos iban a dar.
Por desgracia, nos dice que estamos llegando a una D.
>> Podemos volver atrás y mirar el código y ver lo que estaba pasando allí
para averiguar lo que era - por qué se nos está diciendo que tenemos una D.
Vamos a ver, aquí se esta printf diciendo que tienes una D.
Si tecleamos lista, que se mantenga la lista escribiendo, sigue iterando a través de su programa,
por lo que voy a mostrar las primeras líneas de su programa.
A continuación, le mostraremos las próximas líneas, y el trozo siguiente, y el siguiente trozo.
Y va a seguir tratando de bajar.
Y ahora vamos a llegar a "alinear el número 16 está fuera de alcance".
Debido a que sólo cuenta con 15 líneas.
Si se llega a este punto, y su pregunta: "¿Qué debo hacer?" puede utilizar el comando help.
Utilice ayudar y luego darle el nombre de un comando.
Y ves el BGF nos da todo este tipo de cosas.
Dice: "Sin un argumento, una lista de diez líneas o más, después de todo el listado anterior.
Lista - lista las diez líneas antes - "
Así que vamos a tratar de usar menos de la lista.
Y que las listas de las 10 líneas anteriores, se puede jugar con la lista un poco.
Usted puede hacer la lista, lista -, incluso se puede dar una lista de un número, como lista 8,
y que va a enumerar las 10 líneas en torno a la línea 8.
Y usted puede ver lo que está pasando aquí es que tienes un simple if else.
Si escribe en CS50 rocas, imprime "Se obtiene un sobresaliente"
De lo contrario, se imprime "Se obtiene una D."
Bummer ciudad. Está bien. ¿Sí?
>> [Daniel] Así que cuando he intentado hacer CS50 rocas sin las comillas,
dice "Te dan una D."
Necesitaba las comillas para conseguir que funcione, ¿por qué es eso?
Sí >>. Resulta que cuando - este es otro dato poco divertido -
al ejecutar el programa, si lo ejecutamos y nos escribe en CS50 rocas,
al igual que Daniel estaba diciendo que él hizo, y pulsar Intro,
todavía dice que obtenemos una D.
Y la pregunta es, ¿por qué es esto?
Y resulta que tanto nuestro terminal y GDB analizar estos como dos argumentos distintos.
Porque cuando hay un espacio, que está implicado como
el primer argumento terminó, el siguiente argumento está a punto de comenzar.
La forma de combinar los dos en, o perdón, en un argumento,
es el uso de las comillas.
Así que ahora, si lo ponemos entre comillas y ejecutarlo de nuevo, obtenemos una A.
Así que para recapitular, sin comillas, CS50 y las rocas son interpretadas como dos argumentos distintos.
Con las cotizaciones, se analiza como un argumento completo.
>> Podemos ver esto con un punto de interrupción.
Hasta ahora hemos estado funcionando nuestro programa, y ​​que se está ejecutando ha
hasta que lo seg fallas o éxitos de un error
o hasta que haya salido y todo ha sido totalmente bien.
Esto no es necesariamente lo más útil, porque a veces
tiene un error en su programa, pero no es la causa de un fallo de segmentación.
No es la causa de su programa para detener o algo así.
La manera de conseguir GDB para detener su programa en un punto particular
es establecer un punto de interrupción.
Usted puede hacer esto mediante el establecimiento de un punto de interrupción en un nombre de función
o puede establecer un punto de interrupción en una línea de código en particular.
Me gustaría establecer puntos de interrupción en los nombres de funciones, porque - fácil de recordar,
y si usted realmente entrar y cambiar el código fuente un poco,
entonces el punto de interrupción que se aloja en el mismo lugar dentro de su código.
Mientras que si usted está utilizando los números de línea, y cambiar los números de línea
porque agrega o elimina algo de código, a continuación, sus puntos de ruptura están totalmente jodido.
Una de las cosas más comunes que hacen es establecer un punto de interrupción en la función principal.
A menudo voy a arrancar GDB, voy a escribir b principal, pulse Enter, y que va a establecer un punto de interrupción
la función principal, que simplemente dice, "Pausa el programa tan pronto como empiece a correr"
y de esa manera, cuando ejecuto mi programa con, digamos, CS50 rocas como dos argumentos
y pulse la tecla Enter, se vuelve a la función principal y se detiene justo en la primera línea,
justo antes de que evalúa la función strcmp.
>> Desde que estoy en pausa, ahora puedo empezar limpiando alrededor y ver lo que está pasando
con todas las diferentes variables que se pasan en mi programa.
Aquí puedo imprimir argc y ver lo que está pasando.
Ver que argc es 3, porque tiene 3 valores diferentes en el mismo.
Tiene el nombre del programa, tiene el primer argumento y el segundo argumento.
Podemos imprimir los al mirar argv [0], argv [1], y argv [2].
Así que ahora también se puede ver por qué esta llamada strcmp va a fracasar,
porque ves que se divide el CS50 y las rocas en dos argumentos distintos.
En este punto, una vez que has llegado a un punto de interrupción, puede continuar con el paso a través de su programa
línea por línea, en lugar de empezar su programa de nuevo.
Así que si usted no quiere comenzar su programa de nuevo y seguimos desde aquí,
puede utilizar el comando continue y continuará ejecutar el programa hasta el final.
Al igual que lo hizo aquí.
Sin embargo, si se me reinicia el programa, CS50 rocas, golpea mi punto de interrupción una vez más,
y esta vez, si no quiere sólo tiene que ir todo el camino a través del resto del programa,
Puedo usar el comando siguiente, que yo también abreviar con n.
Y esto va a pasar por la línea de programa en línea.
Así que usted puede ver las cosas como ejecutar, a medida que cambian las variables, como las cosas se actualiza.
Lo cual es bastante agradable.
Lo bueno es otro lugar de repetir el mismo comando una y otra y otra vez,
si simplemente pulsa Intro - así que aquí ves que no has escrito en cualquier cosa -
si tan sólo pulsar Intro, se repetirá el comando anterior,
o el comando GDB anterior que acabo de poner pulg
Puedo mantener oprimir la tecla Enter y va a seguir paso a paso a través de mi código línea por línea.
Me gustaría animar a ustedes para ir a ver los programas con errores de otros también.
No tenemos tiempo para pasar por todos ellos hoy en la sección.
El código fuente está ahí, así que usted puede tipo de ver lo que está pasando
detrás de las escenas si te quedas realmente atascado,
pero al menos, sólo la práctica de arrancar GDB,
la ejecución del programa hasta que se rompe en usted,
obtener la traza de depuración, averiguar cuál es la función del accidente se encontraba,
lo que estaba en línea, la impresión de algunos valores de las variables,
sólo por lo que tener una idea de ello, porque lo que realmente le ayudará en el futuro.
En este punto, vamos a dejar de GDB, lo que lo hace dejar de usar o simplemente q.
Si el programa está en el medio de funcionamiento todavía, y no ha salido,
siempre le preguntará: "¿Estás seguro de que realmente quiere dejar de fumar?"
Sólo puede golpear si.
>> Ahora vamos a ver el siguiente problema que tenemos, que es el programa de gato.
Si usted mira el corto en la reorientación y tuberías, verás que Tommy utiliza este programa
que básicamente imprime toda la salida de un archivo en la pantalla.
Así que si me quedo gato, en realidad es un programa integrado en el aparato,
y si tienes Mac puedes hacer esto en tu Mac también, si usted abre terminal.
Y nosotros - gato, digamos, cp.c, y pulse Enter.
Lo que esto hizo, si nos desplazamos un poco y ver donde nos encontramos con la línea,
o donde ejecutó el comando cat, que literalmente acaba de imprimir el contenido de cp.c a nuestra pantalla.
Podemos ejecutarlo de nuevo y se puede poner en varios archivos juntos.
Así que usted puede hacer cp.c gato, y entonces también podemos concatenar el archivo Cat.C,
que es el programa que vamos a escribir,
y que va a imprimir dos archivos de espaldas a nuestra pantalla.
Así que si nos desplazamos un poco, vemos que cuando nos encontramos con este cp.c gato, Cat.C,
primero se imprime el archivo cp, y luego a continuación, se imprime el archivo Cat.C aquí abajo.
Vamos a usar esto para obtener sólo los pies mojados.
Juega un poco con la impresión simple a la terminal, ver cómo funciona.
Si ustedes abren con gedit Cat.C, pulse Enter,
usted puede ver el programa que estamos a punto de escribir.
Hemos incluido esta placa de la caldera agradable, así que no tiene que gastar tiempo escribiendo todo lo que fuera.
También comprobamos que el número de argumentos pasados ​​pulg
Nos imprimir un mensaje de uso agradable.
>> Este es el tipo de cosas que, de nuevo, al igual que hemos estado hablando,
es casi como la memoria muscular.
Sólo recuerde que seguir haciendo el mismo tipo de cosas
y siempre imprimiendo algún tipo de mensaje útil
por lo que la gente sabe cómo ejecutar su programa.
Con gato, es bastante simple, sólo vamos a ir a través de todos los diferentes argumentos
que se pasaron a nuestro programa, y ​​vamos a imprimir
su contenido hacia fuera a la pantalla de una en una.
Para imprimir archivos fuera de la pantalla, vamos a hacer algo muy similar
a lo que hicimos al final de la prueba.
Al final de la prueba, que contratan programa, tuvimos que abrir un archivo,
y luego tuvimos que imprimir en ella.
En este caso, vamos a abrir un archivo, y vamos a leer de ella en su lugar.
A continuación, vamos a imprimir, en lugar de a un archivo, vamos a imprimir en la pantalla.
Así que la impresión en la pantalla que todos hemos hecho antes con printf.
Así que no es demasiado loco.
Pero la lectura de un archivo es un poco extraño.
Vamos a pasar por eso un poco a la vez.
Si ustedes volver a ese último problema en el quiz, problema 33,
la primera línea que vamos a hacer aquí, al abrir el archivo, es muy similar a lo que hicimos allí.
Entonces, Stella, ¿qué significa esa mirada línea como, cuando abrimos un archivo?
[Stella] Capital * Archivo, Archivo - >> Bueno. >> - Es igual a fopen. >> Yup.
Que en este caso es? Está en el comentario.
>> Está en el comentario? argv [i] y el r?
>> Exactamente. Muy bien. Así que Stella es totalmente correcto.
Esto es lo que la línea se parece.
Vamos a obtener una variable de secuencia de archivo, guárdelo en un FILE *, por lo que todas las tapas,
FILE, *, y el nombre de esta variable será el archivo.
Lo podríamos llamar lo que nos gusta. Podríamos llamarlo first_file o file_i, cualquier cosa que quisiera.
Y luego el nombre del archivo que se aprobó en la línea de comandos para este programa.
Así que está almacenado en argv [i] y luego vamos a abrir el archivo en modo de lectura.
Ahora que hemos abierto el archivo, ¿qué es lo que siempre tenemos que recordar que hacer
cada vez que hemos abierto un archivo? Cerca de él.
Así Missy, ¿cómo cerrar un archivo?
[Missy] fclose (archivo) >> fclose (archivo). Exactamente.
Grande. Bien. Si nos fijamos en esto para hacer un comentario aquí mismo,
que dice, "Open argv [i] y muestra su contenido a la salida estándar."
>> Fuera Standard es un nombre raro. Stdout es sólo nuestra manera de decir
queremos imprimir en el terminal; queremos imprimir la secuencia de salida estándar.
En realidad, puede deshacerse de este comentario aquí.
Yo lo voy a copiar y pegar ya que es lo que hicimos.
En este punto, ahora tenemos que leer el bit de archivo de a poco.
Hemos hablado de un par de maneras de leer archivos.
¿Cuáles son sus favoritos hasta el momento?
Qué maneras has visto ni te acuerdas, para leer los archivos?
[Daniel] fread? >> Fread? Así fread es uno. Jimmy, ¿conoces alguna otra?
[Jimmy] >> No. Está bien. Nope. Charlotte? Alexander? ¿Algún otro? Bien.
Así que los otros son fgetc, es el que vamos a usar.
También hay fscanf; ustedes ver un patrón aquí?
Todos comienzan con f. Nada que ver con un archivo.
Hay fread, fgetc, fscanf. Estas son todas las funciones de lectura.
Para escribir tenemos fwrite, tenemos fputc en lugar de fgetc.
También hemos fprintf como vimos en el cuestionario.
Dado que este es un problema que involucra la lectura de un archivo,
vamos a utilizar una de estas tres funciones.
No vamos a utilizar estas funciones aquí abajo.
Estas funciones se encuentran todos en el estándar de E / S de la biblioteca.
Así que si nos fijamos en la parte superior de este programa,
se puede ver que ya hemos incluido el archivo de cabecera para el estándar de E / S de la biblioteca.
Si queremos averiguar cuál queremos utilizar,
siempre podemos abrir las páginas de manual.
Así que podemos escribir stdio hombre
y leer todo acerca de la entrada de stdio y funciones de salida en C.
Y ya podemos ver oh, mira. Se menciona fgetc, se menciona fputc.
Así que usted puede profundizar un poco más y ver, por ejemplo, fgetc
y buscar en su página de manual.
Usted puede ver que va junto con un montón de otras funciones:
fgetc, fgets, getc, getchar, consigue, ungetc, y su entrada de caracteres y cadenas.
Así que así es como se lee en caracteres y cadenas de los archivos de entrada estándar,
que es esencialmente parte del usuario.
Y así es como lo hacemos en real C.
Así que esto no está utilizando el GetString y funciones getchar
que se utilizó la biblioteca de CS50.
Vamos a hacer este problema en un par de maneras
de modo que usted puede ver dos maneras diferentes de hacerlo.
Tanto la función fread que Daniel menciona y fgetc son buenas maneras de hacerlo.
Creo fgetc es un poco más fácil, ya que sólo tiene, como usted ve,
un argumento, el FILE * que estamos tratando de leer el carácter de,
y su valor de retorno es un int.
Y esto es un poco confuso, ¿no?
>> Debido a que estamos llegando a un personaje, así que ¿por qué no hace una declaración char?
Ustedes tienen alguna idea de por qué esto no puede devolver un char?
[Missy respuestas, ininteligible] >> Yeah. Así que Missy es totalmente correcto.
Si es ASCII, entonces este entero podría ser asignada a una charla real.
Podría ser un carácter ASCII, y así es.
Eso es exactamente lo que está pasando.
Estamos usando un int simplemente porque tiene más bits.
Es más grande que un char, nuestra charla sólo tiene 8 bits, 1 byte que en nuestras máquinas de 32 bits.
Y un int tiene valor en los 4 bytes 'del espacio.
Y resulta que la forma fgetc funciona,
si se desplaza hacia abajo en nuestra sinopsis de esta página de manual un poco,
desplácese hasta el fondo. Resulta que utilizan este valor especial llamado EOF.
Es una constante especial como el valor devuelto por la función fgetc
cada vez que se pulsa el final del archivo o si se produce un error.
Y resulta que para hacer estas comparaciones con EOF correctamente,
Quieres tener esa cantidad extra de información que usted tiene en un int
en lugar de utilizar una variable char.
A pesar de que está efectivamente fgetc conseguir un personaje de un archivo,
quiere recordar que se está volviendo algo que es de tipo int a usted.
Dicho esto, es bastante fácil de usar.
Esto nos va a dar un carácter, por lo que todos tenemos que hacer es seguir pidiendo el archivo,
"Dame el siguiente carácter, me da el siguiente carácter, dame el personaje que viene"
hasta que lleguemos al final del archivo.
Y eso va a tirar de un carácter a la vez de nuestro archivo,
y entonces podemos hacer lo que queramos con ella.
Podemos almacenar, podemos añadir a una cadena, podemos imprimir.
Hacer nada de eso.
>> Acercamiento a salir y volver a nuestro programa Cat.C,
si vamos a utilizar fgetc,
¿cómo nos acercamos a esta siguiente línea de código?
Vamos a usar - fread va a hacer algo un poco diferente.
Y esta vez, sólo vamos a utilizar fgetc para obtener un carácter a la vez.
Para procesar un archivo completo, lo que tenemos que hacer?
¿Cuántos personajes hay en un archivo?
Hay un montón. Así que es probable que desee obtener una
y luego otro y conseguir otro y conseguir otro.
¿Qué tipo de algoritmo crees que podría tener que usar aquí?
¿Qué tipo de -? [Alejandro] Un bucle for? >> Exactamente.
Algún tipo de bucle.
Un bucle es realmente grande, en este caso.
Y, como usted decía, parece que quieres un lazo sobre la totalidad del expediente,
conseguir un carácter a la vez.
¿Alguna sugerencia sobre lo que puede tener un aspecto parecido?
[Alexander, ininteligible]
>> Bueno, me lo dices en Inglés lo que estás tratando de hacer? [Alexander, ininteligible]
Así que en este caso, parece que sólo estamos tratando de iterar sobre el archivo completo.
[Alejandro] Así que > El tamaño de -?
Supongo que el tamaño del archivo, ¿no? El tamaño - nos volveremos simplemente escribirlo así.
Tamaño de archivo por el momento, i + +.
Así que resulta que la forma de hacer esto utilizando fgetc, y esto es nuevo,
es que no hay manera fácil de conseguir apenas el tamaño de un archivo
con este "sizeof" tipo de construcción que haya visto antes.
Cuando usamos esa función fgetc, estamos introduciendo algún tipo de
nueva sintaxis, funky a este bucle, donde en lugar de utilizar simplemente un contador básico
ir carácter por carácter, vamos a tirar un carácter a la vez,
un carácter a la vez, y la manera en que sabemos que estamos en el final
no es cuando hemos contado un número determinado de caracteres,
pero cuando el personaje que sacar es que la final de carácter especial de archivo.
Así que podemos hacer esto - Yo llamo a esta cap, y nosotros vamos a inicializar
con nuestra primera llamada para obtener el primer carácter del archivo.
Así que esta parte, justo aquí, esto se va a poner a un personaje fuera del archivo
y almacenarlo en la variable ch.
Vamos a seguir haciendo esto hasta que llegue al final del archivo,
que hacemos por las pruebas de que el personaje no es igual a ese carácter EOF especial.
Y a continuación, en lugar de hacer ch + +, que acaba de incrementar el valor,
por lo que si leemos un fuera de un archivo, una A mayúscula, por ejemplo,
ch + + nos daría b, y luego nos íbamos a c y d.
Eso no es claramente lo que queremos. Lo que queremos aquí
en esta última parte es que queremos obtener el siguiente carácter del archivo.
>> Entonces, ¿cómo podemos obtener el siguiente carácter del archivo?
¿Cómo conseguimos el primer carácter del archivo?
[Estudiante] fgetfile? >> Fgetc, o, lo siento, tenías toda la razón.
Lo mal escrito ahí. Así que sí.
Aquí en vez de hacer ch + +,
sólo vamos a llamar fgetc (archivo) de nuevo
y almacenar el resultado en la variable ch mismo.
[Pregunta Estudiante, ininteligible]
>> Aquí es donde estos tipos de archivo * son especiales.
La forma de trabajar que es - cuando abra por primera vez - la primera vez que haga esa llamada fopen,
El archivo * sirve efectivamente como un puntero al comienzo del archivo.
Y cada vez que llame fgetc, se mueve un personaje a través del archivo.
Así que cada vez que se llame a esto, usted está incrementando el apuntador de archivo por un carácter.
Y cuando fgetc de nuevo, estás en movimiento a otro personaje
y otro personaje y otro personaje y otro personaje.
[Pregunta Estudiante, ininteligible] >> Y eso es - sí.
Es un poco de esta magia bajo el capó.
Usted acaba de seguir incrementando a través.
En este punto, usted es capaz de trabajar realmente con un personaje.
Entonces, ¿cómo podemos imprimir esto a la pantalla, ahora?
Podemos utilizar la misma cosa printf que utilizamos antes.
Que hemos estado usando durante todo el semestre.
Podemos llamar a printf,
y que puede pasar en el carácter justo de esa manera.
Otra forma de hacerlo es en vez de usar printf y tener que hacer esta cadena de formato,
También se puede utilizar una de las otras funciones.
Podemos utilizar fputc, que imprime un carácter en la pantalla,
excepto si nos fijamos en fputc - quiero alejar un poco.
Vemos lo bueno es que se necesita en el carácter que leemos a cabo utilizando fgetc,
pero entonces tenemos que darle un arroyo para imprimir.
También puede utilizar la función putchar, que pondrá directamente a la salida estándar.
Así que hay un montón de opciones diferentes que podemos usar para la impresión.
Están todos en el estándar de E / S de la biblioteca.
Cada vez que quiere imprimir - por lo printf, por defecto, se imprimirá en la norma especial fuera corriente,
que es la salida estándar.
Así que sólo puede referirse a él como una especie de magia este valor, stdout aquí.
Oops. Poner el punto y coma afuera.
>> Se trata de una gran cantidad de nueva información, funky aquí.
Mucho de esto es muy idiomático, en el sentido de que este es el código
lo que está escrito aquí sólo porque está limpio de leer, fácil de leer.
Hay muchas maneras diferentes de hacerlo, muchas funciones diferentes que puede utilizar,
pero tendemos a seguir sólo los mismos patrones una y otra vez.
Así que no se sorprenda si usted ve un código como el que viene una y otra vez.
Está bien. En este punto, tenemos que romper el día.
Gracias por venir. Gracias por ver si estás en línea. Y nos vemos la próxima semana.
[CS50.TV]