Clase 1
- C
- hello, world
- Compiladores
- Cadena
- Bloques de Scratch en C
- Tipos, formatos, operadores
- Más ejemplos
- Memoria, imprecisión y desbordamiento
C
-
Hoy aprenderemos un nuevo lenguaje, C: un lenguaje de programación que tiene todas las funciones de Scratch y más, pero quizás sea un poco menos amigable ya que es puramente de texto:
#include <stdio.h> int main(void) { printf("hello, world\n"); }
- Aunque las palabras son nuevas, las ideas son exactamente las mismas que los bloques "cuando se hace clic en la bandera verde" y "decir (hola, mundo)" en Scratch:
- Aunque las palabras son nuevas, las ideas son exactamente las mismas que los bloques "cuando se hace clic en la bandera verde" y "decir (hola, mundo)" en Scratch:
-
Aunque parezca críptico, no olvides que 2/3 de los estudiantes de CS50 nunca han tomado CS antes, ¡así que no te asustes! Y aunque al principio, para tomar prestada una frase del MIT, tratar de absorber todos estos conceptos nuevos puede parecer como beber de una manguera contra incendios, ten la seguridad de que para el final del semestre estaremos empoderados y experimentados en aprender y aplicar estos conceptos.
- Podemos comparar muchas de las construcciones en C con los bloques que ya hemos visto y usado en Scratch. La sintaxis es mucho menos importante que los principios, a los que ya hemos sido introducidos.
Hola, mundo
-
El bloque “cuando se dio clic en la bandera verde” en Scratch inicia el programa principal; al hacer clic en la bandera verde, el conjunto correcto de bloques debajo comienza. En C, la primera línea para lo mismo es
int main(void)
, que aprenderemos más en las próximas semanas, seguido de una llave de apertura{
, y una llave de cierre}
, envolviendo todo lo que debería estar en nuestro programa.int main(void) { }
-
El bloque “decir (hola, mundo)” es una función, y corresponde a
printf(“hola, mundo”);
. En C, la función para imprimir algo en la pantalla esprintf
, dondef
significa “formato”, lo que significa que podemos formatear la cadena impresa de diferentes maneras. Luego, usamos paréntesis para transmitir lo que queremos imprimir. Tenemos que usar comillas dobles para rodear nuestro texto para que se entienda como texto, y finalmente, agregamos un punto y coma;
al final de esta línea de código. - Para que nuestro programa funcione, también necesitamos otra línea en la parte superior, una línea de encabezado
#include <stdio.h>
que define la funciónprintf
que queremos usar. En algún lugar hay un archivo en nuestra computadora,stdio.h
, que incluye el código que nos permite acceder a la funciónprintf
, y la línea de#include
le dice a la computadora que incluya ese archivo con nuestro programa. - Para escribir nuestro primer programa en Scratch, abrimos el sitio web de Scratch. Del mismo modo, usaremos el CS50 Sandbox para comenzar a escribir y ejecutar código de la misma manera. CS50 Sandbox es un entorno virtual basado en la nube con las bibliotecas y herramientas ya instaladas para escribir programas en varios idiomas. En la parte superior, hay un editor de código simple, donde podemos escribir texto. Debajo, tenemos una ventana de terminal, en la que podemos escribir comandos:
- Escribiremos nuestro código de antes en la parte superior, después de usar el signo
+
para crear un nuevo archivo llamadohello.c
: - Finalizamos el archivo de nuestro programa con
.c
por convención, para indicar que está destinado a ser un programa en C. Observe que nuestro código está coloreado, para que ciertas cosas sean más visibles.
Compiladores
- Una vez que guardamos el código que escribimos, que se conoce como código fuente, necesitamos convertirlo a código máquina, instrucciones binarias que el computador entiende directamente.
- Usamos un programa llamado compilador para compilar nuestro código fuente en código de máquina.
- Para hacer eso, utilizamos el panel de Terminal, que tiene un símbolo del sistema. El
$
a la izquierda es un símbolo después del cual podemos escribir comandos.- Escribimos
clang hello.c
(dondeclang
significa “lenguajes C”, un compilador escrito por un grupo de personas). Pero antes de presionar Enter, hacemos clic en el ícono de la carpeta en la parte superior izquierda del CS50 Sandbox. Vemos nuestro archivohello.c
. Entonces presionamos Enter en la ventana de terminal y vemos que ahora tenemos otro archivo, llamadoa.out
(abreviatura de “salida de ensamblaje”). Dentro de ese archivo está el código para nuestro programa en binario. Ahora podemos escribir./a.out
en el símbolo del sistema para ejecutar el programaa.out
en nuestra carpeta actual. ¡Acabamos de escribir, compilar y ejecutar nuestro primer programa!
- Escribimos
String
-
Pero después de ejecutar nuestro programa, vemos
hello, world$
, con el nuevo indicador en la misma línea que nuestra salida. Resulta que debemos especificar precisamente que necesitamos una nueva línea después de nuestro programa, para que podamos actualizar nuestro código para incluir un carácter de nueva línea especial,\n
:#include <stdio.h> int main(void) { printf("hello, world\n"); }
- Ahora debemos recordar recompilar nuestro programa con
clang hello.c
antes de poder ejecutar esta nueva versión.
- Ahora debemos recordar recompilar nuestro programa con
-
La línea 2 de nuestro programa está intencionalmente en blanco ya que queremos comenzar una nueva sección de código, al igual que comenzar nuevos párrafos en los ensayos. No es estrictamente necesario que nuestro programa se ejecute correctamente, pero ayuda a los humanos a leer programas más largos con mayor facilidad.
- También podemos cambiar el nombre de nuestro programa de
a.out
a otra cosa. Podemos pasar argumentos de línea de comandos, u opciones adicionales, a programas en la terminal, dependiendo de lo que el programa esté escrito para entender. Por ejemplo, podemos escribirclang -o hello hello.c
, y-o hello
le está diciendo al programaclang
que guarde la salida compilada comohello
. Entonces, podemos simplemente ejecutar./hello
. -
En nuestro símbolo del sistema, podemos ejecutar otros comandos, como
ls
(lista), que muestra los archivos en nuestra carpeta actual:$ ls a.out* hello* hello.c
- El asterisco,
*
, indica que esos archivos son ejecutables o que pueden ser ejecutados por nuestra computadora.
- El asterisco,
-
Podemos usar el comando
rm
(eliminar) para eliminar un archivo:$ rm a.out rm: ¿quitar archivo regular 'a.out'?
- Podemos escribir
y
osí
para confirmar y usarls
nuevamente para ver que efectivamente se fue para siempre.
- Podemos escribir
-
Ahora, intentemos obtener información del usuario, como lo hicimos en Scratch cuando quisimos decir "hola, David":
string answer = get_string("What's your name?\n"); printf("hello, %s\n", answer);
- Primero, necesitamos una cadena, o fragmento de texto (específicamente, cero o más caracteres en una secuencia entre comillas dobles, como
""
,"ba"
, o "bananas"), que podemos solicitarle al usuario, con la funciónget_string
. Pasamos el indicador, o lo que queremos preguntarle al usuario, a la función con"What is your name?\n"
dentro de los paréntesis. A la izquierda, queremos crear una variable,answer
, cuyo valor será lo que ingrese el usuario. (El signo igual=
establece el valor de derecha a izquierda). Finalmente, el tipo de variable que queremos esstring
, por lo que lo especificamos a la izquierda deanswer
. - A continuación, dentro de la función
printf
, queremos el valor deanswer
en lo que imprimimos de nuevo. Usamos un marcador de posición para nuestra variable de cadena,%s
, dentro de la frase que queremos imprimir, como"hello, %s\n"
, y luego le damos aprintf
otro argumento u opción para decirle que queremos que la variableanswer
sea sustituido.
- Primero, necesitamos una cadena, o fragmento de texto (específicamente, cero o más caracteres en una secuencia entre comillas dobles, como
-
Si cometimos un error, como escribir
printf("hello, world"\n);
con el\n
fuera de las comillas dobles de nuestra cadena, veremos errores de nuestro compilador:$ clang -o hello hello.c hello.c:5:26: error: paréntesis esperado printf("hello, world"\n); ^ hello.c:5:11: nota: para que coincida con este '(' printf("hello, world"\n); ^ 1 error generado.
- La primera línea del error nos dice que miremos
hello.c
, línea 5, columna 26, donde el compilador esperaba un paréntesis de cierre, en lugar de una barra invertida.
- La primera línea del error nos dice que miremos
-
Para simplificar las cosas (al menos al principio), incluiremos una biblioteca o un conjunto de código de CS50. La biblioteca nos proporciona el tipo de variable
string
, la funciónget_string
y más. Solo tenemos que escribir una línea en la parte superior paraincluir
el archivocs50.h
:#include <cs50.h> #include <stdio.h> int main(void) { string name = get_string("What's your name?\n"); printf("hello, name\n"); }
-
Así que creemos un nuevo archivo,
string.c
, con este código:#include <stdio.h> int main(void) { string name = get_string("What's your name?\n"); printf("hello, %s\n", name); }
-
Ahora, si intentamos compilar ese código, obtenemos muchas líneas de errores. A veces, un error significa que el compilador comienza a interpretar el código correcto incorrectamente, lo que genera más errores de los que realmente hay. Entonces comenzamos con nuestro primer error:
$ clang -o string string.c string.c:5:5: error: uso de identificador no declarado 'string'; ¿querías decir 'stdin'? string name = get_string("What's your name?\n"); ^~~~~~ stdin /usr/include/stdio.h:135:25: nota: 'stdin' declarado aquí extern struct _IO_FILE *stdin; /* Standard input stream. */
- No quisimos
stdin
("entrada estándar") en lugar destring
, por lo que ese mensaje de error no fue útil. De hecho, necesitamos importar otro archivo que defina el tipostring
(en realidad, una rueda de entrenamiento de CS50, como descubriremos en las próximas semanas).
- No quisimos
-
Entonces podemos incluir otro archivo,
cs50.h
, que también incluye la funciónget_string
, entre otras.#include <cs50.h> #include <stdio.h> int main(void) { string name = get_string("What's your name?\n"); printf("hello, %s\n", name); }
-
Ahora, cuando intentamos compilar nuestro programa, solo tenemos un error:
$ clang -o string string.c /tmp/string-aca94d.o: In function `main': string.c:(.text+0x19): referencia indefinida a `get_string' clang-7: error: el comando del enlazador falló con el código de salida 1 (use -v para ver la invocación)
- Resulta que también tenemos que decirle a nuestro compilador que agregue nuestro archivo de biblioteca especial CS50, con
clang -o string string.c -lcs50
, con-l
para "enlace".
- Resulta que también tenemos que decirle a nuestro compilador que agregue nuestro archivo de biblioteca especial CS50, con
-
Incluso podemos abstraer esto y simplemente escribir
make string
. Vemos que, por defecto en CS50 Sandbox,make
usaclang
para compilar nuestro código desdestring.c
enstring
, con todos los argumentos o banderas necesarios pasados.
Bloques de Scratch en C
- El bloque "poner [contador] a (0)" crea una variable y en C escribimos
int contador = 0;
dondeint
especifica que el tipo de nuestra variable es un entero: - "cambiar [contador] por (1)" es
contador = contador + 1;
en C. (En C, el=
no es como un signo igual en una ecuación que dice quecontador
es igual acontador + 1
. En cambio,=
es un operador de asignación que significa "copia el valor de la derecha en el valor de la izquierda"). Fíjate que ya no tenemos que decirint
porque asumimos que ya lo hemos especificado al decir quecontador
esint
, con cierto valor. También podemos decircontador += 1;
ocontador++;
, que son "azúcar sintáctico" (atajos con menos caracteres). -
Una condición se asigna así:
if (x < y) { printf("x es menor que y\n"); }
- Fíjate que en C, usamos
{
y}
(y también sangrías) para indicar cómo se deben anidar las líneas de código. -
También podemos usar condiciones
if-else
:if (x < y) { printf("x es menor que y\n"); } else { printf("x no es menor que y\n"); }
-
Fíjate que las líneas de código que no son acciones (
if...
y las llaves) no terminan en punto y coma. -
E incluso
si no si
:if (x < y) { printf("x es menor que y\n"); } else if (x > y) { printf("x es mayor que y\n"); } else if (x == y) { printf("x es igual a y\n"); }
-
Fíjate que para comparar dos valores en C usamos
==
, dos signos igual. - Y, lógicamente, no necesitamos
if (x == y)
en la condición final, porque es el único caso que queda y podemos decir simplementeelse
. -
Los bucles pueden escribirse así:
while (true) { printf("hello, world\n"); }
-
La palabra clave
while
también necesita una condición, así que usamostrue
como expresión booleana para garantizar que nuestro bucle se ejecute para siempre. Nuestro programa comprobará si la expresión estrue
(que siempre lo será en este caso) y luego ejecutará las líneas entre las llaves. Luego lo repetirá hasta que la expresión no seatrue
(que no cambiará en este caso). -
Podemos hacer algo un número de veces determinado con
while
:int i = 0; while (i < 50) { printf("hello, world\n"); i++; }
-
Creamos una variable,
i
, y le asignamos el valor 0. Luego, mientrasi < 50
, ejecutamos unas líneas de código y añadimos 1 ai
después de cada ejecución. - Las llaves que rodean las dos líneas dentro del bucle
while
indican que esas líneas se repetirán, y podemos añadir líneas adicionales a nuestro programa después si queremos. -
Para hacer la misma repetición, normalmente podemos usar la palabra clave
for
:for (int i = 0; i < 50; i++) { printf("hello, world\n"); }
-
De nuevo, primero creamos una variable llamada
i
y le asignamos el valor 0. Luego, comprobamos quei < 50
cada vez que llegamos al principio del bucle, antes de ejecutar el código. Si la expresión estrue
, ejecutamos el código. Finalmente, después de ejecutar el código, añadimos uno ai
coni++
y el bucle se repite.
- Fíjate que en C, usamos
Tipos, formatos, operadores
-
Existen otros tipos que podemos utilizar para nuestras variables:
bool
, una expresión booleana deverdadero
ofalso
char
, un solo carácter comoa
o2
double
, un valor de punto flotante con aún más dígitosfloat
, un valor de punto flotante o número real con un valor decimalint
, enteros hasta cierto tamaño o número de bitslong
, enteros con más bits, por lo que pueden contar más altostring
, una cadena de caracteres
-
Y la biblioteca CS50 tiene funciones correspondientes para obtener entrada de varios tipos:
get_char
get_double
get_float
get_int
get_long
get_string
-
Para
printf
, también, hay diferentes marcadores de posición para cada tipo:%c
para caracteres%f
para flotantes, dobles%i
para enteros%li
para largos%s
para cadenas
-
Y hay algunos operadores matemáticos que podemos utilizar:
+
para la adición-
para la resta*
para la multiplicación/
para la división%
para el resto
Más ejemplos
- Para cada uno de estos ejemplos, puedes hacer clic en los enlaces de "sandbox" para ejecutar y editar tus propias copias.
-
En
int.c
, obtenemos e imprimimos un entero:#include <cs50.h> #include <stdio.h> int main(void) { int age = get_int("¿Cuál es tu edad?\n"); int days = age * 365; printf("Tienes por lo menos %i días.\n", days); }
-
Observa que usamos
%i
para imprimir un entero. - Ahora, podemos ejecutar
make int
y ejecutar nuestro programa con./int
. -
Podemos combinar líneas y eliminar la variable
days
con:int age = get_int("¿Cuál es tu edad?\n"); printf("Tienes por lo menos %i días.\n", age * 365);
-
O incluso, combinar todo en una línea:
printf("Tienes por lo menos %i días.\n", get_int("¿Cuál es tu edad?\n") * 365);
-
Sin embargo, una vez que una línea es demasiado larga o complicada, puede ser mejor mantener dos o incluso tres líneas para mejorar la legibilidad.
-
En
float.c
, podemos obtener números decimales (llamados valores de punto flotante en las computadoras, porque la coma decimal puede "flotar" entre los dígitos, según el número):#include <cs50.h> #include <stdio.h> int main(void) { float price = get_float("¿Cuál es el precio?\n"); printf("Tu total es %f.\n", price * 1.0625); }
-
Ahora, si compilamos y ejecutamos nuestro programa, veremos un precio impreso con impuestos.
-
Podemos especificar el número de dígitos impresos después del decimal con un marcador de posición como
%.2f
para dos dígitos después del punto decimal. -
Con
parity.c
, podemos comprobar si un número es par o impar:#include <cs50.h> #include <stdio.h> int main(void) { int n = get_int("n: "); if (n % 2 == 0) { printf("par\n"); } else { printf("impar\n"); } }
-
Con el operador
%
(módulo), podemos obtener el resto den
después de dividirlo por 2. Si el resto es 0, sabemos quen
es par. De lo contrario, sabemos que n es impar. -
Y funciones como
get_int
de la biblioteca CS50 hacen comprobaciones de errores, donde solo se aceptan las entradas del usuario que coincidan con el tipo que queremos. -
En
conditions.c
, convertimos los fragmentos de condición de antes en un programa:// Condiciones y operadores relacionales #include <cs50.h> #include <stdio.h> int main(void) { // Solicitar al usuario x int x = get_int("x: "); // Solicitar al usuario y int y = get_int("y: "); // Comparar x e y if (x < y) { printf("x es menor que y\n"); } else if (x > y) { printf("x es mayor que y\n"); } else { printf("x es igual a y\n"); } }
-
Las líneas que comienzan con
//
son comentarios, o notas para los humanos que el compilador ignorará. -
Para que David compile y ejecute este programa en su entorno "sandbox", primero tuvo que ejecutar
cd src1
en el terminal. Esto cambia el directorio, o carpeta, al lugar donde guardó todos los archivos de origen de la clase. Luego, pudo ejecutarmake conditions
y./conditions
. Conpwd
, puede ver que se encuentra en una carpetasrc1
(dentro de otras carpetas). Ycd
por sí solo, sin argumentos, nos llevará de vuelta a nuestra carpeta predeterminada en el entorno "sandbox". -
En
agree.c
, podemos pedirle al usuario que confirme o niegue algo:// Operadores lógicos #include <cs50.h> #include <stdio.h> int main(void) { // Pedirle al usuario que esté de acuerdo char c = get_char("¿Estás de acuerdo?\n"); // Comprobar si está de acuerdo if (c == 'Y' || c == 'y') { printf("De acuerdo.\n"); } else if (c == 'N' || c == 'n') { printf("No está de acuerdo.\n"); } }
-
Usamos dos barras verticales,
||
, para indicar un "o" lógico, si cualquiera de las expresiones puede ser verdadera para que se siga la condición. -
Y si ninguna de las expresiones es verdadera, no ocurrirá nada, ya que nuestro programa no tiene un bucle.
-
Implementemos el programa de tos de la semana 0:
#include <stdio.h> int main(void) { printf("cough\n"); printf("cough\n"); printf("cough\n"); }
-
Podríamos usar un bucle
for
:#include <stdio.h> int main(void) { for (int i = 0; i < 3; i++) { printf("cough\n"); } }
- Por convenio, los programadores suelen empezar a contar desde 0, por lo que
i
tendrá los valores de0
,1
y2
antes de detenerse, para un total de tres iteraciones. También podríamos escribirfor (int i = 1; i <= 3; i++)
para lograr el mismo efecto final.
- Por convenio, los programadores suelen empezar a contar desde 0, por lo que
-
Podemos trasladar la línea de
printf
a su propia función:#include <stdio.h> void cough(void); int main(void) { for (int i = 0; i < 3; i++) { cough(); } } void cough(void) { printf("cough\n"); }
- Hemos declarado una nueva función con
void cough(void);
, antes de que nuestra funciónmain
la llame. El compilador de C lee nuestro código de arriba abajo, por lo que tenemos que decirle que la funcióncough
existe, antes de usarla. Entonces, después de nuestra funciónmain
, podemos implementar la funcióncough
. De esta forma, el compilador sabe que la función existe y podemos mantener nuestra funciónmain
cerca de la parte superior. - Y nuestra función
cough
no toma ninguna entrada, por lo que tenemoscough(void)
.
- Hemos declarado una nueva función con
-
Podemos abstraer
cough
más a fondo:#include <stdio.h> void cough(int n); int main(void) { cough(3); } void cough(int n) { for (int i = 0; i < n; i++) { printf("cough\n"); } }
- Ahora, cuando queramos imprimir "cough" cualquier número de veces, podemos simplemente llamar a la misma función. Ten en cuenta que, con
void cough(int n)
, indicamos que la funcióncough
toma como entrada unint
, al que nos referimos comon
. Y dentro decough
, usamosn
en nuestro buclefor
para imprimir "cough" el número correcto de veces.
- Ahora, cuando queramos imprimir "cough" cualquier número de veces, podemos simplemente llamar a la misma función. Ten en cuenta que, con
-
Veamos
positive.c
:#include <cs50.h> #include <stdio.h> int get_positive_int(void); int main(void) { int i = get_positive_int(); printf("%i\n", i); } // Solicitar al usuario un entero positivo int get_positive_int(void) { int n; do { n = get_int("%s", "Entero positivo: "); } while (n < 1); return n; }
- La biblioteca CS50 no tiene una función
get_positive_int
, pero podemos escribir una nosotros mismos. Nuestra funciónint get_positive_int(void)
solicitará al usuario unint
y devolverá eseint
, que nuestra funciónmain
almacena comoi
. Enget_positive_int
, inicializamos una variable,int n
, sin asignarle todavía ningún valor. Entonces, tenemos una nueva construcción,do ... while
, que hace algo primero, luego verifica una condición y repite hasta que la condición ya no sea verdadera. - Una vez que el bucle finaliza porque tenemos una
n
que no es< 1
, podemos devolverla con la palabra clavereturn
. Y de regreso en nuestra funciónmain
, podemos establecerint i
en ese valor.
- La biblioteca CS50 no tiene una función
Pantallas
-
Podríamos querer un programa que imprima parte de una pantalla de un videojuego como Super Mario Bros. En
mario0.c
, tenemos:// Imprime una fila de 4 signos de interrogación #include <stdio.h> int main(void) { printf("????\n"); }
-
Podemos pedirle al usuario un número de signos de interrogación y luego imprimirlos, con
mario2.c
:#include <cs50.h> #include <stdio.h> int main(void) { int n; do { n = get_int("Ancho: "); } while (n < 1); for (int i = 0; i < n; i++) { printf("?"); } printf("\n"); }
-
Y podemos imprimir un conjunto bidimensional de bloques con
mario8.c
:// Imprime una cuadrícula de ladrillos de n por n con un bucle #include <cs50.h> #include <stdio.h> int main(void) { int n; do { n = get_int("Tamaño: "); } while (n < 1); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { printf("#"); } printf("\n"); } }
- Tenga en cuenta que tenemos dos bucles anidados, donde el bucle externo usa
i
para hacer todo dentron
veces, y el bucle interno usaj
, una variable diferente, para hacer algon
veces para cada uno de esos tiempos. En otras palabras, el bucle externo imprimen
"filas" o líneas, y el bucle interno imprimen
"columnas" o caracteres#
en cada línea.
- Tenga en cuenta que tenemos dos bucles anidados, donde el bucle externo usa
-
Otros ejemplos no cubiertos en la conferencia están disponibles en "Código fuente" para Semana 1.
Memoria, imprecisiones y desbordamiento
- Nuestra computadora tiene memoria, en chips de hardware llamados RAM, memoria de acceso aleatorio. Nuestros programas usan esa RAM para almacenar datos mientras se ejecutan, pero esa memoria es finita. Entonces, con un número finito de bits, no podemos representar todos los números posibles (de los cuales hay un número infinito). Entonces, nuestra computadora tiene una cierta cantidad de bits para cada float e int, y tiene que redondear al valor decimal más cercano en cierto punto.
-
Con
floats.c
, podemos ver qué sucede cuando usamos flotantes:#include <cs50.h> #include <stdio.h> int main(void) { // Solicita a usuario por x float x = get_float("x: "); // Solicita a usuario por y float y = get_float("y: "); // Realiza division printf("x / y = %.50f\n", x / y); }
-
Con
%50f
, podemos especificar la cantidad de decimales mostrados. -
Hmm, ahora obtenemos …
x: 1 y: 10 x / y = 0.10000000149011611938476562500000000000000000000000
-
Resulta que esto se llama imprecisión de punto flotante, donde no tenemos suficientes bits para almacenar todos los valores posibles, por lo que la computadora tiene que almacenar el valor más cercano que pueda a 1 dividido por 10.
-
Podemos ver un problema similar en
overflow.c
:#include <stdio.h> #include <unistd.h> int main(void) { for (int i = 1; ; i *= 2) { printf("%i\n", i); sleep(1); } }
-
En nuestro ciclo
para
, establecemosi
en1
y lo duplicamos con*= 2
. (Y seguiremos haciendo esto para siempre, así que no hay condición que verifiquemos). - También usamos la función
sleep
deunistd.h
para permitir que nuestro programa se pause cada vez. -
Ahora, cuando ejecutamos este programa, vemos que el número se hace cada vez más grande, hasta:
1073741824 overflow.c:6:25: error de tiempo de ejecucion: desbordamiento de enteros con signo: 1073741824 * 2 no puede ser representado en tipo 'int' -2147483648 0 0 ...
-
Resulta que nuestro programa reconoció que un entero con signo (un entero con un signo positivo o negativo) no podía almacenar ese siguiente valor e imprimió un error. Entonces, como intentó duplicarlo de todos modos,
i
se convirtió en un número negativo y luego en 0. -
Este problema se llama desbordamiento de enteros, donde un entero solo puede ser tan grande antes de que se quede sin bits y "se desborde". Podemos imaginar sumar 1 a 999 en decimal. El último dígito se convierte en 0, llevamos el 1 asi que el siguiente dígito se convierte en 0, y obtenemos 1000. Pero si solo tuviéramos tres dígitos, ¡terminaríamos con 000 ya que no hay lugar para poner el 1 final!
-
El problema del año 2000 surgió porque muchos programas almacenaban el año calendario con solo dos dígitos, como 98 para 1998 y 99 para 1999. Pero cuando se acercaba el año 2000, los programas habrían almacenado 00, lo que llevaría a confusión entre los años 1900 y 2000.
- Un avión Boeing 787 también tuvo un error donde un contador en el generador se desborda después de una cierta cantidad de días de funcionamiento continuo, ya que la cantidad de segundos que ha estado funcionando ya no podía almacenarse en ese contador.
- Entonces, hemos visto algunos problemas que pueden ocurrir, pero ahora entendemos por qué y cómo prevenirlos.
- Con el conjunto de problemas de esta semana, usaremos el CS50 Lab, construido sobre el CS50 Sandbox, para escribir algunos programas con tutoriales que nos guíen.