titivillus 07.07
TRANSCRIPT
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.
BryanW.KernighanyDennisM.Ritchie
EllenguajedeprogramaciónC
ConbaseenelANSIC
ePubr1.0
Titivillus07.07.17
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
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.
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
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
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
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
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,
estáprincipalmentepensadoparaquienesescribencompiladores.Elmanualdeconsultadeestelibrotransmiteladefinicióndellenguajeenunaformamásconcisaysinelmismoestilolegalista.ElapéndiceBesunresumendelabibliotecaestándar,denuevomásparausuariosqueparaimplantadores.ElapéndiceCesunbreveresumendeloscambiosdellenguajeoriginal.Aunque,encasodeduda,elestándaryelcompiladorenusoquedancomolasautoridadesfinalessobreellenguaje.
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.
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.
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");
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.□
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
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
/*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;
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
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
...
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
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
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.□
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
incrementopuedensercualquierexpresión.
Laselecciónentrewhileyforesarbitraria,ysebasaenaquelloqueparezcamásclaro.Elforesporlogeneralapropiadoparaciclosenlosquelainicializaciónyelincrementosonproposicionessencillasylógicamenterelacionadas,puestoqueesmáscompactoqueelwhileymantienereunidasenunlugaralasproposicionesquecontrolanalciclo.
Ejercicio1-5.Modifiqueelprogramadeconversióndetemperaturasdemaneraqueescribalatablaenordeninverso,estoes,desde300gradoshasta0.□
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.
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.
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.
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.□
Ejercicio1-7.EscribaunprogramaqueimprimaelvalordeEOF.□
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()
{
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.
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.
Ejercicio1-8.Escribaunprogramaquecuenteespaciosenblanco,tabuladoresynuevaslíneas.□
Ejercicio1-9.Escribaunprogramaquecopiesuentradaalasalida,reemplazandocadacadenadeunoomásblancosporunsoloblanco.□
Ejercicio1-10.Escribaunprogramaquecopiesuentradaalasalida,reemplazandocadatabulaciónpor\t,cadaretrocesopor\bycadadiagonalinvertidapor\\.Estohacequelastabulacionesylosespaciosseanvisiblessinconfusiones.□
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
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&¶AND;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.□
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);
}
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)
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.□
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)
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
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
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.□
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.
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*/
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[])
{
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
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.□
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()
{
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;
}
/*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.
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.)□
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.
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.
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.
Ejercicio2-1.Escribaunprogramaparadeterminarlosrangosdevariableschar,short,intylong,tantosignedcomounsigned,imprimiendolosvaloresapropiadosdelosheadersestándaryporcálculodirecto.Esmásdifícilsiloscalcula:determinelosrangosdelosvariostiposdepuntoflotante.□
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
\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.
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')
++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.
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:";
Ladeclaraciónconsttambiénsepuedeutilizarconargumentosdetipoarreglo,paraindicarquelafunciónnocambiaesearreglo:
intstrlen(constchar[]);
Siseefectúaunintentodecambiarunconst,elresultadoestádefinidoporlaimplantación.
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.
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
if(válido==0)
Esdifícilgeneralizaracercadecuáleslamejor.Construccionescomo!válidoseleenenformaagradable(“sinoesválido”),perootrasmáscomplicadaspuedenserdifícilesdeentender.
Ejercicio2-2.Escribauncicloequivalentealaiteraciónforanteriorsinusar&&o||.□
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')
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
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
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)
{
next=seed;
}
Ejercicio2-3.Escribalafunciónhtoi(s),queconvierteunacadenadedígitoshexadecimales(incluyendo0xó0Xenformaoptativa)ensuvalorenteroequivalente.Losdígitospermitidossondel0al9,delaaalaf,ydelaAalaF.□
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';
}
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*/
;
}
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.)□
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
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.□
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)
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.□
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");
Ejercicio2-10.Reescribalafunciónlower,queconvierteletrasmayúsculaseminúsculas,conunaexpresióncondicionalenvezdeunif-else.□
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
==!=
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
++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.
CAPÍTULO3:Controldeflujo
Lasproposicionesdecontroldeflujodeunlenguajeespecificanelordenenqueserealizaelprocesamiento.Yahemosvistolamayoríadelasconstruccionesdecontroldeflujoenejemplosanteriores;aquícompletaremoselconjunto,yseremosmásprecisosacercadelasdiscutidasconanterioridad.
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.
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;
}
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.
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.
/*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.□
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'':
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.□
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')
;/*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*/
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
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.□
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';
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.□
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;
.../*trabajaconelementospositivos*/
}
Laproposicióncontinueseempleaamenudocuandolapartedelcicloquesigueescomplicada,demodoqueinvertirlapruebaysangrarotronivelpodríaanidarprofundamenteelprograma.
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]*/
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.
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.
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á
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')
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.
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.□
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;
}
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)
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.□
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.
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(){...}
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;
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.
#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);
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
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.□
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.□
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
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.
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>
#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
mantenermásarchivostipoheader.Hastauntamañomoderadodeprograma,probablementeesmejortenerunarchivodeencabezamientoquecontengatodoloqueserácompartidoentrelaspartesdelprograma;éstaesladecisiónquetomamosaquí.Paraunprogramamuchomásgrande,senecesitaríamásorganizaciónymásarchivostipoheader.
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.□
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.
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.
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
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').
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
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
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.□
4.11.ElpreprocesadordeC
Cproporcionaciertasfacilidadesdelenguajepormediodeunpreprocesador,queconceptualmenteesunprimerpasoseparadoenlacompilación.Losdoselementosqueseusanconmásfrecuenciason#include,paraincluirelcontenidodeunarchivodurantelacompilación,y#define,parareemplazarunsímboloporunasecuenciaarbitrariadecaracteres.Otrascaracterísticasquesedescribenenestasecciónincluyencompilacióncondicionalymacrosconargumentos.
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.
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
#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á.)□
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á
definido.Elprimerejemplode#ifdemásarribapudohaberseescrito
#ifndefHDR
#defineHDR
/*contenidodehdr.hvaaquí*/
#endif
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.
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
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.
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:
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*/
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?□
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],
*(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)
{
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.
Siseestásegurodequeloselementosexisten,tambiénesposibleindexarhaciaatrásenunarreglo;p[-1],p[-2],etc.,sonlegítimosdesdeelpuntodevistasintáctico,yserefierenaelementosqueprecedeninmediatamenteap[0].Porsupuesto,esilegalhacerreferenciaaobjetosquenoesténdentrodeloslímitesdelarreglo.
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:
#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
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++;
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.
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.
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')
;
}
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];
}
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).□
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.
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;
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)
{
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;
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?□
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)
{
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]){...}
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.□
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.
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
enlugardeíndices.□
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)?"":"");
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);
/*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:
#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){
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
tail-n
imprimelasúltimasnlíneas.Elprogramadebecomportarseenformaracionalsinimportarcuánpocorazonablesealaentradaoelvalorden.Escribaelprogramademaneraquehagaelmejorusodelamemoriadisponible;laslíneasdebenalmacenarsecomoenelprogramadeordenamientodelasección5.6,noenunarreglodedosdimensionesdetamañofijo.□
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)
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;
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)
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.)□
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
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):
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;
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);
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=='('){
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
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.□
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.
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.
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
structrectscreen;
entonces
screen.pt1.x
serefierealacoordenadaxdelmiembropt1descreen.
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
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);
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{
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.
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;
}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>
#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;
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])
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];
}
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.□
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)
{
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
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.
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
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>
#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*/
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
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;
}
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.□
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*/
};
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:
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.□
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
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.
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);
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.
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:
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.
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.
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.
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].□
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.
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
e±
xx
o[-]
m
.
dddddd
E±
xx
,endondeelnúmerode
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:
:%-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.□
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;
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.□
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.)
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.
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*/
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.□
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.
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>
/*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)
esloinversodefopen;interrumpelaconexiónquefueestablecidaporfopenentreelapuntadordearchivoyelnombreexterno,liberandoalapuntadordearchivoparaotroarchivo.Puestoquelamayoríadelossistemasoperativostienenalgunaslimitantessobreelnúmerodearchivosqueunprogramapuedetenerabiertossimultáneamente,esunabuenaidealiberarlosapuntadoresdearchivocuandoyanosonnecesarios,comosehizoencat.Tambiénhayotrarazónparausarfcloseenunarchivodesalida—vacíaelbufferenelcualputcestácolectandolasalida.Cuandounprogramaterminanormalmente,fcloseesllamadoautomáticamenteparacadaarchivoabierto.(Sepuedecerrarstdinystdoutsinosonnecesarios.Tambiénpuedenserreasignadosporlafuncióndebibliotecafreopen.)
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)){
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.
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*/
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.□
7.8.Otrasfunciones
Labibliotecaestándarproporcionaunaampliavariedaddefunciones.Estasecciónesunabrevesinopsisdelasmásútiles.EnelapéndiceBpuedenencontrarsemásdetallesymuchasotrasfunciones.
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
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
7.8.3.Ungetc
Labibliotecaestándarproporcionaunaversiónmásrestringidadelafunciónungetchqueescribimosenelcapítulo4;sellamaungetc.
intungetc(intc,FILE*fp)
colocaelcaráctercdenuevoenelarchivofpyregresac,oEOFencasodeerror.Sólosegarantizaponeruncarácterderegresoporarchivo.Esposibleutilizarungetcconcualquieradelasfuncionescomoscanf,getcogetchar.
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.
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.
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
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
)
xy
sqrt(
x
)
raízcuadradade
x
(
x
≥0)
fabs(
x
)
valorabsolutode
x
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.□
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.
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.
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
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.
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.
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
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.□
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.
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{
_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*/
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
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++;
}
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.□
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'*/
}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*/
}
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(".");
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*))
{
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
#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;
}
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;
}
Aunqueelprogramafsizeesbastanteespecializado,ilustraunpardeideasimportantes.Primera,muchosprogramasnoson“programasdelsistema”;simplementeusaninformaciónqueesmantenidaporelsistemaoperativo.Paratalesprogramasescrucialquelarepresentacióndelainformaciónaparezcasóloenheadersestándar,yquelosprogramasincluyanesosarchivosenvezdetenerlasdeclaracionesenellosmismos.Lasegundaobservaciónesqueconcuidadoesposiblecrearunainterfazhaciaobjetosdependientesdelsistemaqueasuvezsearelativamenteindependientedelmismo.Lasfuncionesdelabibliotecaestándarsonbuenosejemplos.
Ejercicio8-5.Modifiqueelprogramafsizeparaqueimprimaelrestodelainformacióncontenidaenlaentradadelnodo-i.□
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.
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.
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;
}
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*/
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;
}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.□
APÉNDICEA:Manualdereferencia
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.
A2.Convencionesléxicas
Unprogramaconsisteenunaomásunidadesdetraducciónalmacenadasenarchivos.Estraducidoenvariasfases,quesedescribenen§A12.Lasprimerasfaseshacentransformacionesléxicasdebajonivel,ejecutandirectivasintroducidasconlíneasqueprincipianconelcarácter#,yrealizanmacrodefinicionesyexpansiones.Cuandoelpreprocesamientode§A12estácompleto,elprogramasehareducidoaunasecuenciadecomponentesléxicos.
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.
A2.2.Comentarios
Loscaracteres/*inicianuncomentario,queterminaconloscaracteres*/.Loscomentariosnoseanidanynopuedenestardentrodecadenasocaracteresliterales.
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.
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
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.
A2.5.Constantes
Hayvariasclasesdeconstantes.Cadaunatieneuntipodedato;en§A4.2sediscutenlostiposbásicos.
constante:
constante-entera
constante-de-carácter
constante-flotante
constante-enumeración
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.
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
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
representaconwchar_t.
Algunasdeestassecuenciasdeescapesonnuevas,enparticularlarepresentaciónhexadecimaldecaracteres.Loscaracteresextendidostambiénsonnuevos.LosjuegosdecaracterescomúnmenteusadosenAméricayEuropaoccidentalsepuedencodificarparaquedareneltipochar;laintenciónprincipaldeagregarwchar_tfueadaptarsealoslenguajesasiáticos.
A2.5.3.Constantesflotantes
Unaconstanteflotanteconstadeunaparteentera,unpuntodecimal,unapartefraccionaria,unaeoE,unexponenteenterosignadooptativoyuntiposufijooptativoentrefoF,loL.Laspartesenterayfraccionariaconstandeunasecuenciadedígitos.Cualquieradelaspartesenteraofraccionaria(noambas)puedeomitirse;cualquieradelaspartesdelpuntodecimalolaeyelexponente(noambas)puedenomitirse.Eltipoestádeterminadoporelsufijo;Foflahacenfloat,Lollahacenlongdouble;deotramaneraesdouble.
Lossufijosenconstantesflotantessonnuevos.
A2.5.4.Constantesdeenumeración
Losidentificadoresdeclaradoscomoenumeradores(véase§A8.4)sonconstantesdetipoint.
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.
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.
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.
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.
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,
cadaunoconosinsigno,ytambiénlostiposdeenumeración,sellamaránconjuntamentetiposenteros.Lostiposfloat,doubleylongdoublesellamarántiposflotantes.
Eltipovoidespecificaunconjuntovacíodevalores.Seusacomoeltiporegresadoporfuncionesquenogeneranunvalor.
A4.3.Tiposderivados
Ademásdelostiposbásicos,existeunacategoríaconceptualmenteinfinitadetiposderivados,construidosapartirdelostiposfundamentalesenlasformassiguientes:
arreglos
deobjetosdeuntipodado;
funciones
queregresanobjetosdeuntipodado;
apuntadores
aobjetosdeuntipodado;
estructuras
quecontienenunasecuenciadeobjetosdevariostipos;
uniones
capacesdecontenerunobjetocualquieradevariostipos.
Engeneral,estosmétodosdeconstruccióndeobjetossepuedenaplicarenformarecursiva.
A4.4.Calificadoresdetipo
Untipodeobjetopuedetenercalificadoresadicionales.Eldeclararconstaunobjetoanunciaquesuvalornocambiará;declararlovolatileanunciaquetienepropiedadesespecialesdeimportanciaparalaoptimización.Ningúncalificadorafectaelrangodevaloresopropiedadesaritméticasdelobjeto.Loscalificadoressediscutenen§A8.2.
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.
A6.Conversiones
Algunosoperadorespueden,dependiendodesusoperandos,provocarlaconversióndelvalordeunoperandodeuntipoaotro.Estasecciónexplicaelresultadoqueseesperadetalesconversiones.§A6.5resumelasconversionesdemandadasporlamayoríadelosoperadoresordinarios;endondeserequiera,serácomplementadaconladiscusióndecadaoperador.
A6.1.Promociónentera
Uncarácter,unenterocortoouncampoenterodebits,todosconosinsigno,ounobjetodetipoenumeración,sepuedeutilizardentrodeunaexpresiónencualquierlugarendondesepuedausarunentero.Siunintpuederepresentaratodoslosvaloresdeltipooriginal,entonceselvaloresconvertidoaint;deotramaneraelvaloresconvertidoaunsignedint.Esteprocesosellamapromociónentera.
A6.2.Conversionesenteras
Unenteroseconvierteauntiposinsignodadoencontrandoelmenorvalornonegativoqueseacongruenteconeseentero,módulounomásqueelmayorvalorquesepuedarepresentareneltiposinsigno.Enunarepresentacióncomplementoados,estoesequivalentealtruncamientoporlaizquierdasielpatróndebitsdeltiposinsignoesmásestrecho,yalllenadoconcerosdevaloressinsignoyextensióndesignoenvaloresconsignosieltiposinsignoesmásamplio.
Cuandocualquierenteroseconvierteauntipoconsigno,elvalornosecambiasipuedeserrepresentadoenelnuevotipo,yenotrocasoestádefinidoporlaimplantación.
A6.3.Enteroyflotante
Cuandounvalordetipoflotanteseconvierteauntipoentero,lapartefraccionariasedescarta;sielvalorresultantenopuedeserrepresentadoeneltipoentero,elcomportamientonoestádefinido.Enparticular,elresultadodeconvertirvaloresflotantesnegativosatiposenterossinsignonoestáespecificado.
Cuandounvalordetipoenteroseconvierteaflotante,yelvalorestáenelrangorepresentableperonoesexactamenterepresentable,entonceselresultadopuedeserelvalorsiguientemásaltoomásbajo.Sielresultadoestáfueraderango,elcomportamientoestáindefinido.
A6.4.Tiposflotantes
Cuandounvalorflotantemenosprecisoseconvierteauntipoflotanteigualomáspreciso,elvalornosemodifica.Cuandounvalorflotantemásprecisoseconvierteauntipoflotantemenospreciso,yelvalorestádentrodelrangorepresentable,elresultadopuedeserelsiguientevalorrepresentablemásaltooelsiguientemásbajo.Sielresultadoestáfueraderango,elcomportamientoestáindefinido.
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.
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.
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.
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.
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.
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.
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.
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
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.
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.
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.
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.
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.
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
&*+-~!
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.
A7.4.2.Operadordedirección
Eloperadorunario&tomaladireccióndesuoperando.Eloperandodebeserelvalor-lquenoserefieraniauncampodebitsniaunobjetodeclaradocomoregister,odebeserdetipofunción.Elresultadoesunapuntadoralobjetoofunciónalqueserefiereelvalor-l.SieltipodeloperandoesT,eltipodelresultadoes“apuntadoraT”.
A7.4.3.Operadordeindirección
Eloperadorunario*denotaindirecciónyregresaelobjetoofunciónaqueapuntasuoperando.Esunvalor-lsieloperandoesunapuntadoraunobjetodetipoaritmético,estructura,uniónoapuntador.Sieltipodelaexpresiónesun“apuntadoraT”eltipodelresultadoesT.
A7.4.4.Operadormásunario
Eloperandodeloperadorunario+debetenertipoaritméticooapuntadoryelresultadoeselvalordeloperando.Unoperandoenterosufrepromociónentera.Eltipodelresultadoeseltipodeloperandopromovido.
El+unarioesnuevoenelestándarANSI.Seagregóporsimetríaconel-unario.
A7.4.5.Operadormenosunario
Eloperadordel-unariodebetenertipoaritméticoyelresultadoeselnegativodesuoperando.Unoperandoenterosufrepromociónentera.Elnegativodeunacantidadsinsignosecalcularestandoelvalorpromovidodelmayorvalordeltipopromovidoyagregándoleuno;peroelceronegativoescero.Eltipodelresultadoeseltipodeloperandopromovido.
A7.4.6.Operadorcomplementoauno
Eloperandodeloperadorunario~debetenertipoenteroyelresultadoeselcomplementoaunodesuoperando.Serealizapromociónentera.Sieloperandoessinsigno,elresultadosecalcularestandoelvalordelmayorvalordeltipopromovido.Sieloperandoesconsigno,elresultadosecalculaconvirtiendoeloperandopromovidoaltiposinsignocorrespondiente,aplicando~yregresandoaltipoconsigno.Eltipodelresultadoeseltipodeloperandopromovido.
A7.4.7.Operadordenegaciónlógica
Eloperandodeloperador!debetenertipoaritméticooserunapuntador,yelresultadoes1sielvalordesuoperandoescomparaiguala0,y0encasocontrario.Eltipodelresultadoesint.
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.
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.
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.
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.
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.
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.
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.
A7.11.OperadorANDparabits
expresión-AND:
expresión-de-igualdad
expresión-AND&expresión-de-igualdad
Lasconversionesaritméticasusualesserealizan;elresultadoeslafunciónANDdebitsdelosoperandos.Eloperadorseaplicasóloaoperandosenteros.
A7.12.OperadorORexclusivoparabits
expresión-OR-exclusivo:
expresión-AND
expresión-OR-exclusivo^expresión-AND
Serealizanlasconversionesaritméticasusuales;elresultadoeslafunciónORexclusivodelosoperandos.Eloperadorseaplicasóloaoperandosenteros.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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:
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
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
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)...
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.
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.
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.
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.
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.
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
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++.
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.
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,
floaty[4][3]={
{1},{2},{3},{4}
};
inicializalaprimeracolumnadey(consideradocomounarreglobidimensional)ydejaalrestoen0.
Finalmente,
charmsg[]="Errordesintaxisenlínea%s\n";
muestraunarreglodecaracterescuyosmiembrossoninicializadosconunacadena;sutamañoincluyeelcarácternulodeterminación.
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”.
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.
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.
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
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.
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.
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.
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.
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.
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.
Unafunciónregresaaquienlainvocóconlaproposiciónreturn.Cuandoreturnesseguidoporunaexpresión,elvalorseregresaalinvocadordelafunción.Laexpresiónseconviene,comosiseasignara,altiporegresadoporlafunciónenlaqueaparece.
Queelflujolleguehastaelfinaldelafunciónesequivalenteaunreturnsinexpresión.Encualquiercaso,elvalorregresadoestáindefinido.
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.
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.
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.
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.
A11.Alcanceyliga
Noesnecesarioqueunprogramasecompiletodoalavez:eltextofuentesepuedemantenerenvariosarchivosconunidadesdetraducción,ysepuedencargarrutinasprecompiladasdebibliotecas.Lacomunicaciónentrelasfuncionesdeunprogramapuedellevarseacabotantoatravésdellamadascomoatravésdelamanipulacióndedatosexternos.
Portanto,existendosclasesdealcanceaconsiderar:primera,elalcanceléxicodeunidentificador,queeslaregióndeltextodelprogramadentrodelaqueseentiendenlascaracterísticasdelidentificador;ysegunda,elalcanceasociadoconobjetosyfuncionesconligaexterna,quedeterminalaconexiónentreidentificadoresenunidadesdetraduccióncompiladasporseparado.
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.
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.
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.
A12.1.Secuenciastrigráficas
ElconjuntodecaracteresdelosprogramasfuentedeCestácontenidodentrodelcódigoASCIIdesietebits,peroesunsuperconjuntodelISO646-1983InvariantCodeSet.Parapoderrepresentaralosprogramasenelconjuntoreducido,todaslasocurrenciasdelassiguientessecuenciastrigráficassereemplazanporelcaráctersimplecorrespondiente.Estereemplazoocurreantesdecualquierotroprocesamiento.
??=
#
??(
[
??<
{
??/
\
??)
]
??>
}
??'
^
??!
|
??-
~
Noocurreningúnotroreemplazo.
LassecuenciastrigráficassonnuevasenelestándarANSI.
A12.2.Unióndelíneas
Laslíneasqueterminanconelcarácterdiagonalinvertida\seempalmaneliminandoladiagonalinversayelsiguientecarácternuevalínea.Estoocurreantesdehacerladivisiónentokens.
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
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,
#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.
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.
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
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.
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.
A12.7.Generacióndeerrores
Unalíneadelpreprocesadordelaforma
#errorsecuencia-de-tokensopt
ocasionaqueelpreprocesadorescribaunmensajedediagnósticoqueincluyelasecuenciadetokens.
A12.8.Pragmas
Unalíneadecontroldelaforma
#pragmasecuencia-de-tokensopt
ocasionaqueelpreprocesadorrealiceunaacciónquedependedelaimplantación.Unpragmanoreconocidoesignorado.
A12.9.Directivanula
Unalíneadelpreprocesadordelaforma
#
notieneefecto.
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.
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
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
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
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]
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);
(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
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
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
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:
línea-eliftexto
partes-elifopt
línea-elif:
#elifexpresión-constante
parte-else:
línea-elsetexto
línea-else:
#else
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.
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.
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)
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).
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.
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.
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.
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
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.
[*...]
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.
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)
ungetcregresac(convertidoenunsignedchar)denuevoalstream,dedondeseráregresadoenlapróximalectura.Sólosegarantizauncarácterderegresoporflujo.EOFnopuedeserregresado,ungetcdevuelveelcarácterregresado,oEOFencasodeerror.
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.
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.
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.
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
(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.
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
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)
regresaunapuntadoralaprimeraocurrenciadelcaráctercencs,oNULLsinoestápresenteentrelosprimerosncaracteres.
void*memset(s,c,n)
colocaelcaráctercenlosprimerosncaracteresdes,regresas.
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
(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
≤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.
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)
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)
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.
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.
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.
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.
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.
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)
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
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
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.
%%
%.
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
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
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
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
DBL_MIN_EXP
mínimo
n
talque10
n
esunnúmeronormalizado
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.
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.
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.
Lasestructuras,unionesyarreglosautomáticossepuedeinicializar,aunqueenunaformarestringida.
Losarreglosdecaracterescontamañoexplícitosepuedeninicializarconunacadenaliteralconexactamentelamismacantidaddecaracteres(el\0seexcluyecalladamente).
Laexpresióndecontrolylasetiquetasdelasalternativasdeunswitch,puedentenercualquiertipoentero.
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.
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.
Notas
[1]Apesardequeeningléslapalabracorrectaes“create”,elnombredelafunciónessólo“creat”.(N.deTrad.)<<