Curso Nestor Algoritmos y Estructura de Datos

108
. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 1 AL LECTOR: En tiempos en que nuestra sociedad sólo lleva a la juventud al FACILISMO, y no a lo productivo; Un tiempo en el que todos vivimos en una gran paradoja, y esto es que gastamos más pero tenemos menos, tenemos casas mas grandes pero hogares diminutos, tenemos más títulos pero menos sentido común, más conocimiento pero menos sabiduría, más expertos pero más problemas, más medicinas pero menos salud; y es que este es un tiempo en que hay personas más altas con caracteres más débiles, con más libertad y menos sonrisas; Y nos preguntamos ¿Dónde ESTA EL ERROR?, mucha gente habla de juventud malograda, pero esta juventud sigue a un padre a una guía, entonces ¿qué clase de guías somos?. Es esta la razón de estás obras por esto que debemos poner cada minuto de nuestro ser en mejorar según nuestras virtudes esta juventud de la cual somos guías. En esta oportunidad deseo presentar a ustedes, este manual de “ALGORITMIA Y ESTRUCTURA DE DATOS” producto del deseo de apoyar a una juventud pujante deseosa de aprender muchísimo más, de no ser uno más sino uno bueno. A usted bienvenido al curso de Algoritmia y Estructura de Datos. Este es un curso inicial que cubre aspectos fundamentales de la algoritmia y estructura de datos desarrollado en BORLAN C++, por lo mismo esta pensado para personas que se inician en la programación de computadoras. Este curso estará en constante mejora: periódicamente se revisará los contenidos, se añadirá más ejercicios, se reformulará algunos ejercicios existentes y se quitará los inadecuados. Por ahora el curso es para leerse en línea sin restricciones de ningún tipo y espero que para seguir así me hagan llegar sus comentarios y sugerencias, para saber si el curso es de utilidad. Agradecido a usted. Ing. Huaracha Velasquez Nestor. [email protected] [email protected] Dedicado a: Mi Madre, Padre y mi hermano Hugo que están en la gracia de Dios . Que fueron guía e inspiración en el forjamiento de mi persona. Ing. Nestor Huaracha Velasquez

description

Curso Nestor Algoritmos y Estructura de Datos

Transcript of Curso Nestor Algoritmos y Estructura de Datos

Page 1: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 1

AL LECTOR:

En tiempos en que nuestra sociedad sólo lleva a la juventud al FACILISMO, y no a lo productivo; Un tiempo en el que todos vivimos en una gran paradoja, y esto es que gastamos más pero tenemos menos, tenemos casas mas grandes pero hogares diminutos, tenemos más títulos pero menos sentido común, más conocimiento pero menos sabiduría, más expertos pero más problemas, más medicinas pero menos salud; y es que este es un tiempo en que hay personas más altas con caracteres más débiles, con más libertad y menos sonrisas; Y nos preguntamos ¿Dónde ESTA EL ERROR?, mucha gente habla de juventud malograda, pero esta juventud sigue a un padre a una guía, entonces ¿qué clase de guías somos?. Es esta la razón de estás obras por esto que debemos poner cada minuto de nuestro ser en mejorar según nuestras virtudes esta juventud de la cual somos guías.

En esta oportunidad deseo presentar a ustedes, este manual de “ALGORITMIA Y ESTRUCTURA DE DATOS” producto del deseo de apoyar a una juventud pujante deseosa de aprender muchísimo más, de no ser uno más sino uno bueno.

A usted bienvenido al curso de Algoritmia y Estructura de Datos. Este es un curso inicial que cubre aspectos fundamentales de la algoritmia y estructura de datos desarrollado en BORLAN C++, por lo mismo esta pensado para personas que se inician en la programación de computadoras. Este curso estará en constante mejora: periódicamente se revisará los contenidos, se añadirá más ejercicios, se reformulará algunos ejercicios existentes y se quitará los inadecuados. Por ahora el curso es para leerse en línea sin restricciones de ningún tipo y espero que para seguir así me hagan llegar sus comentarios y sugerencias, para saber si el curso es de utilidad. 

Agradecido a usted.

Ing. Huaracha Velasquez Nestor.

[email protected]@hotmail.com

Dedicado a:

Mi Madre, Padre y mi hermano Hugo que están en la gracia de Dios .Que fueron guía e inspiración en el forjamiento de mi persona.

Ing. Nestor Huaracha Velasquez

Page 2: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 2 INDICE:

Capítulo 1: Conceptos Básicos de Algoritmia .1. Algoritmo 2. Pseudo código 3. Variables 4. Literales 5. Instrucciones Algorítmicas Básicas6. Expresiones Aritméticas7. Expresiones Lógicas

Capítulo 2: Estructuras de Secuencia1. Concepto 2. Ejercicios

Capítulo 3: Estructuras de Selección1. Concepto 2. Estructura de Selección Simple SI 3. Estructura de Selección Doble SI-SINO 4. Estructura de Selección Doble en Cascada SI-SINO-SI5. Estructura de Selección Múltiple SEGÚN6. Ejercicios

Capitulo 4. Introducción al C++4.1 Esquema general de un computador 4.1.1 Partes o elementos de un computador 4.1.2 La memoria: bits, bytes, palabras 4.1.3 Identificadores 4.2 Concepto de "programa" 4.3 Concepto de "función" 4.3.1 Conceptos generales 4.3.2 Nombre, Valor de retorno y Argumentos de una función 4.3.3 La función main( ) 4.4 Tokens 4.4.1 Palabras clave del C 4.4.2 Identificadores 4.4.3 Constantes 4.4.4 Operadores 4.4.5 Separadores 4.4.6 Comentarios 4.5 Lenguaje C 4.5.1 Compilador4.5.2 Preprocesador4.5.3 Librería estándar 4.6 Ficheros 4.7 Lectura y escritura de datos 4.8 Interfaz con el sistema operativo

Capitulo 5. TIPOS DE DATOS FUNDAMENTALES. VARIABLES 5.1 Caracteres (tipo char) 5.2 Números enteros (tipo int) 5.3 Números enteros (tipo long)5.4 Números reales (tipo float) 5.5 Números reales (tipo double) 5.6 Duración y visibilidad de las variables: Modos de almacenamiento. 5.7 Conversiones de tipo implícitas y explícitas(casting)

Capítulo 6. CONSTANTES 6.1 Constantes numéricas 6.1.1 Constantes enteras. 6.1.2 Constantes de punto flotante 6.2 Constantes carácter 6.3 Cadenas de caracteres 6.4 Constantes de tipo Enumeración 6.4.1 Cualificador const

Capitulo 7. OPERADORES, EXPRESIONES Y SENTENCIAS 257.1 Operadores 7.1.1 Operadores aritméticos7.1.2 Operadores de asignación 7.1.3 Operadores incrementales 7.1.4 Operadores relacionales 7.1.5 Operadores lógicos 7.1.6 Otros operadores 7.2 Expresiones 7.2.1 Expresiones aritméticas 7.2.2 Expresiones lógicas 7.2.3 Expresiones generales 7.3 Reglas de precedencia y asociatividad 7.4 Sentencias 7.4.1 Sentencias simples Resumen de lenguaje ANSI C Página ii7.4.2 Sentencia vacía ó nula 7.4.3 Sentencias compuestas o bloques

Capítulo 8. CONTROL DEL FLUJO DE EJECUCIÓN 8.1 Bifurcaciones 8.1.1 Operador condicional 8.1.2 Sentencia if 8.1.3 Sentencia if ... else 8.1.4 Sentencia if ... else múltiple 8.1.5 Sentencia switch 8.1.6 Sentencias if anidadas 8.2 Bucles

Ing. Nestor Huaracha Velasquez

Page 3: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 3 8.2.1 Sentencia while 8.2.2 Sentencia for 8.2.3 Sentencia do ... while 8.3 Sentencias break, continue, goto

9 TIPOS DE DATOS DERIVADOS. 9.1 Punteros 9.1.1 Concepto de puntero o apuntador 9.1.2 Operadores dirección (&) e indirección (*) 9.1.3 Aritmética de punteros 9.2 Vectores, matrices y cadenas de caracteres 9.2.1 Relación entre vectores y punteros 9.2.2 Relación entre matrices y punteros 9.2.3 Inicialización de vectores y matrices 9.3 Estructuras

10. FUNCIONES 10.1 Utilidad de las funciones 10.2 Definición de una función 10.3 Declaración y llamada de una función 10.4 Paso de argumentos por valor y por referencia 10.5 La función main() con argumentos 10.6 Funciones para cadenas de caracteres 10.6.1 Función strlen() 10.6.2 Función strcat() 10.6.3 Funciones strcmp() y strcomp() 10.6.4 Función strcpy() 10.7 Punteros como valor de retorno 10.8 Paso de arrays como argumentos a una función 10.9 Punteros a funciones

11. FUNCIONES DE ENTRADA/SALIDA 11.1 Función printf() 11.2 Función scanf() 11.3 Macros getchar() y putchar() 11.4 Otras funciones de entrada/salida

12. EL PREPROCESADOR 12.1 Comando #include 12.2 Comando #define 12.3 Comandos #ifdef, #ifndef, #else, #endif, #undef

13. OTROS ASPECTOS DEL LENGUAJE C 13.1 Typedef 13.2 Funciones recursivas 13.3 Gestión dinámica de la memoria

14. Estructura de datos.

14.1 Introducción y definición14.2 Objetivos 14.3 Arreglos 14.4 Arreglos de tipo carácter 14.5 Arreglos bidimensionales (matrices) 14.6 Modularidad 14.7 Metodología descendente: (top – down) 14.8 Variables 14.10 Procedimientos 14.11 Funciones 14.12 Uso de los parámetros: formales – normales o argumentos 14.13 Arquitectura modular 14.14 Recursividad 14.15 Registros 14.16 Conclusiones y recomendaciones 14.17 Ejemplos, ejemplos y mas ejemplos

Ing. Nestor Huaracha Velasquez

Page 4: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 4 1. CONCEPTOS BASICOS DE ALGORITMIA:

1.1 Algoritmo

Un algoritmo es un conjunto ordenado y finito de instrucciones que conducen a la solución de un problema. En la vida cotidiana ejecutamos constantamente algoritmos. Por ejemplo, al instalar un equipo de sonido ejecutamos las instrucciones contenidas en el manual del equipo, este conjunto de instrucciones constituyen un algoritmo. Otro caso de algoritmo es el algoritmo matemático de Euclides para la obtención del máximo común divisor de dos números.

Si un algoritmo puede ser ejecutado por una computadora, se dice que es un algoritmo computacional; en caso contrario, se dice que es un algoritmo no computacional. Según esto, el algoritmo de Euclides es un algoritmo computacional; pero el algoritmo para instalar el equipo de sonido es un algoritmo no computacional. Para que un algoritmo pueda ser ejecutado por una computadora se necesita expresar el algoritmo en instrucciones comprensibles por la computadora, para esto se requiere de un determinado lenguaje de programación. Al algoritmo expresado en un determinado lenguaje de programación, se denomina programa. Puesto de otra manera, podemos decir que, un programa es la implementación o expresión de un algoritmo en un determinado lenguaje de programación siguiendo las reglas establecidas por el lenguaje elegido. En la Figura 2.1 que sigue se muestra la relación entre problema, algoritmo y programa.

Figura 1.1 Problema, algoritmo y programa

Todo algoritmo debe tener las siguientes características: Debe ser preciso, es decir, cada instrucción

debe indicar de forma inequívoca que se tiene que hacer.

Debe ser finito, es decir, debe tener un número limitado de pasos.

Debe ser definido, es decir, debe producir los mismos resultados para las mismas condiciones de entrada.

Todo algoritmo puede ser descompuesto en tres partes: Entrada de datos. Proceso. Salida de resultados.

Ejemplo 1.1:- Algoritmo para preparar ceviche de bonito para 6 personas.

   Entradas :       - 1 kilo de bonito

- 3 camotes sancochados - 3 cebollas cortadas a lo largo - 1 rocoto en rodajas - 3 ramas de apio picado - 2 ramitas de culantro picado - 4 vasos de jugo de limón - 4 cucharadas de ajo molido - 2 cucharadas de ají amarillo molido - sal y pimienta

   Proceso :       - Cortar la carne de pescado en pequeños trozos.       - Mezclar la carne con el jugo de limón, el ajo, la pimienta, el culantro, el ají amarillo y el apio.

- Dejar reposar 30 minutos.- Agregar sal al gusto y echar las cebollas cortadas. - Servir acompañando el cebiche con el camote sancochado y el rocoto

en rodajas    Salida :        El ceviche

Evidentemente este es un algoritmo no computacional, no podrá ser ejecutado por una computadora, pero sí por una persona. Por si acaso el ceviche es peruano.

Ejemplo 1.2:- Algoritmo para expresar en centímetros y pulgadas una cantidad dada en metros.

    Entrada:       La cantidad M de metros     Proceso:       Cálculo de centímetros  : C = M*100        Cálculo de pulgadas     : P = C/2.54      Salida :        La cantidad C de centímetros y la cantidad P de pulgadas

Este es un algoritmo computacional escrito en lenguaje natural, puede ser convertido en un programa de computadora, pero también puede ser ejecutado manualmente por una persona.

1.2 El Pseudocódigo

Ing. Nestor Huaracha Velasquez

Page 5: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 5 El pseudocódigo es un lenguaje de pseudoprogramación utilizado para escribir algoritmos computacionales. Como lenguaje de pseudoprogramación, el pseudocódigo es una imitación de uno o más lenguajes de programación. De esta manera podemos encontrar pseudocódigos orientados a lenguajes de programación como Pascal, Java, C, C++, etc. En el caso de este curso orientaremos los pseudocódigos a los lenguajes Java, C y C++. El objetivo del pseudocódigo es permitir que el programador se centre en los aspectos lógicos de la solución, evitando las reglas de sintáxis de los lenguajes de programación. No siendo el pseudocódigo un lenguaje formal, los pseudocódigos varían de un programador a otro, es decir, no hay un pseudocódigo estándar.

1.3 VariablesUna variable es una localización o casillero en la memoria principal que almacena un valor que puede cambiar en el transcurso de la ejecución del programa. Cuando un programa necesita almacenar un dato, necesita una variable. Toda variable tiene un nombre, un tipo de dato y un valor. Antes de poder utilizar una variable es necesario declararla especificando su nombre y su tipo de dato. Para declarar declarar variables usaremos los siguientes formatos: Declaración de una variable:tipo nombreDeclaración de varias variables con el mismo tipo de dato: tipo nombre1, nombre2, nombre3, ..., nombren

Donde:tipo Es el tipo de dato de la variable que puede ser:

ENTERO (si la variable almacenará un número entero) , REAL (si la variable almacenará un número decimal) , CARACTER (si la variable almacenará un carácter), CADENA (si la variable almacenará un conjunto de carácteres) o LOGICO (si la variable almacenará el valor verdadero o el valor falso).

nombre1, nombre2, ..., nombren

Nombres de las variables . El nombre de una variable debe comenzar con una letra, un símbolo de subrayado o un símbolo de dólar. Los demás caractéres del nombre puede ser letras, símbolos de subrayado o símbolo de dólar. Debe considerarse también que una letra mayúscula se considera diferente de una letra minúscula.

Ejemplo 1.3:- Declaración de variables.

* La siguiente instrucción declara la variable edad de tipo ENTERO y la variable descuento de tipo REAL.. ENTERO edad

REAL descuento

Esto crea los casilleros de memoria edad y descuento. Luego de la creación, las variables están indefinidas ( ? ).

edad ?

descuento ?

* La siguiente instrucción declara las variables nota1, nota2 y nota3, todas de tipo ENTERO.

ENTERO nota1, nota2, nota3

Esto crea los casilleros de memoria nota1, nota2 y nota3. Luego de la creación, las variables están indefinidas ( ? ).

nota1 ?

nota2 ?

nota3 ?

1.4 LiteralesSe denominan literales a todos aquellos valores que figuran en el pseudocódigo y pueden ser:

Literales enteros12, 20300, 15, etc.Literales reales3.1416, 2345.456, etc.Literales de carácter'a', 'B', ';', '<', '+', etc.Lieterales de cadena"Hola", "Algoritmos Computacionales", etc.Literales lógicosverdadero, falso  

1.5 Instrucciones Algorítmicas BásicasExisten tres instrucciones algorítmicas básicas que son las siguientes 

1.5.1 EntradaConsiste en obtener un dato de un dispositivo de entrada, como el teclado, y almacenarlo en una variable. En general, la acción de ingresar un dato a una variable se expresa en el pseudocódigo mediante la palabra LEER, de la siguiente forma:LEER variable Por ejemplo, la instrucción:

Ing. Nestor Huaracha Velasquez

Page 6: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 6 LEER estatura Solicita el ingreso de un valor, desde algún dispositivo de entrada (como el teclado), para la variable estatura.

1.5.2 SalidaConsiste en mostrar el valor de una variable en un dispositivo de salida, como la pantalla. En general, la acción de mostrar el valor de una variable se expresa en el pseudocódigo mediante la palabra IMPRIMIR de la siguiente forma:IMPRIMIR variable Por ejemplo, la instrucción:IMPRIMIR importeCompra Muestra, en algún dispositivo de salida (como la pantalla), el valor de la variable importeCompra.

1.5.3 Asignación Consiste en asignar a una variable el valor de una expresión. La expresión puede ser una simple variable, un simple literal o una combinación de variables, literales y operadores. La asignación se expresa en el pseudocódigo de la siguiente forma: variable = expresión Donde variable y el valor de expresión deben tener el mismo tipo de dato. Cuando se asigna un valor ENTERO a una variable REAL, entonces el valor ENTERO se convertirá en REAL antes de almacenarse. Así, al asignar el valor ENTERO 25 a una variable REAL, se almacenará 25.0.

Ejemplo 1.4:- Algoritmo para expresar en centímetros y pulgadas una cantidad dada en metros.

Esta es una solución en pseudocódigo del ejemplo 1.2 utilizando conceptos computacionales de variable, entrada de datos y salida de resultados. La solución considera que 1 metro = 100 centímetros y que 1 pulgada = 2.54 centímetros.

INICIO   // Declara las variables M, C y P   REAL M, C, P   // Solicita el ingreso de la cantidad en metros    LEER M   // Calcula la cantidad en centímetros y lo asigna a la variable C    C = M*100    // Calcula la cantidad en pulgadas y lo asigna a la variable P    P = C/2.54   // Muestra los valores de las variables C y P   IMPRIMIR C, P

FIN

1.6 Expresiones AritméticasUna expresión aritmética es una combinación de variables, literales y operadores aritméticos.

1.6.1 Operadores Aritméticos En la tabla que sigue se muestran los operadores aritméticos que vamos a utilizar.

Tabla 1.1 Operadores aritméticosOperador Significado Ejemplo

+ Suma a+b

- Resta a-b

* Multiplicación a*b

/ División a/b

% Residuo a%b

Los operadores aritméticos pueden utilizarse con tipos enteros y reales. Si en una operación con dos operandos, ambos operandos son enteros, el resultado es un entero; si alguno de ellos es real, el resultado es real. Así, 15/4 es 3 y no 3.75; en cambio, 15.0/4 es 3.75.

1.6.2 Reglas de jerarquía de los operadores aritméticos Cuando una expresión aritmética tiene más de un operador aritmético, el orden de aplicación de los operadores sigue un orden preciso determinado por las reglas de jerarquía de los operadores aritméticos, que se muestran en la siguiente tabla:

Tabla 1.2 Reglas de jerarquía de los operadores aritméticos Operador Orden de evaluación

() Se evalúan en primer lugar

*, /, % Se evalúan en segundo lugar

+, - Se evalúan en tercer lugar

Si existen paréntesis anidados, se evalúa primero la expresión en el par más interno. Si varios operadores o paréntesis tienen la misma jerarquía, la evaluación será de izquierda a derecha.

Ing. Nestor Huaracha Velasquez

Page 7: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 7

Ejemplo 1.4:- ¿Cuál es el equivalente en pseudocódigo de la siguiente expresión algebraica?

Solucióne = a/b/cComo todos los operadores tienen la misma jerarquía, la evaluación será de izquierda a derecha:Primero, se dividirá a entre b. Segundo, el resultado ya obtenido de a/b se dividirá entre c.

Note que el orden de ejecución esta de acuerdo con la expresión algebraica, por lo que no se requiere ninguna pareja de paréntesis.

Ejemplo 1.5:- ¿Cuál es el equivalente en pseudocódigo de la siguiente expresión algebraica?

Solucióne = a*b*c/d/eComo todos los operadores tienen la misma jerarquía, la evaluación será de izquierda a derecha:Primero, se multiplicará a por b. Segundo, el resultado ya obtenido de a*b se multiplicará por c. Tercero, el resultado ya obtenido de a*b*c se dividirá entre d.Cuarto, el resultado ya obtenido de a*b*c/d se divivirá entre e.

Note que el orden de ejecución esta de acuerdo con la expresión algebraica, por lo que no se requiere ninguna pareja de paréntesis.

Ejercicio 1.6:- ¿Cuál es el equivalente en pseudocódigo de la siguiente expresión algebraica?

Solución

e = 4/((a+b)/(c/d)) + v/w/p + 5*m*n*q Aplicando las reglas de jerarquía de los operadores aritméticos: Primero, se sumará a más b. Segundo, se dividirá c entre d.Tercero, el resultado ya obtenido de a+b se dividirá entre el resultado ya obtenido de c/d.Cuarto, se dividirá 4 entre el resultado ya obtenido de ((a+b)/(c/d)) Quinto, se dividirá v entre w.Sexto, se dividirá el resultado ya obtenido de v/w entre p.Séptimo, se multiplicará 5 por m.Octavo, se multiplicará el resultado ya obtenido de 5*m por n.Noveno, se multiplicará el resultado ya obtenido de 5*m*n por q.Décimo, se sumará el resultado ya obtenido de 4/((a+b)/(c/d)) más el resultado ya obtenido de v/w/p.Undécimo, se sumará el resultado ya obtenido de 4/((a+b)/(c/d)) + v/w/p más el resultado ya obtenido de 5*m*n*q. Se ha utilizado la mínima cantidad posible de paréntesis. Pueden usarse paréntesis adicionales, lo que no es un error. Por ejemplo, otra solución posible que arroja el mismo resultado final es: e = (4/((a+b)/(c/d))) + ((v/w)/p) + (5*m*n*q)Note que usando correctamente las reglas de jerarquía, es posible usar menos parejas de paréntesis.

1.7 Expresiones LógicasUna expresión lógica combina variables, literales, operadores aritméticos, operadores relacionales y operadores lógicos. Los operadores relacionales y los operadores lógicos se muestran en las tablas 3.1 y 3.2.

Tabla 1.3 Operadores relacionalesOperador Significado Ejemplo

> mayor que a > b

>= mayor o igual que a >= b

< menor que a < b

Ing. Nestor Huaracha Velasquez

Page 8: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 8

<= menor o igual que a <= b

== igual a a == b

!= diferente de a != b

Tabla 1.4 Operadores lógicosOperador Significado Ejemplo

! no !a

&& y a && b

|| ó a || b

Ing. Nestor Huaracha Velasquez

Page 9: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 9 2. ESTRUCTURAS DE SENTENCIA:

2.1 ConceptoUna estructura secuencial es aquella en la que las instrucciones están una a continuación de la otra siguiendo una secuencia única, sin cambios de ruta. La estructura secuencial tiene una entrada y una salida. En la Figura 4.1 se muestra el diagrama de flujo y el pseudocódigo de una estructura secuencial.

Diagrama de Flujo

Pseudocódigo

Inicio    .    .        acción 1    acción 2    acción 3    .    .    Fin

Figura 2.1 Estructura Secuencial: Diagrama de Flujo y Pseudocódigo

2.2 Ejercicios

Ejercicio 1:- Diseñe un pseudocódigo que halle el área y el perímetro de un rectángulo. Considere que: area = base x altura y perimetro = 2 x (base+altura).

AlgoritmoINICIO    // Declaración de variables     REAL base, altura, area, perímetro    // Entrada de datos     LEER base, altura     // Proceso de cálculo     area = base*altura    perimetro = 2*(base+altura)    // Salida de resultados     IMPRIMIR area, perímetroFIN    

Ejemplo 2:- Diseñe un pseudocódigo para convertir una longitud dada en metros a sus equivalentes en centímetros, pies, pulgadas y yardas. Considere que: 1 metro = 100 centímetros, 1 pulgada = 2.54 centimetros, 1 pie = 12 pulgadas, 1 yarda = 3 pies.

Algoritmo INICIO     // Declaración de variables      REAL cmetr,ccent, cpies, cpulg, cyard     // Entrada de datos     LEER cmetr      // Proceso de cálculo     ccent = cmetr*100     cpulg = ccent/2.54    cpies = cpulg/12    cyard = cpies/3    // Salida de resultados     IMPRIMIR cpulg, cpies, cyard FIN

Ejercicio 3:- Una institución benéfica europea ha recibido tres donaciones en soles, dolares y marcos. La donación será repartida en tres rubros: 60% para la implementación de un centro de salud, 40% para un comedor de niños y el resto para gastos administrativos. Diseñe un algoritmo que determine el monto en euros que le corresponde a cada rubro. Considere que: 1 dólar = 3.52 soles, 1 dólar = 2.08 marcos, 1 dólar = 1.07 euros.

Algoritmo INICIO    // Declaración de variables     REAL c soles, cdolares, c marcos, ceuros, rubro1, rubro2, rubro3    // Entrada de datos     LEER csoles, cdolares, cmarcos    // Proceso de cálculo     ceuros = (csoles/3.52 + cdolares + cmarcos/2.08)*1.07    rubro1 = ceuros*0.60    rubro2 = ceuros*0.40    rubro3 = ceuros*0.20    // Salida de resultados     IMPRIMIR rubro1, rubro2, rubro3FIN

Ing. Nestor Huaracha Velasquez

Page 10: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 10

Ejercicio 4:- En una competencia atlética de velocidad el tiempo se mide en minutos, segundos y centésimas de segundo y, el espacio recorrido se mide en metros. Diseñe un algoritmo para determinar la velocidad promedio de un atleta en km/hr. Considere que: 1 hora = 60 minutos, 1 minuto = 60 segundos, 1 segundo = 100 centésimas de segundo, 1 kilómetro = 1000 metros.

Algoritmo INICIO     // Declaración de variables     ENTERO tmin, tseg, tcen    REAL thor, velkmhr, espmt, espkm    // Entrada de datos     LEER tmin, tseg, tcen, espmt    // Cálculo del tiempo total empleado en horas    thor = tmin/60 + tseg/3600 + tcen/360000    // Cálculo del espacio recorrido en kilómetros    espkm = espmt/1000    // Cálculo de la velocidad en km/hr    velkmhr = espkm/thor    // Salida de resultados     IMPRIMIR velkmhrFIN

Ejercicio 5:- Diseñe un algoritmo que determine la cifra de las unidades de un número natural.

Solución 1 AnálisisPuede comprobarse que la cifra de las unidades de un número es igual al resto de la división del número entre 10. Observe para ello las siguientes divisiones:3245 105 324

768 108 76

9 109 0Podemos concluir entonces que: unidades = numero % 10Siendo % el operador residuo. Este operador permite obtener el residuo de una división, así como / permite obtener el cociente.AlgoritmoINICIO     // Declaración de variables     ENTERO numero, unidades

    // Entrada de datos    LEER numero    // Proceso de cálculo     unidades = numero % 10    // Salida de resultados     IMPRIMIR unidadesFIN

Solución 2 AnálisisEl residuo de una división entera puede obtenerse también sin recurrir al operador %, de la siguiente forma:unidades = numero - (numero / 10) * 10observe para esto que en la división (numero/10) los operandos son enteros por lo que el cociente será un entero. Así por ejemplo, si numero es igual a 3245, la división (numero/10) produce 324, aunque matemáticamente sea 324.5; es decir, se descarta la parte decimal.AlgoritmoINICIO     // Declaración de variables     ENTERO numero, unidades    // Entrada de datos     LEER numero    // Proceso de cálculo     unidades = numero - (numero/10)*10    // Salida de resultados     IMPRIMIR unidadesFIN

Ejercicio 6:- Diseñe un algoritmo que determine la suma de las cifras de un número entero positivo de 4 cifras.

Solución 1 AnálisisLas cifras pueden ser obtenidas mediante divisiones sucesivas entre 10. Para el efecto, considere el caso de un número N igual a 3245: 3245 105 324unidades = N%10

cociente = N/10 324 104 32decenas  = cociente%10

cociente = cociente/10

Ing. Nestor Huaracha Velasquez

Page 11: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 11 32 102 3centenas = cociente%10millares = cociente/10 Algoritmo INICIO     // Declaración de variables     ENTERO N, suma, millares, centenas, decenas, unidades, resto         // Entrada de datos     LEER N    // Proceso de cálculo     unidades = N%10    cociente = N/10    decenas  = cociente%10    cociente = cociente/10    centenas = cociente%10    millares = cociente/10    suma    = unidades + decenas + centenas + millares    // Salida de resultados     IMPRIMIR suma FIN

Solución 2Análisis 2Considerando que el número tiene 4 cifras, las cifras también pueden ser obtenidas mediante divisiones sucesivas entre 1000, 100 y 10. Para el efecto, considere el caso de un número N igual a 3245: 3245 1000245 3millares = N/1000

resto    = N%1000 245 10045 2centenas = resto/100

resto    = resto%100 45 103 4decenas  = resto/10unidades = resto%10

Algoritmo INICIO     // Declaración de variables    ENTERO N, suma, millares, centenas, decenas, unidades, resto     // Entrada de datos

    LEER N    // Proceso de cálculo     millares  = N/1000    resto   = N%1000   centenas = resto/100    resto   = resto%100    decenas  = resto/10   unidades  = resto%10    suma    = unidades + decenas + centenas + millares    // Salida de resultados     IMPRIMIR sumaFIN

Ejercicio 7:- Diseñe un algoritmo que lea la hora actual del día HH:MM:SS y determine cuantas horas, minutos y segundos restan para culminar el día.

Algoritmo INICIO     // Declaración de variables     ENTERO hor1, min1, seg1, hor2, min2, seg2, segres, resto     // Entrada de datos     LEER hor1, min1, seg1     // Cálculo de la cantidad de segundos que restan para culminar el día    segres = 86400 - (hor1*3600 + min1*60 + seg1)    // Descomposición de segres en horas, minutos y segundos     hor2  = segres/3600    resto = segres%3600   min2  = resto/60    seg2  = resto%60    // Salida de resultados     IMPRIMIR hor2, min2, seg2FIN

Ejercicio 8:- Diseñe un algoritmo para sumar dos tiempos dados en horas, minutos y segundos.

Algoritmo INICIO     // Declaración de variables

Ing. Nestor Huaracha Velasquez

Page 12: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 12     ENTERO hor1, min1, seg1, hor2, min2, seg2, hor3, min3, seg3, totseg, resto

   // Entrada de datos     LEER hor1, min1, seg1, hor2, min2, seg2     // Determina la cantidad total de segundos entre los dos tiempos    totseg = (hor1+hor2)*3600 + (min1+min2)*60 + (seg1+seg2)    // Descompone totseg en horas, minutos y segundos    hor3  = totseg/3600    resto = totseg%3600    min3  = resto/60    seg3  = resto%60    // Salida de resultados     IMPRIMIR hor3, min3, seg3FIN

Ejercicio 9:- El sueldo neto de un vendedor se calcula como la suma de un sueldo básico de S/.250 más el 12% del monto total vendido. Diseñe un algoritmo que determine el sueldo neto de un vendedor sabiendo que hizo tres ventas en el mes.

Algoritmo INICIO    // Declaración de variables     REAL venta1, venta2, venta3, ventatot, comision, sueldoneto    // Entrada de datos     LEER venta1, venta2, venta3    // Proceso de cálculo    ventatot = venta1 + venta2 + venta3    comision = 0.12*ventatot    sueldoneto = 250 + comision    // Salida de resultados     IMPRIMIR sueldonetoFIN

Ejercicio 10:- Diseñe un algoritmo que determine el porcentaje de varones y de mujeres que hay en un salón de clases.

AlgoritmoINICIO    // Declaración de variables     REAL porcvar, porcmuj    ENTERO varones, mujeres, total    // Entrada de datos     LEER varones, mujeres

    // Proceso de cálculo    total = varones + mujeres    porcvar = varones*100.0/total    porcmuj = mujeres*100.0/total    // Salida de resultados     IMPRIMIR porcvar, porcmujFIN

Ejercicio 11:- En países de habla inglesa es común dar la estatura de una persona como la suma de una cantidad entera de pies más una cantidad entera de pulgadas. Así, la estatura de una persona podría ser 3' 2" ( 3 pies 2 pulgadas ). Diseñe un algoritmo que determine la estatura de una persona en metros, conociendo su estatura en el formato inglés. Considere que: 1 pie = 12 plg, 1 plg = 2.54 cm, 1 m = 100 cm.

AlgoritmoINICIO    // Declaración de variables     REAL estmt    ENTERO cpies, cplgs     // Entrada de datos     LEER cpies, cplgs    // Proceso de cálculo     estmt = (cpies*12 + cplgs)*2.54/100    // Salida de resultados     IMPRIMIR estmtFIN

Ejercicio 12:- Diseñe un algoritmo que exprese la capacidad de un disco duro en megabytes, kilobytes y bytes, conociendo la capacidad del disco en gigabytes. Considere que: 1 kilobyte = 1024 bytes, 1 megabyte = 1024 kilobyte, 1 gigabyte = 1024 megabytes.

AlgoritmoINICIO    // Declaración de variables     REAL cgigabyte, cmegabyte, ckilobyte, cbyte    // Entrada de datos     LEER cgigabyte    // Proceso de cálculo

Ing. Nestor Huaracha Velasquez

Page 13: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 13     cmegabyte = cgigabyte*1024    ckilobyte = cmegabyte*1024    cbyte = ckilobyte*1024    // Salida de resultados     IMPRIMIR cmegabyte, ckilobyte, cbyteFIN

Ejercicio 13:- Diseñe un algoritmo que intercambie las cifras de las unidades de dos números naturales.

AlgoritmoINICIO    // Declaración de variables     ENTERO numero1, numero2, unidades1, unidades2    // Entrada de datos     LEER numero1, numero2    // Determina las cifras de las unidades    unidades1 = n1%10    unidades2 = n2%10    // Intercambia las cifras de las unidades     numero1 = numero1 - unidades1 + unidades2     numero2 = numero2 - unidades2 + unidades1     // Salida de resultados     IMPRIMIR n1, n2FIN

Ing. Nestor Huaracha Velasquez

Page 14: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 14 3. ESTRUCTURAS DE SELECCIÓN.-

3.1 IntroducciónLas estructuras de selección son estructuras de control utilizadas para la toma decisiones dentro de un programa. A estas estructuras se conocen también como estructuras selectivas o estructuras de decisión y son las siguientes:

La estructura de selección simple (SI). La estructura de selección doble (SI-SINO). La estructura de selección múltiple (SEGUN)

3.2 Estructura de Selección Simple SILa estructura de selección simple permite ejecutar una acción o un grupo de acciones sólo si se cumple una determinada condición. Así, en el gráfico 3.1, si

la condición es verdadera se ejecuta la acción acciona; en caso contrario, no se hace nada.       Diagrama de Flujo Pseudocódigo (acción simple)

SI( condicion )   acciona

Pseudocódigo (acción compuesta) SI( condicion ){   acciona1   acciona2   .   .   .   accionan}

Figura 3.1 Estructura de Selección SimplePor ejemplo, si se desea cambiar el signo de un número únicamente en caso que sea negativo, podemos escribir:SI( numero < 0 )    numero = -1 * numeroSi el número no es negativo, simplemente esta estructura se pasaría por alto y se continuaría en la siguiente instrucción después del SI.

3.3 Estructura de Selección Doble SI - SINOLa estructura de selección doble permite seleccionar una ruta de dos rutas posibles en base a la verdad o falsedad de una condición. Así, en la Figura 3.2, si la condición es verdadera, se ejecuta la acción A; en caso contrario, se ejecuta la acción B. En la Figura 3.2 se muestra el diagrama de flujo y el pseudocódigo de la estructura de selección doble.

                             Diagrama de Flujo Pseudocódigo (acción simple) SI( condicion )   accionaSINO   accionb

Pseudocódigo (acción compuesta) SI( condicion ){   acciona1   acciona2   .   .   .   accionan}SINO{   accionb1   accionb2   .   .   .   accionbn}

Figura 3.2 Estructura de Selección Doble

Por ejemplo, la siguiente estructura de selección doble determina si una persona es mayor o menor de edad:SI( edad >= 18 )    estado = "Mayor de edad"SINO    estado = "Menor de edad"

Esto imprime "Mayor de edad" si la persona tiene 18 años ó más e imprime "Menor de edad" si la persona tiene menos de 18 años. En cualquiera de los casos, después de efectuar la impresión, se ejecutará la primera instrucción que sigue a la estructura SI...SINO. 

3.4 Estructura de Selección Doble en Cascada SI-SINO-SI

La estructura de selección doble en cascada esta formada por varias estructuras de selección doble SI-SINO puestas una a continuación de otra de forma que a un SI-SINO le sigue otro SI-SINO.

En la estructura de selección doble en cascada, las condiciones se evalúan en orden descendente, pasando de una condición a otra si la condición anterior

Ing. Nestor Huaracha Velasquez

Page 15: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 15 resulta falsa. En el momento que se encuentra una condición verdadera, se efectúa la acción correspondiente a dicha condición y se corta el resto de la estructura. Si todas las condiciones resultan falsas, se efectúa la acción correspondiente al último SINO, que se considera como la acción por defecto. En la Figura 3.3 se muestra el diagrama de flujo y el pseudocódigo de la estructura de selección doble en cascada.

                    Diagrama de Flujo Pseudocódigo ( Forma 1 ) SI( condicion1 )    accion1SINO    SI( condicion2 )        accion2    SINO         SI( condicion3 )            accion3        .        .                  .        SINO            acciondefectoPseudocódigo ( Forma 2 ) SI( condicion1 )    accion1SINO SI( condicion2 )    accion2SINO SI( condicion3 )    accion3    .    .              .SINO    acciondefecto

Figura 3.3 Estructura de Selección Doble en Cascada

Por ejemplo, la siguiente estructura de selección doble en cascada determina el signo de un número entre positivo, negativo o cero:SI( n > 0 )         signo = "Positivo"SINO    SI( n < 0 )         signo = "Negativo"    SINO                signo = "Cero"Usando el otro formato tendríamos:SI( n > 0 )         signo = "Positivo"

SINO SI( n < 0 )     signo = "Negativo"SINO            signo = "Cero"

3.5 Estructura de Selección Múltiple SEGUNLa estructura de selección múltiple SEGUN permite elegir una ruta de entre varias rutas posibles, en base al valor de una variable que actúa como selector. La estructura compara el valor del selector con las constantes c1, c2, ..., cn en orden descendente. En el momento en que se encuentre una coincidencia, se ejecuta la acción correspondiente a dicha constante y se abandona la estructura.

En la Figura 3.4 se muestra el diagrama de flujo y el pseudocódigo de la estructura de selección múltiple.

                              Diagrama de Flujo Pseudocódigo SEGUN( selector ){     CASO c1 : accion1     CASO c2 : accion2     CASO c3 : accion3               .               .               .     CASO cn : accionn     DEFECTO : acciondefecto}

Figura 3.4 Estructura de Selección Múltiple

Por ejemplo, la siguiente estructura de selección múltiple determina el nombre de la estación del año conociendo el número de la estación (1 para Primavera, 2 para Verano, 3 para Otoño y 4 para Invierno) :

Ing. Nestor Huaracha Velasquez

Page 16: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 16 SEGUN(numeroEstacion){    CASO 1  : nombreEstacion = "Primavera"    CASO 2  : nombreEstacion = "Verano"    CASO 3  : nombreEstacion = "Otoño"    DEFECTO : nombreEstacion = "Invierno"}    

3.6 Ejercicios

Ejercicio 1:- En una playa de estacionamiento cobran S/. 2.5 por hora o fracción. Diseñe un algoritmo que determine cuanto debe pagar un cliente por el estacionamiento de su vehículo, conociendo el tiempo de estacionamiento en horas y minutos.

Algoritmo 1 INICIO    // Declaración de variables       ENTERO horas, minutos    REAL pago    

    // Entrada de datos    LEER horas, minutos

    // Si hay alguna fracción de hora, incrementa las horas a pagar en una unidad    SI( minutos > 0 )        horas = horas + 1

    // Determina el importe a pagar    pago = horas * 2.5

    // Salida de resultados    IMPRIMIR pagoFIN    

Algoritmo 2INICIO    // Declaración de variables       ENTERO horas, minutos, horasPagar    REAL pago    

    // Entrada de datos    LEER horas, minutos

    // Determina el número de horas a pagar    SI( minutos > 0 )

        horasPagar = horas + 1    SINO        horasPagar = horas

    // Determina el importe a pagar    pago = horasPagar * 2.5

    // Salida de resultados    IMPRIMIR pagoFIN

Ejercicio 2:- Diseñe un algoritmo que determine si ún número es o no es, par positivo.

AlgoritmoINICIO    // Declaración de variables       REAL numero    CADENA tipoNumero

    // Entrada de datos     LEER numero

    // Determina si el número es o no es, par positivo       SI( (numero%2==0) && (numero>0) )        tipoNumero = "El número es par positivo"    SINO        tipoNumero = "El número no es par positivo"    // Salida de resultados   IMPRIMIR tipoNumeroFIN

Ejercicio 3:- Diseñe un algoritmo que lea tres números y determine el número mayor.

Algoritmo INICIO    // Declaración de variables       REAL numero1, numero2, numero3, numeroMayor     // Entrada de datos

Ing. Nestor Huaracha Velasquez

Page 17: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 17     LEER numero1, numero2, numero3    // Determina el mayor     numeroMayor = numero1     SI( numero2 > numeroMayor )            numeroMayor = numero2     SI( numero3 > numeroMayor )            numeroMayor = numero3    // Salida de resultados       IMPRIMIR mayorFIN

Ejercicio 4:- Una tienda ha puesto en oferta la venta al por mayor de cierto producto, ofreciendo un descuento del 15% por la compra de más de 3 docenas y 10% en caso contrario. Además por la compra de más de 3 docenas se obsequia una unidad del producto por cada docena en exceso sobre 3. Diseñe un algoritmo que determine el monto de la compra, el monto del descuento, el monto a pagar y el número de unidades de obsequio por la compra de cierta cantidad de docenas del producto. 

AlgoritmoINICIO    // Declaración de variables    REAL montopag, montocom, montodes, precio     ENTERO docenas, obsequio         // Entrada de datos     LEER docenas, precio    // Determina el monto de la compra    montocom = docenas*precio        // Determina el monto del descuento y el obsequio     SI( docenas > 3 ){        montodes = 0.15*montocom       obsequio = docenas-3    }    SINO{        montodes = 0.10*montocom        obsequio = 0    }    // Determina el monto a pagar    montopag = montocom - montodes    // Salida de resultados     IMPRIMIR montocom, montodes, montopag, obsequio FIN

Ejercicio 5:- Diseñe un algoritmo que lea un número de tres cifras y determine si es o no capicúa. Un número es capicúa si es igual al revés del número.

Observación Como el número tiene tres cifras, para ser capicúa basta con que la cifra de las unidades sea igual a la cifra de las centenas. Por ejemplo: 353, 878, etc. Algoritmo INICIO    // Salida de resultados     ENTERO numero, unidades, centenas    CADENA tipoNumero

    // Entrada de datos     LEER numero

    // Si el número tiene tres cifras...     SI(numero >= 100 && numero <= 999 ){

         // Determina la cifra de las unidades y la cifra de las centenas         unidades = numero%10        centenas = numero/100

        // Determina el tipo de número entre capicúa o no capicúa        SI( unidades == centenas )            tipoNumero = "El número es capicúa"        SINO            tipoNumero = "El número no es capicúa"

        // Muestra el tipo de número         IMPRIMIR tipoNumero    }    SINO        IMPRIMIR "Ingrese un número de tres cifras"FIN

Ejercicio 6:- Diseñe un algoritmo que califique el puntaje obtenido en el lanzamiento de tres dados en base a la cantidad seis obtenidos, de acuerdo a lo siguiente: tres seis, excelente; dos seis, muy bien; un seis, regular; ningún seis, pésimo.

Algoritmo INICIO    // Declaración de variables

Ing. Nestor Huaracha Velasquez

Page 18: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 18     ENTERO dado1, dado2, dado3    CADENA calificacion     // Entrada de datos    LEER dado1, dado2, dado3   

    // Determina la calificación     SI( dado1 + dado2 + dado3 == 18 )            calificacion = "Excelente"    SINO SI( dado1+dado2 == 12 || dado1+dado3 == 12 || dado2+dado3 == 12 )        calificacion = "Muy bién"    SINO SI( dado1 == 6 || dado2 == 6 || dado3 == 6 )        calificacion = "Regular"    SINO        calificacion = "Pésimo"

    // Salida de resultados     IMPRIMIR calificacion FIN

Ejercicio 7:- Una compañía dedicada al alquiler de automoviles cobra un monto fijo de $30 para los primeros 300 km de recorrido. Para más de 300 km y hasta 1000 km, cobra un monto adicional de $ 0.15 por cada kilómetro en exceso sobre 300. Para más de 1000 km cobra un monto adicional de $ 0.10 por cada kilómetro en exceso sobre 1000. Los precios ya incluyen el 18% del impuesto general a las ventas, IGV. Diseñe un algoritmo que determine el monto a pagar por el alquiler de un vehículo y el monto incluído del impuesto.

AlgoritmoINICIO    // Declaración de variables    REAL kilomrec, montopag, montoigv, montofijo = 30, igv = 0.18  

    // Entrada de datos    LEER kilomrec        // Determina el monto a pagar     SI( kilomrec <= 300 )            montopag = montofijo    SINO SI( kilomrec <= 1000 )        montopag = montofijo + 0.15*(kilomrec-300)    SINO        montopag = montofijo + 0.15*700 + 0.10*(kilomrec-1000)

    // Determina el monto del impuesto     montoigv = igv*montopag /(1+igv)

    // Salida de resultados    IMPRIMIR montopag, montoigvFIN

Ejercicio 8:- Diseñe un algoritmo que determine quienes son contemporáneos entre Juan, Mario y Pedro.

AlgoritmoINICIO    // Declaración de variables    ENTERO juan, mario, pedro    CADENA contemporaneos     // Entrada de datos    LEER juan, mario, pedro

    // Determina quienes son contemporáneos     SI( juan == mario && mario == pedro )        contemporaneos = "Los tres son contemporáneos"    SINO SI( juan == mario )        contemporaneos = "Juan y Mario son contemporáneos"    SINO SI( juan == pedro )        contemporaneos = "Juan y Pedro son contemporáneos"    SINO SI( mario == pedro )        contemporaneos = "Mario y Pedro son contemporáneos"    SINO        contemporaneos = "No hay contemporáneos"

    // Salida de resultados    IMPRIMIR contemporaneos FIN

Ejercicio 9:- El promedio de prácticas de un curso se calcula en base a cuatro prácticas calificadas de las cuales se elimina la nota menor y se promedian las tres notas más altas. Diseñe un algoritmo que determine la nota eliminada y el promedio de prácticas de un estudiante.

AlgoritmoINICIO    // Declaración de variables    REAL pc1, pc2, pc3, pc4, pcmenor, promedio    // Entrada de datos    LEER pc1, pc2, pc3, pc4    // Determina la nota menor    pcmenor = pc1    SI( pc2 < pcmenor )        pcmenor = pc2

Ing. Nestor Huaracha Velasquez

Page 19: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 19     SI( pc3 < pcmenor )        pcmenor = pc3    SI( pc4 < pcmenor )        pcmenor = pc4    // Determina el promedio    promedio = (pc1 + pc2 + pc3 + pc4 - pcmenor )/3    // Salida de resultados    IMPRIMIR promedio, pcmenorFIN

Ejercicio 10:- Diseñe un algoritmo que lea tres longitudes y determine si forman o no un triángulo. Si es un triángulo determine de que tipo de triángulo se trata entre: equilátero (si tiene tres lados iguales), isósceles (si tiene dos lados iguales) o escaleno (si tiene tres lados desiguales). Considere que para formar un triángulo se requiere que: "el lado mayor sea menor que la suma de los otros dos lados".

AlgoritmoINICIO    // Declaración de variables    REAL L1, L2, L3, suma    CADENA tipoRectangulo     // Entrada de datos    LEER L1, L2, L3<        // Determina el lado mayor    mayor = L1    SI( L2 > mayor )        mayor = L2    SI( L3 > mayor )        mayor = L3    // Determina la suma de los lados a excepción del lado mayor    suma = L1 + L2 + L3 - mayor     // Determina de que tipo de triángulo se trata    SI( mayor < suma ){        SI( ( L1 == L2 ) && ( L2 == L3 ) )            tipoRectangulo = "Triángulo equilátero"        SINO SI( ( L1 == L2 ) || ( L1 == L3 ) || ( L2 == L3 ) )            tipoRectangulo = "Triángulo isósceles"        SINO            tipoRectangulo = "Triángulo escaleno"    }    SINO        tipoRectangulo = "No es un triángulo"    // Salida de resultados    IMPRIMIR tipoRectangulo FIN

Ejercicio 11:- Diseñe un algoritmo que lea tres números enteros y determine el menor valor positivo. Si los números positivos son iguales, dar como menor a cualquiera de ellos.

AlgoritmoINICIO    // Declaración de variables     ENTERO a, b, c, menor     // Entrada de datos     LEER a, b, c    // Determina el menor     // Aquí a, b y c podrían ser positivos    SI( a > 0 ){               menor = a        SI( b > 0 && b < menor )            menor = b        SI( c > 0 && c < menor )            menor = c    }    // Aquí sólo b y c podrían ser positivos    SINO SI( b > 0 ){        menor = b        SI( c > 0 && c < menor )            menor = c     }    // Aquí sólo c podrían ser positivos    SINO SI( c > 0 ){        menor = c    }       // Guardamos el indicador -1 para saber que no hay positivos     SINO         menor = -1         // Salida de resultados     SI( menor != -1 )         IMPRIMIR menor     SINO        IMPRIMIR "No se ingresó ningún número positivo" FIN

Ejercicio 12:- Diseñe un algoritmo que lea tres números y los imprima de mayor a menor y de menor a mayor.

AlgoritmoIng. Nestor Huaracha Velasquez

Page 20: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 20 INICIO    // Declaración de variables          REAL n1, n2, n3, mayor, menor, medio    // Entrada de datos     LEER n1, n2, n3    // Determina el menor    menor = n1    SI( n2 < menor )        menor = n2    SI( n3 < menor )        menor = n3    // Determina el mayor    mayor = n1    SI( n2 > mayor )        mayor = n2    SI( n3 > mayor )        mayor = n3    // Determina el medio    medio = n1+n2+n3-mayor-menor    // Imprime en orden ascendente    IMPRIMIR menor, medio, mayor    // Imprime en orden descendente    IMPRIMIR mayor, medio, menorFIN

Ejercicio 13:- Diseñe un algoritmo para obtener el grado de eficiencia de un operario de una fábrica de tornillos, de acuerdo a las siguientes condiciones, que se le imponen para un período de prueba:    - Menos de 200 tornillos defectuosos.    - Más de 10000 tornillos producidos. El grado de eficiencia se determina de la siguiente manera:    - Si no cumple niguna de las condiciones, grado 5.    - Si sólo cumple la primera condición, grado 6.    - Si sólo cumple la segunda condición, grado 7.    - Si cumple las dos condiciones, grado 8.

Las condiciones impuestas por la fábrica son:torpro < 200        siendo torpro el número de tornillos producidostordef > 10000    siendo tordef el número de tornillos defectuosos Algoritmo 1INICIO    // Declaración de variables     ENTERO torpro, tordef, grado    // Entrada de datos     LEER torpro, tordef    

    // Determina el grado de eficiencia    SI( tordef < 200 ){        SI( torpro > 10000 )            grado = 8        SINO            grado = 6    }    SINO{        SI( torpro > 10000 )            grado = 7        SINO            grado = 5    }    // Salida de resultados     IMPRIMIR gradoFINAlgoritmo 2INICIO    // Declaración de variables     ENTERO torpro, tordef, grado    // Entrada de datos     LEER torpro, tordef    // Determina el grado de eficiencia    SI( tordef < 200 && torpro > 10000 )        grado = 8     SINO SI( tordef < 200 )        grado = 6     SINO SI( torpro > 10000 )        grado = 7     SINO        grado = 5    // Salida de resultados     IMPRIMIR gradoFIN

Ejercicio 14:- Se cuenta con los votos obtenidos por Juan, Pedro y Maria en una elección democrática a la presidencia de un club. Para ganar la elección se debe obtener como mínimo el 50% de los votos más 1. En caso que no haya un ganador se repite la elección en una segunda vuelta. Van a la segunda vuelta los dos candidatos que obtengan la más alta votación. Se anula la elección en caso de producirse un empate doble por el segundo lugar o un empate triple. Diseñe un algoritmo que determine el resultado de la elección.

AlgoritmoINICIO    // Declaración de variables     ENTERO vjuan, vpedro, vmaria, vmingan    CADENA resultado

Ing. Nestor Huaracha Velasquez

Page 21: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 21     // Entrada de datos     LEER vjuan, vpedro, vmaria    // Determina la votación mínima para ganar     vmingan = (vjuan + vpedro + vmaria)/2 + 1     // Determina el resultado de la elección    SI( vjuan >= vmingan )       resultado = "Gana Juan "     SINO SI( vpedro >= vmingan )       resultado = "Gana Pedro"     SINO SI( vmaria >= vmingan )       resultado = "Gana María"     SINO SI( vpedro > vjuan && vmaria > vjuan )       resultado = "Pasan a la segunda vuelta Pedro y María"     SINO SI( vpedro > vmaria && vjuan > vmaria )       resultado = "Pasan a la segunda vuelta Pedro y Juan"     SINO SI( vmaria > vpedro && vjuan > vpedro )       resultado = "Pasan a la segunda vuelta María y Juan "     SINO       resultado = "Elección anulada"    // Salida de resultados    IMPRIMIR resultadoFIN

Ejercicio 15:- Diseñe un algoritmo que lea un número entero de 3 cifras, y forme el mayor número posible con las cifras del número ingresado. El número formado debe tener el mismo signo que el número ingresado.

AlgoritmoINICIO    // Declaración de variables     ENTERO num1, num2, numaux, uni, dec, cen, menor, mayor,medio    // Entrada de datos     LEER num1    // Si el número tiene tres cifras...     SI( ( num1 >= 100 && num1 <= 999 ) && ( num1 >= -999 && num1 <= -100 ) ){        // Guarda el número en una variable auxiliar para preservar el signo        numaux = num1        // Cambia el signo de num1 en caso de ser negativo        SI( num1 < 0 )            num1 = -num1        // Determina las cifras del número        cen = num1/100        dec = (num1%100)/10        uni = (num1%100)%10        // Determina la cifra menor        menor = cen

        SI( dec < menor )            menor = dec        SI( uni < menor )            menor = uni        // Determina la cifra mayor        mayor = cen        SI( dec > mayor )            mayor = dec        SI( uni > mayor )            mayor = uni        // Determina la cifra del medio        medio = cen+dec+uni-mayor-menor        // Forma el nuevo número        SI( numaux > 0 )            num2 = mayor*100 + medio*10 + menor        SINO            num2 = -1*(menor*100 + medio*10 + mayor)        // Imprime el nuevo número        IMPRIMIR num2    }    SINO        IMPRIMIR "El número no tiene tres cifras"FIN

Ing. Nestor Huaracha Velasquez

Page 22: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 22 4. BORLAND C++

4. INTRODUCCIÓN AL BORLAND C++En estos apuntes se describe de forma abreviada la sintaxis del

lenguaje C. No se trata de aprender a programar en C, sino más bien de presentar los recursos o las posibilidades que el C pone a disposición de los programadores.

Conocer un vocabulario y una gramática no equivale a saber un idioma. Conocer un idioma implica además el hábito de combinar sus elementos de forma semiautomática para producir frases que expresen lo que uno quiere decir. Conocer las palabras, las sentencias y la sintaxis del C no equivalen a saber programar, pero son condición necesaria para estar en condiciones de empezar a hacerlo, o de entender cómo funcionan programas ya hechos. El proporcionar la base necesaria para aprender a programar en C es el objetivo de estas páginas.

C++ puede ser considerado como una extensión de C. En principio, casi cualquier programa escrito en ANSI C puede ser compilado con un compilador de C++. El mismo programa, en un fichero con extensión *.c puede ser convertido en un programa en C++ cambiando la extensión a *.cpp. C++ permite muchas más posibilidades que C, pero casi cualquier programa en C, con algunas restricciones, es aceptado por un compilador de C++.

4.1 Esquema general de un computadorUn ordenador es un sistema capaz de almacenar y procesar con gran

rapidez una gran cantidad de información. Además, un ordenador tiene capacidad para comunicarse con el exterior, recibiendo datos, órdenes y programas como entrada (por medio del teclado, del ratón, de un disquete, etc.), y proporcionando resultados de distinto tipo como salida (en la pantalla, por la impresora, mediante un fichero en un disquete, etc.).

Los computadores modernos tienen también una gran capacidad de conectarse en red para comunicarse entre sí, intercambiando mensajes y ficheros, o compartiendo recursos tales como tiempo de CPU, impresoras, lectores de CD-ROM, escáners, etc. En la actualidad, estas redes de ordenadores tienen cobertura realmente mundial, y pasan por encima de fronteras, de continentes, e incluso de marcas y modelos de ordenador.

Los computadores que se utilizan actualmente tienen la característica común de ser sistemas digitales. Quiere esto decir que lo que hacen básicamente es trabajar a gran velocidad con una gran cantidad de unos y ceros. La memoria de un computador contiene millones de minúsculos interruptores electrónicos (transistores) que pueden estar en posición on u off.

Al no tener partes mecánicas móviles, son capaces de cambiar de estado muchos millones de veces por segundo. La tecnología moderna ha permitido miniaturizar estos sistemas y producirlos en grandes cantidades por un precio verdaderamente ridículo.

Actualmente, los ordenadores están presentes en casi todas partes: cualquier automóvil y gran número de electrodomésticos incorporan uno o –

probablemente– varios procesadores digitales. La diferencia principal entre estos sistemas y los computadores personales –PCs– que se utilizan en las prácticas de esta asignatura, está sobre todo en el carácter especializadoo de propósito general que tienen, respectivamente, ambos tipos de ordenadores. El procesador que chequea el sistema eléctrico de un automóvil está diseñado para eso y probablemente no es capaz de hacer otra cosa; por eso no necesita de muchos elementos auxiliares. Por el contrario, un PC con una configuración estándar puede dedicarse a multitud de tareas, desde contabilidad doméstica o profesional, procesamiento de textos, dibujoartístico y técnico, cálculos científicos, etc., hasta juegos (¡desde luego no en esta asignatura, al menos por el momento...!).

Existen cientos de miles de aplicaciones gratuitas o comerciales (la mayor parte muy baratas; algunas bastante caras) capaces de resolver los más variados problemas. Pero además, cuando lo que uno busca no está disponible en el mercado (o es excesivamente caro, o presenta cualquier otro tipo de dificultad), el usuario puede realizar por sí mismo los programas que necesite. Este es el objetivo de los lenguajes de programación, de los cuales elC es probablemente el más utilizado en la actualidad. Este es el lenguaje que será presentado a continuación.

4.1.1. PARTES O ELEMENTOS DE UN COMPUTADORUn computador en general, o un PC en particular, constan de distintas

partes interconectadas entre sí y que trabajan conjunta y coordinadamente. No es éste el momento de entrar en la descripción detallada de estos elementos, aunque se van a enumerar de modo muy breve. • Procesador o CPU (Central Processing Unit, o unidad central de proceso). Es el corazón del ordenador, que se encarga de realizar las operaciones aritméticas y lógicas, así como de coordinar el funcionamiento de todos los demás componentes.• Memoria principal o memoria RAM (Random Access Memory). Es el componente del computador donde se guardan los datos y los programas que la CPU está utilizando. Se llama también a veces memoria volátil, porque su contenido se borra cuando se apaga el ordenador, o simplemente cuando se reinicializa.• Disco duro. Es uno de los elementos esenciales del computador. El disco duro es capaz de mantener la información –datos y programas– de modo estable, también con el computador apagado. El computador no puede trabajar directamente con los datos del disco, sino que antes tiene que transferirlos a la memoria principal. De ordinario cada disco duro está fijo en un determinado computador.• Disquetes. Tienen unas características y propiedades similares a las de los discos duros, con la diferencia de que los discos duros son mucho más rápidos y tienen mucha más capacidad. Los disquetes por su parte son muy baratos, son extraíbles y sirven para pasar información de un PC a otro con gran facilidad.

Ing. Nestor Huaracha Velasquez

Page 23: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 23 • Pantalla o monitor. Es el elemento “visual” del sistema. A través de él el computador nos pide datos y nos muestra los resultados. Puede ser gráfica o simplemente alfanumérica (las más antiguas, hoy día ya en desuso).• Ratón. Es el dispositivo más utilizado para introducir información no alfanumérica, como por ejemplo, seleccionar una entre varias opciones en un menú o caja de diálogo. Su principal utilidad consiste en mover con facilidad el cursor por la pantalla.• Teclado. Es el elemento más utilizado para introducir información alfanumérica en el ordenador. Puede también sustituir al ratón por medio de las teclas de desplazamiento (¬,,®,¯).• Otros elementos. Los PCs modernos admiten un gran número de periféricos para entrada/salida y para almacenamiento de datos. Se pueden citar las impresoras, plotters, escáners, CD-ROMs, cintas DAT, etc.

4.1.2. LA MEMORIA: BITS, BYTES, PALABRAS

La memoria de un computador está constituida por un gran número de unidades elementales, llamadas bits, que contienen unos ó ceros. Un bit aislado tiene muy escasa utilidad; un conjunto adecuado de bits puede almacenar casi cualquier tipo de información. Para facilitar el acceso y la programación, casi todos los ordenadores agrupan los bits en conjuntos de 8, que se llaman bytes u octetos. La memoria se suele medir en Kbytes (1024 bytes), Mbytes o simplemente "megas" (1024 Kbytes) y Gbytes o "gigas" (1024 Mbytes).

El que la CPU pudiera acceder por separado a cada uno de los bytes de la memoria resultaría antieconómico. Normalmente se accede a una unidad de memoria superior llamada palabra (word), constituida por varios bytes. En los PCs antiguos la palabra tenía 2 bytes (16 bits); a partir del procesador 386 la palabra tiene 4 bytes (32 bits). Algunos procesadores másavanzados tienen palabras de 8 bytes.

Hay que señalar que la memoria de un ordenador se utiliza siempre para almacenar diversos tipos de información. Quizás la distinción más importante que ha de hacerse es entre datos y programas. A su vez, los programas pueden corresponder a aplicaciones (programas de usuario, destinados a una tarea concreta), o al propio sistema operativo del ordenador, que tiene como misión el arrancar, coordinar y cerrar las aplicaciones, así como mantener activos y accesibles todos los recursos del ordenador.

4.1.3. IDENTIFICADORES

Como se ha dicho, la memoria de un computador consta de un conjunto enorme de palabras, en el que se almacenan datos y programas. Las necesidades de memoria de cada tipo de dato no son homogéneas (por ejemplo, un carácter alfanumérico ocupa un byte, mientras que un número real

con 16 cifras ocupa 8 bytes), y tampoco lo son las de los programas. Además, el uso de la memoria cambia a lo largo del tiempo dentro incluso de una misma sesión de trabajo, ya que el sistema reserva o libera memoria a medida que la va necesitando.

Cada posición de memoria puede identificarse mediante un número o una dirección, y éste es el modo más básico de referirse a una determinada información. No es, sin embargo, un sistema cómodo o práctico, por la nula relación nemotécnica que una dirección de memoria suele tener con el dato contenido, y porque –como se ha dicho antes– la dirección física de un dato cambia de ejecución a ejecución, o incluso en el transcurso de una misma ejecución del programa. Lo mismo ocurre con partes concretas de un programa determinado.

Dadas las citadas dificultades para referirse a un dato por medio de su dirección en memoria, se ha hecho habitual el uso de identificadores. Un identificador es un nombre simbólico que se refiere a un dato o programa determinado. Es muy fácil elegir identificadores cuyo nombre guarde estrecha relación con el sentido físico, matemático o real del dato que representan. Así por ejemplo, es lógico utilizar un identificador llamado salario_bruto para representar el coste anual de un empleado. El usuario no tiene nunca que preocuparse de direcciones físicas de memoria: el sistema se preocupa por él por medio de una tabla, en la que se relaciona cada identificador con el tipo de dato que representa y la posición de memoria en la que está almacenado.

El C, como todos los demás lenguajes de programación, tiene sus propias reglas para elegir los identificadores. Los usuarios pueden elegir con gran libertad los nombres de sus variables y programas, teniendo siempre cuidado de respetar las reglas del lenguaje y de no utilizar un conjunto de palabras reservadas (keywords), que son utilizadas por el propio lenguaje. Más adelante se explicarán las reglas para elegir nombres y cuáles son las palabras reservadas del lenguaje C. Baste decir por ahora que todos los identificadores que se utilicen han de ser declarados por el usuario, es decir, hay que indicar explícitamente qué nombres se van a utilizar en el programa para datos y funciones, y qué tipo de dato va a representar cada uno de ellos. Más adelante se volverá sobre estos conceptos.

4.2. Concepto de "programa"

Un programa –en sentido informático– está constituido por un conjunto de instrucciones que se ejecutan –ordinariamente– de modo secuencial, es decir, cada una a continuación de la anterior. Recientemente, con objeto de disminuir los tiempos de ejecución de programas críticos por su tamaño o complejidad, se está haciendo un gran esfuerzo en desarrollar programas paralelos, esto es, programas que se pueden ejecutar

Ing. Nestor Huaracha Velasquez

Page 24: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 24 simultáneamente en varios procesadores. La programación paralela es mucho más complicada que la secuencial y no sehará referencia a ella en este curso.

Análogamente a los datos que maneja, las instrucciones que un procesador digital es capaz de entender están constituidas por conjuntos de unos y ceros. A esto se llama lenguaje de máquina o binario, y es muy difícil de manejar. Por ello, desde casi los primeros años de los ordenadores, se comenzaron a desarrollar los llamados lenguajes de alto nivel (tales como el Fortran, el Cobol, etc.), que están mucho más cerca del lenguaje natural. Estos lenguajes están basados en el uso de identificadores, tanto para los datos como para las componentes elementales del programa, que en algunos lenguajes se llaman rutinas o procedimientos, y que en C se denominan funciones. Además, cada lenguaje dispone de una sintaxis o conjunto de reglas con las que se indica de modo inequívoco las operaciones que se quiere realizar.

Los lenguajes de alto nivel son más o menos comprensibles para el usuario, pero no para el procesador. Para que éste pueda ejecutarlos es necesario traducirlos a su propio lenguaje de máquina. Esta es una tarea que realiza un programa especial llamado compilador, que traduce el programa a lenguaje de máquina. Esta tarea se suele descomponer en dos etapas, que se pueden realizar juntas o por separado. El programa de alto nivel se suele almacenar en uno o más ficheros llamados ficheros fuente, que en casi todos los sistemas operativos se caracterizan por una terminación –también llamada extensión– especial. Así, todos los ficheros fuente de C deben terminar por (.c); ejemplos de nombres de estos ficheros son calculos.c, derivada.c, etc. La primera tarea del compilador es realizar una traducción directa del programa a un lenguaje más próximo al del computador (llamado ensamblador), produciendo un fichero objeto con el mismo nombre que el fichero original, pero con la extensión (.obj). En una segunda etapa se realiza el proceso de montaje (linkage) del programa, consistente en producir un programa ejecutable en lenguaje de máquina, en el que están ya incorporados todos los otros módulos que aporta el sistema sin intervención explícita del programador (funciones de librería, recursos del sistema operativo, etc.). En un PC con sistema operativo Windows el programa ejecutable se guarda en un fichero con extensión (*.exe). Este fichero es cargado por el sistema operativo en la memoria RAM cuando el programa va a ser ejecutado.

Una de las ventajas más importantes de los lenguajes de alto nivel es la portabilidad de los ficheros fuente resultantes. Quiere esto decir que un programa desarrollado en un PC podrá ser ejecutado en un Macintosh o en una máquina UNIX, con mínimas modificaciones y una simple recompilación. El lenguaje C, originalmente desarrollado por D. Ritchie en loslaboratorios Bell de la AT&T, fue posteriormente estandarizado por un comité del ANSI (American National Standard Institute) con objeto de garantizar su portabilidad entre distintos computadores, dando lugar al ANSI C, que es la variante que actualmente se utiliza casi universalmente.

4.3. Concepto de "función".

4.3.1. CONCEPTOS GENERALES.

Las aplicaciones informáticas que habitualmente se utilizan, incluso a nivel de informática personal, suelen contener decenas y aún cientos de miles de líneas de código fuente. A medida que los programas se van desarrollando y aumentan de tamaño, se convertirían rápidamente en sistemas poco manejables si no fuera por la modularización, que es el proceso consistente endividir un programa muy grande en una serie de módulos mucho más pequeños y manejables. A estos módulos se les ha solido denominar de distintas formas (subprogramas, subrutinas, procedimientos, funciones, etc.) según los distintos lenguajes. El lenguaje C hace uso del concepto de función (function). Sea cual sea la nomenclatura, la idea es sin embargo siemprela misma: dividir un programa grande en un conjunto de subprogramas o funciones más pequeñas que son llamadas por el programa principal; éstas a su vez llaman a otras funciones más específicas y así sucesivamente.

La división de un programa en unidades más pequeñas o funciones presenta –entre otras– las ventajas siguientes:

1. Modularización. Cada función tiene una misión muy concreta, de modo que nunca tiene un número de líneas excesivo y siempre se mantiene dentro de un tamaño manejable. Además, una misma función (por ejemplo, un producto de matrices, una resolución de un sistema de ecuaciones lineales, ...) puede ser llamada muchas veces en un mismo programa, e incluso puede ser reutilizada por otros programas. Cada función puede ser desarrollada y comprobada por separado.

2. Ahorro de memoria y tiempo de desarrollo. En la medida en que una misma función es utilizada muchas veces, el número total de líneas de código del programa disminuye, y también lo hace la probabilidad de introducir errores en el programa.

3. Independencia de datos y ocultamiento de información. Una de las fuentes más comunes de errores en los programas de computador son los efectos colaterales o perturbaciones que se pueden producir entre distintas partes del programa. Es muy frecuente que al hacer una modificación para añadir una funcionalidad o corregir un error, se introduzcan nuevos errores en partes del programa que antes funcionaban correctamente. Una función es

Ing. Nestor Huaracha Velasquez

Page 25: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 25 capaz de mantener una gran independencia con el resto del programa, manteniendo sus propios datos y definiendo muy claramente la interfaz o comunicación con la función que la ha llamado y con las funciones a las que llama, y no teniendo ninguna posibilidad de acceso a la información que no le compete.

Las funciones de C están implementadas con un particular cuidado y riqueza, constituyendo uno de los aspectos más potentes del lenguaje. Es muy importante entender bien su funcionamiento y sus posibilidades.

3.3.2 NOMBRE, VALOR DE RETORNO Y ARGUMENTOS DE UNA FUNCIÓN

Una función de C es una porción de código o programa que realiza una determinada tarea. Una función está asociada con un identificador o nombre, que se utiliza para referirse a ella desde el resto del programa. En toda función utilizada en C hay que distinguir entre su definición, su declaración y su llamada. Para explicar estos conceptos hay que introducir los conceptos de valor de retorno y de argumentos.

Quizás lo mejor sea empezar por el concepto más próximo al usuario, que es el concepto de llamada. Las funciones en C se llaman incluyendo su nombre, seguido de los argumentos, en una sentencia del programa principal o de otra función de rango superior. Los argumentos son datos que se envían a la función incluyéndolos entre paréntesis a continuación del nombre, separados por comas. Por ejemplo, supóngase una función llamada power que calcula x elevado a y. Una forma de llamar a esta función es escribir la siguientesentencia (las sentencias de C terminan con punto y coma):power(x,y);

En este ejemplo power es el nombre de la función, y x e y son los argumentos, que en este caso constituyen los datos necesarios para calcular el resultado deseado. ¿Qué pasa con el resultado? ¿Dónde aparece? Pues en el ejemplo anterior el resultado es el valor de retorno de la función, que está disponible pero no se utiliza. En efecto, el resultado de la llamada a power está disponible, pues aparece sustituyendo al nombre de la función en el mismo lugar donde se ha hecho la llamada; en el ejemplo anterior, el resultado aparece, pero no se hace nada con él. A este mecanismo de sustitución de la llamada por el resultado es a lo que se llama valor de retorno. Otra forma de llamar a esta función utilizando el resultado podría serla siguiente:

distancia = power(x+3, y)*escala;En este caso el primer argumento (x+3) es elevado al segundo argumento y, el resultado de la potencia –el valor de retorno– es multiplicado por escala, y este nuevo resultado se almacena en la posición de memoria asociada con el identificador distancia. Este ejemplo resulta típico de lo que es una instrucción o sentencia que incluye una llamada a una

función en el lenguaje C.

Para poder llamar a una función es necesario que en algún otro lado, en el mismo o en algún otro fichero fuente, aparezca la definición de dicha función, que en el ejemplo anterior es la función power. La definición de una función es ni más ni menos que el conjunto de sentencias o instrucciones necesarias para que la función pueda realizar su tarea cuando sea llamada. En otras palabras, la definición es el código correspondiente a la función. Ademásdel código, la definición de la función incluye la definición del tipo del valor de retorno y de cada uno de los argumentos. A continuación se presenta un ejemplo –incompleto– de cómo podría ser la definición de la función power utilizada en el ejemplo anterior. double power(double base, double exponente){double resultado;...resultado = ... ;return resultado;}

La primera línea de la definición es particularmente importante. La primera palabra double indica el tipo del valor de retorno. Esto quiere decir que el resultado de la función será un número de punto flotante con unas 16 cifras de precisión (así es el tipo double, como se verá más adelante). Después viene el nombre de la función seguido de –entre paréntesis– la definición de los argumentos y de sus tipos respectivos. En este caso hay dos argumentos, base y exponente, que son ambos de tipo double. A continuación se abren las llaves que contienen el código de la función1.

La primera sentencia declara la variable resultado, que es también de tipo double. Después vendrían las sentencias necesarias para calcular resultado como base elevado a exponente.

Finalmente, con la sentencia return se devuelve resultado al programa o función que ha llamado a power.

Conviene notar que las variables base y exponente han sido declaradas en la cabecera – primera línea– de la definición, y por tanto ya no hace falta declararlas después, como se ha hecho con resultado. Cuando la función es llamada, las variables base y exponente reciben sendas copias de los valores del primer y segundo argumento que siguen al nombre de lafunción en la llamada.

Una función debe ser también declarada antes de ser llamada. Además de la llamada y la definición, está también la declaración de la función. Ya se verá más adelante dónde se puede realizar esta declaración. La declaración de una función se puede realizar por medio de la primera línea de la definición, de la que pueden suprimirse los nombres de los argumentos, pero no sus tipos; al final debe incluirse el punto y coma (;). Por ejemplo, la función

Ing. Nestor Huaracha Velasquez

Page 26: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 26 power se puede declarar en otra función que la va a llamar incluyendo la línea siguiente:double power(double, double);La declaración de una función permite que el compilador chequee el número y tipo de los argumentos, así como el tipo del valor de retorno. La declaración de la función se conoce también con el nombre de prototipo de la función.

4.3.3. LA FUNCIÓN MAIN( )

Todo programa C, desde el más pequeño hasta el más complejo, tiene un programa principal que es con el que se comienza la ejecución del programa. Este programa principal es también una función, pero una función que está por encima de todas las demás. Esta función se llama main() y tiene la forma siguiente (la palabra void es opcional en este caso):

void main(void){sentencia_1sentencia_2...}

Las llaves {...} constituyen el modo utilizado por el lenguaje C para agrupar varias sentencias de modo que se comporten como una sentencia única (sentencia compuesta o bloque). Todo el cuerpo de la función debe ir comprendido entre las llaves de apertura y cierre.

4.4 Tokens

Existen seis clases de componentes sintácticos o tokens en el vocabulario del lenguaje C: palabras clave, identificadores, constantes, cadenas de caracteres, operadores y separadores. Los separadores –uno o varios espacios en blanco, tabuladores, caracteres de nueva línea (denominados "espacios en blanco" en conjunto), y también los comentarios escritos por el programador– se emplean para separar los demás tokens; por lo demás sonignorados por el compilador. El compilador descompone el texto fuente o programa en cada 1 A una porción de código encerrada entre llaves {...} se le llama sentencia compuesta o bloque.

uno de sus tokens, y a partir de esta descomposición genera el código objeto correspondiente.El compilador ignora también los sangrados al comienzo de las líneas.

4.4.1 PALABRAS CLAVE DEL C

En C, como en cualquier otro lenguaje, existen una serie de palabras clave (keywords) que el usuario no puede utilizar como identificadores (nombres de variables y/o de funciones). Estas palabras sirven para indicar al computador que realice una tarea muy determinada (desde evaluar una comparación, hasta definir el tipo de una variable) y tienen un especial significado para el compilador. El C es un lenguaje muy conciso, con muchas menos palabras clave que otros lenguajes. A continuación se presenta la lista de las 32 palabras clave del ANSI C, para las que más adelante se dará detalle de su significado (algunos compiladores añaden otras palabras clave, propias de cada uno de ellos. Es importante evitarlas como identificadores):

auto double int struct break else long switchcase enum register typedefchar extern return unionconst float short unsignedcontinue for signed voiddefault goto sizeof volatiledo if static while

4.4.2. IDENTIFICADORES

Ya se ha explicado lo que es un identificador: un nombre con el que se hace referencia a una función o al contenido de una zona de la memoria (variable). Cada lenguaje tiene sus propias reglas respecto a las posibilidades de elección de nombres para las funciones y variables. En ANSI C estas reglas son las siguientes: 1. Un identificador se forma con una secuencia de letras (minúsculas de la a a la z; mayúsculas de la A a la Z; y dígitos del 0 al 9).2. El carácter subrayado o underscore (_) se considera como una letra más.3. Un identificador no puede contener espacios en blanco, ni otros caracteres distintos de los citados, como por ejemplo (*,;.:-+, etc.).4. El primer carácter de un identificador debe ser siempre una letra o un (_), es decir, no puede ser un dígito.5. Se hace distinción entre letras mayúsculas y minúsculas. Así, Masa es considerado como un identificador distinto de masa y de MASA.6. ANSI C permite definir identificadores de hasta 31 caracteres de longitud.

Ejemplos de identificadores válidos son los siguientes:

Ing. Nestor Huaracha Velasquez

Page 27: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 27

tiempo, distancia1, caso_A, PI, velocidad_de_la_luzPor el contrario, los siguientes nombres no son válidos (¿Por qué?)1_valor, tiempo-total, dolares$, %final

En general es muy aconsejable elegir los nombres de las funciones y las variables de forma que permitan conocer a simple vista qué tipo de variable o función representan, utilizando para ello tantos caracteres como sean necesarios. Esto simplifica enormemente la tarea de programación y –sobre todo– de corrección y mantenimiento de los programas. Es cierto que los nombres largos son más laboriosos de teclear, pero en general resulta rentabletomarse esa pequeña molestia.

4.4.3. CONSTANTES

Las variables pueden cambiar de valor a lo largo de la ejecución de un programa, o bien en ejecuciones distintas de un mismo programa. Además de variables, un programa utiliza también constantes, es decir, valores que siempre son los mismos. Un ejemplo típico es el número p, que vale 3.141592654. Este valor, con más o menos cifras significativas, puede aparecer muchas veces en las sentencias de un programa. En C existen distintos tipos de constantes:

1. Constantes numéricas. Son valores numéricos, enteros o de punto flotante. Se permiten también constantes octales (números enteros en base 8) y hexadecimales (base 16).

2. Constantes carácter. Cualquier carácter individual encerrado entre apóstrofos (tal como 'a', 'Y', ')', '+', etc.) es considerado por C como una constante carácter, o en realidad como un número entero pequeño (entre 0 y 255, o entre -128 y 127, según los sistemas).

Existe un código, llamado código ASCII, que establece una equivalencia entre cada carácter y un valor numérico correspondiente.

3. Cadenas de caracteres. Un conjunto de caracteres alfanuméricos encerrados entre comillas es también un tipo de constante del lenguaje C, como por ejemplo: "espacio", "Esto es una cadena de caracteres", etc.

4. Constantes simbólicas. Las constantes simbólicas tienen un nombre (identificador) y en esto se parecen a las variables. Sin embargo, no pueden cambiar de valor a lo largo de la ejecución del programa. En C se pueden definir mediante el preprocesador o por medio de la palabra clave const. En C++ se utiliza preferentemente esta segunda forma. Más adelante se verán

con más detalle estos distintos tipos de constantes, así como las constantes de tipo enumeración.

4.4.4. OPERADORES

Los operadores son signos especiales –a veces, conjuntos de dos caracteres– que indican determinadas operaciones a realizar con las variables y/o constantes sobre las que actúan en el programa. El lenguaje C es particularmente rico en distintos tipos de operadores: Aritméticos (+, -, *, /, %), de asignación (=, +=, -=, *=, /=), relacionales (==, <, >, <=, >=, !=), lógicos (&&, ||, !) y otros. Por ejemplo, en la sentencia: espacio = espacio_inicial + 0.5 * aceleracion * tiempo * tiempo;aparece un operador de asignación (=) y dos operadores aritméticos (+ y *). También los operadores serán vistos con mucho más detalle en apartados posteriores.

4.4.5. SEPARADORESComo ya se ha comentado, los separadores están constituidos por uno o varios espacios en blanco, tabuladores, y caracteres de nueva línea. Su papel es ayudar al compilador a descomponer el programa fuente en cada uno de sus tokens. Es conveniente introducir espacios en blanco incluso cuando no son estrictamente necesarios, con objeto de mejorar la legibilidad de los programas.

4.4.6 COMENTARIOSEl lenguaje C permite que el programador introduzca comentarios en

los ficheros fuente que contienen el código de su programa. La misión de los comentarios es servir de explicación o aclaración sobre cómo está hecho el programa, de forma que pueda ser entendido por una persona diferente (o por el propio programador algún tiempo después). Los comentarios son también particularmente útiles (y peligrosos...) cuando el programa forma parte de un examen que el profesor debe corregir. El compilador2 ignora por completo los comentarios.

Los caracteres (/*) se emplean para iniciar un comentario introducido entre el código del programa; el comentario termina con los caracteres (*/). No se puede introducir un comentario dentro de otro. Todo texto introducido entre los símbolos de comienzo (/*) y final (*/) de comentario son siempre ignorados por el compilador. Por ejemplo:

variable_1 = variable_2; /* En esta línea se asigna avariable_1 el valorcontenido en variable_2 */

Los comentarios pueden actuar también como separadores de otros tokens propios del lenguaje C. Una fuente frecuente de errores –no

Ing. Nestor Huaracha Velasquez

Page 28: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 28 especialmente difíciles de detectar– al programar en C, es el olvidarse de cerrar un comentario que se ha abierto previamente.

El lenguaje ANSI C permite también otro tipo de comentarios, tomado del C++. Todo lo que va en cualquier línea del código detrás de la doble barra (//) y hasta el final de la línea, se considera como un comentario y es ignorado por el compilador. Para comentarios cortos, esta forma es más cómoda que la anterior, pues no hay que preocuparse de cerrar el comentario (el fin de línea actúa como cierre). Como contrapartida, si un comentario ocupa varias líneas hay que repetir la doble barra (//) en cada una de las líneas. Con este segundo procedimiento de introducir comentarios, el último ejemplo podría ponerse en la forma:variable_1 = variable_2; // En esta línea se asigna a// variable_1 el valor// contenido en variable_2

1.5 Lenguaje CEn las páginas anteriores ya han ido apareciendo algunas características importantes del lenguaje C. En realidad, el lenguaje C está constituido por tres elementos: el compilador, el preprocesador y la librería estándar. A continuación se explica brevemente en qué consiste cada uno de estos elementos.4.5.1 COMPILADOR

El compilador es el elemento más característico del lenguaje C. Como ya se ha dicho anteriormente, su misión consiste en traducir a lenguaje de máquina el programa C contenido en uno o más ficheros fuente. El compilador es capaz de detectar ciertos errores durante el proceso de compilación, enviando al usuario el correspondiente mensaje de error.

4.5.2 PREPROCESADOREl preprocesador es un componente característico de C, que no existe

en otros lenguajes de programación. El preprocesador actúa sobre el programa fuente, antes de que empiece la compilación propiamente dicha, para realizar ciertas operaciones. Una de estas operaciones es, por ejemplo, la sustitución de constantes simbólicas. Así, es posible que un programa haga uso repetidas veces del valor 3.141592654, correspondiente al número p. Es posible definir una constante simbólica llamada PI que se define como 3.141592654 al comienzo del programa y se introduce luego en el código cada vez que hace falta. En realidad PI no es una variable con un determinado valor: el preprocesador chequea todo el programa antes de comenzar la compilación y sustituye el texto PI por el texto 3.141592654 cada vez que lo encuentra. Las constantes simbólicas suelen escribirse completamente con mayúsculas, para distinguirlas de las variables.

El preprocesador realiza muchas otras funciones que se irán viendo a medida que se vaya explicando el lenguaje. Lo importante es recordar que

actúa siempre por delante del compilador (de ahí su nombre), facilitando su tarea y la del programador.

4.5.3 LIBRERÍA ESTÁNDAR

Con objeto de mantener el lenguaje lo más sencillo posible, muchas sentencias que existen en otros lenguajes, no tienen su correspondiente contrapartida en C. Por ejemplo, en C no hay sentencias para entrada y salida de datos. Es evidente, sin embargo, que ésta es una funcionalidad que hay que cubrir de alguna manera. El lenguaje C lo hace por medio de funciones preprogramadas que se venden o se entregan junto con el compilador.

Estas funciones están agrupadas en un conjunto de librerías de código objeto, que constituyen la llamada librería estándar del lenguaje. La llamada a dichas funciones se hace como a otras funciones cualesquiera, y deben ser declaradas antes de ser llamadas por el programa (más adelante se verá cómo se hace esto por medio de la directiva del preprocesador #include).

4.6. Ficheros

El código de cualquier programa escrito en C se almacena en uno o más ficheros, en el disco del ordenador. La magnitud del programa y su estructura interna determina o aconseja sobre el número de ficheros a utilizar. Como se verá más adelante, la división de un programa en varios ficheros es una forma de controlar su manejo y su modularidad. Cuando los programas son pequeños (hasta 50»100 líneas de código), un solo fichero suele bastar. Para programasmás grandes, y cuando se quiere mantener más independencia entre los distintos subprogramas, es conveniente repartir el código entre varios ficheros.Recuérdese además que cada vez que se introduce un cambio en el programa hay que volver a compilarlo. La compilación se realiza a nivel de fichero, por lo que sólo los ficheros modificados deben ser compilados de nuevo. Si el programa está repartido entre varios ficheros pequeños esta operación se realiza mucho más rápidamente.Recuérdese también que todos los ficheros que contienen código fuente en C deben terminar con la extensión (.c), como por ejemplo: producto.c, solucion.c, etc.

4.7 Lectura y escritura de datosLa lectura y escritura (o entrada y salida) de datos se realiza por medio de llamadas a funciones de una librería que tiene el nombre de stdio (standard input/output). Las declaraciones de las funciones de esta librería están en un

Ing. Nestor Huaracha Velasquez

Page 29: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 29 fichero llamado stdio.h. Se utilizan funciones diferentes para leer datos desde teclado o desde disco, y lo mismo para escribir resultados o texto en la pantalla, en la impresora, en el disco, etc.

Es importante considerar que las funciones de entrada y salida de datos son verdaderas funciones, con todas sus características: nombre, valor de retorno y argumentos.

4.8 Interfaz con el sistema operativoHace algún tiempo lo más habitual era que el compilador de C se llamase desde el entorno del sistema operativo MS-DOS, y no desde Windows. Ahora los entornos de trabajo basados en Windows se han generalizado, y el MS-DOS está en claro restroceso como entorno de de sarrollo. En cualquier caso, la forma de llamar a un compilador varía de un compilador a otro, y es necesario disponer de los manuales o al menos de cierta información relativa al compilador concreto que se esté utilizando. De ordinario se comienza escribiendo el programa en el fichero fuente correspondiente (extensión .c) por medio de un editor de texto. MS-DOS dispone de un editor estándarllamado edit que puede ser utilizado con esta finalidad. En Windows 3.1 o Windows 95 puede utilizarse Notepad.

Existen también entornos de programación más sofisticados que se pueden utilizar desde Windows, como por ejemplo el Visual C++ de Microsoft, o el C++ de Borland. Estos programas ofrecen muchas más posibilidades que las de un simple compilador de ANSI C. En cualquier caso, lo que hay que hacer siempre es consultar el manual correspondiente al compilador que se vaya a utilizar. Estos sistemas disponen de editores propios con ayudas suplementarias para la programación, como por ejemplo criterios de color para distinguir las palabras clave del lenguaje C.

Ing. Nestor Huaracha Velasquez

Page 30: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 30

5. TIPOS DE DATOS FUNDAMENTALES. VARIABLES

El C, como cualquier otro lenguaje de programación, tiene posibilidad de trabajar con datos de distinta naturaleza: texto formado por caracteres alfanuméricos, números enteros, números reales con parte entera y parte fraccionaria, etc. Además, algunos de estos tipos de datos admiten distintos números de cifras (rango y/o precisión), posibilidad de ser sólo positivos o de ser positivos y negativos, etc. En este apartado se verán los tipos fundamentales de datos admitidos por el C. Más adelante se verá que hay otros tipos de datos, derivados de los fundamentales. Los tipos de datos fundamentales del C se indican en la Tabla 2.1.

Tabla 2.1. Tipos de datos fundamentales (notación completa)

Datos enteros char signed char unsigned charsigned short int signed int signed long intunsigned short int unsigned int unsigned long intDatos reales float double long double

La palabra char hace referencia a que se trata de un carácter (una letra mayúscula o minúscula, un dígito, un carácter especial, ...). La palabra int indica que se trata de un número entero, mientras que float se refiere a un número real (también llamado de punto o coma flotante). Los números enteros pueden ser positivos o negativos (signed), o bien esencialmente no negativos (unsigned); los caracteres tienen un tratamiento muy similar a los enteros y admiten estos mismos cualificadores. En los datos enteros, las palabras short y long hacen referencia al número de cifras o rango de dichos números. En los datos reales las palabras double y long apuntan en esta misma dirección, aunque con un significado ligeramente diferente, como más adelante se verá.Esta nomenclatura puede simplificarse: las palabras signed e int son las opciones por defecto para los números enteros y pueden omitirse, resultando la Tabla 2.2, que indica la nomenclatura más habitual para los tipos fundamentales del C.

Tabla 2.2. Tipos de datos fundamentales (notación abreviada).

Datos enteros char signed char unsigned charshort int longunsigned short unsigned unsigned longDatos reales float double long double

A continuación se va a explicar cómo puede ser y cómo se almacena en C un dato de cada tipo fundamental.

Recuérdese que en C es necesario declarar todas las variables que se vayan a utilizar.

Una variable no declarada produce un mensaje de error en la compilación. Cuando una variable es declarada se le reserva memoria de acuerdo con el tipo incluido en la declaración.

Es posible inicializar –dar un valor inicial– las variables en el momento de la declaración; ya se verá que en ciertas ocasiones el compilador da un valor inicial por defecto, mientras que en otros casos no se realiza esta inicialización y la memoria asociada con la variable correspondiente contiene basura informática (combinaciones sin sentido de unos y ceros, resultado de operaciones anteriores con esa zona de la memoria, para otros fines).

5.1 Caracteres (tipo char)

Las variables carácter (tipo char) contienen un único carácter y se almacenan en un byte de memoria (8 bits). En un bit se pueden almacenar dos valores (0 y 1); con dos bits se pueden almacenar 22 = 4 valores (00, 01, 10, 11 en binario; 0, 1 2, 3 en decimal). Con 8 bits se podrán almacenar 28 = 256 valores diferentes (normalmente entre 0 y 255; con ciertos compiladoresentre -128 y 127).

La declaración de variables tipo carácter puede tener la forma:char nombre;char nombre1, nombre2, nombre3;

Se puede declarar más de una variable de un tipo determinado en una sola sentencia. Se puede también inicializar la variable en la declaración. Por ejemplo, para definir la variable carácter letra y asignarle el valor a, se puede escribir:

char letra = ’a’;

A partir de ese momento queda definida la variable letra con el valor correspondiente a la letra a. Recuérdese que el valor ’a’ utilizado para inicializar la variable letra es una constante carácter. En realidad, letra se guarda en un solo byte como un número entero, el correspondiente a la letra a en el código ASCII, que se muestra en la Tabla 2.3 para los caracteres estándar (existe un código ASCII extendido que utiliza los 256 valores y que contiene caracteres especiales y caracteres específicos de los alfabetos de diversos países:

como por ejemplo las vocales acentuadas y la letra ñ para el castellano).

Ing. Nestor Huaracha Velasquez

Page 31: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 31 Tabla 2.3. Código ASCII estándar.0 1 2 3 4 5 6 7 8 90 nul soh stx etx eot enq ack bel bs ht1 nl vt np cr so si dle dc1 dc2 dc32 dc4 nak syn etb can em sub esc fs gs3 rs us sp ! “ # $ % & ‘4 ( ) * + , - . / 0 15 2 3 4 5 6 7 8 9 : ;6 < = > ? @ A B C D E7 F G H I J K L M N O8 P Q R S T U V W X Y9 Z [ \ ] ^ _ ` a b c10 d e f g h i j k l m11 n o p q r s t u v w12 x y z { | } ~ del

La Tabla 2.3 se utiliza de la siguiente forma. La primera cifra (las dos primeras cifras, en el caso de los números mayores o iguales que 100) del número ASCII correspondiente a un carácter determinado figura en la primera columna de la Tabla, y la última cifra en la primera fila de la Tabla. Sabiendo la fila y la columna en la que está un determinado carácter puede componerse el número correspondiente. Por ejemplo, la letra A está en la fila 6 y la columna 5. Su número ASCII es por tanto el 65. El carácter % está en la fila 3 y la columna 7, por lo que su representación ASCII será el 37. Obsérvese que el código ASCII asocia números consecutivos con las letras mayúsculas y minúsculas ordenadas alfabéticamente. Esto simplifica notablemente ciertas operaciones de ordenación alfabética de nombres.

En la Tabla 2.3 aparecen muchos caracteres no imprimibles (todos aquellos que se expresan con 2 ó 3 letras). Por ejemplo, el ht es el tabulador horizontal, el nl es el carácter nueva línea, etc. Volviendo al ejemplo de la variable letra, su contenido puede ser variado cuando se desee por medio de una sentencia que le asigne otro valor, por ejemplo:

letra = ’z’;También puede utilizarse una variable char para dar valor a otra variable de tipo char:caracter = letra; // Ahora caracter es igual a ’z’

Como una variable tipo char es un número entero pequeño (entre 0 y 255), se puede utilizar el contenido de una variable char de la misma forma que se utiliza un entero, por lo que están permitidas operaciones como:

letra = letra + 1;letra_minuscula = letra_mayuscula + (’a’ - ’A’);

En el primer ejemplo, si el contenido de letra era una a, al incrementarse en una unidad pasa a contener una b. El segundo ejemplo es interesante: puesto que la diferencia numérica entre las letras minúsculas y mayúsculas es siempre la misma (según el código ASCII), la segunda sentencia pasa una letra mayúscula a la correspondiente letra minúscula sumándole dicha diferencia numérica.

Recuérdese para concluir que las variables tipo char son y se almacenan como números enteros pequeños. Ya se verá más adelante que se pueden escribir como caracteres o como números según que formato de conversión se utilice en la llamada a la función de escritura.

5.2. Números enteros (tipo int)

De ordinario una variable tipo int se almacena en 2 bytes (16 bits), aunque algunos compiladores utilizan 4 bytes (32 bits). El ANSI C no tiene esto completamente normalizado y existen diferencias entre unos compiladores y otros. Los compiladores de Microsoft para PCs utilizan 2 bytes.

Con 16 bits se pueden almacenar 216 = 65536 números enteros diferentes: de 0 al 65535 para variables sin signo, y de -32768 al 32767 para variables con signo (que pueden ser positivas y negativas), que es la opción por defecto. Este es el rango de las variables tipo int.

Una variable entera (tipo int) se declara, o se declara y se inicializa en la forma:unsigned int numero;int nota = 10;

En este caso la variable numero podrá estar entre 0 y 65535, mientras que nota deberá estar comprendida entre -32768 al 32767. Cuando a una variable int se le asigna en tiempo de ejecución un valor que queda fuera del rango permitido (situación de overflow o valor excesivo), se produce un error en el resultado de consecuencias tanto más imprevisibles cuanto que de ordinario el programa no avisa al usuario de dicha circunstancia.

Cuando el ahorro de memoria es muy importante puede asegurarse que el computador utiliza 2 bytes para cada entero declarándolo en una de las formas siguientes:short numero;short int numero;

Como se ha dicho antes, ANSI C no obliga a que una variable int ocupe 2 bytes, pero declarándola como short o short int sí que necesitará sólo 2 bytes (al menos en los PCs).

Ing. Nestor Huaracha Velasquez

Page 32: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 32

5.3 Números enteros (tipo long)

Existe la posibilidad de utilizar enteros con un rango mayor si se especifica como tipo long en

su declaración:long int numero_grande;o, ya que la palabra clave int puede omitirse en este caso,long numero_grande;

El rango de un entero long puede variar según el computador o el compilador que se utilice, pero de ordinario se utilizan 4 bytes (32 bits) para almacenarlos, por lo que se pueden representar 232 = 4.294.967.296 números enteros diferentes. Si se utilizan números con signo, podrán representarse números entre -2.147.483.648 y 2.147.483.647. También se pueden declarar enteros long que sean siempre positivos con la palabra unsigned:

unsigned long numero_positivo_muy_grande;

En algunos computadores una variable int ocupa 2 bytes (coincidiendo con short) y en otros 4 bytes (coincidiendo con long). Lo que garantiza el ANSI C es que el rango de int no es nunca menor que el de short ni mayor que el de long.

5.4 Números reales (tipo float)

En muchas aplicaciones hacen falta variables reales, capaces de representar magnitudes que contengan una parte entera y una parte fraccionaria o decimal. Estas variables se llaman también de punto flotante. De ordinario, en base 10 y con notación científica, estas variables se representan por medio de la mantisa, que es un número mayor o igual que 0.1 y menor que 1.0, y -un exponente que representa la potencia de 10 por la que hay que multiplicar la mantisa para obtener el número considerado. Por ejemplo, p se representa como 0.3141592654 · 101.

Tanto la mantisa como el exponente pueden ser positivos y negativos.

Los computadores trabajan en base 2. Por eso un número de tipo float se almacena en 4 bytes (32 bits), utilizando 24 bits para la mantisa (1 para el signo y 23 para el valor) y 8 bits para el exponente (1 para el signo y 7 para el valor). Es interesante ver qué clase de números de punto flotante pueden representarse de esta forma. En este caso hay que distinguir el rango de la precisión. La precisión hace referencia al número de cifras con las que se

representa la mantisa: con 23 bits el número más grande que se puede representar es, 223 = 8.388.608 lo cual quiere decir que se pueden representar todos los números decimales de 6 cifras y la mayor parte –aunque no todos– de los de 7 cifras (por ejemplo, el número 9.213.456 no se puede representar con 23 bits). Por eso se dice que las variables tipo float tienen entre 6 y 7 cifras decimales equivalentes de precisión.

Respecto al exponente de dos por el que hay que multiplicar la mantisa en base 2, con 7 bits el número más grande que se puede representar es 127. El rango vendrá definido por la potencia, 2127 = 1.7014 · 1038 lo cual indica el número más grande representable de esta forma. El número más pequeño envalor absoluto será del orden de 2-128 = 2.9385 · 10-39

Las variables tipo float se declaran de la forma:float numero_real;

Las variables tipo float pueden ser inicializadas en el momento de la declaración, de forma análoga a las variables tipo int.

5.5 Números reales (tipo double)

Las variables tipo float tienen un rango y –sobre todo– una precisión muy limitada, insuficiente para la mayor parte de los cálculos técnicos y científicos. Este problema se soluciona con el tipo double, que utiliza 8 bytes (64 bits) para almacenar una variable. Se utilizan 53 bits para la mantisa (1 para el signo y 52 para el valor) y 11 para el exponente (1 para el signo y 10 para el valor). La precisión es en este caso, 252 = 4.503.599.627.370.496 lo cual representa entre 15 y 16 cifras decimales equivalentes.

Con respecto al rango, con un exponente de 10 bits el número más grande que se puede representar será del orden de 2 elevado a 2 elevado a 10 (que es 1024): 21024 = 1.7977 · 10308 Las variables tipo double se declaran de forma análoga a las anteriores: double real_grande;

Por último, existe la posibilidad de declarar una variable como long double, aunque el ANSI C no garantiza un rango y una precisión mayores que las de double. Eso depende del compilador y del tipo de computador. Estas variables se declaran en la forma:

long double real_pero_que_muy_grande;cuyo rango y precisión no está normalizado. Los compiladores de Microsoft para PCs utilizan 10 bytes (64 bits para la mantisa y 16 para el exponente).

Ing. Nestor Huaracha Velasquez

Page 33: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 33 5.6 Duración y visibilidad de las variables: Modos de almacenamiento.

El tipo de una variable se refiere a la naturaleza de la información que contiene (ya se han visto los tipos char, int, long, float, double, etc.).

El modo de almacenamiento (storage class) es otra característica de las variables de C que determina cuándo se crea una variable, cuándo deja de existir y desde dónde se puede acceder a ella, es decir, desde dónde es visible.En C existen 4 modos de almacenamiento fundamentales: auto, extern, static y register. Seguidamente se exponen las características de cada uno de estos modos.

1. auto (automático). Es la opción por defecto para las variables que se declaran dentro de un bloque {...}, incluido el bloque que contiene el código de las funciones. En C la declaración debe estar siempre al comienzo del bloque. En C++ la declaración puede estar en cualquier lugar y hay autores que aconsejan ponerla justo antes del primer uso de la variable.

No es necesario poner la palabra auto. Cada variable auto es creada al comenzar a ejecutarse el bloque y deja de existir cuando el bloque se termina de ejecutar. Cada vez que se ejecuta el bloque, las variables auto se crean y se destruyen de nuevo.

Las variables auto son variables locales, es decir, sólo son visibles en el bloque en el que están definidas y en otros bloques anidados3 en él, aunque pueden ser ocultadas por una nueva declaración de una nueva variable con el mismo nombre en un bloque anidado.

No son inicializadas por defecto, y –antes de que el programa les asigne un valor– pueden contener basura informática (conjuntos aleatorios de unos y ceros, consecuencia de un uso anterior de esa zona de la memoria). A continuación se muestra un ejemplo de uso de variables de modo auto.

{int i=1, j=2; // se declaran e inicializan i y j...{float a=7., j=3.; // se declara una nueva variable j...j=j+a; // aqui j es float... // la variable int j es invisible... // la variable i=1 es visible}... // fuera del bloque, a ya no existe... // la variable j=2 existe y es entera

}

2. extern. Son variables globales, que se definen fuera de cualquier bloque o función, por ejemplo antes de definir la función main(). Estas variables existen durante toda la ejecución del programa. Las variables extern son visibles por todas las funciones que están entre la definición y el fin del fichero. Para verlas desde otras funciones definidas anteriormente o desde otros ficheros, deben ser declaradas en ellos como variables extern. Por defecto, son inicializadas a cero.

Una variable extern es definida o creada (una variable se crea en el momento en el que se le reserva memoria y se le asigna un valor) una sola vez, pero puede ser declarada (es decir, reconocida para poder ser utilizada) varias veces, con objeto de hacerla accesible desde diversas funciones o ficheros.

También estas variables pueden ocultarse mediante la declaración de otra variable con el mismo nombre en el interior de un bloque. La variables extern permiten transmitir valores entre distintas funciones, pero ésta es una práctica considerada como peligrosa. A continuación se presenta un ejemplo de uso de variables extern.

int i=1, j, k; // se declaran antes de main()main(){int i=3; // i=1 se hace invisibleint func1(int, int);... // j, k son visibles}

Se llama bloque anidado a un bloque contenido dentro de otro bloque.

int func1(int i, int m){int k=3; // k=0 se hace invisible... // i=1 es invisible}

3. static. Cuando ciertas variables son declaradas como static dentro de un bloque, estas variables conservan su valor entre distintas ejecuciones de ese bloque. Dicho de otra forma, las variables static se declaran dentro de un

Ing. Nestor Huaracha Velasquez

Page 34: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 34 bloque como las auto, pero permanecen en memoria durante toda la ejecución del programa como las extern. Cuando se llama varias veces sucesivas a una función (o se ejecuta varias veces un bloque) que tiene declaradas variables static, los valores de dichas variables se conservan entre dichas llamadas. La inicialización sólo se realiza la primera vez. Por defecto, son inicializadas a cero.

Las variables definidas como static extern son visibles sólo para las funciones y bloques comprendidos desde su definición hasta el fin del fichero. No son visibles desde otras funciones ni aunque se declaren como extern. Ésta es una forma de restringir la visibilidad de las variables.

Por defecto, y por lo que respecta a su visibilidad, las funciones tienen modo extern.Una función puede también ser definida como static, y entonces sólo es visible para las funciones que están definidas después de dicha función y en el mismo fichero. Con estos modos se puede controlar la visibilidad de una función, es decir, desde qué otras funciones puede ser llamada.

4. register. Este modo es una recomendación para el compilador, con objeto de que –si es posible– ciertas variables sean almacenadas en los registros de la CPU y los cálculos con ellas sean más rápidos. No existen los modos auto y register para las funciones.

5.7 Conversiones de tipo implícitas y explícitas(casting)

Más adelante se comentarán (ver Sección 4.2) las conversiones implícitas de tipo que tienen lugar cuando en una expresión se mezclan variables de distintos tipos. Por ejemplo, para poder sumar dos variables hace falta que ambas sean del mismo tipo. Si una es int y otra float, la primera se convierte a float (es decir, la variable del tipo de menor rango se convierte al tipo de mayor rango), antes de realizar la operación. A esta conversión automática e implícita de tipo (el programador no necesita intervenir, aunque sí conocer sus reglas), se le denomina promoción, pues la variable de menor rango es promocionada al rango de la otra.

Así pues, cuando dos tipos diferentes de constantes y/o variables aparecen en una misma expresión relacionadas por un operador, el compilador convierte los dos operandos al mismo tipo de acuerdo con los rangos, que de mayor a menor se ordenan del siguiente modo:

long double > double > float > unsigned long > long > unsigned int > int > charOtra clase de conversión implícita tiene lugar cuando el resultado de una expresión es asignado a una variable, pues dicho resultado se convierte al tipo de la variable (en este caso, ésta puede ser de menor rango que la expresión, por lo que esta conversión puede perder información y ser peligrosa). Por ejemplo, si i y j son variables enteras y x es double,x = i*j – j + 1;

En C existe también la posibilidad de realizar conversiones explícitas de tipo (llamadas casting, en la literatura inglesa). El casting es pues una conversión de tipo, forzada por el programador. Para ello basta preceder la constante, variable o expresión que se desea convertir por el tipo al que se desea convertir, encerrado entre paréntesis. En el siguiente ejemplo, k = (int) 1.7 + (int) masa; la variable masa es convertida a tipo int, y la constante 1.7 (que es de tipo double) también. El casting se aplica con frecuencia a los valores de retorno de las funciones.

Ing. Nestor Huaracha Velasquez

Page 35: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 35 6. CONSTANTES

Se entiende por constantes aquel tipo de información numérica o alfanumérica que no puede cambiar más que con una nueva compilación del programa. Como ya se ha dicho anteriormente, en el código de un programa en C pueden aparecer diversos tipos de constantes que se van a explicar a continuación.

6.1 Constantes numéricas

6.1.1 CONSTANTES ENTERAS.

Una constante entera decimal está formada por una secuencia de dígitos del 0 al 9, constituyendo un número entero. Las constantes enteras decimales están sujetas a las mismas restricciones de rango que las variables tipo int y long, pudiendo también ser unsigned. El tipo de una constante se puede determinar automáticamente según su magnitud, o de modo explícito postponiendo ciertos caracteres, como en los ejemplos que siguen:

23484 constante tipo int45815 constante tipo long (es mayor que 32767)253u ó 253U constante tipo unsigned int739l ó 739L constante tipo long583ul ó 583UL constante tipo unsigned long

En C se pueden definir también constantes enteras octales, esto es, expresadas en base 8 con dígitos del 0 al 7. Se considera que una constante está expresada en base 8 si el primer dígito por la izquierda es un cero (0). Análogamente, una secuencia de dígitos (del 0 al 9) y de letras (A, B, C, D, E, F) precedida por 0x o por 0X, se interpreta como una constante entera hexadecimal, esto es, una constante numérica expresada en base 16.

Por ejemplo:

011 constante octal (igual a 9 en base 10)11 constante entera decimal (no es igual a 011)0xA constante haxadecimal (igual a 10 en base 10)0xFF constante hexadecimal (igual a 162-1=255 en base 10)Es probable que no haya necesidad de utilizar constantes octales y hexadecimales, pero conviene conocer su existencia y saber interpretarlas por si hiciera falta. La ventaja de los números expresados en base 8 y base 16 proviene de su estrecha relación con la base 2 ( 8 y 16 son potencias de 2), que es la forma en la que el ordenador almacena la información.

6.1.2 CONSTANTES DE PUNTO FLOTANTE

Como es natural, existen también constantes de punto flotante, que pueden ser de tipo float, double y long double. Una constante de punto flotante se almacena de la misma forma que la variable correspondiente del mismo tipo. Por defecto –si no se indica otra cosa– las constantes de punto flotante son de tipo double. Para indicar que una constante es de tipo float se le añade una f o una F; para indicar que es de tipo long double, se le añade una l o una L. En cualquier caso, el punto decimal siempre debe estar presente si se trata de representar un número real.

Estas constantes se pueden expresar de varias formas. La más sencilla es un conjunto de dígitos del 0 al 9, incluyendo un punto decimal. Para constantes muy grandes o muy pequeñas puede utilizarse la notación científica; en este caso la constante tiene una parte entera, un punto decimal, una parte fraccionaria, una e o E, y un exponente entero (afectando a la base10), con un signo opcional. Se puede omitir la parte entera o la fraccionaria, pero no ambas a la vez. Las constantes de punto flotante son siempre positivas. Puede anteponerse un signo (-), pero no forma parte de la constante, sino que con ésta constituye una expresión, como se verá más adelante.

A continuación se presentan algunos ejemplos válidos:

1.23 constante tipo double (opción por defecto)23.963f constante tipo float.00874 constante tipo double23e2 constante tipo double (igual a 2300.0).874e-2 constante tipo double en notación científica (=.00874).874e-2f constante tipo float en notación científicaseguidos de otros que no son correctos:1,23 error: la coma no esta permitida23963f error: no hay punto decimal ni carácter e ó E.e4 error: no hay ni parte entera ni fraccionaria-3.14 error: sólo el exponente puede llevar signo

6.2 Constantes carácter

Una constante carácter es un carácter cualquiera encerrado entre apóstrofos (tal como 'x' o 't'). El valor de una constante carácter es el valor numérico asignado a ese carácter según el código ASCII (ver Tabla 2.3). Conviene indicar que en C no existen constantes tipo char; lo que se llama aquí constantes carácter son en realidad constantes enteras.Hay que señalar que el valor ASCII de los números del 0 al 9 no coincide con el propio valor numérico. Por ejemplo, el valor ASCII de la constante carácter '7' es 55. Ciertos caracteres no representables gráficamente, el apóstrofo (') y la barra invertida (\) y otros caracteres, se representan mediante la siguiente tabla de secuencias de escape, con ayuda de la barra invertida (\)4 Nombre completo Constante en C ASCII

Ing. Nestor Huaracha Velasquez

Page 36: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 36 sonido de alerta BEL \a 7nueva línea NL \n 10tabulador horizontal HT \t 9retroceso BS \b 8retorno de carro CR \r 13salto de página FF \f 12barra invertida \ \\ 92apóstrofo ' \' 39comillas " \" 34carácter nulo NULL \0 0

Los caracteres ASCII pueden ser también representados mediante el número octal correspondiente, encerrado entre apóstrofos y precedido por la barra invertida. Por ejemplo, '\07' y '\7' representan el número 7 del código ASCII (sin embargo, '\007' es la representación octal del carácter '7'), que es el sonido de alerta. El ANSI C también admite secuencias de escape hexadecimales, por ejemplo '\x1a'.

6.3 Cadenas de caracteresUna cadena de caracteres es una secuencia de caracteres delimitada

por comillas ("), como por ejemplo: "Esto es una cadena de caracteres". Dentro de la cadena, pueden aparecer caracteres 4 Una secuencia de escape está constituida por la barra invertida (\) seguida de otro carácter. La finalidad de la secuencia de escape es cambiar el significado habitual del carácter que sigue a la barra invertida en blanco y se pueden emplear las mismas secuencias de escape válidas para las constantes carácter. Por ejemplo, las comillas (") deben estar precedidas por (\), para no ser interpretadas como fin de la cadena; también la propia barra invertida (\). Es muy importante señalar que el compilador sitúa siempre un byte nulo (\0) adicional al final de cada cadena de caracteres para señalar el final de la misma. Así, la cadena "mesa" no ocupa 4 bytes, sino 5 bytes.

A continuación se muestran algunos ejemplos de cadenas de caracteres:"Informática I""'A'"" cadena con espacios en blanco ""Esto es una \"cadena de caracteres\".\n"

6.4 Constantes de tipo Enumeración

En C existen una clase especial de constantes, llamadas constantes enumeración. Estas constantes se utilizan para definir los posibles valores de ciertos identificadores o variables que sólo deben poder tomar unos pocos valores. Por ejemplo, se puede pensar en una variable llamada

dia_de_la_semana que sólo pueda tomar los 7 valores siguientes: lunes, martes, miercoles, jueves, viernes, sabado y domingo. Es muy fácil imaginar otros tipos de variables análogas, una de las cuales podría ser una variable booleana con sólo dos posibles valores: SI y NO, o TRUE y FALSE, u ON y OFF. El uso de este tipo de variables hace más claros y legibles los programas, a la par que disminuye la probabilidad de introducir errores. En realidad, las constantes enumeración son los posibles valores de ciertas variables definidas como de ese tipo concreto. Considérese como ejemplo la siguiente declaración:

enum dia {lunes, martes, miercoles, jueves, viernes, sabado, domingo};

Esta declaración crea un nuevo tipo de variable –el tipo de variable dia– que sólo puede tomar uno de los 7 valores encerrados entre las llaves. Estos valores son en realidad constantes tipo int: lunes es un 0, martes es un 1, miercoles es un 2, etc. Ahora, es posible definir variables, llamadas dia1 y dia2, que sean de tipo dia, en la forma (obsérvese que en C deben aparecer las palabras enum dia; en C++ basta que aparezca la palabra dia)

enum dia dia1, dia2; // esto es C dia dia 1, dia 2; // esto es C++y a estas variables se les pueden asignar valores en la formadia1 = martes;o aparecer en diversos tipos de expresiones y de sentencias que se explicarán más adelante.

Los valores enteros que se asocian con cada constante tipo enumeración pueden ser controlados por el programador. Por ejemplo, la declaración,

enum dia {lunes=1, martes, miercoles, jueves, viernes, sabado, domingo};asocia un valor 1 a lunes, 2 a martes, 3 a miercoles, etc., mientras que la declaración,enum dia {lunes=1, martes, miercoles, jueves=7, viernes, sabado, domingo};asocia un valor 1 a lunes, 2 a martes, 3 a miercoles, un 7 a jueves, un 8 a viernes, un 9 asabado y un 10 a domingo.

Se puede también hacer la definición del tipo enum y la declaración de las variables en una única sentencia, en la forma enum palo {oros, copas, espadas, bastos} carta1, carta2, carta3; donde carta1, carta2 y carta3 son variables que sólo pueden tomar los valores oros, copas, espadas y bastos (equivalentes respectivamente a 0, 1, 2 y 3).

6.4.1 CUALIFICADOR CONST

Ing. Nestor Huaracha Velasquez

Page 37: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 37 Se puede utilizar el cualificador const en la declaración de una variable para indicar que esa variable no puede cambiar de valor. Si se utiliza con un array, los elementos del array no pueden cambiar de valor. Por ejemplo:

const int i=10;const double x[] = {1, 2, 3, 4};

El lenguaje C no define lo que ocurre si en otra parte del programa o en tiempo de ejecución se intenta modificar una variable declarada como const. De ordinario se obtendrá un mensaje de error en la compilación si una variable const figura a la izquierda de un operador de asignación. Sin embargo, al menos con el compilador de Microsoft, se puede modificar una variable declarada como const por medio de un puntero de la forma siguiente:

const int i=10;int *p;p = &i;*p = 1;

C++ es mucho más restrictivo en este sentido, y no permite de ninguna manera modificar las variables declaradas como const.

El cualificador const se suele utilizar cuando, por motivos de eficiencia, se pasan argumentos por referencia a funciones y no se desea que dichos argumentos sean modificados por éstas.

Ing. Nestor Huaracha Velasquez

Page 38: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 38 7 . OPERADORES, EXPRESIONES Y SENTENCIAS

7.1 Operadores

Un operador es un carácter o grupo de caracteres que actúa sobre una, dos o más variables para realizar una determinada operación con un determinado resultado. Ejemplos típicos de operadores son la suma (+), la diferencia (-), el producto (*), etc. Los operadores pueden ser unarios, binarios y ternarios, según actúen sobre uno, dos o tres operandos, respectivamente.

En C existen muchos operadores de diversos tipos (éste es uno de los puntos fuertes del lenguaje), que se verán a continuación.

7.1.1 OPERADORES ARITMÉTICOS

Los operadores aritméticos son los más sencillos de entender y de utilizar. Todos ellos son operadores binarios. En C se utilizan los cinco operadores siguientes:

– Suma: +– Resta: -– Multiplicación: *– División: /– Resto: %

Todos estos operadores se pueden aplicar a constantes, variables y expresiones. El resultado es el que se obtiene de aplicar la operación correspondiente entre los dos operandos.

El único operador que requiere una explicación adicional es el operador resto %. En realidad su nombre completo es resto de la división entera. Este operador se aplica solamente a constantes, variables o expresiones de tipo int. Aclarado esto, su significado es evidente: 23%4 es 3, puesto que el resto de dividir 23 por 4 es 3. Si a%b es cero, a es múltiplo de b.

Como se verá más adelante, una expresión es un conjunto de variables y constantes –y también de otras expresiones más sencillas– relacionadas mediante distintos operadores. Un ejemplo de expresión en la que intervienen operadores aritméticos es el siguiente polinomio de grado 2 en la variable x:

5.0 + 3.0*x - x*x/2.0

Las expresiones pueden contener paréntesis (...) que agrupan a algunos de sus términos.Puede haber paréntesis contenidos dentro de otros paréntesis. El significado de los paréntesis coincide con el habitual en las expresiones matemáticas, con

algunas características importantes que se verán más adelante. En ocasiones, la introducción de espacios en blanco mejora la legibilidad de las expresiones.

7.1.2 OPERADORES DE ASIGNACIÓN

Los operadores de asignación atribuyen a una variable –es decir, depositan en la zona de memoria correspondiente a dicha variable– el resultado de una expresión o el valor de otra variable (en realidad, una variable es un caso particular de una expresión).

El operador de asignación más utilizado es el operador de igualdad (=), que no debe ser confundido con la igualdad matemática. Su forma general es:nombre_de_variable = expresion; cuyo funcionamiento es como sigue: se evalúa expresion y el resultado se deposita en nombre_de_variable, sustituyendo cualquier otro valor que hubiera en esa posición de memoria anteriormente. Una posible utilización de este operador es como sigue:

variable = variable + 1;

Desde el punto de vista matemático este ejemplo no tiene sentido (¡Equivale a 0 = 1!), pero sí lo tiene considerando que en realidad el operador de asignación (=) representa una sustitución; en efecto, se toma el valor de variable contenido en la memoria, se le suma una unidad y el valor resultante vuelve a depositarse en memoria en la zona correspondiente al identificador variable, sustituyendo al valor que había anteriormente. El resultado ha sidoincrementar el valor de variable en una unidad.

Así pues, una variable puede aparecer a la izquierda y a la derecha del operador (=). Sin embargo, a la izquierda del operador de asignación (=) no puede haber nunca una expresión: tiene que ser necesariamente el nombre de una variable. Es incorrecto, por tanto, escribir algo así como:a + b = c; // incorrecto

Existen otros cuatro operadores de asignación (+=, -=, *= y /=) formados por los 4 operadores aritméticos seguidos por el carácter de igualdad. Estos operadores simplifican algunas operaciones recurrentes sobre una misma variable. Su forma general es:

variable op= expresion;

donde op representa cualquiera de los operadores (+ - * /). La expresión anterior es equivalente a:variable = variable op expresion;

A continuación se presentan algunos ejemplos con estos operadores de asignación:

Ing. Nestor Huaracha Velasquez

Page 39: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 39 distancia += 1; equivale a: distancia = distancia + 1;rango /= 2.0 equivale a: rango = rango /2.0x *= 3.0 * y - 1.0 equivale a: x = x * (3.0 * y - 1.0)

7.1.3 OPERADORES INCREMENTALES

Los operadores incrementales (++) y (--) son operadores unarios que incrementan o disminuyen en una unidad el valor de la variable a la que afectan. Estos operadores pueden ir inmediatamente delante o detrás de la variable. Si preceden a la variable, ésta es incrementada antes de que el valor de dicha variable sea utilizado en la expresión en la que aparece. Si es la variable la que precede al operador, la variable es incrementada después de ser utilizada en la expresión. A continuación se presenta un ejemplo de estos operadores:

i = 2;j = 2;m = i++; // despues de ejecutarse esta sentencia m=2 e i=3n = ++j; // despues de ejecutarse esta sentencia n=3 y j=3

Estos operadores son muy utilizados. Es importante entender muy bien por qué los resultados m y n del ejemplo anterior son diferentes.

También podría ir una dirección de memoria -o una expresión cuyo resultado fuera una dirección de memoria-, precedida del operador indirección (*). Esto es lo que en C se llama left-value o l-value (algo que puede estar a la izquierda del oprador (=)). Más adelante, al hablar de punteros, quedará más claro este tema.

7.1.4 OPERADORES RELACIONALES

Este es un apartado especialmente importante para todas aquellas personas sin experiencia en programación. Una característica imprescindible de cualquier lenguaje de programación es la de considerar alternativas, esto es, la de proceder de un modo u otro según se cumplan o no ciertas condiciones. Los operadores relacionales permiten estudiar si se cumplen o no esas condiciones. Así pues, estos operadores producen un resultado u otro según se cumplan o no algunas condiciones que se verán a continuación.En el lenguaje natural, existen varias palabras o formas de indicar si se cumple o no una determinada condición. En inglés estas formas son (yes, no), (on, off), (true, false), etc. En Informática se ha hecho bastante general el utilizar la última de las formas citadas: (true, false). Si una condición se cumple, el resultado es true; en caso contrario, el resultado es false.

En C un 0 representa la condición de false, y cualquier número distinto de 0 equivale a la condición true. Cuando el resultado de una expresión es true y hay que asignar un valor concreto distinto de cero, por defecto se toma un valor unidad. Los operadores relacionalesde C son los siguientes:

– Igual que: ==– Menor que: <– Mayor que: >– Menor o igual que: <=– Mayor o igual que: >=– Distinto que: !=

Todos los operadores relacionales son operadores binarios (tienen dos operandos), y su forma general es la siguiente: expresion1 op expresion2donde op es uno de los operadores (==, <, >, <=, >=, !=). El funcionamiento de estos operadores es el siguiente: se evalúan expresion1 y expresion2, y se comparan los valores resultantes. Si la condición representada por el operador relacional se cumple, el resultado es 1; si la condición no se cumple, el resultado es 0.

A continuación se incluyen algunos ejemplos de estos operadores aplicados aconstantes:(2==1) // resultado=0 porque la condición no se cumple(3<=3) // resultado=1 porque la condición se cumple(3<3) // resultado=0 porque la condición no se cumple(1!=1) // resultado=0 porque la condición no se cumple

7.1.5 OPERADORES LÓGICOSLos operadores lógicos son operadores binarios que permiten combinar los resultados de los operadores relacionales, comprobando que se cumplen simultáneamente varias condiciones, que se cumple una u otra, etc. El lenguaje C tiene dos operadores lógicos: el operador Y (&&) y el operador O (||). En inglés son los operadores and y or.

Su forma general es la siguiente:expresion1 || expresion2expresion1 && expresion2

El operador && devuelve un 1 si tanto expresion1 como expresion2 son verdaderas (o distintas de 0), y 0 en caso contrario, es decir si una de las dos expresiones o las dos son falsas (iguales a 0); por otra parte, el operador || devuelve 1 si al menos una de las expresiones es cierta. Es importante tener en cuenta que los compiladores de C tratan de optimizar la ejecución de estas expresiones, lo cual puede tener a veces efectos no deseados. Por ejemplo:

Ing. Nestor Huaracha Velasquez

Page 40: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 40

para que el resultado del operador && sea verdadero, ambas expresiones tienen que ser verdaderas; si se evalúa expresion1 y es falsa, ya no hace falta evaluar expresion2, y de hecho no se evalúa. Algo parecido pasa con el operador ||: si expresion1 es verdadera, ya no hace falta evaluar expresion2.

Los operadores && y || se pueden combinar entre sí –quizás agrupados entreparéntesis–, dando a veces un código de más difícil interpretación. Por ejemplo:(2==1) || (-1==-1) // el resultado es 1(2==2) && (3==-1) // el resultado es 0((2==2) && (3==3)) || (4==0) // el resultado es 1((6==6) || (8==0)) && ((5==5) && (3==2)) // el resultado es 0

7.1.6 OTROS OPERADORES

Además de los operadores vistos hasta ahora, el lenguaje C dispone de otros operadores. En esta sección se describen algunos operadores unarios adicionales.

– Operador menos (–).

El efecto de este operador en una expresión es cambiar el signo de la variable o expresión que le sigue. Recuérdese que en C no hay constantes numéricas negativas. La forma general de este operador es:

- expresion– Operador más (+).

Este es un nuevo operador unario introducido en el ANSI C, y que tiene como finalidad la de servir de complemento al operador (–) visto anteriormente. Se puede anteponer a una variable o expresión como operador unario, pero en realidad no hace nada.

– Operador sizeof().Este es el operador de C con el nombre más largo. Puede parecer una función, pero en realidad es un operador. La finalidad del operador sizeof() es devolver el tamaño, en bytes, del tipo de variable introducida entre los paréntesis. Recuérdese que este tamaño depende del compilador y del tipo de computador que se está utilizando, por lo que es necesario disponer de este operador para producir código portable. Por ejemplo:

var_1 = sizeof(double) // var_1 contiene el tamaño

// de una variable double

– Operador negación lógica (!).Este operador devuelve un cero (false) si se aplica a un valor distinto de cero (true), y devuelve un 1 (true) si se aplica a un valor cero (false). Su forma general es:

!expresion

– Operador coma (,).Los operandos de este operador son expresiones, y tiene la forma general:expresion = expresion_1, expresion_2 En este caso, expresion_1 se evalúa primero, y luego se evalúa expresion_2. El resultado global es el valor de la segunda expresión, es decir de expresion_2. Este es el operador de menos precedencia de todos los operadores de C. Como se explicará más adelante, su uso más frecuente es para introducir expresiones múltiples en la sentencia for.

– Operadores dirección (&) e indirección (*).Aunque estos operadores se introduzcan aquí de modo circunstancial, su importancia en el lenguaje C es absolutamente esencial, resultando uno de los puntos más fuertes –y quizás más difíciles de dominar– de este lenguaje. La forma general de estos operadores es la siguiente:

*expresion;&variable;

El operador dirección & devuelve la dirección de memoria de la variable que le sigue. Por ejemplo:variable_1 = &variable_2;

Después de ejecutarse esta instrucción variable_1 contiene la dirección de memoria donde se guarda el contenido de variable_2. Las variables que almacenan direcciones de otras variables se denominan punteros (o apuntadores), deben ser declaradas como tales, y tienen su propia aritmética y modo de funcionar. Se verán con detalle un poco más adelante.

No se puede modificar la dirección de una variable, por lo que no están permitidas operaciones en las que el operador & figura a la izda del operador (=), al estilo de:

&variable_1 = nueva_direccion;

El operador indirección * es el operador complementario del &. Aplicado a una expresión que represente una dirección de memoria (puntero) permite hallar el contenido o valor almacenado en esa dirección. Por ejemplo:

variable_3 = *variable_1;

Ing. Nestor Huaracha Velasquez

Page 41: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 41 El contenido de la dirección de memoria representada por la variable de tipo puntero variable_1 se recupera y se asigna a la variable variable_3.

Como ya se ha indicado, las variables puntero y los operadores dirección (&) e indirección (*) serán explicados con mucho más detalle en una sección posterior.

7.2 Expresiones:

Ya han aparecido algunos ejemplos de expresiones del lenguaje C en las secciones precedentes. Una expresión es una combinación de variables y/o constantes, y operadores. La expresión es equivalente al resultado que proporciona al aplicar sus operadores a sus operandos. Por ejemplo, 1+5 es una expresión formada por dos operandos (1 y 5) y un operador (el +); esta expresión es equivalente al valor 6, lo cual quiere decir que allí donde esta expresión aparece en el programa, en el momento de la ejecución es evaluada y sustituida por su resultado.

Una expresión puede estar formada por otras expresiones más sencillas, y puede contener paréntesis de varios niveles agrupando distintos términos. En C existen distintos tipos de expresiones.

7.2.1 EXPRESIONES ARITMÉTICAS

Están formadas por variables y/o constantes, y distintos operadores aritméticos e incrementales (+, -, *, /, %, ++, --). Como se ha dicho, también se pueden emplear paréntesis de tantos niveles como se desee, y su interpretación sigue las normas aritméticas convencionales. Por ejemplo, la solución de la ecuación de segundo grado:

xb b aca=- + - 2 42

se escribe, en C en la forma:x=(-b+sqrt((b*b)-(4*a*c)))/(2*a);

donde, estrictamente hablando, sólo lo que está a la derecha del operador de asignación (=) es una expresión aritmética. El conjunto de la variable que está a la izquierda del signo (=), el operador de asignación, la expresión aritmética y el carácter (;) constituyen una sentencia. En la expresión anterior aparece la

llamada a la función de librería sqrt(), que tiene como valor de retorno la raíz cuadrada de su único argumento.

En las expresiones se pueden introducir espacios en blanco entre operandos y operadores; por ejemplo, la expresión anterior se puede escribir también de la forma:

x = (-b + sqrt((b * b) - (4 * a * c)))/(2 * a);

7.2.2 EXPRESIONES LÓGICAS

Los elementos con los que se forman estas expresiones son valores lógicos; verdaderos (true, o distintos de 0) y falsos (false, o iguales a 0), y los operadores lógicos ||, && y !. También se pueden emplear los operadores relacionales (<, >, <=, >=, ==, !=) para producir estos valores lógicos a partir de valores numéricos. Estas expresiones equivalen siempre a un valor 1 (true) o a un valor 0 (false). Por ejemplo:

a = ((b>c)&&(c>d))||((c==e)||(e==b));

donde de nuevo la expresión lógica es lo que está entre el operador de asignación (=) y el (;).

La variable a valdrá 1 si b es mayor que c y c mayor que d, ó si c es igual a e ó e es igual a b.

7.2.3 EXPRESIONES GENERALES

Una de las características más importantes (y en ocasiones más difíciles de manejar) del C es su flexibilidad para combinar expresiones y operadores de distintos tipos en una expresión que se podría llamar general, aunque es una expresión absolutamente ordinaria de C.Recuérdese que el resultado de una expresión lógica es siempre un valor numérico (un 1 ó un 0); esto permite que cualquier expresión lógica pueda aparecer como sub-expresión en una expresión aritmética. Recíprocamente, cualquier valor numérico puede ser considerado como un valor lógico: true si es distinto de 0 y false si es igual a 0. Esto permite introducir cualquier expresión aritmética como sub-expresión de una expresión lógica. Por ejemplo:(a - b*2.0) && (c != d)

A su vez, el operador de asignación (=), además de introducir un nuevo valor en la variable que figura a su izda, deja también este valor disponible para ser

Ing. Nestor Huaracha Velasquez

Page 42: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 42 utilizado en una expresión más general. Por ejemplo, supóngase el siguiente código que inicializa a 1 las tres variables a, b y c:

a = b = c = 1;que equivale a:a = (b = (c = 1));

En realidad, lo que se ha hecho ha sido lo siguiente. En primer lugar se ha asignado un valor unidad a c; el resultado de esta asignación es también un valor unidad, que está disponible para ser asignado a b; a su vez el resultado de esta segunda asignación vuelve a quedar disponible y se puede asignar a la variable a.

7.3 Reglas de precedencia y asociatividad

El resultado de una expresión depende del orden en que se ejecutan las operaciones. El siguiente ejemplo ilustra claramente la importancia del orden. Considérese la expresión:3 + 4 * 2Si se realiza primero la suma (3+4) y después el producto (7*2), el resultado es 14; si se realiza primero el producto (4*2) y luego la suma (3+8), el resultado es 11. Con objeto de que el resultado de cada expresión quede claro e inequívoco, es necesario definir las reglas que definen el orden con el que se ejecutan las expresiones de C. Existe dos tipos de reglas para determinar este orden de evaluación: las reglas de precedencia y de asociatividad. Además, el orden de evaluación puede modificarse por medio de paréntesis, pues siempre se realizan primero las operaciones encerradas en los paréntesis más interiores. Los distintos operadores de C se ordenan según su distinta precedencia o prioridad; para operadores de la misma precedencia o prioridad, en algunos el orden de ejecución es de izquierda a derecha, y otros de derecha a izquierda (se dice que se asocian de izda a dcha, o de dcha a izda). A este orden se le llama asociatividad.

En la Tabla 4.1 se muestra la precedencia –disminuyendo de arriba a abajo– y la asociatividad de los operadores de C. En dicha Tabla se incluyen también algunos operadores que no han sido vistos hasta ahora.

Tabla 4.1. Precedencia y asociatividad de los operadores de C.

Precedencia Asociatividad() [] -> . izda a dcha++ -- ! sizeof (tipo)+(unario) -(unario) *(indir.) &(dirección) dcha a izda* / % izda a dcha+ - izda a dcha< <= > >= izda a dcha

== != izda a dcha&& izda a dcha|| izda a dcha?: dcha a izda= += -= *= /= dcha a izda, (operador coma) izda a dcha

En la Tabla anterior se indica que el operador (*) tiene precedencia sobre el operador (+). Esto quiere decir que, en ausencia de paréntesis, el resultado de la expresión 3+4*2 es 11 y no 14. Los operadores binarios (+) y (-) tienen igual precedencia, y asociatividad de izda a dcha. Eso quiere decir que en la expresión, a-b+d*5.0+u/2.0 // (((a-b)+(d*5.0))+(u/2.0)) el orden de evaluación es el indicado por los paréntesis en la parte derecha de la línea (Las últimas operaciones en ejecutarse son las de los paréntesis más exteriores).

7.4 Sentencias:

Las expresiones de C son unidades o componentes elementales de unas entidades de rango superior que son las sentencias. Las sentencias son unidades completas, ejecutables en sí mismas. Ya se verá que muchos tipos de sentencias incorporan expresiones aritméticas, lógicas o generales como componentes de dichas sentencias.

7.4.1 SENTENCIAS SIMPLESUna sentencia simple es una expresión de algún tipo terminada con un carácter (;). Un caso típico son las declaraciones o las sentencias aritméticas. Por ejemplo:

float real;espacio = espacio_inicial + velocidad * tiempo;

7.4.2 SENTENCIA VACÍA Ó NULAEn algunas ocasiones es necesario introducir en el programa una sentencia que ocupe un lugar, pero que no realice ninguna tarea. A esta sentencia se le denomina sentencia vacía y

consta de un simple carácter (;). Por ejemplo:;

7.4.3 SENTENCIAS COMPUESTAS O BLOQUES

Muchas veces es necesario poner varias sentencias en un lugar del programa donde debería haber una sola. Esto se realiza por medio de sentencias

Ing. Nestor Huaracha Velasquez

Page 43: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 43 compuestas. Una sentencia compuesta es un conjunto de declaraciones y de sentencias agrupadas dentro de llaves {...}. También se conocen con el nombre de bloques. Una sentencia compuesta puede incluir otras sentencias, simples y compuestas. Un ejemplo de sentencia compuesta es el siguiente:

{int i = 1, j = 3, k;double masa;masa = 3.0;k = y + j;}

Las sentencias compuestas se utilizarán con mucha frecuencia en el Capítulo 5, al introducir las sentencias que permiten modificar el flujo de control del programa.

Ing. Nestor Huaracha Velasquez

Page 44: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 44

8. CONTROL DEL FLUJO DE EJECUCIÓN

En principio, las sentencias de un programa en C se ejecutan secuencialmente, esto es, cada una a continuación de la anterior empezando por la primera y acabando por la última. El lenguaje C dispone de varias sentencias para modificar este flujo secuencial de la ejecución.

Las más utilizadas se agrupan en dos familias: las bifurcaciones, que permiten elegir entre dos o más opciones según ciertas condiciones, y los bucles, que permiten ejecutar repetidamente un conjunto de instrucciones tantas veces como se desee, cambiando oactualizando ciertos valores.

8.1 Bifurcaciones

8.1.1 OPERADOR CONDICIONAL

El operador condicional es un operador con tres operandos (ternario) que tiene la siguienteforma general:

expresion_1 ? expresion_2 : expresion_3;Explicación: Se evalúa expresion_1. Si el resultado de dicha evaluación es true (#0), se ejecuta expresion_2; si el resultado es false (=0), se ejecuta expresion_3.

8.1.2 SENTENCIA IF

Esta sentencia de control permite ejecutar o no una sentencia simple o compuesta según se cumpla o no una determinada condición. Esta sentencia tiene la siguiente forma general: if (expresion)sentencia;

Explicación: Se evalúa expresion. Si el resultado es true (#0), se ejecuta sentencia; si el resultado es false (=0), se salta sentencia y se prosigue en la línea siguiente. Hay que recordar que sentencia puede ser una sentencia simple o compuesta (bloque { ... }).

8.1.3 SENTENCIA IF ... ELSE

Esta sentencia permite realizar una bifurcación, ejecutando una parte u otra del programa según se cumpla o no una cierta condición. La forma general es la siguiente:if (expresion)sentencia_1;elsesentencia_2;

Explicación: Se evalúa expresion. Si el resultado es true (#0), se ejecuta sentencia_1 y se prosigue en la línea siguiente a sentencia_2; si el resultado es false (=0), se salta sentencia_1, se ejecuta sentencia_2 y se prosigue en la línea siguiente. Hay que indicar aquí también que sentencia_1 y sentencia_2 pueden ser sentencias simples o compuestas (bloques { ... }).

8.1.4 SENTENCIA IF ... ELSE MÚLTIPLE

Esta sentencia permite realizar una ramificación múltiple, ejecutando una entre varias partes del programa según se cumpla una entre n condiciones. La forma general es la siguiente: if (expresion_1)sentencia_1;else if (expresion_2)sentencia_2;else if (expresion_3)sentencia_3;else if (...)...[elsesentencia_n;]

Explicación: Se evalúa expresion_1. Si el resultado es true, se ejecuta sentencia_1. Si el resultado es false, se salta sentencia_1 y se evalúa expresion_2. Si el resultado es true se ejecuta sentencia_2, mientras que si es false se evalúa expresion_3 y así sucesivamente. Si ninguna de las expresiones o condiciones es true se ejecuta expresion_n que es la opción por defecto (puede ser la sentencia vacía, y en ese caso puede eliminarse junto con la palabra else). Todas las sentencias pueden ser simples o compuestas.

8.1.5 SENTENCIA SWITCH

La sentencia que se va a describir a continuación desarrolla una función similar a la de la sentencia if ... else con múltiples ramificaciones, aunque como se

Ing. Nestor Huaracha Velasquez

Page 45: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 45 puede ver presenta también importantes diferencias. La forma general de la sentencia switch es la siguiente:switch (expresion) {case expresion_cte_1:sentencia_1;case expresion_cte_2:sentencia_2;...case expresion_cte_n:sentencia_n;[default:sentencia;]}

Explicación: Se evalúa expresion y se considera el resultado de dicha evaluación. Si dicho resultado coincide con el valor constante expresion_cte_1, se ejecuta sentencia_1 seguida de sentencia_2, sentencia_3, ..., sentencia. Si el resultado coincide con el valor constante expresion_cte_2, se ejecuta sentencia_2 seguida de sentencia_3, ..., sentencia. En general, se ejecutan todas aquellas sentencias que están a continuación de la expresion_cte cuyo valor coincide con el resultado calculado al principio. Si ninguna expresion_cte coincide se ejecuta la sentencia que está a continuación de default. Si se desea ejecutar únicamente una sentencia_i (y no todo un conjunto de ellas), basta poner una sentencia break a continuación (en algunos casos puede utilizarse la sentencia return o la función exit()). El efecto de la sentencia break es dar por terminada la ejecución de la sentencia switch. Existe también la posibilidad de ejecutar la misma sentencia_i para varios valores del resultado de expresion, poniendo varios case expresion_cte seguidos.

El siguiente ejemplo ilustra las posibilidades citadas:switch (expresion) {case expresion_cte_1:sentencia_1;break;case expresion_cte_2: case expresion_cte_3:sentencia_2;break;default:sentencia_3;}8.1.6 SENTENCIAS IF ANIDADAS

Una sentencia if puede incluir otros if dentro de la parte correspondiente a su sentencia, A estas sentencias se les llama sentencias anidadas (una dentro de otra), por ejemplo,if (a >= b)

if (b != 0.0)c = a/b;En ocasiones pueden aparecer dificultades de interpretación con sentencias if...else anidadas, como en el caso siguiente:if (a >= b)if (b != 0.0)c = a/b;elsec = 0.0;En principio se podría plantear la duda de a cuál de los dos if corresponde la parte else del programa. Los espacios en blanco –las indentaciones de las líneas– parecen indicar que la sentencia que sigue a else corresponde al segundo de los if, y así es en realidad, pues la regla es que el else pertenece al if más cercano. Sin embargo, no se olvide que el compilador de Cno considera los espacios en blanco (aunque sea muy conveniente introducirlos para hacer más claro y legible el programa), y que si se quisiera que el else perteneciera al primero de los if no bastaría cambiar los espacios en blanco, sino que habría que utilizar llaves, en la forma:if (a >= b) {if (b != 0.0)c = a/b;}elsec = 0.0;Recuérdese que todas las sentencias if e if...else, equivalen a una única sentencia por la posición que ocupan en el programa.

8.2 Bucles

Además de bifurcaciones, en el lenguaje C existen también varias sentencias que permiten repetir una serie de veces la ejecución de unas líneas de código. Esta repetición se realiza, bien un número determinado de veces, bien hasta que se cumpla una determinada condición de tipo lógico o aritmético. De modo genérico, a estas sentencias se les denomina bucles. Las tres construcciones del lenguaje C para realizar bucles son el while, el for y el do...while.

8.2.1 SENTENCIA WHILEEsta sentencia permite ejecutar repetidamente, mientras se cumpla una determinada condición, una sentencia o bloque de sentencias. La forma general es como sigue: while (expresion_de_control)sentencia;

Ing. Nestor Huaracha Velasquez

Page 46: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 46 Explicación: Se evalúa expresion_de_control y si el resultado es false se salta sentencia y se prosigue la ejecución. Si el resultado es true se ejecuta sentencia y se vuelve a evaluar expresion_de_control (evidentemente alguna variable de las que intervienen en expresion_de_control habrá tenido que ser modificada, pues si no el bucle continuaría indefinidamente). La ejecución de sentencia prosigue hasta que expresion_de_control se hace false, en cuyo caso la ejecución continúa en la línea siguiente a sentencia. En otras palabras, sentencia se ejecuta repetidamente mientras expresion_de_control sea true, y se deja de ejecutar cuando expresion_de_control se hace false. Obsérvese que en este caso el control para decidir si se sale o no del bucle está antes de sentencia, por lo que es posible que sentencia no se llegue a ejecutar ni una sola vez.

8.2.2 SENTENCIA FOR

For es quizás el tipo de bucle mas versátil y utilizado del lenguaje C. Su forma general es la siguiente:for (inicializacion; expresion_de_control; actualizacion)sentencia;Explicación: Posiblemente la forma más sencilla de explicar la sentencia for sea utilizando la construcción while que sería equivalente. Dicha construcción es la siguiente:inicializacion;while (expresion_de_control) {sentencia;actualizacion;}donde sentencia puede ser una única sentencia terminada con (;), otra sentencia de control ocupando varias líneas (if, while, for, ...), o una sentencia compuesta o un bloque encerrado entre llaves {...}. Antes de iniciarse el bucle se ejecuta inicializacion, que es una o más sentencias que asignan valores iniciales a ciertas variables o contadores. A continuación se evalúa expresion_de_control y si es false se prosigue en la sentencia siguiente a la construcción for; si es true se ejecutan sentencia y actualizacion, y se vuelve a evaluar expresion_de_control. El proceso prosigue hasta que expresion_de_control sea false. La parte de actualizacion sirve para actualizar variables o incrementar contadores. Un ejemplotípico puede ser el producto escalar de dos vectores a y b de dimensión n:for (pe =0.0, i=1; i<=n; i++){pe += a[i]*b[i];}Primeramente se inicializa la variable pe a cero y la variable i a 1; el ciclo se repetirá mientras que i sea menor o igual que n, y al final de cada ciclo el valor de i se incrementará en una unidad. En total, el bucle se repetirá n veces. La ventaja de la construcción for sobre la construcción while equivalente está en que en la cabecera de la construcción for se tiene toda

la información sobre como se inicializan, controlan y actualizan las variables del bucle.Obsérvese que la inicializacion consta de dos sentencias separadas por el operador (,).

8.2.3 SENTENCIA DO ... WHILE

Esta sentencia funciona de modo análogo a while, con la diferencia de que la evaluación de expresion_de_control se realiza al final del bucle, después de haber ejecutado al menos una vez las sentencias entre llaves; éstas se vuelven a ejecutar mientras expresion_de_control sea true. La forma general de esta sentencia es:dosentencia;while(expresion_de_control);donde sentencia puede ser una única sentencia o un bloque, y en la que debe observarse que hay que poner (;) a continuación del paréntesis que encierra a expresion_de_control, entre otros motivos para que esa línea se distinga de una sentencia while ordinaria.

8.3 Sentencias break, continue, goto

La instrucción break interrumpe la ejecución del bucle donde se ha incluido, haciendo al programa salir de él aunque la expresion_de_control correspondiente a ese bucle sea verdadera.La sentencia continue hace que el programa comience el siguiente ciclo del bucle donde se halla, aunque no haya llegado al final de las sentencia compuesta o bloque.La sentencia goto etiqueta hace saltar al programa a la sentencia donde se haya escrito la etiqueta correspondiente. Por ejemplo:sentencias ...

...if (condicion)goto otro_lugar; // salto al lugar indicado por la etiquetasentencia_1;sentencia_2;...otro_lugar: // esta es la sentencia a la que se saltasentencia_3;...Obsérvese que la etiqueta termina con el carácter (:). La sentencia goto no es una sentencia muy prestigiada en el mundo de los programadores de C, pues

Ing. Nestor Huaracha Velasquez

Page 47: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 47 disminuye la claridad y legibilidad del código. Fue introducida en el lenguaje por motivos de compatibilidad con antiguos hábitos de programación, y siempre puede ser sustituida por otras construccionesmás claras y estructuradas.

Ing. Nestor Huaracha Velasquez

Page 48: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 48 9. TIPOS DE DATOS DERIVADOS.Además de los tipos de datos fundamentales vistos en la Sección 2, en C existen algunos otros tipos de datos muy utilizados y que se pueden considerar derivados de los anteriores. En esta sección se van a presentar los punteros, las matrices y las estructuras.

9.1 Punteros9.1.1 CONCEPTO DE PUNTERO O APUNTADOREl valor de cada variable está almacenado en un lugar determinado de la memoria, caracterizado por una dirección (que se suele expresar con un número hexadecimal). El ordenador mantiene una tabla de direcciones (ver Tabla 6.1) que relaciona el nombre de cada variable con su dirección en la memoria. Gracias a los nombres de las variables (identificadores), de ordinario no hace falta que el programador se preocupe de la dirección de memoria donde están almacenados sus datos. Sin embargo, en ciertas ocasiones es más útil trabajar con las direcciones que con los propios nombres de las variables. El lenguaje C dispone del operador dirección (&) que permite determinar la dirección de una variable, y de un tipo especial de variables destinadas a contener direcciones de variables. Estas variables se llaman punteros o apuntadores (en inglés pointers).

Así pues, un puntero es una variable que puede contener la dirección de otra variable.Por supuesto, los punteros están almacenados en algún lugar de la memoria y tienen su propia dirección (más adelante se verá que existen punteros a punteros). Se dice que un puntero apunta a una variable si su contenido es la dirección de esa variable. Un puntero ocupa de ordinario 4 bytes de memoria, y se debe declarar o definir de acuerdo con el tipo del dato al que apunta. Por ejemplo, un puntero a una variable de tipo int se declara del siguiente modo:int *direc; lo cual quiere decir que a partir de este momento, la variable direc podrá contener la dirección de cualquier variable entera. La regla nemotécnica es que el valor al que apunta direc (es decir *direc, como luego se verá), es de tipo int. Los punteros a long, char, float y double sedefinen análogamente a los punteros a int.

9.1.2 OPERADORES DIRECCIÓN (&) E INDIRECCIÓN (*)

Como se ha dicho, el lenguaje C dispone del operador dirección (&) que permite hallar la dirección de la variable a la que se aplica. Un puntero es una verdadera variable, y por tanto puede cambiar de valor, es decir, puede cambiar la variable a la que apunta. Para acceder al valor depositado en la zona de memoria a la que apunta un puntero se debe utilizar el operador indirección (*). Por ejemplo, supóngase las siguientes declaraciones y sentencias,

int i, j, *p; // p es un puntero a int

p = &i; // p contiene la dirección de i*p = 10; // i toma el valor 10p = &j; // p contiene ahora la dirección de j*p = -2; // j toma el valor -2

Las constantes y las expresiones no tienen dirección, por lo que no se les puede aplicar el operador (&). Tampoco puede cambiarse la dirección de una variable. Los valores posiblespara un puntero son las direcciones posibles de memoria. Un puntero puede tener valor 0 (equivalente a la constante simbólica predefinida NULL). No se puede asignar una dirección absoluta directamente (habría que hacer un casting). Las siguientes sentencias son ilegales:p = &34; // las constantes no tienen direcciónp = &(i+1); // las expresiones no tienen dirección&i = p; // las direcciones no se pueden cambiarp = 17654; // habría que escribir p = (int *)17654;Para imprimir punteros con la función printf() se deben utilizar los formatos %u y %p,como se verá más adelante.No se permiten asignaciones directas (sin casting) entre punteros que apuntan a distintostipos de variables. Sin embargo, existe un tipo indefinido de punteros (void *, o punteros avoid), que puede asignarse y al que puede asignarse cualquier tipo de puntero. Por ejemplo:int *p;double *q;void *r;p = q; // ilegalp = (int *)q; // legalp = r = q; // legal

9.1.3 ARITMÉTICA DE PUNTEROS

Como ya se ha visto, los punteros son unas variables un poco especiales, ya que guardan información –no sólo de la dirección a la que apuntan–, sino también del tipo de variable almacenado en esa dirección. Esto implica que no van a estar permitidas las operaciones que no tienen sentido con direcciones de variables, como multiplicar o dividir, pero sí otras como sumar o restar. Además estas operaciones se realizan de un modo correcto, pero que no es elordinario. Así, la sentencia:

p = p+1;hace que p apunte a la dirección siguiente de la que apuntaba, teniendo en cuenta el tipo de

Ing. Nestor Huaracha Velasquez

Page 49: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 49 dato. Por ejemplo, si el valor apuntado por p es short int y ocupa 2 bytes, el sumar 1 a pimplica añadir 2 bytes a la dirección que contiene, mientras que si p apunta a un double,sumarle 1 implica añadirle 8 bytes.También tiene sentido la diferencia de punteros al mismo tipo de variable. El resultadoes la distancia entre las direcciones de las variables apuntadas por ellos, no en bytes sino endatos de ese mismo tipo. Las siguientes expresiones tienen pleno sentido en C:p = p + 1;p = p + i;p += 1;p++;Tabla 6.1. Tabla de direcciones.Variable Dirección de memoriaa 00FA:0000b 00FA:0002c 00FA:0004p1 00FA:0006p2 00FA:000Ap 00FA:000EResumen de lenguaje ANSI C Página 40El siguiente ejemplo ilustra la aritmética de punteros:void main(void) {int a, b, c;int *p1, *p2;void *p;p1 = &a; // Paso 1. La dirección de a es asignada a p1*p1 = 1; // Paso 2. p1 (a) es igual a 1. Equivale a a = 1;p2 = &b; // Paso 3. La dirección de b es asignada a p2*p2 = 2; // Paso 4. p2 (b) es igual a 2. Equivale a b = 2;p1 = p2; // Paso 5. El valor del p1 = p2*p1 = 0; // Paso 6. b = 0p2 = &c; // Paso 7. La dirección de c es asignada a p2*p2 = 3; // Paso 8. c = 3printf("%d %d %d\n", a, b, c); // Paso 9. ¿Qué se imprime?p = &p1; // Paso 10. p contiene la dirección de p1*p = p2; // Paso 11. p1= p2;*p1 = 1; // Paso 12. c = 1printf("%d %d %d\n", a, b, c); // Paso 13. ¿Qué se imprime?}Supóngase que en el momento de comenzar la ejecución, las direcciones de memoria delas distintas variables son las mostradas en la Tabla 6.1.La dirección de memoria está en hexadecimal, con el segmento y el offset separados por

dos puntos (:); basta prestar atención al segundo de estos números, esto es, al offset.La Tabla 6.2 muestra los valores de las variables en la ejecución del programa paso apaso. Se muestran en negrita y cursiva los cambios entre paso y paso. Es importante analizar yentender los cambios de valor.Tabla 6.2. Ejecución paso a paso de un ejemplo con punteros.Paso a00FA:0000b00FA:0002c00FA:0004p100FA:0006p200FA:000Ap00FA:000E1 00FA:00002 1 00FA:00003 1 00FA:0000 000FA:00024 1 2 00FA:0000 000FA:00025 1 2 000FA:0002 000FA:00026 1 0 000FA:0002 000FA:00027 1 0 000FA:0002 000FA:00048 1 0 3 000FA:0002 000FA:00049 1 0 3 000FA:0002 000FA:000410 1 0 3 000FA:0002 000FA:0004 000FA:000611 1 0 3 000FA:0004 000FA:0004 000FA:000612 1 0 1 000FA:0004 000FA:0004 000FA:000613 1 0 1 000FA:0004 000FA:0004 000FA:0006

9.2 Vectores, matrices y cadenas de caracteresUn array (también conocido como arreglo, vector o matriz) es un modo de manejar una grancantidad de datos del mismo tipo bajo un mismo nombre o identificador. Por ejemplo,mediante la sentencia:double a[10];

Ing. Nestor Huaracha Velasquez

Page 50: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 50 se reserva espacio para 10 variables de tipo double. Las 10 variables se llaman a y se accede auna u otra por medio de un subíndice, que es una expresión entera escrita a continuación delnombre entre corchetes [...]. La forma general de la declaración de un vector es la siguiente:tipo nombre[numero_elementos];Los elementos se numeran desde 0 hasta (numero_elementos-1). El tamaño de un vectorpuede definirse con cualquier expresión constante entera. Para definir tamaños sonparticularmente útiles las constantes simbólicas. Como ya se ha dicho, para acceder a unelemento del vector basta incluir en una expresión su nombre seguido del subíndice entrecorchetes. En C no se puede operar con todo un vector o toda una matriz como una únicaentidad, sino que hay que tratar sus elementos uno a uno por medio de bucles for o while. Losvectores (mejor dicho, los elementos de un vector) se utilizan en las expresiones de C comocualquier otra variable. Ejemplos de uso de vectores son los siguientes:a[5] = 0.8;a[9] = 30. * a[5];a[0] = 3. * a[9] - a[5]/a[9];a[3] = (a[0] + a[9])/a[3];Una cadena de caracteres no es sino un vector de tipo char, con alguna particularidadque conviene resaltar. Las cadenas suelen contener texto (nombres, frases, etc.), y éste sealmacena en la parte inicial de la cadena (a partir de la posición cero del vector). Para separarla parte que contiene texto de la parte no utilizada, se utiliza un carácter fin de texto que es elcarácter nulo ('\0') según el código ASCII. Este carácter se introduce automáticamente al leer oinicializar las cadenas de caracteres, como en el siguiente ejemplo:char ciudad[20] = "San Sebastián";donde a los 13 caracteres del nombre de esta ciudad se añade un decimocuarto: el '\0'. El restodel espacio reservado –hasta la posición ciudad[19]– no se utiliza. De modo análogo, unacadena constante tal como "mar" ocupa 4 bytes (para las 3 letras y el '\0').Las matrices se declaran de forma análoga, con corchetes independientes para cadasubíndice. La forma general de la declaración es:tipo nombre[numero_filas][numero_columnas];

donde tanto las filas como las columnas se numeran también a partir de 0. La forma deacceder a los elementos de la matriz es utilizando su nombre, seguido de las expresionesenteras correspondientes a los dos subíndices, entre corchetes.En C tanto los vectores como las matrices admiten los tipos de las variables escalares(char, int, long, float, double, etc.), y los modos de almacenamiento auto, extern y static, conlas mismas características que las variables normales (escalares). No se admite el modoregister. Los arrays static y extern se inicializan a cero por defecto. Los arrays auto pueden noinicializarse: depende del compilador concreto que se esté utilizando.Las matrices en C se almacenan por filas, en posiciones consecutivas de memoria. Encierta forma, una matriz se puede ver como un vector de vectores-fila. Si una matriz tiene Nfilas (numeradas de 0 a N-1) y M columnas (numeradas de 0 a la M-1), el elemento (i, j)ocupa el lugar:posición_elemento(0, 0) + i * M + jA esta fórmula se le llama fórmula de direccionamiento de la matriz.En C pueden definirse arrays con tantos subíndices como se desee. Por ejemplo, lasentencia,double a[3][5][7];declara una hipermatriz con tres subíndices, que podría verse como un conjunto de 3 matricesde dimensión (5x7). En la fórmula de direccionamiento correspondiente, el último subíndicees el que varía más rápidamente.Como se verá más adelante, los arrays presentan una especial relación con los punteros.Puesto que los elementos de un vector y una matriz están almacenados consecutivamente en lamemoria, la aritmética de punteros descrita previamente presenta muchas ventajas. Porejemplo, supóngase el código siguiente:int vect[10], mat[3][5], *p;p = &vect[0];printf("%d\n", *(p+2)); // se imprimirá vect[2]p = &mat[0][0];printf("%d\n", *(p+2)); // se imprimirá mat[0][2]printf("%d\n", *(p+4)); // se imprimirá mat[0][4]printf("%d\n", *(p+5)); // se imprimirá mat[1][0]printf("%d\n", *(p+12)); // se imprimirá mat[2][2]

Ing. Nestor Huaracha Velasquez

Page 51: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 51

9.2.1 RELACIÓN ENTRE VECTORES Y PUNTEROSExiste una relación muy estrecha entre los vectores y los punteros. De hecho, el nombre de unvector es un puntero (un puntero constante, en el sentido de que no puede apuntar a otravariable distinta de aquélla a la que apunta) a la dirección de memoria que contiene el primerelemento del vector. Supónganse las siguientes declaraciones y sentencias:double vect[10]; // vect es un puntero a vect[0]double *p;...p = &vect[0]; // p = vect;...El identificador vect, es decir el nombre del vector, es un puntero al primer elementodel vector vect[ ]. Esto es lo mismo que decir que el valor de vect es &vect[0]. Existen máspuntos de coincidencia entre los vectores y los punteros:– Puesto que el nombre de un vector es un puntero, obedecerá las leyes de la aritmética depunteros. Por tanto, si vect apunta a vect[0], (vect+1) apuntará a vect[1], y (vect+i)apuntará a vect[i].– Recíprocamente (y esto resulta quizás más sorprendente), a los punteros se les puedenponer subíndices, igual que a los vectores. Así pues, si p apunta a vect[0] se puedeescribir:p[3]=p[2]*2.0; // equivalente a vect[3]=vect[2]*2.0;– Si se supone que p=vect, la relación entre punteros y vectores puede resumirse como seindica en las líneas siguientes:*p equivale a vect[0], a *vect y a p[0]*(p+1) equivale a vect[1], a *(vect+1) y a p[1]

*(p+2) equivale a vect[2], a *(vect+2) y a p[2]Como ejemplo de la relación entre vectores y punteros, se van a ver varias formasposibles para sumar los N elementos de un vector a[ ]. Supóngase la siguiente declaración ylas siguientes sentencias:int a[N], suma, i, *p;for(i=0, suma=0; i<N; ++i) // forma 1suma += a[i];for(i=0, suma=0; i<N; ++i) // forma 2suma += *(a+i);

for(p=a, i=0, suma=0; i<N; ++i) // forma 3suma += p[i];for(p=a, suma=0; p<&a[N]; ++p) // forma 4suma += *p;

9.2.2 RELACIÓN ENTRE MATRICES Y PUNTEROS

En el caso de las matrices la relación con los punteros es un poco más complicada. Supóngaseuna declaración como la siguienteint mat[5][3], **p, *q;El nombre de la matriz (mat) es un puntero al primer elemento de un vector de punterosmat[ ] (por tanto, existe un vector de punteros que tiene también el mismo nombre que lamatriz), cuyos elementos contienen las direcciones del primer elemento de cada fila de lamatriz. El nombre mat es pues un puntero a puntero. El vector de punteros mat[ ] se creaautomáticamente al crearse la matriz. Así pues, mat es igual a &mat[0]; y mat[0] es&mat[0][0]. Análogamente, mat[1] es &mat[1][0], mat[2] es &mat[2][0], etc. La direcciónbase sobre la que se direccionan todos los elementos de la matriz no es mat, sino &mat[0][0].Recuérdese también que, por la relación entre vectores y punteros, (mat+i) apunta a mat[i].Recuérdese que la fórmula de direccionamiento de una matriz de N filas y M columnasestablece que la dirección del elemento (i, j) viene dada por:dirección (i, j) = dirección (0, 0) + i*M + jTeniendo esto en cuenta y haciendo **p = mat; se tendrán las siguientes formas deacceder a los elementos de la matriz:*p es el valor de mat[0] **p es mat[0][0]*(p+1) es el valor de mat[1] **(p+1) es mat[1][0]*(*(p+1)+1) es mat[1][1]Por otra parte, si la matriz tiene M columnas y si se hace q = &mat[0][0] (direcciónbase de la matriz. Recuérdese que esto es diferente del caso anterior p = mat), el elementomat[i][j] puede ser accedido de varias formas. Basta recordar que dicho elemento tiene pordelante i filas completas, y j elementos de su fila:*(q + M*i + j) // fórmula de direccionamiento*(mat[i] + j) // primer elemento fila i desplazado j elementos(*(mat + i))[j] // [j] equivale a sumar j a un puntero

Ing. Nestor Huaracha Velasquez

Page 52: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 52 *((*(mat + i)) + j)Todas estas relaciones tienen una gran importancia, pues implican una correctacomprensión de los punteros y de las matrices. De todas formas, hay que indicar que lasmatrices no son del todo idénticas a los vectores de punteros: Si se define una matrizexplícitamente por medio de vectores de punteros, las filas pueden tener diferente número deResumen de lenguaje ANSI C Página 44elementos, y no queda garantizado que estén contiguas en la memoria (aunque se puede hacerque sí lo sean). No sería pues posible en este caso utilizar la fórmula de direccionamiento y elacceder por columnas a los elementos de la matriz. La Figura 6.1 resume gráficamente larelación entre matrices y vectores de punteros.····························matmat[]mat[][]dirección del primer elemento de la 1ª filadirección del primerelemento de la 2ª filadirección del primer elemento del vector de direcciones mat[0]Figura 6.1. Relación entre matrices y punteros.

9.2.3 INICIALIZACIÓN DE VECTORES Y MATRICES

La inicialización de un array se puede hacer de varias maneras:– Declarando el array como tal e inicializándolo luego mediante lectura o asignación pormedio de un bucle for:double vect[N];...for(i = 0; i < N; i++)scanf(" %lf", &vect[i]);...– Inicializándolo en la misma declaración, en la forma:double v[6] = {1., 2., 3., 3., 2., 1.};float d[] = {1.2, 3.4, 5.1}; // d[3] está implícitoint f[100] = {0}; // todo se inicializa a 0int h[10] = {1, 2, 3}; // restantes elementos a 0

int mat[3][2] = {{1, 2}, {3, 4}, {5, 6}};donde es necesario poner un punto decimal tras cada cifra, para que ésta sea reconocida comoun valor de tipo float o double.Recuérdese que, al igual que las variables escalares correspondientes, los arrays conmodo de almacenamiento external y static se inicializan a cero automáticamente en elmomento de la declaración. Sin embargo, esto no está garantizado en los arrays auto, y el quese haga o no depende del compilador.

Ing. Nestor Huaracha Velasquez

Page 53: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 53

9.3 EstructurasUna estructura es una forma de agrupar un conjunto de datos de distinto tipo bajo un mismonombre o identificador. Por ejemplo, supóngase que se desea diseñar una estructura queguarde los datos correspondientes a un alumno de primero. Esta estructura, a la que se llamaráalumno, deberá guardar el nombre, la dirección, el número de matrícula, el teléfono, y lasnotas en las 10 asignaturas. Cada uno de estos datos se denomina miembro de la estructura. Elmodelo o patrón de esta estructura puede crearse del siguiente modo:struct alumno {char nombre[31];char direccion[21];unsigned long no_matricula;unsigned long telefono;float notas[10];};El código anterior crea el tipo de dato alumno, pero aún no hay ninguna variabledeclarada con este nuevo tipo. Obsérvese la necesidad de incluir un carácter (;) después decerrar las llaves. Para declarar dos variables de tipo alumno en C se debe utilizar la sentenciaincluyendo las palabras struct y alumno (en C++ basta utilizar la palabra alumno):struct alumno alumno1, alumno2; // esto es Calumno alumno1, alumno2; // esto es C++donde tanto alumno1 como alumno2 son una estructura, que podrá almacenar un nombre dehasta 30 caracteres, una dirección de hasta 20 caracteres, el número de matrícula, el númerode teléfono y las notas de las 10 asignaturas. También podrían haberse definido alumno1 yalumno2 al mismo tiempo que se definía la estructura de tipo alumno. Para ello bastaríahaber hecho:struct alumno {char nombre[31];char direccion[21];unsigned long no_matricula;unsigned long telefono;float notas[10];} alumno1, alumno2;

Para acceder a los miembros de una estructura se utiliza el operador punto (.),precedido por el nombre de la estructura y seguido del nombre del miembro. Por ejemplo,para dar valor al telefono del alumno alumno1 el valor 903456, se escribirá:alumno1.telefono = 903456;y para guardar la dirección de este mismo alumno, se escribirá:alumno1.direccion = "C/ Penny Lane 1,2-A";El tipo de estructura creado se puede utilizar para definir más variables o estructuras detipo alumno, así como vectores de estructuras de este tipo. Por ejemplo:struct alumno nuevo_alumno, clase[300];En este caso, nuevo_alumno es una estructura de tipo alumno, y clase[300] es unvector de estructuras con espacio para almacenar los datos de 300 alumnos. El número dematrícula del alumno 264 podrá ser accedido como clase[264].no_matricula.Los miembros de las estructuras pueden ser variables de cualquier tipo, incluyendovectores y matrices, e incluso otras estructuras previamente definidas. Las estructuras sediferencian de los arrays (vectores y matrices) en varios aspectos. Por una parte, los arrayscontienen información múltiple pero homogénea, mientras que los miembros de lasResumen de lenguaje ANSI C Página 46estructuras pueden ser de naturaleza muy diferente. Además, las estructuras permiten ciertasoperaciones globales que no se pueden realizar con arrays. Por ejemplo, la sentenciasiguiente:clase[298] = nuevo_alumno;hace que se copien todos los miembros de la estructura nuevo_alumno en los miembroscorrespondientes de la estructura clase[298]. Estas operaciones globales no son posibles conarrays.Se pueden definir también punteros a estructuras:struct alumno *pt;pt = &nuevo_alumno;Ahora, el puntero pt apunta a la estructura nuevo_alumno y esto permite una nueva formade acceder a sus miembros utilizando el operador flecha (->), constituido por los signos (-) y(>). Así, para acceder al teléfono del alumno nuevo_alumno, se puede utilizar cualquiera de lassiguientes sentencias:

Ing. Nestor Huaracha Velasquez

Page 54: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 54 pt->telefono;(*pt).telefono;donde el paréntesis es necesario por la mayor prioridad del operador (.) respecto a (*).Las estructuras admiten los mismos modos auto, extern y static que los arrays y lasvariables escalares. Las reglas de inicialización a cero por defecto de los modos extern y staticse mantienen. Por lo demás, una estructura puede inicializarse en el momento de ladeclaración de modo análogo a como se inicializan los vectores y matrices, por medio devalores encerrados entre llaves {}. Por ejemplo, una forma de declarar e inicializar a la vez laestructura alumno_nuevo podría ser la siguiente:struct alumno {char nombre[31];char direccion[21];unsigned long no_matricula;unsigned long telefono;float notas[10];} alumno_nuevo = {"Mike Smith", "San Martín 87, 2º A", 62419, 421794};donde, como no se proporciona valor para las notas, éstas se inicializan a cero.Las estructuras constituyen uno de los aspectos más potentes del lenguaje C. En estasección se ha tratado sólo de hacer una breve presentación de sus posibilidades. C++generaliza este concepto incluyendo funciones miembro además de variables miembro,llamándolo clase, y convirtiéndolo en la base de la programación orientada a objetos.

Ing. Nestor Huaracha Velasquez

Page 55: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 55 10. FUNCIONESComo se explicó en la Sección 1.3, una función es una parte de código independiente delprograma principal y de otras funciones, que puede ser llamada enviándole unos datos (o sinenviarle nada), para que realice una determinada tarea y/o proporcione unos resultados. Lasfunciones son una parte muy importante del lenguaje C. En los apartados siguientes sedescriben los aspectos más importantes de las funciones.

10.1 Utilidad de las funciones

Parte esencial del correcto diseño de un programa de ordenador es su modularidad, esto es sudivisión en partes más pequeñas de finalidad muy concreta. En C estas partes de códigoreciben el nombre de funciones. Las funciones facilitan el desarrollo y mantenimiento de losprogramas, evitan errores, y ahorran memoria y trabajo innecesario. Una misma función puedeser utilizada por diferentes programas, y por tanto no es necesario reescribirla. Además, unafunción es una parte de código independiente del programa principal y de otras funciones,manteniendo una gran independencia entre las variables respectivas, y evitando errores y otros efectos colaterales de las modificaciones que se introduzcan.Mediante el uso de funciones se consigue un código limpio, claro y elegante. Laadecuada división de un programa en funciones constituye un aspecto fundamental en el desarrollo de programas de cualquier tipo. Las funciones, ya compiladas, pueden guardarse en librerías. Las librerías son conjuntos de funciones compiladas, normalmente con una finalidad análoga o relacionada, que se guardan bajo un determinado nombre listas para ser utilizadas por cualquier usuario.

10.2 Definición de una función

La definición de una función consiste en la definición del código necesario para que ésta realice las tareas para las que ha sido prevista. La definición de una función se debe realizar en alguno de los ficheros que forman parte del programa. La forma general de la definición de una función es la siguiente:

tipo_valor_de_retorno nombre_funcion(lista de argumentos con tipos){

declaración de variables y/o de otras funcionescodigo ejecutablereturn (expresión); // optativo}La primera línea recibe el nombre de encabezamiento (header) y el resto de ladefinición –encerrado entre llaves– es el cuerpo (body) de la función. Cada función puededisponer de sus propias variables, declaradas al comienzo de su código. Estas variables, pordefecto, son de tipo auto, es decir, sólo son visibles dentro del bloque en el que han sidodefinidas, se crean cada vez que se ejecuta la función y permanecen ocultas para el resto delprograma. Si estas variables de definen como static, conservan su valor entre distintasllamadas a la función. También pueden hacerse visibles a la función variables globalesdefinidas en otro fichero (o en el mismo fichero, si la definición está por debajo de donde seutilizan), declarándolas con la palabra clave extern.El código ejecutable es el conjunto de instrucciones que deben ejecutarse cada vez quela función es llamada. La lista de argumentos con tipos, también llamados argumentosformales, es una lista de declaraciones de variables, precedidas por su tipo correspondiente yResumen de lenguaje ANSI C Página 48separadas por comas (,). Los argumentos formales son la forma más natural y directa para quela función reciba valores desde el programa que la llama, correspondiéndose en número y tipocon otra lista de argumentos -los argumentos actuales- en el programa que realiza la llamadaa la función. Los argumentos formales son declarados en el encabezamiento de la función,pero no pueden ser inicializados en él.Cuando una función es ejecutada, puede devolver al programa que la ha llamado unvalor (el valor de retorno), cuyo tipo debe ser especificado en el encabezamiento de la función(si no se especifica, se supone por defecto el tipo int). Si no se desea que la función devuelvaningún valor, el tipo del valor de retorno deberá ser void.La sentencia return permite devolver el control al programa que llama. Puede haber

Ing. Nestor Huaracha Velasquez

Page 56: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 56 varias sentencias return en una misma función. Si no hay ningún return, el control sedevuelve cuando se llega al final del cuerpo de la función. Le palabra clave return puede irseguida de una expresión, en cuyo caso ésta es evaluada y el valor resultante devuelto alprograma que llama como valor de retorno (si hace falta, con una conversión previa al tipodeclarado en el encabezamiento). Los paréntesis que engloban a la expresión que sigue areturn son optativos.El valor de retorno es un valor único: no puede ser un vector o una matriz, aunque sí unpuntero a un vector o a una matriz. Sin embargo, el valor de retorno sí puede ser unaestructura, que a su vez puede contener vectores y matrices como elementos miembros.Como ejemplo supóngase que se va a calcular a menudo el valor absoluto de variablesde tipo double. Una solución es definir una función que reciba como argumento el valor de lavariable y devuelva ese valor absoluto como valor de retorno. La definición de esta funciónpodría ser como sigue:double valor_abs(double x){if (x < 0.0)return -x;elsereturn x;}

10.3 Declaración y llamada de una función

De la misma manera que en C es necesario declarar todas las variables, también toda función debe ser declarada antes de ser utilizada en la función o programa que realiza la llamada. De todas formas, ahora se verá que aquí hay una mayor flexibilidad que en el caso de las variables. En C la declaración de una función se puede hacer de tres maneras:

a) Mediante una llamada a la función. En efecto, cuando una función es llamada sin quepreviamente haya sido declarada o definida, esa llamada sirve como declaraciónsuponiendo int como tipo del valor de retorno, y el tipo de los argumentos actuales

como tipo de los argumentos formales. Esta práctica es muy peligrosa (es fuente denumerosos errores) y debe ser evitada.b) Mediante una definición previa de la función. Esta práctica es segura si la definiciónprecede a la llamada, pero tiene el inconveniente de que si la definición se cambia delugar, la propia llamada pasa a ser declaración como en el caso a).

c) Mediante una declaración explícita, previa a la llamada. Esta es la práctica más seguray la que hay que tratar de seguir siempre. La declaración de la función se hace medianteel prototipo de la función, bien fuera de cualquier bloque, bien en la parte dedeclaraciones de un bloque.C++ es un poco más restrictivo que C, y obliga a declarar explícitamente una funciónantes de llamarla.La forma general del prototipo de una función es la siguiente:tipo_valor_de_retorno nombre_funcion(lista de tipos de argumentos);Esta forma general coincide sustancialmente con la primera línea de la definición -elencabezamiento-, con dos pequeñas diferencias: en vez de la lista de argumentos formales oparámetros, en el prototipo basta incluir los tipos de dichos argumentos. Se pueden incluirtambién identificadores a continuación de los tipos, pero son ignorados por el compilador.Además, una segunda diferencia es que el prototipo termina con un carácter (;). Cuando nohay argumentos formales, se pone entre los paréntesis la palabra void, y se pone también voidprecediendo al nombre de la función cuando no hay valor de retorno.Los prototipos permiten que el compilador realice correctamente la conversión del tipodel valor de retorno, y de los argumentos actuales a los tipos de los argumentos formales. Ladeclaración de las funciones mediante los prototipos suele hacerse al comienzo del fichero,después de los #define e #include. En muchos casos –particularmente en programas grandes,con muchos ficheros y muchas funciones–, se puede crear un fichero (con la extensión .h) contodos los prototipos de las funciones utilizadas en un programa, e incluirlo con un #include entodos los ficheros en que se utilicen dichas funciones.

Ing. Nestor Huaracha Velasquez

Page 57: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 57 La llamada a una función se hace incluyendo su nombre en una expresión o sentenciadel programa principal o de otra función. Este nombre debe ir seguido de una lista deargumentos separados por comas y encerrados entre paréntesis. A los argumentos incluidos enla llamada se les llama argumentos actuales, y pueden ser no sólo variables y/o constantes,sino también expresiones. Cuando el programa que llama encuentra el nombre de la función,evalúa los argumentos actuales contenidos en la llamada, los convierte si es necesario al tipode los argumentos formales, y pasa copias de dichos valores a la función junto con el controlde la ejecución.El número de argumentos actuales en la llamada a una función debe coincidir con elnúmero de argumentos formales en la definición y en la declaración. Existe la posibilidad dedefinir funciones con un número variable o indeterminado de argumentos. Este número seconcreta luego en el momento de llamarlas. Las funciones printf() y scanf(), que se verán enla sección siguiente, son ejemplos de funciones con número variable de argumentos.Cuando se llama a una función, después de realizar la conversión de los argumentosactuales, se ejecuta el código correspondiente a la función hasta que se llega a una sentenciareturn o al final del cuerpo de la función, y entonces se devuelve el control al programa querealizó la llamada, junto con el valor de retorno si es que existe (convertido previamente altipo especificado en el prototipo, si es necesario). Recuérdese que el valor de retorno puedeser un valor numérico, una dirección (un puntero), o una estructura, pero no una matriz o unvector.La llamada a una función puede hacerse de muchas formas, dependiendo de qué clase detarea realice la función. Si su papel fundamental es calcular un valor de retorno a partir deuno o más argumentos, lo más normal es que sea llamada incluyendo su nombre seguido delos argumentos actuales en una expresión aritmética o de otro tipo. En este caso, la llamada aResumen de lenguaje ANSI C Página 50

la función hace el papel de un operando más de la expresión. Obsérvese cómo se llama a lafunción seno en el ejemplo siguiente:a = d * sin(alpha) / 2.0;En otros casos, no existirá valor de retorno y la llamada a la función se hará incluyendoen el programa una sentencia que contenga solamente el nombre de la función, siempreseguido por los argumentos actuales entre paréntesis y terminando con un carácter (;). Porejemplo, la siguiente sentencia llama a una función que multiplica dos matrices (nxn) A y B, yalmacena el resultado en otra matriz C. Obsérvese que en este caso no hay valor de retorno(un poco más adelante se trata con detalle la forma de pasar vectores y matrices comoargumentos de una función):prod_mat(n, A, B, C);Hay también casos intermedios entre los dos anteriores, como sucede por ejemplo conlas funciones de entrada/salida que se verán en la próxima sección. Dichas funciones tienenvalor de retorno, relacionado de ordinario con el número de datos leídos o escritos sin errores,pero es muy frecuente que no se haga uso de dicho valor y que se llamen al modo de lasfunciones que no lo tienen.La declaración y la llamada de la función valor_abs() antes definida, se podría realizarde la forma siguiente. Supóngase que se crea un fichero prueba.c con el siguiente contenido:// fichero prueba.c#include <stdio.h>double valor_abs(double); // declaraciónvoid main (void){double z, y;y = -30.8;z = valor_abs(y) + y*y; // llamada en una expresion}La función valor_abs() recibe un valor de tipo double. El valor de retorno de dichafunción (el valor absoluto de y), es introducido en la expresión aritmética que calcula z.La declaración (double valor_abs(double)) no es estrictamente necesaria cuando la

Ing. Nestor Huaracha Velasquez

Page 58: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 58 definición de la función está en el mismo archivo buscar.c que main(), y dicha definición estáantes de la llamada.

10.4 Paso de argumentos por valor y por referencia

En la sección anterior se ha comentado que en la llamada a una función los argumentosactuales son evaluados y se pasan copias de estos valores a las variables que constituyen losargumentos formales de la función. Aunque los argumentos actuales sean variables y noexpresiones, y haya una correspondencia biunívoca entre ambos tipos de argumentos, loscambios que la función realiza en los argumentos formales no se trasmiten a las variables delprograma que la ha llamado, precisamente porque lo que la función ha recibido son copias. Elmodificar una copia no repercute en el original. A este mecanismo de paso de argumentos auna función se le llama paso por valor. Considérese la siguiente función para permutar elvalor de sus dos argumentos x e y:7. FUNCIONES Página 51void permutar(double x, double y) // funcion incorrecta{double temp;temp = x;x = y;y = temp;}La función anterior podría ser llamada y comprobada de la siguiente forma:#include <stdio.h>void main(void){double a=1.0, b=2.0;void permutar(double, double);printf("a = %lf, b = %lf\n", a, b);permutar(a, b);printf("a = %lf, b = %lf\n", a, b);}Compilando y ejecutando este programa se ve que a y b siguen teniendo los mismosvalores antes y después de la llamada a permutar(), a pesar de que en el interior de la función

los valores sí se han permutado (es fácil de comprobar introduciendo en el código de lafunción los printf() correspondientes). La razón está en que se han permutado los valores delas copias de a y b, pero no los valores de las propias variables. Las variables podrían serpermutadas si se recibieran sus direcciones (en realidad, copias de dichas direcciones). Lasdirecciones deben recibirse en variables puntero, por lo que los argumentos formales de lafunción deberán ser punteros. Una versión correcta de la función permutar() que pasadirecciones en vez de valores sería como sigue:void permutar(double *x, double *y){double temp;temp = *x;*x = *y;*y = temp;}que puede ser llamada y comprobada de la siguiente forma:#include <stdio.h>void main(void){double a=1.0, b=2.0;void permutar(double *, double *);printf("a = %lf, b = %lf\n", a, b);permutar(&a, &b);printf("a = %lf, b = %lf\n", a, b);}Al mecanismo de paso de argumentos mediante direcciones en lugar de valores se lellama paso por referencia, y deberá utilizarse siempre que la función deba devolverargumentos modificados. Un caso de particular interés es el paso de arrays (vectores, matricesy cadenas de caracteres). Este punto se tratará con más detalle un poco más adelante. Bastedecir ahora que como los nombres de los arrays son punteros (es decir, direcciones), dichosdatos se pasan por referencia, lo cual tiene la ventaja adicional de que no se gasta memoria ytiempo para pasar a las funciones copias de cantidades grandes de información.Resumen de lenguaje ANSI C Página 52Un caso distinto es el de las estructuras, y conviene tener cuidado. Por defecto las

Ing. Nestor Huaracha Velasquez

Page 59: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 59 estructuras se pasan por valor, y pueden representar también grandes cantidades de datos(pueden contener arrays como miembros) de los que se realizan y transmiten copias, con laconsiguiente pérdida de eficiencia. Por esta razón, las estructuras se suelen pasar de modoexplícito por referencia, por medio de punteros a las mismas.

10.5 La función main() con argumentos

Cuando se ejecuta un programa desde MS-DOS tecleando su nombre, existe la posibilidad depasarle algunos datos, tecleándolos a continuación en la misma línea. Por ejemplo, se le puedepasar algún valor numérico o los nombres de algunos ficheros en los que tiene que leer oescribir información. Esto se consigue por medio de argumentos que se pasan a la funciónmain(), como se hace con otras funciones.Así pues, a la función main() se le pueden pasar argumentos y también puede tenervalor de retorno. El primero de los argumentos de main() se suele llamar argc, y es unavariable int que contiene el número de palabras que se teclean a continuación del nombre delprograma cuando éste se ejecuta. El segundo argumento se llama argv, y es un vector depunteros a carácter que contiene las direcciones de la primera letra o carácter de dichaspalabras. A continuación se presenta un ejemplo:int main(int argc, char *argv[]){int cont;for (cont=0; cont<argc; cont++)printf("El argumento %d es: %s\n", cont, argv[cont]);printf("\n");return 0;}

10.6 Funciones para cadenas de caracteres

En C, existen varias funciones útiles para el manejo de cadenas de caracteres. Las másutilizadas son: strlen(), strcat(), strcmp() y strcpy(). Sus prototipos o declaraciones están en

el fichero string.h, y son los siguientes (se incluye a continuación una explicación de cómo seutiliza la función correspondiente).7.6.1 FUNCIÓN STRLEN()El prototipo de esta función es como sigue:unsigned strlen(const char *s);Explicación: Su nombre proviene de string length, y su misión es contar el número decaracteres de una cadena, sin incluir el '\0' final. El paso del argumento se realiza porreferencia, pues como argumento se emplea un puntero a la cadena (tal que el valor al queapunta es constante para la función; es decir, ésta no lo puede modificar), y devuelve unentero sin signo que es el número de caracteres de la cadena.La palabra const impide que dentro de la función lac cadena de caracteres que se pasacomo argumento sea modificada.

10.6.2 FUNCIÓN STRCAT()

El prototipo de esta función es como sigue:char *strcat(char *s1, const char *s2);Explicación: Su nombre proviene de string concatenation, y se emplea para unir dos cadenasde caracteres poniendo s2 a continuación de s1. El valor de retorno es un puntero a s1. Losargumentos son los punteros a las dos cadenas que se desea unir. La función almacena lacadena completa en la primera de las cadenas. ¡PRECAUCIÓN! Esta función no prevé si tienesitio suficiente para almacenar las dos cadenas juntas en el espacio reservado para la primera.Esto es responsabilidad del programador.

10.6.3 FUNCIONES STRCMP() Y STRCOMP()

El prototipo de la función strcmp() es como sigue:int strcmp(const char *s1, const char *s2)Explicación: Su nombre proviene de string comparison. Sirve para comparar dos cadenas decaracteres. Como argumentos utiliza punteros a las cadenas que se van a comparar. La funcióndevuelve cero si las cadenas son iguales, un valor menor que cero si s1 es menor –en orden

Ing. Nestor Huaracha Velasquez

Page 60: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 60 alfabético– que s2, y un valor mayor que cero si s1 es mayor que s2. La función strcomp() escompletamente análoga, con la diferencia de que no hace distinción entre letras mayúsculas yminúsculas).

10.6.4 FUNCIÓN STRCPY()

El prototipo de la función strcpy() es como sigue:char *strcpy(char *s1, const char *s2)Explicación: Su nombre proviene de string copy y se utiliza para copiar cadenas. Utilizacomo argumentos dos punteros a carácter: el primero es un puntero a la cadena copia, y elsegundo es un puntero a la cadena original. El valor de retorno es un puntero a la cadena copias1.Es muy importante tener en cuenta que en C no se pueden copiar cadenas de caracteresdirectamente, por medio de una sentencia de asignación. Por ejemplo, sí se puede asignar untexto a una cadena en el momento de la declaración:char s[] = "Esto es una cadena"; // correctoSin embargo, sería ilícito hacer lo siguiente:char s1[20] = "Esto es una cadena";char s2[20];...// Si se desea que s2 contenga una copia de s1s2 = s1; // incorrecto: se hace una copia de punterosstrcpy(s2, s1); // correcto: se copia toda la cadena

10.7 Punteros como valor de retorno

A modo de resumen, recuérdese que una función es un conjunto de instrucciones C que:- Es llamado por el programa principal o por otra función.- Recibe datos a través de una lista de argumentos, o a través de variables extern.Resumen de lenguaje ANSI C Página 54- Realiza una serie de tareas específicas, entre las que pueden estar cálculos y operacionesde lectura/escritura en el disco, en teclado y pantalla, etc.- Devuelve resultados al programa o función que la ha llamado por medio del valor deretorno y de los argumentos que hayan sido pasados por referencia (punteros).

El utilizar punteros como valor de retorno permite superar la limitación de devolver unúnico valor de retorno. Puede devolverse un puntero al primer elemento de un vector o a ladirección base de una matriz, lo que equivale a devolver múltiple valores. El valor de retornopuntero a void (void *) es un puntero de tipo indeterminado que puede asignarse sin casting aun puntero de cualquier tipo. Los punteros a void son utilizados por las funciones de reservadinámica de memoria calloc() y malloc(), como se verá más adelante.

10.8 Paso de arrays como argumentos a una funciónPara considerar el paso de arrays (vectores y matrices) como argumentos de una función, hayque recordar algunas de sus características, en particular su relación con los punteros y laforma en la que las matrices se almacenan en la memoria. Este tema se va a presentar pormedio de un ejemplo: una función llamada prod() para realizar el producto de matrizcuadrada por vector ([a]{x}={y}).Para que la definición de la función esté completa es necesario dar las dimensiones de lamatriz que se le pasa como argumento (excepto la 1ª, es decir, excepto el nº de filas), con objeto de poder reconstruir la fórmula de direccionamiento, en la que interviene el número decolumnas pero no el de filas. El encabezamiento de la definición sería como sigue:void prod(int n, double a[][10], double x[], double y[]){...}Dicho encabezamiento se puede también establecer en la forma:void prod(int n, double (*a)[10], double *x, double *y){...}donde el paréntesis (*a) es necesario para que sea "puntero a vector de tamaño 10", es decir,puntero a puntero. Sin paréntesis sería "vector de tamaño 10, cuyos elementos son punteros",por la mayor prioridad del operador [ ] sobre el operador *.La declaración de la función prod() se puede hacer en la forma:void prod(int, double a[][10], double x[], double y[]);o bien,void prod(int n, double (*a)[10], double *x, double *y);Para la llamada basta simplemente utilizar los nombres de los argumentos:double a[10][10], x[10], y[10];...prod(nfilas, a, x, y);

Ing. Nestor Huaracha Velasquez

Page 61: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 61 ...En todos estos casos a es un puntero a puntero, mientras que x e y son punteros.

10.9 Punteros a funcionesDe modo similar a como el nombre de un array en C es un puntero, también el nombre de unafunción es un puntero. Esto es interesante porque permite pasar como argumento a una7. FUNCIONES Página 55función el nombre de otra función. Por ejemplo, si pfunc es un puntero a una función quedevuelve un entero y tiene dos argumentos que son punteros, dicha función puede declararsedel siguiente modo:int (*pfunc)(void *, void *);El primer paréntesis es necesario pues la declaración:int *pfunc(void *, void *); // incorrectocorresponde a una función llamada pfunc que devuelve un puntero a entero. Considérese elsiguiente ejemplo para llamar de un modo alternativo a las funciones sin() y cos(x):#include <stdio.h>#include <math.h>void main(void){double (*pf)(double);*pf = sin;printf("%lf\n", (*pf)(3.141592654/2));*pf = cos;printf("%lf\n", (*pf)(3.141592654/2));}Obsérvese cómo la función definida por medio del puntero tiene la misma “signature”que las funciones seno y coseno. La ventaja está en que por medio del puntero pf las funcionesseno y coseno podrían ser pasadas indistintamente como argumento a otra función.Resumen de lenguaje ANSI C Página 56

Ing. Nestor Huaracha Velasquez

Page 62: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 62 11. FUNCIONES DE ENTRADA/SALIDA

A diferencia de otros lenguajes, C no dispone de sentencias de entrada/salida. En su lugar seutilizan funciones contenidas en la librería estándar y que forman parte integrante dellenguaje.Las funciones de entrada/salida (Input/Output) son un conjunto de funciones, incluidascon el compilador, que permiten a un programa recibir y enviar datos al exterior. Para suutilización es necesario incluir, al comienzo del programa, el archivo stdio.h en el que estándefinidos sus prototipos:#include <stdio.h>donde stdio proviene de standard-input-output.

10.1 Función printf()

La función printf() imprime en la unidad de salida (el monitor, por defecto), el texto, y lasconstantes y variables que se indiquen. La forma general de esta función se puede estudiarviendo su prototipo:int printf("cadena_de_control", tipo arg1, tipo arg2, ...)Explicación: La función printf() imprime el texto contenido en cadena_de_control juntocon el valor de los otros argumentos, de acuerdo con los formatos incluidos encadena_de_control. Los puntos suspensivos (...) indican que puede haber un número variablede argumentos. Cada formato comienza con el carácter (%) y termina con un carácter deconversión.Considérese el ejemplo siguiente,int i;double tiempo;float masa;printf("Resultado nº: %d. En el instante %lf la masa vale %f\n",i, tiempo, masa);en el que se imprimen 3 variables (i, tiempo y masa) con los formatos (%d, %lf y %f),correspondientes a los tipos (int, double y float), respectivamente. La cadena de control seimprime con el valor de cada variable intercalado en el lugar del formato correspondiente.Tabla 8.1. Caracteres de conversión para la función printf().

Carácter Tipo de argumento Carácter Tipo de argumentod, i int decimal o octal unsignedu int unsigned x, X hex. unsignedc char s cadena de charf float notación decimal e, g float not. científ. o brevep puntero (void *)Lo importante es considerar que debe haber correspondencia uno a uno (el 1º con el 1º,el 2º con el 2º, etc.) entre los formatos que aparecen en la cadena_de_control y los otrosargumentos (constantes, variables o expresiones). Entre el carácter % y el carácter deconversión puede haber, por el siguiente orden, uno o varios de los elementos que acontinuación se indican:

- Un número entero positivo, que indica la anchura mínima del campo en caracteres.- Un signo (-), que indica alineamiento por la izda (el defecto es por la dcha).- Un punto (.), que separa la anchura de la precisión.- Un número entero positivo, la precisión, que es el nº máximo de caracteres a imprimiren un string, el nº de decimales de un float o double, o las cifras mínimas de un int olong.- Un cualificador: una (h) para short o una (l) para long y doubleLos caracteres de conversión más usuales se muestran en la Tabla 8.1.A continuación se incluyen algunos ejemplos de uso de la función printf(). El primerejemplo contiene sólo texto, por lo que basta con considerar la cadena_de_control.

printf("Con cien cañones por banda,\nviento en popa a toda vela,\n");El resultado serán dos líneas con las dos primeras estrofas de la famosa poesía. No esposible partir cadena_de_control en varias líneas con caracteres intro, por lo que en esteejemplo podría haber problemas para añadir más estrofas. Una forma alternativa, muysencilla, clara y ordenada, de escribir la poesía sería la siguiente:printf("%s\n%s\n%s\n%s\n","Con cien cañones por banda,","viento en popa a toda vela,","no cruza el mar sino vuela,","un velero bergantín.");En este caso se están escribiendo 4 cadenas constantes de caracteres que se introducen

Ing. Nestor Huaracha Velasquez

Page 63: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 63 como argumentos, con formato %s y con los correspondientes saltos de línea. Un ejemplo quecontiene una constante y una variable como argumentos es el siguiente:printf("En el año %s ganó %ld ptas.\n", "1993", beneficios);donde el texto 1993 se imprime como cadena de caracteres (%s), mientras que beneficios seimprime con formato de variable long (%ld). Es importante hacer corresponder bien losformatos con el tipo de los argumentos, pues si no los resultados pueden ser muy diferentes delo esperado.La función printf() tiene un valor de retorno de tipo int, que representa el número decaracteres escritos en esa llamada.

8.2 Función scanf()La función scanf() es análoga en muchos aspectos a printf(), y se utiliza para leer datos de laentrada estándar (que por defecto es el teclado). La forma general de esta función es lasiguiente:int scanf("%x1%x2...", &arg1, &arg2, ...);donde x1, x2, ... son los caracteres de conversión, mostrados en la Tabla 8.2, que representanlos formatos con los que se espera encontrar los datos. La función scanf() devuelve comovalor de retorno el número de conversiones de formato realizadas con éxito. La cadena decontrol de scanf() puede contener caracteres además de formatos. Dichos caracteres seutilizan para tratar de detectar la presencia de caracteres idénticos en la entrada por teclado. Silo que se desea es leer variables numéricas, esta posibilidad tiene escaso interés. A veces hayque comenzar la cadena de control con un espacio en blanco para que la conversión deformatos se realice correctamente.Resumen de lenguaje ANSI C Página 58En la función scanf() los argumentos que siguen a la cadena_de_control deben serpasados por referencia, ya que la función los lee y tiene que trasmitirlos al programa que laha llamado. Para ello, dichos argumentos deben estar constituidos por las direcciones de lasvariables en las que hay que depositar los datos, y no por las propias variables. Una excepción

son las cadenas de caracteres, cuyo nombre es ya de por sí una dirección (un puntero), y portanto no debe ir precedido por el operador (&) en la llamada.Tabla 8.2. Caracteres de conversión para la función scanf().carácter caracteres leídos argumentoc cualquier carácter char *d, i entero decimal con signo int *u entero decimal sin signo unsigned into entero octal unsigned intx, X entero hexadecimal unsigned inte, E, f, g, G número de punto flotante floats cadena de caracteres sin ' ' charh, l para short, long y doubleL modificador para long doublePor ejemplo, para leer los valores de dos variables int y double y de una cadena decaracteres, se utilizarían la sentencia:int n;double distancia;char nombre[20];scanf("%d%lf%s", &n, &distancia, nombre);en la que se establece una correspondencia entre n y %d, entre distancia y %lf, y entrenombre y %s. Obsérvese que nombre no va precedido por el operador (&). La lectura decadenas de caracteres se detiene en cuanto se encuentra un espacio en blanco, por lo que paraleer una línea completa con varias palabras hay que utilizar otras técnicas diferentes.En los formatos de la cadena de control de scanf() pueden introducirse corchetes [...],que se utilizan como sigue. La sentencia,scanf("%[AB \n\t]", s); // se leen solo los caracteres indicadoslee caracteres hasta que encuentra uno diferente de (’A’,’B’,’ ’,’\n’,’\t’). En otraspalabras, se leen sólo los caracteres que aparecen en el corchete. Cuando se encuentra uncarácter distinto de éstos se detiene la lectura y se devuelve el control al programa que llamó ascanf(). Si los corchetes contienen un carácter (^), se leen todos los caracteres distintos de loscaracteres que se encuentran dentro de los corchetes a continuación del (^). Por ejemplo, lasentencia,scanf(" %[^\n]", s);lee todos los caracteres que encuentra hasta que llega al carácter nueva línea ’\n’. Esta

Ing. Nestor Huaracha Velasquez

Page 64: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 64 sentencia puede utilizarse por tanto para leer líneas completas, con blancos incluidos.Recuérdese que con el formato %s la lectura se detiene al llegar al primer delimitador(carácter blanco, tabulador o nueva línea).

11.3 Macros getchar() y putchar()

Las macros6 getchar() y putchar() permiten respectivamente leer e imprimir un sólo caráctercada vez, en la entrada o en la salida estándar. La macro getchar() recoge un carácterintroducido por teclado y lo deja disponible como valor de retorno. La macro putchar()escribe en la pantalla el carácter que se le pasa como argumento. Por ejemplo:putchar(’a’);escribe el carácter a. Esta sentencia equivale aprintf("a");mientras quec = getchar();equivale ascanf("%c", &c);Como se ha dicho anteriormente, getchar() y putchar() son macros y no funciones,aunque para casi todos los efectos se comportan como si fueran funciones. El concepto demacro se verá con más detalle en la siguiente sección. Estas macros están definidas en elfichero stdio.h, y su código es sustituido en el programa por el preprocesador antes de lacompilación.Por ejemplo, se puede leer una línea de texto completa utilizando getchar():int i=0, c;char name[100];while((c = getchar()) != ’\n’) // se leen caracteres hasta el ’\n’name[i++] = c; // se almacena el carácter en Name[]name[i]='\0'; // se añade el carácter fin de cadena

11.4 Otras funciones de entrada/salida

Las funciones fprintf() y fscanf() se emplean de modo análogo a printf() y scanf(), pero enlugar de leer y escribir en la salida y en la entrada estándar, lo hacen en un archivo de disco.

Dicho archivo deberá haber sido abierto previamente mediante la función fopen(), quefunciona como se explica a continuación.En primer lugar hay que declarar un puntero a archivo (se trata del tipo FILE, un tipoderivado que está predefinido en el fichero stdio.h), que servirá para identificar el archivo conel que se va a trabajar. Después se abre el archivo con la función fopen(), que devuelve comovalor de retorno un puntero al archivo abierto. A fopen() hay que pasarle como argumentos elnombre del archivo que se quiere abrir y el modo en el que se va a utilizar dicho archivo. Acontinuación se presenta un ejemplo:FILE *pf; // declaración de un puntero a archivopf = fopen("nombre", "modo");donde nombre es el nombre del archivo y modo es un carácter que indica el modo en el que elfichero se desea abrir:6 Una macro representa una sustitución de texto que se realiza antes de la compilación por medio delpreprocesador. Para casi todos los efectos, estas macros pueden ser consideradas como funciones. Másadelante se explicarán las macros con algunos ejemplos.Resumen de lenguaje ANSI C Página 60r sólo lectura (read)w escritura desde el comienzo del archivo (write)a escritura añadida al final del archivo (append)r+ lectura y escrituraw+ escritura y lecturarb sólo lectura (archivo binario)wb escritura desde el comienzo del archivo (archivo binario)ab escritura añadida al final del archivo (archivo binario)El puntero pf devuelto por fopen() será NULL (=0) si por alguna razón no se haconseguido abrir el fichero en la forma deseada.Los prototipos de las funciones fscanf() y fprintf() tienen la forma:int fprintf(FILE *fp, "cadena de control", tipo arg1, tipo arg2, ...);int fscanf(FILE *fp, "cadena de control", &arg1, &arg2, ...);y la forma general de llamar a dichas funciones, que es completamente análoga a la forma dellamar a printf() y scanf(), es la siguiente:fprintf(fp, "cadena_de_control", otros_argumentos);fscanf(fp, "cadena_de_control", otros_argumentos);Los argumentos de fscanf() se deben pasar por referencia. Una vez que se ha terminado

Ing. Nestor Huaracha Velasquez

Page 65: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 65 de trabajar con un fichero, es conveniente cerrarlo mediante la función fclose(), en la forma:fclose(fp);Existen también unas funciones llamadas sprintf() y sscanf() que son análogas afprintf() y fscanf(), sustituyendo el puntero a fichero por un puntero a una cadena decaracteres almacenada en la memoria del ordenador. Así pues, estas funciones leen y/oescriben en una cadena de caracteres almacenada en la memoria.Hay otras funciones similares a fprintf() y fscanf(), las funciones fread() y fwrite(),que leen y escriben en disco archivos binarios, respectivamente. Como no se realizanconversiones de formato, estas funciones son mucho más eficientes que las anteriores entiempo de CPU.Las "funciones" putc(c, fp) y getc(fp) son asimismo macros definidas en stdio.h queescriben o leen un carácter de un fichero determinado por un puntero a fichero (FILE *fp).Existen también funciones para acceder a un fichero de modo directo, es decir, nosecuencial. El acceso secuencial lee y escribe las líneas una detrás de otra, en su orden natural.El acceso directo permite leer y escribir datos en cualquier orden.Las funciones remove() y rename() se utilizan para borrar o cambiar el nombre a unfichero desde un programa.Existen en C más funciones y macros análogas a las anteriores. Para más detalles sobrela utilización de todas estas funciones, consultar un manual de C.

Ing. Nestor Huaracha Velasquez

Page 66: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 66 12. EL PREPROCESADOREl preprocesador del lenguaje C permite sustituir macros (sustitución en el programa deconstantes simbólicas o texto, con o sin parámetros), realizar compilaciones condicionales eincluir archivos, todo ello antes de que empiece la compilación propiamente dicha. Elpreprocesador de C reconoce los siguientes comandos:#define, #undef#if, #ifdef, #ifndef, #endif, #else, #elif#include#pragma#errorLos comandos más utilizados son: #include, #define.

12.1 Comando #includeCuando en un archivo .c se encuentra una línea con un #include seguido de un nombre dearchivo, el preprocesador la sustituye por el contenido de ese archivo.La sintaxis de este comando es la siguiente:#include "nombre_del_archivo"#include <nombre_del_archivo>La diferencia entre la primera forma (con comillas "...") y la segunda forma (con lossímbolos <...>) estriba en el directorio de búsqueda de dichos archivos. En la forma concomillas se busca el archivo en el directorio actual y posteriormente en el directorio estándarde librerías (definido normalmente con una variable de entorno del MS-DOS llamadaINCLUDE, en el caso de los compiladores de Microsoft). En la forma que utiliza los símbolos<...> se busca directamente en el directorio estándar de librerías. En la práctica, los archivosdel sistema (stdio.h, math.h, etc.) se incluyen con la segunda forma, mientras que los archivoshechos por el propio programador se incluyen con la primera.Este comando del preprocesador se utiliza normalmente para incluir archivos con losprototipos (declaraciones) de las funciones de librería, o con módulos de programación yprototipos de las funciones del propio usuario. Estos archivos suelen tener la extensión *.h,aunque puede incluirse cualquier tipo de archivo de texto.12.2 Comando #define

El comando #define establece una macro en el código fuente. Existen dos posibilidades dedefinición:#define NOMBRE texto_a_introducir#define NOMBRE(parámetros) texto_a_introducir_con_parámetrosAntes de comenzar la compilación, el preprocesador analiza el programa y cada vez queencuentra el identificador NOMBRE lo sustituye por el texto que se especifica a continuaciónen el comando #define. Por ejemplo, si se tienen las siguientes líneas en el código fuente:#define E 2.718281828459...void main(void) {double a;a= (1.+1./E)*(1.-2./E);...}Resumen de lenguaje ANSI C Página 62al terminar de actuar el preprocesador, se habrá realizado la sustitución de E por el valorindicado y el código habrá quedado de la siguiente forma:void main(void) {double a;a= (1.+1./2.718281828459)*(1.-2./2.718281828459);...}Este mecanismo de sustitución permite definir constantes simbólicas o valoresnuméricos (tales como E, PI, SIZE, etc.) y poder cambiarlas fácilmente, a la vez que elprograma se mantiene más legible.De la forma análoga se pueden definir macros con parámetros: Por ejemplo, lasiguiente macro calcula el cuadrado de cualquier variable o expresión,#define CUAD(x) ((x)*(x))void main() {double a, b;...a = 7./CUAD(b+1.);...}Después de pasar el preprocesador la línea correspondiente habrá quedado en la forma:a = 7./((b+1.)*(b+1.));Obsérvese que los paréntesis son necesarios para que el resultado sea el deseado, y que

Ing. Nestor Huaracha Velasquez

Page 67: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 67 en el comando #define no hay que poner el carácter (;). Otro ejemplo de macro con dosparámetros puede ser el siguiente:#define C_MAS_D(c,d) (c + d)void main() {double a, r, s;a = C_MAS_D(s,r*s);...}con lo que el resultado será:a = (s + r*s);El resultado es correcto por la mayor prioridad del operador (*) respecto al operador (+).Cuando se define una macro con argumentos conviene ser muy cuidadoso para prever todoslos posibles resultados que se pueden alcanzar, y garantizar que todos son correctos. En ladefinición de una macro pueden utilizarse macros definidas anteriormente. En muchasocasiones, las macros son más eficientes que las funciones, pues realizan una sustitucióndirecta del código deseado, sin perder tiempo en copiar y pasar los valores de los argumentos.Es recomendable tener presente que el comando #define:– No define variables.– Sus parámetros no son variables.– En el preprocesamiento no se realiza una revisión de tipos, ni de sintaxis.– Sólo se realizan sustituciones de código.Es por estas razones que los posibles errores señalados por el compilador en una líneade código fuente con #define se deben analizar con las substituciones ya realizadas. Porconvención entre los programadores, los nombres de las macros se escriben con mayúsculas.

Existen también muchas macros predefinidas a algunas variables internas del sistema.Algunas se muestran en la Tabla 9.1.Tabla 9.1. Algunas macros predefinidas.__DATE__ Fecha de compilación__FILE__ Nombre del archivo__LINE__ Número de línea__TIME__ Hora de compilaciónSe puede definir una macro sin texto_a_sustituir para utilizarla como señal a lo largodel programa. Por ejemplo:#define COMP_HOLA

La utilidad de esta línea se observará en el siguiente apartado.

12.3 Comandos #ifdef, #ifndef, #else, #endif, #undef

Uno de los usos más frecuentes de las macros es para establecer bloques de compilaciónopcionales. Por ejemplo:#define COMP_HOLAvoid main() {// si está definida la macro llamada COMP_HOLA#ifdef COMP_HOLAprintf("hola");#else // si no es asíprintf("adios");#endif}El código que se compilará será printf("hola") en caso de estar definida la macroCOMP_HOLA; en caso contrario, se compilará la línea printf("adios"). Esta compilacióncondicional se utiliza con frecuencia para desarrollar código portable a varios distintos tiposde computadores; según de qué computador se trate, se compilan unas líneas u otras. Paraeliminar una macro definida previamente se utiliza el comando #undef:#undef COMP_HOLADe forma similar, el comando #ifndef pregunta por la no-definición de la macrocorrespondiente. Un uso muy importante de los comandos #ifdef y #ifndef es para evitarcomandos #include del mismo fichero repetidos varias veces en un mismo programa.

Ing. Nestor Huaracha Velasquez

Page 68: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 68 13. OTROS ASPECTOS DEL LENGUAJE C

13.1 Typedef

Esta palabra reservada del lenguaje C sirve para la creación de nuevos nombres de tipos dedatos. Mediante esta declaración es posible que el usuario defina una serie de tipos devariables propios, no incorporados en el lenguaje y que se forman a partir de tipos de datos yaexistentes. Por ejemplo, la declaración:typedef int ENTERO;define un tipo de variable llamado ENTERO que corresponde a int.Como ejemplo más completo, se pueden declarar mediante typedef las siguientesestructuras:#define MAX_NOM 30#define MAX_ALUMNOS 400struct s_alumno { // se define la estructura s_alumnochar nombre[MAX_NOM];short edad;};typedef struct s_alumno ALUMNO; // ALUMNO es un nuevo tipo de variabletypedef struct s_alumno *ALUMNOPTR;struct clase {ALUMNO alumnos[MAX_ALUMNOS];char nom_profesor[MAX_NOM];};typedef struct clase CLASE;typedef struct clase *CLASEPTR;Con esta definición se crean las cuatro palabras reservadas para tipos, denominadasALUMNO (una estructura), ALUMNOPTR (un puntero a una estructura), CLASE y CLASEPTR.Ahora podría definirse una función del siguiente modo:int anade_a_clase(ALUMNO un_alumno, CLASEPTR clase){ALUMNOPTR otro_alumno;otro_alumno = (ALUMNOPTR) malloc(sizeof(ALUMNO));otro_alumno->edad = 23;...clase->alumnos[0]=alumno;...return 0;}El comando typedef ayuda a parametrizar un programa contra problemas de

portabilidad. Generalmente se utiliza typedef para los tipos de datos que pueden serdependientes de la instalación. También puede ayudar a documentar el programa (es muchomás claro para el programador el tipo ALUMNOPTR, que un tipo declarado como un puntero auna estructura complicada), haciéndolo más legible.

13.2 Funciones recursivasLa recursividad es la posibilidad de que una función se llame a sí misma, bien directa oindirectamente. Un ejemplo típico es el cálculo del factorial de un número, definido en laforma:N! = N * (N-1)! = N * (N-1) (N-2)! = N * (N-1)*(N-2)*...*2*1La función factorial, escrita de forma recursiva, sería como sigue:unsigned long factorial(unsigned long numero){if ( numero == 1 || numero == 0 )return 1;elsereturn numero*factorial(numero-1);}Supóngase la llamada a esta función para N=4, es decir factorial(4). Cuando se llamepor primera vez a la función, la variable numero valdrá 4, y por tanto devolverá el valor de4*factorial(3); pero factorial(3) devolverá 3*factorial(2); factorial(2) a su vez es2*factorial(1) y dado que factorial(1) es igual a 1 (es importante considerar que sin éste uotro caso particular, llamado caso base, la función recursiva no terminaría nunca de llamarse así misma), el resultado final será 4*(3*(2*1)).Por lo general la recursividad no ahorra memoria, pues ha de mantenerse una pila7 conlos valores que están siendo procesados. Tampoco es más rápida, sino más bien todo locontrario, pero el código recursivo es más compacto y a menudo más sencillo de escribir ycomprender.

13.3 Gestión dinámica de la memoria

Ing. Nestor Huaracha Velasquez

Page 69: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 69 Según lo visto hasta ahora, la reserva o asignación de memoria para vectores y matrices sehace de forma automática con la declaración de dichas variables, asignando suficientememoria para resolver el problema de tamaño máximo, dejando el resto sin usar paraproblemas más pequeños. Así, si en una función encargada de realizar un producto dematrices, éstas se dimensionan para un tamaño máximo (100, 100), con dicha función sepodrá calcular cualquier producto de un tamaño igual o inferior, pero aun en el caso de que elproducto sea por ejemplo de tamaño (3, 3), la memoria reservada corresponderá al tamañomáximo (100, 100). Es muy útil el poder reservar más o menos memoria en tiempo deejecución, según el tamaño del caso concreto que se vaya a resolver. A esto se llama reserva ogestión dinámica de memoria.Existen en C dos funciones que reservan la cantidad de memoria deseada en tiempo deejecución. Dichas funciones devuelven –es decir, tienen como valor de retorno– un puntero ala primera posición de la zona de memoria reservada. Estas funciones se llaman malloc() ycalloc(), y sus declaraciones, que están en la librería stdlib.h, son como sigue:void *malloc(int n_bytes)void *calloc(int n_datos, int tamaño_dato)La función malloc() busca en la memoria el espacio requerido, lo reserva y devuelve unpuntero al primer elemento de la zona reservada. La función calloc() necesita dos argumentos:7 Una pila es un tipo especial de estructura de datos que se estudiará en INFORMÁTICA 2.Resumen de lenguaje ANSI C Página 66el nº de celdas de memoria deseadas y el tamaño en bytes de cada celda; se devuelve unpuntero a la primera celda de memoria. La función calloc() tiene una propiedad adicional:inicializa todos los bloques a cero.Existe también una función llamada free() que deja libre la memoria reservada pormalloc() o calloc() y que ya no se va a utilizar. Esta función usa como argumento el punterodevuelto por calloc() o malloc(). La memoria no se libera por defecto, sino que el

programador tiene que liberarla explícitamente con la función free(). El prototipo de estafunción es el siguiente:void free(void *)A continuación se presenta un ejemplo de gestión dinámica de memoria para elproducto de matriz por vector {y}=[a]{x}. Hay que tener en cuenta que reservando memoriapor separado para cada fila de la matriz, no se garantiza que las filas estén contiguas en lamemoria. Por otra parte, de esta forma se pueden considerar filas de distinto tamaño. Elnombre de la matriz se declara como puntero a vector de punteros, y los nombres de losvectores como punteros (recuérdese la figura 6.1). Supóngase que N es una constantesimbólica predefinida con el número de filas.// declaracionesdouble **a, *x, *y;void prod(int , double **, double *, double *);...// reserva de memoria para la matriz aa = calloc(N, sizeof(double *));for (i=0; i<N; i++)a[i]=calloc(N, sizeof(double));...// reserva de memoria para los vectores x e yx = calloc(N, sizeof(double);y = calloc(N, sizeof(double);...prod(N, a, x, y);...// definicion de la funcion prod()void prod(int N, double **mat, double *x, double *y){...}Con gestión dinámica de memoria es más fácil utilizar matrices definidas como vectoresde punteros que matrices auténticas (también éstas podrían utilizarse con memoria dinámica:bastaría reservar memoria para las N filas a la vez y asignar convenientemente los valores alvector de punteros a[i]). El ejemplo anterior quedaría del siguiente modo:// declaracionesdouble **a, *x, *y;void prod(int , double **, double *, double *);...// reserva de memoria para el vector de punteros a[]

Ing. Nestor Huaracha Velasquez

Page 70: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 70 a = calloc(N, sizeof(double *));// reserva de memoria para toda la matriz a[][]a[0] = calloc(N*N, sizeof(double));// asignación de valor para los elementos del vector de punteros a[]for (i=1; i<N; i++)a[i] = a[i-1]+N;// el resto del programa sería idéntico...

Ing. Nestor Huaracha Velasquez

Page 71: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 71 14. ESTRUCUTRA DE DATOS

14.1 INTRODUCCION Y DEFINICION DE ESTRUCTURA DE DATOS

Como ya sabemos, las computadoras fueron diseñadas o ideadas como una herramienta mediante la cual podemos realizar operaciones de cálculo complicadas en un lapso de mínimo tiempo. Pero la mayoría de las aplicaciones de este fantástico invento del hombre, son las de almacenamiento y acceso de grandes cantidades de información.La información que se procesa en la computadora es un conjunto de datos, que pueden ser simples o estructurados. Los datos simples son aquellos que ocupan sólo una localidad de memoria, mientras que los estructurados son un conjunto de casillas de memoria a las cuales hacemos referencia mediante un identificador único.Debido a que por lo general tenemos que tratar con conjuntos de datos y no con datos simples (enteros, reales, booleanos, etc.) que por sí solos no nos dicen nada, ni nos sirven de mucho, es necesario tratar con estructuras de datos adecuadas a cada necesidad.Las estructuras de datos son una colección de datos cuya organización se caracteriza por las funciones de acceso que se usan para almacenar y acceder a elementos individuales de datos.Una estructura de datos se caracteriza por lo siguiente: Pueden descomponerse en los elementos que la forman. La manera en que se colocan los elementos dentro de la estructura afectará la forma en que se realicen los accesos a cada elemento. La colocación de los elementos y la manera en que se accede a ellos puede ser encapsulada. Ejemplo: Supongamos que nos enfrentamos a un problema como este: Una empresa que cuenta con 150 empleados, desea establecer una estadística sobre los salarios de sus empleados, y quiere saber cual es el salario promedio, y también cuantos de sus empleados gana entre $1250.00 y $2500.00.Si tomamos la decisión de tratar este tipo de problemas con datos simples, pronto nos percataríamos del enorme desperdicio de tiempo, almacenamiento y velocidad. Es por eso que para situaciones de este tipo la mejor solución son los datos estructurados.

14.2. OBJETIVOS:El objetivo por el cual fue el presente trabajo de Estructura de Datos, es el establecer un material de apoyo y consulta para ti que eres alumno de Ingeniería Informática y de Sistemas o de cualquier otra área afín en la cual se imparta la materia de Estructura de Datos.

Una vez que hayas terminado de revisar detenidamente este material, serás capaz de establecer estructuras lógicas de datos que te permitan hacer un uso más eficiente del espacio de memoria, de minimizar los tiempos de

acceso, así como de lograr formas más efectivas de inserción y eliminación de datos en estructuras de almacenamiento. Ahora que ya sabes en lo que te puede ayudar este tutorial, puedes empezar a hacer uso de él, consultando todas tu tareas y dudas que tengas acerca de la materia.Acceder a cualquier elemento del arreglo sin tener que consultar a elementos anteriores o posteriores, esto mediante el uso de un índice para cada elemento del arreglo que nos da su posición relativa.

14.3 ARREGLOSCONCEPTO :Es un conjunto de datos o una estructura de datos homogéneos que se encuentran ubicados en forma consecutiva en la memoria RAM ( sirve para almacenar datos en forma temporal). Un arreglo puede definirse como un grupo o una colección finita, homogénea y ordenada de elementos. Los arreglos pueden ser de los siguientes tipos:

De una dimensión. De dos dimensiones. De tres o más dimensiones

1. ARREGLOS UNIDIMENSIONALESUn arreglo unidimensional es un tipo de datos estructurado que está formado de una colección finita y ordenada de datos del mismo tipo. Es la estructura natural para modelar listas de elementos iguales. Para implementar arreglos unidimensionales se debe reservar espacio en memoria, y se debe proporcionar la dirección base del arreglo, la cota superior y la inferior. Ejemplos1. Diseñar un algoritmo que ingrese 30 notas aprobados y que me muestre la nota mayor y el promedio de todas (Nota>=10.5 y Nota<=20)Solución :Inicionota[30], s, may, p : reali : enteros←0para (i=1; i<=30; i++)repetirIngresar nota [i]hasta (nota[i]>=10.5) y (nota[i]<=20)s ← s + nota[i]si (i=1) entoncesmay ← nota[i]sinosi (nota[i]>may) entoncesmay ← nota[i]fin _ sifin _ sifin _ para

Ing. Nestor Huaracha Velasquez

Page 72: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 72 p ← s/30mostrar "PROMEDIO TOTAL ES",pmostrar "LA NOTA MAYOR ES",mayFin

2. Ingresar 30 valores cualesquiera y determinar cuantos de estos valores son iguales al promedio de los 30 valores ingresados anteriormente.Solución :Inicionum[30], i, s ß 0, c ß 0 : enterop : realpara(i=1;i<=30;i++)Ingresar num[i]S ß s + num[i]fin_parap ß s/30para(i=1;i<=30;i++)si (p=num[i]) entoncescß c+1fin_sifin_paramostrar "Números Iguales al promedio",cFin

3. Controlar el siguiente menú : 1. Ingresar .- En esta opción usted deberá ingresar 20 números positivos

que no sean mayores que 100. 2. Mostrar .- En esta opción usted deberá calcular y mostrar el promedio

solo de los números cuyo primer digito de su izquierda sea el 2 y el 3. Solucion :Inicionum[20], i, opc, indß 0, c, s : enterop : realrepetirmostrar "1 : INGRESAR"mostrar "2 : MOSTRAR"mostrar "3 : SALIR"repetiringresar opcasta (opc>=1) y (opc<=3)según_sea opc hacer1 : Iniciopara (i=1; i<=20; I++)repetiringresar num [i]hasta (num[1]>0) y (num[i]<=100)fin_para

Fin

3 : Iniciosi (ind=1) entoncescß 0sß 0para(i=1; i<=20; i++)si (num[i]>=20 y num[i]<40) entoncessß s+num[i]cß c+1fin_sifin_parasi (c=0) entoncesmostrar "NO EXISTE NUMERO CON DIGITOS 2 Y 3"sinopß s/cmostrar "promedio",pfin_sisinomostrar "INGRESE DATOS"fin_sifinfin_según seaHasta (opc=3)Fin

4. Diseñar un algoritmo que ingrese 15 números cualesquiera.Solución :

Inicionum[15]: enteroi: enteropara (i=1; i<=15; i++)Ingresar num[i]Fin _ paraFin

5. Utilizando arreglos, ingresar 15 números y calcular cual es el número menor.Solución : Inicioi, men, Num[15]: enteropara (i=1; i<=15; i++)Ingresar Num[i]si (i=1) entoncesmen ← num[i]sino

Ing. Nestor Huaracha Velasquez

Page 73: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 73 si (Num[i]< men) entoncesmenor ← Num[i]Fin _ siFin _ siFin _ paraFin

Con Alternativas Múltiples6. Diseñar un algoritmo que controle las siguientes opciones del menú:

1. Ingresar : En esta opción Ud. deberá ingresar 30 números positivos cualesquiera.

2. Mostrar : En esta opción Ud. deberá mostrar el promedio y tambien cuantos números superan dicho promedio.

3. Salir.Solución :

Inicioopc: caracter num[30]: entero

i, s ← 0, c ← 0, sw: enterop : realsw ← 0repetirMostrar "1.- Ingresar"Mostrar "2.- Mostrar"Mostrar "3.- Salir"repetirpedir opchasta (opc>=1 y opc <=3)1: Iniciosw ← 1para (i=1; i<=30; i++)repetirpedir num[i]hasta (num[i]>0)Fin _ paraFin2: Iniciosi (sw = 1) entoncess ← 0para (i=1; i<=30; i++)s ← s+ num[i]fin _ parap ← s/30c ← 0para (i=1; i<=30; i++)si (num[i]>0) entonces

c ← c + 1fin _ sifin _ parasi (c = 0) entoncesmostrar "NÚMEROS IGUALES"sinomostrar p,cfin _ sisinoMostrar "Aún no ingresar datos"Fin _ si hasta opc = 3Fin7. Almacenar en un arreglo los 5 primeros números primos positivos.Solución:Inicioprimo[5]: enteroi, n, d, c: enteroc ← 0n ← 0repetirn ← n+1; d ← 0para (i=1; i<=n; i++)si (n mod i=0) entoncesd ← d+1fin _ sifin _ parasi (d=2) entoncesc ← c+1primo[c] ← NFin_sihasta (c=5)Fin

8. Ingresar 2 números y mostrar cual es el mayor de ellos.Solución:Inicioa, b : enteropedir asi (a>b) entoncesmostrar "a mayor", asinosi (b>a) entonces mostrar "b mayor"sinosi (a=b) entoncesson iguales

Ing. Nestor Huaracha Velasquez

Page 74: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 74 Fin _ siFin _ siFin _ siFin9. Ingresar un número positivo y mostrar cual es su mitad.Solucion :InicioIngresar Nrepetirpedir N hasta que N>0N=N/2Mostrar "La mitad es" N/2Fin _ repetirFin 10 Ingresar un número par y mostrar sus divisores; el número par debe ser positivo.Solución :Inicion, i, c ← 0: enterorepetirIngresar nhasta (n>0) y (n mod 2=0)para (i=1; i<=n; i++)si (n mod i=0) entoncesc ← c+1Mostrar iFin _ siFin _ paraMostrar "Cantidad de divisores"Fin11. Ingresar 5 números negativos y calcular su media aritmética.Solución :IniciorepetirIngresar nhasta (n<0 y n mod 2=0)para (i=0; i<=5; i++)si (n mod i=0) entoncesc ← c+1mostrar ifin _ sifin _ paraescribir "MEDIA ARITMÉTICA ES ", C Fin 12. Ingresar 5 números en un arreglo.

Solución :Inicio

num[5]:enteroi: enteropara (i=1; i<=5; i++)ingresar num[5]Fin _ paraFin 13. Ingresar 5 números positivos. No utilizar la estructura repetir desde.Solución :Inicioi, num[5]: enteroi ← 1mientras (i<=5)repetirIngresar num[i]hasta (num[i]>0)i ← i+1Fin _ mientrasFin 14. Ingresar un número mayor que 50 y calcular la suma y el promedio de sus 5 primeros divisores. Almacenar los divisores en un arreglo.Solución :Iniciox ← 0, s ← 0, c ← 0repetirIngresar nhasta (n>50)repetirx ← x+1si (n mod x=0) entoncesc ← c+1divisor[c] ← xfin _ si hasta (c=s)para (i=1; i<=5; i++)s ← s + divisor[i]fin _ paramostrar "EL PROMEDIO ES", pmostrar "LA SUMA ES", sFin15. Almacenar en un arreglo todos los números primos que se encuentren entre 1 y 40.

Solución :Iniciopara (i=2; i<=39; i++)d ← 0para (j=1; j<=i; j++)si (i mod j=0) entonces

Ing. Nestor Huaracha Velasquez

Page 75: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 75 d ← d+1fin _ sifin _ parasi (d=2) entoncesc ← c+1primo[c]+ ifin _ sifin _ parafin 16. Controlar el siguiente menú:1. Pares: ingresar 35 números pares negativos y mostrar el valor absoluto del promedio.2. Impares: Ingresar 10 números impares positivos que sean dígitos para luego determinar el promedio de los mismos.3 Salir: En esta opción Ud. deberá confirmar si desea abandonar la ejecución del algoritmo.Solución :Inicionum[35], opc, i : enteros, p : enterores : caracterrepetirMostrar "1.Pares"Mostrar "2.Impares"Mostrar "3. Salir"repetirIngresar opchasta(opc>=1) y (opc<=3)según _ sea opc hacer1. Iniciopara(i=1; i<=35; i++)repetirIngresar num[i]hasta(num[i] mod 2=0) y (num[i]<0)s ← s+num[i]fin _ parap ← (s/35)*-1Mostrar "Valor absoluto", pFin 2º Iniciopara(i=1; i<=10; i++)repetirIngresar num[i]hasta(num[i] mod 2=1) y (num[i]>0) y (num[i]<10)s ← s+num[i] fin _ parap ← s/10

Mostrar "promedio", pFin 3º IniciorepetirIngresar "Desea salir (S/N)" Reshasta(res=’S’) o (res=’N’)si (res=’N’) entoncesopc ← 0Fin _ siFinFin _ según _ seahasta opc=3Fin17. Controlar las siguientes opciones del menú:a.- Pares – Impares : En esta opción Ud. Deberá ingresar 30 números pares e impares en forma consecutiva, donde necesariamente el primer número deberá ser un numero par luego un impar y así intercaladamente.b.- Impares – Pares : Ingresar 30 números impares – pares en forma intercalada empezando con un impar.c.- Mostrar : En esta opción Ud. deberá mostrar la suma de los números pares ingresados en la opción A o B, también deberá el algoritmo indicar cual de las dos opciones está mostrando Ud. Ya sea A o B.d.- Salir.NOTA: Ud. deberá trabajar solamente con un arreglo de 30 números.Solución :Inicionum[30]: enteroi, ind, s: enteroopc: caracterrepetirMostrar "A : Pares – Impares"Mostrar "B : Impares – Pares"Mostrar "C : Mostrar"Mostrar "D : Salir"repetirIngresar opchasta (opc="A") o (opc="B") o (opc="C") o (opc="D")según _ sea opc hacerA : Inicioind ← 1para (i=1; i<=30; i++) si (i mod 2=0) entoncesrepetirIngresar num[i] hasta (num[i] mod 2<>0)sinorepetir

Ing. Nestor Huaracha Velasquez

Page 76: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 76 Ingresar num[i]hasta (num[i] mod 2=0) y (num[i]<>0)Fin _ siFin _ paraFin

A. Inicio B : InicioInd ← 2 para (i=1; i<=30; i++) si (i mod 2=0) entoncesrepetiringresar Num[i]hasta (Num[i] mod 2=0) y (Num[i]<>0)sinorepetirIngresar Num[i]hasta (Num[i] mod 2<>0)Fin _ siFin _ paraFin C : Iniciosi (ind =0) entoncesMostrar "Aún no ingresar datos"sinosi (ind =1) entoncesMostrar "Resultado opción 1"sinoMostrar "Resultado opción 2"Fin _ siS ← 0para (i=1; i<=30; i++)si (Num[i] mod 2=0) entoncesS ← S+Num[i]Fin _ siFin _ paraMostrar "S"Fin _ si finfin _ según _ seahasta (opc=’D’)fin18. Ingresar un número que tenga 10 dígitos, donde cada dígito debe de ser almacenado en una posición del arreglo.Solución :InicioN[10] : enteroi : entero

para (i = 1; i <= 10; i ++)si (i=1) entoncesrepetiringresar N[i]hasta (N[i]>0) y (N[i]<10)sinorepetiringresar N[i]hasta (N[i]>=0) y (N[i]<10)fin_sifin_paraFin19. Almacenar en un arreglo los 5 primeros números primos positivos, para luego mostrar cual es el tercer número primo calculado.Solución : Iniciop[5] : enteroc ß 0, cpß 0, d, i : enterorepetirc = c + 1d = 0para (i = 1; i <= c; i ++)si (c mod i = 0) entoncesd = d + 1fin_sifin_parasi (d=2) entoncescp=cp+1p[cp]=cfin_sihasta (cp=5)mostrar p[3]fin

14.4 ARREGLOS DE TIPO CARÁCTER

20. Diseñar un algoritmo que ingrese una cadena de carácter cualesquiera, para luego mostrar cuantos caracteres tiene dicha cadena.Solución :Iniciocad[25]: carácterL: enteroIngresar cadL ← Longitud (cad)Mostrar " Número caracter", L

Ing. Nestor Huaracha Velasquez

Page 77: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 77 Fin21. Escribir un algoritmo que determine si una cadena de caracteres es un palíndromo ( una palabra que al revés dice lo mismo ejm: RADAR)Solución :Iniciocad[30]: carácterL, i, j, C ← 0: enteroIngresar cadL ← Longitud (cad)j ← Lpara (i=0; i <= L-1; i++)j ← j -1si (cad[i]= cad[j] ) entoncesC ← C+1Fin _ siFin _ parasi (C = L) entoncesMostrar "Palíndromo" sinoMostrar "No es palíndromo"Fin _ siFin 22. Ingresar una cadena y mostrar cuantos vocales existen en la cadena.Solución :Iniciocad[25]: caracterL, C ← 0: enteroIngresar cadL ← Longitud cadpara (i=0; i<=L-1; i++)según _ sea cad[i] hacer‘a’ : C ← C+1‘e’ : C ← C+1‘i’ : C ← C+1‘o’ : C ← C+1‘u’ : C ← C+1fin _ según _ seafin_paraMostrar "Cantidad vocales", CFin23. Escribir un algoritmo que permita ingresar una frase y luego la descomponga en sus palabras imprimiéndolas en líneas diferentes ejm : Estructura De Datos EstructuraDeDatos Solución :Inicio

cad[20] : carácteri, L : enteroingresar cad [i]L ß longitud (cad)Para ( i = 0; i <= L-1; i++)mostrar cad [i]si (cad [i] = ‘ ‘) entoncessaltar líneafin_sifin_parafin

14.5 ARREGLOS BIDIMENSIONALES (Matrices) :

Unidimensional:Nombre [10]: tipoNum [10]: enteroIngresarPara (i =1; i £ 10; i ++)Ingresar Num [i]Fin_paraFinBidimensional:Nombre [fila] [columna] : tipoNum [10] [10] : enteroIngresarPara (i = 1; i £ 10; i ++ )Para (j = 1; j £ 10; j ++)Ingresar Num [i] [j]Fin_paraFin_paraFinEjercicios:

1. Diseñar un algoritmo que permita ingresar una matriz de orden n donde todos los elementos de dicha matriz sean números naturales. InicioNum [8] [8]: enteroi, j, N :enteroRepetirIngresar NHasta (N > 1 y N £ 8)Para (i = 1; i £ N; i ++)Para (j = 1; j £ N; j ++)RepetirIngresar Num [i] [j]Hasta (Num [i] [j] ³ 0)Fin_para

Ing. Nestor Huaracha Velasquez

Page 78: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 78 Fin_paraFin

2. Diseñar un algoritmo que permita ingresar 35 números impares en una matriz de orden n x m. InicioNum [35] [35]: enteroi, j, N, M: enteroRepetirIngresar N, MHasta (M x N = 35 y M > 0)Para (i = 1; i £ M; i ++)Para (j = 1; j £ N; j ++)RepetirIngresar Num [i] [j]Hasta (Num [i ] [j] mod 2 < > 0)Fin_paraFin_paraFin.3._ Ingresar 15 números negativos en una matriz de orden mxn. InicioM[15][15]: enteroi, j, m, n: enterorepetirIngresar m, nhasta (m + n =15) y (m>0)para (i=1; i<=m; i++)para (j=1; j<=n; j++)repetirIngresar M[i][j]hasta (M[i][j]>0)Fin _ paraFin _ paraFin 4._ Diseñar un algoritmo que ingrese una matriz cuadrada, para luego calcular su diagonal principal.InicioNum[35][35]: enteroi, j, N, S ← 0: enterorepetir Ingresar Nhasta (N>1; y N<=35)para (i=1; i<=N; i++)para (j=1; j<=N; j++)Ingresar Num[i][j]Fin _ paraFin _ parapara (i=1; i<=N; i++)

para (j=1; j<=N; j++)si i=j entoncesS ← S+Num[i][j]Fin _ siFin _ paraFin _ paraMostrar "Diagonal P:", SFin 5._ Diseñar un algoritmo que ingrese una matriz cuadrada, para luego calcular su diagonal secundaria.InicioNum[35][35]: enteroi, j, N, S ← 0: enterorepetir Ingresar Nhasta (N>1; y N<=35)para (i=1; i<=N; i++)para (j=1; j<=N; j++)Ingresar Num[i][j]Fin _ paraFin _ parapara (i=1; i<=N; i++)para (j=1; j<=N; j++)si i+j=N+1 entoncesS ← S+Num[i][j]Fin _ siFin _ paraFin _ paraMostrar "Diagonal S", SFin 6._ Diseñar un algoritmo que permita almacenar en un arreglo los impares que sean dígitos cuando i + j sea par, para el caso que i + j no sea par usted deberá ingresar cualquier número negativo.InicioM: enteroi, j, N: enteropara i=1 hasta Npara j=1 hasta Nsi (i + j mod 2=0)repetirLeer "Ingresar número", Nhasta que N>0M[i][j] =NsinorepetirLeer "Ingresar número", Nhasta que N<0

Ing. Nestor Huaracha Velasquez

Page 79: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 79 M[i][j] =NFin _ siFin _ paraFin _ paraFin Rellenar una matriz de la siguiente manera:

* 0 * 0 * 0 * 0 * 0 * * 0 * 0 * 0 *

* 0 * 0 * 0 0 * 0 * 0 * 0 * 0 0 * 0

* 0 * 0 * 0 * 0 * 0 * 0 * 0 * 0 *

* 0 * 0 * 0 0 * 0 * 0 * 0 * 0

* 0 * 0 * 0 * 0 * 0 *

* 0 * 0 * 0N=5

N=6

* 0 * 0 * 0 *

* 0 * 0 0 * 0

* 0 * 0 * 0 *

* 0 * 0

N=4 N=3Iniciochar Num[20][20];int n, i, j, C=0;repetirMostrar "Ingresar N:";Mostrar "N";hasta (N<=0 | | N>=20)para (i=0; i<=N-1; i++)para (j=0; j<=N-1; j++)si (C=0) entoncesNum[i][j]=’*’C=1;sinoNum[i][j]=’0’C=0;Fin _ siFin _ paraFin _ parapara (i=0; i<=N-1; i++)para (j=0; j<=N-1; j++)Mostrar "Num[i][j]Fin _ paraFin _ para

Fin

14.6. MODULARIDAD

DEFINICIÓN:Módulo: Un módulo que se supone que representa una función lógica es una secuencia léxicamente continúa de instrucciones que se encuentra limitado por elementos de fronteras y además se caracteriza por disponer de un nombre o identificadorMódulo: Es aquél que está constituido por una o varias instrucciones físicamente contiguas y lógicamente encadenadas, las cuales se pueden referenciar mediante un nombre y pueden ser llamadas desde diferentes puntos de un programa.Un módulo puede ser:

Un programa Una función Una subrutina (o procedimiento)

La modularidad se basa en la descomposición de un problema en una serie de sub problemas; dividiéndolo en módulos que resultan de segmentar el problema en funciones lógicas que son perfectamente diferenciadas. Esta división exige la presencia de un módulo denominado módulo de base o principal a objeto de que controle y se relacione con los demás.Es una técnica de programación que todavía se utiliza tanto para la construcción de algoritmos computacionales básicos así como apoyo al desarrollo de sistemas de gestión (en el diseño de diagramas modulares).La salida del módulo debe ser función de la entrada, pero no de ningún estado interno. En la creación de los módulos deben cumplirse tres aspectos básicos: descripción, rendimiento y diseño.En la descripción se definen las funciones y objetivos del programa. Para obtener el máximo rendimiento se ha de comprobar que el programa realice el proceso aprovechando al máximo todos los recursos de los que dispone. En cuanto al diseño, se debe comprobar la estructura que sigue el módulo, así como la estructura de los datos y la forma de comunicaciones entre los diversos y diferentes módulos.Conforme se extiende el tamaño de los algoritmos, se hace más difícil su revisión, actualización y/o corrección.Una política común para solventar este problema consiste en la modularización. Esto significa que el algoritmo se fragmenta en partes llamadas módulos. En realidad, es un método de diseño que tiende a dividir el

Ing. Nestor Huaracha Velasquez

Page 80: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 80 problema, de forma lógica, en partes perfectamente diferenciadas que pueden ser analizadas, programadas y puestas a punto independiente.

1. Objetivos: Descomponer el sistema en módulos:

- Los grupos deben maximizar el enlace y minimizar el acoplamiento. Determinar las relaciones entre módulos:

- Identificar y especificar las dependencias entre módulos.- Determinar la forma de comunicación entre módulos (variables llamadas a funciones, memoria compartida, paso de mensajes)

Especificar las interfaces de los módulos: - Facilita la prueba independiente entre los módulos.- Mejora la comunicación e integración del grupo

1. Características: Permite reducir la complejidad global del sistema descentralizado; ejm.

Divide y vencerás. Mejora la escalabilidad y la productividad (los módulos pueden

desarrollarse independientemente por varias personas)1. Principios para asegurar diseños modulares: Soporte de lenguaje para unidades modulares.

Los módulos deben corresponder a unidades sintácticas del lenguaje utilizado. Pocas interfaces:

Cada módulo debe comunicarse con tan pocos como sea posible. Interfaces pequeñas (Acoplamiento débil):

Si dos módulos se comunican, deben intercambiar la menor información posible..

Interfaces explícitas: Cuando dos módulos se comunican, debe estar claro en el texto de uno o de ambos.

Ocultación de la información: Toda la información sobre un módulo debe ser privada al módulo, a menos que se haya declarado específicamente como pública.Algunas ventajas de utilizar módulos son:

  Un programa modular es fácil de mantener y modificar.  Un programa modular es más fácil de escribir y depurar (ejecutar, probar y poner a

punto).  Un programa modular es más fácil de controlar. El desglose de un problema en

módulos permite encomendar los módulos más complejos a los programadores más experimentados y los más sencillos a los programadores nóveles.

  Posibilita el uso repetitivo de las rutinas en el mismo o en diferentes programas.Desventajas del uso de módulos:

  No se dispone de algoritmos formales de modularidad, por lo que a veces los programadores no tienen claras las ideas de los módulos.

  La programación modular requiere más memoria y tiempo de ejecución.

Segmento: El segmento a diferencia del módulo se caracteriza porque no dispone de un nombre o identificador

14. 7 METODOLOGÍA DESCENDENTE: (TOP – DOWN)Proceso mediante el cual un problema se descompone en una serie de niveles o pasos sucesivos de refinamiento (stipwise). La metodología descendente consiste en efectuar una relación entre las sucesivas etapas de estructuración, de modo que se relacionen unas con otras mediante entradas y salidas de información.Es decir se descompone un problema en etapas o estructuras jerárquicas, de modo que se puede considerar cada estructura desde dos puntos de vista;

¿Qué hace? Para ver el gráfico seleccione la opción ¨Bajar trabajo¨ del menú superior ¿Cómo lo hace? Para ver el gráfico seleccione la opción ¨Bajar trabajo¨ del menú superior El diseño descendente se puede ver: Para ver el gráfico seleccione la opción ¨Bajar trabajo¨ del menú superior

14.9. VARIABLES:

Clasificación:

Variable Local: Aquella que está declarada y definida dentro de un sub programa, en el sentido de que está dentro de ese sub programa y es distinta de las variables con el mismo nombre declaradas en cualquier parte del programa principal. El significado de una variable se confina al procedimiento en el que está declarada. Cuando otro sub programa utiliza el mismo nombre, se refiere a una posición diferente en memoria.

El uso de variables locales tiene muchas ventajas. En particular, hace a los sub programas independientes con la comunicación entre el programa principal y los sub programas manipulados estructuralmente a través de la lista de parámetros.

Una variable local a un sub programa, no tiene ningún significado en otros sub programas. Si un sub programa asigna un valor a una de sus variables locales, este valor no es accesible a otros programas, es decir, no pueden utilizar este valor.

Variable Global: Aquella que está declarada para el programa o algoritmo principal del que dependen todos los sub programas

Ing. Nestor Huaracha Velasquez

Page 81: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 81 Esta variable tiene la ventaja de compartir información de diferentes sub programas sin una correspondiente entrada en la lista de parámetros

14.10. PROCEDIMIENTOS:

Un procedimiento o sub rutina, es un sub programa que ejecuta un proceso específico. Ningún valor esta asociado con el nombre del procedimiento, por consiguiente no puede ocurrir en una expresión. Un procedimiento se llama escribiendo su nombre Ejm. SORT para indicar que un procedimiento denominado SORT se va a usar.Cuando se invoca el procedimiento los pasos que los define se ejecuta y a continuación se devuelve el control al programa que le llamó.

PROCEDIMIENTO VS FUNCIONLos procedimientos y funciones son sub programas, cuyo diseño y misión son similares, sin embargo existen unas diferencias esenciales entre ellos:

1. Un procedimiento es llamado desde el algoritmo o programa principal, mediante su nombre y una lista de parámetros actuales o bien con la instrucción llamar_a (call). Al llamar al procedimiento se detiene momentáneamente el programa que se está realizando y el control pasa al procedimiento llamado, después de que las acciones del procedimiento se ejecutan, se regresa a la acción inmediata siguiente a la que se llamó.

2. Las funciones devuelven un valor, los procedimientos pueden devolver 0, 1 ó n valores y en forma de lista de parámetros.

3. El procedimiento se declara igual que la función, pero su nombre no está asociado a ninguno de los resultados que obtiene.

14.11. FUNCIONES:

Las funciones son bloques de instrucciones que tienen por objeto el alcanzar un resultado que sustituirá a la función en el punto de invocación (las funciones devuelven un resultado). Cada función se evoca utilizando su nombre en una expresión con los argumentos actuales o reales encerrados entre paréntesis. Para hacer una referencia a una función se invoca mediante un nombre y en caso de existir, una lista de parámetros actuales necesarios (argumentos). Los argumentos deben coincidir en cantidad, tipo y orden con los de la función que fue definida. La función devuelve un valor único.Las funciones a que se hace referencia, se conocen como funciones de usuario puesto que son definidas por él mismo y permiten su uso en forma idéntica a las funciones estándares.

Para coordinar e iniciar el procesamiento, se utiliza un módulo principal que es colocado al final del algoritmo.Una llamada a la función implica los siguientes pasos:

1. A cada parámetro formal se le asigna el valor real de su correspondiente parámetro actual.

2. Se ejecuta el cuerpo de acciones de la función. 3. Se devuelve el valor de la función al nombre de la función y se retorna

al punto de llamada. Declaración de funcionesfunción nombre_función (par1, par2,par3,...) : tipo_del_resultadoInicioacción1acción2:nombre_función Resultado_ObtenidoFin Donde:par1,par2 ....               Lista de parámetros formales o argumentos.nombre_función        Nombre asociado de la función, que será un nombre de identificador válido. acción1, acción2,..      Instrucciones que constituyen la definición de las función, y que debe contener una acción sola de asignación que asigne un valor al nombre de la función. Ejemplo:Obtener el sexto carácter de un nombre y si dicho carácter no existe, se asumirá un asterisco como tal.Función SEXTO(n:string):carácterIniciosi  longitud(n) >= 6 entoncesSEXTO Subcadena(n,6,1)en caso contrarioSEXTO  ‘*’Fin Invocación a las funcionesUna función puede ser llamada sólo mediante referencia de la forma siguiente:nombre_función (lista de parámetros actuales)Donde:nombre_función Función que llama.Lista de param. actuales      Constantes, variables, expresiones, valores de funciones, nombres de funciones o procedimientos.Una llamada a la función implica los siguientes pasos:A cada parámetro formal se le asigna el valor real de su correspondiente parámetro actual (esta correspondencia se verá más tarde y se denomina llamada por valor).Se ejecuta el cuerpo de acciones de la función.Se devuelve el valor de la función y se retorna al punto de llamada.Ejercicio:* Calcular la potencia de un número.

Ing. Nestor Huaracha Velasquez

Page 82: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 82 Funcion POTENCIA(x,n :entero): enteroInicioY=1Desde  i = 1 hasta abs(n) hacer   y = y*xfin Desdesi n < 0 entonces    y =1/yFin siPOTENCIA = yFin

14.12. USO DE LOS PARÁMETROS: FORMALES – NORMALES O ARGUMENTOS

PASO DE PARAMETROSExisten diferentes métodos para el paso de parámetros a subprogramas, un mismo programa puede producir diferentes resultados bajo diferentes sistemas de paso de parámetros. Los parámetros se clasifican de la siguiente manera:1.  Entradas:     Las entradas proporcionan valores desde el programa que llama y que se utilizan dentro de un procedimiento. En los subprogramas función las entradas son los argumentos en el sentido tradicional.2. Salidas:    Las salidas producen los resultados del subprograma; de nuevo si se utiliza el caso una función,  mientras que con procedimientos pueden calcularse cero, una o varias salidas.3. Entradas/Salidas: Un solo parámetro se utiliza para mandar argumentos a un programa y para devolver resultados.Los métodos más empleados para realizar el paso de parámetros son:

Paso por valor (parámetro valor).Se utiliza en muchos lenguajes de programación (pascal, basic, modula-2, algol, etc), debido a su analogía con los argumentos de una función, donde los valores se proporcionan en el orden de cálculo de resultados.  Los parámetros se tratan como variables locales y los valores iniciales se proporcionan copiando los valores de los correspondientes argumentos.Los parámetros formales (locales a la función), reciben como valores iniciales los valores de los parámetros actuales y con ello se ejecutan las acciones descritas en el subprograma.La llamada por valor no devuelve información al programa que llama.

Paso por referencia o dirección  (parámetro variable).Se utiliza cuando se requiere que ciertos parámetros sirvan como parámetros de salida, es decir, devuelvan los resultados a la unidad o programas que llama.  La unidad que llama pasa a la unidad llamada la dirección del

parámetro actual (que está en el ámbito de la unidad llamante). Una referencia al correspondiente parámetro formal se trata como una referencia a la posición de memoria, cuya dirección se ha pasado. Entonces una variable pasada como parámetro real es compartida, es decir, se puede modificar directamente por el subprograma. Si el parámetro actual es una expresión, el subprograma recibe la dirección de la posición temporal que contiene el valor de la expresión.

14.13. ARQUITECTURA MODULAR:

La arquitectura es el elemento estable ante los cambios en el ciclo de vida de los módulos; la clave está en separar interfaces de implementaciones.La separación entre interfaces e implementación:

Aísla de los cambios. Sirve de mecanismo (compilable) de unión entre arquitectura e

implementación. El papel de la arquitectura es proporcionar información de diseño a los

desarrolladores, para que éstos puedan hacer cambios y correcciones a los módulos, sin romper la arquitectura.

En cada escala de un sistema modular, se puede definir una arquitectura y una implementación:

La implementación es la realización de los componentes modulares. La arquitectura es la abstracción que define las interfaces entre

componentes. PLANTEAR Y SOLUCIONAR EJERCICIOS APLICANDO MODULARIDAD:Para ver el gráfico seleccione la opción ¨Bajar trabajo¨ del menú superior RECURSIVIDAD:Puede definirse un programa en términos recursivos, como una serie de pasos básicos, o paso base (también conocido como condición de parada), y un paso recursivo, donde vuelve a llamarse al programa. En un computador, esta serie de pasos recursivos debe ser finita, terminando con un paso base. Es decir, a cada paso recursivo se reduce el número de pasos que hay que dar para terminar, llegando un momento en el que no se verifica la condición de paso a la recursividad. Ni el paso base ni el paso recursivo son necesariamente únicos.Por otra parte, la recursividad también puede ser indirecta, si tenemos un procedimiento P que llama a otro Q y éste a su vez llama a P. También en estos casos debe haber una condición de parada.Existen ciertas estructuras cuya definición es recursiva, tales como los árboles, y los algoritmos que utilizan árboles suelen ser en general recursivos.La funcion FACTORIAL de N expresada en términos recursivos sería: entero funcion factorial(E entero: n)iniciosi (n = 0) retornar 1sino

Ing. Nestor Huaracha Velasquez

Page 83: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 83 retornar (n * factorial(n-1) )fin_sifin_funcion

14.14 RECURSIVIDAD

El concepto de recursividad es muy importante en la programación funcional, y se puede definir " Como el proceso de resolver un problema reduciéndolo a uno ó más subproblemas que son idénticos en su estructura al problema original y más simple de resolver." Una vez que sea subdividido el problema original, se utilizará la misma técnica de descomposición para subdividir cada uno de estos subproblemas en otros que son menos complejos, hasta que los subproblemas llegan a ser tan simples que se pueden resolver sin realizar más subdivisiones, y la solución general del problema se obtiene juntando todos los componentes resueltos.Una función o procedimiento que se puede llamar a sí misma se llama recursivo. La recursividad es una herramienta muy potente en algunas aplicaciones, sobre todo de cálculo. La recursión puede ser utilizada como una alternativa a la repetición o estructura repetitiva.La razón de que existan lenguajes que admitan la recursividad se debe a la existencia de estructuras específicas tipo pilas (stack) para este tipo de procesos y memorias dinámicas.La recursividad es una manera elegante, intuitiva y concisa de plantear una solución, y es uno de los pilares de la programación funcional. Pero no quiere decir que sea un sistema eficiente, es decir, que el número de operaciones que hay que hacer sea inferior que si se utiliza otra forma de resolverlo, como seria mediante una estructura repetitiva. Al contrario la recursividad es cara y exige un mayor procesamiento.Ejemplo://Función Fibonacci recursivaFIB (X):Inicio_FibonacciSi (X = 0 ó X = 1) entoncesFIB = XSi noFIB = FIB (X-1) + FIB (X-2)Fin_siFin_Fibonacci//Función Fibonacci no recursivaFIB (X):Inicio_FibonacciSi (X = 0 ó X = 1) entoncesFIB = NSi noA = 0

B = 1Para (i = 2; i <= X; i++) C = A + BA = BB = CFin_paraFIB = CFin_siFin_Fibonacci

14.15. REGISTROS

A.- Arreglos de Registros:1._ Ingresar 10 fechas y mostrar cuantas pertenecen al mes de "Octubre".Iniciofecha = Registrodía: enteromes: enteroaño: enteroFin _ registrofechas[10]: fechai, C← 0: enteropara (i=1; i<=10; i++)Ingresar fechas[i].fecha.díaIngresar fechas[i].fecha.mesIngresar fechas[i].fecha.añoFin _ parapara (i=1; i<=10; i++)si (fechas[i].fecha.mes=10) entoncesC ← C+1Fin _ siFin _ parasi C=0 entoncesMostrar "Número de fechas:", CFin _ siFin.B.- Registros con Arreglos:Cliente

Código Nombre y ApellidoSaldos Mensuales

Total1 2 3 4 5 .....12

CA01      

CA02      

Ing. Nestor Huaracha Velasquez

Page 84: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 84

       

       

InicioCliente = RegistroCod[6]: caracterNom _ Ape[30]: caractersaldos[12]: realTotal: realFin _ Registroclientes[15]: clientei, j: enteroS ← 0: enteroPara (i=1; i<=5; i++)Ingresar clientes[i].cliente.codIngresar clientes[i].cliente.Nom _ ApeS ← 0Para (j=1; j<=12; j++)RepetirIngresar Clientes[i].cliente.saldos[j]Hasta (clientes[i].cliente.saldos[j]>=0)S ← S+ clientes[i].cliente.saldos[j]Fin _ paraclientes[i].cliente.total ← SFin _ paraFin

C.- Registros Anidados

Cod Apellido Nombre Dirección   Fecha-Nacim.

      calle número distrito D M A

InicioFecha = RegistroD: enteroM: enteroA: EnteroFin _ RegistroDir = RegistroCalle[15]: caracterNum: enteroDistrito[15]: caracter Fin _ RegistroPersona = RegistroCod: enteroApe[15]: caracter

Nom[15]: caracterDirección: dirFecha – Nac: fechaFin _ RegistroPersonas[20]: personai: enteropara (i=1; i<=20; i++)personas[i].persona.cod ← iIngresar personas[i].persona.ApeIngresar personas[i].persona.NomIngresar personas[i].persona.dirección.dir.calleIngresar personas[i].persona.dirección.dir.NumIngresar personas[i].persona.dirección.dir.distritoIngresar personas[i].persona.fecha – Nac.DIngresar personas[i].persona.fecha – Nac.MIngresar personas[i].persona.fecha – Nac.AFin _ paraFin

14.16. CONCLUSIONES

Pongo este material al alcance de todos aquellos que necesitan una guía o material de consulta o referencia.Mediante el desarrollo de este trabajo se ha logrado desarrollar y entender el curso de Estructura de Datos.Conocedores que su realización nos han permitido el aprendizaje en los diferentes temas y están contribuyendo al cambio de nuestra manera de vivir, con ello nuestra formación profesional.La conclusión a lo que se ha llegado con el desarrollo de este importante curso en nuestra carrera, es a poder estructurar un programa, lo que posteriormente nos facilitará el trabajo en los cursos venideros; utilizando para esto la lógica computacional y la estructuración; llegando a lograr comprender de esta manera que existen muchas soluciones a los problemas planteados tanto aplicados a ejemplos como a la vida real.

RECOMENDACIONES Recomendamos mediante el desarrollo de este trabajo a que los

alumnos que se forman para en la carrera de Ingeniería Informática y de Sistemas u otras afines, pongan el interés y empeño necesario en sus actividades académicas.

Hacemos una invocación a los Directivos y Docentes de esta nueva carrera profesional iniciada en esta parte del país para que se preocupen en atender las necesidades y exigencias que tiene para su total desarrollo.

Ing. Nestor Huaracha Velasquez

Page 85: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 85 Recomendamos de igual forma a los Directivos de la Central en la

ciudad de Chiclayo para que implemente el material bibliográfico sobre esta carrera, con textos actualizados y modernos.

14.17. EJEMPLOS, EJEMPLOS Y MAS EJEMPLOS

1.- Diseñar un algoritmo que permita crear un registro Agenda de direcciones cuyos registros constan de los siguientes campos:Nombre, Dirección, Ciudad, Teléfono, EdadLuego deberá permitirme ordenarlo en forma ascendente (método de burbuja) por medio de los nombres para posteriormente ingresar un nuevo registro, y ubique este en el lugar correspondiente, de acuerdo al orden en que le toque.INICIOAgenda = RegistroNombre [40] : CaracterDirección [50] : CaracterCiudad [30] : CaracterTeléfono : EnteroEdad : EnteroFin_registroAgendas[100] : AgendaAuxiliar[1] : Agendai,j,k,m : EnteroResp : BoleanResp = VerdaderoMientras (Resp =Verdadero) HacerPara (i=1 ; i<=100 ; i++ )Ingresar Agendas[i].Agenda.NombreIngresar Agendas[i].Agenda.DireccionIngresar Agendas[i].Agenda.CiudadIngresar Agendas[i].Agenda.TelefonoIngresar Agendas[i].Agenda.Edad Fin_ParaMientras (k Diferente de Null) HacerAgendas[i].Agenda.Nombrem = m + 1Fin_MientrasPara (i=1 ; i<m ; m++)Para (j=i+1 ; j<=m ; j++)Si (Agendas[i].Agenda.Nombre > Agendas[j].Agenda.Nombre) EntoncesAuxiliar[1].Agenda.Nombre = Agendas[i].Agenda.NombreAuxiliar[1].Agenda.Direccion = Agendas[i].Agenda.DireccionAuxiliar[1].Agenda.Ciudad = Agendas[i].Agenda.CiudadAuxiliar[1].Agenda.Telefono = Agendas[i].Agenda.Telefono

Auxiliar[1].Agenda.Edad = Agendas[i].Agenda.EdadAgendas[i].Agenda.Nombre = Agendas[j].Agenda.NombreAgendas[i].Agenda.Direccion = Agendas[j].Agenda.DireccionAgendas[i].Agenda.Ciudad = Agendas[j].Agenda.CiudadAgendas[i].Agenda.Telefono = Agendas[j].Agenda.TelefonoAgendas[i].Agenda.Edad = Agendas[j].Agenda.EdadAgendas[i].Agenda.Nombre = Auxiliar[1].Agenda.NombreAgendas[i].Agenda.Direccion = Auxiliar[1].Agenda.DireccionAgendas[i].Agenda.Ciudad = Auxiliar[1].Agenda.CiudadAgendas[i].Agenda.Telefono = Auxiliar[1].Agenda.TelefonoAgendas[i].Agenda.Edad = Auxiliar[1].Agenda.EdadFin_SiFin_ParaFin_ParaMensaje("Desea Ingresar otro Registro" Yes / No)Si (Yes) EntoncesResp = VerdaderoSinoResp = FalsoFin siFin_MientrasFIN2.- Un director de un colegio desea obtener de 20 alumnos los siguientes datos:

Dado la identificación del alumno se deberá obtener la máxima nota del alumno correspondiente y su respectivo nombre.

Nota media por curso (5 cursos) Nota media del colegio. Mayor nota promedio por alumno y si existen varios alumnos con la

misma nota deberá visualizarse cada uno de ellos. Cuantos alumnos aprobados y desaprobados exiten

INICIOAlumno = RegistroNombre [50] : CaracterNotaCur1 : RealNotaCur2 : RealNotaCur3 : RealNotaCur4 : RealNotaCur5 : RealFin_registroAlumnos [20] : Alumnoi, j, : EnteroxNotaMax, : ReaxTotalCur1, xTotalCur2, xTotalCur3, xTotalCur4, xTotalCur5 : RealxPromedio, xMayorProm, xMayorProm2 : RealxTotalColegio : RealxNombre, : Carácter

Ing. Nestor Huaracha Velasquez

Page 86: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 86 ‘Ingresar datos del alumnoPara (i = 1; i <= 20; i++) Ingresar Alumnos [i].Alumno.NombreIngresar Alumnos [i].Alumno.NotaCur1Ingresar Alumnos [i].Alumno.NotaCur2Ingresar Alumnos [i].Alumno.NotaCur3Ingresar Alumnos [i].Alumno.NotaCur4Ingresar Alumnos [i].Alumno.NotaCur5Fin_Para‘Identificar alumno y mostrar datosIngresar xNombrePara (i=1, i<=20, i++)Si Alumnos[i].Alumno. Nombre = xNombre Entonces xNotaMax = Alumnos[i].Alumno.NotaCur1Si xNotaMax < Alumnos[i].Alumno.NotaCur2 EntoncesxNotaMax = Alumnos[i].Alumno.NotaCur2Fin_SiSi xNotaMax < Alumnos[i].Alumno.NotaCur3 EntoncesxNotaMax = Alumnos[i].Alumno.NotaCur3Fin_SiSi xNotaMax < Alumnos[i].Alumno.NotaCur4 EntoncesxNotaMax = Alumnos[i].Alumno.NotaCur4Fin_SiSi xNotaMax < Alumnos[i].Alumno.NotaCur5 EntoncesxNotaMax = Alumnos[i].Alumno.NotaCur5Fin_SiMostrar xNotaMaxMostrar Alumnos[i].Alumno.NombreFin_SiFin_Para‘Nota media por cursoxTotalCur1=0xTotalCur2=0xTotalCur3=0xTotalCur4=0xTotalCur5=0Para (i = 1; i<=20, i++)xTotalCur1=xTotalCur1 + Alumnos[i].Alumno.NotaCur1xTotalCur2=xTotalCur2 + Alumnos[i].Alumno.NotaCur2xTotalCur3=xTotalCur3 + Alumnos[i].Alumno.NotaCur3xTotalCur4=xTotalCur4 + Alumnos[i].Alumno.NotaCur4xTotalCur5=xTotalCur5 + Alumnos[i].Alumno.NotaCur5Fin_ParaMostrar xTotalCur1/20Mostrar xTotalCur2/20Mostrar xTotalCur3/20Mostrar xTotalCur4/20

Mostrar xTotalCur5/20‘Nota media del ColegioxTotalColegio=0Para (i = 1;i<=20,i++)xTotalColegio=xTotalColegio + Alumnos[i].Alumno.NotaCur1xTotalColegio=xTotalColegio + Alumnos[i].Alumno.NotaCur2xTotalColegio=xTotalColegio + Alumnos[i].Alumno.NotaCur3xTotalColegio=xTotalColegio + Alumnos[i].Alumno.NotaCur4xTotalColegio=xTotalColegio + Alumnos[i].Alumno.NotaCur5Fin_ParaMostrar xTotalColegio/100‘Mayor nota promedio por alumnoxMayorProm = 0Para (i =1; i<=20, i++)xMayorProm2 = (Alumnos[i].Alumno.NotaCur1 + Alumnos[i].Alumno.NotaCur2 + Alumnos[i].Alumno.NotaCur3 + Alumnos[i].Alumno.NotaCur4 +Alumnos[i].Alumno.NotaCur5)/ 5Si xMayorProm<xMayorProm2 EntoncesxMayorProm = xMayorProm2Fin_SiFin_ParaPara (j = 1; j <= 20, j++)xMayorProm2 = (Alumnos[i].Alumno.NotaCur1 + Alumnos[i].Alumno.NotaCur2 + Alumnos[i].Alumno.NotaCur3 + Alumnos[i].Alumno.NotaCur4 +Alumnos[i].Alumno.NotaCur5)/ 5Si xMayorProm = xMayorProm2 EntoncesMostrar xMayorPromMostrar Alumnos[i].Alumno.NombreFin_SiFin_Para‘Total aprobados y desaprobados xTotalAprob = 0xTotalDesaprob = 0Para (i = 1; i <= 20; i++)xPromedio = (Alumnos[i].Alumno.NotaCur1 + Alumnos[i].Alumno.NotaCur2 + Alumnos[i].Alumno.NotaCur3 + Alumnos[i].Alumno.NotaCur4 +Alumnos[i].Alumno.NotaCur5) / 5Si xPromedio >= 10.5 EntoncesxTotalAprob = xTotalAprob + 1SinoxTotalDesaprob = xTotalDesaprob + 1Fin_SiFin_ParaMostrar xTotalAprobMostrar xTotalDesaprob

Ing. Nestor Huaracha Velasquez

Page 87: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 87 FIN3.- Diseñar un algoritmo que permita controlar para 5 libros los siguientes datos:Título, Autos, Editorial, Año de edición, Número de páginas.Luego se permitirá el ingreso de un año determinado y el algoritmo deberá mostrarme todos aquellos libros que pertenezcan a este año y cuyas páginas estén entre 600 y 1400 páginas.INICIOLibro = RegistroTitulo [30] : CaracterAutor [40] : CaracterEditorial [40] : CaracterAñoEdicion : EnteroNumPaginas : EnteroFin_RegistroLibros [5] = Libroi : EnteroxAnio : EnteroPara (i=1; i<=5; i++) Ingresar Libros[i].Libro.TituloIngresar Libros[i].Libro.AutorIngresar Libros[i].Libro.EditorialIngresar Libros[i].Libro.AñoEdicionIngresar Libros[i].Libro.NumPaginasFin_ParaIngresar xAnioPara (i=1; i<=5; i++) Si(Libros[i].Libro.AñoEdicion = xAnio) EntoncesSi (600 < Libros[i].Libro.NumPaginas <1400) EntoncesMostrar Libros[i].Libro.TituloMostrar Libros[i].Libro.AutorMostrar Libros[i].Libro.EditorialMostrar Libros[i].Libro.AñoEdicionMostrar Libros[i].Libro.NumeroPaginasFin_SiFin_SiFin_ParaFIN4.- Diseñar un algoritmo que me permita aceptar la forma en que los datos de un DNI (Documento Nacional de Identidad) están controlados. Los datos que un DNI tiene son:Número del DNI, Apellido paterno, apellido materno, nombres, fecha de nacimiento, sexo, estado civil, fecha de inscripción, fecha de emisión, fecha de caducidad, departamento, provincia, distrito, calle y número, grupo de votación y un campo lógico que determine si la persona desea donar órganos.INICIOFecha = Registro

Dia : EnteroMes : EnteroAño : EnteroFin_RegistroUbicación = RegistroDepartam[50] : CarácterProvincia[50] : CarácterDistrito[50] : CarácterCalle[50] : CarácterNumero : EnteroFin_RegistroPersona = RegistroNumero[8] : CaracterApePaterno[40] : CaracterApeMaterno[40] : CarácterNombres[40] : CarácterFechaNac : FechaSexo: BooleanEstadoCivil[10] : CarácterFechaInsc : FechaFechaEmis : FechaFechaCaduc : FechaDirección : UbicacionGrupoVotac[6] : CaracterDonacOrg : BooleanEdad : EnteroSexo : Boolean Fin_RegistroPersonas[100000] = PersonaI, xReg : EnteroxReg=0Hacer Mostrar "1. Ingresar datos"Mostrar "2. Mostrar datos"Mostrar "3. Salir"Mostrar "Ingrese opción : "HacerIngresar zOpcionHasta (xOpcion>=1 And xOpcion<=3)Según_sea xOpcion hacer1: InicioxReg=xReg+1Ingresar Personas[xReg].Persona.NumeroIngresar Personas[xReg].Persona.ApePaternoIngresar Personas[xReg].Persona.ApeMaternoIngresar Personas[xReg].Persona.NombresIngresa r Personas[xReg].Persona.FechaNac.Fecha.Dia

Ing. Nestor Huaracha Velasquez

Page 88: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 88 Ingresar Personas[xReg].Persona.FechaNac.Fecha.MesIngresar Personas[xReg].Persona.FechaNac.Fecha.AñoIngresar Personas[xReg].Persona.SexoIngresar Personas[xReg].Persona.EstadoCivilIngresar Personas[xReg].Persona.FechaInsc.Fecha.DiaIngresar Personas[xReg].Persona.FechaInsc.Fecha.MesIngresar Personas[xReg].Persona.FechaInsc.Fecha.AñoIngresar Personas[xReg].Persona.FechaEmis.Fecha.DiaIngresar Personas[xReg].Persona.FechaEmis.Fecha.MesIngresar Personas[xReg].Persona.FechaEmis.Fecha.AñoIngresar Personas[xReg].Persona.FechaCaduc.Fecha.DiaIngresar Personas[xReg].Persona.FechaCaduc.Fecha,MesIngresar Personas[xReg].Persona.FechaCaduc.Fecha,AñoIngresar Personas[xReg].Persona.Direccion.Ubicación.DepartamIngresar Personas[xReg].Persona.Direccion.Ubicación.ProvinciaIngresar Personas[xReg].Persona.Direccion.Ubicación.DistritoIngresar Personas[xReg].Persona.Direccion.Ubicación.CalleIngresar Personas[xReg].Persona.Direccion.Ubicación.NumeroIngresar Personas[xReg].Persona.DonacOrg Fin2: InicioPara ( i=1; i<=xReg; i++)Mostrar Personas[xReg].Persona.NumeroMostrar Personas[xReg].Persona.ApePaternoMostrar Personas[xReg].Persona.ApeMaternoMostrar Personas[xReg].Persona.NombresMostrar Personas[xReg].Persona.FechaNac.Fecha.DiaMostrar Personas[xReg].Persona.FechaNac.Fecha.MesMostrar Personas[xReg].Persona.FechaNac.Fecha.AñoMostrar Personas[xReg].Persona.SexoMostrar Personas[xReg].Persona.EstadoCivilMostrar Personas[xReg].Persona.FechaInsc.Fecha.DiaMostrar Personas[xReg].Persona.FechaInsc.Fecha.MesMostrar Personas[xReg].Persona.FechaInsc.Fecha.AñoMostrar Personas[xReg].Persona.FechaEmis.Fecha.DiaMostrar Personas[xReg].Persona.FechaEmis.Fecha.MesMostrar Personas[xReg].Persona.FechaEmis.Fecha.AñoMostrar Personas[xReg].Persona.FechaCaduc.Fecha.DiaMostrar Personas[xReg].Persona.FechaCaduc.Fecha,MesMostrar Personas[xReg].Persona.FechaCaduc.Fecha,AñoMostrar Personas[xReg].Persona.Direccion.Ubicación.DepartamMostrar Personas[xReg].Persona.Direccion.Ubicación.ProvinciaMostrar Personas[xReg].Persona.Direccion.Ubicación.DistritoMostrar Personas[xReg].Persona.Direccion.Ubicación.CalleMostrar Personas[xReg].Persona.Direccion.Ubicación.NumeroMostrar Personas[xReg].Persona.DonacOrg Fin_Para

FinFin_Según_SeaHasta (xOpcion=3)FIN5.- Diseñar un algoritmo que imprima todos los nombres, apellidos y edades de todos los varones nacidos entre dos fechas ingresadas desde el teclado. Para lo cual deberá tener en cuenta el siguiente esquema:Persona.

Código Apellidos NombresFecha de nacimiento

Edad SexoDía Mes Año

INICIOFecha = RegistroDia : EnteroMes : EnteroAño : EnteroFin_RegistroPersona = RegistroCodigo [4] : CaracterApellidos [40] : CaracterNombres [40] : CaracterFechaNac : FechaEdad : EnteroSexo : Boolean Fin_RegistroPersonas [100] = Personai : EnteroPara (i=1; i<=5; i++) Ingresar Personas[i].Persona.CodigoIngresar Personas[i].Persona.ApellidosIngresar Personas[i].Persona.NombresIngresar Personas[i].Persona.FechaNac.Fecha.DiaIngresar Personas[i].Persona.FechaNac.Fecha.MesIngresar Personas[i].Persona.FechaNac.Fecha.AñoIngresar Personas[i].Persona.EdadIngresar Personas[i].Persona.SexoFin_ParaIngresar xDiaIniIngresar xMesIniIngresar xAñoIniIngresar xDiaFinIngresar xMesFinIngresar xAñoFinPara (i=1; i<=5; i++) Si (xAñoIni >= Personas[i].Persona.FechaNac.Fecha.Año <= xAñoFin EntoncesSi (xMesIni >= Personas[i].Persona.FechaNac.Fecha.Mes <= xMesFin Entonces

Ing. Nestor Huaracha Velasquez

Page 89: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 89 Si (xDiaIni >= Personas[i].Persona.FechaNac.Fecha.Dia <= xDiaFinSi Ingresar Personas[i].Persona.Sexo= Verdadero EntoncesMostrar Personas[i].Persona.NombresMostrar Personas[i].Persona.ApellidosMostrar Personas[i].Persona.EdadFin_SiFin_SiFin_SiFin_Si Fin_Para6.- Ingresar y mostrar los datos del siguiente esquema:Alumno:

Código NombresApoderado

N° Doc Apellidos Nombres Vinculo Fam.

INICIOApoderado = RegistroNumDoc[8] : CarácterApeApod[50] : CarácterNomApod[50] : CarácterVinculoFam[50] : CarácterFin_RegistroAlumno = RegistroCodigo[5] : CarácterApeAlum[50] : CaracterNomAlum[50] : CaracterApod : ApoderadoFin_RegistroAlumnos[100] = AlumnoI, xReg : EnteroxReg=0Hacer Mostrar "1. Ingresar datos"Mostrar "2. Mostrar datos"Mostrar "3. Salir"Mostrar "Ingrese opción : "HacerIngresar zOpcionHasta (xOpcion>=1 And xOpcion<=3)Según_sea xOpcion hacer1: InicioxReg=xReg+1Ingresar Personas[xReg].Persona.NumeroIngresar Personas[xReg].Persona.ApePaternoIngresar Personas[xReg].Persona.ApeMaternoIngresar Personas[xReg].Persona.Nombres

Ingresa r Personas[xReg].Persona.FechaNac.Fecha.DiaIngresar Personas[xReg].Persona.FechaNac.Fecha.MesIngresar Personas[xReg].Persona.FechaNac.Fecha.AñoIngresar Personas[xReg].Persona.SexoIngresar Personas[xReg].Persona.EstadoCivilIngresar Personas[xReg].Persona.FechaInsc.Fecha.DiaIngresar Personas[xReg].Persona.FechaInsc.Fecha.MesIngresar Personas[xReg].Persona.FechaInsc.Fecha.AñoIngresar Personas[xReg].Persona.FechaEmis.Fecha.DiaIngresar Personas[xReg].Persona.FechaEmis.Fecha.MesIngresar Personas[xReg].Persona.FechaEmis.Fecha.AñoIngresar Personas[xReg].Persona.FechaCaduc.Fecha.DiaIngresar Personas[xReg].Persona.FechaCaduc.Fecha,MesIngresar Personas[xReg].Persona.FechaCaduc.Fecha,AñoIngresar Personas[xReg].Persona.Direccion.Ubicación.DepartamIngresar Personas[xReg].Persona.Direccion.Ubicación.ProvinciaIngresar Personas[xReg].Persona.Direccion.Ubicación.DistritoIngresar Personas[xReg].Persona.Direccion.Ubicación.CalleIngresar Personas[xReg].Persona.Direccion.Ubicación.NumeroIngresar Personas[xReg].Persona.DonacOrg Fin2: InicioPara ( i=1; i<=xReg; i++)Mostrar Personas[xReg].Persona.NumeroMostrar Personas[xReg].Persona.ApePaternoMostrar Personas[xReg].Persona.ApeMaternoMostrar Personas[xReg].Persona.NombresMostrar Personas[xReg].Persona.FechaNac.Fecha.DiaMostrar Personas[xReg].Persona.FechaNac.Fecha.MesMostrar Personas[xReg].Persona.FechaNac.Fecha.AñoMostrar Personas[xReg].Persona.SexoMostrar Personas[xReg].Persona.EstadoCivilMostrar Personas[xReg].Persona.FechaInsc.Fecha.DiaMostrar Personas[xReg].Persona.FechaInsc.Fecha.MesMostrar Personas[xReg].Persona.FechaInsc.Fecha.AñoMostrar Personas[xReg].Persona.FechaEmis.Fecha.DiaMostrar Personas[xReg].Persona.FechaEmis.Fecha.MesMostrar Personas[xReg].Persona.FechaEmis.Fecha.AñoMostrar Personas[xReg].Persona.FechaCaduc.Fecha.DiaMostrar Personas[xReg].Persona.FechaCaduc.Fecha,MesMostrar Personas[xReg].Persona.FechaCaduc.Fecha,AñoMostrar Personas[xReg].Persona.Direccion.Ubicación.DepartamMostrar Personas[xReg].Persona.Direccion.Ubicación.ProvinciaMostrar Personas[xReg].Persona.Direccion.Ubicación.DistritoMostrar Personas[xReg].Persona.Direccion.Ubicación.CalleMostrar Personas[xReg].Persona.Direccion.Ubicación.NumeroMostrar Personas[xReg].Persona.DonacOrg

Ing. Nestor Huaracha Velasquez

Page 90: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 90 Fin_ParaFinFin_Según_SeaHasta (xOpcion=3)FIN7.- Una empresa desea conocer de sus trabajadores lo siguiente:código, apellidos, nombres, área y departamento en el que labora, cargo que ocupa, condición del trabajador (activo, jubilado, otra condición), fecha que ingreso a laborar, n° de documento de identidad, grupo sanguíneo, dirección y número de carga familiar con la que el trabajador cuenta.INICIOFecha = RegistroDia : EnteroMes : EnteroAño : EnteroFin_RegistroTrabajador = RegistroCodigo [5] : CarácterApeTrabaj[50] : CaracterNomTrabaj[50] : CaracterArea[50] : CaracterDepartamento[50] : CaracterCargo[50] : CarácterCondicTrabaj[50] : CaracterFechaIng : FechaDocumIdent[8] : CarácterGrupoSang[8] : CarácterDireccion[8] : CarácterNumCargaFam[8] : CarácterFin_RegistroTrabakadpres[100] = TrabajadorI, xReg : EnteroxReg=0Hacer Mostrar "1. Ingresar datos del trabajador"Mostrar "2. Mostrar datos del trabajador"Mostrar "3. Salir"Mostrar "Ingrese opción : "HacerIngresar zOpcionHasta (xOpcion>=1 And xOpcion<=3)Según_sea xOpcion hacer1: InicioxReg=xReg+1Ingresar Trabajadores [xReg]. Trabajador.CodigoIngresar Trabajadores[xReg].Trabajador.ApeTrabajIngresar Trabajadores[xReg].Trabajador.NomTrabaj

Ingresa r Trabajadores[xReg]. Trabajador.AreaIngresar Trabajadores[xReg].Trabajador.DepartamentoIngresar Trabajadores[xReg].Trabajador.CargoIngresar Trabajadores[xReg].Trabajador.CondicTrabajIngresar Trabajadores[xReg].Trabajador.Fecha.FechaIngIngresar Trabajadores[xReg].Trabajador.DocumIdentIngresar Trabajadores[xReg].Trabajador.CondicTrabajIngresar Trabajadores[xReg].Trabajador.GruopSangIngresar Trabajadores[xReg].Trabajador.DireccionIngresar Trabajadores[xReg].Trabajador.NumCargaFamFin2: InicioPara ( i=1; i<=xReg; i++)Mostrar Trabajadores [xReg]. Trabajador.CodigoMostrar Trabajadores[xReg].Trabajador.ApeTrabajMostrar Trabajadores[xReg].Trabajador.NomTrabajMostrar Trabajadores[xReg]. Trabajador.AreaMostrar Trabajadores[xReg].Trabajador.DepartamentoMostrar Trabajadores[xReg].Trabajador.CargoMostrar Trabajadores[xReg].Trabajador.CondicTrabajMostrar Trabajadores[xReg].Trabajador.Fecha.FechaIngMostrar Trabajadores[xReg].Trabajador.DocumIdentMostrar Trabajadores[xReg].Trabajador.CondicTrabajMostrar Trabajadores[xReg].Trabajador.GruopSangMostrar Trabajadores[xReg].Trabajador.DireccionMostrar Trabajadores[xReg].Trabajador.NumCargaFamFin_ParaFinFin_Según_SeaHasta (xOpcion=3)FIN8.- Solucionar el siguiente esquema de una boleta de venta.Boleta

Número Cliente DirecciónFecha

TotalDía Mes Año

 Detalle

Número Cantidad Detalle P. Unitario Total

INICIOFecha = RegistroDia : EnteroMes : EnteroAño : EnteroFin_RegistroBoleta = Registro

Ing. Nestor Huaracha Velasquez

Page 91: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 91 Num[5] : CarácterCliente[50] : CaracterDireccion[50] : CaracterFechaBol : FechaTotalBol : RealFin_RegistroDetalle = RegistroNum[5] : CarácterCantidad[50] : CaracterDetalle[50] : CaracterPrecioUni : RealTotalDeta : RealFin_RegistroBoletas[20] = BoletaDetalles[160] = Detallei, xRegD, xCant : EnteroxPrecioUni, xTotalBoleta : RealxDatoOk : BooleanxRpta : CaracterxRegD=0Hacer Mostrar "1. Ingresar boletas"Mostrar "2. Mostrar boletas"Mostrar "3. Salir"Mostrar "Ingrese opción : "Hacer Ingresar zOpcionHasta (xOpcion>=1 And xOpcion<=3)Según_sea xOpcion hacer1: InicioPara ( i=1; i<=20; i++)

Ingresar Boletas[i].Boleta.CodigoIngresar Boletas[i].Boleta.Num

Ingresar Boletas[i].Boleta.ClienteIngresa r Boletas[i].Boleta.DirecciónxDatoOk=FalseMientras xDatoOk=False HacerIngresar Boletas[i].Boleta.Fechabol.Fecha.DiaSi Boletas[i].Boleta.Fechabol.Fecha.Dia =Dato Numerico Entonces

Si (1<=Boletas[i].Boleta.Fechabol.Fecha.Dia<=31 EntoncexDatoOk=TrueFin_SiFin_Si

Fin_MientrasxDatoOk=FalseMientras xDatoOk=False HacerIngresar Boletas[i].Boleta.Fechabol.Fecha.MesSi Boletas[i].Boleta.Fechabol.Fecha.Mes = Dato Numerico EntonceSi (1<=Boletas[i].Boleta.Fechabol.Fecha.Mes<=12) EntoncesxDatoOk=TrueFin_SiFin_SiFin_MientrasxDatoOk=FalseMientras xDatoOk=False Hacer

Ingresar Boletas[i].Boleta.Fechabol.Fecha.AñoSi Boletas[i].Boleta.Fechabol.Fecha.Año =Dato Numerico Entonce

Si (0<=Boletas[i].Boleta.Fechabol.Fecha.Año<=9999) EntoncesxDatoOk=TrueFin_SiFin_Si

xRpta=SixCont=1xTotalBoleta=0

Mientras xRpta=Si And xCont<=8 hacerxNumDeta=xNumDeta + 1

ssssdsa

Ing. Nestor Huaracha Velasquez

Page 92: Curso Nestor Algoritmos y Estructura de Datos

. ALGORITMOS Y ESTRUCTURA DE DATOS Pag. 92 Ingresar Detalles[xRegD].Detalle.Num=Boletas[i].Boleta.NumIngresar Detalles[xRegD].Detalle.CantidadxCantidad= Detalles[xRegD].Detalle.CantidadIngresar Detalles[xRegD].Detalle.DetalleIngresar Detalles[xRegD].Detalle.PrecioUnixPrecioUni= Detalles[xRegD].Detalle.PrecioUniDetalles[xRegD].Detalle.TotalDeta=xCantidad * xPrecioUnixTotalBoleta = xTotalBoleta + (xCantidad * xPrecioUni)Mostrar "Ingresar Nuevo detalle? (Si/No):"Ingresar xRptaFin_MientrasBoletas[i].Boleta.TotalBol=xTotalBoletaFin_Para‘***Realizar el ordenamiento por metodo burbuja‘***Fin2: InicioPara ( i=1; i<=20; i++)Mostrar Boletas[i].Boleta.CodigoMostrar Boletas[i].Boleta.NumMostrar Boletas[i].Boleta.ClienteMostrar Boletas[i].Boleta.DireccionMostrar Boletas[i].Boleta.Fechabol.Fecha.DiaMostrar Boletas[i].Boleta.Fechabol.Fecha.MesMostrar Boletas[i].Boleta.Fechabol.Fecha.AñoMostrar Boletas[i].Boleta.totalBolPara (j=1; j<=160; j++)Si Detalles[j].Num=Boletas.[i].Boleta.Num EntoncesMostrar Detalles[j].Detalle.NumMostrar Detalles[j].Detalle.CantidadMostrar Detalles[j].Detalle.DetalleMostrar Detalles[j].Detalle.PrecioUniMostrar Detalles[j].Detalles.TotalDetaFin_SiFin_ParaFin_ParaFinFin_Según_SeaHasta (xOpcion=3)FIN

Ing. Nestor Huaracha Velasquez