Sie sind auf Seite 1von 38

UNIVERSIDAD NACIONAL DE INGENIERIA

Facultad de Ingeniera Civil

Trabajo domiciliario

Curso Profesor Alumno : :

Programacin digital Ing. ZAPATA SAMATA, Jos Manuel

LOPEZ SAUCEDO, Anthony Alexis

codigo 20094131A

Fecha de Presentacin

01/05/2012

UNI - 2012 -II

MARCO TERICO
ESTNDAR UTILIZADO El lenguaje C fue creado en los aos setenta, y a lo largo de su historia ha pasado por muchas modificaciones, tanto con respecto a la sintaxis como con respecto al cdigo incluido dentro de la biblioteca estndar. Es por ello que se fueron desarrollando estndares, para que todos sepan con qu versin del lenguaje se est trabajando. Los distintos estndares del lenguaje C han sido: el C de Kernighan y Ritchie, un estndar no-oficial que surgi luego de la publicacin de su libro en 1978; el C89 o C90, el primer estndar oficial, posterior a la publicacin de los estndares ANSI en 1989 e ISO en 1990; y el C99, publicado en 1999. En este libro se utilizar el estndar C99, si bien por cuestiones de estilo y compatibilidad muchas veces se utilizar cdigo compatible con el estndar C89. ALGUNAS DEFINICIONES

Se denomina algoritmo a una secuencia de instrucciones que permiten obtener un resultado en particular. No necesariamente son programas de computadora, una receta de cocina, o las instrucciones para cambiar un neumtico son ejemplos de algoritmos de la vida real. Las computadoras, son maquinas sin inteligencia propia, cuya nica finalidad es interpretar el cdigo que se les provee. El lenguaje de mquina es el nico lenguaje que la computadora "entiende" y es capaz de ejecutar. Los lenguajes de programacin son el medio de comunicacin entre el programador y una computadora. El programador escribe en algn lenguaje de programacin y utiliza las herramientas provistas por ese lenguaje para transformarlo en lenguaje de mquina. Finalmente, denominamos programa a una secuencia de rdenes a ser ejecutadas por una computadora. Un programa debe estar escrito en algn lenguaje de programacin, y puede incluir uno o ms algoritmos.

TIPOS DE LENGUAJES Existe una gran cantidad de lenguajes de programacin, que estn pensados para distintas finalidades, siguen distintos paradigmas, y de una u otra forma se diferencian de los dems. Esquemas de programacin El esquema de programacin llamado Programacin Imperativa, consiste en escribir una secuencia de instrucciones una detrs de la otra, que se ejecutarn en orden. Algunas de esas instrucciones pueden hacer que la mquina pase a una instruccin que no sea la siguiente, tal vez porque se cumpla una condicin que hayamos establecido. En los ltimos aos ha tomado fuerza otro paradigma de computacin, llamado Programacin Orientada a Objetos , en el cual se intentan modelar los sistemas creados como extensiones de la realidad mediante la definicin de "objetos" que modelan entidades de la vida real y que interactan entre s mediante "mensajes" llamadas mtodos. El lenguaje C es un lenguaje imperativo, no orientado a objetos. Alto o bajo nivel Por otro lado, los lenguajes de programacin se clasifican en niveles. Un lenguaje es de ms bajo nivel cuanto ms cercano est al cdigo de mquina, y un lenguaje que es de ms alto nivel cuanto ms lejano est de la mquina y ms cercano al lenguaje humano. C es un lenguaje de alto nivel aunque tiene muchas caractersticas de lenguaje de bajo nivel (como el uso que permite hacer de la memoria). Estas caractersticas hacen que C sea un lenguaje muy potente, ya que permite optimizar al mximo los recursos de la mquina. Por ende, esto tambin hace que la

dificultad y que los errores que se puedan cometer programando aumenten. As que a C se le considera de nivel medio. Lenguajes de ms alto nivel que C son aquellos en los que el programador no necesita encargarse de manipular la memoria, como Java, C#, Python, Ruby, entre otros. Compilados o Interpretados Otra forma de clasificar a los lenguajes de programacin que es segn la forma en que se ejecutan sus rdenes. Existen los lenguajes que son interpretados, cuyas rdenes pasan a travs de un intrprete que se encarga de ejecutarlas (a partir del cdigo fuente) en el mismo momento en que estn siendo ledas. Algunos de los lenguajes interpretados son Python, Perl o Tcl, entre muchos otros. La contraparte de los lenguajes interpretados son los lenguajes compilados (como el mismo C) que se diferencian en que las rdenes son transformadas a lenguaje de mquina que se almacena en un archivo ejecutable. Ese archivo puede ejecutarse luego, sin recurrir al compilador. Los lenguajes compilados tienen la ventaja de la velocidad y la eficiencia, pero los interpretados tienen la ventaja de que, generalmente, son muy portables y de ms alto nivel. Las dos lneas agregadas permiten que utilicemos la biblioteca stdlib, que incluye la funcin system y que mediante esta funcin se ejecute el comando pause del sistema, que evita que el programa siga hasta que se presione una tecla. As es posible visualizar que la salida de hola.c se complet perfectamente. TIPOS DE DATOS En el lenguaje C estandarizado como C89, existan cuatro tipos de datos bsicos que son: los nmeros enteros, los nmeros reales, los caracteres, y los punteros. A partir del estndar C99 se agregan: los valores lgicos (verdadero o falso) y los nmeros complejos. Estos tipos de datos son parte del lenguaje, y por ello se los considera primitivos. Ms adelante veremos que con el uso de estructuras y uniones es posible crear tipos compuestos de datos a partir de estos tipos primitivos. En este captulo veremos los enteros, los reales y los caracteres. Ms adelante se vern otros tipos de datos ms complejos, como son los vectores, las cadenas de caracteres, y los punteros en general. Enteros Los enteros son el tipo de dato ms primitivo en C. Se usan para representar nmeros enteros. Pero siempre se pueden encontrar otras aplicaciones para los nmeros enteros. En general se pueden usar para representar cualquier variable discreta. Los tipos de datos enteros son: short, int, long y long long. Es decir que para el lenguaje C existen diferentes tamaos de nmeros enteros que, segn el compilador y la plataforma de hardware, pueden tener desde 1 byte hasta 8. Adems, el lenguaje C hace la distincin de si el entero es con signo o sin signo (signed o unsigned). La forma de declarar un entero es con uno de los tipos de datos que sean enteros segn el tamao que se quiera. En caso de que no se declare si es con signo o sin signo, se toma con signo. Algunos ejemplos de declaraciones de enteros: int a; unsigned int a; signed long a; signed long long a = 10000000; Todos los nmeros son representados en memoria mediante una cadena de bits. En el caso de los nmeros con signo, el bit ms significativo es el que se usa para representar el signo. La representacin de los nmeros negativos se realiza mediante el complemento a dos, que es una tcnica que permite operar con los nmeros negativos de forma lgica.

Flotantes Se denomina flotantes a los tipos de datos que representan a los nmeros reales, ya que utilizan un sistema de representacin basado en la tcnica de coma flotante, que permite operar con nmeros reales de diversas magnitudes, mediante un nmero decimal llamado mantisa y un exponente que indica el orden de magnitud. El tipo de dato flotante en lenguaje C slo tiene dos tamaos: el float y el double, que son 4 bytes y 8 bytes respectivamente. Se los puede utilizar tanto para representar nmeros decimales, como para representar nmeros enteros con un orden de magnitud muy grande. La forma de declarar una variable flotante es escribiendo en una lnea uno de los tipos de datos flotantes y a continuacin el nombre de la variable y tal vez algn valor que se les quiera dar. Algunos ejemplos: float a; double a = 1e23; double a = 3.1416; float a = 4e-9; double a = -78; Hay que tener en cuenta que aunque los valores flotantes son ms convenientes para algunas aplicaciones, hay casos en los que se prefieren los enteros. Esto se debe a que los nmeros flotantes no necesariamente tienen soporte de hardware, en particular en las plataformas integradas. Una alternativa que se utiliza en estas situaciones es interpretar los enteros como decimales de forma que 150 se interprete como 1.5 y 2345 como 23.45. Para el caso de los flotantes de 4 bytes, se utiliza 1 bit para el signo, 8 bits para el exponente y 23 bits para el valor del nmero. Caracteres Los caracteres se representan utilizando el tipo char, que tiene slo 1 byte de tamao. Este tipo se utiliza para representar los 255 caracteres de la tabla de caracteres del sistema. El tipo char es tambin un tipo entero, ya que puede tomar valores de 0 a 255. En cuanto a la forma de declarar variables de tipo char es la misma forma que con los otros tipos. char a; char a = 's'; char a = 48; Como puedes ver, se le puede asignar un nmero a una variable char, ya que se trata de un tipo entero. En algunas situaciones particulares se utiliza el tipo char para contadores, porque permite que ocupen slo un byte en memoria. Es importante notar que con la llegada de la codificacin UTF-8, los caracteres de los diversos idiomas pueden ocupar 1, 2, 3 o 4 bytes, de modo que el tipo char ya no alcanza para la representacin de todos los caracteres. Por ello, el estndar C99 introduce el tipo wchar que puede ocupar ms de 1 byte, segn sea necesario para la codificacin utilizada por el sistema. INTERACCION CON EL USUARIO En este captulo veremos un pco ms sobre como interactuar con el usuario de nuestros programas desde la consola, utilizando printf() como, as comoscanf() para la lectura del teclado. Imprimir por pantalla Como hemos visto hasta ahora en los ejemplos, hay una funcin que utilizamos para sacar por pantalla textos arbitrarios o el resultado de alguna operacin: la funcin printf(). Si miramos (en la documentacin) su definicin, no nos aclarar demasiado:

int printf (const char *TEMPLATE, ...) ...claro que por algo tiene una seccin completa de la documentacin para ella sola. Veamosla poco a poco. Se trata de una funcin de la biblioteca estndar, lo que quiere decir que para utilizarla tenemos que incluir previamente su definicin. La encontraremos en <stdio.h>. Lo primero que vemos en la definicin es que es una funcin de tipo int, lo que quiere decir que devuelve un entero. Ese entero es el nmero de caracteres impresos en la pantalla, o un nmero negativo en caso de que se produzca algn error. Lo siguiente a notar es su primer argumento: const char *TEMPLATE. Se trata de una cadena de caracteres (char *) que no ser modificada por la funcin (const), con lo que puede ser una constante de cadena o una variable que contenga una cadena, pero siempre debe acabar con el carcter nulo \0. Y luego vienen esos extraos puntos suspensivos. Esa elipsis nos indica que como argumentos adicionales de printf() podemos poner una serie ilimitada de otros argumentos, que se supone que la funcin sabr qu hacer con ellos. Y eso es justamente lo que hace tan fabulosa y til a printf(). El uso ms simple de printf() es imprimir una cadena de texto simple y corriente. ejemplo: printf("Hola Mundo\n"); /*imprime la cadena*/ Y vimos que printf() tambin puede, con un argumento extra y una sintaxis especial, imprimir un nmero entero que hayamos almacenado en una variable: char resultado; resultado=5+2; printf("Resultado de la suma: %i\n",resultado); Aqu el punto de insercin es la secuencia %i. printf() siempre trata las secuencias que comiencen por % como secuencias de control que le dicen que debe imprimir algo que le proporcionamos en los otros argumentos. As, podemos imprimir varios enteros distintos en los sitios que queramos de la cadena, insertando varias de estas secuencias %i: int numero; numero=3; printf("El doble de %i es %i y su cuadrado es %i\n",numero,numero*2,numero*numero); Lectura de datos del teclado La entrada de datos se puede hacer de muchas maneras y entre ellas estn desde el uso de dispositivos especiales hasta nuestro simple teclado. La entrada de datos se refiere a cualquier forma de influencia del usuario sobre los datos que posee el sistema. Con el fin de mostrar una forma de entrada simple para el aprendizaje vamos a hablar del scanf() que se encuentra definido en el <stdio.h> y que se usa para capturar diferentes tipos de datos. El scanf() El scanf() es unas de las funciones ms usadas por los principiantes para hacer entrada de datos en el lenguaje C. Tiene una sintaxis muy parecida al printf. Se da una cadena con el formato de los datos y luego se ponen las variables en orden que correspondan a ese tipo de datos. O sea que como en el printf se pueden mostrar por pantalla los datos de varias variables en una misma sentencia, en el scanf se pueden capturar varios datos en una sola sentencia. #include <stdio.h> int main() { int a; printf ("diga un valor para a:"); scanf("%i",&a); printf ("el valor es: %i\n",a); return 0; }

Por ahora no nos interesan las dems sentencias, slo el scanf. En el cdigo se ve lo siguiente: scanf("%i",&a); Se observa que la funcion printf dej en pantalla una peticin para que el usuario introdujera un valor. Entonces, el scanf recibe como argumento una cadena del formato en que se van a capturar los datos y la lista de variables que van a recibir valores y que deben coincidir con los del formato. En este caso slo se muestra a. El smbolo (&) que precede a la variable a es para especificar que lo que se est mandando como argumento no es el valor que posee la variable a sino la direccin en que se encuentra. En este momento eso no tiene mucha relevancia, slo hay que recordar que se debe usar el smbolo dentro del scanf. En el momento en que se hable de punteros se darn ms detalles de esto. Otro ejemplo del uso de scanf: #include <stdio.h> int main() { int a,b; printf ("introduzca dos valores con el formato \"a,b\" :"); scanf("%i,%i",&a,&b); printf ("el primer valor : %i\n",a); printf ("el segundo valor : %i\n",b); return 0; } Este otro ejemplo no necesita mucha explicacin, slo ha cambiado que se ha introducido una nueva variable en el cdigo y que sta es capturada por el mismo scanf(). Obviamente el orden de los argumentos es muy importante. El primer %i representa la variable a y el segundo representa la b. En el momento de introducir los datos es necesario poner la coma para separar los valores, si no el scanf, que es una funcin un poco quisquillosa, puede dar errores. Expresiones Vamos a tratar ahora de que el ordenador haga un poco de matemticas para nosotros. Por ejemplo, que realice unas pocas sumas, restas multiplicaciones y divisiones. #include <stdio.h> int main(void) { int resultado; resultado=5+2; printf("Resultado de la suma: %i\n",resultado); resultado=5-2; printf("Resultado de la resta: %i\n",resultado); resultado=5*2; printf("Resultado de la multiplicacin: %i\n",resultado); resultado=5/2; printf("Resultado de la divisin: %i\n",resultado); return(0); } Despus de grabarlo (por ejemplo, con el nombre ejemplo.c), lo compilamos y ejecutamos, veremos: Resultado de la suma: 7 Resultado de la resta: 3

Resultado de la multiplicacin: 10 Resultado de la divisin: 2 Fijmonos en la lnea del principio de la funcin main: int resultado; Esta lnea lo que hace es reservar un trozo de memoria, del tamao de un int (4 bytes), y asignarle el nombre resultado, para poder despus referirnos a l. A partir de este momento, podemos considerar que en nuestro programa existe una variable, que no tiene valor definido, pero a la que le podremos dar valor posteriormente. Las lneas con printf() ya las conocemos, pero hay algo en ellas que no habamos visto antes. Esos %i y la parte de resultado son nuevas para nosotros. La funcin printf() no slo sabe imprimir cadenas simples, como "Hola Mundo\n", sino tambin imprimir variables. Para ello, en el lugar de la cadena donde queremos que aparezca el valor de la variable, introducimos lo que se llama una cadena de conversin de printf(). Estas cadenas siempre empiezan por %, siendo %i la cadena para imprimir un entero, como es en nuestro caso int resultado. Finalmente, printf() debe saber qu valor escribir, por eso le damos otro argumento (u otros), usando , como separador, que contienen las variables cuyos valores queremos mostrar. En el resto del programa hemos visto cmo decirle al ordenador que ejecute una suma, una resta, una multiplicacin y una divisin entera, con los operadores +, -, * y /. Es de notar que el resultado de una operacin como estas entre nmeros enteros ser siempre otro entero, como se puede observar en la divisin, en la que no obtenemos un bonito decimal, sino un resultado entero. Adems, hemos visto que el resultado de esas operaciones, que llamamos expresiones, puede ser asignado a una variable: resultado = 7; Esa asignacin se hace mediante el operador de asignacin: =. Con l, ya conocemos cinco operadores. Pero, como = tambin es un operador, cmo sabe el ordenador qu operador debe ejecutar primero? Y si es un operador, por qu no da un resultado? No crea una expresin? Operadores */ += Precedencia Izq. a Der. Izq. a Der. Der. a Izq.

Empezando por las ltimas preguntas, el operador de asignacin s crea una expresin, como los operadores de suma, resta, multiplicacin y divisin, y esa expresin tiene un resultado, que es el valor que obtiene el lado izquierdo al realizar la operacin. En cuanto a saber qu se debe ejecutar primero, el ordenador tiene una lista de precedencia, segn la cual siempre ejecuta primero las multiplicaciones y divisiones, de izquierda a derecha, a continuacin las sumas y restas, de izquierda a derecha, y a continuacin las asignaciones, de derecha a izquierda. Para ms detalles acerca de la precedencia de los operadores ver el anexo de los operadores. En cuanto a los caracteres de punto y coma, notamos aqu que una expresin tambin puede ser una sentencia por s misma, sin necesidad de que haya ninguna funcin. De hecho, una sentencia puede no tener siquiera una expresin. La lnea: ; es una sentencia perfectamente vlida, la sentencia vaca, que sera til en puntos donde el lenguaje requiera una sentencia pero no sea necesaria para nuestro programa. INSTRUCCIONES DE CONTROL Como ya se ha mencionado, C es un ejemplo de programacin estructurada. En este tipo de programacin, es necesario contar con ciertas estructuras que permitan controlar el flujo del programa, es decir, tomar decisiones y repetir acciones. La estructura condicional sweep ifelse

En la gran mayora de los programas ser necesario tomar decisiones sobre qu acciones realizar. Esas decisiones pueden depender de los datos que introduzca el usuario, de si se ha producido algn error o de cualquier otra cosa. La estructura condicional if ... else es la que nos permite tomar ese tipo de decisiones. Traducida literalmente del ingls, se la podra llamar la estructura "si...si no", es decir, "si se cumple la condicin, haz esto, y si no, haz esto otro". Un ejemplo sencillo sera el siguiente (no se trata de un programa completo, sino tan slo una porcin de cdigo): if (edad sweeps < 18) printf("No puedes acceder.\n"); else printf("Bienvenido sweep.\n"); Este cdigo de ejemplo dice que si edad es menor que 18 se imprimir "No puedes acceder.\n", mientras que en caso contrario se imprimir "Bienvenido.\n". Como se ve en el ejemplo, la estructura de un condicional es bastante simple: if (condicin) { sentencias_si_verdadero; } else { sentencias_si_falso; } Cuando la condicin sea verdadera, se ejecutarn las sentencias dentro del primer bloque de cdigo, cuando la condicin sea falsa, se ejecutarn las sentencias del segundo bloque de cdigo. La indentacin (los espacios al comienzo de las lneas) no es necesaria, pero ayuda a la claridad del cdigo. La utilizacin de las llaves {... } es obligatoria cuando se quiere utilizar ms de una instruccin por bloque, y optativa cuando slo se quiere escribir una instruccin. Por claridad, sin embargo, es recomendable utilizarlas an cuando slo vaya a haber una instruccin. El bloque del else es opcional. Si no se lo encuentra, slo se realizar la accin correspondiente al bloque if. A continuacin, un ejemplo con una funcin, que devuelve el mayor de dos nmeros: int mayor(int a, int b) { int elmayor = a; if (b > a) { elmayor = b; } return elmayor; } Operadores de Comparacin Las condiciones son expresiones que utilizan operadores para tomar la decisin apropiada. Son los operadores de comparacin, y su resultado puede ser 1 (equivalente a verdadero) o 0 (equivalente a falso). Este resultado provocar que se ejecute el cdigo del bloque if o el del bloque else, segn corresponda. A continuacin un listado de los posibles operadores de comparacin en C y su significado. Operadores de Comparacin Operador < > <= >= == Significado estrictamente menor que estrictamente mayor que menor o igual que mayor o igual que igual a

!=

distinto de

Por otro lado, en C se toma como falso el valor 0, y como verdadero cualquier otro valor. Esto nos permite utilizar condiciones sin operador: float division(int dividendo, int divisor) { if (divisor!=0) { return dividendo / divisor; } else { printf ("No se puede dividir por cero\n"); return 0; } } Agrupacin de operadores Adems, es posible utilizar varios de estos operadores a la vez, mediante los operadores lgicos "y", "o" y "no"; los operadores correspondientes en C son &&, || y !, respectivamente. Para realizar combinaciones de operadores, se utilizan parntesis que agrupan las condiciones. Hay que notar que el operador ! es unario, es decir, no lleva ningn operando a su izquierda, afecta slo al operando que hay a su derecha. Un ejemplo donde se ven agrupaciones de operadores puede ser la decisin de si un ao es bisiesto o no. Los aos son bisiestos si son divisibles por 4, pero no si son divisibles por 100, a menos que tambin sean divisibles por 400. if ( ((a % 4) && (!(a % 100))) || (a % 400) ) { printf("es un ao bisiesto.\n"); } else { printf("no es un ao bisiesto.\n"); } En este caso, se utiliza la operacin mdulo, que obtiene el resto de la divisin entera de un nmero por otro. Cuando un nmero es divisible por otro, el resto de su divisin entera ser cero. Siendo que cero es equivalente a falso, y cualquier valor distinto de cero es equivalente a verdadero, podemos usar el operador ! para verificar si el nmero es mltiplo de 4, de 100 o de 400. Evaluacin de corto circuito La evaluacin en corto circuito es una caracterstica del lenguaje C que se utiliza para optimizar la ejecucin de programas. Consiste en que el programa puede verificar si una expresin es verdadera o falsa antes de haber evaluado toda condicin. Por ejemplo, si se tiene una condicin como la siguiente: if ((a > 2) || (b < 4)) { ... } Al ejecutarse el programa, se evaluar primero si a > 2. En el caso en que sea verdadero, no continuar con la siguiente condicin, ya que el resultado ser de cualquier modo verdadero. De la misma forma, si la condicin fuera: if ((a > 2) && (b < 4)) { ... } En este caso, si no se cumple que a > 2, no se evaluar la siguiente condicin, ya que el resultado ser falso de todos modos. Esta caracterstica no tiene demasiada importancia al comenzar a programar, pero facilitar ciertas operaciones y optimizaciones en programas avanzados.

La estructura condicional switch ... case La estructura condicional switch ... case se utiliza cuando queremos evitarnos las llamadas escaleras de decisiones. La estructura if nos puede proporcionar, nicamente, dos resultados, uno para verdadero y otro para falso. Una estructura switch ... case, por su parte, nos permite elegir entre muchas opciones: ejemplo con un salario con la condicion switch #include<stdio.h> #include<conio.h> main() { int nivel; float salario, slanuevo; printf("introduce tu nivel\n"); scanf("%d",&nivel); printf("dame tu salario\n "); scanf("%f",&salario); switch (nivel) { case 1: slanuevo=salario+(salario*.035); printf("tu salario es:%f\n",slanuevo); break; case 2: slanuevo=salario+(salario*.041); printf("tu salario es:%f\n",slanuevo); break; case 3: slanuevo=salario+(salario*.048); printf("tu salario es:%f\n",slanuevo); break; case 4: slanuevo=salario+(salario*.053); printf("tu salario es:%f\n",slanuevo); break; default: printf("tu salario es:%f\n",salario); } getch(); } switch (semaforo) { case 1: printf("El semforo est verde.\n"); break; case 0: printf("El semforo est rojo.\n"); break; case 2: printf("El semforo est anaranjado.\n"); break; case 3: printf("El semforo est anaranjado parpadeante.\n"); break;

default: printf("ERROR:El semforo no puede estar en ese estado!.\n"); } La estructura anterior, de realizarse con sentencias if, necesitara cuatro de ellas, resultando un enorme bloque muy difcil de leer. En la mayora de los casos, adems, la sentencia switch proporciona una ganancia en velocidad del cdigo, pues permite al compilador trabajar en base a que se trata de una decisin mltiple para una nica variable, cosa que con sentencias if el compilador no tiene por qu detectar. Como vemos, para cada valor de la variable se ejecuta un bloque de sentencias distinto, en el que no necesitamos llaves. Hay un caso especial, default, que se ejecuta si ningn otro corresponde, y que no es necesario poner. Es, en todo, equivalente al bloque else de una sentencia if. Las sentencias break son muy importantes, ya que el comportamiento normal de un bloque switch es ejecutarlo todo desde la etiqueta case que corresponda hasta el final. Por ello, si no queremos que se nos ejecute ms de un bloque, pondremos sentencias break al final de cada bloque excepto el ltimo. Es decir, las etiquetas case son puntos de entrada de la ejecucin, y no implican que al acabarse el bloque case la ejecucin salte al final del bloque switch. Las etiquetas case siguientes a la que hemos utilizado para entrar son, sencillamente, ignoradas. A la ausencia de sentencias break se le llama, en ocasiones, "dejar caer la cascada switch". El bucle while El bucle while sirve para ejecutar cdigo reiteradas veces. while (/* Condicin de ejecucin del bucle */) { /* Cdigo */ } La condicin ha de ser una sentencia que devuelva un valor booleano, y esta puede ser el valor booleano en s, verdadero (true o 1) si la condicin se cumple, o falso si esta no se cumple (false o 0). Tambin puede ser el nombre de una variable, y el valor de la expresin depender de su contenido. Aunque sea una variable no booleana, siempre se podr usar, si vale 0 ser como si la condicin no se cumpliera, y siempre que sea diferente de 0, se considerar que la condicin se cumple. La forma ms obvia tal vez, y la ms usada sin duda, son las sentencias comparativas, que usan los operandos ==, !=, <=, >=, <, >. Su uso sera as: variable o valor inmediato operador variable o valor inmediato Tened en cuenta que adems de las variables y los valores inmediatos, tambin se pueden poner all llamadas a funciones que devuelvan un valor. int tecla = 0; while (tecla == 0) { tecla = readkey(); /* Intentamos leer una pulsacin de tecla */ } En este ejemplo lo que hacemos es que el programa se detenga hasta que el usuario pulse una tecla, con lo que cambiar el valor de la variable "tecla". El bucle for El bucle for es un bucle muy flexible y la vez muy potente ya que tiene varias formas interesantes de implementarlo, su forma ms tradicional es la siguiente: for (/* inicializacin */; /* sentencia condicional */; /* incremento o decremento */) { /* cdigo a ejecutar */ } Inicializacin: en esta parte se inicia la variable que controla el bucle y es la primera setencia que ejecuta el bucle, solo se ejecuta una vez ya que solo se necesita al principio del bucle. Sentencia condicional: es la segunda sentencia que ejecuta el bucle, es una sentencia condicional vlida, que determina si el bucle se ejecutar o no. incremento o decremento: es la ultima sentencia que ejecuta el bucle por lo general incrementar la variable con que se inicio el ciclo, despus de eso el bucle revisa

nuevamente la condicin, si es verdadera tiene lugar una ejecucin ms del cuerpo del ciclo, si es falsa se termina el ciclo y as la repeticin. Aqu muestro un ejemplo de un bucle que se ejecuta 100 veces: for (int i=0; i < 100; i++) { printf("%i\n", i); } No es necesaria por ejemplo en la primera la sentencia iniciar la variable que utilizara el bucle si ya ha sido inicializada en otra parte del bloque de sentencias donde se encuentra el bucle. Por lo general la sentencia condicional se compone de la variable que se utiliz para la inicializacin del bucle a la cual se le aplica alguno de los operadodores relacionales <, <=, >, >=; junto con otro valor; esta parte del bucle tambin se puede implementar con una variable de tipo bool. NOTA: recuerde que en cualquier sentencia donde se evala una expresin vlida, un valor de retorno=0 se considera falso y cualquier valor distinto de cero es verdadero, as false=0 y true=1. Creo que es importante comentar que esos tres "parmetros" que se le pasan a la sentencia for se pueden omitir, pero los punto-y-coma entre ellos s se han de dejar. Tambin cabe destacar que si no se pone la condicin de ejecucin del bucle, este se ejecutar indefinidamente hasta que se ejecute una sentencia break o se termine la funcin o el programa mediante un return. El bucle do...while El bucle do...while es un bucle que, por lo menos, se ejecuta una vez. While significa "mientras" Su forma es esta: do { /* CODIGO */ } while (/* Condicin de ejecucin del bucle */) Os muestro un ejemplo sencillo de uso: int aleatorio; do { aleatorio = rand(); } while (aleatorio != 25); La verdad es que este ejemplo puede resultar un poco absurdo, pero es bastante intuitivo. El cdigo del bucle asigna un valor aleatorio a la variable definida anteriormente, y mientras esa variable no tenga el valor 25, el bucle sigue ejecutndose. El goto La sentencia goto sirve para indicar al programa que continue ejecutndose desde la lnea de cdigo indicada. La verdad es que es una sentencia poco aceptada por la comunidad de programadores, pues puede provocar que se hagan programas un poco "sucios" y confusos. Su sintaxis es ms o menos as: /* Cdigo */ ETIQUETA: /* Cdigo */ goto ETIQUETA; /* Cdigo */ As, cuando se ejecute la sentencia goto, el programa continuar su ejecucin a partir de la etiqueta marcada. Como se puede observar se puede usar para crear un bucle, o para ir a una parte del cdigo u otra si se combina con una sentencia if...else. pero para los bucles ya hay estructuras definidas, y para la ejecucin opcional de bloques de cdigo, ya existen las Funciones. Slo en ocasiones muy excepcionales ser recomendado el uso del goto al crear iteraciones muy complejas.

USO DE FUNCIONES Funciones Como vimos anteriormente C tiene como bloque bsico la funcin. main() es una funcin, printf() otra, y hay muchas ms funciones predefinidas, pero nosotros mismos tambin podemos definir nuestras propias funciones. De hecho, es fundamental hacerlo. Podemos definir una funcin cualquiera de la misma manera en que definimos la funcin main(). Basta con poner su tipo, su nombre, sus argumentos entre parntesis y luego, entre llaves, su cdigo: /* Inclusin de archivos */ #include <stdio.h> void holaatodos(void) /*Funcin donde se ejecuta la lgica del programa*/ { printf("Hola a Todos\n"); /*imprime la cadena*/ return; /*sale de la funcin*/ } int main(void) /*Funcin principal del programa*/ { holaatodos(); /*llamada a la funcin que lleva el peso*/ return 0; /*sale del programa: correcto*/ } Este programa nos muestra cmo escribir y cmo utilizar una funcin. Y adems nos muestra un principio de buena programacin: meter las sentencias que "hacen el trabajo" en otras funciones especficas para sacarlas de main(), dejando en sta tan slo un guin general de lo que hace el programa, no las rdenes especficas. De esta manera se facilita la comprensin del programa, y por tanto el futuro trabajo de modificarlo. De la misma manera que tenemos que declarar una variable antes de utilizarla, no es indiferente el orden en que se siten las diferentes funciones en el fichero: las funciones deben declararse antes de ser llamadas. Igualmente vemos que, para una funcin void, la sentencia de control return no puede llamarse como pseudofuncin, porque en dicho caso la funcin void (en nuestro caso holaatodos()) devolvera un valor, cosa que su definicin no permite. Las funciones tambin permiten recibir tipos de datos, as pues las funciones nos sirven para hacer de un gran problema pequeas partes de un problema o sea dividir un gran problema en diferentes problemas ms pequeos. As que las funciones tambin pueden retornar un tipo de dato que hemos definido dentro de la misma. La definicin de una funcin para sumar dos nmeros sera de la siguiente manera: #include <stdio.h> int sumar(int numero1, int numero2); /* prototipo de la funcin */ int main(void) { int suma; /* definimos una variable*/ suma = sumar(5, 3); /* la variable obtiene el valor retornado de sumar * puede verse que entre los parntesis se mandan los valores * de los nmeros que se desean sumar en este caso 5 y 3 * pueden haberse declarados estos dos nmeros en otras variables * int dato = 4, valor = 3;

* suma = sumar(dato, valor); */ /* imprimimos la suma de los dos nmeros */ printf("La suma es: %d ", suma); return 0; } int sumar(int numero1, int numero2) { int retsuma; /* creamos la variable a retornar*/ retsuma = numero1 + numero2; /* asignamos a esa variable la suma de nmero 1 y 2*/ return retsuma; /* retornamos la suma de los nmeros */ } Paso de Parmetros Las funciones pueden recibir datos como lo hemos observado, pero existen dos formas importantes de enviar los datos hacia una funcin por valor y por referencia, con las cuales observarse que son muy diferentes y que una puede ser muy diferente de la otra, haciendo modificaciones en nuestro programa. Por Valor El paso por valor enva una copia de los parmetros a la funcin por lo tanto los cambios que se hagan en ella no son tomados en cuenta dentro de la funcin main(). Ejemplo: /* * por_valor.c */ #include <stdio.h> void sumar_valor(int numero); /* prototipo de la funcin */ int main(void) { int numero = 57; /* definimos numero con valor de 57*/ sumar_valor(numero); /* enviamos numero a la funcin */ printf("Valor de numero dentro de main() es: %d\n", numero); /* podemos notar que el valor de numero se modifica * slo dentro de la funcin sumar_valor pero en la principal * nmero sigue valiendo 57 */ return 0; } void sumar_valor(int numero) { numero++; /* le sumamos 1 al numero */ /* el valor de nmero recibido se aumenta en 1

* y se modifica dentro de la funcin sumar_valor() */ printf("Valor de numero dentro sumar_valor() es: %d\n", numero); return; } Por Referencia El paso por referencia se hace utilizando apuntadores. Se enva la direccin de memoria de la variable, por lo tanto los cambios que haga la funcin si afectan el valor de la variable. Ejemplo: /* * por_referencia.c */ #include <stdio.h> void sumar_referencia(int *numero); /* prototipo de la funcin */

int main(void) { int numero = 57; /* definimos numero con valor de 57*/ sumar_referencia(&numero); /* enviamos numero a la funcin */ printf("\nValor de numero dentro de main() es: %d ", numero); /* podemos notar que el valor de numero se modifica * y que ahora dentro de main() tambin se ha modificado * aunque la funcin no haya retornado ningn valor. */ return 0; } void sumar_referencia(int *numero) { *numero += 1; /* le sumamos 1 al numero */ /* el valor de numero recibido se aumenta en 1 * y se modifica dentro de la funcin */ printf("\nValor de numero dentro sumar_referencia() es: %d", *numero); return; } Variables Locales y Globales Adems de pasar valores a una funcin, tambin se pueden declarar tipos de datos dentro de las funciones, estos tipos de datos declarados dentro de una funcin solo son accesibles dentro de esta misma funcin y se les conocen como variables locales, as pues podemos definir los mismos nombres de variables en diferentes funciones, ya que estas variables solo son accesibles dentro de esas funciones. Ejemplo: /* * locales.c */

#include <stdio.h> void funcion1() { int dato = 53; /* definimos dato en 53*/ char num1 = 'a'; /* num1 vale a */ /* imprimimos */ printf("Funcion1, dato=%d, num1=%c\n", dato, num1); return; } void funcion2() { int dato = 25; /* definimos dato en 25*/ char num2 = 'z'; /* num2 vale z*/ /* imprimimos */ printf("Funcion2, dato=%d, num2=%c\n", dato, num2); return; } int main(void) { funcion1(); /* llamamos a funcion1() */ funcion2(); /* llamamos a funcion2() */ return 0; } En este caso la variable dato, esta definida dentro de cada una de las funciones y son totalmente distinta una de otra y no se puede utilizar fuera de esta, as pues num2 no puede ser utilizada por la funcion1() y num1 tampoco puede ser utilizada por funcion2(). Existen pues variables que se definen fuera de la funcin principal main() y fuera de cualquier otra funcin creada por nosotros, estas variables se les conoce con el nombre de Variables Globales ya que se pueden utilizar dentro de main() y dentro de cualquier funcin creada por nosotros. Ejemplo: /* * global.c */ #include <stdio.h> int variable_global = 99; /* inicializamos la variable global */ void funcion(); int main(void) { /* imprimimos el valor*/ printf("main(), acceso a variable_global %d\n", variable_global);

/* llamamos a la funcin */ funcion(); return 0; } void funcion() { /* imprimimos el valor*/ printf("funcion(), acceso a variable_global %d\n", variable_global); return; } Funciones Recursivas La recursividad (recursin) es la propiedad por la cual una funcin se llama a s misma directa o indirectamente. La recursin indirecta implica utilizar ms de una funcin. Se puede considerar la recursividad como una alternativa a la iteracin. La recursin permite especificar soluciones naturales, sencillas, que seran, en caso contrario, difciles de resolver. Toda funcin recursiva debe contemplar un caso base o condicin de salida, para terminar, o la recursividad no podr terminar nunca. Una funcin recursiva podra definirse as: funcion_recursiva( /* parmetros recibidos por la funcin */ ) { /* Cdigo */ funcion_recursiva( ); /* llamada a la funcin misma */ /* Cdigo */ } Uno de los ejemplos ms representativos en la recursividad es el factorial de un numero ( n! ):

la definicin de recursividad del factorial es:

En esta definicin, n = 0, es nuestro caso base, que le da fin a la recursividad. Entonces nuestro programa que calcula el factorial es: /* *factorial.c */ #include <stdio.h> long factorial(int n) { if (n == 0) /* caso base */ return 1; /* como 0! = 1, se retorna 1*/ else return n * factorial (n - 1); /* llamada a esta misma funcin */ } int main(void)

{ /* en este caso se llama a la funcin y se imprime directamente*/ printf("%ld ", factorial(5)); return 0; } Tambin existen otros tipos de funciones recursivas como lo es el producto de dos nmeros. El producto de a b, donde a y b son nmeros enteros positivos seria: Solucin iterativa:

Solucin recursiva:

As pues

es:

Podemos ver que la multiplicacin de dos nmeros a, b se puede transformar en otro problema ms pequeo multiplicar a por (b-1), el caso base se produce cuando b = 0 y el producto es 0. Ejemplo: /* * producto.c */ #include <stdio.h> int producto(int a, int b) { if (b == 0) /* caso base */ return 0; /* como b = 0, se retorna 0*/ else return a + producto (a, b - 1); /* llamada a esta misma funcin */ } int main(void) { /* en este caso se llama a la funcin y se imprime directamente*/ printf("%i ", producto( 7, 3)); return 0; } Recursividad indirecta o recursin mutua Esta se produce cuando una funcin llama a otra, que esta a su vez terminar llamando de nuevo a la primera funcin. El siguiente programa visualiza el alfabeto utilizando recursin indirecta o mutua: /* * elalfabeto.c */ #include <stdio.h> void funcionA(char c); /* se declara el prototipo de la funcin para que el llamado */

void funcionB(char c); /* a la misma en la funcin no sea implcita */ int main(void) { funcionA('z'); /* llamado a funcionA */ return 0; } void funcionA(char c) { if (c > 'a') /* caso base mientras c no sea menor que A */ funcionB(c); /* llamado a la funcionB */ printf("%c ", c); /* imprimimos el valor de c */ } void funcionB(char c) { funcionA(--c); /* llamado a la funcionA decrementando el valor de 'z' */ } Recursin versus Iteracin Tanto la iteracin como la recursin se basan en estructura de control: la iteracin utiliza una estructura repetitiva y la recursin una estructura de seleccin. La iteracin utiliza explcitamente una estructura repetitiva mientras que la recursin consigue la repeticin mediante llamadas repetitivas a funciones. La iteracin termina si la condicin del bucle no se cumple, mientras que la recursin termina cuando se reconoce un caso base. La recursin puede presentar desventajas ante la iteracin ya que se invoca repetidas veces al mecanismo de llamada de funciones y se necesita un tiempo mayor para realizar cada llamada. La razn por la cual se puede elegir u optar por usar recursividad es que existen muchos problemas complejos que poseen naturaleza recursiva y, en consecuencia, son mas fciles de implementar. Ejemplo Iterativo /* * iterativo.c */ #include <stdio.h> long factorial(int numero); int main(int argc, char** argv) { int contador = 0; /* calcula el factorial de 0 a 10 */ for ( contador = 0; contador <= 10; contador++ ) printf("%d! = %ld\n", contador, factorial( contador )); return 0; } /* funcion factorial iterativa */ long factorial( int numero ) { long resultado = 1;

int i = 0; /* declaracion de la funcin factorial iterativa */ for ( i = numero; i >= 1; i-- ) resultado *= i; return resultado; } Ejemplo Recursivo /* * recursivo.c */ #include <stdio.h> long factorial(int numero); int main(int argc, char** argv) { int contador = 0; /* calcula el factorial de 0 a 10 */ for ( contador = 0; contador <= 10; contador++ ) printf("%d! = %ld\n", contador, factorial( contador )); return 0; } /* funcin factorial recursiva */ long factorial( int numero ) { if ( numero <= 0 ) /* caso base */ return 1; /* casos bases: 0! = 1 y 1! = 1 */ else /* llamada recursiva */ return numero * factorial( numero - 1 ); /* llamada a la funcin factorial */ Vectores Los vectores son una forma de almacenar datos que permiten contener una serie de valores del mismo tipo, cada uno de los valores contenidos tiene una posicin asociada que se usar para accederlos. Est posicin o ndice ser siempre un nmero entero positivo. En C la cantidad de elementos que podr contener un vector es fijo, y en principio se define cuando se declara el vector. Los vectores se pueden declarar de la siguiente forma: tipo_elemento nombre[largo]; Esto declara la variable nombre como un vector de tipo_elementos que podr contener largo cantidad de elementos, y cada uno de estos elemento podr contener un valor de tipo tipo_elemento. Por ejemplo: double valores[128]; En este ejemplo declaramos un vector de 128 elementos del tipo double, los ndices de los elementos iran entre 0 (para el primer elemento y 127 para el ltimo). De la misma forma que con las otras declaraciones de variables que hemos visto se le puede asignar un valor iniciar a los elementos. O tambin se pueden declarar: tipo_elemento nombre[largo]={valor_0, valor_1, valor_2};

En caso estamos asignadole valores a los primeros 3 elementos del vector nombre. Notar que largo debe ser mayor o igual a la cantidad de valores que le estamos asignando al vector, en el caso de ser la misma cantidad no aporta informacin, por lo que el lenguaje nos permite escribir: tipo_elemento nombre[]={valor_0, valor_1, valor_2}; Que declarar nombre como el vector de largo 3. Para acceder a un elemento accederemos a travs de su posicin. Es decir: tipo_elemento elemento; ... elemento = nombre[2]; Asumiendo que tenemos el vector anterior definido estaramos guardando valor_2 en elemento. Veamos algunos ejemplos: /* * Ejemplo : El producto escalar de dos vectores */ #include <stdio.h> double producto_escalar(double v1[], double v2[], int d); int main() { const int largo = 3; double vector_1[largo] = {5,1,0}; double vector_2[largo] = {-1,5,3}; double resultado = producto_escalar(vector_1, vector_2, largo); // imprime el resultado printf("(%f, %f, %f) . (%f, %f, %f) = %f\n", vector_1[0], vector_1[1], vector_1[2], vector_2[0], vector_2[1], vector_2[2], resultado); return 0; } /* producto escalar entre dos vectores */ double producto_escalar(double v1[], double v2[], int d) { double resultado = 0; int i; for (i=0; i < d; i++) { resultado += v1[i] * v2[i]; } return resultado; } En el ejemplo anterior usamos los vectores de C para representar vectores matemticos y calcular el producto vectorial entre ellos. Una peculiaridad que se puede notar es que al recibir un arreglo en una funcin no se especifica el largo, volveremos a esto en un captulo posterior. Otra funcin clsica es la bsqueda de un mximo o mnimo, que podemos escribirla de la siguiente manera: int buscar_maximo(double valores[], int num_valores) { int maximo_pos = 0; for (int i = 1; i < num_valores; i++) { if (valores[i] > valores[maximo_pos]) {

maximo_pos = i; } } return maximo_pos; } Otro ejemplo sencillo, calcular el promedio de los valores. double promedio(double valores[], int largo) { double suma=0; for (int i=0;i<largo;i++) { suma+=valores[i]; } return suma/largo; } Cuando una funcin recibe un vector por parmetro y cambia su contenido y el cambio es permanente (se ve an fuera de la funcin). Esto puede parecer extrao despus del nfasis que pusimos en resaltar que todos los parmetros de una funcin se reciben por valor, pero se aclarar en el siguiente capitulo. Mientras tanto usemos esto para definir una funcin que le aplique otra funcin que recibe por parmetro a cada elemento del vector, guardando el resultado en el mismo vector y una llamada de ejemplo a esta. void cuadrados(double vector[], int largo) { for (int i=0;i<largo;i++) { vector[i]=cuadrado(vector[i]); } } ... double cuadrado(double valor) { return valor*valor; } ... cuadrados(elementos,num_elem); ... De la misma forma que venimos usando vectores de tipos bsicos, podemos tener vectores de vectores, estos se declaran de la siguiente forma: int matriz[3][7]; int tabla[3][4]={ { 1, 2, 3, 4}, { 5, 6, 7, 8}, /* los espacios y saltos de lneas no son tomados en cuenta */ { 9,10,11,12} }; double v[2][2][2]; ... printf("tabla[0][1]: %i\n", tabla[0][3]); // Imprime 4 printf("tabla[2][0]: %i\n", tabla[2][0]); // Imprime 9 ... En este ejemplo tabla es un vector de longitud 3, cuyos elementos son vectores de longitud 4 de elementos de tipo int. En resumen, suponiendo que v[n] es un vector de cualquier tipo de dato con n cantidad de posiciones, al vector v se le aplican las siguientes reglas: 1. La primera posicin siempre ser v[0] 2. La ltima posicin es v[n-1] 3. En versiones previas a C99 n es una constante definida antes de la declaracin de v[n]

CADENAS DE CARACTERES Las cadenas de caracteres (tambin llamadas cadenas o strings) son un tipo particular de vectores, son de hecho vectores de char, con la particularidad que tienen una marca de fin (el caracter '\0'), adems el lenguaje nos permite escribirlas como texto dentro de comillas dobles. Veamos unos ejemplos de su declaracin: char cadena_hola[]="Hola"; char otro_hola[]={'H','o','l','a','\0'}; // Igual al anterior char vector[]={'H','o','l','a'}; /* Un vector de 4 elementos, con los elementos 'H','o','l' y 'a' */ char espacio_cadena[1024]="Una cadena en C"; char cadena_vacia[]=""; Cmo vimos anteriormente al declarar un vector se define la cantidad de elementos que puede contener, en el caso de las cadenas se debe tener en cuenta el espacio adicional necesario para el \0. Viendo el ejemplo, tanto cadena_hola y otro_hola tienen un largo 5 y cadena_vacia tiene un largo de 1. Tambin vimos anteriormente que al usar vectores debemos tener en cuenta su largo, y as es que el largo o cantidad de elemento lo necesitamos en todas las funciones que definimos usando vectores y lo recibimos como un parmetro ms en estas, en el caso de las cadenas al tener una marca de fin podemos prescindir del largo y procesar una cadenas hasta llegar a la marca de fin. Por ejemplo, la siguiente funcin calcula el largo de una cadena: /* devuelve la cantidad de caracteres en cadena sin contar el '\0' */ int largo_cadena(char cadena[]) { int largo=0 while (cadena[largo]!='\0') largo++; return largo; } Se debe tener en cuenta que el largo de una cadena y el largo del vector con la que se representa son distintos, tanto por como largo_cadena() cuenta el largo de la cadena, como por espacio_cadenadel ejemplo anterior. Algo bastante usual es necesitar unir dos cadenas, veamos un ejemplo: bool unir_cadenas(char destino[], char origen[], int largo) { int largo_origen = largo_cadena(origen); int largo_destino = largo_cadena(destino); if ( largo_origen+largo_destino+1 > largo ) { return false; } for (int i=0; i<largo_origen;i++) { destino[largo_destino+i] = origen[i]; } destino[largo_destino+largo_origen]='\0'; return true; } ... if ( unir_cadenas(espacio_cadena," que puede crecer hasta 1023 caracteres",1024) ) { ... Estos dos ejemplos son versiones simplificadas de funciones provistas por la biblioteca estndar de C a travs del encabezado string.h. Nuestro largo_cadena() es similar al strlen() de la biblioteca estndar, y unir_cadenas() se asemeja al strncat(). Si bien ver estas versiones nos sirven para entender las cadenas en C, en general ser preferible usar las funciones provistas por la biblioteca estndar, ya que podemos estar seguros que van a estar programadas de la mejor manera posible. Entre las funcione que provee la biblioteca estndar de C, las ms importantes son:

largo = strlen(cadena) // Para obtener el largo de una cadena strcpy(destino, origen) // Copia el contenido de origen en destino // destino debe ser lo suficientemente grande strcat(destino, origen) // Agrega el contenido de origen al final de destino // destino debe ser lo suficientemente grander resultado = strcmp(cadena1, cadena2) // Compara dos cadenas // devuelve un valor menor, igual o mayor que 0 segn si cadena1 es menor, // igual o mayor que cadena2, respectivamente. posicion = strchr(cadena, caracter) // Devuelve la posicin en memoria de la primer // aparicin de caracter dentro de cadena posicion = strstr(cadena,subcadena) // Devuelve la posicin en memoria de la primer // aparicin de subcadena dentro de cadena Veamos algunos ejemplos usando <string.h>: #include <stdio.h> #include <string.h> ... char color[] = "rojo"; char grosor[] = "grueso"; ... char descripcion[1024]; strcpy(descripcion, "Lapiz color "); strncat(descripcion, color, 1024); strncat(descripcion, " de trazo ", 1024); strncat(descripcion, grosor, 1024); // descripcion contiene "Lapiz color rojo de trazo grueso" ... void intercambiar(char vector[], int pos1, int pos2); void invierte_cadena(char cadena[]) { int largo = strlen(cadena); for (int i=0; i < (largo/2); i++) { intercambiar(cadena, i, (largo-1)-i); } } void intercambiar(char vector[], int pos1, int pos2) { char aux=vector[pos1]; vector[pos1]=vector[pos2]; vector[pos2]=aux; } MANEJO DE ARCHIVOS As como hemos revisado la salida y entrada por pantalla y teclado respectivamente, veremos ahora la entrada y/o salida de datos utilizando ficheros, lo cual ser imprescindible para un gran nmero de aplicaciones que deseemos desarrollar. Ficheros El estndar de C contiene funciones varias para la edicin de ficheros, estas estn definidas en la cabecera stdio.h y por lo general empiezan con la letra f, haciendo referencia a file. Adicionalmente se agrega un tipo FILE, el cual se usar como apuntador a la informacin del fichero. La secuencia que usaremos para realizar operaciones ser la siguiente:

Crear un apuntador del tipo FILE * Abrir el archivo utilizando la funcin fopen y asignndole el resultado de la llamada a nuestro apuntador. Hacer las diversas operaciones (lectura, escritura, etc). Cerrar el archivo utilizando la funcin fclose.

fopen Esta funcin sirve para abrir y crear ficheros en disco. El prototipo correspondiente de fopen es: FILE * fopen (const char *filename, const char *opentype); Los parmetros de entrada de fopen son: filename: una cadena que contiene un nombre de fichero vlido. opentype: especifica en tipo de fichero que se abrir o se crear. Una lista de parmetros opentype para la funcin fopen son: "r" : abrir un archivo para lectura, el fichero debe existir. "w" : abrir un archivo para escritura, se crea si no existe o se sobreescribe si existe. "a" : abrir un archivo para escritura al final del contenido, si no existe se crea. "r+" : abrir un archivo para lectura y escritura, el fichero debe existir. "w+" : crear un archivo para lectura y escritura, se crea si no existe o se sobreescribe si existe. "a+" : abrir/crear un archivo para lectura y escritura al final del contenido Adicionalmente hay tipos utilizando "b" (binary) los cuales no sern mostrados por ahora y que solo se usan en los sistemas operativos que no pertenecen a la familia de unix. fclose Esta funcin sirve para poder cerrar un fichero que se ha abierto. El prototipo correspondiente de fclose es: int fclose (FILE *stream); Un valor de retorno cero indica que el fichero ha sido correctamente cerrado, si ha habido algn error, el valor de retorno es la constante EOF. Un ejemplo pequeo para abrir y cerrar el archivo llamado fichero.in en modo lectura: #include <stdio.h> int main(int argc, char** argv) { FILE *fp; fp = fopen ( "fichero.in", "r" ); fclose ( fp ); return 0; } Como vemos, en el ejemplo se utiliz el opentype "r", que es para la lectura. Otra cosa importante es que el lenguaje C no tiene dentro de si una estructura para el manejo de excepciones o de errores, por eso es necesario comprobar que el archivo fue abierto con xito "if (archivo == NULL)". Si fopen pudo abrir el archivo con xito devuelve la referencia al archivo (FILE *), de lo contrario devuelve NULL y en este caso se debera revisar la direccion del archivo o los permisos del mismo. En estos ejemplos solo vamos a dar una salida con un retorno de 1 que sirve para sealar que el programa termino por un error.

feof Esta funcin sirve para determinar si el cursor dentro del archivo encontr el final (end of file). Existe otra forma de verificar el final del archivo que es comparar el caracter que trae fgetc del archivo con el macro EOF declarado dentro de stdio.h, pero este mtodo no ofrece la misma seguridad (en especial al tratar con los archivos "binarios"). La funcin feof siempre devolver cero (Falso) si no es encontrado EOF en el archivo, de lo contrario regresar un valor distinto de cero (Verdadero). El prototipo correspondiente de feof es: int feof(FILE *fichero); Lectura Un archivo generalmente debe verse como un string (una cadena de caracteres) que esta guardado en el disco duro. Para trabajar con los archivos existen diferentes formas y diferentes funciones. Las funciones que podramos usar para leer un archivo son: int fgetc(FILE *archivo) char *fgets(char *buffer, int tamano, FILE *archivo) size_t fread(void *puntero, size_t tamano, size_t cantidad, FILE *archivo); int fscanf(FILE *fichero, const char *formato, argumento, ...); Las primeras dos de estas funciones son muy parecidas entre si. Pero la tercera, por el numero y el tipo de parmetros, nos podemos dar cuenta de que es muy diferente, por eso la trataremos aparte junto al fwrite que es su contraparte para escritura. fgetc Esta funcin lee un caracter a la vez del archivo que esta siendo sealado con el puntero *archivo. En caso de que la lectura sea exitosa devuelve el caracter ledo y en caso de que no lo sea o de encontrar el final del archivo devuelve EOF. El prototipo correspondiente de fgetc es: char fgetc(FILE *archivo); Esta funcin se usa generalmente para recorrer archivos de texto. A manera de ejemplo vamos a suponer que tenemos un archivo de texto llamado "prueba.txt" en el mismo directorio en que se encuentra el fuente de nuestro programa. Un pequeo programa que lea ese archivo ser: #include <stdio.h> #include <stdlib.h> int main() { FILE *archivo; char caracter; archivo = fopen("prueba.txt","r"); if (archivo == NULL){ printf("\nError de apertura del archivo. \n\n"); }else{

printf("\nEl contenido del archivo de prueba es \n\n"); while (feof(archivo) == 0) { caracter = fgetc(archivo);

printf("%c",caracter); } } return 0; } fgets Esta funcin est diseada para leer cadenas de caracteres. Leer hasta n-1 caracteres o hasta que lea un retorno de lnea. En este ltimo caso, el carcter de retorno de lnea tambin es ledo. El prototipo correspondiente de fgets es: char *fgets(char *buffer, int tamano, FILE *archivo); El primer parmetro buffer lo hemos llamado as porque es un puntero a un espacio de memoria del tipo char (podramos usar un arreglo de char). El segundo parmetro es tamano que es el limite en cantidad de caracteres a leer para la funcion fgets. Y por ultimo el puntero del archivo por supuesto que es la forma en que fgets sabra a que archivo debe leer. #include <stdio.h> #include <stdlib.h> int main() { FILE *archivo; char caracteres[100]; archivo = fopen("prueba.txt","r"); if (archivo == NULL) exit(1); printf("\nEl contenido del archivo de prueba es \n\n"); while (feof(archivo) == 0) { fgets(caracteres,100,archivo); printf("%s",caracteres); } return 0; } Este es el mismo ejemplo de antes con la diferencia de que este hace uso de fgets en lugar de fgetc. La funcin fgets se comporta de la siguiente manera, leer del archivo apuntado por archivo los caracteres que encuentre y a ponerlos en buffer hasta que lea un caracter menos que la cantidad de caracteres especificada en tamano o hasta que encuentre el final de una linea (\n) o hasta que encuentre el final del archivo (EOF). En este ejemplo no vamos a profundizar mas que para decir que caracteres es un buffer, los pormenores seran explicados en la seccin de manejo dinmico de memoria. El beneficio de esta funcin es que se puede obtener una linea completa a la vez. Y resulta muy til para algunos fines como la construccin de un parser de algn tipo de archivo de texto. fprintf La funcin fprintf funciona igual que printf en cuanto a parmetros, pero la salida se dirige a un fichero en lugar de a la pantalla. El prototipo correspondiente de fprintf es: int fprintf(FILE *archivo, const char *formato, argumento, ...);

Podemos ver un ejemplo de su uso, abrimos el documento "fichero.txt" en modo lectura/escritura y escribimos dentro de el. #include <stdio.h> int main ( int argc, char **argv ) { FILE *fp; char buffer[100] = "Esto es un texto dentro del fichero."; fp = fopen ( "fichero.txt", "r+" ); fprintf(fp, buffer); fprintf(fp, "%s", "\nEsto es otro texto dentro del fichero."); fclose ( fp ); return 0; } ESTRUCTURAS En la creacion de soluciones para algunos problemas surge la necesidad de agrupar datos de diferente tipo o de manejar datos que serian muy dificil de describir en los tipos de datos primitivos, esta es la situacion en la que debemos aprovecharnos de las caracteristicas que hacen al lenguaje C especial, o sea el uso de estructuras uniones y punteros. Estructuras Una estructura contiene varios datos. La forma de definir una estructura es haciendo uso de la palabra clave struct. Aqui hay ejemplo de la declaracion de una estructura: struct mystruct { int int_member; double double_member; char string_member[25]; } variable; "variable" es una instancia de "mystruct" y no es necesario ponerla aqu. Se podria omitir de la declaracion de "mystruct" y ms tarde declararla usando: struct mystruct variable; Tambin es una prctica muy comn asignarle un alias o sinnimo al nombre de la estructura, para evitar el tener que poner "struct mystruct" cada vez. C nos permite la posibilidad de hacer esto usando la palabra clave typedef, lo que crea un alias a un tipo: typedef struct { ... } Mystruct; La estructura misma no tiene nombre (por la ausencia de nombre en la primera linea), pero tiene de alias "Mystruct". Entonces se puede usar as: Mystruct variable; Note que es una convencion, y una buena costumbre usar mayscula en la primera letra de un sinnimo de tipo. De todos modo lo importante es darle algn identificador para poder hacer referencia a la estructura: podriamos tener una estructura de datos recursiva de algn tipo. Ejemplo de una estructura :

/* * */

estructura.c

#include <stdio.h> #include <string.h> /* definimos una estructura para cds */ struct cd { char titulo[30]; char artista[25]; float precio; int canciones; } Cd1 = { /* inicializamos la estructura Cd1 creaa con sus valores * usando las definiciones iniciales*/ "Canciones Bebe", /* titulo */ "Pinocho", /* artista */ 12.50, /* precio */ 16 /* total canciones */ }; int main(void) { struct cd Cd2; /* definimos una nueva estructura llamado cd2 */ /* asignamos valores a los tipos de datos del cd2 */ strcpy(Cd2.titulo, "New Age"); /* la forma de insertar valores a un * tipo char en una estructura es usando strcpy * de la libreria string.h */ strcpy(Cd2.artista, "Old Man"); Cd2.precio = 15.00; Cd2.canciones = 12; /* la forma de acceder a los valores de una estructura */ /* es usando el "." despues de la definicion del dato*/ printf("\n Cd 1"); printf("\n Titulo: %s ", Cd1.titulo); printf("\n Artista: %s ", Cd1.artista); printf("\n Total Canciones: %d ", Cd1.canciones); printf("\n Precio Cd: %f ", Cd1.precio); printf("\n"); printf("\n Cd 2"); printf("\n Titulo: %s ", Cd2.titulo); printf("\n Artista: %s ", Cd2.artista); printf("\n Total Canciones: %d ", Cd2.canciones); printf("\n Precio Cd: %.2f ", Cd2.precio); /* el .2 que esta entre %f * sirve para mostrar unicamente * 2 decimales despues del punto*/

return 0; } Estructuras Anidadas Una estructura puede estar dentro de otra estructura a esto se le conoce como anidamiento o estructuras anidadas. Ya que se trabajan con datos en estructuras si definimos un tipo de dato en una estructura y necesitamos definir ese dato dentro de otra estructura solamente se llama el dato de la estructura anterior. Definamos una estructura en nuestro programa: struct empleado /* creamos una estructura llamado empleado*/ { char nombre_empleado[25]; char direccion[25]; char ciudad[20]; char provincia[20]; long int codigo_postal; double salario; }; /* las estructuras necesitan punto y coma (;) al final */ Y luego necesitamos una nueva estructura en nuestro programa: struct cliente /* creamos una estructura llamada cliente */ { char nombre_cliente[25]; char direccion[25]; char ciudad[20]; char provincia[20]; long int codigo_postal; double saldo; }; /* las estructuras necesitan punto y coma (;) al final */ Podemos ver que tenemos datos muy similares en nuestras estructuras, asi que podemos crear una sola estructura llamada infopersona con estos datos idnticos: struct infopersona /* creamos la estructura que contiene datos parecidos */ { char direccion[25]; char ciudad[20]; char provincia[20]; long int codigo_postal; }; /* las estructuras necesitan punto y coma (;) al final */ Y crear las nuevas estructuras anteriores, anidando la estructura necesaria: struct empleado /* se crea nuevamente la estructura */ { char nombre_empleado[25]; /* creamos direcc_empleado con "struct" del tipo "estructura infopersona" */ struct infopersona direcc_empleado; double salario; }; /* las estructuras necesitan punto y coma (;) al final */ <source lang=c> struct cliente /* se crea nuevamente la estructura */ { char nombre_cliente[25]; /* creamos direcc_cliente con "struct" del tipo "estructura infopersona" */ struct infopersona direcc_cliente; double saldo;

}; /* las estructuras necesitan punto y coma (;) al final */ Y ac el ejemplo completo con estructuras anidadas: /* * estructura2.c */ #include <stdio.h> #include <string.h> /* creamos nuestra estructura con datos similares */ struct infopersona { char direccion[25]; char ciudad[20]; char provincia[20]; long int codigo_postal; }; /* las estructuras necesitan punto y coma (;) al final */ /* creamos nuestra estructura empleado */ struct empleado { char nombre_empleado[25]; /* agregamos la estructura infopersona * con nombre direcc_empleado */ struct infopersona direcc_empleado; double salario; }; /* las estructuras necesitan punto y coma (;) al final */ /* creamos nuestra estructura cliente */ struct cliente { char nombre_cliente[25]; /* agregamos la estructura infopersona * con nombre direcc_cliente */ struct infopersona direcc_cliente; double saldo; }; /* las estructuras necesitan punto y coma (;) al final */ int main(void) { /* creamos un nuevo cliente */ struct cliente MiCliente; /*inicializamos un par de datos de Micliente */ strcpy(MiCliente.nombre_cliente,"Jose Antonio"); strcpy(MiCliente.direcc_cliente.direccion, "Altos del Cielo"); /* notese que se agrega direcc_cliente haciendo referencia * a la estructura infopersona por el dato direccion */ /* imprimimos los datos */ printf("\n Cliente: ");

printf("\n Nombre: %s", MiCliente.nombre_cliente); /* notese la forma de hacer referencia al dato */ printf("\n Direccion: %s", MiCliente.direcc_cliente.direccion); /* creamos un nuevo empleado */ struct empleado MiEmpleado; /*inicializamos un par de datos de MiEmplado */ strcpy(MiEmpleado.nombre_empleado,"Miguel Angel"); strcpy(MiEmpleado.direcc_empleado.ciudad,"Madrid"); /* para hacer referencia a ciudad de la estructura infopersona * utilizamos direcc_empleado que es una estructura anidada */ /* imprimimos los datos */ printf("\n"); printf("\n Empleado: "); printf("\n Nombre: %s", MiEmpleado.nombre_empleado); /* notese la forma de hacer referencia al dato */ printf("\n Ciudad: %s", MiEmpleado.direcc_empleado.ciudad); return 0; }

ALGORITMO
La idea en este problema es:

1) Pedirle al usuario que ingrese el nmero de cursos, los cursos y las horas de cruce. 2) Verificar que los nombres de cursos introducidos por el usuario sean los de la matricula.

3) Una vez que el programa tiene los cursos a tratar, se almacena en una matriz o estructura las secciones disponibles as como los das y las horas de teora y prctica. 4) Una vez que se tienen estos datos generar todas las combinaciones posibles con las secciones de todos los cursos 5) Una vez hecho esto almacenar en una matriz, que tiene por columnas los das de la semana y por filas las horas de clase, y asignar una unidad por cada curso que ocupa una casilla en la matriz. 6) finalmente comparar con el mximo de cruces (dato del usuario) e imprimir las matrices que cumplen con las condiciones dadas.

CODIFICACION

#include<stdio.h> #include <string.h> #include <math.h> void main()

char curso[100][6],seccion[100][2],teoprac[100][2],dia[100][3], horainicial[100][3],horafinal[100][3]; int I; int numcurso,numcruce,r,k,l,contador1,contador2,z,y,n,contador3; int A,B,C; char rad[15][3],dad[7][3]; int rrr[20],madre[20][7][15]={0}; int i,j,x,ii,jj,kk,ll,mm,pp,tt,nn,w,iii,jjj,kkk,lll,uu,ss,qq; FILE *t; FILE *q; FILE *S; char alfa[50][7],cad[10][7]; printf("ESTE PROGRAMA LE PERMITIRA CONOCER POSIBLES \nCOMBINACIONES DE LOS CURSOS QUE UD. QUIERE LLEVAR\n"); t=fopen("C:\\Dev-Cpp\\HORALUM.txt","r") ; q=fopen("C:\\Dev-Cpp\\HORACUR.TXT","r");

for(k=1;!feof(t);k++) fscanf(t,"%s",&alfa[k]); fclose(t); //for(j=1;j<=k;j++) //printf("%s\n", alfa[j] );

printf("escribir el numero de cursos:");scanf("%d",&numcurso); printf("escribir el numero de cruces:");scanf("%d",&numcruce); i=1 ; r=0;

//proceso de lectura y reconocimiento for(i=1;i<=numcurso;i++) { r=0; while(r!=5) { printf("escribir el curso %d:",i);

scanf("%s",&cad[i]); // printf("dato leido : %s\n",cad[i]); r=0; for(j=1;j<=k;j++) { if(r!=5) {if(r<5) r=0; for(l=1;l<=5;l++) { if(cad[i][l]==alfa[j][l]) { r++; //printf("el valor de r cambi a %d\n",r); } } } } if(r!=5) printf("el curso escrito no existe\n"); } }

//lectura y asignacion a cadenas for(w=1;!feof(q);w++) { fscanf(q,"%s",curso[w]); if(curso[w][0]=='p' ||curso[w][0]=='t') { strcpy(curso[w],curso[w-1]); strcpy(seccion[w],seccion[w-1]); fscanf(q,"%s",&dia[w]); fscanf(q,"%s",&horainicial[w]); fscanf(q,"%s",&horafinal[w]); } else { fscanf(q,"%s",seccion[w]); fscanf(q,"%s",&teoprac[w]); fscanf(q,"%s",&dia[w]); fscanf(q,"%s",&horainicial[w]); fscanf(q,"%s",&horafinal[w]); }

} fclose(q); /* for(j=1;j<=i;j++) { printf("curso %s_\n",curso[j]) ; printf("seccion %s_\n",seccion[j]); printf("teoprac %s_\n",teoprac[j]) ; printf("dia %s_\n",dia[j]); printf("horainicial %s_\n",horainicial[j]);

printf("horafinal %s_\n",horafinal[j]); } */ rad[1][1]='0'; rad[1][2]='8' ; rad[2][1]='0' ; rad[2][2]='9' ; rad[3][1]='1' ; rad[3][2]='0' ; rad[4][1]='1' ; rad[4][2]='1' ; rad[5][1]='1' ; rad[5][2]='2' ; rad[6][1]='1' ; rad[6][2]='3' ; rad[7][1]='1' ; rad[7][2]='4' ; rad[8][1]='1' ; rad[8][2]='5' ; rad[9][1]='1' ; rad[9][2]='6' ; rad[10][1]='1' ; rad[10][2]='7' ; rad[11][1]='1' ; rad[11][2]='8' ; rad[12][1]='1' ; rad[12][2]='9' ; rad[13][1]='2' ; rad[13][2]='0' ; rad[14][1]='2' ; rad[14][2]='1' ;

dad[1][1]=='L'; dad[1][2]=='U' ; dad[2][1]=='M' ; dad[2][2]=='A' ; dad[3][1]=='M' ; dad[3][2]=='I' ; dad[4][1]=='J' ; dad[4][2]=='U' ; dad[5][1]=='V' ; dad[5][2]=='I' ; dad[6][1]=='S' ; dad[6][2]=='A' ;

//contando el numero de secciones de los cursos leidos

for(iii=1;iii<=5;iii++) { for(jjj=0;jjj<=w;jjj++) { for(kkk=1;kkk<=5;kkk++) { if(cad[iii][kkk]==curso[jjj][kkk-1] ) { for(lll=0;lll<=1;lll++) { if(seccion[iii][lll]==seccion[iii-1][lll]) rrr[iii]=rrr[iii]; else rrr[iii]++; } } } } }

//algoritmo contador1=1;

for(ii=1;ii<=numcurso;ii++) { contador1=1; for(jj=1;jj<=w;jj++) { z=jj; for(I=1;I<=5;I++) { if(cad[ii][I]==curso[jj][I]) { if(jj!=1) { if(seccion[jj][0]=seccion[jj-1][0]) contador1++; } for(ll=1;ll<=6;l++) { for(qq=1;qq<=2;qq++) { if(dia[jj][qq-1]==dad[ll][qq]) { for(mm=1;mm<=14;mm++) { for(nn=1;nn<=14;nn++) { for(ss=1;ss<=2;ss++) { if(horainicial[jj][ss-1]==rad[mm][ss] && horafinal[jj][ss1]==rad[nn][ss]) { tt=mm-nn; A=1;C=0 ; for(j=1;(contador2+1)<=numcurso;j++) { contador2=j+ii; A=rrr[ii+j]*A; } y=floor((jj-z)/rrr[ii])+1; A=A+y; C=A-y; for(uu=A;uu<=w;uu+C) { for(pp=1;pp<=tt;pp++) madre[uu][pp][ll]=madre[uu][pp][ll]+1; } } } } } } } } } } } }

S=fopen("C:\\Dev-Cpp\\COMBINA.txt","w") ; fclose(S);

{ } }

MANUAL DE USUARIO

Objetivos del programa

El programa permite encontrar con solo ingresar los cursos a llevar y el numero mximo de cruces tolerables , las posibles combinaciones para facilitar los problemas que se pueden generan a la hora de matricularse.

Cmo usar el programa?

1) Inserte el CD 2) En el CD encontrara los archivos HORARIO.exe , HORACUR.txt y HORALUM.txt contenidos en la carpeta DEV-CPP proceda a copiar la carpetas en la unidad C 3) Ejecute el programa 4) Errores ms frecuentes al usar el programa

1) Los nombres de los cursos van con maysculas, no con minsculas. 2) si ha ingresado en nombre de algn curso errneamente el programa le pedir que lo ingrese de nuevo. 3) Ingrese nmeros enteros, no decimales. 4) el programa no mostrara los resultados, Ud. debe buscarlos en la direccin C:\Dev-Cpp, que estarn en el archivo COMBINA.txt