Curso de C

212
Introducción Contenido del Capítulo: El lenguaje C Peculiaridades de C Compiladores El editor El primer programa: Hola Mundo o ¿Como se hace? o Nota adicional sobre comentarios. La creación de un programa paso a paso ¿Qué sabemos hacer? Ejercicios Sobre el curso Algunos capítulos tienen apartados dedicados a algún Sistema Operativo en concreto y está indicado en el título entre paréntesis. Por ejemplo en el Capítulo 2 hay un apartado titulado 'Gotoxy: Posicionando el cursor (DOS)'. El DOS entre paréntesis indica que sólo tiene validez en DOS. El lenguaje C El lenguaje C es uno de los más rápidos y potentes que hay hoy en día. Algunos dicen que está desfasado y que el futuro es Java. No sé si tendrá futuro pero está claro que presente si tiene. No hay más que decir que el sistema operativo Linux está desarrollado en C en su práctica totalidad. Así que creo que no sólo no perdemos nada aprendiéndolo sino que ganamos mucho. Para empezar nos servirá como base para aprender C++ e introducirnos en el mundo de la programación Windows. Si optamos por Linux existe una biblioteca llamada gtk (o librería, como prefieras) que permite desarrollar aplicaciones estilo Windows con C. 1

description

g

Transcript of Curso de C

IntroduccinContenido del Captulo: El lenguaje C Peculiaridades de C Compiladores El editor El primer programa:Hola Mundo Como se hace? Nota adicional sobre comentarios. La creacin de un programa paso a paso Qu sabemos hacer? EjerciciosSobre el cursoAlgunos captulos tienen apartados dedicados a algn Sistema Operativo en concreto y est indicado en el ttulo entre parntesis. Por ejemplo en el Captulo 2 hay un apartado titulado 'Gotoxy: Posicionando el cursor (DOS)'. El DOS entre parntesis indica que slo tiene validez en DOS.El lenguaje CEl lenguajeCes uno de los ms rpidos y potentes que hay hoy en da. Algunos dicen que est desfasado y que el futuro es Java. No s si tendr futuro pero est claro que presente si tiene. No hay ms que decir que el sistema operativo Linux est desarrollado enCen su prctica totalidad. As que creo que no slo no perdemos nada aprendindolo sino que ganamos mucho. Para empezar nos servir como base para aprender C++ e introducirnos en el mundo de la programacin Windows. Si optamos por Linux existe una biblioteca llamada gtk (o librera, como prefieras) que permite desarrollar aplicaciones estilo Windows con C.No debemos confundirCcon C++, que no son lo mismo. Se podra decir que C++ es una extensin de C. Para empezar en C++ conviene tener una slida base de C.Existen otros lenguajes como Visual Basic que son muy sencillos de aprender y de utilizar. Nos dan casi todo hecho. Pero cuando queremos hacer algo complicado o que sea rpido debemos recurrir a otros lenguajes (C++, Delphi,...).Peculiaridades de CUna de las cosas importantes deCque debes recordar es que esCase Sensitive(sensible a las maysculas o algo as). Es decir que paraCno es lo mismo escribirPrintfqueprintf.Conviene indicar tambin que las instrucciones se separan por ";".Compiladores de CUn compilador es un programa que convierte nuestro cdigo fuente en un programa ejecutable (Me imagino que la mayora ya lo sabe, pero ms vale asegurar). El ordenador trabaja con 0 y 1. Si escribiramos un programa en el lenguaje del ordenador nos volveramos locos. Para eso estn lenguajes como el C. Nos permiten escribir un programa de manera que sea fcil entenderlo por una persona (elcdigo fuente). Luego es el compilador el que se encarga de convertirlo al complicado idioma de un ordenador.En la prctica a la hora de crear un programa nosotros escribimos el cdigo fuente, en nuestro caso en C, que normalmente ser un fichero de texto normal y corriente que contiene las instrucciones de nuestro programa. Luego se lo pasamos al compilador y este se encarga de convertirlo en un programa.Si tenemos el cdigo fuente podemos modificar el programa tantas veces como queramos (slo tenemos que volver a compilarlo), pero si tenemos el ejecutable final no podremos cambiar nada (realmente s se puede pero es mucho ms complicado y requiere ms conocimientos).Siguiendo la filosofa de mi pgina los compiladores que usaremos sern gratutos. Si vas a programar en Windows te recomiendo usar el Dev-C++, de fcil instalacin y manejo. Tambin recomiendo usar elDJGPPpara MS-Dos y Windows y el GNUC(gcc.gnu.org) para Linux.

El editorEl compilador en s mismo slo es un programa que traduce nuestro cdigo fuente y lo convierte en un ejecutable. Para escribir nuestros programas necesitamos un editor. La mayora de los compiladores al instalarse incorporan ya un editor; es el caso de los conocidos Turbo C, Borland C, Visual C++,... Pero otros no lo traen por defecto. No debemos confundir por tanto el editor con el compilador. Estos editores suelen tener unas caractersticas que nos facilitan mucho el trabajo: permiten compilar y ejecutar el programa directamente, depurarlo (corregir errores), gestionar complejos proyectos,...Si nuestro compilador no trae editor la solucin ms simple en MS-Dos puede ser usar el edit, en windows el notepad. Pero no son ms que editores sin ninguna otra funcionalidad. Otra posibilidad es un entorno de desarrollo llamado RHIDE, un programa muy til que automatiza muchas de las tareas del programador (del estilo del TurboCy Turbo Pascal). Si queremos una herramienta muy avanzada podemos usar Emacs, que es un editor muy potente, aunque para algunos puede parecer muy complicado (valientes y a por ello). Estos dos programas estn disponibles tanto en Linux como en MS-Dos.El primer programa:Hola MundoEn un alarde de originalidad vamos a hacer nuestro primer programa: hola mundo. Nadie puede llegar muy lejos en el mundo de la programacin sin haber empezado su carrera con este original y funcional programa. All va:#include

int main() { printf("Hola mundo\n"); return 0;}Nota:Hay mucha gente que programa en Windows que se queja de que cuando ejecuta el programa no puede ver el resultado. Para evitarlo se puede aadir antes de return 0; la siguiente lnea: system("PAUSE");Si esto no funciona prueba a aadir getch();Otra nota:En compiladores MS Windows, para poder usar la funcin system() debes aadir al principio del fichero la lnea: #include Qu fcil eh? Este programa lo nico que hace es sacar por pantalla el mensaje:Hola mundoVamos ahora a comentar el programa lnea por lnea (Esto no va a ser ms que una primera aproximacin).#include #include es lo que se llama una directiva. Sirve para indicar al compilador que incluya otro archivo. Cuando en compilador se encuentra con esta directiva la sustituye por el archivo indicado. En este caso es el archivo stdio.h que es donde est definida la funcin printf, que veremos luego.int main()Es la funcin principal del programa. Todos los programas deCdeben tener una funcin llamada main. Es la que primero se ejecuta. Elint(viene de Integer=Entero) que tiene al principio significa que cuando la funcin main acabe devolver un nmero entero. Este valor se suele usar para saber cmo ha terminado el prorama. Normalmente este valor ser 0 si todo ha ido bien, o un valor distinto si se ha producido algn error (pero esto lo decidimos nosotros, ya lo veremos). De esta forma si nuestro programa se ejecuta desde otro el programa 'padre' sabe como ha finalizado, si ha habido errores o no.Se puede usar la definicin 'void main()', que no necesita devolver ningn valor, pero se recomienda la forma con 'int' que es ms correcta. A lo largo de este curso vers muchos ejemplos que uso 'void main' y falta el return 0; del final, el cdigo funciona correctamente pero puede dar un 'warning' al compilar. En estos momentos estoy intentando corregir esto, pido perdn por las molestias.{Son las llaves que indican el comienzo de una funcin, en este caso la funcin main./* Aqu va el cuerpo del programa */Esto es un comentario, no se ejecuta. Sirve para describir el programa. Conviene acostumbrarse a comentar los programas. Un comentario puede ocupar ms de una lnea. Por ejemplo el comentario:/* Este es un comentario que ocupa dos filas */es perfectamente vlido.printf( "Hola mundo\n" );Aqu es donde por fin el programa hace algo que podemos ver al ejecutarlo. La funcin printf muestra un mensaje por la pantalla. Al final del mensaje "Hola mundo" aparece el smbolo '\n'; este hace que despus de imprimir el mensaje se pase a la lnea siguiente.Fjate en el ";" del final. Es la forma que se usa enCpara separar una instruccin de otra. Se pueden poner varias en la misma lnea siempre que se separen por el punto y coma.return 0;Como he indicado antes el programa al finalizar develve un valor entero. Como en este programa no se pueden producir errores (nunca digas nunca jams) la salida siempre ser 0. La forma de hacer que el programa devuelva un 0 es usando return. Esta lnea significa 'finaliza la funcin main haz que devuelva un 0.}...y cerramos llaves con lo que termina el programa. Todos los programas finalizan cuando se llega al final de la funcin main.Cmo se hace?Primero debemos crear el cdigo fuente del programa. Para nuestro primer programa el cdigo fuente es el del listado anterior. Arranca tu compilador de C, sea cual sea. Crea un nuevo fichero y copia el cdigo anterior. Llmalo por ejemploprimero.c.Ahora, tenemos que compilar el programa para crear el ejecutable. Si tu compilador es de windows, o tiene mens busca una opcin llamada "compile", o make, build o algo as.Si estamos usando DJGPP (ver informacin sobreinstalacin y uso de DJGPP): tenemos que llamarlo desde la lnea de comando:gcc -c primero.c -o primero.exeSi usamos Rhide basta con hacer CTRL-F9.Nota adicional sobre los comentariosLos comentarios se pueden poner casi en cualquier parte. Excepto en medio de una instruccin. Por ejemplo lo siguiente no es vlido:pri/* Esto es un comentario */ntf( "Hola mundo" );GARRAFALNo podemos cortar a printf por en medio, tendramos un error al compilar. Lo siguiente no dara error (al menos usando DJGPP), pero es una fea costumbre:printf( /* Esto es un comentario */ "Hola mundo" );Y por ltimo tenemos:printf( "Hola/* Esto es un comentario */ mundo" );Que no dara error, pero al ejecutar tendramos:Hola /* Esto es un comentario */ mundoporque/* Esto es un comentario */queda dentro de las comillas yClo interpreta como texto, no como un comentario.EjerciciosBusca los errores en este programa:int main(){/* Aqu va el cuerpo del programa */Printf( "Hola mundo\n" );return 0;}Solucin:Si lo compilamos posiblemente obtendremos un error que nos indicar que no hemos definido la funcin 'Printf'. Esto es porque no hemos includo la dichosa directiva '#include '. (En algunos compiladores no es necesario incluir esta directiva, pero es una buena costumbre hacerlo).Si lo corregimos y volvemos a compilar obtendremos un nuevo error. Otra vez nos dice que desconoce 'Printf'. Esta vez el problema es el de las maysculas que hemos indicado antes. Lo correcto es poner 'printf' con minsculas. Parece una tontera, pero seguro que nos da ms de un problema.

Mostrando Informacin por pantallaContenido del captulo Printf: Imprimir en pantalla Gotoxy: Posicionando el cursor (DOS) Clrscr: Borrar la pantalla (DOS) Borrar la pantalla (otros sistemas) Qu sabemos hacer? EjerciciosPrintf: Imprimir en pantallaSiempre he credo que cuando empiezas con un nuevo lenguaje suele gustar el ver los resultados, ver que nuestro programa hace 'algo'. Por eso creo que el curso debe comenzar con la funcin printf, que sirve para sacar informacin por pantalla.Para utilizar la funcin printf en nuestros programas debemos incluir la directiva:#include al principio de programa. Como hemos visto en el programahola mundo.Si slo queremos imprimir una cadena basta con hacer (no olvides el ";" al final):printf( "Cadena" );Esto resultar por pantalla:CadenaLo que pongamos entre las comillas es lo que vamos a sacar por pantalla.Si volvemos a usar otro printf, por ejemplo:

#include

int main(){printf( "Cadena" );printf( "Segunda" );

return 0;}Obtendremos:CadenaSegundaEste ejemplo nos muestra cmo funciona printf. Para escribir en la pantalla se usa un cursor que no vemos. Cuando escribimos algo el cursor va al final del texto. Cuando el texto llega al final de la fila, lo siguiente que pongamos ir a la fila siguiente. Si lo que queremos es sacar cada una en una lnea deberemos usar "\n". Es el indicador de retorno de carro. Lo que hace es saltar el cursor de escritura a la lnea siguiente:#include

int main(){printf( "Cadena\n" );printf( "Segunda" );

return 0;}y tendremos:CadenaSegundaTambin podemos poner ms de una cadena dentro del printf:printf( "Primera cadena" "Segunda cadena" );Lo que no podemos hacer es metercosasentre las cadenas:printf( "Primera cadena" texto en medio "Segunda cadena" );esto no es vlido. Cuando el compilador intenta interpretar esta sentencia se encuentra"Primera cadena"y luegotexto en medio, no sabe qu hacer con ello y da un error.Pero qu pasa si queremos imprimir el smbolo"en pantalla? Por ejemplo imaginemos que queremos escribir:Esto es "extrao"Si para ello hacemos:printf( "Esto es "extrao"" );Obtendremos unos cuantos errores. El problema es que el smbolo"se usa para indicar al compilador el comienzo o el final de una cadena. As que en realidad le estaramos dando la cadena "Esto es", luegoextraoy luego otra cadena vaca"". Pues resulta que printf no admite esto y de nuevo tenemos errores.La solucin es usar\". Veamos:printf( "Esto es \"extrao\"" );Esta vez todo ir como la seda. Como vemos la contrabarra '\' sirve para indicarle al compilador que escriba caracteres que de otra forma no podramos.Esta contrabarra se usa en C para indicar al compilador que queremos meter smbolos especiales. Pero Y si lo que queremos es usar '\' como un carcter normal y poner por ejemplo Hola\Adis? Pues muy fcil, volvemos a usar '\':printf( "Hola\\Adis" );y esta doble '\' indica a C que lo que queremos es mostrar una '\'.Esto no ha sido ms que una introduccin a printf. Luego volveremos sobre ella.Gotoxy: Posicionando el cursor (DOS)Esta funcin slo est disponible en compiladores de C que dispongan de la biblioteca Hemos visto que cuando usamosprintfse escribe en la posicin actual del cursor y se mueve el cursor al final de la cadena que hemos escrito.Vale, pero qu pasa cuando queremos escribir en una posicin determinada de la pantalla? La solucin est en la funcin gotoxy. Supongamos que queremos escribir 'Hola' en la fila 10, columna 20 de la pantalla:#include #include

int main(){gotoxy( 20, 10 );printf( "Hola" );

return 0;}(Nota: para usar gotoxy hay que incluir la bibliotecaconio.h).Fjate que primero se pone la columna (x) y luego la fila (y). La esquina superior izquierda es la posicin (1, 1).Clrscr: Borrar la pantalla (DOS)Ahora ya slo nos falta saber cmo se borra la pantalla. Pues es tan fcil como usar:clrscr()(clearscreen, borrar pantalla).Esta funcin n solo borra la pantalla, sino que adems sita el cursor en la posicin (1, 1), en la esquina superior izquierda.#include #include

int main(){clrscr();printf( "Hola" );

return 0;}Este mtodo slo vale para compiladores que incluyan el fichero stdio.h. Si tu sistema no lo tiene puedes consultar la seccin siguiente.Borrar la pantalla (otros mtodos)Existen otras formas de borrar la pantalla aparte de usar stdio.h.Si usas DOS:system ("cls"); //Para DOSSi usas Linux:system ("clear"); // Para LinuxOtra forma vlida para ambos sistemas:char a[5]={27,'[','2','J',0}; /* Para ambos (en DOS cargando antes ansi.sys) */printf("%s",a);Qu sabemos hacer?Bueno, ya hemos aprendido a sacar informacin por pantalla. Si quieres puedes practicar con las instrucciones printf, gotoxy y clrscr. Lo que hemos visto hasta ahora no tiene mucho secreto, pero ya veremos cmo la funcin printf tiene mayor complejidad. EjerciciosEjercicio 1:Busca los errores en el programa.#include

int main(){ClrScr();gotoxy( 10, 10 )printf( Estoy en la fila 10 columna 10 );return 0;}Solucin: ClrScr est mal escrito, debe ponerse todo en minsculas, recordemos una vez ms que elCdiferencia las maysculas de las minsculas. Adems no hemos includo la directiva #include , que necesitamos para usar clrscr() y gotoxy(). Tampoco hemos puesto el punto y coma (;) despus del gotoxy( 10, 10 ). Despus de cada instruccin debe ir un punto y coma. El ltimo fallo es que el texto del printf no lo hemos puesto entre comillas. Lo correcto sera: printf( "Estoy en la fila 10 columna 10" );Ejercicio 2. Escribe un programa que borre la pantalla y escriba en la primera lnea su nombre y en la segunda su apellido:

Solucin:#include #include

int main(){clrscr();printf( "Gorka\n" );printf( "Urrutia" );return 0;}Tambin se poda haber hecho todo de golpe:#include #include

int main(){clrscr();printf( "Gorka\nUrrutia" );return 0;}Ejercicio 3. Escriba un programa que borre la pantalla y muestre el texto "estoy aqui" en la fila 10, columna 20 de la pantalla:Solucin:#include #include int main(){clrscr();gotoxy( 20, 10 );printf( "Estoy aqui" );return 0;}Tipos de DatosContenido del Captulo Introduccin Notas sobre los nombres de las variables El tipo Int Declaracin de variables Imprimir Asignar Operaciones El tipo Char El modificador Unsigned El tipo Float El tipo Double Cmo calcular el mximo valor que admite un tipo de datos Overflow: Cuando nos saltamos el rango Resumen de los tipos de datos en C EjerciciosIntroduccinCuando usamos un programa es muy importante manejar datos. EnCpodemos almacenar los datos en variables. El contenido de las variables se puede ver o cambiar en cualquier momento. Estas variables pueden ser de distintos tipos dependiendo del tipo de dato que queramos meter. No es lo mismo guardar un nombre que un nmero. Hay que recordar tambin que la memoria del ordenador es limitada, as que cuando guardamos un dato, debemos usar slo la memoria necesaria. Por ejemplo si queremos almacenar el nmero 400 usaremos una variable tipoint(la estudiamos ms abajo) que ocupa slo 16 bits, y no una de tipolongque ocupa 32 bits. Si tenemos un ordenador con 32Mb de RAM parece una tontera ponernos a ahorrar bits (1Mb=1024Kb, 1Kb=1024bytes, 1byte=8bits), pero si tenemos un programa que maneja muchos datos puede no ser una cantidad despreciable. Adems ahorrar memoria es una buena costumbre.(Por si alguno tiene dudas: No hay que confundir la memoria con el espacio en el disco duro. Son dos cosas distintas. La capacidad de ambos se mide en bytes, y la del disco duro suele ser mayor que la de la memoria RAM. La informacin en la RAM se pierde al apagar el ordenador, la del disco duro permanece. Cuando queremos guardar un fichero lo que necesitamos es espacio en el disco duro. Cuando queremos ejecutar un programa lo que necesitamos es memoria RAM. La mayora me imagino que ya lo sabes, pero me he encontrado muchas veces con gente que los confunde.)Notas sobre los nombres de las variablesA las variables no se les puede dar cualquier nombre. No se pueden poner ms que letras de la 'a' a la 'z' (la no vale), nmeros y el smbolo '_'. No se pueden poner signos de admiracin, ni de interrogacin... El nombre de una variable puede contener nmeros, pero su primer carcter no puede serlo.Ejemplos de nombres vlidos:camionesnumerobuffera1j10hola29num_alumnosEjemplos de nombres no vlidos:1abcnombre?num/alumnosTampoco valen como nombres de variable laspalabras reservadasque usa el compilador. Por ejemplo:for, main, do, while.Por ltimo es interesante sealar que elCdistingue entre maysculas y minsculas. Por lo tanto:NombrenombreNOMBREseran tres variables distintas.El tipo IntEn una variable de este tipo se almacenan nmeros enteros (sin decimales). El rango de valores que admite es -32767 a 32767. Cuando definimos una variable lo que estamos haciendo es decirle al compilador que nos reserve una zona de la memoria para almacenar datos de tipo int. Para guardarla necesitaremos 16 bits de la memoria del ordenador (216=32767). Para poder usar una variable primero hay que declararla (definirla). Hay que decirle al compilador que queremos crear una variable y hay que indicarle de qu tipo. Por ejemplo:int numero;Esto hace que declaremos una variable llamadanumeroque va a contener un nmero entero.Pero dnde se declaran las variables?Tenemos dos posibilidades, una es declararla como global y otra como local. Por ahora vamos a decir que global es aquella variable que se declara fuera de la funcin main y local la que se declara dentro:Variable GlobalVariable Local

#include

int x;

int main(){}

#include

int main(){int x;}

La diferencia prctica es que las variables globales se pueden usar en cualquier procedimiento. Las variables locales slo pueden usarse en el procedimiento en el que se declaran. Como por ahora slo tenemos el procedimiento (o funcin, o rutina, o subrutina, como prefieras)mainesto no debe preocuparnos mucho por ahora. Cuando estudiemos cmo hacer un programa con ms funciones aparte de main volveremos sobre el tema. Sin embargo debes saber que es buena costumbre usar variables locales que globales. Ya veremos por qu.Podemos declarar ms de una variable en una sola lnea:int x, y;Mostrar variables por pantallaVamos a ir u poco ms all con la funcin printf. Supongamos que queremos mostrar el contenido de la variablexpor pantalla:printf( "%i", x );Suponiendo que x valga 10 (x=10) en la pantalla tendramos:10Empieza a complicarse un poco no? Vamos poco a poco. Recuerdas el smbolo "\" que usbamos para sacar ciertos caracteres? Bueno, pues el uso del "%" es parecido. "%i" no se muestra por pantalla, se sustituye por el valor de la variable que va detrs de las comillas. ( %i, de integer=entero en ingls).Para ver el contenido de dos variables, por ejemplo x e y, podemos hacer:printf( "%i ", x );printf( "%i", y );resultado (suponiendo x=10, y=20):10 20Pero hay otra forma mejor:printf( "%i %i", x, y );... y as podemos poner el nmero de variables que queramos. Obtenemos el mismo resultado con menos trabajo. No olvidemos que por cada variable hay que poner un %i dentro de las comillas.Tambin podemos mezclar texto con enteros:printf( "El valor de x es %i, que bien!\n", x );que quedar como:El valor de x es 10, que bien!Como vemos %i al imprimir se sustituye por el valor de la variable.Asignar valores a variables de tipo intLa asignacin de valores es tan sencilla como:x = 10;Tambin se puede dar un valor inicial a la variable cuando se define:int x = 15;Tambin se pueden inicializar varias variables en una sola lnea:int x = 15, y = 20;Hay que tener cuidado con lo siguiente:int x, y = 20;Podramos pensar que x e y son igual a 20, pero no es as. La variable x est sin valor inicial y la variable 'y' tiene el valor 20.Veamos un ejemplo para resumir todo:#include

int main(){int x = 10;

prinft( "El valor inicial de x es %i\n", x );x = 50;printf( "Ahora el valor es %i\n", x );}Cuya salida ser:El valor inicial de x es 10Ahora el valor es 50Importante!Si imprimimos una variable a la que no hemos dado ningn valor no obtendremos ningn error al compilar pero la variable tendr un valor cualquiera. Prueba el ejemplo anterior quitandoint x = 10;Puede que te imprima el valor 10 o puede que no.El tipo CharLas variables de tipo char sirven para almacenar caracteres. Los caracteres se almacenan en realidad como nmeros del 0 al 255. Los 128 primeros (0 a 127) son el ASCII estndar. El resto es el ASCII extendido y depende del idioma y del ordenador. Consultala tabla ASCIIen el anexo.Para declarar una variable de tipo char hacemos:char letra;En una variable charslo podemos almacenar solo una letra, no podemos almacenar ni frases ni palabras. Eso lo veremos ms adelante (strings, cadenas). Para almacenar un dato en una variable char tenemos dos posibilidades:letra = 'A'; oletra = 65;En ambos casos se almacena la letra 'A' en la variable. Esto es as porque el cdigo ASCII de la letra 'A' es el 65.Para imprimir un char usamos el smbolo %c (c de character=caracter en ingls):

letra = 'A';printf( "La letra es: %c.", letra );resultado:La letra es A.Tambin podemos imprimir el valor ASCII de la variable usando %i en vez de %c:letra = 'A';printf( "El nmero ASCII de la letra %c es: %i.", letra, letra );resultado:El cdigo ASCII de la letra A es 65.Como vemos la nica diferencia para obtener uno u otro es el modificador (%c %i) que usemos.Las variables tipo char se pueden usar (y de hecho se usan mucho) para almacenar enteros. Si necesitamos un nmero pequeo (entre -127 y 127) podemos usar una variable char (8bits) en vez de una int (16bits), con el consiguiente ahorro de memoria.Todo lo dems dicho para los datos de tipointse aplica tambin a los de tipochar.Una curiosidad:letra = 'A';printf( "La letra es: %c y su valor ASCII es: %i\n", letra, letra );letra = letra + 1;printf( "Ahora es: %c y su valor ASCII es: %i\n", letra, letra );En este ejemploletracomienza con el valor 'A', que es el cdigo ASCII 65. Al sumarle 1 pasa a tener el valor 66, que equivale a la letra 'B' (cdigo ASCII 66). La salida de este ejemplo sera:La letra es A y su valor ASCII es 65Ahora es B y su valor ASCII es 66

El modificador UnsignedEste modificador (que significasin signo) modifica el rango de valores que puede contener una variable. Slo admite valores positivos. Si hacemos:unsigned char variable;Esta variable en vez de tener un rango de -128 a 128 pasa a tener un rango de 0 a 255.El tipo FloatEn este tipo de variable podemos almacenar nmeros decimales, no slo enteros como en los anteriores. El rango de posibles valores es del 3,4E-38 al 3,4E38.Declaracin de una variable de tipo float:float numero;Para imprimir valores tipo float Usamos %f.float num=4060.80;printf( "El valor de num es : %f", num );

Resultado:

El valor de num es: 4060.80Si queremos escribirlo en notacin exponencial usamos %e:float num = 4060.80;printf( "El valor de num es: %e", num );

Que da como resultado:

El valor de num es: 4.06080e003

El tipo DoubleEn las variables tipo double se almacenan nmeros reales del 1,7E-307 al 1,7E308. Se declaran comodouble:double numero;Para imprimir se usan los mismos modificadores que en float.Cmo calcular el mximo valor que admite un tipo de datosLo primero que tenemos que conocer es el tamao en bytes de ese tipo de dato. Vamos a ver un ejemplo con el tipo INT. Hagamos el siguiente programa:#include

int main() { int num1;

printf( "El tipo int ocupa %i bytes\n", sizeof(int) ); }Comprobado con DJGPPEn mi ordenador el resultado es:El tipo int ocupa 4 bytes.Como sabemos 1byte = 8bits. Por lo tanto el tipo int ocupa 4*8=32 bits.Ahora para calcular el mximo nmero debemos elevar 2 al nmero de bits obtenido. En nuestro ejemplo: 2^32=4.294.967.296. Es decir en un int se podra almacenar un nmero entre 0 y 4.294.967.296.Sin embargo esto slo es cierto si usamos un tipo unsigned (sin signo, se hace aadiendo la palabra unsigned antes de int). Para los tipos normales tenemos que almacenar nmeros positivos y negativos. As que de los 4.294.967.296 posibles nmeros la mitad sern positivos y la mitad negativos. Por lo tanto tenemos que dividir el nmero anterior entre 2 = 2.147.483.648. Como el 0 se considera positivo el rango de nmeros posibles que se pueden almacenar en un int sera: -2.147.483.648 a 2.147.483.647.Resumen:1. Obtenemos el nmero de bytes.2. Multiplicamos por ocho (ya lo tenemos en bits).3. Elevamos 2 al nmero de bits.4. Dividimos entre 2.Overflow: Qu pasa cuando nos saltamos el rangoEloverflowes lo que se produce cuando intentamos almacenar en una variable un nmero mayor del mximo permitido. El comportamiento es distinto para variablesde nmeros enteros y para variables de nmeros en coma flotante.Con nmeros enterosEn mi ordenador y usando DJGPP bajo Dos el tamao del tipo int es de 4bytes(4*8=32bits). El nmero mximo que se puede almacenar en una variable tipo int es por tanto 2.147.483.647 (ver apartado anterior). Si nos pasamos de este nmero el que se guardar ser el siguiente pero empezando desde el otro extremo, es decir, el -2.147.483.648. El compilador seguramente nos dar un aviso (warning) de que nos hemos pasado.#include

int main() { int num1;

num1 = 2147483648; printf( "El valor de num1 es: %i\n", num1 ); }Comprobado con DJGPPEl resultado que obtenemos es:El valor de num1 es: -2147483648Comprueba si quieres que con el nmero anterior (2.147.483.647) no pasa nada.Con nmeros en coma flotanteEl comportamiento con nmeros en coma flotante es distinto. Dependiendo del ordenador si nos pasamos del rango al ejecutar un programa se puede producir un error y detenerse la ejecucin.Con estos nmeros tambin existe otro error que es elunderflow. Este error se produce cuando almacenamos un nmero demasiado pequeo (3,4E-38 en float).Resumen de los tipos de datos en CEsto es algo orientativo, depende del sistema.TipoDatos almacenadosN de BitsValores posibles (Rango)Rango usando unsigned

charCaracteres8-128 a 1280 a 255

intenteros16-32.767 a 32.7670 a 65.535

longenteros largos32-2.147.483.647 a 2.147.483.6470 a 4.294.967.295

floatNums. reales (coma flotante)323,4E-38 a 3,4E38

doubleNums. reales (coma flotante doble)641,7E-307 a 1,7E308

Esto no siempre es cierto, depende del ordenador y del compilador. Para saber en nuestro caso qu tamao tienen nuestros tipos de datos debemos hacer lo siguiente. Ejemplo para int:#include

int main(){printf( "Tamao (en bits) de int = %i\n", sizeof( int )*8 );return 0;}Ya veremos ms tarde lo que significa sizeof. Por ahora basta con saber que nos dice cual es el tamao de una variable o un tipo de dato.EjerciciosEjercicio 1. Busque los errores:#include

int main(){int nmero;

nmero = 2;return 0;}Solucin:Los nombres de variables no pueden llevar acentos, luego al compilar nmero dar error.#include

int main(){int numero;

numero = 2;

printf( "El valor es %i" Numero );return 0;}Solucin:Falta la coma despus de "El valor es %i". Adems la segunda veznumeroest escrito con maysculas.

Constantes (uso de #define)Contenido del CaptuloIntroduccinConstantes con nombreIntroduccinLas constantes son aquellos datos que no pueden cambiar a lo largo de la ejecucin de un programa.#include

int main(){int radio, perimetro;

radio = 20;perimetro = 2 * 3.1416 * radio;

printf( "El permetro es: %i", perimetro );return 0;}radioyperimetroson variables, su valor puede cambiar a lo largo del programa. Sin embargo 20, 2 y 3.1416 son constantes, no hay manera de cambiarlas. El valor 3.1416 no cambia a lo largo del programa , ni entre ejecucin y ejecucin. Slo cambiar cuando edites el programa y lo cambies tu mismo. Esto es obvio, y no tiene ningn misterio as que no le des vueltas. Slo quera indicarlo porque en algunos libros le dan muchas vueltas.

Constantes con nombreSupongamos que tenemos que hacer un programa en el que haya que escribir unas cuantas veces 3.1416 (como todos sabreis es PI). Es muy fcil que nos confundamos alguna vez al teclearlo y al compilar el programa no tendremos ningn error, sin embargo el programa no dar resultados correctos. Para evitar esto usamos las constantes con nombre. Al definir una constante con nombre estamos dando un nombre al valor, a 3.1416 le llamamos PI.Estas constantes se definen de la manera siguiente:#define nombre_de_la_constantevalor_de_la_constanteEjemplo:#include

#define PI3.1416

int main(){int radio, perimetro;

radio = 20;perimetro = 2 * PI * radio;

printf( "El permetro es: %i", perimetro );return 0;}De esta forma cada vez que el compilador encuentre el nombre PI lo sustituir por 3.1416.A una constante no se le puede dar un valor mientras se ejecuta, no se puede hacer PI = 20;. Slo se le puede dar un valor con #define, y slo una vez. Tampoco podemos usar el scanf para dar valores a una constante:#define CONSTANTE14

int main(){...scanf( "%i", CONSTANTE );...}eso sera como hacer:scanf( "%i", 14 );Esto es muy grave, estamos diciendo que el valor que escribamos en scanf se almacene en la posicin 14 de la memoria, lo que puede bloquear el ordenador.Las constantes se suelen escribir en maysculas slo se puede definir una constante por fila.No se pone ";" al final.Las constantes nos proporcionan una mejor comprensin del cdigo fuente. Mira el siguiente programa:#include

int main(){int precio;

precio = ( 4 * 25 * 100 ) * ( 1.16 );printf( "El precio total es: %i", precio );return 0;}Quien entiende lo que quiere decir este programa? Es difcil si no imposible. Hagmoslo de otra forma.#include

#define CAJAS4#define UNIDADES_POR_CAJA25#define PRECIO_POR_UNIDAD 100#define IMPUESTOS1.16

int main(){int precio;

precio = ( CAJAS * UNIDADES_POR_CAJA * PRECIO_POR_UNIDAD ) * ( IMPUESTOS );printf( "El precio total es: %i", precio );return 0;}A que ahora se entiende mejor? Claro que s. Los nmeros no tienen mucho significado y si revisamos el programa un tiempo ms tarde ya no nos acordaremos qu cosa era cada nmero. De la segunda forma nos enteraremos al momento.

Tambin podemos definir una constante usando el valor de otras. Por supuesto las otras tienen que estar definidas antes:#include #define CAJAS4#define UNIDADES_POR_CAJA25#define PRECIO_POR_UNIDAD100#define PRECIO_POR_CAJAUNIDADES_POR_CAJA * PRECIO_POR_UNIDAD#define IMPUESTOS1.16int main(){int precio;

precio = ( CAJAS * PRECIO_POR_CAJA ) * ( IMPUESTOS );printf( "El precio total es: %i", precio );return 0;}#define tiene ms usos aparte de ste, ya los veremos en el captulo de directivas.

Manipulando datos (Operadores)Contenido del captulo Introduccin, Qu es un operador? Operador = : Asignacin Operadores aritmticos Suma (+) Incremento (++) Resta/Negativo (-) Decremento (--) Multiplicacin (*) Divisin (/) Resto (%) Operadores de comparacin Operadores lgicos Introduccin a los bits y bytes Operadores de bits Operador sizeof Otros Operadores Orden de evaluacin de operadores EjerciciosQu es un operador?Un operador sirve para manipular datos. Los hay de varios tipos: de asignacin, de relacin, lgicos, aritmticos y de manipulacin de bits. En realidad los nombres tampoco importan mucho; aqu lo que queremos es aprender a programar, no aprender un montn de nombres.Operador de asignacinEste es un operador que ya hemos visto en el captulo de Tipos de Datos. Sirve para dar un valor a una variable. Este valor puede ser un nmero que tecleamos directamente u otra variable:a = 3;/* Metemos un valor directamente */oa = b;/* Le damos el valor de una variable */

Podemos dar valores a varias variables a la vez:a = b = c = 10;/* Damos a las variables a,b,c el valor 10 */Tambin podemos asignar a varias variables el valor de otra de un slo golpe:a = b = c = d;/* a,b,c toman el valor de d */Operadores aritmticosLos operadores aritmticos son aquellos que sirven para realizar operaciones tales como suma, resta, divisin y multiplicacin.Si quieres saber cmo usar funciones matemticas ms complejas (exponentes, races, trigonomtricas) vete alcaptulo correspondiente.Operador (+) : SumaEste operador permite sumar variables:#include

int main(){int a = 2;int b = 3;int c;c = a + b;printf ( "Resultado = %i\n", c );}El resultado ser 5 obviamente.Por supuesto se pueden sumar varias variables o variables ms constantes:#include

int main(){int a = 2;int b = 3;int c = 1;int d;

d = a + b + c + 4;printf ( "Resultado = %i\n", c );}El resultado es 10.Podemos utilizar este operador para incrementar el valor de una variable:x = x + 5;Pero existe una forma abreviada:x += 5;Esto suma el valor 5 al valor que tena la variable x. Veamos un ejemplo:#include

int main(){int x, y;

x = 3;y = 5;

x += 2;printf( "x = %i\n", x );x += y;/* esto equivale a x = x + y */printf( "x = %i\n", x );}Resultado:x = 5x = 10Operador (++) : IncrementoEste operador equivale a sumar uno a la variable:#include

int main(){int x = 5;

printf ( "Valor de x = %i\n", x );x++;printf ( "Valor de x = %i\n", x );}Resultado:Valor de x = 5Valor de x = 6Se puede poner antes o despus de la variable.Operador (-) : Resta/NegativoEste operador tiene dos usos, uno es la resta que funciona como el operador suma y el otro es cambiar de signo.Resta:x = x - 5;Para la operacin resta se aplica todo lo dicho para la suma. Se puede usar tambin como:x -= 5;.Pero tambin tiene el uso de cambiar de signo. Poniendolo delante de una variable o constante equivale a multiplicarla por -1.#include

int main(){int a, b;

a = 1;

b = -a;printf( "a = %i, b = %i\n", a, b );}Resultado: a = 1, b = -1. No tiene mucho misterio.Operador (--) : DecrementoEs equivalente a ++ pero en vez de incrementar disminuye el valor de la variable. Equivale a restar uno a la variable.Operador (*) : Multiplicacin y punterosEste operador sirve para multiplicar y funciona de manera parecida a los anteriores.Tambin sirve para definir y utilizar punteros, pero eso lo veremos ms tarde.

Operador (/) : DivisinEste funciona tambin como los anteriores pero hay que tener cuidado. Si dividimos dos nmero en coma flotante (tipo float) tenemos las divisin con sus correspondientes decimales. Pero si dividimos dos enteros obtenemos un nmero entero. Es decir que si dividimos 4/3 tenemos como resultado 1. El redondeo se hace por truncamiento, simplemente se eliminan los decimales y se deja el entero.Si dividimos dos enteros el resultado es un nmero entero, aunque luego lo saquemos por pantalla usando %f o %d no obtendremos la parte decimal.Cuando dividimos dos enteros, si queremos saber cual es el resto (o mdulo) usamos el operador %, que vemos ms abajo.Operador (%) : RestoSi con el anterior operador obtenamos el mdulo o cociente de una divisin entera con ste podemos tener el resto. No funciona ms que con enteros, no vale para nmeros float o double.Cmo se usa:#include

int main(){int a, b;

a = 18;b = 5;printf( "Resto de la divisin: %d \n", a % b );}

Operadores de comparacinLos operadores de condicin se utilizan para comprobar las condiciones de las sentencias de control de flujo (las estudiaremos en el captulo sentencias).Cuando se evala una condicin el resultado que se obtiene es 0 si no se cumple y un nmero distinto de 0 si se cumple. Normalmente cuando se cumplen devuelven un 1.Los operadores de comparacin son:==igual quese cumple si son iguales

!=distinto quese cumple 1 si son diferentes

>mayor quese cumple si el primero es mayor que el segundo

=mayor o igual quese cumple si el primero es mayor o igual que el segundo

5 );printf( "10 > 5 da como resultado %i\n", 10>5 );printf( "5== 5 da como resultado %i\n", 5==5 );printf( "10==5 da como resultado %i\n", 10==5 );}No slo se pueden comparar constantes, tambin se pueden comparar variables.

Operadores lgicosEstos son los que nos permiten unir varias comparaciones: 10>5y6==6. Los operadores lgicos son: AND (&&), OR (||), NOT(!).Operador && (AND, en castellano Y): Devuelve un 1 si se cumplen dos condiciones.printf( "Resultado: %i", (10==10 && 5>2 );Operador || (OR, en castellano O): Devuelve un 1 si se cumple una de las dos condiciones.Operador ! (NOT, negacin): Si la condicin se cumple NOT hace que no se cumpla y viceversa.Ver el captuloSentencias, seccinNotas sobre las condicionespara ms informacin.Introduccin a los bits y bytesEn esta seccin voy a describir lo que son los bytes y los bits. No voy a descubrir nada nuevo, as que la mayora se podrn saltar esta seccin.Supongo que todo el mundo sabe lo que son los bytes y los bits, pero por si acaso all va. Los bits son la unidad de informacin ms pequea, digamos que son la base para almacenar la informacin. Son como los tomos a las molculas. Los valores que puede tomar un bit son 0 1. Si juntamos ocho bits tenemos un byte.Un byte puede tomar 256 valores diferentes (de 0 a 255). Cmo se consigue esto? Imaginemos nuestro flamante byte con sus ocho bits. Supongamos que los ocho bits valen cero. Ya tenemos el valor 0 en el byte. Ahora vamos a darle al ltimo byte el valor 1.00000001 -> 1Este es el uno para el byte. Ahora vamos a por el dos y el tres:00000010 -> 200000011 -> 3y as hasta 255. Como vemos con ocho bits podemos tener 256 valores diferentes, que en byte corresponden a los valores entre 0 y 255.Operadores de bitsYa hemos visto que un byte son ocho bits. Pues bien, con los operadores de bits podemos manipular las variablespor dentro. Los diferentes operadores de bits son:OperadorDescripcin

|OR (O)

&AND (Y)

^XOR (O exclusivo)

~Complemento a uno o negacin

>>Desplazamiento a la derecha

10001111 |239 -> 11101111La operacin OR funciona de la siguiente manera: Tomamos los bits dos a dos y los comparamossi alguno de ellos es uno, se obtiene un uno. Si ambos son cero el resultado es cero. Primero se compara los dos primeros (el primero de cada uno de los nmeros, 1 y 1 -> 1), luego la segunda pareja (1 y 0 -> 1) y as sucesivamente.Operador & (AND):Este operador compara los bits tambin dos a dos. Siambos son 1el resultado es 1. Si no, el resultado es cero.#include

int main(){printf( "El resultado de la operacin 170 & 155 es: %i\n", 170 & 155 );}Tenemos:El resultado de la operacin 170 & 155 es: 138A nivel de bits:170 -> 10101010155 -> 10011011 &138 -> 10001010Operador ^ (XOR):Compara los bits y los pone a unos si sondistintos.235 -> 11101011143 -> 10001111 ^100 -> 01100100Operador ~ (Complemento a uno):Este operador acepta un slo dato (operando) y pone a 0 los 1 y a 1 los 0, es decir los invierte. Se pone delante del operando.#include

int main(){printf( "El resultado de la operacin ~152 es: %i\n", ~152 );}

El resultado de la operacin ~152 es: 103152 -> 10011000 ~103 -> 01100111Operador >> (Desplazamiento a la derecha):Este operador mueve cada bit a la derecha. El bit de la izquierda se pone a cero, el de la derecha se pierde. Si realizamos la operacin inversa no recuperamos el nmero original. El formato es:variable o dato >> nmero de posiciones a desplazar

Elnmero de posiciones a desplazarindica cuantas veces hay que mover los bits hacia la derecha. Ejemplo:#include

int main(){printf( "El resultado de la operacin 150 >> 2 es: %i\n", ~152 );}

El resultado de la operacin 150 >> 2 es: 37Veamos la operacin paso a paso. Esta operacin equivale a hacer dos desplazamientos a la derecha:150 -> 10010110 Nmero original 75 -> 01001011 Primer desplazamiento. Entra un cero por la izquierda,el cero de la derecha se pierde y los dems se mueven a la derecha. 37 -> 00100101 Segundo desplazamiento.NOTA: Un desplazamiento a la izquierda equivale a dividir por dos. Esto es muy interesante porque el desplazamiento es ms rpido que la divisin. Si queremos optimizar un programa esta es una buena idea. Slo sirve para dividir entre dos. Si hacemos dos desplazamientos sera dividir por dos dos veces, no por tres.Operador .

! ~ ++ -- (molde) * & sizeof (El * es el de puntero)

* / % (El * de aqu es el de multiplicacin)

+ -

>

< >=

== !=

&

^

|

&&

||

?:

= += -= *= /=

,

Por ejemplo imaginemos que tenemos la siguiente operacin:10 * 2 + 5 Si vamos a la tabla de precedencias vemos que el * tiene un orden superior al +, por lo tanto primero se hace el producto 10*2=20 y luego la suma 20+5=25. Veamos otra:10 * ( 2 + 5 )Ahora con el parntesis cambia el orden de evaluacin. El que tiene mayor precedencia ahora es el parntesis, se ejecuta primero. Como dentro del parntesis slo hay una suma se evala sin ms, 2+5=7. Ya solo queda la multiplicacin 10*7=70. Otro caso:10 * ( 5 * 2 +3 )Como antes, el que mayor precedencia tiene es el parntesis, se evala primero. Dentro del parntesis tenemos producto y suma. Como sabemos ya se evala primero el producto, 5*2=10. Seguimos en el parntesis, nos queda la suma 10+3=13. Hemos acabado con el parntesis, ahora al resto de la expresin. Cogemos la multiplicacin que queda: 10*13=130.Otro detalle que debemos cuidar son los operadores ++ y --. Estos tienen mayor precedencia que las dems operaciones aritmticas (+, -, *, /, %). Por ejemplo:10 * 5 ++Puede parecer que primero se ejecutar la multiplicacin y luego el ++. Pero si vamos a la tabla de precedencias vemos que el ++ est por encima de * (de multiplicacin), por lo tanto se evaluar primero 5++=6. 10*6=60.Es mejor no usar los operadores ++ y -- mezclados con otros, pues a veces obtenemos resultados inesperados. Por ejemplo:#include

int main(){int a, b;

a = 5;b = a++;printf( "a = %i, b = %i\n", a, b );}Este ejemplo en unos compiladores dar a = 6, b = 5 y en otros a = 6 y b = 6. Por favor si podeis, escribidme diciendo qu valores os salen a vosotros y qu compilador usais.

Para asegurarse lo mejor sera separar la lnea donde se usa el ++ y el =:#include

int main(){int a, b;

a = 5;a++;b = a;printf( "a = %i, b = %i\n", a, b );}EjerciciosEjercicio 1:En este programa hay un fallo muy gordo y muy habitual en programacin. A ver si lo encuentras:#include

int main(){int a, c;

a = 5;c += a +5;}Solucin:Cuando calculamos el valor de 'c' sumamos a+5 ( =10 ) al valor de 'c'. Pero resulta que 'c' no tena ningn valor indicado por nosotros. Estamos usando la variable 'c' sin haberle dado valor. En algunos compiladores el resultado ser inesperado. Este es un fallo bastante habitual, usar variables a las que no hemos dado ningn valor.Ejercicio 2:Cual ser el resultado del siguiente programa?#include #include

int main() { int a, b, c;

a = 5; b = ++a; c = ( a + 5 * 2 ) * ( b + 6 / 2 ) + ( a * 2 ); printf( "%i, %i, %i", a, b, c ); }Solucin:El resultado es 156. En la primera a vale 5. Pero en la segunda se ejecuta b = ++a = ++5 = 6. Tenemos a = b = 6.Ejercicio 3:Escribir un programa que compruebe si un nmero es par o impar.Solucin:#include

int main() { char palabra[100]; int a; a = 124; if ( a % 2 == 0 ) printf( "%d es par\n", a ); else printf( "%d es impar\n", a ); printf( "\n" ); system( "pause" ); return 0;}

Fichero: cap5_ejercicio3.cPara comprobar si un nmero es par o impar podemos usar el operador '%'. Si al calcular el resto de dividir un nmero por 2 el resultado es cero eso indica que el nmero es par. Si el resto es distinto de cero el nmero es impar.

Introducir datos por tecladoContenido del captulo Introduccin Scanf Getch y getche EjerciciosIntroduccinAlgo muy usual en un programa es esperar que el usuario introduzca datos por el teclado. Para ello contamos con varias posibilidades: Usar las funciones de la biblioteca estndar, crear nuestras propias interrupciones de teclado (MS-Dos) o usar funciones de alguna biblioteca diferente (como por ejemplo Allegro).Nosotros en este captulo vamos a estudiar la primera, usando las funciones de la biblioteca estndar. Pero veamos por encima las otras posibilidades.Las funciones estndar estn bien para un programa sencillito. Pero cuando queremos hacer juegos por ejemplo, no suelen ser suficiente. Demasiado lentas o no nos dan todas las posibilidades que buscamos, como comprobar si hay varias teclas pulsadas. Para solucionar esto tenemos dos posibilidades:La ms complicada es crear nuestras propias interrupciones de teclado. Qu es una interrupcin de teclado? Es un pequeo programa en memoria que se ejecuta contnuamente y comprueba el estado del teclado. Podemos crear uno nuestro y hacer que el ordenador use el que hemos creado en vez del suyo. Este tema no lo vamos a tratar ahora, quizs en algn captulo posterior.Otra posibilidad ms sencilla es usar una biblioteca que tenga funciones para controlar el teclado. Por ejemplo si usamos la biblioteca Allegro, ella misma hace todo el trabajo y nosotros no tenemos ms que recoger sus frutos con un par de sencillas instrucciones. Esto soluciona mucho el trabajo y nos libra de tener que aprender cmo funcionan los aspectos ms oscuros del control del teclado.Vamos ahora con las funciones de la biblioteca estndar.

ScanfEl uso de scanf es muy similar al de printf con una diferencia, nos da la posibilidad de que el usuario introduzca datos en vez de mostrarlos. No nos permite mostrar texto en la pantalla, por eso si queremos mostrar un mensaje usamos un printf delante. Un ejemplo:#include int main(){int num;printf( "Introduce un nmero " );scanf( "%i", &num );printf( "Has tecleado el nmero %i\n", num );return 0;}Primero vamos a ver unas notas de esttica, para hacer los programas un poco ms elegantes. Parece una tontera, pero los pequeos detalles hacen que un programa gane mucho. El scanf no mueve el cursor de su posicin actual, as que en nuestro ejemplo queda:Introduce un nmero _ /* La barra horizontal indica dnde esta el cursor */Esto es porque en el printf no hemos puesto al final el smbolo de salto de lnea '\n'. Adems hemos dejado un espacio al final deIntroduce un nmero:para que as cuando tecleemos el nmero no salga pegado al mensaje. Si no hubisemos dejado el espacio quedara as al introducir el nmero 120 (es un ejemplo):Introduce un nmero120Bueno, esto es muy interesante pero vamos a dejarlo y vamos al grano. Veamos cmo funciona el scanf. Lo primero nos fijamos que hay una cadena entre comillas. Esta es similar a la de printf, nos sirve para indicarle al compilador qu tipo de datos estamos pidiendo. Como en este caso es un integer usamos %i. Despus de la coma tenemos la variable donde almacenamos el dato, en este caso 'num'.Fjate que en el scanf la variable 'num' lleva delante el smbolo&, este es muy importante, sirve para indicar al compilador cual es la direccin (o posicin en la memoria) de la variable. Por ahora no te preocupes por eso, ya volveremos ms adelante sobre el tema.

Podemos preguntar por ms de una variable a la vez en un slo scanf, hay que poner un %i por cada variable:#include

int main(){int a, b, c;

printf( "Introduce tres nmeros: " );scanf( "%i %i %i", &a, &b, &c );printf( "Has tecleado los nmeros %i %i %i\n", a, b, c );return 0;}De esta forma cuando el usuario ejecuta el programa debe introducir los tres datos separados por un espacio.Tambin podemos pedir en un mismo scanf variables de distinto tipo:#include int main(){int a;float b;

printf( "Introduce dos nmeros: " );scanf( "%i %f", &a, &b );

printf( "Has tecleado los nmeros %i %f\n", a, b );return 0;}A cada modificador (%i, %f) le debe corresponder una variable de su mismo tipo. Es decir, al poner un %i el compilador espera que su variable correspondiente sea de tipo int. Si ponemos %f espera una variable tipo float.Getch y getcheSi lo que queremos es que el usuario introduzca un caracter por el teclado usamos las funciones getch y getche. Estas esperan a que el usuario introduzca un carcter por el teclado. La diferencia entre getche y getch es que la primera saca por pantalla la tecla que hemos pulsado y la segunda no (la e del final se refiere aecho=eco). Ejemplos:

#include

int main(){char letra;

printf( "Introduce una letra: " );fflush( stdout );letra = getche();printf( "\nHas introducido la letra: %c", letra );return 0;}Resultado:Introduce una letra: aHas introducido la letra: aQuizs te ests preguntando qu es eso de fflush( stdout ). Pues bien, cuando usamos la funcin printf, no escribimos directamente en la pantalla, sino en una memoria intermedia (lo que llaman un bufer). Cuando este bufer se llena o cuando metemos un carcter '\n' es cuando se envia el texto a la pantalla. En este ejemplo yo quera que apareciera el mensajeIntroduce una letra:y el cursor se quedara justo despus, es decir, sin usar '\n'. Si se hace esto, en algunos compiladores el mensaje no se muestra en pantalla hasta que se pulsa una tecla (prubalo en el tuyo). Y la funcin fflush( stdout ) lo que hace es enviar a la pantalla lo que hay en ese bufer.Y ahora un ejemplo con getch:#include

int main(){char letra;

printf( "Introduce una letra: " );fflush( stdout );letra = getch();printf("\n has introducido la letra :%c", letra );return 0;}Resultado:Introduce una letra:Has introducido la letra: aComo vemos la nica diferencia es que en el primer ejemplo se muestra en pantalla lo que escribimos y en el segundo no.

EjerciciosEjercicio 1:Busca el error en el siguiente programa:#include

int main() { int numero; printf( "Introduce un nmero: " ); scanf( "%d", numero ); printf( "\nHas introducido el nmero %d.\n", numero ); return 0;}

Solucin:A la variable nmero le falta el '&' con lo que no estamos indicando al programa la direccin de la variable y no obtendremos el resultado deseado. Haz la prueba y vers que el mensaje "Has introducido el nmero X" no muestra el nmero que habas introducido.

Sentencias de control de flujoContenido del Captulo Introduccin Bucles For While Do While Sentencias de condicin If If else If else if ? (el otro if-else) Switch Sentencias de Salto goto break Salida de un programa: exit() Notas sobre las condiciones EjerciciosIntroduccinHasta ahora los programas que hemos visto eran lineales. Comenzaban por la primera instruccin y acababan por la ltima, ejecutndose todas una sola vez. . Lgico no? . Pero resulta que muchas veces no es esto lo que queremos que ocurra. Lo que nos suele interesar es que dependiendo de los valores de los datos se ejecuten unas instrucciones y no otras. O tambin puede que queramos repetir unas instrucciones un nmero determinado de veces. Para esto estn las sentencias de control de flujo.BuclesLos bucles nos ofrecen la solucin cuando queremos repetir una tarea un nmero determinado de veces. Supongamos que queremos escribir 100 veces la palabrahola. Con lo que sabemos hasta ahora haramos:

#include

int main(){printf( "Hola\n");printf( "Hola\n");printf( "Hola\n");printf( "Hola\n");printf( "Hola\n");... (y as hasta 100 veces)}Menuda locura! Y si queremos repetirlo ms veces nos quedara un programa de lo ms largo.Sin embargo usando un bucleforel programa quedara:#include int main(){int i;for ( i=0 ; i100 ){printf( "El nmero es mayor que 100\n" );}printf( "Fin del programa\n" );}El smbolo&&de la condicin del segundo if es un AND (Y). De esta forma la condicin queda:Si a es mayor que 10 Y a es menor que 100. Consulta la seccinNotas sobre condiciones para saber ms.Y as todos los if else que queramos. Si la condicin del primer if es verdadera se muestra el mensajeEl nmero introducido era menor de 10y se saltan todos los if-else siguientes (se muestraFin del programa). Si la condicin es falsa se ejecuta el siguiente else-if y se comprueba si a est entre 10 y 100. Si es cierto se muestraEl nmero est entre 10 y 100. Si no es cierto se evala el ltimo else-if.? (el otro if-else)El uso de la interrogacin es una forma de condensar un if-else. Su formato es el siguiente:( condicion ) ? ( instruccin 1 ) : ( instruccin 2 )Si se cumple la condicin se ejecuta lainstruccin 1y si no se ejecuta lainstruccin 2. Veamos un ejemplo con el if-else y luego lo reescribimos con "?":#include

int main(){int a;int b;

printf( "Introduce un nmero " );scanf( "%i", &a );if ( a'. Este operador viene a significar algo as como: "dame acceso al miembro ... del puntero ...".Ya slo nos queda saber cmo podemos utilizar los punteros para introducir datos en las estructuras. Lo vamos a ver un ejemplo:#include

struct estructura_amigo { char nombre[30]; char apellido[40]; int edad; };

struct estructura_amigo amigo, *p_amigo;

int main() { p_amigo = &amigo;

/* Introducimos los datos mediante punteros */ printf("Nombre: ");fflush(stdout); gets(p_amigo->nombre); printf("Apellido: ");fflush(stdout); gets(p_amigo->apellido); printf("Edad: ");fflush(stdout); scanf( "%i", &p_amigo->edad );

/* Mostramos los datos */ printf( "El amigo %s ", p_amigo->nombre ); printf( "%s tiene ", p_amigo->apellido ); printf( "%i aos.\n", p_amigo->edad ); }Comprobado con DJGPPNOTA:p_amigoes un puntero que apunta a la estructuraamigo. Sin embargop_amigo->edades una variable de tipo int. Por eso al usar el scanf tenemos que poner el &.Punteros a arrays de estructurasPor supuesto tambin podemos usar punteros con arrays de estructuras. La forma de trabajar es la misma, lo nico que tenemos que hacer es asegurarnos que el puntero inicialmente apunte al primer elemento, luego saltar al siguiente hasta llegar al ltimo.#include

#define ELEMENTOS 3

struct estructura_amigo { char nombre[30]; char apellido[40]; char telefono[10]; int edad; };

struct estructura_amigo amigo[] = { "Juanjo", "Lopez", "504-4342", 30, "Marcos", "Gamindez", "405-4823", 42, "Ana", "Martinez", "533-5694", 20 };

struct estructura_amigo *p_amigo;

int main() { int num_amigo; p_amigo = amigo; /* apuntamos al primer elemento del array */

/* Ahora imprimimos sus datos */ for( num_amigo=0; num_amigonombre ); printf( "%s tiene ", p_amigo->apellido ); printf( "%i aos ", p_amigo->edad ); printf( "y su telfono es el %s.\n" , p_amigo->telefono ); /* y ahora saltamos al siguiente elemento */ p_amigo++; } }Comprobado con DJGPPEn vez dep_amigo = amigo;se poda usar la formap_amigo = &amigo[0];, es decir que apunte al primer elemento (el elemento 0) del array. La primera forma creo que es ms usada pero la segunda quizs indica ms claramente al lector principiante lo que se pretende.Ahora veamos el ejemplo anterior de cmo introducir datos en un array de estructuras mediante punteros:#include

#define ELEMENTOS 3

struct estructura_amigo { char nombre[30]; char apellido[40]; int edad; };

struct estructura_amigo amigo[ELEMENTOS], *p_amigo;

int main() { int num_amigo; /* apuntamos al primer elemento */ p_amigo = amigo;

/* Introducimos los datos mediante punteros */ for ( num_amigo=0; num_amigonombre); printf("Apellido: ");fflush(stdout); gets(p_amigo->apellido); printf("Edad: ");fflush(stdout); scanf( "%i", &p_amigo->edad ); /* vaciamos el buffer de entrada */ while(getchar()!='\n'); /* saltamos al siguiente elemento */ p_amigo++; } /* Ahora imprimimos sus datos */ p_amigo = amigo; for( num_amigo=0; num_amigonombre ); printf( "%s tiene ", p_amigo->apellido ); printf( "%i aos.\n", p_amigo->edad ); p_amigo++; } }Comprobado con DJGPPEs importante no olvidar que al terminar el primer bucle for el puntero p_amigo apunta al ltimo elemento del array de estructuras. Para mostrar los datos tenemos que hacer que vuelva a apuntar al primer elemento y por eso usamos de nuevo p_amigo=amigo; (en negrita).

Paso de estructuras a funcionesLas estructuras se pueden pasar directamente a una funcin igual que hacamos con las variables. Por supuesto en la definicin de la funcin debemos indicar el tipo de argumento que usamos:int nombre_funcin ( struct nombre_de_la_estructura nombre_de_la variable_estructura )En el ejemplo siguiente se usa una funcin llamadasumaque calcula cual ser la edad 20 aos ms tarde (simplemente suma 20 a la edad). Esta funcin toma como argumento la variable estructuraarg_amigo. Cuando se ejecuta el programa llamamos asumadesdemainy en esta variable se copia el contenido de la variableamigo.Esta funcin devuelve un valor entero (porque est declarada como int) y el valor que devuelve (mediante return) es la suma.#include

struct estructura_amigo { char nombre[30]; char apellido[40]; char telefono[10]; int edad; };

int suma( struct estructura_amigo arg_amigo ) { return arg_amigo.edad+20; }int main() { struct estructura_amigo amigo = { "Juanjo", "Lpez", "592-0483", 30 }; printf( "%s tiene ", amigo.apellido ); printf( "%i aos ", amigo.edad ); printf( "y dentro de 20 aos tendr %i.\n", suma(amigo) ); system( "PAUSE" ); }

Fichero: estructuras_funciones.cSi dentro de la funcinsumahubisemos cambiado algn valor de la estructura, dado que es una copia no hubiera afectado a la variableamigode main. Es decir, si dentro de 'suma' hacemos arg_amigo.edad = 20; el valor de arg_amigo cambiar, pero el deamigoseguir siendo 30.Tambin se pueden pasar estructuras mediante punteros o se puede pasar simplemente un miembro (o campo) de la estructura.Si usamos punteros para pasar estructuras como argumentos habr que hacer unos cambios al cdigo anterior (en negrita y subrrayado):#include

...

int suma( struct estructura_amigo *arg_amigo ) { return arg_amigo->edad+20; }int main() { ... printf( "%s tiene ", amigo.apellido ); printf( "%i aos ", amigo.edad ); printf( "y dentro de 20 aos tendr %i.\n", suma(&amigo) ); system( "PAUSE" ); }

>Fichero: estructuras_funciones2.cLo primero ser indicar a la funcin suma que lo que va a recibir es un puntero, para eso ponemos el * (asterisco). Segundo, como dentro de la funcin suma usamos un puntero a estructura y no una variable estructura debemos cambiar el '.' (punto) por el '->'. Tercero, dentro de main cuando llamamos asumadebemos pasar la direccin deamigo, no su valor, por lo tanto debemos poner '&' delante deamigo.Si usamos punteros a estructuras corremos el riesgo (o tenemos la ventaja, segn cmo se mire) de poder cambiar los datos de la estructura de la variableamigode main.

Pasar slo miembros de la estructuraOtra posibilidad es no pasar toda la estructura a la funcin sino tan slo los miembros que sean necesarios. Los ejemplos anteriores seran ms correctos usando esta tercera opcin, ya que slo usamos el miembro 'edad':int suma( char edad ) { return edad+20; }

int main() { printf( "%s tiene ", amigo.apellido ); printf( "%i aos ", amigo.edad ); printf( "y dentro de 20 aos tendr %i.\n", suma(amigo.edad) ); }Comprobado con DJGPPPor supuesto a la funcin suma hay que indicarle que va a recibir una variable tipo char (amigo->edad es de tipo char).Estructuras dentro de estructuras (Anidadas)Es posible crear estructuras que tengan como miembros otras estructuras. Esto tiene diversas utilidades, por ejemplo tener la estructura de datos ms ordenada. Imaginemos la siguiente situacin: una tienda de msica quiere hacer un programa para el inventario de los discos, cintas y cd's que tienen. Para cada ttulo quiere conocer las existencias en cada soporte (cinta, disco, cd), y los datos del proveedor (el que le vende ese disco). Podra pensar en una estructura as:struct inventario { char titulo[30]; char autor[40]; int existencias_discos; int existencias_cintas; int existencias_cd; char nombre_proveedor[40]; char telefono_proveedor[10]; char direccion_proveedor[100]; };

Sin embargo utilizando estructuras anidadas se podra hacer de esta otra forma ms ordenada:struct estruc_existencias { int discos; int cintas; int cd; };

struct estruc_proveedor { char nombre_proveedor[40]; char telefono_proveedor[10]; char direccion_proveedor[100]; };

struct estruc_inventario { char titulo[30]; char autor[40]; struct estruc_existencias existencias; struct estruc_proveedor proveedor; } inventario;Ahora para acceder al nmero de cd de cierto ttulo usaramos lo siguiente:inventario.existencias.cdy para acceder al nombre del proveedor:inventario.proveedor.nombre

Uniones y EnumeracionesContenido Uniones Enumeraciones EjerciciosUnionesHemos visto que las estructuras toman una parte de la memoria y se la reparten entre sus miembros. Cada miembro tiene reservado un espacio para l solo. El tamao total que ocupa una estructura en memoria es la suma del tamao que ocupa cada uno de sus miembros.Las uniones tienen un aspecto similar en cuanto a cmo se definen, pero tienen una diferencia fundamental con respecto a las estructuras: los miembros comparten el mismo trozo de memoria. El espacio que ocupa en memoria una unin es el espacio que ocupa el campo ms grande. Para entenderlo mejor vamos a ver un ejemplo:Primero vamos a ver cmo se define una unin:union nombre_de_la_unin { campos de la unin };NOTA: No se debe olvidar el ';' despus de cerrar llaves '}'.Y aqu va el ejemplo:union _persona { char nombre[10]; char inicial; };Creamos una unin y sus elementos son unnombrede 10 bytes (nombre[10]) y la inicial (1 byte). Como hemos dicho la unin ocupa el espacio de su elemento ms grande, en este casonombre. Por lo tanto la unin ocupa 10 bytes. Las variables nombre e inicial comparten el mismo sitio de la memoria. Si accedemos anombreestaremos accediendo a los primeros 10 bytes de la unin (es decir, a toda la unin), si accedemos ainiciallo que tendremos es el primer byte de la unin.

#include

union _persona { char nombre[10]; char inicial; } pers;

int main() { printf("Escribe tu nombre: "); gets(pers.nombre); printf("\nTu nombre es: %s\n", pers.nombre); printf("Tu inicial es: %c\n", pers.inicial); }Comprobado con DJGPPEjecutando el programa:Escribe tu nombre: Gorka

Tu nombre es: GorkaTu inicial es: GPara comprender mejor eso de que comparten el mismo espacio en memoria vamos a ampliar el ejemplo. Si aadimos unas lneas al final que modifiquen slo la inicial e imprima el nuevo nombre:#include

union _persona { char nombre[10]; char inicial; } pers;

int main() { printf("Escribe tu nombre: "); gets(pers.nombre); printf("\nTu nombre es: %s\n", pers.nombre); printf("Tu inicial es: %c\n", pers.inicial); /* Cambiamos la inicial */ pers.inicial='Z'; printf("\nAhora tu nombre es: %s\n", pers.nombre); printf("y tu inicial es: %c\n", pers.inicial); }Comprobado con DJGPPTendremos el siguiente resultado:Escribe tu nombre: gorka

Tu nombre es: gorkaTu inicial es: g

Ahora tu nombre es: Zorkay tu inicial es: ZAqu queda claro que al cambiar el valor de la inicial estamos cambiando tambin el nombre porque la inicial y la primera letra del nombre son la misma posicin de la memoria.Con las uniones podemos usar punteros de manera similar a lo que vimos en el captulo de las estructuras.EnumeracionesEn el captulo de la constantes (cap. 4) vimos que se poda dar nombre a las constantes con#define. Utilizando esta tcnica podramos hacer un programa en que definiramos las constantesprimero...quinto.#include

#define primero 1#define segundo 2#define tercero 3#define cuarto 4#define quinto 5

int main() { int posicion; posicion=segundo; printf("posicion = %i\n", posicion); }Comprobado con DJGPPSin embargo existe otra forma de declarar estas constantes y es con las enumeraciones. Las enumeraciones se crean con enum:enum nombre_de_la_enumeracin{nombres de las constantes};

Por ejemplo:enum { primero, segundo, tercero, cuarto, quinto };De esta forma hemos definido las constantesprimero, segundo,... quinto. Si no especificamos nada la primera constante (primero) toma el valor 0, la segunda (segunda) vale 1, la tercera 2,... Podemos cambiar estos valores predeterminados por los valores que deseemos:enum { primero=1, segundo, tercero, cuarto, quinto };Ahora primero vale 1, segundo vale 2, tercero vale 3,... Cada constante toma el valor de la anterior ms uno. Si por ejemplo hacemos:enum { primero=1, segundo, quinto=5, sexto, septimo };Tendremos: primero=1, segundo=2, quinto=5, sexto=6, septimo=7.Con esta nueva tcnica podemos volver a escribir el ejemplo de antes:#include

enum { primero=1, segundo, tercero, cuarto, quinto } posicion;

int main() { posicion=segundo; printf("posicion = %i\n", posicion); }Comprobado con DJGPPLas constantes definidas con enumslopueden tomar valores enteros (pueden ser negativos). Son equivalentes a las variables de tipoint.Un error habitual suele ser pensar que es posible imprimir el nombre de la constante:#include

enum { primero=1, segundo, tercero, cuarto, quinto } posicion;

int main() { printf("posicion = %s\n", segundo); }Este ejemplo contiene erroresEs habitual pensar que con este ejemplo tendremos como resultado:posicion = segundo. Pero no es as, en todo caso tendremos:posicion = (null)Debemos pensar en las enumeraciones como una forma de hacer el programa ms comprensible para los humanos, en nuestro ejemplo el ordenador donde veasegundopondr un 2 en su lugar.Asignacin dinmica de memoriaContenido Qu es la asignacin dinmica? Malloc y free EjerciciosQu es la asignacin dinmica?Hasta ahora hemos visto que cada vez que queremos usar una variable debemos reservarle un lugar de la memoria al comenzar el programa. Debemos indicar cunta memoria vamos a usar. Pero hay ocasiones en que esto no es bueno, hay veces en las que no sabemos cunta memoria vamos a necesitar. Por ejemplo si hacemos un editor de texto no podemos saber de antemano cul va a ser la longitud del texto.Por eso a veces es necesario poder reservar memoria segn se va necesitando. Adems de esta forma nuestros programas aprovecharn mejor la memoria del ordenador en el que se ejecuten, usando slo lo necesario.La asignacin de memoria es la base de lo que veremos en captulos posteriores, especialmente los captulos de listas enlazadas. En estos captulos es donde se ver la verdadera utilidad de la asignacin dinmica.Malloc y freeExisten varias funciones para la asignacin dinmica de la memoria, pero las dos funciones bsicas sonmallocyfree.La funcin malloc (Memoryallocate - asignar memoria) reservar una parte de la memoria y devuelve la direccin del comienzo de esa parte. Esta direccin podemos almacenarla en un puntero y as podemos acceder a la memoria reservada. La funcin malloc tiene el siguiente formato:puntero = (tipo_de_variable *) malloc( nmero de bytes a reservar ); puntero: es una variable tipo puntero que almacena la direccin del bloque de memoria reservado. Puede ser un puntero a char, int, float,... (tipo_de_variable*): es lo que se llama unmolde. La funcin malloc nos reserva una cierta cantidad de bytes y devuelve un puntero del tipovoid(que es uno genrico). Con el molde le indicamos al compilador que lo convierta en un puntero del mismo tipo que la variablepuntero. Esto no es necesario en C, ya que lo hace automticamente, aunque es aconsejable acostumbrarse a usarlo.Una vez reservada la memoria y guardada su direccin en un puntero podemos usar ese puntero como hemos visto hasta ahora.Si no haba suficiente memoria libre malloc devolver el valor NULL. El puntero por tanto apuntar a NULL. Es muy importante comprobar siempre si se ha podido reservar memoria o no comprobando el valor depuntero:if (puntero)se cumple si hay memoria suficiente, en caso contrario el falso.Cuando ya no necesitemos ms el espacio reservado debemos liberarlo, es decir, indicar al ordenador que puede destinarlo a otros fines. Si no liberamos el espacio que ya no necesitamos corremos el peligro de agotar la memoria del ordenador. Para ello usamos la funcinfree, que funciona de la siguiente manera:free( puntero );Dondepunteroes un puntero que apunta al comienzo del bloque que habamos reservado. Es muy importante no perder la direccin del comienzo del bloque, pues de otra forma no podremos liberarlo.Vamos a ver un sencillo ejemplo del manejo demallocyfree:#include

int main() { int bytes; char *texto;

printf("Cuantos bytes quieres reservar: "); scanf("%i",&bytes); texto = (char *) malloc(bytes); /* Comprobamos si ha tenido xito la operacin */ if (texto) { printf("Memoria reservada: %i bytes = %i kbytes = %i Mbytes\n", bytes, bytes/1024, bytes/(1024*1024)); printf("El bloque comienza en la direccin: %p\n", texto); /* Ahora liberamos la memoria */ free( texto ); } else printf("No se ha podido reservar memoria\n"); }Comprobado con DJGPPEn este ejemplo se pregunta cunta memoria se quiere reservar, si se consigue se indica cunta memoria se ha reservado y dnde comienza el bloque. Si no se consigue se indica meniante el mensaje: "No se ha podido reservar memoria".Probemos este ejemplo reservando 1000 bytes:Cuantos bytes quieres reservar: 1000Memoria reservada: 1000 bytes = 0 kbytes = 0 MbytesEl bloque comienza en la direccin: 90868Prubalo unas cuantas veces incrementando el tamao de la memoria que quieres reservar. Si tienes 32Mbytes de memoria RAM teclea lo siguiente:Cuantos bytes quieres reservar: 32000000No se ha podido reservar memoriaMalloc no ha podido reservar tanta memoria y devuelve (null) por lo que se nos avisa de que la operacin no se ha podido realizar.

Tipos de datos definidos por el usuarioContenido Typedef Punteros Arrays Estructuras EjerciciosTypedefYa conocemos los tipos de datos que nos ofrece C: char, int, float, double con sus variantes unsigned, arrays y punteros. Adems tenemos las estructuras. Pero existe una forma de dar nombre a los tipos ya establecidos y a sus posibles variaciones: usandotypedef. Con typedef podemos crear nombres para los tipos de datos ya existentes, ya sea por capricho o para mejorar la legibilidad o la portabilidad del programa.Por ejemplo, hay muchos programas que definen muchas variables del tipounsigned char. Imaginemos un hipottico programa que dibuja una grfica:unsigned char x0, y0;/* Coordenadas del punto origen */unsigned char x1, y1;/* Coordenadas del punto final */unsigned char x, y;/* Coordenadas de un punto genrico */int F;/* valor de la funcin en el punto (x,y) */int i;/* Esta la usamos como contador para los bucles */La definicin del tipounsigned charaparte de ser larga no nos da informacin de para qu se usa la variable, slo del tipo de dato que es.Para definir nuestros propios tipos de datos debemos usar typedef de la siguiente forma:typedef tipo_de_variable nombre_nuevo;En nuestro ejemplo podramos hacer:typedef unsigned char COORD;typedef int CONTADOR;typedef int VALOR;

y ahora quedara:COORD x0, y0;/* punto origen */COORD x1, y1;/* punto final */COORD x, y;/* punto genrico */VALOR F;/* valor de la funcin en el punto (x,y) */CONTADOR i;Ahora, nuestros nuevos tipos de datos, aparte de definir el tipo de variable nos dan informacin adicional de las variables. Sabemos quex0, y0, x1, y1, x, yson coordenadas y queies un contador sin necesidad de indicarlo con un comentario.Realmenteno estamos creando nuevos tipos de datos, lo que estamos haciendo esdarles un nombre ms cmodo para trabajar y con sentido para nosotros.PunterosTambin podemos definir tipos de punteros:int *p, *q;Podemos convertirlo en:typedef int *ENTERO;

ENTERO p, q;Aqup, qson punteros aunque no lleven el operador '*', puesto que ya lo llevaENTEROincorporado.ArraysTambin podemos declarar tipos array. Esto puede resultar ms cmodo para la gente que viene de BASIC o PASCAL, que estaban acostumbrados al tipostringen vez dechar:typedef char STRING[255];

STRING nombre;donde nombre es realmentechar nombre[255];.

EstructurasTambin podemos definir tipos de estructuras. Antes, sin typedef:struct _complejo {double real;double imaginario;}

struct _complejo numero;Con typedef:typedef struct {double real;double imaginario;} COMPLEJO

COMPLEJO numero;

RedireccionamientoContenido Qu es la redireccin? Redireccionar la salida Redireccionar la salida con >> Redireccionar la entrada Redireccionar desde el programa - freopen EjerciciosQu es la redireccin?Cuando ejecutamos el comandodirse nos muestra el resultado en la pantalla. Sin embargo podemos hacer que el resultado se guarde en un fichero haciendo:dir > resultado.txtDe esta forma el listado de directorios quedar guardado en el ficheroresultado.txty no se mostrar en la pantalla.Esto es lo que se llamaredireccin. En este ejemplo lo que hemos hecho ha sido redireccionar la salida utilizando '>'.La salida del programa se dirige hacia la salida estndar (stdout, standard output). Normalmente, si no se especifica nada, la salida standard es la pantalla.La entrada de datos al programa se hace desde la entrada estndar (stdin, standard input). Normalmente, por defecto es el teclado.Existe una tercera opcin que es la salida de error estndar (stderr, standard error). Aqu es donde se muestran los mensajes de error del programa al usuario. Normalmente suele ser la pantalla, al igual que la de salida. Por qu tenemos stderr y stdout? Porque de esta forma podemos redireccionar la salida a un fichero y an as podemos ver los mensajes de error en pantalla.Stdin, stdout y stderr en realidad hay que verlos como ficheros: Si stdout es la pantalla, cuando usemos printf, el resultado se muestra en el monitor de nuestro ordenador. Podemos imaginar que stdout es un fichero cuyo contenido se muestra en la pantalla. Si stdin es el teclado imaginemos que lo que tecleamos va a un fichero cuyo contenido lee el programa.Redireccionar la salidaYa hemos visto cmo se redirecciona la salida con el dir. Ahora vamos a aplicarlo a nuestro curso con un sencillo ejemplo. Vamos a ver un programa que toma los datos del teclado y los muestra en la pantalla. Si el usuario teclea 'salir' el programa termina:#include

int main() { char texto[100];

gets(texto); do { printf( "%s\n",texto ); gets(texto); } while ( strcmp(texto, "salir") != 0 ); fprintf( stderr, "El usuario ha tecleado 'salir'" ); }Comprobado con DJGPPEn este programa tenemos una funcin nueva:fprintf. Esta funcin permite escribir en el fichero indicado. Su formato es el siguiente:int fprintf(FILE *fichero, const char *formato, ...);Ya veremos esta funcin ms adelante. Por ahora nos basta con saber que funciona como printf pero nos permite indicar en qu fichero queremos que se escriba el texto. En nuestro ejemplofichero=stderr.Como ya hemos visto antesstderres un fichero. Stderr es la pantalla, as que, si escribimos el texto en el fichero stderr lo podremos ver en el monitor.Si ejecutamos el programa como hemos hecho hasta ahora tendremos el siguiente resultado (en negrita lo que tecleamos nosotros):primera lneaprimera lneasegundasegundaesto es la mondaesto es la mondasalirEl usuario ha tecleado 'salir'Como vemos el programa repite lo que tecleamos.

Si ahora utilizamos la redireccin '> resultado.txt' el resultado por pantalla ser (en negrita lo que tecleamos nosotros):primera lneasegundaesto es la mondasalirEl usuario ha tecleado 'salir'NOTA: Seguimos viendo el mensaje final (El usuario ha tecleado 'salir') porque stderr sigue siendo la pantalla.y se habr creado un fichero llamadoresultado.txtcuyo contenido ser:primera lneasegundaesto es la mondaSi no hubisemos usado stderr el mensaje final hubiese ido a stdout (y por lo tanto al fichero), as que no podramos haberlo visto en la pantalla. Hubiera quedado en el fichero resultado.txt.Redireccionar la salida con >>Existe una forma de redireccionar la salida de forma que se aada a un fichero en vez de sobreescribirlo. Para ello debemos usar '>>' en vez de '>'. Haz la siguiente prueba:dir > resultado.txtdir >> resultado.txtTendrs el listado del directorio dos veces en el mismo fichero. La segunda vez que llamamos al comando dir, si usamos >>, se aade al final del fichero.AvisoTodo esto nos sirve como una introduccin al mundo de los ficheros, pero puede no ser la forma ms cmoda para trabajar con ella (aunque como hemos visto es muy sencilla). El tema de los ficheros lo veremos ms a fondo en el siguiente captulo.

Redireccionar la entradaAhora vamos a hacer algo curioso. Vamos a crear un fichero llamadoentrada.txty vamos a usarlo como entrada de nuestro programa. Vamos a redireccionar la entrada al fichero entrada.txt. El fichero entrada.txt debe contener lo siguiente:Esto no lo he tecleado yo.Se escribe slo.Qu curioso.salirEs importante la ltima lnea 'salir' porque si no podemos tener unos resultados curiosos (en mi caso una sucesin infinita de 'Qu curioso.'.Para cambiar la entrada utilizamos el smbolo 'siguiente' estaremos en el siguiente elemento.Es importante no olvidar saltar al siguiente elemento, puesto que si no lo hacemos as no habr forma de salir del bucle (estaremos siempre en el primer elemento).Como curiosidad se ha aadido una variableicon la que se cuenta el nmero de elementos de la lista. Si al final del bucle 'i' es cero, significa que no hay elementos en la lista. void mostrar_lista() { struct _agenda *auxiliar; /* lo usamos para recorrer la lista */ int i; i=0; auxiliar = primero; printf("\nMostrando la lista completa:\n"); while (auxiliar!=NULL) { printf( "Nombre: %s, Telefono: %s\n", auxiliar->nombre,auxiliar->telefono); auxiliar = auxiliar->siguiente; i++; } if (i==0) printf( "\nLa lista est vaca!!\n" ); }

Las buenas costumbresEn esta seccin voy a tratar de dar unas indicaciones de cual es la forma ms correcta de programar. Qu aspecto dar al cdigo fuente para que sea ms legible y elegante, cmo distribuir el cdigo fuente en distintos ficheros...Aspecto del cdigoObserva el siguiente cdigo:#include int main(void){ char cadena[20]; printf("Introduce una cadena:");fflush(stdout);gets(cadena);printf("has escrito: %s",cadena);return 0;}Ahora compralo con este otro:#include

int main(void) { char cadena[20]; printf( "Introduce una cadena:" ); fflush(stdout); gets(cadena); printf("has escrito: %s",cadena); return 0; }Creo que est claro cual es ms conveniente. Si tienes que entregar una prctica de clase bien hecha recomendamos la segunda forma. Pero si tu cdigo fuente es una chapuza y no sabes bien lo que ests haciendo recomendamos la primera (es una pesadilla intentar corregir un programa as). Por supuesto no me hago responsable de la posible mala leche del profesor.Desde luego no es la nica forma ni la ms correcta, es simplemente mi estilo. Cada uno tiene su estilo personal, aunque conviene que tampoco sea 'muy personal' si es para compartirlo. Otra forma muy habitual es poner '{' justo despus de la funcin:#include

int main(void) { char cadena[20]; printf( "Introduce una cadena:" ); fflush(stdout); gets(cadena); printf("has escrito: %s",cadena); return 0; }Los ComentariosEl cdigo fuente debe estar bien documentado, de tal forma que si se lo pasamos a otra persona pueda entenderlo sin grandes dificultades. Quiz pienses: "mi cdigo es mo y nunca se lo voy a dejar a nadie, as que para que voy a comentarlo". Parece lgico, pero imagina que lo abandonas y en el futuro quieres retocar el programa. Es muy probable que olvides por qu hiciste tal o cual cosa, (pasa muy a menudo, lo digo por experiencia) y tienes que pasarte un montn de tiempo descifrando algo que en su da entendiste perfectamente.Aqu tienes un ejemplo de un programa mal comentado:#include

int main(void) /* declaro la funcin main */ { /* Abro llaves */ char cadena[20]; /* declaro una variable llamada cadena */ printf( "Introduce una cadena:" ); /* Imprimo el mensaje 'Introduce una cadena */ fflush(stdout); /* vaco el buffer de salida */ gets(cadena); /* pregunto por el valor de cadena */ printf("has escrito: %s",cadena); /* muestro el valor que han introducido */ return 0; /* hago que el programa devuelva el valor 0; } /* cierro llaves */Estos comentarios estn bien si el cdigo forma parte de algn curso, pero no de un programa serio. Todo el mundo (que lleva un tiempo programando en C) sabe que con 'int main (void)' se declara una funcin y que con 'char cadena[20]' se declara una variable. Los comentarios deben decirnos qu es lo que hace el programa, para qu sirven las variables y explicar las partes crticas o confusas del programas. Algo mas correcto sera:/* Programa ejemplo creado para el Curso de C para Principiantes */

#include

int main(void) { char cadena[20]; /* En la variable cadena se almacenar el valor a introducir */ printf( "Introduce una cadena:" ); fflush(stdout); gets(cadena); printf("has escrito: %s",cadena); return 0; }Este programa es tan sencillo que no tiene puntososcurospara comentar.Es importante indicar para qu se van a usar las variables. Cuando tengamos muchas y pase el tiempo es difcil descifrar para que era cada una.Los nombres de las variablesCuando hacemos un programa con prisas o por no pensar mucho damos a las variables cualquier nombre. Supongamos un programa como ste int i, j, k; char a, b, c; double x1, x2, x3, x4; char an1, ab, ac, ad, ae; /* ... muchas ms variables */Cmo podemos acordarnos al de un tiempo de qu era cada variable. Por eso es conveniente que aparte de indicar para qu sirve cada variable les demos nombres descriptivos: int num_enemigos; /* Nmero de enemigos en escanario */ int personaje_x, personaje_y; /* Coordenadas del personaje */ char balas; /* Balas en cartuchera */ char vida; /* Vida restante */ char arma; /*modelo del arma */ /* ... etc */

Funciones matemticasEste captulo es muy poco creativo, se trata de buscar las funciones matemticas de la ayuda del Djgpp, traducirlas y ponerlas. Es un trabajo muy aburrido as que agradezco cualquier ayuda al respecto.Contenido Introduccin Funciones matemticas Trigonomtricas acos Potencias, races, exponentes y logaritmos Valor absoluto y redondeo absIntroduccinLas funciones matemticas se encuentran en , algunas estn en , ya se indicar en cada una. Con ellas podemos calcular races, exponentes, potencias, senos, cosenos, redondeos, valores absolutos y logaritmos.Tenemos que fijarnos en el tipo de dato que hay que pasar y en el que devuelven las funciones, si es int o double.En algunas funciones se necesitan conocimientos sobre estructuras. As que sera mejor mirar el captulo correspondiente antes, aunque har una pequea explicacin.

Funciones matemticasAqui va la lista de las funciones ordenadas por categoras.Trigonomtricas

Acos

Devuelve el arcoseno de un nmero.#include double acos(double x);Potencias, races, exponentes y logaritmos

Sqrt

Devuelve la raiz cuadrada de un nmero.#include double sqrt(double x);Valor absoluto y redondeoAbs

Devuelve el valor absoluto de un nmero entero. Si el nmero es positivo devuelve el nmero tal cual, si es negativo devuelve el nmero cambiado de signo.#include int abs( int valor );Ejemplo de uso:#include void main(){int a = -30;int b;b = abs( -55 );printf( "Valores a = %i, abs(a) = %i, b = %i\n", a, abs( a ), b );}No hace falta poner la directiva#include.Como podemos apreciar slo vale para nmeros enteros. Si queremos usar nmeros en coma flotante (o con decimales) debemos usarfabs. Tambin debemos tener cuidado y usar esta ltima si nuestros nmeros int slo llegan hasta 35000.

Instalacin y uso de DJGPPCreacin de programas (Compilacin)Vamos a ver primero cmo compilar un sencillo programa ('hola mundo' estar bien). Es interesante que entiendas esto primero para saber cmo funciona el compilador. Luego puedes usar unIDE, que es un entorno de desarrollo (como por ejemplo Turbo Pascal o Borland C) para hacer el trabajo ms cmodo. Existe uno muy bueno para principiante (y para profesionales) llamadoRhide.Para este ejemplo necesitas un editor de texto: el edit del DOS o el block de notas del Windows estaran bien. Crea un fichero con el editor y copia el siguiente cdigo:#include

int main() { printf( "Hola mundo\n" ); return 0; }Llmalo myfile.c. Puedes guardarlo en el directorio que quieras, no tiene por qu estar dentro del directorio DJGPP. Puedes guardarlo por ejemplo en un directorio llamado misprog (c:\misprog).Ya tenemos el fichero fuente, ahora slo hace falta compilarlo. Para compilar nuestro programa usamos el GCC. Este es un compilador delnea de comando, al que tienes que llamar desde la lnea de comandos del DOS. Se encuentra en el subdirectorio 'bin' del directorio donde hemos instalado djgpp.Compilacin de un programa C con un nico fichero fuenteVamos a compilar nuestro fichero fuente. Desde el directorio donde tenemos guardado myfile.c (por ejemplo c:\misprog) tecleamos:gcc myfile.c -o myfile.exe Si todo va bien (debera hacerlo) aparecer en ese directorio el programa myfile.c listo para ser ejecutado. Perfecto, ya tenemos nuestro primer programa.Compilacin de un programa C que usa alguna biblioteca (o librera)Ahora vamos a suponer que nuestro programa usa la biblioteca (librera) 'lib/libm.a' (el anterior no la usa). Para compilarlo haramos:gcc myfile.c -o myfile.exe -lmLa opcin-lmenlaza con la librera 'lib/libm.a'. La opcin -lm se pone al final.Compilar un programa con varios ficheros fuente1.- Crear Ficheros objeto:Para compilar un fichero de cdigo fuente de C o C++ y dejarlo como fichero objeto, usa la siguiente lnea de comando:gcc -c -Wall myfile.c (para cdigo fuente C) ogcc -c -Wall myfile.cc (para cdigo fuente C++)Con esto obtienes el ficheromyfile.o. La opcin '-Wall' activa muchos mensajes de aviso (warnings) que son especialmente tiles para nuevos usuarios de GCC. Tambin se pueden usar otras extensiones, comp .cpp (ver seccin 8.4 de la FAQ).2.- Enlazar ficheros objetoPara enlazar varios ficheros objeto en un programa ejecutable, usa algo parecido a esto:gcc -o myprog.exe mymain.o mysub1.o mysub2.oCon esto obtienesmyprog.exeque ya puede ser ejecutado.Si en vez de un programa C, tenemos un programa C++, usa algo como esto:gxx -o myprog.exe mymain.o mysub1.o mysub2.ogxxbuscar automticamente las bibliotecas C++, de manera que no tienes que incluirlas en la lnea de comando.3.- Compilacin y enlazado en un solo pasoPuedes combinar los pasos de compilacin y enlazado de la siguiente manera:gcc -Wall -o myprog.exe mymain.c mysub1.c mysub2.cPuedes encontrar ms informacin de las opciones de GCC en la documentacin on-line. Para leerla instala el paqueteTexinfo(txi390b.zip,ver la seccindocumentacin on-line) y ejecuta:info gcc invoking

Debugging (Depuracin)Para depurar un programa antes hay que compilar su cdigo fuente usando la opcin '-g':gcc -c -Wall -g mymain.cgcc -c -Wall -g mysub1.cgcc -c -Wall -g mysub2.cy luego enlazarlo tambin con la opcin '-g':gcc -g -o myprog.exe mymain.o mysub1.o mysub2.oLuego ejecuta tu programa con el debugger (depurador):fsdb myprog.exeogdb myprog.exeoedebug32 myprog.exe(Tendrs que conseguir el ficherogdb416b.zipsi quieres depurar con GDB). FSDB funciona a pantalla completa y tiene pantalla de ayuda a la que se accede pulsando F1. GDB viene con documentos 'Info' (ver ms abajo) que se pue