programacion c

Upload: christian-iguamba

Post on 07-Jan-2016

74 views

Category:

Documents


4 download

DESCRIPTION

Inicios a la programación en C

TRANSCRIPT

  • EDITORIALUNIVERSITAT POLITE`CNICA DE VALE`NCIA

    Gua Practica de Programacionen C

    Septiembre de 2012

    Rafael Llobet Azpitarte

  • Coleccin Acadmica

    Para referenciar esta publicacin utilice la siguiente cita: LLOBET-AZPITARTE, R.(2012). Gua prctica de programacin en C. Valencia : Editorial Universitat Politcnica .

    Primera edicin 2012

    Rafael Llobet- Azpitarte

    todos los nombres comerciales, marcas o signos distintivos de cualquier clase contenidos en la obra estn protegidos por la Ley.

    de la presente edicin: Editorial Universitat Politcnica de Valncia www.editorial.upv.es

    Distribucin: [email protected] Tel. 96 387 70 12

    Imprime: By print percom sl.

    ISBN: 978-84-8363-945-0 Impreso bajo demanda Ref. editorial: 298

    Queda prohibida la reproduccin, distribucin, comercializacin, transformacin, y en general, cualquier otra forma de explotacin, por cualquier procedimiento, de todo o parte de los contenidos de esta obra sin autorizacin expresa y por escrito de sus autores.

    Impreso en Espaa

  • Indice general

    Indice general I

    1 Introduccion a la computacion 1

    1.1 Tratamiento automatico de la informacion . . . . . . . . . . . . . . . . . . . . . . . . . . 1

    1.2 Codicacion de la informacion: el sistema binario . . . . . . . . . . . . . . . . . . . . . 2

    1.3 Concepto de algoritmo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

    1.4 El proceso de la programacion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

    1.5 Lenguajes de programacion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

    1.6 El lenguaje C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

    1.7 Compiladores e interpretes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

    2 Elementos basicos de un programa en C 9

    2.1 Estructura basica de un programa en C . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

    2.2 Mostrando mensajes con printf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

    2.3 Variables y tipos de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

    2.3.1 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

    2.3.2 Tipos de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

    2.3.3 Uso de variables: declaracion y asignacion . . . . . . . . . . . . . . . . . . . . . . . . 13

    2.4 Comentarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

    2.5 Uso avanzado de printf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

    2.6 Leyendo datos con scanf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

    2.7 Expresiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

    2.7.1 Expresiones aritmeticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

    2.7.2 Expresiones relacionales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23I

  • Indice general

    2.7.3 Expresiones logicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

    2.8 Otros conceptos sobre tipos de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

    2.8.1 El tipo char . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

    2.8.2 Conversion de tipos: casting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

    2.9 Punteros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

    2.9.1 Declaracion. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

    2.9.2 El operador de direccion & . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

    2.9.3 El operador de indireccion * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

    2.9.4 La constante NULL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

    2.10 Directivas del precompilador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

    2.10.1 Incluir cheros de cabecera: #include . . . . . . . . . . . . . . . . . . . . . . . . . . 31

    2.10.2 Denicion de constantes: #dene. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

    2.11 Ejercicios resueltos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

    2.12 Ejercicios propuestos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

    3 Estructuras de control 35

    3.1 Sentencias de seleccion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

    3.1.1 Seleccion con if-else . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

    3.1.2 Seleccion con switch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

    3.2 Sentencias de repeticion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

    3.2.1 La sentencia while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

    3.2.2 La sentencia do-while. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

    3.2.3 La sentencia for. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

    3.2.4 Bucles anidados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50

    3.3 Algunas tecnicas utiles: contadores, acumuladores y banderas . . . . . . . . . . . . . . 51

    3.3.1 Contadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

    3.3.2 Acumuladores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

    3.3.3 Banderas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

    3.4 Ejercicios resueltos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

    3.5 Ejercicios propuestos: condicionales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

    3.6 Ejercicios propuestos: bucles. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

    4 Funciones 61

    4.1 Introduccion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61

    4.2 Funciones de la librera de C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61

    II

  • Indice general

    4.3 Creando nuestras propias funciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63

    4.3.1 Cuestiones sintacticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65

    4.3.2 Control de ujo y transferencia de la informacion. . . . . . . . . . . . . . . . . . . . . 67

    4.3.3 Parametros y argumentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69

    4.3.4 Operaciones de Entrada/Salida en las funciones . . . . . . . . . . . . . . . . . . . . . . 70

    4.3.5 Prototipos de funciones y cheros de cabecera . . . . . . . . . . . . . . . . . . . . . . 72

    4.4 Variables locales y globales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73

    4.5 Paso de argumentos por valor y por referencia . . . . . . . . . . . . . . . . . . . . . . . 76

    4.5.1 Paso de argumentos por valor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76

    4.5.2 Paso de argumentos por referencia. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

    4.6 Ejercicios resueltos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79

    4.6.1 Funciones que no devuelven ningun valor . . . . . . . . . . . . . . . . . . . . . . . . . 79

    4.6.2 Funciones que devuelven un valor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80

    4.6.3 Funciones que devuelven un valor del tipo VERDADERO/FALSO . . . . . . . . . . . 81

    4.6.4 Funciones que devuelven mas de un valor . . . . . . . . . . . . . . . . . . . . . . . . . 82

    4.7 Ejercicios propuestos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84

    5 Vectores 87

    5.1 Introduccion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87

    5.2 Declaracion de vectores. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88

    5.3 Acceso a los elementos de un vector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89

    5.4 Operaciones con vectores: automatizacion mediante bucles. . . . . . . . . . . . . . . . 90

    5.5 Paso de vectores a una funcion. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92

    5.6 Devolucion de vectores en una funcion. . . . . . . . . . . . . . . . . . . . . . . . . . . . 98

    5.7 Vectores multidimensionales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98

    5.8 Operaciones con matrices: automatizacion mediante bucles . . . . . . . . . . . . . . . 99

    5.9 Paso de matrices a una funcion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101

    5.10 Relacion entre vectores y punteros. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103

    5.11 Cadenas de caracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105

    5.11.1 Entrada y salida con cadenas de caracteres . . . . . . . . . . . . . . . . . . . . . . . . 106

    5.11.2 Funciones de manipulacion de cadenas de caracteres . . . . . . . . . . . . . . . . . . 109

    5.12 Ejercicios resueltos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110

    5.13 Ejercicios propuestos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114

    III

  • Indice general

    6 Estructuras 117

    6.1 Introduccion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117

    6.2 Declaracion de variables de tipos estructurados . . . . . . . . . . . . . . . . . . . . . . . 117

    6.2.1 Denicion de tipos estructurados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118

    6.2.2 Declaracion de variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118

    6.3 Operaciones con estructuras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119

    6.3.1 Inicializacion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119

    6.3.2 Acceso a los miembros de una estructura . . . . . . . . . . . . . . . . . . . . . . . . . 119

    6.3.3 Asignacion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120

    6.3.4 Otras operaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121

    6.4 Estructuras anidadas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

    6.5 Vectores de estructuras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

    6.6 Punteros a estructuras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124

    6.7 Paso de estructuras como parametros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125

    6.7.1 Pasar los miembros de forma independiente . . . . . . . . . . . . . . . . . . . . . . . . 125

    6.7.2 Pasar una estructura completa por valor . . . . . . . . . . . . . . . . . . . . . . . . . . 125

    6.7.3 Pasar una estructura completa por referencia . . . . . . . . . . . . . . . . . . . . . . . 127

    6.7.4 Pasar un vector de estructuras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127

    6.7.5 Devolver una estructura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128

    6.8 Ejercicios resueltos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128

    6.9 Ejercicios propuestos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131

    7 Gestion de cheros 133

    7.1 Introduccion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133

    7.2 Tipos de cheros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134

    7.3 Operaciones con cheros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134

    7.3.1 Abrir y cerrar cheros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135

    7.3.2 Lectura y escritura de cheros de texto . . . . . . . . . . . . . . . . . . . . . . . . . . 137

    7.3.3 Lectura y escritura de cheros binarios . . . . . . . . . . . . . . . . . . . . . . . . . . 143

    7.4 Acceso aleatorio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146

    7.5 Ejercicios resueltos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146

    7.6 Ejercicios propuestos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148

    Bibliografa 151

    IV

  • Captulo 1

    Introduccion a la computacion

    La informatica es la ciencia que aborda el tratamiento automatico de la informacion pormedio de ordenadores. Es importante conocer el modo en que un ordenador codica,almacena y procesa la informacion, para poder abordar con soltura la tarea de programa-cion. El objetivo de este captulo es dar una pequena introduccion a la computacion y alproceso de programacion.

    1.1 Tratamiento automatico de la informacion

    Cualquier sistema de tratamiento de la informacion, sea o no automatico, puede descom-ponerse, tal y como muestra la gura 1.1, en tres etapas basicas:

    Entrada: Recogida de datos.

    Proceso: Tratamiento de los datos.

    Salida: Presentacion de los resultados obtenidos.

    Cuando el volumen de datos a tratar es muy elevado o se requiere gran velocidad en elproceso de los mismos o simplemente la tarea a realizar es lo sucientemente aburrida

    Proceso Entrada SalidaS

    Figura 1.1: Etapas basicas en el procesamiento de la informacion

    1

  • Captulo 1. Introduccion a la computacion

    o tediosa para un humano, sera deseable realizar este proceso de forma automatica. Eneste sentido, los ordenadores tienen la capacidad de procesar gran cantidad de datos a unavelocidad de miles de millones de operaciones por segundo.

    Para que un ordenador pueda llevar a cabo cualquier tarea, debera disponer de los elemen-tos hardware necesarios para la entrada de datos (teclado, raton, ...), para el procesamientode los mismos (procesador o CPU), para la salida de resultados (monitor, impresora, ...) ypara el almacenamiento temporal o permanente de instrucciones y datos (memoria, discoduro, ...). Ademas de todos estos elementos, sera necesario introducir en el ordenador lasinstrucciones necesarias para realizar las operaciones deseadas sobre los datos, esto es,los programas (software). Los programas son los que hacen que un ordenador sea versatily pueda utilizarse para realizar tareas muy diversas. En este libro aprenderemos a creardichos programas, pero antes sera necesario tener unos conocimientos mnimos sobre elmodo en que un ordenador codica la informacion.

    1.2 Codicacion de la informacion: el sistema binario

    Un ordenador funciona por impulsos electricos, de modo que unicamente puede diferen-ciar entre presencia y ausencia de corriente o carga electrica, esto es, solo puede dife-renciar dos estados. Comunmente identicamos a estos dos estados mediante los dgitos0 y 1. Es por ello que cualquier informacion que deba ser procesada por un ordenador,necesariamente tiene que estar representada mediante una secuencia de unos y ceros, estoes, debe estar codicada en el sistema binario.

    En el sistema decimal que empleamos los humanos, cada dgito tiene un peso distintosegun la posicion que ocupa. De derecha a izquierda tenemos las unidades, decenas, cen-tenas, etc, donde el dgito que representa las unidades tiene un peso de 100, el de lasdecenas de 101, el de las centenas de 102, y as sucesivamente. De modo similar, en el sis-tema binario, empleado por los ordenadores y otros dispositivos electronicos, cada dgito,de derecha a izquierda, tiene un peso de 20, 21, 22, etc.

    Por ejemplo, el numero binario 1101 equivale al decimal 13, ya que 1 23 + 1 22 + 0 21 + 1 20 = 13.A los sistemas decimal y binario (por poner algunos ejemplos de sistemas de numeracion)se los denomina tambien sistema en base 10 y en base 2 respectivamente. En general,para conocer el valor decimal de cualquier numero N expresado en base B aplicaremos laformula:

    N = x0B0 + x1B

    1 + ...+ xnBn =

    ni=0

    xiBi

    donde xi son los dgitos del numero expresado en la base B.

    Denominamos bit a un dgito binario 0/1 y byte a una agrupacion de 8 bits. Un bit uni-camente nos permite diferenciar entre dos estados posibles. Con una secuencia de 2 bits

    2

  • 1.2 Codicacion de la informacion: el sistema binario

    pueden formarse 4 combinaciones distintas (00, 01, 10 y 11), con 3 bits 8 combinaciones(000, 001, 010, 011, 100, 101, 110 y 111). En general, con n bits pueden formarse 2n

    combinaciones. Podemos codicar los elementos de un conjunto dado (numeros enteros,letras, colores, etc.) mediante distintas secuencias de bits. Por ejemplo, con un byte (8bits) pueden codicarse 28 = 256 elementos. Con 4 bytes (32 bits) pueden codicarsemas de cuatro mil millones de elementos.

    Siguiendo con las unidades de medida, diremos que un kilobyte (1 KB) son 1024 bytes,un gigabyte (1 GB) son 1024 KB y un terabyte (1 TB) son 1024 GB (esto es, mas de milmillones de bytes).

    Ya hemos visto como un ordenador puede representar numeros enteros mediante el siste-ma binario, pero tambien debe ser capaz de representar numeros reales, caracteres, image-nes, sonido y por supuesto instrucciones, por poner solo algunos ejemplos. Es necesariodisponer de distintos sistemas de codicacion para poder representar informacion decualquier tipo.

    La codicacion es el proceso por el cual representamos smbolos o secuencias de unalfabeto mediante los smbolos o secuencias de otro alfabeto, es decir, establecemos unacorrespondencia biunvoca entre los smbolos de dos alfabetos distintos. En los ejemplosanteriores hemos visto como codicar numeros enteros mediante secuencias de 1s y 0sen lo que conocemos como sistema de codicacion BCD. Pero, tal y como acabamos demencionar, necesitamos otros sistemas para codicar otros objetos de otros conjuntos.

    Para codicar los numeros reales en el sistema binario se utiliza lo que denominamosrepresentacion en coma otante o formato cientco. Por ejemplo, el numero 12.5 (elcual acabamos de escribir en su notacion habitual o coma ja) se expresara en notacioncientca como 0.125E2. La representacion binaria de dicho numero consiste en la utili-zacion de una cierta cantidad de bits para representar lo que se denomina mantisa (0.125)y otra cierta cantidad de bits para representar el exponente. Valiendonos del sistema BCDutilizado para numeros enteros, codicaramos por un lado el numero 125 (mantisa enformato normalizado) y por otro lado el exponente (2 en este ejemplo).

    Otro sistema de codicacion es el ASCII (American Standard Code for Information Inter-change) utilizado para la representacion de caracteres alfanumericos. Para ello se deneuna tabla de correspondencia, en la que a cada caracter se le asocia un codigo binario.Dicha tabla de correspondencia es un estandar que utilizan todos los sistemas informati-cos, lo que permite el intercambio de informacion entre distintos sistemas. Imaginemosalgo tan habitual como enviar un correo electronico. El texto en el contenido, se repre-sentara mediante en una secuencia de 1s y 0s, resultado de codicar cada uno de loscaracteres del mensaje mediante la tabla ASCII. Dicha secuencia sera sencillamente des-cifrable por cualquier equipo informatico, sin mas que aplicar de nuevo la tabla de con-version ASCII en sentido inverso. Resulta evidente que sin la existencia de estandares decodicacion, no sera posible compartir informacion entre los distintos ordenadores.

    3

  • Captulo 1. Introduccion a la computacion

    1.3 Concepto de algoritmo

    Un algoritmo es una secuencia o conjunto ordenado de operaciones que permiten hallarla solucion de un problema dado en un tiempo nito.

    Aunque los algoritmos datan de tiempos babilonicos y los griegos ya disenaron algorit-mos, aun famosos hoy en da, como por ejemplo el de Euclides (300 A.C.) para calcularel maximo comun divisor de dos numeros, fue el matematico persa Al-Khowarizmi (si-glo IX) el primero que diseno algoritmos pensando en su eciencia, en particular, para elcalculo de races de ecuaciones. La palabra algoritmo procede de las sucesivas deforma-ciones sufridas hasta hoy en da del nombre Al-Khowarizmi1.

    Como ejemplo mostraremos el famoso algoritmo de Euclides para obtener el maximocomun divisor de dos numeros enteros:

    1) Sean a y b dos enteros positivos.

    2) Comparar los dos numeros de forma que:

    3) Si son iguales, ese es el resultado. Finalizar.

    4) Si a es menor que b intercambiar los valores de a y b.

    5) Restar el segundo numero del primero y almacenar en a el sustraendo y en b elresiduo. Ir al paso 2.

    Si aplicamos esta secuencia de reglas a dos numeros enteros positivos, obtendremos elmaximo comun denominador de ambos. Por ejemplo, dados los valores a=5 y b=15, acontinuacion se muestra como evolucionan las variables a y b a medida que se ejecuta elalgoritmo propuesto, hasta llegar a obtener el valor del maximo comun divisor (5):

    a b------------5 1515 55 1010 55 5

    Todo algoritmo debe cumplir las 4 condiciones siguientes:

    Finitud: Un algoritmo tiene que acabar siempre tras un numero nito de pasos.1Hay muchas variantes para el nombre de Al Khowarizmi al usar el alfabeto latino, tales como Al-Khorezmi,

    Al-Khwarizmi, Al-Khawarizmi o Al-Khawaritzmi.

    4

  • 1.4 El proceso de la programacion

    Denibilidad: Toda regla debe denir perfectamente la accion a desarrollar sin quepueda haber ambiguedad alguna de interpretacion.

    General: Un algoritmo no debe solucionar un problema aislado particular, sinotoda una clase de problemas para los que los datos de entrada y los resultadosnales pertenecen respectivamente a conjuntos especcos.

    Ecacia: Se debe pretender que un algoritmo sea ecaz, esto es, que su ejecucionresuelva el problema en el mnimo numero de operaciones posible.

    Se dice que un determinado problema es decidible o computable cuando existe un algo-ritmo que lo resuelve. Existen, sin embargo, muchas clases de problemas no decidibles.Estos problemas, por mucho que aumente la capacidad y velocidad de los computadores,nunca podran resolverse.

    Un ejemplo tpico de problema no decidible es el problema de la teselacion. Una tesela(baldosa) es un cuadrado de 1x1, dividido en cuatro partes iguales por sus dos diagonales.Cada una de estas partes tiene un color. El problema es: dada cualquier supercie nita, decualquier tamano (con dimensiones enteras), puede recubrirse usando teselas de formaque cada dos teselas adyacentes tengan el mismo color en los lados que se tocan? Este esun problema indecidible: no se puede demostrar que la supercie pueda recubrirse segunel planteamiento del problema, pero tampoco puede demostrarse lo contrario. No existeningun algoritmo que resuelva este problema.

    1.4 El proceso de la programacion

    Un programa es la implementacion o escritura de un algoritmo en un lenguaje de progra-macion especco. Las fases para la correcta elaboracion de un programa son las siguien-tes:

    1. Analisis del problema: denir el problema de la manera mas precisa posible.

    2. Diseno del algoritmo: disenar un metodo (algoritmo) que resuelva el problemaplanteado.

    3. Codicacion: escribir (implementar) el algoritmo en un lenguaje de programacion.

    4. Vericacion: comprobacion del correcto funcionamiento del programa. Si no fun-ciona correctamente, dependiendo del error habra que volver al paso 3, al 2 o inclu-so al 1.

    5. Mantenimiento: desarrollo de mejoras y nuevas funcionalidades.

    Estas cinco fases es lo que se denomina el ciclo de vida de un proyecto informatico. Enocasiones el termino programacion se asocia, de forma incorrecta, unicamente al paso3, pero para desarrollar correctamente un programa es necesario abordar todas las fasesdescritas.

    5

  • Captulo 1. Introduccion a la computacion

    1.5 Lenguajes de programacion

    Un lenguaje de programacion es un conjunto de smbolos y palabras especiales que, juntocon unas reglas sintacticas perfectamente denidas, permiten implementar un algoritmo,de modo que este pueda ser ejecutado por un ordenador. En denitiva, un lenguaje deprogramacion permite construir un programa informatico.

    En general los lenguajes de programacion pueden dividirse en:

    Lenguajes de bajo nivel: Son lenguajes cuya sintaxis esta mas proxima a la maqui-na (al ordenador) que al humano. El lenguaje de mas bajo nivel es el codigo maqui-na (cuyas instrucciones son secuencias de unos y ceros), seguido por el lenguajeensamblador. Los lenguajes de bajo nivel resultan poco legibles para el humano.

    Lenguajes de alto nivel: Son lenguajes cuya sintaxis esta mas proxima al lenguajenatural de los humanos y, por tanto, resultan mas comprensibles. Existen multitudde lenguajes de alto nivel como C, C++, Java, Pascal, Basic, PHP, etc. (por citarsolo unos pocos ejemplos).

    A continuacion se muestra, a modo de ejemplo, un programa que realiza la suma dedos numeros enteros, escrito en tres lenguajes de programacion diferentes: C, Pascal yensamblador:

    Suma de dos numeros enteros en C:

    1 #include 2

    3 int main() {4 int a, b, c;5

    6 printf("Introduce 2 numeros enteros");7 scanf("%d%d", &a, &b);8 c = a + b;9 printf("La suma es %d\n", c);

    10 return 0;11 }

    Suma de dos numeros enteros en Pascal:

    1 program suma;2

    3 var a,b,c:integer;4 begin5 writeln(Introduce 2 numeros enteros);

    6

  • 1.6 El lenguaje C

    6 readln(a,b);7 c:= a + b;8 writeln(La suma es ,c);9 end

    Suma de dos numeros enteros en ensamblador:

    1 model small2 .stack3 .data4 var1 db ?5 .code6 .startup7 mov ah,01h8 int 21h9 sub al,30h

    10 mov var1,al11 mov ah,01h12 int 21h13 sub al,30h14 add al,var115 mov dl,al16 add dl,30h17 mov ah,02h18 int 21h19 ;.exit20 end

    1.6 El lenguaje C

    C es un lenguaje estructurado de alto nivel de proposito general. Esto quiere decir que sir-ve para distintos propositos: programas cientcos, programas de gestion, comunicacion,manejadores de dispositivos (drivers), sistemas operativos, compiladores, etc.

    C dispone de las estructuras tpicas de los lenguajes de alto nivel pero, a su vez, permitetrabajar a bajo nivel, por lo que algunos autores lo clasican como lenguaje de medionivel.

    El lenguaje C fue desarrollado en la decada de los 70 por Kenneth Thompson y DennisRitchie en los laboratorios Bell y alcanzo gran popularidad durante la decada de los 80tras la publicacion de su denicion por parte de Brian Kernighan y el propio Ritchie2. La

    2Brian W. Kernighan y Dennis M. Ritchie, The C Programming Languaje, Prentice-Hall, 1978.

    7

  • Captulo 1. Introduccion a la computacion

    creacion del lenguaje C va ligada a otro fenomeno de la informatica: la creacion del sis-tema operativo UNIX, desarrollado tambien en los laboratorios Bell. El nucleo (o kernel)del sistema operativo Unix esta escrito casi en su totalidad en lenguaje C, con excepcionde alguna parte escrita en ensamblador. Tambien el sistema operativo Linux y muchas desus aplicaciones estan escritas en este mismo lenguaje.

    Hoy en da el lenguaje C se sigue utilizando en multitud de programas. Ademas, muchosotros lenguajes de programacion basan su sintaxis en C, como C++, C#, Java, PHP, Perl,etc.

    1.7 Compiladores e interpretes

    Los ordenadores unicamente entienden el lenguaje maquina. Por tanto, un programa es-crito en cualquier otro lenguaje debe ser traducido a lenguaje maquina para que puedaser ejecutado. Este proceso de traduccion se conoce como compilacion o interpretacion,dependiendo de como se realice.

    El proceso de compilacion consiste en traducir el programa completamente a lenguajemaquina antes de ser ejecutado. La interpretacion, por contra, consiste en ir traduciendolas instrucciones una a una o en pequenos grupos, e ir ejecutandolas a medida que setraducen.

    Como puede deducirse, un programa compilado se ejecutara a mayor velocidad que unointerpretado, ya que en el primer caso la traduccion se hace una unica vez, de modo quese almacena en un archivo aparte el programa traducido (denominado codigo maquinao ejecutable) y a continuacion se ejecuta tantas veces como se desee el codigo maquinagenerado, mientras que en el segundo caso es necesario ir traduciendo las instruccionesdurante la propia ejecucion.

    El proceso de compilacion se realiza mediante un programa especial denominado compi-lador, mientras que el programa encargado de la interpretacion se denomina interprete.Un programa dado, dependiendo de el lenguaje en que este escrito, debera ser compiladoo interpretado. El lenguaje C requiere del proceso de compilacion.

    8

  • Captulo 2

    Elementos basicos de un programaen C

    2.1 Estructura basica de un programa en C

    Un programa escrito en lenguaje C tiene, en su forma mas sencilla, la siguiente estructurabasica:

    int main() {sentencia_1;sentencia_2;

    . . .sentencia_N;

    }

    Todo programa en C esta compuesto por una serie de instrucciones o sentencias1, se-paradas por punto y coma. Estas instrucciones se encuentran dentro de la funcion main.En el Captulo 4 se estudiaran en detalle las funciones, de momento es suciente conentender que una funcion es un modulo o bloque de nuestro programa que contiene unaserie de instrucciones y que la funcion main (funcion principal) es el punto de inicio detodo programa en C. Para delimitar el conjunto de instrucciones que contiene una funcion(main en nuestro caso) se utilizan los smbolos { y }.

    1A lo largo de este libro vamos a utilizar indistintamente los terminos instruccion y sentencia.9

  • Captulo 2. Elementos basicos de un programa en C

    El programa mas sencillo que se puede escribir en C es

    1 int main() {2 return 0;3 }

    aunque este programa no hara absolutamente nada ya que la unica instruccion que con-tiene (return 0) indica la nalizacion del mismo.

    2.2 Mostrando mensajes con printf

    El programa mas sencillo, y que ademas haga algo tangible, es aquel que muestra unmensaje por pantalla. Por ejemplo:

    1 #include 2

    3 int main() {4 printf("Hola");5 return 0;6 }

    Ya se ha dicho que la funcion main es el punto de inicio de cualquier programa en C, portanto la primera instruccion que se ejecuta en el programa anterior se encuentra en la lnea4 (mas adelante explicaremos la sentencia #include). La sentencia printf muestra untexto por pantalla, as que el resultado de ejecutar este programa sera simplemente

    Hola

    La sintaxis de printf, en su formato mas sencillo, es

    1 printf("Texto a mostrar");

    En el Apartado 2.5 se estudiaran otras formas de utilizar la sentencia printf.

    Ademas de la funcion main, vemos que en este programa aparece la instruccion

    1 #include

    Sin entrar en detalle, diremos que es necesario incluir esta instruccion para poder utilizarprintf en nuestros programas. En el Apartado 2.10 se explican este tipo de instrucciones

    10

  • 2.3 Variables y tipos de datos

    con mayor profundidad. De momento unicamente es necesario saber que cualquier pro-grama que utilice la instruccion printf debera contener al inicio del mismo la sentencia#include .

    La instruccion return 0 la pondremos habitualmente como ultima instruccion de la fun-cion main. En el Captulo 4 se estudiaran con detalle las funciones y se explicara el usode la instruccion return.

    2.3 Variables y tipos de datos

    Un programa esta compuesto por instrucciones y datos. Los datos, al igual que las ins-trucciones, se almacenan en la memoria del ordenador durante la ejecucion del programa.Cada dato ocupa una posicion de memoria, de modo que es posible consultar o modicarel valor de un dato mediante el acceso a la zona de memoria en la que esta almacenado.

    2.3.1 Variables

    Una variable puede verse como un contenedor donde almacenar un dato determinado. Enrealidad una variable representa una posicion de memoria en la que se encuentra almace-nado un dato. Las variables son un mecanismo que ofrecen los lenguajes de programacionpara facilitar el acceso a los datos sin necesidad de conocer las posiciones o direccionesde memoria en que se encuentran almacenados.

    Cuando se crea una variable se le asigna un nombre que la identica. Un nombre devariable puede constar de uno o mas caracteres y debe cumplir las siguientes restricciones:

    El primer caracter debe ser una letra o el caracter subrayado ( ), mientras que elresto pueden ser letras, dgitos o el caracter subrayado ( ). Las letras pueden serminusculas o mayusculas del alfabeto ingles. Por lo tanto, no esta permitido el usode las letras n, N, vocales acentuadas, smbolos especiales, etc.

    No pueden existir dos variables con el mismo nombre dentro de una misma funcion.

    El nombre de una variable no puede ser una palabra reservada. Las palabras re-servadas son identicadores propios del lenguaje. Por ejemplo, int y main sonpalabras reservadas del lenguaje C.

    Por ejemplo, lo siguiente seran nombres validos de variables: x, y, v1, v2, temperatura,velocidad_maxima, Vmax.

    Los siguientes nombres de variables no son validos: 1v, velocidad-maxima, Vmax,#tag.

    11

  • Captulo 2. Elementos basicos de un programa en C

    2.3.2 Tipos de datos

    Las variables se clasican en distintos tipos, segun la informacion que almacenan. Cuan-do se crea una variable, es necesario especicar a que tipo de dato pertenece, de estemodo se le asigna memoria suciente para almacenar valores del tipo especicado. EnC existen cinco tipos de datos basicos: numeros enteros, numeros reales con precisionsimple, numeros reales de doble precision, caracteres y punteros.

    El tipo de dato de una variable determina:

    El tamano (cantidad de bytes) que ocupara la variable en la memoria del ordenador.

    El rango de valores que la variable podra almacenar.

    El conjunto de operaciones que se puede realizar sobre dicha variable.

    En la Tabla 2.1 se muestran los tipos basicos en C, el tamano que ocupa cada uno de ellosen memoria y el rango de valores que pueden almacenar.2

    Tabla 2.1: Tipos de datos simples en C

    Tipo de dato Nombre del tipo en C Bytes RangoCaracter char 1 -127 a 128Entero int 4 -2147483648 a 2147483647Real float 4 3.4E-38 a 3.4E38Real (doble precision) double 8 1.7E-308 a 1.7E308Puntero (depende del tipo de puntero) 4 -

    Como puede observarse en la Tabla 2.1, el tipo char se puede utilizar tanto para represen-tar caracteres como numeros enteros pequenos. En la Seccion 2.8.1 se explica este tipo dedato con mas detalle. El tipo puntero se emplea para almacenar direcciones de memoria.En la Seccion 2.9 se explican los punteros.

    Los tipos char, int, float y double tambien existen en su version unsigned (sin signo):unsigned char, unsigned int, unsigned float y unsigned double. Las varia-bles de estos tipos unicamente pueden almacenar numeros positivos, pero con la ventajade duplicar el rango de la parte positiva. Por ejemplo, una variable de tipo unsigned charpuede almacenar numeros enteros entre 0 y 255.

    Algunos tipos de datos tambien admiten los modicadores short y long para disminuir yaumentar respectivamente el rango de valores (y consecuentemente el espacio de memoriaempleado). Por ejemplo, una variable de tipo short int ocupa 2 bytes (en lugar de los 4que ocupa el int) y permite almacenar valores entre -32768 y 32768. Una variable de tipo

    2En realidad el tamano y rango de valores pueden variar en funcion de la implementacion. Los valores dadosson los habituales en un ordenador con arquitectura de 32 bits.

    12

  • 2.3 Variables y tipos de datos

    unsigned short int ocupa igualmente 2 bytes, pero en este caso puede almacenarvalores entre 0 y 65535.

    2.3.3 Uso de variables: declaracion y asignacion

    Antes de poder utilizar una variable en un programa hay que declararla. Para ello seemplea la siguiente sintaxis:

    tipo_de_dato nombre_variable;

    Por ejemplo, para declarar una variable de tipo int y nombre x utilizaramos la siguientesentencia:

    1 int x;

    Si se desea declarar mas de una variable del mismo tipo, puede hacerse separandolas porcomas del siguiente modo:

    1 int x, y, z;2 float a, b;

    Las variables pueden declararse:

    Al inicio de cada funcion (por ejemplo de la funcion principal main). A estas va-riables se las denomina variables locales.

    Fuera de las funciones. A estas variables se las denomina variables globales.

    Salvo en casos muy excepcionales, no se recomienda el uso de variables globales. Enla Seccion 4.4 se explica con mas detalle la diferencia entre ambos tipos de variables.De momento, unicamente emplearemos variables locales y, por tanto, la variable x delejemplo anterior la declararamos al inicio de la unica funcion que hasta el momentohemos visto: main.

    1 int main() {2 int x;3

    4 . . .5 }

    13

  • Captulo 2. Elementos basicos de un programa en C

    Para almacenar una valor en una variable se utiliza la operacion de asignacion. En ellenguaje C la asignacion se realiza mediante la operacion =. Por ejemplo, el siguienteprograma declara una variable real de nombre pi y le asigna el valor 3.14;

    1 int main() {2 float pi;3 pi = 3.14;4

    5 . . .6 }

    En la operacion de asignacion, a la izquierda del smbolo = se debe poner siempre elnombre de la variable que recibe el valor y a la derecha el valor que deseamos almacenaro una operacion cuyo resultado sea un valor.

    Por ejemplo la siguiente operacion de asignacion es incorrecta:

    1 3.14 = pi;

    Obviamente el valor que recibe la variable debe de ser compatible con el tipo de dato dela misma. Por ejemplo, no sera adecuado declarar una variable de tipo int y tratar dealmacenar en ella un valor real, tal y como muestra el siguiente ejemplo:

    1 int main() {2 int x;3 x = 2.75;4

    5 . . .6 }

    En este caso en la operacion de asignacion se producira el truncamiento del numero realde modo que en la variable x se almacenara el valor 2 en lugar de 2.7.

    Tambien es posible almacenar en una variable el resultado de una operacion (o expre-sion). El siguiente programa almacena en una variable de nombre area el resultado demultiplicar 3.14 por 4.

    1 int main() {2 float area;3 area = 3.14 * 4;4

    5 . . .6 }

    14

  • 2.3 Variables y tipos de datos

    En las operaciones tambien pueden aparecer variables. En este caso la variable que for-ma parte de la operacion se sustituye por su valor. Por ejemplo, el siguiente programaalmacena en la variable perim el resultado de la operacion 2 3,14 3.

    1 int main() {2 float pi, radio, perim;3 pi = 3.14;4 radio = 3;5 perim = 2 * pi * radio;6

    7 . . .8 }

    De forma generica, la operacion de asignacion tiene siempre la siguiente estructura:

    1 nombre_variable = expresion;

    donde expresion puede ser un valor constante (por ejemplo x=2), una variable (porejemplo x=y), una operacion (por ejemplo x=2*y), etc. En la Seccion 2.7 se explica conmas detalle el concepto de expresion. El efecto de la operacion de asignacion sera alma-cenar en nombre_variable el resultado de expresion.

    Es muy importante tener la precaucion de que cuando se utilice una variable como partede una expresion, dicha variable tenga un valor asignado previamente, de lo contrario elresultado de la expresion sera impredecible. Por ejemplo el siguiente programa, aunquees sintacticamente correcto, su resultado es impredecible:

    1 int main() {2 float pi, radio, perim;3 pi = 3.14;4 perim = 2 * pi * radio;5 radio = 3;6

    7 . . .8 }

    Debe entenderse que las instrucciones de un programa se ejecutan secuencialmente, co-menzando con la primera. El error del ejemplo anterior radica en que cuando se ejecuta lainstruccion perim = 2 * pi * radio el valor de la variable radio es desconocido,ya que todava no se le ha asignado nada. En consecuencia, el resultado almacenado enperim sera impredecible. El hecho de ejecutar posteriormente la instruccion radio=3 yano cambia para nada el valor almacenado en perim.

    15

  • Captulo 2. Elementos basicos de un programa en C

    El que a una variable no le asignemos nada de forma explcita no quiere decir que nocontenga ningun valor, sino que este es desconocido. En el momento de declarar unavariable, esta ya contiene un valor, resultado de lo que hubiese previamente en la zona dememoria que se le asigna, sin embargo, como se ha dicho, este valor es impredecible.

    La operacion de asignacion es destructiva. Esto quiere decir que cuando a una variablese le asigna un valor, pierde el valor que tuviera anteriormente.

    2.4 Comentarios

    En un programa es posible (y recomendable) introducir comentarios. Un comentario esun texto que incluimos en nuestros programas pero que el compilador ignora por com-pleto. El objetivo de los comentarios es hacer los programas mas legibles, ayudando a lacomprension de los mismos.

    En C existen dos modos de anadir comentarios:

    Para anadir un comentario de parrafo se encierra el texto a comentar entre lossmbolos /* y */. Un comentario de parrafo puede contener mas de una lnea. Porejemplo:

    1 /* Este programa calcula el area de un crculo2 dado su radio */3 int main() {4 float area, radio;5 . . .6 }

    Para anadir un comentario de lnea se utiliza //. El texto que aparece desde //hasta el nal de la lnea es ignorado por el compilador. Por ejemplo:

    1 int main() {2 // Declaracion de variables3 float r; // Radio del crculo4 float a; // Area del crculo5

    6 a = 3.14 * r * r;7 . . .8 }

    16

  • 2.5 Uso avanzado de printf

    2.5 Uso avanzado de printf

    En la Seccion 2.2 se ha explicado como mostrar un texto simple con printf. En ocasio-nes, junto con el texto, necesitaremos mostrar el valor de alguna variable. Tomemos comoejemplo el siguiente programa que calcula la suma de dos variables y muestra de formaincorrecta el resultado:

    1 #include 2

    3 int main() {4 int a, b, c;5

    6 a = 2;7 b = 3;8 c = a + b;9 printf("La suma de a y b es c");

    10 return 0;11 }

    El error del programa anterior radica en que la instruccion printf, tal y como se haescrito, mostrara literalmente el texto especicado. Esto es, la ejecucion de este programamostrara por pantalla el mensaje:

    La suma de a y b es c

    Si lo que se pretenda es que el programa mostrase

    La suma de 2 y 3 es 5

    entonces la instruccion printf se debera haber escrito del siguiente modo:

    1 printf("La suma de %d y %d es %d", a, b, c);

    Podemos observar que en la instruccion printf aparece en primer lugar un texto ence-rrado entre dobles comillas, seguido de una serie de variables separadas por comas. Eltexto encerrado entre comillas contiene una serie de codigos especiales %d. Los codigos %(existen mas aparte de %d) indican que esta parte del texto debe ser sustituida por el valorde alguna expresion (una variable en el caso mas sencillo). Concretamente, el codigo %dindica que, en la posicion en la que aparece, debe mostrarse el valor de una expresion quede como resultado un valor entero (por ejemplo una variable de tipo int). La expresiono variable a mostrar sera alguna de las que aparezcan a continuacion del texto encerra-

    17

  • Captulo 2. Elementos basicos de un programa en C

    do entre comillas. La asociacion entre los codigos % y las expresiones que aparecen acontinuacion se hace por orden de aparicion. En consecuencia, en el ejemplo anterior, elprimer codigo %d se asocia a la variable a, el segundo a la variable b y el tercero a c.Debe observarse que es necesario que la instruccion printf contenga tantas expresiones(variables en el ejemplo anterior) como codigos %.

    En la Tabla 2.2 se muestra los codigos % (especicadores) que pueden aparecer en unainstruccion printf. En la primera parte de la tabla se muestran los que se usan de formamas habitual y en los que, de momento, nos centraremos.

    Tabla 2.2: Especicadores mas habituales.

    Especicador Tipo de expresion con que se asocia%d o %i Entero%f Real%c Caracter%u Entero sin signo

    %x o %X Entero (se muestra en notacion hexadecimal)%o Entero (se muestra en notacion octal)

    %e o %E Real de doble precision (se muestra en notacion exponencial)%g o %G Real de doble precision (se muestra en notacion cientca)%s Cadena de caracteres (string)

    Ademas de los especicadores mostrados en la Tabla 2.2, el texto de una instruccionprintf puede contener otras secuencias de caracteres que se interpretan de un modoespecial:

    \n: Se sustituye por un salto de lnea

    \t: Se sustituye por un tabulador

    \\: Muestra el caracter \

    A continuacion se muestra un ejemplo del uso de printf:

    1 #include 2

    3 int main() {4 int entero = 47;5 float real = 128.75;6 char car = A;7

    8 printf("Este texto aparece en la primera lnea.");9 printf("Este tambien.\nAhora en la segunda.\n");

    10 printf("\tEsto aparece tabulado.\n");

    18

  • 2.6 Leyendo datos con scanf

    11 printf("Mostramos el caracter \\.\n");12 printf("Variable entera: %d\n", entero);13 printf("Variable real: %f\n", real);14 printf("Variable de tipo caracter: %c\n", car);15 printf("Variable entera en hexadecimal: %X\n", entero);16 printf("Variable entera en octal: %o\n", entero);17 printf("Variable real en notacion exponencial: %E\n",real);18 printf("Variable real en notacion cientfica: %G\n", real);19

    20 return 0;21 }

    El ejemplo anterior produce la siguiente salida:

    Este texto aparece en la primera lnea.Este tambien.Ahora en la segunda.

    Esto aparece tabulado.Mostramos el caracter \.Variable entera: 47Variable real: 128.750000Variable de tipo caracter: AVariable entera en hexadecimal: 2FVariable entera en octal: 57Variable real en notacion exponencial: 1.287500E+02Variable real en notacion cientfica: 128.75

    2.6 Leyendo datos con scanf

    Habitualmente es necesario que sea el usuario del programa quien introduzca los datos.La instruccion scanf permite almacenar en variables los datos que el usuario introduce atraves del teclado. La sintaxis de esta instruccion es la siguiente:

    scanf("especificadores", lista_de_variables);

    donde especificadores contiene una secuencia de codigos % (tantos como datos sequieran introducir) y lista_de_variables contiene la lista de variables, separadas porcoma, donde se almacenaran los datos. Cada una de estas variables debe ir precedida porel smbolo & (salvo en algun caso especial que ya se comentara en la Seccion 5.11). Losespecicadores o codigos % que usaremos de momento en la instruccion scanf seran %d(o su equivalente %i), %f y %c para leer variables de tipo entero, real o caracter respecti-vamente.

    Por ejemplo, la siguiente instruccion almacena en la variable x un numero que el usuariodebe introducir por teclado:

    19

  • Captulo 2. Elementos basicos de un programa en C

    1 scanf("%d", &x);

    En este caso la variable x debera ser de tipo int.

    El porque las variables deben ir precedidas por el smbolo & es algo que se vera en laSeccion 2.9. De momento basta con saber que es necesario hacerlo de este modo.

    Cuando se ejecuta una instruccion scanf el programa se detiene en espera de que elusuario introduzca los datos necesarios (debe pulsarse la tecla enter para nalizar la intro-duccion). En el momento en que los datos han sido introducidos, estos se almacenan en lasvariables especicadas y el programa continua. A continuacion se muestra un programacompleto que solicita dos numeros y los suma:

    1 #include 2

    3 int main() {4 float a, b, c;5

    6 printf("Introduzca un numero: ");7 scanf("%f", &a);8 printf("Introduzca otro numero: ");9 scanf("%f", &b);

    10 c = a + b;11 printf("La suma es %f\n", c);12 return 0;13 }

    Como se puede observar en el programa anterior, es habitual que cada instruccion scanfvaya precedida de un printf para indicar al usuario de lo que debe hacer.

    Tambien es posible leer mas de un dato con una unica instruccion scanf. Por ejemplo:

    1 printf("Introduzca dos numeros: ");2 scanf("%f%f", &a, &b);

    En este caso el programa se detendra en la instruccion scanf hasta que el usuario hayaintroducido los dos valores.

    20

  • 2.7 Expresiones

    2.7 Expresiones

    Una expresion es una combinacion de constantes, variables, smbolos de operacion, parente-sis y funciones. Por ejemplo, lo siguiente son expresiones validas en C:

    1 a-(b+3)*c2 2*3.1416*r3 sin(x)/2

    En la ultima expresion del ejemplo aparece una llamada a la funcion seno (sin). Las fun-ciones se estudiaran en el Captulo 4.

    Las expresiones se evaluan a un valor determinado, esto es, el resultado de una expre-sion siempre es un valor (entero o real). Las expresiones en C pueden clasicarse en trescategoras:

    Aritmeticas

    Relacionales

    Logicas

    En los siguientes apartados se explica cada una de ellas.

    2.7.1 Expresiones aritmeticas

    Las expresiones aritmeticas son aquellas que utilizan los operadores +, -, *, / y %. Elresultado de una expresion aritmetica es un valor entero o real.

    El operador * representa la multiplicacion. El operador / realiza la division, si bien debellevarse especial cuidado con esta operacion ya que, dependiendo de los operandos, rea-lizara la division entera o la real. Si al menos uno de los dos operandos es un valor real,entonces se hara la division real, pero si ambos operandos son enteros se realizara la di-vision entera. Por ejemplo, el resultado de la expresion 5 / 2 es 2 (division entera) y no2.5 (division real) ya que tanto 5 como 2 son numeros enteros. Sin embargo, el resultadode 5.0 / 2 es 2.5 ya que, en este caso, alguno de los operandos (el primero de ellos eneste ejemplo) es un numero real.

    El operador % realiza la operacion modulo o resto de la division entera. Por ejemplo11 % 3 = 2 ya que la division entera de 11 y 3 da cociente 3 y resto 2. En general, elresultado de a % b sera un numero comprendido entre 0 y b-1, ya que el resto debe de sernecesariamente menor que el divisor. La operacion modulo unicamente puede realizarseentre numeros enteros y puede ser util para diversas situaciones. Por ejemplo, para obtenerla ultima cifra de un numero n basta con hacer n % 10 (por ejemplo, 127 % 10 = 7). Si

    21

  • Captulo 2. Elementos basicos de un programa en C

    se desean las dos ultimas cifras habra que hacer n % 100 (127 % 100 = 27). Para sabersi un numero n es par o impar habra que calcular n % 2. Si el resultado de esta operaciones 0 quiere decir que n es par, mientras que si el resultado es 1 signicara que n es impar.

    Para evaluar las expresiones aritmeticas existen unas reglas de prioridad y asociatividad:

    Las operaciones entre parentesis se evaluan primero.

    Los operadores *, / y % se evaluan antes (tienen mayor prioridad) que + y -.

    Los operadores de igual prioridad se evaluan de izquierda a derecha.

    Por ejemplo, el resultado de 3 + 2 * 4 es 11 (se realiza en primer lugar la multiplica-cion) mientras que (3 + 2) * 4 da 20 (se realiza en primer lugar la suma).

    Operadores de incremento y decremento

    Los operadores ++ y -- sirven, respectivamente, para incrementar y decrementar en unaunidad el valor de una variable. Por ejemplo, n++ incrementa en uno el valor de la varia-ble n, mientras que n-- lo decrementa. Como puede observarse, se trata de operadoresunarios (unicamente tienen un operando).

    La operacion n++ es equivalente a n = n + 1 (se calcula n + 1 y el resultado sealmacena en la propia variable n, lo que provoca que el valor de n acabe incrementandoseen 1). De forma analoga, n-- es equivalente a n = n - 1.

    Tambien es posible escribir el operador antes del operando (++n y --n). Esto no introduceninguna diferencia cuando la operacion se hace de forma aislada, aunque es importantetenerlo en cuenta cuando esta operacion se combina con otras dentro de la misma ex-presion, ya que modica el orden en el que se realiza el incremento o decremento. Porejemplo x / y++ calcula primero la division x / y y a continuacion incrementa la va-riable y, mientras que x / ++y incrementa en primer lugar el valor de y y a continuacionrealiza la division (con el valor de y ya incrementado).

    Operadores reducidos

    Los operadores reducidos mas habituales son +=, -=, *= y /=. Estos operadores permitenexpresar de forma mas compacta algunas operaciones. Por ejemplo, x += 2 equivale ala operacion x = x + 2 (esto es, incrementa el valor de la variable x en dos unidades).x *= 5 equivale a la operacion x = x * 5.

    A continuacion se muestra un ejemplo con el uso de las operaciones aritmeticas vistas:

    22

  • 2.7 Expresiones

    1 #include 2

    3 int main() {4 int x, y, z;5

    6 x = 6;7 x--; // x vale 58 y = x / 2; // y vale 2 (se realiza la division entera)9 z = y++; // z vale 2 e y vale 3 (primero se realiza

    10 // la asignacion y luego el incremento)11 x += 3; // x vale 812 x *= 2; // x vale 1613 z = x % 7; // z vale 2 (el resto de dividir 16 entre 7)14

    15 return 0;16 }

    2.7.2 Expresiones relacionales

    Las expresiones relacionales son aquellas que comparan valores. Para ello se utilizan losoperadores =, == y != (que se corresponden, respectivamente, con las opera-ciones menor, menor o igual, mayor, mayor o igual, igual y distinto). El resultado de unaexpresion relacional es 1 cuando el resultado de la comparacion es cierto y 0 cuando elresultado es falso. Por ejemplo, dado x = 5, el resultado de la operacion x >= 5 es 1(cierto) y el de x != 5 es 0 (falso).

    No debe confundirse la operacion de comparacion == con la operacion de asignacion =(explicada en la Seccion 2.3.3). Por ejemplo, la expresion x==5 comprueba si la variablex vale 5. En caso armativo el resultado de esta expresion sera 1 y de lo contrario dara 0.Por contra, la operacion x=5 almacena el valor 5 en la variable x.

    2.7.3 Expresiones logicas

    Las expresiones logicas son aquellas que utilizan los operadores logicos &&, ||, y !, loscuales se corresponden, respectivamente, con las operaciones Y, O y NO (AND, ORy NOT). Las expresiones logicas permiten combinar otras expresiones cuyo resultado esverdadero/falso (1/0). A su vez, el resultado de una expresion logica es 1 (verdadero) o 0(falso).

    Por ejemplo, dadas las variables a=5 y b=2:

    a != 0 && b >= a (a distinto de cero y b mayor o igual que a) se evalua a 0(falso).

    23

  • Captulo 2. Elementos basicos de un programa en C

    a == 4 || a+b < 8 (a igual a cuatro o a+bmenor que ocho) se evalua a 1 (cierto).

    !(b > a) (no b mayor que a) se evalua a 1 (cierto).

    Los siguientes puntos resumen el uso de los operadores logicos:

    exp1 && exp2 se evalua a cierto cuando tanto exp1 como exp2 son ciertas. Encualquier otro caso se evalua a falso.

    exp1 || exp2 se evalua a cierto cuando alguna de las expresiones exp1 o exp2son ciertas. Se evalua a falso cuando tanto exp1 como exp2 son falsas.

    !exp1 se evalua a cierto cuando exp1 es falso y viceversa.

    Estos tres puntos se resumen en la Tabla 2.3 denominada taba de verdad.

    Tabla 2.3: Tabla de verdad de los operadores logicos.

    exp1 exp2 exp1 && exp2 exp1 || exp2 !exp10 0 0 0 10 1 0 1 11 0 0 1 01 1 1 1 0

    2.8 Otros conceptos sobre tipos de datos

    2.8.1 El tipo char

    Como se ha visto en la Seccion 2.3.2, el lenguaje C utiliza el tipo char para almacenarcaracteres. En realidad el ordenador trabaja unicamente con numeros, por lo que cadacaracter se representa mediante un numero. Esto es, el tipo char realmente almacenanumeros, los cuales pueden ser interpretados como caracteres.

    La interpretacion de que caracter hay almacenado en una variable de tipo char se realizamediante una tabla de conversion. La tabla mas conocida (por ser la primera que aparecio)es el estandar ASCII (American Standard Code for Information Interchange). En la Ta-bla 2.4 se muestra la tabla ASCII. En esta tabla, los codigos del 0 al 31 en realidad no soncaracteres imprimibles sino que representan codigos de control (por ejemplo, el codigo13 representa el salto de lnea o Carriage Return, mientras que el codigo 27 representala tecla Escape). Entre el 65 y el 90 se codican las letras mayusculas, mientras que lasminusculas ocupan los codigos del 97 al 122. Los caracteres numericos (dgitos del 0 al9) aparecen entre los codigos 48 al 57.

    24

  • 2.8 Otros conceptos sobre tipos de datos

    Tabla 2.4: Tabla ASCII

    0 NUL 16 DLE 32 SP 48 0 64 @ 80 P 96 112 p1 SOH 17 DC1 33 ! 49 1 65 A 81 Q 97 a 113 q2 STX 18 DC2 34 50 2 66 B 82 R 98 b 114 r3 ETX 19 DC3 35 # 51 3 67 C 83 S 99 c 115 s4 EOT 20 DC4 36 $ 52 4 68 D 84 T 100 d 116 t5 ENQ 21 NAK 37 % 53 5 69 E 85 U 101 e 117 u6 ACK 22 SYN 38 & 54 6 70 F 86 V 102 f 118 v7 BEL 23 ETB 39 55 7 71 G 87 W 103 g 119 w8 BS 24 CAN 40 ( 56 8 72 H 88 X 104 h 120 x9 HT 25 EM 41 ) 57 9 73 I 89 Y 105 i 121 y10 LF 26 SUB 42 * 58 : 74 J 90 Z 106 j 122 z11 VT 27 ESC 43 + 59 ; 75 K 91 [ 107 k 123 {12 FF 28 FS 44 , 60 < 76 L 92 \ 108 l 124 |13 CR 29 GS 45 - 61 = 77 M 93 ] 109 m 125 }14 SO 30 RS 46 . 62 > 78 N 94 110 n 126 15 SI 31 US 47 / 63 ? 79 O 95 _ 111 o 127 DEL

    Debe aclararse que la tabla ASCII se denio para 7 bits, lo que permite representar 128caracteres. Esto es insuciente para muchas lenguas que utilizan caracteres que no estanrepresentados en esta tabla (vocales acentuadas, N, C, etc.). Por ello se denieron otrosestandares de 8 bits que permitan extender el numero de caracteres a 256 (por ejemplo elISO-8859-1).

    En C los caracteres deben encerrarse entre comillas simples. Por ejemplo, para almacenarel caracter A en una variable lo haremos del siguiente modo:

    1 char c;2 c = A;

    Dado que las variables de tipo char realmente almacenan numeros, es posible realizaroperaciones aritmeticas con este tipo de variables, tal y como se muestra en el siguienteprograma:

    1 #include 2

    3 int main() {4 char c;5

    6 c = A; // Almacena en c el numero 65 (codigo7 // ascii de la letra A)8 printf("%d\n", c); // Imprime el numero 659 printf("%c\n", c); // Imprime la letra A

    10 c += 5; // Almacena en c el numero 7011 printf("%d\n", c); // Imprime el numero 7012 printf("%c\n", c); // Imprime una F (cuyo codigo ascii es 70)

    25

  • Captulo 2. Elementos basicos de un programa en C

    13 c = 68; // Almacena en c el numero 6814 c++; // c vale 6915 printf("%d\n", c); // Imprime el numero 6916 printf("%c\n", c); // Imprime la letra E17 c = 2; // Almacena en c el numero 50 (codigo18 // ascii del caracter 2)19 printf("%d\n", c); // Imprime el numero 5020 printf("%c\n", c); // Imprime el caracter 221

    22 return 0;23 }

    2.8.2 Conversion de tipos: casting

    En ocasiones se utilizan expresiones en las que no todos los datos son del mismo tipo.Imaginemos el siguiente codigo:

    1 float f;2 f = 5;

    La instruccion f = 5 asigna un valor entero a una variable de tipo real, produciendoseuna conversion de entero a real. En este caso se produce una conversion sin perdida deprecision. Otras conversiones, sin embargo, pueden conllevar perdida de precision, tal ycomo se muestra en el siguiente codigo:

    1 float radio = 2.5;2 int area;3 area = 3.1416 * r * r;

    En este caso el resultado de la operacion 3.1416 * r * r se convierte a entero pa-ra poder almacenarlo en la variable area, de tipo int, con la consiguiente perdida deprecision.

    Si ordenamos los tipos de datos de menor a mayor capacidad (char, int, float, double),cualquier conversion de un tipo de menor capacidad a otro de mayor puede realizarse sinperdida de precision, mientras que una conversion en el otro sentido (de mayor a menorcapacidad) puede conllevar perdida de informacion. El compilador realiza de forma au-tomatica estos cambios de tipo, si bien en los casos que impliquen perdida de informacionpuede generar un warning para advertir al programador del posible error.

    En ocasiones es el propio programador el que desea hacer esta conversion de formaexplcita, bien para dejar claro que desea hacer la conversion y evitar los posibles war-nings dados por el compilador, bien para forzar un cambio de tipo en aquellos casos en los

    26

  • 2.8 Otros conceptos sobre tipos de datos

    que el compilador no la hara de forma automatica. Esta conversion explcita se conocepor el nombre de casting. Para realizar el cambio de tipo de una expresion debe escribir-se el nuevo tipo entre parentesis a la izquierda de la expresion, tal y como se muestra acontinuacion::

    1 float radio = 2.5;2 int area;3 area = (int)(3.1416 * r * r);

    Mediante esta conversion explcita el programador deja claro que es consciente del cam-bio de tipo que se va a producir, con la consecuente perdida de precision.

    Tambien hay ocasiones en las que se desea forzar un cambio de tipo ya que el compiladorno lo hace de manera automatica. Tomemos el siguiente ejemplo:

    1 int suma=5, n=2;2 float media;3 media = suma/n;

    En este caso el valor almacenado en media sera 2.0 y no 2.5. Esto es debido (tal y comose explico en la Seccion 2.7.1) a que la operacion suma/n realiza la division entera, yaque ambos operandos (suma y n) son enteros. El hecho de que el resultado se almaceneposteriormente en una variable de tipo float no cambia para nada la situacion ya que eneste caso la perdida de precision se produce en la propia operacion de division y no en laposterior asignacion. Para solucionar este problema debera forzarse el cambio de tipo deal menos uno de los operandos para que se realice la division real, tal y como se muestraa continuacion:

    1 int suma=5, n=2;2 float media;3 media = (float)suma/n;

    En este caso la variable suma se cambia temporalmente a tipo float, con lo que serealiza la division real. Debe quedar claro que este cambio de tipo afecta unicamentea la operacion en la que aparece el casting, en el resto del programa la variable sumaseguira siendo de tipo entero.

    27

  • Captulo 2. Elementos basicos de un programa en C

    2.9 Punteros

    La memoria del ordenador puede verse como una serie de celdas en las que se almacena lainformacion. Cada una de estas celdas tiene asociada una direccion de memoria. Cuandodeclaramos una variable (por ejemplo int x), a esta se le asigna una celda de memoriacon una direccion conocida. Hasta ahora no nos habamos preocupado por la direccionde memoria en la que se ubican nuestras variables, nos bastaba con conocer su nombrepara poder acceder al dato almacenado en las mismas. Este es el momento de empezar apreguntarnos en que direccion se encuentran las variables de nuestros programas.

    Una variable de tipo puntero es una variable que almacena direcciones de memoria. Nor-malmente se utilizan para almacenar la direccion de memoria en la que se encuentraalguna otra variable. Cuando una variable de tipo puntero (por ejemplo p) contiene ladireccion de memoria de alguna otra variable (por ejemplo x) decimos que el puntero papunta a la variable x. Como veremos mas adelante, una variable de tipo puntero de-be conocer el tipo de dato de la variable a la cual apunta (o, en general, el tipo de datoalmacenado en la direccion de memoria que contiene).

    2.9.1 Declaracion

    Para declarar una variable de tipo puntero se emplea la siguiente sintaxis:

    tipo_del_dato_apuntado * nombre_del_puntero;

    Por ejemplo

    1 int * p;

    declara una variable puntero de nombre p que debe utilizarse para almacenar direccionesde memoria en las que se encuentren datos de tipo int.

    2.9.2 El operador de direccion &

    El operador de direccion & (tambien llamado de referencia) obtiene la direccion de me-moria de una variable. Por ejemplo, dada una variable x, la operacion &x obtiene la di-reccion de memoria donde se encuentra x, tal y como se muestra en el siguiente ejemplo:

    1 #include 2

    3 int main() {4 int x = 3;5 printf("La variable x contiene el valor %f y se encuentra en

    la direccion %d\n", x, &x);

    28

  • 2.9 Punteros

    6 return 0;7 }

    Si quisieramos almacenar la direccion de x en otra variable, entonces esta otra variabledebera ser de tipo puntero, tal y como se muestra en el siguiente ejemplo:

    1 #include 2

    3 int main() {4 int x = 3;5 int * p; // Declaramos una variable de tipo puntero a

    entero6 p = &x; // Guardamos en p la direccion de memoria de la

    variable x7 printf("La variable x contiene el valor %f y se encuentra en

    la direccion %d\n", x, p);8 return 0;9 }

    2.9.3 El operador de indireccion *

    El operador de indireccion * (tambien llamado de deferencia) se aplica sobre punteros ydevuelve el valor de la variable apuntada por el puntero. A continuacion se muestra unejemplo:

    1 #include 2

    3 int main() {4 int x = 3, y;5 int * p; // Declaramos una variable de tipo puntero a

    entero6 p = &x; // Guardamos en p la direccion de x7 y = *p; // Almacenamos en y el valor de la variable8 // apuntada por p, esto es, el valor de x9 *p = 2; // Ahora x vale 2

    10 p = &y; // p contiene la direccion de y (p apunta a y)11 *p = 5 * 3; // Ahora y vale 1512 return 0;13 }

    En general, si un puntero p contiene la direccion de cierta variable x (p=&x), entonces laexpresion *p equivale a x. Por ejemplo, la operacion *p=2 es equivalente a x=2.

    29

  • Captulo 2. Elementos basicos de un programa en C

    Como puede verse, el operador * tiene tres usos distintos en C:

    Para declarar variables de tipo puntero. Por ejemplo, int * p;

    Como operador de indireccion. Por ejemplo, *p = 2;

    Como operador de multiplicacion. Por ejemplo, 5 * 3;

    Como puede observarse en el ejemplo anterior, la instruccion *p = 5 * 3 utiliza el *con dos signicados distintos.

    El porque nos interesa almacenar la direccion de una variable en un puntero y luego ac-ceder a dicha variable a traves de su puntero en lugar de utilizar su propio nombre es algoque a estas alturas es difcil de explicar, aunque debe decirse que es de gran importan-cia entender el manejo de punteros para poder entender en profundidad muchos aspectosde la programacion. De forma muy simplicada diremos que en ocasiones puede haberalguna parte de un programa en la que lo unico que se conozca de algunas variables sealas direcciones de memoria que ocupan pero no sus nombres (los cuales pueden inclu-so ni existir). En estos casos el unico modo de acceder a dichas variables es medianteel manejo de punteros. De momento basta con entender la sintaxis y manejo de punte-ros, en captulos posteriores, en la Seccion 4.5.2, se vera una situacion en la que resultanimprescindibles.

    2.9.4 La constante NULL

    Una variable de tipo puntero, ademas de direcciones de memoria, tambien puede almace-nar la constante NULL. Este valor sirve para indicar que el puntero no contiene ningunadireccion de memoria valida. Por ejemplo:

    1 int * p;2 p = NULL; // p no contiene ninguna direccion de memoria

    Para poder utilizar la constante NULL debe incluirse el chero stdlib.h mediante lainstruccion

    1 #include

    30

  • 2.10 Directivas del precompilador

    2.10 Directivas del precompilador

    El precompilador es un programa que analiza y modica el chero fuente antes de lacompilacion real, en funcion de ciertas directivas de compilacion que podemos incluir ennuestros programas. Todas las directivas de compilacion comienzan por el caracter # (porejemplo, #include) y, a diferencia de las sentencias de C, no llevan punto y coma alnal. El precompilador, ademas, elimina todos los comentarios del codigo fuente, ya queestos no forman parte del lenguaje y por tanto no seran entendidos por el compilador. Acontinuacion se explican las directivas #include y #define que utilizaremos de formahabitual en nuestros programas:

    2.10.1 Incluir cheros de cabecera: #include

    La directiva #include se utiliza para incluir en nuestro chero fuente el contenido deotros cheros. Habitualmente los cheros que se incluyen son los denominados cherosde cabecera (header les). La sintaxis empleada es:

    #include

    o

    #include "fichero"

    Por ejemplo, la siguiente directiva incluye el chero de cabecera stdio.h

    1 #include

    El chero stdio.h (standard input output header) contiene el codigo necesario para quese compilen correctamente todas las funciones relacionadas con la entrada/salida (inpu-t/output) de nuestro programa, como por ejemplo printf y scanf. En la Seccion 4.3.5se explica con mas detalle los cheros de cabecera.

    La diferencia entre utilizar los corchetes angulados () y las dobles comillas ("...")radica en que, en el primer caso, el chero incluido sera buscado en los directorios queel compilador tenga congurados a tal efecto, mientras que en el segundo caso el cheroincluido sera buscado en el mismo directorio en el que se encuentra el chero fuente.

    31

  • Captulo 2. Elementos basicos de un programa en C

    2.10.2 Denicion de constantes: #dene

    La directiva #define se emplea para denir constantes (en realidad tambien para denirmacros, aunque nosotros no la emplearemos con esta nalidad). La sintaxis empleada es:

    #define nombre_constante valor

    Por ejemplo, la directiva

    1 #define PI 3.1416

    dene la constante PI con el valor especicado. Una vez denida una constante, estapuede utilizarse a lo largo de todo el programa:

    1 #include 2 #define PI 3.14163

    4 int main() {5 float radio, perim;6

    7 printf("Introduce valor del radio: ");8 scanf("%f", &radio);9 perim = 2 * PI * radio;

    10 printf("El permetro de la circunferencia es %f\n", perim);11 return 0;12 }

    En este caso el precompilador buscara el texto PI como parte de alguna expresion y losustituira por 3.1416, de modo que cuando se inicie el proceso de compilacion la lnea

    1 perim = 2 * PI * radio;

    habra sido sustituida por

    1 perim = 2 * 3.1416 * radio;

    32

  • 2.11 Ejercicios resueltos

    2.11 Ejercicios resueltos

    1. Escribir un programa que solicite la base y la altura de un rectangulo y muestre porpantalla el area y el permetro.

    SOLUCION:

    1 #include 2

    3 int main() {4 float base, alt, area, perim;5

    6 // Pedir datos de entrada7 printf("Introduce la base: ");8 scanf("%f", &base);9 printf("Introduce la altura: ");

    10 scanf("%f", &alt);11

    12 // Calcular resultados13 area = base * alt;14 perim = 2*base + 2*alt;15

    16 // Mostrar resultados17 printf("Area = %f\n", area);18 printf("Permetro = %f\n", perim);19

    20 return 0;21 }

    2. Indicar que mostrara por pantalla el siguiente programa:

    1 #include 2

    3 int main() {4 int a, b=5, res;5 char c=A;6

    7 a = 2;8 printf("%d\n", b/a);9 a *= 2;

    10 b--;11 printf("%d\n", a==b);12 c += a;13 printf("%c\n", c);14 res = ( c==A || ( a > 0 && b < 5 ) );15 printf("%d\n", res);16

    33

  • Captulo 2. Elementos basicos de un programa en C

    17 return 0;18 }

    SOLUCION:

    21E1

    2.12 Ejercicios propuestos

    1. Se pretende calcular el importe del combustible que consume un vehculo duranteun determinado trayecto. Para ello se pide escribir un programa que solicite comodatos de entrada: el consumo medio del vehculo (litros/100 km.), los kilometrosdel trayecto y el precio del litro de combustible. Con esos datos, el programa de-bera calcular y mostrar: el total de litros consumidos y el coste total.

    2. Indicar que mostrara por pantalla el siguiente programa:

    1 #include 2

    3 int main() {4 int a, b, c;5 int * p1, * p2;6

    7 a = 2;8 p1 = &b;9 p2 = &c;

    10 *p1 = a * 2;11 *p2 = *p1 + 3;12 printf("a=%d b=%d c=%d\n", a, b, c);13 p2 = &a;14 *p1 += *p2;15 printf("a=%d b=%d c=%d\n", a, b, c);16 c = *p1 + *p2;17 printf("a=%d b=%d c=%d\n", a, b, c);18 return 0;19 }

    34

  • Captulo 3

    Estructuras de control

    En los programas que hemos realizado hasta ahora, cada una de las instrucciones se eje-cuta en modo secuencial, una tras otra y una unica vez. Sin embargo, es habitual quelos programas necesiten ejecutar, en funcion de cierta condicion, un grupo de instruccio-nes u otro (ejecucion condicional), o que, por ejemplo, requieran ejecutar un bloque deinstrucciones mas de una vez (bucle). Estas situaciones se resuelven mediante lo que sedenomina sentencias de seleccion y sentencias de repeticion.

    3.1 Sentencias de seleccion

    Las sentencias de seleccion permiten ejecutar unas instrucciones u otras, en funcion decierta condicion. En este sentido, el lenguaje C dispone de las instrucciones if-else yswitch.

    3.1.1 Seleccion con if-else

    La instruccion if-else permite ejecutar un bloque de instrucciones u otro, dependiendode que la evaluacion de una expresion logica resulte ser verdadera o falsa. La sintaxisgeneral de esta instruccion es la siguiente:

    if( expresion ) {instruccion_1_1;instruccion_1_2;

    . . .instruccion_1_N;

    }else {

    instruccion_2_1;

    35

  • Captulo 3. Estructuras de control

    instruccion_2_2;. . .

    instruccion_2_N;}

    Si la expresion de la instruccion if se evalua a 1 (cierto), se ejecutaran las instrucciones1_1 a 1_N, en caso contrario se ejecutaran las instrucciones 2_1 a 2_N.

    Por ejemplo, el siguiente programa indica si cierta nota introducida por teclado corres-ponde a un aprobado o a un suspenso:

    1 #include 2

    3 int main() {4 float nota;5

    6 printf("Introduce el valor de la nota: ");7 scanf("%f", &nota);8 if( nota >= 5 ) {9 printf("APROBADO\n");

    10 }11 else {12 printf("SUSPENDIDO\n");13 }14 return 0;15 }

    Cuando alguno de los bloques if o else consta de una unica instruccion, entonces lasllaves son opcionales.

    if( expresion )instruccion_1;

    elseinstruccion_2;

    Por lo tanto la instruccion if-else del ejemplo anterior tambien podra haberse escritocomo:

    1 if( nota >= 5 )2 printf("APROBADO\n");3 else4 printf("SUSPENDIDO\n");

    Por otro lado, debe resaltarse que el bloque else es opcional. En el siguiente ejemplo seutiliza una instruccion if sin el bloque else:

    36

  • 3.1 Sentencias de seleccion

    1 #include 2

    3 int main() {4 float precio;5 char aplicar_descuento;6

    7 printf("Introduce el precio del artculo: ");8 scanf("%f", &precio);9 printf("Desea aplicar descuento? (s/n) ");

    10 scanf("%c", &aplicar_descuento);11

    12 if( aplicar_descuento == s )13 precio = precio * 0.9; // Aplico un descuento del 10%14

    15 printf("Total a pagar: %.2f\n", precio);16

    17 return 0;18 }

    Las instrucciones if-else pueden anidarse, esto es, tanto dentro del bloque if como delelse pueden aparecer otras instrucciones if-else. En el siguiente ejemplo se muestraun programa que solicita tres numeros y muestra el mayor de ellos mediante el uso deif-else anidados:

    1 #include 2

    3 int main() {4 float a, b, c, max;5

    6 printf("Introduce tres numeros: ");7 scanf("%f%f%f", &a, &b, &c);8

    9 if ( a > b ) { // El maximo sera a o c10 if( a > c )11 max = a;12 else13 max = c;14 }15 else { // El maximo sera b o c16 if( b > c )17 max = b;18 else19 max = c;20 }21 printf("El maximo es %f\n", max);

    37

  • Captulo 3. Estructuras de control

    22

    23 return 0;24 }

    Otro modo de resolver el problema anterior podra ser el siguiente:

    1 . . .2

    3 if ( a>b && a>c)4 max = a;5 else {6 if( b > c )7 max = b;8 else9 max = c;

    10 }11 printf("El maximo es %f\n", max);

    En ocasiones es necesario anidar un numero elevado de instrucciones if-else con el nde seleccionar una de entre varias acciones. La sintaxis en este caso no diere para nadade lo expuesto anteriormente, sin embargo, por cuestiones de legibilidad, el codigo sueleescribirse de modo algo distinto, tal y como se muestra a continuacion:

    if( expresion_1 ) {instrucciones;

    }else if (expresion_2) {

    instrucciones;}else if (expresion_3) {

    instrucciones;}. . .

    Debe observarse que el codigo que acabamos de escribir coincide con el que se muestra acontinuacion, aunque el primero resulta mas legible:

    if( expresion_1 ) {instrucciones;

    }else {

    if (expresion_2) {instrucciones;

    }else {

    38

  • 3.1 Sentencias de seleccion

    if (expresion_3) {instrucciones;

    }. . .

    }}

    El siguiente ejemplo muestra la calicacion obtenida (suspenso, aprobado, notable o so-bresaliente) en funcion de la nota numerica, mediante la concatenacion de varias instruc-ciones if-else:

    1 #include 2

    3 int main() {4 float nota;5

    6 printf("Introduce el valor de la nota: ");7 scanf("%f", &nota);8

    9 if( nota >= 9 )10 printf("SOBRESALIENTE\n");11 else if( nota >= 7 )12 printf("NOTABLE\n");13 else if( nota >= 5 )14 printf("APROBADO\n");15 else16 printf("SUSPENDIDO\n");17

    18 return 0;19 }

    3.1.2 Seleccion con switch

    Tal y como se ha visto en el apartado anterior, dados dos grupos de instrucciones, lainstruccion if-else permite seleccionar uno de ellos. Si se desea seleccionar entre masde dos opciones, se ha visto que es necesario utilizar una combinacion de instruccionesif-else.

    Otra alternativa es es utilizar la instruccion switch. Antes de pasar a ver la sintaxis deesta instruccion, debe quedar claro que cualquier algoritmo que se implemente utilizan-do switch puede implementarse igualmente mediante una combinacion de instruccionesif-else. La instruccion switch simplemente proporciona otra manera de escribir cier-tas partes de un programa, lo que en ocasiones puede ofrecer mayor legibilidad a nuestrocodigo.

    39

  • Captulo 3. Estructuras de control

    La sintaxis de la instruccion switch es la siguiente:

    switch( expresion ) {case valor_1: instrucciones;case valor_2: instrucciones;

    . . .case valor_N: instrucciones;default: instrucciones;

    }

    La expresion de la sentencia switch debe evaluarse a un entero o a un caracter (en lamayora de los casos esta expresion sera simplemente una variable de tipo int o char).Si el resultado de dicha expresion coincide con el valor especicado en alguna de las sen-tencias case, entonces se ejecutaran todas las instrucciones que aparecen a continuacionde dicho case, hasta que se encuentre una instruccion break. Si el valor no coincidecon ningun case, entonces se ejecutaran las instrucciones especicadas en default. Elapartado default es opcional, en caso de no existir y de que la expresion del switch nocoincida con ninguno de los valores case, entonces no se hace nada.

    En el siguiente ejemplo el usuario introduce un numero entero y el programa muestra elda de la semana correspondiente:

    1 #include 2

    3 int main() {4 int dia;5

    6 printf("Introduce el da de la semana (1-7): ");7 scanf("%d", &dia);8

    9 switch( dia ) {10 case 1: printf("LUNES\n"); break;11 case 2: printf("MARTES\n"); break;12 case 3: printf("MIERCOLES\n"); break;13 case 4: printf("JUEVES\n"); break;14 case 5: printf("VIERNES\n"); break;15 case 6: printf("SABADO\n"); break;16 case 7: printf("DOMINGO\n"); break;17 default: printf("Da incorrecto\n");18 }19 return 0;20 }

    En este ejemplo la instruccion switch evalua el valor de la variable dia. A continuacionbusca un case cuyo valor coincida con el de esta variable y, si lo encuentra, ejecuta las

    40

  • 3.1 Sentencias de seleccion

    instrucciones correspondientes. Si el valor de la variable dia no coincide con ninguno delos case, entonces se ejecuta el bloque default.

    Debe tenerse en cuenta que si se encuentra un case que coincida con el valor de la expre-sion (en este ejemplo dia), se ejecutan todas las instrucciones que aparezcan a continua-cion, hasta que se alcance una instruccion break. Esto quiere decir que si en el ejemploanterior no se hubieran incluido las instrucciones break y el usuario introduce, por ejem-plo, un 6, se hubiera ejecutado no solo la instruccion printf("SABADO\n") sino tam-bien las instrucciones printf("DOMINGO\n") y printf("Da incorrecto\n"). Lohabitual sera, por tanto, que cada grupo de instrucciones especicados en un case termi-ne con la instruccion break. Sin embargo, tal y como se muestra en el ejemplo siguiente,habra ocasiones en las que interese no incluir la instruccion break.

    1 #include 2

    3 int main() {4 int curso;5

    6 printf("Introduce el curso en el que te encuentras: ");7 scanf("%d", &curso);8

    9 printf("Asignaturas que todava debes cursar:\n");10

    11 switch( curso ) {12 case 1: printf("PROGRAMACION\n");13 case 2: printf("ALGORITMICA\n");14 case 3: printf("PROGRAMACION AVANZADA\n");15 case 4: printf("PROGRAMACION DE REDES\n");16 case 5: printf("INGENIERIA DEL SOFTWARE\n"); break;17 default: printf("Curso incorrecto\n");18 }19 return 0;20 }

    En el ejemplo anterior, si el usuario introduce, por ejemplo, un 2, el programa mostrara:

    Asignaturas que todava debes cursar:ALGORITMICAPROGRAMACION AVANZADAPROGRAMACION DE REDESINGENIERIA DEL SOFTWARE

    Observese que, una vez se entra en un case, se ejecuta el resto de instrucciones hastaalcanzar una instruccion break.

    41

  • Captulo 3. Estructuras de control

    3.2 Sentencias de repeticion

    Las sentencias de repeticion permiten ejecutar un bloque de instrucciones mas de unavez, esto es, permiten hacer bucles. En lenguaje C se pueden implementar bucles de tresmodos distintos, mediante las sentencias while, do-while y for.

    3.2.1 La sentencia while

    Para implementar un bucle while se utiliza la siguiente sintaxis:

    while( expresion ) {instruccion_1;instruccion_2;

    . . .instruccion_N;

    }

    Mientras la expresion de la instruccion while sea cierta, se ejecutaran las instruccionescontenidas en el bucle. Cuando se ejecuta la ultima instruccion del bucle (instruccion_N)se vuelve a evaluar de nuevo la expresion y, si sigue siendo cierta, se ejecutan de nuevotodas las instrucciones. Se denomina iteracion a cada una de las repeticiones.

    Al igual que ocurre con la instruccion if-else, si el bucle contiene una unica instruccion,las llaves se pueden omitir.

    El siguiente ejemplo muestra 10 veces el texto Hola mundo y a continuacion una vez eltexto Fin del programa.

    1 #include 2

    3 int main() {4 int i = 0;5 while( i < 10 ) {6 printf("Hola mundo\n");7 i++;8 }9 printf("Fin del programa\n");

    10 return 0;11 }

    Como puede observarse, en este ejemplo se ha utilizado la variable i a modo de contador,para controlar el numero de veces que queremos que se repita el bucle (numero de itera-ciones). En este caso, el bucle se repite 10 veces ya que en cada iteracion la variable i se

    42

  • 3.2 Sentencias de repeticion

    incrementa en uno. Cuando esta variable valga 10, la condicion i < 10 sera falsa, con loque ya no se entrara de nuevo en el bucle.

    Para evitar bucles innitos es imprescindible que alguna de las instrucciones del buclemodique de algun modo la expresion de la sentencia while, de lo contrario, una vezse entra en el bucle ya no se puede salir del mismo. El siguiente programa muestra unejemplo de un bucle innito:

    1 #include 2

    3 int main() {4 int i = 0;5 while( i < 10 ) { // Esto siempre va a ser cierto6 printf("Hola mundo\n");7 }8 return 0;9 }

    En el siguiente ejemplo se muestra un programa que solicita dos numeros y una operacion(suma, resta, multiplicacion o division) y realiza la operacion especicada. A continua-cion pregunta si se desea hacer otra operacion. En caso armativo se repite de nuevo todoel proceso.

    1 #include 2

    3 int main() {4 float a, b, c;5 int operacion, repetir;6

    7 repetir = 1; // Para forzar la entrada en el bucle la primeravez

    8 while( repetir == 1 ) {9 printf("Introduce dos numeros: ");

    10 scanf("%f%f", &a, &b);11 printf("1.Sumar \n2.Restar \n3.Multiplicar \n4.Dividir \n")

    ;12 scanf("%d", &operacion);13 switch( operacion ) {14 case 1: c = a+b; break;15 case 2: c = a-b; break;16 case 3: c = a*b; break;17 case 4: c = a/b; break;18 default: printf("Operacion incorrecta\n"); c=0;19 }20 printf("El resultado de la operacion es %f\n", c);21 printf("Deseas hacer otra operacion? (1=SI / 2=NO) ");

    43

  • Captulo 3. Estructuras de control

    22 scanf("%d", &repetir);23 }24 return 0;25 }

    Puede ocurrir que el contenido de un bucle while no se ejecute nunca. El siguiente pro-grama solicita numeros enteros hasta que se introduzca un cero y al nal muestra cuantosde ellos eran positivos.

    1 #include 2

    3 int main() {4 int num, positivos;5

    6 positivos = 0; // De momento no se ha introducido ningunnumero positivo

    7 printf("Introduce un numero entero: ");8 scanf("%d", &num);9 while( num != 0 ) {

    10 if( num > 0 )11 positivos++;12 printf("Introduce otro numero: ");13 scanf("%d", &num); // Este numero se utilizara en la

    siguiente iteracion14 }15 printf("Has introducido %d numeros positivos\n", positivos);16 return 0;17 }

    En el ejemplo anterior, si el primer numero introducido es cero, no llega a entrarse en elbucle while. En este caso la variable positivos se queda con su valor inicial cero. Encaso de que se entre en el bucle, al nal del mismo se pide un nuevo numero que, en casode que sea distinto de cero, provocara que se entre de nuevo en el bucle.

    3.2.2 La sentencia do-while

    La sintaxis del bucle do-while es la siguiente:

    do {instruccion_1;instruccion_2;

    . . .instruccion_N;

    } while( expresion );

    44

  • 3.2 Sentencias de repeticion

    La construccion de un bucle do-while es muy similar a la de un bucle while. La unicadiferencia es que en el bucle while primero se comprueba la expresion y, si es cierta, seejecutan las instrucciones del bucle, mientras que en el caso del bucle do-while primerose ejecutan las instrucciones del bucle y al nal se evalua la expresion. Si esta resulta sercierta, entonces se ejecutaran de nuevo todas las instrucciones, as repetidas veces hastaque la expresion sea falsa. Vemos por tanto que en un bucle do-while se hara comomnimo una iteracion.

    Cualquier codigo escrito con un bucle do-while puede reescribirse mediante un buclewhile y viceversa. Por ejemplo, el siguiente bucle do-while

    1 printf("Introduce un numero positivo:");2 do {3 scanf("%d", &num);4 } while( num

  • Captulo 3. Estructuras de control

    En este ejemplo, si el valor introducido en b es cero, entonces la condicion b == 0 escierta y, en consecuencia, se piden los datos de nuevo. En general se puede emplear unbucle do-while con la siguiente sintaxis para validar los datos de entrada:

    do {solicitar datos

    } while( datos incorrectos );

    Otro uso habitual del bucle do-while es para la implementacion de un menu de opciones.A continuacion se muestra un ejemplo que presenta un menu, de modo que el programase ejecuta repetidas veces hasta que se escoge la opcion Salir:

    1 #include 2

    3 int main() {4 float a, b;5 int opc;6

    7 do {8 printf("1.- Sumar\n");9 printf("2.- Restar\n");

    10 printf("3.- Salir\n");11 printf("Elige una opcion: ");12 scanf("%d", &opc);13 printf("Introduce dos numeros: ");14 scanf("%f%f", &a, &b);15 if( opc == 1 ) printf("%f + %f = %f\n", a, b, a+b);16 else if( opc == 2 ) printf("%f - %f = %f\n", a, b, a-b);17 else if( opc == 3 ) printf("Adios\n");18 else printf("Opcion incorrecta\n");19 } while( opc != 3 );20 return 0;21 }

    En este caso el programa presenta un menu con dos opciones, mas una tercera para nali-zar. El bucle do-while provoca que el programa se ejecute repetidas veces hasta que seescoja la opcion 3 (salir). Cualquier otro valor distinto de 3 provoca que el bucle se repitade nuevo. El grupo de instrucciones if-else se podra haber resuelto tambien medianteuna sentencia switch, tal y como se ha mostrado en ejemplos anteriores.

    46

  • 3.2 Sentencias de repeticion

    3.2.3