Lenguaje C
Tecnología Industrial I
Curso 17-18
Contenidos
1. Historia
2. Estructura de un programa
3. Variables
4. Funciones de cabecera
5. Bucles
6. Funciones o subrutinas. Punteros
7. Conjuntos de datos
Historia
•
Creado en 1972 por D. Ritchie
•
Lenguaje de propósito general
•
Transportable (generalmente)
•
Inicialmente de nivel medio (entre alto nivel y
ensamblador)
•
Pensado para (gestionar / programar)
sistemas/comunicaciones
•
Lenguaje compilado (compilar + enlazar)
•
Modular (permite usar bibliotecas propias o estándar
que se enlazan con nuestros programas principales)
•
Es un lenguaje que se ejecuta línea a línea desde el
programa principal.
Estructura de un programa
•
El algoritmo implementado gira alrededor de una
serie de funciones.
•
La primera función a la que va el programa una
vez ejecutado es la función «main()». A partir de
esta, se enlazarán todas las demás para producir
el programa.
•
Por lo tanto, siempre deberá haber una función
main() en nuestro programa, con un tratamiento
especial. El resto de funciones tendrán otro
tratamiento y deberán ser llamadas desde main()
o desde alguna función llamada por main().
Estructura de un programa
•
Estructura formal:
1. INICIO
2. Cabeceras.
3. Constantes.
4. Declaración de funciones y variables globales.
5. Main()
1. Declaración de variables.
2. Operaciones/Llamadas a funciones.
6. Desarrollo de las distintas funciones.
7. FIN
Estructura de un programa
• Cabeceras (o headers)– Fichero con extensión .h
– Contienen funciones ya predefinidas que permiten llamarlas
directamente, sin definirlas previamente. Sencillamente están y se llaman desde la función que sea cuando proceda.
– Algunas cabeceras: • Stdio.h • Math.h • Ctype.h • Stdlib.h • String.h • Time.h • Windows.h
– Para ver las funciones que incluye cada cabecera:
Estructura de un programa
•
Constantes
–
Son valores que siempre tendrán el mismo valor y
no podrán ser modificadas durante la ejecución
del programa.
–
Se usan para asignar una etiqueta a un valor
determinado para no estar constantemente
reescribiendo dicho valor (por ejemplo, pensar en
tener que escribir varias veces el valor de pi, o
sustituirlo por una constante, de etiqueta «pi»).
–
Línea típica:
Estructura de un programa
•
Declaración de funciones y variables globales
–
Todas las funciones que no sean la función main()
deben ir previamente declaradas.
–
La declaración consiste en una línea en la que se
pondrá el tipo de valor devuelto, el nombre de la
función y los parámetros que se les pasa. Se acaba en
«;»
–
También se declararán las variables globales que se
usarán en todo el programa. Una vez usado el nombre
para la variable global, dicho nombre no podrá ser
Estructura de un programa
•
Función main()
–
Es la función inicial del programa y aquella que se
llama desde el principio.
–
Su estructura es sencilla: primero se declaran las
variables que intervendrán en las operaciones, y
luego se escriben las operaciones.
–
A la función main() se le pueden pasar parámetros
y también puede devolver un valor, por lo que hay
códigos en los que aparece como «void main()» o
«int main()».
Estructura de un programa
•
Instrucciones.
–
Las distintas instrucciones representan las
distintas operaciones que se pueden realizar en un
programa:
• Llamada a una función.
• Asignar valores a una variable.
• Operaciones matemáticas básicas.
– Incremento: i++; – Decremento: i--;
• etc…
Estructura de un programa
•
Desarrollo de las distintas funciones o subrutinas
–
Las funciones deben desarrollarse, además de
declararse antes de la función main().
–
Para ello, basta con repetir la cabecera de la función y
comenzar a escribir variables y operaciones.
–
Una función puede ser llamada por otra función, e
incluso por sí misma (función recursiva).
–
Las funciones pueden devolver un determinado valor,
por tanto, se deben acabar con la sentencia «return
X», para indicar que se devuelve el valor X.
Mi primer programa
#include <stdio.h>
int main()
{
// printf() displays the string inside quotation printf("Hello, World!");
return 0;
Mi primer programa
•
Para ejecutar el programa:
–
Copiar el contenido en un archivo nuevo.
–
Guardarlo con el nombre que quieras, pero con
formato de programa en C.
–
Compilar y ejecutar.
–
Ver el resultado y pulsar «intro» para salir.
–
NOTA1
: cada vez que realicemos cambios en nuestro
programa, habrá que volver a compilarlo y a
ejecutarlo.
–
NOTA2
: en la carpeta donde se guarde el archivo con
el código, se guardará también un ejecutable con tu
programa, para que te lo lleves a donde quieras ;)
Mi primer programa
•
Cosas a tener en cuenta:
–
Inclusión de una cabecera (stdio.h -> entrada y
salida estándar, que permite interaccionar con
teclado y pantalla).
–
Llamada a la función printf de la biblioteca stdio.h,
acabada en ‘;’
–
La función main se le pone el tipo ‘int’, y por
tanto, hacemos que al final, devuelva un 0 (return
0;).
Variables
• Son las que contienen la información que va a ser tratada por las funciones del programa.
• Se almacenan en memoria según un cierto criterio, reflejado en el TIPO de la variable.
• Al final, se guardan un conjunto de 1/0, que se interpretan como un determinado número, pero el TIPO define la forma en que el
computador interpreta dicho número. • Tipos más comunes:
– Int -> Tipo entero, sin decimales. – Float -> Tipo real. Con decimales.
– Double -> Tipo real. Con decimales, pero con doble longitud. Ideal para irracionales.
– Char -> Tipo carácter, una letra o una cadena de letras acabadas por el carácter \0. Se almacena siguiendo el código número-letra
denominado ASCII.
– Void -> Tipo vacío o indeterminado. Es el que se usa cuando no se sabe el tipo que se tendrá o cuando no se tiene nada.
Variables
•
Cuando se crea una función, se le suele
asignar un tipo para indicar el valor devuelto.
•
Si devuelve una cadena, se le pondrá un tipo
‘string’, si devuelve un entero, un tipo ‘int’,
etc.
•
¡OJO!, si no devolviera nada, es decir, que
fuera una función que hiciera una operación,
pero sin devolver un resultado concreto, se
usa ‘void’.
Variables: ejemplos
•
Int i = 2;
•
Double pi = 3.1415926
•
Char frase[] = "Hola a todos";
•
Char letra = "c";
•
Int suma (int x, int y);
•
Void cambio (int ok);
Funciones de cabecera
•
<stdio.h>
–
Contiene funciones para la entrada y salida de
datos.
• Printf (imprime una determinada cadena de caracteres, incluyendo valores dados).
• Scanf (lee una cadena a través de la entrada estándar – el teclado, vamos-, y almacena los valores introducidos en una variable –habrá que indicar el tipo-).
• Getchar (lee un solo carácter)
• Putchar (imprime un solo carácter).
Estudio funciones de stdio.h
•
Ojo a los tipos de caracteres:
–
%d -> entero
–
%f -> float
–
%c -> carácter
–
%s -> string
• Lee caracteres hasta que pulses intro.
EJEMPLO
•
Cargar, compilar y ejecutar el código de
«juegaconvariables.c»
•
Atención a:
–
La forma de usar las funciones de la librería
«stdio.h».
–
La forma de almacenar las variables.
–
La forma de almacenar los espacios.
EJERCICIOS
•
Jugar con las lecturas: leer un carácter
asignándolo a una variable número.
•
Leer una cadena pero asignar solo a un carácter.
•
Leer un float y leer un float como un entero.
•
Jugar con los datos y luego presentarlos
correctamente (leer un entero, sumarle un trozo
decimal y luego presentarlo por pantalla).
•
Intentar leer varias palabras separadas por
espacios como varias variables string.
Bucles/Condiciones
•
En muchas situaciones, se puede necesitar de
realizar una tarea un cierto número de veces o
realizarla de forma continua hasta que se cumpla
una condición. Para ello se introducen
instrucciones de bucles.
•
También puede ser necesario evaluar condiciones
de distinto tipo (al igual que se podía ver en el
diagrama de flujo). Para ello, también se
Bucles/Condiciones: Instrucciones de
bucle
• Bucle for
– El bucle for hace que se repita una determinada acción durante un cierto número de veces. Son anidables.
– Estructura:
for (i=0;i<5;i++) {
«conjunto de instrucciones» }
– Inicialmente, el índice se coloca a 0. Para cada iteración, el programa comprobará el valor de i, si fuera menor que 5, realizará las acciones de dentro de los corchetes, finalmente, aumentará en 1 el valor de i, de forma automática, y volverá a evaluar la condición. Si fuera mayor de 5, saldría del bucle y pasaría a la siguiente instrucción pasados los corchetes.
– El índice i puede ser usado para tareas de indexación dentro de las
instrucciones del bucle for. Debe ser previamente declarado. Por tanto, antes de programar, deberíamos hacer una cuenta de cuántos índices vamos a usar e iniciarlos. Los índices se pueden reutilizar en distintas partes del programa.
– A la hora de comparar, se pueden usar tanto > y <, como >= y <=. De la misma forma, se puede hacer decrecer un valor previamente puesto a un valor mayor que cero (i--).
Bucles/Condiciones: Instrucciones de
bucle
• Bucle while
– Realiza una serie de tareas mientras se cumpla una condición: – Estructura:
While (condición) {
«conjunto de instrucciones» }
• Se evalúa la condición y, si se cumple, se ejecutan las
instrucciones internas. Cuando se deje de cumplir, se salta a la siguiente instrucción pasados los corchetes.
• Normalmente, dentro del conjunto de instrucciones,
deberá haber unas condiciones para salir del bucle, si no, se seguiría en él indefinidamente.
• Como se ve, es un bucle similar al for y, de hecho, se pueden usar de forma indistinta, aunque, según la
condición que se quiera implementar, podrá venir mejor uno u otro.
Bucles/Condiciones:
Instrucciones de condiciones
• Condición if/else if/else.
– Estructura:
• En primer lugar, se evalúa la condición del if, si no se
cumple, se salta al else if (puede haber varios, con distintas condiciones), si tampoco se cumple, se ejecutan las
instrucciones del else.
• Si alguna de las condiciones (no tienen por qué ser mutuamente excluyentes, aunque es absurdo) de los
anteriores bucles se cumple, se ejecutan las instrucciones de esa parte y se salta el else.
• No hay bucle, solo se evalúan unas condiciones y, si alguna es cierta, se ejecutan unas instrucciones, solo eso.
If (condición) { «conjunto de instrucciones» } Else if (condición) { «conjunto de instrucciones» } Else { «conjunto de instrucciones» }
Bucles/Condiciones: Instrucciones de
condiciones
• Condición switch/case/default.
– Estructura:
• Esta instrucción permite evaluar una variable, o una condición y ejecutar unas instrucciones u otras en función del valor que tenga.
• Al final de las instrucciones se incluye la instrucción break; para forzar que la ejecución salga
fuera del switch y continúe la ejecución del programa.
Switch (variable) { case valor1: «conjunto de instrucciones» break; case valor2: «conjunto de instrucciones» break; case valor3: «conjunto de instrucciones» break; default: «conjunto de instrucciones» break; }
Algunos detalles más
•
Operadores lógicos
–
Si, en una parte del programa, se
debieran cumplir una serie de
condiciones, se pueden recurrir a
operadores lógicos para cumplirlas:
–
EJ:
if (a==3 && b==2)-> Si a vale 3 y
b vale 2
–
Operadores más comunes:
• && -> operador ‘y’, se deben cumplir ambas condiciones.
• || -> operador ‘o’, se pueden cumplir una de las dos condiciones.
Condiciones:
== -> igualdad != -> desigualdad < -> menor que
<= -> menor igual que > -> mayor que
Algunos detalles más
•
Sentencias break y return
.
•
Son sentencias que te permiten romper el
bucle en el que te encuentres y volver a la
función principal.
–
La sentencia break; te hace salir del blucle en el
que te encuentres, de forma directa.
–
La sentencia return; devuelve el control a la
función main() desde una subrutina/función.
Algunos detalles más
• Condiciones anidadas• Evaluar condiciones suele ser un proceso que toma cierta cantidad de memoria y tiempo (aunque hoy por hoy, con los procesadores actuales, no importa
mucho en programas
sencillos… ojito, por tanto, con el BigData).
– Si tienes que evaluar varias condiciones y algunas están repetidas, puede ser una opción anidar dichas
condiciones.
Por ejemplo, si quiero evaluar si tengo un perro de color negro, blanco o canela, o un gato del mismo color, puedo hacer
directamente.
If (animal == perro)
if (color == blanco)
El perro es blanco. else if (color == negro)
El perro es negro. else if (color == canela)
El perro es canela. If (animal = gato)
if (color == blanco)
El gato es blanco. else if (color == negro)
El gato es negro. else if (color == canela)
Funciones/subrutinas
•
En muchos casos, será interesante, por higiene en el
código (programar el Quijote en C no resulta
interesante ni bueno para el que lee el código
después), o bien porque realicemos una serie de
operaciones de forma sistemática y no queramos
(tampoco debemos) repetir el mismo código varias
veces (lo que realmente también es otra forma de
entender la «higiene en el código»).
•
Por ello, cogeremos algunas partes del código y las
convertiremos en una función o subrutina (ambos
nombres se aceptan), la cual se escribirá aparte de la
función main(). Dicha función, recordamos, llevará un
«tipo» asociado que indicará el tipo de dato que
Funciones/subrutinas
• Una función tiene tres elementos esenciales: el tipo de la función (ya explicado), los parámetros que recibe de la función que la llama (los llamados «parámetros de
entrada», que también llevarán un tipo, y las líneas de código que la componen.
• Para escribir una función, tenemos que tener en cuenta dos partes:
1. La declaración inicial antes de la función main(). Una sola línea para indicar el nombre y tipo de la función, y los parámetros que recibe.
2. La declaración posterior a main() en la que se escribirán las líneas de código que incluye la función.
• La última línea de una función debería ser siempre una
línea return, seguida de la variable o valor que se devuelva. Es importante remarcar que la variable o valor deberá
tener el mismo tipo que el indicado a la hora de declarar la función.
Funciones/subrutinas
•
Punteros
–
C no puede cambiar en una subrutina una variable
definida en otro sitio. Es decir, si yo mando una
variable como parámetro a una función, dicha función
no podrá modificar la variable.
–
Para poder realizar esta acción, se crea lo que se
denomina el puntero (o apuntador) a la variable.
–
Básicamente, un puntero es una variable donde
meteremos el valor de la dirección de memoria que
queremos cambiar. Como parámetro, entonces,
mandaremos el puntero y ahora si podremos tanto
acceder a la variable, como modificarla en la
EJEMPLO
int main () {
int a=10, b=15, resultado=0; suma(a, b, &resultado); printf("%d", resultado); return 0; }
void suma (int a, int b, int *resultado) {
*resultado = a + b; }
Arrays
•
Hasta ahora, hemos utilizado datos simples, pero
puede ser que necesitemos utilizar conjuntos de datos
para nuestro programa. Dichos conjuntos se
denominan Arrays de Datos.
•
Dichos conjuntos se interpretarán como conjuntos de
datos en varias direcciones y se denominan:
– Vectores: conjuntos de datos en una dirección.
– Matrices: conjuntos de datos en dos direcciones.
– Células: conjuntos de datos en tres direcciones.
•
A la hora de definirlos y utilizarlos, será muy
importante tener claro cómo se almacenan en
memoria.
Conjunto de datos
•
Vectores: son un conjunto lineal de datos de un mismo
tipo (int, float, char, etc.);
•
Se declaran de la siguiente manera:
tipo nombre[tamaño]={a,b,c,d,…};
•
Si no se especifica tamaño, se tomará como el número
de elementos.
•
Si se especifica tamaño, se dejarán indefinidos los
elementos que no aparezcan.
•
Si ni se especifica tamaño, ni se rellenan los elementos
pueden aparecer problemas de memoria.
•
Para acceder a los distintos elementos del vector, basta
con hacer: nombre[i]. ¡OJO!, i va desde (0) hasta
EJEMPLOS
/* Usando un array de enteros */ int main() {
/* Declarando el valor del array */ int losnumeros[10];
int i = 0;
/* Modificando el valor del array */ for (i = 0; i < 10; i++)
losnumeros[i] = i;
/* Imprimiendo el valor del array */ for (i = 0; i < 10; i++)
printf("El elemento %d vale %d\n", i, losnumeros[i]);
return 0; }
#define MYSIZE 10 int main() {
/* Declarando el valor del array */ int losnumeros[MYSIZE];
int i = 0;
/* Modificando el valor del array */ for (i = 0; i < MYSIZE; i++)
losnumeros[i] = i;
/* Imprimiendo el valor del array */ for (i = 0; i < MYSIZE; i++)
printf("El elemento %d vale %d\n", i, losnumeros[i]);
return 0; }
Conjunto de datos
•
Matrices o arreglos: se trata de un conjunto
de vectores, o lo que es lo mismo, un conjunto
de datos en dos direcciones.
•
Se declaran de la misma forma que los
vectores, pero en dos dimensiones:
tipo nombre[tamaño1][tamaño2]={a,b,c;d,e,f;…};
•
Para acceder a un elemento, basta hacer
EJEMPLO
int main() { int matrix[2][3]={ {1,2,3}, {4,5,6}, }; printf ("%d", matrix[1][1]); return 0; }Conjunto de datos
•
Tanto vectores como matrices están íntimamente
relacionados con los punteros.
•
Dado que un puntero guarda una dirección de
memoria, si usamos esa dirección de memoria
como índice, podremos usarla para guardar de
forma consecutiva una serie de datos.
•
El nivel de complejidad de esta operación se
escapa al nivel establecido para este curso, pero
parece interesante exponerlo solamente para que
el alumno interesado profundice en ello.
Ejemplo
#include <stdio.h> int main() { int vector[3]; int *p; p=&vector[0]; *p=1; *(p+1)=2; *(p+2)=3; printf ("%d", *(p+1)); return 0; }Ejemplo
•
Trabajo con cadenas de caracteres.
EJERCICIOS/TRABAJO
1. Realizar una calculadora.
– PISTA: no es mas que un programa que, constantemente, te pide dos operandos y una operación, y la realiza, mostrando el resultado.
2. Realiza un «juego» en el que tengas que adivinar un número entre 1 y 10.
3. Realizar un programa que rellene un vector con los valores
introducidos por el teclado y que, finalmente, imprima el primer valor del vector.
– PISTA: tiene pinta que tendrás que meter algún bucle para poder rellenar el vector.
4. Realizar un programa que, dada una cadena de caracteres, te devuelva el número de vocales que contenga.
– PISTA: ojo con los espacios. Mirar tablas ASCII.
5. Realizar un programa que obtenga las soluciones de una ecuación de segundo grado del tipo <ax2 + bx + c = 0>, los valores de a, b y c
los introducirá el usuario (raíces reales solamente, si salen raíces complejas que no las calcule y solo lo indique).