programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los...

101
PROGRAMACIÓN I MÓNICA MACÍAS PARA LA LICENCIATURA EN MATEMÁTICAS Y LA LICENCIATURA EN MATEMÁTICAS APLICADAS ACTUALIZACIÓN: ENERO 2020 BENEMÉRITA UNIVERSIDAD AUTÓNOMA DE PUEBLA FACULTAD DE CIENCIAS FÍSICO MATEMÁTICAS

Transcript of programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los...

Page 1: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

PROGRAMACIÓN I MÓNICA MACÍAS

PARA LA LICENCIATURA EN MATEMÁTICAS Y LA LICENCIATURA EN MATEMÁTICAS APLICADAS

ACTUALIZACIÓN: ENERO 2020

BENEMÉRITA UNIVERSIDAD AUTÓNOMA DE PUEBLA FACULTAD DE CIENCIAS FÍSICO MATEMÁTICAS

Page 2: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

1

CONTENIDO

1 PRELIMINARES, CONCEPTOS BÁSICOS 6

2 CONCEPTO DE ALGORITMO 11

3 LENGUAJES DE PROGRAMACIÓN 12

4 DATOS Y EXPRESIONES EN UN PROGRAMA 14

5 PROCESO DE RESOLUCIÓN DE PROBLEMAS UTILIZANDO UN LENGUAJE

DE PROGRAMACIÓN 17

5.1 Fase de solución ............................................................................................... 17

5.2 Fase de implementación del diseño ................................................................. 22

6 LENGUAJE C 24

7 INSTRUCCIONES DE ENTRADA Y SALIDA 42

8 ESTRUCTURAS SECUENCIALES Y SELECTIVAS 48

8.1 Estructura secuencial ....................................................................................... 48 8.2 Estructuras selectivas ....................................................................................... 48

8.2.1 Alternativa simple (si-entonces) ............................................................... 49 8.2.2 Alternativa doble (si entonces sino) ......................................................... 50

8.2.3 Alternativa múltiple (selector) .................................................................. 51 8.2.4 Alternativa múltiple (no selectora) ........................................................... 52

8.2.5 Estructuras de decisión anidadas o en cascada ......................................... 54

8.2.6 Operador ternario ...................................................................................... 55

9 ESTRUCTURAS REPETITIVAS 56

9.1 Estructura mientras .......................................................................................... 56

9.2 Estructura hacer mientras ................................................................................. 57 9.3 Estructura desde o para .................................................................................... 58

9.4 Estructuras repetitivas anidadas ....................................................................... 61 9.5 Instrucciones que alteran el flujo normal de un ciclo ...................................... 61

10 NÚMEROS PSEUDOALEATORIOS EN EL LENGUAJE C 62

11 ARREGLOS 65

11.1 Arreglos unidimensionales ........................................................................... 66

Page 3: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

2

11.2 Arreglos bidimensionales ............................................................................. 69

12 CARACTERES, CADENAS Y ARREGLOS DE CARACTERES 72

12.1 Caracteres ..................................................................................................... 72 12.2 Cadenas de caracteres................................................................................... 77 12.3 Arreglos de caracteres .................................................................................. 80

13 FUNCIONES 81

13.1 Funciones definidas por el usuario en el lenguaje C .................................... 82 13.2 Prototipo de funciones .................................................................................. 85 13.3 Paso de parámetros por valor y por referencia ............................................. 89

13.4 Reglas básicas de alcance o ámbito (scope) ................................................. 93 13.5 Variables locales y variables globales .......................................................... 94

14 ANEXOS 96

14.1 Prácticas sanas de programación .................................................................. 96

15 REFERENCIAS 99

Page 4: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

3

ÍNDICE DE TABLAS

Tabla 1. Algunos múltiplos del byte. .............................................................................. 10

Tabla 2. Ejemplos del tamaño en bytes de algunos tipos de datos. ................................ 10

Tabla 3. Identificadores de variables. ............................................................................. 16

Tabla 4. Simbología en un diagrama de flujo según la ISO y el ANSI. ........................ 20

Tabla 5. Simbología en un diagrama de flujo según DFD, RAPTOR y PSeInt. ............ 21

Tabla 6. Tipos de datos estándar en el lenguaje C.......................................................... 32

Tabla 7. Operadores aritméticos. .................................................................................... 34

Tabla 8. Prioridad de operadores aritméticos. ................................................................ 35

Tabla 9. Operadores relacionales.................................................................................... 36

Tabla 10. Operadores lógicos. ........................................................................................ 36

Tabla 11. Operadores de asignación. .............................................................................. 38

Tabla 12. Prioridad de operadores. ................................................................................. 40

Tabla 13. Valores resultantes según expresiones aplicadas a las variables a, b, c y d. .. 41

Tabla 14. Secuencias de escape para printf. ................................................................... 43

Tabla 15. Especificaciones de formato para printf . ....................................................... 43

Tabla 16. Códigos de formato para scanf. ...................................................................... 45

Tabla 17. Código ASCII de caracteres de control. ......................................................... 73

Tabla 18. Código ASCII de caracteres alfabéticos, numéricos y especiales. ................. 74

Page 5: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

4

ÍNDICE DE FIGURAS

Figura 1. Estructura funcional de un ordenador. .............................................................. 7

Figura 2. Representación binaria del abecedario. ........................................................... 10

Figura 3. Intérprete. ........................................................................................................ 14

Figura 4. Fases de la compilación. ................................................................................. 15

Figura 5. Fases para producir código ejecutable a partir de código fuente en C. ........... 27

Figura 6. Estructura secuencial. ...................................................................................... 48

Figura 7. Alternativa simple. .......................................................................................... 49

Figura 8. Alternativa doble. ............................................................................................ 50

Figura 9. Alternativa múltiple (selector). ....................................................................... 51

Figura 10. Alternativa múltiple (no selectora). .............................................................. 53

Figura 11. Ejemplo de estructuras selectivas anidadas 1................................................ 54

Figura 12. Ejemplo de estructuras selectivas andadas 2. ................................................ 54

Figura 13. Ejemplo de estructuras selectivas anidadas 3................................................ 55

Figura 14. Estructura mientras. ...................................................................................... 57

Figura 15. Estructura repetir hacer mientras. ................................................................. 58

Figura 16. Estructura desde o para. ................................................................................ 59

Figura 17. Otra forma de representar a la estructura desde o para. ................................ 59

Figura 18. Representación gráfica de un arreglo unidimensional. ................................. 66

Figura 19. Representación gráfica del vector V con 10 elementos de tipo real. ............ 67

Figura 20. Representación gráfica de un arreglo bidimensional . .................................. 69

Figura 21. Representación gráfica del arreglo bidimensional C . .................................. 72

Figura 22. Ejemplo del llamado de una función en el lenguaje C. ................................. 83

Page 6: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

5

Figura 23. Representación gráfica y en memoria de variables y apuntadores. .............. 91

Figura 24. Ejemplo de alcance de una variable en el lenguaje C. .................................. 95

Page 7: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

6

1 PRELIMINARES, CONCEPTOS BÁSICOS

Computadora

Una computadora, también llamada ordenador, es un dispositivo electrónico capaz de

ejecutar cálculos y tomar decisiones lógicas a grandes velocidades, dotada de memoria y de

métodos de tratamiento de información, utilizando programas informáticos (Deitel y Deitel,

1995).

Para Chaitin (2015):

El ordenador era (y aún es) un nuevo concepto filosófico y matemático fabuloso.

Las computadoras alteran la forma de hacer matemáticas, modifican el tipo de modelos

matemáticos que confeccionamos del mundo… evocan una filosofía digital, sugieren una

forma nueva de observar el mundo donde todo es discreto y nada es continuo, donde todo es

información digital, ceros y unos.

Se inventaron para esclarecer una cuestión filosófica relacionada con los fundamentos de las

matemáticas.

Esta historia increíble comienza con David Hilbert, un matemático alemán muy conocido que

a principios del siglo XX propuso formalizar por completo todo el razonamiento matemático.

Resultó que no se puede formalizar el razonamiento matemático, así que en cierto modo su

idea fue un tremendo fracaso. Pero en otro sentido, la idea de Hilbert fue un éxito porque el

formalismo ha supuesto una de las grandes aportaciones del siglo XX, no para el razonamiento

o la deducción matemáticos, sino para la programación, para el cálculo, para la computación:

un fragmento olvidado de la historia del intelecto. (pp. 15-16, 207)

Hardware y software

Los dispositivos como el teclado, la pantalla, los discos duros, la memoria, los circuitos

electrónicos, cables y otros elementos físicos que conforman la máquina en sí, se conocen

como hardware. Por otro lado, los programas o aplicaciones informáticas que se ejecutan

en una computadora se conocen como software.

Dispositivos de entrada

Son los que permiten ingresar datos a la máquina para poder ser procesados, ejemplos

de ellos son: micrófono, teclado, ratón, joystick (palanca o control de mando que se usa en

consolas o videojuegos para desplazar un personaje u objeto), lápiz óptico, interfaz táctil,

escáner, cámara, lector de código de barras, etcétera.

Dispositivos de salida

Son los que permiten visualizar los resultados de los datos transformados o tratados en

la computadora, ejemplos de ellos son: monitor, impresora, bocinas, plotter (dispositivo

que permite dibujar o representar diagramas y gráficos), fax, sintetizador de voz, etcétera.

Page 8: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

7

Organización de la computadora

Si no se toman en cuenta las diferencias en apariencia física, las computadoras pueden

ser divididas en seis unidades lógicas o secciones (ver figura 1) y según Deitel y Deitel

(1995) dichas secciones pueden describirse de la siguiente manera:

1. Unidad de entrada. Esta es la sección “de recepción” de la computadora. Obtiene

datos e instrucciones de la computadora a partir de varios dispositivos de entrada y

los pone a disposición de las otras unidades, de tal forma que la información pueda

ser procesada.

2. Unidad de salida. Toma la información que ha sido procesada por la computadora

y la coloca en varios dispositivos de salida para dejarla disponible para su uso fuera

de la computadora.

3. Unidad de memoria. Esta es la sección donde se almacenan por un corto o largo

periodo tanto los datos como las instrucciones.

Figura 1. Estructura funcional de un ordenador.

Adaptado de Berzal (s.f., p. 7)

a. La memoria principal, primaria o central, también llamada de acceso

directo o interna trabaja a mayor velocidad que la memoria auxiliar, por lo

que se le conoce como de acceso rápido. Retiene información que ha sido

introducida a través de la unidad de entrada, de tal forma que pueda estar

disponible de inmediato para su proceso cuando sea necesario. También

retiene información ya procesada hasta que pueda ser colocada por la unidad

de salida en dispositivos de salida. Existe la memoria de lectura y escritura

Page 9: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

8

que es volátil, conocida como RAM y la memoria de sólo lectura que es

permanente, conocida como ROM. Para que un programa se ejecute, debe

estar almacenado o cargado en la memoria principal. La memoria cuenta con

dirección o localidad y valores o contenido que se almacenan en dichas

localidades.

b. La memoria secundaria, auxiliar, externa o masiva es más lenta que la

principal pero de mayor capacidad. Los datos y programas se suelen

almacenar aquí, para que, cuando se ejecute varias veces un programa o se

utilicen repetidamente unos datos, no sea necesario introducirlos de nuevo.

Los programas o datos que no se estén utilizando de forma activa por otras

unidades están por lo regular colocados en dispositivos de almacenamiento

secundario (por ejemplo, discos duros).

4. Unidad aritmética y lógica (ALU). Esta es la sección de “fabricación” de la

computadora. Es responsable de la ejecución de cálculos como: suma, resta,

multiplicación y división. Contiene los mecanismos de decisión que permiten que la

computadora, por ejemplo, compare dos elementos existentes de la unidad de

memoria para determinar si son o no iguales.

5. Unidad de procesamiento central (CPU). Esta es la sección “administrativa” de la

computadora, responsable (coordinadora) de la supervisión de la operación de las

demás secciones. El CPU le indica a la unidad de entrada cuándo debe leerse la

información y colocarse en la unidad de memoria, señala a la ALU cuándo deberá

utilizar información de la unidad de memoria en cálculos, y le indica a la unidad de

salida cuándo enviar información de la unidad de memoria a ciertos dispositivos de

salida.

6. Unidad de control. Detecta señales de estado procedentes de las distintas partes del

ordenador y genera señales de control dirigidas a todas las unidades para,

precisamente, controlar el funcionamiento de la máquina. Capta de la memoria

principal las instrucciones del programa que ejecuta el ordenador, las decodifica1 (el

concepto de codificar se explica más adelante en esta sección) y las ejecuta una a

una. Contiene un reloj que sincroniza todas las operaciones elementales

involucradas en la ejecución de una instrucción. La frecuencia del reloj determina,

en parte, la velocidad de funcionamiento del ordenador.

Sistema operativo

Un sistema operativo es un conjunto de programas también llamado sistema de

software, que sirve de interfaz entre los usuarios y un sistema de cómputo (el sistema de

cómputo compuesto por hardware y software), cuyo propósito es “ofrecer un ambiente en el

que el usuario pueda ejecutar programas de una forma cómoda y eficiente” (Candela,

García, Quesada, Santana y Santos, 2007, p. 3).

1 Según el Diccionario de la Real Academia Española (DRAE, 2014) “decodificar o descodificar es aplicar

inversamente las reglas de su código a un mensaje codificado para obtener la forma primitiva de éste”.

Page 10: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

9

El sistema operativo coordina el funcionamiento del hardware iniciando todos los

elementos que lo conforman para que estén preparados para recibir trabajo, entonces,

ordena cuándo y cómo deben trabajar los componentes y qué programas se les asignan;

coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de

cómputo, así, toma decisiones para evitar que se produzcan conflictos entre ellos y trata de

que el sistema de cómputo sea lo más eficiente posible (Candela, García, Quesada, Santana

y Santos, 2007).

Entre sus objetivos se encuentran: facilitar la utilización de los recursos del sistema de

cómputo, es decir, facilitar el uso del software y del hardware, por lo que, permite ejecutar

programas, gestiona procesos (programas en ejecución con todos los recursos que

requieren) e implementa la comunicación entre ellos, administra el tiempo de acción del o

los procesadores y la memoria principal, realiza operaciones de entrada y salida para las

aplicaciones que utiliza el usuario, detecta y notifica errores, manipula archivos de todo

tipo, es decir, manipula el sistema de archivos, protege y controla el acceso de programas,

procesos o usuarios a los recursos definidos por un sistema de cómputo, entre otras tareas

(Candela, García, Quesada, Santana y Santos, 2007).

Ejemplos de sistemas operativos: MS-DOS, OS/2, UNIX, SOLARIS, IRIX,

MULTICS, GNU/Linux, Windows (3.x, 95, 98, NT, 2000, XP, Vista, 7, 8, 10, Phone),

MAC-OS, Android, etcétera.

Codificación de la información

Codificar es representar los elementos de un conjunto mediante los de otro, de forma

tal que, a cada elemento del primer conjunto le corresponda uno y sólo un elemento distinto

del segundo. Una codificación asocia signos con los elementos de un conjunto a los que se

les denomina significados. Por ejemplo, se codifican los números del sistema decimal con

los símbolos o signos {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, es decir, se ponen en correspondencia los

símbolos con cantidades (Marzal y Gracia, 2006).

Código binario o código máquina

La unidad básica de información en las computadoras es el bit (binary digit, dígito

binario) cuyos valores establecen una de dos posibilidades mutuamente excluyentes. Los

dígitos binarios 0 y 1 se usan para representar los dos estados posibles de un bit particular.

Cualquier dato que se introduce en la computadora o que sea manipulado por ella se

codifica en su interior por una sucesión de ceros y unos (que físicamente se presenta por

corrientes eléctricas, campos magnéticos, etc.). Entonces puede asignarse cualquier

significado a un patrón de bits particular, en tanto esto se haga en forma consistente, lo que

le da el significado es la interpretación de un patrón de bits; así por ejemplo, a un caracter

le corresponde, según el código utilizado para representarlo, un byte, que es el conjunto de

8 bits, es decir, un byte es el número de bits necesario para almacenar un caracter. En la

figura 2 se muestran ejemplos de representación en código binario de algunos caracteres del

teclado, concretamente, el abecedario.

Page 11: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

10

Para medir la capacidad de almacenamiento de la computadora se utilizan múltiplos del

byte, como se observa en la tabla 1, y en la tabla 2 se presentan algunos ejemplos del

tamaño en bytes de ciertos tipos de datos.

A 01000001 G 01000111 M 01001101 Q 01010001 V 01010110

B 01000010 H 01001000 N 01001110 R 01010010 W 01010111

C 01000011 I 01001001 Ñ 10100101 S 01010011 X 01011000

D 01000100 J 01001010 O 01001111 T 01010100 Y 01011001

E 01000101 K 01001011 P 01010000 U 01010101 Z 01011010

F 01000110 L 01001100

Figura 2. Representación binaria del abecedario.

Adaptado de Berzal (s.f., p. 5)

Tabla 1. Múltiplos del byte.

Adaptado de Berzal (s.f., p. 6)

Unidad Abreviación En sistema

decimal

Capacidad en bytes

Kilobyte 1 kB 103 210 bytes = 1,024

Megabyte 1 MB 106 220 bytes = 1,048,576

Gigabyte 1 GB 109 230 bytes = 1,073,741,824

Terabyte 1 TB 1012 240 bytes = 1,099,511,627,776

Petabyte 1 PB 1015 250 bytes = 1,125,899,906,842,624

Exabyte 1 EB 1018 260 bytes = 11,529,215,046,068,46,976

Zettabyte 1 ZB 1021 270 bytes = 424,303,114,717,026,195,081,1

Yottabyte 1 YB 1024 280 bytes = 671,607,471,926,416,918,529,802,1

Tabla 2. Ejemplos del tamaño en bytes de algunos tipos de datos.

De Berzal (s.f., p.6)

Datos Descripción Tamaño

Texto 1 novela de 200 páginas, 50 líneas por

página y 80 caracteres por línea

800,000 bytes

Aprox. 781.25 kB

Imagen en

blanco y negro

1024x768 pixeles2, 1 bpp (bit por píxel) 98,304 bytes

96 kB

Imagen en color 1024x768 pixeles, 24 bpp (bit por píxel) 2,359,296 bytes

2304 kB o 2.25 MB

Sonido de baja

calidad

3 minutos, 11000 muestras por segundo,

8 bits por muestra

1,980,000 bytes

1933.59375 kB,

cerca de 2 MB

Sonido de alta

calidad

3 minutos, 44100 muestras por segundo,

12 bits por muestra, dos canales

(estéreo)

23,814,000 bytes

Cerca de 23 MB

2 “Un píxel, del inglés pixel es la superficie homogénea más pequeña de las que componen una imagen, que

se define por su brillo y color” (DRAE, 2014).

Page 12: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

11

Video (Calidad

DVD)

90 minutos, 25 fotogramas3 por segundo,

750x576 pixeles de resolución, 24 bpp

(bit por pixel)

174,960,000,000 bytes

170859375 kB

141105.652 MB

Cerca de 163 GB

En la entrada y salida de la computadora, los cambios de código se realizan de forma

automática para que las personas no tengan que introducir ni interpretar la información

codificada.

2 CONCEPTO DE ALGORITMO

Problema

Para López García (2009) un problema se pude definir como:

Una situación en la cual se trata de alcanzar una meta y para lograrlo se deben hallar y

utilizar unos medios y unas estrategias. La mayoría de problemas tienen algunos elementos

en común: un estado inicial; una meta, lo que se pretende lograr; un conjunto de recursos,

lo que está permitido hacer y/o utilizar; y un dominio, el estado actual de conocimientos,

habilidades y energía de quien va a resolverlo. (p. 7)

Algoritmo

Es una secuencia ordenada, finita e inequívoca de pasos a seguir para resolver un

determinado problema, en otras palabras, es la descripción exacta y sin ambigüedades de la

secuencia de pasos elementales a aplicar para, a partir de los datos del problema encontrar

la solución buscada (Cairó Battistutti, 2006).

La palabra Algoritmo tiene su origen en el nombre del matemático Persa “Mohamed ibn Musa

al Khwarizmi” (825 d.C.). Su apellido fue traducido al latín como Algorismus y posteriormente

pasó al español como Algoritmo… Sus trabajos de álgebra, aritmética y tablas astronómicas

adelantaron enormemente el pensamiento matemático y fue el primero en utilizar la

expresión al-yabr (de la que procede la palabra álgebra). Su trabajo con los algoritmos

introdujo el método de cálculo utilizando la numeración arábiga y la notación decimal. (López

García, 2009, p. 21)

Características de un algoritmo

Para que un algoritmo sea completo deberá contemplar todas las alternativas lógicas

posibles que las distintas combinaciones de los datos de entrada puedan presentar.

3 “Fotograma es cada una de las imágenes que se suceden en una película cinematográfica” (DRAE, 2014).

Page 13: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

12

Cualquier problema puede tener diferentes formas de solución, es decir, distintos

algoritmos, cada uno de ellos con ventajas e inconvenientes, por lo que, se busca elegir el

que cumpla una serie de características a la hora de programar; para Cairó Battistutti (2006)

son suficientes los siguientes elementos:

Finitud: el algoritmo tiene que terminar en algún momento, se dice que no debe

ciclarse, es decir, debe tener un número finito de pasos, independientemente de su

complejidad.

Precisión: los pasos a seguir se deben indicar clara y ordenadamente.

Determinismo: si se sigue el algoritmo varias veces proporcionándole los mismos

datos de entrada, se deben obtener siempre los mismos resultados.

Eficiencia: al momento de traducirse a un lenguaje de programación, el programa

no debe tardar mucho tiempo en ejecutarse ni usar mucho espacio de la memoria de

la computadora.

3 LENGUAJES DE PROGRAMACIÓN

Programar

En el nivel más simple consiste en ingresar en la computadora una secuencia de

órdenes para lograr un cierto objetivo. Es elaborar programas para la resolución de

problemas empleando una computadora (DRAE, 2014). “En mi opinión, sólo entendemos

algo cuando sabemos programarlo (¡uno mismo, no otra persona!). En caso contrario no lo

entendemos en realidad, sólo creemos entenderlo” (Chaitin, 2015, p. 16).

Programa

Es la expresión de un algoritmo que consiste en un conjunto de instrucciones que la

computadora puede entender y ejecutar. Es una serie de operaciones que realiza la

computadora para llegar a un resultado con un grupo de datos específicos. Existen dos tipos

importantes de programas:

Programas de aplicaciones: desarrollados para llevar a cabo tareas específicas ya

sea de tipo administrativo, científico o de entretenimiento.

Programas del sistema: son independientes de cualquier área específica de

aplicación y permiten gestionar los recursos de una computadora. Ejemplo: el

sistema operativo.

Page 14: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

13

Lenguaje de programación

Para Chaitin (2015):

El papel que imaginó Hilbert para el formalismo dentro de las matemáticas tiene su

manifestación óptima en los lenguajes de programación informática, que, de hecho, son

formalismos que se pueden interpretar de manera mecánica, pero que aunque sean formalismos

válidos para computar y calcular no lo son para razonar, ni para demostrar teoremas y,

decididamente, tampoco sirven para inventar conceptos matemáticos nuevos ni para lograr

nuevos descubrimientos matemáticos. (p. 23)

Un lenguaje de programación es un conjunto de símbolos junto con un conjunto de reglas

para combinar y utilizar dichos símbolos al escribir programas. Los lenguajes de

programación se componen de: léxico, es decir, de un conjunto de símbolos permitidos o un

vocabulario; sintaxis, o sea, de reglas que indican cómo realizar las construcciones

correctas del lenguaje, y de semántica, en otras palabras, reglas que permiten determinar el

significado de cualquier construcción del lenguaje (Bermúdez et al., 2003).

Un lenguaje de programación es un medio para expresar algoritmos y puede ser tanto

entendido por los humanos como interpretado por las computadoras.

Clasificación de los lenguajes de programación

El lenguaje máquina ordena a la computadora las operaciones fundamentales para

su funcionamiento a través de combinaciones de ceros y unos, formando así órdenes

entendibles sólo para el hardware de cada máquina en particular. Es mucho más

rápido que los lenguajes de alto nivel (éstos se describen más adelante en este

apartado), pero es difícil de usar por la cantidad excesiva de instrucciones que se

generan, donde encontrar un fallo es casi imposible.

El lenguaje de bajo nivel (ensamblador) es un derivado del lenguaje máquina y

está formado por abreviaturas de letras y números llamadas nemotécnicos. Con la

aparición de este lenguaje se crearon los programas traductores para poder pasar los

programas escritos en lenguaje ensamblador a lenguaje máquina. Como ventaja con

respecto al código máquina es que se tienen menos instrucciones, los programas

creados ocupan menos memoria. La desventaja es que depende totalmente de la

máquina en la que se está usando, lo que impide la transportabilidad de los

programas (posibilidad de ejecutar un mismo programa en diferentes máquinas o

entornos sin hacer modificaciones importantes).

Lenguajes de alto nivel son los que manejan un lenguaje más cercano al que utiliza

una persona. Estos lenguajes permiten al programador olvidarse por completo del

funcionamiento interno de la computadora para la que están diseñando el programa.

Tan sólo necesitan de otros programas llamados compiladores o intérpretes que

entiendan tanto las instrucciones como las características de la máquina. Ejemplos

de lenguajes de alto nivel son: Fortran, Pascal, COBOL, SQL, C, C++, SmallTalk,

Java, LISP, PROLOG, ADA, MODULA-2, Basic, G, AutoLisp, Python, etc. Éstos a

Page 15: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

14

su vez se suelen clasificar de acuerdo a los tipos de problemas que permiten resolver

y el estilo de programación que fomentan.

Traductores de lenguaje

Cuando se escribe un programa en un lenguaje de alto nivel, el conjunto de

instrucciones y todo lo que lo conforma se le llama archivo fuente, código fuente o

programa fuente. Los traductores de lenguaje son programas que traducen a su vez los

programas fuente a código máquina y se dividen en:

Compiladores

Intérpretes

Un intérprete es un traductor que toma un programa fuente, traduce y ejecuta cada

instrucción o bloque lógico antes de traducir y ejecutar el siguiente, es decir lo hace

instrucción a instrucción (ver figura 3).

Figura 3. Intérprete.

Un compilador es un programa que traduce los programas fuente a lenguaje máquina

y el programa traducido se le llama programa objeto o código objeto. El compilador

traduce instrucción a instrucción pero no las ejecuta.

La compilación y sus fases

La compilación es el proceso de traducción de programas fuente a programas objeto,

estos últimos normalmente conocidos como código máquina. Para conseguir el programa

final que se pude ejecutar se necesita de un programa llamado montador o enlazador

(linker), como se observa en la figura 4. En la sección 6: Lenguaje C se detallarán las fases

que se siguen al momento de compilar para obtener de un programa fuente un programa

ejecutable.

4 DATOS Y EXPRESIONES EN UN PROGRAMA

Todo programa de computadora tiene dos entidades a considerar: los datos y el

programa en sí.

Page 16: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

15

Figura 4. Fases de la compilación.

Un dato es la expresión general que describe a los objetos con los cuales opera una

computadora. Existen dos clases: simples (sin estructura) y estructurados (compuestos).

La principal característica de los datos simples es que ocupan sólo una casilla de memoria y

los datos estructurados se caracterizan por el hecho de que con un nombre se hace

referencia a un grupo de casillas de memoria, es decir, un dato estructurado tiene varios

componentes. Los distintos tipos de datos se representan en diferentes formas en la

computadora, a nivel de máquina, un dato es un conjunto o secuencia de bits (dígitos 0 y 1)

pero los lenguajes de alto nivel usan los siguientes datos simples:

Numéricos:

o entero, llamado de punto o coma fija4, y es un subconjunto finito de los

números enteros.

o real, llamado de coma flotante o punto flotante5, que consiste en un

subconjunto finito de los números reales.

Caracter: es un conjunto finito y ordenado de símbolos que la computadora

reconoce. Con éstos en sucesión se forman cadenas de caracteres.

Lógico o booleano, indican dos posibles valores: verdadero o falso.

4 Tanto la coma como el punto son signos válidos para separar la parte entera de la parte decimal en un

número. 5 La representación coma flotante o punto flotante está basada en la notación científica (recuerda que esta

última consta de coeficiente, base y exponente) y contiene en representación binaria: signo del número,

mantisa (que es el coeficiente, significado o magnitud del número) y exponente (que indica dónde se coloca el

punto decimal, mejor dicho, binario, en relación al inicio de la mantisa. Un exponente negativo representa

números menores que uno). Se usa en las computadoras para representar números racionales de magnitud

“muy grande” o “muy pequeña”, de forma eficiente y compacta con la que se pueden realizar operaciones

aritméticas (Borgwardterzal, s.f.). En el curso Programación II, se explica a detalle el tema de la

representación binaria de los números en las computadoras.

Page 17: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

16

Por otro lado, los datos estructurados más conocidos son: arreglos, cadenas de

caracteres y registros (en las secciones 11 y 12 se revisarán los arreglos y las cadenas de

caracteres, los registros forman parte del temario de Programación II).

Las constantes son elementos cuyo valor no cambia durante todo el desarrollo del

algoritmo o durante la ejecución del programa, pueden ser enteras, reales, lógicas, de

caracter o de cadena.

Una variable es un elemento cuyo valor puede cambiar durante el desarrollo del

algoritmo o ejecución de un programa. Es una localidad o ubicación de memoria en una

computadora en la cual se almacena un valor y se identifica por un nombre, dicho valor

puede ser entero, real, lógico o caracter. Dependiendo del lenguaje de programación que se

utilice, puede ser necesario declarar una variable, esto es, declarar significa establecer

desde un inicio, el tipo de dato que puede almacenar una variable antes de almacenar dicho

valor, ya que, si no se declara no se puede usar a la variable, con ello, una vez que una

variable se declara de un cierto tipo, sólo puede almacenar valores de ese tipo, por ejemplo,

si se declara de tipo entera, sólo puede contener enteros pero no reales o caracteres; si se

declara de tipo real no puede contener valores lógicos, etc. Si se intenta dar un valor a una

variable que no es de su tipo, se genera un error de tipo. Sin embargo, existen también

lenguajes de programación que no obligan a declarar variables, así, una variable puede

almacenar valores de distintos tipos sin problema alguno.

Los nombres que se les asignan a los datos simples, por ejemplo: una variable o

constante, o a los datos estructurados, por ejemplo: un arreglo, se conocen como

identificadores. Un identificador se forma por medio de letras, dígitos y el caracter guion

bajo, comenzando siempre con un carácter ya sea en minúsculas o mayúsculas. En la tabla

3 se ejemplifican identificadores que representan a variables de distinto tipo.

Una expresión es una combinación de operadores, operandos, paréntesis y nombres de

funciones especiales. Los operandos pueden ser constantes, variables u otras expresiones.

Los operadores puedes ser símbolos de operación: aritméticos, lógicos (AND, OR, NOT)

y/o relacionales (>, <, >=, <=, =, < >).

Tabla 3. Identificadores de variables.

Nombre de la variable (Identificador) Valor Tipo

Altura 2 Entero

Base 5 Entero

Radio 2.5 Real

simbolo_1 ‘a’ Caracter

Simbolo_2 ‘#’ Caracter

Page 18: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

17

5 PROCESO DE RESOLUCIÓN DE PROBLEMAS UTILIZANDO UN

LENGUAJE DE PROGRAMACIÓN

Pueden ser identificadas dos etapas en el proceso de resolución de problemas

utilizando un lenguaje de programación (Cairó Battistutti, 2006):

1. Fase de solución

2. Fase de implementación en un lenguaje de programación

5.1 Fase de solución

Análisis del problema: En esta etapa se debe definir claramente el problema y

comprender lo que se pide, se deben detectar los datos o elementos que se tienen para

usar (llamados datos de entrada), e identificar los datos que se van a dar como salida

(conocidos como resultados). Parar un buen análisis se pueden usar distintas

estrategias, por ejemplo, en ocasiones es necesario leer el problema varias veces para

aclarar lo que se va a resolver, precisar el resultado que se desea lograr, determinar la

o las incógnitas del problema, organizar información, agrupar datos en categorías,

buscar o clarificar las palabras o conceptos desconocidos, detectar las palabras clave,

verificar si se ha resuelto algún problema similar cuya solución pudiera ser de utilidad

para este nuevo problema, desechar los datos superfluos, detectar si falta información

para resolver el problema, preguntarse qué está permitido o prohibido hacer y/o

utilizar, cuáles datos se pueden considerar fijos (constantes), cuáles variables, cuáles

se pueden calcular, qué fórmulas se pueden emplear, etc. (López García, 2009).

Diseño o construcción de la solución: En este proceso se diseña o plantea el

algoritmo a utilizar, para esto se tienen diferentes herramientas: descripciones

narradas, diagramas o pseudocódigo.

Verificación del algoritmo, llamado también prueba de escritorio: Consiste en dar

valores a las variables que se han definido en el algoritmo para seguir su flujo y

comprobar si al final el resultado es el esperado y por tanto el algoritmo es correcto

para cualquier caso posible. Se hace a mano siguiendo las instrucciones que se

plantearon en el algoritmo o bien usando algún software especial.

Diseño de un algoritmo

Los problemas complejos se pueden resolver eficazmente con la computadora cuando

se dividen en subproblemas que sean más fáciles de solucionar que el original, este método

se suele denominar: divide y vencerás. Descomponer un problema en subproblemas más

simples y, a continuación dividir esos subproblemas en otros más simples, que pueden ser

implementados para su solución en la computadora, se denomina diseño descendente (top-

down design). Normalmente, los pasos diseñados en el primer esbozo del algoritmo son

incompletos e indicarán sólo unos pocos pasos. Tras esta primera descripción, éstos se

Page 19: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

18

amplían en una descripción más detallada con más pasos específicos. Este proceso se

denomina refinamiento del algoritmo (stepwise). Para problemas más complejos se

necesitan con frecuencia diferentes niveles de refinamiento antes de que se pueda obtener

un algoritmo claro, preciso y completo (Bermúdez, et al., 2003).

Las ventajas más importantes del diseño descendente son: el problema es más

comprensible al dividirse en partes más simples denominados módulos, las modificaciones

en dichos módulos son más sencillas de realizar y la comprobación del problema es

asequible, cada módulo se puede elaborar de manera independiente por lo que puede haber

más de un programador involucrado y el tiempo de elaboración puede disminuir; la

depuración se puede hacer en cada módulo y el mantenimiento es más sencillo. La

programación de cada módulo se hace mediante: programación estructurada. La

programación estructurada es un conjunto de técnicas para desarrollar algoritmos fáciles

de escribir, verificar, leer y modificar; aquí algunas de sus características:

Tiene un solo punto de entrada y uno de salida.

Toda acción del algoritmo es accesible, es decir, existe al menos un camino que va

desde el inicio hasta el final del algoritmo, se puede seguir y pasa a través de dicha

acción.

No posee lazos o bucles (ciclos) infinitos.

Cabe mencionar que existen distintas clasificaciones para categorizar a los lenguajes de

programación de alto nivel, así, además de los lenguajes de programación imperativos o

procedurales (que se basan en la programación estructurada) existen los lenguajes de

programación orientados a objetos, declarativos, etcétera.

Ahora bien, en la programación estructurada, un programa puede ser escrito utilizando

únicamente tres tipos de estructuras: secuenciales (instrucciones que se ejecutan una tras

otra en forma consecutiva), selectivas (para evaluar condiciones y tomar decisiones sobre

qué camino seguir) y repetitivas (para procesar un conjunto de datos más de una vez,

dependiendo del resultado de una condicional); todas ellas se explican a detalle en las

secciones 8 y 9. Cabe señalar que, dichas estructuras son el corazón de la programación

estructurada y por ende, las bases en el temario de la asignatura Programación I.

Métodos para representar algoritmos

Existen tres métodos para representar un algoritmo:

Descripción narrada: consiste en hacer un relato de la solución en lenguaje

natural.

Pseudocódigo: proviene de la composición de dos palabras: pseudo (falso) y código

(instrucción). Utiliza palabras en lenguaje natural (generalmente inglés, aunque

puede ser en cualquier idioma, por ejemplo el castellano, como lo utiliza la

Page 20: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

19

herramienta de software PSeInt, abreviatura de Pseudo Intérprete) mezcladas con

instrucciones de programación y palabras clave reservadas para representar una

acción en específico. No tiene que escribirse en un lenguaje de programación

particular ni existe una única forma de expresarlo o estándar, esto depende de cómo

se expresa cada persona. Como todo método para representar algoritmos se centra

en los aspectos lógicos de la solución del problema no en un lenguaje de

programación específico.

Diagrama de flujo: flowchart u ordinogramas: es la representación gráfica de un

algoritmo, es decir, representa la solución del problema utilizando símbolos que

tienen un significado único y específico. En la tabla 4 se presentan los símbolos que

satisfacen las recomendaciones de la ISO (International Organization for

Standardization, Organización Internacional para la Estandarización) y el ANSI6

(American National Standars Institute, Instituto Nacional Americano de

Estandarización) desde 1985. Actualmente existen diversas herramientas de

software que permiten tanto elaborar como probar el funcionamiento de un

diagrama de flujo a través de trazas, sirviendo además para el aprendizaje de

algoritmos estructurados. Arellano, Nieva, Solar y Arista (2012) destacan a las

siguientes herramientas:

- DFD (siglas de Data Flow Diagrams, Diagramas de Flujo de Datos). Última

actualización: octubre, 2008

- RAPTOR (acrónimo del inglés Rapid Algorithmic Prototyping Tool for Ordered

Reasoning). Actualizado constantemente hasta la fecha.

- PSeInt (abreviatura de Pseudo Intérprete). Facilita escribir algoritmos en

pseudocódigo generando el diagrama de flujo a partir de éste; también se

actualiza constantemente hasta la fecha.

- Progranimate

Las herramientas mencionadas utilizan su propia simbología para algunos de los

significados que se presentan en la tabla 4 y no respetan el estándar ISO, ANSI,

entonces, en la tabla 5 se muestran los símbolos equivalentes de las herramientas

DFD, RAPTOR y PSeInt, siendo estas últimas dos las más populares.

6 ANSI (American National Standards Institute, Instituto Nacional Estadounidense de Estándares) es una

organización sin fines de lucro que supervisa el desarrollo de estándares para productos, servicios, procesos y

sistemas en los Estados Unidos. Es miembro de la Organización Internacional para la Estandarización (ISO).

También coordina estándares del país estadounidense con estándares internacionales, de tal modo que los

productos de dicho país puedan usarse en todo el mundo. Esta organización aprueba estándares que se

obtienen como fruto del desarrollo de tentativas de estándares por parte de otras organizaciones, agencias

gubernamentales, compañías y otras entidades. Estos estándares aseguran que las características y las

prestaciones de los productos sean consistentes, es decir, que la gente use dichos productos en los mismos

términos y que esta categoría de productos se vea afectada por las mismas pruebas de validez y calidad

(“Instituto Nacional Estadounidense de Estándares”, 2015).

Page 21: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

20

Reglas para la construcción de un diagrama de flujo

Según Cairó Battistutti (2006):

1. Todo diagrama de flujo debe tener un inicio y un fin, construyéndose de arriba hacia

abajo (top-down) y de izquierda a derecha (left-to-right).

2. Las líneas utilizadas para indicar la dirección del flujo del diagrama deben ser

rectas: verticales u horizontales y estar conectadas a otros símbolos: lectura,

decisión, salida, proceso, etc., pero no pueden quedar sin apuntar a un símbolo.

3. La notación utilizada en el diagrama de flujo debe ser independiente del lenguaje de

programación a utilizarse. La solución presentada se puede escribir posteriormente

en diferentes lenguajes de programación.

4. Es conveniente colocar comentarios que ayuden a entender lo que se está

realizando.

Tabla 4. Simbología en un diagrama de flujo según la ISO y el ANSI.

Adaptado de Cairó Battistutti (2006, pp. 5 y 6) y López García (2009, p. 27)

Símbolo Significado Símbolo Significado

Se utiliza para marcar el

inicio y el final del

diagrama de flujo. Del

Inicio sólo puede salir

una línea de flujo y al

Final sólo puede llegar

una línea de flujo.

Representa conexión de

una parte del diagrama

con otra parte del

diagrama entre páginas

diferentes.

Se utiliza para salida y

entrada de datos indistin-

tamente del dispositivo

que se use, aunque existe

un símbolo para indicar

lectura o entrada a través

del teclado, así como

existe un símbolo para

indicar la salida o

escritura a pantalla y

otro para salida a la

impresora.

Se utiliza para representar

la impresión de un

resultado, expresa salida

o escritura a la impresora.

Se utiliza para indicar

entrada de datos a través

del teclado.

Se utiliza para presentar

mensajes o resultados en

pantalla.

Expresa conexión entre

dos partes distintas del

diagrama en una misma

página.

Representa un proceso, en

su interior se colocan

asignaciones, operaciones

aritméticas, etc.

Page 22: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

21

Tabla 5. Simbología en un diagrama de flujo según DFD, RAPTOR y PSeInt.

Significado Simbología DFD Simbología RAPTOR Simbología PSeInt

Entrada o

lectura

Salida o

escritura

Flechas de dirección o

flujo del diagrama.

Flechas de dirección o

flujo del diagrama.

Se utiliza para

representar una decisión

múltiple, en su interior

se almacena un selector

y dependiendo de su

valor se sigue por una de

las ramas o caminos.

Representa una decisión,

en su interior se coloca

una condición y

dependiendo de la

evaluación (resultado

lógico de verdadero o

falso) se sigue uno u otro

camino. Se utiliza para expresar

un módulo (subrutina o

procedimiento) de un

problema (subproblema)

que hay que resolver

antes de continuar con el

flujo normal del

diagrama.

Llamada a la subrutina o

procedimiento

determinado

Acciones

Se utiliza para representar

al ciclo for o para, es

decir, un conjunto de

acciones se repiten un

número determinado de

veces, según lo dicte la

condición especificada.

acciones

Se utiliza para

representar al ciclo while

o mientras, es decir, un

conjunto de acciones se

repiten mientras la

condición es verdadera.

Acciones

Se utiliza para representar

al ciclo hasta que: un

conjunto de acciones se

realizan mientras la

condición es falsa, o en

otras palabras, el ciclo

termina hasta que la

condición sea verdadera,

aunque al menos una vez

se realizan las acciones.

selector

Page 23: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

22

Ciclo while o

mientras

Ciclo for o

para

No existe en

RAPTOR

Ciclo repetir

Hasta que

Módulo de un

problema

(subproblema)

Decisión

múltiple

5.2 Fase de implementación del diseño

Codificar o escribir el programa, traducir el algoritmo a un específico lenguaje de

programación (el concepto de codificar se revisó en la sección 1: Preliminares,

conceptos básicos).

Para

acciones

Fin (para)

MQ

acciones

Fin (MQ)

No existe en

DFD ni en

RAPTOR

acciones

No existe

en

RAPTOR

acciones

No existe

en DFD

Page 24: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

23

Ejecutar o correr el programa: llevar a cabo cada una de las instrucciones que lo

conforman.

Verificar que funcione correctamente el programa.

Instrucciones generales de un programa

Tipos de instrucciones básicas que contiene cualquier lenguaje de programación:

1. Instrucciones de inicio/fin.

2. Instrucciones de asignación.

3. Instrucciones de lectura, conocidas también como instrucciones de entrada.

4. Instrucciones de escritura, conocidas también conocidas como instrucciones de

salida.

5. Instrucciones de bifurcación o decisión.

Elementos básicos de un programa:

1. Palabras reservadas o primitivas son las que tienen un significado especial para un

compilador por lo que no pueden utilizarse para cualquier otro propósito distinto

para el que fueron identificadas.

2. Identificadores, nombres de variables, constantes o funciones declaradas por el

usuario o predefinidas por el lenguaje de programación que se utilice.

3. Caracteres especiales, por ejemplo: coma, apóstrofo, comillas, etc. que se usan para

acciones determinadas.

4. Operadores aritméticos, relacionales o lógicos.

5. Expresiones, están compuestas por valores, funciones, primitivas, constantes y/o

variables, o por una combinación de los anteriores mediante operadores aritméticos,

lógicos o de asignación.

6. Contadores: variables cuyo valor se incrementa o decrementa en una cantidad

constante en cada iteración si se utilizan ciclos.

7. Acumuladores: variables cuya misión es almacenar cantidades resultantes de

operaciones sucesivas como sumas o multiplicaciones por ejemplo. Realiza la

misma función que un contador, con la diferencia de que el incremento o

decremento en cada operación es variable en lugar de constante.

8. Interruptores o conmutadores (switch) a veces se les denomina indicadores o

banderas, son variables que pueden tomar diversos valores a lo largo de la

ejecución del programa y que permite comunicar información de una parte a otra

del mismo. Los interruptores pueden tomar dos valores diferentes: 1 y 0

(encendido/apagado o abierto/cerrado).

9. Estructuras, se definen como “un esquema con cierta distribución y orden que

permite representar una idea de forma simplificada” (López García, 2009, p. 46).

Existen tres estructuras: secuenciales o lineales, selectivas, y repetitivas. La

primera se compone de instrucciones que deben ejecutarse una tras otra en forma

consecutiva o lineal, la segunda permite evaluar condiciones y tomar decisiones y la

tercera permite repetir varias veces un conjunto de instrucciones.

Page 25: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

24

Tipos de errores presentados en la fase de implementación

Errores de sintaxis. Se presentan al momento de compilar un programa,

generalmente por cometer errores al escribir una instrucción o los signos de

puntuación correctos violando la sintaxis con la que se escriben los programas,

según el lenguaje que se esté usando. Así, el compilador indica tanto la línea donde

se ha cometido el error como la clase de error para poder corregirlo.

Errores lógicos. Se presentan al momento de ejecutar un programa, ya que no se

obtienen los resultados esperados, generalmente porque el algoritmo que se planteó

no fue el correcto o porque la traducción (implementación) al lenguaje de

programación utilizado no fue el adecuado, malinterpretando el algoritmo. Esta

clase de errores son más difíciles de corregir.

Errores en tiempo de ejecución. Se presentan al momento de ejecutar el programa,

por ejemplo, si el programa hace referencia al lector de una memoria externa y

dicho lector no está listo con una memoria, entonces marcará un error; otro ejemplo

sería si se espera que el usuario ingrese un dato de tipo entero y lo que ingresa es un

dato de tipo caracter o decimal, entre otros ejemplos.

Warnings. No propiamente son errores, sino advertencias de que algo debería

cambiarse porque es obsoleto o puede causar conflictos.

6 LENGUAJE C

Historia breve del lenguaje C

El lenguaje C fue desarrollado entre 1969 y 1973, según su creador, el científico

estadounidense Dennis M. Ritchie, el período de mayor creatividad fue en 1972 y por ello,

es común leer que en ese año se creó el lenguaje. Se le dio ese nombre porque se considera

el sucesor del lenguaje de programación conocido como B. En 1973, el lenguaje C se había

vuelto tan potente que la mayor parte del kernel (núcleo) de Unix (recuerda que Unix es un

sistema operativo) se reescribió en C. En 1978 Brian W. Kernighan y Dennis M. Ritchie

publicaron el libro de uso del lenguaje C: The C Programming Language, conocido

también como La biblia de C, la cual, tomaron como referencia los fabricantes de

compiladores C de la década de los ochenta y a raíz de esa publicación al C de esa época se

le conoce como K&R C. Hacia finales de los 70, el lenguaje C evolucionó a lo que hoy se

le conoce como C tradicional y su rápida expansión sobre varios tipos de computadoras,

denominadas plataformas de hardware, provocó muchas variantes que, aunque similares

no eran compatibles. Esto generó problemas para los desarrolladores de programas que

necesitaban escribir códigos que pudieran funcionar en varias plataformas. Por tanto, en

1989 se aprobó un estándar para el lenguaje C con una definición no ambigua e

independiente de la máquina donde se desarrollara y a esta versión se le conoce como

Page 26: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

25

ANSI C o C89. Un año después se incluyó en la ISO y el documento que plasma los

cambios se conoce como ANSI/ISO 9899: 1990, por ello, es la versión estandarizada que se

utiliza en todo el mundo, conocida como C90 o ISO C90 (ANSI e ISO se describen en la

nota 5 de la página 17). En 1999 se generó un nuevo estándar de programación de C por el

ISO/IEC, conocido como ISO/IEC 9899 o comúnmente como C99; en 2011 se publicó en

el ISO/IEC 9899:2011, la versión C11 (antes conocido como C1X) y finalmente en el 2018

se publicó en el ISO/IEC 9899:2018, la versión C18 (Deitel y Deitel, 1995; Hernández

Orallo, Henández Orallo & Juan Lizandra, 2002; ISO, 2018; Ritchie, 2003).

Características generales del lenguaje C

Es un lenguaje de propósito general, es decir, puede ser usado para crear

aplicaciones con distintos objetivos, por ejemplo: realizar cálculos matemáticos,

crear sistemas operativos (el kernel del sistema operativo GNU/Linux y Mac OS X

están escritos en C), gestionar bases de datos (PostgreSQL está escrito en C),

comunicar computadoras, capturar datos, editar imágenes (GIMP en su mayoría está

escrito en lenguaje C), generar aplicaciones científicas (el paquete R en estadística y

MATLAB en cálculo están escritos en el lenguaje C), industriales, de simulación,

etcétera.

El código que produce es eficiente y cuenta con características de los lenguajes de

bajo nivel que permiten realizar implementaciones óptimas (rápidas).

Es portátil, es decir, los códigos o programas generados con el lenguaje pueden

ejecutarse en cualquier arquitectura de computadora o cualquier sistema operativo

con variantes mínimas.

Es estructural, en otras palabras, el programa se divide en subprogramas o

segmentos con estructuras simples de secuencia, selección e iteración.

Es case sensitive (distingue entre mayúsculas y minúsculas), es decir, distingue

entre instrucciones e identificadores escritos en mayúsculas y minúsculas, por

ejemplo, una variable identificada como A, es diferente a la variable identificada

como a, o bien, la instrucción If no será reconocida por el compilador, más la

instrucción if sí lo será.

A continuación se detallan las tres partes principales de las que consta todo sistema en

C: Un entorno, biblioteca estándar y el lenguaje en sí

Entorno

Existen diferentes IDEs (acrónimo del inglés: Integrated Development Enviroment

y en español: Entorno Integrado de Desarrollo) que incluyen o integran una interfaz visual

con iconos, menús y ventanas para trabajar con comodidad, con un editor de textos para

escribir el código fuente en el lenguaje C, uno o varios compiladores, enlazadores,

depuradores y demás herramientas. Suelen presentar diferentes asistencias para la escritura

Page 27: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

26

de programas, como: sugerencias de autocompletado, coloreado de la sintaxis del código

fuente, ayuda acerca del lenguaje, etc.

Es necesario recalcar que un IDE no es un compilador, este último es parte de todo el

IDE. Novara (201) presenta algunos ejemplos de IDEs:

DevC++ (disponible sólo para el sistema operativo Windows)

Visual Studio (disponible sólo para el sistema operativo Windows)

Eclipse (disponible para los sistemas operativos Windows, Mac y GNU/Linux)

Monodevelop (disponible para los sistemas operativos Windows, Mac y

GNU/Linux)

ZinjaI, (disponible para los sistemas operativos Windows, Mac y GNU/Linux)

CodeBlocks, (disponible para los sistemas operativos Windows, Mac y

GNU/Linux)

Entre otros

Ya sea que se utilice un IDE o no, en general, cuando se crea un programa en C se

siguen diferentes fases para obtener un código ejecutable a partir del código fuente. La

diferencia con utilizar un IDE está en que el usuario o programador no usa comandos para

llevar a cabo las diferentes fases, sino los iconos y menús que proporciona el propio IDE.

En la figura 5 se pueden observar las diferentes fases que se siguen para obtener un

programa ejecutable. Primero, el programador escribe el programa en C utilizando un

editor de texto, generando con ello un archivo fuente con la extensión .c. Segundo, se hace

el llamado al compilador que traduce el programa fuente a código máquina, éste conocido

también como código objeto (ver apartado Traductores de lenguaje de la sección 3:

Lenguajes de programación), pero justo antes de ello, el propio compilador llama a un

programa conocido como preprocesador, el cual manipula el programa fuente, incluyendo

otros archivos a compilar y reemplazando símbolos especiales con texto de programa (por

ejemplo, cambiando el nombre de una constante por su correspondiente valor). Tercero, el

compilador traduce el código fuente para generar el código objeto, éste es un código aún no

ejecutable, pues generalmente estará incompleto. Cuarto y último, para obtener el código

binario final, se ejecuta el enlazador, el cual se encargará de vincular el código objeto con

el código de las funciones a las que se haya hecho referencia en el programa fuente pero

cuyo código se encuentra en otro u otros archivos, por ejemplo, en la biblioteca estándar

(este concepto será revisado en el siguiente apartado Biblioteca Estándar de esta sección) o

bibliotecas creadas por los propios programadores (Deitel y Deitel, 1995).

Cabe mencionar que, cada IDE puede hacer uso de uno o varios tipos de compiladores

para C, entre los que existen están: GCC, DJGPP, Miracle C, LCC Win 32, Intel C++

Compiler (conocido como ICC o ICL), Mingw, Borland C++.

Page 28: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

27

Figura 5. Fases para producir código ejecutable a partir de código fuente en C.

Page 29: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

28

Biblioteca Estándar

La biblioteca estándar de C contiene una amplia colección de funciones que resuelven

problemas particulares y comunes, por ejemplo: cálculos matemáticos, manipulación de

cadenas o caracteres, detección de errores, mandar o recibir datos hacia o desde los

dispositivos de salida y entrada respectivamente, obtención de fecha y hora, etc. Estas

funciones mejoran tanto el rendimiento de los programas como la portabilidad pero no

forman parte en sí del lenguaje C (Deitel y Deitel, 1995). Las funciones que pertenecen a la

biblioteca estándar ayudan a ahorrar tiempo al programar, evitando que se reescriba código

para resolver un problema cuando la función ya existe, pues permiten la reutilización de

código. Por otro lado, la biblioteca estándar hace uso de archivos de cabecera, los cuales

contienen tanto los prototipos de función de cada una de las funciones a las que hacen

referencia como las definiciones de varios tipos de datos y constantes requeridas para

dichas funciones. Un archivo de cabecera tiene un nombre con la extensión de archivo .h y

se incluye en un programa a través de la instrucción include como se detalla a

continuación.

#include <Nombre_del_archivo_de_cabecera.h>

Lo anterior indica al preprocesador (concepto revisado en el apartado Entorno de esta

sección) que incluya el archivo identificado por Nombre_del_archivo_ de_cabecera.h, el

cual se delimita entre los símbolos < >, va seguido del carácter almohadilla y la palabra

reservada include. Ejemplos de nombres de archivos de cabecera son: stdio.h, stdlib.h,

math.h, string.h, time.h, cyte.h, errno.h, etc. Estos ficheros se encuentran almacenados en el

directorio por default o por defecto donde está almacenado el compilador al momento de

instalarlo. El archivo de cabecera ctype.h contiene, por ejemplo, las funciones prototipo que

pueden ser utilizadas para convertir letras de minúsculas a mayúsculas o viceversa; el

archivo de cabecera math.h contiene prototipos para las funciones matemáticas

trigonométricas, raíz cuadrada, potencia, etc.; el archivo de cabecera stdlib.h contiene entre

otras cosas, prototipos de función para generar números aleatorios.

Ahora bien, un prototipo de función (el tema de funciones se verá a detalle en la

sección 13: Funciones) es útil para: indicar al compilador el tipo de dato que regresará la

función (entero, real, caracter, etc.), la cantidad de argumentos que espera recibir la función

para procesarlos, así como el tipo y el orden en que la función espera recibir a dichos

argumentos. De esta forma, el compilador puede determinar errores por parte del

programador al momento de llamar a una función, evitando problemas en tiempo de

ejecución de un programa (Deitel y Deitel, 1995).

Tanto en el resto de esta sección como en las secciones posteriores, se describirán los

elementos que conforman al lenguaje C, el cual se aprenderá en esta asignatura.

Estructura de un programa

Todo programa en C está conformado por funciones (el tema de funciones será

revisado con mayor detalle en la sección 13: Funciones), ya sean las que se encuentran en

Page 30: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

29

la biblioteca estándar o las que son creadas por el propio programador para resolver un

problema en particular. Además, consta de una función indispensable llamada main( ) a

partir de donde el programa comienza a ejecutarse, su objetivo principal es coordinar a

otras funciones mediante llamadas o invocaciones. Después, contiene la llave izquierda que

abre { para dar inicio al cuerpo de la función principal y termina con la llave derecha que

cierra }. Estas llaves y la porción de programa o instrucciones que existe entre ellas se les

conocen como bloque (Deitel y Deitel, 1995). Este bloque puede estar constituido por

varios elementos que conforman al lenguaje C: operadores relacionales, de asignación,

condicionales, variables, constantes, ciclos, etc., todos ellos se revisarán a lo largo de este

documento.

En general, un programa escrito en el lenguaje C puede contener lo siguiente:

Sección include (se explicó en el apartado Biblioteca Estándar de esta misma

sección).

Cabe mencionar que, cuando se van a agregar funciones que no pertenecen a la

biblioteca estándar, sino que fueron elaboradas por el programador y forman parte

de un archivo de cabecera, entonces, se usa la siguiente sintaxis:

#include “Nombre_del_archivo”

Como se ve, lo único que se modifica son los signos de mayor y menor que, por las

comillas dobles; el nombre del archivo de cabecera no precisamente debe contener

la extensión .h. Con esta forma se indican dos cosas al compilador: que incluya el

archivo especificado en el programa fuente y que dicho archivo se encuentra en una

ruta distinta a la que se tiene por defecto. Si entre comillas se especifica la ruta

además del nombre del archivo, entonces el compilador buscará al archivo en esa

ruta, pero si no se especifica, el compilador buscará al archivo en el mismo

directorio donde se encuentra el fichero fuente.

Sección de declaración de constantes y tipos de datos estructurados.

Sección de declaración de variables globales (se explicará en la sección 13:

Funciones).

Declaración de prototipo de funciones o forward (se explicará en la sección 13:

Funciones). Si no existieran funciones prototipo, puede existir sólo un bloque de

funciones creadas por el programador.

Función main o función principal.

Si se declararon prototipo de funciones y la programación de cada función se

encuentra en el mismo archivo fuente, generalmente constituyen la sección final del

programa.

Page 31: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

30

Ejemplo:

/*Sección include, agregado de archivos de cabecera de la biblioteca

estándar*/

#include <stdio.h>

#include <stdlib.h>

#include <time.h>

/*Declaración de constantes*/

#define TAM 99

#define FREC 10

/*Prototipo de función*/

void moda(int []);

/*Función principal*/

int main( )

{

int i, respuestas[TAM];

srand(time(NULL));

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

respuestas[i]=1 + (rand()%9);

moda(respuestas);

return 0;

}

/*Función declarada por el programador*/

void moda(int resultados[ ])

{

int i,j,mayor=0,posicion,frecuencia[FREC]={0};

for(i=0;i<TAM;i++) ++frecuencia[resultados[i]];

printf("\n%s%15s%15s\n","Respuesta", "Frecuencia","Histograma");

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

{

printf("%8d%10d ",i,frecuencia[i]);

if (frecuencia[i]>mayor)

{

mayor=frecuencia[i];

posicion=i;

}

for(j=1;j<=frecuencia[i];j++) printf("*");

printf("\n");

}

Page 32: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

31

printf("\nLa moda es = %d y se repitio %d veces", posicion,mayor);

return;

}

Identificadores

Son nombres dados a constantes, variables, funciones, tipos, etiquetas de un programa,

y están formados por una secuencia de letras (mayúsculas y/o minúsculas), dígitos y el

caracter guion bajo. El primer carácter de un identificador debe ser una letra o el carácter de

subrayado, y serán significativos los primeros 31 caracteres, toda carácter más allá de este

límite será ignorado por cualquier compilador (Ceballos, 1997).

Palabras clave o reservadas del lenguaje C

Existen un total de 32 palabras clave que están reservadas para uso exclusivo del

compilador C y que tienen un significado especial para dicho compilador, por lo que no

pueden utilizarse como identificadores. Algunas versiones de compiladores pueden tener

palabras adicionales (Ceballos, 1997). Las palabras reservadas son:

Palabras que se refieren a los tipos de datos que se pueden utilizar: int, float,

long, double, short, char, unsigned, signed, volatile,

const, enum, static, typedef, sizeof.

Palabras que se refieren a instrucciones que controlan el flujo de datos: if, else, switch, case, default, break, for, while, do,

continue, goto.

Otras: struct, return, union, register, extern, void, auto.

Tipos de dato estándar

Los tipos de datos básicos en el lenguaje C son:

1. caracter (que se declara con la palabra reservada char) para poder manejar

cualquier caracter del teclado;

2. real (que se declara con la palabras reservadas double o float) para manejar

números con parte decimal, y

3. entero (que se declara con la palabra reservada int) para manejar números enteros.

Con el tipo de dato caracter, se puede formar una variable de tipo cadena, que es una

secuencia de caracteres entre comillas. La tabla 6 muestra una lista detallada de los tipos de

datos7 que existen en el lenguaje C.

7 El estándar C99 del lenguaje C ofrece el archivo de cabecera stdbool.h que permite tener acceso al

tipo de dato bool, el cual permite a una variable almacenar dos posibles valores: true o false.

Page 33: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

32

Tabla 6. Tipos de datos estándar en el lenguaje C.

De Ceballos (1997, pp. 54-61).

Tipo de dato Lo que representa

char

signed char

Cualquier caracter del teclado, que se forma con 1 byte.

Almacena un valor entero en el rango -128 a 127

correspondiente a un carácter del código ASCII (el

código ASCII se ve en la sección 12: Caracteres,

cadenas de caracteres y arreglos de caracteres), aunque

solamente los valores del 0 a 127 son equivalentes a un

carácter

unsigned char

Cualquier caracter del teclado, que se forma con 1 byte.

Almacena un valor en el rango 0 a 255, valores

correspondientes a los números ordinales de los 256

caracteres ASCII

short int

signed short int

Entero corto con signo, es decir un número entero corto

positivo o negativo.

Si está formado por 2 bytes, entonces un número de este

tipo estaría dentro del intervalo cerrado [-32768, 32767],

aunque algunos compiladores pueden utilizar 4 bytes.

unsigned short int

Un número entero corto positivo dentro del intervalo

cerrado [0, 65535] si está formado por 2 bytes (aunque

algunos compiladores pueden utilizar 4 bytes, haciendo

crecer el rango).

int

signed int

Un número entero con signo (positivo o negativo) dentro

del intervalo cerrado [-2147483648, 2147483647] si

estuviera formado con 4 bytes.

unsigned int Un número entero positivo dentro del intervalo cerrado

[0, 4294967295] si está formado por 4 bytes.

long int

signed long int

Un número entero largo con signo (positivo o negativo)

dentro del intervalo cerrado [-9223372036854775808,

9223372036854775807] si estuviera formado por 8

bytes.

unsigned long int

Un número entero largo positivo dentro del intervalo

cerrado [0, 18446744073709551615] si estuviera

formado por 8 bytes.

float

Un número real de simple precisión, es decir, con

precisión de 6 a 7 dígitos significativos, dentro del

intervalo cerrado [-3.402823E+38, -1.701411E-38] para

números negativos y el intervalo cerrado [1.701411E-38,

+3.402823E+38] para números positivos, o el valor cero;

todo esto si estuviera formado con 4 bytes.

Para formarse el número real en simple precisión se

utilizan 23 bits para la mantisa (quien define la

precisión), 1 bit para el signo +/- de la mantisa, 8 bits

para el exponente (quien define el rango).

Page 34: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

33

double

Un número real de doble precisión, es decir, con

precisión de 15 o 16 dígitos significativos, dentro del

intervalo cerrado [-1.79769E+308, -2.22507E-308] para

números negativos y el intervalo cerrado [2.22507E-308,

1.79769E+308] para números positivos, o el valor cero;

todo esto si estuviera formado con 8 bytes.

Para formarse el número real en doble precisión se

utilizan 52 bits para la mantisa (quien define la

precisión), 1 bit para el signo +/- de la mantisa, 11 bits

para el exponente (quien define el rango).

long double

Un número real en doble precisión formato largo, con no

más de 19 dígitos significativos, dentro del intervalo

cerrado [-1.189731E+4932, -3.362103E-4932] para los

números negativos y el intervalo errado [3.362103E-

4932, 1.189731E+4932] para números positivos, o el

valor cero; todo esto si estuviera formado con 12 bytes.

El ANSI C no garantiza un rango y una precisión

mayores que las de double y por tanto, el rango y la

precisión no están normalizados (pueden ser 64 bits para

la mantisa y 16 para el exponente).

Declaración de variables y constantes

Como se mencionó en la definición del término variable en la sección 4: Datos y

expresiones en un programa, todas las variables que se vayan a utilizar en un programa

escrito en el lenguaje C deben declararse antes de usarse. Una variable en C se declara de la

siguiente manera:

tipo_de_dato identificador_1, identificador_2, …, identificador_n ;

donde tipo_de_dato puede ser: int, char, double, etc.

Por ejemplo:

double radio;

declara una variable llamada radio que solo puede almacenar valores de tipo real.

int k;

declara una variable que sólo puede almacenar valores de tipo entero.

Una constante en C se define de la siguiente manera:

#define identificador valor

donde valor puede ser un caracter, un número entero, real o una cadena.

Page 35: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

34

El identificador generalmente se forma con letras en mayúscula para poder

diferenciar rápidamente nombres de constantes de nombres de variables, pero no

es obligatorio. Por ejemplo:

#define E 2.718281828459

declara la constante llamada E para identificar al número de Euler con sólo 12 decimales;

el valor de dicha constante no puede ser alterado a lo largo del programa.

Asignación simple

El signo de igualdad = es el operador básico de asignación. Con este operador se

inicializa el valor de una variable y se le cambia su valor a lo largo de un programa.

variable = expresión ;

Por ejemplo, i = 7; donde la variable i almacena el valor inicial de 7

NOTA IMPORTANTE: La inicialización de una variable en el mismo momento en que es

declarada reduce el tiempo de ejecución de un programa.

Proposiciones

Cuando una expresión va seguida de un punto y coma se convierte en proposición.

Ejemplos: i = 7; printf (“Hola”);

Operadores aritméticos

La tabla 7 muestra los operadores aritméticos permisibles en el lenguaje C.

Tabla 7. Operadores aritméticos.

Adaptado de Bermúdez et al. (2003, p. 37)

Operador Operación que realiza

+ Suma enteros o reales

- Resta enteros o reales

* Multiplica enteros o reales

/ Divide enteros o reales. Si ambos operandos son enteros el resultado es

entero, en el resto de los casos el resultado es real

% Devuelve el módulo o resto de la división de enteros solamente

-

(unario)

El operando entero o real es multiplicado por -1

Page 36: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

35

Prioridad de los operadores

La tabla 8 muestra el orden de prioridad dado a cada operador aritmético y de

asignación, es decir, si se tiene una expresión donde se involucran operadores aritméticos

de suma, resta, multiplicación etc., sin asociar a las operaciones con paréntesis, entonces es

necesario saber cuáles operaciones se realizan primero y cuáles después de acuerdo al

orden de prioridad.

Tabla 8. Prioridad de operadores aritméticos.

Adaptado de Bermúdez et al. (2003, p. 37)

Operadores Asociatividad

-(unario) Derecha a izquierda

* / % Izquierda a derecha

+ - Izquierda a derecha

= Derecha a izquierda

Como se aprecia en la tabla 8, el operador unario es el que tiene mayor orden de

prioridad, es decir, se evaluará primero en una expresión donde haya varios operadores

aritméticos, seguido de la multiplicación, la división y el módulo. En caso de haber más de

un mismo operador con el mismo orden de prioridad, entonces se evaluarán de izquierda a

derecha según se encuentren colocados en la expresión; después se llevarán a cabo la suma

y la resta siguiendo la misma regla explicada antes; finalmente, si en la expresión también

hay un operador de asignación, entonces, una vez que se evalúa toda la expresión, es decir,

una vez que se tiene el resultado calculado se asignará a la variable especificada y si

existiera más de una asignación entonces el orden en que será asignado el resultado es de

derecha a izquierda y no de izquierda a derecha como en los demás operadores.

Por ejemplo:

h = co * co + ca * ca

En la expresión se tiene asignación, multiplicación y suma; siguiendo el orden de

prioridad, lo primero que se evaluará será la multiplicación, después la suma y

finalmente la asignación. Como existen dos multiplicaciones, entonces, se realizará

primero la de la izquierda y después la de la derecha, es decir, primero se multiplicará

co*co, después se multiplicará ca*ca, y ambos resultados se sumarán, finalmente el

resultado de esa suma se asignará a la variable h.

Aunque es necesario conocer, entender y aprender el orden de prioridad de los

operadores, si se tiene duda sobre qué operaciones se realizan primero y qué operaciones

después, se pueden agrupar las operaciones en paréntesis, ya que estos últimos siempre

tendrán el orden de prioridad más alto, es decir, lo que esté encerrado entre paréntesis

siempre se evaluará primero. A lo largo del curso se analizarán varios ejemplos aplicativos

de esta clase de expresiones.

Page 37: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

36

Operadores de relación y lógicos

Cada operador relacional toma dos expresiones como operando y da como resultado el

valor 0 o 1. En el lenguaje C cualquier valor distinto de 0 se considera verdadero y el

valor 0 se considera falso. La tabla 9 muestra los operadores relacionales existentes en el

lenguaje C.

Tabla 9. Operadores relacionales.

Adaptado de Bermúdez et al. (2003, p. 38)

Operador Operación Ejemplos

< Primer operando menor que el

segundo

a < 3

> Primer operando mayor que el

segundo

b > w

<= Primer operando menor o igual que

el segundo

-7.7 <= 99.335

>= Primero operando mayor o igual que

el segundo

-1.3 >= (2.0 * x + 3.3)

== Primer operando igual que el

segundo

c == ’w’

!= Primer operando distinto del segundo x != -2.5

Los operadores lógicos, al igual que los operadores anteriores, cuando se aplican a

expresiones producen los valores 0 o 1 de acuerdo a su tabla de verdad. La tabla 10 muestra

los operadores lógicos existentes en el lenguaje C.

Tabla 10. Operadores lógicos.

Adaptado de Bermúdez et al. (2003, p. 38)

Operador Operación Ejemplo

&&

AND lógico.

Al utilizarse en estructuras condicionales dará

como resultado el valor lógico 1 si todos los

operandos a evaluar son distintos de 0. Si uno

de ellos es 0 el resultado es el valor lógico 0.

(z<x) && (y>w)

Si el valor que almacena

la variable z es menor que

el valor que almacena la

variable x, entonces el

resultado de esa

evaluación es 1; si el valor

que guarda la variable y es

mayor que el valor que

guarda la variable w,

entonces el resultado de

esa evaluación es 1, por

tanto 1 AND 1 es 1

H<=0 && 5

Page 38: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

37

Si el valor que contiene la

variable H es mayor a 0,

entonces el resultado de

esa evaluación es 0; el

valor 5 no se compara con

otro valor, pero es

diferente de 0, por tanto,

la evaluación de esa

expresión es 1, entonces,

0 AND 1 es 0

||

OR lógico.

Al utilizarse en estructuras condicionales dará

como resultado el valor lógico 0 si los

operandos a evaluar son todos cero. Si uno de

los operandos tiene un valor distinto de 0, el

resultado es 1.

(x==y) || (z!=p)

Si el valor que almacena

la variable x es igual al

que almacena y, entonces

el resultado de esa

evaluación es 1; si el valor

que contiene la variable z

es distinto a lo que

contiene p, entonces el

resultado de esa

evaluación es 1; por tanto,

1 OR 1 es 1.

Si el valor que almacena x

es distinto de y, entonces

el resultado de esa

evaluación es 0; si el valor

de z es diferente al de p,

entonces el resultado de

esa evaluación es 1, así, 0

OR 1 es 1.

Si ambas evaluaciones son

falsas, entonces se tiene 0

OR 0 es 0.

!

NOT lógico.

Al utilizarse en estructuras condicionales dará

como resultado el valor lógico 0 si el

operando a evaluar tiene un valor distinto de 0

y 1 en caso contrario.

!a

Si a vale 8, como es

distinto de cero, entonces

la evaluación se toma

como verdadera, al

emplearse la negación, el

resultado de la evaluación

será falsa, es decir, 0.

Si a vale 0, entonces se

Page 39: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

38

considera el valor de

verdad falso, al negarse,

se obtiene el valor

verdadero, es decir, 1.

Operadores de asignación

Además del operador de asignación simple presentado en esta sección, existen los

operadores de asignación que se muestran en la tabla 11.

Tabla 11. Operadores de asignación.

Adaptado de Bermúdez et al. (2003, p. 39)

Operador Operación

= Asignación simple

+= Suma y después asigna

-= Resta y después asigna

*= Multiplica y después asigna

/= Divide y después asigna

%= Obtiene el módulo y después

asigna

++ Incrementa una unidad

-- Decrementa una unidad

Si expr1 y expr2 son expresiones y op un operador aritmético, entonces:

expr1 op= expr2 es equivalente a expr1 = (expr1) op (expr2)

Ejemplos:

c += 3 es equivalente a c = c+3, si c tiene almacenado el valor de 8, después

de aplicar el operador +=, c valdría 11, es decir, 8+3, y el resultado se asigna a la

misma variable c, por tanto, c pierde el valor anterior de 8 y almacena ahora 11.

k *= 3+x es equivalente a k = k*(3+x), si k tuviera almacenado el valor de 2,

y x el valor de 5, entonces, después de aplicar el operador *=, k valdría 16, es decir,

se suma el valor de la variable x, el cual es 5, con el valor 3, el resultado es 8,

después ese valor se multiplica por lo que contiene k, es decir, por 2, resultando 16

y ese valor se almacena en la propia variable k, es decir, k pierde el valor inicial de

2 y ahora almacena 16.

Page 40: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

39

NOTA IMPORTANTE 1: una expresión con un operador de asignación (como en

c+=3) se compila más aprisa que la expresión equivalente expandida (c = c+3) porque en la

primera expresión, la variable c se evalúa únicamente una vez, en tanto que en la segunda

se evalúa dos veces.

NOTA IMPORTANTE 2: Los nombres de variables se dice que son lvalues (por “left

values”) porque pueden ser utilizados en el lado izquierdo de un operador de asignación.

Las constantes se dice que son rvalues (por “right values”) porque sólo pueden ser

utilizadas en el lado derecho de un operador de asignación. Los lvalues también pueden ser

utilizados como rvalues, pero no al revés.

Operadores incrementales y decrementales

Los operadores de incremento ++ y decremento -- son unarios y tienen la misma

prioridad que el operador unario -, éstos se asocian de derecha a izquierda. Tanto ++ como

-- se pueden aplicar a variables pero no a constantes o expresiones. Además pueden estar en

la posición de prefijos o sufijos, con diferentes significados posibles.

Incremento: ++, añade o suma 1 a una variable

Decremento: --, resta 1 a una variable

Ejemplo:

x = x + 1 es equivalente a ++x

si x vale 10, después de aplicar el operador ++, x valdría 11, es decir, se toma el

valor inicial de x, el cual es 10 y se le suma 1, cuyo resultado es 11, este resultado

se almacena en la propia variable x, por tanto, x pierde el valor inicial 10 y

almacena en su lugar el valor 11.

x = x - 1 es equivalente a --x

si x vale 10, después de aplicar el operador --, x valdría 9, es decir, se toma el valor

inicial de x, el cual es 10 y se le resta 1, cuyo resultado es 9, este resultado se

almacena en la propia variable x, por tanto, x pierde el valor inicial 10 y almacena

en su lugar el valor 9.

Estos operadores pueden ir antes o después de la variable:

1. Antes de la variable (preincremento o predecremento). Si el operador ++ o --

aparece antes del operando entonces el operando se incrementa o decrementa antes

de que se evalúe la expresión.

Ejemplo: x = 10;

y = ++x; después de esta evaluación: y = 11 y x = 11

Page 41: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

40

según el orden de prioridad, primero se lleva a cabo el incremento de x, por

tanto si x vale 10, se le suma una unidad y se obtiene el valor 11, ese

resultado se almacena en la misma variable x, es decir, x pierde el valor

inicial de 10 y ahora almacena 11; después se lleva a cabo la asignación, así,

el valor que contiene x es asignando a la variable y, por tanto, y vale 11.

2. Después del operando (postincremento o postdecremento). Si el operador ++ o --

aparece después del operando, entonces primero se evalúa la expresión con el valor

actual del operando y posteriormente se incrementa o decrementa el operando.

Ejemplo: x = 10;

y = x++; después de esta evaluación: y = 10 y x = 11

según el orden de prioridad, primero se lleva a cabo la asignación del valor

de x a la variable y, es decir, si x vale 10, y vale también 10; después se

lleva a cabo el incremento de x, es decir, si x vale 10, se le suma una unidad

y se obtiene el valor 11, ese resultado se almacena en la misma variable x, es

decir, x pierde el valor inicial de 10 y ahora almacena 11.

Es importante hacer notar que al incrementar o decrementar una variable en un

enunciado por sí mismo, es decir, que no se encuentra involucrado con otras expresiones,

las formas de preincremento o predecremento, y postincremento o postdecremento tienen

el mismo efecto. Es decir:

++x; --x;

x++; dan el mismo resultado,

sumando una unidad a la variable x

x--; dan el mismo resultado

restando una unidad a la variable x

Expresiones como ++(x+1) son un error, ya que sólo se utilizan de forma directa en

variables.

Los operadores de incremento y decremento, al afectar el valor de una variable, se les

consideran operadores de asignación como se listaron en la tabla 11.

Tabla de prioridad y orden de evaluación

La tabla 12 muestra el orden de prioridad considerando todos los operadores

mencionados hasta ahora (más completo que el de la tabla 7).

Tabla 12. Prioridad de operadores.

Adaptado de Bermúdez et al. (2003, p. 40)

Operadores Asociatividad

( ) Izquierda a derecha

- (unario) ++ -- ! Derecha a izquierda

* / % Izquierda a derecha

Page 42: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

41

+ - Izquierda a derecha

< <= > >= Izquierda a derecha

== != Izquierda a derecha

&& Izquierda a derecha

|| Izquierda a derecha

= += -= *= %= Derecha a izquierda

Ejemplos de prioridad de operadores: se declaran cuatro variables tipo entero con valores

iniciales que se utilizan para realizar diferentes operaciones aritméticas y de asignación,

obteniendo los resultados que se presentan en la tabla 13, junto con las expresiones

equivalentes a las operaciones aritméticas propuestas.

int a=2,b=-3,c=7,d=-19;

Tabla 13. Valores resultantes según expresiones aplicadas a las variables a, b, c y d.

Expresión Expresión equivalente Valor resultante

a/b (a / b) 0

b/b/a (b/b)/a 0

c%a (c%a) 1

a%b (a%b) 2

d/b%a (d/b)%a 0

-a*d (-a)*d 38

a%-b*c (a%(-b))*c 14

9/c+-20/d (9/c) + ((-20)/d) 2

-d%c-b/a*5+5 (((-d)%c)-

((b/a)*5)) +5

5

7-a%(3+b) 7-(a%(3+b)) Error. Floating point exception,

puesto que no se puede dividir

entre el número cero

---a -(-(-a)) -2

a=b=c=-33 a=(b=(c=-33)) a=-33, b=-33, c=-33

Símbolos para escribir comentarios en un programa

Los programadores insertan comentarios para documentar los programas y mejorar la

legibilidad de éstos. Los comentarios no hacen que la computadora lleve a cabo acción

alguna cuando se ejecute el programa, pues son tratados como texto simple, no como

enunciados, instrucciones o palabras reservadas. Los símbolos que permiten hacer esto son:

/* texto explicativo */

o bien:

// texto informativo

Page 43: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

42

La diferencia entre ellos radica en que, el primero permite que el texto utilice más

de un renglón y el segundo sólo uno.

Ejemplo 1 Ejemplo 2

/* Programa que imprime un mensaje

en pantalla y muestra el uso de

comentarios */

#include <stdio.h>

int main( )

{

printf (“Ejemplo . . . ”);

return 0;

}

#include <stdio.h>

int main( )

{

int i;//i sirve como contador

i = 10;

//Resto del programa

}

7 INSTRUCCIONES DE ENTRADA Y SALIDA

Las operaciones de entrada y salida (abreviadas E/S en español o I/O en inglés)

permiten leer y escribir datos a y desde archivos (también llamados ficheros) o bien,

dispositivos de entrada y salida en general, como lo es el teclado y la pantalla

respectivamente. Dichas operaciones no forman parte del conjunto de sentencias del

lenguaje C sino que pertenecen al conjunto de funciones de la biblioteca estándar de C (la

biblioteca estándar fue descrita en la sección 6: Lenguaje C). Por lo tanto, todo programa

deberá contener la línea inicial: #include <stdio.h>. Esta línea le dice al compilador que

incluya el archivo de cabecera stdio.h (Standard Input Output Header) en el programa,

permitiendo así usar las funciones que manipulan la entrada y salida de datos (Ceballos,

1997).

Las funciones: printf, scanf, getchar, putchar, puts y gets son algunas de las más

utilizadas para entrada y salida de datos. Cada una de ellas tiene una sintaxis que la

identifica y en esta sección se explican únicamente: printf, scanf, getchar y putchar. Tanto

la función puts como gets se ven con más detalle en la sección 12: Caracteres, cadenas de

caracteres y arreglos de caracteres.

Función printf( )

Según Ceballos (1997) se le llama instrucción de salida porque permite presentar datos

en un dispositivo de salida, generalmente la pantalla, dando formato al texto o a los valores.

Ceballos presenta la sintaxis de esta instrucción de la siguiente manera:

printf (cadena de control, lista de argumentos);

Page 44: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

43

donde:

cadena de control especifica el texto que se mandará a pantalla y el formato que se le dará

tanto al texto como a los valores que se quieran presentar. Es una cadena de caracteres

delimitada por comillas dobles “ ” y formada por: texto, secuencias de escape y

especificaciones de formato.

Una secuencia de escape está formada por el carácter \ seguida de una letra o

combinación de dígitos que se utiliza para acciones como: salto de línea, tabular y

representar caracteres no imprimibles (ver tabla 14).

Una especificación de formato siempre comienza con el caracter % seguido de una

serie de símbolos para dar formato a la presentación de los valores, seguidos de una o dos

letras que especifican el tipo de datos que se mostrarán en pantalla: numéricos, caracter,

etc. (ver tabla 15). Cada especificación de formato debe corresponder con un argumento en

la lista de argumentos.

lista de argumentos representa el valor o valores a escribir en pantalla, éstos pueden ser:

variables, constantes, resultados de evaluaciones de funciones o de evaluaciones de

distintas operaciones aritméticas; cuando es más de un argumento deben ir separados por

comas.

Tabla 14. Secuencias de escape para printf.

Secuencia Acción que realiza

\n Genera una nueva línea.

\t Genera una tabulación horizontal.

\v Genera una tabulación vertical.

\b Retrocede el cursor una posición borrando el caracter sobre el que

se posiciona.

\r

Genera un retorno de carro, es decir, el cursor se posiciona al inicio

de la línea donde se encuentra el cursor, por lo que, si se escribe

algún texto éste sobreescribirá a lo que ya exista en la línea.

\a Emite un sonido.

\” Imprime la comilla doble.

\\ Imprime la barra hacia atrás conocida como diagonal invertida.

Tabla 15. Especificaciones de formato para printf.

Adaptado de Ceballos (1997, pp. 112-114).

Código Formato

%d

%i

El argumento a mandar a un dispositivo de salida es un número entero

con signo en notación decimal.

Page 45: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

44

%u

El argumento a mandar a un dispositivo de salida es un número entero

sin signo, en notación decimal.

%hd

%hi

El argumento a mandar a un dispositivo de salida es un número entero

corto, base 10.

%hu

El argumento a mandar a un dispositivo de salida es un número entero

corto sin signo, base 10.

%lu

El argumento a mandar a un dispositivo de salida es un número entero

largo sin signo, base 10.

%ld

El argumento a mandar a un dispositivo de salida es un número entero

largo.

%o

El argumento a mandar a un dispositivo de salida es un número entero

sin signo, en notación octal.

%x,

%X

El argumento a mandar a un dispositivo de salida es un número entero

sin signo, en notación hexadecimal, minúscula o mayúscula.

%g,

%G

Despliega en un dispositivo de salida un valor en punto flotante, ya sea

en forma de punto flotante f, o en la forma exponencial: e o E.

%f

El argumento a mandar a un dispositivo de salida es un número real

(como flotante, con decimales), para tipo double y float.

%Lf

El argumento a mandar a un dispositivo de salida es un número real

largo con signo.

%e,

%E

El argumento a mandar a un dispositivo de salida es un número real

con notación científica en minúscula o mayúscula.

%c El argumento a mandar a un dispositivo de salida es un solo carácter.

%s

El argumento a mandar a un dispositivo de salida es una cadena de

caracteres.

%%

El argumento a mandar a un dispositivo de salida es el caracter signo

de tanto por ciento.

%p

El argumento a mandar a un dispositivo de salida es el valor en

hexadecimal de la dirección física que ocupa una variable en la

memoria.

Page 46: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

45

Función scanf( )

Esta función permite leer o ingresar datos desde el teclado, por lo que se le conoce

como una instrucción de entrada, y presenta su sintaxis de la siguiente forma:

scanf (cadena de control, lista de argumentos);

donde:

cadena de control está formada por códigos de formato de entrada que están precedidos por

un signo % y delimitados por comillas “ ” para especificar el tipo de valor que se leerá

desde teclado (ver la tabla 16).

lista de argumentos que se forma con una o más variables que almacenarán el valor o

valores que se van a leer desde el teclado; cada nombre de variable debe ir precedida por el

carácter & (si las variables son de tipo numérico o caracter, no así con las de tipo cadena) y

separados por comas. Cuando se especifica más de un argumento, los valores

correspondientes en la entrada (al momento de teclearlos o introducirlos) hay que

separarlos por uno o más espacios en blanco, tabuladores o enter.

El carácter & (llamado ampersand) es conocido en el lenguaje C como el operador de

dirección. Al ser combinado con un nombre de variable, le indica a la computadora la

posición en memoria donde se almacenará el valor y la computadora entonces almacena el

valor en esa posición.

Tabla 16. Códigos de formato para scanf.

Adaptado de Ceballos (1997, pp. 119-120).

Código Acción que realiza

%d Permite leer desde el teclado un número entero base10.

%i

Permite leer desde el teclado un entero decimal, octal o

hexadecimal, opcionalmente signado, es decir, con signo + o –

%hu

Permite leer desde teclado un número entero corto sin signo,

base 10.

%u

Permite leer desde el teclado un número entero sin signo, base

10.

%o Permite leer desde el teclado un número en octal.

%x Permite leer desde el teclado un número en hexadecimal.

%hd

%hi

Permite leer desde el teclado un número entero corto, base 10.

%lu Permite leer desde el teclado un número entero largo sin signo,

Page 47: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

46

base 10.

%f

%e,

%E

%g,

%G

Permite leer desde el teclado un número real, por ejemplo, el

tipo flotante con decimales.

%ld

%li

Permite leer desde el teclado un número entero largo, base 10.

%c Permite leer desde el teclado un solo carácter.

%s

Permite leer desde el teclado una palabra o cadena de caracteres

sin espacios.

%lf Permite leer desde el teclado un número real (tipo double).

%Lf

Permite leer desde el teclado un número real largo (tipo long

double).

Función getchar( )

Permite leer un único caracter desde el teclado, de tal forma que el usuario después de

teclear el carácter en cuestión debe presionar la tecla enter para concluir (Cairó Battistutti,

2006). Por ejemplo, el siguiente código permitirá al usuario ingresar desde teclado un

caracter y dicho caracter será almacenado en la variable car después de presionar enter.

car = getchar( ); /*getchar captura el carácter que el

usuario haya pulsado en el teclado y lo almacena en la

variable car.*/

También existen las funciones getch( ) y getche( ) pero son exclusivas para sistemas

operativos MS-DOS (es decir sistemas operativos Windows). La primera lee un carácter del

teclado pero ese caracter que teclea el usuario no se ve en pantalla y no necesita presionar

enter después del caracter; la segunda función lee un caracter del teclado que sí se visualiza

en pantalla y al igual que getch no es necesario presionar enter para concluir o continuar.

Estas dos funciones pertenecen al archivo de cabecera conio.h, el cual, por cierto, ya es

obsoleto.

Ejemplo: Printf(“Presiona una tecla para continuar ”);

getch(); /*La ejecución del programa continuará después de

que el usuario pulse una tecla, la cual no ser verá en

pantalla.*/

Page 48: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

47

Función putchar( )

Permite imprimir un único caracter en la pantalla (Cairó Battistutti, 2006). Por ejemplo,

el siguiente código mostrará en la pantalla el caracter que contenga la variable car.

putchar(car);

Buffer o memoria intermedia

Las funciones estándar de E/S tienen la característica fundamental de que las

operaciones de E/S de datos se realiza a través de un buffer o memoria intermedia, como

una técnica implementada en software para hacer a dichas operaciones más eficientes

(Ceballos, 1997).

Un buffer es un área de datos en la memoria RAM asignada por el programa que se

está ejecutando y que abre automáticamente cinco archivos:

stdin: dispositivo de entrada estándar (teclado)

stdout: dispositivo de salida estándar (pantalla)

stderr: dispositivo de error estándar (pantalla)

sdtaux: dispositivo auxiliar estándar (puerto serie)

stdprn: dispositivo de impresión estándar (impresora en paralelo)

De estos cinco, dos de ellos: el dispositivo serie y el de impresión paralela, dependen

de la configuración de la máquina, por lo tanto, pueden no estar presentes. El que aquí

importa es el dispositivo de entrada estándar (teclado) y por ello se describe a continuación

lo que típicamente sucede al ingresar datos principalmente de tipo caracter.

Las funciones scanf y getchar tienen una característica común: leen los datos

requeridos de la entrada estándar referenciada por stdin. Es necesario tener presente que

cuando son tecleados los datos, no son leídos directamente del dispositivo de entrada, sino

que éstos son depositados en la memoria intermedia buffer, asociada con el dispositivo de

entrada. Los datos son leídos de la memoria intermedia cuando son validados y esto ocurre

cada vez que pulsamos la tecla Enter. Esta tecla se representa con el carácter LF y también

se almacena en el buffer junto con todo lo que haya tecleado el usuario. Por tanto, después

de presionar Enter, las funciones scanf y getchar toman del buffer lo que se haya ingresado

hasta antes del caracter LF, es decir, hasta lo que esté antes del Enter. Pero si las funciones

scanf y/o getchar se vuelven a usar, éstas toman lo que está en el buffer, pero encuentran el

caracter LF antes almacenado, por lo que, para ellas significa que el usuario no ingresó

ningún dato y del programa se ejecuta la siguiente línea de código, es decir, el efecto que se

tiene en el segundo llamado de las funciones scanf y/o getchar es que el usuario no tiene

oportunidad de ingresar sus datos, por lo que verá la ejecución de la siguiente línea de

código(Ceballos, 1997). En conclusión LF o la tecla Enter genera problemas de lecturas

no deseadas SOLO cuando el tipo de dato a ingresar es de tipo caracter o char.

Page 49: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

48

La solución a lo anterior es limpiar el buffer asociado con stdin antes de una lectura o

ingreso de datos con las funciones scanf y getchar, utilizando por ejemplo, las funciones:

fflush(stdin) disponible en el sistema operativo Windows, o bien,

fpurge(stdin) disponible en el sistema operativo GNU/Linux (al inicio de la

función se encuentran dos guiones bajos consecutivos).

Estas funciones pueden colocarse inmediatamente después de haber usado las

instrucciones scanf y/o getchar.

En la sección 12: Caracteres, cadenas de caracteres y arreglos de caracteres se tratará

a fondo el tema de los caracteres en el lenguaje C.

8 ESTRUCTURAS SECUENCIALES Y SELECTIVAS

8.1 Estructura secuencial

Es aquella en la que una acción o instrucción sigue a otra en secuencia o en orden. La

salida de una es la entrada de la siguiente y así sucesivamente (ver figura 6). Dichas

acciones pueden ser instrucciones de entrada, salida, asignación de valores o procesamiento

(Deitel y Deitel, 1995).

Figura 6. Estructura secuencial.

8.2 Estructuras selectivas

Se utilizan para tomar decisiones lógicas. Se les llama estructuras de decisión o

alternativas. Pueden ser: simples, dobles o múltiples.

Page 50: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

49

8.2.1 Alternativa simple (si, entonces)

Ejecuta una o varias acciones cuando se cumple una determinada condición, es decir,

se evalúa la condición y si ésta es verdadera se ejecuta la acción o acciones específicas,

pero si la condición es falsa entonces se hace nada como se muestra en la figura 7.

En el lenguaje C, la estructura de alternativa simple se especifica mediante la

instrucción if, cuya sintaxis se muestra a continuación.

if (expresión)

{

proposiciones;

}

proposición_siguiente;

donde la expresión debe ser de tipo numérica, relacional o lógica.

Si el resultado de evaluar expresión es verdadero entonces se ejecutarán las

proposiciones (que pueden ser una o varias instrucciones de entrada, salida, proceso, otra

condicional o ciclos) y después proposición_siguiente. Por otra parte, si el resultado de la

evaluación es falso entonces no se realiza acción alguna y continúa el flujo del programa a

la siguiente línea de código proposición_siguiente.

Ahora bien, si se tiene sólo una proposición o instrucción a ejecutarse, no es

necesario colocar llaves para englobar la sentencia, pero si es más de una, sí son

necesarias.

Figura 7. Alternativa simple.

Page 51: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

50

8.2.2 Alternativa doble (si, entonces, sino, entonces)

Como se muestra en la figura 8, se ejecutará la acción o acciones S1 si al evaluarse una

condición ésta es verdadera, o bien se realizará la o las acciones S2 si la condición es falsa,

pero nunca ambas acciones S1 y S2 al mismo tiempo.

En el lenguaje C, la estructura de alternativa doble se especifica mediante la

instrucción if else, cuya sintaxis se muestra a continuación.

if (expresión)

{

proposiciones_1;

}

else

{

proposiciones_2;

}

proposición_siguiente;

donde la expresión debe ser de tipo numérica, relacional o lógica.

Si el resultado de evaluar expresión es verdadero entonces se ejecutarán las

proposiciones_1 (que pueden ser una o varias instrucciones de entrada, salida, proceso, otra

condicional o ciclos). Por otro lado, si el resultado de la evaluación es falso entonces no se

realizarán las proposiciones_1 sino que se ejecutarán las proposiciones_2 (que también

pueden ser una o varias instrucciones de entrada, salida, proceso, otra condicional o ciclos).

Después de evaluarse la condición y ejecutarse lo pertinente, si la condición es verdadera o

falsa se continúa con el flujo del programa a la siguiente línea de código

proposición_siguiente.

Al igual que en la alternativa simple, si se tiene sólo una proposición o instrucción a

ejecutarse en el if, entonces no es necesario colocar llaves para englobar la proposición o

sentencia, y lo mismo aplica para el else.

Figura 8. Alternativa doble.

Page 52: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

51

8.2.3 Alternativa múltiple (selector)

La estructura de decisión múltiple (selector) evaluará únicamente el valor de una

variable que podría tomar n valores distintos. Según se elija uno de esos valores de la

variable, se realizará una y sólo una de las n acciones, o lo que es igual, el flujo del

algoritmo seguirá un determinado camino entre los n posibles como se muestra en la figura

9 (Cairó Battistutti, 2006).

Figura 9. Alternativa múltiple (selector).

Adaptado de Cairó Battistutti (2006, p. 58)

En el lenguaje C, esta estructura se especifica como se muestra a continuación.

switch (expresión)

{

case constante1: sentencias1;

break;

case constante2: sentencias2;

break;

case constante3: sentencias3;

break;

default: sentenciasN;

break;

}

donde expresión es una variable de tipo entera o caracter y sentencias pueden ser una o

varias instrucciones de entrada, salida, proceso, condicionales o ciclos.

La sentencia switch evalúa la expresión entre paréntesis y compara su valor con las

constantes de cada case, si coincide la expresión con alguna constante entonces se

ejecutarán todas las sentencias después de los dos puntos de dicho case de coincidencia

hasta la instrucción break, es decir, la instrucción break permite salir de la estructura

switch y no continuar con la ejecución de las sentencias de otro case con el cual no

Page 53: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

52

coindice el valor de la variable, por tanto, se debe utilizar la sentencia break para concluir

le ejecución de las sentencias en cada case. En el caso de que ninguna de las constantes

coincida con la expresión entonces se ejecutarán la o las sentenciasN que se encuentran

después de los dos puntos de la palabra clave default. La sentencia switch puede incluir

cualquier número de cláusulas case y opcionalmente la cláusula default, es decir, se puede

omitir si no se requiere realizar algo en particular al no coincidir el valor de la variable con

algún valor especificado en los distintos case. Las sentencias pueden ser una o varias

instrucciones de entrada, salida, proceso, otra condicional o ciclos.

8.2.4 Alternativa múltiple (no selectora)

En una estructura de decisión múltiple (no selectora) existe más de una condición a

evaluarse como se muestra en la figura 10 y funciona de la siguiente manera. Primero se

evalúa Condición1 y si ésta es verdadera entonces se ejecutan Acciones1 y continua con

AccionesSiguientes, pero si la condición es falsa entonces se evalúa Condición2,

nuevamente, si la Condición2 es verdadera entonces se realizan Acciones2 y continua con

AccionesSiguientes pero si la condición es falsa entonces se repite el proceso anterior por

cada condición que exista, de tal manera que si se llega a la CondiciónN y ésta es verdadera

entonces se realizan las AccionesN y después AccionesSiguientes pero si la condición es

falsa entonces se ejecutan AccionesDefault, es decir, esta o estas instrucciones se llevarán a

cabo si ninguna de las condiciones anteriores fue verdadera.

En el lenguaje C, la estructura de alternativa múltiple (no selectora) se especifica

mediante la instrucción if else if cuya sintaxis se muestra a continuación (en realidad es una

forma particular de presentar la estructura if anidada como se verá en la siguiente sección

8.2.5).

if (expresión1)

{

sentencias1;

}

else if (expresión2)

{

sentencias2;

}

else if (expresión3)

{

sentencias3;

}

else

{

sentenciasN;

}

proposición_siguiente;

Page 54: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

53

Figura 10. Alternativa múltiple (no selectora).

donde la expresión1, expresión2, expresión3, etc. deben ser de tipo numérico, relacional o

lógico. Si la expresión1 es verdadera se ejecutan las sentencias1 (que pueden ser una o

varias instrucciones de entrada, salida, proceso, otra condicional o ciclos) y continúa con

proposición_siguiente, pero si la condición es falsa entonces se examina la expresión2 y

nuevamente, si ésta es verdadera entonces se ejecutan las sentencias2 (que pueden ser una

o varias instrucciones de entrada, salida, proceso, otra condicional o ciclos) para continuar

con proposición_siguiente pero si la condición es falsa se evalúa la tercera expresión y así

sucesivamente hasta llegar al else, ejecutándose las sentenciasN sólo si todas las

expresiones anteriores fueron falsas, para después continuar con proposición_siguiente.

Al igual que en la alternativa simple y doble, si se tiene sólo una proposición o

instrucción a ejecutarse, no es necesario colocar llaves para englobar la sentencia para el if,

cada else if que exista y el else, pero si es más de una, sí son necesarias.

Page 55: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

54

8.2.5 Estructuras de decisión anidadas o en cascada

Las estructuras si interiores a otras estructuras iguales se denominan anidadas,

encajadas o en cascada. Una estructura de selección de n alternativas o de decisión

múltiple, tanto selectora como no selectora, puede ser construida utilizando una estructura

si anidada, es decir unas interiores a otras formando una cascada o escalera como se

muestran en las figuras 11,12 y 13. De hecho la estructura múltiple no selectora es en

realidad una estructura anidada pero presentada con una distribución un tanto diferente.

Figura 11. Ejemplo 1 de estructuras selectivas anidadas.

Figura 12. Ejemplo 2 de estructuras selectivas andadas.

Page 56: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

55

Figura 13. Ejemplo 3 de estructuras selectivas anidadas.

8.2.6 Operador ternario

En el lenguaje C existe un operador conocido como ternario pues necesita tres

argumentos obligatorios que no se pueden omitir. Evalúa una condición de tal manera que

si ésta es verdadera entonces se ejecuta una única instrucción o sentencia, pero si la

condición es falsa entonces se ejecuta otra única instrucción, en otras palabras, con este

operador, a diferencia de las otras instrucciones condicionales descritas, sólo se ejecuta una

instrucción pero no un conjunto de instrucciones. En el operador se usa el caracter de

interrogación que cierra para separar la condición de la instrucción que se realizará si la

condición es verdadera, y se usa el caracter de dos puntos para separar la instrucción que se

realizará si la condición es verdadera de la instrucción que se realizará si la condición es

falsa. Su sintaxis es como se muestra a continuación.

expresión1? sentenciaV : sentenciaF

Si expresión1 es verdadera, entonces se ejecuta sentenciaV, si es falsa se ejecuta

sentenciaF.

La importancia de este operador radica en que se utiliza comúnmente en la asignación

que se le hace a una variable dependiendo del resultado de una condicional. Con este uso, la

condicional aparece del lado derecho de una asignación como se ilustra en el siguiente

ejemplo: mayor = a>b ? a : b;

En la sentencia anterior, se evalúa la expresión a>b y si ésta es verdadera entonces a la

variable mayor se le asignará el valor de la variable a, pero si la expresión es falsa entonces

a la variable mayor se le asignará el valor de la variable b.

Page 57: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

56

9 ESTRUCTURAS REPETITIVAS

En la práctica, durante la solución de problemas, es muy común encontrar operaciones

que se deben ejecutar un número determinado de veces, si bien las instrucciones son las

mismas los datos varían (Cairó Battistutti, 2006).

Las estructuras que repiten una secuencia de instrucciones un número determinado de

veces se denominan bucles, y se llama iteración al hecho de repetir la ejecución de una

secuencia de acciones. En un bucle o ciclo se deben tener en cuenta qué es lo que contiene

el bucle y cuántas veces se debe repetir.

Para detener la ejecución de los bucles se utiliza una condición de parada, esta

condición puede especificarse al principio o al final del bucle según el problema a resolver.

Se tienen así tres tipos de estructuras repetitivas o iterativas:

1. La condición de salida del bucle se verifica al principio de dicho bucle, por lo que el

ciclo se realiza mientras se cumple una condición.

2. La condición de salida se origina al final del bucle; el bucle se ejecuta mientras se

verifica una cierta condición pero después de haberse ejecutado por lo menos una

vez la o las instrucciones.

3. La condición de salida se verifica con un contador que cuenta el número de

iteraciones a realizarse.

9.1 Estructura mientras

Cuando se ejecuta la instrucción mientras, lo primero que se realiza es la evaluación

de la condición (una expresión booleana), si se evalúa como falsa entonces ninguna acción

se ejecuta dentro del bucle y el programa prosigue en la siguiente instrucción fuera del

bucle. Si la expresión booleana es verdadera entonces se ejecuta el cuerpo del ciclo,

después de lo cual se evalúa de nuevo la expresión booleana. Este proceso se repite una y

otra vez mientras la condición es verdadera (ver figura 14). En este tipo de ciclos puede

suceder que nunca se ejecuten acciones si la condición nunca es verdadera, o bien, puede

darse un ciclo infinito si la condición nunca se vuelve falsa.

Como un caso particular, si el problema que se resuelve requiere leer una lista de

valores con un bucle mientras, se debe incluir algún tipo de mecanismo para terminar el

bucle como Deitel y Deitel (1995) lo describen:

a. Preguntar al usuario antes de la iteración,

b. Saber de antemano el número de iteraciones exactas que se van a llevar a cabo,

c. Con un valor llamado centinela, que es un valor especial usado para indicar el final

de una lista de datos.

Page 58: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

57

Ahora bien, en el lenguaje C, la estructura repetitiva mientras se especifica mediante la

instrucción while cuya sintaxis se muestra en seguida.

while (expresión)

{

sentencias1;

}

sentencias2;

donde expresión es cualquier expresión numérica, relacional o lógica. Puede ser numérica

puesto que cualquier valor diferente de cero se considera un valor booleno verdadero,

mientras que el cero se considera un valor booleano falso.

La instrucción ejecuta una sentencia simple o compuesta cero o más veces

dependiendo del valor de la expresión, es decir, se ejecutarán las instrucciones mientras la

expresión es verdadera, en el momento en que se convierte en falsa se ejecuta la línea

después del fin del while, es decir, sentencias2.

Si se tiene sólo una proposición o instrucción a ejecutarse, no es necesario colocar

llaves para englobar la sentencia del ciclo, pero si es más de una, sí son necesarias.

Figura 14. Estructura mientras.

9.2 Estructura hacer mientras

Esta estructura se utiliza cuando se debe ejecutar al menos una vez un bucle antes de

comprobar la condición de repetición (ver figura 15).

La estructura hacer mientras se ejecuta mientras una condición determinada es

verdadera, la cual se comprueba al final del bucle pero cuando la condición es falsa

continúa con las instrucciones fuera del ciclo.

Page 59: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

58

La estructura es adecuada cuando no se sabe el número de veces que se debe repetir un

ciclo pero se sabe que se debe ejecutar por lo menos una vez, además es eficiente para

verificar los datos de entrada en un programa (Cairó Battistutti, 2006).

Figura 15. Estructura hacer mientras.

En el lenguaje C, la estructura repetitiva hacer mientras se especifica con las

instrucciones do while como se muestra a continuación.

do

{

sentencias;

}while ( expresión );

La sentencia do while funciona de la siguiente manera: se ejecuta primero la sentencia

o bloque de sentencias después del do, luego se evalúa la expresión y si es falsa termina la

proposición do while pero si es verdadera (diferente de cero) entonces se repite la sentencia

o sentencias dentro del do{ }.

En esta estructura si se tiene sólo una proposición no es necesario colocar llaves para

englobar la sentencia a ejecutarse, pero si es más de una sí son necesarias.

9.3 Estructura desde o para

Esta estructura se utiliza cuando se sabe cuántas veces se desean ejecutar las acciones

de un ciclo. Se utiliza para repetir un conjunto de instrucciones un número definido de

veces. Comienza con un valor inicial de la variable llamada índice y las acciones

especificadas se ejecutan a menos que el valor inicial sea mayor que el final cuando la

variable índice sufre incrementos, o bien se detiene si la variable índice es menor que el

final si la variable índice sufre decrementos (Cairó Battistutti, 2006). Lo anterior se aprecia

en las figuras 16 y 17.

Page 60: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

59

NOTA IMPORTANTE: toda estructura desde o para se puede sustituir por una

estructura mientras, y viceversa, sin embargo, se recomienda aplicar la estructura desde o

para sólo en aquellos problemas en los que se conoce previamente el número de veces que

se debe repetir el ciclo, y utilizar la estructura mientras en aquellos problemas en que el

número de veces que se tenga que repetir el ciclo dependa de la condición a evaluar y no de

un número determinado de veces.

Figura 16. Estructura desde o para.

Figura 17. Otra forma de representar a la estructura desde o para.

Adaptado de Bermúdez et al. (2003, p. 18).

En el lenguaje C, la estructura repetitiva desde o para se especifica con la instrucción

for como se muestra a continuación.

Page 61: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

60

for (inicialización; condición; incremento/decremento)

{

Sentencias1;

}

Sentencias2;

donde:

inicialización es una proposición de asignación que se utiliza para establecer la variable de

control o índice. Se pueden utilizar varias variables de control en un ciclo de repetición for,

por lo que al inicializar más de una variable, éstas se separan por comas.

condición es una expresión relacional o lógica que determina cuándo terminará el ciclo de

repetición.

incremento/decremento define cómo cambiará la variable de control (variable índice) o las

variables de control (si hay más de una) en cada repetición; dichos cambios generalmente

son incrementos o decrementos sobre las variables índice.

Las tres partes que conforman el encabezado del ciclo for (inicialización, condición e

incremento/decremento) tienen que estar separadas por puntos y comas independientemente

de que se omita la inicialización o el incremento/decremento, pues estas dos partes sí

pueden omitirse, no así la condición. Ahora bien, a pesar de que se pueden omitir las dos

partes antes mencionadas, se recomienda utilizar cada una de las tres, es decir, se

recomienda respetar la propia estructura de la instrucción. En caso de omitir la

inicialización, ésta se debe realizar en algún punto antes del ciclo; si lo que se omite es el

incremento/decremento, entonces éstos deben realizarse dentro del cuerpo de la estructura

for.

Al igual que la estructura while y do while antes mencionadas, en la estructura for, si

se tiene sólo una proposición no es necesario colocar llaves para englobar la sentencia a

ejecutarse, pero si es más de una sí son necesarias.

Por último, como ya se explicó, todo while tiene su equivalente en for y viceversa, a

modo de ejemplo se presenta en seguida el código equivalente.

Ejemplo de un ciclo for Equivalencia con un ciclo while

for (expr1; expr2; expr3)

proposición;

expr1;

while(expr2){

proposición;

expr3;

}

Page 62: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

61

9.4 Estructuras repetitivas anidadas

Como en las estructuras condicionales, es posible insertar un bucle dentro de otro. La

estructura interna debe estar incluida totalmente dentro de la externa y no puede existir

solapamiento. El anidamiento se puede dar entre iguales o diferentes estructuras

repetitivas, es decir, puede existir un ciclo mientras dentro de otro ciclo mientras, un ciclo

hacer mientras dentro de otro ciclo hacer mientras o un ciclo para dentro de otro ciclo

para; pero también, puede existir un ciclo mientras dentro de un ciclo para, un ciclo hacer

mientras dentro de un bucle mientras, o cualquier combinación dependiendo del problema

a resolver. Un ciclo interno completo se repetirá el número de veces que la condición del

ciclo externa sea verdadera. Por ejemplo, si se tuvieran dos anidamientos, es decir un tercer

ciclo dentro de un segundo y éste dentro de un primer ciclo, entonces el ciclo más interno

(el tercero) se ejecutará la cantidad de veces que sea verdadera la condición del segundo

ciclo multiplicado por la cantidad de veces que sea verdadera la condición del primer

ciclo; y el segundo bucle se ejecutará la cantidad de veces que la condición del primer ciclo

sea verdadera.

9.5 Instrucciones que alteran el flujo normal de un ciclo

En ocasiones es necesario disponer de instrucciones que permitan la salida en un punto

intermedio de cualquier bucle sin que se verifique la condición principal de dicho bucle, es

decir, salir del ciclo antes de llegar a la condición. Estas instrucciones sólo están disponible

en algunos lenguajes de programación y en general no es recomendable usarlas, porque el

programa no es tan legible o “limpio” como debe ser.

Sentencia break

Finaliza la ejecución de una proposición switch, for, while y do while en la cual

aparece dicha instrucción, saltándose la condición normal del ciclo de repetición.

Sentencia continue

Interrumpe la ejecución normal de un bucle (for, while y do while) pero no lo finaliza,

sino que, termina la iteración en curso, transfiriendo el control del programa a la

condicional del bucle, para decidir si se debe realizar una nueva iteración o no. Es decir,

continue termina la ejecución de la iteración actual de un bucle, pero no la ejecución del

bucle en sí. Continue evita que se ejecuten las instrucciones que existan después de ella en

la iteración del bucle, saltando hasta la condicional.

Función exit( )

A diferencia de break, terminará no sólo con la ejecución del bucle sino con la

ejecución del programa y regresará el control al sistema operativo.

Page 63: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

62

10 NÚMEROS PSEUDOALEATORIOS EN EL LENGUAJE C

Existen multitud de problemas que requieren que una computadora simule el

comportamiento de un sistema con alguna variable o variables aleatorias, es decir, que

genere números cuyo orden no sea predecible y puedan considerarse al azar, por ejemplo:

el número de viajeros en una estación de autobuses, programación de juegos (tirada de un

dado), etc. Sin embargo, en la práctica, no existen números que, generados por una

computadora, sean realmente aleatorios, pues hay que tener en cuenta que una computadora

es una máquina determinista, es decir, determinada por las condiciones iniciales y en la que

no hay ni puede haber operaciones aleatorias puras. Pero, una computadora sí puede

generar números pseudoaleatorios (Rodríguez y Galindo, 2009).

Un número pseudoaleatorio es un número generado por la computadora que, no es

realmente aleatorio pero se comporta como si se hubiera producido al azar (Rodríguez y

Galindo, 2009).

El lenguaje C permite generar números pseudoaleatorios usando una de dos funciones

disponibles según en el sistema operativo en el que se esté trabajando: la función random(

) en el sistema operativo GNU/Linux y la función rand( ) en el sistema operativo

Windows. Ambas funciones no necesitan un argumento entre paréntesis y devuelven un

número pseudoaleatorio entre los valores del intervalo cerrado [0, RAND_MAX].

RAND_MAX es una constante del lenguaje C que equivale al menos al valor 32,767,

que es lo máximo que se puede almacenar en una variable de tipo entero con signo, aunque

su valor depende de la biblioteca donde se haya implementado dicha constante, es decir,

depende del compilador que se esté utilizando (se habló de los distintos tipos de

compiladores para el lenguaje C en la sección 6 Lenguaje C). El valor 32,767 se encuentra

en la mayoría de las bibliotecas, aunque se puede llegar a encontrar como máximo el

número: 2,147,483,647 (Rodríguez y Galindo, 2009).

Las funciones mencionadas generarán números pseudoaleatorios a partir de un número

inicial llamado semilla y, es con ese valor inicial que generan el primer número, después, a

partir de dicho número generan el segundo, con el segundo, el tercero y así sucesivamente

hasta concluir con la cantidad de números pseudoaleatorios que se necesiten producir.

Cuando se requiere cambiar el valor máximo del intervalo cerrado de números

pseudoaleatorios que da por default el lenguaje C, entonces se debe dimensionar usando

un factor de dimensionamiento, el cual determina el valor máximo. Para ello, se usa la

función que genera los números pseudoaleatorios seguida del operador módulo y el factor

de dimensionamiento deseado (Deitel y Deitel, 1995). A continuación se detalla el

procedimiento suponiendo a n una variable entera como el factor de dimensionamiento y

proporcionada por el programador o usuario:

random( ) % n Es la sintaxis en el sistema operativo GNU/Linux para generar un número pseudoaleatorio

entre los valores del intervalo cerrado [0, n-1].

Page 64: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

63

rand( ) % n Es la sintaxis en el sistema operativo Windows para generar un número pseudoaleatorio

entre los valores del intervalo cerrado [0, n-1].

Ahora bien, cuando se requieren cambiar ambos valores del intervalo cerrado, además

del dimensionamiento, se debe llevar a cabo un desplazamiento. Suponiendo a m y n como

variables enteras proporcionadas por el programador o usuario y, m < n, entonces:

random( ) % (n-m+1) + m Es la sintaxis en el sistema operativo GNU/Linux para generar un número pseudoaleatorio

entre los valores del intervalo cerrado [m, n].

rand( ) % (n-m+1) + m Es la sintaxis en el sistema operativo Windows para generar un número pseudoaleatorio

entre los valores del intervalo cerrado [m, n].

Ejemplos:

/*Se genera un número pseudoaleatorio en el sistema operativo GNU/Linux dentro del

intervalo cerrado [0, 7] y se almacena en la variable numero.*/ numero = random() % 8;

/*Se genera un número pseudoaleatorio en el sistema operativo GNU/Linux dentro del

intervalo cerrado [10, 50] y se almacena en la variable numero.*/ numero = random() % (50-10+1) + 10;

/*Se genera un número pseudoaleatorio en el sistema operativo Windows dentro del

intervalo cerrado [0, 7] y se almacena en la variable numero.*/ numero = rand() % 8;

/*Se genera un número pseudoaleatorio en el sistema operativo Windows dentro del

intervalo cerrado [10, 50] y se almacena en la variable numero.*/ numero = rand() % (50-10+1) + 10;

Por otro lado, en cada ejecución de un programa donde se usan las funciones antes

descritas, se obtiene la misma secuencia de números pseudoaleatorios porque la semilla es

un número fijo. Para evitar esto, se usa de la biblioteca stdlib.h la función srandom(

) si se está trabajando en el sistema operativo GNU/Linux, o la función srand( ) si se

está trabajando en el sistema operativo Windows. Ambas funciones se deben utilizar con un

parámetro que servirá como semilla o número inicial. Si el parámetro especificado es un

número fijo (por ejemplo, una constante o un número generado por las mismas funciones

rand o random) se tiene el mismo problema, es decir, se obtiene la misma secuencia de

Page 65: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

64

números pseudoaleatorios en cada corrida del programa; para corregir esto, se puede hacer

uso de alguna de las siguientes funciones:

- Función time( ) del lenguaje C que se encuentra en la biblioteca time.h

Devuelve la fecha y hora actual que tenga establecido el sistema operativo. La

forma de utilizarla junto con la función srand o srandom es:

srandom( time(NULL) ) en el sistema operativo GNU/Linux, o

srand( time(NULL) ) en el sistema operativo Windows.

La función time( ) devuelve un valor en segundos correspondiente al instante actual en

que se ejecuta el programa, dicho valor se calcula a partir de las cero horas del 1 de enero

de 1970 (inicio en que se utilizó por primera vez el sistema operativo Unix). En Windows

también devuelve el tiempo en segundos partiendo de un valor inicial8.

- Función getpid( ) que se puede encontrar en las bibliotecas: sys/types.h o unistd.h

Devuelve el número de proceso que se le haya asignado al programa que se está

ejecutando actualmente, el cual siempre es distinto en cada corrida de dicho

programa. La forma de utilizarla junto con la función srand o srandom es:

srandom( getpid() ) en el sistema operativo GNU/Linux, o

srand( getpid() ) en el sistema operativo Windows.

Finalmente, la función drand48( ) se usa para obtener números pseudoaleatorios con

decimales, por defecto el valor que devuelve la función está en el intervalo [0.0, 1.0), es

decir, no devolverá el 1.0. La función srand48( ) se usa para cambiar la semilla de inicio,

por lo que también se puede hacer uso de time( ) y getpid( ) como se explicó anteriormente.

Estas funciones no se encuentran en el sistema operativo Windows.

Si se quiere un número en el intervalo [m, n), n>m, m y n reales, entonces se tendría:

numero = drand48()*(n-m) + m

Ejemplo para generar un número entre el rango [10.0, 20.0)

numero = drand48()*(10.0) + 10.0

8 Nota: la función time( ) es de tipo long int. Un tipo de dato long int = 2,147,483,647; 1 año = 31,536,000

segundos, por lo que el valor máximo del long int se alcanzará aproximadamente el 18 de febrero de 2038.

Page 66: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

65

11 ARREGLOS

Introducción a las estructuras de datos

Una estructura de datos es una colección de datos simples que se caracterizan por su

organización y las operaciones que se definan en ella.

Las estructuras de datos estáticas son aquellas en las que el tamaño ocupado en

memoria se define antes de que el programa se ejecute y no puede modificarse dicho

tamaño durante la ejecución del programa. Estas estructuras están implementadas en casi

todos los lenguajes de programación, ejemplos: arreglos, registros y ficheros o archivos.

Las estructuras de datos dinámicas no tienen las limitaciones o restricciones en el

tamaño de memoria ocupada. Mediante el uso de un tipo de dato específico denominado

puntero, es posible construir estructuras de datos dinámicas que son soportadas por la

mayoría de los lenguajes. Las estructuras dinámicas por excelencia son: listas, árboles y

grafos.

Los tipos de datos simples tienen como característica común que cada variable

representa a un elemento, los tipos de datos estructurados tienen como característica común

que un identificador (nombre) puede representar múltiples datos individuales, pudiendo

cada uno de éstos ser referenciado independientemente.

Datos simples

Estándar

Entero

Real

Caracter

Lógico

Definido por el programador

Subrango

Enumerativo

Datos estructurados

Estáticos

Arreglos (vector o matriz)

Registros

Archivos o ficheros

Conjuntos

Cadenas

Dinámicos

Listas (pilas o colas)

Listas enlazadas

Árboles

Grafos

Page 67: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

66

En el curso de Programación I solamente se abarcan arreglos y cadenas, en el curso de

Programación II se explican el resto de estructuras. En los siguientes apartados de esta

sección se revisan en particular los arreglos.

Concepto de arreglo

Un arreglo es una colección finita, homogénea y ordenada de elementos, en otras

palabras, es una estructura compuesta por varios elementos, todos del mismo tipo (entero,

real, carácter o booleano) y almacenados consecutivamente en memoria. Cada componente

puede ser accedido directamente por el nombre del arreglo seguido de uno o varios

subíndices encerrados entre corchetes [ ] según sea la dimensión del arreglo; los subíndices

indican la posición de cada componente del arreglo y pueden ser únicamente valores

enteros positivos, variables tipo entero positivos o expresiones numéricas enteras positivas

(Cairó Battistutti, 2006).

Existen 2 tipos de arreglos según su dimensión: unidimensional, porque para acceder

a un elemento del arreglo sólo se tiene que utilizar un índice, y multidimensional, porque

para acceder a un elemento del arreglo se utilizan múltiples índices. Para este último tipo de

arreglo, el más utilizado es el bidimensional, es decir, el de dos dimensiones, por ello, a

continuación se describen tanto el arreglo unidimensional como el bidimensional.

11.1 Arreglos unidimensionales

El arreglo unidimensional, conocido también como vector, es una colección finita,

homogénea y ordenada de datos, en la que se hace referencia a cada elemento del arreglo

por medio de un índice. Este último indica la casilla en la que se encuentra el elemento.

Para hacer referencia a un componente de un arreglo se deben utilizar tanto el nombre del

arreglo como el índice del elemento (Cairó Battistutti, 2006). En la figura 18 se puede

observar la representación gráfica de un arreglo unidimensional.

Figura 18. Representación gráfica de un arreglo unidimensional.

Adaptado de Cairó Battistutti (2006, p. 177).

En el lenguaje C, el arreglo unidimensional se declara de la siguiente manera:

tipo nombre[tamaño]

Page 68: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

67

donde:

tipo es uno de los tipos predefinidos por el lenguaje: float, int, etc.

nombre: es un identificador que nombra el arreglo y sigue las mismas reglas

especificadas para dar nombre al identificador de una variable.

tamaño es una constante entera positiva que especifica el número de elementos del

arreglo.

En el lenguaje C, los arreglos unidimensionales inician en la posición cero [0], por lo

que la posición máxima del arreglo está dada por el número máximo de elementos menos

1.

También, el lenguaje C no revisa los límites del arreglo unidimensional, por lo que es

responsabilidad del programador el realizar este tipo de operación para no acceder a una

posición negativa o mayor al límite de elementos.

Los elementos de un arreglo pueden ser inicializados en la declaración del arreglo

mismo, para ello, se coloca el signo igual después de la declaración y una lista de valores

inicializadores separados por comas, dicha lista encerrada entre llaves.

De Cairó Battistutti (2006) se pueden analizar los siguientes ejemplos sobre

declaración e inicialización de arreglos unidimensionales:

/*Declara un arreglo unidimensional llamado arreglo para

almacenar 10 elementos de tipo real o flotante de doble

precisión.*/

double arreglo[10];

/*Se declara el arreglo unidimensional llamado V con 10

elementos de tipo real y al mismo tiempo se inicializa cada

casilla del arreglo con cada uno de los valores que se

encuentran entre llaves y separados por comas. La

representación gráfica del arreglo V se muestra en la figura

19.*/

float V[10] = {32.5,15.8, 70.1, 5.9, 0, -12.2, 13.3, 90.4,

56.6, -9.8};

Figura 19. Representación gráfica del vector V con 10 elementos de tipo real.

Page 69: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

68

Si se quiere acceder al primer elemento del arreglo se debe escribir V[0], pero si se quiere

acceder al quinto elemento se debe escribir V[4]. Por otra parte, el valor de V[7] es 90.4, el

de V[3+5] es 56.6 y el resultado de V[2] + V[5] es 57.9.

/*Lo siguiente muestra un error de sintaxis porque se están

proporcionando más inicializadores de arreglo que elementos

existen dentro del mismo.*/

double Valores[5] = {32.1,27.3,64.4,18.6,95.7,14};

/*Si en la lista de inicialización se omite el tamaño del

arreglo, el número de elementos en el arreglo será el número

de elementos incluidos en la lista inicializadora.*/

int n[ ] = {1,2,3,4,5};

/*Si dentro del arreglo existe un número menor de

inicializadores que de elementos, los elementos restantes son

inicializados a cero automáticamente.*/

int A1[10] = {0};

/*El primer componente del arreglo se inicializa con el

número 5 y el resto con el número 0.*/

int B[5] = {5};

Una vez que se definen los arreglos, sus elementos pueden recibir valores a través de

múltiples asignaciones, o bien, como ocurre frecuentemente en la práctica, a través de un

ciclo, este último, generalmente un ciclo para o for, pues se conoce previamente la cantidad

de elementos que contiene el arreglo.

/*Ejemplo de asignación individual después de haber declarado

un arreglo. El primer valor del arreglo vale 23.897*/

arreglo[0]=23.897

Si las posiciones de un arreglo no son inicializados o no se les asigna explícitamente un

valor, se considera que almacenan “basura”, pues en memoria siempre existen datos. No se

debe olvidar almacenar datos en un arreglo antes de realizar operaciones con ellos, tal

como sucede con las variables.

Se pueden realizar distintas operaciones con arreglos unidimensionales durante el

proceso de resolución de un problema, pero generalmente se tiene:

Asignación

Lectura/escritura

Page 70: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

69

Recorrido (acceso secuencial)

Actualizar (añadir, borrar, insertar)

Ordenación

Búsqueda

Puesto que en un arreglo se trabaja más de un dato, generalmente las operaciones antes

listadas se tienen que realizar usando ciclos como se mencionó con la inicialización.

11.2 Arreglos bidimensionales

El arreglo bidimensional se considera un vector de vectores, generalmente llamado

tabla (término financiero) o matriz. Formalmente es una colección finita, homogénea y

ordenada de datos, en la que se hace referencia a cada elemento del arreglo por medio de

dos índices, uno para indicar el renglón o fila y el segundo para indicar la columna del

arreglo (Cairó Battistutti, 2006). La figura 20 muestra la representación gráfica de un

arreglo bidimensional.

Figura 20. Representación gráfica de un arreglo bidimensional .

Adaptado de Cairó Battistutti (2006, p.214).

En el lenguaje C, la declaración de esta estructura es de la siguiente manera:

tipo nombre[num_renglones][num_columnas]

donde:

tipo es uno de los tipos predefinidos por el lenguaje: float, int, etc.

Page 71: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

70

nombre: es un identificador que nombra el arreglo y sigue las mismas reglas

especificadas para dar nombre al identificador de una variable.

num_renglones es una constante entera positiva que especifica el número de filas del

arreglo.

num_columnas es una constante entera positiva que especifica el número de columnas

del arreglo.

En C, los arreglos bidimensionales inician en las posiciones [0][0], por lo que la

posición máxima del arreglo está dada por el número máximo de renglones menos 1 con el número máximo de columnas menos 1. Suponiendo que se tienen N renglones y M

columnas, entonces la posición máxima está en [N-1][M-1], además, se almacenarán N x

M elementos del mismo tipo.

El lenguaje C no revisa los límites de un arreglo, es responsabilidad del

programador el realizar este tipo de operaciones para no acceder a una posición negativa o

mayor al límite de elementos tanto para los renglones como para las columnas.

Ejemplos de declaración e inicialización de arreglos bidimensionales (Cairó Battistutti,

2006):

/*Declara un arreglo bidimensional tipo entero llamado M con

3 filas y 4 columnas*/

int M[3][4];

/*Declara un arreglo bidimensional llamado matriz de 4

renglones y 4 columnas, y un arreglo unidimensional llamado

b5 con 100 elementos, ambos arreglos tipo real o flotante*/

float matriz[4][4], b5[100];

/* Se almacena el valor 10 en el primer renglón y primera

columna de M*/

M[0][0]=10;

/* Se almacena el valor 3.14 en el tercer renglón y tercera

columna de matriz*/

matriz[2][2]=3.14;

/*Todos los elementos del arreglo se inicializan con cero

porque la cantidad de valores asignados es menor que la

dimensión del arreglo bidimensional.*/

int A[3][6] = {0};

Page 72: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

71

/*O bien:*/

int A[3][6] = {{0}};

/*Los primeros cuatro componentes de la primera fila se

inicializan con los valores; 3, 4, 6 y 8. El resto con

cero.*/

int B[3][6] = {3,4,6,8};

/*O bien:*/

int B[3][6] ={ {3,4,6,8}};

/*Cada componente del arreglo recibe un valor. La asignación

se realiza fila a fila.*/

int C[3][6] = {6, 23, 8, 4, 11, 33, 21, 0, 6, 10, 23, 4, 8,

2, 1, 6, 9, 15};

/*La asignación anterior también se puede realizar de esta

forma. La representación gráfica del arreglo bidimensional C

se muestra en la figura 21.*/

int C[3][6] = {{6, 23, 8, 4, 11, 33}, {21, 0, 6, 10, 23, 4},

{8, 2, 1, 6, 9, 15}};

/*Error de sintaxis ya que la fila tiene espacio para seis

elementos y se asignan siete.*/

int C[3][6] = {{6, 23, 8, 4, 11, 35, 8}};

Si las posiciones de un arreglo no son inicializados o no se les asigna explícitamente un

valor, se considera que almacenan “basura”, pues en memoria siempre existen datos. No se

debe olvidar almacenar datos en un arreglo bidimensional antes de realizar

operaciones con ellos, tal como sucede con las variables.

Algunas de las operaciones que se realizan con arreglos bidimensionales son

asignación, lectura/escritura, y aquellas propias para matrices matemáticas, por ejemplo:

suma, multiplicación, inversa, etc., por lo que, el acceso a las posiciones de la tabla o matriz

se realiza normalmente utilizando ciclos anidados, pues para una matriz de m por n, donde

m es el número de renglones y n el número de columnas, generalmente se requiere recorrer

n columnas por cada renglón que constituye a la matriz, es decir, recorrer n columnas m

veces.

Finalmente, el máximo de dimensiones que puede tener un arreglo multidimensional

de más de dos dimensiones, queda determinado por el lenguaje de programación que se

utilice o por el espacio en memoria, por lo que la cantidad de índices que se utilizan para

acceder a sus valores, depende de la dimensión del arreglo.

Page 73: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

72

En en el lenguaje C se declaran de la siguiente manera y como máximo se tienen hasta

12 subíndices de arreglo:

tipo nombre[tamao1][tamaño2]…[tamaño_n]

Figura 21. Representación gráfica del arreglo bidimensional C con 3x6 elementos de tipo entero.

Adaptado de Cairó Battistutti (2006, p.215).

NOTA IMPORTANTE: los corchetes, utilizados para cerrar el subíndice de un

arreglo de cualquier dimensión, son considerados como operadores y tienen el mismo nivel

de precedencia que los paréntesis (el orden de precedencia se revisó en el apartado Tabla de

prioridad y orden de evaluación de la sección 6: Lenguaje C).

12 CARACTERES, CADENAS DE CARACTERES Y ARREGLOS DE

CARACTERES

12.1 Caracteres

Los lenguajes de programación utilizan juegos de caracteres llamados alfabetos para

comunicarse con las computadoras. Las primeras computadoras sólo utilizaban información

numérica digital mediante el código o alfabeto digital y los primeros programas se

escribieron en ese tipo de código denominado código máquina, basado en los dígitos 0 y 1

(como se mencionó en la sección 1: Preliminares, conceptos básicos) por ser inteligible

directamente por la computadora. La difícil tarea de programar en código máquina hizo que

el alfabeto evolucionara y los lenguajes de programación comenzaran a utilizar códigos o

Page 74: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

73

juegos de caracteres similares a los utilizados en los lenguajes humanos. Así, hasta el día de

hoy, la mayoría de las computadoras trabajan con diferentes tipos de juegos de caracteres,

de los cuales destacan el código ASCII por American Standard Code for Information

Interchange y el EBCDIC por Extended Binary Coded Decimal Interchange Code (Deitel y

Deitel, 1995).

El código ASCII básico utiliza 7 bits para cada caracter a representar (el concepto de

bit se dio en la sección 1: Preliminares y conceptos básicos) lo que da un total de 27 = 128

caracteres distintos. El código ASCII ampliado utiliza 8 bits, y en este caso, consta de 28 =

256 caracteres. Este código ASCII adquirió una gran popularidad ya que es el estándar en

todas las familias de computadoras personales y se presenta en la tablas 17 y 18 (Deitel y

Deitel, 1995). Independientemente del sistema operativo que se esté utilizando, los

primeros 128 caracteres, es decir el ASCII básico va a utilizar un código y ese código no va

a cambiar para representar al mismo caracter, pero los otros 128 caracteres pueden utilizar

un valor diferente para representar a un carácter, por ejemplo, la letra ñ se considera un

carácter especial por estar conformado por dos partes: la n y el símbolo ~, así, si se utiliza

Windows, la letra ñ se representa con el código 164 si se utilizan variables unsigned char, y

con el código -92 si se utilizan variables signed char; pero en GNU/Linux la ñ se representa

con el código 241 si se utilizan variables unsigned char y el código -15 si se utilizan

variables signed char.

En general, un caracter ocupará un byte (o sea 8 bits) de almacenamiento de memoria y

se puede definir como un símbolo del juego de caracteres de la computadora.

Deitel y Deitel (1995) indican que el código ASCII se compone de los siguientes tipos

de caracteres:

Alfabéticos (a…z A…Z)

Numéricos (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

Especiales (+, -, *, /, {, }, <, etc.)

De control: son caracteres no imprimibles que realizan una serie de funciones

relacionadas con la escritura, transmisión de datos, separador de archivos, etc., en

realidad con los dispositivos de entrada/salida. Destacan entre ellos: del (eliminar o

borrar), cr (retorno de carro), lf (avance de línea), ff (avance de página), stx (inicio

de texto), etc.

Tabla 17. Código ASCII de caracteres de control.

Adaptado de “ASCII” (2016).

Binario Dec. Hex. Abreviatura Representación Nombre/significado

0000 0000 0 00 NUL ^@ Caracter nulo 0000 0001 1 01 SOH ^A Inicio de encabezado

0000 0010 2 02 STX ^B Inicio de texto

0000 0011 3 03 ETX ^C Fin de texto 0000 0100 4 04 EOT ^D Fin de transmisión

0000 0101 5 05 ENQ ^E Enquiry

Page 75: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

74

0000 0110 6 06 ACK ^F Acknowledgement 0000 0111 7 07 BEL ^G Timbre o pitido: “bip”

0000 1000 8 08 BS ^H Retroceso 0000 1001 9 09 HT ^I Tabulación horizontal

0000 1010 10 0A LF ^J Avance de línea 0000 1011 11 0B VT ^K Tabulación vertical

0000 1100 12 0C FF ^L Avance de página

0000 1101 13 0D CR ^M Retorno de carro 0000 1110 14 0E SO ^N Shift Out

0000 1111 15 0F SI ^O Shift In 0001 0000 16 10 DLE ^P Data Link Escape

0001 0001 17 11 DC1 ^Q Control de dispositivo 1

XON

0001 0010 18 12 DC2 ^R Control de dispositivo 2 0001 0011 19 13 DC3 ^S Control de dispositivo

XOFF 0001 0100 20 14 DC4 ^T Control de dispositivo 4

0001 0101 21 15 NAK ^U Negative

Acknowledgement

0001 0110 22 16 SYN ^V Synchronous Idle

0001 0111 23 17 ETB ^W Fin de transmisión de

bloque

0001 1000 24 18 CAN ^X Cancelar 0001 1001 25 19 EM ^Y End of Medium

0001 1010 26 1A SUB ^Z Substitute 0001 1011 27 1B ESC ^[ or ESC Escape

0001 1100 28 1C FS ^\ Separador de archivo 0001 1101 29 1D GS ^] Separador de grupo

0001 1110 30 1E RS ^^ Separador de registro

0001 1111 31 1F US ^_ Separador de unidad 0111 1111 127 7F DEL ^?,

Delete, o

Backspace

Borrado o retroceso

Tabla 18. Código ASCII de caracteres alfabéticos, numéricos y especiales.

Adaptado de “ASCII” (2016).

Binario Dec. Hex. Representación Binario Dec. Hex. Representación 0010

0000

32 20 espacio ( ) 0101

0000

80 50 P

0010

0001

33 21 ! 0101

0001

81 51 Q

0010

0010

34 22 " 0101

0010

82 52 R

0010

0011

35 23 # 0101

0011

83 53 S

0010

0100

36 24 $ 0101

0100

84 54 T

0010

0101

37 25 % 0101

0101

85 55 U

Page 76: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

75

0010

0110

38 26 & 0101

0110

86 56 V

0010

0111

39 27 ' 0101

0111

87 57 W

0010

1000

40 28 ( 0101

1000

88 58 X

0010

1001

41 29 ) 0101

1001

89 59 Y

0010

1010

42 2A * 0101

1010

90 5A Z

0010

1011

43 2B + 0101

1011

91 5B [

0010

1100

44 2C , 0101

1100

92 5C \

0010

1101

45 2D - 0101

1101

93 5D ]

0010

1110

46 2E . 0101

1110

94 5E ^

0010

1111

47 2F / 0101

1111

95 5F _

0011

0000

48 30 0 0110

0000

96 60 `

0011

0001

49 31 1 0110

0001

97 61 a

0011

0010

50 32 2 0110

0010

98 62 b

0011

0011

51 33 3 0110

0011

99 63 c

0011

0100

52 34 4 0110

0100

100 64 d

0011

0101

53 35 5 0110

0101

101 65 e

0011

0110

54 36 6 0110

0110

102 66 f

0011

0111

55 37 7 0110

0111

103 67 g

0011

1000

56 38 8 0110

1000

104 68 h

0011

1001

57 39 9 0110

1001

105 69 i

0011

1010

58 3A : 0110

1010

106 6A j

0011

1011

59 3B ; 0110

1011

107 6B k

0011

1100

60 3C < 0110

1100

108 6C l

0011

1101

61 3D = 0110

1101

109 6D m

0011

1110

62 3E > 0110

1110

110 6E n

Page 77: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

76

0011

1111

63 3F ? 0110

1111

111 6F o

0100

0000

64 40 @ 0111

0000

112 70 p

0100

0001

65 41 A 0111

0001

113 71 q

0100

0010

66 42 B 0111

0010

114 72 r

0100

0011

67 43 C 0111

0011

115 73 s

0100

0100

68 44 D 0111

0100

116 74 t

0100

0101

69 45 E 0111

0101

117 75 u

0100

0110

70 46 F 0111

0110

118 76 v

0100

0111

71 47 G 0111

0111

119 77 w

0100

1000

72 48 H 0111

1000

120 78 x

0100

1001

73 49 I 0111

1001

121 79 y

0100

1010

74 4A J 0111

1010

122 7A z

0100

1011

75 4B K 0111

1011

123 7B {

0100

1100

76 4C L 0111

1100

124 7C |

0100

1101

77 4D M 0111

1101

125 7D }

0100

1110

78 4E N 0111

1110

126 7E ~

0100

1111

79 4F O 0111

1111

127 7F

Una constante caracter se define como cualquier caracter encerrado entre apóstrofos

o comilla sencilla, específicamente en el lenguaje C se usa la comilla sencilla. Para ingresar

o mostrar tipos de datos caracter en el leguaje C se usan las instrucciones vistas en la

sección 7: Instrucciones de entrada y salida, las cuales pueden ser: scanf, printf, putchat o

getchar (getch o getche para windows).

Cairó Battistutti (2006) menciona las operaciones que se realizan generalmente con

caracteres:

Verificar si un caracter es o no es un dígito.

Verificar si un caracter es o no es una letra

Verificar si un caracter es una letra minúscula o mayúscula

Convertir una letra a minúscula o mayúscula

Page 78: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

77

Para realizar lo anterior, en el lenguaje C existen como parte de la biblioteca ctype.h,

las siguientes funciones: isdigit( ), isalpha( ), islower( ), isupper(

), isspace( ), tolower( ) y toupper( ). Todas reciben como argumento

el valor que se quiere verificar o convertir (Cairó Battistutti, 2006).

12.2 Cadenas de caracteres

Una cadena se define como una secuencia finita de caracteres que finaliza con el

caracter nulo ‘\0’ y se almacena en un área contigua de la memoria. Una constante tipo

cadena consiste en una cadena encerrada entre apóstrofos, comillas sencillas o dobles

comillas, específicamente en el lenguaje C, se encierra la cadena usando el caracter de

doble comilla, la cual no se puede modificar.

Las cadenas se pueden usar en aplicaciones de gestión, generación y actualización de

listas de dirección, inventarios, bases de datos, traductores de lenguajes, etc.

Según Deitel y Deitel (1995) las operaciones comunes que se realizan con cadenas de

caracteres son las siguientes:

Cálculo de longitud de la cadena (número de caracteres que contiene la cadena,

incluyendo el espacio en blanco, sin incluir el caracter nulo. La cadena que no

contiene ningún carácter se denomina cadena vacía o nula y su longitud es cero).

Comparación de cadenas (saber si dos cadenas con iguales o diferentes).

Concatenación de cadenas (unir cadenas para formar nuevas cadenas).

Extracción de subcadenas (extraer una porción de una cadena a la cual se le da el

nombre de subcadena).

Búsqueda de información en una cadena (búsqueda de ciertos caracteres, frases,

etc.).

Insertar subcadenas (agregar nuevas cadenas a cadenas ya formadas).

Borrar cadenas (eliminar cierta cantidad de caracteres a partir de una posición, es

decir, borrar subcadenas).

Cambiar una cadena o subcadena por otra subcadena o cadena.

Convertir cadenas en números y viceversa.

Para ingresar o mostrar en un dispositivo de salida tipos de datos cadena en el lenguaje

C, se usan las instrucciones vistas en la sección 7: Instrucciones de entrada y salida, éstas

son: scanf y printf. Así como las que describen en los ejemplos siguientes: puts, gets y

fgets.

Page 79: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

78

char nombre[15];

/* Declara un arreglo para 15 caracteres. Si no se especifica

el caracter nulo al final de la inicialización, lectura o

asignación del arreglo, entonces, nombre es un simple arreglo

de caracteres, mas no una cadena, pero, si en la

inicialización, lectura o asignación de nombre se le coloca

el caracter nulo al final de todos los caracteres que

contenga, entonces no es un simple arreglo de caracteres,

sino una cadena. En resumen, la diferencia entre un arreglo

de caracteres y una cadena es la existencia del caracter

nulo. Si nombre debe ser una cadena, entonces puede almacenar

como máxima 14 caracteres, pues además contendrá el caracter

nulo.*/

char cadena[ ] = {‘p’,’r’,’i’,’m’,’e’,’r’,’o’,’\0’};

/* Se declara la cadena llamada cadena y se inicializa

caracter a caracter terminando con el caracter nulo. La

variable cadena contendrá la palabra “primero”, la cual

contiene 7 caracteres, pues en el conteo no se suma el

caracter nulo. El arreglo cadena se ajusta a un tamaño de 8

elementos en memoria, pues el caracter nulo ocupa un espacio

en memoria.*/

char frase[ ] = “El perro ladra sin parar.”;

/* Se declara la cadena llamada frase que contiene una

longitud de 25 caracteres, pero en memoria existen 26

asignaciones porque se agrega en automático el caracter nulo

a los caracteres.*/

#define SALUDO “Un saludo afectuoso”

/* Se declara una constante llamada SALUDO que contiene la

frase “Un saludo afectuoso”, es decir, la longitud de la

cadena es de 19 caracteres, mientras que en memoria se

almacenan 20 porque cuando no se inicializa caracter a

caracter sino como cadena (usando las comillas dobles)

automáticamente se agrega el caracter nulo.*/

Como se especificó en la sección 7: Instrucciones de Entrada y Salida (E/S), existe el

parámetro %s para mandar a pantalla variables o constantes de tipo cadena y para ingresar

desde el teclado cadenas que se almacenarán en variables de tipo cadena, por ejemplo:

printf(“%s”, “Un afectuoso saludo”);

Page 80: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

79

/*Imprime la cadena “Un afectuoso saludo”*/

printf(“%s”, SALUDO);

/*Imprime el valor de la constante tipo cadena, llamada

SALUDO*/

printf(“%s”, cadena);

/*Imprime el valor de la variable cadena que contiene la

palabra “primero”*/

puts(frase);

/* Imprime lo que contiene la variable frase: “El perro ladra

sin parar.” La instrucción puts no necesita que se le indique

el tipo de dato que está enviando a pantalla como con printf

y es la más apropiada para escribir cadenas de caracteres.

Esta función baja automáticamente una línea después de

imprimir. (Cairó Battistutti, 2006)*/

scanf(“%s”, nombre);

/* En la variable nombre se almacenarán los caracteres que se

ingresen desde el teclado. Cuando se da un valor a una

variable desde el teclado, no es necesario teclear el

caracter nulo, éste se asigna automáticamente después de

pulsar la tecla enter. El problema con esta forma de ingresar

datos, es que el carácter espacio en blanco no se almacenará

en la variable, de hecho, si se escriben caracteres después

de un espacio en blanco, todos ellos no se almacenarán.*/

gets(cadena);

/* Otra forma de ingresar caracteres desde teclado y a

diferencia del ejemplo anterior, si se ingresan caracteres en

blanco, éstos serán también almacenados en la variable (Cairó

Battistutti, 2006). Sin embargo, no se recomienda utilizar

esta función por presentar problemas de seguridad, ya que si

se teclea una cadena con más caracteres de los que se pueden

almacenar, entonces intentará acceder a porciones de memoria

no permitidas provocando posibles errores en el programa o en

el sistema operativo en general. Se recomienda utilizar scanf

o fgets.*/

Page 81: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

80

fgets(cadena,máximo_de_caracteres,dispositivo_estándar_de_ent

rada);

Concretamente:

fgets(cadena,50,stdin);

/* La función que reemplaza a gets es fgets, esta función

permite almacenar los caracteres tecleados en el arreglo

cadena (también almacena los espacios en blanco), máximo

almacenará lo que se indique como segundo parámetro, en este

ejemplo sólo 50 caracteres y no más, pero además, se debe

contemplar que almacena el carácter enter y automáticamente

el carácter de fin de cadena. El tercer parámetro le indica

al programa que los caracteres se van a ingresar desde el

teclado, pues pudieran leerse los caracteres desde un archivo

o algún otro medio.*/

scanf(“%[^\n]”, frase);

/* En frase se almacenarán todos los caracteres que se

ingresen desde el teclado incluyendo el carácter de espacio

en blanco. El ingresar caracteres termina cuando se pulsa la

tecla enter, sin que este carácter se almacene en memoria, al

igual que la lectura con el tipo de dato %s, se agrega

automáticamente a la cadena el caracter nulo. En realidad la

traducción a lo que está entre corchetes es: almacenas todo

lo ingresado menos el caracter enter.*/

En el lenguaje C ya existen varias funciones para manipular cadenas. Dichas funciones

forman parte de la biblioteca string.h. Algunos ejemplos son:

strlen, para obtener la cantidad de caracteres que tiene una cadena.

strcmp, para comparar dos cadenas y saber si son iguales o no.

strcpy, para copiar el contenido de una cadena a otra cadena.

strrev, invertir los caracteres de una cadena (disponible sólo para windows).

strupr, para convertir los caracteres de una cadena a mayúsculas.

strlwr, para convertir los caracteres de una cadena a minúsculas.

12.3 Arreglos de caracteres

Un arreglo unidimensional de caracteres se define como una colección finita,

homogénea y ordenada de datos, en que se hace referencia a cada elemento del arreglo por

medio de un índice y no necesariamente finaliza con el caracter nulo (Cairó Battistutti,

Page 82: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

81

2006). Como se mencionó anteriormente, la diferencia sustancial entre una cadena y un

arreglo de caracteres es la existencia al final de la cadena del carácter nulo.

Por otra parte, se pueden utilizar arreglos bidimensionales de caracteres para manejar

conjuntos de cadenas, esto es, dado que una cadena se define como un arreglo

unidimensional que termina con el caracter nulo, entonces, si se desea almacenar cadenas

de caracteres en arreglos bidimensionales, cada fila almacenaría una cadena y cada

columna almacenaría los caracteres correspondientes de cada cadena (Cairó Battistutti,

2006). Por ejemplo, si se desea almacenar un grupo de 5 cadenas de caracteres con 30

caracteres como máximo para cada cadena, entonces se podría hacer una declaración como

la siguiente en el lenguaje C:

char cadenas[5][31];

/*El segundo valor es 31 porque se tiene que considerar el

almacenar el caracter nulo*/

Así, el primer índice se utilizaría para hacer referencia a la fila, es decir a cada cadena; y el

segundo índice serviría para señalar el caracter de cada cadena.

13 FUNCIONES

Como se mencionó en el apartado Diseño de un algoritmo de la sección 5: Proceso de

resolución de problemas utilizando un lenguaje de programación, la resolución de un

problema complejo se facilita si dicho problema se divide en problemas más pequeños, es

decir, si se divide en subproblemas, los cuales son tratados de forma individual e

independiente, diseñando así subalgoritmos que se convierten en subprogramas

(Bermúdez et al., 2003). Los subprogramas que se forman con éste método pueden ser de

dos tipos: funciones o procedimientos, estos últimos también conocidos como subrutinas.

Los subprogramas están diseñados para ejecutar alguna tarea específica, se escriben

solamente una vez, pero pueden utilizarse en diferentes puntos de un programa, de manera

que se puede evitar la duplicación innecesaria de código.

Los subprogramas o módulos se escriben sin entrar en detalles con otros módulos

facilitando así la localización de errores.

Un subprograma puede realizar las mismas acciones que un programa: leer datos desde

dispositivos de entrada, hacer asignaciones, realizar cálculos, devolver resultados a través

de un dispositivo de salida, etc., pero en general se utiliza para un propósito específico. El

subprograma recibe datos desde el programa principal o desde cualquier subprograma que

lo llama, procesa dichos datos y si es necesario, devuelve resultados al programa o

subprograma que lo haya llamado.

Page 83: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

82

El enfoque en estos apuntes será sobre los subprogramas llamados funciones, que son

los únicos que existen en el lenguaje C, de hecho todo en el lenguaje C son funciones.

Función

Matemáticamente hablando una función es una regla que asocia a cada elemento de un

cierto conjunto A (llamado dominio de la función) un único elemento de un conjunto B

(conocido como codominio o contradominio de la función), sin embargo,

computacionalmente hablando, una función es una colección de sentencias o instrucciones

que ejecuta una tarea específica, que puede o no recibir valores, llamados parámetros, y no

puede contener a otra función. Para utilizar funciones en un programa es necesario

declararlas previamente.

Todos los lenguajes de programación tienen funciones incorporadas o internas que se

utilizan escribiendo sus nombres con los argumentos adecuados entre paréntesis, (como las

funciones matemáticas del lenguaje C: sqrt, pow, sin, etc.) y funciones definidas por el

usuario o programador, es decir, escritas por él mismo.

Las funciones incorporadas al sistema se denominan funciones internas o intrínsecas

y las funciones definidas por el usuario, funciones externas o extrínsecas. Cuando las

funciones estándares o internas no permiten realizar el tipo de cálculo deseado es necesario

recurrir a las funciones externas.

Una vez que una función ha sido escrita y depurada puede utilizarse una y otra vez.

Cuando una función se manda a llamar, el control se pasa a dicha función para su ejecución

y cuando ésta finaliza, el control es devuelto al módulo que la llamó para continuar con la

ejecución del mismo después de donde se efectuó la llamada, como se muestra en la figura

22 (Bermúdez et al., 2003). En ese ejemplo, dentro de la función principal del lenguaje C, o

sea, la función main se hace el llamado a la función denominada func1, por lo que la

secuencia de ejecución se pasa a dicha función, realizándose una a una las instrucciones

dentro de func1, pero al llegar al llamado de func2, nuevamente la secuencia de la ejecución

se desvía hacia la función func2. Se ejecutan las instrucciones que existan dentro de la

función func2 hasta alcanzar el return, con lo cual se regresa el control a func1 para

continuar con la ejecución de las instrucciones que contenga hasta llegar al return de func1,

para regresar el control a la función principal main. Como nuevamente se hace el llamado a

la función func1, se vuelve a realizar el proceso descrito hasta regresar a la función

principal main para ejecutarse todas las siguientes instrucciones que contenga main hasta

llegar al final del programa, en conclusión, como se muestra en la figura 22, el orden de

ejecución es conforme la numeración del 1 al 8.

13.1 Funciones definidas por el usuario en el lenguaje C

Todo programa en C consta al menos de la función main( ), que es donde inicia la

ejecución de un programa (como se mencionó en la sección 6: Lenguaje C, apartado

Page 84: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

83

Estructura de un programa). También puede constar de otras funciones que ya ofrece el

lenguaje y de aquellas que diseña el programador.

Las funciones que declara el usuario pueden aparecer en cualquier orden y en uno o varios

archivos fuente, conformándose de un encabezado y un cuerpo. De manera explícita se puede decir

que, es un bloque o una proposición compuesta. La estructura básica de la definición de una función

es la siguiente:

tipo_de_retorno nombre (parámetros formales)

{

declaraciones;

proposiciones;

return (expresión);

}

a) Encabezado de una función

tipo_de_retorno indica el tipo del valor devuelto por la función. Puede ser cualquier tipo

básico, estructura o unión. Por defecto es del tipo int. Cuando no se requiere que devuelva

algún valor se usará el tipo void.

nombre es un identificador que indica el nombre de la función. Sigue las mismas reglas que

se tienen para nombrar una variable.

Figura 22. Ejemplo del llamado de una función en el lenguaje C.

Adaptado de Ceballos (1997, p. 251).

Parámetros formales es una secuencia de declaraciones separadas por coma. Cada

parámetro, es decir, variable o arreglo, debe ir con el tipo de dato correspondiente. Si no se

pasan argumentos a la función se puede utilizar la palabra reservada void. Generalmente se

Page 85: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

84

usa la palabra parámetro formal para una variable nombrada en la lista entre paréntesis de

la definición de función, y argumento o parámetro actual para el valor empleado al hacer

la llamada de la función.

b) Cuerpo de la función

Está formado por una sentencia compuesta que contiene sentencias que definen lo que

hace la función. Las declaraciones de variables utilizadas en la función por defecto son

locales a la función, es decir, sólo son definidas, vistas y válidas dentro de la función donde

son empleadas, pero fuera de dicha función, no son conocidas y no tienen valor.

return (expresión) se utiliza para devolver el valor de la función, el cual debe ser del

mismo tipo declarado en el encabezado de la función. Si la sentencia return no se especifica

o se especifica sin contener una expresión, la función no devuelve un valor. Cuando

explícitamente se devuelve un valor, éste puede ir o no entre paréntesis, es decir, los

paréntesis son opcionales. La instrucción return puede ser o no la última que aparezca en el

cuerpo de la función y puede aparecer más de una vez, dependiendo del problema que se

esté resolviendo. En el caso de que la función no retorne algún valor, la instrucción se

puede omitir.

c) Llamado de una función

Para ejecutar una función hay que llamarla. La llamada a una función se hace mediante

su nombre con los argumentos o parámetros actuales o reales entre paréntesis.

Generalmente se asigna el valor que regresa una función a una variable del mismo tipo de

ésta. Cuando se llama a una función, el valor del primer parámetro actual es pasado al

primer parámetro formal, el valor del segundo parámetro actual es pasado al segundo

parámetro formal y así sucesivamente. Todos los argumentos excepto los arreglos, son

pasados por valor. Esto es, a la función se pasa una copia del argumento, no su dirección

en memoria, esto hace que la función C no pueda alterar los contenidos de las variables

transmitidas. Si se desea poder alterar los contenidos de los argumentos en la llamada

entonces hay que pasarlos por referencia (método que se verá más adelante, en la sección

13.5).

Ejemplos: Ejemplo 1 Ejemplo 2

#include <stdio.h>

void letrero(void)

{

printf(“\n Esta es una función

muy simple”);

return;

}

#include <stdio.h>

void letrero2(int i)

{

if (i>0) printf(“\n i es

positivo”);

else printf(“\n i es

negativo”);

}

Page 86: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

85

int main( )

{

letrero( );

return 0;

}

int main( )

{

letrero2(10);

return 0;

}

Ejemplo 3

#include <stdio.h>

int suma(int a, int b)

{

int valor;

valor = a+b;

return (valor);

}

int main( )

{

int res;

int n1=23;

int n2=55;

res = suma(5,10) ;

printf( “La suma es: %d \n”, res);

res = suma(n1,n2);

printf(“La suma de %d + %d = %d

\n”, n1,n2,res);

printf(“La suma de -25 + -12 =

%d”,suma(-25,-12));

return 0;

}

13.2 Prototipo de funciones

Antes de usar o llamar a una función, el lenguaje C debe tener conocimiento del tipo de

dato que regresará y el o los tipos de los parámetros que la función espera recibir, por tanto,

esos valores los conoce el lenguaje cuando la función se declara y define, es decir, cuando

la función se programa antes de la función main, o en general, antes de su llamado en

cualquier parte del programa. Sin embargo, existen casos donde la función es llamada sin

ser declarada previamente o sin conocer el código que la conforma provocando errores de

compilación, por lo que, el lenguaje permite el uso de declaraciones forward (también

llamadas prototipos de funciones) o bien, genera automáticamente una declaración

prototipo implícita (Ceballos, 1997).

Un prototipo de función (también conocido como declaración forward) permite

conocer el nombre de la función, el tipo de resultado que devolverá, así como los tipos y

Page 87: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

86

nombres de los parámetros a recibir; todo ello antes de especificar el cuerpo de la función,

es decir, antes de haberla definido o programado9.

La importancia de usar prototipos de funciones o declaración explícita radica en que:

Se hace el código más estructurado y por lo tanto más fácil de leer.

Permite conocer las características de la función antes de ser utilizada.

Lo anterior aplica dependiendo del alcance de la función. Básicamente si una función

ha sido definida antes de que sea usada o llamada, entonces se puede usar la función sin

problemas.

9 Las funciones prototipo de las funciones pertenecientes a la biblioteca estándar del

lenguaje C son provistas por los ficheros de cabecera estándar: archivos .h, como se

mencionó en la sección 6: Lenguaje C.

Ejemplo adatado de Deitel y Deitel (1995, p. 156):

/*Encontrar el mayor de tres números reales*/

#include <stdio.h>

float maximo(float, float, float); /* Prototipo de la función

maximo */

int main( )

{

float a, b, c;

printf(“Ingrese los tres datos:”);

scanf(“%f%f%f”, &a, &b, &c);

printf(“El máximo es: %f\n”, maximo(a,b,c));

return 0;

}

float maximo (float x, float y, float z)

{

float max = x;

if (y > max) max = y;

if (z > max) max = z;

return max;

}

Page 88: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

87

El prototipo de la función maximo es: float maximo(float, float,

float);

Ese prototipo tiene la misma sintaxis que la primera línea de la definición de la función

(la que se encuentra después de la función main), excepto que termina con punto y coma y

no contiene los nombres de los parámetros: x, y, z, de hecho son opcionales en el prototipo

de una función, de modo que, para el prototipo se puede escribir también:

float maximo(float x, float y, float z);

Lo más común es omitir los identificadores para colocar sólo los tipos.

Es importante recalcar que si la definición de una función o cualquier uso que de ella se

haga no corresponden con su prototipo ocasionará un error.

Conversiones de tipo

En el prototipo de función, es importante que los argumentos coincidan con el tipo

apropiado, es decir, que haya coerción de argumentos. Por ejemplo, la función matemática

sqrt de la biblioteca estándar puede ser llamada con un argumento entero, aun cuando el

prototipo de la función en el archivo de cabecera math.h especifica un parámetro de tipo

double, sin que esto ocasione un error en el resultado. El prototipo de función hará que el

valor entero se convierta a double. (Deitel y Deitel, 1995).

En general, los valores de los argumentos que no correspondan precisamente a los

tipos de los parámetros del prototipo de función serán convertidos al tipo apropiado,

antes de que la función sea llamada. Estas conversiones pueden llevar a resultados

incorrectos si no son seguidas las reglas de promoción del leguaje C. Las reglas de

promoción definen cómo deben ser convertidos los tipos de datos a otros tipos de datos, sin

perder información. Por ejemplo, un tipo double convertido a entero truncará la parte

fraccional del valor double. Nuevamente, en general, convertir tipos enteros grandes a tipos

enteros pequeños puede dar domo resultado valores modificados (Deitel y Deitel, 1995).

Las reglas de promoción se aplican automáticamente a expresiones que contengan

valores de dos o más tipos distintos de datos (también conocidas como expresiones de tipo

mixto). El tipo de cada valor en una expresión de tipo mixto es automáticamente

promovido al tipo más alto en la expresión, es decir, se crea una versión temporal de cada

valor y se utiliza para la expresión conservándose sin cambios los valores originales (Deitel

y Deitel, 1995). Ceballos (1997) presenta las reglas de promoción que se aplican

automáticamente:

1. Si en una operación, el operador de precisión más alta es de tipo long double,

entonces, el otro operador es convertido a tipo long double.

2. Si en una operación, el operador de precisión más alta es de tipo double, entonces,

el otro operador es convertido a tipo double.

Page 89: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

88

3. Si en una operación, el operador de precisión más alta es de tipo float, entonces, el

otro operador es convertido a tipo float.

4. Si en una operación, el operador de precisión más alta es de tipo unsigned long int,

entonces, el otro operador es convertido a tipo unsigned long int.

5. Si en una operación, el operador de precisión más alta es de tipo long int, entonces,

el otro operador es convertido a tipo long int.

6. Si en una operación, el operador de precisión más alta es de tipo unsigned int,

entonces, el otro operador es convertido a tipo unsigned int.

7. Si en una operación, el operador de precisión más alta es de tipo int, entonces, el

otro operador es convertido a tipo int.

8. En una operación, cualquier operando de tipo short es convertido a tipo int.

9. En una operación, cualquier operando tipo char, es convertido a tipo int.

10. Cualquier operando de tipo unsigned short es convertido a tipo unsigned int.

11. Cualquier operando de tipo unsigned char es convertido a tipo unsigned int.

La conversión de valores a tipos inferiores por lo regular resulta en un valor incorrecto.

Por lo tanto, un valor puede ser convertido sólo a un valor inferior, asignando de manera

explícita el valor a una variable de tipo inferior o mediante el uso de un operador cast. Los

valores de los argumentos de las funciones son convertidos a los tipos de parámetro en un

prototipo de función, como si hubieran sido asignados directamente a las variables de esos

tipos, es decir, las conversiones son ejecutadas independientemente sobre cada argumento

en la llamada (Deitel y Deitel, 1995). En general, los reales son convertidos a enteros,

truncando la parte fraccionaria y un double pasa a float redondeando y perdiendo precisión

si el valor double no puede ser representado exactamente como float.

Ahora bien, el operador cast (casting) permite realizar una conversión forzada o

explícita con la siguiente sintaxis:

(nombre_de_tipo_de_dato) expresión

Lo anterior provoca la conversión del valor de la expresión al tipo nombrado entre

paréntesis, aplicando las reglas de conversión expuestas anteriormente.

Ejemplos:

float r;

int i;

r = i; /* i es convertido a float para ser asignado a r */

i = r; /*r es truncada para quedar como entero y ser

asignado a i */

i = 7/3; // i = 2

r = 7/3; // i = 2.000000

i = 12.6/3; // i = 4

r = 12.6/3; // i = 4.2

Page 90: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

89

Declaración de prototipo implícita

La declaración de prototipo implícita, la cual se mencionó al inicio de esta sección, se

da cuando la función es llamada sin existir una declaración previa de la misma y la

definición o código de la función se hace o se escribe después de la función principal main.

En este caso, el lenguaje C por defecto construye una función prototipo con tipo de

resultado int, pero no se supone nada en relación con los argumentos. Esto obliga entonces

a que el tipo del resultado en la definición de la función sea del tipo int y a que, si los

argumentos pasados a la función no son correctos, el compilador no los detecte (Ceballos,

1997).

En el siguiente ejemplo, la función escribir se declara implícitamente para retornar un

valor int, ya que se llama antes de su definición. El compilador crea automáticamente una

función prototipo utilizando la información de la llamada a la función.

#include <stdio.h>

int main( ) {

int r, b = 5 ;

r = escribir(b) ;

printf(“%d\n”, r);

return 0;

}

int escribir (int y){

return y * 3 ;

}

13.3 Paso de parámetros por valor y por referencia

En C existen dos tipos de parámetros en el llamado a una función: por valor o por

referencia.

Paso de parámetros por valor

Significa que la función que se invoca recibe los valores de sus argumentos en

variables temporales y no en las originales, por lo que la función no puede alterar

directamente una variable de la función que hace la llamada, sólo puede modificar su copia

privada y temporal. Significa también copiar los parámetros actuales en sus

correspondientes parámetros formales, operación que se hace automáticamente cuando se

llama a una función, con lo cual no se modifican los parámetros actuales. Con este método

pueden ser transferidas constantes, variables y expresiones.

Page 91: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

90

Paso de parámetros por referencia o dirección

Lo que se transfiere no son los valores sino las direcciones de las variables que

contienen esos valores, con lo cual los argumentos actuales de la función pueden verse

modificados. Una variable tiene una posición de memoria asignada (área de

almacenamiento o dirección) desde la cual se puede obtener o actualizar su valor, por tanto,

el paso de parámetros por referencia es útil cuando la función que llama requiere que la

función llamada modifique el valor de las variables que se pasan como argumentos. Lo

anterior se logra utilizando apuntadores (el tema de apuntadores no se trata ampliamente

en este documento, pues corresponde a la asignatura Programación II, sin embargo, se

menciona de forma básica y concisa, de tal manera que se pueda entender el paso de

parámetros por referencia).

Apuntadores

Una variable por lo regular almacena un valor específico, por su parte, un apuntador

almacena la dirección de una variable que contiene un valor específico. En este sentido, un

nombre de variable se refiere directamente a un valor y, un apuntador se refiere

indirectamente a un valor. El referirse a un valor a través de un apuntador se conoce como

indirección (Deitel y Deitel, 1995).

Los apuntadores, como cualquier otra variable, deben ser declarados antes de que

puedan usarse, lo cual se hace de la siguiente manera:

Tipo_de_dato *nombre_del_apuntador

donde:

Tipo_de_dato es cualquiera de los que existen en el lenguaje C

* es el símbolo obligatorio que se coloca antes del nombre del apuntador

Nombre_del_apuntador sigue las mismas reglas que los identificadores de variables

También, los apuntadores deben ser inicializados cuando son declarados en una

expresión de asignación, ya sea con el valor de la constante simbólica NULL, o bien, con

una dirección de memoria. Un apuntador con el valor NULL apunta a nada.

En la figura 23 se muestra un ejemplo gráfico de apuntadores. Los rectángulos

representan porciones de memoria; arriba de ellos se encuentran los identificadores de las

variables, es decir, los nombres con los que se reconocen esas porciones de memoria por

parte del programador, y los números debajo de los rectángulos son las posiciones reales de

memoria (en hexadecimal) que ocupan las variables. El contenido de cada rectángulo es el

valor que almacena cada variable. En la parte izquierda se tiene una representación gráfica

del apuntador aptValor “apuntando” a la variable valor, y en la parte derecha se muestra la

dirección real que almacena, la cual corresponde a la variable valor. Además, el apuntador

Page 92: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

91

aptSuma al haberse inicializado con el valor NULL, no apunta a alguna porción de

memoria como lo hace aptValor.

Como se observa en el ejemplo, con los apuntadores se hace uso del operador de

referencia & u operador de dirección (que como se ha visto antes, se usa con la

instrucción scanf), el cual regresa la dirección del operando que lo acompaña. Así, a la

variable aptValor se le asigna la dirección de memoria donde se encuentra la variable valor,

por lo que se suele decir que “aptValor apunta a la variable valor”. Por otro lado, el

operador de dirección no puede ser aplicado a constantes o expresiones.

Figura 23. Representación gráfica y en memoria de variables y apuntadores.

Otro operador que se usa con apuntadores es el *, conocido como el operador de

indirección o de desreferencia. Este operador lo que hace es devolver el valor al que

apunta (valga la redundancia) un apuntador. Retomando el ejemplo anterior, si se usara la

instrucción: printf(“%d”, *aptValor), se tendría en pantalla el valor 55.

NOTA: para mandar a pantalla el valor de las direcciones de memoria en hexadecimal

se puede utilizar la especificación de formato %p en la instrucción de salida printf

(revisar la tabla especificaciones de formato para printf de la sección 7: Instrucciones de

entrada y salida). Por ejemplo: printf(“%p-%p-%p”, &valor, aptValor,

&aptValor); tendría como salida: 0028FEE8-0028FEE8-0028FEEC.

Llamadas por referencia en una función

Cuando se llama a una función con argumentos que deban ser modificados, se pasan

las direcciones de los argumentos. Esto puede necesitarse cuando se requiere modificar una

o más variables de quien llama o cuando se requiere pasar un apuntador a un objeto de

datos grades, como una estructura de datos: arreglo, evitando así el hacer demasiadas

copias de los valores (Deitel y Deitel, 1995).

Por regla, cuando se llama a una función, los argumentos enviados en la llamada son

pasados por valor, a menos que se use el operador de dirección (&) a las variables cuyos

valores serán modificados, pues con ello, se estará especificando que los argumentos se

pasan por referencia. Los arreglos no se pasan con el operador & porque el lenguaje C pasa

Page 93: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

92

de forma automática la posición inicial en memoria del arreglo, de hecho, el nombre de un

arreglo es equivalente a escribir &nombre_arreglo[0] (Deitel y Deitel, 1995). En otras

palabras, los arreglos automáticamente se pasan por referencia escribiendo sólo su

nombre.

Cuando se pasa a una función la dirección de una variable, se puede utilizar el operador

de indireccion (*) dentro de la función para modificar el valor de esa posición de memoria,

es decir, para modificar el valor de la variable de quien llama.

Ejemplo adaptado de Ceballos (1997, p.268):

#include <stdio.h>

void sumar(int, int, int, int *);

/*Prototipo de la función sumar*/

int main( )

{

int v = 5, res = 0;

sumar(4, v, v*2-1, &res);

printf(“%d”,res);

return 0;

}

void sumar(int a, int b, int c, int *s)

{

b+=2;

*s = a + b + c;

}

La llamada a la función sumar pasa los parámetros 4, v, y v*2-1 por valor; el primero

es una constante, el segundo es una variable y el terceo una expresión aritmética; pero el

parámetro res es pasado por referencia. Cualquier cambio que sufra el argumento s, sucede

también en su correspondiente parámetro actual res. En cambio, la variable v no se ve

modificada, a pesar de haber variado b dentro de la función, ya que ha sido pasada por

valor. Aquí, la variable res dentro de main se inicia con el valor 0, pero al pasarse su

dirección de memoria, el apuntador s apunta a dicha variable; como dentro de la función

sumar, se usa el operador de indirección para modificar el valor al que apunta s, entonces el

valor de la variable res es cambiado por la suma de los valores que contienen las variables

a, b y c. Es decir, la salida a pantalla del valor que almacena res no será 0, sino 20.

Page 94: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

93

Por último, como se mencionó antes, en el prototipo de una función se pueden omitir

los nombres de los parámetros, por ello, en el prototipo de la función sumar, el apuntador

sólo se especifica con el tipo de dato al que apunta y el *, sin escribir el nombre s.

13.4 Reglas básicas de alcance o ámbito (scope)

El alcance o ámbito de un identificador es la porción del programa en el cual dicho

identificador puede ser referenciado. Por ejemplo, cuando en un bloque declaramos una

variable local, puede ser referenciada sólo en ese bloque o en los bloques anidados dentro

de él. Los tres alcances posibles para un identificador son: alcance de archivo, alcance de

bloque y alcance del prototipo de función.

Un identificador declarado por fuera de cualquier función tiene alcance de archivo. Tal

identificador es conocido en todas las funciones desde el punto donde el identificador se

declara hasta el final del archivo. Las variables globales, las definiciones de funciones y los

prototipos de función colocados fuera de una función tienen alcance de archivo (Deitel y

Deitel, 1995).

Los identificadores dentro de un bloque, tienen alcance llamado así, de bloque. Se

entiende por bloque lo que se encierra entre llaves. Las variables locales declaradas al

principio de una función tienen alcance de bloque como lo tienen los parámetros de

función, que son consideradas por la función como variables locales. Cualquier bloque

puede contener declaraciones de variables. Cuando los bloques están anidados y un

identificador de un bloque externo tiene el mismo nombre que un identificador de un

bloque interno, el identificador del bloque externo estará “oculto” hasta que el bloque

interno termine. Esto significa que, en tanto se ejecute el bloque interno, éste ve el valor de

su propio identificador local y no el valor del identificador de nombre idéntico del bloque

que lo contiene (Deitel y Deitel, 1995).

Los únicos identificadores con alcance de prototipo de función son los que se utilizan

en la lista de parámetros del prototipo de una función. Tal y como se mencionó, los

prototipos de función no requieren de nombres en la lista de parámetros, sólo requieren de

tipos. Si en la lista de parámetros de un prototipo de función se utiliza un nombre, el

compilador ignorará dicho nombre. Los identificadores utilizados en un prototipo de

función, pueden ser reutilizados en cualquier parte del programa, sin ambigüedad (Deitel y

Deitel, 1995).

Ejemplo:

{

int a = 5;

printf(“\n%d”, a);

{

int a = 7;

Page 95: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

94

printf(“\n%d”, a);

}

printf(“\n%d”, ++a);

}

Se ha declarado la misma variable dos veces, pero aunque tengan el mismo nombre son

variables distintas y por tanto, sus valores son distintos, en la segunda declaración de la

variable a, ésta se destruye cuando alcanza el fin del bloque de proposiciones (primera llave

cerrada), así, los valores que se verán impresos en pantalla son: 7 y 6.

13.5 Variables locales y variables globales

La regla de alcance es utilizada comúnmente para utilizar variables globales y locales.

Las variables globales se declaran al inicio del programa fuera del main y fuera de

cualquier función, en cambio las variables locales se declaran dentro de algún bloque. La

diferencia sustancial entre estos dos tipos de variables es el alance: las variables globales

pueden modificar su valor en cualquier parte del programa, mientras que las variables

locales sólo pueden ser usadas en el bloque donde fueron definidas.

Cada variable local de una función comienza a existir sólo cuando se llama a la función

y desaparece cuando la función termina. Debido a que las variables locales aparecen y

desaparecen con la invocación de funciones, no retienen sus valores entre dos llamadas

sucesivas y deben ser inicializadas explícitamente en cada entrada, de no hacerlo,

contendrán basura, es decir, cualquier dato que se halle en la localidad de memoria a la que

apunta.

Las variables globales (externas) existen permanentemente, en lugar de aparecer y

desaparecer cuando se llaman y terminan las funciones, mantienen sus valores aún después

de que se regresa del llamado a la función que les fijó algún valor.

Ejemplo:

#include <stdio.h>

int x = 20;

void escribe_x(void);

int main( )

{

int x = 12;

escribe_x ( );

Page 96: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

95

printf (“El valor de x (local) es= %d \n”, x);

return 0;

}

void escribe_x( )

{

printf(“El valor de x (global) es = %d \n”, x);

}

La salida será: 20, 12.

Una variable local a un subprograma no tiene significado en otros subprogramas. Si un

subprograma asigna un valor a una de sus variables locales, este valor no es accesible a

otros programas, es decir, no pueden utilizar ese valor. A veces, también es necesario que

una variable tenga el mismo nombre en diferentes subprogramas. Por el contrario, las

variables globales tienen la ventaja de compartir información de diferentes subprogramas

sin una correspondiente entrada en la lista de parámetros.

Las variables definidas en un ámbito son accesibles en el mismo, es decir, en todos los

procedimientos interiores. La figura 24 presenta un ejemplo de declaración de variables en

distintos bloques de código y con ello, especifica desde dónde son válidas o accesibles

dichas variables.

Figura 24. Ejemplo de alcance de una variable en el lenguaje C.

Adaptado de Joyanes Aguilar (2008, p. 214).

Variables definidas

en

Accesibles desde

A A, B, C, D, E, F, G

B B, C

C C

D D, E, F, G

E E, F, G

F F

G G

Page 97: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

96

14 ANEXOS

14.1 Prácticas sanas de programación

Deitel y Deitel (1995) al final de cada capítulo de su obra detallan prácticas sanas de

programación, es decir aquello que se debe y no se debe hacer a la hora de programar, aquí

se rescatan algunas de dichas prácticas por temas abarcados en la materia.

Sobre estructuras secuenciales

1. Seleccionar nombres de variables significativas, es decir, que indiquen lo que

almacenarán.

2. Si las variables van a constar de varias palabras, utilizar el guion bajo para separar

dichas palabras.

3. Separar declaraciones de variables y enunciados ejecutables por una línea en blanco

para enfatizar dónde terminan las declaraciones y dónde comienzan los enunciados

ejecutables.

4. Colocar una línea en blanco antes y después de cada estructura de control para

mayor legibilidad.

5. Colocar espacios en blanco a ambos lados de un operador lógico o relacional para

resaltar el operador y hacer que el programa sea más legible.

6. Colocar una sangría en el o los enunciados del cuerpo de una estructura if.

7. Si no se está totalmente seguro del orden de evaluación en una expresión compleja,

utilizar paréntesis para obligar al orden, exactamente como se haría en expresiones

algebraicas.

8. Utilizar sólo letras mayúsculas para los nombres de constantes simbólicas, así

resaltarán en el programa y harán recordar que no se pueden cambiar sus valores

porque son constantes y no variables.

9. En expresiones donde se utilice el operador lógico &&, colocar primero la

condición que más probabilidades tenga de ser falsa; en expresiones que utilicen el

operador lógico ||, colocar primero la condición que más probabilidades tenga de ser

verdadera. Esto puede reducir el tiempo de ejecución de un programa.

10. Escribir las llaves de principio y de terminación de los enunciados compuestos

(como los ciclos o condiciones simples) antes de empezar a escribir en el interior de

dichas llaves los enunciados individuales, esto ayudará a evitar la omisión de una

llave o ambas.

11. Inicializar variables que se utilicen como contadores o como totales.

12. Al ejecutar una división por una expresión cuyo valor pudiera ser cero, probar de

forma explícita este caso y manejarlo de manera apropiada en el programa que se

Page 98: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

97

esté creando, por ejemplo, se puede imprimir un mensaje de error en lugar de

permitir que ocurra un error fatal al momento de ejecutarse el programa.

13. En una estructura switch, cuando la cláusula default se enlista al final, el enunciado

break no es requerido, pero se recomienda incluirlo para fines de claridad y simetría

con otros cases.

Sobre estructuras repetitivas

1. Controlar el contador de ciclos con valores enteros, es decir, aunque se permite usar

variables reales, lo adecuado es usar variables de tipo int.

2. Colocar sangrías en los enunciados del cuerpo de cada estructura de control

repetitiva.

3. Demasiados niveles anidados pueden dificultar la comprensión de un programa.

Como regla general evitar el uso de más de tres niveles.

4. Colocar sólo expresiones que involucren las variables de control en las secciones de

inicialización y de incremento de una estructura for. Las manipulaciones de las

demás variables deberían de aparecer, ya se antes del ciclo (si se ejecutan una vez,

como los enunciados de inicialización) o dentro del cuerpo del ciclo (si se ejecutan

una vez en cada repetición, como son los enunciados incrementales o

decrementales).

5. Aunque el valor de la variable de control puede ser modificado en el cuerpo de un

ciclo for, ello podría ocasionar errores sutiles, por tanto, lo mejor es no cambiarlo.

6. Al ciclar a través de un arreglo, el subíndice de un arreglo no debe de pasar nunca

por debajo de 0 ni ser mayor que el número total de elementos del arreglo menos

uno (tamaño - 1).

Sobre funciones

1. Colocar una o dos líneas en blanco entre definiciones de funciones para separarlas y

para mejorar la legibilidad del programa.

2. Aunque una función por omisión regrese un valor de tipo entero, no omitirlo en la

declaración de la función sino utilizar el tipo int en forma explícita.

3. Aunque hacerlo no es incorrecto, para evitar cualquier ambigüedad, es mejor no

utilizar los mismos nombres en los argumentos que se pasan a una función y en los

que se usan en el momento de la definición de la función.

4. Dar nombres a las funciones de acuerdo a lo que evaluarán como se sugiere con las

variables.

5. Incluir prototipos de función para todas las funciones que se vayan a utilizar.

6. Si se requiere que una función regrese más de un valor o una función recibirá

demasiados parámetros, entonces se sugiere dividir a esa función en funciones más

pequeñas.

Page 99: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

98

7. La declaración de una variable como global en lugar de local, permite que ocurran

efectos colaterales no deseados cuando una función que no requiere de acceso a

dicha variable, la modifica accidentalmente. En general, el uso de variables globales

debe ser evitado.

¿Cómo NO realizar una práctica de programación?

1. Ignorar los mensajes de error.

2. Ignorar las advertencias (warnings).

3. Escribir código directamente sin plantear un algoritmo.

4. Aunque el código no compile o no funcione, seguir programando.

5. Si el código tiene un error que no se produce siempre, ignorarlo y seguir

escribiendo.

6. Si el código tiene un error que se produce siempre, cambiar cosas aleatoreamente

hasta que desaparezca.

7. Construir enormes porciones de código sin compilar, ejecutar y probar.

8. No escribir comentarios, salvo los obligatorios.

9. Ignorar los enunciados y detalles que se especifican en un problema a resolver.

10. Ignorar las normas de programación y estructura de un programa.

11. No aprender a utilizar el depurador ni otras herramientas.

12. No aislar o separar el problema en subproblemas.

Page 100: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

99

15 REFERENCIAS

Arellano Pimentel, J. J., Nieva García O. S., Solar González, R. y Arista López, G.

(diciembre, 2012). Software para la enseñanza-aprendizaje de algoritmos

estructurados. Revista Iberoamericana de Educación en Tecnología y Tecnología en

Educación. 8, 23-33.

ASCII (2016, septiembre 13). En Wikipedia. Recuperado de: https://es.wikipedia.org/wiki/ASCII

Bermúdez Juárez B., Beltrán Martínez, B., Bello López, P., Cervantes Márquez, A. P.,

Castillo Zacatelco, H., De La Rosa Flores, R., …, Vázquez Flores, A. (2003). Notas

de Curso. Facultad de Ciencias de la Computación de la Benemérita Universidad

Autónoma de Puebla, México.

Berzal Galiano, F. (s.f.). Introducción a la informática. Recuperado de:

http://elvex.ugr.es/decsai/java/

Borgwardterzal, M. (s.f.). What Every Programmer Should Know About Floating-Point

Arithmetic or Why don’t my numbers add up?. Recuperado de: https://floating-

point-gui.de/

Candela S., García, C. R., Quesada, A., Santana, F. J. y Santos, J. M. (2007). Fundamentos

de sistemas operativos, teoría y ejercicios resueltos. España: Thompson.

Cairó Battistutti, O. (2006). Fundamentos de programación. Piensa en C (1ra. ed.).

México: Pearson Educación de México, S.A. de C.V.

Ceballos, F. J. (1997). Enciclopedia del Lenguaje C. México: Alfaomega Grupo Editor.

Chaitin, G. (2015). El número omega: Límites y enigmas de las matemáticas (Trad. D.

Otero-Piñeiro). Barcelona, España: Tusquets.

Deitel, H.M. y Deitel, P. J. (1995). Cómo programar en C/C++ (2da. ed.). México:

Prentice Hall Hispanoamericana, S.A.

DRAE (2014). Diccionario de la Real Academia Española. Recuperado de:

http://www.rae.es/ (concepto de pixel o píxel y decodificar o descodificar en la

sección 1: Preliminares, conceptos básicos; concepto de programar en la sección 3:

Lenguajes de programación).

Hernández Orallo, E., Hernández Orallo, J. & Juan Lizandra, M.C. (2002). Programación

con el estándar ISO y la biblioteca de plantillas (STL). C++ estándar. España:

Thomson Paraninfo.

Page 101: programación i - fcfm.buap.mx · coordina y lleva el seguimiento de la ejecución de todos los programas en el sistema de cómputo, así, toma decisiones para evitar que se produzcan

100

Hooshyar, D., Alrashdan, M. y Mikhak, Masih. (Enero-marzo, 2013). Flowchart-based

Programming Environments Aimed at Novices. International Journal of Innovative

Ideas, 13(1), 52-62.

Instituto Nacional Estadounidense de Estándares (2015, abril 15). En Wikipedia.

Recuperado de: http://es.wikipedia.org/wiki/Instituto_Nacional_Estadounidense_de

_Est%C3%A1ndares

ISO. (2018). ISO/IEC 9899:2018. Information technology — Programming languages — C.

Recuperado de: https://www.iso.org/standard/74528.html

Joyanes Aguilar L. (2008). Fundamentos de programación. Algoritmos, estrucutra de datos y

objetos (4a. ed.). España: McGraw-Hill/Interamericana de España.

López García, J. C. (2009). Algoritmos y programación. Guía para docentes (2da. ed.).

Recuperado de: http://www.eduteka.org/GuiaAlgoritmos.php

Marzal, A. y Gracia, I. (2006). Introducción a la programación con Python, Edición

Internet. Departamento de Lenguajes y Sistemas Informáticos, Universitat Jaume I.

Novara, Pablo. (2010). Fundamentos de programación, Asignatura correspondiente al plan

de estudios de la carrera de Ingeniería Informática (Anexo 1). Universidad Nacional

del Litoral, Facultad de Ingeniería y Ciencias Hídricas, Departamento de

Informática. Recuperado de: http://zinjai.sourceforge.net/Anexo1.pdf

Ritchie, D. M. (2003). The Development of the C Language*. Recuperado de:

http://www.bell-labs.com/usr/dmr/www/chist.html

Rodríguez Corral, J. M. y Galindo Gómez, J. (2009). Aprendiendo C (3ra. ed.). España:

Servicio de Publicaciones de la Universidad de Cádiz.