You are on page 1of 430
Tony Zhang Cprenviendo” Ze TRADUCCION: ‘Sergio Kourchenko Barrena REVISION TECNICA: Mariela Quintana Lépe: Maestra en. Ciencias Computacionales + ARGENTINA + BRASIL + COLOMBIA + COSTA RICA + CHILE une AA Resumen de contenido Tnmodueciip Parte |_Los fundamentos de C 9 Hora! El primer paso i 2 Su primer programa de C 29 3__La estructura de un programa de C 41 4 Tipos de datos y palabras reservadas 55 5. Manejo de la entrada y salida esténdar 7 rte Il_ Operadores e instrucciones de control de flujo 89 Hora 6 Manejo de datos. 1 1_Ciclos 105 8 Uso de operadores condicionales 121 9 Modificadores de datos y funciones matemdticas MI 10 Control de: flujo del programa 155 Parte Ill Apuntadores y arreglos 173 Hora 11__Apuntadores 195 12_Arreglos 189 1W3_Cademas 0207 14__Allcance y clases de almacenamiento 223 Parte IV Funciones y asignacién dinamica de memoria 241 Hora 15 _Funciomes J 16 Uso de apuntadores 259 17_Asignacidn de memoria 279 18__ Tipos de datos y funciones especiales 295 Parte V_Estructuras, uniones, E/S de archivos y mas 341 22 Funciones de archive especiales 373 23 Compilacién: el preprocesador de C 391 Parte VI Apéndices 437 Apéndice A Archivos de encabezado del esuindar ANSI 439 B__Respuestas a los cuestionarios y ejercicios 441 Indice 0S Material chroniony prawem autorskim ‘Muestra de un sistema configurado para programar en C 17 ‘Uso del compiladar de Microsoft eal Material chroniony prawem autorskim vi Aprendiendo C en 24 horas ‘Declaracién de variables de Bless Parte Il Operadores e instrucciones de control de flujo 89 Hora 6 Manejo de datos ” viii Aprendiendo C en 24 horas La instmiccidn nila eeeeeeennenninsnncecal ld Uso de expresiones complejas en una instrucciOn FF sceccscresmnnnl I Hora 8 Uso de operadores condicionales m1 ‘Como medir et tamatio de los datos... Todo es Wigico El operador Iogico AND (4a) El operador Igico OR (3) El operador I6gico NOT (1) .. Manejo de bits Conversion de un néimero decimal a hexadecimal o binario Uso de operadores a nivel de bits Hora 9 Modificadores de datos y funciones matemiticas 141 ‘Cémo habilitar o inhabilitar el bit de signa .. pssssnesl42 EX moificador 1090 sesnananan as (Césmo agregar h, 1.0 La los especificadores de formato printt y forintt 147 Fanciones matemiticas en C Liamadas a sin(), 6084) y tan() Llamadas a pow() y sert(} Contenido Hora 10 Control de flujo del programa 155 (COme decir siempre “si. La instruccidn 1¢ 1 Parte Ill Apuntadores y arreglos 173 Hora 11 Apuntadores 175 Hora 12_Arreglos 189 Inicializwcidn de arregios EL tamaiio de un arreglo Arregios y apuntadores ‘Cémo desplegar arreglos de caracteres El cardoter nulo (*\8") .. Aneglos multidimensionales x Aprendiendo C en 24 horas Contenido Use de prototipos Ciéep0 hacer Hamadas a las Funciones ‘Apuntadores y funciones Paso de arreglos a funciones Paso de apuntadores a funciones. Paso de areglos multidimensionales como argumentos x} xxii Aprendiendo C en 24 horas Hora 17_Asignacién de memoria 279 Asignacign de memoria en tempo de ejecucién ee MRO Hora 18 Lea fine eB02080) oe 2865 Declarscién de estructuras, Definiciin de variables de estructuras .. Como hacer referencia a miembros de estructuras con el Estructuras y Hamadas a funciones (Cémo hacer referencia a estruceuras mediante apuntadores (Cémo hacer referencia a.un miembro de una estructura mediante -> Arreglos de estructura, ‘Contenido xiii (Céimo hacer flexibles las estructuras... Definiciéin de campos de bits mediante struct Hora 21 Lectura y escritura de archivos 355 ‘Apuntadores de FILE (Cémo abrir archives (Climo cerrar archivos Lectura y escritura de archivos en disco Un candcter a la vez Unis Ine a la vex Un bloque a la vez xiv Aprendiendo C en 24 horas Hora 22. Funciones de archivo especiales 373 Las funciones fseekt) v Ftely) ns ‘Mis ejemplos de E/S de archivos en disco Lectura y eseritura de datos binarios Las funciones fecant(] y fprint#<) . Redirecci de ls flujo estindar mediante Treopen () Las dinectivas Wit, #olit y Helse Compilucién condicional anidada. Testniccionss de control de fino po pmennannnnennnreceth D6 Contenido Parte VI_Apéndices 437 Apéndice A_Archivos de encabezado del estandar ANSI 439 indice 8 Respuestas a los cuestionarios ictos aay Hora 1, “El pri xvi Aprendiendo C en 24 horas Blereicios ue —_ ee Hora 22, “Funciones de archivo especiales” eons 498 Acerca del autor Toxy ZHANG tiene mas de 15 ailos de experiencia en la programacién de computadoras yen el disefio de sistemas de informacién para empresas. En la actualidad trabaja para una de las cinco grandes firmas consultoras enfocadas al disefio, desarrollo ¢ implemen- tacién de infraestructura relacionada con e-business. Poseedor de un titulo de maestria en fisica, ha publicado diversos articulos de investiga- cién sobre lisers y programacién de computadoras. Entre sus principales intereses estén la pintura al dleo y la fotografia, que son las dos actividades que més disfruta. Puede establecer contacto con Tony a través de Sams Publishing, o escribiéndole al correo electrénico tyc24hBhotmail .com, Acerca del autor colaborador JouN SoUTHMAYD €s ingenieto de disefio de software y tiene experiencia en areas que van desde: la programacién de sistemas y controladores de dispositivos, hasta el desarro~ lo de Windows y tecnologias de Internet. Actualmente trabaja como consultor en Excell Data Corporation y vive con su esposa en Kirkland, Washington. Dedicatoria A mi esposa, Ellen, y a mis padres, Zhi-ying y Bing-rong, por su amor e inspiracién. —Tony Zhang Reconocimientos ‘Quisiera agradecer primero a los lectores de Ia primera ediciOn.en inglés de este libro por sus estimulos, paciencia, comentarios y, en especial, por sus criticas, lo cual contribuy6 a que esta segunda cdicién fuera mcjorada para aquellas personas que desean emprender tun viaje a través del mundo de la programacién en C. Es un gran placer para mf trabajar por segunda acasién con la editora Sharon Cox. Asi- mismo, deseo agradecer a los editores Carol Ackerman y Gus Miklos, y al autor colabo- radar John Southmayd por su excelente trabajo que hizo la segunda edicién de este libro més comprensible y en gran medida, si no es que por completo, libre: de errores. Ademis juiero expresar mi aprecio al gran trabajo de los demas miembros del equipo. Toxios ellos hicieron posible esta segunda edicién. Aprecio mucho el amor y el apoyo de mi esposa, Ellen, quien me inspira a ver el mundo de la tecnologia desde una perspectiva diferente. Siempre es un gran placer comentar con ella temas de filosofia y literatura, Mis padres, a quienes munca podré agradecer lo sufi- cieme, na sélo me dieron amar y carifo, sino también la oportunidad de recibir la mejor educacién que pude tener cuando estaba en China. Pearson Educacién Latinoamérica El personal de Pearson Educacién Latinoamérica est comprometido en presentarle lo micjor en material de consulta sobre computacién. Cada libro de Pearson Educacién Latinoamérica es el resultado de meses de trabajo de nuestro personal, que investiga y refina la informacién que se ofrece. ‘Como parte de este compromisa con usted, el lector de Pearson Educacién Latinoamérica Jo invita a dar su opinién, Por favor hdganos saber si disfruta este libro, si tiene alguna dificultad con la informacién y los ejemplos que se presentin, 0 si tiene alguna sugerencia para la préxima edicién, ‘Sin embargo, recuerde que el personal de Pearson Educacién Latinoamérica no puede ‘ctuar como soporte técnico i responder preguntas acerca de problemas relacionados con el software o él hardware. ‘Si usted tiene alguna pregunta o comentario acerca de cualquieer libro de Pearson Educacién Latinoamérica, existen muchas formas de entrar en contacto con nosotros. Responderemos a todos los lectores que podamos. Su nombre, direcci6n y mimero telefénico jamds formarin parte de ninguna lista de correos ni serdin usados para otro fin, més que el de ayudarnos a seguitle Hevanda los mejores libros posibles. Puede escribimnos a la siguiente direccisn: Pearson Educacién Latinoamérica ‘Attn: Editorial Divisién Computacién Calle Cuatro No. 25, 2° Piso, Col. Frace, Alce Blanco Naucalpan de Juirez, Edo. de México CP 53370, Si lo prefiere, puede mandar un fax a Pearson Educacién Latinoamérica al (525) 5387-0811. También puede ponerse en contacto con Pearson Educacién Latinoamérica a través de muestra pagina Web: http: / /wew. pearson. com. me Introduccion Si alguien aprende de otros pero no razona, estard desconcertado. Si alguien razona pero no aprende de otros, estard en peligro. —Confucio iBienvenido a Aprendiendo C en 24 horas! Con base en el éxito de la primera edicién en inglés de este libro y fa retroalimentacién de los lectores, hemos reescrito 0 modificado cada une de los eapitulos de la primera in para hacer esta segunda edicién mis adecuada para principiantes como usted que desean comenzar tan pronto como sea posible con el lenguaje de programacién C, Desde luego, es muy normal dedicar mas de 24 horas a entender cabalmente las conceptos y habilidades de programaciGn que se presentan en el libro. Sin embargo, la buena noticia es que el libro ofrece muchos programas de muestra y ejercicios con explicaciones y respuestas clara, Jo que facilita la comprensién de los conceptos del lenguaje C. De hecho, Aprendiendo Cen 24 horas le ofrece un buen punto de partida en la progra- macién en C, ya que cubre los temas importantes de esta programacidin y establece una base sélida para un principiante serio como usted. Después de leer el libro podri escribir por su cuenta programas sencillos de C . Se beneficiard de la lectura de este libro cuando comience a aplicar programas de Ca problemas reales 0 cuando decida aprender otros lenguajes de programacién como Perl, C++ y Java, éQuiénes deben leer este libro? Si ésta es In primera vez que estudia C, este libro estd escrito para usted. De hecho, al escribir el libro di por hecho que Jos lectores no tendrfan experiencia previa en progra- macién. Por supuesto, siempre es una gran ventaja si usted tiene algin conocimiento acerca de las computadoras. Caracteristicas especiales de este libro Este libro contiene los siguientes elementos especiales que hacen mis claro y sencilla para usted asimilar las caracteristicas y conceptos de C al momento de presentari * Quadros de sintaxis * Notas = Precauciones * Tips LZ. Aprendiendo C en 24 horas Los ewadros de sintaxis explican algunas de las caracteristicas més complicadas de C. co- mo las estructuras de control, Cada cuadro consiste en una definicidn formal de la earac- teristica, seguida de una explicacién, El siguiente es un ejemplo de un cuadro de sintaxis: La sintaxis de la funcign malioc() es include main() int ch; printf (*Eseriba, por favor, un cardeter:\n"); ch = gete(stdin); i@: —printf(‘E1 cardcter que acaba de introducir es: sein", ch); fi: return 5 12: } Después de erear y ejecutar el archivo ejecutable INL@1 .exa, se despliegan los siguientes resultados. El usuario introduce el cardcter # y el programa despliega lo que introdujo el usuario, Escriba, por favor, un caricter: x El cardcter que acaba de introducir es: H En la linea 2 del listado IN. 1, s¢ incluye el archivo de encabezado stdia. h para las dos funciones que se utilizan en el programa; geto() y printf(). Las lineas 4.9 12 proporcionan el nombre y cuerpo de Ia funcién maint} vn En Ia linea 6 se declara una variable entera ch, la cual s¢ asigna posteriormente al valor de retomo de la funcién gete() de la linea 9. La linea 8 imprime un mensaje que pide al usuario que introduzca un carfcter con el teclado. La funcién printf () de la linea 8 uti- liza la salida estiindar predeterminada stdout para desplegar mensajes en Ia pantalla. En la Ifnea 9, la entrada estindar stdin se pasa a la funcién getc(), lo que indica que el flujo de archivo se recibird desde el teclado. Después de que el usuario escribe un caric- ter, la funcién gete() devuelve el valor numérico (es decir, un entero) del carécter. Observe que en la linea 9 se asigna el valor numérico a la variable entera ch Aprendiendo C en 24 horas En la linea 10 se despliega en Ia pantalla, con ayuda de printf (), el cardeter introdu- cido. Observe que dentra de la funcidn printf() de la linea 10 se usa el especificador de formato de cardcter ‘se. Preguntas, respuestas y taller Cada hora (es decir, cada capftulo) termina con una secciGn de preguntas y respuestas que contiene las respuestas a preguntas comunes relacionadas con la leccién del capitulo. Después de esta seccidn hay un taller que consiste en un cuestionario y ejercicios de pro- gramacidn, Las respuesta a estos cuestionatios y las soluciones para los ejercicios se pre- sentan en el apéndice B, “Respuestas a los cuestionarios y ejercicios”, Para ayudarle a consolidar la comprensién de cada leccién, le recomiendo responder las preguntas de los cuestionarins y terminar los ejercicios que se incluyen en el taller. Convenciones utilizadas en este libro Por cuestiones gramaticales, en este libro, los mensajes del eddigo y su respectiva salida incluyen caracteres propios del idioma espaol, como caracteres acentuadas, eiies y signos de interrogacién y exclamacién, Debido a que el lenguaje C fue desarrollado consideran- do el idioma inglés, aun cuando podra compilar y ejecutar los programas sin problemas, tal vez estos caracteres no aparezcan como usted espera. Por Io tanto, le recomendamos que no los utilice al seguir los ejemplos del libro. Posterior mente, conforme avance en su aprendizaje del lenguaje C, encontraré que puede colocar los acentos o algtin otro caréc- ter empleando el cardcter ASCII correspondiente. Este libro emplea tipos especiales de letra para ayudarle a diferenciar entre el cédigo de Cy el lenguaje normal y para identificar conceptos importantes * El cdidigo de C esti tipografiado en una fuente especial nonoespaciada. Verd que esta fuente se utiliza en listados, ejemplos de entrada/salida y en fragmentos de c6- digo. La explicacién de las caracteristicas de C, los comandos, nombres de archivo, instruceiones, variables y todo texto que vea en la pantalla también apareceran con esta fuente. * La entrada de un comando y todo lo que se supone que usted introduciré apareceré en una fuente monoespaciada en negritas. Esto lo verd principalmente en las secciones de entrada/salida de los ejemplos. * Los indicadores de posicién en las descripciones de sintaxis aparecerén en una fuente monaespaciada en cursivas. Reemplace el indicador de posicién por el nombre de archivo real, parimetro 0 por cualquier elemento que represente. * Las cursivas resaltan términos técnicos cuando aparecen por primera vez en el texto y en ocasiones se utilizan para destacar aspectos importantes. Introduccion 5) Lo que aprendera en 24 horas Aprendiendo C en 24 horas consta de cinco partes. En la parte 1, “Las fundamentas de ©", aprenderd los aspectos basioos de este lenguaje. A continuacién le presentaré un resumen de lo que aprender en esta parte: La hora 1, “El primer paso”, le presenta el lenguaje C, el estindar ANSI y los reque- rimientos basicos de software y hardware para la programacién en C. La hora 2, “Su primer programa de C”, muestra todo el procedimienta para escribir, compilar, enlazar y ejecutar un programa de C. La hora 3, “La estructura de un programa de C”, le ensefia varios conceptos importantes, como constantes, variables, expresiones € instrucciones. En esta hora también se presenta la anatoméa de una funcién. La hora 4, “Tipos de datos y palabras reservadas”, lista todas las palabras reser- vadas de C. Se presentan detalladamente cuatro tipos de datos, char, int, float y double, Ademds, se explican las reglas para nombrar una variable, La hora 5, “Manejo de la entrada y salida estindar”, le ensefia a recibir la entrada del teclado y a imprimir la salida en la pantalla con la ayuda de un conjunto de fun- ciones de C, como gete(), getchar(), putc(), putchar() y prantf(). La parte II, “Operadores e instrucciones de control de flujo”, hace énfasis en los opera~ dores ¢ instmeciones de control de flujo de C. A continuacién le presentaré un resumen de lo que aprenderd en esta parte: La hora 6, “Manejo de datas”, le ensefia cémo utilizar los operadores de asignacién aritmética, el operador de negacién o unario menos, los aperadores de: incremento/de- cremento, los operadores relacionales y el operador de conversin explicita. In iteraciéin) con las instrucciones La hora 7, “Ciclos”, presenta los ciclos (es d for, while 0.do-while, La hora 8, “Uso de operadores condicionales”, le habla de otros operadores, como Jos operadores légicos, los operadores de bits, el operador sizeot yy el operador 7:, los cuales se utilizan con frecuencia en C. La hora 9, “Modificadores de datos y funciones matemdticas”, describe cémo- usar modificadores de datos para habilitar o deshabilitar el bit de signo, © para cambiar el tamafio de un tipo de datos. Ademds, se presentan varias funciones matemdticas que proporciona C. La hora 10, “Control de flujo del programa”, presenta todas las instrucciones de control de flujo que se utilizan en C. Estas son: if, if-else, switch, break, continue Y¥ goto. Aprendiendo C en 24 horas. En la parte III, “Apuntadores y arregios”, se exponen los apuntadores y arreglos, A con- tinuacisin le presentaré un resumen de lo que aprender en esta parte: ‘La hora 11, “Apuntadores”, le ensefia cémo relacionar variables con apuntadores. ‘También se presentan conceptos camo valor izquierda y valor derecho, ‘La hora 12, “Arreglos", explicn cémo declarar ¢ inicializar arreglos. También se ‘expone la relaciGn que hay en C entre el arreglo y el apuntador, ‘La hora 13, “Cadenas”, se enfoca en la lectura y escritura de cadenas. También se ‘presentan varias funciones de la biblioteca de C. para manipular las cadenas, como strlen(), strony’), gets(), puts() y seanf (). La hora 14, “Aleance y clases de almacenamiento”, presenta el alcance de bloque, ‘cl alcance de funcién, el aleance de programa y el alcance de archivo, Ademés, se cexplican los especificadores 0 modificadores de clases de almacenamiento, como auto, static, register, extern, const y volatile. La parte IV, “Funciones y asignaciGn dindmica de memoria”, se enfoca en las funeiones y en la asignaciGn de memoria dindmica en C. A continuacién le presentaré un resumen de lo que aprenderd en esta parte: La hora 15, “Funciones”, describe la declaracién y definicién de funciones en C. Se cexplica la ereacién de prototipos de funciones, asi como la especificacién del tipo de retomo de las mismas, La hora 16, “Uso de apuntadores”, le ensefia eémo realizar operaciones aritméticas ‘de apuntadores, emo acceder a Ios elementos en arregles utilizando apuntadores y -cémo pasar apuntadores a funciones. La hora 17, “Asignacién de memoria”, explica el concepto de asignacién de memo- ria de manera dindmica, Se presentan funciones de C utilizadas para la asignacién de memoria dinimica, como malloc(), calloc(), realloc() y treet). La hora 18, “Tipos de datos y funciones especiales”, presenta el tipo de datos enun ye uso de typeder. En esta hora también se ensefian la recursiGn de funciones y los argumentos de linea de comandos para la funcién main(). La parte V, “Estructuras, uniones, E/S de archivos y mis”, expone las estructuras, uniones y la E/S de archivos en disco en C. A continuacién le presentaré un resumen de Jo que aprender en esta parte: La hora 19, “Estructuras de datos”, presenta el tipo de datos structure. Aprenderd, a tener acceso a los miembros de una estructura y a pasar estructuras a funciones con Ja ayuda de apuntadores. En esta hora también se exponen las estructuras anidadas. La hora 20, “Uniones”, describe ¢l tipo de datos union, y la diferencia entre union y structure. Las aplicaciones de uniones se muestran en varios ejemplos. Introduccion La hora 21, “Lectura y escritura de archivos”, explica los conceptos de archivo y flujo en C. En esta primera parte se presentan los aspectos bésicos de la entrada y sa- lida de archivos en disco, También se presentan, junto con varios ejemplos, las si- guientes funciones de C: fopen(), felose(), fgete(), fputc(), tgets(), touted), fread(), fwrite() y feof {). La hora 22, “Funciones de archivo especiales”, es la segunda parte de la B/S de archivos en disco, en la que se presentan las funciones fseek(), ftell() y rewind() Para mostrar cémo pueden ayudarle a tener un acceso aleatorio a archivos en disco. Ademés, se ensefian y se invocan en programas de muestra las funciones fscanf (), ‘tprintt() y freopen(). La hora 23, “Compilacién: el preprocesador de C”, describe el papel que juega el preprocesador de C. A través de los ejemplos mostrados en esta hora, puede aprender directivas de preprocesador como #éef ine, Kunde, #ifdef, Kendif, #ifndef, #if, welis ywelse. La hora 24, #;Qué sigue después?”, resume las caracteristicas y conceptos impor- tantes presentados en este libro. Ademés se explican brevemente el estilo de progra- macién, Ia programacién modular y la depuracién. Para posteriores lecturas, se incluye una lista de libros recomendables de C. Ahora, al pasar el mundo a un nuevo milenio, esta usted listo para iniciar el viaje a través del aprendizaje del lenguaje C. Diviértase leyendo este libro y disfrute al pro- gramar en C. ‘Tony Zhang Downingtown, Pennsylvania Enero, 2000 a" 1 4, wih "y, \ PaRTE | Los fundamentos de C Hora El primer paso Su primer programa de C 1 2 3 La estructura de un programa de C 4 Tipos de datos y palabras reservadas 5 Manejo de la entrada y salida estandar Obraz chroniony prawem autorskim Material chraniony prawem autorskim Hora 1 El primer paso Un viaje de mil kilémetros comienza dando el primer paso. —Proverbio-china Los pensamientos elevados deben tener un lenguaje elevado. —Aristéfianes Bienvenido a Aprendiendo C en 24 horas. En esta primera lecciGn aprenderd lo siguicnte: * QuéesC * Por qué necesita aprender C + Elestindar ANSI » Hardware y software requeridos para ejecutar programas de C 12 Hora 1 Qué es C Ces un lenguaje de programacién que fuc desarrollado en 1972 por Dennis Ritchie en AT&T Bell Labs. Ritchie lo denominé C simplemente porque ya éxistia un lenguaje de programacién B. (En realidad, el lenguaje B condujo al desarrollo de C.) Ces un lenguaje de programacién de alto nivel, De hecho, ¢s uno de los lenguajes de programacién de propésito general mas populares. En el mundo de la computacién, entre més alejado esté un lenguaje de programacién de la arquitectura de la computadora, su nivel seri mds alto. Los lenguajes de nivel mas bajo son los lenguajes de maquina que las computadoras entienden y ejecutan directa- mente, Por otra parte, los lenguajes de programacién de alto nivel se asemejan més al enguaje humano (wea la figura 1.1) Figura 1.1 El espectra del lenguaje. El lenguaja human (or eiompin, Ch lengua do maquina rooo11 11101100, {es-deoi, obcigo anario} (0100111031000 Bajo Los lenguajes de programacién de alto nivel, incluyendo a C, tienen las siguientes ventajas + Legibitidad: Los programas son féciles de leer. + Facilidad de mantenimiento: Es fécil dar mantenimiento a los programas. + Portabilidad: Es fécll portar los programas a través de diferentes plataformas de compute. El primer paso 13) La legibilidad y facilidad de mantenimiento del lenguaje C se deben precisamente a su semejanza con el lenguaje humano, en especial con el inglés. Cada lenguaje de alto nivel necesita de un compilader o un intérprete para traducir las instruceiones eseritas en el lenguaje de programacién de alto nivel a un lenguaje de méquina que la computadora pueda entender y ejecutar, Cadla méquina podria necesitar tun compilador o intérprete distinto para el mismo lenguaje de programaciéin, Por ejemplo, yo utilizo el compilador C de Microsoft para compilar en mi PC los programas de este libro. Si tuviera que ejecutar estos programas en una estacién de trabajo basada en UNIX, tendria que compilarlos usando otro tipo de compilador de C, Por lo tanto, la portabilidad de los programas escritos en C se logra recompilando estos programas con diferentes compiladores para distintas méquinas (vea la figura 1.2). Froura 1.2 mercmrornes zap» ems — ee one (A evrene CEP ones CaF + seas [4 Hora 1 ‘Ademiis, el lenguaje C tiene otras ventajas. Los programas escritos en este lenguaje pueden ser reutilizados, Usted puede guardar partes de sus programas de C en un archivo de biblioteca © invocarlas en su siguiente proyecto de programacién simplemente inclu- yendo dicho archivo, Muchas tareas de programacién comunes y Gtiles ya estén implemen- tadas en bibliotecas que vienen incluidas con los compiladores. Ademés, las bibliotecas le permiten desencadenar con facilidad el poder y la funcionalidad del sistema aperativo que esté empleando. En el resto de este libro trataremos més detalles sobre el uso de funciones de biblioteca de C, Ces un lenguaje de programacién relativamente pequefio, lo que to hace més fécil para. usted. No tiene que memorizar muchas palabras clave © comandos antes de empezar a escribir programas de C que resuelvan problemas reales Para quienes buscan velocidad conservando la conveniencia y la elegancia de un lenguaje de alto nivel, probablemente C sea la mejor eleccidn. De hecho, C le permite tener el control del hardware y de los periféricos de 1a computadora. Es por ello que en ocasiones. ‘este lenguaje se le Hama el lenguaje de programacién de alto nivel mas bajo. han sido desarrollados con base en C. Por ejemplo, Perl es ‘Varios lenguajes de alto un conocido lenguaje de programacién en el disefio. de World Wide Web (WWW) a tra- vvés de Internet. En realidad, Perl tiene muchas caracteristicas de C. Si usted entiende C, aprender Perl le ser muy fécil. Otro ejemplo es el lenguaje C++, el cual es simplemente una versién ampliada de C, aunque C++ facilita la programacién orientada a objetos. I si usted ya conoce C. Incluso aprender Java es mucho mis f pilados y lenguajes interpretados, ‘Antes de poder ejecutar el programa en su méquina, necesita un compilador para traducir un programa escrito en algin lenguaje compilado a un cédiga que la maquina entienda (es deci @-cédigo binario). Una ver hecha la tra- duccién, puede guardar el cédige binario en un archivo de aplicacién. Puede f En general, existen dos tipos de lenguajes de programacién: lenguajes com- El primer paso 15) mantener operando el archivo de-aplicacién sin ei compilador, a menos que el programa (cédigo fuente) sea actualizado y tenga que recompilarie. Al cédigo binario o archivo de aplicacién también se le-conoce como cédigo ejecutable (o archivo eecutable). Por otra parte, usted pede lejecutar in pecigrama excrita en un lenguaje interpretado inmediatamente después de terminar de escribiria, oo que es igual, mientras lo escribe. Pero, en tiempo de ejecueién, dicho programa slempre necesita un intérprete para traducir las instrucciones de alto nivel a instrucciones que entienda la maquina (cédigo binario). No puede ejecutar el programa en una maquina, a menos que tenga el intérprete adecuado. Puede considerar a C como un lenguaje compilado, debido a que la mayoria de los fabricantes de este lenguaje sélo hacen compiladores para manejar programas escritos en C. Sin embargo, no hay nada inherente a un lenguaje compilado que impida que alguien proporcione un intérprete para dicho lenguaje; asimismo, hay quienes. escriben compiladores para lenguajes interpretades. De hecha, escoman mezclar las dos modalidades de lenguajes; un ejemplo de esto es cuando un programador compil cédigo fuente en un pequefio archivo binario, el cual es ejecutado posteriormente por un intérprete en thempo de ejecucién_ El estandar ANSI de C ‘Durante muchos afios, el estindar de facto para C fue él libro El lenguaje de programacin C, escrito por Brian Kernighan y Dennis Ritchie en 1978. Este libro se conoce en In comu- nnidad de programacién simplemente como Ki&eR (en referencia a las iniciales de los autores), y a la fecha tiene tn hugar en tos libreros de muchos programadores. Sin embargo, el libro fue escrito. como una introduccién a C, no como un estindar general u oficial del lenguaje. Debido a que distintos fabricantes ofrectan diversas implementaciones del lenguaje C, las diferencias entre dichas implementaciones comenzaron a apareces. ‘Temiendo que C perdiera su portabilidad, un grupo de fabricantes de compiladores y desarrotladores de software solicité en 1983 al ANSI (Instituto Estadounidense de Estandares Nacionales) que creara un esténdar del lenguaje C. El instituto aprobs la solicitud y forms el Comité Técnico X3J11 para que trabajara en el estindar de C. A finales de 1989, el comité aprobé el esténdar ANSI del lenguaje de programacién C. El estindar ANSI de C mejora el estindar original K&R y define un grupo de funciones de uso comin de C que se conoce come la biblioteca estindar ANSI de C, En la mayorfa de los casos, los compiladores de C incluyen la biblioteca estiindar, junto con otras bibliotecas para proporcionar algunas otras funciones especificas del compilador. Este libro se centra en las funciones de C definidas en el estdndar ANSI, el cual manejan todos los fabricantes de compiladores. Todos los programas de este libro pueden ser 16 Hora 1 compilados por cualquier compilador que se apegue al estiindar ANSI. Si esta interesado en un compilador especifico, puede aprender sus funciones especificas en su respective manual de referencia. Suposiciones acerca del lector No necesita ninguna experiencia previa en programacién para aprender el lenguaje C can este libro, aunque seria mejor si tuviera algdn conocimiento acerca de las computadoras Ademés, depende de usted determinar qué tan réipido quiere recorrer las 24 horas de este libro: podria sentarse con un gran tarre de café y acabarlo en una sola sesién, © podria tomar una hora al dia durante 24 dias Después de terminar este libro, habiendo realizado todos los ejercicios it dos en él, deberd manejar apropiadamente la sintaxis y las caracterfsticas del lenguaje C. Ademés, ya tendrd cierta experiencia en muchas de las tareas que: se encuentran al programar en C. Cuando esté listo para emprender sus propios proyectos de programacién, serd capaz de usar C como una herramienta para escribir programas utiles y poderosos. Conforme vaya avanzando, enconirard que siempre hay mis que aprender, no sélo acerca de C y de ‘c6mo aprovechar su poder, sino también acerca de nuevas tecnologias ¢ ideas de progra macién en general. Con esfuerzo y mucha préctica podré apoyarse ripidamente en las habilidades y teenologfas que aprenda. Configuracién de su sistema Basicamente, todo lo que necesita para compilar y ejecutar sus propios programas en C @ los de este libro, es una computadora y un compilador de C, En las siguientes secciones se describen el hardware y software recomendados. Hardware Cualquier computadora que tenga 0 que pueda acceder a un compilador de C esta bien. El compilador de C debe ser compatible con el ANSI-C, Es muy probable que tenga una PC sobre su escritorio. Una PC 286 con un disco duro de 50 MB y | MB de memoria (RAM) cs quizés ¢l minimo requerido para ejecutar un compilador de C basado en DOS. Para un compilador de C basado.en Windows, su computadora debe tener un disco duro mis grande y mas memoria. Para més detalles sobre requerimientos. de hardware, consulte al fabricante de su compilador. Software Si utiliza una estacién de trabajo basada en UNIX, tal vez ya tenga un compilador de C cargado en su maquina, © por lo menos puede acceder a uno en un servidor. Consulte a su administrador de sistemas para saber cémo acceder a un compilador compatible con el El primer paso 19) La figura 1.4 muestra ¢l IDE con el texto que acaba de escribir. No se preocupe por el significado del texto, En cl siguiente capitulo, “Su primer programa de C”, se lo explicaré, Ficura 1.4 Cédigo escrito enel IDE de Viswal Co 5.0, ‘A continuacién necesita guardar el texto como un archivo. Llamaremos a este archivo MiprimerPrograma.c. También es una buena idea crear un directorio en su disea duro. para almacenar sus proyectos de programacién, y guardar ahf el archivo, Primero haga clic em el botén Save de la barra de herramientas. Haga clic en el bovin New Folder del cuadro de didlogo Save As. Después haga doble clic en esa carpeta para abvirla, escriba, MiPrimerPrograma.c en el cuadro File Name, y haga clic en Save. Observe que se utiliza Ja-extensién .¢ para indicar que el archivo que acaba de guardar es un programa de C. Ahora necesita hacer clic en el mend Build y seleccionar la opcién Compile MiPrimerPrograma.c. Al hacerlo, solicite al compilador que compile el texto que acaba, de escribir y guardar (vea la figura 1.5). En este punto, Visual C++ podrfa pedirle que cree un nuevo espacio de trabajo; sélo haga clic en Yes y éste se creari en forma automitica. No debe haber errores o advertencias en la ventana de resultados después de ejecutar el compilador. Después haga clic de nuevo en el mend Build, y esta vez elija la opeién Build MiPrimer- Programa exe, la cual producird finalmente un archive ejecutable Hamado MiPrinerro- grama.exe. La figura 1.6 muestra que no hay errores © advertencias después de generar MiPrinerPrograma 20 Frouna 1.5. Conpitactén de wn programa de Cen el IDE Ficuna 1.6 Creacién del archivo efecutable de un programa. Ahora est usted listo acaba de compilar, Programa.exe. Al a que dicho archivo peiatd(itia, amiga! Ente we ai priser programe te 6.58): Fran fb} =U erzoe{a). 0 warning (s) EEE Cp ta, ange! fees ae primer propria fw» Oarrarte). 0 warsiegée) correr el archivo ejecutable, WiPrimerPrograna. exe, que hacerlo mediante la siguiente ruta: Build, Execute MiPrimer- el archivo ejecutable le aparecerd una ventana de DOS, debido aplicacién de modo de consola (yea la figura 1.7). El primer paso Ficura 1.7 Ejecucién de un pro- sprama de C. En fa figura 1.7 puede ver que la primera linea de la ventana de DOS es la misma que acaba de escribir: “jHola, amigo! Este es mi primer programa dé C.” En realidad, éste es el resultado de su primer programa (observe que Ia segunda linea de la ventana de DOS es sdlo un aviso del indicador de comandos del DOS). ‘Muy bien. Acabo de mostrarle cémo usar el compilador de Visual C++ para escribir y compilar un programa de C, y c6mo hacerlo ejecutable. Para més detalles, necesita leer libros como Aprendiendo Visual C++ 5 en 2! dias, el cual se enfoca en ensefiarle c6mo usar el compilador de Visual C++. Uso del compilador de Borland En esta seccién vay a mostrarle.cémo usar el compilador de C que viene con el paquete (C++ de Borland. El procedimiento de esta seceién es muy similar al de la anterior. Si necesita aprender mis detalles sobre cémo instalar ef C+-+ de Borland, siga las instrue- ciones que vienen con el compilador. Daré por hecho que ya instalé una copia de Borland C++ 5,02.en su computadora. Para iniciar el compilador, puede hacer clic en el botdn Inicio de su barra de tareas de Windows 95 (o Windows 98, NT 0 2000) y seleccionar Programas, Borland C++ 5.02, Borland C++. O bien, puede simplemente ejecutar el archivo de aplicaeién bew. exe direc- tamente desde el directorio (carpeta) en el que instalé el paquete Borland C++. La figura 1.8 muestra un ejemplo del entomo de desarrollo integrado (IDE) de Borland C++ 5.02. Después puede abrir un archivo nuevo dentro del IDE, y escribir el siguiente texto en el espacio del archivo recién abierto: ‘finclude main() { printf return “THola, andgol Este es mi primer programa de C.\n"); 2 Hora 1 Ficura 1.8 Creacién de un programa en el IDE de Borland C++, La figura 1.9 n significado del texto. Figura 1.9 Cima guardar terto de un programa de C en ef IDE de Borland. se preocupe porel El primer paso ‘Ahora necesita guardar el texto como un archivo. Llamaremos a este archivo MiPriner Prograna.c. Observe que se utiliza la extensiGn © para indicar que el archivo que acaba de guardar es un programa de C. ‘Ahora necesita hacer clic en el mend Project y seleccionar la opcién Compile. Al hacerlo, solicite al compilador que comience a compilar el texto que acaba de escribir y guardar. La figura 1.10 muestra que no hay errores o advertencias después de compilar MiPriner Prograna.c y crear MiPrimerPrograma. exe Frcuna 1.10 Como compiler wn programa de Cen el IDE de Borland, Ahora estd usted listo para correr el archivo ejecutable, MiPrimerFrograma.exe, que acaba de compilar. Puede correrlo haciendo clic en el boton Run de la barra de herra- mientas, o puede ejecutarlo directamente desde el directorio en donde lo cred. Al correr el archivo ejecutable le aparecerd una ventana dé DOS, debido a que dicho archiva es en realidad una aplicacién de DOS (ves ta figuen 1.11). Frcuna 1.11 Ejecucién de un programa de Cen el IDE de Borland. 23) 24 Hora 1 La figura 1.11 exhibe el resultado exactamente como usted acaba de escribirlo: “jHola, amigo! Este es mi primer programa de C.” En realidad, éste es el resultado de su primer programa de C. Si desea aprender mas detalles sobre edmo usar Borland C+-+, lea un libro como Aprendiendo Borland C++ en 21 dias, Resumen En esta primera leccidn aprendié los siguientes elementos bisicos acerca del lenguaje C: + Ces.un lenguaje de programacién de propdsito general, + Ces.un lenguaje de alto nivel que tiene las ventajas de legibitidad, facilidad de ‘mantenimiento y portabilidad. + Ces.un lenguaje muy eficiente: que permite controlar el hardware y los periféricos de la computadora. + Ces un lenguaje pequefio que usted puede aprender en un tiempo relativamente breve, * Los programas escritos en C pueden reutilizarse, « Los programas escritos en C deben compilarse y traducirse a un eddigo legible para Ia méquina antes de que la computadora pueda ejecutarlos. Muchos lenguajes de programacién, como Perl, C++ y Java, han adoptado concep- tos bisicos y caracteristicas tiles del lenguaje C. Una vez que aprenda C, le sera mas sencillo aprender estos otros lenguajes. + Los fabricantes de compiladores de C manejan el estiindar ANSI de C para mantener Ta portabilidad de los programas escritos en este lenguaje. Puede utilizar cualquier compilador compatible con el ANSI C para compilar todos Jos programas de C incluidas en este libro. En Ja siguiente lecci6n aprender a escribir su primer programa de C. El primer paso 25) Preguntas y respuestas P ;Cudl es lenguaje de-nivel mas bajo-en el mundo de la computacién? R El lenguaje de maquina de la computadora, conformado por ceros y unos, es el de més bajo nivel, debido a que es el tinico lenguaje que la computadora puede enten- der en forma directa. 1 Cuailes son las ventajas de los lenguajes de programacién de alto nivel? R La legibilidad, la facilidad de mantenimiento y Ia portabilidad son las principales ventajas de los lenguajes de alto nivel. 2Qué es C, en tiltima instancia? R Ces um lenguaje de programacién de propésito general, y es un lenguaje de alto nivel que tiene ventajas como la legibilidad, facilidad de mantenimienta y portabi- lidad, Ademis, C permite descender al nivel del hardware para incrementar, si es necesario, la velocidad de rendimiento. Se necesita un compilador de C para traducir los programas escritos en C a un cédigo que la maquina entienda. La portabilidad de estos programas se logra recompilindolos con compiladores de C especificas para cada tipo de computadora, {Puedo aprender C en poce tiempo? R Sf. Ces un lenguaje de programacién pequefio. No hay muchas palabras clave 0 comandos que recordar, Ademis, es muy fiicil leer y escribir los programas de C, ya que éste es un lenguaje de programacién de alto nivel muy parecido al lenguaje humano, en especial al inglés. Por lo tanto, usted puede aprender C en un tiempo relativamente corto. ~ ” ” lidar la comprensidin de la lecciéin de esta hora, le recomiendo que responda el ‘cuestionario de este taller antes de pasar a la siguiente leccién, Las respuestas y sugeren- 3: 4: main() Bt 8: printf (*iHola, amigo! Este es mi primer programa de C.\n*); 7: return a: } Este es un programa de C muy sencilllo que esté guardado en un archivo de nombre 82L01.c. Observe que el nombre de un programa de C debe tener la extensiGn .¢. Si instal un compitador de Cy configuré el entomo de desarrollo correspondiente, podré compilar este programa y convertirlo en un archivo ejecutable. Ms adelante en este capitulo le diré cémo hacer un archivo ejecutable, En la hora anterior aprendié esimo escribir un programa en su editor de texto y eémo- guardarlo como un archivo de programa de C. Quizéi haya observado que a diferencia del ejemplo del capitulo anterior, en este ejemplo cada Linea esté numerada, Sélo hago esto para tener una referencia al momento de explicar lo que hace cada linea del programa. A diferencia de otros lenguajes como BASIC, el lenguaje C no emplea mimeros de linea, De hecho, si usted escribe los niimeros de linea en el listado, su programa no funcionard_ Asi que cuando escriba estes programas recuerde no poner los miimeros de linea que se miuestran én el libro. (Das cosas que puede notar al mirar el listado 2.1 son los caracteres de punto ycoma y la sangria en las lineas 6 y 7. A diferencia de otras lenguajes, como BASIC, e! final de una linea no tiene un significado especial en C. Es.comple- tamentte valido (y recomendablle, en muchos casos) dividir una instruccién en varias lineas pare dar claridad. En general, una instruccién individual de € termina con un punta y coma; pero posteriormente veremos mucho mas.al respecto, La sangria sirve para identificar los distintos niveles de un progra- ma en una especie de formato esquemitico, La funcién main() es el nivel Su primer programa de C 23) Principal del programa, de modo que va a la extrema izquierda. Las lineas 6 y 7 son parte de main), asi que tienen una sangria de un nivel hacia la derecha. Por lo regular se emplea la tecla Tab para sangrar un nivel antes de comenzar a escribir, Debemos sefialar que al igual que con los nimeros de linea, el compilador no realiza el sangrado; ni siquiera Ia nota. El progra- mader es libre de usar cortes de linea y sangrado, conacidas como espacias ‘en blanco, para hacer qué el programa lurca legible, Este es un asunte de ‘estilo, pero es buena idea sequir las convenciones aceptadas generalmente a fin de que otros programadores puedan entender sus programas y viceversa. ‘Observe el uso del espacio en blanco al avanzar en este libro y siéntase en libertad de desarroliar su propio estilo. Yo configuré mi entomo de desarrollo de tal manera que todos los programas de este libro se pudieran compilar y convertir en aplicaciones de consola, Por ejemplo, #2L81 exe esl nombre de la aplicacién de consola generada a partir de @2L01..c. Observe que se incluye -exe como la éxtensiGn del nombre de un programa de aplicacién de DOS o Windows (es decir, un archivo ejecutable). Ademés, guardo todos los archivos ejecutables generados a partir de los programas. de este libro en un directorio de mi computadora lamado ¢:\apa. Por Jo tanto, si escribo @2L01 ‘desde el indicador de comandos de DOS y oprimo la tecla Entrar, puedo ejecuiar el archivo ‘ejecutable 02101 .exe y exhibir en la pantalla el mensaje 1Hola, amigo! Este es mi primer programa de C. El siguiente resultado es una copia de la pantalla: Ey iHola, amiga! Este es mi primer programa de C. Comentarios Veamos ahora mds de cerca el programa de C del listado 2.1. La primera linea contiene un comentario: I eat Este es mi primer programa de C */ Puede observar que esta linea comienza con una combinacién de diagonal y asterisco, /*, y termina con */. En C, ala combinacién /* se le denomina marca de apertura de comentario, y ala combinaci6n */, marca de cierre de comentario. El compilador de C ignora todo Io que se encuentra entre las marcas de apertura y de cierre de comentario. Esto significa que el compilador ignora por completo el comentario de la primera linea Usted puede ver que esta Kinea comienza con un signo de numeral. #, seguido por include. En C, #include forma una directiva de preprocesadar que indica al prepracesador de C que busque un archive y cologue el contenido de ese archivo en donde la directiva include indique. El preprocesador es un programa que hace algunos preparativos para el compilador de ames de compilar su eédigo. En la hora 23, “Compilacién: el preprocesador de C, se exponen mais detalles acerca del preprocesador. ‘También puede ver en esta linea que esté después de la directiva Winclude. Podia pensar que él archivo solicitado por la directiva #include es algo Hamado stdio.h. Tiene raz6n. Aqui, la directiva #include solicita al preprocesador de C que busque y coloque el archive stdio.h en el lugar del programa donde se encuentra la directiva. 3 2 Hora 2 El archivo stdio.n significa encabezade de entrada-salida esténdar. Este archivo con- tiene numerosas prototipos y macros para realizar operaciones de entrada o salida (E/S) de programas de C. Veré mas de la E/S de programas en la hora 5, “Manejo de la entrada y salida estndar”, Algunos sistemas operatives distinguen entre letras maydsculas y mindsculas, pero otros no lo hacen. Por elemplo, stdio.hy STDIO.H son nombres kdénti- «0s.en una PC. pera san diferentes en UNIX. Archivos de encabezado Los archivos que se incluyen mediante la directiva #ineiude, como stdio.h, se denomi- nan archivas de encabezade debido a que las directivas #inelude se colocan casi siempre: al inicio, o a la cabeza, de los programas de C, De hecho, la extensidn .h significa “header” (encabezado), y se suele hacer referencia a ellos como archivos punto h. Ademdis de stdio.n, existen mis archivos de encabezado, como stdiib.n, string.h, math.n, etcétera, En el apéndice A, “Archivos de encabezado del estindar ANSI”, se proporciona una lista de todos ellos. Los archivos de encabezado especificos que necesite incluir dependerin de las fanciones especificas de biblioteca que pretenda Ilamar, La docu mentacién de las funciones de biblioteca le diré qué archivo de encabezado se requiere. Paréntesis angulares (< >) y comillas dobles (* “) En la segunda linea del listado 2.1 hay dos paréntesis angulares, < y >, que se usan para ‘encerrar a stdio.n. Tal vez se preguate para qué sirven los paréntesis angulares. En C, Jos parémesis angulares solicitan al preprocesador de C que busque un archivo de vencabezado en un directorio distinto al actual, Por ejemplo, en mi computadora, el directorio actual que contiene el archivo #2101 .¢ se lama ¢:\code. Por Io tanto, los paréntesis angulares que rodean a |e indican al prepracesador de C que busque el archivo stdio.h en un directorio diferente a C: \code. Si desea que el preprocesador busque primero en el directorio actual antes de buscar en otra parte, puede utilizar comillas dobles para encerrar el nombre del archivo de encabe- zado, Por ejemplo, cuando el preprocesador de C ve “stdio.h*, busca primero el archivo de encabezado stdio.h ca el directorio actual, que en mi méquina es G: \cede, antes de buscar en otra parte. Los archivos de encabezado se guardan normalmente en un subdirectorio denominado include. Por ejemplo, yo instalé un compilador de C de Microsoft en el directorio MSVE de mi disco duro, el cual est etiquetada como la unidad ¢. Entonces, la ruta de acceso al archivo de encabezado se convierte en G: \MSVC\ include. Su primer programa de C 33] Por lo regular, el compilador determina, al momento de instalarlo, la ruta de acceso en donde se guardardn los archives de encabezado, A esto se le conoce cominmente como el directorio include o Ia ruta de acceso include de su entomo. No tendré que preocuparse por el directorio include, sino hasta que cree sus propios archivos de encabezado. Por ahora, slo necesita especificar el nombre del archivo de encabezado que desea incluir. La funcién main() En la linea 4 del listado 2.1 se encuentra la siguiente funci6n: main () Esta es una funcidin muy especial en C. Todo programa de C debe tener una (y s6lo una) funcién nain(), En la hora 3, “La estructura de un programa de C”, se proporcionan explicaciones mis genéricas acerca de las funciones, Puede colocar la funcién main() en cualquier lugar de su programa de C. Sin embargo, la ejecueién de su programa siempre comienza con la funcién main(). Si crea otras fun- ciones en su programa, nain() siempre se ejecutard primero, incluso si esti al final de su archivo de programa, En el listado 2.1, el cuerpo de la funci6n ain() inicia en la linea 4 y termina en la linea 8. Debido a que éste es un programa muy sencillo, main() es 1a tinica funcién definida en el programa. Dentro del cuerpo de la funcién main() se lama a una funcién de biblioteca de C, printf(), a fin de imprimir un mensaje de saludo (vea la linea 6). En la hora 5 se abordan mds detalles acerea de print#(). ‘Otra cosa importante respecto a main() 4 que In ejecucién de todo programa de C ter ‘mina con main(). Un programa concluye cuando se han ejecutado todas las instrucciones dde la funcién main(). El cardcter de nueva linea (\n) Algo que vale la pena mencionar acerca de la funcién printf () ¢s el cardcter de nueva linea, \n. Por lo regular agregado como sufijo al final de un mensaje, el caricter de i Ja computadora que mueva el cursor al inicio de la siguiente linea, para que cualquier cosa que se imprima después de! mensaje comience en la siguiente Vinea de la pantalla, ‘En un entomo UNIX, \n pasa a la siguiente linea por sf mismo, pero deja el cursor en la posicién en que estaba en la linea anterior. En este caso, es necesario imprimir \r\n en ‘vez de solamente \n, El cardicter \r es el caricter de retorno de carro. Al ejecutar los programas de muestra de este libro, podri saber de inmediato si el cursor regresa al prin scipio de la nueva linea; si no es asi, simplemente vtilice \r\n siempre que ves \n en los listados de programas. Hora 2 El ejercicio 3 de esta leccidn le da la oportunidad de utilizar el cardcter de nueva linea para dividir en dos lineas wn mensaje de una linea, La instruccién return En C, todas las funciones devuelven valores. Por ejemplo, al crear una funcién para sumar dos ndmeros, usted puede hacer que dicha funcién le devuelva el valor de Ia suma. La funcién main() por si misma devuelve un valor entero. En C, los enteros son mimeros decimales sin fracciones. Por lo tanto, en la linea 7 del listado: 2.1 hay una instruccién, return @;, que indica que la funcién main() devuelve un @ y el programa termina normalmente. Hay casos en los que debe terminar sus programas debido a una condicidn de error. Cuando eso sucede, puede devolver valores distintos a @ para indicar al sistema operativo (o al programa que ‘ejecut6 su programa) que hubo un error, La funcién exit() ‘También existe una funcién de biblioteca de C, exit(), que se puede utilizar para terminar un programa. Debido a que la funcién exit () esta definida en el archivo de encabezado std1ib-h, usted debe incluir el archive de encabezado al principio de su programa para poder usar la funcién. La funcién exit()no devuelve un valor a su programa por sf misma. ‘Observe que return y exit () también se pueden usar en otras funciones. En lo que resta del libro vers més ejemplos de Ia palabra reservada (0 palabra clave, como también se le conoce) return. Compilacién y enlace Ya debe estar ansioso por saber cémo se hace un archivo ejecutable. Veamos cémo se ‘compila un programa de C y cémo se traduce a un archivo ejecutable. Como se muestra en Ia figura 2,1, se necesitan por lo menos tres pasos para crear un archive ejecutable. Primero se hace un archivo de programa escrito en C, denominado eddige fuente, EL nombre del archive de cédige fuente termina con la extensién .¢ Después, un compiladar de C compila el archive de cédigo fuente y crea un nuevo ar- chivo. El nuevo archivo es un archive objeto, En el sistema operative UNIX, el nombre del archivo objeto termina con la extensién 0, En los sistemas operatives DOS y Windows, la extensidn es .obj No es posible ejecutar el archivo objeto debido a que falta cierto cédigo de funciones. Es necesario coneluir el paso siguiente: el enlace. Este se hace invocando a un programa especial Ilamado enlazador, el cual viene normalmente con ¢l paquete del compilador. Su primer programa de C 35) Un enlazador se emplea para vincular el archivo objeto, la biblioteca estindar de C y otras bibliotecas generadas por el usuario para producir un archivo ejecutable: el eédigo binaria, En esta etapa, el cédigo binaria de las funciones de biblioteca que se llaman en el eddigo fuente se combina con el archivo objeto; el resultado se guarda en un nuevo archivo: un archivo ejecutable. Como aprendid en el primer capftulo de este libro, el nombre de un archivo ejecutable de DOS o de Windows termina por lo regular con la extensién .exe (com es otra extensiGn que se usa para un nombre de archivo ¢jecutable de DOS), En UNIX no es necesario incluir dicha extensiGn en el nombre de un archivo ejecutable, Frouna 2.1 Creacién de un peemoaene te active Pree archivo ejecuable ‘sti \ mediante el compi- st. ladory l enlacador o—s N Miés adelante aprenderd que: en muchos casos tal vez tenga que enlazar varios archivos objeto a fin de crear un programa ejecutable. Observe que tanto el archive objeto como el archivo ejecutable son dependientes de la miquina. Usted no puede simplemente pasar un archivo ejecutable de la plataforma de eGmputo actual a otra que sea operada por un sistema operative distinto, aunque el eddigo fuente de ese archivo ejecutable, presumiblemente escrito en ANSI C, podria ser inde- pendiente de la méquina (es decir, portable). 3 6 Hora 2 La portabilidad es un concepte importante en C, ya que fue una de las metas. que #include “stdio.n"? 2. Bs el momento de que escriba tn programa por su cuenta. Tomando como referencia el programa del listado 2.1, escriba un programa de C que imprima el mensaje: Es divertida escribir mi propio programa de C. 3. Actualice el programa del listado 2.1 agregando un cardcter mds de nueva I{nea dentro del mensaje que imprime la funcién printf (). Después de ejecutar el archive ejecutable actualizado, debe ver en la pantalla dos Ifneas del mensaje: 4, ;Qué mensaje de error o advertencia, si lo hay, obtendré al compilar el siguiente programa? Winelude Winclude nain() { printf (*iHola, amigo! Este es mi primer programa de C.\n* exit( » 5. :Qué mensaje de error obtendri del siguiente programa cuando intente compilarlo? void main() t print (‘iHola, amigo! este es ai primer pragrana de C.tn"); return @; 3 9 Material chroniony prawem autorskim oh i Ss = = — = HorA 3 “ La estructura de un programa de C El entero es igual ala suma de sus partes. —Euclides En la hora 2, “Su primer programa de C”, vio y escribi6 algunos programas sencillos en C. También aprendié acerca de la estructura basica de un pro- grama de C. Usted sabe que un programa escrito en C se tiene que compilar antes de que pueda ser ejecutado. En esta leccién aprender mas de lo fun- damental de un programa de C, como por ejemplo: * Constantes y variables + Expresiones: * Instrucciones * Bloques de instrucciones + Tipos y nombres de funciones de C + Argumentos para funciones + El cuerpo de tna funcién + Llamadas a funciones Hora 3 Los elementos basicos de un programa de C Asi como un edificio esti hecho de ladrillos, un programa de C esti hecho de elementos hasicos, como expresiones, instrucciones, bloques de instrucciones y bloques de funcio- nes, Estos elementos se explican en las siguientes secciones. Pero antes necesita aprender dos elementos mas pequefios pero importantes, las constantes y las variables, las cuales conforman las expresiones. Constantes y variables ‘Como su nombre indica, una constante es un. valor que nunca cambia. Por otra parte, una variable se puede usar para presentar diferentes. valores. Puede comparar a una constante con un disco compacto de la miisica almacenada en el disco compacto nunca cambia. Una variable es mas parecida a un casete de audio: usted puede actualizar el contenido del casete simplemente sustituyendo las canciones que tenia por otras nuevas. Puede ver muchos ejemplos en los que hay constantes y variables en la misma instruc- cidn, Considere, por ejemplo, la siguiente; et en donde el sfmbolo 4 ¢s una Constante ya que siempre tiene el mismo valor (1), y al simbolo i s¢ le asigna la constante 1. En otras palabras, i contiene el valor 1 después de ejecutar Ia instruccién. Luego, si hay otra instruccién, 110; después de que se ejecuta esta instruccién, a i se le asigna el valor 18. Debido a que i puede contener diferentes valores, en el lenguaje C se le llama variable. Expresiones ‘Una expresién es una combinacién de constantes, variables y operadores que se emplean para denotar célculos Por ejemplo, la siguiente: (2+) "10 es una expresién. que primero suma 2 y 3, y después multiplica el resultado de la suma por 10. (El resultado final de la expresién es 58.) En forma similar, la expresién 18 * (4 + §) produce 99. La expresién 80/4 da como resultado 20. Aqui tenemos otros ejemplos de expresiones: La estructura de un programa de C Expresion Descripcion 8 Una expresién de una constante. i Una expresién de una variable. eri ‘Una expresién de una constante més una variable. exit(®) ‘Una expresién de llamada a una funcién. Operadores Como ha visto, una expresién puede contener simbolos como +, estos simbolos se denominan operadores aritméticos. La tabla 3 todos los operadores aritméticos y su significado, y 7. Enel lenguaje C, presenta una lista de: Tapia 3.1 Operadores aritméticos de C Simbolo __Significacto . Suma Resta . Multiplicacién ‘ Divisién ’ Residuo (¢ médule) Tal vez ya esté familiarizado con los operadores aritméticos, con excepcién del de resi- duo (*). Este operador se usa para obtener el residue de la divisin del primer operando entre el segundo. Por ejemplo, la expresi ona produce un valor de 2 debido a que 4 cabe una vez en 6 con un residuo de 2. El operador de residuo, *, también se conoce como operador de médulo, Entre los operadores aritméticos, los operadores de multiplicacién, divisidn y residuo tienen una precedencia més alta que los operadores de suma y resta. Por ejemplo, la expresion ator da como resultado 32, no 56, debido a que el operador de multiplicacién tiene mayor precedencia que el de:suma, Primero se calcula 3 * 1@ y después se suma 2 al resultado de ta multiplicacién. 43 Hora 3 Como quiz sepa, puede colocar paréntesis alrededor de una suma (o de una resta) para forsar que la summa (6 resta) sé realice antes de un céleulo de multiplicacién, divisién o mdédulo, Por ejemplo, la expresién (2+ 3)" 10 realiza primero la suma de 2 y 3 antes de multiplicar el resultado por 10. ‘La coma y el punto y coma son. operadores empleados en la sintaxis. En general, cl punto Y coma se utiliza para indicar el final de una instruccién, como veri més adelante. La ‘coma se usa en ciertas instancias én las que una instruccién consta de una lista de expre- siones o declaraciones, Aprenderi més operadores del lenguaje C en la hora 6, “Manejo de dato: hora 8, Uso de operadores condicionales”. Identificadores Junto con los niimeros (como la constante 7) y los operadores (como él simbolo +), las cexpresiones también pueden contener palabras denominadas identificadores. Los nombres de funciones (como exit) y los nombres de variables (como i), asi como las palabras reservadas son identificadores de C. yenla | siguiente es un conjunto de caracteres que usted puede utilizar para formar un ideatifi- 3: 4: main() 5: { 8: printf (*iHola, amigo! Este es mi priner pragrana de C.\n*); 7: return @; El principio y el final de una funcién Como ya se habré dado cuenta, se emplean Ilaves para sefialar el inicio y el final de una funcién. La lave de apertura ({) indica el comienzo del cuerpo de una funcién, mientras qué la Have de cierre (}) marca el fin del cuerpo de ta funcién. Como se mencioné antes, también se utilizan llaves para marcar el inicio y el final de wn blogue de instrucciones. Puede pensar en ello como una extensiGn natural para usar laves con las funciones, ya que una funcién consta de una o varias instrucciones. El cuerpo de la funcién En una funcién, el cuerpo de la misma es el lugar que contiene declaraciones de variables y otras instrucciones de C. La tarea de una funcién se lleva a cabo mediante la ejecucién de las instracciones, una a la vez, que se encuentran dentro. de su cuerpo. Es importante recordar que toda declaracién de variable se debe colocar al principio del cuerpo de la funcién. Es ilegal poner declaraciones de variables en cualquier otra parte que no sea él inicio de un bloque de instrucciones. ‘Si el cuerpo de su funcién contiene declaraciones de variables, debe colocar dichas declaraciones antes que cualquier otra instruccién. El listado 3.1 muestra una funcién que suma dos enteros especificados por sus argumentos, y devuelve el resuliado de la suma, La estructura de un programa de C 49) Lustape 3.1 Una funcién que suma dos enteros vs 3.0 1 Esta funci6n suna gos enteros y devuelve el resultado */ 2: int suma_enteros ( int x, dot y ) af 4 int resultado; 5: resultado = x + ys 6: return resulted; 7 } Como aprendi en la hora 2, la linea 1 del listado 3.1 es un comentario que describe lo que la funcién puede hacer. Observe que en la linea 2 se pone el tipo de datos int como prefijo, antes del nombre de Ja funcién, Aqui, int se utiliza come el tipo de funcién, lo que significa que la funcién devuelve un entero, El nombre de ta funcién que se muestra en la linea 2 es suma_enteros. La lista de argumentos de la misma I{nea contiene dos argumentos, int x © int y, y el tipo de datos int especifica que ambos argumentos son enteros, La linea 3 contiene la lave de apertura ({) que marca el inicio de la funcién, El cuerpo de la funcién comprende Ias Ifneas 4 a 6 del listado 3.1. La linea 4 presenta la declaracién de la variable resultado, la cual est especificada por él tipo de datos int como un entero, La instruccién de Ia linea 5 suma los dos enteros representados por x y ¥» ¥ asigna el resultado del célculo a la variable resultado. La instruccién return dela Ifnea 6 devuelve entonces el resultado del célculo representado por resultado. Por tiltima, pero no por para cerrar la funcién, Jo menos importante, s¢ usa la llave de cierre (}) de la linea 7 ‘trabajo. Si una funcién tiene mucho que hacer, seré muy dificil de escribir y ‘depurar. Si thene un proyecto de programacién complejo, dividalo en piezas pequeftas. Procure asegurarse de que cada funcién realice solamente una ‘area. g Al crear una funcién en su propio programa de C, no le asigne demasiado Cémo hacer Ilamadas a funciones Con base en lo que hasta ahora ha aprendido, puede escribir un programa en C que lame snteros() para calcular una suma e imprimir el resultado en la pan- talla, En el listado 3.2 se muestra un ejemplo de dicho programa. Hora 3 Listapo 3.2. Un programa de C que calcula una suma e imprime el resultado en la pantalla J* @3L02.c: Calcula una Suma @ imprine @1 resultado */ Winclude /* Esta funeién suma dos enteros y devuelve el resultado */ int suna_enteros( int x, int y ) { int resultado; resultada = x + y; return resuitada; ) int main() int suna; ‘Suma = suna_enteros(5, 12); printf(*La Suna de 5 y 12 es Sd.\n", suma); return @; ecdecaererereetene El programa del listado 3.2 se guarda como un archivo fuente Hamado a3Le2.¢. Desputs de compilarlo y enlazarlo, se ctea un archivo ejecutable para e3L02.c. Ea mi maquina, el archivo ejecutable se Hama 03L02.6x6. La siguiente es la salida que se imprime en la pantalla después de ejecutar dicho archivo en mi maquina: La guna de 5 y 12 es 17. La linea 1 del listado 3.2 es un comentario acerca del programa, Como aprendié en la hora 2, la directiva include de la linea 2 incluye el archivo de encabezada staio.n debido a que en el programa se usa la funcidm printf (). Las lineas 3 a9 representan a la funcién suna_enteros() que, como se explicé en la seccidn anterior, suma das enters. La funcidin nain(), con el tipo de datas int como prefijo, inicia en la Kinea 11. Las linens 12y 18 contienen las Hlaves de apertura y cierre de la funcidn main (}, respectivamente, En la linea 13 se declara una variable entera, suma, ‘La instruccién de la Ifnea 15 lama a la funcién suma_enteros() que usted examiné en la seccién amerior. Observe que las dos constantes enteras, 5 y 12, se pasan a la funcién suma_enteros(), y que a la variable suna se le asigna el resultado devuelto por la fun- cidn suma_enteros(). La estructura de un programa de C 51) En la hora 2 vio la funcién print#() de la biblioteca estindar de C. Si piensa que encon- tnd algo nuevo agregado a la funcidn de Ia linea 16, tiene raz6n. Esta vez se le pasaron dos argumentos a la funcidn printf (), Ellos son la cadena *La suma de S y 12 es d\n" y la variable suna, Observe que en el primer argumento se agrega un nuevo simbolo, sa. El segundo argumen- toes la variable entera suma. Debido a que el valor de suna se imprimiré en la pantalla, usted podria pensar que 4d tiene algo que ver con la variable entera suna. Otra vez tiene razén, Sd indica a la computadora el formato en el que debe imprimir a suna en la pantalla. En a hora 4 se abordan mds detalles sobre id. La relacién entre sd y suma se explica en Ia hora 5, “Manejo de la entrada y salida esténdar”. Pero sobre todo, es importante que se concentre en el programa del listado 3.2 y preste atencién a cémo hacer una llamada, ya sea a una funcién generada por el usuario o a una, funcién de la biblioteca estindar de C, desde la funcién main() Resumen En esta leccién aprendié los siguientes conceptos y operadores + En C, una constante es un valor que nunca cambia. Por otra parte, una variable puede presentar diferentes valores, ‘+ Enel lenguaje C, a una combinacién de constantes, variables y operadores se le ama expresién. Una expresin se utiliza para denotar diferentes. cilculos, + Los operadores aritméticos incluyen +, -.*, / y% + Una instruceién consta de una expreskin completa con un punto y coma como sulfij. + El compilador de C trata a un bloque de instrucciones como a una sola instruccién, aunque e| bloque podria contener més de una instruccién, + El tipo de funcién que se especifica en la declaracién de una funciém determina el tipo de valor que devuelve dicha funcién. + Debe seguir ciertas reglas para formar un nombre de funcién valido, + Un argumento contiene informacién que usted desea pasar a una funcién. Una lista de argumentos contiene dos o mis argumentos separados por comas. ‘+ Las llaves de apertura ({) y de cierre (}) se usan para marcar el inicio y cl final de una funcién de C. + El cuerpo de una funciGn contiene declaraciones de variables ¢ instrucciones, Por lo regular, una funcién debe evar a cabo slo una tarea, En Ia siguiente leccidn aprender més acerca de los tipos de datos del lenguaje C. 52 Hora 3 Preguntas y respuestas P ;Cual es la diferencia entre una constante y una variable? R La principal diferencia es que el valor de una constante no se puede modificar, mientras que el de una variable sf, En su programa de C puede asignar diferentes valores a una variable siempre que sea necesario. P {Por qué necesita un bloque de instrucciones? R Muchas palabras reservadas de C sdlo pueden controlar una instruccién. Un bloque de instrucciones proporciona una forma de poner varias instrucciones juntas, y de que una palabra reservada de C controle ¢| bloque de instrucciones. Entonces, el bloque es tratado come una sola instruccién. P {Qué operadores aritméticos tienen una precedencia més alta? R De entre los cinco operadores aritméticos, los operadores de multiplicacién, divisién y residuo tienen una precedencia mds alta que los operadores de suma y resta. _Cudntas partes tiene normalmente una funcién? R_ Normalmente, una funcién tiene seis partes: el tipo de Ia funcién, el nombre de la funcién, los argumentos, la Have de apertura, el cuerpo de la funcién y la lave de cere. a Taller Para consolidar la comprensién de la leceién de esta hora, le recomiendo responder el ‘cuestionario y terminar los ejercicios de este taller antes de pasar a la siguiente n, Las respuestas y sugerencias se presentan en el apéndice B, “Respuestas a los cuestiona- rios y ejercicio: Cuestionario 1, Es 74 una constante en el lenguaje C?, ;qué hay de 71? 2. jEsx = 578 + 1 unaexpresién?, jloesx = 12 + y? 3. jSon vélidos los siguientes nombres de funcién? anétodos algoritmo_a2 +funcién_inicio Espacto_cuerto .Termina_Exe _suma_turbo 4. (Es2+ 5 * 2iguala (2 + 5) * 2? 5. gProduce 7 % 2 el mismo resultado que 4 © 3? La estructura de un programa de C 53) Ejercicios 1. Dadas las dos instrucciones, x = 3; yy = 5 + x;, jo6mo puede generar con ambas un bloque de instrucciones? 2. {Que esté mal en la siguiente funcién? int Ssuna_enteros( int x, iat y, int 2) ( int suna; suma = x + y + 25 return sums; ) 3. {Qué esti mal en la siguiente funciGn’? int suma_enteros( int x, int y, int 2) 4 int suna; sua = x+y +2 return suna; ) 4, Escriba una funcién de C que pueda multiplicar dos enteros y devolver el resultado. 5, Bscriba un programa en C que lame a la funcidin de C que acaba de escribir en el ejercicio 4, para calcular la multiplicacién de 3 por $ e imprimir después en la pan- talla el valor de retomo de la funeién. a 4, Wily HORA 4 Tipos de datos y palabras reservadas Qué es un nombre? Aquello que [amamos rosa oleria dulce con cualquier otro nombre, —W. Shakespeare En Ia hora 3, “La estructura de un programa de C, aprendié ome formar un nombre vélido para una funciGn de C. Ahora aprenderd més acerca de ‘c6mo nombrar una variable y de las palabras reservadas del compilador de C. Ademiés, en esta hora aprender detalladamente los cuatro tipos de datos del lenguaje C: * el tipo de datos char * €l tipo de datos int * el tipo de datos floet * el tipo de datos double 56 Hora 4 Palabras reservadas de C El lenguaje C reserva ciertas palabras que tienen un significado especial para el lenguaje. Estas palabras reservadas también se conocen como palabras clave de C. No debe utilizar en sus programas palabras reservadas de C para nombrar sus propias variables, constantes @ funciones, La tabla 4.1 presenta una lista de: 32 palabras reservadas de C. Tapia 4.1 Palabras reservadas de C Palabra reservada —_Descripcién auto Especificador de clase de almscenamiento break Instruccidin Instroccidn Especifieador de tipo const Modificador de clase de almacenamiento continue Instruecidin defauit Etiquetas @ Instruccisa couple Especificadar de tipo else Instraceida onus Especificadoe de tipo extern [Especificador de clase de almacenamiento float Especificador de tipo tor Tnstrucciéa, goto ‘Instruccidin, at ‘nstruccidn, int Especificadoe de tipo long ‘Especificadar de tipo roaistor ‘Especificador de elase de almacenamiento return Instruccién shart ‘Especificador de tipo signed Especificador de tipo sizeot ‘Operador static Especificador de clase de almacenamiento struct Especificador de tipo ‘switch Instruccién Tipos de datos y palabras reservadas 57) Palabra reservada __Deseripcién tynedet Instruccién wunion Especificador de tipo unsigned Especificador de tipo: vous Espeeificador de tipo: volatile Modlificador de clase de almacenamiente whi Instruce! ‘No se preacupe si no puede recordar a la primera todas las palabras reservadas de C, En el resto del libro se familiarizaré més con ellas y comenzaré a usatlas en los ejemplos y ejercicios. ‘Observe que todas las palabras reservadas de C estén escritas en mintisculas. Como ya ‘mencioné, C es un lenguaje sensible al uso de maydsculas y mimisculas. Por lo tant ‘como se muestra en la lista, int es una palabra reservada de C, pero INT no lo es. El tipo de datos char Un objeto del tipo de datos char representa un solo cardcter de! conjunto de caracteres ‘que utiliza su computadora. Por ejemplo, A es un carécter, y a también lo es, Pero 7 es un nimero. Sin embargo, una computadora s6lo puede almacenar cédigo numérico. Por lo tanto, los caracteres como A, a, B, b, etcétera, tienen un cédigo numérico tinico que utilizan las computadoras para representar los caracteres. Por lo regular, un cardcter ocupa 8 bits (es decir, 1 byte) para almacenar su cédigo numérico. Para muchas computadoras, los cédigos ASCII son los o6digos estindar para representar un conjunto-de caracteres, (Sélo para su informacién, ASCII significa Cédigo Estindar Estadounidense para e| Intercambio de Informacién.) El conjunto de caracteres ASCIL original tiene solamente 128 caracteres debido a que utiliza los 7 bits menos significa- tivos con los que se pueden representar 2° caracteres (es decir, 128). Sin embargo, en las PCs compatibles con IBM, el conjunto de caracteres se amplié para contener un total de 256 caracteres (esto es, 25) Algo que quisiera mencionar aqui es que el estdndar ANSI de C especifica solo el valor del cardcter nulo, el cual siempre es cero (es decir, un byte con ceros en todos los bits). Los demas valores numéricos de los caracteres los determinan los tipos de computadoras, sistemas operatives y compiladores de- C. Le recomiende que explore el conjunto de caracteres de su computadora, Puede hacerlo con el programa del listado 4.1. [58 Hora 4 En el mundo de la computacién, un bit €s la unidad mas pequefa de almace- namiento de datos, y slo puede tener uno de estos dos valores: 0.0 1. Estot valores representan los dos estados de los interruptores electrénicos que se vusan en la memoria y en la CPU de la computadora. Un byte: es una unidad més grande que un bit. De hecho, acho bits equivalen a un byte. Variables de tipo caracter Una variable que puede representar diferentes caracteres se Hama variable de tipo cardcter. Puede asignar el tipo de datos char a una variable mediante el siguiente formato de declaraciin: char nombrevariable; endonde nombrevariable es el nombre que usted proporciona, y en el que se almace- nardn valores de este tipo. Si tiene mas de una variable que declarar, puede utilizar el siguiente formato: char nombrevariablet; char nombrevariabie2; char nombrevariabie3; © bien, este otro: char nombrevariable1, nombrevariable?, nonbrevariables; Por ejemplo, la siguiente instruccién declara miCaracter y le asigna el valor de char MiGaracter = Del mismo modo, las siguientes instrucciones declaran x, y y z como variables de tipo carter y después les asignan valores: enar x, yy 2 =A; ye't pet Observe que la dltima instruecién, z = ‘7’, asigna a z el valor numérico que representa el cardicter '7' en el conjunto de caracteres, no el ntimero 7 real. ‘Mis adelante aprenden més acerca de las variables de tipo cardcter y como usarlas en ‘sus programas de C_ Constantes de caracter Un candcter encerrado entre comillas.sencillas (*) se llama constante de cardcter. Por ejemplo, 'A*, ‘a’, "8° y 'b’, son constantes de caricter que tienen sus valores numéri- Tipos de datos y palabras reservadas 59] cos tinicos en un. conjunto de caracteres dado, Por ejemplo, podria ver los valores numéricos tinicos del conjunto de caracteres ASCII. Es importante recordar que las constantes de cardcter siempre estdn encerradas entre comillas sencillas (*), mientras que una cadena de més de un cardcter utiliza comillas dobles (*). Si esto le parece confuso, slo recuerde que las comillas sencillas van con un solo cardcter. En la hora anterior vio un ejemplo de comillas dobles y cadenas de carac- teres en las Ilamadas a la funcion printf (}. En el conjunto de caracteres ASCH encontrar que los valores numéricos (decimales) tinicos de “A‘, 'a', “B' y ‘b* son 68, 97, 66 y 98, respectivamente. Por Jo tanto, dada x ‘como una variable de tipo carfcter, y dado el conjunto de caracteres ASCII, las siguien- tes instrucciones de asignacién son equivalentes: Pe x = 65; ‘También lo son las dos siguientes: aera; x= 97; ‘Mas adelante, en el listado 4.2, verd un programa que convierte los valores numéricas en Sus caracteres correspondientes. 03 No confunda x = ‘a‘;conx = a:. La primera instruccion le asigna ala variable x el valor numérico del caracter a, esto es, x contendra el valor 97 desputs de la asignacién (el valor ASCII de la letra ‘a’. Sin embargo, Ia ins- truccién + a: le asigna a la variable x cualquier valor contenido en la variable «.Posteriormente aprenderé mis acerca de esta diferencia. El cardcter de escape (\) En realidad, usted vio el cardcter de escape (\) en la hora 2, “Su primer programa de cuando aprendié a usar el caricter de nueva linea (\n) para dividir un mensaje en dos partes. Por lo tanto, en e] conjunto de caracteres ASCII, la diagonal invertida (\) se llama. cardcter de escape, Este caracter se emplea en el lenguaje C para indicar a la compu: tadora que sigue un carécter especial. Por ejemplo, cuando la computadora ve \ en el cardcter de nueva linea \n, sabe que el siguiente cardcter, n, genera una secuencia de retorno de carro y un salto de Ifnea. 60 Hora 4 Ademis de! cardcter de nueva linea, los siguientes son algunos de los caracteres espe- ciales del lenguaje C: Cardeter__Descripeién rs El cardcter de retroceso; mueve el cursor un cardcter hacia la inquierda, \f El cardcter de salto de pagina; pasa a la parte superior de la pagina siguiente \r El canicter de retorno; regresa al principio-de la linea actual At El cardcter tabulador, avanza al siguiente paro de tabulador, Impresién de caracteres Usted ya sabe que la funciGn print#(), definida en el archivo de encabezado stdio.h de C, se puede utilizar para imprimir mensajes en la pantalla (consulte el listado 2.1 de la hora 2). En esta seccién aprender a usar el especificador de formato de cardcter, %c, el cual indica a la funcién printf () que el argumento por imprimir es un cardcter. (Apren- der més acerca del especificador de formato en Ia hora 5, “Manejo de la entrada y salida estindar”. Aquf sélo tendrd una probadita.) Por ahora, lo importante es que sepa que cada especificador de formato que pase a print? () corresponderd a una de las variables que pase a la funcién. Veamos primero el programa del listado 4.1, el cual imprime earac- teres en la pantalla. Bizet Listapo 4.1 impresién de caracteres en la pantalla [* G4L81.c; Impresién de caracteres */ include main() char ct; char ¢2; ers tay ce = ay printf (‘Convierte el valor de ct a cardcter: %c.\n", et); printf (*Convierte el valor de ¢2 a caracter: %c.\n", c2); return 0; Después de crear el archivo ejecutable de 04L01 .¢ del listado 4.1, puede efecutarlo para ver qué se imprimir en la pantalla. En mi méquina, el archivo ejecutable se llama 04101 .exe. El siguiente es el resultado que se imprimié en la pantalla de mi compu- tadora después de ejecutar el programa: pos de datos y palabras reservadas Convierte el valor de ct Convierte el valor de 2 Las Iineas 6 y 7 declaran dos variables de tipo carécter, ¢1 y ¢2, mientras que las lineas 9 y 10 asignan a ct y a c2 las constantes correspondientes a los caracteres 'A' y ‘a’, respectivamente, Observe que en las lineas 11 y 12 se usa el especificador de formato %e en 1a funciéa, printf (), lo cual indica a la computadora que el contenido de ¢1 y ¢2 se debe imprimir como cardcter, Al ejecutar las dos instrucciones de las lineas 1 y 12, se da formato a dos curacteres y se muestran en la pantalla, con base en los valores numéricos conte- nidos por c' y @2, respectivamente, Ahora observe el programa que se muestra en él listado 4.2. Esta vez, se se usa para con vertir los valores numéricos en sus caracteres correspondientes. Lustavo 4.2. Conve J* 94L02.c: Convierte valores numéricos en caracteres */ include in de valores numéricos en caracteres nain() char 1; char c2; et =65; 62 997; printf(*EL cardeter que tiene el valor numérico de 65 #: Printf(*El cardater que tiene él valor numérico de 97 «: return 0; Re.\n", ot); Renin", 02); EI siguiente es el resultado que se imprimié en la pantalla de mi computadora después de ejecutar el archivo 84.02. exe, (Usted podria obtener un resultado diferente en su compu- tadora; depende de Ia implementacién. Esto es, depende del tipo de su computadora, del sistema operativo y del compilador C que ¢sté utilizando): F que tiene el valor numérico de 65 01 F que tiene el valor numérico de 97 e1 Eta E] programa del listado 4.2 es similar al del listado 4.1, con excepcién de las dos instrucciones de las lineas 9 y 10. Observe que thas lineas del listado 4.2, a las variables de tipo cardcter ct y ¢2 se les asignan los valores 68 y 97, respectivamente, EL carie' EL carde' 62 Hora 4 Coma usted sabe, en el conjunto de caracteres ASCIL, 65 es el valor numérico (decimal) del cardeter A; 97 es el valor numérico de a, En las lineas 11 y 12, el especificador de formato %c convierte los valores numéricos, 65 y 97, en Ay a, respectivamente, Entonces, los caracteres 4 y a se imprimen en la pantalla. El tipo de datos int En la hora 3 vio el tipo de datos entero, La palabra reservada int se utiliza para especi- ficar que una variable es de tipo entero. Los niimeros enteros, Hamados simplemente en- teres, no tienen fracciones ni punto decimal. Por lo tanto, el resultado de una divisién centera se trunca, simplemente porque se ignora cualquier parte de fraccién, La longitud de un entero varia dependiendo del sistema operative y del compilador de C que utilice, Por ejemplo, en la mayoria de las estactones de trabajo UNIX, un entero tiene una longitud de 32 bits, lo que significa que el rango de un entero va de 2147489647 (esto es, 21-1) a -2147489648, Para un entero de 16 bits, el rango va de 92767 (esto es, 2!"1) a -32768, Como lo dije anteriormenie, esto puede variar enire sistemas diferentes, de modo que para estar seguro puede revisar los materiales de referencia de su compilador, ‘Algunos compiladores de C, como el Visual C++ 1.5, silo proporcionan enteros de 16 bits, mientras que otros compiladores de C de 32 bits, como el Visual C++ 3.0, soportan enteros de 32 bits. Declaracién de variables enteras ‘También vio la declaracién de un entero en la hora 3. El siguiente es el formate bisico de declaracidn: int nombrevariable; Al igual que en la declaraci6n de las variables de tipo carfecter, si tiene més de una varia- ble que declarar, puede utilizar un formato como éste: int nombrevariablet; int aombrevariabli int aombrevariables; 9 bien, uno.como Este: int nombrevariablet, nombrevariable2, nombrevariable3; Aqui, nonbrevariable1, nombrevariable2 y nombrevardables indican las posiciones en Jas que usted coloca los nombres de variables de tipo int, Por ejemplo, la siguiemte instruccién declara witntero como una variable entera y le asigna un valor: int MiEntere = 2314; Tipos de datos y palabras reservadas 63 Del mismo modo, la siguiente instruccién declara A, a, By b como variables enteras: Més adelante aprender més acerca del tipo de datos entero, ‘Cémo mostrar los valores numéricos de los caracteres ‘Al igual que el especificador de formato de carticter (%c) que se usa para dar formato a un solo cardcter, el especificador de formato entero, ‘a, se usa para dar formato a un entero. Tal vez recuerde que en la Ifnea 16 del listado 3.2, se usd sd para dar formato de entero al segundo argumento de la funcidn print). En esta seccién estudiard el programa que se muestra en el listado 4.3, el cual puede imprimir los valores numéricos de los carscteres utilizando el especificador de formato entero 46 en la funcidn print () J* O4L03.c: Como mostrar el valor numérico de los caracteres */ Finelude main() char ct; char c2; ers tA; 2 = ta’ printf("EL valor numérico de A es: ‘d.in", ct); printf(*El valor numérico de a es: %d.\n", ¢2); return @; ‘Obtuve el siguiente resultado en la pantalla de mi computadora, después de ejecutar el archivo 04L03..exe. (Usted podria obtener una salida diferente, si su méquina no emplea ef conjunto de caracteres ASCIL) El valor numérico de A es: 65. FER es vaiss ctérsce ae a en: or. ‘Tal vez encuentre que el programa del listado 4.3 es muy similar al del listado 4.1. De hecho, simplemente capié el cédigo fuente del listado: 4.1 al listado 4.3 cambios en las Iineas 11 y 12, El principal cambio que realice fue reemplazar el especificador de formato de caricter (¥c) por el especificador de formato entero (a). Hora 4 Ambos especificadores de formato hacen basicumente lo mismo: insertar ciertos datos en Ja cadena que usted pasa a printt(), pero la diferencia est en la forma en que printf() muestra los datos. El especificador vc siempre imprime un cardcter; el especificador ‘i siempre imprime un ndmero. Incluso cuando se refieran exactamente a los mismos datos, ésios se imprimirn en la forma que se indique en el especificador de formato sin impor- tar el tipo de datos real. Las dos instrucciones de las lineas 11 y 12 dan formato a las dos variables de tipo cart ter (ct y c2) utilizando el especificador de formato entero ‘d, y después imprimen dos mensajes que muestran los valores numéricos 66 y 97 que representan, respectivamente, alos caracteres A y a del conjunto de caracteres ASCIL El tipo de datos float El miimero de punto flotante es otvo tipo de datos del lenguaje C. A diferencia de un mi- mero entero, un nimero de punto flotante contiene un punto decimal. Por ejemplo, 7.01 ‘es un niimero de punto flotante, asi como también 5.71 y -3.14. Los ntimeros de punto flotante también se conocen como niimeros reales: En el lenguaje C, la palabra reservada float especifica un mimero de punto flotante. Las ‘constantes de punto flotante pueden tener el sufijo f o F para especificar float. De ma- nera predeterminada, un nimero de punto flotante sin un sufijo es de tipo double. El tipo ‘de datos double se presenta més adelante en esta lecci6n, Al igual que un mimero entero, un mimero de punto flotante tiene un rango limitado, El ‘estndar ANSI requiere que el rango sea de-—1.0 x 10° a 1.0 x 10". En Ia mayoria de los ‘casos, un ntimero dé punto flotante es de 32 bits. Por lo tanto, en C, wn ndimero de punto flotante es de por lo menos seis digitos de precisiGn. Esto es, un ntimero de punto flotante tiene por lo menos seis dfgitos (0 posiciones decimales) después del punto decimal. A diferencia de Ia divisién entera, en la que se trunca ¢l resultado y se descarta la frac- cién, una divisién de punto flotante produce otro ntimero de punto flotante. Una division de punto flotante se leva a caho si el divisor y él dividendo, 0 s6lo uno de ellos, son niimeros de pinto flotante. Por ejemplo, 571.2 / 19. produce otro nmero de punto flotante, 57, 12, Lo mismo sucede con $71.2 / 10 y 5712 / 10.0. Declaracién de variables de punto flotante El siguiente es el formato de declaracién de una variable de punto flotante: fost aosbrevariable; Tipos de datos y palabras reservadas 65) Igual que en la declaracién de una variable de tipo entero o de cardcter, si ticne mis de una variable que declarar, puede emplear un formato como éste: float nombrevariable3; © bien, uno como el siguiente: float nombrevariable’, nonbreverieble2, nombreveriable3; Por ejemplo, la siguiente instruccién declara miFloat como una variable de punto flotante y le asigna un valor: float mifloat = 3.14; Del mismo modo, la siguiente instruccién declara a, by ¢ come variables de tipo float: float 8, by 6; El especificador de formato de punto flotante (%) ‘También puede emplear el especificador de formato de punto flotante (%) para dar for mato a su salida. El listado 4.4 muestra un ejemplo de cémo usar el especificador de formato ‘f en la funcién printf (). Listapo 4.4. Impresién de resultados de divisiones entera y de punto foarte 1; I Q4L04,cr Division entera vs. division de punto flotante */ 2: include int getc(FILe *flujo); Aqui, FILE “flujo declara un flujo de archive (es decir, una variable). La funcién devuelve el valor numérica del candcter lefdo. Si ocurre un error 0 un fin de: a arehivo, la funcién devuelve ene No se preocupe por ahora de Ia estructura de FILE, ya que se presentan més detalles acerca de esto en la hora 21, “Lectura y escritura de archives”, y en la hora 22, “Funciones de archivo especiales”. En esta seccién se usa el flujo de entrada estindar stain como el archivo de flujo especificado por FILE *fluso. EOF es una constante detinida en el archivo de encabezada stdio.h. EOF son las siglas de end-of-file (fin de archivo). Por lo regular, el valor de EOF e3 1 Pero siga usando EOF, en lugar de -1, para indicar el fin de archivo en sus programas. En esa forma, si mas adelante utiliza un compilader 0 un sistema ‘operative que utilice un valor diferente, su programa seguir funcionando. El listado 5.1 muestra un ejemplo que lee un cardcter escrito por el usuario desde el teclado, y después lo despliega en la pantalla, Listapo 5.1 Lectura de un cardcter Jiante una Llanada a gete() "/ roducido por el usuario [* O5L81.c: Lectura da datos m include main() { int chy prantf(*Eseriba, por favor, un cardeter:\n"); sh = getet stdin }; printf("El cardcter que acaba de introducir es: Sen", ch); return @; El siguiente es el resultado desplegado en 1a pantalla de mi computadora después de sejecutar el archivo 05101 .exe, escribir el cardcter H y oprimir la tecla Entrar: Escriba, por favor, un cardcter: " E1 cardcter que acaba de introgucir es: H 4 Hora 5 Puede ver en la kinea 2 del listado $.1 que se incluye el archive de encabezado stdio.n para las funciones geto() y printf () que se utilizan en el programa, Las lineas 4 a 12 presentan el nombre y el cuerpo de Ia funcién main( Er En Ia linea 6 se declara la variable entera en; més adelante, en Ia linea 9, se le asigna el valor de retorno de la funcién getc(). La linea 8 imprime un mensaje que solicita al usuario que eseriba un cardcter desde el teclado, Como mencioné antes en esta leccidén, la amada a la funcién printf () de la linea 8 usa la salida estindar predeterminada stdout para mostrar mensajes en la pantalla, En Ia linea 9 se pasa el flujo de entrada estindar stdin a la funcién getc(), lo cual indica que el flujo de archivo proviene del teclado. Después de que el usuario introduce un cardcter, la funcidén gete() devuelve el valor numérico (esto es, un entero) del cardcter. Observe que en la linea 9 se na ¢l valor numérico a la variable entera ch. Después, en la linea 10, el cardecter que introdujo el usuario se despliega en la pantalla con la ayuda de print?(). Observe que dentro de la Hamada a Ia funcién print#(), en la misma linea, se usa el especificador de formato de cardcter (a). (En el ejercicio 1 de esta leceiGn se le solicita que utilice +d en un programa para imprimir ef valor numérico de un carécter introducido por el usuario.) Uso de la funciédn getchar() El lenguaje C proporciona otra funcién, getchar (), que re gete(). Para ser mis precisos, la funcién getehar() equivale a gete(stdin). La sintaxis de la funcidn getchar() es include int getchar (void) ¥ Aqui, void indica que no es necesario ningtin argumento para llamar a la funcién. La funci6n devuelve el valor numérico del cardcter leido. Si ocurre un error © un fin a de archivo, la funcién devuelve er. El programa del listado 5.2 muestra cémo usar la funci6n getcnar() para leer entradas. del usuario. Misstigy Listapo 5.2 Lectura de un cardcter mediante una llamada a getchar() {* W5L@2.c: Lectura de datos mediante una llamada a gatchar() */ Winclude int pute(int ¢, FILE *fluja); ¥ Aqui, el primer argumento, int ¢, indica que la. es un caracter almacenado en la variable entera ¢; el segundo argumento, FILe «flujo, especifica un flujo de archivo. Si tiene éxito, pute() devuelve el cardcter escrito; en caso contrario, a devuelve eor. En esta lecci6n se especifica Ia salida estindar stdout como el flujo de archivo de salida de pute(). En el listado 5.3 se utiliza la funcién pute) para desplegar el cardcter A en la pantalla. Listano 5.3. Cémo desplegar un cardcter en la pantalla 1: /* @5LB8.¢: Cémo desplegar un carécter con putc{) */ 2: include 3: 4: main() & int oh; ch = 65; /* el valor numérico de A */ printf("El caracter que tiene el valor numérico de 65 @s:\n"); pute(ch, stdout return El siguiente resultado es el que obtuve en mi méquin: El cardcter que tiene @1 valor nunérico de 65 es: Como ya mencioné, en la linea 2 se incluye el archivo de encabezado stdio.n, el cual contiene la declaracién de pute() En la linea 8 se le asigna ¢] valor numérico 65 a la variable entera ch, declarada en la Ifnea 6. En el conjunto de caracteres ASCII, el valor numérico del carécter A es 65. En [a linea 9 se despliega un mensaje para recordar al usuario que se pondréi en la pan- talla el valor numérico del cardcter. Después, en Ia Ifnea 10, la funciéa pute( )coloca el caricter A én la pantalla, Observe que el primer argumento para la funcién putc() es la variable entera (ch) que contiene el valor 65, y que el segundo argumento es el flujo de: archivo de salida estindar, stdout. Manejo de la entrada y salida estandar 7 Otra funcién para la escritura: putchar () ‘Al igual que putc(). también se puede usar putchar() para desplegar un cardcter en la. pantalla. La tinica diferencia entre las dos funciones es que putchar() sdlo necesita un argumento para contener el cariicter, No es necesario especificar el flujo de archive, debi- do a que la salida esténdar (stdout) se asigna como el flujo de archivo para putchar() La sintaxis de Ia funeiin putehar() es include int putchar(int c); Aqui, 1at ¢ es el argumento que contiene el valor numérico de un cardeter. La fun- cidn devuelve oF si ocurre un error; en caso contrario, devuelve el caricter que se a escribis., En el listado 5.4 se muestra un ejemplo del uso de putohar() a Listape 5.4 Cémo mostrar caracteres con putehar() J* @SLO4.c: Gono mostrar caracteres con putenar() */ Minclude putchar (66) ; putchar (10); . obtuve los siguientes resultados: La forma de escribir el programa del listado 5.4 es un poco diferente. No hay ninguna variable declarada en el programa. Mas bien, los enteros se pasan directa- ‘mente a putchar(), como se muestra en las lineas 6 a 11. ‘Como se habré dado cuenta, 65, 66 y 67 son, respectivamente, los valores numéricas de Jos caracteres A, 8 y C en el conjunto de caracteres ASCII, Seguramente se dio cuenta en el ejercicio 5 de la hora 4, “Tipos de datos y palabras reservadas”, que 1@ es el valor numérico del cardcter de nueva linea (\n). 73 Hora 5 Por lo tanto, las lineas 6 y 7, respectivamente, colocan el caricter A en la pantalla y hacen que Ia computadora comience al principio de la siguiente linea. De la misma manera, la linea & despliega el cardcter 8 en la pantalla y la linea 9 inicia una nueva linea. Después, Ja Linea 10 despliega el cardcter C en Ia pantalla y la linea 11 inicia ofra nueva linea, De acuerdo con esto, A, By C, se colocan al principio de tres lineas consecutivas, como se ‘observ6 en Ia seccién que muestra la salida del programa, Nueva visita a la funci6én printf () La funcién printt() es la primera funcién de la biblioteca de C que utilizé usted en este libro para imprimir mensajes en la pantalla. printf() es una funcién muy importante en C, asf que vale la pena dedicarle mis tiempo. La sintaxis de la funeién print#() es. include int printf (const char *cadena-de-formato, . . v Aqui, const char *cadena-de-formato es el primer argumento que contiene elilos) especificadories) de formato; ... indica la seccién de la expresidn que con- tiene la(s) expresiGn(es) a formatear de acuerdo con los especificadores de formato. El niimero de especificadores de formato que hay en el primer argumenio determina el niimero de expresiones, Si tiene éxito, la funcién devuelve el niimero de expre~ ~ siones formateadas. Si ocurre un error, devuelve un valor negativo. const char * se explica mis adelante en esie libro. Por el momento, considere el primer argumento para Ia funcién printf () como una cadena (una serie de caracteres entre co- las dobles) con algunos especificadores de formato dentro de ella. Por ejemplo, puede Pasar como primer argumento a la funcién “La suma de dos enteros Sd + Sd es: Sd. tnt La figura 5.1 muestra la relacién entre la cadena de formato y las expresiones. Observe que los especificadores de formato y las expresiones coinciden en un orden de inquierda, a derecha. Figura 5.1 Le lin | prance ene da cadena de formato > lar erences prine{("Un mimero de punto flotante: %f; Un entera: Sd.” Manejo de la entrada y salida estandar 73) Recuerde que dentro de la cadena de formato debe usar exactamente el mismo néimero de expresiones y de especificadores de formato, Los siguientes son todos los especificadores de formato que se pueden usar en print#(): gee ec tes ssn se 2 El especificador de formato de carfeter. El especificador de formato entero. El especificador de formato entero (equivale a $d), El especificador de formato de punto flotante, El especifieador de formato de notacién cientifica (observe la e miniscula) El especificador de formato de notacién cientifica (observe la E maytiscula), Utiliza +f 0 %e, cualquiera que resulte més corto, Utiliza +f 0 X€, cualquiera que resulte mas corte. El especificador de formato octal sin signo, El especificador de formato de cadena El especificador de formato entero sin signo, El especificador de formato hexadecimal sin signo (observe la x mindiscula), El especificador de formato hexadecimal sin signo (observe la X maytiseula), Despliega el argumento correspondiente que es un apuntador. Registra el nimero de caracteres escritos hasta el momento. Muestra un signo de porcemaje (8). Entre los especificadores de formato de esta lista, ya presentamos ‘2, 8d, 8f, 4 ¥ SE. Mas adelante se explican varios més. La siguiente seccién muestra cémo convertit mimeros decimales a hexadecimales utilizando *% 0 $x. Conversion a ndmeros hexadecimales ‘Ya que en una computadora todas los datos son binarios (una serie de ceros y unos), cualquier dato con el que trabajemos o que imprimamos es s6lo una clase de represen- taciOn, legible para los humanos, de los datos binarios. Como programador, a menudo es necesario tratar directamente con datos binarios, pero consume demasiado tiempo descifrar una cadena de ceros y unos para convertirla en datos numéricos o caracteres que sean si Hora 5 La solucién a este problema es la notacién hexadecimal (o hex), la cual €s una especie de forma abreviada para representar niimeros binarios. La notacién hexadecimal es un ‘érmino medio entre el sistema numérico de base 2 (o binario) legible para la compu- tadora, ¥ nuestro més conocido sistema de base 10 (o decimal). Convertir niimeras de hexadecimal a decimal (o de binario a hexadecimal) y a la inversa, es mucho mas fil (y mas répido) que convertirlos directamente de binario a decimal, o viceversa, La diferencia entre un nimero hexadecimal y uno decimal es que el primero es un sistema de numeracién de base 16, Un mimero hexadecimal se puede representar mediante cuatro bits. (2% es igual a 16, lo que significa que cuatro bits pueden producir 16 mtimeros tinicos.) Los ntimeros hexadecimales del 0 al 9 emplean los mismos sfmbolos numéricos que se encuentran en los niimeros decimales del 0 al 9. Las letras 4, 8 0, D, € y F, en maytisculas, se usan para representar los ntimeros del 10 al 15. (Asimismo, las letras mindsculas a, b, c,d, @y # sé emplean para representar estos nimeros hexadecimales. Las maytisculas y mindsculas hexadecimales son intercambiables y en realidad se trata sélo de una cuestiin de estilo.) El listado 5.5 presenta un ejemplo de la conversién de mimeros decimales a hexadeci- males utilizando %x 0 8 en la funcidn printf(). Listapo 5.5 Conversién a numeros hexadecimales 1: /* OS5LO5.¢: Conversign a ndmeras. nexadecina’ Hinelude st) maint) 1 printf(*Hex(nayisculas) Hex(mindsculas) —Decinal\n* prantt( 8x x Sa\n", 8, 8, 8); printf (‘ax ax Adin" 1,1, 195 printt(*%X = wd\n", 2, 2, 2); printt ("Sx Sx ‘wdin", 3, 3, 3); peantt ("x te Sint, 4) 4, 4; prantt (=8x wx sain’, 5, 5, 5) prantt( "sx « win", 6, 6, 6) prantt (78% tx Sain, 7, 7, 7) prints ("x oa s\n, 8, 8, B) printe ("9x sain", 9, 9, 9) printt (“9x ~ ‘din", 18, 18, 10) printf ("4x Ad wa\n*, 11, 11, 11 printt ("ex 4 Sd\n", 12, 12, 12); prantt( "se we Sain, 13, 13, 13); prantt( x saint, 14, 14, 1405 print? (x 7 Adin", 15, 15, 18); return @; Manejo de la entrada y salida estandar 81) ente es el resultado que obtuve al ejecutar el archivo @5L05.exe en mi computador: Hex(mayusculas) Hex(mindsculas) Decimal ® 8 8 1 1 1 2 2 2 a 3 a 4 4 4 8 5 5 8 6 6 ? 7 7 a 8 a Q 8 a A a 1° 8 b " ¢ c 12 0 d 13 E e ‘4 F t 15 No se alarme si ve demasiadas llamadas a la funci6n printt() en el listado 5.5, De hecho, el programa de este listado es muy sencillo, El cuerpo de la funcién va de las Lineas 5a Ia 23. La funciGn print () de la Iinea 6 imprime un encabezado que contiene tres campos: Hex (mayGsculas), Hex(minisculas) y Decimal, Las lineas 7 a 22 imprimen los ndmeros hexadecimales y decimales del 0 al 15. Para realizar la tarea se hacen 16 tlamadas.a printf (). Cada una de las lamadas a print? () tiene una cadena de formate como primer argumento seguida de tres enteros que denotan tres expresiones. Observe que dentro de la cadena de formato de cada llamada a prantt() se usan los especificadores hexadecimales %X y ‘x, para convertir las expresiones corres- pondientes al formate hexadecimal (tanto en maytisculas como en mimtisculas), En realidad, nadie escribiria un programa como el del listado 5.5. En su lugar se puede utilizar un ciclo para llamar en forma repetida a la funcién printt(). Los ciclos (o itera- ciones) se presentan en la hora 7, “Ciclos”, Especificacién del ancho minimo del campo En un especificador de formato, el lenguaje C le permite agregar un entero entre el signo de porcentaje (4) y la letra. El entero se Hama especificador del ancho minima det cam- po, debido a que especifica dicha caracterfstica y asegura que la salida alcance el ancho minimo, Por ejemplo, en $1@f, 10 es un especificador del ancho minimo del campo que asegura que la salida sea de por lo menos 10 caracteres de amplitud. Esto es muy uti! al imprimir una columna de nimeros, Hora 5 El ejemplo del listado: 5.6 muestra cémo usar el especificador del ancho minimo del campo. Listape 5.6 Especifica J* Q5L06.c: Especificacién del ancho minimo del campo */ Winclude n del ancho minime del po 1 2 ra 4: main() { ant num, numa; numt = 12; ‘nun? = 12345; print? (“ed print? (“d\ print? (*4sd\n" print #(*sa5a\n 2 printf (*s2d\n" 15: return ej EI siguiente es ¢l resultado que obtuve al ¢jecutar el archivo @5L06.e 42 12345. 12 eoer2 12945, En la Linea 6 del listado 5.6 se declaran dos variables enteras, nut y oum, ¥ en las lineas 8 y 9 sc les asignan los valores 12 y 12945, respectivamente. Sin utilizar ningén especificador del ancho minimo del campo, las lineas 10 y 11 imprimen los dos enteros Iamando a la funcién printf(}. Puede ver en la seccién de salida que el resultado de la instruccién de la linen 10 es 12, el cual ocupa el espacio de dos carac- teres, mientras que el resultado 12945 de la linea 1 ocupa el espacio de cinco caracteres. En Ia linea 12 se especifica un ancho minimo del campo de 5, mediante %5d. Por Io tanto, Ja salida de Ia Linea 12 ocupa el espacio de cinco earacteres, ya que son tres espacios en blanca mais los dos caracteres del 12. (Vea la tercera Ifnea de resultados en In seccién de said.) El especificador ssa que esti en Ia funcidn print#() que se muestra en la Kinea 13, indica que el ancho minimo del campo es 8, y el @ indica que se emplean ceros para “rellenar” los espacios. Par lo tanto, puede ver que cl resultado de la ¢jecucién de la instruccién de Ja linea 13 es 00812. Manejo de la entrada y salida estandar 83) El especificador 2a de la linea 14 asigna 2 al ancho minimo del campo, pero usted sigue viendo la salida completa de 12846 en la linea 14. Esto significa que cuando el ancho minimo del campo es més corto que el ancho de la salida, se toma este ditimo y el resul- tado se sigue imprimiendo completo. Alineacion de la salida ‘Como habrii notado en la seccién anterior, toda la salida se alinca # la derecha, En otras palabras, toda [a salida se coloca en él extremo derecho del campo de manera predeter- minada, en tanto que el ancho del campo sea mayor que el de la s Usted puede alinear la salida a la izquierda. Para hacerlo, necesita ponerle un signo de menos (-) como prefijo al especificador del ancho mfnimo del campo. Por ejemplo, *-124 -especifica que el ancho mfnimo del campo es 12, pero alinea la salida a partir del extremo izquierdo del campo. El listado 5.7 proporciona un ejemplo de oémo derecha, incor la salida a la izquierda o a la Ustapo 5.7 Salida alineada a izquierda o derecha (* Q5L07.c: Alineacién de la salida */ include main() 1 dnt numt, num2, num3, nun, nuns; unt una una und = nun = printf (88d %-8d\n*, numt, num print? (*88d %-8d\n", num2, nun2); printf(*sad %-@d\n*, nun3, mun); print#(*8d %-Bd\n", numd, nund) ; print ("88d %-8d\n", nuns, nuns) ; return @; Obtuve los siguientes resultados después de ejecutar el archivo #8L07 .exe: 14 Ty 12 12 123° 123 teat 1234 1294 12045 Hora 5 En el listada 5.7 hay cinco variables enteras, num, nun2, nuns, num y nuns, las cuales se declaran en Ia Iinea 6 y se les asignan valores en las Iineas 8 a 12. Estos valores representados por las cinco variables se imprimen después por medio de las funciones printt () de las Kineas 13 17, Observe que todas las lamadas a print#() tienen el mismo primer argumento: “Nad %-8d\n*. Aqui, el primer especificador de for- mato, ‘6d, alinea la salida al extremo derecho del campo, y el segundo especificador de formato, *-8d, alinea la salida al extremo izquierdo del campo. Despuds de ejecutar las instrucciones de las lineas 13 a 17, se lleva a cabo la alineacién y se ponen los resultados en la pantalla como sigue: 4 w 123123 1294 1284 12545 12345 Uso del especificador de precision Puede colocar un punto (.) y un entero justo después del especificador del ancho minimo del campo. La combinacién del punto y el entero conforma un especificador de precision. Puede usar el especificador de precisién para determinar el ntimero de posiciones decima- les para los nlimeros de punto flotante, o para especificar el ancho maximo (o longitud) del campo para enteros © cadenas. (Las cadenas de C se presentan en la hora 13, “Cadenas™.) Por ejemplo, con $18.3f, la longitud del ancho minimo del campo se especifica de 10 caracteres, y al némero de posiciones decimales se le asigaa el 3. (Recuerde, el nimero predeterminado de posiciones decimales es de 6.) Para los enteros, %3. 80 indica que el ‘ancho minimo del campo es de 3, y el maximo es de 8. Elli tado 5.8 presenta un ejemplo del uso de los especificadores de precisiGn. BSE) Ustavo 5.8 Uso de los especificadores de precision 1: /* @SLOB.c: Uso de los especificadores de precision */ 2 Hinelude : main() fd 6; int int_num; 7: double f1_num; 8: 8: ant_qum = 123; 1 flt_nun © 123.456789; 14; printf (‘Formato de entere predeterminado: — %4\n", int_nun); Manejo de la entrada y salida estandar 85) printf(*Con especificador de precisién: ‘82.8d\n", int_num); printf(*Formato de punto flotante pradeterminado: Sf \n", f1t_num); printf(*Con especificador de precision: S-1@.28\n", fLt_num) ; return 0: ‘Después de ejecutar en mi computadora el archivo @5L@8.exe, obtuve en la pantalla los iguientes resultados: Con especificador de precisisi Formato de punto flotante predeterminad: Con especificador de precisién: EI programa del listado 3.8 declara una variable entera, int_nus, en la linea 6, y en la linea 7 un ndimero de punto flotante, f1t_num. Las lineas 9 y 10 asignan 123 y 123.456789 a int_num y a 1t_num, respectivamente. En la Ifnea 11 se especifica el formato de entero predeterminado para la variable entera int_nun, mientras que la instruccién de la Linea 12 indica el formato de entero con wn ‘especificador de precisién que determina que el ancho miximo del campo es de acho ‘caracteres. Por lo tanto, puede ver que se incluyeron cinco ceras antes del entero 123 de la segunda Ifnea de los resultados, Para la variable de punto flotante, #1t_num, la linea 13 imprime un valor de punto flotante ‘en el formato predeterminado, y la linea 14 reduce: dos las posiciones decimales poniendo cel especificador de precisidn .2 dentro del especificador de formato 4-18.24. Observe ‘que también se especifica la alineacién a la izquierda por medio del signo de menos {-} en el especificador de formato de punte flotante. La instruccién de la linea 14 produce el niimero de punto flotante 123.48 de la cuarta Ifnea de los resultados, por media del especificador de precisién para das posiciones decimales. Por lo tanto, 123..456789 redondeado a dos posiciones decimales se convierte en 123.46, Resumen En esta leccidn aprendid los siguientes conceptos, especificadores y funciones importantes: + El lenguaje C trata a un archive como una serie de bytes. + stdin, stdout y stderr son tres flujos de archive que son pre-abiertos y siempre estin disponibles para que: usted los utilice. + Se pueden utilizar las funciones getc() y getchar( }de la biblioteca de C para leer un cardicter de la entrada estdndar. « Se pueden utilizar las funciones pute() y putchar() de la biblioteca de C para imprimir un caricter en la salida estdndar. Hora 5 + Se puede emplear 4x o 8x para convert niimeros decimales en hexadecimales. + El ancho mfnimo del campo se puede especificar y asegurar agregando un entero cen el especificador de formato. + Es posible alinear una salida ya sea al extremo izquierdo o al derecho del campo de salida. + Se puede utilizar un especificador de precisién para especificar el nimero de posi- ciones decimales de Jos niimeros de punto flotante, o el ancho maximo del campo para enteras 0 cadenas. En la siguiente lecciGn aprendert acerca de algunos operadores importantes de C. Preguntas y respuestas P ,.Qué son stdin, stdout y stderr? R_EnC, un archivo es tratado como una serie de bytes, a Ia cual se le [ama flujo de archivo. stdin, stdout y stderr son flujos de archivo pre-abiertos. stdin es la entrada esténdar de lectura; stdout es la salida estindar de escritura; stderr es el error estndar para escribir mensajes de error. {Qué valor decimal equivale al mimero hexadecimal 32? El hexadecimal, o hex para abreviar, es un sistema numérico de base 16. Por lo tanto, 32 (hex) es igual a 3*161+2* 16", 0 50 en decimal. {Som equivalentes getc (stdin) y getchar()? R_ Debido a que la funcién getchar() lee de manera predeterminada del flujo de archivo stdin, getc (stdin) y getchar() sf son equivalentes. P En [a funcidn printf("E1 entero %d es lo mismo que el hexadecinal %x", 12, 12), jcudl es la relacién entre los especificadores de formato y las expre- siones? mo ” R. Los dos especificadores de formato, %4 y x, especifican los formatos de valores numéricos contenidos en la seccién de expresiones. Asf, el primer valor numérico de 12 se imprimird en un formato entero, mientras que el segundo 12 (el de la seccién de expresiones) se mostrar en el formato hexadecimal, Hablando en forma general, el niimero de especificadores de formato de la seccién de formato debe coincidit con el miimero de expresiones de la correspondiente seccién de expresiones. Taller Para consolidar la comprensién de la leccién de esta hora, le recomiendo responder el cuestionario y terminar los ejercicios de este taller antes de pasar a la siguiente leccién. Manejo de la entrada y salida estandar a7) Las respuestas y sugerencias se presentan en el apéndice B, “Respuestas a los cuestiona- ios y ejercicios”. Cuestionario. R . Es posible alinear los resultados al extremo izquierdo del campo de salida en lugar de al derecho? . Cuil es la diferencia entre pute() y putehar()? 3. {Qué valor devuelve getehar()? Dentro de ¥19.3f, ,qué parte es el especificador del ancho minimo del campo, ¥ qué parte es el especificador de precisién? Ejercicios lL 2 3. Escriba un programa para poner juntos en la pantalla los caracteres 6, y y @. Despliegue los nimeros 123 y 123.456 alineados al extremo izquierdo de! campo, ‘Dados los tres enteros 15, 150 y 1560, escriba un programa que los imprima en la pantalla en formato hexadecimal. . Escriba un programa que use getchar() y putchar() para leer un cardcter intro- ducido por el usuario y escribalo en Ia pantalla. . Si compila el siguiente programa de C, ;qué mensajes de advertencia o error obtendré? main() { ant ch; ch = getcha putchar(ch) return 0; + ~ et = > = = = Parte Il Operadores e instrucciones de control de flujo Hora Manejo de datos Ciclos Uso de operadores condicionales oon Modificadores de datos y funciones matematicas 10 Control de flujo del programa Obraz chroniony prawem autorskim Material chroniony prawem autorskim =—_ ere = —_ =" HorRA 6 | Manejo de datos “La cuestion es", dijo Humpty Dumpty, “saber quién es ef que manda; eso es todo.” —L. Carroll Pucde imaginar a los operadores de C como verbos que le permiten mani- ular datos (los cuales son como sustantivos). De hecho, en la hora 3, “La estructura de un programa de C”, aprendié algunos operadores como + (suma), ~ (resta), * (multipticacién), / (divisién) y % (residuo). El lenguaje C tiene un conjunto completo de operadores. En esta hora apren- derd acerea de otros operadores, come son: * Los operadores de asignacién aritmeética * El operador de negacién * Los operadores de incremento y decremento * Los operadores relacionales * Los operadores de conversion 92 Hora 6 Los operadores de asignacién aritmética Antes de abordar los operadores de asignacién aritmética, veamos primero més de cerca al propio operador de asignacién. El operador de asignacién (=) En el lenguaje C, al operador = se le Hama operador de asignaciéin, mismo que vista y utilizade en varias horas. ed ha . La forma general de la instruccién para usar un operador de asignacién es: operando_de_ia_irquierda = operando_de_ia_derecha; Aqui, Ia instrucci6n hace que el valor del operande_de_la_derects se asigne (o se escriba) en la localidad de memoria del operando_de_1a_izquierda. De esta manera, después de la asignacién, el valor del operando_de_1a_izquierda ser4 igual al del operando_de_1a_derecha, Adicionalmente, toda Ia expresidn de asignacién se evalda al mismo valor que se asigna al operando_de_la_izquierda. Por ejemplo, la instruccin a = 5; escribe el valor det operando de Ia derecha (5) en la localidad de memoria de la variable entera a (la cual, en este caso, es el operando de la izquierda), De In misma manera, Ia instruccién b = a = §; asigna primero el valor § a la variable entera a, y luego a la variable entera b. Después de la ejecucidn de la instrucciGn, tanto a come b contienen el valor de 6, Es importante recordar que el operando de la izquierda del operador de asignacién debe ser una expresién en la cual pueda escribir datos en forma legal. Una expresién como 6 = a, aunque a primera vista podria parecer correcta, en realidad est al revés y no funcionaré, El operador de asignacién siempre funciona de derecha a izquierda; por lo tanto, el valor del lado izquierdo debe ser alguna variable que pueda recibir datos desde la expresi6n de la derecha. No confunda el operador de asignacién (=) con e1 operador relacional, == (llamado operader de iguaidad). El operador == se presenta més adelante en esta hora, Combinacién de operadores aritméticos con = Considere este ejemplo: ;Cémo asignarfa la suma de las variables enteras x y y ala variable entera 2? Manejo de datos 33) Utilizando el operador de asignacién (=) y el operador de suma (+), puede obtener la siguiente instruccién: pexty; Como puede observar, es muy sencillo. Ahora bien, considere el mismo ejemplo, pero en lugar de asignar el resultado a la tercera variable, z, escribiremos el resultado de la suma en la variable entera x: xexty; Recuerde, el operador = siempre funciona de derecha a izquierda, de modo que primero se evaluard la parte derecha, Aqui, en la parte derecha del operador de asignacidn (= realiza la suma de x y y; en la parte izquierda del operador se reemplaza el valor previ de x con el resultado de la. suma de la parte derecha. El lenguaje C le proporciona un nuevo operador, +=, para hacer la suma y Ia asignacién, juntas, Por lo tanto, puede reescribir la instruccién x = x * y; como: xen; La combinacién del operador de asignacién (=) con los operadores aritméticos, +, y%, le offece otro tipo de operadores, los operadores de asignacién aritmética: Operador Descripeién We” CO perador de asignacin de suma cad Operador de asignacién de resta a Operador de asignacién de multiplicacién I= Operadar de asignacidn de divisidin we Operador de asignacién de residuo Accontinuacién se muestran instrucciones equivalentes: x + ysequivaleax =x + ys x -> ypequivaleax = x - yz x ts ypequivaleax = x * yz x y= ypequivaleax = x / y; x Me y; cquivaleax = x % y; Observe que la instruccién zpeatney 4 Hora 6 no equivale a Ia instruccién aay debide a que pteaey multiplica z por toda la parte derecha de la instruccién; por lo tanto, el resultado serfa 2s zt yy El listado 6.1 presenta un ejemplo del uso de algunos operadores de asigmacién arit- mética. Mets 1: 2: 2a: ar 32: 3a: Listapo 6.1 Uso de los operadores de asignacian aritmética (* Q6LO1.c: Uso de los operadores de asignacién aritmética */ include main() { ant x, ¥, 2; xe ty [* imictalize x *y y=} /* inicializa y */ Z= 10; /* inicializa z */ printf(*Dadas x = Sd, y = Sd, y z= Sd,\n", x,y, ZN) xexty; printf(*x =x + y asigna ‘da xp\n", x); x41; [* restablece x */ Key printf(*x += y asigna Sd a x;\n", x); x= 4; /* restablece x */ zezrtxey; peintt("z = 2 * x + y asigna Sd a z;\n", 2); 2 10; /* restablece z */ zez* (key) peintf(*z = 2" (x + yb asigna 8d a zs\nt, 2); 103 xe printf (*z t= x + y asigna Sd a zl 2); J* restablece z */ return O; » Manejo de datos 95) Después de compilar y enlazar este programa se crea un archivo ejecutable. En mi midquina este archivo ejecutable se denomina 96101 .exe. Los resultados obtenidos después de ejecutar dicho archivo son: Dades x= 4, y= 3, y2= 10, wx +y asigna 4a x; ats y asigna 4a x; zertx+y asign 13 a2; z z 2 * (x+y) asigna 4 a 2; “sx + y asigna 40 az La linea 2 del listado 6.1 incluye el archive de encabezado stdio-h mediante la directiva include. Este archivo de encabezado se requiere para las funciones printf) que se emplean en las Iineas 4 a 33, Las lineas 8 a 10 inicializan tres variables enteras, x. y y 2, las cuales estin declaradas en la linea 6, Después, la linea 11 imprime los valores iniciales asignados ax, y yz. La instruccién de ta linea 13 utiliza un operador de suma y un operador de asignacién para sumar los valores contenidas en x y y, y luego asigna el resultado a x. La linea 14 despliega el resultado en la pantalla, Las Iineas 17 y 18 realizan la misma suma y despliegan de nuevo el resultado, después de restablecer el valor de x a 1 en Ia linea 16. En esta ocasiGn se utiliza el operador de asignaci6n aritmética +=. El valor de x se restablece en la linea 20. La linea 21 realiza una multiplicacién y una suma y guarda el resultado en la variable entera z;estoes,z = 2 * x + y;.La llamada a printf () de la linea 22 despliega como resultado el 13 en la pantalla. Una vez més, la instruccién x = 1; de la linea 20 restablece el valor de la variable entera x. Las lineas 24 a 30 muestran los resultados de dos célculos, De hecho, ambos resultados son iguales (es decir, 48) debido a que los dos célculos de las lineas 25 y 29 son equi- valentes. La nica diferencia entre las dos instrucciones de dichas lineas es que en la linea 29 se utiliza el operador de asignaci6n aritmética *= Obtencion de negaciones de valores numéricos Si desea cambiar el signo de un nimero, puede colocar el operador menos (-} justo antes ‘del mimero, Por ejemplo, puede obtener el valor negative del entero 7 cambiando su igno de esta manera; -7. Aqui, - es el operador menos, Al simbolo - utilizado de esta forma se le llama operador de negacién o unario menos. Esto se debe a que el operador toma s6lo un operando: la expresién inmediata a su derecha. El tipo de datos del operande puede ser cualquier niimero entero o de punto flotante. 96 Hora 6 ‘También puede aplicar el operador de negacién a una variable entera o a una de punto flo- tante. Por ejemplo, dada x = 1.234, -x es igual a -1.284.O deda x = -1.294, -x equivale 1.284, ya que la negacién de un valor negativo da como resultado un niimero positivo. at No confunda él operador de negacién, 0 unario menos, con el operador de No conta pn eosin, oma mena oe pme. C% | sss es en realidad la misma que ésta: zen ty 0 que ésta: Aqui, en ambas instrucciones, el primer simbolo = se usa come el operador de resta, mientras que el segundo es un operadar de negacién. Incremento o decremento en una unidad Los operadores de incremento y decremento son muy pricticos cuando usted desea sumar o restar | @ una variable. El simbolo del operador de incremento es ++, El operador de decremento es =» Por ejemplo, puede reescribir la instruccién x = x + 1; como +4x;, 0 reemplazar x= x + 1) COM =x; En realidad existen dos versiones de los operadores de incremento y decremento. En la instraccién ++x;, en donde ++ aparece antes de su operando, el operador de incremento se denomina operador de preincremenio, Esto se refiere al orden en que suceden las cosas; el operador primero suma I ax, y después produce el nuevo valor de x. Asimismo, en la instruccién --x;, el eperador de predecremento primero resta 1 a x y luego pro- duce el nuevo valor de x. Si tiene una expresién como x++, en In que ++ aparece después de su operando, entonces std empleando un operador de posincrementa. Del mismo modo, en x- -, al eperador de decremento se le lama operador de posctecremento. Por ejemplo, en la instrucciGn y = x#+;, primero se Je asigna a y el valor original de x, y después x se incrementa en | El operador de posdecremento tiene una historia parecida. En la instrucci6n y = x--} primero se asigna el valor de x a y, y despugs se decrementa x. El programa del listado 6.2 muestra las diferencias entre las dos versiones de los operadores de incremento y decremento. Manejo de datos 7) Listapo 6.2 Uso de los operadores de pre y posincremento ros J* 06L82.c: operadores de pre © posincrenento/decrenento*/ include main() t int w, x, ¥, 2, resultado; wexryez printf("Dadas w } /* Anietaliza x y y */ Md, kM, ye MM, yr Sdn, wo ry ZI5 resultado = ++; printf(*EL resultado de la evaluacién de tw es 4d y ahora wes Mdin", resultago, w); 13: resultado = x++; 14: printf ("El resultads de le evaluacién de x++ #5 ‘4 y ahora x es ‘d\n", resultado, x); 15: resultado’= --y; 16: printf ("El resultade de 1a evaluacién de --y es % y ahora y es ‘din*, resultado, y); resultado = z--; printf("El resultado de la evaluacién de z. result: Zh return o; es Sd y ahora z es Mdin*, Dadas w= 1, x= 1, ¥= 1,274, El resultado de la ‘evaluacién de t+w es 2 y ahora w as 2 El resultado de la evaluacién de xt+ es | y ahora x #5 2 El resultado de 1a evaluacién de --y es @ y ahora y es 0 El resultado de 1a evaluacién de z-- es 1 y ahora z #8 0 WY Dentro de Ia funcién main¢), la linea 8 del listado 6.2 asigna 1 a cada una de las variables enteras, w, x, y, y z. La Hamada a printt() de la linea 9 despliega los valores contenidos en las cuatro variables enteras. en Despugs se ejecuta la instruccién de la linea 11 y el resultade del preincremento de w se asigna a la variable entera resultado, En la linea 12 se imprime en la pantalla el valor de resultado, el cual es 2, junto con el valor de w después de la instruccién de preincre- mento. Observe que w sigue siendo 2 ya que el incremento tuvo lugar antes de asignar el nuevo valor de w a resultado. Las lineas 13 y 14 obtienen el posincremento de x e imprimen el resultado. Como usted sabe, el resultado se obtiene antes de incrementar el valor de x. Por Io tanto, usted ve el valor de 1 (el valor anterior de x) en el resultado de x++, mientras que el nuevo valor de x e82, ya que se incrementé después de la asignaciGn a resultado de la linea 13. El operador de predecremento de la linea 15 provoca que se reduzca en | el valor de y antes Hora 6 de asignar el nuevo valor a la variable entera resultado. Por lo tanto, usted ve @ en la pantalla como el resultada de --y, el cual refleja el nuevo valor de y, que es también 8. ‘Sin embargo, el operador de posdecremento de la Iinea 17 no tiene efecto sobre la asigna- cién, ya que el valor original de z se da a la variable entera resultado antes de que z disminuya en 1. El posdecremento actiia como si la linea 17 fuera simplemente resultado = 2, disminuyendo z en | después de cjecutar la instruccién. La linea 18 imprime entonces el resultado 1, el cual es por supuesto el valor original de 2, junto con @, que es el valor de z después del posdecremento, Mayor que o menor que Hay seis tipos de relaciones entre dos expresiones: igual a, diferente de, mayor que, menor que, mayor 0 igual a, y menor o igual a, De acuerdo con esto, el lenguaje C proporciona estos seis operadores relacionales: Operador Descripcitin egal I= Diferente de > Mayor que: < Menor que: 3 Mayor o igual a - Menor o igual a ‘Todos los operadores relacionales tienen una precedencia menor que los operadores arit- méticos. Por lo tanto, todas las operaciones aritméticas a ambos lados de un operador relacional se llevan a cabo antes de hacer cualquier comparacién. Debe colocar parénte- sis para encerrar las operaciones de operadores que se deban realizar primero. Entre los seis operadores relacionales, >, <, >= y <= tienen una mayor precedencia que los operadores == y 1= Por ejemplo, la expresién xryszes se interpreta como ry) <3 Otro punto importante es que todas Las expresiones relacionales producen un resultado de 0.0 1. Enotras palabras, una expresidn relacional se evaltia como 1 si se cumple la relacién especificada. En caso contrario, produce 0. Por ejemplo, dadas x = 3yy = 5, la expresién relacional x < y da un resultado de 1 El listado 6.3 muestra més ejemplos del uso de operadores relacionales. Manejo de datos 99 diferentes, los operandos que estan en medio se asocian con las operadcres ‘en un orden determinado. La precedencia de los operadores se refiere al orden en que se agrupan los operadores y los operands. Primera se agrupan ‘con sus operandas los operadores que tienen la mayor precedencia dentro de la expresion, Por ejemplo, en la expresion riety: 3 g ‘Cuando en una expresién aparecen juntos varios operadores relacionales 7 ‘el operador * tiene mayor precedencia que los operadores + y -. Por lo tanto, x" y se evaluard primero, y su resultado se convertira en el operando de la derecha del operador +. Ese resultade se da entonces al operader - como su ‘operando de la izquierda. ‘Si desea anular la precedencia predeterminada de los operadores, puede uti- lizar paréntesis para agrupar los operandos dentro de una expresién. Por ‘ejemplo, si lo que en realidad queria era multiplicar z + x pory - 3, entonces podria reescribir la expresién anterior como (z+ x) * (y - 3) Ademis, siempre puede usar los paréntesis cuando no esté seguro de los ‘efectos de la precedencia de los operadores, o simplemente cuando desee ‘que su cédigo sea més facil de leer. Listapo 6.3 Resultados producidos por expresiones relacionales J+ 6LO3.c: Uso de operadores ri fanclude acionales */ nain() { int x, ¥i double 2; KT y = 25 2 = 24.46; printf (*Oadas x= Sd, y= Md, yz S.2F Int, XY, Zi printf (tx >= y produce: Sa\n*, x prantt(*x <2 dint, x < 2); printf(* Adin", y > 2); printf("x [= y - 18 produce: Adin", x I= y - 18); printt(* + y Is 2 produce: win", x + y 1 Z| return 8; 100 Hora 6 Después de ejecutar el archivo @603.exe, se desplegaron los siguientes resultados en la pantalla de mi computador Dadas x = 7, y = 25, yz = 24.46, dual x >= y produce: 0 Hay dos variables enteras, x y y, ¥ una variable de punto flotante, z, declaradas en las lineas 6 y 7, respectivamente. En las lineas 9 a 11 se inicializan las tres variables. La linea 12 imprime los valores asig- nados a las variables, Debido a que el valor de x es 7 y el valor de y es 25, y es mayor que x. Par Io tanto, la Linea 13 imprime 8, que es el resultado que produce la expresidn relacional = y de la linea 14 produce @, ‘Las lineas 15 y 16 imprimen el resultado de 1, mismo que producen las dos expresiones x main() ie printf("Dadas x = 84, y = NO\n", xX, ¥95 printf("x / y produce: ‘a\n*, x /'y)3 prantf("(floatix / y praduce: ‘fin", (float)x / y); return 0; ‘Obtuve los siguientes resultadas al ejecutar el programa 061 exe en mi computadora: Dadas x + 7, y= 5 x1 y produce: 1 (float) / y produce: En el listado 6.4 hay dos variables enteras, x y y, declaradas en la linea 6, e ini- cializadas en las lineas 8 y 9, respectivamente. La linea 10 despliega los valores contenidos en las variables enteras x y y. [102 Hora 6 La instruccién de la Iinea 11 imprime la divisién entera de x jy. El resultado de dicha divisién es 1, debide a que se trunca la parte de la fraccién. Sin embargo, el operador de conversin (float) de la linea 12 convierte el valor de x a un valor de punto flotante. Por lo tanto, la expresién (float)x /y se convierte en una divisién de punto flotante y devuelve un mimero de punto flotante. Es por ello que usted ve que se muestra en la pantalla el mimero de punto flotante: 1.498000, después de ejecu- tar la instruceién de la nea 12, Resumen En esta leccién aprendié acerca de los siguientes operadores importantes: + El operador de asignacién =, ¢] cual tiene dos operandos (uno a cada lado). El valor del operando de la derecha se asigna al operando de Ia izquierda. E] operando de la izquierda debe ser un tipo de variable que pueda aceptar el nuevo valor, + Los operadores de asignacién aritmética +=, =, "=, /= y %= son combinaciones de los operadores aritméticas con el operador de asignacién. + El operador de negacién o unario menos (-}, ¢l cual obliene la negacién de un valor numérico. * Las dos versiones del operador de incremento, ++. Usted sabe que en ++x, el ope- rador ++ se denomina operador de preincremento, y en x++, ++ es el operador de posincremento, * Las dos versiones del operador de decremento, --. Usted aprendié que, por ejemplo, en --x, €l operador -- es el operador de predecremento, y en x--, --€8 el operador de posdecremento. * Los scis operadores igual a), t= (diferente de), > (mayor que), < (menor que), >= (mayor o igual a) y <= (menor o igual a), * Cémo cambiar el tipo de datos de una expresién anteponiendo un operador de con- versidn explicita a los datos. En la siguiente leccién aprender acerca de los ciclos en el lenguaje C. Preguntas y respuestas P: ;Cudl es la diferencia entre el operador de preincremento y el operador de posincremento? R_El operador de preincremento primero incrementa en | el valor del operando, y luego produce el valor modificado. Por otra parte, el operader de posincremento primera produce el valor original de su operando y después incrementa el Manejo de datos operando, Por ejemplo, dada la expresién x = 1, la expresién ++x produce 2, mientras que la expresiGn x+* se evaliia como 1 antes de modificar a x. P Es lo mismo el operador de negacién, o unario menos, (-) que el operador de resta (+)? R_ No, aunque ambos operadores comparten ¢! mismo simbolo, no son lo mismo, El significado del simbolo lo determina el contexto en el que aparece, El operador de negacién se usa para cambiar el signo de un valor numérico, En otras palabras, el operador de negaciGn produce la negacién del valor. El operador de resta es un operador aritmético que realiza una resta entre dos operandos, {Qué operador tiene una mayor precedencia, un relacional o un aritmético? R. Un operador aritmético tiene mayor precedencia que un operador relacional. Por cjemplo, en la expresién x * y * z > x + y, la precedencia de operadores de mayor a menor vade * a * y por dltimo a >, La expresién completa se interpreta entonces como ((x * y) + z) > (x + y). Qué valor produce una expresién relacional? R. Una expresidin relacional se evaliia como @ o 1. Si en una expresidn Ia relacién que indica un operador relacional es verdadera, la expresién se evala como 1; en caso contrario se evaliia como 8. ~ oy Taller Para consolidar la comprensién de la leccién de esta hora, le recomiendo responder el cuestionario y terminar los ejercicios de este taller antes de pasar a la siguiente leccién. Las respuestas y sugerencias se presentan en el apéndice B, “Respuestas a los cuestionarios y ejercicios” Cuestionario 1, ¢Cuél es la diferencia entre el operador = y el operador =*? 2, En laexpresién x + - y - - 2, ,cudles operadores son de resta y cudles son de negaci6n? 3. Dadas x = 15 yy = 4, qué valores producen, respectivamente, las expresiones xf yy (floatyx J y? 4. 2Eslaexpresion y *» x + S cquivalemte ala expresiny = y * x + 5? Ejercicios 1. Dadas x = 1 yy © 3, eseriba un programa que imprima los resultados de estas expresiones: x #5 y,x 48 -yx = yk -= “yx ey Ae oy 103) 104 Hora 6 2. Dadasx = ay y = 6, ;cudl es el valor de 2 después de ejecutar la instruccidn zexty ss 18)? 3. Escriba un programa que inicialice la variable entera x con 1 y muestre resultados con las siguientes instrucciones: printf ("x++ produce: din", x++); printf ("Ahora x contiene: ‘ai\n*, x); 4, Reescriba el programa del ejercicio 3. Esta vez incluya las siguientes instrucciones: printf("x = x++ produce: Sd\n", x = Ktt); printf ("Ahora x contiene: din", x); {Qué obtiene después de ejecutar el programa’ {Puede explicar el porqué de dicho resultado? 5, Se supone que el siguiente programa debe comparar las variables x y yen cuanto a igualdad. ;Qué esta mal en el programa? (Sugerencia: ejecute el programa para ver qué imprime.) Winclude maint) d int x, yi x= y=; printf("El resultado de la comparacién es: ‘din‘, x = y)i return @; HORA 7 Ciclos Cielo y tiema: Canticos sutra no escuchados Repe —Proverbio Zen En las lecciones anteriores aprendié los aspectos bisicos de un programa en C, diversas funciones de C importantes, la E/S estindar y algunos opera- dores sities, En esta leccién aprender una caracteristica muy importante del lenguaje C; los cicles, Los ciclos, también Hamados iteraciones, se usan en la programacién para realizar una y otra vez. el mismo conjunto de instrucciones hasta satisfacer una determinada condicién. En C hay tres instrucciones disefiadas para los ciclos: * La instruccién while * La instruccitin do-wnile * La instruccién for En las secciones que siguen veremos estas instrucciones. 106, Hora 7 EI ciclo while La finalidad de la palabra reservada while es ejecutar una instruccién una y otra vez mientras que una condicién dada sea cierta. Cuando la condicién del ciclo while ya no es légicamente verdadera, el ciclo termina y la ejecucién del programa continta en la siguiente instraccién después del ciclo. La fonma general de la instruccién while es while (expresién) instrucedon; Aqui, expresin e¢ In condiciGn de la instruccién while. Esta expresion se evala primero. Si la expresién s¢ evaliia como un valor diferente de cero, entonces se ejecuta la insteuecién. Después de esto se evalia una vez mas la expresidn, Entonces, si la expresién se sigue evaluando como un valor diferente de cero, a instruecidn se ejecuta una vez mas, Este proceso se repite una y otra vez hasta que la expresidn se evaltie como cero, 0 falsa Kégico, La idea es que el oGdigo del ciclo (la instruccién;) haga que la expresién sea légica- mente falsa la siguiente ovasiGn que se evalie, terminando asi el ciclo, Por supuesto, a menudo querré utilizar la palabra reservada while, en lugar de otras instrucciones, para controlar un ciclo. Cuando éste sea el caso, utilice un bloque de instrucciones encerrado con Haves { y }. Cada vez que se evalde Ia expresién wni1e, todo el bloque se ejecutard si la expresién se evalda como verdadera. ‘Veamos ahora un ejemplo del uso de la instruccién while, El programa del listado 7.1 utiliza un ciclo while para leer continuamente y desplegar después el cardeter introducido, siempre y cuando éste sea diferente de "x'. Ustapo 7.1 Uso de un ciclo wile J* O7LO1.c: Uso de un ciclo while */ include nain() int ¢; eet printf("Introduzca un eardcter:\n(introduzca x para terminar)\n"); while (6 l= ‘x") { © = geto(stdin); putenar(c); Deintt(*\ill cielo while ha terminago. asta prontt a"); retura Ciclos. 107) Aqui tenemos una copia de los resultados desplegados en la pantalla de mi computadora, (observe que log caracteres qué introduje estén en negritas). Introduzea un carécter: : : ; H ; ; 1 ciclo while ha terminado. iHasta pront ‘Como puede ver en los resultados, el programa imprime cada cardcter que se teclea, y termina después de x La linea 8 asigna a Ia variable ¢ el valor ' ' (un carécter de espacio). A esto se le conoce como inicializar la variable, y s6lo necesitamos inicializarla a un valor distinto de *x" La linea 10 es la instrucci6n white. La condicin que esté entre los paréntesis, ¢ significa que el ciclo continuard ejecuténdose una y otra vez hasta que c sea igual a ‘x! Debido a que acabamos de inicializar ac con el cardcter ' *, larelaciin ¢ 1= x es, desde luego, verdadera. Después de! paréntesis de cierre hay una tlave de apertura, por lo que el ciclo se ejecutand hasta encontrar una Ilave de cierre. Las lineas 11 y 12 leen un cardcter y lo imprimen en la pantalla, y al haceslo asignan el valor del caracter a la variable c. La linea 13 es la lave de cierre, lo que indica que la iteraciOn se realiz6 y Ia ejecuci6n regresa a la Iinea 10, Ia instruccién white. El ciclo continuard si el cardcter que se introdujo fue diferente de "x"; en caso contrario, ¢ |= x sera I6gicamente falsa, y la ejecuciGn pasard a la siguiente instruccién después de la lave de cierre de la linea 13. En este caso, pasa a la llamada a printt() dela linea 14. El ciclo do-while En Ia instruccién wie que acabamos de ver, la expresién condicional se coloca al principio del ciclo. Sin embargo, en esta seccién verd otra instruccién que se emplea para los eiclos, do-wnite, 1a cual pone la expresién al final del ciclo, De esta forma se garan- tiza que las instrucciones del ciclo se ejecuten por lo menos una vez. antes de verificar la expresiGn. Observe que las instrucciones de un ciclo while no se ejecutan si la expresién condicional se evalia como cero la primera vez. 108 Hora 7 La forma general de la instruccién do-while es do { Anstrucesdnt instruccién2; } while (expresisn); ‘Aqui, las instrucciones que estén dentro del bloque se ejecutan una vez, y Iuega se evalia Ia expresidn a fin de determinar si el ciclo continda. El ciclo do-wniie contiméa si la expresiGn se evaliia como un valor diferente de cero; en casa contrario, la ejecucidin sigue en la siguiente instruccién después del ciclo. Observe que la instruccién do-while termina con un punto y coma, lo cual es una difer~ encia importante con respecto a las instrucciones if y while. El programa del listado 7.2 despliega los caracteres desde la A a la @, as{ como sus respectivos valores mimericos, mediante un ciclo do-while que repite la impresidn y el incremento_ iG ida Listapo 7.2 Uso de un ciclo while {* @7L2.c: Uso de un ciclo do-while */ #inelude main() 1 ant 4; print (*Hextnayisculas) Hex(minéscules) Decinal\q"); for (i=; i main() { int i, i; for (0, j=8; i<8; i++, j--) printf(*ed + Ad = Ad\nt, dy jy def); return @; , Obtuve los siguientes resultados después de ejecutar el archivo O7L@4.exe: ey ae 5-6 La linea 6 del listado 7.4 declara dos variables enteras, i y j, las cuales se uti- zan en un ciclo for: En la primera expresién de la instruccién for, en la linea 8, i se inicializa con @ y a j se le asigna el valor de 8. La segunda expresin contiene una condicién, 1 < 8, la cual le indica a la. computadora que continge las iteraciones, siempre y cuando el valor de i sea menor que 6. En cada iteracién, después de que se cjecuta la instruccién de la linea 9 controlada por el for, se evalda la tercera expresién, lo que provoca que se aumente (incremente) i en 1, mientras que j se reduce (decrementa) en 1. Debido a que sélo hay una instruccién den- tro del ciclo for, no se utilizan aves ({ y }) para formar un bloque de instrucciones. Durante el ciclo, Ia instruccién de la linea 9 despliega en la pantalla la suma de i y j, lo cual produce ocho resultados, uno en cada iteraci6n, mediante la suma de los valores de las dos variables, i yj. Agregar varias expresiones dentro de la instruccién for es una forma muy conveniente de manipular mas de una variable en un ciclo. Para aprender mis sobre cmo utilizar varias expresiones en un ciclo for, observe el ejemplo del listado 7.5. Ciclos 15) Listapo 7.5 Otro ejemplo de cémo utilizar varias expresiones ena instruccion for J* B7LO5.c: Otro ejemplo de varias expresiones */ #include main() 4 ant i, 45 for (10, je1; 128; 16+, 444) printf("sd - Sd = Adint, j, 4, 9 - 405 return 0; it Los siguientes resultados se mostraron en la pantalla de mi maquina después de ejecutar el archivo o7L@5.ex Noueenas En la linea 6 del programa del listado 7.5 se declaran dos variables enteras, sys. ‘Observe que en la primera expresion de la instrucciGn for de la linea 8 hay dos expresiones de asignacién, i*0 y j=1. Estas dos expresiones de asignacién inicializan las variables enteras 4 y 4, respectivamente. En el segundo campo hay una expresi6n relacional, i<8, Ia cual es la condici6n que se debe satisfacer antes de poder llevar a cabo el ciclo. Debido a que 1 comienza en 0 y se inerementa en 1 después de cada ciclo, hay un total de & iteraciones que realizard la instruccidn 1 ‘La tercera expresién contiene dos expresiones, i++ y j++, que incrementan en 1 las dos variables enteras después de que se ejecuta la instruccién de la linea 9. La funcién printt() de la linea 9 despliega la resta de las dos variables enteras, j € 4, dentro del ciclo for. Debido a que solamente hay una instruccién en el bloque de instrucciones, las llaves ({ y }) no son. necesarias. 116 Hora 7 Uso de ciclos anidados Con frecuencia necesita crear un ciclo aunque ya esté dentro de uno, Puede colocar un ciclo (un ciclo interno) dentro de otro (un ciclo externo) para formar ciclos anidados. Cuando el programa llegue al ciclo interno, éste se ejecutard como cualquier otra instruccién dentro del ciclo externo. E] listado 7.6 es un ejemplo de cémo funcionan los ciclos anidados. Asta Listapo 7.6 Uso de ciclos anidados [* @7L06.c: Demostracién de ciclos anidados */ include ix=3; i+¢) { 1* ciclo externo */ printf ("Inicio de 1a iteracién Sd del ciclo externo.\n", i}; for (j#1; fea; j++) J* cielo interno */ printf(" Iteracién %d del ciclo interno. \n", 3); printf (*Fin de la iteracién ‘d del ciclo externo.\n", 4}; + return 8; Los siguientes resultados se obtuvieron mediante la ejecucién del archivo @7L06. ex: Inieio de 1a iteracién 1 del ciclo externo, iteracién 1 del ciclo interna, iteracién 2 del ciclo interno, iteracién 3 del ciclo interno Ateracién 4 del ciclo interno. Fin de 1a iteracién 1 del ciclo externo. Inieio de 1a iteracién 2 del ciclo externo. iteracién 1 del ciclo interno, iteracién 2 del ciclo interna Ateraci6n 3 del ciclo interno iteracién 4 del ciclo interna Fin de la iteracién 2 del ciclo externa. Inicio de 1a iteracién 3 del ciclo externo iteracién 1 del ciclo interno Ateracién 2 del ciclo interno. Ateracién 2 del ciclo interna. iteracién 4 del ciclo interna, Fin de 1a iteracién 3 del ciclo externo Ciclos En el listado 7.6 se anidan dos cicles for. El ciclo externo comienza en la linea 8 termina en Ja linea 13, mientras gue el ciclo interno inicia en la linea 10 y ter- mina en la 11. Aw El ciclo interno slo comprende una instruccién que imprime el niimero de jteracidin de acuerdo con el valor numérico de la variable entera |. Como puede ver en la linea 10, j se inicializa con +, y se incrementa en + después de cada ciclo (es decis, de cada iteracién). La ejecucién del ciclo interno se detiene cuando el valor de j es mayor que 4, interior, el cielo externo tiene otras dos instrucciones en las lineas 9 y 12, respectivamente, La funckin print () de la linea 9 despliegs un mensaje que mues- tra el inicio de una iteracién del ciclo externo, En Ia Ifnea 12 se imprime un mensaje para mostrar el final de la iteracién del ciclo extemno. Puede ver en los resultados que el ciclo imtemno termina antes de que ¢l ciclo externo co- mience otra iteracién. Cuando el ciclo extemno inicia otra iteracién, se encuentra con el ciclo interno y Jo ejecuta de nuevo, Los resultados del programa del listado 7.6 muestran cclaramente el orden de ejecucién de los ciclos interno y externo. No confunda los dos operadores relacionales (< y <=) y no los utilice en & forme equivocada en las expresiones de los clos. Por ejemplo, lo siguiente for (, ist 1 blogue ised je instrucciones */ ? significa que si j es menor que 10, el ciclo continda. De esta manera, el ndmere total de iteraciones es 9, Sin embargo, en el siguiente ejemplo, for (ist; j<=10; Jerid J* blaque de instrucciones */ } | ndmero total de iteraciones es 10 debido a que en este caso se evaliia la expresion relacional j<=10. Gbserve que la expresion se evalua come 1 (ver- dadere Iégico) siempre y cuando j sea menor o igual a 10. Por lo tanto, puede ver que la diferencia entre los operadores < y <= hace que el ciclo del primer ejemplo tenga una iteracién menos que el del segundo ejemplo. 117) 118 Hora 7 Resumen En esta leccidn aprendié los siguientes conceptos ¢ instrucciones importantes: * Se pueden utilizar ciclos para realizar una y otra vez la misma instruccién hasta ‘que se satisfagan las condiciones especificadas, * Los ciclos hacen que su programa sea mis conciso. + En C hay tres instrucciones que se utilizan para los ciclos: while, do-while y for. + La instruccién while contiene una expresién, la cual es la expresién condicional que controla el ciclo. * La instruccién while no termina con un punto y coma. * La instruccién da-while coloca su expresién condicional al final del ciclo. + La instruccién do-while termina con un punto y coma. + Hay tres expresiones en Ia instruccién for. La segunda es la expresién condicional. + Li instrucci6n for no termina oa un punto y coma. + En la instruccién for se pueden usar varias expresiones, combinadas mediante comas, * En un ciclo anidado, el ciclo interno termina antes de que el ciclo externo continge su iteracién. En Ia siguiente leccién aprender acerca de més operadores utilizados en el lenguaje C. Preguntas y respuestas P ;Cudl es la diferencia entre las instrucciones while y do-while? R La principal diferencia es que en la instruccidim while se evaliia la expresin condi- cional al inicio del ciclo, mientras que en la instruccién do-while se evalia al final del ciclo. Por lo tanto, se garantiza que las instrucciones que controla la instruccién do-while sc cjecuten por lo menos una vez, mientras que en una instruccién while es posible que no se ejecuten munca. P {Cémo funciona un ciclo for? R En la instruccién for hay tres expresiones. El primer campo contiene un ini- cializador que se evaliia primero y s6lo una vez antes de la iteracién. La segunda cexpresiGn ¢x la expresién condicional, la cual se debe evaluar como diferente de cero (verdadero Iégico) antes de que se ejecuten las instrucciones que controla la instruccién for. Si la expresién condicional se evalia como un valor distinto de cero (verdadera), lo que significa que: se satisface la condicidn, se Heva a cabo una Ciclos 119) iteracién del ciclo for, Después de cada iteracién se evalia la tercera expresién, y luego se evalia de nuevo la segunda. Este proceso con Ia segunda y tercera expre- siones se repite hasta que la expresiéin condicional se evalie como cero (falso Wsgico). {Puede terminar con un punto y coma Ia instruccién while? R Por definicién, 1a instruccién white no termina con un punto y coma. Sin embargo, en Ces vélido poner un punto y coma justo después de Ia instruccién while como éste: while(expresién) ;, lo que significa que hay una instruceién nula controlada por la instruccidn white. Recuerde que el resultado puede ser muy diferente al que espera si coloca aceidentalmente un punto y coma al final de la instruccién while. P Sise anidan juntas dos ciclos, cual debe terminar primero, el interne @ el externo? R_El ciclo interna debe terminar primero. Luego continuard el ciclo externo hasta ¢l final, y después comenzard otra iteracién si atin se cumple la. condicién especificada, Taller Para consolidar la comprensidn de la leccién de esta hora, le recomienda responder el cuestionario y terminar los ejercicios de este taller antes de pasar a la siguiente leccién, Cuestionario 1, {Puede imprimir algo el siguiente ciclo while? int k = 100; white (ke190)4 printf(*se*, KY; key 1 2, {Puede imprimir algo el siguiente ciclo do-wnile? printt("ee*, ki ket YP while ( 4: void Inpen(char ch); 5: int Sumaatos(int *lista, int max); 6: main() md 8: char cadenal] 8 char “aptr_cadena; int lista[S] int *aptr_int; J* asigna la direceién al apuntador */ aptr_cadena = cadena; Inpth (aptr_cadena) ; ‘Impth (cadena) ; J* asigna la direceién al apuntador */ aptr_int = liste: printf ("La Suma Gevuelta por SumaDatos() 5: Sain", SumaDatos(apte_int, 5}); printf ("La suma devuelta por SumaDatos() @ SumaDatos (lista, 5}); return ® swine, } 7* definicién de funcidn */ void Impcn(char *ch) { printf("esin", ch); } /* definicién de funcidn */ int SunaDatas(int ‘lista, int max) { int ij int suma = 0 Uso de apuntadores Después de ejecutar en mi maquina el archivo 16L04. exe, e introducir tres enteros, 20 y 30, obtuve los siguientes resultados: Escriba tres enteros separados por espacios: 10 20 30 La suma de los tres enteras es: €0 WI La finalidad del programa del listado 16.4 es obtener tres enteros introducides por ¢l usuario, y luego pasarlos como un arreglo a una funcién denominada. sunaTres() para realizar una operacién de suma, La linea 4 declara la funcién SunaTres (). Observe que en la expresién del argumento se usa el arreglo sin dimensionar 14sta{ |, lo cual indica que el argumento contiene la direceién de inicio del arreglo Lista. En Ia Iiea 8 se declaran el arregio Lista y la variable entera suna. La llamada a printt() de la linea 10 despliega un mensaje que solicita al usuario que introduzca tres enteros. Luego, Ia linea 11 utiliza scant) para reeuperar los enteros que escribié el usuario y almacenarlos dentro de las tres ubicaciones de memoria de los elementos del arreglo entero al que hacen referencia Alista[#), &lista[1] y Alista[2], res- pectivamente, La instruccién de la linea 12 Hama a la funcién sumatres() con el nombre del arreglo como argumento. En realidad, la expresién Sunatres (Lista) esti pasando la direccién de inicio del arreglo Lista (&1ista{@)) a la funcién SumaTres() La definicidn de ta funciGn sumatres () esta en las ineas 18 a 26; 1a funcién suma los valores de los tres elementos del arreglo y devuelve el resultado de Ia suma, Dicho re sultado se asigna a la variable entera suna en la linea 12 y se imprime en la linea 13, ‘También puede especificar el tamafo de un arraglo que se pasa a una fun= clén. Por ejemplo: funcion(char cagena[ 16); ‘equivale a la instruccién funcion(char cagena[ |); Recuerde que el compilader puede determinar el tamafe del arreglo sin especificacion de tamafo cadenal]. En arregios multidimensionales, siempre se debe usar en la declaracion ef formato de un arreglo sin especificacién de tamafio. (Vea, mas adelante en esta hora, la seccién "Como pasar arreglos multidimensionates como argu: mentos".) 267 266 Hora 16 En la linea 19 se asigna la direcci6n de inicio del arreglo Lista de tipo int al apuntador aptr_int. Antes de hacer algo con el clemento Lista(2] de este arreglo, imprimo su valor, que en este momento es 3 (vea el resultado que produce la linea 20). En la linea 21 se le da ‘otro valor al elemento Lista[2], -3, a través del operador de indirecci6n *(aptr_int + 2) ‘La llamada a print®() de la linea 22 imprime el valor actualizado de 1ista(2]. Apuntadores y funciones Antes de comenzar a hablar acerea de emo pasar apuntadores a funciones, veamos primero edimo pasar arreglos a funciones, Paso de arreglos a funciones En la prictica, por lo regular es dificil pasar més de cinco © seis argumentos a una fun- cién, Una forma de ahorrar el nfimero de argumentos que se pasan a una funcién es uti- lizar arreglos, Puede poner todas las variables del mismo tipo en un arreglo y Inego transferir el arreglo como un solo angumento. El programa del listado 16.4 muestra c6mo pasar un arreglo de enteros a una funcién, Listapo 16.4 Cémo pasar arreglos a funciones I* 16L04.c: Como pasar arreglos a funciones */ Winclude int SunaTres (int Lista[]); main() { int suma, Lista[3); printf(*Escriba tres enteras separados por espacios:1n*); scanf(*sakded", Alista(], Alista(t}, Slista[2}); Suma = SunaTres (Lista); Printf("La suma de los tres enteros es: Sd\n*, suna}; return 9) } int SumaTres(int lista[]) { for (1-0; i<3; i++) resultado += Lista(i}; retura resultado; Uso de apuntadores 265) char cadenat] = "IES una cadenal*; 135 4) 5h; int “aptr_int; i+ acceso al arreglo de tipo char */ aptr = cadena; PRiNET(*ANtes cel cambio, ca printf(*antes del canbio, cadana[4} contiene: ‘ch *(aptr_cadena + 4) = ‘U's printf(*Después del cambio, cadena[4] contiene: ‘cin", cad Printf("Después del cambio, cadena contiene: ¥3\n", cadena: i* acceso al arregie de tipo int */ aptr_int = Lista; printt(‘antes cal canbio, lista[2] contiene: %a\n*, Lista(2]); *(aptr_int + 2) = -3; printf( "Después del cambic, Listal2] contion contiene: ‘s\n, cadena); » cadena[4)); an) d\n", Listal2}); return 0; Después de crear y ejecutar en mi computadora el archivo 16L03. exe, se desplegaron los siguientes resultados: Antes del cambio, cadena contiene: ifs una cadenal WLAN Antes del cambio, cadena[4] contiene: u Después del cambio, cadena[4] contiene: U Después del cambio, cadena contiene: is Una cad Antes del cambio, lista[2] contiene: 3 Después del cambio, lista[2] contiene: La finalidad del programa del listado 16.3 es mostrarle cOmo acceder a un arre- glo de tipo char, cadena, y a un arreglo de tipo int, lista. En las Iineas 6 y 8 se declarah cadena y Lista y se inicializan con una cadena y con un Conjunto de enteros, respectivamente. En las Lineas 7 y 9 se declaran un apuntador de tipo char, aptr_caden: yun apuntador de tipo int, aptr_int, ‘La linea 12 asigna la direccién de inicio del areglo cadena al apuntador aptr_cadena. Las instrucciones de las lineas 13 y 14 muestran el contenido de la cadena guardada en el arre- glo cadena, asi como el canicter contenido por el elemento cadena|4] del arreglo antes ‘de cambiar cadena, La instrucciém de la linea 15 muestra que la constante de caricter ‘u" se asigna al el ‘mento del arreglo cadena al que apunta la expresién *(aptr_cadena + 4). Para verificar que el contenido del elemento cadena se haya actualizado, las lineas 16 y 17 imprimen el elemento y la cadena completa, respectivamente. Los resultados indican ‘que 'U' sustituyé a la constante de carécter original, 'u" 264 Hora 16 La instruccién de la I{nea 11 muestra la diferencia entre los dos apuntadores int, es decir, la resta de aptr_int2 y aptr_int1. El resultado es 5. La linea 12 asigna entonces otra direceiGn de memoria al apuntador aptr_int2, que es a Ja que hace referencia la expresién aptr_inti-S, aptr_int2 apunta ahora a una ubicacién de memoria que esti 10 bytes més abajo que la ubjcacién de memoria a la que apunta aptr_inti (vea el resultado que produce la linea 13). La diferencia entre aptr_int2 ¥ aptr_intt se obtiene mediante la resta de los dos apuntadores, la cual es -5 (ya que en ‘mi maquina un int es de dos bytes) como lo imprimié la instruccién de la linea 14, Apuntadores y arreglos ‘Como se indicé en lecciones anteriores, los apuntadores y los arreglos tienen. una estre- cha relacién. Usted puede acceder a un arregio a través de un apuntador que contenga la direcciGn de inicio del arreglo. La siguiente subseccidn presenta la forma de acceder a elementos de un arregio a través de apuntadores Acceso de arreglos mediante apuntadores Debido a que un nombre de arreglo al que no le sigue un indice se interpreta como un. apuntador al primer elemento del arreglo, usted puede asignar la direccién de inicio de un arregio a un apuntador del mismo tipo de datos; luego puede acceder a cualquier elemento del arreglo sumando el entero apropiado al apuntador. El valor del entero que utiliza es el mismo que el valor del indice de! elemento al que desea acceder, En otras palabras, dado un arreglo, arregle, y un apuntador, aptr_arreglo, si arreglo y aptr_arregie son del mismo tipo de datos, y aptr_arreglo contiene la direccién de icio del arreglo, es decir aptr_arreglo = arreglo; entonces la expresién arreglo[n] equivale a la expresion *(aptr_arregla + n) Aqui, n es el {ndice del arreglo. E] listado 16.3 muestra cémo acceder a arreglos y modificar valores de elementos de arregios utilizando. apuntadores Lastapo 16.3 Cémo acceder a arreglos por medio de apuntadores J* 16L83.c: Cémo acceder a arreglos mediante spuntadores */ ‘include main() { Uso de apuntadores 263 | Resta de apuntadores Usted puede restar el valor de un apuntador de otro para obtener la distancia entre las dos ubicaciones de memoria, Por ejemplo, dadas dos variables de apuntador de tipo char, aptr_cadenat y aptr_cadena2, puede calcular el desplazamiento entre las dos ubicaciones de memoria a las que apuntan ambos apuntadores, de la siguiente manera; aptr_eadena? - aptr_cadenat Para obtener resultados significativos, es mejor restar solamente apuntadores del mismo tipo de datos. El listado 16.2 muestra un ejemplo de cémo realizar una resta en una variable de apunta- dor de tipo int. Mixstagy Listapo 16.2 Cémo realizar una resta en apuntadores 16LO2.c: Resta de apuntadores */ finclude maint) int *aptr_inti, *aptr_ant2; printf (*Posicién de aptr_intt; ‘pla, aptr_intt); aptr_int2 = aptr_int! + 8; printt(*Posicitn de aptr_into = aptr_intt + 6: Spin‘, aptr_int2); printf(*La resta de aptr_int2 - aptr_intl: din", aptr_int2 - aptr_inti); aptr_int2 = aptr_intt - 3; printt(*Posicién de aptr_int2 = aptr_intt - 8: spin, aptr_int2); printf (*La resta de aptr_int2 . aptr_intt: sdin', aptr_int2 » aptr_ant1); Después de ejecutar el archive 16L02.exe en mi méquina, se desplegaron los siguientes resultados en la pantalla: Posicidn de aptr_intt; Ox0128 Posicidn de aptr int? = aptr_int1 + 5: @xo1s2 La resta de aptr_'nt2 - aptr_intt: 5 Posicidn de aptr_int2 = aptr_int! - La resta de aptr_int2 - aptr_inti: -& EI programa del listado 16.2 declara dos variables de apuntador de tipo int, aptr_int! y aptr_int2, en la linea 6. La instruccién de la linea 8 imprime la posicién de memoria que contiene aptr_int1. La linea 9 asigna a aptr_int2 la direccién de memoria. a la que hace referencia aptr_intt+5. Después se imprime el contenido de aptr_intz en la linea 10. 2 @XOTTE [262 Hora 16 significa moverse a la ubicaci6n de memoria que est un byte mas arriba que la ubicacién actual, 0x8008, a la que hace referencia ¢l apuntador aptr_ch. La Ifnea 16 muestra la ubicacién de memoria a la que hace referencia Ia variable de apurta- dor de tipo int, aptr_int, en @x@288, Debido a que en mi sistema el tamafio de int es de 2 bytes, la expresisn aptr_int+1 mueve a aptr_int a la ubicaciGn de memoria que esta ‘2 bytes més arriba que la ubicacién actual a la que apunta aptr_int. Ese es exactamente el resultado que usted ve en la linea 17. De la misma manera, la linea 18 muestra que aptr_int+2 se mueve para hacer referencia a @x028F, que est 4 bytes mas arriba (2*size- of (int)) que @xozes. La expresign aptr_int-1 de la linea 19 hace referencia a la ubicaciin de memoria ¢x@289; y aptr_int-2, de la linea 20, hace referencia a la ubicacidn Ox6287. En mi sistema, el tamatio del tipo de datos double es de 8 bytes de longitud, Por lo tanto, la expresién aptr_db+1 se interpreta como la direccién de memoria # Ia que hace refer- encia aptr_db més 6 bytes, es decir, 6x0128+8, lo cual da @x0139 en formato hexadeci- ‘mal, como puede ver en la linea 23. Las lineas 24 a 26 imprimen las direcciones de memoria a las que hacen referencia aptr_db+2, aptr_db-1 y aptr_db-2, respectivamente, lo cual demuestra que el compi- Jador utiliz6 el mismo tamaiio escalar de double en la aritmética de los apuntadores, g Los apuntadores son muy utiles cuando se usan en forma adecuada, Sin embargo, un apuntador puede meterie en problemas con rapidez si con- tiene un valor equivocado. Por ejemplo, un error comon es asignar un valor derecho 4 un apuntador que en realidad espera un valor izquierdo. ‘fortunadamente, muchos compiladores de C detectaran dichos errores y emiticén un mensaje de advertencia, Existe otre errer comin que el compilador no siempre detecta: utilizar apun- tadores sin inicializar. Por ejemplo, el siguiente ebdiga tiene un problema potencial: int x, *aptr_int; xs saptr_int = x; El problema es que el apuntador aptr_int no esta inicializado; apunta 3 una ubicacién de memoria desconocida. Por lo tanto, asignar un valor, como en este caso 8, a una ubicackin de memoria desconocida, resulta peligroso. Podria sobreescribir algin dato importante que ya esté guardade en esa lubicacién de memoria, lo que causaria un serio problema, La solucidn es ase- gurarse de que un apuntador esté apuntanda a una ubicacién de memoria valida y legal antes de utilizario. Pera evitar el problema potencial, puede escribir el cédigo de arriba de la si- guiente manera: int x, *aptr_int; x= 8; aptr_int = 8x; /* iniedaliza el apuntagor */ Uso de apuntadores printt("Posicién después de aptr_cn + 1: ‘pin, aptr_ch print? (*Posicin después de aptrich © 2: Spin", aptroch print? (*Posicién después de aptr_ch - 1: Spin, aptr_ch print? (*Posicién después de aptr_ch - 2; Spin", aptroch - /* apuntadar de tipo int aptr_int */ printf (“Posicién actual de aptr_int: ‘p\n*, aptr_int); printf(“Posicion después de apt? int + 1: Sp\n*, aptr_int + 1); printf(-Posicion después de aptr_int + 2: spin", aptrint + 2): printf (*Posicién después de aptr_int - 1: Spin‘, aptr_int - 1); print#(“Posicién después de apte_int - 2: Spin", aptrint - 2); J* apuntador de tipo double aptr_db */ printf (*Posicién actual de aptr_db: Sp\n", aptr_db); Brintt ("Posicién despuds do aptt_db + 1: Spin", aptr_aD + 1); printf(‘Posicién después de aptr_db + 2: Spin’, aptr_db + 2 Brintt (‘Posicién después de aptridb - 1: ‘pln, aptr_db - 1); Brintt(*Posicién después de aptr_ob - 2: Spin", aptr_dD - 2); return @; Obtuve los siguientes resultados al ejecutar en mi miquina el archivo 14L01.exe del programa del listado 16.1, Usted podria obtener direcciones diferentes en su compu tadora, asi como diferentes desplazamientos, dependiendo del tamaio de los tipos de datos de su sistema. Posicién actual de aptr_ch: @x0008 Posicién después de aptr_cn + 1: @xeeec Posicién después de aptr_ch Posicién despues de aptr_ch Posieién después de aptr_eh Posicién actual de aptr_int: Posicién después de aptr_int + Posicién después ds Posicién después de aptr_int - Posiesén despuds de aptr_int Posicién actual de aptr_db Posicién después de aptr_db Posicién después de aptr db Posicién después de aptr_dd Posicién despuds de aptr_d> REIT 2 reese ver ene stad 16.1, hay es spuntadores de ieretes ipo, ptr_en, aptr_int y aptr_db, declarados en las lineas 6 a 8, Entre ellos, aptr_ch es un apuntador a un cardcter, aptr_int es un apuntador a un entero, y aptr_db es un apuntador a un tipo doble, Después, la instruceidn de la linea 10 muestra la direccién de memoria, @xae0s, conte- rida por la variable de apuntador de tipo char, aptr_eh. Las lineas 11 y 12 despliegan dos direcciones, @x@0ec y @x@eeD, cuando se le suman 1 y 2a aptr_eh, respectivamente, Asimismo, las lineas 13 y 14 dan @x00@a y @x0009 cuando se mueve aptr_ch a direc cciones mis bajas de memoria, Debido a que el tamafio de char es 1 byte, aptr_chet [260 Hora 16. mueve el apuntador a la ubis cidn actual de aptr_cadena, cin de memoria que est a un byte de distancia de la posi- Observe que los enteros que se suman o se restan a los apuntadores de diferentes tipos de datos tienen tamaiios diferentes. En otras palabras, sumar (o restar) | a un apuntador no necesariamente le indica al compilador que sume (0 reste) un byte a la direccién, sino as bien que ajuste la direccién para que ésta salte sobre un elemento del tipo del apun- tador, Verd més detalles acerca de esto en las siguientes secciones. El tamafio escalar de los apuntadores La forma general para cambiar la posicién de un apuntador es nombre_spuntador + a Aqui, €s un entero cuyo valor puede ser positivo o negative, nombre_apuntador es el nombre de una variable de apuntador que tiene la siguiente declaracién: especificador_de_tipo_de_datos *nombre_apuntador; Cuando el compilador de C lee la expresidin nombre_apuntador + n, la interpreta de la siguiente manera: nombre_epuntador + a * sizeof (especificador_de_tipo_de_datos) Observe que se utiliza el operador sizeof para obtener el niimero de bytes del tipo de datos especificado, Por lo tanto, para la variable de apuntador de tipo char, aptr_cadena, Inexpresién aptr_cadena + + significa en realidad aptrcadena + 1 * sizeof (char), a que el tamafio de un cardcter es de un byte de longitud, aptr_cadena + 1 le indica al compilador que se mueva a la ubicacién de memoria que esti 1 byte despues de la ubicacién actual a la que hace referencia el apuntador. E] programa del listado 16.1 muestra cémo los tamafios escalares de diferentes tipos de datos afectan los desplazamientos que se suman o se restan a los apuntadores. Listano 16.1 Cémo mover apuntadores de diferentes tipos de datos J" 18L81.c: Aritaética de los apuntadores */ finclude 1 2 3 4: main() Bf 6: char *aptr_chy 7: int *aptr_int} 8 double *aptr_db; #* apuntador de tipo char aptr_ch */ 10: printf ("Posicién actual de apth_eh: Sp\n", apte_ch); Hora 1 Uso de ap Piensa dos veces y achia una, —Proverbio chine En la hora 11, “Apuntadares”, de C. Debido a que los apuntadores Ia pena dedicar otra hora para se exponen las siguientes temas: + Aritmética de tos apuntadores * Paso de arregios a funciones © Paso de apuntadores a * Apuntadores a funciones Aritmética de los En C, usted puede mover la posicién dole enteros. Por ejemplo, dada una aptr_cadena, Ia expresiGn. aptr_cadena + 1 tas bases del uso de los apuntadores muy ttiles en la programacién, vale mas acerea de ellos. En esta leccivin ntadores un apuntador sumindole o restén- de apuntador a caricter, 258 Hora 15 3. Reescriba el programa del listado 15,3. Esta vez haga una funcién que tome un ndmero variable de argumentos de tipo int y que realice la operacién de multi- plicacién sebre ellos. 4, Escriba otra vez el programa del listado 15.3. En esta ocasiGn. imprima todos los argumentos que se pasen a la funcin SumaDobles({}. {Extrae va_arg() cada argu- mento de la lista de argumentos que se pasa a SunaDebles() en cl mismo orden (es decir, de inquierda a derecha)? Funciones 257| Taller Para consolidar la comprensidn de la leccién de esta hora, le recomiendo responder el cuestionario y terminar los ejercicios del taller antes de pasar a la siguiente leccién. Las respuestas y sugerencias se presentan en el apéndice B, “Respuestas a los cuestionarios y ejercicios” Cuestionario 1, Dadas las siguientes declaraciones de funcién, jeusles funciones tienen un némero fijo de argumentos, cudles son funciones sin argumentos y cudles tienen un ‘nGimero variable de argumentos? + int funcion_t(int x, float y}i * void funcion 2(char *cadena + char *asctime(const struct tm *timeptr); ‘+ int funcion_4(void) ; ‘© char funeion_a(char c, ‘© void funeion_s(void); 2, 7Cual de las dos expresiones siguientes es una definicién de funcién? int funcion {int x, int y)j int funcion_2(int x, int y){return x+y;} 3. (Qué tipo de datos devuelve una funcién cuando se omite el especificador de tipo? 4, ;Cudl de las siguientes declaraciones de funcién es ilegal? * double funcion_t{int x, . = void funeion_2(int x, int y, ..-); © char funeion_a(...); © int funcion_4(int, int, int, int); Ejercicios | 1, Reescriba el programa del listado 15.2. Esta vez utilice el especificador de formato ‘sc, en lugar de %s, para imprimir.en su computadora la cadena de caracteres de la hora local, Declare y defina una funcién, Ilamada multidos(), que pueda multiplicar dos va- 7 riables enteras. Llame a la funcidén wulti0os() desde la funcién main() y pasele dos emteros. Imprima después en la pantalla el resultado que devuelva la funcién Muitd00s(). [256 Hora 15 * va_start(), va_arg() y va_end(), todas incluidas em stdarg.h, som necesarias para procesar wn niimero variable de argumentos que se pasa a una funcidn. * time(), localtime() y asctime() son tres funciones de hora que proporciona C, ‘Se pueden usar juntas para obtener una cadena de caracteres que contenga informa- ciém acerca de la fecha y hora locales con base en la hora calendario. En [a siguiente leccién aprender mais acerca de los apuntadores y su aplicacién en C. Preguntas y respuestas P ;Cudil es la principal diferencia funcién? R La principal diferencia es que Ia declaracién de una funcitin no reserva ningiin espacio de memoria, ni especifica lo que hace: la funcién. Una declaraciéin de fun- cidn sélo hace referencia a la definicién de funcién que est colocada en otra parte. ‘Ademiés especifica qué tipo de argumentos y valores se pasan a la funcién y se devuelven de ella. Por otra parte, una definicién de funcidn reserva el espacio de memoria y especifica las tareas que puede levar a cabo la funcidn. P {Por qué son necesarios los prototips de funciin? R_ Al declarar una funcién con prototipos, usted especifica no sélo el tipo de datos que devuelve la funcién, sine también Jos tipos de datos y nombres de los argu- mentos que s¢ le pasan. Con la ayuda de un prototipo de funci6n, el compilador puede realizar en forma automitica una verificacién de tipos sobre la definicién de la funcién, Io cual le ahorra tiempo a usted en la depuracién del programa. P Puede una funcién devolver un apuntador? R_ Si. De hecho, una funcién puede devolver un solo valor que sea de cualquier tipo de datos, excepto un arreglo o una funcién. Un valor de apuntador —es decir, la direceién— devuelto por una funcién puede hacer referencia a un arreglo de carac- teres o a una ubicacién de memoria que almacene otros tipos de datos. Por ejem- plo, la funcién asctime() de la biblioteca de C devuelve un apuntador que apunta avuna cadena de caracteres convertida a partir de una estructura de fecha-hora. P. ;Es posible utilizar juntas la programacién descendente y la programacién ascendente para resolver un problema? R. Si. En Is prictica puede descubrir que en realidad es una buena idea combinar ambos enfoques de programacién estructurada para resolver problemas. Emplear estas des tipos de programacién puede hacer que su programa sea facil de escribir y entender, re una declaracién y una definicién de Funciones 255) J Comprension de la programacion estructurada Ya aprendié Jo basico de la declaracidn y definicidn de funciones. Ames de pasar a la siguiente hora, hablemas un poco de la programacién estructurada en el disefo de programas, La programacién estructurada es una de las mejores metodologias de programaciéa. Existen basicamente dos tipas de programacién estructurada: descendente y ascendente. Cuando usted comienza a escribir un programa para resolver un problema, una manera de hacerlo es trabajar sobre las piezas més pequefias del problema. Primero define y escribe funciones para cada pieza, Después de escribir y probar las funciones, comienza a ensamblarlas para construir un programa que pueda resolver el problema. A este enfoque se le conoce normalmente come programacién ascendente Por otra parte, para resolver un problema puede trabajar primero en un bosqueje y comen- ‘ar su programaci6n a un nivel mds alto. Por ejemplo, puede trabajar al principio sobre la funcién main(). y pasar después al nivel inferior siguiente hasta escribir las funciones del nivel mis bajo. A este tipo de enfoque se le denomina programacién descendente. Gtil combinar estos dos tipos de programacién estructurada y altemar su uso para solucionar problemas reales. Descubrira que result Resumen En esta lecciGn aprendis Jos siguientes conceptas importantes acerca de las funciones de C: + Una declaracién de funcidn hace referencia a una funeidn que est definida en otra parte, y especifica qué tipos de argumentos y valores se pasan a la funcidn y se devuelven de ella, + Una definicisn de funcién reserva el espacio de memoria y define lo que hace la funcién, as{ como el nimero y tipo de argumentos que se le pasan. + Se puede declarar una funcién para que devuelva cualquier tipo de datos, excepto un arreglo 0 una funcién. + Lainstrucei6n return que se usa en la definicién de funciones devuelve un solo valor, cuyo tipo debe coincidir con el seitalado en la declaracién de la funcisn, + Una flamada a una funcién es una expresién que pucde emplearse como una sola instruccién 0 dentro de otras expresiones o instrucciones. * El tipo de datos void es necesario en la declaracién de una funciGn que no toma ningdin argumento, + Para declarar una funcidn que toma un némero variable de argumentos, tiene que especificar por lo menos el primer argumento, y usar los puntos suspensivos (. . para representar al resto de los argumentos que se pasan a la funcién, [254 Hora 15 Despugs de ejecutar el archivo 15109 exe, se desplegaron en Ia pantalla fos siguientes resultados: Dada un argunento: 1.5 MAGE £1 total de argunentos EL resultado que devuelve SunaDobles() Dadas los argunentos: 1.5 ¥ 2.5 EL total de argunentos es: 2 EL resultado que devuelve SumaDobles() es: 4.0 Dados los argunentos: 1.5, 2.5, y 3-5 EL total de argumentos es: 9 EL resultado que devuelve SumDcbles() es: 7.5 Dadas los argunentos: 1.5, 2.5, 3.5, y 4.5 EL total de argunentos es: 4 EL resultado que devuelve SumaDebles() es: 12.0 El programa del listado 15.3 contiene una funcién que puede tomar un ndmero variable de argumentos de tipo doubie, realizar la operacién de suma sobre estos argumentos y devolver después el resultado a la funcién main() La deelaracién de la linea 5 le indica al compilador que la funcién SumaDobles () toma ‘in niimero variable de argumentes, El primer argumento para SunaDobles() es una va- riable entera que contiene el niimero de los argumentos restantes que se pasan a la fun cién cada vez que se Hama a Sumadobies( ). En otras palabras, el primer argumento indica el ndémero de los argumentos restantes a procesar, En las Iineas 30 a 42 se da In definicién de Sunabables(), y en la linea 32 se declara el arregio de tipo va_list, Listaarg. Como ya se menciond, se tiene que llamar a la macro va_start() antes de procesar los argumentos, Asi, la linea 37 invoca a va_start() para inicializar el arreglo Listaarg. El ciclo for de las lineas 38 y 39 extrae el siguiente ar gumenta double guardada en el arreglo 1istearg llamanda a va_arg(). Luego, cada argumento se suma en una variable local double llamada resultado. En Ia Ifnea 40 se Hama a Ja funcién va_end{) después de extraer y procesar todos los argumentos almacenados en Listaarg. Después se devuelve el valor de resultado al Mamador de la funcidn Sunadables (), que en este caso es Ia funcidn mani), Para finalizar el procesamiento de argumentos variables en un programa de C, se debe llamar a la funcién va_end¢). De no hacerlo, el comportamiento del programa seri impredecible, Coma puede ver, dentro de Ia funcién main() se llama cuatro veces a SunaDob1es () cada vez con un ntimero diferente de argumentos. Estos argumentos que se pasan a Sunadobles() se despliegan mediante las llamadas a las funciones print® () de las lineas 14, 17, 20 y 23. Ademés, se imprimen en la pantalla los cuatro diferentes resulta- dos que devuelve Suaadebles() Funciones: 253 El listado 15.3 muestra cémo utilizar va_start(), va_arg() y ¥a que toma un niimero variable de argumentos. 14 () en una funcisn Listano 15.3 Procesamiento de argumentos variables (* 16L03.c: Procesar include #include ento de argumentos varistles */ double SunaDobles{int x, main () 4 double 41 = 1.5; double 42 = 2.5} double 3 = 3.5; double d4 = 4.5; printt ("Dado un argueento: 82.1f\n", 1); printf (“El resultado que devuelve SunaDobles() es: %2.1f\nin", SunaDobles(1, 131; printf (‘Dados los argumentos: 42.1 y S2.if\n", dt printf ("EL resultado que devuelve Sumadobles() SunaDobles(2, 41, o2)); Brintf ("Dados los argumentos: N2.1f, S2.1f y S2-1f\n", a1, a2, 43); printf ("EL resultado que devuelve SumaDobles() es: 2.if\min", SunaDobles(3, di, 2, 43)}; printf ("Osdos los argumentos: N2.1f, S2.1f, S2.1f, y A2.1fIN", a1, d2, 03, 64); printf ("EL resultado que devuelve SumaDobles() es: 82.1fin", SumaDobles(4, di, d2, 43, d4)}; return @; 2); 282. TF nn, » 1* definicién de SumaDobles() */ double SunaDobles(int x, ...} 4 va_list Listaarg; int ij double resultado = printf ("El total de argumentos es: Sdin", x}; va_start (Listaarg, x); for (i=@; icx; is¢) resultado += va; wa_end (Listaarg); return resultado; ‘g(listaarg, double); [252 Hora 15 Por ejemplo, la declaracién de la funcién printf () seria algo como lo siguiente: int printf (const char *fornato, . Procesamiento de argumentos variables En el archivo de encabezado stdarg.h hay tres rutinas declaradas, las cuales le permiten ‘escribir funciones que toman un niimero variable de argumentos, Estas son: va_start (), va_arg() y va_end(). Ademds, en stdarg.h se incluye el tipo de datos va_list, el cual define un tipo de arreglo adecuado para contener los elementos de datos que necesitan va_start(), va_arg() y va_end() Para inicializar un determinado arreglo que necesitan va_arg() y va_end(), tiene que utilizar la rutina macro va_start() antes de procesar cualquier argumento. La sintaxis de la macro va_start() es Minclude void va_start (va_list ap, noaarg); Aqui, ap es el nombre del arreglo que esta por inicializar la rutina macro va_start(). nomarg debe ser el argumento que esti antes de los puntos suspensivos (, ..) en Ia declaracién de la funcién. Al utilizar Ia macro va_arg(). usted puede tratar con una expresién que tenga el tipo y valor del siguiente argumento. En otras palabras, la macro va_arg() se puede utilizar para obtener el siguiente argumento que se pasa & la funcién, La sintaxis de la macro va_arg() es include type va_arg(va_list ap, tipo_datos); ‘Aqui, ap es el nombre del arregio que inicializa Ia rutina macro va_start(}. tipo_datos es cl tipo de datos del argumento que se pasa a la funcién. Para facilitae una devolucién normal de su funcién, debe usar la funcién va_end{) en su programa después de procesar todos los argumentos. La sintaxis de la funcidn va_end() es #ineluse void va_end(va_list ap); Aqui, ap es el nombre del arreglo que inicializa la rutina macro va_start() Recuerde incluir en su programa el archivo de encabezado stdarg.n antes de llamar a va_start(), va_arg() 0 va_end(). Funciones 251) 22, asctine(localtine(Sanora) ), obtiene la expresidn de hora local de la hora calen- dario Hamando Locaitima(), y convierte la hora local en una cadena de caracteres con la ayuda de asctime(), La cadena de caracteres que representa Ia fecha y hora se imprime entonces mediante la Wamada a print? () de las lineas 21 y 22, la cual tiene el siguiente formato: Sat Apr 08 113 1@ 1997\n\@ Observe que en la cadena de caracteres convertida y devuelta por la funcién asctime( ), hay un eanicter de linea nueva agregado justo antes del eardcter aula, Funciones con un numero fijo de argumentos ‘Ya ha visto varios ejemplos que declaran y aman funciones con un nimero fijo de angu- mentos, Por ejemplo, la declaracién de funcion_1() de la linea 4 del listado 15.1 int funeton (int x, int y}; comtiene el prototipo de dos argumentos, x yy. Para deelarar una funcién con un ntimero fijo de argumentos, necesita especificat el tipo de datos de cada argumento, Ademas se recomienda indicar los nombres de los argumen- tos, para que el compilador pueda verificar que los tipos y nombres de argumentos sefia- lados en la declaracidn de una funcién coincidan com la implementacién de la definicién de La misma. Prototipo de un numero variable de argumentos Como tal vez recuerde, la sintaxis de la funcién printf () es Ant printficonst char *fennatol, argumento, ...1); Aqui, los puntos suspensivos (...) representan un nimero variable de argumentos. En otras palabras, ademas del primer argumento que es una cadena de caracteres, la funcién printf () puede tomar un niimero no especificado de argumentos adicionales, tantos como el compilador permita. Los corchetes (| y 1) indican que los argumentos no espe- Cificades son opcionales. La siguiente es una forma general para declarar una funcién con un niimero variable de argumentas: especificador_de_tipo_de_datos ombre_de_funcidn( especificador de tips_de_datos nombre de argumentot, ... h Observe que el nombre del primer argumento esta seguide por los puntos suspensivos (...) que representan ¢l resto de los argumentos no especificados. [250 Hora 15 >< Si Aqui, Hora calendario da la fecha y hora acwuales con base en el calendario Gregoriano, Hora local representa el tiempo calendario en una zona horaria especifica. Horario de verano es la hora local bajo las reglas del horario de verano. En esta seccidn se presentan brevemente tres funciones de fecha y hora: time(), local - time() y asctine() La funcidn tine() devuelve la hora calendario. La sintaxis de la funcién time() es #include tine_t tine (tine ¢ *tiempo); Aqui, time_t es el tipo aritmético que se usa para representar el tiempo. tiempo es una variable de apuntador que apunta a una ubicacién de memoria que puede contener Ix hhora calendario que devuelve esta funcién. La funcién time() devuelve -1 si la hora calendario no estd disponible en la computadora. ‘La funcidn 1ocaitine() devuelve la hora local convertida a partir de la hora calendario, La sintaxis de la funcién Localtine() es Winclude struct tm *localtine(const time_t *tienpo); Aqui, tm es una estructura que contiene los componentes de la hora calendario. struct es la palabra reservada para estructura, 1a cual es otro tipo de datas de C. (El concepto de estructura se presenta en la hora 19, “Estructuras de datos”.) tiempo es una variable de apuntador que apunta a una ubicacién de memoria que contiene la hora calendaria que devuelve la funcidn timo (). Para convertir la fecha y hora representadas por la estructura tm, puede llamar a la fun- cidn asctime() La sintaxis de la funcién asctime() es ‘@include ‘char “asctine(const struct tm *epertisnpo); Aqui, aptrtienpo es un apuntador que hace referencia a la estructura tm que devuelven las funciones de fecha y hora como localtine(). La funcién asctime() convierte en ceadena de caracteres la fecha y hora representadas por tm. ‘Como se muestra en él listado 15.2, la instruccién de la linea 17 declara una variable de tipo time_t Hamada anora. La Ifnea 20 almacena la hora calendario en la ubicacién de memoria a la que hace referencia la variable ahora. Observe que el arguments que se pasa a la funcidn time() debe ser el valor izquierdo de una variable; por lo tanto, se utiliza el operador de direccién (8) antepuesto a anora, Luego, la expresiGn de la linea Funcianes 249 Obtuve los siguientes resultados después de ejecutar el archivo 1SL02.exe del programa del listado 15.2: Antes de Manar a la funcién FechaHora(). Dentro de FechaHora(). La fecha y hora actuales son; Sat Apr 05 11:50:10 1907 Después de llamar a La funcién FechaHora(). La finalidad del programa del listado 15.2 es mostrarle cémo declarar y Hamar tuna funci6n sin pasar argumentos. El programa imprime la fecha y hora actua- Jes de sui computadora Hamnando a la funcién Fechatora(), declarada en la Iinea 5S. Debido a que no es necesario pasar ningiin argumento a la funcién, en la declaracidn de FecnaHora() se usa el tipo de datos void camo prototipo. ‘Ademis se usa otra palabra reservada void antes del nombre de la funcién FechaHora() para indicar que 1a funcién tampoco devuetve ningtin valor (vea ta linea 5). Las instrucciones de las lineas 9 y I imprimen mensajes antes y después de llamar 2 la funciGn FechaHora() desde el interior de la funcién main()- En la linea 10 se Jama a la funcién mediante la instrucciéin FechaHora();. Observe que no se debe pasar ningiin argumento a esta funcién, debide a que su prolotipo es void. La definicién de FechaHora() esti en las Iineas 15 a 23; la funcién obtiene la hora calen- dario y la convierte a una cadena de caracteres Hamando a varias funciones de la biblio- teca de C: time{}, localtime(} y asctime(). Luego, la funcién printf () imprime en 1 pantalla la cadena de caracteres que contiene la fecha y hora actuales, mediante cl especificadar de formato %s, Como puede ver, los resultados muestran en mi pantalla que al momento de ejecutar ef archivo 15L02..exe la fecha y hora fueron las siguientes: Sat Apr 05 tt 10 1997 ‘time (), localtime() y asctime() son funciones de fecha y hora que proporciona <1 lenguaje C. En la siguiente subseceién veremos estas funciones. Tal vez haya notada que se incluye el archivo de encabezado time.h al principio del programa del listada 15.2 antes de usar estas funciones de tiempo. Uso de time(), localtime() y asctime() Hay un grupo de funciones de C que se conocen como funciones de fecha y hora, Las declaraciones de todas las funciones de fecha y hora estdn incluidas en el archive de encabezado tine. h, Estas funciones pueden dar tres tipos de fecha y hora: + Hora calendario + Hora local * Horaria de verano [248 Hora 15 Funciones sin argumentos El primer caso es el de una funcidm que no toma ningdn argumento, Por ejemplo, Ia fun- cidn de biblioteca de C getchar() no necesita argumentos. Se puede usar en un progra- ma de la siguiente manera: © = getenar(); Como puede ver, cuando se llama a la funeién en la segunda insteuccién, se deja en blanco el espacio entre los paréntesis (( y )). En C, la declaracin de la funcidn getehar () puede ser algo como lo siguiente: int getchar(void) ; Observe que en la declaracién se utiliza la palabra reservada void para indicarle al compilador que esta funcién no necesita ningin argumento. El compilador emitiré un mensaje de error si se pasa algiin argumento a getchar() mis adelante en el programa, cuando se lame a la funcisn. Por lo tanto, para una funcién sin ningdn argumento, se usa el tipo de datos void coma el prototipo de la declaracién de Ia funcién, El programa del listado 15.2 muestra otro ejemplo del uso de void en la declaracidn de funciones. n de funciones Bist Listapo 15.2 Uso de void en la declar 1* 15L@2.c: Funciones sin argunentos */ Winclude include 43° int funcion_tcint x, int y); $: double funcion 2(double x, double y) ef 244 Hora 15 Declaraci6n de funciones ‘Como usted sabe, tiene que declarar o definir una variable antes de poder utilizarla. Esto también se aplica a las funciones. En C, debe declarar o definir una funcién antes de que pueda Hamarla, Declaraci6n en comparacién con definicién De acuerdo con el estindar ANSI. la declaracién de una variable o funcién especi la interpretacién y atributos de un conjunto de identificadores. Por otra parte, la definicidn requiere que el compilador de C reserve espacio de almacenamienta para una variable 0 funcién nombrada por un identificador. Una declaracién de variable es una definicisn, pero una declaracién de funcién no lo es. Una declaracién de funcidn hace referencia a una funcién que est definida en otra parte y especifica qué tipo de valor devuelve la funcién. Una definicién de funci6n define lo que hace la funcién, ademis de dar el niimero y tipo de argumentos que se pasan a la funcidn, Una declaracién de funciGn no es una definicién de funcidn. Si coloca una definicién de funcién en su archivo fuente antes de lamar por primera vez.a la funcién, no necesita declarar la funciGn, En caso contrario, debe declarar la funcién antes de invocarla. Por ejemplo, utilicé la funci6n printf () en casi todos los programas de muestra del libro, Tave que incluir en cada programa un archivo de encabezado, stdia..h, debide a que dicho archive contiene la declaraci6n de printf (), Ia cual le indica al compitador el tipo de devolucién y el prototipo de la funeién. La definicién de ta funcién printt() se coloca en cualquier lugar. En C, la definicién de esta funcién se guarda en un archiva de biblioteca que se invoca durante las etapas de enlace. Especificacién de los tipos de retorno Se puede declarar una funci6n para que devuelva cualquier tipo de datos, excepto un arre~ glo o una funcién. La instruccién return que se usa en una definicién de funcidn devuelve tun solo valor cuyo tipo debe caincidir con el sefialado en ta declaracién de la funcién. Si no se especifica ningtin tipo de datos explicito para la funcién, el tipo de retomo de una funcién serd int de manera predeterminada. Antes del nombre de la funcidn se colo- ca un especificador de tipo de datos, como se muestra a continuacién: eepecificador_de_tipo_de_datos nambre_de_funcidn(); Aqui, especificador_de_tipo_de_datos cspecifica el tipo de datos que debe regresar Ja funcién. nombre_de_funcién es el nombre de la funcién que debe seguir las reglas de nombrado de identificadores de C. De hecho, esta forma de declaracién representa la forma tradicional de declaracién de funciones desde antes de la creacién del esténdar ANSI, Después de configurar el estin- dar ANSI, se agrega a la declaracién de la funcién el prototipo de funcién, — Ssemenndl = = — a _-e HoRA 1 5 Funciones La forma sigue a la funcién. =L. H. Sullivan ‘Tal vez haya notado en Ia hora 14, “Alcance y clases de almacenamiento”, que siempre se da primero la definicién de una funcién, antes de Hamar a la funcién desde una funcién wain(). De hecho, puede colocar la definicién de una funcién en donde usted quiera, siempre y cuando-lo haga antes del primer lugar en donde se lame a la funciGn. Aprenderd muchas caracteris- ticas de Jas funciones en los temas que trataremos en esta leo * Declaracién de funciones * Prototipos + Valores que devuelven las funciones + Argumentos para tas funciones * Programacin estructurada Ademis, en esta hora se presentan varias funciones y macros de la biblio- teca de C, como tine(). Localtima(), asctime(). va_start(). va_arg() y va_end(), ‘Obraz chroniony prawem autorskim Material chroniony prawem autorskim ant -nain() { dnt a3 tor (190; <5; it+){ int x = static int y Print ("eka nt, ee, yey + return @; d 4, Reescriba la funcidn suma_dos() del listado 14.3 para imprimir e] resultado ante- rior de la suma, asf come el valor del contador, | 238 Hora 14 Taller Para ayudarle a consolidar la comprensién de esta leccién, le recomiendo responder el cuestionario y terminar los ejercicios del taller antes de pasar a la siguiente leccién. Las respuestas y sugerencias se presentan en el apéndice B, “Respuestas a los cuestionarios y ejercicios”. Cuestionario 1, Dado el siguiente fragmento de c6di son locales con aleance de bloque? ant x= float y = Ant miFuneion(} 4 ant a, . :eudles variables son globales, y cudles 2, ,Cémo sabe el compilador qué variable utilizar cuando se definen dos variables con el mismo nombre? 3, Identifique la clase de almacenamiento de cada declaracisn del siguiente fragmento de cédigs static int x extern float yj Ant miFuneion(} 1 ant i, iy extern float 2; register long static int indice; const char cadena[) = “Mensaje de advertencia.*; hoo 4, Dada la siguiente declaracién: const char cadena[] = "El especificador cons jes vilida Ia instruccién cadena| pee icance y clases de almacenamiento 237 + Para asegurarse de que los valores guardades por una variable no cambien, puede declarar la variable con el modificador const. + Si desea permitir que el compilador sepa que cl valor de una variable se puede cambiar sin una instruceién explicita de asignacién, declare ta variable con el mo- dificador volatile a fin de que el compilador desactive las optimizaciones sobre expresiones que comprendan a la variable. En Ia siguiente lecci6n aprenderé acerca de las declaraciones y prototipos de funciones de C. Preguntas y respuestas P Puede una variable global ser ocultada por una variable local con aleance de bloque? RR Si. Si una variable local comparte el mismo nombre con una variable global, esta \iltima puede ser ocultada por la variable local para el alcance del bloque dentro del cual est definida la variable local. Sin embargo, no es posible ver a la variable local fuera del bloque, por lo que la variable global se hace visible de nuevo. P. ZPor qué necesita el especificador static? R_ En muchos casos, el valor de una variable es necesario, incluso si s¢ ha salido del alcance del bloque en el que est declarada Ia variable. De manera predeterminada, ‘una variable con alcance de bloque tiene un almacenamiento de memoria temporal, ‘es decir, el tiempo de vida de la variable comienza cuando se ejecuta el bloque y se declara la variable, y termina cuando finaliza la ejecucién de ese bloque. Por lo tanto, para declarar una variable con duracin permanente, tiene que usar el especificador static para indicarle al compiladar que la ubjeacién de memoria de la variable y cl valor ahf almacenado se deben conservar después de Ja ejecucién del bloque. P_ ;Puede el uso del especificador register garantizar la mejora en el rendimiento de un programa? R En realidad no. Declarar una variable con el especificador register sélo sugiere al compilador que debe almacenar la variable en un registra. Pero no hay garantia de que esto suceda. El compilador puede ignorar la solicitud con base en 1a dispo- nibilidad de registros o en otras restricciones. P Cuando declara una variable con el especificador extern, jdefine la variable o hace referencia a una variable global en otra parte? R_ Cuando se declara una variable con el especificador extern, el compilador consi- dera Ia declaracién de la variable como una referencia, mds que como una defini- cidn, Por lo tanto, e! compilador buscard en otra parte la variable global a Ia que hace referencia la variable con extern. 236 a4 volatile char car_teclado; /* una variable volatile */ Resumen En esta leccidn aprendis los siguientes concepios importantes acerca de los alcances y Jas clases de almacenamiento de C: + Una variable que se declara dentro de un bloque tiene alcance de bloque. A dicha -variable también se le llama variable local y sélo es visible dentro del bloque. * Una etiqueta de goto tiene un alcance de funcién, lo que significa que es visible -s través del bloque completo de la Funciéin dentro de Ia que se coloca la ctiqueta. Dos etiquetas goto no pueden compartir el mismo nombre dentro de un bloque de funcién. + Una variable que se declara con el especificador static fuera de una funcién tiene aleance de archivo, lo que quiere: decir que es visible a lo largo de todo el archivo fuente en el que esté declarada. * Se dice que una variable que se declara fuera de una funcidn tiene un aleance de ‘programa, Dicha variable también se denomina variable global. Una variable global es visible en todos los archivos fuente. que conforman un programa ejecutable, * Una variable con aleance de bloque tiene Ia visibitidad més limitada. Por otra ‘pane, una variable con alcance de programa es la més visible, y puede verse en todos los archivos, funciones y otros bloques que conforman el programa. ‘La clase de almacenamiento de una variable se refiere a 1a combinacién de sus Tegiones espacial y temporal (es decir, a su alcance y duracién), + Uma variable con alcance de blogue tiene una duracién auto de manera predetermi- nada, y su almacenamiento de memoria es temporal * Uma variable declarada con el especificador static tiene un almacenamiento de memoria permanente, incluso después de que se llam6 a la funcién en la que esta declarada la variable y se salié del alcance de la funcién. Una variable declarada con el especificador register podria almacenarse en un registro para acelerar el rendimiento-de un programa; sin embargo, el compilador puede ignorar el especificador si no hay un registro disponible o si se aplican otras restricciones. + También puede referirse a una variable global definida en otra parte, mediante el ‘especificador extern en el archive fuente actual. Alcance y clases de almacenamiento 235 Por ejemplo, la siguiente expresién le indica al compilador que pi es una variable cuyo valor no debe cambiar: const double pi = 9.141599; De la misma manera, el valor del arreglo de caracteres cadena declarado én la siguiente instruceién tampoco debe cambiar: const char cadena[] = ‘una constante de cadena"; Por lo tanto, no es valido hacer algo como lo siguiente: cadena[o] = ‘a’; /* No se peraite aqui. */ Ademis, puede declarar una variable de apuntador con el modificador const a fin de que ro se pueda modificar el objeto al que sefiala, Por ejemplo, considere la siguiente declaracién de apuntador con el modificador const: char const taptr_caden: = "Una constante de cadena*; Después de 1a inicializacién, no puede modificar el comenido de 1a cadena a la que apunta aptr_cadena. Por ejemplo, no se permite la siguiente instruccidn *aptr_cadena J No se permite aqui, */ Sin embargo, el propio apuntador aptr_cadena puede asignarse a una direccién difereme de una cadena que esté declarada con char const. El modificador volatile A veces necesita declarar una variable cuyo valor se pueda cambiar en su programa sin ninguna instruccién explicita de asignacién. Esto es cierto, especialmente cuando trata de manera directa con el hardware. Por ejemplo, podria declarar una variable global que contenga caracteres intraducides por el usuario, La direecién de la variable se pasa a un registro de dispositive que acepta caracteres desde él teclado. Sin embargo, cuando el compiladar de C optimiza su programa en forma automética, no tiene la intencién de actualizar el valor que conticne la variable, a menos que ésta esté en la parte izquierda de un operador de asignacién (=). En otras palabras, es probable que el valor de la varia- ble no cambie aun cuando el usuario introduzca caracteres desde el teclado. Para solicitar al compilador que desactive ciertas optimizaciones sobre una variable, pue~ de declararta con el modificador volatile. Por ejemplo, en el siguiente fragmento de cédigo, la variable ear_teclado declarada con el modificador volatile, indica al com- pilador que no optimice ninguna expresi6n de la variable debido a que el valor guardado en ella podria cambiar sin la ejecuciém de ninguna expresién explicita de asignacisin: vois 1ee_teclado() 4d [234 Hora 14 La solucisn es utilizar el especificador extern que proporciona el lenguaje C para aludir a. una variable global definida en cualquier otra parte, En este caso, usted declara una variable global en el archivo A, y Iuego declara de nuevo la variable utilizando el espe- cificador extern en el archivo B. Esta no es una declaracién aparte, sino que especifica la declaracién original del archivo A, Por ejemplo, suponga que tiene dos variables globales de tipo int, yy 2, que estin defi- nidas en un archivo, y luego, en otro archivo, podria tener las siguientes declaraciones: int x= [* una variable global */ extern int ys F* una alusidn a una variable global y */ int main() extern int x; /* una alusién a una variable global 2 */ int 4; s* una variable local */ return @; } Como puede ver, hay dos variables enteras, y y z, que estin declaradas con el especifica- dor extern, tanto fuera como dentro de la funciGn main( ), respectivamente. Cuando el compilador ve las dos declaraciones, sabe que en realidad son alusiones a las variables globales y y z definidas en alguna otra parte, —— Para hacer portable su programa entre diferentes plataformas de compute, =| g Bone nica an ll aan rl decrease bei, | + Al decarar una variable glebal, puede ignorar el especificador extern, pero tiene que incluir un inicializader. | | + Debe emplear el especificador extern (sin un inicializader) cuando ‘luda a una variable global definida en otra parte. Los modificadores de clase de almacenamiento Ademis de los cuatro especificadores de clase de almacenamiento presentados en las secciones anteriores, C también te proporcions dos modificadores de clase de almace- namiento (0 calificadores, como a veces se les Hama) que puede usar para indicarle al compilador de C cémo podria acceder a las variables. El modificador const Si declara una variable con el modificador const, el contenido de la misma no se puede modificar una vez inicializada. Alcance y clases de almacenamiento 233 El especificador register La palabra register se toms prestada de la terminologia de hardware computacional. Cada computadora tiene un cierto ndimero de registros para contener datos y realizar operaciones de cilculo aritmético o légico. Debido a que los registros estén ubicados dentro del chip de la CPU (unidad central de procesamiento), resulta mucho més. répido J acceder a un registro que a una ubicacién de memoria que reside fuera del chip. Por lo tanto, almacenar variables en registros podria ayudar a acelerar su programa. E] lenguaje C le proporciona el especificador register, Usted puede aplicar este especi- ficador a variables cuando crea que sea necesario colocarlas dentro de los registros de la computadora, Sin embargo, el especificador register silo hace una sugerencia al compilador. En otras palabras, no se garantiza que una variable especificada con la palabra reservada register se almacene en un registro. El compilador puede ignorar la sugerencia si no hay un registro disponible, o si se aplica alguna otra restriccién. No es vailido tomar Ja direcciGn de una variable que esté declarada con el especificador register, ya que se pretende que la variable se almacene en un registro y no en memoria, Un registro de la CPU no tiene una direcciGn de memoria a la que usted pueda acceder. En el siguiente fragmento de eddigo se declara una variable entera 1 con el especificador rogist Ant main() { J aloance de Bloque con el especificador register */ register int 4; for (1 hs } return 5 MAK NUM; ++) { gunas instrucciones */ , La declaracién de 4 sugiere que el compilador almacene la variable en un registro, Debido a que i se usa de manera intensiva en el ciclo for, almacenarla en un registro podrfa aumentar la velocidad de este cédigo. El especificador extern ‘Como vimos antes en esta hora, en la seccidn titulada “Alcance de programa”, una variable con alcance de programa es visible a través de todos los archivos fuente que conforman un programa ejecutable. A una variable de este tipo también se le conoce como variable global He aqui la pregunta: ;Cémo puede ser vista en el archivo B una variable declarada en el archive A? En otras palabras, ;cOmo sabe el compilador que la variable wtilizada en el archive B es en realidad 1a misma variable declarada en el archivo A? [232 Hora 14 El alcance de archivo y la jerarquia de los alcances En la primera parte de esta hora mencioné tres de los cuatro tipos de alcance: de bloque, de funcién y de programa. Ahora es el momento de presentar el cuarto aleance: el aleance de archivo. En C, se dice que una variable global declarada con el especificador static tiene un alcance de archivo. Una variable con alcance de archivo es visible desde el punto de su declaracién hasta ¢l final del archivo, Aqui, ¢l archivo se refiere al archivo de programa ‘que contiene el cédigo fuente. La mayoria de los programas grandes consta de varios archivos de programa, El siguiente fragmento de c6digo fuente muestra variables con alcance de archivo: int x = 6; J* alcance de prograna */ static int y = © alcance de archivo * static float z I aleance de archivo */ Ant main() { int i; /* allcance de bloque */ return @; b Aqui, la variable y de tipo int y Ia variable z de tipo float tienen alcance de archivo. La figura 14.1 muestra la jerarquia de los cuatro alcances. Como puede ver, una variable ‘con alcance de bloque es La més limitada y no es visible fuera del bloque en el que esti /* La funeién suma_dos */ int suna_dos (int x, int y) { static int contador = 1; prantf(*Llanada ‘da la funcién,\n*, contador++); return (x + y)j y* la funeion main */ main() t int 4, 45 for (i=, j=5; is5; i++, j--) printf(*le suma de ‘dy ‘id es ‘td. \min*, i, J, sumados (i, §)); return 0; } | valor de Ia variable local x con alcance de bloque, mientras que el valor de y sigue siendo el de la variable global y, En las lineas 19 a 23 hay un bloque anidado, dentro del cual se declara ¢ inicializa la variable y de tipo double con alcance de bloque. Al igual que la variable x que est dentro del bloque main(), esta variable y, que esti dentro del bloque anidado, sustituye 4 la variable global y. La instrucciém de la linea 22 despliega en la pantalla los valores de las variables locales x y y Debido a que una variable global es visible entre los diferentes archivos fuente de un programa, su uso incrementa la complejidad de su programa, Jo que a su vez lo hace mas dificil de depurar y de darie mantenimiento. Por lo general, no se recomienda que declare y use Variables globales, 8 menos que sea absolutamente nécesario. Por ejemplo, puede declarar una variable global cuyo valor lo usen (pero nunca lo cambien) diversas subruti- nas de su programa, (En la hora 23, "Compilacién: el preprocesador de C", aprenderd a usar la directiva #deti definir constantes que se utilicen ‘en muchas partes de un programa) Ames de presentar el alcance de archivo, permitame hablar primero acerca de los especi- ficadores de clases de almacenamiento. Los especificadores de clases de almacenamiento En C, la clase de almacenamiento de una variable se refiere a la combinacidin de sus regiones espacial y temporal, ‘Ya uprendid acerca del alcance, el cual especifica la regidn espacial de una variable. Concentrémonos ahora en ta duracién, Ia cual indica la regién temporal de una variable. Existen cuatro especificadores y dos modificadores que se pueden emplear para indicar ta duracién de una variable. Estos se presentan en las siguientes secciones. El especificador auto El especificador auto se usa para indicar que la ubicacién de memoria de una variable es temporal. En otras palabras, el espacio de memoria reservado para una variable se puede borrar o reubicar cuando la variable esté fuera de su alcance. ‘Slo las variables que estén dentro del alcance de blogue se pueden declarar con el especifi- cador auto. Sin embargo, en la prictica rara vez se usa la palabra clave auto, debido a que Ja duracin de una variable con alcance de bloque es temporal de manera predeterminada. Alcance y clases de almacenamienta 229 [28 Hora 14 Listape 14.2 continuacion 6: 7: void funeion_i() a 8: printf (*Desde 1a funcion_i:\n x=8d, y=RtYM", x, ¥); 18: 11: 42: main() 13: { 14: int x = 4921; /* alcance de bloque 1*/ 18: 16: funcion_1(); 17: printf(*Dentro del bloque main:\n x=8d, y=Mf\n", x; ¥); 1a: /* un bloque anidado */ ff 28: double y = 7.654921; /* alcance de Bloque 2 */ a funeion_1 (1; 2 printt(*Dentro del bloque anidado:\n x-¥d, yo¥F\n", x, ¥Ii aa} 24: return @; as} Después de crear y ejecutar el archivo 14162. exe en mi méquina, se desplegaron los ientes resultados en la pantalla: Desde la functon rea, yo 204867 Dentro del bloque main: xed921, y=t 234567 Desde 1a funcién x21284, y=1.234567 Dentro del bloque wea321, ys7.650821 dada: Como puede ver en el listado 14.2, en las lineas 4 y 5 se declaran dos variables globales, x y y, con un alcance de programa, En las lineas 7 a 10 se declara la funcidin denominada funcion_1(). (En la siguiente hora verd mas detalles acerca de la declaracién y prototipos de funciones.) La fun- cion_1{) contiene s6lo una instruceidn; ésta imprime los valores que contienen tanto x como y. Debido a que no se hace una declaracién de variables para x 0 y dentro del blogue de la funcidn, se usan los valores de las variables glabales x y y para la ins- truccién que esti dentro de la funcién. Para demostrar esto, se llama dos veces a fun- cion_1() en las lineas 16 y 21, respectivamente, desde dos blaques anidadas, Los resultados muestran que los valores de las variables globales x y y se pasan a la funcién printf () que esté dentro del cuerpo de la funcién funcion_1() Después, la linea 14 declara otra variable entera, x, con un alcance de bloque, la cual puede reemplazar a la variable global x que esta dentro de! bloque de Ia funcidn main () El resultado de la instruccién de Ia linea 17 muestra que el valor de x corresponde al Alcance y clases de almacenamiento. 227) 1+ La instruccién goto */ return 8; d Aqui, la etiqueta inicio es visible desde el principio hasta el final de la funcién main(). Por lo tanto, no debe haber mis de una etiqueta con el mismo nombre dentro de la fun- cin main(), Alcance de programa Se dice que una variable tiene alcance de programa cuando se declara fuera de una fun- cidn, Por ejemplo, abserve el siguiente eddigo; int x = @; J* aleance de programa */ float y = 0 /* aleance de programa */ int main(} 1 ant 4; /* aeance ae bloque */ return 0; ) Aqui, la variable x de tip int y la variable y de tipo feat tienen un aleance de programa. Las variables con aleance de programa también se conocen como variables global cuales son visibles entre todos los archives fuente que conforman un programa ¢je- cutable. Observe que se declara una variable global fuera de una funcién. E] programa del listado 14,2 muestra la relaciGn entre variables con alcance de programa y variables con alcance de blague. Listavo 14.2 La relacién entre alcance de programa y alcance de bloque /* t4L02.c: Aleance de programa en conparacién con alcance de bloque */ #include int x = 1284; I" aleance de prograna */ double ¥ = 1.284567; /* alcance de programa */ ons [226 Hora 14 iso, j= @ Dentra del bloque externo: i=32 La finalidad del programa del listado 14.1 es mostrarle los diferentes alcances de variables de bioques anidados. Como puede ver, en el listado hay das blo- ques anidados. La variable entera i que se declara en la linea 6 es visible dentro del bloque extema encerrado entre las llaves ({ y }) de las lineas $y 19. Otras des variables enteras, iy j, se declaran en la Linea 11 y son visibles sélo dentro del bloque interno que estd en las Ifneas 10 a 16. Aunque ia variable entera i del bloque exteno tiene ef mismo nombre que una de las variables enteras del bloque interno, no se pueden acceder ambas variables al mismo tiempo debido a sus diferentes alcances, Para demostrar ¢0, la linea 8 imprime por primera vez el valor contenido por i (32) dentro del bloque extemo. Luego, el ciclo for de las Incas 14 y 15 despliega 10 pares de valores asignados a las variables 4 y j que estin dentro del bloque interno. En este punto, no hay ningdin indicio de que:la variable entera 1 del bloque extemno tenga algiin efecta sobre la del bloque interno. Cuando se sale del bloque interno, sus variables ya no son accesibles. En otras palabras, cualquier intento de acceder a j desde el bloque externo seria ilegal. Por ditimo, la instruceién de la linea 17 imprime de nuevo el valor de la variable + del bloque externo para determinar si cambié el valor debido a la variable entera 4 del bbloque interno. Los resultados muestran que estas dos variables se ocultan una de la otra, y no acurre ningin conflieto. Alcance de funcién El alcance de funcién indica que una. variable estd activa y es hasia el final de una funcién En C, s6lo una etiqueta de goto tiene alcance de funcién. Por ejemplo, Ia etiqueta inicio de goto que se muestra en el siguiente e6digo tiene un alcance de funcién: int main() { int 4; /* allcance de bleque */ ble desde el principio inicie: —/* Una etiqueta de goto tiene alcance de funcién */ Alcance y clases de almacenamiento: 225) return 0; } Por lo regular, una variable con alcance de bloque se conace camo variable local. Observe: que las variables lucales se deben declarar al principio del bloque, antes que otras instrucciones, Alcance de bloque anidado ‘También puede declarar variables dentro de un bloque anidado, Cuando una variable que se declara en cl bloque externo tiene el mismo nombre que una de las variables del blo- que interno, la variable que estd dentro del bloque intemo oculta a Ia que estd dentro del bloque externo. Esto se cumple para el alcance del Bloque interno. E] listado 14.1 muestra un ejemplo de alcances de variables en bloques anidados. Listapa 14.1. impresién de variables con diferentes niveles de alcance /* 14L81.c: Aleanes lanidados */ finclude fen blogu maint) int i= 32; /* alcance de bloque 1*/ printf(*Dentro del bloque externa: istd\n*, 4) { _ #* principio del bloque interna */ int i, J; /* aleance de Dloque 2, int 4 oculta a int 4 externo */ printf (‘Dentro del blaque interno: \n*); for (1*@, dent0: itr, f--) printt("i=kad, j-¥adin", i, § } /* final del bloque interno */ printt(*Dentro del bloque externa: i=kd\n", 1}; return @; Después de crear y ejécutar él archivo 14101 .exe del programa del listado 14.1, se desplegaron en Ia pantalla los siguientes resultados: Dentro del bloque externo: ixs2 ELITE centro del bloque interno: i= a, j=10 iia io 2, je 8 l 224 Hora 14 * El especificador auto + El especificador static + El especificador register + El especificador extern + El modificador const + El modificador volatile Cémo ocultar datos Para resolver en la prictica un problema complejo, el programador por lo regular divide el problema en piezas més pequefias y maneja cada pieza del problema escribiendo una ‘0 dos funciones (0 rutinas). Luego conjunta todas las funciones para formar un programa ‘completo que pueda emplear para resolver el problema complejo. En el programa completo podria haber variables que tengan que ser compartidas por todas Jas funciones, Por otra parte, el uso de algunas otras variables podria estar limitado a s6lo ciertas funciones. Es decir, la visibilidad de dichas variables es limitada, y los va~ lores que tienen asignados estén ocultos a muchas funciones. Es muy til limitar el alcance de las variables cuando varios programadores estén traba~ Jando sobre diferentes piezas del mismo programa. Si limitan el alcance de sus variables 1 sus piezas de cédigo, no tienen que preocuparse por conflictos con variables del mismo nombre utilizadas por otros en partes distintas del programa, En C, usted puede declarar una variable e indicar su nivel de visibilidad designando su aleance, De esta manera, s6lo se puede acceder @ las variables con alcance local dentro del blogue en el que se declaran. Las siguientes secciones le ensefian cémo declarar variables con diferentes aleances. Alcance de bloque En esta seccién, un bloque se refiere a todo conjunto de instrucciones encerradas entre Haves ({ y }). Una variable declarada dentro de un bloque tiene un alcance de bloque. Asi, la variable esté activa y accesible desde el punto de su declaracién hasta el final del bloque. En ocasiones, el alcance de bloque se conoce también como alcance lacal, Por ejemplo, In variable i declarada dentro de! bloque de la siguiente funcién main tiene un aleance de bloque: int main() { int i; /* allcance de bloque */ = = = —. HorA 1 4 Alcance y clases de almacenamiento Nadie posee nada, y todo lo que cualguiera tiene es el uso de sus presuntas posesiones —P. Wylie En las horas anteriores aprendié c6mo declarar variables de diferentes tipos de datos, asf como a inicializar y utilizar dichas variables, Se ha asumido ‘que puede acceder a las variables desde cualquier parte. Ahora, la pregunta es: (Puede declarar variables que sean accesibles s6lo a ciertas porciones de un programa? En esta lecci6n aprender acerca del alcance y de las clases de almacenamiento de datos de C. Los temas principales que trata esta lec- cin son los siguientes: + Aleance de bloque + Aleance de funcidn + Aleance de archivo + Alcance de programa Cadenas 221 Taller Para consolidar la comprensién de La leccién de esta hora, le recomiendo responder el ‘cucstionario y terminar los ¢jercicios de este taller antes de pasar a la siguiente I 7 ‘Las respuestas y sugerencias se presentan en el apéndice B, “Respuestas a los cuestiona- Tios y ejercicios™. Cuestionario 1. ;Qué instrucciones son legales en la siguiemte lista? char cadenat[5] = "Texas"; ‘* char cadena2[] = "Una cadena de caracter jar cadena3[2] = "A‘; + char cadena4[2] = "TX"; 2. Dada una variable de apuntador aptr_ch de tipo char, ;son legales las siguientes instrucciones? * taptrch = ta; + aptr_oh = “una eadena de caracteres*; * aptr_oh = 'x * ‘aptr_ch = ‘Es la pregunta 2.°; 3, ;Puede la funcién puts() imprimir el canicter nulo en un arreglo de caracteres? 4, (Qué especificador de formato utiliza con la funcién seanf () para leer una cadena, y cual para leer un ndimero de punto flotante? Ejercicios 1. Dado un arreglo de caracteres en la siguiente instruccidn, char cadenai{] = “este es el ejercicio 1. escriba un programa que copie la cadena cadena’ a otro arreglo, llamado cadenaz. 2, Eseriba un programa que mida la longitud de una cadena evaluando uno a uno los elementos de un arreglo de caracteres hasta encontrar el carécter nulo, Para probar que obtuvo él resultado correcto, puede usar la funcidn strien() para medir de nuevo ta misma cadena. 3, Reescriba el programa del listado 13.4. Esta vez convierta todos los caracteres que estén en maytisculas a su contraparte en mintisculas. 4. Eseriba un programa que use la funcidn scant() para leer dos enteros intraducidos. por el usuario, sume los dos enteros y Iuego imprima el resultado en la pantalla. [229 Hora 13 + La funcién puts() envia todos los caracteres de una cadena a stdout, excepto el nulo, y agrega un caricter de Iinea nueva en la salida, + Puede leer diferentes elementos de datos con la funcién scant (), utilizando dife- rentes especificadores de formato, En la siguieme leccién aprenderd acerca de los conceptos de aleance y almacenamiento enc, Preguntas y respuestas P ;Qué es una cadena? ;Cémo sabe su longitud R En C, una cadena se almacena en un arreglo de caracteres y se termina con un ca- récter nulo ('\@"). El cardeter nulo indica a las funciones de cadena (como puts() y strepy()) que han Hegado al final de la cadena. La funcién strlen()se puede emplear para medir la longitud de una cadena. Si tiene éxito, la funcién strien() devuclve el nimero total de bytes que ocupa La cadena; sin embargo, no se cuenta ¢l cardcter nulo de la cadena. P_ ;Cusiles son las principales diferencias entre una constante de cadena y una constante de carécter? R_ Una constante de cadena es una serie de caracteres encerrados entre comillas dobles, mientras que una constante de caricter es un solo cardeter entre comillas sencillas El compilador agregard un caricter nulo a la cadena cuando ésta se emplee para inicializar un arreglo. Por lo tanto, se debe reservar un byte adicional para el earde- ter nulo, Por otra parte, una constante de eardcter ocupa slo un byte de memoria y no se almacena en un arreglo, P ;Guarda la funcidn gets() el cardcter de linea nueva del flujo de entrada cestiindar? R No. La funcién gets() sigue leyendo caracteres del flujo de entrada estindar hasta ‘que encuentra un earicter de linea nueva 0 un fin de archivo. En lugar de guardar el caricter de linea nueva, Ia funcién gets<) agrega un caricter nulo a Ia cadena y la almacena en el arreglo al que hace referencia el argumento de la funcidn gets(). P {Qué tipos de datos puede leer Ia funcién scant ()? R_Dependiendo de los especificadores de formato del estilo printf () que pase 2 la funcién, scant () puede Icer varios tipos de datos, como una serie de caractcres, ‘enteros © niimeros de punto flotante, A diferencia de gets(}, scant () detiene In Jectura del elemento de entrada actual (y pasa al siguiente elemento, si lo hay) ‘cuando encuentra un cardcter de espacio, de Ifnea nueva, de tabulador, de tabulador vertical 0 de avance de pagina. Después, la funcién seanf() de la linea 11 lee dos enteros que introduce el usuario y los guarda en las ubicaciones de memoria reservadas para las variables enteras x y y. El operador de direccidin se utiliza para obtener las direcciones de memoria de las variables. La instruccin de la linea 13 lee un mimero de punto flotamte y lo guarda en 2. Observe ‘que se utilizan los especificadores de formato, %a y %f, para especificar las formatos ade- ‘cuados para los mimeros introducidos en las lineas 11 y 13. La linea 15 usa la fancién scant () y el especificador de formato ¥s para leer una serie de caracteres que introduce el usuario, y después guarda los caracteres (mas un cardicter nulo como terminador) dentro del arreglo al que apunta cadena. Aqui no se usa el opera dor de direccién, ya que 1a misma cadena apunta a Ia direcciGn de inicio del arreglo. Para demostrar que la funcién seanf () lee todos los miimeros y caracteres que introdujo ‘el usuario, la funcién printf () de Ia linea 17 despliega en Ia pantalla los contenides de x, ¥, Z ¥ cadena. Los resultados muestran que scanf(} s{ hizo su trabajo. Alge que debe tener presente es que la funcién scanf () no comienza a leer la entrada hasta que se presiona la tecla Entrar. Los datos que se introducen desde el teclado se ‘colocan en un bafer de entrada, Cuando se oprime Entrar, la funcidin scant () busea su ‘entrada en el biifer, Aprenderd més acerea de la entrada y salida con biiferes en la hora 21, “Lectura y escritura de archivos”, Resumen En esta leccién aprendié acerca de las siguientes funciones y conceptos importantes acerca de las cadenas de C: + Una cadena es un arreglo de caracteres con un cardcter nulo que marca el final de la cadena, * Una comstante de cadena es una serie de caracteres encerrados entre comillas dobles. + El compilador de C agrega de manera automética un caracter nulo a una constante de cadena que se us6 para inicializar un arreglo. + No se puede asignar una constante de cadena a un apuntador de tipo char indirec- cionado (con el operador de indireccién). * Lafuncién strien() se puede utilizar para medir la tongitud de una cadena, Esta funcién no cuenta el cardcter nulo. * Es posible copiar una cadena de un arregio a otro, Ilamando a la funcién strepy() dec, * La funcién gets() se puede utilizar para leer una serie de caracteres. Esta funcién, deja de leer cuando encuentra un eardcter de linea nueva o un fin de archivo (EOF). La funcisn agrega un cardcter nulo al final de la cadena. 218 Hora 13 ‘Después de leer la cadena, se agrega en forma automdtica un eardcter nulo al arreglo, ‘Observe que con scant(), a diferencia de print#(), usted debe pasar apuntadores a sus ‘argumentos para que la funciGn seant() pueda modificar sus valores. El programa del listada 13.5 muestra cémo usar varios especificadores de formato con la funcidn scant (), Listapo 13.5 Uso de la funcién scant () con varios especificadores de formato mor 2: a { © 13L05.c: Uso de scanf() */ include ain() char cadenal #0) int x, y5 float 2; printf(*Introduzca dos enteros separados por un espacia:\n"); scant ("ed Sd", ax, by); printf("Introduzca un real (punto flotante) :\n Beant (*¥f*, 82); printf(*Introduzca una cadena: scanf(*¥s", cadena) ; printf ("Usted intradujo:\n"); PrANt(*NS SALONF\AAS IN", x,y, 2, Cadena); return @; negritas) desde mi teclado, se desplegaron en la pantall 131@5.exe, e introducir datos (los cuales aparecen en los siguientes resultados: A Introduzea dos enteros separados por un espacio: LID 12345 Introduzea un real (punto flotante: 1.294567 Introduzea una cade Prueba Usted introdujo: 10 12945 1.284867 Prueba fit En las lineas 6 a 8 del listado 13.5 se declaran un arreglo de tipo int (cadena), dos variables int (x y y) y una variable float (2), respectivamente. Cadenas 217 je1t. En la linea 7 se inicializa la variable delt con el valor de la expre- sidm ‘a* ‘A‘, que es la diferencia entre el valor numérico del caracter a en miniscula y su contraparte en maytscula, En otras palabras, al restar Ia diferencia de ‘a’ y ‘A’ del valor entero: de la mingscula, obtenemos el valor entero de la maydscula. Después, la funcién puts() de Ia linea 18 imprime la cadena con todos los caracteres en maytisculas en stdout, ef cual va a la pantalla de manera predeterminada. La funcién puts() agrega un cardcter de linea nueva cuando encuentra el cardcter nulo al final de 1a cadena. Uso de %s con la funcién printf () Hemos usado la funcidn printf () en muchos programas de ejemplo de este libro, Como: usted sabe, con esta funcidn se pueden utilizar muchos especificadores de formato para indicar diferentes formas de despliegue de los datos de diversos tipos. Por ejemplo, puede usar el especificador de formato de cadena, ‘s, con la funcién printf () para desplegar una cadena de caracteres guardada en un arreglo, (Consulte el ejemplo del listado 13.3.) En la siguiente secci6n se presenta la funcién seanf () como una forma de leer valores de distintos tipos de datos con diferentes especificadores de formato, incluyendo al especificador de formato ss, La funcién scanf() La funcién scanf () proporciona otra forma de leer cadenas desde el flujo de entrada estindar. Es mis, esta funcién se puede utilizar para leer varios tipos de datos de entra- da, Los formatos de los argumentos para la funcién seanf() son muy similares a los que emplea la funcién print (). La sintaxis de la funcién scant () es include int scant (const char *formato,...); ificadores de formato dentro de la cadena de for- ‘Aqui se pueden incluir varios espes MI mato a la que hace referencia la variable de apuntador formato de tipo char. Si la funcidn scant () termina con éxito, devuelve el ntimero de elementos de datos leidos a desde stdin, Si acurre un error, Ia funcidn seanf() devuelve EOF (fin de: archiva), El uso del especificador de formato de cadena ‘ss le indica a la funcién seanf () que con- tinde leyende hasta que encuentre un caricter de espacio, de linea nueva, de tabulador, de tabulador vertical, © de avance de pagina. Los caracteres que lee la funcién scant) se almacenan en el arreglo al que hace referencia el argumento correspondieate. El arreglo debe ser lo suficientemente grande para almacenar los caracteres de entrada. 216 Hora 13 Listapo 13.4 Uso de las funciones gets() y puts() {* 19L04.c: Uso de gets() y puts() */ Winclude = ‘a') && (cadena [i] <= ‘2')) cadena [i] -= delt; /* convierte a mayisculas */ +i; + printe(*La cai puts( cadena }; return na introducida (en maysculas) @s:\n"); Durante la ejecucién del archivo 13104. xe, introduje desde el teclado una I{nea de ca- racteres (abajo en negritas), y obtuve los siguientes caracteres en la pantalla (todos en maydsculas), Intraduzea una cadena que tenga menos de 8@ caracteres: Esto es una pruet La cadena introducida (en maydsculas) es: ESTO ES UNA PRUEBA. El programa del listado 13.4 acepta una cadena de caracteres que se introduce desde cl teclado (es decir, stain), y luego convierte a mayiisculas los caracteres que estén en mindsculas. Por tiltimo, la cadena modificada se muestra en la pantalla. En Ia linea 6 se declara un arreglo de caracteres (cadena) que puede contener hasta 80 caracteres. La funcién gets() de la linea 10 lee los caracteres que introduzce el usuario desde el teclado, hasta que éste oprime Ia tecla Entrar, lo que se interpreta como un caréeter de linea nueva. Los caracteres leidos por la funcién gets() se almacenan en el arreglo de caracteres indicado por cadena. El cardcter de linea nueva no se almacena en cadena. En su lugar, se agrega un caricter nulo al arreglo como terminador. El ciclo white de las lineas 12 a 16 tiene una expresidn condicional, cadena( i}. Dicho ciclo continda iterando mientras cadena{1] se evalie como diferente de cero. Dentro del ciclo, el valor de cada cardcter representado por cadena[ i} se evalia en la linea 13, para determinar si es un carécter en mindscula dentro del rango de la a a la z. Si éste es el aso, se convierte a maydsculas en la linea 14, restando a su valor actual el valor de una Cadenas 215) Pantalla. Observe que el especificador de formato ‘s y la direcciGn de inicio de cadena2 y eadenas se pasan a la Hamada a printf () de las lineas 19 y 20, para que ésta imprima todos los caracteres almacenados en cadena? y cadena3, excepto el caricter nulo. Los resultados que se despliegan en la pantalla muestran que cadena2 y cadena tienen exac- tamente el mismo contenido que c: al, Lectura y escritura de cadenas Ahora nos vamos a concentrar en cémo leer o escribir cadenas con los flujos de entrada ¥ salida estdindar, es decir, stdin y stdout. Hay varias funciones en C que usted puede utilizar para la lectura o escritura de cadenas. Las. subsecciones que siguen presentan algunas de estas funciot Las funciones gets() y puts() La funcién gets() se puede usar para leer caracteres desde el flujo de entrada estandar. La sintaxis de la funcidn gets() es Winelude char *gets(char *s); ‘Aquf, los earacteres que se len del flujo de entrada estindar se almacenan en el arreglo de caracteres identificado por s, Cuando la funciin gets() encuentra un carfecter de linea nueva o de fin de archive (EOF), deja de leer y agrega un cardcter nulo \@ al arreglo. Si la funcién concluye con éxito, devuelve ¢, En caso contrario, a devuelve un apuntador nul, La funcién puts() se puede usar para escribir caracteres en el flujo de salida esténdar (es decir, en stdout). La sintaxis de la funeién puts () es Hinclude int puts(canse char +3); ‘Aqui, s se refiere al arreglo de caracteres que contiene una cadena. La funcién puts() escribe la cadena en stdout. Si la funcidin tiene éxito, devuelve @, En caso contrario, devuelve un valor diferente de cera. La funcién puts() agrega un canicter de linea nueva para reemplazar el carécter nulo a del final del arreglo de caracteres. Las funciones gets() y puts() necesitan el archivo de encabezado stéio.n. Puede ver en el listado 13.4 la aplicacién de las dos funciones. 21. Hora 13 Listapo 13.3 continuacién oe A U1 = "Copia una cadena.*; a: 18; 8: char cadenaa{ 1a 1: int 4; Te 42: /* can st 13: strepy(eadenaz, cadenat); 14: /* sin stropy() *7 15: for (4°03 cagenat {i}; +4) 16: cadena3{i) = cadenati}; 17: cadena3[i] = "8; 18: /* muestra cadena? y cadenas */ 19: prantf(*E1 contenido de cadena? usando strepy: %6\n*, cadena2); a printf (“EL contenido de cadena3 sin usar strepy: ‘sin*, cadenss); 21; return 22: } Después de crear y ejecutar el archivo 13103.exe, se desplegaron los siguientes resultados: Eu El contenido de cadena? usando strepy: Copia una ca EL contenido de cadena3 sin usar strepy: Copia una cadena, Enel listado 13.3 se declaran tres arreglos de tipo char, cadenat, cadena? y cadena’. Ademis, en Ia Linea 7 se inicializa cadena1 con una constante de cadena, “Copia una cadena,*. La instraccién de Ia linea 13 lama a la funcién strepy() para copiar el contenido de cadenat (incluyendo el cardcter nulo que agrega el compilador) al arreglo al que hace referencia cadena2. Las lineas 15 a 17 muestran otra forma de copiar el contenido de cadenat a un arreglo- al que hace referencia cadena3. Para ello, el ciclo tor de las ineas 15 y 16 contindia copiando, uno tras otro, los caracteres de cadena’ a los elementos correspondientes de cadena, hasta que encuentra el cardcter nulo que agrega cl compilador. Cuando esto sucede, se evalia como @ la expresién cadenat [i] que se usa como la condicién de la instrucciGn for de la linea 15, lo cual finaliza el ciclo, Debido a que el ciclo for no copia el canicter nulo de cadena’ a cadenad, la instruccién de la linea 17 agrega un caricter nulo al arreglo al que hace referencia cadena, En C, es muy importante asegurarse de que cualquier arreglo que se utilice para almacenar una cadena tenga un caricter nulo al final de la misma. Para demostrar que la constante de carécter a que hace referencia cadenat se copié con éxito a cadena2 y a cadena3, el contenido de cadena? y cadena3 sc despliega cn la Cadenas 213 | 17: return 0; 18: } ‘Obtuve los siguientes resultados al ejecutar el archivo 13Le2.exe del programa de! lis- tado 13.2, La longitud de La longitud de cadena2 es La longitud de la cadena asignada a aptr_cadena es de: 36 bytes FERRIES Eon tees 70 cet aad 15.2 se dectran einai doe aegis do char, cadenat y cadena2, y una variable de apuntador, aptr_cadena, respectivamente. LLuego, Ia instruccién de la linea 13 obtiene la longitud de Ia cadena cadenat, ¢ imprime el resultado. Puede ver en dicho resultado que la funcién strlen() no cuenta el cardcter nulo (\®) que esté al final de cadenat. En las Iineas 14 a 16 se miden y se muestran en la pantalla las longitudes de las constan- tes de cadena a las que hacen referencia cadena2 y aptr_cadena. Las resultados indican que la funcién strien() tampoco cuenta los caracteres nulos que agrega el compilador a Jas dos constantes de cadena, ‘Cémo copiar cadenas con strepy() ‘Si desea copiar una cadena de un arreglo a otro, puede copiar cada elemento del primer arreglo al elemento correspondiente del segundo, o puede simplemente Lamar a la funciéin de C stropy() para que haga el trabajo por usted. ‘La sintaxis de la funcidn strepy() es Hinelude shar *stropy(char ‘dest, const char *orig); Aqui, e! contenido de la cadena orig se copia al arreglo al que hace referencia vest. Si el copiado se realiza con éxito, la funcién strepy() devuelve el valor de orig. Debe incluir en su programa el archivo de encabezado string. antes de llamar a a Ja funcién strepy(). El programa de! listado 13,3 muestra eémo copiar una cadena de un arreglo a otro, ya sea. Tamando a Ia funckin strepy() 0 haciéndolo usted mismo. Listapo 13.3 Cémo copiar cadenas J 19L03.c: Gbno copiar cadenas */ include include Saees smain() contin 212 Hora 13 de cadena, Cuando se encuentra el caricter nulo agregado a la cadena, *aptr_cadena se evahia como @, lo cual hace que se detenga la iteracién del ciclo for, La expresién *aptr_cadenare de la linea 24 mueve el apuntador al siguiente caricter de la cadena despuds de extraer el cardcter actual al que hace referencia el apuntador, En la hora 16, Uso de apuntadores”, aprender mis acerca de la aritmética de los apuntadores, gCuanto mide una cadena? En ocasiones, usted necesita saber cudntos bytes ocupa una cadena, ya que su longitud puede ser menor a la de su arreglo de tipo enar. En C, puede utilizar una funcién Ia- mada strlen() para medig la longitud de una cadena. La funcién strien() Veamos la sintaxis de la funcién strien(). La sintaxis de la funcién strlen() es #include size_t strlen(const char *s); ‘Aqui, § es una variable de apuntador de tipo char. El valor de retomno de la funcidn ¥ es el ndmero de bytes de la cadena, sin contar el cardeter nulo '\@'. size_t es un tipo de datos definido en el archivo de encabezado string.h. El tamafio del tipo de datos depende del sistema de eémputo en particular. Observe que debe incluir a string. n en su programa antes de poder lamar a la funcién strlen). El listado 13.2 proporciona un ejemplo del uso de la funciGn strien() para medir la longitud de cadenas. Listapo 13.2 Cémo medir longitudes de cadenas * 13L02.0: Céno medir longitudes de cadenas */ Winclude nain(} { char cadenat{} = {°U s ' te, ane . a char cadena2(] = *Otra ‘constante de cadena char *aptr cadena = "Asigna una constante a un apuntador: printf(*La longitud de cadenai es de: ‘%d bytesin*, strlen{cadenat}); Printf(*La longitud de cadena? es de: Sd bytesin’, strlen(cadens2) }; Printf(*La longitud de la cadena asignada a aptr_cadena es de: %d bytes\n*, strlen (aptr_cadena) }; garsnsetsreseses Cadenas 211) printf(*\n* /* imprine cadena? */ for (i=@; cadena2{i}; it+) prantf("sc*, cadena2{i]); printf(*\n"); /* asigna una cadena a un apuntador */ aptr_cadena = "Asigna una cadena a un apuntador.\n*; for (i=0; *aptr_cadena; i++) prant#("’c*,”*apte_ return 8; 1 Después de crear y ejecutar el archivo 13L01 .exe del programa del listado 13.1, se desplegaron los siguientes resultados. Una constante de cadena 10. Otra constante Ge cadena Asigna una cadena a un apuntador. ‘Como puede ver en ¢! listado 13.1, en las Iineas 6 a 9 se declaran ¢ inicializan dos arreglos de caracteres, cadena! y cadenaz, En Ia declaracién de cadenat se usa un conjunto de constantes de cardcter, incluyendo un caréeter nulo, para inicializar el arreglo, En la linea 9 se asigna una constante de cadena al arreglo cadena2. El compi- lador agregar un caricter nulo a cadena?. Observe que tanto cadena! como cadenaz se declaran como arreglos sin especificacién de tamafio, para los cuales el compilador determinaré en forma automética cudnta memoria se necesita. La instruccién de la linea 10 declara una variable de apuntador de tipo char, aptr_cadens. rr El ciclo for de las lineas 14 y 15 imprime entonces todos los clementos de cadenat, Debido a que el dltimo elemento contiene un carcter nulo (18) que s¢ evalita como 0, cadenat [4] se usa como la expresién condicional del ciclo for. La expresién cade- nati] s¢ evalda como diferente de cero para cada elemento de cadena! excepto para el que contiene el caricter nulo. Después de la ejecucién del ciclo for, se muestra en Ia pantalla Ia cadena Una constante de ca De |a misma forma, el ciclo for de las lineas 18 y 19 muestra la constante de cadena asignada a cadena2 imprimiendo en la pantalla cada elemento del arreglo. La expresién cadena2[ i] se evalia en la instruccién for, debido a que el compilador agrega un ca- ricter nulo al arreglo, El ciclo for detiene su iteracién cuando cadena2{ i} se evala como ®, Para ese entonces, el contenido de la constante de cadena, Otra constante de cadena, ya se desplegé en la pantalla, La instruccidn de la linea 22 asigna una constame de cadena, "Asigna una cadena a un apuntador.", a la variable de apuntador de tipo char, aptr_eadena, Aqui también se usa un ciclo for para imprimir la constante de cadena, el cual despliega en la pantalla cada carcter de la cadena (vea las lineas 23 y 24). Observe que se usa el operador de indireccién *aptr_cadena para hacer referencia a uno de los caracteres de la constante [219 Hora 13 char ch = "x char cadena[ se reserva un byte para la variable de cardcter ch, y se asignan dos bytes para el arreglo de caracteres cadena. La razén por la que se necesita un byte adicional para cadens ex que el compilador tiene que agregar un cardcter nulo al arreglo. Otra cosa importante es que debido a que la cadena es un arreglo, en realidad es un apuntador de tipo char. Por lo tanto, usted puede asignar directamente una cadena de caracteres a una variable de apuntador, de la siguiente manera: char *aptr_cadena; aptr_eacena = ‘una cadena de caracteres.*; Sin embargo, no puede asignar una constante de carécter a la variable de apuntador, coma se muestra a continuacién: aptreadena = 'x'; /* Es incorrecto. */ En otras palabras, la constante de carécter *x' contiene un valor derecho, y la variable de apuntador aptr_cadena espera un valor izquierdo. Pero C requiere el mismo tipo de valores a ambos lados del operador de Es vélido asignar una constante de cardcter a un apuntador de tipo char indireccionado, de la siguiente manera: char *aptr_caden: *aptr_cadena = 'x'; Ahora los valores que estéin a ambos lados del operador = son del mismo tipo. El programa del listado 13.1 muestra c6mo inicializar, o asignar, arreglos de caracteres con constantes de cadena, Listapo 13.1 Inicializacién de cadenas i* 19L01.c: Inieializacién de cadenas */ include main() { char cadenai{] = {'U", ‘n", ‘ey "a", ‘sty ga oe at char cadenad{] = "otra constante de cadena”; shar *aptr_caden int a3 J* imprine cadenal */ for (iO; cadenat(il; i++) printf("ke", cadenai il); Cadenas 209) El compilador agregard en forma automdtica un cardcter nulo (\@) al final de * iHolat*, yy tratard al arreglo de caracteres como una cadena de caracteres. Observe que el tamaiio ‘del arreglo se especifica para contener hasta siete elementos, aunque la constante de: cadena s6lo tiene seis caracteres encerrados entre comillas dobles, El espacio extra se reserva para el cardcter nulo que agregar el compilador. Si desea que el compilador calcule el nimero total de elementos del arreglo, puede declarar un arreglo de caracteres sin especificar su tamaiio, es decir, sin dimensionarlo, Por ejemplo, la siguiente instruccidn char cadena|] = “Me gusta C.*; inicializa con una constante de cadena el arreglo de caracteres cadena, sin especificar el tamaio, Mas adelante, cuando el compilador vea la instruccién, determinaré el espacio total de memoria necesario para contener la constante de cadena, més un cardcter nulo ‘que agrega el compilador mismo. Si lo desea, puede también declarar un apuntador de tipo enar y luego inicializarlo con una constante de cadena, La siguiente instruccisn es un ejemplo: char “aptr_eadena = ‘Yo aprende C por mi cuenta No especifique muy reducido ¢l tamaio de un arregio de caracteres. De ha- cerlo asi, dste no podré contener una constante de caracteres més un cardcter nulo adicional. Por ejemplo, la siguiente declaracion se considera ilegal: char cadena[5] = "texto"; Observe que muchos compiladores de Co emiticin un mensaje de adver: tencia o de error sobre esta declaracién incorrecta. Los errores en tiempo de ejecucién que podrian surgir a la larga como resultada, podrian ser muy difi- ciles de depurar. Por lo tanto, es su responsabilidad asegurarse de especificar espacio suficiente para una cadena. La siguiente instrucci6n es correcta, ya que especifica el tamafio del arreglo de caracteres cadena lo suficientemente grande para contener la constante de caracteres mis el cardécter nulo adicional: char cadena[6] = "texto"; Constantes de cadena en comparacién con constantes de caracter Como ya sabe, una constante de cadena es una serie de: caracteres encerrados entre co- millas dobles (* *). Por otra parte, una constante de cardcter es un caricter encerrado Hora 13 Declaraci6n de cadenas Esta seccién le ensefia cmo declarar e inicializar cadenas, asf como la diferencia entre constantes de cadena y constantes de carécter. Revisemos primero la definicién de una cadena, Qué es una cadena Como vimos en la hora 12, “Arregios”, una cadena es un arreglo de caracteres, en el cual sé utiliza un cardcter nulo (\@) para marcar el final de la cadena. (La longitud de uuna cadena puede ser mds corta que su arreglo de caracteres.) Por ejemplo, el arreglo de caracteres, arreglo_ch, declarado en la siguiente instruccién es considerado como una cadena de caracteres: char arreglo ch[7] = {*I', ‘HY, "o', “L's a, "H's 0s En C, el cardcter nulo se emplea para marcar el final de una cadena, y siempre se evaltia como @. C trata al (8 como un carécter. Cada carécter de una cadena ocupa sélo I byte. Una serie de caracteres encerrados entre comillas dobles ("*) se llama constante de cadena. El compilador de C agregard en forma automatica un cardcter nulo (\@) al final de una constante de cadena, para indicar el fin de Ia cadena, Por ejemplo, la cadena de caracteres “Una cadena de caracteres." se considera una constante de cadena, lo mismo que "IHola!". Inicializaci6n de cadenas Como vimos en la Jeccién anterior, un arreglo de caracteres se puede declarar ¢ inicializar de la siguiente manera: char arr_cadena[6] = { as ts Aqui, el arreglo arr_cadena es tratado como un arreglo de caracieres. Sin embargo, si le agrega un caricter nulo (\8) al arreglo, puede tener Ia siguiente instruccién: char are_eadena[7} = 1", "WH", "0", "1", "8°, Aqui, el arreglo arr_cadena se amplia para contener siete elementes; él ditimo elemento es un carécter nulo. Ahora, el arreglo de caracteres arr_cadena es considerado una cadena de caracteres debido al cardcter nulo que se agregé al final También puede inicializar un arreglo de caracteres con una constante de cadena, en lugar de una lista de constantes de caricter. Por ejemplo, la siguiente instruceién inicializa un arreglo-de caracteres, cadena, con una constante de cadena, * HO char cadena[7} = *iHol: — — = — —_ Hora 1 3 Cadenas Hice esta carta mds larga que de costumbre, porque me falté tiempo para shacerl mds breve. —B, Pascal En la hora anierior aprendié a usar arreglos para reunir variables del mismo ‘tipo, También aprendié que una cadena de caracteres es en realidad un arre~ glo de caracteres, con un cardeter nulo \@ qué marca el final de la cadena. En esta leccién aprenderd mis acerca de cadenas y funciones de C que se pueden utilizar para manipularlas. Asf pues, trataremas los siguientes temas + Declaracién de una cadena * La Jongitud de una cadena + Como copiar cadenas * Lectura de cadenas con scant() * Las funciones gets() y puts() Arreglos 205 3. (Cudntas dimensiones tienen los siguientes arreglos? * char arreglot(3] [18]; * int arreglo2{}; * float arreglo3(](81(1615 * char arreglos(|(01; 4, {Qué esté mal en la #1 char lista_ch{ A, Ejercicios 1, Dado el arreglo de caractere: char arreglo_ch(S} = {'A‘, “B’, “G’, “D*, “E‘by escriba un programa que despliegue en la pantalla cada elemento del arreglo. . Reescriba el programa del ejercicio 1, pero esta vez utilice un ciclo for que inicia- lice el arreglo de caracteres con ‘a‘, 'b', ‘c', ‘d® y ‘e', imprima después el valor de cada elemento del arreglo. . Dado el siguiente arreglo bidimensional sin especificacién del tamafio de la primera dimensin: char Lista_enii(21 = { 4 ‘ay escriba un programa que mida el total de bytes que ocupa el arreglo, y que imprima después todos los elementos del mismo. 4. Reescriba el programa del listado 12.5. Esta vez ponga en la pantalla la cadena de caracteres iMe gusta ¢! Dado él siguiente arregl double Lista_datos(6] = 5.12345}; utilice las dos formas equivalentes que vimos en esta lecciGn para medir el espacio total de memoria que ocupa el arreglo, y despliegue los resultados en la pantalla. Hora 12 Cuil es el indice minimo en un arreglo? R EnC, el indice minimo de un arreglo de una sola dimensién es 0, e! cual marca el primer elemento del arreglo. Por ejemplo, dado el arreglo entero int arreglo_ent [8]; el primer elemento del arreglo es arreglo_ent(@} De la misma manera, el indice minimo de cada dimensién de un arreglo multii- mensional comienza en 0. .Cémo hace referencia a un arreglo usando un apuntador? R Puede emplear un apuntador para hacer referencia a un arreglo, asignindole al apun- tador la direccién de inicio del arreglo, Por ejemplo, dada una variable de apuntador aptr_ch y un arreglo de caracteres arreglo_ch, puede usar una de las siguientes instrucciones para hacer referencia al arreglo mediante el apuntador: aptr_ch = arreglo_ch; o bien, aptr_ch = Sarreglo_chf) P {Qué hace el cardcter nulo’ R_ En C, el cardcter nulo ('\@") se puede utilizar para marcar el final de una cadena. Por ejemplo, Ia funcién printf () continéa poniendo en la pantalla el siguiente cardcter hasta que encuentra ¢l cardcter nulo, Ademés, el caricter nulo siempre s¢ evaliia, como un valor de cero. Taller Para consolidar la comprensién de la leccién de esta hora, le recomiendo responder el cuestionario y terminar los ejercicios de este taller antes de pasar a la siguiente leccién. Las respuestas y sugerencias se presentan en el apéndice B, “Respuestas a los cuestiona- rios y ejercicios”. Cuestionario 1. {Qué hace la siguiente instruccién’? int arreglo_ent(4] = {12, 23, 9, 56}; 2. Dado el arreglo int datos{3}, ;qué estd mal en la siguiente i datos(1}] = 1; datos[2] = 2; datos(3] = 3; Arreglos 203 (Si el tamafio de int es diferente en su méquina, podria obtener valores diferentes a los del tamaio del arreglo Lista_ent del programa del listado 12.7.) Resumen En esta leccién aprendi¢ los siguientes conceptos importantes acerca de los arreglos en C: *+ Un arreglo es una coleccisn de variables que son del mismo tipo de datos. + En, el indice para un arreglo comienza en 0, + Puede inicializar cada elemento de un arreglo después de declararlo, o puede poner todos los valores iniciales, separados por comas, dentro de un bloque de datos encerrado entre Haves ({ y }) durante la declaraciGn de un arreglo, *+ El espacio de memoria que ocupa un arreglo esté determinado por la multiplicacién del tamafio del tipe de datos por las dimensiones de! arreglo, Se dice que un apuntador hace referencia a un arreglo cuando la direccién del primer elemento del arreglo se asigna al apuntador. L.a direccién del primer elemento de un arreglo también se conoce como direccidn de inicio del arreglo. Para asignar la direccidn de inicio de un arreglo a un apuntador, puede poner la combinacién del operador de direccién (8) y el nombre del primer elemento del arreglo, o simplemente usar el nombre del arreglo a la derecha del operador de asignacién (=). + El caricter mulo ('\0*} marca el final de wna cadena, Las funciones de C, como printf (), detendrin el procesamiento de la cadena al encontrar el carécter nulo, también maneja arreglos multidimensionales. Un par de corchetes vacio (el ape- rador de subindices de arreglo, I y 1) indica una dimensin, El compilador puede calcular en forma automitiea el espacio de memoria nece- sario para un arregio sin especificacién de tamaiio, En la siguiente leccién aprenderd mis acerca de las cadenas de C. Preguntas y respuestas P ;Por qué necesita usar los arreglos? R. En muchos casos necesita declarar un conjunto de variables que son del mismo tipo de datos. En lugar de declarar cada variable por separado, puede declararlas todas en forma colectiva en el formato de un arreglo, Se puede acceder a cada variable, como un elemento del arreglo, ya sea a través de una referencia al elemento del arreglo, © por medio de un apuntador que haga referencia al arreglo. 202 Hora 12 Listapo 12.7 Inicializacion de arreglos sin especificacién de tamafto i* 12L07.e: Inicializacién de arreglos sin especificacién oe tamafo"/ Hinclude nain() 4 int dos_din(3](5] = (1 , 20, 30, 100, 200, 30, 400, 500}; int i, i; for (is; 163; it+)4 printt(*\n"); for (JO; j<5; J++) printt("8d", dos_dim(i{j1); print (“40 return @; ‘Obtuve los siguientes resultados al ejecutar el archive 12L06.exe: 1 2 2 4 5 a 38 0 58 ee Arreglos. 199) En las lineas 6 a 9 del listado 12.5 se declara un arreglo de caracteres, arreglo_ch, ¥ se inicializa con los caracteres de la cadena i¢ es muy potente! (incluyendo los caracteres de espacios). Observe que el tltimo elemento del arreglo contiene el cardcter nulo ('1@*), el eual es necesario para terminar la cadena, El cielo for de las lineas 12 y 13 imprime cada uno de los elementos del arreglo arregio_ch para mostrar en la pantalla la.cadena 1 es muy potente! Por consiguiente, cn la primera expresidn de la instruccién for se inicializa a @ la variable entera i, la cual se usa como indice del arreglo. Después se evaltia Ia expresidn condicional arreglo_eh{ i). Si la expresién se evaltia como diferente de cera, el cicla for realiza una iteracién; en caso contrario, el ciclo se detiene, Comenzando con el primer elemento del arreglo, Ia expresiGn arregio_ch(] continiia produciendo un valor diferente de cero hasta que encuentra el carécter nulo. Por lo tanto, el ciclo for puede desplegar en la pantalla todos los caracteres del arreglo, y ‘dejar de imprimir justo después de que Ia expresién arreglo_ch{] produce un valor de cero, al encontrar el carécter nulo. Arreglos multidimensionales Hasta ahora, todos los arreglos que ha visto han sido arreglos de una sola dimensién, en Jos que los tamafios de las dimensiones se colocan entre corchetes ({ y ])- Ademds de los arreglos de una sola dimensién, el lenguaje C también maneja arreglos multidimensionales. Puede declarar arreglos con tantas dimensiones como permita su compilador, La forma general de declarar un arreglo de N’ dimensiones es ‘tipa_de_datos Nonbre-arreglo [Tamafo-arregiot] [Tamale arregion; rregioz]. . . [Tamato- en donde puede ser cualquier entero positivo, Debido a que el atreglo de dos dimensiones, el cual es muy utilizado, es la forma més simple de arreglo multidimensional, en esta seccién nos. concentraremos en los arreglos de dos dimensiones. Sin embargo, puede aplicar en arreglos de mis de dos dimensiones toda lo que aprenda en esta seccidn. Por ejemplo, la siguiente instrucei6n declara un arreglo bidimensional entero: ant arreglo_ent(2}(3); Aqui, los das pares de corchetes representan las dos dimensiones con un tamaiia de 2 y 3 elementos enteros, respectivamente. Puede inicializar el arreglo bidimensional arreglo_ent de la siguiente manera: 198 Hora 12 Quiza se pregunte edmo sabe la funcidn printf() dénde estd el final del arreglo de. ca- racteres, {Recuerda que el Gitimo elemento del arreglo de caracteres arreglo_ch es un carécter ‘ \@'*? Es este cardcter nulo el que marca el fin de la cadena. Como ya mencioné, en C, a una secuencia de caracteres contiguos que termina con un caricter nulo se le Hama cadena de caracteres. Nosotros no le indicamos a printf () cudntos caracteres hay en el arreglo, por lo que el especificador de formato 's le indica que siga imprimiendo carac- teres hasta encontrar un cardcter nulo, tal como hicimos nosotros en el primer métado. El caracter nulo ('\e') En C, al cardcter nulo ('\@") se le trata como a un canicter; éste-es un cariicter especial que marca el final de una cadena. Por lo tanto, cuando funciones come printf () actiian sobre una cadena de caracteres, procesan un cardcter tras otro hasta encontrar el carécter nulo, (En la hora 13 aprenderé mas acerca de las cadenas.) El caricter nulo ('\@'), el cual siempre se evalda a un valor de cero, también se puede usar para una prueba légica en una instruccién de control de flujo. El listado 12.5 mues- tra un ejemplo de cémo usar el cardcter nulo en un ciclo for. Aisstagy Listano 12.5 Terminacién de la salida en el caracter nulo (* 12L05.c: Detener en el caracter nula */ include nain() { char arreglo_ehi 19] = {1 y . et ant a; J* arreghe_ch{i] en prueba ldgica */ for ( ylo_eh{il; it*) printf(*ke", arreglo ch{i)); prantf(*\n*); return Al gjecutarel archivo 12105. exe obtuve el siguiente resultado: Ea ie es muy potente! Arreglos 197) Jt=-_ método IT —-*7 printf ( "\qluntar todos 10s printf( "es\n*, arreglo_ch); jementes (Método IT):1n"); return @; Cuando ejecuté el archivo 12L04.exe se desplegaron los siguientes resultados: arreglo_ci arreglo_ch[1] arreglo_ch[ 4] arreglo_chi5] arreglo_ch[6] vuntar todas los iolat Juntar todos los elenentos (Método 11): tHolal Como puede ver en el listado 12.4, en la Ifnea 6 se declara e inicializa un areglo de caracteres, arreglo_ch. Cada uno de los elementos del arreglo se imprime por medio de la llamada a printf () del ciclo for que se muestra en las lineas 9 y 10; En el arreglo hay un total de siete elementos, los cuales contienen las siguientes constantes de Hay dos formas de desplegar este arreglo: mostrar todos los caracteres en forma individual, 0 tratarlos como una cadena de caracteres. Las lineas 12 a 14 muestran la primera forma, arregio._ch{ 4}, Ia cual extrae cada elemen- to de manera consecutiva en un ciclo, ¢ imprime un carécter junto al atro por medio del ‘especificador de formato %¢ que esti.en la Hamada a printt () de la linea 14, Como mencioné ames, siempre que trate con un arreglo de caracteres, el cardcter nulo *\@" sefiala el final de la cadena (aunque podria no ser el final del arreglo), Es una buena idea estar pendiente del caricter nulo para que sepa cu‘indo dejar de imprimir; por lo tanto, Ia expresién condicional de la linea 13 terminaré el ciclo for si el elemento actual -es un canicier nulo, La segunda forma es més sencilla, Simplemente le tiene que indicar a la funcién print?) un arreglo de caracteres nain() { char arreglo ch[?] = {'1', ant 45 “a 1 hy for (120; ix7y ee) printf (‘arraglo_ch{%d] contiene: So\n", 4, arregle_ch[i]); [tere método T+ printf( ‘“duntar todos los elenentos (uétodo 1):\n"); for (1-0; arrepio_cn(i] 1= “\e° Bd i<7; ite) 4 printf(*he", arregle chlil); gongs erassene Arreglos 195 | apuntador, Si se hace referencia a un arregio mediante un apuntador, se puede acceder a Jos elementos del arreglo con ayuda de! apuntader, Por ejemplo, las siguientes instrucciones declaran un apuntador y un arreglo, y asignan la direecién del primer elemento a la variable de apuntador: char tapte es char Lista e[ 10); aptr_e = Lista Debido a que la direccin del primer elemento del arreglo Lista_e es la direceién de inicio del arreglo, en realidad la variable de apuntador aptr_c ahora esté haciendo referencia al arreglo a través de su direccidn inicial, El listado 12,3 muestra cémo hacer referencia a.un arreglo con un apuntador, Listapo 12.3 Cémo hacer referencia a un arreglo con un apuntador I* $2L@3.c: Cémo hacer referencia @ un arreglo con un apuntador */ include main) t int taptr_int; int Lista_ent( 10); int 4 for (is@; i 2 4; main) s: 4 6: int 4; 7 int Lista_ent1 10) & 9: tor (180; ic10; ie)4 18: Lista_ent[i] © 4+ 1; Mt prantf( "Listaent('d] se inicializa con %d.in*, i, 1ista_ent(il); 1: } 13: return 8; tad {190 Hora 12 Qué es un arreglo Ahora sabe cémo declarar una variable con un tipo de datos especifico, como. char, int float 0 double. En muchos casos es necesario declarar un conjunto de variables que tengan el mismo tipo de datos. En lugar de hacerlo en forma individual, C le permite declarar como un arreglo a un conjunto de variables del mismo tipo de datos. Un arregio es un conjunto de variables que son del mismo tipo de datos, A cada parte de un arreglo se le denomina elemento, Todos los elementos de un arreglo se referencian con el mismo nombre del areglo y se almacenan en un conjunto de posiciones consecu- tivas de memoria, Declaracién de arreglos La forma general para declarar un arreglo es la siguiente: tipo_de_datos Nombre-arreglo [Tamario-arreglo); Aqui, tip0_de_datos es el especificador de tipo que indica de qué tipo de datos serd el arreglo declarado, Nombre -arregio es el nombre. del arreglo declarado. Tanario-arreglo define cudintos elementos puede contener el arreglo. Observe que en la declaracién de un arreglo se requieren los corchetes ([ y ]). Este par de carchetes ([ y }) se conoce como el operador de subindices del arreglo. For ejemplo, en la siguiente instruccién se declara un arreglo de enteros, int arreglo_ent[s] en donde int especifica el tipo de datos del arreglo cuyo nombre es arreglo_ant. El tamaiio del arreglo es 8, lo que significa que puede almacenar ocho clementos (en este caso, enteros). En C, debe declarar un arreglo de manera explicita, antes de poder utilizarlo, come lo hace con otras variables. Indexacién de arreglos Después de declarar un arreglo, puede acceder por separado a cada uno de sus elementos. Por ejemplo, la siguiente es una declaracién de un arreglo de caracteres: char dial]; Puede acceder a los elementos del arreglo dia une tras otro. Para ello, debe utilizar el nombre del arreglo en una expresiGn, seguido de un miimero, llamado indice, encerrado entre corchetes. Lo que es importante que recuerde es que en C todos los arreglos se indexan comenzan- do en 0. En otras palabras, el indice del primer elemento del arreglo es @, no 1. Por lo tanto, el primer elemento del arreglo dia es dia{0}. Debido a que hay 7 elementos en el arreglo, el dltimo elemento es dia(6], no ¢ia[7}. HORA 1 2 Arreglos Recoged los pedazos que han sobrado, para que no se pierda nada. Juan 6:12 En Ja hora anterior aprendi6 acerca de los apuntadores y del concepto de indireccién, En esta leccidn aprenderd acerca de los arreglos, que son co- lecciones de elementos de datos 8 y estin estrechamente relaciona dos con los apuntadores. Los temas principales que se abordan en esta leceién som los siguientes: ‘Arreglos de una sola dimensién Indexacién de arreglos ‘Apuntadores y arregios ‘Arreglos de caracteres Arregios multidimensionales Arreglos sin dimensionar 188 Hora 11 Taller Para consolidar la comprensién de la leccién de esta hora, le recomiendo responder el cuestionario y terminar los ejercicios de este taller antes de pasar a la siguiente leccién. Las respuestas y sugerencias se presentan en el apéndice B, “Respuestas a los cuestiona- tios y ejercicios”. Cuestionario 1, ¢Cémo puede obtener el valor izquierdo de una variable de tipo carécter ch? 2, jCuiles asteriscos (+) son operadores de indireccién y cudles son operadores de multiplicacién en las siguientes expresiones? te onty ey text ety tees 3, Dado que x = 10, Ia direccidn de x es @x1A38, y aptr_int = &, ,qué producirin aptr_int y *aptr_int, respectivamente? {Qué comtiene x six = 123. aptr_int = &x después de Ia ejecucidn de *aptr_int = 456? * Ejercicios 1. Dadas tres variables enteras, x = 512, y = 1024y z = 2048, escriba un programa que imprima los valores izquierdos y derechos de dichas variables. Escriba un programa que actualice el valor de la variable f1t_num de tipo double, de 123,45 2543.21, por medio de un apuntador double. 3. Dada una variable de tipo cardeter oh, y eh = ‘A’, escriba un programa que actua- lice el valor de ch al decimal 68 por medio de un apuntador. 4. Dado que x°8 y y~6, eseriba un programa que multiplique los dos enteros e imprima cl resultado, ef cual se guarda en x, todo esto en forma de indireccidn (es decir, usando apuntadores). x Apuntadores 187 + Puede actualizar el valor de una variable a In que hace referencia una variable de apuntador. + Varios apuntadores pueden apuntar a la misma ubicacién de una variable en la memoria, En el resto del libro veré mis ejemplos del uso de apuntadores. En la siguiente leccién aprenderd acerca de un tipo agregado, un arreglo, que esti rela- cionado estrechamente con los apuntadores de C, Preguntas y respuestas P {Qué son los valores izquierde y derecho? R_ El valor izquierdo es la direccién de una variable, y el valor derecho es el conte- nido de Ia variable almacenado en la memoria. Hay dos formas de obtener el valor derecho de una variable: usar directamente el nombre de la variable, o usar el valor izquierdo de ésta y el operador de inditeccién para referirse al lugar en que reside él valor derecho. A la segunda forma se le Hama también forma indirecta. {.Cémo puede obtener la direccién de una variable? R. Utilizando el operador de direccién, &. Por ejemplo, dada una variable entera x, la expresiin &x se evalia como la direccién de x. Para imprimir la direccicin de x, puede emplear el especificador de formato ‘p en la funcién printf (). iQué es el concepto de indireccién en términos del uso de apuntadores? R. Antes de esta hora, la Gnica forma que usted conocia para leer o escribir en una variable era invocarla directamente. Por ejemplo, si queria escribir un decimal 16 enna variable entera x, podtia usar ta instruccién x = 16; ‘Como aprendié en esta hora, C le permite acceder de otra forma a una variable, utilizande apuntadores. Por lo tanta, para escribir 16 en x, puede declarar primero un apuntador entero (aptr) y asignarle el valor izquierdo (direccidin) de x, es decir, aptr = &x;, Luego, en lugar de ejecutar la instruccién x = 16;, puede emplear otra instruceién: sapte = 16; " ~ ‘Aqui, el apuntador *aptr bace referencia a la ubicacién de memoria reservada por x, y cl contenido almacenado en la ubicacién de memoria se actualiza a 16 después de ejecutar la instruceién. De moda que, como ve, usar apuntadores para acceder las ubicaciones de memoria de variables es una forma de indireccién, P ;Puede un apuntador nule apuntar a datos ylides? No, Un apuntador nulo no puede apuntar # datos vilidos. Esto se debe a que el var lor contenido por un apuntador nulo se establece a 8. Mas adelante veri ejemplos del uso de apuntadores nulos en arreglos, cadenas y asignacién de memoria. [186 Hora 11 La linea 1 asigna cl valor izquierdo de x a la variable de apuntador aptr_1 para que se pueda utilizar a aptr_t para hacer referencia al valor derecho de x, Para aseguramos de que la variable de apuntador aptr_1 ya contengs la direccién de x, la linew 12 impri- me el valor derecho de aptr_1, junto con su valor izquierdo. Los resultados muestran que aptr_t si contiene la direccién de x, 01638, Después, la linea 13 imprime el valor 1234, que es al que hace referencia la expresién *aptr_1. Observe que el asterisco * de esta expresin es el operador de indireccién. Lu expresin *aptr_2 = & de Ia linea 14 asigna el valor izquierda de x a otra variable de apuntador, aptr_2: es decir, ahora la variable de apuntador aptr_2 est enlazada a la di- reccién de x. La instruccién de la linea 16 muestra en la pantalla el entero 1234 mediante el operador de indireceién * y su operando, aptr_2. En otras palabras, el segundo apun- tador *aptr_2 hace referencia a la ubicacién de memoria de x En Ia linea 17 se le asigna ¢l valor derecho de aptr_1 a la variable de apuntador aptr_3. Debido a que aptr_{ contiene ahora la direccién de x, la expresién aptr_3 = aptr_t equivale a aptr_3 = &x, Entonces, en los resultados producidos por las instrucciones de las lineas 18 y 19, usted ve de nuevo en la pantalla el entero 1234. Esta vez, el tercer apuntador, aptr_3, hace referencia al entero. Resumen En esta Ieceidn aprendié los siguientes conceptos importantes acerca de los apuntadores en: + Un apuntador es una variable cuye valor apunta a otra variable. Una variable declarada en C tiene dos valores: el valor izquierdo y el valor derecho. + El valor izquierdo de una variable es la direceién; el valor derecho es el contenido de la variable. + El operador de direccién (8) se puede usar para abtener el valor izquierdo (direc- cin) de una variable. En una declaracién de apuntador, el asterisco (+) le indica al compilador que la variable es tna variable de apuntador. El operador de indireccién (*) es un operador unario; como tal, sélo-requiere de un operando. + La expresion *nom_apuntador se evalda como cl valor al que apunta la variable de apuntador nom_apuntador, en donde nom_apuntador puede ser cualquier nombre: de variable valido de C. + Si'se le asigna cl valor @ al valor derecho de una varlable de apuntador, entonces el apuntador es nulo, Un apuntador nulo no puede apuntar a datos validos. Apuntadores 185 tipo char, apte_ct = &e y apte_c2 = &c establecen que las dos variables de apuntador apunten a la misma ubicacién de memoria, i El programa del listado 11.4 muestra otro ejemplo de cémo apuntar a lo mismo-con | varios apuntadores. Listapo 11.4 Cémo apuntar a la misma ubicacién de memoria nasa (* 11U04.c: Cémo apuntar a la mist winclude ubicacién */ nain() 4 int x; int *aptr_t, *aptr_2, taptr_9; | w= 1234; printf ("*: direceiéa-kp, contenido=tdin", &x, x); aptr_t = ax; print? (“aptr_1: diraccién=4p, contenido=tpin*, ptt, aptr_ip; printfi**apte_t => Adin", *aptr_i); aptr2 = bx; printt(*aptr_2: direccién-sp, contenide-sp\n", Aaptr_2, aptr_2); prantfi**apte 2 => Adin", *aptr_2); aptr_9 = aptrt printf (*aptr_3: ‘direccién=tp, contenida=tp\n printr("*aptr_3 => d\n", *aptr 3); return 5 faptr_s, aptr_3); AL ejecutar el archivo 11Le4.exe en mi méquina, se desplegaron en la pantalla los siguien- tes resultados (dependiendo de su sistema, usted podria obtener diferentes valores de direcciones): x: direecidnnex1893, contenida=t254 dntr_ts sireceidneectea4, eontenigo-@1 1838 saptr_t => 1234 ite 2: direccidnOx1836, contenido=Bx 1838 ote_2 => 1254 aptr_3: strecciéneexi8s2, contentdo~ent638 saptr_3 => 1234 Como se muestra en el listado 11.4, la linea 6 declara una variable entera, x, y la linea 7 declara tres variables de apuntador enteras, aptr_i, aptr_2 y aptr_3. La instruccién de la linea 10 imprime los valores izquiendo y derecho de x. En mi méquina, el valor izquierdo (direccién) de x es @x1838. El valor derecho (contenido) de x es 1234, inea 9, que es el valor inicial asignado a xen 184 Hora 11 Listapo 11.3 _continuacién 18: printf (**aptr_c => Selo", taptr_ch; 16: printf ("e: direccién=¥p, contenido=sc\n 17: return 6; 18: Después de ejecutar el archivo 11L03.exe en mi méquina, obtuve los siguientes resulta- dos desplegados en la pantalla: c: direccién=@x1824, contenido=A aptr_e: direccién=@x1826, contenido=0x1828 *aptr_c => A aptr_€: direcién=@x1826, contenido=0x1828 saptr_c =? B ¢: direceién=@x1824, contenido=B En la linea 6 del listado 11.3 se declaran una variable de tipo char, c, y una variable de apuntador del mismo tipa, aptr_c. EEE En Ia linea $ se inicializa ta variable c con * por Ia funcién print#() de la linea 9. ja cual es impresa junto con su direecién En la linea 10 se le asigna a la variable de apuntador aptr_c el valor izquierdo (direc de c, No es una sorpresa ver en la salida impresa por las instrucciones de las lineas 11 y 12 que el valor derecho de aptr_c es el valor izquierdo de ¢, y que el apuntador *aptr_c ‘apunta al valor derecho de ¢. La expresién *aptr_c = B’ de la linea 13 pide a la computadora que escriba ‘8' en Ia ubicaci6n a la que apunta él apuntador aptr_e. El resultado que imprime la instruccién de |a Iinew 15 demuestra que el contenido de Ia ubicacién de memoria a Ia que apunta aptr_e se actualiza. La instruccién de 1a linea 14 imprime los valores izquierdo y derecho de la variable de apuntador apte_c y muestra que estas valores permanecen iguales. Co- mo usted sabe, la ubicacién a la que apunta aptr_c es en donde reside la variable de carfeter c. Por Io tanto, la expresidn *aptr_e = '8* en realidad actualiza el contenido {es decir, el valor derecho) de la variable ¢ en '8' Para demostrarlo, la instruccién de la linea 16 despliega en la pantalla los valores izquierdo y derecho de o, El resultado mues- tra que, en efecto, se modificé el valor derecho de c. Cémo apuntar a la misma ubicaci6n de memoria Es posible apuntar # una ubicacién de memoria por medio de mds de un apuntador: Por ejemplo, dado que € = ‘A* y que aptr_et y aptr_c2 son dos variables de apuntador de Apuntadores: 183 Apuntadores nulos Se dice que un apuntador es nul cuando su valor derecho es @. Recuerde, un apuntador nulo nunca puede apuntar a datos vilidos. Por esta razén, puede: verificar un apuntador pa- ra ver si tiene asignado @: si es asf, usted sabe que se trata de un apuntador nulo y que no es vilido. Para establecer tin apuntador nulo, simplemente asigne @ a la variable de apuntador. Por ejemplo: char *aptr_o; int *aptr_int; aptr_e = aptr_int Aqui, aptr_¢ y aptr_int se convierten en apuntadores nulos después de asignaries l valor entero @. Mis adelante verd aplicaciones de los apuntadores nulos utilizados en instrucciones de control de flujo y en arreglos. Actualizacion de variables por medio de apuntadores Come aprendié en ta seccién anterior, puede obtener el valor de una variable utilizande una variable de apuntador, siempre y cuando enlace la variable con dicha variable de apuntador, En otras palabras, puede leer el valor apuntando a la ubicacién de memoria de 1a variable y utilizando el operador de indireccién, Esta seccién le muestra que puede escribir un nuevo valor en la ubicacién de memoria de una variable empleando un apuntador que contenga el valor izquierdo de dicha variable. El listado 11.3 presenta un ejemplo. Listapo 11.3 Modificacién de valores de variables por medio de apuntadores (* 11L03.0: Modificacién de valores por medio de apuntadores: Hinclude nain{) d char c, *aptr_a; cecay pranté("e: direcciéneyp, contenido-sc\n', &, ©); aptric = Bc; printf (*aptr_c: direccién-sp, contenido-p\n", Saptr_e, aptr_c); printf (**aptr_¢c => ‘c\n", *aptr_c); sapte_c = ‘8 printf (*aptr_c: direcciénssp, contenido=Ap\n*, Saptr_e, aptr_c); contin 182 Hora 11 tama tts La imagen de memoria Se een Toye enece ee a ec =) El operador de indireccién (*) Usted ha visto el asterisco (*) en la declaracién de un apuntador. En C, el asterisco se llama operador de indireccién cuando se usa como operador unario. (En ocasiones también se le llama operador de desreferenciacién). Se puede hacer referencia al valor de una variable mediante la combinacién del operador * y su operando, ¢l cual contiene la direc- cién de la variable. Por ejemplo, en el programa que se muestra en el listado 11.2, después de asignar la diree- cin de la variable de carécter ¢ 2 Ia variable de apuntador aptr_c, la expresin *aptr_e ‘hace referencia al valor contenido por ¢. Por lo tanto, para obtener él valor de ¢ puede usar Ja expresin *aptr_e, en vez de usar directamente la variable c. ‘De la misma manera, dada una variable cntera x y siendo x = 1234, pucde, por ejemplo, declarar una variable de apuntador entera, aptr_x, y asignarle el valor izquierdo (direc- cin) de x, es decir, aptr_x = ax. Entonces, la expresidn *apte_x produce 1294, que es el valor derecho (contenido) de x. No confunda el operador de indireceién con el eperador de multiplicaci aunque ambos compartan el misma simbolo, * El operadar de indireccién es un operador unario que toma sélo un operando. Diche operando contiene la direccién (es decir, el valor Izquierdo) de una variable. Por otra parte, el operador de multiplicacidin es un operador binario que necesita des operandos para realizar la operacién de multiplicacién. El significado del simbola * lo determina el contexte en el que lo-utilice. Apuntadores 181) Después de cjecutar en mi maquina el archivo 11L82.exe, obtuve los siguientes resulta- dos desplegados en Ia pantalla: cr direccisn=Ox1898, contenido=A xz direceién=0x1836, contenido=7 ys direcci6n=Ox1832, contenido=123.45 Aptr_c: direccidn=x1830, contenido=0x1838 saptrc => A aptr_x: direccidn=* saptr_x => 7 aptr_y: direccién=®x1B2C, contenido=0x1B92 sapth_y => 123.45 N82E, contenido=0x1896 Enel listado 11.2, hay tres variables ¢, x y y, y tres variables de apuntador, aptr_e, aptr_x y aptr_y, declaradas en las Ifneas 6 a 8, respectivamente. LLas instrucciones de las Iineas 10 a 12 inicializan las variables c, x y y. Después, las Iineas 13a 15 imprimen las direcciones y los contenidos de las tres variables. En la linea 16 se asigna el valor izquierdo de la variable de cardcter v a la variable de apuntador aptr_c. La salida que genera la instruccién de la linea 17 muestra que la variable de apuntador aptr_c contiene la direcci6n de c, En otras palabras, el contenido (es decir, el valor derecho) de aptr_c es la direccién (es decir, el valor izquierda) de c, LLuego, en la linea 18 se imprime el valor al que hace referencia el apuntadar *aptr_c. Los resultados demuestran que el apuntador *aptr_c sf apunta a In ubicacién de memoria de ¢. La linea 19 asigna el valor izquierdo de la variable de tipo entero x a la variable de ‘apuntador entera aptr_x. Las instrucciones de las lineas 20 y 21 imprimen los valores Izquierdo y derecho de Ia. variable de apuntador aptr_x, asf como el valor al que hace referencia el apuntadar *aptr_x. Asimismo, en Ia linea 22 se asigna el valor izquierdo de la variable y de tipo float a la variable de apuntador aptr_y de tipo float, Para demostrar que aptr_y contiene la di- reccién de y, y que “aptr_y da el contenido de y, las Iineas 23 y 24 imprimen los valores derechos de aptr_y y *aptr_y, respectivamente. Las instrucciones de las lineas 16, 19 y 22 le muestran cémo asignar el valor de una variable a otra, en una forma indirecta. En otras palabras, el valor izquierdo de una varia: ble se puede asignar a otra variable, para que la segunda se pueda usar como una variable de apuntador para obtener el valor derecho de la primera, En este caso, el nombre de la variable y el apuntador hacen referencia a la misma ubicacién de memoria. De acuerdo con esto, si en una expresién se usa el nombre de la variable © el apuntador para modi- Ficar el contenido de la ubicacidn de memaria, también cambia para el otro el contenido de la ubieaciéin de memoria. Para ayudarle a entender la indireceién de la asignacién de valores, la figura 11,1 muestra la imagen de memoria de las relaciones entre ¢ y aptr_c, x y aptr_x, asi como entre y y aptr_y, con base en fos resultados obtenidos en mi méquina. 180, Hora 11 La forma general de la declaracién de un apuntador es tipo_de_datos *nombre_del_apuntador; Aqui, tipo_de_datos especifica el tipo de datos al que apunta el apuntador, nomore_del_apuntader es el nombre de la variable de apuntador, el cual puede ser cualquier nombre valida de variable en C. Observe que justo antes del nombre del apuntador hay un asteriseo *, lo que indica que Ja variable es un apuntador, Cuando el compilador ve un asterisco en ta dectaracién, toma nota de que la variable se puede usar como un apuntador, A continuacién se muestran diferentes tipos de apuntadores: char *aptr_c; /* declara un apuntador a un caracter */ int ‘aptr_int; /* declara un apuntader @ un entero */ float “aptr_flt; /* declara un apuntador a un punto flotente */ El programa del listado 11.2 muestra cémo declarar apuntadores y cémo asignarles valores. EESEEE Listapo 11.2 Como declarar apuntadores y cémo asignarles valores _ {+ 11U92.e: Géno declarar apuntaderes y céno asignaries valores */ #include nain() « char cy int x, float y, Gireccién=¥o, contenidotc\n", Bc, chi Gireccién=Ap, contenidorsdin", 8x, x); Gireccién=%p, contenide-s5.2f\n*, Ay, y’ aptr_o = Aci printf ("aptr_e: direccién=kp, contenido=%p\n", Baptr_c, aptr_ch; printf("*apth_e => So\n", *aptr_c); aptr_x = 8x} printf(“aptr_x: direccién=4p, contenide-tp\n", kaptr_x, aptr_x); printt(**aptr_x => d\n", ‘aptr_x); aptr_y = Ay; Printt("aptr_y: direccién=p, contenidossp\n*, Aaptr_y, aptr_y); printf (**aptr_y => %6.2f\n", *aptry); return @; Apuntadores 4 El estindar ANSI maneja el especificador de formato %p-utilizade en la. fun: La instniceién de a linea 10 despliega en la pantalla 1a direccién (el valor izquierdo) y el contenido (el valor derecho) de la variable de candcter ¢. Aqui, la expresién &c produce Ia direcciéin de c. Observe que en la funcién printt {) de la linen 10 se utiliza el especificador de formato ‘%p para desplegar la direccién producida por &. De la misma manera, las lineas 11 y 12 imprimen las direcciones de x y y, asf come su contenido, Puede ver en la primera parte de los resultados que las direcciones de ¢, xy y Som BxXTAF4, OX1AF2 y OxtAF6. Mi computadora imprimié estas direcciones en formato hexadecimal, Sin embargo, el especificador de formato %p no garantiza la impresiGn de direcciones en formato hexadecimal, sino s6lo la conversién de las direociones a una secuiencia de caracteres imprimibles. Debe consultar el manual de su compilador de C para ver qué formate esperar. Debido a que estas tres variables ain no han sido iniciali- zadas. el contenido de sus ubicaciones de memoria corresponde a lo que habia ahi como resultado de la tiltima escritura de memoria, Sin embargo, después de 1a inicializaciGn que se leva a cabo en las lineas 13 a 15, los espacios de memoria reservados para las tres variables contienen ahora fos valores ini- ciales. Las lineas 16 a 18 despliegan las direcciones y contenidos de c, x y y después de Puede ver en la segunda parte de los resultados que los contenidos de ¢, x y y ahora son “AS, Ty 128.45, respectivamente, con las mismas direcciones de memoria. Gidn print (). Si por algan mative su compilador no maneja *p, puede intentar utilizar wu oM1u en la funcién printf {) para convertir & imprimic un valor izquierdo (es decir, una diraccin}, demas, cbtuve las direeciones impresas por los ejempins de esta leccion al -ejecutar los ejemplos en mi maquina. Les valores podrian variar al ejecutar los ejemplos en su maquina. Esto se debe a que la direcci6n de una variable puede variar de un tipo de computadora a otro. Declaracién de apuntadores Como mencioné al principio de esta leccién, un apuntador es una variable, lo que signi- fica que un apuntador también tiene un valor izquierdo y un valor derecho. Sin embargo, ambos valores son direcciones. El valor izquierda de un apuntador se usa para hacer referencia al apuntador mismo, mientras que el valor derecho, que es su contenido, es la direceién de otra variable. [78 Hora 11 El listado 11.1 muestra otro ejemplo de Ia obtencién de direcciones (es decir, valores. izquierdos) de variables. ye vier. Winelude nain() char; direccitn=%p, direccién=%p, direccién=%p, direccién=*p, direccién=*p, direccisn=’p, Listavo 11.1 Obtencién de los valores izquierdos de variables Obtencién de direcciones */ eontenido-%e\n", de, 0); contenido-din", x, x); eontenido=%5.2f\n", ay, ¥ contenido-®cin", Be, ©); contenido =4d\n", Bx, x contenido=ss.2t\n", Sy, ¥); Después de crear y ejecutar en mi computadora el archivo 11101. exe, se exhibieron los siguientes resultados en la pantalla: direcci6n-@x1AF4, direccibn=Ox1AF2, direccién=Ox1AF6, direccibn=Ox1AF4, direceién=Ox1AF2, 1: direccién=Ox1AFé, xy y, respectivamente. Usted podria obtener un resultado diferente, dependiendo de su compu tadora y sistema operative y, en especial, de la situacidn de la memoria de su computadera al momento de ejecutar e! programa, contenidoe contenido= -32557 contenido=A contenido? contenido= 123.45 Como puede ver en el listado 11,1, en las lineas 6 a 8 se declaran las variables c, Apuntadores 177 Luego, cuando se le asigna un valor a Ja variable, éste se almacena como contenido en Ia ubicaciGn reservada de memoria. El contenido también se conoce valor derecho de Ja variable. Por ejemplo, después de declarar la variable entera x y asignarle un valor como el siguiente int x; x97} a variable x tiene ahora dos valores: cel valor izquierdo: 1900 el valor derecho: 7 Aqui, el valor izquierdo, 1980, ¢5 la direccién de la ubicacién de memoria reservada para x. El valor derecho, 7, es el contenido almacenado en esa ubicacién de memoria. Observe que, dependiendo de las computadoras y los sistemas operativos, el valor izquierdo de x puede ser diferemte de una miquina a ota. Puede imaginar que Ia variable x es e! buzdn de su casa, Ia cual tiene la direccidn (normal- ‘mente el nimero de la calle) 106@, Imagine que el valor derecho, 7, es una carta entregada en el buzdn, (Observe que cuando se esté compilando su programa dé C y se esti asignando un valor una Variable, el compilador de C tiene que verificar el valor izquierdo de la variable. Si el compilsdor no puede encontrar el valor izquierdo, emitiré un mensaje de error que dive que la variable es una variable indefinida en su programa. Es por ello que en C tiene que declarar una variable antes de poder utilizarla, (Imagine a un cartero quejéndase de que no puede depositar las eartas dirigidas a usted porque todavia no tiene un buz6n.) Utilizando el valor izquierdo de una variable, el compilader de C puede localizar con facilidad el almacenamiento adecuado de memoria reservado para una vatiable, y luego escribir o leer el valor derecho de la variable El operador de direccién (&) El lenguaje C también le proporciona un operador, &, que puede utilizar en caso de que desee saber el valor izquierdo de una variable. Este operador se llama operador de direc- cidn debido a que se evaliia como la direocidn (es decir, el valor izquierdo) de una variable. Por ejemplo, el siguiente e6digo Long int x; long int *y; y= ax; asigna la direceién de la variable x de tipo long int a la variable de apuntador y. (Mas adelante en este capitulo abundaremos sobre esto y sobre el significado de *y.) 176, Hora 11 Qué es un apuntador Entender los apuntadores es vital para ser un eficaz, programador en C. Hasta ahora, sélo ha tratade directamente con variables, asignindoles valores, Esta hora le presenta un auevo concepto conocido como indireccidn En lugar de asignar los valores en forma directa a las variables, puede manipular indirec- tamente una variable creando otra denominada apuntador, la cual contiene la direccién de memoria de otra variable. Pero, {por qué es tan importante esto? Para los principiantes, utilizar la direcci6n de memoria de sus datos es a menudo la forma mds répida y simple de acceder a ellos. Hay muchas cosas que sin los apuntadores son dificiles, si no es que imposibles, de realizar, como la asignacidin dindmica de memoria, la transferencia de grandes estructuras de datos entre funciones, ¢ incluso hablar con el hardware de su computadora. De hecho ya usé un apuntador en la hora 1 de este libra, “El primer paso”, ;Recuerda la cadena ‘Wola, amigo. Este es mi primer programa de C.\n"? Una cadena es en realidad un arreglo, el cual es, por si mismo, una elase especial de apuntador, Mis adelante le presentaré mis acerca de los arreglos, la asignacién de memoria y las cosas maravillosas que puede hacer con los apuntadores. Por ahora, el primer paso es entender qué es un apuntador y cémo trabajar con uno en sus programas, A partir de la definicién de un apuntador, usted sabe dos cosas: primera, que un apuntador es una variable, asf que puede asignar diferentes valores a una variable: de apuntador, y segunda, que el valor contenido en un apuntador debe ser una direccién que indique la ubicacién de otra variable en. la memoria. Es por ello. que un apuntador también se conoce como variable de direccién. Direccién (valor izquierdo) contra contenido (valor derecho) Como quiz4 sepa, la memoria de su computadora se usa para contener el cédigo binario de su programa, el cual consta de instrucciones y datos, asf como el cédigo binario del sistema operative de su maquina. Cada ubicacién de memoria debe tener una direccién dnica para que la computadora pueda leer o escribir en ella sin ninguna confusién, Esto es parecido al concepta de que ‘cada casa de una ciudad debe tener una direceidn nica, ‘Cuando se declara una variable, se reserva para ella una parte de memoria no utilizada, y Ja direccién tnica de la memoria se asocia al nombre de la variable. La direccién asociada con el nombre de la variable se conoce normalmente como valor izguierdo de la variable Hora 1 1 Apuntadores Los deberes del apuntador fueron sefalar, lamando por sus nombres, a aquellos en la congregacién que debfan tomar nota de alguna idea expuesta en el sermén. —H. B, Otis, Simple Truth En las dltimas 10 horas ha aprendido acerca de tipos de datos, operadores, funciones y ciclos de C, todos ellos muy importantes. En esta lecciGn apren- deri acerca de una de las caracterfsticas mis importantes y poderosas de C: Jos apuntadores, Los temas que trataremos en esta hora son los siguientes: + Variables de apuntador * Direcciones de memoria *+ El concepto de indireccién Declaracidn de un apuntador El operador de direecisin El operador de indireccién En las siguientes horas se mostrariin més ejemplos de Ia aplicacién de tos apuntadores. en especial en la hora 16, “Uso de apuntadores”. ‘Obraz chroniony prawem autorskim Material chroniony prawem autorskim Re . S — — = — al Parte Ill Apuntadores y arreglos Hora 11 Apuntadores 12 Arreglos 13. Cadenas 14 Alcance y clases de almacenamiento 3. Igual que en la pregunta 2, usando x = 4,y = 2, y operador = ‘-', ,cudl es el valor final de x después de ejecutar la siguiente instrucciGn switch? switch (operador){ 4, {Cul es el valor de la variable entera x después de ejecutar el siguiente cddigo? nea; for (iB; ist®; ive}{ if (G83 == continue: wae 4 , Ejercicios Reescriba el programa del listado 10.1. Esta vez utilice la expresiGn logica 88 == @ en la instruccién if. 2. Reescriba el programa del listade 10.1 utilizando instrucciones if anidadas. 3, Escriba un programa que lea caracteres de la E/S estdndar, Si los caracteres son A, 8.y C, despliegue sus valores numéricos en la pantalla (se necesita la instruccién switch). Escriba un programa que siga leyendo caracteres de la entrada estindar hasta que se introduzca el carécter 9. Reescriba el programa del listado 10,7. Esta vez, en vez de saltar el 3 y el 5, salte el entero que se pueda dividir entre 2 y entre 3. Control de flujo del programa iy Taller programa ramifica al bloque de instrucciones que estén bajo la palabra reservada else y regresa a su pista original después de ejecutar las instrucciones que con- ola else, En otras palabras, la instucciGn if permite ejecutar 0 saltar por com- pleto un sole bloque de instrucciones, mientras que la instruccidn if-else ejecuta uno de los dos bloques de instrucciones que estén bajo su control, {Por qué necesito agregar la instruccién break dentro de la instruccién switch? ‘Cuando se selecciona uno de los casos que estin dentro de la instruccién switch, -el control del programa lo ramificard y ejecutard todas las instrucciones del caso seleccionado y las de los casos que le siguen. Por lo tanto, podria obtener mis resultados de los esperados. Para indicarle a la computadora que silo ejecute las instrucciones de un caso seleccionado, puede poner una insirucci6n break al final del caso para que el control de flujo del programa salga de la estructura de switch después de ejecutar las instracciones contenidas en el caso {Qué hace la instruccién continue dentro de un ciclo? Cuando se ejecuta Ia instruccién continue dentro de un ciclo, el control del progra- mma saita al final del ciclo para que se pueda ejecutar la instruccién while o for que tiene el control y comenzar otra iteracién si ain se cumple la expresién condicio- nal. Dentro del ciclo, se saltarin todas las instrucciones que sigan a la instruceién continue cada vez que se ejecute dicha instruccién. Para consolidar la. comprensiGn de la leccidn de esta hora, le recomiendo responder el ‘cuestionaria y terminar los ejercicios de este taller antes de pasar a la siguiente lecciGn, Las respuestas y sugerencias se presentan en el apéndice B, “Respuestas a los cuestiona Tios y ejercicios”. Cuestionario Dada x = 0, {se realizarén las operaciones aritméticas contenidas én la siguiente instruccion if? af (x 1 8) y= 128 / x + 4865; Dadas x = 4,y = 2y operador = *-", ;euél es el valor final de x después de ejecutar la siguiente instruccién. switen? switen (operader){ case ‘+ case * [170 Hora 10 Resumen En esta leccién aprendid las siguientes instrucciones y palabras reservadas de ci ramificacién condicional importantes de C: + Una tarea importante de un programa es instruir a la computadora para que salte a diferentes partes del c6digo de acuerdo con las condiciones de ramificacién es ficadas. + La instruccién if es muy importante en C para la bifurcacién condi 10s y nal, * La instruccién if se puede anidar para formar en su programa una serie de decisio- nes relacionadas. + La instruccidn if-else es una ampliacién de la instruccién if, * La instrucci6n switch le ayuda a mantener mds legible su programa cuando hay en su c6digo mis de dos decisiones relacionadas que tomar. + La palabra reservada case, seguida de dos puntos y un valor constante integral, se usa como etiqueta en la instruccién switch. La etiqueta default: se usa al final de luna instruceién switch cuando ningtin caso corresponde a la condicién. + La instruccién break se puede emplear para salir de la estructura de un switch o de un cicle (por lo regular de un ciclo infinito). + La instruccién continue le permite permanecer dentro de un ciclo saltando al mismo tiempo algunas instrucciones, * La instruccién goto le permitiré a la computadora saltar a otro punto en su cddigo: No se recomienda el uso de esta instruccién, ya que podria hacer que su programa sea dificil de depurar y poco confiable. En la siguiente leccién aprendera acerca de un concepto muy importante, los apuntadores. Preguntas y respuestas P {Cudntas expresiones hay en la instruccién if? R La instruccién if toma sdlo una expresién que contiene el criterio condicional. Las instrucciones que controla la instruccién if se ejecutan cuando la expresiGn se evalia como diferente de cero (es decir, cuando se cumplen las condiciones). En caso con- trario se saltan estas instrucciones y se ejecuta la instruccién que sigue al bloque controlado por if. P {Por qué la instruccién if-else es una ampliacién de la instruccién if? R. Cuando la expresién condicional de la instruccién if se evalia como cero, el control de flujo del programa regresa a la pista original. Sin embargo, cuando la expresién, condicional de la instruccién if-else se evaliia como cero, el control de flujo del Control de flujo del programa 169) La siguiente es Ia forma general de la instruccién goto: noabreariquet instruceiént; instruccién2; goto nombreetiqueta; Aqui, nombreetiqueta es un nombre de etiqueta que le indica a la insteuccién goto a ‘dénde saltar. Debe colocar el nomoreetiqueta en dos lugares: uno es donde la instruecién goto saltard (observe que se deben poner dos punto después del nombre de la etiqueta), y el otro lugar es después de Ia palabra reservada goto La etiqueta a la que salta la instruceién goto puede aparecer antes 0 después de dicha instruccién. Una de las mejores cosas que tiene C es que favorece la programacién estruc- turada, Los programas deben actuar de manera predecible y su comporta- miento debe ser razonablemente obvio tan sélo con leer el cédiga fuente. Por supuesta, otra de las mejores caracteristicas de Ces que no exige este mo- delo de perfeccién. Depende de usted, e! programador, usar las herramientas que se le dan para escribir un cédigo estructurado, claro, elegante y legible En este capitulo vimos tas instrucciones break, continue y goto. El use inadk ccuado de estas intrucciones de ramificacién puede conducir a lo que se co- nioce como “cédigo espagueti”, (Si imprime el cédigo fuente y dibuja lineas, en la pagina para indicar el flujo de ejecucién, terminaré con un dibujo del espagueti) Cuando la ejecuci6n de un programa saita por ahi de manera impredecible, es muy dificil (a menudo imposible, en un proyecto extenso y complejo} determinar la intencién 9 el comportamiento real de un programa, 1 uso de instruceiones goto puede conducir con facilidad al cédigo espague- 1i, 67 especial si se usa para Salter hacia atrés, 0 hacia fuera de instrucciones de control de flujo, Cuando vea uns etiqueta al azar que simplemente est puesta en e| cédigo, s6lo sabré que algiin otro cédigo saltaré abi por medio de una instruccion gote, no sabré cuinde o por qué, sin tener que detenerse ‘a examinar el resto de la funcién. Los efectos de Ia instruccién cant inue estan, por fo: menos, limitados a la instruccion de ciclo en que se usan, Sin embargo, las ciclos complejos pueden ser dificiles-de descifrar, a menos que conozca exactamente cuando y porqué terminara el ciclo Lo mismo se puede decir de break. Ademas de las instrucciones switch, se puede utilizar para saltar fuera de los ciclos for, while © da-while. En ge- eral, esto solo debe hacerse para interrumpir un cicia infinito. En caso con {rario, utilice su propia expresion condicional para terminar el ciclo. 168 Hora 10 Listano 10.7 continuacién suma += 4; + printf(*La suna de 1, 2, 4, return y Tes; Sdin®, uma); Después de ejecutar en mi computadora el archivo 1107 .exe, se muestra el siguiente resultado en Ia pantalla: La suna de 1, 2, 4, 6 y 7 es: 20 ‘Queremos calcular la suma de los valores enteros de 1, 2, 4, 6 y 7 en el listado 10,7. Debido a que lox enteros son casi consécutives, se construye un ciclo for en las lineas 9.0 13, La insteuccién de Ia linea 12 suma todos los enteros consecutivos del 1 al 7 (con excepeién del 3 y el 5, los cuales no estan en la lista y se saltan en el ciclo for). Para saltar estos dos niimeros se evalta la expresién (i==3) |} (ie=5) de la instrucci6a if de la Kinea 10, Si la expresidin se evaliia como 1 (es decir que el valor de ies igual a 3.0.5), entonces se ejecuta la instruccién continue de la linea 11, la cual hace que se salte la suma de la linea 12, y que se inicie otra iteraciéin en la instruccién for, En esta forma se obtiene la suma de los valores enteros 1, 2, 4, 6 y 7, pero saltando automética- mente el 3 y el 5 mediante un ciclo for. Después del ciclo for se despliega en la pantalla el valor de suma, Hamada a printf () de la instruccién de la linea 14, por medio de la La instruccién goto Este libro no estarfa completo sin mencionar la instrucciGn goto, aunque no le recomiende utilizarla, La razén principal de esto es porque es probable que su uso haga que su programa de C sea poco confiable y dificil de depurar, ‘A menudo los programadores se ven tentados a usar fa instruccidn goto, en especial si han utilizado otros lenguajes que no tienen el rico conjunte de instrucciones condicionales de ramificacién que proporciona C. El hecho es que cualquier uso de goto se puede evitar por completo utilizando las otras instrucciones de ramificacién. ‘Usted debe conocer la instruccién goto, pero slo para saber cémo mangjarla de manera apropiada cuando la yea en el cédige de otra persona Control de flujo del programa 167 ‘Obtuve el siguiente resultado al ejecutar en quina el archivo 10L06.exe: FW Introduzca un caricter: Bia (intradurca x para salir) El ciclo while infinite ha sido interrunpido. IHasta pronto! En el listado 10.6 hay un ciclo while infinito, el cual inicia en la linea 9 y termina en la linea 13. Dentro del ciclo infinito, los caracteres que introduce el usuario se asignan, uno a la vez, a la variable entera ¢ (vea la Minea 10). La expresién relacional ¢ == ‘x’ de la instruccidn it se evaliia cada vez que itera el ciclo (vea la Iinea 11). Si la expresién se evalia como @ (es decir, si el usuario no introdujo la letra x), el ciclo continiia. En caso contrario se ejecuta la instruccin break de la linea 12, Ia cual hace que la computadora salte fuera del ciclo infinito y ‘comience a ejecutar la siguiente instraccién, 1a cual se muestra en 1a Ifnea 14. Puede ver en los resultados de muestra que el ciclo while siguié hasta que introduje la letra x, lo que hizo que el ciclo infinito se interrumpiera y se desplegara en la pantalla el mensaje E1 ciclo while infinite ha sido interrumpido. Hasta pronto! La instruccién continue En lugar de interrumpir un ciclo, hay ocasiones en las que usted necesita permanecer en un ciclo pero saltar sobre algunas instrucciones que estén dentro de él. Para hacer esto, puede utilizar la instrucein continue. Esta instrucciéa hace que la ejecucién salte de inmediato al final del ciclo. Por ejemplo, ¢! listado 10.7 muestra cémo usar la instruccién continue en un ciclo que realiza sumas. Listapo 10.7 Uso de la instruccién continue I* YOLO7.c: Uso de la instruccién continue */ Winclude main() { int i, suna ‘ continue; consinis 166 Hora 10 Interrupcién de un ciclo infinito ‘También puede utilizar la instruccién break para interrumpir un ciclo infinito, Un ciclo infinito es aquel en el que la expresiGn condicional se omite completamente; de esta manera, depende del oédigo que estd dentro del ciclo determinar las coi terminarlo. Los siguientes son ejemplos de ciclos infinitos for y while: for (silk dnstruccsént; instruccidn?; } while(1) { instruceiént; instrucciénd; } El ciclo for de arriba omite las tres expresiones, Esto hace que la instruccidn for ejecute siempre el ciclo. La instruccién whi le utiliza 1 como su expresiGn condicional, y ya que esto desde luego nunca se evaléa como @, dicha instruccién siempre continda el ciclo. E] programa del listado 10.6 muestra un ejemplo del uso de Ia instruccién break en un ciclo while infinito, Listapo 10.6 Interrupcién de un ciclo infinito J* t0L@7.c: Interrupeién de un cielo infinite */ #include main() { int ¢; printf(*Intreduzca un carécter:\n(introduzea x para salir) \n wnile(t) { © = gete(stdin); at (@ == ix) break; , Printf("El ciclo while infinito ha sido interrumpioo. iHasta pronto! \n*); return 8; Control de flujo del programa 185) 20: breal ai: case '4 22: printf("El dia 4 es miércoles. \n"); a break; 24: 5° 25: printf(*El dia § es jueves. in"); 28: brea a7: case 6° 28 printt ("El dia 6 @s viernes. \n"); 28: break; a case 7" aM printf("EL dia 7 #6 sdbado.\o"); 32; break; m default: 34 printt ("EL entero no pertenece al rango de 1 a 7.\n"); 38: break; %} a7) return @; 3a: } Con Ia ayuda de ta instruceién break puedo ejecutar el archive 10L05.exe y obtener silo los resultados del caso seleccionado: TIntroduzea un entero pars un dia ID: (dentra del rango de 1a 7): : El dia 1 es domingo. Este programa tiene siete etiquetas case seguidas de las expresiones constantes HRA a4, 5, 6" y '7", respectivamente (vea las lineas 12, 15, 18, 21, 24, 27 y 30). En cada caso hay una instruccién a la que le sigue: una instruccién break. Como ya meneioné, las instrucciones break saldrin de la estructura del switch antes de que la computadora Hegue siquiera a In siguiente etiqueta case y a las instrucciones que le siguen. Ct Por ejemplo, después de que a la variable dia de tipo int se le asigna el valor de 1 y se evalda en Ia instrucei6n switch, se selecciona el caso con '1", y se ejecuta la instruccién de la linea 13. Después se ejecuta la instruccién break de Ia Ifnea 14, la cual interrumpe el control de 1a instruccién switen y lo regresa a la siguiente instrucci6n que esté fuera de la estructura de! switch. En el listado 10.5, la instruccién que sigue es Ia instruccién return de la Knea 37, la cual finaliza la funcidn main. La llamada a la funcién print? () de la lines 13 imprime en ta pantalla la.cadena £1 dia 1 8 domingo Observe que en una instruccién switch no se necesitan las llaves para agrupar las ins- trucciones dentro de un caso individual, ya que case es sélo una ctiqueta y no controla las instrucciones que le siguen. Estas simplemente se ejecutan en orden, comenzando con la etiqueta. ys Hora 10 jentro del rango de 1 8 3): 1 via t Dia 2 Oia 3 Puede ver en los resultados que se ejecuta la instruccién controlada por el caso seleecio- nado, case ‘1’, asi como las instruceiones controladas por el resto de los casos, ya que se despliegan Dia 1, 0{a 2y ofa Sen la pantalla, De la misma manera, si introduzco 2 desde mi teclado, se mostrarin Dia 2 y 04a 3 en la pantal Esta es una caracteristica importante de la instruccién switch: la computadora continta cjecutando las instrucciones que estin después. del caso scleccionado hasta el final de dicha instruceién, En la siguiente seccién aprenderd o6mo salir antes en la ejecucidn de la instruce’ switeh. La instrucci6n break Si desea salir por completo de la instruccién switch después de cada etiqueta case, puede agregar una instruccién break al final de la lista de instrucciones que sigue a cada etiqueta case. La instrucci6a break simplemente sale de la instruccién switch y continia la ejecucién después del bloque de instrucciones switen. El programa del listado 10.5 se asemeja al del listado 10.4, pero esta vez se usa Ia ins- truccién break y los resultados son difcrentes. stape 10.5 Incorporacién de la instruccién break J* 10L05.¢ Incorporacién de 1a instruccién break */ ‘include main() int dia; printf (‘Introduzea un entero para un dia\n*); printf (*(dentro del rango de 1 a 7):\n"); dia = getchar switen (dia){ case 1": printf ("El dia 1 es domingo. \n"); break; 2 #(°E1 dia 2 es lunes.\n*); ca printf ("EL dia 3 es martes.\n'); Control de flujo del programa 163) a main() { int dia; printf("Intraduzca un entero para un dia\n"); printf(*(dentro del rango de 1 a 3):\n"); 10: dia = getenar(); Mir switeh (dia) 42: ease “1': printt(*Dia 1\n"); case “2 printt(*Bia 2\n"); case “3 printt(*Dia 3\n*); default: } 21: return 0; 22: } Si ejecuto el archivo 19L04.exe ¢ introduzco un 3, obtendré los siguientes resultados: Introduzes un entero pars un dia (dentro del rango de 1 a 3}: 3 Dia 3 Como puede ver, en la Iinea 6 se declara una variable int, dia: en la linea 10 se Je asigna la entrada que introduce el usuario. En Ia instruccién switch de la linea 11 se evalia el valor de la variable entera dia. Si el valor es igual a uno de los valores de las expresiones constantes, la computadora comienza a ejecultar instrucciones a partir de ah{, Las expresiones constantes se etiquetan anteponiéndoles el prefijo case, Por ejemplo, yo introduje 3 y después oprimi la tecla Entrar. En la linea 10 se asigna a dia el valor numérico. de 3. Luego, después de encontrar un caso en el que el valor de la expresién constante coincida con el valor contenido en dia, la computadora salia ala linea 17 para ejecutar la funcién print? () y desplegar Dia 3 en la pantal Observe que en Ia linea 19, debajo de la etiqueta default del listado 10.4, hay una instruccién vacia (es decir, nula) que termina con un punto y coma, La computadora no hace nada con una instruccién vacia, Esto significa que si no se aplica ninguna de las expresiones constantes, entonces la instruccién switeh termina sin realizar accién alguna. Sin embargo, si introduzco 1 desde mi teclado y después oprimo la tecla Entrar durante la ejecucién del archive 19.04, exe, obtendré los siguientes resultados: Introduzea un entero para un dia [182 Hora 10 Anstrucedén?; default: instruceidn_predeterminada; ) Aquf, primero se evalda la expresién condicional expresién. La instruccién switch salta después a la etiqueta case correspondiente y ejecuta, en orden, todas las instruc ciones que siguen. Si expresidn produce un valor igual a expresién_constante!, entonces s¢ ejecuta instruceién’, seguida de iastruceién? y de todas las demas hasta instruceién_predeterminada. Si el valor que produjo expresién es el mismo que el valor de expresi6n_constante2, entonces {nstruceién2 se ejecuta primero. Sin embargo, si el valor de expresién no es igual a ninguno de los valores de las expre- siones constantes etiquetadas por la palabra reservada case, entonces se ejecuta la instruccién (ins trucesdn_predeterminada) que sigue a la palabra reservada default, Debe utilizar Ia palabra reservada case para ctiquetar cada caso. Observe que cada etiqueta ease termina con das puntos, no con punto y coma. Esta es la sintaxis de las etiquetas en C. La palabra reservada default se debe usar para el caso “predeterminado”, es decir, cuando ninguna etiqueta case coincide con la expresién condicional, Observe también ‘que dentro de la instruccién switch ninguna de las expresiones constantes asociadas con etiquetas case puede ser idéntica. que la utilice la instruccion condicional de ramiti 2s, en si misma, una instruccién; mas bien le sefiala un lugar al cual saltar cuando necesita apartarse del flujo de ejecucién normal de arriba hacia abajo. LU sintaxis adecuada para una etiqueta es un identificador Gnico sequido de dos puntos, ne de un punto y coma. En este capitulo vera varias formas de usar etiquetas, asi come los nombres de etiqueta reservados case expre- sion: y default. f En C, une etiqueta se usa en su cédigo como una especie de marcador para El programa del listade 10.4 presenta un ejemplo del uso de Ia instruccién switen. El programa también muestra una caracteristica importante de dicha instruceisn, Listavo 10.4 Uso de la instruccién switch 12 /* 10Le4.c Uso de la instruccién switch */ 2: include 0 de la instruccién it de la linea 9. La expresién 4 > @ se usa para comprobar si el valor de 4 es positive o tiene otro valor (enteros negativos, incluyendo al cero). Si la expresién se evalda como 1, la computadora salta a la segunda instrucciGn if (es decir, a la anidada) de la nea 10, ‘Observe que la linea 10 contiene otra expresi6n relacional, :¥2 == 0, la cual comprucba sila Variable entera i es par o non. Por lo tanto, la segunda decisién de desplegar enteros Pares © nones se toma de acuerdo con la evaluacién de la segunda expresién relacional, 182 ** @. Siesta evaluacién produce 1, la llamada a printf () de la linea 11 imprime tun entero par. En caso contrario se ejecuta la instruccidn de Ia Hinea 13 y se muestra un entero non en la pantalla. La computadora ramifica a la linea 14 si la expresién i > 0 de la linea 9 se evaltia como ; 8 decir, si el valor de i es menor que 0, En la linea 14 se anida otra instruccién if dentro de una frase else, y se evahia la expresiG relacional 1 == 0, Sii == @se evalda como verdadero ldgicamente, lo que significa que 4 sf comtiene el valor de cero, se despliega en la pantalla la cadena £1 entero es cera. En caso comtrario, el valor de 4 debe ser negativo, de acuerdo con la evaluacién previa de la expresidn 4 > @ de la linea 9. La instruccidn de la linea 17 imprime entonces el entero negative en la salida esténdar, ‘Como puede ver en el ejemplo, el valor de 4 est dentro. del rango de 5 a -5. Debido a esto, -5, -4, -3, -2y -1 se imprimen coma enteros negativas. Después se imprime un mensaje cuando 4 es cero, y luego se imprimen los enteros nones 1, 3 y 5. as{ com las enteros pares 2 y 4. La instrucci6n switch En la seceién amerior vio que se utilizan las instrucciones if anidadas cuando: hay que tomar decisiones sucesivas relacionadas, Sin embargo, la instruccién if anidada se puede volver muy compleja si es necesario tomar muchas decisiones. En acasiones, un progra- mado tendré problemas para simplemente seguirles la pista a algunas instrucciones if anidadas. Por fortuna existe otra instruccién en C, la instruceidn switen, misma que usted puede usar para tomar decisiones u opciones ilimitadas con base en el valor de una expresién condicional y casos especificos. La forma general de la instruccién switen es switch (expresién) { case expresién_constantet: instrucedént ; case expresion_constante2: 160 Hor Instrucciones if anidadas Como vio en las secciones anteriores, una instruceién if le permite: a un programa tomar una decisién, En muchos casos, un programa tiene que tomar una serie de relacionadas. Para este fin, usted puede utilizar instrucciones if anidadas. El listado 10.3 muestra eémo usar instrucciones 4¢ anidadas, Listapo 10.3 Uso de instrucciones if anidadas 1: /* 10L@3.c Uso de instrucciones if anidadas */ include main() 1 int i; for (is-83 bens; te+)i if (i> 8) if (182 == 0) Print ("Sd @s un entero par.\n*, i); else printf("%d es un entero mon.\n*, 4); else if (== 8) printf(*E1 entero es cero.\n* else 7 printf(*Entero negativo: ‘win", 1); 1B} 18: return @; 20: } Después de ejecutar el archivo 10103.exe, obtuve los siguientes resultados: Entero negative: -5 entero nepetsvo: Entero 3 Entero 2 Entero negative: «1 El entero es cero. 1 es un entero non. 2 88 un entero par. 3 es un entero non. 4 es wtero par. § es un entero non. El listado 10.3 contiene un ciclo fer que comienza en la Iinea 8 y termina en la 18, De acuerdo con las expresiones de la instruccién for de la Kinea 8, toda tarea controlada por la instruccién for se ejecuta hasta 11 veces. Control de flujo del programa 159 Listabo 10.2 Uso de la instruccion if-else /* 10Le2.c Uso de Le instruccién if-else */ include main() int 43 printf ("Entero par Entero non\n"); for (180; ita; i++) if (182 == 0) printt(*sd*, ibs else printf (‘stadia a: return 0; Al ejecutar el archivo 19L02,exe se obtienen los siguientes resultados: Entero par Entero non 1 La linea 6 del listado 10.2 declara una variable emera, i. La funciGn print# () dde Ia linea 8 despliega una linea de encabezado en la pantal La variable entera i se inicializa en la primera expresién de la instruccién for de la linea 9. Controlada por la instruccién for, la instrucci6n if-else de las lineas 10 a 13 se ejecuta 10 veces. De acuerdo con ta instruccidn if -e1se, la llamada a printf() de ta Iinea 11 imprime enteros pares si la expresién relacional 1x2 == @ de la linea 10 se evaliia como 1 (verdadero Igicamente). Si dicha expresidn se evaléa como @ (falso Igicamente), la llamada a printf) de la linea 13, controlada por la palabra reservada ‘e1se, imprime enteros nones en la salida estdndsr, Debido a que se trata a la instruccién if-else como a una & tan las Haves { y } para formar un bloque de instrucciones bajo la instruceién for. De la ‘misma manera, no se usan llaves en la instruccién if -e1se, ya que las palabras reservadas 4f y else controlan, cada una, una sola instruccién en las lineas 11 y 13 respectivamente instruccién, no s¢ necesi- ‘Observe que en Ia funcién printf () de Ia lines 13 se especifica un ancho minimo de 14, de modo que los resultados de los enteros nones se listan a la derecha de los enteros. pares, como puede ver en la seccién de salida. El programa del listado 10.2 verifica los enteros en un rango del @ al 9, y muestra que @, 2, 4, 6 y 8 Son enteros pares y que, 1, 3, 5,7 y 9 son nones. 158 Hora 10 ‘Dentro del ciclo for, la instruccién if de las Iineas 11 y 12 evala la expresidn logica (U2 == @) && (183 == 0). Si la expresién se evalda como 1 (es decir, el valor de i ‘se puede dividir por completo entre 2 y entre 3), entonces se despliega en la pantalla cl valor de i llamando a Ja funcién printt() de la linea 12. En caso contrario se salta la instruccién de la linea 12. Obverve que no se usan las Haves ({ y }}, ya que sélo hay una instruccisn bajo el control de la instruceidn if. El resultado que se muestra en la pantalla presenta todos los enteros dentro del rango de ©. 100 que se pueden dividir entre 2 y entre 3. La instruccién if-else En la instrucciém 4¢, cuando la expresidn condicional se evalia como diferente de cero, Ja computadora pasaré a las instruceiones que controla la instruccidn if y las ejecutard de inmediato. Si la expresién se evahia como cero, la computadora ignorard las instrucciones que controla la instruccidin if. A menudo necesitaré que la computadora eecute un eonjunto alterno de instrucciones cuando la expresidn condicional de la instruceién if se evalde como falso Iégicamente. Para ello, puede usar otra instruccién condicional de ramificaci6n: la instruccién if 8. ‘Como una extensi6n de la instruccién if, la instruccién if-else tiene la siguiente forma: if (expresién) { instrucciént; instruceién2; b alse { Anstruceién_A; instrueci } Si oxpresién se evalia come diferente de cero, entonces se ejecutan Ins instrucciones que controls el if, incluyendo a snstruceiént ¢ instrucedén2. Sin embargo, si expresién se evalia como cero, en su lugar se ejecutan instruceiéa _Ae instrucedén_8, que ssiguen a la palabra reservada else. El programa del listado 10.2 muestra cmo usar la instruecién if-else. Control de flujo del programa 157) x > @.0, la cual se evaliia a un valor de 1 (verdadero lSgicamente) si x es mayor que cero, y se evalia como @ (falso Kbgicamente) si x es menor o igual a cero. El listado 10.1 proporciona otro ejemplo del uso de la instruccidn if, Listapo 10.1 Uso de la instruccién if en la toma de decisiones 1: /* 18LO1.¢ Usa de 1a instrucedén if */ 2: finclude a: 2 main() Anti; printt(*Enteros que se puaden dividir entre 2 y entre 3\n*); printf(*(dentra cel rango de 8 a 1@@):\n"); for (180; d<=t00; iv+){ af (ANZ == 0) BB (NI == 8) printf(* Sd\n", ip; } return @; 1 Después de erear y ejecutar el programa 10101 exe del listado 10,1, se desplegaron los siguientes resultados en la pantalla: ea Enteros que se pueden dividir entre 2 y entre 3 AL (dentro del rango de 0 @ 100) ° 6 12 18 24 30 36 42 48 54 ee 66 72 78 4 98 Como puede ver en el listado 10.1, la fnea 6 declara una variable entera, 4, Las Iineas 8 y 9 imprimen dos lineas de encabezado, Comenzando en la linea 10, Ja instruccién for realiza un ciclo 101 veces. 156 Hora 10 Cémo decir siempre "si..." Si la vida fuera una linea recta, seria muy aburrida. Esto también es cierto para la progra- maci6n. Seria demasiado aburrido si las instrucciones s6lo se pudieran ejecutar en el orden en que aparecen. De hecho, una tarea importante de un programa consiste en instruir a la computadora para que ramifique (es decir, que salte) a diferentes partes del cOdigo y trabaje sobre diferentes tareas cuando se cumplan Ins condiciones especificadas. ‘Sin embargo, en la mayorfa de los casos usted no sabe con anticipacién qué vendri después. Lo que sf sabe es que con toda seguridad algo sucederd si se cumplen ciertas condiciones. Por lo tanto, puede escribir en el programa solamente tareas y condiciones. Las instrucciones condicionales de ramificacién deciden cundo realizar las tareas. La instruccitin if es la instruccién condicional de ramificacitm més comin en C; se puede utilizar para evaluar las condiciones asf como para decidir si se va a ejecutar el bloque de cédigo controlado por la instruccin, La forma general de la instrucciGn if es if (expresion) { Anstrucciént; instruccién2; } Aqui, expresién es el criterio condicional. Si la expresién se evalda como un valor diferente de cero, entonces se ejecutan las instrucciones que estin dentro de las Ilaves (Ly Hi, como instruccién € instruccién?. Si expresién se evalda como cero, entonces se saltan las instrucciones. Observe que las Ilaves ({ y }) forman un bloque de instrucciones que esté bajo el control de la instruccién if. Las Haves se pueden omitir si s6lo hay una instrucciGn dentro del bloque. Sin embargo, siempre se deben usar los paréntesis (( y )) para encerrar la expre- sién condicional. Por ejemplo, la expresién af (x > 0.8) printt(*La raiz cuadrada de x 2: stint, sqrt(xy); Ic indica a la computadora que si el valor dé la variable de punto flotante x es mayor que ®. (es decir, positivo), debe caicular la rafz cuadrada de x llamando a la funcién sqrt(), ¢ imprimir después el resultado. Aqui, el criterio condicional es ls expresién relacional HORA 1 0 Control de flujo del programa Es mds dificil mandar que obedecer. —F. Nietzsche En la hora 7, “Ciclos”, aprendié a usar las instrucciones while, do-while y for para hacer lo mismo una y otra vez. Estas instrucciones se pueden agrupar dentro de Ia categoria de instrucciones de ciclos que se emplean en C para Al control de flujo. En esta leceiGn aprender acerca de las instrucciones que pertenecen a otro grupo de instrucciones de control de flujo, la ramificacién (o saite) condi- ccional, como son: * La instruccién if * La instruccién if-else + La instruccién switen + La instruceiGn break La instruccién continue La instruccién goto. 154 Hora 9 Taller Para consolidar la comprensién de la Ieccién de esta hora, le recomiendo responder el cuestionario y terminar los ejercicios de este taller antes de pasar a la siguiente leccién, Las respucsias y sugerencias se presentan en él apéndice B, “Respuestas a los cuestiona~ tios y ejercicios" Cuestionario Dada una variable x de tipo int y una variable y de tipo unsigned int, siendo x = 0x8765 y y = 0x8765, y empleando como bit de signo el que esté mis a Ia izquierda, jes x igual ay? 2. Qué debe hacer si intenta asignar un valor grande a una variable int, pero el valor que asigna es demasiado grande y obtiene un niimero negativo que no esperaba? 3. Qué especificador de formato se debe emplear para especificar una variable unsigned long int, ldo ‘lu? 4, (Qué nombre de archivo de encabezado debe incluir si llama a alguna funcién matemética en su programa de C? Ejercicios 1. Dadas las instracciones int x; unsigned int yz X= @xAB7B: escriba un programa para desplogar en la pantalla los valores decimales de x y y. 2. Escriba un programa para medir en su maquina el tamaiio de short int, long int y long double. 3. Escriba un programa para multiplicar dos variables signed int con valores posi- tivos, y desplegar el resultado como long int. 4. Escriba un programa para mostrar enteros negativos en formato hexadecimal junto con sus equivalentes signed int. 5. Dado un dngulo de 30 grados, escriba un programa para calcular los valores de su seno y su tangente. 6. Escriba un programa para calcular la raiz cuadrada no negativa de 0x19A1 Modificadores de datos y funciones mateméaticas 153 + Existe un conjunto de funciones de biblioteca de C, como sin(). c05() y tan(), que se puede emplear para realizar célculos trigonamétricos @ hiperbélicos. + Enxiste otro grupo de funciones matemiticas en C, come pow(}, que puede efectuar célleulos exponenciales y logaritmicos + La funcién sqrt() devuelve una rafz cuadrada no negativa. La expresién sqrt (x) equivale a la expresién pow(x, 0.5), si x tiene un valor no negativo, No puede pasar un valor negative a la funcién sqrt(), ya que esto ocasionaria un error. + Debe incluir en su programa de C el archivo de encabezado nath.n si llama a cualquiera de las funciones matemiticas declaradas en ese archiva de encabezado. En la siguiente leccién aprenderd varias instrucciones de control de flujo muy impor- tantes en Preguntas y respuestas P ,,Qué bit se puede usar como bit de signo en un entero? R. Se puede usar el bit més a la izquierda, el ms significativo. Por ejemplo, suponga que cl tipo de datos int tiene 16 bits de longitud. Si cuenta la posicidin de los bits de derecha a izquierda, comenzande por el bit 0, entonces el bit 15 es el bit mis hacia la izquierda, y es el que se puede utilizar como bit de signo, P Qué hace el especificador de formato %1u? R El especificador de formato 41u se puede usar en una cadena de printf () para con- ‘vertir el argumento correspondiente al tipo de datos unsigned long int. Ademis, el especificador de formato %1u equivale a Lu. P ,,Cudndo se utilizan short y long? R. Si necesita ahorrar espacio de memoria, y sabe que el valor de una variable de datos entera permancce dentro de un rango reducido, puede utilizar el modificador short para indicarle al compilador de C que reduzca el espacio de memoria prede- terminado asignado a la variable, por ejemplo, de 32 a 16 bits. Por otra parte, si una variable tiene que contener un nimero que exceda el rango actual de un tipo de dates, puede usar el modificador Long para aumentar el espacio de almacenamiento de la variable, 2 fin de que contenga ese niimero. La funcién in() toma un valor en grados o en radianes? R. Al igual que otras funciones trigonométricas de C, la funeién sin() toma un. valor en radianes, Si tiene un dngulo en grados, debe convertirlo a radianes, La formula es: 7 radianes = grados * (3.141593 / 180.0). 182 Hora 9 La funcidn pow() de Ia linea 12 toma x y y, para caleular después el valor de x elevada a la potencia y. Debido a que el resultado es de tipo double, como ya sé que la parte frac- cionaria serd toda de digitos decimales 9, utilizo el especificador de formate 47.¢f en la funcidn printf () para convertir slo la parte no fraccionaria de! valor. El resultado se muestra en la pantalla como 262144. En la linea 13 se calcula la rafz cuadrada no negativa de x por medio de la llamada a la funcién sqrt(). Al igual que en la Ifnea 12, en Ia linea 13 se usa el especificader de formato 82..¢F para convertr la parte no fraccionaria del valor que devuelve la funcidn sart(), debido a que la parte fraccionaria consta solamente de ceras, Como puede ver en los resultados, Ia raiz cuadrada no negativa de x es 8. Como mencioné antes, la expresién pow(x, 0.5) es equivalente a la expresién sqrt (x). Por lo tanto, no es una sorpresa que la expresin pow(x, 2) de la instruceisn de ta linea 14 produzea el mismo resultado que sqrt (x) en la linea 13, ‘Todos los célculos de punto flotante, incluyende los tipos de datos float y ee ‘double, se realizan en aritmética de doble precisidn. Esto significa que una variable de datos float se debe convertir a double para realizar el célculo, Desputs del edcuic, el tipe double se tiene que corwertir de nuevo a f oat antes de asignar él resultado a la variable float. Por lo tanto, un edleulo float podria tardar més tiempo. La principal razén por la que C maneja el tipo de datos float es el ahorra: de espacio de memoria, ya que el tipo de datos double ecupa el doble de memoria que el tipo flaat. En muchos casos, la precision que afrece el tipo float es suficiente. Resumen En esta leccién aprendié los siguientes modificadores y funciones matematicas impor- tamtes: + El modificador signed se puede utilizar para declarar tipos de datos char e int que contengan valores negativos y no negatives, + Todas las variables int de C tienen signo de manera predeterminada. + El modificador unsigned se puede utilizar para declarar tipos de datos char e int que no contengan valores negatives. Hacer esto duplica efectivamente los valores Positives que puede contener la variable, + El espacio en memoria que ocupa una variable de datos se puede reducir e incre- mentar por medio de los modificadores short y Long, respectivamente. Modificadores de datos y funciones matematicas 151) La sintaxis de la funcién pow() es #include double pow(double x, double y); ‘Aqui, el valor de la variable doubLe x se eleva a la potencia de y. La fun devuelve el resultado en el tipa de datos double. in pow, ) La sintaxis de la funeién sqrt() es #inelude double sqrt(doubLe x); Aqui, a funcién sqrt) devuelve la rafz cuadrada no negativa de x en el tipo de datos double. Si x es negativa, ocurre un error. Si usted pasa @.5 como segundo argumento a la funcién pow{}, y x contiene un valor no negativo, entonces las dos expresiones, pow(x, 0.5) y aqrt (x), son equivalentes, Observe ahora cémo Hamar a las funciones pow(}) y sqrt () en el programa que se mues- tra en el listado 9.5, Listavo 9.5 Aplicacién de las funciones pow() y sart() J* @9L05.c: Uso de las funciones pow() y sqrt() */ Winclude #inelude main() 4 double x, ys 5 x = 64.0; y= 3.05 z= 0. printf (*pow{64.0, 3.0) devuelve: &7.0\n", powix, y))5 printf (*sqrt (64.0) devuelve: —82.0F\n", sqrt (x) printf (*pow(64.0, @.5) devuelve: %2.0f\n", pow(x, z)); return 0; Después de cjecutar el archivo 09L@5. . se desplegaron en la pantalla los siguientes resultados paw(64.0, 3.0) devuelve: 262144 sqrt (64.0) devuelve: = 8 pow (4. 8.5) devuelve: 8 En las Iineas 9 a 11 se inicializan las variables x, yy z del listado 9.5 con 64.9, 3.0 y 0.5, respectivamente [150 Hora 9 Listapo 9.4 continuacién main() { double x; x= 45, J 45 grados x "= 3.141593 / 180.0; /* convierte a radianes */ printt(*El sena de 45 es: Sf. \n*, sin(x) Drintf(*EL coseno de 45 es: ¥f.in°, cos(x) printf(*La tangente es: ef.\n", tam(x)); return 0; Al ejecutar el archivo 09L04.exe se desplegaron en la pantalla los siguientes res El seno de 45 @: El coseno de 45 La tangente de 48 es: 1.000008. Observe que en la linea 3 se incluye el archivo de encabezado nath.n, el cual es necesutio para las funciones matematicas de C. La variable x de tipo double del listado 9.4 se inicializa con 45.0 en Ia Ifnea 9. Aqui, 45.0 es el valor del éngulo en grados, el cual se convierte al valor correspondiente en radianes en Ia Eines 10. Después, la instruccién de la linea 11 calcula el seno de x por medio de la Hamada a la funcién sin{) ¢ imprime el resultado en la pantalla. Asimismo, la nea 12 obtiene el coseno de x y lo muestra en la pantalla. Debido a que x contiene el valor de un angulo de 45 grados, no es una sorpresu que los valores del seno y el coseno sean iguales, alrede- dor de 8.707187. La linea 13 nos da el valor de Ia tangente: de x por medio de la funcién tan(). Como tal ver sepa, Ia tangente de x es igual al seno de x dividido entre el coseno de x. Debido a que el seno de un éngulo de 45 grados es igual al coseno del mismo éngulo, Ia tangente es igual a 1. El resultado (en el formato de punto flotante) de 1.ee0000, en Ia tercera linea de la salida del programa, lo demuestra, ar las cosas, podria declarar una variable P1 inicializada a 3.141599, y otra y usarlas en sus edlculos, © podria simplemente declarar una sola constante inicializada al resultado de 3,141593/180.0, Llamadas a pow() y sqrt() Las funciones paw() y sqrt () son otras funciones matemuiticas utiles de C. A diferencia de otros lenguajes, C no tiene un operador intrinseco para elevar un ndmero a una potencia. Modificadores de datos y funciones matematicas 149 Las dos secciones siguientes presentan varias funciones mateméticas y le muestran cémo uusarlas en sus programas. Llamadas a sin(), cos() y tan() ‘Si no es un fandtico de las mateméticas, puede saltarse las dos secciones que siguen, pues stas no son vitales para entender el lenguaje C. Sin embargo, si necesita hacer cilculos mateméticos, podria apreciar que C le oftece este conjunto de funciones matemiticas, Por ejemplo, dado un. fngulo x en radianes, la expresién sin devuelve el seno del éngulo, Puede utilizar la siguiente {érmula para convertir el valor de un éngulo en grados al valor en radianes: radianes = grados * (3.141893 / 180.0). Aqui, 3.141589 ¢s el valor aproximado de pi. Si ¢s necesario, puede usar mas digitos decimales de pi. ‘Veamos ahora la sintaxis de las funciones sin{}, 608() y tan(). | La sintaxis de la funcidn sin() es #include | double sin(double x); Aqui, la variable x de tipo doubie contiene el valor de un éngulo en radianes. La funcién sin() devuelve el seno de x en el tipo de datos double. La sintaxis de la funcién cos() es #inelude double cos(double x); ‘Aqui, la variable x de tipo double contiene el valor de un dngulo en radianes, La funcin cos() devuelve el coseno de x en el tipo de datos double. La sintaxis. de la funcién tan() es Winclude double tan(double x); ‘Aqui, la variable x de tipo doube contiene el valor de un dingulo en radianes. La funcin ‘tan() devuelve la tangente de x en el tipo de datos double. El listado 9.4 muestra eémo utilizar las funciones sin(), cos () y tan(). Listapo 9.4 Calculo de valores trigonométricos con sin(), cos() y tan() {* @9L04.c: Uso de las funciones sin(), cos() y tan{} */ Winclude #incluge 148 Hora 9 Listapo 9.3 continuacién unsigned int vi long int 55 unsigned long int t; xFFFFFFFF1; FFFFFFFFL; printf ("EL valor short int de OxFFFF es Wnd.\n", x); printf (*€l valor unsigned int de OxFFFF es %u.\n", ¥) printf (*EL valor long int de OxFFFFFFFF 08 Sid.in", 8); printf (*€l valor unsigned long int de @xFFFFFFFF es Slu.\n", t); return 0; Después de crear y ejecutar en mi még pantalla los siguientes resultados: ina el archivo @8L€3.exe, se desplegaron en la El valor short int de OxFFFF es -1 El valor unsigned int de @xFFFF es 65535 El valor long int de xFFFFFFFF es -1. El valor unsigned long int de OxFFFFFFFF es 4294967295 Hay cuatro tipos de datos declarados en el listado 9.3: la variable x de tipo short int, la variable y de tipo unsigned int, la variable s de tipo Lang int, variable t de tipo unsigned Long int. Estas cuatro variables se declaran en las 6 29y se inicializan en las lineas [1 a 14 Para imprimir los valores decimales de x, y, 8 ¥ t, se utilizan los especificadores de formato ‘nd, 4u, 1d y ‘Lu en fas Ifneas 15 a 18, respectivamemte, para convertir los correspondientes ndmeros hexadecimales a nimeros decimales. Los resultados del pro- rama del listado 9.3 muestran que los valores contenidos por x, y, # y t se desplegaron correctamente en la pantalla. Funciones matematicas en C Bésicamente, las funciones mateméticas que proporciona el lenguaje C se pueden clasi- ficar en tres grupos: + Funciones trigonométricas ¢ hiperbélicas, como a¢os{), ¢08(} y cosh + Punciones exponenciales y logaritmicas, como exp), pow) y logt@() + Funciones matemiiticas diversas, como ceil(), fabs() y floor {). ‘Tiene que incluir el archivo de encabezado math.h en su programa de C, antes de poder utilizar cualquiera de las funciones matemsticas definidas en ese archive de encabezado. Modificadores de datos y funciones matematicas 147 | En el listado 9.2 se emplean el operador sizeof y la funcidn printf () para medir el tamatio de los tipos de datos modificados y desplegar los resultados en la pantalla, Por ejemplo, las lineas 6 y 7 obtienen el tamafio del tipo de datos short int ¢ imprimen cen Ta pantalla el nimero de bytes, 2. Por los resultados, usted sabe que en mi méquina el tipo de datos short int es de 2 bytes de longitud. De Ia misma manera, las Iineas 8 y 9 muestran. que el tamaiio del tipo de datos Long int ‘es de 4 bytes de longitud, que es la misma que Is del tipo de datos float obtenida en las lineas 10 y 11, Las lineas 12 y 13 obtienen el tamafio del tipo de datos double, el cual es de 8 bytes en mi méquina. Luego, después de ser modificado por el modificador 1ong, el tamaiio del tipo de datos double se incrementa a 10 bytes (es decir, 80 bits), el cual es impreso por Ja Tamada a la funci6n printf () de las lineas 14 y 15, ‘Como én el ejemplo anterior, es probable que sus resultados sean diferentes si su sistema maneja anchos de datos distintos a los de mi maquina. Al ejecutar este programa en su propia maquina, puede determinar el ancho de estos tipos de datos para su sistema. Como agregar h, 1 0 L a los especificadores de formato printf y fprintf Las funciones printf y fprintf necesitan saber el tipo de datos exacto de los argumentos ‘que se les pasan, a fin de evaluar de manera adecuada dichos argumentos e imprimir sus valores en forma significativa. La cadena de formato de las funciones printf y fprintt -emplea los especificadores de conversidn 4, , 0, u, x 0 X para indicar que el argumento correspondiente es un entero, y que es de tipo int o unsigned int. Puede agregar h dentro de! especificador de formato entero (de la siguiente manera: ‘thd, ‘shi o shu) para indicar que el argument correspondiente es un short int o un unsigned short int Por otra parte, utilizar %1d 0 ‘Ld especifica que el angumento correspondiente es long int. Y ‘lu o $Lu se utilizan para los datos unsigned long int. El programa del listado 9.3 muestra el uso de Shd, lu y 14, Listape 9.3 Uso de snd, sid y slu [* @5L83.c: Uso de los especiticadores thd, Ald y Slu */ Winclude { 1 2 3: 4: main() 5 6 short int x contin 146 Hora 9 El estindar ANSI le permite indicar que una constante tiene el tipo Long, con slo agregar el sufijo 1 o L a la constante: Jong int x, y5 x = 1234567801; y = @xABCDI234L ; Aqui, las constantes del tipo de datos long int, 1234567891 y @xABCD1234L, se asignan a las variables x y y, respectivamente, Ademés puede declarar una variable entera Long de ta siguiente manera: ang x; Jo que equivale a Jang int x; El listado 9:2 contiene un programa que puede imprimir el nimero de bytes para diferentes tipos de datos modificados que proporciona el compilador de C utilizado para compilar el programa. Listapo 9.2 Modificacién de datos con short y long 1: [* @BL02.c: Uso de los modificadores short y long */ 2; include 3: 4: main() printf("El tamafo de short int es: ‘d.\n", sizeof (short int}); printt(*El tamano de long int es: d.\n", sizaot (long int} ); printf("El tamafo de float es: §d.\n", sizeof (float)); print#("El tamafo de double ‘sizeof (double)); printf("El tanafio dé long double es: %d.\n", ‘sizeof (long double) ); turn 83 2 d\n 17: } Obtuve los siguientes resultados después de ejecutar en mi computadora el archivo oste2.exe: El tamaho de la £1 tamaho de El tamaio de El tamato de double es: 8. El tamaho de long doubl LT.) Modificadores de datos y funciones matematicas 145 la funcién print#() de la linea 15 (de hecho, quizd recuerde que en la hora anterior uti- lizamos ‘wu para especificar ef tipo de datas unsigned int como formato de despliegue). Con base en los resultados, puede ver que OxFFFF es igual a -1 para el tipo de datos signed int, y 65535 para el tipo de datos unsigned int. Aqui, el tipo de datos entero tiene una longitud de 16 bits. Las lineas 16 y 17 imprimen #3039 y OxCFC7, que son los formatos hexadecimales de los valores decimales 12345 y - 12345, respectivamente. De acuerdo con el método mencionado en Ja secciGn anterior, @xCFCT se obtiene sumando 1 al valor de complemento de @x3039, Puede obtener resultados diferentes a los de este ejemplo, dependiendo del ancho de tos distintos tipos de datos de su sistema. Lo que es importante entender, es la entre los tipos de datos signed y unsigned. Modificacién del tamafo de los datos En ocasiones desea reducir la memoria que ocupan las variables, o necesita incrementar el espacio de almacenamiento para ciertos tipos de datos. Por fortuna, el lenguaje Cle proporciona la flexibilidad para modificar el tamafio de los tipos de datos, En las dos secciones siguientes se presentan los modificadores de datos short y 1ong. El modificador short Por medio del modificador short se puede modificar un tipo de datos para que ocupe menos memoria. Por ejemplo, puede aplicar el modificador short a una variable entera de 32 bits, lo cual reduce a 16 bits la memoria que ocupa la variable. Puede usar el modi icador short de la siguiente manera: short 3 ‘o bien, unsigned short ys De manera predeterminada, un tipo de datos short int es un ndmero con signo. Por lo tanto, en Ia instruccién shart x;, x és uina variable con signo de tipo entero corto, El modificador long Si necesita més memoria para almacenar valores dentro de un rango més amplio, puede usar el modificador Long para definir un tipo de datos con espacio de almacenamiento aumentado, Por ejemplo, dada una variable entera x de 16 bits de longitud, la declaracicin Long int x; aumenta ¢l tamafio de x a por lo menos 32 bits. 144 Hora 9 Listapo 9.1 Modificacion de datos con signed y unsigned 1s J* Q9LO1.¢; Uso de 108 modificadares signed y unsigned */ 2: include a 4: main() si { 6: signed char ch; 2 int. x} @: unsigned int y5 a 10: ch = OxFF; 11: = OXFFFF; 12: y= OXFFFFU; 13: printf ("EL valor decimal de signed OxFF es %d.\n", ch); 14; print#(*El valor decimal de signed @xFFFF es %d.\n", x}; 15: printf ("EL valor decimal de unsigned OaFFFFu es Su. in", y); 16: printf ("EL valor nexadecinal del decimal 12345 65 Ox¥K.\n", 1245); 17: printf ("EL valor hexadecimal del decimal -12345 es Ox¥X.\n", -12345); 18: return @ En mi maquina, ¢l archivo ¢jecutable del programa del listado 9.1 s¢ Hama @9L1 . exe. (Observe que al compilar este programa podria obtener un mensaje de advertencia con respecto a la instruccién de asignacién ch = @xFF; de la linea 10, debido a que ch fue declarada como una variable signed char. Puede ignorar el mensaje de advertencia,) Los siguientes resultados se desplegaron en la pantalla de mi maquina después de ejecutar el archivo 09L01 exe: E1 valor decinal de signed OxFF es -1 Bislama 1 valor decinal de signed OxFFFF es -1. El valor decinal de unsigned @xFFFFU es 65535. E1 valor hexadecimal del decimal 12345 es @x3839. E1 valor hexadecimal del decimal -12945 es @xCFCT. ‘Como puede ver en el listado 9.1, la I{nea 6 declara una variable char con signo, ch. Las variables int x y unsigned int y se declaran en las lineas 7 y 8, respec- tivamente, En las Ifneas 10 a 12 se inicializan las tres variables, ch, x y y. Observe que en Ja linea 12 se pone el sufijo u a xFFFF para indicar que la constante es un entero sin signo. La instruccidin de la linea 13 muestra el valor decimal de la variable signed char, ch. Los resultados muestran que el valor decimal correspondiente de @xFF es -1 para la variable ‘char con signo ch. Las lineas 14 y 15 imprimen los valores decimales de la variable int x (la cual tiene signa de manera predeterminada) y de la variable unsigned int y, respectivamente. Observe que se utiliza el especificador de formato para enteros sin signo ‘wu para la variable y de Modificadores de datos y funciones matematicas 143) utilizan el bit de signo. (Los modificadores short y Long se presentan mis adelante en este capitulo.) De manera predeterminada, todos los tipos de datos enteros, con excepcién del ipo de datos char, son cantidades con signo. Sin embargo, el estandar ANSI no require que el tipo de datos char tenga signo; depende de los fabricantes de comipiladores. Por lo tanto, si desea utilizar uma variable de cardctet con signo, y asegurarse de que el compi- Indor la reconoce, puede declarar la variable de tipo earicter de la siguiente manera signed char ch; aa fin de que el compilador sepa que la variable de tipo cardcter ch tiene signo, lo que sig- nifica que la variable puede contener valores negativos y positives, Si el tipo char es de & bits de longitud, entonces una variable signed char contendria valores desde -128 (es decir, 2”) hasta 127 (2-1), En contraste, un cardcter sin signo estaria en él rango de 0 a 255 (2-1). El modificador unsigned E! lenguaje C también le proporciona el modificador unsigned, el cual se puede utilizar para indicar al compilador de C que el tipo de datos especificado s6lo es capaz de con~ tener valores. no negativos. ‘Al igual que el modificador signed, el modificador unsigned sdlo tiene sentido para los tipos de datos enteros (char, int, short int y Long int). Por ejemplo, la declaracién unsigned int x; le indica al compilador de C que la variable entera x solamente puede asumir valores positives del @ al 65535 (es decir, 2"-1), si el tipo de datos int tiene una longitud de 16 bits; un tipo mt (con signo) contendria valores desde -32768 (-2'") hasta 32767 (2-1). De hecho, de acuerdo con el estindar ANSI, unsigned int es equivalente (por sf mismo) aunsigned, En otras palabras, unsigned int x; es lo mismo que unsigned x; Ademis el estindar ANSI le permite indicar que una constante es de tipo unsigned poniendo el sufija uo U a la constante. Por ejemplo, unsigned int x, ¥: x 123480; y = OxABCOU; ‘Aqui se asignan las constantes enteras sin signe 12046U y @xABCOU a las variables x y y, respectivamente, El programa del listado 9.1 es un ejemplo del uso de los modificadores signed y unsigned [42 Hora 9 Ademis aprenderd acerca de varias funciones mateméticas que offece el lenguaje C, como son: * La funcién sin() * La funcién cos () * La funcién tan() + La funcién pow() * La funeién sqrt() Como habilitar o inhabilitar el bit de signo Como usted sabe, es muy fiicil expresar un mimero negative en decimal. Todo lo que necesita hacer es poner un signo de menos frente al valor absoluto del niimero (el valor absoluto es la distancia del niimero a partir del cero). Pero, je6ma representa la compu- tadora un mimero negativo en el formato binario? Normalmente se puede utilizar un bit para indicar si el valor de un mimero representado en el formato binario es negativo. A este bit se le llama bit de signa. Las des secciones siguientes le presentan des modificadores de datos, signed y unsigned, que pueden emplearse para habilitar o inhabilitar el bit de signo, de hecho, el lenguaje C estindar no hace ningin requerimienta de que se ice un bit de signo, aunque éste es un método comin. Lo importante es entender las diferencias entre los tipos de datos signed y unsigned, El modificador signed En los enteros, el bit mis a la izquierda se puede usar como bit de signo. Por ejemplo, si el tipo de datos int es de 16 bits de longitud y el bit mas a la derecha se cuenta como el bit 0, entonces puede usar el bit 15 como bit de signo, Cuando se le asigna 1 al bit de signo, el compilador de C sabe que el valor representado por la variable de datos es negative. Existen varias formas de representar un valor negative para los tipas de datos float 0 double, Las implementaciones de los tipos de datos float y double exceden el alcance de este libro, Para mds detalles sobre la representacién de valores negativos de los tipos de datos float y double, consulte el libro E! Lenguaje de Programacién C, de Kernighan y Rite! El lenguaje C proporciona un modificador de datos, signed, que se puede utilizar para indicarle al compilador que los tipas de datos enteros (char, int, short int y Long int) a = = at —_ a HoRA 9 Modificadores de datos y funciones matematicas Sino tiene éxito a la primera, transforme sus datos. —Leyes de Murphy de las computadoras En In hora 4, “Tipos de datos y palabras reservadas”, aprendi6 acerca de varios tipos de datos de! lenguaje C, como char, int, float y double. En sta hora aprender acerca de cuatro modificadores de datos que le permiten tener un gran control sobre los datos. Las palabras reservadas de C para los cuatro modificadores de datos son las siguientes + signed + unsigned + short. = long Uso de operadores condicionales 139) Tomando los valores de x y y asignados en el ejercicio |, eseriba un programa que imprima los valores de 1x y Ly utilizando los formatos Md y Su en la funcién printt() Dadas x = 123 yy = 4, escriba un programa que despliegue los resultados de las expresiones x <= yy x >* y. Escriba un programa que muestre los valores (en hexadecimal) de las expresiones OXFFFF*@x8B85, OXABCO & @x4567, y OXDCBA | Ox1234, Use el operador ?: y la instruccién for para escribir un programa que contintie tomando carscteres introducidos por el usuario hasta encontrar el cardcter 9. (Sugerencia: ponga la expresin xt='q' 7 1 : @ como la segunda expresién en una instruccién for.) [138 Hora & Por otra parte, |} ¢s el operador Kigico OR, y requiere de dos operandos (o expre~ siones). El operador produce @ sélo si ambos operandos se evaldan como 0, En caso contrario, produce 1 P 65) 2 "Retirado*: "Wo retirado® le indica a la computadora que si el valor de edad es mayor que 65, entonces se debe elegir Ia cadena Retirado; en caso contratin se selecciona No retirado. Ed Taller Para consolidar la comprensidin de la leccidn de esta hora, le recomiendo responder el cuestionario y terminar los ejercicios de este taller ames de pasar a la siguiente leecién Las respuestas y sugerencias se presentan en el apéndice B, “Respuestas a los cuestiona- y ejercicios”. Cuestionario 1. {Qué producen, respectivamente, las expresiones (x=1) && (y=1@) y (x=1) 8 y=18)? 2. Dadas x = 98,y = 1, yz = 69, je6mo se evalia la expresiOn ly 7 x == 2 : 3. Si tiene dos variables enteras x y y, teniendo x el valor binario 0011000000111" y teniendo y cl valor binario 1190111111@00110, ;qué valores producen las dos expresiones -x y ~y? 4, Dada x=9, ;qué produce (x%2=-@) || (x83==0)? 2¥ que produce (62==@) 8H (xNI==O) 7 5. jEs6 >> 3 equivalente a 8/2? ,Qué hay de 1 << 3? Ejercicios 1. Dadas x = OxeFFF yy = @x1@e0 (es decir, EFFF y 1908 como valores hexadeci- males), qué valores hexadecimales se obtienen al evaluar =x y -y? Uso de operadores condicionales Resumen En esta leceisn aprendi los siguientes operadores ligicos y de manejo de bits, los cuales son muy importantes en C: * El operador sizeot evalia el ntimero de bytes que tiene un tipo de datos especi- fico, Puede utilizar este operador para medir el tamafto de un tipo de datos en su maquina, + El operador ldgic AND (88) produce 1 (verdadero 16gico) slo si sus das expresiones de operandos se evalian como valores diferentes de cero. En caso contrario, produce @. + El operador l6gico OR (} !) produce @ sélo si sus dos operandos se evalidan coma 9. En caso contrario, produce 1. * El operador légico NOT (1) produce @ cuando su operando se evalda como diferente de cero, y produce 1 sélo si su operando se evalda como @. + Hay scis operadores de manejo de bits: el operador AND: a nivel de bits (8), ef operador OR a nivel de bits (|), el operador XOR a nivel de bits (*), el operador de complemento a nivel de bits (-), el operador de desplazamiento a la derecha (>>) y el operador de desplazamiento a la izquierda (<=). * El operador condicional (?:) es el inico operador en C que puede tener tres operands, En la siguiente leccién aprenderd acerca de los madificadores de tipo de datos de! lenguaje C Preguntas y respuestas P ;Por qué es necesario el operador sizeof? R El operador sizeof se puede utilizar para medir los tamaiios de todos los tipos de datos definidos en C. Al escribir un programa portable en C que necesite saber el tamafio de una variable entera, es una mala idea codificar directamente el tamaiio con base en la méquina que esté usando en ese momento. La mejor forma de indi carle al programa el tamajio de In variable es utilizar el operador sizeof, el cual produce el tamafio de la variable entera en tiempo de ejecucién. P ;Cuél es la diferencia entre | y |}? R_ | esel operador OR a nivel de bits que tiene dos operandos, El operador | compara cada bit de un operando con el bit correspondiente en otro operando. Si ambos bits son @, entonces se coloca @ en el resultado, en la misma posicién del bit, En caso contrario, se pone 1 en el resultado, 136 Hora 8 Listapo 8.7 _continuacion int x; 1 tipo de datos int tiene 2 bytes." “int no tiene 2 bytes."); printf(*EL valor maximo de int (els 2) 2 -(1 ex 8-1) return @; sain, ~(1 << 18) ); El siguiente resultado se desplegé en la pantalla al ejecutar en mi maquina el archivo O8L07.ex0: El tipo de datos int tiene 2 bytes, EL valor maxino de int es: 32767 En la linea 8 del listado 8.7 se mide primero el tamaio del tipo de datos int por medio del operador sizeot, y se asigna el nimero de bytes a Ia variable entera x. Las lineas 9 0 12 contienen una instruccién, en la cual se usa el eperador condicional (2:) para comprobar si el mimero de bytes guardados en x es igual a 2, y se imprime el resultado, Si la expresiGn x == 2 se evalia como diferente de cero, entonces la funcidn printf) de la instruccién imprime la cadena £1 tipo de datos int tiene 2 bytes. En caso contrario, se imprime en la pantalla la cadena int na tiene 2 bytes. demas, la instruccién de las Iineas 13 y 14 tata de determinar el valor maximo del tipo de datos int en la miquina actual. En la instruccién se evalda primero la expresién x tm 2, Si la expresién devuelve un valor diferente de cero (es decir, ef miimere de bytes del tipo de datos int no es igual a 2), se evalda la expresiin =(1 << x * @ - 1}, yse ‘elige el resultado como el valor de retorno. Aqui, la expresiGn ~(1 << x * 8 - 1)es una forma general para calcular el valor maximo del tipo de datos int, el cual equivale: age". 4, (Bn la seccién anterior se presentaron los operadores de complemento, =, y de desplazamiento, <<.) Por otra parte, si la condicién x t= 2 de la linea 14.devuelve @, lo cual significa que el valor de x sf es igual a 2, se elige el resultado de la expresién -(1 << 15). Aqui tal vez ya haya usted determinado que -{1 << 15) equivale a 2-1, que es el valor maximo que puede tener un tipo de datos int de 16 bits. E] resultado que se despliega en la pantalla muestra que el tipo de datos int es de 2 bytes (0 16 bits) de longitud en mi maquina, y que el valor miximo del tipo de datos int es 32767, Uso de operadores condicionales 135 La operacién del operador de desplazamiento hacia la derecha (>) equivale 3 g | dividir entre potencias de dos. En otras palabras, la instruccién xory equivale 3 nie Aqui, x es un entero ne negative. Por otra parte, el desplazamiento hacia la izquierda equivale a multiplicar por potencias de dos, es decis, xacy equivale a nea Qué significa x?y:z? Al operador 7: se le llama eperador condicional, y ¢s el nico operador que tiene operandos. La forma general del operador condicional es x?yta Aqui, x, y yz son tres expresiones de operandos. Entre ellos, x contiene la condici6n a probar, mientras que y y z representan los dos valores finales posibles de la expresién. Si x se evalia como diferente de cero (verdadero Idgicamente), entonces se elige y; en caso contrario, z es el resultado que produce la expresién condicional. El operador con- dicional se utiliza como una especie de forma abreviada de una instruccién if. Por ejemplo, expresién x0? oF se evaltia como 'T* si el valor de x es mayor que @. En caso contrario, la expresién condicional se evalia como 'F”. El listado 8.7 muestra el uso del operador condicional EEE => {* W8LO7.c: Uso del operader 2: Wincluge Uso del operador condicional main() [34 Hora 8 Asimismo, la expresién § << 1 desplaza al operando 5 un bit hacia Ia izquier duce 18 en decimal. El programa del listado 8.6 imprime més resultados por medio de los operadores de des- plazamiento. ¥ pro: Listapo 8.6 Uso de los operadores de desplazamiento I* @8L06.c: Uso de los operadores de desplazan #include main() { ant ky Ys ze x = 255; y 55 print? (*Dadas x peintt(* y peK>y; printf("x >> y produce: 86d, es decir, @XWO4X\n", z, 2}; zexey; printf("x << y produce: S6d, es decir, @xWe4X\n", 2, 2); return 0; ‘Md, 05 decir, OXWEX\N", x, x ‘Md, es decir, exMeax\n", y, y); Los siguientes resultados se desplegaron al ejecutar en mi computadora el archivo 88L06.0xe: Dadas x = 255, es decir, aXOUrF 5, es decir, axeees xy produc 7, es decir, axeo7 x << y produce: 8168, es decir, OXIFE® i) En la linea 6 del listado 8.6 se declaran tres variables enteras, x,y y 2. En la linea & se inicializa x a 255; en la linea 9 se inicializa y a $. Después, las lineas La instruccién de la linea 12 desplaza y bits hacia la derecha al operando x, y luego asigna el resultado a z. La Ifnea 13 imprime el resultado del desplazamiento realizado ‘en Ia linea 12, El resultado es 7 en decimal, o X0@07 en hexadecimal, Las lineas 14 y 15 desplazan y bits hacia la izquierda al operando x, y también despliegan ‘el resultado en la pantalla. El resultado del desplazamiento hacia la izquierda cs 8166 en decimal, 0 @x1FE® en hexadecimal. Uso de operadores condicionales 133) Las lineas 14 y 15 realizan In operacién que especifica el operador OR a nivel de bits (;) ¢ imprimen el resultado en los formatos decimal y hexadecimal. De la misma manera, las Iineas 16 y 17 dan et resultade de ta operacién que realiz6 el operador XOR a nivel de bits (*). Por citimo, 1a instruceién de 1a Iinea 18 imprime et valor complementario de x por medio del operador de complemento (-) a nivel de bits. El resultado se despliega en la pantalla -en los formatos decimal y hexadecimal ‘Observe que en ta funcién print? () se utilizan el especificador de formato entera sin signo con un ancho minimo de campo de 6, ¥6u, y el especificador de formato hexadeci- mal en maytisculas con un ancho minimo de campo de 4, 04x. Aquf se utiliza el tipo de datos entero sin signo para que se pueda mostrar y entender con facilidad el valor com- plementario de un entero. En la hora 9 se presentan més detalles sobre ef modificador de datos sin signo, No confunda los operadores a nivel de bits & y { con los operadores Jogicas Ak y |. Por ejemplo, (eT) & (y=T0) 5 una expresin completamente distinta de (rst) ak (yt) Uso de operadores de desplazamiento En C hay dos operadores de desplazamiento. El operador >> desplaza a la derecha los bits de un operando; el operador <« los desplaza hacia la izquierda. Las formas generales de los dos operadores de desplazamiento son n> y n«y ‘Aqui, x es un operando que va ser desplazado. y contiene el mimero especificado de posiciones a desplazar. Por ejemplo, la expresién @ >> 2 le indica a la computadora que desplace al operanda 8 dos bits a la derecha, lo cual produce el mimero 2 en decimal, La expresién B >> 2 que equivale a(I*2)+072+0*2'+0*2) >>2 produce lo siguiente: (0° 2402+ 1*2!40* 2%, lo cual equivale a 0010 (en el formato binario), 6.22 (en el formate decimal). 132 Hora & Observe que el valor complementatio de: 12 es 65529 debido a que el tipo de datos entero sin signo (de 16 bits) tiene el nimero maximo 65535. En otras palabras, 65,523 es el resul- lado de restar 12 de 65,535. (El modificador de datos sin signo se presenta en la hora 9, “Modificadores de datos y funciones matemticas") El programa del listado 8.5 muestra el uso de los operadores a nivel de bits. Listapo 8.5 Uso de operadores a nivel de bits 1: /* @BLOS.c: Uso de operadores a nivel de bits */ 2: include a: > main() Bf 8: int x, ¥, 2) n : x = 4321; y = $678; printf (*Oadas x = Au, es decir, @x¥O4X\n", x, x); printf (* y=, 65 decir, OxwaXin”, y, ¥)i zee ay; printf ("x & y devuelve: M6u, es decir, Oxwesx\n’, z, zexly; printt(*x | y devuelve: S6u, es decir, axweaxin", 2, BER"; printe(*x"* y devuelve: S8u, 68 decir, OXNM4X\n", 2, 2); printt(* -x devuelve: Gu, es decir, @xNedxin", x, x); return @; Los siguientes resultados se desplegaron en Ia pantalla después de crear el archivo @8L05. exe y cjecutarlo en mi maquina Dadas x = 4321, es decir, OX10E1 Ss y = 5878, es decir, OX162E x Ay devuelve: 4128, es decir, ox1028 iy a: es decir, OXtGeF x” y devuelve: es decir, Oxe6cr -« develve: es decir, OXEFIE En la linea 6 del listado 8.5 se declaran tres variables enteras, x, y y z. Las lineas 8 y 9 asignan ax y ay los valores 4321 y 5678, respectivamente. Las lineas 10 y 11 imprimen los valores de x y y en formatos decimal y hexadecimal, Los ntimeros hexa- -decimales tienen el prefijo ox. La instrucciGn de la linea 12 asigna el resultado de la operacin que realizé-el operador AND a nivel de bits (4) con las variables x y y. Luego, la linea 13 despliega el resultado -en los formatos decimal y hexadecimal. Uso de operadores condicionales 129 En la linea 10, la expresién relacional nun < 7 se evalia como @ debido a que el valor de nun noes menor que 7. Sin embargo, mediante el operador 6gico de negacidn, (num < 7) produce 1 (consulte la tabla 8.3). Asimismo, la expresisn Igica | (num > 7) se evaltia como 1 en la linea 11. La expresidn relacional nun == 7 produce 1, debido a que nun tiene el valor de 7; sin embargo, la expresién légica | (num =» 7) de Ia linea 12 se evaléa como @, Manejo de bits En las horas anteriores aprendié que los datos y archivos de la computadora estdin hechos de bits. En esta seccidn aprender’ acerca de un conjunto de operadores que le permite an tinuar, més acerca de 128 Hora 8 El operador ldgico NOT (!) El formato general del operador lgico NOT es: lexpresisn en donde expresién ¢s el operando del operador NOT. En la tabla 8.3 se muestra la tabla de verdad del operador NOT. Tanta 8.3 Los valores que devuelve el operador NOT expresion Valor que dewelve ! diferente de cero ° 1 ‘Veamos ahora el ejemplo del listado 8.4, el cual muestea c6mo usar el operador ligico NOT, o de negacién, (1). Listapo 8.4 Uso del operador Iégico NOT (!) #* @BLO4.c: Uso del operador 16gica NOT */ finclude 1" a: a: 4: main() Bt 6: int nun; r 8 mum = 7; 8 printf (‘Dado num = Tha"); 1@: —printf(“I(num < 7) produce: Sdim", 1 num < 7); 44: printf(*t(num > 7) produce: din", 1(num > 7); 12 13) printf(*!(num == 7) produce: Sd\n*, !(num == 7); return @ Los siguientes resultados se desplegaron al ejecutar el archivo 88L04. exe: Dado nun = 7 BE rey produce: 1 rum > 7) prod {num == 7) produce Observe que en la linea 8 se inicializa la variable entera num a 7, lo cual es. desplegado después por Ia funcién print () de la linea 9. Uso de aperadores condicionales 127 nain() q int Aun; printf(*Introduzca un entero entre @ y 9 que se pueda \ndividir entre 2 y entre 3:\n*); 8: for (num = 15 {mumk2 I= 8) f) (numAS t= 8); 10 fun = getchar() - 11: printe(*i@ient EL entero es: Win", num); 12; return @; 13) Los siguientes resultados se desplegaron después de ¢jecutar en mi maquina el archivo 08L03.exe, Los mimneros en negritas son los que yo introduje, (Es necesario oprimir la tecla Entrar cada vez que se intreduzca un nimero.) En ¢l rango del 0 al 9, 0 y 6 son Jos Gnicos nimeros que se pueden dividir tanto entre 2 como entre 3 sin producir residuo’ Introduzea un entero entre @ y 8 que se pueda dividir entre 2 y entre 3: 2 GiBien! El entero es: 6 una variable entera, num, La linea usuario que introduzca un entero entre 0 y 9. En Ia linea 6 del listado 8.3 se dec! imprime dos Iineas que solicitan La variable entera num se inicializa en la primera expresién de la instruccién for de la linea 9_ num se inicializa con 1 debido a que 1 no es divisible entre 2 ni entre 3. De este modo, se garantiza que el ciclo se ejecute por lo menos tna ver. La parte clave del programa del listado 8.3 ¢s la expresion kigica de la instruceién for: (numi2 = 9) }! (numa I= a) Aquf se evalian las dos expresiones relacionales qum2 t= 0 y num3 l= 9, De acuerdo con la tabla de verdad del operador + (vea la tabla 8.2), usted sabe que si una de Las. expresiones relacionales se evalda como diferente de cero, 10 cual indica que él valor de num no se puede dividir entre 2 o entre 3, entonces la expresidn l6gica OR se evalda como 1, to cual permite que el ciclo for contintie, E| ciclo for se detiene sélo si ¢l usuario introduce un entero entre 0 y 9 que sea divisible entre 2 y entre 3. En otras palabras, cuando ambas expresiones relacionales se evalian como 8, el operador lgico OR produce , lo cual ocasiona la terminacién del ciclo tar. 126 Hora & num == 0 también produce 1. Entonces, de acuerdo con la tabla de verdad del opera- dor a8 (ea ta tabla 8.1), usted sabe que la combinacién del operadar légico AND (88) con las dos expresiones relacionales produce 1 si ambas expresiones se evaliian como diferentes de cero, En caso contrario, produce 0. En nuestro caso, cuando nun se inicializa a en la linea 8, tanto ©%2 como 3 producen residuos de cero, asf que las dos expresiones relacionales se evaldan como 1. Pot lo tanto, el operador I6gico AND produce 1. Sin embargo, cuando a nun se le asigna el valor de 2 @ 3. como se muestra en las Iineas I y 14, los operadores ligicos AND de las Iineas 13 y 16 producen 0. La razén es que 2 y 3 no se pueden dividir entre 2 y 3, respectivamente, y obtener un residuo, La linea 17 asigna luego el valor de 6 a num. Ya que 6 ¢s un mdltiplo tanto de 2 como de: 3, e] operador légico AND de Ia linea 19 produce 1, el cual es impreso por la funcién printf () de tas Iineas 18 y 19. El operador ldgico OR (|; ‘Como mencioné antes, el operador kigico OR produce 1 (verdadera 16gicanente) si una © ambas expresiones se evalian a un valor diferente de cero. E operador |; produce 0 si, y s6lo si, ambas expresiones producen @ Un formato general del operador Idgico OR es: expt |! exp? en donde exp? y exp2 son dos expresiones de operandos que evalda el operador OR. La tabla 8.2 es Ia tabla de verdad del operador OR. Tasta 8.2. Los valores que devuelve el operador OR expt exp2, Produce Giferente ce cero diferente de cero diferente de cero 1 ° diferente se cera 1 . a * El programa del listado 8.3 muestra cémo usar el operador I Lra00 1: /* @BLOG.c: Uso del operador Logica OR */ 2: Winclude OR (; }). Uso del operador légico OR (: 1) Uso de operadores condicionales 125) El listado 8,2 es un ejemplo del uso del operador légico AND (88). Listavo 8.2 Uso de! operador ldgico AND (88) J* @BLO2.c: Usa del operador 6gico AND */ #include in() int nus nun = printf("El operador AMO produce: ‘din’, (num == 0) && (numkd == 0}); rum = 25 printf ("El operador AND produce (oumk2 == @) a8 (auass rum = 35 printf ("El operador AMO produce: sdin*, (numk2 == 6) 48 (nueAd == 0)); um = 6; printt(*EL oper (rum Soin, ns jor AND produce: Sin", @) 8 (mums == 0)); return 0; Después de compilar y enlazar este programa, se crea un archivo ejecutable, @8L@2.exe. Los siguientes resultados se. desplegaron en Ia pantalla después de ejecutar dicho archivo en mi méquin EL operador AND produce: EL oparador aN produce: EL operador AND produce EL operador AND produce: En la linea 6 del listado 8.2 se declara una variable entera, nun, y se inicializa por primera vez en la linea 8. Las lineas 9 y 10 imprimen el valor que produce el operador ldgico AND en la siguiente expresi (numa == @) 84 (umes == @) Aqui ve dos expresiones relacionales, numt2 == @ y nuns == 0, En Ia hora 3, “La es- tructura de un programa de C”, aprendié que se puede usar el operador aritmético * para obtener el residuo de la divisién del primer operando entre el segundo, Por Io tanto, numi2 produce el residuo de nun dividido entre 2, La expresién relacional nunk2 == @ produce 1 siel residuo es igual a @, es decir, el valor de num se puede dividir entre 2 sin dejar residuo, Asimismo, si el valor de num se puede dividir entre 3, la expresi6n relacional 4 Hora 8 Todo es ldgico Es el momento de aprender acerca de un nuevo conjunto de operadores: los operadores ligicos. En el lenguaje C hay tres operadores légicos: 4&8 —_El operador légico AND 11 Bloperador Iigico OR ! El operador kigico NOT Los dos primeros operadores, AND y OR, son operadores binarios; es decir, ambos tienen dos operandos (uno a la izquierda y otro a la derecha del operador), El operador Igico AND (88) se usa para evaluar la veracidad o falsedad de un par de expresiones. Si ambas expresiones se evaliian como @ (es decir, falsas légicamente), el operador produce un va- Jor de ®. En caso contrario, si, y s6lo si, las expresiones de ambos operandos se evaldan ‘como valores diferentes de cero, el operador I6gico AND produce un valor de 1 (verdadero Végicamente), El operador légico OR (; |) produce un valor de 1 cada vez que una o ambas expresiones de los operandos se evalian como diferentes de cero (verdadero I6gicamente), El opera- dor || produce @ slo si ambas expresiones de los operandos se evaliian como cero (falso).. El operador I6gico NOT (1) es un operador unario; es decir, s6lo tiene un operando (1a expresi6n a su derecha). Si el operando se evalda como un valor diferente de cero, el operador 1 produce © (falso Iégicamente); s6lo cuando la expresiéin del operando se evalia como 8, el operador produce 1 (verdadero légicamente). Las siguientes tres secciones contienen ejemplos que le muestran cémo usar los tres ‘operadores légicos. El operador Iégico AND (aa) ‘Un formato general del operador Iégico AND es: exp! 84 exp2 en donde expt y exp? son dos expresiones de operandos que evaltia el operador AND. ‘Una buena forma de entender el operador AND es observar una tabla que miiestre los ‘valores que produce él operador AND dependiendo de los valores posibles de expt y ‘exp2, Vea la tabla 8.1, a la cual podemos llamar tabla de verdad del operador AND. ‘Tata 8.1. Los valores que devuelve el operador AND exp! exp2 88 Produce Wiferente de cere Giferente de cero 7 diferente de cero 8 a diferente de cera a 8 eee Uso de operadores condicionales 123) printf (*EL tanafo de double es: printf(*E1 tanano de db1_num 6: Ad bytes\n', sizeot (double}); 0 bytes\n*, sizeof db1_num); Después de compilar y enlazar este programa, se cred ¢l archivo ejecutable #8L01 exe. Los siguientes resultados se imprimieron en la pantalla después de ejecutar dicho archivo ‘en mi maquina: El tamafio de char es: 1 byte El tamafio de ch es: 1 byte El tamafo de int es: 2 bytes El tamafo de int_num es: 2 bytes El tamafio de float es: 4 bytes El tamafo de flt_num es: 4 bytes El tamafio de double es: 8 bytes El tanafio de dbl_aum es: 8 bytes La linea 2 del listado 8.1 incluye el archivo de encabezado stdio.h para la funcién printf () que se utiliza en la instruccién que esté dentro: del cuerpo de la. funciGn main () Las lineas 6 a 9 declaran una Variable de tipo char (ch), una variable de tipo int (int_eum), una variable de tipo float (f1t_nus) y una variable de tipo double (db1_num), respectiva- mente, Adems, se inicializan estas cuatro variables. Observe que en la linea 8, el valor inicial para £1t_num tiene una f como sufijo para especificar Float. (Como aprendié en ta hora 4, puede utilizar ¢ 0 F para especificar el tipo float de un niimero de punto flotante.) Las lineas 11 y 12 despliegan el tamafio del tipo de datos char, asf como él de la variable ch de tipo char. Observe: que el operador sizeof se usa tanto en Ia linea 11 como en la 12 para obtener el mimero de bytes que pueden tener el tipo de datos char o la variable ch. Debido a que la variable ch no ¢s una palabra reservada en C, en la linea 12 se omiten los paréntesis del operador sizeof. Las instrucciones de las Ifneas 11 y 12 imprimen las dos primeras lineas de los resultados, respectivamente. Puede ver en los resultados que el tamafo del tipo de datos char es de | byte, que €s el mismo tamaio de la variable ch. Esto no es ninguna sorpresa, ya que la variable ch esta declarada como de tipo char. De la misma manera, las Iineas 13 y 14 imprimen los tamafios del tipo de datos int y de Ia variable int_nus de tipo int utilizando el operador sizeof. Puede ver que el tamaiio de ambos es de 2 bytes. Asimismo, utilizando el operador sizeof, las Ifheas 15a 18 proporcionan el tamafio del tipo de datos Float, el de la variable f1t_num de tipo float, el del tipo de datos double y el de Ia variable ab1_num de tipo double, respectivamente. La seccidn de salida muestra que el tipo de datos float y la variable #1t_nun tienen el mismo: tamafic (4 bytes). El tamafio del tipo de datos double y de la variable ob1_nua es, en ambos casos, de 8 bytes. 122 Hora 8 Cémo medir el tamanio de los datos Tal vez recuerde que en la hora 4, “Tipos de datos y palabras reservadas”, mencioné que cada tipo de datos tiene su propio tamafio. El tamaiio de los tipos de datos varia dependien- do del sistema operativo y del compilador de C que utilice. Por ejemplo, en la mayoria de las estaciones de trabajo de UNIX, un entero tiene una longitud de 32 bits, mientras que la mayorfa de los compiladores de C s6lo mangjan 16 bits en una maquina basada en DOS. ‘Asi que, ,cbmo puede saber el tamafio de un tipo de datos en su méquina? La respuesta es que puede medir el tipo de datos por medio del operador sizeof que proporciona C, La forma general del operador sizeof es sizeof (expresidn) Aqui, expresién es el tipo de datos o variable cuyo tamafio es medido por el operador sizeof. El operador sizeof evalia el tamafio, en bytes, de su operando. El operando del operador sizeof puede ser una palabra reservada de C que represente a un tipo de datos (como int, char 0 float), 0 puede ser una expresién que se reficra # los tipos de datos cu- yo tamaio se puede determinar (como una constante o ¢l nombre de una variable), En la forma general del operador los paréntesis son opcionales. Si la expresiéia no es una palabra reservada de C para un tipo de datos, se pueden omitir los paréntesis. Por ejemplo, la siguiente instruceisn tamanio = sizeof (int); coloca el tamafio, en bytes, del tipo de datos int en la variable tanania. El programa del listado 8.1 encuentra los tamafios de los tipos de datas char, int, fleat y doubie en mi miquina, ec Listao 8.1 Uso del operador sizeof : Uso del aperador sizeof */ char ch = * int ant_nun float flt_nun double bl_nue = 18 11: printf(*EL tanaho de char es: %d bytein", sizeof(char)); 12; printf(*€L tanafio de ch es: ‘d byte\n", sizeof ch ); 13; printf ("EL tanaho de int es: %d bytesin", sizeof{int)); 14: printf("EL tanafho de int_nun es: §d bytesin", sizeof int_nun); 15: printf ("EL tomaho de float es: ‘d bytes\n", sizeof(float)); 16: printf("E1 tanafho de flt_nun es: %d bytes\n", sizeof f1t_nu HoRA 8 Uso de operadores condicionales La civilizacién avanza amplianda el riimera de operaciones importantes que podemas realizar sin pensar en ellas —A.N. Whitehead En la hora 6, “Manejo de datos”, aprendié acerca de algunos operadores: importantes de C, como los operadores de asignacién aritmética, él operador unarie menos, u operador de negacién, los operadores de incremento y decremento y los operadores relacionales. En esta leccién conocera mas ‘operadores que son muy importantes en la programacién en C, incluyendo * El operador sizeof * Los operadores légicos * Los operadores de manipulacién de bits * El operador condicional ()803 eaeuing aajs0A9p anb opeymsas [9 uaumdan (ZA QZ sou] se sugisenuTUOD y JOPESOAUT [E EUINS B] SAPSNADP K #4 STT UD SOUR]UD sOIUDUID]> 40] SOpOr tums ()Soregeung enb ‘gp @ Ze seaUTT SE ap ()SOIEGeUNG UDISUNG EY ap UOLOAUEISP FL ua 224 apang ‘O1SIU 9p ULADANp F] Bp as aiuaWRIOS 1s OFZau [ap oRURr) [2 sPURMIZAp apand ou upyauny By onb 8 apigap wz1[NN as xew CYuaWNgUe [gy “eIS¥T OfFaue [2 10d Sopfuamuos souawafa ap oWTxpH OXAUIDU [a S9-anb *s uOS onl *() soxedeuns UOLUTY vy e eed as aur-vade sopemunde jo *[z wou] ef ua ‘Oden wut wade axUe sopriunde Te E2857 Cuoqua ofan [ap O1ONH ap UO!22aNP E| LUISE G| OU] E| ap UOIIMNSUL E| “opfaue [ap asquiou jap orpaui sod ()uodur & wsed 9s saua1 -ouma ap o[Saum [ap o1{u; ap upPpoarp vf anb ensanw g] aus] ey “A )uodwE UpISUNY RY opesed < ouawndie woo eueped ofFaure [ap auquiou | opuesn smNzos apand “oy20y aq] ‘QugduT worsuny F] 9p onuep ‘omstr -niiim owos upiouny o] v esd as o1>1u! ap upIasauIp wknd ‘euaped offaum jap opDTuOD Jo sunaduny 67 rouge] ap OsauTad e epeMET eT ‘Og & LZ Sea Su ap CHuodur ap uproTE “ap ¥L UOO opsanse 3q] "ST wAUH| B| ap () UOdUE UHOUNY vB OTHDWNEZE OWOD esed 9s suspeo”42de Jopeiunde [2 “sgndsaq “p] F2uH] &] 2p UgIOEUaISE ap USLONASUT B] SUEIP

You might also like