informÁtica libro de problemas

269
Centro Universitario de la Defensa INFORMÁTICA Libro de Problemas Fernando Pereñíguez García MaríaTeresa Martínez Inglés Nina Skorin-Kapov

Upload: others

Post on 23-Jul-2022

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: INFORMÁTICA Libro de Problemas

CentroUniversitariode la Defensa

INFORMÁTICALibro de Problemas

Fernando Pereñíguez García

MaríaTeresa Martínez Inglés

Nina Skorin-Kapov

Page 2: INFORMÁTICA Libro de Problemas

INFORMÁTICA

Libro de Problemas Primera edición Fernando Pereñíguez García María Teresa Martínez Inglés Nina Skorin-Kapov

Page 3: INFORMÁTICA Libro de Problemas

© Fernando Pereñiguez García, María Teresa Martínez Inglés, Nina Skorin-Kapov INFORMÁTICA. Libro de problemas. Primera edición. Primera Edición. Noviembre 2020 Reservados todos los derechos. El contenido de esta obra está protegido por la ley, que establece penas de prisión y/o multas, además de las correspondientes indemnizaciones por daños y perjuicios, para quienes reprodujeren, plagiaren, distribuyeren o comunicasen públicamente, en todo o en parte, una obra literaria, artística o científica, o su transformación, interpretación o ejecución artística fijada en cualquier tipo de soporte o comunicada a través de cualquier medio, sin la preceptiva autorización Publicado por: Centro Universitario de la Defensa (CUD) de San Javier Base Aérea de San Javier C/ Coronel López Peña, s/n 30720 Santiago de la Ribera, Murcia (España). Impresión: Talleres Gráficos Edelvives ISBN: 978-84-942962-3-9 DL: MU 854-2020 IMPRESO EN ESPAÑA / PRINTED IN SPAIN

Page 4: INFORMÁTICA Libro de Problemas

AGRADECIMIENTOS

A todos los profesores que han impartido la asignatura de Informática en el Centro Universitario de la Defensa de San Javier. Este libro es fruto de vuestro esfuerzo y empeño por ofrecer la mejor docencia a nuestros alumnos. Gracias a todos vosotros, en especial, a Pedro J. García Laencina, que sin su dedicación, no hubiera sido possible esta recopilación. Además, queremos agradecer tanto el apoyo como el material que nos ha brindado Pedro Alcover Garau, ya que muchos de los ejercicios están basados en sus ejemplos y ejercicios de libros recomendados en la asignatura.

Y finalmente, pero no menos importante, a nuestros alumnos. Sois lo que nos anima a superarnos como docentes año tras año. Este libro es por y para vosotros.

Page 5: INFORMÁTICA Libro de Problemas
Page 6: INFORMÁTICA Libro de Problemas

PRÓLOGO

Como Director del Centro es para mí un placer realizar el prólogo de este libro que tiene en sus manos. En él encontrará una recopilación de ejercicios relacionados con los contenidos tratados en la asignatura Informática que se imparte en el primer curso del título de Grado en Ingeniería en Organización Industrial (GIOI) en el Centro Universitario de la Defensa (CUD), ubicado en la Academia General del Aire (AGA). Es una gran satisfacción constatar la ilusión con la que el profesorado del Centro afronta el reto de formar con excelencia a nuestros alumnos como futuros oficiales del Ejército del Aire. Sin lugar a dudas, con la elaboración de esta herramienta docente, los autores de este libro, el Dr. Fernando Pereñíguez García, la Dra. María Teresa Martínez Inglés y la Dra. Nina Skorin-Kapov, demuestran su compromiso con la excelencia en la enseñanza que desde el CUD se impulsa de manera constante.

Conscientes de la elevada carga de trabajo a la que están sometidos los alumnos durante su etapa de formación, el CUD de San Javier impulsó la iniciativa de dotar a sus alumnos de un material didáctico de calidad que les permitiera desarrollar con éxito la intensa labor de aprendizaje de las diferentes materias contenidas en el Plan de estudios de la Titulación; sin olvidar la doble formación que los alumnos reciben de manera simultánea, universitaria y militar, y teniendo siempre presente la realidad profesional a la que se enfrentarán nuestros futuros egresados.

Alineado con este objetivo, este libro no es una simple recopilación de problemas, sino que pretende ser una herramienta complementaria que sirva de apoyo a la formación que recibe el alumno durante la impartición de la asignatura Informática. Con esta finalidad, los autores han seleccionado cuidadosamente los ejercicios que mejor permiten al alumno asimilar los contenidos teóricos de la asignatura. Además, estos son presentados en orden incremental

Page 7: INFORMÁTICA Libro de Problemas

de dificultad e incorporan abundantes explicaciones encaminadas a facilitar la compresión de la resolución de los mismos.

La publicación de este libro es una excelente noticia para el CUD de San Javier, ya que es una nueva obra que se suma a la ya larga lista de manuales teóricos y prácticos en el ámbito del Título de GIOI que han sido publicados por este Centro desde el comienzo de su actividad en el curso académico 2010-2011.

La elaboración de este material docente ha sido posible gracias al esfuerzo y la continua dedicación de sus autores por mejorar la calidad con la que desarrollan sus tareas docentes. Además, su publicación se produce en un momento donde sus autores, encargados de impartir la asignatura para la que va destinado este libro, han acumulado una amplia experiencia y conocimiento sobre el contexto tan particular en el que se imparte esta materia. No cabe la menor duda que Fernando, María Teresa y Nina han sabido identificar con éxito la colección de problemas suficiente y necesaria que permitirán al alumno comprender e interiorizar el contenido teórico de la asignatura de manera que pueda ser aplicado con éxito en su futuro ejercicio profesional en el seno de las Fuerzas Armadas.

Finalmente deseo felicitar a los autores por la excelente obra realizada, por la gran herramienta docente que aporta al Centro, compañeros y alumnos, y en definitiva por el brillante legado que ello representa.

Nicolás Madrid García Director del Centro Universitario de la Defensa - AGA

Page 8: INFORMÁTICA Libro de Problemas

CONTENIDO

1 INTRODUCCIÓN ................................................................................................................. 13

2 REPRESENTACIÓN DE LA INFORMACIÓN................................................................... 19

2.1. Cambios de base: Conversión de cualquier base a base decimal ............................... 21

2.2. Cambios de base: Conversión de base decimal a cualquier base............................... 23

2.3. Cambios de base: Conversión general entre bases ...................................................... 27

2.4. Cambios de base: Conversión entre bases binaria, octal y hexadecimal ................... 30

2.5. Sumar y restar en binario .............................................................................................. 36

2.6. Restar en binario usando el complemento a la base ................................................... 39

2.7. Codificacion de números en binario con signo ........................................................... 43

2.8. Codificacion de números en hexadecimal con signo .................................................. 47

3 PROGRAMACIÓN ESTRUCTURADA Y ALGORITMIA ............................................... 53

3.1. Suma de pares ................................................................................................................ 55

3.2. Tabla de multiplicar ....................................................................................................... 56

3.3. Calcular hora .................................................................................................................. 57

3.4. Corredor elegido ............................................................................................................ 58

3.5. Calcular cuadros y cubos .............................................................................................. 59

3.6. Número primo ............................................................................................................... 60

3.7. Análisis de secuencia numérica .................................................................................... 62

Page 9: INFORMÁTICA Libro de Problemas

3.8. Suma de números .......................................................................................................... 63

3.9. Potencia ........................................................................................................................... 64

3.10. Sucesión de ULAM ..................................................................................................... 65

4 TIPOS DE DATOS PRIMITIVOS ......................................................................................... 67

4.1. Operadores de asignación, aritméticos y asignación compuesta .............................. 69

4.2. Operadores relacionales, lógicos y a nivel de bit ........................................................ 76

4.3. Operadores de tamaño y cambio de tipo ..................................................................... 93

5 OPERACIONES DE ENTRADA/SALIDA .......................................................................... 99

5.1. Promoción ..................................................................................................................... 101

5.2. Media ............................................................................................................................ 102

5.3. Incrementos .................................................................................................................. 103

5.4. Leer caracteres .............................................................................................................. 104

6 ESTRUCTURAS DE CONTROL: SELECCIÓN ................................................................ 107

6.1. Par-impar ...................................................................................................................... 109

6.2. Divisor ........................................................................................................................... 110

6.3. Calificación examen ..................................................................................................... 111

6.4. Calificación literal ........................................................................................................ 113

6.5. Ecuación de segundo grado ........................................................................................ 116

6.6. Número entero en texto ............................................................................................... 119

6.7. Bilingue ......................................................................................................................... 121

7 ESTRUCTURAS DE CONTROL: REPETICIÓN ............................................................... 125

7.1. Números pares ............................................................................................................. 127

7.2. Factorial ........................................................................................................................ 128

7.3. Máximo y media versión while .................................................................................. 129

7.4. Factorial consecutivo ................................................................................................... 132

7.5. Convocatorias ............................................................................................................... 134

7.6. Maximo y media versión for ....................................................................................... 136

7.7. Primo o compuesto ...................................................................................................... 138

7.8. Aproximación Pi/4 ....................................................................................................... 141

7.9. Aproximación Pi/2 ....................................................................................................... 143

8 FUNCIONES........................................................................................................................ 147

8.1. Potencia ......................................................................................................................... 149

8.2. Factorial ........................................................................................................................ 152

Page 10: INFORMÁTICA Libro de Problemas

8.3. Factorial global ............................................................................................................. 155

8.4. Resolver ecuación......................................................................................................... 156

8.5. Es primo ........................................................................................................................ 158

8.6. Perfecto ......................................................................................................................... 164

9 ARRAYS NUMÉRICOS ...................................................................................................... 169

9.1. Operaciones vectores ................................................................................................... 171

9.2. Vector Ordenado .......................................................................................................... 175

9.3. Negativos positivos ..................................................................................................... 178

9.4. Factoriales ..................................................................................................................... 181

9.5. Introducir polinomio ................................................................................................... 183

9.6. Evaluar polinomio ....................................................................................................... 186

9.7. Derivar polinomio ........................................................................................................ 188

9.8. Suma matrices .............................................................................................................. 191

9.9. Identidad triangular .................................................................................................... 194

9.10. Matriz 01.................................................................................................................... 198

9.11. Suma elementos matriz ............................................................................................ 199

9.12. Suma positivos pares ............................................................................................... 202

10 CARACTERES Y CADENAS DE CARACTERES ............................................................ 205

10.1. Tipos de caracteres ................................................................................................... 207

10.2. Número a carácter .................................................................................................... 210

10.3. Leer cadenas.............................................................................................................. 212

>> Uso de la función scanf() ............................................................................................... 212

>> Uso de la función gets() ................................................................................................. 216

>> Uso de la función fgets() ............................................................................................... 218

10.4. Longitud cadena ....................................................................................................... 221

10.5. Contar Aa .................................................................................................................. 224

10.6. Nombre apellido ....................................................................................................... 226

10.7. Caracteres iguales ..................................................................................................... 230

10.8. Encuentra y suma digitos ........................................................................................ 232

10.9. Cadena invertida ...................................................................................................... 234

11 REGISTROS ......................................................................................................................... 237

11.1. Persona fecha ............................................................................................................ 239

11.2. Fracciones .................................................................................................................. 242

Page 11: INFORMÁTICA Libro de Problemas

11.3. Números complejos .................................................................................................. 247

11.4. Polígono .................................................................................................................... 250

11.5. Pacientes hospital ..................................................................................................... 257

Page 12: INFORMÁTICA Libro de Problemas

1

INTRODUCCIÓN

Page 13: INFORMÁTICA Libro de Problemas
Page 14: INFORMÁTICA Libro de Problemas

Capítulo 1. Introducción | 15

Este libro sirve como apoyo a la formación teórica que reciben los caballeros y damas cadetes durante en la asignatura Informática del 1º curso del Grado en Ingeniería de Organización Industrial (GIOI) por la Universidad Politécnica de Cartagena, impartido en el Centro Universitario de la Defensa en San Javier. El núcleo formativo de la asignatura reside en la introducción al desarrollo de software donde los alumnos aprenden los fundamentos teóricos y prácticos de la programación y adquieren las habilidades necesarias para aplicarlos. Para ello, los alumnos aprenderán no sólo cómo se representa y codifica la información en un ordenador, sino también entenderán cómo se manipulan y procesan los datos codificados mediante secuencias de instrucciones formando programas. En esta asignatura, los alumnos serán capaces de realizar programas básicos utilizando el lenguaje de programación C. Este libro proporciona una colección de problemas y ejercicios comentados para clarificar y apoyar los ejemplos vistos en clase.

Los contenidos que encontrará el lector en los siguientes capítulos se organizan de la siguiente forma.

En el Capítulo 2 se proporciona una serie de ejercicios relacionados con la representación de la información en un ordenador. Toda información esta almacenada dentro del ordenador en formato binario con precisión y tamaño finito. Es importante entender cómo se codifica y guarda la información para poder saber cómo procesarla, las limitaciones asociadas y los errores que puedan surgir. Para entenderlo, en este capítulo se ofrecen ejercicios de cambios de base numérica, con particular atención a conversiones entre base decimal y las bases de potencias a 2 (binario, octal, hexadecimal). Además, se proporcionan ejercicios de sumar y restar números en binario, codificar números con signo en binario y hexadecimal con tamaño finito, y hacer operaciones entre números codificados con signo aplicando el complemento a la base.

El Capítulo 3 engloba una colección de problemas sencillos que requieren el desarrollo de un algoritmo para su resolución representada de una forma gráfica. Los algoritmos definen una serie finita y precisa de instrucciones para procesar los datos y llevar a cabo una tarea. Estos algoritmos se pueden representar de forma gráfica mediante un Diagrama de Flujo, o flujograma. Este capítulo presenta varios ejemplos de flujogramas que realizan distintas tareas. A la hora de diseñar los algoritmos, es recomendable que sean estructurados. Para que un algoritmo o programa sea estructurado, debe ajustarse a una colección reducida de estructuras básicas de secuencia, de decisión y/o de iteración. La programación estructurada permite la sustitución de cualquier bloque de instrucción por una nueva estructura básica.

En el Capítulo 4 se muestran varios ejercicios sobre los operadores y tipos de datos primitivos en el lenguaje de programación C. Es importante a la hora de programar, conocer el tamaño y entender la codificación de los datos primitivos y la manera en que los operadores manipulan esos datos para evitar errores de precisión, desbordamiento, conversión entre tipos, etc. Además, en este capítulo se familiariza los alumnos con la sintaxis básica de C para codificar y manipular datos. Primero se describen los operadores de asignación, aritméticos y de la asignación compuesta para realizar operaciones básicas de aritmética que

Page 15: INFORMÁTICA Libro de Problemas

16 | Informática. Libro de problemas

normalmente forman estructuras de secuencias. A continuación, se muestran los operadores relacionales y lógicos que son imprescindibles para poder crear estructuras de decisión (los condicionales) y de iteración (repetición). Se proporcionan también ejemplos de operadores relacionados con el tamaño de las variables y de cambios de tipo.

A partir de este capítulo, se presentan los ejercicios relacionados con la resolución de problemas de programación en el lenguaje C. Para cada problema, se proporcionan ejemplos de ejecución1 y las posibles soluciones en forma de código fuente. Además, se añaden comentarios para explicar las soluciones que se han propuesto.

En el Capítulo 5 se familiariza al alumno con las operaciones básicas de entrada/salida de datos. Se proporciona una serie de problemas que deben ser resueltos mediante programas sencillos. Este capítulo ayuda a familiarizarse con la estructura básica de los programas (la función principal, uso de librerías, uso de comentarios) y el uso correcto de las funciones prinft() y scanf() de la librería stdio.h que ofrecen mecanismos para facilitar la salida/entrada de datos por línea de comandos.

En el Capítulo 6 se presentan diversos problemas que pretenden afianzar el uso de las estructuras de decisión o selección. Las estructuras de control de selección, o condicionales, usadas en lenguaje C son: if, if-else, y switch. Estas estructuras de selección condicionales varían el flujo de ejecución de un programa dependiendo de una condición. La sentencia if permite a un programa elegir entre dos alternativas, comprobando el valor de una expresión lógica. Una sentencia if puede ir acompañada opcionalmente por una clausula else. Cuando usamos el anidamiento de sentencias if para evaluar, de manera consecutiva, condiciones que son mutuamente excluyentes, se puede emplear la concatenación if - else. Para comparar una expresión con un conjunto de valores, se podría usar sentencias if anidadas, o emplear la sentencia switch que compara sucesivamente el valor de una expresión con una lista de constantes de tipo entero o carácter.

En el Capítulo 7, se proporcionan varios problemas para ilustrar el uso de las estructuras básicas de iteración, o repetición. Las estructuras de repetición permiten iterar sobre un conjunto de instrucciones, es decir un bucle, mientras se cumpla una condición. Las estructuras de repetición usadas en lenguaje C y presentadas en este capítulo son: while, do-while, y for. La sentencia while es la más sencilla que ofrece C para ejecutar de manera repetida un conjunto de instrucciones. Las sentencias dentro del bucle while se ejecutarán mientras que la condición definida por una expresión lógica sea verdadera. La estructura do-while es parecida a la del while, salvo que la condición se evalúa por primera vez después de ejecutar todas las sentencias. Eso asegura que las sentencias que forman el do-while se

1 A la hora de mostrar los ejemplos de ejecución, la información introducida por el usuario mediante teclado se ha destacado por medio de un sombreado de texto de color gris.

Page 16: INFORMÁTICA Libro de Problemas

Capítulo 1. Introducción | 17

ejecutarán siempre, al menos, una vez. El bucle for permite escribir de una forma compacta la inicialización de una o más variables que van a formar parte del bucle, la condición (expresión lógica) que determinará cuando finaliza el bucle y el cambio de las variables en cada iteración del bucle. En este capítulo también se introducen ejemplos de salida de los bucles mediante la instrucción break.

El Capítulo 8 contiene problemas para afianzar los conceptos relacionados con el uso de funciones. Las funciones representan fragmentos de código que realizan tareas determinadas y nos permiten dividir la solución de un problema complejo en pequeños problemas más sencillos de forma modular. También nos permite realizar la misma tarea varias veces dentro del programa sin repetir del código. Los ejemplos proporcionados ayudan a entender el uso de funciones centrándose en los conceptos clave en el uso de funciones en C: la declaración, definición e invocación de una función. La declaración especifica los parámetros de entrada y salida de la función, la invocación define como se usa la función, y la definición incluye las instrucciones que ejecuta la función para realizar la tarea.

En el Capítulo 9, se presentan varios problemas para familiarizarse con el manejo de arrays numéricos, que son un tipo básico de datos agregado que permiten almacenar colecciones de datos del mismo tipo. Un array es una colección de variables del mismo tipo que se referencian mediante un único identificador. Las variables se guardan de forma consecutiva en memoria y a las posiciones del array (cada variable) se puede acceder indexando mediante un índice. En este capítulo, se presenta el uso de arrays numéricos unidimensionales (vectores) y bidimensionales (matrices) y como recorrerlos mediante estructuras de repetición e índices.

El Capítulo 10, para complementar la formación en el uso de arrays, versa sobre la manipulación de arrays que almacenan caracteres, también conocidos como cadenas de caracteres. Se proporcionan ejemplos donde se usan funciones de la biblioteca ctype.h para manipular caracteres. Además, se muestran las diferentes formas de leer cadenas de texto aplicando funciones como scanf(), gets(), fgets(). Por último, se presentan problemas para recorrer cadenas de caracteres con el fin de copiar, manipular o evaluarlas, en algunos casos aplicando funciones de la biblioteca string.h.

En el Capítulo 11, se completa el uso de los tipos de datos estructurados aprendiendo el uso de los registros, también conocidos como estructuras. Un registro es un tipo de dato que almacena bajo un mismo nombre información relacionada pero representada con tipos de datos heterogéneos. A diferencia de los arrays, en los registros los elementos no tienen que ser del mismo tipo y se accede a cualquier elemento del registro a través del nombre. Se proporcionan varios ejemplos de cómo declarar registros como nuevos tipos de datos, inicializar variables de los tipos nuevos definidos mediante registros y acceder a los campos dentro de los variables tipo registro.

Page 17: INFORMÁTICA Libro de Problemas
Page 18: INFORMÁTICA Libro de Problemas

2

REPRESENTACIÓN DE LA INFORMACIÓN

Page 19: INFORMÁTICA Libro de Problemas
Page 20: INFORMÁTICA Libro de Problemas

Capítulo 2. Representación de la información | 21

2.1. Cambios de base: Conversión de cualquier base a base decimal Esta sección contiene diversos ejercicios que consisten en cambiar un número n1 expresado en base b1 a su correspondiente número n2 expresado en base b2=10.

n1=11011, b1=2, b2=10, n2=?

(11011)2(___)10

Solución: n2 = 27

Procedimiento: Se recomienda aplicar el método de expansión.

(11011)2 1·24 + 1·23 + 0·22 + 1·21 + 1·20 = 16+8+0+2+1 = (27)10

n1=534, b1=6, b2=10, n2=?

(534)6(___)10

Solución: n2 = 202

Procedimiento: Se recomienda aplicar el método de expansión.

(534)6 5·62 + 3·61 + 4·60 = 180 + 18 + 4 = (202)10

n1=A3F, b1=16, b2=10, n2=?

(A3F)16(___)10

Solución: n2 = 2623

Procedimiento:

Se recomienda aplicar el método de expansión.

(A3F)16 10·162 + 3·161 + 15·60 = 2560 + 48 + 15 = (2623)10

Posición 24 Posición 20

Page 21: INFORMÁTICA Libro de Problemas

22 | Informática. Libro de problemas

n1=778, b1=9, b2=10, n2=?

(778)9(___)10

Solución: n2 = 638

n1=11101110, b1=2, b2=10, n2=?

(11101110)2(___)10

Solución: n2 = 238

n1=A44, b1=16, b2=10, n2=?

(A44)16(___)10

Solución: n2 = 2628

n1=452, b1=6, b2=10, n2=?

(452)6(___)10

Solución: n2 = 176

n1=1101, b1=3, b2=10, n2=?

(1101)3(___)10

Solución: n2 = 37

n1=770, b1=8, b2=10, n2=?

(770)8(___)10

Solución: n2 = 504

Page 22: INFORMÁTICA Libro de Problemas

Capítulo 2. Representación de la información | 23

n1=23F, b1=16, b2=10, n2=?

(23F)16(___)10

Solución: n2 = 575

2.2. Cambios de base: Conversión de base decimal a cualquier base Este apartado contiene diversos ejercicios que consisten en cambiar un número n1 expresado en base b1=10 a su correspondiente número n2 expresado en base b2.

n1=254, b1=10, b2=4, n2=?

(254)10(___)4

Solución: n2 = 3332

Procedimiento:

Se recomienda aplicar el método de divisiones sucesivas. Se debe comenzar dividiendo el número n1 entre b2. Guardamos el resto que obtenemos mientras que el cociente se vuelve a dividir entre b2. Este proceso se repite de forma sucesiva hasta que se obtenga un cociente menor que b2. Los dígitos que forman el número n2 expresado en base b2 es el cociente obtenido en la última división, seguido por los restos obtenidos en las sucesivas divisiones (desde el ultimo al primero).

Aplicando el procedimiento descrito anteriormente, se concluye el número 254 expresado en base 10 equivale al número 3332 expresado en base 4:

(254)10(3332)4

254 4

2 63 4

3 15 4

3 3

Dividendo (n1)

Resto

Divisor (base b2)

Cociente

Page 23: INFORMÁTICA Libro de Problemas

24 | Informática. Libro de problemas

n1=133, b1=10, b2=2, n2=?

(133)10(___)2

Solución: n2 = 10000101

Procedimiento:

Se recomienda aplicar el método de divisiones sucesivas.

Aplicando el procedimiento descrito anteriormente, se concluye el número 133 expresado en base 10 equivale al número 10000101 expresado en base 2:

(133)10(10000101)2

133 2

1 66 2

0 33 2

1 16 2

0 8 2

0 4 2

0 2 2

0 1

n1=3390, b1=10, b2=16, n2=?

(3390)10(___)16

Solución: n2 = C3D

Procedimiento:

Se recomienda aplicar el método de divisiones sucesivas.

Page 24: INFORMÁTICA Libro de Problemas

Capítulo 2. Representación de la información | 25

(3390)10(D3E)16

3390 16

14 211 16

3 13

n1=56, b1=10, b2=7, n2=?

(56)10(___)7

Solución: n2 = 110

n1=323, b1=10, b2=9, n2=?

(323)10(___)9

Solución: n2 = 388

n1=9, b1=10, b2=16, n2=?

(9)10(___)16

Solución: n2 = 9

n1=9, b1=10, b2=5, n2=?

(9)10(___)5

Solución: n2 = 14

E en base 16

Divisor (base b2)

D en base 16

Page 25: INFORMÁTICA Libro de Problemas

26 | Informática. Libro de problemas

n1=54, b1=6, b2=8, n2=?

(54)10(___)8

Solución: n2 = 66

n1=22, b1=10, b2=2, n2=?

(22)10(___)2

Solución: n2 = 10110

n1=167, b1=10, b2=16, n2=?

(167)10(___)16

Solución: n2 = A7

n1=43, b1=10, b2=5, n2=?

(43)10(___)5

Solución: n2 = 133

Page 26: INFORMÁTICA Libro de Problemas

Capítulo 2. Representación de la información | 27

2.3. Cambios de base: Conversión general entre bases

Este apartado contiene diversos ejercicios que consisten en cambiar un número n1 expresado en base b1 a su correspondiente número n2 expresado en base b2: (n1)b1(n2)b2

n1=124, b1=6, b2=8, n2=?

(124)6(___)8

Solución: n2 = 64

Procedimiento:

En primer lugar, se recomienda convertir el número n1 expresado en base b1 a base 10 mediante el método de expansión (Paso 1). Seguidamente deberemos convertir el valor obtenido (en base 10) a base b2, empleando para ello el método de divisiones sucesivas (Paso 2).

• Paso 1:

(124)6(___)10

Resuelto mediante el método de expansión:

(124)6 1·62+2·61+4·60 = 36+12+4 = (52)10

• Paso 2:

(52)10(___)8

Resuelto mediante el método de divisiones sucesivas:

52 8

4 6

Aplicando el procedimiento descrito anteriormente, se concluye el número 124 expresado en base 6 equivale al número 64 expresado en base 8:

(52)10(64)8

Dividendo

Resto

Divisor (base b2)

Cociente

64

Page 27: INFORMÁTICA Libro de Problemas

28 | Informática. Libro de problemas

n1=251, b1=8, b2=3, n2=?

(251)8(___)3

Solución: n2 = 20021

Procedimiento:

En primer lugar, debemos transformar el número n1 expresado en base b1 a base 10 mediante el método de expansión (Paso 1). A continuación, convertiremos el valor obtenido (en base 10) a base b2, empleando el método de divisiones sucesivas (Paso 2).

• Paso 1:

(251)8(___)10

Resuelto mediante el método de expansión:

(251)8 2·82+5·81+1·80 = 128+40+1 = (169)10

• Paso 2:

(169)10(___)3

Resuelto mediante el método de divisiones sucesivas:

Por lo tanto, aplicando el procedimiento descrito anteriormente, se concluye el número 251 expresado en base 8 equivale al número 20021 expresado en base 3:

(169)10(20021)3

169 3

1 56 3

2 18 3

0 6 3

0 2

Page 28: INFORMÁTICA Libro de Problemas

Capítulo 2. Representación de la información | 29

n1=87, b1=9, b2=5, n2 =?

(87)9(___)5

Solución: n2 = 304

n1=241, b1=5, b2=9, n2=?

(241)5(___)9

Solución: n2 = 78

n1=122, b1=3, b2=5, n2=?

(122)3(___)5

Solución: n2 = 32

n1=130, b1=5, b2=6, n2=?

(130)5(___)6

Solución: n2 = 104

n1=56, b1=8, b2=7, n2=?

(56)8(___)7

Solución: n2 = 64

n1=AA, b1=16, b2=5, n2=?

(AA)16(___)5

Solución: n2 = 1140

Page 29: INFORMÁTICA Libro de Problemas

30 | Informática. Libro de problemas

n1=1234, b1=5, b2=9, n2=?

(1234)5(___)9

Solución: n2 = 235

n1=43, b1=6, b2=5, n2=?

(43)6(___)5

Solución: n2 = 102

2.4. Cambios de base: Conversión entre bases binaria, octal y hexadecimal

Este apartado agrupa diversos ejercicios que proponen realizar la conversión de valores numéricos expresados en base binaria, octal y hexadecimal.

Dado el número n1 expresado en binario (con 8 bits), determina sus correspondientes valores numéricos n2 en base octal (con 3 dígitos) y n3 en base hexadecimal (con 2 dígitos).

n1= 0100 1110, n2=?, n3=?

(0100 1110)2(___)8 y (0100 1110)2(___)16

Solución: n2 = 116, n3 = 4E

Procedimiento:

Se podría aplicar el procedimiento general (descrito en el apartado 2.3) y transformar el número binario a base 10 y, seguidamente, transformar este a sus valores numéricos equivalentes en las bases octal y hexadecimal. Sin embargo, para las transformaciones entre las bases 2, 8, y 16, se puede aplicar un procedimiento más rápido, que mostramos a continuación.

Page 30: INFORMÁTICA Libro de Problemas

Capítulo 2. Representación de la información | 31

Binario Octal

Se debe dividir el número dado en binario en grupos de 3 bits, empezando por la derecha. Cada grupo corresponde a un digito en octal que se calcula aplicando el método de expansión.

(0 1 0 0 1 1 1 0) 2 0 1 0 0 1 1 1 0

Según observamos en la anterior figura, el valor 0100 1110 expresado en binario equivale al valor 116 expresado en base octal:

(0100 1110)2(116)8

Binario Hexadecimal

Se debe dividir el número dado en binario en grupos de 4 bits, empezando por la derecha. Cada grupo corresponde a un digito en hexadecimal que se calcula aplicando el método de expansión.

(0 1 0 0 1 1 1 0) 2 0 1 0 0 1 1 1 0

Según se muestra en la figura anterior, el valor 0100 1110 expresado en binario equivale al valor 4E expresado en base hexadecimal:

(0100 1110)2(4E)16

Dado el número n1 expresado en octal (con 2 dígitos), determina sus correspondientes valores numéricos n2 en binario (con 8 bits) y n3 en hexadecimal (con 2 dígitos).

n1= 53, n2=?, n3=?

(53)8(___)2 y (53)8(___)16

1·22+1·21+0·20=6

0·22+0·21+1·20=1

0·21+1·20=1

1·23+1·22+1·21+0·20=(14)10=(E)16 0·23+1·22+0·21+0·20=(4)10=(4)16

Page 31: INFORMÁTICA Libro de Problemas

32 | Informática. Libro de problemas

Solución: n2 = 00101011, n3 = 2B

Procedimiento:

Se recomienda transformar el valor octal a binario y, a su vez, convertir este en su correspondiente valor hexadecimal.

Octal Binario

Debemos convertir cada digito octal (de formal individual) a un valor binario con 3 bits. Como un único digito en octal es igual que en decimal, se puede usar el método de divisiones sucesivas. Es importante mencionar que, si el número en binario tiene menos de 3 bits, deberemos rellenar con ceros las posiciones de la izquierda.

(53)8 5 3

Tal y como se muestra en la figura anterior, el valor 53 expresado en base octal equivale al valor 101011 expresado en base binaria:

(53)8 (101 011)2

Debido a que el ejercicio nos solicita el número en binario empleando 8 bits, rellenamos con 0´s las posiciones de la izquierda hasta llegar a 8 bits, resultando lo siguiente:

(53)8 (00101011)2

Binario Hexadecimal

Se debe dividir el número dado en binario en grupos de 4 bits, empezando por la derecha. Cada grupo corresponde a un digito en hexadecimal que se calcula aplicando el método de expansión.

(101011) 2 1 0 1 0 1 1

Según se muestra en la figura anterior, el valor 101011 expresado en binario equivale al valor 2B expresado en base hexadecimal:

(101011)2(2B)16

5 2

1 2 2

0 1

3 2

1 1

1·23+0·22+1·21+1·20=(11)10=(B)16 0·23+0·22+1·21+0·20=(2)10=(2)16

Page 32: INFORMÁTICA Libro de Problemas

Capítulo 2. Representación de la información | 33

Dado el número n1 expresado en hexadecimal (con 2 dígitos), determina sus correspondientes valores numéricos n2 en binario (con 8 bits) y n3 en octal (con 3 dígitos).

n1= 65, n2=?, n3=?

(65)16(___)2 y (65)16(___)8

Solución: n2 = 0110 0101, n3 = 145

Procedimiento:

Se recomienda transformar el valor hexadecimal a binario y, a su vez, convertir este en su correspondiente valor octal.

Hexadecimal Binario

Debemos convertir cada digito hexadecimal (de forma individual) a un valor binario con 4 bits. Si el número resultante en binario tiene menos que 4 bits, rellenamos conceros las posiciones de la izquierda.

(65)16 6 5

(0110 0101)2

Tal y como se muestra en la figura anterior, el valor 65 expresado en base hexadecimal equivale al valor 0110 0101 expresado en base binaria:

(65)16(0110 0101)2

Binario Octal

Se debe dividir el número dado en binario en grupos de 3 bits, empezando por la derecha. Cada grupo corresponde a un digito en octal que se calcula aplicando el método de expansión.

5 2

1 2 2

0 1

6 2

0 3 2

1 1

Page 33: INFORMÁTICA Libro de Problemas

34 | Informática. Libro de problemas

(0 1 1 0 0 1 0 1) 2 0 1 1 0 0 1 0 1

Según observamos en la anterior figura, el valor 0110 0101 expresado en binario equivale al valor 145 expresado en base octal:

(0110 0101)2(145)8

Dado el número n1 expresado en binario (con 8 bits), determina sus correspondientes valores numéricos n2 en base octal (con 3 dígitos) y n3 en base hexadecimal (con 2 dígitos).

n1= 1100 0110, n2=?, n3=?

(1100 0110)2(___)8 y (1100 0110)2(___)16

Solución: n2 = 306, n3 = C6

Dado el número n1 expresado en binario (con 8 bits), determina sus correspondientes valores numéricos n2 en base octal (con 3 dígitos) y n3 en base hexadecimal (con 2 dígitos).

n1= 1110 0111, n2=?, n3=?

(1110 0111)2(___)8 y (1110 0111)2(___)16

Solución: n2 = 347, n3 = E7

Dado el número n1 expresado en octal (con 3 dígitos), determina sus correspondientes valores numéricos n2 en binario (con 10 bits) y n3 en hexadecimal (con 3 dígitos).

n1= 761, n2=?, n3=?

(761)8(___)2 y (761)8(___)16

Solución: n2 = 0111110001, n3 = 1F1

1·22+0·21+1·20=5

1·22+0·21+0·20=4

0·21+1·20=1

Page 34: INFORMÁTICA Libro de Problemas

Capítulo 2. Representación de la información | 35

Dado el número n1 expresado en octal (con 3 dígitos), determina sus correspondientes valores numéricos n2 en binario (con 8 bits) y n3 en hexadecimal (con 2 dígitos).

n1= 275, n2=?, n3=?

(275)8(___)2 y (275)8(___)16

Solución: n2 = 10111101, n3 = BD

Dado el número n1 expresado en hexadecimal (con 2 dígitos), determina sus correspondientes valores numéricos n2 en binario (con 8 bits) y n3 en octal (con 3 dígitos).

n1= AA, n2=?, n3=?

(AA)16(___)2 y (AA)16(___)8

Solución: n2 = 10101010, n3 = 252

Dado el número n1 expresado en hexadecimal (con 3 dígitos), determina sus correspondientes valores numéricos n2 en binario (con 12 bits) y n3 en octal (con 4 dígitos).

n1= F10, n2=?, n3=?

(F10)16(___)2 y (F10)16(___)8

Solución: n2 = 111100010000, n3 = 7420

Dado el número n1 expresado en hexadecimal (con 2 dígitos), determina sus correspondientes valores numéricos n2 en binario (con 8 bits) y n3 en octal (con 3 dígitos).

n1= 0E, n2=?, n3=?

(0E)16(___)2 y (0E)16(___)8

Solución: n2 = 00001110, n3 = 016

Page 35: INFORMÁTICA Libro de Problemas

36 | Informática. Libro de problemas

2.5. Sumar y restar en binario

Dados los valores n1 y n2, ambos expresados en base binaria, calcule la suma y resta de los mismos en base binaria.

n1= 1101, n2=1011, n1+n2=?, n1-n2=?

Solución: n1+n2 = 11000, n1-n2 = 10

Procedimiento:

+1 +1 +1

1 1 0 1

+ 1 0 1 1

1 1 0 0 0

-1 1 1 0 1

- 1 0 1 1

0 0 1 0

Dados los valores n1 y n2, ambos expresados en base binaria, calcule la suma y resta de los mismos en base binaria.

n1= 1110, n2=1011, n1+n2=?, n1-n2=?

Solución: n1+n2 = 11001, n1-n2 = 11

Procedimiento:

+1 +1

1 1 1 0

+ 1 0 1 1

1 1 0 0 1

-1 -1 1 1 1 0

- 1 0 1 1

0 0 1 1

Page 36: INFORMÁTICA Libro de Problemas

Capítulo 2. Representación de la información | 37

Dados los valores n1 y n2, ambos expresados en base binaria, calcule la suma y resta de los mismos en base binaria.

n1= 10010, n2=11, n1+n2=?, n1-n2=?

Solución: n1+n2 = 10101, n1-n2 = 1111

Procedimiento:

+1

1 0 0 1 0

+ 1 1

1 0 1 0 1

-1 -1 -1 -1 1 0 0 1 0

- 1 1

0 1 1 1 1

Dados los valores n1 y n2, ambos expresados en base binaria, calcule la suma y resta de los mismos en base binaria.

n1= 1001, n2=111, n1+n2=?, n1-n2=?

Solución: n1+n2 = 10000, n1-n2 = 10

Dados los valores n1 y n2, ambos expresados en base binaria, calcule la suma y resta de los mismos en base binaria.

n1= 11, n2=1, n1+n2=?, n1-n2=?

Solución: n1+n2 = 100, n1-n2 = 10

Dados los valores n1 y n2, ambos expresados en base binaria, calcule la suma y resta de los mismos en base binaria.

n1= 101, n2=11, n1+n2=?, n1-n2=?

Solución: n1+n2 = 1000, n1-n2 = 10

Page 37: INFORMÁTICA Libro de Problemas

38 | Informática. Libro de problemas

Dados los valores n1 y n2, ambos expresados en base binaria, calcule la suma y resta de los mismos en base binaria.

n1= 10011, n2=1011, n1+n2=?, n1-n2=?

Solución: n1+n2 = 11110, n1-n2 = 1000

Dados los valores n1 y n2, ambos expresados en base binaria, calcule la suma y resta de los mismos en base binaria.

n1= 11011, n2=110, n1+n2=?, n1-n2=?

Solución: n1+n2 = 100001, n1-n2 = 10101

Dados los valores n1 y n2, ambos expresados en base binaria, calcule la suma y resta de los mismos en base binaria.

n1= 1011, n2=0110, n1+n2=?, n1-n2=?

Solución: n1+n2 = 10001, n1-n2 = 101

Dados los valores n1 y n2, ambos expresados en base binaria, calcule la suma y resta de los mismos en base binaria.

n1= 1111, n2=1000, n1+n2=?, n1-n2=?

Solución: n1+n2 = 10111, n1-n2 = 111

Dados los valores n1 y n2, ambos expresados en base binaria, calcule la suma y resta de los mismos en base binaria.

n1= 10001, n2=101, n1+n2=?, n1-n2=?

Solución: n1+n2 = 10110, n1-n2 = 1100

Page 38: INFORMÁTICA Libro de Problemas

Capítulo 2. Representación de la información | 39

2.6. Restar en binario usando el complemento a la base

Dados los valores n1 y n2 (expresados en base binaria con 8 bits), calcule:

• El complemento a 1 (complemento a la base menos uno) de n2 con 8 bits. • El complemento a 2 (complemento a la base) de n2 con 8 bits. • La resta n1-n2 considerando 8 bits haciendo uso del procedimiento basado en

complemento a la base.

n1= 0111 1011, n2=0100 1011, 𝐶𝐶18(𝑛𝑛2) =?, 𝐶𝐶28(𝑛𝑛2) =?, n1-n2=?

Solución: 𝑪𝑪𝟏𝟏𝟖𝟖(𝒏𝒏𝒏𝒏)= 1011 0100, 𝑪𝑪𝒏𝒏𝟖𝟖(𝒏𝒏𝒏𝒏) =1011 0101, n1-n2 = 0011 0000

Procedimiento: El complemento a 1 de un número binario se obtiene fácilmente sustituyendo todos los ceros por unos y viceversa:

n2=0100 1011 𝐶𝐶18(𝑛𝑛2)=1011 0100 El complemento a 2 de un número binario se obtiene al sumarle la unidad al complemento a 1 de dicho número:

𝐶𝐶18(𝑛𝑛2)= 1011 0100

+ 1

𝐶𝐶28(𝑛𝑛2)= 1011 0101 La resta n1-n2 considerando x bits se puede calcular como los x bits menos significativos de la suma n1+C2(n2), donde n1 y C2(n2) deben ser valores binarios expresados haciendo uso de x bits. En este ejemplo, la resta esta calculada considerando 8 bits, es decir, x = 8:

0111 1011 n1

+ 1011 0101 𝐶𝐶28(𝑛𝑛2)

10011 0000

Atendiendo al procedimiento descrito anteriormente de resta binario en complemento a la base, la resta de los valores n1-n2 resulta en el valor 0011 0000.

8 bits Descartar

Page 39: INFORMÁTICA Libro de Problemas

40 | Informática. Libro de problemas

Dados los valores n1 y n2 (expresados en base binaria con 8 bits), calcule:

• El complemento a 1 (complemento a la base menos uno) de n2 con 10 bits. • El complemento a 2 (complemento a la base) de n2 con 10 bits. • La resta n1-n2 considerando 10 bits haciendo uso del procedimiento basado en

complemento a la base.

n1= 0111 1011, n2 = 0100 1011, 𝐶𝐶110(𝑛𝑛2)=?, 𝐶𝐶210(𝑛𝑛2) =?, n1-n2=?

Solución: 𝑪𝑪𝟏𝟏𝟏𝟏𝟏𝟏(𝒏𝒏𝒏𝒏)= 1011 0100, 𝑪𝑪𝒏𝒏𝟏𝟏𝟏𝟏(𝒏𝒏𝒏𝒏) =1011 0101, n1-n2 = 0011 0000

Procedimiento: El complemento a 1 de un número binario se obtiene fácilmente al sustituir todos los ceros por unos y viceversa. Como el ejercicio especifica con 10 bits, tenemos que añadir dos ceros en las posiciones ás a la izquierda del numero n2:

n2=00 0100 1011 𝐶𝐶110(𝑛𝑛2)=11 1011 0100

El complemento a 2 de un número binario se obtiene al sumarle la unidad al complemento a 1 de dicho número.

𝐶𝐶110(𝑛𝑛2)= 11 1011 0100

+ 1

𝐶𝐶210(𝑛𝑛2)= 111011 0101

La resta n1-n2 considerando x bits se puede calcular como los x bits menos significativos de la suma n1+C2(n2), donde n1 y C2(n2) deben ser valores binarios expresados haciendo uso de x bits. En este ejemplo, la resta esta calculada considerando 10 bits, es decir, x = 10:

00 0111 1011 n1 con 10 bits

+ 11 1011 0101 𝐶𝐶210(𝑛𝑛2)

1000011 0000

Atendiendo al procedimiento descrito anteriormente de resta binario en complemento a la base, la resta de los valores n1-n2 resulta en el valor 00 0011 0000.

10 bits Descartar

Page 40: INFORMÁTICA Libro de Problemas

Capítulo 2. Representación de la información | 41

Dados los valores n1 y n2 (expresados en base binaria con 8 bits), calcule:

• El complemento a 1 (complemento a la base menos uno) de n2 con 8 bits. • El complemento a 2 (complemento a la base) de n2 con 8 bits. • La resta n1-n2 considerando 8 bits haciendo uso del procedimiento basado en

complemento a la base.

n1= 1101 1100, n2=1000 1110, 𝐶𝐶18(𝑛𝑛2)=?, 𝐶𝐶28(𝑛𝑛2) =?, n1-n2=?

Solución: 𝑪𝑪𝟏𝟏𝟖𝟖(𝒏𝒏𝒏𝒏)= 0111 0001, 𝑪𝑪𝒏𝒏𝟖𝟖(𝒏𝒏𝒏𝒏) =0111 0010, n1-n2 = 0100 1110

Dados los valores n1 y n2 (expresados en base binaria con 4 bits), calcule:

• El complemento a 1 (complemento a la base menos uno) de n2 con 5 bits. • El complemento a 2 (complemento a la base) de n2 con 5 bits. • La resta n1-n2 considerando 5 bits haciendo uso del procedimiento basado en

complemento a la base.

n1= 1011, n2=0011, 𝐶𝐶15(𝑛𝑛2)=?, 𝐶𝐶25(𝑛𝑛2) =?, n1-n2=?

Solución: 𝑪𝑪𝟏𝟏𝟓𝟓(𝒏𝒏𝒏𝒏)= 11100, 𝑪𝑪𝒏𝒏𝟓𝟓(𝒏𝒏𝒏𝒏) =11101, n1-n2 = 01000

Dados los valores n1 y n2 (expresados en base binaria con 8 bits), calcule:

• El complemento a 1 (complemento a la base menos uno) de n2 con 8 bits. • El complemento a 2 (complemento a la base) de n2 con 8 bits. • La resta n1-n2 considerando 8 bits haciendo uso del procedimiento basado en

complemento a la base.

n1= 0100 1101, n2=0001 1110, 𝐶𝐶18(𝑛𝑛2)=?, 𝐶𝐶28(𝑛𝑛2) =?, n1-n2=?

Solución: 𝑪𝑪𝟏𝟏𝟖𝟖(𝒏𝒏𝒏𝒏)= 1110 0001, 𝑪𝑪𝒏𝒏𝟖𝟖(𝒏𝒏𝒏𝒏) =1110 0010, n1-n2 = 0010 1111

Page 41: INFORMÁTICA Libro de Problemas

42 | Informática. Libro de problemas

Dados los valores n1 y n2 (expresados en base binaria con 8 bits), calcule:

• El complemento a 1 (complemento a la base menos uno) de n2 con 8 bits. • El complemento a 2 (complemento a la base) de n2 con 8 bits. • La resta n1-n2 considerando 8 bits haciendo uso del procedimiento basado en

complemento a la base.

n1= 1001 0101, n2=1000 1110, 𝐶𝐶18(𝑛𝑛2)=?, 𝐶𝐶28(𝑛𝑛2) =?, n1-n2=?

Solución: 𝑪𝑪𝟏𝟏𝟖𝟖(𝒏𝒏𝒏𝒏)= 0111 0001, 𝑪𝑪𝒏𝒏𝟖𝟖(𝒏𝒏𝒏𝒏) =0111 0010, n1-n2 = 0000 0111

Dados los valores n1 y n2 (expresados en base binaria con 4 bits), calcule:

• El complemento a 1 (complemento a la base menos uno) de n2 con 4 bits. • El complemento a 2 (complemento a la base) de n2 con 4 bits. • La resta n1-n2 considerando 8 bits haciendo uso del procedimiento basado en

complemento a la base.

n1= 1011, n2=1010, 𝐶𝐶14(𝑛𝑛2)=?, 𝐶𝐶24(𝑛𝑛2) =?, n1-n2=?

Solución: 𝑪𝑪𝟏𝟏𝟒𝟒(𝒏𝒏𝒏𝒏)= 0101, 𝑪𝑪𝒏𝒏𝟒𝟒(𝒏𝒏𝒏𝒏) =0110, n1-n2 = 0001

Dados los valores n1 y n2 expresados en base binaria con 5 y 3 bits, respectivamente, calcule:

• El complemento a 1 (complemento a la base menos uno) de n2 con 8 bits. • El complemento a 2 (complemento a la base) de n2 con 8 bits. • La resta n1-n2 considerando 8 bits haciendo uso del procedimiento basado en

complemento a la base.

n1= 1 0101, n2=110, 𝐶𝐶18(𝑛𝑛2)=?, 𝐶𝐶28(𝑛𝑛2)=?, n1-n2=?

Solución: 𝑪𝑪𝟏𝟏𝟖𝟖(𝒏𝒏𝒏𝒏)=1111 1001, 𝑪𝑪𝒏𝒏𝟖𝟖(𝒏𝒏𝒏𝒏) =1111 1010, n1-n2 = 0000 1111

Page 42: INFORMÁTICA Libro de Problemas

Capítulo 2. Representación de la información | 43

Dados los valores n1 y n2 (expresados en base binaria con 8 bits), calcule:

• El complemento a 1 (complemento a la base menos uno) de n2 con 8 bits. • El complemento a 2 (complemento a la base) de n2 con 8 bits. • La resta n1-n2 considerando 8 bits haciendo uso del procedimiento basado en

complemento a la base.

n1= 1111 1111, n2=0000 1110, 𝐶𝐶18(𝑛𝑛2)=?, 𝐶𝐶28(𝑛𝑛2) =?, n1-n2=?

Solución: 𝑪𝑪𝟏𝟏𝟖𝟖(𝒏𝒏𝒏𝒏)= 1111 0001, 𝑪𝑪𝒏𝒏𝟖𝟖(𝒏𝒏𝒏𝒏) =1111 0010, n1-n2 = 1111 0001

Dados los valores n1 y n2 (expresados en base binaria con 4 bits), calcule:

• El complemento a 1 (complemento a la base menos uno) de n2 con 4 bits. • El complemento a 2 (complemento a la base) de n2 con 4 bits. • La resta n1-n2 considerando 4 bits haciendo uso del procedimiento basado en

complemento a la base.

n1=1111, n2= 0110, 𝐶𝐶14(𝑛𝑛2)=?, 𝐶𝐶24(𝑛𝑛2) =?, n1-n2=?

Solución: 𝑪𝑪𝟏𝟏𝟒𝟒(𝒏𝒏𝒏𝒏)= 1001, 𝑪𝑪𝒏𝒏𝟒𝟒(𝒏𝒏𝒏𝒏) =1010, n1-n2 = 1001

2.7. Codificacion de números en binario con signo

Codifique el valor n1, expresado en base decimal, para obtener su correspondiente código n2 en formato binario de 8 bits y con posibilidad de signo (usando el complemento a 2).

n1= -5, n2=?

Solución: n2 = 1111 1011

Procedimiento: Debido a que el número es negativo, primero se debe convertir el valor absoluto a binario con 8 bits. Para ello aplicaremos el método de las divisiones sucevias (Paso 1). Seguidamente, procederemos a calcular el complemento a 2 del valor binario obtenido (Paso 2).

Page 43: INFORMÁTICA Libro de Problemas

44 | Informática. Libro de problemas

• Paso 1:

(5)10(___)2

Tal y como se puede observar, el número 5 expresado en base 10 equivale al número 0000 0101 expresado en base binaria. Nótese que se han añadido ceros en las posiciones más a la izquierda para obtener el valor representado con 8 bits:

(5)10(0000 0101)2

• Paso 2:

Se calcula el complemento a 1 del valor binario obtenido en el paso 1:

𝐶𝐶18 (0000 0101) = 1111 1010

A partir de este, procedemos a calcular el complemento a 2:

𝐶𝐶28 (0000 0101) = 𝐶𝐶18(0000 0101) + 1 = 1111 1010 + 1 = 1111 1011

Por lo tanto, se concluye que n2=1111 1011.

5 2

1 2 2

0 1

Codifique el valor n1, expresado en base decimal, para obtener su correspondiente código n2 en formato binario con 8 bits y con posibilidad de signo (usando el complemento a 2).

n1 = 20, n2 = ?

Solución: n2 = 00010100

Procedimiento: Debido a que el número positivo, simplemente deberemos convertir el número a binario aplicando el método de divisiones sucesivas. Si fuera necesario, complementamos con ceros las posiciones más a la izquierda para obtener una representación en 8 bits, tal y como solicita el enunciado del ejercicio. En definitiva, tras aplicar este procedimiento, se llega a la conclusión que el número 20 (expresado en base 10) equivale al número 0001 0100 (expresado en base binaria):

(20)10(0001 0100)2

Page 44: INFORMÁTICA Libro de Problemas

Capítulo 2. Representación de la información | 45

Dado el valor n1, codificado en formato binario con 8 bits y posibilidad de signo (usando el complemento a 2), obtenga su valor n2 equivalente en base decimal.

n1= 1111 1001, n2=?

Solución: n2 = -7

Procedimiento: Debido a que el valor binario proporcionado comienza por el bit "1", nos encontramos ante un número negativo.

1111 1001 El número es negativo

En este caso, se debe proceder de la siguiente manera: primero calculamos el complemento a 2 del número en binario (Paso 1) y, seguidamente, convertimos a decimal (Paso 2) el valor obtenido. El resultado obtenido será el valor absoluto del resultado que solicita el ejercicio.

• Paso 1:

Complemento a 1 (𝐶𝐶18):

𝐶𝐶18 (1111 1001)=0000 0110

Complemento a 2, (𝐶𝐶28):

𝐶𝐶28 (1111 1001)= 𝐶𝐶18 (1111 1001)+1=0000 0110+1=0000 0111

• Paso 2: (0000 0111)21·22+1·21+1·20 =(7)10, 7 es el valor absoluto

Tal y como se ha explicado anteriormente, el resultado obtenido (7 en base decimal) es el valor absoluto del resultado que buscamos. Por lo tanto, se puede afirmar que 1111 1001 es la representación binaria del valor -7 decimal:

n2=-7

Calcule el valor n1 codificado en formato binario con 8 bits y con posibilidad de signo (usando el complemento a 2) a su valor n2 equivalente en base decimal.

n1= 0000 1110, n2=?

Solución: n2 = 14

Page 45: INFORMÁTICA Libro de Problemas

46 | Informática. Libro de problemas

Procedimiento: Debido a que el número binario comienza con el bit "0", entonces nos encontramos ante un número positivo.

0000 1110 El número es positivo

En este caso, para resolver el ejercicio simplemente se debe convertir el número representado en binario a decimal aplicando el método de expansión:

(0000 1110)21·23+1·22+1·21 = (14)10 A la vista del resultado obtenido en la operación anterior, afirmamos que el valor binario 0000 1110 equivale al valor 14 en base decimal:

n2 = 14

Dado el valor n1, representado en base decimal, obtenga su correspondiente código n2 en formato binario con 8 bits y posibilidad de signo (usando el complemento a 2).

n1= -14, n2=?

Solución: n2 = 1111 0010

Dado el valor n1, representado en formato binario con 8 bits y posibilidad de signo (usando el complemento a 2), determine su valor n2 equivalente en base decimal.

n1= -32, n2=?

Solución: n2 = 1110 0000

Dado el valor n1, representado en base decimal, obtenga su correspondiente código n2 en formato binario con 8 bits y posibilidad de signo (usando el complemento a 2).

n1= -17, n2=?

Solución: n2 = 1110 1111

Page 46: INFORMÁTICA Libro de Problemas

Capítulo 2. Representación de la información | 47

Dado el valor n1, representado en formato binario con 8 bits y posibilidad de signo (usando el complemento a 2), determine su valor n2 equivalente en base decimal.

n1= 1111 0111, n2=?

Solución: n2 = -9

Dado el valor n1, representado en formato binario con 8 bits y posibilidad de signo (usando el complemento a 2), determine su valor n2 equivalente en base decimal.

n1= 1000 0000, n2=?

Solución: n2 = -128

Dado el valor n1, representado en formato binario con 8 bits y posibilidad de signo (usando el complemento a 2), determine su valor n2 equivalente en base decimal.

n1= 0000 0011, n2=?

Solución: n2 = 3

2.8. Codificacion de números en hexadecimal con signo

Dado el valor n1, representado en base decimal, determine el valor n2 equivalente representado en base hexadecimal con 4 dígitos y con posibilidad de signo (usando el complemento a la base).

n1= -69, n2=?

Solución: n2 = FFBB

Procedimiento: Debido a que el valor n1 es un número negativo, para resolver este ejercicio debemos seguir dos pasos. En primer lugar, convertimos el valor absoluto de n1 (es decir, el valor 69) a hexadecimal con 4 dígitos (Paso 1). A continuación, calculamos el complemento a la base (𝐶𝐶164 ) del valor obtenido (Paso 2). Para calcular el complemento a la base en hexadecimal bastará con sumar 1 al complemento a la base menos uno (𝐶𝐶154 ). A su vez, para obtener el complemento a la base menos uno, deberemos restar a FFFF el valor en cuestión.

Page 47: INFORMÁTICA Libro de Problemas

48 | Informática. Libro de problemas

• Paso 1

(69)10(___)16

Como debemos obtener una representación con 4 dígitos hexadecimales, añadimos ceros en las posiciones más a la izquierda. De este modo, obtenemos lo siguiente:

(69)10(0045)16

• Paso 2

En primer lugar, calculamos el complemento a la base menos uno (𝐶𝐶154 ) del valor hexadecimal 0045:

FFFF

- 0045

𝐶𝐶154 (0045)= FFBA

Ahora procedemos a calcular el complemento a la base (𝐶𝐶164 ): 𝐶𝐶154 (0045) = FFBA

+ 1

𝐶𝐶164 (0045)= FFBB Por lo tanto, se concluye que n2 = FFBB.

69 16

5 4

Dado el valor n1, representado en base decimal, determine el valor n2 equivalente representado en base hexadecimal con 5 dígitos y con posibilidad de signo (usando el complemento a la base).

n1= 37, n2=?

Solución: n2 = 0025

Procedimiento: Debido a que n1 es positivo, para resolver este ejercicio simplemente debemos convertir n1 a hexadecimal aplicando el método de divisiones sucesivas.

Page 48: INFORMÁTICA Libro de Problemas

Capítulo 2. Representación de la información | 49

Para obtener una representación con 5 dígitos hexadecimales rellenamos con ceros las posiciones más a la izquierda. Por lo tanto, concluimos que n2 = 00025.

37 16

5 2

Dado el valor n1, representado en formato hexadecimal con 6 dígitos y con posibilidad de signo (usando el complemento a la base), determine el valor n2 equivalente en base decimal.

n1= FFFFF0, n2=?

Solución: n2 = -16

Procedimiento: Un número expresado en base hexadecimal es negativo cuando comienza por el dígito 8, 9, A, B, C, D, E o F. En nuestro caso, n1 comienza con el dígito F, por lo que es un número negativo.

FFFFF0 El número es negativo En esta situación, para resolver el ejercicio debemos seguir dos pasos. En primer lugar, se debe calcular el complemento a la base (𝐶𝐶166 ) en hexadecimal, de manera que obtenemos el valor absoluto de n1, es decir, su valor equivalente positivo (Paso 1). A continuación, se debe convertir a decimal el valor obtenido en el paso anterior. El valor decimal que obtenemos será el valor absoluto del resultado que buscamos (n2).

• Paso 1

En primer lugar calculamos el complemento a la base menos uno (𝐶𝐶156 ) de n1: FFFFFF

- FFFFF0

𝐶𝐶156 (FFFFF0) = 00000F

Page 49: INFORMÁTICA Libro de Problemas

50 | Informática. Libro de problemas

A partir de 𝐶𝐶156 calculamos fácilmente el complemento a la base (𝐶𝐶166 ): 𝐶𝐶156 (FFFFF0) = 00000F

+ 1

𝐶𝐶166 (FFFFF0)= 000010

• Paso 2

Convertimos de hexadecimal a decimal el valor 𝐶𝐶166 aplicando el método de expansión:

(000010)161·161 = (16)10, 16 es el valor absoluto

El valor decimal que hemos obtenido en el paso 2 (16) es el valor absoluto del resultado final. Por lo tanto, se concluye que n2=-16.

Dado el valor n1, representado en formato hexadecimal con 4 dígitos y con posibilidad de signo (usando el complemento a la base), determine el valor n2 equivalente en base decimal.

n1= AFF5, n2=?

Solución: n2 = -20491

Procedimiento: Un número expresado en base hexadecimal es negativo cuando comienza por el dígito 8, 9, A, B, C, D, E o F. En nuestro caso, n1 comienza con el dígito A, por lo que es un número negativo.

AFF5 El número es negativo Por lo tanto, para resolver este ejercicio se deben seguir los mismos pasos explicados en el anterior (Ejercicio 2.75).

• Paso 1

Calculamos el complemento a la base menos uno (𝐶𝐶154 ) de n1: FFFF

- AFF5

𝐶𝐶154 (AFF5) = 500A

Page 50: INFORMÁTICA Libro de Problemas

Capítulo 2. Representación de la información | 51

A partir de 𝐶𝐶154 calculamos el complemento a la base (𝐶𝐶164 )

𝐶𝐶154 (AFF5) = 500A

+ 1

𝐶𝐶164 (AFF5) = 500B • Paso 2

Convertimos de hexadecimal a decimal el valor 𝐶𝐶164 aplicando el método de expansión:

(500B)165·163+0·162+1·161+11·160 = (20491)10, 20491 es el valor absoluto

El valor decimal que se ha obtenido en el paso 2 (20491) es el valor absoluto del resultado final. Por lo tanto, concluimos que n2=-20491.

Dado el valor n1, representado en base decimal, determine el valor n2 equivalente representado en base hexadecimal con 5 dígitos y con posibilidad de signo (usando el complemento a la base).

n1= -1, n2=?

Solución: n2 = FFFFF

Dado el valor n1, representado en base decimal, determine el valor n2 equivalente representado en base hexadecimal con 4 dígitos y con posibilidad de signo (usando el complemento a la base).

n1= -33, n2=?

Solución: n2 = FFDF

Dado el valor n1, representado en base decimal, determine el valor n2 equivalente representado en base hexadecimal con 4 dígitos y con posibilidad de signo (usando el complemento a la base). n1= -563, n2=?

Solución: n2 = FDCD

Page 51: INFORMÁTICA Libro de Problemas

52 | Informática. Libro de problemas

Dado el valor n1, representado en formato hexadecimal con 4 dígitos y con posibilidad de signo (usando el complemento a la base), determine el valor n2 equivalente en base decimal.

n1= 8000, n2=?

Solución: n2 = -32768

Dado el valor n1, representado en formato hexadecimal con 5 dígitos y con posibilidad de signo (usando el complemento a la base), determine el valor n2 equivalente en base decimal.

n1= 00029, n2=?

Solución: n2 = 41

Dado el valor n1, representado en formato hexadecimal con 6 dígitos y con posibilidad de signo (usando el complemento a la base), determine el valor n2 equivalente en base decimal.

n1= FFFFE5, n2=?

Solución: n2 = -27

Page 52: INFORMÁTICA Libro de Problemas

3

PROGRAMACIÓN ESTRUCTURADA Y

ALGORITMIA

Page 53: INFORMÁTICA Libro de Problemas
Page 54: INFORMÁTICA Libro de Problemas

Capítulo 3. Programación estructurada y algoritmia | 55

3.1. Suma de pares Diseñe el flujograma de un programa que muestre la suma de los números pares menores o iguales que 100. Posible solución:

BEGIN

suma ← 0

numero ← 2

numero ≤ 100

suma ← suma + numero

numero ← numero + 2

END

SI NO

Mostrar suma

Page 55: INFORMÁTICA Libro de Problemas

56 | Informática. Libro de problemas

3.2. Tabla de multiplicar Diseñe el flujograma de un programa que recoja por pantalla un número entero positivo comprendido en el intervalo [0,9] y que muestre la tabla de multiplicar del mismo. En caso de que el valor introducido por el usuario no sea válido, deberá informar del error y permitirle introducir un nuevo valor. Posible solución:

Leer n

i ← 0

n ≥ 0 AND n≤9

END

BEGIN

Mostrar “ERROR VALOR”

i ≤ 10

i ← i + 1

Mostrar n x i

NO

SI

SI NO

Page 56: INFORMÁTICA Libro de Problemas

Capítulo 3. Programación estructurada y algoritmia | 57

3.3. Calcular hora Diseñe el flujograma de un programa que calcula la siguiente hora. Por ejemplo, si el usuario introduce las 14 horas, 32 minutos y 50 segundos el programa devolverá las 14:32:51. El programa debe contemplar aquellos casos en los que los horas, minutos o segundos alcancen sus valores límite. Por ejemplo, si el usuario introduce las 19 horas, 59 minutos y 59 segundos, entonces deberá devolver las 20:00:00 horas. Posible solución:

BEGIN

s ← s + 1

s < 59

END

Leer h

Leer m

Leer s

SI NO

m ← m + 1

m < 59SI NO

s ← 0

h ← 0

h = 23SI NO

m ← 0

h ← h + 1

Mostrar h:m:s

Page 57: INFORMÁTICA Libro de Problemas

58 | Informática. Libro de problemas

3.4. Corredor elegido Escriba el flujograma de un programa que determine si un atleta es seleccionado para correr una maratón. Para seleccionar a un corredor, debe haber terminado una maratón anterior en un tiempo máximo. Los tiempos de calificación son 150 minutos para hombres menores de 40 años, 175 minutos para hombres igual o mayor de 40 años, y 180 minutos para mujeres. Los datos a introducir al programa son los siguientes: sexo (H/M), edad y tiempo efectuado en su anterior maratón. El programa mostrará el mensaje "Seleccionado" o "No seleccionado", según los criterios anteriormente indicados. Posible solución:

sexo = V

END

Mostrar “SELECCIONADO”

BEGIN

Leer sexo

Leer edad

Leer tiempo

seleccionado ← 0

edad < 40 ANDtiempo ≤ 150

seleccionado ← 1

SI

SI NO

edad ≥ 40 ANDtiempo ≤ 175

seleccionado ← 1

SI NO

tiempo ≤ 180

seleccionado ← 1

SI

NO

NO

seleccionado = 1

Mostrar “NO SELECCIONADO”

Page 58: INFORMÁTICA Libro de Problemas

Capítulo 3. Programación estructurada y algoritmia | 59

3.5. Calcular cuadros y cubos Diseñe el flujograma de un programa que calcule los cuadrados y los cubos de los números comprendidos entre dos valores M y N introducidos por teclado. Si N no es mayor que M, el programa finalizará su ejecución mostrando un mensaje de error. Posible solución:

BEGIN

END

Mostrar M x M

Leer M

Leer N

M < N

Mostrar “ERROR VALORESNO VÁLIDO”

NO

M ≤ NNO

SI

Mostrar M x M x M

M ← M + 1

SI

Page 59: INFORMÁTICA Libro de Problemas

60 | Informática. Libro de problemas

3.6. Número primo Diseñe el flujograma de un programa que reciba un número entero positivo mayor a 0 y que determine si se trata de un número primo. Recuerde que un número es primo si tiene exactamente dos divisores: el 1 y él mismo. Posible solución 1:

BEGIN

d ← 1

END

Leer n

n ≤ 0Mostrar “ERROR VALOR”

SI

NO

c ← 0

d ≤ nSI NO

N mod d = 0

c ← c + 1

d ← d + 1

SI NOc = 2

Mostrar “ES PRIMO”

Mostrar “NO ES PRIMO”

SI NO

Page 60: INFORMÁTICA Libro de Problemas

Capítulo 3. Programación estructurada y algoritmia | 61

Posible solución 2:

BEGIN

d ← 1

END

Leer n

n ≤ 0Mostrar “ERROR VALOR”

SI

NO

c ← 0

SI NO

n mod d = 0

c ← c + 1

d ← d + 1

SI NOc = 1

Mostrar “ES PRIMO”

Mostrar “NO ES PRIMO”

SI NO

1≤

cAND

nd

Page 61: INFORMÁTICA Libro de Problemas

62 | Informática. Libro de problemas

3.7. Análisis de secuencia numérica Realice el flujograma de un programa que realice la siguiente tarea. Inicialmente debe solicitar al usuario el número de valores numéricos que desea introducir por teclado. Seguidamente debe verificar que el valor recibido es mayor a 0. Si esto se cumple, el programa recogerá todos valores enteros (positivos y negativos) del usuario. Por último, el programa devolverá los siguientes datos: número más grande, número más pequeño, la media de los valores introducidos. Posible solución:

END

BEGIN

Leer n

n ≤ 0Mostrar “ERROR VALOR”

SI

NO

Leer v

min ← v

max ← v

suma ← v

c ← 1

c < n

Leer v

min > v

min ← v

SI NO

max < v

max ← v

SI NO

suma ← suma + v

c ← c + 1

SI NO

Mostrar max

Mostrar min

Mostrar suma/n

Page 62: INFORMÁTICA Libro de Problemas

Capítulo 3. Programación estructurada y algoritmia | 63

3.8. Suma de números Escriba el flujograma de un programa que encuentre el primer valor N para el que la suma

1 + 2 + 3 + 4 + ....+ N exceda un valor M que se introduce por teclado. El programa debe asegurarse que M es un valor entero positivo mayor a 0. Posible solución:

suma ← 1

suma > M

END

Mostrar N

BEGIN

Leer M

M ≤ 0Mostrar “ERROR VALOR”

SI

NO

N ← 1

SI

N ← N + 1

suma ← suma + N

NO

Page 63: INFORMÁTICA Libro de Problemas

64 | Informática. Libro de problemas

3.9. Potencia Desarrolle el flujograma de un programa en C que reciba un número entero positivo N y que calcule el valor NN. Si el número N introducido por el usuario fuera menor o igual a 0, el programa terminará mostrando un mensaje de error. Posible solución:

BEGIN

pot ← N

N ≤ 0

END

Leer N

Mostrar “ERROR VALOR”

SI

c ← 1

c < N

NO

NOMostrar pot

pot ← pot x N

c ← c + 1

SI

Page 64: INFORMÁTICA Libro de Problemas

Capítulo 3. Programación estructurada y algoritmia | 65

3.10. Sucesión de ULAM Desarrolle el flujograma de un programa en C que reciba un entero positivo N y que devuelva la sucesión de ULAM. Se debe comprobar que el valor N es mayor o igual a 1. El cálculo de la sucesión de ULAM consiste en los siguientes pasos:

1. Se inicia con cualquier entero positivo N. 2. Si el número es par, se divide entre 2. Si es impar, se multiplica por 3 y se suma 1 al

resultado. 3. Se deben obtener sucesivamente números enteros repitiendo el proceso descrito en el

paso anterior. 4. El proceso finaliza cuando se obtenga el número 1.

Por ejemplo, si el entero inicial es 45, la secuencia es la siguiente: 45, 136, 68, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1. Posible solución:

N = 1

END

BEGIN

Leer N

N ≤ 0Mostrar “ERROR VALOR”

SI

NO

SI NO

N mod 2 = 0

N ← N / 2 N ← N x 3

N ← N + 1

SI NO

Mostrar N

Page 65: INFORMÁTICA Libro de Problemas
Page 66: INFORMÁTICA Libro de Problemas

4

TIPOS DE DATOS PRIMITIVOS

Page 67: INFORMÁTICA Libro de Problemas
Page 68: INFORMÁTICA Libro de Problemas

Capítulo 4. Tipos de datos primitivos | 69

4.1. Operadores de asignación, aritméticos y asignación compuesta

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable y tras ejecutar la operación resaltada en negrita?

int x=3, y=5;

x = y;

y = x;

Solución: y = 5

Comentarios: Debido a que el valor almacenado en la variable y (5) se ha guardado en la variable x, la operación destacada en negrita vuelve a almacenar dicho valor en la variable y.

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable z tras ejecutar la operación resaltada en negrita?

int x=7, y=2, z;

z = x / y;

Solución: z = 3

Comentarios: La división entera produce un cociente entero. Cualquier parte fraccionaria se desecha, no hay redondeo. Por lo tanto, la operación 7 / 2 produce como resultado 3, siendo este el valor que se almacena en la variable z.

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable z tras ejecutar la operación resaltada en negrita?

int x=7, y=2;

float z;

z = x / y;

Solución: z = 3.0

Comentarios: La división entera produce un cociente entero. Cualquier parte fraccionaria se desecha, no hay redondeo. Por lo tanto, la operación 7 / 2 produce como resultado 3, el cual se convierte posteriormente a un valor punto flotanto (3.0) para ser almacenado en la variable z.

Page 69: INFORMÁTICA Libro de Problemas

70 | Informática. Libro de problemas

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable z tras ejecutar la operación resaltada en negrita?

int x=7, y=2;

int z;

z = x / y;

Solución: z = 3

Comentarios:

La división entre variables float produce un resultado 3.5 pero al guardarlo en una variable entera se pierde la parte fraccionaria.

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable z tras ejecutar la operación resaltada en negrita?

int y=2;

float z;

z = 7 / y;

Solución: z = 3.0

Comentarios:

Un literal sin decimal (como el número 7) se codifica como un entero. La división entera produce un cociente entero. Cualquier parte fraccionaria se desecha, no hay redondeo. Por lo tanto, la operación 7 / 2 produce 3, siendo este el valor que se almacena en la variable z.

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable z tras ejecutar la operación resaltada en negrita?

int y=2;

float z;

z = 7.0 / y;

Solución: z = 3.5

Comentarios:

Un literal con decimal (como el número 7. o 7.0) se codifica como un punto flotante y, por lo tanto, la división produce un resultado con decimal 3.5.

Page 70: INFORMÁTICA Libro de Problemas

Capítulo 4. Tipos de datos primitivos | 71

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable c tras ejecutar la operación resaltada en negrita?

int a=11, b=3;

short c;

c = a % b;

Solución: c = 2

Comentarios:

El operador % devuelve el resto que produce la división entera entre el contenido de la variable a el contenido de la varible b.

Recuerde que el operador de módulo solamente se puede aplicar a enteros (es decir, las variables a y b no pueden ser números reales).

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable c tras ejecutar la operación resaltada en negrita?

int a=11, b=3;

float c;

c = a % b;

Solución: c = 2.0

Comentarios:

El operador % devuelve el resto que produce la división entera entre el contenido de la variable a el contenido de la varible b. El resultado del operador módulo (2) se almacena en la variable c que, al ser de tipo float, debe convertirse en un valor punto flotante.

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable x tras ejecutar la operación resaltada en negrita?

int x=3, y=5;

x = y++ + 2;

Solución: x = 7

Comentarios: La operación resaltada en negrita es equivalente a ejecutar las siguientes operaciones:

x = y + 2;

y = y + 1;

Page 71: INFORMÁTICA Libro de Problemas

72 | Informática. Libro de problemas

Es decir, primero se ejecuta la operación x = y + 2 donde se suma el valor almacenado en la variable y (5) y literal entero 2. El resultado de esta operación se almacena en la variable x. A continuación, se ejecuta la operación y = y + 1 que almacena en la variable y el valor de la misma pero incrementado en una unidad.

En definitiva, la variable x almacena el valor 7, mientra que la variable y el valor 6. Observe que el valor almacenado inicialmente en la variable x se pierde.

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable "x" tras ejecutar la operación resaltada en negrita?

int x, y=5;

x = 3 * y++;

Solución: x = 15

Comentarios:

La operación resaltada en negrita es equivalente a ejecutar las siguientes operaciones: x = 3 * y;

y = y + 1;

Es decir, primero se multiplica el valor inicial de la variable y (5) con 3 y el resultado se almacena en x. A continuación, el contenido almacenado en la variable y se incrementa en una unidad, almacenándose el nuevo valor en dicha variable.

En definitiva, la variable x toma el valor de 15 mientras que y toma el valor de 6.

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable x tras ejecutar la operación resaltada en negrita?

int x=1, y=5;

x = ++y + 2;

Solución: x = 8

Comentarios:

La operación resaltada en negrita es equivalente a ejecutar las siguientes operaciones: y = y + 1;

x = y + 2;

La primera operación incrementa en una unidad el valor almacenado en la variable y. Seguidamente, la segunda operación suma el número 2 y el nuevo valor almacenado en la variable y, de manera que el resultado se almacena en la variable x.

Page 72: INFORMÁTICA Libro de Problemas

Capítulo 4. Tipos de datos primitivos | 73

En definitiva, tras ejecutar la operación indicada en este ejercicio, la variable y contiene el valor 6 mientras que la variable x el valor 8. Observe que el valor inicial de la variable x (1) se pierde.

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable x tras ejecutar la operación resaltada en negrita?

int x, y=5;

x = 3 * ++y;

Solución: x = 18

Comentarios:

La operación resaltada en negrita es equivalente a ejecutar las siguientes operaciones: y = y + 1;

x = 3 * y;

Es decir, primero se incrementa en una unidad el valor almacenado en y. La segunda operación, multiple el literal entero 3 por el nuevo valor de la variable y, almacenándose el resultado en la variable x.

En definitiva, tras ejecutar la operación indica en este ejercicio, la variable y toma el valor 6 y la variable x el valor 18.

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable z tras ejecutar la operación resaltada en negrita?

int x=5, y=8, z;

z = ++x + y++;

Solución: z = 14

Comentarios:

La operación resaltada en negrita es equivalente a ejecutar las siguientes operaciones: x = x + 1;

z = x + y;

y = y + 1;

Tras ejecutar estas operaciones, la variable x adopta el valor 6, la variable y el valor 9 y la variable z el valor 14.

Page 73: INFORMÁTICA Libro de Problemas

74 | Informática. Libro de problemas

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable z tras ejecutar la operación resaltada en negrita?

int x=5, y=8, z;

x = ++x + ++y;

Solución: z = 15

Comentarios:

La operación resaltada en negrita es equivalente a ejecutar las siguientes operaciones: x = x + 1;

y = y + 1;

z = x + y;

Tras ejecutar estas operaciones, la variable x adopta el valor 6, la variable y el valor 9 y la variable z el valor 15.

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable d tras ejecutar la operación resaltada en negrita?

int a=5, b=2;

short c=10, d;

d = a + b + c--;

Solución: d = 17

Comentarios:

La operación resaltada en negrita es equivalente a ejecutar las siguientes operaciones: d = a + b + c;

c = c - 1;

Tras ejecutar estas operaciones, la variable d adopta el valor 17 y la variable c el valor 9. El valor almacenado en las variables a y b no cambia.

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable d tras ejecutar la operación resaltada en negrita?

int a=5, b=2;

float c=10, d;

d = a + b + --c;

Solución: d = 16.0

Page 74: INFORMÁTICA Libro de Problemas

Capítulo 4. Tipos de datos primitivos | 75

Comentarios:

La operación resaltada en negrita es equivalente a ejecutar las siguientes operaciones: c = c - 1;

d = a + b + c;

Tras ejecutar estas operaciones, la variable d adopta el valor 17 y la variable c el valor 9.

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable a tras ejecutar la operación resaltada en negrita?

int a = 5;

a *= 2;

Solución: a = 10

Comentarios:

La operación resaltada en negrita es equivalente a ejecutar la siguiente operación: a = a * 2;

Tras ejecutar esta operación, la variable a adopta el valor 10.

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable a tras ejecutar la operación resaltada en negrita?

int a = 5, b = 3;

a *= b;

Solución: a = 15

Comentarios:

La operación resaltada en negrita es equivalente a ejecutar la siguiente operación: a = a * b;

Tras ejecutar esta operación, la variable a adopta el valor 15. Observe que el valor almacenado en la variable b no cambia.

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable a tras ejecutar la operación resaltada en negrita?

int a=5, b=3;

a *= b + 3;

Solución: a = 30

Page 75: INFORMÁTICA Libro de Problemas

76 | Informática. Libro de problemas

Comentarios:

La operación resaltada en negrita es equivalente a ejecutar la siguiente operación: a = a * (b + 3);

Tras ejecutar esta operación, la variable a adopta el valor 30. Observe que el valor almacenado en la variable b no cambia.

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable a tras ejecutar la operación resaltada en negrita?

float a=5, b=3;

a *= b++;

Solución: a = 15.0

Comentarios:

La operación resaltada en negrita es equivalente a ejecutar las siguientes operaciones: a = a * b;

b = b + 1;

Tras ejecutar esta operación, la variable a adopta el valor 15 mientras que la variable b adopta el valor 4.

4.2. Operadores relacionales, lógicos y a nivel de bit

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita?

int x=1, y=4, z=-2;

x > y || y > z

Solución: Verdadero

Comentarios: Según el orden de precedencia de operadores, primero se deben evaluar las expresiones que involucran el uso de operadores relacionales:

x > y Falso

y > z Verdadero A continuación, se evalua el operador lógico "OR" (||), tomando como referencia los valores que han producido las expresiones anteriores:

Falso || Verdadero Verdadero

Por lo tanto, la operación genera el valor "Verdadero".

Page 76: INFORMÁTICA Libro de Problemas

Capítulo 4. Tipos de datos primitivos | 77

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita?

int x=1, y=4, z=-2;

x > y && y > z

Solución: Verdadero

Comentarios: Según el orden de precedencia de operadores, primero se deben evaluar las expresiones que involucran el uso de operadores relacionales:

x > y Falso

y > z Verdadero

A continuación, se evalua el operador lógico "AND" (&&), tomando como referencia los valores que han producido las expresiones anteriores:

Falso && Verdadero Falso

Por lo tanto, la operación genera el valor "Falso".

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita?

int x=1, y=4;

x * 3 == y * 4

Solución: Verdadero

Comentarios: Según el orden de precedencia de operadores, primero se deben evaluar las expresiones que involucran el uso de operadores aritméticos, en nuestro caso, el operador multiplicación (*) :

x * 3 3

y * 4 16

A continuación, se debe evaluar el operador relacional "==", tomando como referencia los valores que han producido las expresiones anteriores:

3 == 16 Falso

Por lo tanto, la operación genera el valor "Falso".

Page 77: INFORMÁTICA Libro de Problemas

78 | Informática. Libro de problemas

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita?

short a=10;

int b=2, c=7;

a>=c || b!=2

Solución: Verdadero

Comentarios: Según el orden de precedencia de operadores, primero se deben evaluar las expresiones que involucran el uso de operadores relacionales:

a >= c Verdadero

b != 2 Falso

A continuación, se debe evaluar el operador lógico "OR" (||), tomando como referencia los valores que han producido las expresiones anteriores:

Verdadero || Falso Verdadero

Por lo tanto, la operación genera el valor "Verdadero".

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita?

int x=1, y=4, z=-3;

x > y && !(z > y)

Solución: Falso

Comentarios: En este caso, el uso de paréntesis modifica el orden en el que deben ser evaluados los operadores. En primer lugar, debemos evaluar el operador relacional "MAYOR" (>) que se emplea en la expresión situada entre paréntesis:

x > y Falso En segundo lugar, debemos evaluar el operador "NEGACIÓN" (!), tomando como referencia el valor producido anteriormente por la expresión z > y;

!(Falso) Verdadero En tercer lugar, pasamos a evaluar el uso del operador relacional "MAYOR" (>) de la expresión x > y :

x > y Falso

Page 78: INFORMÁTICA Libro de Problemas

Capítulo 4. Tipos de datos primitivos | 79

Por último, evaluamos el operador lógico "AND" (&&), tomando como referencia los valores que han producido las expresiones anteriores:

Falso && Verdadero Falso

Por lo tanto, la operación genera el valor "Falso".

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita?

int x=1, y=4, z=-3;

x > y || !z

Solución: Falso

Comentarios: Según el orden de precedencia de operadores, primero se deben evaluar la expresión que hace uso del operador "NEGACIÓN" (!):

!z Falso

Tenga en cuenta que cualquier valor distinto de 0 se considera verdadero, por lo que el valor almacenado en la variable z (4) es considerado como verdadero. Al negarlo, se genera el valor falso.

En segundo lugar, el operador más prioritario es el relacional (>), por lo que procedemos a evaluar la expresión afectada por el mismo:

x > y Falso

En último lugar, evaluamos el operador lógico "OR" (||), tomando como referencia los valores que han producido las expresiones anteriores:

Falso || Falso Falso

Por lo tanto, la operación genera el valor "Falso".

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita?

int a=7, b=10;

float z=2.56;

z<a && b>=a

Solución: Verdadero

Page 79: INFORMÁTICA Libro de Problemas

80 | Informática. Libro de problemas

Comentarios: Según el orden de precedencia de operadores, primero se deben evaluar las expresiones que involucran el uso de operadores relacionales:

z > a Verdadero

b >= a Verdadero

A continuación, se debe evaluar el operador lógico "AND" (&&), tomando como referencia los valores que han producido las expresiones anteriores:

Verdadero && Verdadero Verdadero

Por lo tanto, la operación genera el valor "Verdadero".

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita? int a=7, b=10;

float z=2.56;

z<a && b>=a && !a

Solución: Falso

Comentarios: Según el orden de precedencia de operadores, primero se debe evaluar el operador lógico de "NEGACIÓN" (!).

!a Falso

Tal y como se ha visto en ejercicios anteriores, cualquier valor distinto de 0 se considera verdadero, por lo que el valor almacenado en la variable a (7) es considerado como verdadero. Al negarlo, se genera el valor falso.

En segundo lugar, debemos evaluar los operadores relacionales pues, de entre los que faltan por evaluar en la expresión, estos son los que tienen mayor prioridad:

z < a Verdadero b >= a Verdadero

Para finalizar, debemos procesar el uso de los operadores lógicos, en nuestro caso, el operador "AND" (&&). Teniendo en cuenta que es asociativo por la izquierda, la evaluación debemos realizarla según se indica a continuación:

Verdadero && Verdadero && Falso

Por lo tanto, la operación genera el valor "Falso".

Verdadero && Falso Falso

Page 80: INFORMÁTICA Libro de Problemas

Capítulo 4. Tipos de datos primitivos | 81

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita?

int a=7, b=10;

float z=2.56;

z>a || b>=a && !a

Solución: Falso

Comentarios: Atendiendo all orden de precedencia de operadores, primero se debe evaluar el operador lógico de "NEGACIÓN" (!).

!a Falso

Tal y como se ha visto en ejercicios anteriores, cualquier valor distinto de 0 se considera verdadero, por lo que el valor almacenado en la variable a (7) es considerado como verdadero. Al negarlo, se genera el valor falso.

En segundo lugar, debemos evaluar los operadores relacionales pues, de entre los que faltan por evaluar en la expresión, estos son los que tienen mayor prioridad:

z > a Falso b >= a Verdadero

Para finalizar, debemos procesar el uso de los operadores lógicos, en nuestro caso, el operador "OR" (||) y "AND" (&&). En el orden de precedencia, el operador "AND" tiene mayor prioridad que el operador "OR", por lo que la evaluación debemos realizarla según se indica a continuación:

Falso || Verdadero && Falso

Por lo tanto, la operación genera el valor "Falso".

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita?

int a=10, b=7;

a>2 && b%2 && a

Solución: Verdadero

Falso | | Falso Falso

Page 81: INFORMÁTICA Libro de Problemas

82 | Informática. Libro de problemas

Comentarios: Según el orden de precedencia de operadores, primero se deben evaluar las expresiones que involucran el uso de operadores aritméticos:

a > 2 Verdadero

b % 2 Verdadero (cualquier valor distinto de 0 se considera verdad) Para finalizar, debemos procesar el uso del operador lógico "AND" (&&). Teniendo en cuenta que es asociativo por la izquierda, la evaluación debemos realizarla según se indica a continuación:

Verdadero && Verdadero && Verdadero

Por lo tanto, la operación genera el valor "Verdadero".

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita? int a=10, b=7, c=0;

a>2 && b%2 && c

Solución: Verdadero

Comentarios: Según el orden de precedencia de operadores, primero se deben evaluar las expresiones que involucran el uso de operadores aritméticos:

a > 2 Verdadero

b % 2 Verdadero (cualquier valor distinto de 0 se considera verdad) Para finalizar, debemos procesar el uso del operador lógico "AND" (&&). Teniendo en cuenta que es asociativo por la izquierda, la evaluación debemos realizarla según se indica a continuación:

Verdadero && Verdadero && Falso

Por lo tanto, la operación genera el valor "Falso."

Verdadero && Verdadero Verdadero

Verdadero && Falso Falso

Page 82: INFORMÁTICA Libro de Problemas

Capítulo 4. Tipos de datos primitivos | 83

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita? int a=10, b=2;

(a-2 > 0 && b!=1) || ( 2*b >= 7)

Solución: Verdadero

Comentarios: El uso de parentésis altera el orden de evaluación de los operadores marcado por el orden de precedencia. En este caso, observamos dos expresiones, cada una acotada por un paréntesis: (a-2 > 0 && b!=1) y (2*b >= 7).

A continuación se explica como se resuelve la expresión (a-2 > 0 && b!=1) aplicando el orden de precedencia de operadores en C:

(a-2 > 0 && b!=1)

( 8 > 0 && b!=1) ( Verdadero && b!=1) ( Verdadero && Verdadero)

Verdadero

Seguidamente procesamos la expresión (2*b >= 7) según se indica a continuación:

(2*b >= 7)

(4 >= 7) Falso Por último, procesamos el operador lógico "OR" (||), tomando como referencia los valores devueltos por las dos expresiones analizadas anteriormente:

Verdadero || Falso Verdadero

Por lo tanto, la operación genera el valor "Falso."

Nota: Observe que el resultado obtenido sería el mismo si la expresión no hiciera uso de paréntesis. No obstante, se aconseja hacer uso de los paréntesis cuando no estamos seguros de la precedencia de operadores, especialmente en expresiones que involucra el uso de operadores de distinta naturaleza.

Page 83: INFORMÁTICA Libro de Problemas

84 | Informática. Libro de problemas

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita? int x=3;

x>4 || (x<=4 && (x+1)%2==0)

Solución: Verdadero

Comentarios: La siguiente figura representa de manera resumida como se debe proceder para resolver esta expresión:

x>4 || (x<=4 && (x+1)%2==0)

x>4 || (x<=4 && ( 4 )%2==0)

x>4 || (x<=4 && 0 ==0)

x>4 || (Verdadero && Verdadero)

x>4 || Verdadero

Falso || Verdadero

Verdadero

Por lo tanto, la operación genera el valor "Verdadero."

Nota: Observe que el resultado obtenido sería el mismo si la expresión no hiciera uso de paréntesis. No obstante, se aconseja hacer uso de los paréntesis cuando no estamos seguros de la precedencia de operadores, especialmente en expresiones que involucra el uso de operadores de distinta naturaleza.

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita? short e, f=0x00CA, g=0XFF1F;

e = f&g;

Solución: 0x000A

Page 84: INFORMÁTICA Libro de Problemas

Capítulo 4. Tipos de datos primitivos | 85

Comentarios:

Los enteros representados con el prefijo 0x indican que el número es en hexadecimal. Con la representación en hexadecimal podemos fácilmente ver su codificación binaria convirtiendo cada símbolo en hexadecimal a binario con 4 bits:

f=0x00CA en binario es: 0000 0000 1100 1010

g=0XFF1F en binario es: 1111 1111 0001 1111

El operador & es el operador "AND" a nivel de bit. Tal y como se muestra a continuación, se aplica de manera consecutiva entre cada pareja de bits que ocupan la misma posición en los valores almacenados en las varaibles f y g:

f 0 0 0 0 0 0 0 0 1 1 0 0 1 0 1 0 g 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1

e=f&g 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0

Si transformamos el número binario en representación hexadecimal obtenemos 0x000A, que es el valor que se almacena en la variable e.

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita? short e, f=0x00AC, g=0XFF10;

e=f&g;

Solución: 0x0000

Comentarios:

Los enteros representados con el prefijo 0x indican que el número es en hexadecimal. Con la representación en hexadecimal podemos fácilmente ver su codificación binaria convirtiendo cada símbolo en hexadecimal a binario con 4 bits:

f=0x00AC en binario es: 0000 0000 1010 1100

g=0XFF10 en binario es: 1111 1111 0001 0000

El operador & es el operador "AND" a nivel de bit. Tal y como se muestra a continuación, se aplica de manera consecutiva entre cada pareja de bits que ocupan la misma posición en los valores almacenados en las varaibles f y g:

0 & 1 0 1 & 0 0 0 & 0 0 1 & 1 1

Page 85: INFORMÁTICA Libro de Problemas

86 | Informática. Libro de problemas

f 0 0 0 0 0 0 0 0 1 0 1 0 1 1 0 0 g 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 0

e=f&g 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Si transformamos el número binario en representación hexadecimal obtenemos 0x0000, que es el valor que se almacena en la variable e.

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita? short e, f=0x00CA, g=0xFF1F;

e=f|g;

Solución: 0xFFDF

Comentarios:

Los enteros representados con el prefijo 0x indican que el número es en hexadecimal. Con la representación en hexadecimal podemos fácilmente ver su codificación binaria convirtiendo cada símbolo en hexadecimal a binario con 4 bits:

f=0x00CA en binario es: 0000 0000 1100 1010

g=0xFF1F en binario es: 1111 1111 0001 1111

El operador | es el operador "OR" a nivel de bit. Tal y como se muestra a continuación, se aplica de manera consecutiva entre cada pareja de bits que ocupan la misma posición en los valores almacenados en las varaibles f y g:

f 0 0 0 0 0 0 0 0 1 1 0 0 1 0 1 0 g 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1

e=f|g 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1

Si transformamos el número binario en representación hexadecimal obtenemos 0xFFDF, que es el valor que se almacena en la variable e.

0 | 1 1 1 | 0 1 0 | 0 0 1 | 1 1

Page 86: INFORMÁTICA Libro de Problemas

Capítulo 4. Tipos de datos primitivos | 87

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita?

short e, f=0xAA, g=0xF1F;

e=f|g;

Solución: 0x0FBF aunque también es válido el valor 0xFBF

Comentarios:

Los enteros representados con el prefijo 0x indican que el número es en hexadecimal. Las variables f y g son tipo short (16 bits), por lo que la codificación completa de la variable f en hexadecimal es 0x00AA mientras que la codificción de la variable g es 0x0F1F. Con la representación en hexadecimal podemos fácilmente ver su codificación binaria convirtiendo cada símbolo en hexadecimal a binario con 4 bits:

f=0x00AA en binario es: 0000 0000 1010 1010

g=0x0F1F en binario es: 0000 1111 0001 1111

El operador | es el operador "OR" a nivel de bit. Tal y como se muestra a continuación, se aplica de manera consecutiva entre cada pareja de bits que ocupan la misma posición en los valores almacenados en las varaibles f y g:

f 0 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 g 0 0 0 0 1 1 1 1 0 0 0 1 1 1 1 1

e=f|g 0 0 0 0 1 1 1 1 1 0 1 1 1 1 1 1

Si transformamos el número binario en representación hexadecimal obtenemos 0x0FBF, que es el valor que se almacena en la variable e.

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita?

short e, f=0x00CA, g=0xFF1F;

e=f^g;

Solución: 0xFFD5

Comentarios:

Los enteros representados con el prefijo 0x indican que el número es en hexadecimal. Con la representación en hexadecimal podemos fácilmente ver su codificación binaria convirtiendo cada símbolo en hexadecimal a binario con 4 bits:

f=0x00CA en binario es: 0000 0000 1100 1010

Page 87: INFORMÁTICA Libro de Problemas

88 | Informática. Libro de problemas

g=0xFF1F en binario es: 1111 1111 0001 1111

El operador ^ es el operador "XOR" (OR Exclusivo) a nivel de bit. Al igual que ocurre con cualquier operador de este tipo, se aplica de manera consecutiva entre cada pareja de bits que ocupan la misma posición en los valores almacenados en las varaibles f y g:

F 0 0 0 0 0 0 0 0 1 1 0 0 1 0 1 0 G 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1

e=f^g 1 1 1 1 1 1 1 1 1 1 0 1 0 1 0 1

Si transformamos el número binario en representación hexadecimal obtenemos 0xFFD5, que es el valor que se almacena en la variable e.

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita?

short e, g=0xFFA1;

e= ∼g;

Solución: 0x005E

Comentarios:

Los enteros representados con el prefijo 0x indican que el número es en hexadecimal. Con la representación en hexadecimal podemos fácilmente ver su codificación binaria convirtiendo cada símbolo en hexadecimal a binario con 4 bits:

g=0xFFA1 en binario es: 1111 1111 1010 0001

El operador ~ es el operador "NOT" (Complemento a 1) a nivel de bit. Al igual que ocurre con cualquier operador de este tipo, se aplica de individual a cada uno de los bits que confoman el valor almacenado en la variable g. Para aplicar este operador bastará con invertir el valor de cada bit, tal y como se indica continuación:

G 1 1 1 1 1 1 1 1 1 0 1 0 0 0 0 1

e=~g 0 0 0 0 0 0 0 0 0 1 0 1 1 1 1 0

Si transformamos el número binario en representación hexadecimal obtenemos 0x005E, que es el valor que se almacena en la variable e.

0 | 1 1 1 | 0 1 0 | 0 0 1 | 1 0

Page 88: INFORMÁTICA Libro de Problemas

Capítulo 4. Tipos de datos primitivos | 89

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita?

short e, g=0xFA;

e= ∼g;

Solución: 0xFF05

Comentarios:

Los enteros representados con el prefijo 0x indican que el número es en hexadecimal. Con la representación en hexadecimal podemos fácilmente ver su codificación binaria convirtiendo cada símbolo en hexadecimal a binario con 4 bits:

g=0x00FA en binario es: 0000 0000 1111 1010

El operador ~ es el operador "NOT" (Complemento a 1) a nivel de bit. Al igual que ocurre con cualquier operador de este tipo, se aplica de individual a cada uno de los bits que confoman el valor almacenado en la variable g. Para aplicar este operador bastará con invertir el valor de cada bit, tal y como se indica continuación:

G 0 0 0 0 0 0 0 0 1 1 1 1 1 0 1 0

e=~g 1 1 1 1 1 1 1 1 0 0 0 0 0 1 0 1

Si transformamos el número binario en representación hexadecimal obtenemos 0xFF05, que es el valor que se almacena en la variable e.

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita?

short e, g=0xFFA1;

e= g>>4;

Solución: 0xFFFA

Comentarios:

Los enteros representados con el prefijo 0x indican que el número es en hexadecimal. Con la representación en hexadecimal podemos fácilmente ver su codificación binaria convirtiendo cada símbolo en hexadecimal a binario con 4 bits:

g=0xFFA1 en binario es: 1111 1111 1010 0001

Page 89: INFORMÁTICA Libro de Problemas

90 | Informática. Libro de problemas

El operador >> desplaza los bits de variable g un número (el valor indicado como operando derecho) de posiciones determinado a la derecha rellenando la parte izquierda con el valor del bit que ocupa la posición más a la izquierda izquierda (bit de signo).

g 1111 1111 1010 0001

e=g>>4 1111 1111 1111 1010

Si transformamos el número binario en representación hexadecimal obtenemos el 0xFFFA, que es el valor que se almacena en la variable e.

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita?

int e, g=0xFFA1;

e= g>>4;

Solución: 0xFFA aunque también es válido el valor 0x00000FFA

Comentarios:

La variable g es tipo int (32 bits) indicando que la codificación completa del valor almacenado en la misma (en hexadecimal) es 0x0000FFA1. La codificación binaria equivalente es la siguiente:

g=0x0000FFA1 en binario es: 0000 0000 0000 0000 1111 1111 1010 0001

El operador >> desplaza los bits de variable g un número (el valor indicado como operando derecho) de posiciones determinado a la derecha rellenando la parte izquierda con el valor del bit que ocupa la posición más a la izquierda izquierda (bit de signo).

g 0000 0000 0000 0000 1111 1111 1010 0001

e=g>>4 0000 0000 0000 0000 0000 1111 1111 1010

Si transformamos el número binario en representación hexadecimal obtenemos 0x00000FFA (que también se puede expresar como 0xFFA), que es el valor que se almacena en la variable e.

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita?

short g=0xF5A1;

g<<=8;

Solución: 0xA100

Page 90: INFORMÁTICA Libro de Problemas

Capítulo 4. Tipos de datos primitivos | 91

Comentarios:

Los enteros representados con el prefijo 0x indican que el número es en hexadecimal. Con la representación en hexadecimal podemos fácilmente ver su codificación binaria convirtiendo cada símbolo en hexadecimal a binario con 4 bits:

g=0xF5A1 en binario es: 1111 0101 1010 0001

La operación g<<=8 utiliza la asignación compuesta y es equivalente a g= g<<8.

El operador << desplaza los bits de variable g un número (el valor indicado como operando derecho) de posiciones determinado a la izquierda, rellenando la parte derecha siempre con bits inicializados con el valor cero.

g 1111 0101 1010 0001

g>>=8 1010 0001 0000 0000

Si transformamos el número binario en representación hexadecimal obtenemos el 0xA100, que es el valor que se almacena en la variable g.

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita?

short g=0xF5A1;

g<<=5;

Solución: 0xB420

Comentarios:

Los enteros representados con el prefijo 0x indican que el número es en hexadecimal. Con la representación en hexadecimal podemos fácilmente ver su codificación binaria convirtiendo cada símbolo en hexadecimal a binario con 4 bits:

g=0xF5A1 en binario es: 1111 0101 1010 0001

La operación g<<=5 utiliza la asignación compuesta y es equivalente a g= g<<5.

El operador << desplaza los bits de variable g un número (el valor indicado como operando derecho) de posiciones determinado a la izquierda, rellenando la parte derecha siempre con bits inicializados con el valor cero.

g 1111 0101 1010 0001

g<<=5 1011 0100 0010 0000

Si transformamos el número binario en representación hexadecimal obtenemos el 0xB420, que es el valor que se almacena en la variable g.

Page 91: INFORMÁTICA Libro de Problemas

92 | Informática. Libro de problemas

Observe el código que se muestra a continuación. ¿Qué resultado generan las operaciones resaltadas en negrita?

short e, f= 0xFF, g=0xA1;

g>>=4;

e = f&g;

Solución: 0x000A o 0xA

Comentarios:

La variable g es de tipo short y el valor indicado está expresado en hexadecimal (debido a que emplea el prefijo 0x).

g=0x00A1 en binario es: 0000 0000 1010 0001

La operación g>>=4 utiliza la asignación compuesta y es equivalente a g=g>>4.

g 0000 0000 1010 0001

g>>=4 0000 0000 0000 1010

Si transformamos el número binario en representación hexadecimal obtenemos el 0x000A, que es el valor que se almacena en la variable g.

Una vez conocemos el valor almacenado en la variable g, podemos procesar la operación e = f & g. Esta hace uso del operador "AND" a nivel de bit. Tal y como se muestra a continuación, se aplica de manera consecutiva entre cada pareja de bits que ocupan la misma posición en los valores almacenados en las variables f y g:

f 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 g 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0

e=f&g 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0

Si transformamos el número binario en representación hexadecimal obtenemos 0x000A (que también se puede expresar como 0xA), que es el valor que se almacena en la variable e.

Observe el código que se muestra a continuación. ¿Qué resultado genera la operación resaltada en negrita?

short e, f, g=0xFFA1;

f=∼g;

e= f|g

Solución: 0xFFFF

Page 92: INFORMÁTICA Libro de Problemas

Capítulo 4. Tipos de datos primitivos | 93

Comentarios:

La variable g es de tipo short y el valor indicado está expresado en hexadecimal (debido a que emplea el prefijo 0x).

g=0XFFA1 en binario es: 1111 1111 1010 0001

La operación f=~g hace uso del operador "NOT" (~) a nivel de bit. Al igual que ocurre con cualquier operador de este tipo, se aplica de individual a cada uno de los bit que confoman el valor almacenado en la variable g. Para aplicar este operador bastará con invertir el valor de cada bit, tal y como se indica continuación:

g 1 1 1 1 1 1 1 1 1 0 1 0 0 0 0 1

f=~g 0 0 0 0 0 0 0 0 0 1 0 1 1 1 1 0

Si transformamos el número binario en representación hexadecimal obtenemos 0x005E, que es el valor que se almacena en la variable f.

Una vez conocemos el valor almacenado en la variable f, podemos procesar la operación e=f|g. Esta hace uso del operador "OR" a nivel de bit. Tal y como se muestra a continuación, se aplica de manera consecutiva entre cada pareja de bits que ocupan la misma posición en los valores almacenados en las variables f y g:

f 0 0 0 0 0 0 0 0 0 1 0 1 1 1 1 0 g 1 1 1 1 1 1 1 1 1 0 1 0 0 0 0 1

e=f|g 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

Si transformamos el número binario en representación hexadecimal obtenemos 0xFFFF, que es el valor que se almacena en la variable e.

4.3. Operadores de tamaño y cambio de tipo

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable x tras ejecutar la operación resaltada en negrita?

short x;

x=sizeof(float);

Solución: 4

Comentarios:

El operador sizeof devuelve el tamaño en bytes de un tipo de datos o una variable. El tipo de datos float tiene 32 bits que corresponde a 4 bytes.

Page 93: INFORMÁTICA Libro de Problemas

94 | Informática. Libro de problemas

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable x tras ejecutar la operación resaltada en negrita?

short x;

x=sizeof(char);

Solución: 1

Comentarios:

El operador sizeof devuelve el tamaño en bytes de un tipo de datos o una variable. El tipo char tiene 8 bits que corresponde a 1 byte.

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable x tras ejecutar la operación resaltada en negrita?

short x;

int y=9;

x=sizeof(y);

Solución: 4

Comentarios:

El operador sizeof devuelve el tamaño en bytes de un tipo de datos o una variable. La variable y es de tipo int, siendo por tanto su tamaño de 32 bits (4 bytes).

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable x tras ejecutar la operación resaltada en negrita?

int x, y;

x=sizeof(y);

Solución: 4

Comentarios: Igual que el ejercicio anterior. No cambia nada si el resultado devuelto por sizeof se guarda en una variable de tipo int o de tipo short.

Page 94: INFORMÁTICA Libro de Problemas

Capítulo 4. Tipos de datos primitivos | 95

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable x tras ejecutar la operación resaltada en negrita?

float x;

x=sizeof(double);

Solución: 8.0

Comentarios: El operador sizeof devuelve el tamaño en bytes de un tipo de datos o una variable. El tipo double emplea 64 bits (8 bytes) para almacenar valores en punto flotante. Como el valor devuelto por sizeof se guarda en una variable tipo float, el numero 8 se convierte a punto flotante (8.0).

Observe el código que se muestra a continuación. ¿Cuántas conversiones implícitas se realizan en la instrucción resaltada en negrita?

char a=3;

short b=2, c=1;

float d;

d=(b+c)*a;

Solución: 2

Comentarios:

Teniendo en cuenta los paréntesis definidos en la operación y aplicando la precedencia de operadores definida en C, se siguen los siguientes pasos:

1. Se resuelve la expresión b+c sin ser necesario realizar ninguna conversión debido a que las dos variables son tipo short.

2. El resultado tipo short obtenido en el paso anterior se multiplica por el valor almacenado en la variable a. Como variable a es tipo char, se convierte de forma implícita a tipo short.

3. Finalmente, el resultado de tipo short obtenido en el paso anterior se debe almacenar (operador igualdad) en la variable d de tipo char. Esto obliga al lenguaje C a realizar una nueva conversión implícita.

En resumen, el procesamiento de la operación indicada requiere realizar 2 conversiones implícitas.

Page 95: INFORMÁTICA Libro de Problemas

96 | Informática. Libro de problemas

Observe el código que se muestra a continuación. ¿Cuántas conversiones implícitas se realizan en la instrucción resaltada en negrita?

float x, y=3.5;

x= 5 * y;

Solución: 2

Comentarios:

Teniendo en cuenta la precedencia de operadores definida en C, se siguen los siguientes pasos:

1. Se resuelve la expresión 5*y que requiere la multiplicación de un literal entero y un valor de tipo float (valor almacenado en la variable y). Esto requiere convertir de forma implícita el literal entero 5 a un tipo float. De este modo, el resultado generado por la multiplicación será de tipo float.

2. El resultado generado en el paso anterior se almacena en la variable x (operador igualdad). Debido a que el dato y el tipo de la variable x coinciden (ambos son float) no es necesario realizar conversión alguna.

En resumen, el procesamiento de la operación indicada requiere realizar una conversión implícita.

Observe el código que se muestra a continuación. ¿Cuántas conversiones implícitas se realizan en la instrucción resaltada en negrita?

int x;

float y=3.5;

x= 5 * y;

Solución: 17

Comentarios:

Teniendo en cuenta la precedencia de operadores definida en C, se siguen los siguientes pasos:

1. Se resuelve la expresión 5*y que requiere la multiplicación de un literal entero y un valor de tipo float (valor almacenado en la variable y). Esto requiere convertir de forma implícita el literal entero 5 a un tipo float. De este modo, el resultado generado (17.5) por la multiplicación será de tipo float.

2. El resultado generado en el paso anterior (de tipo float) debe almacenarse en la variable x (de tipo int). Debido a la incompatibilidad existente, el valor que generó la multiplicación (17.5) debe convertirse de forma implícita a un int. En

Page 96: INFORMÁTICA Libro de Problemas

Capítulo 4. Tipos de datos primitivos | 97

consecuencia, se perderá la parte fraccionaria de modo que en la variable x se almacenará el valor 17.

En resumen, el procesamiento de la operación indicada requiere realizar 2 conversiones implícitas.

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable x tras ejecutar la operación resaltada en negrita?

int x;

float y=3.5;

x= 5 * (int) y;

Solución: 15

Comentarios:

Teniendo en cuenta los paréntesis definidos en la operación y aplicando la precedencia de operadores definida en C, se siguen los siguientes pasos:

1. El valor almacenado en la variable y (de tipo float) se convierte de forma explícita a un valor de tipo int. Como consecuencia se perderá la parte fraccionaria, generando el valor entero 3.

2. Se resuelve el operador multiplicación tomando como operandos el literal entero 5 y el resultado generado en el paso anterior. Esta operación no requiere realizar ninguna conversión debido a la compatibilidad de tipos que existe. Como resultado, se genera el valor entero 15.

3. El operador de igualdad solicita que el resultado generado en el paso anterior se debe almacenar en la variable x. Ejecutar esta operación no requiere realizar tampoco conversión alguna, debido a que tanto el dato a almacenar como la variable destino son del mismo tipo.

Como consecuencia, en la variable x se almacenará el valor 15.

Observe el código que se muestra a continuación. ¿Qué valor adopta la variable x tras ejecutar la operación resaltada en negrita?

float x, y=3.5;

x= 5.0 * (int) y;

Solución: 15.0

Page 97: INFORMÁTICA Libro de Problemas

98 | Informática. Libro de problemas

Comentarios:

Teniendo en cuenta los paréntesis definidos en la operación y aplicando la precedencia de operadores definida en C, se siguen los siguientes pasos:

1. El valor almacenado en la variable y (de tipo float) se convierte de forma explícita a un valor de tipo entero. Como consecuencia se perderá la parte fraccionaria, generando el valor 3 de tipo int.

2. Se resuelve el operador multiplicación tomando como operandos el literal punto flotante 5.0 y el resultado de tipo int generado en el paso anterior (3). Esta operación requiere realizar una conversión implícita, concretamente el 3 se convertirá en un 3.0. Una vez realizar esta conversión, se ejecuta la multiplicación de ambos valores, resultando el valor 15.0 de tipo float.

3. El operador de igualdad solicita que el resultado generado en el paso anterior se debe almacenar en la variable x. Ejecutar esta operación no requiere realizar tampoco conversión alguna, debido a que tanto el dato a almacenar como la variable destino son del mismo tipo.

Como consecuencia, en la variable x se almacenará el valor 15.0 de tipo float.

Page 98: INFORMÁTICA Libro de Problemas

5

OPERACIONES DE ENTRADA/SALIDA

Page 99: INFORMÁTICA Libro de Problemas
Page 100: INFORMÁTICA Libro de Problemas

Capítulo 5. Operaciones de entrada/salida | 101

5.1. Promoción Escriba un programa que solicite al usuario introducir su promoción y la nota del primero de la promoción. A continuación, el programa debe imprimir esa información por pantalla. Un ejemplo de ejecución sería el siguiente: Ejemplo de ejecución *-*-*-*-*-* PROGRAMA *-*-*-*-*-* Buenos dias Introduzca su promocion.... 2 La nota del primero fue....9.5 Somos la promocion 2 y la nota del primero es 9.50 Posible solución: Código 5.1

1. #include <stdio.h> 2. int main(void) 3. { 4. int P; 5. double notaPrimero; 6. printf("*-*-*-*-*-*\n"); 7. printf("PROGRAMA\n"); 8. printf("*-*-*-*-*-*\n"); 9. printf("Buenos dias"); 10. printf("\n"); 11. printf("Introduzca su promocion....\n"); 12. scanf("%d", &P); 13. printf("La nota del primero fue...."); 14. scanf("%lf", &Primero); 15. printf("\nSomos la promocion %d", P); 16. printf("\ny la nota del primero es %.2lf\n", notaPrimero); 17. return 0; 18. }

Comentarios:

• La primera línea del Código 5.1 (#include <stdio.h>) nos permite tener acceso a las funciones de entrada y salida que se encuentren dentro de la biblioteca sdio.h. En concreto, en esa biblioteca se incluyen printf() y scanf(). Cuando creamos un nuevo proyecto en CodeLite esta librería se incluye por defecto.

Page 101: INFORMÁTICA Libro de Problemas

102 | Informática. Libro de problemas

• Cuando se utiliza la función printf(), todo el texto que se encuentra entre comillas se imprime por pantalla, salvo caracteres de control que están indicados con una contrabarra (\) y tipos de variables que están indicados con un carácter de porcentaje (%). Es importante destacar que los nombres de las variables se encuentran fuera de las comillas, separados por una coma.

• Notar que la función printf()solamente salta una línea cuando encuentra el carácter de control '\n' (no cuando pasamos a una nueva línea de código y/o una nueva función de scanf()).

• Se debe tener cuidado con la correspondencia entre los especificadores de formato y los tipos de datos de las variables empleadas en printf() y scanf(). El especificador de formato (%d, %lf, etc.) tiene que corresponder con el tipo de la variable que vamos a imprimir (en caso de usar printf()) o en la que vamos a guardar el dato introducido (en caso de usar scanf()).

• No olvidar que en la función scanf() hay que introducir un ampersand (&) antes del nombre de la variable donde se va a guardar el dato introducido.

5.2. Media

Escriba un programa que solicite al usuario introducir dos valores enteros y calcule la media, guardándola en una variable de punto flotante de tamaño 8 bytes. A continuación, el programa debe mostrar por pantalla la media calculada. Ejemplo de ejecución: Ejemplo de ejecución Introduzca un numero...5 Introduzca otro ...2 La media es..... 3.500000

Posible solución: Código 5.2

1. #include <stdio.h> 2. int main(void) 3. { 4. int x, y; 5. double z; 6. printf("Introduzca un numero..."); 7. scanf("%d", &x); 8. printf("\nIntroduzca otro ..."); 9. scanf("%d", &y);

Page 102: INFORMÁTICA Libro de Problemas

Capítulo 5. Operaciones de entrada/salida | 103

10. z = (double)(x + y) / 2; 11. printf("\nLa media es..... %lf\n", z); 12. return 0; 13. }

Comentarios:

• En este ejercicio, para calcular la media es necesario utilizar el operador de división. Debemos tener especial cuidado con los tipos de datos de las variables cuando se utiliza dicho operador, ya que, si se divide un entero entre otro entero, se pierde la parte fraccionaria. Para evitar ese problema, este programa utiliza el operador de casting para convertir la suma de x + y a un punto flotante con 8 bytes (double) antes de dividir con 2:

z = (double) (x+y)/2;

• Otra manera de asegurar que no se pierde la parte fraccionaria seria convertir el literal 2 a un punto flotante añadiendo un punto, según se indica en la siguiente instrucción:

z = (x+y)/2.;

5.3. Incrementos Escriba un programa que declare 3 variables (a, b, c) de tipo entero corto. A la variable a debe asignarse el valor 4 y a la variable b el valor 8. A continuación, el programa debe asignar a la variable c el valor de la variable a, y luego incrementar el valor de a en una unidad. Para finalizar, el programa debe imprimir el valor de las tres variables por pantalla.

Ejemplo de ejecución: Ejemplo de ejecución El valor de a es 5, el de b es 8 y c es 4

Posible solución:

Código 5.3

1. #include <stdio.h> 2. int main(void) 3. { 4. short a, b = 8; 5. short c; 6. a = 4; c = a++; 7. printf("El valor de a es %hd, el de b es %hd y c es %hd\n", a, b, c); 8. return 0; 9. }

Page 103: INFORMÁTICA Libro de Problemas

104 | Informática. Libro de problemas

Comentarios:

• Como puede observar, los valores de las variables se pueden asignar en el momento de declararlas (como se hace para la variable b en la línea 4) o hacerlo más tarde en el programa mediante una instrucción de asignación (como se hace para la variable a en la línea 6).

• Recuerde que las instrucciones en C siempre terminan con el símbolo ';'.

• En una misma línea puede haber más de una instrucción, como ocurre en la línea 6: a = 4; c = a++;

• En la resolución se ha hecho uso de un operador de post-incremento. En la línea 6, la instrucción c = a++; primero asigna el valor de la variable a a la variable c, y luego se incrementa el valor de a.

5.4. Leer caracteres

Escriba un programa que solicite al usuario dos caracteres que debe guardar en dos variables tipo char. El primer carácter se debe leer mediante la función scanf(), y el segundo mediante la función getchar(). Después de pedir cada carácter, el programa debe mostrar el carácter leído por pantalla. Ejemplo de ejecución: Ejemplo de ejecución Introduzca un caracter ...a Ha introducido ... a Introduzca un caracter ...b Ha introducido ... b Posible solución: Código 5.4

1. #include <stdio.h> 2. int main(void) 3. { 4. char a, b; 5. // Comentario 6. /* Esto es un 7. comentario de varias

Page 104: INFORMÁTICA Libro de Problemas

Capítulo 5. Operaciones de entrada/salida | 105

8. lineas */ 9. printf("Introduzca un caracter ..."); 10. // Primera forma : con scanf 11. fflush(stdin); 12. scanf(" %c", &a); 13. printf("\nHa introducido ... %c", a); 14. 15. printf("\nIntroduzca un caracter ..."); 16. // Segunda forma : con getchar 17. fflush(stdin); 18. b = getchar(); 19. printf("\nHa itroducido ... %c\n", b); 20. return 0; 21. }

Comentarios:

• En la resolución de este ejercicio se muestra la forma de introducir comentarios en el código. Dichos comentarios, se utilizan normalmente para facilitar el entendimiento del programa indicando lo que hace un cierto bloque de código.

• Cuando queremos comentar una línea se utilizan dos contrabarras (\\) para incluir un comentario en el programa. Es decir, el resto de la línea después del "\\" no es parte del código y el compilador ignora ese texto durante la compilación.

• Para escribir un comentario de múltiples líneas, se utilizan los caracteres "/*" y "*/" . Con "/*" se abre el comentario y con "*/" se cierra. Todo lo que está escrito entre el "/*" y el "*/" es ignorado por el compilador.

• Antes de leer un dato utilizando una función de entrada (scanf() o getchar()), se recomienda utilizar la función fflush(stdin) que permite vaciar (limpiar) el buffer del teclado.

• La función getchar() es una función alternativa para leer caracteres introducidos por el teclado. La instrucción b=getchar() lee un carácter introducido por teclado y lo almacena en la variable b. Esta función no tiene argumentos de entrada y solamente se puede utilizar para leer caracteres.

Page 105: INFORMÁTICA Libro de Problemas
Page 106: INFORMÁTICA Libro de Problemas

6

ESTRUCTURAS DE CONTROL: SELECCIÓN

Page 107: INFORMÁTICA Libro de Problemas
Page 108: INFORMÁTICA Libro de Problemas

Capítulo 6. Estructuras de control: Selección | 109

6.1. Par-impar

Escriba un programa que solicite al usuario un número entero e indique por pantalla si el número introducido es par o impar. A continuación, se muestran ejemplos de ejecución:

Ejemplo 1 de ejecución Introduzca un entero...15 15 es IMPAR

Ejemplo 2 de ejecución Introduzca un entero... 10 10 es PAR

Posible solución: Código 6.1

1. #include <stdio.h> 2. int main(void) 3. { 4. short n; 5. printf("Introduzca un entero..."); 6. scanf("%hd", &n); 7. if((n % 2) != 0) 8. printf("%hd es IMPAR\n", n); 9. else 10. printf("%hd es PAR\n", n); 11. return 0; 12. }

Comentarios:

• Como puede observar, para averiguar si un número es par o impar se ha empleado el operador resto (%). Dicho operador sólo se puede usar con variables de tipo entero.

• Se ha empleado la estructura if-else para evaluar el resultado del operador resto (%) entre el valor que contenga la variable n y el número 2. De esta manera, si el resultado es distinto de cero, se imprime por pantalla que el número es impar. En otro caso, se imprimirá que el número es par.

• Note que la expresión (n % 2) != 0 se podría también escribir como !(n % 2).

Page 109: INFORMÁTICA Libro de Problemas

110 | Informática. Libro de problemas

6.2. Divisor Escriba un programa que solicite al usuario dos números enteros y los almacene en dos variables llamadas a y b. El programa debe indicar si el número contenido en b es un divisor del número contenido en a. Además, el programa deberá notificar al usuario si ha introducido como segundo valor, el valor de 0. A continuación se muestra un ejemplo de ejecución: Ejemplo 1 de ejecución Introduce un numero entero...15 Introduce otro numero entero...3 3 es DIVISOR de 15

Ejemplo 2 de ejecución Introduce un numero entero...20 Introduce otro numero entero...5 5 es DIVISOR de 20

Ejemplo 3 de ejecución Introduce un numero entero...15 Introduce otro numero entero...7 7 NO es DIVISOR de 15

Ejemplo 4 de ejecución Introduce un numero entero...20 Introduce otro numero entero...0 El segundo valor no puede ser CERO

Posible solución: Código 6.2

1. #include <stdio.h> 2. int main(void) 3. { 4. short a, b; // a: primer entero introducido 5. // b: segundo entero introducido 6. short resto;

Page 110: INFORMÁTICA Libro de Problemas

Capítulo 6. Estructuras de control: Selección | 111

7. printf("Introduce un numero entero..."); 8. scanf("%hd", &a); 9. printf("Introduce otro numero entero..."); 10. scanf("%hd", &b); 11. if(b != 0) { 12. // Se comprueba si b es divisor de a 13. resto = a % b; 14. if(resto == 0) 15. printf("%hd es DIVISOR de %hd \n", b, a); 16. else 17. printf("%hd NO es DIVISOR de %hd \n", b, a); 18. } else { 19. printf("El segundo valor no puede ser CERO \n"); 20. } 21. return 0; 22. }

Comentarios:

• En este ejercicio, después de guardar los datos introducidos por el usuario en las variables a y b, se emplean dos estructuras de selección. La primera, evalúa si el número guardado en b es distinto de 0. Si esta condición es verdadera, se ejecutará la siguiente estructura de selección. Si no es verdadera, directamente se imprimirá por pantalla que el usuario ha introducido el valor de 0 y, por lo tanto, no calcula si es divisor.

• La segunda estructura evalúa si lo que contiene la variable auxiliar resto es cero. Si es verdadera, imprimirá que el número es divisor y en caso contrario, que no lo es.

• Note que en vez de utilizar la variable auxiliar resto, se podría calcular el resto directamente en la condición de la estructura if como:

if (a % b == 0)

6.3. Calificación examen Escriba un programa que muestre por pantalla si la nota numérica de tipo entero que introduce el usuario se corresponde con suspenso o aprobado. Además, el programa debe contemplar si la nota numérica introducida es inválida (menor que 0 o mayor que 10), en cuyo caso mostrará un mensaje de error. A continuación, se muestran ejemplos de ejecución: Ejemplo 1 de ejecución Introduce tu nota ....8 APROBADO

Page 111: INFORMÁTICA Libro de Problemas

112 | Informática. Libro de problemas

Ejemplo 2 de ejecución Introduce tu nota ....3 SUSPENSO

Ejemplo 3 de ejecución Introduce tu nota ....14 NOTA INVALIDA

Posible solución: Código 6.3

1. #include <stdio.h> 2. int main(void) 3. { 4. short n; 5. printf("Introduce tu nota ...."); 6. scanf("%hd", &n); 7. if(n >= 0 && n <= 10) { 8. if(n >= 5) 9. printf("APROBADO"); 10. else 11. printf("SUSPENSO"); 12. 13. } else { 14. printf("NOTA INVALIDA\n"); 15. } 16. return 0; 17. }

Comentarios:

• En este programa se utilizan dos estructuras de selección. La primera de ellas comprueba que el usuario haya introducido correctamente la nota numérica; es decir, que la nota se encuentre dentro del rango 0-10 incluyendo ambos valores. En caso contrario, se notifica por pantalla que la nota es inválida.

• La segunda estructura evalúa si la nota es igual o superior al valor de 5, indicando por pantalla si supera la asignatura (aprobado) o si está suspenso.

• Si se quisiera modificar el programa con el objetivo de tener calificaciones con números reales, se podría declarar la variable n de tipo float o double. En ese caso, en la llamada a la función scanf de la línea 6, habría que cambiar el tipo a %f (float) o %lf (double), respectivamente.

Page 112: INFORMÁTICA Libro de Problemas

Capítulo 6. Estructuras de control: Selección | 113

6.4. Calificación literal

Escriba un programa que muestre por pantalla la correspondencia de la nota numérica que introduce un usuario con la nota literal (Suspenso, Aprobado, Notable, Sobresaliente o Matricula). Además, el programa debe mostrar un mensaje de error si la nota numérica que introduce el usuario es inválida (menor que 0 o mayor que 10). A continuación, se muestran ejemplos de ejecución: Ejemplo 1 de ejecución Introduce tu nota: 8.9 NOTABLE

Ejemplo 2 de ejecución Introduce tu nota: 6 APROBADO

Ejemplo 3 de ejecución Introduce tu nota: 4.1 SUSPENSO

Ejemplo 4 de ejecución Introduce tu nota: -1 ERROR: NOTA INCORRECTA

Ejemplo 5 de ejecución Introduce tu nota: 10 MATRICULA DE HONOR

Page 113: INFORMÁTICA Libro de Problemas

114 | Informática. Libro de problemas

Posibles soluciones: Código 6.4.1

1. #include <stdio.h> 2. int main(void) 3. { 4. double nota; 5. printf("Introduce tu nota:\t"); 6. scanf("%lf", &a); 7. if(nota < 0 || nota > 10) 8. printf("ERROR: NOTA INCORRECTA"); 9. else if(nota < 5) 10. printf("SUSPENSO"); 11. else if(nota < 7) // else if (nota >= 5 && nota < 7) 12. printf("APROBADO"); 13. else if(nota < 9) // else if (nota >= 7 && nota < 9) 14. printf("NOTABLE"); 15. else if(nota < 10) 16. printf("SOBRESALIENTE"); 17. else 18. printf("MATRICULA DE HONOR"); 19. printf("\n"); 20. return 0; 21. } 22.

Código 6.4.2

1. #include <stdio.h> 2. int main(void) 3. { 4. double nota; 5. printf("Introduce tu nota:\t"); 6. scanf("%lf", &a); 7. if(nota < 0 || nota > 10) { 8. printf("ERROR: NOTA INVALIDA"); 9. } else { 10. if(nota < 5.0) 11. printf("SUSPENSO"); 12. else if(nota < 7.0) 13. printf("APROBADO"); 14. else if(nota < 9.0) 15. printf("NOTABLE"); 16. else if(nota < 10) 17. printf("SOBRESALIENTE"); 18. else 19. printf("MATRICULA DE HONOR"); 20. } 21. printf("\n"); 22. return 0; 23. }

Page 114: INFORMÁTICA Libro de Problemas

Capítulo 6. Estructuras de control: Selección | 115

Código 6.4.3

1. #include <stdio.h> 2. int main(void) 3. { 4. double nota; 5. printf("Introduce tu nota:\t"); 6. scanf("%lf", ¬a); 7. if(nota < 0 || nota > 10) { 8. printf("ERROR: NOTA INVALIDA"); 9. } else { 10. if(nota < 5.0) 11. printf("SUSPENSO"); 12. else { 13. if(nota < 7.0) 14. printf("APROBADO"); 15. else { 16. if(nota < 9.0) 17. printf("NOTABLE"); 18. else { 19. if(nota < 10) 20. printf("SOBRESALIENTE"); 21. else 22. printf("MATRICULA DE HONOR"); 23. } 24. } 25. } 26. } 27. printf("\n"); 28. return 0; 29. }

Comentarios:

• Para la resolución de este ejercicio se han mostrado tres posibles soluciones. Como se observa, las tres soluciones cumplen con los requisitos del enunciado y su ejecución es la misma.

• Los programas se diferencian en el uso de las estructuras de selección anidadas if-else y las concatenadas if-else if-else.

• El programa mostrado en Código 6.4.1 se hace uso de la concatenación con else if de forma que se evalúan diferentes condiciones de manera consecutiva. Teniendo en cuenta el planteamiento de las distintas condiciones, es importante apreciar que la clásula else representa aquella situación en la que la nota obtenida por el alumno es Matrícula de Honor.

• El programa mostrado en Código 6.4.2 opta por emplear una estructura if-else que, a su vez, anida dentro de la cláusula else una estructura de concatenación else if.

• Por último, el programa mostrado en Código 6.4.3 se muestra como ejemplo de lo que sería un mal estilo de programación. Este tercer programa se hace uso de anidamiento de

Page 115: INFORMÁTICA Libro de Problemas

116 | Informática. Libro de problemas

múltiples estructuras básicas de if-else. Esta solución conocida como "escalera de if-else" no es aconsejable y se debe evitar.

• En cualquier solución hay que tener especial cuidado con el correcto uso de llaves cuando se añaden las cláusulas if, else if y else.

• Note que la condición que comprueba si una nota es inválida también se podría escribir de esta forma:

if(!(nota >= 0 && nota <= 10)) printf("ERROR: NOTA INCORRECTA");

6.5. Ecuación de segundo grado Escriba un programa que resuelva una ecuación de segundo grado (ax2+bx+c=0). El programa debe solicitar al usuario los coeficientes de la ecuación (a,b,c) y mostrar el resultado por pantalla. Además, se debe contemplar las siguientes situaciones:

• Si la ecuación no tiene soluciones reales, el programa debe mostrar un mensaje de error.

• Si el coeficiente a es 0, el programa debe indicar que es una ecuación del primer grado y mostrará la solución.

• Si los coeficientes a y b son 0, el programa debe indicar que la ecuación no es válida.

A continuación, se muestran diversos ejemplos de ejecución: Ejemplo 1 de ejecución ****************************************** ** Ecuacion de Segundo Grado ** ****************************************** Introduzca los coeficientes... a --> 2 b --> 8 c --> 3 Las soluciones reales son: x1 --> -0.418861 x2 --> -3.581139

Page 116: INFORMÁTICA Libro de Problemas

Capítulo 6. Estructuras de control: Selección | 117

Ejemplo 2 de ejecución ****************************************** ** Ecuacion de Segundo Grado ** ****************************************** Introduzca los coeficientes... a --> 1 b --> 1 c --> -2 Las soluciones reales son: x1 --> 1.000000 x2 --> -2.000000

Ejemplo 3 de ejecución ****************************************** ** Ecuacion de Segundo Grado ** ****************************************** Introduzca los coeficientes... a --> 5 b --> 4 c --> 2 ERROR: Ecuacion sin soluciones reales.

Ejemplo 4 de ejecución ****************************************** ** Ecuacion de Segundo Grado ** ****************************************** Introduzca los coeficientes... a --> 0 b --> 10 c --> 2 Ec. de primer grado. Una unica solucion. x1 --> -0.200000

Ejemplo 5 de ejecución ****************************************** ** Ecuacion de Segundo Grado ** ****************************************** Introduzca los coeficientes... a --> 0 b --> 0 c --> 4 No hay ecuacion.

Page 117: INFORMÁTICA Libro de Problemas

118 | Informática. Libro de problemas

Posible solución: Código 6.5

1. #include <math.h> 2. #include <stdio.h> 3. int main(void) 4. { 5. double a, b, c; 6. double d; // discrimante 7. 8. // Introduccion de parametros... 9. printf("******************************************\n"); 10. printf("**\t Ecuacion de Segundo Grado \t**\n"); 11. printf("******************************************\n"); 12. printf("Introduzca los coeficientes...\n\n"); 13. printf("a --> "); 14. scanf(" %lf", &a); 15. printf("b --> "); 16. scanf(" %lf", &b); 17. printf("c --> "); 18. scanf(" %lf", &c); 19. 20. if(a == 0) { 21. // Ecuacion de primer grado... 22. if(b == 0) { 23. // No hay ecuacion ... 24. printf("No hay ecuacion.\n"); 25. } else { // Si¬ hay ecuacion de primer grado 26. printf("Ec. de primer grado.\n"); 27. printf("Una unica solucion.\n"); 28. printf("x1 --> %lf\n", -c / b); 29. } 30. } else if((d = b * b - 4 * a * c) < 0) { 31. // Ecuacion de segundo grado. Soluciones imaginarias. 32. printf("ERROR: Ecuacion sin soluciones reales.\n"); 33. } else { 34. // Ecuacion de segundo grado. Soluciones reales. 35. printf("Las soluciones reales son:\n"); 36. d = sqrt(d); 37. printf("\tx1 --> %lf\n", (-b + d) / (2 * a)); 38. printf("\tx2 --> %lf\n", (-b - d) / (2 * a)); 39. } 40. return 0; // el programa ha acabado correctamente 41. } 42.

Comentarios:

• El programa mostrado en Código 6.5 resuelve una ecuación de segundo grado donde el usuario introduce los términos. Para resolver dicha ecuación, se necesita usar la operación de raíz cuadrada. Para ello, se ha empleado la función sqrt() que se encuentra en la

Page 118: INFORMÁTICA Libro de Problemas

Capítulo 6. Estructuras de control: Selección | 119

biblioteca math.h. Note como al inicio del programa, mediante la sentencia #include <math.h> se incluye dicha biblioteca.

• Las variables que se han declarado son del tipo double ya que los resultados de las operaciones pueden ser números reales.

• Como se puede observar, en la solución se emplea una estructura principal de concatenación else if, la cual va evaluando si la ecuación es de primer grado, segundo grado con soluciones imaginarias o de segundo grado con soluciones reales. Para el caso de que no exista ecuación porque el usuario haya introducido coeficientes con el valor de cero, vea cómo en la primera condición de la estructura principal else if se evalua dicho caso mediante una estructura if else.

6.6. Número entero en texto

Escriba un programa que solicite al usuario escoger un valor entero entre 0 y 2. El programa mostrará por pantalla la cadena de texto "El numero es" y a continuación el número introducido por el usuario con letras. Además, si el usuario introduce un valor distinto de los permitidos, el programa debe de mostrar un mensaje indicando que el número es incorrecto. Para resolver este programa se debe de utilizar la estructura switch. A continuación, se muestran diversos ejemplos de ejecución: Ejemplo 1 de ejecución Introduce un entero entre 0 y 2: 2 El numero es DOS

Ejemplo 2 de ejecución Introduce un entero entre 0 y 2: 0 El numero es CERO

Ejemplo 3 de ejecución Introduce un entero entre 0 y 2: 5 El numero es INCORRECTO

Ejemplo 4 de ejecución Introduce un entero entre 0 y 2: 1.5 El numero es UNO

Page 119: INFORMÁTICA Libro de Problemas

120 | Informática. Libro de problemas

Posible solución: Código 6.6

1. #include <stdio.h> 2. int main(void) 3. { 4. short n; 5. printf("Introduce un entero entre 0 y 2: "); 6. scanf(" %hd", &n); 7. printf("\nEl numero es "); 8. switch(n) { 9. case 0: 10. printf("CERO"); 11. break; 12. case 1: 13. printf("UNO"); 14. break; 15. case 2: 16. printf("DOS"); 17. break; 18. default: 19. printf("INCORRECTO"); 20. } 21. printf("\n"); 22. return 0; 23. } 24.

Comentarios:

• Este programa muestra de forma sencilla el uso de la estructura switch. Como se puede observar, cada instrucción case evalua una opción y, si se cumple, entonces ejecuta las sentencias que tiene anidadas.

• Es muy importante no omitir las instrucciones break. Si se omiten las instrucciones break al final de cada caso, el programa ejecutaría el código establecido para todos los casos definidos después del caso elegido. Por ejemplo, si el usuario introduce el valor numérico 1, entonces el programa mostraría la cadena "El numero es UNODOSINCORRECTO".

• Note que la instrucción scanf() en la línea 6 almacena un valor de tipo entero corto y lo guarda en la variable n. Por lo tanto, si es usuario introduce un valor real, por ejemplo, 1.5, solamente guarda el número 1 en la variable n, mientras .5 va a permanecer en el buffer de entrada.

Page 120: INFORMÁTICA Libro de Problemas

Capítulo 6. Estructuras de control: Selección | 121

6.7. Bilingue Escriba un programa que permita al usuario elegir el idioma inglés o castellano. Para ello, el usuario introducirá la letra 'E' o 'e' para la opción de inglés y 'C' o 'c' para la opción de castellano. El programa mostrará un mensaje de error si el usuario introduce una letra diferente. Después, en el idioma elegido, el programa solicitará un número de tipo entero y mostrará si dicho número es par o impar. A continuación, se muestran diversos ejemplos de ejecución: Ejemplo 1 de ejecución Choose your language/Escoge tu idioma English (E) / Castellano (C)...E Enter an integer...5 5 IS ODD

Ejemplo 2 de ejecución Choose your language/Escoge tu idioma English (E) / Castellano (C)...e Enter an integer...7 7 IS ODD

Ejemplo 3 de ejecución Choose your language/Escoge tu idioma English (E) / Castellano (C)...C Introduce un entero...4 4 ES PAR

Ejemplo 4 de ejecución Choose your language/Escoge tu idioma English (E) / Castellano (C)...X INVALID OPTION / OPCION NO VALIDA

Ejemplo 5 de ejecución Choose your language/Escoge tu idioma English (E) / Castellano (C)...8 INVALID OPTION / OPCION NO VALIDA

Page 121: INFORMÁTICA Libro de Problemas

122 | Informática. Libro de problemas

Posible solución: Código 6.7

1. #include <stdio.h> 2. int main(void) 3. { 4. short a; // número a comprobar si es par o impar 5. char opcion; 6. printf("Choose your language/Escoge tu idioma\n"); 7. printf("English (E) / Castellano (C)..."); 8. opcion = getchar(); 9. switch(opcion) { 10. case 'e': 11. case 'E': 12. printf("Enter an integer..."); 13. scanf("%hd", &a); 14. if(a % 2 == 0) 15. printf("\n %hd IS EVEN", a); 16. else 17. printf("\n %hd IS ODD", a); 18. break; 19. case 'c': 20. case 'C': 21. printf("Introduce un entero..."); 22. scanf("%hd", &a); 23. if(a % 2 == 0) 24. printf("\n %hd ES PAR", a); 25. else 26. printf("\n %hd ES IMPAR", a); 27. break; 28. default: 29. printf("INVALID OPTION / OPCION NO VALIDA"); 30. } 31. printf("\n"); 32. return 0; 33. }

Comentarios:

• Como se puede observar, para poder implementar la opción del idioma se ha usado la estructura switch. Cuando el usuario introduce una minúscula e ó c, el programa ejecuta las instrucciones dadas para los casos de E o C, respectivamente, ya que los casos que se corresponden con las letras minúsculas no llevan una instrucción break y, por lo tanto, el programa pasa al siguiente caso.

• Note que se ha utilizado una variable de tipo char para almacenar la opción que introduzca el usuario y que esta misma variable es la usada para evaluar en la estructura switch.

Page 122: INFORMÁTICA Libro de Problemas

Capítulo 6. Estructuras de control: Selección | 123

• Dentro de cada case, se ha utilizado una estructura if-else para comprobar si el número entero introducido es par o impar y, en consecuencia, mostrar el mensaje apropiado.

• Si el usuario introduce una opción que no encuentra en los casos (algo distinto de e, E, c o C), entonces se ejecutan las instrucciones indicadas como default (línea 29).

• La instrucción de la línea 8: opcion = getchar();

se podría escribir como

scanf("%c", &opcion);

Page 123: INFORMÁTICA Libro de Problemas
Page 124: INFORMÁTICA Libro de Problemas

7

ESTRUCTURAS DE CONTROL: REPETICIÓN

Page 125: INFORMÁTICA Libro de Problemas
Page 126: INFORMÁTICA Libro de Problemas

Capítulo 7: Estructuras de control: Repetición | 127

7.1. Números pares Escriba un programa que muestre por pantalla los números pares entre 1 y 20 en orden descendente haciendo uso de la estructura while. A continuación, se muestra un ejemplo de la salida por pantalla: Ejemplo de ejecución 20 18 16 14 12 10 8 6 4 2

Posible solución: Código 7.1

1. #include <stdio.h> 2. int main(void) 3. { 4. short x = 20; 5. while(x) { 6. if(x % 2 == 0) 7. printf("%hd\n", x); 8. x = x - 1; 9. } 10. return 0; 11. } 12.

Comentarios:

• En este ejercicio se solicita mostrar por pantalla los números pares que hay entre dos números utilizando la estructura while. Al especificar el enunciado que se tratan de números enteros (1-20), se utiliza la variable x de tipo short.

• Una primera solución más simple podría consistir en decrementar 2 unidades el valor que contenga la variable x en cada iteración del bucle while. Sin embargo, esta solución sólo sería válida si el valor inicial es par.

• La solución que se ha propuesto funcionará para cualquier valor numérico inicial (par o impar) que pueda tomar la variable x.

Page 127: INFORMÁTICA Libro de Problemas

128 | Informática. Libro de problemas

• Note que la condición while(x) es equivalente a while(x!=0). Recuerde que cualquier valor distinto a 0 se considera verdadero en C.

7.2. Factorial

Escriba un programa que solicite al usuario un número entero positivo y muestre por pantalla su factorial haciendo uso de la estructura while. El programa asume que el usuario siempre introducirá un valor positivo, por lo tanto, no siendo necesario que el programa compruebe que esta condición se cumple. A continuación, se muestran un par de ejemplos de salida por pantalla: Ejemplo 1 de ejecución Introduce un entero positivo...6 El factorial es...720

Ejemplo 2 de ejecución Introduce un entero positivo...5 El factorial es...120

Posible solución: Código 7.2

1. #include <stdio.h> 2. int main(void) 3. { 4. unsigned short n; 5. unsigned long F; 6. printf("Introduce un entero positivo..."); 7. scanf("%hu", &n); 8. F = 1; 9. while(n != 0) { 10. F = F * n; 11. n = n - 1; 12. } 13. /* OTRA FORMA ALTERNATIVA 14. while(n) 15. F *= n--; 16. */ 17. printf("El factorial es...%lu\n", F); 18. return 0; 19. }

Page 128: INFORMÁTICA Libro de Problemas

Capítulo 7: Estructuras de control: Repetición | 129

Comentarios:

• En este ejercicio se propone calcular el factorial del número entero positivo que introduce el usuario. Note que dadas las especificaciones del enunciado en cuanto las características del número que tiene que introducir el usuario, es recomendable que la variable empleada para almacenar dicho valor sea declarada de tipo unsigned short.

• El resultado del factorial calculado por el programa se almacenará en la variable F. Esta variable se ha declarado de tipo long. Tenga en cuenta que el factorial de valores mayores o iguales a 13 no se puede representar con 32 bits. En este sentido, es importante destacar que existen compiladores donde el tamaño de un long es de 32 bits. En este caso, sería necesario declarar la variable F de tipo long long, con el objetivo se asegurar como mínimo un tamaño de 64 bits.

• Para implementar el factorial se tiene que hacer uso de la estructura de repetición while. Note que, para cada iteración, teniendo la variable F inicializada al valor de 1, simplemente lo que se hace es ir multiplicando lo que contenga la variable F por el valor que contenga la variable n. Además, en cada iteración, el valor de n va decrementándose en 1. Este bucle se ejecutará mientras que el valor que cotenga n sea distinto del valor 0.

• Observe que la condición while(n!=0) es equivalente a while(n). Recuerde que cualquier valor distinto a 0 se considera verdadero en C.

• Otra forma de implementar las instrucciones de las líneas 10 y 11 sería la siguiente: F *= n--;

Esta instrucción combina el uso de dos operadores de manera simultánea: multiplicación compuesta y postdecremento. Primero se realizaría la operación de multiplicar el contenido de la variable F por el contenido de la variable n y, después, se ejecutaría el decremento del valor que contiene n.

7.3. Máximo y media versión while Escriba un programa que solicite al usuario 5 valores numéricos enteros empleando la estructura while. El programa deberá mostrar por pantalla la suma, el valor máximo y la media de los valores introducidos. A continuación, se muestran varios ejemplos de salida por pantalla:

Ejemplo 1 de ejecución Introduce un entero...5 Introduce un entero...3 Introduce un entero...8 Introduce un entero...2 Introduce un entero...4 Suma es ... 22 Maximo es ... 8 Media es ... 4.40

Page 129: INFORMÁTICA Libro de Problemas

130 | Informática. Libro de problemas

Ejemplo 2 de ejecución Introduce un entero...2 Introduce un entero...0 Introduce un entero...3 Introduce un entero...2 Introduce un entero...1 Suma es ... 8 Maximo es ... 3 Media es ... 1.60

Ejemplo 3 de ejecución Introduce un entero...1 Introduce un entero...2 Introduce un entero...-1 Introduce un entero...-2 Introduce un entero...0 Suma es ... 0 Maximo es ... 2 Media es ... 0.00

Ejemplo 4 de ejecución Introduce un entero...-1 Introduce un entero...-2 Introduce un entero...-4 Introduce un entero...-5 Introduce un entero...-10 Suma es ... -22 Maximo es ... -1 Media es ... -4.40

Posible solución: Código 7.3

1. #include <stdio.h> 2. int main(void) 3. { 4. int n, c, suma, maximo = 0; 5. int N = 5; 6. c = 0; 7. suma = 0; 8. while(c < N) { 9. printf("Introduce un entero..."); 10. scanf("%d", &n); 11. c++; 12. suma = suma + n;

Page 130: INFORMÁTICA Libro de Problemas

Capítulo 7: Estructuras de control: Repetición | 131

13. if(c == 1) 14. maximo = n; 15. else if(n > maximo) 16. maximo = n; 17. } 18. printf("Suma es ... %d", suma); 19. printf("\nMaximo es ... %d", maximo); 20. double media = (double)suma / N; 21. printf("\nMedia es ... %.2lf\n", media); 22. return 0; 23. }

Comentarios:

• Este programa hace uso de una estructura while para implementar las operaciones que solicita el enunciado sobre un cierto número de valores que recogen por pantalla. Note que en la solución propuesta se utiliza la variable N para almacenar el número máximo de valores que puede introducir el usuario que, en este caso, es 5. Además, se ha declarado la variable c que actuará de contador; es decir, en esta variable se almacenará el número de valores actual que ha introducido el usuario. Esta variable c se ha inicializado al valor de 0.

• Atendiendo a lo explicado en el punto anterior, en la línea 8 del programa, se encuentra la condición que evalúa la estructura while: mientras el valor almacenado en la variable c sea menor que lo que contenga la variable N, el bucle se seguirá ejecutando. En cuanto c tenga un valor igual a N, al estar inicializada en 0, el bucle deja de ejecutarse porque ya habrá llegado al número máximo de valores que el usuario puede introducir.

• Note como, en cada iteración, después de almacenar el valor que introduce el usuario, la variable contador c se incrementa en una unidad.

• Para determinar cuál es el mayor número introducido por el usuario, se ha implementado una estructura if - else if. Si es el primer número que ha introducido el usuario, la variable c tendría el valor 1 y, como en este caso sólo disponemos de un número, a la variable maximo se le asigna el valor que introduce el usuario por teclado. En otro caso, el valor que ha introducido será el segundo o sucesivos, en cuyo caso debemos comprobar si este fuera mayor que el guardado en la variable maximo. Observe que, si no es así, no se realiza ningún cambio en la variable máximo.

• La variable donde se calcula la media debe ser real (float o double). Recuerde que al dividir dos enteros perdemos la parte fraccionaria si no utilizamos el casting para convertir el dividendo y/o el divisor a un número real como en la instrucción:

double media = (double) suma/N;

• Aunque este programa declara la variable media en la línea 20, siempre es aconsejable realizar la declaración de variables al comienzo del programa. Aunque no es obligatorio, sí es una práctica de programación altamente recomendable.

Page 131: INFORMÁTICA Libro de Problemas

132 | Informática. Libro de problemas

7.4. Factorial consecutivo Escriba un programa que muestre el factorial de un número entero positivo que proporciona el usuario por teclado. Asuma que el usuario respetará esta restricción y siempre introducirá un valor positivo. Además, el programa debe ofrecer al usuario la opción de repetir la operación un máximo de 5 veces. El programa debe hacer uso de la estructura do-while. A continuación, se muestran un par de ejemplos de salida por pantalla: Ejemplo 1 de ejecución Introduce un entero positivo...4 El factorial es...24 Quieres seguir? (s/n)...s Introduce un entero positivo...7 El factorial es...5040 Quieres seguir? (s/n)...s Introduce un entero positivo...3 El factorial es...6 Quieres seguir? (s/n)...n

Ejemplo 2 de ejecución Introduce un entero positivo...4 El factorial es...24 Quieres seguir? (s/n)...s Introduce un entero positivo...6 El factorial es...720 Quieres seguir? (s/n)...s Introduce un entero positivo...3 El factorial es...6 Quieres seguir? (s/n)...s Introduce un entero positivo...8 El factorial es...40320 Quieres seguir? (s/n)...s Introduce un entero positivo...7 El factorial es...5040 Quieres seguir? (s/n)...s

Posible solución: Código 7.4

1. #include <stdio.h> 2. int main(void) 3. { 4. unsigned short n; 5. unsigned long F; 6.

Page 132: INFORMÁTICA Libro de Problemas

Capítulo 7: Estructuras de control: Repetición | 133

7. char opcion; // 's' SI continuo, 'n' NO continuo 8. short contador = 0; 9. do { 10. printf("Introduce un entero positivo..."); 11. scanf("%hu", &n); 12. F = 1; 13. 14. while(n != 0) { 15. F = F * n; 16. n = n - 1; 17. } 18. printf("El factorial es...%lu", F); 19. contador++; 20. printf("\nQuieres seguir? (s/n)..."); 21. fflush(stdin); 22. opcion = getchar(); // scanf("%c",&opcion); 23. } while(opcion == 's' && contador < 5); 24. return 0; 25. } 26.

Comentarios:

• A diferencia del Ejercicio 7.2, en este ejercicio se permite que el usuario solicite el cáculo del factorial de hasta 5 valores distintos. Para implementar este comportamiento, el programa mostrado hace uso de la estructura do-while.

• Recuerde que la estructura do-while siempre se ejecutará una vez, es decir, siempre va a ejecutar al menos una primera iteración. En esta primera iteración se ejecutan todas las instrucciones delimitadas por dicha estructura y seguidamente se evalúa la siguiente condición (ver línea 23):

opcion == 's' && contador < 5

Note cómo en la condición se utiliza el operador && para asegurar que sólo se podrá volver a ejectuar la estructura do-while si el usuario introduce un carácter 's' y si el número de valores introducidos es menor que 5.

• Aunque el uso de la instrucción fflush(stdin) es opcional, se recomienda emplearla siempre que se recoja información por teclado mediante las funciones scanf o getchar. Además, su uso es especialmente importante cuando se va a leer por teclado un único carácter, tal y como ocurre en el programa en la instrucción de la línea 22:

opcion = getchar();

• El programa termina cuando el usuario no introduce un 's' caracter 's' o si ya ha introducido 5 números. En el ejemplo 2 de ejecución mostrado anteriormente, aunque el usuario ha introducido un caracter 's' en la ultima línea, el programa finaliza su ejecución porque ha llegado al máximo de 5 entradas. Se podría ampliar el programa para mostrar un mensaje al usuario que ha llegado al máximo número de entradas con la siguiente instrucion después de la línea 23: if(contador >= 5 && opcion == 's')

printf("Has llegado al maximo entradas\n");

Page 133: INFORMÁTICA Libro de Problemas

134 | Informática. Libro de problemas

7.5. Convocatorias Escriba un programa que solicite al usuario las notas que ha obtenido un alumno en las convocatorias de una asignatura. Para ello, el programa comienza solicitando al usuario que introduzca la nota obtenida en la primera convocatoria. Si la nota numérica es menor que 5, el programa deberá de volver a solicitar la nota obtenida por el alumno en la siguiente convocatoria. Este proceso lo hará hasta un máximo de 5 veces. El programa debe contemplar dos situaciones:

• Si el usuario introduce en una convocatoria X una nota numérica mayor o igual que 5, el programa mostrará que ha superado la asignatura en la convocatoria X y finalizará su ejecución.

• Si en la quinta (y última) convocatoria el alumno vuelve a introducir una nota menor que cinco, el programa deberá mostrar un mensaje indicando que debe solicitar una convocatoria extraordinaria.

Por ultimo, el programa debe de hacer uso de la estructura do-while. A continuación, se muestran varios ejemplos de la salida por pantalla: Ejemplo 1 de ejecución Introduzca su nota en convocatoria 1....4 Introduzca su nota en convocatoria 2....6.5 HA SUPERADO LA ASIGNATURA EN LA CONV. 2

Ejemplo 2 de ejecución Introduzca su nota en convocatoria 1....3.5 Introduzca su nota en convocatoria 2....4 Introduzca su nota en convocatoria 3....8.4 HA SUPERADO LA ASIGNATURA EN LA CONV. 3

Ejemplo 3 de ejecución Introduzca su nota en convocatoria 1....4 Introduzca su nota en convocatoria 2....2.3 Introduzca su nota en convocatoria 3....3 Introduzca su nota en convocatoria 4....1 Introduzca su nota en convocatoria 5....2.5 Debe solicitar una convocatoria extraordinaria

Page 134: INFORMÁTICA Libro de Problemas

Capítulo 7: Estructuras de control: Repetición | 135

Posible solución: Código 7.5

1. #include <stdio.h> 2. int main(void) 3. { 4. double nota; 5. int contador = 1; 6. do { 7. printf("Introduzca su nota en convocatoria %d....", contador); 8. scanf("%lf", &a); 9. contador++; 10. } while(nota < 5 && contador <= 5); 11. if(nota >= 5) 12. printf("HA SUPERADO LA ASIGNATURA EN LA CONV. %d\n", contador - 1); 13. else 14. printf("Debe solicitar una convocatoria extraordinaria\n"); 15. return 0; 16. } 17.

Comentarios:

• En este ejercicio el usuario va a introducir la nota obtenida en una asignatura. Este proceso finalizará cuando el usuario introduzca una nota superior a 5 o cuando haya suspendido de manera consecutiva 5 veces. En este ultimo caso, el programa mostrará un mensaje indicando que el alumno debe solicitar una convocatoria extraordinaria.

• Para implementar este ejercicio se hace uso de la estructura do-while, de forma que, siempre se ejecutará al menos una vez. Después de ejecutarse las instrucciones, evaluará (ver línea 10) si la calificación obtenida (almacenada en la variable nota) es menor que 5 y si el número de convocatorias (valor de la variable contador) también es menor que 5. Si esta condición se cumple, entonces volverá a realizarse una nueva iteración del bucle.

• Note cómo se utiliza la variable contador para ir contabilizando las sucesivas convocatorias a las que se presenta un alumno. Esta variable se incrementa en cada iteración del bucle. Como puede observar en la línea 12, la función printf imprime el valor contador-1 ya que el valor almacenado en contador se incrementa después de pedir la convocatoria.

• Observe que el programa no asegura que la calificación proporcionada por el usuario sea una nota válida, es decir, que se encuentre comprendiad entre 0 y 10. Para solucionar este problema, se podría ampliar el programa de manera que se detecte esta situación y se vuelva a solicitar al usaurio la introducción de una nota válida. Concretamente, sería necesario sustituir las líneas 7-8 por el siguiente código:

Page 135: INFORMÁTICA Libro de Problemas

136 | Informática. Libro de problemas

do {

printf("Dime tu nota en convocatoria %d....", contador); scanf("%lf", &a);

} while(nota < 0 || nota > 10);

En este caso, un ejemplo de ejecución del programa sería el siguiente:

Ejemplo de ejecución Dime tu nota en convocatoria 1....4 Dime tu nota en convocatoria 2....-1 Dime tu nota en convocatoria 2....11 Dime tu nota en convocatoria 2....8 HAS SUPERADO LA ASIGNATURA EN LA CONV. 2

7.6. Maximo y media versión for

Escriba un programa que solicite al usuario 5 valores numéricos enteros. El programa deberá mostrar por pantalla el resultado de la media de los valores introducidos y el valor máximo de los números introducidos. Para implementar este ejercicio debe utilizar la estructura de repetición for. A continuación, se muestran un par de ejemplos de la salida por pantalla: Ejemplo 1 de ejecución Introduce el numero 1....4 Introduce el numero 2....7 Introduce el numero 3....10 Introduce el numero 4....3 Introduce el numero 5....8 La media de los valores es ... 6.400 El maximo es ... 10

Ejemplo 2 de ejecución Introduce el numero 1....2 Introduce el numero 2....7 Introduce el numero 3....-7 Introduce el numero 4....14 Introduce el numero 5....-13 La media de los valores es ... 0.600 El maximo es ... 14

Page 136: INFORMÁTICA Libro de Problemas

Capítulo 7: Estructuras de control: Repetición | 137

Posible solución: Código 7.6

1. #include <stdio.h> 2. int main(void) 3. { 4. int n, suma, N = 5; 5. int maximo; 6. short i; 7. for(i = 1, suma = 0; i <= N; i++) { 8. printf("Introduce el numero %hd....", i); 9. scanf("%d", &n); 10. suma = suma + n; 11. if(i == 1) 12. maximo = n; 13. else if(n > maximo) 14. maximo = n; 15. } 16. double media = (double)suma / N; 17. printf("\nLa media de los valores es ... %.3lf", media); 18. printf("\nEl maximo es ... %d\n", maximo); 19. return 0; 20. } 21.

Comentarios:

• Al igual que en el Ejercicio 7.3, el programa debe mostrar por pantalla la media y el número máximo que introduce el usuario, teniendo en cuenta que este sólo puede introducir 5 valores. La diferencia con respecto al Ejercicio 7.3 radica en que este ejercicio solicita emplear la estructura de repetición for.

• Recordando, la sintaxis de la estructura for es: for(s1; ex; s2){s3}

o s1 representa una o más sentencias de inicialización (si son más de una, se separan con comas). Su uso es opcional, por lo que, si fuera necesario, se podría omitir s1. Estas sentencias solamente se ejecutan una vez al principio del bucle for y normalmente se utiliza para inicializar variables de tipo contador. Note que en la estructura for que se utiliza en este programa (línea 7), hay dos sentencias de inicialización: i = 1, suma = 0.

o ex representa una expresión lógica que se evalúa al inicio del bucle y después de cada iteración. Mientras sea verdadera se sigue iterando, es decir, el programa entra en el bucle y ejecuta las instrucciones s3. Cuando sea falsa, el bucle finaliza su ejecución.

Page 137: INFORMÁTICA Libro de Problemas

138 | Informática. Libro de problemas

En este programa, la condición es i<=N. Su uso es opcional, por lo que se puede omitir, en cuyo caso es obligatorio el uso de una sentencia de ruptura como break en el cuerpo del bucle (bloque s3) para finalizar su ejecución.

o s3 son una o más instrucciones que se ejecutan en cada iteración. Si son múltiples, es obligatorio poner llaves para indicar el principio y fin de este bloque. Las instrucciones se separan con ';'. Su uso es opcional.

En este programa, s3 se corresponde con las instrucciones de código comprendidas entre las líneas 8 y 14, las cuales se encuentran delimitadas entre llaves en dicha estructura; es decir, el código correspondiente a la introducción del número y el cómputo de la suma y del valor máximo.

o s2 representa una o más sentencias que se ejecutan después de cada iteración (i.e., después de ejecutar el bloque s3) y antes de evaluar la expresión ex de nuevo. Aunque su uso es opcional, normalmente se utiliza para incrementar/decrementar uno o más contadores. En este programa s2 se corresponde con la insrucción i++.

• El resto del programa es idéntico al explicado en el Ejercicio 7.3. Para más información sobre el resto de instrucciones, se recomienda consultar las explicaciones dadas para dicho ejercicio.

7.7. Primo o compuesto

Escriba un programa que solicite al usuario un número entero positivo y muestre por pantalla si ese número es primo o compuesto. El programa debe hacer uso de la instrucción break. Además, deberá controlar que el número que introduce el usuario sea un valor positivo estrictamente mayor que 0. Seguidamente se muestran varios ejemplos de ejecución del programa que ilustran el funcionamiento esperado: Ejemplo 1 de ejecución Introduce un entero positivo mayor que cero....7 PRIMO

Ejemplo 2 de ejecución Introduce un entero positivo mayor que cero....15 COMPUESTO

Page 138: INFORMÁTICA Libro de Problemas

Capítulo 7: Estructuras de control: Repetición | 139

Ejemplo 3 de ejecución Introduce un entero positivo mayor que cero....0 Introduce un entero positivo mayor que cero....-1 Introduce un entero positivo mayor que cero....6 COMPUESTO

Posible solución: Código 7.7

1. #include <stdio.h> 2. int main(void) 3. { 4. int n, d; 5. unsigned short esPrimo; 6. 7. do { 8. printf("Introduce un entero positivo mayor que cero...."); 9. scanf("%d", &n); 10. } while(n <= 0); 11. 12. esPrimo = 1; // Inicializamos a valor verdadero (distinto de cero) 13. for(d = 2; d < n/2; d++) { 14. if(n % d == 0) { 15. esPrimo = 0; // Marcamos esPrimo con el valor falso (cero) 16. break; 17. } 18. } 19. 20. if(esPrimo) 21. printf("PRIMO\n"); 22. else 23. printf("COMPUESTO\n"); 24. 25. return 0; 26. }

Comentarios:

• Para cumplir con la restricción de que el usuario sólo puede introducir un número entero positivo mayor que 0, se emplea una estructura do-while. Esta estructura permite:

o Que se ejecute, al menos, una vez las funciones printf y scanf, es decir, que el programa solicite al usuario el número a evaluar y lo almacene en la variable n.

o Si el usuario introduce un valor menor o igual que 0, vuelve a solicitar el número, es decir, si el valor que se almacena en la variable n es menor o igual que 0, no se sale del bucle y vuelven a ejecutar las sentencias del mismo.

• En este programa se utiliza una variable denominada esPrimo que toma valores 0 o 1 para indicar si el número introducido por teclado es primo o compuesto. Aplicando las

Page 139: INFORMÁTICA Libro de Problemas

140 | Informática. Libro de problemas

reglas del lenguaje C, si esta variable contiene un valor distinto de 0 se interpreta como verdadero, y si tiene el valor 0 se interpreta como falso.

Observe como el programa inicializa esPrimo con el valor 1 (verdad) en la línea 12, por lo que el programa inicialmente asume que el valor introducido es primo. Más tarde, si el programa encuentra un divisor, entonces significará que el valor no es primo y, por tanto, se cambiará su valor a 0 (falso).

• Se usa una estructura for (líneas 13 -18), para buscar posibles números primos del valor recogido por teclado (almacenado en la variable n). Es importante apreciar lo siguiente:

o El bucle emplea la variable d para recorrer todos los valroes enteros en el intervalo [2, n/2]. Es decir, el bucle evita comprobar si del valor d=1 es divisor (lo cual no tiene sentido) así como cualquier valor mayor a n/2.

o El cuerpo del bucle lo conforma una sentencia if que comprueba para cada iteración si el valor almacenado en d es divisor de n gracias a la expresión n%d==0.

(1) Si esta comparación resulta verdadera, entonces se ejecutan las instrucciones de las líneas 15 y 16. La primera instrucción almacena el valor 0 en esPrimo, con el objetivo de "almacenar" la conclusión a la que se ha llegado: que el valor n no es primo. Seguidamente, se ejecuta la instrucción break, con el objetivo de romper la iteración del bucle y saltar directamente a la primera instrucción inmediatamente posterior al bucle (línea 20).

(2) Si la comparación resulta falsa, entonces no se ejecuta ninguna instrucción del if, pasando a ejecutar el incremento (d++) y seguidamente evaluar la condición del bucle (d < n/2) que determina si se debe ejecutar una nueva iteración o finalizar el mismo.

• En general, no se recomienda utilizar la sentencia break, ya que crea programas no estructurados. Para evitar el uso de instrucción break y múltiples salidas de los bucles, se puede utilizar la variable esPrimo en la expresión lógica que determina la permanencia del bucle, tal y como se muestra en el siguiente ejemplo:

for(d = 2; d < n/2 && esPrimo; d++) { if(n % d == 0) esPrimo = 0; }

• El valor almacenado en la variable esPrimo es usado como referente a la hora de imprimir por pantalla el mensaje correcto. En las líneas 20-23 se puede observar el sencillo uso de una estructura if-else para implementar este comportamiento.

Page 140: INFORMÁTICA Libro de Problemas

Capítulo 7: Estructuras de control: Repetición | 141

7.8. Aproximación Pi/4

Escriba un programa que calcule el número Pi sabiendo que este número verifica la siguiente relación:

𝜋𝜋4 = �

(−1)𝑘𝑘

2𝑘𝑘 + 1

𝑘𝑘=0

Para resolverlo, tenga en cuenta que el número de términos o iteraciones (k) es 100000 y muestre el valor obtenido con 15 decimales. Un ejemplo de ejecución del programa sería: Ejemplo de ejecución El valor de Pi en 100000 iteraciones ... 3.141582653589720

Posible solución: Código 7.8

1. #include <stdio.h> 2. #define _Niter 100000 3. int main(void) 4. { 5. double Pi = 0; 6. int k; 7. int n = 1, d = 1; 8. for(k = 0; k < _Niter; k++) { 9. Pi = Pi + (double)n / d; 10. d = d + 2; 11. if(k % 2 == 0) 12. n = -1; 13. else 14. n = +1; 15. } 16. Pi = Pi * 4; 17. printf("El valor de Pi en %d iteraciones ... %.15lf\n", _Niter, Pi); 18. 19. return 0; 20. } 21.

Comentarios:

• En este ejercicio, siguiendo la expresión que se indica en el enunciado y el número de términos, se calcula el valor del número Pi.

Page 141: INFORMÁTICA Libro de Problemas

142 | Informática. Libro de problemas

• Antes de la función principal main, en la línea 2, se usa la directiva define para indicar el número de iteraciones mediante un valor constante.

• En este tipo de ejercicios es recomendable desarrollar la expresión que se indica. Así, dicha expresión se puede escribir como:

𝜋𝜋4 =

(+1)1 +

(−1)3 +

(+1)5 +

(−1)7 +

(+1)9 +

(−1)11 +

(+1)13 …

𝜋𝜋 = 4 × �(+1)

1 +(−1)

3 +(+1)

5 +(−1)

7 +(+1)

9 +(−1)

11 +(+1)

13 . . .�

Como se puede apreciar, la expresión está compuesta por términos cuyo denominador empieza con el valor 1 y el siguiente término tiene un valor de denominador incrementado en 2. Además, el signo va alternando, de forma que si consideramos el primer término como par (k=0), tendrá el signo positivo, en cambio, para los términos impares, el signo será negativo. Tenga en cuenta que, una vez calculado el valor de la suma de los k términos, para obtener el valor de Pi tendremos que multiplicar por 4.

• Note que, con el objetivo de tener una mayor precisión, se declara la variable Pi como double en vez de float.

• Para implementar lo anterior, el programa va sumando los elementos en el bucle for, donde la variable n representa el numerador, la variable d representa el denominador y la variable k representa el índice del término de la serie.

• Como puede apreciar, el bucle for va recorriendo todos los términos y realiza la suma (ver línea 9). Después, actualiza los parámetros para la siguiente iteración en función del término correspondiente (líneas 10 a 14).

• Si se incluye la librería math.h, se podría sustituir las instrucciones que conforman el cuerpo del bucle for (líneas 9-14) con la siguiente línea:

Pi+=pow(-1, k)/(2*k+1)

La función pow devuelve el numero -1 elevado a i.

• Observe que para imprimir el valor de la variable Pi con 15 decimales se utiliza el especificador de formato %.15lf.

• Otra forma alternativa de implementar el bucle for sería: for(k=0,n=1,d=1; k < _Niter; k++,d+=2,n=-n)

Pi = Pi + (double) n/d; Observe que este bucle incluye la inicialización de las variables n y d como sentencias de inicialización del bucle (s1). Además, se han añadido las instrucciones de actualización de las variables d y n como sentencias que se deben ejecutar al finalizar cada iteración (s3).

Page 142: INFORMÁTICA Libro de Problemas

Capítulo 7: Estructuras de control: Repetición | 143

7.9. Aproximación Pi/2

Escriba un programa que calcule el número Pi sabiendo que este número verifica la siguiente relación:

𝜋𝜋2 =

21 ∙

23 ∙

43 ∙

45 ∙

65 ∙

67 ∙

87 ∙

89 ∙

109 ∙ …

Además, el programa debe solicitar al usuario el número de iteraciones. Si el valor que introduce el usuario es menor de cero, el programa vuelve a solicitar dicho valor. A continuación, se muestran varias ejecuciones del programa que ilustran el comportamiento esperado: Ejemplo 1 de ejecución Introduce numero de iteraciones: 10 El valor de Pi es .... 3.0021759546

Ejemplo 2 de ejecución Introduce numero de iteraciones: 100 El valor de Pi es .... 3.1260789002

Ejemplo 3 de ejecución Introduce numero de iteraciones: 1000 El valor de Pi es .... 3.1400238186

Ejemplo 4 de ejecución Introduce numero de iteraciones: -1 Introduce numero de iteraciones: 1200 El valor de Pi es .... 3.1402850189

Page 143: INFORMÁTICA Libro de Problemas

144 | Informática. Libro de problemas

Posible solución: Código 7.9

1. #include <stdio.h> 2. int main(void) 3. { 4. double Pi = 1; 5. int i; 6. int n = 2, d = 1; // n: numerador; d: denominador 7. int Niter; 8. do { 9. printf("Introduce numero de iteraciones: "); 10. scanf("%d", &Niter); 11. } while(Niter <= 0); 12. 13. for(i = 0; i < Niter; i++) { 14. Pi = Pi * (double)n / d; 15. if(i % 2 == 0) 16. d = d + 2; 17. else 18. n = n + 2; 19. // printf("\n En la iteracion %d, Pi = %.15lf", i, Pi*2); 20. } 21. Pi = Pi * 2; 22. printf("\n El valor de Pi es .... %.10lf\n", Pi); 23. return 0; 24. } 25.

Comentarios:

• En este ejercicio, al igual que en el Ejercicio 7.8, se propone una aproximación para el cálculo del numero Pi. La diferencia en este caso, además de la relación, es que el número de iteraciones se solicita al usuario y, además, se nos indica que se debe controlar que dicho número será mayor de 0.

• En la solución propuesta, observe que se utiliza una estructura do-while para asegurar que el usuario introduce un número de iteraciones positivo. Esto permite lograr el comportamiento mostrado en el Ejemplo 4 de ejecución mostrado anteriormente, donde el programa vuelve a pedir que se introduzca el número de iteraciones cuando el usuario introduce un número negativo.

• Para implementar la solución, vemos que: 𝜋𝜋2 =

21 ∙

23 ∙

43 ∙

45 ∙

65 ∙

67 ∙

87 ∙

89 ∙

109 ∙ … → 𝜋𝜋 = 2 × �

21 ∙

23 ∙

43 ∙

45 ∙

65 ∙

67 ∙

87 ∙

89 ∙

109 ∙. . . �

Cuando tengamos el valor de Pi calculado como el producto de un cierto número de términos, se debe de multiplicar por 2.

Page 144: INFORMÁTICA Libro de Problemas

Capítulo 7: Estructuras de control: Repetición | 145

• Note que en cada iteración del bucle for, el programa incrementa el denominador o el numerador en 2 en función de si la iteración es par o impar. Otra manera de implementar la solución podría ser la siguiente:

if(n>d) d += 2; else n += 2;

Si el numerador es mayor que el denominado, entonces incremena el denominador en 2. En caso contrario, el incrementa el numerador también en 2.

• Observe que se imprime el valor de la variable Pi con 10 decimales usando el especificador de formato %.10lf.

• Finalmente, en la línea 19, se puede observar que hay una instrucción comentada: //printf("\n En la iteracion %d, Pi = %.15lf", i, Pi*2);

En caso de quitar el comentario asociado a esta instrucción, el programa imprimiría en cada iteración el valor de la variable Pi con el fin de ver cómo va cambiando el valor de Pi. Esto nos permitiría ver como, conforme se va incorporando al cálculo de Pi nuevos términos de la serie, el valor que se obtiene es más preciso.

Page 145: INFORMÁTICA Libro de Problemas
Page 146: INFORMÁTICA Libro de Problemas

8

FUNCIONES

Page 147: INFORMÁTICA Libro de Problemas
Page 148: INFORMÁTICA Libro de Problemas

Capítulo 8: Funciones | 149

8.1. Potencia Escriba un programa que calcule la potencia de un número. El programa solicitará al usuario que introduzca tanto el exponente (entero) como la base (punto flotante) para calcular la potencia. El programa realizará tres cálculos solicitando al usuario, para cada uno, los valores de base y exponente. A continuación, se muestra un ejemplo de ejecución que ilustra el funcionamiento esperado: Ejemplo de ejecución Introduce la base 1............2.2 Introduce el exponente 1.......8 El resultado es ......... 548.76 Introduce la base 2............200.5 Introduce el exponente 2.......5 El resultado es ......... 324020050062.53 Introduce la base 3............9 Introduce el exponente 3.......9 El resultado es ......... 387420489.00

Posible solución: Código 8.1

1. #include <math.h> 2. #include <stdio.h> 3. #define _MAX 3 4. 5. // 1. Declaración de funciones. Prototipos 6. double potencia(double, short); 7. void mostrarResultado(double); 8. 9. int main(void) 10. { 11. double a; // base 12. short b; // exponente 13. double c; // resultado potencia 14. short contador = 0; 15. 16. do { 17. printf("Introduce la base %hd............", contador + 1); 18. scanf(" %lf", &a); 19. 20. printf("Introduce el exponente %hd.......", contador + 1); 21. scanf(" %hd", &b); 22. 23. // 3. Llamada/invocación

Page 149: INFORMÁTICA Libro de Problemas

150 | Informática. Libro de problemas

24. c = potencia(a, b); 25. mostrarResultado(c); 26. contador++; 27. 28. } while(contador < _MAX); 29. 30. return 0; 31. } 32. 33. // 2. Definición de las funciones 34. double potencia(double x, short y) 35. { 36. short i; 37. double z = 1; 38. for(i = 1; i <= y; i++) { 39. z = z * x; 40. } 41. return z; 42. } 43. 44. void mostrarResultado(double x) 45. { 46. printf("El resultado es ......... %.2lf\n\n", x); 47. return 0; 48. }

Comentarios:

• Para la resolución de este ejemplo, se ha optado por realizar dos funciones. Una de ellas es la función potencia(), que necesitará como parámetros de entrada la base y el exponente, y devolverá el resultado de la operación. La otra función es mostrarResultado(), que mostrará el resultado de la potencia por pantalla.

• La declaración de las funciones se hace antes de la función principal main(). En relación a esta, es importante destacar lo siguiente:

o La declaración de la función potencia() especifica que se devolverá un dato de tipo double y que los parámetros de entrada serán de tipo double (la base) y de tipo short int (el exponente). También se podría haber escrito la declaración de la siguiente manera:

double potencia(double x, short y);

donde se indica el nombre de cada dato de entrada, en este caso x e y.

o Respecto a la declaración de la función mostrarResultado() observe que esta función no va a devolver nada (tipo void) y que, como parámetro de entrada, se espera un dato de tipo double. Al igual que en el caso anterior, también se podría haber escrito la declaración de la siguiente manera:

void mostrarResultado(double x);

donde se indica el nombre del dato de entrada, en este caso x.

Page 150: INFORMÁTICA Libro de Problemas

Capítulo 8: Funciones | 151

o Note que se ha usado el mismo nombre x para declarar un parámetro tanto en la función potencia() y mostrarResultado(). Nótese que esto es perfectamente válido y no genera problema alguno debido a que cada función constituye un ámbito diferente integrado por los parámetros y las variables locales definidas en ella.

o Note que la declaración de una función termina con el símbolo ";". Es un detalle que frecuentemente suele pasar desapercibido y, por tanto, fuente de problemas en la compilación de programas.

• Para poder controlar que el programa solicite tres veces los datos de base y exponente, tal y como se nos solicita en el enunciado, en la función main se ha implementado la estructura do-while. De esta forma conseguimos que las sentencias que hayan dentro de esta estructura do-while se repitan hasta que el valor de la variable contador llegue a ser igual que la constante _MAX (declarada e inicializada a 3 antes del main).

• Para que se muestre por pantalla el mensaje "Introduce la base 1... " donde el número 1 indica que se introduzca la primera base, la función printf se implementa de la siguiente manera (línea 17): printf("Introduce la base %hd............",contador+1);

El especificador %hd indica el lugar donde ubicar el resultado la operación contador+1. Note que NO se modifica la variable contador, sino que se va a mostrar el valor que se genera tras incrementar en una unidad el valor que contiene la variable contador.

• Fíjese en las definiciones de las funciones, las cuales se encuentra después del main(). Al igual que en la declaración, se indica el tipo de dato que va a devolver, el nombre y los parámetros de entrada, aunque, ahora, es obligatorio indicar los nombres de las variables de los parámetros de entrada.

• Note que las sentencias que conforman el cuerpo de una función van siempre entre llaves.

• Con respecto a la función potencia() definida en líneas 34 – 42, destacamos lo siguiente:

o Se declara variable i de tipo short que actúa de contador en la estructura for.

o Se declara la variable z, de tipo double, cuyo cometido será almacenar el valor calculado por la función.

o Fíjese que para calcular la potencia del valor que contenga x, lo que se implementa es la estructura for de manera que, en la variable z se va a almacenar en cada iteración el producto del valor de x con el valor de z. Note que la variable z se inicializa a 1, para que en la primera iteración del bucle for, se almacene el valor de 1*x.

o El bucle for se ejecutará tantas veces como el valor que contenga la variable y, es decir, el exponente.

o Obviamente, se podría haber utilizado otra estructura de repetición para implementar la potencia, como while o do-while.

Page 151: INFORMÁTICA Libro de Problemas

152 | Informática. Libro de problemas

o Para devolver el resultado de la potencia, se utiliza la sentencia return indicando la variable que contiene el dato que queremos devolver, en este caso, la variable z. Note que la variable z debe ser del mismo tipo, que el tipo de dato que hemos indicado que devuelve la función, en este caso, de tipo double.

• Con respecto a la función mostrarResultado() definida en las líneas 44-48, observe que:

o Su cometido es imprimir por pantalla el valor de la potencia que se ha calculado.

o Se emplea la función printf, que muestra el valor que contiene la variable x, la cual es el parámetro de entrada de la función.

• La invocación a las funciones se hace desde la función principal main(). Tal y como se puede observar en el Código 8.1, las sentencias donde se invocan a las funciones se encuentran en las líneas líneas 24 y 25:

c = potencia(a, b); mostrarResultado(c);

o La primera invocación es a la función potencia(). Fíjese como el resultado de la función se almacena en la variable c, la cual, se ha declarado previamente de tipo double para que pueda almancer el valor decimal que devuelve la función potencia().

o A la función potencia() le tenemos que indicar los parámetros de entrada, es decir, las variables que contienen los datos de base y exponente. En el ámbito de la función main(), estos valores se encuentran almacenados en las variables a y b, respectivamente.

o Con respecto a la invocación de la función mostrarResultado(). Puesto que esta función no devuelve nada, la invocación se ha realizado indicando simplemente el nombre a la función y, entre paréntesis, el nombre de la variable donde se encuentra almacenado el cálculo de la potencia (variable c).

8.2. Factorial

Escriba un programa que calcule el factorial de un número entero positivo que introduce el usuario por pantalla. Asuma que el usuario siempre introduce un valor positivo, por lo que no es necesario que el programa verifique que esta restricción se cumple. El programa imprimirá por pantalla el resultado calculado.

A continuación, se muestran un par de ejemplos de ejecución que ilustran el funcionamiento esperado:

Ejemplo 1 de ejecución Introduce un numero entero...5 El factorial de 5 es ... 120

Page 152: INFORMÁTICA Libro de Problemas

Capítulo 8: Funciones | 153

Ejemplo 2 de ejecución Introduce un numero entero...0 El factorial de 0 es ... 1

Posible solución: Código 8.2

1. #include <stdio.h> 2. 3. // 1. Declaración de funciones. Prototipos 4. long factorial(short); 5. 6. int main(void) 7. { 8. short n; 9. long F; 10. printf(" Introduce un numero entero..."); 11. fflush(stdin); 12. scanf(" %hd", &n); 13. 14. // 3. Llamada/invocación 15. F = factorial(n); 16. 17. printf("\n El factorial de %hd es ... %ld \n", n, F); 18. 19. return 0; 20. } 21. 22. // 2. Definición de la función 23. long factorial(short x) 24. { 25. long Fact = 1; 26. short i = 1; 27. while(i <= x) 28. Fact *= i++; 29. return Fact; 30. }

Comentarios:

• En este ejercicio se ha implementado la función llamada factorial() cuyo cometido será realizar el cálculo del factorial de un número entero positivo que recibe como parámetro.

• Como se observa en la declaración, el tipo de dato que va a devolver es long, y el tipo de dato de entrada que espera es short. Otra opción de escribir la declaración sería la siguiente:

Page 153: INFORMÁTICA Libro de Problemas

154 | Informática. Libro de problemas

long factorial(short x)

indicando el nombre de la variable (x en este caso) que contiene el dato del parámetro de entrada.

• El procedimiento que se sigue para calcular el factorial de un número lo encontramos en la definición de la función (líneas 23 – 30):

o Se declaran e inicializan dos variables, Fact e i. En Fact se guardará el resultado.

o Gracias al uso de la estructura de repetición while, se va a realizar el cálculo del factorial de forma progresiva: mientras que la variable i (inicializada a 1) no sea mayor que x, en la variable Fact se guardará el resultado de multiplicar lo que contenga Fact por lo que contenga i.

o Recuerde que el uso del operador post-incremento hace que cuando se ejecute la sentencia Fact *= i++; el valor de la variable i se incremente en uno.

o Fíjese que la variable Fact debe ser inicializada a 1 para que el cálculo se realice de manera correcta incluso cuando el valor de x es 0.

o Note que esta solución no es única. Se puede implementar el cálculo del factorial de un número con estructuras como for o do-while.

o Como esta función tiene que devolver el resultado del factorial, se utiliza la sentencia return Fact. Note que la variable Fact es del mismo tipo de dato que devuelve la función.

• La invocación a la función factorial() se realiza desde el main() en la línea 15 del código:

F = factorial(n);

o En la variable F se va a guardar el valor que devuelve la función factorial. A la función se le pasa el valor que contenga la variable n, que es el número que ha introducido el usuario.

o Nótese que el paso de parámetros a la función factorial es por valor, es decir, el contenido de la variable n se copia a la variable x de la definición.

• Note que este programa tiene una capacidad limitada de operar correctamente. Dependiendo del tipo de compilador que usted emplee y de la arquitectura de su ordenador, podría experimentar dos situaciones distintas:

o Que el programa no calcule correctamente el factorial para valores de n mayores o iguales a 13. Esto se debe a que se usan 32 bits para almacenar valores de tipo long y, por lo tanto, sólo se puede representar el factorial de valores menores o iguales a 12.

o Que el programa no calcule correctamente el factorial para valores de n mayores o iguales a 21. Esto se debe a que se usan 64 bits para almacenar valores de tipo long y, por lo tanto, sólo se puede representar el factorial de valores menores o iguales a 20.

Page 154: INFORMÁTICA Libro de Problemas

Capítulo 8: Funciones | 155

8.3. Factorial global Escriba un programa que calcule el factorial de un número entero positivo que introduce el usuario por pantalla. Asuma que el usuario siempre introduce un valor positivo, por lo que no es necesario que el programa verifique que esta restricción se cumple. Para su resolución, debe emplear variables globales. El programa imprimirá por pantalla el resultado. A continuación, se muestran un par de ejemplos de ejecución que ilustran el funcionamiento esperado: Ejemplo 1 de ejecución Introduce un numero entero...5 El factorial de 5 es ... 120 Ejemplo 2 de ejecución Introduce un numero entero...0 El factorial de 0 es ... 1 Posible solución: Código 8.3

1. #include <stdio.h> 2. 3. long miFact = 1; // Esta es una variable global 4. 5. // 1. Declaración de funciones. Prototipos 6. void factorial(short); 7. 8. int main(void) 9. { 10. short n; 11. printf("Introduce un numero entero..."); 12. fflush(stdin); 13. scanf(" %hd", &n); 14. 15. // 3. Llamada/invocación 16. factorial(n); 17. 18. printf("El factorial de %hd es ... %ld\n", n, miFact); 19. 20. return 0; 21. } 22. 23. // 2. Definición de las funciones 24. void factorial(short x)

Page 155: INFORMÁTICA Libro de Problemas

156 | Informática. Libro de problemas

25. { 26. short i = 1; 27. while(i <= x) 28. miFact *= i++; 29. }

Comentarios:

• Se ha declarado la variable global miFact antes de la declaración de la función. Esta variable será donde la función factorial() almacena el valor calculado. Observe que dicha variable se inicializa con el valor 1, con el objetivo de realizar el cálculo correcto para cualquier valor indicado por el usuario, incluso cuando solicite calcular el factorial de 0.

• La declaración de la función (ubicada en la línea 6) es la siguiente: void factorial(short);

Si lo comparamos con la solución propuesta del Ejercicio 8.2, ahora observamos que esta función no devuelve ningún valor (void). Esto se debe a que el resultado (cálculo del factorial) se va a guardar en la variable global miFact.

• Note como en la definición se usa directamente la variable global miFact (línea 28) dentro de la estructura while, es decir, no se declara ninguna variable local en la función para almacenar el resultado puesto que se va a emplear en la variable global miFact.

• Ahora, la invocación (línea 16) se realiza llamando directamente a la función y pasándole la variable n, que es donde se ha almacenado el número que ha introducido el usuario.

8.4. Resolver ecuación

Escriba un programa que resuelva una ecuación de primer grado del tipo ax+b=0. El valor de los coeficientes (a y b) pueden ser inicializados de manera estática por el programa, no siendo necesario solicitar sus valores al usuario por pantalla. A continuación, se muestra un ejemplo de ejecución que ilustra el comportamiento esperado: Ejemplo de ejecución La solucion de la ecuacion 3x + 5 es -1.67

Page 156: INFORMÁTICA Libro de Problemas

Capítulo 8: Funciones | 157

Posible solución: Código 8.4

1. #include <stdio.h> 2. // 1. Declaración de funciones. Prototipos 3. double solveEq(double a, double b); 4. double solveEq2(double a, double b); 5. 6. int main(void) 7. { 8. double a = 3; 9. double b = 5; 10. double solucionEc; 11. double solucionEc2; 12. 13. // 3. Llamada/invocación 14. solucionEc = solveEq(a, b); // Posible solucion 1 15. solucionEc2 = solveEq2(a, b); // Posible solucion 2 16. printf("\nLa solucion de la ecuacion %.0lfx + %.0lf es %.2lf\n", a, b, soluc

ionEc); 17. // printf("\nLa solucion de la ecuacion %.0lfx + %.0lf es %.2lf\n", a, b, so

lucionEc2); 18. 19. return 0; 20. } 21. 22. // 2. Definición de las funciones 23. // Posible solución usando una variable local para el resultado 24. double solveEq(double a, double b) 25. { 26. double x; 27. x = -b / a; 28. return x; 29. } 30. 31. // Posible solución sin usar variables locales 32. double solveEq2(double a, double b) 33. { 34. return -b / a; 35. }

Comentarios:

• En este ejemplo se presentan dos soluciones al ejercicio, cada una reflejadas en una función distinta: solveEq() y solveEq2(). Cada una de estas funciones cumple con el mismo objetivo: la resolución de una ecuación de primer grado.

• Con respecto a la función solveEq():

o Note que en la declaración (línea 3) se indica que esta función va a devolver un tipo de dato double, que será el resultado de la ecuación. Como parámetros de entrada, esta función espera dos variables de tipo double, que se corresponderán con los términos numéricos de la ecuación: la variable a, que representa el término

Page 157: INFORMÁTICA Libro de Problemas

158 | Informática. Libro de problemas

que acompaña a la incógnita (o termino lineal); y la variable b, que representa el termino independiente.

o En la definición de la función (líneas 24-29), observe que se ha declarado una variable local x de tipo double donde se guardará el resultado de la ecuación, es decir, la negación del resultado que produce la división de los valores contenidos en las variables b y a. Para devolver el resultado, se utiliza la instrucción return (ver línea 28).

• Con respecto a la función solveEq2(), comparada con la anterior, observamos que esta no utiliza ninguna variable local para guardar el resultado de la ecuación, sino que, directamente, en la instrucción return se ha devuelto el resultado calculado.

8.5. Es primo Escriba un programa que indique si un número entero positivo es primo o es compuesto. El programa solicita al usuario que introduzca el número entero. Asuma que el usuario siempre introduce un valor positivo, por lo que no es necesario que el programa verifique que esta restricción se cumple. A continuación, se muestran un par de ejemplos de ejecución que ilustran el comportamiento esperado: Ejemplo 1 de ejecución Introduce un numero entero...5 El numero 5 es PRIMO

Ejemplo 2 de ejecución Introduce un numero entero...10 El numero 10 es COMPUESTO

Posible solución 1ª: Código 8.5.1

1. #include <stdio.h> 2. 3. // 1. Declaración de funciones. Prototipos 4. short esPrimo(short); 5. 6. int main(void) 7. { 8. short x; 9. printf("Introduce un numero entero...");

Page 158: INFORMÁTICA Libro de Problemas

Capítulo 8: Funciones | 159

10. scanf(" %hd", &x); 11. 12. // Opcion 1: con funcion esPrimo 13. if(esPrimo(x)) // 3. Llamada/invocación 14. printf("El numero %hd es PRIMO\n", x); 15. else 16. printf("El numero %hd es COMPUESTO\n", x); 17. 18. return 0; 19. } 20. 21. // 2. Definición de las funciones 22. short esPrimo(short a) 23. { 24. short d; 25. short bandera = 1; 26. for(d = 2; d < a/2 && bandera; d++) { 27. if(a % d == 0) 28. bandera = 0; 29. } 30. return bandera; 31. }

Comentarios solución 1ª:

• Para resolver el ejercicio, debemos tener presente que un número es primo si solamente es divisible por él mismo y por la unidad. En caso contrario, el número se considera compuesto.

• En esta primera propuesta de solución, se ha implementado la función esPrimo(). Como se puede ver en la declaración de la función (línea 4), la función devuelve un tipo de dato short y, como parámetros de entrada, recibe un dato de tipo short.

• Con respecto a la definición de la función esPrimo() localizada entre las líneas 22 y 31, destacar lo siguiente:

o La variable a actuará como parámetro de entrada y almacenará el valor que introduce el usuario. Note que, en realidad, la función principal es la encargada de recoger el valor por pantalla que introduce el usuario (llamada scanf() en la línea 10) y almacenarlo en la variable x. Más tarde, cuando desde la función main() se invoca a la función esPrimo() (ver línea 13), el valor que contiene la variable x se copia a la variable a. Gracias a esto, cuando se ejecuta la función esPrimo(), este valor está accesible.

o Se declaran dos variables locales a la función de tipo short:

(1) La variable d, la cual se utilizará dentro del bucle for para comprobar si cada número menor que a es un posible divisor de a.

(2) La variable bandera, la cual se utilizará para señalizar que se ha encontrado un divisor. Dicha variable bandera se ha inicializado a 1, de forma que, si esta variable no cambia su valor, se considera que el número que contenga la variable a es primo. En caso de localizar algún divisor, la

Page 159: INFORMÁTICA Libro de Problemas

160 | Informática. Libro de problemas

variable bandera cambiará su valor a 0. Esto último se realiza dentro del bucle for, tal y como se explica a continuación.

o La forma en que se determina si el valor almacenado en la variable a es primo es muy similar a la explicada en el Ejercicio 7.7 (Capítulo 7). El bucle for de la línea 26 es el responsable de hacer esta tarea. Tal y como puede observar, d se inicializa a 2, y mientras se cumpla la condición de permanencia (d < a/2 && bandera) se ejecutarán las instrucciones asociadas a este bucle (líneas 27-28). Al final de la iteración, se incrementará en uno el valor de la variable d (d++) para después comprobar la condición de permanencia que determina si se termina el bucle o se realiza una nueva iteración.

o En cada iteración, se comprueba si la operación a%d (línea 27) es igual a 0. Si es así, significa que se ha encontrado un divisor de a y, por lo tanto, la variable bandera pasa a valer 0. Esto provocará que la condición de permanencia del bucle no se cumpla, finalizando por tanto su ejecución.

o Cuando se llega a la condición de parada del bucle for, mediante la instrucción return bandera se devuelve el valor que contenga la variable bandera, de forma que, si bandera vale 1, el número que contiene a es primo, y si es 0, es compuesto.

• La llamada o invocación a la función esPrimo(), que se hace desde la función principal main(), está dentro de una estructura de decisión en la línea 13. Tal y como acabamos de explicar, la función esPrimo() devuelve un valor 0 o 1. Estos valores no han sido escogidos aleatoriamente, sino que corresponde con la interpretación que hace el lenguaje C de la falsedad (valor 0) y la verdad (cualquier valor distinto de 0).

Teniendo en cuenta la información que devuelve la función esPrimo(), en la solución propuesta, se ha realizado la llamada dentro de la condición que valora la estructura if.

Otra opción también válida, aunque menos elegante desde un punto de visto de uso del lenguaje, hubiera sido la siguiente:

resultado= esPrimo(x) if(resultado==1) printf("El numero %hd es PRIMO\n", x); else printf("El numero %hd es COMPUESTO\n", x);

Como se puede observar, se podría haber guardado el resultado de la función esPrimo() en una variable declarada como resultado de tipo short y luego, en la estructura if, evaluar si el número que contiene resultado es 1 o 0.

Page 160: INFORMÁTICA Libro de Problemas

Capítulo 8: Funciones | 161

Posible solución 2ª: Nota: Se ha resaltado en color amarillo los cambios introducidos con respecto a la solución 1ª. Código 8.5.2

1. #include <stdio.h> 2. 3. // 1. Declaración de funciones. Prototipos 4. short esPrimo(short); 5. short esCompuesto(short); 6. 7. int main(void) 8. { 9. short x; 10. printf("Introduce un numero entero..."); 11. scanf(" %hd", &x); 12. 13. // Opcion 2:Usando una función que llame a otra 14. if(esCompuesto(x)) // 3. Llamada/invocación 15. printf("El numero %hd es COMPUESTO\n", x); 16. else 17. printf("El numero %hd es PRIMO\n", x); 18. 19. 20. return 0; 21. } 22. 23. // 2. Definición de las funciones 24. short esPrimo(short a) 25. { 26. short d; 27. short bandera = 1; 28. for(d = 2; d < a; d++) { 29. if(a % d == 0) 30. bandera = 0; 31. } 32. return bandera; 33. } 34. 35. short esCompuesto(short a) 36. { 37. return !esPrimo(a); 38. }

Comentarios solución 2ª:

• En esta segunda solución se ha implementado el programa usando dos funciones: esPrimo() (igual que en la anterior solución) y esCompuesto(). Es decir, esta solución alternativa ofrece una nueva función esCompuesto() que, invocada desde la función principal, indica si un número es compuesto o no.

• Como se puede observar en la declaración de las funciones ubicadas en las líneas 4 y 5, antes de la función main(), ambas funciones van a devolver un tipo de dato short (que

Page 161: INFORMÁTICA Libro de Problemas

162 | Informática. Libro de problemas

representará verdad o falsedad) y, como parámetros de entrada, ambas esperan datos de tipo short (que representará el valor proporcionado por el usuario).

• Respecto a la definición de la función esCompuesto() que se encuentre en las líneas 35-38, es importante aclarar lo siguiente:

o Esta función basa su funcionamiento en invocar los servicios de la función esPrimo(). Si la función esPrimo() nos indica que el valor introducido por el usuario es primo, entonces la función esCompuesto deberá devolver falsedad. Algo parecido ocurre cuando la función esPrimo() nos indica que el valor introducido no es primo, en cuyo caso la función esCompuesto() devuelve verdad. En otras palabras, la función esCompuesto() siempre devuelve el valor contario a la función esPrimo().

o Este comportamiento se consigue con una única instrucción (ver línea 37) en el cuerpo de la función esCompuesto():

return !esPrimo(a);

o Se emplea el operador negación ya que la función esCompuesto() debe devolver lo contrario que devuelva la función esPrimo(); esto es, si un número es primo, no puede ser compuesto y viceversa.

• En relación a esta solución 2ª, tenga en cuenta que esta propuesta tiene como objetivo que el lector aprecie cómo se puede invocar una función desde otra función. Desde un punto de vista de programación, la solución óptima y más elegante que resuelve el problema planteado sería la propuesta anteriormente (solución 1ª).

Posible solución 3ª: Nota: Se ha resaltado en color amarillo los cambios introducidos con respecto a la solución 1ª. Código 8.5.3

1. #include <stdio.h> 2. 3. // 1. Declaración de funciones. Prototipos 4. short esPrimo(short); 5. void imprimir(short); 6. 7. int main(void) 8. { 9. short x; 10. short resultado; 11. printf("Introduce un numero entero..."); 12. scanf(" %hd", &x); 13. 14. 15. // Opcion 3: Usando función para imprimir 16. resultado = esPrimo(x); 17. imprimir(resultado); 18. 19. return 0;

Page 162: INFORMÁTICA Libro de Problemas

Capítulo 8: Funciones | 163

20. } 21. 22. // 2. Definición de las funciones 23. short esPrimo(short a) 24. { 25. short d; 26. short bandera = 1; 27. for(d = 2; d < a; d++) { 28. if(a % d == 0) 29. bandera = 0; 30. } 31. return bandera; 32. } 33. 34. 35. void imprimir(short b) 36. { 37. if(b) 38. printf("El numero es PRIMO\n"); 39. else 40. printf("El numero es COMPUESTO\n"); 41. }

Comentarios solución 3ª:

• En estea tercera solución se utiliza también la función esPrimo() pero se introduce una nueva función imprimir() encargada de la salida por pantalla del resultado obtenido.

• Respecto a la declaración de la función imprimir(), note como se usa el tipo void para indicar que la función no devuelve nada.

• Respecto al contenido de la función principal main(), se declara una variable llamada resultado, de tipo short, que almacena el valor devuelto por la función esPrimo(). Desde la función main(), se realizan las dos invocaciones a las funciones anteriores:

resultado = esPrimo(x); imprimir(resultado);

o Primero, en resultado se guarda el valor devuelto por la función esPrimo(), esto es, un 1 (verdad) si el número que contiene la variable x es primo, o un 0 (falsedad) en caso contrario, es decir, si es compuesto.

o Seguidamente, se invoca la función imprimir() pasándole la variable resultado.

• Respecto a la definición de la función imprimir(), ubicada en las líneas 35-41, destacar la siguiente:

o Mediante la estructura if se comprueba si el valor almacenado en la variable b (valor devuelto por la función esPrimo()) es verdad o falsedad.

o Si representa verdad, entonces el número que contiene la variable x es primo.

Page 163: INFORMÁTICA Libro de Problemas

164 | Informática. Libro de problemas

o En caso contrario, significa que b es igual a 0 y, por tanto, dicho número será compuesto. Para cada situación, se imprime por pantalla (invocación a la función printf()) el mensaje que corresponda.

8.6. Perfecto Escriba una función cuyo prototipo es el siguiente:

short Perfecto(int);

Esta función devolverá el valor numérico de 1 si el número introducido por el usuario es un número perfecto o el valor 0 en caso contrario. Tenga en cuenta que un número perfecto es aquel número entero positivo que es igual a la suma de sus divisores propios.

Aunque en este enunciado sólo se nos pide la implementación de la función Perfecto(), para su mejor comprensión, la resolución de este ejercicio va a mostrar el programa completo que hace uso de esta función. El programa solicitará al usuario un valor entero positivo y mostrará por pantalla si este es perfecto o no.

Para clarificar como debería ser el comportamiento del programa, a continuación, se muestran diversos ejemplos de ejecución:

Ejemplo 1 de ejecución Introduce un entero positivo...10 El numero 10 NO es PERFECTO

Ejemplo 2 de ejecución Introduce un entero positivo...6 El numero 6 PERFECTO

Ejemplo 3 de ejecución Introduce un entero positivo...-3 Introduce un entero positivo...16 El numero 16 NO es PERFECTO

Page 164: INFORMÁTICA Libro de Problemas

Capítulo 8: Funciones | 165

Ejemplo 4 de ejecución Introduce un entero positivo...11.2 El numero 11 NO es PERFECTO

Posible solución: Código 8.6

1. #include <stdio.h> 2. 3. // 1. Declaración de funciones. Prototipos 4. short esPerfecto(int); 5. 6. int main(void) 7. { 8. int x; 9. short a; 10. do { 11. printf("Introduce un entero positivo..."); 12. scanf(" %d", &x); 13. } while(x <= 0); 14. 15. // 3. Llamada/invocación 16. a = esPerfecto(x); 17. 18. if(a == 1) 19. printf("\nEl numero %d PERFECTO\n", x); 20. else 21. printf("\nEl numero %d NO es PERFECTO\n", x); 22. return 0; 23. } 24. 25. // 2. Definición de las funciones 26. short esPerfecto(int x) 27. { 28. int suma = 1; 29. int d; 30. for(d = 2; d <= x / 2; d++) { 31. if(!(x % d)) 32. suma += d; 33. } 34. return (suma == x); 35. }

Comentarios:

• En la función main() se declaran dos variables: x y a.

o La variable x almacenará el valor que introduce el usuario. El programa debe averiguar si este valor es un número perfecto.

Page 165: INFORMÁTICA Libro de Problemas

166 | Informática. Libro de problemas

o La variable a guardará el resultado devuelto por la función esPerfecto(). Note como esta variable a es de tipo short, ya el enunciado de este ejercicio nos indica que short es el tipo de dato que devuelve la función esPerfecto().

• De manera similar a como se ha visto en ejercicios anteriores, para asegurarnos que el usuario introduce un número entero positivo, se hace uso de una estructura do-while: mientras que lo que contenga la variable x sea menor o igual a cero, se volverá a solicitar al usuario que introduzca un nuevo valor.

• En la definición de la función (líneas 26-35), se encuentran las instrucciones que son necesarias para calcular la suma de los divisores del número que introduce el usuario y comprobar, si esa suma es igual a dicho número. En relación a esto, es importante realizar algunas aclaraciones:

o En la búsqueda de posibles divisores que realizar el bucle for (línea 30), observe como se recorre todos los valores comprendidos entre 2 y la mitad del número (x) que introduce el usuario. Esto se hace así porque no tiene sentido buscar divisores en valores comprendidos en el intervalo x/2 y x.

o Para cada uno de los valores comprendidos en este rango, se averigua si es un divisor de x por medio de una estructura if cuya condición es !(x % d).

(1) Esto significa que se entrará en la estructura if si el resultado de la operación resto entre la variable x y la variable d no existe, o mejor dicho, si la operación resto devuelve un 0.

(2) Fíjese que esto es así porque se emplea el operador de negación. Por lo tanto, si el operador resto devuelve un 0 (que representa falsedad), significa que d es divisor de x, siendo necesario aplicar el operador de negación para transformar ese valor 0 (falsedad) en un 1 (verdad).

(3) Notar que la estructura if no usa llaves ya que su cuerpo consta de una única instrucción.

o Cuando finaliza el bucle for, se ejecuta la instrucción de la línea 34: return (suma == x);

El operador == devolverá un 1, si los valores que contienen las variables son iguales, esto es, si la suma de los divisores es igual al número que introduce el usuario. En este caso el número será perfecto. En caso contrario, devolverá un 0 y significará que el número no es perfecto.

• En la invocación desde la función principal main() (ver línea 16) se guarda en la variable a el valor devuelto por la función esPerfecto(). Seguidamente, se implementa una estructura if-else donde, dependiendo del valor que contenga a (1 o 0), se imprimirá si es perfecto o no.

• Note, que al igual que se propuso en la resolución del Ejercicio 8.5 (ver Código 8.5.1), se podría haber implementado la estructura if-else llamando directamente a la función

Page 166: INFORMÁTICA Libro de Problemas

Capítulo 8: Funciones | 167

esPerfecto() dentro de la condición de la estructura, tal y como se muestra a continuación:

if(esPerfecto(x)) printf("\nEl numero %d PERFECTO\n", x); else printf("\nEl numero %d NO es PERFECTO\n", x);

Esta alternativa no es sólo más elegante sino también más eficiente pues se ahorra el uso de la variable a.

Page 167: INFORMÁTICA Libro de Problemas
Page 168: INFORMÁTICA Libro de Problemas

9

ARRAYS NUMÉRICOS

Page 169: INFORMÁTICA Libro de Problemas
Page 170: INFORMÁTICA Libro de Problemas

Capítulo 9: Arrays numéricos | 171

9.1. Operaciones vectores Escriba un programa que declare cuatro vectores de enteros. Estos vectores tendrán la misma dimensión, la cual se especificará mediante un valor constante definido usando la directiva define. El programa debe realizar las siguientes operaciones:

1) Al primer vector se le asignarán los valores por teclado. 2) El segundo vector será copia del primer vector. 3) El tercero será copia en orden inverso del primero. 4) El cuarto será la suma del segundo y tercero.

El programa finalizará su ejecución mostrando los cuatro vectores. Primero los mostrará en filas y luego los mostrará en columnas. A continuación, se muestra un ejemplo de ejecución que ilustra el comportamiento esperado por el programa para vectores de dimensión 5. Ejemplo 1 de ejecución Introduzca el 1° elemento para Vec1: 5 Introduzca el 2° elemento para Vec1: 4 Introduzca el 3° elemento para Vec1: 3 Introduzca el 4° elemento para Vec1: 2 Introduzca el 5° elemento para Vec1: 1 Los cuatro vectores son: Vec1: 5 4 3 2 1 Vec2: 5 4 3 2 1 Vec3: 1 2 3 4 5 Vec4: 6 6 6 6 6 Los cuatro vectores en columna: 5 5 1 6 4 4 2 6 3 3 3 6 2 2 4 6 1 1 5 6 Ejemplo 2 de ejecución Introduzca el 1° elemento para Vec1: -1 Introduzca el 2° elemento para Vec1: -2 Introduzca el 3° elemento para Vec1: 0 Introduzca el 4° elemento para Vec1: 3 Introduzca el 5° elemento para Vec1: 4 Los cuatro vectores son: Vec1: -1 -2 0 3 4 Vec2: -1 -2 0 3 4

Page 171: INFORMÁTICA Libro de Problemas

172 | Informática. Libro de problemas

Vec3: 4 3 0 -2 -1 Vec4: 3 1 0 1 3 Los cuatro vectores en columna: -1 -1 4 3 -2 -2 3 1 0 0 0 0 3 3 -2 1 4 4 -1 3

Posible solución: Código 9.1

1. #include <stdio.h> 2. #define _D 5 3. 4. int main(void) 5. { 6. int Vec1[_D], Vec2[_D], Vec3[_D], Vec4[_D]; 7. int i; 8. 9. // Vec1 -->Asignación de valores por teclado 10. for(i = 0; i < _D; i++) { 11. printf("Introduzca el %d%c elemento para Vec1: ", i + 1, 248); 12. scanf(" %d", &Vec1[i]); 13. } 14. 15. // Vec2 -->Copia de Vec1 16. for(i = 0; i < _D; i++) { 17. Vec2[i] = Vec1[i]; 18. } 19. 20. // Vec3 -->Copia de Vec1 en orden inverso 21. 22. for(i = 0; i < _D; i++) { 23. Vec3[i] = Vec1[(_D - 1) - i]; 24. } 25. // Vec4 --> Suma de Vec2 y Vec3 26. for(i = 0; i < _D; i++) { 27. Vec4[i] = Vec2[i] + Vec3[i]; 28. } 29. 30. // Se imprime cada vector en una línea 31. printf("\nLos cuatro vectores son: "); 32. 33. printf("\nVec1:"); 34. for(i = 0; i < _D; i++) { 35. printf(" % d", Vec1[i]); 36. } 37. 38. printf("\nVec2:"); 39. for(i = 0; i < _D; i++) { 40. printf(" % d", Vec2[i]); 41. } 42.

Page 172: INFORMÁTICA Libro de Problemas

Capítulo 9: Arrays numéricos | 173

43. printf("\nVec3:"); 44. for(i = 0; i < _D; i++) { 45. printf(" % d", Vec3[i]); 46. } 47. 48. printf("\nVec4:"); 49. for(i = 0; i < _D; i++) { 50. printf(" % d", Vec4[i]); 51. } 52. 53. // Se muestran los cuatro arrays en cuatro columnas 54. printf("\n"); 55. printf("\nLos cuatro vectores en columna: \n"); 56. for(i = 0; i < _D; i++) { 57. printf("% d\t% d\t% d\t% d\n", Vec1[i], Vec2[i], Vec3[i], Vec4[i]); 58. } 59. printf("\n"); 60. return 0; 61. }

Comentarios:

• En este ejercicio se van a usar cuatro vectores. El enunciado del ejercicio no especifica un tamaño para dichos vectores, por lo que definiremos una constante _D con valor de 5 (ver directiva #define en línea 2) que usaremos en la declaración de los vectores para indicar el tamaño. La declaración de los vectores se realiza en la línea 6 del programa.

• Atendiendo a las indicaciones del ejercicio, al primer vector Vec1 se le asignan los valores que el usuario introduzca por teclado. Para ello, tendremos que recorrer el vector y, en cada posición, ir guardando el valor recogido por teclado gracias a la función scanf(). Tal y como se observa en las líneas 10-13, se utiliza la estructura for de la siguiente manera:

for(i = 0; i < _D; i++) { printf("Introduzca el %d%c elemento para Vec1: ", i + 1, 248); scanf(" %d", &Vec1[i]); }

o Mediante el contador i, en cada posición del vector vec1 se va guardando el valor que introduce el usuario mediante scanf(). Fíjese como la posición en la que se almacena el primer valor que introduce el usuario es la posición 0, ya que es la primera posición de un vector.

o Note que en la llamada a printf() se utiliza la expresión i+1 para indicar el orden que corresponde a cada número que introduce el usuario. Por ejemplo, para que en la primera iteración del bucle se muestre por pantalla el mensaje "Introduzca el 1º elemento para Vec1: " se utiliza i+1 puesto que el contador i comienza en el valor 0. Para que aparezca el carácter 'º' se utiliza el valor numérico 248, que se corresponde en ASCII a dicho carácter.

Page 173: INFORMÁTICA Libro de Problemas

174 | Informática. Libro de problemas

o Este bucle for se ejecutará hasta que el contador i adopte el valor de _D-1, puesto que la condición de parada es i<_D. Note que otra forma de indicar la misma condición de parada sería: i<=_D-1.

• El segundo vector debe ser una copia del primero. Para ello, se recorrerá todas las posiciones del vector Vec2 asignándole los valores numéricos contenidos en el vector Vec1 en el mismo orden. Esta tarea se lleva a cabo gracias a las líneas de código 16-18:

for(i = 0; i < _D; i++) { Vec2[i] = Vec1[i]; }

o Nuevamente, se usa una estructura for con el contador i, el cual se inicializa a 0 dentro de la misma estructura.

o El proceso de copia se lleva a cabo iteración a iteración, según se indica a continuación:

1ª iteración Vec2[0]=Vec1[0] 2ª iteración Vec2[1]=Vec1[1] 3ª iteración Vec2[2]=Vec1[2] 4ª iteración Vec2[3]=Vec1[3] 5ª iteración Vec2[4]=Vec1[4]

• Para inicializar el tercer vector Vec3, se tienen que copiar todos los valores de Vec1 pero en orden inverso. El código encargado de esta operación se encuentra en las líneas 22-24:

for(i = 0; i < _D; i++) { Vec3[i] = Vec1[(_D-1)-i]; }

o Dada una posición i el vector Vec3, el valor que se copiará del vector Vec1 será aquel que se encuentre en la posición (_D-1) – i. De este modo, se tendrá que:

1ª iteración Vec2[0]=Vec1[4] 2ª iteración Vec2[1]=Vec1[3] 3ª iteración Vec2[2]=Vec1[2] 4ª iteración Vec2[3]=Vec1[1] 5ª iteración Vec2[4]=Vec1[0]

o Otra forma de implementar la copia en orden inverso sería inicializando el contador i dentro de la estructura for con el valor _D-1, quedando de la siguiente forma:

for(i = _D-1; i >= 0; i--) { Vec3[i] = Vec1[(_D - 1) - i]; }

o En el caso anterior, note que ahora el contador i debe ir decrementándose en cada iteración (i--), de manera que el bucle se ejecutará mientras que el contador sea mayor o igual que cero (i>=0). De este modo, se tendrá que:

Page 174: INFORMÁTICA Libro de Problemas

Capítulo 9: Arrays numéricos | 175

1ª iteración Vec2[4]=Vec1[0] 2ª iteración Vec2[3]=Vec1[1] 3ª iteración Vec2[2]=Vec1[2] 4ª iteración Vec2[1]=Vec1[3] 5ª iteración Vec2[0]=Vec1[4]

• En el caso del cuarto vector, en cada posición de Vec4 se guardará la suma de los valores que contengan en esa misma posición los vectores Vec2 y Vec3. La implementación propuesta para llevar a cabo esta tarea es la siguiente:

for(i = 0; i < _D; i++) { Vec4[i] = Vec2[i] + Vec3[i]; }

• Para imprimir cada vector en línea o en serie, debemos emplear nuevamente la estructura de repetición for para recorrer todas las posiciones del vector. Para cada posición, emplearemos la función printf() para imprimir por pantalla el valor almacenado. Por ejemplo, para el vector Vec4:

for(i = 0; i < _D; i++) { printf(" % d", Vec4[i]); }

Observe como, de manera intencionada, se ha insertado un espacio en el especificador de formato, ubicado entre el símbolo "%" y la letra que indica el tipo (d). Esto provocará que se deje un espacio cuando se imprima un número positio, o se imprima el signo cuando se trate de un número negativo.

• Para poder mostrar los cuatro vectores en columna, se imprime en una misma línea todos los valores que ocupen de la misma posición en cada vector. Esta tarea se lleva a cabo en las líneas 56-58 del Código 9.1.

9.2. Vector Ordenado

Escriba un programa que solicite al usuario 5 valores numéricos enteros. Seguidamente el programa mostrará el mensaje "Los valores introducidos están ordenados" si los valores introducidos están ordenados de menor a mayor. En caso contrario, se mostrará el mensaje "Los valores introducidos no están ordenados". A continuación, se muestran un par de ejemplos de ejecución que ilustran el comportamiento esperado del programa:

Page 175: INFORMÁTICA Libro de Problemas

176 | Informática. Libro de problemas

Ejemplo 1 de ejecución Introduzca el 1° valor: 8 Introduzca el 2° valor: 4 Introduzca el 3° valor: 6 Introduzca el 4° valor: 2 Introduzca el 5° valor: 4 Los valores introducidos no estan ordenados

Ejemplo 2 de ejecución Introduzca el 1° valor: 3 Introduzca el 2° valor: 4 Introduzca el 3° valor: 6 Introduzca el 4° valor: 7 Introduzca el 5° valor: 9 Los valores introducidos estan ordenados

Ejemplo 3 de ejecución Introduzca el 1° valor: 3 Introduzca el 2° valor: 4 Introduzca el 3° valor: 4 Introduzca el 4° valor: 4 Introduzca el 5° valor: 5 Los valores introducidos estan ordenados Posible solución: Código 9.2

1. #include <stdio.h> 2. #define _N 5 3. int main(void) 4. { 5. int v[_N]; 6. short i; 7. short ordenado = 1; 8. for(i = 0; i < _N; i++) { 9. printf("Introduzca el %d%c valor: ", i + 1, 248); 10. scanf(" %d", &v[i]); 11. } 12. for(i = 0; (i < _N - 1) && ordenado; i++) { 13. if(v[i] > v[i + 1]) { 14. ordenado = 0; 15. } 16. } 17. if(ordenado)

Page 176: INFORMÁTICA Libro de Problemas

Capítulo 9: Arrays numéricos | 177

18. printf("\nLos valores introducidos estan ordenados\n"); 19. else 20. printf("\nLos valores introducidos no estan ordenados\n"); 21. return 0; 22. } 23.

Comentarios:

• En este ejercicio se debe comprobar si una secuencia de valores numéricos se encuentra ordenada de manera ascendente. Para ello, en primer lugar, el programa propuesto opta por almacenar los valores en un vector. Seguidamente, se comprobará si los valores contenidos en el vector se encuentran en orden ascendente.

• Según lo anterior, los valores que introduce el usuario se guardan en el vector v[_N], el cual es un vector de tipo entero y con dimensión definida por la constante _N. Dicha constante tiene el valor 5, debido a que el enunciado indica que esta será la cantidad de valores numéricos que se soliciten al usuario por teclado.

• Se declara una variable de tipo short llamada ordenado. Esta variable se inicializa al valor de 1 (verdad), de manera que inicialmente se presupone que los valores del vector se encuentran ordenados. Es tarea del programa verificar que esto es así. En caso de detectar que los valores del vector no se almacenan en orden ascendente, entonces el valor de ordenado valor se cambiará a 0 (falso).

• Para comprobar si los valores están ordenados de manera ascendente, se recorre el vector mediante la estructura for (líneas 12-16):

for(i=0; (i<_N-1) && ordenado; i++) { if(v[i] > v[i+1]) { ordenado=0; } }

o Esta estructura repetitiva se ejecutará mientras el contador i se menor que _N-1 y, además, que el valor almacenado en variable ordenado represente verdad (distinto de cero). Dicho de otra forma, la ejecución iterativa se detendrá cuando se alcance la última posición del vector o cuando la variable ordenado cambie su valor a 0 (falso).

o En la estructura de decisión if, se comprueba si el valor del vector en una posición es mayor que el valor de la posición siguiente. Si se cumple dicha condición, implicará que el vector no está ordenado de forma ascendente, por lo que a la variable ordenado se le asigna el valor de 0 (falso).

• El programa finaliza (líneas 17-20) mediante una estructura if-else que comprueba el valor de la variable ordenado. Si el valor que contiene la variable ordenado equivale a verdad, entonces el vector está ordenado de forma ascendente y, por tanto, se imprimirá por pantalla el mensaje "Los valores introducidos están ordenados". En caso contrario, se ejecutará la sentencia que se corresponde con else, mostrando por pantalla

Page 177: INFORMÁTICA Libro de Problemas

178 | Informática. Libro de problemas

un mensaje informando al usuario que los valores no están ordenados. Fíjese como la estructura if-else prescinde del uso de llaves, ya que sólo existe una instrucción en cada caso.

9.3. Negativos positivos

Escriba un programa que permita introducir 10 valores reales que deberán ser almacenados en un vector. El programa calculará la media de los valores positivos y la media de los valores negativos, de forma independiente. Para calcular ambos promedios, no se tendrán en cuenta los valores nulos. Además, el programa deberá avisar si no se puede calcular la media debido a que el usuario ha introducido solamente valores positivos, valores negativos o valores nulos. El programa finalizará su ejecución mostrando por pantalla los valores calculados. A continuación, se muestran varios ejemplos de ejecución que ilustran el comportamiento esperado del programa: Ejemplo 1 de ejecución Introduzca el 1° valor: 5 Introduzca el 2° valor: 3 Introduzca el 3° valor: -7 Introduzca el 4° valor: 1.5 Introduzca el 5° valor: 0 Introduzca el 6° valor: -5 Introduzca el 7° valor: 2.5 Introduzca el 8° valor: -2 Introduzca el 9° valor: 0 Introduzca el 10° valor: 1.5 Media Positivos: 2.700000 Media Negativos: -4.666667

Ejemplo 2 de ejecución Introduzca el 1° valor: 3 Introduzca el 2° valor: 4 Introduzca el 3° valor: 2 Introduzca el 4° valor: 5 Introduzca el 5° valor: 6 Introduzca el 6° valor: 7 Introduzca el 7° valor: 8 Introduzca el 8° valor: 2 Introduzca el 9° valor: 1 Introduzca el 10° valor: 91 Media Positivos: 12.900000 Media Negativos: No es posible realizar la media porque no hay valores negativos

Page 178: INFORMÁTICA Libro de Problemas

Capítulo 9: Arrays numéricos | 179

Ejemplo 3 de ejecución Introduzca el 1° valor: 0 Introduzca el 2° valor: 0 Introduzca el 3° valor: 0 Introduzca el 4° valor: 0 Introduzca el 5° valor: 0 Introduzca el 6° valor: 0 Introduzca el 7° valor: 0 Introduzca el 8° valor: 0 Introduzca el 9° valor: 0 Introduzca el 10° valor: 0 No es posible realizar la media porque no hay valores positivos ni negativos.

Posible solución: Código 9.3

1. #include <stdio.h> 2. #define _N 10 3. int main(void) 4. { 5. double vector[_N]; 6. double SumaP = 0, SumaN = 0; 7. short Np = 0, Nn = 0; 8. int i; 9. for(i = 0; i < _N; i++) { 10. printf("Introduzca el %d%c valor: ", i + 1, 248); 11. scanf(" %lf", &vector[i]); 12. if(vector[i] > 0) { 13. SumaP += vector[i]; // SumaP=SumaP+vector[i]; 14. Np++; // Np+=1; //Np=Np+1; 15. } else { 16. SumaN += vector[i]; 17. if(vector[i]) 18. Nn++; 19. } 20. } 21. if(Np > 0 && Nn > 0){ 22. printf("\nMedia Positivos: %lf", SumaP / Np); 23. printf("\nMedia Negativos: %lf\n", SumaN / Nn); 24. } 25. else if (Np==0 && Nn > 0){ 26. printf("\nMedia Positivos: No es posible realizar la media porque no

hay valores positivos”); 27. printf("\nMedia Negativos: %lf\n", SumaN / Nn); 28. } 29. else if (Np > 0 && Nn==0){ 30. printf("\nMedia Positivos: %lf", SumaP / Np); 31. printf("\nMedia Negativos: No es posible realizar la media porque no

hay valores negativos”); 32. } 33. else

Page 179: INFORMÁTICA Libro de Problemas

180 | Informática. Libro de problemas

34. printf("\n No es posible realizar la media porque no hay valores ni positivos ni negativos.\n”);

35. 36. return 0; 37. }

Comentarios:

• Al tratar con números reales, se declara un vector de tipo double llamado vector y con dimensión dada por la constante _N (definida mediante la directiva #define) de valor 10.

• Además, se declaran dos variables de tipo double, llamadas SumaP y SumaN donde se almacenará la suma de los valores positivos y negativos, respectivamente. Note como estas variables están inicializadas al valor 0. También se declaran dos variables (Np y Nn) de tipo short, que se emplearán para contabilizar la cantidad de valores positivos y negativos que introduce el usuario, respectivamente. Para llevar a cabo una contabilización correcta, observe como es necesario inicializar Np y Nn a cero debido a que, en el Código 9.3, estas variables van a ser incrementadas en una unidad cada vez que se encuentre un valor.

• La estructura for comprendida entre las líneas 9-20 se encarga de recoger valores por teclado, almacenarlos en vector y realizar tanto la suma acumulativa como la contabilización del valor de manera adecauda, según sea positivo o negativo. Concretamente, respecto a su funcionamiento, destacamos lo siguiente:

o Fíjese como el número de ejecuciones iterativas de este bucle viene determinado por el valor de la constante _N, que es el valor de la dimensión de vector, o lo que es lo mismo, la cantidad de valores numéricos que se solicitan al usuario.

o En este bucle, en cada iteración, se le pide al usuario que introduzca un valor numérico real (líneas 10-11). Después de almacenar ese valor en la posición correspondiente en vector, se comprueba si el valor numérico introducido es positivo o negativo (líneas 12-20). En función del caso, se lleva realiza una operación distinta:

Si el valor proporcionado por el usuario es mayor que 0, entonces en la variable SumaP se asignará la suma de lo que contiene la variable SumaP con el número que ha introducido el usuario (línea 13), y que está almacenado en la posición correspondiente de vector. Además, el contador de números positivos (Np) se incrementará en 1 (línea 14).

Si no se cumple la condición anterior, el número o bien es negativo o bien es cero. Dentro del else se llevan a cabo las siguientes acciones:

- En primer lugar, se ejecuta la instrucción SumaN += vector[i] (línea 16). Observe que si el contenido vector[i] es cero, el valor de SumaN no se va a alterar.

Page 180: INFORMÁTICA Libro de Problemas

Capítulo 9: Arrays numéricos | 181

- Sin embargo, para que el contador Nn se incremente sólo cuando el valor numérico no sea nulo, se emplea una estructura if (líneas 17-19) que verifica si el contenido de vector[i] es distinto de cero. Si se cumple esta condición, significará que es un número negativo y, por lo tanto, en ese caso Nn se incrementará (línea 18).

• Por último, se mostrará por pantalla un mensaje con la información acerca de la media de los valores positivos y negativos que se ha calculado, adaptado a los distintos casos que se pueden presentar. Para ello, se emplea una estructura if-else if-else (líneas 21-34) donde se distiguen las siguientes situaciones:

o Existen valores positivos y negativos. En este caso, se cumple la condición Np>0 && Nn>0 (línea 21), y se muestra el promedio de positivos y negativos.

o No existen valores positivos pero sí valores negativos. En este caso, se cumple la condición Np==0 && Nn>0 (línea 25), mostrándose únicamente el promedio de negativos.

o Existen valores positivos, pero ninguno negativo. En este caso, se cumple la condición Np > 0 && Nn==0 (línea 29), mostrándose únicamente el promedio de positivos.

o No existen ni valores positivos ni negativos, es decir, todos los valores facilitados por el usuario son nulos. Este sería el último caso posible, activando por tanto la cláusula else (línea 33) que muestra un mensaje informando sobre esta situación especial.

• Note como en cada instrucción, dentro de la función printf, se calcula directamente la media. Observe que, en cada caso, aunque la división se realiza entre una variable double y otra de tipo short, el resultado es el correcto ya que se realiza una conversión implícita donde el valor short promociona a double.

9.4. Factoriales

Escriba un programa que muestre por pantalla el factorial de los valores enteros comprendidos entre 0 y 9, ambos inclusive. Se deberá emplear un vector para guardar el valor de los distintos factoriales calculados. A continuación, se muestra un ejemplo de ejecución que ilustra el comportamiento esperado del programa:

Page 181: INFORMÁTICA Libro de Problemas

182 | Informática. Libro de problemas

Ejemplo de ejecución El factorial de 0 es 1 El factorial de 1 es 1 El factorial de 2 es 2 El factorial de 3 es 6 El factorial de 4 es 24 El factorial de 5 es 120 El factorial de 6 es 720 El factorial de 7 es 5040 El factorial de 8 es 40320 El factorial de 9 es 362880 Posible solución: Código 9.4

1. #include <stdio.h> 2. #define _N 10 3. int main(void) 4. { 5. int fact[_N]; 6. short i; 7. fact[0] = 1; 8. for(i = 1; i < _N; i++) { 9. fact[i] = i * fact[i - 1]; 10. } 11. for(i = 0; i < _N; i++) { 12. printf("El factorial de %hd es %d\n", i, fact[i]); 13. } 14. return 0; 15. }

Comentarios:

• Para realizar el cálculo del factorial de los números comprendidos entre 0 y 9, debemos emplear un vector de tamaño 10. Por este motivo, declaramos una constante _N (línea 2) con el valor 10, que es empleada para indicar la dimensión del vector fact.

• Mediante un bucle for (líneas 8-10) se recorre cada posición del vector fact con el objetivo de calcular el factorial de cada número de manera progresiva:

- Para el cálculo del factorial de un número se aplica la siguiente expresión:

N! = N x (N-1)!

- Según lo anterior, observamos que, en cada posición del vector fact, se guarda el resultado de multiplicar el contador i por el valor que contenga la posición anterior del vector fact. De este modo, la ejecución del bucle for resulta en lo siguiente:

i=1 fact[1]= 1* fact[0]

i=2 fact[2]= 2* fact[1]

Page 182: INFORMÁTICA Libro de Problemas

Capítulo 9: Arrays numéricos | 183

i=3 fact[3]= 3* fact[2]

i=4 fact[4]= 4* fact[3]

i=5 fact[5]= 5* fact[4]

i=6 fact[6]= 6* fact[5]

i=7 fact[7]= 7* fact[6]

i=8 fact[8]= 8* fact[7]

i=9 fact[9]= 9* fact[8]

- Para que esta operación funcione, debemos ser cuidados y asignar a fact[0] un valor adecuado. Como ya sabrá, cuando se declara una variable o un vector en el lenguaje C, sus elementos pueden presentar valores arbitrarios. Por lo tanto, se debe asignar a la posición 0 del vector fact el valor de 1, como puede ver en la línea 7 del Código 9.4.

• El programa finaliza su ejecución imprimiendo por pantalla el resultado calculado. Para ello se emplea un sencillo bucle for (líneas 11-13) que muestra los valores almacenados en el vector fact. Observe que para indicar el número del que se ha calculado el factorial, en cada iteración se emplea el valor contador i.

9.5. Introducir polinomio Escriba un programa que solicite al usuario los coeficientes (valores de tipo entero) de un polinomio de grado 5. El grado del polinomio se definirá mediante un valor constante. A continuación, el programa debe mostrar el polinomio por pantalla. A continuación, se muestran varios ejemplos de ejecución que ilustran el comportamiento esperado del programa: Ejemplo 1 de ejecución Introduzca el termino independiente: 3 Introduzca el coeficiente de x elevado a 1: 4 Introduzca el coeficiente de x elevado a 2: 5 Introduzca el coeficiente de x elevado a 3: 1 Introduzca el coeficiente de x elevado a 4: 4 Introduzca el coeficiente de x elevado a 5: 3 El polinomio es: 3 +4x^1 +5x^2 +1x^3 +4x^4 +3x^5

Page 183: INFORMÁTICA Libro de Problemas

184 | Informática. Libro de problemas

Ejemplo 2 de ejecución Introduzca el termino independiente: 4 Introduzca el coeficiente de x elevado a 1: 2 Introduzca el coeficiente de x elevado a 2: 0 Introduzca el coeficiente de x elevado a 3: 6 Introduzca el coeficiente de x elevado a 4: 0 Introduzca el coeficiente de x elevado a 5: 2 El polinomio es: 4 +2x^1 +6x^3 +2x^5

Ejemplo 3 de ejecución Introduzca el termino independiente: -3 Introduzca el coeficiente de x elevado a 1: 4 Introduzca el coeficiente de x elevado a 2: 2 Introduzca el coeficiente de x elevado a 3: -4 Introduzca el coeficiente de x elevado a 4: 0 Introduzca el coeficiente de x elevado a 5: -1 El polinomio es: -3 +4x^1 +2x^2 -4x^3 -1x^5

Ejemplo 4 de ejecución Introduzca el termino independiente: 0 Introduzca el coeficiente de x elevado a 1: 3 Introduzca el coeficiente de x elevado a 2: 2 Introduzca el coeficiente de x elevado a 3: -1 Introduzca el coeficiente de x elevado a 4: 2 Introduzca el coeficiente de x elevado a 5: 0 El polinomio es: +3x^1 +2x^2 -1x^3 +2x^4 Posible solución: Código 9.5

1. #include <stdio.h> 2. #define _N 5 3. int main(void) 4. { 5. int Pol[_N + 1]; 6. int i; 7. for(i = 0; i < _N + 1; i++) { 8. switch(i) { 9. case 0: 10. printf("\nIntroduzca el termino independiente: "); 11. break; 12. default: 13. printf("\nIntroduzca el coeficiente de x elevado a %d: ", i); 14. } 15. scanf(" %d", &Pol[i]); 16. } 17. printf("\n\nEl polinomio es:"); 18. for(i = 0; i < _N + 1; i++) {

Page 184: INFORMÁTICA Libro de Problemas

Capítulo 9: Arrays numéricos | 185

19. if(Pol[i] != 0) { // if(Pol[i]) 20. switch(i) { 21. case 0: 22. printf(" %d ", Pol[i]); 23. break; 24. default: 25. printf("%+dx^%d ", Pol[i], i); 26. } 27. } 28. } 29. printf("\n"); 30. return 0; 31. }

Comentarios:

• Un polinomio cualquiera se puede expresar como:

f (x)= ao + a1 x +…+ aN-1 xN-1 + aN xN

o Para resolver el ejercicio, debemos tener presente que el grado de un polinomio implica N coeficientes más un término independiente.

o Por ello, el vector numérico en el que guardaremos los coeficientes del polinomio debe de ser de dimensión N+1.

• En consecuencia, se declara un vector nombrado Pol de tipo entero (línea 5) y con dimensión _N+1, siendo _N una constante, que representa el grado del polinomio y que es definida mediante la directiva #define con valor de 5 (línea 2).

int Pol[_N + 1];

a0 a1 a2 a3 a4 a5 a6 ... aN-1 aN

Pol[0] Pol[1] Pol[2] Pol[3] Pol[4] Pol[5] Pol[6] Pol[N-1] Pol[N]

o A la hora de solicitar al usuario que introduzca los valores de los coeficientes, tendremos en cuenta que en la primera posición del array (en la posición 0) se guardará el término independiente. De esta manera, cuando se acceda al contenido de una posición del vector para recuperar un coeficiente determinado, el valor que tome la variable i se corresponderá con el valor que toma el exponente asociado a dicho coeficiente.

• Según lo indicando anteriormente, el primer bucle for (líneas 7-16) recoge los valores introducidos por el usuario y los almacena en el vector Pol. Observe que:

o La condición de parada del bucle i<_N+1 también se puede sustituir por i<=_N ya que el contador i comienza en 0.

o Se emplea una estructura switch (línea 8) para determinar el tipo de mensaje más apropiado. Concretamente, se distingue un mensaje para el término independiente (línea 10) y otro parametrizable para el resto de términos (línea 13).

Page 185: INFORMÁTICA Libro de Problemas

186 | Informática. Libro de problemas

o La llamada a la función scanf() (línea 15) para recoger el coeficiente por teclado siempre se ejecutará ya que está fuera del ámbito de acción del switch.

• Para imprimir el polinomio, debemos tener en cuenta si el usuario ha introducido un valor nulo para un coeficiente, ya que, en ese caso, no procede mostrar dicho coeficiente. Esta tarea se lleva a cabo por medio de un bucle for (líneas 18-28), donde observamos que:

o Para controlar que el coeficiente a imprimir no sea nulo, se emplea una estructura if (línea 19) que evalúa la condición Pol[i]!=0. Note que esta condición es equivalente a (Pol[i]).

o Para mostrar el polinomio de manera adecuada se emplea una estructura switch. Concretamente se tiene en cuenta si lo que se muestra por pantalla es el término independiente o no. Debido a que el término independiente se almacena en la primera posición (i=0) del vector, dentro de la estructura switch hacemos un tratamiento especial:

(1) Para case 0 (línea 21) sólo se imprime por pantalla el valor almacenado en la primera posición del vector.

(2) En caso contrario (default, línea 24), se imprimirá el valor del coeficiente con la incógnita x elevada al grado que corresponda. En este caso, observe que el especificador de formato empleado "%+dx^%d" en la llamada a printf() hace uso del símbolo "+" para solicitar que siempre se imprima el signo de los coeficientes, con independencia de que sean positivoso negativos.

9.6. Evaluar polinomio

Amplíe el programa realizado en el Ejercicio 9.3 para que se resuelva el polinomio introducido por el usuario para un valor de tipo real, que será proporcionado por el usuario. El resultado se mostrará por pantalla. Para clarificar como debería ser el comportamiento del programa, a continuación, se muestra un ejemplo de ejecución: Ejemplo de ejecución Introduzca el termino independiente: 4 Introduzca el coeficiente de x elevado a 1: 5 Introduzca el coeficiente de x elevado a 2: 0 Introduzca el coeficiente de x elevado a 3: 2 Introduzca el coeficiente de x elevado a 4: 1 Introduzca el coeficiente de x elevado a 5: 7 El polinomio es: 4 +5x^1 +2x^3 +1x^4 +7x^5 Introduzca un valor para x: 3.2 El resultado es: 2539.203840

Page 186: INFORMÁTICA Libro de Problemas

Capítulo 9: Arrays numéricos | 187

Posible solución:

Se resalta en color amarillo las nuevas líneas de código añadidas, tomando como base la solución propuesta para el Ejercicio 9.5.

Código 9.6

1. #include <math.h> 2. #include <stdio.h> 3. #define _N 5 4. int main(void) 5. { 6. int Pol[_N + 1]; 7. int i; 8. double x, valor = 0; 9. for(i = 0; i < _N + 1; i++) { 10. switch(i) { 11. case 0: 12. printf("\nIntroduzca el termino independiente: "); 13. break; 14. default: 15. printf("\nIntroduzca el coeficiente de x elevado a %d: ", i); 16. } 17. scanf(" %d", &Pol[i]); 18. } 19. printf("\n\nEl polinomio es:"); 20. for(i = 0; i < _N + 1; i++) { 21. if(Pol[i] != 0) { // if(Pol[i]) 22. switch(i) { 23. case 0: 24. printf(" %d ", Pol[i]); 25. break; 26. default: 27. printf("%+dx^%d ", Pol[i], i); 28. } 29. } 30. } 31. printf("\n\nIntroduzca un valor para x: "); 32. scanf(" %lf", &x); 33. for(i = 0; i < _N + 1; i++) { 34. valor += Pol[i] * pow(x, i); // valor=valor+Pol[i]*pow(x,i); 35. } 36. printf("El resultado es: %lf\n", valor); 37. return 0; 38. }

Comentarios:

• Para evaluar el polinomio, se declara una variable de tipo double nombrada como valor, en la que se guardará el resultado de evaluar el polinomio para el valor indicado por el usuario.

Page 187: INFORMÁTICA Libro de Problemas

188 | Informática. Libro de problemas

• Mediante una estructura for (líneas 33-35) se recorre cada posición del vector Pol y se va realizando la siguiente operación:

valor += Pol[i] * pow(x, i);

En cada iteración, la expresión Pol[i]*pow(x,i) resuelve un término de la ecuación, donde:

o Pol[i] es el coeficiente del término i-ésimo de la ecuación.

o Pow(x,i) es una función de la librería <math.h> devuelve el resultado de la potencia xi, donde i es el grado y x el valor indicado por el usuario para resolver la ecuación.

• Por último, se imprime el resultado (línea 36) que se encuentra almacenado en la variable valor.

9.7. Derivar polinomio

Amplíe el programa realizado en el Ejercicio 9.3 de forma que el programa calcule el polinomio resultante de derivar el polinomio introducido. A continuación, se muestran un par de ejemplos de ejecución para clarificar como debería ser el comportamiento del programa: Ejemplo de ejecución Introduzca el termino independiente: 3 Introduzca el coeficiente de x elevado a 1: 5 Introduzca el coeficiente de x elevado a 2: 6 Introduzca el coeficiente de x elevado a 3: 1 Introduzca el coeficiente de x elevado a 4: 2 Introduzca el coeficiente de x elevado a 5: 6 El polinomio es: 3 +5x^1 +6x^2 +1x^3 +2x^4 +6x^5 El polinomio derivado es:5+12x^1+3x^2+8x^3+30x^4

Ejemplo de ejecución Introduzca el termino independiente: 0 Introduzca el coeficiente de x elevado a 1: -3 Introduzca el coeficiente de x elevado a 2: -2 Introduzca el coeficiente de x elevado a 3: 5 Introduzca el coeficiente de x elevado a 4: 6 Introduzca el coeficiente de x elevado a 5: 0 El polinomio es: -3x^1 -2x^2 +5x^3 +6x^4 El polinomio derivado es: -3-4x^1+15x^2+24x^3

Page 188: INFORMÁTICA Libro de Problemas

Capítulo 9: Arrays numéricos | 189

Posible solución:

Se resalta en color amarillo las nuevas líneas de código añadidas, tomando como base la solución propuesta para el Ejercicio 9.5. Código 9.7

1. #include <stdio.h> 2. #define _N 5 3. int main(void) 4. { 5. int Pol[_N + 1]; 6. int PolDer[_N]; 7. int i; 8. 9. for(i = 0; i < _N + 1; i++) { 10. switch(i) { 11. case 0: 12. printf("\nIntroduzca el termino independiente: "); 13. break; 14. default: 15. printf("\nIntroduzca el coeficiente de x elevado a %d: ", i); 16. } 17. scanf(" %d", &Pol[i]); 18. } 19. printf("\n\nEl polinomio es:"); 20. for(i = 0; i < _N + 1; i++) { 21. if(Pol[i] != 0) { // if(Pol[i]) 22. switch(i) { 23. case 0: 24. printf(" %d ", Pol[i]); 25. break; 26. default: 27. printf("%+dx^%d ", Pol[i], i); 28. } 29. } 30. } 31. for(i = 0; i < _N; i++) { 32. PolDer[i] = (i + 1) * Pol[i + 1]; 33. } 34. printf("\n\nEl polinomio derivado es:"); 35. for(i = 0; i < _N; i++) { 36. if(PolDer[i] != 0) { 37. switch(i) { 38. case 0: 39. printf("%d", PolDer[i]); 40. break; 41. default: 42. printf("%+dx^%d", PolDer[i], i); 43. } 44. } 45. } 46. printf("\n\n"); 47. return 0; 48. } 49.

Page 189: INFORMÁTICA Libro de Problemas

190 | Informática. Libro de problemas

Comentarios:

• Para resolver este ejemplo hay que tener en cuenta que la derivada f ’(x) de un polinomio f(x) se calcula como:

f (x)= ao + a1 x +…+ aN-1 xN-1 + aN xN

f ’(x)= a1 + 2*a2 x +…+ (N-1)*aN-1 xN-2 + N*aN xN-1

• A priori, vamos a necesitar otro vector donde guardar los coeficientes solución de la derivada. Este vector se ha declarado (línea 6) con el nombre PolDer, del mismo tipo que Pol pero con dimensión _N ya que la derivada del termino independiente es cero y no se muestra.

• El cálculo de la derivada se lleva a cabo mediante un bucle for (líneas 31-33) de la siguiente manera:

o La condición de parada del bucle es i<_N, por tanto, lo que se ajusta a la dimensión del vector PolDer.

o En cada iteración se guarda en la posición actual (indicada por la variable i) del vector PolDer el resultado de multiplicar i+1 por el coeficiente que tenga guardado el vector Pol en una posición posterior. En otras palabras, en cada posición del vector PolDer se almacena el nuevo coeficiente resultado de la derivada:

i=0 PolDer[0]= 1*Pol[1] a1 i=1 PolDer[1]= 2*Pol[2] 2*a2 i=2 PolDer[2]= 3*Pol[3] 3*a3 a1 + 2*a2 x + 3*a3 x2 + 4*a4 x3 + 5*a5 x4

i=3 PolDer[3]= 4*Pol[4] 4*a4 i=4 PolDer[4]= 5*Pol[5] 5*a5

• Otra forma equivalente de implementar la derivada podría ser la siguiente: for(i = 1; i < _N + 1; i++) { PolDer[i - 1] = i * Pol[i]; }

o En relación a la definición del bucle for, la variable i se inicializa a 1, por lo que la condición de parada debe ser i<_N+1.

o Para acceder, en cada iteración, a la posición correcta del vector PolDer se debe restar 1 a la variable i. Del mismo modo, el coeficiente derivado viene dado por la multiplicación del grado por el valor que contenga la posición en ese momento Pol.

Page 190: INFORMÁTICA Libro de Problemas

Capítulo 9: Arrays numéricos | 191

9.8. Suma matrices

Escriba un programa que muestre por pantalla la suma de dos matrices cuadradas de dimensión 3. Los valores de las matrices serán de tipo entero corte y se inicializan de manera estática dentro del propio programa, es decir, no se solicita al usuario que los introduzca. A continuación, se muestra un ejemplo de ejecución del programa: Ejemplo de ejecución La suma de esta matriz 1 2 3 2 2 2 3 2 1 y de esta matriz.... 1 2 3 2 2 2 3 2 1 es.... 2 3 4 4 4 4 6 5 4 Posible solución: Código 9.8

1. #include <stdio.h> 2. #define _N 3 3. int main(void) 4. { 5. short A[_N][_N] = { { 1, 2, 3 }, { 2, 2, 2 }, { 3, 2, 1 } }; 6. short B[_N][_N] = { { 1, 1, 1 }, { 2, 2, 2 }, { 3, 3, 3 } }; 7. short C[_N][_N]; 8. short i, j; 9. printf("La suma de esta matriz\n"); 10. for(i = 0; i < _N; i++) { 11. for(j = 0; j < _N; j++) 12. printf("%hd\t", A[i][j]); 13. printf("\n"); 14. } 15. printf("\n y de esta matriz....\n"); 16. for(i = 0; i < _N; i++) { 17. for(j = 0; j < _N; j++) 18. printf("%hd\t", A[i][j]); 19. printf("\n"); 20. } 21. printf("\n es....\n"); 22. for(i = 0; i < _N; i++) { 23. for(j = 0; j < _N; j++) { 24. C[i][j] = A[i][j] + B[i][j];

Page 191: INFORMÁTICA Libro de Problemas

192 | Informática. Libro de problemas

25. } 26. } 27. for(i = 0; i < _N; i++) { 28. for(j = 0; j < _N; j++) 29. printf("%hd\t", C[i][j]); 30. printf("\n"); 31. } 32. printf("\n"); 33. return 0; 34. }

Comentarios:

• En este ejemplo se declaran tres matrices nombradas como A, B y C, de tipo short y de dimensión 3. Dicha dimensión viene definida por una constante _N declarada por medio de la directiva #define (línea 2).

• Las dos primeras matrices se inicializan (líneas 5-7) con valores cualesquiera. Fíjese que para inicializar una matriz se ponen entre llaves las filas, las cuales van separadas por comas y, a su vez, los elementos de la fila separados por comas también.

• Para mostrar por pantalla el contenido de una matriz se hace uso de dos bucles for anidados con el objetivo de recorrer todas las posiciones. Un bucle for recorre las filas mientras que el otro las columnas. Veamos, por ejemplo, cómo se recorre la matriz A (líneas 10-14). Con el fin de que la explicación sea más comprensible, se identifica al primer for con la etiqueta de for_filas y al segundo con for_columnas, según se muestra a continuación:

for(i = 0; i < _N; i++) { for_filas for(j = 0; j < _N; j++) for_columnas

printf("%hd\t", A[i][j]); printf("\n"); }

(1) Comienza la ejecución del bucle for_filas. En la primera iteración, la variable i toma el valor 0 (i=0), con el objetivo de imprimir la primera fila de la matriz. Realmente la impresión por pantalla la llevará a cabo la ejecución del bucle for_columnas, tal y como se describe en el siguiente paso.

(2) Comienza la ejecución del bucle for_columnas. En la primera iteración, la variable j adopta el valor 0 (j=0), por lo que se la ejecución del printf() hará que se muestre el elemento de la matriz ubicado en la fila 0 y columna 0. En la siguiente iteración del for_columnas, la variable j adopta el valor 1 (j=1), por lo que se la ejecución del printf() hará que se muestre el elemento de la matriz ubicado en la fila 0 y columna 1. Note que en la llamada a printf() se emplea el carácter de control \t para separar los valores.

(3) En definitiva, la ejecución de todas las iteraciones del bucle for_columnas tiene como efecto imprimir todos los valores de la matriz ubicados en la primera fila (i=0). Visualmente, se imprimirá la primera fila (color azul):

Page 192: INFORMÁTICA Libro de Problemas

Capítulo 9: Arrays numéricos | 193

2 3 4 4 4 4 6 5 4

(4) Cuando finaliza la ejecución del bucle for_columnas, se imprime un salto de línea gracias a la llamada printf("\n"). Con esto se consigue que la próxima impresión por pantalla (de la siguiente fila de la matriz) se realice en una nueva línea. Una vez hecho esto, finaliza la primera iteración del bucle for_filas.

(5) Se ejecuta la instrucción de incremento asociada al bucle for_filas, por lo que ahora i adopta el valor 1 (i=1). Seguidamente comprueba la condición de permanencia del bucle (i<_N), la cual se cumple. Comienza la segunda iteración del bucle for_filas, con el objetivo de imprimir la segunda fila de la matriz (i=1).

(6) Comienza una nueva ejecución del bucle for_columnas. Se sigue el mismo procedimiento explicado en los pasos (2) y (3), resultando la impresión de todos los valores de la matriz ubicados en la segunda fila (i=1). Visualmente, se imprimirá la segunda fila (color verde):

2 3 4 4 4 4 6 5 4

(7) Finaliza la ejecución del bucle for_columnas y, a continuación, se imprime un salto de línea gracias a la llamada printf("\n"). Con esto se consigue que se imprima la siguiente fila de la matriz en una nueva línea. Una vez hecho esto, finaliza la primera iteración del bucle for_filas.

(8) Se ejecuta la instrucción de incremento asociada al bucle for_filas, por lo que ahora i adopta el valor 2 (i=2). Seguidamente comprueba la condición de permanencia del bucle (i<_N), la cual se cumple. Comienza la tercera iteración del bucle for_filas, con el objetivo de imprimir la tercera fila de la matriz (i=2).

(9) Comienza una nueva ejecución del bucle for_columnas. Se sigue el mismo procedimiento explicado en los pasos (2) y (3), resultando la impresión de todos los valores de la matriz ubicados en la tercera fila (i=2). Visualmente, se imprimirá la tercera fila (color amarillo):

2 3 4 4 4 4 6 5 4

(10) Cuando finaliza la ejecución del bucle for_columnas, se imprime un salto de línea gracias a la llamada printf("\n"). Una vez hecho esto, finaliza la primera iteración del bucle for_filas.

Page 193: INFORMÁTICA Libro de Problemas

194 | Informática. Libro de problemas

(11) Se ejecuta la instrucción de incremento asociada al bucle for_filas, por lo que ahora i adopta el valor 3 (i=3). Seguidamente se comprueba la condición de permanencia del bucle (i<_N), la cual ahora no se cumple. Por lo tanto, finaliza la ejecución del bucle for_filas.

• Para sumar las matrices A y B, se deben recorrer todas las posiciones de ambas matrices. Es decir, nuevamente se necesitan dos bucles for anidados (líneas 22-26) con dos índices o contadores, uno para las filas (en este ejemplo, el contador i) y otro para las columnas (en este ejemplo, el contador j). Para cada posición de la matriz C (donde se va a guardar el resultado) se almacena la suma de los dos valores que contenga A y B en esa misma posición:

C[i][j] = A[i][j] + B[i][j];

9.9. Identidad triangular

Escriba un programa que asigne a dos matrices cuadradas de dimensión 5 el valor de la matriz identidad y el valor de una matriz triangular superior utilizando estructuras de repetición. Para llevar a cabo la inicialización de ambas matrices no se puede hacer asignación directa. El programa deberá mostrar por pantalla las dos matrices resultantes. A continuación, se muestra un ejemplo de ejecución para clarificar como debería ser el comportamiento del programa: Ejemplo de ejecución La matriz Identidad es: 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 La matriz Triangular Superior es: 1 1 1 1 1 0 1 1 1 1 0 0 1 1 1 0 0 0 1 1 0 0 0 0 1

Page 194: INFORMÁTICA Libro de Problemas

Capítulo 9: Arrays numéricos | 195

Posible solución: Código 9.9

1. #include <stdio.h> 2. #define D 5 3. int main(void) 4. { 5. short M_I[D][D]; 6. short M_T[D][D]; 7. short i, j; 8. 9. // Matriz Identidad 10. for(i = 0; i < D; i++) { 11. for(j = 0; j < D; j++) { 12. if(i == j) 13. M_I[i][j] = 1; // M[i][j]=i==j?1:0; 14. else 15. M_I[i][j] = 0; 16. } 17. } 18. 19. // Matriz Triangular Superior 20. for(i = 0; i < D; i++) { 21. for(j = 0; j < D; j++) { 22. if(i <= j) 23. M_T[i][j] = 1; // M[i][j]=i<=j?1:0; 24. else 25. M_T[i][j] = 0; 26. } 27. } 28. 29. printf("La matriz Identidad es:\n"); 30. for(i = 0; i < D; i++) { 31. for(j = 0; j < D; j++) { 32. printf("%hd\t", M_I[i][j]); 33. } 34. printf("\n"); 35. } 36. 37. printf("\nLa matriz Triangular Superior es:\n"); 38. for(i = 0; i < D; i++) { 39. for(j = 0; j < D; j++) { 40. printf("%hd\t", M_T[i][j]); 41. } 42. printf("\n"); 43. } 44. return 0; 45. }

Page 195: INFORMÁTICA Libro de Problemas

196 | Informática. Libro de problemas

Comentarios:

• Para resolver este ejercicio debemos llevar a cabo un análisis previo:

o Dada una matriz cuadrada 3x3, la matriz identidad sería la siguiente:

o Dada una matriz cuadrada 3x3, la matriz triangular superior sería la siguiente:

o Seguidamente es importante que nos detengamos a analizar cada matriz y

observar los índices i y j:

o Para implementar mediante una estructura de repetición la matriz identidad,

observamos que tendríamos que asignar el valor 1 a las posiciones de la matriz que tengan el mismo valor de índice, es decir, las posiciones de la matriz correspondientes a i=j=0, i=j=1 e i=j=2. Las restantes posiciones de la matriz valdrán 0.

o Para el caso de la matriz triangular superior, observamos que en aquellas posiciones para las que el índice i sea menor o igual que el índice j, los valores de esas posiciones de la matriz son 1. Para posiciones con índices i mayores estrictos que j, los valores son 0.

• Una vez hemos identificado el comportamiento que debemos seguir para inicializar cada tipo de matriz con los valores adecuados, podemos resolver el caso de la matriz identidad de una manera sencilla mediante el siguiente código (líneas 10-16):

for(i = 0; i < D; i++) { for(j = 0; j < D; j++) { if(i == j) M_I[i][j] = 1;

Page 196: INFORMÁTICA Libro de Problemas

Capítulo 9: Arrays numéricos | 197

else M_I[i][j] = 0; }

}

o Como se observa, se utilizan dos bucles for para recorrer las posiciones de la matriz. El índice i recorrerá las filas mientras que el índice j las columnas. Mediante una estructura if-else se va evaluando si el valor de los índices i y j es el mismo o no. Si es igual, a esa posición de la matriz se le asigna el valor de 1, en caso contrario, se asigna el valor de 0.

o A continuación, le vamos a presentar una solución bastante más elegante donde la estructura if-else se sustituye por el uso del operador ?:

for(i = 0; i < D; i++) { for(j = 0; j < D; j++) { M_I[i][j] = i == j ? 1 : 0; } }

o En la instrucción M_I[i][j] = i == j ? 1 : 0 se asigna el resultado que proporciona el operador ?. Dicho operador evalúa la condición que hay antes de dicho operador. Si esa condición es verdadera, devuelve el valor 1 (el valor que está antes de los :) y, si es falsa, se devuelve el valor 0. Lo que devuelva el operador ? se asignará a la posición correspondiente de la matriz M_I.

• Para resolver el caso de la matriz triangular superior, el código que se propone es el siguiente:

for(i = 0; i < D; i++) { for(j = 0; j < D; j++) { if(i <= j) M_T[i][j] = 1; else M_T[i][j] = 0; } }

o En este caso, al igual que el anterior, mediante una estructura if-else se comprueba si el índice i es menor o igual que j. Si ese caso es verdadero, se asignará a esa posición de M_T el valor de 1, en caso contrario, se asignará un 0.

o Al igual que en el caso anterior, se podría plantear una solución más elegante empleando el operador ?. La solución quedaría como sigue:

for(i = 0; i < D; i++) { for(j = 0; j < D; j++) { M_T[i][j] = i <= j ? 1 : 0; } }

Page 197: INFORMÁTICA Libro de Problemas

198 | Informática. Libro de problemas

9.10. Matriz 01

Desarrolle un programa que asigne valores a una matriz cuadrada de dimensión _D, utilizando estructuras de repetición (no se puede hacer asignación directa), de la siguiente forma:

A continuación, se muestra un ejemplo de ejecución para clarificar como debería ser el comportamiento del programa: Ejemplo de ejecución 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 Posible solución: Código 9.10

1. #include <stdio.h> 2. #define D 5 3. int main(void) 4. { 5. short M[D][D]; 6. short i, j; 7. for(i = 0; i < D; i++) { 8. for(j = 0; j < D; j++) { 9. if((i + j) % 2 == 0) 10. M[i][j] = 0; 11. else 12. M[i][j] = 1; 13. } 14. } 15. for(i = 0; i < D; i++) { 16. for(j = 0; j < D; j++) { 17. printf("%hd\t", M[i][j]); 18. } 19. printf("\n"); 20. } 21. printf("\n"); 22. return 0; 23. }

Page 198: INFORMÁTICA Libro de Problemas

Capítulo 9: Arrays numéricos | 199

Comentarios:

• Para resolver este ejercicio, de nuevo, es necesario realizar un análisis previo que nos ayude a determinar qué condición debe cumplirse para discernir el valor correcto que debe asignarse a cada posición de la matriz. Concretamente, debemos poner atención en los valores de los índices i y j para cada valor de la matriz.

• Para las posiciones de la matriz donde hay un valor de 1, observe que se cumple que la suma de los índices i y j es un número impar. Por el contrario, para aquellas posiciones inicializadas a 0 dicha suma será un valor par. Para que se aprecie mejor este comportamiento, vea la siguiente figura donde:

o En rojo se indican los valores que toma el índice i (filas).

o En verde se indican los valores que toma el índice j (columnas).

o En azul se indica para cada posición el valor resultado de sumar los índices (i+j).

Puede ver cómo se ha implementado en las líneas 7-14 del Código 9.10.

9.11. Suma elementos matriz

Escriba un programa que calcule la suma de todos los elementos de una matriz. Dicha matriz debe ser inicializada a partir de los valores (enteros cortos) proporcionados por el usuario. A continuación, se muestran varios ejemplos de ejecución que ilustran el comportamiento esperado del programa: Ejemplo 1 de ejecución Introduzca elemento de la fila 0 y la columna 0: 4 Introduzca elemento de la fila 0 y la columna 1: 5 Introduzca elemento de la fila 0 y la columna 2: 6 Introduzca elemento de la fila 1 y la columna 0: 1 Introduzca elemento de la fila 1 y la columna 1: 2 Introduzca elemento de la fila 1 y la columna 2: 8 Introduzca elemento de la fila 2 y la columna 0: 6 Introduzca elemento de la fila 2 y la columna 1: 4 Introduzca elemento de la fila 2 y la columna 2: 3 La matriz introducida es

Page 199: INFORMÁTICA Libro de Problemas

200 | Informática. Libro de problemas

4 5 6 1 2 8 6 4 3 La suma de sus elementos es: 39

Ejemplo 2 de ejecución Introduzca elemento de la fila 0 y la columna 0: -2 Introduzca elemento de la fila 0 y la columna 1: 3 Introduzca elemento de la fila 0 y la columna 2: -5 Introduzca elemento de la fila 1 y la columna 0: 0 Introduzca elemento de la fila 1 y la columna 1: 3 Introduzca elemento de la fila 1 y la columna 2: 9 Introduzca elemento de la fila 2 y la columna 0: -4 Introduzca elemento de la fila 2 y la columna 1: 2 Introduzca elemento de la fila 2 y la columna 2: 8 La matriz introducida es -2 3 -5 0 3 9 -4 2 8 La suma de sus elementos es: 14

Ejemplo 3 de ejecución Introduzca elemento de la fila 0 y la columna 0: 22 Introduzca elemento de la fila 0 y la columna 1: 9 Introduzca elemento de la fila 0 y la columna 2: 45 Introduzca elemento de la fila 1 y la columna 0: 2 Introduzca elemento de la fila 1 y la columna 1: -3 Introduzca elemento de la fila 1 y la columna 2: -19 Introduzca elemento de la fila 2 y la columna 0: 2 Introduzca elemento de la fila 2 y la columna 1: 0 Introduzca elemento de la fila 2 y la columna 2: 4 La matriz introducida es 22 9 45 2 -3 -19 2 0 4 La suma de sus elementos es: 62

Posible solución: Código 9.11

1. #include <stdio.h> 2. #define _F 3 3. #define _C 3 4. int main(void) 5. { 6. short m[_F][_C]; 7. short i, j;

Page 200: INFORMÁTICA Libro de Problemas

Capítulo 9: Arrays numéricos | 201

8. long suma = 0; 9. for(i = 0; i < _F; i++) { 10. for(j = 0; j < _C; j++) { 11. printf("Introduzca elemento de la fila %hd y la columna %hd: ", i, j); 12. scanf(" %hd", &m[i][j]); 13. suma += m[i][j]; // suma=suma+m[i][j]; 14. } 15. } 16. printf("\nLa matriz introducida es\n"); 17. for(i = 0; i < _F; i++) { 18. for(j = 0; j < _C; j++) { 19. printf("%hd\t", m[i][j]); 20. } 21. printf("\n"); 22. } 23. printf("\nLa suma de sus elementos es: %ld \n", suma); 24. return 0; 25. }

Comentarios:

• Como el enunciado del ejercicio no especifica que esta matriz deba ser cuadrada, se definen (líneas 2-3) dos valores constantes distintos por medio de la directiva define (_F y _C) para indicar la dimensión de las filas y las columnas, respectivamente.

• Se declara una matriz nombrada m y de tipo short (línea 6) con dimensión para las filas indicada por la constante _F y para las columnas por la constante _C.

• Para que el usuario introduzca los valores a la matriz, observe como se utilizan dos bucles for anidados (líneas 9-10). Para cada posición de la matriz, mediante la función printf() se le solicita al usuario (línea 11) que introduzca el elemento que corresponda. Fíjese que, para indicar al usuario el elemento de la matriz que se está solicitando, se utilizan los valores de los índices i y j.

• Después, mediante scanf(), se van almacenando esos valores (línea 12) en la posición que corresponda de la matriz m. Recuerde que la posición viene siempre indicada por los índices i y j.

• A la misma vez que se van solicitando los valores al usuario para inicializar la matriz, se realiza la suma de los elementos en una variable de tipo long nombrada como suma. La suma se realiza de manera acumulativa iteración a iteración (línea 13) por medio de la siguiente instrucción:

suma += m[i][j];

Page 201: INFORMÁTICA Libro de Problemas

202 | Informática. Libro de problemas

9.12. Suma positivos pares

En este ejercicio, se pide que se amplíe el Ejercicio 9.11 teniendo en cuenta dos consideraciones:

1) Que el programa controle que todos los datos que introduce el usuario son mayores que cero.

2) Que sume los valores pares que se encuentren almacenados en la matriz. A continuación, se muestra un ejemplo de ejecución para clarificar como debería ser el comportamiento del programa: Ejemplo de ejecución Introduzca elemento de la fila 0 y la columna 0: 1 Introduzca elemento de la fila 0 y la columna 1: -4 Introduzca elemento de la fila 0 y la columna 1: -2 Introduzca elemento de la fila 0 y la columna 1: 5 Introduzca elemento de la fila 0 y la columna 2: 2 Introduzca elemento de la fila 1 y la columna 0: 7 Introduzca elemento de la fila 1 y la columna 1: 8 Introduzca elemento de la fila 1 y la columna 2: 0 Introduzca elemento de la fila 1 y la columna 2: 4 La matriz introducida es 1 5 2 7 8 4 La suma de los valores pares es: 14

Posible solución: Se resalta en color amarillo los cambios introducidos con respecto al Ejercicio 9.11. Código 9.12

1. #include <stdio.h> 2. #define _F 2 3. #define _C 3 4. int main(void) 5. { 6. short m[_F][_C]; 7. short i, j; 8. long suma = 0; 9. for(i = 0; i < _F; i++) { 10. for(j = 0; j < _C; j++) { 11. do { 12. printf("Introduzca elemento de la fila %hd y la columna %hd: ", i,j); 13. scanf(" %hd", &m[i][j]); 14. } while(m[i][j] <= 0);

Page 202: INFORMÁTICA Libro de Problemas

Capítulo 9: Arrays numéricos | 203

15. 16. if(m[i][j] % 2 == 0) 17. suma += m[i][j]; // suma=suma+m[i][j]; 18. } 19. } 20. printf("\nLa matriz introducida es\n"); 21. for(i = 0; i < _F; i++) { 22. for(j = 0; j < _C; j++) { 23. printf("%hd\t", m[i][j]); 24. } 25. printf("\n"); 26. } 27. printf("\nLa suma de los valores pares es: %ld \n", suma); 28. return 0; 29. }

Comentarios:

• Para satisfacer el primer requisito que se nos pide, se emplea una estructura do-while líneas 11-14. De este modo, cuando el usuario introduce un valor negativo o un valor nulo, se le vuelve a solicitar que introduzca un valor para la misma posición.

• Con respecto al segundo requisito, se introduce una estructura if (líneas 16-17) mediante la cual se garantiza que sólo se realizará la suma si el valor que se acaba de recoger por pantalla del usuario (almacenado en m[i][j]) es un número par. Note que, si es un número impar, ejecutará la siguiente iteración del bucle for.

Page 203: INFORMÁTICA Libro de Problemas
Page 204: INFORMÁTICA Libro de Problemas

10

CARACTERES Y CADENAS DE CARACTERES

Page 205: INFORMÁTICA Libro de Problemas
Page 206: INFORMÁTICA Libro de Problemas

Capítulo 10: Caracteres y cadenas de caracteres | 207

10.1. Tipos de caracteres

Escriba un programa que muestre el número de letras, de dígitos, de signos de puntuación y de espacios que el usuario introduce. El programa dejará de solicitar caracteres al usuario cuando este introduzca el carácter '@', que también deberá ser procesado para el recuento que realiza el programa.

A continuación, se muestran un par de ejemplos de ejecución que ilustran el comportamiento esperado del programa: Ejemplo 1 de ejecución Introduce caracteres (termina con una @) 4 w . o R 2 - @ Has introducido 2 letras Has introducido 2 digitos Has introducido 3 signos de puntuacion Has introducido 2 espacios

Ejemplo 2 de ejecución Introduce caracteres (termina con una @) a , % D @ Has introducido 2 letras Has introducido 0 digitos Has introducido 3 signos de puntuacion Has introducido 0 espacios

Page 207: INFORMÁTICA Libro de Problemas

208 | Informática. Libro de problemas

Posible solución: Código 10.1

1. #include <ctype.h> 2. #include <stdio.h> 3. int main(void) 4. { 5. char ch; 6. printf("Introduce caracteres (termina con una @)\n\n"); 7. short cL, cD, cS, cE; 8. cL = cD = cS = cE = 0; 9. do { 10. fflush(stdin); 11. ch = getchar(); 12. 13. if(isalpha(ch) != 0) 14. cL++; 15. else if(isdigit(ch) != 0) 16. cD++; 17. else if(ispunct(ch) != 0) 18. cS++; 19. else if(isspace(ch) != 0) 20. cE++; 21. 22. } while(ch != '@'); 23. printf("\nHas introducido %hd letras", cL); 24. printf("\nHas introducido %hd digitos", cD); 25. printf("\nHas introducido %hd signos de puntuacion", cS); 26. printf("\nHas introducido %hd espacios\n", cE); 27. 28. return 0; 29. }

Comentarios:

• De acuerdo con las indicaciones del enunciado, el programa debe evaluar carácter a carácter, es decir, solicitar al usuario que introduzca un carácter. El tratamiento que debe realizar el programa para cada carácter consiste en contabilizarlo de manera adecuada según sea una letra, digito, signo de puntuación o espacio. Esta tarea se repetirá siempre que el carácter que se acaba de procesar sea distinto de '@'. En caso contrario, el programa finalizará.

• Para desarrollar este programa, bastará con emplear una variable de tipo char. No es necesario recurrir al uso de una cadena.

• Según lo indicado en el punto anterior, el programa propuesto declara la variable ch de tipo char para guardar el carácter que introduce el usuario. Además, se declaran e inicializan a 0 (línea 8) cuatro variables de tipo short nombradas como cL, cD, cS y cE, que se emplearán para contar el número de letras, números, signos de puntuación y espacios que el usuario ha introducido, respectivamente.

Page 208: INFORMÁTICA Libro de Problemas

Capítulo 10: Caracteres y cadenas de caracteres | 209

• El funcionamiento iterativo del programa (solicitar carácter + procesarlo) se controlará mediante una estructura tipo do-while (líneas 9-22). Optar por una estructura do-while es una elección acertada pues así nos aseguramos de que se va a ejecutar al menos una primera iteración.

- Como se puede observar, antes de usar la función getchar(), para guardar el carácter que introduce el usuario en la variable ch, se invoca la función fflush() para limpiar el buffer (línea 10).

- Note que, como alternativa a la función getchar(), también puede utilizar la función scanf() para leer un carácter de teclado: scanf("%c", &ch);

- Para evaluar qué tipo de carácter hay en ch, utilizamos la estructura if-else if- else (líneas 13-20) donde se identifica la variable contador que se debe incrementar Concretamente, el código propuesto es el siguiente:

if(isalpha(ch) != 0) Función isalpha() devuelve un valor numérico distinto de cero (verdad) si ch es una letra.

cL++; Si es este caso, entonces el contador de letras se incrementará.

else if(isdigit(ch) != 0) Función isdigit() devuelve un valor numérico distinto de cero (verdad) si ch es un número.

cD++; Entonces el contador de números se incrementará.

else if(ispunct(ch) != 0) Función ispunct() devuelve un valor numérico distinto de cero (verdad) si ch es un signo de puntuación.

cS++; Entonces el contador de signos de puntuación se incrementará.

else if(isspace(ch) != 0) Función isspace() devuelve un valor numérico distinto de cero (verdad) si ch es un signo de puntuación.

cE++; Entonces el contador de espacios se incrementará. } while(ch != '@');

- Esta estructura se repetirá hasta que la condición del while no se cumpla. Como se puede observar, dicha condición es ch!='@', es decir, mientras que el valor contenido en la variable ch sea distinto de '@', se volverán a ejecutar las instrucciones de esta estructura.

• Por último, se muestra por pantalla (líneas 23-26) el contenido de las variables contador, atendiendo a las indicaciones del enunciado de este problema.

Page 209: INFORMÁTICA Libro de Problemas

210 | Informática. Libro de problemas

10.2. Número a carácter

Escriba un programa que indique si un número introducido por el usuario (comprendido entre 0 y 9) es divisible por 4. Asuma que el usuario siempre respetará esta restricción, por lo que no es necesario que el programa verifique que se cumple. El valor que introduce el usuario deberá ser almacenado obligatoriamente en una variable de tipo char. A continuación, se muestran un par de ejemplos de ejecución que ilustran el comportamiento esperado del programa: Ejemplo 1 de ejecución Introduce un digito entre 0 y 9 5 NO es divisible entre 4

Ejemplo 2 de ejecución Introduce un digito entre 0 y 9 8 Es divisible entre 4 Posible solución: Código 10.2

1. #include <stdio.h> 2. int main(void) 3. { 4. char ch; 5. short num; 6. printf("Introduce un digito entre 0 y 9\n"); 7. fflush(stdin); 8. ch = getchar(); 9. num = ch - '0'; 10. if(num % 4 == 0) 11. printf("Es divisible entre 4\n"); 12. else 13. printf("NO es divisible entre 4\n"); 14. return 0; 15. }

Page 210: INFORMÁTICA Libro de Problemas

Capítulo 10: Caracteres y cadenas de caracteres | 211

Comentarios:

• En este ejercicio se pretende que el alumno conozca la forma de convertir un carácter de tipo dígito a un número entero para, posteriormente, poder realizar operaciones aritméticas.

• Una vez que tenemos en ch el carácter de tipo dígito que ha introducido el usuario gracias al uso de getchar() (línea 8), en la variable de tipo entero corto num guardamos el resultado de la operación ch-'0' (línea 9).

o Esta operación devolverá el valor numérico al que corresponde el carácter de tipo dígito. Para comprender el sentido de esta instrucción, debemos tener en cuenta los siguientes aspectos:

1. El contenido en memoria de una variable char es un valor numérico binario.

2. La tabla ASCII nos indica el valor numérico que se empleará para almacenar en memoria un carácter. Es decir, por ejemplo, en memoria no se almacena el carácter % sino el valor binario equivalente el número 37 en decimal.

3. Una operación aritmética (suma, resta, división, etc.) entre dos variables de tipo char se realiza empleando el valor numérico en memoria de cada variable.

o Teniendo en cuenta lo anterior, si nos fijamos en la tabla ASCII, observamos que los caracteres desde el '0' al '9' tienen asignados una codificación numérica consecutiva, concretamente la comprendida en el intervalo [48,57].

o Es por ello que, si al carácter que introduce el usuario le restamos el carácter '0', el

resultado de esa resta será el número decimal al que equivale el carácter de tipo dígito. Es decir, al carácter '0' le corresponde el valor numérico 0, al carácter '1' le corresponde el carácter '1', y así sucesivamente. Por ejemplo, si el usuario introduce el carácter '5', que es de tipo dígito, entonces:

num = ch - '0' num = 53 – 48 num = 5

• Por último, después de tener en la variable num el dígito convertido a número, se evalúa mediante una estructura if-else (líneas 10-13) el resultado de la operación num%4. Si la operación devuelve 0, entonces el programa indicará por pantalla que dicho número es divisible entre 4 (línea 11). En caso contrario, se indicará que no es divisible (línea 13).

Page 211: INFORMÁTICA Libro de Problemas

212 | Informática. Libro de problemas

10.3. Leer cadenas

Este ejercicio presenta de forma guiada las distintas funciones que existen en C para leer texto por teclado. Primero, se verá la función scanf(), después gets() y, finalmente, fgets(). >> Uso de la función scanf() Vamos a partir del código que se muestra a continuación: Código 10.3.1

1. #include <stdio.h> 2. #define _MAX 50 3. int main(void) 4. { 5. char a[_MAX], b[_MAX]; 6. printf("\nIntroduce cadena de texto "); 7. scanf(" %s", a); 8. printf("\nLa cadena guardada por scanf es %s \n", a); 9. return 0; 10. }

En este código se declaran dos vectores (a y b) de tipo char (línea 5) cuya dimensión viene determinada por el valor constante _MAX definida mediante la directiva #define (línea 2). Seguidamente, haciendo uso de scanf() (línea 7), se almacena la frase que introduce el usuario en la variable a. Note cómo ahora en la invocación a scanf(), el segundo parámetro no lleva el operador & ya que para cadenas no es necesario.

A la vista de este programa, ¿qué guarda exactamente la función scanf()?. Veamos un par de ejemplos de ejecución:

Ejemplo 1 de ejecución Introduce cadena de texto Supercalifragilisticoespialidoso La cadena guardada por scanf es Supercalifragilisticoespialidoso

Ejemplo 2 de ejecución Introduce cadena de texto Estudio en la Academia General del Aire. La cadena guardada por scanf es Estudio

Page 212: INFORMÁTICA Libro de Problemas

Capítulo 10: Caracteres y cadenas de caracteres | 213

En el primer ejemplo de ejecución, el texto que se introduce se guarda correctamente. Sin embargo, en el segundo ejemplo, sólo se guarda la primera palabra (Estudio). ¿Qué ocurre? Que la función scanf() va a guardar los caracteres que se introducen hasta que encontrar un carácter espacio o el carácter salto de línea. Por lo tanto, llegamos a la conclusión de que scanf() sólo sirve para para leer una palabra.

Ahora vamos a limitar el número de caracteres que puede guardar scanf(). En concreto, le indicamos que sólo pueda almacenar 10 caracteres. Para ello, en el especificador de formato empleado indicaremos un ancho de 10 (ver línea 7 en Código 10.3.2):

Código 10.3.2

1. #include <stdio.h> 2. #define _MAX 50 3. int main(void) 4. { 5. char a[_MAX], b[_MAX]; 6. printf("\nIntroduce cadena de texto "); 7. scanf(" %10s", a); 8. printf("\nLa cadena guardada por scanf es %s \n", a); 9. return 0; 10. }

Veamos un ejemplo de ejecución del programa mostrado en Código 10.3.2: Ejemplo 3 de ejecución Introduce cadena de texto Supercalifragilisticoespialidoso La cadena guardada por scanf es Supercalif

Como podemos observar, scanf() guarda sólo 10 caracteres, debido a que este es el número que le hemos indicado (%10s). Sin embargo, a la vista de este comportamiento, se nos plantea la duda sobre qué es lo que ocurre con los otros caracteres tecleados. Vamos a tratar de responder esta pregunta ampliando el programa mostrado en Código 10.3.2:

Código 10.3.3

1. #include <stdio.h> 2. #define _MAX 50 3. int main(void) 4. { 5. char a[_MAX], b[_MAX], c; 6. printf("Introduce cadena de texto "); 7. scanf(" %10s", a); // Limitamos los caracteres que se guardan 8. printf("\nLa cadena guardarda por scanf es %s \n", a); 9. printf("\nLo que queda en el buffer... \n"); 10. while((c = getchar()) != '\n')

Page 213: INFORMÁTICA Libro de Problemas

214 | Informática. Libro de problemas

11. printf("%c", c); 12. return 0; 13. }

Si ejecutamos el programa mostrado en Código 10.3.3 obtenemos lo siguiente: Ejemplo 4 de ejecución Introduce cadena de texto Supercalifragilisticoespialidoso La cadena guardarda por scanf es Supercalif Lo que queda en el buffer... ragilisticoespialidoso

Como vemos, los caracteres que no han podido ser almacenados en la variable a, se quedan en el buffer de entrada. Entonces, ¿qué puede ocurrir si seguidamente volvemos a pedir al usuario que introduzca otra frase mediante scanf()? Tratemos de responder a esta pregunta mediante la ejecución del programa mostrado en Código 10.3.4, donde donde realizamos una segunda invocación a la función scanf() para almacenar el contenido en la variable b.

Código 10.3.4

1. #include <stdio.h> 2. #define _MAX 50 3. int main(void) 4. { 5. char a[_MAX], b[_MAX]; 6. printf("Introduce cadena de texto "); 7. scanf(" %10s", a); // Limitamos los caracteres que se guardan 8. printf("\nIntroduce SEGUNDA cadena de texto "); 9. scanf(" %10s", b); // Limitamos los caracteres que se guardan 10. printf("\nLa cadena guardarda por scanf es %s \n", a); 11. printf("\nLa segunda cadena guardada por scanf es %s \n", b); 12. return 0;

Ejemplo 5 de ejecución Introduce cadena de texto Supercalifragilisticoespialidoso Introduce SEGUNDA cadena de texto La cadena guardarda por scanf es Supercalif La segunda cadena guardada por scanf es ragilistic

Page 214: INFORMÁTICA Libro de Problemas

Capítulo 10: Caracteres y cadenas de caracteres | 215

Si ejecutamos el Código 10.3.4 experimentamos un comportamiento anómalo. Concretamente observamos que cuando el programa imprime la frase "Introduce SEGUNDA cadena de texto", este no nos permite introducir ningún texto y directamente aparecen los mensajes que muestran el contenido almacenado en las cadenas a y b. A buen seguro se estará preguntando el motivo por el que ocurre esto. Debido a que el buffer de entrada contiene caracteres (aquellos que no fueron procesados por la primera llamada a scanf() en la línea 7), la segunda llamada a scanf() en la línea 9 se "nutre" de este contenido que está en el buffer y, por lo tanto, no necesita que el usuario el usuario introduzca una frase por teclado. En otras palabras, una llamada a scanf() hará que se detenga el programa y espere a que el usuario teclee una frase sólo si el buffer está vacío. Por este motivo, en el caso anterior observamos que en la cadena b se han guardado los siguientes 10 caracteres que hay en el buffer.

Para solucionar esta situación y forzar a que la segunda llamada a scanf() permita al usuario introducir una frase, deberemos invocar los servicios de la función fflush() que se encargará de vaciar el buffer de entrada. De este modo, cuando se ejecute la segunda llamada a scanf(), el buffer no tendrá contenido alguno y scanf() se verá en la obligación de quedar a la espera de que el usuario introduzca una frase. Usando fflush(), el nuevo código queda de la siguiente manera:

Código 10.3.5

1. #include <stdio.h> 2. #define _MAX 50 3. int main(void) 4. { 5. char a[_MAX], b[_MAX]; 6. printf("\nIntroduce cadena de texto "); 7. scanf(" %10s", a); // Limitamos los caracteres que se guardan 8. printf("\nIntroduce SEGUNDA cadena de texto "); 9. fflush(stdin); 10. scanf(" %10s", b); // Limitamos los caracteres que se guardan 11. printf("\nLa cadena guardarda por scanf es %s \n", a); 12. printf("La segunda cadena guardarda por scanf es %s \n", b); 13. } 14.

Si ejecutamos el programa mostrado en Código 10.3.5, obtenemos la siguiente salida: Ejemplo 6 de ejecución

Introduce cadena de texto Supercalifragilisticoespialidoso Introduce SEGUNDA cadena de texto Estudio en la Academia General del Aire La cadena guardarda por scanf es Supercalif La segunda cadena guardarda por scanf es Estudio

Page 215: INFORMÁTICA Libro de Problemas

216 | Informática. Libro de problemas

Vemos como ahora sí que podemos teclear una segunda frase, que se almacena en la variable b y que scanf(), como estaba previsto, aunque podría guardar hasta 10 caracteres, al encontrar un espacio antes de llegar al límite, se queda con la primera palabra. >> Uso de la función gets() Vamos a partir del código que se muestra a continuación:

Código 10.3.6

1. #include <stdio.h> 2. #define _MAX 20 3. int main(void) 4. { 5. char a[_MAX], b[_MAX]; 6. int c = 5; 7. 8. printf("\nIntroduce cadena de texto "); 9. gets(a); 10. printf("\nLa cadena guardada por gets es %s \n", a); 11. 12. printf("\nIntroduce segunda cadena de texto "); 13. gets(b); 14. printf("\nLa segunda cadena guardada por gets es %s \n", b); 15. 16. printf("\nEl numero que hay en c es %d \n", c); 17. return 0;

Ahora la longitud máxima permitida para los vectores tipo char (valor constante _MAX definido mediante la directiva #define en la línea 2) va a ser 20, con el fin de poder presentar mejor este ejemplo. Además, incluimos una variable entera denominada c que es inicializada con el valor 5.

Como se puede observar, este programa va a pedir al usuario que introduzca dos frases y, posteriormente, las mostrará por pantalla. En último lugar, el programa mostrará el valor que contiene la variable c.

Vamos a ejecutar el programa mostrado en Código 10.3.6 y realizar una prueba donde introduciremos un texto de longitud menor que la máxima permitida (20 caracteres):

Ejemplo 7 de ejecución Introduce cadena de texto CUD-AGA La cadena guardada por gets es CUD-AGA Introduce segunda cadena de texto M.T. MARTINEZ

Page 216: INFORMÁTICA Libro de Problemas

Capítulo 10: Caracteres y cadenas de caracteres | 217

La segunda cadena guardada por gets es M.T. MARTINEZ El numero que hay en c es 5

Como se observa, el programa se ejecuta sin ningún problema. Gracias a la función gets() conseguimos recoger todos los caracteres que el usuario introduce hasta que el usuario pulse la tecla Intro, es decir, hasta que el usuario inserte el carácter salto de línea ('\n'). Notar que gets() no incluye este último carácter ('\n') en la cadena que devuelve.

Vamos a volver a ejecutar el programa, pero, en esta ocasión, para el primer texto solicitado vamos a introducir una frase que tenga una longitud mayor que la indicada en la dimensión del vector de la variable a (20).

Ejemplo 8 de ejecución Introduce cadena de texto Supercalifragilisticoespialidoso aunque suene extravagante La cadena guardada por gets es Supercalifragilisticoespialidoso aunque suene extravagante Introduce segunda cadena de texto raro y espantoso La segunda cadena guardada por gets es raro y espantoso El numero que hay en c es 544174959

El programa muestra un valor de c que, a priori, no es el esperado. Además, después de unos pocos segundos, el programa se cierra de una forma inesperada. En la ejecución anterior del programa, de manera intencionada hemos proporcionado un mensaje cuya longitud excedía la capacidad máxima (20 caracteres) de la cadena a que se emplea para almacenar el mismo. La función gets() tiene el inconveniente de no controlar que la cadena de texto introducida por el usuario quepa en el vector que se usa para su almacenamiento. De hecho, en esta situación, lo que hace gets() es leer toda la frase y escribirla en memoria, aunque ello implique escribir en una zona de memoria que pertenezca a otra variable del programa (en nuestro caso la variable c) o, lo que es peor, en una zona de memoria que pueda pertenecer a otro programa. Como consecuencia de lo anterior, el programa finaliza de forma abrupta.

Llegados a este punto, se preguntará si existe manera de solucionarlo. Con la función gets() no tenemos ninguna forma de poder controlar esta situación. Podemos indicarle al usuario mediante un printf() que lleve cuidado en no proporcionar un mensaje que exceda una determinada cantidad de caracteres. Sin embargo, a nivel de programación, no podemos hacer otra cosa que declarar cadenas de caracteres con una longitud suficientemente grande. Cuando usemos la función gets() deberemos optar por aplicar esta medida, pero es de reconocer que no es la solución más eficiente dado que estamos reservando una cantidad de memoria que quizás no sea necesaria.

Page 217: INFORMÁTICA Libro de Problemas

218 | Informática. Libro de problemas

Aunque la función scanf() no nos va a permitir leer por teclado frases que contengan espacios, sí que podemos limitar la cantidad de caracteres que se pueden almacenar. Dicho de otra forma, con scanf() sí que podemos evitar que el usuario proporcione una cadena de texto de una longitud mayor a la permitida.

>> Uso de la función fgets() La función fgets() es de propósito general, en el sentido de que nos permite leer información proveniente de diversas fuentes: teclado, fichero, socket2, etc. Nosotros nos vamos a centrar en su aplicación para la lectura de información proporcionada por el usuario empleando el teclado.

El uso de la función fgets() es parecido al visto anteriormente para la función gets(). Sin embargo, fgets() tiene una característica muy interesante: permite asegurar que no se almacenará un texto cuya longitud exceda la capacidad máxima de la variable cadena empleada para su almacenamiento.

Tomando como referencia el programa mostrado en Código 10.3.7, vamos a ejecutarlo e introducir las mismas frases que en el Ejemplo 8 de ejecución.

Código 10.3.7

1. #include <stdio.h> 2. #define _MAX 20 3. int main(void) 4. { 5. char a[_MAX], b[_MAX]; 6. 7. printf("\nIntroduce cadena de texto "); 8. fgets(a, 20, stdin); 9. printf("\nLa cadena guardada por fgets es %s \n", a); 10. 11. printf("\nIntroduce segunda cadena de texto "); 12. fgets(b, 20, stdin); 13. printf("\nLa segunda cadena guardada por fgets es %s \n", b); 14. 15. return 0; 16. }

2 Un socket es un elemento de programación que permite el intercambio de información entre dos aplicaciones software que se ejecutan en ordenadores diferentes conectados a través de una red de comunicaciones como, por ejemplo, Internet.

Page 218: INFORMÁTICA Libro de Problemas

Capítulo 10: Caracteres y cadenas de caracteres | 219

Ejemplo 9 de ejecución Introduce cadena de texto Supercalifragilisticoespialidoso aunque suene extravagante La cadena guardada por fgets es Supercalifragilisti Introduce segunda cadena de texto La segunda cadena guardada por fgets es coespialidoso aunqu

A diferencia de lo que nos ocurría con la función gets(), ahora usando fgets() no experimentamos problema alguno en la ejecución de este programa. Como puede observar, el programa no nos ha permitido introducir una segunda frase, sino que, directamente ha tomado los caracteres que han quedado en el buffer, es decir, aquellos que la primera llamada a fgets() dejó sin procesar debido a que excedían la capacidad de la variable cadena a.

Este problema no es nuevo pues se ha visto en ejercicios anteriores. Si queremos que no ocurra esto y que la segunda llamada a fgets() funcione correctamente, bastará con invocar en el programa la función fflush() antes de la llamada a gets() en la línea 13, con el objetivo de borrar el contenido del buffer y asegurarnos que en la segunda llamada a la función gets() el buffer no tiene información "sobrante" de una lectura anterior de información por teclado.

Teniendo en cuenta lo anterior, se puede mejorar el programa mostrado en Código 10.3.7 incorporando el uso de la función fflush().

Código 10.3.8

1. #include <stdio.h> 2. #define _MAX 20 3. int main(void) 4. { 5. char a[_MAX], b[_MAX]; 6. 7. printf("\nIntroduce cadena de texto "); 8. fgets(a, 20, stdin); 9. printf("\nLa cadena guardada por fgets es %s \n", a); 10. 11. fflush(stdin); 12. printf("\nIntroduce segunda cadena de texto "); 13. fgets(b, 20, stdin); 14. printf("\nLa segunda cadena guardada por fgets es %s \n", b); 15. 16. return 0; 17. }

Si ejecutamos el programa mostrando en Código 10.3.8, tenemos lo siguiente:

Page 219: INFORMÁTICA Libro de Problemas

220 | Informática. Libro de problemas

Ejemplo 10 de ejecución Introduce cadena de texto Supercalifragilisticoespialidoso aunque suene extravagante La cadena guardada por fgets es Supercalifragilisti Introduce segunda cadena de texto raro y espantoso La segunda cadena guardada por fgets es raro y espantoso

Ahora el programa funciona correctamente y permite al usuario introducir al usuario dos frases de cualquier tamaño.

Para finalizar, a modo de conclusión, se ofrece la siguiente tabla donde se comparan los servicios proporcionados por las tres funciones analizadas.

scanf() gets() fgets()

¿Cuándo detiene la lectura de caracteres

introducidos por teclado?

- Encuentra un espacio - Encuentra un salto de

línea ('\n') - Llega al límite que se le

puede imponer

- Encuentra un salto de línea ('\n')

- Encuentra un salto de línea ('\n')

- Llega al límite que se le puede imponer

¿Almacena el carácter final leído que

provocó el fin de la lectura?

No. No. Sí (el '\n').

¿Inserta el carácter nulo '\0' fin de

cadena?

Sí, pero sólo cuando el mensaje no excede el

tamaño máximo.

Sí, pero sólo cuando el mensaje no excede el

tamaño máximo.

Sí, incluso cuando el mensaje excede el tamaño máximo.

¿Permite controlar que no se exceda el

tamaño máximo de la cadena destino?

Sí.

No. Puede ocasionar errores durante la

ejecución del programa.

Sí.

Tal y como se muestra en la tabla anterior, la función fgets() es la que ofrece una funcionalidad más completa. Sin embargo, tiene un pequeño inconveniente: incluye como parte del texto leído el carácter que provocó el fin de la lectura por teclado, es decir, el carácter salto de línea ('\n'). Esto hace que a la hora de programar deba ser tenido en cuenta.

Para comprender mejor esta última cuestión, veamos un ejemplo. Supongamos que tenemos dos variables C y D de tipo cadena, ambas de dimensión 10. Según esto, el usuario como máximo podrá proporcionar un mensaje de 9 caracteres, puesto que fgets() siempre fuerza que el último carácter sea el carácter nulo ('\0'). ¿Qué ocurre si al hacer la lectura con fgets(), para la primera tecleamos el mensaje "JOSE LUIS" y para la segunda "BLANCA"? La respuesta se encuentra en la siguiente figura.

Page 220: INFORMÁTICA Libro de Problemas

Capítulo 10: Caracteres y cadenas de caracteres | 221

En el primer caso, fgets() no inserta el carácter de control de salto de línea puesto que JOSE LUIS tiene una longitud de 9. Pero, en el segundo caso, BLANCA, tiene 6 caracteres, por lo que introduce el carácter salto de línea ('\n') y, después de este, el carácter nulo ('\0'). ¿En qué puede afectar esto? Si vamos a procesar de alguna manera esta cadena, tendremos que tener en cuenta que, si se ha usado fgets() para la lectura de dicha cadena, es posible que tengamos el carácter '\n' en la penúltima posición del array.

10.4. Longitud cadena

Escriba un programa que solicite al usuario sus apellidos. El programa deberá mostrar por pantalla la longitud del texto proporcionado por el usuario.

A continuación, se muestra un ejemplo de ejecución que ilustra el comportamiento esperado del programa:

Ejemplo 1 de ejecución Introduzca sus apellidos Martinez Garcia La cadena apellidos tiene una dimension de 100. Lo que ha introducido el usuario ocupa una longitud de 15

En este ejercicio se va a mostrar, de una forma guiada, las diferentes opciones que existen para determinar la longitud real de un texto almacenado en una variable cadena.

Como sabemos, el vector de tipo char donde se almacena el texto que introduce un usuario va a tener definida una dimensión D. Si tenemos en cuenta que toda cadena de texto en C debe finalizar con el carácter nulo ('\0'), entonces como máximo podremos almacenar un texto que tenga D-1 caracteres. No obstante, la situación más frecuente será aquella en la que el usuario proporcione un mensaje con una longitud menor a D-1.

Para resolver este problema, vamos a plantear un programa donde declaremos una variable cadena llamada apellidos. Esta variable será declarada como un vector de tipo char al que se le asignará una dimensión de 100. Por lo tanto, según lo indicado en el párrafo anterior, el programa almacenará correctamente un mensaje de hasta 99 caracteres. Es decir, el número total de caracteres que forma los apellidos de una persona (apellido 1º + espacio + apellido 2º) no podrá exceder de 99 caracteres.

Page 221: INFORMÁTICA Libro de Problemas

222 | Informática. Libro de problemas

Partiendo de esta situación, el programa mostrado en Código 10.4 recoge las diferentes formas que existen para determinar la longitud real del texto almacenado en una cadena.

Código 10.4

1. #include <stdio.h> 2. #include <string.h> 3. #define _MAX 100 4. int main(void) 5. { 6. char apellidos[_MAX]; 7. short i, u, j, k; 8. printf("Introduzca sus apellidos "); 9. gets(apellidos); 10. // Alternativa 1: utilizando for con break ------------ 11. for(i = 0; i < _MAX; i++) { 12. if(apellidos[i] == '\0') 13. break; 14. } 15. // Alternativa 2: utilizando un solo for --------------- 16. for(u = 0; apellidos[u] != '\0'; u++); 17. // Alternativa 3: utilizando while---------------------- 18. j = 0; 19. while(apellidos[j] != '\0') 20. j++; 21. // Alternativa 4: utilizando strlen--------------------- 22. k = strlen(apellidos); 23. 24. printf("\nLa cadena apellidos tiene una dimension de %d \n", 25. (int) sizeof(apellidos)); 26. printf("\nLo que ha introducido el usuario tiene una longitud de...\n"); 27. printf("\t - Utilizando for con break: %d caracteres\n", i); 28. printf("\t - Utilizando un solo for: %d caracteres\n", u); 29. printf("\t - Utilizando while: %d caracteres\n", j); 30. printf("\t - Utilizando la funcion strlen: %d caracteres\n", k); 31. return 0; 32. }

La ejecución del programa mostrado en Código 10.4 es la siguiente: Ejemplo 2 de ejecución Introduzca sus apellidos Martinez Garcia La cadena apellidos tiene una dimension de 100 Lo que ha introducido el usuario tiene una longitud de... - Utilizando for con break: 15 caracteres - Utilizando un solo for: 15 caracteres - Utilizando while: 15 caracteres - Utilizando la funcion strlen: 15 caracteres

Page 222: INFORMÁTICA Libro de Problemas

Capítulo 10: Caracteres y cadenas de caracteres | 223

Si analiza el Código 10.4, apreciará que el programa emplea las variables i, u, j, k de tipo short (línea 7) para guardar las longitudes calculadas de diferentes formas. Por otro lado, para leer la cadena se utiliza los servicios de la función gets() (línea 9). El texto proporcionado por el usuario se almacenará en el vector apellidos de tipo char y tamaño _MAX, siendo este un valor constante definido mediante la directiva #define (línea 3) con un valor de 100 que, a priori, es suficiente para almacenar el primer y segundo apellido de una persona. Seguidamente, el programa muestra 4 maneras diferentes determinar la longitud real del texto proporcionado por el usuario. A continuación, explicamos el funcionamiento de cada una:

• La primera alternativa (líneas 11-14) de calcular la longitud real del texto emplea un bucle for y una sentencia de ruptura break.

for(i = 0; i < _MAX; i++) { if(apellidos[i] == '\0') break;

}

o Como se puede observar, empleando una estructura de repetición for, vamos a ir recorriendo todas las posiciones de la cadena apellidos, de forma que, en cada iteración, vamos a ir comprando mediante una estructura if si lo que contiene esa posición de la cadena apellidos es el carácter nulo.

o Cuando esa condición sea verdadera, se solicita la ruptura del bucle (break) para salir del bucle. En ese momento, la variable i contendrá el número de veces que se ha ejecutado ese bucle for, es decir, el número de veces que esa cadena contenía algo diferente al carácter nulo. En definitiva, el valor de i representa la longitud real de la cadena introducida por el usuario.

• La segunda alternativa (línea 16) emplea una estructura for de la siguiente forma: for(u = 0; apellidos[u] != '\0'; u++);

o Como puede observar, esta sentencia for no tiene asociada ninguna instrucción. Por este motivo, la sentencia termina con ;

o Fíjese en la condición de parada de este bucle. Este bucle se ejecutará mientras que lo que devuelva la operación apellidos[u] != '\0' sea cierto, es decir, mientras que el carácter que se analiza en cada iteración (apellidos[u]) no sea el carácter nulo ('0'). Al finalizar, la variable u contendrá la longitud real de esa cadena.

• Una tercera alternativa (líneas 18-20) consiste en utilizar la estructura de repetición while: j=0; while(apellidos[j] != '\0') j++;

o Esta versión es muy parecida a la anterior pero, en este caso, se emplea la estructura iterativa while. Mientras que lo que contenga apellidos en la posición

Page 223: INFORMÁTICA Libro de Problemas

224 | Informática. Libro de problemas

que indica el contador j, sea distinto del carácter nulo, ese contador j se incrementará.

o Note que se ha inicializado la variable j a 0 antes de que se ejecute la estructura while ya que es necesario para que funcione correctamente la contabilización de caracteres.

• La cuarta alternativa (línea 22) que se presenta, y la más común, consiste en emplear la función strlen(), disponible en la librería <string.h>.

k = strlen(apellidos);

o Esta función recibe, como parámetro de entrada, la cadena (en este caso apellidos) de la que debe determinar su longitud.

o Como es de esperar, esta función devuelve un valor entero que representa el número de caracteres que forman la cadena sin contar el carácter nulo final.

10.5. Contar Aa Escriba un programa que solicite al usuario una frase de máximo 100 caracteres . El programa mostrará por pantalla el número de vocales 'a' y 'A' que se han introducido. A continuación, se muestran diversos ejemplos de ejecución que ilustran el comportamiento esperado del programa: Ejemplo 1 de ejecución Introduzca un texto con un maximo de 100 caracteres Se dice que el sol se pone por el oeste No ha introducido ninguna vocal A/a

Ejemplo 2 de ejecución Introduzca un texto con un maximo de 100 caracteres Hoy tenemos luna creciente En el texto hay un solo caracter A/a

Ejemplo 3 de ejecución Introduzca un texto con un maximo de 100 caracteres El agua hierve a 100 grados En el texto hay 4 caracteres A/a

Page 224: INFORMÁTICA Libro de Problemas

Capítulo 10: Caracteres y cadenas de caracteres | 225

Posible solución: Código 10.5

1. #include <stdio.h> 2. #include <string.h> 3. #define _MAX 101 4. int main(void) 5. { 6. short i, a = 0; 7. char texto[_MAX]; 8. printf("Introduzca un texto con un maximo de 100 caracteres\n"); 9. gets(texto); 10. for(i = 0; texto[i] != '\0'; i++) { 11. if(texto[i] == 'a' || texto[i] == 'A') 12. a++; 13. } 14. if(a == 0) 15. printf("No ha introducido ninguna vocal A/a \n\n"); 16. else if(a == 1) 17. printf("En el texto hay un solo caracter A/a \n\n"); 18. else 19. printf("En el texto hay %hd caracteres A/a \n\n", a); 20. return 0; 21. }

Comentarios:

• Mediante la llamada a la función gets() (línea 9) guardamos el texto que introduce el usuario en la variable texto, la cual se declara (línea 3) como un vector tipo char con dimensión _MAX, que es un valor constante definido mediante la directiva #define con el valor 101. ¿Por qué 101? Porque al usuario le indicamos que puede introducir 100 caracteres como máximo, por lo tanto, al trabajar con cadenas de caracteres, debemos tener en cuenta que la dimensión será un número más debido al carácter nulo.

• Seguidamente, se recorre mediante un bucle for (líneas 10-13) todas las posiciones de la cadena texto que contengan caracteres distintos del carácter final de cadena ('\0'):

for(i = 0; texto[i] != '\0'; i++) { if(texto[i] == 'a' || texto[i] == 'A') a++; }

o Para cada posición, mediante una estructura if, evaluaremos si el carácter que hay en cada posición es igual a la vocal a o A.

o Si es así, se incrementará la variable a en una unidad, la cual se ha declarado como short e inicializado al valor de 0.

• Por último, para mostrar el resultado, se emplea una estructura if-else (líneas 14-19) y, dependiendo del número de vocales (a/A) que haya introducido el usuario, se mostrará por pantalla tres tipos de mensajes personalizados para los siguientes casos: si no se ha

Page 225: INFORMÁTICA Libro de Problemas

226 | Informática. Libro de problemas

encontrado ninguna vocal a/A, si sólo se ha encontrado una vocal a/A o si se ha encontrado más de una vocal a/A.

10.6. Nombre apellido Escriba un programa que primero solicite al usuario su nombre y que, a continuación, solicite su apellido. El programa mostrará por pantalla el nombre completo del usuario. A continuación, se muestra un ejemplo de ejecución para clarificar el comportamiento del programa: Ejemplo de ejecución Introduzca Nombre: MAR Introduzca Apellido: RUIZ AGUIRRE El usuario se llama: MAR RUIZ AGUIRRE Posible solución: Código 10.6.1

1. #include <stdio.h> 2. #include <string.h> 3. #define _MAX 30 4. int main(void) 5. { 6. char nombre[_MAX], apellido[_MAX]; 7. char nombrecompleto[_MAX * 2]; 8. short Lnombre, Lapellido, i, j; 9. printf("Introduzca Nombre: "); 10. gets(nombre); 11. printf("Introduzca Apellido: "); 12. gets(apellido); 13. Lnombre = strlen(nombre); 14. Lapellido = strlen(apellido); 15. for(i = 0; i < Lnombre; i++) 16. nombrecompleto[i] = nombre[i]; 17. nombrecompleto[i] = ' '; 18. for(j = 0, i = i + 1; j < Lapellido; j++, i++) 19. nombrecompleto[i] = apellido[j]; 20. nombrecompleto[i] = '\0'; 21. printf("El usuario se llama: %s\n", nombrecompleto); 22. return 0; 23. }

Page 226: INFORMÁTICA Libro de Problemas

Capítulo 10: Caracteres y cadenas de caracteres | 227

Comentarios:

• El objetivo de este programa es mostrar cómo se puede generar una nueva cadena como resultado de combinar dos cadenas existentes.

• Según se puede observar en las líneas 6 y 7, el programa propuesto declara tres cadenas: nombre, apellido y nombrecompleto.

- Las dos primeras almacenarán el nombre y apellidos que introduzca el usuario de manera independiente. Su dimensión viene determinada por la constante _MAX, que se encuentra definida en la línea 3.

- La cadena nombrecompleto será donde se almacene el nuevo texto que se genere fruto de concatenar los dos textos (nombre y apellidos) introducidos por el usuario, insertando un carácter espacio entre ellas para separar el nombre del primer apellido.

• El nombre y los apellidos que introduce el usuario se leen mediante la invocación de la función gets() (líneas 10 y 12).

• Una vez realizada la lectura por teclado, el programa debe construir el nuevo texto que se almacenará en la cadena nombrecompleto. Para ello, primero vamos a calcular la longitud del texto almacenado en las cadenas nombre y apellido. En el código propuesto, esto se realiza en las líneas 13 y 14 mediante la llamada a la función strlen(). Observe que:

o Para tener acceso a esta función, en el programa hemos debido incluir la librería <string.h>.

o Asignamos a las variables Lnombre y Lapellido el resultado de la función strlen().

• Seguidamente se copia el contenido de la primera cadena (nombre) en la cadena nombrecompleto. Ello se hace mediante el siguiente bucle for (líneas 15-16):

for(i = 0; i < Lnombre; i++) nombrecompleto[i] = nombre[i];

o El copiado se hace carácter a carácter. Se recorre toda la cadena nombre y, para cada carácter ubicado en la posición indicada por el índice i, se copia y asigna a la misma posición de la cadena nombrecompleto.

o Una forma alternativa de implementar lo mismo hubiera sido emplear en la condición de parada de la estructura for directamente la función strlen(), de manera que el código resultante sería:

for(i = 0; i < strlen(nombre); i++) nombrecompleto[i] = nombre[i];

(1) Esta alternativa es más eficiente ya que permite ahorrarnos la declaración de dos variables (Lnombre y Lapellido).

Page 227: INFORMÁTICA Libro de Problemas

228 | Informática. Libro de problemas

(2) Notar que la condición de parada del bucle también se puede escribir como i<=strlen(nombre)-1.

• Una vez hecho esto, hay que introducir el carácter espacio en nombrecompleto. Debido a que al finalizar el bucle for, el índice i se habrá incrementado, este tendrá el valor de la siguiente posición en la cadena nombrecompleto, que es la posición donde deberemos de insertar el espacio. Por ello, inmediatamente después de la finalización del bucle for, se ejecuta la siguiente instrucción (línea 17):

nombrecompleto[i] = ' ';

• Una vez insertado el espacio que debe separar el nombre de los apellidos, podemos proceder a insertar la cadena apellido en nombrecompleto. Para implementar esto, el código propuesto es el siguiente (líneas 18-19):

for(j = 0, i = i + 1; j < Lapellido; j++, i++) nombrecompleto[i] = apellido[j];

o El índice j se empleará para moverse por las distintas posiciones de la cadena apellido. Este índice se inicializa en 0, puesto que la primera posición de la cadena es la 0.

o El índice i recorrerá las posiciones de nombrecompleto. Para ello, hay que tener en cuenta la posición a partir de la cual comenzará a asignar el valor que contenga apellido en la primera posición. Por ello, la variable i se inicializa a el valor que contenga incrementado en una unidad. Esto es así porque, como ya que como hemos visto, en la posición que indicaba i nada más terminar el primer for, hemos insertado el carácter espacio. Así que tendremos que incrementar en 1 el valor que contenga la variable i para que en la posición correcta empiece a insertar los caracteres almacenados en la cadena apellido.

• Para terminar de crear el nuevo texto, debemos añadir en la última posición el carácter nulo. Esta operación simple se consigue con la siguiente instrucción (línea 20):

nombrecompleto[i] = '\0';

o Al igual que antes, cuando termine el segundo bucle for, el índice i apuntará a la posición de la cadena correcta donde se debe insertar el carácter nulo.

• Para que de forma visual se pueda comprender la estrategia seguida para construir el nuevo texto que se almacena en la cadena nombrecompleto, en la siguiente figura se muestra la interacción existente entre las cadenas, los índices (variables i y j) empleados y los bucles for empleados.

Page 228: INFORMÁTICA Libro de Problemas

Capítulo 10: Caracteres y cadenas de caracteres | 229

o Cuando termina la ejecución del primer for, la variable i tendrá el valor de 3.

o Haciendo uso de este mismo valor se inserta en esa posición el espacio.

o Cuando termina la ejecución del segundo for, el variable i tiene el valor 16.

o Haciendo uso de este mismo valor, se inserta en esa posición el carácter nulo que marca el fin de la nueva cadena construida.

• Por último, se imprime la cadena nombrecompleto. Recuerde que los vectores numéricos no se pueden imprimir con una simple invocación a printf(), sino que debemos recorrer el array y solicitar la impresión del valor numérico contenido en cada posición. Sin embargo, las cadenas, aunque también son un tipo de vectores, sí que se pueden imprimir su contenido con una única invocación a printf()empleando el especificador de formato %s, tal y como se muestra en la línea 21:

printf("El usuario se llama: %s\n", nombrecompleto);

Solución alternativa:

Una vez comprendida la solución anterior, ahora proporcionamos otra solución alternativa que emplea la función strcpy(), disponible en la librería <string.h>. Esta función copia el contenido de una cadena a otra y recibe dos parámetros de entrada:

- El primer parámetro representa la cadena destino, es decir, la cadena donde se desea almacenar la copia

- El segundo parámetro será la cadena origen, es decir, la cadena que tiene el texto del que deseamos generar una copia.

Basados en la solución anterior, a continuación, presentamos el código resultante donde se resalta de color amarillo las nuevas líneas de código que se deben introducir:

Código 10.6.2

1. #include <stdio.h> 2. #include <string.h> 3. #define _MAX 30

Page 229: INFORMÁTICA Libro de Problemas

230 | Informática. Libro de problemas

4. int main(void) 5. { 6. char nombre[_MAX], apellido[_MAX]; 7. char nombrecompleto[_MAX * 2]; 8. short Lnombre, Lapellido, i, j; 9. printf("Introduzca Nombre: "); 10. gets(nombre); 11. printf("Introduzca Apellido: "); 12. gets(apellido); 13. Lnombre = strlen(nombre); 14. Lapellido = strlen(apellido); 15. strcpy(nombrecompleto, nombre); 16. i = Lnombre; 17. nombrecompleto[i] = ' '; 18. for(j = 0, i = i + 1; j < Lapellido; j++, i++) 19. nombrecompleto[i] = apellido[j]; 20. 21. nombrecompleto[i] = '\0'; 22. printf("El usuario se llama: %s\n", nombrecompleto); 23. return 0; 24. }

Como puede observar, gracias a la función strcpy() conseguimos copiar de una manera fácil el texto contenido en la cadena nombre a la cadena nombrecompleto. Realizar esta operación mediante la función strcpy()tiene un pequeño inconveniente: debemos calcular de alguna manera la posición correcta donde insertar el espacio en blanco que debe separar el nombre de los apellidos. En verdad, es fácil averiguarlo ya que la posición correcta coincide con el tamaño de la cadena nombre, que previamente se ha calculado con la función strlen(). Por ejemplo, si la cadena nombre almacena el texto "Mar", entonces la instrucción strlen(nombre) nos devuelve el número 3. Este valor nos indica la posición exacta de la cadena nombrecompleto donde se debe insertar el espacio en blanco. Es decir, nombrecompleto[3], que hace referencia a la 4ª posición de la cadena, es el lugar donde se debe insertar el carácter espacio en blanco.

10.7. Caracteres iguales Escriba un programa que muestre por pantalla el número de vocales que existen en una frase que introduzca el usuario por teclado. A continuación, se muestra un ejemplo de ejecución del programa: Ejemplo 1 de ejecución Introduzca texto: No por mucho madrugar amanece mas temprano Hay 15 vocales en el texto introducido

Page 230: INFORMÁTICA Libro de Problemas

Capítulo 10: Caracteres y cadenas de caracteres | 231

Ejemplo 2 de ejecución Introduzca texto: Como en casa, en ningun sitio Hay 11 vocales en el texto introducido

Posible solución: Código 10.7

1. #include <stdio.h> 2. #include <string.h> 3. #define _MAX 100 4. int main(void) 5. { 6. short i, j, iguales = 0; 7. char cad1[_MAX]; 8. char cad2[_MAX] = "aeiou"; 9. printf("Introduzca texto: "); 10. gets(cad1); 11. for(i = 0; cad2[i] != 0; i++) { 12. for(j = 0; cad1[j] != 0; j++) { 13. if(cad2[i] == cad1[j]) 14. iguales++; 15. } 16. } 17. printf("Hay %hd vocales en el texto introducido\n", iguales); 18. printf("\n"); 19. return 0; 20. }

Comentarios:

• Para resolver este ejemplo, se declaran dos variables cadena (líneas 7-8): cad1 y cad2. En cad1 se almacenará el texto que introduce el usuario. La cadena cad2 se inicializa con un texto formado únicamente por las vocales. Note que, para inicializar una cadena, en este ejemplo se ha optado por hacerlo mediante comillas dobles.

• Después de obtener el texto que introduce el usuario mediante la función gets() (línea 10), procedemos a comparar ambas cadenas. Para ello, se emplean dos estructuras for anidadas (líneas 11-16) de la siguiente forma:

for(i = 0; cad2[i] != 0; i++) { for(j = 0; cad1[j] != 0; j++) { if(cad2[i] == cad1[j]) iguales++; }

}

Page 231: INFORMÁTICA Libro de Problemas

232 | Informática. Libro de problemas

o Cada for recorre una de las cadenas. Concretamente, el primer for recorre todas las posiciones de la cadena cad2 mientras que el segundo for recorre las posiciones de cad1.

o La ejecución del código seguiría los siguientes pasos:

1. Se ejecuta el primer bucle for i=0 1.1. Entra en el segundo bucle for j=0

1.1.1. Se evalúa la condición de permanenciala estructura if 1.1.1.1. Opción 1: la evaluación resulta verdadera, entonces significa que

lo que contiene cad2 en la posición cero, es igual a lo que contiene cad1 en la posición 0 (es decir, el carácter 'a')

1.1.1.1.1. El contador iguales se incrementa en una unidad. 1.1.1.2. Opción 2: la evaluación resulta falsa. No se entra en la estructura

if. 1.1.2. Variable j se incrementa j=1. 1.1.3. Se evalúa la condición de parada del segundo bucle for

1.1.3.1. Opción 1: No se cumple la condición de parada del segundo bucle for. Se vuelve a ejecutar el punto 1.1.1

1.1.3.2. Opción 2: Se cumple la condición de parada. Se sale del segundo bucle for. Continuar por el punto 1.2

1.2. Variable i se incrementa i=1. 1.3. Se evalúa la condición de parada del primer bucle for

1.3.1. Opción 1: No se cumple condición de parada. Continuar por el punto 1.1. Si i tiene el valor 1, entonces en la siguiente iteración se comparará la vocal e. En próximas iteraciones, conforme i vaya tomando valores mayores, se compararán el resto de vocales (i, o, u)

1.3.2. Opción 2: Se cumple la condición de parada. Finaliza la ejecución del primer bucle for.

• Por último, se muestra el valor que contiene la variable iguales (línea 17).

10.8. Encuentra y suma digitos

Escriba un programa que solicite al usuario una frase. El programa analizará el texto introducido por el usuario e identificará aquellos caracteres que sean numéricos (i.e. dígitos). El programa deberá mostrar por pantalla la suma de estos caracteres numéricos. A continuación, se muestra un ejemplo de ejecución del programa para ilustrar el comportamiento esperado:

Page 232: INFORMÁTICA Libro de Problemas

Capítulo 10: Caracteres y cadenas de caracteres | 233

Ejemplo de ejecución Introduzca un texto...21 de Abril del año 2020 La suma es .... 7 Posible solución: Código 10.8

1. #include <ctype.h> 2. #include <stdio.h> 3. #define _MAX 70 4. int main(void) 5. { 6. int i; 7. int suma = 0; 8. char texto[_MAX]; 9. printf("Introduzca un texto..."); 10. gets(texto); 11. for(i = 0; texto[i] != '\0'; i++) { 12. if(isdigit(texto[i]) != 0) 13. suma += texto[i] - '0'; 14. } 15. printf("La suma es .... %d\n", suma); 16. return 0; 17. } 18.

Comentarios:

• En este ejemplo se emplea la función isdigit() disponible en la librería <string.h>. Esta función recibe como parámetro de entrada un carácter (variable o literal constante tipo char) y devuelve un valor distinto de 0 en caso de que el carácter sea un dígito, y el valor 0 en caso contrario.

• Si la función isdigit() nos indica que el carácter es un dígito, entonces debemos realizar la conversión de carácter a entero. Este procedimiento ya lo vimos en el programa del Ejercicio 10.2 de este capítulo.

• Una vez realizada la conversión, se sumará el valor entero obtenido a lo que contenga la variable suma.

• Por último, se mostrará el resultado de la variable suma mediante una invocación a la función printf().

Page 233: INFORMÁTICA Libro de Problemas

234 | Informática. Libro de problemas

10.9. Cadena invertida Escriba un programa que pida al usuario que introduzca una frase. El programa deberá mostrar por pantalla la cadena de texto resultante de invertir los caracteres. A continuación, se muestra un ejemplo de ejecución para clarificar como debería ser el comportamiento del programa: Ejemplo de ejecución Introduzca un texto....A mal tiempo, buena cara La cadena invertida es arac aneub ,opmeit lam A

Posible solución: Código 10.9

1. #include <stdio.h> 2. #include <string.h> 3. #define _MAX 100 4. int main(void) 5. { 6. char original[_MAX], copiaInv[_MAX]; 7. short i, L, j; 8. printf("Introduzca un texto...."); 9. gets(original); 10. L = strlen(original); 11. for(i = 0, j = L - 1; i < L; i++, j--) 12. copiaInv[j] = original[i]; 13. copiaInv[L] = '\0'; 14. printf("\nLa cadena invertida es %s\n", copiaInv); 15. return 0; 16. }

Comentarios:

• Para resolver este ejemplo se han usado dos índices, i y j. El índice i recorrerá las posiciones de la cadena original (texto que introduce el usuario) y el índice j, las posiciones de la cadena copiaInv (cadena que guardará la cadena invertida).

Page 234: INFORMÁTICA Libro de Problemas

Capítulo 10: Caracteres y cadenas de caracteres | 235

• Mediante la estructura for, teniendo en cuenta que el índice j se inicializa a la última posición de la cadena copiaInv, se va copiando el contenido de la cadena original en las posiciones que corresponden al orden inverso de copiaInv.

• Note que en la última posición de copiaInv hay que introducir el carácter nulo '\0'.

• Existe una manera más eficiente de resolver este ejemplo empleando un sólo un índice. El siguiente código muestra este procedimiento empleando únicamente la variable i:

for(i = 0; i < L; i++) copiaInv[i] = original[(L-1)-i]; copiaInv[L] = '\0';

o En este código, para cada posición i de la cadena copiaInv se calcula mediante una fórmula (L-1-i) la posición que ocupa el carácter que debe ser copiado desde la cadena original.

o Veamos mediante un ejemplo el motivo por el que esta fórmula funciona. Supongamos que la cadena original tiene una longitud de 4 caracteres, es decir, L=4.

(1) En la primera iteración, i=0 copiaInv[0] = original[3]; (2) En la segunda iteración, i=1 copiaInv[1] = original[2]; (3) En la tercera iteración, i=2 copiaInv[2] = original[1]; (4) En la cuarta iteración, i=3 copiaInv[3] = original[0];

Page 235: INFORMÁTICA Libro de Problemas
Page 236: INFORMÁTICA Libro de Problemas

11

REGISTROS

Page 237: INFORMÁTICA Libro de Problemas
Page 238: INFORMÁTICA Libro de Problemas

Capítulo 11: Registros | 239

11.1. Persona fecha

Escriba un programa que almacene los datos de dos personas (nombre, edad y sexo) y dos fechas (día, mes y año). El programa deberá hacer uso de estructuras de datos para almacenar la información sobre personas y fechas. La inicialización se deberá hacer de manera estática en el mismo código del programa, no siendo necesario solicitar datos al usuario por teclado. Seguidamente, el programa deberá mostrar por pantalla los datos de las dos personas y las dos fechas. Se solicita que se haga uso de una función genérica capaz de imprimir por pantalla los datos de cualquier persona que reciba como parámetro, así como otra función que haga lo mismo pero para una fecha.

Para clarificar el funcionamiento del programa, a continuación, se muestra un ejemplo de ejecución: Ejemplo de ejecución DATOS DE PERSONA 1 Nombre: Javier Edad: 23 Sexo: Varon DATOS DE PERSONA 2 Nombre: Angela Edad: 33 Sexo: Mujer DATOS FECHA 1 Dia: 23 Mes: Abril Anio 2020 DATOS FECHA 2 Dia: 12 Mes: Septiembre Anio 2018

Posible solución: Código 11.1

1. #include <stdio.h> 2. #include <string.h> 3. 4. struct Persona { 5. char nombre[40]; 6. short edad; 7. char sexo; 8. };

Page 239: INFORMÁTICA Libro de Problemas

240 | Informática. Libro de problemas

9. 10. struct Fecha { 11. short dia; 12. char mes[12]; 13. int anio; 14. }; 15. 16. typedef struct Persona tipoPersona; 17. typedef struct Fecha tipoFecha; 18. 19. void imprimirUsuario(tipoPersona p); 20. void imprimirFecha(tipoFecha f); 21. 22. int main(void) 23. { 24. tipoPersona usuario1 = {"Javier", 23, 'V'}; 25. 26. tipoPersona usuario2; 27. strcpy(usuario2.nombre, "Angela"); 28. usuario2.edad = 33; 29. usuario2.sexo = 'M'; 30. 31. tipoFecha fecha1 = {23, "Abril", 2020}; 32. 33. tipoFecha fecha2; 34. fecha2.dia = 12; 35. strcpy(fecha2.mes, "Septiembre"); 36. fecha2.anio = 2018; 37. 38. printf("DATOS DE PERSONA 1\n"); 39. imprimirUsuario(usuario1); 40. 41. printf("DATOS DE PERSONA 2\n"); 42. imprimirUsuario(usuario2); 43. 44. printf("DATOS FECHA 1\n"); 45. imprimirFecha(fecha1); 46. 47. printf("DATOS FECHA 2\n"); 48. imprimirFecha(fecha2); 49. 50. return 0; 51. } 52. 53. void imprimirUsuario(tipoPersona p) 54. { 55. printf("Nombre:\t%s\n", p.nombre); 56. printf("Edad:\t%hd\n", p.edad); 57. printf("Sexo:\t%s\n\n", p.sexo == 'V' ? "Varon" : "Mujer"); 58. } 59. 60. void imprimirFecha(tipoFecha f) 61. { 62. printf("Dia:\t%hd\n", f.dia); 63. printf("Mes:\t%s\n", f.mes); 64. printf("Anio\t%d\n\n", f.anio); 65. }

Page 240: INFORMÁTICA Libro de Problemas

Capítulo 11: Registros | 241

Comentarios:

• En este ejemplo se declaran dos tipos de registros con los campos que se indican en el enunciado: struct Persona (líneas 4-8) y struct Fecha (líneas 10-14). Además, utilizando typedef se han creado los nombres tipoPersona y tipoFecha, que permitirán declarar variables de una forma más cómoda.

• Se han declarado dos funciones, imprimirUsuario() e imprimirFecha() en las líneas 19 y 20, respectivamente. Ambas funciones van a imprimir por pantalla datos y no van a devolver ningún dato. Por ello, en la declaración se especifica con void el tipo de dato de salida.

o La función imprimirUsuario() recibe como parámetro de entrada un registro tipoPersona.

o La función imprimirFecha() recibe como parámetro de entrada un registro tipoFecha.

• Atendiendo a las indicaciones del enunciado, se debe almacenar los datos de dos personas. Para ello, dentro de la función main(), se declaran las variables usuario1 (línea 24) y usuario2 (línea 26), ambas de tipo tipoPersona. Como se observa, cada variable se inicializa de una manera diferente:

o usuario1 se inicializa indicando los datos separados por comas, entre llaves y siguiendo el mismo orden definido en la estructura. Recuerde que este tipo de inicialización sólo se puede hacer en el momento de declarar la variable registro.

tipoPersona usuario1 = {"Javier", 23, 'V'};

o usuario2 se inicializa (líneas 27-29) accediendo directamente a los campos del registro. Recuerde que este tipo de inicialización se debe emplear obligatoriamente si lo estamos haciendo en un momento que no es la declaración de la variable registro.

strcpy(usuario2.nombre, "Angela"); usuario2.edad = 33; usuario2.sexo = 'M';

(1) Para inicializar el campo nombre, nuevamente empleamos la función strcpy(), la cual copia el contenido de la cadena especificada como segundo parámetro, en la cadena que se indica como primer parámetro en esta función. Para acceder al campo nombre de usuario2, se usa el operador ".". De este modo se consigue copiar el texto "Angela" en el campo nombre de usuario2.

Los campos edad y sexo se inicializan de manera sencilla mediante el operador "." Accedemos a estos campos de usuario2 y le asignamos los literales constantes 33 y 'M', respectivamente.

• La declaración e inicialización de las variables fecha1 y fecha2 (líneas 31-36) se ha implementado de manera similar a la explicada para usuario1 y usuario2.

Page 241: INFORMÁTICA Libro de Problemas

242 | Informática. Libro de problemas

• Por último, la función main() debe mostrar por pantalla los datos almacenados en las variables usuario1, usuario2, fecha1 y fecha2. Para ello, se invocarán a las funciones imprimirUsuario() e imprimirFecha(), a las cuales, como en sus declaraciones (líneas 19-20) se muestra, les pasaremos los registros correspondientes como parámetros de entrada.

• La función imprimirUsuario() se define en las líneas 53-58 de la siguiente forma: void imprimirUsuario(tipoPersona p) { printf("Nombre:\t%s\n", p.nombre); printf("Edad:\t%hd\n", p.edad); printf("Sexo:\t%s\n\n", p.sexo == 'V' ? "Varon" : "Mujer"); }

o Para imprimir los campos de un registro se hace uso de la función printf(), de la misma forma que se ha visto en los capítulos anteriores. La única diferencia radica en la forma de acceder a las variables que se desean imprimir. En este caso, son campos de un registro y hacemos uso de 3 componentes: nombre de la variable registro, el operador "." y el nombre del campo.

o Así, en esta función, p es el nombre asignado a la variable registro que se recibe como parámetro de entrada a la función. Por tanto, para acceder al nombre, se usa p.nombre, para acceder a la edad se usa p.edad y, finalmente, para acceder al sexo se usa p.sexo.

o Por último, para imprimir el sexo de la persona (línea 57) se usa el operador ?, de forma que si lo que tiene p.sexo es una 'V', entonces se imprimirá "Varon" o, en caso contrario, "Mujer".

• La función imprimirFecha() se define en las líneas 60-65 de forma muy similar a la vista en imprimirUsuario().

11.2. Fracciones

Escriba un programa que implemente las operaciones de suma, resta, multiplicación y división de dos fracciones. El programa se iniciará solicitando al usuario los valores (de tipo entero) de dos fracciones. Seguidamente deberá mostrar un menú donde el usuario pueda seleccionar aquella operación que desea realizar. A continuación, se muestran diversos ejemplos de ejecución que ilustran el comportamiento esperado del programa:

Page 242: INFORMÁTICA Libro de Problemas

Capítulo 11: Registros | 243

Ejemplo 1 de ejecución Introduzca primera fraccion (num/num) 2/3 Introduzca segunda fraccion (num/num) -4/5 ¿Que operacion desea realizar? 1) Sumar 2) Restar 3) Multiplicar 4) Dividir Introduzca su eleccion: 1 El resultado es -2/15

Ejemplo 2 de ejecución Introduzca primera fraccion (num/num) 3/2 Introduzca segunda fraccion (num/num) 7/8 ¿Que operacion desea realizar? 1) Sumar 2) Restar 3) Multiplicar 4) Dividir Introduzca su eleccion: 2 El resultado es 10/16

Ejemplo 3 de ejecución Introduzca primera fraccion (num/num) -5/8 Introduzca segunda fraccion (num/num) -7/3 ¿Que operacion desea realizar? 1) Sumar 2) Restar 3) Multiplicar 4) Dividir Introduzca su eleccion: 3 El resultado es 35/24

Ejemplo 4 de ejecución Introduzca primera fraccion (num/num) 9/5 Introduzca segunda fraccion (num/num) 3/2 ¿Que operacion desea realizar? 1) Sumar 2) Restar 3) Multiplicar 4) Dividir Introduzca su eleccion: 4 El resultado es 18/15

Ejemplo 5 de ejecución Introduzca primera fraccion (num/num) 8/9 Introduzca segunda fraccion (num/num) 3/4 ¿Que operacion desea realizar? 1) Sumar 2) Restar 3) Multiplicar 4) Dividir Introduzca su eleccion: 8 Opcion incorrecta.

Page 243: INFORMÁTICA Libro de Problemas

244 | Informática. Libro de problemas

Posible solución: Código 11.2

1. #include <stdio.h> 2. struct fraccion { // Cociente de dos números enteros 3. int numerador; 4. int denominador; 5. }; 6. typedef struct fraccion tipoFraccion; 7. tipoFraccion sumar(tipoFraccion frac1, tipoFraccion frac2); 8. tipoFraccion restar(tipoFraccion frac1, tipoFraccion frac2); 9. tipoFraccion multiplicar(tipoFraccion frac1, tipoFraccion frac2); 10. tipoFraccion dividir(tipoFraccion frac1, tipoFraccion frac2); 11. 12. int main(void) 13. { 14. tipoFraccion f1, f2, res; 15. short op; 16. printf("Introduzca primera fraccion (num/num) "); 17. scanf("%d/%d", &f1.numerador, &f1.denominador); 18. 19. printf("Introduzca segunda fraccion (num/num) "); 20. scanf("%d/%d", &f2.numerador, &f2.denominador); 21. 22. printf("%cQue operacion desea realizar?\n", 168); 23. printf("\t 1) Sumar\n"); 24. printf("\t 2) Restar\n"); 25. printf("\t 3) Multiplicar\n"); 26. printf("\t 4) Dividir\n"); 27. printf("Introduzca su eleccion: "); 28. scanf("%hd", &op); 29. 30. switch(op) { 31. case 1: 32. res = sumar(f1, f2); 33. break; 34. case 2: 35. res = restar(f1, f2); 36. break; 37. case 3: 38. res = multiplicar(f1, f2); 39. break; 40. case 4: 41. res = dividir(f1, f2); 42. break; 43. default: 44. printf("Opcion incorrecta.\n"); 45. } 46. if(op >= 1 && op <= 4) 47. printf("El resultado es %d/%d \n", res.numerador, res.denominador); 48. return 0; 49. } 50. 51. tipoFraccion sumar(tipoFraccion frac1, tipoFraccion frac2) 52. { 53. tipoFraccion r; 54. if(frac1.denominador == frac2.denominador) {

Page 244: INFORMÁTICA Libro de Problemas

Capítulo 11: Registros | 245

55. // Suma de fracciones con igual denominador 56. r.denominador = frac1.denominador; 57. r.numerador = frac1.numerador + frac2.numerador; 58. } else { 59. // Suma de fracciones con distinto denominador 60. r.denominador = frac1.denominador * frac2.denominador; 61. r.numerador = frac1.numerador * frac2.denominador + frac2.numerador * fr

ac1.denominador; 62. } 63. return r; 64. } 65. 66. tipoFraccion restar(tipoFraccion frac1, tipoFraccion frac2) 67. { 68. tipoFraccion r; 69. if(frac1.denominador == frac2.denominador) { 70. // Resta de fracciones con igual denominador 71. r.denominador = frac1.denominador; 72. r.numerador = frac1.numerador - frac2.numerador; 73. } else { 74. // Resta de fracciones con distinto denominador 75. r.denominador = frac1.denominador * frac2.denominador; 76. r.numerador = frac1.numerador * frac2.denominador - frac2.numerador * fr

ac1.denominador; 77. } 78. return r; 79. } 80. 81. tipoFraccion multiplicar(tipoFraccion frac1, tipoFraccion frac2) 82. { 83. tipoFraccion r; 84. r.numerador = frac1.numerador * frac2.numerador; 85. r.denominador = frac1.denominador * frac2.denominador; 86. return r; 87. } 88. 89. tipoFraccion dividir(tipoFraccion frac1, tipoFraccion frac2) 90. { 91. tipoFraccion r; 92. r.numerador = frac1.numerador * frac2.denominador; 93. r.denominador = frac1.denominador * frac2.numerador; 94. return r; 95. }

Comentarios:

• En este ejercicio se crea el tipo de datos struct fracción (líneas 2-5), que es un registro que permite almacenar una fracción. El registro está formado por dos campos de tipo entero: numerador y denominador. Mediante typedef se define (línea 6) el nombre alternativo tipoFraccion, de manera que en nuestro código podremos declarar variables basadas en este tipo de registro empleando tipoFraccion en lugar de struct fraccion.

• Se declara el prototipo de cuatro funciones (líneas 7-10) para implementar las cuatro operaciones que se indican en el enunciado: suma, resta, multiplicación y división de

Page 245: INFORMÁTICA Libro de Problemas

246 | Informática. Libro de problemas

fracciones. Note cómo todas estas funciones van a devolver un resultado de tipo tipoFraccion. Así mismo, como parámetros de entrada, esperan recibir dos variables de tipo tipoFraccion, nombradas como frac1 y frac2.

• En la función main(), se declaran tres variables (línea 14) denominadas f1, f2 y res, todas de tipo tipoFraccion. Las dos primeras variables se inicializarán con los valores que introduzca el usuario por pantalla (líneas 17 y 20), mientras que la última (res) será la variable donde se guarde el resultado de la operación que haya seleccionado el usuario.

• La lectura por pantalla de los componentes de una fracción se realiza mediante el uso de la función scanf(). Vamos a analizar el código de la línea 17 encargado de recoger por teclado el numerador y denominador para el registro f1:

scanf("%d/%d", &f1.numerador, &f1.denominador);

o Observe que para acceder a los campos de una variable tipoFraccion se necesitan 3 elementos: el nombre de la variable, el operador "." y el nombre del campo.

o El manejo de los campos de un registro es el mismo que hemos aprendido para una variable normal. En este caso, anteponemos el operador & para indicar a scanf() el lugar donde debe almacenar los datos de tipo entero leídos por teclado.

• Seguidamente, mediante printf() se muestra el menú (líneas 22-27) al usuario. El usuario deberá elegir una opción tecleando un valor numérico, que es recogido mediante scanf() (línea 28) y se almacenará en la variable de tipo short llamada op.

• El menú se implementa con una estructura switch (líneas 30-45). Dependiendo del contenido de la variable op, se ejecutarán unas líneas de código diferentes. Fíjese que, para cada caso, se hará la invocación a la función que corresponda, asignando el valor devuelto por la función (registro tipoFraccion) a la variable res. Si el usuario indica como opción un valor entero no perteneciente al intervalo [1,4], entonces se imprimirá el mensaje "Opción incorrecta".

• Por último, en la función main(), se imprime el resultado. Note que la impresión está condicionada (línea 46) a que la opción introducida por el usuario sea válida. Una invocación a la función printf() (línea 47) se encarga de realizar la impresión por pantalla. Cabe destacar nuevamente la manera en que accedemos a los campos de la variable res: res.numerador y res.denominador.

• Las definiciones de las funciones (líneas 51-95) implementan las operaciones suma, resta, multiplicación y división de dos fracciones. La implementación de cada función hace lo siguiente:

o Se declara una variable de tipo tipoFraccion nombrada r para guardar el resultado.

o La operación entre fracciones se implementa accediendo a los campos numerador y denominador de las dos fracciones que se reciben como parámetro de entrada (frac1 y frac2) y de la variable r.

Page 246: INFORMÁTICA Libro de Problemas

Capítulo 11: Registros | 247

o La función finaliza devolviendo el contenido de la variable r mediante la sentencia return.

o Respecto a la manera de implementar las operaciones con fracciones, notar que la suma y resta de fracciones debe considerar si los denominadores son iguales o distintos.

11.3. Números complejos

Desarrolle un programa que permita al usuario comprobar si ha realizado de forma correcta una operación con números complejos. Inicialmente, el programa solicitará que introduzca dos números complejos. Para cada número complejo solicitara la parte real y la parte imaginaria, ambos valores tipo float. Seguidamente el programa preguntará por la operación que desea realizar. El programa debe soportar suma, resta y multiplicación de números complejos. Por último, el programa solicitará que introduzca el resultado que ha obtenido el usuario. El programa finalizará mostrando un mensaje que indique si el resultado calculado por el usuario es correcto. A continuación, se muestran diversos ejemplos de ejecución que ilustran el comportamiento esperado del programa: Ejemplo 1 de ejecución Digame un numero complejo (real,imaginaria): 3,4 Digame otro numero complejo (real,imaginaria): 6,2 Que operacion desea realizar con estos numeros complejos (+ - * )?+ Indique el resultado que usted ha calculado (real,imaginaria):9,6 Enhorabuena, su calculo es correcto !!

Ejemplo 2 de ejecución Digame un numero complejo (real,imaginaria): 3,7 Digame otro numero complejo (real,imaginaria): 2,8 Que operacion desea realizar con estos numeros complejos (+ - * )?- Indique el resultado que usted ha calculado (real,imaginaria):2,6 Su calculo es erroneo. Revise el resultado obtenido.

Ejemplo 3 de ejecución Digame un numero complejo (real,imaginaria): 6,7 Digame otro numero complejo (real,imaginaria): 2,5 Que operacion desea realizar con estos numeros complejos (+ - * )?/ La operacion solicitada no existe.

Page 247: INFORMÁTICA Libro de Problemas

248 | Informática. Libro de problemas

Posible solución: Código 11.3

1. #include <stdio.h> 2. struct complejo { 3. float r; // Parte real 4. float i; // Parte imaginaria 5. }; 6. typedef struct complejo tipoNumComplejo; 7. tipoNumComplejo sumaComplejos(tipoNumComplejo a, tipoNumComplejo b); 8. tipoNumComplejo restaComplejos(tipoNumComplejo a, tipoNumComplejo b); 9. tipoNumComplejo multiplicaComplejos(tipoNumComplejo a, tipoNumComplejo b); 10. 11. int main(void) 12. { 13. tipoNumComplejo c1, c2, cu, cr; 14. char op, error = 0; 15. printf("Digame un numero complejo (real,imaginaria): "); 16. scanf("%f,%f", &c1.r, &c1.i); 17. printf("Digame otro numero complejo (real,imaginaria): "); 18. scanf("%f,%f", &c2.r, &c2.i); 19. printf("Que operacion desea realizar con estos numeros complejos (+ - * )?")

; 20. fflush(stdin); 21. scanf("%c", &op); 22. switch(op) { 23. case '+': 24. cr = sumaComplejos(c1, c2); 25. break; 26. case '-': 27. cr = restaComplejos(c1, c2); 28. break; 29. case '*': 30. cr = multiplicaComplejos(c1, c2); 31. break; 32. default: 33. printf("La operacion solicitada no existe.\n"); 34. error = 1; // Marcamos verdad en variable error 35. } 36. if(!error) { 37. printf("Indique el resultado que usted ha calculado (real,imaginaria):"); 38. scanf("%f,%f", &cu.r, &cu.i); 39. 40. if(cu.r == cr.r && cu.i == cr.i) 41. printf("Enhorabuena, su calculo es correcto !! \n"); 42. else 43. printf("Su calculo es erroneo. Revise el resultado obtenido.\n"); 44. } 45. return 0; 46. } 47. 48. // Definición de funciones 49. tipoNumComplejo sumaComplejos(tipoNumComplejo a, tipoNumComplejo b) 50. { 51. tipoNumComplejo c; 52. c.r = a.r + b.r; 53. c.i = a.i + b.i;

Page 248: INFORMÁTICA Libro de Problemas

Capítulo 11: Registros | 249

54. return c; 55. } 56. 57. tipoNumComplejo restaComplejos(tipoNumComplejo a, tipoNumComplejo b) 58. { 59. tipoNumComplejo c; 60. c.r = a.r - b.r; 61. c.i = a.i - b.i; 62. return c; 63. } 64. 65. tipoNumComplejo multiplicaComplejos(tipoNumComplejo a, tipoNumComplejo b) 66. { 67. tipoNumComplejo c; 68. c.r = a.r * b.r - a.i * b.i; 69. c.i = a.r * b.i + a.i * b.r; 70. return c; 71. }

Comentarios:

• En este ejemplo se define el tipo de dato struct complejo (líneas 2-5) con dos campos: uno para almacenar la parte real (r) y otro la parte imaginaria (i) de un número complejo. Observe que estos campos son de tipo float. Al igual que en los ejercicios anteriores, usamos typedef (línea 6) para definir el nombre alternativo tipoNumComplejo. De este modo, en nuestro código podremos declarar de una forma más cómoda variables basadas en este tipo de registro empleando tipoNumComplejo en lugar de struct complejo.

• Se declaran tres funciones (líneas 7-9) para implementar las operaciones especificadas en el enunciado: suma, resta y multiplicación. Las funciones reciben, como parámetros de entrada, dos variables tipoNumComplejo. Así mismo, las tres funciones devuelven un valor tipoNumComplejo.

• En la línea 13 de la función main() se declaran las variables c1, c2, cr y cu .

o Las variables c1 y c2 van a almacenar los dos números complejos que introduzca el usuario. Como es de esperar, la recogida de información se realiza con scanf(), tal y como se observa en las líneas 16 y 18.

o La variable cr será donde se almacene el resultado de la operación que calculará el programa entre los números complejos c1 y c2. El cálculo lo realizará la función correspondiente.

o La variable cu será donde se guarde el resultado calculado por el usuario y que será recogido mediante scanf().

• Note que, al igual que en el anterior ejemplo, se ha optado por una estructura switch (líneas 22-35) para implementar el menú. En cada caso, se invoca a la función correspondiente y el resultado que devuelve se guarda en la variable cr. Observe que, a diferencia del anterior ejemplo, los case están determinados por literales carácter debido a que cada opción del menú viene identificada por un símbolo: "+" para la suma, "- "para

Page 249: INFORMÁTICA Libro de Problemas

250 | Informática. Libro de problemas

la resta y " * " para la multiplicación. Por lo tanto, es necesario en la instrucción default usar una variable, en este caso llamada error, para indicar si el usuario no ha introducido una opción válida.

• Seguidamente se implementa una estructura if (líneas 36-44) donde se comprueba el contenido de la variable error. Si dicha variable representa la verdad, es decir, contiene un valor distinto de cero, entonces el usuario ha introducido una opción del menú correcta. En este caso, se le solicita al usuario que introduzca el número complejo que ha obtenido como resultado de la operación (línea 37) y se guardará en la variable cu (línea 38).

• Después, mediante una estructura if-else (líneas 40-43) se comprueba si el número complejo facilitado por el usuario es igual al resultado que ha calculado el programa. Recordemos que en el switch se invocó a la función correspondiente y el resultado se almacenó en cr. En caso de ser igual, se mostrará un mensaje indicando que su resultado es correcto, y en caso contrario, se indicará que el resultado es erróneo.

• Las definiciones de las funciones que se encuentran en las líneas 49-71 implementan las tres operaciones sobre números complejos (suma, resta y multiplicación) solicitadas en el enunciado del ejercicio. Es importante apreciar que:

o Las tres funciones declaran un registro c de tipoNumComplejo para guardar el resultado.

o Los números complejos sobre los que realizar la operación son recibidos como parámetros de entrada por medio de dos reigstros (a y b) de tipoNumComplejo.

o El acceso a los campos de los registros a y b se hace siguiendo el procedimiento descrito en ejemplos anteriores.

o Todas las funciones finalizan devolviendo el contenido de c por medio de return.

11.4. Polígono

Escriba un programa que calcule el perímetro de un polígono. Para ello, primero solicitará al usuario el número de puntos que forman el polígono. A continuación, el programa solicitará al usuario las coordenadas (x, y) de todos los puntos que forman el polígono. El programa finalizará mostrando los lados del polígono (cada lado viene determinado por un punto de inicio y otro de fin) así como el perímetro del polígono. A continuación, se muestra un ejemplo de ejecución para clarificar el comportamiento del programa. Para ello se va a usar el polígono de ejemplo que se muestra en la siguiente imagen:

Page 250: INFORMÁTICA Libro de Problemas

Capítulo 11: Registros | 251

Ejemplo de ejecución ¿Cuantos puntos forman el poligono que desea crear?4 Introduzca el primer punto (x,y): 1,1 Introduzca el siguiente punto (x,y): 2,6 Introduzca el siguiente punto (x,y): 6,8 Introduzca el siguiente punto (x,y): 8,3 Lado 1: (1,1) -> (2,6) Lado 2: (2,6) -> (6,8) Lado 3: (6,8) -> (8,3) Lado 4: (8,3) -> (1,1) El perimetro del poligono es 22.24

Posible solución: Código 11.4

1. #include <math.h> 2. #include <stdio.h> 3. #define MAX_LADOS_POL 30 4. struct punto { 5. int x; 6. int y; 7. }; 8. typedef struct punto tipoPunto; 9. struct linea { 10. tipoPunto p_inicio; // registro anidado a registro punto 11. tipoPunto p_fin; 12. }; 13. typedef struct linea tipoLinea; 14. struct Poligono { 15. tipoLinea lados[MAX_LADOS_POL]; // registro anidado a registro linea 16. short numLados; 17. }; 18. typedef struct Poligono tipoPoligono; 19.

Page 251: INFORMÁTICA Libro de Problemas

252 | Informática. Libro de problemas

20. // Declaración de funciones 21. void crearLineasPoligono(tipoLinea lados[MAX_LADOS_POL], int c); 22. void mostrarLadosPoligono(tipoPoligono p); 23. float calcularPerimetro(tipoPoligono p); 24. 25. int main(void) 26. { 27. tipoPoligono miPoligono; 28. float perimetro; 29. printf("%cCuantos puntos forman el poligono que desea crear?", 168); 30. scanf("%hd", &miPoligono.numLados); 31. 32. // Solicitamos al usuario los puntos que conforman el polígono. 33. // A partir de los puntos deberemos determinar los lados. 34. crearLineasPoligono(miPoligono.lados, miPoligono.numLados); 35. 36. // Mostramos por pantalla los lados del polígono 37. mostrarLadosPoligono(miPoligono); 38. 39. // Calculamos el perímetro del polígono 40. perimetro = calcularPerimetro(miPoligono); 41. 42. // Mostramos por pantalla el valor calculado 43. printf("El perimetro del poligono es %.2f \n", perimetro); 44. return 0; 45. } 46. 47. // Definición de funciones 48. void crearLineasPoligono(tipoLinea lados[MAX_LADOS_POL], int c) 49. { 50. int i; 51. i = 0; 52. printf("Introduzca el primer punto (x,y): "); 53. scanf("%d,%d", &lados[i].p_inicio.x, &lados[i].p_inicio.y); 54. i++; 55. while(i < c) { 56. printf("Introduzca el siguiente punto (x,y): "); 57. scanf("%d,%d", &lados[i - 1].p_fin.x, &lados[i - 1].p_fin.y); 58. lados[i].p_inicio.x = lados[i - 1].p_fin.x; 59. lados[i].p_inicio.y = lados[i - 1].p_fin.y; 60. i++; 61. } 62. lados[i - 1].p_fin.x = lados[0].p_inicio.x; 63. lados[i - 1].p_fin.y = lados[0].p_inicio.y; 64. } 65. 66. void mostrarLadosPoligono(tipoPoligono p) 67. { 68. int i; 69. for(i = 0; i < p.numLados; i++) { 70. printf("Lado %d: (%d,%d) - (%d,%d) \n", i + 1, 71. p.lados[i].p_inicio.x, p.lados[i].p_inicio.y, 72. p.lados[i].p_fin.x, p.lados[i].p_fin.y); 73. } 74. } 75. 76. float distanciaEntre2Puntos(tipoPunto p1, tipoPunto p2) 77. { 78. // Aplicamos Teorema de Pitágoras 79. return sqrt(pow(p2.x - p1.x, 2) + pow(p2.y - p1.y, 2));

Page 252: INFORMÁTICA Libro de Problemas

Capítulo 11: Registros | 253

80. } 81. 82. float calcularPerimetro(tipoPoligono p) 83. { 84. int i; 85. float r = 0; 86. for(i = 0; i < p.numLados; i++) { 87. r += distanciaEntre2Puntos(p.lados[i].p_inicio, p.lados[i].p_fin); 88. } 89. return r; 90. }

Comentarios:

• La información necesaria para almacenar un polígono se ha modelado de la siguiente forma:

o Un punto indica una posición en el plano y viene definido por sus coordenadas (x, y).

o Una línea recta viene determinada por un punto inicial y un punto final.

o Un polígono es una figura geométrica plana compuesta por una secuencia finita de líneas rectas (llamadas lados) consecutivas que encierran una región en el plano.

• Teniendo en cuenta el modelo anterior, se ha realizado un diseño de registros anidados.

o Primero, se ha declarado el registro punto (líneas 4-8) que contiene dos campos x e y, que se corresponden con las coordenadas que definen un punto en el plano. Por simplicidad, asumimos que las coordenadas son valores numéricos de tipo entero con signo.

o En segundo lugar, se declara el registro línea (líneas 9-12) compuesto por dos campos de tipoPunto que indican el inicio y el fin de la línea.

o Por último, definimos el registro tipoPoligono, que se compone de dos campos:

(1) Un array llamado lados de tipoLinea. Este array almacena los lados que definen un polígono.

(2) Una variable de tipo short llamada numLados que contendrá el número de lados que tiene el polígono.

• La siguiente figura muestra de forma visual el anidamiento que existe entre los tres tipos de registros:

Page 253: INFORMÁTICA Libro de Problemas

254 | Informática. Libro de problemas

tipoPoligono tipoLinea tipoPunto

tipoLinea lados [MAX_LADOS_POL] tipoPunto p_inicio int x

short numLados; tipoPunto p_fin; int y

struct Poligono { tipoLinea lados[MAX_LADOS_POL]; short numLados; }; typedef struct Poligono tipoPoligono;

struct linea { tipoPunto p_inicio; tipoPunto p_fin; }; typedef struct linea tipoLinea;

struct punto { int x; int y; }; typedef struct punto tipoPunto;

• La lógica de este programa se localiza en tres funciones que se declaran (líneas 21-23) antes de la función main(): crearLineasPoligono(), mostrarLadosPoligono() y calcularPerimetro(). Como se puede observar, estas funciones modelan el comportamiento esperado del programa: definir un polígono a partir de una serie de puntos, mostrar por pantalla el polígono creado y calcular el perímetro del mismo. Más adelante explicaremos con detalle el código de cada función pues, sin duda, hay aspectos que merecen la pena destacar.

• Según lo comentado en el punto anterior, la función main() será liberada de tener que implementar todas aquellas tareas que requieren la manipulación de un polígono. Para cualquier operación que requiera acceder a los lados y/o puntos que forman un polígono, se ha definido una función. Concretamente, dentro de la función main() encontramos lo siguiente:

o Se declara una variable registro (línea 27) llamada miPoligono de tipoPoligono. Esta variable almacenará el polígono que defina el usuario.

o Se declara una variable (línea 28) llamada perimetro, de tipo float, que será donde guardemos el resultado del cálculo del perímetro.

o Se solicita al usuario (línea 29) que introduzca el número de puntos que forman el polígono. El valor se recoge mediante una llamada a la función scanf() (línea 30) de la siguiente forma:

scanf("%hd",&miPoligono.numLados);

El valor obtenido por teclado se almacena en el campo numLados del registro miPoligono. La manera de acceder a este campo sigue el mismo procedimiento visto en ejercicios anteriores.

o Seguidamente, la función main() invocará las diferentes funciones de manera secuencial, con el objetivo de implementar el comportamiento esperado.

(1) En primer lugar, se invoca la función crearLineasPoligono() (línea 34) cuyo objetivo es crear el polígono a partir de una serie de puntos. Esta función no devuelve ningún valor.

Page 254: INFORMÁTICA Libro de Problemas

Capítulo 11: Registros | 255

(2) En segundo lugar, se invoca a la función mostrarLadosPoligono() (línea 37) que se encargará de mostrar por pantalla los lados de polígono recién creado. Esta función no devuelve ningún valor.

(3) En tercer y último lugar, se invoca la función calcularPerimetro() (línea 40) que se encargará de calcular el perímetro del polígono que será devuelto como valor de tipo float.

o La función main() finaliza con una invocación a printf() (línea 43) para mostrar por pantalla el perímetro del polígono.

• En relación a la función crearLineasPoligono() (líneas 48-64) podemos destacar lo siguiente:

o Note que, a diferencia de las otras dos funciones que reciben como parámetro de entrada una variable de tipoPoligono, la función crearLineasPoligono recibe como parámetro de entrada el array de lados (tipoLinea lados [MAX_LADOS_POL]) y el número de lados (int c) que forman el polígono. Esto se debe hacer así por dos razones:

(1) Pasar como parámetro de entrada a una función una variable de tipo registro implica realizar una copia de todos los campos. Esta copia es la que se entrega a la función. Por lo tanto, cualquier cambio que la función realice sobre el registro que recibe será sobre la copia, no sobre el registro original que maneja la función main(). Esto es un problema para la función crearLineasPoligono() ya que su objetivo fundamental es modificar el array de lados.

(2) El paso de un array como parámetro de una función siempre se hace por referencia. Es decir, cualquier modificación que una función realice sobre un array que recibe como parámetro de entrada, será visible externamente por la función main(). Y esto es precisamente lo que necesita hacer la función crearLineasPoligono(), modificar el array lados que recibe como parámetro.

o Para crear los lados del polígono, esta función solicita al usuario que proporcione los puntos que lo conforman. La variable i de tipo entero (declarada en la línea 50) será fundamental a la hora de determinar el lado al que pertenece un punto facilitado por el usuario.

o Para comprender el comportamiento del código, debemos tener en cuenta que un punto pertenece a dos lados. Por ejemplo, dado el polígono que se ha usado para el ejemplo de ejecución, el punto (2,6) pertenece a "Lado 1" pero también a "Lado 2".

o Teniendo en cuenta esto, la construcción de los lados del polígono sigue el siguiente proceso.

(1) Se solicita al usuario que introduzca el primer punto del polígono (líneas 52-53). Este punto tiene un tratamiento especial, pues se asigna como punto de inicio del primer lado del polígono (i=0):

Page 255: INFORMÁTICA Libro de Problemas

256 | Informática. Libro de problemas

printf("Introduzca el primer punto (x,y): "); scanf("%d,%d", &lados[i].p_inicio.x, &lados[i].p_inicio.y);

(2) Seguidamente (línea 54) la variable i se incrementa en una unidad (i++), para referenciar al segundo lado del polígono (i=1)

(3) Ejecutamos un bucle while (línea 55) para solicitar el resto de puntos del polígono (condición de parada i<c).

(4) Para cada punto que introduce el usuario dentro del bucle while, se almacena dos veces. Por un lado, como punto final del lado anterior (i-1) (en la llamada a scanf() de la línea 57) y como punto inicial del lado actual (i) (líneas 58-59): scanf("%d,%d", &lados[i - 1].p_fin.x, &lados[i - 1].p_fin.y); lados[i].p_inicio.x = lados[i - 1].p_fin.x; lados[i].p_inicio.y = lados[i - 1].p_fin.y;

(5) La última instrucción del while (línea 60) incrementa la variable i en una unidad para avanzar al siguiente lado del polígono.

(6) Una vez finalizado el bucle while, hay que hacer un tratamiento especial (líneas 62-63) para el último lado del polígono: el punto final de este lado es el punto inicial del primer lado: lados[i-1].p_fin.x = lados[0].p_inicio.x; lados[i-1].p_fin.y = lados[0].p_inicio.y;

Tomando como ejemplo el polígono mostrado en la figura anterior, si asumimos que el usuario introduce los puntos en el orden (1,1) (2,6) (6,8) (8,3), vemos que para definir el "Lado 4" correctamente es necesario indicar como punto final el punto (1,1), que es el punto inicial del "Lado 1".

• En relación a la función mostrarLadosPoligono() (líneas 66-74), podemos destacar lo siguiente:

o Esta función recibe una variable llamada p de tipoPoligono.

o Haciendo uso de un bucle for (línea 69), se imprimen todos los lados del polígono. El número total de lados está almacenado en el campo numLados del registro p.

o Dentro de la invocación a la función printf(), observe el procedimiento que se aplica para acceder a las coordenadas de los puntos inicial y final de un lado.

printf("Lado %d: (%d,%d) -> (%d,%d) \n", i+1, p.lados[i].p_inicio.x, p.lados[i].p_inicio.y, p.lados[i].p_fin.x, p.lados[i].p_fin.y );

El método de acceso sigue basándose en usar el operador "." de manera repetitiva para viajar en el anidamiento de registros.

• Con relación a la función distanciaEntre2Puntos() (líneas 76-80), podemos destacar lo siguiente:

Page 256: INFORMÁTICA Libro de Problemas

Capítulo 11: Registros | 257

o Se trata de una función que sólo es invocada por la función calcularPerimetro(). Por este motivo, desde un punto de vista de diseño, es más elegante que la función no sea accesible para el main() y que, de alguna manera, quede oculta. Esto se consigue no declarando su prototipo al comienzo del programa, antes de la definición del main().

o La función recibe como parámetro de entrada dos registros de tipoPunto, nombrados como p1 y p2.

o La implementación de la función es extremadamente sencilla: se aplica el Teorema de Pitágoras para hallar la distancia entre los puntos p1 y p2. Asumiendo que p1=(x1,y1) y p2=(x2,y2) se aplica la siguiente fórmula:

𝑑𝑑𝑑𝑑𝑑𝑑𝑑𝑑𝑑𝑑𝑛𝑛𝑑𝑑𝑑𝑑𝑑𝑑 = �((𝑥𝑥2− 𝑥𝑥1)2 + (𝑦𝑦2 − 𝑦𝑦1)2)2

• Respecto a la función calcularPerimetro() (líneas 82-90), podemos destacar lo siguiente:

o Recibe como parámetro de entrada un registro de tipoPoligono llamado p.

o Hace uso de una variable local llamada r de tipo float, para almacenar el cálculo del perímetro del polígono. La variable es inicializada a cero para que el cálculo se efectúe de manera correcta.

o Mediante un bucle for (líneas 86-88) se recorren los lados del polígono. Las condiciones de inicio, parada e incremento se basan en el uso de la variable auxiliar i así como el número total de lados del polígono, que está disponible en el campo numLados del registro p. for (i=0; i < p.numLados; i++) { r+=distanciaEntre2Puntos(p.lados[i].p_inicio, p.lados[i].p_fin); }

o En cada iteración se calcula la distancia existente entre los dos puntos que forman un lado gracias a la invocación de la función distanciaEntre2Puntos().

11.5. Pacientes hospital

El Ministerio de Defensa necesita el desarrollo de un programa que permita gestionar los pacientes ingresados en un hospital de campaña. Para cada paciente, se desea conocer su nombre (máximo 20 caracteres), apellidos (máximo 40 caracteres cada uno), edad, sexo, teléfono y su domicilio. Los datos relativos a su domicilio lo forman la calle (máximo 50 caracteres), el número, código postal y la ciudad (máximo 20 caracteres). La capacidad máxima del hospital de campaña es de 100 pacientes. El programa deberá hacer uso de un conjunto de tipo de datos adecuado y ser modular a través del correcto uso de funciones. Además, como parte del proceso de arranque del

Page 257: INFORMÁTICA Libro de Problemas

258 | Informática. Libro de problemas

programa, se debe inicializar las estructuras de datos del programa con, al menos, dos pacientes. El programa debe ofrecer un menú que soporte las siguientes operaciones:

(1) Listar pacientes hospital. El programa mostrará toda la información disponible sobre los pacientes ingresados en el hospital de campaña.

(2) Ingresar nuevo paciente. El programa solicitará toda la información necesaria sobre el nuevo paciente para incorporarlo a la lista de pacientes ingresados. El programa avisará si el hospital de campaña ha alcanzado su máximo y no es posible ingresar el paciente.

(3) Dar de alta paciente. El programa solicitará el nombre y apellidos del paciente que va a ser dado de alta. El programa deberá avisar si el paciente no se encuentra ingresado en el hospital de campaña.

A continuación, se muestra un ejemplo de ejecución del programa que ejemplifica el comportamiento esperado: Ejemplo de ejecución ---------------- MENU ---------------- a) Listar pacientes hospital b) Ingresar nuevo paciente c) Dar de alta paciente d) Salir del programa Seleccione una opcion del menu (letra en minuscula): a Existen 2 pacientes ingresados PACIENTE 1 Jose Perez Lopez, varon de 47 años Reside en C/ Gran Via, 12. CP: 31456. Murcia PACIENTE 2 Ana Sanchez Castillo, mujer de 62 años Reside en C/ Calle Mayor, 24. CP: 12445. Madrid ---------------- MENU ---------------- a) Listar pacientes hospital b) Ingresar nuevo paciente c) Dar de alta paciente d) Salir del programa Seleccione una opcion del menu (letra en minuscula): e ---------------- MENU ---------------- a) Listar pacientes hospital b) Ingresar nuevo paciente

Page 258: INFORMÁTICA Libro de Problemas

Capítulo 11: Registros | 259

c) Dar de alta paciente d) Salir del programa Seleccione una opcion del menu (letra en minuscula): b Nombre: Pedro Primer apellido: Perez Segundo apellido: Alcaraz Edad: 42 Sexo (V/M): V Calle: Coronel Ruiz Maya Numero: 35 Codigo postal: 43123 Ciudad: Valencia Telefono:543786123 ---------------- MENU ---------------- a) Listar pacientes hospital b) Ingresar nuevo paciente c) Dar de alta paciente d) Salir del programa Seleccione una opcion del menu (letra en minuscula): a Existen 3 pacientes ingresados PACIENTE 1 Jose Perez Lopez, varon de 47 años Reside en C/ Gran Via, 12. CP: 31456. Murcia PACIENTE 2 Ana Sanchez Castillo, mujer de 62 años Reside en C/ Calle Mayor, 24. CP: 12445. Madrid PACIENTE 3 Pedro Perez Alcaraz, varon de 42 años Reside en C/ Coronel Ruiz Maya, 35. CP: 43123. Valencia ---------------- MENU ---------------- a) Listar pacientes hospital b) Ingresar nuevo paciente c) Dar de alta paciente d) Salir del programa Seleccione una opcion del menu (letra en minuscula): c Introduzca nombre:Ana Introduzca apellido 1:Sanchez Introduzca apellido 2:Castillo Paciente eliminado!! ---------------- MENU ---------------- a) Listar pacientes hospital b) Ingresar nuevo paciente c) Dar de alta paciente d) Salir del programa Seleccione una opcion del menu (letra en minuscula): a Existen 2 pacientes ingresados

Page 259: INFORMÁTICA Libro de Problemas

260 | Informática. Libro de problemas

PACIENTE 1 Jose Perez Lopez, varon de 47 años Reside en C/ Gran Via, 12. CP: 31456. Murcia PACIENTE 2 Pedro Perez Alcaraz, varon de 42 años Reside en C/ Coronel Ruiz Maya, 35. CP: 43123. Valencia ---------------- MENU ---------------- a) Listar pacientes hospital b) Ingresar nuevo paciente c) Dar de alta paciente d) Salir del programa Seleccione una opcion del menu (letra en minuscula): d

Posible solución: Código 11.5

1. #include <stdio.h> 2. #include <string.h> 3. 4. #define MAX_NOMBRE 20 5. #define MAX_APELLIDO 40 6. #define MAX_CALLE 50 7. #define MAX_CIUDAD 20 8. #define MAX_PACIENTES 100 9. 10. struct domicilio { 11. char calle[MAX_CALLE]; 12. short numero; 13. int postal; 14. char ciudad[MAX_CIUDAD]; 15. }; 16. typedef struct domicilio tipoDomicilio; 17. 18. struct paciente { 19. char nombre[MAX_NOMBRE]; 20. char apellido1[MAX_APELLIDO]; 21. char apellido2[MAX_APELLIDO]; 22. short edad; 23. char sexo; 24. tipoDomicilio dom; 25. int telefono; 26. }; 27. typedef struct paciente tipoPaciente; 28. 29. struct hospital { 30. tipoPaciente listaPacientes[MAX_PACIENTES]; 31. short pi; // Pacientes ingresados 32. }; 33. typedef struct hospital tipoHospital;

Page 260: INFORMÁTICA Libro de Problemas

Capítulo 11: Registros | 261

34. 35. void mostrarPaciente(tipoPaciente p); 36. tipoPaciente crearPaciente(); 37. 38. int main(void) 39. { 40. char opcion; 41. short i, j; 42. char nom[MAX_NOMBRE]; 43. char ap1[MAX_APELLIDO]; 44. char ap2[MAX_APELLIDO]; 45. tipoHospital hospitalAGA; 46. hospitalAGA.pi = 0; 47. 48. // Insertamos primer paciente 49. tipoDomicilio dom = { "Gran Via", 12, 31456, "Murcia" }; 50. tipoPaciente pac = { "Jose", "Perez", "Lopez", 47, 'V', dom, 654123789 }; 51. hospitalAGA.listaPacientes[hospitalAGA.pi] = pac; 52. hospitalAGA.pi++; 53. 54. // Insertamos segundo paciente 55. strcpy(dom.calle, "Calle Mayor"); 56. dom.numero = 24; 57. dom.postal = 12445; 58. strcpy(dom.ciudad, "Madrid"); 59. 60. strcpy(pac.nombre, "Ana"); 61. strcpy(pac.apellido1, "Sanchez"); 62. strcpy(pac.apellido2, "Castillo"); 63. pac.edad = 62; 64. pac.sexo = 'M'; 65. pac.dom = dom; 66. pac.telefono = 41248956; 67. 68. hospitalAGA.listaPacientes[hospitalAGA.pi] = pac; 69. hospitalAGA.pi++; 70. 71. do { 72. printf("\n----------------\n"); 73. printf("MENU"); 74. printf("\n----------------\n"); 75. printf("a) Listar pacientes hospital \n"); 76. printf("b) Ingresar nuevo paciente \n"); 77. printf("c) Dar de alta paciente \n"); 78. printf("d) Salir del programa \n"); 79. printf("Seleccione una opcion del menu (letra en minuscula):"); 80. fflush(stdin); 81. scanf(" %c", &opcion); 82. switch(opcion) { 83. case 'a': 84. printf("Existen %d pacientes ingresados\n", hospitalAGA.pi); 85. for(i = 0; i < hospitalAGA.pi; i++) { 86. printf("\nPACIENTE %d \n", i + 1); 87. mostrarPaciente(hospitalAGA.listaPacientes[i]); 88. } 89. break; 90. case 'b': 91. hospitalAGA.listaPacientes[hospitalAGA.pi] = crearPaciente(); 92. hospitalAGA.pi++; 93. break;

Page 261: INFORMÁTICA Libro de Problemas

262 | Informática. Libro de problemas

94. case 'c': 95. printf("Introduzca nombre:"); 96. fflush(stdin); 97. gets(nom); 98. printf("Introduzca apellido 1:"); 99. fflush(stdin); 100. gets(ap1); 101. printf("Introduzca apellido 2:"); 102. fflush(stdin); 103. gets(ap2); 104. 105. for(i = 0; i < hospitalAGA.pi; i++) { 106. if(strcmp(nom, hospitalAGA.listaPacientes[i].nombre) == 0 && 107. strcmp(ap1, hospitalAGA.listaPacientes[i].apellido1) == 0 && 108. strcmp(ap2, hospitalAGA.listaPacientes[i].apellido2) == 0) 109. break; 110. } 111. 112. if(i < hospitalAGA.pi) { 113. for(j = i + 1; j < hospitalAGA.pi; j++) 114. hospitalAGA.listaPacientes[j-1]=hospitalAGA.listaPacientes[j]; 115. hospitalAGA.pi--; 116. printf("Paciente eliminado!!"); 117. } else 118. printf("Error. Paciente no encontrado."); 119. 120. break; 121. } 122. } while(opcion != 'd'); 123. return 0; 124. } 125. 126. void mostrarPaciente(tipoPaciente p) { 127. printf("\t%s %s %s, %s de %hd a%cos \n", p.nombre, p.apellido1, 128. p.apellido2, p.sexo == 'V' ? "varon" : "mujer", p.edad, 164); 129. printf("\tReside en C/ %s, %hd. CP: %d. %s\n\n ", p.dom.calle, 130. p.dom.numero, p.dom.postal, p.dom.ciudad); 131. } 132. 133. tipoPaciente crearPaciente() 134. { 135. tipoPaciente p; 136. 137. printf("Nombre: "); 138. fflush(stdin); 139. gets(p.nombre); 140. 141. printf("Primer apellido: "); 142. fflush(stdin); 143. gets(p.apellido1); 144. 145. printf("Segundo apellido: "); 146. fflush(stdin); 147. gets(p.apellido2); 148. 149. printf("Edad: "); 150. fflush(stdin); 151. scanf("%hd", &p.edad); 152. 153. printf("Sexo (V/M): ");

Page 262: INFORMÁTICA Libro de Problemas

Capítulo 11: Registros | 263

154. fflush(stdin); 155. scanf("%c", &p.sexo); 156. 157. printf("Calle: "); 158. fflush(stdin); 159. gets(p.dom.calle); 160. 161. printf("Numero: "); 162. fflush(stdin); 163. scanf("%hd", &p.dom.numero); 164. 165. printf("Codigo postal: "); 166. fflush(stdin); 167. scanf("%d", &p.dom.postal); 168. 169. printf("Ciudad: "); 170. fflush(stdin); 171. gets(p.dom.ciudad); 172. 173. printf("Telefono:"); 174. fflush(stdin); 175. scanf("%d", &p.telefono); 176. 177. return p; 178. }

Comentarios:

• Si analizamos la información que debe manipular el programa, podemos extraer dos conclusiones:

o La información que define el domicilio en el que reside un paciente se debe manejar como un conjunto de datos relacionados que es conveniente agrupar. Por este motivo se creará un nuevo tipo de datos agregado que, atendiendo a las instrucciones del enunciado, contenga: calle, número, código postal y ciudad.

o La información relacionada con un paciente también se debe tratar como un conjunto de datos que es conveniente agrupar. Por ello, se creará un nuevo tipo de datos agregado que almacenará: nombre, primer y segundo apellido, edad, sexo, domicilio en que reside y teléfono. Como observamos, la inclusión del domicilio provocará que debamos recurrir al uso de registros anidados.

• Teniendo en cuenta lo anterior, el programa define tres nuevos tipos de datos basados en registros:

o En primer lugar, se declara el tipo de datos struct Domicilio (líneas 10-15), que se empleará para almacenar todos los datos relacionados con la dirección donde reside un paciente. Este registro contiene cuatro campos: dos de ellos son cadenas (calle y ciudad) y los restantes (numero y postal) de tipo entero. El tipo strut

Page 263: INFORMÁTICA Libro de Problemas

264 | Informática. Libro de problemas

Domicilio se redefine como tipoDomicilio por medio de typedef (línea 16), lo que facilitará la futura declaración de variables basadas en este nuevo tipo de dato.

o En segundo lugar, se declara el tipo struct paciente (líneas 18-16), que servirá para almacenar toda la información relacionada con un paciente que se encuentra ingresado en el hospital. Este registro contiene ocho campos: tres cadenas (nombre, primer y segundo apellido), dos de tipo entero (edad y telefono), uno de tipo carácter (sexo) y otro de tipoDomicilio (domicilio donde reside el paciente). Este último campo es el que origina el anidamiento de registros explicado anteriormente.

o En tercer lugar, se declara el tipo struct hospital (líneas 29-32), que servirá para almacenar la información de todos los pacientes ingresados en el hospital. Este registro sólo contiene dos campos: un array (llamado listaPacientes) de elementos tipoPaciente (dimensión 100, tal y como indica el enunciado del problema) y una variable de tipo entero corto (llamada pi) que almacenará el número de pacientes ingresados en el hospital. El contenido de pi es muy importante ya que de manera implícita nos informa del número de elementos que realmente se están usando del array listaPacientes.

La siguiente figura muestra de forma visual los nuevos tipos de datos basados en registros y el anidamiento que existe:

Page 264: INFORMÁTICA Libro de Problemas

Capítulo 11: Registros | 265

struct hospital { short pi; // Pacientes ingresados tipoPaciente listaPacientes[MAX_PACIENTES]; }; typedef struct hospital tipoHospital;

tipoHospital short pi; tipoPaciente listaPacientes[MAX_PACIENTES];

tipoPaciente tipoDomicilio char nombre[MAX_NOMBRE]; char calle[MAX_CALLE]; char apellido1[MAX_APELLIDO]; short numero; char apellido2[MAX_APELLIDO]; int postal;

short edad; char ciudad[MAX_CIUDAD];

char sexo; tipoDomicilio dom; int telefono;

struct paciente { char nombre[MAX_NOMBRE]; char apellido1[MAX_APELLIDO]; char apellido2[MAX_APELLIDO]; short edad; char sexo; tipoDomicilio dom; int telefono; }; typedef struct paciente tipoPaciente;

struct domicilio { char calle[MAX_CALLE]; short numero; int postal; char ciudad[MAX_CIUDAD]; }; typedef struct domicilio tipoDomicilio;

• A diferencia de la solución propuesta para el Ejercicio 11.4, el programa propuesto opta

por incluir la lógica de funcionamiento en la función principal main(). No obstante, se han definido dos funciones auxiliares: mostrarPaciente() y crearPaciente(). Como se puede intuir por su nombre, estas funciones servirán de apoyo a la hora de mostrar por pantalla toda la información de un paciente que se encuentre ingresado en el hospital, así como en la creación de las estructuras de datos necesarias para almacenar nuevos pacientes que son ingresados. Más adelante explicaremos con detalle el código de estas funciones.

Page 265: INFORMÁTICA Libro de Problemas

266 | Informática. Libro de problemas

• Respecto al uso de variables en la función main(), observamos que se declaran las siguientes (líneas 40-44):

o opcion: variable de tipo char que almacenará la opción del menú seleccionada por el usuario.

o i y j: variables de tipo entero corto con signo que servirán de ayuda a la hora de recorrer arrays.

o nom, ap1 y ap2: cadenas auxiliares que servirán para almacenar temporalmente datos recogidos por teclado de un paciente.

o hospitalAGA: esta variable de tipoHospital es una de las más importantes ya que contendrá toda la información que el programa debe almacenar para cada paciente hospitalizado. Inicialmente el hospital no tiene pacientes ingresados, por lo que el campo pi se inicializa a cero.

• A continuación, la función main() atiende la petición que hace el ejercicio de inicializar las estructuras de datos del programa con, al menos, dos pacientes. Para realizar esta inserción de pacientes nos apoyaremos en el uso de los registros dom y pac de tipoDomicilio y tipoPaciente, respectivamente. Para realizar una correcta inicialización de los campos deun registro debemos distinguir dos situaciones:

o Inicialización en el momento de la declaración del registro. Se puede realizar de dos formas distintas: (1) indicando la lista de constantes separadas por comas y llaves (respetando el orden de declaración de los campos de la estructura) o (2) mediante inicializadores designados. El código propuesto (líneas 49-50) aplica la primera forma para inicializar las variables dom y pac con los datos del primer paciente:

tipoDomicilio dom = {"Gran Via", 12, 31456, "Murcia"}; tipoPaciente pac = {"Jose", "Perez", "Lopez", 47, 'V', dom, 654123789};

Recordemos que la variable pac contiene un campo que, a su vez, es un registro (de tipoDomicilio). Para inicializar los valores de este campo el código anterior se apoya en la variable dom. Sin embargo, podríamos evitar el uso de la variable dom si lo hacemos de la siguiente manera:

tipoPaciente pac = { "Jose", "Perez", "Lopez", 47, 'V', {"Gran Via",12,31456,"Murcia"},654123789};

Por último, si deseamos optar por el uso de inicializadores designados, entonces podemos realizar esta inicialización empleando el siguiente código: tipoDomicilio dom = {.calle="Gran Via", .ciudad="Murcia", .postal=31456, .numero=12 }; tipoPaciente pac = {.apellido1="Perez", .apellido2="Lopez", .nombre="Jose",.sexo='V', .edad=47, .dom=dom, .telefono=654123789};

Page 266: INFORMÁTICA Libro de Problemas

Capítulo 11: Registros | 267

Observe que el orden en el que se proporcionan los valores para cada campo no es necesario que respete el mismo orden en que fueron declarados al definir los tipos de datos struct domicilio y struct paciente.

o Inicialización en un momento posterior a la declaración del registro. Para insertar los datos del segundo paciente no podemos aplicar el procedimiento que acabamos de explicar para el primer paciente, salvo que optemos por declarar nuevas variables registro de tipoDomicilio y tipoPaciente, lo cuál sería un uso ineficiente de recursos dadas las pretensiones del programa. Es por ello que debemos optar por modificar los valores contenidos en los registros dom y pac para lograr la inserción del segundo paciente. Para hacer esta inicialización, bastará con acceder a cada campo del registro y modificar su valor de manera independiente. Esto se puede observar en las líneas 55-66 del programa.

• Es importante comprender el funcionamiento del código (líneas 51-52 y 68-69) que se encarga de insertar un nuevo paciente en el hospital:

hospitalAGA.listaPacientes[hospitalAGA.pi] = pac; hospitalAGA.pi++;

Para realizar la inserción manejamos los campos del registro hospitalAGA. Por un lado, los pacientes ingresados se encuentran en el campo listaPacientes, que es un array de registros tipoPaciente. Dado que el campo pi nos indica el número de pacientes ingresados en el hospital, podemos emplear su valor para localizar la posición correcta del array donde deberemos almacenar una copia de la variable pac que, según hemos explicado anteriormente, contiene los datos del nuevo paciente. Los pasos que se siguen para la inserción de los dos primeros pacientes es la siguiente:

o Inicialmente, el campo pi tiene el valor 0. Por lo tanto, el código de la línea 51 del programa inserta el primer paciente en la posición hospitalAGA.listaPacientes[0].

o Seguidamente, en la línea 52 incrementamos el valor de pi en una unidad, de modo que pi pasa a valer 1.

o Cuando procedamos a insertar el segundo paciente (línea 68) accederemos a la posición hospitalAGA.listaPacientes[1].

o Seguidamente, en la línea 69 incrementamos el valor de pi en una unidad, de modo que pi pasa a valer 2.

• De manera similar a como hemos visto en ejemplos anteriores, el menú del programa se construye por medio de una estructura switch que, en este caso, se encuentra dentro de un do-while necesario para conseguir que el menú se muestre al usuario de manera repetitiva, después de ejecutar la opción seleccionada.

• El listado de los pacientes ingresados en el hospital (opción 'a' del menú, línea 83) se basa en recorrer el array hospitalAGA.listaPacientes aplicando las técnicas ya conocidas

Page 267: INFORMÁTICA Libro de Problemas

268 | Informática. Libro de problemas

de iteración (líneas 85-88) sobre los elementos de un array. Para la impresión por pantalla de los datos de un paciente determinado se recurre a la función mostrarPaciente().

• El ingreso de un nuevo paciente (opción ' b' del menú, línea 90) se implementa de manera muy similar a como antes se ha realizado la inserción manual de los dos primeros pacientes. Sin embargo, en este caso, los datos del nuevo paciente son recogidos por pantalla haciendo uso de la función crearPaciente().

• El alta de un paciente (opción 'c' del menú, línea 94) es un proceso que tiene varias particularidades que merece la pena explicar con detenimiento:

o El programa solicita el nombre y apellidos del paciente (líneas 95-103) que se va a proceder a dar de alta. La recogida de la información se realiza por medio de gets()y se almacena en las cadenas nom, ap1, ap2.

o Seguidamente se itera sobre el array hospitalAGA.listaPacientes (líneas 105-110) para buscar la posición que ocupa el paciente indicado por el usuario.

for(i = 0; i < hospitalAGA.pi; i++) { if(strcmp(nom,hospitalAGA.listaPacientes[i].nombre) ==0 && strcmp(ap1,hospitalAGA.listaPacientes[i].apellido1)==0 && strcmp(ap2,hospitalAGA.listaPacientes[i].apellido2) ==0 ) break; }

Observe que, para cada registro tipoPaciente almacenado en el array, se usa la función strcmp() para comparar los campos nombre, apellido1 y apellido2 con los datos indicados por el usuario. Si la búsqueda tiene éxito se provocará la ruptura del bucle mediante break.

o A continuación, se implementa una estructura if - else (líneas 112-121) que evalúa la condición i<hospitalAGA.pi. Si la condición es verdadera entonces la anterior ejecución del bucle for encontró el registro del paciente indicado por el usuario y se procederá al borrado del elemento dentro del array.

if (i< hospitalAGA.pi){ /** CODIGO NECESARIO PARA BORRAR EL PACIENTE **/ printf("Paciente eliminado!!"); } else printf("Error. El paciente no encontrado.");

o El borrado de un paciente del array hospitalAGA.listaPacientes se ha implementado de manera que preserva que todos los pacientes ingresados en el hospital se encuentran almacenados de manera consecutiva en las primeras posiciones del array hospitalAGA.listaPacientes. El código empleado es el siguiente (líneas 113-115):

for(j=i+1; j<hospitalAGA.pi; j++) hospitalAGA.listaPacientes[j-1] = hospitalAGA.listaPacientes[j]; hospitalAGA.pi--;

Page 268: INFORMÁTICA Libro de Problemas

Capítulo 11: Registros | 269

(1) El anterior bucle for itera sobre todos los registros tipoPaciente que se almacenan en las posiciones posteriores al registro que se desea borrar.

(2) Cada registro almacenado en la posición j se "mueve" a la posición anterior, es decir, j-1. En realidad, no se mueve físicamente, sino que se hace una copia del registro, la cual se guarda en la posición inmediatamente anterior.

(3) Una vez completado el "movimiento" de registros, se actualiza el nuevo número de pacientes ingresados. Por este motivo decrementamos en una unidad el valor almacenado en el campo pi del registro hospitalAGA.

• Respecto a la definición de la función mostrarPaciente() (líneas 126-131), podemos destacar lo siguiente:

o Recibe como parámetro de entrada un registro tipoPaciente llamado p.

o Mediante dos invocaciones a la función printf() se formatea la impresión por pantalla de manera adecuada para mostrar todos los datos del paciente que se recibe como parámetro.

o El acceso a los campos del registro p se realiza empleando el mismo procedimiento visto en ejercicios anteriores. Sin embargo, es importante destacar como se realiza el acceso a campos pertenecientes a registros anidados gracias a la sucesiva concatenación del operador ".".

printf("\tReside en C/ %s, %hd. CP: %d. %s\n\n ", p.dom.calle, p.dom.numero, p.dom.postal,p.dom.ciudad);

• Respecto a la definición de la función crearPaciente() (líneas 133-178) destacamos lo siguiente:

o Su objetivo es inicializar un registro tipoPaciente con los datos proporcionados por el usuario por pantalla. Por ello, se declara un registro p de tipoPaciente como variable local.

o Los campos del registro p se inicializan accediendo de manera individual a cada campo conforme se van obteniendo mediante sucesivas invocaciones a las funciones scanf() y gets().

o Observe como la información recogida por pantalla se almacena directamente en los campos del registro p, de manera que evitamos la declaración de variables auxiliares con el propósito de almacenar la información recogida de teclado para, posteriormente, realizar una copia al correspondiente campo del registro.

Page 269: INFORMÁTICA Libro de Problemas