Titivillus 07.07

444

Transcript of Titivillus 07.07

Page 1: Titivillus 07.07
Page 2: Titivillus 07.07

Elmundodelacomputaciónhasufridounarevolucióndesdelapublicación,en1978,deEllenguajedeprogramaciónC.Lasgrandescomputadorassonahoramuchomásgrandes,ylascomputadoraspersonalestienencapacidadesquerivalizanconlosmainframesdehaceunadécada.TambiénellenguajeChacambiadoenesetiempo,aunquesóloenformamodesta,ysehaextendidomásalládeloquefueronsusorígenescomoellenguajedelsistemaoperativoUNIX.

LacrecientepopularidaddeC,loscambiosenellenguajealolargodelosaños,ylacreacióndecompiladoresporgruposnoinvolucradosensudiseño,secombinaronparademostrarlanecesidaddeunadefinicióndellenguajemásprecisaycontemporáneaquelaqueproporcionólaprimeraedicióndeestelibro.En1983,elAmericanNationalStandardsInstitute(ANSI)establecióuncomitécuyospropósitoseranproducir“unadefiniciónnoambiguadellenguajeCe,independientedelamáquina”,cuidandolaconservacióndesuespíritu.ElresultadoeselestándarANSIparaellenguajeC.

Page 3: Titivillus 07.07

BryanW.KernighanyDennisM.Ritchie

EllenguajedeprogramaciónC

ConbaseenelANSIC

ePubr1.0

Titivillus07.07.17

Page 4: Titivillus 07.07

Títulooriginal:TheCProgrammingLanguage

BryanW.KernighanyDennisM.Ritchie,1988

Traducción:NéstorGómezMuñoz

Traduccióndela1ªedición:JuanJoséPadilla

Primeraedicióneninglés:1978.Enespañol:1985

Segundaedicióneninglés:1988.Enespañol:1991

Editordigital:Titivillus

ePubbaser1.2

Page 5: Titivillus 07.07

Prefacio

Elmundodelacomputaciónhasufridounarevolucióndesdelapublicación,en1978,deEllenguajedeprogramaciónC.Lasgrandescomputadorassonahoramuchomásgrandes,ylascomputadoraspersonalestienencapacidadesquerivalizanconlosmainframesdehaceunadécada.TambiénellenguajeChacambiadoenesetiempo,aunquesóloenformamodesta,ysehaextendidomásalládeloquefueronsusorígenescomoellenguajedelsistemaoperativoUNIX.

LacrecientepopularidaddeC,loscambiosenellenguajealolargodelosaños,ylacreacióndecompiladoresporgruposnoinvolucradosensudiseño,secombinaronparademostrarlanecesidaddeunadefinicióndellenguajemásprecisaycontemporáneaquelaqueproporcionólaprimeraedicióndeestelibro.En1983,elAmericanNationalStandardsInstitute(ANSI)establecióuncomitécuyospropósitoseranproducir“unadefiniciónnoambiguadellenguajeCe,independientedelamáquina”,cuidandolaconservacióndesuespíritu.ElresultadoeselestándarANSIparaellenguajeC.

Elestándarformalizaconstruccionessugeridasperonodescritasenlaprimeraedición,particularmentelaasignacióndeestructuraylasenumeraciones.Proporcionaunanuevaformadedeclaracióndefunciones,quepermiterevisarcomparativamentesudefiniciónyuso.Especificaunabibliotecaestándar,conunconjuntoextensivodefuncionespararealizarlaentradaysalida,laadministracióndememoria,lamanipulacióndecadenasytareassemejantes.Precisaelcomportamientodecaracterísticasquenosemencionaronenladefiniciónoriginal,yalmismotiempoestableceexplícitamentecuálesaspectosdellenguajetienenaúndependenciademáquina.

EstasegundaedicióndeEllenguajedeprogramaciónClodescribetalcomolodefinióelestándarANSI.(Enelmomentodeescribirestaedición,elestándarseencontrabaenlaetapafinalderevisión;seesperabasuaprobaciónafinalesde1988.Lasdiferenciasentreloquesehadescritoaquíylaformafinaldeberánsermínimas.)Aunquehemoshechoanotacionesenloslugaresdondeellenguajehaevolucionado,preferimosescribirexclusivamenteenlanuevaforma.Engeneralestonohaceunadiferenciasignificativa;elcambiomásvisibleeslanuevaformadedeclaraciónydefinicióndefunciones.Losmodernoscompiladoresmanejanyalamayoríadelasposibilidadesdelestándar.

Hemostratadodemantenerlabrevedaddelaprimeraedición.EllenguajeCnoesgrande,ynoleestábienungranlibro.Hemosmejoradolaexposicióndecaracterísticascríticas,comolosapuntadores,quesonpartecentralenlaprogramaciónconC.Hemosredefinidolosejemplosoriginalesyagregamosejemplosnuevosenvarioscapítulos.Porejemplo,seaumentóeltratamientodedeclaracionescomplicadasconprogramasqueconviertendeclaracionesenpalabrasyviceversa.Comoantes,todoslosejemplossehanprobadodirectamenteapartirdeltexto,elcualestádiseñadodemaneraquelopuedaleerlamáquina.

ElapéndiceA,manualdereferencia,noeselestándar,sinoquenuestraintenciónfuetrasladarlaesenciadelestándaraunespaciomáspequeño.Estáhechoconelánimodequeproporcioneunafácilcomprensiónparalosprogramadores,peronocomounadefinicióndellenguajeparaquienesescribencompiladores—esepapelpropiamentelecorrespondealestándarensí.ElapéndiceBesunresumendelasposibilidadesdelabibliotecaestándar.Tambiéntieneelpropósitodeserunareferenciaparaprogramadores,noparaimplantadores.EnelapéndiceCseofreceunresumendeloscambiosdelaversiónoriginal.

Page 6: Titivillus 07.07

Comomencionamosenelprefacioalaprimeraedición,C“sellevabien,enlamedidaenqueaumentanuestraexperienciaconél”.Conunadécadamásdeexperiencia,aúnlosentimosasí.DeseamosqueestelibroleayudeaaprenderellenguajeCytambiéncómousarlo.

Tenemosunprofundoreconocimientohacialosamigosquenosayudaronaproducirestasegundaedición.JonBentley,DougGwyn,DougMcIlroy,PeterNelsonyRobPikenosdieronvaliososcomentariossobrecasicadapáginadelborradordeestemanuscrito.EstamosagradecidosporlacuidadosalecturadeAlAho,DennisAllison,JoeCampbell,G.R.Emlin,KarenFortgang,AllenHolub,AndrewHume,DaveKristol,JohnLinderman,DaveProsser,GeneSpafford,yChrisVanWyk.TambiénrecibimosútilessugerenciasdeBillCheswick,MarkKernighan,AndyKoening,RobinLake,TomLondon,JimReeds,ClovisTondoyPeterWeinberger.DaveProsserrespondiómuchaspreguntasdetalladasacercadelestándarANSI.UtilizamosextensivamenteelintérpretedeC++deBjarneStroustrup,paralapruebalocaldenuestrosprogramas,yDaveKristolnosofrecióuncompiladorANSICparalaspruebasfinales.RichDrechslernosayudógrandementeconlacomposición.

Nuestrosinceroagradecimientoatodos.

BrianW.Kernighan

DennisM.Ritchie

Page 7: Titivillus 07.07

Prefacioalaprimeraedición

Cesunlenguajedeprogramacióndepropósitogeneralqueofrececomoventajaseconomíadeexpresión,controldeflujoyestructurasdedatosmodernosyunricoconjuntodeoperadores.Además,Cnoesunlenguajede“muyaltonivel”ni“grande”,ynoestáespecializadoenalgunaáreaespecialdeaplicación.Perosuausenciaderestriccionesysugeneralidadlohacenmásconvenienteyefectivoparamuchastareasqueotroslenguajessupuestamentemáspoderosos.Originalmente,CfuediseñadoparaelsistemaoperativoUNIXyDennisRitchieloimplantósobreelmismoenlaDECPDP-11.Elsistemaoperativo,elcompiladordeCyesencialmentetodoslosprogramasdeaplicacióndeUNIX(incluyendotodoelsoftwareutilizadoparaprepararestelibro)estánescritosenC.Tambiénexistencompiladoresparalaproducciónenotrasmáquinas,incluyendolaIBMSystem/370,laHoneywell6000ylaInterdata8/32.EllenguajeCnoestáligadoaningúnhardwareosistemaenparticularyesfácilescribirprogramasquecorreránsincambiosencualquiermáquinaquemanejeC.

LafinalidaddeestelibroesayudarallectoraaprendercómoprogramarenC.Contieneunaintroduccióngeneralparahacerquelosnuevosusuariosseinicienlomásprontoposible,capítulosseparadossobrecadacaracterísticaimportanteyunmanualdereferencia.Lamayoríadelasexposicionesestánbasadasenlalectura,escriturayrevisióndeejemplos,másqueenelsimpleestablecimientodereglas.Ensumayoría,losejemplossonprogramasrealesycompletos,nofragmentosaislados.Todoslosejemploshansidoprobadosdirectamenteapartirdeltexto,elcualestáenformalegibleparalamáquina.Ademásdedemostrarcómohacerunusoefectivodellenguaje,dondehasidoposible,tratamosdeilustraralgoritmosútilesyprincipiosdebuenestiloydiseño.

Ellibronoesunmanualdeintroducciónalaprogramación;sesuponeenélfamiliaridadconlosconceptosbásicosdeprogramación,comovariables,proposicionesdeasignación,ciclosyfunciones.Noobstante,unprogramadornovatodebersercapazdeleeryobtenerlosconceptosdellenguaje,aunqueleayudaríalacooperacióndeuncolegamásexperimentado.

Deacuerdoconnuestraexperiencia,Chademostradoserunlenguajeagradable,expresivoyversátilparaunaampliavariedaddeprogramas.Esfácildeaprenderyseobtienenmejoresresultadosamedidaqueaumentanuestraexperienciaconél.Deseamosqueestelibroleayudeallectorausarlocorrectamente.

Lascríticasysugerenciasdemuchosamigosycolegashanaumentadomuchísimolosconceptosdeestelibroyhasidounplacerescribirlo.EnparticularnuestroagradecimientoaMikeBianchi,JimBlue,StuFeldman,DougMcIlroy,BillRoome,BobRosinyLarryRoslerqueleyeroncuidadosamentelasnumerosasversiones.TambiénagradecemosAlAho,SteveBourne,DanDvorak,ChuckHaley,DebbieHaley,MarionHarris,RickHolt,SteveJohnson,JohnMashey,BobMitze,RalphMuha,PeterNelson,ElliotPinson,BillPlauger,JerrySpivack,KenThompsonyPeterWeinbergerporsusvaliososcomentariosatravésdevariasetapas;aMikeLeskyJoeOssanna,porsuinvaluableayudaenlaimpresión.

BrianW.Kernighan

DennisM.Ritchie

Page 8: Titivillus 07.07

Introducción

CesunlenguajedeprogramacióndepropósitogeneralquehasidoestrechamenteasociadoconelsistemaUNIXendondefuedesarrolladopuestoquetantoelsistemacomolosprogramasquecorrenenélestánescritosenlenguajeC.Sinembargo,estelenguajenoestáligadoaningúnsistemaoperativonianingunamáquina,yaunqueselellama“lenguajedeprogramacióndesistemas”debidoasuutilidadparaescribircompiladoresysistemasoperativos,seutilizaconigualeficaciaparaescribirimportantesprogramasendiversasdisciplinas.

MuchasdelasideasimportantesdeCprovienendellenguajeBCPL,desarrolladoporMartinRichards.LainfluenciadeBCPLsobreCsecontinuóindirectamenteatravésdellenguajeB,elcualfueescritoporKenThompsonen1970paraelprimersistemaUNIXdelaDECPDP-7.

BCPLyBsonlenguajes“carentesdetipos”.Encontraste,Cproporcionaunavariedaddetiposdedatos.Lostiposfundamentalessoncaracteres,enterosynúmerosdepuntoflotantedevariostamaños.Además,existeunajerarquíadetiposdedatosderivados,creadosconapuntadores,arreglos,estructurasyuniones.Lasexpresionesseformanapartirdeoperadoresyoperandos;cualquierexpresión,incluyendounaasignaciónounallamadaafunción,puedeserunaproposición.Losapuntadoresproporcionanunaaritméticadedireccionesindependientedelamáquina.

Cproporcionalasconstruccionesfundamentalesdecontroldeflujoqueserequierenenprogramasbienestructurados:agrupacióndeproposiciones,tomadedecisiones(if-else),seleccióndeuncasoentreunconjuntodeellos(switch),iteraciónconlacondicióndeparoenlapartesuperior(while,for)oenlaparteinferior(do),yterminaciónprematuradeciclos(break).

Lasfuncionespuedenregresarvaloresdetiposbásicos,estructuras,unionesoapuntadores.Cualquierfunciónpuedeserllamadarecursivamente.Lasvariableslocalessonnormalmente“automáticas”,ocreadasdenuevoconcadainvocación.Ladefinicióndeunafunciónnopuedeestaranidada,perolasvariablespuedenestardeclaradasenunamodalidadestructuradaporbloques.LasfuncionesdeunprogramaenCpuedenexistirenarchivosfuenteseparados,quesecompilandemaneraseparada.Lasvariablespuedenserinternasaunafunción,externasperoconocidassólodentrodeunarchivofuente,ovisiblesalprogramacompleto.

Unpasodepreprocesamientorealizasubstitucióndemacroseneltextodelprograma,inclusióndeotrosarchivosfuenteycompilacióncondicional.

Cesunlenguajederelativo“bajonivel”.Estacaracterizaciónnoespeyorativa,simplementesignificaqueCtrataconelmismotipodeobjetosquelamayoríadelascomputadoras,llámensecaracteres,númerosydirecciones.Estospuedensercombinadosycambiadosdesitioconlosoperadoresaritméticosylógicosimplantadospormáquinasreales.

Cnoproporcionaoperacionesparatratardirectamenteconobjetoscompuestos,talescomocadenasdecaracteres,conjuntos,listasoarreglos.Noexistenoperacionesquemanipulenunarregloounacadenacompleta,aunquelasestructuraspuedencopiarsecomounaunidad.Ellenguajenodefineningunafacilidadparaasignacióndealmacenamientoquenosealadedefiniciónestáticayladisciplinadepilasprovistaporlasvariableslocalesdefunciones;noempleaheapnirecolectordebasura.Finalmente,Censímismonoproporcionacapacidadesdeentrada/salida;nohayproposiciones

Page 9: Titivillus 07.07

READoWRITE,nimétodospropiosdeaccesoaarchivos.Todosesosmecanismosdealtoniveldebenserproporcionadosporfuncionesllamadasexplícitamente.

Demanerasemejante,Csolamenteofreceuncontroldeflujofranco,ylineal:condiciones,ciclos,agrupamientosysubprogramas,peronomultiprogramación,operacionesparalelas,sincronizaciónnicorrutinas.

Aunquelaausenciadealgunadeesascapacidadespuedeparecercomounagravedeficiencia(“¿significaquesetienequellamaraunafunciónparacomparardoscadenasdecaracteres?”),elmantenerallenguajedeuntamañomodestotienebeneficiosreales.PuestoqueCesrelativamentepequeño,sepuededescribirenunpequeñoespacioyaprenderseconrapidez.Unprogramadorpuederazonablementeesperarconocer,entenderyutilizarenverdadlatotalidaddellenguaje.

Pormuchosaños,ladefinicióndeCfueelmanualdereferenciadelaprimeraedicióndeEllenguajedeprogramaciónC.En1983,elAmericanNationalStandardsInstitute(ANSI)establecióuncomitéparaproporcionarunamodernaycomprensibledefinicióndeC.Ladefiniciónresultante,elestándarANSIo“ANSIC”,seesperabafueraaprobadaafinesde1988.Lamayoríadelascaracterísticasdelestándaryaseencuentransoportadasporcompiladoresmodernos.

Elestándarestábasadoenelmanualdereferenciaoriginal.Ellenguajehacambiadorelativamentepoco;unodelospropósitosdelestándarfueasegurarquelamayoríadelosprogramasexistentespudiesenpermanecerválidoso,almenos,queloscompiladorespudieranproducirmensajesdeadvertenciaacercadelnuevocomportamiento.

Paralamayoríadelosprogramadores,elcambiomásimportanteesunanuevasintaxisparadeclararydefinirfunciones.Unadeclaracióndefunciónahorapuedeincluirunadescripcióndelosargumentosdelafunción;lasintaxisdeladefinicióncambiaparacoincidir.Estainformaciónextrapermitequeloscompiladoresdetectenmásfácilmenteloserrorescausadosporargumentosquenocoinciden;deacuerdoconnuestraexperiencia,esunaadiciónmuyútilallenguaje.

Existenotroscambiosdemenorescalaenellenguaje.Laasignacióndeestructurasyenumeraciones,quehaestadoampliamentedisponible,esahoraparteoficialdellenguaje.Loscálculosdepuntoflotantepuedenahorarealizarseconprecisiónsencilla.Laspropiedadesdelaaritmética,especialmenteparatipossinsigno,estánesclarecidas.Elpreprocesadoresmáselaborado.Lamayorpartedeesoscambiossólotendránefectossecundariosparalamayoríadelosprogramadores.

UnasegundacontribuciónsignificativadelestándaresladefinicióndeunabibliotecaqueacompañeaC.Estaespecificafuncionesparateneraccesoalsistemaoperativo(porejemplo,leerdearchivosyescribirenellos),entradaysalidaconformato,asignacióndememoria,manipulacióndecadenasyotrasactividadessemejantes.Unacoleccióndeencabezadores(headers)estándarproporcionanunaccesouniformealasdeclaracionesdefuncionesytiposdedatos.Losprogramasqueutilizanestabibliotecaparainteractuarconunsistemaanfitriónestánaseguradosdeuncomportamientocompatible.Lamayorpartedelabibliotecaestáestrechamentemodeladaconbaseenla“bibliotecaE/Sestándar”delsistemaUNIX.Estabibliotecasedescribióenlaprimeraediciónyhasidotambiénampliamenteutilizadaenotrossistemas.Denuevo,lamayoríadelosprogramadoresnonotaránmuchoelcambio.

DebidoaquelostiposdedatosyestructurasdecontrolprovistasporCsonmanejadasdirectamenteporlamayoríadelascomputadoras,labibliotecadeejecución(run-time)requeridaparaimplantarprogramasautocontenidosespequeña.Lasfuncionesdelabibliotecaestándarúnicamentesellamanenformaexplícita,demaneraquesepuedenevitarcuandonosenecesitan.LamayorpartepuedeescribirseenC,yexceptopor

Page 10: Titivillus 07.07

detallesocultosdelsistemaoperativo,ellasmismassonportátiles.

AunqueCcoincideconlascapacidadesdemuchascomputadoras,esindependientedecualquierarquitectura.Conunpocodecuidadoesfácilescribirprogramasportátiles,estoes,programasquepuedancorrersincambiosenunavariedaddemáquinas.Elestándarexplicalosproblemasdelatransportabilidad,yprescribeunconjuntodeconstantesquecaracterizanalamáquinaenlaqueseejecutaelprograma.

Cnoesunlenguajefuertementetipificado,sinoque,alevolucionar,suverificacióndetiposhasidoreforzada.LadefiniciónoriginaldeCdesaprobó,peropermitió,elintercambiodeapuntadoresyenteros;estosehaeliminadoyelestándarahorarequierelaadecuadadeclaraciónylaconversiónexplícitaqueyahasidoobligadaporlosbuenoscompiladores.Lanuevadeclaracióndefuncionesesotropasoenestadirección.Loscompiladoresadvertirándelamayoríadeloserroresdetipo,ynohayconversiónautomáticadetiposdedatosincompatibles.Sinembargo,Cmantienelafilosofíabásicadequelosprogramadoressabenloqueestánhaciendo;sólorequierequeestablezcansusintencionesenformaexplícita.

Comocualquierotrolenguaje,Ctienesusdefectos.Algunosdelosoperadorestienenlaprecedenciaequivocada;algunoselementosdelasintaxispuedensermejores.Apesardetodo,Chaprobadoserunlenguajeextremadamenteefectivoyexpresivoparaunaampliavariedaddeprogramasdeaplicación.

Ellibroestáorganizadocomosigue.Elcapítulo1esunaintroducciónorientadaalapartecentraldeC.Elpropósitoeshacerqueellectorseinicietanprontocomoleseaposible,puestoquecreemosfirmementequelaformadeaprenderunnuevolenguajeesescribirprogramasenél.Laintroducciónsuponeunconocimientoprácticodeloselementosbásicosdelaprogramación;nohayunaexplicacióndecomputadoras,decompilación,nidelsignificadodeunaexpresióncomon=n+1.Aunquehemostratadodemostrartécnicasútilesdeprogramaciónendondefueposible,laintencióndellibronoesladeseruntextodeconsultasobreestructurasdedatosyalgoritmos;cuandonosvimosforzadosahacerunaelección,noshemosconcentradoenellenguaje.

Enloscapítulosdel2al6sediscutenvariosaspectosdeCenmayordetalleymásformalmentedeloquesehaceenelcapítulo1,aunqueelénfasisestáaúnenlosejemplosdeprogramascompletos,másqueenfragmentosaislados.Elcapítulo2tratadelostiposbásicosdedatos,operacionesyexpresiones.Elcapítulo3tratasobrecontroldeflujo:if-else,switch,while,for,etc.Enelcapítulo4secubrenfuncionesylaestructuradeunprograma—variablesexternas,reglasdealcance,archivosfuentemúltiplesyotrosaspectos—ytambiénabarcaalpreprocesador.Elcapítulo5discutesobreapuntadoresyaritméticadedirecciones.Elcapítulo6cubreestructurasyuniones.

Elcapítulo7describelabibliotecaestándar,lacualproporcionaunainterfazcomúnconelsistemaoperativo.EstabibliotecaestádefinidaporelestándarANSIyseintentaquesetengaentodaslasmáquinasquemanejanC;así,losprogramasquelausenparaentrada,salidayotrosaccesosalsistemaoperativosepuedantransportardeunsistemaaotrosincambios.

Elcapítulo8describeunainterfazentrelosprogramasenCyelsistemaoperativoUNIX,concentrándoseenentrada/salida,elsistemadearchivosylaasignacióndememoria.AunquealgodeestecapítuloesespecíficodesistemasUNIX,losprogramadoresqueusenotrossistemasdetodasmanerasencontraránaquímaterialdeutilidad,incluyendoalgunacomprensiónacercadecómoestáimplantadaunaversióndelabibliotecaestándar,asícomosugerenciasparaobteneruncódigoportátil.

ElapéndiceAcontieneunmanualdeconsultadellenguaje.ElinformeoficialdelasintaxisylasemánticadeCesensíelestándarANSI.Esedocumento,sinembargo,

Page 11: Titivillus 07.07

estáprincipalmentepensadoparaquienesescribencompiladores.Elmanualdeconsultadeestelibrotransmiteladefinicióndellenguajeenunaformamásconcisaysinelmismoestilolegalista.ElapéndiceBesunresumendelabibliotecaestándar,denuevomásparausuariosqueparaimplantadores.ElapéndiceCesunbreveresumendeloscambiosdellenguajeoriginal.Aunque,encasodeduda,elestándaryelcompiladorenusoquedancomolasautoridadesfinalessobreellenguaje.

Page 12: Titivillus 07.07

CAPÍTULO1:Introduccióngeneral

ComencemosconunaintroducciónrápidaaC.Nuestroobjetivoesmostrarloselementosesencialesdellenguajeenprogramasreales,perosinperdernosendetalles,reglasoexcepciones.Porelmomento,nointentamossercompletosniprecisos(exceptuandoenlosejemplos,quesíloson).Deseamosllevarlotanrápidocomoseaposiblealpuntoendondepuedaescribirprogramasútiles,yparahacerlotenemosqueconcentrarnosenlasbases:variablesyconstantes,aritmética,controldeflujo,funcionesylosrudimentosdeentradaysalida.HemosdejadointencionalmentefueradeestecapítulolascaracterísticasdeCquesonimportantesparaescribirprogramasmásgrandes.Esascaracterísticasincluyenapuntadores,estructuras,lamayorpartedelricoconjuntodeoperadoresdeC,variasproposicionesparacontroldeflujoylabibliotecaestándar.

Esteenfoquetienesusinconvenientes.Lomásnotorioesqueaquínoseencuentraladescripcióncompletadeningunacaracterísticaparticulardellenguaje,ylaintroducción,porsubrevedad,puedetambiénserconfusa.YdebidoaquelosejemplosnoutilizanlapotenciacompletadeC,nosontanconcisosyelegantescomopodríanserlo.Hemostratadodeaminoraresosefectos,perotengacuidado.Otroinconvenienteesqueloscapítulosposterioresnecesariamenterepetiránalgodeloexpuestoenéste.Esperamosquelarepetición,másquemolestar,ayude.

Encualquiercaso,losprogramadoresconexperienciadebensercapacesdeextrapolardelmaterialqueseencuentraenestecapítuloasuspropiasnecesidadesdeprogramación.Losprincipiantesdebencomplementarloescribiendopequeñosprogramassemejantesalosaquíexpuestos.Ambosgrupospuedenutilizarestecapítulocomounmarcodereferenciasobreelcualasociarlasdescripcionesmásdetalladasquecomienzanenelcapítulo2.

Page 13: Titivillus 07.07

1.1.Comencemos

Laúnicaformadeaprenderunnuevolenguajedeprogramaciónesescribiendoprogramasconél.Elprimerprogramaporescribireselmismoparatodosloslenguajes:

Imprimalaspalabras

hola,mundo

Esteeselgranobstáculo;paralibrarlodebetenerlahabilidaddecreareltextodelprogramadealgunamanera,compilarloconéxito,cargarlo,ejecutarloydescubriradóndefuelasalida.Coneldominiodeestosdetallesmecánicos,todolodemásesrelativamentefácil.

EnC,elprogramaparaescribir“hola,mundo”es

#include<stdio.h>

main()

{

printf("hola,mundo\n");

}

Laformadeejecutaresteprogramadependedelsistemaqueseestéutilizando.Comounejemploespecífico,enelsistemaoperativoUNIXsedebecrearelprogramaenunarchivocuyonombreterminecon“.c”,comohola.c,ydespuéscompilarloconlaorden

cchola.c

Sinosehacometidoalgúnerror,comolaomisióndeuncarácteroescribiralgoenformaincorrecta,lacompilaciónseharásinemitirmensajealguno,ycrearáunarchivoejecutablellamadoa.out.Siseejecutaa.outescribiendolaorden

a.out

seescribirá

hola,mundo

Enotrossistemas,lasreglasserándiferentes,consúlteloconunexperto.

Ahoraalgunasexplicacionesacercadelprogramaensí.UnprogramaenC,cualquieraqueseasutamaño,constadefuncionesyvariables.Unafuncióncontieneproposicionesqueespecificanlasoperacionesdecálculoquesevanarealizar,ylasvariablesalmacenanlosvaloresutilizadosduranteloscálculos.LasfuncionesdeCsonsemejantesalassubrutinasyfuncionesdeFortranoalosprocedimientosyfuncionesdePascal.Nuestroejemploesunafunciónllamadamain.Normalmentesetienelalibertaddedarcualquiernombrequesedesee,pero“main”esespecial—elprogramacomienzaaejecutarsealprincipiodemain.Estosignificaquetodoprogramadebetenerunmainenalgúnsitio.

Page 14: Titivillus 07.07

Porlocomúnmainllamaráaotrasfuncionesqueayudenarealizarsutrabajo,algunasqueustedyaescribió,yotrasdebibliotecasescritaspreviamente.Laprimeralíneadelprograma.

#include<stdio.h>

indicaalcompiladorquedebeincluirinformaciónacercadelabibliotecaestándardeentrada/salida;estalíneaaparecealprincipiodemuchosarchivosfuentedeC.Labibliotecaestándarestádescritaenelcapítulo7yenelapéndiceB.

Unmétodoparacomunicardatosentrelasfuncionesesquelafunciónquellamaproporcionaunalistadevalores,llamadosargumentos,alafunciónqueestáinvocando.Losparéntesisqueestándespuésdelnombredelafunciónencierranalalistadeargumentos.Enesteejemplo,mainestádefinidoparaserunafunciónquenoesperaargumentos,locualestáindicadoporlalistavacía().

#include<stdio.h>

incluyeinformaciónacercadelabibliotecaestándar

main()

defineunafunciónllamada

main

quenorecibevaloresdeargumentos

{

lasproposicionesde

main

estánencerradasentrellaves

printf("hola,mundo\n");

mainllamaalafuncióndebiblioteca

printf

paraescribirestasecuenciadecaracteres;

\n

representaelcarácternuevalínea

}

ElprimerprogramaenC

Lasproposicionesdeunafunciónestánencerradasentrellaves{}.Lafunciónmainsólocontieneunaproposición,

printf("hola,mundo\n");

Page 15: Titivillus 07.07

Unafunciónseinvocaalnombrarla,seguidadeunalistadeargumentosentreparéntesis;deestamaneraseestállamandoalafunciónprintfconelargumento"hola,mundo\n".printfesunafuncióndebibliotecaqueescribelasalida,enestecasolacadenadecaracteresqueseencuentraentrecomillas.

Aunasecuenciadecaracteresentrecomillas,como"hola,mundo\n",selellamacadenadecaracteresoconstantedecadena.Porelmomento,nuestroúnicousodecadenasdecaracteresserácomoargumentosparaprintfyotrasfunciones.

Lasecuencia\nenlacadenarepresentaelcarácternuevalíneaenlanotaciónC,yhaceavanzarlaimpresiónalmargenizquierdodelasiguientelínea.Siseomiteel\n(unexperimentoquevalelapena),encontraráquenohayavancedelíneadespuésdelaimpresión.Sedebeutilizar\nparaincluiruncarácternuevalíneaenelargumentodeprintf;siseintentaalgocomo

printf("hola,mundo

");

elcompiladordeCproduciráunmensajedeerror.

printfnuncaproporcionaunanuevalíneaautomáticamente,demaneraquesepuedenutilizarvariasllamadasparaconstruirunalíneadesalidaenetapas.Nuestroprimerprogramatambiénpudohabersidoescritodelasiguientemanera.

#include<stdio.h>

main()

{

printf("hola,");

printf("mundo");

printf("\n");

}

produciéndoseunasalidaidéntica.

Nóteseque\nrepresentaunsolocarácter.Unasecuenciadeescapecomo\nproporcionaunmecanismogeneralyextensiblepararepresentarcaracteresinvisiblesodifícilesdeescribir.EntreotrosqueCproporcionaestán\tparatabulación,\bpararetroceso,\"paracomillas,y\\paraladiagonalinvertida.Hayunalistacompletaenlasección2.3.

Ejercicio1-1.Ejecuteelprograma"hola,mundo"ensusistema.Experimenteconlaomisióndepartesdelprograma,paraverquémensajesdeerrorseobtienen.□

Ejercicio1-2.Experimenteeldescubrirquépasacuandolacadenadelargumentodeprintfcontiene\c,endondecesalgúncarácternopuestoenlistaanteriormente.□

Page 16: Titivillus 07.07

1.2.Variablesyexpresionesaritméticas

Elsiguienteprogramautilizalafórmula°C=(5/9)(°F-32)paraimprimirlasiguientetabladetemperaturasFahrenheitysusequivalentescentígradosoCelsius:

0

-17

20

-6

40

4

60

15

80

26

100

37

120

48

140

60

160

71

180

82

200

93

220

104

Page 17: Titivillus 07.07

240

115

260

126

280

137

300

148

Ensíelprogramaaúnconsistedeladefinicióndeunaúnicafunciónllamadamain.Esmáslargoqueelqueimprime"hola,mundo",peronoescomplicado.Introducevariasideasnuevas,incluyendocomentarios,declaraciones,variables,expresionesaritméticas,ciclosysalidaconformato.

#include<stdio.h>

/*imprimelatablaFahrenheit-Celsius

parafahr=0,20,...,300*/

main()

{

intfahr,celsius;

intlower,upper,step;

lower=0;/*límiteinferiordelatabladetemperaturas*/

upper=300;/*límitesuperior*/

step=20;/*tamañodelincremento*/

fahr=lower;

while(fahr<=upper){

celsius=5*(fahr-32)/9;

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

fahr=fahr+step;

}

}

Lasdoslíneas

Page 18: Titivillus 07.07

/*imprimelatablaFahrenheit-Celsius

parafahr=0,20,...,300*/

sonuncomentario,queenestecasoexplicabrevementeloquehaceelprograma.Cualesquiercaracteresentre/*y*/sonignoradosporelcompilador,ypuedenserutilizadoslibrementeparahaceraunprogramamásfácildeentender.Loscomentariospuedenaparecerencualquierlugardondepuedecolocarseunespacioenblanco,untabuladoronuevalínea.

EnC,sedebendeclarartodaslasvariablesantesdesuuso,generalmentealprincipiodelafunciónyantesdecualquierproposiciónejecutable.Unadeclaraciónnotificalaspropiedadesdeunavariable;constadeunnombredetipoyunalistadevariables,como

intfahr,celsius;

intlower,upper,step;

Eltipointsignificaquelasvariablesdelalistasonenteros,encontrasteconfloat,quesignificapuntoflotante,estoes,númerosquepuedentenerunapartefraccionaria.Elrangotantodeintcomodefloatdependedelamáquinaqueseestáutilizando;losintde16bits,queestáncomprendidosentreel-32768y+32767,soncomunes,comolosonlosintde32bits.Unnúmerofloattípicamenteesde32bits,porlomenosconseisdígitossignificativosyunamagnitudgeneralmenteentre10-38y10+38.

Ademásdeintyfloat,Cproporcionavariostiposdedatosbásicos,incluyendo:

char

carácter—unsolobyte

short

enterocorto

long

enterolargo

double

puntoflotantededobleprecisión

Lostamañosdeestosobjetostambiéndependendelamáquina.Tambiénexistenarreglos,estructurasyunionesdeestostiposbásicos,apuntadoresaellosyfuncionesqueregresanvaloresconesostipos,todolocualseveráenelmomentooportuno.

Loscálculosenelprogramadeconversióndetemperaturasprincipianconlasproposicionesdeasignación.

lower=0;

upper=300;

step=20;

Page 19: Titivillus 07.07

fahr=lower;

queasignanalasvariablessusvaloresiniciales.Lasproposicionesindividualesseterminanconpuntoycoma.

Cadalíneadelatablasecalculadelamismamaneraporloqueseutilizaunaiteraciónqueserepiteunavezporcadalíneadesalida;esteeselpropósitodelciclowhile

while(fahr<=upper){

...

}

Elciclowhilefuncionadelasiguientemanera:sepruebalacondiciónentreparéntesis.Deserverdadera(fahresmenoroigualqueupper),elcuerpodelciclo(lastresproposicionesentrellaves)seejecuta.Luegolacondiciónsepruebanuevamente,ysiesverdadera,elcuerposeejecutadenuevo.Cuandolapruebaresultafalsa(fahrexcedeaupper)laiteracióntermina,ylaejecucióncontinúaenlaproposiciónquesiguealciclo.Noexisteningunaotraproposiciónenesteprograma,demodoquetermina.

Elcuerpodeunwhilepuedetenerunaomásproposicionesencerradasentrellaves,comoenelconvertidordetemperaturas,ounasolaproposiciónsinllaves,comoen

while(i<j)

i=2*i;

Encualquiercaso,siempresesangralaproposicióncontroladaporelwhileconunatabulación(loquesehamostradoconcuatroespacios)parapoderapreciardeunvistazocuálesproposicionesestándentrodelciclo.Elsangradoacentúalaestructuralógicadelprograma.AunquealoscompiladoresdeCnolesimportalaaparienciadelprograma,unsangradoyespaciamientoadecuadossonmuyimportantesparahacerprogramasfácilesdeleer.Serecomiendaescribirunasolaproposiciónporlíneayutilizarespaciosenblancoalrededordelosoperadoresparadarclaridadalagrupamiento.Laposicióndelasllavesesmenosimportante,aunquelagentemantienecreenciasapasionadas.Seeligióunodelosvariosestilospopulares.Seleccioneunestiloquelesatisfagayúseloenformaconsistente.

Lamayorpartedeltrabajoserealizaenelcuerpodelciclo.LatemperaturaCelsiussecalculayseasignaalavariablecelsiusporlaproposición.

celsius=5*(fahr-32)/9;

Larazóndemultiplicarpor5ydespuésdividirentre9enlugardesolamentemultiplicarpor5/9esqueenC,comoenmuchosotroslenguajes,ladivisióndeenterostruncaelresultado:cualquierpartefraccionariasedescarta.Puestoque5y9sonenteros,5/9seríatruncadoaceroyasítodaslastemperaturasCelsiussereportaríancomocero.

Esteejemplotambiénmuestraunpocomásacercadecómofuncionaprintf.Enrealidad,printfesunafuncióndepropósitogeneralparadarformatodesalida,quesedescribirácondetalleenelcapítulo7.Suprimerargumentoesunacadenadecaracteresqueseránimpresos,concada%indicandoendondeunodelosotros(segundo,tercero,...)argumentosvaasersustituido,yenquéformaseráimpreso.Porejemplo,%despecificaunargumentoentero,demodoquelaproposición

Page 20: Titivillus 07.07

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

hacequelosvaloresdelosdosenterosfahrycelsiusseanescritos,conunatabulación(\t)entreellos.

Cadaconstrucción%enelprimerargumentodeprintfestáasociadaconelcorrespondientesegundoargumento,tercero,etc.,ydebencorresponderapropiadamenteennúmeroytipo,osetendránsolucionesincorrectas.

Conrelaciónaesto,printfnoespartedellenguajeC;noexistepropiamenteunaentradaosalidadefinidaenC.printfessólounaútilfuncióndelabibliotecaestándardefuncionesqueestáaccesiblenormalmentealosprogramasenC.Sinembargo,elcomportamientodeprintfestádefinidoenelestándarANSI,porloquesuspropiedadesdebenserlasmismasencualquiercompiladorobibliotecaqueseapegueaél.

ParaconcentrarnosenC,nohablaremosmuchoacercadelaentradaylasalidahastaelcapítulo7.Enparticular,pospondremoseltemadelaentradaconformatohastaentonces.Sisetienequedarleentradaanúmeros,léaseladiscusióndelafunciónscanfenlasección7.4.Lafunciónscanfescomoprintf,exceptuandoqueleedelaentradaenlugardeescribiralasalida.

Existenunpardeproblemasconelprogramadeconversióndetemperaturas.Elmássimpleesquelasalidanoesmuyestéticadebidoaquelosnúmerosnoestánjustificadoshaciasuderecha.Estoesfácildecorregir;siaumentamosacada%ddelaproposiciónprintfunaamplitud,losnúmerosimpresosseránjustificadoshaciasuderechadentrodesuscampos.Porejemplo,podríadecirse

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

paraescribirelprimernúmerodecadalíneaenuncampodetresdígitosdeancho,yelsegundoenuncampodeseisdígitos,comoesto:

0

-17

20

-6

40

4

60

15

80

26

100

37

...

Page 21: Titivillus 07.07

Elproblemamásgraveesquedebidoaquesehautilizadoaritméticadeenteros,lastemperaturasCelsiusnosonmuyprecisas;porejemplo,0°Fesenrealidadaproximadamente-17.8°C,no-17.Paraobtenersolucionesmásprecisas,sedebeutilizararitméticadepuntoflotanteenlugardeentera.Estorequieredealgunoscambiosenelprograma.Aquíestáunasegundaversión:

#include<stdio.h>

/*imprimelatablaFahrenheit-Celsius

parafahr=0,20,...,300;versióndepuntoflotante*/

main()

{

floatfahr,celsius;

intlower,upper,step;

lower=0;/*límiteinferiordelatabladetemperaturas*/

upper=300;/*límitesuperior*/

step=20;/*tamañodelincremento*/

fahr=lower;

while(fahr<=upper){

celsius=(5.0/9.0)*(fahr-32.0);

printf("%3.0f%6.1f\n",fahr,celsius);

fahr=fahr+step;

}

}

Estoesmuysemejantealoanterior,exceptoquefahrycelsiusestándeclaradoscomofloat,ylafórmuladeconversiónestáescritaenunaformamásnatural.Nopudimosutilizar5/9enlaversiónanteriordebidoaqueladivisiónenteralotruncaríaacero.Sinembargo,unpuntodecimalenunaconstanteindicaqueéstaesdepuntoflotante,porloque5.0/9.0nosetruncadebidoaqueesunarelacióndedosvaloresdepuntoflotante.

Siunoperadoraritméticotieneoperandosenteros,seejecutaunaoperaciónentera.Siunoperadornuméricotieneunoperandodepuntoflotanteyotroentero,esteúltimoseráconvertidoapuntoflotanteantesdehacerlaoperación.Sisehubieraescritofahr-32,el32seríaconvertidoautomáticamenteapuntoflotante.Escribirconstantesdepuntoflotanteconpuntosdecimalesexplícitos,auncuandotenganvaloresenteros,destacasunaturalezadepuntoflotanteparaloslectoreshumanos.

Lasreglasdetalladasdecuándolosenterosseconviertenapuntoflotanteseencuentranenelcapítulo2.Porahora,nótesequelaasignación

Page 22: Titivillus 07.07

fahr=lower;

ylaprueba

while(fahr<=upper)

tambiéntrabajanenlaformanatural—elintseconvierteafloatantesdeefectuarselaoperación.

Laespecificacióndeconversión%3.0fdelprintfindicaqueseescribiráunnúmerodepuntoflotante(enestecasofahr)porlomenoscontrescaracteresdeancho,sinpuntodecimalysindígitosfraccionarios;%6.1fdescribeaotronúmero(celsius)queseescribiráenunaamplituddeporlomenos6caracteres,con1dígitodespuésdelpuntodecimal.Lasalidaseverácomosigue:

0

-17.8

20

-6.7

40

4.4

...

Laamplitudylaprecisiónpuedenomitirsedeunaespecificación:%6findicaqueelnúmeroesporlomenosdeseiscaracteresdeancho;%.2findicadoscaracteresdespuésdelpuntodecimal,peroelanchonoestárestringido;y%fúnicamenteindicaescribirelnúmerocomopuntoflotante.

%d

escribecomoenterodecimal

%6d

escribecomoenterodecimal,porlomenoscon6caracteresde

amplitud

%f

escribecomopuntoflotante

%6f

escribecomopuntoflotante,porlomenoscon6caracteresde

amplitud

%.2f

Page 23: Titivillus 07.07

escribecomopuntoflotante,con2caracteresdespuésdelpunto

decimal

%6.2f

escribecomopuntoflotante,porlomenoscon6caracteresde

anchoy2despuésdelpuntodecimal

Entreotros,printftambiénreconoce%oparaoctal,%xparahexadecimal,%cparacarácter,%sparacadenadecaracteresy%%para%ensí.

Ejercicio1-3.Modifiqueelprogramadeconversióndetemperaturasdemodoqueescribaunencabezadosobrelatabla.□

Ejercicio1-4.EscribaunprogramaqueimprimalatablacorrespondienteCelsiusaFahrenheit.□

Page 24: Titivillus 07.07

1.3.Laproposiciónfor

Existensuficientesformasdistintasdeescribirunprogramaparaunatareaenparticular.Intentemosunavariacióndelprogramadeconversióndetemperaturas.

#include<stdio.h>

/*imprimelatablaFahrenheit-Celsius*/

main()

{

intfahr;

for(fahr=0;fahr<=300;fahr=fahr+20)

printf("%3d%6.1f\n",fahr,(5.0/9.0)*(fahr-32));

}

Esteproducelosmismosresultados,perociertamentesevediferente.Uncambioimportanteeslaeliminacióndelamayoríadelasvariables;sólopermanecefahrylahemoshechoint.Loslímitesinferiorysuperioryeltamañodelavancesóloaparecencomoconstantesdentrodelaproposiciónfor,queesunanuevaconstrucción,ylaexpresiónquecalculalatemperaturaCelsiusahoraaparececomoeltercerargumentodeprintfenvezdeunaproposicióndeasignaciónseparada.

Esteúltimocambioejemplificaunareglageneral—encualquiercontextoenelquesepermitautilizarelvalordeunavariabledealgúntipo,esposibleusarunaexpresiónmáscomplicadadeesetipo.Puestoqueeltercerargumentodeprintfdebeserunvalordepuntoflotanteparacoincidircon%6.1f,cualquierexpresióndepuntoflotantepuedeestarallí.

Laproposiciónforesunciclo,unaformageneralizadadelwhile.Sisecomparaconelwhileanterior,suoperacióndebeserclara.Dentrodelosparéntesisexistentressecciones,separadasporpuntoycoma.Laprimera,lainicialización

fahr=0

seejecutaunavez,antesdeentrarpropiamentealciclo.Lasegundaseccióneslacondiciónopruebaquecontrolaelciclo:

fahr<=300

Estacondiciónseevalúa;siesverdadera,elcuerpodelciclo(enestecasounsimpleprintf)seejecuta.Despuéselincrementodeavance

fahr=fahr+20

seejecutaylacondiciónsevuelveaevaluar.Elcicloterminasilacondiciónsehacefalsa.Talcomoconelwhile,elcuerpodelciclopuedeserunaproposiciónsencillaoungrupodeproposicionesencerradasentrellaves.Lainicialización,lacondiciónyel

Page 25: Titivillus 07.07

incrementopuedensercualquierexpresión.

Laselecciónentrewhileyforesarbitraria,ysebasaenaquelloqueparezcamásclaro.Elforesporlogeneralapropiadoparaciclosenlosquelainicializaciónyelincrementosonproposicionessencillasylógicamenterelacionadas,puestoqueesmáscompactoqueelwhileymantienereunidasenunlugaralasproposicionesquecontrolanalciclo.

Ejercicio1-5.Modifiqueelprogramadeconversióndetemperaturasdemaneraqueescribalatablaenordeninverso,estoes,desde300gradoshasta0.□

Page 26: Titivillus 07.07

1.4.Constantessimbólicas

Unaobservaciónfinalantesdedejardefinitivamenteeltemadelaconversióndetemperaturas.Esunamalaprácticaponer“númerosmágicos”como300y20enunprograma,yaqueproporcionanmuypocainformaciónaquientengaqueleerelprograma,ysondifícilesdemodificarenunaformasistemática.Unamaneradetrataraesosnúmerosmágicosesdarlesnombressignificativos.Unalínea#definedefineunnombresimbólicooconstantesimbólicacomounacadenadecaracteresespecial:

#definenombretextodereemplazo

Apartirdeesto,cualquierocurrenciadenombre(quenoestéentrecomillasnicomopartedeotronombre)sesustituiráporeltextodereemplazocorrespondiente.Elnombretienelamismaformaqueunnombredevariable:unasecuenciadeletrasydígitosquecomienzaconunaletra.Eltextodereemplazopuedesercualquiersecuenciadecaracteres;noestálimitadoanúmeros.

#include<stdio.h>

#defineLOWER0/*límiteinferiordelatabla*/

#defineUPPER300/*límitesuperior*/

#defineSTEP20/*tamañodelincremento*/

/*imprimelatablaFahrenheit-Celsius*/

main()

{

intfahr;

for(fahr=LOWER;fahr<=UPPER;fahr=fahr+STEP)

printf("%3d%6.1f\n",fahr,(5.0/9.0)*(fahr-32));

}

LascantidadesLOWER,UPPERySTEPsonconstantessimbólicas,novariables,porloquenoaparecenentrelasdeclaraciones.Losnombresdeconstantessimbólicas,porconvención,seescribenconletrasmayúsculas,demodoquesepuedandistinguirfácilmentedelosnombresdevariablesescritosconminúsculas.Nótesequenohaypuntoycomaalfinaldeunalínea#define.

Page 27: Titivillus 07.07

1.5.Entradaysalidadecaracteres

Ahoravamosaconsiderarunafamiliadeprogramasrelacionadosparaelprocesamientodedatosdetipocarácter.Seencontraráquemuchosprogramassólosonversionesampliadasdelosprototiposquesetratanaquí.

Elmodelodeentradaysalidamanejadoporlabibliotecaestándaresmuysimple.Laentradaysalidadetexto,sinimportardóndefueoriginadaohaciadóndesedirige,setratancomoflujos(streams)decaracteres.Unflujodetextoesunasecuenciadecaracteresdivididosentrelíneas,cadaunadelascualesconstadeceroomáscaracteresseguidosdeuncarácternuevalínea.Labibliotecaesresponsabledehacerquecadasecuenciadeentradaosalidaestédeacuerdoconestemodelo;elprogramadordeCqueutilizalabibliotecanonecesitapreocuparsedecómoestánrepresentadaslaslíneasfueradelprograma.

Labibliotecaestándarproporcionavariasfuncionesparaleeroescribiruncarácteralavez,delascualesgetcharyputcharsonlasmássimples.Cadavezqueseinvoca,getcharleeelsiguientecarácterdeentradadeunasecuenciadetextoylodevuelvecomosuvalor.Estoes,despuésde

c=getchar()

lavariableccontieneelsiguientecarácterdeentrada.Loscaracteresprovienennormalmentedelteclado;laentradadearchivossetrataenelcapítulo7.

Lafunciónputcharescribeuncaráctercadavezqueseinvoca:

putchar(c)

escribeelcontenidodelavariableenteraccomouncarácter,generalmenteenlapantalla:Lasllamadasaputcharyaprintfpuedenestaralternadas;lasalidaapareceráenelordenenqueserealicenlasllamadas.

Page 28: Titivillus 07.07

1.5.1.Copiadearchivos

Congetcharyputcharsepuedeescribirunacantidadsorprendentedecódigoútilsinsabernadamásacercadeentradaysalida.Elejemplomássencilloesunprogramaquecopialaentradaenlasalida,uncarácteralavez:

leeuncarácter

while(carácternoesindicadordefindearchivo)

mandaalasalidaelcarácterreciénleído

leeuncarácter

AlconvertirestoenCseobtiene

#include<stdio.h>

/*copialaentradaalasalida;1a.versión*/

main()

{

intc;

c=getchar();

while(c!=EOF){

putchar(c);

c=getchar();

}

}

Eloperadorderelación!=significa“noiguala”.

Loqueaparececomouncaráctereneltecladooenlapantallaes,porsupuesto,comocualquierotracosa,almacenadointernamentecomounpatróndebits.Eltipochartienelafunciónespecíficadealmacenaresetipodedato,perotambiénpuedeserusadocualquiertipodeentero.Usamosintporunasutilperoimportanterazón.

Elproblemaesdistinguirelfindelaentradadelosdatosválidos.Lasoluciónesquegetchardevuelveunvalordistintivocuandonohaymásalaentrada,unvalorquenopuedeserconfundidoconningúnotrocarácter.EstevalorsellamaEOF,por“endoffile(findearchivo)”.Sedebedeclararcconuntipoquesealosuficientementegrandeparaalmacenarcualquiervalorqueleregresegetchar.NosepuedeutilizarcharpuestoquecdebesersuficientementegrandecomoparamanteneraEOFademásdecualquierotrocarácter.Porlotanto,seempleaint.

Page 29: Titivillus 07.07

EOFesunenterodefinidoen<stdio.h>,peroelvalornuméricoespecíficonoimportamientrasquenoseaelmismoqueningúnvalortipochar.Utilizandolaconstantesimbólica,hemosaseguradoquenadaenelprogramadependedelvalornuméricoespecífico.

ElprogramaparacopiarpodríaescribirsedemodomásconcisoporprogramadoresexperimentadosdeC.EnlenguajeC,cualquierasignación,talcomo

c=getchar()

esunaexpresiónytieneunvalor,eldelladoizquierdoluegodelaasignación.Estosignificaqueunaasignaciónpuedeaparecercomopartedeunaexpresiónmáslarga.Silaasignacióndeuncarácteracsecolocadentrodelaseccióndepruebadeunciclowhile,elprogramaquecopiapuedeescribirsedelasiguientemanera:

#include<stdio.h>

/*copialaentradaalasalida;2a.versión*/

main()

{

intc;

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

putchar(c);

}

Elwhileobtieneuncarácter,loasignaac,yentoncespruebasielcarácterfuelaseñaldefindearchivo.Denoserlo,elcuerpodelwhileseejecuta,escribiendoelcarácter;luegoserepiteelwhile.Luego,cuandosealcanzaelfinaldelaentrada,elwhileterminaytambiénlohacemain.

Estaversióncentralizalaentrada—ahorahaysólounareferenciaagetchar—yreduceelprograma.Elprogramaresultanteesmáscompactoymásfácildeleerunavezquesedominaeltruco.Ustedveráseguidoesteestilo.(Sinembargo,esposibledescarriarseycrearcódigoimpenetrable,unatendenciaquetrataremosdereprimir.)

Losparéntesisqueestánalrededordelaasignacióndentrodelacondiciónsonnecesarios.Laprecedenciade!=esmásaltaquelade=,loquesignificaqueenausenciadeparéntesislapruebaderelación!=serealizaríaantesdelaasignación=.Deestamanera,laproposición

c=getchar()!=EOF

esequivalentea

c=(getchar()!=EOF)

Estotieneelefectoindeseabledehacerquecsea0o1,dependiendodesilallamadadegetcharencontrófindearchivo.(Enelcapítulo2setrataestetemaconmásdetalle).

Ejercicio1-6.Verifiquequelaexpresióngetchar()!=EOFes0o1.□

Page 30: Titivillus 07.07

Ejercicio1-7.EscribaunprogramaqueimprimaelvalordeEOF.□

Page 31: Titivillus 07.07

1.5.2.Conteodecaracteres

Elsiguienteprogramacuentacaracteresyessemejantealprogramaquecopia.

#include<stdio.h>

/*cuentaloscaracteresdelaentrada;1a.versión*/

main()

{

longnc;

nc=0;

while(getchar()!=EOF)

++nc;

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

}

Laproposición

++nc;

presentaunnuevooperador,++,quesignificaincrementaenuno.Esposibleescribirnc=nc+1,pero++ncesmásconcisoymuchasvecesmáseficiente.Hayunoperadorcorrespondiente--paradisminuiren1.Losoperadores++y--puedensertantooperadoresprefijos(++nc)comopostfijos(nc++);esasdosformastienendiferentesvaloresdentrodelasexpresiones,comosedemostraráenelcapítulo2,peroambos++ncync++incrementananc.Porelmomentoadoptaremoslaformadeprefijo.

Elprogramaparacontarcaracteresacumulasucuentaenunavariablelongenlugardeunaint.Losenteroslongsonporlomenosde32bits.Aunqueenalgunasmáquinasintylongsondelmismotamaño,enotrasunintesde16bits,conunvalormáximode32767,ytomaríarelativamentepocalecturaalaentradaparadesbordaruncontadorint.Laespecificacióndeconversión%ldindicaaprintfqueelargumentocorrespondienteesunenterolong.

Seríaposibletenerlacapacidaddetrabajarconnúmerosmayoresempleandoundouble(floatdedobleprecisión).Tambiénseutilizaráunaproposiciónforenlugardeunwhile,parademostrarotraformadeescribirelciclo.

#include<stdio.h>

/*cuentaloscaracteresdelaentrada;2a.versión*/

main()

{

Page 32: Titivillus 07.07

doublenc;

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

;

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

}

printfutiliza%ftantoparafloatcomoparadouble;%.0fsuprimelaimpresióndelpuntodecimalydelapartefraccionaria,queescero.

Elcuerpodeestecicloforestávacío,debidoaquetodoeltrabajoserealizaenlasseccionesdepruebaeincremento.PerolasreglasgramaticalesdeCrequierenqueunaproposiciónfortengauncuerpo.Elpuntoycomaaisladosellamaproposiciónnula,yestáaquíparasatisfaceresterequisito.Locolocamosenunalíneaaparteparaqueseavisible.

Antesdeabandonarelprogramaparacontarcaracteres,obsérvesequesilaentradanocontienecaracteres,lapruebadelwhileodelfornotieneéxitodesdelaprimerallamadaagetchar,yelprogramaproducecero,elresultadocorrecto.Estoesimportante.Unodelosaspectosagradablesacercadelwhileydelforesquehacenlapruebaaliniciodelciclo,antesdeprocederconelcuerpo.Sinohaynadaquehacer,nadasehace,aunsiellosignificanopasaratravésdelcuerpodelciclo.Losprogramasdebenactuarenformainteligentecuandoselesdaunaentradadelongitudcero.Lasproposicioneswhileyforayudanaasegurarquelosprogramasrealizancosasrazonablesconcondicionesdefrontera.

Page 33: Titivillus 07.07

1.5.3.Conteodelíneas

Elsiguienteprogramacuentalíneasalaentrada.Comosemencionóanteriormente,labibliotecaestándaraseguraqueunasecuenciadetextodeentradaparezcaunasecuenciadelíneas,cadaunaterminadaporuncarácternuevalínea.Porlotanto,contarlíneasessolamentecontarcaracteresnuevalínea:

#include<stdio.h>

/*cuentalaslíneasdelaentrada*/

main()

{

intc,nl;

nl=0;

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

if(c=='\n')

++nl;

printf("%d\n",nl);

}

Elcuerpodelwhileconsisteahoraenunif,elcualasuvezcontrolaelincremento++nl.Laproposiciónifpruebalacondiciónqueseencuentraentreparéntesisy,silacondiciónesverdadera,ejecutalaproposición(ogrupodeproposicionesentrellaves)quelesigue.Hemossangradonuevamenteparamostrarloquecontrolacadaelemento.

Eldoblesignodeigualdad==eslanotacióndeCparaexpresar“iguala”(comoel=simpledePascaloel.EQ.deFortran).Estesímboloseempleaparadistinguirlapruebadeigualdaddel=simplequeutilizaCparalaasignación.Unmensajedealerta:losprincipiantesdeCocasionalmenteescriben=cuandoenrealidaddebenusar==.Comoseveráenelcapítulo2,elresultadoesporlogeneralunaexpresiónlegal,demodoquenoseobtendráningunaadvertencia.

Uncarácterescritoentreapóstrofosrepresentaunvalorenteroigualalvalornuméricodelcarácterenelconjuntodecaracteresdelamáquina.Estosellamaunaconstantedecarácter,aunquesóloesotraformadeescribirunpequeñoentero.Así,porejemplo'A'esunaconstantedecarácter;enelconjuntoASCIIdecaracteressuvalores65,estoes,larepresentacióninternadelcarácterA.Porsupuesto'A'espreferibleque65:susignificadoesobvio,yesindependientedeunconjuntodecaracteresenparticular.

Lassecuenciasdeescapequeseutilizanenconstantesdecadenatambiénsonlegalesenconstantesdecarácter;así,'\n'significaelvalordelcarácternuevalínea,elcuales10encódigoASCII.Sedebenotarcuidadosamenteque'\n'esuncaráctersimple,yenexpresionesessólounentero;porotrolado,"\n"esunaconstantecadenaquecontienesólouncarácter.Enelcapítulo2setrataeltemadecadenasversuscaracteres.

Page 34: Titivillus 07.07

Ejercicio1-8.Escribaunprogramaquecuenteespaciosenblanco,tabuladoresynuevaslíneas.□

Ejercicio1-9.Escribaunprogramaquecopiesuentradaalasalida,reemplazandocadacadenadeunoomásblancosporunsoloblanco.□

Ejercicio1-10.Escribaunprogramaquecopiesuentradaalasalida,reemplazandocadatabulaciónpor\t,cadaretrocesopor\bycadadiagonalinvertidapor\\.Estohacequelastabulacionesylosespaciosseanvisiblessinconfusiones.□

Page 35: Titivillus 07.07

1.5.4.Conteodepalabras

Elcuartoennuestraseriedeprogramasútilescuentalaslíneas,palabrasycaracteres,usandoladefinicióndequeunapalabraescualquiersecuenciadecaracteresquenocontieneespacioenblanconitabulaciónninuevalínea.EstaesunaversiónreducidadelprogramawcdeUNIX.

#include<stdio.h>

#defineIN1/*enunapalabra*/

#defineOUT0/*fueradeunapalabra*/

/*cuentalíneas,palabras,ycaracteresdelaentrada*/

main()

{

intc,nl,nw,nc,state;

state=OUT;

nl=nw=nc=0;

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

++nc;

if(c=='\n')

++nl;

if(c==''||c=='\n'||c=='\r')

state=OUT;

elseif(state==OUT){

state=IN;

++nw;

}

}

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

}

Cadavezqueelprogramaencuentraelprimercarácterdeunapalabra,contabilizaunapalabramás.Lavariablestateregistrasiactualmenteelprogramaestáonosobreuna

Page 36: Titivillus 07.07

palabra;aliniciares“noestásobreunapalabra”,porloqueseasignaelvalorOUT.EspreferibleusarlasconstantessimbólicasINyOUTquelosvaloresliterales1y0,porquehacenelprogramamáslegible.Enunprogramatanpequeñocomoéste,ladiferenciaesmínima,peroenprogramasmásgrandeselincrementoenclaridadbienvaleelesfuerzoextraquesehayarealizadoparaescribirdeestamaneradesdeelprincipio.Tambiénsedescubriráqueesmásfácilhacercambiosextensivosenprogramasdondelosnúmerosmágicosaparecensólocomoconstantessimbólicas.

Lalínea

nl=nw=nc=0;

inicializaalastresvariablesencero.Estenoesuncasoespecialsinounaconsecuenciadelhechodequeunaasignaciónesunaexpresiónconunvalor,yquelasasignacionesseasociandederechaaizquierda.Escomosisehubieseescrito

nl=(nw=(nc=0));

Eloperador||significa“O”(obien“OR”),porloquelalínea

if(c==''||c=='\n'||c=='\r')

dice“sicesunblancoocesnuevalíneaocesuntabulador”.(Recuerdequelasecuenciadeescape\tesunarepresentaciónvisibledelcaráctertabulador.)Existeuncorrespondienteoperador&&paraAND;suprecedenciaesmásaltaquelade||.Lasexpresionesconectadaspor&&o||seevalúandeizquierdaaderecha,ysegarantizaquelaevaluaciónterminarátanprontocomoseconozcalaverdadofalsedad.Sicesunblanco,nohaynecesidaddeprobarsiesunanuevalíneaountabulador,demodoqueesaspruebasnosehacen.Estonoesdeparticularimportanciaenestecaso,peroessignificativoensituacionesmáscomplicadas,comoseverámásadelante.

Elejemplomuestratambiénunelse,elcualespecificaunaacciónalternativasilacondicióndeunaproposiciónifesfalsa.Laformagenerales

if(expresión)

proposición1

else

proposición2

Unaysólounadelasdosproposicionesasociadasconunif-elseserealiza.Silaexpresiónesverdadera,seejecutaproposición1,sinoloes,seejecutaproposición2.Cadaproposiciónpuedeserunaproposiciónsencillaovariasentrellaves.Enelprogramaparacontarpalabras,laqueestádespuésdelelseesunifquecontroladosproposicionesentrellaves.

Ejercicio1-11.¿Cómoprobaríaelprogramaparacontarpalabras?¿Quéclasedeentradaeslamásconvenienteparadescubrirerroressiéstosexisten?□

Ejercicio1-12.Escribaunprogramaqueimprimasuentradaunapalabraporlínea.□

Page 37: Titivillus 07.07

1.6.Arreglos

Escribamosunprogramaparacontarelnúmerodeocurrenciasdecadadígito,decaracteresespaciadores(blancos,tabuladores,nuevalínea),ydetodoslosotroscaracteres.Estoesartificioso,peronospermiteilustrarvariosaspectosdeCenunprograma.

Existendocecategoríasdeentrada,porloqueesconvenienteutilizarunarregloparamantenerelnúmerodeocurrenciasdecadadígito,enlugardetenerdiezvariablesindividuales.Estaesunaversióndelprograma:

#include<stdio.h>

/*cuentadígitos,espaciosblancos,yotros*/

main()

{

intc,i,nwhite,nother;

intndigit[10];

nwhite=nother=0;

for(i=0;i<10;++i)

ndigit[i]=0;

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

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

++ndigit[c-'O'];

elseif(c==''||c=='\n'||c=='\t')

++nwhite;

else

++nother;

printf("dígitos=");

for(i=0;i<10;++i)

printf("%d",ndigit[i]);

printf(",espaciosblancos=%d,otros=%d\n",nwhite,nother);

}

Page 38: Titivillus 07.07

Lasalidadeesteprogramaalejecutarlosobresímismoes

dígitos=9300000001,espaciosblancos=123,otros=345

Ladeclaración

intndigit[10];

declarandigitcomounarreglode10enteros.EnC,lossubíndicesdearregloscomienzanencero,porloqueloselementossonndigit[0],ndigit[1],...,ndigit[9].Estosereflejaenlosciclosforqueinicializaneimprimenelarreglo.

Unsubíndicepuedesercualquierexpresiónentera,loqueincluyeavariablesenterascomoi,yconstantesenteras.

Esteprogramaenparticularsebasaenlaspropiedadesdelarepresentacióndelosdígitoscomocaracteres.Porejemplo,laprueba

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

determinasielcarácterencesundígito.Siloes,elvalornuméricodeldígitoes

c-'0'

Estosólofuncionasi'0','1',...,'9'tienenvaloresconsecutivosascendentes.Porfortuna,estoesasíentodoslosconjuntosdecaracteres.

Pordefinición,loscharsonsólopequeñosenteros,porloquelasvariablesylasconstantescharsonidénticasalasintenexpresionesaritméticas.Estoesnaturalyconveniente;porejemplo,c-'0'esunaexpresiónenteraconunvalorentre0y9,correspondientealoscaracteres'O'a'9'almacenadosenc,porloqueesunsubíndiceválidoparaelarreglondigit.

Ladecisióndesiuncarácteresdígito,espacioenblancouotracosaserealizaconlasecuencia

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

++ndigit[c-'0'];

elseif(c==''||c=='\n'||c=='\t')

++nwhite;

else

++nother;

Elpatrón

if(condición1)

proposición1

elseif(condición2)

Page 39: Titivillus 07.07

proposición2

...

...

else

proposiciónn

seencuentrafrecuentementeenprogramascomounaformadeexpresarunadecisiónmúltiple.Lascondicionesseevalúanenordendesdeelprincipiohastaquesesatisfacealgunacondición;enesepuntoseejecutalaproposicióncorrespondiente,ylaconstruccióncompletatermina.(Cualquierproposiciónpuedeconstardevariasproposicionesentrellaves.)Sinosesatisfaceningunadelascondiciones,seejecutalaproposiciónqueestádespuésdelelsefinal,siéstaexiste.Cuandoseomitenelelseylaproposiciónfinales,talcomosehizoenelprogramaparacontarpalabras,notienelugarningunaacción.Puedehabercualquiernúmerodegruposde

elseif(condición)

proposición

entreelifinicialyelelsefinal.

Serecomienda,porestilo,escribirestaconstruccióntalcomosehamostrado;sicadaifestuviesesangradodespuésdelelseanterior,unalargasecuenciadedecisionespodríarebasarelmargenderechodelapágina.

Laproposiciónswitch,quesetrataráenelcapítulo3,proporcionaotraformadeescribirunadecisiónmúltiple,queesparticularmenteapropiadacuandolacondiciónesdeterminarsialgunaexpresiónenteraodecaráctercorrespondeconalgúnmiembrodeunconjuntodeconstantes.Paracontrastar,sepresentaráunaversióndeesteprograma,usandoswitch,enlasección3.4.

Ejercicio1-13.Escribaunprogramaqueimprimaelhistogramadelaslongitudesdelaspalabrasdesuentrada.Esfácildibujarelhistogramaconlasbarrashorizontales;laorientaciónverticalesunretomásinteresante.□

Ejercicio1-14.Escribaunprogramaqueimprimaelhistogramadelasfrecuenciasconquesepresentandiferentescaracteresleídosalaentrada.□

Page 40: Titivillus 07.07

1.7.Funciones

EnlenguajeC,unafuncióneselequivalenteaunasubrutinaofunciónenFortran,oaunprocedimientoofunciónenPascal.Unafunciónproporcionaunaformaconvenientedeencapsularalgunoscálculos,quesepuedenempleardespuéssinpreocuparsedesuimplantación.Confuncionesdiseñadasadecuadamente,esposibleignorarcómoserealizauntrabajo;essuficientesaberquésehace.EllenguajeChacequeelusodefuncionesseafácil,convenienteyeficiente;escomúnverunafuncióncortadefinidayempleadaunasolavez,únicamenteporqueesoesclarecealgunapartedelcódigo.

Hastaahorasólosehanutilizadofuncionescomoprintf,getcharyputchar,quenoshansidoproporcionadas;yaeselmomentodeescribirunaspocasnosotrosmismos.DadoqueCnoposeeunoperadordeexponenciacióncomoel**deFortran,ilustremoselmecanismodeladefinicióndeunafunciónalescribirlafunciónpower(m,n),queelevaunenteromaunapotenciaenteraypositivan.Estoes,elvalordepower(2,5)es32.Estafunciónnoesunarutinadeexponenciaciónpráctica,puestoquesólomanejapotenciaspositivasdeenterospequeños,peroessuficienteparailustración(labibliotecaestándarcontieneunafunciónpow(x,y)quecalculaxy).

Acontinuaciónsepresentalafunciónpoweryunprogramamainparautilizarla,demodoquesevealaestructuracompletadeunavez.

#include<stdio.h>

intpower(intm,intn);

/*pruebalafunciónpower*/

main()

{

inti;

for(i=0;i<10;++i)

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

return0;

}

/*power:elevalabasealan-ésimapotencia;n>=0*/

intpower(intbase,intn)

{

inti,p;

p=1;

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

Page 41: Titivillus 07.07

p=p*base;

returnp;

}

Unadefinicióndefuncióntienelaformasiguiente:

tipo-de-retornonombre-de-función(declaracióndeparámetros,siloshay)

{

declaraciones

proposiciones

}

Lasdefinicionesdefunciónpuedenaparecerencualquierordenyenunoovariosarchivosfuente,perounafunciónnopuedesepararseenarchivosdiferentes.Sielprogramafuenteapareceenvariosarchivos,talvezsetenganqueespecificarmáscosasalcompilarycargarloquesiestuvieraenunosolo,peroesoescosadelsistemaoperativo,nounatributodellenguaje.PorahorasupondremosqueambasfuncionesestánenelmismoarchivoycualquiercosaquesehayaaprendidoacercadecómoejecutarprogramasenC,aúnfuncionarán.

Lafunciónpowerseinvocadosvecespormain,enlalínea

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

Cadallamadapasadosargumentosapower,quecadavezregresaunentero,alqueseponeformatoyseimprime.Enunaexpresión,power(2,i)esunenterotalcomoloson2ei.(Notodaslasfuncionesproducenunvalorentero;loqueseveráenelcapítulo4.)

Laprimeralíneadelafunciónpower,

intpower(inbase,intn)

declaralostiposynombresdelosparámetros,asícomoeltipoderesultadoquelafuncióndevuelve.Losnombresqueempleapowerparasusparámetrossonlocalesalafunciónysoninvisiblesacualquierotrafunción:otrasrutinaspuedenutilizarlosmismosnombressinqueexistaproblemaalguno.Estotambiénesciertoparalasvariablesiyp:laidepowernotienenadaqueverconlaidemain.

Generalmenteusaremosparámetroparaunavariablenombradaenlalistaentreparéntesisdeladefinicióndeunafunción,yargumentoparaelvalorempleadoalhacerlallamadadelafunción.Lostérminosargumentoformalyargumentorealseempleanenocasionesparahacerlamismadistinción.

Elvalorquecalculapowerseregresaamainpormediodelaproposiciónreturn,alacuallepuedeseguircualquierexpresión:

returnexpresión;

Unafunciónnonecesitaregresarunvalor;unaproposiciónreturnsinexpresiónhacequeelcontrolregresealprograma,peronodevuelvealgúnvalordeutilidad,comose

Page 42: Titivillus 07.07

haríaal“caeralfinal”deunafunciónalalcanzarlallavederechadeterminación.Además,lafunciónquellamapuedeignorarelvalorqueregresaunafunción.

Probablementehayanotadoquehayunaproposiciónreturnalfinaldemain.Puestoquemainesunafuncióncomocualquierotra,tambiénpuederegresarunvaloraquienlainvoca,queesenefectoelmedioambienteenelqueelprogramaseejecuta.Típicamente,unvalorderegresoceroimplicaunaterminaciónnormal;losvaloresdiferentesdeceroindicancondicionesdeterminaciónnocomunesoerróneas.Parabuscarlasimplicidad,sehanomitidohastaahoralasproposicionesreturndelasfuncionesmain,peroseincluiránmásadelante,comounrecordatoriodequelosprogramasdebenregresarsuestadofinalasumedioambiente.

Ladeclaración

intpower(intm,intn);

precisamenteantesdemain,indicaquepoweresunafunciónqueesperadosargumentosintyregresaunint.Estadeclaración,alacualselellamafunciónprototipo,debecoincidirconladefiniciónyusodepower.Esunerrorelqueladefinicióndeunafunciónocualquierusoquedeellasehaganocorrespondaconsuprototipo.

Losnombresdelosparámetrosnonecesitancoincidir;dehecho,sonoptativosenelprototipodeunafunción,demodoqueparaelprototiposepudohaberescrito

intpower(int,int);

Noobstante,unosnombresbienseleccionadossonunabuenadocumentación,porloqueseemplearánfrecuentemente.

Unanotahistórica:LamayormodificaciónentreANSICylasversionesanterioresescómoestándeclaradasydefinidaslasfunciones.EnladefiniciónoriginaldeC,lafunciónpowersepudohaberescritodelasiguientemanera:

/*power:elevalabasean-ésimapotencia;n>=0*/

/*(versiónenestiloantiguo)*/

power(base,n)

intbase,n;

{

inti,p;

p=1;

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

p=p*base;

returnp;

}

Losparámetrossenombranentrelosparéntesisysustipossedeclaranantesdeabrirlallaveizquierda;losparámetrosquenosedeclaransetomancomoint.(Elcuerpodela

Page 43: Titivillus 07.07

funciónesigualalaanterior.)

Ladeclaracióndepoweraliniciodelprogramapudohabersevistocomosigue:

intpower();

Nosepermitióningunalistadeparámetros,demodoqueelcompiladornopudorevisarconfacilidadquepowerfuerallamadacorrectamente.Dehecho,puestoqueporomisiónsepodíasuponerquepowerregresabaunentero,todaladeclaraciónpodríahaberseomitido.

Lanuevasintaxisdelosprototiposdefuncionespermitequeseamuchomásfácilparaelcompiladordetectarerroresenelnúmerootipodeargumentos.ElviejoestilodedeclaraciónydefiniciónaúnfuncionaenANSIC,almenosporunperiododetransición,peroserecomiendaampliamentequeseutilicelanuevaformasisetieneuncompiladorquelamaneje.

Ejercicio1-15.Escribadenuevoelprogramadeconversióndetemperaturadelasección1.2,demodoqueutiliceunafunciónparalaconversión.□

Page 44: Titivillus 07.07

1.8.Argumentos—llamadaporvalor

HayunaspectodelasfuncionesdeCquepuedeparecerpocofamiliaralosprogramadoresacostumbradosaotroslenguajes,particularmenteFortran.EnC,todoslosargumentosdeunafunciónsepasan“porvalor”.Estosignificaquelafunciónqueseinvocarecibelosvaloresdesusargumentosenvariablestemporalesynoenlasoriginales.Estoconduceaalgunaspropiedadesdiferentesalasquesevenenlenguajescon“llamadasporreferencia”comoFortranoconparámetrosvarenPascal,endondelarutinaqueseinvocatieneaccesoalargumentooriginal,noaunacopialocal.

LadiferenciaprincipalesqueenClafunciónqueseinvocanopuedealterardirectamenteunavariabledelafunciónquehacelallamada;sólopuedemodificarsucopiaprivadaytemporal.

Sinembargo,lallamadaporvaloresunaventaja,nounadesventaja.Porlocomún,estoconduceaelaborarprogramasmáscompactosconpocasvariablesextrañas,debidoaquelosparámetrossetratanenlafuncióninvocadacomovariableslocalesconvenientementeinicializadas.Porejemplo,heaquíunaversióndepowerqueutilizaestapropiedad.

/*power:elevalabasealan-ésimapotencia;n>=0;versión2*/

intpower(intbase,intn)

{

intp;

for(p=1;n>0;--n)

p=p*base;

returnp;

}

Elparámetronseutilizacomounavariabletemporal,ysedecrementa(uncicloforqueseejecutahaciaatrás)hastaquellegaacero;yanoesnecesarialavariablei.Cualquiercosaqueselehagaandentrodepowernotieneefectosobreelargumentoconelquesellamóoriginalmentepower.

Cuandoseanecesario,esposiblehacerqueunafunciónmodifiqueunavariabledentrodeunarutinainvocada.Lafunciónquellamadebeproporcionarladireccióndelavariablequeserácambiada(técnicamenteunapuntadoralavariable),ylafunciónqueseinvocadebedeclararqueelparámetroseaunapuntadorytengaaccesoalavariableindirectamenteatravésdeél.Losapuntadoressetrataránenelcapítulo5.

Lahistoriaesdiferenteconlosarreglos.Cuandoelnombredeunarregloseempleacomoargumento,elvalorquesepasaalafuncióneslalocalizaciónoladireccióndelprincipiodelarreglo—nohaycopiadeloselementosdelarreglo.Alcolocarlesubíndicesaestevalor,lafunciónpuedeteneraccesoyalterarcualquierelementodelarreglo.Esteeseltemadelasiguientesección.

Page 45: Titivillus 07.07

1.9.Arreglosdecaracteres

EltipodearreglomáscomúnenCeseldecaracteres.Parailustrarelusodearreglosdecaracteresyfuncionesquelosmanipulan,escribaunprogramaqueleaunconjuntodelíneasdetextoeimprimalademayorlongitud.Elpseudocódigoesbastantesimple:

while(hayotralínea)

if(esmáslargaquelaanteriormáslarga)

guárdala

guardasulongitud

imprimelalíneamáslarga

Estepseudocódigodejaenclaroqueelprogramasedividenaturalmenteenpartes.Unatraeunanuevalínea,otralapruebayelrestocontrolaelproceso.

Puestoqueladivisióndelaspartesesmuyfina,locorrectoseráescribirlasdeesemodo.Asípues,escribamosprimerounafuncióngetlineparaextraerlasiguientelíneadelaentrada.Trataremosdehaceralafunciónútilenotroscontextos.Almenos,getlinetienequeregresarunaseñalacercadelaposibilidaddeunfindearchivo;undiseñodemásutilidaddeberáretornarlalongituddelalínea,ocerosiseencuentraelfindearchivo.Ceroesunregresodefindearchivoaceptabledebidoaquenuncaesunalongituddelíneaválida.Cadalíneadetextotienealmenosuncarácter;inclusounalíneaquesólocontengauncarácternuevalíneatienelongitud1.

Cuandoseencuentreunalíneaqueesmayorquelaanteriormentemáslarga,sedebeguardarenalgúnlugar.Estosugiereunasegundafuncióncopy,paracopiarlanuevalíneaaunlugarseguro.

Finalmente,senecesitaunprogramaprincipalparacontrolargetlineycopy.Elresultadoeselsiguiente:

#include<stdio.h>

#defineMAXLINE1000/*tamañomáximodelalíneadeentrada*/

intgetline(charline[],intmaxline);

voidcopy(charto[],charfrom[]);

/*imprimelalíneadeentradamáslarga*/

main()

{

intlen;/*longitudactualdelalínea*/

intmax;/*máximalongitudvistahastaelmomento*/

Page 46: Titivillus 07.07

charline[MAXLINE];/*líneadeentradaactual*/

charlongest[MAXLINE];/*lalíneamáslargaseguardaaquí*/

max=0;

while((len=getline(line,MAXLINE))>0)

if(len>max){

max=len;

copy(longest,line);

}

if(max>0)/*hubounalínea*/

printf("%s",longest);

return0;

}

/*getline:leeunalíneaens,regresasulongitud*/

intgetline(chars[],intlim)

{

intc,i;

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

s[i]=c;

if(c=='\n'){

s[i]=c;

++i;

}

s[i]='\0';

returni;

}

/*copy:copia'from'en'to';suponequetoessuficientementegrande*/

voidcopy(charto[],charfrom[])

{

Page 47: Titivillus 07.07

inti;

i=0;

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

++i;

}

Lasfuncionesgetlineycopyestándeclaradasalprincipiodelprograma,quesesuponeestácontenidoenunarchivo.

mainygetlinesecomunicanatravésdeunpardeargumentosyunvalorderetorno.Engetlinelosargumentossedeclaranporlalínea

intgetline(chars[],intlim)

queespecificaqueelprimerargumento,s,esunarreglo,yelsegundo,lim,esunentero.Elpropósitodeproporcionareltamañodeunarregloesfijarespaciodealmacenamientocontiguo.Lalongituddelarreglosnoesnecesariaengetline,puestoquesutamañosefijaenmain.Engetlineseutilizareturnpararegresarunvaloraquiénlollama,talcomohizolafunciónpower.Estalíneatambiéndeclaraquegetlineregresaunint;puestoqueinteselvalorderetornoporomisión,puedesuprimirse.

Algunasfuncionesregresanunvalorútil;otras,comocopy,seempleanúnicamenteporsuefectoynoregresanunvalor.Eltipoderetornodecopyesvoid,elcualestableceexplícitamentequeningúnvalorseregresa.

Engetlinesecolocaelcarácter'\0'(carácternulo,cuyovalorescero)alfinaldelarregloqueestácreando,paramarcarelfindelacadenadecaracteres.EstaconvencióntambiénseutilizaporellenguajeC:cuandounaconstantedecaráctercomo

"hola\n"

apareceenunprogramaenC,sealmacenacomounarregloquecontieneloscaracteresdelacadenayterminaconun'\0'paramarcarelfin.

h

o

l

a

\n

\0

Laespecificacióndeformato%sdentrodeprintfesperaqueelargumentocorrespondienteseaunacadenarepresentadadeestemodo;copytambiénsebasaenelhechodequesuargumentodeentradaseterminacon'\0',ycopiaestecarácterdentrodelargumentodesalida.(Todoestoimplicaque'\0',noespartedeuntextonormal.)

Esútilmencionardepasoqueaununprogramatanpequeñocomoéstepresentaalgunosproblemasdediseño.Porejemplo,¿quédebehacermainsiencuentraunalínea

Page 48: Titivillus 07.07

queesmayorquesulímite?getlinetrabajaenformasegura,enesecasodetienelarecopilacióncuandoelarregloestálleno,aunquenoencuentreelcarácternuevalínea.Probandolalongitudyelúltimocarácterdevuelto,mainpuededeterminarsilalíneafuedemasiadolarga,yentoncesrealizaeltratamientoquesedesee.Porbrevedad,hemosignoradoelasunto.

Paraunusuariodegetlinenoexisteformadesaberconanticipacióncuánlargapodráserunalíneadeentrada,porloquegetlinerevisaunposibledesbordamiento(overflow).Porotrolado,elusuariodecopyyaconoce(olopuedeaveriguar)cuáleseltamañodelacadena,porloquedecidimosnoagregarcomprobacióndeerroresenella.

Ejercicio1-16.Corrijalarutinaprincipaldelprogramadelalíneamáslargademodoqueimprimacorrectamentelalongituddelíneasdeentradaarbitrariamentelargas,ytantotextocomoseaposible.□

Ejercicio1-17.Escribaunprogramaqueimprimatodaslaslíneasdeentradaqueseanmayoresde80caracteres.□

Ejercicio1-18.Escribaunprogramaqueeliminelosblancosylostabuladoresqueesténalfinaldecadalíneadeentrada,yqueborrecompletamentelaslíneasenblanco.□

Ejercicio1-19.Escribaunafunciónreverse(s)queinviertalacadenadecaracteress.Úselaparaescribirunprogramaqueinviertasuentrada,líneaalínea.□

Page 49: Titivillus 07.07

1.10.Variablesexternasyalcance

Lasvariablesqueestánenmain,talcomoline,longest,etc.,sonprivadasolocalesaella.Debidoaquesondeclaradasdentrodemain,ningunaotrafunciónpuedeteneraccesodirectoaellas.Lomismotambiénesválidoparavariablesdeotrasfunciones;porejemplo,lavariableiengetlinenotienerelaciónconlaiqueestáencopy.Cadavariablelocaldeunafuncióncomienzaaexistirsólocuandosellamaalafunción,ydesaparececuandolafuncióntermina.Estoesporloquetalesvariablessonconocidascomovariablesautomáticas,siguiendolaterminologíadeotroslenguajes.Aquíseutilizaráenadelanteeltérminoautomáticoparahacerreferenciaaesasvariableslocales.(Enelcapítulo4sediscutelacategoríadealmacenamientoestática,enlaquelasvariableslocalessíconservansusvaloresentrellamadas.)

Debidoaquelasvariableslocalesaparecenydesaparecenconlainvocacióndefunciones,noretienensusvaloresentredosllamadassucesivas,ydebenserinicializadasexplícitamenteencadaentrada.Denohacerlo,contendrán“basura”.

Comounaalternativaalasvariablesautomáticas,esposibledefinirvariablesquesonexternasatodaslasfunciones,estoes,variablesalasquetodafunciónpuedeteneraccesoporsunombre.(EstemecanismoesparecidoalCOMMONdeFortranoalasvariablesdePascaldeclaradasenelbloquemásexterior.)Debidoaqueesposibleteneraccesoglobalalasvariablesexternas,éstaspuedenserusadasenlugardelistasdeargumentosparacomunicardatosentrefunciones.Además,puestoquelasvariablesexternassemantienenpermanentementeenexistencia,enlugardeaparecerydesaparecercuandosellamanyterminanlasfunciones,mantienensusvaloresaundespuésdequeregresalafunciónquelosfijó.

Unavariableexternadebedefinirse,exactamenteunavez,fueradecualquierfunción;estofijaunespaciodealmacenamientoparaella.Lavariabletambiéndebedeclararseencadafunciónquedeseeteneraccesoaella;estoestableceeltipodelavariable.Ladeclaracióndebeserunaproposiciónexternexplicita,obienpuedeestarimplícitaenelcontexto.Paraconcretarladiscusión,reescribamoselprogramadelalíneamáslargaconline,longestymaxcomovariablesexternas.Estorequierecambiarlasllamadas,declaracionesycuerposdelastresfunciones.

#include<stdio.h>

#defineMAXLINE1000/*máximotamañodeunalíneadeentrada*/

intmax;/*máximalongitudvistahastaelmomento*/

charline[MAXLINE];/*líneadeentradaactual*/

charlongest[MAXLINE];/*lalíneamáslargaseguardaaquí*/

intgetline(void);

voidcopy(void);

/*imprimelalíneadeentradamáslarga;versiónespecializada*/

main()

Page 50: Titivillus 07.07

{

intlen;

externintmax;

externcharlongest[];

max=0;

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

if(len>max){

max=len;

copy();

}

if(max>0)/*hubounalínea*/

printf("%s",longest);

return0;

}

/*getline:versiónespecializada*/

intgetline(void)

{

intc,i;

externcharline[];

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

line[i]=c;

if(c=='\n'){

line[i]=c;

++i;

}

line[i]='\0';

returni;

}

Page 51: Titivillus 07.07

/*copy:versiónespecializada*/

voidcopy(void)

{

inti;

externcharline[],longest[];

i=0;

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

++i;

}

Lasvariablesexternasdemain,getlineycopyestándefinidasenlasprimeraslíneasdelejemploanterior,loqueestablecesutipoycausaqueselesasigneespaciodealmacenamiento.Desdeelpuntodevistasintáctico,lasdefinicionesexternassonexactamentecomolasdefinicionesdevariableslocales,peropuestoqueocurrenfueradelasfunciones,lasvariablessonexternas.Antesdequeunafunciónpuedausarunavariableexterna,sedebehacersaberelnombredelavariablealafunción.Unaformadehacerestoesescribirunadeclaraciónexterndentrodelafunción;ladeclaracióneslamismaqueantes,exceptoporlapalabrareservadaextern.

Bajociertascircunstancias,ladeclaraciónexternsepuedeomitir.Siladefinicióndeunavariableexternaocurredentrodelarchivofuenteantesdesuusoporunafunciónenparticular,entoncesnoesnecesarioelusodeunadeclaraciónexterndentrodelafunción.Ladeclaraciónexternenmain,getlineycopyes,porlotanto,redundante.Dehecho,unaprácticacomún,esponerlasdefinicionesdetodaslasvariablesexternasalprincipiodelarchivofuenteydespuésomitirtodaslasdeclaracionesextern.

Sielprogramaestáenvariosarchivosfuenteyunavariablesedefineenarchivo1yseutilizaenarchivo2yarchivo3,entoncessenecesitandeclaracionesexternenarchivo2yarchivo3paraconectarlasocurrenciasdelavariable.Laprácticacomúnesreunirdeclaracionesexterndevariablesyfuncionesenunarchivoseparado,llamadohistóricamenteheader,queesincluidopor#includealprincipiodecadaarchivofuente.Elsufijo.hseusaporconvenciónparanombresdeheaders.Lasfuncionesdelabibliotecaestándar,porejemplo,estándeclaradasenheaderscomo<stdio.h>.Estetemasetrataampliamenteenelcapítulo4,ylabibliotecaenelcapítulo7yenelapéndiceB.

Puestoquelasversionesespecializadasdegetlineycopynotienenargumentos,lalógicasugeriríaquesusprototiposalprincipiodelarchivodebensergetline()ycopy().PeroporcompatibilidadconprogramasdeCanteriores,elestándartomaaunalistavacíacomounadeclaraciónalviejoestilo,ysuspendetodarevisióndelistasdeargumentos;paraunalistaexplícitamentevacíadebeemplearselapalabravoid.Estosediscutiráenelcapítulo4.

Sedebenotarqueempleamoscuidadosamentelaspalabrasdefiniciónydeclaracióncuandonosreferimosavariablesexternasenestasección.Lapalabra“definición”serefiereallugardondesecrealavariableoseleasignaunlugardealmacenamiento;“declaración”serefiereallugardondeseestablecelanaturalezadelavariableperonoseleasignaespacio.

Page 52: Titivillus 07.07

Apropósito,existeunatendenciaaconvertirtodoenvariablesextern,debidoaqueaparentementesimplificalascomunicaciones—laslistasdeargumentossoncortasylasvariablesexistensiempre,cuandoselesrequiere.Perolasvariablesexternasexistensiempre,auncuandonohacenfalta.Descansarfuertementesobrevariablesexternasespeligroso,puestoquellevaaprogramascuyasconexionesentredatosnosoncompletamenteobvias—lasvariablespuedencambiarseenformainesperadaeinadvertida,yelprogramaesdifícildemodificar.Lasegundaversióndelprogramadelalíneamayoresinferioralaprimera,enparteporlasanterioresrazonesyenparteporquedestruyelageneralidaddedosútilesfunciones,introduciendoenellaslosnombresdelasvariablesquemanipula.

HastaestepuntohemosdescritoloquepodríallamarselosfundamentosconvencionalesdeC.Conestosfundamentos,esposibleescribirprogramasútilesdetamañoconsiderable,yprobablementeseríaunabuenaideahacerunapausasuficientementegrandepararealizarlos.Estosejerciciossugierenprogramasdecomplejidadalgomayorquelosanterioresdelcapítulo.

Ejercicio1-20.Escribaunprogramadetabquereemplacetabuladoresdelaentradaconelnúmeroapropiadodeblancosparaespaciarhastaelsiguienteparodetabulación.Considereunconjuntofijodeparosdetabulación,digamoscadancolumnas.¿Debesernunavariableounparámetrosimbólico?□

Ejercicio1-21.Escribaunprogramaentabquereemplacecadenasdeblancosporelmínimonúmerodetabuladoresyblancosparaobtenerelmismoespaciado.Considerelosparosdetabulacióndeigualmaneraqueparadetab.Cuandountabuladorounsimpleespacioenblancofuesesuficienteparaalcanzarunparodetabulación,¿acuálseledebedarpreferencia?□

Ejercicio1-22.Escribaunprogramapara“doblar”líneasgrandesdeentradaendosomáslíneasmáscortasdespuésdelúltimocarácternoblancoqueocurraantesdelan-ésimacolumnadeentrada.Asegúresedequesuprogramasecomporteapropiadamenteconlíneasmuylargas,ydequenohayblancosotabuladoresantesdelacolumnaespecificada.□

Ejercicio1-23.EscribaunprogramaparaeliminartodosloscomentariosdeunprogramaenC.Noolvidemanejarapropiadamentelascadenasentrecomillasylasconstantesdecarácter.LoscomentariosdeCnoseanidan.□

Ejercicio1-24.EscribaunprogramapararevisarloserroresdesintaxisrudimentariosdeunprogramaenC,comoparéntesis,llavesycorchetesnoalineados.Noolvidelascomillasnilosapóstrofos,lassecuenciasdeescapeyloscomentarios.(Esteprogramaesdifícilsisehacecompletamentegeneral.)□

Page 53: Titivillus 07.07

CAPÍTULO2:Tipos,operadoresyexpresiones

Lasvariablesylasconstantessonlosobjetosdedatosbásicosquesemanipulanenunprograma.Lasdeclaracionesmuestranlasvariablesquesevanautilizaryestableceneltipoquetienenyalgunasvecescuálessonsusvaloresiniciales.Losoperadoresespecificanloqueseharáconlasvariables.Lasexpresionescombinanvariablesyconstantesparaproducirnuevosvalores.Eltipodeunobjetodeterminaelconjuntodevaloresquepuedeteneryquéoperacionessepuedenrealizarsobreél.Estossonlostemasdeestecapítulo.

ElestándarANSIhahechomuchospequeñoscambiosyagregadosalostiposbásicosyalasexpresiones.Ahorahayformassignedyunsigneddetodoslostiposenteros,ynotacionesparaconstantessinsignoyconstantesdecarácterhexadecimales.Lasoperacionesdepuntoflotantepuedenhacerseenprecisiónsencilla;tambiénhayuntipolongdoubleparaprecisiónextendida.Lasconstantesdecadenapuedenconcatenarsealtiempodecompilación.Lasenumeracionessonyapartedellenguaje,formalizandounacaracterísticapendientepormuchotiempo.Losobjetospuedenserdeclaradosconst,loqueimpidequecambien.Lasreglasparaconversiónautomáticaentretiposaritméticosseaumentaronparamanejarelahoramásricoconjuntodetipos.

Page 54: Titivillus 07.07

2.1.Nombresdevariables

Aunquenolomencionamosenelcapítulo1,existenalgunasrestriccionesenlosnombresdelasvariablesydelasconstantessimbólicas.Losnombressecomponendeletrasydígitos;elprimercarácterdebeserunaletra.Elcarácterdesubrayado“_”cuentacomounaletra;algunasvecesesútilparamejorarlalegibilidaddenombreslargosdevariables.Sinembargo,nosedebecomenzarlosnombresdevariablesconestecarácter,puestoquelasrutinasdebibliotecaconfrecuenciausantalesnombres.Lasletrasmayúsculasyminúsculassondistintas,detalmaneraquexyXsondosnombresdiferentes.LaprácticatradicionaldeCesusarletrasminúsculasparanombresdevariables,ytodoenmayúsculasparaconstantessimbólicas.

Almenoslosprimeros31caracteresdeunnombreinternosonsignificativos,paranombresdefuncionesyvariablesexternaselnúmeropuedesermenorque31,puestoquelosnombresexternoslospuedenusarlosensambladoresyloscargadores,sobrelosqueellenguajenotienecontrol.Paranombresexternos,elestándargarantizadistinguirsólopara6caracteresysindiferenciarmayúsculasdeminúsculas.Laspalabrasclavecomoif,else,int,float,etc.,estánreservadas:nosepuedenutilizarcomonombresdevariables.Todasellasdebenescribirseconminúsculas.

Esconvenienteelegirnombresqueesténrelacionadosconelpropósitodelavariable,quenoseaprobableconfundirlostipográficamente.Nosotrostendemosautilizarnombrescortosparavariableslocales,especialmenteíndicesdeiteraciones,ynombresmáslargosparavariablesexternas.

Page 55: Titivillus 07.07

2.2.Tiposytamañosdedatos

HayunoscuantostiposdedatosbásicosenC:

char

unsolobyte,capazdeconteneruncarácterdelconjuntodecaractereslocal.

int

unentero,normalmentedeltamañonaturaldelosenterosenlamáquinaenlaqueseejecuta.

float

puntoflotantedeprecisiónnormal.

double

puntoflotantededobleprecisión.

Además,existenalgunoscalificadoresqueseaplicanaestostiposbásicos,shortylongseaplicanaenteros:

shortintsh;

longintcounter;

Lapalabraintpuedeomitirsedetalesdeclaraciones,loquetípicamentesehace.

Laintenciónesqueshortylongpuedanproporcionardiferenteslongitudesdeenterosdondeseapráctico;intseránormalmenteeltamañonaturalparaunamáquinaenparticular.Amenudoshortesde16bitsylongde32;intesde16ode32bits.Cadacompiladorpuedeseleccionarlibrementelostamañosapropiadosparasupropiohardware,sujetosóloalarestriccióndequelosshortseintsson,porlomenosde16bits,loslongssonporlomenosde32bitsyelshortnoesmayorqueint,elcualasuveznoesmayorquelong.

Elcalificadorsignedounsignedpuedeaplicarseacharoacualquierentero.Losnúmerosunsignedsonsiemprepositivosoceroyobedecenlasleyesdelaaritméticamódulo2n,dondeneselnúmerodebitseneltipo.Así,porejemplo,siloscharsonde8bits,lasvariablesunsignedchartienenvaloresentre0y255,entantoquelasvariablessignedchartienenvaloresentre-128y127(enunamáquinadecomplementoados).Elhechodequeloscharsordinariosseanconsignoosinéldependedelamáquina,peroloscaracteresquesepuedenimprimirsonsiemprepositivos.

Eltipolongdoubleespecificapuntoflotantedeprecisiónextendida.Igualqueconlosenteros,lostamañosdeobjetosdepuntoflotantesedefinenenlaimplantación;float,doubleylongdoublepuedenrepresentaruno,dosotrestamañosdistintos.

Losarchivosdeencabezadoheadersestándar<limits.h>y<float.h>contienenconstantessimbólicasparatodosesostamaños,juntoconotraspropiedadesdelamáquinaydelcompilador,loscualessediscutenenelapéndiceB.

Page 56: Titivillus 07.07

Ejercicio2-1.Escribaunprogramaparadeterminarlosrangosdevariableschar,short,intylong,tantosignedcomounsigned,imprimiendolosvaloresapropiadosdelosheadersestándaryporcálculodirecto.Esmásdifícilsiloscalcula:determinelosrangosdelosvariostiposdepuntoflotante.□

Page 57: Titivillus 07.07

2.3.Constantes

Unaconstanteenteracomo1234esunint.Unaconstantelongseescribeconunal(ele)oLterminal,comoen123456789L;unenterodemasiadograndeparacaberdentrodeuninttambiénserátomadocomolong.LasconstantessinsignoseescribenconunauoU,terminalyelsufijouloULindicaunsignedlong.

Lasconstantesdepuntoflotantecontienenunpuntodecimal(123.4)ounexponente(1e-2)oambos;sutipoesdouble,amenosquetengansufijo.LossufijosfoFindicanunaconstantefloat;loLindicanunlongdouble.

Elvalordeunenteropuedeespecificarseenformaoctalohexadecimalenlugardedecimal.Un0(cero)alprincipioenunaconstanteenterasignificaoctal;0xó0Xalprincipiosignificahexadecimal.Porejemplo,eldecimal31puedeescribirsecomo037enoctaly0x1fó0X1Fenhexadecimal.LasconstantesoctalesyhexadecimalestambiénpuedenserseguidasporLparaconvertirlasenlongyUparahacerlasunsigned:0XFULesunaconstanteunsignedlongconvalorde15endecimal.

Unaconstantedecarácteresunentero,escritocomouncarácterdentrodeapóstrofos,talcomo'x'.Elvalordeunaconstantedecaráctereselvalornuméricodelcarácterenelconjuntodecaracteresdelamáquina.Porejemplo,enelconjuntodecaracteresASCIIelcarácterconstante'0'tieneelvalorde48,elcualnoestárelacionadoconelvalornumérico0.Siescribimos'0'envezdeunvalornuméricocomo48quedependedelconjuntodecaracteres,elprogramaesindependientedelvalorparticularymásfácildeleer.Lasconstantesdecarácterparticipanenoperacionesnuméricastalcomocualesquierotrosenteros,aunqueseutilizanmáscomúnmenteencomparacionesconotroscaracteres.

Ciertoscaracterespuedenserrepresentadosenconstantedecarácterydecadena,Pormediodesecuenciasdeescapecomo\n(nuevalínea);esassecuenciassevencomodoscaracteres,perorepresentansólouno.Además,unpatróndebitsarbitrariodetamañodeunbytepuedeserespecificadopor

'\ooo'

endondeooosondeunoatresdígitosoctales(0...7)opor

'\xhh‘

endondehhsonunoomásdígitoshexadecimales(0...9,a...f,A...F).Asípodríamosescribir

#defineVTAB'\013'/*tabverticalASCII*/

#defineBELL'\007'/*caráctercampanaASCII*/

o,enhexadecimal,

#defineVTAB'\xb'/*tabverticalASCII*/

#defineBELL'\x7'/*caráctercampanaASCII*/

Elconjuntocompletodesecuenciasdeescapees

Page 58: Titivillus 07.07

\a

carácterdealarma(campana)

\\

diagonalinvertida

\b

retroceso

\?

interrogación

\f

avancedehoja

\'

apóstrofo

\n

nuevalínea

\"

comillas

\r

regresodecarro

\ooo

númerooctal

\t

tabuladorhorizontal

\xhh

númerohexadecimal

\v

tabuladorvertical

Laconstantedecarácter'\0'representaelcarácterconvalorcero,elcarácternulo.'\0'amenudoseescribeenvezde0paraenfatizarlanaturalezadecarácterdealgunasexpresiones,peroelvalornuméricoesprecisamente0.

Page 59: Titivillus 07.07

Unaexpresiónconstanteesunaexpresiónquesóloinmiscuyeconstantes.Talesexpresionespuedenserevaluadasdurantelacompilaciónenvezdequesehagaentiempodeejecución,yportantopuedenserutilizadasencualquierlugarenquepuedaencontrarseunaconstante,comoen

#defineMAXLINE1000

charline[MAXLINE+1];

o

#defineLEAP1/*enañosbisiestos*/

intdays[31+28+LEAP+31+30+31+30+31+31+30+31+30+31];

Unaconstantedecadenaocadenaliteral,esunasecuenciadeceroomáscaracteresencerradosentrecomillas,comoen

"Soyunacadena"

o

""/*lacadenavacía*/

Lascomillasnosonpartedelacadena,sólosirvenparadelimitarla.Lasmismassecuenciasdeescapeutilizadasenconstantesdecarácterseaplicanencadenas;\"representaelcaráctercomillas.Lasconstantesdecadenapuedenserconcatenadasentiempodecompilación:

"hola,""mundo"

esequivalentea

"hola,mundo"

Estoesútilparasepararcadenaslargasentrevariaslíneasfuente.

Técnicamente,unaconstantedecadenaesunarreglodecaracteres.Larepresentacióninternadeunacadenatieneuncarácternulo'\0'alfinal,demodoqueelalmacenamientofísicorequeridoesunomásdelnúmerodecaracteresescritosentrelascomillas.Estarepresentaciónsignificaquenohaylímiteencuantoaquétanlargapuedeserunacadena,perolosprogramasdebenleercompletamenteunacadenaparadeterminarsulongitud.Lafunciónstrlen(s)delabibliotecaestándarregresalalongituddesuargumentosdetipocadenadecaracteres,excluyendoel'\0'terminal.Aquíestánuestraversión:

/*strlen:regresalalongituddes*/

intstrlen(chars[])

{

inti;

i=0;

while(s[i]!='\0')

Page 60: Titivillus 07.07

++i;

returni;

}

strlenyotrasfuncionesparacadenasestándeclaradasenelheaderestándar<string.h>.

Sedebesercuidadosoaldistinguirentreunaconstantedecarácteryunacadenaquecontieneunsólocarácter:'x'noeslomismoque"x".Elprimeroesunentero,utilizadoparaproducirelvalornuméricodelaletraxenelconjuntodecaracteresdelamáquina.Elúltimoesunarreglodecaracteresquecontieneuncarácter(laletrax)yun'\0'.

Existeotraclasedeconstante,laconstantedeenumeración.Unaenumeraciónesunalistadevaloresenterosconstantes,comoen

enumboolean{NO,YES};

Elprimernombreenunenumtienevalor0,elsiguiente1,yasísucesivamente,amenosqueseanespecificadosvaloresexplícitos.Sinotodoslosvaloressonespecificados,losvaloresnoespecificadoscontinúanlaprogresiónapartirdelúltimovalorquesílofue,comoenelsegundodeesosejemplos:

enumescapes{BELL='\a',RETROCESO='\b',TAB='\t',

NVALIN='\n',VTAB='\v',RETURN='\r'};

enummonths{ENE=1,FEB,MAR,ABR,MAY,JUN,

JUL,AGO,SEP,OCT,NOV,DIC};

/*FEBes2,MARes3,etc.*/

Losnombresqueestánenenumeracionesdiferentesdebenserdistintos.Losvaloresnonecesitanserdistintosdentrodelamismaenumeración.

Lasenumeracionesproporcionanunamaneraconvenientedeasociarvaloresconstantesconnombres,unaalternativaa#defineconlaventajadequelosvalorespuedensergeneradosparauno.Aunquelasvariablesdetiposenumpuedenserdeclaradas,loscompiladoresnonecesitanrevisarqueloquesevaaalmacenarentalvariableesunvalorválidoparalaenumeración.Noobstante,lasvariablesdeenumeraciónofrecenlaoportunidadderevisarlasytalcosaesamenudomejorque#define.Además,undepuradorpuedesercapazdeimprimirlosvaloresdevariablesdeenumeraciónensuformasimbólica.

Page 61: Titivillus 07.07

2.4.Declaraciones

Todaslasvariablesdebenserdeclaradasantesdesuuso,aunqueciertasdeclaracionespuedenserhechasenformaimplícitaporelcontexto.Unadeclaraciónespecificauntipo,ycontieneunalistadeunaomásvariablesdeesetipo,comoen

intlower,upper,step;

charc,line[1000];

Lasvariablespuedenserdistribuidasentrelasdeclaracionesencualquierforma;lalistadearribapodríaigualmenteserescritacomo

intlower;

intupper;

intstep;

charc;

charline[1000];

Estaúltimaformaocupamásespacio,peroesconvenienteparaagregaruncomentarioacadadeclaraciónoparamodificacionessubsecuentes.

Unavariabletambiénpuedeserinicializadaensudeclaración.Sielnombreesseguidoporunsignodeigualyunaexpresión,laexpresiónsirvecomouninicializador,comoen

charesc='\\';

inti=0;

intlimit=MAXLINE+1;

floateps=1.0e-5;

Silavariableencuestiónnoesautomática,lainicializaciónesefectuadasólounavez,conceptualmenteantesdequeelprogramainiciesuejecución,yelinicializadordebeserunaexpresiónconstante.Unavariableautomáticaexplícitamenteinicializadaesinicializadacadavezqueseentraalafunciónobloqueenqueseencuentra;elinicializadorpuedesercualquierexpresión.Lasvariablesestáticasyexternassoninicializadasenceroporomisión.Lasvariablesautomáticasparalasquenohayuninicializadorexplícitotienenvaloresindefinidos(estoes,basura).

Elcalificadorconstpuedeaplicarsealadeclaracióndecualquiervariableparaespecificarquesuvalornoserácambiado.Paraunarreglo,elcalificadorconstindicaqueloselementosnoseránalterados.

constdoublee=2.71828182845905;

constcharmsg[]="precaución:";

Page 62: Titivillus 07.07

Ladeclaraciónconsttambiénsepuedeutilizarconargumentosdetipoarreglo,paraindicarquelafunciónnocambiaesearreglo:

intstrlen(constchar[]);

Siseefectúaunintentodecambiarunconst,elresultadoestádefinidoporlaimplantación.

Page 63: Titivillus 07.07

2.5.Operadoresaritméticos

Losoperadoresaritméticosbinariosson+,-,*,/,yeloperadormódulo%.

Ladivisiónenteratruncacualquierpartefraccionaria.Laexpresión

x%y

produceelresiduocuandoxesdivididoentrey,porloqueescerocuandoydivideaxexactamente.Porejemplo,unañoesbisiestosiesdivisibleentre4peronoentre100,exceptoaquellosañosquesondivisiblesentre400,quesísonbisiestos.Porlotanto

if((year%4==0&&year%100!=0)||year%400==0)

printf(”%desunañobisiesto\n",year);

else

printf("%dnoesunañobisiesto\n",year);

Eloperador%nopuedeaplicarseaoperandosfloatodouble.Ladireccióndetruncamientopara/yelsignodelresultadode%sondependientesdelamáquinaparaoperandosnegativos,asícomolaacciónquesetomaencasodesobreflujoosubflujo.

Losoperadoresbinarios+y-tienenlamismaprecedencia,lacualesmenorquelaprecedenciade*,/,y%,queasuvezesmenorque+y-unarios.Losoperadoresaritméticosseasociandeizquierdaaderecha.

Latabla2-1queseencuentraalfinaldeestecapítulo,resumelaprecedenciayasociatividadparatodoslosoperadores.

Page 64: Titivillus 07.07

2.6.Operadoresderelaciónylógicos

Losoperadoresderelaciónson

>>=<<=

Todosellostienenlamismaprecedencia.Precisamentebajoellosenprecedenciaestánlosoperadoresdeigualdad:

==!=

Losoperadoresderelacióntienenprecedenciainferiorquelosoperadoresaritméticos,asíqueunaexpresióncomoi<lim-1setomacomoi<(lim-1),comoseesperaría.

Másinteresantessonlosoperadoreslógicos&&y||.Lasexpresionesconectadaspor&&o||sonevaluadasdeizquierdaaderecha,ylaevaluaciónsedetienetanprontocomoseconoceelresultadoverdaderoofalso.LamayoríadelosprogramasenCdescansansobreesaspropiedades.Porejemplo,aquíestáunciclodelafuncióndeentradagetlinequeescribimosenelcapítulo1:

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

s[i]=c;

Antesdeleerunnuevocarácteresnecesarioverificarquehayespacioparaalmacenarloenelarreglos,asíquelapruebai<lim-1debehacerseprimero.Además,siestapruebafalla,nodebemosseguiryleerotrocarácter.

Demanerasemejante,seríadesafortunadosicfueseprobadacontraEOFantesdequesellameagetchar;porlotanto,lallamadaylaasignacióndebenocurrirantesdequesepruebeelcarácterc.

Laprecedenciade&&esmásaltaquelade||,yambassonmenoresquelosoperadoresderelaciónydeasignación,asíqueexpresionescomo

i<lim-1&&(c=getchar())!='\n'&&c!=EOF

norequierendeparéntesisadicionales.Peropuestoquelaprecedenciade!=essuperiorquelaasignación,losparéntesissenecesitanen

(c=getchar())!='\n'

paraobtenerelresultadodeseadodeasignaciónacydespuéscomparacióncon'\n'.

Pordefinición,elvalornuméricodeunaexpresiónderelaciónológicaes1silarelaciónesverdadera,y0silarelaciónesfalsa.

Eloperadorunariodenegación!convierteaunoperandoquenoesceroen0,yaunoperandoceroen1.Unusocomúnde!esenconstruccionescomo

if(!válido)

enlugarde

Page 65: Titivillus 07.07

if(válido==0)

Esdifícilgeneralizaracercadecuáleslamejor.Construccionescomo!válidoseleenenformaagradable(“sinoesválido”),perootrasmáscomplicadaspuedenserdifícilesdeentender.

Ejercicio2-2.Escribauncicloequivalentealaiteraciónforanteriorsinusar&&o||.□

Page 66: Titivillus 07.07

2.7.Conversionesdetipo

Cuandounoperadortieneoperandosdetiposdiferentes,éstosseconviertenauntipocomúndeacuerdoconunreducidonúmerodereglas.Engeneral,lasúnicasconversionesautomáticassonaquellasqueconviertenunoperando“angosto”enuno“amplio”sinpérdidadeinformación,talcomoconvertirunenteroapuntoflotanteenunaexpresióncomof+i.Lasexpresionesquenotienensentido,comoutilizarunfloatcomosubíndice,nosonpermitidas.Lasexpresionesquepodríanperderinformación,comoasignaruntipomayoraunomáscorto,ountipodepuntoflotanteaunentero,puedenproducirunaadvertencia,peronosonilegales.

Uncharsóloesunenteropequeño,porloqueloscharsepuedenutilizarlibrementeenexpresionesaritméticas.Estopermiteunaflexibilidadconsiderableenciertasclasesdetransformacióndecaracteres.Unaesejemplificadaconestaingenuaimplantacióndelafunciónatoi,queconvierteunacadenadedígitosensuequivalentenumérico.

/*atoi:conviertesenentero*/

intatoi(chars[])

{

inti,n;

n=0;

for(i=0;s[i]>='0'&&s[i]<='9';++i)

n=10*n+(s[i]-'0');

returnn;

}

Talcomosediscutióenelcapítulo1,laexpresión

s[i]-'0'

daelvalornuméricodelcarácteralmacenadoens[i],debidoaquelosvaloresde'0','1',etc.,formanunasecuenciaascendentecontigua.

Otroejemplodeconversióndecharainteslafunciónlower,queconvierteuncaráctersencilloaminúsculaparaelconjuntodecaracteresASCII.Sielcarácternoesunaletramayúscula,lowerloregresasincambio.

/*lower:conviertecaminúscula;solamenteASCII*/

intlower(intc)

{

if(c>='A'&&c<='Z')

Page 67: Titivillus 07.07

returnc+'a'-'A';

else

returnc;

}

EstofuncionaparaASCIIdebidoaquelascorrespondientesletrasmayúsculasyminúsculasestánaunadistanciafijacomovaloresnuméricosycadaalfabetoescontiguo—nohaysinoletrasentreAyZ.Sinembargo,estaúltimaobservaciónnoesciertaparaelconjuntodecaracteresEBCDIC,asíqueestecódigopodríaconvertiralgomásquesóloletrasenEBCDIC.

Elheaderestándar<ctype.h>,quesedescribeenelapéndiceB,defineunafamiliadefuncionesqueproporcionanpruebasyconversionesindependientesdelosjuegosdecaracteres.Porejemplo,lafuncióntolower(c)regresaelvalordelaletraminúsculadecsicesunamayúscula,demodoquetoloweresunreemplazotransportableparalafunciónlowermostradaantes.Demodosemejante,laprueba.

c>='0'&&c<='9'

puedereemplazarsepor

isdigit(c)

Nosotrosutilizaremoslasfuncionesde<ctype.h>enadelante.

Existeunsutilpuntoacercadelaconversióndecaracteresaenteros.Ellenguajenoespecificasilasvariablesdetipocharsonvaloresconosinsigno.Cuandouncharseconvierteaint,¿puedeproduciralgunavezunenteronegativo?Larespuestavaríadeunamáquinaaotra,reflejandodiferenciasenlaarquitectura.Enalgunasmáquinasuncharcuyobitmásalaizquierdaes1seconvertiráaunenteronegativo(“extensióndesigno”).Enotras,uncharespromovidoaunintagregandocerosdelladoizquierdo,asíquesiempreespositivo.

LadefinicióndeCgarantizaqueningúncarácterqueestéenelconjuntoestándardecaracteresdeimpresióndelamáquinaseránegativo,demodoqueesoscaracteressiempreseráncantidadespositivasenlasexpresiones.Perohaypatronesarbitrariosdebitsalmacenadosenvariablesdetipocarácterquepuedenaparecercomonegativosenalgunasmáquinas,aunqueseanpositivosenotras.Portransportabilidad,sedebeespecificarsignedounsignedsisevanaalmacenardatosquenosoncaracteresenvariablestipochar.

Lasexpresionesderelacióncomoi>jylasexpresioneslógicasconectadaspor&&y||estándefinidasparatenerunvalorde1siendoverdaderas,y0alserfalsas.Deestemodo,laasignación

d=c>='0'&&c<='9'

hace1adsicesundígito,y0sinoloes.Sinembargo,lasfuncionescomoisdigitpuedenregresarcualquiervalordiferentedecerocomoverdadero.Enlapartedevalidacióndeif,while,for,etc.,“verdadero”essólo“diferentedecero”,porloqueestonohacediferencia.

Lasconversionesaritméticasimplícitastrabajancomoseespera.Engeneral,siunoperadorcomo+o*quetomadosoperandos(operadorbinario)tieneoperandosde

Page 68: Titivillus 07.07

diferentestipos,eltipo“menor”espromovidoaltipo“superior”antesdequelaoperaciónproceda.Elresultadoeseldeltipomayor.Lasección6delapéndiceAestablecelasreglasdeconversiónenformaprecisa.Sinohayoperandosunsigned,sinembargo,elsiguienteconjuntoinformaldereglasbastará:

Sicualquieroperandoeslongdouble,conviértaseelotroalongdouble.

Deotramanera,sicualquieroperandoesdouble,conviértaseelotroadouble.

Deotramanera,sicualquieroperandoesfloat,conviértaseelotroafloat.

Deotramanera,conviértasecharyshortaint.

Después,sicualquieroperandoeslong,conviértaseelotroalong.

Nótesequelosfloatqueestánenunaexpresiónnoseconviertenautomáticamenteadouble;estoesuncambiodeladefiniciónoriginal.Engeneral,lasfuncionesmatemáticascomolasde<math.h>utilizarándobleprecisión.Larazónprincipalparausarfloatesahorrarespaciodealmacenamientoenarreglosgrandeso,conmenorfrecuencia,ahorrartiempoenmáquinasendondelaaritméticadedobleprecisiónesparticularmentecostosa.

Lasreglasdeconversiónsonmáscomplicadascuandohayoperandosunsigned.Elproblemaesquelascomparacionesdevaloresconsignoysinsignosondependientesdelamáquina,debidoaquedependendelostamañosdelosvariostiposdeenteros.Porejemplo,supóngasequeintesde16bitsylongde32.Entonces-1L<1U,debidoaque1U,queesunint,espromovidoasignedlong.Pero-1L>1UL,debidoaque-1Lespromovidoaunsignedlongyasípareceserungrannúmeropositivo.

Lasconversionestambiéntienenlugarenlasasignaciones;elvalordelladoderechoesconvertidoaltipodelaizquierda,elcualeseltipodelresultado.

Uncarácteresconvenidoaunentero,tengaonoextensióndesigno,comosedescribióanteriormente.

Losenterosmáslargossonconvertidosacortosoachardesechandoelexcesodebitsdemásaltoorden.Asíen

inti;

charc;

i=c;

c=i;

elvalordecnocambia.Estoesverdaderoyaseaqueseinmiscuyaonolaextensióndesigno.Sinembargo,elinvertirelordendelasasignacionespodríaproducirpérdidadeinformación.

Sixesfloateiesint,entoncesx=iei=xproduciránconversiones;defloataintprovocaeltruncamientodecualquierpartefraccionaria.Cuandodoubleseconvierteafloat,elqueseredondeeotrunqueelvaloresdependientedelaimplantación.

Puestoqueunargumentodelallamadaaunafunciónesunaexpresión,tambiénsucedenconversionesdetipocuandosepasanargumentosafunciones.Enausenciadelprototipodeunafunción,charyshortpasanaserint,yfloatsehacedoble.Estaesla

Page 69: Titivillus 07.07

razónporlaquehemosdeclaradolosargumentosafuncionescomointydouble,auncuandolafunciónsellamaconcharyfloat.

Finalmente,laconversiónexplícitadetipopuedeserforzada(“coaccionada”)encualquierexpresión,conunoperadorunariollamadocast.Enlaconstrucción

(nombre-de-tipo)expresión

laexpresiónesconvertidaaltiponombrado,porlasreglasdeconversiónanteriores.Elsignificadoprecisodeuncastescomosilaexpresiónfueraasignadaaunavariabledeltipoespecificado,queseutilizaentoncesenlugardelaconstruccióncompleta.Porejemplo,larutinadebibliotecasqrtesperaunargumentodedobleprecisiónyproduciráresultadossinsentidosimanejainadvertidamentealgodiferente,(sqrtestádeclaradoen<math.h>.)Así,sinesunentero,podemosusar

sqrt((double)n)

paraconvertirelvalordenadobleantesdepasarloasqrt.Nótesequelaconversiónforzosaproduceelvalordeneneltipoapropiado;nensínosealtera.Eloperadorcasttienelamismaaltaprecedenciaqueotrosoperadoresunarios,comoseresumeenlatabladelfinaldeestecapítulo.

Siunprototipodefuncióndeclaraargumentos,comodebesernormalmente,ladeclaraciónproduceconversiónforzadaautomáticadelosargumentoscuandolafunciónesllamada.Así,dadoelprototipodelafunciónsqrt:

doublesqrt(double);

lallamada

raíz2=sqrt(2);

obligaalentero2aserelvalordouble2.0sinnecesidaddeningúncast.

Labibliotecaestándarincluyeunaimplantacióntransportabledeungeneradordenúmerospseudoaleatorios,yunafunciónparainicializarlasemilla;loprimeroilustrauncast:

unsignedlongintnext=1;

/*rand:regresaunenteropseudoaleatorioen0..32767*/

intrand(void)

{

next=next*1103515245+12345;

return(unsignedint)(next/65536)%32768;

}

/*srand:fijalasemillapararand()*/

voidsrand(unsignedintseed)

{

Page 70: Titivillus 07.07

next=seed;

}

Ejercicio2-3.Escribalafunciónhtoi(s),queconvierteunacadenadedígitoshexadecimales(incluyendo0xó0Xenformaoptativa)ensuvalorenteroequivalente.Losdígitospermitidossondel0al9,delaaalaf,ydelaAalaF.□

Page 71: Titivillus 07.07

2.8.Operadoresdeincrementoydecremento

EllenguajeCproporcionadosoperadorespococomunesparaincrementarydecrementarvariables.Eloperadordeaumento++agrega1asuoperando,entantoqueeloperadordedisminución--leresta1.Hemosusadofrecuentemente++paraincrementarvariables,comoen

if(c=='\n')

++nl;

Elaspectopococomúnesque++y--puedenserutilizadocomoprefijos(antesdelavariable,comoen++n),ocomopostfijos(despuésdelavariable:n++).Enamboscasos,elefectoesincrementarn.Perolaexpresión++nincrementaanantesdequesuvalorseutilice,entantoquen++incrementaandespuésdequesuvalorsehaempleado.Estosignificaqueenuncontextodondeelvalorestásiendoutilizado,ynosóloelefecto,++nyn++sondiferentes.Sines5,entonces

x=n++;

asigna5ax,pero

x=++n;

hacequexsea6.Enamboscasos,nsehace6.Losoperadoresdeincrementoydecrementosólopuedenaplicarseavariables;unaexpresióncomo(i+j)++esilegal.

Dentrodeuncontextoendondenosedeseaningúnvalor,sinosóloelefectodeincremento,comoen

if(c=='\n')

ni++;

prefijosypostfijossoniguales.Peroexistensituacionesendondeserequiereespecíficamenteunouotro.Porejemplo,considéreselafunciónsqueeze(s,c),queeliminatodaslasocurrenciasdelcaráctercdeunacadenas.

/*squeeze:borratodaslascdes*/

voidsqueeze(chars[],intc)

{

inti,j;

for(i=j=0;s[i]!='\0';i++)

if(s[i]!=c)

s[j++]=s[i];

s[j]='\0';

Page 72: Titivillus 07.07

}

Cadavezqueseencuentraunvalordiferentedec,éstesecopiaenlaposiciónactualj,ysóloentoncesjesincrementadaparaprepararlaparaelsiguientecarácter.Estoesexactamenteequivalentea

if(s[i]!=c){

s[j]=s[i];

j++;

}

Otroejemplodeconstrucciónsemejantevienedelafuncióngetlinequeescribimosenelcapítulo1,endondepodemosreemplazar

if(c=='\n'){

s[i]=c;

++i;

}

poralgomáscompactocomo

if(c=='\n')

s[i++]=c;

Comountercerejemplo,considéresequelafunciónestándarstrcat(s,t),queconcatenalacadenatalfinaldelacadenas.strcatsuponequehaysuficienteespacioensparaalmacenarlacombinación.Comolahemosescrito,strcatnoregresaunvalor;laversióndelabibliotecaestándarregresaunapuntadoralacadenaresultante.

/*strcat:concatenatalfinaldes;sdebesersuficientementegrande*/

voidstrcat(chars[],chart[])

{

inti,j;

i=j=0;

while(s[i]!='\0')/*encuentraelfindes*/

i++;

while((s[i++]=t[j++])!='\0')/*copiat*/

;

}

Page 73: Titivillus 07.07

Comocadacaráctersecopiadetas,el++postfijoseaplicatantoaicomoajparaestarsegurosdequeambosestánenposiciónparalasiguienteiteración.

Ejercicio2-4.Escribaunaversiónalternadesqueeze(s1,s2)queborrecadacarácterdes1quecoincidaconcualquiercarácterdelacadenas2.□

Ejercicio2-5.Escribalafunciónany(s1,s2),queregresalaprimeraposicióndelacadenasiendondeseencuentrecualquiercarácterdelacadenas2,o-1sis1nocontienecaracteresdes2.(Lafuncióndebibliotecaestándarstrpbrkhaceelmismotrabajoperoregresaunapuntadoralaposiciónencontrada.)□

Page 74: Titivillus 07.07

2.9.Operadoresparamanejodebits

EllenguajeCproporcionaseisoperadoresparamanejodebits;sólopuedenseraplicadosaoperandosintegrales,estoes,char,short,int,ylong,conosinsigno.

&

ANDdebits

|

ORinclusivodebits

^

ORexclusivodebits

<<

corrimientoalaizquierda

>>

corrimientoaladerecha

~

complementoauno(unario)

EloperadorANDdebits&amenudoesusadoparaenmascararalgúnconjuntodebits;porejemplo,

n=n&0177;

hacecerotodoslosbitsden,menoslos7demenororden.

EloperadorORdebits|esempleadoparaencenderbits:

x=x|SET_ON;

fijaenunoatodoslosbitsdexquesonunoenSET_ON.

EloperadorORexclusivo^poneununoencadaposiciónendondesusoperandostienenbitsdiferentes,yceroendondesoniguales.

Sedebendistinguirlosoperadoresdebits&y|delosoperadoreslógicos&&y||,queimplicanevaluacióndeizquierdaaderechadeunvalordeverdad.Porejemplo,sixes1yyes2,entoncesx&yesceroentantoquex&&yesuno.

Losoperadoresdecorrimiento<<y>>realizancorrimientosalaizquierdayaladerechadesuoperandoqueestáalaizquierda,elnúmerodeposicionesdebitsdadoporeloperandodeladerecha,elcualdebeserpositivo.Asíx<<2desplazaelvalordexalaizquierdadosposiciones,llenandolosbitsvacantesconcero;estoesequivalentea

Page 75: Titivillus 07.07

unamultiplicaciónpor4.Elcorreraladerechaunacantidadunsignedsiemprellenalosbitsvacantesconcero.Elcorreraladerechaunacantidadsignadallenaráconbitsdesigno(“corrimientoaritmético”)enalgunasmáquinasyconbits0(“corrimientológico”)enotras.

Eloperadorunario~daelcomplementoaunodeunentero;estoes,conviertecadabit1enunbit0yviceversa.Porejemplo,

x=x&~077

fijalosúltimosseisbitsdexencero.Nótesequex&~077esindependientedelalongituddelapalabra,yporlotanto,espreferiblea,porejemplo,x&0177700,quesuponequexesunacantidadde16bits.Laformatransportablenoinvolucrauncostoextra,puestoque~077esunaexpresiónconstantequepuedeserevaluadaentiempodecompilación.

Comoilustracióndealgunosdelosoperadoresdebits,considerelafuncióngetbits(x,p,n)queregresaelcampodenbitsdex(ajustadoaladerecha)queprincipiaenlaposiciónp.Sesuponequelaposicióndelbit0estáenelbordederechoyquenypsonvalorespositivosadecuados.Porejemplo,getbits(x,4,3)regresalostresbitsqueestánenlaposición4,3y2,ajustadosaladerecha.

/*getbits:obtienenbitsdesdelaposiciónp*/

unsignedgetbits(unsignedx,intp,intn)

{

return(x>>(p+1-n))&~(~0<<n);

}

Laexpresiónx>>(p+1-n)mueveelcampodeseadoalbordederechodelapalabra.~0estodoslosbitsen1;corriendonbitshacialaizquierdacon~0<<ncolocacerosenlosnbitsmásaladerecha;complementadocon~haceunamáscaradeunosenlosnbitsmásaladerecha.

Ejercicio2-6.Escribaunafunciónsetbits(x,p,n,y)queregresaxconlosnbitsqueprincipianenlaposiciónpigualesalosnbitsmásaladerechadey,dejandolosotrosbitssincambio.□

Ejercicio2-7.Escribaunafuncióninvert(x,p,n)queregresaxconlosnbitsqueprincipianenlaposiciónpinvertidos(estoes,1cambiadoa0yviceversa),dejandolosotrossincambio.□

Ejercicio2-8.Escribaunafunciónrightrot(x,n)queregresaelvalordelenteroxrotadoaladerechanposicionesdebits.□

Page 76: Titivillus 07.07

2.10.Operadoresdeasignaciónyexpresiones

Lasexpresionestalescomo

i=i+2

enlasquelavariabledelladoizquierdoserepiteinmediatamenteenelderecho,puedenserescritasenlaformacompacta

i+=2

Eloperador+=sellamaoperadordeasignación.

Lamayoríadelosoperadoresbinarios(operadorescomo+quetienenunoperandoizquierdoyotroderecho)tienenuncorrespondienteoperadordeasignaciónop=,endondeopesunode

+-*/%<<>>&^|

Siexpr1yexpr2sonexpresiones,entonces

expr1op=expr2

esequivalentea

expr1=(expr1)op(expr2)

exceptuandoqueexpr1secalculasólounavez.Nótenselosparéntesisalrededordeexpr2:

x*=y+1

significa

x=x*(y+1)

yno

x=x*y+1

Comoejemplo,lafunciónbitcountcuentaelnúmerodebitsen1ensuargumentoentero.

/*bitcount:cuentabits1enx*/

intbitcount(unsignedx)

{

intb;

for(b=0;x!=0;x>>=1)

Page 77: Titivillus 07.07

if(x&01)

b++;

returnb;

}

Declararalargumentoxcomounsignedaseguraquecuandosecorrealaderecha,losbitsvacantessellenaránconceros,noconbitsdesigno,sinimportarlamáquinaenlaqueseejecuteelprograma.

Muyapartedesuconcisión,losoperadoresdeasignacióntienenlaventajadequecorrespondenmejorconlaformaenquelagentepiensa.Decimos“suma2ai”o“incrementaien2”,no“tomai,agrégale2,despuésponelresultadodenuevoeni”.Asílaexpresióni+=2espreferibleai=i+2.Además,paraunaexpresióncomplicadacomo

yyval[yypv[p3+p4]+yypv[p1+p2]]+=2

eloperadordeasignaciónhacealcódigomásfácildeentender,puestoqueellectornotienequeverificararduamentequedosexpresionesmuylargassonenrealidadiguales,opreguntarseporquénoloson,yunoperadordeasignaciónpuedeinclusoayudaralcompiladoraproducircódigomáseficiente.

Yahemosvistoquelaproposicióndeasignacióntieneunvalorypuedeestardentrodeexpresiones;elejemplomáscomúnes

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

...

Losotrosoperadoresdeasignación(+=,-=,etc.)tambiénpuedenestardentrodeexpresiones,aunqueestoesmenosfrecuente.

Entodasesasexpresiones,eltipodeunaexpresióndeasignacióneseltipodesuoperandodelladoizquierdo,ysuvaloreselvalordespuésdelaasignación.

Ejercicio2-9.Enunsistemadenúmerosdecomplementoados,x&=(x-1)borraelbit1demásaladerechaenx.Expliqueelporqué.Utiliceestaobservaciónparaescribirunaversiónmásrápidadebitcount.□

Page 78: Titivillus 07.07

2.11.Expresionescondicionales

Lasproposiciones

if(a>b)

z=a;

else

z=b;

calculanenzelmáximodeayb.Laexpresióncondicional,escritaconeloperadorternario“?:”,proporcionaunaformaalternativaparaescribiréstayotrasconstruccionessemejantes.Enlaexpresión

expr1?expr2:expr3

laexpresiónexpr1esevaluadaprimero.Siesdiferentedecero(verdadero),entonceslaexpresiónexpr2esevaluada,yéseeselvalordelaexpresióncondicional.Deotraforma,expr3seevalúa,yéseeselvalor.Sólounodeentreexpr2yexpr3,seevalúa.Así,parahacerzelmáximodeayb,

z=(a>b)?a:b;/*z=máx(a,b)*/

Sedebenotarquelaexpresióncondicionalesensíunaexpresión,ysepuedeutilizarencualquierlugardondeotraexpresiónpueda.Siexpr2yexpr3sondetiposdiferentes,eltipodelresultadosedeterminaporlasreglasdeconversióndiscutidasanteriormenteenestecapítulo.Porejemplo,sifesunfloatynesunint,entonceslaexpresión

(n>0)?f:n

esdetipofloatseanpositivoono.

Losparéntesisnosonnecesariosalrededordelaprimeraexpresióndeunaexpresióncondicional,puestoquelaprecedenciade?:esmuybaja,sóloarribadelaasignación.Decualquiermodosonrecomendables,puestoquehacenmásfácildeverlapartedecondicióndelaexpresión.

Laexpresióncondicionalfrecuentementellevaauncódigoconciso.Porejemplo,estecicloimprimenelementosdeunarreglo,10porlínea,concadacolumnaseparadaporunblanco,yconcadalínea(incluidalaúltima)terminadaporunanuevalínea.

for(i=0;i<n;i++)

printf("%6d%c",a[i],(i%10==9||i==n-1)?'\n':'');

Seimprimeuncarácternuevalíneadespuésdecadadiezelementos,ydespuésdeln-ésimo.Todoslosotroselementossonseguidosporunespacioenblanco.Estopodríaverseoscuro,peroesmáscompactoqueelif-elseequivalente.Otrobuenejemploes

printf("Hay%delemento%s.\n",n,n==1?"":"s");

Page 79: Titivillus 07.07

Ejercicio2-10.Reescribalafunciónlower,queconvierteletrasmayúsculaseminúsculas,conunaexpresióncondicionalenvezdeunif-else.□

Page 80: Titivillus 07.07

2.12.Precedenciayordendeevaluación

Latabla2-1resumelasreglasdeprecedenciayasociatividaddetodoslosoperadores,incluyendoaquellosqueaúnnosehantratado.Losoperadoresqueestánenlamismalíneatienenlamismaprecedencia;losrenglonesestánenordendeprecedenciadecreciente,así,porejemplo,*,/,y%tienentodoslamismaprecedencia,lacualesmásaltaquelade+y-binarios.El“operador”()serefierealallamadaaunafunción.Losoperadores->y.sonutilizadosparateneraccesoamiembrosdeestructuras;seráncubiertosenelcapítulo6,juntoconsizeof(tamañodeunobjeto).Enelcapítulo5sediscuten*(indirecciónatravésdeunapuntador)y&(direccióndeunobjeto),yenelcapítulo3setrataaloperadorcoma.

Nótesequelaprecedenciadelosoperadoresdebits&,^,y|estádebajode==y!=.Estoimplicaquelasexpresionesdepruebadebitscomo

if((x&MASK)==0)...

debensercompletamentecolocadasentreparéntesisparadarlosresultadosapropiados.

TABLA2-1.PRECEDENCIAYASOCIATIVIDADDEOPERADORES

OPERADORES

ASOCIATIVIDAD

()[]->

izquierdaaderecha

!~++--+-*&(

tipo

)sizeof

derechaaizquierda

*/%

izquierdaaderecha

+-

izquierdaaderecha

<<>>

izquierdaaderecha

<<=>>=

izquierdaaderecha

Page 81: Titivillus 07.07

==!=

izquierdaaderecha

&

izquierdaaderecha

^

izquierdaaderecha

|

izquierdaaderecha

&&

izquierdaaderecha

||

izquierdaaderecha

?:

derechaaizquierda

=+=-=*=/=%=&=^=|=<<=>>=

derechaaizquierda

,

izquierdaaderecha

Los+,-,y*unarios,tienenmayorprecedenciaquelasformasbinarias.

Comomuchoslenguajes,Cnoespecificaelordenenelcuallosoperandosdeunoperadorseránevaluados.(Lasexcepcionesson&&,||,?:y‘,’)Porejemplo,enproposicionescomo

x=f()+g();

fpuedeserevaluadaantesdegoviceversa;deestemodosifogalteranunavariabledelaquelaotradepende,xpuededependerdelordendeevaluación.Sepuedenalmacenarresultadosintermediosenvariablestemporalesparaasegurarunasecuenciaparticular.

Demanerasemejante,elordenenelqueseevalúanlosargumentosdeunafunciónnoestáespecificado,demodoquelaproposición

printf(”%d%d\n",++n,power(2,n));/*EQUIVOCADO*/

puedeproducirresultadosdiferentescondistintoscompiladores,dependiendodesinesincrementadaantesdequesellameapower.Lasolución,porsupuesto,esescribir

Page 82: Titivillus 07.07

++n;

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

Lasllamadasafunciones,proposicionesdeasignaciónanidadas,ylosoperadoresdeincrementoydecrementoprovocan“efectoscolaterales”—algunavariableesmodificadacomoproductodelaevaluacióndeunaexpresión.Encualquierexpresiónqueinvolucraefectoscolaterales,puedenexistirsutilesdependenciasdelordenenquelasvariablesinvolucradasenlaexpresiónseactualizan.Lainfortunadasituaciónestipificadaporlaproposición

a[i]=i++;

Lapreguntaessielsubíndiceeselviejooelnuevovalordei.Loscompiladorespuedeninterpretarestoenformasdiferentes,ygenerardiferentesrespuestasdependiendodesuinterpretación.Elestándardejaintencionalmentesinespecificaciónlamayoríadetalesaspectos.Cuandohayefectoscolaterales(asignaciónavariables)dentrodeunaexpresión,sedejaalaprudenciadelcompilador,puestoqueelmejorordendependegrandementedelaarquitecturadelamáquina.(Elestándarsíespecificaquetodoslosefectoscolateralessobreargumentossucedanantesdequelafunciónseallamada,peroesopodríanoayudarenlallamadaaprintfmostradaanteriormente.)

Lamoralejaesqueescribiruncódigoquedependadelordendeevaluaciónesunamalaprácticadeprogramaciónencualquierlenguaje.Naturalmente,esnecesarioconocerquécosasevitar,perosinosabecómosehacenlascosasenvariasmáquinas,nodebeintentaraprovecharunaimplantaciónenparticular.

Page 83: Titivillus 07.07

CAPÍTULO3:Controldeflujo

Lasproposicionesdecontroldeflujodeunlenguajeespecificanelordenenqueserealizaelprocesamiento.Yahemosvistolamayoríadelasconstruccionesdecontroldeflujoenejemplosanteriores;aquícompletaremoselconjunto,yseremosmásprecisosacercadelasdiscutidasconanterioridad.

Page 84: Titivillus 07.07

3.1.Proposicionesybloques

Unaexpresióncomox=0ói++oprintf(...)seconvierteenunaproposicióncuandovaseguidadeunpuntoycoma,comoen

x=0;

i++;

printf(...);

EnC,elpuntoycomaesunterminadordeproposición,enlugardeunseparador,comoloesenunlenguajetipoPascal.

Lasllaves{y}seempleanparaagrupardeclaracionesyproposicionesdentrodeunaproposicióncompuestaobloque,demodoquesonsintácticamenteequivalentesaunaproposiciónsencilla.Lasllavesqueencierranlasproposicionesdeunafunciónsonunejemploobvio;otrosejemplossonlasllavesalrededordeproposicionesmúltiplesdespuésdeunif,else,whileofor.(Puedendeclararsevariablesdentrodecualquierbloque;estoseexpondráenelcapítulo4.)Nohaypuntoycomadespuésdelallavederechaqueterminaunbloque.

Page 85: Titivillus 07.07

3.2.if-else

Laproposiciónif-elseseutilizaparaexpresardecisiones.Formalmente,lasintaxises

if(expresión)

proposición1

else

proposición2

dondelapartedelelseesoptativa.Laexpresiónseevalúa;siesverdadera(estoes,silaexpresióntieneunvalordiferentedecero),laproposición1,seejecuta.Siesfalsa(expresiónescero)ysiexisteunapartedeelse,laproposición2seejecutaensulugar.

Puestoqueunifsimplementepruebaelvalornuméricodeunaexpresión,sonposiblesciertasabreviacionesdecódigo.Lomásobvioesescribir

if(expresión)

enlugarde

if(expresión!=0)

Algunasvecesestoesclaroynatural;otraspuedesermisterioso.

Debidoaquelaparteelsedeunif-elseesoptativa,existeunaambigüedadcuandounelseseomitedeunasecuenciaifanidada.Estoseresuelvealasociarelelseconelifanteriorsinelsemáscercano.Porejemplo,en

if(n>0)

if(a>b)

z=a;

else

z=b;

elelsevaconelifmásinterno,comosemuestraconelsangrado.Siesonoesloquesedesea,sedebenutilizarllavesparaforzarlaasociacióncorrecta:

if(n>0){

if(a>b)

z=a;

}

Page 86: Titivillus 07.07

else

z=b;

Laambigüedadesespecialmenteperniciosaensituacionescomoesta:

if(n>=0)

for(i=0;i<n;i++)

if(s[i]>0){

printf("...");

returni;

}

else/*MAL*/

printf("error-nesnegativo\n");

Elsangradomuestraenformainequívocaloquesedesea,peroelcompiladornoentiendeelmensajeyasociaelelseconelifmásinterno.Puedeserdifícilencontrarestaclasedeerrores;esunabuenaideautilizarllavescuandohayvariosifanidados.

Apropósito,nótesequehayunpuntoycomadespuésdez=aen

if(a>b)

z=a;

else

z=b;

Estosedebeaquegramaticalmentealiflesigueunaproposición,yunaexpresióncomo"z=a;"siempreseterminaconpuntoycoma.

Page 87: Titivillus 07.07

3.3.else-if

Laconstrucción

if(expresión)

proposición

elseif(expresión)

proposición

elseif(expresión)

proposición

elseif(expresión)

proposición

else

proposición

ocurredemodotanfrecuentequebienvaleunapequeñadiscusiónaparte.Estasecuenciadeproposicionesifeslaformamásgeneraldeescribirunadecisiónmúltiple.Lasexpresionesseevalúanenorden;sicualquierexpresiónesverdadera,laproposiciónasociadaconellaseejecuta,yestoterminatodalacadena.Comosiempre,elcódigoparacadaproposiciónesunaproposiciónsimpleoungrupodentrodellaves.

Lapartedelúltimoelsemanejaelcaso“ningunodelosanteriores”ocasoporomisióncuandoningunadelasotrascondicionessesatisface.Enalgunoscasosnohayunaacciónexplícitaparalaomisión;enesecasoel

else

proposición

delfinalpuedeomitirse,opuedeutilizarseparadeteccióndeerroresalatraparunacondición“imposible”.

Parailustrarunadecisióndetresvías,semuestraunafuncióndebúsquedabinariaquedecidesiunvalorparticulardexseencuentraenelarregloordenadov.Loselementosdevdebenestarenordenascendente.Lafunciónregresalaporción(unnúmeroentre0yn-1)sixestáenv,y-1sinoesasí.

Labúsquedabinariaprimerocomparaelvalordeentradaxconelelementomediodelarreglov.Sixesmenorqueelvalordelmedio,labúsquedaseenfocasobrelamitadinferiordelatabla;deotramaneralohaceenlamitadsuperior.Encualquiercaso,elsiguientepasoescompararaxconelelementomediodelamitadseleccionada.Esteprocesodedividirendoscontinúahastaqueseencuentraelvaloroyanohayelementos.

Page 88: Titivillus 07.07

/*binsearch:encuentraxenv[0]<=v[l]<=...<=v[n-1]*/

intbinsearch(intx,intv[],intn)

{

intlow,high,mid;

low=0;

high=n-1;

while(low<=high){

mid=(low+high)/2;

if(x<v[mid])

high=mid-1;

elseif(x>v[mid])

low=mid+1;

else/*elelementofueencontrado*/

returnmid;

}

return-1;/*noseencontró*/

}

Ladecisiónfundamentalessixesmenorque,mayorqueoigualalelementomediov[mid]encadapaso;estoesunelse-ifnatural.

Ejercicio3-1.Nuestrabúsquedabinariarealizadospruebasdentrodelciclo,cuandounapodríasersuficiente(alpreciodemáspruebasenelexterior).Escribaunaversiónconsólounapruebadentrodelcicloymidaladiferenciaentiempodeejecución.□

Page 89: Titivillus 07.07

3.4.switch

Laproposiciónswitchesunadecisiónmúltiplequepruebasiunaexpresióncoincideconunodeunnúmerodevaloresconstantesenteros,ytrasladaelcontroladecuadamente.

switch(expresión){

caseexp-const:proposiciones

caseexp-const:proposiciones

default:proposiciones

}

Cadacaseseetiquetaconunoomásvaloresconstantesenterosoexpresionesconstantesenteras.Siuncasecoincideconelvalordelaexpresión,laejecucióncomienzaallí.Todaslasexpresionescasedebenserdiferentes.Eletiquetadocomodefaultseejecutasiningunodelosotrossesatisface.Eldefaultesoptativo;sinoestáyningunodeloscasoscoincide,nosetomaacciónalguna.Lascláusulascaseydefaultpuedenocurrirencualquierorden.

Enelcapítulo1seescribióunprogramaparacontarlasocurrenciasdecadadígito,espacioenblancoytodoslosdemáscaracteres,usandounasecuenciadeif...elseif...else.Aquíestáelmismoprogramaconunswitch:

#include<stdio.h>

main()/*cuentadígitos,espaciosblancos,yotros*/

{

intc,i,nwhite,nother,ndigit[10];

nwhite=nother=0;

for(i=0;i<10;i++)

ndigit[i]=0;

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

switch(c){

case'0':case'1':case'2':case'3':case'4':

case'5':case'6':case'7':case'8':case'9':

ndigit[c-'0']++;

break;

case'':

Page 90: Titivillus 07.07

case'\n':

case'\t':

nwhite++;

break;

default:

nother++;

break;

}

}

printf("dígitos=");

for(i=0;i<10;i++)

printf("%d",ndigit[i]);

printf(",espaciosblancos=%d,otros=%d\n",

nwhite,nother);

return0;

}

Laproposiciónbreakprovocaunasalidainmediatadelswitch.Puestoqueloscasesirvensólocomoetiquetas,despuésdequeseejecutaelcódigoparauno,laejecuciónpasaalsiguiente,amenosquesetomeunaacciónespecíficaparaterminarelswitch.Lasformasmáscomunesdedejarunswitchsonbreakyreturn.Unaproposiciónbreaktambiénsepuedeemplearparaforzarunasalidainmediatadeloscicloswhile,forydo,comoseverámásadelanteenestecapítulo.

Pasaratravésdeloscaseesenpartebuenoyenparteno.Porelladopositivo,estopermiteconectarvarioscaseaunaacciónsimple,comoconlosdígitosdeesteejemplo.Peroesotambiénimplicaquecadacasenormalmentedebeterminarconunbreakparaprevenirpasaralsiguiente.Pasardeuncaseaotronoesunaprácticamuysólidayessusceptiblealadesintegracióncuandosemodificaelprograma.Conlaexcepcióndeetiquetasmúltiplesparauncálculosimple,loanteriorsedebeutilizarconcautelayemplearcomentarios.

Comoformalidad,coloqueunbreakdespuésdelúltimocase(enestecasoeldefault)aunsieslógicamenteinnecesario.Algúndía,cuandoseagregueotrocasealfinal,estaprácticadeprogramacióndefensivalosalvará.

Ejercicio3-2.Escribaunafunciónescape(s,t)queconviertecaracterescomonuevalíneaytabulaciónensecuenciasdeescapevisiblescomo\ny\tmientrascopialacadenatas.Utiliceunswitch.Escribatambiénunafunciónparaladireccióninversa,convirtiendosecuenciasdeescapeencaracteresreales.□

Page 91: Titivillus 07.07

3.5.Ciclos—whileyfor

Yahemosencontradoloscicloswhileyfor.En

while(expresión)

proposición

laexpresiónseevalúa.Siesdiferentedecero,seejecutalaproposiciónysereevalúalaexpresión.Esteciclocontinúahastaquelaexpresiónsehacecero,puntoenelcualsesuspendelaejecuciónparacontinuardespuésdelaproposición.

Laproposiciónfor

for(expr1;expr2;expr3)

proposición

esequivalentea

expr1;

while(expr2){

proposición

expr3;

}

exceptoporelcomportamientodecontinuequesedescribeenlasección3.7.

Gramaticalmente,lastrescomponentesdeuncicloforsonexpresiones.Porlocomún,expr1,yexpr3sonasignacionesollamadasafunciónyexpr2esunaexpresiónderelación.Cualquieradelastrespartessepuedeomitir,aunquedebenpermanecerlospuntoycoma.Siexpr1oexpr3seomite,sólosedesechadelaexpansión.Silapruebaexpr2noestápresente,setomacomopermanentementeverdadera,asíque

for(;;){

...

}

esunaiteración“infinita”,quepresumiblementeseráinterrumpidaporotrosmedios,comounbreakounreturn.

Elusarwhileoforesprincipalmentecuestióndepreferenciapersonal.Porejemplo,en

while((c=getchar())==''||c=='\n'||c=='\t')

Page 92: Titivillus 07.07

;/*ignoracaracteresespaciadores*/

nohayinicializaciónoreinicialización,porloqueelwhileesmásnatural.

Elforseprefierecuandoexisteunainicializaciónsimpleeincrementos,puestoquemantienelasproposicionesdecontroldelciclojuntasyvisiblesalprincipiodelmismo.Estoesmásobvioen

for(i=0;i<n;i++)

...

queeslaformacaracterísticadeprocesarlosprimerosnelementosdeunarregloenC,loanálogoalcicloDOdeFortranoalfordePascal.Sinembargo,laanalogíanoesperfectapuestoquetantoelíndicecomoellímitedeuncicloforenCpuedenseralteradosdesdedentrodelciclo,ylavariabledelíndiceiretienesuvalorcuandolasiteracionesterminanporcualquierrazón.Debidoaquelascomponentesdelforsonexpresionesarbitrarias,susciclosnoestánrestringidosaprogresionesaritméticas.Porotraparte,considerequeesunmalestiloincluirenlasseccionesdeinicializacióneincrementooperacionesnorelacionadasconesasactividades,quemásbiensereservanparaaccionesdecontroldelciclo.

Comounejemplomásamplio,aquíestáotraversióndeatoiparaconvertirunacadenaasuequivalentenumérico.Estaesligeramentemásgeneralqueladelcapítulo2;tratatambiénlosespaciosenblancopreviosalnúmero,ylossignos+o-.(Elcapítulo4muestraatof,querealizalamismaconversiónparanúmerosdepuntoflotante.)

Laestructuradelprogramareflejalaformadelaentrada:

ignoraespaciosenblanco,siloshay

tomaelsigno,silohay

tomalaparteenterayconviértela

Cadapasorealizasuparte,ydejalascosasenformaclaraparaelsiguiente.Latotalidaddelprocesoterminaconelprimercarácterquenopuedaserpartedeunnúmero.

#include<ctype.h>

/*atoi:conviertesaentero;versión2*/

intatoi(chars[])

{

inti,n,sign;

for(i=0;isspace(s[i]);i++)/*ignoraespacioenblanco*/

;

sign=(s[i]=='-')?-1:1;

if(s[i]=='+'||s[i]=='-')/*ignoraelsigno*/

Page 93: Titivillus 07.07

i++;

for(n=0;isdigit(s[i]);i++)

n=10*n+(s[i]-'0');

returnsign*n;

}

Labibliotecaestándarproporcionaunafunciónmáselaborada,strtol,paralaconversióndecadenasaenteroslargos;véaselasección5delapéndiceB.

Lasventajasdemantenercentralizadoelcontroldelciclosonaúnmásobviascuandoexistenciclosanidados.LasiguientefunciónesunaclasificaciónShellparaordenarunarreglodeenteros.Laideabásicadeestealgoritmodeordenamiento,quefueinventadoen1959porD.L.Shell,esqueenlasprimerasetapasseancomparadoselementoslejanos,enlugardelosadyacentes,comoenlosordenamientosdeintercambiomássimples.Estotiendeaeliminarrápidamentegrancantidaddedesorden,asíquelosestadosposteriorestienenmenostrabajoporhacer.Elintervaloentreloselementoscomparadosdisminuyeenformagradualhastauno,puntoenelqueelordenamientovieneaserefectivamenteunmétodoadyacentedeintercambio.

/*shellsort:ordenav[0]...v[n-1]enordenascendente*/

voidshellsort(intv[],intn)

{

intgap,i,j,temp;

for(gap=n/2;gap>0;gap/=2)

for(i=gap;i<n;i++)

for(j=i-gap;j>=0&&v[j]>v[j+gap];j-=gap){

temp=v[j];

v[j]=v[j+gap];

v[j+gap]=temp;

}

}

Existentresciclosanidados.Elmásexternocontrolaelespacioentreloselementoscomparados,reduciéndolodesden/2porunfactordedosencadapasohastaquellegaacero.Elciclointermediorecorreloselementos.Elciclomásinternocomparacadaparejadeelementosqueestáseparadaporelespaciogapeinviertealasqueesténdesordenadas.Puestoquegapfinalmentesereduceauno,todosloselementosseordenancorrectamente.Nótesecómolageneralidaddelforhacequeelciclomásexternocoincidaconlaformadelosotros,auncuandonoesunaprogresiónaritmética.

UnúltimooperadordeCeslacoma“,”,quefrecuentementeencuentrausoenlaproposiciónfor.Unaparejadeexpresionesseparadasporunacomaseevalúade

Page 94: Titivillus 07.07

izquierdaaderecha,yeltipoyvalordelresultadosoneltipoyvalordeloperandoderecho.Así,enunaproposiciónforesposiblecolocarexpresionesmúltiplesenlasdiferentespartes,porejemplo,paraprocesardosíndicesenparalelo.Estoseilustraenlafunciónreverse(s),queinviertealacadenasenelmismolugar.

#include<string.h>

/*reverse:inviertelacadenasenelmismolugar*/

voidreverse(chars[])

{

intc,i,j;

for(i=0,j=strlen(s)-l;i<j;i++,j--){

c=s[i];

s[i]=s[j];

s[j]=c;

}

}

Lascomasqueseparanalosargumentosdeunafunción,lasvariablesendeclaraciones,etc.,nosonoperadorescoma,ynogarantizanevaluacióndeizquierdaaderecha.

Losoperadorescomadeberánutilizarsepoco.Losusosmásadecuadossonenconstruccionesfuertementerelacionadasunaconlaotra,comoenelciclofordereverse,yenmacrosendondeuncálculodepasomúltipledebeserunaexpresiónsimple.Unaexpresióncomapodríatambiénserapropiadaparaelintercambiodeelementosenreverse,dondeelintercambiopuedeseratravésdeunaoperaciónsimple:

for(i=0,j=strlen(s)-1;i<j;i++,j--)

c=s[i],s[i]=s[j],s[j]=c;

Ejercicio3-3.Escribalafunciónexpand(s1,s2)queexpandenotaciónabreviadacomoa-z,quevieneenlacadenas1,enlalistaequivalentecompletaabc...xyz,ens2.Permitaletrasmayúsculasyminúsculas,asícomodígitos,yestépreparadoparamanejarcasoscomoa-b-cya-z0-9y-a-z.Hagaquelosguionesaliniciooalfinalsetomenliteralmente.□

Page 95: Titivillus 07.07

3.6.Ciclos—do-while

Comoyaseexpusoenelcapítulo1,loscicloswhileyforverificanalprincipiolacondicióndetérmino.Encontraste,eltercercicloenC,eldo-while,pruebaalfinaldespuésderealizarcadapasoatravésdelcuerpodelciclo,elcualseejecutasiempreporlomenosunavez.

Lasintaxisdeldoes

do

proposición

while(expresión);

Laproposiciónseejecutaydespuésseevalúalaexpresión.Siesverdadera,laproposiciónseevalúadenuevo,yasísucesivamente.Cuandolaexpresiónsehacefalsa,elciclotermina.Exceptoporelsentidodelaprueba,eldo-whileesequivalentealaproposiciónrepeat-untildePascal.

Laexperienciademuestraqueeldo-whileesmuchomenosutilizadoqueelwhileyelfor.Aunquedecuandoencuandoesvalioso,comoenlasiguientefunciónitoa,queconvierteunnúmeroaunacadenadecaracteres(loinversodeatoi).Eltrabajoesligeramentemáscomplicadodeloquepodríapensarseenunprincipio,debidoaquelosmétodosfácilesparagenerardígitoslosgeneranenelordenincorrecto.Hemoselegidogenerarlacadenaalrevésydespuésinvertirla.

/*itoa:conviertenacaracteresens*/

voiditoa(intn,chars[])

{

int,i,sign;

if((sign=n)<0)/*registraelsigno*/

n=-n;/*vuelveanpositivo*/

i=0;

do{/*generadígitosenordeninverso*/

s[i++]=n%10+'0';/*tomaelsiguientedígito*/

}while((n/=10)>0);/*bórralo*/

if(sign<0)

s[i++]='-';

s[i]='\0';

Page 96: Titivillus 07.07

reverse(s);

}

Eldo-whileesnecesario,oalmenosconveniente,puestoqueporlomenossedebeinstalaruncarácterenelarreglos,aunsinescero.Tambiénempleamosllavesalrededordelaproposiciónsimplequehaceelcuerpodeldo-while,aunquesoninnecesarias,yasíellectorapresuradonoconfundirálaseccióndelwhileconelprincipiodeunciclowhile.

Ejercicio3-4.Enunarepresentacióndenúmerosencomplementoados,nuestraversióndeitoanomanejaelnúmeronegativomásgrande,estoes,elvalordeniguala-(2tamañopalabra-1).Expliqueporqué.Modifíqueloparaimprimirelvalorcorrectamente,sinimportarlamáquinaenqueejecute.□

Ejercicio3-5.Escribalafunciónitob(n,s,b)queconviertealenteronenunarepresentacióndecaracteresconbasebdentrodelacadenas.Enparticular,itob(n,s,16)daformatoancomounenterohexadecimalens.□

Ejercicio3-6.Escribaunaversióndeitoaqueaceptetresargumentosenlugardedos.Eltercerargumentoesunanchomínimodecampo;alnúmeroconvertidosedebenagregarblancosalaizquierdasiesnecesarioparahacerlosuficientementeancho.□

Page 97: Titivillus 07.07

3.7.breakycontinue

Algunasvecesesconvenientetenerlaposibilidaddeabandonarunciclodeotramaneraquenoseaprobandoaliniciooalfinal.Laproposiciónbreakproporcionaunasalidaanticipadadeunfor,whileydo,talcomolohaceelswitch.Unbreakprovocaqueelciclooswitchmásinternoqueloencierratermineinmediatamente.

Lasiguientefunción,trim,eliminaespaciosblancos,tabuladoresynuevaslíneasalfinaldeunacadena,utilizandounbreakparasalirdeunciclocuandoseencuentraelno-blanco,no-tabuladorono-nuevalíneademásaladerecha.

/*trim:eliminablancos,tabuladoresynuevalíneaalfinal*/

inttrim(chars[])

{

intn;

for(n=strlen(s)-1;n>=0;n--)

if(s[n]!=''&&s[n]!='\t'&&s[n]!='\n')

break;

s[n+l]='\0';

returnn;

}

strlenregresalalongituddelacadena.Elcicloforiniciaalfinalyrastreahaciaatrás,buscandoelprimercarácterquenoseablancootabuladoronuevalínea.Elcicloseinterrumpecuandoseencuentraalgunoocuandonsehacenegativa(estoes,cuandoseharastreadotodalacadena.Sedeberáverificarqueestecomportamientoescorrecto,auncuandolacadenaestévacíaosólocontieneespaciosenblanco.

Laproposicióncontinueestárelacionadaconelbreak,peroseutilizamenos;provocaqueinicielasiguienteiteracióndelciclofor,whileodoquelacontiene.Dentrodewhileydo,estosignificaquelapartedelapruebaseejecutainmediatamente;enelfor,elcontrolsetrasladaalpasodeincremento.Laproposicióncontinueseaplicasolamenteaciclos,noaswitch.Uncontinuedentrodeunswitchqueestáasuvezenunciclo,provocalasiguienteiteracióndelciclo.

Comounejemplo,elsiguientefragmentoprocesasóloloselementosnonegativosqueestánenelarregloa;losvaloresnegativossonignorados.

for(i=0;i<n;i++){

if(a[i]<0)/*ignoraelementosnegativos*/

continue;

Page 98: Titivillus 07.07

.../*trabajaconelementospositivos*/

}

Laproposicióncontinueseempleaamenudocuandolapartedelcicloquesigueescomplicada,demodoqueinvertirlapruebaysangrarotronivelpodríaanidarprofundamenteelprograma.

Page 99: Titivillus 07.07

3.8.gotoyetiquetas

Cproporcionalainfinitamenteabusableproposicióngoto,yetiquetasparasaltarhaciaellas.Formalmente,elgotonuncaesnecesario,yenlaprácticaescasisiempremásfácilescribircódigosinél.Enestelibronosehausadogotoalguno.

Sinembargo,hayalgunassituacionesdondelosgotopuedenencontrarunlugar.Lamáscomúnesabandonarelprocesamientoenalgunaestructuraprofundamenteanidada,talcomosalirdedosomásciclosalavez.Laproposiciónbreaknosepuedeutilizardirectamente,puestoquesólosaledelciclomásinterno.Así:

for(...)

for(...){

...

if(desastre)

gotoerror;

}

...

error:

arreglaeldesorden

Estaorganizaciónesútilsielcódigodemanejodeerrornoestrivialysiloserrorespuedenocurrirenvarioslugares.

Unaetiquetatienelamismaformaqueunnombredevariableyesseguidapordospuntos.Puedeseradheridaacualquierproposicióndelamismafunciónenlaqueestáelgoto.Elalcancedeunaetiquetaestodalafunción.

Comootroejemplo,considéreseelproblemadedeterminarsidosarreglos,ayb,tienenunelementoencomún.Unaposibilidades

for(i=0;i<n;i++)

for(j=0;j<m;j++)

if(a[i]==b[j]

gotoencontrado;

/*noseencontróningúnelementoencomún*/

encontrado:

/*setieneuno:a[i]==b[j]*/

Page 100: Titivillus 07.07

Elcódigoqueinvolucraungotosiemprepuedeescribirsesinél,aunquetalvezalpreciodealgunaspruebasrepetidasovariablesextra.Porejemplo,labúsquedaenlosarreglosquedará

encontrado=0;

for(i=0;i<n&&!encontrado;i++)

for(j=0;j<m&&!encontrado;j++)

if(a[i]==b[j])

encontrado=1;

if(encontrado)

/*setieneuno:a[i-1]==b[j-1]*/

...

else

/*noseencontróalgúnelementoencomún*/

...

Conpocasexcepciones,comolascitadasaquí,elcódigoquesebasaenproposicionesgotoesgeneralmentemásdifícildeentenderydemantenerqueelcódigosinellas.Aunquenosomosdogmáticosacercadelasunto,sevequelasproposicionesgotodebenserutilizadasraramente,siacaso.

Page 101: Titivillus 07.07

CAPÍTULO4:Funcionesylaestructuradelprograma

Lasfuncionesdividentareasgrandesdecomputaciónenvariasmáspequeñas,ypermitenlaposibilidaddeconstruirsobreloqueotrosyahanhecho,enlugardecomenzardesdecero.Lasfuncionesapropiadasocultanlosdetallesdeoperacióndelaspartesdelprogramaquenonecesitansaberacercadeellos,asíquedanclaridadalatotalidadyfacilitanlapenosatareadehacercambios.

EllenguajeCsediseñóparahacerquelasfuncionesfueraneficientesyfácilesdeusar;losprogramasescritosenCsecomponendemuchasfuncionespequeñasenlugardesóloalgunasgrandes.Unprogramapuederesidirenunoomásarchivosfuente,loscualespuedencompilarseporseparadoycargarsejuntoconfuncionesdebibliotecapreviamentecompiladas.Notrataremosaquítalesprocesos,puestoquelosdetallesvaríandeunsistemaaotro.

LadeclaraciónydefinicióndefuncioneseseláreadondeelestándarANSIhahecholoscambiosmásvisiblesaC.Talcomomencionamosenelcapítulo1,ahoraesposibledeclararlostiposdelosargumentoscuandosedeclaraunafunción.Lasintaxisdeladefinicióndefuncionestambiéncambia,demodoquelasdeclaracionesylasdefinicionescoincidan.Estohaceposiblequeelcompiladorpuedadetectarmuchosmáserroresdeloquepodíaanteriormente.Además,cuandolosargumentossedeclaranconpropiedad,serealizanautomáticamentelasconversionesconvenientes.

Elestándarclarificalasreglassobreelalcancedelosnombres;enparticular,requierequesólohayaunadefinicióndecadaobjetoexterno.Lainicializaciónesmásgeneral:losarreglosylasestructurasautomáticasahorasepuedeninicializar.

ElpreprocesadordeCtambiénsehamejorado.Lasnuevasfacilidadesdelprocesadorincluyenunconjuntomáscompletodedirectivasparalacompilacióncondicional,unaformadecrearcadenasentrecomilladasapartirdeargumentosdemacrosyunmejorcontrolsobreelprocesodeexpansióndemacros.

Page 102: Titivillus 07.07

4.1.Conceptosbásicosdefunciones

Paracomenzar,diseñemosyescribamosunprogramaqueimprimacadalíneasuentradaquecontengaun“patrón”ocadenadecaracteresenparticular.(EsteesuncasoespecialdelprogramagrepdeUNIX.)Porejemplo,albuscarelpatróndeletras“ould”enelconjuntodelíneas

AhLove!couldyouandIwithFateconspire

TograspthissorrySchemeofThingsentire,

Wouldnotweshatterittobits--andthen

Re-moulditnearertotheHeart'sDesire!

producirálasalida

AhLove!couldyouandIwithFateconspire

Wouldnotweshatterittobits--andthen

Re-moulditnearertotheHeart'sDesire!

Eltrabajoseajustaordenadamenteentrespartes:

while(hayotralínea)

if(lalíneacontieneelpatrón)

imprímela

Aunqueciertamenteesposibleponerelcódigodetodoestoenmain,unamejorformaesaprovecharlaestructurahaciendodecadaparteunafunciónseparada.Esmásfáciltrabajarcontrespiezaspequeñasqueconunagrande,debidoaquelosdetallesirrelevantessepuedenocultardentrodelasfunciones,yminimizarasíelriesgodeinteraccionesnodeseadas.Losfragmentosinclusosepuedenemplearenotrosprogramas.

“Mientrashayotralínea”esgetline,funciónqueyaescribimosenelcapítulo1,e“imprímela”esprintf,quealguienyanosproporcionó.Estosignificaquesólonecesitamosescribirunarutinaparadecidirsilalíneacontieneunaocurrenciadelpatrón.

Podemosresolvereseproblemaescribiendounafunciónstrindex(s,t),queregresalaposiciónoíndiceenlacadenasendondecomienzalacadenat,o-1sisnocontienet.DebidoaquelosarreglosenCprincipianenlaposicióncero,losíndicesseránceroopositivos,yasíunvalornegativocomo-1esconvenienteparaseñalarunafalla.Cuandoposteriormentesenecesiteunacoincidenciadepatronesmáselaborada,sólosedebereemplazarstrindex;elrestodelcódigopuedepermanecerigual.(Labibliotecaestándarproveeunafunciónstrstrqueessemejanteastrindex,exceptoenqueregresaunapuntadorenlugardeuníndice.)

Unavezdefinidotodoestediseño,llenarlosdetallesdelprogramaessimple.Aquíestá

Page 103: Titivillus 07.07

ensutotalidad,demodoquesepuedevercómolaspiezasquedanjuntas.Porahora,elpatrónquesebuscaráesunacadenaliteral,locualnoeselmecanismomásgeneral.Regresaremosenbreveaunadiscusiónsobrecómoinicializararreglosdecaracteres,yenelcapítulo5mostraremoscómohacerqueelpatróndecaracteresseaunparámetrofijadocuandoseejecutaelprograma.Tambiénhayunaversiónligeramentediferentedegetline,quesepodrácompararconladelcapítulo1.

#include<stdio.h>

#defineMAXLINE1000/*longitudmáximaporlíneadeentrada*/

intgetline(charline[],intmax);

intstrindex(charsource[],charsearchfor[]);

charpattern[]="ould";/*patrónporbuscar*/

/•encuentratodaslaslíneasquecoincidanconelpatrón*/

main()

{

charline[MAXLINE];

intfound=0;

while(getline(line,MAXLINE)>0)

if(strindex(line,pattern)>=0){

printf("%s",line);

found++;

}

returnfound;

}

/*getline:traelíneaylaponeens,regresasulongitud*/

intgetline(chars[],intlim)

{

intc,i;

i=0;

while(--lim>0&&(c=getchar())!=EOF&&c!='\n')

s[i++]=c;

if(c=='\n')

Page 104: Titivillus 07.07

s[i++]=c;

s[i]='\0';

returni;

}

/*strindex:regresaelíndicedetens,-1sinoexiste*/

intstrindex(chars[],chart[])

{

inti,j,k;

for(i=0;s[i]!='\0';i++){

for(j=i,k=0;t[k]!='\0'&&s[j]==t[k];j++,k++)

;

if(k>O&&t[k]=='0')

returni;

}

return-1;

}

Cadadefinicióndefuncióntienelaforma

tipo-regresadonombre-de-función(declaracionesdeargumentos)

{

declaracionesyproposiciones

}

Variaspartespuedenomitirse;unafunciónmínimaes

nada(){}

quenohaceniregresanada.Unafunciónhacer-nada,comoésta,esalgunasvecesútilparareservarlugaraldesarrollarunprograma.Sieltipoqueregresaseomite,sesuponeint.

Unprogramaessólounconjuntodedefinicionesdevariablesyfunciones.Lacomunicaciónentrefuncionesesporargumentosyvaloresregresadosporlasfunciones,yatravésdevariablesexternas.Lasfuncionespuedenpresentarseencualquierordendentrodelarchivofuente,yelprogramafuentesepuededividirenvariosarchivos,mientraslasfuncionesnosedividan.

Page 105: Titivillus 07.07

Laproposiciónreturneselmecanismoparaquelafunciónquesellamaregreseunvalorasuinvocador.Alreturnlepuedeseguircualquierexpresión:

returnexpresión

Laexpresiónseconvertiráaltipoderetornodelafunciónsiesnecesario.Confrecuenciaseutilizanparéntesisparaencerrarlaexpresión,perosonoptativos.

Lafunciónquellamatienelalibertaddeignorarelvalorregresado.Incluso,nohaynecesidaddeunaexpresióndespuésdereturn;entalcaso,ningúnvalorregresaalinvocador.Tambiénelcontrolregresa,sinvalor,cuandolaejecución“caealfinal”delafunciónalalcanzarlallavederechaquecierra.Noesilegal,aunqueprobablementeunsignodeproblemas,elqueunafunciónregreseunvalordesdeunlugaryningunodesdeotro.Encualquiercaso,siunafunciónnoregresaexplícitamenteunvalor,su“valor”esciertamentebasura.

Elprogramadebúsquedadelpatrónregresaunestadodesdemain,elnúmerodecoincidenciasencontradas.Estevalorestádisponibleparaserempleadoporelmedioambientequellamóalprograma.

ElmecanismodecómocompilarycargarunprogramaenCqueresideenvariosarchivosfuentevaríadeunsistemaaotro.EnelsistemaUNIX,porejemplo,laordenccmencionadaenelcapítulo1haceeltrabajo.Supóngasequelastresfuncionessealmacenanentresarchivosllamadosmain.c,getline.c,ystrindex.c.Entonceslaorden

ccmain.cgetline.cstrindex.c

compilalostresarchivos,sitúaelcódigoobjetoresultanteenlosarchivosmain.o,getline.o,ystrindex.o,ydespuésloscargatodosdentrodeunarchivoejecutablellamadoa.out.Siexisteunerror,digamosenmain.c,esearchivopuedevolverseacompilarporsímismoyelresultadocargadoconlosarchivosobjetoprevios,conlaorden.

ccmain.cgetline.ostrindex.o

ccemplealaconvención“.c”contra“.o”paradistinguirlosarchivosfuentedelosarchivosobjeto.

Ejercicio4-1.Escribalafunciónstrrindex(s,t),queregresalaposicióndelaocurrenciademásaladerechadetens,ó-1sinohayalguna.□

Page 106: Titivillus 07.07

4.2.Funcionesqueregresanvaloresnoenteros

Hastaahoralosejemplosdefuncioneshanregresadooningúnvalor(void)ounint.¿Quépasasiunafuncióndeberegresaralgodeotrotipo?Muchasfuncionesnuméricascomosqrt,sinycosregresandouble;otrasfuncionesespecializadasregresantiposdiferentes.Parailustrarcómotratarconesto,escribamosyusemoslafunciónatof(s),queconviertelacadenasasuvalorequivalentedepuntoflotantededobleprecisión.Lafunciónatofesunaextensióndeatoi,delaquemostramosversionesenloscapítulos2y3.Manejasignoypuntodecimaloptativos,ypresenciaoausenciadeparteenteraofraccionaria.Nuestraversiónnoesunarutinadeconversióndealtacalidad;tomaríamásespaciodelquepodemosdedicarle.Labibliotecaestándarincluyeunatof;elheader<stdlib.h>ladeclara.

Primero,atofporsímismadebedeclarareltipodelvalorqueregresa,puestoquenoesint.Elnombredeltipoprecedealnombredelafunción:

#include<ctype.h>

/*atof:conviertelacadenasadouble*/

doubleatof(chars[])

{

doubleval,power;

inti,sign;

for(i=0;isspace(s[i]);i++)/*ignoraespaciosblancos*/

;

sign=(s[i]=='-')?-1:1;

if(s[i]=='+'||s[i]=='-')

i++;

for(val=0.0;isdigit(s[i]);i++)

val=10.0*val+(s[i]-'0');

if(s[i]=='.')

i++;

for(power=1.0;isdigit(s[i]);i++){

val=10.0*val+(s[i]-'0');

power*=10.0;

}

Page 107: Titivillus 07.07

returnsign*val/power;

}

Segundo,eigualmenteimportante,larutinaquellamadebeindicarqueatofregresaunvalorquenoesint.Unaformadeasegurarestoesdeclararatofexplícitamenteenlarutinaquelallama.Ladeclaraciónsemuestraenestaprimitivacalculadora(apenasadecuadaparaunbalancedechequera),queleeunnúmeroporlínea,precedidoenformaoptativaporunsigno,yloacumula,imprimiendolasumaactualdespuésdecadaentrada:

#include<stdio.h>

#defineMAXLINE100

/*calculadorarudimentaria*/

main()

{

doublesum,atof(char[]);

charline[MAXLINE];

intgetline(charline[],intmax);

sum=0;

while(getline(line,MAXLINE)>0)

printf("\t%g\n",sum+=atof(line));

return0;

}

Ladeclaración

doublesum,atof(char[]);

señalaquesumesunavariabledouble,yqueatofesunafunciónquetomaunargumentochar[]yregresaundouble.

Lafunciónatofsedebedeclararydefinirconsistentemente.Siatofensímismaylallamadaaellaenmaintienentiposinconsistentesdentrodelmismoarchivofuente,elerrorserádetectadoporelcompilador.Perosi(comoesprobable)atoffueracompiladaseparadamente,lafaltadeconsistencianosedetectaría,atofregresaríaunvalordoublequemaintrataríacomoint,yseproduciríanresultadosincongruentes.

Alaluzdeloquehemosmencionadoacercadecómodebencoincidirlasdeclaracionesconlasdefiniciones,estopodríasersorprendente.Larazóndequeocurraunafaltadecoincidenciaesque,sinoexisteelprototipodeunafunción,éstaesdeclaradaimplícitamentelaprimeravezqueapareceenunaexpresión,como

sum+=atof(line)

Page 108: Titivillus 07.07

Sienunaexpresiónseencuentraunnombrequenohasidodeclaradopreviamenteyestáseguidoporparéntesisizquierdo,sedeclaraporcontexto,demodoquesesuponequeeselnombredeunafunciónqueregresaunint,ynadasesuponeacercadesusargumentos.Aúnmás,siladeclaracióndeunafunciónnoincluyeargumentoscomoen

doubleatof();

tambiénestomadademodoquenosesuponenadaacercadelosargumentosdeatof;sedesactivatodarevisióndeparámetros.EstesignificadoespecialdelalistadeargumentosvacíasehaceparapermitirquelosprogramasenCviejossecompilenconlosnuevoscompiladores.Peroesunamalatácticausarestoconprogramasnuevos.Silafuncióntomaargumentos,declárelos;sinolostoma,usevoid.

Dadoatof,propiamentedeclarado,podemosescribiratoi(convierteunacadenaaint)entérminosdeél:

/*atoi:conviertelacadenasaenterousandoatof*/

intatoi(chars[])

{

doubleatof(chars[]);

return(int)atof(s);

}

Nóteselaestructuradelasdeclaracionesylaproposiciónreturn.Elvalordelaexpresiónen

returnexpresión;

seconviertealtipodelafunciónantesdequesetomeelreturn.Porlotanto,elvalordeatof,undouble,seconvierteautomáticamenteaintcuandoapareceenestereturn,puestoquelafunciónatoiregresaunint.Sinembargo,estaoperaciónpotencialmentedescartainformación,asíquealgunoscompiladoresloprevienen.Elcastestableceexplícitamenteloquelaoperaciónintentaysuprimelasadvertencias.

Ejercicio4-2.Extiendaatofparaquemanejenotacióncientíficadelaforma

123.45e-6

dondeunnúmerodepuntoflotantepuedeirseguidoporeoEyopcionalmenteunexponenteconsigno.□

Page 109: Titivillus 07.07

4.3.Variablesexternas

UnprogramaenCconstadeunconjuntodeobjetosexternos,quesonvariablesofunciones.Eladjetivo“externo”seempleaencontrastecon“interno”,quedescribelosargumentosylasvariablesdefinidasdentrodelasfunciones.Lasvariablesexternassedefinenfueradecualquierfunción,yporlotanto,estánpotencialmentedisponiblesparamuchasfunciones.Lasfuncionesensímismassonsiempreexternas,puestoqueCnopermitedefinirfuncionesdentrodeotrasfunciones.Poromisión,lasvariablesyfuncionesexternastienenlapropiedaddequetodaslasreferenciasaellasporelmismonombre,inclusodesdefuncionescompiladasseparadamente,sonreferenciasalamismacosa.(Elestándarllamaaestapropiedadligadoexterno.)Enestesentido,lasvariablesexternassonanálogasalosbloquesCOMMONdeFortranoalasvariablesdelbloquemásexternodePascal.Másadelanteveremoscómodefinirvariablesyfuncionesexternasqueseanvisiblessólodentrodeunarchivofuente.

Debidoaquelasvariablesexternassonaccesiblesglobalmente,proporcionanunaalternativaalosargumentosenfuncionesyalosvaloresderetornoparacomunicardatosentrefunciones.Cualquierfunciónpuedeteneraccesoavariablesexternashaciendoreferenciaaellassolamenteporsunombre,siéstehasidodeclaradodealgunamanera.

Siungrannúmerodevariablessedebecompartirentrefunciones,lasvariablesexternassonmáscovenientesyeficientesquelaslargaslistasdeargumentos.Sinembargo,comoseseñalóenelcapítulo1,esterazonamientosedeberáaplicarconprecaución,puespuedetenerunefectonegativosobrelaestructuradelprogramaydarlugaraprogramascondemasiadasconexionesdedatosentrefunciones.

Lasvariablesexternassontambiénútilesdebidoasumayoralcanceytiempodevida.Lasvariablesautomáticassoninternasaunafunciónysuexistenciaseiniciacuandoseentraalafunciónydesaparecencuandoéstaseabandona.Porotrolado,lasvariablesexternassonpermanentes,demodoqueretienensusvaloresdelainvocacióndeunafunciónalasiguiente.Así,sidosfuncionesdebencompartiralgunosdatos,aunsiningunallamaalaotra,confrecuenciaesmásconvenientequelosdatoscompartidossemantenganenvariablesexternas,enlugardequeseanpasadoscomoargumentosdeentradaysalida.

Examinemosmásafondoestetemaconunejemplomásamplio.Elproblemaesescribirelprogramadeunacalculadoraqueprovealosoperadores+,-,*y/.Porsermásfácilsuimplantación,lacalculadorautilizaránotaciónpolacainversaenlugardeinfija.(Lapolacainversaesutilizadaporalgunascalculadorasdebolsillo,yenlenguajescomoForthyPostScript.)

Ennotaciónpolacainversa,cadaoperadorsigueasusoperandos;unaexpresióninfijacomo

(1-2)*(4+5)

seintroducecomo

12-45+*

Losparéntesisnosonnecesarios;lanotaciónnoesambiguamientrassepamoscuántosoperandosesperacadaoperador.

Page 110: Titivillus 07.07

Laimplantaciónessimple.Cadaoperandoseintroduceenunapilaostack;cuandounoperadorllega,elnúmerocorrectodeoperandos(dosparaoperadoresbinarios)sonextraídos,seaplicaeloperadoryelresultadoseregresaalapila.Enelejemploanterior,seintroducen1y2,despuéssereemplazanporsudiferencia,-1.Enseguidaseintroducen4y5yluegosereemplazanporsusuma,9.Elproductode-1y9,quees-9,losreemplazaenlapila.Elvalorqueseencuentraeneltopedelapilaseextraeeimprimecuandoseencuentraelfindelalíneadeentrada.

Laestructuradelprogramaesasíuncicloquerealizalasoperacionesadecuadassobrecadaoperadoryoperandoqueaparece:

while(siguienteoperadoruoperandonoesfindearchivo)

if(número)

introducirlo

elseif(operador)

extraeroperandos

haceroperaciones

introducirelresultado

elseif(nuevalínea)

extraeeimprimeeltopedelapila

else

error

Lasoperacionesdeintroducir(push)yextraerdeunapila(pop)sonsencillas,perocuandoselesagregadetecciónyrecuperacióndeerrores,sonsuficientementelargascomoparaqueseamejorponerlasenfuncionesseparadasenlugardelcódigoalolargodetodoelprograma.Además,debeexistirunafunciónseparadaparabuscarelsiguienteoperadoruoperando.

Laprincipaldecisióndediseñoqueaúnnosehaexplicadoesdóndeestálapila,estoes,cuálesrutinastienenaccesoaelladirectamente.Unaposibilidadesmantenerlaenmain,ypasarlapilaylaposiciónactualalasrutinasqueintroducenyextraenelementos.Peromainnonecesitasaberacercadelasvariablesquecontrolanalapila;sóloefectúaoperacionesdeintroduciryextraer.Así,hemosdecididoalmacenarlapilaysuinformaciónasociadaenvariablesexternasaccesiblesalasfuncionespushypop,peronoamain.

Traducirestebosquejoacódigoessuficientementefácil.Siporahorapensamosqueelprogramaexisteenunarchivofuente,severáasí:

#includes

#defines

declaracióndefuncionesparamain

main(){...}

Page 111: Titivillus 07.07

variablesexternasparapushypop

voidpush(doublef){...}

doublepop(void){...}

intgetop(chars[]){...}

rutinasllamadasporgetop

Másadelanteseverácómoestosepuededividirentredosomásarchivosfuente.

Lafunciónmainesuncicloquecontieneungranswitchsobreeltipodeoperadoryoperando;ésteesunusodelswitchmástípicoqueelmostradoenlasección3.4.

#include<stdio.h>

#include<stdlib.h>/*paraatof()*/

#defineMAXOP100/*máxtamañodeoperandouoperador*/

#defineNUMBER'0'/*señaldequeunnúmeroseencontró*/

intgetop(char[]);

voidpush(double);

doublepop(void);

/*calculadorapolacainversa*/

main()

{

inttype;

doubleop2;

chars[MAXOP];

while((type=getop(s))!=EOF){

switch(type){

caseNUMBER:

push(atof(s));

break;

case'+':

push(pop()+pop());

break;

Page 112: Titivillus 07.07

case'*':

push(pop()*pop());

break;

case'-':

op2=pop();

push(pop()-op2);

break;

case'/':

op2=pop();

if(op2!=0.0)

push(pop()/op2);

else

printf("error:divisorcero\n");

break;

case'\n':

printf("\t%.8g\n",pop());

break;

default:

printf("error:comandodesconocido%s\n",s);

break;

}

}

return0;

}

Puestoque+y*sonoperadoresconmutativos,elordenenelquesecombinanlosoperandosextraídosesirrelevante,peropara-y/debendistinguirselosoperandosizquierdoyderecho.En

push(pop()-pop());/*INCORRECTO*/

nosedefineelordenenelqueseevalúanlasdosllamadasdepop.Paragarantizarelordencorrecto,esnecesarioextraerelprimervalorenunavariabletemporal,comosehizoenmain.

Page 113: Titivillus 07.07

#defineMAXVAL100/*máximaprofundidaddelapilaval*/

intsp=0;/*siguienteposiciónlibreenlapila*/

doubleval[MAXVAL];/*valoresdelapila*/

/*push:introducefalapila*/

voidpush(doublef)

{

if(sp<MAXVAL)

val[sp++]=f;

else

printf("error:pilallena,nopuedeefectuarpush%g\n",f);

}

/*pop:extraeyregresaelvalorsuperiordelapila*/

doublepop(void)

{

if(sp>0)

returnval[--sp];

else{

printf("error:pilavacía\n");

return0.0;

}

}

Unavariableesexternasiseencuentradefinidafueradecualquierfunción.Así,lapilayelíndicedelapilaquedebensercompartidosporpushyporpopsedefinenfueradeestasfunciones.Peromainensímismanohacereferenciaalapilaoalaposicióndelapila—larepresentaciónpuedeestaroculta.

Pasemosahoraalaimplantacióndegetop,lafunciónquetomaelsiguienteoperadoruoperando.Latareaesfácil.Ignorarblancosytabuladores.Sielsiguientecarácternoesundígitoopuntodecimal,regresarlo.Deotramanera,reunirunacadenadedígitos(quepuedaincluirunpuntodecimal),yregresarNUMBER,laseñaldequehasidoreunidounnúmero.

#include<ctype.h>

intgetch(void);

Page 114: Titivillus 07.07

voidungetch(int);

/*getop:obtieneelsiguienteoperadoruoperandonumérico*/

intgetop(chars[])

{

inti,c;

while((s[0]=c=getch())==''||c=='\t')

;

s[l]='\0';

if(!isdigit(c)&&c!='.')

returnc;/*noesunnúmero*/

i=0;

if(isdigit(c))/*reúnelaparteentera*/

while(isdigit(s[++i]=c=getch()))

;

if(c=='.')/*reúnelapartefraccionaria*/

while(isdigit(s[++i]=c=getch()))

;

s[i]='\0';

if(c!=EOF)

ungetch(c);

returnNUMBER;

}

¿Quésongetchyungetch?Porlocomúnsedaelcasodequeunprogramanopuededeterminarsihaleídosuficientedelaentradahastaquehaleídodemasiado.Unejemploesreunirloscaracteresqueformanunnúmero:hastaqueseveaelprimerno-dígito,elnúmeronoestácompleto.Peroentonceselprogramahaleídouncarácterdemás,paraelcualnoestápreparado.

Elproblemapodríaserresueltosifueraposible“desleer”elcarácternodeseado.Entonces,cadavezqueelprogramaleauncarácterdemás,podríaregresarloalaentrada,asíqueelrestodelcódigosepodrácomportarcomosinuncasehubieseleído.Afortunadamente,esfácilsimularelregresodeuncarácter,escribiendounpardefuncionescooperativas,getchentregaelsiguientecarácterdelaentradaquevaaserconsiderado;ungetchreintegraelcarácterdevueltoalaentrada,demodoquellamadas

Page 115: Titivillus 07.07

posterioresagetchloregresaránantesdeleeralgonuevodelaentrada.

Cómotrabajanjuntasessencillo,ungetchcolocaelcarácterregresadoenunbuffercompartido—unarreglodecaracteres,getchleedelbuffersihayalgoallíyllamaagetcharsielbufferestávacío.Tambiéndebeexistirunavariableíndicequeregistrelaposicióndelcarácteractualenelbuffertemporal.

Puestoqueelbufferyelíndicesoncompartidosporgetchyungetchydebenretenersusvaloresentrellamadas,debenserexternosaambasrutinas.Así,podemosescribirgetch,ungetchysusvariablescompartidascomo:

#defineBUFSIZE100

charbuf[BUFSIZE];/*bufferparaungetch*/

intbufp=0;/*siguienteposiciónlibreenbuf*/

intgetch(void)/*obtieneun(posiblementeyaregresado)carácter*/

{

return(bufp>0)?buf[--bufp]:getchar();

}

voidungetch(intc)/*regresacarácteralaentrada*/

{

if(bufp>=BUFSIZE)

printf("ungetch:demasiadoscaracteres\n");

else

buf[bufp++]=c;

}

Labibliotecaestándarincluyeunafunciónungetcqueproporcionaelregresodeuncarácter;estoseveráenelcapítulo7.Sehautilizadounarregloparaloqueseregresaalaentrada,enlugardeuncaráctersencillo,paradarunaideamásgeneral.

Ejercicio4-3.Dadalaestructurabásica,esfácilextenderlacalculadora.Agregueeloperadormódulo(%)yconsideracionesparanúmerosnegativos.□

Ejercicio4-4.Agregueórdenesparaimprimirelelementoaltopedelapilasinsacarlodeella,paraduplicarloyparaintercambiarlosdoselementosdeltope.Agregueunaordenparalimpiarlapila.□

Ejercicio4-5.Agregueaccesoafuncionesdebibliotecacomosin,expypow.Consulte<math.h>enelapéndiceB,sección4.□

Ejercicio4-6.Agregueórdenesparamanipularvariables.(Esfácilproporcionarveintiséisvariablesconnombresdeunaletra.)Añadaunavariableparaelvalorimpresomásreciente.□

Page 116: Titivillus 07.07

Ejercicio4-7.Escribaunarutinaungets(s)queregresaalaentradaunacadenacompleta.¿Debeungetsconoceracercadebufybufp,osólodebeusarungetch?□

Ejercicio4-8.Supongaquenuncaexistirámásdeuncarácterderegreso.Modifiquegetchyungetchdeacuerdoconeso.□

Ejercicio4-9.NuestrosgetchyungetchnomanejancorrectamenteunEOFqueseregresa.DecidacuálesdebensersuspropiedadessiseregresaunEOF,ydespuésrealicesudiseño.□

Ejercicio4-10.Unaorganizaciónalternativaempleagetlineparaleerunalíneacompletadeentrada;estohaceinnecesariosagetchyaungetch.Corrijalacalculadoraparaqueuseesteplanteamiento.□

Page 117: Titivillus 07.07

4.4.Reglasdealcance

LasfuncionesyvariablesexternasqueconstituyenunprogramaenCnonecesitansercompiladasalavez;eltextofuentedelprogramasepuedetenerenvariosarchivosysepuedencargarrutinaspreviamentecompiladasdebiblioteca.Entrelaspreguntasdeinterésestán

¿Cómoseescribenlasdeclaracionesdemodoquelasvariablesseandeclaradasadecuadamentedurantelacompilación?

¿Cómosearreglanlasdeclaracionesdemodoquetodaslaspiezasseconectenadecuadamentecuandosecargaelprograma?

¿Cómoseorganizanlasdeclaracionesdemodoquesólohayaunacopia?

¿Cómoseinicializanlasvariablesexternas?

Discutamosestostemasreorganizandoelprogramadelacalculadoraenvariosarchivos.Entérminosprácticos,lacalculadoraesdemasiadopequeñaparaqueconvengasepararla,peroesunaexcelenteilustracióndelosconceptosquesurgenenprogramasmayores.

Elalcancedeunnombreeslapartedelprogramadentrodelcualsepuedeusarelnombre.Paraunavariableautomáticadeclaradaalprincipiodeunafunción,elalcanceeslafuncióndentrodelacualestádeclaradoelnombre.Lasvariableslocalesconelmismonombrequeesténenfuncionesdiferentesnotienenrelación.Lomismoesválidoparalosparámetrosdeunafunción,queenefectosonvariableslocales.

Elalcancedeunavariableofunciónexternaabarcadesdeelpuntoenquesedeclarahastaelfindelarchivoqueseestácompilando.Porejemplo,simain,sp,val,push,ypopestándefinidasenunarchivo,enelordenexpuestoanteriormente,estoes,

main(){...}

intsp=0;

doubleval[MAXVAL];

voidpush(doublef){...}

doublepop(void){...}

entonceslasvariablesspyvalsepuedenutilizarenpushypopsimplementenombrándolas;nosenecesitaningunaotradeclaración.Peroestosnombresnosonvisiblesenmain,nipushnipop.

Porotrolado,sisevaahacerreferenciaaunavariableexternaantesdesudefinición,osiestádefinidaenunarchivofuentediferentealqueseestáutilizando,entoncesesobligatoriaunadeclaraciónextern.

Esimportantedistinguirentreladeclaracióndeunavariableexternaysudefinición.Unadeclaraciónexponelaspropiedadesdeunavariable(principalmentesutipo);unadefinicióntambiénprovocaquereserveunespacioparaalmacenamiento.Silaslíneas

Page 118: Titivillus 07.07

intsp;

doubleval[MAXVAL];

aparecenfueradecualquierfunción,definenlasvariablesexternasspyval,reservanunespacioparaalmacenamientoytambiénsirvencomodeclaraciónparaelrestodeesearchivofuente.Porotrolado,laslíneas

externintsp;

externdoubleval[];

declaranparaelrestodelarchivoquespesunintyquevalesunarreglodouble(cuyotamañosedeterminaenalgúnotrolugar),peronocreanlasvariablesnilesreservanespacio.

Sólodebeexistirunadefinicióndeunavariableexternaentretodoslosarchivosqueformanunprogramafuente;otrosarchivospuedencontenerdeclaracionesexternparateneraccesoaellas.(Tambiénpuedehaberdeclaracionesexternenelarchivoquecontieneladefinición.)Lostamañosdelosarreglosdebenserespecificadosconladefinición,peroesoptativohacerloenunadeclaraciónextern.

Lainicializacióndeunavariableexternasólovaconsudefinición.

Aunquenoesunaorganizaciónidóneaparaesteprograma,lasfuncionespushypoppuedendefinirseenunarchivo,ylasvariablesvalysppodríanserdefinidaseinicializadasenotro.Entoncessenecesitaríanlassiguientesdefinicionesydeclaracionesparaenlazarlas:

Enelarchivo1:

externintsp;

externdoubleval[]

voidpush(doublef){...}

doublepop(void){...}

Enelarchivo2:

intsp=0

doubleval[MAXVAL];

Debidoaquelasdeclaracionesexternqueseencuentranenelarchivo1estánsituadasantesyafueradelasdefinicionesdefunciones,seaplicanatodaslasfunciones;unconjuntodedeclaracionesbastaparatodoelarchivo1.Estamismaorganizacióntambiénseríanecesariasilasdefinicionesdespyvalseencontrarandespuésdesuusoenunarchivo.

Page 119: Titivillus 07.07

4.5.Archivodeencabezamientoheader

Consideremosahoraladivisióndelprogramadelacalculadoraenvariosarchivosfuente,comopodríasersicadaunodeloscomponentesfuerasustancialmentemayor.Lafunciónmainirádentrodeunarchivo,alquellamaremosmain.c;push,popysusvariablesvandentrodeunsegundoarchivo,stack.c;getopvaenuntercero,getop.c.Finalmente,getchyungetchvandentrodeuncuartoarchivo,getch.c;lassepararemosdelasotrasdebidoaquepodríanvenirdeunabibliotecacompiladaseparadamenteenunprogramarealista.

Hayalgomásdequépreocuparse—lasdefinicionesydeclaracionescompartidasentrearchivos.Debemoscentralizarlashastadondeseaposible,demodoquehayasólounacopiapormantenermientrassedesarrollaelprograma.Enconsecuencia,situaremosestematerialcomúnenunarchivotipoheader,calc.h,queseincluirádondeseanecesario.(Lalínea#includesedescribeenlasección4.11.)Entonces,elprogramaresultantesevecomosigue:

main.c:

#include<stdio.h>

#include<stdlib.h>

#include"calc.h"

#defineMAXOP100

main(){

...

}

calc.h:

#defineNUMBER'0'

voidpush(double);

doublepop(void);

intgetop(char[]);

intgetch(void);

voidungetch(int);

getop.c:

#include<stdio.h>

#include<ctype.h>

Page 120: Titivillus 07.07

#include"calc.h"

getop(){

...

}

getch.c:

#include<stdio.h>

#defineBUFSIZE100

charbuf[BUFSIZE];

intbufp=0;

intgetch(void){

...

}

intungetch(void){

...

}

stack.c:

#include<stdio.h>

#include"calc.h"

#defineMAXVAL100

intsp=0;

doubleval[MAXVAL];

voidpush(double)(

...

}

doublepop(void){

...

}

Existeuncompromisoentreeldeseodequecadaarchivosólotengaaccesoalainformaciónquenecesitaparasutrabajoylarealidadprácticadequeesmásdifícil

Page 121: Titivillus 07.07

mantenermásarchivostipoheader.Hastauntamañomoderadodeprograma,probablementeesmejortenerunarchivodeencabezamientoquecontengatodoloqueserácompartidoentrelaspartesdelprograma;éstaesladecisiónquetomamosaquí.Paraunprogramamuchomásgrande,senecesitaríamásorganizaciónymásarchivostipoheader.

Page 122: Titivillus 07.07

4.6.Variablesestáticas

Lasvariablesspyvalenstack.c,ybufybufpengetch.c,sonparaelusoprivadodelasfuncionesqueestánensusrespectivosarchivosfuente,ysesuponequenadamástieneaccesoaellas.Ladeclaraciónstatic,aplicadaaunavariableofunciónexterna,limitaelalcancedeeseobjetoalrestodelarchivofuentequeseestácompilando.Asílasvariablesstaticexternasproporcionanunaformadeocultarnombrescomobufybufpenlacombinacióngetch-ungetch,quedebenserexternasparaquepuedansercompartidas,aunquenodebenservisiblesalosusuariosdegetchyungetch.

Elalmacenamientoestáticoseespecificaalanteponeraladeclaraciónnormallapalabrastatic.Silasdosrutinasylasdosvariablessecompilanenunarchivo,comoen

staticcharbuf[BUFSIZE];/*bufferparaungetch*/

staticintbufp=0;/*siguienteposiciónlibreenbuf*/

intgetch(void){...}

voidungetch(intc){...}

entoncesningunaotrarutinaserácapazdeteneraccesoabufniabufp,yesosnombresnoentraránenconflictoconlosmismosnombresqueesténenotrosarchivosdelmismoprograma.Delamismamanera,lasvariablesquepushypoputilizanparalamanipulacióndelapilasepuedenocultar,declarandospyvalcomostatic.

Ladeclaraciónstaticexternaseusaconmásfrecuenciaenvariables,perotambiénsepuedeaplicarafunciones.Normalmente,losnombresdefuncionessonglobales,visiblesacualquierpartedelprogramacompleto.Sinembargo,siunafunciónsedeclaracomostatic,sunombreesinvisiblefueradelarchivoenelqueestádeclarada.

Ladeclaraciónstatictambiénpuedeaplicarseavariablesinternas.Lasvariablesinternasstaticsonlocalesaunafunciónenparticular,talcomolosonlasvariablesautomáticas,peroadiferenciadeellas,mantienensuexistenciaenlugardeiryvenircadavezqueseactivalafunción.Esosignificaquelasvariablesinternasstaticproporcionanalmacenamientoprivadoypermanentedentrodeunafunción.

Ejercicio4-11.Modifiquegetopdemodoquenonecesiteutilizarungetch.Sugerencia:empleeunavariablestaticinterna.□

Page 123: Titivillus 07.07

4.7.Variablestiporegistro

Unadeclaraciónregisterindicaalcompiladorquelavariableencuestiónseemplearáintensamente.Laideaesquelasvariablesregistersecoloquenenregistrosdelamáquina,loquepuededarcomoresultadoprogramasmáspequeñosyrápidos.Peroloscompiladorestienenlalibertaddeignorarestasugerencia.

Ladeclaraciónregisterseveasí:

registerintx;

registercharc;

etcétera.Ladeclaraciónregistersólosepuedeaplicaravariablesautomáticasyalosparámetrosformalesdeunafunción.Enesteúltimocaso,aparececomo

f(registerunsignedm,registerlongn)

{

registerinti;

...

}

Enlaprácticaexistenrestriccionesenlasvariablestiporegistro,quereflejanlarealidaddelequipodondeseopera.Sóloalgunasvariablesdecadafunciónsepuedenmantenerenregistros,ysólosepermitenciertostipos.Sinembargo,elexcesodedeclaracionestiporegistronoprovocadaños,puestoquelapalabraregisterseignoraenlasdeclaracionesexcesivasonopermitidas.Además,noesposibletomarladireccióndeunavariabledetiporegistro(temaquesetrataráenelcapítulo5),sinimportarsilavariableestáonorealmenteenunregistro.Lasrestriccionesespecíficassobreelnúmeroytipodeestasvariablesvaríandeunamáquinaaotra.

Page 124: Titivillus 07.07

4.8.Estructuradebloques

CnoesunlenguajeestructuradoenbloquesenelsentidodePascalolenguajessemejantes,puestoquelasfuncionesnosepuedendefinirdentrodeotrasfunciones.Porotraparte,lasvariablessepuedendefinirenunamodalidaddeestructuradebloquesdentrodeunafunción.Lasdeclaracionesdevariables(incluyendolainicialización)puedenseguiralallaveizquierdaqueindicacualquierproposicióncompuesta,nosólolaqueiniciaaunafunción.Lasvariablesdeclaradasdeestamaneraocultancualquiernombreidénticodevariablesenbloquesexternos,ypermanecenhastaqueseencuentralallavederechaquecorrespondeconlainicial.Porejemplo,en

if(n>0){

inti;/*declaraunanuevai*/

for(i=0;i<n;i++)

...

}

elalcancedelavariableieslarama“verdadera”delif;estainotienenadaqueverconalgunaifueradelbloque.Unavariableautomáticadeclaradaeinicializadaenunbloqueseinicializacadavezqueseentraalbloque.Unavariablestaticseinicializasólolaprimeravezqueseentraalbloque.

Lasvariablesautomáticas,incluyendolosparámetrosformales,tambiénescondenalasvariablesyfuncionesexternasdelmismonombre.Dadaslasdeclaraciones

intx;

inty;

f(doublex)

{

doubley;

...

}

enlafunciónf,lasocurrenciasdexserefierenalparámetro,queesundouble;fueradef,serefierenalintexterno.Lomismoesválidoparalavariabley.

Porestilo,esmejorevitarnombresdevariablesquecoincidenconnombresdeunalcanceexterior;lapotencialidaddeconfusiónyerroresmuygrande.

Page 125: Titivillus 07.07

4.9.Inicialización

Laincializaciónyasehamencionadomuchasveces,perosiemprealrededordealgúnotrotema.Estasecciónresumealgunasdelasreglas,ahoraqueyasehandiscutidolasdiferentescategoríasdealmacenamiento.

Enausenciadeunainicializaciónexplícita,segarantizaquelasvariablesexternasyestáticasseinicializaránencero;lasvariablesautomáticasytiporegistrotienenvaloresinicialesindefinidos(estoes,basura).

Lasvariablesescalaressepuedeninicializarcuandosedefinen,siguiendoalnombreconunsignodeigualyunaexpresión:

intx=1;

charapóstrofo='\'';

longdía=1000L*60L*60L*24L;/*milisegundos/día*/

Paravariablesexternasyestáticas,elinicializadordebeserunaexpresiónconstante;lainicializaciónserealizaunavez,conceptualmenteantesdequeelprogramainiciesuejecución.Paravariablesautomáticasytiporegistro,sehacecadavezqueseentraalafunciónobloque.

Paravariablesautomáticasytiporegistro,elinicializadornoselimitaaunaconstante:puedesercualquierexpresiónquecontengavalorespreviamentedefinidos,inclusollamadasafunciones.Porejemplo,lainicializacióndelprogramadebúsquedabinariadelasección3.3podríaescribirsecomo

intbinsearch(intx,intv[],intn)

{

intlow=0;

inthigh=n-1;

intmid;

...

}

enlugarde

intlow,high,mid;

low=0;

high=n-1;

Enefecto,lasinicializacionesdevariablesautomáticassonsóloabreviaturasdeproposicionesdeasignación.Laelecciónesengranmedidacuestióndegusto.Nosotros

Page 126: Titivillus 07.07

hemosempleadogeneralmenteasignacionesexplícitas,debidoaquelosinicializadoresenlasdeclaracionessondifícilesdeverylejanosdellugardeuso.

Unarreglopuedeserinicializadoalseguirsudeclaraciónconunalistadeinicializadoresencerradosentrellavesyseparadosporcomas.Porejemplo,parainicializarunarreglodíasconelnúmerodedíasdecadames:

intdías[]={31,28,31,30,31,30,31,31,30,31,30,31};

Cuandoseomiteeltamañodeunarreglo,elcompiladorcalcularálalongitudcontandolosinicializadores,loscualesson12enestecaso.

Siexistenmenosinicializadoresparaunarregloquelosdeltamañoespecificado,losotrosseránceroparavariablesexternasoestáticas,perobasuraparaautomáticas.Esunerrortenerdemasiadosinicializadores.Nohayformadeindicarlarepeticióndeuninicializador,nideinicializarunelementoqueestáalamitaddeunarreglosinproporcionartambiéntodoslosvaloresprecedentes.

Losarreglosdecaracteressonuncasoespecialdeinicialización;sepuedeutilizarunacadenaenlugardelanotacióndellavesycomas:

charpatrón[]="ould";

esmáscortoperoequivalentea

charpatrón[]={'o','u','l','d','\0'};

Enestecaso,eltamañodelarregloescinco(cuatrocaracteresmáselterminador'\0').

Page 127: Titivillus 07.07

4.10.Recursividad

LasfuncionesdeCpuedenemplearserecursivamente;estoes,unafunciónpuedellamarseasímismayaseadirectaoindirectamente.Considerelaimpresióndeunnúmerocomounacadenadecaracteres.Comoyasemencionóanteriormente,losdígitossegeneranenordenincorrecto:losdígitosdeordeninferiorestándisponiblesantesdelosdígitosdeordensuperior,perosedebenimprimirenelordeninvertido.

Existendossolucionesaesteproblema.Unaesalmacenarlosdígitosenunarreglotalcomosegeneran,ydespuésimprimirlosenordeninverso,comosehizoconitoaenlasección3.6.Laalternativaesunasoluciónrecursiva,enlaqueprintdprimerosellamaasímismaparatratarconlosprimerosdígitos,ydespuésimprimeeldígitodelfinal.Denuevo,estaversiónpuedefallarconelnúmeronegativomásgrande.

#include<stdio.h>

/*printd:imprimenendecimal*/

voidprintd(intn)

{

if(n<0){

putchar('-');

n=-n;

}

if(n/10);

printd(n/10);

putchar(n%10+'0');

}

Cuandounafunciónsellamaasímismarecursivamente,cadainvocaciónobtieneunconjuntonuevodetodaslasvariablesautomáticas,independientedelconjuntoprevio.Así,enprintd(123)elprimerprintdrecibeelargumenton=123.Pasa12alsegundoprintd,queasuvezpasa1auntercero.Elprintddeltercernivelimprime1,despuésregresaalsegundonivel.Eseprintdimprime2,despuésregresaalprimernivel.Eseimprime3ytermina.

Otrobuenejemploderecursividadesquicksort,unalgoritmodeordenamientodesarrolladoen1962porC.A.R.Hoare.Dadounarreglo,unelementoseseleccionaylosotrosseparticionanendossubconjuntos—aquellosmenoresqueelelementodelaparticiónyaquellosmayoresoigualesaél.Elmismoprocesoseaplicadespuésrecursivamentealosdossubconjuntos.Cuandounsubconjuntotienemenosdedoselementosnonecesitayadeningúnordenamiento;estodetienelarecursividad.

Nuestraversióndequicksortnoeslamásrápidaposible,peroesunadelasmás

Page 128: Titivillus 07.07

simples.Empleamoselelementointermediodecadasubarregloparaparticionar.

/*qsort:ordenav[left]...v[right]enordenascendente*/

voidqsort(intv[],intleft,intright)

{

inti,last;

voidswap(intv[],inti,intj);

if(left>=right)/*nohacenadasielarreglocontiene*/

return;/*menosdedoselementos*/

swap(v,left,(left+right)/2);/*mueveelelementodepartición*/

last=left;/*av[0]*/

for(i=left+1;1<=right;i++)/*partición*/

if(v[i]<v[left])

swap(v,++last,i);

swap(v,left,last);/*regresaelelementodepartición*/

qsort(v,left,last-1);

qsort(v,last+1,right);

}

Pasamoslaoperacióndeintercambioaunafunciónseparadaswap,puestoqueocurretresvecesenqsort.

/*swap:intercambiav[i]yv[j]*/

voidswap(intv[],inti,intj)

{

inttemp;

temp=v[i];

v[i]=v[j];

v[j]=temp;

}

Labibliotecaestándarincluyeunaversióndeqsortquepuedeordenarobjetosdecualquiertipo.

Larecursividadnopuedeproporcionarunahorroenalmacenamiento,puestoqueen

Page 129: Titivillus 07.07

algúnlugarsedebemantenerunapiladelosvaloresprocesados.Niserámásrápida.Peroelcódigorecursivoesmáscompactoyfrecuentementemuchomásfácildeescribirydeentenderquesuequivalentenorecursivo.Larecursividadesespecialmenteconvenienteparaestructurasdedatosdefinidasenformarecursiva,comoárboles;veremosunagradableejemploenlasección6.5.

Ejercicio4-12.Adaptelasideasdeprintdalescribirlaversiónrecursivadelprogramaitoa;estoes,conviertaunenteroenunacadenallamandoaunarutinarecursiva.□

Ejercicio4-13.Escribaunaversiónrecursivadelafunciónreverse(s),queinviertelacadenasensulugar.□

Page 130: Titivillus 07.07

4.11.ElpreprocesadordeC

Cproporcionaciertasfacilidadesdelenguajepormediodeunpreprocesador,queconceptualmenteesunprimerpasoseparadoenlacompilación.Losdoselementosqueseusanconmásfrecuenciason#include,paraincluirelcontenidodeunarchivodurantelacompilación,y#define,parareemplazarunsímboloporunasecuenciaarbitrariadecaracteres.Otrascaracterísticasquesedescribenenestasecciónincluyencompilacióncondicionalymacrosconargumentos.

Page 131: Titivillus 07.07

4.11.1.Inclusióndearchivos

Lainclusióndearchivosfacilitaelmanejodegruposde#defineydeclaraciones(entreotrascosas).Cualquierlíneafuentedelaforma

#include"nombre”

o

#include<nombre>

sereemplazaporelcontenidodelarchivonombre.Sielnombreseencierraentrecomillas,labúsquedadelarchivocomienzanormalmentedondeseencontróelprogramafuente;sinoseencuentraallí,osielnombresedelimitapor<y>,labúsquedasigueunarutapredefinidaporlaimplantaciónparaencontrarelarchivo.Unarchivoincluidopuedecontenerlíneas#include.

Frecuentementeexistenvariaslíneas#includealprincipiodeunarchivofuente,paraincluirproposiciones#defineydeclaracionesexterncomunes,oparateneraccesoaladeclaracióndelprototipodeunafuncióndebibliotecadesdeheaderscomo<stdio.h>.(Estrictamentehablando,nonecesitanserarchivos;losdetallesdecómosetieneaccesoalosheadersdependendelaimplantación.)

#includeeslamejormaneradeenlazarlasdeclaracionesparaunprogramagrande.Garantizaquetodoslosarchivosfuentesesupliránconlasmismasdefinicionesydeclaracionesdevariables,yasíeliminauntipodeerrorparticularmentedesagradable.Porsupuesto,cuandosecambiaunarchivoinclude,sedebenrecompilartodoslosarchivosquedependendeél.

Page 132: Titivillus 07.07

4.11.2.Substitucióndemacros

Unadefinicióntienelaforma

#definenombretextodereemplazo

Pidelasubstitucióndeunamacrodeltipomássencillo—lassiguientesocurrenciasdenombreseránsubstituidasporeltextodereemplazo.Elnombreenun#definetienelamismaformaqueunnombredevariable;eltextodereemplazoesarbitrario.Normalmenteeltextodereemplazoeselrestodelalínea,perounadefiniciónextensapuedecontinuarseenvariaslíneas,colocandouna\alfinaldecadalíneaquevaacontinuar.Elalcancedeunnombredefinidocon#definevadesdesupuntodedefiniciónhastaelfindelarchivofuentequesecompila.Unadefiniciónpuedeempleardefinicionesprevias.Lassubstitucionesserealizansóloparaelementos,ynosucededentrodecadenasdelimitadasporcomillas,porejemplo,siAFIRMAesunnombredefinido,nohabrásubstituciónenprintf("AFIRMA”)nienAFIRMATIVO.

Cualquiernombrepuededefinirseconcualquiertextodereemplazo.Porejemplo.

#defineporsiemprefor(;;)/*cicloinfinito*/

defineunanuevapalabra,porsiempre,parauncicloinfinito.

Tambiénesposibledefinirmacrosconargumentos,paraqueeltextodereemplazopuedaserdiferenteparadiferentesllamadasdelamacro.Comounejemplo,definaunamacrollamadamax;

#definemax(A,B)((A)>(B)?(A):(B))

Aunqueaparentaserunallamadaafunción,elusodemaxseexpandeacódigo.Cadaocurrenciadeunparámetroformal(AoB)seráreemplazadaporelargumentorealcorrespondiente.Así,lalínea

x=max(p+q,r+s);

seráreemplazadaporlalínea

x=((p+q)>(r+s)?(p+q):(r+s));

Entantoquelosargumentossetratenconsistentemente,estamacroserviráparacualquiertipodedatos;nohaynecesidaddediferentestiposdemaxparadiferentestiposdedatos,comolahabríaconlasfunciones.

Siexaminalaexpansióndemax,notaráalgunosriesgos.Lasexpresionesseevalúandosveces;estoesmalosiinvolucraefectoscolateralescomooperadoresincrementalesodeentradaysalida.Porejemplo,

max(i++,j++)/*INCORRECTO*/

incrementaráelvalormásgrandedosveces.Tambiéndebetenersealgúncuidadoconlosparéntesis,paraasegurarquesepreservaelordendeevaluación;considerequépasacuandolamacro

Page 133: Titivillus 07.07

#definecuadrado(x)x*x/*INCORRECTO*/

seinvocacomocuadrado(z+1).

Sinembargo,lasmacrossonvaliosas.Unejemploprácticovienede<stdio.h>,dondegetcharyputcharsedefinenfrecuentementecomomacrosparaevitarelexcesodetiempodeejecucióndeunallamadaafunciónporcadacarácterprocesado.Lasfuncionesen<ctype.h>tambiénserealizangeneralmentecomomacros.

Losnombressepuedenhacerindefinidoscon#undef,paraasegurarqueunarutinaesrealmenteunafunción,nounamacro:

#undefgetchar

intgetchar(void){...}

Losparámetrosformalesnosereemplazandentrodecadenasentrecomillas.Sinembargo,siunnombredeparámetroestáprecedidoporun#eneltextodereemplazo,lacombinaciónseexpandiráenunacadenaentrecomillas,conelparámetroreemplazadoporelargumentoreal.Estopuedecombinarseconconcatenacióndecadenasparahacer,porejemplo,unamacrodeimpresiónparadepuración:

#definedprint(expr)printf(#expr"=%g\n",expr)

Cuandoseinvoca,comoen

dprint(x/y);

lamacroseexpandeen

printf("x/y""=%g\n",x/y);

ylascadenasseconcatenan,asíelefectoes

printf("x/y=%g\n",x/y);

Dentrodelargumentoreal,cada"sereemplazapor\"ycada\por\\,asíqueelresultadoesunaconstantedecadenalegítima.

Eloperador##delpreprocesadorproporcionaunaformadeconcatenarargumentosrealesdurantelaexpansióndeunamacro.Siunparámetroqueestáeneltextodereemplazoesadyacenteaun##,esreemplazadoporelargumentoreal,seeliminanel##ylosespaciosenblancoquelorodean,yelresultadoserastreadenuevo.Porejemplo,lamacropasteconcatenasusdosargumentos:

#definepaste(front,back)front##back

así,paste(nombre,1)creaeltokennombre1.

Lasreglasparaelusoanidadode##sonmisteriosas;enelapéndiceAsepuedenencontrarmayoresdetalles.

Ejercicio4-14.Definaunamacroswap(t,x,y)queintercambiedosargumentosdetipot.(Laestructuradebloquesayudará.)□

Page 134: Titivillus 07.07

4.11.3.Inclusióncondicional

Esposiblecontrolarelpreprocesamientomismoconproposicionescondicionalesqueseevalúanduranteesaetapa.Estoproporcionaunaformadeincluircódigoselectivamente,dependiendodelvalordecondicionesevaluadasdurantelacompilación.

Lalínea#ifevalúaunaexpresiónconstanteentera(quenopuedeincluirsizeof,castsoconstantesenum).Silaexpresiónesdiferentedecero,seincluyenlassiguienteslíneashastaun#endif,#elifo#else.(Laproposicióndeprocesador#elifescomoelseif).Laexpresióndefined(nombre)enun#ifes1sielnombresehadefinido,y0deotramanera.

Porejemplo,paraasegurarsedequeelcontenidodeunarchivohdr.hseincluyasólounavez,elcontenidodelarchivosedelimitaconunacondicionalcomoésta:

#if!defined(HDR)

#defineHDR

/*elcontenidodehdr.hvaaquí*/

#endif

Laprimerainclusióndehdr.hdefineelnombreHDR;lassiguientesinclusionesencontrarándefinidoalnombreypasaránhaciael#endif.Unestilosemejantepuedeemplearseparaevitarincluirarchivosvariasveces.Siesteestiloseutilizaenformaconsistente,entoncescadaheaderpuedeensímismoincluircualquierotrodelquedependa,sinqueelusuariotengaquetratarconlainterdependencia.

LasiguientesecuenciapruebaelnombreSYSTEMparadecidircuálversióndeunheaderincluir:

#ifSYSTEM==SYSV

#defineHDR"sysv.h"

#elifSYSTEM==BSD

#defineHDR"bsd.h"

#elifSYSTEM==MSDOS

#defineHDR"msdos.h"

#else

#defineHDR"default.h"

#endif

#includeHDR

Laslíneas#ifdefe#ifndefsonformasespecializadasquepruebansiunnombreestá

Page 135: Titivillus 07.07

definido.Elprimerejemplode#ifdemásarribapudohaberseescrito

#ifndefHDR

#defineHDR

/*contenidodehdr.hvaaquí*/

#endif

Page 136: Titivillus 07.07

CAPÍTULO5:Apuntadoresyarreglos

Unapuntadoresunavariablequecontieneladireccióndeunavariable.LosapuntadoresseutilizanmuchoenC,enpartedebidoaqueellossonenocasioneslaúnicaformadeexpresarunaoperación,yenpartedebidoaqueporlogeneralllevanuncódigomáscompactoyeficientedeloquesepuedeobtenerenotrasformas.Losapuntadoresylosarreglosestánrelacionadosíntimamente;estecapítulotambiénexploraestasrelacionesymuestracómoexplotarlas.

Losapuntadoressehanpuestojuntoalaproposicióngotocomounaformamaravillosadecrearprogramasininteligibles.Estoesverdaderocuandoseutilizanenformadescuidada,yesfácilcrearapuntadoresqueseñalenaalgúnlugarinesperado.Sinembargo,condisciplina,losapuntadorespuedentambiénemplearseparaobtenerclaridadysimplicidad.Esteeselaspectoquetrataremosdeilustrar.

ElprincipalcambioenANSICeshacerexplícitaslasreglasacercadecómopuedenmanipularselosapuntadores,obligandoaloquelosbuenosprogramadoresyapracticanyloquelosbuenoscompiladoresyaimponen.Además,eltipovoid*(apuntadoravoid)reemplazaachar*comoeltipoapropiadoparaunapuntadorgenérico.

Page 137: Titivillus 07.07

5.1.Apuntadoresydirecciones

Empecemosconundibujosimplificadodecómoseorganizalamemoria.Unamáquinatípicatieneunarreglodeceldasdememorianumeradasodireccionadasconsecutivamente,quepuedenmanipularseindividualmenteoengruposcontiguos.Unasituacióncomúnesquecualquierbytepuedeserunchar,unpardeceldasdeunbytepuedentratarsecomounenteroshort,ycuatrobytesadyacentesformanunlong.Unapuntadoresungrupodeceldas(generalmentedosocuatro)quepuedenmantenerunadirección.Así,sicesuncharypesunapuntadorqueapuntaaél,podríarepresentarselasituacióndeestamanera:

Eloperadorunario&daladireccióndeunobjeto,demodoquelaproposición.

p=&c;

asignaladireccióndecalavariablep,ysedicequep“apuntaa”c.Eloperador&sóloseaplicaaobjetosqueestánenmemoria:variablesyelementosdearreglos.Nopuedeaplicarseaexpresiones,constantesovariablestiporegistro.

Eloperadorunario*eseloperadordeindirecciónodesreferencia;cuandoseaplicaaunapuntador,daaccesoalobjetoalqueseñalaelapuntador.Supóngasequexyysonenteroseipesunapuntadoraint.Estasecuenciaartificialmuestracómodeclararunapuntadorycómoemplear&y*:

intx=1,y=2,z[10];

int*ip;/*ipesunapuntadoraint*/

ip=&x;/*ipahoraapuntaax*/

y=*ip;/*yesahora1*/

*ip=0;/*xesahora0*/

ip=&z[0];/*ipahoraapuntaaz[0]*/

Lasdeclaracionesdex,yyzsonloquehemosvistotodoeltiempo.Ladeclaracióndelapuntadorip,

int*ip;

funcionacomomnemónico;dicequelaexpresión*ipesunint.Lasintaxisdeladeclaraciónparaunavariableimitalasintaxisdeexpresionesenlasquelavariablepuedeaparecer.Esterazonamientoseaplicatambiénaladeclaracióndefunciones.Por

Page 138: Titivillus 07.07

ejemplo,

double*dp,atof(char*);

indicaqueenunaexpresión*dpyatof(s)tienenvaloresdetipodouble,yqueelargumentodeatofesunapuntadorachar.

Tambiénsedebenotarlaimplicaciónquetieneelhechodequeunapuntadorestárestringidoaseñalaraunaclaseparticulardeobjeto:cadaapuntadorseñalaauntipoespecíficodedatos.(Hayunaexcepción:un“apuntadoravoid”seempleaparamantenercualquiertipodeapuntador,peroensímismonopuedeserdesreferenciado.Estosevolveráatratarenlasección5.11.)

Siipapuntaalenterox,entonces*ippuedepresentarseencualquiercontextodondexpuedahacerlo,asíque

*ip=*ip+10;

incrementa*ipen10.

Losoperadoresunarios*y&seliganmásestrechamentequelosoperadoresaritméticos;así,laasignación

y=*ip+1

tomaaquelloaloqueapunteip,leagrega1,yasignaelresultadoay,mientrasque

*ip+=1

incrementaenunoaquelloaqueipapunta,comolohace

++*ip

y

(*ip)++

Losparéntesissonnecesariosenesteúltimoejemplo;sinellos,laexpresiónincrementaríaipenlugardealoqueapunta,debidoaquelosoperadoresunarioscomo*y++seasociandederechaaizquierda.

Porúltimo,puestoquelosapuntadoressonvariables,sepuedenemplearsindesreferenciamiento.Porejemplo,siiqesotroapuntadoraint,

iq=ip

copiaelcontenidodeipeniq;así,hacequeiqapuntealoqueipestáapuntando.

Page 139: Titivillus 07.07

5.2.Apuntadoresyargumentosdefunciones

PuestoqueCpasalosargumentosdefuncionesporvalor,noexisteunaformadirectaparaquelafunciónqueseinvocaaltereunavariabledelafunciónquelallama.Porejemplo,unarutinadeordenamientopodríaintercambiardoselementosdesordenadosconunafunciónllamadaswap.Noessuficienteescribir

swap(a,b);

dondelafunciónswapestádefinidacomo

voidswap(intx,inty)/*INCORRECTO*/

{

inttemp;

temp=x;

x=y;

y=temp;

}

Debidoalallamadaporvalor,swapnopuedeafectarlosargumentosaybqueestánenlarutinaquelallamó.Lafunciónanteriorsólointercambiacopiasdeaydeb.

Laformadeobtenerlosresultadosquesedeseanesqueelprogramainvocadorpaseapuntadoresalosvaloresquesecambiarán:

swap(&a,&b);

Puestoqueeloperador&produceladireccióndeunavariable,&aesunapuntadoraa.Dentrodelamismafunciónswap,losparámetrossedeclaranparaserapuntadores,ysetieneaccesoalosoperandosindirectamenteatravésdeellos.

voidswap(int*px,int*py)/*intercambia*pxy*py*/

{

inttemp;

temp=*px;

*px=*py;

*py=temp;

}

Gráficamente:

Page 140: Titivillus 07.07

Losargumentostipoapuntadorpermitenaunafunciónteneraccesoycambiarobjetosqueestánenlafunciónquelallamó.Comoejemplo,considereunafuncióngetintquerealizaunaconversióndeentradaenformatolibre,desglosandounflujodecaracteresenvaloresenteros,unenteroporllamada.Así,getinttienequeregresarelvalorencontradoytambiénunaseñaldefindearchivocuandoyanohaymásquetomar.Esosvalorestienenqueregresarseporrutasseparadas,paraquesinimportarquévalorseempleaparaEOF,tambiénpuedaserelvalordeunenterodelaentrada.

Unasolucióneshacerquegetintregreseelestadodefindearchivocomosuvalordefunción,usandounargumentoapuntadorparaalmacenarelenteroconvertidoytenerloenlafuncióninvocadora.Esteesquematambiénesutilizadoporscanf,comoseveráenlasección7.4.

Elsiguienteciclollenaunarregloconenterospormediodellamadasagetint:

intn,array[SIZE],getint(int*);

for(n=0;n<SIZE&&getint(&array[n])!=EOF;n++)

;

Cadallamadaponeenarray[n]elsiguienteenteroqueseencuentraalaentradaeincrementan.Obsérvesequeesesencialpasarladireccióndearray[n]agetint.Deotramaneranohayformadequegetintcomuniqueelenteroconvertidohacialafuncióninvocadora.

EstaversióndegetintregresaEOFcomofindearchivo,cerosilasiguienteentradanoesunnúmero,yunvalorpositivosilaentradacontieneunnúmeroválido.

#include<ctype.h>

intgetch(void);

voidungetch(int);

/*getint:obtieneelsiguienteenterodelaentradayloasignaa*pn*/

Page 141: Titivillus 07.07

intgetint(int*pn)

{

intc,sign;

while(isspace(c=getch()))/*ignoraespaciosenblanco*/

;

if(!isdigit(c)&&c!=EOF&&c!='+'&&c!='-'){

ungetch(c);/*noesunnúmero*/

return0;

}

sign=(c=='-')?-1:1;

if(c=='+'||c=='-')

c=getch();

for(*pn=0;isdigit(c);c=getch())

*pn=10**pn+(c-'0');

*pn*=sign;

if(c!=EOF)

ungetch(c);

returnc;

}

Alolargodegetint,*pnseempleacomounavariableintordinaria.Tambiénseutilizógetchyungetch(descritasenlasección4.3)paraqueelcarácterextraquedebeleersepuederegresaralaentrada.

Ejercicio5-1.Comoseescribió,getinttrataaun+oun-noseguidoporundígitocomounarepresentaciónválidadecero.Corríjalaparaqueregresetalcarácteralaentrada.□

Ejercicio5-2.Escribagetfloat,laanalogíadepuntoflotantedegetint.¿Quétiporegresagetfloatcomosuvalordefunción?□

Page 142: Titivillus 07.07

5.3.Apuntadoresyarreglos

EnCexisteunafuerterelaciónentreapuntadoresyarreglos,tanfuertequedebendiscutirsesimultáneamente.Cualquieroperaciónquepuedalograrseporindexacióndeunarreglotambiénpuederealizarseconapuntadores.Laversiónconapuntadoresseráporlogeneralmásrápida,pero,almenosparalosnoiniciados,algomásdifícildeentender.

Ladeclaración

inta[10];

defineunarregloadetamaño10,estoes,unbloquede10objetosconsecutivosllamadosa[0],a[l],...,a[9].

Lanotacióna[i]serefiereali-ésimoelementodelarreglo.Sipaesunapuntadoraunentero,declaradocomo

int*pa;

entonceslaasignación

pa=&a[0];

hacequepaapuntealelementocerodea;estoes,pacontieneladireccióndea[0].

Ahoralaasignación

x=*pa;

copiaráelcontenidodea[0]enx.

Sipaapuntaaunelementoenparticulardeunarreglo,entoncespordefiniciónpa+1apuntaalsiguienteelemento,pa+iapuntaielementosdespuésdepa,ypa-iapuntaielementosantes.Así,sipaapuntaaa[0],

Page 143: Titivillus 07.07

*(pa+l)

serefierealcontenidodea[l],pa+iesladireccióndea[i]y*(pa+i)eselcontenidodea[i].

Loanterioresverdaderosinimportareltipootamañodelasvariablesdelarregloa.Elsignificadode“agregar1aunapuntador”,yporextensión,todalaaritméticadeapuntadores,esquepa+1apuntaalsiguienteobjeto,ypa+iapuntaali-ésimoobjetoadelantedepa.

Lacorrespondenciaentreindexaciónyaritméticadeapuntadoresesmuyestrecha.Pordefinición,elvalordeunavariableoexpresióndetipoarregloesladireccióndelelementocerodelarreglo.Así,quedespuésdelaasignación

pa=&a[0];

payatienenvaloresidénticos.Puestoqueelnombredeunarregloesunsinónimoparalalocalidaddelelementoinicial,laasignaciónpa=&a[0]puedeescribirsetambiéncomo

pa=a;

Mássorprendente,almenosaprimeravista,eselhechodequeunareferenciaaa[i]tambiénpuedeescribirsecomo*(a+i).Alevaluara[i],Claconvierteinmediatamentea*(a+i);lasdosformassonequivalentes.Alaplicareloperador&aambaspartesdeestaequivalencia,sederivaque&a[i]ya+itambiénsonidénticas:a+iesladireccióndeli-ésimoelementodelantedea.Porotraparte,sipaesunapuntador,lasexpresionespuedenusarloconunsubíndice;pa[i]esidénticoa*(pa+i).Enresumen,cualquierexpresióndearregloeíndiceesequivalenteaunaexpresiónescritacomounapuntadoryundesplazamiento.

Existeunadiferenciaentreunnombredearregloyunapuntador,quedebetenerseenmente.Unapuntadoresunavariable,porestopa=aypa++sonlegales.Perounnombredearreglonoesunavariable;construccionescomoa=paya++sonilegales.

Cuandounnombredearreglosepasaaunafunción,loquesepasaeslalocalidaddelelementoinicial.Dentrodelafunciónquesellama,esteargumentoesunavariablelocal,yporlotanto,unparámetrodenombredearregloesunapuntador,estoes,unavariablequecontieneunadirección.Sepuedeutilizarestehechoparaescribirotraversióndestrlen,quecalculalalongituddeunacadena.

/*strlen:regresalalongituddelacadenas*/

intstrlen(char*s)

{

Page 144: Titivillus 07.07

intn;

for(n=0;*s!='\0';s++)

n++;

returnn;

}

Puestoquesesunapuntador,esperfectamentelegalincrementarlo;s++notieneefectoalgunosobrelacadenadecaracteresdelafunciónquellamóastrlen,sinoquesimplementeincrementalacopiaprivadadelapuntadordestrlen.Esosignificaquellamadascomo

strlen("hola,mundo");/*constantedecadena*/

strlen(array);/*chararray[100];*/

strlen(ptr);/*char*ptr;*/

sífuncionan.

Puestoquelosparámetrosformalesenunadefinicióndefunción,

chars[];

y

char*s;

sonequivalentes,preferimoselúltimo,porqueindicamásexplícitamentequeelparámetroesunapuntador.Cuandounnombredearreglosepasaaunafunción,éstapuedeinterpretarasuconvenienciaquesehamanejadounarregloounapuntador,ymanipularloenconsecuencia.Puedeinclusoemplearambasnotacionessiellolohaceapropiadoyclaro.

Esposiblepasarpartedeunarregloaunafunción,pasandounapuntadoraliniciodelsubarreglo.Porejemplo,siaesunarreglo,

f(&a[2])

y

f(a+2)

ambaspasanalafunciónfladireccióndelsubarregloqueiniciaena[2].Dentrodef,ladeclaracióndeparámetrospuedeser

f(intarr[]){...}

o

f(int*arr){...}

Así,hastadondeafleconcierne,elhechodequeelparámetroserefieraapartedeunarreglomásgrandenoesdeconsecuencia.

Page 145: Titivillus 07.07

Siseestásegurodequeloselementosexisten,tambiénesposibleindexarhaciaatrásenunarreglo;p[-1],p[-2],etc.,sonlegítimosdesdeelpuntodevistasintáctico,yserefierenaelementosqueprecedeninmediatamenteap[0].Porsupuesto,esilegalhacerreferenciaaobjetosquenoesténdentrodeloslímitesdelarreglo.

Page 146: Titivillus 07.07

5.4.Aritméticadedirecciones

Sipesunapuntadoraalgúnelementodeunarreglo,entoncesp++incrementapparaapuntaralsiguienteelemento,yp+=ilaincrementaparaapuntarielementosadelantededondeactualmentelohace.Esasyotrasconstruccionessemejantessonlasformasmássimplesdearitméticadeapuntadoresodedirecciones.

EllenguajeCesconsistenteyregularensuenfoquealaaritméticadedirecciones;suintegracióndeapuntadores,arreglosyaritméticadedireccionesesunodelosaspectosqueledanfuerza.Loilustraremosalescribirunrudimentarioasignadordememoria.Haydosrutinas:laprimera,alloc(n),regresaunapuntadorpanposicionesconsecutivas,quepuedenserempleadasporelinvocadordeallocparaalmacenarcaracteres.Lasegunda,afree(p),liberaelalmacenamientoadquiridoenestaforma,demodoquepuedaserreutilizadoposteriormente.Lasrutinassonrudimentarias,puestoquelasllamadasaafreedebenrealizarseenelordenopuestoalasllamadasrealizadasaalloc.Esdecir,elalmacenamientomanejadoporallocyafreeesunapilaolistadeltipoúltimo-que-entra,primero-que-sale.Labibliotecaestándarproporcionafuncionesanálogasllamadasmallocyfreequenotienentalesrestricciones;enlasección8.7semostrarácómosepuedenrealizar.

Laimplantaciónmássencillaeshacerqueallocmanejepiezasdeungranarreglodecaracteresalquellamaremosallocbuf.Estearregloestáreservadoparaallocyparaafree.Puestoqueéstashacensutrabajoconapuntadores,noconíndices,ningunaotrarutinanecesitaconocerelnombredelarreglo,elcualpuedeserdeclaradocomostaticenelarchivofuentequecontieneaallocyaafree,yasíserinvisiblehaciaafuera.Enlaimplantaciónpráctica,elarreglopuedeinclusonotenerunnombre;podríaobtenersellamandoamallocopidiendoalsistemaoperativounapuntadorhaciaalgúnbloquesinnombredememoria.

Laotrainformaciónnecesariaescuántodeallocbufsehautilizado.Empleamosunapuntador,llamadoallocp,queapuntahaciaelsiguienteelementolibre.Cuandoserequierenncaracteresaalloc,primerorevisasihaysuficienteespaciolibreenallocbuf.Silohay,allocregresaelvaloractualdeallocp(estoes,elprincipiodelbloquelibre),despuésloincrementaennparaapuntaralasiguienteárealibre.Sinohayespacio,allocregresacero,entantoqueafree(p)simplementehaceallocpigualapsipestádentrodeallocbuf.

antesdellamaraalloc:

despuésdellamaraalloc:

Page 147: Titivillus 07.07

#defineALLOCSIZE10000/*tamañodelespaciodisponible*/

staticcharallocbuf[ALLOCSIZE];/*almacenamientoparaalloc*/

staticchar*allocp=allocbuf;/*siguienteposiciónlibre*/

char*alloc(intn)/*regresaunapuntadorancaracteres*/

{

if(allocbuf+ALLOCSIZE-allocp>=n){/*sícabe*/

allocp+=n;

returnallocp-n;/*antiguap*/

}else/*nohaysuficienteespacio*/

return0;

}

voidafree(char*p)/*almacenamientolibreapuntadoporp*/

{

if(p>=allocbuf&&p<allocbuf+ALLOCSIZE)

allocp=p;

}

Engeneral,unapuntadorpuedeserinicializadotalcomocualquierotravariable,aunquenormalmentelosúnicosvaloressignificativossonceroounaexpresiónqueinvolucreladireccióndeundatopreviamentedefinidoydeuntipoapropiado.Ladeclaración

staticchar*allocp=allocbuf;

defineaallocpcomounapuntadoracaracteresyloinicializaparaapuntaralprincipiodeallocbuf,queeslasiguienteposiciónlibrecuandoelprogramacomienza.Estotambiénpodríahaberseescrito

staticchar*allocp=&allocbuf[0];

puestoqueelnombredelarregloesladireccióndelelementocero-ésimo.

Laprueba

if(allocbuf+ALLOCSIZE-allocp>=n){/*sícabe*/

compruebasiexistesuficienteespacioparasatisfacerlapeticióndencaracteres.Silohay,elnuevovalordeallocpsería,cuandomucho,unoadelantedelfindeallocbuf.Silapeticiónpuedesatisfacerse,allocregresaunapuntadoralprincipiodeunbloquedecaracteres(nóteseladeclaracióndelafunción).Delocontrario,allocdeberegresar

Page 148: Titivillus 07.07

algunaseñaldequenoquedaespacio.EllenguajeCgarantizaqueceronuncaesunadirecciónválidaparadatosyporlotantopuedeusarseunvalordecerocomoretornoparaseñalarunsucesoanormal,enestecaso,faltadeespacio.

Losapuntadoresylosenterosnosonintercambiables.Ceroeslaúnicaexcepción:laconstanteceropuedeserasignadaaunapuntador,yéstepuedecompararsecontralaconstantecero.LaconstantesimbólicaNULLseempleaconfrecuenciaenlugardecero,comounmnemónicoparaindicarmásclaramentequeesunvalorespecialparaunapuntador.NULLestádefinidoen<stdio.h>.DeaquíenadelanteseutilizaráNULL.

Pruebascomo

if(allocbuf+ALLOCSIZE-allocp>=n){/*sícabe*/

y

if(p>=allocbuf&&p<allocbuf+ALLOCSIZE)

muestranvariasfacetasimportantesdelaaritméticadeapuntadores.Primero,losapuntadorespuedencompararsebajociertascircunstancias.Sipyqapuntanamiembrosdelmismoarreglo,entoncesrelacionescomo==,!=,<,>=,etc.,funcionancorrectamente.Porejemplo,

p<q

esverdaderosipapuntaaunelementoqueestáantesenelarreglodeloqueestáalqueapuntaq.Cualquierapuntadorpuedesercomparadoporsuigualdadodesigualdadconcero.Peroestáindefinidoelcomportamientoparalaaritméticaocomparacionesconapuntadoresquenoapuntanamiembrosdelmismoarreglo.(Existeunaexcepción:ladireccióndelprimerelementoqueestádespuésdelfindeunarreglopuedeemplearseenaritméticadeapuntadores.)

Segundo,yasehaobservadoqueunapuntadoryunenteropuedensumarseorestarse.Laconstrucción

p+n

significaladireccióndeln-ésimoobjetoadelantedelqueapuntaactualmentep.Estoesverdaderosinimportarlaclasedeobjetoalqueapuntap;nesescaladadeacuerdoconeltamañodelosobjetosalosqueapuntap,locualestádeterminadoporladeclaracióndep.Siunintesdecuatrobytes,porejemplo,laescalaparaelintserádecuatro.

Larestadeapuntadorestambiénesválida:sipyqapuntanaelementosdelmismoarreglo,yp<q,entoncesq-p+1eselnúmerodeelementosdesdephastaq,inclusive.Estehechopuedeusarseparaescribirtodavíaotraversióndestrlen:

/*strlen:regresalalongituddelacadenas*/

intstrlen(char*s)

{

char*p=s;

while(*p!='\0')

p++;

Page 149: Titivillus 07.07

returnp-s;

}

Ensudeclaración,pseinicializaens,estoes,paraapuntaralprimercarácterdelacadena.Enelciclowhile,cadacarácterseexaminaensuturnohastaquealfinalseencuentrael'\0'.Debidoaquepapuntaacaracteres,p++avanzapalsiguientecaráctercadavez,yp-sdaelnúmerodecaracteresqueseavanzaron,estoes,lalongituddelacadena.(Elnúmerodecaracteresenlacadenapuedeserdemasiadograndecomoparaalmacenarseenunint.Elheader<stddef.h>defineuntipoptrdiff_t,queessuficientementegrandeparaalmacenarladiferenciasignadadedosvaloresapuntadores.Sinembargo,siseesmuycauteloso,sedebeusarsize_tparaeltipoderetornodestrlen,paracoincidirconlaversióndelabibliotecaestándar,size_teseltipodeenterosinsignoqueregresaeloperadorsizeof.)

Laaritméticadeapuntadoresesconsistente:siestuviéramostratandoconfloats,queocupanmásespaciodememoriaqueloschars,ysipfueraunapuntadorafloat,p++avanzaríaalsiguientefloat.Así,podemosescribirotraversióndeallocquemantengafloatsenlugardechars,simplementecambiandodecharafloatentodoallocyafree.Todaslasmanipulacionesdeapuntadorestomaránautomáticamenteencuentaeltamañodelosobjetosapuntados.

Lasoperacionesválidasdeapuntadoressonasignacióndeapuntadoresdelmismotipo,sumaysubstraccióndeunapuntadoryunentero,restaocomparacióndedosapuntadoresamiembrosdelmismoarreglo,yasignaciónocomparaciónconcero.Todaotraaritméticadeapuntadoresesilegal.Noeslegalsumardosapuntadores,multiplicarlosodividirlos,enmascararlosoagregarlesunfloatoundouble,oaún,exceptoparavoid*,asignarunapuntadordeuntipoaunapuntadordeotrotiposinunaconversiónforzosadetipo.

Page 150: Titivillus 07.07

5.5.Apuntadoresacaracteres,yfunciones

Unaconstantedecadena,escritacomo

“Soyunacadena”

esunarreglodecaracteres.Enlarepresentacióninterna,elarregloterminaconelcarácternulo'\0',detalmaneraquelosprogramaspuedanencontrarelfin.Lalongituddealmacenamientoesasíunomásqueelnúmerodecaracteresentrelascomillas.

Posiblementelamáscomúnocurrenciadecadenasconstantesseencuentracomoargumentosafunciones,comoen

printf(”hola,mundo\n");

Cuandounacadenadecaracterescomoéstaapareceenunprograma,elaccesoaellaesatravésdeunapuntadoracaracteres;printfrecibeunapuntadoraliniciodelarreglodecaracteres.Estoes,setieneaccesoaunacadenaconstanteporunapuntadorasuprimerelemento.

Lascadenasconstantesnonecesitanserargumentosdefunciones.Sipmessagesedeclaracomo

char*pmessage;

entonceslaproposición

pmessage=“yaeseltiempo";

asignaapmessageunapuntadoralarreglodecaracteres.Estanoeslacopiadeunacadena;sóloconcierneaapuntadores.EllenguajeCnoproporcionaningúnoperadorparaprocesarcomounidadunacadenadecaracteres.

Existeunaimportantediferenciaentreestasdefiniciones:

charamessage[]="yaeseltiempo";/*arreglo*/

char*pmessage="yaeseltiempo";/*apuntador*/

amessageesunarreglo,suficientementegrandecomoparacontenerlasecuenciadecaracteresyel'\0'queloinicializa.Sepuedenmodificarcaracteresindividualesdentrodelarreglo,peroamessagesiempresereferiráalamismalocalidaddealmacenamiento.Porotrolado,pmessageesunapuntador,inicializadoparaapuntaraunacadenaconstante;elapuntadorpuedemodificarseposteriormenteparaqueapunteaalgúnotrolado,peroelresultadoesindefinidositratademodificarelcontenidodelacadena.

Page 151: Titivillus 07.07

Ilustraremosmásaspectosdelosapuntadoresylosarreglos,estudiandoversionesdedosútilesfuncionesadaptadasdelabibliotecaestándar.Laprimerafunciónesstrcpy(s,t),quecopialacadenatalacadenas.Seríaagradabledecirsimplementes=t,peroestocopiaelapuntador,noloscaracteres.Paracopiarloscaracteresserequieredeunciclo.Primeroestálaversiónconunarreglo:

/*strcpy:copiathacias;versióndesubíndices*/

voidstrcpy(char*s,char*t)

{

inti;

i=0;

while((s[i]=t[i])!='\0')

i++;

}

Encontraste,aquíestáunaversióndestrcpyconapuntadores:

/*strcpy:copiathacias;versión1conapuntadores*/

voidstrcpy(char*s,char*t)

{

while((*s=*t)!='\0'){

s++;

t++;

}

}

Puestoquelosargumentossepasanporvalor,strcpypuedeutilizarlosparámetrossytenlaformaqueleparezcamejor.Aquíhayapuntadoresconvenientementeinicializados,quesedesplazanalolargodelarreglouncarácteralavez,hastaqueel'\0'conqueterminatsehacopiadoas.

Enlapráctica,strcpynoseescribiríacomosemostróanteriormente.LosprogramadoresexpertosdeCpreferirían

/*strcpy:copiathacias;versión2conapuntadores*/

voidstrcpy(char*s,char*t)

{

while((*s++=*t++)!='\0')

Page 152: Titivillus 07.07

;

}

Estotrasladaelincrementodesydethaciadentrodelapartedepruebadelciclo.Elvalorde*t++eselcarácteralqueapuntatantesdeincrementarse;el++postfijonomodificatsinohastadespuésdequesehatomadoelcarácter.Enlamismaforma,elcaráctersealmacenaenlaposiciónanteriordesantesdequesseincremente.Tambiénestecaráctereselvalorcontraelcualsecompara'\0'paracontrolarelciclo.Elefectorealesqueloscaracteressecopiandetas,hastael'\0'final,incluyéndolo.

Comoresumenfinal,observequeunacomparacióncontra'\0'esredundante,puestoquelapreguntaessimplementesilaexpresiónescero.Así,lafunciónpodríaescribirsecorrectamentecomo

/*strcpy:copiathacias;versión3conapuntadores*/

voidstrcpy(char*s,char*t)

{

while(*s++=*t++)

;

}

Aunqueestopuedeparecermisteriosoaprimeravista,laconvenienciadeestanotaciónesconsiderable,ydebedominarseelestilo,puestoqueseencontraráfrecuentementeenprogramasdeC.

Enlabibliotecaestándar(<string.h>)strcpy,devuelvelacadenaobjetivocomoelvalordelafunción.

Lasegundarutinaqueexaminaremosesstrcmp(s,t),quecomparalascadenasdecaracteressyt,yregresaunvalornegativo,ceroopositivosiseslexicográficamentemenorque,iguala,omayorquet.Elvalorseobtienealrestarloscaracteresdelaprimeraposiciónenquesytnocoinciden.

/*strcmp:regresa<0sis<t,0sis==t,>0sis>t*/

intstrcmp(char*s,char*t)

{

inti;

for(i=0;s[i]==t[i];i++)

if(s[i]=='\0')

return0;

returns[i]-t[i];

}

Page 153: Titivillus 07.07

Laversiónconapuntadoresdestrcmp:

/*strcmp:regresa<0sis<t,0sis==t,>0sis>t*/

intstrcmp(char*s,char*t)

{

for(;*s==*t;s++,t++)

if(*s=='\0')

return0;

return*s-*t;

}

Puestoque++y--sonoperadoresprefijosopostfijos,sepresentanotrascombinacionesde*,++y--,aunqueconmenosfrecuencia.Porejemplo,

*--p

disminuyepantesdetraerelcarácteralqueapunta.Enefecto,laparejadeexpresiones

*p++=val;/*metevalenlapila*/

val=*--p;/*sacaeltopedelapilayloponeenval*/

sonexpresionesidiomáticasestándarparameterysacaralgodeunapila;véaselasección4.3.

Elheader<string.h>contienedeclaracionesparalasfuncionesquesemencionanenestasección,ademásdeunavariedaddeotrasfuncionesparamanipulacióndecadenasenlabibliotecaestándar.

Ejercicio5-3.Escribaunaversiónconapuntadoresdelafunciónstrcatquesemuestraenelcapítulo2:strcat(s,t)copialacadenatalfinaldes.□

Ejercicio5-4.Escribalafunciónstrend(s,t),queregresa1silacadenatsepresentaalfinaldelacadenas,ycerosinoesasí.□

Ejercicio5-5.Escribaversionesdelasfuncionesdebibliotecastrncpy,strncat,ystrncmp,queoperanconhastalosnprimeroscaracteresdesusargumentosdecadena.Porejemplo,strncpy(s,t,n)copiahastancaracteresdethacias.EnelapéndiceBseexponendescripcionesmáscompletas.□

Ejercicio5-6.Reescribalosprogramasyejerciciosapropiadosdeloscapítulosanteriores,empleandoapuntadoresenlugardeíndicesdearreglos.Buenosprospectossongetline(capítulos1y4),atoi,itoa,ysusvariantes(capítulos2,3y4),reverse(capítulo3)ystrindexygetop(capítulo4).□

Page 154: Titivillus 07.07

5.6.Arreglosdeapuntadores;apuntadoresaapuntadores

Puestoqueensímismoslosapuntadoressonvariables,puedenalmacenarseenarreglostalcomootrasvariables.Ilustraremosestoalescribirunprogramaqueordenaunconjuntodelíneasdetextoenordenalfabético,queesunaversiónrestringidadelprogramasortdeUNIX.

Enelcapítulo3sepresentóunafuncióndeordenamientoShellquepodíaordenarunarreglodeenteros,yenelcapítulo4semejoróconunquicksort.Elmismoalgoritmofuncionará,exceptoqueahorasedebetratarconlíneasdetextodediferenteslongitudes,yque,adiferenciadelosenteros,nosepuedencompararnicambiarenunasimpleoperación.Senecesitaunarepresentacióndedatosquemanejeeficienteyconvenientementelíneasdetexto.

Aquíesdondeentranlosarreglosdeapuntadores.Silaslíneasquesevanaordenarsealmacenanjuntasenungranarreglodecaracteres,entoncessepuedeteneraccesoacadalíneapormediodeunapuntadorasuprimercarácter.Porsulado,losapuntadoressepuedenalmacenarenunarreglo.Doslíneassepuedencompararpasandosusapuntadoresastrcmp.Cuandodoslíneasdesordenadastienenqueintercambiarse,seintercambianlosapuntadoresenelarreglodeapuntadores,nolaslíneasdetexto.

Estoeliminaeldobleproblemadeunmanejocomplicadodealmacenamientoyexcesodeprocesamientoqueseproduciríaalmoverlaslíneas.

Elprocesodeordenamientotienetrespasos:

leetodaslaslíneasdeentrada

ordénalas

imprímelasenorden

Comoesusual,esmejordividirelprogramaenfuncionesquecoincidanconestadivisiónnatural,conlarutinaprincipalcontrolandoalasotrasfunciones.Abandonemosporunmomentoelpasodeordenamiento,yconcentrémonosenlasestructurasdedatosylaentradaysalida.

Larutinadeentradatienequereuniryguardarloscaracteresdecadalínea,yconstruirunarreglodeapuntadoreshacialaslíneas.Tambiéndebecontarelnúmerodelíneasdeentrada,puestoqueesainformaciónserequiereparaelordenamientoylaimpresión.Debidoaquelafuncióndeentradasólopuedetratarconunnúmerofinitodelíneas,puederegresaralgunacuentadelíneasilegal,como-1,sisepresentademasiadotextoalaentrada.

Page 155: Titivillus 07.07

Larutinadesalidasólotienequeimprimirlaslíneasenelordenenqueaparecenenelarreglodeapuntadores.

#include<stdio.h>

#include<string.h>

#defineMAXLINES5000/*máx#delíneasporordenar*/

char*lineptr[MAXLINES];/*apuntadoresalíneasdetexto*/

intreadlines(char*lineptr[],intnlines);

voidwritelines(char*lineptr[],intnlines);

voidqsort(char*lineptr[],intleft,intright);

/*ordenalíneasdeentrada*/

main()

{

intnlines;/*númerodelíneasdeentradaleídas*/

if((nlines=readlines(lineptr,MAXLINES))>=0){

qsort(lineptr,0,nlines-1);

writelines(lineptr,nlines);

return0;

}else{

printf(error:entradademasiadograndeparaordenarla\n");

return1;

}

}

#defineMAXLEN1000/*máxlongituddecualquierlíneadeentrada*/

intgetline(char*,int);

char*alloc(int);

/*readlines:leelíneasdeentrada*/

intreadlines(char*lineptr[],intmaxlines)

{

intlen,nlines;

Page 156: Titivillus 07.07

char*p,line[MAXLEN];

nlines=0;

while((len=getline(line,MAXLEN))>0)

if(nlines>=maxlines||(p=alloc(len))==NULL)

return-1;

else{

line[len-1]='\0';/*eliminacarácternuevalínea*/

strcpy(p,line);

lineptr[nlines++]=p;

}

returnnlines;

}

/*writelines:escribelíneasdesalida*/

voidwritelines(char*lineptr[],intnlines)

{

inti;

for(i=0;i<nlines;i++)

printf("%s\n",lineptr[i]);

}

Lafuncióngetlinesetratóenlasección1.9.

Elprincipalnuevoelementoesladeclaraciónparalineptr:

char*lineptr[MAXLINES]

queindicaquelineptresunarreglodeMAXLINESelementos,cadaunodeloscualesesunapuntadorachar.Estoes,lineptr[i]esunapuntadoracarácter,y*lineptr[i]eselcarácteralqueapunta,elprimercarácterdelai-ésimalíneadetextoalmacenada.

Puestoquelineptresporsímismoelnombredeunarreglo,puedetratarsecomounapuntadorenlamismaformaqueennuestrosejemplosanteriores,ywritelinespuedeescribirseensulugarcomo

/*writelines:escribelíneasdesalida*/

voidwritelines(char*lineptr[],intnlines)

{

Page 157: Titivillus 07.07

while(nlines-->0)

printf("%s\n",*lineptr++);

}

Inicialmente*lineptrapuntaalaprimeralínea;cadaincrementoloavanzaalsiguienteapuntadoralíneamientrasnlinessedisminuye.

Teniendolaentradaylasalidabajocontrol,podemosprocederaordenar.Elquicksortdelcapítulo4necesitasólocambiosdepocaimportancia:lasdeclaracionesdebenmodificarse,ylaoperacióndecomparacióndebehacersellamandoastrcmp.Elalgoritmopermaneceigual,loquenosdaciertaconfianzadequeaúntrabajará.

/*qsort:ordenav[left]...v[right]enordenascendente*/

voidqsort(char*v[],intleft,intright)

{

inti,last;

voidswap(char*v[],inti,intj);

if(left>=right)/*nohacenadasielarreglocontienemenosdedoselementos*/

return;

swap(v,left,(left+right)/2);

last=left;

for(i=left+1;i<=right;i++)

if(strcmp(v[i],v[left])<0)

swap(v,++last,i);

swap(v,left,last);

qsort(v,left,last-1);

qsort(v,last+1,right);

}

Demanerasemejante,larutinadeintercambiosólorequieremodificacionespocosignificativas:

/*swap:intercambiav[i]yv[j]*/

voidswap(char*v[],inti,intj)

{

char*temp;

Page 158: Titivillus 07.07

temp=v[i];

v[i]=v[j];

v[j]=temp;

}

Puestoquecualquierelementoindividualdev(aliaslineptr)esunapuntadoracarácter,temptambiéndebeserlo,demodoqueunopuedacopiarsealotro.

Ejercicio5-7.Reescribareadlinesparaalmacenarlíneasenunarregloproporcionadopormain,enlugardellamaraallocparaobtenerespaciodealmacenamiento.¿Cuántomásrápidoeselprograma?□

Page 159: Titivillus 07.07

5.7.Arreglosmultidimensionales

EllenguajeCproporcionaarreglosmultidimensionalesrectangulares,aunqueenlaprácticaseusanmenosquelosarreglosdeapuntadores.Enestasecciónmostraremosalgunasdesuspropiedades.

Considéreseelproblemadelaconversióndefechas,dedíadelmesadíadelañoyviceversa.Porejemplo,el1demarzoesel60°díadeunañoquenoesbisiesto,yel61°díadeunoquesíloes.Definamosdosfuncionesparahacerlaconversión:day_of_yearconviertemesydíaeneldíadelaño,ymonth_dayconvierteeldíadelañoenmesydía.Puestoqueestaúltimafuncióncalculadosvalores,losargumentosdemesydíadebenserapuntadores:

month_day(1988,60,&m,&d)

hacemiguala2ydiguala29(29defebrero).

Ambasfuncionesnecesitanlamismainformación,unatabladelosnúmerosdedíasdecadames(“treintadíastieneseptiembre...”).Puestoqueelnúmerodedíaspormesdifiereparaañosbisiestosynobisiestos,esmásfácilsepararlosendosrenglonesdeunarreglobidimensionalquesigalapistadeloquelepasaafebreroduranteloscálculos.Elarregloylasfuncionesquerealizanlastransformacionessoncomosemuestraacontinuación:

staticchardaytab[2][13]={

{0,31,28,31,30,31,30,31,31,30,31,30,31},

{0,31,29,31,30,31,30,31,31,30,31,30,31},

};

/*day_of_year:obtienedíadelañoapartirdemesyaño*/

intday_of_year(intyear,intmonth,intday)

{

inti,leap;

leap=year%4==0&&year%100!=0||year%400==0;

for(i=1;i<month;i++)

day+=daytab[leap][i];

returnday;

}

/*month_day:obtienemes,ydíaapartirdedíadelaño*/

voidmonth_day(intyear,intyearday,int*pmonth,int*pday)

Page 160: Titivillus 07.07

{

inti,leap;

leap=year%4==0&&year%100!=0||year%400==0;

for(i=1;yearday>daytab[leap][i];i++)

yearday-=daytab[leap][i];

*pmonth=i;

*pday=yearday;

}

Recuérdesequeelvaloraritméticodeunaexpresiónlógica,comoladeleap,escero(falso)ouno(verdadero),asíquepuedeemplearsecomoíndicedelarreglodaytab.

Elarreglodaytabtienequeserexternotantoaday_of_yearcomoamonth_day,paraqueambaspuedanutilizarlo.Lohicimoscharparailustrarunusolegítimodecharparaalmacenarenterospequeñosquenosoncaracteres.

daytabeselprimerarreglodecaracteresdedosdimensionesconelquehemostratado.EnC,unarreglodedosdimensionesesenrealidadunarreglounidimensional,cadaunodecuyoselementosesunarreglo.Porello,lossubíndicesseescribencomo

daytab[i][j]/*[renglón][columna]*/

enlugarde

daytab[i,j]/*INCORRECTO*/

Apartedeestadiferenciadenotación,unarreglodedosdimensionespuedetratarseenformamuysemejantealadelosotroslenguajes.Loselementossealmacenanporrenglones,asíqueelíndicedemásaladerecha,ocolumna,variamásrápidocuandosetieneaccesoaloselementosenordendealmacenamiento.

Unarregloseinicializaconunalistadeinicializadoresentrellaves;cadarenglóndeunarreglodedosdimensionesseinicializaconunasublista.Elarreglodaytabseiniciaconunacolumnadeceros,demodoquelosnúmerosdemespuedanvariarentre1y12enlugarde0a11.Puestoqueelespacionoesapremianteaquí,estoesmásclaroqueajustarlosíndices.

Siunarreglodedosdimensionessepasaaunafunción,ladeclaracióndeparámetrosenlafuncióndebeincluirelnúmerodecolumnas;elnúmeroderenglonesesirrelevante,puestoqueloquesepasaes,comoantes,unapuntadoraunarregloderenglones,dondecadarenglónesunarreglode13ints.Esestecasoparticular,esunapuntadoraobjetosquesonarreglosde13ints.Entonces,sielarreglodaytabsepasaraalafunciónf,ladeclaracióndefsería

f(intdaytab[2][13]){...}

Tambiénpodríaser

f(intdaytab[][13]){...}

Page 161: Titivillus 07.07

porqueelnúmeroderenglonesesirrelevante,opodríaser

f(int(*daytab)[13]){...}

queindicaqueelparámetroesunapuntadoraunarreglode13enteros.Losparéntesissonnecesarios,puestoqueloscorchetes[]tienenmásaltaprecedenciaque*.Sinparéntesis,ladeclaración

int*daytab[13]

esunarreglode13apuntadoresaentero.Demodomásgeneral,sólolaprimeradimensión(subíndice)deunarregloquedaabierta;todaslasotrasdebenespecificarse.

Enlasección5.12sediscutemásacercadedeclaracionescomplicadas.

Ejercicio5-8.Noexistedeteccióndeerroresenday_of_yearnienmonth_day.Solucioneesedefecto.□

Page 162: Titivillus 07.07

5.8.Inicializacióndearreglosdeapuntadores

Considéreseelproblemadeescribirunafunciónmonth_name(n),queregreseunapuntadoraunacadenadecaracteresquecontenganelnombredeln-ésimomes.Estaesunaaplicaciónidealparaunarreglostaticinterno,month_namecontieneunarregloreservadodecadenasdecaracteres,yregresaunapuntadoralacadenaapropiadacuandosellama.Estasecciónmuestracomoseinicializaesearreglodenombres.

Lasintaxisessemejantealadeinicializacionesprevias:

/*month_name:regresaelnombredeln-ésimomes*/

char*month_name(intn)

{

staticchar*name[]={

"Mesilegal",

"Enero","Febrero","Marzo",

"Abril","Mayo","Junio",

"Julio","Agosto","Septiembre",

"Octubre","Noviembre","Diciembre"

};

return(n<1||n>12)?name[0]:name[n];

}

Ladeclaracióndename,queesunarreglodeapuntadoresacaracteres,eslamismaqueladelineptrenelejemplodelordenamiento.Elinicializadoresunalistadecadenasdecaracteres;cadaunaseasignaalaposicióncorrespondientedentrodelarreglo.Loscaracteresdelai-ésimacadenasecolocanenalgúnlugar,yenname[i]sealmacenaunapuntadoraellos.Puestoqueeltamañodelarreglonamenoestáespecificado,elcompiladorcuentalosinicializadoresycompletaelnúmerocorrecto.

Page 163: Titivillus 07.07

5.9.Apuntadoresvs.arreglosmultidimensionales

LosnuevosusuariosdeCalgunasvecesseconfundenconladiferenciaentreunarreglodedosdimensionesyunodeapuntadores,comonameenelejemploanterior.Dadaslasdefiniciones

inta[10][20];

int*b[10];

entoncestantoa[3][4]comob[3][4]sonreferenciassintácticamentelegítimasaunúnicoint.Peroaesverdaderamenteunarreglodedosdimensiones:selehanasignado200localidadesdetamañodeunint,yseempleaelcálculoconvencionaldesubíndicesrectangulares20×renglón+columnaparaencontrarelementoa[renglón,columna].Parab,sinembargo,ladefiniciónsóloasigna10apuntadoresynolosinicializa;lainicializacióndeberealizarseenformaexplícita,yaseaestáticamenteoconcódigo.Suponiendoquecadaelementodebapuntaaunarreglodeveinteelementos,entoncesexistirán200intsreservados,másdiezceldasparalosapuntadores.Laventajaimportantedelarreglodeapuntadoresesquelosrenglonesdelarreglopuedenserdelongitudesdiferentes.Estoes,noesnecesarioquecadaelementodebapunteaunvectordeveinteelementos;algunopuedeapuntaradoselementos,otroacincuentayalgúnotroaninguno.

Aunquehemosbasadoestadiscusiónentérminosdeenteros,elusomásfrecuentedearreglosdeapuntadoresesparaalmacenarcadenasdecaracteresdelongitudesdiversas,comoenlafunciónmonth_name.Compareladeclaraciónylagráficaparaunarreglodeapuntadores:

char*name[]={"Mesilegal","Ene","Feb","Mar"};

conladeunarreglobidimensional:

charaname[][15]={"Mesilegal","Ene","Feb","Mar"};

Ejercicio5-9.Reescribalasrutinasday_of_yearymonth_dayempleandoapuntadores

Page 164: Titivillus 07.07

enlugardeíndices.□

Page 165: Titivillus 07.07

5.10.Argumentosenlalíneadeórdenes

DentrodeunmedioambientequemanejeChayunaformadepasarargumentosenlalíneadeórdenesodeparámetrosaunprogramacuandoempiezasuejecución.Cuandosellamaamainseleinvocacondosargumentos.Elprimero(llamadoporconvenciónargc,porargumentcount)eselnúmerodeargumentosenlalíneadeórdenesconlosqueseinvocóelprograma;elsegundo(argv,porargumentvector)esunapuntadoraunarreglodecadenasdecaracteresquecontienelosargumentos,unoporcadena.Seacostumbrautilizarnivelesmúltiplesdeapuntadoresparamanipularesascadenasdecaracteres.

Elejemplomássencilloeselprogramaecho,quedespliegasusargumentosdelalíneadeórdenesenunalínea,separadosporblancos.Estoes,laorden

echohola,mundo

imprime

hola,mundo

Porconvención,argv[0]eselnombreconelqueseinvocóelprograma,porloqueargcesporlomenos1.Siargces1,entoncesnohayargumentosenlalíneadespuésdelnombredelprograma.Enelejemploanterior,argces3,yargv[0],argv[1]yargv[2]son"echo","hola"y"mundo",respectivamente.Elprimerargumentooptativoesargv[l]yelúltimoesargv[argc-1];además,elestándarrequierequeargv[argc]seaunapuntadornulo.

Laprimeraversióndeechotrataaargvcomounarreglodeapuntadoresacaracteres:

#include<stdio.h>

/*ecodelosargumentosdelalíneadeórdenes;1a.versión*/

main(intargc,char*argv[])

{

inti;

for(i=1;i<argc;i++)

printf("%s%s",argv[i],(i<argv-1)?"":"");

Page 166: Titivillus 07.07

printf("\n");

return0;

}

Comoargvesunapuntadoraunarreglodeapuntadores,sepuedenmanipularalapuntadorenlugardeindexaralarreglo.Estasiguientevariaciónsebasaenincrementarargv,queesunapuntadoraunapuntadorachar,entantosedisminuyeargc:

#include<stdio.h>

/*ecodelosargumentosdelalíneadeórdenes;2a.versión*/

main(intargc,char*argv[])

{

while(--argc>0)

printf("%s%s",*++argv,(argc>1)?"":"");

printf("\n");

return0;

}

Puestoqueargvesunapuntadoraliniciodelarreglodecadenasdeargumentos,incrementarloen1(++argv)lohaceapuntarhaciaargv[l]enlugardeapuntaraargv[0].Cadaincrementosucesivolomuevealsiguienteargumento;entonces*argveselapuntadoraeseargumento.Almismotiempo,argcdisminuye;cuandollegaacero,noquedanargumentosporimprimir.

Enformaalternativa,podemosescribirlaproposiciónprintfcomo

printf((argc>1)?"%s":"%s",*++argv);

Estodemuestraqueelargumentodeformatodelprintftambiénpuedeserunaexpresión.

Comounsegundoejemplo,hagamosalgunasmejorasalprogramadelasección4.1queencuentraunpatrón.Siserecuerda,sefijóelpatróndebúsquedaenloprofundodelprograma,unesquemaqueobviamentenoessatisfactorio.SiguiendolaguíadelprogramagrepdeUNIX,cambiemoselprogramademodoqueelpatrónquesedebeencontrarseespecifiqueporelprimerargumentoenlalíneadeórdenes.

#include<stdio.h>

#include<string.h>

#defineMAXLINE1000

intgetline(char*line,intmax);

Page 167: Titivillus 07.07

/*find:imprimelíneasquecoincidenconelpatróndel1er.argumento*/

main(intargc,char*argv[])

{

charline[MAXLINE];

intfound=0;

if(argc!=2)

printf("Uso:findpatrón\n");

else

while(getline(line,MAXLINE)>0)

if(strstr(line,argv[l]!=NULL){

printf("%s",line);

found++;

}

returnfound;

}

Lafunciónstrstr(s,t)delabibliotecaestándarregresaunapuntadoralaprimeraocurrenciadelacadenatdentrodelacadenas,oNULLsinoexiste.Lacadenaestádeclaradaen<string.h>.

Ahorasepuedeextenderelmodeloparailustrarconstruccionesadicionalesdeapuntadores.Supongaquedeseamospermitirdosargumentosoptativos.Unoindica“imprimetodaslaslíneasexceptoaquellasquecoincidanconelpatrón”;elsegundodice“precedecadalíneaimpresaconsunúmerodelínea”.

UnaconvencióncomúnparaprogramasenCensistemasUNIXesqueunargumentoqueprincipiaconunsignodemenosintroduceunabanderaoparámetrooptativo.Siseleccionamos-x(por“excepto”)paraindicarlainversión,y-n(“número”)parasolicitarlanumeracióndelíneas,entonceslaorden

find-x-npatrón

imprimirácadalíneaquenocoincidaconelpatrón,precedidaporsunúmerodelínea.

Losargumentosparaopcionesdebenserpermitidosencualquierorden,yelrestodelprogramadebeserindependientedelnúmerodeargumentosqueestuvieranpresentes.Además,esconvenienteparalosusuariosquelosargumentosdelasopcionespuedancombinarse,comoen

find-nxpatrón

Aquíestáelprograma:

Page 168: Titivillus 07.07

#include<stdio.h>

#include<string.h>

#defineMAXLINE1000

intgetline(char*line,intmax);

/*find:imprimelíneasquecoincidenconelpatróndel1er.argumento*/

main(intargc,char*argv[])

{

charline[MAXLINE];

longlineno=0;

intc,except=0,number=0,found=0;

while(--argc>0&&(*++argv)[0]=='-')

while(c=*++argv[0])

switch(c){

case'x':

except=1;

break;

case'n':

number=1;

break;

default:

printf("find:opciónilegal%c\n",c);

argc=0;

found=-1;

break;

}

if(argc!=1)

printf("Uso:find-x-npatrón\n");

else

while(getline(line,MAXLINE)>0){

Page 169: Titivillus 07.07

lineno++;

if((strstr(line,*argv)!=NULL)!=except){

if(number)

printf("%ld:",lineno);

printf("%s",line);

found++;

}

}

returnfound;

}

argcsedisminuyeyargvseincrementaantesdecadaargumentoopcional.Alfinaldelciclo,sinohayerrores,argcdicecuántosargumentospermanecensinprocesaryargvapuntaalprimerodeéstos.Así,argcdebeser1y*argvdebeapuntaralpatrón.Nóteseque*++argvesunapuntadoraunargumentotipocadena,asíque(*++argv)[0]essuprimercarácter.(Unaformaalternativaválidasería**++argv.)Debidoaque[]tienemásprioridadque*yque++,losparéntesissonnecesarios;sinellos,laexpresiónseríatomadacomo*++(argv[0]).Enefecto,estoesloqueempleamosenelciclomásinterno,dondelatareaesprocederalolargodeunacadenaespecíficadeargumentos.Enelciclomásinterno,laexpresión*++argv[0]incrementaelapuntadorargv[0].

Esraroqueseempleenexpresionesconapuntadoresmáscomplicadasqueéstas;entalcaso,serámásintuitivosepararlasendosotrespasos.

Ejercicio5-10.Escribaelprogramaexpr,queevalúaunaexpresiónpolacainversadelalíneadeórdenes,dondecadaoperadoruoperandoesunargumentoporseparado.Porejemplo,

expr234+*

seevalúacomo2×(3+4).□

Ejercicio5-11.Modifiqueelprogramaentabydetab(escritoscomoejerciciosenelcapítulo1)paraqueaceptenunalistadepuntosdetabulacióncomoargumentos.Utilicelostabuladoreshabitualessinohayargumentos.□

Ejercicio5-12.Extiendaentabydetabdemodoqueaceptenlaabreviatura

entab-m+n

queindicapuntosdetabulacióncadancolumnas,iniciandoenlacolumnam.Seleccioneelcomportamientoporomisiónmásconveniente(paraelusuario).□

Ejercicio5-13.Escribaelprogramatail,queimprimelasúltimasnlíneasdesuentrada.Poromisión,nes10,digamos,peropuedemodificarseconunargumentooptativo,demodoque

Page 170: Titivillus 07.07

tail-n

imprimelasúltimasnlíneas.Elprogramadebecomportarseenformaracionalsinimportarcuánpocorazonablesealaentradaoelvalorden.Escribaelprogramademaneraquehagaelmejorusodelamemoriadisponible;laslíneasdebenalmacenarsecomoenelprogramadeordenamientodelasección5.6,noenunarreglodedosdimensionesdetamañofijo.□

Page 171: Titivillus 07.07

5.11.Apuntadoresafunciones

EnC,unafunciónporsísolanoesunavariable,peroesposibledefinirapuntadoresafunciones,quepuedenasignarse,sercolocadosenarreglos,pasadosafunciones,regresadosporfuncionesyotrascosasmás.Ilustraremosestomodificandoelprocedimientodeordenamientodescritoanteriormenteenestecapítulo,demodoquesisedaelargumentoopcional-n,ordenarálaslíneasdeentradanuméricamenteenlugardelexicográficamente.

Frecuentementeunordenamientoconsistedetrespartes—unacomparaciónquedeterminaelordendecualquierpardeobjetos,unintercambioqueinviertesuorden,yunalgoritmodeordenamientoquerealizacomparacioneseintercambioshastaquelosobjetosesténenorden.Elalgoritmodeordenamientoesindependientedelasoperacionesdecomparacióneintercambio;así,alpasarlediferentesfuncionesdecomparacióneintercambio,sepuedenobtenerclasificacionescondiferentescriterios.Estaeslatácticaquesesigueennuestronuevométodo.

Lacomparaciónlexicográficadedoslíneasesrealizadaporstrcmp,comoantes;tambiénrequeriremosdeunarutinanumcmpquecompareelvalornuméricodedoslíneasyregreselamismaclasedeindicaciónquehacestrcmp.Estasfuncionessedeclaranantesdemain,yaqsortselepasaunapuntadoralafunciónapropiada.Sehahechounprocesamientodeficientedeloserroresenlosargumentos,conelfindeconcentrarnosenloselementosprincipales.

#include<stdio.h>

#include<string.h>

#defineMAXLINES5000/*máx#delíneasaordenar*/

char*lineptr[MAXLINES];/*apuntadoresalíneasdetexto*/

intreadlines(char*lineptr[],intnlines);

voidwritelines(char*lineptr[],intnlines);

voidqsort(void*lineptr[],intleft,intright,

int(*comp)(void*,void*));

intnumcmp(char*,char*);

/*ordenalíneasdeentrada*/

main(intargc,char*argv[])

{

intnlines;/*númerodelíneasdeentradaleídas*/

intnumeric=0;/*1siesordenamientonumérico*/

if(argc>1&&strcmp(argv[l],"-n")==0)

Page 172: Titivillus 07.07

numeric=1;

if((nlines=readlines(lineptr,MAXLINES))>=0){

qsort((void**)lineptr,0,nlines-1,

(int(*)(void*,void*))(numeric?numcmp:strcmp));

writelines(lineptr,nlines);

return0;

}else{

printf("entradademasiadograndeparaserordenada\n");

return1;

}

}

Enlallamadaaqsort,strcmpynumcmpsondireccionesdefunciones.Comosesabequesonfunciones,eloperador&noesnecesario,enlamismaformaquenoesnecesarioantesdelnombredeunarreglo.

Hemosescritoqsortdemodoquepuedaprocesarcualquiertipodedato,nosólocadenasdecaracteres.Comoseindicaporlafunciónprototipo,qsortesperaunarreglodeapuntadores,dosenterosyunafuncióncondosargumentosdetipoapuntador.Paralosargumentosapuntadoresseempleaeltipodeapuntadorgenéricovoid*.Cualquierapuntadorpuedeserforzadoaservoid*yregresadodenuevosinpérdidadeinformación,demodoquepodemosllamaraqsortforzandolosargumentosavoid*.Elelaboradocastdelargumentodelafunciónfuerzalosargumentosdelafuncióndecomparación.Estogeneralmentenotendráefectosobrelarepresentaciónreal,peroaseguraalcompiladorquetodoestébien.

/*qsort:clasificav[left]...v[right]enordenascendente*/

voidqsort(void*v[],intleft,intright,

int(*comp)(void*,void*))

{

inti,last;

voidswap(void*v[],int,int);

if(left>=right)/*nohacenadasielarreglocontienemenosdedoselementos*/

return;

swap(v,left,(left+right)/2);

last=left;

Page 173: Titivillus 07.07

for(i=left+1;i<=right;i++)

if((*comp)(v[i],v[left])<0)

swap(v,++last,i);

swap(v,left,last);

qsort(v,left,last-1,comp);

qsort(v,last+1,right,comp);

}

Lasdeclaracionesdebenestudiarseconcuidado.Elcuartoparámetrodeqsortes

int(*comp)(void*,void*)

queindicaquecompesunapuntadoraunafunciónquetienedosargumentosvoid*yregresaunint.

Elusodecompenlalínea

if((*comp)(v[i],v[left]<0)

esconsistenteconladeclaración:compesunapuntadoraunafunción,*compeslafunción,y

(*comp)(v[i],v[left])

eslallamadaaella.Losparéntesissonnecesariosparaqueloscomponentesseancorrectamenteasociados;sinellos,

int*comp(void*,void*)/*INCORRECTO*/

indicaquecompesunafunciónqueregresaunapuntadoraint,locualesmuydiferente.

Yahemosmostradostrcmp,quecomparadoscadenas.Aquíestánumcmp,quecomparadoscadenasnuméricamente,valorquesecalculallamandoaatof:

#include<stdlib.h>

/*numcmp:comparas1ys2numéricamente*/

intnumcmp(char*s1,char*s2)

{

doublev1,v2;

v1=atof(s1);

v2=atof(s2);

if(v1<v2)

Page 174: Titivillus 07.07

return-1;

elseif(v1>v2)

return1;

else

return0;

}

Lafunciónswap,queintercambiadosapuntadores,esidénticaalaquepresentamosanteriormenteenestecapítulo,exceptoenquelasdeclaracionessehancambiadoavoid*.

voidswap(void*v[],inti,intj)

{

void*temp;

temp=v[i];

v[i]=v[j];

v[j]=temp;

}

Puedeagregarseunavariedaddeotrasopcionesalprogramadeordenamiento;algunasseconviertenenejerciciosinteresantes.

Ejercicio5-14.Modifiqueelprogramadeordenamientodemodoquemanejeunabandera-r,queindicaordenarenordeninverso(descendente).Asegúreseque-r,trabajacon-n.□

Ejercicio5-15.Agreguelaopción-fparaigualarlasletrasmayúsculasyminúsculas,demodoquenosehagadistinciónentreellasduranteelordenamiento;porejemplo,alcomparar,ayAsoniguales.□

Ejercicio5-16.Agreguelaopción-d(“ordendedirectorio”),quecomparasóloletras,númerosyblancos.Asegúresedequetrabajaenconjuncióncon-f.□

Ejercicio5-17.Agreguecapacidaddemanejodecampos,paraqueelordenamientosehagasobrecamposdelaslíneas,cadacampoordenadodeacuerdoconunconjuntoindependientedeopciones.(Elíndicedeestelibrofueordenadocon-dfparalasentradasy-nparalosnúmerosdepágina.)□

Page 175: Titivillus 07.07

5.12.Declaracionescomplicadas

AllenguajeCselerepruebaalgunasvecesporlasintaxisdesusdeclaraciones,particularmentelasqueinvolucranapuntadoresafunciones.Enlasintaxishayunintentodehacerquecoincidanlasdeclaracionesconsuuso;trabajabienparacasossimples,peropuedeserconfusaparalosdifíciles,debidoaquelasdeclaracionesnopuedenleersedeizquierdaaderecha,ydebidoalexcesodeusodeparéntesis.Ladiferenciaentre

int*f();/*f:funciónqueregresaunapuntadoraint*/

y

int(*pf)();/*pf:apuntadoraunafunciónqueregresaunint*/

ilustraelproblema:*esunoperadorprefijoytienemenorprecedenciaque(),demodoquelosparéntesissonnecesariosparaobligaraunaasociaciónapropiada.

Aunqueenlaprácticaesextrañoqueaparezcandeclaracionesverdaderamentecomplicadas,esimportantesabercómoentenderlasy,siesnecesario,cómocrearlas.Unabuenaformadesintetizardeclaracionesesenpequeñospasoscontypedef,quesediscuteenlasección6.7.Comounaalternativa,enestasecciónpresentaremosunpardeprogramasqueconviertendeCválidoaunadescripciónverbalyviceversa.Ladescripciónverbalseleedeizquierdaaderecha.

Laprimera,dcl,eslamáscompleja.ConvierteunadeclaracióndeCenunadescripciónhechaconpalabras,comoenestosejemplos:

char**argv

argv:apuntadoraunapuntadorachar

int(*daytab)[13]

daytab:apuntadoraunarreglo[13]deint

int*daytab[13]

daytab:arreglo[13]deapuntadoresaint

void*comp()

comp:funciónqueregresaapuntadoravoid

void(*comp)()

comp:apuntadoraunafunciónqueregresavoid

char(*(*x())[])()

x:funciónqueregresaunapuntadoraunarreglo[]deapuntadoresaunafunciónqueregresachar

Page 176: Titivillus 07.07

char(*(*x[3])())[5]

x:arreglo[3]deapuntadoresaunafunciónqueregresaunapuntadoraunarreglo[5]dechar

dclestábasadaenlagramáticaqueespecificaundeclarador,quesedefineenformaprecisaenelapéndiceA,sección8.5;éstaesunaformasimplificada:

dcl:

*soptativosdcl-directa

dcl-directa:

nombre

(dcl)

dcl-directo()

dcl-directa[tamañooptativo]

Conpalabras,unadclesunadcl-directa,talvezprecedidopor*s.Unadcl-directaesunnombre,ounadclentreparéntesis,ounadcl-directaseguidaporparéntesis,ounadcl-directaseguidaporcorchetesconuntamañooptativo.

Estagramáticapuedeemplearseparareconocerdeclaraciones.Porejemplo,considereestedeclarador:

(*pfa[])()

pfaseidentificarácomounnombreyporendecomounadcl-directa.Entoncespfa[]estambiénunadcl-directa.Luego*pfa[]sereconocecomounadcl,demodoque(*pfa[])esunadcl-directa.Entonces(*pfa[])()esunadcl-directayportantounadcl.Tambiénpodemosilustrarelanálisisconunárboldeestructuragramaticalcomoéste(endondedcl-directasehaabreviadocomodcl-dir):

Page 177: Titivillus 07.07

Elcorazóndelprogramadclesunpardefunciones,dclydirdcl,quedescribenunadeclaracióndeacuerdoconestagramática.Debidoaquelagramáticaestádefinidarecursivamente,lasfuncionessellamanrecursivamenteunaalaotra,mientrasreconocenpiezasdeunadeclaración;elprogramaseconocecomoanalizadorsintácticopordescensorecursivo.

/*dcl:reconoceunadeclaración*/

voiddcl(void)

{

intns;

for(ns=0;gettoken()=='*';)/*cuenta*s*/

ns++;

dirdcl();

while(ns-->0)

strcat(out,"apuntadora");

}

/*dirdcl:reconoceundeclaradordirecto*/

voiddirdcl(void)

{

inttype;

Page 178: Titivillus 07.07

if(tokentype=='('){/*(dcl)*/

dcl();

if(tokentype!=')')

printf("error:falta)\n");

}elseif(tokentype==NAME)/*nombredevariable*/

strcpy(name,token);

else

printf("error:nombreo(dcl)esperado\n");

while((type=gettoken())==PARENS||type==BRACKETS)

if(type==PARENS)

strcat(out,"funciónqueregresa");

else{

strcat(out,"arreglo");

strcat(out,token);

strcat(out,"de");

}

}

Puestoqueseintentaqueelprogramaseailustrativo,noapruebadebalas,hayrestriccionessobredcl,quesólopuedemanejaruntiposimplededatoscomocharoint.Nomanejatiposdeargumentosdentrodefunciones,ocalificadorescomoconst.Losespaciosenblancoinadecuadosloconfunden.Noserecuperamuchoanteloserrores,demodoquelasdeclaracionesinválidastambiénloconfunden.Esasmejorassedejancomoejercicios.

Aquíestánlasvariablesglobalesylarutinaprincipal:

#include<stdio.h>

#include<string.h>

#include<ctype.h>

#defineMAXTOKEN100

enum{NAME,PARENS,BRACKETS};

voiddcl(void);

voiddirdcl(void);

Page 179: Titivillus 07.07

intgettoken(void);

inttokentype;/*tipodelúltimotoken*/

chartoken[MAXTOKEN];/*cadenadelúltimotoken*/

charname[MAXTOKEN];/*nombredelidentificador*/

chardatatype[MAXTOKEN];/*tipodedato=char,int,etc.*/

charout[1000];/*cadenadesalida*/

main()/*convierteunadeclaraciónapalabras*/

{

while(gettoken()!=EOF){/*1er.tokenenlalínea*/

strcpy(datatype,token);/*eseltipodedato*/

out[0]='\0';

dcl();/*reconoceelrestodelalínea*/

if(tokentype!='\n')

printf("errordesintaxis\n");

printf("%s:%s%s\n",name,out,datatype);

}

return0;

}

Lafuncióngettokenignorablancosytabuladoras,yencuentraelsiguientetokendelaentrada;un“token”esunnombre,unpardeparéntesis,unpardecorchetesquetalvezincluyenunnúmero,ocualquierotrocaráctersimple.

intgettoken(void)/*regresaelsiguientetoken*/

{

intc,getch(void);

voidungetch(int);

char*p=token;

while((c=getch())==''||c=='\t')

;

if(c=='('){

Page 180: Titivillus 07.07

if((c=getch())==')'){

strcpy(token,"()");

returntokentype=PARENS;

}else{

ungetch(c);

returntokentype='(';

}

}elseif(c=='['){

for(*p++=c;(*p++=getch())!=']';)

;

*p='\0';

returntokentype=BRACKETS;

}elseif(isalpha(c)){

for(*p++=c;isalnum(c=getch());)

*p++=c;

*p='\0';

ungetch(c);

returntokentype=NAME;

}else

returntokentype=c;

}

getchyungetchsediscutieronenelcapítulo4.

Esmásfácilirenladireccióninversa,especialmentesinonospreocupamosporlageneracióndeparéntesisredundantes.Elprogramaundclconvierteunadescripciónverbalcomo“xesunafunciónqueregresaunapuntadoraunarreglodeapuntadoresafuncionesqueregresanchar”,queseexpresarácomo

x()*[]*()char

yseconvertiráen

char(*(*x())[])()

Lasintaxisabreviadadelaentradanospermitereutilizaralafuncióngettoken.La

Page 181: Titivillus 07.07

funciónundcltambiénemplealasmismasvariablesexternasquedcl.

/*undcl:convierteunadescripciónverbaladeclaración*/

main()

{

inttype;

chartemp[MAXTOKEN];

while(gettoken()!=EOF){

strcpy(out,token);

while((type=gettoken())!='\n')

if(type==PARENS||type==BRACKETS)

strcat(out,token);

elseif(type=='*'){

sprintf(temp,"(*%s)",out);

strcpy(out,temp);

}elseif(type==NAME){

sprintf(temp,”%s%s",token,out);

strcpy(out,temp);

}else

printf"entradainválidaen%s\n",token);

printf("%s\n",out);

}

return0;

}

Ejercicio5-18.Hagaquedclserecuperedeerroresenlaentrada.□

Ejercicio5-19.Modifiqueundcldemodoquenoagregueparéntesisredundantesalasdeclaraciones.□

Ejercicio5-20.Extiendedclparaquemanejedeclaracionescontiposdeargumentosdefunciones,calificadorescomoconst,etcétera.□

Page 182: Titivillus 07.07

CAPÍTULO6:Estructuras

Unaestructuraesunacoleccióndeunaomásvariables,detiposposiblementediferentes,agrupadasbajounsolonombreparamanejoconveniente.(Lasestructurasseconocencomo“records”enalgunosotroslenguajes,principalmentePascal.)Lasestructurasayudanaorganizardatoscomplicados,enparticulardentrodeprogramasgrandes,debidoaquepermitenqueaungrupodevariablesrelacionadasselestratecomounaunidadenlugardecomoentidadesseparadas.

Unejemplotradicionaldeestructuraeselregistrodeunanómina:unempleadoestádescritoporunconjuntodeatributos,comonombre,domicilio,númerodelsegurosocial,salario,etc.Algunosdeestosatributospueden,asuvez,serestructuras:unnombretienevarioscomponentes,comolostieneundomicilioyaúnunsalario.Otroejemplo,mástípicoparaC,procededelasgráficas:unpuntoesunpardecoordenadas,unrectánguloesunpardepuntos,yotroscasossemejantes.

ElprincipalcambiorealizadoporelestándarANSIesladefinicióndelaasignacióndeestructuras—lasestructurassepuedencopiaryasignar,pasarafuncionesyserregresadasporfunciones.Estohasidomanejadopormuchoscompiladoresdurantevariosaños,perolaspropiedadesestánahoradefinidasenformaprecisa.Lasestructurasylosarreglosautomáticosahoratambiénsepuedeninicializar.

Page 183: Titivillus 07.07

6.1.Conceptosbásicossobreestructuras

Definamosalgunasestructuraspropiasparagraficación.Elobjetobásicoesunpunto,delcualsupondremosquetieneunacoordenadaxyunacoordenaday,ambasenteras.

Losdoscomponentespuedensercolocadosenunaestructuradeclaradaasí:

structpoint{

intx;

inty;

};

Lapalabrareservadastructpresentaladeclaracióndeunaestructura,queesunalistadedeclaracionesentrellaves.Unnombreoptativo,llamadorótulodeestructura,puedeseguiralapalabrastruct(comoaquílohacepoint).Elrótulodanombreaestaclasedeestructura,yenadelantepuedeserutilizadocomounaabreviaturaparalapartededeclaracionesentrellaves.

Lasvariablesnombradasdentrodelaestructurasellamanmiembros.Unmiembrodeestructuraorótulo,yunavariableordinaria(estoes,nomiembro)puedentenerelmismonombresinconflicto,puestoquesiempresepuedendistinguirporelcontexto.Además,endiferentesestructuraspuedenencontrarselosmismosnombresdemiembros,aunqueporcuestionesdeestilosedeberíandeusarlosmismosnombressóloparaobjetosestrechamenterelacionados.

Unadeclaraciónstructdefineuntipo.Lallavederechaqueterminalalistademiembrospuedeserseguidaporunalistadevariables,comosehaceparacualquiertipobásico.Estoes,

struct{...}x,y,z;

essintácticamenteanálogoa

intx,y,z;

enelsentidodequecadaproposicióndeclaraax,yyzcomovariablesdeltiponombradoycausaqueselesreserveespaciocontiguo.

Page 184: Titivillus 07.07

Unadeclaracióndeestructuraquenoestáseguidaporunalistadevariablesnoreservaespaciodealmacenamientosinoquesimplementedescribeunaplantillaolaformadeunaestructura.Sinembargo,siladeclaraciónestárotulada,elrótulosepuedeemplearposteriormenteendefinicionesdeinstanciasdelaestructura.Porejemplo,dadaladeclaraciónanteriordepoint,

structpointpt;

defineunavariableptqueesunaestructuradetipostructpoint.Unaestructurasepuedeinicializaralseguirsudefiniciónconunalistadeinicializadores,cadaunounaexpresiónconstante,paralosmiembros:

structpointmaxpt={320,200};

Unaestructuraautomáticatambiénsepuedeinicializarporasignaciónollamandoaunafunciónqueregresaunaestructuradeltipoadecuado.

Sehacereferenciaaunmiembrodeunaestructuraenparticularenunaexpresiónconunaconstruccióndelaforma

nombre-estructura,miembro

Eloperadormiembrodeestructura“.”conectaalnombredelaestructuraconelnombredelmiembro.Porejemplo,paraimprimirlascoordenadasdelpuntopt,

printf("%d,%d",pt.x,pt.y);

oparacalcularladistanciadelorigen(0,0)apt,

doubledist,sqrt(double);

dist=sqrt((double)pt.x*pt.x+(double)pt.y*pt.y);

Lasestructuraspuedenanidarse.Unarepresentacióndeunrectánguloescomounpardepuntosquedenotanlasesquinasdiagonalmenteopuestas:

structrect{

structpointpt1;

structpointpt2;

};

Laestructurarectcontienedosestructuraspoint.Sideclaramosscreencomo

Page 185: Titivillus 07.07

structrectscreen;

entonces

screen.pt1.x

serefierealacoordenadaxdelmiembropt1descreen.

Page 186: Titivillus 07.07

6.2.Estructurasyfunciones

Lasúnicasoperacioneslegalessobreunaestructurasoncopiarlaoasignarlacomounidad,tomarsudireccióncon&,yteneraccesoasusmiembros.Lacopiaylaasignaciónincluyenpasarlascomoargumentosafuncionesytambiénregresarvaloresdefunciones.Lasestructurasnosepuedencomparar.Unaestructurasepuedeinicializarconunalistadevaloresconstantesdemiembros;unaestructuraautomáticatambiénsepuedeinicializarconunaasignación.

Investiguemoslasestructurasescribiendoalgunasfuncionesparamanipularpuntosyrectángulos.Hayporlomenostresacercamientosposibles:pasarseparadamenteloscomponentes,pasarunaestructuracompletaopasarunapuntadoraella.Cadaunotienesuspuntosbuenosymalos.

Laprimerafunción,makepoint,tomadosenterosyregresaunaestructurapoint:

/*makepoint:creaunpuntoconlascomponentesx,y*/

structpointmakepoint(intx,inty)

{

structpointtemp;

temp.x=x;

temp.y=y;

returntemp;

}

Nótesequenohayconflictoentreelnombredelargumentoyelmiembroconelmismonombre;inclusolareutilizacióndelosnombresrefuerzaelvínculo.

makepointahorasepuedeusarparainicializardinámicamentecualquierestructura,oparaproporcionarlosargumentosdelaestructuraaunafunción:

structrectscreen;

structpointmiddle;

structpointmakepoint(int,int);

screen.pt1=makepoint(0,0);

screen.pt2=makepoint(XMAX,YMAX);

middle=makepoint((screen.pt1.x+screen.pt2.x)/2,

(screen.pt1.y+screen.pt2.y)/2);

Elsiguientepasoesunconjuntodefuncionesparahaceroperacionesaritméticassobre

Page 187: Titivillus 07.07

lospuntos.Porejemplo,

/*addpoint:sumadospuntos*/

structpointaddpoint(structpointp1,structpointp2)

{

p1.x+=p2.x;

p1.y+=p2.y;

returnp1;

}

Aquí,tantolosargumentoscomoelvalorderetornosonestructuras.Incrementamosloscomponentesenp1enlugardeutilizarexplícitamenteunavariabletemporalparahacerénfasisenquelosparámetrosdelaestructurasonpasadosporvalorcomocualesquieraotros.

Comootroejemplo,lafunciónptinrectpruebasiunpuntoestádentrodeunrectángulo,dondehemosadoptadolaconvencióndequeunrectánguloincluyesusladosizquierdoeinferiorperonosusladossuperioryderecho:

/*ptinrect:regresa1sipestáenr,0sinoloestá*/

intptinrect(structpointp,structrectr)

{

returnp.x>=r.pt1.x&&p.x<=r.pt2.x

&&p.y>=r.pt1.y&&p.y<=r.pt2.y;

}

Estosuponequeelrectánguloestárepresentadoenunaformaestándarendondelascoordenadaspt1sonmenoresquelascoordenadaspt2.Lasiguientefunciónregresaunrectángulo,garantizandoqueestáenformacanónica:

#definemin(a,b)((a)<(b)?(a):(b))

#definemax(a,b)((a)>(b)?(a):(b))

/*canonrect:poneenformacanónicalascoordenadasdeunrectángulo*/

structrectcanonrect(structrectr)

{

structrecttemp;

temp.pt1.x=min(r.pt1.x,r.pt2.x);

temp.pt1.y=min(r.pt1.y,r.pt2.y);

Page 188: Titivillus 07.07

temp.pt2.x=max(r.pt1.x,r.pt2.x);

temp.pt2.y=max(r.pt1.y,r.pt2.y);

returntemp;

}

Siunaestructuragrandevaaserpasadaaunafunción,generalmenteesmáseficientepasarunapuntadorquecopiarlaestructuracompleta.Losapuntadoresaestructurassoncomolosapuntadoresavariablesordinarias.Ladeclaración

structpoint*pp;

dicequeppesunapuntadoraunaestructuradetipostructpoint.Sippapuntaaunaestructurapoint,*ppeslaestructura,y(*pp).xy(*pp).ysonlosmiembros.Paraemplearpp,sepodríaescribir,porejemplo,

structpointorigin,*pp;

pp=&origin;

printf("elorigenes(%d,%d)\n",(*pp).x,(*pp).y;

Losparéntesissonnecesariosen(*pp).xdebidoaquelaprecedenciadeloperadormiembrodeestructura.esmayorquelade*.Laexpresión*pp.xsignifica*(pp.x),locualesilegaldebidoaquexnoesunapuntador.

Losapuntadoresaestructurasseusancontantafrecuenciaquesehaproporcionadounanotaciónalternativacomoabreviación.Sipesunapuntadoraestructura,entonces

p->miembrodeestructura

serefierealmiembroenparticular.(Eloperador->esunsignomenosseguidoinmediatamentepor>.)Deestamanerapodríamoshaberescrito

printf("elorigenes(%d,%d)\n",pp->x,pp->y);

Tanto.como->seasociandeizquierdaaderecha,demodoquesitenemos

structrectr,*rp=r;

entoncesestascuatroexpresionessonequivalentes:

r.pt1.x

rp->pt1.x

(r.pt1).x

(rp->pt1).x

Losoperadoresdeestructuras.y->,juntocon()parallamadasafuncionesy[]parasubíndices,estánhastaarribadelajerarquíadeprecedenciasyseasocianestrechamente.Porejemplo,dadaladeclaración

struct{

Page 189: Titivillus 07.07

intlen;

char*str;

}*p;

entonces

++p->len

incrementaalen,noap,puestoquelosparéntesisimplícitosson++(p->len).Losparéntesissepuedenemplearparaalterarlaasociación:(++p)->lenincrementaapantesdeteneraccesoalen,y(++p)->lenincrementaapdespuésdelacceso.(Esteúltimoconjuntodeparéntesisesinnecesario.)

Delamismamanera,*p->strobtienecualquiercosaalaquestrapunte;*p->str++incrementaastrdespuésdehacerelaccesoaloqueapunta(exactamentecomo*s++);(*p->str)++incrementacualquiercosaalaquestrapunte;y*p++->strincrementaapdespuésdehacerelaccesoaloquestrapunta.

Page 190: Titivillus 07.07

6.3.Arreglosdeestructuras

ConsidéreseescribirunprogramaparacontarlasocurrenciasdecadapalabrareservadadeC.Serequieredeunarreglodecadenasdecaracteresparamantenerlosnombres,yunarreglodeenterosparalascuentas.Unaposibilidadesusardosarreglosparalelos,keywordykeycount,comoen

char*keyword[NKEYS];

intkeycount[NKEYS];

Peroelhechodequelosarreglosseanparalelossugiereunaorganizacióndiferente,unarreglodeestructuras.Cadaentradadeunapalabraesunapareja:

char*word;

intcount;

yhayunarreglodeparejas.Ladeclaracióndeestructura

structkey{

char*word;

intcount;

}keytab[NKEYS];

declarauntipodeestructurakey,defineunarreglokeytabdeestructurasdeesetipo,yreservaespaciodealmacenamientoparaellas.Cadaelementodelarregloesunaestructura.Estotambiénsepodríaescribircomo

structkey{

char*word;

intcount;

};

structkeykeytab[NKEYS];

Comolaestructurakeytabcontieneunconjuntoconstantedenombres,esmásfácilconvertirlaenunavariableexternaeinicializarladeunavezcuandosedefine.Lainicializacióndelaestructuraesanálogaaotrasanteriores—ladefiniciónesseguidaporunalistadeinicializadoresentrellaves:

structkey{

char*word;

intcount;

Page 191: Titivillus 07.07

}keytab[]={

"auto",0,

"break",0,

"case",0,

"char",0,

"const",0,

"continue",0,

"default",0,

/*...*/

"unsigned",0,

"void",0,

"volatile",0,

"while",0

}

Losinicializadoresselistanenparejascorrespondientesalosmiembrosdelasestructuras.Podríasermásprecisoencerrarlosinicializadoresparacada“renglón”oestructuraentrellaves,comoen

{“auto",0},

{"break",0},

{"case",0},

...

perolasllavesinternasnosonnecesariascuandolosinicializadoressonvariablessimplesocadenasdecaracteres,ycuandotodosestánpresentes.Comoesusual,elnúmerodeentradasenelarreglokeytabsecalcularásilosinicializadoresestánpresentesyel[]sedejavacío.

Elprogramaquecuentapalabrasreservadasprincipiaconladefinicióndekeytab.Larutinaprincipalleedelaentradaconllamadasrepetidasalafuncióngetword,quetraeunapalabraalavez.Cadapalabraseconsultaenkeytabconunaversióndelafuncióndebúsquedabinariaqueseescribióenelcapítulo3.Lalistadepalabrasreservadasdebeestarordenadaenformaascendenteenlatabla.

#include<stdio.h>

#include<ctype.h>

#include<string.h>

Page 192: Titivillus 07.07

#defineMAXWORD100

intgetword(char*,int);

intbinsearch(char*,structkey*,int);

/*cuentapalabrasreservadasdeC*/

main()

{

intn;

charword[MAXWORD];

while(getword(word,MAXWORD)!=EOF)

if(isalpha(word[0]))

if((n=binsearch(word,keytab,NKEYS))>=0)

keytab[n].count++;

for(n=0;n<NKEYS;n++)

if(keytab[n].count>0)

printf("%4d%s\n",

keytab[n].count,keytab[n].word);

return0;

}

/*binsearch:encuentraunapalabraentab[0]...tab[n-1]*/

intbinsearch(char*word,structkeytab[],intn)

{

intcond;

intlow,high,mid;

low=0;

high=n-1;

while(low<=high){

mid=(low+high)/2;

if((cond=strcmp(word,tab[mid].word))<0)

high=mid-1;

Page 193: Titivillus 07.07

elseif(cond>0)

low=mid+1;

else

returnmid;

}

return-1;

}

Mostraremoslafuncióngetwordenunmomento;porahoraessuficientedecirquecadallamadaagetwordencuentraunapalabra,quesecopiadentrodelarregloreferidocomosuprimerargumento.

LacantidadNKEYSeselnúmerodepalabrasenkeytab.Aunquelaspodríamoscontarmanualmente,esmuchomásfácilyseguroquelohagalamáquina,especialmentesilalistaestásujetaacambios.Unaposibilidadseríaterminarlalistadeinicializadoresconunapuntadornuloyluegohaceruncicloalolargodekeytabhastaqueseencuentraelfin.

Peroestoesmásdeloqueserequiere,puestoqueeltamañodelarregloestádeterminadocompletamentealtiempodecompilación.Eltamañodelarregloeseltamañodeunaentradamultiplicadoporelnúmerodeentradas,asíqueelnúmerodeentradases

sizeofkeytab/sizeofstructkey

CProporcionaunoperadorunarioatiempodecompilaciónllamadosizeofquesepuedeemplearparacalculareltamañodecualquierobjeto.Lasexpresiones

sizeofobjeto

y

sizeof(nombredetipo)

danunenteroigualaltamañoenbytesdeltipouobjetoespecificado.(Estrictamente,sizeofproduceunvalorenterosinsignocuyotipo,size_t,estádefinidoenelheader<stddef.h>.)Unobjetopuedeserunavariable,arreglooestructura.Unnombredetipopuedeserelnombredeuntipobásicocomointodoubleountipoderivadocomounaestructuraounapuntador.

Ennuestrocaso,elnúmerodepalabraseseltamañodelarreglodivididoentreeltamañodeunelemento.Estecálculoseutilizaenunaproposición#defineparafijarelvalordeNKEYS:

#defineNKEYS(sizeofkeytab/sizeof(structkey))

Otraformadeescribirestoesdividireltamañodelarregloentreeltamañodeunelementoespecífico:

#defineNKEYS(sizeofkeytab/sizeofkeytab[0])

Page 194: Titivillus 07.07

Estotienelaventajadequenonecesitasermodificadosieltipocambia.

Unsizeofnosepuedeutilizarenunalínea#if,debidoaqueelpreprocesadornoanalizanombresdetipos.Perolaexpresióndel#definenoesevaluadaporelpreprocesador,yaquíelcódigoeslegal.

Ahoralafuncióngetword.Hemosescritounafuncióngetwordmásgeneraldeloqueserequiereparaesteprograma,peronoescomplicada,getwordobtienelasiguiente“palabra”delaentrada,dondeunapalabraescualquiercadenadeletrasydígitosqueprincipiaconunaletra,ounsolocarácterquenoseaespacioenblanco.Elvalordelafuncióneselprimercarácterdelapalabra,oEOFparafindearchivo,oelcarácterensímismocuandonoesalfabético.

/*getword:obtienelasiguientepalabraocarácterdelaentrada*/

intgetword(char*word,intlim)

{

intc,getch(void);

voidungetch(int);

char*w=word;

while(isspace(c=getch()))

:

if(c!=EOF)

*w++=c;

if(!isalpha(c)){

*w='\0';

returnc;

}

for(;--lim>0;w++)

if(!isalnum(*w=getch())){

ungetch(*w);

break;

}

*w='\0';

returnword[0];

}

Page 195: Titivillus 07.07

getwordutilizagetchyungetch,queseescribieronenelcapítulo4.Cuandolarecoleccióndeunsímboloalfanuméricosedetiene,getwordsehacolocadouncarácteradelante.Lallamadaaungetchregresaelcarácteralaentradaparalasiguientellamada,getwordtambiénusaisspaceparaignorarespaciosenblanco,isalphaparaidentificarletras,eisalnumparaidentificarletrasydígitos;todasprovienendelheaderestándar<ctype.h>.

Ejercicio6-1.Nuestraversióndegetwordnomanejaadecuadamentelassubrayas,cadenasconstantes,comentariosolíneasdecontrolparaelpreprocesador.Escribaunaversiónmejorada.□

Page 196: Titivillus 07.07

6.4.Apuntadoresaestructuras

Parailustraralgunasdelasconsideracionesinvolucradasconapuntadoresyarreglosdeestructuras,escribamosdenuevoelprogramadeconteodepalabrasreservadas,estavezutilizandoapuntadoresenlugardesubíndices.

Ladeclaraciónexternadekeytabnorequieredecambios,peromainybinsearchsínecesitanmodificaciones.

#include<stdio.h>

#include<ctype.h>

#include<string.h>

#defineMAXWORD100

intgetword(char*,int);

structkey*binsearch(char*,structkey*,int);

/*cuentapalabrasreservadasdeC;versiónconapuntadores*/

main()

{

charword[MAXWORD];

structkey*p;

while(getword(word,MAXWORD)!=EOF)

if(isalpha(word[0]))

if((p=binsearch(word,keytab,NKEYS))!=NULL)

p->count++;

for(p=keytab;p<keytab+NKEYS;p++)

if(p->count>0)

printf(“%4d%s\n",p->count,p->word);

return0;

}

/*binsearch:encuentraunapalabraentab[0]...tab[n-1]*/

structkey*binsearch(char*word,structkey*tab,intn)

Page 197: Titivillus 07.07

{

intcond;

structkey*low=&tab[0];

structkey*high=&tab[n];

structkey*mid;

while(low<high){

mid=low+(high-low)/2;

if((cond=strcmp(word,mid->word))<0)

high=mid;

elseif(cond>0)

low=mid+1;

else

returnmid;

}

returnNULL;

}

Aquíhayvariascosasqueameritannota.Primero,ladeclaracióndebinsearchdebeindicarqueregresaunapuntadorastructkeyenlugardeunentero;estosedeclaratantoenelprototipodelafuncióncomoenbinsearch.Sibinsearchencuentralapalabra,regresaunapuntadoraella;sino,regresaNULL.

Segundo,ahorasetieneaccesoaloselementosdekeytabpormediodeapuntadores.Estorequieredecambiossignificativosenbinsearch.

Losinicializadoresparalowyhighsonahoraapuntadoresalinicioyjustodespuésdelfinaldelatabla.

Elcálculodelelementointermedioyanopuedesersimplemente

mid=(low+high)/2/*INCORRECTO*/

puestoquelasumadedosapuntadoresesilegal.Sinembargo,larestaeslegítima,porloquehigh-loweselnúmerodeelementos,yasí

mid=low+(high-low)/2

hacequemidapuntealelementoqueestáalamitadentrelowyhigh.

Elcambiomásimportanteesajustarelalgoritmoparaestarsegurosdequenogeneraunapuntadorilegalointentahaceraccesoaunelementofueradelarreglo.Elproblema

Page 198: Titivillus 07.07

esque&tab[-1]y&tab[n]estánambasfueradeloslímitesdelarreglotab.Laprimeraesestrictamenteilegal,yesilegaldesreferenciarlasegunda.Sinembargo,ladefinicióndellenguajegarantizaquelaaritméticadeapuntadoresqueinvolucraelprimerelementodespuésdelfindeunarreglo(estoes,&tab[n])trabajarácorrectamente.

Enmainescribimos

for(p=keytab;p<keytab+NKEYS;p++)

Sipesunapuntadoraunaestructura,laaritméticaconptomaencuentaeltamañodelaestructura,asíquep++incrementapconlacantidadcorrectaparaobtenerelsiguienteelementodelarreglodeestructuras,ylapruebadetieneelcicloenelmomentocorrecto.

Sinembargo,nohayquesuponerqueeltamañodeunaestructuraeslasumadelostamañosdesusmiembros.Debidoarequisitosdealineaciónparadiferentesobjetos,podríahaber“huecos”noidentificadosdentrodeunaestructura.Asíporejemplo,siuncharesdeunbyteyunintdecuatrobytes,laestructura

struct{

charc;

inti;

};

bienpodríarequerirochobytes,nocinco.Eloperadorsizeofregresaelvalorapropiado.

Finalmente,uncomentarioacercadelformatodelprograma:cuandounafunciónregresauntipocomplicadocomounapuntadoraestructura,comoen

structkey*binsearch(char*word,structkey*tab,intn)

elnombredelafunciónpuedeserdifícildeleerydeencontrarconuneditordetexto.Poreso,algunasvecesseempleaunestiloalternativo:

structkey*

binsearch(char*word,structkey*tab,intn)

Estoesalgodegustopersonal;seleccionelaformaqueprefieraymanténgala.

Page 199: Titivillus 07.07

6.5.Estructurasautorreferenciadas

Supóngasequedeseamosmanejarelproblemamásgeneraldecontarlasocurrenciasdetodaslaspalabrasenalgunaentrada.Comolalistadepalabrasnoseconoceporanticipado,nopodemosordenarlasconvenientementeyutilizarunabúsquedabinaria.Nopodemoshacerunabúsquedalinealparacadapalabraquellega,paraversiyasehavisto,puestoqueelprogramatomaríademasiadotiempo.(Enformamásprecisa,sutiempodeejecucióntiendeacrecerenproporcióncuadráticaconelnúmerodepalabrasdeentrada.)¿Cómopodemosorganizarlosdatosparatratareficientementeunalistadepalabrasarbitrarias?

Unasoluciónesmantenersiempreordenadoelconjuntodepalabrasqueyasehanvisto,colocandocadaunaensuposicióncorrectacuandollega.Esto,decualquiermanera,nosepodríarealizarrecorriendolaspalabrasenunarreglolineal—tambiéntomadodemasiadotiempo.Enlugardeelloutilizaremosunaestructuradedatosllamadaárbolbinario.

Elárbolcontieneun“nodo”porcadapalabradistinta;cadanodocontiene

unapuntadoraltextodelapalabra

unacuentadelnúmerodeocurrencias

unapuntadoralnodohijodelaizquierda

unapuntadoralnodohijodeladerecha

Ningúnnodopuedetenermásdedoshijos;sólopuedetenerceroouno.

Losnodossemantienendetalmaneraqueencualquiernodoelsubárbolizquierdocontienesólopalabrasquesonlexicográficamentemenoresquelapalabraqueestáenelnodo,yelsubárboldeladerechasólocontienepalabrasquesonmayores.Esteeselárbolparalaoración“Estiempodequetodosloshombresbuenosvenganalauxiliodesupartido”,comoseconstruyóalinsertarcadapalabratalcomofueencontrada.

Paradescubrirsiunanuevapalabrayaestáenelárbol,inicieenlaraízycompárelaconlaqueestáalmacenadaenesenodo.Sicoincide,lapreguntaserespondeafirmativamente.Silanuevapalabraesmenorquelapalabradelárbol,continúebuscandoenelnodohijodelaizquierdao,deotramanera,enelnodohijodela

Page 200: Titivillus 07.07

derecha.Siyanohayunhijoenladirecciónrequerida,lapalabranuevanoestáenelárbol,ydehecholaentradavacíaesellugarapropiadoparaagregarlapalabranueva.Esteprocesoesrecursivo,yaquelabúsquedadesdecualquiernodoempleaunabúsquedadesdeunodesushijos.Porello,unasrutinasrecursivasparainsercióneimpresiónseránlomásnatural.

Regresandoaladescripcióndeunnodo,serepresentaconvenientementecomounaestructuraconcuatrocomponentes:

structtnode{/*elnododelárbol:*/

char*word;/*apuntahaciaeltexto*/

intcount;/*númerodeocurrencias*/

structtnode*left;/*hijoalaizquierda*/

structtnode*right;/*hijoaladerecha*/

};

Estadeclaraciónrecursivadeunnodopodríaparecerriesgosa,peroescorrecta.Esilegalqueunaestructuracontengaunainstanciadesímisma,pero

structtnode*left;

declaraaleftcomounapuntadoratnode,nocomountnodeensí.

Ocasionalmente,serequieredeunavariacióndeestructurasautorreferenciadas:dosestructurasquehaganreferenciaunaalaotra.Laformademanejarestoes:

structt{

...

structs*p;/*papuntaaunas*/

};

structs{

...

structt*q;/*qapuntaaunat*/

};

Elcódigodetodoelprogramaessorprendentementepequeño,dadounnúmeroderutinasdesoporte,comogetword,queyahemosdescrito.Larutinaprincipalleepalabrascongetwordylasinstalaenelárbolconaddtree

#include<stdio.h>

#include<ctype.h>

#include<string.h>

Page 201: Titivillus 07.07

#defineMAXWORD100

structtnode*addtree(structtnode*,char*);

voidtreeprint(structtnode*);

intgetword(char*,int);

/*conteodefrecuenciadepalabras*/

main()

{

structtnode*root;

charword[MAXWORD];

root=NULL;

while(getword(word,MAXWORD)!=EOF)

if(isalpha(word[0]))

root=addtree(root,word);

treeprint(root);

return0;

}

Lafunciónaddtreeesrecursiva,mainpresentaunapalabraalnivelsuperiordelárbol(laraíz).Encadaetapa,lapalabrasecomparaconlaqueyaestáalmacenadaenelnodo,ysefiltrabajandohaciaelsubárbolizquierdooderechoconunallamadarecursivaaaddtree.Finalmentelapalabracoincidiráconalgoqueyaestáenelárbol(encuyocasolacuentaseincrementa),oseencuentraunapuntadornulo,indicandoquesedebecrearunnodoyagregarloalárbol.Sisecreaunnuevonodo,addtreeregresaunapuntadoraél,yloinstalaenelnodopadre.

structtnode*talloc(void);

char*strdup(char*);

/*addtree:agregaunnodoconw,enobajop*/

structtnode*addtree(structtnode*p,char*w)

{

intcond;

if(p==NULL){/*llegóunanuevapalabra*/

p=talloc();/*creaunnuevonodo*/

Page 202: Titivillus 07.07

p->word=strdup(w);

p->count=1;

p->left=p->right=NULL;

}elseif((cond=strcmp(w,p->word))==0)

p->count++;/*palabrarepetida*/

elseif(cond<0)/*menorqueelcontenidodelsubárbolizquierdo*/

p->left=addtree(p->left,w);

else/*mayorqueelcontenidodelsubárbolderecho*/

p->right=addtree(p->right,w);

returnp;

}

Elespaciodealmacenamientoparaelnuevonodoseobtieneconlarutinatalloc,lacualregresaunapuntadoraunespaciolibreadecuadoparamantenerunnododelárbol,ylanuevapalabrasecopiaaunlugarocultoconstrdup.(Hablaremosdeesasrutinasenunmomento.)Lacuentaseinicializaylosdoshijossehacennulos.Estapartedelcódigoseejecutasóloparalashojasdelárbol,cuandoestásiendoagregadounnuevonodo.Hemosomitido(imprudencialmente)larevisióndeerroresenlosvaloresregresadosporstrdupytalloc.

treeprintimprimeelárbolenformaordenada;paracadanodoescribeelsubárbolizquierdo(todaslaspalabrasmenoresqueésta),despuéslapalabraensí,yposteriormenteelsubárbolderecho(todaslaspalabrasmayores).Sisesienteinsegurosobrelaformaenquetrabajalarecursión,simulelaoperacióndetreeprintsobreelárbolmostradoanteriormente.

/*treeprint:impresióndelárbolpenorden*/

voidtreeprint(structtnode*p)

{

if(p!=NULL){

treeprint(p->left);

printf("%4d%s\n",p->count,p->word);

treeprint(p->right);

}

}

Unanotapráctica:sielárbolse“desbalancea”debidoaquelaspalabrasnolleganenordenaleatorio,eltiempodeejecuciónpuedeaumentardemasiado.Enelpeordeloscasos,silaspalabrasyaestánenorden,esteprogramarealizaunacostosasimulación

Page 203: Titivillus 07.07

debúsquedalineal.Existengeneralizacionesdelárbolbinarioquenopadecendeestecomportamientodelpeorcaso,peronolasdescribiremosaquí.

Antesdedejaresteejemplo,tambiénesdeseableunabreveexposiciónsobreunproblemarelacionadoconlosasignadoresdememoria.Esclaramentedeseablequesóloexistaunasignadordealmacenamientoenunprograma,auncuandoasignediferentesclasesdeobjetos.Perosiunasignadorvaaprocesarpeticionesde,digamos,apuntadoresacharyapuntadoresastructtnodes,surgendospreguntas.Primera,¿cómocumplelosrequisitosdelamayorpartedelasmáquinasreales,dequelosobjetosdeciertostiposdebensatisfacerrestriccionesdealineación(porejemplo,generalmentelosenterosdebensersituadosenlocalidadespares)?Segunda,¿cuálesdeclaracionespuedentratarconelhechodequeunasignadordememorianecesariamentedeberegresardiferentesclasesdeapuntadores?

Losrequisitosdealineaciónporlogeneralsepuedensatisfacerfácilmente,alcostodealgúnespaciodesperdiciado,asegurandoqueelasignadorsiempreregreseunapuntadorquecumplacontodaslasrestriccionesdealineación.Elallocdelcapítulo5nogarantizaningunaalineaciónenparticular,demodoqueemplearemoslafunciónmallocdelabibliotecaestándar,quesílohace.Enelcapítulo8semostraráunaformaderealizarmalloc.

Lapreguntaacercadeltipodedeclaraciónparaunafuncióncomomallocesdifícilparacualquierlenguajequetomeconseriedadlarevisióndetipos.EnC,elmétodoapropiadoesdeclararquemallocregresaunapuntadoravoid,despuésforzarexplícitamenteconuncastalapuntadorparahacerlodeltipodeseado,mallocylasrutinasrelativasestándeclaradasenelheaderestándar<stdlib.h>.Así,tallocsepuedeescribircomo

#include<stdlib.h>

/*talloc:creauntnode*/

structtnode*talloc(void)

{

return(structtnode*)malloc(sizeof(structtnode));

}

strdupsimplementecopialacadenadadaporsuargumentoaunlugarseguro,obtenidoporunallamadaamalloc:

char*strdup(char*s)/*creaunduplicadodes*/

{

char*p;

p=(char*)malloc(strlen(s)+1);/*+1para'\0'*/

if(p!=NULL)

strcpy(p,s);

returnp;

Page 204: Titivillus 07.07

}

mallocregresaNULLsinohayespaciodisponible;strduppasaesevalor,dejandoelmanejodeerrorasuinvocador.

Elespacioobtenidoalllamaramallocpuedeliberarseparasureutilizaciónllamandoafree;véanseloscapítulos7y8.

Ejercicio6-2.EscribaunprogramaqueleaunprogramaenCeimprimaenordenalfabéticocadagrupodenombresdevariablequeseanidénticasensusprimeros6caracteres,perodiferentesenelresto.Nocuentepalabrasdentrodecadenasnicomentarios.Hagaque6seaunparámetroquepuedafijarsedesdelalíneadeórdenes.□

Ejercicio6-3.Escribaunprogramadereferenciascruzadasqueimprimaunalistadetodaslaspalabrasdeundocumento,yparacadapalabra,unalistadelosnúmerosdelíneaenlosqueaparece.Eliminepalabrascomo“el”,“y”,etcétera.□

Ejercicio6-4.Escribaunprogramaqueimprimalasdistintaspalabrasdesuentrada,ordenadasenformadescendentedeacuerdoconsufrecuenciadeocurrencia.Precedeacadapalabraporsuconteo.□

Page 205: Titivillus 07.07

6.6.Búsquedaentablas

Enestasecciónescribiremosloscomponentesdeunpaquetedebúsquedaentablas,parailustrarmásaspectosacercadeestructuras.Estecódigoestípicodeloquepodríaencontrarseenlasrutinasdemanejodetablasdesímbolosdeunmacroprocesadorocompilador.Porejemplo,considerelaproposición#define.Cuandoseencuentraunalíneacomo

#defineIN1

elnombreINyeltextodereemplazo1sealmacenanenunatabla.Después,cuandoelnombreINapareceenunaproposicióncomo

state=IN;

sedebereemplazarpor1.

Existendosrutinasquemanipulanlosnombresytextosdereemplazo.install(s,t)registraelnombresyeltextodereemplazotenunatabla;sytsonsólocadenasdecaracteres,lookup(s)buscasenlatablayregresaunapuntadorallugarendondefueencontrado,oNULLsinoestá.

Elalgoritmoesunabúsquedahash—elnombrequellegaseconvierteaunpequeñoenterononegativo,quedespuésseusaparaindexarunarreglodeapuntadores.Unelementodelarregloapuntaalprincipiodeunalistaligadadebloquesquedescribennombresquetienenesevalordehash.ElelementoesNULLsiningúnnombrehaobtenidoesevalor.

nombre

defn

Unbloquedelalistaesunaestructuraquecontieneapuntadoresalnombre,altextodereemplazoyalsiguientebloquedelalista.Unsiguienteapuntadornulomarcaelfinaldelalista.

structnlist{/*entradadelatabla:*/

structnlist*next;/*siguienteentradaenlacadena*/

char*name;/*nombredefinido*/

char*defn;/*textodereemplazo*/

Page 206: Titivillus 07.07

};

Elarreglodeapuntadoresessólo

#defineHASHSIZE101

staticstructnlist*hashtab[HASHSIZE];/*tabladeapuntadores*/

Lafuncióndehash,queseutilizatantoenlookupcomoeninstall,agregacadavalordecarácterdelacadenaaunacombinaciónmezcladadelosanterioresyregresaelmódulodelresiduoentreeltamañodelarreglo.Estanoeslamejorfuncióndehashposible,peroespequeñayefectiva.

/*hash:formaunvalorhashparalacadenas*/

unsignedhash(char*s)

{

unsignedhashval;

for(hashval=0;*s!='\0';s++)

hashval=*s+31*hashval;

returnhashval%HASHSIZE;

}

Laaritméticasinsignoaseguraqueelvalordehashnoesnegativo.

Elprocesodehashproduceuníndiceinicialenelarreglohashtab;silacadenaseencontraraenalgúnlugar,seráenlalistadebloquesqueempiezaallí.Labúsquedaserealizaporlookup.Silookupencuentraquelaentradayaestápresente,regresaunapuntadoraella;deotramanera,regresaNULL.

/*lookup:buscasenhashtab*/

structnlist*lookup(char*s)

{

structnlist*np;

for(np=hashtab[hash(s)];np!=NULL;np=np->next)

if(strcmp(s,np->name)==0)

returnnp;/*seencontró*/

returnNULL;/*noseencontró*/

}

Elcicloforqueestáenlookupeslaexpresiónidiomáticaestándarparamoversesobreunalistaligada:

Page 207: Titivillus 07.07

for(ptr=head;ptr!=NULL;ptr=ptr->next)

...

installusaalookupparadeterminarsielnombrequesevaainstalaryaestápresente;deserasí,lanuevadefinicióntomaellugardelaanterior.Deotramanera,secreaunanuevaentrada,installregresaNULLsiporcualquierrazónnohayespacioparaunanuevaentrada.

structnlist*lookup(char*);

char*strdup(char*);

/*install:coloca(name,defn)dentrodehashtab*/

structnlist*install(char*name,char*defn)

{

structnlist*np;

unsignedhashval;

if((np=lookup(name))==NULL){/*nofueencontrado*/

np=(structnlist*)malloc(sizeof(*np));

if(np==NULL||(np->name=strdup(name))==NULL)

returnNULL;

hashval=hash(name);

np->next=hashtab[hashval];

hashtab[hashval]=np;

}else/*yaestáallí*/

free((void*)np->defn);/*liberalaanteriordefn*/

if((np->defn=strdup(defn)==NULL)

returnNULL;

returnnp;

}

Ejercicio6-5.Escribaunafunciónundefqueborreunnombreyunadefinicióndelatablamantenidaporlookupeinstall.□

Ejercicio6-6.Hagaunaversiónsimpledelprocesador#define(estoes,sinargumentos)adecuadaparausarseconprogramasenC,basadaenlasrutinasdeestasección.Tambiénpodráencontrarútilesgetchyungetch.□

Page 208: Titivillus 07.07

6.7.typedef

Cproporcionaunafacilidadllamadatypedefparacrearnuevostiposdedatos.Porejemplo,ladeclaración

typedefintLongitud;

hacedelnombreLongitudunsinónimodeint.EltipoLongitudpuedeemplearseendeclaraciones,casts,etc.,exactamentedelamismamaneraenquelopodríaserint.

Longitudlen,maxlen;

Longitud*lengths[];

Demodosemejante,ladeclaración

typedefchar*Cadena;

haceaCadenaunsinónimoparachar*oapuntadoracarácter,quedespuéspuedeusarseendeclaracionesycasts:

Cadenap,lineptr[MAXLINES],alloc(int);

intstrcmp(Cadena,Cadena);

p=(Cadena)malloc(100);

Nótesequeeltipoquesedeclaraenuntypedefapareceenlaposicióndeunnombredevariable,nojustodespuésdelapalabratypedef.Sintácticamente,typedefescomolasclasesdealmacenamientoextern,static,etc.Hemosempleadonombresconmayúsculaparalostypedef,paradestacarlos.

Comounejemplomáscomplicado,podríamosdeclararmediantetypedeflosnodosdelárbolmostradosanteriormenteenestecapítulo:

typedefstructtnode*Treeptr;

typedefstructtnode{/*elnododelárbol:*/

char*word;/*apuntahaciaeltexto*/

intcount;/*númerodeocurrencias*/

Treeptr*left;/*hijoizquierdo*/

Treeptr*right;/*hijoderecho*/

}Treenode;

Estocreadosnuevaspalabrasreservadasparatipos,llamadosTreenode(unaestructura)yTreeptr(unapuntadoralaestructura).Entonces,larutinatallocpodríaser

Page 209: Titivillus 07.07

Treeptrtalloc(void)

{

return(Treeptr)malloc(sizeof(Treenode));

}

Sedebedestacarqueunadeclaracióntypedefnocreaunnuevotipoenningúnsentido;simplementeagregaunnuevonombreparaalgúntipoyaexistente.Tampocoesalgunanuevasemántica:lasvariablesdeclaradasdeestamaneratienenexactamentelasmismaspropiedadesquelasvariablescuyasdeclaracionesseescribenexplícitamente.Enefecto,typedefescomo#define,exceptoquealserinterpretadoporelcompiladorpuederealizarsubstitucionestextualesqueestánmásalládelascapacidadesdelpreprocesador.Porejemplo,

typedefint(*AAF)(char*,char*);

creaeltipoAAF,de“apuntadorafunción(dedosargumentoschar*)queregresaint”,elcualsepuedeusarencontextoscomo

AAFstrcmp,numcmp;

dentrodelbreveprogramadelcapítulo5.

Ademásdelasrazonespuramenteestéticas,haydosrazonesprincipalesparaempleartypedef.Laprimeraesparametrizarunprogramacontralosproblemasdetransportabilidad.Siseempleatypedefparatiposdedatosquepuedenserdependientesdelamáquina,cuandounprogramasetraslada,sólolostypedefrequierendecambios.Unasituacióncomúnesusarnombresdetypedefparavariascantidadesenteras,yentonceshacerunconjuntoapropiadodeseleccionesdeshort,intylongparacadamáquina.Tiposcomosize_typtrdiff_tdelabibliotecaestándarsonejemplos.

Elsegundopropósitodelostypedefesproporcionarmejordocumentaciónparaunprograma—untipollamadoTreeptrpuedesermásfácildeentenderqueunodeclaradosólocomounapuntadoraunaestructuracomplicada.

Page 210: Titivillus 07.07

6.8.Uniones

Unauniónesunavariablequepuedecontener(enmomentosdiferentes)objetosdediferentestiposytamaños,yelcompiladorhaceelseguimientodeltamañoyrequisitosdealineación.Lasunionesproporcionanunaformademanipulardiferentesclasesdedatosdentrodeunasolaáreadealmacenamiento,sinincluirenelprogramaningunainformacióndependientedelamáquina.SonanálogasalosvariantrecordsdePascal.

Comounejemplo,quepodríaserencontradoenelmanejadordelatabladesímbolosdeuncompilador,supóngasequeunaconstantepodríaserunint,unfloat,ounapuntadoracarácter.Elvalordeunaconstanteenparticulardebeserguardadoenunavariabledeltipoadecuado.Noobstante,esconvenienteparaelmanejadordetablassielvalorocupalamismacantidaddememoriayesguardadoenelmismolugarsinimportarsutipo.Esteeselpropósitodeuna“unión”—unasolavariablequepuedelegítimamenteguardarunodevariostipos.Lasintaxissebasaenlasestructuras:

unionu_tag{

intival;

floatfval;

char*sval;

}u;

Lavariableuserásuficientementegrandecomoparamanteneralmayordelostrestipos:eltamañoespecíficodependedelaimplantación.Cualquieradeestostipospuedeserasignadoauydespuésempleadoenexpresiones,mientrasqueelusoseaconsistente:eltiporecuperadodebesereltipoquesealmacenómásrecientemente.Esresponsabilidaddelprogramadorllevarelregistrodeltipoqueestáalmacenadoactualmenteenunaunión;sialgosealmacenacomountipoyserecuperacomootro,elresultadodependedelaimplantación.

Sintácticamente,setieneaccesoalosmiembrosdeunaunióncon

nombre-unión.miembro

o

apuntador-unión->miembro

precisamentecomoalasestructuras.Silavariableutypeseempleaparallevarelregistrodeltipoactualmentealmacenadoenu,entoncessepodríaverelcódigocomo

if(utype==INT)

printf("%d\n",u.ival);

elseif(utype==FLOAT)

printf("%f\n",u.fval);

Page 211: Titivillus 07.07

elseif(utype==STRING)

printf("%s\n",u.sval);

else

printf("datoincorrecto%denutype\n",utype);

Lasunionespuedenpresentarsedentrodeestructurasyarreglos,yviceversa.Lanotaciónparateneraccesoaunmiembrodeunauniónenunaestructura(oviceversa)esidénticaaladelasestructurasanidadas.Porejemplo,enelarreglodeestructurasdefinidopor

struct{

char*name;

intflags;

intutype;

union{

intival;

floatfval;

char*sval;

}u;

}symtab[NSYM];

almiembroivalselerefierecomo

symtab[i].u.ival

yalprimercarácterdelacadenasvalporcualquierade

*symtab[i].u.sval

symtab[i].u.sval[0]

Enefecto,unauniónesunaestructuraenlacualtodoslosmiembrostienenundesplazamientodeceroapartirdelabase,laestructuraessuficientementegrandeparamanteneralmiembro“másancho”,ylaalineacióneslaapropiadaparatodoslostiposdelaunión.Estánpermitidaslasmismasoperacionessobrelasunionescomosobrelasestructuras:asignaciónocopiacomounidad,tomarladirección,yhacerelaccesoaunmiembro.

Unauniónsólosepuedeinicializarconunvalordeltipodesuprimermiembro,asíquelauniónudescritaanteriormentesólosepuedeinicializarconunvalorentero.

Elasignadordealmacenamientodelcapítulo8muestracómosepuedeusarunauniónparaobligaraqueunavariableseaalineadaparaunaclaseparticulardelímitesdealmacenamiento.

Page 212: Titivillus 07.07

6.9.Camposdebits

Cuandoelespaciodealmacenamientoesescaso,puedesernecesarioempaquetarvariosobjetosdentrodeunasolapalabrademáquina;unusocomúnesunconjuntodebanderasdeunbitenaplicacionescomotablasdesímbolosparacompiladores.Losformatosdedatosimpuestosexternamente,comointerfaceshaciadispositivosdehardware,frecuentementerequierenlacapacidaddetomarpartesdeunapalabra.

Imagíneseunfragmentodeuncompiladorquemanipulaunatabladesímbolos.Cadaidentificadordentrodeunprogramatieneciertainformaciónasociadaaél,porejemplo,siesonounapalabrareservada,siesonoexternay/oestáticayotrosaspectos.Laformamáscompactadecodificartalinformaciónesconunconjuntodebanderasdeunbitdentrodeuncharoint.

Laformausualenqueestoserealizaesdefiniendounconjuntode“máscaras”correspondientesalasposicionesrelevantesdebits,comoen

#defineKEYWORD01

#defineEXTERNAL02

#defineSTATIC04

o

enum{KEYWORD=01,EXTERNAL=02,STATIC=04};

Losnúmerosdebenserpotenciasdedos.Elaccesoalosbitsvieneasercosade“jugar”conlosoperadoresdecorrimiento,enmascaramientoycomplemento,quesedescribieronenelcapítulo2.

Ciertasexpresionesaparecenfrecuentemente:

flags|=EXTERNAL|STATIC;

enciendelosbitsEXTERNALySTATICenflags,entantoque

flags&=~(EXTERNAL|STATIC);

losapaga,y

if((flags&(EXTERNAL|STATIC))==0)...

esverdaderosiambosbitsestánapagados.

Aunqueestasexpresionessedominanfácilmente,comoalternativaCofrecelacapacidaddedefiniryteneraccesoacamposdeunapalabramásdirectamentequepormediodeoperadoreslógicosdebits.Uncampodebits,osimplementecampo,esunconjuntodebitsadyacentesdentrodeunaunidaddealmacenamientodefinidaporlaimplantación,alquellamaremos“palabra”.Lasintaxisparaladefiniciónyaccesoacamposestábasadaenestructuras.Porejemplo,laanteriortabladesímbolos#definepodríahabersidoreemplazadaporladefinicióndetrescampos:

Page 213: Titivillus 07.07

struct{

unsignedintis_keyword:1;

unsignedintis_extern:1;

unsignedintis_static:1;

}flags;

Estodefineunavariablellamadaflags,quecontienetrescamposdeunbit.Elnúmeroquesiguealcarácterdospuntosrepresentaelanchodelcampoenbits.Loscampossondeclaradosunsignedintparaasegurarqueseancantidadessinsigno.

Loscamposindividualessonreferidosenlamismaformaqueparaotrosmiembrosdeestructuras:flags.is_keyword,flags.is_extern,etc.Loscampossecomportancomopequeñosenterosypuedenparticiparenexpresionesaritméticas,comolohacenotrosenteros.Así,elejemplopreviopudoescribirsemásnaturalmentecomo

flags.is_extern=flags.is_static=1;

paraencenderlosbits;

flags.is_extern=flags.is_static=0;

paraapagarlos;y

if(flag.is_extern==0&&flags.is_static==0)

...

paraprobarlos.

Casitodoacercadeloscamposesdependientedelaimplantación.Elqueuncampopuedatraslaparallímitedeunapalabrasedefineporlaimplantación.Loscamposnonecesitantenernombre;loscampossinnombre(dospuntosysuamplitudsolamente)seempleanparallenarespacios.Elanchoespecial0puedeemplearseparaobligaralaalineaciónalsiguientelímitedepalabra.

Loscamposseasignandeizquierdaaderechaenalgunasmáquinasydederechaaizquierdaenotras.Estosignificaqueaunqueloscampossonútilesparaelmantenimientodeestructurasdedatosdefinidasinternamente,lapreguntadequépuntavieneprimerotienequeconsiderarsecuidadosamentecuandoseseleccionandatosdefinidosexternamente;losprogramasquedependendetalescosasnosontransportables.Loscampossólosepuedendeclararcomoenteros;portransportabilidad,sedebeespecificarexplícitamentesignedounsigned.Nosonarreglosynotienendirecciones,demodoqueeloperador&nopuedeaplicarseaellos.

Page 214: Titivillus 07.07

CAPÍTULO7:Entradaysalida

LasoperacionesdeentradaysalidanosonensípartedellenguajeC,porloquehastaahoranolashemosdestacado.Sinembargo,losprogramasinteractúanconsumedioambienteenformasmuchomáscomplicadasdelasquehemosmostradoantes.Enestecapítulodescribiremoslabibliotecaestándar,unconjuntodefuncionesqueproporcionanentradaysalida,manipulacióndecadenas,manejodememoria,rutinasmatemáticasyunavariedaddeotrosserviciosparaprogramasenC,aunqueharemoshincapiéenlaentradaysalida.

ElestándarANSIdefinedemaneraprecisaestasfuncionesdebiblioteca,demodoquepuedenexistirenformacompatibleencualquiersistemaendondeexistaC.Losprogramasquerestringensuinteracciónconelsistemaalasfacilidadesprovistasporlabibliotecaestándarpuedenserllevadosdeunsistemaaotrosincambios.

Laspropiedadesdelasfuncionesdebibliotecaestánespecificadasenmásdeunadocenadeheaders;yahemosvistoalgunos,incluyendo<stdio.h>,<string.h>y<ctype.h>.Nopresentaremosaquílatotalidaddelabiblioteca,puestoqueestamosmásinteresadosenescribirprogramasenCquelosusan.LabibliotecasedescribeendetalleenelapéndiceB.

Page 215: Titivillus 07.07

7.1.Entradaysalidaestándar

Comoseñalamosenelcapítulo1,labibliotecaconsisteenunmodelosimpledeentradaysalidadetexto.Unflujodetextoconsisteenunasecuenciadelíneas,cadaunadelascualesterminaconuncarácternuevalínea.Sielsistemanooperadeesemodo,labibliotecahaceloqueseanecesarioparasimularqueasífunciona.Porejemplo,labibliotecapodríaconvertirelregresodecarroyavancedelíneaaunanuevalíneaenlaentradaydenuevoenlasalida.

Elmecanismodeentradamássimpleesleeruncarácteralavez.delaentradaestándar,normalmenteelteclado,congetchar:

intgetchar(void)

getcharregresaelsiguientecarácterdelaentradacadavezqueseinvoca,oEOFcuandoencuentrafindearchivo.LaconstantesimbólicaEOFestádefinidaen<stdio.h>.Elvalorestípicamente-1,perolaspruebassedebenescribirenfuncióndeEOF,demodoqueseanindependientesdelvalorespecífico.

Enmuchosmediosambientes,unarchivopuedetomarellugardeltecladoempleandolaconvención<pararedireccionamientodeentrada:siunprogramaprogusagetchar,entonceslalíneadeórdenes

prog<archent

provocaqueprogleacaracteresdearchent.Elcambiodelaentradaserealizadetalmaneraqueprogmismoesajenoalcambio;enparticular,lacadena“<archent”noestáincluidaentrelosargumentosdelalíneadeórdenesenargv.Elcambiodelaentradaestambiéninvisiblesilaentradavienedeotroprogramavíaunmecanismodeinterconexión(pipe):enalgunossistemas,lalíneadeórdenes

otroprog|prog

ejecutatantoalprogramaotroprogcomoaprog,einterconectalasalidaestándardeotroprogconlaentradaestándarparaprog.

Lafunción

intputchar(int)

seempleaparasalida:putchar(c)colocaelcaráctercenlasalidaestándar,queporomisióneslapantalla,putcharregresaelcarácterescrito,oEOFsiocurrealgúnerror.Denuevo,lasalidapuedeserdirigidahaciaalgúnarchivocon>nombrearch:siprogutilizaputchar,

prog>archsal

escribirálasalidaestándarhaciaarchsal.Sisepermitelainterconexión,

prog|otroprog

dejalasalidaestándardeprogenlaentradaestándardeotroprog.

Page 216: Titivillus 07.07

Lasalidaproducidaporprintftambiénencuentrasucaminohacialasalidaestándar.Lasllamadasaputcharyaprintfpuedenestartraslapadas—lasalidaapareceenelordenenquesehicieronlasllamadas.

Cadaarchivofuentequeserefieraaunafuncióndebibliotecadeentrada/salidadebecontenerlalínea

#include<stdio.h>

antesdelaprimerareferencia.Cuandounnombresedelimitapor<y>serealizaunabúsquedadelheaderenalgunoslugaresestándar(porejemplo,enlossistemasUNIX,típicamenteeneldirectorio/usr/include).

Muchosprogramasleensólounflujodeentradayescribensólounflujodesalida;paratalesprogramaslaentradaysalidacongetchar,putcharyprintf,puedesertotalmenteadecuadayenrealidadessuficienteparacomenzar.Estoesparticularmenteciertosiseemplealaredirecciónparaconectarlasalidadeunprogramaalaentradadeotro.Porejemplo,considéreseelprogramalower,queconviertesuentradaaminúsculas:

#include<stdio.h>

#include<ctype.h>

main()/*lower:conviertelaentradaaminúsculas*/

{

intc;

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

putchar(tolower(c));

return0;

}

Lafuncióntolowerestádefinidaen<ctype.h>;convierteunaletramayúsculaaminúscula,yregresalosotroscaracteresintactos.Comomencionamosantes,las“funciones”comogetcharyputcharen<stdio.h>ytoloweren<ctype.h>sonamenudomacros,evitándoseasílasobrecargadeunallamadaafunciónporcadacarácter.Enlasección8.5semostrarácómosehaceesto.Sinimportarcómoseanlasfuncionesde<ctype.h>enunamáquinadada,losprogramasquelasempleanestánaisladosdeljuegodecaracteres,decaracteres.

Ejercicio7-1.Escribaunprogramaqueconviertamayúsculasaminúsculasoviceversa,dependiendodelnombreconqueseinvoque,dadoenargv[0].□

Page 217: Titivillus 07.07

7.2.Salidaconformato—printf

Lafuncióndesalidaprintftraducevaloresinternosacaracteres.Yahemosempleadoinformalmenteprintfenloscapítulosanteriores.Ladescripcióndeaquícubrelosusosmástípicos,peronoestácompleta;paraladefinicióncompleta,véaseelapéndiceB.

intprintf(char*format,arg1,arg2,...)

printfconvierte,daformatoeimprimesusargumentosenlasalidaestándarbajoelcontroldeformat.Regresaelnúmerodecaracteresimpresos.

Lacadenadeformatocontienedostiposdeobjetos:caracteresordinarios,quesoncopiadosalflujodesalida,yespecificacionesdeconversión,cadaunodeloscualescausalaconversióneimpresióndelossiguientesargumentossucesivosdeprintf.Cadaespecificacióndeconversióncomienzaconun%yterminaconuncarácterdeconversión.Entreel%yelcarácterdeconversiónpuedenestar,enorden:

Unsignomenos,queespecificaelajustealaizquierdadelargumentoconvertido.

Unnúmeroqueespecificaelanchomínimodecampo.Elargumentoconvertidoseráimpresodentrodeuncampodealmenosesteancho.Siesnecesarioserállenadodeblancosalaizquierda(oaladerecha,siserequiereajustealaizquierda)paracompletarlaamplituddelcampo.

Unpunto,queseparaelanchodecampodelaprecisión.

Unnúmero,laprecisión,queespecificaelnúmeromáximodecaracteresdeunacadenaqueseránimpresos,oelnúmerodedígitosdespuésdelpuntodecimaldeunvalordepuntoflotante,oelnúmeromínimodedígitosparaunentero.

Unahsielenteroseráimpresocomounshort,ounal(letraele)siserácomounlong.

Loscaracteresdeconversiónsemuestranenlatabla7-1.Sielcarácterdespuésdel%noesunaespecificacióndeconversión,elcomportamientonoestádefinido.

TABLA7-1.CONVERSIONESBÁSICASDEPRINTF

CARÁCTER

TIPODEARGUMENTO:IMPRESOCOMO

d,i

int;númerodecimal.

o

int;númerooctalsinsigno(sinceroinicial).

x,X

int;númerohexadecimalsinsigno(conun0xo0Xinicial,usandoabcdefoABCDEFpara10,...15.

Page 218: Titivillus 07.07

u

int;númerodecimalsinsigno.

c

int;caráctersencillo.

s

char*;imprimecaracteresdeunacadenahastaun'\0'oelnúmerodecaracteresdadoporlaprecisión.

f

double;[-]

m

.

dddddd

,endondeelnúmerode

ds

estádadoporlaprecisión(predeterminadoa6).

e,E

double;[-]

m

.

dddddd

xx

o[-]

m

.

dddddd

xx

,endondeelnúmerode

Page 219: Titivillus 07.07

ds

estádadoporlaprecisión(predeterminadoa6).

g,G

double;usa%eo%Esielexponenteesmenorque-4omayoroigualalaprecisión;deotraformausa%f.Loscerosoelpuntoalfinalnoseimprimen.

p

void*;apuntador(representacióndependientedelainstalación).

%

noesconvertidoenningúnargumento;imprimeun%.

Unaamplitudoprecisiónsepuedeespecificarpor*,encuyocasoelvalorsecalculaconvirtiendoelsiguienteargumento(quedebeserint).Porejemplo,paraimprimiralmenosmaxcaracteresdeunacadenas,

printf("%.*s",max,s);

Lamayoríadelasconversionesdeformatosehanilustradoencapítulosanteriores.Unaexcepcióneslaprecisiónrelacionadaconlascadenas.Lasiguientetablamuestraelefectodeunavariedaddeespecificacionesalimprimir"hola,mundo"(11caracteres).Hemoscolocadoelcarácterdospuntosalrededordecadacampoparaquesepuedaapreciarsuextensión.

:%s:

:hola,mundo:

:%10s:

:hola,mundo:

:%.10s:

:hola,mund:

:%-10s:

:hola,mundo:

:%.15s:

:hola,mundo:

:%-15s:

:hola,mundo:

:%15.10s:

:hola,mund:

Page 220: Titivillus 07.07

:%-15.10s:

:hola,mund:

Unaadvertencia:printfempleasuprimerargumentoparadecidircuántosargumentoslesiguenycuálessonsustipos,printfseconfundiráyseobtendránresultadoserróneossinohaysuficientesargumentosositienentiposincorrectos.Tambiéndebeadvertirladiferenciaentreestasdosllamadas:

printf(s);/*FALLAsiscontiene%*/

printf(”%s",s);/*SEGURO*/

Lafunciónsprintfrealizalasmismasconversionesqueprintf,peroalmacenalasalidaenunacadena:

intsprintf(char*cadena,char*format,arg1,arg2,...)

sprintfdaformatoalosargumentosqueestánenarg1,arg2,etc.,deacuerdoconformatcomoantes,perocolocaelresultadoencadenaenvezdeenlasalidaestándar;cadenadebesersuficientementegrandecomopararecibirelresultado.

Ejercicio7-2.Escribaunprogramaqueimprimaunaentradaarbitrariaenformasensata.Comomínimo,deberáimprimircaracteresnográficosenoctalohexadecimaldeacuerdoconlacostumbrelocal,ysepararlíneaslargasdetexto.□

Page 221: Titivillus 07.07

7.3.Listasdeargumentosdelongitudvariable

Estaseccióncontienelarealizacióndeunaversiónmínimadeprintf,paramostrarcómoescribirunafunciónqueproceseunalistadeargumentosdelongitudvariableenunaformatransportable.Puestoqueestamosinteresadosprincipalmenteenelprocesamientodeargumentos,minprintfprocesarálacadenadeformatoylosargumentos,perollamaráalprintfrealparahacerlasconversionesformato.

Ladeclaracióncorrectaparaprintfes

intprintf(char*fmt,...)

dondeladeclaración...significaqueelnúmeroytipodeesosargumentospuedevariar.Ladeclaración...sólopuedeapareceralfinaldelalistadeargumentos.Nuestraminprintfsedeclaracomo

voidminprintf(char*fmt,...)

yaquenoregresarálacuentadecaracteresqueregresaprintf.

Eltrucoestáencómominprintfrecorrelalistadeargumentoscuandolalistanisiquieratieneunnombre.Elheaderestándar<stdarg.h>contieneunconjuntodemacrodefinicionesquedefinencómoavanzarsobreunalistadeargumentos.Larealizacióndeesteheadervariarádeunamáquinaaotra,perolainterfazquepresentaesuniforme.

Eltipova_listseempleaparadeclararunavariablequesereferiráacadaargumentoensumomento;enminprintf,estavariablesellamaap,por“argumentpointer”(apuntadoraargumento).Lamacrova_startinicializaapparaapuntaralprimerargumentosinnombre.Debellamarseunavezantesdeusarap.Almenosdebehaberunargumentoconnombre;elúltimoargumentoconnombreesempleadoporva_startparainiciar.

Cadallamadadeva_argregresaunargumentoyavanzaapalsiguiente;va_argempleaunnombredetipoparadeterminarquétiporegresarycuángrandeseráelavance.Finalmente,va_endrealizalaslaboresdelimpiezayarregloqueseannecesarias.Debeinvocarseantesquelafunciónregrese.

Estaspropiedadesformanlabasedenuestroprintfsimplificado:

#include<stdarg.h>

/*minprintf:printfmínimaconlistavariabledeargumentos*/

voidminprintf(char*fmt,...)

{

va_listap;/*apuntaacadaargsinnombreenorden*/

char*p,*sval;

intival;

Page 222: Titivillus 07.07

doubledval;

va_start(ap,fmt);/*hacequeapapunteal1er.argsinnombre*/

for(p=fmt;*p;p++){

if(*p!='%'){

putchar(*p);

continue;

}

switch(*++p){

case'd':

ival=va_arg(ap,int);

printf("%d",ival);

break;

case'f':

dval=va_arg(ap,double);

printf("%f",dval);

break;

case's':

for(sval=va_arg(ap,char*);*sval;sval++)

putchar(*sval);

break;

default:

putchar(*p);

break;

}

}

va_end(ap);/*limpiacuandotodoestáhecho*/

}

Ejercicio7-3.Aumenteminprintfparaquemanejeotrasdelascaracterísticasdeprintf.□

Page 223: Titivillus 07.07

7.4.Entradaconformato—scanf

Lafunciónscanfeslaentradaanálogadeprintf,yproporcionamuchasdelasmismasfacilidadesdeconversiónenladirecciónopuesta.

intscanf(char*format,...)

scanfleecaracteresdelaentradaestándar,losinterpretadeacuerdoconlasespecificacionesqueestánenformat,yalmacenalosresultadosatravésdelosargumentosrestantes.Elargumentodeformatosedescribeabajo;losotrosargumentos,cadaunodeloscualesdebeserunapuntador,indicandóndedeberáalmacenarselaentradacorrespondientementeconvertida.Comoconprintf,estasecciónesunresumendelasposibilidadesmásútiles,nounalistaexhaustiva.

scanfsedetienecuandoterminaconsucadenadeformato,ocuandoalgunaentradanocoincideconlaespecificacióndecontrol.Regresacomosuvalorelnúmerodeítemsdeentradaquecoincidenconéxito.Estosepuedeemplearparadecidircuántosítemsseencontraron.Alfinaldelarchivo,regresaEOF;nótesequeestoesdiferentede0,quesignificaqueelsiguientecarácterdeentradanocoincideconlaprimeraespecificaciónenlacadenadeformato.Lasiguientellamadaascanfcontinúalabúsquedainmediatamentedespuésdelúltimocarácterqueyafueconvertido.

Existetambiénunafunciónsscanfqueleedeunacadenaynodelaentradaestándar:

intsscanf(char*cadena,char*format,arg1,arg2,...)

Rastrealacadenadeacuerdoconelformatoenformat,yalmacenaelvalorresultanteatravésdearg1,arg2,etc.Estosargumentosdebenserapuntadores.

Lacadenadeformatogeneralmentecontieneespecificacionesdeconversión,lascualessonempleadasparacontrolarlaconversióndeentrada.Lacadenadeformatopuedecontener:

Blancosotabuladores,loscualessonignorados.

Caracteresordinarios(no%),queseesperacoincidanconelsiguientecarácterquenoseaespacioenblancodelflujodeentrada.

Especificacionesdeconversión,consistentesenelcarácter%,uncarácteroptativodesupresióndeasignación*,unnúmerooptativoqueespecificaelanchomáximodecampo,unah,l,oLoptativaqueindicalaamplituddelobjetivo,yuncarácterdeconversión.

Laespecificacióndeconversióndirigelaconversióndelsiguientecampodeentrada.Normalmenteelresultadosecolocaenlavariableapuntadaporelargumentocorrespondiente.Siseindicalasupresióndeasignaciónconelcarácter*,sinembargo,elcampodeentradaesignoradoynoserealizaasignaciónalguna.Uncampodeentradaestádefinidocomounacadenadecaracteresquenosonespacioenblanco;seextiendehastaelsiguienteespacioenblancoohastaqueelanchodecamposeagote,siestáespecificado.Estoimplicaquescanfleeráentrevariaslíneasparaencontrarsuentrada,yaquelasnuevaslíneassonespaciosenblanco.(Loscaracteresdeespacioenblancosontabulador,nuevalínea,retornodecarro,tabuladorverticalyavancedehoja.)

Page 224: Titivillus 07.07

Elcarácterdeconversiónindicalainterpretacióndelcampodeentrada.Elargumentocorrespondientedebeserunapuntador,comoesrequeridoporlasemánticadelasllamadasporvalordeC.Loscaracteresdeconversiónsemuestranenlatabla7-2.

TABLA7-2.CONVERSIONESBÁSICASDESCANF

CARÁCTER

DATODEENTRADA;TIPODEARGUMENTO:

d

enterodecimal;int*.

i

entero;int*.Elenteropuedeestarenoctal(iniciadocon0)ohexadecimal(iniciadocon0xo0X).

o

enterooctal(conosinceroinicial);int*.

u

enterodecimalsinsigno;unsignedint*.

x

enterohexadecimal(iniciadoonocon0xo0X);int*.

c

caracteres;char*.Lossiguientescaracteresdeentrada(poromisión1)soncolocadosenelsitioindicado.Elsaltonormalsobrelosespaciosenblancoessuprimido;paraleerelsiguienteespacionoblanco,use%ls.

s

cadenadecaracteres(noentrecomillada);char*,apuntaaunarreglodecaracteressuficientementegrandeparalacadenayunaterminación'\0'queseráagregada.

e,f,g

númerodepuntoflotanteconsigno,puntodecimalyexponenteoptativos;float*.

%

%literal;nosehaceasignaciónalguna.

Loscaracteresdeconversiónd,i,o,u,xpuedenserprecedidosporhparaindicarqueenlalistadeargumentosapareceunapuntadorashortenlugardeaint,oporl(letraele)paraindicarqueapareceunapuntadoralongenlalistadeargumentos.Enformasemejante,loscaracteresdeconversióne,f,gpuedenserprecedidosporlparaindicarquehayunapuntadoradoubleenlugardeafloatenlalistadeargumentos.

Page 225: Titivillus 07.07

Comounprimerejemplo,larudimentariacalculadoradelcapítulo4sepuedeescribirconscanfparahacerlaconversióndeentrada:

#include<stdio.h>

main()/*calculadorarudimentaria*/

{

doublesum,v;

sum=0;

while(scanf("%lf",&v)==1)

printf("\t%.2f\n",sum+=v);

return0;

}

Supongaquedeseamosleerlíneasdeentradaquecontienenfechasdelaforma

25Dic1988

Laproposiciónscanfes

intday,year;

charmonthname[20];

scanf("%d%s%d",&day,monthname,&year);

Noseemplea&conmonthname,yaqueunnombredearregloesunapuntador.

Puedenaparecercaracteresliteralesenlacadenadeformatodescanf,ydebencoincidirconlosmismoscaracteresdelaentrada.Demodoquepodemosleerfechasdelaformamm/dd/yyconestaproposiciónscanf:

intday,month,year;

scanf("%d/%d/%d",&month,&day,&year);

scanfignoralosblancosylostabuladoresqueesténensucadenadeformato.Además,saltasobrelosespaciosenblanco(blancos,tabuladores,nuevaslíneasetc.)mientrasbuscalosvaloresdeentrada.Paraleerdeentradascuyoformatonoestáfijo,amenudoesmejorleerunalíneaalavez,ydespuéssepararlaconsscanf.Porejemplo,supongaquedeseamosleerlíneasquepuedencontenerfechasencualquieradelasformasanteriores.Entoncespodemosescribir

while(getline(line,sizeof(line))>0){

if(sscanf(line,"%d%s%d",&day,monthname,&year)==3)

printf("válido:%s\n",line);/*forma25Dic1988*/

Page 226: Titivillus 07.07

elseif(sscanf(line,"%d/%d/%d",&month,&day,&year)==3)

printf("válido:%s\n",line);/*formamm/dd/yy*/

else

printf("inválido:%s\n",line);/*formainválida*/

}

Lasllamadasascanfpuedenestarmezcladasconllamadasaotrasfuncionesdeentrada.Lasiguientellamadaacualquierfuncióndeentradainiciaráleyendoelprimercarácternoleídoporscanf.

Unaadvertenciafinal:losargumentosdescanfysscanfdebenserapuntadores.Elerrormáscomúnesescribir

scanf("%d",n);

enlugarde

scanf("%d",&n);

Esteerrorgeneralmentenosedetectaentiempodecompilación.

Ejercicio7-4.Escribaunaversiónprivadadescanfanálogaaminprintfdelasecciónanterior.□

Ejercicio7-5.Reescribalacalculadorapostfijadelcapítulo4usandoscanfy/osscanfparahacerlaentradaylaconversión.□

Page 227: Titivillus 07.07

7.5.Accesoaarchivos

Hastaahoratodoslosejemploshanleídodelaentradaestándaryescritoenlasalidaestándar,lascualessedefinenautomáticamenteparalosprogramasporelsistemaoperativolocal.

Elsiguientepasoesescribirunprogramaquedéaccesoaunarchivoquenoestéyaconectadoalprograma.Unprogramaqueilustralanecesidaddetalesoperacionesescat,elcualconcatenaenlasalidaestándarunconjuntodearchivosnombrados,catseempleaparaescribirarchivosenlapantalla,ycomouncolectordeentradasdepropósitogeneralparaprogramasquenodisponendelacapacidaddeteneraccesoalosarchivospornombre.Porejemplo,laorden

catx.cy.c

imprimeelcontenidodelosarchivosx.cyy.c(ynadamás)enlasalidaestándar.

Lapreguntaescómohacerquelosarchivosnombradosseanleídos—estoes,cómoconectarlasproposicionesqueleenlosdatos,conlosnombresexternosqueunusuariotieneenmente.

Lasreglassonsimples.Antesdequepuedaserleídooescrito,unarchivotienequeserabiertoporlafuncióndebibliotecafopen,lacualtomaunnombreexternocomox.coy.c,hacealgunosarreglosynegociacionesconelsistemaoperativo(cuyosdetallesnodebenimportarnos),yregresaunapuntadorqueseráusadoenposterioreslecturasoescriturasdelarchivo.

Esteapuntador,llamadoapuntadordearchivo,apuntaaunaestructuraquecontieneinformaciónacercadelarchivo,talcomolaubicacióndeunbuffer,laposicióndecarácteractualenelbuffer,sielarchivoestásiendoleídooescritoysihanocurridoerroresofindearchivo.Losusuariosnonecesitansaberlosdetalles,debidoaquelasdefinicionesobtenidasde<stdio.h>incluyenunadeclaracióndeestructurallamadaFILE.Laúnicadeclaraciónnecesariaparaunapuntadordearchivoseejemplificapor

FILE*fp;

FILE*fopen(char*nombre,char*modo);

EstodicequefpesunapuntadoraunFILE,yfopenregresaunapuntadoraFILE.NótesequeFILEesunnombredetipo,comoint,nounrótulodeestructura;estádefinidoconuntypedef.(LosdetallesdecómorealizarfopenenelsistemaUNIXseexplicanenlasección8.5.)

Lallamadaafopenenunprogramaes

fp=fopen(nombre,modo);

Elprimerargumentodefopenesunacadenadecaracteresquecontieneelnombredelarchivo.Elsegundoargumentoeselmodo,tambiénunacadenadecaracteres,queindicacómoseintentaemplearelarchivo.Losmodosdisponiblesincluyenlectura("r"),escritura("w"),yañadido("a").Algunossistemasdistinguenentrearchivosdetextoybinarios;paralosúltimos,debeescribirseuna"b"luegodelacadenademodo.

Page 228: Titivillus 07.07

Siunarchivoquenoexisteseabreparaescribiroañadir,secrea,siesposible.Abrirunarchivoexistenteparaescribirprovocaqueloscontenidosanterioresseandesechados,mientrasqueabrirloparaañadirlospreserva.Esunerrortratardeleerunarchivoquenoexiste,ytambiénpuedenhaberotrascausasdeerror,comotratardeleerunarchivocuandonosetienepermiso.Siexistecualquiererror,fopenregresaNULL.(Elerrorpuedeseridentificadoenformamásprecisa;véaseladiscusióndefuncionesparamanipulacióndeerroresalfinaldelasección1enelapéndiceB.)

Losiguientequeserequiereesunaformadeleeroescribirelarchivounavezqueestáabierto.Existenvariasposibilidades,delascualesgetcyputcsonlasmássimples,getcregresaelsiguientecarácterdeunarchivo;necesitaelapuntadordelarchivoparadecirlecuáles.

intgetc(FILE*fp)

getcregresaelsiguientecarácterdelflujoalqueserefierefp;regresaEOFsiocurrealgúnerror.

putcesunafunciónsalida:

intputc(intc,FILE*fp)

putcescribeelcaráctercenelarchivofpyregresaelcarácterescrito,oEOFsiocurreunerror.Talcomogetcharyputchar,getcyputcpuedensermacrosenlugardefunciones.

CuandosearrancaunprogramaenC,elmedioambientedelsistemaoperativoesresponsabledeabrirtresarchivosyproporcionarapuntadoresdearchivoparaellos.Estosarchivossonlaentradaestándar,lasalidaestándaryelerrorestándar;losapuntadoresdearchivocorrespondientessellamanstdin,stdoutystderr,yestándeclaradosen<stdio.h>.Normalmentestdinseconectaaltecladoystdoutystderrseconectanalapantalla,perostdinystdoutpuedenserredirigidosaarchivosoainterconexiones(pipes)comosedescribeenlasección7.1.

getcharyputcharpuedenestardefinidosentérminosdegetc,putc,stdinystdout,comosigue:

#definegetchar()getc(stdin)

#defineputchar(c)putc((c),stdout)

Paraentradaosalidadearchivosconformatosepuedenemplearlasfuncionesfscanfyfprintf.Estassonidénticasascanfyprintf,exceptoenqueelprimerargumentoesunapuntadordearchivoqueespecificaelarchivoqueseráleídooescrito;lacadenadeformatoeselsegundoargumento.

intfscanf(FILE*fp,char*formato,...)

intfprintf(FILE*fp,char*formato,...)

Habiendohechoaunladoestosprerrequisitos,yaestamosahoraenposicióndeescribirelprogramacat,queconcatenaarchivos.Eldiseñosehaencontradoconvenienteparamuchosprogramas.Siexistenargumentosenlalíneadeórdenes,seinterpretancomonombresdearchivos,yseprocesanenorden.Sinohayargumentos,seprocesalaentradaestándar.

#include<stdio.h>

Page 229: Titivillus 07.07

/*cat:concatenaarchivos,versión1*/

main(intargc,char*argv[])

{

FILE*fp;

voidfilecopy(FILE*,FILE*);

if(argc==1)/*sinargs;copialaentradaestándar*/

filecopy(stdin,stdout);

else

while(--argc>0)

if((fp=fopen(*++argv,"r"))==NULL){

printf("cat:nosepuedeabrir%s\n",*argv);

return1;

}else{

filecopy(fp,stdout);

fclose(fp);

}

return0;

}

/*filecopy:copiaelarchivoifpalarchivoofp*/

voidfilecopy(FILE*ifp,FILE*ofp)

{

intc;

while((c=getp(ifp))!=EOF)

putc(c,ofp);

}

LosapuntadoresdearchivostdinystdoutsonobjetosdetipoFILE*.Sinembargo,sonconstantes,novariables,porloquenoesposibleasignarlesalgo.

Lafunción

intfclose(FILE*fp)

Page 230: Titivillus 07.07

esloinversodefopen;interrumpelaconexiónquefueestablecidaporfopenentreelapuntadordearchivoyelnombreexterno,liberandoalapuntadordearchivoparaotroarchivo.Puestoquelamayoríadelossistemasoperativostienenalgunaslimitantessobreelnúmerodearchivosqueunprogramapuedetenerabiertossimultáneamente,esunabuenaidealiberarlosapuntadoresdearchivocuandoyanosonnecesarios,comosehizoencat.Tambiénhayotrarazónparausarfcloseenunarchivodesalida—vacíaelbufferenelcualputcestácolectandolasalida.Cuandounprogramaterminanormalmente,fcloseesllamadoautomáticamenteparacadaarchivoabierto.(Sepuedecerrarstdinystdoutsinosonnecesarios.Tambiénpuedenserreasignadosporlafuncióndebibliotecafreopen.)

Page 231: Titivillus 07.07

7.6.Manejodeerrores—stderryexit

Elmanejodeloserroresencatnoeselideal.Elproblemaesquesinosepuedeteneraccesoaunodelosarchivosporalgunarazón,eldiagnósticoseimprimealfinaldelasalidaconcatenada.Esopodríaseraceptablesilasalidavaalapantalla,peronosivahaciaunarchivoohaciaotroprogramamedianteunainterconexión.

Paramanejarmejorestasituación,seasignaunsegundoflujodesalida,llamadostderr,aunprogramaenlamismaformaenquestdinystdout.Lasalidaescritahaciastderrnormalmenteapareceenlapantalla,aunsilasalidaestándaresredirigida.

Corrijamoscatparaescribirsusmensajesdeerrorenelarchivodeerrorestándar.

#include<stdio.h>

/*cat:concatenaarchivos,versión2*/

main(intargc,char*argv[])

{

FILE*fp;

voidfilecopy(FILE*,FILE*);

char*prog=argv[0];/*nombredelprogramaparaerrores*/

if(argc==1)/*sinargs;copialaentradaestándar*/

filecopy(stdin,stdout);

else

while(--argc>0)

if((fp=fopen(*++argv,"r"))==NULL){

fprintf(stderr,“%s:nosepuedeabrir%s\n",

prog,*argv);

exit(1);

}else{

filecopy(fp,stdout);

fclose(fp);

}

if(ferror(stdout)){

Page 232: Titivillus 07.07

fprintf(stderr,"%s:erroralescribirstdout\n",prog);

exit(2);

}

exit(0);

}

Elprogramaseñalaerroresendosmaneras.Primero,lasalidadediagnósticosproducidaporfprintfvahaciastderr,demodoqueencuentrasucaminohacialapantallaenlugardedesaparecerenunainterconexiónodentrodeunarchivodesalida.Incluimoselnombredelprograma,tomándolodeargv[0],enelmensaje,paraquesiesteprogramaseusaconotros,seidentifiquelafuentedelerror.

Segundo,elprogramautilizalafuncióndebibliotecaestándarexit,queterminalaejecucióndeunprogramacuandoselellama.Elargumentodeexitestádisponibleparacualquierprocesoquehayallamadoaéste,paraquesepuedaprobareléxitoofracasodelprogramaporotroquelousecomosubproceso.Convencionalmente,unvalorderetorno0señalaquetodoestábien;losvaloresdiferentesdecerogeneralmenteseñalansituacionesanormales,exitllamaafcloseporcadaarchivodesalidaabierto,paravaciarcualquiersalidageneradaatravésdeunbuffer.

Dentrodemain,returnexpresequivalenteaexit(expr).exittienelaventajadequepuedeserllamadadesdeotrasfunciones,yquelasllamadasaellasepuedenencontrarconunprogramadebúsquedadepatronescomoeldelcapítulo5.

Lafunciónferrorregresaunvalordiferentedecerosiocurrióunerrorenelflujofp.

intferror(FILE*fp)

Aunqueloserroresdesalidasonraros,siocurren(porejemplo,siundiscosellena),porloquelosprogramasdeproduccióndebenrevisartambiénesto.

Lafunciónfeof(FILE*)esanálogaaferror;regresaunvalordiferentedecerosihaocurridounfindearchivoenelarchivoespecificado.

intfeof(FILE*fp)

Engeneral,nonoshemospreocupadoporelestadodelasalidadenuestrospequeñosprogramasilustrativos,perotodoprogramaseriodebetenercuidadoderegresarvaloresdeestadosensatosyútiles.

Page 233: Titivillus 07.07

7.7.Entradaysalidadelíneas

Labibliotecaestándarproporcionaunarutinadeentradafgets,essemejantealafuncióngetlinequehemosempleadoencapítulosanteriores:

char*fgets(char*línea,intmaxlínea,FILE*fp)

fgetsleelasiguientelínea(incluyendoelcarácternuevalínea)delarchivofpyladejaenelarreglodecaractereslínea;seleenhastamaxlínea-1caracteres.Lalínearesultanteseterminacon'\0'.Normalmente,fgetsregresalínea;encasodefindearchivoodeerror,regresaNULL.(Nuestragetlineregresalalongituddelalínea,queesunvalormásútil;cerosignificafindearchivo.)

Parasalida,lafunciónfputsescribeunacadena(quenonecesitacontenerunanuevalínea)aunarchivo:

intfputs(char*línea,FILE*fp)

EstafunciónregresaEOFsiocurreunerrorycerosinoocurre.

Lasfuncionesdebibliotecagetsyputssonsemejantesafgetsyfputs,perooperansobrestdinystdout.Demododesconcertante,getseliminael'\n'terminalyputsloagrega.

Paramostrarquenohaynadaespecialsobrefuncionescomofgetsyfputs,aquíestán,copiadasdelabibliotecaestándardenuestrosistema:

/*fgets:obtienehastancaracteresdeiop*/

char*fgets(char*s,intn,FILE*iop)

{

registerintc;

registerchar*cs;

cs=s;

while(--n>0&&(c=getc(iop))!=EOF)

if((*cs++=c)=='\n')

break;

*cs='\0';

return(c==EOF&&cs==s)?NULL:s;

}

/*fputs:colocalacadenasenelarchivoiop*/

Page 234: Titivillus 07.07

intfputs(char*s,FILE*iop)

{

intc;

while(c=*s++)

putc(c,iop);

returnferror(iop)?EOF:0;

}

Porrazonesquenosonobvias,elestándarespecificavaloresderetornodiferentesparafgetsyfputs.

Esfácilrealizarnuestrogetlineapartirdefgets:

/*getline:leeunalínea,regresasulongitud*/

intgetline(char*line,intmax)

{

if(fgets(line,max,stdin)==NULL)

return0;

else

returnstrlen(line);

}

Ejercicio7-6.Escribaunprogramaparacomparardosarchivos,imprimiendolaprimeralíneaendondedifieran.□

Ejercicio7-7.Modifiqueelprogramadebúsquedadeunpatróndelcapítulo5paraquetomesuentradadeunconjuntodearchivosnombradoso,sinohayarchivosnombradoscomoargumentos,delaentradaestándar.¿Debeescribirseelnombredelarchivocuandoseencuentraunalíneaquecoincide?□

Ejercicio7-8.Escribaunprogramaparaimprimirunconjuntodearchivos,iniciandocadanuevoarchivoenunapáginanueva,conuntítuloyuncontadordepáginaporcadaarchivo.□

Page 235: Titivillus 07.07

7.8.Otrasfunciones

Labibliotecaestándarproporcionaunaampliavariedaddefunciones.Estasecciónesunabrevesinopsisdelasmásútiles.EnelapéndiceBpuedenencontrarsemásdetallesymuchasotrasfunciones.

Page 236: Titivillus 07.07

7.8.1.Operacionessobrecadenas

Yahemosmencionadolasfuncionessobrecadenasstrlen,strcpy,strcat,ystrcmp,queseencuentranen<string.h>.Enadelante,sytsondetipochar*,ycynsonints.

strcat(s,t)

concatenatalfinaldes

strncat(s,t,n)

concatenancaracteresdetalfinaldes

strcmp(s,t)

regresanegativo,cero,opositivoparas<t,s==t,os>t

strncmp(s,t,n)

igualquestrcmpperosóloenlosprimerosncaracteres

strcpy(s,t)

copiatens

strncpy(s,t,n)

copiaalomásncaracteresdetas

strlen(s)

regresalalongituddes

strchr(s,c)

regresaunapuntadoralprimercqueestéens,oNULLsinoestápresente

strrchr(s,c)

regresaunapuntadoralúltimocqueestéens,oNULLsinoestápresente

Page 237: Titivillus 07.07

7.8.2.Pruebayconversióndeclasesdecaracteres

Variasfuncionesde<ctype.h>realizanpruebasyconversionesdecaracteres.Enloquesemuestraacontinuación,cesunintquesepuederepresentarcomoununsignedcharoEOF.Lasfuncionesregresanint.

isalpha(c)

diferentedecerosicesalfabética,0sinoloes

isupper(c)

diferentedecerosicesmayúscula,0sinoloes

islower(c)

diferentedecerosicesminúscula,0sinoloes

isdigit(c)

diferentedecerosicesundígito,0sinoloes

isalnum(c)

diferentedecerosiisalpha(c)oisdigit(c),0sinoloes

isspace(c)

diferentedecerosicesunblanco,tabulador,nuevalínea,retorno,avancedelíneaotabuladorvertical

toupper(c)

regresacconvertidaamayúscula

tolower(c)

regresacconvertidaaminúscula

Page 238: Titivillus 07.07

7.8.3.Ungetc

Labibliotecaestándarproporcionaunaversiónmásrestringidadelafunciónungetchqueescribimosenelcapítulo4;sellamaungetc.

intungetc(intc,FILE*fp)

colocaelcaráctercdenuevoenelarchivofpyregresac,oEOFencasodeerror.Sólosegarantizaponeruncarácterderegresoporarchivo.Esposibleutilizarungetcconcualquieradelasfuncionescomoscanf,getcogetchar.

Page 239: Titivillus 07.07

7.8.4.Ejecucióndeórdenes

Lafunciónsystem(char*s)ejecutalaordencontenidaenlacadenadecaracteress,ydespuéscontinúalaejecucióndelprogramaactual.Loscontenidosdesdependenfuertementedelsistemaoperativolocal.Comounejemplotrivial,ensistemasUNIX,laproposición

system("date");

provocaqueseejecuteelprogramadate,elcualimprimelafechayhoradeldíaenlasalidaestándar,systemregresadelcomandoejecutadounestadoenterodependientedelsistema.EnelsistemaUNIX,elestadoderetornoeselvalorregresadoporexit.

Page 240: Titivillus 07.07

7.8.5.Administracióndelalmacenamiento

Lasfuncionesmallocycallocobtienenbloquesdememoriadinámicamente.

voidmalloc(size_tn)

regresaunapuntadoranbytesdealmacenamientonoinicializado,oNULLsilapeticiónnosesatisface.

void*calloc(size_tn,size_tsize)

regresaunapuntadorasuficienteespacioparaalmacenarunarreglodenobjetosdeltamañoespecificado,oNULLsilapeticiónnosesatisface.Elespaciodealmacenamientoesinicializadoencero.

Elapuntadorregresadopormallococalloctienelaalineaciónapropiadaparaelobjetoencuestión,peroseledebehacerunaconversiónforzadaaltipoapropiado,comoen

int*ip;

ip=(int*)calloc(n,sizeof(int));

free(p)liberaelespacioapuntadoporp,dondepseobtuvooriginalmenteporunallamadaamallococalloc.Noexistenrestriccionessobreelordenenelqueseliberaelespacio,peroesungraveerrorelliberaralgonoobtenidoporunallamadaacallocomalloc.

Tambiénesunerrorusaralgodespuésdehabersidoliberado.Untípicoperoerróneofragmentodecódigoesestecicloqueliberaelementosdeunalista:

for(p=head;p!=NULL;p=p->next)/*INCORRECTO*/

free(p);

laformacorrectaesguardarlonecesarioantesdeliberar;

for(p=head;p!=NULL;p=q){

q=p->next;

free(p);

}

Lasección8.7muestralarealizacióndeunasignadordealmacenamientocomomalloc,enelcuallosbloquesasignadossepuedenliberarencualquierorden.

Page 241: Titivillus 07.07

7.8.6.Funcionesmatemáticas

Existenmásdeveintefuncionesmatemáticasdeclaradasen<math.h>;aquíestánalgunasdelasempleadasconmásfrecuencia.Cadaunatomaunoodosargumentosdoubleyregresaundouble.

sin(

x

)

senode

x

,

x

enradianes

cos(

x

)

cosenode

x

,

x

enradianes

atan2(

y

,

x

)

arcotangentede

y/x

,enradianes

Page 242: Titivillus 07.07

exp(

x

)

funciónexponencial

ex

log(

x

)

logaritmonatural(base

e

)de

x

(

x

>0)

log10(

x

)

logaritmocomún(base10)de

x

(

x

>0)

pow(

x

,

y

)

Page 243: Titivillus 07.07

xy

sqrt(

x

)

raízcuadradade

x

(

x

≥0)

fabs(

x

)

valorabsolutode

x

Page 244: Titivillus 07.07

7.8.7.Generacióndenúmerosaleatorios

Lafunciónrand()calculaunasecuenciadeenterospseudoaleatoriosenelrangodeceroaRAND_MAX,queestádefinidoen<stdlib.h>.Unaformadeproducirnúmerosaleatoriosdepuntoflotantemayoresoigualesaceroperomenoresqueunoes

#definefrand()((double)rand()/(RAND_MAX+1))

(Sisubibliotecayaproporcionaunafunciónparanúmerosaleatoriosdepuntoflotante,esprobablequetengamejorespropiedadesestadísticasqueésta.)

Lafunciónsrand(unsigned)fijalasemillapararand.Laimplantaciónportátilderandydesrandsugeridaporelestándarapareceenlasección2.7.

Ejercicio7-9.Sepuedenescribirfuncionescomoisupperparaahorrarespaciootiempo.Exploreambasposibilidades.□

Page 245: Titivillus 07.07

CAPÍTULO8:LainterfazconelsistemaUNIX

ElsistemaoperativoUNIXproporcionasusserviciosatravésdeunconjuntodellamadasalsistema,queconsistenenfuncionesqueestándentrodelsistemaoperativoyquepuedenserinvocadasporprogramasdelusuario.EstecapítulodescribecómoemplearalgunasdelasmásimportantesllamadasalsistemadesdeprogramasenC.SiellectorusaUNIX,estodebeserledirectamenteútil,debidoaquealgunasvecesesnecesarioemplearllamadasalsistemaparatenermáximaeficiencia,oparateneraccesoaalgunafacilidadquenoestéenlabiblioteca.Incluso,siseempleaCenunsistemaoperativodiferenteellectordeberíasercapazdeadentrarseenlaprogramaciónestudiandoestosejemplos;aunquelosdetallesvarían,seencontraráuncódigosemejanteencualquiersistema.PuestoquelabibliotecadeCANSIestáenmuchoscasosmodeladaconbaseenlasfacilidadesdeUNIX,estecódigopuedeayudartambiénasuentendimiento.

Elcapítuloestádivididoentrespartesfundamentales:entrada/salida,sistemadearchivosyasignacióndealmacenamiento.LasprimerasdospartessuponenunamodestafamiliaridadconlascaracterísticasexternasdelossistemasUNIX.

Elcapítulo7tuvoqueverconunainterfazdeentrada/salidauniformeentresistemasoperativos.Encualquiersistemalasrutinasdelabibliotecaestándarsetienenqueescribirentérminosdelasfacilidadesproporcionadasporelsistemaanfitrión.EnlasseccionesdeestecapítulodescribiremoslasllamadasalsistemaUNIXparaentradaysalida,ymostraremoscómopuedeescribirsepartedelabibliotecaestándarconellas.

Page 246: Titivillus 07.07

8.1.Descriptoresdearchivos

EnelsistemaoperativoUNIX,todaslasentradasysalidasserealizanporlalecturaoescrituradearchivos,debidoaquelosdispositivosperiféricos,auneltecladoylapantalla,sonarchivosqueestánenelsistema.Estosignificaqueunasencillainterfazhomogéneamanejatodaslascomunicacionesentreunprogramaylosdispositivosperiféricos.

Enelcasomásgeneral,antesdeleeroescribirunarchivo,primerosedebeinformaralsistemaacercadelaintencióndehacerlo,medianteelprocesollamadoabrirunarchivo.Sisevaaescribirenunarchivotambiénpuedesernecesariocrearloodescartarelcontenidoprevio.Elsistemaverificalosderechosdehacertalcosa(¿Elarchivoexiste?¿tienepermisodehaceraccesoaél?)y,sitodoestácorrecto,regresaalprogramaunpequeñoenterononegativollamadodescriptordearchivo.Siemprequesevanaefectuaraccionesdeentradaysalidasobreesearchivo,seusaeldescriptordearchivoparaidentificarloenlugardelnombre.(UndescriptordearchivoesanálogoalapuntadordearchivousadoporlabibliotecaestándaroalmanipuladordearchivodeMS-DOS.)Todalainformaciónacercadeunarchivoabiertoesmantenidaporelsistema;elprogramadelusuarioserefierealarchivosóloporeldescriptor.

Puestoqueestancomúnquelaentradaylasalidainvolucrenaltecladoyalapantalla,existenarreglosespecialesparahacerestoconvenientemente.Cuandoelintérpretedecomandos(el“shell”)ejecutaunprogramaseabrentresarchivos,condescriptores0,1,2,llamadosentradaestándar,salidaestándaryerrorestándar.Siunprogramaleede0yescribea1ya2,puedehacerentradaysalidasinpreocuparsedeabrirarchivos.

ElusuariodeunprogramapuederedirigirlaE/Shaciaydesdearchivoscon<y>:

prog<archent>archsal

Enestecaso,shellcambialasasignacionespredefinidasparalosdescriptores0y1alosarchivosnombrados.Normalmenteeldescriptordearchivo2permaneceasignadoalapantalla,paraquelosmensajesdeerrorpuedanirhaciaallá.Observacionessemejantesseaplicanparalaentradaysalidaasociadaconunainterconexión.Entodosloscasos,laasignacióndearchivoslacambiashell,noelprograma.Elprogramanosabededóndeprovienesuentradanihaciadóndevasusalida,mientrasusealarchivo0paraentraday1y2parasalida.

Page 247: Titivillus 07.07

8.2.E/Sdebajonivel—readywrite

Laentradaysalidausalasllamadasalsistemareadywrite,alasquesetieneaccesodesdeprogramasescritosenCatravésdedosfuncionesllamadasreadywrite.Paraambas,elprimerargumentoesundescriptordearchivo.Elsegundoargumentoesunarreglodecaracterespertenecientealprogramahaciaodedondelosdatosvanairovenir.Eltercerargumentoeselnúmerodebytesqueserántransferidos.

intn_leídos=read(intfd,char,*buf,intn);

intn_escritos=write(intid,char*buf,intn);

Cadallamadaregresaunacuentadelnúmerodebytestransferidos.Enlalectura,elnúmerodebytesregresadospuedesermenorqueelnúmerosolicitado.Unvalorderegresodecerobytesimplicafindearchivoy-1indicaunerrordealgúntipo.Paraescritura,elvalorderetornoeselnúmerodebytesescritos:siéstenoesigualalnúmerosolicitado,haocurridounerror.

Enunallamadapuedenleersecualquiernúmerodebytes.Losvaloresmáscomunesson1,quesignificauncarácteralavez(sinbuffer),yunnúmerocomo1024o4098,quecorrespondealtamañodeunbloquefísicodeundispositivoperiférico.Losvaloresmayoresseránmáseficientesdebidoaqueseránrealizadasmenosllamadasalsistema.

Parajuntarestostemas,podemosescribirunsencilloprogramaquecopiesuentradaasusalida,elequivalentedelprogramacopiadordearchivosescritoparaelcapítulo1.Esteprogramacopiarácualquiercosaacualquiercosa,yaquelaentradaylasalidapuedenserredirigidashaciacualquierarchivoodispositivo.

#include"syscalls.h"

main()/*copialaentradaalasalida*/

{

charbuf[BUFSIZ];

intn;

while((n=read(0,buf,BUFSIZ))>0)

write(1,buf,n);

return0;

}

Hemosreunidoprototiposdefuncionesparalasllamadasalsistemaenunarchivollamadosyscalls.h,demodoquepodamosincluirloenlosprogramasdeestecapítulo.Sinembargo,estenombrenoesestándar.

ElparámetroBUFSIZtambiénestádefinidodentrodesyscalls.h;suvaloresuntamañoadecuadoparaelsistemalocal.SieltamañodelarchivonoesunmúltiplodeBUFSIZ,algúnreadregresaráunnúmeromenordebytesaserescritosporwrite;lasiguiente

Page 248: Titivillus 07.07

llamadaareaddespuésdeesoregresarácero.

Esinstructivovercómosepuedenusarreadywriteparaconstruirrutinasdealtonivelcomogetchar,putchar,etc.Porejemplo,aquíestáunaversióndegetcharquerealizaentradasinbuffer,leyendodelaentradaestándaruncarácteralavez.

#include"syscalls.h"

/*getchar:entradadeuncaráctersimplesinbuffer*/

intgetchar(void)

{

charc;

return(read(0,&c,1)==1)?(unsignedchar)c:EOF;

}

cdebeserunchar,aquereadnecesitaunapuntadoracarácter.Forzarcaserunsignedcharenlaproposiciónderegresoeliminacualquierproblemadeextensióndesigno.

Lasegundaversióndegetcharhacelaentradaengrandesfragmentosysacaloscaracteresunoalavez.

#include"syscalls.h"

/*getchar:versiónconbuffersimple*/

intgetchar(void)

{

staticcharbuf[BUFSIZ];

staticchar*bufp=buf;

staticintn=0;

if(n==0){/*elbufferestávacío*/

n=read(0,buf,sizeofbuf);

bufp=buf;

}

return(--n>=0)?(unsignedchar)*bufp++:EOF;

}

Siestaversióndegetcharfueseasercompiladacon<stdio.h>incluida,seríanecesarioeliminarladefinicióndelnombregetcharcon#undefencasodequeestéimplantadacomounamacro.

Page 249: Titivillus 07.07

8.3.Open,creat,close,unlink

Ademásdelaentrada,lasalidayelerrorestándar,sepuedenabrirexplícitamentearchivosparaleerlosoescribirlos.Existendosllamadasalsistemaparaesto,openycreat.[1]

openescomoelfopenexpuestoenelcapítulo7,exceptoqueenlugarderegresarunapuntadordearchivo,regresaundescriptordearchivo,queestansólounint.openregresa-1siocurrealgúnerror.

#include<fcntl.h>

intfd;

intopen(char*nombre,intflags,intperms);

fd=open(nombre,flags,perms);

Comoconfopen,elargumentonombreesunacadenadecaracteresquecontieneelnombredelarchivo.Elsegundoargumento,flags,esunintqueespecificacómoseráabiertoelarchivo;losprincipalesvaloresson

O_RDONLY

abrirsóloparalectura

O_WRONLY

abrirsóloparaescritura

O_RDWR

abrirparalecturayescritura

Estasconstantesestándefinidasen<fcntl.h>ensistemasUNIXSystemV,yen<sys/file.h>enversionesBerkeley(BSD).

Paraabrirunarchivoyaexistenteparalectura,

id=open(nombre,O_RDONLY,0);

Elargumentopermsessiempreceroparalosusosdeopenquediscutiremos.

Esunerrortratardeabrirunarchivoquenoexiste.Paracrearnuevosarchivosoreescribiranteriores,seproporcionalallamadaalsistemacreat.

intcreat(char*nombre,intperms);

fd=creat(nombre,perms);

regresaundescriptordearchivosifuecapazdecrearelarchivo,y-1sinolofue.Sielarchivoyaexiste,creatlotruncaráalongitudceroyportantodescartarásucontenidoprevio;noesunerrorcrearcreatunarchivoqueyaexiste.

Page 250: Titivillus 07.07

Sielarchivonoexiste,creatlocreaconlospermisosespecificadosporelargumentoperms.EnelsistemadearchivosdeUNIXhaynuevebitsparainformacióndepermisosasociadosconunarchivo,quecontrolanelaccesoalalectura,escriturayejecuciónparaelpropietariodelarchivo,paraelgrupodelpropietarioyparatodoslosdemás.Así,unnúmerooctaldetresdígitosesconvenienteparaespecificarlospermisos.Porejemplo,0755especificapermisosparaleer,escribiryejecutarparaelpropietario,yleeryejecutarparaelgrupoyparacualquierotro.

Parailustrarlo,aquíestáunaversiónsimplificadadelprogramacpdeUNIX,quecopiaunarchivoaotro.Nuestraversióncopiasólounarchivo,nopermitequeelsegundoargumentoseaundirectorioeinventalospermisosenlugardecopiarlos.

#include<stdio.h>

#include<fcntl.h>

#include"syscalls.h"

#definePERMS0666/*lecturayescrituraparapropietario,grupoyotros*/

voiderror(char*,...);

/*cp:copiaf1af2*/

main(intargc,char*argv[])

{

intf1,f2,n;

charbuf[BUFSIZ];

if(argc!=3)

error("Uso:cpdehacia");

if((f1=open(argv[l],O_RDONLY,0))==-1)

error("cp:nosepuedeabrir%s",argv[l]);

if((f2=creat(argv[2],PERMS))==-1)

error("cp:nosepuedecrear%s,modo%03o",argv[2],PERMS);

while((n=read(f1,buf,BUFSIZ))>0)

if(write(f2,buf,n)!=n)

error("cp:errordeescrituraenelarchivo%s",argv[2]);

return0;

}

Esteprogramacreaelarchivodesalidaconpermisosfijos0666.Conlallamadaalsistemastat,descritaenlasección8.6,podemosdeterminarelmododeunarchivo

Page 251: Titivillus 07.07

existenteyasídarelmismomodoalacopia.

Nótesequelafunciónerroresinvocadaconunalistavariabledeargumentosmuysemejantealadeprintf.Larealizacióndeerrorilustracómoutilizarotrosmiembrosdelafamiliaprintf.Lafuncióndebibliotecaestándarvprintfescomoprintf,exceptoquelalistavariabledeargumentosesreemplazadaporunsoloargumentoquehasidoinicializadollamandoalamacrova_start.Enformasemejante,vfprintfyvsprintfcoincidenconfprintfysprintf.

#include<stdio.h>

#include<stdarg.h>

/*error:imprimeunmensajedeerrorymuere*/

voiderror(char*fmt,...)

{

va_listargs;

va_start(args,fmt);

fprintf(stderr,"error:");

vfprintf(stderr,fmt,args);

fprintf(stderr,"\n");

va_end(args);

exit(l);

}

Existeunlímite(regularmente20)enelnúmerodearchivosqueunprogramapuedetenerabiertossimultáneamente.Deacuerdoconesto,unprogramaqueintenteprocesarmuchosarchivosdebeserpreparadoparareutilizardescriptoresdearchivo.Lafunciónclose(intfd)suspendelaconexiónentreundescriptordearchivoyunarchivoabierto,yliberaaldescriptordearchivoparaserutilizadoconalgúnotroarchivo;correspondeafclosedelabibliotecaestándarexceptoenquenoexisteunbufferquevaciar.Laterminacióndeunprogramavíaexitoreturndesdeelprogramaprincipalcierratodoslosarchivosabiertos.

Lafunciónunlink(char*nombre)remueveelarchivonombredelsistemadearchivos.Correspondealafuncióndelabibliotecaestándarremove.

Ejercicio8-1.Reescribaelprogramacatdelcapítulo7usandoread,write,openyclose,enlugardesusequivalentesdelabibliotecaestándar.Hagaexperimentosparadeterminarlavelocidadrelativadelasdosversiones.□

Page 252: Titivillus 07.07

8.4.Accesoaleatorio—lseek

Laentradaylasalidasonnormalmentesecuenciales:cadareadowriteocurreenunaposicióndelarchivojustodespuésdelaanterior.Sinembargo,cuandoesnecesario,unarchivosepuedeleeroescribirencualquierordenarbitrario.Lallamadaalsistemalseekproporcionaunaformademoverseenunarchivosinleeroescribirningúndato:

longlseek(intfd,longoffset,intorigen);

fijaenoffsetlaposiciónactualenelarchivocuyodescriptoresfd,quesetomarelativoalalocalizaciónespecificadapororigen.Unalecturaoescrituraposteriorprincipiaráenesaposición,origenpuedeser0,1o2paraespecificarqueeldesplazamientooffsetserámedidodesdeelprincipio,desdelaposiciónactual,odesdeelfindelarchivo,respectivamente.Porejemplo,paraagregaraunarchivo(laredirección>>enelshelldeUNIX,o"a"defopen),hayqueiralfinalantesdeescribir:

lseek(fd,0L,2);

Pararegresaralprincipio(“rebobinar”),

lseek(fd,0L,0);

Nóteseelargumento0L;tambiénpodríaserescritocomo(long)0osólocomo0silseekestádeclaradoadecuadamente.

Conlseek,esposibletrataralosarchivosmásomenoscomoarreglosextensos,alpreciodeunaccesomáslento.Porejemplo,lasiguientefunciónleecualquiernúmerodebytesencualquierlugararbitrariodeunarchivo.Regresaelnúmeroleído,o-1encasodeerror.

#include"syscalls.h"

/*get:leenbytesdelaposiciónpos*/

intget(intfd,longpos,char*buf,intn)

{

if(lseef(fd,pos,0)>=0)/*sesitúaenpos*/

returnread(fd,buf,n);

else

return-1;

}

Elvalorderegresodelseekesunlongquedalanuevaposiciónenelarchivo,o-1siocurreunerror.Lafuncióndebibliotecaestándarfseekessemejantealseek,exceptoenqueelprimerargumentoesunFILE*yelvalorderegresoesdiferentedecerosiocurrióunerror.

Page 253: Titivillus 07.07

8.5.Ejemplo—unarealizacióndefopenygetc

Ilustremosahoracómoalgunasdeestaspiezasquedanjuntas,mostrandounarealizacióndelasrutinasfopenygetcdelabibliotecaestándar.

Recuérdesequelosarchivosenlabibliotecaestándarsondescritosporapuntadoresdearchivosenvezdecondescriptoresdearchivo.Unapuntadordearchivoesunapuntadoraunaestructuraquecontieneinformaciónvariaacercadelarchivo:unapuntadoraunbuffer,paraqueelarchivopuedaserleídoengrandesfragmentos;unacuentadelnúmerodecaracteresquequedanenelbuffer;unapuntadoralaposicióndelsiguientecarácterenelbuffer;eldescriptordearchivo,ybanderasquedescribenelmododelectura/escritura,estadodeerror,etcétera.

Laestructuradedatosquedescribeunarchivoestácontenidaen<stdio.h>,quesedebeincluir(con#include)encualquierarchivofuentequeutilicerutinasdelabibliotecadeentrada/salidaestándar.Tambiénestáincluidoenlasfuncionesdelabiblioteca.Enelsiguientefragmentodeun<stdio.h>típico,losnombresqueseintentaemplearsóloenlasfuncionesdelabibliotecaestándarprincipianconunsubguión,porloquesonmenossusceptiblesdetenerconflictoconnombresenlosprogramasdelusuario.Estaconvenciónlaempleantodaslasrutinasdelabibliotecaestándar.

#defineNULL0

#defineEOF(-1)

#defineBUFSIZ1024

#defineOPEN_MAX20/*máximonúmerodearchivosabiertosalavez*/

typedefstruct_iobuf{

intcnt;/*caracteresquequedan*/

char*ptr;/*posicióndelsiguientecarácter*/

char*base;/*localizacióndelbuffer*/

intflag;/*mododeaccesoalarchivo*/

intfd;/*descriptordearchivo*/

}FILE;

externFILE_iob[OPEN_MAX];

#definestdin(&_iob[0])

#definestdout(&_iob[1])

#definestderr(&_iob[2])

enum_flags{

Page 254: Titivillus 07.07

_READ=01,/*archivoabiertoparalectura*/

_WRITE=02,/*archivoabiertoparaescritura*/

_UNBUF=04,/*archivosinbuffer*/

_EOF=010,/*ocurriófindearchivo(EOF)enestearchivo*/

_ERR=020/*ocurrióunerrorenestearchivo*/

};

int_fillbuf(FILE*);

int_flushbuf(int,FILE*);

#definefeof(p)(((p)->flag&_EOF)!=0)

#defineferror(p)(((p)->flag&_ERR)!=0)

#definefileno(p)((p)->fd)

#definegetc(p)(--(p)->cnt>=0\

?(unsignedchar)*(p)->ptr++:_fillbuf(p))

#defineputc(x,p)(--(p)->cnt>=0\

?*(p)->ptr++=(x):_flushbuf((x),p))

#definegetchar()getc(stdin)

#defineputchar(x)putc((x),stdout)

Lamacrogetcnormalmentedecrementalacuenta,avanzaelapuntadoryregresaelcarácter.(Recuerdequeun#definelargosecontinúaconunadiagonalinvertida.)Silacuentasehacenegativa,sinembargo,getcllamaalafunción_fillbufparallevarelbuffer,reinicializaelcontenidodelaestructura,yregresauncarácter.Loscaracteressondevueltosunsigned,loqueaseguraquetodosloscaracteresseránpositivos.

Aunquenodiscutiremosningúndetalle,hemosincluidoladefinicióndeputcparamostrarqueoperaenformamuysemejanteagetc,llamandoaunafunción_flushbufcuandosubufferestálleno.Tambiénhemosincluidomacrosparateneraccesoalestadodeerror,findearchivo,yaldescriptordelmismo.

Ahorapuedeescribirselafunciónfopen.Lamayorpartedefopentienequevercontenerelarchivoabiertoycolocadoenellugarcorrecto,yconfijarlosbitsdelabanderaflagparaindicarelestadoapropiado,fopennoasignaningúnespacioparaelbuffer;estoesrealizadopor_fillbufcuandoelarchivoseleeporprimeravez.

#include<fcntl.h>

#include"syscalls.h"

#definePERMS0666/*lecturayescrituraparapropietario,grupo,otros*/

/*fopen:abreunarchivo,regresaunapuntadordearchivo*/

Page 255: Titivillus 07.07

FILE*fopen(char*name,char*mode)

{

intfd;

FILE*fp;

if(*mode!='r'&&*mode!='w'&&*mode!='a')

returnNULL;

for(fp=_iob;fp<_iob+OPEN_MAX;fp++)

if((fp->flag&(_READ|_WRITE))==0)

break;/*seencontróunaentradalibre*/

if(fp>=_iob+OPEN_MAX)/*nohayentradaslibres*/

returnNULL;

if(*mode=='w')

fd=creat(name,PERMS);

elseif(*mode=='a'){

if((fd=open(name,O_WRONLY,0))==-1)

fd=creat(name,PERMS);

lseek(fd,0L,2);

}else

fd=open(name,O_RDONLY,0);

if(fd==-1)/*nohuboaccesoalnombre*/

returnNULL;

fp->fd=fd;

fp->cnt=0;

fp->base=NULL;

fp->flag=(*mode=='r')?_READ:_WRITE;

returnfp;

}

Estaversióndefopennomanejatodaslasposibilidadesdemodosdeaccesodelestándar,aunqueelagregarlasnosellevaríamuchocódigo.Enparticular,nuestra

Page 256: Titivillus 07.07

fopennoreconocela“b”queindicaaccesobinario,yaqueesonotienesignificadoensistemasUNIX,niel“+”quepermitetantolecturacomoescritura.

Laprimerallamadaagetcparaunarchivoenparticularencuentraunacuentadecero,loqueobligaaunallamadaa_fillbuf.Si_fillbufencuentraqueelarchivonoestáabiertoparalectura,regresaEOFdeinmediato.Deotraforma,tratadeasignarunbuffer(silalecturaseráconbuffer).

Unavezqueelbufferhasidoestablecido,_fillbufllamaareadparallenarlo,fijalacuentaylosapuntadores,yregresaelcarácterdelprincipiodelbuffer.Lasposterioresllamadasa_fillbufencontraránunbufferasignado.

#include"syscalls.h"

/*_fillbuf:asignayllenaunbufferdeentrada*/

int_fillbuf(FILE*fp)

{

intbufsize;

if((fp->flag&(_READ|_EOF_ERR))!=_READ)

returnEOF;

bufsize=(fp->flag&_UNBUF)?1:BUFSIZ;

if(fp->base==NULL)/*sinbufferaún*/

if((fp->base=(char*)malloc(bufsize))==NULL)

returnEOF;/*nopuedeobtenerunbuffer*/

fp->ptr=fp->base;

fp->cnt=read(fp->fd,fp->ptr,bufsize);

if(--fp->cnt<0){

if(fp->cnt==-1)

fp->flag|=_EOF;

else

fp->flag|=_ERR;

fp->cnt=0;

returnEOF;

}

return(unsignedchar)*fp->ptr++;

}

Page 257: Titivillus 07.07

Elúnicocabosueltoescómoarrancartodo.Elarreglo_iobdebeserdefinidoeinicializadoparastdin,stdoutystderr:

FILE_iob[OPEN_MAX]={/*stdin,stdout,stderr:*/

{0,(char*)0,(char*)0,_READ,0},

{0,(char*)0,(char*)0,_WRITE,1},

{0,(char*)0,(char*)0,_WRITE|_UNBUF,2}

};

Lainicializacióndelaparteflagdelaestructuramuestraquestdinseráleído,stdoutseráescrito,ystderrseráescritosinbuffer.

Ejercicio8-2.Reescribafopeny_fillbufconcamposenvezdeoperacionesexplícitasdebits.Compareeltamañodelcódigoylavelocidaddeejecución.□

Ejercicio8-3.Diseñeyescriba_flushbuf,fflush,yfclose.□

Ejercicio8-4.Lafuncióndebibliotecaestándar

intfseek(FILE*fp,longoffset,intorigen)

esidénticaalseekexceptoquefpesunapuntadordearchivoenvezdeundescriptordearchivo,yelvalorregresadoesunestadoint,nounaposición.Escribafseek.Asegúresedequesufseeksecoordinaapropiadamenteconelmanejodebuffersrealizadoporlasotrasfuncionesdelabiblioteca.□

Page 258: Titivillus 07.07

8.6.Ejemplo—listadodedirectorios

Algunasvecesserequiereunaformadiferentedeinteracciónconelsistemadearchivos,paradeterminarinformaciónacercadeunarchivo,noloquecontiene.UnprogramaquelistaundirectoriotalcomolaordenlsdeUNIXesunejemplo—imprimelosnombresdelosarchivosqueestáneneldirectorio,y,enformaoptativa,másinformación,talcomotamaños,permisosyesascosas.LaordendirdeMS-DOSesanáloga.

ComoundirectoriodeUNIXessimplementeunarchivo,lssólonecesitaleerloparaobtenerlosnombresdearchivos.Peroesnecesarioutilizarunallamadaalsistemaparateneraccesoalaotrainformaciónacercadelarchivo,talcomosutamaño.Enotrossistemaspuedesernecesariaunallamadaalsistemainclusoparalosnombresdelosarchivos;ésteeselcasodeMS-DOS,porejemplo.Loquenosotrosqueremosesproporcionaraccesoalainformaciónenunaformarelativamenteindependientedelsistema,apesarinclusodequelarealizaciónpuedaseraltamentedependientedelsistema.

Ilustraremosalgodeestoescribiendounprogramallamadofsize.fsizeesunaformaespecialdelsqueimprimelostamañosdetodoslosarchivosnombradosensulistadeargumentos.Siunodelosarchivosesundirectoriofsizeseaplicaenformarecursivaparaesedirectorio.Sinohayningúnargumento,procesaeldirectorioactual.

PrincipiemosconunabreverevisióndelaestructuradelsistemadearchivosdeUNIX.Undirectorioesunarchivoquecontieneunalistadenombresdearchivoyalgunasindicacionesdedóndeselocalizan.La“localización”esuníndiceenotratablallamadala“listadenodos-i”.Elnodo-iparaunarchivoesdondesemantienetodalainformaciónacercadeunarchivo,exceptosunombre.Unaentradaeneldirectorioconsistegeneralmenteensólodosítems,elnombredelarchivoyelnúmerodenodo-i.

Desafortunadamente,elformatoyelcontenidoprecisodeundirectorionoeselmismoentodaslasversionesdelsistema.Demodoquedividiremoslatareaendospartesparatratardeaislarlaspartesnotransportables.ElnivelmásexternodefineunaestructurallamadaDirentytresrutinas,opendir,readdir,yclosedirparaproporcionaraccesoindependientedelsistemaalnombreynúmerodenodo-ienunaentradadeldirectorio.Escribiremosfsizeconestainterfaz.DespuésmostraremoscómohacerestoensistemasqueusanlamismaestructuradedirectoriosqueUNIXVersión7,ySystemV;lasvariantessondejadascomoejercicios.

LaestructuraDirentcontieneelnúmerodenodo-iyelnombre.LalongitudmáximadeuncomponentedelnombredearchivoesNAME_MAX,queesunvalordependientedelsistema,opendirregresaunapuntadoraunaestructurallamadaDIR,análogaaFILE,queesempleadaporreaddiryclosedir.Lainformaciónesrecolectadaenunarchivollamadodirent.h.

#defineNAME_MAX14/*componentedenombredearchivomásgrande;dependientedelsistema*/

typedefstruct{/*entradadedirectoriotransportable:*/

longino;/*númerodenodo-i*/

charname[NAME_MAX+1];/*nombre+terminador'\0'*/

Page 259: Titivillus 07.07

}Dirent;

typedefstruct{/*DIRmínima:sinbuffer,etc.*/

intfd;/*descriptordearchivoparaeldirectorio*/

Direntd;/*laentradadeldirectorio*/

}DIR;

DIR*opendir(char*dirname);

Dirent*readdir(DIR*dfd);

voidclosedir(DIR*dfd);

Lallamadaalsistemastattomaunnombredearchivoyregresatodalainformaciónqueestáenelnodo-iparaesearchivo,o-1siexisteunerror.Estoes,

char*nombre;

structstatstbuf;

intstat(char*,structstat*);

stat(nombre,&stbuf);

llenalaestructurastbufconlainformacióndelnodo-iparaelnombredearchivo.Laestructuraquedescribeelvalorregresadoporstatestáen<sys/stat.h>,ytípicamenteseveasí:

structstat/*informacióndenodo-iregresadaporstat*/

{

dev_tst_dev;/*dispositivodenodo-i*/

ino_tst_ino;/*númerodenodo-i*/

shortst_mode;/*bitsdemodo*/

shortst_nlink;/*númerodeligasalarchivo*/

shortst_uid;/*id.deusuariodelpropietario*/

shortst_gid;/*id.degrupodelpropietario*/

dev_tst_rdev;/*paraarchivosespeciales*/

off_tst_size;/*tamañodelarchivoencaracteres*/

time_tst_atime;/*horadelúltimoacceso*/

time_tst_mtime;/*horadelaúltimamodificación*/

time_tst_ctime;/*horadecreaciónoriginal*/

Page 260: Titivillus 07.07

}

Lamayoríadeestosvaloressonexplicadosporloscamposdecomentario.Lostiposcomodev_tyino_testándefinidosen<sys/types.h>,quetambiéndebeserincluido.

Laentradast_modecontieneunconjuntodebanderasquedescribenelarchivo.Ladefinicióndebanderasestátambiénincluidaen<sys/stat.h>;sólorequerimosdelapartequetienequeverconeltipodearchivo

#defineS_IFMT0160000/*tipodearchivo*/

#defineS_IFDIR0040000/*directorio*/

#defineS_IFCHR0020000/*especialdecaracteres*/

#defineS_IFBLK0060000/*especialdebloques*/

#defineS_IFREG0100000/*regular*/

/*...*/

Ahoraestamoslistosparaescribirelprogramafsize.Sielmodoobtenidodestatindicaqueunarchivonoesundirectorio,entonceseltamañoestáalamanoypuedeserimpresodirectamente.Sielarchivoesundirectorio,sinembargo,entoncestenemosqueprocesaresedirectoriounarchivoalavez;puedeasuvezcontenersubdirectorios,demodoqueelprocesoesrecursivo.

Larutinaprincipaltrataconlosargumentosdelalíneadeórdenes;pasacadaargumentoalafunciónfsize.

#include<stdio.h>

#include<string.h>

#include"syscalls.h"

#include<fcntl.h>/*banderasparalecturayescritura*/

#include<sys/types.h>/*typedefs*/

#include<sys/stat.h>/*estructuraregresadaporstat*/

#include"dirent.h"

voidfsize(char*);

/*imprimetamañosdearchivos*/

main(intargc,char**argv)

{

if(argc==1)/*default:directorioactual*/

fsize(".");

Page 261: Titivillus 07.07

else

while(--argc>0)

fsize(*++argv);

return0;

}

Lafunciónfsizeimprimeeltamañodelarchivo.Sinembargo,sielarchivoesundirectorio,fsizellamaprimeroadirwalkparamanejartodoslosarchivosenél.NotecomoseusanlosnombresdelasbanderasS_IFMTyS_IFDIRde<sys/stat.h>paradecidirsielarchivoesundirectorio.Elusodelosparéntesisimporta,debidoaquelaprecedenciade&esinferiorquelade==.

intstat(char*,structstat*);

voiddirwalk(char*,void(*fcn)(char*));

/*fsize:imprimeeltamañodelarchivo"name"*/

voidfsize(char*name)

{

structstatstbuf;

if(stat(name,&stbuf)==-1){

fprintf(stderr,"fsize:nosetieneaccesoa%s\n",name);

return;

}

if((stbuf.st_mode&S_IFMT)==S_IFDIR)

dirwalk(name,fsize);

printf("%81d%s\n",stbuf.st_size,name);

}

Lafuncióndirwalkesunarutinadepropósitogeneralqueaplicaunafunciónacadaarchivoqueestádentrodeundirectorio.Abreeldirectorio,iteracontodoslosarchivosquehayenél,llamandoencadaunoalafunción;despuéscierraeldirectorioyregresa.Puestoquefsizellamaadirwalkencadadirectorio,lasdosfuncionessellamanrecursivamenteunaalaotra.

#defineMAX_PATH1024

/*dirwalk:aplicafcnatodoslosarchivosdedir*/

voiddirwalk(char*dir,void(*fcn)(char*))

Page 262: Titivillus 07.07

{

charname[MAX_PATH];

Dirent*dp;

DIR*dfd;

if((dfd=opendir(dir))==NULL){

fprintf(stderr,"dirwalk:nosepuedeabrir%s\n",dir);

return;

}

while((dp=readdir(dfd))!=NULL){

if(strcmp(dp->name,".")==0

||strcmp(dp->name,"..")==0)

continue;/*seignoraasimismoyasupadre*/

if(strlen(dir)+strlen(dp->name)+2>sizeof(name))

fprintf(stderr,"dirwalk:nombre%s/%sdemasiadolargo\n",

dir,dp->name);

else{

sprintf(name,"%s/%s",dir,dp->name);

(*fcn)(name);

}

}

closedir(dfd);

}

Cadallamadaareaddirregresaunapuntadorainformaciónparaelsiguientearchivo,oNULLcuandoyanoquedanarchivos.Cadadirectoriosiemprecontieneentradasparasimismo,llamada“.”,yparasupadre“..”;debenserignoradas,oelprogramaiteraráporsiempre.

Enestenivel,elcódigoesindependientedecómoestáelformatodelosdirectorios.Elsiguientepasoespresentarversionesmínimasdeopendir,readdir,yclosedirparaunsistemaespecífico.LassiguientesrutinassonparasistemasUNIXVersión7ySystemV;utilizanlainformaciónqueestáenelheader<sys/dir.h>,queapareceasí:

#ifndefDIRSIZ

Page 263: Titivillus 07.07

#defineDIRSIZ14

#endif

structdirect/*entradadeldirectorio*/

{

ino_td_ino;/*númerodenodo-i*/

chard_name[DIRSIZ];/*losnombreslargosnotienen'\0'*/

};

Algunasversionesdelsistemapermitennombresmuchomáslargosytienenunaestructuradedirectoriosmáscomplicada.

Eltipoino_tesuntypedefquedescribealíndicealalistadenodos-i.Enelsistemaqueusamosregularmenteesununsignedshort,peroéstanoeslaclasedeinformaciónparaincluirenunprograma;puedeserdistintaenunsistemadiferente,demodoquetypedefesmejor.Unjuegocompletodetipos“delsistema”seencuentraen<sys/types.h>.

opendirabreeldirectorio,verificaqueelarchivoseaundirectorio(estavezpormediodelallamadaalsistemafstat,queescomostatexceptoenqueseaplicaaundescriptordearchivo),asignaunaestructuradedirectorio,ygrabalainformación.

intfstat(intfd,structstat*);

/*opendir:abreundirectorioparallamadasdereaddir*/

DIR*opendir(char*dirname)

{

intfd;

structstatstbuf;

DIR*dp;

if((fd=open(dirname,O_RDONLY,0))==-1

||fstat(fd,&stbuf)==-1

||(stbuf.st_mode&S_IFMT)!=S_IFDIR

||(dp=(DIR*)malloc(sizeof(DIR)))==NULL)

returnNULL;

dp->fd=fd;

returndp;

}

Page 264: Titivillus 07.07

closedircierraelarchivodeldirectorioyliberaelespacio:

/*closedir:cierraundirectorioabiertoporopendir*/

voidclosedir(DIR*dp)

{

if(dp){

close(dp->fd);

free(dp);

}

}

Finalmente,readdirusaareadparaleercadaentradadeldirectorio.Siunaentradadeldirectorionoestáactualmenteenuso(debidoaquehasidoremovidounarchivo),elnúmerodenodo-iescero,yestaposiciónsesalta.Deotraforma,elnúmerodenodo-iyelnombresoncolocadosenunaestructuraestáticayseregresaalusuariounapuntadoraella.Cadallamadasobreescribelainformacióndelaanterior.

#include<sys/dir.h>/*estructuralocaldedirectorio*/

/*readdir:leeensecuencialasentradasdeundirectorio*/

Direntreaddir(DIR*dp)

{

structdirectdirbuf;/estructuralocaldedirectorio*/

staticDirentd;/regreso:estructuratransportable*/

while(read(dp->fd,(char*)&dirbuf,sizeof(dirbuf))

==sizeof(dirbuf)){

if(dirbuf.d_ino==0)/*entradaquenoestáenuso*/

continue;

d.ino=dirbuf.d_ino;

strncpy(d.name,dirbuf.d_name,DIRSIZ);

d.name[DIRSIZ]='\0';/*aseguralaterminación*/

return&d;

}

returnNULL;

}

Page 265: Titivillus 07.07

Aunqueelprogramafsizeesbastanteespecializado,ilustraunpardeideasimportantes.Primera,muchosprogramasnoson“programasdelsistema”;simplementeusaninformaciónqueesmantenidaporelsistemaoperativo.Paratalesprogramasescrucialquelarepresentacióndelainformaciónaparezcasóloenheadersestándar,yquelosprogramasincluyanesosarchivosenvezdetenerlasdeclaracionesenellosmismos.Lasegundaobservaciónesqueconcuidadoesposiblecrearunainterfazhaciaobjetosdependientesdelsistemaqueasuvezsearelativamenteindependientedelmismo.Lasfuncionesdelabibliotecaestándarsonbuenosejemplos.

Ejercicio8-5.Modifiqueelprogramafsizeparaqueimprimaelrestodelainformacióncontenidaenlaentradadelnodo-i.□

Page 266: Titivillus 07.07

8.7.Ejemplo—asignadordememoria

Enelcapítulo5presentamosunasignadordememoriamuylimitadoquefuncionabaenmododepila.Laversiónqueescribiremosahoranotienerestricciones.Lasllamadasamallocyfreepuedenocurrirencualquierorden;mallocllamaalsistemaoperativoparaobtenermásmemoriacuandoesnecesaria.Estasrutinasilustranalgunasdelasconsideracionesimplicadasenlacreacióndecódigodependientedemáquinaenunaformarelativamenteindependiente,ytambiénmuestranunaaplicacióndeestructura,unionesytypedefalavidareal.

Envezdeasignarunarregloprecompiladodetamañofijo,mallocsolicitaráespacioalsistemaoperativocuandoseanecesario.Dadoqueotrasactividadesenelprogramatambiénpuedenrequerirespaciosinllamaraesteasignador,elespacioquemallocmanejapuedenosercontiguo.Así,elespaciolibredealmacenamientoesmantenidocomounalistadebloqueslibres.Cadabloquecontieneuntamaño,unapuntadoralsiguientebloque,yelespacioensí.Losbloquessonmantenidosenordenascendentededireccióndealmacenamiento,yelúltimobloque(direcciónmásalta)apuntaalprimero.

listalibre

enuso

libre,apropiadopormalloc

enuso,apropiadopormalloc

noapropiadopormalloc

Cuandosehaceunasolicitud,serastrealalistalibrehastaqueseencuentraunbloquesuficientementegrande.Estealgoritmoesllamado“deprimerajuste”(first-fit),encontrastecon(bestfit),quebuscaelbloquemáspequeñoquesatisfarálasolicitud.Sielbloqueesexactamentedeltamañorequerido,sedesligadelalistayseentregaalusuario.Sielbloqueesdemasiadograndesedivide,ylacantidadapropiadaesentregadaalusuariomientrasqueelrestopermaneceenlalistalibre.Sinoseencuentraunbloquesuficientementegrande,algúnotrotrozograndeseobtienedelsistemaoperativoyseligaalalistalibre.

Page 267: Titivillus 07.07

Laliberacióntambiénprovocaunabúsquedaenlalistalibre,paraencontrarellugarapropiadoparainsertarelbloquequeestásiendoliberado.Sielbloquequeestásiendoliberadoesadyacenteaunbloquelibreencualquieradesuslados,seuneconélenunbloqueúnicomásgrande,porloqueelalmacenamientonosefragmentademasiado.Determinarlaadyacenciaesfácilpuestoquelalistalibreesmantenidaenordenascendentededirecciones.

Unproblema,alquealudimosenelcapítulo5,esasegurarqueelalmacenamientoregresadopormallocestéalineadoapropiadamenteparalosobjetosquesealmacenaránenél.Aunquelasmáquinasvarían,paracadaunaexisteuntipoqueeselmásrestrictivo:sieltipomásrestrictivopuedeseralmacenadoenunadirecciónparticular,todoslosotrostipostambiénloserán.Enalgunasmáquinas,eltipomásrestrictivoesundouble;enotras,bastaintolong.

Unbloquelibrecontieneunapuntadoralsiguientebloquedelacadena,unregistrodeltamañodelbloque,yluegoelespaciodisponibleensí;lainformacióndecontrolqueestáalinicioesllamadaelencabezador.Parasimplificarlaalineación,todoslosbloquessonmúltiplosdeltamañodelencabezador,yéstesealineaapropiadamente.Estoselogramedianteunauniónquecontienelaestructuradeseadadelencabezadoryunaocurrenciadeltipodealineaciónmásrestrictivo,alquearbitrariamentehemoshecholong:

typedeflongAlign;/*paraalineamientoallímitemayor*/

unionheader{/*encabezadordelbloque*/

struct{

unionheader*ptr;/*siguientebloquesiestáenlalistalibre*/

unsignedsize;/*tamañodeestebloque*/

}s;

Alignx;/*obligaalaalineacióndebloques*/

};

typedefunionheaderHeader;

ElcampoAlignnuncaesutilizado;sólohacequecadaencabezadorestéalineadoallímitedelpeorcaso.

Enmalloc,eltamañorequeridoencaracteresesredondeadoalnúmeroapropiadodeunidadesdetamañodelencabezador;elbloquequeseráasignadocontieneunaunidadmás,paraelencabezadorensí,yésteeselvalorgrabadoenelcamposize.Elapuntadoresregresadopormallocapuntaalespaciolibre,noencabezador.Elusuariopuedehacercualquiercosaconelespaciorequerido,perosialgoseescribefueradelespacioasignado,lalistasepuededesorganizar.

Page 268: Titivillus 07.07

apuntaalsiguientebloquelibre

tamaño

direcciónregresadaalusuario

Unbloqueregresadopormalloc

Elcamposizeesnecesariodebidoaquelosbloquescontroladospormallocnorequierensercontiguos—noesposiblecalculartamañosmediantearitméticadeapuntadores.

Lavariablebaseseusaparacomenzar.SifreepesNULL,comoloesenlaprimerallamadademalloc,entoncessecreaunalistalibredegeneradaquecontieneunbloquedetamañoceroyapuntaasímisma.Encualquiercaso,luegosebuscaenlalistalibre.Labúsquedadeunbloquelibredetamañoadecuadoprincipiaenelpunto(freep)dondeseencontróelúltimobloque;estaestrategiaayudaamantenerlalistahomogénea.Siseencuentraunbloquedemasiadogrande,alusuarioseleregresalapartefinal;enestaformaelencabezadordeloriginalsólonecesitatenerajustadosutamaño.Entodosloscasos,elapuntadorregresadoalusuarioapuntaalespaciolibredentrodelbloque,queprincipiaunaunidadmásalládelencabezador.

staticHeaderbase;/*listavacíaparainiciar*/

staticHeader*freep=NULL;/*iniciodeunalistalibre*/

/*malloc:asignadordealmacenamientodepropósitogeneral*/

void*malloc(unsignednbytes)

{

Header*p,*prevp;

Header*morecore(unsigned);

unsignednunits;

nunits=(nbytes+sizeof(Header)-1)/sizeof(Header)+1;

if((prevp=freep)==NULL){/*nohaylistalibreaún*/

base.s.ptr=freep=prevp=&base;

base.s.size=0;

Page 269: Titivillus 07.07

}

for(p=prevp->s.ptr;;prevp=p,p=p->s.ptr){

if(p->s.size>=nunits){/*suficientementegrande*/

if(p->s.size==nunits)/*exacto*/

prevp->s.ptr=p->s.ptr;

else{/*asignalapartefinal*/

p->s.size-=nunits;

p+=p->s.size;

p->s.size=nunits;

}

freep=prevp;

return(void*)(p+1);

}

if(p==freep)/*diolavueltaalalistalibre*/

if((p=morecore(nunits))==NULL)

returnNULL;/*nadalibre*/

}

}

Lafunciónmorecoreobtieneespaciodealmacenamientodelsistemaoperativo.Losdetallesdecómolohacevaríandesistemaasistema.Debidoaquepedirmemoriaalsistemaesunaoperacióncomparativamentecostosa,nodeseamoshacerloencadallamadaamalloc,asíquemorecoresolicitaalmenosNALLOCunidades;estebloquegrandeseráseccionadodeacuerdoconlasnecesidades.Despuésdefijarelcamposize,morecoreinsertalamemoriaadicionalllamandoafree.

Lallamadasbrk(n)alsistemaUNIXregresaunapuntadoranbytesmásdealmacenamiento,sbrkregresa-1sinohuboespacio,aunqueNULLhubierasidounmejordiseño.El-1debeserforzadoachar*paraquepuedasercomparadoconelvalorderetorno.Nuevamente,lasconversionesforzadashacenalafunciónrelativamenteinmunealosdetallesderepresentacióndeapuntadoresenmáquinasdiferentes.Hay,sinembargo,unasuposiciónmás;quelosapuntadoresabloquesdiferentesregresadosporsbrkpuedensercomparados.Estonoesgarantizadoporelestándar,quesólopermitelacomparacióndeapuntadoresdentrodeunarreglo.Así,estaversióndemallocesportátilsóloentremáquinasparalasquelacomparacióngeneraldeapuntadoresessignificativa.

#defineNALLOC1024/*mínimo#deunidadesporrequerir*/

/*morecore:solicitamásmemoriaalsistema*/

Page 270: Titivillus 07.07

staticHeader*morecore(unsignednu)

{

char*cp,*sbrk(int);

Header*up;

if(nu<NALLOC)

nu=NALLOC;

cp=sbrk(nu*sizeof(Header));

if(cp==(char*)-1)/*nohaynadadeespacio*/

returnNULL;

up=(Header*)cp;

up->s.size=nu;

free((void*)(up+1));

returnfreep;

}

freeeslaúltimasección.Recorrelalistalibre,iniciandoenfreep,buscandodóndeinsertarelbloquelibre.Estoesentredosbloquesexistentesoenunodelosextremosdelalista.Encualquiercaso,sielbloquequeestásiendoliberadoesadyacenteaalgúnvecino,losbloquesadyacentessecombinan.Losúnicosproblemassonmantenerlosapuntadoresseñalandoalascosascorrectasymantenerlostamañoscorrectos.

/*free:colocaelbloqueapenlalistavacía*/

voidfree(void*ap)

{

Header*bp,*p;

bp=(Header*)ap-1;/*apuntaalencabezadordeunbloque*/

for(p=freep;!(bp>p&&bp<p->s.ptr);p=p->s.ptr)

if(p>=p->s.ptr&&(bp>p||bp<p->s.ptr))

break;/*liberabloquealiniciooalfinal*/

if(bp+bp->s.size==p->s.ptr){/*unealnbrsuperior*/

bp->s.size+=p->s.ptr->s.size;

bp->s.ptr=p->s.ptr->s.ptr;

Page 271: Titivillus 07.07

}else

bp->s.ptr=p->s.ptr;

if(p+p->s.size==bp){/*unealnbrinferior*/

p->s.size+=bp->s.size;

p->s.ptr=bp->s.ptr;

}else

p->s.ptr=bp;

freep=p;

}

Aunquelaasignacióndememoriaesintrínsecamentedependientedelamáquina,elcódigoanteriorilustracómopuedensercontroladaslasdependenciasdelamáquinayconfinadasaunapartemuypequeñadelprograma.Elusodetypedefydeunionmanejalaalineación(suponiendoquesbrkproporcionaunapuntadorapropiado).Lasconversionesforzosashacenquelosapuntadoressemanejenadecuadayexplícitamente,einclusoseacoplanaunainterfazparaelsistemamaldiseñada.Auncuandolosdetallesaquíestánrelacionadosconlaasignacióndealmacenamiento,elacercamientogeneralesaplicabletambiénaotrassituaciones.

Ejercicio8-6.Lafuncióncalloc(n,size)delabibliotecaestándarregresaunapuntadoranobjetosdetamañosize,conelalmacenamientoinicializadoencero.Escribacalloc,invocandoamallocomodificándola.□

Ejercicio8-7.mallocaceptauntamañosolicitadosinverificarlaposibilidaddequeseaválido;freecreequeelbloquequesepideliberarcontieneuncampodetamañocorrecto.Mejoreesasrutinasparaquesetomenmásmolestiasenlarevisióndeerrores.□

Ejercicio8-8.Escribaunarutinabfree(p,n)quelibereunbloquearbitrariopdencaracteresenlalistalibremantenidapormallocyfree.Utilizandobfree,unusuariopuedeagregarunarregloestáticooexternoalalistalibreencualquiermomento.□

Page 272: Titivillus 07.07

APÉNDICEA:Manualdereferencia

Page 273: Titivillus 07.07

A1.Introducción

EstemanualdescribeallenguajeCtalcomoseespecificaenDraftProposedAmericanNationalStandardforInformationSystems—ProgrammingLanguageC,documentonúmeroX3J11/88-001,confecha11deenerode1988.Esteborradornoeselestándarfinal,ytodavíaesposiblequeocurranalgunoscambiosenellenguaje.Asípues,estemanualnodescribeladefiniciónfinaldellenguaje.Másaúnesunainterpretacióndelborradorpropuestodelestándar,noelestándarensí,aunquesehatenidocuidadodehacerlounaguíaconfiable.

Ensumayorparte,estemanualsiguelalíneaampliadelborradorestándar,queasuvezsigueladelaprimeraedicióndeestelibro,aunquelaorganizacióndifiereeneldetalle.Exceptoporrenombraralgunasproduccionesyporquenoseformalizanlasdefinicionesdeloscomponentesléxicosodelpreprocesador,lagramáticadadaaquíparaellenguajeesequivalentealadelborradoractual.

Enestemanual,elmaterialcomentadoseencuentrasangradoyescritoenuntipomáspequeño,comoeste.AmenudoestoscomentariosresaltanlasformasenlasqueelestándarANSIdeCdifieredellenguajedefinidoporlaprimeraedicióndeestelibro,oderefinamientosintroducidosposteriormenteenvarioscompiladores.

Page 274: Titivillus 07.07

A2.Convencionesléxicas

Unprogramaconsisteenunaomásunidadesdetraducciónalmacenadasenarchivos.Estraducidoenvariasfases,quesedescribenen§A12.Lasprimerasfaseshacentransformacionesléxicasdebajonivel,ejecutandirectivasintroducidasconlíneasqueprincipianconelcarácter#,yrealizanmacrodefinicionesyexpansiones.Cuandoelpreprocesamientode§A12estácompleto,elprogramasehareducidoaunasecuenciadecomponentesléxicos.

Page 275: Titivillus 07.07

A2.1.Componentesléxicos(tokens)

Existenseisclasesdecomponentesléxicos:identificadores,palabrasreservadas,constantes,cadenasliterales,operadoresyotrosseparadores.Losblancos,tabuladoreshorizontalesyverticales,nuevalínea,avancedeformaycomentarios,comosedescribenadelante(ensuconjunto,llamados“espacioenblanco”)sonignorados,exceptolosqueseparancomponentes.Serequieredealgúnespacioenblancoparasepararidentificadoresdeotramaneraadyacentes,palabrasreservadasyconstantes.

Sielflujodeentradasehaseparadoencomponenteshastauncarácterdeterminado,elsiguientecomponenteeslacadenamáslargadecaracteresquepuedeconstituiruno.

Page 276: Titivillus 07.07

A2.2.Comentarios

Loscaracteres/*inicianuncomentario,queterminaconloscaracteres*/.Loscomentariosnoseanidanynopuedenestardentrodecadenasocaracteresliterales.

Page 277: Titivillus 07.07

A2.3.Identificadores

Unidentificadoresunasecuenciadeletrasydígitos.Elprimercarácterdebeserunaletra;elsubguión_cuentacomounaletra.Lasletrasminúsculasymayúsculassondiferentes.Losidentificadorespuedentenercualquierlongitudy,paraidentificadoresinternos,almenoslosprimeros31caracteressonsignificativos;algunasimplantacionespuedenhacerquemáscaracteresseansignificativos.Losidentificadoresinternosincluyenlosnombresdemacrosdelpreprocesadorytodoslosotrosnombresquenotienenligadoexterno(§A11.2).Losidentificadoresconligadoexternoestánmásrestringidos:lasimplantacionespuedenhacerquesóloseansignificativosseiscaracteresypuedenignorarladistinciónentremayúsculasyminúsculas.

Page 278: Titivillus 07.07

A2.4.Palabrasreservadas

Lossiguientesidentificadoressonpalabrasreservadasynosepuedenutilizardeotramanera:

auto

double

int

struct

break

else

long

switch

case

enum

register

typedef

char

extern

return

union

const

float

short

unsigned

continue

for

signed

void

Page 279: Titivillus 07.07

default

goto

sizeof

volatile

do

if

static

while

Algunasimplantacionestambiénreservanlaspalabrasfortranyasm.

Laspalabrasconst,signedyvolatilesonnuevasenelestándarANSI;enumyvoidsonnuevasdesdelaprimeraedición,peroenusocomún;entry,antesreservadaperonuncausada,yanoestáreservada.DependiendodelasdecisionesdelcomitéX3J11,lapalabranoaliastambiénpuedeestarreservada.

Page 280: Titivillus 07.07

A2.5.Constantes

Hayvariasclasesdeconstantes.Cadaunatieneuntipodedato;en§A4.2sediscutenlostiposbásicos.

constante:

constante-entera

constante-de-carácter

constante-flotante

constante-enumeración

Page 281: Titivillus 07.07

A2.5.1.Constantesenteras

Unaconstanteenteraqueconsisteenunasecuenciadedígitossetomacomooctalsiprincipiacon0(dígitocero),deotramaneraesdecimal.Lasconstantesoctalesnocontienenlosdígitos8ó9.Unasecuenciadedígitosprecedidapor0xó0X(dígitocero)setomacomounenterohexadecimal.LosdígitoshexadecimalesincluyendelaaoAhastalafoFconvalores10al15.

UnaconstanteenterapuedetenerlaletrauoUcomosufijo,locualespecificaqueesunsigned.TambiénpuedetenercomosufijolaletraloLparaestipularqueeslong.

Eltipodeunaconstanteenteradependedesuforma,valorysufijo(véase§A4paraunadiscusióndetipos).Undecimalsinsufijotieneelprimerodeestostipos,enelquesuvalorpuedaserrepresentado:int,longint,unsignedlongint.Siesoctalohexadecimalsinsufijo,tieneelprimervalorposibledeestostipos:int,unsignedint,longint,unsignedlongint.SitieneelsufijouoU,entoncesesunsignedint,unsignedlongint.SitieneelsufijoloL,entonceseslongint,unsignedlongint.

Laelaboracióndelostiposdeconstantesenterasvaconsiderablementemásalládelaprimeraedición,quesimplementehacíaquelasgrandesconstantesenterasfueranlong.LossufijosUsonnuevos.

Page 282: Titivillus 07.07

A2.5.2.Constantesdecarácter

Unaconstantedecarácteresunasecuenciadeunoomáscaracteresencerradosentreapóstrofos,como'x'.Elvalordeunaconstantedecarácterconunsolocaráctereselvalornuméricodelcarácterenelconjuntodecaracteresdelamáquinaaltiempodeejecución.Elvalordeunaconstantemulticarácterestádefinidoporlaimplantación.

Lasconstantesdecarácternocontienenelcarácter'onuevalínea;pararepresentarlos,asícomoaalgunosotroscaracteres,sepuedenutilizarlassiguientessecuenciasdeescape.

nuevalínea

NL(LF)

\n

tabhorizontal

HT

\t

tabvertical

VT

\v

retroceso

BS

\b

regresodecarro

CR

\r

avancedeforma

FF

\f

señalaudible

BEL

\a

Page 283: Titivillus 07.07

diagonalinversa

\

\\

interrogación

?

\?

apóstrofo

'

\'

comillas

"

\"

númerooctal

ooo

\

ooo

númerohexadecimal

hh

\x

hh

Elescape\oooconsisteenladiagonalinversaseguidapor1,2ó3dígitosoctales,queestipulanelvalordelcarácterdeseado.Unejemplocomúndeestaconstrucciónes\0(noseguidoporundígito),queespecificaelcarácterNUL.Elescape\xhhconsisteenladiagonalinversaseguidaporx,seguidapordígitoshexadecimales,queestipulanelvalordecarácterdeseado.Nohaylímiteenelnúmerodedígitos,peroelcomportamientoquedaindefinidosielvalordecarácterresultanteexcedealdelcaráctermásgrande.Paracaracteresoctalesohexadecimales,silaimplantacióntrataaltipocharcomosigned,elvaloresextendidoensignocomosiseforzaraaserdetipochar.Sielcarácterquesiguea\noesunodelosespecificados,elcomportamientonoestádefinido.

Enalgunasimplantaciones,existeunconjuntoextendidodecaracteresquenosepuederepresentarporeltipochar.UnaconstanteenesteconjuntoextendidoseescribeconunaLprecedente,porejemploL'x',ysellamaunaconstantedecarácteramplio.Talconstantetienetipowchar_t,untipoenterodefinidoenelheader<stddef.h>.Comoconlasconstantesdecarácterordinarias,sepuedenemplearescapesoctalesohexadecimales;elefectoestáindefinidosielvalorespecificadoexcedealquese

Page 284: Titivillus 07.07

representaconwchar_t.

Algunasdeestassecuenciasdeescapesonnuevas,enparticularlarepresentaciónhexadecimaldecaracteres.Loscaracteresextendidostambiénsonnuevos.LosjuegosdecaracterescomúnmenteusadosenAméricayEuropaoccidentalsepuedencodificarparaquedareneltipochar;laintenciónprincipaldeagregarwchar_tfueadaptarsealoslenguajesasiáticos.

Page 285: Titivillus 07.07

A2.5.3.Constantesflotantes

Unaconstanteflotanteconstadeunaparteentera,unpuntodecimal,unapartefraccionaria,unaeoE,unexponenteenterosignadooptativoyuntiposufijooptativoentrefoF,loL.Laspartesenterayfraccionariaconstandeunasecuenciadedígitos.Cualquieradelaspartesenteraofraccionaria(noambas)puedeomitirse;cualquieradelaspartesdelpuntodecimalolaeyelexponente(noambas)puedenomitirse.Eltipoestádeterminadoporelsufijo;Foflahacenfloat,Lollahacenlongdouble;deotramaneraesdouble.

Lossufijosenconstantesflotantessonnuevos.

Page 286: Titivillus 07.07

A2.5.4.Constantesdeenumeración

Losidentificadoresdeclaradoscomoenumeradores(véase§A8.4)sonconstantesdetipoint.

Page 287: Titivillus 07.07

A2.6.Cadenasliterales

Unacadenaliteral,tambiénllamadacadenaconstanteesunasecuenciadecaracteresdelimitadosporcomillas,comoen"...".Unacadenatieneeltipo“arreglodecaracteres”ycategoríadealmacenamientostatic(véase§A4,abajo)yseinicializaconloscaracteresdados.Elquecadenasidénticasseandistintasestádefinidoporlaimplantación,yelcomportamientodeunprogramaqueintentaalterarunacadenaliteralestáindefinido.

Cadenasliteralesadyacentesseconcatenanenunasolacadena.Despuésdecualquierconcatenación,seagregaunbytenulo\0alacadena,demodoquelosprogramasquerastreanlacadenapuedanencontrarelfin.Lascadenasliteralesnocontienencaracteresnuevalíneaocomillas;pararepresentarlos,seusanlasmismassecuenciasdeescapequeparalasconstantesdecarácter.

Comoconlasconstantesdecarácter,lascadenasliteralesenunconjuntodecaracteresextendidoseescribenconunaLprecedente,comoenL"...".Lascadenasliteralesampliasdecaracterestienentipo“arreglodewchar_t”.Laconcatenacióndecadenasliteralesordinariasyampliasestáindefinida.

Laespecificacióndequelascadenasliteralesnotienenporquéserdistintas,ylaprohibiciónencontrademodificarlas,sonnovedadesdentrodelestándarANSI,asícomolaconcatenacióndecadenasliteralesadyacentes.Lascadenasliteralesdecaracteresampliossonnuevas.

Page 288: Titivillus 07.07

A3.Notaciónsintáctica

Dentrodelanotaciónsintácticaqueseempleaenestemanual,lascategoríassintácticasseindicanconestiloitálico,ylaspalabrastextualesycaracteresenestilomecanográfico.Lascategoríasalternativasusualmenteselistanenlíneasseparadas;enalgunoscasos,unconjuntoampliodealternativascortassepresentaenunalínea,marcadaporlafrase“unode”.Unsímbolooptativoterminalonoterminalllevaelsubíndice“opt”,demodoque,porejemplo,

{expresiónopt}

significaunaexpresiónoptativa,encerradaentrellaves.Lasintaxisseresumeen§A13.

Adiferenciadelagramáticaempleadaenlaprimeraedicióndeestelibro,laqueaquísedahaceexplícitalaprecedenciayasociatividaddelosoperadoresdeexpresión.

Page 289: Titivillus 07.07

A4.Significadodelosidentificadores

Losidentificadores,onombres,serefierenaunavariedaddecosas:funciones;rótulosdeestructuras,unionesyenumeraciones;miembrosdeestructurasodeuniones;constantesdeenumeración;nombrestypedefyobjetos.Unobjeto,algunasvecesllamadovariable,esunalocalidadenelespaciodealmacenamientoysuinterpretacióndependededosatributosfundamentales:sucategoríadealmacenamientoysutipo.Lacategoríadealmacenamientodeterminaeltiempodevidadelalmacenamientoasociadoconelobjetoidentificado;eltipodeterminaelsignificadodelosvaloresencontradosenelobjetoidentificado.Unnombretambiéntieneunalcance,queeslaregióndelprogramadentrodelaqueseconoce,yunaliga,quedeterminasielmismonombreenotroalcanceserefierealmismoobjetoofunción.Elalcanceylaligasediscutenen§A11.

Page 290: Titivillus 07.07

A4.1.Categoríasdealmacenamiento

Existendoscategoríasdealmacenamiento:automáticayestática.Variaspalabrasreservadas,juntoconelcontextodeladeclaracióndeunobjeto,especificansucategoríadealmacenamiento.Losobjetosautomáticossonlocalesaunbloque(§A9.3),ysondescartadosalsalirdelbloque.Lasdeclaracionesdentrodeunbloquecreanobjetosautomáticossinosemencionaunaespecificacióndecategoríadealmacenamiento,osiseempleaelespecificadorauto.Losobjetosdeclaradoscomoregistersonautomáticos,ysealmacenan(siesposible)enregistrosrápidosdelamáquina.

Losobjetosestáticospuedenserlocalesaunbloqueoexternosatodoslosbloques,peroencualquiercasomantienensuvalorentrelassalidasyreentradasafuncionesobloques.Dentrodeunbloque,incluyendounoqueproporcioneelcódigodeunafunción,losobjetosestáticossedeclaranconlapalabrareservadastatic.Losobjetosquesedeclaranfueradetodoslosbloques,almismonivelqueladefinicióndelasfunciones,sonsiempreestáticos.Sepuedenhacerlocalesaunaunidaddetraducciónenparticularporelusodelapalabrareservadastatic;estolesotorgaligainterna.Sehacenglobalesaunprogramacompletoomitiendounacategoríaexplícitadealmacenamiento,outilizandolapalabrareservadaextern;estolesotorgaligaexterna.

Page 291: Titivillus 07.07

A4.2.Tiposbásicos

Existenvariostiposbásicos.Elheaderestándar<limits.h>quesedescribeenelapéndiceBdefinelosvaloresmayoresymenoresdecadatipodentrodelaimplantaciónlocal.LosnúmerosdadosenelapéndiceBmuestranlasmenoresmagnitudesaceptables.

Losobjetosdeclaradoscomocaracteres(char)sonsuficientementegrandesparaalmacenarcualquiermiembrodelconjuntodecaracteresenejecución.Siuncaráctergenuinodeeseconjuntosealmacenaenunobjetochar,suvaloresequivalentealcódigoenteroparaesecarácter,yesnonegativo.Sepuedenalmacenarotrascantidadesenvariableschar,peroelrangodevaloresdisponibles,yenespecialsielvalortienesigno,dependedelaimplantación.

Loscaracteressinsignodeclaradosunsignedcharconsumenlamismacantidaddeespacioqueloscaracteressencillos,perosiempreaparecencomononegativos;loscaracteresexplícitamentesignadosquesedeclaransignedchartomanigualmenteelmismoespacioqueloscaracteressencillos.

unsignedcharnoapareceenlaprimeraedicióndeestelibro,peroesdeusocomún.signedcharesnuevo.

Ademásdelostiposchar,haytrestamañosdeenteros,declaradoscomoshortint,int,ylongint.Losobjetosintsimplestieneneltamañonaturalsugeridoporlaarquitecturadelamáquinadondeseejecuta;losotrostamañosseproporcionanparacumplirconnecesidadesespeciales.Losenterosmásgrandesproporcionanporlomenostantoalmacenamientocomolosmenores,perolaimplantaciónpuedehaceralosenterossimplesequivalentesalosenteroscortos,oalosenteroslargos.Todoslostiposintrepresentanvaloresconsignoamenosqueseespecifiquelocontrario.

Losenterossinsigno,declaradosmediantelapalabrareservadaunsigned,obedecenalasleyesdelaaritméticamódulo2ndondeneselnúmerodebitsenlarepresentación,porloquelaaritméticasobrecantidadessignadasnuncapuededesbordarse.Elconjuntodevaloresnonegativosquesepuedenalmacenarenobjetosconsignoesunsubconjuntodelosquesepuedenalmacenarenelcorrespondienteobjetosinsigno,ylarepresentaciónparalosvaloresencomúneslamisma.

Cualquieradelostipospuntoflotantedeprecisiónsencilla(float),puntoflotantedeprecisióndoble(double)ypuntoflotantedeprecisiónextra(longdouble)puedesersinónimo,perolosúltimosenlalistasonalmenostanprecisoscomolosquelosanteceden.

longdoubleesnuevo.Laprimeraediciónhizoalongfloatequivalenteadouble;estoseharechazado.

Lasenumeracionessontiposúnicosquetienenvaloresenteros;asociadoconcadaenumeraciónhayunconjuntodeconstantesnombradas(§A8.4).Lasenumeracionessecomportancomoenteros,peroescomúnqueuncompiladordéunaadvertenciacuandounobjetodeuntipodeenumeraciónenparticularseasignaaalgoquenoseaunadesusconstantesounaexpresióndesutipo.

Debidoaquelosobjetosdeestostipossepuedeninterpretarcomonúmeros,seharáreferenciaaelloscomotiposaritméticos.Lostiposchareintdetodoslostamaños,

Page 292: Titivillus 07.07

cadaunoconosinsigno,ytambiénlostiposdeenumeración,sellamaránconjuntamentetiposenteros.Lostiposfloat,doubleylongdoublesellamarántiposflotantes.

Eltipovoidespecificaunconjuntovacíodevalores.Seusacomoeltiporegresadoporfuncionesquenogeneranunvalor.

Page 293: Titivillus 07.07

A4.3.Tiposderivados

Ademásdelostiposbásicos,existeunacategoríaconceptualmenteinfinitadetiposderivados,construidosapartirdelostiposfundamentalesenlasformassiguientes:

arreglos

deobjetosdeuntipodado;

funciones

queregresanobjetosdeuntipodado;

apuntadores

aobjetosdeuntipodado;

estructuras

quecontienenunasecuenciadeobjetosdevariostipos;

uniones

capacesdecontenerunobjetocualquieradevariostipos.

Engeneral,estosmétodosdeconstruccióndeobjetossepuedenaplicarenformarecursiva.

Page 294: Titivillus 07.07

A4.4.Calificadoresdetipo

Untipodeobjetopuedetenercalificadoresadicionales.Eldeclararconstaunobjetoanunciaquesuvalornocambiará;declararlovolatileanunciaquetienepropiedadesespecialesdeimportanciaparalaoptimización.Ningúncalificadorafectaelrangodevaloresopropiedadesaritméticasdelobjeto.Loscalificadoressediscutenen§A8.2.

Page 295: Titivillus 07.07

A5.Objetosyvalores-l

Unobjetoesunaregióndealmacenamientoconnombre;unvalor-lesunaexpresiónqueserefiereaunobjeto.Unejemploobviodeunaexpresiónvalor-lesunidentificadorconuntipoadecuadoyunacategoríadealmacenamiento.Existenoperadoresqueproducenvalores-l:porejemplo,siEesunaexpresióndetipoapuntador,entonces*Eesunaexpresiónvalor-lqueserefierealobjetoalcualapuntaE.Elnombre“valor-l”provienedelaexpresióndeasignaciónEl=E2enlaqueeloperadorizquierdoE1debeserunaexpresiónvalor-l.Ladiscusióndecadaoperadorespecificasiesperaoperandosvalor-lysientregaunvalor-l.

Page 296: Titivillus 07.07

A6.Conversiones

Algunosoperadorespueden,dependiendodesusoperandos,provocarlaconversióndelvalordeunoperandodeuntipoaotro.Estasecciónexplicaelresultadoqueseesperadetalesconversiones.§A6.5resumelasconversionesdemandadasporlamayoríadelosoperadoresordinarios;endondeserequiera,serácomplementadaconladiscusióndecadaoperador.

Page 297: Titivillus 07.07

A6.1.Promociónentera

Uncarácter,unenterocortoouncampoenterodebits,todosconosinsigno,ounobjetodetipoenumeración,sepuedeutilizardentrodeunaexpresiónencualquierlugarendondesepuedausarunentero.Siunintpuederepresentaratodoslosvaloresdeltipooriginal,entonceselvaloresconvertidoaint;deotramaneraelvaloresconvertidoaunsignedint.Esteprocesosellamapromociónentera.

Page 298: Titivillus 07.07

A6.2.Conversionesenteras

Unenteroseconvierteauntiposinsignodadoencontrandoelmenorvalornonegativoqueseacongruenteconeseentero,módulounomásqueelmayorvalorquesepuedarepresentareneltiposinsigno.Enunarepresentacióncomplementoados,estoesequivalentealtruncamientoporlaizquierdasielpatróndebitsdeltiposinsignoesmásestrecho,yalllenadoconcerosdevaloressinsignoyextensióndesignoenvaloresconsignosieltiposinsignoesmásamplio.

Cuandocualquierenteroseconvierteauntipoconsigno,elvalornosecambiasipuedeserrepresentadoenelnuevotipo,yenotrocasoestádefinidoporlaimplantación.

Page 299: Titivillus 07.07

A6.3.Enteroyflotante

Cuandounvalordetipoflotanteseconvierteauntipoentero,lapartefraccionariasedescarta;sielvalorresultantenopuedeserrepresentadoeneltipoentero,elcomportamientonoestádefinido.Enparticular,elresultadodeconvertirvaloresflotantesnegativosatiposenterossinsignonoestáespecificado.

Cuandounvalordetipoenteroseconvierteaflotante,yelvalorestáenelrangorepresentableperonoesexactamenterepresentable,entonceselresultadopuedeserelvalorsiguientemásaltoomásbajo.Sielresultadoestáfueraderango,elcomportamientoestáindefinido.

Page 300: Titivillus 07.07

A6.4.Tiposflotantes

Cuandounvalorflotantemenosprecisoseconvierteauntipoflotanteigualomáspreciso,elvalornosemodifica.Cuandounvalorflotantemásprecisoseconvierteauntipoflotantemenospreciso,yelvalorestádentrodelrangorepresentable,elresultadopuedeserelsiguientevalorrepresentablemásaltooelsiguientemásbajo.Sielresultadoestáfueraderango,elcomportamientoestáindefinido.

Page 301: Titivillus 07.07

A6.5.Conversionesaritméticas

Muchosoperadoresprovocanunaconversiónyproducentiposresultantesenformasemejante.Elefectoespasarlosoperandosauntipocomún,queestambiéneltipodelresultado.Aestepatrónselellamaconversionesaritméticasusuales.

Primero,sicualquieroperandoesunlongdouble,elotroesconvertidoalongdouble.

Deotramanera,sicualquieroperandoesdouble,elotroesconvertidoadouble.

Deotramanera,sicualquieroperandoesfloat,elotroesconvertidoafloat.

Deotramanera,serealizapromociónenteraenambosoperandos;después,sicualquieroperandoesunsignedlongint,elotroesconvertidoaunsignedlongint.

Deotramanera,siunoperandoeslongintyelotroesunsignedint,elefectodependedesiunlongintpuederepresentaratodoslosvaloresdeununsignedint;siesasí,eloperandounsignedintesconvertidoalongint;sinoloes,ambossonconvertidosaunsignedlongint.

Deotramanera,siunoperandoeslongint,elotroesconvertidoalongint.

Deotramanera,sicualquieroperandoesunsignedint,elotroesconvertidoaunsignedint.

Deotramanera,ambosoperandostienentipoint.

Aquíhaydoscambios.Primero,laaritméticasobreoperandosfloatsepuederealizarenprecisiónsencilla,enlugardedoble;laprimeraediciónespecificabaquetodalaaritméticaflotanteeradedobleprecisión.Segundo,lostipossinsignomáspequeños,cuandosecombinanconuntipoconsignomayor,nopropaganlapropiedaddenosignadoaltiporesultante;enlaprimeraedición,siempredominabalonosignado.Lasnuevasreglassonligeramentemáscomplicadas,perodealgunaformareducenlassorpresasquepuedenocurrircuandounacantidadsinsignoencuentraaotraconsigno.Aúnpuedenocurrirresultadosinesperadoscuandounaexpresiónsinsignoescomparadaconunaexpresiónconsignodelmismotamaño.

Page 302: Titivillus 07.07

A6.6.Apuntadoresyenteros

Unaexpresióndetipoenteropuedesersumadaorestadadeunapuntador;entalcaso,laexpresiónenteraesconvertidatalcomoseespecificaenladiscusióndeloperadordeadición(§A7.7).

Dosapuntadoresaobjetosdelmismotipo,dentrodelmismoarreglo,puedenserrestados;elresultadoesconvertidoaunenterocomoseespecificaenladiscusióndeloperadordesustracción(§A7.7).

Unaexpresiónenteraconstanteconvalor0,oesaexpresiónforzadaaltipovoid*,puedeserconvertida,pormediodeuncast,porasignación,oporcomparación,aunapuntadordecualquiertipo.Estoproduceunapuntadornuloqueesigualaotroapuntadornulodelmismotipo,perodiferenteacualquierapuntadoraunafunciónuobjeto.

Sepermitenotrasciertasconversionesqueinvolucranapuntadores,perotienenaspectosdependientesdelaimplantación.Sedebenespecificarconunoperadorexplícitodeconversióndetipoocast(§§A7.5yA8.8).

Unapuntadorsepuedeconvertirauntipoenterosuficientementegrandeparamantenerlo;eltamañorequeridodependedelaimplantación.Lafuncióndemapeotambiéndependedelaimplantación.

Unobjetodetipoenterosepuedeexplícitamenteconvertiraunapuntador.Elmapeosiemprellevaunenterosuficientementeamplioconvertidodeunapuntadorderegresoalmismoapuntador,perodeotramaneraesdependientedelaimplantación.

Unapuntadordeuntiposepuedeconvertiraunapuntadoraotrotipo.Elapuntadorresultantepuedecausarerroresdedireccionamientosinoserefiereaunobjetoadecuadamentealineadoenlamemoria.Segarantizaqueunapuntadoraunobjetosepuedeconvertiraunapuntadoraunobjetocuyotiporequieredeunamenoroigualmenteestrictaalineaciónenelalmacenamientoyregresadodenuevosincambio;lanociónde“alineación”esdependientedelaimplantación,perolosobjetosdetipochartienenlosrequisitosdealineaciónmenosestrictos.Comosedescribeen§A6.8,unapuntadorsepuedeconveniratipovoid*yregresadodenuevosincambio.

Finalmente,unapuntadoraunafunciónsepuedeconvertiraunapuntadoraotrotipodefunción.Lallamadaalafunciónespecificadaporelapuntadorconvertidoesdependientedelaimplantación;sinembargo,sielapuntadorconvertidoesreconvertidoasutipooriginal,elresultadoesidénticoalapuntadororiginal.

Page 303: Titivillus 07.07

A6.7.Void

El(inexistente)valordeunobjetovoidnosepuedeutilizarenningunaforma,nisepuedeaplicarlaconversiónexplícitaoimplícitaaningúntiponovoid.Debidoaquelaexpresiónvoiddenotaunvalorinexistente,sólosepuedeutilizardondenosearequeridoelvalor,porejemplo,unaproposicióndeexpresión(§A9.2)oeloperandoizquierdodeunoperadorcoma(§A7.18).

Unaexpresiónsepuedeconvertiratipovoidconuncast.Porejemplo,unaconversiónforzadaavoiddejadocumentadoelrechazodelvalordeunallamadaafunciónutilizadacomoproposicióndeexpresión.

voidnoaparecíaenlaprimeraedicióndeestelibro,perosehavueltocomúndesdeentonces.

Page 304: Titivillus 07.07

A6.8.Apuntadoresavoid

Cualquierapuntadorsepuedeconvertiratipovoid*sinpérdidadeinformación.Sielresultadoseregresaaltipodeapuntadororiginal,ésteesrecuperado.Adiferenciadelaconversiónapuntador-a-apuntadordiscutidaen§A6.6,querequiereuncastexplícito,losapuntadorespuedenserasignadoshaciaydesdeapuntadoresdetipovoid*ypuedensercomparadosconellos.

Estainterpretacióndeapuntadoresvoid*esnueva;anteriormente,losapuntadoreschar*jugabanelpapeldeapuntadoresgenéricos.ElestándarANSIespecíficamenteconsienteelencuentrodeapuntadoresvoid*conapuntadoresaobjetosenasignacionesyrelaciones,mientrasquerequierecastexplícitosparaotrasmezclasdeapuntadores.

Page 305: Titivillus 07.07

A7.Expresiones

Laprecedenciadelosoperadoresenexpresioneseslamismaqueelordendelassubseccionesprincipalesdeestasección,primerolamásaltaprecedencia.Así,porejemplo,lasexpresionesalasquesehacereferenciacomooperandosde+(§A7.7)sonlasdefinidasen§§A7.1-A7.6.Dentrodecadasubsección,losoperadorestienenlamismaprecedencia.Encadasubsecciónseespecificalaasociatividadporlaizquierdaoladerechaparalosoperadoresdiscutidosallí.Lagramáticaincorporalaprecedenciayasociatividaddelosoperadoresdelaexpresiónyseresumeen§A13.

Laprecedenciayasociatividaddelosoperadoresestáespecificadacompletamente,peroelordendeevaluacióndelasexpresionesestá,conciertasexcepciones,indefinido,aúnsilassubexpresionesinvolucranefectoscolaterales.Estoes,amenosqueladefinicióndeunoperadorgaranticequesusoperandosseevalúenenunordenparticular,laimplantaciónestáenlibertaddeevaluarlosoperandosencualquierorden,oinclusointercalarsuevaluación.Sinembargo,cadaoperadorcombinalosvaloresproducidosporsusoperandosenunaformacompatibleconelanálisisgramaticaldelaexpresiónenqueaparece.

ElcomitéANSIdecidió,últimamenteensusreportes,restringirlaanteriorlibertaddereordenarlasexpresionesqueinvolucranoperadoresmatemáticamenteconmutativosyasociativos,peroquepuedennoserasociativoscomputacionalmente.Enlapráctica,elcambiosóloafectaaloscálculosdepuntoflotantecercanosaloslímitesdesuprecisiónyensituacionesendondeesposibleeldesbordamiento.

Elmanejodeldesbordamiento,erroresdedivisiónyotrascondicionesdeerrordentrodelaevaluacióndeexpresionesnoestádefinidoporellenguaje.LamayoríadelasrealizacionesexistentesdeCignoraneldesbordamientoenlaevaluacióndeexpresionesyasignacionesenterasconsigno,peroestecomportamientonoestágarantizado.Eltratodeladivisiónentre0,ytodaslascondicionesdeerrordepuntoflotante,varíaentrelasimplantaciones;algunasvecesesajustablemedianteelusodefuncionesnoestándardebiblioteca.

Page 306: Titivillus 07.07

A7.1.Generacióndeapuntadores

Sieltipodeunaexpresiónosubexpresiónesun“arreglodeT”,paraalgúntipoT,entonceselvalordelaexpresiónesunapuntadoralprimerobjetodelarreglo,yeltipodelaexpresiónesalteradoa“apuntadoraT”.Estaconversiónnosucedesilaexpresióneseloperandodeunoperador&unario,ode++,--,sizeof,oeloperandoizquierdodeunoperadordeasignacióno“eloperador.”Demodosemejante,unaexpresióndetipo“funciónqueregresaT”,exceptocuandoseutilizacomoeloperandodeloperador&,esconvertidaa“apuntadorafunciónqueregresaT”.Unaexpresiónquehasufridounadeestasconversionesnoesvalor-l.

Page 307: Titivillus 07.07

A7.2.Expresionesprimarias

Lasexpresionesprimariassonidentificadores,constantes,cadenas,oexpresionesentreparéntesis.

expresiónprimaria:

identificador

constante

cadena

(expresión)

Unidentificadoresunaexpresiónprimaria,siemprequehayasidodeclaradoadecuadamentetalcomosediscutióanteriormente.Sutipoestáespecificadoporsudeclaración.Unidentificadoresunvalor-lsiserefiereaunobjeto(§A5)ysisutipoesaritmético,estructura,uniónoapuntador.

Unaconstanteesunaexpresiónprimaria.Sutipodependedesuforma,talcomosediscutióen§A2.5.

Unacadenaesunaexpresiónprimaria.Sutipoesoriginalmente“arreglodechar”(paracadenasdecaracteresamplios,“arreglodewchar_t”),perosiguiendolaregladadaen§A7.1,usualmentesemodificaa“apuntadorachar”(wchar_t)yelresultadoesunapuntadoralprimercarácterdelacadena.Laconversióntampocoocurreenciertosinicializadores;véase§A8.7.

Unaexpresiónentreparéntesisesunaexpresiónprimariacuyotipoyvalorsonidénticosalosdeunaexpresiónquenoloesté.Lapresenciadeparéntesisnoafectaelquelaexpresiónseaunvalor-l.

Page 308: Titivillus 07.07

A7.3.Expresionesposfijas

Losoperadoresdeexpresionesposfijasseagrupandeizquierdaaderecha.

expresión-posfija:

expresión-primaria

expresión-posfija[expresión]

expresión-posfija(lista-de-expresiones-argumentoopt)

expresión-posfija.identificador

expresión-posfija->identificador

expresión-posfija++

expresión-posfija--

lista-expresiones-argumento:

expresión-de-asignación

lista-expresiones-argumento,expresión-de-asignación

Page 309: Titivillus 07.07

A7.3.1.Referenciasaarreglos

Unaexpresiónposfijaseguidaporunaexpresióndentrodecorchetesesunaexpresiónposfijaquedenotaunareferenciaindexadaaunarreglo.Unadelasdosexpresionesdebetenertipo“apuntadoraT”,dondeTesalgúntipo,ylaotradebetenertipoentero;eltipodelaexpresiónsubíndiceesT.LaexpresiónE1[E2]esidéntica(pordefinición)a*((E1)+(E2)).Véase§A8.6.2paraunadiscusiónadicional.

Page 310: Titivillus 07.07

A7.3.2.Llamadasafunciones

Unallamadaafunciónesunaexpresiónposfija,conocidacomodesignadordefunción,seguidodeparéntesisquecontienenunalistaposiblementevacíadeexpresionesdeasignaciónseparadasporcomas(§A7.17),queconstituyenlosargumentosdelafunción.Silaexpresiónposfijaconsisteenunidentificadorparaelquenoexisteunadeclaracióndentrodelalcanceactual,elidentificadoresexplícitamentedeclaradocomosiladeclaración

externintidentificador();

hubiesesidodadaenelbloquemásinternoquecontengalallamadaalafunción.Laexpresiónposfija(despuésdeunaposibledeclaraciónimplícitaygeneracióndeapuntador,§A7.1)debeserdeltipo“apuntadorafunciónqueregresaT”,paraalgúntipodeT,yelvalordelallamadaalafuncióntieneeltipoT.

Enlaprimeraedición,eltipoestabarestringidoa“función”yserequeríadeunoperador*explícitoparainvocaratravésdeapuntadoresafunciones.ElestándarANSIestádeacuerdoconalgunoscompiladoresexistentespermitiendolamismasintaxisparallamadasafuncionesyafuncionesespecificadasporapuntadores.Lasintaxisanterioraúnsepuedeutilizar.

Eltérminoargumentoseutilizaparaunaexpresiónpasadaporunallamadaafunción,eltérminoparámetroseempleaparaunobjetodeentrada(osuidentificador)recibidoporunadefinicióndefunciónodescritodentrodeladeclaracióndeunafunción.Lostérminos“argumento(parámetroreal)”y“argumento(parámetro)formal”respectivamente,seusanalgunasvecesparahacerlamismadistinción.

Enpreparaciónparalallamadaaunafunción,sehaceunacopiadecadaargumento;todoelpasodeargumentosesestrictamenteporvalor.Unafunciónpuedecambiarlosvaloresdesusobjetosparámetros,quesoncopiasdelasexpresionesargumentos,peroestoscambiosnopuedenafectarlosvaloresdelosargumentos.Sinembargo,esposiblepasarunapuntadorenelentendimientodequelafunciónpuedecambiarelvalordelobjetoalqueapuntaelapuntador.

Existendosestilosenlosquesepuedendeclararlasfunciones.Enelnuevoestilo,lostiposdelosparámetrossonexplícitosysonpartedeltipodelafunción;taldeclaraciónsellamatambiénelprototipodelafunción.Enelestiloanterior,lostiposdelosparámetrosnoseespecifican.Ladeclaracióndeunafunciónsetrataen§§A8.6.3yA10.1.

Siladeclaracióndefuncióndentrodelalcancedeunallamadaestáenelestiloanterior,entonceslapromocióndeargumentospredefinidaseaplicaencadaargumentocomosigue:lapromociónentera(§A6.1)serealizaencadaargumentodetipoentero,ycadaargumentofloatesconvertidoadouble.Elefectodelallamadaquedaindefinidosielnúmerodeargumentosnocoincideconelnúmerodeparámetrosdeladefinicióndelafunción,osieltipodeunargumentodespuésdelapromociónnocoincideconeldelparámetrocorrespondiente.Lacoincidenciadetiposdependedesilafuncióndelafunciónestáenelnuevooelviejoestilo.Siestáenelanterior,entonceslacomparaciónesentreeltipopromovidodelargumentodelallamadayeltipopromovidodelparámetro;siladefiniciónestáenelestilonuevo,eltipopromovidodelargumentodebesereldelparámetroensí,sinpromoción.

Page 311: Titivillus 07.07

Siladeclaracióndelafunciónenelalcancedeunallamadaestáenestilonuevo,entonceslosargumentosseconvierten,comoporasignación,alostiposdelosparámetroscorrespondientesdelprototipodelafunción.Elnúmerodeargumentosdebeserelmismoqueelnúmerodeparámetrosexplícitamentedeclarados,amenosdequelalistadeparámetrosdeladeclaracióntermineconlanotacióndecomaytrespuntos(,...).Enesecaso,elnúmerodeargumentosdebeigualaroexcederalnúmerodeparámetros;losargumentosmásalládelosparámetroscontipoexplícitamentedeclaradosufrenlapromociónpredefinidadeargumentosdescritaenelpárrafoprecedente.Siladefinicióndelafunciónestáenelestiloanterior,entonceseltipodecadaparámetrodentrodelprototipovisiblealallamadadebecoincidirconlosparámetroscorrespondientesdeladefinición,despuésdequealtipodeparámetrodeladefiniciónselehahecholapromocióndeargumentos.

Estasreglassonespecialmentecomplicadasdebidoaquedebensatisfacerunamezcladefuncionesenelnuevoyviejoestilos.Lasmezclassedebenevitarsiesposible.

Elordendeevaluacióndelosargumentosnoestáespecificado;nótesequeloscompiladoresdifieren.Sinembargo,losargumentosylosdesignadoresdefunciónsoncompletamenteevaluados,incluyendotodoslosefectoscolaterales,antesdequeseentrealafunción.Sepermitenlasllamadasrecursivasacualquierfunción.

Page 312: Titivillus 07.07

A7.3.3.Referenciasaestructuras

Unaexpresiónposfijaseguidaporunpuntoseguidodeunidentificadoresunaexpresiónposfija.Elprimeroperandodelaexpresióndebeserunaestructuraounaunión,yelidentificadordebenombraraunmiembrodelaestructuraounión.Elvaloreselmiembronombradodelaestructuraouniónysutipoeseltipodelmiembro.Laexpresiónesunvalor-lsilaprimeraexpresiónesunvalor-l,ysieltipodelasegundaexpresiónnoesuntipoarreglo.

Unaexpresiónposfijaseguidaporunaflecha(construidacon-y>)seguidaporunidentificadoresunaexpresiónposfija.Elprimeroperandoenlaexpresióndebeserunapuntadoraunaestructuraounauniónyelidentificadordebenombraraunmiembrodelaestructuraounión.Elresultadoserefierealmiembronombradodelaestructuraouniónalcualapuntaelapuntadordelaexpresión,yeltipoeseltipodelmiembro;elresultadoesunvalor-lsieltiponoesarreglo.

AsílaexpresiónE1->MOSeslomismoque(*E1).MOS.Lasestructurasyunionessediscutenen§A8.3.

Enlaprimeraedicióndeestelibroyaestabalaregladequeunnombredemiembroenunaexpresiónasíteníaqueperteneceralaestructuraouniónmencionadaenlaexpresiónposfija;sinembargo,unanotaadmitíaqueestareglanoseseguíafirmemente.LoscompiladoresrecientesyelANSIlasiguen.

Page 313: Titivillus 07.07

A7.3.4.Incrementosposfijos

Unaexpresiónposfijaseguidadeunoperador++o--esunaexpresiónposfija.Elvalordelaexpresióneselvalordeloperando.Despuésdeusarelvalor,seincrementaeloperando(++)osedecrementa(--)en1.Eloperandodebeserunvalor-l;véaselasdiscusióndeoperadoresaditivos(§A7.7)ydeasignación(§A7.17)paraposterioresrestriccioneseneloperandoydetallesdelaoperación.Elresultadonoesunvalor-l.

Page 314: Titivillus 07.07

A7.4.Operadoresunarios

Lasexpresionesconoperadoresunariosseagrupandederechaaizquierda.

expresión-unaria:

expresión-posfija

++expresión-unaria

--expresión-unaria

operador-unarioexpresión-cast

sizeofexpresión-unaria

sizeof(nombre-de-tipo)

operador-unario:unode

&*+-~!

Page 315: Titivillus 07.07

A7.4.1.Operadoresprefijosdeincremento

Unaexpresiónunariaprecedidaporunoperador++o--esunaexpresiónunaria.Eloperandoseincrementa(++)odecrementa(--)en1.Elvalordelaexpresióneselvalordespuésdelincremento(decremento).Eloperandodebeserunvalor-l;véaseladiscusióndeoperadoresaditivos(§A7.7)ydeasignación(§A7.17)paraposterioresrestriccioneseneloperandoydetallesdelaoperación.Elresultadonoesunvalor-l.

Page 316: Titivillus 07.07

A7.4.2.Operadordedirección

Eloperadorunario&tomaladireccióndesuoperando.Eloperandodebeserelvalor-lquenoserefieraniauncampodebitsniaunobjetodeclaradocomoregister,odebeserdetipofunción.Elresultadoesunapuntadoralobjetoofunciónalqueserefiereelvalor-l.SieltipodeloperandoesT,eltipodelresultadoes“apuntadoraT”.

Page 317: Titivillus 07.07

A7.4.3.Operadordeindirección

Eloperadorunario*denotaindirecciónyregresaelobjetoofunciónaqueapuntasuoperando.Esunvalor-lsieloperandoesunapuntadoraunobjetodetipoaritmético,estructura,uniónoapuntador.Sieltipodelaexpresiónesun“apuntadoraT”eltipodelresultadoesT.

Page 318: Titivillus 07.07

A7.4.4.Operadormásunario

Eloperandodeloperadorunario+debetenertipoaritméticooapuntadoryelresultadoeselvalordeloperando.Unoperandoenterosufrepromociónentera.Eltipodelresultadoeseltipodeloperandopromovido.

El+unarioesnuevoenelestándarANSI.Seagregóporsimetríaconel-unario.

Page 319: Titivillus 07.07

A7.4.5.Operadormenosunario

Eloperadordel-unariodebetenertipoaritméticoyelresultadoeselnegativodesuoperando.Unoperandoenterosufrepromociónentera.Elnegativodeunacantidadsinsignosecalcularestandoelvalorpromovidodelmayorvalordeltipopromovidoyagregándoleuno;peroelceronegativoescero.Eltipodelresultadoeseltipodeloperandopromovido.

Page 320: Titivillus 07.07

A7.4.6.Operadorcomplementoauno

Eloperandodeloperadorunario~debetenertipoenteroyelresultadoeselcomplementoaunodesuoperando.Serealizapromociónentera.Sieloperandoessinsigno,elresultadosecalcularestandoelvalordelmayorvalordeltipopromovido.Sieloperandoesconsigno,elresultadosecalculaconvirtiendoeloperandopromovidoaltiposinsignocorrespondiente,aplicando~yregresandoaltipoconsigno.Eltipodelresultadoeseltipodeloperandopromovido.

Page 321: Titivillus 07.07

A7.4.7.Operadordenegaciónlógica

Eloperandodeloperador!debetenertipoaritméticooserunapuntador,yelresultadoes1sielvalordesuoperandoescomparaiguala0,y0encasocontrario.Eltipodelresultadoesint.

Page 322: Titivillus 07.07

A7.4.8.Operadorsizeof

Eloperadorsizeofproduceelnúmerodebytesrequeridosparaalmacenarunobjetodeltipodesuoperando.Eloperandoesunaexpresión,quenoesevaluada,ounnombredetipoentreparéntesis.Cuandosizeofseaplicaachar,elresultadoes1;cuandoseaplicaaunarreglo,elresultadoeselnúmerototaldebytesenelarreglo.Cuandoseaplicaaunaestructuraounión,elresultadoeselnúmerodebytesenelobjeto,incluyendocualquierrellenorequeridoparacompletaraunarreglo:eltamañodeunarreglodenelementosesnveceseltamañodeunelemento.Eloperadornosepuedeaplicaraunoperandodetipofunciónodetipoincompleto,oauncampodebits.Elresultadoesunenteroconstantesinsigno;eltipoparticularsedefineporlaimplantación.Elheaderestándar<stddef.h>(véaseelapéndiceB)defineestetipocomosize_t.

Page 323: Titivillus 07.07

A7.5.Cast

Unaexpresiónunariaprecedidaporelnombreentreparéntesisdeuntipoprovocalaconversióndelvalordelaexpresiónaltiponombrado.

expresión-cast:

expresión-unaria

(nombre-de-tipo)expresión-cast

Estaconstrucciónsellamacast(conversiónforzada).Losnombresdetiposedescribenen§A8.8.Losefectosdeconversiónsondescritosen§A6.Unaexpresiónconuncastnoesunvalor-l.

Page 324: Titivillus 07.07

A7.6.Operadoresmultiplicativos

Losoperadoresmultiplicativos*,/,y%seagrupandeizquierdaaderecha.

expresión-multiplicativa:

expresión-cast

expresión-multiplicativa*expresión-cast

expresión-multiplicativa/expresión-cast

expresión-multiplicativa%expresión-cast

Losoperandosde*y/debentenertipoaritmético;losoperandosde%debentenertipoentero.Lasconversionesaritméticasusualesserealizansobrelosoperandos,yprediceneltipodelresultado.

Eloperadorbinario*denotamultiplicación.

Eloperadorbinario/produceelcocienteyeloperador%elresiduodeladivisióndelprimeroperandoentreelsegundo;sielsegundooperandoes0,elresultadoestáindefinido.Deotramanera,siempreesciertoque(a/b)*b+a%besigualquea.Siningunodelosoperandosesnegativo,entonceselresiduoesnonegativoymenorqueeldivisor;sinoloson,segarantizasóloqueelvalorabsolutodelresiduoesmenorqueelvalorabsolutodeldivisor.

Page 325: Titivillus 07.07

A7.7.Operadoresaditivos

Losoperadoresaditivos+y-seagrupandeizquierdaaderecha.Silosoperandostienentipoaritmético,serealizanlasconversionesaritméticasusuales.Existenalgunasposibilidadesadicionalesdetiposparacadaoperador.

expresión-aditiva:

expresión-multiplicativa

expresión-aditiva+expresión-multiplicativa

expresión-aditiva-expresión-multiplicativa

Elresultadodeloperador+eslasumadelosoperandos.Unapuntadoraunobjetoqueestéenunarregloyunvalordecualquiertipoenterosepuedensumar.Loúltimoseconvierteaunadireccióndedesplazamiento,multiplicándoloporeltamañodelobjetoalqueelapuntadorapunta.Lasumaesunapuntadordelmismotipoqueelapuntadororiginalyapuntaaotroobjetodentrodelmismoarreglo,desplazadoapropiadamentedelobjetooriginal.Así,siPesunapuntadoraunobjetoenunarreglo,laexpresiónP+1enunapuntadoralsiguienteobjetoenelarreglo.Sielapuntadordelasumaapuntafueradeloslímitesdelarreglo,exceptoalaprimeralocalidadmásalládelfinal,elresultadoesindefinido.

Laposibilidaddeapuntadoresmásalládelfinaldelarregloesnueva.Estolegitimizaunaexpresiónidiomáticacomúnparaiterarsobreloselementosdeunarreglo.

Elresultadodeloperador-esladiferenciadelosoperandos.Unvalordecualquiertipoenterosepuederestardeunapuntador,yseaplicanlasmismasconversionesycondicionesqueparalaadición.

Siserestandosapuntadoresaobjetosdelmismotipo,elresultadoesunvalorenteroconsignoquerepresentaeldesplazamientoentrelosobjetosapuntados;losapuntadoresaobjetossucesivosdifierenen1.Eltipodelresultadodependedelaimplantación,peroestádefinidocomoptrdiff_tenelheaderestándar<stddef.h>.Elvalorestáindefinidoamenosdequelosapuntadoresapuntenaobjetosdentrodelmismoarreglo;sinembargo,siPapuntaalúltimomiembrodeunarreglo,entonces(P+l)-Ptienevalor1.

Page 326: Titivillus 07.07

A7.8.Operadoresdecorrimiento

Losoperadoresdecorrimiento<<y>>seagrupandeizquierdaaderecha.Paraambosoperadores,cadaoperandodebeserenteroyestásujetoalaspromocionesenteras.Eltipodelresultadoeseldeloperandopromovidodelaizquierda.Elresultadoestáindefinidosieloperandodeladerechaesnegativo,mayoroigualalnúmerodebitsdeltipodelaexpresióndelaizquierda.

expresión-de-corrimiento:

expresión-aditiva

expresión-de-corrimiento<<expresión-aditiva

expresión-de-corrimiento>>expresión-aditiva

ElvalordeE1<<E2esE1(interpretadocomounpatróndebits)recorridoalaizquierdaE2bits;enausenciadedesbordamiento,estoesequivalentealamultiplicaciónpor2E2.ElvalordeE1>>E2esE1recorridoaladerechaE2posicionesdebits.Elcorrimientoaladerechaesequivalentealadivisiónentre2E2siE1esnotienesignoositieneunvalornonegativo;deotraformaelresultadoestádefinidoporlaimplantación.

Page 327: Titivillus 07.07

A7.9.Operadoresderelación

Losoperadoresderelaciónseagrupandeizquierdaaderecha,peroestonoesdeutilidad,a<b<cseanalizacomo(a<b)<c,ya<bseevalúacomo0ocomo1.

expresión-relacional:

expresión-de-corrimiento

expresión-relacional<expresión-de-corrimiento

expresión-relacional>expresión-de-corrimiento

expresión-relacional<=expresión-de-corrimiento

expresión-relacional>=expresión-de-corrimiento

Losoperadores<(menorque),>(mayorque),<=(menoroiguala)y>=(mayoroiguala)dantodos0silarelaciónespecificadaesfalsa,y1siesverdadera.Eltipodelresultadoesint.Lasconversionesaritméticasusualesserealizansobrelosoperandosaritméticos.Puedencompararselosapuntadoresaobjetosdelmismotipo;elresultadodependedelaslocalidadesrelativasenelespaciodedireccionamientodelosobjetosapuntados.Lacomparacióndeapuntadoresestádefinidasóloparapartesdelmismoobjeto:sidosapuntadoresapuntanalmismoobjetosimple,secomparancomoiguales;silosapuntadoreslohacenamiembrosdelamismaestructura,losapuntadoresaobjetosdeclaradosmásadelanteenlaestructurasecomparancomomayores;silosapuntadoressonamiembrosdelamismaunión,secomparancomoiguales;silosapuntadoreshacenreferenciaamiembrosdeunarreglo,lacomparaciónesequivalentealacomparacióndeloscorrespondientessubíndices.SiPapuntaalúltimomiembrodeunarreglo,entoncesP+1secomparacomomayorqueP,inclusoaunqueP+1apuntefueradelarreglo.Deotramanera,lacomparacióndeapuntadoresestáindefinida.

Estasreglasliberanalgolasrestriccionesestablecidasenlaprimeraedición,permitiendolacomparacióndeapuntadoresadiferentesmiembrosdeunaestructuraounión.Tambiénlegalizanlacomparaciónconunapuntadorjustomásalládelfinaldeunarreglo.

Page 328: Titivillus 07.07

A7.10.Operadoresdeigualdad

expresión-de-igualdad:

expresión-relacional

expresión-de-igualdad==expresión-relacional

expresión-de-igualdad!=expresión-relacional

Losoperadores==(iguala)y!=(noiguala)sonanálogosalosoperadoresderelaciónexceptoporsumenorprecedencia.(Asía<b==c<des1cuandoa<byc<dtenganlosmismosvaloresdeverdad).

Losoperadoresdeigualdadsiguenlasmismasreglasquelosoperadoresderelación,peropermitenposibilidadesadicionales:unapuntadorpuedesercomparadoconunaexpresiónconstanteenteraconvalor0,oconunapuntadoravoid.Véase§A.6.6.

Page 329: Titivillus 07.07

A7.11.OperadorANDparabits

expresión-AND:

expresión-de-igualdad

expresión-AND&expresión-de-igualdad

Lasconversionesaritméticasusualesserealizan;elresultadoeslafunciónANDdebitsdelosoperandos.Eloperadorseaplicasóloaoperandosenteros.

Page 330: Titivillus 07.07

A7.12.OperadorORexclusivoparabits

expresión-OR-exclusivo:

expresión-AND

expresión-OR-exclusivo^expresión-AND

Serealizanlasconversionesaritméticasusuales;elresultadoeslafunciónORexclusivodelosoperandos.Eloperadorseaplicasóloaoperandosenteros.

Page 331: Titivillus 07.07

A7.13.OperadorORinclusivoparabits

expresión-OR-inclusivo:

expresión-OR-exclusivo

expresión-OR-inclusivo|expresión-OR-exclusivo

Serealizanlasconversionesaritméticasusuales;elresultadoeslafunciónORinclusivodesusoperandos.Eloperadorseaplicasóloaoperandosenteros.

Page 332: Titivillus 07.07

A7.14.OperadorlógicoAND

expresión-lógica-AND:

expresión-OR-inclusivo

expresión-lógica-AND&&expresión-OR-inclusivo

Eloperador&&seagrupadeizquierdaaderecha.Regresa1siambosoperandossecomparancomodiferentesdecero;deotramanera,regresa0.Adiferenciade&,&&garantizalaevaluacióndeizquierdaaderecha:elprimeroperandoesevaluado,incluyendotodoslosefectoscolaterales;siesiguala0,elvalordelaexpresiónes0.Deotramanera,eloperandoderechoesevaluado,ysiesiguala0,elvalordelaexpresiónes0;deotramaneraes1.

Losoperandosnorequierendetenerelmismotipo,perocadaunodebetenertipoaritméticooserunapuntador.Elresultadoesint.

Page 333: Titivillus 07.07

A7.15.OperadorlógicoOR

expresión-lógica-OR:

expresión-lógica-AND

expresión-lógica-OR||expresión-lógica-AND

Eloperador||seagrupadeizquierdaaderecha.Regresa1sialgunodesusoperandosnosecomparacomocero,y0encasocontrario.Adiferenciade|,||garantizalaevaluacióndeizquierdaaderecha:elprimeroperandoesevaluado,incluyendolosefectoscolaterales;siesdiferentede0,elvalordelaexpresiónes1.Deotramanera,esevaluadoeloperandoderechoy,siesdiferentede0,elvalordelaexpresiónes1;deotramaneraescero.

Losoperandosnorequierentenerelmismotipo,perocadaunodeellosdebetenernuméricooserapuntador.Elresultadoesint.

Page 334: Titivillus 07.07

A7.16.Operadorcondicional

expresióncondicional:

expresión-lógica-OR

expresión-lógica-OR?expresión:expresión-condicional

Laprimeraexpresiónseevalúa,incluyendotodoslosefectoscolaterales;sisecomparacomodiferentede0,elresultadoeselvalordelasegundaexpresión;deotramanera,eseldelaterceraexpresión.Sóloseevalúaunodelosoperadoressegundootercero.Sielsegundoyelterceroperandossonaritméticos,serealizanlasconversionesaritméticasusualesparahacerlosdealgúntipocomúnyeseeseltipodelresultado.Siambossonvoid,estructurasounionesdelmismotipo,oapuntadoresaobjetosdelmismotipo,elresultadotieneeltipocomún.Siunoesunapuntadoryelotrolaconstante0,el0esconvertidoatipoapuntadoryelresultadotieneesetipo.Siunoesunapuntadoravoidyelotroesotroapuntador,elotroapuntadoresconvertidoaapuntadoravoidyéseeseltipodelresultado.

Enlacomparacióndetiposparaapuntadores,loscalificadoresdetipo(§A8.2)eneltipoalqueapuntaelapuntadornoimportan,peroelresultadoheredaloscalificadoresdeambasramasdelacondicional.

Page 335: Titivillus 07.07

A7.17.Expresionesdeasignación

Existenvariosoperadoresdeasignación;todosseagrupandederechaaizquierda.

expresión-de-asignación:

expresión-condicional

expresión-unariaoperador-de-asignaciónexpresión-de-asignación

operador-de-asignación:unode

=*=/=%=+=-=<<=>>=&=^=|=

Todosrequierendeunvalor-lcomooperandoizquierdoyestedebesermodificable:nodebeserunarregloynodebeteneruntipoincompletoniserunafunción.Tampocodebesercalificadoconconst;siesunaestructuraounión,nodebetenerningúnmiembroo,recursivamenteningúnsubmiembrocalificadoconconst.Eltipodeunaexpresióndeasignacióneseldesuoperandoizquierdo,yelvaloreselalmacenadoeneloperandoizquierdodespuésdequehatenidolugarlaasignación.

Enlaasignaciónsimplecon=,elvalordelaexpresiónreemplazaaldelobjetoalquesehacereferenciaconelvalor-l.Unodelossiguientesdebeserverdadero:ambosoperandostienentipoaritmético,entalcaso,eloperandodeladerechaesconvertidoaltipodeloperandoizquierdoporlaasignación;oambosoperandossonestructurasounionesdelmismotipo;ounoperandoesunapuntadoryelotroesunapuntadoravoid;oeloperandoizquierdoesunapuntadoryeloperandoderechoesunaexpresiónconstanteconvalor0;oambosoperandossonapuntadoresafuncionesuobjetoscuyostipossonlosmismosexceptoporlaposibleausenciadeconstovolatileeneloperandoderecho.

UnaexpresióndelaformaE1op=E2esequivalenteaEl=Elop(E2)exceptoqueE1esevaluadosólounavez.

Deacuerdoconlasrestriccionesanteriores,esilegalasignarapuntadorescuandoelladoderechoapuntaaunobjetodealgúntipoyelladoizquierdoapuntaaunobjetoconunaversióncalificadaconconstdeesetipo.Unalecturaestrictadeestareglaysuanálogaparacastcausadificultadesalimplantarciertasfuncionesdebiblioteca;seriabuenoquefueramenosrestricta.

Page 336: Titivillus 07.07

A7.18.Operadorcoma

expresión:

expresión-de-asignación

expresión,expresión-de-asignación

Unpardeexpresionesseparadasporunacomaseevalúadeizquierdaaderechayelvalordelaexpresiónizquierdasedescarta.Eltipoyvalordelresultadosoneltipoyvalordeloperandodeladerecha.Todoslosefectoscolateralesdelaevaluacióndeloperandoizquierdosecompletanantesdeprincipiarlaevaluacióndeloperandoderecho.Encontextosdondealacomaseledaunsignificadoespecial,porejemploenlistasdeargumentosparafunciones(§A7.3.2)ylistasdeinicializadores(§A8.7),launidadsintácticarequeridaesunaexpresióndeasignación,demodoqueeloperadorcomasóloapareceenunaagrupaciónlimitadaporparéntesis;porejemplo,

f(a,(t=3,t+2),c)

tienetresargumentos,elsegundodeloscualestieneelvalor5.

Page 337: Titivillus 07.07

A7.19.Expresionesconstantes

Sintácticamente,unaexpresiónconstanteesunaexpresiónrestringidaaunsubconjuntodeoperadores:

expresión-constante:

expresión-condicional

Lasexpresionesqueseevalúanaunaconstanteserequierenenvarioscontextos:despuésdecase,comolímitesdeunarregloylongitudesdecamposdebits,comovalordeunaconstantedeenumeración,eninicializadoresydentrodeciertasexpresionesdelpreprocesador.

Lasexpresionesconstantesnopuedencontenerasignaciones,operadoresdeincrementoodecremento,llamadasafuncionesnioperadorescoma,exceptoenunoperandodesizeof.Siserequierequelaexpresiónconstanteseaentera,susoperandosdebenconsistirenconstantesenteras,deenumeración,decaracteresyflotantes;loscastdebenestipularuntipoenteroycualquierconstanteflotantedebeserconvertidaaentero.Estonecesariamenteexcluyeoperacionessobrearreglos,indirección,dirección-deymiembrosdeestructura.(Sinembargo,sepermitecualquieroperandoparasizeof.)

Haymáslibertadparalasexpresionesconstantesdeinicializadores;losoperandospuedenserdecualquiertipodeconstanteyeloperandounario&puedeseraplicadoaobjetosexternosoestáticosyaarreglosexternosoestáticos,indexadosconunaexpresiónconstante.Eloperadorunario&tambiénsepuedeaplicarimplícitamenteporlaaparicióndearreglosnoindexadosyfunciones.Losinicializadoresdebenevaluarseaunaconstanteoaladireccióndeunobjetoexternooestáticopreviamentedeclaradomásomenosunaconstante.

Sepermitemenoslibertadparalasexpresionesenterasconstantesdespuésde#if;nosepermitenexpresionessizeof,constantesdeenumeraciónnicast.Véase§A12.5.

Page 338: Titivillus 07.07

A8.Declaraciones

Lasdeclaracionesespecificanlainterpretacióndadaacadaidentificador;nonecesariamentereservanespaciodealmacenamientoasociadoconelidentificador.Lasdeclaracionesquereservanalmacenamientosellamandefiniciones.Lasdeclaracionestienenlaforma

declaración:

especificadores-de-declaraciónlista-de-declaradores-initopt;

Losdeclaradoresqueestánenlalista-de-declaradores-initcontienenlalistadeidentificadoresqueestánsiendodeclarados;losespecificadores-de-declaraciónconsistenenunasecuenciadeespecificadoresdetipoycategoríadealmacenamiento.

especificadores-declaración:

especificador-categoría-almacenamientoespecificadores-de-declaraciónopt

especificador-de-tipoespecificadores-de-declaraciónopt

cualificador-de-tipoespecificadores-de-declaraciónopt

lista-declaradores-init:

declarador-init

lista-declaradores-init,declarador-init

declarador-init:

declarador

declarador=inicializador

Losdeclaradoressediscutiránposteriormente(§A8.5),ycontienenlosnombresqueestánsiendodeclarados.Unadeclaracióndebeteneralmenosundeclaradorosuespecificadordetipodebedeclararelrótulodeunaestructura,unrótulodeuniónolosmiembrosdeunaenumeración;nosepermitendeclaracionesvacías.

Page 339: Titivillus 07.07

A8.1.Especificadoresdecategoríadealmacenamiento

Losespecificadoresdecategoríadealmacenamientoson:

especificador-categoria-almacenamiento:

auto

register

static

extern

typedef

Lossignificadosdelascategoríasdealmacenamientosediscutieronen§A4.

Leespecificadoresautoyregisterdanalosobjetosdeclaradoscategoríadealmacenamientoautomáticoysólosepuedenusardentrodefunciones.Talesdeclaracionestambiénsirvencomodefinicionesyprovocanquesereservealmacenamiento.Unadeclaraciónregisteresequivalenteaunadeclaraciónauto,perosugierequeseharáaccesofrecuentealosobjetosdeclarados.Pocosobjetossonrealmentelocalizadosenregistrosysólociertostipossonelegibles;lasrestriccionessondependientesdelaimplantación.Sinembargo,siunobjetoesdeclaradoregister,eloperadorunario&noselepuedeaplicar,explícitaoimplícitamente.

Laregladequeesilegalcalcularladireccióndeunobjetodeclaradoregister,peroquerealmentesetomarácomoauto,esnueva.

Elespecificadorstaticdaalosobjetosdeclaradoscategoríadealmacenamientoestática,ysepuedeempleardentroofueradelasfunciones.Dentrodeunafunción,esteespecificadorprovocaqueseasignealmacenamientoysirvecomodefinición;parasusefectosfueradeunafunción,véase§A11.2.

Unadeclaraciónconextern,utilizadadentrodeunafunción,especificaqueelalmacenamientoparalosobjetosdeclaradosestádefinidoenalgúnotrolugar;parasusefectosfueradeunafunción,véase§A11.2.

Elespecificadortypedefnoreservaalmacenamientoysellamaespecificadordecategoríadealmacenamientosóloporconvenienciasintáctica;sediscuteen§A8.9.

Cuandomássepuededarunespecificadordecategoríadealmacenamientodentrodeunadeclaración.Sinosedaninguno,seutilizanestasreglas:losobjetosdeclaradosdentrodeunafunciónsetomancomoauto;lasfuncionesdeclaradasdentrodeunafunciónsetomancomoextern;losobjetosyfuncionesdeclaradosfueradeunafunciónsetomancomoestáticos,conligaexterna.Véase§§A10-A11.

Page 340: Titivillus 07.07

A8.2.Especificadoresdetipo

Losespecificadoresdetiposon

especificador-de-tipo:

void

char

short

int

long

float

double

signed

unsigned

especificador-estructura-o-unión

especificador-enum

nombre-typedef

Cuandomássepuedeespecificarunadelaspalabraslongoshortjuntoconint;elsignificadoeselmismosinosemencionaint.Lapalabralongsepuedeespecificarjuntocondouble.Cuandomássepuedeespecificarunadelaspalabrassignedounsignedjuntoconintocualquieradesusvariantes,short,longoconchar.Cualquieradelasdospuedeaparecersola;entalcasoseentiendecomoint.Elespecificadorsignedesútilparaforzaralosobjetoscharatenersigno;espermisibleperoredundantedentrodeotrostiposenteros.

Deotramanera,cuandomássepuededarunespecificadordetipoenundeclaración.Sielespecificadordetiposeomitedeunadeclaración,setomacomoint.

Lostipostambiénsepuedencalificar,paraindicarpropiedadesespecialesdelosobjetosqueestánsiendodeclarados.

calificador-de-tipo

const

volatile

Loscalificadoresdetipopuedenaparecerconcualquierespecificadordetipo.Unobjetoconstsepuedeinicializar,perodespuésnoselepuedeasignarnada.Nohaysemánticaindependientedelaimplantaciónparaobjetosvolatile.

Page 341: Titivillus 07.07

LaspropiedadesconstyvolatilesonnuevasdentrodelestándarANSI.Elpropósitodeconstesanunciarobjetosquepuedenserlocalizadosenmemoriadesólolecturaytalvezincrementarlasoportunidadesparaoptimización.Elpropósitodevolatileesforzaralaimplantaciónasuprimirlaoptimizaciónque,deotramanera,podríaocurrir.Porejemplo,paraunamáquinaconentrada/salidaasignadoamemoria,elapuntadoraunregistrodedispositivosepodríadeclararcomounapuntadoravolatileparaprevenirqueelcompiladorremuevalasreferenciasaparentementeredundantesatravésdelapuntador.Exceptoquedebediagnosticarexplícitamentelosintentosdecambiarobjetosconst,elcompiladorpuedeignorarestoscalificadores.

Untercercalificador,noalias,permanecebajoconsideraciónporelcomitédeestandarización.

Page 342: Titivillus 07.07

A8.3.Declaracionesdeestructurayunión

Unaestructuraesunobjetoqueconstadeunasecuenciademiembrosnombradosdevariostipos.Unauniónenunobjetoquecontiene,enmomentosdistintos,cualquieradealgunosmiembrosdevariostipos.Losespecificadoresdeestructurayunióntienenlamismaforma.

especificador-estructura-o-unión:

estructura-o-uniónidentificadoropt{lista-declaraciones-struct}

estructura-o-uniónidentificador

estructura-o-unión:

struct

unión

Unalista-de-declaraciones-structesunasecuenciadedeclaracionesparalosmiembrosdelaestructuraounión:

lista-declaraciones-struct:

declaración-struct

lista-declaraciones-structdeclaración-struct

declaración-struct:

lista-calificador-especificadorlista-de-declaradores-struct;

lista-cualificador-especificador:

especificador-de-tipolista-calificador-especificadoropt

calificador-de-tipolista-calificador-especificadoropt

lista-declaradores-struct:

declarador-struct

lista-declaradores-struct,declarador-struct

Porlogeneral,undeclarador-structessóloundeclaradorparaunmiembrodeestructuraounión:Unmiembrodeestructuratambiénpuedeconstardeunnúmeroespecificadodebits.Talmiembrotambiénsellamacampodebits,osimplementecampo;uncarácterdospuntosmarcaeliniciodesulongituddespuésdelnombredelcampo.

declarador-struct:

Page 343: Titivillus 07.07

declarador

declaradoropt:expresión-constante

Unespecificadordetipodelaforma

estructura-o-uniónidentificador{lista-declaraciones-struct}

declaraqueelidentificadorseráelrótulodelaestructuraouniónespecificadoporlalista.Unadeclaraciónposteriorenelmismoalcanceomásinternosepuedereferiralmismotipoutilizandoelrótulodentrodeunespecificadorsinlalista:

estructura-o-uniónidentificador

Siapareceunespecificadorconunrótuloperosinlistacuandoelrótulonoestádeclarado,seespecificauntipoincompleto.Losobjetoscontipoincompletodeestructuraouniónsepuedenmencionarencontextosdondenoseanecesariosutamaño,porejemplo,endeclaraciones(nodefiniciones),paraestipularunapuntadoroparacrearuntypedef,peronodeotramanera.Eltiposecompletaalpresentarseunespecificadorsubsecuenteconeserótuloquecontengaunalistadedeclaraciones.Inclusoenespecificadoresconunalista,eltipodelaestructuraouniónqueestásiendodeclaradoesincompletodentrodelalista,ysecompletasóloenelqueterminaelespecificador.

Unaestructuranopuedecontenerunmiembrodetipoincompleto.Porlotanto,esimposibledeclararunaestructuraouniónquecontengaunainstanciadeellamisma.Sinembargo,ademásdedarunnombrealtipodeestructuraounión,losrótulospermitenladefinicióndeestructurasautorreferenciadas;unaestructuraouniónpuedecontenerunapuntadoraunainstanciadeellamisma,debidoaquepuedenserdeclaradosapuntadoresatiposincompletos.

Unareglamuyespecialseaplicaadeclaracionesdelaforma

estructura-o-uniónidentificador;

quedeclaraunaestructuraounión,peronotienelistadedeclaracionesnideclaradores.Aunsielidentificadoresunrótulodeestructuraouniónyadeclaradoenunalcancemásexterno(§A11.1),estadeclaraciónhacealidentificadorelrótulodeunanuevaestructuraounión,detipoincompleto,enelalcanceactual.

EstareglaesnuevabajoANSI.Sufunciónestratarconestructurasmutuamenterecursivasdeclaradasenunalcancemásinterno,perocuyosrótulospodríanhabersidoyadeclaradosenelalcancemásexterno.

Unespecificadordeestructuraouniónconunalistasinrótulocreauntipoúnico;selepuedehacerreferenciadirectamentesóloenladeclaracióndelaqueesparte.

Losnombresdemiembrosyrótulosnoentranenconflictoentreellosoconvariablesordinarias.Unnombredemiembronopuedeaparecerdosvecesenlamismaestructuraounión,peroelmismonombredemiembrosepuedeemplearendiferentesestructurasouniones.

Enlaprimeraedicióndeestelibro,losnombresdemiembrosdeestructurasyunionesnoestabanasociadosconsupadre.Sinembargo,estaasociaciónsehizocomúnencompiladoresmuchoantesdelestándarANSI.

Unmiembroquenoseacampodeunaestructuraouniónpuedetenercualquiertipode

Page 344: Titivillus 07.07

objeto.Unmiembrocampo(quenorequieretenerundeclaradory,portanto,puedenotenernombre)tienetipoint,unsignedint,osignedint,yesinterpretadocomounobjetodetipoenterodelalongitudenbitsespecificada;elqueuncampointsetratecomoconsignodependedelaimplantación.Loscamposadyacentesquesonmiembrosdeestructurasseempaquetanenunidadesdealmacenamientodependientesdelaimplantaciónenunadireccióntambiéndependiente.Cuandohaylaposibilidaddequeuncampoquesigueaotronoentreenunaunidaddealmacenamientoparcialmentellena,sepuedesepararenunidades,olaunidadsepuederellenar.Uncamposinnombreconamplitud0fuerzaaesterellenado,demodoqueelsiguientecampoprincipiaráenlaorilladelasiguienteunidaddeasignación.

ElestándarANSIhacequeloscamposseanaúnmásdependientesdelaimplantaciónquelaprimeraedición.Esrecomendableleerlasreglasdellenguajeparaalmacenarcamposdebitscomo“dependientesdelaimplantación”sinlimitaciones.Lasestructurasconcamposdebitssepuedenemplearcomounaformatransportabledeintentarreducirelalmacenamientorequeridoparaunaestructura(conelcostoprobabledeincrementarelespaciodeinstruccionesytiempoparateneraccesoaloscampos),ocomounaformanotransportablededescribirunaplantilladealmacenamientoconocidaalniveldebits.Enelsegundocaso,esnecesarioentenderlasreglasdelaimplantaciónlocal.

Losmiembrosdeunaestructuratienendireccionesascendentesenelordendesusdeclaraciones.Deunaestructuraunmiembroquenoseacamposealineaconunlímitededireccionamientodependiendodesutipo;portanto,puedehaberhuecossinnombredentrodeunaestructura.Siunapuntadoraunaestructuraesconvertidoaltipodeunapuntadorasuprimermiembro,elresultadoserefierealprimermiembro.

Sepuedepensarenunaunióncomounaestructuradondetodossusmiembrosprincipianeneldesplazamiento0ycuyotamañoessuficienteparaconteneracualquieradesusmiembros.Cuandomás,unodelosmiembrospuedeseralmacenadodentrodeunauniónalavez.Siunapuntadorauniónesconvertidoaltipodeunapuntadoraunmiembro,elresultadoserefiereaesemiembro.

Unejemplosimplededeclaracióndeestructuraes

structtnode{

chartword[20];

intcount;

structtnode*left;

structtnode*right;

};

quecontieneunarreglode20caracteres,unenteroydosapuntadoresaestructurassemejantes.Unavezquesehadadoestadeclaración,ladeclaración

structtnodes,*sp;

declarascomounaestructuradelavariedaddadayspcomoapuntadoraunaestructuradeesetipo.Conestasdeclaraciones,laexpresión

sp->count

Page 345: Titivillus 07.07

serefierealcampocountdelaestructuraalaqueapuntasp;

s.left

serefierealapuntadoralsubárbolizquierdodelaestructuras;y

s.right->tword[0]

serefierealprimercarácterdelmiembrotworddelsubárbolderechodes.

Engeneralunmiembrodeunauniónnopuedeserinspeccionadoamenosdequeelvalordelauniónhayasidoasignadoutilizandoesemiembro.Sinembargo,unaconsideraciónespecialsimplificaelusodeuniones:siunaunióncontienevariasestructurasquecompartenunasecuenciainicialcomún,ysilauniónactualmentecontieneunadeesasestructuras,sepermitehacerreferenciaalaparteinicialcomúndecualesquieradelasestructurascontenidas.Porejemplo,elsiguientefragmentoeslegítimo:

union{

struct{

inttype;

}n;

struct{

inttype;

intintnode;

}ni;

struct{

inttype;

floatfloatnode;

}nf;

}u;

...

u.nf.type=FLOAT;

u.nf.floatnode=3.14;

...

if(u.n.type==FLOAT)

...sin(u.nf.floatnode)...

Page 346: Titivillus 07.07

A8.4.Enumeraciones

Lasenumeracionessontiposconvaloresquefluctúanentreunconjuntodeconstantesnombradasquesellamanenumeradores.Laformadeunespecificadordeenumeraciónsetomadeladelasestructurasyuniones.

especificador-enum:

enumidentificadoropt{lista-de-enumerador}

enumidentificador

lista-de-enumerador:

enumerador

lista-de-enumerador,enumerador

enumerador:

identificador

identificador=expresión-constante

Losidentificadoresdentrodeunalistadeenumeradorsedeclarancomoconstantesdetipointypuedenaparecerencualquierlugardondeserequieraunaconstante.Sinoaparecenenumeradorescon=,entonceslosvaloresdelascorrespondientesconstantesprincipianen0yseincrementanen1alleerladeclaracióndeizquierdaaderecha.Unenumeradorcon=daalidentificadorasociadoelvalorespecificado;losidentificadoressubsecuentescontinúanlaprogresióndelvalorasignado.

Losnombresdeenumeradoresenelmismoalcancedebenserdistintosentresíydelosnombresdevariablesordinarias,peronoesnecesarioquelosvaloresseandistintos.

Elpapeldelidentificadorenelespecificador-enumesanálogoaldelrótulodelasestructurasenunespecificador-de-estructura;nombraunaenumeraciónparticular.Lasreglasparaespecificadores-enumconysinrótulosylistassonlasmismasqueparaespecificadoresdeestructurasyuniones,exceptoquelostiposdeenumeraciónincompletanoexisten;elrótulodeunespecificador-enumsinunalistadeenumeradoresdebereferirseaunespecificadorenelalcancedentrodelalista.

Lasenumeracionessonnuevasdesdelaprimeraedicióndeestelibro,perohansidopartedellenguajeporalgunosaños.

Page 347: Titivillus 07.07

A8.5.Declaradores

Losdeclaradorestienenlasintaxis:

declarador

apuntadoroptdeclarador-directo

declarador-directo:

identificador

(declarador)

declarador-directo[expresión-constanteopt]

declarador-directo(lista-tipos-de-parámetro)

declarador-directo(lista-de-identificadoresopt)

apuntador:

*lista-calificadores-de-tipoopt

*lista-calificadores-de-tipooptapuntador

lista-calificadores-de-tipo:

calificador-de-tipo

lista-calificadores-de-tipocalificador-de-tipo

Laestructuradelosdeclaradoresessemejantealadelasexpresionesdeindirección,funcionesyarreglos;elagrupamientoeselmismo.

Page 348: Titivillus 07.07

A8.6.Significadodelosdeclaradores

Lalistadedeclaradoresaparecedespuésdeunasecuenciadeespecificadoresdecategoríadetipoyalmacenamiento.Cadadeclaradordeclaraunidentificadorprincipalúnico,queaparececomolaprimeraalternativadelaproducciónparadeclarador-directo.Losespecificadoresdecategoríadealmacenamientoseaplicandirectamenteaesteidentificador,perosutipodependedelaformadesudeclarador.Undeclaradoresleídocomolaafirmacióndequecuandosuidentificadorapareceenunaexpresióndelamismaformaqueeldeclarador,produceunobjetodeltipoespecificado.

Considerandosólolaspartesdetipodelosespecificadoresdedeclaración(§A8.2)yundeclaradorparticular,unadeclaracióntienelaforma“TD”,dondeTesuntipoyDesundeclarador.Eltipoatribuidoalidentificadorenlasvariasformasdeldeclaradorsedescribeinductivamenteempleandoestanotación.

EnunadeclaraciónTDdondeDesunidentificadorsolo,eltipodelidentificadoresT.

EnunadeclaraciónTDdondeDtienelaforma

(D1)

eltipodelidentificadorenD1eselmismoqueeldeD.Losparéntesisnoalteraneltipo,peropuedencambiarlaasociacióndedeclaradorescomplejos.

Page 349: Titivillus 07.07

A8.6.1.Declaradoresdeapuntadores

EsunadeclaraciónTDendondeDtienelaforma

*lista-calificadores-de-tipooptD1

yeltipodelidentificadorqueestáenladeclaraciónTD1es“modificador-de-tipoT”,eltipodelidentificadordeDes“modificador-de-tipolista-calificadores-de-tipoapuntadoraT”.Loscalificadoresquesiguenal*seaplicanalapuntadorensí,noalobjetoalqueapunta.

Porejemplo,considereladeclaración,

int*ap[];

Aquíap[]juegaelpapeldeD1;unadeclaración“intap[]”(másabajo)daráaapeltipo“arreglodeint”,lalistacalificador-de-tipoestávacía,yelmodificador-de-tipoes“arreglode”.Porconsiguienteladeclaracióndaaapeltipo“arreglodeapuntadoresaint”.

Comootrosejemplos,lasdeclaraciones

inti,*pi,*constcpi=&i;

constintci=3,*pci;

declaranunenteroiyunapuntadoraunenteropi.Elvalordelapuntadorconstantecpinopuedesercambiado;siempreapuntaalamismalocalidad,aunqueelvaloralqueserefierepuedeseralterado.Elenterociesconstante,ynosepuedecambiar(aunquesísepuedeinicializar,comoaquí).Eltipodepcies“apuntadoraconstint”,ypciensípuedesermodificadaparaapuntaraotrolugar,peroelvaloralqueapuntanosepuedealterarporasignaciónatravésdepci.

Page 350: Titivillus 07.07

A8.6.2.Declaradoresdearreglos

EnunadeclaraciónTDdondeDtienelaforma

D1[expresión-constanteopt]

yeltipodelidentificadorenladeclaraciónTD1es“modificador-de-tipoT”,eltipodelidentificadorDes“modificador-de-tipoarreglodeT”.Silaexpresión-constanteestápresente,debeserdetipoentero,yconvalormayorque0.Siseomitelaexpresiónconstantequeespecificaellímite,elarreglotienetipoincompleto.

Unarreglosepuedeconstruirapartirdeuntipoaritmético,deunapuntador,deunaestructuraouniónodeotroarreglo(paragenerarunarreglodevariasdimensiones).Cualquiertipodelqueseconstruyaunarreglodebesercompleto;nodebeserunarreglooestructuradetipoincompleto.Estoimplicaqueparaunarreglomultidimensional,sólosepuedeomitirlaprimeradimensión.Eltipodeunobjetodetipoarregloincompletosecompletaconotradeclaraciónparaelobjeto(§A10.2),completaoporsuinicialización(§A8.7).Porejemplo,

floatfa[17],*afp[17];

declaraunarreglodenúmerofloatyunarreglodeapuntadoresanúmerofloat.Porotrolado,

staticintx3d[3][5][7];

declaraunarreglotridimensionalestáticodeenteros,conrango3×5×7.Contododetalle,x3desunarreglodetreselementos;cadaelementoesunarreglodecincoarreglos;cadaunodelosúltimosarreglosesunarreglodesieteenteros.Cualquieradelasexpresionesx3d,x3d[i],x3d[i][j],x3d[i][j][k]puedenaparecerrazonablementedentrodeunaexpresión.Losprimerostrestienentipo“arreglo”yelúltimotienetipoint.Másespecíficamente,x3d[i][j]esunarreglode7enteros,yx3d[i]esunarreglode5arreglosde7enteros.

LaoperacióndeindexadodeunarregloestádefinidademodoqueE1[E2]esidénticaa*(E1+E2).Porlotanto,fueradesuaparienciaasimétrica,laindexaciónesunaoperaciónconmutativa.Debidoalasreglasdeconversiónqueseaplicana+yalosarreglos(§§A6.6,A7.1,A7.7),siE1esunarregloyE2unentero,entoncesE1[E2]serefierealE2-ésimomiembrodeE1.

Enelejemplo,x3d[i][j][k]esequivalentea*(x3d[i][j]+k).Laprimerasubexpresiónx3d[i][j]seconviertepor§A7.1altipo“apuntadoraarreglodeenteros”;por§A7.7,laadicióninvolucramultiplicaciónporeltamañodeunentero.Delasreglassesiguequelosarreglossealmacenanporrenglones(elúltimosubíndicevaríamásrápido),yqueelprimersubíndicedentrodeladeclaraciónayudaadeterminarlacantidaddealmacenamientoconsumidoporunarreglo,peronotienemásutilidadenelcálculodesubíndices.

Page 351: Titivillus 07.07

A8.6.3.Declaracióndefunciones

EnunadeclaracióndelnuevoestiloTD,dondeDtienelaforma

D1(lista-tipos-de-parámetro)

yeltipodelidentificadordentrodeladeclaraciónTD1es“modificador-de-tipoT”,eltipodelidentificadordeDes“modificador-de-tipofunciónconargumentolista-tipos-de-parámetrosqueregresaT”.

Lasintaxisdelosparámetroses

lista-tipos-de-parámetro:

lista-de-parámetros

lista-de-parámetros,...

lista-de-parámetros:

declaración-parámetro

lista-de-parámetros,declaración-parámetro

declaración-parámetro:

especificadores-de-declaracióndeclarador

especificadores-de-declaracióndeclarador-abstractoopt

Enladeclaracióndelnuevoestilo,lalistadeparámetrosestipulalostiposdelosparámetros.Comouncasoespecial,eldeclaradorparaunafuncióndelnuevoestilosinparámetrostieneunalistadetiposdeparámetrosconsistenteúnicamenteenlapalabrareservadavoid.Silalistadetiposdeparámetrosfinalizaconpuntossuspensivos“,...”entonceslafunciónpuedeaceptarmásargumentosqueelnúmerodeparámetrosdescritosexplícitamente;ver§A7.3.2.

Lostiposdeparámetrosquesonarreglosofuncionessealteranyquedancomoapuntadores,deacuerdoconlasreglasparaconversionesdeparámetros;ver§A10.1.Elúnicoespecificadordecategoríadealmacenamientopermitidodentrodeunespecificadordedeclaracióndeparámetrosesregister,yesteespecificadoresignoradoamenosqueeldeclaradordefunciónencabeceunadefinicióndefunción.Demodosemejante,silosdeclaradoresqueestánenlasdeclaracionesdeparámetroscontienenidentificadores,yeldeclaradordefunciónnoencabezaunadefinicióndefunción,losidentificadoressaleninmediatamentedelalcance.Losdeclaradoresabstractos,quenomencionanalosidentificadores,sediscutenen§A8.8.

EnunadeclaracióndefuncióndelestiloanteriorTD,dondeDtienelaforma

D1(lista-de-identificadoresopt)

yeltipodelidentificadordentrodeladeclaraciónTD1es“modificador-de-tipoT”,el

Page 352: Titivillus 07.07

tipodelidentificadordeDes“modificador-de-tipofuncióndeargumentosnoespecificadosqueregresaT”.Losparámetros(siestánpresentes)tienenlaforma

lista-de-identificadores:

identificador

lista-de-identificadores,identificador

Eneldeclaradordelestiloanterior,lalistadeidentificadoresdebeestarausenteamenosdequeeldeclaradorseutiliceenelencabezadordeunadefinicióndefunción(§A10.1).Ladeclaraciónnoproporcionaningunainformaciónacercadelostiposdelosparámetros.Porejemplo,ladeclaración

intf(),*fpi(),(*pfi)();

declaraunafunciónfqueregresaunentero,unafunciónfpiqueregresaunapuntadoraunentero,yunapuntadorpfiaunafunciónqueregresaunentero.Enningunadeéstasseespecificalalistadeparámetros;estánenestiloanterior.

Enunadeclaracióndelnuevoestilo

intstrcpy(char*dest,constchar*source),rand(void);

strcpyesunafunciónqueregresaunint,condosargumentos,elprimeroesunapuntadoracarácteryelsegundounapuntadoracaracteresconstantes.Losnombresdelosparámetrossonrealmentecomentarios.Lasegundafunciónrandnoempleaargumentosyregresaint.

Losdeclaradoresdefuncionesconprototiposdeparámetrosson,conmucho,elcambiomásimportanteintroducidoallenguajeporelestándarANSI.Ofrecenunaventajasobrelosdeclaradores“delestiloanterior”delaprimeraedición,proporcionandodeteccióndeerroresyconversióndeargumentosentrellamadasafunciones,peroauncosto;desordenyconfusióndurantesuintroducción,ylanecesidaddepermitirambasformas.Serequirieronalgunasaberracionessintácticasparacompatibilidad,comovoid,usadocomounamarcaexplícitadelasfuncionessinparámetrosdelnuevoestilo.

Lanotacióndepuntossuspensivos“,...”parafuncionesconnúmerovariabledeargumentostambiénesnuevay,juntoconlasmacrosenelheaderestándar<stdarg.h>,formalizaunmecanismoqueestuvooficialmenteprohibidoperoextraoficialmentepermitidoenlaprimeraedición.

EsasnotacionesfueronadaptadasdellenguajeC++.

Page 353: Titivillus 07.07

A8.7.Inicialización

Cuandosedeclaraunobjeto,sudeclarador-initpuedeespecificarunvalorinicialparaelidentificadorqueestásiendodeclarado.Elinicializadoresprecedidopor=,yesunaexpresiónounalistadeinicializadoresanidadosentrellaves.Unalistapuedeterminarconcoma,unbuendetalleparaunformatoclaro.

inicializador:

expresión-asignación

{lista-de-inicializadores}

{lista-de-inicializadores,}

lista-de-inicializadores:

inicializador

lista-de-inicializadores,inicializador

Todaslasexpresionesdelinicializadorparaunobjetooarregloestáticodebenserexpresionesconstantestalcomosedescribeen§A7.19.Lasexpresionesenelinicializadorparaunobjetooarregloautooregisterdebenigualmenteserexpresionesconstantessielinicializadoresunalistaencerradaentrellaves.Sinembargo,sielinicializadorparaunobjetoautomáticoesunaexpresiónsimple,norequiereserunaexpresiónconstante,sinoquedebetenersimplementeeltipoapropiadoparalaasignaciónalobjeto.

Laprimeraediciónnoaprobabalainicializacióndeestructurasautomáticas,unionesoarreglos.ElestándarANSIlopermite,perosóloporconstruccionesconstantesamenosqueelinicializadorsepuedaexpresarconunaexpresiónsimple.

Unobjetoestáticonoinicializadoexplícitamenteseinicializacomosiaél(oasusmiembros)seleasignalaconstante0.Elvalorinicialdeunobjetoautomáticoquenoestéexplícitamenteinicializadoesindefinido.

Elinicializadorparaunapuntadorounobjectodetipoaritméticoesunaexpresiónsimple,quizásentrellaves.Laexpresiónseasignaalobjecto.

Elinicializadorparaunaestructuraesounaexpresióndelmismotipo,ounalistaentrellavesdeinicializadoresparasusmiembrosenorden.Sihaymenosinicializadoresquelosmiembrosdelaestructura,losúltimosmiembrossoninicializadoscon0.Nopuedehabermásinicializadoresquemiembros.

Elinicializadorparaunarregloesunalistadeinicializadoresentrellavesparasusmiembros.Sielarreglotienetamañodesconocido,elnúmerodeinicializadoresdeterminaeltamañodelarregloysutiposecompleta.Sielarreglotienetamañofijo,elnúmerodeinicializadoresnopuedeexcederalnúmerodemiembrosdelarreglo;sihaymenos,losúltimosmiembrossoninicializadoscon0.

Comocasoespecial,unarreglodecaracteressepuedeinicializarconunacadenaliteral;loscaracteressucesivosdelacadenainicializanmiembrossucesivosdelarreglo.

Page 354: Titivillus 07.07

Demodosemejante,uncarácterliteralamplio(§A2.6)puedeinicializarunarreglodetipowchar_t.Sielarreglotienetamañodesconocido,elnúmerodecaracteresenlacadena,incluyendoelcarácternulodeterminación,determinasutamaño;sisutamañoesfijo,elnúmerodecaracteresdelacadena,sincontarelcarácternulodeterminación,nodebeexcederaltamañodelarreglo.

Elinicializadorparaunauniónesunaexpresiónsimpledelmismotipoouninicializadorentrellavesparaelprimermiembrodelaunión.

Laprimeraediciónnopermitíalainicializaciónparauniones.Laregladel“primermiembro”esconfusa,peroesdifícilgeneralizarsinlanuevasintaxis.Ademásdepermitirquelasunionesseaninicializadasexplícitamente,almenosenunaformaprimitiva,estareglaANSIvuelvedefinitivalasemánticadeunionesestáticasnoinicializadasexplícitamente.

Unagregadoesunaestructuraounarreglo.Siunagregadocontienemiembrosdetipoagregado,lasreglasdeinicializaciónseaplicanenformarecursiva.Lasllavespuedendesaparecerdelainicializacióncomosigue:sielinicializadorparaunmiembrodeagregadoqueensíesunagregadoprincipiaconunallaveizquierda,entonceslalistadeinicializadoresseparadosporcomaquesigueinicializalosmiembrosdelsubagregado;eserróneoquehayamásinicializadoresquemiembros.Sinembargo,sielinicializadorparaunsubagregadonoprincipiaconunallaveizquierda,entoncessólosetomandelalistaloselementossuficientesparalosmiembrosdelsubagregado;cualesquieramiembrosrestantessedejanparainicializarelsiguientemiembrodelagregadodelcualelsubagregadoesparte.

Porejemplo,

intx[]={1,3,5};

declaraeinicializaxcomounarreglodeunadimensióncontresmiembros,puestoquenosehaespecificadotamañoyexistentresinicializadores.

floaty[4][3]={

{1,3,5},

{2,4,6},

{3,5,7},

};

esunainicializacióncompletamenteentrellaves:1,3,y5inicializanalprimerrenglóndearregloy[0],esdeciry[0][0],y[0][1],yy[0][2].Enigualforma,lassiguientesdoslíneasinicializany[1]yy[2].Elinicializadorterminaantesy,porlotanto,loselementosdey[3]soninicializadoscon0.Precisamenteelmismoefectosepuedeobtenercon

floaty[4][3]={

1,3,5,2,4,6,3,5,7

};

Elinicializadorparayprincipiaconunallaveizquierda,peroeldey[0]no,porloqueseutilizantreselementosdelalista.Delamismaformalossiguientestreselementosdelalistasetomansucesivamenteparay[1]ydespuésy[2].También,

Page 355: Titivillus 07.07

floaty[4][3]={

{1},{2},{3},{4}

};

inicializalaprimeracolumnadey(consideradocomounarreglobidimensional)ydejaalrestoen0.

Finalmente,

charmsg[]="Errordesintaxisenlínea%s\n";

muestraunarreglodecaracterescuyosmiembrossoninicializadosconunacadena;sutamañoincluyeelcarácternulodeterminación.

Page 356: Titivillus 07.07

A8.8.Nombresdetipos

Dentrodemuchoscontextos(paraespecificarlasconversionesdetipoexplícitamenteconuncast,paradeclarartiposdeparámetrosendeclaradoresdefunción,ycomounargumentodesizeof)esnecesarioproporcionarelnombredeuntipodedato.Estoselograutilizandounnombredetipo,quesintácticamenteesunadeclaraciónparaunobjetodeesetipo,omitiendoelnombredelobjeto.

nombre-de-tipo:

lista-calificador-especificadordeclarador-abstractoopt

declarador-abstracto:

apuntador

apuntadoroptdeclarador-abstracto-directo

declarador-abstracto-directo:

(declarador-abstracto)

declarador-abstracto-directoopt[expresión-constanteopt]

declarador-abstracto-directoopt(lista-tipos-de-parámetroopt)

Esposibleidentificarunívocamenteellugardentrodeldeclaradorabstractoendondepodríaaparecerelidentificadorsilaconstrucciónfueraundeclaradorenunadeclaración.Eltiponombradoesentonceselmismoqueeltipodelidentificadorhipotético.Porejemplo,

int

int*

int*[3]

int(*)[]

int*()

int(*[])(void)

nombrarespectivamentelostipos“entero”,“apuntadoraentero”,“arreglode3apuntadoresaenteros”,“apuntadoraunarreglodeunnúmeronoespecificadodeenteros”,“funcióndeparámetrosnoespecificadosqueregresaunapuntadoraentero”y“arreglo,detamañonoespecificado,deapuntadoresafuncionessinparámetrosqueregresacadaunaunentero”.

Page 357: Titivillus 07.07

A8.9.Typedef

Lasdeclaracionescuyoespecificadordecategoríadealmacenamientoestypedefnodeclaranobjetos;enlugardeellodefinenidentificadoresquenombrantipos.Esosidentificadoressellamannombrestypedef.

nombre-typedef:

identificador

Unadeclaracióntypedefatribuyeuntipoacadanombreentresusdeclaradoresenlaformausual(ver§A8.6).Luegodeeso,cadanombretypedefessintácticamenteequivalenteaunapalabrareservadaparaespecificadordetipoparaeltipoasociado.

Porejemplo,despuésde

typedeflongBlockno,*Blockptr;

typedefstruct{doubler,theta;}Complex;

lasconstrucciones

Blocknob;

externBlockptrbp;

Complexz,*zp;

sondeclaracioneslegítimas.Eltipodebeslong,eldebpes“apuntadoralong”,yeldezeslaestructuraespecificada;zpesunapuntadoratalestructura.

typedefnointroducenuevostipos,sóloformassinónimasparatiposquesepodríanmencionarenotraforma.Enelejemplo,btieneelmismotipoquecualquierotroobjetolong.

Losnombrestypedefsepuedenredeclarardentrodeunalcancemásinterno,perosedebedarunconjuntonovacíodeespecificadoresdetipo.Porejemplo,

externBlockno;

noredeclaraaBlockno,pero

externintBlockno;

sílohace.

Page 358: Titivillus 07.07

A8.10.Equivalenciadetipo

Doslistasdeespecificadoresdetiposonequivalentessicontienenelmismoconjuntodeespecificadoresdetipo,tomandoencuentaquealgunosespecificadorespuedenimplicarotros(porejemplo,longsoloimplicalongint).Estructuras,uniones,yenumeracionesconrótulosdiferentessondistintas,yunaunión,estructura,oenumeraciónsinrótuloestipulauntipoúnico.

Dostipossonelmismosisusdeclaradoresabstractos(§A8.8),despuésdeexpandircualesquieratipostypedefydeeliminarcualesquieraidentificadoresdeparámetrosdefunción,sonlasmismasoequivalenteslistasdeespecificadoresdetipo.Lostamañosdelosarreglosylosparámetrosdelasfuncionessonsignificativos.

Page 359: Titivillus 07.07

A9.Proposiciones

Exceptoendondeasísedescribe,lasproposicionesseejecutanensecuencia.Lasproposicionesseejecutanporsusefectosynotienenvalores.Entranenvariosgrupos.

proposición:

proposición-etiquetada

proposición-expresión

proposición-compuesta

proposición-de-selección

proposición-de-iteración

proposición-de-salto

Page 360: Titivillus 07.07

A9.1.Proposicionesetiquetadas

Lasproposicionespuedenteneretiquetascomoprefijos.

proposición-etiquetada:

identificador:proposición

caseexpresión-constante:proposición

default:proposición

Unaetiquetaconsistenteenunidentificadordeclaraalidentificador.Elúnicousodeunaetiquetaidentificadoraescomodestinodeungoto.Elalcancedelidentificadorestádentrodelafunciónactual.Debidoaquelasetiquetastienensupropioespaciodenombre,nointerfierenconotrosidentificadoresynosepuedenredeclarar.Véase§A11.1.

Lasetiquetasdecaseydefaultseaplicanconlaproposiciónswitch(§A9.4).Laexpresiónconstantedelcasedebetenertipoentero.

Lasetiquetasporsímismasnoalteranelflujodecontrol.

Page 361: Titivillus 07.07

A9.2.Proposicióndeexpresión

Lamayoríadelasproposicionessonproposicionesdeexpresión,quetienenlaforma

proposición-expresión:

expresiónopt;

Lamayoríadelasproposicionesexpresionessonasignacionesollamadasafunción.Todoslosefectoscolateralesdelaexpresiónsoncompletadosantesdeejecutarlasiguienteproposición.Silaexpresiónseomite,laconstrucciónsellamaproposiciónnula;amenudoseempleaparaproporcionaruncuerpovacíoaunaproposicióndeiteraciónoparasituarunaetiqueta.

Page 362: Titivillus 07.07

A9.3.Proposicióncompuesta

Paraquesepuedanutilizarvariasproposicionesdondeseesperauna,seproporcionalaproposicióncompuesta(tambiénllamada“bloque”).Elcuerpodeunadefinicióndefunciónesunaproposicióncompuesta.

proposición-compuesta:

{lista-declaraciónoptlista-de-proposicionesopt}

lista-de-declaraciones:

declaración

lista-de-declaracionesdeclaración

lista-de-proposiciones:

proposición

lista-de-proposicionesproposición

Siunidentificadordentrodelalista-de-declaracionesestuvoenunalcanceexterioralbloque,ladeclaraciónmásexternasesuspendedentrodelbloque(véase§A11.1),despuésdelocualcontinúa.Unidentificadorsepuededeclararsólounavezdentrodelmismobloque.Estasreglasseaplicanaidentificadoresdentrodelmismoespaciodenombre(§A11);losidentificadoresdentrodeespaciosdenombrediferentessontratadoscomodistintos.

Lainicializacióndeobjetosautomáticosserealizacadavezqueseentraalbloqueporlapartesuperior,yprocedeenelordendelosdeclaradores.Siseejecutaunsaltodentrodelbloque,estasinicializacionesnoserealizan.Lasinicializacionesdeobjetosstaticserealizansólounavez,antesdequeelprogramacomiencesuejecución.

Page 363: Titivillus 07.07

A9.4.Proposicionesdeselección

Lasproposicionesdeseleccióneligenunodevariosflujosdecontrol.

proposición-de-selección:

if(expresión)proposición

if(expresión)proposiciónelseproposición

switch(expresión)proposición

Enambasformasdelaproposiciónif,laexpresión,quedebeseraritméticaodetipoapuntador,esevaluada,incluyendotodoslosefectoscolaterales,ysisecomparacomodiferentede0,seejecutalaprimerasubproposición.Enlasegundaforma,lasegundasubproposiciónseejecutasilaexpresiónes0.Laambigüedaddelelseseresuelveconectandounelseconelúltimoifsinelseencontradoenelmismoniveldeanidamientodelbloque.

Laproposiciónswitchprovocaqueelcontrolseatransferidoaunadevariasproposiciones,dependiendodelvalordeunaexpresión,quedebetenertipoentero.Lasubproposicióncontroladaporunswitchusualmenteescompuesta.Cualquierproposicióndentrodelasubproposiciónsepuedeetiquetarconunaomásetiquetascase(§A9.1).Laexpresióndecontroltienepromociónintegral(§A6.1),ylasconstantesdeloscasesonconvertidasaltipopromovido.Nosepermitequedosdelasexpresionescaseasociadasconelmismoswitchpuedantenerelmismovalordespuésdelaconversión.Cuandomáspuedehaberunaetiquetadefaultasociadaconunswitch.Lasproposicionesswitchpuedenestaranidadas;unaetiquetacaseodefaultestáasociadaconelswitchmásanidadoquelacontiene.

Cuandoseejecutalaproposiciónswitch,suexpresiónseevalúaincluyendotodoslosefectoscolateralesyescomparadaconcadaconstantedelcase.Siunadelasconstantescaseesigualalvalordelaexpresión,elcontrolpasaalaproposicióndelaetiquetacasecoincidente.Siningunaconstantecasecoincideconlaexpresiónysiexisteunaetiquetadefault,elcontrolpasaalaproposiciónetiquetada.Siningúncasocoincideynohaydefault,entoncesnoseejecutaningunadelassubproposicionesdelswitch.

Enlaprimeraedicióndeestelibro,serequeríaquelaexpresióndecontroldelswitchylasconstantescasetuvierantipoint.

Page 364: Titivillus 07.07

A9.5.Proposicionesdeiteración

Lasproposicionesdeiteraciónespecificanlaejecucióndeunciclo.

proposición-de-iteración:

while(expresión)proposición

doproposiciónwhile(expresión);

for(expresiónopt;expresiónopt;expresiónopt)proposición

Enlasproposicioneswhileydo,lasubproposiciónseejecutaenformarepetidamientrasqueelvalordelaexpresiónpermanezcadiferentede0;laexpresióndebetenertipoaritméticooapuntador.Conwhile,laprueba,incluyendotodoslosefectoscolateralesdelaexpresión,ocurreantesdecadaejecucióndelaproposición;condo,lapruebasiguedecadaiteración.

Enlaproposiciónfor,laprimeraexpresiónseevalúaunavezyespecificalainicializaciónparaelciclo.Nohayrestricciónencuantoasutipo.Lasegundaexpresióndebetenertipoaritméticooapuntador;seevalúaantesdecadaiteracióny,siesiguala0,elfortermina.Laterceraexpresiónseevalúaantesdecadaiteraciónyespecificaunareinicializaciónparaelciclo.Nohayrestricciónencuantoasutipo.Losefectoscolateralesdecadaexpresiónsecompletaninmediatamentedespuésdesuevaluación.Silasubproposiciónnocontienecontinue,unaproposición

for(expresión1;expresión2;expresión3)proposición

esequivalentea

expresión1;

while(expresión2){

proposición

expresión3;

}

Cualquieradelastresexpresionessepuededescartar.Lafaltadeunasegundaexpresiónhacequelapruebaimplicadaseaequivalenteaprobarunaconstantediferentedecero.

Page 365: Titivillus 07.07

A9.6.Proposicionesdesalto

Lasproposicionesdesaltotransfierenelcontrolincondicionalmente.

proposición-de-salto:

gotoidentificador;

continue;

break;

returnexpresiónopt;

Enlaproposicióngoto,elidentificadordebeserunaetiqueta(§A9.1)localizadaenlafunciónactual.Elcontrolsetransfierealaproposiciónetiquetada.

Unaproposicióncontinuesólopuedeaparecerdentrodeunaproposicióndeiteración,yocasionaqueelcontrolpasealaporcióndecontinuacióndelciclomásanidadoqueencierraatalproposición.Enformamásprecisa,dentrodecadaunadelasproposiciones

while(...){

...

contin:;

}

do{

...

contin:;

}while(...);

for(...){

...

contin:;

}

uncontinuequenoestécontenidodentrodeunaproposicióndeiteraciónmásanidadaeslomismoquegotocontin.

Unaproposiciónbreakpuedeaparecersólodentrodeunaproposicióndeiteraciónodeunaproposiciónswitch,yterminalaejecucióndelomásanidadoqueencierretalproposición;elcontrolpasaalaproposiciónquesiguealaproposiciónterminada.

Page 366: Titivillus 07.07

Unafunciónregresaaquienlainvocóconlaproposiciónreturn.Cuandoreturnesseguidoporunaexpresión,elvalorseregresaalinvocadordelafunción.Laexpresiónseconviene,comosiseasignara,altiporegresadoporlafunciónenlaqueaparece.

Queelflujolleguehastaelfinaldelafunciónesequivalenteaunreturnsinexpresión.Encualquiercaso,elvalorregresadoestáindefinido.

Page 367: Titivillus 07.07

A10.Declaracionesexternas

LaunidaddeentradaproporcionadaalcompiladordeCsellamaunidaddetraducción;consisteenunasecuenciadedeclaracionesexternas,quesondeclaracionesodefinicionesdefunción.

unidad-de-traducción:

declaración-externa

unidad-de-traduccióndeclaración-externa

declaración-externa:

definición-de-función

declaración

Elalcancedelasdeclaracionesexternaspersistehastaelfinaldelaunidaddetraducciónenlaquesondeclaradas,precisamentecomoelefectodelasdeclaracionesdentrodelosbloquespersistehastaelfinaldelbloque.Lasintaxisdelasdeclaracionesexternaseslamismaqueparatodaslasdeclaraciones,exceptoqueelcódigodelasfuncionessólosepuededarenestenivel.

Page 368: Titivillus 07.07

A10.1.Definicióndefunciones

Lasdefinicionesdefuncionestienenlaforma

definición-de-función:

especificadores-de-declaraciónoptdeclaradorlista-de-declaracionesoptproposición-compuesta

Losúnicosespecificadoresdecategoríadealmacenamientopermitidosentrelosespecificadoresdedeclaraciónsonexternostatic;véase§A11.2paraladistinciónentreellos.

Unafunciónpuederegresaruntipoaritmético,unaestructura,unaunión,unapuntadorovoid,peronounafunciónounarreglo.Eldeclaradorenladeclaracióndeunafuncióndebeespecificarexplícitamentequeelidentificadordeclaradotienetipofunción;estoes,debecontenerunadelasformas(véase§A8.6.3)

declarador-directo(lista-tipos-de-parámetros)

declarador-directo(lista-de-identificadoresopt)

dondeeldeclarador-directoesunidentificadorounidentificadorconparéntesis.Enparticular,nodebeadquirireltipodefunciónpormediodeuntypedef.

Enlaprimeraforma,ladefiniciónesunafunciónenelestilonuevo,ysusparámetros,juntoconsustipos,sondeclaradosdentrodesulistadetiposdeparámetros;lalista-de-declaracionesquesiguealdeclaradordelafuncióndebeestarausente.Salvoquelalistadetiposdeparámetrosconsistasolamenteenvoid,mostrandoquelafunciónnotieneparámetros,cadadeclaradorqueestéenlalistadetiposdeparámetrosdebecontenerunidentificador.Silalistadetiposdeparámetrosterminacon“,...”entonceslafunciónsepuedellamarconmásargumentosqueparámetros;parahacerreferenciaalosargumentosextrasedebeutilizarelmecanismodelamacrova_argdefinidoenelheaderestándar<stdarg.h>ydescritoenelapéndiceB.Lasfuncionesconnúmerovariabledeargumentosdebenteneralmenosunparámetronombrado.

Enlasegundaforma,ladefiniciónestáenelestiloanterior:lalistadeidentificadoresnombralosparámetros,entantoquelalistadedeclaracioneslesatribuyetipos.Sinosedaningunadeclaraciónparaunparámetro,sutiposetomacomoint.Lalistadedeclaracionesdebedeclararsolamenteparámetrosnombradosenlalista;noestápermitidalainicializaciónyelúnicoespecificadordecategoríadealmacenamientoposibleesregister.

Enambosestilosdedefinicióndefunciones,seentiendequelosparámetrosserándeclaradosprecisamentedespuésdelprincipiodelaproposicióncompuestaqueconstituyeelcuerpodelafunciónynopuedenserredeclaradosallílosmismosidentificadores(aunquepodrían,comootrosidentificadores,serredeclaradosenbloquesmásinternos).Sisedeclaraqueunparámetrotendrátipo“arreglodetipo”,ladeclaraciónseajustaparaser“apuntadoratipo”;demanerasemejante,siunparámetroesdeclaradocontipo“funciónqueregresatipo”,ladeclaraciónseajustacomo“apuntadorafunciónqueregresatipo”.Durantelallamadaaunafunción,losargumentosseconviertendeacuerdoconlasnecesidadesysonasignadosalosparámetros;véaseA7.3.2.

Page 369: Titivillus 07.07

LadefinicióndefuncionesenelnuevoestiloesnuevaenelestándarANSI.Tambiénhayunpequeñocambioenlosdetallesdelapromoción;laprimeraediciónestipulaquelasdeclaracionesdeparámetrosfloatseajustaronparaleersecomodouble.Ladiferenciaesnotoriacuandodentrodeunafunciónsegeneraunapuntadoraunparámetro.

Unejemplocompletodeunafunciónenelestilonuevoes

intmax(inta,intb,intc)

{

intm;

m=(a>b)?a:b;

return(m>c)?m:c;

}

Aquíinteselespecificadordeladeclaración;max(inta,intb,intc)eseldeclaradordelafunción,y{...}eselbloqueconelcódigoparalafunción.Lacorrespondientedefiniciónenelestiloanteriorsería

intmax(a,b,c)

inta,b,c;

{

/*...*/

)

dondeahoraintmax(a,b,c)eseldeclarador,einta,b,c;eslalistadedeclaracionesparalosparámetros.

Page 370: Titivillus 07.07

A10.2.Declaracionesexternas

Lasdeclaracionesexternasestipulanlascaracterísticasdeobjetos,funcionesyotrosidentificadores.Eltérmino“externa”serefiereasulocalizaciónfueradelasfunciones,ynoestádirectamenteconectadoconlapalabrareservadaextern;lacategoríadealmacenamientoparaunobjetodeclaradoexternamentepuededejarsevacía,osepuedeespecificarcomoexternostatic.

Puedenexistirmuchasdeclaracionesexternasparaelmismoidentificadordentrodelamismaunidaddetraducciónsicorrespondenconsutipoyliga,ysihaycuandomásunadefiniciónparaelidentificador.

Dosdeclaracionesparaunobjetoofunciónsehacencoincidirentipobajolasreglasdiscutidasen§A8.10.Además,silasdeclaracionesdifierendebidoaqueuntipoesunaestructura,uniónoenumeraciónincompleta(§A8.3)yelotroeseltipocompletocorrespondienteconelmismorótulo,seconsideraquelostiposcoinciden.Másaún,siunoesuntipodearregloincompleto(§A8.6.2)yelotroesuntipodearreglocompleto,lostipos,siporlodemássonidénticos,tambiénseconsiderancoincidentes.Finalmente,siuntipoestipulaunafunciónenelestiloanterioryelotrounafunciónenelnuevoyporlodemásidéntica,condeclaracióndeparámetros,lostipossetomancomocoincidentes.

Silaprimeradeclaraciónexternaparaunafunciónuobjetoincluyeelespecificadorstatic,éstetieneligainterna;deotramaneratieneligaexterna.Laligasediscuteen§A11.2.

Unadeclaraciónexternaparaunobjetoesunadefiniciónsitieneinicializador.Ladeclaracióndeunobjetoexternoquenotieneinicializadorynocontieneelespecificadorextern,esunadefinicióntentativa.Sienunaunidaddetraducciónapareceunadefiniciónparaunobjeto,cualesquieradeclaracionestentativassetratansimplementecomodeclaracionesredundantes.Sinoapareceningunadefiniciónparaelobjetodentrodelaunidaddetraducción,todassusdefinicionestentativasseconviertenenunasoladefiniciónconinicializador0.

Cadaobjetodebetenerexactamenteunadefinición.Paraobjetosconligainterna,estareglaseaplicaenformaseparadaparacadaunidaddetraducción,debidoaquelosobjetosligadosinternamentesonúnicosparaunaunidaddetraducción.Paraobjetosconligaexternaseaplicaalprogramacompleto.

Aunquelaregladeunasoladefiniciónestáformuladaalgodiferenteenlaprimeraedicióndeestelibro,esenefectoigualalaqueseestableceaquí.Algunasimplantacioneslaaligeran,generalizandolaideadedefinicióntentativa.Enlaformulaciónalterna,queescomúnensistemasUNIXyreconocidacomounaextensióncomúnporelestándar,todaslasdefinicionestentativasparaunobjetoligadoexternamente,atravésdetodaslasunidadesdetraduccióndeunprograma,seconsideranjuntasenlugardeseparadamenteencadaunidaddetraducción.Sienalgúnlugardelprogramaocurreunadefinición,entonceslasdefinicionestentativassonsimplesdeclaraciones,perosinoapareceningunadefinición,entoncestodassusdefinicionestentativassehacendefinicionesconinicializador0.

Page 371: Titivillus 07.07

A11.Alcanceyliga

Noesnecesarioqueunprogramasecompiletodoalavez:eltextofuentesepuedemantenerenvariosarchivosconunidadesdetraducción,ysepuedencargarrutinasprecompiladasdebibliotecas.Lacomunicaciónentrelasfuncionesdeunprogramapuedellevarseacabotantoatravésdellamadascomoatravésdelamanipulacióndedatosexternos.

Portanto,existendosclasesdealcanceaconsiderar:primera,elalcanceléxicodeunidentificador,queeslaregióndeltextodelprogramadentrodelaqueseentiendenlascaracterísticasdelidentificador;ysegunda,elalcanceasociadoconobjetosyfuncionesconligaexterna,quedeterminalaconexiónentreidentificadoresenunidadesdetraduccióncompiladasporseparado.

Page 372: Titivillus 07.07

A11.1.Alcanceléxico

Losidentificadoressedividenenvariosespaciosdenombrequenointerfierenentresí;elmismoidentificadorsepuedeutilizarparadiferentespropósitos,inclusodentrodelmismoalcance,silosusossonendiferentesespaciosdenombre.Estascategoríasson:objetos,funciones,nombrestypedefyconstantesenum;etiquetas;rótulosdeestructura,unionesyenumeraciones;ymiembrosdecadaestructuraouniónindividualmente.

Estasreglasdifierenenvariasformasdelasdescritasenlaprimeraedicióndeestemanual.Lasetiquetasnoteníananteriormentesupropioespaciodenombre;losrótulosdeestructurasydeunionesteníancadaunosuespacioseparado,yenalgunasimplantacionestambiénloteníanlosrótulosdeenumeraciones;colocarlasdiferentesclasesderótulosenelmismoespacioesunanuevarestricción.Elmásimportantealejamientodelaprimeraediciónesquecadaestructuraounióncreaunespaciodenombreseparadoparasusmiembros,demodoqueenvariasestructuraspuedeaparecerelmismonombre.Estareglahasidounaprácticacomúnpormuchosaños.

Elalcanceléxicodelidentificadordeunobjetoofuncióndentrodeunadeclaraciónexternaprincipiaalfinaldesudeclaradorypersistehastaelfinaldelaunidaddetraducciónenlaqueaparece.Elalcancedelparámetrodeunadefinicióndefunciónprincipiaaliniciodelbloquequedefinelafunción,ypersisteatravésdelafunción;elalcancedeunparámetroenladeclaracióndelafunciónterminaalfinaldeldeclarador.Elalcancedeunidentificadordeclaradoalacabezadeunbloqueprincipiaalfinaldesudeclaradorypersistehastaelfinaldelbloque.Elalcancedeunaetiquetaeslatotalidaddelafunciónenlacualaparece.Elalcancedelrótulodeunaestructura,uniónoenumeración,odeunaconstantedeenumeración,principiaalaparecerenunespecificadordetipoypersistehastaelfinaldelaunidaddetraducción(paradeclaracionesenelnivelexterno)ohastaelfinaldelbloque(paradeclaracionesdentrodeunafunción).

Siunidentificadorsedeclaraexplícitamentealacabezadeunbloque,incluyendoelqueconstituyealafunción,cualquierdeclaracióndelidentificadorfueradelmismobloquesesuspendehastaelfinal.

Page 373: Titivillus 07.07

A11.2.Liga

Dentrodeunaunidaddetraducción,todaslasdeclaracionesdelmismoidentificadordeobjetoofunciónconligainternaserefierenalamismacosa,yelobjetoofunciónesúnicoparaesaunidaddetraducción.Todaslasdeclaracionesparaelmismoidentificadordeobjetoofunciónconligaexternaserefierenalamismacosa,yelobjetoofunciónescompartidoportodoelprograma.

Comosediscutióen§A10.2,laprimeradeclaraciónexternaparaunidentificadordaalidentificadorligainternasiseusaelespecificadorstatic,deotramanera,ledaligaexterna.Siladeclaraciónparaunidentificadordentrodeunbloquenoincluyeelespecificadorextern,elidentificadornotieneligayesúnicoparalafunción.Siincluyeexternyhayunadeclaraciónexternaactivaparaelidentificadordentrodelalcancequerodeaalbloque,entonceselidentificadortienelamismaligaqueladeclaraciónexternayserefierealmismoobjetoofunción;perosinohayningunadeclaraciónexternavisible,suligaesexterna.

Page 374: Titivillus 07.07

A12.Preprocesamiento

Unpreprocesadorrealizamacrosubstituciones,compilacióncondicionaleinclusióndearchivosnombrados.Laslíneasqueprincipiancon#,aunqueesténprecedidasporespaciosenblanco,secomunicanconestepreprocesador.Lasintaxisdeestaslíneasesindependientedelrestodellenguaje;puedenaparecerencualquierlugarysuefectotermina(independientementedelalcance)hastaelfinaldelaunidaddetraducción.Loslímitesdelaslíneassonsignificativos;cadalíneaseanalizaindividualmente(perovéase§A12.2cómounirlíneas).Paraelpreprocesador,untokenesuntokendellenguajeounasecuenciadecaracteresquedaunnombredearchivocomoenladirectiva#include(§A12.4);además,cualquiercarácterquenoestédefinidodeotramanerasetomacomotoken.Sinembargo,elefectodeloscaracteresespacioenblancoquenoseanespacioytabuladorhorizontalestádefinidodentrodelaslíneasdelpreprocesador.

Elpreprocesamientosucedeenvariasfaseslógicamentesucesivasque,enunaimplantaciónenparticular,sepuedencondensar.

Primero,lassecuenciastrigráficasquesedescribenen§A12.1sonreemplazadasporsusequivalentes.Derequerirloelmedioambientedelsistemaoperativo,seintroducencaracteresnuevalíneaentrelaslíneasdelarchivofuente.

Cadaocurrenciadeuncarácterdiagonalinversa\seguidoporunanuevalíneaseelimina,uniendoasílíneas(§A12.2).

Elprogramasedivideen

tokens

separadosporcaracteresespacioenblanco;loscomentariossereemplazanporunsoloespacio.Despuésseobedecenlasdirectivasdepreprocesamiento,ylasmacros(§§A12.3-A12.10)seexpanden.

Lassecuenciasdeescapequeestándentrodecaracteresycadenasliteralesconstantes(§§A2.5.2,A2.6)sereemplazanporsusequivalentes;despuésseconcatenanlascadenasliteralesadyacentes.

Elresultadosetraduce,despuésseligajuntoconotrosprogramasybibliotecas,recolectandolosprogramasydatosnecesariosyconectandolasfuncionesyobjetosexternosconsusdefiniciones.

Page 375: Titivillus 07.07

A12.1.Secuenciastrigráficas

ElconjuntodecaracteresdelosprogramasfuentedeCestácontenidodentrodelcódigoASCIIdesietebits,peroesunsuperconjuntodelISO646-1983InvariantCodeSet.Parapoderrepresentaralosprogramasenelconjuntoreducido,todaslasocurrenciasdelassiguientessecuenciastrigráficassereemplazanporelcaráctersimplecorrespondiente.Estereemplazoocurreantesdecualquierotroprocesamiento.

??=

#

??(

[

??<

{

??/

\

??)

]

??>

}

??'

^

??!

|

??-

~

Noocurreningúnotroreemplazo.

LassecuenciastrigráficassonnuevasenelestándarANSI.

Page 376: Titivillus 07.07

A12.2.Unióndelíneas

Laslíneasqueterminanconelcarácterdiagonalinvertida\seempalmaneliminandoladiagonalinversayelsiguientecarácternuevalínea.Estoocurreantesdehacerladivisiónentokens.

Page 377: Titivillus 07.07

A12.3.Definiciónyexpansióndemacros

Unalíneadecontroldelaforma

#defineidentificadorsecuencia-de-tokens

hacequeelpreprocesadorreemplacelasinstanciassubsecuentesdelidentificadorconlasecuenciadetokensdada;sedescartanlosespaciosenblancoqueseencuentranalrededordelasecuenciadetokens.Unsegundo#defineparaelmismoidentificadoreserróneoamenosquelasegundasecuenciadetokensseaidénticaalaprimera,endondetodoslosespaciosenblancoseconsideranequivalentes.

Unalíneadelaforma

#defineidentificador(lista-de-identificadores)secuencia-de-tokens

dondenohayespacioenblancoentreelprimeridentificadoryel(,esunamacrodefiniciónconparámetrosdadosporlalistadeidentificadores.Talcomolaprimeraforma,losespaciosenblancoalrededordelasecuenciadetokenssedescartan,ylamacropuederedefinirsesóloconunadefiniciónenlaqueelnúmeroydescripcióndeparámetrosylasecuenciadetokensseaidéntica.

Unalíneadecontroldelaforma

#undefidentificador

hacequeelpreprocesadorolvideladefinicióndelidentificador.Noeserróneoaplicar#undefaunidentificadordesconocido.

Cuandounamacrosehadefinidoenlasegundaforma,lasinstanciastextualesposterioresdelidentificadordelamacroseguidasporespacioenblancooptativo,ydespuéspor(,unasecuenciadetokensseparadosporcomasyun),constituyenunallamadaalamacro.Losargumentosdelallamadasonlassecuenciasdetokensseparadosporcomas;lascomasqueseencuentranentrecomillasoprotegidasporparéntesisanidadosnoseparanargumentos.Durantelarecolecciónlosargumentosnosonmacroexpandidos.Elnúmerodeargumentosenlallamadadebecoincidirconelnúmerodeparámetrosenladefinición.Despuésdequelosargumentosseaíslan,seremuevenlosespaciosenblancoquelosprincipianyfinalizan.Despuéssesubstituyelasecuenciadetokensresultantedecadaargumentoporcadaocurrencianoentrecomilladadelidentificadordelparámetrocorrespondienteenlasecuenciadereemplazodetokensdelamacro.Amenosdequeelparámetroenlasecuenciadereemplazoestéprecedidopor#,oprecedidooseguidopor##,lostokensargumentosseexaminanparamacrollamadasyseexpandencomoseanecesario,justoantesdelainserción.

Dosoperadoresespecialesinfluyensobreelprocesodereemplazo.Primero,silaocurrenciadeunparámetroenlasecuenciadetokensdereemplazoestáprecedidainmediatamentepor#,secolocancomillas(")alrededordelparámetrocorrespondienteydespués,tantoel#comoelidentificadordelparámetro,sereemplazanporelargumentoentrecomillado.Antesdecadacarácter"o\queaparezcaalrededorodentrodeunacadenaliteraloconstantedecarácterenelargumento,seinsertauncarácter\.

Segundo,silasecuenciadedefinicióndetokensparacualquierclasedemacrocontiene

Page 378: Titivillus 07.07

unoperador##,entoncesjustodespuésdelreemplazodelosparámetros,seeliminacada##,juntoconcualquierespacioenblancodeamboslados,paraconcatenarlostokensadyacentesyformarunonuevo.Elefectoestáindefinidosiseproducentokensinválidos,osielresultadodependedelordendeprocesamientodelosoperadores##.Además,##nopuedeapareceralprincipioofindeunasecuenciadetokensdereemplazo.

Enambasclasesdemacro,lasecuenciadereemplazodetokensserastreanuevamenteenformarepetida,buscandomásdefinicionesdeidentificadores.Sinembargo,unavezqueunidentificadordadohasidoreemplazoenunaexpansióndada,nosereemplazasiseencuentranuevamentedurantelabúsqueda,sinoquepermanecesincambio.

Auncuandoelvalorfinaldeunamacroexpansiónprincipiecon#,nosetomacomounadirectivadepreprocesamiento.

LosdetallesdelprocesodelamacroexpansiónsedescribenenformamásprecisaenelestándarANSIqueenlaprimeraedición.Elcambiomásimportanteeslaadicióndelosoperadores#y##,quehacenadmisibleelentrecomilladoylaconcatenación.Algunasdelasnuevasreglas,especialmentelasqueinvolucranconcatenación,sonmuyextrañas.(Véanselosejemplossiguientes.)

Porejemplo,estosepuedeutilizarpara“constantesmanifiestas”,comoen

#defineTABSIZE100

inttable[TABSIZE];

Ladefinición

#defineABSDIFF(a,b)((a)>(b)?(a)-(b):(b)-(a))

defineunamacroqueregresaelvalorabsolutodeladiferenciaentresusargumentos.Adiferenciadelafunciónquehacelamismaactividad,losargumentosyeltiporegresadopuedentenercualquiertipoaritméticooinclusoserapuntadores.Losargumentosquepuedentenerefectoscolateralessonevaluadosdosveces,unaparalapruebayotraparaproducirelvalor.

Dadaladefinición

#definetempfile(dir)#dir"/%s"

lamacrollamadatempfile(/usr/tmp)entrega

"/usr/tmp""/%s"

queposteriormenteseconcatenarácomounacadenasencilla.Despuésde

#definecat(x,y)x##y

lallamadacat(var,123)producevar123.Sinembargo,lallamadacat(cat(l,2),3))estáindefinida:lapresenciade##impidequelosargumentosdelallamadamásexternaseanexpandidos.Asíseproducelacadenadetokens.

cat(1,2)3

y)3(launióndelúltimotokendelprimerargumentoconelprimertokendelsegundo)noesuntokenlegal.Siseintroduceunsegundoniveldemacrodefinición,

Page 379: Titivillus 07.07

#definexcat(x,y)cat(x,y)

lascosastrabajanmássuavemente;xcat(xcat(l,2),3)produce123,debidoaquelaexpansióndexcatensínoinvolucraaloperador##.

Enlamismaforma,ABSDIFF(ABSDIFF(a,b),c)produceloesperado,unresultadocompletamenteexpandido.

Page 380: Titivillus 07.07

A12.4.Inclusióndearchivos

Unalíneadecontroldelaforma

#include<nombre-de-archivo>

ocasionaelreemplazodeesalíneaporelcontenidocompletodelarchivonombre-de-archivo.Loscaracteresdelnombrenombre-de-archivonodebenincluir>onuevalíneayestáindefinidoelefectosicontiene",',\,o/*.Elarchivonombradosebuscaenunasecuenciadelugaresdependiendodelaimplantación.

Demodosemejante,unalíneadecontroldelaforma

#include"nombre-de-archivo"

buscaprimeroenasociaciónconelarchivofuenteoriginal(fasedeliberadamentedependientedelaimplantación),ysitalbúsquedafalla,entonceslohacecomoenlaprimeraforma.Elefectodeusar',\,o/*enelnombredelarchivopermaneceindefinido,peroestápermitido>.

Finalmente,unadirectivadelaforma

#includesecuencia-de-tokens

quenocoincidaconunadelasformaspreviasseinterpretaexpandiendolasecuenciadetokenscomotextonormal;deberesultarunadelasdosformascon<...>o"...",yentoncessetratacomosedescribióanteriormente.

Losarchivos#includepuedenestaranidados.

Page 381: Titivillus 07.07

A12.5.Compilacióncondicional

Partedeunprogramasepuedencompilarcondicionalmente,deacuerdoconlasiguientesintaxisesquemática.

preprocesador-condicional:

línea-iftextopartes-elifparte-elseopt#endif

línea-if:

#ifexpresión-constante

#ifdefidentificador

#ifndefidentificador

partes-elif:

línea-eliftexto

partes-elifopt

línea-elif:

#elifexpresión-constante

parte-else:

línea-elsetexto

línea-else:

#else

Cadaunadelasdirectivas(línea-if,línea-elif,línea-else,y#endif)aparecesolaenunalínea.Lasexpresionesconstantesqueestánen#ifyposterioreslíneas#elifseevalúanenordenhastaqueseencuentraunaexpresiónconvalordiferentedecero;eltextoquesigueaunalíneaconvalorcerosedescarta.Eltextoquesigueaunalíneadedirectivaconéxitosetratanormalmente.Aquí“texto”serefiereacualquiermaterial,incluyendolíneasdelpreprocesador,quenoespartedelaestructuracondicional;puedeservacío.Unavezquesehaencontradounalínea#ifo#elifconéxitoysehaprocesadosutexto,laslíneas#elify#elsequelesiguen,juntoconsutexto,sedescartan.Sitodaslasexpresionessonceroyhayun#else,eltextoquesigueal#elsesetratanormalmente.Eltextocontroladoporramificacionesinactivasdelacondicionalseignora,exceptoparaverificarelanidamientodecondicionales.

Laexpresiónconstanteen#ify#elifestásujetaamacroreemplazoordinario.Además,cualesquierexpresionesdelaforma

definedidentificador

Page 382: Titivillus 07.07

o

defined(identificador)

sereemplazan,antesdebuscarmacros,por1Lsielidentificadorestádefinidoenelpreprocesadorypor0Lsinoloestá.Cualesquieraidentificadoresrestantesdespuésdelamacroexpansiónsereemplazanpor0L.Finalmente,cadaconstanteenteraseconsideracomoconsufijoL,demodoquetodalaaritméticaseformacomolongounsignedlong.

Laexpresiónconstantequeresulta(§A7.19)estárestringida:debeserenteraynodebecontenersizeof,ounaconstantedeenumeración.

Laslíneasdecontrol

#ifdefidentificador

#ifndefidentificador

sonequivalentesa

#ifdefinedidentificador

#if!definedidentificador

respectivamente.

#elifesnuevadesdelaprimeraediciónaunquehaestadodisponibleenalgunospreprocesadores.Eloperadordefineddelpreprocesadortambiénesnuevo.

Page 383: Titivillus 07.07

A12.6.Controldelínea

ParabeneficiodeotrospreprocesadoresquegeneranprogramasenC,unalíneaenunadelasformas

#lineconstante"nombre-de-archivo"

#lineconstante

ocasionaqueelcompiladorsuponga,parapropósitosdediagnósticodeerrores,queelnúmerodelíneadelasiguientelíneafuenteestádadoporlaconstanteenteradecimal,yqueelarchivoactualdeentradaestánombradoporelidentificador.Sielnombredearchivoentrecomilladoestáausente,elnombrerecordadonocambia.Lasmacrosdelalíneasonexpandidasantesdeserinterpretadas.

Page 384: Titivillus 07.07

A12.7.Generacióndeerrores

Unalíneadelpreprocesadordelaforma

#errorsecuencia-de-tokensopt

ocasionaqueelpreprocesadorescribaunmensajedediagnósticoqueincluyelasecuenciadetokens.

Page 385: Titivillus 07.07

A12.8.Pragmas

Unalíneadecontroldelaforma

#pragmasecuencia-de-tokensopt

ocasionaqueelpreprocesadorrealiceunaacciónquedependedelaimplantación.Unpragmanoreconocidoesignorado.

Page 386: Titivillus 07.07

A12.9.Directivanula

Unalíneadelpreprocesadordelaforma

#

notieneefecto.

Page 387: Titivillus 07.07

A12.10.Nombrespredefinidos

Variosidentificadoresestánpredefinidos,yseexpandenparaproducirinformaciónespecial,niellosnieloperadordeexpresióndelpreprocesadordefined,puedenestarsindefiniciónoredefinidos.

__LINE__

Constantedecimalquecontieneelnúmerodelíneaactual.

__FILE__

Cadenaliteralquecontieneelnombredelarchivoqueseestácompilando.

__DATE__

Cadenaliteralquecontienelafechadelacompilación,enlaforma“Mmmddaaaa”.

__TIME__

Cadenaliteralquecontienelahoradelacompilación,enlaforma“hh:mm:ss”.

__STDC__

Laconstante1.Esteidentificadorserádefinidocomo1sóloenimplantacionesqueconformanelestándar.

#errory#pragmasonnuevosconelestándarANSI;lasmacrospredefinidasdelpreprocesadorsonnuevas,peroalgunasdeellashanestadodisponiblesenalgunasimplantaciones.

Page 388: Titivillus 07.07

A13.Gramática

Acontinuaciónseencuentraunarecapitulacióndelagramáticaexpuestaalolargodelaprimerapartedeesteapéndice.Tieneexactamenteelmismocontenido,peroseencuentraendiferenteorden.

Lagramáticaharetiradoladefiniciónalossímbolosterminalesconstante-entera,constante-de-carácter,constante-flotante,identificador,cadena,yconstante-enumeración;laspalabrasenestilomecanográficoylossímbolossonterminalesdadasliteralmente.Lagramáticasepuedetransformarmecánicamenteenunaentradaaceptableporungeneradordeparsersautomático.Ademásdeagregaralgunamarcasintácticaparaindicaralternativasenlasproducciones,esnecesarioexpandirlasconstrucciones“unode”y(dependiendodelasreglasdelgeneradordeparsers)duplicarcadaproducciónconsímboloopt,unavezconelsímboloyotrasinél.Conuncambioadicional,borrarlaproducciónnombre-typedef:identificadoryhaceranombre-typedefsímboloterminal,estagramáticaesaceptableparaelgeneradordeparsersYACC.Sólotieneunconflicto,generadoporlaambigüedaddelif-else.

unidad-de-traducción:

declaración-externa

unidad-de-traduccióndeclaración-externa

declaración-externa:

definición-de-función

declaración

definición-de-función:

especificadores-de-declaraciónoptdeclaradorlista-de-declaracionesopt

proposición-compuesta

declaración:

especificadores-de-declaraciónlista-declaradores-initopt;

lista-de-declaraciones:

declaración

lista-de-declaracionesdeclaración

especificadores-de-declaración:

especificador-categoría-almacenamientoespecificadores-de-declaraciónopt

especificador-de-tipoespecificadores-de-declaraciónopt

Page 389: Titivillus 07.07

calificador-de-tipoespecificadores-de-declaraciónopt

especificador-categoría-almacenamiento:unode

autoregisterstaticexterntypedef

especificador-de-tipo:unode

voidcharshortintlongfloatdoublesigned

unsignedespecificador-estructura-unión

especificador-enumnombre-typedef

calificador-de-tipo:unode

constvolatile

especificador-estructura-o-unión:

estructura-o-uniónidentificadoropt{lista-declaraciones-struct}

estructura-o-uniónidentificador

estructura-o-unión:unode

structunion

lista-declaraciones-struct:

declaración-struct

lista-declaraciones-structdeclaración-struct

lista-declaradores-init:

declarador-init

lista-declaradores-init,declarador-init

declarador-init:

declarador

declarador=inicializador

declaración-struct:

lista-calificador-especificadorlista-declaradores-struct;

lista-calificador-especificador:

especificador-de-tipolista-calificador-especificadoropt

calificador-de-tipolista-calificador-especificadoropt

Page 390: Titivillus 07.07

lista-declaradores-struct:

declarador-struct

lista-declaradores-struct,declarador-struct

declarador-struct:

declarador

declaradoropt:expresión-constante

especificador-enum:

enumidentificadoropt{lista-de-enumerador}

enumidentificador

lista-de-enumerador:

enumerador

lista-de-enumerador,enumerador

enumerador:

identificador

identificador=expresión-constante

declarador:

apuntadoroptdeclarador-directo

declarador-directo:

identificador

(declarador)

declarador-directo[expresión-constanteopt]

declarador-directo(lista-tipos-de-parámetro)

declarador-directo(lista-de-identificadoresopt)

apuntador:

*lista-calificadores-de-tipoopt

*lista-calificadores-de-tipooptapuntador

lista-calificadores-de-tipo:

calificador-de-tipo

Page 391: Titivillus 07.07

lista-calificadores-de-tipocalificador-de-tipo

lista-tipos-de-parámetro:

lista-de-parámetros

lista-de-parámetros,...

lista-de-parámetros:

declaración-parámetro

lista-de-parámetros,declaración-parámetro

declaración-parámetro:

especificadores-de-declaracióndeclarador

especificadores-de-declaracióndeclarador-abstractoopt

lista-de-identificadores:

identificador

lista-de-identificadores,identificador

inicializador:

expresión-asignación

{lista-de-inicializadores}

{lista-de-inicializadores,}

lista-de-inicializadores:

inicializador

lista-de-inicializadores,inicializador

nombre-de-tipo:

lista-calificador-especificadordeclarador-abstractoopt

declarador-abstracto:

apuntador

apuntadoroptdeclarador-abstracto-directo

declarador-abstracto-directo:

(declarador-abstracto)

declarador-abstracto-directoopt[expresión-constanteopt]

Page 392: Titivillus 07.07

declarador-abstracto-directoopt(lista-tipos-de-parámetroopt)

nombre-typedef:

identificador

proposición:

proposición-etiquetada

proposición-expresión

proposición-compuesta

proposición-de-selección

proposición-de-iteración

proposición-de-salto

proposición-etiquetada:

identificador:proposición

caseexpresión-constante:proposición

default:proposición

proposición-expresión:

expresiónopt;

proposición-compuesta:

{lista-declaraciónoptlista-de-proposicionesopt}

lista-de-proposiciones:

proposición

lista-de-proposicionesproposición

proposición-de-selección:

if(expresión)proposición

if(expresión)proposiciónelseproposición

switch(expresión)proposición

proposición-de-iteración:

while(expresión)proposición

doproposiciónwhile(expresión);

Page 393: Titivillus 07.07

(expresiónopt;expresiónopt;expresiónopt)proposición

proposición-de-salto:

gotoidentificador;

continue;

break;

returnexpresiónopt;

expresión:

expresión-de-asignación

expresión,expresión-de-asignación

expresión-de-asignación:

expresión-condicional

expresión-unariaoperador-de-asignaciónexpresión-de-asignación

operador-de-asignación:unode

=*=/=%=+=-=<<=>>=&=^=|=

expresión-condicional:

expresión-lógica-OR

expresión-lógica-OR?expresión:expresión-condicional

expresión-constante:

expresión-condicional

expresión-lógica-OR:

expresión-lógica-AND

expresión-lógica-OR||expresión-lógica-AND

expresión-lógica-AND:

expresión-OR-inclusivo

expresión-lógica-AND&&expresión-OR-inclusivo

expresión-OR-inclusivo:

expresión-OR-exclusivo

expresión-OR-inclusivo|expresión-OR-exclusivo

Page 394: Titivillus 07.07

expresión-OR-exclusivo:

expresión-AND

expresión-OR-exclusivo^expresión-AND

expresión-AND:

expresión-de-igualdad

expresión-AND&expresión-de-igualdad

expresión-de-igualdad:

expresión-relacional

expresión-de-igualdad==expresión-relacional

expresión-de-igualdad!=expresión-relacional

expresión-relacional:

expresión-de-corrimiento

expresión-relacional<expresión-de-corrimiento

expresión-relacional>expresión-de-corrimiento

expresión-relacional<=expresión-de-corrimiento

expresión-relacional>=expresión-de-corrimiento

expresión-de-corrimiento:

expresión-aditiva

expresión-de-corrimiento<<expresión-aditiva

expresión-de-corrimiento>>expresión-aditiva

expresión-aditiva:

expresión-multiplicativa

expresión-aditiva+expresión-multiplicativa

expresión-aditiva-expresión-multiplicativa

expresión-multiplicativa:

expresión-cast

expresión-multiplicativa*expresión-cast

expresión-multiplicativa/expresión-cast

Page 395: Titivillus 07.07

expresión-multiplicativa%expresión-cast

expresión-cast:

expresión-unaria

(nombre-de-tipo)expresión-cast

expresión-unaria:

expresión-posfijo

++expresión-unaria

--expresión-unaria

operador-unarioexpresión-cast

sizeofexpresión-unaria

sizeof(nombre-de-tipo)

operador-unario:unode

&*+-~!

expresión-posfijo:

expresión-primaria

expresión-posfijo[expresión]

expresión-posfijo(lista-de-expresiones-argumentoopt)

expresión-posfijo.identificador

expresión-posfijo->identificador

expresión-posfijo++

expresión-posfijo--

expresión-primaria:

identificador

constante

cadena

(expresión)

lista-expresiones-argumento:

expresión-de-asignación

Page 396: Titivillus 07.07

lista-expresiones-argumento,expresión-de-asignación

constante:

constante-entera

constante-de-carácter

constante-flotante

constante-enumeración

Lasiguientegramáticaparaelpreprocesadorresumelaestructuradelaslíneasdecontrol,peronoesadecuadaparaunparsermecanizado.Incluyeelsímbolotext,queestextoordinariodeprograma,líneasdecontrolnocondicionalesdelpreprocesador,oconstruccionescondicionalescompletasdelpreprocesador.

líneadecontrol:

#defineidentificadorsecuencia-de-tokens

#defineidentificador(identificador,...,identificador)secuencia-de-tokens

#undefidentificador

#include<nombre-de-archivo>

#include"nombre-de-archivo"

#includesecuencia-de-tokens

#lineconstante"nombre-de-archivo"

#lineconstante

#errorsecuencia-de-tokensopt

#pragmasecuencia-de-tokensopt

#

preprocesador-condicional

preprocesador-condicional:

línea-iftextopartes-elifparte-elseopt#endif

línea-if:

#ifexpresión-constante

#ifdefidentificador

#ifndefidentificador

partes-elif:

Page 397: Titivillus 07.07

línea-eliftexto

partes-elifopt

línea-elif:

#elifexpresión-constante

parte-else:

línea-elsetexto

línea-else:

#else

Page 398: Titivillus 07.07

APÉNDICEB:Bibliotecaestándar

EsteapéndiceesunresumendelabibliotecadefinidaporelestándarANSI.LabibliotecaestándarnoespropiamentepartedellenguajeC,perounentornoqueopereconCestándarproporcionarálasdeclaracionesytiposdefuncionesylasmacrodefinicionesdeestabiblioteca.Hemosomitidoalgunasfuncionesquesondeutilidadlimitadaofácilmentesintetizadasapartirdeotras;tambiénhemosomitidocaracteresdebytesmúltiplesasícomoladiscusióndecuestioneslocales,estoes,propiedadesquedependendellenguajelocal,lanacionalidadolacultura.

Lasfunciones,tiposymacrosdelabibliotecaestándarestándeclaradosenheadersestándar:

<assert.h><float.h><math.h><stdarg.h><stdlib.h>

<ctype.h><limits.h><setjmp.h><stddef.h><string.h>

<errno.h><locale.h><signal.h><stdio.h><time.h>

Sepuedeteneraccesoaunheaderpormediode

#include<header>

Losheaderssepuedenincluirencualquierordenynúmerodeveces,unheadersedebeincluirfueradecualquierdeclaraciónodefiniciónexternayantesdecualquierusodecualquiercosaquedeclare.Noesnecesarioqueunheaderseaunarchivofuente.

Losidentificadoresexternosqueprincipianconsubguiónestánreservadosparausodelabiblioteca,comoloestántodoslosotrosidentificadoresqueprincipianconunsubguiónyunaletramayúsculauotrosubguión.

Page 399: Titivillus 07.07

B1.Entradaysalida:<stdio.h>

Lasfunciones,tiposymacrosdeentradaysalida,definidosen<stdio.h>,representancercadelatercerapartedelabiblioteca.

Unflujo(stream)esunafuenteodestinodedatosquepuedeestarasociadaconundiscouotroperiférico.Labibliotecamanejaflujosdetextoyflujosbinarios,aunqueenalgunossistemas,notablementeUNIX,sonidénticos.Unflujodetextoesunasecuenciadelíneas;cadalíneatieneceroomáscaracteresyestáterminadapor'\n'.Unentornopuedenecesitarconvertirunflujodetextoaalgunarepresentación,odealgunaotrarepresentación(talcomolaasociaciónde'\n'aretornodecarroyavancedelínea).Unflujobinarioesunasecuenciadebytesnoprocesadosquerepresentandatosinternos,conlapropiedaddequesiesescritoydespuésleídodenuevoenelmismosistema,serácomparadocomoigual.

Unflujoseconectaaunarchivoodispositivoalabrirlo;laconexiónserompecerrandoelflujo.ElabrirunarchivoregresaunapuntadoraunobjetodetipoFILE,queregistracualquierinformaciónnecesariaparacontrolarelflujo.Usaremos“apuntadordearchivo”y“flujo”indistintamentecuandonohayaambigüedad.

Cuandounprogramaprincipiasuejecución,losflujosstdin,stdout,ystderryaestánabiertos.

Page 400: Titivillus 07.07

B1.1.Operacionessobrearchivos

Lassiguientesfuncionestratanconoperacionessobrearchivos.Eltiposize_teseltipoenterosinsignoproducidoporeloperadorsizeof.

FILE*fopen(constchar*filename,constchar*mode)

fopenabreelarchivonombrado,yregresaunflujo,oNULLsifallaelintento.Losvaloreslegítimosdemodeincluyen

"r"

abrearchivodetextoparalectura

"w"

creaarchivodetextoparaescritura;descartaelcontenidopreviosiexiste

"a"

agrega;abreocreaunarchivoparaescribiralfinal

"r+"

abrearchivoparaactualización(estoes,lecturaoescritura)

"w+"

creaarchivodetextoparaactualización;descartacualquiercontenidopreviosiexiste

"a+"

agrega;abreocreaarchivodetextoparaactualización,escribiendoalfinal

Elmododeactualizaciónpermitelalecturayescrituradelmismoarchivo;entreunalecturayunaescrituradebellamarseafflushoaunafuncióndeposiciónoviceversa.Sielmodoincluyebdespuésdelaletrainicial,comoen"rb"o"w+b",indicaqueelarchivoesbinario.LosnombresdearchivoestánlimitadosaFILENAME_MAXcaracteres.CuandomáspuedenserabiertosFOPEN_MAXarchivosalavez.

FILE*freopen(constchar*filename,constchar*mode,FILE*stream)

freopenabreelarchivoconelmodoestipuladoyasociaalflujoconél.Regresastream,oNULLsiocurreunerror.freopennormalmenteseusaparacambiarlosarchivosasociadosconstdin,stdoutostderr.

intfflush(FILE*stream)

Paraunflujodesalida,fflushocasionaqueseaescritocualquierdatoconusodebufferquehastaesemomentonohaysidoescrito;paraunflujodeentrada,elefectoestáindefinido.RegresaEOFencasodeunerrordeescritura,yceroencasocontrario.

intfclose(FILE*stream)

Page 401: Titivillus 07.07

fclosedescargacualquierdatonoescritodestream,descartacualquierbufferdeentradanoleído,liberacualquierbufferasignadoautomáticamente,despuéscierraelflujo.RegresaEOFsiocurrecualquiererroryceroencasocontrario.

intremove(constchar*filename)

removeremueveelarchivonombrado,demodoqueunintentoposteriordeabrirlofallará.Regresaunvalordiferentedecerosielintentofalla.

intrename(constchar*oldname,constchar*newname)

renamecambiaelnombredeunarchivo;regresaunvalordiferentedecerosielintentofalla.

FILE*tmpfile(void)

tmpfilecreaunarchivotemporalconmodo"wb+"queseráremovidoautomáticamentecuandosecierreocuandoelprogramaterminenormalmente,tmpfileregresaunflujo,oNULLsinopuedecrearelarchivo.

char*tmpnam(chars[L_tmpnam])

tmpnam(NULL)creaunacadenaquenoeselnombredeunarchivoexistenteyregresaunapuntadoraunarregloestáticointerno,tmpname(s)almacenalacadenaensytambiénlaregresacomoelvalordelafunción;sdebetenerespaciosuficienteparaalmenosL_tmpnamcaracteres,tmpnamgeneraunnombrediferentecadavezqueseinvoca;cuandomásestángarantizadosTMP_MAXdiferentesnombresdurantelaejecucióndelprograma.Nótesequetmpnamcreaunnombre,nounarchivo.

intsetvbuf(FILE*stream,char*buf,intmode,size_tsize)

setvbufcontrolaelusodebufferparaelflujo;sedebeinvocarantesdeleeroescribir.Unmodo_IOFBFocasionausocompletodebuffers,_IOLBFusodebuffersporlíneadearchivodetexto,e_IONBFningúnusodebuffer.SibufnoesNULL,seemplearácomoelbuffer,deotramaneraseráasignadounbuffer.sizedeterminasutamaño,setvbufregresaunvalordiferentedeceroencasodecualquiererror.

voidsetbuf(FILE*stream,char*buf)

SibufesNULL,sesuspendeelusodebufferparaelflujo.Deotramanera,setbufesequivalentea(void)setvbuf(stream,buf,_IOFBF,BUFSIZ).

Page 402: Titivillus 07.07

B1.2.Salidaconformato

Lasfuncionesprintfproporcionanconversionesdesalidaconformato.

intfprintf(FILE*stream,constchar*format,...)

fprintftomaunasalidaylaconvierteyescribehaciaelstreambajoelcontroldeformat.Elvalorregresadoeselnúmerodecaracteresescritos,ounvalornegativosiocurrióalgúnerror.

Lacadenadeformatocontienedostiposdeobjetos:caracteresordinarios,quesoncopiadosalflujodesalida,yespecificacionesdeconversión,cadaunodeloscualesprovocalaconversióneimpresióndelossiguientesargumentossucesivosdefprintf.Cadaespecificacióndeconversiónprincipiaconelcarácter%yterminaconuncarácterdeconversión.Entreel%yelcarácterdeconversiónpuedehaber,enorden:

Banderas(encualquierorden),quemodificanlaespecificación:

-,queespecificaajustedelargumentoconvertidohacialaizquierdadentrodesucampo.

+,queestipulaqueelnúmerosiempreseráimpresoconsigno.

espacio

:sielprimercarácternoesunsigno,seprefijaráunespacio.

0:paraconversiónnumérica,estipularellenadoconcerosinicialesdelatotalidaddelcampo.

#,queestipulaunaformaalternadesalida.Parao,elprimerdígitoserácero.ParaxoX,cualquierresultadodiferentedeceroseráprefijadocon0xo0X.Parae,E,f,g,yG,lasalidasiempretendráunpuntodecimal;paragyG,loscerosacarreadosnoseránremovidos.

Unnúmeroqueestipulaunanchomínimodecampo.Elargumentoconvertidoseráimpresoenuncampodeporlomenosestaamplitud,yenunamayorsiesnecesario.Sielargumentoconvertidotienemenoscaracteresqueelanchodecampo,serárellenadoalaizquierda(oderecha,siseharequeridojustificaciónalaizquierda)paracompletarelanchodecampo.Elcarácterderellenonormalmenteesespacio,peroes0siestápresentelabanderaderellenoconceros.

Unpunto,queseparaelanchodecampodelaprecisión.

Unnúmero,laprecisión,queestipulaelnúmeromáximodecaracteresdeunacadenaqueseránimpresos,oelnúmerodedígitosqueseránimpresosdespuésdelpuntodecimalparaconversionese,E,of,oelnúmerodedígitossignificativosparaconversionesgoG,oelnúmeromínimodedígitosqueseránimpresosparaunentero(seránagregadoscerosalprincipioparacompletarelanchodecamponecesario).

Unmodificadordelongitudh,l(letraele),oL."h"indicaqueelargumentocorrespondientevaaserimpresocomoshortounsignedshort;"l"indicaqueelargumentoeslongounsignedlong;"L"indicaqueelargumentoeslongdouble.

Page 403: Titivillus 07.07

Con*sepuedeespecificarlaamplitudoprecisión,oambas,entalcasoelvalorsecalculaconvirtiendoel(los)siguiente(s)argumento(s),quedebe(n)serint.

LoscaracteresdeconversiónysussignificadossemuestranenlatablaB-1.Sielcarácterqueestádespuésdel%noesuncarácterdeconversión,elcomportamientoestáindefinido.

TABLAB-1.CONVERSIONESDEPRINTF

CARÁCTER

TIPODEARGUMENTO;CONVERTIDOA

d,i

int;notacióndecimalconsigno.

o

int;notaciónoctalsinsigno(sincerosalprincipio)

x,X

int;notaciónhexadecimalsinsigno(sin0xo0Xalprincipio),utilizandoabcdefpara0xoABCDEFpara0X.

u

int;notacióndecimalsinsigno.

c

int;caráctersencillo,despuésdelaconversiónaunsignedchar.

s

char*;loscaracteresdelacadenasonimpresoshastaquesealcanzaun'\0'ohastaquehasidoimpresoelnúmerodecaracteresindicadosporlaprecisión.

f

double;notacióndecimaldelaforma[-]mmm.ddd,endondeelnúmerodedesespecificadoporlaprecisión.Laprecisiónporomisiónes6;unaprecisión0suprimeelpuntodecimal.

e,E

double;notacióndecimaldelaforma[-]m.dddddde±xxo[-]m.ddddddE±xx,endondeelnúmerodedestáespecificadoporlaprecisión.Laprecisiónporomisiónes6;unaprecisión0suprimeelpuntodecimal.

g,G

double;seusa%eo%Esielexponenteesmenorque-4omayoroigualquelaprecisión;deotraformaesusado%f.Loscerosyelpuntodecimalalfinalnosonimpresos.

Page 404: Titivillus 07.07

p

void*;imprimecomounapuntador(representacióndependientedelaimplantación).

n

int*;elnúmerodecaracteresescritoshastaelmomentoporestallamadaaprintfesescritoenelargumento.Noesconvertidoningúnargumento.

%

Noesconvertidoningúnargumento;seimprimecomo%.

intprintf(constchar*format,...)

printf(...)esequivalenteafprintf(stdout).

intsprintf(char*s,constchar*format,...)

sprintfeslomismoqueprintfexceptoquelasalidaesescritaenlacadenas,terminadacon'\0'.sdebesersuficientementegrandeparacontenerelresultado.Lacuentaregresadanoincluyeel'\0'.

vprintf(constchar*format,va_listarg)

vfprintf(FILE*stream,constchar*format,va_listarg)

vsprintf(char*s,constchar*format,va_listarg)

Lasfuncionesvprintf,vfprintf,yvsprintfsonequivalentesalascorrespondientesfuncionesprintf,exceptoquelalistavariabledeargumentosesremplazadaporarg,quehasidoinicializadoporlamacrova_startytalvezllamadasava_arg.Véaselaexposiciónde<stdarg.h>enlasecciónB7.

Page 405: Titivillus 07.07

B1.3.Entradaconformato

Lasfuncionesscanftratanconlaconversióndeentradaconformato.

intfscanf(FILE*stream,constchar*format,...)

fscanfleedelstreambajoelcontroldeformat,yasignalosvaloresconvertidosatravésdeargumentossubsecuentes,

cadaunodeloscualesdebeserunapuntador

.Regresacuandoformatsehaagotado,fscanfregresaEOFsiseencuentrafindearchivoounerrorantesdelaconversión;deotraformaregresaelnúmerodeartículosdeentradaconvertidosyasignados.

Lacadenadeformatogeneralmentecontieneespecificacionesdeconversión,quesonutilizadasparadirigirlainterpretacióndelaentrada.Lacadenadeformatopuedecontener:

Blancosotabuladores,quesonignorados.

Caracteresordinarios(no%),queseesperacoincidanconlossiguientescaracteresquenosonespacioenblancodelflujodeentrada.

Especificacionesdeconversión,consistentesen%,uncarácteroptativodesupresióndeasignación*,unnúmerooptativoqueespecificaunaamplitudmáximadecampo,unah,loLoptativaqueindicalaamplituddelobjetivo,yuncarácterdeconversión.

Unaespecificacióndeconversióndeterminalaconversióndelsiguientecampodeentrada.Normalmenteelresultadoessituadoenlavariableapuntadaporelargumentocorrespondiente.Sinembargo,siseindicasupresióndeasignacióncon*,comoen%*s,elcampodeentradasimplementesesalta;nosehaceasignación.Uncampodeentradaestádefinidoporunacadenadecaracteresdiferentesdeespacioenblanco;seextiendehastaelsiguientecarácterdeespacioenblancoohastaqueelanchodecampo,siestáespecificado,sehaagotado.Estoimplicaquescanfleerámásalládeloslímitesdelalíneaparaencontrarsuentrada,yaquelasnuevaslíneassonespaciosenblanco.(Loscaracteresdeespacioenblancosonblanco,tabulador,nuevalínea,retornodecarro,tabuladorverticalyavancedelínea.)

Elcarácterdeconversiónindicalainterpretacióndelcampodeentrada.Elargumentocorrespondientedebeserunapuntador.LoscaracteresdeconversiónlegalessemuestranenlatablaB-2.

Loscaracteresdeconversiónd,i,n,o,u,yxpuedenestarprecedidosporhsielargumentoesunapuntadorashortenvezdeint,oporl(letraele)sielargumentoesunapuntadoralong.Loscaracteresdeconversióne,f,ygpuedenestarprecedidosporlsienlalistadeargumentoshayunapuntadoradoubleynoafloat,yporLsihayunapuntadoralongdouble.

TABLAB-2.CONVERSIONESDESCANF

CARÁCTER

Page 406: Titivillus 07.07

DATODEENTRADA;TIPODEARGUMENTO

d

enterodecimal;int*.

i

entero;int*.Elenteropuedeestarenoctal(iniciadocon0)ohexadecimal(iniciadocon0xo0X).

o

enterooctal(conosinceroalprincipio);int*.

u

enterodecimalsinsigno;unsignedint*.

x

enterohexadecimal(conosin0xo0Xalprincipio);int*.

c

caracteres;char*.Lossiguientescaracteresdeentradasepondránenelarregloindicado,hastaelnúmerodadoporelanchodecampo;elvalorporomisiónesl.Noseagrega'\0'.Enestecasosesuprimeelsaltonormalsobreloscaracteresdeespacioenblanco;paraleerelsiguientecarácterquenoseablanco,use%ls.

s

cadenadecaracteresquenoesespacioenblanco(noentrecomillados);char*,apuntaaunarreglodecaracteressuficientementegrandeparacontenerlacadenayun'\0'terminalqueseleagregará.

e,f,g

númerodepuntoflotante;float*.Elformatodeentradaparalosfloatesunsignooptativo,unacadenadenúmerosposiblementeconunpuntodecimal,yuncampooptativodeexponenteconunaEoeseguidaposiblementedeunenteroconsigno.

p

valorapuntadorcomoseimprimeporprintf("%p");void*.

n

escribeenelargumentoelnúmerodecaracteresescritoshastaelmomentoporestallamada;int*.Noseleeentradaalguna.Lacuentadeelementosconvertidosnoseincrementa.

[...]

coincideconlamayorcadenanovacíadecaracteresdeentradadelconjuntoentrecorchetes;char*.Seagregaun'\0'.[]...]incluye]enelconjunto.

Page 407: Titivillus 07.07

[*...]

coincideconlamayorcadenanovacíadecaracteresdeentradaquenoseandelconjuntoentrecorchetes;char*.Seagregaun'\0'.[^]...]incluye]enelconjunto.

%

literal;nosehaceningunaasignación.

intscanf(constchar*format,...)

scanf(...)esidénticaafscanf(stdin,...).

intsscanf(char*s,constchar*format,...)

sscanf(s,...)esequivalenteascanf(...)exceptoqueloscaracteresdeentradasontomadosdelacadenas.

Page 408: Titivillus 07.07

B1.4.Funcionesdeentradaysalidadecaracteres

intfgetc(FILE*stream)

fgetcregresaelsiguientecarácterdestreamcomounsignedchar(convertidoaunint),oEOFsiseencontróelfindearchivoounerror.

char*fgets(char*s,intn,FILE*stream)

fgetsleehastalossiguientesn-1caracteresenelarreglos,deteniéndosesiencuentranuevalínea;elnuevalíneaesincluidoenelarreglo,queesterminadopor'\0'.fgetsregresas,oNULLsiseencuentrafindearchivouocurreunerror.

intfputc(intc,FILE*stream)

fputcescribeelcarácterc(convertidoaunsignedchar)enstream.Regresaelcarácterescrito,oEOFencasodeerror.

intfputs(constchar*s,FILE*stream)

fputsescribelacadenas(quenonecesitacontener'\n')enstream;regresaunvalornonegativo,oEOFsihayerror.

intgetc(FILE*stream)

getcesequivalenteafgetcexceptoquesiesunamacro,puedeevaluarastreammásdeunavez.

intgetchar(void)

getcharesequivalenteagetc(stdin).

char*gets(char*s)

getsleelasiguientelíneadeentradayladejaenelarreglos;reemplazaelcarácternuevalíneafinalcon'\0'.Regresas,oNULLsiocurrefindearchivooerror.

intputc(intc,FILE*stream)

putcesequivalenteafputcexceptoque,siesunamacro,puedeevaluarastreammásdeunavez.

intputchar(intc)

putchar(c)esequivalenteaputc(c,stdout).

intputs(constchar*s)

putsescribelacadenasyunnuevalíneaastdout.RegresaEOFsiocurreunerror,deotraforma,unvalornonegativo.

intungetc(intc,FILE*stream)

Page 409: Titivillus 07.07

ungetcregresac(convertidoenunsignedchar)denuevoalstream,dedondeseráregresadoenlapróximalectura.Sólosegarantizauncarácterderegresoporflujo.EOFnopuedeserregresado,ungetcdevuelveelcarácterregresado,oEOFencasodeerror.

Page 410: Titivillus 07.07

B1.5.Funcionesdeentradaysalidadirecta

size_tfread(void*ptr,size_tsize,size_tnobj,FILE*stream)

freadleedestreamenelarregloptrhastanobjobjetosdetamañosize.freadregresaelnúmerodeobjetosleídos;estopuedesermenorqueelnúmerosolicitado.Paradeterminarelstatusdebenutilizarsefeofyferror.

size_tfwrite(constvoid*ptr,size_tsize,size_tnobj,FILE*stream)

fwriteescribe,delarregloptr,nobjobjetosdetamañossizeenstream.Devuelveelnúmerodeobjetosescritos,queesmenorquenobjencasodeerror.

Page 411: Titivillus 07.07

B1.6.Funcionesdecolocaciónenarchivos

intfseek(FILE*stream,longoffset,intorigin)

fseekfijalaposiciónenelarchivoparaelstream;unalecturaoescrituraposteriortendráaccesoadatosqueprincipianenlanuevaposición.Paraunarchivobinario,laposiciónsefijaaoffsetcaracteresdeorigin,elcualpuedeserSEEK_SET(principio),SEEK_CUR(posiciónactual),oSEEK_END(findelarchivo).Paraunstreamdetexto,offsetdebesercero,ounvalorregresadoporftell(entalcasoorigindebeserSEEK_SET.)fseekregresaunvalordiferentedeceroencasodeerror.

longftell(FILE*stream)

ftellregresalaposiciónactualdestreamenelarchivo,o-1Lencasodeerror.

voidrewind(FILE*stream)

rewind(fp)esequivalenteafseek(fp,0L,SEEK_SET);clearerr(fp).

intfgetpos(FILE*stream,fpos_t*ptr)

fgetposgrabaen*ptrlaposiciónactualdestream,parausoposteriordefsetpos.Eltipofpos_tesadecuadoparagrabartalesvalores,fgetposregresaunvalordiferentedeceroencasodeerror.

intfsetpos(FILE*stream,constfpos_t*ptr)

fsetposcolocastreamenlaposicióngrabadaen*ptrporfgetpos.Encasodeerror,fsetposregresaunvalordiferentedecero.

Page 412: Titivillus 07.07

B1.7.Funcionesdeerror

Muchasfuncionesdelabibliotecaactivanindicadoresdeestadocuandoocurreunerrorofindearchivo.Estosindicadoressepuedenfijaryprobarexplícitamente.Además,laexpresiónenteraerrno(declaradaen<errno.h>puedecontenerunnúmerodeerrorquedainformaciónadicionalacercadelerrormásreciente.

voidclearerr(FILE*stream)

clearerrlimpialosindicadoresdefindearchivoyerrorparaelstream.

intfeof(FILE*stream)

feofregresaunvalordiferentedecerosiestáencendidoelindicadordefindearchivoparastream.

intferror(FILE*stream)

ferrorregresaunvalordiferentedecerosiestáencendidoelindicadordeerrordestream.

voidperror(constchar*s)

perror(s)imprimesyunmensajedeerrordefinidoporlaimplantación,correspondientealenteroqueestáenerrno,comosifuera

fprintf(stderr,"%s:%s\n",s,"mensajedeerror")

VerstrerrorenlasecciónB3.

Page 413: Titivillus 07.07

B2.Pruebasdeclasificacióndecaracteres:<ctype.h>

Elheader<ctype.h>declarafuncionesparalapruebadecaracteres.Paracadafunción,elargumentoesunintcuyovalordebeserEOForepresentableporununsignedchar,yelvalorderetornoesunint.Lasfuncionesregresandiferentedecero(verdadero)sielargumentocsatisfacelacondicióndescrita,ycerosinolohace.

isalnum(c)

isalpha(c)oisdigit(c)esverdadera

isalpha(c)

isupper(c)oislower(c)esverdadera

iscntrl(c)

carácterdecontrol

isdigit(c)

dígitodecimal

isgraph(c)

carácterdeimpresiónexceptoespacio

islower(c)

letraminúscula

isprint(c)

carácterdeimpresiónincluyendoespacio

ispunct(c)

carácterdeimpresiónexceptoespacio,letraodígito.

isspace(c)

espacio,avancedelínea,nuevalínea,retornodecarro,tabulador,tabuladorvertical

isupper(c)

letramayúscula

isxdigit(c)

dígitohexadecimal

EnelconjuntodecaracteresASCIIdesietebits,loscaracteresdeimpresiónsonde0x20('')a0x7E('~');loscaracteresdecontrolsonde0(NUL)a0x1F(US)y0x7F

Page 414: Titivillus 07.07

(DEL).

Además,haydosfuncionesqueconviertenletras:

inttolower(intc)

conviertecaminúscula

inttoupper(intc)

conviertecamayúscula

Sicesunaletramayúscula,tolower(c)regresalacorrespondienteletraminúscula;enotrocasoregresac.Sicesunaletraminúscula,toupper(c)regresalacorrespondienteletramayúscula;enotrocasoregresac.

Page 415: Titivillus 07.07

B3.Funcionesparacadenas:<string.h>

Haydosgruposdefuncionesparacadenasdefinidasenelheader<string.h>.Lasprimerastienennombresquecomienzanconstr;lassegundastienennombresquecomienzanconmem.Exceptoparamemmove,elcomportamientoestáindefinidosilacopiaocurreentreobjetosquesetraslapan.

Enlasiguientetabla,lasvariablessytsondetipochar*;csyctsondetipoconstchar*;nesdetiposize_t;ycesunintconvertidoachar

char*strcpy(s,ct)

copialacadenactalacadenas,incluyendo'\0';regresas.

char*strncpy(s,ct,n)

copiahastancaracteresdelacadenactas;regresas.Rellenacon'\0'sicttienemenosdencaracteres.

char*strcat(s,ct)

concatenalacadenactalfinaldelacadenas;regresas;

char*strncat(s,ct,n)

concatenahastancaracteresdelacadenactalacadenas,terminandocon'\0';regresas.

intstrcmp(cs,ct)

comparalacadenacsconlacadenact;regresa<0sics<ct,0sics==ct,o>0sics>ct.

intstrncmp(cs,ct,n)

comparahastancaracteresdelacadenacsconlacadenact;regresa<0sics<ct,0sics==ct,o>0sics>ct.

char*strchr(cs,c)

regresaunapuntadoralaprimeraocurrenciadecencs,oNULLsinoestápresente.

char*strrchr(cs,c)

regresaunapuntadoralaúltimaocurrenciadecencs,oNULLsinoestápresente.

size_tstrspn(cs,ct)

regresalalongituddelprefijodecsqueconsisteenloscaracteresenct.

size_tstrcspn(cs,ct)

regresalalongituddelprefijodecsqueconsisteenloscaracteres

Page 416: Titivillus 07.07

queno

estánenct.

char*strpbrk(cs,ct)

regresaunapuntadoralaprimeraocurrenciaenlacadenacsdecualquiercarácterdelacadenact,oNULLsiningunoestápresente.

char*strstr(cs,ct)

regresaunapuntadoralaprimeraocurrenciadelacadenactencs,oNULLsinoestápresente.

size_tstrlen(cs)

regresalalongituddecs.

char*strerror(n)

regresaunapuntadoraunacadenadefinidaporlaimplantación,correspondientealerrorn.

char*strtok(s,ct)

strtokbuscaens

tokens

delimitadosporcaracteresdect;verabajo.

Unasecuenciadellamadasastrtok(s,ct)dividesentokens,cadaunodelimitadoporuncarácterdect.LaprimerallamadaenunasecuenciatieneunasnoNULL.Encuentraelprimertokenensqueconsisteencaracteresquenoestánenct;terminaalsobreescribirelsiguientecarácterdescon'\0'yregresaunapuntadoraltoken.Cadallamadasubsiguiente,indicadaporunvalorNULLdes,regresaeltokensiguiente,buscandojustoapartirdelfinaldelanterior,strtokregresaNULLcuandoyanoencuentratokens.Lacadenactpuedeserdiferenteencadallamada.

Laintencióndelasfuncionesmem...esmanipularobjetoscomoarreglosdecaracteres;laintencióneslograrunainterfazpararutinaseficientes.Enlasiguientetabla,sytsondetipovoid*;csyctsondetipoconstvoid*;nesdetiposize_t;ycesunintconvertidoaunsignedchar.

void*memcpy(s,ct,n)

copiancaracteresdectas,yregresas.

void*memmove(s,ct,n)

lomismoquememcpyexceptoquefuncionaaunsilosobjetossetraslapan.

intmemcmp(cs,ct,n)

comparalosprimerosncaracteresdecsconct;regresalomismoquestrcmp.

void*memchr(cs,c,n)

Page 417: Titivillus 07.07

regresaunapuntadoralaprimeraocurrenciadelcaráctercencs,oNULLsinoestápresenteentrelosprimerosncaracteres.

void*memset(s,c,n)

colocaelcaráctercenlosprimerosncaracteresdes,regresas.

Page 418: Titivillus 07.07

B4.Funcionesmatemáticas:<math.h>

Elheader<math.h>declarafuncionesymacrosmatemáticas.

LasmacrosEDOMyERANGE(queseencuentranen<errno.h>)sonconstantesenterasconvalordiferentedeceroqueseusanparaseñalarerroresdedominioyderangoparalasfunciones;HUGE_VALesunvalorpositivodouble.Unerrordedominioocurresiunargumentoestáfueradeldominiosobreelqueestádefinidalafunción.Encasodeunerrordedominio,errnotomaelvalordeEDOM;elvalorregresadodependedelaimplantación.Unerrorderangoocurresielresultadodelafunciónnosepuederepresentarcomoundouble.Sielresultadosedesborda,lafunciónregresaHUGE_VALconelsignocorrecto,yerrnosehaceERANGE.Sielresultadoestanpequeñoquenosepuederepresentar(underflow),lafunciónregresacero;elqueerrnoseafijadoaERANGEdependedelaimplantación.

Enlatablasiguiente,xyysondetipodouble,nesunint,ytodaslasfuncionesregresandouble.Losángulosparalasfuncionestrigonométricasestánrepresentadosenradianes.

sin(x)

senodex

cos(x)

cosenodex

tan(x)

tangentedex

asin(x)

sin

-1

(x)enelrango[-π/2,π/2],x∈[-1,1].

acos(x)

cos

-1

(x)enelrango[0,π],x∈[-1,1].

atan(x)

tan

-1

Page 419: Titivillus 07.07

(x)enelrango[-π/2,π/2].

atan2(y,x)

tan

-1

(

y/x

)enelrango[-π,π].

sinh(x)

senohiperbólicodex

cosh(x)

cosenohiperbólicodex

tanh(x)

tangentehiperbólicadex

exp(x)

funciónexponencial

ex

log(x)

logaritmonaturalln(x),x>0.

log10(x)

logaritmobase10log

10

(x),x>0.

pow(x,y)

xy

.Ocurreunerrordedominiosi

x

=0y

y

Page 420: Titivillus 07.07

≤0,osi

x

<0y

y

noesunentero.

sqrt(x)

√x,x≥0.

ceil(x)

menorenteronomenorquex,comodouble.

floor(x)

mayorenteronomayorquex,comodouble.

fabs(x)

valorabsoluto|x|

ldexp(x,n)

x-2

n

frexp(x,int*exp)

dividexenunafracciónnormalizadadentrodelintervalo[1/2,1],queseregresa,yunapotenciade2,quesealmacenaen*exp.Sixescero,ambaspartesdelresultadosoncero.

modf(x,double*ip)

dividexenparteenterayfraccionaria,cadaunaconelmismosignoquex.Almacenalaparteenteraen*ip,yregresalapartefraccionaria,

fmod(x,y)

residuodepuntoflotantedex/y,conelmismosignoquex.Siyescero,elresultadoestádefinidoporlaimplantación.

Page 421: Titivillus 07.07

B5.Funcionesdeutilería:<stdlib.h>

Elheader<stdlib.h>declarafuncionesparaconversiónnumérica,asignacióndememoriaytareassemejantes.

doubleatof(constchar*s)

atofconviertesadouble;esequivalenteastrtod(s,(char**)NULL).

intatoi(constchar*s)

conviertesaint;esequivalentea(int)strtol(s,(char**)NULL,10).

longatol(constchar*s)

conviertesalong;esequivalenteastrtol(s,(char**)NULL,10).

doublestrtod(constchar*s,char**endp)

strtodconvieneelprefijodesadouble,ignorandoelespacioenblancoinicial;almacenaen*endpunapuntadoracualquiersufijonocubiertosalvocuandoendpesNULL.Silarespuestasedesborda,regresaHUGE_VAL,conelsignoapropiado;sielresultadofueratanpequeñoquenosepuedarepresentar(

underflow

),seregresacero.EncualquiercasoerrnotomaelvalorERANGE.

longstrtol(constchar*s,char**endp,intbase)

strtolconvierteelprefijodesalong,ignorandolosespaciosenblancoiniciales;almacenaunapuntadoren*endpacualquiersufijonocubiertoamenosdequeendpseaNULL.Sibaseestáentre2y36,laconversiónserealizasuponiendoquelaentradaesescritaenesabase.Sibaseescero,labasees8,10,o16;los0inicialesimplicanoctal,mientrasque0xy0X,hexadecimal.Lasletras,yaseanmayúsculasominúsculas,representandígitosdesde

10

hasta

base-1

;enbase16sepermiteiniciarcon0xo0X.Sielresultadosedesborda,seregresaLONG_MAXoLONG_MIN,dependiendodelsignodelresultado,yerrnosehaceERANGE.

unsignedlongstrtoul(constchar*s,char**endp,intbase)

strtouleslomismoquestrtolexceptoqueelresultadoesunsignedlongyelvalordeerroresULONG_MAX.

intrand(void)

Page 422: Titivillus 07.07

randdevuelveunenteropseudoaleatorioenelrangode0aRAND_MAX,queesalmenos32767.

voidsrand(unsignedintseed)

srandutilizaseedcomosemillaparaunanuevasecuenciadenúmerospseudoaleatorios.Lasemillainiciales1.

void*calloc(size_tnobj,size_tsize)

callocdevuelveunapuntadoralespacioparaunarreglodenobjobjetos,cadaunodetamañosize,oNULLsilasolicitudnopuedesatisfacerse.Elespacioseinicializaabytesconcero.

void*malloc(size_tsize)

mallocregresaunapuntadoralespacioparaunobjetodetamañosize,oNULLsilasolicitudnosepuedesatisfacer.Elespacionoseinicializa.

void*realloc(void*p,size_tsize)

realloccambiaeltamañodelobjetoapuntadoporpasize.Elcontenidonocambiarásinohastaelmínimodelostamañosviejoynuevo.Sielnuevotamañoesmayor,elespacionuevonoseinicializa.reallocregresaunapuntadoralnuevoespacio,oNULLsilasolicitudnosepuedesatisfacer;entalcaso*pnocambia.

voidfree(void*p)

freedesasignaelespacioapuntadoporp;sipesNULL,nohacenada,pdebeserunapuntadoraunespaciopreviamenteasignadoporcalloc,malloc,orealloc.

voidabort(void)

abortocasionaqueelprogramatermineanormalmente,comoconraise(SIGABRT).

voidexit(intstatus)

exitocasionalaterminaciónnormaldelprograma.Lasfuncionesatexitsellamanenordeninversodelregistrado,losarchivosabiertossevacían,losflujosabiertossecierran,yelcontrolseregresaalentorno.Cómoseregresestatusalentornedependedelaimplantación,peroceroindicacuandolaterminacióntieneéxito.SepuedenutilizartambiénlosvaloresEXIT_SUCCESSyEXIT_FAILURE.

intatexit(void(*fcn)(void))

atexitregistraalafunciónfcnparaqueseallamadacuandoelprogramaterminanormalmente;regresaunvalordiferentedecerocuandonosepuedehacerelregistro.

intsystem(constchar*s)

systempasalacadenasalentornoparaqueseejecute.SisesNULL,systemregresaunvalordiferentedecerosihayunprocesadordeórdenes.SisnoesNULL,elvalorregresadodependedelaimplantación.

char*getenv(constchar*name)

Page 423: Titivillus 07.07

getenvregresalacadenadelentornoasociadaconname,oNULLsinoexiste.Losdetallesdependendelaimplantación.

void*bsearch(constvoid*key,constvoid*base,size_tn,size_tsize,int(*cmp)(constvoid*keyval,constvoid*datum))

bsearchbuscaenbase[0]...base[n-1]unelementoquecoincidacon*key.Lafuncióncmpdeberegresarunvalornegativosisuprimerargumento(lallavedebúsqueda)esmenorquesusegundo(unaentradaenlatabla),cerosiesigual,ypositivoparamayor.Loselementosdelarreglobasedebenestarenordenascendente,bsearchregresaunapuntadoralelementocoincidente,oNULLsinoexiste.

voidqsort(void*base,size_tn,size_tsize,int(*cmp)(constvoid*,constvoid*))

qsortclasificaenordenascendenteunarreglobase[0]...base[n-1]deobjetosdetamañosize.Lafuncióndecomparacióncmpescomoenbsearch.

intabs(intn)

absregresaelvalorabsolutodesuargumentoint.

longlabs(longn)

labsregresaelvalorabsolutodesuargumentolong.

div_tdiv(intnum,intdenom)

divcalculaelcocienteyelresiduodenum/denom.Losresultadossealmacenanenlosmiembrosdetipointquotyremdeunaestructuradetipodiv_t.

ldiv_tldiv(longnum,longdenom)

ldivcalculaelcocienteyelresiduodenum/denom.Losresultadossonalmacenadosenlosmiembrosdetipolongquotyremdeunaestructuradetipoldiv_t.

Page 424: Titivillus 07.07

B6.Diagnósticos:<assert.h>

Lamacroassertesusadaparaagregardiagnósticosalosprogramas:

voidassert(intexpresión)

Siexpresiónescerocuando

assert(expresión)

seejecuta,lamacroassertimprimiráenstderrunmensaje,como

Assertionfailed:expresión,filefilename,linennn

Despuésllamaaabortparaterminarlaejecución.Elarchivofuentefilenameyelnúmerodelíneavienedelasmacros__FILE__y__LINE__delpreprocesador.

SiNDEBUGestádefinidocuandoseincluyó<assert.h>seignoralamacroassert.

Page 425: Titivillus 07.07

B7.Listasdeargumentosvariables:<stdarg.h>

Elheader<stdarg.h>proporcionarecursospararecorrerunalistadeargumentosdefuncióndetamañoytipodesconocido.

Supóngasequelastargeselúltimoparámetronombradodeunafunciónfconunnúmerovariabledeargumentos.Entoncessedeclaradentrodefunavariableapdetipova_listqueapuntaráacadaargumentoenorden:

va_listap;

apsedebeinicializarunavezconlamacrova_listantesdeteneraccesoacualquierargumentononombrado:

va_start(va_listap,lastarg);

Despuésdeeso,cadaejecucióndelamacrova_argproduciráunvalorquetieneeltipoyvalordelsiguienteargumentononombrado,ymodificarátambiénapdemodoqueelpróximousodeva_argdevuelvaelargumentosiguiente:

typeva_arg(va_listap,type);

Lamacro

voidva_end(va_listap);

sedebellamarunavezdespuésdequehansidoprocesadoslosargumentos,peroantesdehabersalidodef.

Page 426: Titivillus 07.07

B8.Saltosnolocales:<setjmp.h>

Lasdeclaracionesqueestánen<setjmp.h>proporcionanunaformadeevitarlasecuencianormaldellamadayregresodefunciones,típicamenteparapermitirunregresoinmediatodeunallamadaaunafunciónprofundamenteanidada.

intsetjmp(jmp_bufenv)

Lamacrosetjmpguardalainformacióndelestadoquesetieneenenvparaserusadaporlongjmp.Elretornoescerodesdeunallamadadirectadesetjmpydiferentedecerodesdeunallamadasubsiguientealongjmp.Sólopuedeocurrirunallamadaasetjmpdentrodeciertoscontextos,básicamentelapruebadeif,switch,yciclos,ysóloenexpresionesderelaciónsimples.

if(setjmp(env)==0)

/*llegaaquíenunallamadadirecta*/

else

/*llegaaquíporunallamadadelongjmp*/

voidlongjmp(jmp_bufenv,intval)

longjmprestableceelestadoguardadoporlallamadamásrecientedesetjmp,utilizandolainformaciónalmacenadaenenv:laejecucióncontinúacomosilafunciónsetjmpsólohubierasidollamadayhubieraregresadounvalordevaldiferentedecero.Lafunciónquecontienesetjmpnodebehaberterminado.Losobjetosaccesiblestienenlosvaloresqueteníanenelmomentoenquelongjmpfuellamada;losvaloresnosonguardadosporsetjmp.

Page 427: Titivillus 07.07

B9.Señales:<signal.h>

Elheader<signal.h>dafacilidadesparamanejarcondicionesexcepcionalesqueaparecendurantelaejecución,talcomounaseñaldeinterrupcióndeunafuenteexternaounerrorenlaejecución.

void(*signal(intsig,void(*handler)(int)))(int)

signaldeterminacómosemanejaránlasseñalessubsiguientes.SihandleresSIG_DFL,seusaelcomportamientopredefinidoporlaimplantación;siesSIG_IGN,laseñalseignora;deotramanera,sellamaráalafunciónapuntadaporhandler,conlosargumentosdeltipodelaseñal.Lasseñalesválidasincluyen

SIGABRT

terminaciónanormal,p.ej.,desdeabort

SIGFPE

erroraritmético,p.ej.,divisiónentreceroosobreflujo

SIGILL

imagendefunciónilegal,p.ej.,instrucciónilegal

SIGINT

atenciónilegalalalmacenamiento;p.ej.,accesofueradeloslimites

SIGSEGV

accesoilegalalalmacenamiento,vgr.,accesofueradeloslímitesdememoria

SIGTERM

solicituddeterminaciónenviadaaesteprograma

signalregresaelvalorpreviodehandlerparalaseñalespecífica,oSIG_ERRsiocurreunerror.

Cuandoocurresubsecuentementeunaseñalsig,laseñalseregresaasucomportamientopredeterminado;luegosellamaalafunciónmanejadoradelaseñal,comosiseejecutara(*handler)(sig).Sielmanejadorregresa,laejecucióncontinuarádondeseencontrabacuandoocurriólaseñal.

Elestadoinicialdelasseñalesestádefinidoporlaimplantación.

intraise(intsig)

raiseenvíalaseñalsigalprograma;regresaunvalordiferentedecerocuandonotieneéxito.

Page 428: Titivillus 07.07

B10.Funcionesdefechayhora<time.h>

Elheader<time.h>declaralostiposyfuncionesparamanipulacióndefechayhora.Algunasfuncionesprocesanlahoralocal,quepuedediferirdeladelcalendario,porejemplo,debidoalazonahoraria,clock_tytime_tsontiposaritméticosquerepresentantiempos,ystructtmmantienelascomponentesdeuncalendario;

inttm_sec;

segundosdespuésdelminuto(0,59)

inttm_min;

minutosdespuésdelahora(0,59)

inttm_hour;

horasdesdelamedianoche(0,23)

inttm_mday;

díadelmes(1,31)

inttm_mon;

meses

desde

enero(0,11)

inttm_year;

añosdesde1900

inttm_wday;

díasdesdeeldomingo(0,6)

inttm_yday;

díasdesdeenero1(0,365)

inttm_isdst;

banderade

DaylightSavingTime

tm_isdstespositivasiDaylightSavingTimeestáenefecto,cerosinoloestáynegativasilainformaciónnoestádisponible.

clock_tclock(void)

Page 429: Titivillus 07.07

clockregresaeltiempodeprocesadorempleadoporelprogramadesdeeliniciodesuejecución,o-1sinoestádisponible.clock()/CLK_TCKeseltiempoensegundos.

time_ttime(time_t*tp)

timeregresalafechayhoraactualdelcalendario,o-1sinoestádisponible.SitpnoesNULL,elvalorderetornotambiénesasignadoa*tp.

doubledifftime(time_ttime2,time_ttime1)

difftimeregresatime2-time1expresadoensegundos.

time_tmktime(structtm*tp)

mktimeconviertelafechayhoralocaldelaestructura*tpafechayhoradelcalendarioenlamismarepresentaciónutilizadaportime.Loscomponentestendránvaloresdentrodelosrangosmostrados,mktimeregresalafechayhoradelcalendario,o-1sinopuedeserrepresentada.

Lassiguientescuatrofuncionesregresanapuntadoresaobjetosestáticosquepuedensersobrescritosporotrasllamadas.

char*asctime(conststructtm*tp)

asctimeconviertelahoradelaestructura*tpaunacadenadelaforma

SunJan315:14:131988\n\0

char*ctime(consttime_t*tp)

ctimeconviertelahoradelcalendario*tpahoralocal;esequivalentea

asctime(localtime(tp))

structtm*gmtime(consttime_t*tp)

gmtimeconvienelahoradelcalendario*tpaHoraCoordinadaUniversal(

CoordinatedUniversalTime—UTC

).RegresaNULLsiUTCnoestádisponible.Elnombregmtimetienesignificadohistórico.

structtm*localtime(consttime_t*tp)

localtimeconviertelahoradelcalendario*tpahoralocal.

size_tstrftime(char*s,size_tsmax,constchar*fmt,conststructtm*tp)

strftimedaformatoalahorayfechade*tpensdeacuerdoconfmt,queesanálogoalformatoprintf.Loscaracteresordinarios(incluyendolaterminación'\0')secopiandentrodes.Cada

%c

sereemplazacomosedescribeabajo,utilizandolosvaloresapropiadosdelentorno.En

Page 430: Titivillus 07.07

snosecolocanmásdesmaxcaracteres,strftimeregresaelnúmerodecaracteres,excluyendoel'\0',ocerosifueronproducidosmásdesmaxcaracteres.

%a

nombreabreviadodeldíadelasemana.

%A

nombrecompletodelasemana.

%b

nombreabreviadodelmes.

%B

nombrecompletodelmes.

%c

representaciónlocaldefechayhora.

%d

díadelmes(01-31).

%H

hora(relojde24horas)(00-23).

%I

hora(relojde12horas)(01-12).

%j

díadelaño(001-366).

%m

mes(01-12).

%M

minuto(00-59).

%p

equivalencialocaldeAMoPM.

%S

segundos(00-59).

%U

Page 431: Titivillus 07.07

númerodesemanadelaño(domingoeselprimerdíadelasemana)(00-53).

%w

díadelasemana(0-6,domingoes0).

%W

númerodesemanadelaño(luneseselprimerdíadelasemana)(00-53).

%x

representaciónlocaldelafecha.

%x

representaciónlocaldelahora.

%y

añosinelsiglo(00-99).

%Y

añoconelsiglo.

%Z

nombredelazonahoraria,siexiste.

%%

%.

Page 432: Titivillus 07.07

B11.Límitesdefinidosenlaimplantación:<limits.h>y<float.h>

Elheader<limits.h>defineconstantesparaeltamañodelostiposenteros.Losvaloresmostradossonmagnitudesmínimasaceptables;sepuedenemplearvaloresmayores.

CHAR_BIT

8

bitsenunchar

CHAR_MAX

UCHAR_MAX

or

SCHAR_MAX

valormáximodechar

CHAR_MIN

0

or

SCHAR_MIN

valormínimodechar

INT_MAX

+32767

valormáximodeint

INT_MIN

-32767

valormínimodeint

LONG_MAX

+2147483647L

valormáximodelong

LONG_MIN

-2147483647L

Page 433: Titivillus 07.07

valormínimodelong

SCHAR_MAX

+127

valormáximodesignedchar

SCHAR_MIN

-127

valormínimodesignedchar

SHRT_MAX

+32767

valormáximodeshort

SHRT_MIN

-32767

valormínimodeshort

UCHAR_MAX

255U

valormáximodeunsignedchar

UINT_MAX

65535U

valormáximodeunsignedint

ULONG_MAX

4294967295UL

valormáximodeunsignedlong

USHRT_MAX

65535U

valormáximodeunsignedshort

Losnombresdelatablasiguiente,subconjuntode<float.h>,sonconstantesrelacionadasconlaaritméticadepuntoflotante.Cuandosedaunvalor,representalamagnitudmínimaparalacantidadcorrespondiente.Cadaimplantacióndefinelosvaloresapropiados.

FLT_RADIX

Page 434: Titivillus 07.07

2

radicaldelarepresentaciónexponencial,p.ej.,2,16

FLT_ROUNDS

mododeredondeodepuntoflotanteparaadición

FLT_DIG

6

dígitosdecimalesdeprecisión

FLT_EPSILON

1E-5

menornúmero

x

talque1.0+x≠1.0

FLT_MANT_DIG

númerodedígitosdebaseFLT_RADIXenlamantisa

FLT_MAX

1E+37

máximonúmerodepuntoflotante

FLT_MAX_EXP

máximo

n

talqueFLT_RADIX

n

-1esrepresentable

FLT_MIN

1E-37

mínimonúmeronormalizadodepuntoflotante

FLT_MIN_EXP

mínimo

Page 435: Titivillus 07.07

n

talque10

n

esunnúmeronormalizado

DBL_DIG

10

dígitosdecimalesdeprecisión

DBL_EPSILON

1E-9

menornúmero

x

talque1.0+

x

≠1.0

DBL_MANT_DIG

númerodedígitosdebaseFLT_RADIXenlamantisa

DBL_MAX

1E+37

máximonúmerodoubledepuntoflotante

DBL_MAX_EXP

máximo

n

talqueFLT_RADIX

n

-1esrepresentable

DBL_MIN

1E-37

mínimonúmerodoublenormalizadodepuntoflotante

Page 436: Titivillus 07.07

DBL_MIN_EXP

mínimo

n

talque10

n

esunnúmeronormalizado

Page 437: Titivillus 07.07

APÉNDICEC:Resumendemodificaciones

Desdelapublicacióndelaprimeraedicióndeestelibro,ladefinicióndellenguajeChasufridomodificaciones.Casitodasfueronextensionesallenguajeoriginal,yfuerondiseñadascuidadosamenteparapermanecercompatiblesconlaprácticaexistente;algunasrepararonambigüedadesdeladescripciónoriginal,yotrasrepresentanmodificacionesdelaprácticaexistente.MuchasdelasnuevascaracterísticasseanunciaronenlosdocumentosqueacompañanaloscompiladoresdisponiblesdeAT&T,yposteriormentesehanadoptadoporotrosproveedoresdecompiladoresdellenguajeC.Recientemente,elcomitéANSIincorporómásdeesoscambiosestandarizandoellenguaje,ytambiénintrodujootrasmodificacionessignificativas.Sureportefueenparteanticipadoporalgunoscompiladorescomercialesaúnantesdelapublicacióndelestándarformal.

Esteapéndiceresumelasdiferenciasentreellenguajedefinidoporlaprimeraedicióndeestelibro,yloesperadocomoladefinicióndelestándarfinal.Tratasolamenteallenguajeensí,noasuentornoniasubiblioteca;aunqueesassonpartesimportantesdelestándar,haypococonquécompararlas,puestoqueenlaprimeraediciónnoseintentódefinirlas.

ElpreprocesamientoestádefinidomáscuidadosamenteenelEstándarqueenlaprimeraedición,yestáextendido:estáexplícitamentebasadoen

tokens

(símbolos);existennuevosoperadoresparalaconcatenaciónde

tokens

(##)ycreacióndecadenas(#);haynuevaslíneasdecontrolcomo#elify#pragma;estáexplícitamentepermitidalaredeclaracióndemacrosporlamismasecuenciade

tokens

;yanosereemplazanlosparámetrosqueestándentrodecadenas.Laseparacióndelíneaspor\estápermitidaencualquierlugar,nosóloendefinicionesdecadenasymacros.Véase§A12.

Elsignificadomínimodetodoslosidentificadoresinternosseincrementóa31caracteres;permitidoparaidentificadoresconligaexternopermaneceen6letras,sinimportarsinsonmayúsculasominúsculas(muchasimplantacionesproporcionanmás).

Lassecuenciastrigráficasintroducidaspor??permitenlarepresentacióndecaracteresquenoseencuentranenalgunosconjuntos.Estándefinidoslosescapespara#\^[]{}|~.Véase§A12.1.Obsérvesequelaintroduccióndetrigrafospuedecambiarelsignificadodecadenasquecontenganlasecuencia??.

Seintrodujeronnuevaspalabrasreservadas(void,const,volatile,signed,enum).Lapalabrareservadaentry,quenuncasepusoenuso,fueretirada.

Sedefinennuevassecuenciasdeescapeparausodentrodeconstantesdecarácterycadenasliterales.Elefectodeseguir\conuncarácterquenoseapartedeunasecuenciadeescapeaprobadaestáindefinido.Véase§A2.5.2.

Page 438: Titivillus 07.07

Eltrivialcambiofavoritodetodos:8y9nosondígitosoctales.

Elestándarintroduceunconjuntomásgrandedesufijosparahacerexplícitoeltipodeconstantes:UoLparaenteros,FoLparaflotantes.Tambiénafinalasreglasparaelusodeconstantessinsufijo(§A2.5).

Lascadenasliteralesadyacentesseconcatenan.

Existeunanotaciónparacadenasliteralesampliasdecaracteresyconstantesdecarácter.Véase§A2.6.

Loscaracteres,asícomootrostipos,puedenserexplícitamentedeclaradosparateneronosigno,utilizandolaspalabrasreservadassignedounsigned.Seretirólalocuciónlongfloatcomounsinónimoparadouble,perolongdoublepuedeserutilizadaparadeclararunacantidadflotantedeprecisiónextra.

Poralgúntiempo,eltipounsignedcharhaestadodisponible.Elestándarintroducelapalabrareservadasignedparahacerexplícitoelsignoparacharyotrosobjetosenteros.

Poralgunosaños,eltipovoidhaestadodisponibleenalgunasimplantaciones.Elestándarintroduceelusodeltipovoid*comountipodeapuntadorgenérico;anteriormentechar*desempeñóestepapel.Almismotiempo,secrearonreglasexplícitascontralamezcladeapuntadoresyenteros,ydeapuntadoresdediferentetipo,sinelusodeoperadores

cast

.

Elestándarfijamínimosexplícitosenlosrangosdetiposaritméticosydelegaalosarchivos

header

(<limits.h>y<float.h>)eldarlascaracterísticasdecadaimplantaciónparticular.

Lasenumeracionessonalgonuevodesdelaprimeraedicióndeestelibro.

ElestándaradoptadeC++lanocióndecalificadordetipo,porejemplo,const(§A8.2).

Lascadenasyanosonmodificables,porloquepuedensituarseenmemoriadesólolectura.

Secambiaronlas“convencionesaritméticasusuales”,esencialmentede“paraenteros,unsignedsiempregana;parapuntoflotante,siempreusedouble”a“promuevaaltipomáspequeñodesuficientecapacidad”.Véase§A6.5.

Losantiguosoperadoresdeasignacióncomo=+realmentedesaparecieron.También,losoperadoresdeasignaciónsonahora

tokens

sencillos;enlaprimeraediciónfueronparejasysepodíansepararporespacioenblanco.

Secancelólalicenciadelcompiladorparatrataralosoperadoresmatemáticamenteasociativoscomocomputacionalmenteasociativos.

Page 439: Titivillus 07.07

Seintrodujounoperadorunario+porsimetríaconel-unario.

Unapuntadoraunafunciónsepuedeutilizarcomoundesignadordefunciónsinunoperador*explícito.Véase§A7.3.2.

Lasestructurassepuedenasignar,pasarafunciones,yregresarporfunciones.

Estápermitidoaplicareloperador“direcciónde”aarreglos,yelresultadoesunapuntadoralarreglo.

Eloperadorsizeof,enlaprimeraedición,dabaeltipoint;posteriormente,muchasimplantacioneslohicieronunsigned.Elestándarhaceeltipoexplícitamentedependientedelaimplantaciónperorequierequeeltiposize_tseadefinidoenun

header

estándar(<stddef.h>).Uncambiosemejanteocurreeneltipo(ptrdiff_t)deladiferenciaentreapuntadores.Véase§A7.4.8y§A7.7.

Eloperador&(“direcciónde”)nosepuedeaplicaraunobjetodeclaradoregister,aunsilaimplantacióndecidenomanteneralobjetoenunregistro.

Eltipodeunaexpresióndecorrimientoeseldeloperandodelaizquierda;eloperandodeladerechanopuedepromoverelresultado.Véase§A7.8.

Elestándarlegalizalacreacióndeunapuntadorjustomásalládelfindeunarregloypermitearitméticayrelacionessobreél;Véase§A7.7.

Elestándarintroduce(tomándolodeC++)lanocióndedeclaracióndeunafunciónprototipoqueincorporalostiposdelosparámetros,eincluyeunreconocimientoexplícitodefuncionesconlistasvariablesdeargumentos,juntoconunaformaaprobadadetratarlas.Véase§§A7.3.2,A8.6.3yB7.Elestiloantiguotodavíaseacepta,conrestricciones.

Lasdeclaracionesvacías,quenotienendeclaradoresynodeclaranalmenosaunaestructura,uniónoenumeración,estánprohibidasporelestándar.Porotrolado,unadeclaraciónconsólounrótulodeestructuraodeunión,redeclaraeserótuloaunsifuedeclaradoenunalcancemásexterno.

Estánprohibidaslasdeclaracionesexternassinningúnespecificadorocalificador(consóloeldeclarador).

Algunasimplantaciones,cuandoexaminanunadeclaraciónexternenunbloquemásinterno,podíanexportarladeclaraciónalrestodelarchivo.Elestándarhaceclaroqueelalcancedetaldeclaraciónessóloelbloque.

Elalcancedelosparámetrosseintroduceenlaproposicióncompuestadeunafunción,asíquelasdeclaracionesdevariablesenelnivelsuperiordelafunciónnopuedenocultarlosparámetros.

Losespaciosdenombredelosidentificadoressonalgodiferentes.Elestándarponetodoslosrótulosenunespaciosencillodenombre,ytambiénintroduceunespacioseparadodenombresparaetiquetas;véase§A11.1.Losnombresdemiembrostambiénestánasociadosconlaestructuraounióndelaquesonparte(estohasidoprácticacomúnporalgúntiempo).

Lasunionessepuedeninicializar;elinicializadorserefierealprimermiembro.

Page 440: Titivillus 07.07

Lasestructuras,unionesyarreglosautomáticossepuedeinicializar,aunqueenunaformarestringida.

Losarreglosdecaracterescontamañoexplícitosepuedeninicializarconunacadenaliteralconexactamentelamismacantidaddecaracteres(el\0seexcluyecalladamente).

Laexpresióndecontrolylasetiquetasdelasalternativasdeunswitch,puedentenercualquiertipoentero.

Page 441: Titivillus 07.07

BRIANWILSONKERNIGHAN(Toronto,Ontario,1deenerode1942),científicodelacomputación,nacidoenToronto,Canadáen1942.Conocidoporlaco-autoríadellibroEllenguajedeprogramaciónC.TrabajóenlosLaboratoriosBelljuntoconKenThompsonyDennisRitchie,dondeayudóeneldesarrollodelsistemaoperativoUnix,programandoutilidadescomoditroff.KernighanrecibiósulicenciaturaenfísicaeingenieríaenlaUniversidaddeToronto.SedoctoróeningenieríaeléctricaporlaUniversidaddePrinceton,dondedesde2000esprofesordecienciasdelacomputación(yen2006continúatrabajandoenelmismositio).

AunqueprefiereellenguajeCacualquierotro(dijoquesituvieraquellevarseunlenguajedeprogramaciónaunaisladesierta,tendríaqueserC)Kernighanniegacualquiercontribuciónsuyaensudiseño,acreditandosuautoríatotalaDennisRitchie(«esenteramenteobradeDennisRitchie»).NoobstantecontribuyóenlacreacióndeotroslenguajescomoAWKyAMPL.La«K»delasletrasK&Rconlasqueseconocesulibromásfamoso,yla«K»deAWKderivande«Kernighan».

KernighanfuetambiéneditorentemasdesoftwareparaPrentice-HallInternational.SuserieSoftwareToolsextendiólaesenciadel«pensamientoC/Unix»,comomejorasobrelosmásestablecidosenelmomentoBASIC,FORTRAN,yPascal.

Page 442: Titivillus 07.07

DENNISMACALISTAIRRITCHIE(9deseptiembrede1941-12deoctubrede2011)fueuncientíficodelacomputaciónestadounidense.

ColaboróeneldiseñoydesarrollodelossistemasoperativosMulticsyUnix,asícomoeldesarrollodevarioslenguajesdeprogramacióncomoelC,temasobreelcualescribióuncélebreclásicodelascienciasdelacomputaciónjuntoaBrianWilsonKernighan:EllenguajedeprogramaciónC.

RecibióelPremioTuringde1983porsudesarrollodelateoríadesistemasoperativosgenéricosysuimplementaciónenlaformadelsistemaUnix.En1998lefueconcedidalaMedallaNacionaldeTecnologíadelosEstadosUnidosdeAmérica.Elaño2007sejubiló,siendoeljefedeldepartamentodeInvestigaciónensoftwaredesistemasdeAlcatel-Lucent.

Page 443: Titivillus 07.07

Notas

[1]Apesardequeeningléslapalabracorrectaes“create”,elnombredelafunciónessólo“creat”.(N.deTrad.)<<

Page 444: Titivillus 07.07