Documentos de Académico
Documentos de Profesional
Documentos de Cultura
El Lenguaje de Programacion C (Ansi C) 2 Ed Kernighan - Ritchie Espaol Spanish PDF
El Lenguaje de Programacion C (Ansi C) 2 Ed Kernighan - Ritchie Espaol Spanish PDF
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 sex12 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 ) 0136 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 mallizadores 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 c154 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é alma156 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; $ yt160 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) wr168 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 e170 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 eH178 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 imprime180 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 catnt 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 poscaprtutos: 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, otros96 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)