├── LICENSE ├── README.md ├── book.adoc ├── capitulo01.adoc ├── capitulo02.adoc ├── capitulo03.adoc ├── capitulo04.adoc ├── capitulo05.adoc ├── capitulo06.adoc ├── capitulo07.adoc ├── capitulo08.adoc ├── capitulo09.adoc ├── capitulo10.adoc ├── crear_libro.sh ├── imagenes ├── listas1.gif ├── listas2.gif ├── listas3.gif ├── listas4.gif ├── punteros1.png ├── punteros1.xcf ├── punteros2.png ├── punteros2.xcf ├── punteros3.png ├── punteros3.xcf ├── punteros4.png ├── punteros4.xcf ├── union.png ├── union.xcf ├── union1.png └── union1.xcf └── programacion-c-principiantes-gorka-urrutia.pdf /LICENSE: -------------------------------------------------------------------------------- 1 | Attribution-NonCommercial-NoDerivatives 4.0 International 2 | 3 | ======================================================================= 4 | 5 | Creative Commons Corporation ("Creative Commons") is not a law firm and 6 | does not provide legal services or legal advice. Distribution of 7 | Creative Commons public licenses does not create a lawyer-client or 8 | other relationship. Creative Commons makes its licenses and related 9 | information available on an "as-is" basis. Creative Commons gives no 10 | warranties regarding its licenses, any material licensed under their 11 | terms and conditions, or any related information. Creative Commons 12 | disclaims all liability for damages resulting from their use to the 13 | fullest extent possible. 14 | 15 | Using Creative Commons Public Licenses 16 | 17 | Creative Commons public licenses provide a standard set of terms and 18 | conditions that creators and other rights holders may use to share 19 | original works of authorship and other material subject to copyright 20 | and certain other rights specified in the public license below. The 21 | following considerations are for informational purposes only, are not 22 | exhaustive, and do not form part of our licenses. 23 | 24 | Considerations for licensors: Our public licenses are 25 | intended for use by those authorized to give the public 26 | permission to use material in ways otherwise restricted by 27 | copyright and certain other rights. Our licenses are 28 | irrevocable. Licensors should read and understand the terms 29 | and conditions of the license they choose before applying it. 30 | Licensors should also secure all rights necessary before 31 | applying our licenses so that the public can reuse the 32 | material as expected. Licensors should clearly mark any 33 | material not subject to the license. This includes other CC- 34 | licensed material, or material used under an exception or 35 | limitation to copyright. More considerations for licensors: 36 | wiki.creativecommons.org/Considerations_for_licensors 37 | 38 | Considerations for the public: By using one of our public 39 | licenses, a licensor grants the public permission to use the 40 | licensed material under specified terms and conditions. If 41 | the licensor's permission is not necessary for any reason--for 42 | example, because of any applicable exception or limitation to 43 | copyright--then that use is not regulated by the license. Our 44 | licenses grant only permissions under copyright and certain 45 | other rights that a licensor has authority to grant. Use of 46 | the licensed material may still be restricted for other 47 | reasons, including because others have copyright or other 48 | rights in the material. A licensor may make special requests, 49 | such as asking that all changes be marked or described. 50 | Although not required by our licenses, you are encouraged to 51 | respect those requests where reasonable. More considerations 52 | for the public: 53 | wiki.creativecommons.org/Considerations_for_licensees 54 | 55 | ======================================================================= 56 | 57 | Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 58 | International Public License 59 | 60 | By exercising the Licensed Rights (defined below), You accept and agree 61 | to be bound by the terms and conditions of this Creative Commons 62 | Attribution-NonCommercial-NoDerivatives 4.0 International Public 63 | License ("Public License"). To the extent this Public License may be 64 | interpreted as a contract, You are granted the Licensed Rights in 65 | consideration of Your acceptance of these terms and conditions, and the 66 | Licensor grants You such rights in consideration of benefits the 67 | Licensor receives from making the Licensed Material available under 68 | these terms and conditions. 69 | 70 | 71 | Section 1 -- Definitions. 72 | 73 | a. Adapted Material means material subject to Copyright and Similar 74 | Rights that is derived from or based upon the Licensed Material 75 | and in which the Licensed Material is translated, altered, 76 | arranged, transformed, or otherwise modified in a manner requiring 77 | permission under the Copyright and Similar Rights held by the 78 | Licensor. For purposes of this Public License, where the Licensed 79 | Material is a musical work, performance, or sound recording, 80 | Adapted Material is always produced where the Licensed Material is 81 | synched in timed relation with a moving image. 82 | 83 | b. Copyright and Similar Rights means copyright and/or similar rights 84 | closely related to copyright including, without limitation, 85 | performance, broadcast, sound recording, and Sui Generis Database 86 | Rights, without regard to how the rights are labeled or 87 | categorized. For purposes of this Public License, the rights 88 | specified in Section 2(b)(1)-(2) are not Copyright and Similar 89 | Rights. 90 | 91 | c. Effective Technological Measures means those measures that, in the 92 | absence of proper authority, may not be circumvented under laws 93 | fulfilling obligations under Article 11 of the WIPO Copyright 94 | Treaty adopted on December 20, 1996, and/or similar international 95 | agreements. 96 | 97 | d. Exceptions and Limitations means fair use, fair dealing, and/or 98 | any other exception or limitation to Copyright and Similar Rights 99 | that applies to Your use of the Licensed Material. 100 | 101 | e. Licensed Material means the artistic or literary work, database, 102 | or other material to which the Licensor applied this Public 103 | License. 104 | 105 | f. Licensed Rights means the rights granted to You subject to the 106 | terms and conditions of this Public License, which are limited to 107 | all Copyright and Similar Rights that apply to Your use of the 108 | Licensed Material and that the Licensor has authority to license. 109 | 110 | g. Licensor means the individual(s) or entity(ies) granting rights 111 | under this Public License. 112 | 113 | h. NonCommercial means not primarily intended for or directed towards 114 | commercial advantage or monetary compensation. For purposes of 115 | this Public License, the exchange of the Licensed Material for 116 | other material subject to Copyright and Similar Rights by digital 117 | file-sharing or similar means is NonCommercial provided there is 118 | no payment of monetary compensation in connection with the 119 | exchange. 120 | 121 | i. Share means to provide material to the public by any means or 122 | process that requires permission under the Licensed Rights, such 123 | as reproduction, public display, public performance, distribution, 124 | dissemination, communication, or importation, and to make material 125 | available to the public including in ways that members of the 126 | public may access the material from a place and at a time 127 | individually chosen by them. 128 | 129 | j. Sui Generis Database Rights means rights other than copyright 130 | resulting from Directive 96/9/EC of the European Parliament and of 131 | the Council of 11 March 1996 on the legal protection of databases, 132 | as amended and/or succeeded, as well as other essentially 133 | equivalent rights anywhere in the world. 134 | 135 | k. You means the individual or entity exercising the Licensed Rights 136 | under this Public License. Your has a corresponding meaning. 137 | 138 | 139 | Section 2 -- Scope. 140 | 141 | a. License grant. 142 | 143 | 1. Subject to the terms and conditions of this Public License, 144 | the Licensor hereby grants You a worldwide, royalty-free, 145 | non-sublicensable, non-exclusive, irrevocable license to 146 | exercise the Licensed Rights in the Licensed Material to: 147 | 148 | a. reproduce and Share the Licensed Material, in whole or 149 | in part, for NonCommercial purposes only; and 150 | 151 | b. produce and reproduce, but not Share, Adapted Material 152 | for NonCommercial purposes only. 153 | 154 | 2. Exceptions and Limitations. For the avoidance of doubt, where 155 | Exceptions and Limitations apply to Your use, this Public 156 | License does not apply, and You do not need to comply with 157 | its terms and conditions. 158 | 159 | 3. Term. The term of this Public License is specified in Section 160 | 6(a). 161 | 162 | 4. Media and formats; technical modifications allowed. The 163 | Licensor authorizes You to exercise the Licensed Rights in 164 | all media and formats whether now known or hereafter created, 165 | and to make technical modifications necessary to do so. The 166 | Licensor waives and/or agrees not to assert any right or 167 | authority to forbid You from making technical modifications 168 | necessary to exercise the Licensed Rights, including 169 | technical modifications necessary to circumvent Effective 170 | Technological Measures. For purposes of this Public License, 171 | simply making modifications authorized by this Section 2(a) 172 | (4) never produces Adapted Material. 173 | 174 | 5. Downstream recipients. 175 | 176 | a. Offer from the Licensor -- Licensed Material. Every 177 | recipient of the Licensed Material automatically 178 | receives an offer from the Licensor to exercise the 179 | Licensed Rights under the terms and conditions of this 180 | Public License. 181 | 182 | b. No downstream restrictions. You may not offer or impose 183 | any additional or different terms or conditions on, or 184 | apply any Effective Technological Measures to, the 185 | Licensed Material if doing so restricts exercise of the 186 | Licensed Rights by any recipient of the Licensed 187 | Material. 188 | 189 | 6. No endorsement. Nothing in this Public License constitutes or 190 | may be construed as permission to assert or imply that You 191 | are, or that Your use of the Licensed Material is, connected 192 | with, or sponsored, endorsed, or granted official status by, 193 | the Licensor or others designated to receive attribution as 194 | provided in Section 3(a)(1)(A)(i). 195 | 196 | b. Other rights. 197 | 198 | 1. Moral rights, such as the right of integrity, are not 199 | licensed under this Public License, nor are publicity, 200 | privacy, and/or other similar personality rights; however, to 201 | the extent possible, the Licensor waives and/or agrees not to 202 | assert any such rights held by the Licensor to the limited 203 | extent necessary to allow You to exercise the Licensed 204 | Rights, but not otherwise. 205 | 206 | 2. Patent and trademark rights are not licensed under this 207 | Public License. 208 | 209 | 3. To the extent possible, the Licensor waives any right to 210 | collect royalties from You for the exercise of the Licensed 211 | Rights, whether directly or through a collecting society 212 | under any voluntary or waivable statutory or compulsory 213 | licensing scheme. In all other cases the Licensor expressly 214 | reserves any right to collect such royalties, including when 215 | the Licensed Material is used other than for NonCommercial 216 | purposes. 217 | 218 | 219 | Section 3 -- License Conditions. 220 | 221 | Your exercise of the Licensed Rights is expressly made subject to the 222 | following conditions. 223 | 224 | a. Attribution. 225 | 226 | 1. If You Share the Licensed Material, You must: 227 | 228 | a. retain the following if it is supplied by the Licensor 229 | with the Licensed Material: 230 | 231 | i. identification of the creator(s) of the Licensed 232 | Material and any others designated to receive 233 | attribution, in any reasonable manner requested by 234 | the Licensor (including by pseudonym if 235 | designated); 236 | 237 | ii. a copyright notice; 238 | 239 | iii. a notice that refers to this Public License; 240 | 241 | iv. a notice that refers to the disclaimer of 242 | warranties; 243 | 244 | v. a URI or hyperlink to the Licensed Material to the 245 | extent reasonably practicable; 246 | 247 | b. indicate if You modified the Licensed Material and 248 | retain an indication of any previous modifications; and 249 | 250 | c. indicate the Licensed Material is licensed under this 251 | Public License, and include the text of, or the URI or 252 | hyperlink to, this Public License. 253 | 254 | For the avoidance of doubt, You do not have permission under 255 | this Public License to Share Adapted Material. 256 | 257 | 2. You may satisfy the conditions in Section 3(a)(1) in any 258 | reasonable manner based on the medium, means, and context in 259 | which You Share the Licensed Material. For example, it may be 260 | reasonable to satisfy the conditions by providing a URI or 261 | hyperlink to a resource that includes the required 262 | information. 263 | 264 | 3. If requested by the Licensor, You must remove any of the 265 | information required by Section 3(a)(1)(A) to the extent 266 | reasonably practicable. 267 | 268 | 269 | Section 4 -- Sui Generis Database Rights. 270 | 271 | Where the Licensed Rights include Sui Generis Database Rights that 272 | apply to Your use of the Licensed Material: 273 | 274 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right 275 | to extract, reuse, reproduce, and Share all or a substantial 276 | portion of the contents of the database for NonCommercial purposes 277 | only and provided You do not Share Adapted Material; 278 | 279 | b. if You include all or a substantial portion of the database 280 | contents in a database in which You have Sui Generis Database 281 | Rights, then the database in which You have Sui Generis Database 282 | Rights (but not its individual contents) is Adapted Material; and 283 | 284 | c. You must comply with the conditions in Section 3(a) if You Share 285 | all or a substantial portion of the contents of the database. 286 | 287 | For the avoidance of doubt, this Section 4 supplements and does not 288 | replace Your obligations under this Public License where the Licensed 289 | Rights include other Copyright and Similar Rights. 290 | 291 | 292 | Section 5 -- Disclaimer of Warranties and Limitation of Liability. 293 | 294 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE 295 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS 296 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF 297 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, 298 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, 299 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR 300 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, 301 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT 302 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT 303 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. 304 | 305 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE 306 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, 307 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, 308 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, 309 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR 310 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN 311 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR 312 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR 313 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. 314 | 315 | c. The disclaimer of warranties and limitation of liability provided 316 | above shall be interpreted in a manner that, to the extent 317 | possible, most closely approximates an absolute disclaimer and 318 | waiver of all liability. 319 | 320 | 321 | Section 6 -- Term and Termination. 322 | 323 | a. This Public License applies for the term of the Copyright and 324 | Similar Rights licensed here. However, if You fail to comply with 325 | this Public License, then Your rights under this Public License 326 | terminate automatically. 327 | 328 | b. Where Your right to use the Licensed Material has terminated under 329 | Section 6(a), it reinstates: 330 | 331 | 1. automatically as of the date the violation is cured, provided 332 | it is cured within 30 days of Your discovery of the 333 | violation; or 334 | 335 | 2. upon express reinstatement by the Licensor. 336 | 337 | For the avoidance of doubt, this Section 6(b) does not affect any 338 | right the Licensor may have to seek remedies for Your violations 339 | of this Public License. 340 | 341 | c. For the avoidance of doubt, the Licensor may also offer the 342 | Licensed Material under separate terms or conditions or stop 343 | distributing the Licensed Material at any time; however, doing so 344 | will not terminate this Public License. 345 | 346 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public 347 | License. 348 | 349 | 350 | Section 7 -- Other Terms and Conditions. 351 | 352 | a. The Licensor shall not be bound by any additional or different 353 | terms or conditions communicated by You unless expressly agreed. 354 | 355 | b. Any arrangements, understandings, or agreements regarding the 356 | Licensed Material not stated herein are separate from and 357 | independent of the terms and conditions of this Public License. 358 | 359 | 360 | Section 8 -- Interpretation. 361 | 362 | a. For the avoidance of doubt, this Public License does not, and 363 | shall not be interpreted to, reduce, limit, restrict, or impose 364 | conditions on any use of the Licensed Material that could lawfully 365 | be made without permission under this Public License. 366 | 367 | b. To the extent possible, if any provision of this Public License is 368 | deemed unenforceable, it shall be automatically reformed to the 369 | minimum extent necessary to make it enforceable. If the provision 370 | cannot be reformed, it shall be severed from this Public License 371 | without affecting the enforceability of the remaining terms and 372 | conditions. 373 | 374 | c. No term or condition of this Public License will be waived and no 375 | failure to comply consented to unless expressly agreed to by the 376 | Licensor. 377 | 378 | d. Nothing in this Public License constitutes or may be interpreted 379 | as a limitation upon, or waiver of, any privileges and immunities 380 | that apply to the Licensor or You, including from the legal 381 | processes of any jurisdiction or authority. 382 | 383 | ======================================================================= 384 | 385 | Creative Commons is not a party to its public 386 | licenses. Notwithstanding, Creative Commons may elect to apply one of 387 | its public licenses to material it publishes and in those instances 388 | will be considered the “Licensor.” The text of the Creative Commons 389 | public licenses is dedicated to the public domain under the CC0 Public 390 | Domain Dedication. Except for the limited purpose of indicating that 391 | material is shared under a Creative Commons public license or as 392 | otherwise permitted by the Creative Commons policies published at 393 | creativecommons.org/policies, Creative Commons does not authorize the 394 | use of the trademark "Creative Commons" or any other trademark or logo 395 | of Creative Commons without its prior written consent including, 396 | without limitation, in connection with any unauthorized modifications 397 | to any of its public licenses or any other arrangements, 398 | understandings, or agreements concerning use of licensed material. For 399 | the avoidance of doubt, this paragraph does not form part of the 400 | public licenses. 401 | 402 | Creative Commons may be contacted at creativecommons.org. 403 | 404 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Libro Programacion en C para Principiantes 2 | 3 | Licencia Creative Commons
Esta obra está bajo una Licencia Creative Commons Atribución-NoComercial-SinDerivadas 4.0 Internacional. 4 | 5 | Este es un libro de programación en C escrito por mí (Gorka Urrutia Landa) en el año 1999. Desde entonces he ido haciendo algunas revisiones. Este libro ha estado a la venta en Amazon durante varios años pero ahora lo pongo a la disposición de todo el mundo de manera gratuita. 6 | 7 | Si quieres participar en el libro simplemente haz un "pull request" y envía los cambios. 8 | 9 | Si lo único que quieres es decargar el libro símpemente busca el archivo "book.pdf". 10 | 11 | Para preguntas con respecto al contenido del libro puedes entrar en [la sección de consultas sobre el libro de C](https://elrincondelc.com/foros/viewforum.php?f=11). O los foros sobre C del [Rincón del C](https://elrincondelc.com/foros). 12 | 13 | ## Preguntas/comentarios frecuentes 14 | 15 | ### ¿Cómo me descargo el libro? 16 | 17 | Directo al grano ¿eh? Si lo que quieres es descargar el libro y no tienes interés en colaborar mejorándolo simplemente usa este enlace: 18 | 19 | [Pincha aquí para descargar el libro](https://github.com/gorkau/Libro-Programacion-en-C/blob/master/programacion-c-principiantes-gorka-urrutia.pdf) 20 | 21 | Ahora bien, si el libro te gusta y quieres que sea mejor puedes colaborar. 22 | 23 | ### ¡El formato es horrible! 24 | 25 | ¡Pues claro! Estamos en ello. Quéjate menos y colabora más. Tienes el código fuente del libro para ir descargándolo y editándolo. 26 | 27 | ### ¿Puedo colaborar? 28 | 29 | ¡Claro! Ni siquiera hace falta que sepas de C. En la primera fase vamos a ponerlo en un formato "bonito". 30 | 31 | ### ¿Cómo puedo colaborar? 32 | 33 | * Avisando si has visto algún error. 34 | * Ayudar dando formato al libro. Estoy usando [AsciiDoctor](https://asciidoctor.org/). Es muy fácil de usar. 35 | * Sugiriendo nuevas secciones o cambiando cosas que consideres que están mal explicadas. 36 | * Actualizando los contenidos del libro. El libro lo escribí allá por el 1999 y muchas cosas han cambiado. Convendría darle un repaso, por ejemplo a capítulo de tipos de datos. 37 | 38 | ### ¿Qué herramientas/conocimientos necesito para colaborar? 39 | 40 | * Para editar los textos te vale cualquier editor de texto plano. Yo uso Atom pero puedes usar el que prefieras. 41 | * Para "compilar" el libro necesitarás AsciiDoctor. 42 | 43 | En cuanto a conocimientos necesitarás conocer un poco de [AsciiDoctor](https://asciidoctor.org/). Es un formato muy sencillo similar al MarkDown que se usa en GitHub. 44 | 45 | # Instrucciones para colaboradores 46 | 47 | ## Normas de estilo 48 | 49 | ### Cada frase en una línea 50 | 51 | En lugar de: 52 | 53 | ``` 54 | Es mejor poner cada frase en una línea. De esta forma se identifican de manera rápida las frases excesivamente largas o párrafos muy farragosos. ¿No crees? 55 | ``` 56 | Creo que es mejor así: 57 | 58 | ``` 59 | Es mejor poner cada frase en una línea. 60 | De esta forma se identifican de manera rápida las frases excesivamente largas o párrafos muy farragosos. 61 | ¿No crees? 62 | ``` 63 | 64 | ### Código 65 | 66 | Todos los bloques de código (y las líneas de código sueltas) deben ir dentro de un bloque: 67 | 68 | ``` 69 | [source,c] 70 | ---- 71 | // Aquí dentro va el código 72 | ---- 73 | ``` 74 | 75 | La salida de un programa (lo que se mostraría en la pantalla) se debe encerrar entre los símbolos: 76 | 77 | ``` 78 | ---- 79 | Ejemplo de la salida de un programa. 80 | ---- 81 | ``` 82 | 83 | Si la salida consiste en una única línea bastará con poner un espacio al principio de la misma. 84 | 85 | ## Estado 86 | 87 | * [13/10/2019] Añadido el capítulo 10 y mejoras en el formato del 9. 88 | * [14/09/2018] Subido hasta el capítulo 6. 89 | * [08/09/2018] Subido hasta el capítulo 5. Mejoras en el formato del capítulo 1. 90 | * [22/07/2018] Ya he subido hasta el capítulo 3. La mitad del capítulo está con un formato bastante feo. 91 | * [15/07/2018] Por ahora sólo está listo el capítulo 1 con un formato horrible. 92 | -------------------------------------------------------------------------------- /book.adoc: -------------------------------------------------------------------------------- 1 | Programación en C para principiantes 2 | ==================================== 3 | Gorka Urrutia 4 | :doctype: book 5 | :source-highlighter: coderay 6 | :author: Gorka Urrutia 7 | :toc: right 8 | :icons: font 9 | :ascii-ids: 10 | 11 | include::capitulo01.adoc[] 12 | include::capitulo02.adoc[] 13 | include::capitulo03.adoc[] 14 | include::capitulo04.adoc[] 15 | include::capitulo05.adoc[] 16 | include::capitulo06.adoc[] 17 | include::capitulo07.adoc[] 18 | include::capitulo08.adoc[] 19 | include::capitulo09.adoc[] 20 | include::capitulo10.adoc[] 21 | -------------------------------------------------------------------------------- /capitulo01.adoc: -------------------------------------------------------------------------------- 1 | //// 2 | Copyright: Gorka Urrutia Landa, 1999-2018 3 | Licencia: Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) https://creativecommons.org/licenses/by-sa/4.0/ 4 | //// 5 | 6 | :chapter: 001 7 | :Cmasmas: C++ 8 | <<< 9 | 10 | == Capítulo 1. Introducción. 11 | 12 | === Sobre el libro 13 | 14 | Este es un curso para principiantes así que intentaré que no haga falta ningún conocimiento anterior para seguirlo. 15 | Muchos otros cursos suponen conocimientos previos pero voy a intentar que eso no suceda aquí. 16 | 17 | NOTA IMPORTANTE: Si te pierdes no te desanimes, ponte en contacto conmigo y consúltame (al final del libro tienes varias formas para contactarme). 18 | Puede que alguna sección esté mal explicada. De esta forma estarás colaborando a mejorar el libro. 19 | 20 | === Cómo resolver tus dudas 21 | 22 | En la última sección del libro podrás encontrar varias formas de contactar conmigo (email, Twitter, mi blog, etc). 23 | 24 | === El lenguaje C 25 | 26 | El lenguaje C es uno de los más rápidos y potentes que hay hoy en día. Hay quien dice que está desfasado. No se si tendrá futuro pero está claro que presente si tiene. No hay más que decir que el sistema operativo Linux está desarrollado en C en su práctica totalidad. Así que creo que no sólo no perdemos nada aprendiéndolo sino que ganamos mucho. Para empezar nos servirá como base para aprender C++ e introducirnos en el mundo de la programación Windows. Si optamos por Linux existe una biblioteca llamada gtk (o librería, como prefieras) que permite desarrollar aplicaciones estilo Windows con C. 27 | 28 | No debemos confundir C con {Cmasmas}, que no son lo mismo. Se podría decir que {Cmasmas} es una extensión de C. 29 | Para empezar en {Cmasmas} conviene tener una sólida base de C. 30 | Existen otros lenguajes como Visual Basic que son muy sencillos de aprender y de utilizar. 31 | Nos dan casi todo hecho. 32 | Pero cuando queremos hacer algo complicado o que sea rápido debemos recurrir a otros lenguajes ({Cmasmas}, Delphi,...). 33 | 34 | === Peculiaridades de C 35 | 36 | Una de las cosas importantes de C que debes recordar es que es Case Sensitive (sensible a las mayúsculas o algo así). Es decir que para C no es lo mismo escribir Printf que printf. 37 | Conviene indicar también que las instrucciones se separan por ";". 38 | 39 | === Compiladores de C 40 | 41 | Un compilador es un programa que convierte nuestro código fuente en un programa ejecutable (me imagino que la mayoría ya lo sabéis pero más vale asegurar). 42 | El ordenador trabaja con 0 y 1. 43 | Si escribiéramos un programa en el lenguaje del ordenador nos volveríamos locos. Para eso están lenguajes como el C. 44 | Nos permiten escribir un programa de manera que sea fácil entenderlo por una persona (el código fuente). 45 | Luego es el compilador el que se encarga de convertirlo al complicado idioma de un ordenador. 46 | 47 | En la practica a la hora de crear un programa nosotros escribimos el código fuente, en nuestro caso en C, que normalmente será un fichero de texto normal y corriente que contiene las instrucciones de nuestro programa. 48 | Luego se lo pasamos al compilador y este se encarga de convertirlo en un programa. 49 | 50 | Si tenemos el código fuente podemos modificar el programa tantas veces como queramos (sólo tenemos que volver a compilarlo), pero si tenemos el ejecutable final no podremos cambiar nada (realmente sí se puede pero es mucho más complicado y requiere más conocimientos). 51 | 52 | Existen multitud de compiladores. 53 | Yo suelo recomendar el Geany y Code::Blocks, que tiene versiones tanto para Linux como para Windows. 54 | Estos programas usan el compilador GNU GCC (http://gcc.gnu.org) y se pueden descargar aquí: 55 | 56 | * Geany - http://www.geany.org/ 57 | * Code::Blocks - http://www.codeblocks.org/ 58 | 59 | Nota: Cuando comencé a escribir el curso solía usar el DJGPP en Windows, sin embargo, ahora me decanto más bien por el Geany por la comodidad y facilidad que supone para los principiantes. 60 | 61 | === El editor de código fuente 62 | 63 | El compilador en sí mismo sólo es un programa que traduce nuestro código fuente y lo convierte en un ejecutable. Para escribir nuestros programas necesitamos un editor. La mayoría de los compiladores al instalarse incorporan ya un editor; es el caso de los conocidos Turbo C, Borland C, Code::Blocks, Visual C++,... Pero otros no lo traen por defecto. No debemos confundir por tanto el editor con el compilador. 64 | Estos editores suelen tener unas características que nos facilitan mucho el trabajo: permiten compilar y ejecutar el programa directamente, depurarlo (corregir errores), gestionar complejos proyectos, etc. 65 | Si nuestro compilador no trae editor la solución más simple usar un editor de texto plano (sin formato). 66 | 67 | === IDE: Entorno de desarrollo integrado 68 | 69 | Para la comodidad de los desarrolladores se crearon lo que se llaman Entornos de Desarrollo Integrado (en inglés IDE). Un IDE es un software que incluye todo lo necesario para la programación: un compilador (con todos sus programas accesorios), un editor con herramientas que ayudan en la creación de programas, un depurador para buscar errores, etc... Es la solución más completa y recomendada. 70 | 71 | Existen multitud de IDE que puedes utilizar. Geany y Code::Blocks anteriormente mencionados son muy recomendables en entornos MS Windows, para Linux tenemos montones de opciones, como el Geany, Anjuta o el Kdevelop. 72 | 73 | === El primer programa: Hola Mundo 74 | 75 | En un alarde de originalidad vamos a hacer nuestro primer programa: hola mundo. Nadie puede llegar muy lejos en el mundo de la programación sin haber empezado su carrera con este original y funcional programa. Allá va: 76 | 77 | [source,c] 78 | ---- 79 | #include 80 | #include 81 | 82 | int main() 83 | { 84 | /* Aquí va el cuerpo del programa */ 85 | printf("Hola mundo\n"); 86 | return EXIT_SUCCESS; 87 | } 88 | ---- 89 | 90 | .Si trabajas en Windows 91 | [NOTE] 92 | ==== 93 | Hay mucha gente que programa en Windows que se queja de que cuando ejecuta el programa no puede ver el resultado. 94 | Para evitarlo se puede añadir antes de return 0; la siguiente línea: 95 | 96 | [source,c] 97 | ---- 98 | system("PAUSE"); 99 | ---- 100 | 101 | Si esto no funciona prueba a añadir getch(); 102 | 103 | Otra nota: En compiladores MS Windows, para poder usar la función _system()_ debes añadir al principio del fichero la línea: 104 | 105 | [source,c] 106 | ---- 107 | #include 108 | ---- 109 | ==== 110 | 111 | Este programa lo único que hace es sacar por pantalla el mensaje: 112 | 113 | ---- 114 | Hola mundo 115 | ---- 116 | 117 | Vamos ahora a comentar el programa línea por línea (Esto no va a ser más que una primera aproximación). 118 | 119 | [source,c] 120 | ---- 121 | #include 122 | #include 123 | ---- 124 | 125 | #include es lo que se llama una directiva. 126 | Sirve para indicar al compilador que incluya otro archivo. 127 | Cuando en compilador se encuentra con esta directiva la sustituye por el archivo indicado. 128 | En este caso son los archivos _stdio.h_ (que es donde está definida la función printf, que veremos luego) y _stdlib.h_. 129 | 130 | [source,c] 131 | ---- 132 | int main() 133 | ---- 134 | 135 | Es la *_función_* principal del programa. 136 | Todos los programas de C deben tener una función llamada _main_, que es la que primero se ejecuta. 137 | 138 | El _int_ (viene de Integer=Entero) que tiene al principio significa que cuando la función main acabe devolverá un número entero. 139 | Este valor se suele usar para saber cómo ha terminado el programa. 140 | Normalmente este valor será 0 si todo ha ido bien, o un valor distinto si se ha producido algún error (pero esto lo decidimos nosotros, ya lo veremos). 141 | De esta forma si nuestro programa se ejecuta desde otro el programa 'padre' sabe como ha finalizado, si ha habido errores o no. 142 | 143 | Se puede usar la definición: 144 | 145 | [source,c] 146 | ---- 147 | void main() 148 | ---- 149 | 150 | que no necesita devolver ningún valor, pero se recomienda la forma con 'int' que es más correcta. 151 | Es posible que veas muchos ejemplos que uso 'void main' y en los que falta el return 0; del final; el código funciona correctamente pero puede dar un 'warning' (un aviso) al compilar dado que no es una práctica correcta. 152 | 153 | [source,c] 154 | ---- 155 | {} 156 | ---- 157 | 158 | Las _llaves_ indican, entre otras cosas, el comienzo y el final de una función; en este caso la función _main_. 159 | 160 | [source,c] 161 | ---- 162 | /* Aquí va el cuerpo del programa */ 163 | ---- 164 | 165 | Esto es un comentario, el compilador lo ignorará. 166 | Sirve para describir el programa a otros desarrolladores o a nosotros mismos para cuando volvamos a ver el código fuente dentro de un tiempo. 167 | Conviene acostumbrarse a comentar los programas pero sin abusar de ellos (ya hablaremos sobre esto más adelante). 168 | 169 | Los comentarios van encerrados entre /* y */. 170 | 171 | Un comentario puede ocupar más de una línea. Por ejemplo el comentario: 172 | 173 | [source,c] 174 | ---- 175 | /* Este es un comentario 176 | que ocupa dos filas */ 177 | ---- 178 | 179 | es perfectamente válido. 180 | 181 | [source,c] 182 | ---- 183 | printf( "Hola mundo\n" ); 184 | ---- 185 | 186 | Aquí es donde por fin el programa hace algo que podemos ver al ejecutarlo. 187 | La función *_printf_* muestra un mensaje por la pantalla. 188 | 189 | Al final del mensaje "Hola mundo" puedes ver el símbolo '\n'. 190 | Éste hace que después de imprimir el mensaje se pase a la línea siguiente. Por ejemplo: 191 | 192 | [source,c] 193 | ---- 194 | printf( "Hola mundo\nAdiós mundo" ); 195 | ---- 196 | 197 | mostrará: 198 | 199 | ---- 200 | Hola mundo 201 | Adiós mundo 202 | ---- 203 | 204 | Fíjate en el ";" del final. 205 | Es la forma que se usa en C para separar una instrucción de otra. 206 | Se pueden poner varias en la misma línea siempre que se separen por el punto y coma. 207 | 208 | [source,c] 209 | ---- 210 | return EXIT_SUCCESS; 211 | ---- 212 | 213 | Como he indicado antes el programa al finalizar develve un valor entero. 214 | Este valor se devuelve usando *_return_*. 215 | El valor devuelto será el que pongamos después de _return_. 216 | 217 | En este caso el valor que devolvemos es _EXIT_SUCCESS_, que es una *_constante_* (un valor predefinido que no cambia) que tiene el valor 0. 218 | 219 | .¿De dónse sale EXIT_SUCCESS? 220 | NOTE: El valor de EXIT_SUCCESS está definido en el fichero _stdlib.h_. 221 | 222 | ¿Y por qué no poner return 0 en lugar de return EXIT_SUCCESS? 223 | 224 | Sería perfectamente válido usar un 0 en lugar de EXIT_SUCCESS, pero el programa se entiende mejor usando esta última. 225 | Cuando lees esa línea ya entiendes, sin ninguna duda, que el programa está termiando con éxito. 226 | 227 | ...y por fin cerramos llaves con lo que termina el programa. 228 | Todos los programas finalizan cuando se llega al final de la función _main_. 229 | 230 | === ¿Cómo se hace? 231 | 232 | Primero debemos crear el código fuente del programa. 233 | Para nuestro primer programa el código fuente es el del listado anterior. 234 | 235 | .Arranca tu entorno de desarrollo de C, sea cual sea. 236 | .Crea un nuevo fichero y copia el código anterior. 237 | .Llámalo, por ejemplo, primero.c. 238 | .Ahora, tenemos que compilar el programa para crear el ejecutable. 239 | .Si estás usando un IDE busca una opción llamada "compile", o make, build o algo así. 240 | 241 | Si estamos usando el compilador *_gcc_* sin IDE tenemos que llamarlo desde la línea de comando: 242 | 243 | ---- 244 | gcc primero.c -o primero 245 | ---- 246 | 247 | === Nota adicional sobre los comentarios 248 | 249 | Los comentarios se pueden poner casi en cualquier parte. Excepto en medio de una instrucción. Por ejemplo lo siguiente no es válido: 250 | 251 | [source,c] 252 | ---- 253 | pri/* Esto es un comentario */ntf( "Hola mundo" ); 254 | ---- 255 | 256 | No podemos cortar a printf por en medio, tendríamos un error al compilar. Lo siguiente puede no dar un error, pero es una fea costumbre: 257 | 258 | [source,c] 259 | ---- 260 | printf( /* Esto es un comentario */ "Hola mundo" ); 261 | ---- 262 | 263 | Y por último tenemos: 264 | 265 | [source,c] 266 | ---- 267 | printf( "Hola/* Esto es un comentario */ mundo" ); 268 | ---- 269 | 270 | Que no daría error, pero al ejecutar tendríamos: 271 | 272 | ---- 273 | Hola /* Esto es un comentario */ mundo 274 | ---- 275 | 276 | porque /* Esto es un comentario */ queda dentro de las comillas y C lo interpreta como texto, no como un comentario. 277 | 278 | === ¿Qué sabemos hacer? 279 | 280 | Pues la verdad es que todavía no hemos aprendido mucho. 281 | Lo único que podemos hacer es compilar nuestros programas. 282 | Pero paciencia, en seguida avanzaremos. 283 | 284 | === Ejercicios 285 | 286 | Busca los errores en este programa: 287 | 288 | [source,c] 289 | ---- 290 | int main() 291 | { 292 | /* Aquí va el cuerpo del programa */ 293 | Printf( "Hola mundo\n" ); 294 | return 0; 295 | } 296 | ---- 297 | 298 | Solución: 299 | 300 | Si lo compilamos obtendremos un error que nos indicará que no hemos definido la función 'Printf'. 301 | Esto es porque no hemos incluído la dichosa directiva '#include '. 302 | 303 | NOTE: En algunos compiladores no es necesario incluir esta directiva, pero es una buena costumbre hacerlo. 304 | 305 | Si lo corregimos y volvemos a compilar obtendremos un nuevo error. 306 | Otra vez nos dice que desconoce 'Printf'. 307 | Esta vez el problema es el de las mayúsculas que hemos indicado antes. 308 | Lo correcto es poner _printf_ con minúsculas. 309 | 310 | Te habrás fijado que en esta ocasión hemos usado _return 0_ en lugar de _return EXIT_SUCCESS_. 311 | En realidad ambas son equivalentes puesto que _EXIT_SUCCESS_ tiene el valor 0. 312 | 313 | === ¿Dudas? 314 | 315 | Si tienes dudas sobre este capítulo plantéalas en el foro: 316 | 317 | https://elrincondelc.com/foros/viewforum.php?f=47 318 | 319 | === ¿Has visto un error? 320 | 321 | Si has encontrado algún error o quieres sugerir cambios entra aquí: 322 | 323 | https://github.com/gorkau/Libro-Programacion-en-C/blob/master/capitulo1.adoc 324 | -------------------------------------------------------------------------------- /capitulo02.adoc: -------------------------------------------------------------------------------- 1 | //// 2 | Copyright: Gorka Urrutia Landa, 1999-2018 3 | Licencia: Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) https://creativecommons.org/licenses/by-sa/4.0/ 4 | //// 5 | 6 | :chapter: 002 7 | 8 | <<< 9 | 10 | == Capítulo 2. Mostrando Información por pantalla. 11 | 12 | === Printf: Imprimir en pantalla 13 | 14 | Siempre he creído que cuando empiezas con un nuevo lenguaje suele gustar el ver los resultados, ver que nuestro programa hace 'algo'. 15 | Por eso creo que el curso debe comenzar con la función *_printf_*, que sirve para sacar información por pantalla. 16 | Para utilizar la función _printf_ en nuestros programas debemos incluir la directiva: 17 | 18 | [source,c] 19 | ---- 20 | #include 21 | ---- 22 | 23 | al principio de programa. 24 | Como hemos visto en el programa hola mundo. 25 | Si sólo queremos imprimir una cadena basta con hacer (no olvides el ";" al final): 26 | 27 | [source,c] 28 | ---- 29 | printf( "Cadena" ); 30 | ---- 31 | 32 | Esto resultará por pantalla: 33 | 34 | ---- 35 | Cadena 36 | ---- 37 | 38 | Lo que pongamos entre las comillas es lo que vamos a sacar por pantalla. 39 | Si volvemos a usar otro _printf_, por ejemplo: 40 | 41 | [source,c] 42 | ---- 43 | #include 44 | int main() { 45 | printf( "Cadena" ); 46 | printf( "Segunda" ); 47 | return 0; 48 | } 49 | ---- 50 | 51 | Obtendremos: 52 | 53 | ---- 54 | CadenaSegunda 55 | ---- 56 | 57 | Este ejemplo nos muestra cómo funciona printf. Para escribir en la pantalla se usa un cursor que no vemos. Cuando escribimos algo el cursor va al final del texto. Cuando el texto llega al final de la fila, lo siguiente que pongamos irá a la fila siguiente. Si lo que queremos es sacar cada una en una línea deberemos usar "\n". Es el indicador de retorno de carro. Lo que hace es saltar el cursor de escritura a la línea siguiente: 58 | 59 | [source,c] 60 | ---- 61 | #include 62 | 63 | int main() 64 | { 65 | printf( "Cadena\n" ); 66 | printf( "Segunda" ); 67 | return 0; 68 | } 69 | ---- 70 | 71 | y tendremos: 72 | 73 | ---- 74 | Cadena 75 | Segunda 76 | ---- 77 | 78 | También podemos poner más de una cadena dentro del printf: 79 | 80 | [source,c] 81 | ---- 82 | printf( "Primera cadena" "Segunda cadena" ); 83 | ---- 84 | 85 | Lo que no podemos hacer es meter cosas entre las cadenas: 86 | 87 | [source,c] 88 | ---- 89 | printf( "Primera cadena" texto en medio "Segunda cadena" ); 90 | ---- 91 | 92 | esto no es válido. Cuando el compilador intenta interpretar esta sentencia se encuentra _"Primera cadena"_ y luego texto en medio, no sabe qué hacer con ello y da un error. 93 | Pero ¿qué pasa si queremos imprimir el símbolo _"_ en pantalla? Por ejemplo imaginemos que queremos escribir: 94 | 95 | ---- 96 | Esto es "raro" 97 | ---- 98 | 99 | Si hacemos: 100 | 101 | [source,c] 102 | ---- 103 | printf( "Esto es "raro"" ); 104 | ---- 105 | 106 | obtendremos unos cuantos errores. 107 | El problema es que el símbolo " se usa para indicar al compilador el comienzo o el final de una cadena. 108 | Así que en realidad le estaríamos dando la cadena "Esto es", luego extraño y luego otra cadena vacía "". 109 | Pues resulta que _printf_ no admite esto y de nuevo tenemos errores. 110 | 111 | La solución es usar \". Veamos: 112 | 113 | [source,c] 114 | ---- 115 | printf( "Esto es \"extraño\"" ); 116 | ---- 117 | 118 | Esta vez todo irá como la seda. 119 | Como vemos la contrabarra '\' sirve para indicarle al compilador que escriba caracteres que de otra forma no podríamos. 120 | Esta contrabarra se usa en C para indicar al compilador que queremos meter símbolos especiales. 121 | Pero ¿Y si lo que queremos es usar '\' como un carácter normal y poner por ejemplo Hola\Adiós? Pues muy fácil, volvemos a usar '\': 122 | 123 | [source,c] 124 | ---- 125 | printf( "Hola\\Adiós" ); 126 | ---- 127 | 128 | y esta doble '\' indica a C que lo que queremos es mostrar una '\'. 129 | He aquí un breve listado de códigos que se pueden imprimir: 130 | 131 | Código 132 | Nombre 133 | Significado 134 | \a 135 | alert 136 | Hace sonar un pitido 137 | \b 138 | backspace 139 | Retroceso 140 | \n 141 | newline 142 | Salta a la línea siguiente (salto de línea) 143 | \r 144 | carriage return 145 | Retorno de carro (similar al anterior) 146 | \t 147 | horizontal tab 148 | Tabulador horizontal 149 | \v 150 | vertical tab 151 | Tabulador vertical 152 | \\ 153 | backslash 154 | Barra invertida 155 | \? 156 | question mark 157 | Signo de interrogación 158 | \' 159 | single quote 160 | Comilla sencilla 161 | \" 162 | double quote 163 | Comilla doble 164 | 165 | Es recomendable probarlas para ver realmente lo que significa cada una. 166 | 167 | Esto no ha sido mas que una introducción a printf. Luego volveremos sobre ella. 168 | 169 | === Gotoxy: Posicionando el cursor (requiere conio.h) 170 | Esta función sólo está disponible en compiladores de C que dispongan de la biblioteca , de hecho, en la mayoría de compiladores para Linux no viene instalada por defecto. 171 | No debería usarse aunque se menciona aquí porque en muchos cursos de formación profesional y en universidades aún se usa. 172 | Hemos visto que cuando usamos printf se escribe en la posición actual del cursor y se mueve el cursor al final de la cadena que hemos escrito. 173 | 174 | Vale, pero ¿qué pasa cuando queremos escribir en una posición determinada de la pantalla? La solución está en la función gotoxy. Supongamos que queremos escribir 'Hola' en la fila 10, columna 20 de la pantalla: 175 | 176 | [source,c] 177 | ---- 178 | #include 179 | #include 180 | 181 | int main() 182 | { 183 | gotoxy( 20, 10 ); 184 | printf( "Hola" ); 185 | return 0; 186 | } 187 | ---- 188 | 189 | NOTE: para usar gotoxy hay que incluir la biblioteca conio.h). 190 | 191 | Fíjate que primero se pone la columna (x) y luego la fila (y). La esquina superior izquierda es la posición (1, 1). 192 | 193 | === Clrscr: Borrar la pantalla (requiere conio.h) 194 | 195 | Ahora ya sólo nos falta saber cómo se borra la pantalla. Pues es tan fácil como usar: 196 | 197 | [source,c] 198 | ---- 199 | clrscr(); 200 | ---- 201 | 202 | (clear screen, borrar pantalla). 203 | 204 | Esta función nó solo borra la pantalla, sino que además sitúa el cursor en la posición (1, 1), en la esquina superior izquierda. 205 | 206 | [source,c] 207 | ---- 208 | #include 209 | #include 210 | 211 | int main() 212 | { 213 | clrscr(); 214 | printf( "Hola" ); 215 | return 0; 216 | } 217 | ---- 218 | 219 | Este método sólo vale para compiladores que incluyan el fichero conio.h. Si tu sistema no lo tiene puedes consultar la sección siguiente. 220 | 221 | === Borrar la pantalla (otros métodos) 222 | 223 | Existen otras formas de borrar la pantalla aparte de usar conio.h. 224 | 225 | Si usas DOS: 226 | 227 | system ("cls"); //Para DOS 228 | 229 | Si usas Linux: 230 | 231 | system ("clear"); // Para Linux 232 | 233 | Otra forma válida para ambos sistemas: 234 | 235 | char a[5]={27,'[','2','J',0}; /* Para ambos (en DOS cargando antes ansi.sys) */ 236 | printf("%s",a); 237 | 238 | === ¿Qué sabemos hacer? 239 | Bueno, ya hemos aprendido a sacar información por pantalla. 240 | Si quieres puedes practicar con las instrucciones printf, gotoxy y clrscr. 241 | Lo que hemos visto hasta ahora no tiene mucho secreto, pero ya veremos cómo la función printf tiene mayor complejidad. 242 | 243 | === Ejercicios 244 | 245 | *Ejercicio 1:* Busca los errores en el programa (este programa usa conio.h, pero aunque tu compilador no la incluya aprenderás algo con este ejercicio). 246 | 247 | [source,c] 248 | ---- 249 | #include 250 | int main() 251 | { 252 | ClrScr(); 253 | gotoxy( 10, 10 ) 254 | printf( Estoy en la fila 10 columna 10 ); 255 | return 0; 256 | } 257 | ---- 258 | 259 | Solución: 260 | 261 | ClrScr está mal escrito, debe ponerse todo en minúsculas, recordemos una vez más que el C diferencia las mayúsculas de las minúsculas. Además no hemos incluído la directiva #include , que necesitamos para usar clrscr() y gotoxy(). 262 | Tampoco hemos puesto el punto y coma (;) después del gotoxy( 10, 10 ). Después de cada instrucción debe ir un punto y coma. 263 | El último fallo es que el texto del printf no lo hemos puesto entre comillas. Lo correcto sería: printf( "Estoy en la fila 10 columna 10" ); 264 | 265 | *Ejercicio 2:* Escribe un programa que borre la pantalla y escriba en la primera línea tu nombre y en la segunda tu apellido: 266 | 267 | Solución: 268 | 269 | [source,c] 270 | ---- 271 | #include 272 | #include 273 | int main() 274 | { 275 | clrscr(); 276 | printf( "Gorka\n" ); 277 | printf( "Urrutia" ); 278 | return 0; 279 | } 280 | ---- 281 | 282 | También se podía haber hecho todo de golpe: 283 | 284 | [source,c] 285 | ---- 286 | #include 287 | #include 288 | int main() 289 | { 290 | clrscr(); 291 | printf( "Gorka\nUrrutia" ); 292 | return 0; 293 | } 294 | ---- 295 | 296 | *Ejercicio 3:* Escribe un programa que borre la pantalla y muestre el texto "estoy aqui" en la fila 10, columna 20 de la pantalla. 297 | 298 | Solución: 299 | 300 | [source,c] 301 | ---- 302 | #include 303 | #include 304 | int main() { 305 | clrscr(); 306 | gotoxy( 20, 10 ); 307 | printf( "Estoy aqui" ); 308 | return 0; 309 | } 310 | ---- 311 | -------------------------------------------------------------------------------- /capitulo03.adoc: -------------------------------------------------------------------------------- 1 | //// 2 | Copyright: Gorka Urrutia Landa, 1999-2018 3 | Licencia: Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) https://creativecommons.org/licenses/by-sa/4.0/ 4 | //// 5 | 6 | :chapter: 003 7 | 8 | <<< 9 | 10 | == Capítulo 3. Tipos de Datos. 11 | 12 | === Introducción 13 | 14 | Cuando usamos un programa es muy importante manejar datos. 15 | En C podemos almacenar los datos en variables. 16 | Una variable es una porción de la memoria del ordenador que queda asignada para que nuestro programa pueda almacenar datos. 17 | El contenido de las variables se puede ver o cambiar en cualquier momento. 18 | Estas variables pueden ser de distintos tipos dependiendo del tipo de dato que queramos meter. 19 | No es lo mismo guardar un nombre que un número. 20 | 21 | Hay que recordar también que la memoria del ordenador es limitada, así que cuando guardamos un dato, debemos usar sólo la memoria necesaria. 22 | Por ejemplo si queremos almacenar el número 400 usaremos una variable tipo _int_ (la estudiamos más abajo) que ocupa menos memoria que una variable de tipo _float_. 23 | Si tenemos un ordenador con 32Mb de RAM parece una tontería ponernos a ahorrar bits (1Mb=1024Kb, 1Kb=1024bytes, 1byte=8bits), pero si tenemos un programa que maneja muchos datos puede no ser una cantidad despreciable. 24 | Además ahorrar memoria es una buena costumbre. 25 | 26 | NOTE: Por si alguno tiene dudas: No hay que confundir la memoria con el espacio en el disco duro. 27 | Son dos cosas distintas. 28 | La capacidad de ambos se mide en bytes, y la del disco duro suele ser mayor que la de la memoria RAM. 29 | La información en la RAM se pierde al apagar el ordenador, la del disco duro permanece. 30 | Cuando queremos guardar un fichero lo que necesitamos es espacio en el disco duro. 31 | Cuando queremos ejecutar un programa lo que necesitamos es memoria RAM. 32 | La mayoría me imagino que ya lo sabéis, pero me he encontrado muchas veces con gente que los confunde). 33 | 34 | === Notas sobre los nombres de las variables 35 | 36 | A las variables no se les puede dar cualquier nombre pero siguiendo unas sencillas normas: 37 | 38 | * No se pueden poner más que letras de la 'a' a la 'z' (la ñ no vale), números y el símbolo '_'. 39 | * No se pueden poner signos de admiración, ni de interrogación... 40 | * El nombre de una variable puede contener números, pero su primer carácter no puede ser un número. 41 | 42 | Ejemplos de nombres válidos: 43 | 44 | * camiones 45 | * numero 46 | * buffer 47 | * a1 48 | * j10hola29 49 | * num_alumnos 50 | 51 | Ejemplos de nombres no válidos: 52 | 53 | * 1abc 54 | * nombre? 55 | * número 56 | * num/alumnos 57 | 58 | Tampoco valen como nombres de variable las palabras reservadas que usa el compilador. Por ejemplo: for, main, do, while. 59 | Lista de palabras reservadas según el estándar ISO-C90: 60 | 61 | ---- 62 | auto double int struct 63 | break else long switch 64 | case enum register typedef 65 | char extern return union 66 | const float short unsigned 67 | continue for signed void 68 | default goto sizeof volatile 69 | do if static while 70 | ---- 71 | 72 | Por último es interesante señalar que el C distingue entre mayúsculas y minúsculas. 73 | Por lo tanto: 74 | 75 | * Nombre 76 | * nombre 77 | * NOMBRE 78 | 79 | serían tres variables distintas. 80 | 81 | === El tipo Int 82 | 83 | En una variable de este tipo se almacenan números enteros (sin decimales). 84 | El rango de valores que admite es -32.768 a 32.767. 85 | 86 | NOTE: Nota importante: el rango indicado (de -32.768 a 32.767) puede variar de un compilador a otro, en este caso sería un compilador donde el tipo int es de 16 bits. 87 | 88 | ¿Por qué estos números tan extraños? Esto se debe a los 16 bits mencionados. 89 | 2^16 = 65.536, que dividido por dos nos da 32.768. 90 | Por lo tanto, en una variable de este tipo podemos almacenar números negativos desde el -32.768 hasta el -1 y números desde el 0 hasta el 32.767. 91 | 92 | Cuando definimos una variable lo que estamos haciendo es decirle al compilador que nos reserve una zona de la memoria para almacenar datos de tipo _int_. 93 | Para guardarla necesitaremos por tanto 16 bits de la memoria del ordenador. 94 | 95 | Las variables de tipo int se definen así: 96 | 97 | [source,c] 98 | ---- 99 | int número; 100 | ---- 101 | 102 | Esto hace que declaremos una variable llamada número que va a contener un número entero. 103 | 104 | ==== ¿Pero dónde se declaran las variables? 105 | 106 | Tenemos dos posibilidades, una es declararla como global y otra como local. Por ahora vamos a decir que global es aquella variable que se declara fuera de la función main y local la que se declara dentro. 107 | 108 | Variable global: 109 | 110 | [source,c] 111 | ---- 112 | #include 113 | #include 114 | 115 | int x; 116 | int main() 117 | { 118 | } 119 | ---- 120 | 121 | Variable local: 122 | 123 | [source,c] 124 | ---- 125 | #include 126 | #include 127 | 128 | int main() 129 | { 130 | int x; 131 | } 132 | ---- 133 | 134 | La diferencia práctica es que las variables globales se pueden usar en cualquier función (o procedimiento). Las variables locales sólo pueden usarse en el procedimiento en el que se declaran. Como por ahora sólo tenemos el procedimiento (o función, o rutina, o subrutina, como prefieras) main esto no debe preocuparnos mucho por ahora. Cuando estudiemos cómo hacer un programa con más funciones aparte de main volveremos sobre el tema. Sin embargo debes saber que es buena costumbre usar variables locales que globales. Ya veremos por qué. 135 | 136 | Podemos declarar más de una variable en una sola línea: 137 | 138 | [source,c] 139 | ---- 140 | int x, y; 141 | ---- 142 | 143 | ==== Mostrar variables por pantalla 144 | 145 | Vamos a ir un poco más allá con la función _printf_. 146 | Supongamos que queremos mostrar el contenido de la variable x por pantalla: 147 | 148 | [source,c] 149 | ---- 150 | printf( "%i", x ); 151 | ---- 152 | 153 | Suponiendo que x valga 10 (x=10) en la pantalla tendríamos: 154 | 155 | ---- 156 | 10 157 | ---- 158 | 159 | Empieza a complicarse un poco ¿no? 160 | Vamos poco a poco. 161 | ¿Recuerdas el símbolo "\" que usábamos para sacar ciertos caracteres? 162 | Bueno, pues el uso del "%" es parecido. 163 | "%i" no se muestra por pantalla, se sustituye por el valor de la variable que va detrás de las comillas (%i, de integer=entero en inglés). 164 | Para ver el contenido de dos variables, por ejemplo x e y, podemos hacer: 165 | 166 | [source,c] 167 | ---- 168 | printf( "%i ", x ); 169 | printf( "%i", y ); 170 | ---- 171 | 172 | resultado (suponiendo x=10, y=20): 173 | 174 | 10 20 175 | 176 | Pero hay otra forma mejor: 177 | 178 | [source,c] 179 | ---- 180 | printf( "%i %i", x, y ); 181 | ---- 182 | 183 | ...y así podemos poner el número de variables que queramos. 184 | Obtenemos el mismo resultado con menos trabajo. 185 | No olvidemos que por cada variable hay que poner un %i dentro de las comillas. 186 | 187 | También podemos mezclar texto con enteros: 188 | 189 | [source,c] 190 | ---- 191 | printf( "El valor de x es %i, ¡que bien!\n", x ); 192 | ---- 193 | 194 | que quedará como: 195 | 196 | El valor de x es 10, ¡que bien! 197 | 198 | Como vemos %i al imprimir se sustituye por el valor de la variable. 199 | 200 | ==== A veces %d, a veces %i 201 | 202 | Seguramente habrás visto que en ocasiones se usa el modificador %i y otras %d ¿cuál es la diferencia entre ambos? ¿cuál debe usarse? 203 | En realidad, cuando los usamos en un _printf_ no hay ninguna diferencia, se pueden usar indistintamente. 204 | La diferencia está cuando se usa con otras funciones como _scanf_ (esta función la estudiaremos más adelante). 205 | 206 | Hay varios modificadores para los números enteros: 207 | 208 | [cols=3*,options=header] 209 | |======================================================= 210 | |Tipo de variable|Descripción|Modificador 211 | | _int_ | Entero decimal | %i 212 | | _int_ | Entero decimal | %i 213 | | _unsigned int_| Entero decimal sin signo | %u 214 | | _int_ | Entero octal | %o 215 | | _int_ | Entero hexadecimal | %x 216 | |======================================================= 217 | 218 | Podemos verlos en acción con el siguiente ejemplo: 219 | 220 | [source,c] 221 | ---- 222 | #include 223 | #include 224 | 225 | int main() 226 | { 227 | int numero = 13051; 228 | 229 | printf("Decimal usando 'i': %i\n", numero); 230 | printf("Decimal usando 'd': %d\n", numero); 231 | printf("Hexadecimal: %x\n", numero); 232 | printf("Octal: %o\n", numero); 233 | return EXIT_SUCCESS; 234 | } 235 | 236 | ---- 237 | 238 | Este ejemplo mostraría: 239 | 240 | ---- 241 | Decimal usando 'i': 13051 242 | Decimal usando 'd': 13051 243 | Hexadecimal: 32fb 244 | Octal: 31373 245 | ---- 246 | 247 | ==== Asignar valores a variables de tipo int 248 | 249 | La asignación de valores es tan sencilla como: 250 | 251 | [source,c] 252 | ---- 253 | x = 10; 254 | ---- 255 | 256 | También se puede dar un valor inicial a la variable cuando se define: 257 | 258 | [source,c] 259 | ---- 260 | int x = 15; 261 | ---- 262 | 263 | También se pueden dar valores iniciales a varias variables en una sola línea: 264 | 265 | [source,c] 266 | ---- 267 | int x = 15, y = 20; 268 | ---- 269 | 270 | Hay que tener cuidado con lo siguiente: 271 | 272 | [source,c] 273 | ---- 274 | int x, y = 20; 275 | ---- 276 | 277 | Podríamos pensar que _x_ e _y_ son igual a 20, pero no es así. La variable _x_ está sin valor inicial y la variable _y: tiene el valor 20. 278 | 279 | Veamos un ejemplo para resumir todo: 280 | 281 | [source,c] 282 | ---- 283 | #include 284 | #include 285 | 286 | int main() 287 | { 288 | int x = 10; 289 | printf( "El valor inicial de x es %i.\n", x ); 290 | x = 50; 291 | printf( "Ahora el valor de x es %i.\n", x ); 292 | 293 | return EXIT_SUCCESS; 294 | } 295 | ---- 296 | 297 | Cuya salida será: 298 | 299 | ---- 300 | El valor inicial de x es 10 301 | Ahora el valor es 50 302 | ---- 303 | 304 | .Valores iniciales 305 | [NOTE] 306 | ==== 307 | ¡Importante! 308 | Antes de usar una variable debemos darle un valor inicial. 309 | En compiladores nuevos se nos avisa si intentamos usar una variable antes de asignarle un valor inicial. 310 | En los más viejos no se nos avisa y esto puede dar lugar a errores "lógicos". 311 | Prueba a cambiar: 312 | [source,c] 313 | ---- 314 | int x = 10; 315 | ---- 316 | por: 317 | [source,c] 318 | ---- 319 | int x; 320 | ---- 321 | ==== 322 | 323 | === El tipo Char 324 | 325 | Las variables de tipo char se puede usar para almacenar caracteres. 326 | Los caracteres se almacenan en realidad como números del 0 al 255. 327 | Los 128 primeros (0 a 127) son el ASCII estándar. 328 | El resto es el ASCII extendido y depende del idioma y del ordenador. 329 | Consulta la tabla ASCII en el anexo (más información sobre los caracteres ASCII: http://es.wikipedia.org/wiki/Ascii). 330 | 331 | Para declarar una variable de tipo char hacemos: 332 | 333 | [source,c] 334 | ---- 335 | char letra; 336 | ---- 337 | 338 | En una variable char sólo podemos almacenar solo una letra, no podemos almacenar ni frases ni palabras. 339 | Eso lo veremos más adelante (strings, cadenas). 340 | Para almacenar un dato en una variable _char_ tenemos dos posibilidades: 341 | 342 | [source,c] 343 | ---- 344 | letra = 'A'; 345 | ---- 346 | 347 | o: 348 | 349 | [source,c] 350 | ---- 351 | letra = 65; 352 | ---- 353 | 354 | En ambos casos se almacena la letra 'A' en la variable. 355 | Esto es así porque el código ASCII de la letra 'A' es el 65. 356 | 357 | Para imprimir un _char_ usamos el símbolo _%c_ (c de character=carácter en inglés): 358 | 359 | [source,c] 360 | ---- 361 | letra = 'A'; 362 | printf( "La letra es: %c.", letra ); 363 | ---- 364 | 365 | resultado: 366 | 367 | ---- 368 | La letra es A. 369 | ---- 370 | 371 | También podemos imprimir el valor ASCII de la variable usando %i en vez de %c: 372 | 373 | [source,c] 374 | ---- 375 | letra = 'A'; 376 | printf( "El número ASCII de la letra %c es: %i.", letra, letra ); 377 | ---- 378 | 379 | resultado: 380 | 381 | ---- 382 | El código ASCII de la letra A es 65. 383 | ---- 384 | 385 | Como vemos la única diferencia para obtener uno u otro es el modificador (%c ó %i) que usemos. 386 | Las variables tipo char se pueden usar (y de hecho se usan mucho) para almacenar enteros. 387 | Si necesitamos un número pequeño (entre -128 y 127) podemos usar una variable char (8bits) en vez de una int (16bits), con el consiguiente ahorro de memoria. 388 | Todo lo demás dicho para los datos de tipo “int” se aplica también a los de tipo “char”. 389 | 390 | Una curiosidad: 391 | 392 | [source,c] 393 | ---- 394 | #include 395 | #include 396 | 397 | int main() 398 | { 399 | char letra = 'A'; 400 | printf( "La letra es: %c y su valor ASCII es: %i.\n", letra, 401 | letra ); 402 | letra = letra + 1; 403 | printf( "Ahora es: %c y su valor ASCII es: %i.\n", letra, letra ); 404 | 405 | return EXIT_SUCCESS; 406 | } 407 | ---- 408 | 409 | En este ejemplo letra comienza con el valor 'A', que es el código ASCII 65. 410 | Al sumarle 1 pasa a tener el valor 66, que equivale a la letra 'B' (código ASCII 66). 411 | La salida de este ejemplo sería: 412 | 413 | ---- 414 | La letra es A y su valor ASCII es 65 415 | Ahora es B y su valor ASCII es 66 416 | ---- 417 | 418 | === El modificador Unsigned 419 | 420 | Este modificador (que significa sin signo) modifica el rango de valores que puede contener una variable. 421 | Solo admite valores positivos. Si hacemos: 422 | 423 | [source,c] 424 | ---- 425 | unsigned char variable; 426 | ---- 427 | 428 | Esta variable en vez de tener un rango de -128 a 127 pasa a tener un rango de 0 a 255. 429 | Los indicadores de signo _signed_ y _unsigned_ solo pueden aplicarse a los tipos enteros. 430 | El primero indica que el tipo puede almacenar tanto valores positivos como negativos y el segundo indica que solo se admiten valores no negativos, esto es, solo se admite el cero y valores positivos. 431 | Si se declara una variable de tipo short, int o long sin utilizar un indicador de signo esto es equivalente a utilizar el indicador de signo signed. 432 | Por ejemplo: 433 | 434 | [source,c] 435 | ---- 436 | signed int i; 437 | int j; 438 | ---- 439 | 440 | Declara dos variables de tipo _signed int_. 441 | 442 | La excepcion es el tipo *_char_*. 443 | Cuando se declara una variable de tipo char sin utilizar un indicador de signo si esta variable es equivalente a signed char o a unsigned char depende del compilador que estemos utilizando. 444 | Por lo mismo si debemos tener total certeza de que nuestras variables de tipo char puedan almacenar (o no) valores negativos es mejor indicarlo explicitamente utilizando ya sea signed char o unsigned char. 445 | 446 | === El tipo Float 447 | 448 | En este tipo de variable podemos almacenar números decimales, no sólo enteros como en los anteriores. El mayor número que podemos almacenar en un float es 3,4E38 y el más pequeño 3,4E-38. 449 | ¿Qué significa 3,4E38? Esto es equivalente a 3,4 * 10^38, que es el número: 450 | 340.000.000.000.000.000.000.000.000.000.000.000.000 451 | El número 3,4E-38 es equivalente a 3,4 * 10^-38, vamos un número muy, muy pequeño. 452 | 453 | Declaración de una variable de tipo float: 454 | 455 | [source,c] 456 | ---- 457 | float número; 458 | ---- 459 | 460 | Para imprimir valores tipo float Usamos %f. 461 | 462 | [source,c] 463 | ---- 464 | int main() 465 | { 466 | float num=4060.80; 467 | printf( "El valor de num es : %f", num ); 468 | } 469 | ---- 470 | 471 | Resultado: 472 | 473 | ---- 474 | El valor de num es: 4060.80 475 | ---- 476 | 477 | Si queremos escribirlo en notación exponencial usamos %e: 478 | 479 | [source,c] 480 | ---- 481 | float num = 4060.80; 482 | printf( "El valor de num es: %e", num ); 483 | ---- 484 | 485 | Que da como resultado: 486 | 487 | ---- 488 | El valor de num es: 4.06080e003 489 | ---- 490 | 491 | === El tipo Double 492 | 493 | En las variables tipo double se almacenan números reales. 494 | El mayor número que se pueda almacenar es el 1,7E308 y el más pequeño del 1,7E-307. 495 | Se declaran como double: 496 | 497 | [source,c] 498 | ---- 499 | double número; 500 | ---- 501 | 502 | Para imprimir se usan los mismos modificadores que en float. 503 | 504 | ==== Números decimales ¿float o double? 505 | 506 | Cuando escribimos un número decimal en nuestro programa, por ejemplo 10.30, ¿de qué tipo es? ¿float o double? 507 | 508 | [source,c] 509 | ---- 510 | #include 511 | #include 512 | 513 | int main() 514 | { 515 | printf( "%f\n", 10.30 ); 516 | return EXIT_SUCCESS; 517 | } 518 | ---- 519 | 520 | Por defecto, si no se especifica nada, las constantes son de tipo double. Para especificar que queremos que la constante sea float debemos especificar el sufijo “f” o “F”. Si queremos que la constante sea de tipo long double usamos el sufijo “l” o “L”. 521 | Veamos el siguiente programa: 522 | 523 | [source,c] 524 | ---- 525 | #include 526 | #include 527 | 528 | int main() { 529 | float num; 530 | 531 | num = 10.20 * 20.30; 532 | 533 | return EXIT_SUCCESS; 534 | } 535 | ---- 536 | 537 | En este caso, ya que no hemos especificado nada, tanto 10.20 como 20.30 son de tipo double. 538 | La operación se hace con valores de tipo double y luego se almacena en un float. 539 | Al hacer una operación con double tenemos mayor precisión que con floats, sin embargo es innecesario, ya que en este caso al final el resultado de la operación se almacena en un float, de menor precisión. 540 | El programa sería más correcto así: 541 | 542 | [source,c] 543 | ---- 544 | int main() 545 | { 546 | float num; 547 | num = 10.20f * 20.30f; 548 | } 549 | ---- 550 | 551 | === Cómo calcular el máximo valor que admite un tipo de datos 552 | 553 | Lo primero que tenemos que conocer es el tamaño en bytes de ese tipo de dato. Vamos a ver un ejemplo con el tipo INT. Hagamos el siguiente programa: 554 | 555 | [source,c] 556 | ---- 557 | #include 558 | #include 559 | 560 | int main() 561 | { 562 | printf( "El tipo int ocupa %lu bytes\n", sizeof(int) ); 563 | return EXIT_SUCCESS; 564 | } 565 | ---- 566 | 567 | NOTE: En este caso usamos el modificador _%lu_ porque _sizeof()_ devuelve un valor del tipo _long unsigned int_. 568 | 569 | La función sizeof() calcula el tamaño en bytes de una variable o un tipo de datos. 570 | En mi ordenador el resultado era (en tu ordenador podría ser diferente): 571 | 572 | ---- 573 | El tipo int ocupa 4 bytes. 574 | ---- 575 | 576 | Como sabemos 1 byte = 8 bits. Por lo tanto el tipo int ocupa 4*8=32 bits. 577 | Ahora para calcular el máximo número debemos elevar 2 al número de bits obtenido. 578 | En nuestro ejemplo: 2^32=4.294.967.296. Es decir en un int se podrían almacenar 4.294.967.296 números diferentes. 579 | 580 | El número de valores posibles y únicos que pueden almacenarse en un tipo entero depende del número de bits que lo componen y esta dado por la expresión 2^N donde N es el número de bits. 581 | Si usamos un tipo unsigned (sin signo, se hace añadiendo la palabra unsigned antes de int) tenemos que almacenar números positivos y negativos. 582 | 583 | Así que de los 4.294.967.296 posibles números la mitad serán positivos y la mitad negativos. 584 | Por lo tanto tenemos que dividir el número anterior entre 2 = 2.147.483.648. 585 | Como el 0 se considera positivo el rango de números posibles que se pueden almacenar en un int sería: -2.147.483.648 a 2.147.483.647. 586 | 587 | === El fichero 588 | 589 | Existe un fichero llamado limits.h en el directorio includes de nuestro compilador (sea cual sea) en el que se almacena la información correspondiente a los tamaños y máximos rangos de los tipos de datos char, short, int y long (signed y unsigned) de nuestro compilador. 590 | Se recomienda como curiosidad examinar este fichero. 591 | 592 | === Overflow: Qué pasa cuando nos saltamos el rango 593 | 594 | El overflow es lo que se produce cuando intentamos almacenar en una variable un número mayor del máximo permitido. 595 | El comportamiento es distinto para variables de números enteros y para variables de números en coma flotante. 596 | 597 | ==== Con números enteros 598 | Supongamos que en nuestro ordenador el tipo int es de 32 bits. 599 | El número máximo que se puede almacenar en una variable tipo int es por tanto 2.147.483.647 (ver apartado anterior). 600 | Si nos pasamos de este número el que se guardará será el siguiente pero empezando desde el otro extremo, es decir, el -2.147.483.648. 601 | El compilador seguramente nos dará un aviso (warning) de que nos hemos pasado. 602 | 603 | [source,c] 604 | ---- 605 | #include 606 | #include 607 | 608 | int main() { 609 | int num1; 610 | 611 | num1 = 2147483648; 612 | printf( "El valor de num1 es: %i\n", num1 ); 613 | 614 | return EXIT_SUCCESS; 615 | } 616 | ---- 617 | 618 | El resultado que obtenemos es: 619 | 620 | ---- 621 | El valor de num1 es: -2147483648 622 | ---- 623 | 624 | Comprueba si quieres que con el número anterior (2.147.483.647) no pasa nada. 625 | 626 | ==== Con números en coma flotante 627 | 628 | El comportamiento con números en coma flotante es distinto. 629 | Dependiendo del ordenador si nos pasamos del rango al ejecutar un programa se puede producir un error y detenerse la ejecución. 630 | Con estos números también existe otro error que es el underflow. 631 | Este error se produce cuando almacenamos un número demasiado pequeño (3,4E-38 en float). 632 | 633 | === Los tipos short int, long int y long double 634 | 635 | Existen otros tipos de datos que son variaciones de los anteriores que son: short int, long int, long long y long double. 636 | 637 | En realidad, dado que el tamaño de los tipos depende del compilador, lo único que nos garantiza es que: 638 | 639 | * El tipo long long no es menor que el tipo int. 640 | * El tipo long no es menor que el tipo int. 641 | * El tipo int no es menor que el tipo short. 642 | 643 | === Resumen de los tipos de datos en C 644 | 645 | Los números en C se almacenan en variables llamadas “de tipo aritmético”. 646 | Estas variables a su vez se dividen en variables de tipos enteros y de tipos en coma flotante. 647 | Los tipos enteros son char, short int, int y long int. 648 | Los tipos short int y long int se pueden abreviar a solo short y long. 649 | Esto es algo orientativo, depende del sistema. 650 | 651 | Por ejemplo en un sistema de 16 bits podría ser algo así: 652 | 653 | [cols=5*,options=header] 654 | |=== 655 | | Tipo 656 | | Datos almacenados 657 | | Nº de Bits 658 | | Valores posibles (Rango) 659 | | Rango usando unsigned 660 | 661 | | char 662 | | Caracteres y enteros pequeños 663 | | 8 664 | | -128 a 127 665 | | 0 a 255 666 | 667 | | int 668 | | Enteros 669 | | 16 670 | | -32.768 a 32.767 671 | | 16 0 a 65.535 672 | 673 | | long 674 | | Enteros largos 675 | | 32 676 | | -2.147.483.648 a 2.147.483.647 677 | | 0 a 4.294.967.295 678 | 679 | | float 680 | | Números reales (coma flotante) 681 | | 32 682 | | 3,4E-38 a 3,4E38 683 | | No se aplica 684 | 685 | | double 686 | | Números reales (coma flotante doble) 687 | | 64 688 | | 1,7E-307 a 1,7E308 689 | | No se aplica 690 | |=== 691 | 692 | Como hemos mencionado antes esto no siempre es cierto, depende del ordenador y del compilador. Para saber en nuestro caso qué tamaño tienen nuestros tipos de datos debemos hacer lo siguiente. 693 | 694 | Ejemplo para int: 695 | 696 | [source,c] 697 | ---- 698 | #include 699 | #include 700 | 701 | int main() { 702 | printf( "Tamaño (en bits) de int = %i\n", sizeof( int )*8 ); 703 | 704 | return EXIT_SUCCESS; 705 | } 706 | ---- 707 | 708 | Ya veremos más tarde lo que significa sizeof. 709 | Por ahora basta con saber que nos dice cual es el tamaño de una variable o un tipo de dato. 710 | 711 | === Ejercicios 712 | 713 | *Ejercicio 1:* Busca los errores: 714 | 715 | [source,c] 716 | ---- 717 | #include 718 | #include 719 | 720 | int main() 721 | { 722 | int número; 723 | número = 2; 724 | return EXIT_SUCCESS; 725 | } 726 | ---- 727 | 728 | *Solución:* Los nombres de variables no pueden llevar acentos, luego al compilar número dará error. 729 | 730 | [source,c] 731 | ---- 732 | #include 733 | #include 734 | 735 | int main() 736 | { 737 | int número; 738 | número = 2; 739 | printf( "El valor es %i" número ); 740 | return EXIT_SUCCESS; 741 | } 742 | ---- 743 | 744 | *Solución:* Falta la coma después de "El valor es %i". 745 | Además la segunda vez número está escrito con mayúsculas. 746 | -------------------------------------------------------------------------------- /capitulo04.adoc: -------------------------------------------------------------------------------- 1 | //// 2 | Copyright: Gorka Urrutia Landa, 1999-2018 3 | Licencia: Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) https://creativecommons.org/licenses/by-sa/4.0/ 4 | //// 5 | 6 | :chapter: 004 7 | 8 | <<< 9 | 10 | == Capítulo 4. Constantes (uso de #define). 11 | 12 | [[introducción]] 13 | === Introducción 14 | 15 | Las constantes son aquellos datos que no pueden cambiar a lo largo de la ejecución de un programa. 16 | 17 | [source,c] 18 | ---- 19 | #include 20 | #include 21 | 22 | int main() 23 | { 24 | 25 | double radio, perimetro; 26 | 27 | radio = 20; 28 | perimetro = 2 * 3.1416 * radio; 29 | printf( "El perimetro es: %f", perimetro ); 30 | return EXIT_SUCCESS; 31 | 32 | } 33 | ---- 34 | 35 | _radio_ y _perimetro_ son variables, su valor puede cambiar a lo largo del programa. 36 | Sin embargo 20, 2 y 3.1416 son constantes, no hay manera de cambiarlas. 37 | El valor 3.1416 no cambia a lo largo del programa, ni entre ejecución y ejecución. 38 | Solo cambiará cuando edites el programa y lo cambies tu mismo. 39 | En resumen, cuando escribimos directamente un número se le llama una constante. 40 | 41 | [[tipos-de-datos-en-las-constantes]] 42 | === Tipos de datos en las constantes 43 | 44 | En el capítulo anterior vimos que las existen diferentes tipos de datos para las variables. 45 | Las constantes también tienen tipos de datos. 46 | Recordemos que especificábamos el tipo de dato de la variable usando int, float, double y otros. 47 | Con las constantes indicamos el tipo dependiendo del sufijo que empleemos después de la constante. 48 | Veamos unos ejemplos: 49 | 50 | [source,c] 51 | ---- 52 | a = 100; /* 100 es de tipo signed int */ 53 | b = 200U; /* 200U es de tipo unsigned int */ 54 | c = 300L; /* 300L es de tipo signed long */ 55 | d = 400UL; /* 400UL es de tipo unsigned long */ 56 | ---- 57 | 58 | Pero ¿para qué queremos indicar el tipo de dato de una constante? 59 | Al fin y al cabo son todos números. 60 | Veremos más adelante que es muy importante, sobre todo a la hora de hacer ciertas operaciones matemáticas. 61 | 62 | [[constantes-en-base-10-sin-parte-fraccionaria]] 63 | ==== Constantes en base 10 sin parte fraccionaria 64 | 65 | .NOTA 66 | [NOTE] 67 | ==== 68 | Los números en base 10 son los que llamamos decimales. Se llaman 69 | así porque los números se pueden representar usando como base el 10: 70 | 71 | 3.284 = 3x1000 + 2x100 + 8x10 + 4 = 3x10^3^ + 2x10^2^ + 8x10^1^ + 72 | 4x10^0^ 73 | ==== 74 | 75 | Recordemos que también hay números binarios (en base 2), hexadecimales y octales. 76 | 77 | Las constantes en base 10 y sin fracción ni exponente son de tipo _signed int_. 78 | 79 | ¿Y que pasa si una constante "no cabe" en el tipo indicado? 80 | 81 | Supongamos un ordenador de 16 bits donde el valor máximo que se puede almacenar en el tipo int es 32.767 y (por poner un ejemplo) en nuestro programa tenemos: 82 | 83 | [source,c] 84 | ---- 85 | int a = 32768; /* recordemos 32768 "no cabe" en un int de 16 bits. */ 86 | ---- 87 | 88 | ¿Que es lo que sucede? 89 | 90 | Cuando el número no cabe en el tipo que se está indicando (en este caso no se indica nada así que se considera como un tipo int) se comprueba si cabe en el siguiente tipo de dato. 91 | Si tampoco cabe se prueba con el siguiente. 92 | El orden que se sigue es: 93 | 94 | . int 95 | . long 96 | . unsigned long 97 | 98 | Debido a que en nuestro ejemplo 32.768 no cabe en un int se comprueba con el tipo _signed long_. 99 | Si en éste tampoco cabe se considera que el tipo de la constante es __unsigned long__. 100 | 101 | Si la constante en cuestión tiene uno de los dos sufijos 'U' o 'L' el tipo a utilizar se restringe (limita) y selecciona en este orden: 102 | 103 | A) En el caso de utilizar 'U': 104 | 105 | . unsigned int 106 | . unsigned long 107 | 108 | B) En el caso de utilizar 'L': 109 | 110 | . signed long 111 | . unsigned long 112 | 113 | [[constantes-en-base-10-y-con-decimales]] 114 | ==== Constantes en base 10 y con decimales 115 | 116 | Las constantes en base 10 y con un punto decimal y/o exponente son de tipo double. 117 | 118 | Algunos ejemplos: 119 | 120 | [source,c] 121 | ---- 122 | a = 100.0; /* 100.0 es de tipo 'double' */ 123 | b = 10E2; /* 10E2 es de tipo 'double' */ 124 | ---- 125 | 126 | Nota técnica: 127 | 128 | Las constantes de punto flotante son de tipo double a menos que se utilice uno de estos sufijos ya sea en minúsculas o mayúsculas: 129 | 130 | * El sufijo 'F' indica que la constante es de tipo float. 131 | * El sufijo 'L' indica que la constante es de tipo long double. 132 | 133 | Solo se puede utilizar uno de estos sufijos pero no ambos. 134 | 135 | Algunos ejemplos: 136 | 137 | [source,c] 138 | ---- 139 | a = 100.0F /* 100.0F es de tipo float */ 140 | b = 200.0 /* 200.0 es de tipo double */ 141 | c = 300.0L /* 300.0L es de tipo long double */ 142 | ---- 143 | 144 | [[constantes-con-nombre]] 145 | === Constantes con nombre 146 | 147 | Imagina el siguiente programa: 148 | 149 | [source,c] 150 | ---- 151 | #include 152 | #include 153 | 154 | int main() 155 | { 156 | 157 | float precio; 158 | 159 | precio = ( 4 * 25 * 100 ) * ( 1.16 ); 160 | 161 | printf( "El precio total es: %f", precio ); 162 | 163 | return EXIT_SUCCESS; 164 | 165 | } 166 | ---- 167 | 168 | Es un programa sencillo y que funciona bien. 169 | Sin embargo ¿qué sentido tienen los números 4, 25, 100 y 1,16? Es difícil saberlo. 170 | Es bastante habitual escribir un programa así, volver a echarle un vistazo unos meses más tarde y no recordar qué eran esos números. 171 | 172 | Ahora mira este otro programa: 173 | 174 | [source,c] 175 | ---- 176 | #include 177 | #include 178 | 179 | #define CAJAS 4 180 | #define UNIDADES_POR_CAJA 25 181 | #define PRECIO_POR_UNIDAD 100 182 | #define IMPUESTOS 1.16 183 | 184 | int main() 185 | { 186 | 187 | float precio; 188 | 189 | precio = 190 | ( CAJAS * UNIDADES_POR_CAJA * PRECIO_POR_UNIDAD ) * 191 | ( IMPUESTOS ); 192 | 193 | printf( "El precio total es: %f", precio ); 194 | return EXIT_SUCCESS; 195 | 196 | } 197 | ---- 198 | 199 | Ahora todos los números tienen un significado claro. Es porque esta vez 200 | estamos usando __constantes con nombre__. 201 | 202 | #define es lo que se llama una __directiva__. Estas directivas se 203 | utilizan, entre otras cosas, para definir constantes. Los usos de 204 | #define y de otras directivas los veremos en el capítulo de directivas. 205 | 206 | Las constantes, una vez definidas, no pueden cambiar su valor. No son 207 | como las variables. Cuando hacemos: 208 | 209 | [source,c] 210 | ---- 211 | #define CAJAS 4 212 | ---- 213 | 214 | estamos diciendo que, dentro de nuestro programa, donde aparezca la 215 | palabra CAJAS hay que sustituirlo por el valor 4. 216 | 217 | Para definir constantes hay que seguir unas sencillas normas: 218 | 219 | * Sólo se puede definir una constante por línea. 220 | * No llevan ';' al final. 221 | * Se suelen escribir en mayúsculas aunque no es obligatorio. 222 | 223 | También podemos definir una constante usando el valor de otras. Por 224 | supuesto las otras tienen que estar definidas antes: 225 | 226 | [source,c] 227 | ---- 228 | #include 229 | #include 230 | 231 | #define CAJAS 4 232 | #define UNIDADES_POR_CAJA 25 233 | #define PRECIO_POR_UNIDAD 100 234 | #define PRECIO_POR_CAJA UNIDADES_POR_CAJA * PRECIO_POR_UNIDAD 235 | #define IMPUESTOS 1.16 236 | 237 | int main() 238 | 239 | { 240 | 241 | float precio; 242 | 243 | precio = ( CAJAS * PRECIO_POR_CAJA ) * ( IMPUESTOS ); 244 | 245 | printf( "El precio total es: %f", precio ); 246 | 247 | return EXIT_SUCCESS; 248 | 249 | } 250 | ---- 251 | -------------------------------------------------------------------------------- /capitulo05.adoc: -------------------------------------------------------------------------------- 1 | //// 2 | Copyright: Gorka Urrutia Landa, 1999-2018 3 | Licencia: Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) https://creativecommons.org/licenses/by-sa/4.0/ 4 | //// 5 | 6 | :chapter: 005 7 | 8 | <<< 9 | 10 | [[capítulo-5.-manipulando-datos-operadores]] 11 | == Capítulo 5. Manipulando datos (operadores) 12 | 13 | [[qué-es-un-operador]] 14 | === ¿Qué es un operador? 15 | 16 | Un operador sirve para manipular datos. 17 | Los hay de varios tipos: de asignación, de relación, lógicos, aritméticos y de manipulación de bits. 18 | En realidad los nombres tampoco importan mucho; aquí lo que queremos es aprender a programar, no aprender un montón de nombres. 19 | 20 | [[operador-de-asignación]] 21 | === Operador de asignación 22 | 23 | Este es un operador que ya hemos visto en el capítulo de Tipos de Datos. 24 | Sirve para dar un valor a una variable. Este valor puede ser un número que tecleamos directamente u otra variable: 25 | 26 | [source,c] 27 | ---- 28 | a = 3; /* Metemos un valor directamente */ 29 | ---- 30 | 31 | o 32 | 33 | [source,c] 34 | ---- 35 | a = b; /* Le damos el valor de una variable */ 36 | ---- 37 | 38 | Podemos dar valores a varias variables a la vez: 39 | 40 | [source,c] 41 | ---- 42 | a = b = c = 10; /* Damos a las variables a,b,c el valor 10 */ 43 | ---- 44 | 45 | También podemos asignar a varias variables el valor de otra de un solo golpe: 46 | 47 | a = b = c = d; /* a,b,c toman el valor de d */ 48 | 49 | [[operadores-aritméticos]] 50 | === Operadores aritméticos 51 | 52 | Los operadores aritméticos son aquellos que sirven para realizar operaciones tales como suma, resta, división, multiplicación y módulo (o resto o residuo). 53 | 54 | [[operador-suma]] 55 | ==== Operador (+) : Suma 56 | 57 | Este operador permite sumar variables: 58 | 59 | [source,c] 60 | ---- 61 | #include 62 | #include 63 | 64 | int main() 65 | 66 | { 67 | 68 | int a = 2; 69 | int b = 3; 70 | int c; 71 | 72 | c = a + b; 73 | 74 | printf ( "Resultado = %i\n", c ); 75 | 76 | return EXIT_SUCCESS; 77 | 78 | } 79 | ---- 80 | 81 | El resultado será 5 obviamente. 82 | 83 | Por supuesto se pueden sumar varias variables o variables más constantes: 84 | 85 | [source,c] 86 | ---- 87 | #include 88 | #include 89 | 90 | int main() 91 | 92 | { 93 | 94 | int a = 2; 95 | int b = 3; 96 | int c = 1; 97 | int d; 98 | 99 | d = a + b + c + 4; 100 | 101 | printf ( "Resultado = %i\n", d ); 102 | 103 | return EXIT_SUCCESS; 104 | 105 | } 106 | ---- 107 | 108 | El resultado es 10. 109 | 110 | Podemos utilizar este operador para incrementar el valor de una 111 | variable: 112 | 113 | [source,c] 114 | ---- 115 | x = x + 5; 116 | ---- 117 | 118 | Pero existe una forma abreviada: 119 | 120 | [source,c] 121 | ---- 122 | x += 5; 123 | ---- 124 | 125 | Esto suma el valor 5 al valor que tenía la variable x. Veamos un 126 | ejemplo: 127 | 128 | [source,c] 129 | ---- 130 | #include 131 | #include 132 | 133 | int main() 134 | { 135 | 136 | int x, y; 137 | 138 | x = 3; 139 | y = 5; 140 | x += 2; 141 | 142 | printf( "x = %i\n", x ); 143 | 144 | x += y; /* esto equivale a x = x + y */ 145 | 146 | printf( "x = %i\n", x ); 147 | 148 | return EXIT_SUCCESS; 149 | 150 | } 151 | ---- 152 | 153 | 154 | Resultado: 155 | 156 | ---- 157 | x = 5 158 | x = 10 159 | ---- 160 | 161 | [[operador-incremento]] 162 | ==== Operador (++) : Incremento 163 | 164 | Este operador equivale a sumar uno a la variable: 165 | 166 | [source,c] 167 | ---- 168 | #include 169 | #include 170 | 171 | int main() 172 | { 173 | 174 | int x = 5; 175 | 176 | printf ( "Valor de x = %i\n", x ); 177 | 178 | x++; 179 | 180 | printf ( "Valor de x = %i\n", x ); 181 | 182 | return EXIT_SUCCESS; 183 | 184 | } 185 | ---- 186 | 187 | Resultado: 188 | 189 | ---- 190 | Valor de x = 5 191 | Valor de x = 6 192 | ---- 193 | 194 | Se puede poner antes o después de la variable. 195 | 196 | [[operador---restanegativo]] 197 | ==== Operador (-) : Resta/Negativo 198 | 199 | Este operador tiene dos usos, uno es la resta que funciona como el operador suma y el otro es cambiar de signo. 200 | 201 | Resta: 202 | 203 | [source,c] 204 | ---- 205 | x = x - 5; 206 | ---- 207 | 208 | Para la operación resta se aplica todo lo dicho para la suma. 209 | Se puede usar también como: 210 | 211 | [source,c] 212 | ---- 213 | x -= 5; 214 | ---- 215 | 216 | Pero también tiene el uso de cambiar de signo. 217 | Poniéndolo delante de una variable o constante equivale a multiplicarla por -1. 218 | 219 | [source,c] 220 | ---- 221 | #include 222 | #include 223 | 224 | int main() 225 | { 226 | 227 | int a, b; 228 | 229 | a = 1; 230 | b = -a; 231 | 232 | printf( "a = %i, b = %i\n", a, b ); 233 | 234 | return EXIT_SUCCESS; 235 | 236 | } 237 | ---- 238 | 239 | Resultado: a = 1, b = -1. No tiene mucho misterio. 240 | 241 | [[operador----decremento]] 242 | ==== Operador (--) : Decremento 243 | 244 | Es equivalente a ++ pero en vez de incrementar disminuye el valor de la 245 | variable. Equivale a restar uno a la variable. 246 | 247 | [[operador-multiplicación-y-punteros]] 248 | ==== Operador (*) : Multiplicación y punteros 249 | 250 | Este operador sirve para multiplicar y funciona de manera parecida a los 251 | anteriores. 252 | 253 | También sirve para definir y utilizar punteros, pero eso lo veremos más 254 | tarde. 255 | 256 | [[operador-división]] 257 | ==== Operador (/) : División 258 | 259 | Este funciona también como los anteriores pero hay que tener dos cosas 260 | en cuenta: 261 | 262 | ===== División de enteros 263 | 264 | Si dividimos dos números en coma flotante (tipo __float__) tenemos las 265 | división con sus correspondientes decimales. Pero si dividimos dos 266 | enteros obtenemos un número entero. Es decir que si dividimos 4/3 267 | tenemos como resultado 1. Se hace un redondeo por truncamiento y se 268 | eliminan los decimales. 269 | 270 | Para conseguir el resultado correcto debemos usar 4.0/3.0, dado que 4 se 271 | considera como _int_ y 4.0 como __float__. 272 | 273 | Al dividir dos enteros el resultado es siempre un número entero, aunque 274 | luego lo saquemos por pantalla usando %f no obtendremos la parte 275 | decimal. 276 | 277 | Si queremos saber cuál es el resto (o módulo) usamos el operador %, que 278 | vemos más abajo. 279 | 280 | ===== División por cero 281 | 282 | En C no podemos dividir un número por cero, es una operación ilegal. Hay 283 | que evitar esto pues se producirá un error en nuestro programa. Los 284 | operadores división y módulo no aceptan como segundo parámetro el cero. 285 | No se puede usar: 286 | 287 | * El valor 0 con los operadores de división y módulo. 288 | * El valor 0.0 con el operador de división. 289 | 290 | [[operador-módulo-o-resto]] 291 | ==== Operador (%) : Módulo o Resto 292 | 293 | Si con el anterior operador obteníamos el módulo o cociente de una división entera con éste podemos tener el resto. 294 | **Sólo funciona con enteros**, no vale para números _float_ o _double_. 295 | 296 | Cómo se usa: 297 | 298 | [source,c] 299 | ---- 300 | #include 301 | #include 302 | 303 | int main() 304 | { 305 | 306 | int a, b; 307 | 308 | a = 18; 309 | 310 | b = 5; 311 | 312 | printf( "Resto de la división: %d \n", a % b ); 313 | 314 | return EXIT_SUCCESS; 315 | 316 | } 317 | ---- 318 | 319 | [[operadores-de-comparación]] 320 | === Operadores de comparación 321 | 322 | Los operadores de condición se utilizan para comprobar las condiciones de las sentencias de control de flujo (las estudiaremos en el capítulo sentencias). 323 | 324 | Cuando se evalúa una condición el resultado que se obtiene es 0 si no se cumple y un número distinto de 0 si se cumple. 325 | Normalmente cuando se cumplen devuelven un 1. 326 | 327 | Los operadores de comparación son: 328 | 329 | [cols="",] 330 | |======================================================================= 331 | |Operador |Descripción |Aplicación 332 | 333 | |== |igual que |se cumple si son iguales 334 | 335 | |!= |distinto que |se cumple si son diferentes 336 | 337 | |> |mayor que |se cumple si el primero es mayor que el segundo 338 | 339 | |< |menor que |se cumple si el primero es menor que el segundo 340 | 341 | |>= |mayor o igual que |se cumple si el primero es mayor o igual que el 342 | segundo 343 | 344 | |+<+= |menor o igual que |se cumple si el primero es menor o igual que el 345 | segundo 346 | |======================================================================= 347 | 348 | Veremos la aplicación de estos operadores en el capítulo Sentencias. 349 | Pero ahora vamos a ver un ejemplo: 350 | 351 | [source,c] 352 | ---- 353 | #include 354 | #include 355 | 356 | int main() 357 | 358 | { 359 | 360 | printf( "10 > 5 da como resultado %i\n", 10>5 ); 361 | 362 | printf( "10 < 5 da como resultado %i\n", 10<5 ); 363 | 364 | printf( "5 == 5 da como resultado %i\n", 5==5 ); 365 | 366 | printf( "10 == 5 da como resultado %i\n", 10==5 ); 367 | 368 | return EXIT_SUCCESS; 369 | 370 | } 371 | ---- 372 | 373 | Como se puede ver al ejecutar este programa: 374 | * cuando la condición se cumple el resultado es un 1 (true) 375 | * cuando no se cumple es un 0 (false). 376 | 377 | No sólo se pueden comparar constantes, también se pueden comparar variables. 378 | 379 | [[operadores-lógicos]] 380 | === Operadores lógicos 381 | 382 | Estos son los que nos permiten unir varias comparaciones, por ejemplo: 383 | 10>5 y 6==6. 384 | Los operadores lógicos son: *_AND (&&), OR (||), NOT(!)_*. 385 | 386 | Operador && (AND, en castellano Y): Devuelve un 1 si se cumplen dos condiciones. 387 | 388 | [source,c] 389 | ---- 390 | printf( "Resultado: %i", (10==10 && 5>2 ); /* Resultado: 1 */ 391 | 392 | printf( "Resultado: %i", (10==10 && 5<2 ); /* Resultado: 0 */ 393 | ---- 394 | 395 | Operador || (OR, en castellano O): Devuelve un 1 si se cumple una de las 396 | dos condiciones. 397 | 398 | [source,c] 399 | ---- 400 | printf( "Resultado: %i", (10==10 || 5<2 ); /* Resultado: 1 */ 401 | ---- 402 | 403 | Operador ! (NOT, negación): Si la condición se cumple NOT hace que no se cumpla y viceversa. 404 | 405 | [source,c] 406 | ---- 407 | printf( "Resultado: %i", !10==10 ); /* Resultado: 0 */ 408 | 409 | printf( "Resultado: %i", !(5<2) ); /* Resultado: 1 */ 410 | ---- 411 | 412 | En los operadores && y || primero se evalúa la condición de la izquierda y si es necesario se evalúa la de la derecha. Por ejemplo: 413 | 414 | [source,c] 415 | ---- 416 | (10>5 && 6==6) 417 | ---- 418 | 419 | Se evalúa 10>5 -> verdadera. 420 | A continuación se evalúa 6==6 -> verdadera. Resultado: verdadera. 421 | 422 | [source,c] 423 | ---- 424 | (10<5 && 6==6) 425 | ---- 426 | 427 | Se evalúa la de la izquierda -> falso. 428 | Dado que el operador && requiere que ambas condiciones sean ciertas no es necesario evaluar la segunda ya que aunque sea cierta el resultado será falso. 429 | Es decir: 430 | 431 | * En el caso del operador AND si la primera expresión es falsa (igual a 432 | 0) el resultado final va a ser falso así que la segunda expresión no se 433 | evalúa. 434 | 435 | * En el caso del operador OR si la primera expresión es verdadera 436 | (diferente de 0) el resultado final va a ser verdadero así que la 437 | segunda expresión no se evalúa. 438 | 439 | Por esta forma de funcionamiento se les llama operadores shortcircuit 440 | operators (u operadores cortocircuito). 441 | 442 | Estos dos operadores son particularmente útiles cuando se debe evaluar 443 | (o no) una expresión dependiendo de la evaluación de una expresión 444 | anterior. 445 | 446 | Por ejemplo supongamos que tenemos dos números enteros (a y b) y tenemos 447 | que verificar si el primero (a) es un múltiplo del segundo (b). Podemos 448 | hacer: 449 | 450 | [source,c] 451 | ---- 452 | if ((a % b == 0)) 453 | printf(“%d es divisible por %d”, a, b); 454 | ---- 455 | 456 | Pero si b es cero tendremos un error de división por cero. 457 | Para evitarlo podemos usar la siguiente expresión: 458 | 459 | [source,c] 460 | ---- 461 | if ((b != 0) && (a % b == 0)) 462 | /* b es múltiplo de a */ 463 | ---- 464 | 465 | .NOTA 466 | NOTE: el funcionamiento del 'if' lo estudiaremos en un capítulo posterior. 467 | Por ahora es suficiente con saber que permite controlar el flujo de un programa dependiendo de la condición que le sigue. 468 | 469 | Aquí el operador AND primero evalúa la expresión a su izquierda y solo 470 | si esta es verdadera (¿_b_ es diferente de cero?) se evalúa la 471 | expresión a su derecha (¿el residuo de _a_ entre _b_ es cero?). 472 | 473 | Ver el capítulo Sentencias, sección Notas sobre las condiciones para más información. 474 | 475 | [[introducción-a-los-bits-y-bytes]] 476 | === Introducción a los bits y bytes 477 | 478 | Supongo que todo el mundo sabe lo que son los bytes y los bits, pero por si acaso allá va. 479 | 480 | Los bits son la unidad de información más pequeña, digamos que son la base para almacenar la información. 481 | Son como los átomos a las moléculas. 482 | Los valores que puede tomar un bit son 0 ó 1. 483 | Si juntamos ocho bits tenemos un byte. 484 | 485 | Un byte puede tomar 256 valores diferentes (de 0 a 255). 486 | 487 | ¿Cómo se consigue esto? Imaginemos nuestro flamante byte con sus ocho bits. 488 | Supongamos que los ocho bits valen cero. 489 | Ya tenemos el valor 0 en el byte. 490 | Ahora vamos a darle al último byte el valor 1. 491 | 492 | Cambiando los 1 y 0 podemos conseguir los 256 valores: 493 | 494 | 00000000 → 0 495 | 496 | 00000001 → 1 497 | 498 | 00000010 → 2 499 | 500 | 00000011 → 3 501 | 502 | … 503 | 504 | 11111110 → 254 505 | 506 | 11111111 → 255 507 | 508 | Como vemos con ocho bits podemos tener 256 valores diferentes, que en byte corresponden a los valores entre 0 y 255. 509 | 510 | En C en lugar de utilizarse el byte la unidad “básica” es el **unsigned char**. 511 | Aunque su numero de bits es usualmente ocho no tiene por qué ser así y puede ser mayor. 512 | Dependerá del compilador. 513 | 514 | Para estar seguros del numero de bits por carácter lo mejor es verificar 515 | el valor de la macro _CHAR_BIT_, esta se define en el header _limits.h_. 516 | 517 | [[operadores-de-bits]] 518 | === Operadores de bits 519 | 520 | Ya hemos visto que las variables unsigned char están compuestas de bits. 521 | Pues bien, con los operadores de bits podemos manipular las variables 522 | por dentro. Los diferentes operadores de bits son: 523 | 524 | | OR (O) 525 | 526 | & AND (Y) 527 | 528 | ^ XOR (O exclusivo) 529 | 530 | ~ Complemento a uno o negación 531 | 532 | >> Desplazamiento a la derecha 533 | 534 | << Desplazamiento a la izquierda 535 | 536 | [[operador-or]] 537 | ==== Operador | (OR) 538 | 539 | Toma dos valores y hace con ellos la operación OR. 540 | Vamos a ver un ejemplo: 541 | 542 | [source,c] 543 | ---- 544 | #include 545 | #include 546 | 547 | int main() 548 | { 549 | printf( "El resultado de la operación 235 | 143 es: %i\n", 235 | 550 | 143 ); 551 | 552 | return EXIT_SUCCESS; 553 | 554 | } 555 | ---- 556 | 557 | Se obtiene: 558 | 559 | ---- 560 | El resultado de la operación 235 | 143 es: 239 561 | ---- 562 | 563 | Veamos la operación a nivel de bits: 564 | 565 | 235 -> 11101011 566 | 567 | 143 -> 10001111 | 568 | 569 | 239 -> 11101111 570 | 571 | La operación OR funciona de la siguiente manera: 572 | Tomamos los bits de cada uno de los valores y los comparamos si alguno de los bits es 1, se obtiene un uno. 573 | Si ambos bits son cero el resultado es cero. 574 | Primero se compara los dos primeros (el primero de cada uno de los números, 1 y 1 -> 1), luego la segunda pareja (1 y 0 -> 1) y así sucesivamente. 575 | 576 | [[operador-and]] 577 | ==== Operador & (AND) 578 | 579 | Este operador compara los bits también dos a dos. Si ambos son 1 el 580 | resultado es 1. Si no, el resultado es cero. 581 | 582 | [source,c] 583 | ---- 584 | #include 585 | #include 586 | 587 | int main() 588 | { 589 | printf( "El resultado de la operación 170 & 155 es: %i\n", 170 & 155 ); 590 | 591 | return EXIT_SUCCESS; 592 | } 593 | ---- 594 | 595 | Tenemos: 596 | 597 | ---- 598 | El resultado de la operación 170 & 155 es: 138 599 | ---- 600 | 601 | A nivel de bits: 602 | 603 | 170 -> 10101010 604 | 605 | 155 -> 10011011 & 606 | 607 | 138 -> 10001010 608 | 609 | [[operador-xor]] 610 | ==== Operador ^ (XOR) 611 | 612 | Compara los bits y los pone a unos si son distintos. Si son iguales el 613 | bit resultante es un cero. 614 | 615 | 235 -> 11101011 616 | 617 | 143 -> 10001111 ^ 618 | 619 | 100 -> 01100100 620 | 621 | [[operador-complemento-a-uno]] 622 | ==== Operador ~ (Complemento a uno) 623 | 624 | Este operador acepta un sólo dato (operando) y pone a 0 los 1 y a 1 los 0, es decir los invierte. 625 | Se pone delante del operando. 626 | 627 | [source,c] 628 | ---- 629 | 630 | #include 631 | #include 632 | 633 | int main() 634 | { 635 | 636 | printf( "El resultado de la operación ~152 es: %i\n", ~152 & 0xFF ); 637 | 638 | return EXIT_SUCCESS; 639 | 640 | } 641 | ---- 642 | 643 | ---- 644 | El resultado de la operación ~152 es: 103 645 | ---- 646 | 647 | Y a nivel de bits:name: value 648 | 649 | 152 -> 10011000 ~ 650 | 651 | 103 -> 01100111 652 | 653 | [[operador-desplazamiento-a-la-derecha]] 654 | ==== Operador >> (Desplazamiento a la derecha) 655 | 656 | Este operador mueve cada bit a la derecha. El bit de la izquierda se 657 | pone a cero, el de la derecha se pierde. Si después de usar este 658 | operador realizamos la operación inversa no recuperamos el número 659 | original. El formato es: 660 | 661 | variable o dato >> número de posiciones a desplazar 662 | 663 | El _número de posiciones a desplazar_ indica cuantas veces hay que mover 664 | los bits hacia la derecha. Ejemplo: 665 | 666 | [source,c] 667 | ---- 668 | #include 669 | #include 670 | 671 | int main() 672 | { 673 | 674 | printf("El resultado de 150U >> 2 es %u\n", 150U >> 2); 675 | 676 | return EXIT_SUCCESS; 677 | 678 | } 679 | ---- 680 | 681 | Salida: 682 | 683 | ---- 684 | El resultado de la operación 150 >> 2 es: 37 685 | ---- 686 | 687 | Veamos la operación paso a paso. 688 | Esta operación equivale a hacer dos desplazamientos a la derecha: 689 | 690 | 150 -> 10010110 Número original 691 | 692 | 75 -> 01001011 Primer desplazamiento. Entra un cero por la izquierda. El 693 | bit de la derecha se pierde. 694 | 695 | 37 -> 00100101 Segundo desplazamiento. 696 | 697 | .NOTA 698 | [NOTE] 699 | ==== 700 | Un desplazamiento a la derecha equivale a dividir por dos. 701 | Esto es muy interesante porque el desplazamiento es más rápido que la división. 702 | 703 | Si queremos optimizar un programa esta es una buena idea. 704 | Sólo sirve para dividir entre dos. 705 | Si hacemos dos desplazamientos sería dividir por dos dos veces, no por tres. 706 | ==== 707 | 708 | Los "bits de relleno", los que se añaden por la izquierda, son siempre 709 | ceros cuando el número al que hacemos la operación es un entero sin 710 | signo. 711 | 712 | En caso de que el desplazamiento se haga sobre un valor entero con signo 713 | hay un pequeño problema; los bits de relleno será uno o cero dependiendo 714 | del compilador. 715 | Por ejemplo: 716 | 717 | -1 >> 4 /* No se puede predecir el resultado */ 718 | 719 | El rango válido para el desplazamiento va desde 0 hasta (sizeof(int) * 720 | CHAR_BIT) - 1. 721 | 722 | [[operador-desplazamiento-a-la-izquierda]] 723 | ==== Operador << (Desplazamiento a la izquierda) 724 | 725 | Funciona igual que la anterior pero los bits se desplazan a la 726 | izquierda. Esta operación equivale a multiplicar por 2. 727 | 728 | [[operador-sizeof]] 729 | === Operador Sizeof 730 | 731 | Este es un operador muy útil. Nos permite conocer el tamaño en bytes de una variable. 732 | De esta manera no tenemos que preocuparnos en recordar o calcular cuanto ocupa. 733 | Además el tamaño de una variable cambia de un compilador a otro, es la mejor forma de asegurarse. 734 | Se usa poniendo el nombre de la variable después de sizeof y separado de un espacio: 735 | 736 | [source,c] 737 | ---- 738 | #include 739 | #include 740 | 741 | int main() 742 | { 743 | int variable; 744 | 745 | printf( "Tamaño de la variable: %lu\n", 746 | (unsigned long) sizeof (variable) ); 747 | 748 | return EXIT_SUCCESS; 749 | 750 | } 751 | ---- 752 | 753 | *NOTA:* Como se puede apreciar, para mostrar el tamaño de la variable hemos usado %lu en lugar de %i. 754 | Esto es así porque _sizeof_ devuelve un valor del tipo _size_t_ y el estándar ISO-C90 sólo especifica que size_t 755 | debe ser un entero sin signo (puede ser un __int__, _short int_ o __long int__). 756 | Para asegurarnos que mostramos correctamente su valor debemos usar %lu en lugar de %i. 757 | 758 | También se puede usar con los especificadores de tipos de datos (char, int, float, double...) para averiguar su tamaño: 759 | 760 | [source,c] 761 | ---- 762 | #include 763 | #include 764 | 765 | int main() 766 | { 767 | 768 | printf( "Las variables tipo int ocupan: %lu\n", 769 | 770 | (unsigned long) sizeof(**int**) ); 771 | 772 | return EXIT_SUCCESS; 773 | 774 | } 775 | ---- 776 | 777 | [[otros-operadores]] 778 | === Otros operadores 779 | 780 | Existen además de los que hemos visto otros operadores. 781 | Sin embargo ya veremos en sucesivos capítulos lo que significa cada uno. 782 | 783 | [[orden-de-evaluación-de-operadores]] 784 | === Orden de evaluación de Operadores 785 | 786 | Debemos tener cuidado al usar operadores pues a veces podemos tener resultados no esperados si no tenemos en cuenta su orden de evaluación. 787 | Vamos a ver la lista de precedencias, cuanto más arriba se evalúa antes: 788 | 789 | Precedencia 790 | 791 | ---- 792 | () [] -> . 793 | 794 | ! ~ ++ -- (molde) * & sizeof (El * es el de puntero) 795 | 796 | * / % (El * de aquí es el de multiplicación) 797 | 798 | + - 799 | 800 | << >> 801 | 802 | < <= > >= 803 | 804 | == != 805 | 806 | & 807 | 808 | ^ 809 | 810 | | 811 | 812 | && 813 | 814 | || 815 | 816 | ?: 817 | 818 | = += -= *= /= 819 | 820 | , 821 | ---- 822 | 823 | Por ejemplo imaginemos que tenemos la siguiente operación: 824 | 825 | 10 * 2 + 5 826 | 827 | Si vamos a la tabla de precedencias vemos que el * tiene un orden 828 | superior al +, por lo tanto primero se hace el producto 10*2=20 y luego 829 | la suma 20+5=25. 830 | 831 | Veamos otra: 832 | 833 | 10 * ( 2 + 5 ) 834 | 835 | Ahora con el paréntesis cambia el orden de evaluación. 836 | El que tiene mayor precedencia ahora es el paréntesis, se ejecuta primero. 837 | Como dentro del paréntesis sólo hay una suma se evalúa sin más, 2+5=7. 838 | Ya solo queda la multiplicación 10*7=70. 839 | 840 | Otro caso: 841 | 842 | 10 * ( 5 * 2 + 3 ) 843 | 844 | Como antes, el que mayor precedencia tiene es el paréntesis, se evalúa primero. 845 | Dentro del paréntesis tenemos producto y suma. 846 | Como sabemos ya se evalúa primero el producto, 5*2=10. Seguimos en el paréntesis, nos queda la suma 10+3=13. 847 | Hemos acabado con el paréntesis, ahora al resto de la expresión. 848 | Cogemos la multiplicación que queda: 849 | 850 | 10*13=130 851 | 852 | Otro detalle que debemos cuidar son los operadores ++ y --. 853 | Es mejor no usar los operadores ++ y -- mezclados con otros, pues puede ser confuso y a veces obtenemos resultados inesperados. 854 | Por ejemplo: 855 | 856 | [source,c] 857 | ---- 858 | #include 859 | #include 860 | 861 | int main() 862 | { 863 | 864 | int a; 865 | 866 | a = 5; 867 | 868 | printf( "a = %i\n", a++ ); 869 | 870 | return EXIT_SUCCESS; 871 | 872 | } 873 | ---- 874 | 875 | El resultado sería: 876 | 877 | ---- 878 | a = 5 879 | ---- 880 | 881 | Para evitar confusiones lo mejor sería separar la línea donde se usa el ++: 882 | 883 | [source,c] 884 | ---- 885 | #include 886 | #include 887 | 888 | int main() 889 | { 890 | 891 | int a; 892 | 893 | a = 5; 894 | a++; 895 | 896 | printf( "a = %i\n", a ); 897 | 898 | return EXIT_SUCCESS; 899 | 900 | } 901 | ---- 902 | 903 | [[ejercicios]] 904 | === Ejercicios 905 | 906 | *Ejercicio 1:* En este programa hay un fallo muy gordo y muy habitual en 907 | programación. A ver si lo encuentras: 908 | 909 | [source,c] 910 | ---- 911 | #include 912 | #include 913 | 914 | int main() 915 | { 916 | 917 | int a, c; 918 | 919 | a = 5; 920 | 921 | c += a +5; 922 | 923 | return EXIT_SUCCESS; 924 | 925 | } 926 | ---- 927 | 928 | Solución: 929 | 930 | Cuando calculamos el valor de 'c' sumamos a+5 ( =10 ) al valor de 'c'. 931 | Pero resulta que 'c' no tenía ningún valor indicado por nosotros. 932 | Estamos usando la variable 'c' sin haberle dado valor. En algunos 933 | compiladores el resultado será inesperado. Este es un fallo bastante 934 | habitual, usar variables a las que no hemos dado ningún valor. 935 | 936 | *Ejercicio 2:* ¿Cual será el resultado del siguiente programa? 937 | 938 | [source,c] 939 | ---- 940 | #include 941 | #include 942 | 943 | int main() 944 | { 945 | 946 | int a, b, c; 947 | 948 | a = 5; 949 | b = ++a; 950 | c = ( a + 5 * 2 ) * ( b + 6 / 2 ) + ( a * 2 ); 951 | 952 | printf( "%i, %i, %i", a, b, c ); 953 | 954 | return EXIT_SUCCESS; 955 | 956 | } 957 | ---- 958 | 959 | Solución: 960 | 961 | El resultado es 156. En la primera a vale 5. Pero en la segunda se 962 | ejecuta b = ++a = ++5 = 6. Tenemos a = b = 6. 963 | 964 | *Ejercicio 3:* Escribir un programa que compruebe si un número es par o 965 | impar. 966 | 967 | Solución: 968 | 969 | [source,c] 970 | ---- 971 | #include 972 | #include 973 | 974 | int main() \{ 975 | 976 | int a; 977 | 978 | a = 124; 979 | 980 | if ( a % 2 == 0 ) { 981 | printf( "%d es par\n", a ); 982 | } 983 | else { 984 | printf( "%d es impar\n", a ); 985 | } 986 | 987 | printf( "\n" ); 988 | 989 | return EXIT_SUCCESS; 990 | 991 | } 992 | ---- 993 | 994 | Para comprobar si un número es par o impar podemos usar el operador '%'. 995 | Si al calcular el resto de dividir un número por 2 el resultado es cero eso indica que el número es par. 996 | Si el resto es distinto de cero el número es impar. 997 | 998 | === ¿Dudas? ¿Errores? 999 | 1000 | Si tienes dudas sobre este capítulo plantéalas en el foro: 1001 | 1002 | https://elrincondelc.com/foros/viewforum.php?f=51 1003 | 1004 | Si has encontrado algún error o quieres sugerir cambios entra aquí: 1005 | 1006 | https://github.com/gorkau/Libro-Programacion-en-C/blob/master/capitulo5.adoc 1007 | -------------------------------------------------------------------------------- /capitulo06.adoc: -------------------------------------------------------------------------------- 1 | //// 2 | Copyright: Gorka Urrutia Landa, 1999-2018 3 | Licencia: Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) https://creativecommons.org/licenses/by-sa/4.0/ 4 | //// 5 | 6 | :chapter: 006 7 | 8 | <<< 9 | 10 | [[capítulo-6.-introducir-datos-por-teclado]] 11 | == Capítulo 6. Introducir datos por teclado 12 | 13 | [[introducción]] 14 | === Introducción 15 | 16 | Algo muy usual en un programa es esperar que el usuario introduzca datos por el teclado. 17 | Para ello contamos con varias posibilidades: Usar las 18 | funciones de la biblioteca estándar, crear nuestras propias 19 | interrupciones de teclado o usar funciones de alguna biblioteca 20 | diferente (como por ejemplo Allegro). 21 | 22 | Nosotros en este capítulo vamos a estudiar la primera opción (biblioteca 23 | estándar) mediante el uso de la función _scanf_ y también la tercera 24 | opción (bibliotecas de terceros) mediante el uso de las funciones 25 | _getch_ y _getche_. Estas ultimas solo funcionan con los compiladores 26 | que soporten la biblioteca _conio_ de Borland. Pero antes veamos por 27 | encima las otras posibilidades. 28 | 29 | Las funciones estándar están bien para un programa sencillito. Pero 30 | cuando queremos hacer juegos por ejemplo, no suelen ser suficiente. 31 | Demasiado lentas o no nos dan todas las posibilidades que buscamos, como 32 | comprobar si hay varias teclas pulsadas. Para solucionar esto tenemos 33 | dos posibilidades: 34 | 35 | La más complicada es crear nuestras propias interrupciones de teclado. 36 | ¿Qué es una interrupción de teclado? Es un pequeño programa en memoria 37 | que se ejecuta continuamente y comprueba el estado del teclado. Podemos 38 | crear uno nuestro y hacer que el ordenador use el que hemos creado en 39 | vez del suyo. Este tema no lo vamos a tratar ahora, quizás en algún 40 | capítulo posterior. 41 | 42 | Otra posibilidad más sencilla es usar una biblioteca que tenga funciones 43 | para controlar el teclado. Por ejemplo si usamos la biblioteca Allegro, 44 | ella misma hace todo el trabajo y nosotros no tenemos más que recoger 45 | sus frutos con un par de sencillas instrucciones. Esto soluciona mucho 46 | el trabajo y nos libra de tener que aprender cómo funcionan los aspectos 47 | más oscuros del control del teclado. 48 | 49 | Vamos ahora con las funciones de la biblioteca estándar. 50 | 51 | [[scanf]] 52 | === Scanf 53 | 54 | El uso de scanf es muy similar al de printf con una diferencia, nos da la posibilidad de que el usuario introduzca datos en vez de mostrarlos. 55 | No nos permite mostrar texto en la pantalla, por eso si queremos mostrar un mensaje usamos un printf delante. 56 | 57 | El formato de _scanf_ es: 58 | 59 | [source,c] 60 | ---- 61 | scanf( "%d", &var ); 62 | ---- 63 | 64 | Donde: 65 | 66 | * %d puede ser un modificador de los que ya habíamos visto en el _printf_. 67 | En la sección “link:#anchor[Modificadores]” hay una lista de modificadores que se pueden usar. 68 | * _var_ es la variable donde se va a almacenar el valor que teclee el usuario. 69 | 70 | Un ejemplo: 71 | 72 | [source,c] 73 | ---- 74 | #include 75 | #include 76 | 77 | int main() 78 | { 79 | int num; 80 | 81 | printf( "Introduce un número: " ); 82 | 83 | fflush(stdout); 84 | 85 | scanf( "%d", &num ); 86 | 87 | printf( "Has tecleado el número %d\n", num ); 88 | 89 | return EXIT_SUCCESS; 90 | } 91 | 92 | ---- 93 | 94 | *NOTA 1:* En este ejemplo hemos usado el modificador %d en lugar de %i. 95 | Si usamos el modificador %i puede llevar a resultados inesperados debido 96 | a que %i acepta tanto números en base 10 como en base 8 (octal) y 16 97 | (hexadecimal). 98 | 99 | Por ejemplo si se introduce el número 0123 éste no se interpreta (como 100 | es de esperarse) como un número decimal sino como un número octal. 101 | El resultado del programa sería: 102 | 103 | ---- 104 | Introduce un numero: 0123 105 | 106 | Has tecleado el numero 83 107 | ---- 108 | 109 | NOTE: Quizás te estés preguntando qué es eso de _fflush( stdout )_. 110 | Cuando usamos la función printf, no escribimos directamente 111 | en la pantalla, sino en una memoria intermedia (lo que llaman un 112 | _buffer_). 113 | Cuando este _buffer_ se llena o cuando metemos un carácter '\n' es cuando se envía el texto a la pantalla. 114 | En algunos compiladores es posible que el texto “Introduce una letra:” no se muestre sin el _fflush_ (pruébalo en el tuyo). 115 | 116 | Primero vamos a ver unas nota de estética, para hacer los programas un poco más elegantes. 117 | Parece una tontería, pero los pequeños detalles hacen que un programa gane mucho. 118 | El _scanf_ no mueve el cursor de su posición actual, así que en nuestro ejemplo queda: 119 | 120 | ---- 121 | Introduce un número _ 122 | ---- 123 | 124 | NOTE: La barra horizontal indica dónde esta el cursor. 125 | 126 | Esto es porque en el printf no hemos puesto al final el símbolo de salto 127 | de línea '\n'. 128 | Además hemos dejado un espacio al final de _Introduce un número:_ para que así cuando tecleemos el número no salga pegado al mensaje. 129 | Si no hubiésemos dejado el espacio quedaría así al introducir el número 120 (es un ejemplo): 130 | 131 | ---- 132 | Introduce un número120 133 | ---- 134 | 135 | Bueno, esto es muy interesante pero vamos a dejarlo y vamos al grano. 136 | Veamos cómo funciona el _scanf_. 137 | Lo primero nos fijamos que hay una cadena entre comillas. 138 | Esta es similar a la de _printf_, nos sirve para indicarle al programa qué tipo de datos puede aceptar. 139 | 140 | En el ejemplo, al usar %d, estábamos diciendo al programa que acepte 141 | únicamente números enteros decimales (en base 10). 142 | 143 | Después de la coma tenemos la variable donde almacenamos el dato, en este caso 'num'. 144 | 145 | Fíjate que en el _scanf_ la variable 'num' lleva delante el símbolo &. 146 | Éste es muy importante; sirve para indicar al compilador cuál es la dirección (o posición en la memoria) de la variable. 147 | Por ahora no te preocupes por eso, ya volveremos más adelante sobre el tema. 148 | 149 | Podemos pedir al usuario más de un dato a la vez en un sólo _scanf_. 150 | Para eso hay que poner un modificador por cada variable: 151 | 152 | [source,c] 153 | ---- 154 | #include 155 | #include 156 | 157 | int main() 158 | { 159 | 160 | int a, b, c; 161 | 162 | printf( "Introduce tres números: " ); 163 | 164 | fflush(stdout); 165 | 166 | scanf( "%d %d %d", &a, &b, &c ); 167 | 168 | printf( "Has tecleado los números %d %d %d\n", a, b, c ); 169 | 170 | return EXIT_SUCCESS; 171 | } 172 | 173 | ---- 174 | 175 | De esta forma cuando el usuario ejecuta el programa debe introducir los tres datos separados por un espacio. 176 | 177 | También podemos pedir en un mismo scanf variables de distinto tipo: 178 | 179 | [source,c] 180 | ---- 181 | #include 182 | #include 183 | 184 | int main() 185 | { 186 | int a; 187 | float b; 188 | 189 | printf( "Introduce dos numeros: " ); 190 | 191 | fflush(stdout); 192 | 193 | scanf( "%d %f", &a, &b ); 194 | 195 | printf( "Has tecleado los numeros %d %f\n", a, b ); 196 | 197 | return EXIT_SUCCESS; 198 | } 199 | ---- 200 | 201 | A cada modificador (%d, %f) le debe corresponder una variable de su mismo tipo. 202 | Es decir, al poner un %d el compilador espera que su variable correspondiente sea de tipo int. 203 | Si ponemos %f espera una variable tipo float. 204 | 205 | [[modificadores]] 206 | === [[anchor]]Modificadores 207 | 208 | Hemos visto que cuando el dato introducido lo queremos almacenar en una variable tipo int usamos el modificador %d. 209 | Cada variable usa un modificador diferente. 210 | 211 | [cols=",",] 212 | |======================================================= 213 | |int: entero. Puede ser decimal, octal o hexadecimal |%i 214 | |int: entero decimal |%d 215 | |unsigned int: entero decimal sin signo |%u 216 | |int: entero octal |%o 217 | |int: entero hexadecimal |%x 218 | |float |%f 219 | |double |%lf 220 | |char |%c 221 | |cadena de caracteres |%s 222 | |======================================================= 223 | 224 | [[ejercicios]] 225 | === Ejercicios 226 | 227 | *Ejercicio 1:* Busca el error en el siguiente programa: 228 | 229 | [source,c] 230 | ---- 231 | #include 232 | #include 233 | 234 | int main() 235 | { 236 | int numero; 237 | 238 | printf( "Introduce un numero: " ); 239 | 240 | scanf( "%d", numero ); 241 | 242 | printf( "\nHas introducido el número %d.\n", numero ); 243 | 244 | return EXIT_SUCCESS; 245 | } 246 | ---- 247 | 248 | Solución: 249 | 250 | A la variable número le falta el '&' con lo que no estamos indicando al 251 | programa la dirección de la variable y no obtendremos el resultado 252 | deseado. 253 | Haz la prueba y verás que el mensaje "Has introducido el número X" no muestra el número que habías introducido. 254 | 255 | *Ejercicio 2:* Escribe un programa que pida 3 números: un float, un 256 | double y un int y a continuación los muestre por pantalla. 257 | 258 | Solución: 259 | 260 | [source,c] 261 | ---- 262 | #include 263 | #include 264 | 265 | int main() 266 | { 267 | float num1; 268 | double num2; 269 | int num3; 270 | 271 | printf( "Introduce 3 numeros: " ); 272 | 273 | scanf( "%f %lf %i", &num1, &num2, &num3 ); 274 | 275 | printf ( "\nNumeros introducidos: %f %f %i\n", 276 | num1, num2, num3 ); 277 | 278 | return EXIT_SUCCESS; 279 | } 280 | ---- 281 | 282 | === ¿Dudas? ¿Errores? 283 | 284 | Si tienes dudas sobre este capítulo plantéalas en el foro: 285 | 286 | https://elrincondelc.com/foros/viewforum.php?f=52 287 | 288 | Si has encontrado algún error o quieres sugerir cambios entra aquí: 289 | 290 | https://github.com/gorkau/Libro-Programacion-en-C/blob/master/capitulo6.adoc 291 | -------------------------------------------------------------------------------- /capitulo07.adoc: -------------------------------------------------------------------------------- 1 | //// 2 | Copyright: Gorka Urrutia Landa, 1999-2018 3 | Licencia: Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) https://creativecommons.org/licenses/by-sa/4.0/ 4 | //// 5 | 6 | :chapter: 007 7 | 8 | <<< 9 | 10 | [[capítulo-7.-sentencias-de-control-de-flujo]] 11 | == Capítulo 7. Sentencias de control de flujo 12 | 13 | [[introducción]] 14 | === Introducción 15 | 16 | Hasta ahora los programas que hemos visto eran lineales. 17 | Comenzaban por la primera instrucción y acababan por la última, ejecutándose todas una sola vez. 18 | Lógico ¿no?. 19 | Pero resulta que muchas veces no es esto lo que queremos que ocurra. 20 | Lo que nos suele interesar es que dependiendo de los valores de los datos se ejecuten unas instrucciones y no otras. O 21 | también puede que queramos repetir unas instrucciones un número determinado de veces. 22 | Para esto están las sentencia de control de flujo. 23 | 24 | [[bucles]] 25 | === Bucles 26 | 27 | Los bucles nos ofrecen la solución cuando queremos repetir una tarea un número determinado de veces. 28 | Supongamos que queremos escribir 100 veces la palabra hola. 29 | Con lo que sabemos hasta ahora haríamos: 30 | 31 | [source,c] 32 | ---- 33 | #include 34 | #include 35 | 36 | int main() 37 | { 38 | 39 | printf( "Hola\n"); 40 | printf( "Hola\n"); 41 | printf( "Hola\n"); 42 | printf( "Hola\n"); 43 | printf( "Hola\n"); 44 | ... (y así hasta 100 veces) 45 | 46 | return EXIT_SUCCESS; 47 | 48 | } 49 | ---- 50 | 51 | ¡Menuda locura! Y si queremos repetirlo más veces nos quedaría un programa de lo más largo. 52 | 53 | Sin embargo usando un *bucle _for_* (ya lo veremos con calma en un rato) el programa quedaría: 54 | 55 | [source,c] 56 | ---- 57 | #include 58 | #include 59 | 60 | int main() 61 | { 62 | int i; 63 | 64 | for ( i=0 ; i<100 ; i++ ) 65 | { 66 | printf( "Hola\n" ); 67 | } 68 | 69 | return EXIT_SUCCESS; 70 | } 71 | ---- 72 | 73 | 74 | Con lo que tenemos un programa más corto. 75 | 76 | [[el-bucle-for]] 77 | ==== El bucle For 78 | 79 | El formato del bucle for es el siguiente: 80 | 81 | [source,c] 82 | ---- 83 | for( valores iniciales; condiciones; incrementos/cambios ) 84 | { 85 | /* conjunto de instrucciones a ejecutar en el bucle */ 86 | } 87 | ---- 88 | 89 | El bucle for tiene tres partes: 90 | 91 | * Valores iniciales: En esta parte damos los valores iniciales a nuestro bucle, para empezar el bucle como más nos convenga. 92 | * Condiciones: antes de comenzar cada ciclo del bucle comprobamos si se cumplen ciertas condiciones. 93 | Si se cumplen se ejecuta el conjunto de instrucciones del bucle. 94 | * Incrementos/cambios: esta parte se ejecuta después del conjunto de instrucciones. 95 | Hacemos algún cambio en alguna de las variables que hemos usado en la parte de condiciones y pasamos al siguiente ciclo del __for__. 96 | 97 | Vamos a verlo con el ejemplo anterior: 98 | 99 | [source,c] 100 | ---- 101 | for ( i=0 ; i<100 ; i++ ) 102 | ---- 103 | 104 | Las tres partes antes mencionadas serían: 105 | 106 | * En este caso usamos la variable _i_ para controlar nuestro bucle. 107 | Asignamos a esta variable el valor inicial 0. 108 | Esa es la parte de _valores iniciales_. 109 | * Luego tenemos _i<100_. 110 | Esa es la parte _condiciones_. 111 | En este caso la condición es que _i_ sea menor que 100, de modo que el bucle continuará mientras _i_ sea menor que 100. 112 | Es decir, mientras se cumpla la condición. 113 | Si se cumple se ejecuta el bloque de instrucciones del _for_. 114 | Si no se cumple la condición damos el bucle por terminado y el programa continúa. 115 | * Luego tenemos la parte de _incrementos_, donde indicamos cuánto se incrementa la variable. 116 | En el ejemplo le sumamos uno a la variable _i_. 117 | 118 | *¿Cómo funciona el for?* 119 | 120 | * La primera vez que el programa llega al _for_ se asigna un valor inicial a _i_. 121 | * A continuación se comprueba la condición. 122 | * Como i tiene el valor 0 se cumple. 123 | * Se ejecuta el bloque de instrucciones que está justo después del for. 124 | * El programa va a la sección de incrementos y ve que tiene que incrementar el valor de _i_ en 1. 125 | * Se comprueba la condición otra vez. 126 | * ... 127 | * Repetimos hasta que ya no se cumpla la condición (_i_ coge el valor 100). 128 | 129 | El _for_ va delante del grupo de instrucciones a ejecutar. 130 | Si la condición es falsa desde el principio, esas instrucciones no se ejecutan ni una sola vez. 131 | Por ejemplo: 132 | 133 | [source,c] 134 | ---- 135 | #include 136 | #include 137 | 138 | int main() 139 | { 140 | char i; 141 | 142 | for (i=0; i<0; i++) { 143 | printf("Me siento tan invisible \n"); 144 | } 145 | 146 | return EXIT_SUCCESS; 147 | } 148 | ---- 149 | 150 | Este programa no va a mostrar nada porque el _printf_ no llega a ejecutarse nunca. 151 | 152 | Cuidado: No se debe poner un ";" justo después de la sentencia for. 153 | Si lo hacemos entonces sería un bucle vacío y las instrucciones siguientes sólo se ejecutarían una vez. 154 | Veamoslo con un ejemplo: 155 | 156 | [source,c] 157 | ---- 158 | #include 159 | #include 160 | 161 | int main() 162 | { 163 | int i; 164 | 165 | for ( i=0 ; i<100 ; i++ ); /* Cuidado con este punto y coma */ 166 | { 167 | printf( "Hola\n" ); 168 | } 169 | 170 | return EXIT_SUCCESS; 171 | } 172 | ---- 173 | 174 | Este programa sólo escribirá en pantalla: 175 | 176 | ---- 177 | Hola 178 | ---- 179 | 180 | una sola vez. 181 | El bucle se ejecuta pero el ';' hace que el bloque que viene a continuación no se considere parte del _for_. 182 | 183 | También puede suceder que quieras ejecutar un cierto número de veces una sola instrucción (como sucede en nuestro ejemplo). 184 | Entonces no necesitas las llaves "\{}": 185 | 186 | [source,c] 187 | ---- 188 | #include 189 | #include 190 | 191 | int main() 192 | { 193 | int i; 194 | 195 | for ( i=0 ; i<100 ; i++ ) printf( "Hola\n" ); 196 | 197 | return EXIT_SUCCESS; 198 | } 199 | ---- 200 | 201 | o también: 202 | 203 | [source,c] 204 | ---- 205 | for ( i=0 ; i<100 ; i++ ) 206 | printf( "Hola\n" ); 207 | ---- 208 | 209 | Sin embargo, yo me he encontrado muchas veces que es mejor poner las llaves aunque sólo haya una instrucción; 210 | a veces al añadir una segunda instrucción más tarde se te olvidan las comillas y no te das cuenta. 211 | Parece una tontería, pero muchas veces, cuando programas, son estos los pequeños fallos los que te vuelven loco. 212 | 213 | En otros lenguajes, como Basic, la sentencia for es muy rígida. 214 | En cambio en C es muy flexible. 215 | Se puede omitir cualquiera de las secciones (inicialización, condiciones o incrementos). 216 | También se pueden poner más de una variable a inicializar, más de una condición y más de un incremento. 217 | Por ejemplo, el siguiente programa sería perfectamente correcto: 218 | 219 | [source,c] 220 | ---- 221 | #include 222 | #include 223 | 224 | int main() 225 | { 226 | int i, j; 227 | 228 | for( i=0, j=5 ; i<10 ; i++, j=j+5 ) 229 | { 230 | printf( "Hola " ); 231 | printf( "Esta es la línea %i", i ); 232 | printf( "j vale = %i\n", j ); 233 | } 234 | 235 | return EXIT_SUCCESS; 236 | } 237 | ---- 238 | 239 | 240 | Como vemos en el ejemplo tenemos más de una variable en la sección de inicialización y en la de incrementos. 241 | También podíamos haber puesto más de una condición. 242 | Los elementos de cada sección se separan por comas. 243 | Cada sección se separa por punto y coma. 244 | 245 | [[bucles-infinitos]] 246 | ===== Bucles infinitos 247 | 248 | Entramos en un bucle infinito cuando nuestro for nunca termina. 249 | Esta es una situación a evitar y puede ocurrir si no tenemos cuidado. 250 | Con un _for_ un bucle infinito puede ocurrir cuando: 251 | 252 | 1) No usamos la condición: 253 | 254 | En caso de omitirse la condición el bucle se ejecuta continuamente sin detenerse. 255 | A este tipo de bucle se le conoce como 'endless loop' o 'bucle infinito'. 256 | Por ejemplo: 257 | 258 | [source,c] 259 | ---- 260 | #include 261 | #include 262 | 263 | int main() 264 | { 265 | int i, j; 266 | 267 | for( i=0; ; i++ ) { 268 | printf( "Este bucle no terminará nunca." ); 269 | } 270 | 271 | return EXIT_SUCCESS; 272 | } 273 | ---- 274 | 275 | 276 | Este ejemplo estará ejecutándose indefinidamente porque el bucle _for_ no tiene una condición de finalización. 277 | Lo mismo ocurriría con, por ejemplo, este otro: 278 | 279 | for( ; ; ) 280 | 281 | 2) No usamos incrementos: 282 | 283 | Si no hay nada que cambie en cada ciclo, el _for_ no puede “avanzar”: 284 | 285 | [source,c] 286 | ---- 287 | #include 288 | #include 289 | 290 | int main() 291 | { 292 | int i; 293 | 294 | for (i=0; i<10; ) { 295 | printf("Soy un bucle infinito\n"); 296 | } 297 | 298 | return EXIT_SUCCESS; 299 | } 300 | ---- 301 | 302 | En este ejemplo _i_ nunca será mayor que 10 puesto que su valor no cambia nunca. 303 | 304 | 3) La condición se cumple siempre: 305 | 306 | [source,c] 307 | ---- 308 | #include 309 | #include 310 | 311 | int main() 312 | { 313 | char i; 314 | 315 | for (i=0; i==i; i++) { 316 | printf("Soy un bucle infinito\n"); 317 | } 318 | 319 | return EXIT_SUCCESS; 320 | } 321 | ---- 322 | 323 | En este caso siempre se va a cumplir que i==i por lo tanto el bucle no terminará nunca. 324 | 325 | [[while]] 326 | ==== While 327 | 328 | 329 | El formato del bucle while es es siguiente: 330 | 331 | [source,c] 332 | ---- 333 | while ( condición ) 334 | { 335 | /* bloque de instrucciones a ejecutar */ 336 | } 337 | ---- 338 | 339 | _While_ quiere decir _mientras_. 340 | Aquí se ejecuta el bloque de instrucciones mientras se cumpla la condición impuesta en while. 341 | 342 | Vamos a ver un ejemplo: 343 | 344 | [source,c] 345 | ---- 346 | #include 347 | #include 348 | 349 | int main() 350 | { 351 | int contador = 0; 352 | 353 | while ( contador<100 ) { 354 | contador++; 355 | printf( "Ya voy por el %i, pararé enseguida.\n", contador ); 356 | } 357 | 358 | return EXIT_SUCCESS; 359 | } 360 | ---- 361 | 362 | Este programa imprime en pantalla los valores del 1 al 100. 363 | Cuando i=100 ya no se cumple la condición. 364 | Un detalle importante: si hubiésemos cambiado el orden de las instrucciones a ejecutar tendríamos un resultado diferente: 365 | 366 | [source,c] 367 | ---- 368 | printf( "Ya voy por el %i, pararé enseguida.\n", contador ); 369 | contador++; 370 | ---- 371 | 372 | En esta ocasión se imprimen los valores del 0 al 99. 373 | Cuidado con ésto, que a veces produce errores difíciles de encontrar. 374 | 375 | [[do-while]] 376 | ==== Do While 377 | 378 | El formato del bucle do-while es: 379 | 380 | [source,c] 381 | ---- 382 | do 383 | { 384 | /* instrucciones a ejecutar */ 385 | } while ( condición ); 386 | ---- 387 | 388 | La diferencia entre _while_ y _do-while_ es que en este último, la condición va despues del conjunto de instrucciones a ejecutar. 389 | De esta forma, esas instrucciones se ejecutan al menos una vez. 390 | 391 | Su uso es similar al de _while_. 392 | 393 | [[sentencias-de-condición]] 394 | === Sentencias de condición 395 | 396 | Hasta aquí hemos visto cómo podemos repetir un conjunto de instrucciones las veces que deseemos. 397 | Pero ahora vamos a ver cómo podemos controlar totalmente el flujo de un programa. 398 | Dependiendo de los valores de alguna variable se tomarán unas acciones u otras. 399 | Empecemos con la sentencia _if_. 400 | 401 | [[if]] 402 | ==== If 403 | 404 | La palabra _if_ significa _si_ (condicional), pero supongo que esto ya 405 | lo sabías. Su formato es el siguiente: 406 | 407 | [source,c] 408 | ---- 409 | if ( condición ) 410 | { 411 | /* instrucciones a ejecutar */ 412 | } 413 | ---- 414 | 415 | Cuando se cumple la condición entre paréntesis se ejecuta el bloque inmediatamente siguiente al if (bloque _instrucciones a ejecutar_). 416 | 417 | En el siguiente ejemplo tenemos un programa que nos pide un número, si ese número es 10 se muestra un mensaje. 418 | Si no es 10 no se muestra ningún mensaje: 419 | 420 | [source,c] 421 | ---- 422 | #include 423 | #include 424 | 425 | int main() 426 | { 427 | int num; 428 | 429 | printf( "Introduce un numero: " ); 430 | fflush(stdout); 431 | scanf( "%i", &num ); 432 | 433 | if (num==10) { 434 | printf( "El numero es igual a 10.\n" ); 435 | } 436 | 437 | return EXIT_SUCCESS; 438 | } 439 | ---- 440 | 441 | Como siempre, la condición es falsa si es igual a cero. 442 | Si es distinta de cero será verdadera. 443 | 444 | [[if---else]] 445 | ==== If - Else 446 | 447 | El formato es el siguiente: 448 | 449 | [source,c] 450 | ---- 451 | if ( condición ) 452 | { 453 | /* bloque que se ejecuta si se cumple la condición */ 454 | } 455 | else 456 | { 457 | /* bloque que se ejecuta si no se cumple la condición */ 458 | } 459 | ---- 460 | 461 | En el _if_ del apartado anterior si no se cumplía la condición no se ejecutaba el bloque siguiente y el programa seguía su curso normal. 462 | Con el _if-else_ tenemos un bloque adicional que sólo se ejecuta si no se cumple la condición. 463 | Veamos un ejemplo: 464 | 465 | [source,c] 466 | ---- 467 | #include 468 | #include 469 | 470 | int main() 471 | { 472 | int a; 473 | 474 | printf( "Introduce un numero: " ); 475 | fflush(stdout); 476 | scanf( "%i", &a ); 477 | 478 | if ( a==8 ) { 479 | printf ( "El numero introducido era un ocho.\n" ); 480 | } 481 | else { 482 | printf ( "Pero si no has escrito un ocho!!!\n" ); 483 | } 484 | 485 | return EXIT_SUCCESS; 486 | } 487 | ---- 488 | 489 | Al ejecutar el programa si introducimos un 8 se ejecuta el bloque siguiente al _if_ y se muestra el mensaje: 490 | 491 | El numero introducido era un ocho. 492 | 493 | Si escribimos cualquier otro número se ejecuta el bloque siguiente al else mostrándose el mensaje: 494 | 495 | ---- 496 | Pero si no has escrito un ocho!!! 497 | ---- 498 | 499 | [[if-else-if]] 500 | ==== If else if 501 | 502 | Se pueden poner if else anidados si se desea: 503 | 504 | [source,c] 505 | ---- 506 | #include 507 | #include 508 | 509 | int main() 510 | { 511 | int a; 512 | 513 | printf( "Introduce un numero: " ); 514 | fflush(stdout); 515 | scanf( "%i", &a ); 516 | 517 | if ( a<10 ) { 518 | printf ( "El numero introducido era menor de 10.\n" ); 519 | } 520 | else if ( a>=10 && a<=100 ) { 521 | printf ( "El numero esta entre 10 y 100\n" ); 522 | } 523 | else if ( a>100 ) { 524 | printf( "El numero es mayor que 100\n" ); 525 | } 526 | 527 | printf( "Fin del programa.\n" ); 528 | 529 | return EXIT_SUCCESS; 530 | } 531 | ---- 532 | 533 | *NOTA:* El símbolo && de la condición del segundo if es un AND (Y). 534 | De esta forma la condición queda: Si a es mayor que 10 Y a es menor que 100. 535 | Consulta la sección link:#anchor[Notas sobre las condiciones ] para saber más. 536 | 537 | Podemos poner todos los if else que queramos. 538 | Si la condición del primer if es verdadera se muestra el mensaje "El número introducido era menor de 10" y se saltan todos los if-else siguientes (se muestra el mensaje "Fin del programa"). 539 | Si la condición es falsa se ejecuta el siguiente else-if y se comprueba si a está entre 10 y 100. 540 | Si es cierto se muestra “El número está entre 10 y 100”. 541 | Si no es cierto se evalúa el último else-if. 542 | 543 | [[el-otro-if-else]] 544 | ==== ? (el otro if-else) 545 | 546 | El uso de la interrogación es una forma de condensar un if-else. 547 | Su formato es el siguiente: 548 | 549 | [source,c] 550 | ---- 551 | ( condicion ) ? ( instrucción 1 ) : ( instrucción 2 ) 552 | ---- 553 | 554 | Si se cumple la condición se ejecuta la _instrucción 1_ y si no se ejecuta la _instrucción 2_. 555 | Veamos un ejemplo con el if-else y luego lo reescribimos con "?": 556 | 557 | [source,c] 558 | ---- 559 | #include 560 | #include 561 | 562 | int main() 563 | { 564 | int a; 565 | int b; 566 | 567 | printf( "Introduce un número " ); 568 | fflush(stdout); 569 | scanf( "%i", &a ); 570 | 571 | if ( a<10 ) { 572 | b = 1; 573 | } 574 | 575 | else { 576 | b = 4; 577 | } 578 | printf ( "La variable 'b' toma el valor: %i\n", b ); 579 | 580 | return EXIT_SUCCESS; 581 | } 582 | ---- 583 | 584 | Si el valor que tecleamos al ejecutar es menor que 10 entonces la variable b toma el valor '1'. 585 | En cambio si tecleamos un número mayor o igual que 10 'b' será igual a 4. 586 | Ahora vamos a reescribir el programa usando '?': 587 | 588 | [source,c] 589 | ---- 590 | #include 591 | #include 592 | 593 | int main() 594 | { 595 | int a; 596 | int b; 597 | 598 | printf( "Introduce un número " ); 599 | fflush(stdout); 600 | scanf( "%i", &a ); 601 | 602 | b = ( a<10 ) ? 1 : 4 ; 603 | 604 | printf ( "La variable 'b' toma el valor: %i\n", b ); 605 | 606 | return EXIT_SUCCESS; 607 | } 608 | ---- 609 | 610 | ¿Qué es lo que sucede ahora? Se evalúa la condición a<10. 611 | Si es verdadera (a menor que 10) se ejecuta la instrucción 1, es decir, que b toma el valor '1'. 612 | Si es falsa se ejecuta la instrucción 2, es decir, b toma el valor '4'. 613 | 614 | [[switch]] 615 | ==== Switch 616 | 617 | El formato de la sentencia _switch_ es: 618 | 619 | switch ( valor ) 620 | { 621 | case _opción 1_: 622 | /* código a ejecutar si el valor es el de "opción 1" */ 623 | break; 624 | case _opción 1_: 625 | /* código a ejecutar si el valor es el de "opción 1" */ 626 | break; 627 | default: 628 | /* Código a ejecutar si el valor no es ninguno de los anteriores */ 629 | break; 630 | } 631 | 632 | Vamos a ver cómo funciona. 633 | La sentencia _switch_ sirve para elegir una opción entre varias disponibles. 634 | Dependiendo del valor se cumplirá un caso u otro. 635 | 636 | Por ejemplo si la opción elegida fuera la dos se ejecutaría el código que está justo después de: 637 | 638 | [source,c] 639 | ---- 640 | case _opción 2_: 641 | ---- 642 | 643 | hasta el primer _break_ que encontremos. 644 | 645 | Vamos a ver un ejemplo de múltiples casos con if-else y luego con switch: 646 | 647 | [source,c] 648 | ---- 649 | #include 650 | #include 651 | 652 | int main() 653 | { 654 | int num; 655 | 656 | printf( "Introduce un número: " ); 657 | fflush(stdout); 658 | scanf( "%d", &num ); 659 | 660 | if ( num==1 ) { 661 | printf ( "Es un 1\n" ); 662 | } 663 | else if ( num==2 ) { 664 | printf ( "Es un 2\n" ); 665 | } 666 | else if ( num==3 ) { 667 | printf ( "Es un 3\n" ); 668 | } 669 | else { 670 | printf ( "No era ni 1, ni 2, ni 3\n" ); 671 | } 672 | 673 | return EXIT_SUCCESS; 674 | } 675 | ---- 676 | 677 | Ahora con _switch_: 678 | 679 | [source,c] 680 | ---- 681 | #include 682 | #include 683 | 684 | int main() 685 | { 686 | int num; 687 | 688 | printf( "Introduce un número: " ); 689 | fflush(stdout); 690 | scanf( "%d", &num ); 691 | 692 | switch( num ) { 693 | 694 | case 1: 695 | printf( "Es un 1\n" ); 696 | break; 697 | 698 | case 2: 699 | printf( "Es un 2\n" ); 700 | break; 701 | 702 | case 3: 703 | printf( "Es un 3\n" ); 704 | break; 705 | 706 | default: 707 | printf( "No es ni 1, ni 2, ni 3\n" ); 708 | } 709 | 710 | return EXIT_SUCCESS; 711 | } 712 | ---- 713 | 714 | Como vemos el código con _switch_ es más cómodo de leer. 715 | 716 | Vamos a ver qué pasa si nos olvidamos algún __break__: 717 | 718 | [source,c] 719 | ---- 720 | #include 721 | #include 722 | 723 | int main() 724 | { 725 | int num; 726 | 727 | printf( "Introduce un número: " ); 728 | fflush(stdout); 729 | scanf( "%d", &num ); 730 | 731 | switch( num ) { 732 | 733 | case 1: 734 | printf( "Es un 1\n" ); 735 | /* Nos olvidamos el break que debería haber aquí */ 736 | 737 | case 2: 738 | printf( "Es un 2\n" ); 739 | break; 740 | 741 | default: 742 | 743 | printf( "No es ni 1, ni 2, ni 3\n" ); 744 | } 745 | 746 | return EXIT_SUCCESS; 747 | } 748 | ---- 749 | 750 | Si al ejecutar el programa escribimos un 2 tenemos el mensaje _“Es un dos”_. 751 | Todo correcto. 752 | Pero si escribimos un 1 lo que nos sale en pantalla es: 753 | 754 | ---- 755 | Es un 1 756 | Es un 2 757 | ---- 758 | 759 | ¿Por qué? 760 | Pues porque cada caso empieza con un _case_ y acaba donde hay un _break_. 761 | Si no ponemos break aunque haya otro _case_ más adelante el programa sigue hacia adelante. 762 | Por eso se ejecuta el código del _case_ 1 y del _case_ 2. 763 | 764 | Puede parecer una desventaja pero a veces es conveniente. 765 | Por ejemplo cuando dos _case_ deben tener el mismo código. 766 | Si no tuviéramos esta posibilidad tendríamos que escribir dos veces el mismo código. 767 | 768 | NOTE: Vale, vale, también podríamos usar funciones, pero si el código es corto puede 769 | ser más conveniente no usar funciones. 770 | Ya hablaremos de eso más tarde. 771 | 772 | Sin embargo switch tiene algunas limitaciones. 773 | Por ejemplo no podemos usar condiciones en los case. 774 | El ejemplo que hemos visto en el apartado if-else-if no podríamos hacerlo con switch. 775 | 776 | [[sentecias-de-salto-goto]] 777 | === Sentecias de salto: Goto 778 | 779 | La sentencia *_goto_* (ir a) nos permite hacer un salto a la parte del programa que deseemos. 780 | En el programa podemos poner etiquetas, estas etiquetas no se ejecutan. 781 | Es como poner un nombre a una parte del programa. 782 | Estas etiquetas son las que nos sirven para indicar a la sentencia _goto_ dónde tiene que saltar. 783 | 784 | [source,c] 785 | ---- 786 | #include 787 | #include 788 | 789 | int main() 790 | { 791 | printf( "Línea 1\n" ); 792 | 793 | goto linea3; /* Le decimos al goto que busque la etiqueta _linea3_ */ 794 | 795 | printf( "Línea 2\n" ); 796 | 797 | linea3:/* Esta es la etiqueta */ 798 | 799 | printf( "Línea 3\n" ); 800 | 801 | return EXIT_SUCCESS; 802 | } 803 | ---- 804 | 805 | Resultado: 806 | 807 | ---- 808 | Línea 1 809 | Línea 3 810 | ---- 811 | 812 | Como vemos no se ejecuta el printf de Línea 2 porque nos lo hemos saltado con el goto. 813 | 814 | El goto sólo se puede usar dentro de funciones, y no se puede saltar 815 | desde una función a otra (Las funciones las estudiamos en el siguiente 816 | capítulo). 817 | 818 | Un apunte adicional del goto: Cuando yo comencé a programar siempre oía 819 | que no era correcto usar el goto, que era una mala costumbre de programación. 820 | Decían que hacía los programas ilegibles, difíciles de entender. 821 | Ahora en cambio hay quien dice que no está tan mal. 822 | En Internet se pueden encontrar páginas que discuten sobre el tema. 823 | Pero como conclusión yo diría que cada uno la use si quiere, el caso es no abusar de ella y tener cuidado. 824 | 825 | [[notas-sobre-las-condiciones]] 826 | === [[anchor]]Notas sobre las condiciones 827 | 828 | Las condiciones de las sentencias (por ejemplo del _if_) se evalúan al 829 | ejecutarse. 830 | De esta evaluación obtenemos un número. 831 | *Las condiciones son falsas si este número es igual a cero*. 832 | Son *verdaderas si es distinto de cero* (los números negativos son verdaderos). 833 | 834 | Ahí van unos ejemplos: 835 | 836 | [source,c] 837 | ---- 838 | a = 2; 839 | b = 3; 840 | if ( a == b ) ... 841 | ---- 842 | 843 | Aquí *a==b* sería igual a 0, por lo tanto _falso_. 844 | 845 | [source,c] 846 | ---- 847 | if ( 0 ) ... 848 | ---- 849 | 850 | Como la condición es igual a cero, es falsa. 851 | 852 | [source,c] 853 | ---- 854 | if ( 1 ) ... 855 | ---- 856 | 857 | Como la condición es distinta de cero, es verdadera. 858 | 859 | [source,c] 860 | ---- 861 | if ( -100 ) ... 862 | ---- 863 | 864 | Como la condición es distinta de cero, es verdadera. 865 | 866 | Supongamos que queremos mostrar un mensaje si una variable es distinta 867 | de cero: 868 | 869 | [source,c] 870 | ---- 871 | if ( a!=0 ) printf( "Hola\n" ); 872 | ---- 873 | 874 | Esto sería redundante, bastaría con poner: 875 | 876 | [source,c] 877 | ---- 878 | if ( a ) printf( "Hola\n" ); 879 | ---- 880 | 881 | Esto sólo vale si queremos comprobar que es distinto de cero. 882 | Si queremos comprobar que es igual a 3: 883 | 884 | [source,c] 885 | ---- 886 | if ( a == 3 ) printf( "Es tres\n" ); 887 | ---- 888 | 889 | Como vemos las condiciones no sólo están limitadas a comparaciones, se puede poner cualquier expresión que devuelva un valor. 890 | Dependiendo de si este valor es cero o no, la condición será falsa o verdadera. 891 | 892 | También podemos evaluar varias condiciones en una sola usando && (AND), || (OR). 893 | 894 | ==== Ejemplos de && (AND) 895 | 896 | if ( a==3 && b==2 ) printf( "Hola\n" );/* Se cumple si a es 3 *Y* b es 897 | dos */ 898 | 899 | if ( a>10 && a<100 ) printf( "Hola\n" );/* Se cumple si a es mayor que 900 | 10 *Y* menor que 100 */ 901 | 902 | if ( a==10 && b<300 ) printf( "Hola\n" ); /* Se cumple si a es igual a 903 | 10 *Y* b es menor que 300 */ 904 | 905 | ==== Ejemplos de || (OR): 906 | 907 | [source,c] 908 | ---- 909 | if ( a<100 || b>200 ) printf( "Hola\n" ); /* Se cumple si a menor que 100 ó b mayor que 200 */ 910 | ---- 911 | 912 | [source,c] 913 | ---- 914 | if ( a<10 || a>100 ) printf( "Hola\n" ); /* Se cumple si a menor que 10 ó a mayor que 100 */ 915 | ---- 916 | 917 | Se pueden poner más de dos condiciones: 918 | 919 | [source,c] 920 | ---- 921 | if ( a>10 && a<100 && b>200 && b<500 )/* Se deben cumplir las cuatro condiciones */ 922 | ---- 923 | 924 | Esto se cumple si a es mayor que 10 y menor que 00 y b es mayor que 200 y menor que 500. 925 | 926 | También se pueden agrupar mediante paréntesis varias condiciones: 927 | 928 | [source,c] 929 | ---- 930 | if ( ( a>10 && a<100 ) || ( b>200 && b<500 ) ) 931 | ---- 932 | 933 | Esta condición se leería como sigue: 934 | 935 | * si a es mayor que 10 y menor que 100 *o* 936 | * si b es mayor que 200 y menor que 500 937 | 938 | Es decir que si se cumple el primer paréntesis o si se cumple el segundo 939 | la condición es cierta. 940 | 941 | [[ejercicios]] 942 | === Ejercicios 943 | 944 | **Ejercicio 1: **¿Cuántas veces nos pide el siguiente programa un número 945 | y por qué? 946 | 947 | [source,c] 948 | ---- 949 | #include 950 | #include 951 | 952 | int main() 953 | { 954 | int i; 955 | int numero, suma = 0; 956 | 957 | for ( i=0; i<4; i++ ); { 958 | 959 | printf( "\nIntroduce un número: " ); 960 | scanf( "%d", &numero ); 961 | suma += numero; 962 | } 963 | 964 | printf ( "\nTotal: %d\n", suma ); 965 | 966 | return EXIT_SUCCESS; 967 | } 968 | ---- 969 | 970 | *Solución:* El programa pedirá un número una única vez puesto que al final de la sentencia _for_ hay un punto y coma. 971 | Como sabemos, el bucle for hace que se ejecuten las veces necesarias la sentencia siguiente (o 972 | el siguiente bloque entre \{} ). 973 | 974 | Para que el programa funcione correctamente habría que eliminar el punto y coma. 975 | 976 | *Ejercicio 2:* Una vez eliminado el punto y coma ¿cuántas veces nos pide 977 | el programa anterior un número? 978 | 979 | *Solución:* Se ejecuta cuatro veces. Desde i=0 mientras la segunda condición sea verdadera, es decir, desede i=0 hasta i=3. 980 | Cuando i vale 4 la condición del _for_ no es cierta y no se ejecuta más su código. 981 | 982 | *Ejercicio 3:* Escribe un programa que muestre en pantalla lo siguiente: 983 | 984 | ---- 985 | * 986 | ** 987 | *** 988 | **** 989 | ***** 990 | ---- 991 | 992 | **Solución:** 993 | 994 | [source,c] 995 | ---- 996 | #include 997 | #include 998 | 999 | int main() 1000 | { 1001 | int i, j; 1002 | 1003 | for( i=0; i<6; i++ ) { 1004 | for( j=0; j 1029 | #include 1030 | 1031 | int main() 1032 | { 1033 | int numero; 1034 | 1035 | do { 1036 | printf("Introduce un numero: "); 1037 | fflush(stdin); 1038 | scanf( "%d", & numero ); 1039 | } while ( numero!=-1 ); 1040 | 1041 | printf( "Fin de programa\n" ); 1042 | 1043 | return EXIT_SUCCESS; 1044 | } 1045 | ---- 1046 | -------------------------------------------------------------------------------- /capitulo08.adoc: -------------------------------------------------------------------------------- 1 | //// 2 | Copyright: Gorka Urrutia Landa, 1999-2018 3 | Licencia: Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) https://creativecommons.org/licenses/by-sa/4.0/ 4 | //// 5 | 6 | :chapter: 008 7 | 8 | <<< 9 | 10 | [[capítulo-8.-introducción-a-las-funciones]] 11 | == [[anchor]]Capítulo 8. Introducción a las funciones 12 | 13 | [[introducción]] 14 | === [[anchor-1]]Introducción 15 | 16 | Vamos a dar un paso más en la complejidad de nuestros programas. 17 | Vamos a empezar a usar funciones creadas por nosotros. 18 | Las funciones son de una gran utilidad en los programas. 19 | Nos ayudan a que sean más legibles y más cortos. 20 | Con ellos estructuramos mejor los programas. 21 | 22 | Una función sirve para realizar tareas concretas y simplificar el programa. 23 | Nos sirve para evitar tener que escribir el mismo código varias veces. 24 | 25 | Los bucles que hemos estudiado son útiles cuando hay que repetir una parte del código varias veces. 26 | Las funciones son útiles cuando tenemos que repetir el mismo código en diferentes partes del programa. 27 | 28 | Ya hemos visto en el curso algunas funciones como printf y scanf. 29 | Algunas de éstas están definidas en una biblioteca (la biblioteca estándar de C) que el compilador carga automáticamente en cada programa. 30 | 31 | Sin embargo nosotros también podemos definir nuestras propias funciones. 32 | Pocas veces se ve un programa un poco complejo que no use funciones. 33 | Una de ellas, que usamos siempre, es la función main. 34 | 35 | [[definición-de-una-función]] 36 | === [[anchor-2]]Definición de una función 37 | 38 | Una función tiene el siguiente formato: 39 | 40 | [source,c] 41 | ---- 42 | tipo_de_dato nombre_de_la_función( argumentos ) 43 | { 44 | definición de variables; 45 | 46 | cuerpo de la función; 47 | 48 | return valor; 49 | } 50 | ---- 51 | 52 | A continuación vamos a ver en detalle cada una de las partes de una función: 53 | 54 | [[el-nombre-de-la-función]] 55 | ==== El nombre de la función 56 | 57 | El nombre de la función se usa para llamarla dentro del programa. 58 | Nombres de funciones que ya conocemos serían _printf_ o _scanf_. 59 | 60 | El nombre de una función debe cumplir los siguientes requisitos: 61 | 62 | * Sólo puede contener letras, números y el símbolo '_'. 63 | * No se pueden usar tildes ni espacios. 64 | * El nombre de una función debe empezar por una letra, nunca por un número. 65 | * No podemos usar _palabras reservadas_. Las palabras reservadas son 66 | aquellas que se usan en C, por ejemplo _if_, _for_, _while_. Un 67 | nombre de función puede contener una palabra reservada: por ejemplo 68 | _while_ no se puede usar como nombre de función, pero _while_1_ sí. 69 | 70 | [[tipo-de-dato]] 71 | ==== Tipo de dato 72 | 73 | Cuando una función se ejecuta y termina puede devolver un valor. 74 | Este valor puede ser cualquiera de los tipos de variables que hemos visto en el capítulo de Tipos de datos (int, char, float, double). 75 | También puede ser un tipo de dato definido por nosotros (esto lo veremos más tarde). 76 | El valor que devuelve la función suele ser el resultado de las operaciones que se realizan en la función, o si han tenido éxito o no. 77 | 78 | El valor devuelto debe ser del tipo indicado en _tipo_de_dato_. 79 | 80 | También podemos usar el tipo *void*. 81 | Este nos permite indicar que la función no devuelve ningún valor. 82 | Cuando este sea el caso la palabra reservada _return_ se utiliza sola, sin ningún valor a continuación de ésta. 83 | O también podemos emitir poner _return_. 84 | 85 | En este ejemplo usamos una (absurda) función que devuelve un número entero: 86 | 87 | [source,c] 88 | ---- 89 | #include 90 | #include 91 | 92 | int dame_un_diez() 93 | { 94 | return 10; 95 | } 96 | 97 | int main() 98 | { 99 | printf( "%d\n", dame_un_diez() ); 100 | 101 | return EXIT_SUCCESS; 102 | } 103 | ---- 104 | 105 | El tipo de dato que devuelve es _int_ y lo devuelve a través del _return_. 106 | 107 | [[definición-de-variables]] 108 | ==== Definición de variables 109 | 110 | Dentro de la función podemos definir variables que sólo tendrán validez dentro de la propia función. 111 | Si declaramos una variable en una función no podemos usarla en otra. 112 | A estas variables que solo existen dentro de una función las llamamos *_variables locales_*. 113 | 114 | Ver “link:#anchor-3[Vida de una variable ]” para más información sobre el tema. 115 | 116 | Otro (absurdo) ejemplo de una función que usa una _variable local_: 117 | 118 | [source,c] 119 | ---- 120 | #include 121 | #include 122 | 123 | int dame_un_diez() 124 | { 125 | int diez = 10; 126 | 127 | return diez; 128 | } 129 | 130 | int main() 131 | { 132 | printf( "%d\n", dame_un_diez() ); 133 | 134 | return EXIT_SUCCESS; 135 | } 136 | ---- 137 | 138 | En este ejemplo la variable _diez_ no está accesible desde _main_. 139 | 140 | [[cuerpo-de-la-función]] 141 | ==== Cuerpo de la función 142 | 143 | Aquí es donde va el código de la función. 144 | 145 | [[argumentos-o-parámetros]] 146 | ==== Argumentos o parámetros 147 | 148 | Antes hemos visto que una variable definida en una función no se puede 149 | usar dentro de otra. Entonces ¿cómo le pasamos valores a una función 150 | para que trabaje con ellos? Para esto es para lo que se usan los 151 | argumentos. 152 | 153 | Estos son variables que se pasan como datos a una función. Una función 154 | puede tener un argumento, muchos o ninguno. Cuando tiene más de uno 155 | éstos deben ir separados por una coma. Cada variable debe ir con su tipo 156 | de variable. 157 | 158 | Un ejemplo de una función con parámetros sería: 159 | 160 | [source,c] 161 | ---- 162 | #include 163 | #include 164 | 165 | int suma(int numero1, int numero2) 166 | { 167 | return numero1 + numero2; 168 | } 169 | 170 | int main() 171 | { 172 | printf( "%d\n", suma(10, 5) ); 173 | 174 | return EXIT_SUCCESS; 175 | } 176 | ---- 177 | 178 | [[dónde-se-definen-las-funciones]] 179 | === [[anchor-4]]Dónde se definen las funciones 180 | 181 | Las funciones deben definirse siempre antes de donde se usan. 182 | Lo habitual en un programa es: 183 | 184 | [cols="",] 185 | |======================================================================= 186 | |*Sección * |*Descripción * 187 | 188 | |Includes |Aquí se indican qué ficheros externos se usan. 189 | 190 | |Definiciones de constantes |Aquí se definen las constantes que se usan 191 | en el programa. 192 | 193 | |Definición de variables |Aquí se definen las variables globales (las 194 | que se pueden usar en TODAS las funciones). 195 | 196 | |Prototipos de funciones |Aquí es donde se definen las cabeceras de las 197 | funciones. 198 | 199 | |Definición de las funciones |Aquí se “desarrollan” las funciones. 200 | Pueden colocarse en cualquier orden. Por costumbre, yo suelo poner main 201 | en primer lugar. 202 | |======================================================================= 203 | 204 | Esta es una forma muy habitual de estructurar un programa. Sin embargo 205 | esto no es algo rígido, no tiene por qué hacerse así, pero es 206 | recomendable. 207 | 208 | Los prototipos de las funciones consisten en definir solo las cabeceras 209 | de las funciones, sin escribir su código. Esto nos permite luego poner 210 | las funciones en cualquier orden. El estándar ANSI C dice que no son 211 | obligatorios los prototipos de las funciones pero es recomendable 212 | usarlos. 213 | 214 | Ejemplos: 215 | 216 | #include 217 | 218 | int compara( int a, int b ); /* Definimos la cabecera de la función */ 219 | 220 | int main() 221 | 222 | \{ 223 | 224 | int num1, num2; 225 | 226 | int resultado; 227 | 228 | printf( "Introduzca dos numeros: " ); 229 | 230 | scanf( "%d %d", &num1, &num2 ); 231 | 232 | resultado = compara( num1, num2 ); 233 | 234 | printf( "El mayor de los dos es %d\n", resultado ); 235 | 236 | return 0; 237 | 238 | } 239 | 240 | int compara( int a, int b ) /* Ahora podemos poner el cuerpo de la 241 | función donde queramos. Incluso después de donde la llamamos (main) */ 242 | 243 | \{ 244 | 245 | int mayor; 246 | 247 | if ( a>b ) 248 | 249 | mayor = a; 250 | 251 | else 252 | 253 | mayor = b; 254 | 255 | return mayor; 256 | 257 | } 258 | 259 | ________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 260 | *NOTA:* Por simplicidad este ejemplo no tiene en cuenta el caso de que 261 | los números sean iguales. Se deja al alumno como ejercicio modificar el 262 | programa para que tenga en cuenta la posibilidad de que los números sean 263 | iguales. 264 | ________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 265 | 266 | Cuando se define la cabecera de la función sin su cuerpo (o código) 267 | debemos poner un ';' al final. Cuando definamos el cuerpo más tarde no 268 | debemos poner el ';', se hace como una función normal. 269 | 270 | La definición debe ser igual cuando definimos sólo la cabecera y cuando 271 | definimos el cuerpo. Mismo nombre, mismo número y tipo de parámetros y 272 | mismo tipo de valor devuelto. 273 | 274 | Las funciones deben definirse antes de ser llamadas. En los ejemplos a 275 | continuación se llama a la función desde main, así que tenemos que 276 | definirlas antes que main. Lo habitual es definir primero la “cabecera” 277 | o prototipos de la función, que no es más que la definición de la 278 | función si su “cuerpo” y desarrollar después la función completa. 279 | 280 | **Ejemplo 1**. Función sin argumentos que no devuelve nada: 281 | 282 | Este programa llama a la función prepara pantalla que borra la pantalla 283 | y muestra el mensaje "la pantalla está limpia". Por supuesto es de nula 284 | utilidad pero nos sirve para empezar. 285 | 286 | #include 287 | 288 | void mostrar_mensaje(); /* Prototipo de la función */ 289 | 290 | int main() 291 | 292 | \{ 293 | 294 | printf( "Esta es la función main\n" ); 295 | 296 | prepara_pantalla();/* Llamamos a la función */ 297 | 298 | return 0; 299 | 300 | } 301 | 302 | /* Desarrollo de la función */ 303 | 304 | void mostrar_mensaje() /* No se debe poner punto y coma aquí */ 305 | 306 | \{ 307 | 308 | printf( "Esta es la funcion mostrar_mensaje\n" ); 309 | 310 | return; /* No hace falta devolver ningún valor, 311 | 312 | este return no es necesario */ 313 | 314 | } 315 | 316 | *Ejemplo 2.* Función con argumentos, no devuelve ningún valor: 317 | 318 | En este ejemplo la función _compara_ toma dos números, los compara y nos 319 | dice cual es mayor. 320 | 321 | #include 322 | 323 | void compara( int a, int b ); 324 | 325 | int main() 326 | 327 | \{ 328 | 329 | int num1, num2; 330 | 331 | printf( "Introduzca dos numeros: " ); 332 | 333 | fflush(stdout); 334 | 335 | scanf( "%d %d", &num1, &num2 ); 336 | 337 | /* Llamamos a la función con sus dos argumentos */ 338 | 339 | compara( num1, num2 ); 340 | 341 | return 0; 342 | 343 | } 344 | 345 | void compara( int a, int b ) /* Pasamos los parámetros a y b a la 346 | función */ 347 | 348 | \{ 349 | 350 | if ( a>b ) 351 | 352 | printf( "%d es mayor que %d\n" , a, b ); 353 | 354 | else if ( a 369 | 370 | int compara( int a, int b ); 371 | 372 | int main() 373 | 374 | \{ 375 | 376 | int num1, num2; 377 | 378 | int resultado; 379 | 380 | printf( "Introduzca dos numeros: " ); 381 | 382 | fflush(stdout); 383 | 384 | scanf( "%d %d", &num1, &num2 ); 385 | 386 | /* Recogemos el valor que devuelve la función en la variable 387 | *resultado* */ 388 | 389 | resultado = compara( num1, num2 ); 390 | 391 | printf( "El mayor de los dos es %d\n", resultado ); 392 | 393 | return 0; 394 | 395 | } 396 | 397 | /* Metemos los parámetros a y b a la función */ 398 | 399 | int compara( int a, int b ) 400 | 401 | \{ 402 | 403 | /* Esta función define su propia variable, 404 | 405 | esta variable sólo se puede usar aquí */ 406 | 407 | int mayor; 408 | 409 | if ( a>b ) 410 | 411 | mayor = a; 412 | 413 | else 414 | 415 | mayor = b; 416 | 417 | return mayor; 418 | 419 | } 420 | 421 | En este ejemplo podíamos haber hecho también: 422 | 423 | printf( "El mayor de los dos es %i\n", compara( num1, num2 ) ); 424 | 425 | De esta forma nos ahorramos tener que definir la variable 'resultado'. 426 | 427 | [[vida-de-una-variable]] 428 | === [[anchor-5]][[anchor-3]][[anchor-5]]Vida de una variable 429 | 430 | Cuando definimos una variable dentro de una función, esa variable sólo 431 | es válida dentro de la función. Este tipo de variables se denominan 432 | **variables locales**. Si definimos una variable dentro de main sólo 433 | podremos usarla dentro de main, será por tanto una variable local de la 434 | función main. 435 | 436 | Si por el contrario la definimos fuera de las funciones se trataría de 437 | una *variable global* y se podría usar en cualquier función. 438 | 439 | Podemos crear una variable global y en una función una variable local 440 | con el mismo nombre. Dentro de la función estaremos trabajando con la 441 | variable local, no con la global. Esto no da errores pero puede crear 442 | confusión al programar y al analizar el código. No es nada recomendable 443 | seguir esta práctica. 444 | 445 | Por norma general *es aconsejable usar siempre variables locales* frente 446 | a las globales ya que será más sencilla la localización de errores y 447 | ayuda a la reutilización de código (podemos copiar/pegar las funciones a 448 | otro programa). Por sencillez, en muchos ejemplos usaremos variables 449 | globales, pero el alumno debería acostumbrarse a usar variables locales. 450 | 451 | [[ejercicios]] 452 | === [[anchor-6]]Ejercicios 453 | 454 | *Ejercicio 1:* Descubre los errores: 455 | 456 | #include 457 | 458 | int main() 459 | 460 | \{ 461 | 462 | int num1, num2; 463 | 464 | int resultado, 465 | 466 | printf( "Introduzca dos números: " ); 467 | 468 | fflush(stdout); 469 | 470 | scanf( "%d %d", &num1, &num2 ); 471 | 472 | resultado = compara( num1, num2 ); 473 | 474 | printf( "El mayor de los dos es %d\n", resultado ); 475 | 476 | return 0; 477 | 478 | } 479 | 480 | int compara( int a, int b ); 481 | 482 | \{ 483 | 484 | int mayor; 485 | 486 | if ( a>b )mayor = a; 487 | 488 | else mayor = b; 489 | 490 | return mayor; 491 | 492 | } 493 | 494 | **Solución**: 495 | 496 | * Hay una coma después de _int_ _resultado_ en vez de un punto y coma. 497 | * Llamamos a la función _compara_ dentro de main antes de definirla. Si 498 | hubiésemos puesto el prototipo de la función al principio del código no 499 | hubiera sido problema. 500 | * Cuando definimos la función _compara_ hemos puesto un punto y coma al 501 | final, eso es un error. El código que hay justo detrás no pertenece a 502 | ninguna función. 503 | 504 | *Ejercicio 2:* Busca los errores. 505 | 506 | #include 507 | 508 | int resultado( int parametro ) 509 | 510 | int main() 511 | 512 | \{ 513 | 514 | int a, b; 515 | 516 | a = 2; b = 3; 517 | 518 | printf( "%i", resultado( a ); 519 | 520 | return 0; 521 | 522 | } 523 | 524 | char resultado( int parametro ) 525 | 526 | \{ 527 | 528 | return parametro + b; 529 | 530 | } 531 | 532 | Solución: 533 | 534 | * Hemos definido el prototipo de _resultado_ sin punto y coma. 535 | * Cuando definimos el cuerpo de _resultado_ en su cabecera hemos puesto 536 | __char__, que no coincide con el prototipo. 537 | * En la función _resultado_ estamos usando la variable 'b' que está 538 | definida sólo en main. No es una variable global y por lo tanto es como 539 | si no existiera para __resultado__. 540 | * En printf nos hemos dejado un paréntesis al final. 541 | -------------------------------------------------------------------------------- /capitulo09.adoc: -------------------------------------------------------------------------------- 1 | //// 2 | Copyright: Gorka Urrutia Landa, 1999-2018 3 | Licencia: Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) https://creativecommons.org/licenses/by-sa/4.0/ 4 | //// 5 | 6 | :chapter: 009 7 | 8 | <<< 9 | 10 | [[capítulo-9.-punteros]] 11 | == Capítulo 9. Punteros 12 | 13 | [[introducción]] 14 | === [[anchor]]Introducción 15 | 16 | Este capítulo puede resultar problemático a aquellos que no han visto nunca lo que es un puntero. 17 | Por lo tanto si tienes alguna duda o te parece que alguna parte está poco clara ponte en contacto conmigo. 18 | 19 | ¡¡¡Punteros!!! uff. 20 | Este es uno de los temas que más suele costar a la gente al aprender C. 21 | Los punteros son una de las más potentes características de C, pero a la vez uno de sus mayores peligros. 22 | Si no se manejan con cuidado pueden ser una fuente ilimitada de errores. 23 | Un error usando un puntero puede bloquear el sistema y a veces puede ser difícil detectarlo. 24 | 25 | Otros lenguajes no nos dejan usar punteros para evitar estos problemas, pero a la vez nos quitan parte del control que tenemos en C. 26 | 27 | A pesar de todo esto no hay que tenerles miedo. 28 | Casi todos los programas C usan punteros. 29 | Si aprendemos a usarlos bien no tendremos más que algún problema esporádico. Así que atención, valor y al toro. 30 | 31 | [[la-memoria-del-ordenador]] 32 | === [[anchor-1]]La memoria del ordenador 33 | 34 | Si tienes bien claro lo que es la memoria del ordenador puedes saltarte esta sección. 35 | Pero si confundes la memoria con el disco duro o no tienes claro lo que es no te la pierdas. 36 | 37 | A lo largo de mi experiencia con ordenadores me he encontrado con mucha gente que no tiene claro cómo funciona un ordenador. 38 | Cuando hablamos de memoria nos estamos refiriendo a la memoria RAM del ordenador. 39 | Son unas _pastillas_ que se conectan a la placa base y nada tienen que ver con el disco duro. 40 | El disco duro guarda los datos permanentemente (hasta que se rompe) y la información se almacena como ficheros. 41 | Nosotros podemos decirle al ordenador cuándo grabar, borrar, abrir un documento, etc. 42 | La memoria RAM en cambio, se borra al apagar el ordenador. 43 | La memoria RAM la usan los programas sin que el usuario de éstos se de cuenta. 44 | 45 | Hay otras memorias en el ordenador aparte de la mencionada. 46 | Por ejemplo la memoria de vídeo (que está en la tarjeta gráfica), las memorias caché (del procesador, de la placa...). 47 | 48 | [[direcciones-de-variables]] 49 | === [[anchor-2]]Direcciones de variables 50 | 51 | Vamos a ir como siempre por partes. 52 | Primero vamos a ver qué pasa cuando declaramos una variable. 53 | 54 | Al declarar una variable estamos diciendo al ordenador que nos reserve una parte de la memoria para almacenarla. 55 | Cada vez que ejecutemos el programa la variable se almacenará en un sitio diferente. 56 | Eso no lo podemos controlar, depende de la memoria disponible y otros factores "misteriosos". 57 | Puede que se almacene en el mismo sitio, pero es mejor no fiarse. 58 | 59 | Dependiendo del tipo de variable que declaremos el ordenador nos reservará más o menos memoria. 60 | Como vimos en el capítulo de tipos de datos cada tipo de variable ocupa más o menos bytes. 61 | Por ejemplo si declaramos un _char_, el ordenador nos reserva 1 byte (usualmente 8 bits). 62 | Una variable de tipo _int_ ocupará más espacio (depende del compilador y el sistema en el que trabajemos). 63 | 64 | Cuando finaliza el programa todo el espacio reservado para las variables queda libre para ser usado por otros programas. 65 | 66 | NOTE: Si bien usualmente un carácter (char) esta constituido por ocho bits esto no lo garantiza el estándar. 67 | El numero exacto esta dado por la macro CHAR_BIT). 68 | 69 | Saber cuánto ocupa un carácter en tu sistema es imporante. 70 | Para saberlo puedes usar este sencillo programa: 71 | 72 | [source,c] 73 | ---- 74 | #include 75 | #include 76 | #include 77 | 78 | int main() 79 | { 80 | printf("Bits que ocupa un carácter: %d", CHAR_BIT); 81 | 82 | return EXIT_SUCCESS; 83 | } 84 | ---- 85 | 86 | 87 | Existe una forma de saber qué direcciones nos ha reservado el ordenador para nuestras variables. 88 | Se trata de usar el operador *&* (operador de dirección). 89 | Ya lo habíamos visto en el _scanf_ pero no sabíamos bien para qué era. 90 | Vamos a ver un ejemplo: Declaramos la variable 'a' y obtenemos su valor y dirección. 91 | 92 | [source,c] 93 | ---- 94 | #include 95 | #include 96 | 97 | int main() 98 | { 99 | char a; 100 | 101 | a = 10; 102 | 103 | printf( "La variable 'a' se almacena en la posición de memoria %p ", (void *) &a ); 104 | printf( "y su valor es %d\n.", a ); 105 | 106 | return EXIT_SUCCESS; 107 | } 108 | ---- 109 | 110 | NOTE: Para mostrar la dirección de la variable usamos %p (en lugar de %d). 111 | Éste _modificador de formato_ sirve para escribir direcciones de memoria. 112 | El formato que se usa para mostrar las direcciones de memoria es el hexadecimal. 113 | 114 | El resultado sería algo como: 115 | 116 | ---- 117 | La variable a se almacena en la posición de memoria 0x7fff13be7627 y su valor es 10. 118 | ---- 119 | 120 | Si ejecutamos el programa varias veces seguidas veremos algo curioso: 121 | 122 | * El valor de _a_ siempre es el mismo. 123 | * Pero la posición de la memoria donde se almacena la variable cambia cada vez. 124 | 125 | La segunda vez pude mostrar algo como ésto: 126 | 127 | ---- 128 | La variable a se almacena en la posición de memoria 0x7fff8e74c037 y su valor es 10. 129 | ---- 130 | 131 | Y la tercera: 132 | 133 | ---- 134 | La variable a se almacena en la posición de memoria 0x7ffc79a200a7 y su valor es 10. 135 | ---- 136 | 137 | Como podemos ver, cada vez que ejecutamos el programa la dirección de la memoria donde se almacena _a_ es diferente. 138 | Pero una vez el sistema nos ha reservado esa dirección ya no cambia durante la ejecución del programa. 139 | 140 | El valor de _a_ lo podemos controlar nosotros. 141 | El valor de la memoria que nos asigna el sistema podemos conocerlo pero no controlarlo. 142 | 143 | Es importante tener clara la diferencia entre el valor de _a_ y el valor de la memoria donde se almacena _a_. 144 | 145 | El nombre de la variable es equivalente a poner un nombre a una zona de la memoria. 146 | Cuando en el programa escribimos 'a', en realidad estamos diciendo, "el valor que está almacenado en la dirección de memoria a la que llamamos 'a'". 147 | 148 | [[qué-son-los-punteros]] 149 | === [[anchor-3]]Qué son los punteros 150 | 151 | Ahora ya estamos en condiciones de ver lo que es un puntero. 152 | Un puntero es una variable un tanto especial. 153 | Con un puntero podemos almacenar direcciones de memoria. 154 | En un puntero podemos tener guardada la dirección de una variable. 155 | 156 | Vamos a ver si captamos bien el concepto de puntero y la diferencia entre éstos y las variables _normales_. 157 | 158 | image:imagenes/punteros1.png[image,width=132,height=154] 159 | 160 | En el dibujo anterior tenemos una representación de lo que sería la memoria del ordenador. 161 | Cada casilla representa un byte de la memoria. 162 | Y cada número es su dirección de memoria. 163 | La primera casilla es la posición 00001 de la memoria. 164 | La segunda casilla la posición 00002 y así sucesivamente. 165 | 166 | Supongamos que ahora declaramos una variable _char_: 167 | 168 | [source,c] 169 | ---- 170 | char numero = 43. 171 | ---- 172 | 173 | El ordenador nos guardaría por ejemplo la posición 00003 para esta variable. 174 | Esta posición de la memoria queda reservada y ya no la puede usar nadie más. 175 | Además esta posición a partir de ahora se le llama _numero_. 176 | Como le hemos dado el valor 43 a _numero_, el valor 43 se almacena en numero, es decir, en la posición 00003. 177 | 178 | image:imagenes/punteros2.png[image,width=193,height=154] 179 | 180 | Veamos cómo hubiera sido el resultado del programa anterior con esta 181 | situación: 182 | 183 | [source,c] 184 | ---- 185 | #include 186 | #include 187 | 188 | int main() 189 | { 190 | char numero; 191 | 192 | numero = 43; 193 | 194 | printf( "La variable numero " ); 195 | printf( "se almacena en la posición de memoria %p,", (void *) &numero ); 196 | printf( "y su valor es %d\n", numero ); 197 | 198 | return EXIT_SUCCESS; 199 | } 200 | 201 | ---- 202 | 203 | El resultado sería: 204 | 205 | ---- 206 | La variable numero se almacena en la posición de memoria *00003*, y su 207 | valor es *43* 208 | ---- 209 | 210 | Creo que así ya está clara la diferencia entre el valor de una variable (43) y su dirección (00003). 211 | 212 | Ahora vamos un poco más allá, vamos a declarar un puntero. 213 | Hemos dicho que un puntero sirve para almacenar la direcciones de memoria. 214 | Muchas veces los punteros se usan para guardar las direcciones de variables. 215 | Vimos en el capítulo Tipos de Datos que cada tipo de variable ocupa un espacio distinto en la memoria. 216 | Por eso cuando declaramos un puntero debemos especificar el tipo de datos cuya dirección almacenará. 217 | En nuestro ejemplo queremos que almacene la dirección de una variable char. 218 | Así que para declarar el puntero *punt* debemos hacer: 219 | 220 | [source,c] 221 | ---- 222 | char *punt; 223 | ---- 224 | 225 | El * (asterisco) sirve para indicar que se trata de un puntero, debe ir 226 | antes del nombre de la variable. 227 | 228 | *NOTA:* El lenguaje C es un lenguaje de "formato libre" y la declaración 229 | de la variable "punt" podría realizarse en cualquiera de estas formas, 230 | todas ellas validas: 231 | 232 | [source,c] 233 | ---- 234 | char*punt; + 235 | char* punt; + 236 | char * punt; + 237 | char *punt; + 238 | char + 239 | * + 240 | punt; 241 | ---- 242 | 243 | En la variable punt sólo se pueden guardar direcciones de memoria, no se 244 | pueden guardar datos. Vamos a volver sobre el ejemplo anterior un poco 245 | ampliado para ver cómo funciona un puntero: 246 | 247 | #include 248 | #include 249 | 250 | int main() 251 | 252 | \{ 253 | 254 | char numero; 255 | 256 | char *punt; 257 | 258 | numero = 43; 259 | 260 | punt = &numbero; 261 | 262 | printf( "La variable numero se almacena en la posición de memoria %p, y 263 | su valor es %d\n", (void *) &numero, numero ); 264 | 265 | return EXIT_SUCCESS; 266 | 267 | } 268 | 269 | Vamos a ir línea a línea: 270 | 271 | * En el primer _int numero_ reservamos memoria para _numero_ (supongamos 272 | que queda como antes, posición 00003). Por ahora _numero_ no tiene 273 | ningún valor. 274 | * Siguiente línea: _int *punt;_. Reservamos una posición de memoria para 275 | almacenar el puntero, por ejemplo en la posición 00004. Por ahora _punt_ 276 | no tiene ningún valor, es decir, no apunta a ninguna variable. Esto es 277 | lo que tenemos por ahora: 278 | 279 | image:imagenes/punteros3.png[image,width=193,height=154] 280 | 281 | * Tercera línea: _numero = 43;_. 282 | Aquí ya estamos dando el valor 43 a _numero_. 283 | Se almacena 43 en la dirección 00003, que es la de _numero_. 284 | * Cuarta línea: _punt = \№_. 285 | Por fin damos un valor a punt. 286 | El valor que le damos es la dirección de numero (ya hemos visto que _&_ devuelve la dirección de una variable). 287 | Así que _punt_ tendrá como valor la dirección de numero, 00003. 288 | Por lo tanto ya tenemos: 289 | 290 | image:imagenes/punteros4.png[image,width=193,height=154] 291 | 292 | Cuando un puntero tiene la dirección de una variable se dice que ese 293 | puntero *apunta* a esa variable. 294 | 295 | _*NOTA:*_ La declaración de un puntero depende del tipo de dato al que 296 | queramos apuntar. En general la declaración es: 297 | 298 | tipo_de_dato *nombre_del_puntero; 299 | 300 | Si en vez de querer apuntar a una variable tipo _char_ como en el 301 | ejemplo hubiese sido de tipo _int_: 302 | 303 | int *punt; 304 | 305 | [[para-qué-sirve-un-puntero-y-cómo-se-usa]] 306 | === [[anchor-4]]Para qué sirve un puntero y cómo se usa 307 | 308 | Los punteros tienen muchas utilidades, por ejemplo nos permiten pasar 309 | variables a una función y modificarlos. También permiten el manejo de 310 | cadenas de texto de arrays, de ficheros y de listas enlazadas (ya 311 | veremos todo esto más adelante). Otro uso es que nos permiten acceder 312 | directamente a la pantalla, al teclado y a todos los componentes del 313 | ordenador (sólo en determinados sistemas operativos). 314 | 315 | Pero si sólo sirvieran para almacenar direcciones de memoria no 316 | servirían para mucho. Nos deben dejar también la posibilidad de acceder 317 | a esas posiciones de memoria. Para acceder a ellas se usa el operador *, 318 | que no hay que confundir con el de la multiplicación. 319 | 320 | #include 321 | #include 322 | 323 | int main() 324 | 325 | \{ 326 | 327 | char numero; 328 | 329 | char *punt; 330 | 331 | numero = 43; 332 | 333 | punt = № 334 | 335 | printf( "La variable numero se almacena en la posición de memoria %p, y 336 | su valor es %d.\n", 337 | 338 | (void *) &numero, **punt* ); 339 | 340 | return EXIT_SUCCESS; 341 | 342 | } 343 | 344 | Si nos fijamos en lo que ha cambiado con respecto al ejemplo anterior, 345 | vemos que para acceder al valor de número usamos *punt en vez de numero. 346 | Esto es así porque punt apunta a numero y *punt nos permite acceder al 347 | valor al que apunta punt. 348 | 349 | #include 350 | #include 351 | 352 | int main() 353 | 354 | \{ 355 | 356 | char numero; 357 | 358 | char *punt; 359 | 360 | numero = 43; 361 | 362 | punt = № 363 | 364 | **punt = 30;* 365 | 366 | printf( "La variable numero se almacena en la posición de memoria %p, y 367 | su valor es %d.\n", (void *) &numero, numero ); 368 | 369 | return EXIT_SUCCESS; 370 | 371 | } 372 | 373 | Ahora hemos cambiado el valor de numero a través de _*punt_. 374 | 375 | En resumen, usando _punt_ podemos apuntar a una variable y con _*punt_ 376 | vemos o cambiamos el contenido de esa variable. 377 | 378 | Un puntero no sólo sirve para apuntar a una variable, también sirve para 379 | apuntar una dirección de memoria determinada. Esto tiene muchas 380 | aplicaciones, por ejemplo nos permite controlar el hardware directamente 381 | (en MS-Dos y Windows, no en Linux). Podemos escribir directamente sobre 382 | la memoria de vídeo y así escribir directamente en la pantalla sin usar 383 | printf. 384 | 385 | [[usando-punteros-en-una-comparación]] 386 | === [[anchor-5]]Usando punteros en una comparación 387 | 388 | Veamos el siguiente ejemplo. Queremos comprobar si dos variables son 389 | iguales usando punteros: 390 | 391 | #include 392 | #include 393 | 394 | int main() 395 | 396 | \{ 397 | 398 | int a, b; 399 | 400 | int *punt1, *punt2; 401 | 402 | a = 5; b = 5; 403 | 404 | punt1 = &a; punt2 = &b; 405 | 406 | if ( punt1 == punt2 ) 407 | 408 | printf( "Son iguales.\n" ); 409 | 410 | return EXIT_SUCCESS; 411 | 412 | } 413 | 414 | Alguien podría pensar que el _if_ se cumple y se mostraría el mensaje 415 | _Son iguales_ en pantalla. Pues no es así, el programa es erróneo. Es 416 | cierto que a y b son iguales. También es cierto que punt1 apunta a 'a' y 417 | punt2 a 'b'. Lo que queríamos comprobar era si a y b son iguales. Sin 418 | embargo con la condición estamos comprobando si punt1 apunta al mismo 419 | sitio que punt2, estamos comparando las direcciones donde apuntan. Por 420 | supuesto a y b están en distinto sitio en la memoria así que la 421 | condición es falsa. Para que el programa funcionara deberíamos usar los 422 | asteriscos: 423 | 424 | #include 425 | #include 426 | 427 | int main() 428 | 429 | \{ 430 | 431 | int a, b; 432 | 433 | int *punt1, *punt2; 434 | 435 | a = 5; b = 5; 436 | 437 | punt1 = &a; punt2 = &b; 438 | 439 | if ( **punt1 == *punt2* ) 440 | 441 | printf( "Son iguales.\n" ); 442 | 443 | return EXIT_SUCCESS; 444 | 445 | } 446 | 447 | Ahora sí. Estamos comparando el contenido de las variables a las que 448 | apuntan punt1 y punt2. Debemos tener mucho cuidado con esto porque es un 449 | error que se nos puede escapar con mucha facilidad. 450 | 451 | Vamos a cambiar un poco el ejemplo. Ahora 'b' no existe y punt1 y punt2 452 | apuntan a 'a'. La condición se cumplirá porque apuntan al mismo sitio. 453 | 454 | #include 455 | #include 456 | 457 | int main() 458 | 459 | \{ 460 | 461 | int a; 462 | 463 | int *punt1, *punt2; 464 | 465 | a = 5; 466 | 467 | *punt1 = &a; punt2 = &a;* 468 | 469 | if ( punt1 == punt2 ) 470 | 471 | printf( "punt1 y punt2 apuntan al mismo sitio.\n" ); 472 | 473 | return EXIT_SUCCESS; 474 | 475 | } 476 | 477 | [[punteros-como-argumentos-de-funciones]] 478 | === [[anchor-6]]Punteros como argumentos de funciones 479 | 480 | Hemos visto en el capítulo de funciones cómo pasar parámetros y cómo 481 | obtener resultados de las funciones (con los valores devueltos con 482 | return). Pero tiene un inconveniente, sólo podemos tener un valor 483 | devuelto. Ahora vamos a ver cómo los punteros nos permiten modificar 484 | varias variables en una función. 485 | 486 | Hasta ahora para pasar una variable a una función hacíamos lo siguiente: 487 | 488 | #include 489 | #include 490 | 491 | int suma( int a, int b ) 492 | 493 | \{ 494 | 495 | return a+b; 496 | 497 | } 498 | 499 | int main() 500 | 501 | \{ 502 | 503 | int var1, var2, resultado; 504 | 505 | var1 = 5; var2 = 8; 506 | 507 | resultado = suma(var1, var2); 508 | 509 | printf( "La suma es : %i\n", resultado ); 510 | 511 | return EXIT_SUCCESS; 512 | 513 | } 514 | 515 | Aquí hemos pasado a la función los parámetros 'a' y 'b' (que no podemos 516 | modificar) y nos devuelve la suma de ambos. 517 | 518 | Vamos a modificar el ejemplo para que use punteros: 519 | 520 | #include 521 | #include 522 | 523 | void suma( int a, int b, int *total ) 524 | 525 | \{ 526 | 527 | *total = a + b; 528 | 529 | } 530 | 531 | int main() 532 | 533 | \{ 534 | 535 | int var1, var2, resultado; 536 | 537 | var1 = 5; var2 = 8; 538 | 539 | suma(var1, var2, &resultado); 540 | 541 | printf( "La suma es: %d.\n", resultado ); 542 | 543 | return EXIT_SUCCESS; 544 | 545 | } 546 | 547 | Como podemos ver la función ya no devuelve un valor, pero le hemos 548 | añadido un tercer parámetro _int *total_. Este parámetro es un puntero 549 | que va a recibir la dirección donde se almacena _resultado_ 550 | (_&resultado_) y va a guardar ahí el resultado de la suma. Cuando 551 | finalice la función y volvamos a la función _main_ la variable 552 | _resultado_ se encontrará con que tiene como valor la suma de los dos 553 | números. 554 | 555 | Supongamos ahora que queremos tener la suma pero además queremos que 556 | _var1_ se haga cero dentro de la función. Para eso haríamos lo 557 | siguiente: 558 | 559 | #include 560 | #include 561 | 562 | int suma_y_cambia( *int *a*, int b ) 563 | 564 | \{ 565 | 566 | int c; 567 | 568 | c = *a + b; 569 | 570 | *a = 0; 571 | 572 | return c; 573 | 574 | } 575 | 576 | int main() 577 | 578 | \{ 579 | 580 | int var1, var2, resultado; 581 | 582 | var1 = 5; var2 = 8; 583 | 584 | resultado = suma_y_cambia(*&var1*, var2); 585 | 586 | printf( "La suma es: %d y var1 vale: %d.\n", resultado , var1 ); 587 | 588 | return EXIT_SUCCESS; 589 | 590 | } 591 | 592 | Fijémonos en lo que ha cambiado (con letra en negrita): En la función 593 | suma hemos declarado 'a' como puntero. En la llamada a la función 594 | (dentro de main) hemos puesto & para pasar la dirección de la variable 595 | var1. Ya sólo queda hacer cero a var1 a través de *a=0. 596 | 597 | También usamos una variable 'c' que nos servirá para almacenar la suma 598 | de 'a' y 'b'. 599 | 600 | Es importante no olvidar el operador & en la llamada a la función ya que 601 | sin el no estaríamos pasando la dirección de la variable sino el valor 602 | de _var1_. 603 | 604 | Podemos usar tantos punteros como queramos en la definición de la 605 | función. 606 | 607 | *NOTA IMPORTANTE*: Existe la posibilidad de hacer el ejercicio de esta 608 | otra manera, sin usar la variable _resultado_: 609 | 610 | #include 611 | #include 612 | 613 | int suma( *int *a*, int b ) 614 | 615 | \{ 616 | 617 | int c; 618 | 619 | c = *a + b; 620 | 621 | *a = 0; 622 | 623 | return c; 624 | 625 | } 626 | 627 | int main() 628 | 629 | \{ 630 | 631 | int var1, var2; 632 | 633 | var1 = 5; var2 = 8; 634 | 635 | printf( "La suma es: %d y var1 vale: %d\n", suma(*&var1*, var2) , var1 636 | ); 637 | 638 | return EXIT_SUCCESS; 639 | 640 | } 641 | 642 | Sin embargo, esto puede dar problemas, ya que no podemos asegurar de 643 | cómo va a evaluar el compilador los argumentos de printf. Es posible que 644 | primero almacene el valor de var1 antes de evaluar _suma_. Si ocurriese 645 | así el resultado del programa sería: _La suma es 13 y a vale 5_, en 646 | lugar de La suma es 13 y a vale 0. 647 | 648 | [[ejercicios]] 649 | === [[anchor-7]]Ejercicios 650 | 651 | _*Ejercicio 1:*_ Encuentra un fallo muy grave: 652 | 653 | #include 654 | #include 655 | 656 | int main() 657 | 658 | \{ 659 | 660 | int *a; 661 | 662 | *a = 5; 663 | 664 | return EXIT_SUCCESS; 665 | 666 | } 667 | 668 | *Solución*: No hemos dado ninguna dirección al puntero. No sabemos a 669 | dónde apunta. Puede apuntar a cualquier sitio, al darle un valor estamos 670 | escribiendo en un lugar desconocido de la memoria. Esto puede dar 671 | problemas e incluso bloquear el ordenador. Recordemos que al ejecutar un 672 | programa éste se copia en la memoria, al escribir en cualquier parte 673 | puede que estemos cambiando el programa (en la memoria, no en el disco 674 | duro). 675 | 676 | _*Ejercicio 2:*_ Escribe un programa que asigne un valor a una variable 677 | de tipo _int_. Hacer un puntero que apunte a ella y sumarle 3 usando el 678 | puntero. Luego mostrar el resultado. 679 | 680 | *Solución*: Esta es una posible solución: 681 | 682 | #include 683 | #include 684 | 685 | int main() 686 | 687 | \{ 688 | 689 | int a; 690 | 691 | int *b; 692 | 693 | a = 5; 694 | 695 | b = &a; 696 | 697 | *b += 3; 698 | 699 | printf( "El valor de a es = %d.\n", a ); 700 | 701 | return EXIT_SUCCESS; 702 | 703 | } 704 | 705 | También se podía haber hecho: 706 | 707 | printf( "El valor de a es = %d\n", *b ); 708 | -------------------------------------------------------------------------------- /capitulo10.adoc: -------------------------------------------------------------------------------- 1 | //// 2 | Copyright: Gorka Urrutia Landa, 1999-2019 3 | Licencia: Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) https://creativecommons.org/licenses/by-sa/4.0/ 4 | //// 5 | 6 | :chapter: 010 7 | 8 | <<< 9 | 10 | [[capítulo-10.-arrays]] 11 | == Capítulo 10. Arrays 12 | 13 | [[qué-es-un-array]] 14 | === [[anchor]]¿Qué es un array? 15 | 16 | Nota: algunas personas conocen a los _arrays_ como _arreglos, matrices o vectores_. 17 | Sin embargo, en este curso, vamos a usar el término array ya que es, según creo, el más extendido en la bibliografía sobre el tema. 18 | 19 | La definición sería algo así: 20 | 21 | Un array es un conjunto de variables del mismo tipo que tienen el mismo 22 | nombre y se diferencian en el índice. 23 | 24 | Pero ¿qué quiere decir esto y para qué lo queremos? 25 | Pues bien, supongamos que somos un meteorólogo y queremos guardar en el ordenador la temperatura que ha hecho cada hora del día. 26 | Para darle cierta utilidad al final calcularemos la media de las temperaturas. 27 | Con lo que sabemos hasta ahora sería algo así (que nadie se moleste ni en probarlo): 28 | 29 | [source,c] 30 | ---- 31 | #include 32 | #include 33 | 34 | int main() 35 | { 36 | 37 | /* Declaramos 24 variables, una para cada hora del día */ 38 | int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8; 39 | int temp9, temp10, temp11, temp12, temp13, temp14, temp15, temp16; 40 | int temp17, temp18, temp19, temp20, temp21, temp22, temp23, temp0; 41 | 42 | float media; 43 | 44 | /* Ahora tenemos que dar el valor de cada una */ 45 | printf( "Temperatura de las 0: " ); 46 | scanf( "%d", &temp0 ); 47 | 48 | printf( "Temperatura de las 1: " ); 49 | scanf( "%d", &temp1 ); 50 | 51 | printf( "Temperatura de las 2: " ); 52 | scanf( "%d", &temp2 ); 53 | 54 | ... 55 | 56 | printf( "Temperatura de las 23: " ); 57 | scanf( "%d", &temp23 ); 58 | 59 | media = ( temp0 + temp1 + temp2 + temp3 + temp4 + ... + temp23 ) / 24; 60 | printf( "\nLa temperatura media es %f\n", media ); 61 | 62 | return EXIT_SUCCESS; 63 | 64 | } 65 | ---- 66 | 67 | NOTE: Los puntos suspensivos los he puesto para no tener que escribir todo y que no ocupe tanto, no se pueden usar en un programa. 68 | 69 | Para acortar un poco el programa podríamos hacer algo así: 70 | 71 | [source,c] 72 | ---- 73 | #include 74 | #include 75 | 76 | int main() 77 | { 78 | /* Declaramos 24 variables, una para cada hora del día */ 79 | int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8; 80 | int temp9, temp10, temp11, temp12, temp13, temp14, temp15, temp16; 81 | int temp17, temp18, temp19, temp20, temp21, temp22, temp23, temp0; 82 | 83 | float media; 84 | 85 | /* Ahora tenemos que dar el valor de cada una */ 86 | printf( "Introduzca las temperaturas desde las 0 hasta las 23 separadas 87 | por un espacio: " ); 88 | scanf( "%d %d %d ... %d", &temp0, &temp1, &temp2, ... &temp23 ); 89 | 90 | media = ( temp0 + temp1 + temp2 + temp3 + temp4 + ... + temp23 ) / 24; 91 | 92 | printf( "\nLa temperatura media es %f\n", media ); 93 | 94 | return EXIT_SUCCESS; 95 | } 96 | ---- 97 | 98 | Lo que no deja de ser un muy laborioso además de confuso para el usuario. 99 | Y esto con un ejemplo que tiene tan sólo 24 variables, ¡imagínate si son más! 100 | 101 | Y precisamente aquí es donde nos vienen de perlas los arrays. 102 | Vamos a hacer el programa con un array. 103 | Usaremos nuestros conocimientos de bucles _for_ y de _scanf_. 104 | 105 | [source,c] 106 | ---- 107 | #include 108 | #include 109 | 110 | int main() 111 | { 112 | int temp[24]; /* Con esto ya tenemos declaradas las 24 variables */ 113 | float media = 0; 114 | int hora; 115 | 116 | /* Ahora tenemos que dar el valor de cada una */ 117 | for( hora=0; hora<24; hora++ ) { 118 | printf( "Temperatura de las %i: ", hora ); 119 | scanf( "%d", &temp[hora] ); 120 | 121 | media += temp[hora]; 122 | } 123 | 124 | media = media / 24; 125 | printf( "\nLa temperatura media es %f\n", media ); 126 | 127 | return EXIT_SUCCESS; 128 | } 129 | ---- 130 | 131 | Como ves es un programa más corto que los anteriores (recuerda que hemos 132 | usado puntos suspensivos en los ejemplos anteriores, sin ellos el código 133 | hubiera sido mucho más largo). 134 | 135 | Como ya hemos comentado cuando declaramos una variable lo que estamos haciendo es reservar una zona de la memoria para ella. 136 | Cuando declaramos un array lo que hacemos (en este ejemplo) es reservar espacio en memoria para 24 variables de tipo _int_. 137 | El tamaño del array (24) lo indicamos entre corchetes al definirlo. 138 | 139 | En este ejemplo recorremos la matriz mediante un bucle _for_ y vamos dando valores a los distintos elementos de la matriz. 140 | Para indicar a qué elemento nos referimos usamos un número entre corchetes (en este caso la variable hora), este número es lo que se llama *Índice*. 141 | El primer elemento de la matriz tiene el índice 0, el segundo tiene el 1 y así sucesivamente. 142 | 143 | El índice de un elemento es siempre la posición del elemento menos uno. 144 | De modo que el cuarto elemento tendrá el índice 4-1 = 3. 145 | Y podemos asignarle un valor haciendo: 146 | 147 | [source,c] 148 | ---- 149 | temp[ 3 ] = 20; 150 | ---- 151 | 152 | NOTE: No hay que confundirse; En la declaración del array el número 153 | entre corchetes es el número de elementos, en cambio cuando ya usamos la 154 | matriz el número entre corchetes es el índice. 155 | 156 | [[declaración-de-un-array]] 157 | === [[anchor-1]]Declaración de un Array 158 | 159 | La forma general de declarar un array es la siguiente: 160 | 161 | _tipo_de_dato_ nombre_del_array[ dimensión ]; 162 | 163 | El _tipo_de_dato_ es uno de los tipos de datos conocidos (_int, char, 164 | float_...) o de los definidos por nosotros mismos con _typdef_ (lo 165 | estudiaremos más adelante). En el ejemplo el tipo de dato que habíamos 166 | usado era _int_. 167 | 168 | El _nombre_del_array_ es el nombre que damos al array, en el ejemplo era 169 | _temp_. El nombre de un array tiene las mismas limitaciones que vimos 170 | para un nombre de variable. 171 | 172 | La _dimensión_ es el número de elementos que tiene el array. 173 | 174 | Como he indicado antes, al declarar un array reservamos en memoria 175 | tantas variables del _tipo_de_dato_ como las indicada en _dimensión_. 176 | 177 | [[sobre-la-dimensión-de-un-array]] 178 | === [[anchor-2]][[anchor-3]]Sobre la dimensión de un Array 179 | 180 | Hemos visto en el ejemplo que tenemos que indicar en varios sitios el 181 | tamaño del array: en la declaración, en el bucle for y al calcular la 182 | media. Este es un programa pequeño, en un programa mayor probablemente 183 | habrá que escribirlo muchas más veces. Si en un momento dado queremos 184 | cambiar la dimensión del array tendremos que cambiar todos. Si nos 185 | equivocamos al escribir el tamaño (ponemos 25 en vez de 24) cometeremos 186 | un error y puede que no nos demos cuenta. Por eso es mejor usar una 187 | constante con nombre, por ejemplo ELEMENTOS. Además, nuestro código será 188 | más legible. 189 | 190 | Este sería el ejemplo anterior usando una constante para el tamaño del 191 | array: 192 | 193 | #include 194 | 195 | #define ELEMENTOS 24 196 | 197 | int main() 198 | 199 | \{ 200 | 201 | int temp[*ELEMENTOS*]; /* Con esto ya tenemos declaradas las 24 202 | variables */ 203 | 204 | float media = 0; 205 | 206 | int hora; 207 | 208 | /* Ahora tenemos que dar el valor de cada una */ 209 | 210 | for( hora=0; hora<**ELEMENTOS**; hora++ ) 211 | 212 | \{ 213 | 214 | printf( "Temperatura de las %i: ", hora ); 215 | 216 | scanf( "%d", &temp[hora] ); 217 | 218 | media += temp[hora]; 219 | 220 | } 221 | 222 | media = media / *ELEMENTOS*; 223 | 224 | printf( "\nLa temperatura media es %f\n", media ); 225 | 226 | return 0; 227 | 228 | } 229 | 230 | Ahora con sólo cambiar el valor de elementos una vez lo estaremos 231 | haciendo en todo el programa. 232 | 233 | [[inicializar-un-array]] 234 | === [[anchor-4]]Inicializar un array 235 | 236 | En *C* se pueden inicializar los arrays al declararlos igual que 237 | hacíamos con las variables. Recordemos que se podía hacer: 238 | 239 | int numero = 34; 240 | 241 | Con arrays se puede hacer: 242 | 243 | int temperaturas[24] = \{ 244 | 245 | 15, 18, 20, 23, 22, 24, 22, 25, 246 | 247 | 26, 25, 24, 22, 21, 20, 18, 17, 248 | 249 | 16, 17, 15, 14, 14, 14, 13, 12 250 | 251 | }; 252 | 253 | Así el primer elemento del array (que tiene índice 0), es decir 254 | temperaturas[0] valdrá 15. El segundo elemento (temperaturas[1]) valdrá 255 | 18 y así con todos. Vamos a ver un ejemplo: 256 | 257 | #include 258 | 259 | int main() 260 | 261 | \{ 262 | 263 | int hora; 264 | 265 | int temperaturas[24] = \{ 15, 18, 20, 23, 22, 24, 22, 25, 26, 25, 24, 266 | 267 | 22, 21, 20, 18, 17, 16, 17, 15, 14, 14, 14, 268 | 269 | 13, 12 }; 270 | 271 | for (hora=0 ; hora<24 ; hora++ ) 272 | 273 | \{ 274 | 275 | printf( "La temperatura a las %i era 276 | 277 | de %i grados.\n", hora, 278 | 279 | temperaturas[hora] ); 280 | 281 | } 282 | 283 | return 0; 284 | 285 | } 286 | 287 | *Nota:* en la inicialización de arrays sólo pueden usarse numeros y 288 | constantes. No se pueden usar variables. Por ejemplo: 289 | 290 | #define ELEMENTOS 24 291 | 292 | ... + 293 | int array[3] = \{1, ELEMENTOS, 3}; 294 | 295 | Pero a ver quién es el habilidoso que no se equivoca al meter los datos, 296 | no es difícil olvidarse alguno. Hemos indicado al compilador que nos 297 | reserve memoria para un array de 24 elementos de tipo int. ¿Qué ocurre 298 | si metemos menos de los reservados? Pues no pasa nada, sólo que los 299 | elementos que falten valdrán cero. 300 | 301 | #include 302 | 303 | int main() 304 | 305 | \{ 306 | 307 | int hora; 308 | 309 | /* Faltan los tres últimos elementos */ 310 | 311 | int temperaturas[24] = \{ 15, 18, 20, 23, 22, 24, 22, 25, 26, 25, 312 | 313 | 24, 22, 21, 20, 18, 17, 16, 17, 15, 14, 14 }; 314 | 315 | for (hora=0 ; hora<24 ; hora++ ) 316 | 317 | \{ 318 | 319 | printf( "La temperatura a las %i era de %i grados.\n", hora, 320 | temperaturas[hora] ); 321 | 322 | } 323 | 324 | return 0; 325 | 326 | } 327 | 328 | El resultado será: 329 | 330 | La temperatura a las 0 era de 15 grados. 331 | 332 | La temperatura a las 1 era de 18 grados. 333 | 334 | La temperatura a las 2 era de 20 grados. 335 | 336 | La temperatura a las 3 era de 23 grados. 337 | 338 | ... 339 | 340 | La temperatura a las 17 era de 17 grados. 341 | 342 | La temperatura a las 18 era de 15 grados. 343 | 344 | La temperatura a las 19 era de 14 grados. 345 | 346 | La temperatura a las 20 era de 14 grados. 347 | 348 | La temperatura a las 21 era de 0 grados. 349 | 350 | La temperatura a las 22 era de 0 grados. 351 | 352 | La temperatura a las 23 era de 0 grados. 353 | 354 | Vemos que los últimos 3 elementos son nulos, que son aquellos a los que 355 | no hemos dado valores. El compilador no nos avisa que hemos metido menos 356 | datos de los reservados. 357 | 358 | NOTA: Fíjate que para recorrer del elemento 0 al 23 (24 elementos) 359 | hacemos: 360 | 361 | for(hora=0; hora<24; hora++) 362 | 363 | La condición es que _hora_ sea menor que 24. También podíamos haber 364 | hecho que hora!=24, pero es menos correcto. 365 | 366 | Ahora vamos a ver el caso contrario, metemos más datos de los 367 | reservados. Vamos a meter 25 en vez de 24. Si hacemos esto dependiendo 368 | del compilador obtendremos un error o al menos un warning (aviso). En 369 | unos compiladores el programa se creará y en otros no, pero aún así nos 370 | avisa del fallo. 371 | 372 | Si la matriz debe tener una longitud determinada usamos el método de 373 | indicar el número de elementos al declarar el array. En nuestro caso era 374 | conveniente, porque los días siempre tienen 24 horas. Es importante 375 | definir el tamaño de la matriz para que nos avise si metemos más 376 | elementos de los necesarios. 377 | 378 | Hay casos en los que podemos usar un método alternativo, dejar al 379 | ordenador que cuente los elementos que hemos metido y nos reserve 380 | espacio para ellos: 381 | 382 | #include 383 | 384 | int main() 385 | 386 | \{ 387 | 388 | int hora; 389 | 390 | /* Faltan los tres últimos elementos */ 391 | 392 | int **temperaturas**__*[]*__ = \{ 393 | 394 | 15, 18, 20, 23, 22, 395 | 396 | 24, 22, 25, 26, 25, 397 | 398 | 24, 22, 21, 20, 18, 399 | 400 | 17, 16, 17, 15, 14, 401 | 402 | 14 }; 403 | 404 | for ( hora=0 ; hora<24 ; hora++ ) 405 | 406 | \{ 407 | 408 | printf( "La temperatura a las %i era de %i grados.\n", hora, 409 | temperaturas[hora] ); 410 | 411 | } 412 | 413 | return 0; 414 | 415 | } 416 | 417 | Vemos que no hemos especificado la dimensión del array _temperaturas_. 418 | Hemos dejado los corchetes en blanco. El ordenador contará los elementos 419 | que hemos puesto entre llaves y reservará espacio para ellos. De esta 420 | forma siempre habrá el espacio necesario, ni más ni menos. La pega es 421 | que si ponemos más de los que queríamos no nos daremos cuenta, como en 422 | el ejemplo. 423 | 424 | Este es el resultado que obtendríamos: 425 | 426 | La temperatura a las 0 era de 15 grados. 427 | 428 | La temperatura a las 1 era de 18 grados. 429 | 430 | La temperatura a las 2 era de 20 grados. 431 | 432 | ... 433 | 434 | La temperatura a las 20 era de 14 grados. 435 | 436 | La temperatura a las 21 era de -1216612880 grados. 437 | 438 | La temperatura a las 22 era de 0 grados. 439 | 440 | La temperatura a las 23 era de 134513819 grados. 441 | 442 | Vemos que las últimas tres líneas dan un resultado extraño. ¿De dónde 443 | salen esos números? Se debe a que el array sólo tenía 21 elementos pero 444 | hemos leído 24 valores. Los tres últimos son datos que había en la 445 | memoria y que no tenían relación con el array. Se debe tener mucho 446 | cuidado con esto. 447 | 448 | Para saber en este caso cuantos elementos tiene la matriz podemos usar 449 | el operador sizeof. Dividimos el tamaño de la matriz entre el tamaño de 450 | sus elementos y tenemos el número de elementos. 451 | 452 | #include 453 | 454 | int main() 455 | 456 | \{ 457 | 458 | int hora; 459 | 460 | int elementos; 461 | 462 | int temperaturas[] = \{ 15, 18, 20, 23, 22, 24, 22, 25, 26, 25, 463 | 464 | 24, 22, 21, 20, 18, 17, 16, 17, 15, 14, 14 }; 465 | 466 | *elementos = sizeof temperaturas / sizeof(int);* 467 | 468 | for ( hora=0 ; hora 503 | 504 | int main() 505 | 506 | \{ 507 | 508 | int hora; 509 | 510 | int temperaturas[24] = \{ 511 | 512 | 15, 18, 20, 23, 22, 513 | 514 | 24, 22, 25, 26, 25, 515 | 516 | 24, 22, 21, 20, 18, 517 | 518 | 17, 16, 17, 15, 14, 519 | 520 | 14, 13, 13, 12 }; 521 | 522 | for (hora=0 ; *hora<28* ; hora++ ) 523 | 524 | \{ 525 | 526 | printf( "La temperatura a las %i era de %i grados.\n", hora, 527 | temperaturas[hora] ); 528 | 529 | } 530 | 531 | return 0; 532 | 533 | } 534 | 535 | Lo que se obtiene es algo similar a esto: 536 | 537 | La temperatura a las 22 era de 15 grados. 538 | 539 | ... 540 | 541 | La temperatura a las 23 era de 12 grados. 542 | 543 | La temperatura a las 24 era de 24 grados. 544 | 545 | La temperatura a las 25 era de 3424248 grados. 546 | 547 | La temperatura a las 26 era de 7042 grados. 548 | 549 | La temperatura a las 27 era de 1 grados. 550 | 551 | Vemos que a partir del elemento 24 (incluido) tenemos resultados 552 | extraños. Esto es porque nos hemos salido de los límites del array e 553 | intenta acceder al elemento temperaturas[25] y sucesivos que no existen. 554 | Así que nos muestra el contenido de la memoria que está justo detrás de 555 | temperaturas[23] que puede ser cualquiera. Al contrario que otros 556 | lenguajes C no comprueba los límites de los array, nos deja saltárnoslos 557 | a la torera. Este programa no da error al compilar ni al ejecutar, tan 558 | sólo devuelve resultados extraños. Tampoco bloqueará el sistema porque 559 | no estamos escribiendo en la memoria sino leyendo de ella. 560 | 561 | Otra cosa muy diferente es meter datos en elementos que no existen. 562 | Veamos un ejemplo *(ni se te ocurra ejecutarlo)*: 563 | 564 | #include 565 | 566 | int main() 567 | 568 | \{ 569 | 570 | int temp[24]; 571 | 572 | float media = 0; 573 | 574 | int hora; 575 | 576 | for( hora=0; *hora<28*; hora++ ) 577 | 578 | \{ 579 | 580 | printf( "Temperatura de las %d: ", hora ); 581 | 582 | scanf( "%d", &temp[hora] ); 583 | 584 | media += temp[hora]; 585 | 586 | } 587 | 588 | media = media / 24; 589 | 590 | printf( "\nLa temperatura media es %f\n", media ); 591 | 592 | return 0; 593 | 594 | } 595 | 596 | En muchos ordenadores seguramente el programa se cerrará por un error o 597 | puede que incluso quede bloqueado el ordenador. Es probable que incluso 598 | haya que apagarlo. El problema ahora es que estamos intentando escribir 599 | en el elemento _temp[24]_ que no existe y puede ser un lugar cualquiera 600 | de la memoria. Como consecuencia de esto podemos estar cambiando algún 601 | programa o dato de la memoria que no debemos y el sistema hace pluf. Así 602 | que mucho cuidado con esto. 603 | 604 | [[punteros-a-arrays]] 605 | === [[anchor-5]]Punteros a arrays 606 | 607 | Aquí tenemos otro de los importantes usos de los punteros, los punteros 608 | a arrays. Estos están íntimamente relacionados. 609 | 610 | Para que un puntero apunte a un array se puede hacer de dos formas, una 611 | es apuntando al primer elemento del array: 612 | 613 | int *puntero; 614 | 615 | int temperaturas[24]; 616 | 617 | puntero = &temperaturas[0]; 618 | 619 | El puntero apunta a la dirección del primer elemento. Otra forma 620 | equivalente, pero mucho más usada es: 621 | 622 | puntero = temperaturas; 623 | 624 | Con esto también apuntamos al primer elemento del array. Fijaos que el 625 | puntero tiene que ser del mismo tipo que el array (en este caso int). 626 | 627 | Ahora vamos a ver cómo acceder al resto de los elementos. Para ello 628 | empezamos por cómo funciona un array: Un array se guarda en posiciones 629 | consecutivas en memoria, de tal forma que el segundo elemento va 630 | inmediatamente después del primero en la memoria. En un ordenador en el 631 | que el tamaño del tipo int es de 32 bits (4 bytes) cada elemento del 632 | array ocupará 4 bytes. Veamos un ejemplo: 633 | 634 | #include 635 | 636 | int main() 637 | 638 | \{ 639 | 640 | int i; 641 | 642 | int temp[24]; 643 | 644 | for( i=0; i<24; i++ ) 645 | 646 | \{ 647 | 648 | printf( "La dirección del elemento %i es %p.\n", 649 | 650 | i, (void *)&temp[i] ); 651 | 652 | } 653 | 654 | return 0; 655 | 656 | } 657 | 658 | NOTA: Recuerda que %p sirve para mostrar en pantalla una posición de 659 | memoria en hexadecimal. 660 | 661 | El resultado es (en mi ordenador): 662 | 663 | La dirección del elemento 0 es 4c430. 664 | 665 | La dirección del elemento 1 es 4c434. 666 | 667 | La dirección del elemento 2 es 4c438. 668 | 669 | La dirección del elemento 3 es 4c43c. 670 | 671 | ... 672 | 673 | La dirección del elemento 21 es 4c484. 674 | 675 | La dirección del elemento 22 es 4c488. 676 | 677 | La dirección del elemento 23 es 4c48c. 678 | 679 | (Las direcciones están en hexadecimal). Vemos aquí que efectivamente 680 | ocupan posiciones consecutivas y que cada una ocupa 4 bytes. Si lo 681 | representamos en una tabla: 682 | 683 | [cols=",,,",] 684 | |================================== 685 | |4C430 |4C434 |4C438 |4C43C 686 | |temp[0] |temp[1] |temp[2] |temp[3] 687 | |================================== 688 | 689 | Ya hemos visto cómo funcionan los arrays por dentro, ahora vamos a verlo 690 | con punteros. Voy a poner un ejemplo: 691 | 692 | #include 693 | 694 | int main() 695 | 696 | \{ 697 | 698 | int i; 699 | 700 | int temp[24]; 701 | 702 | int *punt; 703 | 704 | *punt = temp;* 705 | 706 | for( i=0; i<24; i++ ) 707 | 708 | \{ 709 | 710 | printf( "La dirección de temp[%i] es %p y la de punt es %p.\n", 711 | 712 | i, (void *) &temp[i], (void *) *punt* ); 713 | 714 | *punt++;* 715 | 716 | } 717 | 718 | return 0; 719 | 720 | } 721 | 722 | Cuyo resultado es: 723 | 724 | La dirección de temp[0] es 4c430 y la de punt es 4c430. 725 | 726 | La dirección de temp[1] es 4c434 y la de punt es 4c434. 727 | 728 | La dirección de temp[2] es 4c438 y la de punt es 4c438. 729 | 730 | ... 731 | 732 | La dirección de temp[21] es 4c484 y la de punt es 4c484. 733 | 734 | La dirección de temp[22] es 4c488 y la de punt es 4c488. 735 | 736 | La dirección de temp[23] es 4c48c y la de punt es 4c48c. 737 | 738 | En este ejemplo hay dos líneas importantes (en negrita). La primera es 739 | _punt = temp_. Con esta hacemos que el punt apunte al primer elemento de 740 | la matriz. Si no hacemos esto punt apunta a un sitio cualquiera de la 741 | memoria y debemos recordar que no es conveniente dejar los punteros así, 742 | puede ser desastroso. 743 | 744 | La segunda línea importante es _punt++_. Con esto incrementamos el valor 745 | de punt, pero curiosamente aunque incrementamos una unidad (punt++ 746 | equivale a punt=punt+1) el valor aumenta en 4. Aquí se muestra una de 747 | las características especiales de los punteros. Recordemos que en un 748 | puntero se guarda una dirección. También sabemos que un puntero apunta a 749 | un tipo de datos determinado (en este caso int). Cuando sumamos 1 a un 750 | puntero sumamos el tamaño del tipo al que apunta. En el ejemplo el 751 | puntero apunta a una variable de tipo int que es de 4 bytes, entonces al 752 | sumar 1 lo que hacemos es sumar 4 bytes. Con esto lo que se consigue es 753 | apuntar a la siguiente posición int de la memoria, en este caso es el 754 | siguiente elemento de la matriz. 755 | 756 | Esta tabla describe el bucle programa paso a pos: 757 | 758 | [cols=",,",] 759 | |======================================================================= 760 | |Operación |Equivalente |Valor de _punt_ 761 | 762 | |punt = temp; |punt = &temp[0]; |4c430 763 | 764 | |punt++; (en el primer ciclo del for) |sumar 4 al contenido de _punt_ 765 | (4c430 + 4) |4c434 766 | 767 | |punt++; (en el segundo ciclo del for) |sumar 4 al contenido de _punt_ 768 | (4c434 + 4) |4c438 769 | |======================================================================= 770 | 771 | Cuando hemos acabado estamos en temp[24] que no existe. Si queremos 772 | haver que _punt_ vuelva al elemento 1 podemos hacer _punt = temp_ otra 773 | vez o restar 24 a punt: 774 | 775 | punt -= 24; 776 | 777 | con esto hemos restado 24 posiciones a punt (24 posiciones int*4 bytes 778 | por cada int= 96 posiciones). 779 | 780 | Al final del programa _punt_ apunta a la dirección de memoria 4C490. 781 | Para volver a la primera posición hemos dicho que restamos 24, que es 782 | equivalente a hacer: 783 | 784 | 4C490 – 18 * 4 = 4c430 785 | 786 | donde: 787 | 788 | * 4C490 es la posición de _punt_. 789 | * 18 es el número de posiciones que queremos restar (¡ojo! 24 en 790 | hexadecimal es 18). 791 | * 4 es el tamaño de un _int_ (en el sistema donde se ha probado el 792 | ejemplo anterior). 793 | 794 | Si coges una calculadora científica podrás ver que los números 795 | coinciden. 796 | 797 | Vamos a ver ahora un ejemplo de cómo recorrer la matriz entera con 798 | punteros y cómo mostrarla en pantalla: 799 | 800 | #include 801 | 802 | int main() 803 | 804 | \{ 805 | 806 | int temperaturas[24] = \{ 807 | 808 | 15, 18, 20, 23, 22, 809 | 810 | 24, 22, 25, 26, 25, 811 | 812 | 24, 22, 21, 20, 18, 813 | 814 | 17, 16, 17, 15, 14, 815 | 816 | 14, 13, 12, 12 }; 817 | 818 | int *punt; 819 | 820 | int i; 821 | 822 | punt = temperaturas; 823 | 824 | for( i=0 ; i<24; i++ ) 825 | 826 | \{ 827 | 828 | printf( "Elemento %i: %i\n", i, *punt ); 829 | 830 | punt++; 831 | 832 | } 833 | 834 | return 0; 835 | 836 | } 837 | 838 | Cuando termina el bucle _for_ el puntero _punt_ apunta a 839 | _temperaturas[24]_, y no al primer elemento, si queremos volver a 840 | recorrer la matriz debemos volver como antes al comienzo. Para evitar 841 | perder la referencia al primer elemento de la matriz (_temperaturas[0]_) 842 | se puede usar otra forma de recorrer la matriz con punteros: 843 | 844 | #include 845 | 846 | int main() 847 | 848 | \{ 849 | 850 | int temperaturas[24] = \{ 851 | 852 | 15, 18, 20, 23, 22, 853 | 854 | 24, 22, 25, 26, 25, 855 | 856 | 24, 22, 21, 20, 18, 857 | 858 | 17, 16, 17, 15, 14, 859 | 860 | 14, 13, 12, 12 }; 861 | 862 | int *punt; 863 | 864 | int i; 865 | 866 | punt = temperaturas; 867 | 868 | for( i=0 ; i<24; i++ ) 869 | 870 | \{ 871 | 872 | printf( "Elemento %i: %i\n", i, _**(punt+i)*_ ); 873 | 874 | } 875 | 876 | return 0; 877 | 878 | } 879 | 880 | Con _*(punt+i)_ lo que hacemos es tomar la dirección a la que apunta 881 | _punt_ (la dirección del primer elemento de la matriz) y le sumamos _i_ 882 | posiciones. De esta forma tenemos la dirección del elemento _i_. No 883 | estamos sumando un valor a _punt_, para sumarle un valor habría que 884 | hacer _punt++_ o _punt+=algo_, así que _punt_ siempre apunta al 885 | principio de la matriz. 886 | 887 | Se podría hacer este programa sin usar _punt_. Sustituyéndolo por 888 | _temperaturas_ y dejar __*(temperaturas+i)__. Lo que no se puede hacer 889 | es: __temperaturas++;__. 890 | 891 | *Importante:* Como final debo comentar que el uso de índices es una 892 | forma de maquillar el uso de punteros. El ordenador convierte los 893 | índices a punteros. Cuando al ordenador le decimos _temp[5]_ en realidad 894 | le estamos diciendo *(temp+5). Así que usar índices es casi equivalente 895 | a usar punteros de una forma más cómoda (en la sección siguiente vamos a 896 | ver una diferencia). 897 | 898 | Las que sí son equivalentes son estas dos definiciones: 899 | 900 | int temp[]; 901 | 902 | int *temp; 903 | 904 | [[paso-de-un-array-a-una-función]] 905 | === [[anchor-6]]Paso de un array a una función 906 | 907 | En *C* se suele usar un puntero cuando se quiere pasar un parámetro a 908 | una función: 909 | 910 | int sumar( int *m ) 911 | 912 | Otras declaraciones equivalentes serían: 913 | 914 | int sumar( int m[] ) 915 | 916 | o 917 | 918 | int sumar( int m[10] ) 919 | 920 | En realidad esta última no se suele usar, porque el número de elementos 921 | es ignorado por el compilador. 922 | 923 | Con el puntero que hemos usado en la definición de la función podemos 924 | recorrer el array: 925 | 926 | #include 927 | 928 | int sumar( int *m ) 929 | 930 | \{ 931 | 932 | int suma, i; 933 | 934 | suma = 0; 935 | 936 | for( i=0; i<10; i++ ) 937 | 938 | \{ 939 | 940 | suma += m[i]; 941 | 942 | } 943 | 944 | return suma; 945 | 946 | } 947 | 948 | int main() 949 | 950 | \{ 951 | 952 | int contador; 953 | 954 | int matriz[10] = \{ 10, 11, 13, 10, 14, 9, 10, 18, 10, 10 }; 955 | 956 | /* Mostramos el array */ 957 | 958 | for( contador=0; contador<10; contador++ ) 959 | 960 | printf( " %3i\n", matriz[contador] ); 961 | 962 | /* Calculamos la suma de los elementos y la mostramos */ 963 | 964 | printf( "+ -----\n" ); 965 | 966 | printf( " %3i", sumar( matriz ) ); 967 | 968 | return 0; 969 | 970 | } 971 | 972 | NOTA: Este programa tiene un detalle adicional que es que muestra toda 973 | la matriz en una columna. Además se usa para imprimir los números el 974 | modificador *%3i*. El 3 indica que se tienen que alinear los números a 975 | la derecha, así queda más elegante. 976 | 977 | Como he indicado no se pasa el array, sino un puntero a ese array. Antes 978 | hemos usado el truco del _sizeof_ para calcular el número de elementos 979 | de un array. Si lo probamos aquí no funcionará. Vamos a verlo con un 980 | ejemplo: 981 | 982 | #include 983 | 984 | void calcular_tamano( int *m ) 985 | 986 | \{ 987 | 988 | printf( "Tamaño del array (m, dentro de la función): %i Kb\n", sizeof m 989 | ); 990 | 991 | } 992 | 993 | int main() 994 | 995 | \{ 996 | 997 | int matriz[10] = \{ 10, 11, 13, 10, 14, 9, 10, 18, 10, 10 }; 998 | 999 | int *pmatriz; 1000 | 1001 | pmatriz = matriz; 1002 | 1003 | printf( "Tamaño del array (matriz): %i Kb\n", sizeof matriz ); 1004 | 1005 | printf( "Tamaño del array (pmatriz): %i Kb\n", sizeof pmatriz ); 1006 | 1007 | calcular_tamano( matriz ); 1008 | 1009 | return 0; 1010 | 1011 | } 1012 | 1013 | El resultado será: 1014 | 1015 | Tamaño del array (matriz): 40 Kb 1016 | 1017 | Tamaño del array (pmatriz): 4 Kb 1018 | 1019 | Tamaño del array (m, dentro de la función): 4 Kb 1020 | 1021 | ¿Por qué dice _sizeof_ que el tamaño es 4 Kb cuando usamos un puntero? 1022 | Porque nos calcula el tamaño del tipo de dato al que apunta el puntero. 1023 | ¿Cómo sabemos entonces cual es el tamaño del array dentro de la función? 1024 | En este caso lo hemos puesto nosotros mismos, 10. Pero se pueden 1025 | utilizar constantes como en el apartado “link:#anchor-2[Sobre la 1026 | dimensión de un Array]”, o se puede pasar el tamaño del array como 1027 | parámetro a la función. 1028 | 1029 | En el ejemplo usamos un puntero pero vemos que luego estamos usando 1030 | _m[i]_. Esto lo podemos hacer porque, como se ha mencionado antes, el 1031 | uso de índices en una forma que nos ofrece *C* de manejar punteros con 1032 | matrices. Ya hemos visto que _m[i]_ es equivalente a _*(m+i)_. 1033 | -------------------------------------------------------------------------------- /crear_libro.sh: -------------------------------------------------------------------------------- 1 | # Software necesario 2 | # sudo apt install asciidoc 3 | # sudo apt install libxml2-utils 4 | # sudo apt install dblatex 5 | 6 | # AsciiDoctor PDF 7 | asciidoctor -r asciidoctor-pdf -b pdf book.adoc 8 | mv book.pdf programacion-c-principiantes-gorka-urrutia.pdf 9 | 10 | 11 | -------------------------------------------------------------------------------- /imagenes/listas1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gorkau/Libro-Programacion-en-C/d11c2c6446c0a9efb6aea3da5e10a1f5e93954d0/imagenes/listas1.gif -------------------------------------------------------------------------------- /imagenes/listas2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gorkau/Libro-Programacion-en-C/d11c2c6446c0a9efb6aea3da5e10a1f5e93954d0/imagenes/listas2.gif -------------------------------------------------------------------------------- /imagenes/listas3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gorkau/Libro-Programacion-en-C/d11c2c6446c0a9efb6aea3da5e10a1f5e93954d0/imagenes/listas3.gif -------------------------------------------------------------------------------- /imagenes/listas4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gorkau/Libro-Programacion-en-C/d11c2c6446c0a9efb6aea3da5e10a1f5e93954d0/imagenes/listas4.gif -------------------------------------------------------------------------------- /imagenes/punteros1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gorkau/Libro-Programacion-en-C/d11c2c6446c0a9efb6aea3da5e10a1f5e93954d0/imagenes/punteros1.png -------------------------------------------------------------------------------- /imagenes/punteros1.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gorkau/Libro-Programacion-en-C/d11c2c6446c0a9efb6aea3da5e10a1f5e93954d0/imagenes/punteros1.xcf -------------------------------------------------------------------------------- /imagenes/punteros2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gorkau/Libro-Programacion-en-C/d11c2c6446c0a9efb6aea3da5e10a1f5e93954d0/imagenes/punteros2.png -------------------------------------------------------------------------------- /imagenes/punteros2.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gorkau/Libro-Programacion-en-C/d11c2c6446c0a9efb6aea3da5e10a1f5e93954d0/imagenes/punteros2.xcf -------------------------------------------------------------------------------- /imagenes/punteros3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gorkau/Libro-Programacion-en-C/d11c2c6446c0a9efb6aea3da5e10a1f5e93954d0/imagenes/punteros3.png -------------------------------------------------------------------------------- /imagenes/punteros3.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gorkau/Libro-Programacion-en-C/d11c2c6446c0a9efb6aea3da5e10a1f5e93954d0/imagenes/punteros3.xcf -------------------------------------------------------------------------------- /imagenes/punteros4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gorkau/Libro-Programacion-en-C/d11c2c6446c0a9efb6aea3da5e10a1f5e93954d0/imagenes/punteros4.png -------------------------------------------------------------------------------- /imagenes/punteros4.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gorkau/Libro-Programacion-en-C/d11c2c6446c0a9efb6aea3da5e10a1f5e93954d0/imagenes/punteros4.xcf -------------------------------------------------------------------------------- /imagenes/union.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gorkau/Libro-Programacion-en-C/d11c2c6446c0a9efb6aea3da5e10a1f5e93954d0/imagenes/union.png -------------------------------------------------------------------------------- /imagenes/union.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gorkau/Libro-Programacion-en-C/d11c2c6446c0a9efb6aea3da5e10a1f5e93954d0/imagenes/union.xcf -------------------------------------------------------------------------------- /imagenes/union1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gorkau/Libro-Programacion-en-C/d11c2c6446c0a9efb6aea3da5e10a1f5e93954d0/imagenes/union1.png -------------------------------------------------------------------------------- /imagenes/union1.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gorkau/Libro-Programacion-en-C/d11c2c6446c0a9efb6aea3da5e10a1f5e93954d0/imagenes/union1.xcf -------------------------------------------------------------------------------- /programacion-c-principiantes-gorka-urrutia.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gorkau/Libro-Programacion-en-C/d11c2c6446c0a9efb6aea3da5e10a1f5e93954d0/programacion-c-principiantes-gorka-urrutia.pdf --------------------------------------------------------------------------------