¡Te damos la bienvenida a Scribd!
Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Documentos de Pasatiempos y Manualidades
Documentos de Crecimiento personal
\n"}; Cuando una cadena de caracteres como ésta aparece en un progra sella cs a través de un apuntador a caracteres; printf recibe un apuntay del arreglo de caracteres Esto es, se tiene acceso a una cadena constante po apuntador a su primer elemento. [Las cadenas constantes no necesitan ser argumentos de funciones, Si pmessage se declara cono char “pmessage; ‘entonees la proposicién message = "ya or el tempo”; ‘signa a pmessage un apuntador al arreglo de caracteres. Esta no es la copia de luna cadena; s6lo concierse a apuntadores. El lenguaje C no proporciona ningin operador para procesar como unidad una cadena de caracteres Existe una importante diferencia entre estas definiciones: cchar amessage[ ] = "ya es el tiempo"; / arreglo «/ char spmessage = "ya os el tiempo"; /* apuntador +/ Amessage es un arreglo, suficientemente grande como para contener Ia secuencia feewrctiesy AAO a 2a Se pueden mouificarearactresindividua. '6 dno del aregl, peo amessage sempre se refer ala isn localad de ‘cenamiento. Por oto lado, pmessage es un apuntador, inicializado para ‘Dania a una eadena constante el apuntador puede modifcase posterionmente due apunte a alin otro lado, pero el resultado es indefinido si trata de mo- ificar et Poecsage: [—}—e[ ahora ov elena ] anessage: [ahora es 0IG APUNTADORES ¥ ARREGLOS ann APUNTADORES A CARACTERES Y FUNCIONES 117 lustraremos més aspects de los apuntadores los ateglos, estudiando jae ciclo. El efecto rederque lon caracteresss.co siones de dos utiles funciones adaptadas de funcién es strepy(e), que copia la cadena t a simplemente 8, pero esto copia el apun:ador, no los caracteres. Para cearacteres Se requiere de un ciclo. Primero esti la version con un arreglo. versién de eubindicas +/ “Samo restimen final, observe que una comparacién contra \O' es redundante, ‘que la pregunta es simplemente si la expresién es cero. Asi, la funcién po- ia escribirse correctamente como J+ stropy: copia t hacia old ainipyfchar va, abi + stropy: copia t hacia s; versién 3 con apuntadoros */ void strepy(char +5, char “t) { = while (*s+ + = t+ +) , la conveniencia de esta Puesto que se encontrar (0 puede parecer misterioso a primers iderable, y debe dominarse el en programas de C. feca esténdar () strepy, devuelve la cadena objetivo vin, ue examinaremos es stromp(s,{), que compara las cadenas regresa un valor negativo, cero 0 positivo sis es Iexicogratfi- igual a, o mayor que t. El valor se obtiene al restar los carac- teres de la primera posicion en que s y t no coinciden, (+ stromp: regresa 0 a1 s>t +/ int tromp(char +, char +!) Puesto que los argumentos se pasan por valor, stropy puede toss y t en la forma que le parezca mejor. Aqui hay apuntadores com mente iniiaizados, que se desplazan a lo largo del areglo un carécter a la \O' con que termina t se ha copiado a s. En la préctica, strepy no se escribiria como se mostré anteriormente. Los fan return sli] — ' J+ stropy: copia t hacia s; void strcpy(char +s, char { sién 2 con apuntadores +/ a versién con apuntadores de stremp: while (est = st4 +) I= 0) } Esto traslada el incremento de s y de t hada dentro de la parte de prucba d clo. Bl valor de *t-+ + es el cardcter al que apunta t ante118 APUNTADORES Y ARREGLOS Puesto que ++ y — son operadores prefijos o post ', Se presentan ot combinaciones de +, ++ y ——, aunque con menos frec cia. Por ejemplo, — disminuye p antes de traer el cardcter al que apunta. En efecto, la pareja de J+ meta val en la pila +/ J» saca el tope de ia pila y lo pone en val «/ son expresiones idiomiticas esténdar para meter y sacar algo de una pi Ia seccién 4.3, El header contiene declaraviones para las funciones que se en esta seccién, ademas de una variedad de otras funciones para mi de cadenas en Ia biblioteca estandar, Ejercicio 5-3. Escriba una versién con apuntadores de la funcién streat que ‘muestra en el capitulo 2: streat(s,) copia la cadena t al final de s. C rend(s,t, que regresa 1 si la cadena t se pr inal de la cadena, y cero si no « asi. © Ejercicio 5-5. Escriba versiones de las funciones de biblioteca stmomp, que operan con hasta los n primeros caracteres de sus argument ) copia hasta n caracteres de t hacia 8, Ei jones mas completas. © 56, Reescriba los pro} . empleando apuntador lo 3 se presento una funcin de ordenamiento Shell que podia’ lo de enteros, yen lo 4 se mejor6 con un quicksort 10 funcionard, excepto que akora se debe tratar con Iineas de tudes, y que, a diferencia de los enteros, no se pueden ibiar en una simple operacién. Se necesita una representacién de Aqui es donde entran los arreglos de apantadores. Si las lineas que se ¥ ordenar se almacenan juntas en un gran arreglo de earacteres, entonces s@ tener acceso a cada linea por medio de un apuntador a su primer cardcter- sBOCION 58 AKKEGLOS DE APUNTADORES; APUNTADORES A APUNTADORES 119 lado, los apuntadores se pueden almacenar en un arreglo, Dos lineas se pueden asando sus apuntadores a stremp. Cuando dos lineas desordenadas rcambian los apuntadores en el arreglo de apun- EE jina el doble problema de un manejo complicado de almacenamiento y roduciria al mover ne tFes pasos: proceso de ordenzmiento lee todas las lineas de entrada ‘ordénalas Jimprimelas en ordea apuntadores hi irada, puesto que esa informacién se req i. Debido a que la funcidn de entrada s6l cas, puede regresar alguna cuenta de ne que imprimir las lineas en el orden en que apare- arreglo de apuntadores. #include include ‘#define MAXLINES 5000 J+ max # de lineas por ordenar */ char ‘lineptr[MAXLINES]; _/* apuntadores a neas de texto */ ft ceadlines(char «linepte| old writelines(cha: “linept Void qeort(char “lineptl |, int let, int right); ‘+ ordona lineae de entrada +/ main) (120 APUNTADORES ¥ ARREGLOS worn ARREGLOS DE APUNTADORES; APUNTADORES A APUNTADORES 121 secc1ON 56 int lines; J+ mimero de ineas de entrada leidas «/ que indica que lineptr es un atteglo de MAXLINES elementos, cada uno de los ss un apuntador a char. Esto es, lineptr[i] es un api cs el cardcter al que apunta, el primer cardcter de readlinex(tinoptr, MAXLINES)) > = 0) { -D; wnitelines(lizeptr, tam 0; ombre de como un apuntador en la misma forma que en nuestros ejemplos anteriores (rrtelines puede escribirse en su lugar como or: entrada demasiado grande para ordenara\n") 1 waltelines: ei void wrtelinoe(c i while (alines— > 0) ‘deline MAXLEN 1000 + méx longitud de cua printl(%s\n", sineptr+ +); int geiline(char +, ini}; } Inicialmente *lineptr apunta a la primera linea; cada incremento lo avanza al si- (+ readlines: lee lineas de entrada +/ {int readlines(char slinepts{ |, int mazlines) ( ‘int Ion, lines; ‘char *p, line[MAXLEN]; jones deben modificarse, y la operacién de comparacién debe hacerse ‘a stromp. El algoritmo permanece igual, lo que nos da cierta confianza de que ain trabajard. len—l] = \0'; /+ elimina earécter nueva linea +/ strepy(, lin + no hace nada si el arreglo contiene */ ‘menos de doe elementos =/ ft + sight)/2); sswap(y, left, as) cgeor(y, left, last); gone, last +1, right) for () = 0; < mlines; i+ rinti("%e\n", linep ' La funcién getline se traté en la seccién 1.9, EI principal nuevo elemento es la declaracién para lineptr: cchar slineptr[MAXLINES] ina de i Poco sig + swap: inlercambia vii] y vil +/ void swap(char +], {122 APUNTADORES ¥ ARREGLOS carrtut spCcION 527 AARREGLOS MULTIDIMENSIONALES 123 leap = your¥s4 == 0 Gite yoas%6100 != 0 year%6400 = = 0; for (1 = 1;4 < month; 14 +) day += daytab[leap]til; return day; ano +/ 5 y dia a partir de dia Puesto que cual void month daylint year, int yearday, int *pmonth, int «pday cardcter, temp lemento individual de v (alias lineptr) es un apuntador debe serlo, de medo que uno pueda copiarse al otro, Ejercicio §-7. Reescriba readlines para almacenar lineas en un arreglo pr cionado por main, en lugar de llamar a alloc para obtener espacio de almac leap = yoar%d == 0 &6 year%100 != 0 ! year%400 = = 0; miento. {Cudnto més rapido es el programa? 0 ee a for (1 = 1; yoarday > yearday —= dayta spmonth = 3 spday = yearday; 5.7 Arreglos multidimensionale: EI lenguaje C proporciona arreglos muitidimensionales rectangulares, cen la préctica se usan menos que los arreglos de apuntadores. En esta s ‘mostraremos algunas de sus propiedades. Considérese el problema de la conversion de fechas, de dia del mes a dia ao y viceversa. Por ejemplo, el 1 de mazo es el 60° dia de un ano que no bisiesto, y el 61° dia de uno que silo es. Definamos dos funciones para hacer month_day, para que conversion: day_of_year convierte mes y dia en el dia del ano, convierte el dia del afio en mes y dia, Puesto que esta valores, 1os argumentos de mes y dia deben ser apuntadores: month day(1988, 60, &m, &d) hhace m igual a 2 yd igual a 2 ‘Ambas funciones dias de cada mes ( por mes difiere para ¥ Bo bsiestos, es mas facil separarlos en renglones de un arreglo ional quessiga la pista de lo q durante los célculos. El arreglo y las funciones que real son como se muestra a continuacién: static char daytab(2] (13] = { (0, 31, 28, 31, 30, 31, 20, 31, 31. 30, 31, 30, (0, 31, 29, 31, 30, 31, 30, 31, 31. 30, 31, 20, 31}, daytab es el primerarreglo de caracteres de dos dimensiones con el que hemos tratado. En C, un arrezlo de dos dimensiones es en realidad un arreglo unidimen- sional, cada uno de cuyos elementos es un arreglo, Por ello, los subindices se es- ciben como daytab| ‘+ [ronglén} {columaa] +/ cn lugar de ‘+ day-ol_year: obtiene dia del ato a partir de mes y atlo «/ int day-ot_year(int year, int month, iat day) 4 pasa a una funci el numero de columnas declaracién de pa- inti, leap; imiimero de renglo-APUNTADORES VS. ARREGLOS MULTIDIMENSIONALES 125 124 APUNTADORES ¥ ARREGLOS caprTuto seCCION 58 hi totum (n <1 {n> 12)? namo(0] ; name[n]; , La declaracién de name, que es un ar rma que [a de lneptr en el ejemplo del de cadenas de caracteres; cada una Los caractetes dk nes es itrelevante, puesto que lo que se pasaes, como antes, un apuntador @ arreglo de renglones, donde cada rengln es un arreglo de 13 ints. Es este particular, es un apuntador a objetos que son arreglos de 13 ints. Entonces, el arreplo daytab se pasara a la funcién f, a declaracién de f seria Sint daytab ‘También podria ser © podria ser | niimero corr que indica que el pardmetro es un apuntador a un arreglo de 13 enteros. Los rémesis son necesarios, puesto que los corchetes [tienen mas alta preced 5.9 Apuntadores vs. arreglos multidimensionales 1s nuevos usuarios de C algunas veces se confunden con la le dos dimersiones y uno de apuntadores, como name en el ejemplo rncia entre int +daylab (13) es un arreglo de 13 apuntadores a entero. De modo mas general, dimensién (subindice) de un arreglo queda abierta; todas las ot En la seccién 5.12 se discute mas acerca de declaraciones complicadas, i "4 entonces tanto afi ] son referencias sintdcticamente legitimas a co int, Per snte un arreglo de dos dimensiones: se le han asignado 200 localidades de tamafio de un int, y se emplea el célculo convencional de subindices rectangulares 20% renglén-+columna para encontrar elemento alrengl6n,columna]. Para b, sin embargo, la definicién s6lo asigna 10 apuntado- res y no los icializacién debe realizarse en forma expli stéticamente con cédigo. Suponiendo que cada elemento de b ap arreglo de veinte elemestos, entonces existiran 200 ints reservados, mas diez cel- das para los apuntadores. La ventaja importante del arreglo de apuntadores es pueden ser de longitudes diferentes. Esto es, m0 ¢s rcicio 5-8. No © Solucione ese defect fe deteccién de errores en day-of_year ni en mont o izacién de arreglos de apuntadores rese el problema de escribir una funcién month_name(n), que lor a una cadena de caracteres que contengan el nombre del n: ‘a es una aplicacién ideal para un arreglo static interno, mont contiene un arreglo reservado de cadenas de caracteres, y regresa un apunt a la cadena apropiada cuando se llama, Este seccién muestra como se inici ese arreglo de nombres, La fo a ningun. (05, el uso mas fre- s de anuntadores es para almacenar cadenas de cari como en la funcién month_name. Compare la declaracion J+ month name: regresa el nombre dei n-ésimo met +! ‘char *month name(int 2)126 APUNTADORES Y ARREGLOS con la de un arreglo bidimensional: b’, cchar aname| ] [15] = { "Mes ilegal", "Ene", “Feb”, “Mar” } 8 0 8 0 Ejercicio 5-9. Reescriba las rutinas day_ol_year y month_day empleando aj tadores en lugar de indices. 5.10 Argumentos en Ia linea de érdenes Dentro de un medio ambiente que maneje C hay una forma de pasar mentos en la linea de ordenes o de parimetros a un programa cuando empi ejecucion. Cuando se llama a main se le invaca con dos argumentos. El pri (llamado por conveneién arge, por argument count) sel niumero de argumei en la linea de ordenes con los que se invocé el programa; el segundo (argv, por gument vector) es un apuntador a un arreglo de cadenas de caracteres que et ne los argumentos, uno por cadena. Se acostumbra utilizar niveles mult \dores para manipular esas cadenas de caracteres. sjemplo mas set rograma echo, que desplicga sus argu inea de Ordenes en una linea, separsdos por blancos. Esto es, la of ‘echo hola, mundo imprime hola, mundo Por convencidn, argv(0] es el nombre con ef que se invocd el programa, que argc es por lo menos 1. Si argc es 1, entonce no hay argumentos en la después del nombre del programa. En el ejemplo anterior, arge es 3, y a1 “hola” y “mando”, respectivamente. El prit ‘gumento optativo es argv} y el altimo es argv[arge—1]; ademas, el quiere que argvlarge] sea un apuntador nulo. argy: -Lechon ] seC10N 5.10 ARGUMENTOS EN LA LINEA DE COMANDOS 127 La primera version de echo trata a argv como un arreglo de apuntadores a ca #include 1+ eco de los argumentos de la linea de érdenes; 1a. versién +/ ‘main(int argc, char ¢argv! J) ( } Como argv es un apunador a un arreglo de apuntadores, se pueden manipular ‘al apuntador en lugar ce indexar al arreglo. Esta siguiente variacién se basa en IF argv, que ¢s un apuntador a un apuntador a char, en tanto se dis fe los argumentos de la linea de érdenes; 2a. versién +) age, cher "ar uesto que argy es un apuntadar al inicio del arreglo de cadenas de argumentos, incrementarlo en 1 (+ +argu) lo hace apuntar hacia argv(1] en lugar de apuntar 4 argv(0]. Cada incremento sucesivo lo mueve al siguiente argumento; entonces “argv es el apuntador aese argumento. Al mismo tiempo, arge disminuye; cuan- 4o lesa a cero, no quedan argumentos por imprimir. En forma alternativa, podemos escribir la proposicién printf como print{(arge > 1)? "Ya": "9%", ++ + arev); Eso demuestra que el argumento de formato del printf también puede ser una presion Como un segundo ejemplo, hagamos algunas me; 28"4.1 que encuentra un patron. Si se recuerda, potundo del progra Farts la guia del BY €l patron que se debe encontrar se especifique por el primer areumento en la Mea de drdenes. yrograma de la sec nde busqueda en128 APUNTADORES ¥ ARREGLOS carn #include include ‘#define MAXLINE 1000 {int gotlino(char line, int max); J+ find: smprime lineas que coinciden con el patrén del Jer. argumento main(int argc, char *arav{ }) c cchar line[MARLINE]; int found = 0; i (arge I= 2) printi("Uso: find patrén\n"); alse while (getline(line, MAXLINE) > 0) Mf (steteline, aray{l] != NULL) { printf("%s", line); found+ +; return found } La funcién strstr(s,t) de la biblioteca esténda: regresa un apuntador a la pri cocurrencia de la cadena t dentro de la cadena s, 0 NULL si no exis sda linea impresa con su nimero de linea ‘Una convencién comiin para programas en C en sistemas UNIX es que un (*nimero") para solicitar la numeracién de lineas, entonces la orden find —x -n patrén cada linea que no coincida con el patrén, precedida por su numero’ Los argumentos para opciones deben ser permitidos en cualquier orden resto del programa debe ser independiente de! nimero de argumentos que ran presentes. Ademés, es conveniente para los usuarios que los argument las opciones puedan combinarse, como en find ~ax patron Aqui esta el programa: sgcc108 5.10 ARGUMENTOS EN LA LINEA DE COMANDOS 129 #include include ‘#doline MAXLINE 1000 (char ‘line, int max); Js find: imprime lineas que coinciden con el patrén del Ler. argumento +/ ‘main(int arge, char argv! J) 4 char line[MAXLINE); Jong lineno = 0; int ©, except = 0, number = 0, found = 0; while (—arge > 0 &é (++ +argv)[0] = = 9 while (¢ = ++ +aravi0)) umber = 1; break; defeat printi(“ind: opcién ilegal %c\n", ¢); arge = 0; found = ~2; Dreak; ‘while (gelline(line, MAXLINE) > 0) { linexo+ +; if ((tratx(line, vargv) |= NULL) != oxcopt) { f (oumber) return found; ) 1a S965 di ¥y argy se incrementa antes de cada argumento opcional. inal del ci 10 hay errores, argc dice cudntos argumentos permanecen,130 APUNTADORES ¥ ARREGLOS caPrTULo sin procesar y argy apunta al primero de éstos. Asi, arge debe ser Ly +argy det + +argv)[O} cs su primer cara En efecto, esto es lo que empleamos en el ciclo mAs interno, donde la tarea proceder a lo largo de una cadena especifice de argumentos. En el ciclo mas expresion *+ +argv{0] incrementa el apuntador argvi0] Es raro que se empleen expresiones con apuntadores més complicadas que tas; en tal caso, seré més intutivo separarlas en dos 0 tres pasos. Ejercicio 5-10. Escriba el programa expr, que evalia una expresién polaca im st a de ordenes, donde cada operador w operando es un argumento p separado. Por ejemplo, opr 234 + se evahia como 2 x G+4). 0 rcicio 5-11. Modifique el programa entab y detab (escritos como ejercicios de puntos de tabulacién como argu: los tabuladores habituales si no hay argumentos. © Ejercicio $-12, Extienda entab y detab de modo que acepten la abreviatura ‘entab-m + que indica puntos d in cada m columnas, i en la columna m. leccione el comportamiento por omisién més conveniente (para el usuario). Ejercicio 5-13. Escriba el programa tail, qu¢ imprime las ultimas n lineas entrada. Por omisién, 1s 10, digamos, pero puede madificarse con un argu {0 optativo, de modo que tal-n imprime las tiltimas 1 lineas. El programa debe comportarse en forma raci sin importar cuan poco razonable sea la entrada o el valor de n. Escriba el pr ma de manera que haga el mejor uso de la memoria disponible; las almacenarse como en el programa de ordenamiento de la seccién 5.6, no arreglo de dos dimensiones de tamaiio fijo. 5.11 Apuntadores a funciones En C, una funcién por si sola no es una variable, pero es posible definit tadores a funciones, que pueden asignarse, ser solocados en arreglos, pasados SECCION 5.11 modo que sise da el argum: APUNTADORES A FUNCIONES 131 snéricamente en lugar de lexicograti La comparacién lexicogrifica de do ‘es; también requeriremos de una ruti as y regrese la jones se declaran antes 1e los objetosesten en orden. las operaciones de comparaci ineas es realizada por stremp, como an- jumemp que compare el valor numérico .cidn que hace stremp. Bstas fun- de los errores en los argu: jos elementos principales. clude ‘#deline MAXLINES 5000 cchar +lineptr/MAXLINES); int readlines(char “linept void wrtelines(char slineptr| void qsort(void slineptr| J Js max # de liness 2 ordenar +/ 1+ apuntadores a lineas de texto */ int (comp) (void +, Int numemp(char *, char *); /» ordena linear de entrada +/ main(int argc, char ‘argv{ 1) { 1+ mximero de lineas de entrada leidas +/ J+ 1.81 08 ordenamionto numérico +/ int alines; int numeric = 0; (arge > 1 & stremplargy(l], "-n") = = 0) MAXLINES)) >= 0) { el (numeric ? numemp : stromp));132 APUNTADORES ¥ ARREGLOS ‘carro rada demasiado grande para ser ordenada\n"); En la llamada a qsort, stromp y numemp son direcciones de funciones. Ci se sabe que son funciones, el operador & no es necesario, en la misma forma tno es necesario antes del nombre de un arreglo. Hemos escrito qsort de modo que pueda procesar cualquier tipo de dato, slo cadenas de caracteres. Como se indice por la funcién prototipo, qsort es un arreglo de apuntadores, dos enteros y una funcién con dos argumentos de ti apuntador. Para los argumentos apuntadores se emplea el tipo de apuntador rico void +. Cualquier apuntador puede ser forzado a ser void * y resresa de nuevo sin pérdida de informacion, de modo que podemos llamar a qsort fe zando los argumentos a voids. Fl elaborado cast del argumento de la Fanci fuerza los argumentos de la funcion de comparacion. Esto generalmente tendra efecto sobre la representacion real, pero asegura al compilador que t if (left >= right) /+no hace nada si el arreglo contiene */ Las declaraciones deben estudiarse con cuidado, Eleuarto pardimetro de qsort int (comp) (void +, void +) Que indica que comp es un apuntador a una funcién qu; void * y regresa un El uso de comp SeCCION 5.1 APUNTADORES A FUNCIONES 133 te con la declaracion: comp es un apuntador a una funcién, *comp es is son necesarios para que los componentes sean correctamente asociados; sin ellos, int scomp(void +, void +) f+ INCORRECTO «/ indica que comp es una funcién que regresa un apuntador a int, lo cual es muy diferente. ‘Ya hemos mostrade stremp, que c ‘que compara dos cadenas numericamente, valor que include (> numemp: compara sl y 62 numéricamente */ int umemp(char *s1, char +52) { La funcién swap, que intercambia dos apuntadores, es idéntica a la que pre- Sentamos anteriormente en este capitulo, excepto en que las declaraciones se han cambiado a void +. ‘oid swap(void 4 Sint 5, int) } Puede agregarse una variedad dé lgunas se convierten en ejercicios opciones al programa de ordenamien- teresantes. Ejercicio 5-14. Modificue el programa de ordenamiento de modo que maneje na bandera x, que iadica ordenar en orden inverso (descendente). Asegurese que —x, trabaja con =n. 3134 APUNTADORES ¥ ARREGLOS carrrul las letras maysculas y miniis las durante el ordenamiento; Ejercicio 5-15. Agregue la opcién ~f para ign Jas, de modo que no se haga distincién ent ejemplo, al comparar, ay A son iguales. © jercicio 5-16. Agregue la opcién ~d (“orden de directorio”), que compara s was, nuimeros y blancos. Aseguirese de que trabaja en conjuncién conf. 0 jercicio 5-17. Agregue capacidad de manejo de campos, para que el order (0 se haga sobre campos de las lineas, caca campo ordenado de acuerdo con 10 independiente de opciones. (EI indice de este libro fue ordenado, las entradas y —n para los mimeres de pagina.) O 5.12 Declaraciones complicadas Al lenguaje C se le reprucba algunas veces por la sit icularmente las que involucran apuntadores a ful de haver que coincidan las declaraciones con » pero puede ser confusa para los dificiles, del sno pueden leerse de izquierda a derecha, y debido al exceso de uso de sis. La diferencia entre ‘+ f funcién que regresa un apuntador a int «/ int (ep ilustra el problema: « es un operador prefijoy tiene menor precedencia que ( ‘modo que los paréntesis son necesarios para obligar a una asociacién apropi ‘Aunque en la préctica es extrafio que aparezcan declaraciones verdad ¢ sadas, es importante saber como entenderlas y, si es nevesario, . Una buena forma de sintetizar decaraciones es en pequefios pasos , que se discute en la seccién 6.7. Como una alten presentaremos un par de programas que cenvierten de C valido a una dé cin verbal y viceversa, La descripcién verbal se lee de izquierda a derecha. La primera, del, es la més compleja. Cenvierte una declaracién de C en descripcién hecha con palabras, como en egos ejemplos: ‘(+ pf: apuntador a una funcién que regresa un int «/ chen sarge apuntador 4 unapuntador # char fuacién que regress apurtador a void srcciON 3.12 DECLARACIONES COMPLICADAS 135 comp: apuniador a una funcién que regresa void har (x 010. x: funcién cue regresa un apuniador a un arzeglol | de ‘apuntadores auna funciéa que regresa char char (+(x) x: arreglo[ de apuntadores a wna funcion que regresa ‘up apuntador a un arregio[8] de char del esti basada en la gramatica que especi en forma precisa en el apéndice A, seccién 8.5; ésta es una forma simplificada: considere este declarador: dt \ ] et | det-ir | detdir act ca un declarador, at puede emplearse para reconocer declaraciones, Por ejemplo, define136 APUNTADORES ¥ ARREGLOS ca El coraz6n del programa del es un par de funciones, del y dirdcl, que bben una declaracién de acuerdo con esta gramética. Debido a que la grami llaman recursivamente una a sel programa se conoce eonocen piezas de una ictico por descenso rei J+ del: reconoce una declaracién void del{veid) int ns; for (ns = 0; gettoken( ) /* euenia +6 */ dirdel( while (as strcaifout, “apuntador a); } J+ dirdel: reconoce un declarador directo */ ‘void dirdel(void) { int type; iM (lokentype == "(){ —fs (ech) +f while ((ype=gettoken( )) == PARENS | type = = BRACKETS) ‘modo que las declaraciones invalidas tambi dejan come ejetccios, ‘cupera mucho ante los lo confunden, Esas secC10N 5.12 DECLARACIONES COMPLICADAS 137 ‘Aqui estén las variables globales y la rutina principal: waclude #include #include ‘#deline MAXTOKEN 100 ‘enum { NAME, PARENS, BRACKETS }; {nt gettoken(void) int tokentypo; char token|MAXTOKEN]; cchar name[MAXTOKEN]; cchar datatype[MAXTOKEN]; nombre del identiicador + tipe de dato = char, int, while ((c = geteh()) == He == 40DECLARACIONES COMPLICADAS 139 138 APUNTADORES v ARREGLOS caprruto gf seccion $12 zotum tokentype = PARENS; } else { ungeteh(c); return tokentype = ‘( } else (6 == ‘19 for (p++ = ci (p++ = geteh( )) “p= "0; ‘P+ + = c;lsalnum(e = getch( ));) jo 5-20. Extiende del para que maneje declaraciones con tipos de argu- de funciones, ealificadores como const, etcétera, C se discutieron en el capitulo 4. en la direccién inversa, especialmente si no nos preocu Por la generacién de paréntesis redundantes. El programa undel convierte Aescripcién verbal como "x es una funcién que regresa un apuntador a un de apuntadores a funciones que regresan char”, que se expresaré como {La sintaxis abreviada de la entrada nos permite reutilizar ala funcién gettoken. Funcién undel también emplea las mismas variables externas que dol. /* undel: convierle una descripcién vetbal a declaracién «/ main( ) { int type; char temp(MAXTOKEN}; =n) ype = = BRACKETS)carituLoé: Estructuras Una estructura es una coleccién de una 0 mas variables, de tipos posiblemente diferentes, agrupadas bajo un solo nombre para manejo convenient fructuras se conocen como “records” en algunos otros lenguajes, p Pascal.) Las estructuras ayudan a organizar datos complicados, en particular dentro de programas grandes, debido a que permiten que a un grupo de relacionadas se les trate como una unidad en lugar de como entidades separadas. ‘Unejemplo tradicional de estructura es el registro de una némina: un emplea- do estd descrito por un conjunto de atributos, como nombre, domicilio, numero del seguro social, salario, etc. Algunos de estos atributos pueden, a su vez, ser estructuras: un nombre tiene varios componentes, como los tiene un domicilio y aiin un salario. Otro ejemplo, mas tipico para C, procede de las graticas: un pun- to es un par de coo-denadas, un rectangulo es un par de puntos, y otros casos semejantes. EI principal cambio realizado por el estiindar ANSI es la definicién de la asig- nacign de estructuras —las estructuras se pueden copiar y asignar, pasar a funcio- nes y ser regresadas por funciones. Esto ha sido manejado por muchos compiladores durante varios afios, pero las propiedades estin ahora definidas en forma precisa. Las estructuras y lot arreglas automaticos ahora también se pueden inicializar. 6.1 Conceptos basicos sobre estructuras Definamos alguras estructuras propias para graficacién. El objeto basico es ‘un punto, del cual supondremos que tiene una coordenada x y una coordenada 3 ambas enteras,142 esrRUCTURAS on Los dos componentes pueden ser colocados en una estructura declarada asi: struct point ( int x; int ¥: k La palabra reservada struct presenta la declaracion de una estructura, que ces una lista de declaraciones entre llaves. Ln nombre optativo, llamado rétulo estructura, puede seguir a la palabra struct (como aqui lo hace poi da nombre a esta clase de ble ordinaria (esto es, no miemt pueden tener el mismo nombre sin conflicto, puesto que siempre se pueden dist ir por el contexto. Ademas, en diferentesestructuras pueden encontrarse los ‘mos nombres de miembros, aunque por ciestiones de estilo se deberian de los mismos nombres s6lo para objetos esirechamente relacionados. Una declaracién struct define un tipo. La llave derecha que termina Ia ls de miembros puede ser seguida por una lista de variables, como se hace para c quier tipo basico. Esto es, struct ve es sintdcticamente andlogo a int x,y, cn el sentido de que cada props Una declaracién de serva espacio de almacenamiento sino que si ola forma de una mbargo. lo se puede emplear post ra. Por ejemplo, dada la declaracién arterior de point, struct point pt; define una variable pt que es una estructura de tipo struct point. Una estruct se puede inicializar al seguir su definicién con una tuno una expresin constante, para los miembros: struct point maxpt = { 320, 200 }; Una estructura automatica también se puede inicializar por asignacién o Ia do a una funcién que regresa una estructura del tipo adecuado. Se hace referencia a un miembro de una estructura en particular en una €¥ presién con una construccién de la forme nombre-estructura.miembro SPCCION 62 [ESTRUCTURAS Y FUNCIONES 143 El operador miembro de estructura “.” conecta al nombre de la estructura con el nombre del miembro. Por ejemplo, para imprimir las coordenadas del pun- 0 rinti('%d,%d", pt.x, pt para calcular la cistancia del origen double dist, syt(double); apt, dist = sqet((double)pt.x + ptx + (double y+ pty) Las ras pueden anidarse. Una representacion de un rectangulo es co- ‘mo un par de puntos que denotan las esquinas diagonalmente opuestas: » or Pal struct rect { struct point ptl; struct point pt2; h La estructura 1 Si declaramos screen como contiene dos estructuras poi struct rect scteen; entonces sereen.ptlx se refiere a la coordenada x del miembro prl de screen. 6.2 Estructuras y funciones ura son copiarla 0 asignarla in con &, y tener acceso a sus miembros. La copia la asignacién incltyen pasarlas como argumentos a funciones y también regre- valores de funciones. Las estructuras no se pueden comparar. Una estructura se puede ini144 estRucTURAS carrito Investiguemos las estructuras escribiendo algunas funciones para maniput puntos y rectingulos. Hay por lo menos tres acercamientos posibles: pasar radamente los componentes, pasar una estructura completa o pasar un apuni a ella, Cada uno tiene sus puntos buenos ¥ malos. La primera funcion, makepoint, toma dos enteros y regresa una estructung point: J+ makepoint: crea un punto con las componentes x, ¥ */ struct point makepoint(int x, it y) f struct point temp; tomp.x = x tempy = yi return temp; ' Nétese que no hay conflicto entre el nombr: del argumento y el mi ‘mismo nombre; incluso la reutilizacién de los nombres refuerza el ‘makepoint ahora se puede usar para inicializar dindmicamente cualquier tructura, o para proporcionar los argumentos de la estructura a una funci struct point makepoin! screen.ptl = makepoint(0, ptl.y + soreen.p2.9)/2), EI siguiente paso es un conjunto de funciones para hacer operaciones arit ticas sobre los puntos. Por ejemplo, Js addpoint: uma dos puntos */ nto 10s argumentos como el valor de retorno son estructuras. Incr famos los componentes en pl en lugar de utilizar explicitamente una variable t poral para hacer énfasis en que los pardmetros de la estructura son pasados valor como cualesquiera otros. sECCION 62 [ESTRUCTURAS Y FUNCIONES 145 ‘Como otro ejemplo, la funcién ptinrect prueba si un punto esti dentro de un sectdngulo, donde hemos adoptado la convencién de que un rectangulo incluye fs lados igquierdo ¢ inferior pero no sus lados superior y derecho: ptinroct: regreta 1 si p esté en r, 0 sino lo ests «/ plinrect(atruct point p, struct rect 2) return px >= rptlx 6& px < rpldx 88 py >= epi y GG py < rpi2y; } Eso supone que el ecténgulo estérepresentado en una forma esténdar en donde Jas coordenadas ptl son menores que las coordenadas pi2. La siguiente Funcion regresa un recténgulo, garantizando que esté en forma candnica: / canontect: pone en Jorma candnica las coordenadas de un rectingulo */ struct rect cancareci(struct rect) { struct rect ‘emp; lemp.pi2.y = max(rptl.y, rp return temp; , Si una estructura grande va a ser pasada a una funcion, generalmente es mas a estruct son como los apuntadores a variables ordinarias. La declaracion struct point *ppi dice que pp es un apuntador a una estructura de tipo struct point. Si pp apunta 4 una estructura point, “pp es la estructura, y (+pp).x y (*pp)-y son los miem- bros, Para emplear pp, se podria escribir, por ejemplo, struct point origin, «pp: Los paréntesis son necesarios en (*pp).x debido a que la precedencia del opera- dor miembro de estructura . es mayor que la de +. La expresién «pp.x significa “(ep.x), lo cual es ilegal debido a que x no es un apuntador.146 estRuctuRAS caprruto Los apuntadores a estructuras se usan cor frecuencia que se ha prc cionado una notacién alternativa como aoreviacidn. Si p es un apuntador a tructura, entonces p> miembro de estructura se refiere al miembro en particular. (El operador -> es un signo menos segui inmediatamente por >.) De esta manera podriamos haber escrito printi("el origon es (%éd, %d)\n", pp->x, pp->y); Tanto . como —> se asocian de izquietda a derecha, de modo que si tent struct rect 1, ¢xp = 7: centonces estas cuatro expresiones son equivalentes: Los operadores de estructuras . y ->, junto con ( ) para llamadas a funci para subindices, estan hasta arriba de la jerarquia de precedencias y se Los paréntesis se pueden emplear para alterar ‘+p)->len incrementa a p innecesario.) ier cosa a la que str apunl tecomo *8+ +); (*p- “p+ +->str incrementa a p después de hacer el acceso a lo que str apunta. 6.3. Arreglos de estructuras (Considérese escribir un programa para contar las ocurrencias de cada pal reservada de C. Se requiere de un arreglo de cadenas de caracteres para manté seCCION 63 ARREGLOS DE ESTRUCTURAS 147 tos nombres, y un arreglo de enteros para las cuentas. Una posibilidad es usar 's arreglos paralelos, keyword y keyconunt, como en ero el hecho de quelos arreglos sean paralelos sugiere una organizacién diferen- te, un arreglo de estructuras. Cada entrada de una palabra es una pareja: char *word; int count; y hay un arreglo de parejas. La declaracién de estructura struct key { cchar *word; int coun! ) keytab[NKEYS| declara un tipo de estructura key, define un arreglo keytab de estructuras de ese tipo, y reserva espacio de almacenamiento para ellas. Cada elemento del arre- alo es una estructura. Esto también se podria escribir como struct key { char *word; int count ki struct key keyiabINKEYS]; cidn es seguida por ana lista de inicializadores entre llaves: struct key { char word; int count; ) keytabl } = |148 EsTRUCTURAS SECCION 631 ARREGLOS DE ESTRUCTURAS 149 rotor 0; bbinsearch: encuentra wna palabra Binsearch(char *word, struct ke 14s preciso encerrar los ii © estructura entre llaves, como en int cond; int low, hich, mid; pero simples 0 cadenas de caracteres, y cuando todos das en el arreglo keytab se calculard 1 se deja vacto. ‘else if (cond > 0) low = mid + 1; else setura mid ' return ~1; ) #include #inclade ‘#include Mostraremos la funcién getword en un momento; por ahora es suficiente decir que cada llamada a getword encuentra una palabra, que se copia dentro del arre- alo referido como su primer argumento, La cantidad NKEYS es el nimero de palabras en keytab, Aunque las 10 mas Facil y seguro que lo haga la ma- fa a cambios. Una pos izedores con un apuntador nulo y luego re0 de keytab hasia que se encuentra el fin. ‘#dcline MAXWORD 100 int getword(char ‘mero de entradas es size of keytab / sze of struct key C proporciona un ope! S€ puede emplear para c siaeof objeto sizeof (nombre de tipo)150° esrRUCTURAS cart SECCION 6 APUNTADORES 0 ESTRUCTURAS 181 dan un entero igual al tamaiio en bytes de mente, sizeof produce un valor entero sit signo cuyo ne] header .) Un objeto puede ser una vari ipo basico como int 0 de © un apuntador. : aito del arreglo dividido liza en una proposicién #¢ gotword fecoleccion de un cardcter adelamt La llamada a ungetch regresa el cardcter a la entrada para la getword también usa isspace cl tamafo de un elemento. Este cal para fijar el valor de NKEYS: #deline. NKEYS (sizeof keytab / of(struct key) ersion de getword tra forma de escribir esto es dividir el tamafio del arreglo entre el tama jemtarios 0 fi un elemento especifico: ‘#deline NKEYS (cizoo! keylab / sizeof keytab[0]) ventaja de que no neces izeof no se puede utilizar en una linea #if, debido a que el prepr no analiza nombres di ‘0 la expresion del #define no es evaluada el preprocesador, y aqui el cédigo ‘Ahora la funcién getword. Hemos esc neral de obtiene ‘palabra’? de dena de letras y digitos que principia con una espacio en blanco. El valor de la funcién es el primer caracter de la palat EOF para fin de archivo, 0 el cardcter e1 si mismo cuando no es alfabét J+ gotword: obtiene la siguiente palabra o cardctor de la entrada */ int getword(char *word, { 6.4 Apuntadores a estructuras ar algunas de las consideraciones involucradas con apuntadores y le nuevo el programa de conteo de palabras Ladeclaraci 1a de keytab no requiere de cambios, pero main y binsearch si necesitan modificasiones. include #include ‘include +#dofine MAXWORD 100 int gotword(char «, int); struct key ebinsearch(char «, struct key int c, gatoh(roid); void uagetch( char w = word; J cuenta palakcas reservadas de C; versién con apuntadores «/ main( ) { char wordMAXWORD]; struct key *p; while (isspace(c = getch( ))) while (getword(word, MAXWORD) != EOF) caipha( word il (p=binsearch(word, keytab, NKEYS)) != NULL) p>eount + +; for (p = keytab; p < keytab + NKEYS; p+ +) if (p—>count > 0) 4d s/n", p->count, p~>word); j lim > 0; w+ +) isalnum(+w = goteh( )) { ‘ungetch(+w); break; return 0;‘encuentra una palabra en tab| key *binsearch(char *word, struct key +tab, struct key shigh = étl requiere de cambios significaiivos en binsearch. izadores para low y high son ahora apuntadores al inicio y j El cdlculo del elemento itermedio ya no puede ser simplemente mid = (low+high) /2 Puesto que la suma de dos apuntadores es iegal. Sin embargo, la resta es ma, por lo que high-low es el ntimero de elementos, y asi hhace que mid apunte al elemento que est a la mitad entre low y high. El cambio mas importante es ajustar el algoritmo para estar seguros de al o intenta hacer acceso a un elemento fuera del slo. El problema es que &tab[—I] y &tab[n’ estan ambas fuera de los limites arreglo tab. La primera es estrictamente ilegal, y icin det lenguaje garantiza que la aritmética de apunt hho genera un apuntador i zal desreferenciar la seat seCCION 63 [ESTRUCTURAS AUTORREFERENCIADAS 183 es que involucra el primer elemento después del fin de un arreslo (esto es, Gtabla} trabajara correctamente, ‘En main escribimos for (p = keytab; > < keylab + NKEYS; p+ +) i p ¢5 un apuntador < una estructura, la aritmética con p roma en cuenta el para obtener el siguiente ele {1 ciclo en el momento zorrecto. embargo, no hay que suponer que el tamafo de una estructura es la suma de los tamafios de sus miembros. Debido a requisitos de alineacion pai tes objet0s, podria haber “huecos” no identificados dentro de una estructura, ‘Asi por ejemplo, si un char es de un byte y un int de cuatro bytes, la estructura struct { char ¢; int % bien podria requerir ocho bytes, no cinco. El operador sizeof regresa el valor apropiado. Finalmente, un comentario acerca del formato del programa: cuando una funcién regresa un tipo complicado como un apuntador a estructura, como en struct key *binsearch(char +word, struct key stab, int 2) i de leer y de encontrar con un editor de lexto. Por eso, algunas veces se emplea un estilo alternativo: struct key * binsearch(char *word, struct key stab, int n) Esto es algo de gusto personal; seleccione a forma que prefiera y manténgala. 6.5 Estructuras autorreferenciadas ‘Supéngase que deseamos manejar el problema mas general de contar las ocu- or anticipado, 20 podemos orden: biisqueda binaria. No pedemos hacer una busqueda lineal para cada "eee, para ver siya se ha visto, puesto que el programa tomaria demasiad bo, cjecucidn tiende a recer en pr mere de palabras de entrada.) {Como podemos organizar los ‘tos para trata eficien-emente una lista de palabras arbitrarias? Una solucidn es martener siempre ordenado el conjunto de palabras que ya ‘han visto, colocando cada una en su posicién correcta cuando Mega. Esto,154 esrRUCTURAS de cualquier manera, no se podria realizar recorriendo las palabras en un lineal —también tomado demasiado estructura de datos llamada drbo! binario, El arbol contiene tun apuntador tena cuenta tun apuntador al nodo hijo de la izquiorda tun apuntador al nodo his Ningiin nodo puede tener més de dos hi Los nodos se mantienen de tal manera que en cualquier nodo el subérbol quierdo contiene sélo palabras que son bra que esté en el nodo, y el subarbol de la derecha slo contiene palabras son mayores, Este es el drbol para la oracién bres buenos vengan al auxi palabra tal como fue encontrada. labra nueva. Este proceso es recursiv para insercion ¢ impresion seran lo mas natural. Regresando a la des ‘mo una estructura con cuatro componentes: spCCION 6S [ESTRUCTURAS AUTORREFERENCIADAS 155 sta declaracién recursiva de un nodo podria parecer riesgosa, pero es correcta. fs ilegal que una estructura contenga una instancia de si misma, pero carrrun mpo. En lugar de ello utilizaremos ruct tnode “left {eclara a left como un apuntador @ tnode, no como un inode en si. ‘Ocasionalmente, se requiere de una variacién de estructuras autorreferenciadas: dos estructuras que hagan referencia una a la otra. La forma de manejar esto es: ‘nodo” por cada palabra distinta; cada nodo conti lo de la palabra ‘mimero de ocurrencias | struct t{ dorecha lp pubae tener: cero una struct sp; /+ p apunta a una 8 */ icograficamente menores que la iat struct {+q; + qapunta una t +/ 's tiempo de que todos los de su partido”, como se construyé al insertar es sorprendentemente pequeti yetword, que ya hemos descrit include include include ‘#define MAXWORD 100, struct tnode raddiree(struct tnode *, char *); void treeprini(strict tnode *); int gotword(char , int); J+ conteo de frecuencia de palabras +/ main( ) i a nueva palabra es menor que la palabra del arb. iequierda o, de otra manera, en el nodo hij cen la direceién requerida, la palabra nueva no struct tnode *r00t; char word[NAXWORD]; isqueda desde uno de sus hijos. Por ello, unas rutinas recursi root = NULL; jtwerd(word, MAXWORD) != EOF) (isalpha(word| ion de un nodo, se representa convenientemente rot = ad sick als lm of Ee: ete (sepa hain eto »/ Paar iat count (+ imero de ocurrencas +! : tact node iol ingulerde #1 acne sete La funcidn adatroo es recursiva, main presenta una palabra al nivel superior {el ral (a rai). En ead etapa la palabra se compara con la que ya est alma156 ESTRUCTURAS carr cenada en el nodo, y se filtra bajando hacia el subérbol izquierdo 0 derecho una llamada recursiva a addtree. Finalmente la palabra que ya esta en se incremet apuntador nulo, indicando que se debe crear un nodo y agr ‘crea un nuevo nodo, addtree regresa un apuntacor a él, ylo struct tnode stalloo( voi char *strdup(char un modo con w, eno bajo p */ uct tnode +p, ckar *w) Js addtree: age struct inode raddi int cond i (p == NULL /+ llegé una nueva palabra +/ prSword pr>eount = 1; pr>lelt = p—> (cond = stremp(w, p~> ws J> palabra repetida +/ } ‘menor que el contenido del subsrbol izquierdo po>right = addtree(p—> ni return p: lun nodo del érbol, y la nueva palabra se copia un lugar ocul blaremos de esas rutinas en un momento.) Le cuenta se iniciali se hacen nulos. Esta parte del cédigo se ejecuta s6lo para las hojas del art bol izquierdo (todas las palabras menores que és posteriormente el subarbol derecho (todas las palabras mayores). Si se si inseguro sobre a forma en que trabaja la recursion, simule la operacion ol mostrado anteriormente. Iimpresién del arbol pen orden */ (struct tnode +p SECCION 6.5 [ESTRUCTURAS AUTORREFERENCIADAS 157 cl arbol se *'desbalancea’’ debido a que las palabras no Hlegan en orden aleato: -mpo de ejecucién puede aumentar demasiado. En el peor de los casos, si las palabras ya estén en orden, este programa realiza una ccostosa simulacién de bisqueda lineal. Existen generalizaciones del érbol binario ‘que no padecen de este comportamiento del peor caso, pero no las describiremos aqui. Antes de dejar este zjemplo, también es deseable una breve exposicién sobre un problema relacionaco con los asignadores de memoria. Es claramente desea- ble que s6lo exista un asignador de almacenamiento en un programa, aun cuando srentes clases de objetos. Pero si un asignador va a procesar peticiones igamos, apuntadores a char y apuntadores a struct tnodes, surgen dos pre- imera, gc6mo cumple los requisitos de la mayor parte de las maquinas reales, de que los objetos de ciertos tipos deben satisfacer restricciones de alinea- isn (por ejemplo, genecalmente los enteros deben ser situados en localidades pa- res)? Segunda, cuales ceclaraciones pueden tratar con el hecho de quie un asigna dor de memoria necesariamente debe regresar diferentes clases de apuntadores? Los requisitos de alixeacién por lo general se pueden satisfacer facilmente, al costo de algiin espacio desperdiciado, asegurando que el asignador siempre regre- se un apuntador que ctmpla con todas las restricciones de alineacién. El alloc el capitulo 5 no garantiza ninguna alineacién en particular, de modo que emplea- remos la funcion malloc de la biblioteca estandar, que st lo hace. En el capitulo 8 se mostrara una forma de realizar malloc. La pregunta acerca del tipo de declaracién para una funcién como malloc es para cualquier Ienguaje que tome con seriedad la revision de tipos. En , el método apropiadoes declarar que malloc regresa un apu bués forzar explicitamente con un cast al apuntador para hacerlo del seado, malloc y las rutinas relativas estan declaradas en et header . Asi, talloc se puede escribir como Una nota practi ude ces un tnode */ node “tall selumn (struct tnode +) malloc(sizeoi(struct tnode)): } Strdup simplemente copia la cadena dada por su argumento a un lugar segu- 9, obtenido por una llamada a mallee:158 rstRucTURAS captTuto, char *strdup(char *) _/+ crea un duplcado de s «/ { char *p: p= (char +) malloo(stelon(s) +); /* +1 para \O! +/ M(p != NULL) Py(P, 8); return p ) ‘malloc regresa NULL si manejo de jay espacio dispenible; strdup pasa ese valor, de- invocador, a malloc puede los 7 y 8. yerarse para str den alfabético cada grupo de nombres de variable que sean idénticas en sus pri ‘meros 6 caracteres, pero diferentes en el resto. No cuente palabras dentro de denas ni comentarios. Haga que 6 sea un parimetro que pueda fijarse desde tinea de ordenes. 0 6-3. Bscriba un programa de referencas eruzadas que imprima una list \s palabras de un documento, y para cada palabra, un: inea en los que aparece. Elimine palastas como “ Ejercicio 6-4, Escriba un programa que imprina las distintas palabras de su en trada, ordenadas en forma descendente de acuerdo con su frecuencia de ocur cia. Precede a cada palabra por su conteo. C 6.6 Busqueda en tablas sta seceion escribiremos los componentes de un paquete de basqueda doting IN 1 bre IN y el texto de reer cuando el nombre IN apar state = IN; se debe reemplazar por 1 sn dos rut registra el nombre s y el los nombres y textos de reempl sxto de reemplazo t en una tabla; s y t s SECCION 66 BUSQUEDA EN TABLAS 159 solo cadenas de caractetes. lookup(s) busca s en la tabla y regresa un apuntador fl lugar en donde fue encontrado, o NULL si no esti, El algoritmo es una bisqueda hash —el nombre que llega se convierte a pequeio entero no negaivo, que después se usa para indexar un arreglo de apunt ores. Un clemento delarreglo apunta al prineipio de u gue describen nombres que tienen ese valor deh j2in nombre ha obtenico ese valor. jgada de bloques es NULL si nin. 5 SL nombre Se Lam sombre 2 ES dea > entrada de la tabla: +/ J+ siguiente entrada en Ta cadena +/ J+ nombre definido */ J+ texto de reemplazo */ cchar *defn; El arreglo de apuntadores es s6lo “#doline HASHSIE 101 static struct nlis shashtab[HASHSIZE]; /+ tabla de apuntadores+/ La funcion de hash, que se utiliza tanto en lookup como en inst de cardcter de la cadena a una combinacion mezclada de los a resa el médulo de. residuo entre el tamafo del arreglo, Esta no es la mejor ion de hash posible, pero es pequeila y efectiva. ‘+ hash: forma un valor hash para la cadena s */ unsigned hash(char +=) { ‘unsigned hachval; for (hashval = 0; +5 != ‘\O'; s+ +) hhashval = ++ + 31 + hashval; rotum hachral % HASHSIZE; , La aritmetica sin signe asegura que el valor de hash no es neeativo,160 estaucruras El proceso de haslt produce un indice inicial en el areglo hasht se encontrara en algun lugar, serd en la lista de bloques que empi «queda se realiza por lookup. Si lookup encuentra que la entrada ya regresa un apuntador a ella; de otra manera, regresa NULL. J+ lookup: busca s en hashtab +/ struct alist “lookp(char +2) { struct alist emp; for (np = hashtab[hash(s)|; np != NULL; np = np->next) 3 (sremp(s, np->name) = 0) ; Ir e0 enconixs +) + no 48 encontz6 */ El ciclo for que est en lookup es la expresién idiomitica esténdar para movers sobre una lista ligada: for (ptr = head; ptr != NULL; pir = ptr~>next de ser asi, la nueva defi struct nlist lookup(char char ‘strdup(char * ‘+ install: coloca (name, dein) struct nlistcinstall(char *name, char *¢efn) { if (ap = lookup(as fue encontrado */ ap = (struct (ap = = NULL sp(name)) = = NULL) hashval = hash( id +) ap~>detn); /+ M((ap~>defn = strdup(defn) = = retura NULL; retum ap; ‘SECCION 67 TyPEDEr 161 Ejercicio 6-8. Escriba una funcién undef que borre un nombre y una defini- cidn de la tabla mantenida por lookup ¢ install. 0 ss, sin jercicio 6-6. Haga ina version simple del procesador #define ( inas de argumentos) adecuadz para usarse con programas en C, basada en la esta seecidn, También podré encontrar dtiles getch y ‘ungetch. © 6.7 Typedef proporciona una facilidad llamada typedet para crear nuevos tipos de da- typedef int Longitud; nombre Longitud un sinénimo de int. El tipo Longitud puede emplearse aciones, casts, ctc., exactamente de la misma manera en que lo podria Longitud on, mazlen; Longitud “lenzthsl De modo semejante, la declaracién typedef char *Cadena; hace a Cadena un sindnimo para char * o apuntador a cardcter, que después puc- de-usarse en declaraciones y casts alloctint); nombre de variable, 10 justo después di ‘typedef es como las clases de almacenami do nombres con mayiscula para los typé Como un ejemplo més complicado, podriamos declarar Rodos del drbol mostrados anteriormente en este capitulo: typedef struct tnede Treeptr; ic. Hemos emplea- typedef struct tnode{ /+ el nodo del Arbol: +/ char *word; J+ apunta hacia el texto */ int couat + niimero de ocurrencias +) Troo; J hijo izquierdo +/ Treeptr right; J" hijo derecho */ ) Treenode;162 ESTRUCTURAS captTuta, Esto crea dos nuevas palabras reservadas para tipos, llamados Treenode (una. ‘tructura) y Treeptr (un apuntador a la estructura). Entonces, la rutina tal podria ser Troeptr talloc(void) { retum (Treepte) malloc(sizeof(Treenode)); ‘ningtin sentido; simplemente agrega un nuevo nombre para algiin tipo ya exist ie. Tampoco es alguna nueva sem jables declaradas de esta ms jtamente, En efecto, type ser interpretado por el compilador puece realizar subst estiin mas alla de las capacidades del preprocesador. Por ejemplo, typedef int (*AAF)(char *, char *); crea el tipo AAF, de “apuntador a funciin (de dos argumentos char *) que sgresa int”, el cual se puede usar en contextos como AAF strcmp, numemp; rias cantidades enteras, y entonces hacer un conjunto apropiado le short, int y long para cada méquina. Tipos como size_t y ptrdiftt de la bibl esténdar son ejemplos. El segundo proposito de los typedef es proporcionar mejor document cién para un programa —un tipo lamadoTreeptr puede ser més facil de que uno declarado s6lo como un apuntador a una estructura complicada. 6.8 Uniones ‘Una unién es una variable que puede contener (en momentos diferentes) 105 de diferentes tipos y tamafios, y el conppilador hace el segui y requisitos de alineacion. Las uniones proporcionan una forma de manipular Ferentes clases de datos dentro de una sola area de almacenamiento, el program; informacion depenciente de la maquina. Son an: variant records de Pascal. SECCION 68 UMIONES 163 Como un ejemplo, que podria ser encontrado en el manejador de la tabla de simbolos de un compilador, supéngase que una constante podria ser un| 0 un apuntador a cardcter. El valor de una co guardado en una variable del tipo ad No ob manejador de tablas si el valor ocupa la misma ca do en el mismo lugar sin importar su tipo. Este es el propé: una sola variable que puede l La variable u sera suficientemente grande como para mantener al mayor de los plant macenado actualmente en una unidn; si algo se almacena como un tipo y se recu- pera como otfo, el resultado depende de la implantacién, Sintacticamente, se tiene acceso a los miembros de una unin con nombre-unidn. miembro ‘apuntador-uniin—> miembro precisamente como a las estructuras. Si la variable utype se emplea para llevar el registro del tipo actualmente almacenado en u, entonces se podria ver el cédigo como if (utype = = INT) prinii("dato incorrecto Sod en utype\n”, ulyp Las uniones pueden presentarse dentro de estructuras y arreglos, y viceversa. La notacién para tener acceso @ un miembro de una unién en una estructura (0 Viceversa) es idéntica a la de las estructuras anidadas. Por ejemplo, en el arreglo de estructuras defirido por tract {164 estmuctuRAS capituto int utype; union { al; float fval; char *sval; ) symtebINSYM; al miembro ival se le refiere como En efecto, una unién es una estructura en la cual todos los miembros tiei un desplazamiento de cero a partir de la bas grande para mantener al miembro ‘més anc! jas las mismas operaciones sobi luras: asignacion o copia como unidad, tom miembro. F con un valor del tipo de su pirimer miem- jormente solo se puede inicializar con un v El asignador de almacenamiento del cay tuna unién para obligar a gue una variable de limites de almacenamiento. lo 8 muestra cémo se puede alineada para una clase pari 6.9 Campos de bits Cuando el espacio de almacenamiemo es escaso, puede ser necesario Paquetar varios objetos dentro de una sola palabra de maqui 8 un conjunto de banderas de un bit er aplicaciones como tat ara compiladores. Los formaios de datos impuestos externa faces hacia dispostivos de hardware, frecuentemente requieren tomar partes de una palabra, Imaginese un fragmento de un compilador que manipula una tabla de simbé los. Cada identificador dentro de un programa tiene cierta informacién asoci ‘41, por ejemplo, si es o no una palabra reservada, si es 0 no externa y/o est ¥ otros aspectos. La forma mas compacta de codifical conjunto de banderas de un bit dentro de un char o int La forma usual en que esto se realiza es definiendo un conjunto de “mai ras!” correspondientes a las posiciones relevantes de bits, como en secCION 69 CAMPOS DE BITS 165 ‘#define KEYWORD 01 define EXTERNAL 02 #define STATIC 04 ‘enum { KEYWORD = 01, EXTERNAL = 02, STATIC = 04 }; a ser cosa de complemento, 145 expresiones aparecen frecuentemente: lags |= EXTERNAL } STATIC; enciende los bits EXTERNAL y STATIC en flags, en tanto que flags 6 = ~(EXTERNAL j STATIC); Jos apaga, ¥ if (lags & (EXTERNAL | STATIC)) = = 0) .. s estén apagados. es verdadero si ambos Ait yacer eqs sed Pia Gri, Por Chip, a bolos #define podria haber sido reemplazada por la definici6n 0 en que sigue al caracter dos puntos representa : idades si ipos son dedarados unsigned int para ase Los campos individuales son referidos en la misma forma que para otros iembros de estructuras: flags.is__keyword, flags.is_extemn, etc, Los campos comportan como 2equefios enteros y pueden participar en expresiones aritmé- como lo hacenotros enteros. Asi, el ejemplo previo pudo eseribirse més na- almente como flags.is_oatera = flags.ia_static = 1;166 esrRUcTURAS cap para encender los bi flags.is_ext = flags.is_statie = 0; para apagarlos; y lag.is_extern = = 0 8 flage.ie_static = = 0) para probarlos. Casi todo acerea de los campos es dependiente de la implan o pueda traslapar al ‘campos no necesitan tener nombre; los campos sin. nombre (dos pk plitud solamente) se emplean para aderecha en algunas méquinas y de ierda en otras. Esto significa que aunque los campos son itiles el mantenimiento de estructuras de datos definidas internamente, la pregunts ‘qué punta viene primero tiene que considerarse cuidadosamente cuando se ionan datos definidos externamente; ‘os programas que dependen de tales. no son transportables. Los campos sélo se pueden declarar como enteros; u idad, se debe especificar explicitamente signed o unsigned. son arregios y no tienen direcciones, ce modo que el operador & no puede arse a ellos, con su medio amt trado antes. En ese c¢ de funciones que proporcionan jo de memoria, rat mM la bibl ©stdndar, normalmente el teclado, con getchar: int getchar(void) Las propiedadles de las funciones de docena de headers; ya hemi sjemplo, la biblioteca jeva inca en la entrada y de nuevo en la capituLo 7: Entrada y salida 167 que hasta ahora nolas hemos destacado. Sin embargo, los programas interactéan de cadenas, mane-168 ENTRADA ¥ SALIDA carro 7 getchar regresa el siguiente cardoter de la entrada cada vez que se invoca, 0 EOF cuando encuentra fin de archivo, La sonstante simbdlica EOF esta definida en . El valor es tipicamente 1, pero las pruebas se deben escribir en fun- cién de EOF, de modo que sean independientes del valor especifico. En muchos medios ambientes, un archivo puede tomar empleando la convencién < para redireccionamiento de entrada: prog prog nombrearch: si prog ida puede ser liza putchar, prog >archsal escribira la salida estndar hacia archsal. Si se per ntereonexion, prog | otroprog deja la salida estindar de prog en la entrada estandar de otropr La salida producida por printf tamtién encuentra su camino haci tandar. Las llamadas a putchar y a printf pueden estar traslapadas —la salid aparece en el orden en que se hicieron las lamadas. : Cada archivo fuente que se refiera a una funcién de biblioteca de entrada/' lida debe contener la linea #include ida con getchar, putohar y p' lad es sufiviente para comenzar. Est 8 particularmente cierto si se emplea la redireccidn para conectar la salida de seccion 7.2 SALIDA CON FORMATO-PRINTE 169 programa a la en:rada de otro. Por ejemplo, considérese el programa lower, que convierte su entrada a minisculas: #include #include convierte la entrada a mindsculas *) main( ) Int; la, y represa los otros caracteres in sane * como getchar y putchar en y tolower en ido macros, evitandose asi la sobrecarga di |. Eseriba un programa que convierta mayusculas a min sndiendo del nombre con que s¢ invoque, dado en argy 7.2. Salida con formato—printt a funcién de ida printf traduce val res. La deseripeidn de para la definicién comple- are,, are , da formato e imp! cl control de format. Regresa el La cadena de formato contiene dos tipos de obj ue son copiados al flujo de de los euales causa la conversion é sus argumentos en la salida estandar bajo \lmero de caracteres impresos. : caracteres ordinarios,70 exTRADA Y SALIDA ‘caPrTUuLo 7 ‘* Un signo menos, que especifica el ajuste s la izquierda del argumento conver- rimero que especifica el ancho mi 1» de campo. El argumento converti- cadena que ‘0 el numero minimo de digitos para un entero, © Unahsi Ie) si sera como un long. Los caracteres de conversién se muestran en ba tabla 7-1. Si el cardcter después del Ye no es una especificacién de conversién, el comportamiento no esta definido, TTARLA 7-1. CONVERSIONES BASICAS DE PRINTF CaRACTER TIPO DE ARGUMENTO: IMPRESO COMO vimero decimal. ° vimero octal sin signo (sin ero inicial. aX ; niimero hexadecimal sin signe (con un Ox 0 OX inicial, usando abcd ‘© ABCDEF para 10, ... 1S. 8 i; mimero decimal sin signo. e i; cardcter se 5 cchar *; imprime caracteres de una cadena hasta un \O" o el nimero de: racteres dado por la precsién 1 double; [—Jm.dddddd, en donde et nimero de ds esta dado por ta preci sin (predeterminado 3 6), ,£ | double; [-]m.dddddde = xx 0 [bn.ddddddE + xx, en donde el nimero d dis esta dado por la precision (predeterminado a 6) aG ‘expouente es menor que —4 0 mayor 0 i8t P ;puntador (representacion dependiente de la instalacion). % ido en ningiin argumento: imprime un Ye. far por +, en cuyo caso el valor do el siguiente argumento (que debe ser int), Por ejemplo, pat ir al menos max caracteres de una cadena s, print(%6.0", max, 8); SECCION 73 LSTAS DE ARGUMENTOS DE LONGITUD VARIABLE 171 La mayoria de lasconversiones de formato se han ilustrado en capitulos ante- siores. Una excepcién es la precisién relacionada con las cadenas dda campo para que se pueda apreciar su extensién, 6s: ‘hola, mundo: 96108: ‘hola, mundo: %,108: ‘hola, mund: 4-108: ‘hola, mundo: 96.15 ‘hola, mundo: 194715: ‘hola, mundo 418.106: hola, mand: 15.105: ‘hola, mund printf emplea su primer argumento para decidir cuéntos ceuiles son sus tipos. printf se con hay suficientes argumentos a si ia diferencia entre estas dos Js FALLA si ¢ contiene % +/ ); f+ SEGURO «/ La funcién sprintf realiza las mismas conversiones que printf, pero almacena ta salida en de una cadena: sprinti(char ‘cadena, char “format, ar ) arg, et, de acuerdo con format como antes, pero coloca el resultado en sadendjen vez de en la salida es- {eadenal debe ser suficientemente grande como pa ‘imal de acuerdo con la costumbre local, y separar lineas largas de texto. 0 7.3 Listas de argumentos de longitud variable Esta seccion contiene la realizacion de una version minima de printf, para Mostrar cémo escribir una funcién que procese una lista de argumentos de lot ‘ud variable en una forma transportable. Puesto que estamos interesados princi Palimente en el procesemiento de argumentos, minprint! procesara la cadena de ‘ormato y los argumentos, pero llamara al printf real para hacer las conversiones te formato.172 ENTRADA Y SALIDA caprtuto! La declaracién correcta para printf es Ant print(char * donde la declaracién .. significa que el mimero y tipo de esos argumentos . s6lo puede aparecer al final de la lista de argument ‘Nuestra minprintf se declara como ) ya que no regresard la cuenta de caracteres que regresa printf El truco est4 en cémo minprintf recorre Ia lista de argumentos cuando la ls ni siquiera tiene un nombre. El header estindar contiene un junto de macrodefiniciones que definen cénio avanzar sobre una mentos. La realizacion de este header variera de una maquina a interfaz que presenta es void minp! El tipo va_list se emplea para declarar una variable que se referiré a argumento en su momento; enminprintf,es'a variable se llama ap, por ‘ment pointer" (apuntador a argumento). La macro va_stazt ini apuntar al primer argumento sin nombre. Debe Hamarse una vez antes de ap. Al menos debe haber un argumento con nombre; el iltimo argumento nombre es empleado por va_start para Cada llamada de va_arg regresa un argumento y avanza ap al sigui va_arg emplea un nombre de tipo para deteminar qué tipo regresar y cudn. ge serit el avance, Finalmente, va-end realiza las labores de limpieza y arré {que sean necesarias. Debe invocarse antes que la funcin regrese. Estas propiedades forman la base de nuestro printf simplificado: #include J+ minprintf: printf minima com lista variable de argumentos +/ void minprint{char #fmt, ..) { va_list ap; /+ apunta a cada ary sin nombre en orden «/ cchar «p, ‘eval; int ival; double aval ce que ap apunte al ler. arg sin nombre «/ (+ +p) { case val = va_arg(ap, SECCION 74 ENTRADA CON FORMATO-SCANF 173, for (oval = va_arg(ap, char +); esval; sval+ +) ‘putchar(+sval); va_end(ap); /* limpia cuando todo esté hecho +/ t 7-3, Aumente minprin fa que maneje otras de las caract printf. 0 7.4 Entrada con formato—scant La funcién scanf es la entrada andloga de print, y proporciona muchas de las mismas facilidades de conversién en la direccién opuesta int scanf{char slormat, ...) scanf lee caracteres dela entrada estindar, los cificaciones que estan en format, resultados a través de los argu- ments restantes. El a:gumento de formato se describe abajo; los otros argumen- tos, cada uno de lo; cwales debe ser un apuntador, indican dénde deberd almacenarse la entrada correspondientemente conv "omo con printf, esta Seccidn es un resumen de las po: iva, scanf se detiene cuando termi entrada no coincide con la esp nnimero de ftems de ertrada que ecidir cudntos iter tese que esto es "no coincide cor llamada a seanf conti ‘er que ya fue conv Existe también una funcién sscanf que lee de una cadena y no de la entrada ssténdar: int escanf(char ‘cadena, char format, arg, ary =) preta de acuerdo con las espe ‘iden con éxito. Esto se puede emplear para ron, Al final del archivo, regresa EOF; n6- tardcter de entrada era especificacidn en la cadena de formato. La siguiente ala busqueda inmediatamente después de!174 ENTRADA Y SALIDA caprtuto 7 Rasirea la cadena de acuerdo con el formato en format, y almacena el valor resultante a través de arg,, arg,, etc. Estos argumentos deben ser apuntadot La cadena de formato generalmente contiene especificaciones de conversién, las cuales son empleadas para controlar la conversién de entrada. La cadena de formato puede contener: * Blancos o tabuladores, los cuales son ignorados. (no %), que se espera coincidan con el siguiente carée- spacio en blanco del flujo de entrada, cs de conversion, consstenes eel carcter Mo, un cardcteropkati= vo de supresién de asignacién +, un ntmero optativo que especifica el ancho maximo de campo, una b, I, 0 L optativa que indica la amplitud del objetivo, yum cardcter de conversion. La especificacion de conversion dirige la conversion del siguiente campo de en- trada, Normalmente el resultado se coloca en la variable apuntada por el argu ‘mento correspor . Si se indica la supresion de asignacién con el cardcter +, sin embargo, ida es ignorado y no se realiza asignacion alguna, Un campo de ‘4 definido como una cadena de caracteres que no son espa cio cn blanco; se extiende hasta el ite espacio en blanco o hasta que el blanco. es de espacio en blanco son tabulador, de carro, tabulador vertical y avance de El cardeter de conversién indica la interpretacién del campo de entrada. El argumento correspondiente debe ser un apuntador, como es requerido por la se- ‘mintica de las llamadas por valor de C. Los eacacteres de conversion se mu en la tabla 7-2. TTAMLA 7-2, CONVERSIONES BASICAS DE SCANE ‘CARACTER Dao DE ENTRADA: “IPO DE ARGUMENTO: 7 aaraaaas Eleni puede eure xl iad con Oo hxadeill icado, El sako normal sobre los espacios en blanco 8 suprimido; para leer el siguiente espacio no blanco, use 961s. SeCCION 74 ENTRADA CON FORMATO-SCANF 175 5 cadena de caracter taracteressuficiente que serd agregada ‘nero de punto flotante con signo, punto decimal y exponente optativos; float « % % literal; no se hace asignacién alguna, lada); char *, apunta a un arreglo de ara la cadena y una terminacion "Ot Los caracteres de conversion d, i, 0, u, x pueden ser precedidos por h para indicar que en la lista de argumentos aparece un apuntador a short en lugar de 2 int, por] (letra ele} para indicar que aparece un apuntador a long en la lista de argumentos. En forma semejante, los caracteres de conversién e, f, ¢ pueden idos por 1 para indicar que hay un apuntador a double en lugar de a float en la lista de argimentos. ‘Como un primer ejemplo, Ia rudimentaria calculadora del capitulo 4 se puede cscribir con scanf para hacer la conversién de entrada: #include ‘Suponga que desearos leer lineas de entrada que contienen fechas de la forma 25 Die 1988 La proposicién scant es int day, year; char monthname(20]; scanf("%d %s Md", Say, monthname, Seat); ‘No se emplea & con monthname, ya que un nombre de arreglo es un apuntador. Pueden aparecer caracteres literales en la cadena de formato de scant, y de- ben coincidir con los mismos caracteres de la entrada. De modo que podemos leer fechas de la forma mn/dd/yy con esta proposicién scant: int day, month, year; | Bmonth, Bday, ye176 ENTRADA ¥ SALIDA sscanf ignora los blancos y los tabuladores Ademés, salta sobre los espacios en blanco (blancos, tabuladores, nuevas lineas, tc.) mientras busca los valores de entrada. Para leer de entradas cuyo format sscanf. Por ejemplo, suponga que deseamos leer lineas que pueden contener fe chas en cualquiera de las formas anteriores. Entonces podemos escribir rma 25 Dic 1988 +/ , day, Gyear) = = 3) } Las llamadas a scanf pueden estar me ciones de entrada. La siguiente llamada a c en lugar de scant("%d", &n); Este error generalmente no se detecta en tiempo de compilacién. Ejercicio 7-4. Escriba una versién privada de scanf andloga a minprinti de seccidn anterior. Ejercicio 7-5. Reescriba la calculadora postfija del capitulo 4 usando scanf y/ seanf para hacer la entrada y la conversién. 0 7.5. Acceso a archivos Hasta ahora todos los ejemplos han la salida estandar, las cuales se definen tivo local es escribir un programa que dé acceso a un de la entrada estandar y escrito toma ACCESO A ARCHIVOS 177 SBECION 75 colector de entradas de sropésito general para prograi idad de vener acceso a los arc! eatzc yc {mprime el contenido delos archivos x.c y y.c (y nada mds) en la salida estandar. La pregunta es como hacer que los archivos nombratdos sean leidos —esto es, 10 conectar las propesiciones que leen los datos, con los nombres externos que o tiene en m {que Ser abierto por la fu no como x.¢ 0 y.c, hace ‘yo (cuyos detal cen posteriores lectut Este apuntador informacién acerca del archivo, posicién de cardcter actual en el buifer, y si han ocurrido errores o fin de archivo. Los usuarios no ne detalles, debido a que las definiciones obtenidas de incluyen una declaraci6n de estructura Hamada FILE. La tinica declaracién necesaria para un apuntador de archivo se ejemplifica por junos arreglos y negociaciones con el sistema operati- . y regresa un apuntador que sera usado o escrituras del archiv FILE «ip; FILE «fopen(char +nombre, char modo); FILE, Notese que FILE & ra; esta definido con un typedef, (Los det ma UNIX se explican en la seccion 8.5.) La llamada a fopen en un programa es fp = fopen(nomb:e, modo); El primer argumento de fopen es una cadena de caracteres que contiene el nom- yen lectura ("x"), escritara (w"), y afladido ("a entre archivos de texto ybinarios; para los ditimos, debe ese de ta cadena de modo. Si un archivo que nc existe se abre para escribir 0 afadir, se crea, si es p ble. Abrir un archivo existente para escribir provoca que los contenidos anterio- res sean desechadas, mientras que abrirlo para afladir los preserva. Es un error ar de leer un archivo que no existe, y también pueden haber otras causas de ttror, como tratar de leer un archivo cuando no se tiene permiso. Si existe cual- la seccion 1 en el apéndice B.)178 erRapa ¥ SALIDA carrots Lo siguiente que se requiere es una forma de leer o escribir el archivo una que est abierto, Existen varias posibilidades, de las cuales gete y pute son las ples. gete regresa el siguiente cardcter de un archivo; necesita el apuntadg del archivo para decirle cual es. (FILE stp) ete regresa el siguiente caracter del flujo al que se refiere fp; regresa EOF si o re algin error. pate es una funcion s int puto(int ¢, FILE fp) pute escribe el cardcter ¢ en el archivo fp y regresa el cardcter escrito, o EOI ‘ocurre un error. Tal como getchar y putchar, gote y pute pueden ser macros; lugar de funciones ‘Cuando se arranca un programa en C, a medio ambiente del sistema oper vo es responsable de abrir tres archivos y proporcionar apuntadores de ar ppara ellos. Estos archivos son la entrada estandar, la salida estandar y el estndar; los apuntadores de archivo correspondientes se llaman stdin, st stdery, y estin declarados en . Normalmente stdin se conecta a do y stdout y stderr se conectan a la pant rigidos a archivos 6 a in getchar y putchar puede! y stdout, como sigue: #deline getchar( ) _getc(sidin) +#define putchar(c) pute((c), stdout) da o salida de archivos con formato se pueden emplear las funcic nes fscanf y fprintf. Estas son idénticas a scanf y printf, excepto en que el pri argumento es un apuntador de archivo que especifica el archivo que sera la cadena de formato es el segundo argumento. int fprint(FILE “fp, char "form Habiendo hecho a un lado estos prerrequisitos, ya estamos ahora en posi jr el programa cat, que concatena archivos. El diseno se ha encontr argumentos en la linea de ord y se procesan en orden. Si no ha nes, se interpretan como nombres de argumentos, se procesa la entrada es! include 1+ cat: concatena archivos, versién 1 »/ main(int arge, char *argu{ |) { FILE “ip; void filecopy(FILE +, FILE SHCCION 76 [MANEIO DE ERRORES-STOERR Y EXIT 179 i (erge == 1) /* sin args; copia la entrada esténdar filecopy(stdin, stdout); lee while (——arge > 0) 4 (Up = fopen(++ +argy, "x")) = = NULL) { pinti("cat: no ge puede abrir %s\n", argv); rotum 1 else { lecopy dor retum 0; ) Js ilecopy: 60 void filecopy(FILE 1 inte; chive ifp al archivo ofp */ FILE +ofp) ile ((e = getcti Pute(e, ofp); != EOF) ) Los apuntadores dle archivo stdin y stdout son objetos de tipo FILE +. Sin embar- ‘20, son constantes, #0 variables, por lo que no es posible asignarles algo. La funcién 3t fcloso(FILE +ip) slo inverso de fopex; interrumpe la conexién que fue establecida por fopen en- reel apuntador de archivo y el nombre externo, liberando al apuntador de archi- vo para otro archivo, Puesto que la mayoria de los sistemas operativos tienen al- sotre el mimero de archivos que un programa pu yerar los apuntadores de archivo ‘cuando ya no son necesarios, usar felose en un archivo de sal do la salida, Cuando un programa termina normalmente, maticamente para cada archivo abierto. (Se puede cerrar son necesarios, También pueden ser reasignados por la funcién de bi reopen.) 7.6 Manejo de errores—stderr y exit E] manejo de los errores en cat no es el ideal. El pri de tener acceso a unode los archivos por alguna razén, iagndstico se imprime180. ENTRADA Y SALIDA ‘captruLoy SeCCION 77 ENTRADA Y SALIDA DE LINEAS 181 al final de la salida concatenada. Eso podria ser aceptable sila salida va a la pan. probar el éxito o fracaso del program: + Pero 1 acia un archivo o hacia otro programa mediante una inter. Convencionalmente, un valor de conexidn, diferentes de cero generalmente sei {close por cacla archivo de salida abierto, a través de un butffe: Dentro de main, return expr es equivalente a es xit tiene la ventaja de que puede ser llamada desde otras funciones, y que las llamadas a ella se pue~ iden encontrar con ur. programa de biisqueda de patrones como el del capitulo 5. La funcién ferxor regresa un valor diferente de cero si ocurrié un error en el ‘ujo fp. ‘int forror(FILE +fp) Para manejar mejor esta situacion, se asigna un segundo flujo de salida, mado stderr, a un programa en la misma forma en que stdin y stdout. La cescrita hacia ‘stderr normalmente aparece en la pantalla, aun sila Corrijamos cat para escribir sus mensajes de error en el archivo de err cestindar. #include aida 2 +) Aunque los errores de salida son raros, si ocurren (po. WeoAPILR a sing ln Prom ua vclerdifersahe door jido un fir de archivo en el archivo especificado. void filecopy(FILE +, FIL char “prog = argi nombre del programa para errores «/ reupado por el estado de a salida dk ograma serio debe 1 large == 1) /+ sin args; copia la entrada esténdar +/ filecopy(sidin, stdout char fgeta(char “linea, int maxlinea, FILE +fp) {puts escribe una cadena (que no necesita contener una exit(2); (2); nueva linea) a un archivo: int fputs(char “nea, FILE «fp) Esta funcién regresa EO) i ocurre un error y cero si no ocurre eva gels y puts son semejantes a fgets y fpuls, pero in y stdout, De modo desconcertante, gets elimina el fal torms- ‘qui estan, copiadas de la biblioteca estandar de nuestro sistema J+ fgets: cbtisne hasta n caracteres de iop +! char +lgets(char «s, int n, FILE siop) uniguier proceso que haya lamado a tste, para que se182 _exreaba y satis, caprruLo EOF Gs = = 5) ? NULL: s ‘coloca Ja cadena & en el archivo iop +/ thar +8, FILE siop) while (e = +844) ute(c, iop); return ferror(iop) ? EOF : 0; / golline: lee un int getline(char “Ii regrosa s longitud */ max) (line, max, stdin) = = NULL) return 0; else return strlen( fograma para comparar dos archivos, imprimiendo inea en donde difieran. 0 Ejercicio 7-7, Modifique el programa de >iisqueda de un patrén del capitul para que tome su entrada de un conjunto de archivos nombrados , si no archivos nombrados como argumentos, de la ¢} cl nombre del archivo cuando se encuentra una Ejerciclo 7-8. Escriba un programa para imprimir un conjunto de arc siando cada nuevo archivo en una pagina nueva, con un t pagina por cada archivo, © seCCION 78 OTRAS FUNCIONES 183 7.8 Otras funciones ,teca estindar proporciona wi variedad de funciones, Esta 7.8.1 Operaciones sobre cadenas ‘Ya hemos mencionado las funciones sobre cadenas stelen, stropy, st y stremp, que se encuentran en <(iring-B>. En adelante, s y char *, yey n son irts, igual que stremp pero s6lo en los prumeros n caracteres copia ten s copia a lo mas n caracteres det as regresa la longitud de s regresa un apuntador al primer c que esté en s, 0 NULL. si no esta prese regresa un apuntador al imo ¢ que esté en s, @ NULL, sino esta presente strnepy(st,s) strohr(s,e) strrebr(s,¢) 7.8.2 Prueba y conversion de clases de caracteres Varias funciones de realizan pruebas y conversiones de caracte- res. En lo que se muestra a continuacién, c es un int que se puede representar como un unsigned char o EOF. Las funciones regresan [int touppex(c) tolower(e) 7.8.3 Ungete (eva estandar proporciona una version més restringida de la funcién “agetch que escribimos en el capitulo 4; se llama ungetc.184 ENTRADA y Sal - carruto int ungete(int c, FILE tp) coloca el cardcter ¢ de nuevo en el archivodo y regresa c, 0 EOF en caso de erroy Solo se garantiza poner un cardcter de regreso por archivo. Es posible tungete con cualquiera de las funciones como scanf, gete 0 getchar. 7.8.4 Ejecucion de ordenes La funcién system(char *s) ¢jecuta la orden contenida en la cadena de car teres 8, y después continita la ejccucidn del programa actual. Los contenidos 8 dependen fuertemente del sistema operativo local. Como un ejemplo t sistemas UNIX, la proposicién programa date, el next) OTRAS FUNCIONES 185 mies de liberar for (p = head: p!= NULL: p = q) = po>mext; seccion 8.7 asignador de al malloc, en el cual los bloques asignados se pueden liberar en cualquier o1 7.8.6 Funciones matematicas Existen mas de veinte funciones matemticas declaradas en ; aqui an algunas de las empleadas con mas frecuencia. Cada una toma uno 0 dos argumentos double y tegresa un double. ints) se1o de x, x en radianes cout) coreno dle x, x en radianes alan2.x) arco tangente de y/x, en radianes exp) funcién exponencial e* ogtx) logaritmo natural (base ¢) de x (x>0) Jog10(x) smo comin (base 10) de x (x>0) powsy) a sqrtty,) __rait evadrada de x (¥>0) fabst) valor absoluto de x 7.8.7 Generacién de numeros aleatorios La funcién xand( ) calcula una secuencia de enteros pseudoaleatorios en el rango de cero a RAND_MAK, que cs! producir mimeros aleatotios de punto flotante mayores 0 iguales a cero pero me- ores que uno es ‘#define frand{ ) (double) rand( (Si su biblioteca ya proporciona una funcién para mimeros aleatorios de flotante, es probable que tenga mejores propiedades esta és a funcién srand(ussigned) fija la semilla para rand. L til de rand y de srand sugerida por el esténdar aparece en la seccién 2.7. Ejerciio 7-9. Se pueden escribir funsiones como isapper nara ahorar espacio @ tempo, Explore ambasposibildades. ©capitutos: La interfaz con el sistema UNIX El sistema operative UNIX proporciona sus servicios a través de un conjunto de Hamadas al sistema, que consi we estan dentro del sistema ‘operative y que pueden ser deseribe como emples ema para tener maxima, no esté en la bil ia, 0 para cener avceso a alguna fac se emplea Cen un si la programa des de UNIX, este codigo puede ayudar tamt . El capitulo esté divid do en tres partes fundamentales:entrada/salida, sistema {archivos y asignacién Je almacenamiento. Las primeras dos partes suponen uma ‘modesta familiaridad con las caracteristcas externas de los sistemas UNIX. con una len que escribir en términos de las fac En las seeciones de este capi UNIX para entrada y salida, y mostraremos como puede escribirse parte de la biblioteca estandar con ellas. 8.1 Descriptores de archivos En el sistema operative UNIX, todas las entradas y salidas se realizan por la lectura o escritura de archivos, debido a que los dispositivos periféricos, aun el que una la interfaz homogéxea maneja todas las comunicaciones entre un programa ico. s disposi En el caso mis gene! mar al sistema acere «primero se debe in- eel proceso llamado188 LA INTERFAZ DEL SISTEMA UNIX. (9 no ncgativo llamado re que se van a efectuar acciones de entrada y salida sobre ese jor de archivo para ident ar del nombre, 20 al apuntador de archivo usado por ka lador de archivo de MS-DOS.) Toda la informas tan comin que la en cexisten arreglos es} rprete de comandos n descriptores 0, lamados entrada estandar, salida estandar estandar. Si un programa lee deO y scribe a! y a2, puede hacer entrada, preocuparse de abrir archivos. El usuario de un programa puede redit la E/S hacia y desde archivos prog archsal En este caso, Oy Laos arc! ce asignado cambia las asignak -s predefinidas para los deseriptore ‘de archivo 2 perm jograma no sabe de dénde ientras use al archivo 0 para entrada y 1 y 2 para sal 8.2 E/S de bajo nivel—read y write La entrada y salida usa las llamadas al sistema read y write, a las que se acceso desde programas escritos en C a través de dos funciones llamadas write. Para ambas, el primer argumento e: un descriptor de archivo. El seg argumento es un arreglo de caracteres perteneciente al programa hacia o de d los datos van a iro venir. El tercer argumento es el nimero de bytes que s transferidos. int meidos = read(int f4, char, +bu:, {nt n_escritos = waite(int fd, char «bu! Cada llamada regresa una cuenta del mimero de bytes transferidos. En el nimero de bytes regresados puede ser menor que SCION 82 [B/S DE BAJO NINEL—READ Y WRITE 189) tipo. Para escritura, el valor de retorno es el ntimero de bytes escritos: si éste no ¢s igual al mimero solicitado, ha ocurrido un error, En una llamada pueden leerse cualquier niimero de bytes. Los valores mas co- | que senifica wi ala vez (sin buffer), y un niimero como 1024 04098, que co-responde al tamatio de un bloguefsio de un dispositive pe. rico. Los valores mayores seran més eficientes debido a que serdn realizadas ienos llamadas al sistema, Para juntar estos temas, podemos escribir un sencillo programa que co entrada a su salida, 21 equivalente del programa copiador de archivos escri cosa, ya qi salida pueden ser redirigidas hacia cualquier archivo o disposi entrada y ‘include “syecalls.h” mai ( [+ copia Ja entrada a la salida +/ char bufBUFSIZ); int n; while ((n = read(0, bul, BUFSIZ)) > 0) writ, buf, return 0; Hemos reunido prototipos de funciones para las llamadas al sistema en un ar- chivo llamado syscalls.h, de modo que podamos incluirlo en los programas de in embargo, este nombre dentro de syscalls.h; su valor es imaiio adecuado para el sistema loce tamafio del archivo no es un mil de BUFSIZ, alziin read regresara un nimero menor de bytes a ser eseritos Por write; la siguiente llamada a read después de eso regresara cero, Es insiructivo ver como se pueden usar read y write para construir rutinas de ‘alto nivel como getchar, putchar, etc. Por ejemplo, aqui esta una versién de get- char que realiza entrada sin buffer, leyendo de la entrada estdndar un cardcter @ la vez, ‘include "sysclls.h” J+ gotchar: onirada de un cardcter simple sin buffer «/ int getchan(void) { char ¢; ra (read(0, &c, 1) = = 1) ? (uns190 La INTERFAZ DEL SISTEMA UNIX. caPrTULo SECCION 8. OPEN, CREAT, CLOSE, UNLINK 191 O_RDONLY abr O_WRONLY al O_RDWR tb sélo para leetura s6lo para escritura para lectura y eseritura © debe ser un char, a que read necesita un apuntador a cardcter. Forzar f¢ 4 ser unsigned char en la proposicion de regreso elimina cualquier problema de extensién de signo. ; La segunda version de getchar hace la entrada en grandes fragmentos y saca los earacteres uno a la ver. Estas constantes estan definidas en en sistemas UNIX System V, y en en rersiones Berkeley (BSD) 'syscalls.h” Para abrir un archivo ya existente para Lectura, vvorsién con buffer simple +/ a (void) fd = opon(nombre, O_RDONLY, 0); El argumento per Es un error trat 8 28 siempre cero para [os usos de open que discutiremos. de at static char buf[BUFSIZ); inf ereat(char «sombre, int perme); fd = creat(nombre, perms); sesa un descriptor de archiva si fue capaz de crear el archivo, return (-—n >= 0) ? (unsigned ctar) sbufp+ + : EOF; , Si esta versién de getchar fuese a ser compilada con incluida, seri necesario eliminar la definicién del nombre getchar con #undef en caso de q esté implantada como una macro. 83 Open, creat, close, unlink of Seed aioateas WeUN ‘Ademis de la entrada, la salida y el erroresténdar, se pueden abrir explicit ee ee mente archivos para leerlos o escribitlos. Existen dos llamadas al sistema para e to, open y creat.s ‘open es como el fopen expuesto en el caritulo 7, excepto que en lugar de _resar tn apuntador de archivo, regresa un descriptor de archivo, que es tan s tun int. open regresa —I si ocurre algiin error. #include include ‘#include #include “syscalls.h” #define PERMS0666. /.loctura y escritura para propietario, grupo y atrose! int fa; void error(char +, ..); int open(char snombre, int flags, int perms); Joep: copia fl a2 +/ main(int argo, char ‘argv! |) { fd = open(nombre, flags, perms); Como con fopen, el argumento nombre es ura cadena de caracteres que conti el nombre del archivo. El segundo argumento, flags, es un int que especi como serd abierto el archivo; los principale: valores son int 1, £2, 25 iH (arge != 3) 1A pesar de queen inglés la palabra correcta es “emate™, el nombre de la funcion es s6l0 " terror ("Uso: ep de hacia") oreat”. (N. de T.){LA INTERFAZ DEL SISTEMA UNIX, if (EL = opentarav{i], O_RDOMLY, error("ep: no se puede M ((2 = creat(argvi2], PERMS)) == —1) error("ep: no s0 puede crear %s, modo %6030", bul, BUFS22)) > 0) if (wrto(!2, buf, n) |= 2) "op: error de eszritura en el archivo 96s", argv seccién 8.5, podemos determinar el modo de smo modo a la copia. muy semejai como printf, excepto que solo argumento qi ma semejante, vipri y vsprintf coinciden con fprintf y sprintf. include #include Js error: imprime un mensaje de enor y muere +/ void error(char “fmt, ...) { va_list args; fe archivo para ser ul biblioteca estandar excepto un buffer que vaciar. La terminacién de un programa via exit 0 turn desde el programa principal cierra todos los archivos abiertos. SeCCION BA ACCESO ALEATORIOWISHEK 193, stema de La funcién unlink(char *nombre) remueve el archivo nombre del archivos. Corresponde a la funcién de la bi open 1 doterminar Ia velocidad reatva de las dos versiones. 8.4 Acceso aleatorio—iseek La entrada y la salida Ta ace dscns ad pregnant Bea pes Se sin leer 0 exribir ningiin dato: long offset, int origen); én actual en el archivo cuyo descriptor es fa, localizecién especficada por igen), Una lectura 0 escrit en ¢sa posicidn. forigen| puede ser 0, 1 0 2 para especificar que desde la posicin act: ara agregar a un jue se toma Para regresar al principio (‘‘rebobinay Isoek(fd, OL, 0); Nétese et argumento Osi Iseek esta decler Con’ 50s, al precio de unacceso mas , uier numero de bytes en cualquier lugar arbitrario de un archivo. Regresa el nt mero leido, 0 1 er caso de error. ambién podria ser escrito como (long) 0 0 sélo como adecuadamente. #include “syscalls.h!” lee 1 bytes de la posicién pos +/ 2g pos, char *buf, int n) 1 (lseef(d, por, 0) >=0) /+ se sitia en pos +/ elu read{fd, bul, n);194 La intexrAz DEL SISTEMA UNIX carrrutog seCCION 8S EIEMPLOUNA IMPLEMENTACION DE FOPEN Y GETC 195 else ‘Pdeline stdin (&iob(01) return =I #define.stdout (ob (1) } #detine sider (S4i0b (2) de regreso de Iseek es un long cue da la nueva posicién en el archivo, ‘enum fags ( =I Si ocurre un error. La funcidn de biblioteca estandar fseek es semejante “READ = 01, _/+ archivo abierto para k, excepto en que el primer argumento es un FILE + y el valor de rexreso ex LWRITE = (2, + archivo abierio pare ese iferente de cero si ocurrié un error. TUNBUF = 04, /+ archivo sin bullor «/ [HOF = 010, ocurté fin de archivo (EOF) en este archivo +/ TERR = 020 [+ ocurré un error en este archivo +/ h 8.5 Ejemplo—una realizacién de fopen y getc ‘nt Sillbul(FLB »); int Slushbuflint, FILE +); ca estandar son descritos por apu rhivos en vez de con descripiores de archivo. Un apuntador ‘apuntador a una estructura que contiene informacion varia aceres del archivo: un apuntador a un buffer, para que el archivo pueda ser leid cen grandes fragmentos; niimero de caracteres que quedan en buffer; un apuntador a la posicién del siguente cardcter en el buffer; el deseript ¥ banderas que describen el modo de lectura/eseritura, estado #dofine feof(e) (((p)—> flag & BOF) != 0) ro(p) __(((p)—> flag & ERR) != 0) fileno(p) (@)—> 44) tadores de #define getc(p) (——(p}—>ont >= 0\ eee 9 Gamma clas) ofp)—Dpir + ¢ filha!) ‘#define putcix.p) (——(p)—>ent > = 0\ F (p)—>ple+ + = (x) + flashbull ) en cushauier archivo fuente qu doting gotchax) —_gote(stdin) a ‘#define puicha: pute((x), stdout) tuiente fragmento de un hombres que se intenta emplear solo en las funciones de la bi rincipian con un subguién, por lo que soa menos suscept ‘con nombres en los programas del usuario. Esta convencion la emplean todas k rutinas de la biblioteca estandar, 0 gele norm: fecuerde que ‘#deline NULL ° cy 1024 ‘#dotino OPEN_MAX 20 /+ méximo mimeto de archivos abiortos a la vez ‘Aunque no diseatiremos ningin det ara mostrar que opera en forma mu funcién flushbuf cuando su buffer esta para tener acceso al estado de error Ahora puede escribirse la funcid typedet struct iobuf { Int ent; J+ caractores que quedan +/ ao ace go para el bu’ eto es realizado por -filbut evande el archivo se lee por int flag; J+ modo de ecceso al archivo +/ Drimera vez. in 1s deveipor de archivo #/ pati ca } FILE; #include “syscalls.h” ‘extern FILE iob[OPEN MAX]; ‘#doline PERMS 0666 /+ Tectura y sscritura para propietario, grupo, otros +/196 14 ivreRvAz DEL SISTEMA UNIX Js fopen: abre un archivo, regresa un apuntador de archivo +/ FILF , fopen(char «name, char #mode) { i (ip > = ob + OPEN_MAX) return NULL; fr no hay entradas if (smode = = ‘w) fd = creat(name, PERMS); = open(name, O_WRONLY, 0)) = = -1) = creat(name, PERMS); Isook(d, OL, 2); se {d= open(name, O_RDONLY, J+ no hbo 20: 10 al nombre «/ fp—>base = NULL; ip—>flag = (mode = = ‘y) 7_READ : _WRITE; retura fp; } Esta versin de fopen no maneja todas las posibilidades de modo: esténdar, aunque el levaria mucho eédigo. En ps tra fopen no reconoc a acceso bint que permite asignar un buffer (si la lectura sera con suffer Una ver que el buffer ha sido establecito, _fillbuff llama a read para Il fija la cuenta y los apuntadores, y regresael cardcter del principio del buffer. posteriores amadas a _fillbuf encontrarin un buffer asignado. Elercicio 8-4, EIEMPLO—UNA INPLEMENTACION DE FOPEN Y GETC 197 ‘#inclode “syscalls.h” asigna y lena un buffer de entrada +/ tillbui(FILE +fp) lag&(-READ|.£OF}_ERR)) != READ) EOF, )—> lag & -UNBUF) ? 1 : BUFSIZ; == NULL) (+ sin buffer ain >base = (char +) malloc(butsize)) = = NULL) return EOF; (+ no puede obtener un buffer */ fp—>pir = fp—>base; fp—>eit = read(fp—> id, fp—>ptr, bulsize); if (——p—>ent < 0) { if (p—>ent = = —1) fp—>flag |= EOF; |= ERR; rotten EOF; ' rotum (unsigned char) sfp—>ptr+ +; cabo suelto es como artancar todo, El arteglo ob debe ser defini- ado péra stdin, stdout y stder MLR _scbfOPeH_MAR] = { fr sin bint odes») lin serd leido, juctura muestra que y stderr sera escrito sin buffer. Reestriba fopen y _fillbut con campos en vez de operaciones ex- a funcién de biblioteca estindar int fseek(FILE « fp, long offset, int origen)198 La ivreRraz Det SISTEMA UNIX carrruce s idéntica a Iseek except sun apuntador de archivo en vez de un dé vos que estan en el omo tamaios, permisos 0 de UNIX es simplemente un archivo, 10 para obtener los nombres de archivos. Pero es necesario al sistema para tener acceso a la otra infomacion acerca DOS, por ejemplo. Lo q ormacidn en una forma relat 4 pesar incluso de que la realizacién pus imprime los tamaios de todos los arc de argumentos. Si uno de los archivos es un rio fsize se apli 4 para ese directorio. Sino hay ningin argumento, procesa de UNIX. Un directorio es un archivo que sontiene una vo y algunas indicaciones de dénde se localizan. La del sistema al nombre y nimero del directorio, Escriviremos {size con esta interfaz. ISTADO DE DIRECTORIOS 199 dependiente del sistema. opendir regresa un apuntador @ una estructura llamada DIR, andloga a FILE, que es empleada por readdir y closedir. La informacién es recolectada en un archivo llamado dirent.h #deline NAME_MAX 14 /+ componente de nombre de archivo més gran- de; = Js dependiente del sistama +) typedef struct { _/+ entrada de directorio transportable: +/ Tong ino; ‘nuimero de nodo.i +/ char nameNAME.MAX+1]; /+ nombre + terminador \0' +/ ) Dirent; J* DIR minima: sin bs f= descrip J» la entrada del dizectorio «/ typedaf struct { Disent d; ) DIR: de archivo para el directorio +/ DIR opendir(char *dimnam Diront «readdiriDIR «dfa) struct stat dov_t mot short + muimero de ligas al archivo */ + id. de usuario del propi id. de grupo del propietanio200 La INTERFAZ DBL SISTENA UNIX cAPITULO #: La mayoria de estos valores son explicados por los campos de comentario. Los ‘tipos como dev_t y ino_testin definidos 2n , que también debe. ser incluido, La entrada st_mode contiene un conjinto de banderas que describen el ar- chivo. La definieién de banderas esta también incluida en ; slo re- querimos de la parte que tiene que ver con el tipo de archivo SIFMT 0160000 /+ SLIFDIR 0049000 ‘SIFCHR 0020000 ‘S.IFBLK 0060000 S.IFREG 0100000 especial de bloques «/ regalar */ 1a.con los argui n fsize, include #include ‘include “eysealls.b” #include #include include include “airent.b” ‘void fsize(cha: sanderas para lecture y escritura */ typedets «/ rructara regresada por stat +/ arge > 0) (+ ergy) return 0; La funcién fsize imprime el tamafo del archivo. Sin embargo, 65 un directorio, fsize llama primero a dirwalk para manejar todos en él. Note como se usan los nombres de las banderas SIFMT y S_IFDIR para decidir si el archivo es un directorio, El uso de los parentesis importa, debido a que la precedencia de & es inferior que la de = = int stat(char +, struct sta void dirwalk(char +, void ( 2) (char +); SEECION A EJEMPLO-LISTADO DE DIRECTORIOS 201 tiene acceso %s\n", name); retara; (etbuf mode & SIFMT) == $_IFDIR) ) = = NULL) { irwalk: no se puede abrir %s\n" 1@ ignora 2 si mismo y a su padre */ len{dp—>name) +2 > sizeof{name! frint(stders, “dirwallenombre 962/%e demasiado largo\n", dir, dp—>name); "M%a/%s", dir, dp—>name); closedir(ai);202 La INTEREAZ DEL SISTEMA UNIX caPrruLo g lamada a readdir regresa un apuntador a NULL. ormacion para el siguiente “ddigo es independierte de como esti el formato de los direc: © paso es presentar versiones minimas de opendir, readdir, y Lis sigui ‘#iindef DIRSIZ ‘define DIRSIZ. 14 Fondit struct direct _/ { not dino; char d_name[DIRSIZ); rnlmero de nodos */ los nombres largos no tienen \O'*/ h Algunas versiones del sistema permiten nombres mucho més largos y tienen una estructura de directorios més complicada, El tipo inot ¢s un typedef que describe al indice a la lista de nodos-i. En ema que usamos regularmente es un unsigned short, pero al de informacion para incluir en un programa; puede ser distinta en renie, de modo que typedef es mejor. Un juego comp! se encuentra en . que cs como stat excepto en que se ap aun descriptor de archivo), asigna una estructura de directorio, y graba la infor- macion, 4, struct opendir: abre un directorio pars lamadas de readdir «/ sopendin(char dirname) ' closedir ) readdir: EIEMPLO-LISTADO DE DIRECTORIOS 203 dp—>id = return dp; Js estructura local de directorio +/ Jee en secuencia las entradas de un directorio «/ Disent readdi(DIR +dp) 1 struct direct dirbuf; / estructura local de directorio */ static Dizent J regres while (zead(dp—>fd, (char *) & stmepy(d.name, d.name(DIRSIZ] = ‘\0'; rotum &d; roturn NULL; ue Ia represent que los programas,EJEMPLO-ASIGNADOR DE MEMORIA 208. captruto| SECCION 3.7 jin es que con cuidado s del sistema que a su vez ‘La liberacin ambien provoca una bitsqueda en ca i le esta siend | lugar apropiado para insertar el bloque que est yeraco es adyacente a un bloque libre en cualquiera de sus lados, n sloque iinico mas grande, por lo que el almacenami ‘agmenta demssiado. Determinar la adyacencia es facil puesto que I: wre es mantenida en orden ascendente de direcciones. Un problema, al que aludimos en el capftulo 5, es asegurar que el almacena- 8 obj para cada una que esta siendo macion contenida en la entrada del nodo-i, ista 8.7 Ejemplo—asignador de memoria ido que fu 1odo de pila. La version que escribiremos ahora no tiene restr ‘ma operativo para obiener més memoria cuando es lustran algunas de las consideracione: g0 dependiente de maquina en una forma re bign muestran una apl amente independiente, yt ones y typedef a la vida res arreglo precompilado de tamano jema operative cuando sea necesario, Dado que otras acti dades en el programa también pueden requerir espacio sin llamar a este dor, el espacio que malloc maneja puede ne ser contiguo. Asi, el espaci como una lista de bloques libres. Cada blogt contiene un tamaiio, un apuntador al siguiente blogue, y el espacio en si. Los bl ues son mantenidos en orden ascendente de direccién de almacenamiento, y liltimo bloque (direccién mas alta) apunta al primero. logra mediante wi deseada del encabezador y una oeurrencia d o, al que arbitrariamente hemos hecho long: typedef long Align; /* para alinoamiento al limite mayor +/ Js encabezador del bloque +/ sigulente blogue si esté e: lista bre tamano de esto bloqut J+ obliga a la alineaciéa de bloques +/ = aprosiage por malloc euro] en uso, aprpiado por malloc 10 apropisdo por malloc prapiado de unidades de amano del encabezad ene una unidad mas, para el encabezador cn si, apuntador es regresado por malloc apunta al esp: bezador io puede hacer cualquier cosa con el espacio reque ignado,206 LAINTERFAZ DEL SISTEMA UNIX carte ® apunta al seuiente blog 4 Tomato fog recon reread al usatio Un blogue restesado ror malloc 7 El campo[siaa] es necesario debido a que os bloques controlados por malo no iguos —no es posible caleulartamafios mediante aritmétea de iable bas se usa para comenvzar. Si freep es NULL, como lo es en I mada de malloc, entonces se crea una lista libre degenerada que co misma. En cualquier caso, luego se re de tamatio adecuado prine 10 bloque: esta estrate iado ers 3 le regresa la parte final; en esta forma el encabezador del origi ier ajustado su tamailo, En todos los casos, el apuntad uario apunta al espacio libre dentro del blogue, que prineipia un lt del encabezador. unidad mas. Header base; J» lista vacia para iniciar +/ static Header vfreep = NULL; [+ iniolo do una lista libre «/ {+ malloc: asignador de almacenamionto de propésito general «/ ‘void *malloc(unsigned nbyles) { Header «p, « prevp: Header rmoreco: ‘unsigned nu: units = (nbyies + siz grande */ if (p—>a.size = = auni provp—>s.ptr = p->sptr; secciON 87 EJEMPLO-ASIONADOR DE MEMORIA 207 freep = prove: return void +) (p+); ) f+ dio la vuelta a ta lista Libro «/ mada a malloc, asi que morecore sol que grande sera seccionado de acuerdo c campo size, morecore inserta la memor las ni adici llamada sbrk(n) al sistema UNIX regresa un apuntador an bytes mas de almacenamiento, sbrk ‘egresa -I si no hubo espacio, aunque NULL hubiera sido er comparados. Esto no es gat- permite la comparacion de apuntadores malloc ¢s portitil s6lo entre miquinas eral de apuntadores es si que la comparac ‘define NALLOC —1024—_/* minimo # de unidades por requerir */ J morecore: slicita més memoria al sistema +/ static Header smorecoro(unsigned { ‘char “ep, Header up: (au < NALLOO) nu = NALLOG; xy nada de espacio +/208 Ls INTERFAZ DEL SISTEMA UNIX carry SECCION 87 BJEMPLO-ASIGNADOR DE MEMORIA 209 pjercicio 8-8. Eserita una ruling bfreo(p,n) que libere un blogue arbitrario.p de n caracteres en Iz lista libre mantenida por malloc y free. Utilizando bi suario puede agregar un arreglo estatica o externo a la lista libre en cual ‘momento. Cl free es la tiltima seccion, Recorre la lista libre, iniciando en freep, busca donde insertar el bloque libre. Esto es En cualquier caso, si el bloque que esta siendo liberado adyacente a algiin vecino, los bloques adyacentes se combinan, Los uni problemas son mantener los apuntadores sehalando a las cosas ct tener los tamanos correctos. coloca ol bloque ap en la lita vacia */ (void ep) Header «bp, *p; 1 encaberador de un bloque Pid B= if (bp + bp—>s.size = = p—>s-ptr) | /+ une al abr superior «/ bp—>saite += p—>s.pt—>s.siz vane? PERE pant mee bp—>a.pte = po tr J+ ane al nbr inferior */ } Aunque la asignacién de memoria es intrinsecamente dependiente de la a, el iustra como pueden ser controladas las dependenci ma parte muy pequeia del programa. El uso Bjercicio 8-6. La funcién calloc(n,size) de la biblioteca estandar regresa Ul apuntador a n objetos de tamano size, con el almacenamiento inicalizado en ro, Eseriba calloc, invoeando a malloc o modificandola. © tado sin verificar la posibilidad crar contiene un campo det que sea vl maito correarenoice | Manual de referencia At. Introduecién Este manual describe al lenguaje C tal como se especifica en Draft Proposed American cl lenguaje. Ast pues, este manual isdn final del lenguaje, Mas aiin es una interpretacion del borrador nuesto del estndar, no el estandar en si, aunque se ha tenido euidado de hacerlo una confiable. mayor parte, este manual sigue la dor estindar, que asu vez sigue lade la primera edicion de ese libro, aunque la organizacin difiere em el detalle, Ex- cento por renombrar algunas produeciones y porque no se formalizan las definiciones de los componentes lexis o del preprocesador, la gramética dada aqui para el lenguaje es ccquvalente ala del borrador actual sateria comentado se encuentra sanarado y eseritoenun tipo mas pegueno, como éte. A menudo estos comentarios resale las formas eas ida ANSI de Cdifere del lenguae definido por la primera edcibn de iro, 0 de ena rodueidosposariorment en varios conpladores A2. Convenciones Iéxicas 1acrodefiniciones ¥ expansiones, Cuando el preprocesamien- de §A12 esta completo, el programa se ha reducido @ una secuencia de componentes lexicos, 42.1. Componentes léxicos (tokens) Existen seis eases de componentes léxicos:identificadores, palabras reservadas, cons- lanes, cadenas literaes, operadores y otros separadores. Los blancos, tabuladores ho~ Zontales ¥ vertivales, nueva linea, avance de forma y comentarios, como se deseriben 1 (en su conjunto, lamados “espacio en blanco") son ignorados, excepto las que au212 MANUAL DE REFERENCIA APENDICE 4 SPCCION Az ‘CONVENCIONES LEXICAS 213 constante-entera constanre-de-cardeter ‘constante-flotante ‘constan‘e-enumeracién caracteres /+_inician un comentario, que termina con los caracteres +/. Los coe jos no se anidan y no pueden estar dentro de cadenas 0 caracteres literals, 82.5.1 Constantes enteras © F con valores 10 al 15. Una constante entera puede tener la letra u o U como sufijo, lo cual especifica que es unsigned. También puede tener como sufi la letra 1 0 L para estipular que es long. El tipo de una constants entera depende de su forma, valor y sufijo (véase $A para uns suficientemente grandes para alm en ejecucién. Si un eardcter gem lores equivalente al edigo en arreglos de objetos de un tipo dado; “funciones que regresin objetos de un tipo dado; ‘apuntadores a objetcs de un tipo dado; cenar cualquier miembeo del canjunto de ca de ese conjunto se almacena en un objeto char, ddeclaran signed char toman igualmente ‘que los caracteres sencills. ‘unsigned char no aparece en I primera edicibn de este libro, pero es de ws0 co ‘mun. signed char es nueva. AS Objetos y valores-1 Un objeto es una regién de almacenamiento con nombre; un dectarados mediante la palabra reservada unsign iumética médulo 2" donde m es el niimero de bits expresion valo de la expres BZ en la que el operador izquierdo £1 debe ser una ‘expresion valor—I. La dicusién de cada operador especifica si espera operandos valor si entroga un valor-L A6., Conversiones Algunos operadores 7 wdiendo de sus operandos, provocar Ia conversién del218 MANUAL DE REFERENCIA APENDICE A todos con o sin signo, 6 un x dentro de wna expresién en cualquier lugar puede rzpresentar a todos los valores del tipo. a manera el valor es convertido a un Este proceso se llama prom A6.2 Conversiones enteras Un entero se converte un tipo sn sino dado encontrand et menor valor no negativg ‘que el mayor valor que se pueda repre: sentar en el tipo sin signo. En una representaciOn complemento a dos, esto es equivalente al truncamiento por la izquierda si el patrén de bits el tipo sin signo es mas estrec Ienado con eros de valores sin signo y extensién de signo en valores con signo si present siguiente més alto 0 mas indefinido, A6.4 Tipos flotantes Cuando un. €iso, el valor no se m Flotance menos pre lor Flotante menos preciso se convistte a un tipo flotant ‘Cuando un valor flotante més preciso se 30, y el valor esté dentro del rango representable, el resultado pued ble mas alto o el siguiente mis bajo. Si el resultado es {era de rango, el comportamieno estéindfinida antes en forma jemel tipo del SECCION A6 CONVERSIONES 219 ‘De otra manera, siun cperando es long int y el otro es unsigned int, el efecto depende de si un long int puede representar a todos los valores de un unsigned int; si es asi, int es convertido a long int; si no lo es, ambos son convertids 5 convertide a lon lotto es convert Finalmente, un apuntacor a una funcidn se puede convertir a un apuntador a otto tipo 4e Funcién. La llamada a funcién especificada por el apuntador convertido es depen-220 MANUAL. DE REFERENCIA APENDICE 4) sin embargo, si el apuntador convertido es reconvertido a su, lo es idéntico al apurtador original. no void. Debido a que la F donde no sea requerida el (§A9.2) 0 el operando izquierdo de un plo, una conversién lel valor de una llamada a funcién utilizada fanaionesy rlacioney nintas que re ‘apuntadores. AT. Expresiones ‘La precedencia de los operadores en expresienes es la misma que el orden siones principales de esta seecin, primero la mas alta precedencia. Asi, sa las que se hace refer tividad de los operadcres estéespecificada completamente, ion de las epresiones est, cov ciertas excepxiones, indefinido, ain si wolucran efectos colaterales. Eso es, a menos que la definicién de un ops opera combina lo: valores producidos por sus operandos luna forma compatible con el and is gramatical de la expresin en que aparece EXPRESIONES 221 SECCION A entonces el valor de dela expresin es iecisinieacamne A tata un operador de asgnasin 0 "el operador. estas conversiones no es valor A7.2 Expresiones primarias idenificador consante lendo la regla dada en 847.1, usualmente se mo (wehar_t) y do es lun apuntador al primer carécter de la cadena. La conversién tampoco ocurre en ciertos inicializadores; véase (8.7.(wari mente, se usan algunas aracion para ky joel paso de argumenios es estrictamente por valor. Una funcién puede cambiat los va- res de sus objetos pardmetros, que son copias de las expresiones argumentos, pero estos ‘es posible pasar to de que la funcién puede cambiar el valor del objeto al A7.3 Expresiones postijas ro) formal” respect 1 se agrupan de izquierda a derecha, Lexpresion } lista-de-expresiones-argument0y) identifieador => identificacor lista-expresiones-argumento: expresién-de-asignacién : sta-expresiones-argumento , expresin-de-asignacisn i AT.3.1 Referencias a arreglos aque denota una referencia indexada a ipo “apuntador a 7”, donde T es agin tipo, ipo de la expresién subindice es 7, La expresion £1[E2] es idéntica (por definicién) a posfija (después de una posible declaracion im A7.1) debe ser del tipo “apuntador a funcién que regresa 7”, el valor de la Yamada a la funcién por una definicién de funcién o descrito dentro de la declaracién de una funcién. LosSBcCION a7 EXPRESIONES 225 224 MANUAL DE REFERENCIA APENDICE A, A7.4.2 Operador de dreccién El operador unario atoms la direcci6n de su operando, El operando debe ser el va- obj no register, 0 )bjeto 0 funcién al que se reflere es “apuntador a 7”, po de bits ni a resultado es un apuntador sando es T, el tipo del una estructura o una uniéa yl ientfcador debe nombrar a un mlembey ructura o unién. El resultad AT.4.3 Operador de Inireccién El operador unario + enota indireceiin y regresa el objeto 0 ‘expresién E1~>MOS es lo mismo que (+E1).MOS, Las estrueturas y uniones fen en §A8.3, tunién o apunador. Si el tipo de la expresion es un “apuntador a 7”, el resultado es T. a | 7.4.4 Operador més nario El operando del operalor unario + debe tener tipo f salor del opersila. Un operando entero sufre prom resultado es el tipo del oerando prom B+ tmético o apuntador y el resulta entera, Eltipo det A7.3.4 Incrementos postijos Una expresion post seguida de un operador + + 0 -— del operando, Desputs de us |. El operand AT.4.5 Operador mencs unatio El operador del ~ untio debe tener tipo aritmético y el resultado es el negativo de su jo. Un operandventero sufte promocion entera. El negativo de una cantidad in signo se calcula restaido el valor promovido del mayor valor del tipo promovido y agregindole uno; pero elero negativo es cero. El tipo del resultado es el tipo del operando romovido. las discusién de operadores aditv. : restriceiones en el operando y detalles de la operaci6n. El resultado no es un valor. 7) de asignacién (8 A7.4 Operadores unarios Las expresiones con operadores unarios se agrupan de derecha a izquierda. 7.4.8 Operador comsemento a uno expresion-unaria; expresién-posfiia ‘++ expresin-unaria == expresién-unaria operador-unario expresin-cast sizeof expresidn-unaria sizeof (nombre-de-ipo) ‘operador-unario: uno de és + --t 7.4.1 Operadores prefijos de incremento ‘Una expresién unaria precedida por un operalor ++ 0 ~~ es una exp (© decrementa (-—) en 1. El valor de la ex 7.4.8 Operador sizeot El operador sizeof preluce el nimero de bytes requeridos para almacenar un objeto 4e| tipo de su operando. H opperando es una expresién, que no es evaluada, 0 un nombre226 MANUAL DE REFERENCIA APENDICE| dle tipo entre paréntesis. Cuando sizeof se aplicaa char, el resultado es 1; cuando se aplig aun arreglo, ef resultado es el mimero total de bytes en el arreglo. Cuando se aplica a un . bytes en el objeto, incluyendo cuala ‘un arrealo: eltamano dk ATS Cast Una expresion unaria precedida por el nombre entre paréntesis de un tipe provoca conversién del valor de la expresién al tipo nombrado.. expresién-cast: expresién-unaria (nombre-de-tipo ) expresién-cast da). Los nombres de tipo se deseriben en er §A6. Una expresion con un cas? no es un J expresion-cast iva % expresion-cast Los operandos de * y / deben tener tipo aritnético; los operandos de % deben tem 0, Las conversiones aritmétieas usuales se realizan sobre los operandos, y realizan las conversiones aritméticas usuales, Existen algunas PO pos para cada operador SECCION A? EXPRESIONES 227 expresidn-aditiva: expresién-muliplicativa expresion-aditiva + expresién-multiplicativa cexpresién-aditiva ~ expresién.m tva do del operador + es la suma de los ope al que el apuntador apunta, La suma es un apuntador del mismo tipo que el apuntador original y apunta a otra objeto dentro del mismo arreglo, desplazado apropiadamente del ‘objeto original. Asi, si es un apuntador a un objeto en un arreglo, la expresién P + 1 tun apuntador al siguiente objeto en el arreslo. de Ios limites del arreglo, excepto a la primera lo ¢s indefinido, resultado del operador ~ es [a o entero se puede resar de un apunt nes que para la ad A7.8 Operadores de corrimiento Los operadores de torrimiento << y >> se agrupan de izquierda a derecha. Para peradores, cada operando debe ser entero y El tino del resultado es el del operando promovido de la izquierda. El opeando dela derecha es negativ, mayor o igual al numero de bts el tipo de la expresir de la izquierda. expresién-descorrimiento: expresin-adit expresién-de.corrimiento << expresidn-aditiva b)co, y ach se evalia como 0 o como I dad, acb expresidn-de-corrimiento <= expresién-descorrimiento P apunta al ditimo niembro de un arreglo, entonces P+ 1. a como mayor que P, incluso aunque P+1 apunte fuera del arreglo. De otra ‘manera, la comparacién de apuntadores esté - liza comparscién con un apunaorjusio mas AT.10 Operadores de igualdad expresién-de-igualdad: expresién-relacional expresién-de-igualdad == expresién-relacional expresién-de-igualdad |= expresién-relacional (no igual a) so1 andlogos a los operadores de relacién cedencia, (Asfacb == e tamano y existen, ave nisiizaor para una estructura eso une expresin del mismo por lo que lementos de sma forma los siguientes liza a primera columna de y (considerado como un arreglo bidimensional) y deja al to en 0, Finalmente, char msg{) = “Error de sintaxis on linea s\n"; teal amplio $2.6) puede inicializar un arreglo de wohar.*, Sil arreglo tiene tamano desconocid, el niimero de caracteres en Ia cadena, i244 MANUAL DE REFERENCIA APENDICE 4, SBCCION Av PROPOSICIONES 245 cteres cuyos miembros son inicalizadas con una cadena; su ta- exc clenpie ecu nulo de terminaciéa typedef long Blockno, +Blockptrs typedef struct { double r, theta; } Complex; las construcciones Blockso bs a tipos que se podrian smo tipo que cualquier otro objeto fe un alcance més interno, pero se lino. Por ejemplo, ‘apuntador Spuntadorg dectarador-absracto-directo declarador-abstracto-dir ( declarador abstract debe dar un conjunto no vacfo de especificadores extern Blockno; no redeclara a Blockno, pero extern int Blockno; si To hace. 8.10 Equivalencia de tipo jcadores de pardmetros de le tipo. Los tamafios de luna un entero” 48.9 Typedet Las declaraciones cuyo especficado: } art wo} + No ocurre ningin oto reemplazo. ‘Las secuenciastrigrdficas son nuevas en el estindar ANS. ‘A12.2 Unién de lireas inan con el cardcter diagonal en tokens.254° MANUAL DE REPERENCIA APENDICE A AY2.3 Definicién y expansién de macros Una linea de control de la forma # define identificador secuencia-de-tokens tancias subsecuentes del Secuencia de fokens dada; se descarian los espacio en blanco que de la secuencia de rokens. Un segundo # define sara el eeunda secuencia de sokens sea idént ‘spacios en blanco se consideran equivalentes, ‘Una linea de la forma *# dotine identificador ( listade-devtficadores ) secuencia-de-tokens dona no hay espacio en blanco entre el primer identificador ye (, es una macrodefinicién macro puede rémetros y inea de control de la forma # undef identificador hace aue cl preprocesador olvide la definicién del ide ‘car #undef a un identificador desconocido, 18 definido en la segunda form: rancias jor de lam pacio en blanco aptat radios por comas; las comas ‘comillas o protepidas por paréntesis anidados no separan argu. mn, se remueven los espacios en blanco que los p lye la secuencia de rokensresultante de cada argume lada del identificacor del parémetzo correspondiente ‘eeuensia de reemplazo de cakens de la macro. A menos de que el pardmetroen a svc oe eemplazo esté precedido por #,o precedido o examinan para macrollamadas y se expanclen com, Dos operadores especiales influyen sobre el rrencia de un para ‘mente por #, se col tanto el # como el i den de procesamiento de os operadores #1. Adi io 0 fin de una secuencia de rokens de reemplazo, PREPROCESAMIENTO 255 SEOCION A12 embargo, una ver soe en eee ae tuna directiva de preprocesamiento. Los detaes del proceso de la macroexpansin se describen en form: as, especialmente as Tos ejemplos siguientes.) Por ejemplo, esto se puede #aefine TARSIZE int table(TABSIzi La definicién #4efine ABSDIFF(a, b) ( fine una macro que mgresa el ‘A diferencia de la funcién que hace pueden 1 colaterales son evaluados os veces, una para la prucba y otra para pro: duct et valor. Dada la definicién #define tempfile(dir) #air "/%s" | macrollamada tempfie(/ust/tmp) entrega “yasr/tmp" "Vx que posteriormente se concatenard como una cadena sencilla. Después de #3efine cate, y) »soken del primer argumento con el primer token del segundo) foduce un segundo nivel de macrodefinicion, y)3 (a unién ‘no es un roken legal. Sise #aefine xcat(x,y) cat(x, las ona rabajan ms savemente; x ) produce 123, debido a qu a x- ion de wat ens no vor iz En la misma forma, ABSDIFF(ABSDIFI completamente expandito. produce lo esperado, un resultado286 MANUAL DE REFERENCIA APENDICE 4 12.4 Inclusion de archivos Una linea de control de la forma # include ‘casiona el reemplazo de esa linea por el contenido completo del archivo nombre-de. archivo. Los caracteres del nombre nombre-de-erchivo no deben incluir > 0 nueva linea i nombrado se busca en # include “nombre-de-archivo” €l archivo fiente original (fase deliberadamente de al bsqued 12.5 Compilacién condicional rte de un programa se pueden compilar condicionalmente, de acuerdo con la sigui taxis esquematica, ‘preprocesador-condicional; Uinea-if texto partes-elif parterlsey, #onast Iinea-if: *# if expresion-constante # ildot identificade # inde! identificador artes-lif: linew-elif texto Partes-llfy, Unea-etif # elif expresién-constante Cada una de las directivas (linewif,lnea-elif,Unea-lse, y Wendi aparece sola en una ‘ca. Las expresiones constantes que estén en #if j posteriores lineas weld se evalian eT SSECCION At2 PREPROCESAMIENTO 257 mn consante en #if y #elif esté sujeta a macroreemplazo ordinario. Ade- mas, cualesquier expresiones de la forma defined dentificador etined ( identificador ) se roemplazan, antes de busear macros, por IL si el identificador esta definido en el preprocesador y por OL sino lo esté, Cual reamplazan por OL. ‘#ilndel dentficador son equivalentes a if detized identificador # if | delined identificador ee ‘eli es nueva desde la primera edicién aunque ha estado disponible en algunos onocanior El opeador ened Gl reposeacor mmbn © mst. 12.6 Control de linea Para beneficio de otros preprocesadores que generan programas en C, ui de las formas288 MANUAL DE REFERENCIA APENDICE A, ‘A12.7 Generacién de errores ‘Une linea del preprocesador de la forma # ontor secuencla-de-tokensiy ‘casiona que el preprocesador escriba un mensaje de diagnéstico que incluye la secuencia de tokens A12.8 Pragmas Una linea de control de la forma # pragma secuencia-de-tokens, 1a que el preprocesad no reconocida es ignarado, aceién que depende de la implantacién, Un 412.9 Directiva nula ‘Una linea del preprocesador de la forma * no tiene efecto. A12.10 Nombres predefinidos Varios identificadores estén predefinidos, y se expanden para producir informacién es- ios ni el operador de expresion del preprocesador defined, pueden estar sin ion 0 redefinidos, LINE__ ~-PILE__ sta compi- --DATE__ en la forma “Mmm dd aga", TIME Cadena literal que cont ma Coen S100. Lacon an el Dreprocesador son nuevas, pero algunas de ells han estado disponibles en alge as implantacions, Ai, Gramética ‘A continuacién se encuentra una recapitulaciér dela gramatica expuesta a lo largo de ‘a primera parte de este apéndice, Tiene exactamente el mismo contenido, pero se encuet- tra en diferente orden, -~ SECCION As ORAMATICA 259 rador de parsers YACC por la ambiguedad di uunidad-de-traduecin decleracién-externa unidad-de-traduccidn declaracién-externa declaracin-externa: definicién-de-funcion declracién definicidnde-funcion: especificadoresde-declaracin, declarador lista-de-declaracionessy, especifeadores-de-dectaracién lista-dectaradores lista-de-declaraciones: declaracion lista-te-declaraciones declaracién especificatores-de-deciaracién. ‘especificador-categorla-aimacenamiento especificadores-de- decloracinye icador-de-tipo especificadores-de-declaracidyy, voié char short int long float double signed unsigned _especificador-estructura-uniéon espedficador-enum nombresypedef califcado:-detipo: une de const volatile especificadoresiructura-o-uni260 MANUAL DE REFERENCIA lista-declaradores-init, declarador-init Inicializador specificador ksta-declaradores-struct ; lfieador-especificador is ta-calificator-especificador ay uct, deelarador-struct ectarador x : expresién-constante especificador-enum: rap {lista deenumerador } Uista-de-enumerador , enumerator enumerador: identificador for = expresidn-constante ‘apuntadory, declarador-directo lista-de-pardmetros: declaracién-pardmetro lista-de-pardmetros , declaracién-pardmetro declaracién-parémetro: especificadores-de-dectaracién dectarador especificadores-de-declaracidn declarador-abstractOag, lista-de-identifieadores: ‘dentificador APENDICE a, gaa al GRAMATICA 261 identifieadores . identifieador declarador-asstracio: caso expresin-conslane : proposicién default propasicid propasleliectereiant expresiony proposicin-compuesta list delaracig ist-de propsiciones ‘sta de-propasiciones: proposes Usta-de-proposiciones proposicién ‘proposicion-ée-seleccién. if ( expresin ) proposicion262 MANUAL DE REFERENCIA APENDICE a SECCION AL GRAMATICA 263 break : return expresinyy $ expresién: expresién-de-asignacién expresion , expresin-de-asignacién expresién-de-asignacin: -condicional unaria operador-de-asignacin expresién-de-asignacién ‘operador-de-asignacidn: uno de i" soe fe Me oe ns dee oe Be Tete licativa * expresion-cast 2 esresion-unaria operetorsnaro expresén-ast co-OR 7 expresion: exprestén-condcional eed expresionsmaria sizeol ( nombre-de-tipo ) perador- mario uo de ri ea. OR 1 expres expreiin gla: ‘xpresion OR ncusvo expres lipo AND 88. esprit. OR inchsvo expen OR inchs presin OR exsvo expresién OR ncnsvo | expreion OR excasvo expresion OR exchro exretingrimaria ipreién-AND deni ador xpresn-ORceschsvo* expreion AND contante exresion-AND. Cadera cxprestin de ual expres AND & expresin-deigualdad expresién-relacional expresién-de-igualdad =x expresién-relacional expresién-de-igualdad 1" expresién-relacional expresién-relacional < expresin-de-corrimiento > expresion-de-corrimiento <= expresién-de-corrimiento expresion-multiplicativa264 MANUAL DE REFERENCIA APENDICE A # Une constante “nombre-de-erchivo” # line constante apenoice 8: Biblioteca estandar expresién-constante # ifdef identificador # iindel identificador partes-lif: linea elif texto i Uinea-elif: # elif expresién-constante Las funciones, tipes y macros de la biblioteca esténdar estén declarados en headers es- tindar: Se puede tener acceso a un header por medio de #include Los headers se pueden ineluir en cualquier orden y numero de veces. un header se debe imcluir fuera de cualquier declaracién 0 d ‘guier cosa que declare, No es necesar Los identificadoresexternos que principian con subguién estén reservados para uso de teca, como fo stn todos los otros identificadores que principian con un subguidn y tna letra maytiscula u otro subguién, 1. Entrada y salida: Las funciones, tipos y macros de entrada y salida, definidos en , represen- rera parte de la biblioteca.266. 1BLIOTECA ESTANDAR APENDICE B se conecta aun archivo 0 di ir un archivo regresa un apuntador a un objeto de tipo FILE, que es sobre archivos, Eline size_t es el tino foducido por el operador sizeot. FILE *fopen(const char *filename, const char +node) archivo nombrado, y regresa un-flujo, o NULL si falla el 10s de mode ineluyen contenido previo si bre o crea un archivo para escribir al final "ze" abre archivo para actualizacion (esto es, lectura o escritura) "crea archivo de texto para actaizacién; descarta cualquier conteni= do previo si existe as" agrega; abre o crea archivo de texto para actualizacién, eseribiendo al final tra del mismo archivo; entre una de posicién o viceversa. indica que [NULL si ocurre un erro. freopen normalmete se usa para cambiar los archi- vos asociados con stdin, stdout 0 stderr. int fflush(FILE +stream) SECCION BL ENTRADA Y SALIDA — 267 4o, © NULL si no puede erear el archivo, char *tmpnam(char s{L_tapnam]) ‘tmpnam(NULL) crea una cadena que no es el nombre de un archivo existentey regres ‘un apuntador aun arresloestatico inter imacena la cadena en sy tam- i lor de la Funci6 ue tmpnam efea un nombre, no un archivo, stream, char buf, int mods void setbuf(PILE «stream, char +but) Si buf es NULL, se suspende el uso de buffer para el ujo. De otra manera, eetbuf es equivalente a (void! setvbuf (stream, buf, _TOFBP, BUFSIZ). 1.2 Salida con formato Las funciones printf proporcionan conversiones de salida con formato. int fprint€(PILE +stream, const char *format, . ila y la convierte y escribe hack es el mtimero de caracteres es format. El valor ret sri6 algiin error. La cadena de formatocontiene dos tipos de objetos: caracteres or sera cero, Para x 0%, cual268 BIBLIOTECA ESTANDAR ‘que esipula el mimero mximo de caracteres de una cadena que serén 'nimero de digits que sen impreso:desputs del punto desimal para conversiones rimero de digtossgnifien!+0s para conversiones g 0 G, o el nlmero minimo de Agios que sen impresos para un entero (serén aregados ceros al principio para complear el an- ‘cho de campo necesari). indica que el srgumento correspondiente va indica que el argumento es long 0 unsigned Indica que Con * se puede especi ud o precisiGn, o ambas, ental caso el valor se calcula argumento(s), que debe(a) ser int Los caracteres de conversion y sus significados se muestran en la tabla B-1. Sielcardcter ‘que est después del % no es un earicter de conversion, el comportamiento est indefinido, ‘TABLA B-I. CONVERSIONES DE PRINTF son impresos hasta que se alcanza un ‘numero de caracteres indicados por la ee aG SECCION 81 ENTRADA Y SALIDA 269 Ant printé(cons: char *format, ...) printé(,..) ¢s eqivalente a fprintf(stdout.) int eprinti(char #2, const char +fornat, so mismo que printf excepto que la salida es con \O'.s debe ser suficientemente grande para contener sada no incluye d "\0 resultado, La cuenta regre vprint£(const ciar «format, va_list arg) veprint£(PILE «stream, const char +fornat, va_list arg) vsprintf(char #s, const char *format, va_list arg) ‘Las funciones vpuinti, ,y vepeintf son equivalentes a las ,exerpto que la lista variable de argumentos es remplazada vado por la macro va.start y tal vez llamadas a cidn de en la seccidn BY. arg, que arg. Véase la exposi- B1.3 Entrada con formato Las funciones scant tratan con la conversién de entrada con formato. int fscanf (PILE «stream, const char *format, {scant lee del stresm bajo el control de format, y signa los valores convertidos a través de argumentos subseeuentes, cada uno de las cuales debe ser wn apuntador. Regresa cuan- do format se ha agotsdo. facanf regresa EOF si se encuentra fin de archivo o un error antes ‘de la conversin; de otra forma regresa el nimero de articulos de entrada convertidos y asignadas, La cadena de fornato generalmente contiene especificaciones de conversién, que son ia interpretacion de la entrada, La cadena de formato puede contener Una especificacién de conversién determina la conversin del sigui trada, Normalmente el resultado es situado en la variable apuntada po ‘campo de entrada sinplemente se salta; no se hace asignacion. Un campo de definido por una cadena de caracteres diferentes de espacio en blanco; se extiende i que el ancho pacio en blanco son blanco, de tinea.) El caracter de conversién indica Ia interpretacion del campo de er jespondiente debe ser un apuntador. Los caracteres de conver abla B-2, Los caracteres de conversion dy i, ‘mento es un apuntacor a short en ver d tador @ long. Los caracteres de conve210 BIBLIOTECA ESTANDAR APENDICE B la fa de rgumentos hay un aputador a double yn a loa, y pr sha a long double. a : TaBLA B-2. CONVERSIONES DE SCANF DATO DE ENTRADA; TIPO DE ARGUNENTO eka El formato de entrada para los float es blemente con un punto deci -seguida posiblemente Pp ‘convertidos no se inerementa [el | coincide con la mayor cadena no vacis de caracteres de entrada del conjunto : entre corchetes; char *. Se agroga un’\0\ Pad ide con la mayor cadena no vacia de caracteres de entrada que no sean del conjunto entre corchetes; char *. Se agrega un ‘\O'.['.~]incluye } ‘el conjunto. % no se hace ninguna asignaciéa, int scanf(const char sformat, ...) Scang(...) es idéntica a Escang(etdin,.-) int sscanf(ehar *s, const char efornat, ...) sscant{s,...) es equivalente a scanf(..) excepto 4 dos de ta eadena s. 1.4 Funciones de entrada y salida de caracteres int fgete( FILE +etream) ‘egresa el siguiente cardcter de stream como unsigned char (convertido a un EOF si se encontré el fin de archivo o ua erro. SECCION BI ENTRADA Y SALIDA 271 char sfgets(char +s, int n, FILE «stream) fgets lee hast tes n—1 caracteres en el arreplo s, det ete es equivalencea {gete excepto que si es una macro, puede evaluar a stream més de una ver. int getchar(void) getchar es equivalente a gete( stain) char *gets(char +s) ‘gots ee la siguiente linea de entrada y la deja en el arreglo #3 reemplaza cl cardcter nueva linea final con NO". Regresa s, 0 NULL si ocurre fin de archivo o error. int pute(int ¢, FILE estream) pute es equivalentea fpule excepto 4) de una vez cs una macro, puede evaluar a stream més int putchar(int ©) putchar(c) es equivalente @ pute(e, stdout) int puts (const ctar +s) ‘ibe la cadeva s ¥ un nueva linea a stdout. Regresa EOF si ocurre un error, de no negati int ungetc(int c, PILE sstream) lungete regresa c (convertido en unsigned chaz) de nuevo al stream, de donde seré regresado en la préxima lectura, Sélo se garantiza un cardcter de regreso por flujo. EOF no puede ser regresado, ungete devuelve el cardcter regresado, 0 EOF en caso de error, B1.5 Funciones de entrada y salida directa izet size, size_t nobj, PILE «stream) ‘py hasta nobj objetos de tamafo size. fread regresa ‘esto puede ser menor que el niimero solicitado. Para deter- ¢ feot y ferzor. size_t fwrite(const void +ptr, size_t size, size_t nobj, FILE +stream) scribe, del srreslo ptr, nobj ob) de objeto ue es menor size_t fread(voic sptr, famanos size en stream. Devuelve el bj en caso de error.272 BIBLIOTECA ESTANDAR APENDICE B1.6 Funciones de colocacién en archivos t, int origin) represado por fel (ental caso origin debe ser SEEK” fseek regresa un valor diferente de cero en caso de error. Jong ftell(FILE +stream) regresa la posicién actual de stream en el archivo, © IL en caso de error. void rewind(PILE +stream) xewind(fp) es equivalente a fseek(fp,OL, SEEK SET); clearer). int fgetpos (PILE «stream, fpos_t «ptr) fgetpos graba en ptr la posicion aciual de stream, para uso posterior de fsetpos, ELtipo fpos.tes adecuado para grabar tales valores, fgetpos regresa un valor diferente de cero en caso de error. int fsetpos(PILE «stream, const fpos_: +ptr) ‘arabada en «ptr por Sgetpos. En caso de error, tun valor diferente de cero, B1.7 Funciones de error i biblioteca activan indicadores de estado cuando ocurre un error ferror regresa un valor diferente de cero si estd encendido el indicador de error de stream, void per’ fprintf(stderr, Ver strerror en la seccién B3 + "mensaje de error ) 2, Pruebas de clasificacién de caracterss: El header declara funciones para la prueba de caracteres. Para cada fun- ign, el argumento es un int euyo valor debe ser EOF o representable por un unsigned char, y el valor de retorno es un int. Las funciones regresan diferente de cero (verdadero) si el argumento e satisface la condicion deserita, y cero sino lo hace. r isprint(c) ispunct (c) Asspace(c) Asupper(c) isxdigit( int tolower(int ¢) int toupper(int ©) Sie es una letra maytse caso rearesa ©. Sic es may char *strepy(s,ct) char +strncpy(s,ct,n) char setzcat(s,ct) char +etencat: int stremp(es,ct) int strnemp(cs,ct,n) char sstrehr(cs,e) char sstrrehe(es,¢) 3s funciones que convierten FUNCIONES PARA CADENAS: 273 Asdigit(e) es verdadera lower (e) es verdadera ter de impresién excepto espacio letra mimiscula ‘maytiscula res de impresién son de 0x20 8 0x1P (US) y 0x7 (DEL). convierte ¢ a mimiscula convierte © a mayiscula s, terminando con "\0'; regresas. compara la cadena es con la cadena ot; regresa <0 si cscct, 0si ces=ct, 0 >0 if carct. dena es con la cadena 0 >Osiesrct, cia dee en es, ia dee en 5,0 NULL si no est presente274 BIBLIOTECA ESTANDAR APENDICE & regresa la longited del prefiio de es que consiste en las ea. racteres en ct size_t strspnice,ct) size_t strespn(cs,ct) la primera ocurrencia en la cadena dela cadena ct, o NULL si ning. char +stepbrie(cs,ct) char sstestr(oe,ct) size_t strlenics) char estrerror(n) Plantacion, correspondiente al error m. striok busca en sokens del char tatrtok(s,ct) ape ya no encuentra tokens. La cadena et 8 manipular objetos como arreglos de caracte- En [a siguiente tabla, sy ¢ io size.t; y ces un intcon- oa unsigned char. void smemcpy(s,ct,n) copia m caracteres de ct a s, y regresas. void smenmove(s,ct,n) lo mismo que memepy excepto que funciona aun si los dobjetos se traslapan ‘compara los prineros n caracteres de ot con ct; regresa Jo mismo que stremp. regresa un apuntedor a Ant menemp(cs,ct,n) void smenehr(es,e,n) ens, o NULLsi no esté presente entre los primeros m cearacteres. void emenset(s,c,n) _coloca el caracter een los primeros m caracteres de 8, Fe gresa s. B4. Funciones mateméticas: ‘n> declara funciones y macros mateméticas. 'y ERANGE (que se encuentran en ) son constantes eh i FUNCIONES DE UTILERIA: 275 SBCCION Bs Los ngulos para las funciones seno de x ‘coseno de x tangeate de x sin"! @) en el rango [—x/2, #/2), tangerte hiperbsl funeién exponenci logaritmo nat logaritmo base 10 tog,9 2. Ocurre un error de dominio Si x=0 y y<0, 0 $1x<0 yy no es un en. ero. vx, x30, ‘menor entero no menor frexplx, int sexp) divide x en una fraccién normalizada dentro del intervalo (1/2, 1], que se regres, y una potencia de 2, que se almacena en exp. Sixes cero, ambas partes del resultado son cero. nod£(x, double ip) declara funciones para conversién num areas semejantes asignacion de me: atof (const char +s) f convierte # a double; es equivalente a strtoa| + (ohare ULL).276 RIBLIOTECA ESTANDAR APENDICE B int atoi (const char +s) convierte # a int; es equivalente a (int) stetol(s, (char+#)NULL, 10). lea strtol(s, (chares)NULL, lerror es ULONG_MAX. int rand(voia) aud devuelve un entero pseudoaleatorio en el rango deO a RAND_MAX, que es al me- nos 32767, void scalloc(size_t no! calloe devuelve un apuntador tamano size, 0 NULL sila sol bytes con cet, ize_t size) cio para un arreglo de nobj abjetos, cada uno de ‘ho puede saisfacerse. El espacio se incializa a void smalloc(size t size) malloc regresa un apuntador al espacio para un objeto de tamafio size, o NULL sila Solicitud no se puede satisfacer. El espacio no se inicaliza, void srealloc(void +p, size_t size) 9 NULLS — SECCION Bs FUNCIONES PARA UTILERIA: 277 void free(votd +p void sbsearen(const void «key, const void ebase, size t n, eizet size apuntador al element void qsort (void sbas int abs(int n) ‘abs regresa el valor absoluto de su argumento int long labs(1ong a) labe regresa el valor absoluta de su fados se almacenan en los divs Jos son almacenados 9 18a.278 BIBLIOTECA ESTANDAR APENDICE B BG. Diagnésticos: La macro assert es usada para agregar diagnistices a los programas: void assert (int expresién) Si expresién es cero cuando assert (etpresifn) macro assert imprimird en stderr in mensaje, como fertion failed: expresién, file filename, line nnn ia ejecucién. El archivo fuente filename y cl niimero _-LTIB__ del preprocesador. luyo se jgnora la macro astert B7. Listas de argumentos variables: El header proporciona recursos para recorrer una lista de argumentos de funciSn de tamato y tipo desconacido, ‘Supéngase que imo pardmetro 1ombrado de une funcién { con un nic dentro de € una variable ap de tipa ap se debe inicializar una vez con la macro va list antes de tener acceso a cualquier argu- ‘mento no nombrado: + lastare én de la macro va.a:g product igulente argument no nombrado, y mo« uso de va_arg devuelva el argumemo siguient iype va_arg\va_list ap, (pel; La macro void va_end(va_list ap); gue tiene el tipo también ap de modo que y sdlo en ex ja aqui en wna llamada d SECCION Be SERALES: 279 Tega aqui por una llamada de longimp */ void longjap(Jap_buf env, int val) de facilidades para manejar condiciones excepcionales que durante la eecucién, tal como una sefial de interrupcién de una fuente externa un error en la ejecucin, SIGILL SIGINT SIGSEGV SIGTERM signal regresael valor previo de handler para la seal especiica, 0 S¥G=ERR si ocurre un280 BIBLIOTECA ESTANDAR APENDICE B int tm_secs int tmmin; sty negativa le provesador empieado por el programa desde el inicio de su td disponible. elock{ }/2LK_7CK es el tiempo en segundos. time t time(timet *tp) lime regresa la fecha y hora actual del calendar, 0-1 si no esta disponible. Si tpno 8 NULL, el valor de retorno también es asignato a +tp. double 4ifftime(time_t time2, time t time dititime regresa time?-timel expresado en seguris, time t mktime(struct tm +tp) sma representaciin de los rangos mostrados, mktime regresala fecha y hora del lecaltime size.t strftime(char +s, size_t smax, const char «fmt, const struct tm «tp) SECCION Bit : piados del entorno. Ens no se colocan mis de smax caracteres. stftime regresa el mimero de caracteres, excluyendo el | caracteres Say BF BRFRE BEE ‘UINT_MAX LIMITES DEFINIDOS EN LA IMPLANTACION 281 © cero si fueron producidos mas de smax breviado del dia de Ta semana. cequivdlencia local de AM 0 PM. segundos (00-55). rnimero de semana del afto (domingo es el primer dia de la semana) 00.59). dia dela semana (0-6, domingo es 0). rimero de semana del afto (lunes es el primer dia de la semana) (00-59. represntacin local de la fecha. represntacion local de Ia hora. afto sin el siglo (00-98). valor méximo de char valor minimo de char valor maximo de int © or SCHAR_MIN #32767 32767 minimo de int 421474836470 maximo de long 21474036470 ‘minimo de long +127 maximo de signed char =127 inimo de signed char 432767 smiximo de short 32767 valor minlmo de short 2550 valor méximo de unsigned char 655350 valor maximo de unsigned int282 BIBLIOTECA FSTANDAR vLoNG_Max ‘USHRT_MAX 4294967295uL 655350 valor maximo de unsigned short PLT_RADIX PLT_ROUNDS PLT_OIG FLT_EPSILON FLT MANT DIG FLT MAK PLT MAK_EXP PLT_MIN FLT_MIN_EXP BL_DIG DBL_EPSILON DBL_MANT_DIG DBL_MAK DBL _MAX_ =x? DBL_MIN DBL_MIN_EXP tea7 16-37 radical dela repreentacian exp modo de redondeo de punto flotante para adicién digitos decimales de precisién ‘menor numero x tal que 1.0 + x # 1.0 mimero de digitos de base FLT_RADIX en la mantisa ro de punto flotante al que FLT_RADIX'=I es representable que 1LO+x #10 rnimero de digitos de base PL-7_RADIX en la mantisa maximo nimero double de punto flotante ‘maximo 7 tal que 7E7_RADIX'=1 es representable inimo niimero double normalizado de punto flotante ‘minimo n tal que 10" es un numero normalizado apenoice c: Resumen de modificaciones Desde la publicacin de la primera edicién de este libro, la definicién del lenguaje C la préctica existente. Muchas de ue acompafan a los compiladores dsp do por otros proveedores de compiladores del lenguaje C. Recientement incorpor6 mas de esos cambios estandarizando el lenguaje, y también introdujo o dlificaciones significativis. Su reporte fue en parte anticipado por algunos compiladores comerciales aiin antes de la publicacién del estindar formal Este apéndice resume las diferencias entre el lenguaje definido por la primera edici6n 0, y lo esperado como la definicidn del estindar final. Trata solamente al len- ‘no a su entorno ni a su biblioteca; aunque esas son partes importantes del ‘ay poco con qué compararlas, puesto que en la primera edicion no se intent Permitide para id son mayiiscul los escapes para #" fos puede cam! signed, enum), La El efecto de sezuir \ con ndefinido. Véase §A2.5.2. 283284 RESUMEN DE MODIFICACIONES APENDICE © APENDICE C285 el del operando deta izquierda; el operando BAT, Flotante de precisién 90 unsigned char igned para hacer exp unién o enumeracion, lo disponible. Fl estindar introduce con slo un rétulo de objetos cada implantaci6n particular ‘+ Las enumeraciones son algo nuevo desde la primera edicién de este libro. + El estindar adopta de C++ la nocidn de ealifcador de tipo, por ejemplo, const (6A8.2) ‘+ Las cadenas ya no son modificables, por lo que puede leetura arse en memoria de s6lo , esencialmente de siempre use double” al tipo més pequeno de suficiente capacidad”. Véase §A6.5. ‘+ Los antiguos operadores de asignacién como =+ realmente desaparecieron, Tam- bign, los operadores de asignacion son ahora rokens sencillos; en la primera edicion fueron parejas y se podian separar por espacio en blanco. ‘Se cancel la licencia del compilador pat 2 los operadores mateméticamente ivos como computacionalmente asociativos. \dujo un operador unario + por simetria con el ~ unario. ‘* Un apuntador a una funeién se puede utilizar como un designador de funcién sin un apuntador al arrego. ‘+ El operador sizeof, en la primera edicién, dabe el tipo int; posteriormente, muchas ‘unsigned. El estandar hace 0 requiere que el ipo a rencia entre apuntadares. Véase §A7.4,8 y §A7.1 + El operador & (“direccion de") no se puede aplicar a un objeto declarade register, ‘un si la implantacién decide no mantener al otjeto en un re27288 EL LENGUAJE DEL PROGRAMADOR C INDICE EL LENGUAJE DELPROGRAMADOR C 22s 24, 238 ematical eesivo- descendent 136 on 22 19-184, 269,20. EXIT_FAILURE, EXIT_SUCCESS 277 ‘expen de macros 2545520 EL LENGUAJE DEL PROGRAMADOR C INDICE EL LENGUAJE DEL PROGRAMADOK C iota vp, pil, vpn func func de bho Hor 23 min de na win 209 fnci eoth—oene D4202 ELLENGUAJE DEL PROGRAMADOR C INDICE EL LENGUAJE DEL PROGRAMADOR C INDICE 293 ropesin de aenasion aida 1,22, 57 in 28204 EL LENGUAJE DEL PROGRAMADOR C INDICE teancamento por diab eh vo 15, 6,