[Powered by Google Translate] [Review] [Quiz 0] [Lexi Ross, Tommy MacWilliam, Lucas Freitas, Joseph Ong] [Harvard University] [Esta es CS50.] [CS50.TV] Hey, todo el mundo. Bienvenidos a la sesión de revisión para Quiz 0, que se celebra este miércoles. Lo que vamos a hacer esta noche, estoy con 3 otros FF, y juntos vamos a ir a través de una revisión de lo que hemos hecho en el curso hasta el momento. No va a ser 100% completo, pero debe darle una idea mejor de lo que ya tiene y por lo que todavía tiene que estudiar antes del miércoles. Y no dude en levantar la mano con preguntas como vamos a lo largo, pero tenga en cuenta que también vamos a tener un poco de tiempo al final- si conseguimos a través de unos minutos de sobra para hacer preguntas generales, así que tenlo en mente, así que vamos a empezar desde el principio con la Semana 0. [Concurso 0 Review!] [Parte 0] [Lexi Ross] Pero antes de hacer eso vamos a hablar de la logística de la prueba. [Logística] [Concurso tendrá lugar el miércoles 10/10 en lugar de la conferencia] [(Ver http://cdn.cs50.net/2012/fall/quizzes/0/about0.pdf para más detalles)] Es el miércoles, 10 de octubre. Eso es este miércoles, y si vas a esta URL aquí que también es accesible desde CS50.net-ahí 's un enlace a ella- puede ver información acerca de dónde ir sobre la base de su apellido o afiliación escolar, así como se habla exactamente lo que la prueba incluirá y los tipos de preguntas que usted va a obtener. Tenga en cuenta que usted también tendrá la oportunidad de revisar el cuestionario en la sección, por lo que sus TFS debe ir sobre algunos problemas de la práctica, y esa es otra buena oportunidad para ver de dónde usted todavía tiene que estudiar para el examen. Vamos a empezar desde el principio con bytes 'n' Bits. Recuerde que un bit es un 0 o un 1, y un byte es una colección de 8 de estos bits. Echemos un vistazo a esta colección de bits aquí. Debemos ser capaces de averiguar cuántos bits hay. Donde se cuenta que hay sólo 8 de ellos, ocho 0 ó 1 unidades. Y puesto que hay 8 bits, eso es 1 byte, y vamos a convertir a hexadecimal. Hexadecimal es base 16, y es bastante fácil de convertir en un número binario, que es lo que es, a un número en hexadecimal. Todo lo que hacemos es mirar en grupos de 4, y convertirlos al dígito hexadecimal correspondiente. Comenzamos con el grupo de más a la derecha de 4, así que 0011. Eso va a ser un 1 y un 2, por lo que en conjunto hace 3. Y luego vamos a ver el otro bloque de 4. 1101. Eso va a ser un 1, un 4 y un 8. Junto eso va a ser de 13, lo que hace D. Y vamos a recordar que en hexadecimal no nos limitamos a ir del 0 al 9. Vamos 0 a F, por lo que después de 9, 10 corresponde a A, 11 a B, etcétera, donde F es 15. Aquí 13 es una D, por lo que para convertir a decimal todo lo que hacemos es en realidad tratar cada posición como una potencia de 2. Esa es una de 1, un 2, cero 4s, 8s cero, uno 16, etcétera, y es un poco difícil de calcular en la cabeza, pero si vamos a la siguiente diapositiva podemos ver la respuesta a eso. Esencialmente vamos al otro lado de la derecha de nuevo a la izquierda, y estamos multiplicando cada dígito por la correspondiente potencia de 2. Y recuerda, para hexadecimal que denotan estas cifras con 0x al principio así que no lo confunda con un número decimal. Continuando, esta es una tabla ASCII, y lo que utilice ASCII para es mapear de caracteres a valores numéricos. Recuerde que en el conjunto de procesadores criptografía hemos hecho un uso extensivo de la tabla ASCII con el fin de utilizar varios métodos de criptografía, el César y el cifrado de Vigenère, para convertir letras diferentes en una cadena de acuerdo con la clave proporcionada por el usuario. Vamos a ver un poco de matemáticas ASCII. En cuanto a 'P' + 1, en formato de caracteres que sería Q, y recuerda que '5 '≠ 5. Y cómo podríamos convertir entre estas 2 formas? No es en realidad demasiado dura. Con el fin de obtener 5 restamos '0 ' porque hay 5 lugares entre el 0 y el '5 '. Con el fin de ir hacia el otro que sólo tiene que añadir el 0, por lo que es una especie de aritmética regular. Sólo recuerde que cuando algo tiene comillas alrededor de él que es un personaje y por lo tanto corresponde a un valor en la tabla ASCII. Entrando en temas más generales de informática. Nos enteramos de lo que un algoritmo es y cómo se utiliza la programación para implementar algoritmos. Algunos ejemplos de algoritmos son algo realmente simple, como comprobar si un número es par o impar. Para los que se acuerdan de nosotros mod el número por 2 y comprobar si el resultado es 0. Si es así, es aún. Si no es así, es extraño. Y eso es un ejemplo de un algoritmo muy básico. Un poco de una mayor participación es la búsqueda binaria, que vamos a repasar más tarde en la sesión de revisión. Y la programación es el término que usamos para tomar un algoritmo y la conversión a codificar el ordenador puede leer. 2 ejemplos de programación Scratch, que es lo que hicimos en la semana 0. A pesar de que en realidad no se escribe el código es una forma de implementar este algoritmo, que es la impresión de los números 1-10, y aquí hacemos lo mismo en el lenguaje de programación C. Estos son funcionalmente equivalentes, acaba de escribir en diferentes idiomas o de sintaxis. Después nos enteramos acerca de las expresiones booleanas, y un booleano es un valor que es verdadero o falso, y aquí muchas veces expresiones booleanas ir dentro de las condiciones, así que si (x ≤ 5), bueno, ya establecer x = 5, por lo que el estado se va a evaluar en true. Y si es verdadero, todo el código está por debajo de la condición va a ser evaluado por el ordenador, de modo que cadena se va a imprimir la salida estándar, y la condición de término se refiere a todo lo que está dentro de los paréntesis de la instrucción if. Recuerde que todos los operadores. Recuerda que es && y | | cuando estamos tratando de combinar 2 o más condiciones, == No = para comprobar si dos cosas son iguales. Recuerde que es = para la asignación mientras == es un operador booleano. ≤, ≥ y luego la final 2 son fáciles de entender. Una revisión general de la lógica booleana aquí. Y expresiones booleanas son también importantes en bucles, que vamos a repasar ahora. Aprendimos unas 3 tipos de bucles en lo que va CS50, for, while y do tiempo. Y es importante saber que mientras para la mayoría de los propósitos de hecho podemos utilizar cualquier tipo de bucle en general hay ciertos tipos de propósitos o patrones comunes en la programación que específicamente llamar a uno de estos bucles hacer que el. más eficiente o elegante para codificar de esa manera Vamos a repasar lo que cada uno de estos bucles se suele utilizar para más frecuencia. En un bucle for por lo general, ya sé cuántas veces queremos repetir. Eso es lo que ponemos en la condición. Para, i = 0, i <10, por ejemplo. Ya sabemos que queremos hacer algo 10 veces. Ahora, por un bucle while, por lo general, no necesariamente sé cuántas veces queremos que el bucle se ejecute. Pero sí sabemos algún tipo de condición que queremos que siempre es verdadera o siempre falsa. Por ejemplo, mientras que se establece. Digamos que es una variable booleana. Si bien es cierto que queremos que el código para evaluar, así que un poco más extensible, un poco más general que un bucle for, pero para cualquier bucle también se puede convertir en un bucle while. Por último, hacer bucles while, que pueden ser los más difíciles de comprender de inmediato, se utiliza a menudo cuando queremos evaluar el primer código antes de la primera vez que compruebe el estado. Un caso de uso común que un ciclo do while es cuando se desea conseguir la entrada del usuario, y usted sabe que usted quiere preguntar al usuario para la entrada de por lo menos una vez, pero si no te dan una buena entrada de inmediato quiere seguir preguntando hasta que te dan la buena entrada. Ese es el uso más común de un bucle Do While, y echemos un vistazo a la estructura real de estos bucles. Por lo general siempre tienden a seguir estos patrones. En el bucle para el interior tiene 3 componentes: inicialización, por lo general algo como int i = 0 donde i es el contador, condición, donde queremos decir para ejecutar este bucle, siempre que esta situación todavía se mantiene, como i <10, y, por último, la actualización, que es la forma en que incrementa la variable de contador en cada punto en el bucle. Una cosa común ver sólo hay i + +, lo que significa incrementar i en 1 cada vez. También se podría hacer algo como i + = 2, lo que significa añadir 2 a i cada vez que vaya a través del bucle. Y a continuación, el hacer esto sólo se refiere a cualquier código que realmente se ejecuta como parte del bucle. Y por un bucle while, esta vez en realidad tenemos la inicialización fuera del bucle, así por ejemplo, digamos que estamos tratando de hacer el mismo tipo de bucle, como acabo de describir. Diríamos int i = 0 antes del bucle comienza. Entonces podríamos decir que mientras i <10 hacer esto, por lo que el mismo bloque de código como antes, y esta vez la parte de actualización del código, por ejemplo, i + +, en realidad va dentro del bucle. Y por último, para hacer un rato, es similar al bucle while, pero tenemos que recordar que el código se evaluará una vez antes de que la condición se comprueba, por lo que tiene mucho más sentido si nos fijamos en ella con el fin de arriba a abajo. En una, do while evalúa el código, incluso antes de ver la condición mientras mientras que un bucle while, comprueba en primer lugar. Las declaraciones y variables. Cuando queremos crear una nueva variable que primero desea inicializar. Por ejemplo, la barra int inicializa la variable bar, pero no le da un valor, entonces ¿cuál es el valor de la barra ahora? No lo sé. Podría ser un valor basura que estaba previamente almacenado en la memoria allí, y no queremos usar esa variable hasta que realmente le dan un valor, así lo declaramos aquí. Luego inicializamos a ser 42. Ahora, por supuesto, sabemos que esto se puede hacer en una sola línea, bar int = 42. Pero para ser claros los múltiples pasos que se están produciendo, la declaración e inicialización están sucediendo aquí por separado. Esto ocurre en un solo paso, y el siguiente, int = bar baz + 1, esta declaración de abajo, que baz incrementos, por lo que al final de este bloque de código si tuviéramos que imprimir el valor de baz sería 44 porque declarar e inicializar a ser de 1 bar>, y luego lo incrementa una vez más con el + +. Repasamos brevemente esta bonita, pero es bueno tener un general comprensión de lo que las discusiones y los eventos son. Principalmente nos hizo esto en Scratch, así que usted puede pensar en temas como varias secuencias de código ejecutando al mismo tiempo. En realidad, es probable que no se está ejecutando al mismo tiempo, sino una especie de forma abstracta, podemos pensar en él de esa manera. En Scratch, por ejemplo, tuvimos los sprites múltiples. Se podría ejecutar código diferente al mismo tiempo. Uno podía caminar mientras que el otro está diciendo algo en una parte diferente de la pantalla. Los eventos son otra manera de separar la lógica entre los diferentes elementos de su código, y en Scratch hemos sido capaces de simular los eventos utilizando la difusión, y que en realidad es cuando recibo, no cuando oigo, pero en esencia se trata de una forma de transmitir información de un sprite a otro. Por ejemplo, es posible que desee transmitir más de juego, y cuando otro duende recibe más de juego, que responde de una manera determinada. Es un modelo importante para entender la programación. Sólo para pasar la Semana básico 0, lo que hemos ido hasta ahora, echemos un vistazo a este programa C simple. El texto puede ser un poco más pequeña de aquí, pero voy a ir sobre ella muy rápido. Estamos incluyendo dos archivos de cabecera en la parte superior cs50.h y stdio.h. Estamos entonces definir un límite constante llamado a ser 100. Estamos entonces la implementación de nuestra función principal. Debido a que no utiliza argumentos de línea de comandos aquí tenemos que poner vacío como los argumentos a favor principal. Vemos int arriba principal. Ese es el tipo de retorno, por lo tanto, devolver 0 en la parte inferior. Y estamos usando la función de biblioteca CS50 conseguir int solicitar al usuario datos, y la almacenamos en esta variable x, por lo que declaramos x arriba, y lo inicializa con x = getInt. A continuación, comprobar para ver si el usuario nos dio buena entrada. Si se trata de LIMIT ≥ queremos devolver un código de error de 1 y mostrará un mensaje de error. Y, por último, si el usuario nos ha dado buenos aportes vamos a cuadrar el número e imprimir el resultado. Sólo para asegurarse de que todos los afectados casa se puede ver las etiquetas de diferentes partes del código aquí. Mencioné archivos constantes de cabecera. Oh, int x. Asegúrese de recordar que es una variable local. Esto contrasta de una variable global, lo que vamos a hablar de un poco más adelante en la sesión de revisión, y estamos llamando a la función de biblioteca printf, así que si no había incluido el archivo de cabecera stdio.h no sería capaz de llamar a printf. Y creo que la flecha que se cortó aquí está apuntando a la d% que es una cadena de formato de printf. Dice imprimir esta variable como un número d%. Y que es la Semana de 0. Ahora Lucas va a continuar. Hey, chicos. Mi nombre es Lucas. Soy un estudiante de segundo año en la mejor casa en el campus, Mather, y voy a hablar un poco sobre la Semana 1 y 2,1. [Semana 1 y 2,1!] [Lucas Freitas] Como Lexi estaba diciendo, cuando empezamos a traducir el código desde cero en C una de las cosas que hemos notado es que se puede no sólo escribir el código y ejecutarlo con una bandera verde más. En realidad, usted tiene que utilizar algunos pasos para hacer su programa en C convertirse en un archivo ejecutable. Básicamente lo que haces cuando estás escribiendo un programa es que traducir su idea en un lenguaje que un compilador puede entender, así que cuando usted está escribiendo un programa en C lo que estás haciendo es escribir realmente algo que el compilador va a entender, y el compilador va a traducir ese código en algo que su equipo va a entender. Y la cosa es que el equipo es realmente muy tonto. El equipo sólo se puede entender 0s y 1s, lo que en realidad en los primeros ordenadores gente suele programarse con 0 y 1, pero ya no, gracias a Dios. No tenemos que memorizar las secuencias de 0s y 1s para un bucle o para un bucle while y así sucesivamente. Es por eso que tenemos un compilador. Lo que un compilador hace es que básicamente se traduce el código C, en nuestro caso, a un idioma que el equipo va a entender, que es el código objeto, y el compilador que estamos utilizando se llama sonido metálico, así que esto es realmente el símbolo de sonido metálico. Cuando usted tiene su programa, usted tiene que hacer 2 cosas. En primer lugar, usted tiene que compilar el programa, y ​​luego se va a ejecutar el programa. Para compilar el programa tiene un montón de opciones para hacerlo. La primera de ellas tiene que ver program.c clang en qué programa es el nombre del programa. En este caso se puede ver que están diciendo "Hey, compilar mi programa". Usted no está diciendo "Quiero que este nombre para mi programa", ni nada. La segunda opción es dar un nombre a su programa. Se puede decir clang-o y luego el nombre que desea el archivo ejecutable para ser nombrado como y, a continuación program.c. Y también se puede hacer hacer el programa, y ​​ver cómo en los primeros 2 casos Puse. C, y en el tercero sólo tengo programas? Sí, en realidad no debería poner. C cuando se utiliza hacer. De lo contrario el compilador es en realidad va a gritar a usted. Y también, no sé si ustedes recuerdan, pero muchas veces también usamos lcs50-o-lm. Eso se llama enlace. Simplemente le dice al compilador que va a utilizar las bibliotecas allí mismo, así que si usted desea utilizar cs50.h que realmente tiene que escribir clang program.c-lcs50. Si no lo hace, el compilador no va a saber que está utilizando estas funciones en cs50.h. Y cuando se quiere ejecutar el programa tiene 2 opciones. Si usted hizo program.c clang usted no dio un nombre a su programa. Usted tiene que ejecutar con. / A.out. A.out es un nombre estándar que le da a su sonido metálico programa si no le damos un nombre. De lo contrario, vamos a hacer. / Programa si usted le dio un nombre a su programa, y también si lo has hecho hacer el programa el nombre de un programa que se va a poner ya va a ser programado con el mismo nombre que el archivo c. Luego hablamos de tipos de datos y los datos. Básicamente los tipos de datos son la misma cosa como pequeñas cajas que utilizan para almacenar los valores, por lo que los tipos de datos son en realidad como Pokémons. Vienen en todos los tamaños y tipos. No sé si esa analogía tiene sentido. El tamaño de los datos depende en realidad de la arquitectura de la máquina. Todos los tamaños de datos que voy a mostrar aquí son en realidad para una máquina de 32-bit, que es el caso de nuestro aparato, pero si usted está realmente codificación de su Mac o en Windows también Probablemente usted va a tener un equipo de 64 bits, así que recuerde que los tamaños de los datos que voy a mostrar aquí son para la máquina de 32-bit. El primero que vimos fue un int, que es bastante sencillo. Utilice int para almacenar un entero. También vimos el carácter, el char. Si desea utilizar una letra o un símbolo poco usted está probablemente va a utilizar un char. Un char tiene 1 byte, es decir 8 bits, como dijo Lexi. Básicamente tenemos una tabla ASCII que tiene 256 las posibles combinaciones de 0s y 1s, y luego, cuando se escribe una charla va a traducir el carácter que las entradas que un número que tiene en la tabla ASCII, como dijo Lexi. También tenemos el flotador, que utilizamos para almacenar números decimales. Si usted quiere elegir 3.14, por ejemplo, usted va a utilizar un flotador o un doble que tiene más precisión. Un flotador tiene 4 bytes. Un doble tiene 8 bytes, por lo que la única diferencia es la precisión. También tenemos un largo que se utiliza para los números enteros, y se puede ver una máquina de 32-bit un int y un largo tienen el mismo tamaño, por lo que en realidad no tiene sentido utilizar un largo en una máquina de 32-bit. Pero si usted está usando un Mac y de 64 bits, en realidad una larga tiene un tamaño de 8, así que realmente depende de la arquitectura. Para que la máquina 32-bit no tiene sentido usar un largo realidad. Y luego un largo tiempo, por otro lado, tiene 8 bytes, por lo que es muy bueno si usted quiere tener un entero largo. Y por último, tenemos cadena, que es en realidad un char *, que es un puntero a un char. Es muy fácil pensar que el tamaño de la cadena va a ser como el número de caracteres que tiene allí, pero en realidad el propio char * tiene el tamaño de un puntero a un char, que es 4 bytes. El tamaño de un char * es de 4 bytes. No importa si usted tiene una pequeña palabra o una letra o nada. Va a ser de 4 bytes. También hemos aprendido un poco acerca de casting, Así como usted puede ver, si usted tiene, por ejemplo, un programa que dice: int x = 3 y luego printf ("% d", x / 2) ¿Ustedes saben lo que va a imprimir en la pantalla? ¿Alguien? >> [Los estudiantes] 2. 1. >> 1, sí. Al hacer 3/2 que va a obtener 1,5, pero ya que estamos usando un número entero que va a hacer caso omiso de la parte decimal, y vas a tener 1. Si usted no quiere que eso suceda lo que puede hacer, por ejemplo, Se declara un flotador y = x. Entonces x que antes eran 3 ahora va a ser 3,000 en y. Y entonces usted puede imprimir el a / 2. En realidad, yo debería tener un 2. por allí. Va a hacer 3.00/2.00, y vas a obtener 1,5. Y nosotros tenemos este f 0.2 sólo para pedir 2 unidades decimales de la parte decimal. Si tiene .3 f que va a tener realmente 1.500. Si se trata de dos que va a ser 1,50. También tenemos este caso. Si lo hace float x = 3,14 x y entonces usted printf usted va a obtener 3,14. Y si lo hace x = int x, lo que significa tratar a x como un entero y se imprime x ahora usted va a tener 3,00. ¿Eso tiene sentido? Debido a que usted está tratando primeramente x como un entero, por lo que está haciendo caso omiso de la parte decimal, y luego imprime x. Y, por último, también se puede hacer esto, int x = 65, y entonces se declara un char c = x, y luego, si se imprime el c estás realmente va a conseguir A, así que básicamente lo que estás haciendo aquí está traduciendo el entero en el carácter, al igual que la tabla ASCII hace. También hablamos de los operadores matemáticos. La mayoría de ellos son bastante sencillos, por lo que +, -, *, /, y también hablamos de mod, que es el resto de una división de dos números. Si tiene 10% 3, por ejemplo, que significa dividir 10 por 3, y lo que es el resto? Va a ser 1, por lo que es realmente muy útil para muchos de los programas. Para Vigenère y César estoy bastante seguro de que todos ustedes utilizan mod. Operadores matemáticos, tenga mucho cuidado al combinar * y /. Por ejemplo, si usted hace (3/2) * 2 ¿Qué vas a conseguir? [Los estudiantes] 2. Sí, 2, porque 3/2 va a ser 1,5, pero ya que estamos haciendo operaciones entre dos números enteros en realidad estás sólo va a tener en cuenta 1, y luego 1 * 2 va a ser de 2, así que ten mucho cuidado al hacer aritmética con números enteros porque usted puede ser que consiga que 2 = 3, en ese caso. Y también tener mucho cuidado con prioridad. Generalmente, usted debe usar paréntesis para estar seguro de que usted sabe lo que está haciendo. Algunos atajos útiles, por supuesto, se trata de i + + o i + = 1 o usando + =. Esto es lo mismo que hacer i = i + 1. También puedo hacer - o i - = 1, que es lo mismo que i = i -1, algo que ustedes usar en los bucles for, al menos. Además, para *, si utiliza * = y si lo hace, por ejemplo, i * = 2 es lo mismo que decir i = i * 2, y lo mismo para la división. Si lo hace i / = 2 es lo mismo que i = i / 2. Ahora, acerca de las funciones. Ustedes aprendieron que las funciones son una estrategia muy buena para guardar el código mientras que usted está programando, así que si usted desea llevar a cabo la misma tarea en el código una y otra vez, probablemente desee utilizar una función sólo para que usted no tiene que copiar y pegar el código una y otra vez. En realidad, la principal es una función, y cuando te muestran el formato de una función vas a ver que eso es bastante obvio. También utilizamos las funciones de algunas bibliotecas, por ejemplo, printf, Getin, que es de la biblioteca CS50, y otras funciones como toupper. Todas estas funciones se llevan a la práctica otras bibliotecas, y cuando se pone los archivos de sujeción al principio de su programa que dices puede darme el código para las funciones así que no tienes que ponerlas en práctica por mí mismo? Y usted también puede escribir sus propias funciones, por lo que al iniciar la programación te das cuenta de que las bibliotecas no tienen todas las funciones que usted necesita. Para el conjunto de procesadores pasado, por ejemplo, escribimos dibujar, lucha y búsqueda, y es muy, muy importante ser capaz de escribir funciones porque son útiles, y los usamos todo el tiempo en la programación, y se ahorra una gran cantidad de código. El formato de una función es éste. Contamos con tipo de retorno al principio. ¿Cuál es el tipo de cambio? Es sólo cuando su función se va a devolver. Si dispone de una función, por ejemplo, factorial, que se va a calcular un factorial de un número entero, es probable que lo va a devolver un entero también. A continuación, el tipo de retorno va a ser int. Printf en realidad tiene un tipo de retorno void porque no se está volviendo algo. No eres más que la impresión de las cosas a la pantalla y salida de la función después. Entonces usted tiene el nombre de la función que usted puede elegir. Usted debe ser un poco razonable, al igual que no elige un nombre como xyz o como x2F. Trate de hacer un nombre que tenga sentido. Por ejemplo, si es factorial, digamos factorial. Si se trata de una función que se va a dibujar algo, el nombre de dibujar. Y luego tenemos a los parámetros, que también se llaman argumentos, que son como los recursos que necesita su función a partir de su código para realizar su tarea. Si desea calcular el factorial de un número Probablemente es necesario tener un número para calcular un factorial. Uno de los argumentos que vamos a tener es el propio número. Y luego se va a hacer algo y devolver el valor al final a menos que sea una función void. Veamos un ejemplo. Si quiero escribir una función que sume todos los números en una matriz de enteros, en primer lugar, el tipo de retorno va a ser int porque tengo una matriz de enteros. Y entonces me voy a tener el nombre de la función como sumArray, y entonces va a tener el mismo array, int nums a, y entonces la longitud de la matriz, así que sé la cantidad de números que hay que sumar. Entonces tiene que inicializar una variable llamada suma, por ejemplo, a 0, y cada vez que veo a un elemento de la matriz que debería añadir a la suma, así que hice un bucle for. Como dijo Lexi, ¿verdad int i = 0, i longitud 0, entonces es positivo. Si es = a 0, entonces es 0, y si es <0, entonces es negativo. Y el otro está haciendo si, else if, else. La diferencia entre los dos es que éste es en realidad va a comprobar si> 0, <0 = 0 o tres veces, así que si usted tiene el número 2, por ejemplo, va a venir aquí y decir if (x> 0), y que va a decir que sí, así que imprimir positivo. Pero aunque sé que es> 0 y que no va a ser 0 o <0 Todavía voy a hacer es 0, es <0, así que estoy realmente va dentro de IFS que yo no tenía que porque ya sabemos que no va a satisfacer alguna de estas condiciones. Puedo usar el if, else if, else declaración. Básicamente dice que si x = 0 imprimo lo positivo. Si no es así, voy a probar esto también. Si es 2, no voy a hacer esto. Básicamente si tuviera x = 2 le diría if (x> 0), sí, así que imprimir esto. Ahora que sé que es> 0 y que satisface la primera, si Yo ni siquiera voy a ejecutar este código. El código se ejecuta más rápido, en realidad, tres veces más rápido si los usas. También aprendimos sobre AND y OR. No voy a pasar por esto porque Lexi ya hablaba de ellos. Es sólo el && y | operador |. Lo único que voy a decir es tener cuidado cuando usted tiene 3 condiciones. Utilice paréntesis porque es muy confuso cuando usted tiene una condición y otro o uno al otro. Utilice paréntesis para estar seguro de que sus condiciones de tener sentido porque en ese caso, por ejemplo, se puede imaginar que podría ser la primera condición y una o la otra o las dos condiciones combinadas en una y o el tercero, así que ten cuidado. Y por último, hemos hablado acerca de los modificadores. Un interruptor es muy útil cuando se tiene una variable. Digamos que usted tiene una variable como n que puede ser 0, 1, o 2, y para cada uno de los casos usted va a realizar una tarea. Se puede decir cambiar la variable, e indica que entonces el valor de valor1 es como voy a hacer esto, y luego rompo, lo que significa que no voy a mirar en cualquiera de los otros casos porque ya convencido de que el caso y luego valor2 y así sucesivamente, y también puede tener un interruptor predeterminado. Eso significa que si no satisface cualquiera de los casos que he tenido que voy a hacer otra cosa, pero eso es opcional. Eso es todo para mí. Ahora vamos a Tommy. Muy bien, esto va a ser la semana 3-ish. Estos son algunos de los temas que trataremos, crypto, alcance, matrices, etc. Sólo un breve comentario sobre criptografía. No vamos a recalcar este. Lo hicimos en conjunto de procesadores 2, pero para la prueba asegúrate de saber la diferencia entre el cifrado César y el cifrado Vigenère, cómo ambos funcionan esas cifras y lo que es para cifrar y descifrar el texto usando esos 2 cifras. Recuerde, el cifrado César simplemente rota cada personaje en la misma cantidad, asegurándose de mod por el número de letras en el alfabeto. Y el cifrado de Vigenère, por otro lado, hace girar cada carácter por un monto diferente, así que en lugar de decir cada personaje gira por 3 Vigenère rotará cada personaje por una cantidad diferente dependiendo de alguna palabra clave donde cada letra de la palabra clave representa una cierta cantidad diferente para girar el texto claro. Vamos a hablar primero de alcance variable. Hay 2 tipos diferentes de variables. Tenemos las variables locales, y estos van a ser definidos fuera de principal o fuera de cualquier función o bloque, y estos serán accesibles en cualquier parte de su programa. Si usted tiene una función y que en función de un bucle while la variable global grande es accesible en todas partes. Una variable local, por otra parte, tiene como alcance el lugar en el que está definida. Si usted tiene una función aquí, por ejemplo, tenemos esta función g, y en el interior de g no es una variable llamada aquí y, y eso significa que se trata de una variable local. A pesar de que esta variable se llama y y esta variable se denomina Y Estas 2 funciones no tienen idea de lo que los demás son variables locales. Por otra parte, aquí se dice int x = 5, y esto está fuera del alcance de cualquier función. Está fuera del alcance de la principal, por lo que esta es una variable global. Eso significa que dentro de estas 2 funciones cuando digo x - x + + o Estoy accediendo a la misma por lo que este x y y esto son variables diferentes. Esa es la diferencia entre una variable global y una variable local. En lo que a diseño se refiere, a veces es probablemente una mejor idea para mantener las variables locales siempre que sea posible ya que tener un montón de variables globales se puede volver muy confuso. Si usted tiene un montón de funciones modificando todo la misma cosa es posible que olvide lo que si esta función accidentalmente modifica este mundial, y esta otra función que no sabe nada de ella, y que se pone bastante confuso a medida que más código. Mantener las variables locales siempre que sea posible es sólo un buen diseño. Arrays, recordemos, son simplemente listas de elementos del mismo tipo. Dentro de CI no se puede tener una lista como 1, 2,0, hola. No podemos hacer eso. Cuando se declara una matriz C en todos los elementos tienen que ser del mismo tipo. Aquí tengo una matriz de 3 enteros. Aquí tengo la longitud de la matriz, pero si yo sólo lo estoy declarando en esta sintaxis donde puedo especificar lo que todos los elementos son técnicamente yo no necesito esto 3. El compilador es suficientemente inteligente como para saber el tamaño de la matriz debe ser. Ahora cuando quiero obtener o establecer el valor de una matriz esta es la sintaxis para hacerlo. En realidad, esto modificará el segundo elemento de la matriz porque, recordar, numeración comienza en 0, no en 1. Si quiero leer ese valor lo que puedo decir algo como int x = array [1]. O si desea establecer ese valor, como que estoy haciendo aquí, Puedo decir array [1] = 4. Que el tiempo para acceder a los elementos por su índice o su posición o donde están en la matriz, y que la lista comienza en 0. También podemos tener matrices de matrices, y esto se llama una matriz multi-dimensional. Cuando tenemos una matriz multi-dimensional eso significa que podemos tener algo como filas y columnas, y esto es sólo una forma de visualizar esto o pensar en ello. Cuando tengo una matriz multi-dimensional que significa que voy a empezar a necesitar más de un índice porque si tengo una red Sólo digo lo que está en la fila no nos da un número. Eso es realmente sólo nos va a dar una lista de números. Digamos que tengo esta serie aquí. Tengo una matriz llamada cuadrícula, y yo estoy diciendo que es 2 filas y 3 columnas, por lo que esta es una forma de visualizarlo. Cuando digo que quiero obtener el elemento en [1] [2] que significa que debido a que estas son las filas primera y luego columnas Voy a saltar a la fila 1 ya he dicho 1. Entonces me voy a venir aquí a la columna 2, y voy a obtener el valor 6. Tiene sentido? Multi-dimensionales, recordemos, son técnicamente sólo un conjunto de matrices. Podemos tener arrays de arrays de arrays. Podemos seguir adelante, pero en realidad una forma de pensar cómo se está expuesto y lo que pasa es visualizarlo en una red como ésta. Al pasar matrices a funciones, que van a comportarse un poco diferente que cuando pasamos variables regulares a las funciones como pasar un int o un float. Cuando pasamos en un tipo int o char o cualquiera de estos otros datos nos lo tomamos un vistazo a si la función modifica el valor de dicha variable de que el cambio no se va a propagar hasta a la función de llamada. Con una matriz, por otro lado, que va a pasar. Si paso en una matriz a una función y que la función cambia algunos de los elementos, cuando vuelva a la función que se llama mi matriz ahora va a ser diferente, y el vocabulario para que es arrays se pasan por referencia, como veremos más adelante. Esto se relaciona con cómo funcionan los punteros, donde estos tipos de datos básicos, Por otra parte, se pasan por valor. Podemos pensar que a medida que se hace una copia de una variable y luego pasar en la copia. No importa lo que hagamos con esa variable. La función de llamada no se dará cuenta de que se ha cambiado. Las matrices son un poco diferentes en ese sentido. Por ejemplo, como acabamos de ver, la principal es simplemente una función que puede tomar en dos argumentos. El primer argumento de la función principal es argc, o el número de argumentos, y el segundo argumento se llama argv, y esos son los valores reales de esos argumentos. Digamos que tienen un programa llamado this.c, y yo digo que esto, y voy a correr esto en la línea de comandos. Ahora, para pasar algunos argumentos para mi programa que se llama esto, Podría decir algo así como. / Esto es cs 50. Esto es lo que nos imaginamos a David a hacer todos los días a la terminal. Pero ahora la función principal dentro de ese programa tiene estos valores, por lo que argc es 4. Puede ser un poco confuso porque en realidad sólo estamos pasando es cs 50. Eso es sólo 3. Pero recuerda que el primer elemento de argv o el primer argumento es el nombre de la función en sí. Así que eso significa que hay 4 cosas aquí, y el primer elemento va a ser. / este. Y esto se representa como una cadena. A continuación, los elementos restantes son lo que escribió en el después del nombre del programa. Así que, en un aparte, ya que es probable que vi en pset 2, recordar que la cadena 50 es el número entero ≠ 50. Así que no podemos decir algo como, 'int x = argv 3. Eso no va a tener sentido, porque esto es una cadena, y este es un entero. Así que si usted desea convertir entre los dos, recuerda, vamos a tiene esta función mágica llamada atoi. Para eso se necesita una cadena y devuelve el entero representado dentro de esa cadena. Así que eso es un error fácil de hacer en el concurso, pensando que este será automáticamente el tipo correcto. Pero sólo sé que estos siempre serán cadenas incluso si la cadena sólo contiene un número entero o un carácter o un flotador. Así que ahora vamos a hablar de tiempo de ejecución. Cuando tengamos todos estos algoritmos que hacen todas estas cosas locas, se hace muy útil para hacer la pregunta, "¿Cuánto tiempo tomará?" Representamos a que, con algo que se llama notación asintótica. Así que esto significa que - bueno, vamos a decir que le damos nuestro algoritmo algunas entradas muy, muy, muy grande. Queremos hacer la pregunta, "¿Cuánto tiempo va a tomar? ¿Cuántos pasos se tarda en nuestro algoritmo para ejecutar como una función del tamaño de la entrada? " Así que la primera forma podemos describir el tiempo de ejecución es de gran O. Y este es el peor de los casos el tiempo de funcionamiento. Así que si queremos ordenar un array, y damos nuestro algoritmo de una matriz eso es en orden descendente, cuando debería estar en orden ascendente, que va a ser el peor de los casos. Este es nuestro límite superior de la duración máxima del tiempo de nuestro algoritmo tomará. Por otra parte, este Ω se va a describir mejor de los casos el tiempo de funcionamiento. Así que si le damos un arreglo ya está ordenado a un algoritmo de clasificación, ¿cuánto tiempo se tarda en resolverlo? Y esto, a continuación, se describe un límite inferior en tiempo de ejecución. Así que aquí son sólo algunas palabras que describen algunos momentos comunes de funcionamiento. Estos son en orden ascendente. El mejor tiempo de funcionamiento que tenemos se llama constante. Eso significa que no importa cuántos elementos damos nuestro algoritmo, no importa lo grande que es nuestra matriz, su clasificación o hacer lo que estamos haciendo a la matriz siempre tendrá la misma cantidad de tiempo. Por lo tanto, puede representar que sólo con un 1, que es una constante. También nos fijamos en tiempo de ejecución logarítmica. Así que algo como la búsqueda binaria es logarítmica, donde cortamos el problema a la mitad cada vez y entonces las cosas sólo llegar más alto desde allí. Y si alguna vez escribir una O de cualquier algoritmo factorial, es probable que no deben considerar esto como su trabajo del día. Al comparar los tiempos de ejecución, es importante tener en cuenta estas cosas. Así que si tengo un algoritmo que es O (n), y otra persona tiene un algoritmo de O (2n) son en realidad asintóticamente equivalente. Así que si nos imaginamos n sea un número grande como ciento once mil millones: así que cuando estamos comparando ciento once mil millones a algo así como ciento once millones + 3, que de repente tres en realidad no hacen una gran diferencia ya. Es por eso que vamos a empezar a considerar estas cosas como equivalentes. Así que cosas como estas constantes aquí, hay 2 x esto, o la adición de un 3, estos son sólo constantes, y estos van a caer hacia arriba. Así que por eso todos los 3 de estos tiempos de funcionamiento son los mismos que dicen que son O (n). Del mismo modo, si tenemos 2 tiempos de ejecución otros, digamos O (n + 2n ³ ²), podemos añadir + N, + 7, y luego tenemos otro tiempo de ejecución que es sólo O (³ n). de nuevo, se trata de lo mismo, porque estos - estos no son los mismos. Estas son las cosas mismas, lo siento. Así que estos son los mismos porque Este ³ n va a dominar esta ² 2n. Lo que no es lo mismo es que si se nos ha acabado veces como O (³ n) y O (n ²) porque este ³ n es mucho mayor que esta ² n. Así que si tenemos exponentes, de repente esta se inicia a la materia, pero cuando sólo estamos tratando con factores como estamos aquí, entonces no va a importar, ya que sólo se va a abandonar. Echemos un vistazo a algunos de los algoritmos que hemos visto hasta ahora y hablar de su tiempo de ejecución. La primera forma de buscar un número en una lista, que vimos, era la búsqueda lineal. Y la aplicación de búsqueda lineal es super sencillo. Sólo tenemos una lista, y vamos a ver cada elemento de la lista hasta encontrar el número que estamos buscando. Eso significa que en el peor de los casos, este O (n). Y el peor de los casos aquí podría ser si el elemento está el último elemento, a continuación, utilizando una búsqueda lineal que tenemos que mirar a cada elemento hasta llegar a la última con el fin de saber que en realidad estaba en la lista. No podemos abandonar a mitad de camino y decir: "Probablemente no sea allí". Con la búsqueda lineal que tenemos que mirar a todo el asunto. El tiempo de ejecución del mejor caso, en cambio, es constante porque en el mejor de los casos el elemento que estamos buscando es sólo el primero de la lista. Así que va a llevarnos exactamente un paso, no importa lo grande que la lista es si estamos buscando el primer elemento cada vez. Así que cuando usted busca, recordemos, no se requiere que la lista esté ordenada. Porque estamos simplemente va a mirar por encima de cada elemento, y no importa realmente qué orden los elementos se in Un algoritmo de búsqueda más inteligente es algo así como la búsqueda binaria. Recuerde, la aplicación de búsqueda binaria es cuando usted va a seguir buscando en la mitad de la lista. Y debido a que está buscando en el medio, es necesario que la lista está ordenada o de lo que no sabemos donde el centro es, y tenemos que mirar por encima de toda la lista para encontrarla, y entonces en ese punto estamos perdiendo el tiempo. Así que si tenemos una lista ordenada y nos encontramos con el medio, vamos a comparar el medio para el elemento que estamos buscando. Si es demasiado alto, entonces nos podemos olvidar de la mitad derecha porque sabemos que si nuestra elemento ya es demasiado alto y todo a la derecha de este elemento es aún mayor, entonces no es necesario mirar allí. Cuando por el contrario, si nuestro elemento es demasiado bajo, lo sabemos todo a la izquierda del elemento que también es demasiado baja, por lo que no tiene mucho sentido mirar allí, tampoco. De esta manera, con cada paso y cada vez que nos fijamos en el punto medio de la lista, vamos a reducir nuestro problema a la mitad porque de pronto sabemos un montón de números que no pueden ser la que estamos buscando. En este pseudocódigo sería algo como esto, y porque estamos cortando la lista por la mitad cada vez, nuestros peores saltos de tiempo de ejecución de lineal a logarítmica. Así que de repente se tiene log-in pasos con el fin de encontrar un elemento en una lista. El tiempo de ejecución mejor de los casos, sin embargo, sigue siendo constante porque ahora, vamos a decir que el elemento que estamos buscando es siempre el centro exacto de la lista original. Así que podemos hacer crecer nuestra lista tan grande como queramos, pero si el elemento que estamos buscando está en el medio, entonces sólo va a llevarnos un paso. Así que por eso estamos O (log n) y Ω (1) o constante. Vamos a ejecutar realmente la búsqueda binaria en esta lista. Así que digamos que estamos buscando el elemento 164. Lo primero que vamos a hacer es encontrar el punto medio de esta lista. Lo que pasa es que el punto medio se va a caer en medio de estos dos números, así que vamos a decir arbitrariamente, cada vez que el punto medio se sitúa entre dos números, vamos a reunir. Sólo tenemos que asegurarnos de que hacemos esto cada paso del camino. Así que nos vamos a reunir y vamos a decir que 161 es el centro de nuestra lista. Así 161 <164, y cada elemento a la izquierda de 161 También es <164, por lo que sabemos que no nos va a ayudar en absoluto para empezar a buscar por aquí porque el elemento que estamos buscando no puede estar allí. Así que lo que podemos hacer es simplemente podemos olvidar que la mitad de toda la izquierda de la lista, y ahora sólo tienen en cuenta desde la derecha de la década de 161. Así que de nuevo, este es el punto medio, vamos a redondear. Ahora 175 es demasiado grande. Así que sabemos que no va a ayudarnos a buscar aquí o aquí, por lo que sólo se puede tirar eso, y al final nos va a golpear el 164. Cualquier pregunta sobre la búsqueda binaria? Vamos a pasar de buscar a través de una lista ya ordenada- para realmente teniendo una lista de números en cualquier orden y hacer que la lista en orden ascendente. El primer algoritmo vimos fue llamado tipo burbuja. Y esto sería más simple de los algoritmos que vimos. Ordenamiento de burbuja, dice que cuando cualquiera de los 2 elementos dentro de la lista están fuera de lugar, es decir, hay un número superior a la izquierda de un número más bajo, entonces vamos a cambiar, porque eso significa que la lista será "Más ordenada" de lo que era antes. Y sólo vamos a continuar con este proceso una y otra vez y otra vez hasta que, finalmente, el tipo de elementos burbuja a su ubicación correcta y tenemos una lista ordenada. El tiempo de ejecución de que esto va a ser O (n ²). ¿Por qué? Bueno, pues en el peor de los casos, vamos a tomar cada elemento, y vamos a terminar comparándolo con cualquier otro elemento en la lista. Pero en el mejor de los casos, tenemos una lista ya ordenada, burbuja tipo de sólo va a pasar por una vez, diga "Nope. Yo no hice ningún swaps, así que he terminado." Así que tenemos un tiempo mejor de los casos el funcionamiento de Ω (n). Vamos a correr especie de burbuja en una lista. O vamos a mirar algunos pseudocódigo muy rápido. Queremos decir que queremos perder de vista, en cada iteración del bucle, hacer un seguimiento de si podemos o no cambiar ningún elemento. Así que la razón de esto es, que vamos a parar cuando no hemos cambiado ningún elemento. Así que al principio de nuestro bucle no hemos cambiado nada, así que voy a decir que es falso. Ahora, vamos a ir por la lista y comparar elemento a elemento i i + 1 y si es el caso que hay un número más grande a la izquierda de un número más pequeño, entonces sólo vamos a intercambiarlas. Y luego vamos a recordar que nos cambiado un elemento. Eso significa que tenemos que pasar por la lista al menos una vez más porque la condición en la que se detiene cuando toda la lista ya está ordenada, lo que significa que no han hecho ningún swaps. Así que por eso nuestra condición aquí es ", mientras que algunos elementos han sido cambiados. Así que ahora vamos a ver esto que se ejecuta en una lista. Tengo la lista 5,0,1,6,4. Ordenamiento de burbuja va a comenzar todo el camino a la izquierda, y va a comparar Los elementos que, de modo 0 a i + 1, que es el elemento 1. Va a decir, bueno 5> 0, pero en este momento 5 es a la izquierda, así que tengo que cambiar el 5 y el 0. Cuando les intercambiar, de repente me sale este lista diferente. Ahora 5> 1, por lo que vamos a intercambiarlas. 5 no es> 6, por lo que no tiene que hacer nada aquí. Pero 6> 4, por lo que tenemos que cambiar. Una vez más, tenemos que repasar la lista entera para descubrir finalmente que éstas están fuera de servicio, nos cambiarlos, y en este momento tenemos que pasar por la lista 1 hora más para asegurarse de que todo está en su orden, y en este tipo burbuja punto ha terminado. Un algoritmo diferente para tomar algunos elementos y ordenarlos es una especie de selección. La idea detrás de ordenación por selección es que vamos a construir una parte ordenada de la lista 1 elemento a la vez. Y la forma en que vamos a hacerlo es construyendo el segmento izquierdo de la lista. Y en el fondo, todos - en cada paso, vamos a tener el más mínimo elemento que nos queda que no ha sido aún ordenado, y nos vamos a mover en ese segmento ordenada. Eso significa que tenemos que encontrar continuamente el elemento mínimo sin clasificar y luego tomar ese elemento mínimo e intercambiarlo con lo dejó a la mayoría de elementos que no está ordenada. El tiempo de ejecución de que esto va a ser O (n ²) porque en el peor de los casos tenemos que comparar cada elemento a todos los demás elementos. Debido a que estamos diciendo que si empezamos en la mitad izquierda de la lista, es necesario ir a través de todo el segmento derecho para encontrar el elemento más pequeño. Y entonces, de nuevo, tenemos que ir sobre el segmento de la derecha y todo seguir repitiendo una y otra y otra vez. Eso va a ser ² n. Vamos a necesitar un lazo para el interior de otro bucle for lo que sugiere ² n. En el pensamiento mejor de los casos, vamos a decir que le damos una lista ya ordenada; que en realidad no hacen nada mejor que ² n. Por tipo de selección no tiene manera de saber que el elemento mínimo es el que sucede a mirar. Todavía necesita para asegurarse de que esto es realmente mínimo. Y la única manera de asegurarse de que es el mínimo, utilizando este algoritmo, es mirar cada elemento nuevo. Así que en realidad, si le dan - si se le da una lista de ordenación por selección ya clasificada, que no va a hacer nada mejor que darle una lista que no está ordenada todavía. Por cierto, si pasa a ser el caso de que algo es O (algo) y el omega de algo, sólo puedo decir más brevemente que es θ de algo. Así que si ves que surgen en cualquier parte, eso es lo que eso significa. Si algo es theta de ² n, es a la vez grande O (n ²) y Ω (n ²). Así que lo mejor y el peor caso, no hace ninguna diferencia, el algoritmo se va a hacer la misma cosa cada vez. Así que esto es lo que pseudocódigo para ordenar selección podría ser similar. Estamos básicamente va a decir que quiero para iterar sobre la lista de izquierda a derecha, y en cada iteración del bucle, voy a mover el elemento mínimo en esta porción de la lista ordenada. Y una vez que me muevo algo allí, no tengo que mirar a ese elemento nuevo. Porque tan pronto como cambiar un elemento en el segmento izquierdo de la lista, se ordenan porque estamos haciendo todo en orden ascendente utilizando mínimos. Entonces dijimos, bueno, estamos en la posición i, y tenemos que mirar todos los elementos a la derecha de i con el fin de encontrar el mínimo. Así que eso significa que queremos mirar desde i + 1 hasta el final de la lista. Y ahora, si el elemento que estamos mirando es menor que nuestro mínimo hasta el momento, que, recordemos, estamos empezando el descuento mínimo para ser justo cualquier elemento que estamos actualmente, voy a asumir que es el mínimo. Si encuentro un elemento que es más pequeño que eso, entonces yo voy a decir, bueno, Bueno, he encontrado un nuevo mínimo. Voy a recordar dónde estaba ese mínimo. Así que ahora, una vez que haya pasado por ese segmento sin clasificar derecho, Puedo decir que voy a cambiar el elemento mínimo con el elemento que se encuentra en la posición i. Eso va a construir mi lista, mi porción ordenada de la lista de izquierda a derecha, y no alguna vez tiene que ver un elemento de nuevo una vez que esté en esa parte. Una vez que lo hemos cambiado. Así que vamos a ejecutar la ordenación por selección en esta lista. El elemento azul aquí va a ser la i, y el elemento rojo va a ser el elemento mínimo. Así que comienza todo el camino a la izquierda de la lista, por lo menos 5. Ahora tenemos que encontrar el elemento unsorted mínimo. Por eso decimos 0 <5, por lo que 0 es mi nuevo mínimo. Pero no puede quedarse ahí, porque aunque podemos reconocer que 0 es el más pequeño, tenemos que pasar por todos los demás elementos de la lista para asegurarse. Así 1 es más grande, es más grande 6, 4 es más grande. Esto significa que después de ver todos estos elementos, he determinado 0 es el más pequeño. Así que voy a cambiar el 5 y el 0. Una vez que cambie eso, me voy a poner una nueva lista, y sé que nunca tengo que mirar en ese 0 de nuevo porque una vez que lo he cambiado, lo he clasificado y ya está. Ahora da la casualidad de que el elemento azul vuelve a ser el 5, y tenemos que mirar a la 1, la 6 y la 4 para determinar que una Es el elemento más pequeño de menos, así que vamos a cambiar el 1 y el 5. Una vez más, tenemos que mirar - comparar el 5 y el 6 y el 4, y vamos a cambiar el 4 y el 5, y, finalmente, comparar, esos 2 números e intercambiarlos hasta que tengamos nuestra lista ordenada. Cualquier pregunta sobre tipo de selección? Bien. Pasemos al último tema aquí, y que es la recursividad. La recursividad, recuerde, es esta cosa meta realmente donde una función repetidamente se llama. Entonces, en algún momento, mientras que nuestro succion en repetidas ocasiones que se hace llamar, tiene que haber algún punto en el que dejamos de llamarnos. Porque si no hacemos eso, entonces sólo vamos a seguir haciendo esto para siempre, y nuestro programa no sólo va a terminar. Llamamos a esta condición, el caso base. Y el caso base, dice, en lugar de llamar a una función más, Sólo voy a volver algún valor. Así que una vez que hemos devuelto un valor, hemos dejado de llamar a nosotros mismos, y el resto de las llamadas que hemos hecho hasta ahora también pueden regresar. Lo contrario de la hipótesis de base es el caso recursivo. Y aquí es cuando queremos hacer otra llamada a la función que se encuentra, Y es probable que, aunque no siempre, se desea utilizar diferentes argumentos. Así que si tenemos una función llamada f, y f acaba de llamar a tomar un argumento, y nos siguen llamando f (1), f (1), f (1), y da la casualidad de que el argumento cae en un caso recursivo, estamos todavía nunca va a parar. Incluso si tenemos un caso base, hay que asegurarse de que a la larga nos va a golpear ese caso base. No nos limitamos a seguir permaneciendo en este caso recursivo. Por lo general, cuando nos llame, nosotros probablemente vamos a tener un argumento diferente cada vez. He aquí una función recursiva realmente simple. Así que esto va a calcular el factorial de un número. Encima de la tapa aquí tenemos a nuestro caso base. En el caso de que n ≤ 1, no vamos a llamar a factorial de nuevo. Vamos a parar, sólo vamos a devolver algún valor. Si esto no fuera cierto, entonces vamos a golpear nuestro caso recursivo. Nótese aquí que no sólo estamos llamando factorial (n), porque eso no sería muy útil. Vamos a llamar a factorial de otra cosa. Y para que pueda ver, con el tiempo si pasamos algo factorial (5) o, vamos a llamar a factorial (4) y así sucesivamente, y al final nos va a golpear este caso base. Así que esto tiene buena pinta. Vamos a ver qué pasa cuando realmente ejecutar este. Se trata de la pila, y digamos que principal va a llamar a esta función con un argumento (4). Así que una vez factorial ve y = 4, factorial se llamará. Ahora, de repente, tenemos factorial (3). Así pues, estas funciones se va a seguir creciendo hasta que finalmente llegamos a nuestro caso base. En este punto, el valor de retorno de ello es el retorno (nx el valor de retorno de esta), el valor de retorno de esta nx es el valor de retorno de esta. Finalmente, tenemos que llegar a algún número. En la parte superior aquí, decimos return 1. Esto significa que una vez que regrese a ese número, que puede hacer estallar este de la pila. Así que este factorial (1) está hecho. Cuando uno regresa, esta factoriales (1) devoluciones, este retorno a 1. El valor de retorno de esta, recordemos, era nx el valor de retorno de esta. Entonces, de repente, este hombre sabe que quiero volver 2. Así que recuerda, devolver el valor de esto es sólo el valor de retorno nx aquí. Así que ahora podemos decir 3 x 2, y, por último, aquí podemos decir esto va a ser de 4 x 3 x 2. Y una vez que esto vuelva, nos ponemos manos a un solo número entero dentro del principal. ¿Tiene preguntas sobre la recursividad? Está bien. Así que no hay más tiempo para preguntas al final, pero ahora Joseph cubrirá los temas restantes. [Joseph Ong] De acuerdo. Así que ahora que hemos hablado de recurrencias, vamos a hablar un poco sobre lo que merge sort es. Combinar tipo es básicamente otra manera de ordenar una lista de números. Y la forma en que funciona es, con una especie de mezcla tiene una lista, y es lo que hacemos decimos, vamos a dividirla en dos mitades. En primer lugar, se quedará sin fundirse de nuevo tipo en la mitad izquierda, entonces vamos a correr merge sort en la mitad derecha, y eso nos da ahora dos mitades que se ordenan, y ahora vamos a combinar las mitades. Es un poco difícil de ver sin un ejemplo, así que vamos a seguir todo el procedimiento y ver qué pasa. Así que empezar con esta lista, se lo divide en dos mitades. Corremos merge sort en la mitad izquierda primero. Así que esa es la mitad izquierda, y ahora ejecuta a través de esta lista otra vez que se pasa en una especie de mezcla, y luego nos vemos, de nuevo, en el lado izquierdo de esta lista y se corre fusionar tipo sobre el mismo. Ahora, nos ponemos manos a una lista de números 2, y ahora la mitad izquierda es sólo un elemento de largo, y no podemos dividir una lista que es sólo un elemento en la mitad, por lo que acaba de decir, una vez que tengamos 50, que es sólo un elemento, ya está solucionado. Una vez que hayamos terminado con esto, podemos ver que podemos pasar a la parte derecha de esta lista, y 3 también se clasifican, por lo que ahora que las dos mitades de esta lista están ordenadas podemos unir estos números de nuevo juntos. Así que vemos 50 y 3; 3 es menor que 50, lo que va en primer lugar y luego 50 entra Ahora, eso está hecho, volvemos a esa lista y ordenar es la mitad derecha. 42 es su propio número, así que ya ordenados. Así que ahora comparamos estos 2 y 3 es menor que 42, por lo que se puso en primer lugar, ahora de 42 años se puso en, y el 50 se pone adentro Ahora, que está clasificado, vamos todo el camino hasta la cima, 1337 y 15. Bueno, ahora nos fijamos en la parte izquierda de esta lista; 1337 es por sí mismo lo que es ordenado y lo mismo con 15. Así que ahora combinamos estos dos números para ordenar la lista original, 15 <1337, lo que va en primer lugar, a continuación, va in 1337 Y ahora nos ordenan las dos mitades de la lista original hasta la parte superior. Y todo lo que tienes que hacer es combinar estos. Nos fijamos en los 2 primeros números de esta lista, 3 <15, por lo que entra en la matriz primero ordenar. 15 <42, así que va pulg Ahora, 42 <1337, que va in 50 <1337, por lo que va in Y note que sólo tardó 2 números fuera de esta lista. Así que no sólo estamos alternando entre las dos listas. Estamos viendo el principio, y estamos tomando el elemento que es más pequeño y luego ponerlo en nuestra matriz. Ahora hemos fusionado todos las mitades y ya está. Cualquier pregunta acerca de fusionar tipo? ¿Sí? [Estudiante] Si se trata de dividir en grupos diferentes, ¿por qué no acaba de dividir una vez y tiene 3 y 2 en un grupo? [Resto pregunta ininteligible] La razón - por lo que la pregunta es, ¿por qué no podemos simplemente combinarlos en ese primer paso después de que los tenemos? La razón por la que podemos hacer esto, comience en los elementos de izquierda-la mayoría de ambas partes, y luego tomar la más pequeña y la puso adentro, es que sabemos que estos listas individuales de los pedidos ordenados. Así que si estoy mirando a los elementos más a la izquierda de las dos mitades, Yo sé que van a ser los elementos más pequeños de esas listas. Así que puedo ponerlos en los lugares más pequeños elementos de esta larga lista. Por otro lado, si miro a esos dos listas en el segundo nivel de allá, 50, 3, 42, 1337 y 15, los que no están ordenadas. Así que si miro a los 50 y 1337, me voy a poner 50 en mi primera lista. Pero eso no tiene mucho sentido, ya que 3 es el elemento más pequeño de todos ellos. Así que la única razón por la que podemos hacer este paso se debe a la combinación de nuestras listas ya están ordenados. Es por eso que tenemos que bajar todo el camino hasta el fondo porque cuando tenemos un solo número, usted sabe que un solo número en y de por sí ya es una lista ordenada. ¿Alguna pregunta? No? Complejidad? Bueno, se puede ver que en cada paso hay números finales, y podemos dividir una lista en el registro medio n veces, que es de donde se obtiene este log n x n complejidad. Y verás el mejor de los casos por tipo de combinación es n log n, y que sólo sucede así que el peor de los casos, o la Ω allá, también es n log n. Algo a tener en cuenta. Cambiando de tema, vamos a ir a algún archivo de súper básico I / O. Si se miraba en Scramble, te darás cuenta de que tenía algún tipo de sistema donde se puede escribir en un archivo de registro si usted lee a través del código. Vamos a ver cómo se puede hacer eso. Bueno, tenemos fprintf, que se puede considerar como justo printf, pero sólo imprimir a un archivo en lugar, y por lo tanto la f al principio. Este tipo de código hasta aquí, lo que hace es, como habrás visto en Scramble, pasa a través de la impresión matriz 2-dimensional fuera fila por fila cuáles son los números. En este caso, printf imprime a su terminal o lo que llamamos la salida estándar de sección. Y ahora, en este caso, lo único que tienes que hacer es reemplazar printf con fprintf, dicen que sobre el archivo que desea imprimir y, en este caso, sólo se imprime a ese archivo en lugar de ello imprimiendo a su terminal. Bueno, entonces eso nos lleva a la pregunta: ¿De dónde sacamos este tipo de archivo desde, ¿verdad? Pasamos identifícate para este fuction de fprintf, pero no teníamos idea de dónde vino. Bueno, al principio del código, lo que tuvimos fue este fragmento de código por aquí, que básicamente dice que se puede abrir el archivo log.txt llama. ¿Qué hacemos después de eso es que tenemos que asegurarnos de que el archivo está realmente abierto con éxito. Así que puede fallar por múltiples razones, usted no tiene suficiente espacio en su ordenador, por ejemplo. Así que siempre es importante antes de hacer cualquier operación con el archivo que comprobamos si ese archivo se abrió correctamente. Así que lo que a, ese es un argumento a fopen, bueno, puede abrir un archivo de muchas maneras. Lo que podemos hacer es que se lo puede transmitir w, lo que significa reemplazar el archivo si sale ya, Podemos pasar una a, que añadir al final del archivo en lugar de que sea redefinido, o podemos especificar r, es decir, vamos a abrir el archivo como de sólo lectura. Así que si el programa intenta realizar cambios en el archivo, gritar en ellos y no dejes que lo hagan. Finalmente, una vez que hayamos terminado con el archivo, hecha realizar operaciones en él, tenemos que asegurarnos de que cierre el archivo. Y así, al final de su programa, que va a pasar de nuevo el archivo que ha abierto, y simplemente cerrarla. Así que esto es algo importante que hay que asegurarse de que usted lo hace. Así que recuerde que puede abrir un archivo, entonces se puede escribir en el archivo, realizar operaciones en el archivo, pero luego se va a cerrar el archivo al final. Cualquier pregunta sobre el archivo de base de E / S? ¿Sí? [Pregunta Estudiante, ininteligible] Aquí mismo. La pregunta es, ¿de dónde viene este archivo log.txt aparecer? Bueno, si sólo le dan log.txt, se crea en el mismo directorio que el ejecutable. Así que si TU ESTAS - >> [pregunta Estudiante, ininteligible] Sí. En la misma carpeta, o en el mismo directorio, como usted lo llama. Ahora la memoria, pila y pila. Entonces, ¿cómo es la memoria se establece en la computadora? Bueno, se puede imaginar como una especie de memoria de este bloque aquí. Y en la memoria que tenemos lo que se llama el montón atrapado allí, y la pila que está ahí abajo. Y la pila crece hacia abajo y la pila crece hacia arriba. Así como Tommy mencionó - oh, bueno, y tenemos estas otras 4 segmentos que voy a llegar en un segundo - Como Tommy dicho antes, usted sabe cómo se llaman sus funciones y llamar a los demás? Ellos construyen este tipo de marco de pila. Bueno, si los principales llamadas foo, foo se ponen en la pila. Foo llama bar, bar llegar a poner en la pila, y que se ponen en la pila después. Y al regresar, cada uno de ellos se llevan de la pila. ¿Qué cada uno de estos lugares y mantener la memoria? Pues bien, la parte superior, que es el segmento de texto, contiene el programa en sí. Así que el código máquina, que está ahí, una vez que se compila el programa. A continuación, cualquier inicializa las variables globales. Así que hay variables globales en su programa, y ​​como usted dice, a = 5, que se puso en ese segmento, y justo debajo de eso, Tiene datos globales no inicializados, que se acaba de int a, pero no te dicen que es igual a nada. Darse cuenta de que estas son variables globales, por lo que están fuera de la principal. Así que esto significa que las variables globales que se declaran pero no se inicializa. Así que lo que está en el montón? La memoria asignada con malloc, que vamos a llegar a un poco. Y, por último, con la pila tiene alguna variables locales y cualquier otra función que se podría llamar en cualquiera de sus parámetros. La última cosa que usted realmente no tiene que saber cuáles son las variables de entorno hacen, pero cada vez que se ejecute el programa, hay algo asociado, al igual que este es el nombre de la persona que ejecutó el programa. Y eso va a ser una especie de en la parte inferior. En términos de direcciones de memoria, que son valores hexadecimales, los valores al comienzo superior a 0, y van todo el camino hasta el fondo. En este caso, si usted está en el sistema de 32-bit, la dirección al final va a ser 0x, seguido por af, porque eso es 32 bits, que es de 8 bytes, y en este caso 8 bytes corresponde a 8 dígitos hexadecimales. Así que aquí va a tener, como, 0xffffff, y allí vas a tener 0. ¿Cuáles son los punteros? Algunos de ustedes no han cubierto esto en la sección anterior. pero sí que fuimos a través de ella en la conferencia, por lo que un puntero es sólo un tipo de datos que almacena, en lugar de algún tipo de valor como 50, que almacena la dirección de algún lugar en la memoria. Al igual que la memoria [ininteligible]. Así que en este caso, lo que tenemos es, tenemos un puntero a un entero o un int *, y contiene la siguiente dirección hexadecimal de 0xLOQUESEA. Así que lo que tenemos es, ahora, este puntero en algún lugar de la memoria, y eso es sólo una, el valor 50 está en esta posición de memoria. En algunos sistemas de 32-bit, en todos los sistemas de 32-bit, los punteros ocupan 32 bits o 4 bytes. Pero, por ejemplo, en un sistema de 64-bit, los punteros son de 64 bits. Así que eso es algo que usted querrá tener en cuenta. Así en un sistema de extremo de bits, un puntero es cantoneras de largo. Los punteros son un poco difícil de digerir sin cosas extras, así que vamos a ir a través de un ejemplo de asignación de memoria dinámica. ¿Qué asignación de memoria dinámica hace por usted, o lo que llamamos malloc, le permite asignar un tipo de datos fuera del set. Así que este tipo de datos es más permanente para la duración del programa. Porque, como usted sabe, si usted declara x dentro de una función, y que recupera el funcionamiento, que ya no tienen acceso a los datos almacenados en x. ¿Qué indicadores vamos a hacer es que vamos a almacenar los valores de la memoria o la tienda en un segmento diferente de la memoria, es decir, el montón. Ahora, una vez que regresemos de la función, siempre que tenemos un puntero a esa ubicación en la memoria, entonces lo que podemos hacer es simplemente podemos ver los valores allí. Veamos un ejemplo: Este es nuestro nuevo diseño de la memoria. Y tenemos esta función principal. Lo que hace es - está bien, tan simple, derecho - int x = 5, que es sólo una variable en la pila en principal. Por otro lado, ahora se declara un puntero que llama a los giveMeThreeInts función. Y ahora entramos en esta función y se crea un nuevo marco de pila para ello. Sin embargo, en este marco de pila, declaramos int * temp, que en mallocs 3 enteros para nosotros. Así que el tamaño de int nos dará la cantidad de bytes esto es int, malloc y nos da que muchos bytes de espacio en el montón. Así que en este caso, hemos creado un espacio suficiente para 3 números enteros, y el montón está ahí arriba, y por eso lo he dibujado más arriba. Una vez que hayas terminado, volvemos aquí, sólo necesita 3 enteros devueltos, y devuelve la dirección, en este caso más que donde la memoria es. Y nos pusimos puntero = interruptor, y allí tenemos más que otro puntero. Pero lo que devuelve la función se apila aquí, y desaparece. Así temperatura desaparece, pero todavía mantienen la dirección de donde esos 3 números enteros se encuentran dentro de la red. Así que en este juego, los punteros están en el ámbito local para el marco de apilado, pero la memoria a la que se refieren es en el montón. ¿Eso tiene sentido? [Estudiante] ¿Podría repetir eso? >> [Joseph] Sí. Así que si me vuelvo un poco, se ve que la temperatura asignada parte de la memoria en el montón hasta allí. Por eso, cuando esta función, giveMeThreeInts devoluciones, esta pila de aquí va a desaparecer. Y con ello ninguna de las variables, en este caso, este puntero que se ha asignado en el marco de apilado. Eso va a desaparecer, pero desde que regresamos temp y nos pusimos puntero = temp, puntero ahora va a apuntar la misma memoria de la ubicación como la temperatura era. Así que ahora, a pesar de que pierda temperatura, ese puntero local, que aún conservan la dirección de memoria de lo que estaba señalando hacia el interior de ese indicador variable. ¿Preguntas? Eso puede ser un poco de un tema confuso si usted no ha pasado por encima de la sección. Podemos, su TF duda alguna sobre el mismo y, por supuesto, podemos responder a las preguntas al final de la sesión de revisión para esto. Pero esto es una especie de un tema complejo, y no tengo más ejemplos que van a aparecer que ayudará a aclarar lo que en realidad son punteros. En este caso, los punteros son equivalentes a las matrices, por lo que sólo puede utilizar este indicador como la misma cosa como una matriz int. Así que estoy de indización en 0, y cambiando el primer número entero de 1, cambiando el segundo número entero de 2, y el entero tercero a 3. Así que más de punteros. Bueno, recuerdo Binky. En este caso hemos asignado un puntero, o que declaramos un puntero, pero al principio, cuando me acaba de declarar un puntero, no está apuntando a cualquier parte de la memoria. Son sólo los valores de basura en el interior de la misma. Así que no tengo idea de donde este indicador está apuntando. Tiene una dirección que se acaba de llenar con 0 y 1, donde se declaró inicialmente. No puedo hacer nada con esto hasta que yo llamo malloc en él y luego me da un poco de espacio en el montón donde puedo poner los valores en el interior. Por otra parte, yo no sé lo que hay dentro de esta memoria. Así que lo primero que tienes que hacer es comprobar si el sistema tiene suficiente memoria que me devuelva un número entero, en primer lugar, por lo que yo estoy haciendo esta comprobación. Si el puntero es nulo, lo que significa que no tiene suficiente espacio o algún otro error, así que debería salir de mi programa.  Pero si se tuvo éxito, ahora puedo usar ese puntero y lo que hace es * puntero se deduce que la dirección es a donde ese valor es, y lo pone igual a 1. Así que aquí, estamos comprobando si dicha memoria existido. Una vez que se sabe que existe, puede poner en él cuál es el valor que desea poner en él, en este caso 1. Una vez que haya terminado con ella, la necesidad de liberar ese puntero porque tenemos que volver al sistema que la memoria que usted solicitó en primer lugar. Debido a que el equipo no sabe cuando hayamos terminado con él. En este caso estamos diciendo explícitamente, está bien, hemos terminado con esa memoria. Si algún otro proceso que necesita, algún otro programa que necesita, no dude en seguir adelante y tomarlo. Lo que también se puede hacer es que sólo se puede obtener la dirección de las variables locales en el set. Así int x está dentro del marco de apilado principal. Y cuando utilizamos este signo, este y el operador, lo que hace es Se tarda x, y x es sólo algunos datos en la memoria, pero que tiene una dirección. Se encuentra ubicado en algún lugar. Entonces, llamando & x, lo que esto hace es que nos da la dirección de x. Al hacer esto, estamos haciendo puntero al punto donde x está en la memoria. Ahora sólo nos queda hacer algo como * x, vamos a llegar al 5 de vuelta. La estrella se llama eliminación de referencias a él. Siga la dirección y se obtiene el valor de la misma se almacena allí. ¿Alguna pregunta? ¿Sí? [Estudiante] Si usted no hace la cosa tres puntas, ¿sigue teniendo compilar? Sí. Si usted no hace la cosa de 3-puntos, que todavía va a compilar, pero te voy a mostrar lo que pasa en un segundo, y sin hacer eso, eso es lo que llamamos una pérdida de memoria. Usted no está dando el sistema copias de su memoria, así que después de un tiempo el programa se va a acumular memoria que no está utilizando, y nada más pueda usarlo. Si alguna vez has visto a Firefox con 1,5 millones de kilobytes en su computadora, en el administrador de tareas, eso es lo que está pasando. Usted tiene una pérdida de memoria en el programa que no está manejando. Entonces, ¿cómo hace el trabajo puntero aritmética? Bueno, la aritmética de punteros es una especie de indexación como en una matriz. En este caso, tengo un puntero, y lo que yo hago es hacer punto puntero al primer elemento de esta serie de tres números enteros que he asignado. ¿Y ahora qué hago, puntero estrella sólo cambia el primer elemento de la lista. Estrella puntero +1 puntos aquí. Así puntero está por aquí, un puntero es por aquí, puntero +2 es por aquí. Así sólo añadir 1 es lo mismo que mover a lo largo de esta matriz. Lo que hacemos es, cuando hacemos un puntero a obtener la dirección por aquí, y con el fin de obtener el valor de aquí, se pone una estrella en toda la expresión de para eliminación de referencias. Así, en este caso, me estoy dando el primer lugar en esta matriz a 1, ubicación a 2 segundos, y tercera ubicación a 3. Entonces, ¿qué estoy haciendo aquí es que estoy imprimiendo nuestro puntero +1, que sólo me da 2. Ahora estoy incrementando puntero, por lo que es igual puntero puntero +1, que se mueve hacia delante. Y ahora si me imprima un puntero, puntero +1 es ahora 3 años, que en este caso se imprime 3. Y para algo gratis, el puntero que le doy debe apuntar al principio de la matriz que volví de malloc. Así que, en este caso, si yo tuviera que llamar 3 aquí, esto no sería correcto, porque está en el centro de la matriz. Tengo que resta para llegar a la ubicación original el acto inicial antes de que pueda liberarlo. Por lo tanto, aquí hay un ejemplo más complicado. En este caso, estamos asignando 7 caracteres en una matriz de caracteres. Y en este caso lo que estamos haciendo es que estamos recorrer los 6 primeros de ellos, y los estamos estableciendo a la Z. Así, por int i = 0, i> 6, i + +, Por lo tanto, el puntero + i sólo nos dará, en este caso, puntero, puntero +1, 2 puntero, puntero 3, y así sucesivamente y así sucesivamente en el bucle. ¿Qué va a hacer es que llegue esa dirección, desreferencia para obtener el valor, y que los cambios a un valor Z. Luego, al final recuerda que esto es una cadena, ¿no? Todas las cadenas tienen que terminar con el carácter nulo de terminación. Por lo tanto, lo que hago es en puntero 6 puse el carácter terminador nulo pulg Y ahora lo que estoy haciendo básicamente aquí está implementando printf para una cadena, ¿no? Así que, ¿cuándo printf ahora cuando se ha llegado al final de una cadena? Cuando llegue el carácter nulo de terminación. Así, en este caso, mis puntos puntero original al principio de esta matriz. Puedo imprimir el carácter primero en salir. Lo muevo a través de uno. Puedo imprimir ese personaje. Lo muevo de nuevo. Y sigo haciendo esto hasta que llegue al final. Y ahora el puntero * Final voluntad dereference esto y el carácter nulo de terminación de vuelta. Y así mi bucle while se ejecuta sólo cuando ese valor no es el carácter nulo de terminación. Así que, ahora salgo de este bucle. Y por lo que si le resto 6 de este indicador, Vuelvo hasta el final hasta el principio. Recuerda, yo estoy haciendo esto porque tengo que ir al principio con el fin de liberarla. Por lo tanto, sé que era mucho. ¿Hay alguna pregunta? Por favor, ¿sí? [Ininteligible pregunta Estudiante] ¿Se puede decir que más fuerte? Lo siento. [Estudiante] En la última diapositiva justo antes de que liberó al puntero, donde estabas realmente cambiar el valor del puntero? [José] Por lo tanto, aquí mismo. >> [Estudiante] Oh, está bien. [José] Por lo tanto, tengo un puntero menos negativo, derecha, que mueve la cosa de nuevo, y luego lo libere, porque este puntero tiene que ser señalado al principio de la matriz. [Estudiante] Pero eso no sería necesario que se detuvo después de esa línea. [José] Así que, si me hubiera detenido después de esto, esto sería considerado una pérdida de memoria, porque no se ha ejecutado el programa gratuito. [Estudiante] I [ininteligible] después de las tres primeras líneas donde tenías puntero +1 [ininteligible]. [José] Uh-huh. Entonces, ¿cuál es la pregunta que hay? Lo siento. No, no. Vaya, vaya, por favor. [Estudiante] Por lo tanto, no estamos cambiando el valor de punteros. No habría tenido que hacer puntero menos negativo. [José] Sí, exactamente. Por lo tanto, cuando hago un puntero y el puntero +2, No voy a hacer puntero es igual a un puntero. Por lo tanto, el puntero sólo se queda apuntando al principio de la matriz. Es sólo cuando lo hago plus plus que establece el valor de nuevo en el puntero, que en realidad se mueve a lo largo de este. Está bien. Más preguntas? Una vez más, si esto es una especie de insoportable, esto se tratará en la sesión. Pregúntele a su compañero de enseñanza en ello, y podemos responder a las preguntas al final. Y por lo general no nos gusta que hagas esto menos. Esto tiene que me exigen hacer el seguimiento de lo mucho que he posición de la matriz. Así que, en general, esto es sólo para explicar cómo funciona la aritmética de punteros. Pero lo que normalmente queremos hacer es que nos gusta para crear una copia del puntero, y luego vamos a utilizar esa copia cuando nos movemos alrededor de la cadena. Por lo tanto, en estos casos se utiliza la copia para imprimir toda la cadena, pero no tenemos que hacer como puntero menos 6 o llevar un registro de cuánto nos trasladamos en esto, sólo porque sabemos que nuestro punto original sigue señaló el comienzo de la lista y todo lo que fue alterado esta copia. Así, en general, modificar las copias de su puntero original. No trate de algo así como - no alterar las copias originales. Tratar de alterar únicas copias de su original. Así, se da cuenta cuando pasamos la cadena en printf usted no tiene que poner una estrella en la frente de ella como lo hicimos con todos los desreferencia otros, ¿no? Por lo tanto, si imprime la cadena s% espera que todo es una dirección, y en este caso un puntero o en este caso como una matriz de caracteres. Personajes, char * s, y las matrices son la misma cosa. Pointer es caracteres y matrices de caracteres son la misma cosa. Y así, todo lo que tenemos que hacer es pasar puntero. No tenemos que pasar como puntero * ni nada de eso. Por lo tanto, las matrices y los punteros son la misma cosa. Cuando estás haciendo algo como x [y] por aquí por una matriz, lo que está haciendo bajo el capó es lo que está diciendo, está bien, se trata de una matriz de caracteres, por lo que es un puntero. Y así, x son la misma cosa, y por lo tanto lo que hace es que añade yax, lo que es lo mismo que mover hacia adelante en la memoria que mucho. Y ahora x + y nos da algún tipo de dirección, y eliminar la referencia al domicilio o siga la flecha a donde esa ubicación en la memoria es y obtenemos el valor de dicha ubicación en la memoria. Así, por lo que estos dos son exactamente la misma cosa. Es sólo una manera de expresar. Ellos hacen lo mismo. Son sólo sintáctica diferentes entre sí. Así que, ¿qué puede ir mal con punteros? Al igual, mucho. Bien. Así, las cosas malas. Algunas de las cosas malas que puede hacer no está comprobando si su llamada malloc devuelve un valor nulo, ¿no? En este caso, estoy pidiendo al sistema que me diera - ¿Cuál es ese número? Como 2 mil millones de veces 4, debido a que el tamaño de un entero de 4 bytes. Lo estoy pidiendo como 8 millones de bytes. Por supuesto, mi equipo no va a ser capaz de darme vuelta que mucha memoria. Y no comprobar si este es nulo, por lo que cuando tratamos de eliminar la referencia que allí - siga la flecha a donde se va a - no tenemos esa memoria. Esto es lo que llamamos la eliminación de referencias a un puntero nulo. Y esto hace que esencialmente violación de segmento. Esta es una de las formas en que puedes violación de segmento. Otras cosas malas que usted puede hacer - bueno. Eso fue desreferencia un puntero nulo. Bien. Otras cosas malas - bueno, al fijar que usted acaba de poner un cheque en allí que comprueba si el puntero es nulo y salir del programa si ocurre que malloc devuelve un puntero nulo. Ese es el cómic xkcd. La gente lo entiendo ahora. Casi. Así, la memoria. Y me fui por esto. Estamos llamando a malloc en un bucle, pero cada vez que llamamos a malloc estamos perdiendo la pista de donde este indicador hace referencia, porque lo estamos golpeando fuertemente. Por lo tanto, la primera llamada a malloc me da memoria aquí. Mis punteros punteros a esto. Ahora, yo no lo liberará, así que ahora yo llamo malloc nuevo. Ahora apunta hacia aquí. Ahora mi memoria apunta hasta aquí. Apuntando hacia aquí. Apuntando hacia aquí. Pero he perdido la cuenta de las direcciones de toda la memoria por aquí que me asignaron. Y ahora no tengo ninguna referencia a ellos nunca más. Por lo tanto, no puedo liberarlos fuera de este bucle. Y así, con el fin de fijar algo como esto, si se olvida de la memoria libre y se obtiene esta pérdida de memoria, Hay que liberar la memoria dentro de este bucle una vez que haya terminado con él. Bueno, esto es lo que sucede. Sé que muchos de ustedes odian esto. Pero ahora - yay! Se obtiene como 44.000 kilobytes. Así, que se libre en el extremo del bucle, y eso va a liberar sólo la memoria cada vez. En esencia, el programa no tiene una pérdida de memoria más. Y ahora otra cosa que puedes hacer es liberar la memoria que usted ha pedido dos veces. En este caso, es algo malloc, cambia su valor. Usted se libre una vez porque dijiste que habías terminado con ella. Pero luego lo liberó de nuevo. Esto es algo que es bastante malo. No va a violación de segmento al principio, pero después de un rato lo que esto hace es liberar esta doble corrompe la estructura de montón, y usted aprenderá un poco más sobre esto si usted decide tomar una clase como CS61. Pero esencialmente después de un tiempo el equipo va a confundirse acerca de lo que las posiciones de memoria donde están y hacia dónde se almacena - donde los datos se almacenan en la memoria. Y así liberar un puntero dos veces es una mala cosa que no quiero hacer. Otras cosas que pueden salir mal no está usando sizeof. Así que, en este caso malloc 8 bytes, y eso es lo mismo que dos enteros, ¿no? Entonces, eso es perfectamente seguro, pero lo es? Bueno, como Lucas habló sobre diferentes arquitecturas, enteros son de longitudes diferentes. Por lo tanto, el aparato que está utilizando, los enteros son alrededor de 4 bytes, pero en algún otro sistema que podría ser de 8 bytes o pueden ser 16 bytes. Por lo tanto, si sólo utilizan este número para acá, este programa puede trabajar en el aparato, pero no va a asignar suficiente memoria en algún otro sistema. En este caso, esto es lo que el operador sizeof se utiliza para. Cuando llamamos a sizeof (int), lo que hace es  que nos da el tamaño de un entero en el sistema que se ejecuta el programa. Así, en este caso, sizeof (int) devolverá 4 en algo como el aparato, y ahora esta voluntad 4 * 2, que es 8, que es sólo la cantidad de espacio necesario para dos enteros. En un sistema diferente, si un entero es como 16 bytes u 8 bytes que sólo va a volver suficientes bytes para almacenar esa cantidad. Y, por último, las estructuras. Por lo tanto, si desea almacenar una tabla de sudoku en la memoria, ¿cómo podemos hacer esto? Se podría pensar en como una variable para la primera cosa, una variable para la segunda cosa, una variable para la tercera cosa, una variable para la cuarta cosa - malo, ¿verdad? Por lo tanto, una mejora que usted puede hacer sobre esto es hacer una matriz de 9 x 9. Eso está bien, pero lo que si desea asociar otras cosas con la tarjeta de sudoku como lo que la dificultad de la junta es, o, por ejemplo, cuál es su puntaje es, o cuánto tiempo ha tomado usted para resolver este foro? Bueno, lo que puedo hacer es que usted puede crear una estructura. Lo que estoy diciendo es, básicamente, estoy definiendo esta estructura por aquí, y estoy definiendo un tablero de sudoku que consiste en una placa que es 9 x 9. Y lo que tiene que tiene punteros a el nombre del nivel. También cuenta con x e y, que son las coordenadas de donde estoy en estos momentos. También ha tiempo pasado [ininteligible], y tiene el número total de movimientos que he ofrecida hasta ahora. Y así, en este caso, puede agrupar una gran cantidad de datos en una sola estructura en vez de tenerlo como volar alrededor de la misma distintas variables que en realidad no puedo seguir la pista. Y esto nos permite tener sólo sintaxis agradable para hacer referencia a una especie de cosas diferentes dentro de esta estructura. Yo sólo puedo hacer board.board, y me sale el tablero sudoku espalda. Board.level, me sale lo difícil que es. Board.x board.y y me dan las coordenadas de dónde podría estar en el tablero. Y, entonces, acceder a lo que llamamos campos de la estructura. Esto define sudokuBoard, que es un tipo que tengo. Y ahora estamos aquí. Tengo una variable llamada "junta" de sudokuBoard tipo. Y así que ahora puedo acceder a todos los campos que componen esta estructura aquí. Cualquier pregunta acerca de las estructuras? ¿Sí? [Estudiante] Para int x, y, a la vez que declaró en una línea? >> [Joseph] Uh-huh. [Estudiante] Así que, ¿puedes hacer eso con todos ellos? Al igual que en x, Y coma veces que el total? [José] Sí, definitivamente se puede hacer eso, pero la razón por la que poner x e y en la misma línea - y la pregunta es ¿por qué sólo podemos hacer esto en la misma línea? ¿Por qué no sólo hay que poner todo esto en la misma línea es x e y se relacionan entre sí, y esto es sólo estilísticamente más correcto, en cierto sentido, porque es agrupar dos cosas en la misma línea ese tipo de como se refieren a la misma cosa. Y me acaba de romper estos pedazos. Es sólo una cosa estilo. Es funcionalmente no hace ninguna diferencia en absoluto. Cualquier otra pregunta sobre las estructuras? Se puede definir una Pokédex con una estructura. Un Pokémon tiene un número y tiene una carta, un propietario, un tipo. Y entonces, si usted tiene una gran variedad de Pokémon, usted puede hacer una Pokédex, ¿verdad? De acuerdo, genial. Por lo tanto, las preguntas sobre las estructuras. Los que están relacionados con las estructuras. Por último, el BGF. ¿Qué GDB permiten hacer? Le permite depurar el programa. Y si usted no ha utilizado GDB, me recomendó ver el corto y repasando lo que GDB es decir, cómo se trabaja con él, cómo puede usarlo, y probarlo en un programa. Y así lo GDB le permite hacer es que le permite pausar la [ininteligible] su programa y una línea de práctica. Por ejemplo, quiero hacer una pausa en la ejecución como la línea 3 de mi programa, y ya que estoy en la línea 3 que puede imprimir todos los valores que están allí. Y así lo que denominamos como una pausa en una línea Se le llamamos poner un punto de interrupción en esa línea y entonces podremos imprimir las variables en el estado del programa en ese momento. Podemos entonces desde allí paso a paso el programa línea por línea. Y entonces puede mirar en el estado de la pila en el momento. Y así, con el fin de utilizar GDB, lo que hacemos es que llamamos sonido metálico en el archivo C, pero tenemos que pasar la bandera ggdb. Y una vez que hayas terminado con eso nos basta con ejecutar gdb en el archivo de salida resultante. Y para que pueda obtener algo de masa como de texto como este, pero en realidad lo único que tienes que hacer es introducir comandos en el principio. Romper principal pone un punto de ruptura en principal. Lista 400 enumera las líneas de código alrededor de la línea 400. Y así, en este caso, sólo puede mirar alrededor y decir, oh, Quiero establecer un punto de interrupción en la línea 397, que es esta línea, y luego el programa se ejecuta en ese paso y que va a romper. Se va a hacer una pausa allí, y usted puede imprimir, por ejemplo, el valor de baja o alta. Y así hay un montón de opciones que necesita saber, y esta presentación va a subir en el sitio web, así que si lo que desea es hacer referencia a estos o similares las puso en tus hojas de trucos, no dude. Cool. Eso fue Quiz Revisión 0, y vamos a quedar si tiene alguna pregunta. Está bien.  [Aplauso] [CS50.TV]