DAVID MALAN: Bien.
Esto es CS50 y esta es la lección 1.
Recordarán, por supuesto, que hace solo unos días
introdujimos algunas bases de programación e informática,
y de pensamiento computacional, por así decirlo.
Y hoy haremos construcciones con base en estas ideas,
pero comenzaré la transición hacia un aspecto más críptico,
no obstante con un lenguaje mucho más poderoso, básicamente una transición
desde Scratch.
Tuvimos la oportunidad de configurar el problema
desde cero, experimentar con Scratch, arrastrar y soltar las piezas
y recordar que el verdadero objetivo de Scratch,
más allá de tener un poco de diversión para presumir,
lo cual se puede lograr con algo como esto,
es explorar las ideas como bucles, funciones y condiciones.
Quizás algunas expresiones booleanas o eventos.
Realmente depende de cómo se reúnan estos ingredientes.
Hoy introduciremos un lenguaje
que ha existido desde hace varias
décadas, llamado C. Es un lenguaje antiguo
y francamente, después de CS50, es probable que no les guste
utilizar mucho este lenguaje, si alguna vez se da el caso.
Pero ha sido la base para muchos de los lenguajes más modernos que
llegaron después.
Entonces, cerca de la mitad del semestre, cuando hagamos la transición al lenguaje
Python, y luego a SQL, y después a
JavaScript, verán muchas coincidencias en cuanto a principios, sintaxis e ideas.
Y verán que todo lo que hicimos la semana pasada en Scratch
está impregnado de todos estos lenguajes distintos.
Porque al final del día, no aprenderán C en CS50.
No aprenderán Scratch o Python o JavaScript.
Aprenderán bases en ciencias de la computación y, en definitiva,
en herramientas de programación.
Entonces, comenzaremos a traducir algunas de últimas ideas
hacia una apariencia más críptica, sin embargo, serán ideas básicamente
idénticas, de la forma siguiente.
Así que teníamos un programa súper sencillo que simplemente
mostraba en la pantalla de manera predeterminada la frase, hello, world.
Bien, comenzaremos por traducir esto como algo textual,
tal como se hace en la mayoría de los lenguajes de programación,
enfocándonos primero solo en este bloque.
A esta pieza morada del rompecabezas,
¿qué tipo de construcción la llamamos en programación?
Es como una función.
Es un verbo o una acción, que hace algo en Scratch.
MIT decidió ponerlos en color púrpura de manera arbitraria,
pero son consistentes en el programa porque todos son
muy similares en espíritu.
Ahora en C, a partir de hoy y durante las semanas siguientes,
esa misma pieza de color púrpura empezará a verse como esto.
Y la última vez, vislumbramos este printf, hello, world.
Pero tengan en cuenta que hay algunas características notables
más allá de las palabras, hello, world.
Existe un printf y hoy veremos qué representa la f.
Tenemos un paréntesis y acá tenemos también un paréntesis cerrado.
Y ese tipo de equilibrio será importante, no solo intelectualmente, sino también
sintácticamente, porque la computadora
espera que seamos súper precisos.
Las comillas de apertura y de cierre, veremos que encierran las palabras
que se escriben en un programa.
Entonces, aunque la última vez en Scratch escribimos la palabra en un cuadro blanco,
ahora haremos lo mismo en su teclado
pero encerrándolo entre comillas.
Finalmente, tendremos esta molestia, este punto y coma, el cual
muchos lenguajes utilizan y que simplemente quiere decir, fin de la idea.
Para un programador equivale a colocar un punto al final de una oración.
Y se darán cuenta de que, entre las frustraciones
que experimentan los nuevos programadores, incluido yo mismo hace un tiempo,
es que realmente no nos damos cuenta de estas cosas desde el principio.
Y podrían escribir todo desde su lógica y sentirse bien
con su programa, tratar de ejecutarlo y percatarse de que no funciona porque
olvidaron algo tan tonto como esto.
Entonces, el punto clave especial para este día es no
sentirse frustrado por cosas estúpidas.
Definitivamente van a darse de topes contra las paredes, aunque no del todo
cuando vean lo que yo puedo ver después de todos estos años de práctica.
Pero en tan solo algunas semanas comenzarán a notar ciertos patrones.
Y los errores que seguramente cometerán durante la primera semana
serán mucho más obvios durante la segunda, la tercera y las semanas subsiguientes.
Entonces esto podría ser una función en C. Vamos a
combinarlo como un programa completo, como ya vimos la última vez.
Entonces, si tuvieran que implementar este mismo programa,
hello, world en C, estas serían todas las líneas que tendrían que escribir.
No pueden escribir simplemente printf.
Deben configurar primero el programa.
Ahora, ¿por qué ocurre ésto?
Bueno, podemos analizar esto solo con ver algunas de las palabras clave
en este ejemplo de aquí.
Lo resaltado en amarillo es main.
Y algunos humanos decidieron, muchos años atrás,
ya saben, que cuando otro humano escribe un programa,
tiene que llamar a su función, como lo veremos pronto, "main".
La pudieron haber llamado de cualquier otro modo,
pero main era una buena palabra para llamar a la parte principal del programa.
Entonces este es nuestro equivalente a la bandera verde en este lenguaje
llamado C.
Mientras tanto, si destacamos otra palabra clave printf,
será el equivalente, en C, del bloque morado.
Entonces printf únicamente imprimirá algo en la pantalla.
Mientras tanto, lo amarillo que está aquí, es lo que llamaremos una cadena.
Cadena es solo una palabra técnica para una secuencia de caracteres o palabras,
frases, párrafos, o lo que sea.
Entonces lo que ahora está resaltado en amarillo, es una cadena.
Y noten que va junto con printf, como podemos ver.
Si se pone inmediatamente después de la palabra printf, como hello, world,
en el cuadro blanco que está justo después de la palabra say.
Y ahora las cosas se ponen más misteriosas cuando lo resaltado en amarillo es stdio.h.
Definitivamente, hasta ahora es lo más críptico de las palabras clave.
Esto es el soporte para las entradas y salidas estándar.
Y solo es una forma elegante de decir que este archivo, como ya veremos,
está relacionado, de algún modo, con la impresión, lo cual es una salida,
y de algún modo también se relaciona con los teclados, que son la entrada.
Entonces, en algún lugar de ese archivo, veremos este tipo de funcionalidad
que esperarían que una computadora tuviera.
Material de entrada y de salida.
Y entonces veremos que eso es el sitio de donde obtenemos
este tipo de funcionalidad estándar.
Scratch no tiene un equivalente.
Solo es cualquier tipo de trabajo, lo cual es bueno en Scratch.
Mientras tanto, veremos que lo que incluye esta palabra clave,
literalmente, solo dice eso.
Hey computadora, incluye la funcionalidad estándar para entradas y salidas
de manera que pueda hacer algo interesante con mi programa.
Y sin esa línea de código, no podríamos hacer casi nada
en este lenguaje C.
Ahora demos un vistazo a algunas otras piezas del rompecabezas,
algunos conceptos que tal vez son muy simples e intuitivos.
Y luego a lo largo del día haremos parcialmente la transición
para escribir realmente un código, daremos muchos ejemplos reales
y también ejecutamos el código.
Pero la última vez, podrían haber implementado
un bucle infinito, uno que simplemente durara para siempre, con un bloque eterno.
Y en Scratch, podrían tener un bloque para decir algo, o que tuviera
algo más en el interior.
A partir de hoy, las mismas piezas comenzarán a verse un poco raras.
Se verán como esto.
While (true), printf, hello, world.
Y francamente, existe una gran variedad de formas
en las que se podría implementar.
Solo estoy eligiendo la forma más simple, relativamente, o la más convencional.
Pero ¿por qué esto es lo mismo?
Bueno, he resaltado en amarillo la primera línea, while true.
Y si bien, while es una especie de palabra agradable en inglés,
es solo una especie de sugerencia intuitiva de que,
cada vez que ocurra algo, es como una especie de bucle.
Y a la vez, lo que está entre paréntesis es una expresión booleana
que Scratch tiene al arrastrar y soltar
esas piezas en el bloque equivalente cuando se dan las condiciones.
Pero en este caso en particular, solo estamos diciendo while (true).
Entonces (true).
(true) es como un sí.
Y el otro día, dijimos que sí algo es como el número 1, mientras que no es
falso o como el número 0.
Y eso es genial porque si tenemos un mundo de verdadero, falso o un
mundo de sí, no, o un mundo 1, 0, ese maravilloso [INAUDIBLE] para el hardware,
que tenemos en nuestras laptops y en nuestros bolsillos, aquello
que es la informática basada en transistores y electricidad y todo
aquello de lo que ahora vamos a abstraernos.
No importa cómo funciona ahora la electricidad, ni los ceros, ni los unos.
Solo sé que puedo representar unos o ceros, unos o ceros,
o su equivalente (true).
Mientras la lámpara esté encendida, o mientras sea (true), printf hello, world.
Entonces la razón lógica para que el código que
tenemos en la pantalla imprima hello, world, para siempre
es porque así debe ser, como si nunca hubiéramos apagado la lámpara.
Así es mientras pemanezca encendida.
Sigue haciendo lo mismo, lo mismo y lo mismo, una y otra
y otra vez, al igual que en Scratch.
Mientras tanto, también podríamos hacer lo siguiente
después de varias iteraciones de eso.
Podríamos tener un número finito de iteraciones con este bloque de repetición.
Este dice, por supuesto, repite lo siguiente 50 veces.
Ahora este, de seguro, se verá un poco más feo.
Esta es, probablemente, la forma más convencional
de traducir este bloque de Scratch a C. Ahora parece ser mucho a la vez,
pero una vez más, después de un par de días o de semanas,
comenzarán a ver los patrones.
Déjenme resaltar algunas de las funciones de este código.
Entonces, resalté aquí, en amarillo, solamente lo que
llamaremos inicialización.
Es como decir, hey computadora, dame una variable y llámala i, solo porque sí,
podría llamarla de cualquier forma,
e inicialízala en 0.
Así que otra vez, como en álgebra, se podría
tener x igual a 0, o y igual a 0 y esto sería igual a 0.
Y a pesar de que no hemos hablado de esto,
podrían adivinar qué hace la palabra clave, int, ¿tal vez significa?
Entero.
Correcto.
Me refiero a que no tuvimos la misma idea en Scratch.
En Scratch, si se desea un número, simplemente se escribe.
Si se desea una palabra, simplemente se escribe.
Pero en C debemos ser un poco más precisos.
Debemos decirle a la computadora el tipo de valor
que se pondrán en las variables.
No solo serán números enteros.
Podemos poner cadenas, o verdaderos y falsos,
o podemos poner otras cosas por el camino.
Así que esto simplemente significa, hey computadora, dame
una variable que contenga un entero, un número como el negativo de 1, 0, 1
y así sucesivamente, pero inicia en 0.
Haz que este número sea 0 de modo predeterminado. Y eso es todo.
Es un modo breve y críptico de decirlo.
Entonces el bloque de este código dice lo siguiente.
Hey computadora, solo para estar seguro, ¿i es menor a 50?
¿Se trata de una expresión booleana verdadera o falsa?
¿Entonces en este momento i es menor a 50?
Obviamente, porque es 0
y por supuesto que es menor que 50.
Entonces la computadora hará lo siguiente.
printf hello, world.
Entonces inicializará la variable.
Comprobará que es menor a cierto número, en este caso a 50.
Y si esa condición es verdadera, imprimirá hello, world.
Y aún cuando ustedes nunca antes hayan visto un código,
quizás por un proceso de eliminación, ¿cuál es, probablemente, el paso siguiente?
Probablemente, ¿qué resaltaré después en la pantalla?
Sí, la i más, más.
Aún no es totalmente obvio lo que hace, pero quizás adivinen que la i más, más
es una forma convencional en este lenguaje para decir, ya saben qué,
sigue y cambia el valor de i por 1.
Así que si 0 se vuelve 1, 1 se volverá 2, 2 se volverá 3, y así sucesivamente.
Pero por ahora, solo cambiamos el 0 por el 1.
Así que en este momento, i es 1.
¿Qué hace la computadora?
Por ahora solo hace muchas repeticiones de las cosas.
Vamos a revisarlo nuevamente, hey, ¿i es menor a 50?
Una pregunta simple.
i es 1, entonces ¿ahora i es menor a 50?
Obviamente lo es.
Y entonces imprimirá de nuevo hello, world.
Entonces se incrementará el valor de i.
Así que ahora será 2.
Se verificará de nuevo esa condición.
¿2 es menor que 50?
Sí, obviamente.
Y entonces imprimirá de nuevo hello, world.
Luego, se incrementará de nuevo el valor de i y se convertirá en 3.
Se verificará de nuevo esa condición.
¿3 es menor que 50?
Obviamente.
Y entonces imprimirá de nuevo hello, world.
Y continuará con el mismo proceso, ¿pueden adivinar cuántas veces?
50 veces en total, y no queremos aburrirnos con la
historia completa.
i será igual a 50, debido a todo el montón de más, más.
Y en este punto de la historia, la computadora preguntará,
¿es 50 menor que 50?
No, obviamente no.
Y en ese punto, el código detendrá la ejecución.
Y lo que sea que esté por debajo en su programa,
como inferior en su archivo,
es lo que sucederá después, incluso aunque no haya nada descrito allí.
Entonces, de nuevo es críptico.
Pero sigue este patrón.
Y una vez que se sientan cómodos con ese patrón,
serán capaces de escribirlo en un teclado
y sabrán lo que se supone que deben hacer, sin siquiera pensar en ello,
así, metódicamente.
El otro día, quizás ese fue el mayor conjunto de piezas de rompecabezas
con el que hayamos jugado, aunque probablemente es
solo una pequeña parte de algunos de sus propios proyectos en Scratch.
Pero de hecho esto esquematiza bastante bien el código de C.
No es tan colorido como aquel,
pero verán que antes, cuando preguntamos si x era menor que y, en código,
en realidad lucía bastante idéntico.
De hecho, podría ser un poco más sencillo de observar.
Tenemos solo algunos paréntesis.
Tenemos el signo menor que.
Y por supuesto, x y y, las cuales, en este contexto,
se supone que son variables, de manera similar a x y y en álgebra.
¿De dónde vienen?
Ni idea.
En este contexto, solo asumimos que es parte de un programa más grande.
Entonces, si x es menor que y, imprime que x es menor que y.
Y si x es mayor que y, imprime que x es mayor que y.
Si no, imprime que x es igual a y.
Y justo así, como este rompecabezas amarillo parece
que abraza las piezas del rompecabezas morado, de igual modo
tenemos estos corchetes, que tal vez nunca
han tenido la ocasión de utilizar en su teclado.
Pero es probable que estén cerca de su tecla Enter, en un teclado de los EE.UU.
Parece como si envolvieran las líneas de código
que desean ejecutar.
Ahora, hay algo curioso que no he mencionado todavía
y que veremos al regresar a esta extraña diagonal inversa n.
En un momento veremos por qué se encuentra ahí.
Ahora haré una pausa porque ya teníamos listo algo.
¿Tienen alguna duda sobre funciones, bucles o condiciones, antes de que
comencemos a traducirlos de Scratch a C?
¿Nada?
¿Sí?
PÚBLICO: ¿Por qué tenemos dos signos más y no solo uno?
DAVID: Buena pregunta.
¿Por qué hay dos signos positivos y no solo uno?
Si se tiene solo un signo positivo, y de hecho lo veremos muy pronto
en un ejemplo, significa añadir un número a la izquierda
de un número a la derecha.
Entonces, en este caso, es solo porque parece ser la respuesta trivial.
Es porque, si queremos tener esta operación especial en donde
no hay ningún número a la derecha, únicamente tenemos que
añadir un 1 al número de la izquierda.
Los humanos, muchos años atrás, decidimos que más, más es demasiado breve
y que aún no se utiliza para otros fines.
Así que eso es todo.
¿Sí?
Sí, justo ahí.
PÚBLICO: [INAUDIBLE]
DAVID: Correcto.
No comenzaría a pensar en ello como si tuviera un bucle en su interior,
porque al final veremos que pueden poner otro bucle
que tenga la misma palabra clave, dentro de otro,
al ponerle sangría.
Así que, piensen en ello cuando necesiten un bucle
como el que vimos hace un momento,
que el bucle se compone de estas cuatro líneas.
Y como algo que solo ocurre de manera cíclica
alrededor de todo el cuerpo de éste código, por así decirlo.
¿Alguna otra pregunta?
¿Sí?
PÚBLICO: ¿Por qué usamos int para el método principal?
DAVID: ¿Por qué usamos int para el método principal?
Dejen regreso a la quinta diapositiva para explicarlo.
Lo que ustedes preguntan, solo para ser claros,
es este ejemplo de aquí, donde nuestro más simple y convencional, relativamente
hablando, pero programa al fin, hace la menor cantidad de trabajo posible,
aquí también mencionamos int.
También mencionamos esta curiosidad, void.
Permítanme posponer esta respuesta por un momento
hasta que tengamos el vocabulario necesario para responder a eso.
Bien.
Entonces, hemos buscado funciones int en bucles y en condiciones.
También hay un par de piezas de otros rompecabezas que analizamos antes.
Pero por ahora, tomaremos estas como nuestras únicas traducciones,
solo para darles una idea acerca de que, aunque la sintaxis es
diferente, aunque que no hayan escrito esos caracteres en su teclado,
las ideas que vimos hoy son las mismas que la vez pasada.
Pero claro, incluso cuando los humanos empezamos a escribir un código,
este código es solo para caracteres como el que está en la pantalla,
el problema se mostró en otra lección, las computadoras no hablan un pseudo código.
Ellas no hablan inglés, per se.
Y ni siquiera hablan en código, per se.
¿Cuál es el único lenguaje que entienden las computadoras?
unos y ceros, es decir, binarios.
A fin de cuentas, solo entienden ceros y unos, y pueden hacer
muchas cosas con ellos.
Pero de algún modo, si yo, el humano, escribo cosas como esta en mi pantalla,
antes de que mi Mac o mi PC puedan comprenderlas, lamentablemente,
voy a tener que convertirlas en ceros y unos.
Y de vuelta a ese día,
de vuelta incluso a este campus, es posible que hace años hayan
oído algo sobre las tarjetas perforadas, un libro de historia, o algo similar, que
captura efectivamente simbologías como esta.
La gente regresó a los programas en binario, al menos en un principio,
después inventaron otros lenguajes más bonitos
y luego inventaron otros lenguajes aún más bonitos.
Pero al final de todo, nuestras computadoras Intel Inside
solamente entienden esto.
Pero por suerte, los humanos no necesitamos preocuparnos
de por qué esos ceros y unos significan,
hey computadora, imprime hello, world en la pantalla, debido a lo siguiente.
De aquí en adelante escribiremos el código fuente.
Y eso es técnicamente lo que hicimos con Scratch.
A pesar de que arrastraron y soltaron las piezas de rompecabezas,
estaban escribiendo el código fuente.
Una sintaxis parecida a la humana, pero más digerible para nosotros.
Pero al final necesitamos convertir el código fuente en código máquina,
ceros y unos que los CPU de Intel, u otros CPU, entiendan.
Por suerte otros humanos antes que nosotros inventaron un software,
llamados compiladores, cuyo único propósito es traducir el código fuente
como lo hemos visto en la pantalla, mediante códigos máquina, ceros y unos.
Y de hecho, se trata de toda una área de investigación
en ciencias de la computación sobre cómo hacerlo bien y rápidamente,
especialmente para programas muy grandes.
Es una herramienta que utilizaremos en CS50 para no preocuparnos
de cómo suceden esas traducciones.
Y para lograrlo, generalmente utilizaremos el mismo entorno,
algo llamado CS50 IDE.
IDE significa entorno de desarrollo integrado,
que es una forma elegante de llamar a un entorno de computación
idéntico para todos nosotros.
Porque, sobre todo cuando nos iniciamos en programación,
una de las frustraciones más comunes es seguir un montón de instrucciones
en nuestra Mac o PC, solo para lograr que el entorno sea
idéntico al del que está al lado, pero invariablemente, algunos
tenemos versiones de navegador diferentes
o tenemos diferentes versiones de Mac OS o Windows.
Y es un dolor de cabeza tratar de estar todos en la misma sintonía.
Y así es cada vez más común en la industria, incluso en las empresas,
que todos tengamos un entorno de desarrollo uniforme,
incluso si todos no tienen las mismas computadoras.
Entonces, todo aquello a lo que tendrán acceso a partir de hoy,
incluso después del curso, será un entorno que lucirá así.
Este entorno de desarrollo integrado está basado en la web.
Y para aquellos que estudiaron algo de CS antes,
es similar a Eclipse, NetBeans, Visual Studio, o herramientas como esas.
Pero si no están familiarizados, pueden pensar en ello como una aplicación web.
Un sitio web en el que tendrán nombres de usuario y contraseñas que
les permitirán iniciar sesión y ver, esencialmente, un entorno
como este, que tiene una gran ventana en donde se puede escribir el código,
tal como lo hemos visto en la pantalla hasta el momento.
Tendrá una ventana conocida como terminal en la parte inferior
donde, tal como haremos hoy, pueden escribir comandos de nivel inferior
y decirle a la computadora qué hacer, incluso sin la ayuda de un ratón.
Y entonces, al igual que muchas Mac OS y Windows,
podrán ver todos sus archivos y carpetas.
Esto es en la nube, por así decirlo.
Y tendrán cierta cantidad de gigabytes en la nube
y solo ustedes tendrán acceso, o sus compañeros de clase
si ustedes les dan acceso, y podrán entrar a este entorno.
Y tendrán acceso, por supuesto, desde cualquier sitio que tenga internet.
Incluso si no tienen buen internet durante las vacaciones
o mientras van hacia la escuela o practican deportes,
también pueden descargar una versión sin conexión del mismo entorno.
Y también hay un modo nocturno, si son de ese tipo de personas.
Pero veamos cómo utilizamos este entorno.
O más bien, a fin de cuentas, cómo programamos.
Entonces, me conecté previamente para ver el CS50 IDE.
Me puse aquí en modo nocturno.
La dirección es CS50.io y pueden seguirla desde aquí si lo desean.
Pero tal vez es mejor que vayan a un ritmo más lento por su cuenta,
ya sea alrato, para ver la serie de problemas, o posteriormente.
Ahora escribiré mi primer programa.
No me importa lo que esté pasando a la izquierda
pues aún no tengo archivos ni carpetas, excepto esta carpeta que se ve aquí.
De modo predeterminado, todos tendrán su propia carpeta de trabajo
y es en donde pondrán sus series de problemas y archivos.
Ahora la ocultaré dando un clic en el icono de la carpeta,
para simplificar lo que vemos.
Y ahora verán dos secciones en la pantalla.
El editor de código, aquí arriba, es donde pueden escribir el código, no aquel.
Y luego, aquí abajo, está la ventana llamada terminal.
Entonces escribiré mi primer programa.
Primero daré clic en Archivo, Guardar, al igual que en una Mac o una PC.
Y llamaré a esto, hello.c.
Por convención, cualquier programa que escriba en C
tendrá la terminación .c.
Al igual que en Scratch termina en .sb2,
si lo notaron en su Mac o PC.
Por convención, en C siempre es c y siempre se usan minúsculas.
Y por convención, no se usan espacios,
se usan guiones bajos o guiones, como cuando se crean archivos,
de otro modo se dificulta hallar las cosas en el espacio de trabajo.
Entonces, tengo un archivo o una etiqueta llamada hello.c.
Puedo hacer esto rápidamente porque ya lo he hecho antes,
pero escribiré el programa siguiente.
printf("hello, world;)" y guardamos.
Noten que, de algún modo, mi código está
muy colorido, aunque lo escribí fuera del teclado de mi Mac.
Verán lo mismo en su PC.
Esto pasa porque muchos IDE que se integran en los entornos de desarrollo,
colorean el código del código fuente, con el fin de
llamar la atención hacia las funciones u otras palabras clave.
No tiene ningún significado y no se almacena en el archivo.
Es solo una función en la interfaz gráfica del usuario
que se obtiene automáticamente.
Pero ¿cómo ejecuto este programa?
Como en su Mac o PC, ¿como ejecutan un programa?
PÚBLICO: Le damos clic.
DAVID: Sí, le damos clic.
Tal vez damos doble clic en un icono.
En iOS o Android solo se toca un icono.
Pero en entornos de programación esto es posible.
Y en Mac y PC se puede escribir un software tan simple como este,
guardarlo y luego dar doble clic en un icono.
Pero en realidad, los aspirantes a especialistas en sistemas,
o quien quiera hacer cosas más poderosas con las computadoras,
pueden hacer mucho más con el teclado,
incluso si no escriben tan rápidamente.
Porque nada que escribamos en el teclado será tan largo
o detallado.
Pero se darán cuenta de que es mucho más fácil y flexible
porque pueden hacer más de aquello que hacen los entornos gráficos actuales.
Así que todo consiste en decir que desean ejecutar ese programa,
de hecho necesito compilarlo.
Recuerden que compilar significa tomar algo que se ve así en código
y convertirlo en esto.
Entonces necesito ejecutar mi código fuente en un compilador
para obtener el código máquina.
Y hay varias maneras de hacerlo.
La primera forma que intentaré es la siguiente.
Haré clic en la parte azul de mi pantalla, que en lo sucesivo
llamaré ventana del terminal.
Es un término de la vieja escuela que simplemente describe a un cursor
donde pueden escribir comandos y palabras.
Ampliamos aquí.
Y haré lo siguiente.
clang, en lenguaje C, es un compilador del lenguaje C,
y luego escribiré hello.c.
Es posible que no estén acostumbrados a esto en Mac y PC,
pero si crecieron con Dos, Linux, o algún otro sistema operativo,
es posible que lo estén.
Ahora oprimiré la tecla Enter
y parece que nada sucede.
En este entorno de programación y en CS50 IDE
se ejecuta un sistema operativo llamado Ubuntu Linux, el cual
es diferente, pero similar a Windows y Mac OS,
al parecer nada sucedió y generalmente eso es bueno.
Porque si no ven un mensaje de error,
significa que la computadora no tiene nada de qué quejarse.
Entonces ¿qué hago a continuación?
Bien, observen lo siguiente.
Si abro mi explorador de archivos, veo que aparecieron un par de cosas.
Hace unos minutos no había nada, excepto mi espacio de trabajo.
Tal vez tiene sentido que ahora existe hello.c porque hice eso.
Fui a archivo, guardar.
Pero, ¿qué creen que es a.out?
Parece que es otro archivo, pero yo no escribí esa palabra.
¿Sí?
PÚBLICO: [INAUDIBLE]
DAVID: Díganlo otra vez.
PÚBLICO: [INAUDIBLE]
DAVID: ¿Otro archivo?
PÚBLICO: Un archivo ejecutable.
DAVID: Es lo que puedo ejecutar, exacto.
Entonces, cuando ejecuto el compilador Clang en mi código fuente,
prometí en la diapositiva anterior, que se vería el código máquina
de ceros y unos.
Sería un poco molesto si esto, literalmente, generara un código
de ceros y unos en la pantalla, porque eso no me resulta útil
y la computadora no necesita verlo en la pantalla.
Así que esos ceros y unos se guardan en un archivo llamado a.out, por convención.
a es la primera letra del alfabeto y out es la salida.
Aunque su origen es un poco más elegante que eso.
Pero eso es todo, solo el nombre predeterminado del archivo.
Entonces ¿Cómo lo ejecuto?
Bueno, en una Mac o en una PC, generalmente le daría clic.
Pero no lo haré así en un entorno de línea de comando.
Y esa palabra, entorno de línea de comandos, o CLI, su acrónimo.
Literalmente tengo que hacer todo en la línea de comandos
escribiendo los comandos con mi teclado.
Y la manera de hacerlo es la siguiente, ./a.out.
El punto significa la búsqueda en mi directorio actual, donde sea que esté,
por ejemplo, en mi área de trabajo.
La diagonal solo es un separador que tal vez ya han visto en Mac y PC
para separar los nombres de las carpetas.
y a.out es el nombre del programa.
Y ahora, cuando presiono Enter, es como si hiciera doble clic sobre un icono
en una interfaz gráfica moderna, como la de Mac OS o Windows.
Pero yo diría que este programa tiene algunos defectos, ¿o no?
Mi pantalla, antes que parecer novedosa para la mayoría,
se ve un poco tonta, por el momento.
¿Por qué?
Estéticamente.
¿Sí?
PÚBLICO: Está en la misma línea que hello, world [INAUDIBLE] espacio de trabajo.
DAVID: Sí.
Hello, world, en blanco está en línea con la palabra clave en el espacio de trabajo.
Y el espacio de trabajo solo me recuerda cada línea en donde estoy.
Porque, otra vez, justo ahora no es gráfico, es textual.
Así que literalmente veo en azul dónde estoy, en cual carpeta me encuentro.
Y francamente, esto me molesta.
Soy un poco analítico y no me gusta cómo luce.
Y podría decirse que es un error.
Pero, ¿por qué ocurre esto?
Bueno, simplemente porque la computadora me interpretó literalmente.
Aquí, en mi código fuente, noten que de manera deliberada
cometí este error o inconsistencia con lo que vimos hace un momento.
Omití algo de esta línea.
¿Qué fue eso?
Sí, la n con la diagonal inversa.
Entonces, ¿cuál es la parte que sirve?
Bueno, la n con la diagonal inversa es una manera explícita de decir
hey computadora, inserta una línea nueva aquí.
Presiona la tecla Enter aquí.
Y se escribe como n diagonal inversa solo porque al hacerlo
se ve desordenado y es el tipo de cosas poco obvias que se supone que ocurren.
Entonces los programadores, decidieron hace años, ya saben,
que expresaremos la noción de presionar Enter simbólicamente
con la diagonal inversa n.
Eso es todo.
Ahora, si guardo el archivo, lo cual puedo hacer con el comando s,
o Control+s, e incluso se puede ser más explícito e ir a Archivo y Guardar,
igual que en sus computadoras, y ahora ejecuto ./a.out, Enter...
Diablos.
¿Qué salió mal?
Ah sí, tengo que volver a compilar.
Entonces de nuevo, este es un proceso.
Guardé el archivo.
Mi código fuente ahora es correcto.
Pero mi código fuente está desactualizado porque no lo he compilado de nuevo.
A final de cuentas la computadora es un dispositivo bastante tonto.
Aunque sea muy rápida, solo hará lo que le diga.
Así es que, mejor ponemos de nuevo clang hello.c.
Parece que no ocurre nada.
Pero es posible que cambió a.out.
De hecho, si pongo ./a.out, ahora puedo ver hello, world.
Aparentemente coloca un salto de línea invisible en la pantalla,
pero ahora, todo se ve un poco más ordenado.
Pero clang hello.c nos da un nombre de archivo bastante tonto.
Sería genial si pudiera llamar a mi programa hello o hello, world,
o algo por el estilo.
Y podemos hacerlo en un par de maneras.
Haré de nuevo un acercamiento.
Voy a limpiar la pantalla, solo para mantener todo ordenado.
Y parece que puedo poner comandos como clang y otros
que después veremos con los argumentos de la línea de comandos.
De hecho puedo especificar, clang, en vez de poner solo hello.c
como tu entrada, también haz esto.
Que la salida sea un archivo llamado hello.
Y esto varía según el programa.
clang no es el único programa que
veremos en esta ventana de terminal azul.
Esto significa, hey clang, haz un archivo de salida llamado hello
y toma como entrada el archivo anterior, hello.c.
¿Por qué?
Bueno, los humanos decidieron que O sería la primera letra de la palabra salida.
Y que -o sería una linda forma de decir salida.
Así que -o hello significa la salida un archivo llamado hello
en vez de la predeterminada a.out.
Otra vez parece que nada sucede, pero si me alejo y veo mi explorador de archivos,
notarán que ahora tengo el antiguo a.out y además hello
en mi código fuente.
Por intuición, ¿cómo ejecuto esta nueva versión llamada hello?
Sería ./ porque el punto significa "aquí"
y la diagonal separa el nombre del archivo.
Hello, enter, es exactamente lo mismo.
Ahora seguiré abriendo y cerrando el explorador de archivos
para que podamos ver las cosas gráficamente.
Pero eso no es necesario.
Resulta que en un entorno de líneas de comandos
se tienen muchos comandos.
Por ejemplo, puedo escribir ls, que es una manera breve de decir lista.
Hey computadora, lista todos los archivos de la carpeta actual.
La carpeta actual se llama espacio de trabajo,
por eso la mantengo marcada en azul.
Y ahora verán tres cosas, a.out con asterisco, hello con asterisco,
y hello.c.
Y también están codificados por color.
En la mayoría de los entornos de texto,
si lo configuran así, cualquier programa que esté resaltado en verde
y tenga un asterisco al lado, significa que es ejecutable.
Pueden ejecutarlo.
No con doble clic, sino escribiendo punto, diagonal, nombre del programa.
Cualquier cosa que esté en blanco aquí será un archivo de texto, como hello.c.
Solo tengo uno de esos.
Si tengo carpetas, vería así sus nombres.
Y puedo crear carpetas como en Mac OS y Windows
en dos maneras diferentes.
De hecho, puedo ir con mi ratón hasta mi explorador de archivos.
Puedo dar Control, clic, o dar allí un clic derecho,
desplazarme hasta el final y elegir Nueva carpeta.
Y cuando lo haga verán la nueva carpeta.
Tal vez quiero aplicarlo para pset1 one, serie de problemas uno,
y presiono Enter.
Y ahora tengo una carpeta llamada pset1.
Puedo verla en mi entorno de línea de comandos si tecleo de nuevo ls, Enter.
Y ahora noten que tengo el mismo par de programas ejecutables
que en el mismo archivo de texto, hello.c
y un directorio en azul llamado pset1.
Y la diagonal solo sirve para indicar, hey, humano, soy una carpeta.
¿Cómo puedo abrir pset1?
Bueno, en Mac OS y Windows podrían hacer doble clic
para expandir las cosas y mostrar lo que hay adentro.
Pero una vez más, se trata de un entorno textual.
Así que dejémoslo, vayamos abajo y cambiemos a pset1 como sigue.
cd es otro comando en un entorno de Linux.
pero Linux es solo otro sistema operativo, como Mac OS o Windows,
que ejecutamos desde la nube.
Y si pongo cd pset1, con o sin diagonal,
no importa, y presiono Enter, mi cursor cambió.
Y mi cursor corresponde a las palabras que están en la pantalla
solo para recordarme en qué punto me encuentro.
En azul decía anteriormente espacio de trabajo,
ahora dice espacio de trabajo/pset1 porque he aplicado el equivalente
de hacer doble clic sobre pset1 con mi teclado,
para abrirlo y entrar en él.
Haré una suposición.
Si escribo ls dentro de mi directorio pset1 y presiono Enter,
¿qué deberíamos ver?
Con suerte, nada, porque sería algo raro si todo lo que hice
fue crear una carpeta y de repente hubiera algo en su interior.
De hecho no hay nada en ella.
Escribir ls, Enter no muestra nada, lo que significa que no hay nada adentro.
Sin embargo, si decido que tiene un error, me estoy adelantando,
puedo volver
y podría no ser evidente, pero "cd .."
significa retroceder un directorio o técnicamente ir a la base.
Pueden pensar en la estructura de carpetas de su Mac o PC y en los IDE
como en un árbol,
un árbol genealógico,
Y simplemente fui hacía el origen del espacio de trabajo llamado pset1.
Entonces, cd .. los lleva de regreso, si lo ven así, o los lleva
si así lo prefieren, al modelo mental de un árbol genealógico.
Si ahora presiono Enter, mi cursor regresa al espacio de trabajo.
Si escribo ls, me siento cómodo de nuevo, puedo ver lo que ya sabemos.
Y si deseo eliminar ese directorio,
simplemente escribo rmdir, para eliminar el directorio pset1,
y desaparece.
Y confirmo que ls tuvo mucho que ver.
Así que, en resumen, esta es la forma textual de hacer cosas
que tal vez han hecho por años en su Mac, PC o teléfono
todos los días.
Bien.
Nada de esto es intelectualmente interesante.
Ahora que hemos aprendido cómo crear archivos y carpetas,
profundicemos en algunos de los códigos
y en las ideas con las que resolvemos los problemas.
Este primer programa realmente no hizo mucho
aunque al parecer expresó una idea.
Y comenzaremos dando por hecho,
más aún, lo que realmente es una función.
Y tal vez, solo para aclarar este punto, haré lo siguiente.
Cambiaré la pantalla anterior a un lienzo en blanco.
Es decir, todos los círculos que dibuje anteriormente.
Necesito un voluntario, ¿tal vez a cambio de una pelotita para el estrés?
OK, eso fue rápido, ven acá.
¿Cómo te llamas?
SAM: Sam.
DAVID: Muy bien.
Sam, aquí tenemos una etiqueta para ti.
Pero en vez de llamarte Sam,
te llamaremos por el momento printf.
Así que si no te importa, di hola, mi nombre es printf.
SAM: Hola, mi nombre es printf.
DAVID: OK, gracias.
Pon eso donde quieras.
Muy bien, quédate allí un momento.
Mientras, yo seré el programador en mi computadora
y mi objetivo es, simplemente, imprimir en la pantalla hello, world.
Ahora que he programado durante años
tengo varias pantallas acumuladas a lo largo de años,
Y no me importa cómo las palabras que escribo en mi programa
salen en la pantalla.
Quiero delegar esa funcionalidad en alguien
o en algo más.
Y afortunadamente Sam ha programado durante algún tiempo,
sabe cómo hablarle o imprimir cosas en las pantallas de la computadora,
y así puedo externar la funcionalidad que quiero usar.
Pero no me interesa cómo se implementará
o cómo lo aplique Sam, simplemente llamo a Sam
y le pido que haga algo.
Así que en este caso, Sam, ahora eres printf.
Así que tomaré un pedazo de papel y les diré,
si no les importa, para asignar la entrada,
le daré a Sam un trozo de papel que dice, hello, world.
Y si no te molesta, ¿puedes imprimirlo en la pantalla
ya que, de hecho, eres printf.
Y puedes hacerlo con solo poner tu dedo en la pantalla.
Así que, soy el programa de computadora,
no tengo idea de cómo funciona la impresión,
solo sé que escribí una línea de código,
ejecuté el programa,
printf está en marcha,
está haciendo su trabajo
y perfecto.
Sam, vuelve aquí.
Y ahora Sam terminó de ejecutarlo, si les parece bien.
Muchas gracias.
Y esa fue una manera ridículamente extensa de
mostrar que las funciones no son intelectualmente interesantes.
Es solo empaquetar estas funcionalidades
que no necesariamente debo saber o que me importe cómo funciona.
Pero quiero completar el trabajo.
Y de hecho, podemos hacer un trabajo más.
Si no les importa cambiar su nombre solo por un momento.
¿Qué tal a cambio de dos pelotas para el estrés?
Así que ahora voy a pedirles que cambien su nombre por get_string, porque
ocurre que, en el mundo de las computadoras...
técnicamente, esto no ayuda a ponerlo en marcha, pero está bien.
Así que, en el mundo de las computadoras hay muchas
otras funciones que pueden utilizar, y algunas son específicas para CS50.
Pero la mayoría no lo son.
Y, de hecho, si abro esta lista,
algunas de las funciones que utilizaremos y daremos por hecho
son estas.
get_char para obtener un carácter, get_int para obtener un entero, get_string
para obtener una cadena o una frase,
get_float para algo incluso distinto,
y aún no sé cómo funcionan.
Realmente no sé cómo trabajan los teclados o de dónde vienen las entradas.
Pero afortunadamente, alguien más lo hizo.
Sam, en este caso, implementó el comando get_string.
Y ahora, si no te importa, Sam,
voy a escribir otro programa contigo justo allí.
Y lo veremos en lugar de esto.
Voy crear un nuevo archivo al que llamaré string.c
luego pondré #include ,
Int main(void), el cual solo copiaremos y pegaremos del anterior.
Pero en lugar de solo escribir hello, world,
voy a poner string s = get_string("Name: ");
Y luego escribiré printf("hello, %...
printf("hello, %s\ n", s);
¿Qué ocurre entonces?
Regresaremos a la línea 6 en un momento.
Pero ahora la línea 5 está haciendo dos cosas en el lado izquierdo,
está declarando una variable s, la cual
almacenará, aparentemente, ¿qué tipo de datos?
Una cadena, que puede ser una palabra, una frase, un párrafo o lo que sea,
son caracteres del teclado.
¿Y qué va dentro de s?
Cuando hablamos antes sobre las variables, pusimos dentro de otra variable
llamada i, el número 0.
Aquí, en el lado derecho del signo igual,
ponemos en cambio el nombre de una función, lo cual es interesante,
porque antes, cuando Sam era una función llamada printf, hizo algo
y después volvió a mí, pero no me dio nada.
Solo le di las gracias y seguí adelante.
Pero en este caso, quiero que Sam simplemente
vaya hacia al público con esta pluma y un trozo de papel,
que vaya y me consiga una cadena.
Por favor, consigue el nombre de una persona,
cualquiera que desees.
Una vez más, no tengo idea de cómo se implementa esto.
Le pudo tomar a Sam 5 líneas de código o 20 líneas de código, o 100 para
respaldar el proceso de obtener la entrada de un humano.
Pero lo que es diferente en el caso de esta función
es que ahora volverá a mí y no solo terminará de ejecutarlo,
de hecho me devolverá algo
y empezaremos a llamar a esto, gracias, Sam,
un valor de retorno, el nombre de Katrina.
Y así me entregó lo que llamaremos un valor de retorno.
A continuación haré algo con esto.
Y, ¿cómo conecto esto a mi cadena?
Lo hago con esta línea 6 que tengo aquí.
Le digo a printf, no solamente hello, sino hello, %s,
y %s es solo una forma críptica de decir, pon una cadena aquí.
¿Cuál cadena quiero añadir?
Bueno, inmediatamente después de la coma, noten que
mencioné el nombre de la misma variable, s, en la cual
guardé lo que Sam me entregó.
Y así, para cada función que escribimos, utilizamos a un voluntario real.
Pero eso es todo lo que ocurre.
No tengo idea de a quién fue a buscar Sam.
No tengo la menor idea de si él escribirá
con cursivas o sin cursivas en la pantalla.
Solo sé que él era capaz de hacerlo.
Así que, tal vez podríamos darle a Sam una ronda de aplausos.
Gracias.
Entonces, basta con decirlo, hay otras funciones, no solo get_string.
Pero si quieren obtener un entero, hay otra función para ello.
Si quieren obtener un carácter único, get_char es otra función que sirve.
Pero también hay más cosas aquí,
double, float y long_long, y lo que sea que signifiquen.
Resulta que para las computadoras, especialmente con lenguajes como C,
necesitamos ser súper precisos en cuanto al tipo de datos
que se almacenarán en ellas.
Y se tiene que especificar por adelantado, esta es una cadena, este es un entero,
esto es algo con un punto decimal, no solo un entero.
Y para continuar propondremos un ejemplo
como el siguiente, esta vez utilizaremos un número entero.
Voy a volver al IDE.
Voy a crear un nuevo archivo llamado int.c.
y abriré los archivos anteriores, #include ,
int main void
y esta vez pondré
int i = get_string(" integer: ");
Y después printf...
Qué tal solo printf("hello, %...
no s, porque el comando s es para una cadena,
sino printf("hello, %i\ n"), donde i es para los enteros.
Esto luce como un programa completo, aunque no lo hemos utilizado,
perdón, hay un error en get_int.
Entonces, esto parece un programa completo, aunque mucha de la sintaxis
puede ser nueva para ustedes.
Ahora tratemos de ejecutarlo.
¿Cómo ejecuto éste programa?
Aún no puedo ejecutarlo.
¿Cuál es el primer paso?
Sí, primero tengo que compilarlo.
¿Y cómo lo compilo?
Sí, con clang,
puedo poner -o,
puedo llamarlo int, porque deseo que el nombre del programa sea int.
Francamente, esto es molesto.
No quiero escribir todo el tiempo clang, -o, nombre del archivo.
Solo quiero hacer el programa.
No quiero preocuparme por esto.
Y resulta que hay formas para lograrlo.
Porque en el IDE está instalado un comando muy popular que se llama
make.
Y make les permite escribir solamente esto
make int.
No tienen que especificar .c.
Solamente deben especificar el inicio del nombre del archivo.
De modo que si esto es int.c, ustedes escriben int,
si es hello.c, entonces escriben hello.
Y solo tienen que escribir make int.
Y make será un programa diferente,
técnicamente no se trata de un compilador,
pero es un programa que sabe cómo utilizar un compilador.
Y cuando presionamos Enter, vean la larga y loca salida que arroja.
Incluye la palabra clang, pero luego incluye también todos estos argumentos
de línea de comandos que nunca querrán recordar o tener que
escribirlos ustedes mismos.
Sería increíblemente tedioso.
Pero eso es simple, porque nosotros hemos preconfigurado
el IDE para que se configure el clang de cierto modo
de modo que les proporcione ciertas funciones sin que tengan que activarlas
ustedes mismos, todo el tiempo.
Pero desafortunadamente, aún cuando traté de compilar mi código,
posiblemente no esté bien.
Veo tres errores en un programa que apenas tiene tres líneas de largo.
No resulta muy prometedor.
Bueno, no deben sentirse abrumados
cuando vean muchos errores en la pantalla
después de escribir un programa, ya que algunas veces
la computadora se confunde.
Y el error más importante probablemente sea el primero
que detectó la computadora, y que los otros sean simplemente
dependientes de los resultados de ese primer error.
Así que no se sientan abrumados por el número de errores.
En vez de ello, miren el primer error y notarán
que la declaración implícita de la función get_int es
inválida en C99 y que luego hay otras cosas misteriosas.
Luego puedo ver una línea de mi código como la tercera línea de esa salida.
Por el momento no sé lo que esto significa.
Pero parece ser un error relacionado de algún modo con get_int.
Ahora, ¿por qué ocurre ésto?
Bueno, resulta que get_int no viene con C.
Es una especie de rueda de entrenamiento que utilizamos
durante las primeras semanas del curso, antes de eliminarlas,
solo para que la introducción a C sea más sencilla.
En Scratch, solo tienen un montón de piezas de rompecabezas
las cuales facilitan las cosas.
En C, no las tienen.
Si simplemente quieren obtener la entrada del usuario,
tienen que saltar a través de algunos aros,
por así decirlo, y escribir más líneas de código de lo que es ideal.
Entonces, escribimos eso que llamamos biblioteca, una colección de funciones,
como un montón de Sams
que saben hacer cosas muy específicas.
Y les pusimos nombres como get_int, get_string y así sucesivamente.
Pero el truco es que, dado que CS50 los hizo,
no se encuentran en la biblioteca de entradas y salidas estándar.
Están en la biblioteca de CS50.
Así que si desean usar algunas de estas funcionalidades durante la primera
semana del curso, de hecho, tengo que agregar una inclusión más.
Debo decir, hey computadora, no solo incluyas
la biblioteca para las entradas y salidas estándar,
donde las bibliotecas son solo una colección de códigos de alguien más,
y en este caso, las que solo contienen printf.
Pero ahora la biblioteca de CS50 también contiene get_int y get_string,
y otras piezas de funcionalidad.
Entonces, guardaré el archivo y volveré a la parte final de mi ventana.
Y volveré a ejecutar make int,
cruzaré mis dedos y Enter.
Diablos.
¿Qué sucedió aquí?
Este es mi segundo error, pero vamos progresando.
Ahora tengo dos errores en rojo.
Y esta vez dice, error, más conversiones por ciento
que argumentos de datos.
Puedo concentrar mi mente en eso.
Pero noten que no he practicado lo que les aconsejé hace un momento.
¿Qué falta en la línea 7 que resalté?
PÚBLICO: Debes poner una coma después de la cadena
y después añadir la variable.
DAVID: Sí, exactamente.
Tengo este marcador %i y dice que debo introducir un entero aquí.
Pero no terminé la idea.
Como algunas piezas en Scratch, que tienen varias cajas blancas,
en las que se puede escribir o arrastrar otras piezas del rompecabezas.
Así que aún no he terminado la idea.
Debo indicar el valor que deseo introducir en esta cadena,
y en C pueden hacerlo si separan las entradas con comas.
Y, de hecho, esas entradas a las funciones se llaman parámetros o argumentos,
según el contexto.
Y entonces, ¿a cuál argumento deseo llegar?
Bueno, quiero mover i como una segunda caja blanca en una pieza de Scratch
que influya de algún modo en la primera entrada, conocida también como argumento.
Y ahora, si en serio cruzo mis dedos, guardo el archivo y ejecuto make int,
ya no tengo más errores
y no tener errores es bueno.
Ahora, si escribo ls, ¿cuál archivo debería ver entre mis otros archivos?
Con suerte será un programa llamado int.
De hecho se encuentra allí en verde, con un asterisco después de su significado,
Puedo poner ./int, integer.
Dénme un número.
Lo primero que oí fue 3.
Hello, 3.
Vamos a ejecutarlo otra vez.
Escuché 6 antes.
Hello, 6.
Y podemos hacer esto todo el día, a menos que probemos al azar y escribamos monkey.
Pero el programa va a notarlo.
Eso es parte de la funcionalidad que obtendrán con la biblioteca de códigos.
Nos tomamos el tiempo para implementar get_int de tal manera
que si ustedes, humanos, no nos proporcionan un int,
solamente los reescribiremos, los reescribiremos y los reescribiremos.
Entonces, en este caso, no sirve escribir una palabra,
tampoco funciona escribir algo como 1.23, porque no es un entero.
Eso es lo que llamamos un número real,
un número con punto flotante, donde realmente hay un punto en él.
Pero si escribo algo como 42, entonces obtendré un hello 42.
Haré aquí una pausa, porque hemos visto demasiado
y he dejado muy poco tiempo para hacer preguntas.
¿Sí?
PÚBLICO: Entiendo que hizo una biblioteca para que la usemos,
pero cuando etiqueta [INAUDIBLE] biblioteca, ¿de dónde se obtiene?
DAVID: Es una excelente pregunta.
Cuando se pone esa línea de código al principio del programa,
¿dónde está el código?
Fue instalado previamente en algún lugar en la nube,
dentro de alguna carpeta en el IDE de su CS50.
Y gracias a que instalamos software estándar, ese software,
como Clang, solo sabe en dónde buscar en el disco duro
al que tiene acceso.
Tenemos un archivo que escribimos antes, llamado CS50.c, el cual tiene
todo el código C que lo implementa.
En CS50.h solo hay un resumen.
Pronto veremos .h, en el encabezado de un archivo.
Y en realidad solo tiene un resumen breve
de la funcionalidad a la que tienen acceso,
así que simplemente tienen que escribir una línea
y después tendrán acceso a toda la caja de herramientas de la funcionalidad
en la biblioteca de CS50, la biblioteca estándar de I/O o en otro lugar.
Eso es lo que obtienen.
¿Sí?
PÚBLICO: [INAUDIBLE] y entonces como [INAUDIBLE].
DAVID: Exacto.
Pueden usar cualquiera de esas funciones, get_int, get_float, get_string,
y aún no hemos hablado de lo que son algunas de ellas,
pero siempre y cuando las almacenen en el tipo de variable correcta,
las cambien a la cadena, o cambien la cadena en algo más, entonces sí,
pueden utilizar cualquiera para obtener la entrada del usuario,
así sus programas serán realmente dinámicos.
No implicará dar clics con el ratón y demás,
pero al menos pueden tomar la entrada textual del usuario.
Ahora abriré un programa que escribí anteriormente.
Para continuar tomaré esto
que se llama ints, en plural.
Y después abriré esto de la siguiente manera.
Este es el código que también se encuentra en el sitio de web del curso,
así que pueden echarle un vistazo en cualquier momento.
Es un poco más complicado
pero se ve como sigue.
Hasta arriba del archivo, noten que comienza con diagonal diagonal.
Resulta que los lenguajes de programación como C
son compatibles con lo que llamamos comentarios.
Los comentarios no son un código, son notas para uno mismo
que recuerdan aquello con lo que se estaba trabajando,
o a sus compañeros lo que se supone que hace el programa.
Y en este caso quiero mostrar la aritmética de enteros, lo que sea que
esto signifique.
Ahora tengo un par de "include" y los agrupé.
Añadí líneas en blanco, pero eso es solamente
para mantener todo limpio y ordenado.
No es estrictamente necesario.
Aquí tengo main y probablemente volveremos
para discutir por qué tenemos ints y void.
Pero hoy, supongamos que esto es el equivalente
a cuando hice clic en la bandera verde.
Y ahora tenemos aquí algunas líneas de código.
Tengo dos comentarios que les dirán
lo que ocurre en el cursor del usuario para x y para y.
Debajo de cada comentario están las líneas de código que hacen eso.
¿Y qué opinan sobre esta línea de código?
Es similar a lo que vimos apenas, aunque con otros nombres.
En el lado izquierdo de la línea 9
estamos diciendo, hey computadora, dame una variable
que se llame x, y almacenarás en ella cierto tipo de datos,
int, un entero, como un número.
Luego, a la derecha, se llamará
get_int, que es como otra versión de la que Sam recopiló,
y obtendrá un entero del usuario, en donde el usuario lo escriba
en el teclado, presione Enter y luego get_int lo devuelva al programa.
Y ya que get_int está en el lado derecho del signo igual,
ese valor, como el que Sam me entregó en un pedazo de papel,
se transferirá de derecha a izquierda
y se almacenará a la izquierda de la variable.
Así que si escribo el número 1, x contendrá el número uno.
Y si el siguiente número que escribo es el 2,
la variable y almacenará el número 2 de derecha a izquierda.
Ahora, esto es un poco abrumador a primera vista,
pero es solo un copia y pega de algunas de las mismas ideas
para hacer aritmética.
En este programa quería demostrar
algunas operaciones aritméticas que son compatibles con C.
Pueden sumar, restar, multiplicar y dividir números.
Puede no ser obvio cual símbolo deben utilizar y por eso veremos esto.
En la línea 15, vemos el siguiente ejemplo.
Tenemos aquí la cadena que dice, introduce algún valor,
luego dice la palabra "plus", entonces añade un valor,
luego dice la palabra "is", entonces añade un tercer valor.
Todos los valores son enteros
porque después de esta cadena resaltada, tengo tres entradas adicionales
para la función printf.
Tres valores adicionales para añadir, literalmente, a x y a y.
Y si quieren hacer matemáticas en C, solo escriban x más y,
eso devolverá 1 más 2, o cualquiera de los valores que contenga.
Y de nuevo, aquí habrá tres valores separados por comas
porque hay tres marcadores de posición en el lado izquierdo.
Mientras tanto, el resto es solo copiar y pegar
pero con diferentes palabras y operadores.
Entonces, algo menos algo es algo.
¿Y cómo obtengo esa salida, x y y, y después x menos y?
Entonces menos es lo que se espera que sea.
x algunas veces algo, es algo.
Bueno, esto sería x, y, x * y.
Entonces, el asterisco en C representa la multiplicación.
Y entonces x algo, dividido por algo, es algo,
x, y, x / y nos da la división.
Y después, la última, tal vez sea la única extraña
o la que nunca escribieron con un teclado.
El restante de algo cuando es dividido por algo, es algo
y ese carácter es el signo de porcentaje.
Probablemente nunca lo escribieron como un comando,
a menos que hayan practicado la aritmética modular, pero tal vez
recordaron la escuela primaria.
Si divido un número por otro, ¿cuál es el restante?
Este signo de porcentaje sirve para expresar esa misma idea.
Ahora voy a compilar este programa.
Y en resumen, ¿cuál es la forma más breve para
compilar un programa que está en un archivo llamado int.c?
Make ints.
Una vez más nos abstraemos de todos esos detalles
y será un patrón.
Solo cuando las cosas parezcan demasiado detalladas y difíciles,
colocaremos una capa superior, como un modo fácil de hacer las cosas,
y daremos por hecho que sabemos que algo
está sucediendo por debajo del agua.
Parece que make ints funciona porque no hay mensajes de error.
Entonces ./int Enter.
x será 1.
De hecho, hagamos esto.
Probemos con 2.
2 y 2, Enter.
Muy bien, 2 más 2 es 4,
2 menos 2 es 0,
2 por 2 es 4,
2 dividido por 2 es 1,
el restante de 2 dividido por 2 es 0.
Creo que ya son todos los que hay por revisar.
Pero... pero, pero, pero...
Siento que la prueba no es realmente una prueba.
Así que trataremos una vez más.
1 por x,
2 por y,
OK, 1 más 2 es 3,
1 menos 2 es 1 negativo,
2 por 1 es 2,
1 dividido por 2... ¿es 0?
¿Qué debería ser?
Probablemente 0.5, ¿cierto?
Algo como 1/2.
1 dividido por 2 no es matemáticamente cero,
pero el restante de dividir 1 por 2 es 1,
así que por alguna razón, la división está rota.
Al parecer mi computadora no divide correctamente.
Pero, ¿por qué ocurre esto?
Bueno, probablemente puedan adivinar aunque no sea obvio.
¿a qué se debe esto?
¿Qué está pasando?
¿Sí?
PÚBLICO: Está buscando un entero.
DAVID: Busca un entero.
Entonces dividió 1 por 2
y si la salida debe ser un entero, porque de %s
tiene que elegir una u otra manera.
Entonces, lo que hace un programa de computadora es arrojar
todo en el punto decimal.
Si utilizan ints y los ints no tienen puntos decimales,
serían números reales en vez de números irracionales,
solo arrojaremos todo después del punto decimal
y estaremos a la izquierda, por supuesto, del cero.
Porque 1 dividido por 2 técnicamente es 0.5.
Así que perdemos todo después del punto.
¿Cómo lo arreglamos?
Bueno, podemos solucionarlo de un par de maneras,
pero quizás lo más simple es lo siguiente.
Dejen prosigo y tomo otro ejemplo que escribí anteriormente.
Este se llama float.c, y float es una referencia
a un punto flotante en aritmética.
Literalmente, el punto flotante se refiere a un punto
que se mueve de izquierda a derecha, según el valor trate de expresar.
Y en este caso, noten que cambié el programa para que ya no utilice
más ints sino floats.
Entonces es un tercer tipo de datos.
Teníamos cadena.
Teníamos int.
Y tenemos float.
Y float permite que nuestros números tengan puntos en ellos.
Y ahora, si hago algo de aritmética aquí, solo una línea,
será la misma línea de código anterior,
pero ahora utilizo %f en vez de %i
para imprimir un valor de punto flotante.
Vamos a volverlos float.
Enter.
./floats.
Y lo intentamos de nuevo.
1, 2.
Y ahora obtengo la respuesta que espero.
Eso es algo interesante.
Ahora solo tengo que ser más preciso con lo que está pasando.
Así que tenemos cadenas, ints y floats.
Haré una pausa para resolver dudas sobre lo que generalmente
llamamos tipos, tipos de variables.
¿Sí?
PÚBLICO: ¿Cómo se aumenta el número de cifras en los decimales?
DAVID: Oh, muy buena pregunta.
Cómo aumentar el número de cifras en los decimales.
Podemos hacerlo de una manera muy específica.
Justo ahora, tenemos uno, dos, tres, cuatro, cinco, seis valores
impresos de manera estándar. Supongamos que queremos tener 10.
Es un poco críptico, pero en general puedo
poner .10, que es la manera oficial de decir dame
10 números después del punto decimal.
Y francamente olvido este tipo de detalles todo el tiempo.
Solo Google y ustedes pueden obtener ese tipo de información.
Vamos a intentar con make floats
y ahora ./floats.
1, 2.
Y así obtengo más ceros después del punto decimal.
También pueden ir en otra dirección para hacer redondeos implícitamente.
Sí, pregunta.
PÚBLICO: ¿Pueden tener los primeros dos enteros [INAUDIBLE]?
DAVID: Ah, buena pregunta.
¿Pueden los dos primeros ser enteros y los dos últimos ser un float?
Puedo escribir int x, get int.
int y, get int.
Y cambiar esto para i, i, pero dejándolo como un float.
Es muy buena pregunta.
Pero nada es trivial, en cualquier momento
pueden surgir este tipo de preguntas cuando van por su cuenta
y no solo en un entorno como este, así que inténtenlo.
Entonces pongamos de nuevo make floats,
y no es bueno, pero el compilador notó
que hice algo que no está permitido.
El compilador siempre es misterioso, estos son mensajes de error.
Pero el formato especifica un tipo double.
Double es un valor de punto flotante
pero con más capacidad para los números después del punto decimal.
En pocas palabras, float generalmente utiliza 32 bits,
lo cual nos da muchos ceros y unos con los cuales
se representan valores de punto flotante o números reales.
Si se utiliza un double, se obtienen 64 bits
y según nuestra conversación en la primera lección,
solo significa que tienen un mayor rango de valores, o mayor precisión.
Así especificamos un tipo double pero el argumento es de tipo int.
Así que el compilador nos cachó y simplemente no podemos hacerlo.
Podríamos omitir esta advertencia y tratar de hacerlo,
pero es posible que obtengamos un comportamiento inesperado.
Buena pregunta.
¿Había otra pregunta antes de esta?
¿No?
OK.
Muy bien, esto es un tipo de valor diferente.
Pero introduzcamos algunas de esas construcciones lógicas que prometimos
al inicio.
Prosigamos.
A continuación tomaré un archivo,
que también está en el sitio web del curso,
llamado conditions.c.
Es un programa que también escribí y que trata un poco de lógica.
De nuevo estoy siguiendo un patrón
para que en cada tipo de programa se presenten una o dos ideas nuevas.
Entonces tengo get_int dos veces y almacenan los valores en x y y,
y luego llevaré a cabo algunas operaciones lógicas.
En realidad se trata de copiar y pegar lo que hemos visto antes,
pero es, en código, el modo en que podría comparar dos variables.
Dije antes que no tenía idea de dónde provienen x y y, ¿verdad?
Vimos el ejemplo fuera de contexto
y ahora tenemos el contexto.
Las líneas que vemos arriba las llamamos dos veces get_int
y almacenan los valores en x y y, respectivamente.
Así que ahora x y y existen realmente en mi programa.
Entonces, aquí abajo, solo hago exactamente lo mismo
que hacía aquella gran colección de piezas de rompecabezas en Scratch,
si compilo y ejecuto este programa, conditions.c,
veamos que pasa.
ponemos las condiciones y ahora escribimos ./conditions.
1 y luego 2, ¿qué debe imprimir?
Con suerte, que x es menor que y.
Y de hecho, eso es exactamente lo que hace el programa.
Si lo ejecuto otra vez con 2 y 1, x es mayor que y.
Y si lo ejecuto con 1 y 1, x es igual a y.
Solo estoy traduciendo las piezas del rompecabezas de Scratch,
en este caso para ver que me da algo un poco diferente.
Pero, ¿qué pasa si no quiero comparar solo una cosa?
En Scratch, es probable que rápidamente construyan escenarios
donde desearán comprobar varias cosas a la vez,
o tal vez quieran hacer varias preguntas.
Si no, es probable que crucen ese puente en poco tiempo.
Ahora, para continuar pondré otro ejemplo.
Empezaré desde cero.
Voy a llamar a este noswitch.c, por razones
que se aclararán en un momento,
y lo incluiré en la biblioteca CS50.
Lo incluiré en la biblioteca estándar, de modo que
pueda obtener la entrada y la salida de impresión.
int main(void), la cual es una línea que por hoy daremos por hecho.
Y luego pondré lo siguiente, char c = get_char("Answer: ");
Y solo quiero que esto sea la respuesta del usuario.
char es un simple carácter, no es una cadena que
pueda ser toda una frase o un párrafo.
Y luego escribiré lo siguiente.
If c == 'Y', entonces
escribo printf("yes\ n");
else if (c == 'N')
esto imprimirá printf("no\ n);
Y eso es todo.
Entonces, ¿qué hace este programa?
Bueno, si nunca ejecutaron un programa con un botón para dar clic en sí o no,
o tal vez un programa de línea de comandos, o utilicen el teclado
y tengan que escribir sí, estoy de acuerdo con los términos y condiciones
o no, no lo estoy, esta es una forma súper sencilla para comprobar
si el humano escribió y para yes o n para no.
Entonces ejecutemos esto y volvamos a la razón por la cual se implementó así.
Pongamos make noswitch
y luego regresaré al porqué de este nombre.
Ahora pondré y ejecutaré ./noswitch
Enter.
Y mi respuesta debería ser y para yes.
Tiene errores.
Qué...
¿Qué estaba esperando?
Sí, esperaba que al presionar y, imprimiera yes.
Pero pensemos en lo que mi código está pidiendo.
¿Dónde está el error?
¿Por qué mi programa no imprime Y-E-S?
¿Sí?
PÚBLICO: No está en mayúsculas.
DAVID: sí, es tan sencillo como eso.
No está en mayúsculas.
Así que recuerden, la precisión es super importante.
Escribí un programa que dice if c, si el carácter que el usuario
escribió es Y mayúscula, imprimirá eso.
Si no, si es N mayúscula, imprimirá esto.
No hice nada de eso.
Así que el programa no está roto per se.
Solo le falta una característica, si lo quieren ver así.
Carece de compatibilidad con las minúsculas.
Pero si pongo una Y mayúscula, por supuesto que funciona.
¿Por qué está escrito de esta manera?
Bueno, aquí hay un par de detalles.
Y puede ser una pregunta en la que se basó su comentario anterior.
¿Por qué se pone igual, igual, y no solo igual, como en matemáticas?
Se ve un poco raro.
¿Sí?
PÚBLICO: Un igual es para asignar valores [INAUDIBLE].
DAVID: Sí, parece que es la respuesta.
Los humanos ya utilizamos el signo igual con un propósito distinto
para la asignación, que así se llama.
Movieron un valor de derecha a izquierda.
Así que cuando se dieron cuenta, oh cielos, quedaron atrapados en su propia trampa.
¿Cómo comprobamos la igualdad en aritmética?
Se necesita un símbolo distinto para que la computadora sepa la diferencia.
Así que es igual, igual, lamentablemente significa igual.
Igual significa asignaciones.
Y eso es todo.
Y una vez que se acuerden de ello, todo se vuelve muy sencillo,
pero es por eso.
Hay otra cosa que hice un poco diferente.
Y es un detalle molesto.
Por qué creen que repentinamente cambié a caracteres individuales,
¡diablos!
¿Por qué, de repente, cambié a apóstrofes simples en vez
de comillas dobles, como antes?
PÚBLICO: Las comillas simples solo funcionan para los caracteres.
DAVID: Bueno,sí.
Qué astuto.
Sí, así es exactamente.
Las comillas simples, como las que acabo de escribir,
significan que se tienen variables individuales, en este caso como y o n.
Las comillas dobles se utilizan cuando hay varios caracteres para las cadenas en sí.
Y más adelante analizaremos la razón de esto.
Pero por ahora, esa es la razón.
Si ustedes revisan un carácter, esto se hace con comillas simples.
Si se trata de más de un carácter, definitivamente
necesitarán utilizar las comillas dobles para varios caracteres.
Pero hay maneras de solucionarlo.
Ciertamente podría hacer trampa, y sería como... OK, arreglé mi programa.
Ahora puedo usar make noswitch.
Puedo ejecutar noswitch de nuevo.
Y ahora puedo escribir y, y funciona.
Por desgracia ya no puedo escribir la Y en mayúscula, así que es un poco tonto.
¿Cuál creen que sería una mejor solución para este programa?
PÚBLICO: [INAUDIBLE] ambas.
DAVID: Aceptar ambas de alguna forma.
Entonces, ¿cómo lo harían en Scratch, por ejemplo?
¿Qué es lo que harían?
¿Cuáles piezas del rompecabezas utilizarían de nuevo?
PÚBLICO: Utilizaríamos un or.
DAVID: OK, podemos utilizar un or.
Exactamente.
Así que hay una pieza de rompecabezas, que podemos, o no, haber utilizado.
Y me gustaría simplemente poder escribir la palabra or, pero
las computadoras son algo enigmáticas, aunque algunos lenguajes,
como Python, pueden introducir de nuevo la palabra or.
En C existen dos barras verticales.
Y solo tienen que recordalo.
Las dos barras verticales permiten decir, if (c == 'Y'), con mayúscula
y aquí abajo, puedo decir, if (c == 'N'), con mayúscula.
Y ahora puedo hacer dos preguntas a la vez.
Y ahora si lo reduzco y lo vuelvo a compilar, make noswitch, Enter.
Entonces puedo ejecutar ./noswitch.
Y ahora puedo poner y minúscula, Y mayúscula, n minúscula
y N mayúscula. Pero no puedo poner un signo de interrogación
porque no es compatible.
la s tampoco funciona.
No fue un carácter y el último no fue y o n.
Hay otro modo en el que podría haber hecho esto.
¿De qué otra manera podría haberlo implementado, sobre todo
si no supiera que existen estas dos barras verticales?
¿Qué otra pieza del rompecabezas o bloque de código podría utilizar?
AUDIENCIA: [INAUDIBLE]
DAVID: Sí, exactamente.
Podía haber utilizado otro else, if.
Podría decir if el carácter es igual a y, como hace un momento.
Pero también podría resultar if (c == 'Y') mayúscula,
entonces imprimiré también printf("yes\ n");
Y puedo hacer lo mismo para no.
¿Cómo elegir entre estas dos opciones?
Porque esta es solo la primera de muchas veces
en las tendrán que tomar una decisión
sobre cómo implementar algo.
¿Alguien tiene un argumento en favor o en contra de ello?
¿Un poco más atrás?
Sí.
AUDIENCIA: [INAUDIBLE].
DAVID: Sí, el primero utilizó menos líneas de código
y eso es algo bueno.
Porque entre menos líneas de código haya, es menos probable
que tengan errores en sus programas.
Porque escribieron menos código y hay menos sitios para cometer errores.
Y hay otro argumento, pienso que a favor del primero.
No solo son menos líneas de código, ¿qué más hay?
AUDIENCIA: [INAUDIBLE].
DAVID: Exacto.
El segundo también es redundante, ya que digo
printf yes dos veces.
Y eso parece innecesario, ¿verdad?
Hemos visto ejemplos en Scratch donde algo se aplica varias veces
si se tiene un bucle.
Bueno, aquí ocurre lo mismo con las condiciones.
¿Por qué hago las cosas varias veces si puedo combinarlas en una?
Porque además, si luego quieren
cambiar la salida a yes, signo de admiración
podría actualizarse a medias en muchos lugares
si hubiera solo un bloque en vez de dos.
Pueden estar en desacuerdo y una persona razonable
podría argumentar que no, que esto es más limpio
porque lo que estamos revisando ahora es muy explícito.
Y a eso se reducirá en un curso como este, en algo
llamado diseño.
Habrá correcciones, es decir, que su código funcione según lo indicado,
pero, ¿está bien diseñado?
Una persona razonable votaría a favor,
es decir, que sí se hizo un buen trabajo de implementación.
Sería el equivalente de alguien que evalúa un ensayo
diciendo sí, expresaron sus pensamientos, pero estaban dispersos.
Y también hay un tercer eje de estilo de evaluación.
Se darán cuenta de que todo mi código tiene sangrías
y que hay comentarios en los archivos que escribí.
Es una cuestión de buen estilo, lo cual significa
que tienen un código que luce bien y que
es más fácil de leer que si escribiéramos todo en una línea.
Pero veremos más en un momento.
A continuación abriré una alternativa
y no lo haré desde cero.
A continuación abriré un archivo llamado switch.c,
solo para introducir otra idea o función.
Huy.
OK, fue un accidente pero es una buena idea.
¿Qué acabo de hacer y por qué se ve de esta manera?
Dí mal un click.
AUDIENCIA: Abriste el archivo compilado.
DAVID: Sí, abrí el archivo compilado, el programa, no el código fuente.
Así que lo que veo es el código máquina.
Y dado que mi navegador no conoce su código máquina, de ceros y unos,
malinterpreta los ceros y unos como si fueran caracteres ASCII.
Recuerden que en ASCII la A mayúscula es 65, y la B mayúscula es 66.
El IDE trata de interpretar los ceros y unos en el código máquina de mi programa
como si fueran caracteres.
Pero no es realmente inglés, o no se trata de la sintaxis del inglés.
Son solo ceros y unos aleatorios en cierto sentido.
Y por eso estamos viendo caracteres y colores locos.
Porque son malinterpretados como colores o caracteres
que yo no escribí.
Así que no se preocupen.
Ignoren el problema y ciérrenlo.
Y luego abran switch.c.
Esta no es una característica de Scratch, pero sirve para demostrar,
incluso en C, que hay más formas de aplicar la misma idea.
Me desplazaré un poco hacia arriba.
Y verán que en la parte superior del archivo tengo main como antes.
Pongo el cursor en el usuario para un carácter.
Pero esta vez no utilizo if ni else.
Noten que uso una nueva palabra clave que no existe en Scratch, llamada switch.
Se pone entre paréntesis, es una variable que desean ver
y una variable o valor con la que desean
tomar decisiones, según sus bases para tomar decisiones.
Y parece que tenemos cuatro casos aquí, los cuales
son más atractivos de lo que aparentan.
¿Qué hace este programa cuando se ejecuta?
Aunque nunca antes hayamos visto una oración con switch.
¿Qué parece hacer?
¿Qué es eso?
PÚBLICO: En diferentes casos, hay diferentes opciones.
DAVID: Sí, diferentes casos, diferentes opciones.
Así que, si escribo una Y mayúscula para este programa cuando se ejecuta,
¿Qué pasará?
Imprimirá yes.
¿Y si escribo una N mayúscula?
PÚBLICO: [INAUDIBLE].
DAVID: ¿n minúscula?
PÚBLICO: [INAUDIBLE].
DAVID: Y así sucesivamente.
De hecho es exactamente el mismo programa,
solo que se escribió con una función diferente,
entonces existen diferentes modos en los que pueden expresarse,
como si dos personas tuvieran la misma opinión en un caso judicial.
Puede que tengan las mismas opiniones, pero ellas
se expresarán en inglés de diferente manera.
Así que en C, pueden escribir el mismo programa, se comportará exactamente igual,
pero usarán un enfoque diferente con distintas construcciones
como switches.
Y este es el caso con la Y mayúscula y la y minúscula,
solo significa que si se presenta cualquiera de estos dos casos,
se debe insertar el código debajo de ellas.
Pero después se interrumpe.
Si se interrumpe, deben asegurarse de que no se siga ejecutando lo que está debajo.
Porque si no tiene una interrupción, el programa
continuará ejecutando las líneas del código que están debajo.
Y si he escrito y, podría decir de manera incorrecta
yes, no, porque no le dije que se detuviera.
Pueden obtener interrupciones libremente con los condicionales If
porque tenemos esas llaves.
El switch no utiliza llaves en su interior,
sino una sintaxis ligeramente distinta.
¿Cuál es la mejor?
Depende.
Algunas veces, parece mejor [INAUDIBLE] el switch en cierto sentido,
una persona razonable podría decir [INAUDIBLE] una mejor
versión del programa que acabamos de escribir.
Porque véanlo, es mucho más compacto, ¿cierto?
Es más fácil de digerir visualmente.
Escribí menos caracteres.
Pero quizás alguien no esté de acuerdo y diga, yo rara vez utilizo switches,
nunca recuerdo cómo funcionan.
Esto es menos legible para mí.
Entonces, se trata del estilo de cada persona
en casos como este, cuando se trata de diseños.
Muy bien.
Vamos a introducir otra idea, otro bloque de construcciones
que hemos visto antes, pero que no hemos aplicado.
Para continuar haremos lo siguiente.
Voy a crear un programa que se llamará return.c,
así puedo poner en práctica la idea que Sam actuó para nosotros.
A continuación incluiré la biblioteca del CS50
y después voy a incluir la biblioteca estándar.
Después pondré este int main(void), como antes.
Y luego, aquí abajo, pondré int x = get_int("x: );
Y señalaré al usuario con la x.
Y entonces diré printf("%i\ n")...
Y ahora quiero el cuadrado de x printf("%i\ n", x*x)
Porque x veces por sí misma me dará x al cuadrado.
Ahora es muy sencillo.
No es un programa difícil de escribir, especialmente
una vez que se conoce la multiplicación.
Y esto parece hacer exactamente eso.
Si escriben 2, me da 2 al cuadrado, igual a cuatro, y así sucesivamente.
Pero ya saben, el cuadrado es una función que me gusta mucho usar,
¿verdad?
Es como una operación matemática.
Y sí, claro que es trivial implementarlo con x veces x.
Pero sería bueno abstraernos y solo decir
la palabra square.
Bueno, si su lenguaje de programación no viene con una función
llamada square, no hay mucho problema.
Podemos implementarla nosotros mismos.
Podemos hacerlo de la siguiente manera.
Entonces escribiré lo siguiente.
int square(int n)
Y luego aquí, return n * n;
¿Qué acabo de hacer?
Es posible que no hayan hecho esto en sus programas de Scratch,
pero tal vez recuerden que en la última clase,
dimos un ejemplo sobre la tos, con una pieza del rompecabezas personalizada
era una pieza de rompecabezas morada.
La tos no era un bloque que existiera cuando mi equipo lo hizo en Scratch
pero lo creamos.
Es posible que square no exista en C, en las bibliotecas que estamos usando.
Así que lo construiremos.
¿Cómo lo hacemos?
Bueno, podemos comenzar por solucionar en parte
la pregunta que surgió antes sobre int y void, aunque solo parcialmente
por hoy.
Este es el nombre de mi función.
Es mi pieza de rompecabezas personalizada, si quieren verlo así.
Toma como entrada, con los paréntesis, un valor que arbitrariamente
llamaré n.
Podría llamarlo m, o, p, o lo que quieran.
Pero n representa un número, así que tomé n, como cualquier especialista en sistemas.
Y todo lo que hace es ejecutar una línea de código.
n veces n,
pero entonces devuelve el valor.
Y en especial, esta palabra clave que está resaltada aquí,
es parecida a la que Sam me devolvió en una hoja de papel.
Él me devolvió un valor en una hoja de papel.
Aquí devuelve n veces n.
Y eso implica, ¿qué tipo de datos devuelve esta función personalizada
a quien la usa?
Es un entero, porque n es un entero.
Y resulta lógico que n veces n sea un número entero.
Esa es la razón por la cual también especifiqué a int aquí.
Resulta que las funciones, para ser más claros, pueden tomar entradas
y pueden devolver salidas.
Si toman entradas, estas deben ponerse entre paréntesis,
como las que he resaltado aquí, en la línea 10.
Y en este caso se trata de una entrada, una variable llamada n de tipo int.
Pero esta función también, al igual que la implementación de Sam con get_string
devuelve un valor, no una cadena sino un entero.
Entonces tengo que decir a la computadora, hey, esta función personalizada
que acabo de escribir devolverá un número entero a quien la utilice.
Y es esta línea del código, la línea 12, la que realmente
implementa la funcionalidad de la cual se obtiene el valor que interesa.
De modo que ya no necesito repetir esto ni reinventar la rueda.
Ahora puedo utilizar square como una palabra clave en todos mis programas.
Pero, ¿cómo la llamamos?
Hasta ahora, cada vez que he nombrado funciones, lo hago de esta manera.
int squaredvalue =...
Y luego podría ponerle int squaredvalue = square(x);
Pero hago esto de manera intuitiva, ¿cierto?
No sé si es lo mejor, pero hace que siga un patrón.
En el lado izquierdo, declaré una variable llamada squaredvalue,
aunque es un nombre algo pretencioso.
Probablemente podríamos usar algo mejor.
Pero squaredvalue es un tipo de entero.
En el lado derecho lo llamo square,
pongo su nombre, abro paréntesis
y luego introduzco el valor de entrada,
del mismo modo en que le entregué a Sam un pedazo de papel con los datos.
Y entonces regreso ese valor de derecha a izquierda.
Luego utilizo el operador de asignación, simplemente el signo igual.
Entonces, ¿cómo puedo mejorar la línea 8 para finalizar esta idea?
En vez de escribir x veces x, ¿qué debo escribir aquí simplemente?
Pues squaredvalue, lo cual es un poco tonto ahora que he
añadido más caracteres y que he logrado exactamente lo mismo.
Pero no necesito este valor intermedio y aquí tenemos
una oportunidad para mejorar el diseño.
Si en la línea 7 únicamente declaro una variable
y luego la uso de inmediato en la línea 8, entonces no es necesario que exista,
porque pueden anidar bloques de código de la siguiente manera.
Puedo tomar square de x, el cual sé que nos devuelve el cuadrado de x.
Puedo borrar la línea 7 por completo.
Y puedo hacer esto aún más elegante, así como también se pueden anidar las piezas.
Y podría decirse que tiene un mejor diseño
porque tiene menos líneas de código.
Solamente dice lo que hace.
Y no tendrán ninguna variable aleatoria temporal que vaya de una línea
hacia el texto.
Tal vez sea menos legible, cada persona tiene su propio estilo,
pero al menos ahora tengo esto.
Aunque hay un problema.
Incluso si todo esto tiene sentido, o si es súper nuevo para muchos de ustedes,
Tengo un error.
Cometí un error.
¿Y cómo puedo solucionarlo?
La declaración implícita de la función "square" es inválida en C99.
C99 significa que es la versión de 1999 de un lenguaje llamado C.
La declaración implícita de la función square.
Bueno, aún no lo hemos dicho explícitamente,
pero C es un poco tonto.
Solo hace lo que se le pide que haga.
Y por desgracia, y esto es un error, en la línea 7
llamo a la función square mencionando su nombre.
Por desgracia, ¿en cuál línea de código enseño a la computadora que square
siquiera existe?
No hasta unas líneas después, en la línea 10 y posteriores.
Así que es demasiado tarde.
Traté de utilizar square incluso antes de existiera.
Pero puedo arreglarlo en un par de formas.
Puedo tomar este bloque de código, moverlo y guardarlo otra vez.
Y ejecutar make return y funciona.
Pero es como el juego del gato y el ratón.
Con el tiempo verán que sus programas se complican bastante,
no podrán mover cada función por encima de las otras funciones.
En algún momento, construirán un escenario
donde ninguna función puede estar por encima de otra.
Pero eso está bien.
Porque también podemos deshacer esto y escribir square en la parte inferior
y mantener main en la parte superior, lo cual es la mejor opción.
Es mejor mantenerlo en la parte superior ya que es la función predeterminada
que al humano le interesa.
Y puedo ser algo redundante,
pero está bien en este caso.
Puedo darle al compilador, clang en este caso, una pista de lo que vendrá.
No tengo que decirle cómo se implementa.
Pero en la línea 4, puedo usar algo llamado prototipo.
Un pequeño avance, parecido al trailer de una película, de la función que
finalmente se implementará.
Todo lo que clang debe saber desde el principio
es, cuáles son sus entradas y sus salidas.
La implementación entre llaves puede ponerse más tarde.
Entonces, si pongo return otra vez, el programa
parece compilar con éxito, puedo escribir ./return
Y luego, si pongo que x es 3, el cuadrado de x
será 9 en este caso.
Y podemos hacer estas abstracciones en muchos contextos diferentes
implementando ideas como el cuadrado, y entonces llamarlo
por su nombre, square, pero no se preocuparán
por cómo se implementó.
Lamentablemente, chocaremos con algunos límites.
Chocaremos con algunos límites como el que sigue.
Para continuar, les recordaré un visual
que posiblemente no han visto dentro de su computadora
Y es el siguiente.
De hecho, dentro de sus Mac, PC, laptops, o incluso de sus teléfonos,
hay cosas como esta.
Estas son placas de RAM o de memoria.
Cuando digo que mi computadora tiene uno o dos gigabytes de memoria,
generalmente tiene una o más de estas cosas.
Y podrían tener formas ligeramente diferentes.
Por ejemplo, esta proviene de una laptop.
Y hay otras cosas dentro de sus computadoras que también tienen límites.
Pero por ahora, solo nos interesa esto.
Se trata de un dispositivo físico.
Almacena ceros y unos cuando sus computadoras están funcionando.
Cuando dan doble clic en un icono de Mac OS o Windows, y cargan un programa,
estudian matemáticas o escriben un ensayo, eso se almacena en este hardware físico
como ceros y unos.
Pero la ram, la memoria que tenemos en nuestras computadoras, es finita.
Esta mide solo algunas pulgadas por algunas pulgadas.
Solo almacena cierta cantidad de millones o miles de millones de bits,
y eso es todo.
Entonces tenemos una cantidad fija de memoria.
Eso no es bueno cuando se trata de escribir programas
en los que no se sabe previamente qué tan grandes serán los números
que los humanos escribirán.
O qué tan largo será un ensayo escrito por un humano.
Sin duda se podría idear un escenario donde el ensayo sea solo pura palabrería
que no quepa en la memoria de la computadora.
O que su número tenga tantos dígitos,
que no quepa en la memoria de la computadora, porque es fija.
Solo se tiene una cantidad finita.
Y esto trae consecuencias muy serias para al menos dos problemas.
Existe algo bastante esotérico, que se llama desbordamiento de enteros,
y se puede ver de vez en cuando
en los medios de comunicación, como un problema del mundo real.
Aquí, por ejemplo, hay 8 bits.
La última vez observamos solo tres, pero aquí hay ocho.
Y si lo notan, es un número bastante elevado.
Son muchos unos.
Y esto sucede, si hacen los cálculos de la última vez,
para representar 254.
¿Qué sucede si incremento este número en 1?
¿Qué cambios ocurren, según la última lección?
Sí, lo más correcto.
El 0 se convierte en 1.
Y luego todos se convierten en unos,
lo que sucede es que si se cuentan 255 lugares.
Si a esto le sumamos 1 más, ¿qué ocurre?
En el mundo humano, idealmente tomaríamos un marcador o un gis
y escribiríamos un número más.
Pero en el mundo de las computadoras, si solo tienen una cantidad fija de memoria,
que con suerte es mayor a 8 bits,
podría haber millones o miles de millones, y en algún momento se agotará.
De hecho, todos los tipos de datos de los que hablamos hoy, como ints, chars
y floats utilizan un número finito de bits,
que por lo general es 8, 16, 32 o 64.
Es una potencia de dos pero fija, es decir un programa de computadora
usa ints, chars y floats para contar un número muy alto,
mientras que los humanos, en teoría, podemos contar hasta el infinito.
Y el problema es, si se tiene una serie como esta
que ya es lo más grande posible, con todos los bits 1, todos los focos prendidos,
si se le agrega uno más
y ya no cabe ni uno,
entonces todos esos valores, de pronto se convertirán en 0
y los enteros se desbordarán.
Se obtiene el 255, y qué creen que siga después del 255, si solo se tienen 8 bits.
Cero, aparentemente, porque todos los 1 cambian y se convierten en 0.
Entonces, una computadora solo puede contar tan alto usando un int,
un float o un double.
Y en algún momento, si se intenta añadir uno más,
los números se desbordarán y terminarán
siendo algo que no se espera.
Tal vez sea positivo, tal vez negativo, o tal vez termine siendo 0.
Y de hecho podemos verlo.
Para mostrarlo abriré un programa llamado
Overflow, que está disponible en línea, y que literalmente hace esto
si lo ejecuto.
Make overflow.
./overflow.
Conforme ejecuto este programa, contará de 1, a 2, a 4,
a 8, a 16.
Simplemente escribí un programa que duplica
el número en cada iteración del bucle.
Y también utilicé otra función llamada sleep
de modo que esto no se salga de la pantalla.
Quería hacer una pausa, como en Scratch.
Pueden esperar.
Se vuelve cada vez más grande y más grande, y esto es exponencial.
Así que se volverá más grande y más grande mucho más rápido, lo cual
es bueno porque no tardará eternamente
para alcanzar un número muy grande.
Pero estoy usando un entero.
Y con un entero solo se puede contar, aproximadamente, hasta 4 mil millones
y técnicamente solo hasta 2 mil millones si quieren también números negativos,
si desean que la mitad sea negativa y la mitad positiva.
Y ahí está.
Eventualmente, si hablo lo suficiente, duplicaré este entero tantas veces
que simplemente no cabrá en 32 bits y la computadora me avisará
con un error en el tiempo de ejecución.
Y luego pasarán cosas extrañas.
Ahora estoy atascado en 0.
Y ahora ven realmente como sucede.
Pero también hay un otro problema y se trata de un programa super sencillo
que no pensarían que pudiera presentar errores, pero lo hace.
A continuación escribiré rápidamente un programa
que incluya la biblioteca estándar.
Int main(void), como antes.
Guardaré esto como una imprecisión, como un problema diferente,
.c
Y simplemente haré lo siguiente.
printf("%f\ n", 1-0 / 10.0);
...con 1.0 dividido por 10.0.
Ahora, según lo que aprendieron en la primaria, ¿Cuál sería la respuesta?
PÚBLICO: 0.1.
DAVID: 0.1.
Eso es el 10%.
0.1.
Y si continúo y ejecuto ./imprecision.
Y esto sería 0.10000, lo cual es lo mismo.
Pero estoy dispuesto a apostar un dólar a que nos han mentido a todos.
Ya que 1 dividido entre 10 realmente no es 0.1.
¿Alguien quiere apostar?
Debería haber afirmado esto antes de sacar el dólar.
Lo siento, ya mostré mis cartas.
Hago esta afirmación debido a lo siguiente.
Tal vez no estoy buscando lo suficiente dentro del número,
cuando pregunté antes cómo podíamos mostrar más dígitos decimales,
déjenme ver 10 de ellos,
déjenme tener algo de consuelo,
dejen que vuelva a compilar el programa,
dejen que lo vuelva a ejecutar
y pierda mi dólar.
Voy a cambiar... no sé... a los 55 dígitos posibles.
Observemos a profundidad dentro del número.
./imprecision.
Interesante.
Entonces, si alguien más jugara, apostaría de nuevo el dólar en este punto.
Y ahora, vemos que 1 dividido entre 10 en realidad no es 0.10000,
como nuestros maestros de primaria nos dijeron, esos ceros deberían irse
al infinito.
Es impreciso.
¿Por qué es así?
¿Por que 1 dividido entre 10, al menos en mi Mac o en el IDE de CS50,
no es en realidad 0.1?
¿Qué les dice su intuición?
Bueno, si solo tienen una cantidad finita de este elemento,
solo pueden representar un número finito de números, ¿verdad?
Si solo tienen 32 o 64 bits, sin embargo, no importa cuantos bits tengan
solo podrán permutarlos en un número finito de maneras.
Finalmente, se quedarán sin patrones de ceros y unos.
Y resulta que 1 dividido por 10, por lo menos en este equipo,
no puede representarse con precisión porque no tenemos un número infinito
de patrones 0 y 1 para representar los números reales posibles, llamado
Valores de punto de flotante.
Porque, por supuesto, hay un número infinito de ellos
y solo una cantidad finita de memoria.
Para concluir, y esto tiene implicaciones en el mundo real,
si alguna vez jugaron Lego Star Wars
habrán notado que el número máximo de monedas que podían recolectar
era de 4 mil millones
y lo redondeaban un poco.
Técnicamente se podía contar un poco más de 4 mil millones,
y probablemente era porque, ¿qué tipo de datos usaba Lego
para almacenar el número de monedas?
Números enteros, que son de 32 bits.
Todo estaba bien,
ya que en realidad lo anticiparon y pensaron en ello.
Aquí vemos un Boeing 787,
o de hecho, aquí hay una historia divertida.
Bueno, este es un Boeing 787 cuya
documentación asociada a él, donde decía que el avión debía
ser reiniciado cada 248 días.
En especial este avión modelo 787, que había funcionado continuamente
durante 248 días, si no se reiniciaba podía perder toda su corriente eléctrica
debido a que la computadora se ponía simultáneamente
en modo a prueba de fallos.
Esta condición era causada por un software contador
interno en la computadora, que se desbordaba
después de recibir 248 días de corriente continua.
Así que una compañía como Boeing
no sabía que si dejaban un avión durante el tiempo suficiente
y solo se utiliza un número entero o 32 bits, o lo que sea
esos números podrían, sigilosamente, ser lo suficientemente grandes como para
invertirse y causar una catastrófe, como hacer que el avión se apague
en este caso.
Y un poco menos aterrador, pero no obstante real,
les contaré un cuento antes de finalizar,
y se trata de Civilización, o de Gandhi en este caso.
Si llegan a jugar el juego Civilización
elijan al personaje de Gandhi, quien era muy tranquilo, según la definición
del juego, tenía un nivel de agresividad
de solo uno, lo cual significa que era muy inofensivo.
Pero los autores de este juego, Civilización,
solo utilizaron 8 bits, eso significa que solo pueden contar hasta 255.
Entonces 255 sería el máximo de agresividad.
Así que 1 es nada agresivo.
Pero hay una característica en el juego, en la cual, si Gandhi en su civilización
adoptaba la democracia, había una línea de código que
decía que, si en cualquier época una civilización adopta la democracia,
su agresividad disminuye por dos, ya que son personas satisfechas.
Desafortunadamente, si sus niveles de agresividad comienzan en 1 y le restan 2,
se puede desbordar, o desbordarse inversamente, como ocurre en 1 menos 2,
que daría un 1 negativo.
Y esto, de hecho, sería 255.
Así que nos daría la cifra absurdamente alta de 255
y haría que Gandhi tuviera el nivel más agresivo que existe en Civilización.
Así que aquí podemos ver decisiones de diseño del mundo real.
Y lo que haremos en la próxima lección del viernes, y posteriormente,
es explorar estas cuestiones, iniciaremos resolviendo problemas sobre ellas.
Mientras tanto, la serie de problemas uno ya está en línea.
La reunión de orientación es hoy y mañana.
Pueden quedarse si tienen dudas o preguntas.
Y nos vemos el siguiente viernes.