1. Toma de contacto con C
NOTA: Este apartado
está sin
terminar de revisar.
Falta incluir imágenes, añadir colores... incluso
releer ;-)
Dentro de los lenguajes de programación, C es
un
lenguaje que tiene un cierto “prestigio”. Esto se
debe
fundamentalmente a dos razones:
- Es bastante “portable”: un programa bien hecho en C se podrá llevar a un ordenador distinto o incluso a un sistema operativo distinto (de MsDos a Windows o a Linux, por ejemplo) con muy pocos cambios o quizás incluso sin ningún cambio. El motivo es que existe un estándar: el ANSI C, que soportan casi todos los compiladores. Por eso, si nos ceñimos al estándar, es seguro que nuestros programas funcionarán en distintos sistemas; cuanto más nos separemos del estándar (en ocasiones podremos hacerlo), más difícil será que funcionen en otro sistema distinto.
- Permite hacer “casi de todo”:
podemos usar
órdenes de alto nivel (muy cercanas al lenguaje humano),
pero
también de bajo nivel (más cercanas a lo que
realmente
entiende el ordenador). De hecho, podremos incluso incorporar
órdenes en lenguaje ensamblador en medio de un programa escr
#include <stdio.h>
main() { printf("Hola"); }
ito en C, aunque eso supone que ganemos en control de la máquina que estamos manejando, a costa de perder en portabilidad (el programa ya no se podrá llevar a otros ordenadores que no usen el mismo lenguaje ensamblador).
En su contra, el lenguaje C tiene que es más
difícil de aprender que otros y que puede resultar
difícil de leer (por lo que ciertos errores pueden tardar
más en encontrarse).
Los pasos que seguiremos para crear un programa en C
serán:
- Escribir el programa en lenguaje C (fichero fuente), con cualquier editor de textos.
- Compilarlo con nuestro compilador. Esto creará un “fichero objeto”, ya convertido a un lenguaje que el ordenador es capaz de entender.
- Enlazarlo con otros ficheros del compilador, unas bibliotecas auxiliares que incluirán en nuestro programa aquellas posibilidades que hayamos empleado nosotros pero que realmente no sean parte del lenguaje C básico, sino ampliaciones de algún tipo. Esto dará lugar al fichero ejecutable, que ya podremos usar desde MsDos o el sistema operativo que estemos manejando, en nuestro ordenador o en cualquier otro, aunque ese otro ordenador no tenga el compilador que nosotros hemos utilizado.
La mayoría de los compiladores actuales
permiten dar
todos estos pasos desde un único entorno, en el que
escribimos
nuestros programas, los compilamos, y los depuramos en caso de que
exista algún fallo.
En el siguiente apartado veremos un ejemplo de uno de
estos entornos, dónde localizarlo y cómo
instalarlo.
1.1 Escribir un texto en C
Vamos con un primer ejemplo de programa en C, posiblemente el más sencillo de los que “hacen algo útil”. Se trata de escribir un texto en pantalla. La apariencia de este programa la vimos en el tema anterior. Vamos a verlo ahora con más detalle:
#include <stdio.h>
void main()
{
printf("Hola");
}
Esto escribe “Hola” en la pantalla. Pero hay mucho
que comentar:
- Eso de “#include” nos permite incluir ciertas características para ampliar el lenguaje base. En este caso, el motivo es que en el lenguaje C base no hay predefinida ninguna orden para escribir en pantalla (hay que recordar que un ordenador no es sólo lo que acostumbramos a tener sobre nuestra mesa, con pantalla y teclado. Existen otros muchos tipos de ordenadores que realizan tareas complejas y nonecesitan una pantalla durante su funcionamiento normal, como el que controla el ABS de un coche), sino que este tipo de órdenes son una extensión, que se define en un fichero llamado “stdio.h”. Esto no es un problema, vamos a encontrar ese “stdio.h” en cualquier compilador que usemos. ¿Y por qué se pone entre < y >? ¿Y por qué eso de # al principio? Esos detalles los iremos viendo un poco más adelante.
- Ya que hemos hablado de ella, "printf" es la orden que se encarga de mostrar un texto en pantalla, la responsable de que hayamos escrito ese “include” al principio del programa.
- Aun quedan cosas: ¿qué hacen esas llaves { y } ? C es un lenguaje estructurado, en el que un programa está formado por diversos “bloques”. Todos los elementos que componen este bloque deben estar relacionados entre sí, lo que se indica encerrándolos entre llaves: { y }.
- Finalmente, ¿qué es eso de “main”? Es algo que debe existir siempre, e indica el punto en el que realmente comenzará a funcionar el programa. Después de "main" van dos llaves { y }, que delimitan el bloque más importante: el cuerpo del programa. ¿Y por qué tiene un paréntesis vacío a continuación? Eso lo veremos más adelante...
Y la cosa no acaba aquí. Aún queda
más
miga de la que parece en este programa, pero cuando ya vayamos
practicando un poco, iremos concretando más alguna que otra
cosa
de las que aquí han quedado poco detalladas.
Ejercicio propuesto: Crea un programa en C que te salude
por tu nombre (ej: “Hola, Nacho”).
Sólo un par de cosas más antes de
seguir adelante:
- Cada orden de C debe terminar con un punto y coma (;)
- El C es un lenguaje de formato libre, de modo que
puede
haber varias órdenes en una misma línea, u
órdenes
separadas por varias líneas o espacios entre medias. Lo que
realmente indica dónde termina una orden y donde empieza la
siguiente son los puntos y coma. Por ese motivo, el programa anterior
se podría haber escrito también así
(aunque no es aconsejable, porque puede resultar menos legible):
#include
<stdio.h>
main() { printf("Hola"); }
De hecho, hay dos formas especialmente frecuentes de colocar la llave de comienzo, y yo usaré ambas indistintamente. La primera forma es como hemos hecho en el primer ejemplo: en una línea, sola, y justo encima de la llave de cierre correspondiente. La segunda forma habitual es situándola a continuación del nombre del bloque que comienza (en nuestro caso, a continuación de la palabra “main”), así:
#include
<stdio.h>
main() {
printf("Hola");
}
La gran mayoría de las órdenes que
encontraremos
en el lenguaje C son palabras en inglés o abreviaturas de
éstas. Pero hay que tener en cuenta que C distingue entre
mayúsculas y minúsculas, por lo que "printf" es
una
palabra reconocida, pero "Printf", "PRINTF" o "PrintF" no lo son.
1.1.1 Cómo probar este programa en Linux
Los sistemas operativos de la familia Unix, como Linux,
suelen
incluir un compilador de C, de modo que será
fácil probar
nuestros programas. Supondremos que se trata de una versión
de
Linux de los últimos años, que tenga entorno
gráfico. Podríamos usar el editor del texto del
entorno
gráfico, teclear el fuente y guardarlo en nuestra carpeta
personal, por ejemplo con el nombre ejemplo001.c (lo que sí
es
importante es que termine en “.c”): (en esta imagen
se
trata de Mandrake Linux 9.1, con el entorno Gnome y el editor
básico que incorpora, GEdit).
Después abriríamos una ventana de terminal y teclearíamos la siguiente orden para compilar nuestro fuente:
cc ejemplo001.c –o miprograma
Donde:
#include <stdio.h>
main()
{ printf("Hola"); }
- “cc” es la orden que se usa para poner el compilador en marcha.
- “ejemplo001.c” es el nombre del fuente que queremos compilar.
- La opción “-o” se usa para indicar el nombre que queremos que tenga el fichero ejecutable resultante (la “o” viene de “output”, salida).
- “miprograma” es el nombre que tendrá el programa ejecutable.
Y para probar el programa teclearíamos
./miprograma
Con lo que debería aparecer escrito
“Hola” en la pantalla.
(Nota: Las versiones más recientes de Linux
tienen
entornos integrados, desde los que podemos teclear y probar nuestro
programa, con más comodidad, como en el caso de la
herramienta
que vamos a comentar para Windows. Dos de los entornos más
extendidos son KDevelop y Anjuta).
1.1.2 Cómo probar este programa en Windows
La familia de sistemas Windows no incluye
ningún
compilador de C, de modo que tendremos que localizar uno e instalarlo.
Existen muchos gratuitos que se pueden descargar de Internet, y que
incluyen un editor y otras herramientas auxiliares. Es el caso de
Dev-C++, por ejemplo, que tiene su página oficial en
www.bloodshed.net. La instalación es poco más que
hacer
doble clic en el fichero descargado, y hacer clic varias veces en el
botón “Siguiente”:
En el caso de Dev-C++, podemos incluso trabajar con el
entorno en español:
Para crear nuestro programa
Nos preguntará un nombre para el proyecto que
estamos comenzando
Y ya podemos empezar a teclear. Para ver el programa en
funcionamiento, entraríamos al menú
“Ejecutar” y usaríamos la
opción
“Compilar y ejecutar”:
(si todavía no hemos guardado los cambios en
nuestro fuente, nos pediría antes que lo
hiciéramos).
Puede ocurrir que se muestre el texto en pantalla, pero
la
ventana desaparezca tan rápido que no tengamos tiempo de
leerlo.
Si es nuestro caso, tenemos dos opciones:
- Algunos entornos (como los de la familia Turbo C y Borland C) tienen una opción “User Screen” (pantalla de usuario) en el menú “Run” (ejecutar), que nos mostraría lo que ha aparecido en esa pantalla que no pudimos leer.
- Otros entornos, como Dev-C++, no tienen esa posibilidad, por lo que deberíamos hacer un pequeño cambio a nuestro fuente, para que espere a que pulsemos la tecla Intro antes de terminar. La orden que nos permitiría hacer eso (y que veremos con más detalle más adelante) es “getchar()”, así que nuestro fuente quedaría
#include <stdio.h>
void main()
{
printf("Hola");
getchar();
}
1.2 Mostrar números enteros en pantalla
Cuando queremos escribir un texto “tal
cual”, como
en el ejemplo anterior, lo encerramos entre comillas. Pero no siempre
querremos escribir textos prefijados. En muchos casos, se
tratará de algo que habrá que calcular. El caso
más sencillo es el de una operación
matemática. En
principio, podríamos pensar en intentar algo así:
printf(3+4);
En muchos lenguajes de programación esto es
perfectamente válido, pero no en C. La función
“printf” nos obliga a que lo que escribamos en
primer lugar
sea un texto, indicado entre comillas. Eso que le indicamos entre
comillas es realmente un código de formato. Dentro de ese
código de formato podemos tener caracteres especiales, con
los
que le indicamos dónde y cómo queremos que
aparezca un
número (u otras cosas). Esto lo veremos con detalle un poco
más adelante, pero de momento podemos anticipar que
“%d” sirve para decir “quiero que
aquí
aparezca un número entero”.
¿Qué
número? El que le indicamos a continuación,
separado por
una coma:
printf("%d", 3+4);
Este ejemplo mostraría en pantalla un
número entero (%d) que sea el resultado de suma 3 y 4.
Podemos escribir entre las comillas más
detalles sobre lo que estamos haciendo:
printf("El resultado de sumar 3 y 4 es %d", 3+4);
Ejercicio propuesto: crea un programa que diga el
resultado de sumar 118 y 56.
1.3 Operaciones aritméticas básicas
Está claro que el símbolo de la suma será un +, y podemos esperar cual será el de la resta, pero alguna de las operaciones matemáticas habituales tiene símbolos menos intuitivos.
Veamos cuales son los más importantes:
Operador
Operación
+ Suma
- Resta, negación
* Multiplicación
/ División
% Resto de la div
Ejercicio propuesto: Hacer un programa que calcule el
producto de los números 12 y 13.
1.3.1. Orden de prioridad de los operadores
Sencillo:
- En primer lugar se realizarán las operaciones indicadas entre paréntesis.
- Luego la negación.
- Después las multiplicaciones, divisiones y el resto de la división.
- Finalmente, las sumas y las restas.
- En caso de tener igual prioridad, se analizan de izquierda a derecha.
Ejercicio propuesto: Calcular (a mano y
después comprobar desde C) el resultado de estas operaciones:
- -2 + 3 * 5
- (20+5) % 6
- 15 + -5*6 / 10
- 2 + 10 / 5 * 2 - 7 % 1
1.3.2. Introducción a los problemas de desbordamiento
El espacio del que disponemos para almacenar los
números es limitado. Si el resultado de una
operación es
un numero “demasiado grande”, obtendremos un
resultado
erróneo. Por eso en los primeros ejemplos usaremos
números pequeños. Más adelante veremos
a
qué se debe realmente este problema y cómo
evitarlo.
1.4 Introducción a las variables: int
Las variables son algo que no contiene un valor
predeterminado, un espacio de memoria al que nosotros asignamos un
nombre y en el que podremos almacenar datos.
El primer ejemplo nos permitía escribir
“Hola”. El segundo nos permitía sumar
dos
números que habíamos prefijado en nuestro
programa. Pero
esto tampoco es “lo habitual”, sino que esos
números
dependerán de valores que haya tecleado el usuario o de
cálculos anteriores.
Por eso necesitaremos usar variables, en las que
guardemos los
datos con los que vamos a trabajar y también los resultados
temporales. Vamos a ver como ejemplo lo que haríamos para
sumar
dos números enteros que fijásemos en el programa.
1.4.1 Definición de variables: números enteros
Para usar una cierta variable primero hay que
declararla: indicar su nombre y el tipo de datos que querremos guardar.
El primer tipo de datos que usaremos serán números enteros (sin decimales), que se indican con “int” (abreviatura del inglés “integer”). Después de esta palabra se indica el nombre que tendrá la variable:
int primerNumero;
Esa orden reserva espacio para almacenar un
número
entero, que podrá tomar distintos valores, y al que nos
referiremos con el nombre “primerNumero”.
1.4.2 Asignación de valores
Podemos darle un valor a esa variable durante el programa haciendo
primerNumero=234;
O también podemos darles un valor inicial (“inicializarlas”) antes de que empiece el programa, en el mismo momento en que las definimos:
int primerNumero=234;
O incluso podemos definir e inicializar más
de una variable a la vez
int primerNumero=234, segundoNumero=567;
(esta línea reserva espacio para dos variables, que usaremos para almacenar números enteros; una de ellas se llama primerNumero y tiene como valor inicial 234 y la otra se llama segundoNumero y tiene como valor inicial 567).
Después ya podemos hacer operaciones con las variables, igual que las hacíamos con los números:
suma = primerNumero + segundoNumero=567;
1.4.3 Mostrar el valor de una variable en pantalla
Una vez que sabemos cómo mostrar un
número en
pantalla, es sencillo mostrar el valor de una variable. Para un
número hacíamos cosas como
printf("El resultado es %d", 3+4);
pero si se trata de una variable es idéntico:
printf("El resultado es %d", suma);
Ya sabemos todo lo suficiente para crear nuestro
programa que sume dos números usando variables:
#include <stdio.h>
int primerNumero;
int segundoNumero;
int suma;
main()
{
primerNumero = 234;
segundoNumero = 567;
suma = primerNumero + segundoNumero;
printf("Su suma es %d", suma);
}
Repasemos lo que hace:
- Ø #include <stdio.h> dice que queremos usar funciones de entrada/salida estándar.
- Ø int primerNumero; reserva espacio para guardar un número entero, al que llamaremos primerNumero.
- Ø int segundoNumero; reserva espacio para guardar otro número entero, al que llamaremos segundoNumero.
- Ø int suma; reserva espacio para guardar un tercer número entero, al que llamaremos suma.
- Ø main() indica donde comienza en sí el cuerpo del programa.
- Ø { señala el principio del cuerpo (de “main”)
- Ø primerNumero = 234; da el valor del primer número que queremos sumar
- Ø segundoNumero = 567; da el valor del segundo número que queremos sumar
- Ø suma = primerNumero + segundoNumero; halla la suma de esos dos números y la
- guarda en otra variable, en vez de mostrarla directamente en pantalla.
- Ø printf("Su suma es %d", suma); muestra en pantalla el resultado de esa suma.
- Ø } señala el principio del cuerpo (de “main”)
Podemos resumir un poco este fuente, si damos los
valores a las variables al inicializarlas:
#include <stdio.h>
int primerNumero = 234;
int segundoNumero = 567;
int suma;
main()
{
suma = primerNumero + segundoNumero;
printf("Su suma es %d", suma);
}
Ejercicio propuesto: Hacer un programa que calcule el
producto de los números 121 y 132, usando variables.
1.5 Identificadores
Estos nombres de variable (lo que se conoce como
“identificadores”) pueden estar formados por
letras,
números o el símbolo de subrayado (_) y deben
comenzar
por letra o subrayado. No deben tener espacios entre medias, y hay que
recordar que las vocales acentuadas y la eñe son
problemáticas, porque no son letras "estándar" en
todos
los idiomas. Algunos compiladores permiten otros símbolos,
como
el $, pero es aconsejable no usarlos, de modo que el programa sea
más portable (funcione con facilidad en distintos sistemas).
Por eso, no son nombres de variable válidos:
1numero (empieza por número)
un numero (contiene un espacio)
Año1 (tiene una eñe)
MásDatos (tiene una vocal acentuada)
Tampoco podremos usar como identificadores las palabras
reservadas de C. Por ejemplo, la palabra "int" se refiere a que cierta
variable guardará un número entero,
así que esa
palabra "int" no la podremos usar tampoco como nombre de variable (pero
no vamos a incluir ahora
una lista de palabras reservadas de C, ya nos iremos encontrando con
ellas).
De momento, intentaremos usar nombres de variables que a nosotros nos resulten claros, y que no parezca que puedan ser alguna orden de C.
Hay que recordar que en C las mayúsculas y minúsculas se consideran diferentes, de modo que si intentamos hacer
PrimerNumero = 0;
primernumero = 0;
o cualquier variación similar, el compilador
protestará y nos dirá que no conoce esa variable,
porque
la habíamos declarado como
int primerNumero;
El número de letras que puede tener un
"identificador"
(el nombre de una variable, por ejemplo) depende del compilador que
usemos. Es frecuente que permitan cualquier longitud, pero que
realmente sólo se fijen en unas cuantas letras (por ejemplo,
en
las primeras 8 o en las primeras 32). Eso quiere decir que puede que
algún compilador considerase como iguales las variables
NumeroParaAnalizar1 y NumeroParaAnalizar2, porque tienen las primeras
18 letras iguales. El C estándar (ANSI C) permite cualquier
longitud, pero sólo considera las primeras 31.
1.6 Comentarios
Podemos escribir comentarios, que el compilador ignora, pero que pueden servir para aclararnos cosas a nosotros. Se escriben entre /* y */:
int suma; /* Porque guardaré el valor para
usarlo más tarde */
Es conveniente escribir comentarios que aclaren la
misión de las partes de nuestros programas que puedan
resultar
menos claras a simple vista. Incluso suele ser aconsejable que el
programa comience con un comentario, que nos recuerde qué
hace
el programa sin que necesitemos mirarlo de arriba a abajo. Un ejemplo
casi exagerado:
/* ---- Ejemplo en C: sumar dos números
prefijados ---- */
#include <stdio.h>
int primerNumero = 234;
int segundoNumero = 567;
int suma; /* Porque guardaré el valor para usarlo
más tarde */
main()
{
/* Primero calculo la suma */
suma = primerNumero + segundoNumero;
/* Y después muestro su valor */
printf("Su suma es %d", suma);
}
Un comentario puede empezar en una línea y
terminar en otra distinta, así:
/* Esto
es un comentario que
ocupa más de una línea
*/
1.7 Datos por el usuario: scanf
Si queremos que sea el usuario de nuestro programa quien
teclee los valores, necesitamos una nueva orden, llamada
“scanf”. Su manejo recuerda al de
“printf”, con
una pequeña diferencia: scanf("%d", &primerNumero);
Con ese “%d” indicamos que esperamos leer un número entero (igual que para “printf”) y con &primerNumero decimos que queremos que ese valor leído se guarde en la variable llamada “primerNumero”. La diferencia está en ese símbolo & que nos obliga scanf a poner antes del nombre de la variable. Más adelante veremos qué quiere decir ese símbolo y en qué otros casos se usa.
Un ejemplo de programa que sume dos números tecleados por el usuario sería:
/*-------------------------*/
/* Ejemplo en C nº 5: */
/* C005.C */
/* */
/* Leer valores para */
/* variables */
/*-------------------------*/
#include <stdio.h>
int primerNumero, segundoNumero, suma; /* Nuestras variables */
main() /* Cuerpo del programa */
{
printf("Introduce el primer número ");
scanf("%d", &primerNumero);
printf("Introduce el segundo número ");
scanf("%d", &segundoNumero);
suma = primerNumero + segundoNumero;
printf("Su suma es %d", suma);
}
Ejercicios propuestos:
1. Multiplicar dos números tecleados por
usuario
2. El usuario tecleará dos números (x e y), y el
programa
deberá calcular cual es el resultado de su
división y el
resto de esa división.
3. El usuario tecleará dos números (a y b), y el
programa
mostrar el resultado de la operación (a+b)*(a-b) y el
resultado
de la operación a2-b2.