Está en la página 1de 153
LENGUAJE DE PROGRAMACION BRIAN W. KERNIGHAN DENNIS M. RITCHIE EDICION EN INGLES [UNIX 5 una marea resistrada AT&T EL LENGUAJE DE PROGRAMACION € Tradlucido de la segunda edition en inglés de: ‘THE C PROGRAMMING LANGUAGE al o parcial de este obra, por cualquier medio 0 método, ior DERECHOS RESERVADOS © 1991 respecto a Is segunda edicion er espaitol por PRENTICE-HALL HISPANOAMERICANA, S.A. ‘Alzccmaieo Nit, S00-5* Piso Col Industrial Atouo 53519, Naucalpan de Jude, Blo. de México ‘Miembro de la Cémara Nacional de la Industria Editorial, Reg, Nam, 1524 ISBN 968-880-205-0 ISBN 0-13-110362-8 IMPRESO EN MEXICO / PRINTED IN MEXICO Prefacio Prefacio a Ia primera edicién Introduccion Constantes simbélicas Entrada y selida de caraeteres Arreglos Funciones Argumentos—llamada por valor Tipos y tamatios de datos Constantes Declaractones Operadores avitmeticos Operadores de velacion y loyicos Conversions de tipo ‘Operadores de incremento y deeremenco Operadores para mancjo de bits 3.5 Cielos—while y for 35 Ciclos—do-while CONTENIDO ay ilo 4, Functones Conceptos Funciottes que restesan valores no-enteros El preprocesador de € jlo S. Apuntadores y arreglos ‘Apuntadores ¥ direcciones ‘Apuntadores y argumentas de funciones Apuntadores y arregles Atitmetica de diteceiones Apuntadores a caracieres y funciones ‘Anreplos de apuntadores; apuntadores 4 apuntadores reglos multidimensionales Inicinlizacion de arceglos de apuntadores iG egl0s multidimensionales ‘Conceptos basicos sobre estructuras Estructuras y funeiones ‘Arreglas de estruciuras ‘Apuntadores o estructures Estructuras autorreferenciadas ‘ilsqueda en tablas ‘Typedet Uniones Campos de bits Capitulo 7. Fateada y salida 2 Envcada y salida estindar Salida con formato—printt Listas de argumentos de longitud variable Entrada con formato—scant ‘Acceso a archivos Mancje de errores—stdett y exit 7.7 Entrada y salida de tineas 118 tras tnciones Capitele 8. La imtertaz det sistema UNIX Apéndice A. Manual de referencia ‘AL Introduccion ‘A2 Convenciones 16xieas ‘Ad Notacidn sintéeticn ‘Ad Sipnificado de los identiticadores AS Objeios y valores-t ‘AG Conversiones AT Expresiones AS. Declaraciones AY Proposiciones AIO. Declaraciones externas ALB Gramética Apéndice B. Biblioteca estindar BI Entrada y salida: B2_ Pruebas de clasficacion de caracteres: Apéndice C. Resumen de moditicaciones Prefacio El mundo de la computacion ha sufrido una revolucién desde la publicacion, en 1978, de El enguaje de programacién C. Las grandes computadoras son aho- ra mucho mas grandes, y las computadoras personales tienen capacidades que ri- valizan con los mainframes de hace una década én el lenguaje C ha imbiado en ese tiempo, alla de io que fueron sus La ereciente popularidad de C, los cambios en el lenguaje a Io larga de los aflos, y la creacién de compiladores por grupos no im en su disefto, se combinaron para demostrar Is necesidad de ui cisa y contempordnes que la que proporci Elestandar formaliza consirucciones sugeridas pero no descritas en le primera edicién, particularmente la asignacion de 1 y las enumeraciones. Pro- porciona wna nueva forma de declaracion de y uso. Especifica una bibl lizar la encrada y salida, mpo establece exp! ia de maquina. n de Et enguaje de programacién icas eriticas, como los apuntadores, que son parte central en la progra- -Hemos redefinido los ejemplos originales y agregamos ejemplos nuevos en varios capttulos. Por ejemplo, se aumenté el tratamizmio de declaracio- ines complicadas con programas que convierten declaraciones en palabras y vice- versa. Como rdos los ejemplos se han probado direstamente @ partir del seflado de manera que lo pueda leer la maquina. ladares —ese pay es un resumen de las posi pdsito de ser una relerenicia para programaderes, no para implantador: apéndice C se ofrece un resumen de los cambios de la versién original, - Deseamas que como usatlo, roy, Peter cada pagina del bo- la culdadosa lectura de Al , Karen Fortgang, Allen Ho- Tohn Linderman, Dave Prosser, Gene Spaf- ford, y Chris Van Wyk. También recibimos utiles sugerencias de Bill Cheswick, Mark Kernighan, Andy Koening, Robin Lake, Tom London, Jim Reeds, Clovis lo y Peter Weinberger. Dave Prosser cespondié muchas preguntas detalladas del estindar ANSI. Utilizamos extensivamente el intérprete de C++ de Bjarne Strousteup, para la prueba local de nuestros programas, y Dave Kristol Brian W. Kernighan Dennis M. Ritchie Prefacio a la primera edicién 1 lenguaje de programacién de propésito general que ofrece como ven- de expresidn, control de flujo y estructuras de datos modernos uaje de “muy alto ni- especial de aplicacién rema operativo, el compila- ss de aplicacién de UNIX Gncluyendo existen compiladores para la produccién en otras méquinas, incluyendo la [BM System/370, la Honeywell 6000 y la Inerdata 8/32. El lenguaje C no esta ligado ‘aningiin hardware o sistema en p ran sin cambios en cualquier maquina que mangje C 1a finalidad de este libro es ayudar al lector a apcentler eémo programar en ©. Contiene na introduccion general para hacer que fos nuevos usta cien lo mas pronto posible, capitulos separados sobre cada caracteristica impor- tante y un manual de referencia, La mayoria de las exposiciones estan basadas ena lectura, escritura y revision de ejemplos, mas que en el simple esta Jos ejemplos son programas reales y completes, no fragmentos sislados. Todos los ejemplos han sido probados direstamente a partir del texco, el cual esta en form: para la maquina. Ademas de demostrar ‘eémo hacer un uso efectivo del lenguaje, donde ha sido posible, tratamos de ilus- y cise. El libro no es tun manual de introduceién a la programacién; se supone en él iaridad con los coaveptos bisicos de programacién, como variables, propo- Siciones de asignacién, ciclos y funciones. No obstante, un programador novato Ueber ser capaz de leer y obtener los concepts del lenguaje, aunque fe ayudaria | cooperacién de un colega més experimen De acuerdo con nuestra experiencia, Cha demostrado ser un lenguaje agrada le, expresivo y verstil para una amplia variedad de programas. Es fail de apren- der y se obtienen mejor dos a medida que aumenta nuestra experiencia Con €1, Deseamos que este libro le ayude al lector a usarlo correctamente. lar y es fdcil escribir programas que corre- All PREFACIOA LA PRIMERA RDICION ‘Las critieas y sugerencias de muchos amigos y colegas han aumentado muchi- de este libro y ha sido un placer escribirlo. En particular nues- ‘4 Mike Bianchi, Jim Blue, Stu Feldman, Doug Mellroy, Bill in y Larry Rosler que leyeron cuidadosamente las numerosas ‘versiones. También agradecemos A] Aho, Steve Bourne, Dan Dvorak, Chuck Haley, Debbie Haley, Marion Harsris, Rick Holt, Steve Johnson, John Mashey, Bob Mitze, Ralph Muha, Peter Nelson, Elliot Pinson, Bill Plauger, Jerry Spi- vack, Ken Thompson y Peter Weinberger por sus valiosos comentarios a través, de varias etapas; a Mike Lesk y Joe Ossanna, por su invaluable ayuda en la im- presion, Brian W. Kernighan Dennis M. Ritchie Introducci6én (Ces um lenguaje de programacion de propésito general que ha sido estrecha- mente asociado con el sistema UNIX en donde fue desarrollado puesto que tanto el sistema como los programas que corren. en él estan escritas en lenguaje C. Sin embargo, este lenguaje no esta ligado a ningin sistema operativo ni a ninguna miiquina, y aunque se le Hama “'lenguaje de programacidn de sistemas” debido iad para escribir compiladores y sistemas operativos, se utiliza con igual Muchas de ls ideas importantes de C provienen del lenguaje BCPL., desarro- llado por Martin Richards. La influencia de BCPL sobre C se contin ct ‘mente través del lenguaje B, el cual fue escrito por Ken Thompson en 1970 para er sistema UNIX de la DEC PDP-7, BCPL y B son lenguajes “carentes de tipos". En contraste, C proporciona una variedad de tipes de datos. Los tipos fundamentales son caracteres, enteros ‘yniimeros de punto flotante de varios tamafios. Ademis, existe una jerarquia de tipos de datos derivados, creados con apuntadores, arreglos, est nes, Las expresiones se forman a partir de operadores y operandos; expresién, incluyendo una asignacién o una llamada a funcin, pucde 5 in. Los apumtadores proporcionan una aritmética de direcciones Pendiente de la méquina. C proporciona las coastrucciones fundamentales de control de flujo ‘uieren en programas bien estructurados: agcupacion de propo a de un caso entre un conjunto de con Ja condicién de paro en la parte superior (wile, inferior (do), y terminacién prematura de eiclos (break). Las funciones pueden regresar valores dei © apuntadores. Cualquier funcién puede ser Fables locales 30 ‘ocacion. La definicidn de una funcidn no puede estar anidada, pero las var Dueden estar declaradas en una modalidad estrueturada por blogues, Las func ss den programa en C pueden existir en archivos fuente separudos, que se com bila de manera separada. Las variables pueden ser intermas a una funcién, externas pero conocidas solo dentro de un archivo fui completo, 2 awimopvecion Un paso de preproce: programa, inclusion de ro es peyora- 0 tipe de objetos que la mayo Ces.un lenguaje de ret a, simplemente significa que C pueden ser combinadé splantados por méquinas reales jorciona operaciones para tratar directamente con objetos compues- reglos. No existen ope- jables locales de lea > en s! mismo no proporciona capacidades de en- mies READ o WRITE, ni métodos propios de deben ser proporcionados fat no hay propos vas. Todos esos mecanismas de alto, ofrece un control de flujo france, y lineal: pero no multiprogramacion, capacidades puede parecer como una wei para compa. lenguaje de un tamaiio modesto mnle pequefio, se puede describir HL LENGUAIE DEPROGRAMACIONG 3 Existen otros cambios de menor escala en el nguaje. La asignacién dk ‘operativo (por ejemplo, leer de archivos ye ignacién de memoria, manipulacién de cade elecucion (rant ‘uefa. Las funciones de la plitita, de manera que se puc puede eseribirse en C, y excepto poi extores de tipo, y no hay conve Sin embarga, C mejores. A pesar de todo, C ha probado ser un lenguaje extremadamente efectivo y expresivo para una amplia variedad de programas de aplicacién, El libro esta organizado como sigue. El capitulo 1 es una intcoduccién orien- tada ala parte central de C. El propdsito es hacer que el lector se inicie tan pronto ‘como le sea posible, puesto que creemos firmemente que lz forma de aprender tun nuevo lenguaje es escribir programas en él. La introduccién supone un conoci- snto practico de los elementos basicos dc la programacion; no hay una explica- cidn de compntadoras, de eompilaci6n, ni del significado de una expresion como n=n+1, Aunque hemos tratado de mostrar s de programacion en donde fue posible, la intencién del libro no ¢s la de ser un texto de vonsulta sobre joritmos; cuando nos vimos forzados a hacer una elec- in, nos hemos concentrado en el lenguaje. En los capitulos del 2 al 6 se discuten varios aspectos de C en mayor detalle rmalmente de lo que se hace en el capitulo 1, aunque el énfasis esté atin en los ejemplos de programas completos, mas que en fragmentos aislados. El ca- 2 trata de los tipos bisieos de datos, operaciones y expresiones. El capitulo ‘rata sobre control de flujo: iFelse, switch, while, for, etc. En el capitulo 4 se cubren funciones y la estructura de un programa —variables externas, reglas es ¥ otras aspectos— y también abarca al pre- een estndar, la cual proporeiona una i Esta biblioteca esta definida por e! estindar todas Jas maquinas que manejan C; as ‘eramas que la usen para entrada, salida y otros accesos al sistema aperativo se puedan transportar de un sistema a otro sin cambios. wgramas en Cy el sistema ope -indose en entradla/salida, el sistema de archivos y la asig- jue algo de este capitulo es especifico de sistemas UNIX, sen otras sistemas de todas maneras encontraran aqui Juyendo alguna comprensién acerca de cémo esté implan- 5 como sugereneias para obtener un js Ia semantica de C es en si el rincipalmente pensado sobre el lenguaie. capitulo; Introduccion general rapido como sea posible al punto cn donde pueda escri erlo tenemos que cot sduccion, por su breyedad, puede también ser e: cjemplos no utilizan la potencia completa de C, no sot veramacién, Los principiantes deben complementarlo ias semejantes & los agui expuestas. Ambos grupes pi lo como un marco de referencia sobre el cual as idas que comienzan en el capitulo 2. 1.1. Comencemos forma de aprender un nuevo lenguaje de program: rama por csc Inprime tas petatoras ‘ola, mundo 8 INTRODUCCIONLENERAL ‘ Este es et gran obsticulo; rarlo debe tener la habilidad de erear del programa de alguna mai a donde Tue n C, el programa para escribir “hola, mand. tinclude La forma de ejecutar este programa dopende del sistema que se esté utilizan- do. Como un ejemplo especifico, en el 10 UNIX se debe crear el como hela.c, ¥ después Si ng se hu cometido algin error, como la omisidn de un caract hard sin emitir mensaje al i se ejecuta a.out es hola, mundo En ottos sistemas, las reglas serén diferentes, consiltelo con un experto. Ahora algunas explicaciones acerca del programa en si. Un programa en C, cualquiera que'sea su tamafio, consta de funciones y variables . Una funcién con- proposiciones que especifican las operaciones de célculo que se van a reali- \dos durante los cdiculos. Las fun« antes a Jas subrutinas y funciones de Fortran o a les es de Pascal. Nuestro ejemplo es una funcién Hamada bertad de dar cualquier nombre dese, especial —el programa comienza a ejecutarse al principio de ‘ode programa debe tener un main en aleun sitio Por lo comiin main llamard a otras funciones que ayuden a realizar su traba- algunas que usted ya escribi6, y otras de bibliotecas.eseritas previamemte. La era linea del programa, include ealdio.h> ioteca estan ipio de muchos archives fuente lo 7 yen el apéndice B. indica al compiladar dar de entrada/salida; esta linea aparece al py de C. La biblioteca estandar esta descrita en el capi SOCIOL Los paréntesis q\ # inclade sain( } EI primer prog esti después del nombre de la ‘main esté de indieado por la main Hama ala funciéie do biblioteca pri para escribir esta sec \a representa ef car de caraeteres; fer nueva tne yrama en C Las proposiciones de una fan ign main s6lo contiene una proposicién, impresién al \u (un experimento que vate la ues de la impresion. Se debe ut vA linea en el argumento de printf; s) estat encerradas entire Haves { }. La fun- pena), encontrar que no hay avance \n para incluir un eardeter nue enta algo como BmTRoDuCCION GENERAL carat: printf nunea proporciona una nueva linea automdticamente, de manera que se pueden utilizar varias llamadas para construir una linea de salida en ctapas. Nuestro primer programa tambien pudo haber sido escrito ee la #inclade Nétese que \n representa mn solo cardcter. Una secuencia de escape vomo \n un meeanisimo general y extensible para representarcarnctere invisi ue € proporciona estén \t para tabula. \\ para la diagonal inverts, Hay una on, \b para retroceso, \" para com ta completa en la seccidn 2.3 Bjercieio 1-1. Ejecute el programa “hola, mundo" en su sistema. Experimente con Ja omision de partes del programa, para ver qué mensajes de error se obtietien. C Ejercicio 1-2, Experimente el desclibrir qué pasa cuando la cadena del argumento de printf contiene \c, en doade c es algiia cardeter no puesto en lista anterior- mente, 1.2 Variables y expresiones aritméticas liza la formula °C = ($/9) (°F-32) para imprimir turas Fahrenheit y sus equivalentes centigrados 0 SECCION 12 240 115 Sahrenbeit-Colsius , 20, 200 »/ fe inferior de la tabla de temperaturas «/ le superior «/ smaio del inoremento +i Jahr = lower; while (labs < = upper) ( far = fake + step; Las dos lineas {1 imprime la tabla Fahrenheit-Celsius para fahr = 0, 20, ..., 900 «/ brevemente lo que hace el progray ados par el co! ograma mis facil en blanco, un tabulador o nueva linea, En C, se deben declarar todas las variables antes de su Principio de la funcién y antes de cualqu: efecu a las propiedades de una variable; consta de un nombre de es, como int far, eolsiue, int lower, upper, step; 10 INTRODUCCION GENERAL ner smo de float depende de la maquina quese 2768 y +3267, son ativos una magnitud generalmente entre ma varios tipos de datos basicos, incluyendo: double punto flotante de dobie precisiin Los tamahos de estos objetos tambidn dependen de la maquina. Tambign existen carreglos, estructuras y uniones de estos tipos bisicos, apuntadores ellos y funciones que regresan valores con e:0s tipos, todo lo cual se vera en e! momento oportuno. ‘Los calculos en el programa de conversion de temperaturas prineipian con las proposiciones de asignaci@n. lower = 05 sper = 300; step = 20; {abr = lower; que asignan a las variables sus valores iniciales. Las proposiciones individuales se terminan con punto y coma. Cada linea de Ia tabla se calcula de la misma manera por lo que se utiliza una se repite una ver por cada linea de salida; este es el propésito del while (fshr <= upper) { gue uppex), el cuerpo del ciclo Luego la condicién se prueba nue- el cuerpo se ejecta de nuevo. Cuando la prueba resul- jahr excede a upper fermina, y la ejecucién continua en la proposicion que sigue al ciclo, No existe ninguna otra proposicién en este progra- ‘ma, de modo que termina. El cuerpo de un while puede tener una 0 més proposiciones encerradas entre aves, como en el convertidor de temperaturas, o una sola proposicién sin Haves, SHeCION VARIABLES YEXPRESIONES ARITMETICAS. 11 La mayor parte d se calcula y ive que (05 valores de los das enteros fab y celsius sean escritos, con una tabu estiindar de Funciones que esta accesible normalmente a los programas en C. Sin embargo, el comporiamiento de printf est que sus propiedades deben ser las mismas e gue se apegue a él, 12 wTRODUCEIOW GENERAL caprres ten un par de problemas con el prourama de conversidn de temperaturas jea debido a que los printh868d %6d\n", lahr, celsius); i el primer miimero de cada segunda en un campo de si 7 mm 6 40 4 o 6 0 2 10037 El problema mas grave es qué debido a que se ha utilizado ar tcros, las temperaturas Celsius no son muy precisas; por ejemplo, 0°F es en rea~ lidad aproximadamente —17.8°C, no —17, Para obtener soluciones mis preci- sas, se debe utilizar aritmética de punto flotante en lugar de entera, Esto requiere de algunos cambios en el programa, Aqut estd una segunda versién: # include /+ imprime Is tabla Fokrenkewt Celssas para labr = 0, 20, } versién de punto tlotante +/ t lower = 0; ‘upper = 300; step = 20; seoc1oN 12 \VARIAGLES Y EXPRESIONES ARIIMETICAS 13 excepto que far y celsius estin deel formula de conversion est eserta en una forma mis natural, i debido a que la divisidn entera lo trunearfa a cero, Sin embargo, un punto decimal en una constante indica que ésta cde puinto flotante, por lo que 8.0/8.0 no se trunce debido a que es una celacién de dos valores de punto flotante. Si un operailor aritmético tiene operands entero, se ejecuta una operacion cntera, Si un eperador numérico tiene un operando de punto flotante y otro ente- ro, este Gliimo serd eonvertido a punto flotante antes de hacer 1a operacién. Si to jera esctito fahr — 32, el 32 seria convertido automaticamenie a .¢, Escribir constantes de punto floranie con puntos decimales ext res enteros, destaca su naturaleza de punto flotante para Las reglas detalladas de cudndo los enteros se convierten @ punto flotante se ‘encuentran en el capitulo 2. Por ahora, nétese que la asignacion fahr = lower; Ja prueba while (lake <= upper) también trabajan en la forma natural — tuarse la operacién. La especificacion de conversiém %3.01 del print! incl rimero de punto flotante (en este caso fahx) por lo menos c« sin punto decimal y sin digitos fraccionarios; 966. se convierte a float antes de efter: o 178 2000-87 40 44 ‘a amplitud y ta precisién pueden omitirse de una especi el alimero es por lo menos de seis caracteres de ancho; %. después del punto decimal, pero el ancho no esta restringido; y %f unicamente indjea escribir el niimero como punto flotante. tea scribe como entero decimal 66 cseribe como entero decimal, por lo menos con 6 caracteres de amplitud ot ceseribe como punto flatente a6 escribe como punto flotamte, por lo menos con 6 caracteres de amplitud 6.1 ceseribe como punto flotante, con 2 ex de %6.2t —_eseribe come punto flotante, por lo menos con 6 caracteres de ancho y 2 después del punto decimal printf también reconoce %o para octal, %x para hexadecimal, %e 96s para cadena de caracteres y %4% para % en s Ejercicio 1-3, Modifique el programa de conversin de temperaturas de modo. que eseriba un encabezado sobre ta tabla, © |. Eseriba un programa que imprima la tabla correspondiente Celsius. a 1.3. La proposicién for Enisten suficlemes formas distintas de escribir un programa para una ‘area en particular. 108 tina variacién del programa deconversién de temperaturas. include imo Ia tabla Fahrenheit Coleiue «/ for (fake = 0; fahr < rinti('63d 966.11 ahr = tahr + 20) ah, (5.0/9.0) -(fahr -32)); Este produce los mismos resultados, pero ciertamente se ve diferente, Un cambio importante es Ia eliminacién de la mayoria de las variables; solo permanece fahr y lahemos hecho int. Los limites inferior y superior y el tamano del avance s6lo ‘parecen como coristantes dentro de la proposicidn for, que e wna nueva construceién, y la expresién que calcula Ia temperatura Celsius ahora aparece ‘como cl tercer argumento de print! en vez de una proposicién de asignacién sepa- rada, printf debe ser un valor de punto flot resin de punto flotante puede est La proposicisin for es um ciclo, con el while anterior, su operaci tes Seeciones, separadas por punto y coma. La primer fahr = 0 SECCION CONSTANTESSIMBOLICAS 15 e ejecura una ver, antes de entrar propiamente al ciclo. La segunda seccién es [a condicion 0 pru fahe <= 300 sin condicién se evalia; sies verdadera, el cuerpo el ciclo (en este caso um sim- ple printf) se ejecuta. Después el inctemento de avance fobs = fahr + 20 se ejecuta y la condicidn se vuelve a evaluar. El cielo termina si la condicién se trace falsa. Tal como con el while, el cuerpo del ciclo puede ser uaa proposicion ‘un grupo de proposiciones encerradas entre llaves. La inicializacién, la sondicién y el ineremento pueden ser cualquier expresién, _La seleusidn entre while y for es arbitraria, y se basa en aquello que parezca for es por lo general apropiado para ciclos en los que la inicializa~ smento son proposiciones sencillas y légicamente relacionadas, pues {que es mas compacto que cl while y mantiene reunidas en un lugar a las propo- wes que controlan al ciclo. xeiclo 1-5. Modifique el programa de conversién de temperaturas de manera que escriba la tabla en orden inyerso, esto es, desde 300 grados hasta 0. C peree, Bytan nals pede poate Programa, ya que proporcionan muy poca informacidn leer el programa, y son di ra de tratar a esos mimeros magi #deline define un nambre simbélico 0 constante simbdl ‘caracteres especial: #aetine texto de reemplases cualquier secuencia de caracteres; 10 ‘include inforior de la tabla «/ superior +) amano del incremenio / define LOWER 0 define UPPER 300 Adeline STEP 20 16 ysTROBLCCION GENERAL Js smprime la ‘abla Fahzenhett-Colslus « / int fahe; for lahr = LOWER; fahr <= UPPER; fahr = fahe + STEP) print("963d $66.1i\a", fab, (8.0/9.0) b Las cantidades LOWER, UPPER y STEP son constantes s por lo que no aparscen entre las declaraciones. Los 1.5. Entrada y salida de caracteres Ahora vamos a considerar una familia de programas relacionados para el pro- de cero © mas caracteres seguidos de un cardcier responsable de hacer que cada sec joteca estindar proporcina varias funciones para leer 0 es carfcter a la ver, de las Guales getchar y putchar son las més simples. Cada vez 6 = gatchar() Ja variable ¢ contiene ef siguiente cardcter de entrada. Los caracteres provienen normalmente del teclado; la entrada de archivos se trata en el capitulo 7. La funcién putchar escribe un cardcter eada vez que se invoca: putchar(e) ido de Ia variable entera © como un cardcter, generalmente cn jamadas a putohar y a printf pueden estar alternadas; la salida aparecerd en el orden en que se realicen las lamadas. SECCIUNLS ENTKADAY SALIDA DECARACTERES 17 1.8.1 Copia de archivos Con getchary putchar se puede escribir una cantidad sorprendente de eédigo in saber nada mas acerca de entrada y salida. El ejemplo ms sencillo es un a que copia la entrada en la salids, un cardcter a la ver: dee un carder while (oardeter no es indloador de fin de archivo) ‘manda a la saida el caricer recién ldo ee un cardeter Al convertir esto en C se obtiene include Js copia la entrada a la Fl operador de relacién |= significa ‘no igual a’ Lo que aparece como un cardcter en el teclado o en la pantalla es, por supues- como cualquier otra cosa, almacenado interniamente como un patron de "0 char tiene la funcién especifica de almacenar cse tipo de dato, pero tam- biga pucde ser usacio cualquier tipo de entero, Usamos int por una sutil pero im- portante razn. El problema es dist Fin de la entrada de tos datos validos. La solueibn 8 que getchar devucive un valor distintive cuando no hay més a la entrada, un lor que no puede serconfundido con ningin BOR, por “end of, nde ai sea lo suficientemente grande para almacena char. No se puede utilizar char puesto que ¢ debe ser s como para mantener a EOF ademas de cualquier otro cardcter. Por lo tanto, se emplea int. EOF es un entero definido en , pero el valor numérivo especifico 8 que no sea el mismo que ningtin valor tipo char. Utilizendo ibdlica, hemos asegurado que nadu en el programa depende del UW IeTRODECCION GENERAL carne 5] programa para copiar podria escribirse de mado mis conciso por progra- ‘madores experimentados de C, En lenguaje C, cualquier asignacidn, tal como (@ = gotchax putchax(-); = EOF) la asignacién dentro de ta co: alta que lade = , to prueba de relacién != se realizaria antes de la asigna- cidn =. De esta manera, la proposicién © = getcharl ) |= EOF es equivalente & © = (gotchar( ) != EOF) Esto tiene el efecto indeseable de hacer que e sea shar encontré fin de archivo. (En el e mas detalle), SECEIUN TS ENTRADA Y SALIDA DECARACTERES 19 .2 Conteo de caracteres Fi sigaiente programa cuenta caracteres ¥ cs semejante al programa que copia. include ls Joe caractores de la entrada; I. vessiéin «/ smain( ) i Toag ne; ne = 0; while (getchar( ) != EOF) ++ printi(9Td\n", no); , La proposicidn + tne: presenta un nuevo operador, ++, 4 nc = ne + 1.pero + neces: de prefijo. ‘BI programa para contar caracteres acumula su cuenta en una variable long on luger de una int. Los enteros long son por lo menos de 32 bits. Aunque en algunas maquinas int y leng son con un valor maximo de 32767, include + cuenta los caractores de la ontrada; 23. versién «/ ‘main( ) double ne; for (ne = 0; getchax() != EOF; ++u¢) 6.010", ne}; 20 INTRODUCKION GENERAL caPrrULD | printf utiliza %i tanto para float como para double; %.Of suprime la impresion dsl punto decimal y de la parte fraceionaria, que es cero. El cuerpo de este ciclo for esté vacio, debido a que todo el trabajo se realiza cen las secciones de prueba e incremento. Pero las reglas gramaticales de C requie- una proposicidn for tenga un El punto y coma aislado se llama proposicion nula, yesté aqui para satisfacer este requisito. Lo colocatmos en una linea aparte para que sea visible. Antes de abandonar el programa para contar caracteres, obsérvese que si la entrada no comer earacteces, La prueba del while @ del for no tiene éxito desde la primera llamada @ getches, y el programa produce cero, el resultado correcto, Esto ex importante. Uno e los aspectos agradables acerca del while y del for es ‘que haven la prueba a inicio del ciclo, antes de proceder con el cuerpo. Si no hay nada que hacer, nada se hace, aun ica no pasar a través del cuerpo del ciclo. Los programas deben actuar en f ligente cuando se Jes dx una entrada de longitud cero. Las proposiciones while y for ayudan a asegurar que los programas realizan cosas razonables con condiciones de frontera. 1.5.3 Conteo de lineas sra que una secuoncia de texto de entrada pa- secuencia de lineas, cada una terminada por un «: ter nueva linea. El cuerpo del while consiste aliora en un if, el cual a su vez controla el incre- mento + +nl. La proposicién if prueba la condicién que se encuentra entre pa- icin es verdadera, ejecuta la proposicién (o grupo de propo- ue le sigue. Hemos sangrado nuevamente para mostrar 10 que controla cada elemento. El doble signo de igualdad = = es la niotacién de C para expresar (como el = simple de Pascal oe! .EQ, de Fortran), Este simbolo se SeCCION PNTRADAYSALIDADECAKACTERES 21 distinguir la prueba de igualdad del = simple que utiliza C para la asignactén Un mensaje de alerta: 10s principiantes de C ocasionaimente escriben = cuando cen realidad deben usar = =, Como se vera en el capitulo 2, el resultado es por Jo general una expresidn legal, de modo que no se obtendré ninguna advertencia. Un cacdicter escrito entre apéstrofos representa un valor entero igual al valor numérico dei cardeter en el conjunto de caracteres de la maquina. Esto se llama una constante de cardeter, aunque s6lo es otra forma de escribir un pequeRo ente 10. Asi, por ejemplo ‘A’ es una constante de cardcter; en cl conjunto ASCH de 3 del cardcter K. Por su yes independiente de un puesto ’A’ es preferible que 65: su significado es obvi conjunto de caracteres en particulat [Las secucncias de escape que se ul ales en constantes de carat constante cadena que contiene s6lo un de cadenas versus caracteres, Ejercicio 1-8, Escriba un programa que cuente espacios en blanco, tabuladores Ejerdl Escriba un programa que copie su entrada @ la salida, reemplazando cada cadena de uno © mas blances por un solo blaneo. O Ejercieio 1-10, Escriba un programa que copie su entrada ata sali do cada tabulacidn por \t, cada retroveso por \b y cada \. Esto hace que las tabulaciones y los espacios sean visibl 1.5.4 Conteo de palabras El cuarto en nuestra serie de programas tiles icteres, usando la definicién de que una palabr: teres que no contiene espacio en blanco Versién reducida del programa wo de UNI Esta es una Hinclude #dclme IN 1 /+ om una palabra «/ #deline OUTO —/. fuera dena palabra «/ (+ cuenta lineas, palabras, y caractoros de Ja entrada «/ main( ) t int c, al, aw, ne, slate; INTRODUCION GENERAL state = OUT; ea= state = IN; + nm } } printi ("bd Md %d\n", ml, nw, ne); } (Cada ver que cl programa encuentra el primer eardeter de una palabra, conta Diliza una palabra mas. La variable state registra si actualmente el programa esta © no sobre una palabra; al iniciar es ‘no estd sobre una palabra”, por lo que se asigna el valor OUT. Fs preferible usar las constantes simbélicas IN y OUT que Jos valores literales | y 0, porque hacen el programa mds legible. En un programa tan pequetio como éste, Ja diferencia es amas mas grandes cl incremento en claridad bien vale el esfuerzo extra que se haya realizado para escribir de esta manera desde el principio. También se descubrird que es mas faci ‘hacer cambios extensivos en programas donde los nimeros migicos aparecer slo como constantes simbélicas. La ines nl = nw = no = 0; inicializa a las tres variables en cero. Este no es un caso especial sino una conse- cuencia det Hecho ce que una asignacion es una expresién con un valor, y que las asignaciones se asocian de derecha a izquierda. Es como si se hubiese escrito al = (w= (ne = O)} El operado: ignifiea "0" (0 bien YOR"), por lo que la linea Benn ona whe== 0 dive “si ¢ 5 un blanco 0 ¢ es nueva linea a ¢ es ut de escape \t es una representacién vi tabulador'’, (Recuerde que derecha, y se zar Jn verdad o fs cs un blanco, no hay necesidad de probar sies una nue~ va linea 0 un tabulador, de modo que esas prucbas no se hacen, Esto no es de SECCION Le ‘Apreatos 23 Jar importancia en este caso, pero ¢s significative en situaciones més com- das, como se vera mas adelante. zjemplo muestra también un else, el cual especifica una acci6n alieruativa la condicién de una proposicidn if es falsa, La forma general es af (expresisn) proposicién, else proposiciing Lina y s6lo una de las dos propasiciones asociadas con un it-else se cealiza, Si es verdaderu, se ejeculs p ves. En el programa para contar palabras, la que controla dos proposiciones entre llaves {Cémo probaria el programa para cont ada es la més conveniente para descubrir errores palabras? ;Que clase istas exisien? © jercicio 1-12. Escriba un programa que imprima su entrada una palabra por a, 1.6 Arregios Bscribamos un prog Variables individuales. Esta es una versiGn de] programa: Hinclade /+ cuenta digitos, expacios blancos, y ottos +/ ain{ ) 24 INTRODUCCION GENERAL eaprruta 1 SECCION Le ARREGLOS 28 while (e = getchar( }} != EOF) (ec >= Vasec= 9) olse f (0 == + + nuh: == Wie =. 90 lee = + +nother; EL patron. i (eondivion) ed, otxos = %d\0", La salida de este programa al ejeeutarlo sobre si mismo es Aigitos = 9300.00000 1, espacios blancos = 123, otros = 345, La dectaracién detlara ndigit como un arreglo de 10 enteros. En C, los subindices de arreglos comienzan en cero, por lo que los elementos son ndigit[O], ndigit ‘Un subindice puede ser cualquier expresién entera, lo que incluye a variables fenteras como i, ¥ constantes enteras. Este programs en particular se basa en las propiedades de la representacion de los digitos como caracteres. Por ejemplo, la prueba, W(e>= UV &bo<= miembro de un conjunto de constantes. Para contrastar, se presentard una n de este programa, usando switch, en la seccién 3.4, subindice valido para el La decision de si un cardeter es digito, espagio en blanco w otra cosa se realiza con la secuencia ere 0 b&e < + tndigitfo~t 26 INTRODUCCION GENERAL captruto 1 1.7 Funciones En Lenguaje C, una fareién es el equivalente a une subrutina 0 fins Fortran, o a un procedimiento o funciéa en Pascal. Una funcién propor una forma conveniente de encapsular algunos céleulos, que se pueden emplear despues sin preacuparse de su implantactén. Con fun mente, es posible ignorar edmo se realiza un trabajos es hace, Fl lenguaje C hace que el uso de funciones sea fi onveniente y eficien- sola vez, Uinicamente ruting de exponen ivas de enteros pe Esto es, el quetios, pero es su jon pow(z,y) que calcula x). ‘A continuacidn se presenta la funcién power y un programa main para utili. zarla, de modo que se vea la estructura completa de-una vez include int power(int m, int); J+ prueba la fuacién power «/ maint ) { int i; rintf("96d Yd Yoda return 0; fs power: eleva la base a la n-dsima polencia; s >= 0 +/ Int powor(int base, int n) pel for (= Lh <= m+ 41) P= pe base; seccioN 17 Funcionts 27 Una definicidn de funeion tiene ta forma tipo-de-retorno nombre-de-funcion (decleracién de pardmetros, si tos has) ien nueden aparecer on cualquier orden y en puede separarse en archivos aparece en varios archi I ver se tengan que especificar ilar y cargarto que si estuviera en uno solo, pero eso es cosa ema operative, no un atributo del lenguaje. Por ahora supondremos que ambas funciones estan en el mismo archivo y cualquier cosa que se haya aprendi- do acerca de como ejccutar programas en C, aiin funeionariin La funeién power se invoca das veces por main, en la linea ved Sed Yd\n", t, powor(2,), powart=3, formato y se imprime. En una expresién, power( lo son 2 e 4. (No locas las funciones producen un valor ea de la funciin power, int power(in base, Int n) declara fos tipos y nombres de los parémetros, asi como el tipo de resultado que funcidn devuelve. Los nombres que emplea power para sus pai funcién y som invisibles a cualquier otra funcidn: otras rutinas pueden ‘mismos nombres sin que exista problema alguno. Esto tambien es cier- © para las variables iy p: la de power no tiene nada que ver con la 3 de main. Generalmente usaremos pardmeiro para un variable nombrada en la lista en- do al hacer Los términos argumento formal 0 real se emrplean en ocasiones para hacer la El valor que calcula power se regresa a mai puede seguir cualquier expresion: rotuen expresion Jna funcién no ‘return al final de main mnbign puede regresar un we en el que el programa rente haya notado que hay una proposi Pucsto que main es una funcién como cualquier ra quien la invoea, que es en efecto el medio ar 2H INTRODUCCION GENERAL carr ca una terminacién nor- ‘omitido hasta ahora las propo- siviones return de las funciones main, pero sc incluiréin mAs adelante, como un recordatorio de que los programas deben regresar su estado final a su medio am- biente. La dectaracién ica que power es una funcién declaracién, a la cual se le llama funcion pro- sn y uso de power. Es un error el que la defl- uso que de ella se haga no corresponda con precisamente antes de main fe espera dos ar- gumentos int y regresa un ipo, debe coincidir con ‘de una funcién o cualqui escrito. int powerti No obstante, unos nombres bien seleccionados sori una buena documentacion, por lo que se empleardn frecuentemente beam +49 p= pe base: return p: sus tipos se declaran amtes de declaran se toman como int jimetros se nombran entre ierda; los parame funcién es igual a se visto como sigue: seccION DA AROUMENTOS—LLAMADA POR VALOR 29 {que por omision se padia suponer que power regresaba un entero, toda la decla- racién podria haberse omitido. La nueva sintaxis de los prototipos de funciones permite que sea muctio més para el compilador detectar errores en el mimero © tipo de ar ‘gn, pero se tecomienda ampliamente que se wor que la maneje, 1.8 Argumentos—Ilamadas por valor Hay un aspecto de las funciones de C que puede parecer poco familiar a los programadorcs acostumbrados a otros lenguajes, particularmente Fortran. En C, argumentos de una funcién se pasan “'por valor”. Esto significa que {que se invoca recibe los valores de sus argumentas en variables tempo- rales ¥ no en las originales. Esto conduve a algunas propiedacles diferenies a las que se ven en Ienguajes con “'Ilamadas por referencia” como Fortran a con pata os var en Pascal, et donde la rutin que se invoes tiene aecese al argumento inal, no a una copia local. La diferencia principal es que en C la funcidu que se invoea no puede alterar directamente una variable de la funcién que hace la llamada; sélo puede modifi- car su copia privada y temporal, Sin embargo, la llamada por valor es una ventaja, no una desventaja, Por lo comin, esto conduce a elaborar programas més compactos con poces variables extranas, debido a que los pardmetros se tratan en la funicin invocada como va lables locales convenientemente inicializadas. Por ejemplo, he aqui una version de power que ullliza esta propiedad, is power: eleva le base a la n-ésima potencia; n> =0; version 2 +/ int power{int base, int a) A int ps for (p = 1; > 0; —-n) Fl pardmetro 2 se utiliza como una variable temporal, y se decrementa (up cielo for que se ejecuta hacia atr4s) hastz que Vega a cero; ya no es necesaria Ja variable 3. Cuslquier cosa que se le haga a n dentro de power no tiene efecto sobre el argu- mento con el que s¢ Llamé originalmente power, 30, qwrkoDUCcION GENERAL, carrrutoy Cuando sea necesario, es posible hacer que una funcién modifique una va- riable dentro de una ruting invocada. La funcién que llama debe proporcionar ln direccidn de la variable que sera cambiada (téenicamente un apuntador ala va- rable) y la funcién que se invoca debe declarar que cl parametro sea un apunta- dlr y tenga acceso a la variable indirectamente a través de él. Los apuntadores se tratarén en el capitule $. La historia es diferente con los arreglos. Cuando el nombre de un arreglo se valor que se pasa a la funcion ¢s la localizacion © del arreglo —no hay copia de los elementos dicl arreglo, ‘este valor, la funcién puede tener acceso y alterar cual quier elemento del arreglo. Este es el tema de la siguiente seccién. 1.9 Arreglos de caracteres (nay ore linea) le ‘que la anterior mds larga) eudrdale uarda su fongiiud Imprime ta tinea mds targa Este pseudocédigo deja e tes, Una trae una nueva linea, otra la prueba y el Puesto que la division de las partes es mur de ese modo. Asf pues, esribamos primero uu Sn gelline para extract la siguiente lines de la entrada. Trataremos de hacer a la funcién ttl en otros eon- textos, Al menos, geiline tiene que cegresar una sefal acerca de un fin de archivo; un diseno de més u ‘ea, 0 cero si se encuentra el fin de archivo. Cero es un regreso de fin de arc ceptable debido a que nunca es una longitud de linea valida, Cada linea de texto ‘ene al meaos un cardeter; incluso una linea que s6lo contenga nn cerdcter mucva Jinea tiene longitud ‘0 que el programa se divide naturalmente en par~ le es mayor que la anteriormente més larga, sugiere una segunda funcion copy, para vo- Nt ARREOLOSDECARACTERES 31 #inclade define MAXLINE 1000 [+ tamaao maximo de la linea de entrada «/ cchar longest[MAXLINE]; /+ la linea mas larga se guards aqui «/ , MAXLINE)) > 0) Ihubo una linea +/ longest); ) J+ gelline: leo una linea en s, regrega si longitad / ‘nt geiline(char s[], int kim) { late, im-L G6 (e=getcksx{ )) !=EOF 66 cl="\n'; + +i) } ‘+ copy: copia void copy(char son ‘to’; eupone quo to os suficiantomante grande +/ ], char from) 32 INTRODUCCION GENERAL carmmuto a Las funconesgeltiney copy extn decaracas al principio del progr s¢ supone esta conten tnein ¥ gollin se conunican e treed de til par dédaguméntosy on valarde retorno. En getline los argumentos se deciaran por la linea int gellino(cha: (que especifica que el primer argumemto, s, ¢s un arteglo, ¥ el segundo, lim, es un entero, El propésito de proporcionar el tamano de un arreglo es fijar espacio de almacenamiento contiguo, La longitud del arreglo s no es necesaria en getline, puesto que su tamafio se fija en main, En getline se utiliza zeturn para rearesat un valor ¢ quién lo Hama, tal como hizo la funcién power. Esta linea también dedlara que getline rearésa unt int; puesto que int es el valor de retorno por omi- sién, puede supr Algunas funciones regresan unt valor util; otras, como copy, se emplean ti camente por su efecto y no regresan un valor. El tipo de retorno de eepy es void, smemte que ningtin valor se regresa En getline se coloca el cardcter ‘\O'(cardcter mufo, cayo valor es cera) al final delarreglo que estd creando, para marcar el finde ia cadena de caracteres, Esta con- n seutiliza por el Ienguaje C: euarido una constante de caracter com ‘nt lire) rograma en C, se almacena como un arreslo que contiene los caracteres de la cadena y termina con un "\O' para marcar el fin. ETe]’][«]“]w de que su argumento de entrada se termina con ‘\0', y copia este ca récier dentro del argumento de salida. (Todo esto implica que “\O", no es parte de un texto Ly Es titil mencionar de paso que aun un programa tan pequefio como éste pre- senta algunos problemas de diseno. Por ejemplo, zqué debe hacer main si en cer inea que es mayor que sy limite? getline trabaja en forma segur en ee caso detiene Ia recopilacién cuando el arteglo esta leno, aunque no en- 2. Probande la Tongitud y el ihimo cardcter devuel- Tels ests cots cl a fae Garang, concn ela tamano de la cadena, por lo que decidimos no agregar eomprobacién de errores en ella. SeCCIONL 10 YVARIADLESEXTERNAS VALENCE 33 Ejercicio 1-16. Corrija la rutina principal del programa de la Hinea més larga de ‘modo que imprima correctamente la longitud de lineas de entrada arbitrariamen- ie largas, y tanto texto como sea posible. C Eje 7. Eseriba un programa que imprima todas las ineas de entrada que sean mayores de 80) caracteres. 0. Kjercicio 1-18, Escriba un programa que elimine los blancos y las tabuladores que estén al final de cada linea de entrada, y que borre completamente las lineas on blanco. Ejercicio 1-19. Bs res s. Usela para esc '@ funcién roverse(s) que-invigrta la cadena de caracte- jr Un programa que invierta su entrada, linea a linea. © 1.10 Variables externas y aleance Las variables que estiin en main, tal como line, longest, etc, son pri ales a ella, Debido a que Son declaradas dentro de main, ninguna otra fun er acceso directo @ ellas. Lo mismo tam funciones; por ejemplo, Ia variable 4 en 3 com la; que esté en copy. Cada variable local de una funcién co sélo cuando se Nama 1 para hacer referencia a esas variables loc: categoria de almacenamiento estiti van sus valores entre lamadas.) Debido a que las variab Como una alternativa a Ins variables aut \n externas & todes las funcione: le tener acceso por su nombre. an o.a las variables de Pascal deelaradas en el bloque mas exterior.) Debi- fener acceso global 1 las variables externas, éstas pueden ser s de arguinentos para comunicar daios entre fu Puesto que las variables externas se mantienen permanentemente en » en lugar de aparecer y desaparecer cuando se Maman y terminan las jones, mantienen sus valores aun después de que regresa la funcién que los Una variable externa debe definirse, exactamente una ver, fuera de cualquier ‘uncion; esto fija un espacio de almacenamiento para ella, La variable también que desee tener acceso a ella; esto establece el debe ser una proj externespil Puede estar implicita en el contexto, Para concretar la 34 vTropuccioN GENERAL, carrmuto Tinea més larga con line, longest y max como cambiar las lamadas, declaraciones y euerpos: programa Esto requi #include #dofine MAXLINE 1000 /. maximo lamaio de una linea de entrada ./ J maxima longitud vista hasta ol momento «/ de entrada actual «/ linea mas larga so quarda aqul +/ 1" imprime la linea de entrada mae Isrga: vorsi6n eepecializada */ main( } f int len; ‘extern int max; extem char longest|); max = 0; while (len = getline( )) > 0) 1s golline: veraign expecislizada +/ int gollixo(vold) jables externas, VARIABLESEXTERNASYALCANCE 35 lineli] = \0% retura ih 1 / copy: version especlalizada +/ void copyiveid) int i; extern char line|}, longest; 1=0; vmhile (Congest Las variables externas de main, getline y copy estén definidas en las primeras lineas del ejemplo aaterior, lo que establece su ti cio de almacenamiento. Desde el punto de nas son exactamente como las det variables locales, pero puesto que som externas. Antes de que una fun- (én pueda usar una variable externa, se debe hacer saber ef nombre de la variable ‘la funcidn, Una forma de hacer esto es escribir una declaracién extern dentro de 1a funcién; la declaracion es la misma que antes, excepto por Ia palabra reser- vada extern, Bajo ciertas circunstancias, la declaracion extern se puede o1 ‘Gn de una variable externa oeurre dentro del atc te antes 12 funcién en particular, entonces no es necesario el uso d redundante. De hecho, una préctica comiin, es poner las definic das las variables externas al principio del archivo fuente y después o das las declaraciones extern. rama esta en varios archivos fuente y una variable se define en archi- en archivo? y archivo3, entonces se necesitan declaraciones extern Ja variable, La practica jones en un archivo sepa- jer, que es incluido por #inclede al principio hse usa por convencién para nombres de hea- 8. Las funciones de a Biblioteca estindar, por ejemplo, edn decaradas on 'aders como . Este tema se trata ampliamente en el capitulo 4, y la feca en el capitulo 7 y en el apéndice B. decade archivo 36 INTNODUCCION GENERAL carrroLo ‘Puesto que Tas versiones éspetializadas de getline y copy no tienen argumen- sugeritia que sus prototipos al principio del archivo deben ser gotli ero por compatibilidad con programas de C anteriores, el estén. Ja palabra voi ‘Se debe notar que empleamo: idadesementels pleas defini y del ies externas en esta seecion, La palabra “de se crea Ia variable 0 se le asigna un lugar de ” se refiere al higar donde se establece la naturale- za.de la variable pero no se Te asigna espacio, A propésito, existe una tendencia a convertir todo en Variables exten, debido aque aparentemente simplifica las comunicaciones —Ias lista de argumeatos son cortas y las variables existen siempre, cuando se les requiere. Pero las variables externas existen siempre, aun cuando no haven falta, Descansar fuertemente 80- bre variables externas es peligroso, puesto que lleva a programas cuyas cone: xiones entre datos no son completamente obvias —lus variables pueden cambiar seen forma inesperada ¢ inadvertide, y el programa es diflcil de modificar. La segunda versién del programa de fa fines mayor es inferior ala primera, en parte . Con estos Eundamentes, es posible: tamano considerable, y probablemente se cientemente grande para realizaclos, Esto: jos sugieren programas de com- plejidad algo mayor que los anteriores det capitulo. Ejercicio 1-20. Bseriba un programa detab que reemplace tabuladores de ta en- ‘vada con el ndmero apropiado de blancos para espaciar hasta de tabulacién. Considere un conjunte fijo de paros de tabulacién, digamos cada nm columnas. ;Debe ser una variable 0 un pardmeira simbético? O Ejercieio 1-21. Escriba un programa entab que reemplace cadenas de blancos por el minimo niimero de tabuladores y blancos para obtener el mismo espaciado. Considere los paros de tabulacién de igual manera que para detab. Cuando un tabulador o un simple espacio en blanco fuese suficiente para aleanzar un paro de tabulacién, ja cual se le debe dar preferencia? O Escriba un programa para ‘“doblar’” lineas grandes de entrada en no blanco que ocurra an~ ese de que su programa se comporte, apropiadamente con lineas muy largas, y de que no hay blancos o tabuladores, antes de la columna especificada, -€C108110 VARIABLES EXTERNASY ALCANCE 37 Ejercicio 1-24. Escriba un programa paca revisar los errores de sintaxis rudimen ios de un programa en C, como parent ves y carchetes no alineados, No vide las comillas ni los apéstrofos, las secuencias de escape y 10s comentarios. ste programa ¢s dificil si se hace co general.) capituLo2; Tipos, operadores y expresiones Las variables y las constantes son los objetos de datos basicos que se manipu- lizar y establecen et tipo que tienen y algunas veces cudles son sus valores ini- ss. Los operadores especifican lo que se hard con las variables, Las expresio- nes combinan variables y constantes para producir nuevos valores, El tipo de un objeto determina el eonjunto de valores que puede tener y qué oper den realizar sobre él, Estos son los temas de este capitulo. El estindar ANSI ha hecho muchos pequefios cambios y agregados a los ti- 1pos bisicos y a Jas expresiones. Ahora hay formas signed y unsigned de todos ipos enteros, y notaciones para constantes sin signo y constantes de caracter hexadecimales. Las operacionesde punto flotante pueden hacerse cn precision sen mbién hay un tipo long double para precision extendida. Las constames de cadena pueden concatenarse al tiempo de compilacion. Las enumeraciones son va parte del lenguaje, formalizando una caracteristica pendiente por mucho ‘empo. Los objetos pueden ser declarados const, lo que impide que cambien, Las reglas para conversion automatica entre tipos aritméticos se aumentaron pa ra maugjar el ahora mas rico conjunto de tipos. 2.1 Nombres de variables Aunque no to mencionamos en el capitulo 1, existen algunas x 's nombre de las variables y de las constantes simbdlicas. Los nor 40 71005, OPERADORES Y EXPRESIONES capruto2 0s 31 caracteres dé un nombre interno son signi se pueden utilizar como nombres indsculas, muveniene clegit nombres que estén relacionados con el propdsito de la ilizar nombres cortos para . ¥ nombres mas largos para vai 2.2 Tipos y tamajios de datos Hay unos cuantos tipos de datos basics en C: cher un solo byte, capaz de contener im etrdater del conjunto de int tun entezo, jente det tara natural de Tos enteros en ta maquina en la-que se elecuta, float punto flotante de precisién normal. punto flotante de dable precisién. 0s calificadores que se aplican a estos tipos basicos. Jeng int counter; {a palabra int puede omitirse de tales declaraciones, lo que tipicamente se hace. La inteneién es que short y long puedan proporcionar diferentes longitudes deenteros donde sea practico; iat sera normalmente el tamaflo natural para una.” ‘niquina en particular. A menudo short es de 16 bits y long de 32; int es de 16 ode 32 bits. Cada compilador puede seleccionar libremente los tamafos apropia- dos para sv propio hardware, sujeto s6lo a la restriccion de que los shorts « ints son por Jo menos de 16 bits, os longs son por lo menos de 32 bits y el short no ts mayor que int, el cual a su ver no es mayor que long. Flealificador signed 0 unsigned puede aplicarse a char o a cualquier entero. :meros unsigned son siempre positives 0 ¢ero y obedecen las loyes de la donde mes el niimero de bits en el tipo. Ast, por ejemplo, Jas variables unsigned char tienen valores entre 0 y 255, en valores entre ~128 y 127 (en una io de que los chess ordinarios sean com. seccion2.s onstrates 4 aque se pueden imprimir EI Lipo long double especifica punto floiante de precisién extendida, Igual s tamanos de objetos de punto flotante se definen en la Ejercicio 2-1. Eseriba un programa para determinar los rangos de variables char, Signed como signed, imptimiendo los valores epropiae ica hexadecimal, Por ejempl yOxlf 6 OXF en hexadecimal. lor particular y mas facil de leer. Las constantes de ‘ones muméricas tal como cualesquier oiros ‘idnmente en comparaciones con otros cat Ciertos curacteres pueden ser representa Por medio de secuencias de e 42 TIPOS, OPERADORES VENPRESIONES ‘earrteLo2 como dos caracteres, pero representan sélo uno. Ademas, un pation de bits ar- bitrario de tamafio de un byte puede ser especificado por ‘ooo! en donde 090 son de uno a tres digitos octales (0...7) 0 por "ehh en donde Ad son uno 0 mas digitos hexadecimales (0... mos escribir define VIAB'\013'—_/+ tab vertical ASCII «/ #doline BELL "\007' —_/+ carSctor campana ASCII «! £, A..F). Ast podria- , en hexadecimal, #dotine VIAB ‘\xb’ + tab vertical ASCIL «/ #doling BELL "x7! —_—_/+ catdoter campana ASCII «/ El conjunto completo de secuencias de escape es \ecardster de ataima (eampanay \\ diagonal invertida \b retraseso \?— imterrogacisn AE avance de hoia \.apéstrofo \m nueva tinea \"comillas \eoe nimero octal (shh niimero hexadevimal Me reaeso de caro At tabulador horizontal \¥tabulador verti Laconstante de cardcier ‘\G' representa ol eardcter eon valor cero, el carter aula, “\O" a menudo se esribe en ver de 0 para enfatizar la naturaleza de caracter de algunas expresiones, pero cl valor numérico es precisamente 0. ‘Una expresién constante es una expresign que sdlo inmiscuye constantes, Ta les expresiones pueden ser evaluadas durante la compilacién en ver de que se haga en tiempo de ejeeucién, y por tanto pueden ser utilizadas en cualquier lugar en que pueda encontrarse uns constante, como en #dsline MAXLINE 1000 char line [MAXLINE + 1); ‘define LEAP 1 /+ on aios bisizstose/ nt days (91+28+LBAP+31+30+91+30+31+31490+31+30+911; Una constante de cadena o eadena fiterat, es una secuencia de eeto 0 mas ca- Facteres encerrados entre comillas, como en "Soy una cadena” ° Ta cadena vactn «/ seccionas CONSTANTES 43, Las mismas cadena: es equivalemie a “hola, mundo! (s) de la biblioteca cadena de caracteres, ex: |. Aqui esté nuestra versidn: longitud de = */ Sstring-h> ‘enum boslean (NO, YES), El primer nombre en un enum tiene valor 0, el siguiente 1 #8 menos que sean especificados valores explicitas. Sino todos los valores son es- 44) p08, OPERADORES FEXPRESIONES cuties: pecificados, los valores 90 especificados continian la tltimo valor que sf lo fue, como en el segundo de esas resin a partir det ‘enum escapes { BELL = “\a', NVALIN = enum months {ENE = 1, FEB, MAR, ABR, MAY, IUY, WL, AGO, Sk, OCT, NOV, DIC), = FEE 66 2, MAR es 3, etc, +/ jones diferentes deben ser distintos. Los va- Fiables de enumeracign offecen la oportunidad de revisarlas y tal vova es @ menudo mejor que #doline. Ademas, un depurador puede ser capaz de impr tnir los valores de variables de eniumeracién en sy forma § 2.4 Declaraciones “Todas las variables deben Ser declaradas antes de su uso, aunque ciertas decla- raciones pueden ser heclas €n forma implicita por el contexto. Una declaracion .¥ comiené una lista de una © mas variables de es tipo, como en las entre ls declaraciones en cuslquier forma: de arriba podria igualmente ser esrita como sat lower: int upper sn stop: het char line); Esta diltima forma ocapa mis espacio, pero es conveniente para agregar un co- memtario a cada declaracién © para modificaciones subsecuentes, ‘Una variable también puede ser iniciatizada en su declaracién, Si el nombre ‘0 por un signo de igual y una expresién, la expresién sitve como un ini- dor, como en SECCIONES OPERADORES AMITAUETICOS 48 har ace = ‘\' 1 €s efectunida slo ai cambiado, Para un arreglo, {tos no seran alierados, cont double w = 2.7182a182245905; const char msol] = “procaucién: eambia ese arreglo: Int stlon(const char{}; ¢ efectiia un intento de cambiar un const, cl resultado esta de! intacion, 2.8 Operadores aritméticos Los operadores aritméticos binarios son +, —, «, /, y el operador médulo %. La divisién entera trunca cualquier parte fraccionaria. La expresién xy produce el residuo cuando x es dividido entre y, por lo que es cero cuanda y Uivi de a x exactamente. Per ejemplo, un afi es bisicsto si es divisible entre 4 pero xno entre 100, excepto aquellos aftos que son divisibles enire 400, que si som bisies . Por Jo tanto (year % 4 == 086 year % 100 1= 0)} rintf('%4d 00 um ato bistosto\a”, year) year 409 == 0) alse Pri dno es un aro bisiesto\n”, year operador % no puede aplicarse a operandos float © double. truncamiento para / y el signo del resultado de % son dependientes de la mo ara operandos negalivos, asi como la accidn que se toma en caso de sob © subflujo, 46. TIPOS, OPERADORES Y EXPHESIONES caprruo2 es menor arios. Los Los operadores binarios + y ~ tienen Ja misma precedencia, | que la precedencia de *, /, ¥ 96, que a su vez-es menor que + ¥— operadores aritméticas se asocian de izquierda a derecha. La tabla 2-1 que se encuentra al final de este capitulo, resume la precedencia idad para todos los operadores. 2.6 Operadores de relacion y légicos Los operadores de relacisn son soos eee ‘Todos ellos tienen la misma prevedencia, Precisamente bajo ellos en prevecencia estan los operadores de igualdad sen precedencia inferior que los operadores ‘ion vomo i < lim=1 setoma como i< miticos, como se esperacia, Mas interesantes son los operadores lénicos && y ||, Las expresiones conecta~ das por &é&0 } son evaluadas jerda a derecha, y la evaluacion se detiene tan promio eomo se conoce el resultado. verdadero 0 falso, La mayoria de los programas en C descansan sobre esas propiedades. Por ejemplo, aqui esté un ci- clo de la funcién de entrada getline que escribimos en el capitulo 1: ‘mis, si esta prueba falla, no debeiios seguir y Teer otto cardcter. Dema ba desal de que s¢ llame a getchar; por lo antes de que se pruebe e} cardcter ¢: La precedencia de && es mis alta que la de {!, y ambas son menores que 10s operadores de y de asignacion, asi que expresiones como = WW 86 ¢1= EOF no requieren de paréntesis adicionales. Pero puesto que la precedencia de != es superior que Ja asignacion, los paréntesis se necesitan en tenet ee ‘obtener el resultado deseadlo de asignacién a © y después comparacién con a nado si ¢ fuese probada contra EOF antes llamada y la asignacién deben ocurti s= Nahe <= 2) sohuen © + ‘at "A lse return ¢; ' Esto funciona para ASCH debido a que las correspondientes letras mayusculas ¥y minisculas estan a una distancia fija como valores numéricos y cada alfabeto atre Ay Z, Sin embareo, ta para el conjunto de caracteres EBCDIC, asi que este ebdigo podria convertir algo ma: ‘header estandar , que se describe en el apéndice B, define una \clones que proporcionan prucbas ¥ conversiones independientes de los jucgos de cara lejra minwscula dee transportable para la funcién lower mostrada ant prueba. ope Ubkes= 0 puede reemplazarse por {adigi(c) Nosotros utiizaremos las funciones de en adelante, | punto acerea de Ia conversidn de earacteres 2 enteros. El len- ‘tuaje no especifica si las variables de tipo char son valores con © sin signo. Cuan- o un char se convierte a int, j y las exprestones Idgicas conectadas estén definidas para tener un valor de 1 siendo verdaderas, ¥ 0 al este modo, Ia asignacion aparecer come negativos en algunas més iad, se debe especi nace Ia dsie es un digito, yO si no lo es, Sin embargo, las funciones como isdi- git pueden regresar cualquier valor diferente de cero como verdadero. En la parte Ge validacion de if, while, fo, es., “verdadero” es solo “diferente de cero, por To que esto ne hace diferencia. cas implictas trabajan como se espera. En general, sim operador como + 0 + que ioma dos operands (operador binaro) rene operandos de diferentes tipos, cl tipa ‘menor’ es promovido al tipo “supe! antes de que la operacion proceda, El resullado es el del tipo mayor. La seceidn 6 del apéndice A establece las reglas de conversi6n en forma precisa. Si no hay operaaddos unsigned, sin embargo, el siguiente conjunto informal de reglas bas- card: Si cualquier operando es long double, conviértase el otro a long double. De otra manera, si cualquier operando es double, conviértase el otro a double. De otra manera, si cualquier operando es float, conviértase el otro a float. De otra manera, conviértase char y short a int. ‘Después, si cualquier operando es long, conviértase el otro a long, Notese que los float que estén en una expresidn no se convierten auiomativa- i original, En general, las funs clones mateméticas como las de utilizarn doble precisién. La razon ppara usar float es ahorcar espacio de almacenamien(o en atregios gran- ‘menor frecuencia, ahorrar tiempo en maquinas en donde la aritmé- nS particularmente costosa. son mas complicadas cuando hay operandos us que TU, que es un nod long, Pero~IL > TUL, debido a que ~IL x prom asi parece ser un gran ntimero po: » es promovide a ‘a unsigned long ‘50 TIPOS, OPFRADORES ¥ EXPRESIONES carmio2 Las coniversiones también tienen lugar en las asignaciones; el valor del lado derecho es convertido al tipo «i jerda, el cual ¢s ef tipo del resultado. Un cardcter e8 converuido a un entero, tenga o no extensidn de signo, como se describié anteriormente. LLos enteros mas largos son convertidos a cortos 0 a char desechando el exceso ida de informacién. mntonces® = sei = x prod a tnt provos cumiento de cualquier parte Sraccionaria. Cuando double se comvierte a flea, el que se redondec o trunque el valor es dependiente de plantacién. Puesto que un argumento dela llamada a una funcidn es una expresién, sma‘con char y Finalmente, Ja conversiOn explicita de tipo puede ser forzada ("‘coacci da”) on cualquier expresién, con un operador unario llamado east. En la constructién (nombre-de-tipo) expresin la expresin es convertida al tipo nombrado, por las reglas de eonversidn anterio- tes, El significadoprecisode un cust es como si la expresion fuera asignada a una cida completa, Por ejemplo, la rutina de biblioteca sqrt espera un argumento de doble precision y produciré resultados sin sentido si mancja inadvertidamente algo diferente, (sqrt esta declarado en .) Asi, sim es un entero, pode- ‘mos usar sqri((double) 2) la conver se altera. ros aperadores unarios, co- swecrona8 DOPERADOKES DE INCREMENTO Y DECREMENTO 51 lara argumentos, como debe set normalmente, forzada automatica de ios argumemos cuando mada. Asi, dado el prototipo de la double sart(double); mada aie? = sari(2): unsigned long int next = 1; + rand: regress un entero peoudoaloatorio en 0,,22767 +/ nt rand! vo { next = next « elu (unsigned (newt/65836) % 32768, } fe srand: ja la semilla para zona) «! vold stand(unsioned int seed) { nex! = seed; 2.8 Operadores de incremento y decremento Fl ienguaje C proporciona dos operadores poco comunes para incrementar y dccrementar variables. El operador de aumento + + agrega | a su operando, en wo que el operador de disminucién ~~ le resta 1. Hemos usado frecuentemen- ++ para incrementar variables, como en He ==") + eal; aspecto poco comin es que ++ y ~ ss de la varial 2+ +), Enam! Svementa a nantes de que su valor {$2 T1005, OFERADORES Y FXPRESIONTS carrutog ignifiea que en wn cootexto, +42 y n+ + sonuite aviespués de que su valor se hia empleado. ‘deel valor esta siendo utilizado, yno solo el Simes 5, entonces asigna 5 a x, pero x= +n hace que'x sea 6, En ambos casos, n se hace 6. Los operadores de ineremente y decremento s6lo pueden aplicarse a variables; una expresién como (i+j)+ + Cada vee que se encuentra un valor diferente de ©, éste se copia en la posicion saccual j, y solo entonecs j es incrementada para prepararla para el siguiente carde- Otro ejemplo de construceidn semejante viene de la Tunciin getline que escri- bhimos en ¢] capitulo 1, en donde podemos reemplazar as OPERADORES PARA MANEIODERIIS 53 por algo més compacto como == ta) sit +] = ' ymo cada cariicter se copia de tas, el ++ postfiio se apl para estar seguros de que aribos estén en posicisn para una version squeeze(s1, <2) vardcter de la cadena s2, 0 ‘que regresa l idndar strpbr hace ‘ion encontrada.) $ Operadores para manejo de bits El lenguaje C proporeiona seis operadores dos & operandos integrales, esto es, & AND ado bits 1 OR inclusive de bits OR oxclusive de bite << corimiento a la inquierda >> cortimianto a Is derecha complemento a uno (unatio) S41 05, PERAMORES VEXPRESIONES, eaprruto2 Fl operadar AND de bits & a menudo es usado para enmascarar alain con. Junto de bits; por ejemplo, a= 980177; hace cero todos los bits de n, menos los 7 de menor orden. El operador OR de bits | es empleado para encender bits: x= x) SET_ON; fija en uno a todos los bits de x que son uno en SET_ON. El operador OR exclusiva” pone un uno en cada posicién en donde sus ope- randos tienen bits diferentes, y cero en donde son iguates. Se deben los operadores de bits & y | de los operadores Idgicos && ¥ jh. que implican evaluacion de izquierda a derecha de un valor de verdad. Por ejemplo, sixes Ly y es 2, entonces x & y es cero en tanto que x && y es un Los operadores de corrimiento << y >> realizan corrimientos a la izquier- day a la derechs d rando que esté a la izquierda, el nimera de posicie- nes de bits dado por el operando de la derechia, el cual debe ser positivo. As << 2 desplaza el valor de x a Ia izquierda dos posiciones, enando los bits vacantes con cero; esto es equivalents a una n por 4. El corer a la derecha una canticad vacates con cero, El carrer a [a derecha una cantidad signada Ilenard con bits de signo (“‘corrimiento aritmé- tuco”) en algunas maquinas y con bits 0 (‘‘corrimiento Igico”) en otras. El operador unario ~ da el complemento a uno de un entero; esto es, con- vierte cada i un bit O y viceversa, Por ejer xeU7 rimos seis bits de x en cero, Nétese que x & “077 es independiente de x& 0177700, que supone que x es wna cantidad de 16 bits. La forma transportable fo involucra un costo extra, puesto que “O77 es una expresion constante que pue- de ser evaluada en tiempo de compilacién. icidn de algunos ce Tos operadores de bits, considers 1a fone de x (ajustado a la derecha) del bit O esta en cl borde tm) & o00 << a); ‘mueve e:campo descado al borde derecho de la pa- derecha; compiementado con ~ hace una mascara bits mAs «la derecha. seeci0n2.10 (OPERADORES DE ASIGNACIONY EXPRESIONES 55 2.10 Operadores de asignacién y expresiones Las expresiones tales como inate cen las que fa v pueden ser ese el derecho, pana El operador + = se llama operador de asignacién. nacidn op=, en donde op es uno de Fn Mce >> a} Si expr, y expr, son expresiones, entonces exh op= expr lente a exun = (@x9R) p ccepiuando que expr, se calcula sélo una vez. N es xexeG+) 56 T1P0S,OPERADORES VEXPRESIONES cariTuto2 (= biteount: euonta buts 1 on x +/ sat bilcount{snsigned ) { int by ;gumento x como unsigned asegu vacantes se lenarin con ceros, no con bits de signo, imporcar pen la ventaja de expresion com yyvallyypelp+ p4] + yypvipl+p2l] += 2 while ((e = gelchar( }) != BOF) Los otros operadores de asignacién (+ =,~ =, et) también pueden estar dentro Em todas esas expresiones, ¢} de su operando del lac Ejercicio 2-9, En un sistema de mimeros de cor ra el bit slemento a dos, x &= (2-1) bo- de ms ¢ la derecha en x, Explique el porqué. Utilice esta observacion. una version més rapida de bitcount, () nes condicionales Las proposiciones Ma > b) seeer0Na.2 PRECEDENCIAY ORDENDREVALUACION 57 calculan en 2 ¢] maximo de a yb. La expresiéin condicional, escrita con el opera dor ternacio "?:", proporciona una forma alternativa para escribie ésta y otras consiruceiones semejantes. En la expresién p seeval Bo (a> b)Parbs cs un int, entonces la expresién @sO?ta ¢ de tipo float sea n pasitivo 0 no, printh* 664%", afi], (6610= =9 |) = =2-2) > \a Tes otfon elementos son Sequios por un esp eh compact que el tele vay buen ejemplo es Printi("Hay 6d elementovis.\n", m, n= =1?™ Ejercieto 2-10. Roeseriba ta funcién [Tower], que convierte letras maytisculas ‘minasculas, con una expresién condicional en vez de un itelse. 2.12 Precedencia y orden de evaluacion tabla 2-1 resume las realas de precedencia y asociatividad de todos los ope- lores, incluyendo aquellos que atin no se han tratado.. Los aperadores que ‘én en la misma linea tienen la misma precedencia; los renglones estan en orden ‘SR _TIPOH, OPERADORES YEXPRESIONES carrreio2 | scedencia, la cual es mais al ala Wamada a una funcién. Los operador deben ser completamente colocatas entre paréntesis para dar los resultados apro- piacos, TABLA 2, PRECEDENCIA ¥ ASOCIATIVIDAD DE OPERADORES (OreRADORES += 8 (ipo) sizeot Ete cess lee bes fe ces poe | — derecbaaizquicrda : inqulierda a derecha mayor precedencia qi Como muchos lenguajes, C no especifica ¢} orden en e! cual los operandos de pCCION 2.12 PRECEDENCIAYORDENBEEVALUACION 59 sultados diferentes con distintos compiladores, dependiendo de ia antes de que se llame a power. La solucién, por supuesto, prini("%d %62\a", m, power2, n}): Lag lamadas a funcion caeiruo 3, Control de flujo ‘mos mis precisos acerca de las discutidas con anterioridad, 3.1. Proposiciones y bloques Una expresign como x = 0161+ + 0 printf...) se convicrte'en una propost anc va seguida de un punto y coma, come en En Ce ps erminador de proposiciéa, en lugar de un separa dor, Coma To es én un Tenguaje tipo, Pascal Las llaves{y | se emplean para agrupar declaraciones:y prop de wentd 0 blogue, de mode que son sin salentes a. una props de una Suneion son un ejemplo ebvio; otros ejemplos son las laves alrededor de roposiciones miltiples después de un if, else, while-o for. (Pueden declararse ‘avables dentro de ewalguier blogue; esto se expondrd en el capitule-a.} No hay unto y coma después ce la llave derecha que termina un blogue, 3.2 Ielse 8 proposicién ifelse se utiliza para expresar decisiones. Formalmen! iDlaxis es 4 (expres) 6 2 conTROt DF cameruLoa es verdadera (esto donde ia parte del else es 6) i la expresidn tiene wn val La expresion se e ugar Puesio que un if simplemente prueba el valor numérica de una expresién, son posibles ciertas abreviaciones de cddigo. Lo mis obvio es exeribir (eapresion) en Tugar de i (expresiin = 0} Debido a que l nando un «/ else con el if anterior sin else més cercano. Por ejemplo, en te > a> b) = oy cl else va con el if mas lo que se desea, se deben v1 izar laves para forzar la asociaciéy (n> Ha > b) else sPeCION ee [A propésito, nétese que hay un punto y coma después de z = a en #a>b p= b debe a que gramaticalmente alle sigue una proposicdin, y una expresion " nto y coma. propasician loa 1 expresiin) proposicién lee propasicion ce modo tan frecuente que bien vale una pequefia discusion aparte, Esta de proposiciones if es Ja forma més general de escribir una decision ¥y esto termina toda igo para cada proposicién es una proposicién simple o un llaves. imo else manga el caso gtupe dentro La parte del muede utilizarse para deteccin de errores al atrapar $2 muesira una Tuncion de bisqueda bi- haria que decide si un valor particular de x se encuentra en el arreglo ordenado *. Los clementos de v deben estar en otden ascendente, La funcién regresa la po- Scidn (un nimero entre 0 y n-1) si x esid env, y —1 si no ey asi La basqueda binaria primero compara el valor de entrada x con el elemento Medio del arreglo v. Si x es menor que el valor del medio, la busqueda se enfoca 64 -conTRoL DEFLLIO enwrrucos hasta que se en- = <= vind} +/ also sf (x > v [mid low = mid + 1; alse /+ el elemento fue encontrado «/ return mid; , retum -1; /* nose enconird «/ } La decisién fundamental es si x es menor que, mayor que o igual al elemento me- dio vlmid] en cada paso; esto es un flse-if natural. una versién con de ejecucion. 11 3.4 Switch La proposicién switch es una decisién miiltiple que prueba si una expresion coincide con uno de un nimero de valores constantes enteras, y traslada el con- trol adecuadamente, sith (expres { caso exp-const: proposicones case exp-const: proposicones detaul: proposciones étiqueta con uno © mas valores constantes enteros 0 expresic eras. Si un|ease|eoincide con el valor de la expresign, Ia eject sgcc10N as swine 65 sma acci6n algu- jer orden, wnelude (+ cuenta digites, espacios Blancos, y otros" white, nother, ndigit[10]; return 0; } La proposicién break provoca una salida inmediata del switch, Puesto que son break yro- se puede emplear para forzar una salida ‘como se vera mas adelante en este capitulo. seecion3.s cictos-wwEYFoR 67 prueba expr, no esté presente, se toma como permaneniemente facién “infinita””, que presumiblemente serd interrumpida por tres in break 0 un return. ea y tabula copia la cadena t as, Utilce un switch, Escriba tambien una funcién para la di- Feecisn inversa, convirtiendo secuencias de escape en earaeteres reales. 1 3.5 Ciclos—while y for Ya hemos encontrado los eiclos while y for. En while (expresisn) propasician la expresidin se evalita, Si es diferente de cero, se ejecuta la proposicién y se reeva- hia la expreston. Este ciclo continia hasta que la expresién se hace cero, punto cen el cual se suspende la ejecucion para continuar después de Ia proposicidn. La proposicion for nC, lo andlogoal eta DO de Fo sia no es perfecta puesto métieas. Por otra ps ializacidn © ides, que mas bien se reservan para acciones de control del ciclo, Como un ejemplo mas amplio, aqui esta otra versién de atoi para convertir Und cadena a su equivalente numérico, Esta es ligeramente mas general que la de! tos espacios en blanco previos al nimero, y los signos tulo-4 muestra atol, que realiza la misina conversién para nime- unto flotante.) 1ura del programa refleja la forma de la entrada or (expr: expres expr) proposieiin valente @ te, ¥ deja las cosas en ‘dad del proceso termina con el primer cat mero, sma clara para el que no pueda ser parte de tres partes se pucde or 1a. Si expr 0 expr, se om) € desecha de Ia 68 CONTROL DERLWIO enmutoy include a entero; version 2 «/ int, a. sim: Js sqnora espacio en blanco « Je gqnora el sighd «/ 1eca estdndar proporciona una funcién mas elshorada, strtol, para 1 de cadenas 8 enteros largos; véase la seccién 5 del apéndice B. © orden las primeras eta} int gap, i temp, for (gap = w2; cap > 0; gap /= 2 (4 = gop: vli+ gap; in=9ee) { vil = vt 99Pl) vii+aap) = temp; ) ' Existen tres eiclos anidados. El mas externo controla el espacio entre los ele 108 comparados, reduciéndola desde n/2 por ut ide dos en cada paso seccION 33 CICLOSWHE FOR 68 que llega a cero. El ci medio reeorte los elementos, El cielo mas interno, ‘compara cada pareja de clementos que esta separada por el espacio gap e invierte ie citer desordenaclas, Puesto que gap_finalmente se reduce a uno, todos se ordenan correctamente, Natese como la generalidad del for hace ‘que ei ciclo mds exierno coincida con la forma de los otros, aun cuando no es tuna progresion aritmética. imo operador de C es la coma que frecuentemente encuentra uso is Separadas por una coma se eva- iia de izquierda a derecha, y el tipo y valor del resultado son el tipo y valor del operando derecho. Asi, én una proposicién for es posible colocar expresiones ics en las diferentas partes, por ejemplo, para procesar dos indices en pata- Bato se ilustra en la funcién reversa(s), que invierte a la cadena a en el mis- w lugar. #include Js reverse: invierte la cadena s on el mismo lugar +/ void reverse(char s{l) = 0; n—-) el cuerpo det ado no confundiré la seccién del while con e én de nimeros en complemento a dos, nuestr mero negative més grande, esto es, el valor 4& 4. Enna represent version de itoa no maneja 2 conmmoLvERLWIO ‘eannui03 sicidn continue se aplica solamente a ciclos, no a switch. Un continue dentro de ‘un switch que esté a su vez en un ciclo, provoca la Siguiente iteracion det ciclo, Como un eiemplo, e} siguiente fragmento procesa sélo los elementos no negativos quie estén en el arreslo a; los valores negativos son ignorados. for(i = Qi cm it4y{ ignora elementos negatives +/ ‘+ trakaja con elementos poulivos +/ ‘La proposicién continue se emplea a menudo cuando In parte del ciclo que sigue es complicada, de modo que invertir la prueba y sangrar otro nivel podria anidar profundamente el programa. 3.8 Goto y etiquetas la infinitamente abusable proposicién goto, y etiquetas goto nunca es necesario, ¥en Ja préctica casi siempre mas facil escribir cédigo sin 4. En este libro no se ha usado: alguno. ‘Sin embargo, hay algunas situaciones donde los goto pueden encontrar un gar. La mas comin es abandonar el procesamiento en alguna estructura pro damente anidada, tal como salir de dos o mas cilos a la vez. Le proposic break no se puede utilizar directamente, puesto que solo sale 10. Ast carregla ef desorden Esta organizacisn es itil siel e6digo de manejo de error noes res pueden oeurrir en varios lugares. Una etiqueta tiene Ia misma forma que un nombre de variable y es segul por dos puntos, Puede ser adherida a cualquier proposicign de Ia misma fun cen Ta que esta el goto. Fl alcance de una etiqueta es toda la funcién, Como otro ejem scérese el prablema de determinar si dos arreglosy yb, tienen un elemento en comin. Una posibilidad es seCCIONS A corovEnQUETAS 73 /+ no s¢ ericontié ningun elemento en comun +! ‘encontrado: (* getiene une: ==5f El c6digo que invotuera un goto siempre puede escribirse sin 1, aunque tal sez al previo de algunas pruebas repetidas 0 variables extra. Por ejemplo, Ia bus- queda en los arreglos quedtara ‘encontrads = 0; for (i = 2 86 loncontrado; i+ +) for) = 0; | < 2m && lencontrado; 3+ +) i) = = bill) jcontuado = 1; if (encontrado) Jo ge tiane uno: alt] == bj} a! lee Jo no se encontrd algiin elemento en com «/ pocas excepeiones, como las vitadas aqui, el codigo que se basa en oro nes goto es generalmente mas dificil de entender y de mantener que el codi- las. Aunque no somos dogmdticos acerca del asunto, se ve que las nes goto deben ser utilizadas raramente, si acaso. capituco 4 Funciones y la estructura del programa Tugar de cotenzar detde ceo, Las Funcioncy aprepiedas ocultan low det ion de las partes del programa que no necesitan saber acerca de 4 [a totalidad y facilitan Ii penosa carea de hacer ‘C se disend para hacer que las funciones fuera eficientesy facies 8 programas escritos en C se componen de muchas funciones pequehias, ‘en lugar de s6io algunas grandes. Lin programa puede residir en uno o mas archi- vos fuente, 1os cuales pueden compilarse por separade y eargarse junto con fun- teca previamente compiladas, No trataremos aqui tales provssos, puesto que los detalles varian de un sistema a otro. ‘La declaracion y definicién de funciones es el area donde el estindar ANSI hha hecho los cambios mas visibles a C. Tal como mencionamos en el capitulo ahora es posible declarar los tipos de los argumentas cuando se dectara una ft ign, La sintaxis de la definicion de funciones también cambia, de modo que las declaraciones y las definiciones coincidan. Esto hace posible que el compitador pueda detectar muchos mas errores de lo que podia anteriormente, Ademas, uando los argumentos se declaran con propiedad, se realizan aut 4.1, Conceptos basicos de funciones Para comenzar, dseiemos y eseribamos un programa que imprima cada inea e-su entrada que comenga un * ” o cadena de caracteres en particular, 76 PUNCIONES ¥ LA ESTRUCTURA DEL PROGRAMA carrruLes (Este es un caso especial del programa grep de UNIX.) Por ejemplo, al buscar cl patrén de letras “ould” en el conjunto de lineas A Love! could you and 1 with Fate conspire To grasp this sorry Schene of Things entire, Would not we shatter it to bits =~ and then Re-moulé it nearer to the Heart's Desire! producird la salida ah Lovet could you and T with Fate conspire Would not we shatter it to bite -- and then Re-nould it nearer to the Heart’s Desire! 1 crabajo se ajusta ordenadamence en tres partes: Aunque clertameiite ¢s posible poner el c6digo de todo esto en main, una me- jor forma es aprovechar Ta estructura haciendo de cada parte una funcién separa da, Es mis fcil vrabajar con tres piegas pequefias que con una wrande, del ‘que los detalles irrelevantes se pueden ocultar dentro de las funciones, y minimi- nes no deseadas. Los fragmentos incluso se pueden (Cuando posteriormente se necesite una coinci solo se debe recmplazar strindex; el resto del cédigo pue- ismo mas general. Regresarer sea un parémetro fijado cuando se ejecuta el programa. jon ligeramente diferente de getline, que se podré. compa 1 SECCION 41 CONCEPTOS NASICOS DE FURGIONES 77 # include ‘define MAXILINE 1000 /* Jongitud maxine por linoa do ontrade +! int gotline(char line| |, int max); char searchtor()) ‘char pattern [] = “ould”; /* patton por buscar +/ ro todse Tae linear quo oincidan con al patrén «/ walle (gelline(line, MAXLINE) > 0) if (teindex(line, pattern) > = 0) { rint("968", line); found + +; } seta found; } {+ gelling: rae Tinea y Ia pone en 2, rogresa ru longitud +/ sat getino(ohar of], int i) { inte, i Jim > 0 && (o=getchaxt)) |= EOF &&c !="\n') sil = return i; J+ strindax: togresa el indico dot en s,~1 si no existe +/ int strindox(char s{ |, char 78 FUNCIONES ¥ LA uSTRUCTURA DEL PROGRAMA cAPTULO > o&&tlki == 0) return §; return “Ly ipo-regresailo nombresde-funciGn(declaraciones de argumentos) { ' declaraciones y propasiciones Varias partes pueden omitirse; una funcién minima es nada ) {) hhace ni regresa nada. Una funcién hacer-nada, como ésta, es algunas v Ingar al desarrollar un programa. Si el tipo que regresa. les externas. Las funciones pueden presentarse en eus ichivo fuente, y el programa fuente se pued: varios archivos, mientras las funciones no se dividan. La proposicién return es el mecanismo para que la funcién que se lama se un valor a su invocador. Al return le puede seguir cualquier expresion: return expresidn La expresidn se convertiré al tipo de retorno de Ia funcidn si es necesario. Con, frecuencia se utilizan paréntesis para encerrar la expresién, pero son optativos. {La funcién que lama tiene la libertad de ignorar el valor reatesado, Incluso, idad de una expresiGn después de xeturn; en tal caso, ningiin vale el control regresa, sin valor, cuando la ej alcanzar la Have derecha que cierra. No es El programa de bilsqueda del patrén regresa un estado desde main, el nimero de coincidencias encontradas. Este valor est disponible para ser empleado por el medio ambiente que llamé al programa. El mecanismo de cémo compilar y curgar un programa en C que reside en va~ ros archivos fuente varia de un’ seccioN 42 FUNCIONES QUE REGRESA® VALORES NOENTEROS 79 iy5 funiciones Se almavenan en tres archivos Hamados main.c, gatline.c, y strin- dex.c: la orden ce main.c gelline.c strindex. ce emplea Ta convencién ",e" contra "0" para distinguis los archivos fuente de objete. Bjercicio 4-1, Escriba Ia funcién strrind rrencia de més a la derecha que regresa la posicidn de la ocu- hay alguna, 0 4.2 Funciones que tegresan valores no enteros Hasta ahora los ejemplos de funciones han rearesado 0 ni oun int. :Qué pasa si una funcidn debe regresar algo de otro tipo? Muché ciones numéricas como sqrt, sin y cos regresan double; otras funciones especi convierte la cadena s a su valor equivalente de mn, La funcidn atof es una extension de atoi, de la mos dedicarle, La biblioteca estindar incluye un atof; cl reader la declara, Primero, atot por si misma debe declarar ef tipo del valor que regresa, puesto que no es int. El nombre de! tipo precede al nombre de Ta funcién: ‘include double val, power; sat i, sign for (1 « 0; isspace(s[i); i++) /+ ignora espacios blances +/ sign = (sl) == 7-12 80 FUNCIONES VTA ESTRUCTURA DEL. PROGRAMA carrie atc FUNCIONES QUE REGRESAN VALORES NOLENTEROS 81 eqresaria un valor double que main trataria como int, ¥ se producirian resulte- dios incongrucntes. ; ; ‘A la luz de lo que hemos mencionado acerca dé eémo deben coincidir las de- slaraciones con las definiciones, esto podria ser sorprendente. La razon de que Seurva una falta de coincidencia es que, si no existe el prototipo de una funcién, Geuves declarada impleitamente la primera vez que aparece en una expresion, co- mo for (val = 0.0; sadig val = 10.0 val + a for (power = 1.0; isdig val = 10.0 val + (6 ~ 0); power == 10.0; sum += atedfline) ‘sien una expresidn se encuentra un nombre que no ha sido declarado previamen- yest sezuido por parentesis izquierdo, se declara por contexto, de mado.que } rotum sign * val / power: 1 Segundo, e igualmente importante, la rutina que llama debe indiear que at regresa un valor que no es int. Una forma de asegurar esto es dectarar atof expl tamente en Ta rutina que la llama. La declaracidn se muestra en esta primitiva cal culadora (apenas adecuada para un balance de chequera), que lee un mimero linea, precedido'en forma optativa por un signo, y lo acumula, imprimiendo suma actual después de cada entrada: ‘include double atol( J; también es tomada de modo que no se supone nada acerca de 1os argue: afof, se desactiva toda revisién de pardmetros. Este significado especial de la de argumentos vacia se hace para periitir que los pr pilen con los nuevos compiladores. Pero es una mal sramas mievos. Si la funcibn toma argumentos, declarelos; si mo los toma, use void. Dado atof, propiamente declarado, podemos escribir atoi (convierte una vade- na g int) en términos de él: ‘#dofino MAXLINE 100 /> caleuladore rudimentaris +/ J» aloi: convierts In cadena s a enlero usando atof +/ int atoifehar sf }) 4 double atol{char Notese la estructura de las declaraciones y la proposicién return, El valor de la expresion en ) refare expres, La decks St cor te al tipo de la funcién antes de que se tome el return. Por lo tanto, clvaior de aff, un double, se converte automaticamente a int cuando aparece eneste return, puesto qué la funcion aol una variable double, y que atof es una funcidn que toma cin potencialm y regresa un double. 4 consistentemente. Si atof en st mi sistentes dentro del mismo dor. Pera si (camo es prol vonsistencia no se detectaria, a 123.4866 jo 4-2, Extienda atef para que manejé natacion clentifica de ia forma 43 /ARIABLES EXTERNAS 82 FUNCIONES ¥ LA reTRLICTURA DEL PROGRAMA carrruteg| seccios VaRiaacEs 3 En notacién polaca inversa, cada operador sigue a sus operandos; una expre- sibn infija como a-aa+9 conde un niimero de punto flotante puede ir seguido por @ o Ey opeionalinente: tun exponente con signo. 5 se introduce como 12-454 Jos paréntesis no son necesarios; la notacién no es ambigua mientras sepamos nats opetandos espera cada operador La implantacidn es simple, Cada operando se imroduce en una pila o 4.3 Variables externas Un programa en C coasta de un conjunto de objets externos, que son van rinbles o funciones. El adjetivo “externo” se emplea en contrasie con “interna” que desc ¢ los argumentos y las variables definidas dentro de las funciones. La externas se definen fuera de cualquier funcién, y por Jo tanto, estén po ce disponibles para muchas funciones. Las funtciones en » puesto que C no permite definir funciones dentro de otras fy én, las variables y funciones externas tienen la propiedad de q todas las referencias a ellas por el mismo nombre, incluso desde funciones com ladas separadamente, son referencias a la misma cosa. (El esténdar llama a es propiedad figado externo.) En este sentido, las variables externas son andlogas los blogues COMMON de Fortran o a las variables del bloque mas externo d Pascal. Mas adelante veremos cémo defini variables y funciones externas que seq visibles sélo demtro de un archivo fuente Debido a que las variables externas son accesibles globalmente, proporcionan una altermativa a los ar después se reemplazan por ‘erencia, ~1. En seguida go se reemplazan por st suma, 9. El producto de—1 y 9, que es ~9, los reemplaza en la pila, El valor que seencuenira en el tope de la pila se extrae ¢ imprime cuando se encuenira el fin de la linea de entrada. Laesiructura del programa es as{ un ciclo que realiza las operaciones adecua- das sobre cada operador y operando que aparece: wile (Siewiente operador x aperando no es.fin de archivo) hacer operaciones iniroducir et resultado Si un gran nimero de variables se debe compartir entre fu ‘lables externas son més covenientes y eficientes que las largas listas de argh tos. Sin embargo, como se sefialé en el ci else if (nueve Tien) extras e imprime of tope de fa pita Las variables externas son también titles debido a su mayot aleance y Gc vida. Las variables autométicas son internas a una funcion y su existencia cia cuando se entra a Ja funcion y desaparecen cuando ésta se abandona, 0 lado, las variables externas son permanentes, de modo invocacion de una a ‘compartir algunos datos, am buscar el La pr decision de disefio que ain Pil, esto es, cudles rutinas tienen acceso a ella directamtente. Una posibilidad es Cntenerla en main, y pasar la ple y la posicién actual a las rutinas que introdu- 'raen elementos. Pero main no necesita saber acerca de las variables que olan a la pilas slo efectiia operaciones de introducir y extraer, Asi, heros almacenar la pila y su informacion asociada en variables externas accesi ‘unciones push y pop, pero no & main. ste bosquejo a cédigo es suficientemente facil. Si por ahora pensa ograma existe en un archivo fuente, se vera asi gar de que scan pasados como argumentos de entrada y salida Examinemos nas a fondo este tema con un ejemplo mas ampl 6 osoribir ¢] programa de una calculadora que provea los opera 4. Por ser mis fa 84 FUNCIONESY LA ESTRUCTURA DIL PROGRAMA rador y operando; éste es un uso del switch mas tipico que el mostrado en Ia s ion 3.4, ‘seceran 43 VARIABLES EXTERNAS 85 includes #Astinns ‘eclaracidn de funefones para main main(){ 1 variables externas para push » pop printi(errar: divisor cero\n"); break; cease "\n' priati("\135.89\n", popt }); ppuiati(“error: comando deaconocide "s\n", 5) #includs i include /* para atol() +! } rotura 0; ‘#deline MAXOP 100 _/* max tamano do operando u operador */ j ‘#define NUMEER ‘0! /* softal de que un tiimero se encontré +! int getop(cha void push(do double pop(void); (* MMCORRECTO +/ + oaleuladora pola inverse 41 . —_ Jen en el que se evaléan Tas dos Namadas de pop. Para yaran- (0, 6s necesario extraer el primer valor en una variable tempo- en main. ‘define MAXVAL 100 /, maxima profundidad de Ia pila val «! ) 1= BOR) { int sp = 0; Jy siguiente posicién libre ea le pile «/ double val[MAXVAL]; /. valores de la pila «/ Js push: introduce f ala pila «/ void push(deuble 1) { (ep < MAXVAL) vallsp-+ +] = push(pop() + pont }): ‘break: 86 FUNCIDNES V1.4 ESTRUCTURA DEL PROGRAMA caPituto « ere shaincveeRaeO, "error; pila llena, no puede efectuar push Sa/n", regress el valor superior de la pile «/ ) a pop: x double popty: 1 if (op > 0) zofurn vall—spl: ‘ma ha leido un eardcter de mas, para el cual no es . E] problema podria ser resuelto si fuera posible canicter no desea- do. Entonces, cada vez que el programa lea un cardcter de mds, podria regresar ls printf(*orror: pila vacta\a") return 0.0; se encuentra definida fuera de cualquier funcié la que deben ser compartidos por push y por pt misma no hace referenel puede estar oculta, ‘golop, la funcion que toma el sui operador u operando. La tarea ¢ facil. Ignorar blancos y tabuladores. 5i cl si guiente earderer no es un digita 0 punto decimal, regresario. De otra manera, ret hic una cadena de digitos (que pueda incluir un punto decimal), y regres NUMBER, la sefial de que ha sido reunido un niimero, Her estd vacio, También debe existi - Asi, pode- include int getch{vel void ungstch(int); ‘/* gotop: obtiono ol ciguionte operadcr u operando numérico */ int getop(char s| |) ( ‘deine BUFSIZR 100 char bul{BUFSIZE]; /+ buifor para ungetch +/ int bufp = 0; ‘+ siguionto posicion libre en but +/ ‘st geich(void) /+ obliene un (posiblamente ya regresado) carkcter */ 1 while (0) = c = gotch()) == "* Jo == "V4 return (bufp > 0) ? bui[-—bufp « gotohar ( ); ) void ungetch(int c) /+ regresa carscter a le entrsds +) st > = BUFSIZE) printf(“ungetch: demasiados carscteres\n"); ‘buffbufp+ +] =e; rede la parte Sraccionaria + [++i] = © = getchl )) HUSCIONES Y LA ESTRUCTURA DEL PROGRAMA iables, -2.) Anada una variable para el Ejercicio 4-6. Agregue Ordenes para mat nar veintistis variables con nombres de una Jor impreso ms reciente. Ejercicio 4-7. Escriba una rutina ungets(s) que negresa a la entrada una completa, ;Debe ungets conocer acerca de bul y buip, 0 sélo debe usar unc a Ejercicio 4-8. Suponga que nunca existird més de un carécter de Modifique getch y ungotch de acuerdo con ex0. © Rjercico 49, Nuestros getoh y ungetch no mancjan correctamente un BOF qh . Desida cuales deben ser sus propiedades si se resresa un EOF, y completa de entrada; esta hace innecesarios a gatch y a ungetch. Cortlj la dora para que use este planteamiento, 4.4 Reglas de alcance Las funciones y variables externas que constituyen un programa en C no sitan ser compiladas a la ver; el (exto fuente del programa se puede tener en yy se pueden cargar rutinas previamente compiladas de biblioteca. sguntas de interés 2 *# Cémo se eseriben las declaraciones de modo que las variables sean declar adecuadamente durante la compilation? .Cémo se arreglan las deciaraciones de modo que todas las piezas se co adecuadamente cuando se carga el programa? ‘© ,Como se organizan las declaraciones de modo que sélo haya una copi * :Cémo se iniciatizan las variables exteraas? Discutamos estos temas reorganizando el programa de la caleuladora en archivos. En terminos pricticos, Ia calculadora es demasiado pequenia para RECLAS DE ALEANCE 39) SeeCION 4 iscracion de los eonceptos que surgen usar el nombre, Para una variable automatica declarads al n, el alcance es la funcidn dentro de la cual esta declarado el nombre. Las va- él punto en que se jemplo, si main, sp, ten el orden expuesto anteriormen- nish, ¥ pop estdn definidas en un archivo, int sp = 0; double vall MAXVAL| void push(doubl double pep(veid) { .] centonees las variables sp y val se pueden utilizar en push y pop simplemente nom- bréndolas: no se necesita ninguna otra declaracion. Pero estas nombres no son visibles en main, ni push ni pop. Por otro lado, si se va a hacer referencia a una variable externa antes de sw 1, si estd definida en un archivo fuente diferente al que se esta wilizan- centonces es obligatoria una declaracién extern, importante distinguir entre la declaracién de una variable externa y su defi 1. Una declaraci6n expone las propiedades de una variable (principalmente una definieién también provoca que reserve un espacio para almacena- ‘Si las lineas int sp; doublo val MAXVALI; aparecen fuera de cualquier funcion, definen las variables externas sp y val, T2- Servan un espacio para almacenamiento y también sirven como declaracién para resto de ese archivo fuente. Por otro lado, las lineas extern in sp; exter double vall |; ectaran para el resto del archivo que sp es un int y que val es un arreglo double rmaho sc determina en algin oro niles reservan espacio. ‘Slo debe existir una definicién de una variable externa entre todos los archi- Yos que Forman un programa fuente; otros archives pueden contener declaraciones 90 FUNCIONES ¥ LA ESTRUCTURA DEL PROGKAMA, carrito 4 | Aunque no es una organizacién iddnea para este programa, las funciones push y pop pueden definirse en un archivo, y las variables val y sp podrian ser definidas ¢inicializadas en otro. Fntonces se necesitarfan las siguientes definicio,, nes y declaraciones para enlazarlas: ( En of archivo 1: extern int ep texters double vall ] void push(double #) { .} double pop(void) En el archivo 2: int sp = 0 double vallMAXVAL|; Debide a que las declaraciones extern que se encuentran en el archivo J estén ‘tuadas antes y afuera de las definiciones de funciones, se aplican a todas las f ciones; un conjunto de declaraciones basta para todo el arckivo 1. Esta mi organizacion también seria necesaria si las Gefiniciones de sp y val se encontraran después de su uso en un archivo, 4.5 Archivo de encabezamiento [header Consideremos ahora la divisiéa del programa de la calculadora en varios chivos fuente, como podria ser si cada uno de las camponentes fuera sustanci mente mayor. La funcion main ira dentro de un archivo, al que lamare ‘tmain.c: push, pop y sus variables van dentro de un segundo archivo, stack.¢ getop va en un tercero, gotop.c. Finalmente, getch y ungetch van dentro de u cuarto archivo, gete! ieca compilada separadamente s separarsmos de las otras debido a que podrian v in programa realista, is y declaraciones comparti- hnasta donde sea posible, de modo Entonces, el programa resultante se ve como sigue: seccion 48 VARIABLE ESTATICAS OL ache Fach SIEET ‘Pacis Yea Halice MAXWAE 100 pclae Saabs Paclude coats Paciads | include “cule bt ‘ocinde “eal ‘deine MAKOP 100 eto axe)! getche: Heke BUESIZE 10 ‘har bul(BUFSIE, int bap = 0, int ates) | r oud ungetii { sélo tenga acceso tea de que es més ‘un programa mucho mas grande, s¢ 1 fos tipo header 4.6 Variables estaticas ‘bles sp y val en stack.c, y(Bul]y [bufp| en a8 funeiones qu estan en sus respectivDs a on para el uso te, y'se supone Las Privad 2 os 15S V LA ESTRUCTURA DEL PROGRAMA enPrruLo que nada mas tiene acceso @ ellas, La declaracién static, aplicada 2 una variable © funcién externa, limita el alcance de ese objeto al resto del archivo fuente que. se-esta compilando. Asi las variables static externas proporcionan una Forma de. mbres como buf y bufp en la com ss para que puedan scr compartidas, getch-ungetch, que dcben ye no deben ser visibles alos, static char buf[BUFSIZE); statlc int bulp = 0; 1+ baller para ungetch */ (+ Siguiente posiciée libre en bul +/ int gotch(void) ( void ungetch(int ‘entonees ninguna otra rutina serd eapaz de tener acceso a buf ni a bulp, y hombres no entrardn en conflicto con los mismos nombres que estén en otros ar lel mismo programa. De la para la manipulacion de ta pi come static. La declaracién static externa se usa con més frecuencia en variables, una funciGn se devlara como static, su nombre ¢s invisible fuera del archivo el que esti declarada laracidn static también puede aplicarse a variable ique getop de modo que no neces! ia variable static interna. ©) 4.7, Variables tipo registro Una declaracién regist ¥ rapidos. Pero iad de ignorar esta sugerenc La delaras 4 secci0Nn 48 ESTRUCTURA DE BLOGUE 93 . La declaracién [egiter s6lo se puede aplicar a variables automaticas y . En este dltimo easo, aparece como ‘ado en blogues en el sentido de Pascal 0 ones no se pueden definir dentro de otras funcio- 1s, Por otta part, las variables se pueden defini en una modalidad de estructura de biogues dentro de una funcién. Las declaraciones de variables (incluyendo la inieilizacion) pueden seguir a le Tlave izquierda que indica cvalquier proposi: ci6n compuesta, no sélo la que inicia @ una funcién, Las variables declaradas de «sta manera oculian cualquier nombre idémtico de variables en bloques externos, 4 permanecen hasta que se encuentra la lave derecha que corresponde con la ini- dial. Por ejemplo, en Hea > Ot declara una mueva | +/ for (= O14 < mit +) a las variables y fun, Faciones 94 FUNCIONES ¥ LA ESTRUCTURA DEL PROGRAMA en la funcién f, las ocurrencias de se refieren al parametso, que ¢s un do: se refieren al int externo. Lo mismo e valido para la variable y, 8 mejor evitar nombres de variables que coinciden con nom SE¢CCION 440 RECURSIVIDAD 95 en lugar de iat low, high, mids low high = =a En efecto, las inicializaciones de variables automaticas son slo abreviaturas de jones de asignacién. La elecci fda cuestion de gusto. tas, debido a que los clalizadores encerrados entre llaves y sepazades por comas. 1 un arreglo das con el mimero de dias de eada mes: ] = (31, 28, 31, 30, 31, 30, 31, 31, 90, 31, 30, 31; Cuando se omite el tamaiio de un arreglo, él compilador caleulard la longitud contando los i lores, los cuales son 12 en este caso, ‘Si exiscen menos inicializadores para un arreglo que los del amano especifica- do, Jos ott0s serén cero para variables externas 0 estiicas, pero basura para aulo- nidticas, Es umn error tener demasiado: la repeticion de un inicializador, ni de de un arreglo sin proporcionar tambii precedentes. Los arzeglos de caracteres son un caso especial de inicializacidn; se puede util rar una cadena.cn lugar de la notacién de llaves y comas: char patrén{ | = “ould”; ‘8 més corto pero equivalente a ito que esti a la mitad ‘Eneste caso, el tamafo del arreglo es ‘N09. 1¢0 (cuatro caracteres mas el terminador 4.10 Recursividad Las funciones de C pueden emplearse recursivamente; esto es Suede amarse a si misma ya sea directa oindirectamente, Conse un mimero como una eadena de caracteres. Camo ya se men: ‘Rats, los distos se generan en orden incorrect: los digits de orden inferior Aisponibies antes de los digitos de orden superior, pero se deben imprimir 9 el orden invertide, '2n dos soluciones a este problema. Una es almacenar los digitos en un ‘mo se generat, y después imprimirlos en orden inverso, como se hizo 96 FUNCIONES ¥ LA PSTRUCTURA DEL PROGRAMA cariTuto x Jn recursiva, en la que sy despues wr com el niimero ne. con itoa en Ia seccién 3.6, La alternativa os una solu eel digito del final, De nuevo, esta versién pues gativo mas grande, include J» printd: imprime 2 en decimal +/ vold printdlint n) i (a /10% rina 10); putehar(a Yo 10 + ‘09; j e ‘Cuando una funcién se ama a sf misma recursivamente, cada invocaciéa obt ‘un conjunta nuevo de todas las variables autonséticas, independiente del con} to previo. Asf,en printd(128) el primer printd recibe el argumenton = 123. 12al segundo printd, que a su vez pasa L'a un tercero, El printd del tereerniv imprime 1, después represe al segundo nivel. Ese printd imprime 2, después ‘gresa al primer nivel, E me 3 y termina, Otro buen ejemplo de recursividad es quicksort, un algoritmo de ordenami to desarrollado en 1962 por C. A. R. Hoare. Dado un arreglo, un elemento seleeciona y los otros se particionan en dos sudconjuntos —aquellos menores cl clememto de Ia particion y aquellos mayores o iguales a él. El mismo pr. se aplica después recursivamence a los dos subsonjuntos, Cuando un subeon ne Ja recursividad. Nuestra versién de quicksart no es la més rapida posible, pero es una de ims simples. Empleamos el elemento imtermedio de cada subarreglo para cionar. { seecion tt ELPREPROCESADOK DEE 97 swaply, left, (eft + right)/2}; [+ mueye el elemento de pariicién */ molars) ro pac +f last, 1): /» regresa el elemento de particion +/ Seo ha } Pasamos la operacién de intercambio « una funcién separada swap, puesto que courte tres veces ent qsort J+ swap: intercambia efi] ¥ v fl °/ ‘void swap(int vf J, 4 int temp; jeca estindar incluye una versién de gsort que puede ordenar objetos de cualquier tipo. [a recursividad no puede proporcionar un ahorro en almacenamiento, puesto ‘que en algiin lugar se debe mantener una pila de los valores procesados. Ni seré 1 eddigo recursive es més compa y de entender que su eauivaen: )pecialmente conveniente para estructuras de datos definidas en forma recur ‘como drboles; veremos un agradable ejemplo en la seccion 6.5. Bjercicio 4-12, Adapte las ideas de[printdal escribir la versiGn recursiva del pro- Eratnaltoa esi0 es, eonvierta un enievo en una cadens llamando @ una rutina re- sursiva, Rjercicio 413. Escriba una versidn recursiva de la funcién revorsoe), que invier- tela cadena s en su lugar, O 4.111 preprocesador de C C proporciona ciertas facilidades de lenguaje por medio de un preprocesador, un primer paso separado en Ja compilacion. Los dos ¢! ‘usan con més frecuencia son #include, para incluir el cont o durante la compilacion, v #deline, para reemplazar un simbolo por 98 PUNCIONES Y LA ESTRUCTURA DEL PROGRAMA carrute una secuencia ar esta seccién incluy ia de caracteres. Otras caracteristicas que se describen, compilaciéa condicional y macros con argumentos, 4.41.1 Inclusién de archivos La inclusién de archivos nes (entre otras cosas). Cualqui #includs “nombre” el manejo de grupos de #define y dectar inea fuente de la forma #nelude Frecuentemente existen varias lineas #include al principio de un archi fuente, para incluir proposiciones #dofine y declaraciones extern comunes, aa eer ares aa delaracién del prottio de una fue include cs la mejor manera de enlazar las declaraciones para un progr grande. Garantiza que todos los archivos fuente se suplirén con las mismas dé niciones y declaraciones de variables, y asf elimina un tipo de error particul mente desagradable. Por supuesto, cuando se cambia un archivo include, se ben recompilar todos los archivos que dependen de él 4.11.2 Substitueién de macros uombre exto de reemplazo BL PREPROGESADOR DEC 99 sgcci0N at ie definido con #define se compila 1adas. par comillas. earek nbredetinido, no habrasubstitucion en. printt (¢ASIRMA”) ni en AFIRMATIVO. Cualquier nombre puede definirse con cualquier texto de reemplazo. Por ejemplo. ‘#detina porsiomprs {or ( Tambien es posible def , para que el texte de reem- ser diferente para diferentes Hamadas de Ta macro. Como un ejer 1a macro Jlamada me ‘tdofine max (B, B) Aunque aparema ser una Cada eurrencia de un parametro formal (A 0 B)seri reemplazada por el argu. mento real correspondiente. Ast, x= mar(pta, +9) serd reemplazada por | x= (+a) > (e+8) 2 4a): EFD) En tanto que los argumentos se traten consistentemente, esta macro serviré para cnalquier tipo de datos; no hay necesidad de diferentes tipos de max para diferen- tes tipos de datos, como la habria con las funciones. Si cxamina la expansién de max, notaré algunos riesgos. Las expresiones 5¢ valian dos veces; esto es malo si involucra efectos colaterales como operadores Incrementales 0 de entrada y salida, Por ejemplo, max{i++, j++) /* INCORRECTO +/ Incrementard el valor mas grande dos veces, También debe tenerse do con los paréntesis, para asegurar que se preserva el orden de evalacion; consi- dere qué pasa cuando la macro #doline cuadrado(x) x + x invoca como cuadrado (x + 1), Sin embargo, las macros son valiosas. Un ejemplo prictico viene de ‘Ssidic-h>, donde gotchar y puichar se definen frecuentemente como macros Pata evitar el exceso de tiempo de ejecucién de una llamada a funcién por cada ‘atéter procesado, Las funciones en tambien se realizar general lente como macros. ‘Los nombres se pueden hacer indefinidos con #unde/, para asegurar que una Tuting es realmente una funcién, no una macro: Js INCORRECTO +/ 100 FUNCIONES Y LA ESTRUCTURA DEL PROGRAMA, capmruny FL PREPROCESADOR DEC 101 undel getchar int gotchar (void) 4 .. } formales no se reemplazan dentro de eadenas entre comil yen las (La proposicién de procesador ot es como else if). La expresién detined(nombre) en un #if es 1 si el nombre x¢ hi definido, y 0 de otra manera. Por ejemplo, para aseaurarse de que el contenido de un archive hd. se in- ‘una vez, el contenida del archivo se delimita con una vondicional como pardmetro reemplazado pore argumente rea de cadenas para hacer, por ejemplo, una macro de impresion para if Idefined (HDR) ‘define HDR (4 el contenido de hdr.h va aqui */ Ja macro se expande en peint(xy" "= gle" VR: y las cadenas se concatenan, asi el efecto es print(aly = %g\a" ay) Dentro del argumento real, cadal")se reemplaza por {\"| y cada {\] por [), que cl resultado e una constante de caden El operador ## del preprocesador proporciona una forma de concaten ‘gumentos reales durante fa expansién de una macro. Sj un pardmerro que ‘uencia prueba el nombre SYSTEM para decidir 4s SYSTEM == SYSV ‘define HDR “aysv_h” #olit SYSTEM == BSD ‘#daline HDR "bed. 0" elit SYSTEM = = MSDOS #deline HDR "mados.h" ‘#deline pastellronl, back) front ## back asi, pasto(nombre, 1) crea el token nombre]. ‘Las reglas para el uso anidado de ## son misteriosas; en el apéndice A else den encontrar mayores detalles. | #doline HDR “default.” 4 Fondit Ejercicio 4-14. Defina una macro[swaplt}z.9) que intercambie dos argu #inclade HOR de tipo (La estructura de bloques ayudaré.) G snetthlineas #ildal e#ilado! son formas especialzadas que prueban si un nom- ‘td definido. Fl primer ejemplo de #if de mds arriba pudo haberse escrito ‘Fifadel HDR define HDR 4.11.3 Inclusién condicional + contenido de hath ya aqui */ onait capituto s: Apuntadores y arreglos Un apuntador es una variable que contiene fa direction de una variable, Los apuntadores se utilizan mucho en C, en parte debido a que ellos son en ocasiones de erear programas . Esto ey verdadero cuando se utili- forma descuidada, y es facil crear apuntadores que seflalen a algiin lugar in ewnbargo, con disciplina, los apuntadores pueden también emplear- fener claridad y simplicidad. Este es el aspecto que trataromos de ‘lus {apuntador n void) reemplaza a char * como el tipo apropiado para un ‘pumtador penérico. 5.1 Apuntadores y direcciones mos con in dibujo simplificado de céimo se organiza la memoria. Una ica tiene un arreglo de celdas de memoria numeradas o direecionadas te, que pueden manipularse individualmente o en grupos conti- icin comtin es que cualquier byte puede ser un char, un par de cel- = de un byte pueden tratarse como un entero shor “nian un long. Un apuntador es tin grupo de eeld $8 Pueden mantener una direccién. Asi, “Pinta a et, podrla representarse la 104 APUNTADORES ¥ ARREGLOS 2 objetos que estan en arse a expresiones, jo * es cl operador de n lor, da acceso al objeto EL operador aplica a un apm ip es wn apuntador a iat +/ fp ahora apunta a x */ Las dectaraciones de x, y y z son lo que hemos visto todo el tiempo. La dé cidn del apuntador ip, le *dp, atol(char *); indica que en una expresion dp y ato{(e) tienen valores de tipo double, y qi argumento de atei ¢§ un apuntadar a char. ‘Tambien se debe notar la implicacién que tiene el hecho de que un apu do a senalar a una clase particular de objeto: cada apuntador s 0 de datos. (Hay una excopeién: un “‘apuntador a void” se plea para mantener cualquier tipo de apuntador, pero en si mismo no pu desrefe 10 se volver a tratar en la seceida $.11.) Stip apunta al encero x, entonces *ip puede presentarse en cualquier con donde xn ero, asi que tip = sip + 10; incrementa *ip en 10, [APUSTABORES V ARGLMENTOS DE FUNCIONES 108 {Los operadores unarios * y & se tigan mas estrechament os operadores aritmeticos; asi, la asignacién yor +2 fp, leagrega 1, y asigna ef resultado ay, mientras a que ip apunta, vo (ein) + + Los paréniesis son nevesarios en este apuntadores son variables, se pueden emplear sin (ig. €s ott apuntador a ist, copia el contenido de ip en ig; asi, hace que iq apunte a lo que Sp estd apuntando, 5.2 Apuntadores y argumentos de funciones Puesto que C pasa los argumentos de funciones por valor, no existe wna forma para gue la funcion que se invoca altere una variable de la funcion que la Por ejemplo, una rutina de ordenamienio podria intereamiblar dos elemen- tos desordenados con una funcidn llamada swap. No es suficiente ese erate, b); onde la funcién swap esta definida como void swap(iat x, int y) /+ INCORRECTO +f { int temp; 105 APUNTAPORES v ARREGLOS car spcC10N 32 APUNIADORES ¥ AROUMENTOS DE FUNCIONES 107 ue gotint regrese el estado de fin de io un argumento apuntador para almavent funcidn invocadora. Este esquemia tam los argumentos ay b. io intercambia copias Debido u la Lamada por valor, cestin en la rutina que ia lam. 1 ydeb, La forma de obtener Ios resultados que se desean es que el programa inv dor pase apuntadores a los valores que se cambiardn’ swap(Ga, 8b): Pugsto que el operador & produce la direccién de una variable, Ba es un or a a. Dentro de la misma funcion swap, los pardmetros se declaran para § apuntadores, y Se tiene acceso a los operandos indirectamente a través de void swaplint #px, int py) f+ intarcambia spx y *py +! { sian 7.4. na un asteglo con enteros por medio de Namadas a getint: fat tome : Ja funcion invocadora. cess = ay Esta versidn de getint regresa EOF como fin de archivo, cero sila spe = “py; tradi no es un mimero, y un valor positiv sila catrada contiene un nimero valido. spy = temp; b include Graficamente: int gotch(void); ‘oid ungetcktint); ‘> gotint: obtione el siguiente entero de la entrada y lo asigna.a “pn «/ int getin(int *pa) { st 6, slams ‘while (lecpace(e = gate + ignora espagios on blanco */ A llindig(e) 6c 1= BOF 86 c!= "+ GG != 9 | ‘ungelabal; + no nun hmero +/ Jor encontrado y también una sefal de fin de archivo cuank no hay mas que tomar, Esos valores tienen que regresarse por rutas separa para que sin importar qué valor se emplea para EOF, también pueda ser el de-un entero de la entrada, 108 APUNTADORES ¥ ARREOLOS carrung s9CC10N 33 APUNTAMORES Y ARREOLOS 109 ‘ahora la asignacién £= ely copiara el contenido de af0] en x. Sipe apunta a un elemento en particular de un arreglo, entonces por definicién pa] apunta al siguiente clemento, pa +i apunta i elementos después de pa, y pet apunta i elementos antes, Asi, si pa apunta a [0], “a+1) serefiere al contenido de afl], pa+ies la direccidn de als) go de pu patie \ “7 (or 3t ordinaria, También a que cl caracter ext que debe leerse puede regresar a cio 5-1. Como se escribi6, getint trata aun +0 .un — no seguido por ‘como una representacién valida de cera. Corrijala para que regrese tal ca a la entrada, o Ejercicio $:2, Escriba gatiloat, la analogia de punto flotante de getint. Qué ti regresa getfloat como su valor de funcién? © (pati) esel conteni- 5.3 Apuntadores y arreglos En C existe uma fuerte relactin entre apuntadores y arreglos, tan fuerte deben discutirse simultaneamente, Cualguier operacién que pueda lograrse pe indexacin de un arregio también puede realizarse con apuntadores. La version apuntadores ser por lo general mds rapids, pero, al menos para los no inicis algo més dificil de entender. Lo anterior es verdadero’ sin importar el tino 0 La declaracién daermgios. int flO}; la ariumética de apuntadores, es que pa+1 apunta al siguiente objeto, y pa+i define un arreglo a de tamafio 10, esto ¢s, un bloque de 10 objetos consecuti amados af0),a{1)..,a19] iumética de apuntadores es leo expresién de tipo arreglo es a direc pa = Gal si0eo =a pa ya tienen valores idénticos. Puesto que el nombre de un arregio es un sinénimo para la localidad del elemento inicial, la asignacién pa= = cabe */ ailocp += 2) oe etelehar +p) almacsuamiento ibe apstade por» + HM (p >= allocbuf && p < allochui + ALLOCSIZE) j sllocp = p; En general, un apuntador puede ser inicializado able, aunque normalmemte los tinicos valor presidn que involucre la direccion de un dato apropiado. La declaracién Static char ‘alloep = allocbul; como-cualquicr otra ss son cero 0 una definido y de un sece1ONS 4 ARCTMETICA DE DiRRCCTOWES 113 define a alloop coino un apuntador principio de allocbuf, que es la sig frienza. Esto también podria habers stale char salloop = @allocbut Jo inicializa para apuncar al i libre cuando cl programa co- puesto que'el nombre del arreglo es la direccién del elemento cero-ésimo. La prueba i (ellocbuf + ALLOCSIZE ~ allocp >= 2) {/+ sl cabo +/ i existe suficiente espacio para satisfacer la peticiin de m caracteres, facerse, alloc regresa un apuntador al pri ). De los El enguaje C wed ‘apuntadores y los entetos no son intercambiables. Cero ¢s Ia unica excep- constante cero puede ser asignada a un apumtador, y éste puede compa rarse contra la constaute cero. La constante simbélica NULL se emplea con fre~ cueneia en lugar de ecr0, come un mneménico para indicar mas claramente que ‘es un valor especial para un apuntador. NULL esté definido en . De aqui en adelante se utilizar NULL. Pruchas como H (allecbuf + ALLOOSIZE — alleep >= n) ( /* si cabe */ U(p >= allochu! &# p< allocbuf + ALLOCSIZE) ‘mussiran varias facetas importantes dé la aritmética de apuniadores. Primero, ts apuntadones posden comparase bao lias cicuntanci Sip Y q spuntan del mismo arreglo, entonees relacianes coma ==, !=, <, >= R stropy: copia t hacia void strepy(char +s, char +t) ( sat J+ srcpy: copie t haota s; version 3 con apuntadores */ void elcopy(char +=, char #1) 4 while (+++ = +14 +) 1=0; 3 ‘while (al = ¢ fi) != 40) Sey } En contraste, agul esti una versién de strepy con apuntadores: ‘J+ steepy: copia | hacia 5; veraiéx 1 con spuntadores +/ ‘void strepy(char +3, char +t) { while (9 = +1) = “\0) [ atts tees ‘Aunque esto puede parecer mi ‘notacion es considerable, y debe ‘Srocuentemiente en programas de . En la biblioteca esténdar () strepy, devuelve la cadena objetivo ‘como el valor de la funcién, La segunda rutina que examinaremos es stromp(s,t), que compara las cadenas sy ty regresa un valor negativo, cero © positive si s es lexicoarafi- 1, huesto que se encor que # y tno coinciden, t ) Osta==t, 30 Puesto que los argumencos se pasan por valor, stropy puode urilizar Jos pad la forma que le parezca mejor. Aqui hay apuntadores convenie lzdos, que se desplazan a lo largo del arreglo un cardeter a la ‘\O’ con que termina 4 se ha copiado a 8, { En la practica, strepy no ve eseribiria como se mostr6 anteciormente. Los p agramadores expertos de C preferirian Js steopy: copia t hacia s; versién 2 con apuintadexes +/ ‘oid strepy(char 4s, char *!) { while ((se+ + = st4 4) 1= 40) + Esto traslads el incremento de s y de t hacia dentro de la parte de prueba clo. El vak 1a version con apuntadores de stremp: /* stomp: ragrasa t +f int stromp(char *6, char *) TI APUNEABORES ¥ ARREGLOS ‘carcteLo Puesto que ++ y ~~ son operadores prefljas o postfijos, se presentan ot vombinacionss de *, ++ ¥——, aunque con menos frecuencia, Por ejemplo, de traer el caracter al que punta. En efeeio, la pareja de oy sp++ = val: val = py + mete val en la pila */ saca el tope de Ia pila y lo pone en val */ ‘son expresiones idiométicas estindar para meter y sacar algo de una pila; Ia seecidn 4.3, con apuntadores de la funcidn streat que s ia cadena ¢ a] final des. = muestra en el capitulo 2: stroat(e,)) Ejercicio 5-4. Escriba la Funciéa strend| ) copia hasta n caracteres de * hacia s, En ‘apéndice B se exponen descripciones més completas, = 5-6, Reescriba los programas y ejercicios apropiados de los capitula leando apuntadores en ue, a diferencia de los enteros, no se pueden ot iple ope donde entran los arreglos de apuntadores. cordenar se almacenan juntas en un gran arreglo de caracter : fener acceso & cada Linea por medio de un apuntador 2 su primer cardcier. SEOCION 56 ARREGLOS DE APUNTADOKES; APUNTADORES A APUNTADORES 119) «i lado, [08 apuntaclores se pueden almacenar en un arregio. Dos Iineas se pueden Zomparar pasando sus apuntadores a stromp. Cuando clos fineas desordenadas Genen gue intercambiarse, se intercambian Jos apuntadores en el arreglo de apun- tadores, no [as lineas de texto. lee todas tas tineas de entrada ‘ordénatas inprimelas en arden es mejor dividir el programa e n momento el paso de ordenamiento, y concentrémonos en las ¢s- tructuras de datos y la entrada y salida, La rutina de entrada tiene que reunir y guardar los caracteres de cada linea, y coustruir un arreglo de apumadores hacia las Wneas, También debe cont ada, puesto que esa informacién se requiere para el orde- ebido a que Ia funcién de entrada sl iene que imprimir las lineas en el orden en que apare- en en el arreglo de apuntadores, include ‘include « ‘deline MAXLINES 8000 finde # do .0a8 por ordenar +! char +linopte[MAZLINES); _/+ apuntadares a lineas de texto */ ‘at readhines(char Voie waitelines(char ine eid geort(ohar inept | nt Jolt, nt sight); + oxdena Iineas de entrada */ ‘aain( ) Br SPUNTADORES Y ARKEGLOS en int lines; /+ mimero de linees de entrada leidas «/ a que lineptr es un af tun apuntador @ char. Est i ((nlinee = readline ‘georilinepte, 0, lines ‘old wrilelines{chay slinept| |, lines) ( while (alines—~ > 0) line: lee lineas de entrad / imes(char “lineptl J, st maxtines) int len, nlines; char *p, line! MAXLEN), alin trabajard. lines = 0; white (Ven = getline(ine, MAXLEK}) > 0) Mf (lines >= maxing: | (p = alloc(len)) = = NULL) J+ qoort: ordena v vyoid qsori(char ett, int right) ‘\O% /* climina cardeter nueva tinea */ lineptr[olines+ +] = p; rota nbines; t J+ wsitelinoe: osoribe linees de salide */ ‘Void writelines(char slinepir{ |, int alines) { \a", lineptni); getline se traté en la seccién 1.9. ‘Tuevo elemento es la declaracién para inept: ‘lineptrMAXCINES] void snapichar “vf |, 122 APUNTADORES Y ARAECLOS ceaprruny Puesto que cualquier elemento individual de v (alias Hnepte) es un apumtador cardcter, temp también debe serlo, de modo que uno pueda copiarse ai otro, Ejercicio 5-7, Reeseriba readlines para alimacenar lineas en un arreglo prop cionado por main, en lugar de llamar a alloc para obtener espacio de miento. ;Cudnto mas rapido es el programa? 5,7 Arreglos multidimensionales Lenguaje C proporciona arreglos multidimensionales rectangulares, en Ia practica se usan menos que los arreglos de apuntadores. En esta, ‘mostraremas algunas ée sus propiedades, Considérese el problema de la conversién de fechas, de dia del mes a dia. ano y vieeversa, Por ejemplo, ef 1 de marzo es el 60° dia de un ato que no bisiesto, y ol 61° dia de uno que sf los. Definamos dos funciones para hace : day-of-yeer coavierte mes y dia en el dia del ato, y mont (eel dia del ano en mes y dia. Pucsto que esta ltima funcién calcula valores, los argumentos de mes y dia deben ser apuntadores: month day(1968, 60, Sm, &d) hace m igual a 2 y d igual 8 29 (29 de febrero), ‘Ambas funciones necesitan siga, le pasa a feb urante los célculos. Fl arreglo y fas funciones que realizan las transform son como se muestra a continuacién: {0, 31, 28, 31, 30, del ato 8 partic de mes y ato +/ ‘month, int day) int 5, leap; secci0w 37 ‘thon de un arreglo de do ARKEGLOS MULTIDIMENSIONALES 123 oap = yoar¥d == 0 && yeer95100 != Cj year%4d00 = = 0; return day; j Je monthday: obtiens mes, y dia a ‘yoid month day(int year, it yearday, ico de una expresion loxica, come lade leap, ev cero fe emplearse como indice del arroglo daytab. jay, para que ambas pucdan utilizarlo, (imo de char para almacenar enteros pequefos que no son daytab es el primer arreglo de caracteres de dos dimensiones eon el que hemos tratado. En C, un arreglo de dos dimensiones es en realidad un arveglo unidimen- sional, cada uno de cuyos elementos es un arreglo. Por ello, los subindices se es- criben como days /+ [renglén} [columna] +! 5 de modo que los nimeros de mes pue- Puesio que el espacio no es apremiante bse inicia con una fo es més claro arreglo de dos dim en Ia fumeién debe la declaracion de pa iniimero de renglo- 124 APUNTADORES ¥ ARREELaS carrot s1CciON 59 AVONTADORES V5. ARKEGLOS MULIIDIMENSIONALES 125 k rota (n <1 f'n > 12)? name(O] ; aame(al; ‘También podria ser Hint daytabt J 130) 1.) porque el nimero de renglones es irrelevante, o podria ser amel] $e almacena un apuntador a ellos. Puesto que ct ame no esté especificado, el compilador cuenta los inicializadores y completa ¢ aximero correcto. 3 un apuntador a 1mm arteglo de 13 entteros. Los (0 que los corchetes [| tienen mas alta preved 6.9 Apuntadores vs. arreglos multidimensionales 1evs ustarios de C algunas veces se contunden con la diferencia entre int tdaytab (13) 6 un arreglo de 13 apuntadores a entero. De modo més general, sélo la primer dimensién (subindice) de un arreglo queda abierta; todas las otras deben e3 carse, En la sevcitn $.12 se discute mas acerea de declaraciones complicadas, Ejercivio $-8. No existe deteccién de errores en day-of year ni en mont Soluclont:ntodefesto: asignade 200 locaidades de tamano de un int, y se emplea el cdlculo convencional de subindices rectangulares 20%rengién+columna para encontrar elemento 5.8 Inicializacién de arreglos de apuntadores Considérese el problema de escribir una funcién month name(n), que re tun apuntador a una cadena de caracteres que comiengan el nombre del n-Est mes. Esta es una aplicacién ideal para un arreglo static interno, mot contiene un arreglo reservado de cadenas de caracteres, y regresa un apur Ia cadena apropiada cuando se llama. Esta seccién muestra como se ese arreglo de nombres. La sintaxis es semejante a la de iniciaizaciones previas (08, otro a cincuenta y algin otro a ninguno. ingue hemos basado esta discusion en crminos de enceros, el uso mas fre- as de caracteres de + month name: —regresa él sombre del n-esimo mes +/ char “month nametint 2) char *naime| ] = { "Mos iegal’, “Ene, “Feb', "Mar" js nombre: ‘Mes legals} 126 APUNTADOMES ¥ ARREGLOS con la de un arreglo bidimensional: char anamme| ) [15] = { "Mos ilegal”, "Ene", "Feb", "Mar" J; 0 Ejercicio 5-9. Reescriba las rutinas day_ot_year y month_day empleando apy tadores en lugar de indices. 0 5.10 Argumentos en la linea de ordenes Dentro de un medio ambiente que maneje C hay una forma de pasar ar mentos en a lines de érdenes ode parametrosa un programa cuando empieza ejecucion. Cuando se llama a main se le invoea eon dos arguments. El prime (llamado por convencion arge, por ars i inea de Ordenes con los que se invae6 el programa; el segundo (axgv, por vector) €s un apuntador a un arreglo de cadenas de caravteres qu ne los argumentos, uno por cadena, Se acostumbea utilizar niveles ra lar esas cadenas de caracteres. imprime ‘ola, mundo Por convencién, argv{0] es ef nombre con ‘que argc es por lo menos 1. Si arge es 1, entonce no hay argu después del nombre del programa. En el ejemplo anterior, argo es argv(l] y argv{2] son “echo”, y “mundo, respectivamente guimento optativo cs argv[i] y el ultimo es axgvlargo—]; ademas, e est ‘quiere que argv[arge] sea un apuntador nulo, ergy: seCC10N 510 ARGUMENTOS EN LA LINEA DE ComANDOS 127 La primera version de echo trata a axgy como un arreglo de apuntadores a ca acters: ‘include J+ eco do los argumentos de la linea de éidenes; Ie. versidn «/ main(int arge, char argv J) int 5 argv) 2" ‘Como argv es un apuntador a un arreglo de apuntadores, se pucden manipular al apuntador en Tugar de indexar al arreglo. Esta siguiente variacién se basa en Incrementar argv, que es un apuntador 2 un apuntador a char, en tanto se dis ‘minuye arge: #inolude los arguuisntos de la linea de érdenes; 2s, version +/ ‘argc, char “ar while (—arge > 0) "Shadée", +4 tangy, (argo > 1) 2": retam 0; ' Puesto que argv es vin apuntador al inicio del arreglo de cadenas de argumentos, Inerementarlo en | (+ + argv) lo hace apuntar hacia argv(1] en lugar de apuntar ‘4 argv[0]. Cada incremento sucesivo lo mucve al siguiente argumento; entonces “argy es el apuntador a ese argumento. Al mismo tiempo, arge disminuye; cuan: 4 lesa a cero, no quedan argumentos por imprimit. Ex forma alternativa, podemos escribir la proposicién print! como priatlarge > Esto demuestra que el argumento de formato del print! también puede ser una Soren es Como un segundo ejemplo, hagames algunas mejoras ‘On 4.1 que encuentra un patron. Si se recuer: del programa, un e-quema que obs del programa grep de UNIX, cambiemos el programa de moi FE patron que se debe encontrar se espeifique por el primer argummento en ka de ordenes. "es", ++ tara), programa de la sex 12 APUNEABOKES y ARREGIOS Amncludo include ‘#deliae MAXLINE 1000) int qeiline(ehar vline, int max); (+ find: imprime Mneas que coincidien con el patrén del ler. arcumente main(int arge, char *argv! J) { har line[MAXLINE]; int found = 0; 4 (arge t= 2} pprial(*Uso: fad patsso\n"), ' Los arguments para opciones eben ser permitidos en cualquier orden; resto del programa debe ser independiente del numero de argumentos que ran presentes, Ademés, es conveniente para los usuarios que los argument Jas opciones puedan combinarse, como en find —ax pairdn Aqui esta el programa: seccION S10 ARGEMESTOS EN LA CINEA DECOMANDOS 129 #inclnde include ‘#detine MAXLINE 1000 {nt getline(char line, int max}: (> ind: imprime Vneas que coinciden con el patrén del ler. argumenta +/ ‘satn(int argo, char sargvt 1) { cchar line[MAXLINE]; eng lineno = 0; int ¢; except = 0, number = 0, found = 0; hile (—-arge > 0 86 (++ +argyi[0] == 9 while (¢ = ++ +argvid)) switch (c) ( case's: excopt = 1; break; umber = 1; break: default: printi“find opeisn ilegal Yeo\n", ©); arge = 0; found = —1) break; 130 APUNTADURES ¥ ARREGLOS sin procesar ¥ argv apunta al primera de tstos. AS, axge debe ser 1 y *argy det + tangy es un apuniador a un argumento tx mer carter. (Una formaalvernativa vil ne mids prioridad que * y que + +, k resiGn seria tomada como * + + (axgul émpleamos en el ciclo mas interno, donde la tarea tas; en tal caso, serd mis intuitivo separarlas en dos 0 tres pasos. ome 234 4 + se evallia.como 2 G44). 0 |. Modifique el programa entab y detab (escrites como ejerci ara que acepten una lista de puntos de tabulacién como arg los tabuladores habituales sino hay argumentos, 0 Ejercicio 5-12. Extienda entab y detab de modo que acepten la abreviatura, entab—m +n que indica puntos de tabulacion cada # columns, iniciando en la columma m. leccione ef comportamiento por omision mas conveniente (para el usuario). imprime las Gltimas 7 lineas. El progeama debe comportarse en forma 1 sin importar cua poco razonable sea la entrada o el valor de mt. Escriba él mma de manera qué haga el mejor uso de a memoria disponible; las Incas almacenarse como en el programa de ordenamiento de la seccién 5.6, 00 arreglo de dos dimensiones de tamaio fijo. © 5.11, Apuntadores a funciones En C, una funcién por si sola no es una variable, pero es ‘adores a funciones, que pueden asignarse, sor coloendos en si SeCCION St APUNTADORES A FUNCIDNES 131 ones, represados por funciones y otras cosas més, Ilustraremos esto modifican- sdinmiento de ordenami it que determina el orden de cualquier par de 1 ¥ unt algoritmo de ordenamiento que realiza comparaciones ented I a es de comparaci renies criterion, Estas la matodo. La comparacién lexicogréfica de dos lineas es realizada por stremp, como an- ‘cs; también requeriremos de una rutina numemp que compare el valor numérico dz dos lincas y regrese a misma clase de indicacin que hace stremp. Estas fun- ciones se declaran antes de main, y a qsort se le pasa un apuntador @ la funcién a. Se ha hecho un procesamienio deficiente de los errores en los atx con el fin de concentramnos en los elementos prin #inclde inchude ‘#doline MAXLINES 5000 ‘char *linoptr(MAXLINES}, 1+ mdi # de lineas @ ordenar */ apustadoree a lineae de taxto +/ dinex(char +lineptel telinoa(char “linen ‘oid geontvoid “lineptr (> orden linens de ent main(int argo, char +arg 4 int alinee ‘nt cumaric = 0) J» mimoro de lineae de entra Js 1 si oe ordenamisnte oumés if (arge > 1 8 stremp{argy{l), "-n") = = ;, MAXLINES)) >= 0) { ? aumomp : strome)}; 182 ARUNTADORES ¥ ARREGLOS canmens ceCc1ON 52 APUNTADORES \ FUNCIONES 1383 printf (enicada demasiado grande para ser ordenada\n") ‘esconsistemie con la declaracin; comp es un apuntador a una funcién, “comp es mend jg fancion, y ’ (oomp) (vil, lett) En la llamada a qsort, stromp y numemp son direeciones de funciones. Ci gsla llamada a 0s paréntesis son neeesarios para que los componentes sean correctamente asociados; sin ellos, int tcomp(void +, void *) [+ INCORRECTO «/ ‘que comp es una funcién que regresa un apuntador a is se sabe que son funciones, el operador & no es necesario, en la misma forma mo es necesario antes del nombre de un arreglo. Hemos eserito qsort de modo que pueda procesar cualquier tipo de dato, sélo cadenas de caracterés, Como se indica por la funcién prototipo, qsort tun arreglo de apuntadores, dos enteros y una funcién con dos argumentos de apuntador. Para los argumentos apuntadores se emplea @] tipo de apuntador ngrico void *, Cualquicr apuntader puede ser forzada a ser void * y res ‘sin pérdid de in ntos a veid*, El elaborada cast del argumento de la funci Ta funcion de lo cual es muy cadens mumeéric #aclade ‘pumcmp: compare sl y 32 numéricamente ¥/ int aumemp(char *s1, char "s2) { double vl, v2 I+ geoxt: clasitica v{let]...vjright] en orden axcendente +/ void qsor( vid tn int (rcomp) (void +, void +)) { inti, last; return — 2; void swap(void *4{ J, amt, it); ase df (vl > eZ) return 1; if (elt >= right) /*no hace nada si el arreglo contiene */ ‘abe return: f+ mence de dos aletnentos */ retuen 0 + right)2); b La funcién swap, que intercambia dos apuntadores, es idéntica a la que pre Seatamas anteriormente en este capitulo, excepto en que las deelaraciones se han cambiado a void +. void sirap(void of) , int georty, Inst +1, right, come); } {Las declaraciones dchen esiudiarye con euidado. El cuarto para comp) (veld, void + vg plea 3) Puede agregarse una ‘os algunas se convierten Rjerciclo $-14. Modifique el programa de ordenamicnto de modo que maneje lia bandera —r, que indica ordenar en orden inverso (descendente). Asegirese de que “x, trabaja con —n, 0 ue indiea que comp es un apuntador s una funcidn qué tiene dos argu void * y regresa un int EL uso de comp en la linea <0 ((reomp) 134 APUNTADORES ¥ ARREGLOS caprrut jereicio 5-15. Agregue la opcién ~f para igualar las letras maydseulas y mings nodo que no se haga distincién entre ellas durante el ordenamientos comparat, ay A son iguales. 5 5-16, Agregue la opci6a ~d (“orden de directorio’ independiente de opciones. “df para las entradas y —u para los nilmeros de pagina. 5.12 Declaraciones complicadas fencién que regresa un apuntador a int +/ (PC): (* pf: apuntador a une funcida que regresa un int +f ihustra el problema: + cs un operador prefijo y'ticne menor precedencia que (}, ‘modo que Jos paréntesis son necesarios para obligar a una asociacin apropi jon es extrafo que aparezcan declaraciones verdade ‘iGn verbal y viceversa. La deseripeién verbal se lee de izai La primera, del, es la més compleja, Convierte una dey deseripcién hecha con palabras, camo en estos ejemplos: aa tag. argv: apuniador a un apuntador a char int (edayr Gaylab: apuntador aun acroglo[13] de int int *daytabl23) daytab: arreglo[l3] do apuntadores 2 int ‘woid seompt ) comp: fuacion que regresa apuntador a void iCC10N 5.2 DECLARACIONSS COMPLICADAS 138 oie ¢comp) () char (6 4X: funeion que regress un apuntador @.un arreglal | de ‘ana fanesoa que ragress char apuntsdor a una juncion que regress void de apuniadores's una funcién que reareta tan apuniador 2 un arreqlo[8] de char dol esta basada en la gramatica que’ especifica un deckaraclor, que s¢ define en forma precisa en cl apéndice A, seccién 8.8; ésta es una forma simplificada: jiado como como éste (en donde dchdirecta se ha aby ( . pla ul ) 0 136 APUNTADORES v ARREGLOS El corazsn del programa del es un par de funciones, del y dirdel, que a declaracin; el programa se conoce streatfout, “apnmtador a"); ) I+ ditdel: reconoce an declarador ditecto +/ vold dirdl(void) { int type; ‘U Gokentppe == ({ aol; 5 Cokentspe 1= 9) printf oer: fats )\n") } ele if (tokentype. = = NAME) /+ norihre de variable +/ stropy(name, token); se prinii('error: nombre 0 (de!) esperade\"), ‘hile (ype = geiidken( )) = = PARENS | type “= BRACKETS) Js (del) o/ cupera mucho ante los ervores, lo confunden. Fsas mejoras se dejan como ejereicios. carn funciones se Maman recursivamente una a siCc1ON 12 BECLARACIONES COMPLICADAS 137 “Aqui estiin las variables globales y Ia cutina prineipal: sinclade include #inclnde ‘#deline MAXTOREN 100 enum { NAME, PARENS, BRACKETS }; > tipo del iin token «/ int ‘okentype; ‘char ‘oken{MAXTOKEN]: ‘cher name[MAXTOKEN]; Mess awhile (e = steht 3) = = 138 APUYTADOKES v aRREGLOS caprreto. totum tokentype = PARENS; Fase { ungetch(<); le del se recupere de errores en la entrada, © jue undel de modo que no agregue paréatesis redundantes 5-20, Extiende del para que maneje declaraciones con tipos de argu- 19s de funciones, calificadores como const, eioétera. relum tokentype = ¢; } Setch y ungeich se discutieron en el capitulo 4, Es mas facil ir en Ia cireccién inversa, especialmente si no nos preocup: or la generaci Paréntesis redundantes. El programa undel convierie descripcién verbal como "x ¢s una funcidn que regresa un apuntador a un de apuntadores a funciones que regeesan char”, que se expresard como C11) Tuncién undel también emplea las mismas variables externas que del. i {+ undel: convierte una descripelén verbal a declaracién */ main( ) 4 ‘at type; ‘char temp|MAXTOKEN), capuoe: Estructuras ‘Una estructura es una coleccién de una o mas variables, de tipos posiblemente diferentes, agrupadas bajo un solo nombre para manejo conveniente. (Las ex- inieturas se eonocen como “records” en algunos otros lenguajes, principalmente Pascal.) Las estructuras ayudan a organizar datos complicados, en pai dentro de programas grandes, debido a que permiten quea un grupo de variables relacionadas se les trate como una unidacl en lugar de como entidades separadas. ‘Un ejemplo tradicional de estructura es un ernplea- do esta descrito pot un conjunto de atriby mamero del seguro social, salario, ete. Algunos de estos atributos pued vez, Ser = eomponentes, como los tiene un domicilio y ‘alo un salario. Ciro ejemplo, mas tipico para C, procede de las gréficas: um pun- to es un par de coordenadas, un recidngulo es un par de puntos, y otros casos El principal cambio realizado por el esténdar ANSI es la defincién de la asig- acon de estructuras —las estructuras se pueden copier y asigiiar, pasar a funcio- nosy Ser regresadas por Funciones. Esto ha sido manejado por muchos compiladores durante Varios alos, pero las propiedades estan ahora definidas en forma precisa, Las estructuras y los arreglos automaticos ahora también se pueden inicializar. 8.1 Conceptos basicos sobre estructuras Definamos algunas estructuras propias para graficacién. EI objeto biisico es ‘wn punto, del cual supondremos que tiene una coordenada x y una coordenada ¥, ambas enteras. 142 Esrmucruxas carrito s seccion 62 [ESTRUCTURAS V FUNCIONES 143 Los des camponentes pueden ser colocados en una estructura declarada asi or pgniectn al nombre URSIN Gon Jas coordenadas del pun- Fl opecador miembro de estructura el nombre del miembro. Por ejemplo, to ph printi'bd, 4d", plix, ply); pata ealcular Ja distancia del origen (0,0) a pt, double dist, sqr(double) struc ity La palabra reservada struct presenta la declaracion de una estructura, que es una lista de declaraciones entre llaves, Un nombre optativo, llamado rétuto de. estructura, puede seguir a la palabra struct (como aqui lo hase point). El rd da nombre a esta clase de estructura, yen adelante puede ser utilizado como abrevintura para la parte de decta as variables nombradas dentro de la estructura se aman siembros. miembro de estructura o rétulo, y une variable ordinaria (esto es, no. miembs x pueden tener el mismo nombre sin conflicto, puesto que siempre se pueden dis i pie ‘mos nombres de miembros, aunque por cuestiones de estilo se deberian de usar [| uit por el contexto, Ademas, en diferentes: pil dist = sari((double)pt.c* px + (double)pty + pty); Las estruet jeden anidarse. Una representacion de un rec tun par de puntos que denoran las esquinas diagonalmente Una declaracién struct define un tipo. La llave derecha que termina la e de miembros puede ser Seguida por uns lista de variables, como se hace para cua quier tipo basico, Esto es, struct rect { struct { 2.) 8 struct pein s sintécticamente andlogo a y SES ‘La estructura reot contiene dos estructuras point. Si declaramos screen como jo de que cada proposicién declara a x, y y # como variables del tipe nombrado y causa que se les reserve espacio voutiguo. Una declaracién de estructura que no esta seguida por una lista de variabl no reserva espacio de almacenamiento sino que simplemente describe una plan ola forma de una ia declaracion esta rotulada, ¢ snes de instancias dela esirue de point, struct rect screen; cntonices screen. pil se refiere a la coordenada x del miembro pil de screen, define una variable pt que es una estructura de tipo struct point. Una estruct se puede inicializar al senuir su definiciém con uma lista de inicializadores, cada uno una expresidn constante, para los miembros: struct point maxpt ~ { $20, 200); ‘Una estructura automuitica también se puede inicializar por asignacién o la o a una funcion que regresa una estructura del tipo adecuado. Se hace referencia. a un miembro de una estructura en particular en una eX resin con una construccién de la forma nombre estructure.mlombro 6.2. Estructuras y funciones cas operaciones legales sobre una estructura son eopiarla 0 asignarla ambos, La copia ¥’la asignacién incluyen pasarlas como argumentos a funciones y también regre- Sar valores de funciones. Las éstructuras no se pueden comparar. Una estructura Se puede iniializar con una lista de valores eanstantes de miembros; una estruc ‘ura automatiea también se puede inicializar eon una asignacion, 144 esraverueas carttutog Investiguemos las estructuras eseribiendo algunas funciones para maniput puntos y retangulos. Hay por lo menos ites acercamicntos posibles: pasar radamente los componentes, pasar una estructura completa 0 pasar un apuntadk sella. Cada'uno tiene sus puntos buenos y malos. La primera funcién, makepoint, toma dos enteros y regresa ua estructy poial: 1 \Notese que no hay conflicto mismo nombre; incluso la struct rect screen; struct point middle; struct point makepoint(int, is!); sercon.ptl = makepoint(0, 0); screen pl = makepoint(XMAX, YMAX); middle = makepoint(ecreen.ptl.x + screen. pt2.x)/2, (screen ptl-y + screen.pi2.y)/2}; EL siguiente paso es un conjunio de funciones para hacer operaciones arit ‘icas sobre los puntos. Por Js addpolst: suma dos puntos +/ stroct point addpeini(struct peint pl, suet point 2) selum ph; } Aqui, tanto los argumentos como e! valor de retorna son estructuras. Incre ‘amos los componentes en pl en lugar de utilizar ex poral para hacer énfasis en que los parémetros de Valor como cualesquiera 0170s, secon 62 ESTRUCTURAS YFUNCIONES 148 Como otro ejemplo, Ja funcién ptinzect pruca si un punto esta dentro de un recténgulo, donde hemos adoprado la convencién de que un recténgulo incluye is lados izquierdo ¢ inferior pero no sus lados superior y derecho: (+ ptineoot: regrosa sip est en 1, O sino lo esta «/ {nt plinnect(vicuct point p, struct veet ¥) { golumn p.x >= 1pll.x G6 px < rpihx 8 py >> reply G8 py < Kp: b sto supone que el rectdngulo esta representado en una forma esténdar en donde rdenadas ptl son menores que las coordenadas piZ, La siguiente funcién un rectdngulo, garantizando que esté en forma candnica: (+ canonrect: pone en lorma candnics les coordenadas de wn rectanguls +! pact rect canonrect(struct rect ¥) struct rect tempi temp ptl.x = min(r.ptl.x, rpt2x); temp.ptl.y = min(r.ptl.y, r.pi2.y); temp.pt2.x = max(e pix, rpl22); tomp.pi2.y « max(rptl.y, rpt2y); return temp; ) una estructura granéle va a ser pasada a una fu pasar un apuntador que copiar fa estructa ructuras sont como los apuntadores « variables ord) struct point *Dp; dive que pp ¢s un apuntador a una estructura de tipo struct point. Si pp apunta @ una estructura point, *pp es la estructura, y (*pp).x y (*pp)-¥ son los miem- bros. Para emplear pp, S¢ podria escribir, por ciemplo, struct point origin, “pp; pp =Borigin; 1 origen es (S60, %d)\n", Cpp).x, (+ppl.y: ‘on necesarios en (*pp).x debido a que la precedencia del opera- dde estructura . es mayer que la de +, La expresion »pp.x significa “(Pp.x), to cual es ilegal debido a que x no es un apuntador. 146 estaucruRas, capmtuto, cere ABREGLOS DE ESTRUCTURAS 147 Los spuntadores a estructuras se usan eon tanta frecuencia que se hap cionado una notacién alternativa como abreviacion. Si p ¢s un apuntador a ‘tructura, entonces Jos nombres, ¥ un arreulo de enteros para las cuentas. Una posibilidad es usar dios arreglos paralelos, keyword y keyconunt, char +keyword(NKEYS| int keycount{NKEYS} pero el hecho de que Los arreglos sean paralelos suaiere una organizacidn diferen- fe, un arreglo de estructuras, Cada entrada de una palabra es una pareja: pe >milembra de estructura jembro en particular, El operador -> es un signo menos seguida por >.) De esta manera podriamos haber escrite ‘origen es (%64,¢d)\n", pp->, pP->); Tanto . como — > se asocian de izquierda a derecha, de modo que si ten char *word: ‘at count; struct wet 3, 9p = y bey un arreglo de parejas, La declaracién de estructura stroct key { entonces estas cuatro expresiones son equivalentes: ‘char "word; ee iat (rp-> ptll).x a un tipo de estructura key, define un arreglo keytab de estructuras de 10, ¥ reserva espacio de almacenamiento para ellas. Cada elemento del arre- ‘Los operadores de estructuras . y «>, junto con ( ) para lamadas a funci Shop une ecirvelere, Beles innibnste podtta esebir ori ¥ [] para subindices, estén hasta arriba de la jerarquia de precedencias y se sian estrechamente, Por ejemplo, dada la dedlaracién strat key ( eee ha wo bie i : we Struct hoy keytab KEYS); entonves +4 poten ‘es andloga a otras anteriores —la defini incrementa a Jen, no a p, puesto que los paréntesis implicitos son + abirecieeule ot an ise clones sais ase Los paréntesis se pueden emplear para alterar la asociaciOn: (+ + p)-—>lon inen ies de tener acceso a len, Y len incrementa a p struct key { char *word ‘p+ +->atr incrementa a p después de hacer el acceso a lo que str apunt 6.3 Arreglos de estructuras CConsidérese eseribir un programa para contar las ocurrencias de cada reservada de C. Se requiere de un arreplo de cadenas de caracteres para mal lizadores se listan en parejas correspondientes alos miembros de las . Podria ser mils preciso encerrar los inicializadores para cada“ estruetura entre Haves, como en pero las Haves internas no son necesarias cuando los inicializadores som varial simples o cadenas de caracteres, y cuando todos estan pr 1 numero de entradas ea el arreglo keytab se caleulard 8 presentes y el [] se deja vacio, progam que ches pas palabras reservadas debe estar orddenada en forma ascendente en Ia include ‘Pinchode #inchde ‘#doline MAKWORD 100 int getword(char +, int binsearch(char *, i ot key +, 1+ cuenta palabras resorvadae do C */ nain{ ) { int a; char word[MAXWORD]; while (aoiword(word, MAXWORD) |= EOF) i ‘eyiak(a|.covnl, keytablal.word); nde la funciona de busqueda binaria que se eseribié en el capitulo rae ARREGLOS DE ESTRUCTURAS 149 rotwen Q; } J binsearch: encuentra una palabra en tabfO). . .tabfn—1) «/ int binsoarch{char *word, struct key tab( | , int 2) 4 ‘nt cond; int low, high, mids a low = 0; bigh = 2-1; while (low <= bi = (low shi if ((cond = stromp(word, tab[mid.word)) < 0} igh = mid — ‘lee if (cond > 0) low = mid + 1; else roturn mid } return “1; ) Mostraremos la funcién getword en un momento; por ahora es suficiente decir que cada Hamada a getword encuentra una palabra, que se copia dentro del arve- alo referido como su primer argume! La cantidad NKEYS es ol de palabras en keytab, Aungue de keytab hasia que se encu Pero esto es mas de lo que se requiere, pu Geterminado con tamano del arregio es mirada, asi que el nt: cde entradas es size of keytab / size of struct key jona un operador 1 ir para ealvular slasof ubjero sizeo! (nombre de tipo) 150° stu S£0CI0N 64 APUNTABORES OESTRUCIURAS 151 =A; ira word|0]; dan un entero igual al tamano en byt ‘mente, sizeof produce un valor entero ra, Un nombre de tipo puede ser el n basico como int 0 dou! (0 un tipo derivado como una estructura © un apuntador. En nuestro caso, el nimero de palabras es te céleuta se jeron en cel capi e getword se ha coloca x adelante. La llamada a ungetch represa el caracter a la entrada para la spacios . sy digios; todas doling NEES (slenc! keytab / sizeo(steuct key) ‘otra forma de escribir esto es dividir el tamato del arceglo entre el tamana ‘#deline NKEYS (sizeo! keytab / sizeot keytabl0}) la ventaja de que no necesita set modificado si el tipo vambia, izeof no se puede utilizar en una linea #i, debido a que el preproces de tipos. Pera la expresion del #define no es evaluada el preprocesador, y aqui el codigo os lexal. ‘Ahora la funcién getword. Hemos escrito una funcién getword ‘que se requiere para este programa, pero no es complicada. ‘palabra” de la cotrada, donde una palabra es cualquiet dena de letras y digitos que principia con una espacio en blanco, El valor de la funcién EOF para fin de archivo, o el cardcter en sf mismo cuando no €s J+ qeiword: obtiene la siguiente palabra o cardcter de la entrada +) jab getword(char “word, int lim) { 6.4 Apuntadores a estructuras ara ilustrar algunas de las consideraciones invalucradas con apuntadores y arreglos de estructuras, escribamos de nuevo el programa de conteo de palabras, reservadas, esta vez utilizando apuntadores en lugar de subindices. Ladeclaracién externa de keytab no requiere de cambios, pero main y binsearch. si necesitan modificaciones, #unclude #inclade < ctype b> #include #dsfine MAXWORD 100 int getword(ohar «, int); struct kay -binsearch(char «, struct key Fs euonta palabrae xeservadas de C; version con apuntadares «/ main) 1 cher word[MAXWORD} struct key 2; while (getword{word, MAXWORD) = EOF) i ((salpha(word|0))) Uf (p= binsearch{word, keytab, NKEYS)) != NULL) po>count+ +7 for (p = keytab; p < keylab + NKEYS; p+ +) i (p—>count > 0) printd("966a Sein", p—Seounl, p~> word) return 0; for ( ; ~-lim > 0; w+ +) = gotch( )) ( ane eeaesubce sie s6CCION 65 ESTRUCTURAS AUTORREFERENCIADAS 183, imer elemento después det tin de un acreglo (esto es, =tablat] + int 2) + binsoarch: encuentra una palabra en struct key *binsearch(char *woed, struct key { int cond struct key “low = Stab) struct key *high = struct key +d; iéa con p toma en cuenta et srementa_p con la cantidad correcta feglo de estructuras, y la prueba while Clow < igh) { mid = low + (high-low) / 2; [cond = stremp{word, mid— >ward)) < 0) high = mid) ‘else if (cond > 0) low = mid + 1; else zoturn mid; 1 return NUL; comentario acerca del formato del programa: cuando una funcidn regresa un tipo complicado como un apuntador a estructura, como en scuct key sbinsearch(char *word, struct koy “tab, int) ‘el nombre de la funcién puede ser dificil fexto. Por eso, algunas veces se emplea Agui hay varias cosas que ameritan nota. Primero, la declaracién de bin debe indicar que rearesa un apuntador a struct key en lugar de un entero; eto a tanto en cl prototipo de la funcién como en binsearch. Si binsearch enc palabra, regresa un apuntador a ella; sino, regresa NULL. ‘Segundo, ahora se tiene acceso a los elementos de keytab por medio de apus tadores, Esto requiere de cambios significativos en binseazch. izadores para low y high son ahora apuntadores al inicio y just despues del final de la tabla, EL cdlculo del elemento intermedio ya no puede ser simplemente yy de encontrar con un editor de lo alternative: sieucl key + binsearch(char *word, struct key #lab, int n) Esto ¢s algo de gusto personal; seleccione la forma que prefiera y manténgala. mid = (low thigh} (2 /* INCORRECTO +/ 85 Estructuras autorreferenciadas puesto que I ma, por lo qn 4 de dos apuntadores es ilegal. Sin embargo, Ta resta es le ighdow ese! miknero de-elementos,¥-aal Supbngise que descamos mana problem mis gta de contar as ote TPencias de codas las palabras en alguna Pot anticipado, no podemos or mid = low + (high-low) / 2 hace que mid apunte al elemento que esté a la mitad entre low y high. EL cambio més importante es ajustar el algoritmo para estar Seguros de qUs ‘no genera un apuntador ilegal 0 acceso a un elemento Fuera del ar alo. ambas fuera de los limites leenl desreferenciar las Sin embargo, la definicién del lenguaje garantiza que la aritmética de apu! ide a crecer en prop lemos organizar los ins? de palabras que ya es mantener siempre ordenado el con; jocando cada wna en su posiciOn c 154 eSTRUCTURAS earrrvt de cualquier manera, no se podria realizar recorriendo fas palabras en un arrey lineal —tambien tornado demasiado tiempo. En lugar de ello utilizaremos i El drbol contiene ua “nodo”” por cada palabra ‘up spuntador al texto de la palabra tuna cuenta dal numero de ocurrencias un apuntador al nodo hijo de Ia iaquiorda tun apuntador al node hija de la darecha \Ningiin nodo puede tener més de dos hijos; s6lo puede tener cero 0 uno, Los nodos se mantienen de tal manera que en cualquier nodo el subsérbol | quierdo contienc sélo palabras que son lexicograficamente menores que la ‘bra que est on e) nodo, y el subdrbol de la derecha sélo contiene palabras son mayores, Este es el arbol para la oracién “Es tiempo de que todos los ‘bres buenos vengan al auxilio de su partide”, como se construy6 al insertar palabra tal como fue encontrada. aN ae” Sane we, oh Sys ahah Nes 7 \ auzllio hombres partido Para descubrir si una nueva palabra ya esta en cl art rela con la que esta almacenada en ese noda. Si coincide, la pregunta se resp la nueva palabra es menor que la palabra del érbol, conti ra manera, en el nodo hijo: Ia palabra nueva ne .propiado para agregar la sinict tnode ( + el nodo del Arbol: +/ ‘char “word; f> apunta hacia ol texto +/ int count; f+ mimers de ocurrencias */ struct inode «leit struct inode “right; hijo a la izquierda ala derecha */ ESTRUCTURNS AUTORREFERENCIAOAS 18S sec1ON 6S za declaracion recursiva de un nodo podria parecer riesgoss, pero es correcta. fo ilegal Ue ura esiruetora contenga ina instancia de si misma, ere struct tnode left; igeclaea a Tolt como wn apuntador @ trode, no como un node en sf ‘Ocasionalmente, se requiere de una variacgn de estructuras autorreferenciadas: dos estructuvas que Hagan referencia una a la otra. La forma de manejar esto es: struct t ( suet s*p; /* p apunta a una s +/ if struct «4 sicuct ts; f+ q ayiunla a uma t+) todo el programa es sorprendentemente pequeho, dado un instala en el arbol con #inclade rnclude ‘#detine MAXWORD 100 ruct inode *addtreo(struct tnode +, char *); void treep: 1 inode *); lt gotword(cbar *, it}; 1+ conteo de irocuencia do palabras */ maint ) { struct node oot) char word/MAXWORD]; root = NULL; while (getword(word, MAXWORD) != 80F) ((salpha(wordl root = addtzse(root, word); sreeprint(rcot return O; Jin addtree es recursiva. main presenta una palabra al nivel superior ‘cl arbol (fa raiz). En cada etapa, la palabra se compara con la que ya esté alma 156 ESTRUCTUEAS crea un nuevo nodo, addtree regresa un apuntador a él struct tnode “talloctvoid); char *strdup(char *); new: agvege un nods con w, ano bajo p */ struct tmode raddiroe(etruct inode »p, char w) 4 int cond) == NULL) /+ Megé una nueva palabra +/ p= tallool); (crea un auewo modo +/ po>ward = stedupl); pr>eoust = ly praleft = p—>right = NULL; ) else sf ((cond = stromp(w, p~>word)) poScountt +; + palabra ra else (cond < 0) /* menor que ol contenido del subarbol ixquiordo +f po>left = addtroe(p~>left, w); 4 else J+ mayor gue el contenido del subsrbal derecho poSright = addtrea(n> right, ve); rolurn p: y ls nueva palabra se copia a un lugar bBlaremos de esas rutinas en un momento.) La cuen sé hacen nulos. Esta parte del eddigo se ejecuta s ando esté siendo agregado tun nuevo nodo. Hemos omit impeosicn del arbol p on orcas 4/ void treeprint(atruct tode =p) = NUL) { SECCION 6S LESTRUCTURAS AUTORREFERENCIADAS 187 treeprint(p—>: printl("%4d Ye ‘treeprint(n~ > right) p> eount, p~> word); 1 , Una nota practice: si el drbol se ‘“desbalancea”’ debido a que las palabras no llegan en orden aleatoria, cl tiempo de ejecucion puede aumentar demasiado, En el peor de [os casos, si las palabras ya estin en orden, este programa real cosa simulacién de bisqueda lineal. Existen gencralizaciones del ar 10 padeven de este comportamiento del peor caso, pero no las desc iremos ces dé dejar este ejemplo, también es descable una breve exposicién sobre ‘oblema relacionado can los asignadores de memoria. Es claramente desea- ble que s6lo exista un asignador de almaccnamiento en un programa, aun cuando asigne diferentes clases de objetos. Pero si un asignador va a procesar peticiones de, digamos, apuntadores a char y apuntadores a struct tnodes, surgen des pre- sguntas, Primera, :cémo cumple los requisitos de la mayor parte de las mndquinas reales, de que los objetos de ciertos tipos deben satisfacer restricciones de alinea- cidn (por ejemplo, generalmente los enteros deben ser situados en localidades pa- a4)? Segunda, ,cusles declaraciones pueden iraiar con el hecho de que un asigna- dor de memoria necesariamente debe regresar diferentes clases de apuntadores? Los requisitos de alineacién por lo general se pueden satisfacer facilmente, al espacio desperdiciado, asegurando que el asignador siempre regre 0 de declaraci6n para una funcida c pregunta acerca del para cualquier lenguaje que tome con scriedad la metodo apropiado es declarar que malloc regres un api at explicitame . malloc y las rutinas relativas estan declaradas en cl header Satdlib.h>. Asi, talloc se puede escribir como #include Js talloc: erga un tnode +/ struct tmode “talloc(roid) 4 return (struct inode +) malloc(sizeoi(etract taode)); ) Strdup simplemente copia la eaden ©, obtenido por una llamada a mal por su argumentoa un lugar segu- 158 rsTaLcraAs cart | secciOn ss DUSQUEDA EN TABLAS 159 y regresa un apuntador SHEARER A)" EAS HnlIaNdD Gere sélo cadenas de earacteres. Jookup(e) busca s al lugar ea donde fue encontrado, o NULL ae EI algori queda fash —el pequefio ent ue despues Se usa para index amaleciicands) +3} 4 FL pase NG #/ Gores. Un elemento del arreglo apui quedk gin nombre ha obtenide ese valor. = EET i wate i F [oe =—7] = sombre Seta Ejercicio 6-2, Escriba un programa que lea un programa en C e imprima en or den afabético sada grujo de nombres de variable que sean idénticas en sus pri Un bloque de fa lista es una estructura que contiene apuintadores al nombre, al texto de reemplazo y al siguiente blogue de la lista, Un siguiente apuntador ‘ulo magca el final de fa lista, Ejercicia 6-3. Escriba un programst de referencias eruzacks que imprima una struct alist { ada de la tabla: +/ de todas las palabras de un documento, ¥ para cada palabra, una lista de los struct alist next; /+ siguiente entrada ex Ia cadena */ rmeros de linea en los que aparece. Elimine palabras como * har ‘name; nombre definide *! char *doln; 1+ taxto de roomplazo +! Ejercicio 6-4, Bscriba un programa que imprima las distintas palabras de su en ‘trada, ordenadas en forma descendente de acuerdo con su frecuencia de ocus cia, Precede a cada palabra por su contco. 0 E/ arreglo de apuntadores es 3610 #deline HASHSIZE 101 6.6 Busqueda en tablas sci shitiremos os commoners de un paquets de Doe en las rtinay de manejo de tablas de simibolos de -nplo, considere la proposicion #def de hash posible, pero es pequenta y cfectiva Yash: forma un valor hach para la cadena s */ unsigned hash(char *s) { unsigned haskval; for (hasbval = 0; +8 |= "\0' hhashval = +3 + 1 + hashval; return hachval % BASHSIZE, } La aritmética sin signo asegura que el valor de hash no es negative. se debe reemplazar por 1 Enisten dos rutinas que manipulan los nombres y textos de reempl install(s,t) registra el nombre s y el texto de reemplazo t en una tabla; $ yt 160 rsrRuerunas. otra manera, regresa NULL. ‘busca ¢ on hashtab +/ Aeokupchar +s) J» Teokup: struct alist «np; for (ap = hashlabfhash(s)]; np != NULL; np = np~>anext] El cielo for que esta en lockup ¢s la expresidn idiomatica esténdar para moverse sobre una lista ligada: for (ptr = head; ptr != NULL; ptr = ptr~>next) unsigned hashval; (ap = lookup{name hhoshval = hash{naz xnp->aoxt = hashlab[hashvall; Libera la anterior defn +/ NOLL) :CCI0N 67 Ejercieio 6-5, Escriba una funcién undef que cidn de la tabla mantenida por lookup ¢ install imo de int. El tipo Longitud puede emplearse .ctamente de la misma manera en que lo podria Longitud len, maslea: Longitud “lengths! |; De mode asa 1a declaracién Notese que el tipo que se declara en un typedef aparece en Ja posivién de un nombre de variable, no justo después ce la palabra typedef. Sintacticamente, typedef es como las clases de almacenamient 40 nombres con mayiscula } Teeonede; 162 esreverunas exprrute SeCCION 68 UNIOWES 163 encontrado en ol mancjad te pod . El valor de una constante én pa sto crea dos nuevas palabras reservadas para tipas, lamados Treenode (una ex. oman ejemplo, que pod tructura) y Treeptr (un apuntador a la estructura). Entonces, la rutina t podria ser “Toweptr manejador de tablas si el valor: do en el mismo lugar sin importar su tipo. Este es el propdsito de uri —una sola variable que puede legitimamente guardar uno de varios tipos. La sin- on typedef no crea un nuevo tipo ef ro nombre para agin tipo ya existen- Jas varinbles declaradas de esta man las mismas propiedades que las variables cuyas declar iente En una unin; si algo se almacena como un tipo y se recu- el resultado depende de Ia implantacién. iene acceso u los miembros de una union ‘AF sttemp, mumempy dentro del breve programa del capitulo 5, apuntador-unicin—> miernbro precisamente como a las estructuras. Si la variable utype se emplea para llevar ido en u, entonces se podria ver el c6digo ras cantidades enteras, y entonces hacer un conjunto apropiade de seleeciones short, int y long para cada maquina, Tipes como size y ptrdiff_t de la bibliote ‘estindar son ejemplos, EI segundo propdsito de los typedef es proporcionar mejor docu! cién para un programa —un tipo llamado Treeptr puede ser mas facil de entendi que uno declarado s6lo como un apuntador a una estructura complicada. 6.8 Uniones Viceversa) esi de-estructuras definido por struct ‘char same; sal flags, 164 esrmucturas carnuto int ulype; ‘al miembro sval se le refiere como symiabi-uival yal primer cardcter de la cadena sval por cualquiera de En efecto, una unién es una estructura en un desplazamiento de cero a pa grande para mantener al imacensmiento del capitulo € muestra cémo se puede obligar a que una variable sea alineada para una clase particul 6.9 Campos de bits ‘Cuando el espacio de almacen: Paquetar varios objetos dentro de una sola palabra de maquina; un uso co! €6 un conjunto de banderas de un bit en aplicaciones como tablas de sim! para compiladores. Los formates de dato 8 eXLermamente, como inter Faces hacia dispostivos de hardware, frecuentemente requieren la capacidad de tomar partes de una palabra. Imaginese un fragmento de un compitador que manipula una tabla de sf los, Cada identificador dentro de un programa tiene cicrta informacidn asoci ‘41, por ejemplo, si es o no una palabra reservada, si es 0 no externa y/o estat macion es co 10 de banderas de un bit deniro de un char o int, La forma usual en que esto se realiza es definiendo un conjunto de “més as" correspondientes a las posiciones relevantes de bits, como en s6CC108 69 CAMPOS DEBTS 165 ‘#deline KEYWORD O1 #doline EXTERNAL 02 #dsline STATIC 4 esum | KEYWORD = 01, EXTERNAL ~ 02, STATIC = 04 }; Ciertas expresiones aparecen frecuentemente: flags |= EXTERNAL | STATIC; enciende los bits EXTERNAL y STATIC en flags, en tanto que flogs é=~[EXTERNAL | STATIC); los apaga, y igs & (EXTERNAL | STATIC)) == 0) tin apagados. struct ( unsigned int is_static 1, ) flags; is_extorn, etc. Los campos Comportan como pequchos enteros y pueden participar en expresiones aritmé- como Jo hacen otros enteras. Asi, el ejemplo previo pudo eseribirse mis na- imente como flags.is_extorn = flags.is_static = 1; 166 rsraucrunas para encender tos bits; 98.is_exlern = flags.le_static = 0; para apagarl A (flag ix_extern = = 0 68 flage.iestatic = = 0) para probarlos. ‘Casi todo acerca de los campos es denendiente de la implantacion. Elique un lapar al limite de una palabra se define por la implantacion, iecesitan tener namire; los campos sin nombre (dos puntos y su: ‘ud solamente) se emplean para llenar espacios. El ancho especial 0 puede Plearse para ob| alineacion al siguient a. j Los campos se asignan de izquierda a derecha en algunas maquinas y de cha a izquierda en otras. Esto significa que aunque los campos son titiles el mantenimiento de estructuras de datos definidas internamente, la pregunt ‘qué punta viene primero tiene que considerarse cuidadosamente cuando se cionan datos definidos externamente; los programas que dependen de tales ‘ho son transportables. Los campos silo se pueden declarar como enteros; transpei lidad, se debe especificar ex} ¢ signed 0 unsigned. } ie el operador & no puede arse a ello capruto7; Entrada y salida Sstandar, normalmente et teclado, con getchar: int getchar(eoid) wr 168 ENTRADA VsALIDA eaprruLo 7 getchar regresa el siguiente cardeter de la entrada cada vez que se invoca, o EOF cuando encuentra fin de archive. La constante simbélica EOF esta defiaida en . El valor es tipicamente 1, pero las pruebas se deben eseribir en fun. s6idn de BOF, de modo que sean independientes del valor especilico. En muchos mecios ambientes, 10 puede tomar el lugar del 1eeladg -empleande la convencién < para redireccionamiento de entrada: si un programa prog usa getchar, en: a de Grdenes, prog nombrearch: si preg utiliza putchar, prog >archsal cescribird la salida estandar hacia archsal. Si st pet prog | etroproy dijo Ya saida exténdar de prog en ia entrada esténdar de otropreg. La sada procueida por pein también encuentra su camino hacis lx sida es tandar. Las llamadas a putchar y @ printf pueden estar traslapadas —la sali ‘aparece en el orden en que se hicieron las llamadas. ‘Cada archivo fuente que se refiera 2 una funcién de biblioteca de entrada/' lida debe contencr la linea| include antes dele primera referencia, Cuando un nombre se del liga una busqueda del header en algunos lugares es iemas UNIX, tipicamente en el directorio /usr/inclade). Muchos prostamas teen solo un flujo de entrada y esstiben s6lo un flujo ¢ ales programas In entrada y solida von getohar, putchar y pr adecuada y en realidad es suficente para comenzar. Bi corto si se emplea la redirecciSn para conectar Ia salida de seecion 72 SALIDA CON FORMATO PRINTE 169 programa a la entrada de otro, Por ejemplo, eonsidérese al programa lower, que convierte su entrada a mindsculas: #inclade #include sain( ) J" lower: conviecte le entrada mindseules */ int 6; Escriba un programa que convierta mayisculas a miniisculas 0 vi- sa, dependiende del nombre con que se inveque, dado en axgvi0). 7.2. Salida con formato—printt ta, véase el apéndice B. nt printi(char “format, argy, a ime sus argumientos en Ja Salida estanndar bajo rniimero de caracteres impresos. La cadena de formato contiene dos tipos de objecos: earacteres ordinarios, ue son copiados al flujo de salida, y es jiones de conversion, cada uno Se fos cuales causa la conversion e impresion de los siguientes argumentos sucesi- Ws de printf. Cada especificacion de conversisa comienza con un We y termina n un caracter de conversién. Entre el % y el caracter de conversién pueden es- 1 orden: -Priatf convierte, da formato e 170 EyeRADAYY SALIDA carmnoy © Un signo menos, que especifica el ajuste a la izquierda del argumento conver ‘ndmero que expecifica el ancho minimo de campo. El argumento converti- do sera impreso dentro de un campo. de al menos este ancho. Si es mecesario ado de blancos a la izquierda (0 a la derecha, si se requiere ajuste a rda) para completar Ta amplitud del campo, que separa el ancho de campo de Ia precisi6 precision, que especifies ef mimero maximo de earacteres de una, cadena que seran impresos, 0 el nimero de dixitos después del punto decimal de digitos para un emero, a ele) si sera como Ipreso como un short, © Una hsiel ent ong. Los caracteres de conversién se muestran en la tabla 7-1. Si el cardecter después del % no es una especificaciin de conversién, el comportamiento no esta definido, ‘TAMLA 71. CONVERSIONES BASICAS DE PRINTE ‘CakacteR Tivo DF ARGEMENTO: IMPRESS COMO i; mmero cetal sin sigho (sin vero inicial). xX | int; ndmero hexadecimal sin signo (con un Ox © OX inicial, usando abed © ABCDEF para 10, » ro decimal sin signo ° areter sen s char *; imprime caractecex de una cadena hasta un \O"o ol mimero de racteres dado por la precision, 4 1 Imadldddddd, ea donde el nimero de ds esta dado por la prec sion (predeterminad a 6, ek -sauco [—Jmddtdldl = xx, en donde el nimero 6 mn (predeterminado a 6). a6 Fai el exponen es menor que —4 o mayor 0 gull jpuntador (represeniacion dependiente de la yavertido en ningum argumentot iniprime un ar por +, en cuyo caso el valor. (que debe ser int). Por ejemplo, printi("6a8", max, ¢); seceton73 LSTAS DE ARGLMENTOS DE LONGITUD VARIABLE 17H La mayoria de las conversiones de formato se han jlustrado en ca sigres. Una excepcion ¢3 la precision relacionada can las cadena. dda campo para que se pueda apreciar su e he ‘hola, mundo: 26108 ‘hola, mundo: %4.108: ‘hola, mund: 5-10: hola, mundo: 41S hola, mundo: 6-188: hola, mundo %15.10e ; ola, mund: 6-15.10: chola, mud Una advertencia: prin emplea su primer argumento pata devidir eusintos tos. También debe advertr la diferencia entre estas dos print J+ BALLA eis contione % +/ pecintf("Y9s", 5); /* SURO +/ La funcién sprint re Is salida en de una cadena: Jnl sprinliichar *eadona, char "format, ar Jas misinas conversiones que printf, pero almacena sprinifda formato a los ara format como antes, pero catoca simat de acuerdo con la eostumbre local, y separar Iineas largas de texto, 3 7.3. Listas de argumentos de longitud variable sia seevibn contiene la realizacin de und versién minima de printf, para ‘Mostrar e6mo escribir una funcidn que procese una lisa de argumentos de lon ‘Wd variable en una forma transportable. Puesto que estamos interesados pr Talniente en el procesamiento de argumentos, minprint! procesard la cadena de forexata y losargumentos, nero lamar al printf real para acer las conversiones & formato, 172_ENTRADS YSALIDA La declaracidn correcta para printf es ) significa que el niimero y tipo de esos argumentos pu su SOlo puede aparecer al final de la lista de argumentoy Nuestra minprintf se declara como ‘void minprinifehar “imt, ..) RO cent 1 nemuleanimeres cere printf rico sta en cémo minprint! recorre la lista de arguimentos cuanda int printi(cher “ imo argumento nombre ¢5-empleado por vastart para iniciar. Cada lamada de yaar regresa un argumento y avanza ap al sigui ‘at val; euble dvali switch (2+ +p) conse val = va_arg(ap, iat); SECCION 3.4 ENTRADA CON FORWATO-SCANF 173, (ap, double) seval; val+ +) default potoharlen); break; ) } va_end(ap); (+ limpla cuando todo eslé hecho +/ -3. Auimiente minprintt para que mane! 7.4 Entrada con formato—scant La funcién scant es la entrada anéloga de printf, y proporciona muchas. de las mismas facilidades de conversion en la direccién opuesta, int soanf{char “format, ...) cant lee caracteres de Ia entrada estindar, los imerpreta de acuerdo con las espe- cificaciones que estén en formal, y almacena los resultados almacenarse la entrada correspondientemente convertida. Como con printf, esta seveidn es un resumen de las lidades mas ‘no una lista exhaustiva. scenf se detiene cuando termina con su cadena de formato, 0 cuando alguna catrada no coincide con la especificacién de control. Regresa como su valor el uimero de items de entrada que coinciden con éxito. Esto se puede emplear para Gecidir cuamtos jtems se encontraron. Al final del archivo, regresa BOF; né~ tose que esto es diferente de 0, q -a que el siguiente caracter de enti -oineide con la primera especificacién en Ja caciena de formato, La signi ada a seanf continia la busqueda inmediatamente después del Gltimo cardc- ler que ya fue convertido. Existe también una funcién sscanf que lee de una cadena y no de Ja entrada eséndar: {at secani(ehar ‘cadena, char format, argy, ard.) 174 ENTRADA SALIDA, caritULo 2 a la cadena de acuerdo con el formato en format, ¥ almacena el valor resultante a través de arg,, arg,, etc. Estos argumentos deben ser apuntadores, La cadena de formato generalmente contiene especificaciones de conversién, las cuales son empleadas para controlar la conversion de entrada. La cadena de. Formato puede contener: vo de supresién de asigna maximo de campo, una hy yun carieter de conversién La expeciticaciom de conversion dirige la conversion det siguiente campo de en trada, Normalmeme el resultado se colocs en la variable apuntada por el argus mento correspondiente. Si se indica la supresin de asignacién con el cardctet «, sin embargo, el cimpo de entrada es ignorado y no se realiza asignacfon alguna. Un campo de entrada esta definide como una cadena de caracteres que no son espa~ cio en blanco; se extiende hasta el siguiente espacio en blanco 0 que ef ancho de campo se agor 6 siiprimido: para leer el siguiente espacio no blanco, use %ls, SECEION 7 ENTRADA CON FORMATO-SCANE 175 © cadena de earscweres (no entraeor char *, apunuaa un acreglo de ssorace jentemente grande para Ia cadena y una terminacién NO" ‘que serd agresada, nlimero de punto flotante con signo, punto decimal y exponente optativos; float « % 5 literals no se hace asignacién alguna. Los caracteres de conversion d, i, ©, u, x pueden ser precedidos por h para indicar que en la a de argumentos aparece un apuntador a short en hugar de :) para indicar que aparece un apuntador a long en la lista jane, los caracteres de conversién «, £, ¢ pueden ser precedidos por I para indicar que hay un apuntadora double en lugarde a ta de arguiientos, Como un primer ejemplo, la rudimentaria calculadora del capitulo 4 se puede eseribir com seant para hacer la conversion ee entrada: include mein() /+-ealeuladore nidimentaria «/ 1 ) Supongu que deseamos leer lineas de entrada que contienen fechas de la forma 28 Dic 1988 Ls proposicién seanf es int day, year; char rionthname!20) sconi(6d %s 96a", Sday, monthname, Byes); No se emplea & con monthname, un apuntador. Pueden aparever caracteres de scant, yde- ben caincidir con los mismos caracteres de la entrada. De modo que podemos leer fechas de la forma mm/dd/yy con esta propasicién scanf: tnt day, month, year; scani{"%4a/%ha! 4d", month, Sey, Syear); 316 ENTRADA Y-SALIDA carrie! scant ignora los blancos y los tabuladores que estén en su cadena de formato, Ademés, salta sobre los espacios en blanco (blancos, tabuladores, nuevas li ete.) mientras busca los valores de entrada. Para leer de entradas cuyo fe Lo est fijo, a menudo es mejor leer una linea a la vez, y despues separarla eng, sscanf. Por ejemplo, suponga que deseamos leer lineas que pueden contener fe- cchas en cualquiera de las formas anteriores. Entonces pademos escribir while (gellinegline, sizeof{line)) > 0) { sacani(line, “Yd 0 Yad", éday, morthmame, year) = = 3) rini(*vdlido: $48\0", Lie); [> forma 28 Dio 1988 +/ rcani(line, "%ed/%d/ 4d", month, &day, &yea:) == 3) porlatl(élido; Ge\n", line); J+ forma romidadlgy +! eintl(invalido: Yie\n", line); 7+ forma iavalida +/ ur mezeladas con llamadas a otras fume Hamada a cualquier funcién de entrada iniciard lo por scant, wentos de seand y sseani deben ser ap seank{"%a", n), fen lugar de Gx); Ejercielo 7-5, Reescriba {a calculadara postfija del capitulo 4 usando scant y/ scant para hacer la entrada y la conversién, © 7.5 Acceso a archivos ‘Hasta ahora todos los ejemplos han leido de la entrada estandar y eserit la salida estindar, las cuales se definen aurométicamente para los programas ema operativo local. siguiente paso es escribir un programa que dé acceso aun archivo que et ya conectado al programa. Un programa que ilustra la necesidad de tale ‘operaciones es cat, el cual concatena en la salida estandar un conjunto de atel vyos nombrados, cat se emplea para escribi fos en la pantalla, y como uf ACCRSO A ARCHIVOS 177 -4 programas que nombre. Por ejemy id de tener acceso a los archivo: cal ne v6 jmprime el contenido de los archivos x.c y y.c (y nada mis) en la salida estandar. 19 hacer que los archivos nombrados sean leidos —esto-es, iciones que leen los datos, con los nombres externos que sreglas son simples, Antes de que pueda ser Iefdo o escrito, un archivo tient {que ser abierto por la funcidn de biblioteca fopen, Ia cual toma un nombre exter- coma x.c 0 ¥.6, hace algunos arregios y negociaciones con el sistemia operati- 1yos detalles no deben importarnos), ¥ regresa un apuntador que sera usado posteriores lectures 0 escrituras del archivo, apuntador, Hamad qpuntador de archivo, apunts una estructura que ‘ontiene informacion acerca del archivo, tal como la ubicacién de un buffer, la posicién de cardcter actual en el bi archivo est siendo Iefdo 0 escrito yy si han ocurtido errores o ‘in de archivo. Los usbarios no necesitan saber los detalles, debido a que las definiciones obtenidas de incluyen una declaraci6n de estructura llamada FILE. La dnica declarackin necesaria para un apuntador de archivo se ejemplifies por FILE ofp; FILE sfopon(char enombre, char moda); que fp es un apuntador @ un FILE, ne FILE es un nombre de “La llamada a fopen en un programa es fp = fopen(nombse, medo); ble. Abrir un atehivo existente para sean desechados, mientras que de leer un archivo que a0 e: como tratar de leer un archi et eH 178 ERTRADA,Y SALIDA, earrtuco seccion 76 MAMEIO DF ERRORES-SIDERR YEXIT 179 Wlarge == 1) /* sin args; copia Ia entsada esténdar + flecepr(ctdin, stdout); else. ‘while (~—argo:> Df Lo siguiente que se requiere es una forma de leer o escribir el archivo tna que est abierio. Existen varias posibilidades, de las cuales gete y puto s simples. gete regresa el siguiente cardcter de un archivo; necesita el ap del archivo para dei sal gote(FILE ip) gate regresa el siguiente cardeter del flujo al que se refiere fp; regresa EOF si geu. re algiin error. pute es una fu int putelint ¢, FILE sip) == NULL) ( 1 a0 puede abrir e\n", vargy): pute escribe el cardcter © en el archivo fp y regresa el cardcter escrito, 0 EOF return 0; ‘ocurre un error, Tal como getchar y putchar, gete y pute pueden ser macros en ugar de funciones. ‘Cuando se arranca un programa en C, el medio ambiente del sistema ‘vo es responsable de abrir tres archives ¥ proporcionar apuntadores de arc para ellos. Estos archivos son la entrada estandar, la salida esténdar y el cstindar; los apuntadores de archivo eorrespondientes a stderr, y estin declarados en , Normalmente stdin se conect al do y sldout y skderr se conectan @ Ia pantalla, pero stdin y stdout pueden ser rigidas a arehivos 0 a interconexiones (pipe: been la sees geichar y putchar pueden estar definidos en términos de getc, pute, y stdout, como sigue: ‘Hdsline gotchart ) goto(sta ‘A#doline putchar(e) pute , Js flecopy: copia el archive ifp al archiva ofp! vyold Hlecony(FILE «ifp, FILE +afp) 4 int ©; while ((¢ = aetotifp)) != EOF) puicte, oleh: ) Los apuntadores de archivo stdin y stdout son objetos de tipo FILE +. Sin embar- 180, son constantes, no variables, por lo que no es posible asignarles algo. ‘La funcion loae(FILE +fp) fue establecida por fopen en- indo al apuntador de archi- temas operativos tienen al- que un programa puede tener idea liberar los apuntadores de archive rumpe la conexién qi inverso de tops: jvo que especifica cl archivo que ser ahinuntadnrden segundo. argumento, argumento es un apuniador de a © escrito; la cadena de formato es argumentos, se procesa la entrada estandar. ‘include (+ cal: concalens archivos, versiéa 1 «/ maintint arge, char “argvt 1) { FILE “ips vyoid fiecopy(FILE +, FILE -); El manejo de los errores en cat no ¢8 el ideal. El problema es que si no se pule- de tener acceso a uno de los archivos por alguna raz6n, el diagnéstico se imprime 180 wvreADay SALIDA carrrutog| al final de la salida concacenada. Bso podria ser aceptable sila salida va.a la pane ero no si ya hacia un archivo o hacia otro programa medisnte una inter. ida, Hae La sal segundo flujo de stderr rormalmente aparece enla pantalla, mensajes de error en el arc! cestiindar, Finclude while (——arae > 0) UU (Up = fopen(s + +axgv, “x)) == NULL) { nose puede abrir Sa\n", fprinifetdere, " El programa seftala errores en dos ial producida por fprinté va hacia stderr, de mot EXTAADA'Y SALIDA DELINEAS 181 secc10N 77 ida desde otras funciones, y rama de busqueda de patrones como el del sell {La funcidn feof(FILE «) ¢s analoga a ferror; regresa un valor diferente de cero si hs ocurrido un fin de archivo en el archivo especificado. 0 ode error, regresa NULL. (Nuestra geiline regresa la longiiud de la nea, que es un valor mas iil; cero significa fin de archivo. Fara slid, funn fos eeibe una cadena (que no neces content una nueva linea) @ sntfputa(char slinea, FILE +fp) Esta funci6n regresa EOF si ocurre un error ¥ cero si no acurre. Las funciones de biblioteca gets y puts son semejantes a fgets y fpuis) pero eran sobre stdin y stdout, De modo desconcertante, gets elimina et {nl termi- 2al y puts lo aarega. Para mostrar que no hay nada espe copiadas de ka biblioteca es 1 sobre funciones como fgets y fputs, i de nuestro si ay gels: cbliene hasta n earacieres de iop +/ cchar sfgots(char +s, int 2, FILE viop) 192 evraapa v sation cAPHTULO rovister ite: register har *es; ‘op)) != EOF) rotum (© = = EOF 86 cs == 5) ? NULL: 6; J J+ puts: coloca Ta cadena s «8 ‘int fputs(char +s, FILE «iop) ¢ ichivo lop +/ int while (o = +344) Por razones que no son obvias, el estanclar especifica valores de retorno dif tes pare fgets y fputs. Fs facil realizar nuestro gelline @ partir de fete: resa su longitud */ Ejercicio 7-6. Escriba un programa para comparar dos archivos, imprimiendd primera linea en donde difieran, 0 Ejercicio 7-7. Modifique el programa de busqueda de un patrén del capitul Para que tome sw entrada de un conjunio de 2b brados 0, si mo archivos nombrados como argumentos, de la entrada estandar. {Dede oscrl el nombre del archivo cuando se encuentra una linea que coincide? C Ejereicio 7-8. Escriba un programa para imprimir un conjunto de archivos, clando cada nuevo archivo en unis pagina nueva, con un titulo y un contador pagina por eada archivo. © en OTRAS FLINCIONES 183 7.8 Otras funciones variedad de Tuneiones, Esta 7.8.1 Operaciones sobre cadenas Ya hemos mencionado las funciones sobre cadenas strlen, strepy, strcat, y siremp, que se encuentean en . En adelante, « y t son de tipo char, ¥ ey n son ints, concatena ta final dee concatenit n caracieres cea regres negatino, eto, 0 yeqeeetie rot invsl que stomp pero solo en los prmeras n caacieres copia ten s copia a lo mas n caracteres de 4 a's stelen(s) regresa fa longitu de atechr(s,e) fegresa un apuntadar al primer-e que eaté-en a, 0 NULL sino estd presente strxehr(s,¢) regresa un apuni limo © que esié en s, ¢ NULL sino esta presente 7.8.2 Prueba y conversién de clases de caracteres Varias funciones de realizan pruchas y conversiones de carac tes, En [o que se muestra a corttinuaciOn, © es un int que se puede represemtar como un unsigned char o FOF. Las funciones regres diferent dlferea regresa ¢ comvertida & mi mn mas restringida de la funcion lama ungete, ieca estindar propor Sngatch que eseribimos en el ca tnt ungete(int ©, FILE fp) coloca el cardcter ¢ de nuevo en el archivo fp y regresa fe garaniien poner un cay con cualquicra de junciones como scan{, getc © gotchar 7.8.4 Ejecucién de ordenes tema operative local. Como un ejemph roposiciéa system("date"); ‘a queseejecutee! programa date, el cual imprinne lt fecha y hora del ; aqui algunas de las empleadas con mas frecuencia, Cada una toma uno 0 dos argumentos double y regresa un double. seno de, xen radians soseno de x, «en radianes co tangente de x, en radianes cin exponencial e* logaritme ustural (base) de x (x= logaritmo comiin (base 10) dex (x rair cuadrada de x (x2 valor abjoluto de x 7.8.7 Generacion de nuimeros aleatorios La funcin rand( ) calcula una ia de emteros pseudoaleatorios en ef rango de cero a RAND MAX, que n . Una forms de produeir niimeros aleatorios de punto flotante mayores 0 iguales a cero pero me- noves que uno es RAND. _MAK+1)) (Si su biblioteca ya proporciona una funcion para nuimeras aleatorios de punto flotante, ¢s probable que tenga mejores propiedades estadisticas que ésta.) La funcién srand(unsigned) fije la semilla para rand. La implantacién porté- ‘il de xand y de srand sugerida por el estandar aparece en la seecidn 2.7, 10 igupper (lala allorrar espacio empo, Explore ambas pos caprtutos: La interfaz con el sistema UNIX lo esta dividido en tres partes furidamental de archivos y asignacion de alimacenamiento. Las primeras dos partes suponen una dad. com fas caracteristicas externas de los sistemas UNIX. 188 LA eerueaz DFL SISTEMA UNIX carrie puede ser necesarig. 1a los derechos de hacer re que se van a eleciar a descriptor de ari salida sin preocuparse de abrir uretivos. El usuario de un programa puede redirgi la B/S hacia y desde archivos cg =¥o? prog archsal En este caso, [Shel] cambia las asignaciones predefinidas para los deseri Oy | alos archivos nombrados. Normalmente cl descriptor de archivo 2 per ce asignade ara que los mensaes de ervor puedan ir hacia Gbservac se apican para la entrada y slide sociada con una saakenaitn deartivstavanbia Sieh 19 programa. El programa no sabe de dénde proviene su entrada ni hacia donde da, miniras seal archivo 0 para entrada y 1'y2 para sida. ; 8.2. E/S de bajo nivel—read y write La entrada y salida usa las lamadas al sistema xead y writ acceso desde programas escritos en C a través de dos funcions write, Para ambas, el primer argumento es un descriptor de archivo. argumento es un arreglo de earacreresperteneciente al programa hacia o de do fos datos van a ir o venit. Bl tercer argumento es el ulmero de bytes que $2 transferidos. Cada llamada regresa una cuenta del niimero de byt cl miimero de bytes rearesados puede ser menor que el lor de regreso de cero bytes implica fin de archivo y —I indica un error de: SECCION 82 PSDP RAIONIEL—eeAD Y wRITE 189 tipo, Para escritura, el valor de retorno es el mimero de bytes escritos: si éste no 6s gual al nero toledo scar ut ro lamada pueden leerse cualquier numero de bytes. Los valores mis co- mane son Ir que sein tn caret ala ver (n 1024.0 4098, que corresponde al tamafio de un blogue fi siferico. Los valores mayores serdn mas eficientes debido a que serdn re ‘menos Hamadas al sistema, Para juntar estos temas, podemos escribir un sencillo programa que copie su entrada a su salida, el equivalente del programa copislor de archivas escrito para ei capitulo 1, Este programa copiard cualquier cosa a cualquier cosa, ya que la entrada y la salida pueden ser redirigidas hacia cualquier archiva 0 dispositive, #includs "sysealis.h” main() { (+ copia Ia entrada a la salida +) char bu(BUFSIZ); 1 chive llamado sysealls.h, de modo que podamos incluirlo en los programas de este capitulo. Sin embargo, este nombre no ¢s estandar. El parmetro BUFSIZ tambien estd definido dentro de syscalls.b; su valor ¢s lin timano adeeuado para el sistema local. mafo del archivo no es un ri de BUFSIZ, algun read regresara un niimero menor de bytes a ser escritos la a read despues de eso regresart cero, se pueden usar read y write para consteuir sutinas de ako nivel como getchar, putchar, ete. Por ejemplo, aqui esta una versién de get- char que realiza entrada sin b yendo de la entrada estdndar un eardeter ala vez, #include “syscall.” getchar: Int getchar(void) t de un carécter simple sin butler «/ char ¢; return (read(0, &e, 1) = = 1) ? (unsigned char) © = EOF; } 190. vrenraz net sisTeNwA UNI carmmut9y © debe ser un char, a que read nevesita un apa ¢ Scr unsigned char en In proposicion de regreso el de extensién de signo. “Lasepuda ves de gocher act in entrada rand rgmentosy acy los caracteres uno a Ia vez. include “eyscalle.h” fe getchar: version con bufler simple «/ int gotchar(void) { r static char buf[BUFSIZ); ststic char vbufp = bul; static int n = 0; (a == 0){ Je ol Buller ead vecio +! a = r0ad{0, buf, sioo! bul) Iufp = bot; } return (—-a >= 0)? (unsigned cher) sbutp+ + + BOF; } Si esta version de getohar fuese a ser compilada con incluida, jinar la definicidn del nombre getchar con #undef en caso de q 8.3 Open, creat, close, unlink Ademés de la entrada, la salida y e1 error estindar, se pueden abrir explic mente archivos para leerlos © sen dos Namadas al sistema para to, open y creat.§ ‘open es como el fopen expuesto en el capttulo 7, excepto que en lugar de. seresar un apuntador de archivo, reucesa un descriptor de archive, que es tan so ln nt. open regresa —1 si ocurre algiin error. Facade it fd; int open(char «nombre, int flags, int perms); 4d = open(aombre, flags, perms); Como con fopen, el argumento nombre es una cadena de caracteres que contien€ €] nombre del archivo. El segundo argumento, flags, es un int que especifi dino send abierto el archivo; los principales valores son 4 poser de geen ig a palabra correcta es “ent, cl nombre de a farm 5 40 stone (Node) SECCION 63 OPEN, CHEAT, CLOSE, UNLINK 191. O_ADONLY abrir slo para lecture O_WRONLY abrir slo para eseritura O_RDWR abrir para leetura y eseritira Estas constantes esti definidas en en sistemas UNIX System V, y Pata abrir un archivo ya existente para lecture, fd = open{nombre, O_RDONLY, 0); El argumento perms es siempre cero para los usos de open que discutiremos, Es un error tratar de abrir un archivo que no existe. Para crear nuevos archi- ema creat. vos © reeseribir anteriores, se proporciona la llamada al int creat(char «nombre, int perms); fd = cresi(nombre, perms); segresa un descriptor de archivo. ‘archivo, que controlan cl aces a la lectura 1a para el propietatio del archivo, para el grupo del propietario y para todos los demés. Asi, un miimero octal de tres digitos es convenience para ‘especificar los permisos. Par ejemplo, 0755 especifica permisos para leer, escribir ppara cl propietario, y leer y para el grupo y para cualquier otro rarlo, aqui esté una versin simplificada del programa cp de UNIX, que copia un archivo 8 otro, Nuestra version copia slo un archivo, na permite segundo argumento sea un directorio ¢ inventa los permisos en lugar de include include include “syscalls bi" ‘Adeline PERMS 0846 /-lecturs y escriture para propisierio, grupo y otros! void error(cher +, .): fe op: copia fla int arge, char “argv 1) (arge |= error (Use: op de hacia’) 192 La nvreRPa@ EL sistEMA UNI carreg) (iL = epenargv{l], ORDONLY, 0}) = = —) erot(‘ep: no ce puede absir 36s", argvitD) (12 = erecifergr[2, PERMS)) = = —1) I able de argumentos es reemplazada por ¥ mando a la macro vastart. En soinciden con {printf y sprintf ma semejante, viprinll y vs #include #aclude J+ error: smprime ua mensaje de erzor y musre +/ void erzor(char fmt, ..) wiprintl(siderr, mt, args {printiistderr, “\n"); va_end(args); cexi(a}; un programa que: archivos debe ser preparado para ceutilizar descriptores n close(int fd) suspende la conexi6n entre un descriptor de chivo y un archivo abierto,y libera al descriptor de archivo para ser utlizado' algin otro archivo; correspond a felose de la biblioieea estandar excepto: ‘que no existe un buffer que vaciar. La terminacién de un programa via exit 0 turn desde el programa principal eierra todos los archivos abiertos. seCCION 84 ACCESG ALEATORIO—ISEEK 193 La funci6n unlink(char *nombre) remueve ¢| archivo nombre del sistema de archivos, Corresponde 4 1a funcign de ta biblioteca estindar remove, Ejercido #1. Reescribael programa vat del capitulo 7 usando read, write, open yyolose, en lugar de-sus equivalentes de la biblioteca esténdar. Haga experimentos para determinar la velocidad relativa de las dos versiones. 0 8.4 Acceso aleatorio—iseek La entrada y Ie salida son normalmente secuenciales: cada read o write ‘hiv justo después de la anterior. Sin embargo, odesde e! fin det archivo, respectivamente, Por ejemplo, para agreuar a un ar >> enel [shell] de UNIX, o “@” de fopen), hay queir Iseok(fd, OL, 2); Para regresat al principio (“'rebobinar"*), lecek(ld, OL, 595, al precio de uit acceso mas nimero de bytes en cual include “syacali h get: lee n bytes de la posicida pos +/ int get(int id, long pos, char “buf, snt 2) { if (acef(fd, poe, 0) > return read(ld, ‘on pos */ 194 LA INTURFAZ DEL SISTEMA UNIX eAPHTULO sF0C108 45 [IEMPLO-UNA IMPLEMENTACION DE.FOPEN Y.GETE 195 lee ‘Adeline stdin (obl0) return -1) Hachne.stdout (0b) } Adaline stderr (@cb{2)) El valor de regreso de Iseek: es un long que da la nueva posieién en el archivo, ea gs ( © —1 si ocurre un error. 8.5 Ejemplo—una realizacion de fopen y gete funci6n de bibliote seek, excepto en que el primer argumento es un FILE + y €l valor de resreso 65 diferente de cero si ocurrié un error. estindar iseek es semejante a “READ = 01, _/+ archivo ablerlo para lectura «/ “WRITE = 02, /« archive abierto para caoritura +/ CUNBUF = 04, /+ archive sin bulfer «/ TEOF = 010, _/+ ceurrié fim de archivo (HOF) on cate archive: +) ERR = 020 /+ oourtid un eor en este archivo «/ ® ‘nt fillbul(FILE int ushbul ILE +); archivos en la biblioteca estandar son desctitos por apum ‘#ietise lool) (((p}-> flag & FOF) = 0) lel archive: un ap en grandes fragmentos; ‘#detine NULL #doline EOF +#define BUFSIZ ‘define OPEN_MAX typed struct iobuf { ) FILE; extern FILE _iob|OPEN_MAX]; en vez de con des ‘#deline ferror(e) (p)—> flag & ERR) |= 0) wdstine Wene(e) (@->1) #éstine getolp) (——(p)—>omt >= 0 2 (unsigned char) +(p)—>ptr+ + + illbul(e)) ‘#dsfine pute(x,p) (——(p)—>emt >= 0 2 (p)—>phr+ + = (x) flushbuf((),0)) #define getchar( ) +#define putchar(*) Aunque no discutiremos ningin de para mostrar que opera en forma cy 1004 20 /+ maximo nimoro de archivos abiertos a la ver «/ i -aracteres que quedan «/ + posicién del siguiente cazdcter */ + lecalizacion del buffer +/ Js moda de accato al azchive «/ /+ descriptor de archivo */ Waclude H#iaclude "syscalls.b” ‘#deline PERMS 0666 [+ loctura’y escsitura para propielario, grupo, otros 96 La ITERFAZ DEL SISTEMA UNIX ‘+ fopen: abro wn archivo, ro¥rosa un apuatador de archive +/ FILF , lopen(char wname, char smode) { int fd; FILE ofp; it (smode I= "Y' @& emode |= 'w' && smede I= ‘2 (p—>flag & (READ j WHITH break: (ae encentr6 un: Wp >= toh + OPENMAZ) J+ nh zoturn NULL: 1d = open{name, O_RDONLY, 0); ida == —) Je nig bube acceso al nombrd «/ return NULL; fp—>te = fa; } sténdar, aungue el agregarlis no se llevaria mucho e6digo. En particular, ‘tra fopen no reconoce la “(8 que indica acceso binacio, ya que es0 no ti ficado en sistemas UNIX, ni el “(3)” que permite tanto lectura como es La primera llamada 2 gete para un archivo en particular encuentra una cuet de cero, lo que obliga a una llamada a fillbaf, Si_fillbufencuentra que el a no estd abierto para leviura, regresa EOF de inmediato, De otra forma, trata asignar un buffer (Gi la lectura seré con butfer) Una vez que el buffer ha sido establecido, filloulf llama a read para lena fija la cuenta y los apuntadores, y regresa el cardcter del principio del butler. posteriores Uamadas a fillbuf encontrarén un buffer asignado. sieci0n 4s EILNDPLO-UNS IMPLESENTACION DE HOMER YGEKE—A9T ‘include “oyvcalls-h" js Silbut: asigna y llona un bulfer de entrada +/ int fllbul(FILE fp) ' int bulsice; 38 (lp—>flaga(-READ|.SOF|_naM)) 1= READ) return EOF; bulge = (fp-—Slag & UNBUF) ? 1; BUFSI2; if p—>base == NULL) /+ sin buffer san +/ 41 ((p—>base = (char +) malloc(bulsize)) = = NULL) rohim FOF; i+ no puede obtener vn buffer */ Ip—>ple = fp~>base; fp—>ent = readth (tp pent < | fpr, bolsiee); il (Seat ) fp—>flag |= _ EOF, lee ip—>flag |= ERR, fp—>ent = 0; rolumn EOF, t return (unsigned char) +fp—>pir+ +; cabo suclto es izado para stain, jo arranear todo. El arreglo Lich debe ser defini tdout y stderr: La inteializacién de la parte flag de la estructura muestra que stdin ser4 leido, Sldout sera escrito, y slderr sera es butter Disefte y eseriba _flushiba 8-4. La funcidm de bi int eak(FILE «ip, Jong ofise ish, y folose. 0 reca astindar origen)

También podría gustarte