Está en la página 1de 104

Curso de introducción al

lenguaje

Curso de lenguaje C, adaptado para la asignatura Técnicas de Programación


del primer curso del Ciclo Formativo de Grado Superior Desarrollo de
Productos Electrónicos.

Profesor: Miguel Ángel García Marcos

Curso académico: 2006 / 2007

Departamento de Electrónica del Instituto de Educación Secundaria Joan Miró


San Sebastián de los Reyes (Madrid)
Introducción al lenguaje C

Índice de contenidos

1. Introducción .....................................1 4. Control del flujo del programa (2)..47


1.1 Marco histórico ...............................................1 4.1 Introducción ..................................................47
1.2 Características .................................................1 4.2 Estructura if...else if.......................................47
1.3 Fases de desarrollo de un programa.................2 4.3 Estructura switch...case..................................49
A) Análisis del problema ............................2
B) Diseño del algoritmo .............................3 5. Control del flujo del programa (3)..53
C) Codificación del programa ....................5 5.1 Introducción...................................................53
D) Compilación del programa.....................6 5.2 Sentencia for .................................................53
E) Verificación y depuración.......................6 5.3 Sentencia while..............................................57
1.4 Desarrollo de un programa en C......................7 5.4 Sentencia do...while.......................................61
Resumen mediante un gráfico.....................9 5.5 Ejercicios de repaso.......................................62
1.5 Ejemplo básico de programa en C ..................9
1.6 Bibliotecas estándares .....................................9
1.7 Estructura de un fichero fuente .....................10
6. Arrays y cadenas ............................67
6.1 Introducción ..................................................67
1.8 Comentarios ..................................................10
6.2 Los arrays .....................................................67
1.9 Algunos programas más de ejemplo .............11
6.3 No sobrepasar los límites del array ...............71
6.4 Cadenas de caracteres ...................................72
2. Manipulación básica de datos ........15 6.5 Funciones estándar para manejo de cadenas . 73
2.1 Literales ........................................................15 6.5.1 gets( ) ...............................................73
2.2 Tipos básicos ................................................15 6.5.2 strcpy( ) ...........................................74
2.3 Rangos de valores y tipos modificados .........16 6.5.3 strcat( ) .............................................75
Rango de los enteros .................................16 6.5.4 strcmp( )...........................................75
Tipo char ..................................................17 6.5.5 strlen( ).............................................77
Datos numéricos reales..............................17 6.6 La ventaja de usar el terminador nulo............78
Tabla resumen de tipos de datos................17 6.7 Arrays de 2 o más dimensiones.....................79
2.4 Nombres de variables (identificadores) ........18 6.8 Inicialización de arrays..................................82
2.5 Declaraciones de variables ............................19 6.8.1 Inicialización abreviada....................83
2.6 Las constantes................................................21 6.9 Ejercicios de repaso.......................................84
2.7 Cómo se almacenan los datos en memoria.....22
2.8 Expresiones y operadores .............................24
2.8.1 Operadores aritméticos...............................27
7. Las funciones en lenguaje C ..........87
7.1 Introducción...................................................87
7.2 Paso de parámetros........................................89
3. Control del flujo del programa (1)..29 7.2.1 Paso por valor...................................89
3.1 Introducción...................................................29 7.2.2 Paso por referencia...........................91
3.2 Estructura de selección..................................30 7.2.3 Método a emplear.............................94
A) Sentencia if...........................................30 7.2.4 Algunos problemas con diagramas...97
B) Sentencia if...else..................................33 7.2.5 Ejercicios de repaso..........................98
3.3 Qué poner como condición............................34 7.3 Variables automáticas y estáticas...................98
A) Operadores de relación.........................34 7.4 Variables globales y locales...........................99
B) Operadores lógicos...............................36 7.5 Tabla de símbolos con funciones.................100
Uso de scanf( )........................................39 7.6 Ejercicios de repaso.....................................104
C) Operadores de asignación.....................43
D) Prioridad entre operadores....................44
Agradezco a mis alumnos del primer curso de Ciclo de Grado Superior de Desarrollo de Productos
Electrónicos del I.E.S. Joan Miró su colaboración a la hora de detectar defectos en este texto, pues gracias a
ellos se ha acelerado mucho el proceso de depurado de este curso de introducción al lenguaje C. Al mismo
tiempo agradezco su paciencia por no quejarse al recibir cada poco tiempo versiones inacabadas del
documento que contenían dichos defectos.

Confío en que las muchas horas que he dedicado a confeccionar este texto sirvan para que la asignatura de
Técnicas de Programación les resulte más asequible, y para que les motive a seguir aprendiendo a programar
cuando acaben este curso.

Foto de portada: macro-fotografía de un cabezal de disco duro, en la que se pueden distinguir el entrehierro
del cabezal y la bobina que conecta dicho cabezal con la circuitería del disco duro. Esta bobina, durante los
procesos de escritura, se encarga de convertir la corriente eléctrica del flujo de bits (0 y 1) en campos
magnéticos variables; durante los procesos de lectura lleva a cabo el proceso inverso: transforma los campos
magnéticos variables, generados por los bits grabados en la superficie del disco, en una corriente eléctrica
proporcional a esas variaciones de flujo magnético. Igualmente, se puede apreciar el resalte que forma uno
de los patines del deslizador del cabezal, en el cual el fabricante ha practicado un pequeño bisel para facilitar
que todo el cabezal flote sobre la superficie del disco cuando éste acelera su velocidad de giro; así se evita
que exista rozamiento entre el cabezal y el disco cuando está en funcionamiento.

Para hacernos una idea de las dimensiones: la lámina metálica con un pequeño agujero en medio, que
aparece en la parte inferior de la imagen, tiene una anchura de tan sólo unos 2 milímetros.

Fotografía: Miguel Ángel García Marcos


Lenguaje C

Tema 1: Introducción
En este texto se introducen los elementos principales de la programación en lenguaje C. Se cubre gran parte
de las características del lenguaje, así como algunas funciones de las bibliotecas estándares.

1.1 Marco histórico


El lenguaje C fue creado entre 1970 y 1972 por Brian Kernighan y Dennis Ritchie para escribir el código del
sistema operativo UNIX.

Desde su nacimiento se fue implantando como el lenguaje de programación de sistemas 1 favorito para
muchos programadores, sobre todo por ser un lenguaje que conjugaba la abstracción de los lenguajes de alto
nivel con la eficiencia del lenguaje máquina. Los programadores de sistemas que trabajaban sobre MS-DOS
y Macintosh también utilizaban C, con lo cual la práctica totalidad de aplicaciones de sistema para
microordenadores y para sistemas UNIX está escrita en este lenguaje.

A mediados de los ochenta, el C se convierte en un estándar internacional ISO. Este estándar incluye tanto la
definición del lenguaje como una enorme biblioteca de funciones para entrada/salida, tratamiento de textos,
matemáticas, etc.

A mediados de los ochenta se crea el C++, extensión de C orientada a objetos. El C++ se convierte en
estándar ISO en 1998. En el momento actual, el lenguaje C no va a modificarse más. Será el C++ el que
incorporará nuevos cambios.

1.2 Características
El lenguaje C está orientado a la programación de sistemas, es decir, permite el control directo del hardware.

Como características ventajosas, podemos citar:

· Es altamente transportable. Esto significa que el mismo código fuente puede usarse para máquinas
muy distintas. De este modo no hay que reescribir cada programa para cada tipo de microprocesador.

· Es muy flexible; permite al programador hacer prácticamente cualquier cosa que se pueda programar.

· Genera código muy eficiente, por lo que los programas escritos en C funcionan muy rápidos.

· Es muy expresivo (se pueden realizar muchas cosas escribiendo pocas líneas de código).

Y como inconvenientes:

1 Programar un sistema significa programar la electrónica que lo gestiona.

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 1


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

· Es muy poco modular. No facilita por sí mismo las buenas técnicas de programación estructurada.

· Hace pocas comprobaciones, lo que obliga a programar con mucho cuidado; así se puede generar
código muy eficiente, lo cual es una ventaja, pero es causa de muchos fallos graves en los programas si
el programador no tiene cuidado.

· No impone disciplina al programador. Si el programador no se auto-impone esa disciplina, sus


programas serán muy difíciles de depurar, corregir y modificar.

· Es difícil leer código escrito por otras personas (e incluso por nosotros mismos si hace tiempo que lo
hemos escrito); de ahí que sea imprescindible documentar bien cada programa.

1.3 Fases de desarrollo de un programa


A) Análisis del problema:

Antes de empezar a escribir el código de un programa, hay que definir con claridad el problema que
queremos resolver, expresando lo que deberá hacer ese programa y cuál debe ser el resultado o solución
deseado. Para ello hay que responder por escrito a estas preguntas:

· ¿Qué entradas hacen falta? (tipo y cantidad).

· ¿Cuál es la salida deseada? (tipo y cantidad, si corresponde).

· ¿Qué proceso (algoritmo) sabemos que produce la salida deseada?

Como ejemplo de análisis, estudiemos el siguiente caso trivial:

ENUNCIADO:

Realizar un programa que calcule el interés, en euros, que producirá un capital de x euros si se deja a plazo
fijo durante y años en un banco que dé un tipo de interés del z %.

ANÁLISIS DEL PROBLEMA:

Entradas: Capital (en euros).

Tipo de interés o rédito (en %).

Duración o tiempo (en años).

Salidas: Interés (en euros).

C · r ·t
Proceso: Cálculo del interés en euros . Sabemos que se hace mediante → i=
100

2 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

B) Diseño del algoritmo:

Si en la etapa de análisis se determinó qué debía hacer el programa, en esta etapa se debe desarrollar el cómo
llevará a cabo el programa la tarea solicitada.

Los métodos más eficaces para diseñar un algoritmo están basados en el método de divide y vencerás: un
problema complejo siempre se puede dividir en subproblemas más simples, y a continuación éstos se
vuelven a subdividir, hasta llegar a tener cada pequeña tarea asignada a un módulo del programa. Así, el
programa será visto como un conjunto de pequeños programas simples (los módulos), que se comunican
entre sí siguiendo una jerarquía. Cuando se hace este trabajo, se dice que se llega a la solución mediante
refinamientos sucesivos. A este método de diseño se le conoce con el nombre de diseño descendente (top-
down) o modular.

Cada uno de los módulos obtenidos mediante diseño descendente debe tener siempre un único punto de
entrada y un único punto de salida. Para entender esto, conviene observar el diagrama de flujo de la página
siguiente, y pensar en cada uno de los bloques que lo componen como si fuera un módulo del programa.

Hechos de esta forma, los módulos se pueden diseñar y programar de forma independiente unos de otros,
incluso por programadores distintos. Al final sólo hay que unir todos los módulos para obtener el programa
completo.

Un detalle muy importante: el análisis y el diseño del algoritmo son independientes del lenguaje de
programación que se vaya a usar en las etapas siguientes para escribir el programa.

El diseño del algoritmo puede hacerse mediante pseudocódigo, o mediante diagramas de flujo.

a) Mediante pseudocódigo: consiste en escribir las acciones que debe realizar el programa usando el
lenguaje natural, aunque respetando algunas reglas en cuanto a tabulación de las líneas y al uso de palabras
especiales para marcar determinadas acciones (en este ejemplo son las que se muestran en negrita y
subrayadas).

A continuación vemos cómo se haría, en pseudocódigo, el desarrollo del algoritmo para el problema
planteado en el análisis:
hacer
visualizar pantalla de presentación y toma de datos
introducir
capital
rédito
tiempo
calcular interés en euros
si desea imprimir entonces
imprimir resultados
fin si
mientras otro_cálculo = SI

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 3


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

(b) Mediante diagrama de flujo: en este caso se trata de mostrar, de manera gráfica, las acciones que deberá
hacer el programa. Para ello se utilizan una serie de símbolos predefinidos que son estándares ANSI.

Existen una gran cantidad de estos símbolos, pero nosotros los reduciremos a tan sólo estos pocos:

NO
Terminal Decisión
Subprograma

Proceso interno Entrada y/o


Salida
Conectores

La descripción del algoritmo del problema de ejemplo podría quedar así si la hiciésemos mediante un
diagrama de flujo:

Inicio

Visualizar
presentación

Introducir capital,
rédito y tiempo

Calcular interés

Visualizar
resultados


¿Imprimir?

NO
Imprimir
resultados


¿Otro cálculo?

NO

Fin

4 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

Durante el diseño del algoritmo iremos poniendo nombre a cada dato que vayamos a utilizar. Estos datos
pueden ser constantes (si no van a cambiar su valor durante todo el programa) o variables (en caso contrario).
Pues bien, debemos escribir una lista con esos datos, que llamaremos lista de símbolos, en la que aparezcan:

· Nombre del dato: elegiremos un nombre corto, pero que aclare su misión en el programa.

· Tipo de dato: si es un número, una letra, etc. (más adelante hablaremos sobre los tipos).

· Valor, o margen de valores que puede tomar durante el programa.

· Descripción resumida de qué misión tiene en el programa.

Una vez que elijamos un nombre para un dato, no debemos cambiarlo ni siquiera mínimamente a lo largo del
programa, respetando incluso el uso de mayúsculas y minúsculas.

Si el programa tiene más de un módulo, también hay que darlos nombre, y apuntarlos en la lista.

Toda la información que recopilemos durante el proceso de análisis y el de diseño del algoritmo, junto con el
manual de usuario del programa (si fuese necesario) constituyen lo que se denomina documentación externa.

C) Codificación del programa:

Una vez que ya hemos dejado claro por escrito qué hará el programa y cómo debe hacerlo, tenemos que
proceder a escribir el programa propiamente dicho, es decir, su código fuente. Esto es lo que técnicamente se
conoce como codificar el programa. Para ello podemos usar cualquier editor de textos sencillo, pero es
preferible emplear un editor de textos específico para programar en el lenguaje de programación que
hayamos elegido; en nuestro caso el C. Un editor de textos específico nos aporta algunas ventajas, como
veremos más tarde.

Del mismo modo que existe la documentación externa, debemos añadir, en el propio código del programa, la
documentación interna, que consiste en escribir comentarios en lenguaje natural que expliquen las acciones
que se van desarrollando dentro del programa. De este modo el programa resulta muchísimo más
comprensible incluso para el propio programador.

A la hora de codificar el programa, debemos poner mucha atención en seguir las reglas que permiten lo que
se llama programación estructurada:

· El programa debe tener un diseño modular: si un módulo es demasiado complejo, debemos dividirlo
en submódulos independientes, de forma que cada uno de ellos se encargue de una única tarea sencilla.

Esto habrá sido hecho en la fase de diseño del algoritmo.

· Cada módulo se habrá obtenido por refinamientos sucesivos del módulo principal (diseño
descendente).

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 5


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

· Durante la codificación propiamente dicha, usaremos única y exclusivamente las tres estructuras de
control básicas: secuencia, selección y repetición. Estas estructuras las estudiaremos más adelante.
Esto quiere decir que está terminantemente prohibido el uso de la instrucción GOTO, pese a que
también existe en el lenguaje C.

D) Compilación del programa:

Cuando escribimos el código del programa, lo guardamos en un archivo de texto plano; es decir, que no tiene
ningún tipo de código especial, como por ejemplo para resaltar el texto mediante subrayados o letra en
negrita. Nosotros podemos leer directamente el contenido de esos ficheros abriéndolos con cualquier editor o
procesador de textos; sin embargo, eso no es un código comprensible para el microprocesador.

Necesitamos "traducir" ese texto a un formato que sí sea entendible directamente por el microprocesador.
Esta tarea se puede hacer a mano, y en los primeros años de la informática era así; pero, como podemos
suponer, sería una tarea muy laboriosa, por lo que en su día se inventaron los programas que traducían
automáticamente el texto con las instrucciones escritas por el programador en lenguaje de alto nivel (o en
ensamblador), a lenguaje máquina. Estos programas se llaman ensambladores, si traducen el lenguaje
ensamblador, y compiladores, si lo que traducen es un lenguaje de alto nivel.

Tanto los ensambladores, como los compiladores, crean un nuevo fichero en el que guardan el programa
traducido a lenguaje máquina. Se dice que estos ficheros son ficheros binarios, para distinguirlos de los
ficheros de texto que podemos leer las personas.

Existe una tercera categoría dentro de estos programas traductores, formada por lo que se llama intérpretes.
Un intérprete traduce desde un lenguaje de alto nivel a lenguaje máquina, pero no crea un fichero en el que
guardar lo traducido. Esto quiere decir que, cada vez que se tenga que ejecutar el programa, hay que volver a
interpretarlo. Como podemos imaginar, los programas interpretados funcionan mucho más lentamente que
los compilados. Sin embargo, nosotros nos vamos a centrar en el lenguaje C, que es un lenguaje compilado.

E) Verificación y depuración de un programa:

Después de traducir el programa a código máquina, lo normal es que lo ejecutemos, es decir, que lo
pongamos en funcionamiento. De este modo comprobaremos si funciona correctamente, esto es, lo
verificaremos. Si el programa funciona bien, podremos darlo por finalizado, pero si no es así, habrá que
buscar la causa del error y corregirlo.

El error podemos encontrarlo en cualquiera de las fases de desarrollo que se han ido explicando a lo largo de
este apartado. Esto significa que, tal vez, lo que falla es el análisis inicial del problema que queremos
resolver. Si es así, obligará a repasar ese análisis, y después, casi con toda seguridad, habrá que modificar el
diseño del algoritmo, y por lo tanto las partes afectadas del código del programa, lo que a su vez implica

6 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

volver a traducirlo a lenguaje máquina.

Sin embargo, lo más habitual es que el error lo encontremos directamente en el código fuente del programa.
En estos casos, además de corregirlo ahí, debemos comprobar si esta modificación implica un cambio en el
diseño del algoritmo, o incluso en el análisis del problema; en tal caso nunca debemos pasar por alto
actualizar esa documentación externa, pues de lo contrario posteriores intentos de depurar el programa
pueden resultarnos extremadamente enrevesados.

De nuevo hay que ejecutar el programa para verificarlo, y si es necesario, volver a depurarlo. Como podemos
ver, esto es un ciclo continuo que ni siquiera finaliza cuando el programa sale al mercado pues,
precisamente, las nuevas versiones de los programas constituyen versiones depuradas (y a veces también
ampliadas) de la versión anterior.

En definitiva, los errores que podemos encontrar son de tres tipos:

– Errores de sintaxis: son los más frecuentes, sobre todo cuando estamos aprendiendo a programar.
Significan que no hemos usado correctamente las reglas del lenguaje de programación. En este caso
el programa traductor no entiende la instrucción que está mal escrita. Si se trata de un intérprete, éste
se detendrá y mostrará un mensaje de error. Si es un compilador, no generará el fichero en código
máquina, y mostrará una lista con todos los errores encontrados durante la compilación.

– Errores de ejecución: se trata de instrucciones que el microprocesador comprende, pero no puede


llevar a cabo. Por ejemplo: divisiones por cero o raíces cuadradas de números negativos. El
programa se detiene, y el sistema operativo muestra un error. En algunos lenguajes de programación
es posible evitar que sea el sistema operativo quien muestre los errores, haciendo que el propio
programa gestione esas irregularidades.

– Errores lógicos: en este caso, el origen del error suele ser el diseño del algoritmo. El programa
funciona “aparentemente” bien, pero no produce los resultados esperados. Incluso puede ocurrir que
esos resultados incorrectos sólo se den en circunstancias muy concretas, lo que hace que sea muy
difícil detectar el error y su origen.

1.4 Desarrollo de un programa en lenguaje C


Teniendo en cuenta lo dicho en el apartado anterior, vamos a especificar aquí los programas que necesitamos
utilizar para desarrollar un programa empleando el lenguaje C. Veremos que hay algunos pasos intermedios
que no hemos comentado antes, pues no todos los lenguajes de programación los necesitan.

A) Editor de textos:

Permite que el programador plasme por escrito las instrucciones del programa, partiendo siempre del

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 7


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

diagrama de flujo o del pseudocódigo que desarrolle el algoritmo que describe ese programa.

Produce el código o programa fuente, que es un simple fichero de texto plano (sin códigos especiales).

B) Preprocesador:

Transforma el programa fuente, convirtiéndolo en otro archivo fuente preparado para ser compilado. Las
transformaciones incluyen:

· Eliminar los comentarios.

· Incluir en el código fuente el contenido de los ficheros declarados con #include <fichero.h>
(a estos ficheros se les suele llamar cabeceras – headers –).

· Sustituir en el código fuente las macros declaradas con #define (por ejemplo: #define CIEN 100).

C) Compilador:

Convierte el código fuente entregado por el preprocesador en un archivo en lenguaje máquina: el conocido
como fichero objeto.

Algunos compiladores pasan por una fase intermedia en lenguaje ensamblador, pero eso no es algo de lo que
el programador pueda darse cuenta al mandar compilar.

D) Enlazador (linker):

Un fichero objeto es código máquina, pero no se puede ejecutar, porque le falta código que se encuentra en
otros archivos binarios.

El enlazador genera el fichero ejecutable binario, a partir del contenido de los ficheros objetos y de las
bibliotecas.

Las bibliotecas contienen el código objeto de funciones precompiladas, a las que el archivo fuente llama en
algún momento (por ejemplo printf).

En la siguiente ilustración se puede ver todo el proceso de manera gráfica:

8 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

Editor de
textos

Para nosotros, todo esto parecerá


que se lleva a cabo en un único paso
cuando mandamos compilar el
fichero fuente.

Código fuente Pre- Código fuente


pre-procesado Compilador Código objeto
(texto) procesador (binario)
(texto)

Programa
Enlazador ejecutable
Cabeceras (linker)
(texto) (binario)

Bibliotecas
precompiladas
(binario)

1.5 Ejemplo básico de programa en C

#include <stdio.h>

main(){
/* Escribe un mensaje */
printf ("Hola, mundo\n");
}

1.6 Bibliotecas estándares


El lenguaje C es muy simple. Carece de los tipos de datos y de los servicios que sí forman parte de otros
lenguajes. Por ejemplo, no tiene tipo booleano, ni permite por sí solo el manejo de cadenas, ni el manejo de
memoria dinámica.
No obstante, el estándar de C define un conjunto de bibliotecas de funciones, que necesariamente vienen con
todo entorno de compilación de C, y que satisfacen estos servicios elementales.
Las interfaces de estos servicios (algo así como el medio para poder utilizarlos) vienen definidas en unos
ficheros de cabeceras (header files). El nombre de estos ficheros tiene la extensión .h (de header). El modo
de incluirlos en un programa en C es escribiendo, al principio del fichero fuente, la instrucción #include,
tal y como se ha visto en el ejemplo del apartado anterior.
Algunos de los servicios proporcionados por las bibliotecas estándares son:
· Entrada y salida de datos (stdio.h)
· Manejo de cadenas (string.h)
· Memoria dinámica (stdlib.h)

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 9


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

· Rutinas matemáticas (math.h)


Pero hay muchísimos más.

1.7 Estructura de un fichero fuente


Un fichero fuente en lenguaje C tendrá esta estructura típica:

#include <biblioteca1.h>
#include <biblioteca2.h>
... declaraciones de funciones ...
... declaraciones de variables globales ...
int main(){
... cuerpo del programa principal ...
}
... definiciones (cuerpos de funciones) ...

Las declaraciones y definiciones se pueden hacer en cualquier orden, aunque es preferible declarar las
funciones al principio del programa (por legibilidad). En todo caso, siempre hay que declarar una variable,
una constante, o una función, antes de poder utilizarla (y por tanto, antes de poder definirla)
Lo que se considera programa principal, en C tiene siempre el nombre main, y es simplemente una función
más del programa, con la particularidad de que es el punto de entrada al programa, y por lo tanto es
obligatorio que exista una función main en cualquier programa.

1.8 Comentarios
Los comentarios tienen como misión aclarar lo que hace el programa en cada momento.
Nunca se debe comentar lo obvio, sino que los comentarios deben resultar útiles para cualquier programador
(incluyendo a nosotros mismos) a la hora de “descifrar” por qué están ahí tales o cuales instrucciones de
código.
Teniendo en cuenta lo anterior, además hay que procurar que los comentarios sean breves.

En el C original, los comentarios tienen la forma


/* cualquier texto */
De este modo los comentarios se pueden extender varias líneas si lo necesitamos.
Cuando el comentario sólo va a ocupar una línea, una modificación del C original permite que se escriba más
rápidamente de este modo:
// cualquier texto
Con este método, todo lo que se escriba a partir de las dos barras es un comentario, que terminará con el final
de la línea.

10 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

Ejemplos:
{
/* Esto es un comentario
que ocupa varias líneas.
Finaliza cuando cerremos el comentario con estos dos símbolos
*/

/* Aunque también pueden ponerse así comentarios de una sola línea */

// Ésta es otra forma de poner un comentario. Sólo puede ocupar una línea.
// Para escribir otra línea seguida, hay que volver a poner las 2 barras.
}

1.9 Algunos programas más de ejemplo


Ahora se muestran varios programas simplemente para ejemplificar las cuestiones que han aparecido a lo
largo de este tema. No se pretende que se entienda absolutamente todo lo que hacen y cómo lo hacen, pero sí
que hay que fijarse en los pequeños detalles que se indicarán en cada caso.
Puesto que “a programar sólo se aprende programando”, conviene no limitarse a “leer” los ejemplos que
aparezcan de aquí en adelante, sino que es muy necesario escribirlos todos en el ordenador, por muy simples
que parezcan, y compilarlos, enlazarlos, ejecutarlos, y depurarlos en caso necesario.

Ejemplo 1: escribirlo y comprobar que da un error al enlazarlo, pues las funciones printf() y
esfera() no están definidas (esto lo explicaremos en otro tema).

// Fichero: EJEMP01.C
// Objetivo: calcular el volumen de una esfera.

int main() { No siempre se acaba la línea con punto y coma (;)


float volumen; Pero casi siempre se acaba así.
int radio2= 4; En rojo se ha resaltado la sangría que debe hacerse para marcar hasta dónde abarca un bloque
Es recomendable dejar una línea en blanco entre la declaración de variables y las instrucciones ejecutables.
volumen= esfera(radio2);
printf("Volumen: %f\n", volumen);
} Fijarse en que main termina aquí y por eso se cierra la llave.

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 11


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

Ejemplo 2: ahora se ha añadido lo que le faltaba al ejemplo anterior y ya funciona. Pese a ser un ejemplo
muy corto, podemos observar las distintas partes que componen habitualmente un programa en C.

// Fichero: EJEMP02.C
// Objetivo: calcular el volumen de una esfera.
Conviene dejar una línea o dos en blanco para separar cada parte del programa.

#include <stdio.h>

#define PI 3.14

float esfera(int); Declaración de funciones (simplemente se indica que se van a usar en el programa).

int main() { Programa principal : empieza aquí y va encerrado entre llaves.


float volumen;
int radio2= 4;

volumen= esfera(radio2);
printf("Volumen: %f\n", volumen);

return 0;
}

float esfera(int radio) { Definición de funciones (se "describe" o desarrolla cada función que se use).
float result;

result= radio*radio*radio;
result= 4*PI*result;
result= result/3;

return result;
}

Ejemplo 3:
Hacer un programa que calcule el interés en euros, de un capital de 600 € que se pongan a plazo fijo durante
50 años en un banco que dé un interés del 3%.

El análisis del problema y el diseño del algoritmo ya se hicieron en el apartado 1.3 (páginas 2 a 4). Debemos
fijarnos en ese trabajo hecho previamente, para poder hacer ahora el código fuente del programa. En dicho
código podremos observar otros detalles, como las partes de que consta este programa simple, o el uso de
comentarios. Además, hay que seguir fijándose en los pequeños detalles marcados en los ejemplos
anteriores.

// Fichero: EJEMP03.C Nos acostumbraremos a poner un encabezado como éste a todos nuestros programas.
// Objetivo: Calcular el interés producido por un plazo fijo.
// Nombre del programador: Miguel Ángel García Marcos
// Fecha: 28–11–2006
// Versión: 1.0

12 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

# include <stdio.h>
# include <conio.h>

int main (){


float capital; // Cantidad de dinero puesto a plazo fijo.
float interes; // Cantidad de dinero producido al final del plazo.
int redito; // Tipo de interés ofrecido por el banco.
int tiempo; // Duración del plazo fijo en años.

clrscr(); // Borra la pantalla.


printf("Cálculo de intereses \n");
capital= 600.00;
redito= 3;
tiempo= 50;
interes= capital * redito * tiempo / 100;
printf("\n\n RESULTADOS: \n");
printf("Interés obtenido: %1.2f euros", interes);

return 0;
}

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 13


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

14 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

Tema 2. Manipulación básica de datos

En este tema vamos a ver qué tipos de datos admite el lenguaje C, y cómo trabajar con ellos.

2.1 Literales
Un literal es un dato escrito directamente por el programador en el código fuente (por ejemplo, 1234, "hola",
etc.).

Nombre Descripción Ejemplos


Decimal Entero en base 10 1234
Hexadecimal Entero en base 16 0x1234
Octal Entero en base 8 01234
Carácter Byte en ASCII 'A'
Coma flotante Número real 1.25
expresado en 3.456e6
coma flotante 3.456e-6
Cadena Texto literal "hola, mundo"

2.2 Tipos básicos


Los datos en C han de tener un tipo. Las variables contienen datos, y se han de declarar del tipo adecuado a
los valores que van a contener. Por ejemplo, si se desea almacenar un dato tal como el radio de un círculo, y
se sabe que no siempre será un valor entero (podría a veces tener decimales), lo adecuado será crear una
variable que llamaremos radio, y advertir al compilador que será un número real usando el tipo adecuado;
en este caso float. Al declarar los datos con el tipo correcto, el compilador siempre sabrá la cantidad de
memoria que tiene que reservar para almacenar esa información y cómo interpretarla.

El C dispone de estos tipos básicos:

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 15


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

int enteros (números enteros positivos y negativos)


char caracteres (letras y demás símbolos)
float números en coma flotante (números reales)
double números en coma flotante de doble precisión
void no-tipo (se emplea con punteros)

Todos estos tipos -salvo void- son tipos numéricos; incluso el tipo char, que se emplea para almacenar
caracteres, es un tipo numérico.

Se pueden construir tipos de datos más elaborados a partir de los anteriores tipos básicos:
• Vectores y matrices (también llamados arrays o arreglos).
• Punteros
• Tipos estructurados (registros)

2.3 Rangos de valores y tipos modificados


Rango de los enteros:
Una variable entera acepta valores positivos y negativos dentro de un rango determinado, que depende de la
plataforma y del compilador. Así, en PCs bajo DOS se usan 16 bits, por lo que el rango de valores está
comprendido entre -32768 y 32767 cuando es un int, y entre 0 y 65535 cuando es un unsigned int; en
Windows y en Linux los enteros son números de 32 bits. De todos modos, podemos usar la función sizeof( )
(tamaño de) si queremos conocer el tamaño de éstos o cualquier otro tipo en nuestro sistema. Por ejemplo:
int main () {
printf("\n%d", sizeof (int));
printf("\n%d", sizeof (unsigned int));
return 0;
}

Existen modificaciones para el tipo int, para alterar el rango de valores sobre el que trabaja:

Modificador Significado
short entero corto (rango más pequeño)
long entero largo (rango más amplio)
unsigned entero sin signo (0..N)
signed entero con signo (-N-1 .. +N)

La palabra int se puede omitir en la declaración de la variable, pues es el tipo por defecto. Sin embargo, es
recomendable escribirla siempre, para que quede más claro.

16 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

Los modificadores de tamaño (short, long) y de signo (signed, unsigned) se pueden combinar.
Por omisión, un entero es signed (en la práctica, esta palabra reservada casi nunca se emplea).

Ejemplos:
unsigned radio; /* entero sin signo */
long saldoEnCuenta; /* entero largo con signo */
unsigned long telefono; /* entero largo sin signo */

Tipo char:
El tipo char permite manejar caracteres (letras y demás símbolos), aunque se trata de un tipo numérico.
Puesto que este tipo utiliza un byte (8 bit) para almacenar el dato en memoria, el rango de valores va de –128
a +127 (signed char), o bien de 0 a 255 (unsigned char).
Los literales de tipo carácter se pueden utilizar como números, y a la inversa, como se muestra en este
ejemplo:

int main() {
char caracter;
int entero;

caracter = 65; // valdría como una ‘A’ (valor binario= 0100 0001)
entero = ‘A’; // valdría como un 65 (valor binario= 0000 0000 0100 0001)
printf("%d\n", caracter); // INTERPRETAMOS el dato como un int (65)
printf("%c\n", caracter); // INTERPRETAMOS el dato como un char ('A')
printf("%d\n", entero); // INTERPRETAMOS el dato como un int (65)
printf("%c\n", entero); // INTERPRETAMOS el dato como un char ('A')

return 0;
}

Tipos para almacenar los datos numéricos reales:


Los datos numéricos reales son los que contienen decimales, en contraposición con los números enteros, que
no los tienen. Se va a almacenar en memoria de forma completamente distinta el número 4028, si se declara
como de tipo entero, que el número 4028.0 que habrá que declararlo como de tipo real. Además, ambos
números ocuparán muy distinto tamaño, en bytes, en la memoria.

Tabla resumen:
En esta tabla aparecen todos los tipos de datos simples que maneja el C, el tamaño que ocupan en memoria, y
el rango de valores que soporta cada uno:

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 17


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

Tipo Bytes Nombre Rango de valores


int * Entero simple *
unsigned int * Entero simple sin signo *
char 1 Entero de tipo carácter -128 a 127
ENTEROS

unsigned char 1 Entero de tipo carácter sin signo 0 a 255


short 2 Entero corto -32.768 a 32.767
unsigned short 2 Entero corto sin signo 0 a 65.535
-2.147.483.648 a
long 4 Entero largo
2.147.483.647
unsigned long 4 Entero largo sin signo 0 a 4.294.967.295
enum 2 Dato enumerado -32.768 a 32.767
float 4 ±3,4E ±38 (7 dígitos)
REALES

Real de simple precisión


double 8 Real de doble precisión ±1,7E ±308 (16 dígitos)

long double 10 Real doble largo ±1,2E ±4932 (18 dígitos)

* Depende del sistema, como se ha comentado al principio de este apartado.

2.4 Nombres de variables (identificadores)


Las variables se utilizan para guardar datos que pueden cambiar su valor dentro del programa.
Un identificador es un nombre que define a una variable, una constante, una función o un tipo de datos.
Para que un identificador sea válido, ha de empezar por una letra o por el carácter de subrayado _, seguido de
letras, dígitos o subrayados.
El nombre del identificador puede tener un máximo de 31 caracteres; si se ponen más, el resto se ignoran.
Se distinguen mayúsculas de minúsculas. NO es lo mismo longitud que Longitud, que LONGITUD.
No se pueden utilizar palabras reservadas del lenguaje C, como int, char, o while.
Muchos compiladores no permiten el uso de letras acentuadas o eñes en los identificadores, por lo que es
muy recomendable no usar estos caracteres nunca con este fin.
Los identificadores nos tienen que dar una idea rápida de a qué se refieren, por lo que debemos elegirlos con
cuidado. Interesa que sean nombres cortos, pero lo más descriptivos posible. Es decir, si una variable se va a
usar para almacenar el radio de una circunferencia, es preferible llamarla radio que simplemente r, y mucho
menos algo así como elefante o j, pues lo único que harían sería confundir y enrevesar el programa.

Ejemplos válidos:
char letra;
int Letra;
float CHAR;

18 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

int __variable__;
int cantidad_envases;
double precio123;
int __; /* Aunque es válido, no es útil, ni recomendable,
poner este nombre de identificador */
int var.nueva; /* El punto tiene un significado especial */

Ejemplos NO válidos:
int 123var; /* Empieza por dígitos */
char int; /* int es una palabra reservada */
int una sola; /* Contiene espacios */
int US$; /* Contiene $ */
int eñe; /* Puede no funcionar */

Siempre usaremos este método a la la hora de elegir identificadores para las variables: todas las letras con
minúsculas, excepto si son palabras compuestas; en este caso, la primera palabra empezará con minúscula, y
las siguientes empezarán con mayúsculas, para distinguir cada palabra. Por ejemplo: numMaximoPar

2.5 Declaraciones de variables


Como se ha dicho en el apartado anterior, las variables se utilizan para guardar datos que pueden cambiar de
valor dentro del programa.
Siempre hay que declarar las variables antes de usarlas. Declarar una variable permite dar al compilador dos
informaciones que debe conocer obligatoriamente para cada dato con el que queramos trabajar:
· Hay que especificar un tipo. Como se ha indicado en el apartado anterior, esto permite al
compilador saber cuánto espacio tiene que reservar en memoria para esa variable.
· Hay que asignar un nombre a esa variable. De este modo, a lo largo del programa, podremos
referirnos a la zona de memoria reservada para guardar ese dato mediante el nombre asignado. Si no
lo hiciéramos así, tendríamos que indicar la posición de memoria en la que está guardado el dato
cada vez que quisieramos usarlo o almacenarlo.
Forma de declarar una variable:
tipo nombre;
Ejemplo:
float radio;

Las variables globales se declaran justo antes de main() y fuera de cualquier función, y afectan a todo el
programa.
Las variables locales se declaran al principio de la función que las vaya a emplear, y sólo afectan a esa
función.
Veamos un pequeño ejemplo de programa para apreciar cómo se declaran las variables:

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 19


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

// Fichero: EJEMP04.C
// Objetivo: Mostrar la declaración de variables.
// Nombre del programador: Miguel Ángel García Marcos
// Fecha: 16–1–2007
// Versión: 1.0

# include <stdio.h> // Fichero de cabecera necesario para printf( )


# include <conio.h> // Fichero de cabecera necesario para clrscr( )

int main (){


char letra= 'h';
int entero= 1285;
float real= 123456789123456789123.0; // Con el punto aseguramos nº real
double realDoble= 123456789123456789123.0;
long double realDobleLargo= 123456789123456789123.0L;// L asegura un long

clrscr();
printf("letra= %c\n", letra);
printf("entero= %d\n", entero);
printf("real= %1.2f\n", real); // Cambiar %1.2 y observar.
printf("realDoble= %1.2f\n", realDoble);
printf("realDobleLargo= %1.2Lf\n", realDobleLargo);// L mayúscula (long)

return 0;
}

Al compilarlo con Code:Blocks en Windows (que usa MinGW como compilador por defecto),
comprobamos que se produce un aviso de que el modificador L no existe. El mencionado compilador no
soporta los números reales de doble precisión largos. Esto conlleva que no se pueda visualizar en pantalla la
variable realDobleLargo, pues aparece un número negativo gigantesco pero sin precisión, dado que tiene una
ristra enorme de ceros en sus cifras menos significativas. Este problema no sucede si se usan otros
compiladores; incluso sale bien si se compila con la versión de Code:Blocks para Linux, donde se muestra el
valor 123456789123456789120.00.

Ahora cambiaremos algunas cosas y añadiremos variables nuevas:


– Añadimos las líneas siguientes en los lugares adecuados:
char valor= 147;
printf("valor= %d\n", valor);
como char es un tipo que usa 8 bit con signo, convertirá 147 (1001 0011 en binario) en -109 (0110 1101
el mismo número en complemento a 2).
– Añadimos correctamente:
char numero= 'a';
printf("numero= %c\n", numero);
no hay ningún error, pues el nombre de la variable no influye en absoluto.
– Modificamos la declaración de la variable letra:
char letra= 65;
tampoco hay error, ya que 65 es el código ASCII de la letra A mayúscula.

20 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

– Añadimos:
char letra2= 472;
printf("letra2= %c\n", letra2);
en este caso sí hay un error pues el tipo char ocupa 8 bits en memoria, por tanto no cabe el número 472.
– Modificamos la declaración de la variable entero:
int entero= 2147483648;
Esto también provoca un resultado erróneo, debido a que el número asignado se pasa del tamaño
admitido por el tipo int.
– Añadimos:
int cosa= 2.6;
printf("cosa= %d\n", cosa);
El tipo int no admite decimales, pues es un tipo entero. Al hacer esta asignación simplemente se eliminan
los decimales sin hacer redondeo: 2.6 se convierte en 2 (y no en 3 como ocurriría si se redondeara).
– Cambiamos la declaración de la variable real:
float real= 66;
En este caso el error consiste en que, para las variables de tipo real, los números asignados deben tener
obligatoriamente decimales. Lo correcto, por tanto, sería escribir 66.0 y no 66.

2.6 Las constantes


Las constantes se utilizan para almacenar aquellos datos cuyo valor no debe (y no puede) cambiar durante la
ejecución del programa. Por lo demás, tienen las mismas características que las variables, y se pueden
manejar igual que éstas.

Cuando un número se escribe sin prefijo alguno, es tratado como un número en base decimal. Sin embargo,
si añadimos el prefijo 0x, entonces será considerado como un número hexadecimal. Pero si lo que deseamos
es que sea entendido como un número octal, entonces escribiremos un cero justo delante del número.
Por otra parte, si un número no incluye punto decimal, se entenderá que se trata de un número de tipo entero.
Por el contrario, si tiene un punto decimal, será un número de tipo real.

Si se añade una letra L (en mayúscula o en minúscula) justo después del número, se considera que es de tipo
long. Es preferible escribirla en mayúsculas para evitar que la letra l (ele) se confunda con el número 1.
Cuando se añade una U (mayúsczula o minúscula) después del número, se tratará de un unsigned (sin signo).
En el caso de que se añada una F (mayúscula o minúscula) después del número, estaremos ante un número
en coma flotante (número real).

Las letras L, U y F se pueden combinar según interese para conseguir los distintos tipos, como se nombran

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 21


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

en la tabla de la página 18. Por ejemplo, el número 4275UL se almacenará en memoria como un entero
(pues no tiene punto decimal), de tipo largo (por la L), y sin signo (pues así lo indica la U).

Los identificadores que se usen para nombrar las constantes deben escribirse con todas sus letras en
mayúsculas; de este modo los distinguiremos rápidamente de los identificadores dedicados a los nombres de
variables, que se escribirán con minúsculas. Por ejemplo, si queremos utilizar el valor de π para calcular la
longitud de una circunferencia, lo adecuado es que declaremos al principio del programa una constante que
llamaremos PI y la asignemos el valor 3.141593 (el número máximo de decimales que podemos emplear
dependerá del tipo de dato que consideremos, como se muestra en la tabla de la página 18). De este modo
tendremos dos posibilidades de declarar esa constante:

a) Mediante la directiva del preprocesador # define


# define PI 3.141593 // NO se ponen = ni el punto y coma al final.
b) Del mismo modo que declararíamos cualquier variable, pero añadiendo delante la palabra reservada const
const PI= 3.141593; // En este caso hay que insertar el símbolo de
//asignación y terminar con punto y coma.

2.7 Cómo se almacenan los datos en memoria


El espacio necesario para almacenar un dato depende del tipo de dato que se utilice para guardarlo.
Como se dijo al principio del apartado 2.3, se puede utilizar la función sizeof para conocer cuánto ocupa un
dato en memoria. En este ejemplo lo podemos apreciar:
// Fichero: EJEMP05.C
// Objetivo: Mostrar cómo se almacenan los datos en memoria.
// Nombre del programador: Miguel Ángel García Marcos
// Fecha: 21–1–2007
// Versión: 1.0

#include <stdio.h>

int main(){
char valor1= 5;
int valor2= 5;

printf("\n\n\n Tamaño de \"valor1\"= %d bytes\n", sizeof valor1);


printf("\n Tamaño de \"valor2\"= %d bytes\n", sizeof valor2);
printf("\n\n Los tipos de datos distintos suelen ocupar distinto\
tamaño en la memoria del ordenador"); // Observar lo que ocurre cuando
//no cabe todo en 1 línea de la pantalla.
//NO es aconsejable hacer estas líneas tan
//largas. Conviene "trocearlas" con varias
//sentencias printf().
return 0;
}
Con el siguiente ejemplo, además se pretende mostrar cómo se usa la memoria para guardar cada dato:

22 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

// Fichero: EJEMP06.C
// Objetivo: Mostrar la dirección, el contenido y el tamaño en bytes
// de distintas variables. Así se comprenderá cómo son almacenadas
// en cada "piso" de la memoria.
// Nombre del programador: Miguel Ángel García Marcos
// Fecha: 24–5–2010
// Versión: 1.5

#include <stdio.h>

int main(){
// Declaración de las variables que se usarán:
char variable1, variable2;
int variable3, variable4;
float variable5, variable6;

// Presentación de resultados antes de inicializar las variables:


printf("\n\n\n");
printf(" NOMBRE \tDIRECCIÓN \tCONTENIDO \tTAMAÑO \n");
printf("----------------------------------------------------------\n");
printf("variable1 \t%u \t%d= %c \t\t%d bytes \n",(unsigned int)&variable1,\
variable1, variable1, sizeof variable1);
printf("variable2 \t%u \t%d= %c \t\t%d bytes \n",(unsigned int)&variable2,\
variable2, variable2, sizeof variable2);
printf("variable3 \t%u \t%d \t%d bytes \n", (unsigned int)&variable3,\
variable3, sizeof variable3);
printf("variable4 \t%u \t%d \t%d bytes \n", (unsigned int)&variable4,\
variable4, sizeof variable4);
printf("variable5 \t%u \t%f \t%d bytes \n", (unsigned int)&variable5,\
variable5, sizeof variable5);
printf("variable6 \t%u \t%f \t%d bytes \n", (unsigned int)&variable6,\
variable6, sizeof variable6);

// Inicialización de todas las variables:


variable1= 66;
variable2= 'B';
variable3= -4721;
variable4= 20371;
variable5= 4.6;
variable6= 2.0E3;

// Presentación de los resultados después de la inicialización:


printf("\n\n");
printf("variable1 \t%p \t%d= %c \t\t%d bytes \n", &variable1,\
variable1, variable1, sizeof variable1); // %p indica puntero
printf("variable2 \t%p \t%d= %c \t\t%d bytes \n", &variable2,\
variable2, variable2, sizeof variable2);
printf("variable3 \t%p \t%d \t\t%d bytes \n", &variable3,\
variable3, sizeof variable3);
printf("variable4 \t%p \t%d \t\t%d bytes \n", &variable4,\
variable4, sizeof variable4);
printf("variable5 \t%p \t%f \t%d bytes \n", &variable5,\
variable5, sizeof variable5);
printf("variable6 \t%p \t%f \t%d bytes \n", &variable6,\
variable6, sizeof variable6);

return 0;
}

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 23


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

La salida de este programa será similar a esto, aunque, como es lógico, antes de la inicialización, las
variables pueden contener cualquier valor aleatorio:

NOMBRE DIRECCIÓN CONTENIDO TAMAÑO


----------------------------------------------------
variable1 3216599407 -65= � 1 bytes
variable2 3216599406 -71= � 1 bytes
variable3 3216599400 134514416 4 bytes
variable4 3216599396 13295604 4 bytes
variable5 3216599392 0.000000 4 bytes
variable6 3216599388 0.000000 4 bytes

variable1 0xbfb9696f 66= B 1 bytes


variable2 0xbfb9696e 66= B 1 bytes
variable3 0xbfb96968 -4721 4 bytes
variable4 0xbfb96964 20371 4 bytes
variable5 0xbfb96960 4.600000 4 bytes
variable6 0xbfb9695c 2000.000000 4 bytes

Podría ser que la dirección apareciera en formato segmento-desplazamiento. Eso dependerá del compilador y
modelo de memoria que se haya elegido para compilar el programa (desde tiny –diminuto– hasta huge –
enorme–). Si fuera así, entonces, para conocer la dirección completa, habría que multiplicar el valor
segmento por 16 y sumar el desplazamiento.

2.8 Expresiones y operadores


Expresión: conjunto de variables, constantes y funciones, unidas por operadores.
Por ejemplo:
capital * redito * tiempo / 100
es una expresión formada por 3 variables (capital, redito y tiempo) y una constante numérica (100). Estos 4
elementos están unidos por 3 operadores (en este caso se trata de operadores aritméticos).
En C, el resultado de una expresión es un número, o una cadena de caracteres. En otros lenguajes también
puede ser un valor booleano (verdadero o falso – true o false – ), aunque no hay demasiados problemas para
interpretarlo también así en C si lo necesitamos.

Uno de los operadores más utilizados es el de asignación (=). Con este operador se evalúa todo el resto de la
expresión y el resultado se asigna a una variable. Dicho con otras palabras, se llevan a cabo todas las
operaciones necesarias para conocer cuál es el resultado de todas las operaciones que se indiquen en la
expresión; cuando se obtiene el resultado, éste se copia en la posición de memoria que se haya reservado
para la variable escrita a la izquierda del operador de asignación.
Antes de ver los distintos tipos de operadores que existen, hay que resaltar un detalle: debemos tener mucho
cuidado al mezclar distintos tipos de datos en una misma expresión. Debido a que el C no hace

24 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

comprobaciones, podemos obtener resultados “extraños” completamente imprevistos. Veamos esto con un
ejemplo:

// Fichero: EJEMP07.C
// Objetivo: Provocar un resultado erróneo por incompatibilidad de tipos.
// Nombre del programador: Miguel Ángel García Marcos
// Fecha: 20–2–2011
// Versión: 1.5

# include <stdio.h>

int main() {
long enteroLargo= 45000;
float real= 10.0;
short enteroCorto;

enteroCorto= enteroLargo + real;


printf("%d\n", enteroCorto);
return 0;
}

Extrañamente, el resultado de sumar 45000 +10 no es 45010, sino un número negativo. ¿Dónde está el
problema? Aunque pueda parecer que lo incorrecto es mezclar un número entero con otro real, el fallo no es
ese (en este caso). Veamos una nueva versión del programa, en la que prescindimos del número real:

// Fichero: EJEMP07B.C
// Objetivo: Provocar un resultado erróneo por incompatibilidad de tipos.
// Nombre del programador: Miguel Ángel García Marcos
// Fecha: 20–2–2011
// Versión: 2.5

# include <stdio.h>

int main() {
long enteroLargo= 45000;
short enteroCorto;

enteroCorto= enteroLargo;
printf("%d\n", enteroCorto);
return 0;
}

¿Por qué sigue fallando? Para dar una respuesta razonada, debemos mirar de nuevo en la tabla de la página
18. Ahí comprobamos que un dato de tipo long utiliza 4 bytes para almacenar su valor; sin embargo, un dato
de tipo short, emplea tan sólo 2 bytes, y además hay que reservar un bit para el signo, por lo que se dispone
de sólo 15 bits. Si hacemos cuentas, obtenemos que 2 15= 32768, es decir, que el número 45000 que
intentamos meter en la variable enteroCorto no cabe. Si intentásemos almacenar el número 32769 ya
desbordaríamos la capacidad de almacenamiento de esta variable, y el bit nº 16 pasaría de 0 a 1: acabamos
de poner el signo negativo, y tendríamos el -32767 guardado en esa variable. Eso es así porque los números
negativos se interpretan en complemento a 2. El problema se puede entender mejor si se escribe una tabla

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 25


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

que contenga todos los valores binarios posibles usando 3 bit más uno de signo en complemento a 2, y
escribiendo al lado el valor decimal correspondiente. Después procedemos a sumar 1 al número positivo más
alto posible en esa tabla (+7); ¿qué obtenemos? ¡justamente -8!
Ante esto tenemos dos soluciones, y ambas pasan por cambiar el tipo de dato para reservar más espacio para
esta variable: o bien usar un unsigned short, o bien usar un long. Veamos el problema resuelto en la siguiente
versión del programa:

// Fichero: EJEMP07C.C
// Objetivo: Provocar un resultado erróneo por incompatibilidad de tipos.
// En esta versión se resuelve el problema.
// Nombre del programador: Miguel Ángel García Marcos
// Fecha: 21–1–2007
// Versión: 3.0

# include <stdio.h>

int main() {
long enteroLargo= 45000;
float real= 10.0;
unsigned short enteroCorto; // Sin bit de signo, se duplica su capacidad.

enteroCorto= enteroLargo+real;
printf("%d\n", enteroCorto); // %d interpreta un entero con bit de signo.
printf("%u\n", enteroCorto); // %u indica que se imprima un unsigned int.
return 0;
}

Un nuevo ejemplo nos muestra más errores producidos al mezclar tipos de datos:
// Fichero: EJEMP08.C
// Objetivo: Muestra cómo se produce un error de cálculo cuando se mezclan
// variables de diferentes tipos en una expresión.
// Programador: Miguel Ángel García Marcos
// Fecha: 20-2-2011
// Versión: 1.5

#include <stdio.h>

int main(){
long enteroLargo= 2100000000;
long enteroLargo2;
short enteroCorto;
float real= 5.3;
float real2;
double real3;

enteroCorto= real+enteroLargo;
enteroLargo2= real+enteroLargo;
real2= real+enteroLargo;
real3= real+enteroLargo;

printf("\n\n%d\n", enteroCorto);// Error de tipos. Muestra "-32768".


printf("%ld\n", enteroLargo2); // Trunca decimales. Muestra "2100000005".
printf("%f\n", real2); // float no tiene precisión suficiente.
// Muestra "2100000000.000000"
printf("%lf\n", real3); // Correcto, pero hay que ajustar el nº de decimales

26 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

// Muestra "2100000005.300000"
printf("%14.2f\n\n", real3); // Imprime mínimo 14 caracteres, incluyendo
//el punto y los 2 decimales pedidos.
//Muestra " 2100000005.30".
return 0;
}

En C disponemos de todos estos tipos de operadores:


• Aritméticos: para operar con datos numéricos.
• Relacionales o de relación: para comparar números o caracteres.
• Lógicos: permiten crear expresiones lógicas, es decir, basadas en el álgebra de Boole.
• De asignación: transfieren datos de una expresión, una constante o una variable, a una variable.
• Direccionales: permiten conocer la dirección de memoria en la que está almacenada una variable o una
función. También sirven para conocer el valor del dato almacenado en una dirección dada.

En este tema únicamente vamos a ver los operadores aritméticos; el resto los iremos viendo a medida que los
necesitemos, y cuando conozcamos las estructuras del lenguaje que los utilizan.

2.8.1 Operadores aritméticos


Operador Nombre
* Multiplicación
/ División
% Resto de división (módulo)
+ Suma
- Resta
++ Incremento
-- Decremento
- Cambio de signo

Como los operadores de incremento y decremento son nuevos para el programador que desconoce el
lenguaje C, haremos un ejemplo con el primero de ellos (operador incremento) y el alumno lo modificará
para observar el funcionamiento del otro (operador decremento).

// Fichero: EJEMP09.C
// Objetivo: Mostrar el funcionamiento del operador de incremento.
// Programador: Miguel Ángel García Marcos
// Fecha: 21-1-2007
// Versión: 1.0

#include <stdio.h>

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 27


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

int main(){
int valor1,
valor2= 3,
valor3= 3;

printf("\n\n\nvalor1= %d\n", valor1); // Será un valor "aleatorio"


//por no estar inicializada.
printf("valor2= %d valor3= %d\n", valor2, valor3);
printf("\nAumenta valor2 con el\
operador a la derecha.\n"); // Así se parte un texto que no
//cabe en 1 línea de código.
// Aunque no es recomendable usarlo.
printf("Primero asigna el valor y posteriormente aumenta su valor: \n");
valor1= valor2++; // Esto se llama POST-INCREMENTO
printf("valor1= %d valor2= %d\n",\
valor1, valor2); // Y no sólo parte el texto, sino cualquier
//sentencia que no quepa en una línea.
printf("\nAumenta valor3 con el operador a la izquierda.\n");
printf("Primero aumenta su valor y luego asigna éste: \n");
valor1= +valor3; // PROBAR 1º ESTO y ver la diferencia.
printf("valor1= %d valor3= %d\n", valor1, valor3);
valor1= ++valor3; // Esto se llama PRE-INCREMENTO
printf("valor1= %d valor3= %d\n", valor1, valor3);

return 0;
}

28 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

Tema 3. Control del flujo del programa (1)

3.1 Introducción
Se entiende por flujo de un programa el modo en que se avanza de una instrucción a la siguiente dentro de
ese programa. También podríamos decir que es la forma en que fluyen las intrucciones por el
microprocesador.
El programador debe controlar en todo momento cuál es la siguiente instrucción que se ejecutará en cada
caso. Es decir, debe controlar el flujo de instrucciones de ese programa.
Cuando se ha ejecutado una instrucción, sólo existen tres posibilidades a la hora de escoger la siguiente
instrucción, o lo que es lo mismo, de controlar cuál será la siguiente instrucción en ejecutarse. Por eso sólo
existen tres estructuras de control del flujo:

Instrucción 1
Instrucción 1 Instrucción 1

Instrucción 2 Instrucción 2
Condición

LE
Instrucción 3
Instrucción 3 C
Opción A Opción B
BU

Instrucción 4
Condición

Estructura secuencial Estructura de selección


Instrucción 4

Estructura de repetición

• Estructura secuencial: la siguiente instrucción que se ejecuta es la que está justo a continuación en el
listado del código fuente del programa, y que estará en la siguiente posición de memoria cuando se
compile.
• Estructura de selección: dependiendo del resultado de la evaluación de una condición, seguidamente se
ejecutará una instrucción u otra. De este modo el flujo de instrucciones se divide en dos o más caminos,

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 29


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

aunque si la condición decide avanzar por un camino se abandonarán los otros (no se puede avanzar por
más de un camino a la vez).
• Estructura de iteración o repetición: la siguiente instrucción que se ejecuta se encuentra antes que la
que se acaba de ejecutar, pues ya se ha pasado por ella anteriormente. Diremos que se ha formado un
lazo o bucle en el flujo del programa. Normalmente hay que evitar los bucles infinitos, dando la
posibilidad de que en algún momento (mediante una condición) se dejen de repetir las mismas
instrucciones.

Hasta aquí, todos los programas de ejemplo que se han planteado tenían una estructura secuencial, pues eran
muy simples. No obstante, lo habitual es que un programa incluya las tres estructuras.

3.2 Estructura de selección


Normalmente ocurre que una parte concreta del programa conviente que se ejecute sólo cuando se cumple
determinada condición. Cuando dicha condición no se cumple, entonces no deben ejecutarse las
instrucciones contenidas en esa parte del programa.
En estos casos estamos seleccionando el camino a seguir por el flujo del programa. Pueden darse tres
situaciones:

A) La parte que no conviene ejecutar simplemente se salta. Para esto, en lenguaje C se usa la sentencia if.

// Fichero: EJEMP10.C
Inicio // Objetivo: mostrar funcionamiento de la sentencia if
// Versión: 1.0

# include <stdio.h>
Condición No # include <conio.h> Se necesita para usar la función getche
cierta
int main( ){
Sí char tecla;
Se ejecuta printf("Pulsa A para ver el mensaje \n");
esto tecla= getche(); Abreviatura de GET CHar with Echo
if(tecla == 'A') NO termina con punto y coma
printf("Has pulsado la letra A mayúscula\n\n");
printf("El programa continúa aquí\n");
Continuación return 0;
del programa }

Ahora modificamos el ejemplo y para comprobar el porqué, si queremos hacer una comparación de igualdad,
en lenguaje C debemos usar el signo = = (dos signos de igual seguidos, sin espacios entre medias). En caso
de escribir un único signo de igualdad, lo que estaremos haciendo es asignar, a la parte izquierda del igual, lo
que haya en la parte derecha.

30 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

// Fichero: EJEMP10B.C
// Objetivo: mostrar funcionamiento de la sentencia if
// Versión: 1.1

# include <stdio.h>
# include <conio.h>

int main( ){
char tecla;

printf("Pulsa A para ver el mensaje \n");


tecla= getche();
if(tecla = 'A') ATENCIÓN: en este caso se trata de una asignación, no de una comparación.
printf("Has pulsado la A mayúscula\n\n");
printf("El programa continúa aquí\n");
return 0;
}

El funcionamiento de una asignación situada dentro de los paréntesis de una condición es el siguiente:
• En primer lugar se lleva a cabo dicha asignación de forma normal, por lo que estamos cambiando el
valor de la parte izquierda (en este caso la variable tecla).
• A continuación se evalúa la condición; para ello simplemente se comprueba el valor que tiene la parte
izquierda (en este caso la variable tecla):
― Si el valor es cero, entonces la condición es falsa.
― Si el valor es distinto de cero (positivo o negativo), entonces la condición se considera cierta.

Una nueva pequeña modificación del ejemplo original: ahora usaremos la función getch() en vez de getche().
La diferencia es que ahora no se mostrará en pantalla la tecla pulsada automáticamente (no hay eco).
Lo que haremos será mostrar la tecla pulsada sólo si se trata de la A, y después visualizaremos el mismo
mensaje que antes si hemos pulsado dicha tecla.
Eso sí, volvemos a hacer la comparación del modo correcto (sin hacer una asignación).

// Fichero: EJEMP10C.C
// Objetivo: mostrar funcionamiento de la sentencia if
// Versión: 1.2

# include <stdio.h>
# include <conio.h>

int main( ){
char tecla;

printf("Pulsa A para ver el mensaje \n");


tecla= getch();
if(tecla == 'A')
printf("%c", tecla);
printf("Has pulsado la A mayúscula");
return 0;
}

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 31


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

Pero resulta que nos dice que hemos pulsado la letra A, independientemente de qué tecla pulsemos ¿Por
qué no funciona como esperamos?
La respuesta es simple, y nos sirve de excusa para destacar la enorme importancia que tiene la tabulación de
cada línea. Tal como hemos tabulado las dos líneas después del if, nos parece que ambas están incluidas en la
estructura de ese if. Sin embargo, para el compilador (que ignora todos los tabuladores que escribamos, pues
los elimina el pre-procesador) la única línea que tiene algo que ver con la instrucción condicional es la
primera de las dos (la que muestra el carácter almacenado en la variable tecla); la línea siguiente se ejecutará
de forma incondicinal, es decir, siempre. Esto queda más claro si vemos el diagrama de flujo equivalente:

EJEMP10
VER. 1.2

“Pulsa A”

Atención a la diferencia entre


tecla ← desde teclado
una asignación (signo ← )

No
tecla = 'A'
y una comparación (signo = )
Sí en los diagramas de flujo.

Muestra valor
de tecla

Como vemos, esto se ejecutará SIEMPRE,


“Has pulsado A”
y no de forma condicional.

Fin

Aquí hay que resaltar un detalle: pese a que en esta ocasión hemos hecho el diagrama de flujo a partir del
código, lo correcto es hacerlo al revés, como se explicó en el tema 1. Si se ha hecho así es simplemente
porque ahora lo que se busca es mostrar el funcionamiento de las estructuras condicionales y su escritura en
lenguaje C, más que el desarrollo de un programa. Sin embargo este detalle no se nos debe olvidar nunca.

Continuando con la explicación del ejemplo, cuando deseamos que dos o más instrucciones se ejecuten de
forma condicional, es imprescindible agruparlas en un bloque. Para hacerlo, tan sólo hay que encerrarlas
entre llaves. Ésta es la versión final del programa, junto con su diagrama de flujo asociado, para que
podamos apreciar mejor la diferencia:

32 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

// Fichero: EJEMP10D.C
Inicio
// Objetivo: mostrar funcionamiento de
// la sentencia if
// Versión: 1.3

No # include <stdio.h>
Condición # include <conio.h>
cierta
int main( ){
Sí char tecla;

Se ejecuta printf("Pulsa A para ver el mensaje \n");


esto tecla= getch();
if(tecla == 'A'){ // Indica el principio del bloque
printf("%c", tecla);
printf("Has pulsado la A mayúscula");
} // Indica el final del bloque

Continuación return 0;
del programa }

Si ahora no tabulásemos esas dos líneas del modo que indica la zona marcada en verde, el programa seguiría
funcionando exactamente igual, dado que, como se ha dicho antes, el compilador ignora los tabuladores,
independientemente de que haya o no llaves. Sin embargo, sigue siendo imprescindible tabularlo de forma
correcta, para que el programador vea con más claridad cuáles son las líneas de código que se ejecutarán de
forma condicional.

B) La segunda situación que se puede dar en las estructuras de selección es que, cuando no se ejecuta una
parte del programa, se ejecuta una opción alternativa. Para este caso emplearemos la sentencia if...else.
Else, en inglés, se puede traducir por "y si no...".
// Fichero: EJEMP11.C
// Objetivo: mostrar el funcionamiento de
Inicio // la sentencia if...else

# include <stdio.h>
# include <conio.h>
No (else)
Condición
cierta int main( ){
char tecla;

printf("Pulsa A para ver el mensaje \n");
Acción A Acción B tecla= getch();
if(tecla == 'A') NO termina con punto y coma
printf("Has pulsado la letra A");
else NO termina con punto y coma
printf("Te dije que pulsaras A");
Continuación printf("\n\nEl programa continúa aquí");
del programa return 0;
}

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 33


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

Del mismo modo que para la sentencia if, cuando deseemos que else afecte a más de una instrucción,
encerraremos tales instrucciones entre llaves para que formen un bloque.
Ejercicio: ¿Cómo se haría para que, sólo en caso de no pulsar A, el programa mostrara la tecla pulsada?

C) El tercer y último caso, que nos podemos encontrar al usar las estructuras condicionales, es cuando
existen más de dos opciones donde elegir para continuar el programa. En esta situación podemos emplear
una sentencia if...else múltiple, o bien una sentencia switch(...) case...
Este caso lo veremos con detenimiento en el tema siguiente. Por el momento es preferible afianzar las
estructuras de selección vistas en los casos A) y B).

3.3 Qué se puede poner como condición para hacer una selección
Hemos visto que en las estructuras de selección siempre aparece un bloque (dibujado con un rombo en el
diagrama de flujo) que corresponde a una condición lógica. Para poder componer una condición de este tipo
necesitamos conocer los operadores de relación y los operadores lógicos.

A) Operadores de relación: un operador de éstos compara dos datos; el resultado de esa comparación sólo
puede ser de dos formas:
· Verdadero
· Falso
El lenguaje C utiliza el valor 0 (cero) para representar falso, mientras que cualquier valor distinto de 0
significará verdadero.
Esto ya fue explicado en la página 31 al escribir la versión 1.2 del programa EJEMP10, por lo que podemos
repasar ese ejemplo para comprenderlo mejor. En esa ocasión nos estábamos refiriendo a lo que ocurría
cuando escribíamos el signo de asignación en vez de poner el signo de comparación de igualdad; sin
embargo, no es necesario que haya una asignación, sino que podemos encontrarnos con lo siguiente:

// Fichero: EJEMP12.C
// Objetivo: Mostrar el significado de CIERTO y FALSO en lenguaje C

#include <stdio.h>

int main () {
int numero;

numero= 4;
if (numero)
printf("La condición es cierta"); // Esto sí se visualizará.
numero= 0;
if (numero)
printf("La condición es falsa"); // Esto NO se visualizará.

return 0;
}

34 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

Los operadores de relación son los siguientes:

Operador Significado
> Mayor que
>= Mayor o igual que
< Menor que
<= Menor o igual que
== Igual que
!= No igual (distinto) que

Para ilustrar el uso de estos operadores, vamos a ver un ejemplo. Conviene leer el código de este programa e
intentar averiguar, ANTES de escribirlo en el ordenador, qué mensajes se visualizarán al ejecutarlo, y cuáles
no. Puede ser útil mirar al mismo tiempo el diagrama de flujo y el código fuente. Después se cambiará el
valor de la variable numero, para comprobar el funcionamiento del programa en distintos casos.
Se escribirán en un papel los resultados previstos del programa, antes de teclear su código.

EJEMP13 // Fichero: EJEMP13.C


// Objetivo: Mostrar el uso de los
// operadores de relación.
numero ← 10 // Programador: Miguel Ángel García Marcos
// Fecha: 14-2-2007
numero = 11
No // Versión: 1.0

#include <stdio.h>
“El nº es 11”
int main(){
int numero;
No
numero = 10
Sí numero= 10;
printf("\n\n");
“El nº es 10”
if(numero==11)
printf("El número es 11 \n");
No if(numero==10)
numero ≤ 15
printf("El número es 10 \n");
Sí if(numero<=15)
“Nº menor o igual que 15” printf("Es menor o igual a 15 \n");
if(numero!=10)
printf("No es 10 \n");
No
numero ≠ 10
return 0;

}
“El nº no es 10”

FIN

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 35


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

B) Operadores lógicos:
Una expresión lógica es aquella que da como resultado cierto o falso.
Por ejemplo: numero < 5 es una expresión lógica, pues puede ser cierto o falso, dependiendo del valor que
tenga la variable numero en el momento de evaluar esa expresión.
Los operadores lógicos sirven para concatenar dos o más expresiones lógicas. El resultado final de evaluar el
conjunto de esas expresiones también será verdadero o falso; por lo tanto, esas expresiones juntas también
formarán una expresión lógica.
Ejemplo: (numero < 5) && (nivel >= 2) (en este caso no serían necesarios los paréntesis)
Tenemos dos expresiones lógicas unidas por un operador lógico, lo que forma otra expresión lógica
más compleja.

Estos son los operadores lógicos que se usan normalmente:

Operador Significado
! Negación (No)
&& Conjunción (Y)
|| Disyunción (O)

Los siguientes operadores lógicos, sin embargo, se emplean sólo cuando se desea trabajar a nivel de bits
independientes, y por eso únicamente son válidos con datos de los tipos char, int, long y enum.

Operador Significado
~ Negación de bits (No)
& Conjunción de bits (Y)
| Disyunción de bits (O)
^ O exclusiva (XOR)
<< Desplazamiento de bits a la izquierda
>> Desplazamiento de bits a la derecha

De nuevo ilustraremos el uso de estos operadores mediante un par de ejemplos. Igual que antes, hay que
intentar averiguar el funcionamiento del programa antes de escribir el código en el ordenador. Los diagramas
de flujo se van a poner después del código del programa. El alumno intentará obtener esos diagramas a partir
del código, sin haberlos mirado previamente, y después podrá comparar su resultado.

36 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

// Fichero: EJEMP14.C
// Objetivo: Mostrar el uso de los operadores lógicos.
// Programador: Miguel Ángel García Marcos
// Fecha: 14-2-2007
// Versión: 1.0
#include <stdio.h>

int main(){
char codigo;
int valor;

printf("\n\n");
codigo= 'z';
valor= 471;
if(codigo=='z' && valor !=200)
printf("\n Se cumple la condición requerida\n");
if(codigo=='h' || codigo=='b' || (codigo=='z' && valor==471))
printf("\n Se cumple también la condición\n");
if(codigo!='z' && valor>=500){
printf("\n ¿Se cumplirá esta condición? \n");
printf("¿O no se cumplirá?\n");
}
return 0;
}

// Fichero: EJEMP15.C
// Objetivo: Mostrar el uso de los operadores lógicos.
// Programador: Miguel Ángel García Marcos
// Fecha: 14-2-2007
// Versión: 1.0

#include <stdio.h>

int main(){
int valor= 0;
if(!valor)
printf("\n\n\n El valor es cero\n");
if(valor)
printf("\n\n\n El valor es distinto de cero\n");
return 0;
}

Para entender mejor este programa, conviene repasar lo dicho en las páginas 31 y 34. No obstante esta
sintaxis abreviada, que permite el lenguaje C en las condiciones, puede resultar a veces confusa, por lo que
es preferible prescindir de ella, y escribir las condiciones del modo en que se muestra en el diagrama de flujo
correspondiente a este programa.

En la página siguiente aparece el diagrama de flujo correspondiente a cada uno de estos dos programas.

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 37


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

EJEMP14 EJEMP15

codigo 'z' valor 0


valor 471

No
valor = 0
No
codigo = 'z'


“El valor es cero”
No
valor ≠ 200


No
valor ≠ 0
“Se cumple la condición”

“El valor es distinto de 0”


No
codigo = 'h'

Sí FIN
No
codigo = 'b'


No
codigo = 'z'

No
valor = 471

“También se cumple”

No
codigo ≠ 'z'

No
valor ≥ 500

“¿Se cumplirá?
¿o no se cumplirá?”

FIN

Ejemplo: hacer un programa que calcule la siguiente función lógica: S=A·B+C·D

Solución:
Este ejemplo servirá al mismo tiempo como muestra del uso de los operadores lógicos, y como presentación

38 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

de una nueva función predefinida estándar en lenguaje C. Se trata de scanf( ), que nos servirá a partir de
ahora para introducir datos a través del teclado (sobre todo datos numéricos), de una forma sencilla (si se
deseara una entrada de datos realmente robusta, habría que descartar categóricamente el uso de esta función).
Básicamente, scanf( ) tiene esta forma que, aunque nos recuerda a la de printf( ), tiene sus particularidades:

scanf("%Carácter_de_tipo", &variable);

Entre las comillas no debemos meter nada que no sea el signo de porcentaje y el carácter de tipo, junto con el
carácter de modificador de tipo (opcional). Se pueden poner algunas cosas que permiten controlar un poco la
entrada que se almacena, pero se trata de una cuestión avanzada, y aquí no las necesitaremos. Si se desea
saber más, se puede recurrir a la ayuda del propio compilador Turbo C de Borland.
Siempre tendremos que poner el nombre de la variable en la que deseamos almacenar el dato recogido.
Justo antes de esa variable se debe añadir el signo &. El motivo es que, en realidad, debemos especificar la
dirección de la variable en memoria.

Carácter_de_tipo puede ser uno cualquiera de los que se exponen a continuación, dependiendo del tipo de
dato que queramos almacenar en la variable, pero justo delante puede (es opcional) tener alguno de los
caracteres de modificación de tipo que se muestran en la primera tabla de la página siguiente:

Carácter_de_tipo Entrada que se espera del usuario


d Entero con signo, en decimal
D Entero largo con signo, en decimal
o Entero sin signo, en octal
O Entero largo sin signo, en octal
x Entero sin signo, en hexadecimal
X Entero largo sin signo, en hexadecimal
i Entero con signo, en decimal, octal o hexadecimal
I Entero largo, en decimal, octal o hexadecimal
u Entero sin signo, en decimal
U Entero largo sin signo, en decimal
f, g, G Nº en coma flotante
E, e Nº en coma flotante, en notación científica
c Carácter
s Cadena de caracteres

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 39


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

Modificador de tipo ¿Qué significa?


h Entero corto
Entero largo (long), en caso de que Carácter_de_tipo indique un entero.
l
Doble precisión (double), en caso de que Carácter_de_tipo indique un float
L Doble precisión largo; válido sólo si Carácter_de_tipo indica un float

La información mostrada en las dos tablas anteriores es igualmente válida para utilizarla con la función
printf( ), de la que ya se han ido mostrando varios ejemplos a lo largo del texto. Además, para usar printf( )
(y para otras tareas dentro de la programación) es muy útil tener a mano los siguientes códigos ASCII,
conocidos como caracteres de control:

Carácter de control Valor hexadecimal Valor decimal Significado


\0 0x00 0 Nulo (NUL)
\a 0x07 7 Alarma (BEL)
\b 0x08 8 Retroceso de carácter (BS)
\t 0x09 9 Tabulador horizontal (HT)
\n 0x0A 10 Nueva línea (LF)
\v 0x0B 11 Tabulador vertical (VT)
\f 0x0C 12 Salta a nueva página (FF)
\r 0x0D 13 Retorno de carro (CR)
\" 0x22 34 Comillas dobles
\' 0x27 39 Comilla simple
\\ 0x5C 92 Barra invertida
\0nn nn (octal) nn (pasado a decimal) Número en octal
\xnn nn (hexadecimal) nn (pasado a decimal) Número en hexadecimal

Un último detalle respecto a scanf( ): para evitar problemas cuando introducimos por teclado algo que no se
espera esta función, es más que recomendable usar justo después otra función estándar llamada fflush(stdin),
Esto sirve para vaciar la memoria temporal (búfer) del teclado (flush the toilet, en inglés se usa para expresar
que se tira de la cadena, por lo que nos da una idea de lo que hace esta función).
Volviendo al ejercicio que ha motivado estas explicaciones, hay que hacer incapié en que las entradas (A, B,
C y D) del programa sólo pueden valer 0 o 1, dado que se trata de simular un circuito digital.
Dado que queremos utilizar la función scanf( ), nada impedirá al usuario escribir un número mayor que 1.
Para simplificar las cosas, si eso ocurre, forzaremos el valor para que sea un 1, mientras que si es un 0, lo
dejaremos como está.

40 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

Vamos a necesitar la siguiente Lista de variables:


Entradas:
a, b, c, d: Enteros cortos sin signo.
Almacenarán el valor (0 o 1) que introduzca el usuario para cada entrada.
Salida:
s: Entero corto sin signo.
Almacenará el resultado final de la función digital simulada.
Otras:
aux: Entero corto sin signo.
Variable auxiliar que guardará un estado lógico intermedio entre las entradas y la salida.

El diagrama de flujo del programa será el siguiente, y a su derecha se muestra el código del programa
resultante:
// Fichero: EJEMP16.C
EJEMP16 // Objetivo: Simular una función lógica.
// Programador: Miguel Ángel García M.
// Fecha: 19-2-2007
“Introducir valores de entrada (0 o 1)” // Versión: 1.0
Almacenarlos en las variables
a, b, c, d
# include <stdio.h>
# include <conio.h>
No
a>1
int main (){
Sí int a, b, c, d, // Entradas lógicas
a←1 s, // Salida lógica
aux; // Estado intermedio

No clrscr();
b>1
printf("Simulación de la función ");
Sí printf("S = A·B+C·D\n");
b←1 printf("Introduce valor (0 o 1)\n");
printf("\nValor de A: ");
scanf("%ui", &a);
No fflush(stdin);
c >1 printf("\nValor de B: ");
Sí scanf("%ui", &b);
fflush(stdin);
c←1
printf("\nValor de C: ");
scanf("%ui", &c);
fflush(stdin);
No
d>1 printf("\nValor de D: ");
Sí scanf("%ui", &d);
fflush(stdin);
d←1 if(a>1)
a= 1;
if(b>1)
s ← a AND b b= 1;
if(c>1)
aux ← c AND d c= 1;
if(d>1)
s ← s OR aux
d= 1;
s= a&b;
aux= c&d;
“La salida de la función es “ s s= s|aux;
printf("\nSalida función: S =%i", s);
FIN return 0;
}

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 41


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

Este programa se podría hacer también (y sería mejor) recogiendo un único carácter con getch( ), e
ignorando todas aquellas pulsaciones que no correspondieran a las teclas '0' o '1'. Después habría que
convertir esos símbolos (recordemos que son caracteres) en los números 0 o 1 respectivamente. Un método
inmediato para hacer esta conversión consiste en restar al carácter tecleado el carácter '0'. Por ejemplo:

int numero;
char tecla= '4';

numero= tecla – '0'; // Ahora la variable numero contiene el valor numérico 4

La explicación es muy simple: el valor numérico del símbolo ASCII del '0' es 48 y el del símbolo del '4' es
52. Por tanto, si restamos '4' – '0' , en realidad estamos restando 52 – 48, que sabemos que es precisamente 4.

Se deja como ejercicio para el alumno la modificación del programa EJEMP16, de manera que use la
función getch( ) en vez de scanf( ). Llamaremos EJEMP16B al programa resultante.

Resulta interesante hacer hincapié en la diferencia que existe entre el operador ! y el operador ~ ( tilde). Si
bien ambos se emplean como negación, el primero se limita a considerar falso (valor 0) todo aquello que sea
cierto (valor distinto de 0) y a la inversa; por el contrario, el operador tilde invierte bit a bit el valor binario
de un número. Veámoslo con un ejemplo:

// Fichero: EJEMP17.C
// Objetivo: Mostrar la diferencia entre los operadores ! y ~
// Programador: Miguel Ángel García Marcos
// Fecha: 20-2-2007
// Versión: 1.0

# include <stdio.h> // Fichero de cabecera necesario para printf( )


# include <conio.h> // Fichero de cabecera necesario para clrscr( )

int main ( ){
unsigned char num= 132,
inver1,
inver2;

clrscr();
printf("Valor original: %u\n", num);
inver1= !num;
inver2= ~num;
printf("\nNegado con !: %u\n", inver1); // inver1 vale 0
printf("\nNegado con ~: %u", inver2); // inver2 vale 123
return 0;
}

Esta misma diferencia se encuentra entre los operadores && y &, y entre los operadores || y |.

42 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

C) Operadores de asignación:
Este tipo de operadores no suelen utilizarse dentro de condiciones, aunque puede hacerse. Sin embargo, son
imprescindibles en cualquier lenguaje de programación, por lo que se les va a dedicar ahora un espacio, y de
esta forma se podrán usar de aquí en adelante con mayor conocimiento.
Los operadores de asignación transfieren un dato a una variable o a una constante.
Este dato puede escribirse de forma literal en el código:
valor = 23;
O bien, puede estar contenido previamente en otra variable:
nuevoValor = valor;
Estos son los operadores de asignación que soporta el lenguaje C:

(Nota: cuando un operador lo formen dos o tres caracteres, éstos deben escribirse sin espacios entre medias.)

Operador Ejemplo Significado


= Asignación simple.
−− c−− Decrementa c en una unidad.
++ c ++ Incrementa c en una unidad.
+= c+=4 Incrementa c en 4 unidades.
−= c−=4 Decrementa c en 4 unidades.
*= c*=4 Modifica c multiplicándolo por 4.
/= c/=4 Ahora c contendrá el cociente de dividir c entre 4.
%= c%=4 Ahora c contendrá el resto de dividir c entre 4.
Ahora c contendrá el resultado de desplazar
<<= c <<= 4
4 bits a la izquierda a la propia variable c.
Ahora c contendrá el resultado de desplazar
>>= c >>= 4
4 bits a la derecha a la propia variable c.
Se hace la operación AND
&= c&=4 entre los bits de c y los del valor 4.
El resultado se almacena en c.
Se hace la operación OR
|= c|=4 entre los bits de c y los del valor 4.
El resultado se almacena en c.
Se hace la operación XOR
^= c^=4 entre los bits de c y los del valor 4.
El resultado se almacena en c.

// Fichero: EJEMP18.C
// Objetivo: Mostrar el uso de algunos operadores de asignación.
// Programador: Miguel Ángel García Marcos
// Fecha: 19-2-2007
// Versión: 1.0

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 43


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

#include <stdio.h>

int main(){
int valor, prueba; // Así se puede declarar más de una variable del
//mismo tipo en una única sentencia.
valor= 3;
printf("\n\n\n");
// El valor de la variable valor ya ha sido definido,
//pero el de la variable prueba todavía es aleatorio:
printf("valor= %d, prueba= %d \n", valor, prueba); // Muestra 3, ?
valor--;
printf("valor= %d \n", valor); // Muestra 2
valor++;
printf("valor= %d, valor= %d \n", valor++, valor); // Muestra 3, 4
prueba= valor+30;
printf("valor= %d, prueba= %d \n", valor, prueba); // Muestra 4, 34
printf("El cociente de prueba/valor es: %d \n", prueba/valor);//Muestra 8
//Esto demostrará que en la sentencia anterior no hay asignación:
printf("valor= %d, prueba= %d \n", valor, prueba); // Muestra 4, 34
printf("El resto de prueba/valor es: %d \n", prueba%valor); // Muestra 2
//Esto demuestra que en la sentencia anterior tampoco se asigna nada:
printf("valor= %d, prueba= %d", valor, prueba); // Muestra 4, 34
return 0;
}

D) Prioridad entre operadores:


Cuando en una expresión aparecen varios operadores distintos, el resultado final de esa expresión puede
variar dependiendo del modo en que se escriba. Esto es así porque unos operadores tienen prioridad sobre
otros, del mismo modo que ocurre cuando se hace una operación aritmética. Por ejemplo, no es lo mismo:
3 + 2 · 4 que (3 + 2) · 4. En el primer caso obtenemos 11, y en el segundo el resultado es 20.
En esta tabla se muestran todos los operadores soportados por el lenguaje C, ordenados de mayor a menor
prioridad (algunos de estos operadores se estudiarán en temas siguientes):

PRIORIDAD DE EJECUCIÓN DE LOS OPERADORES EN LENGUAJE C


Tipo de operadores Operadores Asociatividad
De expresión () : > [ ] . − De izquierda a derecha
Unitarios − ~ ! * & ++ − − sizeof De derecha a izquierda
Multiplicativos * / % De izquierda a derecha
Aditivos + − De izquierda a derecha
De movimiento de bits >> << De izquierda a derecha
Relacionales < <= > >= = = != De izquierda a derecha
AND binario & De izquierda a derecha
XOR binario ^ De izquierda a derecha
OR binario | De izquierda a derecha
AND lógico && De izquierda a derecha

44 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

OR lógico || De izquierda a derecha


Condicionales ?: De derecha a izquierda
De asignación = *= /= %= += −= <<= >>= &= |= ^ = De derecha a izquierda
Evaluación secuencial , De izquierda a derecha

Dentro de una expresión que contenga varios operadores de la misma prioridad (en la tabla estarán en la
misma fila), se ejecutarán de izquierda a derecha.
Siempre se evalúan primero las expresiones que se encuentren contenidas entre paréntesis. Si se anidan
varios paréntesis (es decir, se ponen unos dentro de otros), entonces se empiezan evaluando las expresiones
que estén en los paréntesis más internos y se continúa hacia los exteriores.
Debido a lo anterior, si alguna vez una expresión puede presentarnos dudas acerca de cómo la evaluará el
compilador, lo más sencillo es encerrar entre paréntesis aquellas partes que se desea que se evalúen antes.

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 45


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

46 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

Tema 4. Control del flujo del programa (2)

4.1 Introducción
El tema anterior ha estado centrado principalmente en las estructuras básicas de selección; mediante ellas
sólo era posible elegir entre un máximo de dos opciones. En este tema abordaremos las estructuras de control
del flujo del programa que nos permitirán seleccionar una de entre más de dos opciones. Se trata de la
estructura if...else if... (que es simplemente una ampliación de if...else) y de la estructura switch...case.

4.2 Estructura if...else if...


Recordemos un momento el programa EJEMP13, en la página 35. En aquella ocasión se usaba la estructura
if, y de esta forma, el hecho de que una condición fuese cierta no impedía que se evaluasen las condiciones
siguientes. Por eso se mostraba más de un mensaje por la pantalla.
Veamos ahora este otro ejemplo, intentando predecir lo que aparecerá por pantalla y dibujando su diagrama
de flujo antes de escribirlo en el ordenador:

// Fichero: EJEMP19.C
// Objetivo: Mostrar el uso de la estructura if...else...if...
// Programador: Miguel Ángel García Marcos
// Fecha: 20-2-2007
// Versión: 1.0

# include <stdio.h>

int main( ) {
int numero;

numero= 10;
printf("\n\n");
if(numero==11)
printf("El número es 11 \n");
else if(numero==10)
printf("El número es 10 \n");
else if(numero<=15)
printf("Es menor o igual a 15 \n");
else if(numero!=10)
printf("No es 10 \n");
else
printf("¡Pues vaya número más raro!");
return 0;
}

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 47


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

Ahora se muestra siempre uno y sólo uno de los mensajes, independientemente del valor que asignemos a la
variable numero al principio del programa. Quizás lo entendamos mejor al obtener su diagrama de flujo:

EJEMP19

numero ← 10

No (else)
numero = 11

Sí No (else)
numero = 10

No (else)
numero ≤ 15


No (else)
numero ≠ 10

“El número es 11” “El número es 10” “El número ≤ 15” “El número no es 10” “Vaya número más raro”

FIN

Como vemos en el diagrama, resulta del todo imposible alcanzar el final del programa sin pasar por una caja
de mensaje. También apreciamos que, en cuanto pasamos por una cualquiera de esas cajas de mensaje, ya no
resulta posible dirigirse hacia otra de estas cajas; es decir: siempre se muestra uno y sólo uno de los
mensajes.
Este "efecto", que parece trivial, se llama técnicamente completitud de la condición. Significa que las
condiciones impuestas abarcan todos los casos posibles. En este ejemplo existe una gran redundancia, pero
para que lo entendamos mejor, fijémonos en este otro ejemplo:

if (numero < 10)


printf("El número es menor que 10");
else
printf("El número es mayor o igual que 10");

Resulta obvio que cualquier número debe ser, o bien menor que 10, o bien mayor, o bien igual; de este modo
están contemplados todos los casos posibles.
Lo mismo ocurre a continuación, aunque ahora se distinguen los tres casos de forma separada:

if (numero < 10)


printf("El número es menor que 10");
else if (numero > 10)
printf("El número es mayor que 10");
else
printf("El número es 10");

48 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

El hecho de poner un else al final, permite recoger cualquier caso no contemplado con las condiciones
anteriores. Basta con que recordemos que else, en inglés, podemos traducirlo como "y si no...", que en esta
situación final podríamos entenderlo como "y para todos los demás casos..."
Sin embargo, si no ponemos else al final, podríamos obtener esto:

if (numero < 10)


printf("El número es menor que 10");
else if (numero == 10)
printf("El número es 10");

resulta que ahora, cuando el número sea mayor que 10, el programa no llevará a cabo tarea específica alguna,
sino que se continúa la ejecución por un camino que vuelve a ser común para todos los valores de la variable
numero.
Tal vez eso esté previsto, pero si no es así, nos encontramos con que el programa podría fallar, o funcionar
de un modo totalmente inesperado.
La conclusión de todo esto es que siempre debemos prever la completitud de las condiciones, o lo que es lo
mismo, debemos tener en cuenta todos los casos posibles para cada situación.

4.3 Estructura switch...case


Se utiliza, al igual que if...else...if..., cuando hay más de dos bloques alternativos.
Empecemos viendo un sencillo ejemplo de uso de esta estructura:
// Fichero: EJEMP20.C
// Objetivo: Mostrar la sintaxis de la extructura switch...case
// Programador: Miguel Ángel García Marcos
// Fecha: 20-2-2007
// Versión: 1.0

#include <stdio.h> // Fichero de cabecera necesario para printf( )


#include <conio.h> // Fichero de cabecera necesario para getch( )

int main(){
char tecla;

printf("\n\n Pulsa la tecla A. \n");


tecla= getch();
switch (tecla){
case 'A':
printf("Has presionado la tecla A mayúscula.\n");
break;
case 'a':
printf("Has presionado la tecla a minúscula\n");
break;
default:
printf("No has presionado ni A, ni a.\n");
}
return 0;
}

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 49


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

En el diagrama de flujo equivalente podemos ver que se ha logrado la completitud de la condición, es decir,
se han previsto todos los casos posibles que se pueden dar al pulsar una tecla.

EJEMP20

“Pulsa una tecla”

tecla ← desde teclado

¿tecla?

= 'A' = 'a' Otros

“Has pulsado 'A'” “Has pulsado 'a'” “No pulsaste ni 'A', ni 'a'”

Espera una tecla

FIN

La estructura switch...case funciona del modo siguiente:


1.- Al llegar a switch, se evalúa el valor de la variable o expresión que se encuentre encerrada entre los
paréntesis. El resultado obtenido debe ser obligatoriamente un número entero (tipos char, int, long, etc.).
2.- El control del programa se transfiere a la sentencia cuya etiqueta (valor de case) coincida con el valor
obtenido en el paso 1. Las etiquetas también deben ser un valor entero (incluyendo el tipo char). Además, las
etiquetas deben ser constantes, o expresiones formadas únicamente por constantes.
3.- A partir de ahí, el programa continúa ejecutando sentencia a sentencia, hasta que encuentre una
instrucción break (o el final de toda la estructura switch). Esto es importante, porque significa que no se
detiene simplemente por encontrar una nueva etiqueta, si no encuentra ningún break.
4.- Si no se encuentra ninguna etiqueta con el valor obtenido en el paso 1, el control se traspasa a la sentencia
etiquetada default, si existe, puesto que default es opcional.
En caso contrario, el control se traslada a la instrucción inmediatamente posterior a la estructura
switch...case.
5.- La etiqueta default permite obtener la completitud de la condición, puesto que engloba a todos los casos
no recogidos por las etiquetas previas. Por este motivo, debe ser la última etiqueta en aparecer dentro de la
estructura, aunque, como se ha dicho es opcional.

¿Cuándo emplear switch...case y cuando else...if?

50 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

A veces no se puede elegir. No se puede emplear switch...case cuando la elección esté basada en una
comparación de variables o expresiones de tipo real (float, double, o long double).
Tampoco conviene usar esta estructura si la variable puede estar comprendida entre un cierto rango. Por
ejemplo, es muy sencillo escribir:
if (entero > 2 && entero < 1000)
pero intentar cubrir esta posibilidad con un switch...case implicaría teclear etiquetas case para todos y cada
uno de los enteros existentes desde 3 hasta 999.
Sin embargo, en general, switch...case es más eficiente en la ejecución del programa, y ocupa menos código.
Además, es más fácil leer un programa con switch...case que con if...else...if...
En resumen: a igualdad de condiciones, es preferible usar switch...case.

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 51


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

52 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

Tema 5. Control del flujo del programa (3)

5.1 Introducción
Para completar el estudio de las estructuras de control del flujo del programa, nos faltan, tal y como se
anunció al comienzo del tema 3, las estructuras de repetición o iteración.
Hasta ahora nos resultaba imposible hacer que el flujo del programa retrocediera para ejecutar una
instrucción anterior en el código de ese programa. Precisamente eso es lo que nos van a permitir las
estructuras de iteración. Mediante ellas podremos hacer que se ejecute una parte concreta del programa todas
las veces que deseemos, antes de proseguir con el resto del programa; y para lograr esto, evidentemente hay
que poder retroceder en el código.
Aunque en programación se pueden encontrar varias estructuras de repetición distintas, en realidad todas
ellas son equivalentes por completo. Esto quiere decir que con una sola de ellas, cualquiera que sea, se podría
hacer lo mismo que con las demás. Entonces, ¿para qué hay más de una? La respuesta es simple: cada una de
esas estructuras se amolda mejor a determinadas situaciones que se pueden encontrar en las tareas que deben
realizar los programas. De este modo se pueden escribir los programas con más facilidad y rapidez usando la
estructura de repetición que mejor se adapte a cada caso.
En concreto, en lenguaje C disponemos de estas tres sentencias para realizar bucles:
for (...) {...}
do {...} while (...)
while (...) {...}
Algo que hay que tener muy presente cada vez que queramos repetir una o más instrucciones, es asegurarnos
de que ese bucle no se repetirá infinitamente, sino que terminará por sí mismo en algún momento controlado
por el programador o el por el usuario. De no ser así habría que abortar el programa completo bruscamente, y
esto sería una señal inequívoca de que el programa está mal hecho.

5.2 Sentencia for (...)


Se usa cuando conocemos de antemano el número de veces que debe repetirse el bucle de instrucciones.
Utiliza un contador para comprobar si se ha alcanzado el número de repeticiones deseado. Ese contador debe
ser una variable de tipo entero.

En la misma instrucción (y normalmente en la misma línea de texto) se realizan tres tareas:

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 53


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

• Se inicializa el contador.
• Se comprueba (con la condición adecuada) si se ha alcanzado el número de repeticiones máximo.
• Se actualiza el contador, incrementándolo o decrementándolo.
Estas tres cosas se separan mediante un punto y coma, y todas juntas se encierran entre paréntesis.
No obstante, la sintaxis del C es enormemente flexible, y permite que en cada uno de los tres apartados del
paréntesis se haga cualquier otra tarea. Sin embargo, lo más aconsejable es atenerse a la norma básica, y usar
cada apartado para lo que se acaba de mencionar.
Veremos que de un modo u otro esas tres tareas son las que hay que llevar a cabo para cualquier bucle que
queramos hacer en el programa, y no sólo cuando queramos controlarlo mediante for (...).
El diagrama de flujo básico de una sentencia for (...) sería el siguiente:

Bucle for

contador ← valor_inicial

No
contador < máximo

BLOQUE
DE
SENTENCIAS

(Cualquier cosa)

contador ← contador + 1

Fin del bucle


(continúa el
programa)

El bucle for (...) funciona del siguiente modo:


• La primera expresión del paréntesis (en el gráfico: contador ← valor_inicial) sólo se realiza una vez al
principio, y no vuelve a ejecutarse.
• La segunda expresión del paréntesis debería ser siempre una condición. El bucle se ejecutará mientras
esa condición sea cierta, y terminará cuando sea falsa. Además hay que hacer hincapié en que siempre
se va a comprobar esta condición antes de ejecutar las sentencias del bucle, y no después. Dicho de
otra forma: la decisión de dar cada vuelta al bucle se toma antes de atravesarlo (podría no entrarse en él).
• A continuación se realizarán todas aquellas tareas que deseemos que se repitan. Si se trata de más de una
instrucción, debemos encerrarlas entre llaves, para que el compilador entienda que se trata de un bloque
de instrucciones. Aquí podemos incluso meter un nuevo bucle anidado.
• La tercera expresión del paréntesis (en el gráfico: contador ← contador + 1) debe servir para poner un

54 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

medio que permita que el bucle no se repita indefinidamente. Lo habitual es usar un contador, y aquí
actualizaremos su valor, para conseguir que en algún momento la condición de entrada al bucle sea falsa.

Con estos ejemplos se verá con más claridad el uso y funcionamiento de for (...) en el lenguaje C:
EJEMP21 // Fichero: EJEMP21.C
// Objetivo: Uso básico del bucle for(...).
// Muestra una lista con todos los
numero ← 20 // números del 20 al 25.
// Programador: Miguel Ángel García Marcos
// Fecha: 26-2-2007
// Versión: 1.0
No
numero < 26
# include <stdio.h>

# include <conio.h>

int main(){
Muestra el valor de numero
y salta de línea int numero;

printf("\n\n");
for(numero=20; numero<=25; numero+=1)
numero ← numero + 1
printf("numero = %d\n", numero);
getch();
Fin
return 0;
}

En el ejemplo siguiente se mostrará un pequeño listado (sin demasiada utilidad) de 3 filas y 2 columnas. El
algoritmo que realiza esta tarea puede ser como sigue:

EJEMP22

fila ← 1
columna ← 1

No
fila < 10

Muestra el valor de fila y


de columna, y salta de línea

fila ← fila * 3
columna ← columna * 10

Fin

En este ejemplo se va a aprovechar para mostrar cómo se pueden utilizar los tres campos de la instrucción for
(...), que van entre paréntesis, para escribir más de una sentencia en cada uno. No obstante, como ya se ha
dicho antes, es preferible no usar esta posibilidad que brinda el lenguaje C, pues resulta menos claro.

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 55


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

Veamos el código equivalente al diagrama de flujo anterior:

// Fichero: EJEMP22.C
// Objetivo: Ejemplo de uso del bucle for(...).
// Muestra un pequeño listado de 3 filas y 2 columnas.
// Programador: Miguel Ángel García Marcos
// Fecha: 26-2-2007
// Versión: 1.0

# include <stdio.h> // Fichero de cabecera necesario para printf( )


# include <conio.h> // Fichero de cabecera necesario para getch( )

int main(){
int fila, columna;

printf("\n\n");
for(fila=1, columna=1; fila<10; fila*=3,columna*=10)
printf("fila= %d columna= %d\n", fila, columna);
getch();
return 0;
}

Lo mejor es hacer una asignación inicial a una variable, comparar el valor de esa variable, y modificar
finalmente el valor de esa variable para hacer que la condición sea falsa en algún momento. Así se ha hecho
en esta versión 1.1:
// Fichero: EJEMP22B.C
// Objetivo: Ejemplo de uso del bucle for(...)
// Muestra un pequeño listado de 3 filas y dos columnas.
// Programador: Miguel Ángel García Marcos
// Fecha: 26-2-2007
// Versión: 1.1

# include <stdio.h> // Fichero de cabecera necesario para printf( )


# include <conio.h> // Fichero de cabecera necesario para getch( )

int main(){
int fila, columna;

printf("\n\n");
columna= 1; <-- Esto tiene que ejecutarse 1 ÚNICA VEZ, antes de bucle, por eso no puede estar dentro del bucle.
for(fila=1; fila<10; fila*=3){<-- No se nos deben olvidar las llaves: el bucle incluye más de 1 instrucción.
printf("fila= %d columna= %d\n", fila, columna);
columna*=10;
} <-- Si hemos abierto la llave, tenemos que cerrarla al acabar el bloque de instrucciones, tabulando correctamente.
getch();
return 0;
}

El diagrama de flujo no se verá alterado en absoluto por escribir el código según la versión 1.0 o la 1.1. Esto
siempre será así, pues ya se dijo en el tema 1 que el diseño del algoritmo (mediante diagrama de flujo o
mediante pseudocódigo) es totalmente independiente del lenguaje de programación con el que se escriba
finalmente el programa.

56 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

5.3 Sentencia while (...)


Produce una estructura casi idéntica a la del bucle for (...). Esto significa que el diagrama de flujo podría no
cambiar en absoluto por la decisión de usar una sentencia for (...) o una while (...). De hecho, ambas
sentencias se pueden intercambiar en cualquier programa sin demasiados problemas. Entonces, ¿cómo
sabemos cuál debemos usar en cada caso? Muy sencillo:
– Cuando conozcamos de antemano el número de repeticiones que necesitamos, emplearemos for (...).
– En caso contrario, optaremos por while (...).
Al igual que ocurre con el bucle for (...), debido a que la condición se evalúa al principio, es posible que el
bloque de instrucciones que contiene no se ejecute ni una sola vez.
While, en inglés, significa "mientras". Esto explica el funcionamiento de esta sentencia:
• Mientras la condición que va entre paréntesis sea cierta, se ejecuta el bloque de instrucciones que va
a continuación.
• Cuando la condición deja de cumplirse, se termina el bucle, y se continúa con la siguiente
instrucción del programa.
Debido a que usaremos while(...) cuando no conozcamos previamente cuántas repeticiones se van a producir,
no suele tener sentido hablar de una variable contador, como ocurría con for (...). Éste es el motivo por el que
el diagrama de flujo básico de while (...) aparece algo distinto al de for (...). Sin embargo, no se nos tiene que
olvidar nunca que hay que asegurarse de que en algún momento la condición de entrada al bucle debe ser
falsa, para evitar caer en un bucle infinito . Y esto, por fuerza, nos obliga a poner, dentro de la parte que
se repite, algo que modifique el valor de una o más variables que intervengan en la condición de entrada al
bucle.

Bucle while

Falso
condición

Verdadero

BLOQUE
DE
SENTENCIAS

(Cualquier cosa)

Fin del bucle


(continúa el
programa)

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 57


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

Veamos el uso de while (...) con el siguiente ejemplo simple:

EJEMP23

numerosPares ← 0

No
numerosPares < 12

Muestra el valor de
numerosPares,
y salta de línea

numerosPares ← numerosPares + 2

Fin

// Fichero: EJEMP23.C
// Objetivo: Lista de los 10 primeros números pares usando while()
// Programador: Miguel Ángel García Marcos
// Fecha: 27-2-2007
// Versión: 1.0

#include <stdio.h>

int main(){
int numerosPares= 0;

printf("\n\n");
while(numerosPares < 12){
printf("numerosPares=%d\n",numerosPares);
numerosPares= numerosPares + 2;
}
return 0;
}

Antes se ha comentado que las sentencias for (...) y while (...) son perfectamente intercambiables. Para
demostrarlo está el ejemplo que aparece a continuación. En su diagrama de flujo observamos que se
encuentra formado por dos partes absolutamente idénticas. Esto quiere decir que vamos a repetir la misma
tarea dos veces. Sin embargo, en el código, usaremos la estructura for (...) para implementar la primera parte,
y la estructura while (...) para implementar la segunda parte. De este modo aprenderemos el modo de
convertir un for (...) en un while (...) y viceversa.

58 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

EJEMP24

Bucle cantidad ← 0
for (...)

No
cantidad < 10

Muestra el valor de
cantidad,
y salta de línea

cantidad ← cantidad + 1

Bucle
while (...) cantidad ← 0

No
cantidad < 10

Muestra el valor de
cantidad,
y salta de línea

cantidad ← cantidad + 1

Fin

// Fichero: EJEMP24.C
// Objetivo: Comparar for() con while() y aprender cómo intercambiarlos
// Programador: Miguel Ángel García Marcos
// Fecha: 27-2-2007
// Versión: 1.0
#include <stdio.h>
int main(){
int cantidad;
printf("\n\nCON EL BUCLE for(...){...}\n");
for(cantidad= 0; cantidad < 10; cantidad++)
printf("cantidad= %d\n", cantidad);
printf("\nCON EL BUCLE while(...){...}\n");
cantidad= 0;
while(cantidad < 10){
printf("cantidad= %d\n", cantidad);
cantidad++;
}
return 0;
}

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 59


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

5.4 Sentencia do ... while (...)


Es muy parecida a la anterior; pero ahora, la condición se comprueba al final. Esto implica que siempre se
va a ejecutar el bloque de instrucciones del bucle al menos una vez.
Precisamente, esa diferencia que existe en while (...) y do...while (...) es la que nos hará decidirnos por una u
otra en cada caso. No obstante, es fácil convertir una estructura en la otra y viceversa.

Éste es el diagrama de flujo básico de esta estructura de control:

Bucle do-while

BLOQUE
DE
SENTENCIAS

(Cualquier cosa)

condición
Verdadero
Falso

Fin del bucle


(continúa el
programa)

Para ilustrar el uso de esta sentencia en lenguaje C, usaremos el sencillo ejemplo que sigue:

EJEMP25 // Fichero: EJEMP25.C


// Objetivo: Mostrar funcionamiento de do...while(...)
// Programador: Miguel Ángel García Marcos
// Fecha: 1-3-2007
“Dime tu edad” // Versión: 1.0

#include <stdio.h>
edad ← Desde teclado
int main(){
int edad;
Visualiza el valor de edad
do{
printf("\nDame tu edad\n");
scanf("%d", &edad);
Sí fflush(stdin);
edad ≠ 0
printf("Tu edad es: %d\n\n", edad);
No }while(edad!=0);
return 0;
Fin }

60 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

5.5 Ejercicios de repaso


Con los siguientes ejercicios se pone en práctica todo lo aprendido hasta el momento. Para hacerlos, tal y
como se explicó en el tema 1, primero debe pensarse en el análisis del problema, haciendo una lista de
símbolos; a continuación se desarrolla el algoritmo, dibujando el diagrama de flujo que describa el
funcionamiento del programa; y por último se codificará en lenguaje C, escribiendo los comentarios de la
cabecera y todos aquellos que sean necesarios para aclarar el funcionamiento del programa.
Los nombres de los ficheros serán EJER01.C, EJER02.C, etc.

Ejercicio 1:
Mostrar la tabla de multiplicar del 5 en forma de columna. En pantalla deberá aparecer del siguiente modo:
5x0=0
5x1=5
5 x 2 = 10
.
.
.
5 x 10 = 50

Hacerlo usando la sentencia for (...).

Ejercicio 2:
Igual que el Ejercicio 1, pero usando la sentencia while (...).

Ejercicio 3:
Igual que el Ejercicio 1, pero usando la sentencia do ... while (...).

Ejercicio 4:
Mostrar las tablas de multiplicar del 1 al 5 en cinco columnas (una para cada tabla), usando for (...).
Con este ejercicio se pretende que el alumno practique el uso de bucles anidados (un bucle metido dentro de
otro).
En pantalla debe aparecer algo similar a lo siguiente:
1x0=0 2x0=0 3x0=0 4x0=0 5x0=0
1x1=1 2x1=2 3x1=3 4x1=4 5x1=5
. . . . .
. . . . .
. . . . .
1 x 10 = 10 2 x 10 = 20 3 x 10 = 30 4 x 10 = 40 5 x 10 = 50

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 61


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

Ejercicio 5:
Igual que el ejercicio 4, pero usando while (...).

Ejercicio 6:
Igual que el ejercicio 4, pero usando do ... while (...).

Ejercicio 7:
Visualizar la tabla del código ASCII extendido (0 – 255). Dado que no cabe todo en una pantalla, se hará una
pausa cada 25 filas de la tabla, continuando el listado cuando se pulse cualquier tecla.
Existen los siguientes códigos especiales que no son imprimibles, y que estropean el formato de la tabla si
nos los controlamos. Estos códigos deben sustituirse por su nombre estándar abreviado:
0: NUL 7: BEL 8: BS 9: HT 10: LF
11: VT 12: FF 13: CR 26: SUB

Ejercicio 8:
Presentar por pantalla un triángulo rectángulo relleno con el carácter 'A'.
La figura tendrá un número de filas igual que el de columnas. Este valor lo indicará el usuario en tiempo de
ejecución, y deberá estar comprendido entre 1 y 20. El programa controlará el valor de esa entrada y lo
ajustará si es necesario.
Ejemplo de salida con 6 filas:
A
AA
AAA
AAAA
AAAAA
AAAAAA

Ejercicio 9:
Mostrar un triángulo rectángulo como el del ejercicio 8, pero esta vez el "relleno" será como se presenta en
este ejemplo de salida para 6 filas:
F
FE
FED
FEDC
FEDCB
FEDCBA <--- El último carácter siempre debe ser 'A'
Como antes, el usuario decidirá cuántas filas desea visualizar y el programa controlará ese dato.

62 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

Ejercicio 10:
Visualizar un triángulo isósceles como el que se presenta en el ejemplo de salida para 5 filas:
*
***
*****
*******
*********

Al igual que en los dos ejercicios anteriores, el usuario decidirá cuántas filas desea que aparezcan, y el
programa ajustará este valor si se sale de los límites 1 – 20.

Ejercicio 11:
Mostrar por pantalla un triángulo isósceles como el que se presenta en el ejemplo de salida para 5 filas:
*
* *
* *
* *
*********

Al igual que en los casos anteriores, el usuario decidirá cuántas filas desea que aparezcan, y el programa
ajustará este valor si se sale de los límites 1 – 20.
Dado que este ejercicio es algo más complejo que los anteriores, conviene tener en cuenta las siguientes
observaciones:
– Después de último asterisco de cada línea, hay que pasar a la línea siguiente: printf("*\n");
– La última línea la consideraremos especial, y la haremos fuera del bucle principal, mediante un bucle
para ella sola que imprima todos sus asteriscos.
– En todas las "fórmulas" se buscará relacionar las columnas en las que debe dibujarse un asterisco con el
número total de filas y con la fila actual.

Ejercicio 12:
Hacer un programa que pida al usuario un número comprendido entre 1 y 10 (ambos incluidos). A
continuación, el ordenador tratará de "adivinarlo" (en realidad no hay nada que adivinar, pues el usuario le ha
dado el número previamente). Para ello probará con un valor que se encuentre en mitad de la lista. Si no es el
que ha introducido el usuario, el programa preguntará si el número dado era mayor. Si era mayor, buscará de
nuevo el valor entre los números de la mitad superior de la lista y si no, lo buscará entre los números de la
mitad inferior. De nuevo preguntará al usuario, y si no ha "acertado", repetirá el proceso con las mitades
sucesivas. Cuando lo encuentre mostrará el mensaje "ACERTÉ".
El programa debe incluir controles para las respuestas dadas por el usuario. De esta forma, si el usuario mete
un número fuera del rango 1 – 10, el programa pedirá un nuevo valor al usuario.

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 63


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

Ejercicio 13:
Repetir el programa de ejemplo de la página 38, en el que se pedía calcular la siguiente función lógica:
S=A·B+C·D
En esta ocasión será obligatorio usar la función getch( ) para capturar los valores binarios que introduzca el
usuario por el teclado. Sin embargo, a diferencia de lo que se hizo cuando se planteó este problema como
ejemplo, ahora únicamente se admitirán los valores 0 y 1 como datos de entrada. También se admitirá la
pulsación de la tecla 'Escape', de forma que se pueda salir del programa en cualquier momento, sin esperar a
introducir todos los datos. Cualquier otra tecla que se pulse será ignorada, de modo que el programa
permanecerá en un bucle para cada dato de entrada, hasta que se pulse una de las tres teclas válidas
mencionadas.
Cuando la tecla pulsada sea 0 o 1 se visualizará su correspondiente carácter, mientras que en cualquier otro
caso no se mostrará la tecla pulsada; por eso se debe usar getch( ) y no getche( ).

64 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

Tema 6. Arrays y cadenas de caracteres

6.1 Introducción
En casi todos los lenguajes de programación (incluido el C), además de los tipos de datos básicos (enteros,
reales, etc.) que hemos visto, se dispone de tipos de datos más complejos, que están formados por múltiples
tipos básicos. Esto es lo que se conoce como tipos de datos estructurados.
Podemos encontrarnos tipos de datos estructurados de las siguientes clases:
– Arrays (también llamados arreglos, vectores, o matrices).
– Registros
– Tipos estructurados definidos por el usuario

Por el momento sólo vamos a estudiar los primeros, los arrays.


Hay lenguajes de programación que pueden manejar directamente las cadenas de caracteres, pues los
contemplan como un tipo de dato especial dentro de los estructurados. Sin embargo, el lenguaje C utiliza
arrays para gestionar las cadenas de caracteres, debido a que no soporta ese tipo de dato por sí mismo.

6.2 Los arrays


Un array es un conjunto de datos de un mismo tipo.
Los elementos de un array se identifican mediante uno o varios números que se llaman índices.
En ocasiones se denominan matrices, por la similitud que existe entre los arrays y estos elementos de
matemáticas. Al igual que las matrices, los arrays pueden ser de una sola dimensión (tienen una única fila de
elementos), de dos dimensiones (varias filas x varias columnas), de tres, etc.
Debido a que los arrays de más de dos dimensiones ocupan un tamaño desmesurado en memoria cuando son
de muchos elementos, casi no se usan. Por lo tanto, nos vamos a centrar sólo en los arrays unidimensionales
y bidimensionales.
Antes de usar un array, debe ser declarado; para ello hay que dar al compilador tres informaciones:
– Nombre del array.
– Número de elementos que contendrá ese array.
– Tipo de dato que corresponde a cada elemento (todos los elementos serán del mismo tipo).

De esta forma el compilador puede tomar la decisión acerca de cuánta memoria debe reservar para ese array.

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 65


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

Así, si deseamos declarar un array que contenga 7 números enteros (int), y queremos llamarlo pares,
haremos lo siguiente:
int pares[7];

Los valores en un array deben guardarse celdilla a celdilla, es decir, no se pueden almacenar todos los
valores que contendrá el array "de golpe".
La primera posición de un array, en lenguaje C, siempre se nombra con el índice 0.
Cuando queramos referirnos a la primera "casilla" del array anterior, para guardar en ella el valor 486 (por
ejemplo), lo haremos así:
pares[0] = 486;
Y cuando queramos guardar algo en la última posición de dicho array:
pares[6] = 128;
Esto significa que el valor del índice para la última posición de un array, en C, siempre será igual a su
tamaño (número de elementos declarados) menos 1.

Podemos imaginarnos este array gráficamente del siguiente modo:

Índice: 0 1 2 3 4 5 6

Contenido: 486 1324 2360 -252 30 18 128

Nombre del array: pares

Si ahora deseamos leer el valor que contiene la celdilla número 4 del array del ejemplo, lo podemos hacer de
esta forma:
num = pares[4];
Suponiendo que el array pares contiene lo que aparece como ejemplo en el gráfico, tras ejecutarse la
instrucción anterior, la variable num pasaría a tener el valor 30.

Como vemos, los arrays se manejan igual que las variables tradicionales, pero añadiendo el número de
celdilla (es decir, el índice) encerrado entre corchetes. De todos modos, conviene aclarar que, en lenguaje C,
si escribimos el nombre del array sin indicar un índice, entonces se entiende que nos estamos
refiriendo A LA DIRECCIÓN de su primera celdilla exclusivamente, y no al array entero . Por tanto,
estas dos cosas son equivalentes:
*pares = 24; // Al escribir * nos estamos refiriendo al contenido de pares[0]
pares[0] = 24;
En ambos casos estamos asignando el valor 24 a la primera celdilla del array.
Dado que el nombre del array, sin corchetes, se refiere a una dirección de memoria, y no al contenido de
dicha dirección, no podemos hacer lo siguiente, pues no tiene sentido:

66 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

pares = 24; // Recordemos que pares no es una variable normal, sino un array.
En este caso estaríamos intentando reubicar en memoria el array, pidiendo que empiece en la posición de
memoria número 24. Esto no nos lo va a permitir el compilador, pues es él, junto con el sistema operativo,
quien decide dónde se coloca cada dato en la memoria.
Por este motivo, es preferible acostumbrarse a escribir siempre el índice, para evitar confusiones.

En el ejemplo siguiente usaremos un array de enteros para almacenar 5 valores numéricos que irá
introduciendo el usuario. Posteriormente el programa calculará la media aritmética de esos 5 valores.
Además de fijarse en el manejo del array, conviene poner atención al uso que se hace de los comentarios
para "separar" cada parte del programa.

// Fichero: EJEMP26.C
// Objetivo: Ejemplo de uso de arrays.
// Calcula la media aritmética de varios valores dados por el usuario.
// Programador: Miguel Ángel García Marcos
// Fecha: 2-3-2007
// Versión: 1.0
# include <stdio.h>
# include <conio.h> // Fichero de cabecera necesario para clrscr( )

# define NVALORES 5 // Nº de valores que contendrá la muestra.

int main( ){
int muestra[NVALORES], // Array que contendrá todos los valores.
i; // Contador para manejar el índice del array.
float media; // Almacenará la media aritmética de los 5 valores dados.

clrscr();
// Información para el usuario:
printf("Este programa calcula la media aritmética de %d ", NVALORES);
printf("valores numéricos enteros.");
printf("\n\nEl usuario debe introducir cada uno de esos valores ");
printf("a medida\nque se le vayan pidiendo.\n\n");
printf("Después de teclear cada dato, se debe validar pulsando INTRO.\n");
// Entrada de datos:
for(i= 0; i < NVALORES; i++){
printf("\n\tIntroducir el valor número %d: ", i+1);
scanf("%d", &muestra[i]);
fflush(stdin);
}
// Cálculo de la media aritmética del contenido del array:
media= 0;
for(i= 0; i < NVALORES; i++){
media= media+muestra[i];
}
media= media / NVALORES;
// Presentación del resultado:
printf("\n\n\nLa media aritmética de los %d ", NVALORES);
printf("valores introducidos es: %1.2f", media);
return 0;
}

A continuación se muestra el diagrama de flujo correspondiente al código anterior, con la finalidad de que se

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 67


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

observe cómo se representa la manipulación de arrays en estos diagramas.


A la izquierda aparece el diagrama general del programa, en el que no se especifican detalles; tan sólo se
hace un bosquejo de lo que debe hacer el programa.
A la derecha se ha desarrollado el diagrama general, usando la técnica de refinamientos sucesivos.

EJEMP26 EJEMP26

NVALORES ← 5
InformaUsuario

Borra la pantalla.
Informa al usuario sobre
el uso del programa
TomaDatos

TomaDatos i ←0

Calculo

No
i < NVALORES


MuestraResultado
“Introduce el valor nº: “ i

Fin
muestra[i] ← dato desde el teclado

i ← i+1

Calculo media ← 0

i ←0

i < NVALORES
No

media ← media + muestra[i]

i ← i+1

“El valor medio es: “ media / NVALORES

Fin

68 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

6.3 Asegurar que no se sobrepasan los límites del array


Como ya se apuntó en un tema anterior, los compiladores de lenguaje C generan unos programas muy
optimizados, por lo que funcionan casi tan rápidos como si hubiesen sido escritos en ensamblador. Sin
embargo, para lograr esto, los compiladores de lenguaje C no hacen ninguna comprobación del uso de la
memoria que haya hecho el programador.
En el caso que nos ocupa, eso significa que podemos declarar un array de 10 enteros, pero después (por
error) intentar escribir más de 10 valores. Si esto ocurre, el compilador no nos lo advertirá, y generará el
programa ejecutable sin que nos percatemos del error cometido al programar. Sin embargo esto seguramente
tendrá consecuencias desastrosas cuando pongamos el programa en funcionamiento; puede ser que no ocurra
nada malo, pero lo más habitual es que el programa se comporte de forma anómala, e incluso que finalice
inesperadamente con un mensaje de error del mismo sistema operativo.
Si el código del programa intenta escribir un dato en una posición de memoria que no ha sido reservada
previamente, ese dato es muy probable que sobreescriba otros datos del propio programa, o incluso datos o
instrucciones de otro programa distinto.
Por tanto, al escribir un programa en lenguaje C, siempre será responsabilidad del programador hacer todas
las comprobaciones de contorno (es decir, de los límites de cada dato en memoria) que sean necesarias. Esto
es particularmente importante tenerlo en cuenta cuando se manejan arrays.

Esto sería un ejemplo de un programa que usa incorrectamente un array:


// Fichero: EJEMP27.C
int main ( ){
int array[10], i;

for (i= 0; i < 20; i ++)


array[i]= i; // Cuando i sea mayor que 9, se intentará escribir fuera
//de los límites del array.
for (i= 0; i < 20; i++)
printf("Dato en la posición %d del array: %d\n", i, array[i]);
return 0;
}

Una forma de evitar que nos suceda por descuido lo que en el ejemplo anterior, es utilizar constantes. Con
esta modificación, veamos cómo ahora es imposible que nos saltemos los límites del array sin darnos cuenta:
// Fichero: EJEMP27B.C
# define LIMITE 10

int main ( ){
int array[LIMITE], i;

for (i= 0; i < LIMITE; i ++)


array[i]= i; // Ahora es imposible que i valga más de 9 en este punto
for (i= 0; i < LIMITE; i++)
printf("Dato en la posición %d del array: %d\n", i, array[i]);
return 0;
}

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 69


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

Para poder hacer esto, lo más recomendable es "declarar" la constante mediante una directiva # define, pues
aunque se puede usar una constante declarada con la palabra reservada const en la declaración de un array,
hacer lo siguiente puede darnos algún problema usando el depurador:
const LIMITE= 10;
int array[LIMITE];

Esto se debe a que no sabrá el tamaño del arrray, y al intentar visualizarlo con el examinador (watch), no lo
veremos correctamente a no ser que nosotros le indiquemos cuántos elementos formar dicho array.

6.4 Cadenas de caracteres


Uno de los usos más habituales de los arrays en lenguaje C es el almacenamiento y manipulación de cadenas
de caracteres.
Una cadena de caracteres no es otra cosa que una sucesión de caracteres que se almacenan en posiciones de
memoria consecutivas. Con ello se pretende guardar una palabra, una frase, un párrafo, o un texto completo,
en memoria para que sean manipulados por el programa.
Muchos lenguajes de programación incluyen un tipo de dato especial para las cadenas de caracteres (también
llamadas strings, en inglés). Sin embargo éste no es el caso del C, por lo que hay que guardar las cadenas de
caracteres en arrays, y manipular éstos del mismo modo que se hace cuando almacenan números.
Por tanto, para declarar una cadena de caracteres en C, lo haremos declarando un array de caracteres. Por
ejemplo, así declaramos un array de caracteres llamado cadena, con capacidad para 20 símbolos del código
ASCII extendido:
char cadena[20]; // Reserva 20 bytes en memoria.
La declaración anterior permitiría almacenar una palabra o frase de 19 letras (u otros símbolos), pese a que se
ha declarado un array de 20 bytes. Esto es así porque en C, y en otros lenguajes de programación
importantes, como Java, todas las cadenas de caracteres deben obligatoriamente finalizar con el carácter
nulo (el símbolo 0 del código ASCII). Éste carácter lo representaremos habitualmente como ' \0' (lo
leeremos "barra cero"). El carácter nulo, igual que los restantes símbolos del código ASCII extendido ocupa
un byte, y tenemos que reservar espacio en el array para almacenarlo.
No es necesario que la cadena de caracteres almacenada ocupe todo el espacio reservado en el array.
Precisamente por esto se obliga a finalizar todas las cadenas con el carácter nulo; de modo que \0 se
considera el indicador de final de cadena. Dicho de otra manera: el tamaño efectivo de una cadena de
caracteres no lo impone el tamaño del array que la almacena.
Supongamos que, en el array de caracteres declarado anteriormente, almacenamos la frase "Esto es un
ejemplo". Esta frase tiene 18 caracteres; al añadir el carácter nulo tendremos 19 caracteres. De esta forma,
todavía nos queda 1 byte del array sin usar para nuestra cadena de caracteres. Sin embargo, este byte no
utilizado no es un hueco vacío, sino que deberá estar compuesto de 8 bit, como es lógico; y esos bits podrán
tener cualquier valor, que representará algún símbolo del código ASCII extendido, aunque no nos importa
cuál sea, por lo que podemos considerarlo como "basura".

70 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

De forma gráfica, el contenido de la memoria ocupada por el array cadena se verá así:

Nombre del array: cadena


Índice: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Contenido: E s t o e s u n e j e m p l o \0 ê

Carácter nulo: final de la cadena

Esto lo consideramos “basura”

6.5 Algunas funciones estándar para el manejo de cadenas en lenguaje C


6.5.1 gets( )
Con esta función podemos leer una cadena desde el teclado (su nombre es la abreviatura de get string).
Su formato general es
gets(nombre_del_array);
El nombre del array no incluirá los corchetes, sólo el nombre.
gets( ) seguirá leyendo caracteres desde el teclado hasta que se pulse intro. En ese momento guarda en el
array la cadena leída del teclado.
Algo muy importante, que debe ser tenido en cuenta, es que esta función no comprueba el contorno del array
que se le pasa como parámetro en la llamada. Si no se tiene cuidado, esto puede causar muchos problemas,
como se comentó en el apartado 6.3. Si se desea una entrada de datos robusta, la mejor opción es recurrir,
una vez más, a la función getch( ) y hacer una porción de programa que tome los caracteres uno a uno, los
compruebe, y en caso de aceptarlos, los coloque en la posición correcta del array después de comprobar que
no se sobrepasan los límites de éste.
Veamos el uso de gets( ) con este pequeño ejemplo:

// Fichero: EJEMP28.C
// Objetivo: Ejemplo de uso de la función gets( ) para leer una cadena.
// Programador: Miguel Ángel García Marcos
// Fecha: 24-4-2007
// Versión: 1.0

# include <stdio.h> // Éste es el fichero de cabecera necesario para gets( )

int main( ){
char cadena[80];

printf("Escribe una frase (máximo 79 caracteres): ");


gets(cadena);
printf("La frase escrita era: %s\n", cadena);
return 0;
}

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 71


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

Para comprobar un poco el funcionamiento de los arrays, y observar la "basura" de la que se hablaba en el
apartado 6.4 anterior, conviene ejecutar el programa paso a paso viendo como evoluciona el array mediante
un watch.
A continuación cambiaremos la declaración del array por lo siguiente:
char cadena[80]= "";
De este modo habremos inicializado el array con una cadena vacía. Lo que hace el compilador es colocar el
carácter nulo ('\0') en la posición 0 del array (Code::Blocks rellena también el resto del array con nulos). Éste
es el motivo por el que el depurador del entorno de desarrollo no muestra nada de la mencionada "basura".
Una vez que encuentra un carácter nulo, ya no visualiza más caracteres del array.

Ahora cambiaremos de nuevo la declaración del array con esta línea:


char cadena[80]= "Hola\0Adiós";
Debido a que ponemos el carácter nulo en medio, la palabra Adiós y todo lo que pueda existir después en
memoria hasta completar los 80 caracteres se considera "basura". Además Code::Blocks rellena todo el resto
del array con nulos después de cerrar las comillas de la inicialización.

6.5.2 strcpy( )
Se emplea para copiar el contenido de una cadena en otra cadena, es decir en otro array de caracteres (su
nombre es la abreviatura, en inglés, de string copy).
Su forma de uso es la siguiente:
strcpy(array_destino, array_origen);
Debido a que esta función no comprueba los límites de los arrays que recibe, el programador debe asegurarse
que el array_destino tiene al menos el tamaño del array_origen para que quepa completo al copiarlo.
Aquí va un pequeño ejemplo de uso de strcpy( ):
// Fichero: EJEMP29.C
// Objetivo: Ejemplo de uso de la función strcpy( ) para copiar una cadena.
// Programador: Miguel Ángel García Marcos
// Fecha: 24-4-2007
// Versión: 1.0

# include <stdio.h> // Fichero de cabecera necesario para printf( )


# include <string.h> // Fichero de cabecera necesario para strcpy( )

int main( ){
char frase[40], copia[40];

strcpy(frase, "Esto es un sencillo ejemplo");


printf("\nLa frase escrita en el array es: %s", frase);
strcpy(copia, frase);
printf("\nLa frase copiada es: %s", copia);
return 0;
}
Es conveniente ejecutarlo paso a paso, viendo cómo cambia el contenido del array frase[].

72 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

6.5.3 strcat( )
El nombre de esta función procede de la abreviación de las palabras inglesas string concatenation.
Traduciendo eso, queda claro que sirve para concatenar 2 cadenas de caracteres, es decir, para añadir una
cadena a continuación de otra existente.
Se usa del siguiente modo:
strcat(cadena1, cadena2);
Lo que hace es añadir cadena2 a continuación de cadena1.
El resultado quedará guardado en cadena1, lo que significa que cadena1 queda modificada.
Las dos cadenas iniciales deben finalizar con el carácter nulo (como es habitual).
strcat( ) quita el carácter nulo de la posición original de cadena1, por lo que, al final, sólo contendrá el
carácter nulo que corresponda tras haber añadido cadena2.
El programador debe asegurarse de que el array cadena1 tiene un tamaño suficiente para acoger también a
cadena2. De no ser así, los resultados podrían ser bastante desastrosos, pues strcat( ) no comprueba el
contorno de los arrays que le llegan.
Éste es un ejemplo sencillo del uso de esta función:

// Fichero: EJEMP30.C
// Objetivo: Ejemplo de uso de la función strcat( ) para añadir una cadena.
// Programador: Miguel Ángel García Marcos
// Fecha: 24-4-2007
// Versión: 1.0

# include <stdio.h> // Fichero de cabecera necesario para printf( )


# include <string.h> // Fichero de cabecera necesario para strcat( )

int main( ){
char frase1[60], frase2[30];

strcpy(frase1, "Esto es un sencillo ejemplo ");


strcpy(frase2, "de cómo se utiliza strcat.");
strcat(frase1, frase2);
printf("\nLa frase resultante es: %s", frase1);
return 0;
}

6.5.4 strcmp( )
Su nombre procede de abreviar las palabras inglesas string comparison.
Se utiliza para comparar dos cadenas de caracteres.
La forma que tiene de informar sobre la igualdad o no de las dos cadenas es devolviendo un número entero,
que puede ser recogido por el programador y aprovecharlo para decidir la siguiente acción que realizará el
programa. Su forma habitual es así:
iguales= strcmp(cadena1, cadena2);
Internamente, strcmp( ) "resta" cadena1 menos cadena2. En realidad va restando el primer carácter de

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 73


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

cadena1 menos el primer carácter de cadena2; si ambos son iguales (la resta ha dado 0), resta el segundo
carácter de cadena1 menos el segundo carácter de cadena2; así sucesivamente, hasta que encuentra que dos
caracteres que ocupan posiciones equivalentes son distintos, o hasta que llega al final de ambas cadenas sin
encontrar diferencias. Éstos son los 3 resultados posibles:
– Si las dos cadenas son iguales, devuelve 0. Por ejemplo, 'A' – 'A' = 0.
– Si cadena1 es mayor (lexicográficamente) que cadena2, devuelve un número positivo. Este número será
el resultado de la última resta realizada durante la comparación. Por ejemplo, 'h' – 'a' = 7.
– Si cadena1 es menor (lexicográficamente) que cadena2, devuelve un número negativo (el resultado de la
última resta). Por ejemplo, 'b' – 'g' = – 5 .
El primero de estos resultados nos indica que devuelve el valor 0. Esto lo podemos interpretar como un valor
booleano, de manera que, cuando ambas cadenas sean iguales, strcmp( ) devolverá falso.
Sin embargo, cuando las cadenas son distintas, strcmp( ) devuelve cierto, pues hemos de recordar que
cualquier valor distinto de 0 es interpretado como el valor cierto por el compilador.
En el siguiente ejemplo aprovecharemos la posibilidad de interpretar el valor devuelto como si fuese un
booleano:

// Fichero: EJEMP31.C
// Objetivo: Ejemplo de uso de la función strcmp( ) para comparar 2 cadenas.
// Programador: Miguel Ángel García Marcos
// Fecha: 24-4-2007
// Versión: 1.0

# include <stdio.h> // Fichero de cabecera necesario para printf( )


# include <conio.h> // Fichero de cabecera necesario para clrscr( )
# include <string.h> // Fichero de cabecera necesario para strcmp( )

int main( ){
char clave[80];

do{
clrscr();
printf("Teclea la contraseña (máximo 79 caracteres): ");
gets(clave);
}while(strcmp(clave, "acceso"));
printf("\n\nPuedes acceder al sistema");
return 0;
}

Ahora vamos a reescribir el programa, de modo que haga lo mismo, pero resulte algo más fácil de entender.

// Fichero: EJEMP31B.C
// Objetivo: Ejemplo de uso de la función strcmp( ) para comparar 2 cadenas.
// Programador: Miguel Ángel García Marcos
// Fecha: 24-4-2007
// Versión: 2.0

# include <stdio.h> // Fichero de cabecera necesario para printf( )


# include <conio.h> // Fichero de cabecera necesario para clrscr( )
# include <string.h> // Fichero de cabecera necesario para strcmp( )

74 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

int main( ){
char clave[15], intento[80];
int iguales= 0;

strcpy(clave, "acceso");
do{
clrscr();
if(iguales != 0)
printf("La contraseña es incorrecta\n\n");
printf("Teclea la contraseña (máximo 79 caracteres): ");
gets(intento);
iguales= strcmp(intento, clave);
}while(iguales != 0);
printf("\n\nPuedes acceder al sistema");
return 0;
}

Como de costumbre, es muy recomendable ejecutar paso a paso ambas versiones del programa, viendo cómo
evolucionan todas las variables que intervienen, para así comprender mejor su funcionamiento.

6.5.5 strlen( )
Traduciendo del inglés las palabras string length, que abreviadas forman el nombre de esta función,
entendemos que sirve para medir la longitud de una cadena.
Se llama a esta función de la siguiente forma:
longitud= strlen(cadena);
donde longitud debe ser un entero, y cadena un array de caracteres.
En la longitud de la cadena no cuenta el carácter nulo: si el array cadena contiene "EJEMPLO", strlen( )
devolverá el valor 7.
Veamos su funcionamiento con un ejemplo sencillo:
// Fichero: EJEMP32.C
// Objetivo: Ejemplo de uso de la función strlen( ) para medir una cadena.
// Programador: Miguel Ángel García Marcos
// Fecha: 24-4-2007
// Versión: 1.0

# include <stdio.h> // Fichero de cabecera necesario para printf( )


# include <conio.h> // Fichero de cabecera necesario para clrscr( )
# include <string.h> // Fichero de cabecera necesario para strlen( )

int main( ){
char frase[80];

clrscr();
printf("Teclea una frase de 79 caracteres como máximo:\n");
gets(frase);
printf("\n\nLa frase que has escrito tiene %d caracteres.", strlen(frase));
return 0;
}

Vemos cómo en este ejemplo el valor devuelto por strlen( ) no se recoge de forma explícita en una variable

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 75


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

de tipo entero. En su lugar, es la función printf( ) la que lo recibe en el lugar donde ya espera un entero. Ésta
es una forma muy habitual de trabajar al escribir programas en C y otros lenguajes.

6.6 La ventaja de usar el terminador nulo


Al hacer que todas las cadenas terminen con el carácter nulo se simplifican mucho los programas. ¿Por qué?
La respuesta es que el carácter nulo sirve como indicador estándar de que la cadena de caracteres (no el array
que la contiene) ha terminado en todos los casos. De esta forma no hay que leer el array completo si no es
necesario, ni "adivinar" dónde termina una palabra o una frase contenida en ese array.
En este ejemplo vemos lo sencillo que es recorrer la parte "útil" del array que contiene una frase, para
convertirla a mayúsculas.
La tarea de convertir en mayúsculas cada carácter se la dejamos a otra función estándar: toupper( ).
Existe la función complementaria, que convierte a minúsculas un carácter: tolower( ).

// Fichero: EJEMP33.C
// Objetivo: Ventaja de usar el terminador nulo en las cadenas de caracteres.
// El programa pide una frase y la convierte a mayúsculas.
// Programador: Miguel Ángel García Marcos
// Fecha: 24-4-2007
// Versión: 1.0

# include <stdio.h> // Fichero de cabecera necesario para printf( )


# include <conio.h> // Fichero de cabecera necesario para clrscr( )
# include <string.h> // Fichero de cabecera necesario para strcpy( )
# include <ctype.h> // Fichero de cabecera necesario para toupper( )

int main( ){
char frase[40];
int i;

clrscr();
strcpy(frase, "Frase de ejemplo.");
i= 0;
while(frase[i] != '\0'){ // Mientras no encuentra el final de la cadena:
frase[i]= toupper(frase[i]); // Convierte ese carácter a mayúsculas.
i++;
}
printf("\n\nFrase en mayúsculas: ");
printf(frase);
return 0;
}

Atención a la última línea, que muestra un nuevo modo de utilizar printf para visualizar un texto en pantalla.
Es una forma perfectamente válida debido a que frase es un array de caracteres, aunque en algunos
compiladores puede provocar un aviso (warning) al compilar. Internamente, la función printf( ) se aprovecha
de que la cadena finalizará con un carácter nulo, y de esa forma no tiene por qué presentar por pantalla todo
el contenido del array, sino solamente los caracteres que formen la cadena contenida en ese array.
Pero si intentásemos esto:

76 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

char frase[10];
printf(frase);
Los resultados serían completamente imprevisibles, debido a que no hemos inicializado el array. Si entre
esos 10 caracteres reservados en memoria para el array no se encuentra casualmente un carácter nulo,
printf( ) seguirá mostrando caracteres "aleatorios" por pantalla (e incluso soltando pitidos, cada vez que
encuentre un carácter BEL – un byte con el valor decimal 7 –) que representan el contenido de esa zona de la
RAM, hasta que llegue en algún momento a un byte que tenga el valor cero (carácter nulo), lo que podría
ocurrir nada más empezar (y no visualizaría nada), o quizás después de "emborronar" varias veces la
pantalla.

6.7 Arrays de 2 o más dimensiones


Aunque los más frecuentes son los arrays unidimensionales, vistos hasta ahora, son también muy habituales
los de 2 dimensiones (bidimensionales).
Podemos imaginarlos como tableros rectangulares que tienen sus casillas organizadas en filas y columnas; de
ahí que a los arrays bidimensionales también se les llame matrices.
Sin embargo, la RAM es unidimensional, de modo que cada fila está ubicada linealmente a continuación de
la fila anterior.
Veremos gráficamente estas dos representaciones: la gráfica, más intuitiva, y la ubicación "real" en la RAM,
que es útil conocerla para algunos casos; pero primero estudiemos un ejemplo, ejecutándolo paso a paso.
Supongamos que queremos calcular y guardar en memoria el cuadrado de los 10 primeros números enteros.
Lo podríamos hacer fácilmente con este programa, siendo interesante ejecutarlo paso a paso y pedir que el
depurador nos muestre en cada instante (watch) el valor de cuadrados, cuadrados[fila-1] y cuadrados[fila]:
// Fichero: EJEMP34.C
// Objetivo: Ejemplo de array bidimensional.
// Calcula el cuadrado de los 10 primeros números enteros.
// Programador: Miguel Ángel García Marcos
// Fecha: 26-4-2007
// Versión: 1.0
# include <stdio.h>
# include <conio.h>

int main( ){
int cuadrados[10][2]; // Array de 10 filas x 2 columnas.
int fila; // Índice para manejar el array.

clrscr();
printf("Cálculo del cuadrado de los 10 primeros números enteros:\n\n");
// Cálculo y almacenaje de los cuadrados:
for(fila= 0; fila<10; fila++){
cuadrados[fila][0]= (fila+1); // Nº entero actual.
cuadrados[fila][1]= (fila+1)*(fila+1); // Calcula y guarda su cuadrado
}
// Muestra por pantalla los resultados:
for(fila= 0; fila<10; fila++){
printf("%2d x %2d= ", cuadrados[fila][0], cuadrados[fila][0]);

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 77


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

printf("%3d\n", cuadrados[fila][1]);
}
return 0;
}

Gráficamente podríamos ver así el array cuadrados usado en el anterior ejemplo:


En primer lugar se muestra la ocupación que hace el array de la RAM. Se ha preferido usar una ubicación
relativa, comenzando en la posición 0, para mayor claridad, aunque en realidad empezará en una posición
que determinará el sistema operativo en el momento de reservar esa memoria.
Debajo aparece la representación gráfica en forma de filas y columnas, más intuitiva por estar más
relacionada con la idea de trabajo en 2 dimensiones.

Nombre del array: cuadrados


Posición relativa
en memoria: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Contenido en la RAM: 1 1 2 4 3 9 4 16 5 25 6 36 7 49 8 64 9 81 10 100

Índices de las filas:

0 1 Índices de las
columnas:
0 E
1 1
s
1 E
2 s
4
REPRESENTACIÓN INTUITIVA E
3 9
s
2
DEL ARRAY cuadrados
3 E
4 s
16
4 E
5 s
25
5 E
6 36
s
6 E
7 s
49
7 E
8 s
64
8 E
9 s
81
9 10
E 100
s

Si deseamos calcular cuánta RAM (en bytes) ocupa este array, lo haremos con esta línea de código:
tamano= FILAS * COLUMNAS * sizeof(int); // En este caso FILAS= 10 y COLUMNAS= 2
Por tanto estaríamos ocupando 10 filas x 2 columnas x 2 bytes/dato= 20 datos x 2 bytes/dato= 40 bytes.

Uno de los usos que se le puede dar a un array bidimensional es almacenar varias cadenas de caracteres para
componer, por ejemplo, el texto de una página. Podemos entenderlo como un array de cadenas.
Supongamos que cada línea de ese texto puede tener 80 caracteres, y que la página tiene una longitud de 100
líneas. Entonces reservaríamos memoria en un array bidimensional como éste:
char pagina[100][80];
Si por ejemplo queremos usar gets( ) para guardar una cadena en la décima línea de la página, lo haríamos
así:

78 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

gets(pagina[9]);
Recodemos que, al estudiar la función gets( ), habíamos resaltado el hecho de que había que llamarla
enviándole sólo el nombre del array, sin poner el índice. Pues bien, en realidad seguimos haciendo lo mismo,
pues lo que hacemos es indicar que se trata de la cadena número 9, sin más (la explicación concreta es algo
compleja por el momento, mientras no conozcamos las funciones y las técnicas para pasarles los
parámetros).

Escribir y ejecutar paso a paso el siguiente programa, como ejemplo de los arrays de cadenas:
// Fichero: EJEMP35.C
// Objetivo: Ejemplo de array de cadenas.
// Toma líneas de texto desde el teclado y las imprime después.
// Programador: Miguel Ángel García Marcos
// Fecha: 26-4-2007
// Versión: 1.0

# include <stdio.h>
# include <conio.h>
# define LINEAS 100 // Nº máximo de líneas del texto.
# define COLUMNAS 80 // Nº máximo de caracteres (+1) por cada línea.

int main( ){
char texto[LINEAS][COLUMNAS]; // Página de texto.
int fila; // Índice que señala cada línea del texto tecleada.
int i; // Contador de líneas para reproducirlas.

clrscr();
printf("Teclea un texto. Pulsa intro después de cada línea.\n");
printf("Escribe como máximo 79 caracteres por línea.\n");
printf("Puedes escribir un máximo de 100 líneas de texto.\n");
printf("Si quieres acabar antes de las 100 líneas, ");
printf("escribe una línea en blanco pulsando sólo la tecla INTRO.\n");
printf("A la izquierda se te mostrará el número de línea a escribir.\n\n");
// Toma de datos:
fila= 0;
do{
printf("%d: ", fila+1);
gets(texto[fila]);
fila++;
}while(fila<LINEAS && texto[fila-1][0]!='\0');
// Reproducción línea a línea del texto tecleado:
for(i=0; i< fila; i++)
printf("%s\n", texto[i]); // Visualiza completa la línea nº i.
return 0;
}

Sin embargo, pese a lo útiles que son los arrays bidimensionales, no estamos restringidos a este límite en
cuanto al número de dimensiones de los arrays. Si lo necesitamos, podemos crear arrays de todas las
dimensiones que queramos. No obstante, esto tiene un precio: la memoria.
Con un sencillo array de caracteres (tan solo 1 byte por cada dato) de 3 dimensiones, y que tenga un tamaño
total de 20 x 100 x 80 celdillas (algo así como 20 "páginas" de 100 líneas con 80 caracteres cada una), nos
encontramos que consume una memoria de 1 x 20 x 100 x 80 = 160.000 bytes.

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 79


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

Si el array tuviera más de 3 dimensiones, el consumo de memoria se dispararía aún más rápidamente.

En caso de necesitarlo, tendremos que declarar el nombre del array y el tamaño de todas sus dimensiones,
para reservar la memoria necesaria, tal como hacíamos con arrays de una y dos dimensiones. La forma
general de declararlo es ésta:
tipo nombre[tamaño1][tamaño2]...[tamañoN];
Por ejemplo, para el array tridimensional mencionado antes:
char libro[20][100][80];

6.8 Inicialización de arrays


Ahora veremos cómo inicializar los arrays en el momento de su declaración, pues hasta ahora hemos tenido
que darles un valor posteriormente mediante otras instrucciones (por ejemplo con strcpy( ), o con una
asignación).
Los valores que deba tener el array forman una lista. Para que el compilador de C lo entienda, separaremos
cada valor con una coma, y agruparemos toda la lista del mismo modo que se hace para agrupar un bloque de
instrucciones: mediante dos llaves. Veamos algunos ejemplos:

Si se trata de un array que almacenará números:


int datos[10]= {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};

Cuando queramos inicializar caracteres, además de lo anterior, debemos encerrar cada carácter entre comillas
simples:
char vocales[5]= {'a', 'e', 'i', 'o', 'u'};

Si lo que queremos es inicializar una cadena de caracteres, tenemos dos opciones:


a) La forma general, similar al caso anterior, pero añadiendo al final el carácter nulo:
char palabra[5]= {'H', 'o', 'l', 'a', '\0'};
b) La forma abreviada, mucho más cómoda, y por eso mismo, la más empleada:
char palabra[5]= "Hola";
En este caso, el compilador de C añade automáticamente el carácter nulo al final.

Supongamos que queremos inicializar el array bidimensional que almacenaba el cuadrado de los 10 primeros
números. Podemos hacerlo también de dos maneras, aunque en este caso sólo cambiaremos el estilo de
hacerlo:
a) Escribiendo todos los números en una única línea, recordando el gráfico de la página 78, donde se
mostraba el contenido del array en la RAM:

80 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

int cuadrados[10][2]={1, 1, 2, 4, 3, 9, 4, 16, 5, 25, 6, 36, 7, 49, 8, 64,


9, 81};

b) Colocando todos los números en forma de filas y columnas, para que resulte más claro e intuitivo al ver la
declaración. Siempre es preferible este método:
int cuadrados[10][2]= { 1, 1,
2, 4,
3, 9,
4, 16,
5, 25,
6, 36,
7, 49,
8, 64,
9, 81};

6.8.1 Inicialización abreviada


Para todos los casos de inicializaciones de arrays descritos, el lenguaje C tiene un método alternativo que
permite agilizar tales inicializaciones, a la vez que contribuye a reducir los errores cometidos por el
programador al hacerlas. Se trata de omitir el tamaño del array cuando se trata de un array de una única
dimensión, y de omitir el tamaño de la primera dimensión cuando se inicializa un array de 2 o más
dimensiones. Tan sólo deberemos escribir los corchetes vacíos para la dimensión omitida, y lo demás se
hace igual que antes. Veamos de nuevo los ejemplos previos, pero con esta abreviación:

a) Array unidimensional de enteros:


int datos[]= {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
El compilador cuenta el número de valores que hemos escrito, y reserva exactamente el tamaño que se
necesita para guardarlos todos.

b) Con un array unidimensional de caracteres procederemos igual que lo anterior:


char vocales[]= {'a', 'e', 'i', 'o', 'u'};

Con las cadenas de caracteres dijimos que disponíamos de dos opciones:


a) La forma general:
char palabra[]= {'H', 'o', 'l', 'a', '\0'};
b) La forma abreviada:
char palabra[]= "Hola";
Si la cadena fuese más larga, nos ahorraría tener que contar todos los caracteres que contiene la frase,
evitando el más que probable error de conteo:
char frase[]= "En este ejemplo hay muchos caracteres, pero no los tenemos
que contar.";

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 81


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

En este caso no podemos tabular correctamente, pues los tabuladores formarían parte de propia la cadena. Si
se da esta situación, conviene, cuando eso sea posible, dividir la cadena en dos o más partes.

Ahora inicializamos el array bidimensional del ejemplo gráfico:


Esto nos permitiría añadir o quitar filas al array, simplemente añadiendo o quitando parejas de números,
respectivamente. Sin embargo, siempre estamos obligados a declarar el tamaño de la segunda dimensión
y las siguientes (en el caso de arrays de más de 2 dimensiones).
a) Escribiendo todos los números en una única línea
int cuadrados[][2]={1, 1, 2, 4, 3, 9, 4, 16, 5, 25, 6, 36, 7, 49, 8, 64,
9, 81};

Hay que aclarar que al hacerlo así se provoca un aviso (warning) en tiempo de compilación con algunos
compiladores (entre ellos Code::Blocks), por lo que la forma más correcta de hacerlo es como sigue:
int cuadrados[][2]={{1, 1}, {2, 4}, {3, 9}, {4, 16}, {5, 25}, {6, 36}, {7,
49}, {8, 64}, {9, 81}};

b) Colocando todos los números en forma de filas y columnas para que resulte mucho más claro:
int cuadrados[][2]= { 1, 1,
2, 4,
3, 9,
4, 16,
5, 25,
6, 36,
7, 49,
8, 64,
9, 81};

De nuevo, lo más correcto es hacerlo así:


int cuadrados[][2]={ {1, 1},
{2, 4},
{3, 9},
{4, 16},
{5, 25},
{6, 36},
{7, 49},
{8, 64},
{9, 81}
};

Cuando declaramos un array omitiendo su primera dimensión, posteriormente no podremos guardar más
valores que la cantidad que hayan sido inicializados. Sin embargo, nada impide que éstos se modifiquen
durante el programa, a no ser que el array haya sido declarado como constante:

const char frase[]= "Este mensaje no podrá modificarse después";

82 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

6.9 Ejercicios de repaso

Ejercicio 1:
Hacer un programa que simule el funcionamiento de la función strlen( ). Es decir, dada una cadena de
caracteres, debe contar esos caracteres (excepto el nulo). Al final mostrará el resultado de ese conteo.

Ejercicio 2:
Diseñar y codificar un programa que simule el funcionamiento de la función strcpy( ). Además, este
programa debe comprobar el contorno de los arrays que maneja, de modo que nunca copie una cadena en un
array en el que no quepa, incluyendo su carácter nulo.
Al final mostrará en pantalla el contenido de la cadena original y de la copia. Sin embargo, queremos que la
copia se muestre en orden inverso; por ejemplo "Esto es una prueba" se verá como "abeurp anu se otsE".

Ejercicio 3:
Realizar un programa que simule el funcionamiento de la función strcmp( ). Debe recibir ambas cadenas
desde el teclado mediante la función gets( ). Si las dos cadenas a comparar son iguales, simplemente
mostrará el mensaje "Son iguales". En caso contrario, el mensaje será "Son distintas", y además dará el
número (positivo o negativo) resultante de la diferencia de ambas cadenas.

Ejercicio 4:
Hacer un programa que simule el funcionamiento de la función strcat( ). A diferencia de esa función, este
programa sí debe comprobar el contorno de los arrays que maneja, de modo que nunca intente añadir
caracteres en el array destino si no hay espacio para ellos.
El programa mostrará las dos cadenas, antes de ser concatenadas, y después.

Ejercicio 5:
Desarrollar un programa que tome una cadena desde el teclado y cuente el número de veces que aparece cada
una de las cinco vocales, mostrando este resultado por pantalla.

Ejercicio 6:
Hacer un programa que inicialice un array de enteros bidimensional de 10 x 2 y lo copie en otro array del
mismo tamaño y dimensiones.

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 83


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

Después debe copiar el mismo array original en otro, pero éste debe ser unidimensional de tamaño 20.
Al final del programa, se debe visualizar en pantalla el contenido de los dos arrays de destino: el primero
como 10 filas y 2 columnas, y el segundo en una sola línea o una sola columna.

Ejercicio 7:
Crear un programa que solicite al usuario 6 frases, las almacene en un array de 6 x 80 caracteres, y después
las muestre por pantalla en el orden inverso al que fueron introducidas desde el teclado. Sin embargo, cada
frase en sí misma no será invertida, sino que seguirá leyéndose igual que su original.

84 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

Tema 7. Las funciones en lenguaje C

7.1 Introducción
Antes de empezar a hablar de qué es una función en cualquier lenguaje de programación, escribiremos y
probaremos este ejemplo:
// Fichero: EJEMP36.C
// Objetivo: Mostrar en qué consiste una función en programación.
// Programador: Miguel Ángel García Marcos
// Fecha: 30-4-2007
// Versión: 1.0

# include <stdio.h>
# include <conio.h>

int Suma(int, int); // Declaración de la función.


// Su nombre aparece con la 1ª letra en mayúsculas.
// Observar que finaliza con punto y coma (;)

int Suma(int a, int b){ // Definición de la función.


// No acaba en punto y coma, pero se abre una llave.
int s;
s= a+b;
return s;
} // Con esta llave cerrada finaliza la definición de la función.

int main(){ // Definición de la función principal del programa.


int valorA, valorB, valorS;

valorA= 5;
valorB= 4;
valorS= Suma(valorA, valorB); // Llamada a la función.
clrscr();
printf("El resultado de sumar %d + %d es: %d\n", valorA, valorB, valorS);
printf("3 + 2= %d\n", Suma(3, 2));
return 0;
}

· Las funciones son "pequeños programas" que cumplen tareas muy específicas.
· Ventajas principales que se consiguen con su uso:
– Si una tarea concreta se utiliza varias veces en un programa, no es necesario escribir su código
más que una vez.
– El programa principal queda mucho más "limpio", y por tanto más legible, debido a que
sacamos de él todos los pequeños detalles del programa, y dejamos sólo las tareas principales.

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 85


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

– Las funciones facilitan la programación estructurada al adaptarse de forma natural a las técnicas
de divide y vencerás y de refinamientos sucesivos.
· Tipos de funciones:
– Funciones: devuelven un único valor al programa que las llama.
Es el caso de la función del ejemplo anterior, que suma 2 números y devuelve el resultado.
– Procedimientos: realizan su tarea, pero no devuelven valor alguno de forma explícita.
Por ejemplo la función predefinida que borra la pantalla: clrscr()

· Las funciones, al igual que las variables, deben ser declaradas antes de ser utilizadas en el resto del
programa. Por lo tanto distinguiremos entre:
– Declaración:
• Indica: · El nombre de la función.
· Número de parámetros que recibe.
· Tipo de esos parámetros.
· Si devuelve un valor o no.
· En su caso, el tipo de parámetro devuelto.
• Termina con un punto y coma (;).
– Definición:
• Es la implementación, es decir, el desarrollo completo de esa función.
• Comienza con una cabecera.
• Esa cabecera es idéntica a la declaración, excepto en que a los parámetros que recibe
hay que ponerlos un nombre obligatoriamente (en la declaración es opcional). Con esto,
lo que se hace es declarar las variables que representan a esos parámetros.
• Esta cabecera finaliza SIN el signo de punto y coma (;).
• Después de la cabecera viene el cuerpo de la función, que debe ir encerrado entre llaves.
• Si la función devuelve un valor, la variable que lo represente debe ser declarada en el
cuerpo de la función, y su tipo debe coincidir con el indicado en la declaración de la
función y en su cabecera.
– Llamada: si se implementa una función es, lógicamente, para utilizarla a lo largo del programa
una o más veces. La forma de utilizarla se denomina llamada y en ella:
• Se pondrá el nombre de la función.
• Encerrados entre paréntesis se escribirán tantos argumentos como parámetros tenga la
declaración de la función.
• Esos argumentos no son otra cosa que variables. Pues bien, deben coincidir con los
tipos que se hayan declarado en la función y además deben colocarse en el orden
correcto.
• Si la función devuelve un valor, éste se recogerá poniendo, en la llamada, una variable
del mismo tipo a la izquierda del nombre de la función y separada por un signo de igual

86 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

(operando de asignación). Sin embargo, no es obligatorio recoger el valor devuelto;


puede ser ignorado, como por ejemplo cuando se llama a la función getch()
simplemente para hacer una pausa en el programa.
• Como el resto de las instrucciones, la llamada terminará con (;).

· Cuando la función no toma o no devuelve valor alguno, se pone void (vacío, en inglés).

7.2 Paso de parámetros por valor o por referencia


Para ver los dos modos de pasar datos a una función, primero escribiremos y comprobaremos estos dos
programas: EJEMP37.C y EJEMP38.C

7.2.1 Paso por valor


// Fichero: EJEMP37.C
// Objetivo: Demostrar el funcionamiento del paso de parámetros por valor
// a una función.
// Programador: Miguel Ángel García Marcos
// Fecha: 3-5-2007
// Versión: 1.0

# include <stdio.h>
# include <stdlib.h> // Fichero de cabecera necesario para system( )

void Prueba(int);

int main(){
int numero= 5;

system("cls");// Eso es en Windows, en Linux escribir system("clear");


printf("Valor de numero antes de la llamada: %d\n", numero);
Prueba(numero); // Pasamos el contenido de la variable 'numero'.
printf("\n\nValor de numero después de la llamada: %d", numero);
return 0;
}

void Prueba(int num){


printf("\nValor de num dentro de la función, al principio: %d", num);
num= 7;
printf("\nValor de num dentro de la función, al final: %d", num);
}
Si observamos bien lo que muestra por pantalla este programa, nos daremos cuenta que la función Prueba no
ha modificado en absoluto el valor de la variable numero que se le ha pasado. Esto es así porque lo que se
hace es copiar el contenido de la posición de memoria reservada para la variable numero en la posición de
memoria reservada para la variable num. De esta forma, la función Prueba puede leer y escribir lo que
contiene su variable local num, pero no tiene acceso de ningún modo a lo que hay en la variable numero, que
pertenece exclusivamente a la función main.

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 87


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

Gráficamente, podemos verlo así:

Paso de parámetros Por valor:

Identificador Contenido Dirección


10
9
8
Se copia el contenido de la variable numero
7 en otra posición de memoria para la variable
num 247 6 num.
5 El contenido de la dirección 1 NO puede ser
4 alterado por la función llamada.
3
2
numero 247 1
0

Para que nos hagamos una idea de cómo representar todo esto mediante diagramas de flujo, aquí se muestra
el equivalente para el programa anterior:
EJEMP37 Prueba

numero ← 5 num ← numero

Borra la “Valor de num


pantalla dentro de la función,
al principio: ”
num

“Valor de numero
antes
de la llamada: ” num ← 7
numero

“Valor de num
Prueba(numero) dentro de la función,
al final: ”
num

“Valor de numero
después FIN
de la llamada: ”
numero

FIN

La mayor diferencia respecto a lo que veníamos haciendo hasta ahora, al representar subprogramas en los
diagramas de flujo, es el paso de parámetros al subprograma (lo que ahora llamamos función). Debido a que,
cuando los parámetros se pasan por valor, realmente se está haciendo una asignación al inicio de la función ,
esto es precisamente lo que aparece en el recuadro resaltado en verde. Sin embargo, esto es sólo un recurso
didáctico que utilizaremos aquí, pues en la práctica la función Prueba podría ser llamada múltiples veces y
cada vez con parámetros distintos, lo que hace imposible dibujar siempre esa asignación explícitamente.

88 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

7.2.2 Paso por referencia


// Fichero: EJEMP38.C
// Objetivo: Demostrar el funcionamiento del paso de parámetros por referencia
// a una función.
// Programador: Miguel Ángel García Marcos
// Fecha: 3-5-2007
// Versión: 1.0
# include <stdio.h>
# include <conio.h>

void Prueba(int *); // La función recibirá la DIRECCIÓN de


// una variable de tipo entero.

int main(){
int numero= 5;

clrscr();
printf("Valor de numero antes de la llamada: %d\n", numero);
Prueba(&numero); // Indicamos a la función Prueba la dirección donde se
// almacena la variable 'numero', no su contenido.
printf("\n\nValor de numero después de la llamada: %d", numero);
return 0;
}

void Prueba(int *num){ // num es una dirección de memoria.


printf("\nValor de num dentro de la función, al principio: %d", *num);
*num= 7; // El contenido de la DIRECCIÓN 'num' es 7.
printf("\nValor de num dentro de la función, al final: %d", *num);
}

En este caso sí se modifica el contenido de la variable numero del programa principal (main). Esto es debido
a que lo que ahora se envía a la función Prueba cuando se la invoca, es la dirección de memoria donde se
encuentra almacenada la variable numero, y por tanto la función lee y escribe directamente en esa dirección
de memoria, y no en una copia, como ocurría cuando se pasaba un parámetro por valor.

Podemos entender mejor este método de paso de parámetros mediante el gráfico siguiente:
Paso de parámetros Por referencia

Identificador Contenido Dirección


10
9
8
7 A la función se le “dice” el valor de la dirección, para
que trabaje directamente sobre esa posición de
6
memoria.
5
El contenido de la dirección 1 puede ser alterado por la
4 función.
3
2
numero ≡ num 247 1
0

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 89


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

Del mismo modo que se ha hecho con el paso de parámetros por valor, a continuación se muestra un modo
de representar el paso de parámetros por referencia en un diagrama de flujo.

EJEMP38 Prueba

numero ← 5 num ≡ numero

Borra la “Valor de num


pantalla dentro de la función,
al principio: ”
num

“Valor de numero
antes
de la llamada: ” num ← 7
numero

“Valor de num
Prueba(numero) dentro de la función,
al final: ”
num

“Valor de numero
después FIN
de la llamada: ”
numero

FIN

En este caso, no existe asignación de valores, sino que se asigna la dirección. De esta forma se establece una
equivalencia entre el nombre de la variable en la función que llama, y el nombre de la variable en la función
llamada, para la misma dirección de memoria. De ahí que se haya escogido el símbolo matemático '≡'
(equivalente) para representar la asignación hecha en el recuadro resaltado en verde.

Igual que se comentó antes, este recuadro que se ha remarcado de verde es un recurso didáctico que
usaremos aquí, porque en la práctica una función puede ser llamada múltiples veces y no siempre con los
mismos parámetros. Para resolver este problema, lo que haremos será indicar con claridad, en la tabla de
símbolos, qué parámetros recibirá la función, de qué tipo son, y si se pasan por valor o por referencia .
En el apartado 7.2.4 se mostrará una posible forma de indicarlo también en el diagrama.

7.2.3 ¿Qué método debemos emplear para pasar parámetros?


Ambos métodos de paso de parámetros – por valor y por referencia – son igualmente importantes, puesto
que en unas ocasiones será preferible uno y en otras resultará más útil el otro.
En igualdad de condiciones, es preferible utilizar el paso por valor, dado que así se separan completamente
los datos de la función llamante y de la función llamada, quedando más protegidos frente a errores de
programación. Sin embargo, hay ocasiones en que no se puede elegir, bien por la propia naturaleza del
trabajo que tiene que realizar la función (ver el ejercicio 2 del apartado siguiente), o bien porque lo que se

90 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

pretende pasar a la función es un array.


En efecto, el caso de los arrays es una situación particular a la hora de pasarlos como parámetros a una
función. Para entenderlo, supongamos que tenemos un array de 50000 enteros y queremos pasarlo a una
función.

A) Si lo pasáramos por valor, el compilador debería crear por sí mismo las instrucciones correspondientes
para que, en tiempo de ejecución y precisamente en el momento de la llamada a esa función, se
realizara un bucle que fuese haciendo copia, uno por uno, del contenido de todos los elementos del
array original ubicado en la función que hace la llamada, a la correspondiente posición del array
ubicado en la función llamada.
En definitiva, en este caso se tendrían que realizar 50000 copias (asignaciones de valores), más las
necesarias instrucciones del propio bucle, que también deberían hacerse 50000 veces.
Como se puede suponer, pasar arrays por valor resultaría del todo ineficiente, por lo que nunca se hace
así.

B) Al pasar un array por referencia, lo único que se necesita pasar es su dirección de comienzo. Esta
tarea apenas consume tiempo, de modo que es altamente eficiente. Por este motivo, los arrays siempre
se pasan por referencia en todos los lenguajes de programación, sin que se permita la opción de
pasarlos por valor (ni siquiera por error o descuido del programador).

Veamos un ejemplo:
// Fichero: EJEMP39.C
// Objetivo: Calcular el cubo + 1 de los primeros 10 enteros y mostrarlos.
// Programador: Miguel Ángel García Marcos
// Fecha: 14-6-2010
// Versión: 1.0

# include <stdio.h>

# define MAX 10//Total de elementos del array datos[] en función principal.

/*************************************************************************\
* Función SumaUno
* Descripción: Recibe un array de enteros y suma 1 a cada uno de sus
* elementos.
* Recibe: - Un array de enteros.
* - Un entero que indica el número de elementos del array recibido.
* Devuelve: Nada.
* Modifica: El array recibido vuelve (se pasa por referencia) después de
* haber sumado 1 a cada uno de sus elementos.
\*************************************************************************/
void SumaUno(int *, const int);(Al pasar un array, realmente se pasa la dirección de su primer elemento)

int main() {
int datos[MAX], // Array que recibirá el resultado de todo el cálculo.
i; // Índice del array.

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 91


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

for(i= 0; i < MAX; i++)


datos[i]= i*i*i; // Calcula el cubo de su posición.
SumaUno(datos, MAX); (En la llamada no hay que poner *, porque el nombre del array es una DIRECCIÓN)
printf("Contenido de \"datos\" después de llamar a la función: \n");
for(i= 0; i < MAX; i++)
printf("%d\n", datos[i]);
return 0;
}

/*************************************************************************\
* Función SumaUno
* Descripción: Recibe un array de enteros y suma 1 a cada uno de sus
* elementos.
* Recibe: - valores: array de enteros.
* - TOTAL: constante entera. Indica nº de elementos del array recibido.
* Devuelve: Nada.
* Modifica: El array recibido vuelve (se pasa por referencia) después de
* haber sumado 1 a cada uno de sus elementos.
\*************************************************************************/
void SumaUno(int *valores, const int TOTAL) {
int j; // Índice para desplazarse por el array valores.

for (j= 0; j < TOTAL; j++)


valores[j]= valores[j]+1;
}

Seguidamente se muestra el diagrama de flujo de este ejemplo:

EJEMP39 SumaUno

valores ≡ datos
i←0
TOTAL ← MAX

No j←0
i < MAX


No
datos[i] ← i3 j < TOTAL


i ← i+1 valores[j] ← valores[j] + 1

j ← j+1
SumaUno(datos, MAX)

“Contenido de datos después FIN


de la llamada a SumaUno: ”

i←0

No
i < MAX


Visualiza datos[i]
Y salta de línea

i ← i+1

FIN

92 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

Un apunte para señalar que, en el código fuente de este ejemplo, lo que se ha puesto como comentario
de la función SumaUno (tanto en su declaración como en su definición), es lo que debe anotarse en la
tabla de símbolos, en el apartado dedicado a dicha función; en dicha tabla, además, deberían aparecer
todas sus variables locales (en este caso la variable j).

7.2.4 Cómo resolver algunos problemas al representar un diagrama de flujo


Hasta ahora hemos representado siempre diagramas de flujo de procedimientos, es decir funciones que no
devuelven valor alguno de forma explícita. Aquí vamos a ver una forma posible de representar una función
pura (es decir, que sí devuelve un valor) mediante un diagrama de flujo.
Nos basaremos en el código que aparece en el apartado 7.1 (Introducción), en la página 85. Veamos por tanto
cómo representar la llamada a la función en el programa principal y la propia función Suma:

EJEMP36 Suma

valorA ← 5 Recibe:
valorB ← 4 a (por valor)
b (por valor)

valorS ← Suma(valorA, valorB)


s←a+b

Borra la pantalla
Devuelve s

Visualiza FIN
valorA “+” valorB “=” valorS

Y salta de línea

temp ←
Prueba
Suma(3, 2)

Visualiza
“3 + 2= “ temp

FIN

Fijémonos en primer lugar en el rectángulo azul: la función tiene que devolver el valor de la variable s, y esto
se explicita así de la forma más sencilla y más clara posible.
Ahora prestemos atención a las dos llamadas a la función Suma() (rectángulos amarillos): dado que se espera
que la función devuelva un valor, éste se recoge haciendo una asignación a la variable que lo vaya a utilizar.
Como ya se ha indicado, un valor devuelto por una función puede ser ignorado, en cuyo caso no haremos
asignación.

En cuanto al paso de los parámetros, aquí nos encontramos con que tenemos que resolver el problema de que

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 93


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

hay dos llamadas a la función Suma(), y en cada caso se envían un par de parámetros distintos. Por tanto, ya
no resulta posible representar de forma explícita la asignación que se produce durante la llamada a la función
en el paso de parámetros por valor. En su lugar optamos de nuevo por representar esa acción de la forma más
simple y clara posible (contenido del rectángulo verde al principio de la función Suma()). Como puede
suponerse, este método es igualmente válido para el caso de que los parámetros se pasen por referencia: tan
sólo habrá que indicar esta circunstancia en el rectángulo donde se reciben.

Y por último comentaremos otro problema que es frecuente tener que resolver. Si observamos el código de
este ejemplo, al final de la función main() aparece una llamada a la función Suma() dentro de una llamada a
la función printf():
printf("3 + 2= %d", Suma(3, 2));
Esto no se puede representar directamente en un diagrama de flujo. Por eso se ha optado por dividir esa
instrucción en dos y representarlo en el diagrama en el orden en que se ejecutarían:
- Primero se llama a la función Suma(), y el valor que devuelve lo asignamos a una variable temporal
ficticia (temp), en el sentido de que dicha variable no es imprescindible y podría (como es el caso) no
existir en el código final.
- A continuación se llama a la función printf() y se le pasa el valor de la variable temporal obtenido en
el paso anterior.

7.2.5 Ejercicios de repaso


Ejercicio 1:
Hacer una función de nombre Calculador( ) que, dados dos números reales A y B, realice con ellos una de
las 4 operaciones básicas y devuelva el resultado obtenido. La operación que se lleve a cabo dependerá de un
parámetro de tipo carácter. Así:
'+': suma A más B.
'-': resta A menos B.
'*': multiplica A por B.
'/': divide A entre B.
Escribir un programa sencillo que llame a esa función para probarla, y llamarlo CALCULA.C.

Ejercicio 2:
Hacer una función, de nombre Intercambio( ), que reciba dos números enteros y los intercambie entre sí.
Hacer, igualmente, un programa que llame a esa función y llamarlo INTERCAM.C.

94 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

7.3 Variables automáticas y estáticas


Escribir el siguiente programa de ejemplo y ejecutarlo paso a paso, observando los valores que toma cada
variable.

// Fichero: EJEMP40.C
// Objetivo: Mostrar el uso de las variables estáticas y automáticas.
// Programador: Miguel Ángel García Marcos
// Fecha: 30-4-2007
// Versión: 1.0
# include <stdio.h>
# include <conio.h>

int Incrementa1(void);
int Incrementa2(void);

int main(void){
int a= 0, b= 0;

clrscr();
do{
a= Incrementa1();
b= Incrementa2();
printf("\na= %d, b= %d", a, b);
}while((a<10) && (b<10));
getch();
return 0;
}

int Incrementa1(void){
int valor1= 3; // Si no se indica nada, esta variable es AUTOMÁTICA:
// - Se inicializa cada vez que se llama a la función.
// - Es "destruida" cada vez que la función termina.

valor1++;
return valor1;
}

int Incrementa2(void){
static int valor2= 3; // Esta variable es ESTÁTICA:
// - Se inicializa la primera vez que se llama
// a la función, pero después conserva su
// último valor en cada llamada.
valor2++;
return valor2;
}

Como vemos, las variables estáticas mantienen su valor hasta la siguiente llamada a la función que las
contiene y su declaración solo se lleva a cabo la primera vez que se llama a esa función.
Según nuestras necesidades, en unos casos dejaremos que las variables declaradas en la función sean
automáticas, y en otras ocasiones haremos que sean estáticas.
La función main( )es la única que sólo se va a ejecutar una vez a lo largo del programa; por tanto no tiene
sentido declarar como static sus variables.

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 95


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

7.4 Variables globales y locales


Escribir el siguiente programa de ejemplo y ejecutarlo paso a paso, observando el valor que toma cada
variable y su "existencia" y "desaparición" a lo largo del programa.

// Fichero: EJEMP41.C
// Objetivo: Mostrar la diferencia entre variables globales y locales.
// Programador: Miguel Ángel García Marcos
// Fecha: 30-4-2007
// Versión: 1.0
# include <stdio.h>
# include <conio.h>

void Suma(int, int);

int varGlobal;

int main(void){
int varLocal1, varLocal2;

clrscr();
varLocal1= 3;
varLocal2= 5;
Suma(varLocal1, varLocal2);
printf("%d + %d= %d\n", varLocal1, varLocal2, varGlobal);
getch();

return 0;
}

void Suma(int varLocal3, int varLocal4){


varGlobal= varLocal3 + varLocal4;
printf("\n%d + %d= %d\n", varLocal3, varLocal4, varGlobal);
}

Después de probarlo, cambiamos los nombres de las variables varLocal3 y varLocal4, que se usan en la
función Suma( ), por el de varLocal1 y varLocal2 respectivamente, y observaremos que el resultado no varía
en absoluto, puesto que las variables locales de la función main( ) son distintas de las de Suma( ), aunque
tengan los mismos nombres, porque se guardan en posiciones de memoria distintas. Para comprobar esto, al
ejecutarlo paso a paso, es interesante examinar (watch) &varGlobal, &varLocal1, &varLocal2, &varLocal3
y &varLocal4, para ver en que dirección se encuentra cada variable.

El uso de variables globales, como se ve en este ejemplo, evita que tengamos que pasar y devolver valores a
y desde las funciones. Sin embargo, el uso de variables globales debe restringirse al mínimo
imprescindible puesto que, en programas un poco grandes, pueden ser fuente de muchos errores. Esto se
debe a que una variable global puede ser modificada directamente por cualquier parte del programa, lo que
impide que las funciones que las usan sean completamente independientes unas de otras y del programa
principal.

96 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

7.5 Tabla de símbolos en un programa con funciones


Cuando hagamos un programa que incluya una o más funciones (aparte de la función main), haremos lo
siguiente:
Una tabla de símbolos para el programa principal, en la que incluiremos:
– Descripción del programa (qué hace, o para qué sirve el programa en su conjunto).
– Símbolos (variables y constantes) que sean globales al programa, señalando su condición de globales.

Una tabla de símbolos para cada función (incluida main), que debe contener:
– Nombre de la función.
– Descripción de la función (objetivo que se persigue con ella).
– Argumentos que recibe (por cada uno se indicará la siguiente información):
nombre,
tipo,
descripción,
método de paso (por valor o por referencia),
rango de valores válidos.
– Si modifica alguno de sus argumentos de entrada, aclarar de qué forma quedará modificado.
– Si devuelve algún valor, especificar de qué tipo es, qué significado tiene, y entre qué rango de valores
cabe esperar que esté.
– Símbolos (variables y constantes) locales a esa función: tipo, significado (descripción) y rango de
valores.

Aquí se representa un ejemplo de cómo tendría que ser la tabla de símbolos para el caso del programa
EJEMP36:
TABLA DE SÍMBOLOS:

Programa principal:
Objetivo: sumar dos números y mostrar el resultado en pantalla.
Dicha suma la realizará una función específica para esa tarea.
Símbolos globales: no existen.

Función main:
Objetivo: el del programa principal.
Recibe: nada.
Modifica: nada (ya que no recibe argumentos de entrada).
Devuelve: un número entero (siempre devolverá un 0).

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 97


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

Símbolos locales:
valorA: Variable de tipo entero.
Es uno de los sumandos.
Rango de valores: de -50.000 a + 50.000.
valorB: Variable de tipo entero.
Es el otro sumando.
Rango de valores: de -50.000 a + 50.000.
valorS: Variable de tipo entero.
Contendrá el resultado de la suma.
Rango de valores: [-100.000, +100.000] (forma de expresarlo matemáticamente)

Función Suma:
Objetivo: sumar los dos números enteros que reciba y devolver el resultado de esa suma.
Recibe:
a: Variable de tipo entero.
Es uno de los sumandos.
Se recibe por valor.
Rango de valores: [-50.000, + 50.000]
b: Variable de tipo entero.
Es el otro sumando.
Se recibe por valor.
Rango de valores: [-50.000 , + 50.000]
Modifica: nada.
Devuelve: un valor de tipo entero.
Representa el resultado de la suma realizada con los dos argumentos de entrada.
Rango de valores: [-100.000, +100.000]

Símbolos locales:
s: Variable de tipo entero.
Contendrá el resultado de la suma realizada con los dos argumentos de entrada.
Rango de valores: [-100.000, +100.000]

Toda esta información, además de formar parte de la documentación externa (en papel), debe quedar
convenientemente incluida también en el código fuente, en forma de comentarios. Así quedaría el código
fuente que aparece en la introducción de este tema, después de añadir dichos comentarios:

98 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html


Lenguaje C

// Fichero: EJEMP36.C
// Objetivo: sumar dos números y mostrar el resultado en pantalla.
// Programador: Miguel Ángel García Marcos
// Fecha: 23-6-2010
// Versión: 1.5

# include <stdio.h>
# include <conio.h>

/*************************************************************************\
* Función Suma
* Descripción: suma los dos números enteros que reciba y devuelve el
* resultado de esa suma.
* Recibe:
* 2 enteros, que son los sumandos con los que se operará.
* Ambos se reciben por valor.
* Ambos tienen el mismo rango de valores: [-50.000, + 50.000]
* Devuelve:
* Un valor de tipo entero.
* Representa el resultado de la suma realizada con los dos
* argumentos de entrada.
* Rango de valores: [-100.000, +100.000]
* Modifica: nada.
\*************************************************************************/
int Suma(int, int);

int main(){
int valorA, valorB, // Son los 2 sumandos de la primera suma.
valorS; // Acogerá el resultado de la primera suma.

valorA= 5;
valorB= 4;
valorS= Suma(valorA, valorB);
clrscr();
printf("El resultado de sumar %d + %d es: %d\n", valorA, valorB, valorS);
printf("3 + 2= %d\n", Suma(3, 2));
return 0;
}

/*************************************************************************\
* Función Suma
* Descripción: sumar los dos números enteros que reciba y devolver el
* resultado de esa suma.
* Recibe:
* a: Variable de tipo entero.
* Es uno de los sumandos.
* Se recibe por valor.
* Rango de valores: [-50.000, + 50.000]
* b: Variable de tipo entero.
* Es el otro sumando.
* Se recibe por valor.
* Rango de valores: [-50.000, + 50.000]
* Devuelve:
* Un valor de tipo entero.
* Representa el resultado de la suma realizada con los dos
* argumentos de entrada.
* Rango de valores: [-100.000, +100.000]
* Modifica: nada.
\*************************************************************************/

Dep. Electrónica I.E.S. Joan Miró: www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html 99


Técnicas de Programación Ciclo Formativo de Grado Superior Desarrollo de Productos Electrónicos

int Suma(int a, int b){


int s; // Resultado de la suma realizada con los dos argumentos de entrada.
// Rango de valores: [-100.000, +100.000].

s= a+b;
return s;
}

7.6 Ejercicios de repaso


Ejercicio 1:
Escribir una función, de nombre Min( ), que devuelva el menor de dos valores reales y comprobarla con un
pequeño programa de ejemplo que llamaremos MINIMO.C.

Ejercicio 2:
Diseñar una función, de nombre PoneEnXY( ), que escriba el carácter pedido en la posición de coordenadas
(x, y) que se desee de la pantalla. Comprobarla con un programa de ejemplo que llamaremos
PONEENXY.C.
Para hacer esta sencilla función, necesitamos auxiliarnos de la función estándar de biblioteca gotoxy( ), que
se limita a situar el cursor en las coordenadas que se le indiquen dentro de una pantalla de texto. Como
entrada recibe dos valores enteros, correspondientes respectivamente a la coordenada x y a la coordenada y.

Ejercicio 3:
Escribir una función que simule el comportamiento de la función predefinida strlen( ); llamarla LongCad( ).
Escribir otra función que imite el comportamiento de la función predefinida strcpy( ) y llamarla CopiaCad( ).
Escribir una función más, que imite el comportamiento de la función predefinida strcat( ) y llamarla
UneCad( ).
Estas tres funciones pueden aprovecharse del análisis del problema y el diseño del algoritmo que se hicieron
para resolver los correspondientes problemas de repaso del tema 6.
Probar esas tres funciones en un mismo programa de ejemplo que se llame CADENAS.C y que haga uso de
cada una de ellas al menos una vez.

Ejercicio 4:
Escribir una función que reciba una frase y la escriba en pantalla en orden inverso. Llamarla Invierte( ) y
probarla con un programa de ejemplo que se llame CADINVER.C. Puede hacer uso de las funciones de
cadena diseñadas en el ejercicio anterior.

100 Dep. Electrónica I.E.S. Joan Miró: http://www.educa.madrid.org/web/ies.joanmiro.sansebastian/departamentos/ele-eo/index.html

También podría gustarte