el lenguaje de programacion c [2ª ed] - kernighan & ritchie

305
SEGUNDA EDICION  _______ EL  LENGUAJE DE  PROGRAMACION BRIAN W. KERNIGHAN DENNIS M. RITCHIE

Upload: jefmur

Post on 10-Oct-2015

339 views

Category:

Documents


52 download

TRANSCRIPT

  • SEGUNDA EDICION

    _______EL LENGUAJE DE

    PROGRAMACION

    BRIAN W. KERNIGHAN DENNIS M. RITCHIE

  • EDICION EN INGLES

    UNIX es una marca registrada AT & T

    ______________ EL LENGUAJE DE PROGRAM ACION C________________

    Traducido de la segunda edicin en ingls de:

    THE C PROGRAMMING LANGUAGE

    Prohibida la reproduccin total o parcial de esta obra, per cualquier medio o mtodo sin autorizacin escrita del editor

    DERECHOS RESERVADOS 1991 respecto a la segunda edicin en espaol por PRENTICE-HALL HISPANOAMERICANA, S.A.

    Atlacomulco Nm. 500-5 Piso Col. Industrial Atoto53519, Naucalpan de Jurez, Edo. de Mxico

    Miembro de la Cmara Nacional de la Industria Editorial, Reg. Nm. 1524

    ISBN 968-880-205-0

    Original English language edition published by Copyright MCMLXXXVII1 by Prentice-Hall, Inc.All Rights Reserved

    ISBN 0-13-110362-8

    IMPRESO EN MEXICO / PRINTED IN MEXICO

  • PrefacioCONTENIDO

    L\

    Prefacio a la primera edicin xi

    Introduccin 1

    Captulo 1. Introduccin general 51.1 Comencemos 51.2 Variables y expresiones aritmticas 81.3 La proposicin for 141.4 Constantes simblicas 151.5 Entrada y salida de caracteres 161. 6 Arreglos 231.7 Funciones 261.8 Argumentosllamada por valor 291.9 Arreglos de caracteres 301.10 Variables externas y alcance 33

    Captulo 2. Tipos, operadores y expresiones 3 92.1 Nombres de variables 3 92.2 Tipos y tamaos de datos 402.3 Constantes 412.4 Declaraciones 442.5 Operadores aritmticos 452.6 Operadores de relacin y lgicos 462.7 Conversiones de tipo 472.8 Operadores de incremento y decremento 51ly9 Operadores para manejo de bits 532.10 Operadores de asignacin y expresiones 552 .1 1 Expresiones condicionales 562.12 Precedencia y orden de evaluacin 57

    Captulo 3. Control de flujo 6 13.1 Proposiciones y bloques 613.2 If-else 613.3 Else-if 633.4 Switch 643.5 Cicloswhile y for 6 63.6 Ciclosdo-while 70

  • 3.7 Break y continu 713.8 Goto y etiquetas 72

    Captulo 4. Funciones y la estructura del programa 754.1 Conceptos bsicos de funciones 754.2 Funciones que regresan valores no-enteros 794.3 Variables externas 824.4 Reglas de alcance 8 84.5 Archivos header 904.6 Variables estticas 914.7 Variables registro 924.8 Estructura de bloque 934.9 Inicializacin 944.10 Recursividad 954.11 El preprocesador de C 97

    Captulo 5. Apuntadores y arreglos 1035.1 Apuntadores y direcciones 1035.2 Apuntadores y argumentos de funciones 1055.3 Apuntadores y arreglos 1085.4 Aritmtica de direcciones m5.5 Apuntadores a caracteres y funciones 1155.6 Arreglos de apuntadores; apuntadores a apuntadores 1185.7 Arreglos multidimensionales 1225.8 Inicializacin de arreglos de apuntadores 1245.9 Apuntadores vs. arreglos multidimensionales 1255.10 Argumentos en la lnea de comandos 1 ^5.11 Apuntadores a funciones ^5.12 Declaraciones complicadas

    Captulo 6. Estructuras 1416.1 Conceptos bsicos sobre estructuras 1416.2 Estructuras y funciones 1436.3 Arreglos de estructuras 1466.4 Apuntadores o estructuras 1516.5 Estructuras autorreferenciadas 1536 . 6 Bsqueda en tablas 1586.7 Typedef 1616 . 8 Uniones 1626.9 Campos de bits 164

    Captulo 7. Entrada y salida 1677.1 Entrada y salida estndar 1677.2 Salida con formatoprintf 1697.3 Listas de argumentos de longitud variable 1717.4 Entrada con formatoseanf 1737.5 Acceso a archivos 1767.6 Manejo de erroresstderr y exit 179

  • 7.7 Entrada y salida de lneas7.8 Otras funciones

    181183

    Captulo t. La interfaz del sistema UNIX 1878 .1 Descriptores de archivos 1878 . 2 E/S de bajo nivelread y write 1888.3 open, creat, cise, unlink 1908.4 Acceso aleatoriolseek 1938.5 Ejemplouna implementacin de fopen y getc 1948 . 6 Ejemplolistado de directorios 1988.7 Ejemploasignador de memoria 204

    Apndice .A. Manual de referencia 211Al Introduccin 2 1 1A2 Convenciones lxicas 2 1 1A3 Notacin sintctica 215A4 Significado de los identificadores 215A5 Objetos y valores-1 217A6 Conversiones 217A l Expresiones 2 2 0A 8 Declaraciones 232A9 Proposiciones 245A10 Declaraciones externas 249Al 1 Alcance y ligadura 251A12 Preprocesamiento 253A13 Gramtica 258

    Apndice B. Biblioteca estndar 2 5 5B1 Entrada y salida: ^B2 Pruebas de clasificacin de caracteres: 2 7 2B3 Funciones para cadenas: 2 7 3B4 Funciones matemticas: 2 7 4B5 Funciones de utilera: < stdlib.h > 2 7 5B6 Diagnsticos: 278B7 Listas de argumentos variables: 278B8 Saltos no locales: 278B9 Seales: 279B10 Funciones de fecha y hora: 279B ll Lmites definidos en la implantacin: y < float.h> 281

    Apndice C. Resumen de modificaciones 283

    Indice 287

  • Prefacio

    El m undo de la com putacin ha sufrido una revolucin desde la publicacin, en 1978, de El lenguaje de programacin C. Las grandes com putadoras son ahora mucho ms grandes, y las com putadoras personales tienen capacidades que rivalizan con los mainframes de hace una dcada. Tambin el lenguaje C ha cambiado en ese tiempo, aunque slo en form a modesta, y se ha extendido ms all de lo que fueron sus orgenes como el lenguaje del sistema operativo UNIX.

    La creciente popularidad de C , los cambios en el lenguaje a lo largo de los aos, y la creacin de compiladores por grupos no involucrados en su diseo, se combinaron para dem ostrar la necesidad de una definicin del lenguaje ms precisa y contem pornea que la que proporcion la prim era edicin de este libro. En 1983, el American National Standards Instilute (ANSI) estableci un comit cuyos propsitos eran producir una definicin no ambigua del lenguaje C e, independiente de la m quina , cuidando la conservacin de su espritu. El resultado es el estndar ANSI para el lenguaje C.

    El estndar formaliza construcciones sugeridas pero no descritas en la primera edicin, particularm ente la asignacin de estructura y las enumeraciones. P roporciona una nueva form a de declaracin de funciones, que permite revisar com parativam ente su definicin y uso. Especifica una biblioteca estndar, con un conjunto extensivo de funciones para realizar la entrada y salida, la adm inistracin de memoria, la m anipulacin de cadenas y tareas semejantes. Precisa el com portam iento de caractersticas que no se m encionaron en la definicin original, y al mismo tiempo establece explcitamente cules aspectos del lenguaje tienen an dependencia de m quina.

    Esta segunda edicin de El lenguaje de programacin C lo describe tal como lo defini el estndar ANSI. (En el momento de escribir est edicin, el estndar se encontraba en la etapa final de revisin; se esperaba su aprobacin a finales de 1988. Las diferencias entre lo que se ha descrito aqu y la form a final debern ser mnimas.) Aunque hemos hecho anotaciones en los lugares donde el lenguaje ha evolucionado, preferimos escribir exclusivamente en la nueva forma. En general esto no hace una diferencia significativa; el cambio ms visible es la nueva forma de declaracin y definicin de funciones. Los modernos compiladores manejan ya la mayora de las posibilidades del estndar^

  • X PREFACIO

    Hemos tratado de mantener la brevedad de la primera edicin. El lenguaje C no es grande, y no le est bien un gran libro. Hemos m ejorado la exposicin de caractersticas crticas, como los apuntadores, que son parte central en la programacin con C. Hemos redefinido los ejemplos originales y agregamos ejemplos nuevos en varios captulos. Por ejemplo, se aum ent el tratam iento de declaraciones complicadas con program as que convierten declaraciones en palabras y viceversa. Como antes, todos los ejemplos se han probado directamente a partir del texto, el cual est diseado de m anera que lo pueda leer la mquina.

    El apndice A, manual de referencia, no es el estndar, sino que nuestra intencin fue trasladar la esencia del estndar a un espacio ms pequeo. Est hecho con el nimo de que proporcione una fcil comprensin para los programadores, pero no como una definicin del lenguaje para quienes escriben compiladores ese papel propiam ente le corresponde al estndar en s. El apndice B es un resumen de las posibilidades de la biblioteca estndar. Tambin tiene el propsito de ser una referencia para program adores, no para im plantadores. En el apndice C se ofrece un resumen de los cambios de la versin original.

    Como mencionamos en el prefacio a la prim era edicin, C se lleva bien, en la medida en que aum enta nuestra experiencia con l . Con una dcada ms de experiencia, an lo sentimos as. Deseamos que este libro le ayude a aprender el lenguaje C y tambin cmo usarlo.

    Tenemos un profundo reconocimiento hacia los amigos que nos ayudaron a producir esta segunda edicin. Jon Bentley, Doug Gwyn, Doug Mcllroy, Peter Nelson y Rob Pike nos dieron valiosos comentarios sobre casi cada pgina del borrador de este manuscrito. Estamos agradecidos por la cuidadosa lectura de AI Aho, Dennis Allison, Joe Campbell, G. R. Emlin, Karen Fortgang, Alien Ho- lub, Andrew Hume, Dave Kristol, John Linderman, Dave Prosser, Gene Spaf- ford, y Chris Van Wyk. Tambin recibimos tiles sugerencias de Bill Cheswick, Mark Kernighan, Andy Koening, Robin Lake, Tom London, Jim Reeds, Clovis Tondo y Peter Weinberger. Dave Prosser respondi muchas preguntas detalladas acerca del estndar ANSI. Utilizamos extensivamente el intrprete de C + + de Bjarne Stroustrup, para la prueba local de nuestros programas, y Dave Kristol nos ofreci un compilador ANSI C para las pruebas finales. Rich Drechsler nos ayud grandem ente con la composicin.

    Nuestro sincero agradecimiento a todos.

    Brian W. Kernighan Dennis M. Ritchie

  • Prefacio a la primera edicin

    C es un lenguaje de program acin de propsito general que ofrece como ventajas economa de expresin, control de flujo y estructuras de datos modernos y un rico conjunto de operadores. Adems, C no es un lenguaje de muy alto nivel ni grande , y no est especializado en alguna rea especial de aplicacin. Pero su ausencia de restricciones y su generalidad lo hacen ms conveniente y efectivo para muchas tareas que otros lenguajes supuestamente ms poderosos. Originalmente, C fue diseado para el sistema operativo UNIX y Dennis Ritchie lo implant sobre el mismo en la DEC P D P-11. El sistema operativo, el compilador de C y esencialmente todos los program as de aplicacin de UNIX (incluyendo todo el sofware utilizado para preparar este libro) estn escritos en C. Tambin existen compiladores para la produccin en otras m quinas, incluyendo la IBM System/370, la Honeywell 6000 y la Interdata 8/32. El lenguaje C no est ligado a ningn hardware o sistema en particular y es fcil escribir programas que corrern sin cambios en cualquier m quina que maneje C.

    La finalidad de este libro es ayudar al lector a aprender cmo program ar en C. Contiene una introduccin general para hacer que los nuevos usuarios se inicien lo ms pronto posible, captulos separados sobre cada caracterstica im portante y un manual de referencia. L a m ayora de las exposiciones estn basadas en la lectura, escritura y revisin de ejemplos, ms que en el simple establecimiento de reglas. En su m ayora, los ejemplos son programas reales y completos, no fragmentos aislados. Todos los ejemplos han sido probados directamente a partir del texto, el cual est en form a legible para la m quina. Adems de demostrar cmo hacer un uso efectivo del lenguaje, donde ha sido posible, tratam os de ilustrar algoritmos tiles y principios de buen estilo y diseo.

    El libro no es un manual de introduccin a la programacin; se supone en l familiaridad con los conceptos bsicos de program acin, como variables, proposiciones de asignacin, ciclos y funciones. No obstante, un program ador novato deber ser capaz de leer y obtener los conceptos del lenguaje, aunque le ayudara la cooperacin de un colega ms experimentado.

    De acuerdo con nuestra experiencia, C ha dem ostrado ser un lenguaje agradaba expresivo y verstil para una amplia variedad de programas. Es fcil de aprender y se obtienen mejores resultados a medida que aum enta nuestra experiencia cn l. Deseamos que este libro le ayude al lector a usarlo correctamente.

  • x ii PREFACIO A LA PRIMERA EDICION

    Las crticas y sugerencias de muchos amigos y colegas han aum entado muchsimo los conceptos de este libro y ha sido un placer escribirlo. En particular nuestro agradecimiento a Mike Bianchi, Jim Blue, Stu Feldman, Doug Mcllroy, Bill Roome, Bob Rosin y Larry Rosler que leyeron cuidadosamente las numerosas versiones. Tambin agradecemos Al A ho, Steve Bourne, Dan Dvorak, Chuck Haley, Debbie Haley, M arin H arrris, Rick H olt, Steve Johnson, John Mashey, Bob Mitze, Ralph M uha, Peter Nelson, Elliot Pinson, Bill Plauger, Jerry Spi- vack, Ken Thom pson y Peter W einberger por sus valiosos comentarios a travs de varias etapas; a Mike Lesk y Joe Ossanna, por su invaluable ayuda en la impresin.

    Brian W. Kernighan Dennis M. Ritchie

  • Introduccin

    C es un lenguaje de program acin de propsito general que ha sido estrechamente asociado con el sistema UNIX en donde fue desarrollado puesto que tanto el sistema como los program as que corren en l estn escritos en lenguaje C. Sin embargo, este lenguaje no est ligado a ningn sistema operativo ni a ninguna mquina, y aunque se le llama lenguaje de program acin de sistemas debido a su utilidad para escribir compiladores y sistemas operativos, se utiliza con igual eficacia para escribir im portantes programas en diversas disciplinas.

    Muchas de las ideas im portantes de C provienen del lenguaje BCPL, desarrollado por M artin Richards. La influencia de BCPL sobre C se continu indirectamente a travs del lenguaje B, el cual fue escrito por Ken Thom pson en 1970 para el primer sistema UNIX de la DEC PDP-7.

    BCPL y B son lenguajes carentes de tipos . En contraste, C proporciona una variedad de tipos de datos. Los tipos fundamentales son caracteres, enteros y nmeros de punto flotante de varios tam aos. Adems, existe una jerarqua de tipos de datos derivados, creados con apuntadores, arreglos, estructuras y uniones. Las expresiones se form an a partir de operadores y operandos; cualquier expresin, incluyendo una asignacin o una llamada a funcin, puede ser una proposicin. Los apuntadores proporcionan una aritmtica de direcciones independiente de la m quina.

    C proporciona las'construcciones fundamentales de control de flujo que se requieren en programas bien estructurados: agrupacin de proposiciones, tom a de decisiones (if-else), seleccin de un caso entre un conjunto de ellos (switch), iteracin con la condicin de paro en la parte superior (while, for) o en la parte inferior (do), y terminacin prem atura de ciclos (break).

    Las funciones pueden regresar valores de tipos bsicos, estructuras, uniones o apuntadores. Cualquier funcin puede ser llamada recursivamente. Las variables locales son norm alm ente autom ticas , o creadas de nuevo con cada invocacin. La definicin de una funcin no puede estar anidada, pero las variables pueden estar declaradas en una m odalidad estructurada por bloques. Las funciones de un programa en C pueden existir en archivos fuente separados, que se compilan de manera separada. Las variables pueden ser internas a una funcin, externas pero conocidas slo dentro de un archivo fuente, o visibles al program a completo.

  • 2 INTRODUCCION

    Un paso de preprocesamiento realiza substitucin de macros en el texto del program a, inclusin de otros archivos fuente y compilacin condicional.

    C es un lenguaje de relativo bajo nivel . Esta caracterizacin no es peyorativa, simplemente significa que C tra ta con el mismo tipo de objetos que la mayora de las com putadoras, llmense caracteres, nmeros y direcciones. Estos pueden ser combinados y cambiados de sitio con los operadores aritmticos y lgicos im plantados por mquinas reales.

    C no proporciona operaciones para tra tar directamente con objetos compuestos, tales como cadenas de caracteres, conjuntos, listas o arreglos. No existen operaciones que manipulen un arreglo o una cadena completa, aunque las estructuras pueden copiarse como una unidad. El lenguaje no define ninguna facilidad para asignacin de almacenamiento que no sea la de definicin esttica y la disciplina de pilas provista por las variables locales de funciones; no emplea heap ni recolector de basura. Finalmente, C en s mismo no proporciona capacidades de entrada/salida; no hay proposiciones READ o W RITE, ni mtodos propios de acceso a archivos. Todos esos mecanismos de alto nivel deben ser proporcionados por funciones llamadas explcitamente.

    De manera semejante, C solamente ofrece un control de flujo franco, y lineal: condiciones, ciclos, agrupamientos y subprogram as, pero no m ultiprogramacin, operaciones paralelas, sincronizacin ni cor-rutinas.

    Aunque la ausencia de alguna de esas capacidades puede parecer como una grave deficiencia ( significa que se tiene que llamar a una funcin para com parar dos cadenas de caracteres? ), el m antener al lenguaje de un tam ao modesto tiene beneficios reales. Puesto que C es relativamente pequeo, se puede describir en un pequeo espacio y aprenderse con rapidez. Un program ador puede razonablemente esperar conocer, entender y utilizar en verdad la totalidad del lenguaje.

    Por muchos aos, la definicin de C fue el manual de referencia de la primera edicin de El lenguaje de programacin C. En 1983, el American National Stari- durds Institute (ANSI) estableci un comit para proporcionar una m oderna y comprensible definicin de C. La definicin resultante, el estndar ANSI o ANSI C , se esperaba fuera aprobada a fines de 1988. La m ayora de las caractersticas del estndar ya se encuentran soportadas por compiladores modernos.

    El estndar est basado en el manual de referencia original. El lenguaje ha cambiado relativamente poco; uno de los propsitos del estndar fue asegurar que la mayora de los programas existentes pudiesen permanecer vlidos o, al menos, que los compiladores pudieran producir mensajes de advertencia acerca del nuevo com portam iento.

    Para la mayora de los program adores, el cambio ms im portante es una nueva sintaxis para declarar y definir funciones. Una declaracin de funcin ahora puede incluir una descripcin de los argumentos de la funcin; la sintaxis de la definicin cambia para coincidir. Esta informacin extra permite que los compiladores detecten ms fcilmente los errores causados por argumentos que no coinciden; de acuerdo con nuestra experiencia, es una adicin muy til al lenguaje.

  • EL LENGUAJE DE PROGRAMACION C 3

    Existen otros cambios de m enor escala en el lenguaje. La asignacin de estructuras y enumeraciones, que ha estado ampliamente disponible, es ahora parte oficial del lenguaje. Los clculos de punto flotante pueden ahora realizarse con precisin sencilla. Las propiedades de la aritmtica, especialmente para tipos sin signo, estn esclarecidas. El preprocesador es ms elaborado. La mayor parte de esos cambios slo tendrn efectos secundarios para la mayora de los programadores.

    Una segunda contribucin significativa dei estndar es la definicin de una biblioteca que acompae a C. Esta especifica funciones para tener acceso al sistema operativo (por ejemplo, leer de archivos y escribir en ellos), entrada y salida con form ato, asignacin de memoria, m anipulacin de cadenas y otras actividades semejantes. Una coleccin de encabezadores (headers) estndar proporcionan un acceso uniforme a las declaraciones de funciones y tipos de datos. Los programas que utilizan esta biblioteca para interactuar con un sistema anfitrin estn asegurados de un com portam iento com patible. La mayor parte de la biblioteca est estrechamente modelada con base en la biblioteca E /S estndar del sistema UNIX. Esta biblioteca se describi en la prim era edicin y ha sido tambin ampliamente utilizada emotros sistemas. De nuevo, la mayora de los programa- dores no notarn mucho el cambio.

    Debido a que los tipos de datos y estructuras de control provistas por C son manejadas directamente por la m ayora de las com putadoras, la biblioteca de ejecucin (run-time) requerida para im plantar program as autocontenidos es pequea. Las funciones de la biblioteca estndar nicamente se llaman en forma explcita, de manera que se pueden evitar cuando no se necesitan. La mayor parte puede escribirse en C, y excepto por detalles ocultos del sistema operativo, ellas mismas son porttiles.

    Aunque C coincide con las capacidades de muchas com putadoras, es independiente de cualquier arquitectura. Con un poco de cuidado es fcil escribir programas porttiles, esto es, programas que puedan correr sin cambios en una variedad de mquinas. El estndar explica los problemas de la transportabilidad, y prescribe un conjunto de constantes que caracterizan a la m quina en la que se ejecuta el programa.

    C no es un lenguaje fuertemente tipificado, sino que, al evolucionar, su verificacin de tipos ha sido reforzada. La definicin original de C desaprob, pero permiti, el intercambio de apuntadores y enteros; esto se ha eliminado y el estndar ahora requiere la adecuada declaracin y la conversin explcita que ya ha sido obligada por los buenos compiladores. La nueva declaracin de funciones es otro paso en esta direccin. Los compiladores advertirn de la mayora de los errores de tipo, y no hay conversin autom tica de tipos de datos incompatibles. Sin embargo, C mantiene la filosofa bsica de que los program adores saben lo Que estn haciendo; slo requiere que establezcan sus intenciones en forma explcita.

    Como cualquier otro lenguaje, C tiene sus defectos. Algunos de los operadores tienen la precedencia equivocada; algunos elementos de la sintaxis pueden ser

  • 4 INTRODUCCION

    mejores. A pesar de todo, C ha probado ser un lenguaje extremadamente efectivo y expresivo para una amplia variedad de program as de aplicacin.

    El libro est organizado como sigue. El captulo 1 es una introduccin orientada a la parte central de C. El propsito es hacer que el lector se inicie tan pronto como le sea posible, puesto que creemos firmemente que la form a de aprender un nuevo lenguaje es escribir program as en l. La introduccin supone un conocimiento prctico de los elementos bsicos de la programacin; no hay una explicacin de com putadoras, de compilacin, ni del significado de una expresin como n = n + 1 . Aunque hemos tratado de m ostrar tcnicas tiles de program acin en donde fue posible, la intencin del libro no es la de ser un texto de consulta sobre estructuras de datos y algoritmos; cuando nos vimos forzados a hacer una eleccin, nos hemos concentrado en el lenguaje.

    En los captulos del 2 al 6 se discuten varios aspectos de C en mayor detalle y ms formalmente de lo que se hace en el captulo 1, aunque el nfasis est an en los ejemplos de programas completos, ms que en fragmentos aislados. El captulo 2 tra ta de los tipos bsicos de datos, operaciones y expresiones. El captulo 3 tra ta sobre control de flujo: if-else, switch, while, for, etc. En el captulo 4 se cubren funciones y la estructura de un program a variables externas, reglas de alcance, archivos fuente mltiples y otros aspectos y tambin abarca al pre- procesador. El captulo 5 discute sobre apuntadores y aritmtica de direcciones. El captulo 6 cubre estructuras y uniones.

    El captulo 7 describe la biblioteca estndar, la cual proporciona una interfaz comn con el sistema operativo. Esta biblioteca est definida por el estndar ANSI y se intenta que se tenga en todas las mquinas que manejan C; as, los programas que la usen para entrada, salida y otros accesos al sistema operativo se puedan transportar de un sistema a o tro sin cambios.

    El captulo 8 describe una interfaz entre los program as en C y el sistema operativo UNIX, concentrndose en entrada/salida, el sistema de archivos y la asignacin de memoria. Aunque algo de este captulo es especfico de sistemas UNIX, los program adores que usen otros sistemas de todas maneras encontrarn aqu material de utilidad, incluyendo alguna comprensin acerca de cmo est implantada una versin de la biblioteca estndar, as como sugerencias para obtener un cdigo porttil.

    El apndice A contiene un manual de consulta del lenguaje. El inform e oficial de la sintaxis y la semntica de C es en s el estndar ANSI. Ese docum ento, sin embargo, est principalmente pensado para quienes escriben compiladores. El manual de consulta de este libro transmite la definicin del lenguaje en una forma ms concisa y sin el mismo estilo legalista. El apndice B es un resumen de la biblioteca estndar, de nuevo ms para usuarios que para implantadores. El apndice C es un breve resumen de los cambios del lenguaje original. Aunque, en caso de duda, el estndar y el compilador en uso quedan como las autoridades finales sobre el lenguaje.

  • c a p i t u l o i: Introduccin general

    Comencemos con una introduccin rpida a C. Nuestro objetivo es mostrar los elementos esenciales del lenguaje en program as reales, pero sin perdernos en detalles, reglas o excepciones. Por el momento, no intentamos ser completos ni precisos (exceptuando en los ejemplos, que s lo son). Deseamos llevarlo tan rpido como sea posible al punto en donde pueda escribir programas tiles, y para hacerlo tenemos que concentrarnos en las bases: variables y constantes, aritmtica, control de flujo, funciones y los rudimentos de entrada y salida. Hemos dejado intencionalmente fuera de este captulo las caractersticas de C que son importantes para escribir program as ms grandes. Esas caractersticas incluyen apuntadores, estructuras, la mayor parte del rico conjunto de operadores de C, varias proposiciones para control de flujo y la biblioteca estndar.

    Este enfoque tiene sus inconvenientes. Lo ms notorio es que aqu no se encuentra la descripcin completa de ninguna caracterstica particular del lenguaje, y la introduccin, por su brevedad, puede tambin ser confusa. Y debido a que los ejemplos no utilizan la potencia completa de C, no son tan concisos y elegantes como podran serlo. Hemos tratado de am inorar esos efectos, pero tenga cuidado. Otro inconveniente es que los captulos posteriores necesariamente repetirn algo de lo expuesto en ste. Esperamos que la repeticin, ms que molestar, ayude.

    En cualquier caso, los program adores con experiencia deben ser capaces de extrapolar del material que se encuentra en este captulo a sus propias necesidades de programacin. Los principiantes deben complementarlo escribiendo pequeos programas semejantes a los aqu expuestos. Ambos grupos pueden utilizar este captulo como un marco de referencia sobre el cual asociar las descripciones ms detalladas que comienzan en el captulo 2.

    1.1 ComencemosLa nica forma de aprender un nuevo lenguaje de programacin es escribien

    do programas con l. El primer program a por escribir es el mismo para todos los lenguajes:

    Imprima las palabras hola, mundo

    5

  • t> INTRODUCCION GENERAL CAPITULO 1

    Este es el gran obstculo; para librarlo debe tener la habilidad de crear el texto del programa de alguna manera, com pilarlo con xito, cargarlo, ejecutarlo y descubrir a dnde fue la salida. Con el dom inio de estos detalles m ecnicos, todo lo dems es relativamente fcil.

    En C, el program a para escribir hola, m undo es

    #include

    main( )(

    printf("hola, mundo\n");}

    La forma de ejecutar este program a depende del sistema que se est utilizando. Como un ejemplo especfico, en el sistema operativo UNIX se debe crear el program a en un archivo cuyo nom bre termine con .c , como ho la .c , y despus compilarlo con la orden

    cc hola.c

    Si no se ha cometido algn error, como la omisin de un carcter o escribir algo en forma incorrecta, la compilacin se har sin emitir mensaje alguno, y crear un archivo ejecutable llamado a .ou t. Si se ejecuta a.out escribiendo la orden

    a.out

    se escribir

    hola, mundo

    En otros sistemas, las reglas sern diferentes, consltelo con un experto.Ahora algunas explicaciones acerca del program a en s. Un program a en C,

    cualquiera que sea su tam ao, consta de funciones y variables . Una funcin contiene proposiciones que especifican las operaciones de clculo que se van a realizar, y las variables almacenan los valores utilizados durante los clculos. Las funciones de C son semejantes a las subrutinas y funciones de Fortran o a los procedimientos y funciones de Pascal. Nuestro ejemplo es una funcin llamada main. Normalmente se tiene la libertad de dar cualquier nombre que se desee, pero m ain es especial el program a comienza a ejecutarse al principio de m ain. Esto significa que todo program a debe tener un m ain en algn sitio.

    Por lo comn main llamar a otras funciones que ayuden a realizar su trabajo , algunas que usted ya escribi, y otras de bibliotecas escritas previamente. La primera lnea del programa.

    #include

    indica al compilador que debe incluir informacin acerca de la biblioteca estndar de entrada/salida; esta lnea aparece al principio de muchos archivos fuente de C. La biblioteca estndar est descrita en el captulo 7 y en el apndice B.

  • SECCION 1.1 COMENCEMOS /

    Un mtodo para comunicar datos entre las funciones es que la funcin que llama proporciona una lista de valores, llamados argumentos, a id funcin que est invocando. Los parntesis que estn despus del nombre de la funcin encierran a la lista de argumentos. En este ejemplo, main est definido para ser una funcin que no espera argum entos, lo cual est indicado por la lista vacia ( ).

    # include incluye informacin acerca de la biblioteca estndar

    main( ) define una funcin llamada mainque no recibe valores de argumentos

    { las proposiciones de main estn encerradas entre llaves

    printf("hola, mundo\n"); main llama a la funcin de biblioteca printf.} para escribir esta secuencia de caracteres;

    \n representa el carcter nueva lnea

    El prim er programa en C

    Las proposiciones de una funcin estn encerradas entre llaves { }. La funcin main slo contiene una proposicin,

    printf (hola, mundo\n);

    Una funcin se invoca al nom brarla, seguida de una lista de argumentos entre parntesis; de esta manera se est llamando a la funcin printf con el argumento hola, m u n d o \n . printf es una funcin de biblioteca que escribe la salida, en este caso la cadena de caracteres que se encuentra entre comillas.

    A una secuencia de caracteres entre comillas, como ''hola, m undo \n", se le llama cadena de caracteres o constante de cadena. Por el momento, nuestro nico uso de cadenas de caracteres ser com o argumentos para printf y otras funciones.

    La secuencia \n en la cadena representa el carcter nueva lnea en la notacir de C, y hace avanzar la impresin al margen izquierdo de la siguiente lnea. Si se omite el \n (un experimento que vale la pena), encontrar que no hay avance de lnea despus de la impresin. Se debe utilizar \n para incluir un carcter nueva lnea en el argumento de printf; si se intenta algo como

    printf ("hola, mundo

    el eompilador de C producir un mensaje de error.

  • 8 INTRODUCCION GENERAL CAPITULO 1

    printf nunca proporciona una nueva lnea autom ticam ente, de manera que se pueden utilizar varias llamadas para construir una lnea de salida en etapas. Nuestro primer programa tambin pudo haber sido escrito de la siguiente manera.

    #include

    main( )f

    printf ("hola,"); printf ("mundo"); printf ("\n");

    ^producindose una salida idntica.Ntese que \n representa un solo carcter. U na secuencia de escape como \n

    proporciona un mecanismo general y extensible para representar caracteres invisibles o difciles de escribir. Entre otros que C proporciona estn \ t para tabulacin, \b para retroceso, \ " para comillas, y \ \ para la diagonal invertida. Hay una lista completa en la seccin 2.3.

    Ejercicio 1-1. Ejecute el programa "hola, mundo" en su sistema. Experimente con la omisin de partes del program a, para ver qu mensajes de error se obtienen.

    Ejercicio 1-2. Experimente el descubrir qu pasa cuando la cadena del argumento de printf contiene \c , en donde c es algn carcter no puesto en lista anteriormente.

    1.2 Variables y expresiones aritmticas

    El siguiente program a utiliza la frm ula C = (5/9) (E -32) para imprimir la siguiente tabla de tem peraturas Fahrenheit y sus equivalentes centgrados o Celsius:

    0 -1 72 0 - 6

    40 460 1580 261 0 0 371 2 0 48140 60160 71180 822 0 0 932 2 0 104

  • SECCION 1.2 VARIABLES Y EXPRESIONES ARITMETICAS 9

    240 115 260 126 280 137 300 148

    En si el program a an consiste de la definicin de una nica funcin llamada main. Es ms largo que el que imprime "hola, m undo", pero no es complicado. Introduce varias ideas nuevas, incluyendo comentarios, declaraciones, variables, expresiones aritmticas, ciclos y salida con formato.

    #include /* imprime la tabla Fahrenheit-Celsius

    para fahr = 0, 20, ..., 300 */ main ( ){

    int fahr, celsius; int lower, upper, step;

    lower = 0 ; /* lmite inferior de la tabla de temperaturas */upper = 300; /* lmite superior */step = 2 0 ; f* tamao del incremento */

    fahr = lower;while (fahr < = upper) {

    celsius = 5 * (fahr32) / 9; printf("%d\t%d\n", fahr, celsius); fahr = fahr + step;

    }}

    Las dos lneas

    /* imprime la tabla Fahrenheit-Celsius para fahr = 0, 20, ..., 300 */

    son un comentario , que en este caso explica brevemente lo que hace el programa. Cualesquier caracteres entre /* y */ son ignorados por el compilador, y pueden ser utilizados libremente para hacer a un program a ms fcil de entender. l.os com entarios pueden aparecer en cualquier lugar donde puede colocarse un espacio en blanco, un tabulador o nueva lnea.

    En C, se deben declarar todas las variables antes de su uso, generalmente al principio de la funcin y antes de cualquier proposicin ejecutable. Una declaracin notifica las propiedades de una variable; consta de un nombre de tipo y una lista de variables, como

    int fahr, celsius; int lower, upper, step;

  • 10 INTRODUCCION GENERAL CAPITULO 1

    El tipo int significa que las variables de la lista son enteros, en contraste con float, que significa punto flotante, esto es, nmeros que pueden tener una parte fraccionaria. El rango tanto de int como de float depende de la m quina que se est utilizando; los int de 16 bits, que estn comprendidos entre el -32768 y + 32767, son comunes, como lo son los int de 32 bits. Un nmero float tpicamente es de 32 bits, por lo menos con seis dgitos significativos y una magnitud generalmente entre 10-. y io^8 .

    Adems de int y float, C proporciona varios tipos de datos bsicos, incluyendo:

    char carcter un solo bvteshort entero cortolong entero largodouble punto flotante de doble precisin

    Los tamaos de estos objetos tambin dependen de la mquina. Tambin existen arreglos, estructuras y uniones de estos tipos bsicos, apuntadores a ellos y funciones que regresan valores con esos tipos, todo lo cual se ver en el momento oportuno.

    Los clculos en el program a de conversin de tem peraturas principian con las proposiciones de asignacin.

    lower = 0 ; upper = 300; step = 2 0 ; fahr = lower;

    que asignan a las variables sus valores iniciales. Las proposiciones individuales se terminan con punto y coma.

    Cada lnea de la tabla se calcula de la misma manera por lo que se utiliza una iteracin que se repite una vez por cada lnea de salida; este es el propsito del ciclo while

    while (fahr < = upper) {

    El ciclo while funciona de la siguiente manera: se prueba la condicin entre parntesis. De ser verdadera (fahr es menor o igual que upper), el cuerpo del ciclo (las tres proposiciones entre llaves) se ejecuta. Luego la condicin se prueba nuevamente, y si es verdadera, el cuerpo se ejecuta de nuevo. Cuando la prueba resulta falsa (fahr excede a upper) la iteracin termina, y la ejecucin contina en la proposicin que sigue al ciclo. No existe ninguna otra proposicin en este programa, de modo que termina.

    El cuerpo de un while puede tener una o ms proposiciones encerradas entre llaves, como en el convertidor de tem peraturas, o una sola proposicin sin llaves, como en

    while (i < j) i = 2 i;

  • SECCION 1.2 VARIABLES Y EXPRESIONES ARITMETICAS 1 1

    En cualquier caso, siempre se sangra la proposicin controlada por el while con una tabulacin (lo que se ha m ostrado con cuatro espacios) pard poder apreciar de un vistazo cules proposiciones estn dentro del ciclo. El sangrado acenta la estructura lgica del program a. A unque a los compiladores de C no les im porta la apariencia del program a, un sangrado y espaciamicnto adecuados son muy importantes para hacer programas fciles de leer. Se recomienda escribir una sola proposicin por lnea y utilizar espacios en blanco alrededor de los operadores para dar claridad al agrupam iento. La posicin de las llaves es menos im portante, aunque la gente mantiene creencias apasionadas. Se eligi uno de los varios estilos populares. Seleccione un estilo que le satisfaga y selo en forma consistente.

    La mayor parte del trabajo se realiza en el cuerpo del ciclo. La tem peratura Celsius se calcula y se asigna a la variable celsius por la proposicin.

    celsius = 5 * (fahr32) / 9;

    La razn de multiplicar por 5 y despus dividir entre 9 en lugar de solamente multiplicar por 5/9 es que en C, com o en muchos otros lenguajes, la divisin de enteros trunca el resultado: cualquier parte fraccionaria se descarta. Puesto que 5 y 9 son enteros, 5/9 sera truncado a cero y as todas las tem peraturas Celsius se reportaran como cero.

    Este ejemplo tambin muestra un poco ms acerca de cmo funciona printf. En realidad, printf es una funcin de propsito general para dar form ato de salida, que se describir con detalle en el captulo 7. Su primer argumento es una cadena de caracteres que sern impresos, con cada % indicando en donde uno de los otros (segundo, tercero, ...) argum entos va a ser sustituido, y en qu forma ser impreso. Por ejemplo, % d especifica un argum ento entero, de modo que la proposicin

    printf(''%d\t%d\n", fahr, celsius);

    hace que los valores de los dos enteros fahr y celsius sean escritos, con una tabulacin (\t) entre ellos.

    Cada construccin % en el primer argumento de printf est asociada con el correspondiente segundo argum ento, tercero, etc., y deben corresponder apropiadamente en nmero y tipo, o se tendrn soluciones incorrectas.

    Con relacin a esto, printf no es parte del lenguaje C; no existe propiamente una entrada o salida definida en C. printf es slo una til funcin de la biblioteca estndar de funciones que est accesible normalmente a los programas en C. Sin embargo, el com portam iento de prin tf est definido en el estndar ANSI, por lo que sus propiedades deben ser las mismas en cualquier compilador o biblioteca que se apegue a l.

    Para concentrarnos en C, no hablaremos mucho acerca de la entrada y la salida hasta el captulo 7. En particular, pospondremos el tema de la entrada con formato hasta entonces. Si se tiene que darle entrada a nmeros, lase la discusin de la funcin scanf en la seccin 7.4. La funcin scanf es como printf, exceptuando que lee de la entrada en lugar de escribir a la salida.

  • 12 INTRODUCCION GENERAL CAPITULO I

    Existen un par de problemas con el program a de conversin de tem peraturas. El ms simple es que la salida no es muy esttica debido a que los nmeros no estn justificados hacia su derecha. Esto es fcil de corregir; si aumentamos a cada % dde la proposicin printf una amplitud, los nmeros impresos sern justificados hacia su derecha dentro de sus cam pos. Por ejemplo, podra decirse

    printf ("%3d %6 d\n", fahr, celsius);

    para escribir el primer nmero de cada lnea en un campo de tres dgitos de ancho, y el segundo en un campo de seis dgitos, como esto:

    0 -1 72 0 - 6

    40 460 1580 26

    1 0 0 37

    El problem a ms grave es que debido a que se ha utilizado aritmtica de enteros, las tem peraturas Celsius no son muy precisas; por ejemplo, 0oF es en realidad aproximadamente 17.8C, no 17. Para obtener soluciones ms precisas, se debe utilizar aritmtica de punto flotante en lugar de entera. Esto requiere de algunos cambios en el program a. Aqu est una segunda versin:

    # include

    /* imprime la tabla Fahrenheit-Celsiuspara fahr = 0, 20, ..., 300; versin de punto flotante */

    main( ){

    float fahr, celsius; int lower, upper, step;

    lower = 0 ; /* lmite superior de la tabla de temperaturas */upper = 300; /* lmite superior */step = 2 0 ; /* tamao del incremento */

    fahr = lower;while (fahr < = upper) {

    celsius = (5.0/9.0) * (fahr-32.0); printf("%3.0f %6.1f\n", fahr, celsius); fahr = fahr + step;

  • SECCION 1.2 VARIABLES Y EXPRESIONES ARITMETICAS 13

    Esto es muy semejante a lo anterior, excepto que fahr y celsius estn declarados como float, y la frmula de conversin est escrita en una forma ms natural. No pudimos utilizar 5/9 en la versin anterior debido a que la divisin entera lo truncara a cero. Sin embargo, un punto decimal en una constante indica que sta es de punto flotante, por lo que 5 .0 /9 .0 no se trunca debido a que es una relacin de dos valores de punto flotante.

    Si un operador aritmtico tiene operandos enteros, se ejecuta una operacin entera. Si un operador numrico tiene un operando de punto flotante y otro entero, este ltimo ser convertido a punto flotante antes de hacer la operacin. Si se hubiera escrito fahr - 32, el 32 sera convertido autom ticam ente a punto flotante. Escribir constantes de punto flotante con puntos decimales explcitos, aun cuando tengan valores enteros, destaca su naturaleza de punto flotante para los lectores humanos.

    Las reglas detalladas de cundo los enteros se convierten a punto flotante se encuentran en el captulo 2. Por ahora, ntese que la asignacin

    fahr = lower;

    y la prueba

    while (fahr < = upper)

    tambin trabajan en la form a natural el int se convierte a float antes de efectuarse la operacin.

    La especificacin de conversin % 3.0f del printf indica que se escribir un nmero de punto flotante (en este caso fahr) por lo menos con tres caracteres de ancho, sin punto decimal y sin dgitos fraccionarios; % 6.1f describe a otro nmero (celsius) que se escribir en una am plitud de por lo menos 6 caracteres, con 1 dgito despus del punto decimal. La salida se ver como sigue:

    La amplitud y la precisin pueden omitirse de una especificacin: %6f indica que el nmero es por lo menos de seis caracteres de ancho; % .2f indica dos caracteres despus del punto decimal, pero el ancho no est restringido; y % nicamente indica escribir el nm ero como punto flotante.

    0 -1 7 .820 -6 .740 4.4

    %d%6 d

    escribe como entero decimalescribe como entero decimal, por lo menos con 6 caracteres de amplitudescribe como punto flotanteescribe como punto flotante, por lo menos con 6 caracteres de amplitud

    %f%6f

  • 14 INTRODUCCION GENERAL CAPITULO I

    %.2 f escribe como punto flotante, con 2 caracteres despus del puntodecimal

    %6 .2 f escribe como punto flotante, por lo menos con 6 caracteres deancho y 2 despus del punto decimal

    Entre otros, printf tambin reconoce %o para octal, % x para hexadecimal, % c para carcter, /os para cadena de caracteres y % % para % en s.

    Ejercicio 1-3. M odifique el program a de conversin de tem peraturas de modo que escriba un encabezado sobre la tabla.

    Ejercicio 1-4. Escriba un program a que imprima la tabla correspondiente Celsius a Fahrenheit.

    1.3 La proposicin forExisten suficientes formas distintas de escribir un programa para una tarea en

    particular. Intentemos una variacin del programa de conversin de temperaturas.

    #include < std io .h>

    /* imprime la tabla Fahrenheit-Celsius */ main( )

    int fahr;

    for (fahr = 0; fahr < = 300; fahr = fahr + 20)printf("%3d %6.1f/n", fahr, (5.0/9.0)*(fahr-32));

    }

    Este produce los mismos resultados, pero ciertamente se ve diferente. Un cambio im portante es la eliminacin de la m ayora de las variables; slo permanece fahr y la hemos hecho int. Los lmites inferior y superior y el tam ao del avance slo aparecen como constantes dentro de la proposicin for, que es una nueva construccin, y la expresin que calcula la tem peratura Celsius ahora aparece como el tercer argumento de printf en vez de una proposicin de asignacin separada.

    Este ltimo cambio ejemplifica una regla general en cualquier contexto en el que se permita utilizar el valor de una variable de algn tipo, es posible usar una expresin ms complicada de ese tipo. Puesto que el tercer argum ento de printf debe ser un valor de punto flotante para coincidir con % 6.1f, cualquier expresin de punto flotante puede estar all.

    La proposicin for es un ciclo, una forma generalizada del while. Si se compara con el while anterior, su operacin debe ser clara. Dentro de los parntesis existen tres secciones, separadas por punto y coma. La primera, la inicializacin

    fahr = 0

  • SECCION 1.4 CONSTANTES SIMBOLICAS 15

    se ejecuta una vez, antes de entrar propiam ente al ciclo. La segunda seccin es la condicin o prueba que controla el ciclo:

    fahr < = 300

    Esta condicin se evala; si es verdadera, el cuerpo del ciclo (en este caso un simple printf) se ejecuta. Despus el incremento de avance

    fahr = fahr + 2 0

    se ejecuta y la condicin se vuelve a evaluar. El ciclo term ina si la condicin se hace falsa. Tal como con el while, el cuerpo del ciclo puede ser una proposicin sencilla o un grupo de proposiciones encerradas entre llaves. La inicializacin, la condicin y el incremento pueden ser cualquier expresin.

    La seleccin entre while y for es arb itraria, y se basa en aquello que parezca ms claro. El for es por lo general apropiado para ciclos en los que la inicializacin y el incremento son proposiciones sencillas y lgicamente relacionadas, puesto que es ms compacto que el while y mantiene reunidas en un lugar a las proposiciones que controlan al ciclo.

    Ejercicio 1-5. Modifique el program a de conversin de tem peraturas de manera que escriba la tabla en orden inverso, esto es, desde 300 grados hasta 0.

    1.4 Constantes simblicas

    Una observacin final antes de dejar definitivamente el tema de la conversin de tem peraturas. Es una mala prctica poner nmeros mgicos como 300 y 20 en un program a, ya que proporcionan muy poca inform acin a quien tenga que leer el program a, y son difciles de m odificar en un forma sistemtica. Una manera de tra tar a esos nmeros mgicos es darles nombres significativos. Una lnea # define define un nombre simblico o constante simblica como una cadena de caracteres especial:

    #define nombre texto de reemplazo

    A partir de esto, cualquier ocurrencia de nombre (que no est entre comillas ni como parte de otro nombre) se sustituir por el texto de reemplazo correspondiente. El nombre tiene la misma form a que un nombre de variable: una secuencia de letras y dgitos que comienza con una letra. El texto de reemplazo puede ser cualquier secuencia de caracteres; no est limitado a nmeros.

    #include

    #define LOWER 0 /* lmite inferior de la tabla /#define UPPER 300 /* limite superior */#define STEP 2 0 /* tamao del incremento */

  • 16 INTRODUCCION GENERAL CAPITULO 1

    /* imprime la tabla Fahrenheit-Celsius */ main( ){

    int fahr;

    for (fahr = LOWER; fahr < = UPPER; fahr = fahr STEP) printf("/o3d %6.1\n", fahr, (5.0/9.0) * (fahr-32));

    \

    Las cantidades LOWER, UPPER y STEP son constantes simblicas, no variables, por lo que no aparecen entre las declaraciones. Los nombres de constantes simblicas, por convencin, se escriben con letras maysculas, de modo que se puedan distinguir fcilmente de los nombres de variables escritos con minsculas. Ntese que no hay punto y coma al final de una lnea # d e fin e .

    1.5 Entrada y salida de caracteres

    Ahora vamos a considerar una familia de programas relacionados para el procesamiento de datos de tipo carcter. Se encontrar que muchos program as slo son versiones ampliadas de los prototipos que se tratan aqu..

    El modelo de entrada y salida m anejado por la biblioteca estndar es muy simple. La entrada y salida de texto, sin im portar dnde fue originada o hacia dnde se dirige, se tratan como flujos (streams) de caracteres. Un f lu jo ele texto es una secuencia de caracteres divididos entre lneas, cada una de las cuales consta de cero o ms caracteres seguidos de un carcter nueva lnea. La biblioteca es responsable de hacer que cada secuencia de entrada o salida est de acuerdo con este modelo; el program ador de C que utiliza la biblioteca no necesita preocuparse de cmo estn representadas las lneas fuera del program a.

    La biblioteca estndar proporciona varias funciones para leer o escribir un carcter a la vez, de las cuales g e tch a r y p u teh ar son las ms simples. C ada vez que se invoca, g e tch ar lee el siguiente carcter de entrada de una secuencia de texto y lo devuelve como su valor. Esto es, despus de

    c = getchar( )

    la variable c contiene el siguiente carcter de entrada. Los caracteres provienen normalmente del teclado; la entrada de archivos se trata en el captulo 7.

    La funcin p u teh ar escribe un carcter cada vez que se invoca:

    putchar(c)

    escribe el contenido de la variable entera c como un carcter, generalmente en la pantalla; Las llamadas a pu teh ar y a printf pueden estar alternadas; la salidaaparecer en el orden en que se realicen las llamadas.

  • SECCION 1.5 ENTRADA Y SALIDA DE CARACTERES 17

    1.5.1 Copia de archivos

    Con getchar y putehar se puede escribir una cantidad sorprendente de cdigo til sin saber nada ms acerca de entrada y salida. El ejemplo ms sencillo es un program a que copia la entrada en la salida, un carcter a la vez:

    lee un carcterwhile (carcter no es indicador de fin de archivo)

    manda a la salida el carcter recin ledo lee un carcter

    Al convertir esto en C se obtiene

    #include

    /* copia la entrada a la salida; la . versin */main( )

    int c;

    c = getchar( );while (c ! = EOF) {

    putchar(c); c = getchar( );

    }}

    El operador de relacin != significa no igual a .Lo que aparece como un carcter en el teclado o en la pantalla es, por supues

    to, como cualquier otra cosa, almacenado internam ente como un patrn de bits. El tipo ch ar tiene la funcin especfica de almacenar ese tipo de dato, pero tam bin puede ser usado cualquier tipo de entero. Usamos int por una sutil pero importante razn.

    El problem a es distinguir el fin de la entrada de los datos vlidos. La solucin es que ge tchr devuelve un valor distintivo cuando no hay ms a la entrada, un valor que no puede ser confundido con ningn otro carcter. Este valor se llama EOF, por end o f file (fin de archivo) . Se debe declarar c con un lipo que sea lo suficientemente grande para almacenar cualquier valor que le regrese getchar. No se puede utilizar ch ar puesto que c debe ser suficientemente grande como para mantener a EOF adems de cualquier otro carcter. Por lo tanto, se emplea int.

    EOF es un entero definido en < s td io .h > , pero el valor numrico especfico no im porta mientras que no sea el mismo que ningn valor tipo char. Utilizando la constante simblica, hemos asegurado que nada en el programa depende del valor numrico especfico.

  • 18 INTRODUCCION GENERAL CAPITULO I

    El program a para copiar podra escribirse de modo ms conciso por programadores experimentados de C. En lenguaje C, cualquier asignacin, tal como

    c = getchar( )

    es una expresin y tiene un valor, el del lado izquierdo luego de la asignacin. Esto significa que una asignacin puede aparecer como parte de una expresin ms larga. Si la asignacin de un carcter a c se coloca dentro de la seccin de prueba de un ciclo while, el program a que copia puede escribirse de la siguiente manera:

    #include

    /* copia la entrada a la salida; 2 a. versin */ main( ){

    int c;

    while ((c = getchar( )) ! = EOF) putchar(c);

    }

    El while obtiene un carcter, lo asigna a c, y entonces prueba si el carcter fue la seal de fin de archivo. De no serlo, el cuerpo del while se ejecuta, escribiendo el carcter; luego se repite el while. Luego, cuando se alcanza el final de la entrada, el while term ina y tambin lo hace m ain.

    Esta versin centraliza la entrada ahora hay slo una referencia a getchar y reduce el program a. El program a resultante es ms compacto y ms fcil de leer una vez que se domina el truco. Usted ver seguido este estilo. (Sin embargo, es posible descarriarse y crear cdigo impenetrable, una tendencia que trataremos de reprimir.)

    Los parntesis que estn alrededor de la asignacin dentro de la condicin son necesarios. La precedencia de ! = es ms alta que la de = , lo que significa que en ausencia de parntesis la prueba de relacin ! = se realizara antes de la asignacin = . De esta manera, la proposicin

    c = getchar( ) ! = EOF

    es equivalente a

    c = (getchar( ) 1 = EOF)

    Esto tiene el efecto indeseable de hacer que c sea 0 o 1, dependiendo de si la llam ada de g e tch ar encontr fin de archivo. (En el captulo 2 se tra ta este tema con ms detalle).

    Ejercicio 1-6. Verifique que la expresin ge tchar ( ) ! = EOF es 0 o 1.

    Ejercicio 1-7. Escriba un program a que imprima el valor de EOF.

  • SECCION 1.5 ENTRADA Y SALIDA DE CARACTERES 19

    1.5.2 Conteo de caracteres

    El siguiente programa cuenta caracteres y es semejante al programa que copia.

    #include

    / cuenta los caracteres de la entrada; la . versin */main( ){

    long nc;

    nc = 0 ;while (getchar( ) ! = EOF)

    + + nc; printf("%ld\n", nc);

    }

    La proposicin

    + +nc;

    presenta un nuevo operador, + + , que significa incrementa en uno. Es posible escribir nc = nc + 1, pero + + n c es ms conciso y muchas veces ms eficiente. Hay un operador correspondiente - para disminuir en 1. Los operadores + + y pueden ser tanto operadores prefijos (+ + nc) como postfijos (nc + + ); esas dos formas tienen diferentes valores dentro de las expresiones, como se dem ostrar en el captulo 2, pero ambos + + n c y n c + + incrementan a nc. Por el momento adoptarem os la forma de prefijo.

    El program a para contar caracteres acumula su cuenta en una variable long en lugar de una int. Los enteros long son por lo menos de 32 bits. Aunque en algunas mquinas int y long son del mismo tam ao, en otras un int es de 16 bits, con un valor mximo de 32767, y tom ara relativamente poca lectura a la entrada para desbordar un contador int. La especificacin de conversin % ld indica a printf que el argumento correspondiente es un entero long.

    Sera posible tener la capacidad de trabajar con nmeros mayores empleando un double (float de doble precisin). Tambin se utilizar una proposicin for en lugar de un while, para dem ostrar otra forma de escribir el ciclo.

    #include

    /* cuenta los caracteres de la entrada; 2 a. versin */main( ){

    double nc;

    for (nc = 0; getchar( ) 1= EOF; + +nc)

    printf(''%.0 f\n'', nc);

  • 20 INTRODUCCION GENERAL CAPITULO 1

    printf utiliza % tanto para float como para double; % .0 f suprime la impresin del punto decimal y de la parte fraccionaria, que es cero.

    El cuerpo de este ciclo for est vaco, debido a que todo el trabajo se realiza en las secciones de prueba e incremento. Pero las reglas gramaticales de C requieren que una proposicin for tenga un cuerpo. El punto y coma aislado se llama proposicin nula, y est aqu para satisfacer este requisito. Lo colocamos en una lnea aparte para que sea visible.

    Antes de abandonar el program a para contar caracteres, obsrvese que si la entrada no contiene caracteres, la prueba del while o del for no tiene xito desde la primera llamada a ge tchar, y el program a produce cero, el resultado correcto. Esto es im portante. Uno de los aspectos agradables acerca del while y del for es que hacen la prueba al inicio del ciclo, antes de proceder con el cuerpo. Si no hay nada que hacer, nada se hace, aun si ello significa no pasar a travs del cuerpo del ciclo. Los programas deben actuar en form a inteligente cuando se les da una entrada de longitud cero. Las proposiciones while y for ayudan a asegurar que los programas realizan cosas razonables con condiciones de frontera.

    1.5.3 Cqnteo de lneas

    El siguiente program a cuenta lneas a la entrada. Como se mencion anteriormente, la biblioteca estndar asegura que una secuencia de texto de entrada parezca una secuencia de lneas, cada una terminada por un carcter nueva lnea. Por lo tanto, contar lneas es solamente contar caracteres nueva lnea:

    #include

    /* cuenta las lneas de la entrada */main( ){

    int c, ni;

    ni = 0 ;while ((c = getchar( )) != EOF)

    if (c = = 7 n')+ + ni;

    printf(''%d\n", ni);

    El cuerpo del while consiste ahora en un if, el cual a su vez controla el incremento + + ni. La proposicin if prueba la condicin que se encuentra entre parntesis y, si la condicin es verdadera, ejecuta la proposicin (o grupo de proposiciones entre llaves) que le sigue. Hemos sangrado nuevamente para m ostrar lo que controla cada elemento.

    El doble signo de igualdad = = es la notacin de C para expresar igual a (como el = simple de Pascal o el .EQ. de Fortran). Este smbolo se emplea para

  • SECCION 1.5 ENTRADA Y SALIDA DE CARACTERES 21

    distinguir la prueba de igualdad del = simple que utiliza C para la asignacin. Un mensaje de alerta: los principiantes de C ocasionalmente escriben = cuando en realidad deben usar = = . Com o se ver en el captulo 2, el resultado es por lo general una expresin legal, de m odo que no se obtendr ninguna advertencia.

    Un carcter escrito entre apstrofos representa un valor entero igual al valor numrico del carcter en el conjunto de caracteres de la m quina. Esto se llama una constante de carcter, aunque slo es otra form a de escribir un pequeo entero. As, por ejemplo 'A ' es una constante de carcter; en el conjunto ASCII de caracteres su valor es 65, esto es, la representacin interna del carcter A. Por supuesto 'A ' es preferible que 65: su significado es obvio, y es independiente de un conjunto de caracteres en particular.

    Las secuencias de escape que se utilizan en constantes de cadena tambin son legales en constantes de carcter; as, ' \ n ' significa el valor del carcter nueva lnea, el cual es 10 en cdigo ASCII. Se debe notar cuidadosamente que '\ n ' es un carcter simple, y en expresiones es slo un entero; por otro la d o ," \n "e s una constante cadena que contiene slo un carcter. En el captulo 2 se trata el tema de cadenas versus caracteres.

    Ejercicio 1-8. Escriba un program a que cuente espacios en blanco, tabuladores y nuevas lneas.

    Ejercicio 1.9. Escriba un programa que copie su entrada a la salida, reemplazando cada cadena de uno o ms blancos por un solo blanco.

    Ejercicio 1-10. Escriba un program a que copie su entrada a la salida, reemplazando cada tabulacin por \ t , cada retroceso por \b y cada diagonal invertida por \ \ . Esto hace que las tabulaciones y los espacios sean visibles sin confusiones.

    1.5.4 Conteo de palabras

    El cuarto en nuestra serie de program as tiles cuenta las lneas, palabras y caracteres, usando la definicin de que una palabra es cualquier secuencia de caracteres que no contiene espacio en blanco ni tabulacin ni nueva lnea. Esta es una versin reducida del program a wc de UNIX.

    #include

    #define IN 1 /* en una palabra */#define OUT 0 /* fuera de una palabra */

    /* cuenta lineas, palabras, y caracteres de la entrada */ main( ){

    int c, ni, nw, nc, state;

  • 22 INTRODUCCION GENERAL CAPITULO 1

    State = OUT;ni = nw = nc = 0 ;while ((c = getchar( )) ! = EOF) {

    + +nc;if (c = = V )

    + +nl;if (c = = ' ' ! c = = V | c = = '\t')

    state = OUT; else if (state = = OUT) {

    state = IN;+ +nw;

    }}printf ("%d %d % d\n", ni, nw, nc);

    }

    Cada vez que el program a encuentra el primer carcter de una palabra, contabiliza una palabra ms. La variable state registra si actualmente el program a est o no sobre una palabra; al iniciar es no est sobre una palabra , por lo que se asigna el valor OUT. Es preferible usar las constantes simblicas IN y OUT que los valores literales 1 y 0, porque hacen el program a ms legible. En un programa tan pequeo como ste, la diferencia es mnima, pero en program as ms grandes el incremento en claridad bien vale el esfuerzo extra que se haya realizado para escribir de esta m anera desde el principio. Tambin se descubrir que es ms fcil hacer cambios extensivos en program as donde los nmeros mgicos aparecen slo como constantes simblicas.

    La lnea

    n i = nw = nc = 0 ;

    inicializa a las tres variables en cero. Este no es un caso especial sino una consecuencia del hecho de que una asignacin es una expresin con un valor, y que las asignaciones se asocian de derecha a izquierda. Es como si se hubiese escrito

    n i = (nw = (nc = 0 ));

    El operador { significa O (o bien O R ), por lo que la lnea

    if (c = = " i c = = V !! c = = V )

    dice si c es un blanco o c es nueva lnea o c es un tabulador . (Recuerde que la secuencia de escape \ t es una representacin visible del carcter tabulador.) Existe un correspondiente operador && para AND; su precedencia es ms alta que la de . Las expresiones conectadas por && o se evalan de izquierda a derecha, y se garantiza que la evaluacin term inar tan pronto como se conozca la verdad o falsedad. Si c es un blanco, no hay necesidad de probar si es una nueva lnea o un tabulador, de modo que esas pruebas no se hacen. Esto no es de

  • SECCION 1.6 ARREGLOS 23

    particular im portancia en este caso, pero es significativo en situaciones ms complicadas, como se ver ms adelante.

    El ejemplo muestra tambin un else, el cual especifica una accin alternativa si la condicin de una proposicin if es falsa. La form a general es

    if (expresin) proposicin

    elseproposicin2

    Una y slo una de las dos proposiciones asociadas con un if-else se realiza. Si la expresin es verdadera, se ejecuta p r o p o s ic i n si no lo es, se ejecuta proposic in . Cada proposicin puede ser una proposicin sencilla o varias entre llaves. En el program a para contar palabras, la que est despus del else es un if que controla dos proposiciones entre llaves.

    Ejercicio 1-11. Cmo probara el program a para contar palabras? Qu clase de entrada es la ms conveniente para descubrir errores si stos existen?

    Ejercicio 1-12. Escriba un program a que imprima su entrada una palabra por lnea.

    1.6 Arreglos

    Escribamos un programa para contar el nmero de ocurrencias de cada dgito, de caracteres espaciadores (blancos, tabuladores, nueva lnea), y de todos los otros caracteres. Esto es artificioso, pero nos permite ilustrar varios aspectos de C en un program a.

    Existen doce categoras de entrada, por lo que es conveniente utilizar un arreglo para mantener el nmero de ocurrencias de cada dgito, en lugar de tener diez variables individuales. Esta es una versin del program a:

    #include

    /* cuenta dgitos, espacios blancos, y otros */ main( ){

    int c, i, nwhite, nother; int ndigit[1 0 J;

    nwhite = nother = 0 ; for (i = 0 ; i < 1 0 ; + + i)

    ndigit[i] = 0 ;

  • 24 INTRODUCCION GENERAL CAPITULO 1

    while ((c = getchar( )) ! = EOF) if (c > = '0' && c < = '9')

    + + ndigit [c'O']; else if (c = = " ! c = = V \\ c = = V )

    + + nwhite;else

    + + nother;

    printf ("dgitos = "); for (i = 0 ; i < 1 0 ; + + i)

    printf(" %d", ndigit[i]); printf(, espacios blancos = %d, otros = %d\n",

    nwhite, nother);}

    La salida de este program a al ejecutarlo sobre s mismo es

    dgitos = 9 3 0 0 0 0 0 0 0 1 , espacios blancos = 123, otros = 345

    La declaracin

    int ndigit [1 0 ];

    declara ndigit como un arreglo de 10 enteros. En C, los subndices de arreglos comienzan en cero, por lo que los elementos son ndigit[0], ndigit [1], ndi- git[9]. Esto se refleja en los ciclos for que inicializan e imprimen el arreglo.

    Un subndice puede ser cualquier expresin entera, lo que incluye a variables enteras como i, y constantes enteras.

    Este program a en particular se basa en las propiedades de la representacin de los dgitos como caracteres. Por ejemplo, la prueba

    if (c > = '0' && c < = '9') ...

    determina si el carcter en c es un dgito. Si lo es, el valor numrico del dgito es

    c - '0 '

    Esto slo funciona si '0 ', '1', ... , '9 ' tienen valores consecutivos ascendentes. Por fortuna, esto es as en todos los conjuntos de caracteres.

    Por definicin, los ch a r son slo pequeos enteros, por lo que las variables y las constantes char son idnticas a las int en expresiones aritmticas. Esto es natural y conveniente; por ejemplo, c - '0 ' es una expresin entera con un valor entre 0 y 9, correspondiente a los caracteres 0 a 9 almacenados en c, por lo que es un subndice vlido para el arreglo ndigit.

    La decisin de si un carcter es dgito, espacio en blanco u otra cosa se realiza con la secuencia

    if (c > = '0' && c < = '9')+ + ndigit [c'0 '];

  • SECCION 1.6 ARREGLOS 25

    else if (c = = ' ' j c = = '\n' { ! *=== '\t')-I- + nwhite;

    else+ + nother;

    El patrn

    if (condicin,) proposicin,

    else if (condicin2) proposicin^

    elseproposicin,,

    se encuentra frecuentemente en program as como una forma de expresar una decisin mltiple. Las condiciones se evalan en orden desde el principio hasta que se satisface alguna condicin ; en ese punto se ejecuta la proposicin correspondiente, y la construccin completa termina. (Cualquier proposicin puede constar de varias proposiciones entre llaves.) Si no se satisface ninguna de las condiciones, se ejecuta la proposicin que est despus del else final, si sta existe. Cuando se omiten el else y la proposicin finales, tal como se hizo en el programa para contar palabras, no tiene lugar ninguna accin. Puede haber cualquier nmero de grupos de

    else if (condicin) proposicin

    entre el if inicial y el else final.Se recomienda, por estilo, escribir esta construccin tal como se ha mostrado;

    si cada if estuviese sangrado despus del else anterior, una larga secuencia de decisiones podra rebasar el margen derecho de la pgina.

    La proposicin switch, que se tratar en el captulo 3, proporciona otra forma de escribir una decisin mltiple, que es particularmente apropiada cuando la condicin es determinar si alguna expresin entera o de carcter corresponde con algn miembro de un conjunto de constantes. Para contrastar, se presentar una versin de este program a, usando switch, en la seccin 3.4.

    Ejercicio 1-J3. Escriba un program a que imprima el histograma de las longitudes e las palabras de su entrada. Es fcil dibujar el histograma eon las barras hori-

    /0 n tales; la orientacin vertical es un reto ms interesante.

    Ejercicio 1-14. Escriba un programa que imprima el histograma de las frecuencias con que se presentan diferentes caracteres ledos a la entrada.

  • 26 INTRODUCCION GENERAL CAPITULO I

    1.7 FuncionesEn lenguaje C, una funcin es el equivalente a una subrutina o funcin en

    Fortran, o a un procedimiento o funcin en Pascal. Una funcin proporciona una forma conveniente de encapsular algunos clculos, que se pueden emplear despus sin preocuparse de su im plantacin. Con funciones diseadas adecuadamente, es posible ignorar cmo se realiza un trabajo; es suficiente saber qu se hace. El lenguaje C hace que el uso de funciones sea fcil, conveniente y eficiente; es comn ver una funcin corta definida y empleada una sola vez, nicamente porque eso esclarece alguna parte del cdigo.

    H asta ahora slo se han utilizado funciones como printf, ge tchar y pu tehar, que nos han sido proporcionadas; ya es el momento de escribir unas pocas nosotros mismos. Dado que C no posee un operador de exponenciacin como el * * de Fortran, ilustremos el mecanismo de la definicin de una funcin al escribir la funcin pow er(m ,n), que eleva un entero m a una potencia entera y positiva n. Esto es, el valor de power(2,5) es 32. Esta funcin no es una rutina de exponenciacin prctica, puesto que slo m aneja potencias positivas de enteros pequeos, pero es suficiente para ilustracin (la biblioteca estndar contiene una funcin pow(x,y) que calcula xy).

    A continuacin se presenta la funcin pow er y un program a main para utilizarla, de m odo que se vea la estructura completa de' una vez.

    #include

    int power(int m, int n);

    /* prueba la funcin power */ main( ){

    int i;

    for (i = 0 ; i < 1 0 ; + +i)printf("%d %d %d\n", i, power(2,i), power(-3,i));

    return 0 ;

    /* power: eleva la base a la n-sima potencia; n > = 0 */int power(int base, int n){

    int i, p;

    p = 1 ;for (i = 1 ; i < = n; + + i)

    p = p * base; return p;

  • SECCION 1.7 FUNCIONES 27

    Una definicin de funcin tiene la form a siguiente:

    tipo-de-retorno nombre-de-funcin (declaracin de parmetros, si los hay){

    declaracionesproposiciones

    }Las definiciones de funcin pueden aparecer en cualquier orden y en uno o varios archivos fuente, pero una funcin no puede separarse en archivos diferentes. Si el program a fuente aparece en varios archivos, tal vez se tengan que especificar ms cosas al compilar y cargarlo que si estuviera en uno solo, pero eso es cosa del sistema operativo, no un atributo del lenguaje. Por ahora supondremos que ambas funciones estn en el mismo archivo y cualquier cosa que se haya aprendido acerca de cmo ejecutar program as en C, an funcionarn.

    La funcin pow er se invoca dos veces por m ain, en la lnea

    printf("%d %d %d\n", i, power(2,i), power(-3,i));

    Cada llamada pasa dos argumentos a pow er, que cada vez regresa un entero, al que se pone form ato y se imprime. En una expresin, power(2,i) es un entero tal como lo son 2 e i. (No todas las funciones producen un valor entero; lo que se ver en el captulo 4.)

    La primera lnea de la funcin pow er,

    int power(in base, int n)

    declara los tipos y nombres de los parm etros, as como el tipo de resultado que la funcin devuelve. Los nombres que emplea pow er para sus parm etros son locales a la funcin y son invisibles a cualquier otra funcin: otras rutinas pueden utilizar los mismos nombres sin que exista problema alguno. Esto tambin es cierto para las variables i y p: la i de pow er no tiene nada que ver con la i de main.

    Generalmente usaremos parmetro para una variable nom brada en la lista entre parntesis de la definicin de una funcin, y argumento para el valor empleado al hacer la llamada de la funcin. Los trminos argumento fo rm a l y argumento real se emplean en ocasiones para hacer la misma distincin.

    El valor que calcula pow er se regresa a m ain por medio de la proposicin re- lum , a la cual le puede seguir cualquier expresin:

    return expresin

    Una funcin no necesita regresar un valor; una proposicin return sin expresin hace que el control regrese al program a, pero no devuelve algn valor de utilidad, como se hara al caer al final de una funcin al alcanzar la llave derecha de terminacin. Adems, la funcin que llama puede ignorar el valor que regresa una funcin.

    Probablemente haya notado que hay una proposicin return al final de main. Puesto que main es una funcin com o cualquier otra, tambin puede regresar un valor a quien la invoca, que es en efecto el medio ambiente en el que el programa

  • 28 INTRODUCCION GENERAL CAPITULO 1

    se ejecuta. Tpicamente, un valor de regreso cero implica una terminacin normal; los valores diferentes de cero indican condiciones de terminacin no com unes o errneas. Para buscar la simplicidad, se han omitido hasta ahora las p roposiciones return de las funciones m ain, pero se incluirn ms adelante, como un recordatorio de que los programas deben regresar su estado final a su medio am biente.

    La declaracin

    int power(int m, int n);

    precisamente antes de m ain, indica que pow er es una funcin que espera dos argumentos int y regresa un int. Esta declaracin, a la cual se le llama funcin prototipo, debe coincidir con la definicin y uso de power. Es un error el que la definicin de una funcin o cualquier uso que de ella se haga no corresponda con su prototipo.

    Los nombres de los parm etros no necesitan coincidir; de hecho, son optativos en el prototipo de una funcin, de modo que para el prototipo se pudo haber escrito

    int power(int, int);

    No obstante, unos nombres bien seleccionados son una buena documentacin, por lo que se emplearn frecuentemente.

    Una nota histrica: La mayor modificacin entre ANSI C y las versiones anteriores es cmo estn declaradas y definidas las funciones. En la definicin original de C, la funcin pow er se pudo haber escrito de la siguiente manera:

    /* power: eleva la base a n-sima potencia; n > = 0 *//* (versin en estilo antiguo) */power(base, n) int base, n;{

    int i, p;

    p = 1 ;for (i = 1 ; i < = n; + + i)

    p p * base; return p;

    }

    Los parm etros se nom bran entre los parntesis y sus tipos se declaran antes deabrir la llave izquierda; los parm etros que no se declaran se tom an como int.{El cuerpo de la funcin es igual a la anterior.)

    La declaracin de power al inicio del programa pudo haberse visto como sigue:

    int power( );

    No se permiti ninguna lista de parm etros, de modo que el com pilador no pudo revisar con facilidad que pow er fuera llamada correctamente. De hecho, puesto

  • SECCION 1.8 ARGUMENTOSLLAMADA POR VALOR 29

    que por omisin se poda suponer que pow er regresaba un entero, toda la declaracin podra haberse omitido.

    La nueva sintaxis de los prototipos de funciones permite que sea mucho ms fcil para el com pilador detectar errores en el nmero o tipo de argumentos. El viejo estilo de declaracin y definicin an funciona en ANSI C, al menos por un periodo de transicin, pero se recomienda ampliamente que se utilice la nueva form a si se tiene un compilador que la maneje.

    Ejercicio 1-15. Escriba de nuevo el program a de conversin de tem peratura de la seccin 1.2, de m odo que utilice una funcin para la conversin.

    1.8 Argumentpsllamadas por valor

    Hay un aspecto de las funciones de C que puede parecer poco familiar a los programadores acostum brados a otros lenguajes, particularm ente Fortran. En C, todos los argumentos de una funcin se pasan por valor . Esto significa que la funcin que se invoca recibe los valores de sus argumentos en variables tem porales y no en las originales. Esto conduce a algunas propiedades diferentes a las que se ven en lenguajes con llamadas por referencia como Fortran o con parmetros v a ren Pascal, en donde la rutina que se invoca tiene acceso al argum ento original, ilo a una copia local.

    La diferencia principal es que en C la funcin que se invoca no puede alterar directamente una variable de la funcin que hace la llam ada; slo puede m odificar su copia privada y temporal.

    Sin embargo, la llam ada por valor es una ventaja, no una desventaja. Por lo comn, esto conduce a elaborar program as ms compactos con pocas variables extraas, debido a que los parm etros se tratan en la funcin invocada como variables locales convenientemente inicializadas. Por ejemplo, he aqu una versin de pow er que utiliza esta propiedad.

    /* power: eleva la base a la n-sima potencia; n > = 0 ; versin 2 */int power(int base, int n){

    int p;

    for (p = 1 ; n > 0 ; n) p = p * base;

    return p;}

    El parm etro n se utiliza como una variable tem poral, y se decrementa (up ciclo for que se ejecuta hacia atrs) hasta que llega a cero; ya no es necesaria la variable i- Cualquier cosa que se le haga a n dentro de pow er no tiene efecto sobre el argumento con el que se llam originalmente power.

  • 30 INTRODUCCION GENERAL CAPITULO 1

    Cuando sea necesario, es posible hacer que una funcin modifique una variable dentro de una rutina invocada. La funcin que llama debe proporcionar la direccin de la variable que ser cam biada (tcnicamente un apuntador a la variable), y la funcin que se invoca debe declarar que el parm etro sea un apuntador y tenga acceso a la variable indirectamente a travs de l. Los apuntadores se tratarn en el captulo 5.

    La historia es diferente con los arreglos. C uando el nom bre de un arreglo se emplea como argum ento, el valor que se pasa a la funcin es la localizacin o la direccin del principio del arreglo no hay copia de los elementos del arreglo. Al colocarle subndices a este valor, la funcin puede tener acceso y alterar cualquier elemento del arreglo. Este es el tem a de la siguiente seccin.

    1.9 Arreglos de caracteres

    El tipo de arreglo ms comn en C es el de caracteres. Para ilustrar el uso de arreglos de caracteres y funciones que los m anipulan, escriba un program a que lea un conjunto de lneas de texto e im prim a la de mayor longitud. El pseudoc- digo es bastante simple:

    while (hay otra lnea)if (es ms larga que la anterior ms larga)

    gurdalaguarda su longitud

    imprime la lnea ms larga

    Este pseudocdigo deja en claro que el program a se divide naturalm ente en partes. Una trae una nueva lnea, otra la prueba y el resto controla el proceso.

    Puesto que la divisin de las partes es muy fina, lo correcto ser escribirlas de ese m odo. As pues, escribamos primero una funcin getline para extraer la siguiente lnea de la entrada. Tratarem os de hacer a la funcin til en otros contextos. Al menos, getline tiene que regresar una seal acerca de la posibilidad de un fin de archivo; un diseo de ms utilidad deber retornar la longitud de la lnea, o cero si se encuentra el fin de archivo. Cero es un regreso de fin de archivo aceptable debido a que nunca es una longitud de lnea vlida. Cada lnea de texto tiene al menos un carcter; incluso una lnea que slo contenga un carcter nueva lnea tiene longitud 1.

    Cuando se encuentre una lnea que es mayor que la anteriorm ente ms larga, se debe guardar en algn lugar. Esto sugiere una segunda funcin copy, para copiar la nueva lnea a un lugar seguro.

    Finalmente, se necesita un program a principal para controlar getline y copy. El resultado es el siguiente:

  • SECCION 1.9 ARREGLOS DE CA RACTERES 31

    #include #define MAXLINE 1000 /* tamao mximo de la lnea de entrada */int getline(char line[], int maxline); void copy(char to[], char from[]);

    /* imprime la lnea de entrada ms larga */ main( )

    char line[MAXLINE];

    int len; int max;

    /* longitud actual de la lnea *// * .xima longitud vista hasta el momento */

    /* lnea de entrada actual */char longest[MAXLINE]; /* la lnea ms larga se guarda aqu */

    max = 0 ;while ((len = geine(line, MAXLINE)) > 0)

    if (len > max) { max = len; copy(longest, line);

    }if (max > 0 ) /* hubo una lnea */

    printf("%s", longest); return 0 ;

    }

    /* getline: lee una lnea en s, regresa su longitud / int getline(char s[], int lim){

    int c, i;

    for (i = 0; ic lim 1 && (c = getchar( )) !=EOF && c! = '\n'; + + i)

    /* copy: copia 'from' en 'to'; supone que to es suficientemente grande */ void copy(char to[], char from[])

    s[i] = c; if (c = = '\n') {

    s[i] = c;+ +i;

    int i;

    i = 0 ;while ((to[i] = from[i]) != '\0 ')

    + +i;

  • 32 INTRODUCCION GENERAL CAPITULO I

    Las funciones getline y copy estn declaradas al principio del program a, que se supone est contenido en un archivo.

    main y getline se comunican a travs de un par de argumentos y un valor de retorno. En getline los argum entos se declaran por la lnea

    int getline(char s[], int lim)

    que especifica que el primer argum ento, s, es un arreglo, y el segundo, lim, es un entero. El propsito de proporcionar el tam ao de un arreglo es fijar espacio de almacenamiento contiguo. La longitud del arreglo s no es necesaria en getline, puesto que su tam ao se fija en m ain. En getline se utiliza re turn para regresar un valor a quin lo llama, tal como hizo la funcin pow er. Esta lnea tambin declara que getline regresa un int; puesto que int es el valor de retorno por omisin, puede suprimirse.

    Algunas funciones regresan un valor til; otras, como copy, se emplean nicamente por su efecto y no regresan un valor. El tipo de retorno de copy es void, el cual establece explcitamente que ningn valor se regresa.

    En getline se coloca el carcter '\0 ' (carcter nulo , cuyo valor es cero) al final del arreglo que est creando, para marcar el fin de la cadena de caracteres. Esta convencin tambin se utiliza por el lenguaje C; cuando una constante de carcter como

    hola\n"

    aparece en un programa en C, se almacena como un arreglo que contiene los caracteres de la cadena y term ina con un '\0 ' para m arcar el fin.

    \n \0

    La especificacin de form ato %s dentro de printf espera que el argum ento correspondiente sea una cadena representada de este modo; copy tambin se basa en el hecho de que su argumento de entrada se term ina con '\0 ', y copia este carcter dentro del argumento de salida. (Todo esto implica que '\ 0 \ no es parte de un texto norm al.)

    Es til mencionar de paso que aun un program a tan pequeo como ste presenta algunos problemas de diseo. Por ejemplo, qu debe hacer m ain si encuentra una lnea que es mayor que si^ lmite? getline trabaja en form a segura, en ese caso detiene la recopilacin cuando el arreglo est lleno, aunque no encuentre el carcter nueva lnea. Probando la longitud y el ltimo carcter devuelto, main puede determinar si la lnea fue demasiado larga, y entonces realiza el tratamiento que se desee. Por brevedad, hemos ignorado el asunto.

    Para un usuario de getline no existe form a de saber con anticipacin cun larga podr ser una lnea de entrada, por lo que getline revisa un posible desbordamiento (overflon ;). Por otro lado, el usuario de copy ya conoce (o lo puede averiguar) cul es el tam ao de la cadena, por lo que decidimos no agregar comprobacin de errores en ella.

  • SECCION 1.10 VARIABLES EXTERNAS Y ALCANCE 33

    Ejercicio 1-16. C orrija la rutina principal del program a de la lnea ms larga de modo que imprima correctamente la longitud de lneas de entrada arbitrariam ente largas, y tanto texto como sea posible.

    Ejercicio 1-17. Escriba un program a que imprima todas las lneas de entrada que sean mayores de 80 caracteres.

    Ejercicio 1-18. Escriba un program a que elimine los blancos y los tabuladores que estn al final de cada lnea de entrada, y que borre completamente las lneas en blanco.

    Ejercicio 1-19. Escriba una funcin reverse(s) que invierta la cadena de caracteres s. Usela para escribir un program a que invierta su entrada, lnea a lnea.

    1.10 Variables externas y alcanceLas variables que estn en m ain, tal como line, longest, etc., son privadas

    o locales a ella. Debido a que son declaradas dentro de m ain, ninguna otra funcin puede tener acceso directo a ellas. Lo mismo tambin es vlido para variables de otras funciones; por ejemplo, la variable i en getline no tiene relacin con la i que est en copy. Cada variable local de una funcin comienza a existir slo cuando se llama a la funcin, y desaparece cuando la funcin term ina. Esto es por lo que tales variables son conocidas como variables automticas, siguiendo la terminologa de otros lenguajes. Aqu se utilizar en adelante el trm ino automtico para hacer referencia a esas variables locales. (En el captulo 4 se discute la categora de almacenamiento esttica, en la que las variables locales s conservan sus valores entre llamadas.)

    Debido a que las variables locales aparecen y desaparecen con la invocacin de funciones, no retienen sus valores entre dos llamadas sucesivas, y deben ser inicia- lizadas explcitamente en cada entrada. De no hacerlo, contendrn basura .

    Como una alternativa a las variables autom ticas, es posible definir variables que son externas a todas las funciones, esto es, variables a las que toda funcin puede tener acceso por su nom bre. (Este mecanismo es parecido al COMMON de Fortran o a las variables de Pascal declaradas en el bloque ms exterior.) Debido a que es posible tener acceso global a las variables externas, stas pueden ser usadas en lugar de listas de argum entos para cpmunicar datos entre funciones. Adems, puesto que las variables externas se mantienen permanentemente en existencia, en lugar de aparecer y desaparecer cuando se llaman y terminan las funciones, mantienen sus valores aun despus de que regresa la funcin que los fij.

    Una variable externa debe definirse, exactamente una vez, fuera de cualquier funcin; esto fija un espacio de almacenamiento para ella. La variable tambin debe declararse en cada funcin que desee tener acceso a ella; esto establece el tipo de la variable. La declaracin debe ser una proposicin extern explcita, o bien Puede estar implcita en el contexto. Para concretar la discusin, reescribamos el

  • 34 INTRODUCCION GENERAL CAPITULO 1

    program a de la lnea ms larga con lin e, longest y max como variables externas. Esto requiere cambiar las llam adas, declaraciones y cuerpos de las tres funciones.

    #include

    #define MAXLINE 1000 /* mximo tamao de una lnea de entrada */

    int max; /* mxima longitud vista hasta el momento */char line [MAXLINE]; /* lnea de entrada actual */char longest [MAXLINE]; /* la lnea ms larga se guarda aqu */

    int getline(void); void copy(void);

    /* imprime la lnea de entrada ms larga; versin especializada */ main( ){

    int len;extern int max; extern char longest [];

    max = 0 ;while ((len = getline( )) > 0 )

    if (len > max) { max = len; copy( );

    }if (max > 0 ) /* hubo una lnea */

    printf("%s", longest); return 0 ;

    }

    /* getline: versin especializada */ int getline(void){

    int c, i;extern char line[J;

    for (i = 0; i < MAXLINE-1&& (c = getchar( )) != EOF && c != '\n'; + +i )

    line[i] = c;

  • SECCION 1.10 VARIABLES EXTERNAS Y ALCANCE 35

    if (C = = '\n ') { line [i] = c;+ + i;

    }line [i] = '\0 ';return i;

    }

    /* copy: versin especializada */void copy(void){

    int i;extern char line[], longest[];

    i = 0 ;while ((longestfi] = line[i]) ! = '\0 ')

    + + i;}

    Las variables externas de main, getline y copy estn definidas en las primeras lneas del ejemplo anterior, lo que establece su tipo y causa que se les asigne espacio de almacenamiento. Desde el punto de vista sintctico, las definiciones externas son exactamente como las definiciones de variables locales, pero puesto que ocurren fuera de las funciones, las variables son externas. Antes de que una funcin pueda usar una variable externa, se debe hacer saber el nombre de la variable a la funcin. U na form a de hacer esto es escribir una declaracin ex tern dentro de la funcin; la declaracin es la misma que antes, excepto por la palabra reservada extern.

    Bajo ciertas circunstancias, la declaracin extern se puede omitir. Si la definicin de una variable externa ocurre dentro del archivo fuente antes de su uso por una funcin en particular, entonces no es necesario el uso de una declaracin extern dentro de la funcin. La declaracin ex tern en main, getline y copy es, por lo tanto, redundante. De hecho, una prctica comn, es poner las definiciones de todas las variables externas al principio del archivo fuente y despus omitir to das las declaraciones extern.

    Si el program a est en varios archivos fuente y una variable se define en archivo y se utiliza en archivo2 y archivo3, entonces se necesitan declaraciones extern en archi\o2 y archi\o3 para conectar las ocurrencias de la variable. La prctica comn es reunir declaraciones ex tern de variables y funciones en un archivo separado, llamado histricamente header, que es incluido por # in c lu d e al principio de cada archivo fuente. El sufijo .h se usa por convencin para nombres de hea- ders. Las funciones de la biblioteca estndar, por ejemplo, estn declaradas en headers como < s td io .h > . Este tem a se trata ampliamente en el captulo 4, y la biblioteca en el captulo 7 y en el apndice B.

  • 36 INTRODUCCION GENERAL CAPITULO 1

    Puesto que las versiones especializadas de getline y copy no tienen argumentos, la lgica sugerira que sus prototipos al principio del archivo deben ser getli- ne( ) y copy( ). Pero por com patibilidad con program as de C anteriores, el estndar tom a a una lista vaca como una declaracin al viejo estilo, y suspende toda revisin de listas de argumentos; para una lista explcitamente vaca debe emplearse la palabra void. Esto se