Bitácora del desarrollo de mi clase de C++, en el que publicaré el material de la clase y recibiré comentarios y sugerencias de mis alumnos.

miércoles, 21 de febrero de 2007

6.6. Enunciado switch



Estructura de selección múltiple switch
En forma ocasional, un algoritmo contendrá una serie de decisiones, en las cuales una variable o expresión se probará por separado contra cada uno de los valores constantes enteros que puede asumir, y se tomarán diferentes acciones. Para esta forma de toma de decisiones se proporciona una estructura de selección múltiple switch.

La sintaxis de switch es:

switch (expresion_entera)
{
   case expresion1:
       enunciado;
       break;
   case expresion2:
       enunciado;
       break;
   .
   .
   default:
       enunciado;
}

La manera de actuar de switch es comparar expresion_entera con las expresiones en cada enunciado case, si expresion_entera es igual a expresion1, ejecuta todos los enunciados que están enseguida, y así lo hará para cada expresión case, si ninguna de las expresiones case resultó igual a expresion_entera, ejecutará los enunciados que se encuentran después de default. En las listas de enunciados en cada expresión case se tiene un enunciado break, lo que hace es obligar al control del programa a salir de la estructura switch para que no ejecute los siguientes enunciados pertenecientes a otros case, de otra manera al resultar igual a una expresion case Turbo C ejecutará todos los enunciados enseguida hasta donde termina la estructura switch.

En el siguiente ejemplo se presenta al usuario varias opciones para ejecutar con un número que el mismo capturó, mediante una estructura switch se evalúa la selección del usuario y se procede a hacer lo que él desea.

#include (stdio.h)
#include (conio.h)
main( )
{
int seleccion, numero, i, total;
seleccion = 0;
while (selección != 4)
  {
    clrscr();
    printf(“Introduzca un número entero: “);
    scanf(“%d”, &numero);
    printf(“1.- Suma de los números de 1 a %d. \n”,numero);
    printf(“2.- Suma de los números pares de 2 a %d.\n”,numero);
    printf(“3.- Suma de los números nones 1 a %d.\n”,numero);
    printf(“4.- Salir.\n”);
    printf(“Selección : “);
    scanf(“%d”,&selección);
    total=0;
    switch (seleccion)
        {
          case 1:
          for (i = 1;i <= numero; i++)
              total += i;
          break;
          case 2:
          for (i = 2; i <= numero; i+=2)
               total += i;
          break;
          case 3:
          for (i = 1; i <= numero;i+=2)
              total += i;
          break;
         }
  printf(“El total es : %d\n”,total);
  printf(“Presione una tecla para continuar.\n”);
  numero = getch( );
  }
return 0;
}

Se está utilizando una función getch( ) que reside en la librería conio.h, que captura un solo caracter de teclado, pero no lo muestra en pantalla, el caracter capturado se asigna a número, aunque no es la función de numero recibir el caracter, otro numero será pedido al usuario y ocupará el lugar del caracter introducido para la continuación del programa.

En el siguiente ejemplo se solicitará una serie de calificaciones con letra al usuario, y el programa determinará cuántos alumnos obtuvieron cada calificación. Como ya se ha visto un caracter tiene un equivalente en entero y puede representarse de ambas maneras.

#include (stdio.h)
#include (conio.h)
main( )
{
int calif;
int aCuenta=0, bCuenta=0, cCuenta=0, dCuenta=0, eCuenta=0;
clrscr();
printf(“Introduzca las calificaciones.\n”);
while (calif=getchar()) != EOF)
 {
   switch (calif)
     {
      case ‘A’: case ‘a’:
        ++aCuenta;
        break,
      case ‘B’: case ‘b’:
        ++bCuenta;
        break,
      case ‘C’: case ‘c’:
        ++cCuenta;
        break,
      case ‘D’: case ‘d’:
        ++dCuenta;
        break,
      case ‘E’: case ‘e’:
        ++eCuenta;
        break,
      default:
        printf(“Se introdujeron calificaciones erroneas”);
        printf(“Intente de nuevo.\n”);
        break;
     }
 }
printf(“Totales por calificación:\n”);
printf(“A : %d\n”, aCuenta);
printf(“B : %d\n”, bCuenta);
printf(“C : %d\n”, cCuenta);
printf(“D : %d\n”, dCuenta);
printf(“E : %d\n”, eCuenta);
printf(“Presione una tecla para continuar.\n”);
calif = getch();
return 0;
}


Se utiliza una función getchar(), que puede capturar desde uno a varios caracteres, devolviendo de uno por uno a la variable asignada. getchar() deja de capturar caracteres hasta encontrar un caracter de fin de archivo, se debe introducir CTRL-Z para que getchar() termine de capturar caracteres y continúen los siguientes enunciados. getchar() se encuentra en la biblioteca stdio.h.

Para cada valor de calif se evalúa en la estructura switch, y dependiendo del caracter que sea, incrementa el respectivo contador de calificaciones. Al final, después del while, muestra los totales para cada calificación.



lunes, 12 de febrero de 2007

6.5. Enunciados break y continue y función exit

pendiente

6.4. Estructura de repetición while y while anidados


Estructura de repetición while
Una estructura de repetición permite especificar que se repita una acción, mientras que una condición se mantenga verdadera. El enunciado o enunciados contenidos en la estructura de repetición while constituyen el cuerpo del while. El cuerpo de la estructura while puede ser un enunciado sencillo o un enunciado compuesto.

Ejemplo: deseamos obtener la primer potencia de 2 que sea mayor a 1000..
product = 2;
while (product (= 1000)
product = 2 * product;
printf(“La primer potencia de 2 mayor a 1000 es: %d\n”, product);

Este segmento de programa multiplicará 2 * 2 * 2 * ... hasta que el resultado (almacenado en la variable product sea mayor a 1000, una vez terminada la estructura de repetición while (ciclo) imprimirá el valor 1024, antes en cada pasada del ciclo product tomará los valores de 4, 8, 16, 32, 64, 128, 256, 512 y 1024, que hará que la condición sea falsa y el ciclo termine.

Formulación de algoritmos.

Ejemplo:

Una clase de diez alumnos hizo un examen. Las calificaciones (de 0 a 100) correspondientes a este examen están a su disposición. Determine el promedio de este exámen.

Lo que se necesita:
obtener de teclado las diez calificación
realizar el cálculo del promedio de las diez calificaciones
imprimir el resultado

Ya que conocemos el número de calificaciones que serán capturadas (10) necesitaremos una estructura de repetición que se ejecute 10 veces. Necesitaremos una variable que funcione como contador para esas 10 veces y una variable que vaya almacenando la sumatoria de las calificaciones capturadas.

La variable contador deberá ser iniciada en 1 la primera vez que se ejecute la petición de calificación y se vaya incrementando con cada calificación capturada. La variable donde almacenaremos la suma de las calificaciones deberá ser iniciada en 0 para ir sumando desde la primera hasta la calificación número 10.

El algoritmo en pseudocódigo sería:

Asignar 0 a total
Asignar 1 a contador
Mientras contador es menor o igual a 10
Introducir calificacion
Añadir calificación a total
Añadir uno a contador
Asignar a promedio total dividido entre 10
Imprimir el promedio

La solución escrita en lenguaje C es:

#include (stdio.h)
#include (conio.h)
main( )
{
int contador, calificacion, total, promedio;
/* Inicialización de variables*/
contador = 1;
total = 0;
/* captura y acumulación de las 10 calificaciones */
while (contador (= 10)
{
printf(“Introduzca calificación : “);
scanf(“%d”, &calificacion);
total = total + calificacion;
contador = contador + 1;
}
/*cálculo e impresión */
promedio = total / 10;
printf(“El promedio de clase es %d\n”, promedio);
getch ( );
return 0;
}

Hagamos ahora una variante al programa anterior. Que pueda obtener el promedio de un número no conocido de calificaciones. Esto nos obliga a programar un ciclo controlado no por un contador, sino por una variable que introduzca el usuario y que termine cuando tome cierto valor, una variable de tipo centinela.

En el ejemplo pediremos al usuario que termine introduciendo una calificación de -1.

#include (stdio.h)
#include (conio.h)
main( )
{
float promedio;
int contador, calificacion, total; total = 0;
contador = 0;
printf(“Introduzca una calificación o -1 para terminar: “);
scanf (“%d”, &calificacion);
while (calificacion != -1)
{
total = total + calificacion;
contador = contador + 1;
printf (“Introduzca una calificación o -1 para terminar: “);
scanf(“%d”, &calificacion);
}
if (contador != 0)
{
promedio = (float) total / contador;
printf ( “El promedio de clase es %.2f”, promedio”);
}
else
printf(“No se introdujeron calificaciones.\n”);
getch ( );
return 0;
}

Un nuevo tipo de dato es el float o número de punto flotante, que es un número que puede contener una parte entera, un punto decimal, una parte fraccionaria y una parte exponencial.en un rango desde 3.4 X 10-38 hasta 3.4 X 1038. En la línea: promedio = (float) total / contador; se está utilizando un operador (float) que genera una copia del entero total a su equivalente en decimal o en tipo float. En el enunciado printf ( “El promedio de clase es %.2f”, promedio”); se está utilizando una secuencia de escape de formato %.2f, que indica a printf la impresiòn de una expresión de tipo flotante con dos dígitos después del punto.

Operadores de asignación

C dispone de varios operadores de asignación para la abreviatura de las expresiones de asignación. Por ejemplo:

c = c + 4

puede ser abreviada utilizando el operador de asignación +=
c += 4

De manera general las asignaciones de tipo

variable = variable operador expresión;

pueden ser sustituidas por una expresión del tipo

variable operador= expresion;

donde operador puede ser cualquiera de los operadores binarios +, -, *, / ó %

Un ejemplo de cada operador se muestra en la siguiente tabla:
Tenemos las variables:

int c = 3, d = 5, e = 4, f = 6, g = 12;

Operador de asignación Asignación en el formato tradicional Asignación en el formato nuevo Valor asignado a la variable
+= c = c + 7 c += 7 10
-= d = d – 4 d -= 4 1
*= e = e * 5 e *= 5 20
/= f = f / 3 f /= 3 2
%= g = g % 9 g %= 9 3

Operadores de incremento y decremento
C también tiene el operador incremental unario, ++ y el operador decremental unario -- . Si una variable contador es incrementada en 1, el operador incremental puede ser utilizado en vez de las expresiones contador = contador + 1 o bien contador += 1 .Si los operadores incrementales o decrementales son colocados antes de una variable, se conocen como operadores de preincremento o de predecremento, respectivamente. Si los operadores de incremento o decremento se colocan después de una variable, se conocen como operadores de postincremento o de postdecremento respectivamente.

Estos operadores se resumen en la siguiente tabla:

Operador Expresión de muestra Explicación
++ ++a Se incrementa a en 1 y a continuación se utiliza el nuevo valor de a en la expresión en la cual resida.
++ a++ Utiliza el valor actual de a en la expresión en la cual reside a y después se incrementa a en 1.
-- --b Se decrementa b en 1 y a continuación se utiliza el nuevo valor de b en la expresión en la cual reside b.
-- b-- Se utiliza el valor actual de b en la expresión en la cual reside b y después se decrementa b en 1.

Para clarificar estos operadores se presenta un ejemplo en el cual se utiliza un operador preincremental y posteriormente se utiliza uno postincremental.

#include (stdio.h)
#include (conio.h)
main( )
{
int prueba;
prueba = 5;
printf(“%d\n”, prueba);
/* postincremental */
printf(“%d\n”, prueba++);
printf(“%d\n\n”, prueba);

prueba = 5;
printf(“%d\n”, prueba);
/* preincremental */
printf(“%d\n”, ++prueba);
printf(“%d\n”, prueba);
getch ( );
return 0;
}

De esta manera se tienen ya varias formas para incrementar una variable en uno.

contador = contador + 1;
contador += 1;
++ contador;
contador ++;

Es importante hacer notar que al incrementar o decrementar una variable en un enunciado por sí mismo, las formas de preincremento y postincremento tienen el mismo efecto. Es sólo cuando la variable aparece en el contexto de una expresión más grande que el preincrementar y postincrementar tiene efectos distintos. Sólo se puede utilizar un nombre simple de variable como operando de un operador de incremento o decremento, es decir no es correcto: ++ (x + 1)

Estructura de repetición do/while
La estructura de repetición do/while es similar a la estructura while. En la estructura while la condición de continuación de ciclo se prueba al principio del ciclo, antes de ejecutarse el cuerpo del mismo. La estructura do/while prueba la condición de continuación del ciclo, después de ejecutarse el cuerpo del ciclo, y por lo tanto, el cuerpo del ciclo se ejecutará por lo menos una vez. Cuando termina do/while, la ejecución continuará con el enunciado que aparezca dspués de la cláusula while. Nótese que en la estructura do/while no es necesario utilizar llaves, si en el cuerpo existe sólo un enunciado. Sin embargo, por lo regular las llaves se utilizan para evitar confusión entre las estructuras while y do/while. Un do/while sin llaves rodeando el cuerpo de un solo enunciado, aparece como:

do
enunciado;
while (condicion);

lo que podría ser motivo de confusión. La última línea while (condicion); pudiera ser confundida por una estructura while conteniendo un enunciado vacío. Por esta razón se acostumbra poner llaves en cualquier estructura do/while aunque el cuerpo del ciclo sólo contenga un enunciado de la siguiente forma:

do
{
enunciado;
} while (condicion);

Un ejemplo sencillo de esto es la captura validada de un entero positivo:

do
{
printf(“Introduzca un entero positivo: “);
scanf(“&d”, &amp;num);
}
while (num<=0);

el segmento de programa pedirá una vez un entero positivo, y si no es así, insistirá hasta que el usuario introduzca un entero positivo.

Anteriormente se describió un programa que calcula el promedio de n calificaciones. Las calificaciones son introducidas y sumadas al total hasta que el usuario introduce una calificacion de -1, como valor de término:

#include (stdio.h)
#include (conio.h)
main( )
{
float promedio;
int contador, calificacion, total;
total = 0;
contador = 0;
printf(“Introduzca una calificación o -1 para terminar: “);
scanf (“%d”, &calificacion);
while (calificacion != -1)
{
total = total + calificacion;
contador = contador + 1;
printf (“Introduzca una calificación o -1 para terminar: “);
scanf(“%d”, &calificacion);
}
if (contador != 0 )
{
promedio = (float) total / contador;
printf ( “El promedio de clase es %.2f”, promedio”);
}
else
printf(“No se introdujeron calificaciones.\n”);
return 0;
}

En este ejemplo la petición de calificación debe hacerse dos veces, una para una primer calificación y otra dentro del cuerpo del ciclo, este es un ejemplo claro de algo que se desea ejecutar por lo menos una vez, y dependiendo de los valores obtenidos en el cuerpo del ciclo se ejecutará o no más veces.

En este caso podemos utilizar una estructura do/while para ejecutar el cuerpo del ciclo al menos una vez, sin embargo será necesario evaluar si en esa primera ejecución no se dio la condición de fin de ciclo, es decir, se introdujo una calificación de -1.

#include (stdio.h)
#include (conio.h)
main( )
{
float promedio;
int contador, calificacion, total;
total = 0;
contador = 0;
do
{
printf (“Introduzca una calificación o -1 para terminar: “);
scanf(“%d”, &calificacion);
if (calificacion != -1)
{
total += calificacion;
contador++;
}
}
while (calificacion != -1)
if (contador != 0 )
{
promedio = (float) total / contador;
printf ( “El promedio de clase es %.2f”, promedio”);
}
else
printf(“No se introdujeron calificaciones.\n”);
getch ( );
return 0;
}

Ejemplos:
Hacer un programa que pida 10 números enteros y al final muestre la suma de todos los pares y la suma de todos los nones que se hayan introducido.

#include (stdio.h)
#include (conio.h)
main( )
{
int pares, nones, numero, contador;
contador = 0;
pares = 0;
nones = 0;
while (contador menor 10)
{
printf ( “Introduzca un número entero: “);
scanf(“%d”, &numero);
contador ++;
if (numero % 2 == 0)
pares ++;
else
nones ++;
}
printf (“La suma de los números pares es %d\n”, pares);
printf (“La suma de los números nones es %d\n”, nones);
getch ( );
return 0;
}

Un programa que calcule el factorial de un número entero cualquiera que el usuario introduzca.

#include (stdio.h)
#include (conio.h)
main( )
{
int numero, factorial, siguientevalor;
printf(“Introduzca un número entero: “);
scanf(“%d”, &numero);
siguientevalor = numero;
factorial = numero;
if (numero>0)
{
while (numero>1)
factorial *= (--numero);
printf(“El factorial es %d\n”, factorial);
}
else
printf(“No es posible obtener el factorial de un número menor o igual a cero.\n”);
getch ( );
return 0;
}

/*Ejemplo de sumar 15 números y separar el
total en unidades, decenas, etc.*/

#include (stdio.h)
#include (conio.h)
main( )
{
int numero, suma, i;
i=1;
suma=0;
while (i<=15)
{
prinf(“Introduzca un número”);
scanf(“%d”,&numero);
suma += numero;
i++;
}
printf(“La suma es %d\n”, suma);
divisor=10;
while (suma >= 0)
{
printf(“%d\n”, suma % divisor);
suma -= (suma % divisor);
divisor *= 10;
}
}

6.3. Estructura de repetición for y for anidados



Conceptos básicos de repetición
En temas anteriores se mencionaban tres tipos de estructuras de control de programa: estructura de secuencia, de decisión y de repetición, las cuales permiten tomar diferentes caminos en la ejecución de los programas o tomar varias veces el mismo camino.

La mayor parte de los programas incluyen repeticiones o ciclos. Un ciclo es un grupo de instrucciones que la computadora ejecuta en forma repetida, en tanto se conserve verdadera alguna condición de continuación del ciclo. Se han analizado dos procedimientos de repetición: controlada por contador y controlada por centinela.

La repetición controlada por contador se denomina repetición definida, porque con anticipación se sabe con exactitud cuántas veces se ejecutará el ciclo. La repetición controlada por centinela se denomina repetición indefinida, porque no se sabe con anticipación cuantas veces el se ejecutará el ciclo.

En la repetición controlada por contador se utiliza una variable de control para contar el número de repeticiones. La variable de control es incrementada cada vez que se ejecuta todo el conjunto de instrucciones. Cuando el valor de la variable de control indica que se ha ejecutado el número correcto de repeticiones, se termina el ciclo y la computadora continúa ejecutando el enunciado siguiente al de la estructura de repetición.

Los valores centinela se utilizan para controlar la repetición cuando es desconocido el número preciso de repeticiones y cuando el ciclo incluye enunciados que deben obtener datos cada vez que el ciclo se ejecuta. El valor centinela en este caso indica “fin de datos”. Las variables centinela deben ser diferentes a los elementos normales de datos.

Repetición controlada por cuentas
La repetición controlada por contador requiere:
El nombre de una variable de control (o contador)
El valor inicial de la variable de control.
El incremento o decremento con el que será modificada la variable de control cada vez que se termine un ciclo.
La condición o límite que compruebe la existencia del valor final de la variable de control.

En el programa:

#include (stdio.h)
#include (conio.h)
main()
{
int contador;
contador=1;
while (counter menor o igual a 10)
{
printf(“%d\n”, contador);
contador ++;
}
getch ( );
return 0;
}
Se declara la variable de control llamada contador como un entero, se le da un valor inicial de 1, se incrementa en 1 en cada “pasada” del ciclo., hasta llegar hacer falsa la condición (o llegar al límite) del ciclo (counter <= 10).
Estructura de repetición for
La estructura de repetición for maneja automáticamente todos los detalles de la repetición controlada por contador:

Sintaxis
for ( expresion1; expresion2; expresion3)
enunciado;

Primero se evalúa expresion1 (comunmente el inicio del ciclo o el valor inicial del contador), posteriormente se evalúa expresion2, y si es verdadera se ejecuta el o los enunciados dentro de la estructura, posteriormente se evalúa expresión3, en las siguientes pasadas la expresion1 no se evaluará, solamente la expresion2 y expresion3, mientras la expresion2 resulte verdadera el o los enunciados dentro del ciclo se estarán ejecutando.

Anteriormente se vio un ejemplo de cálculo de promedio de 10 calificaciones capturadas utilizando la estructura de repetición while.

#include (stdio.h)
#include (conio.h)
main()
{
int contador, calificacion, total, promedio;
/* Inicialización de variables*/
contador = 1;
total = 0;
/* captura y acumulación de las 10 calificaciones */
while (contador menor o igual a 10)
{
printf(“Introduzca calificación : “);
scanf(“%d”, &calificacion);
total = total + calificacion;
contador = contador + 1;
}
/*cálculo e impresión */
promedio = total / 10;
printf(“El promedio de clase es %d\n”, promedio);
getch ();
return 0;
}
Este mismo programa lo podemos escribir utilizando la estructura for, ya que el número de ejecuciones del ciclo es conocido (se capturarán y acumularán 10 calificaciones).
#include (stdio.h)
#include (conio.h)
main( )
{
int contador, calificacion, total, promedio;
/* Inicialización de variables*/
contador = 1;
total = 0;
/* captura y acumulación de las 10 calificaciones */
for (contador = 1; contador menor o igual a 10; contador ++)
{
printf(“Introduzca calificación : “);
scanf(“%d”, &calificacion);
total = total + calificacion;
}
/*cálculo e impresión */
promedio = total / 10;
printf(“El promedio de clase es %d\n”, promedio);
getch ( );
return 0;
}
Volviendo a la sintaxis de la estructura for
for ( expresion1; expresion2; expresion3)
enunciado;

Las tres expresiones de la estructura for son opcionales. Si se omite expresion2, C supondrá que la condición es verdadera, creando por lo tanto un ciclo infinito. También se puede omitir la exresión1, si la variable de control se inicializa en alguna otra parte del programa. La expresión3 podría también omitirse, si el incremento se calcula mediante enunciados en el cuerpo de la estructura for, o si no se requiere ningún incremento.

Ejemplos de estructura for:

Variar la variable de control de 1 a 100 en incrementos de 1.
for(i=1; i menor o igual a100; i++)
Variar la variable de control de 100 a 1 en incrementos de -1
for(i=100; i mayor o igua a 1; i--)
Variar la variable de control de 7 a 77 en pasos de 7.
for(i=7; i menor o igua a 77; i+=7)
Variar la variable de control de 20 a 2 en pasos de -2.
for(i=20; i mayor o igual a 2, i-=2)
Variar la variable de control a lo largo de la siguiente secuencia de valores: 2, 5, 8, 11, 14, 17, 20.
for(i=2; i menor o igual a 20, i+=3)
Variar la variable de control de acuerdo a la siguiente secuencia de valores: 99, 88, 77, 66, 55, 44, 33, 22, 11, 0.
for(i=99; i mayor o igual a 0, i-=11)

/* Programa que suma los números pares de 2 a 100 */
#include (stdio.h)
#include (conio.h)
main()
{
int sum=0, num;
for (num=2; num menor o igual 100; num+=2)
     sum+=num;
printf(“La suma es %d\n”, sum);
getch ();
return 0;
}

El programa anterior también puede escribirse de la siguiente manera:

/* Programa que suma los números pares de 2 a 100 */
#include (stdio.h)
#include (conio.h)
main( )
{
int sum=0, num;
for (num=2; num menor o igual100; sum+=num, num+=2);
printf(“La suma es %d\n”, sum);
getch ();
return 0;
}

Las diferencias con el primer ejemplo son: 1.- Dentro de la estructura for, en la tercera expresión aparte de hacer el incremento de la varable de control se está realizando también el incremento de la variable sum, es decir se está integrando un enunciado que antes pertenecía al cuerpo del ciclo como parte de la estructura. 2.- La estructura for tiene un ; (punto y coma) al final que indica que ahí termina el ciclo, es decir, no existe ningún enunciado como cuerpo del ciclo. Aunque es válido tener estructuras for semejantes, incluso con más de una variable de inicio, los programas resultan menos legibles y también se debe tener cuidado el orden de las expresiones.

En el ejemplo anterior si se escribe num+=2 antes de sum+=num, el primer incremento de sum será con 4 y no con 2 como ocurría en la primera presentación del mismo programa.

/*Programa que calcula el interés mensual de un depósito para presentar el saldo acumulado en base a un interés mensual de 5% y un depósito inicial de 1000 */
#include (stdio.h)
#include (conio.h)
main( )
{
int mes;
double deposito=1000, interes=0.05;
clrscr( );
printf(“%4s%10s\n”,”Mes”, “Depósito”);
for (mes=1; mes menor o igual a 12; mes++)
  {
   deposito *= (1+interes);
   printf(“%4d%10.2f\n”,mes,deposito);
  }
getch ();
return 0;
}

Ejemplo: Programa que muestra el resultado de las potencias de 11, 22, 33, 44, 55.

#include (stdio.h)
#include (conio.h)
main( )
{
int num, i;
long potencia;
clrscr();
for (num=1, num menor o igual a5; num++)
   {
    potencia=num;
    for (i=1, i menor o igual a num-1; i++)
        potencia *= num;
    printf(“La potencia de %d a la %d es %d\n”,num,num,potencia);
   }
getch ();
return 0;
}

En este caso el primer ciclo for lleva la variable num desde 1 hasta 5, para imprimir la cada número elevado a la misma potencia, es decir, la variable num toma la base de cada potencia. En el segundo ciclo (el mas interno o anidado), se realiza la multiplicación para cada base un número de veces igual al número menos 1, ya que el equivalente a la potencia 1 se obtiene al asignar el valor de num a la variable potencia.

miércoles, 7 de febrero de 2007

6.2. Estructuras condiconales anidadas (if anidadados)


Estructura de selección if/Else
La estructura de selección if/else permite al programador ejecutar acciones diferentes cuando la condición es verdadera que cuando es verdadera. La sintaxis es:

if ( )
    enunciado1;
else
   enunciado2;

Significa “si condicion es verdadera ejecuta el enunciado1, si no ejecuta el enunciado2”.

Ejemplo en pseudocódigo:
si la calificación es mayor o igual a 7
      imprime “Aprobado”
si no
     imprime “Reprobado”

Ejemplo en lenguaje C:

if (calificacion >= 7)
       printf(“Aprobado\n”)
else
       printf(“Reprobado\n”)

Durante la ejecución del programa sucederá que si la variable llamada calificacion contiene un valor mayor o igual a 7, el programa mostrará “Aprobado”, si no (si calificacion tiene un valor menor a 7) se mostrará “Reprobado”.

C tiene el operador ?: que está estrechamente relacionado con la estructura if/else. Este operador es el único operador que utiliza tres operandos (operador ternario). Su sintaxis es la siguiente:

? =7 ? “Aprobado” : “Reprobado”);

El enunciado printf imprime una cadena literal que es “Aprobado” si calificacion es mayor o igual que 7, si no es “Reprobado”.

Ya que los valores de una expresión condicional también pueden ser acciones a ejecutar, podíamos haber escrito:

calificacion >= 7 ? printf(“Aprobado\n”) : printf(“Reprobado\n”) ;

Es decir, si calificacion es mayor o igual a 7 imprime “Aprobado”, si no imprime “Reprobado”.

En ocasiones requeriremos utilizar estructuras if/else anidadas.

Ejemplo en pseudocódigo:
si x > y
      imprimir “x es mayor que y”
si no
     si x = y
         imprimir “x es igual a y”
     si no
         imprimir “x es menor que y”

Ejemplo en lenguaje C

if (x > y)
     printf (“%d es mayor que %d”,x,y);
else
     if (x == y)
           printf (“%d es igual a %d”,x,y);
     else
           printf (“%d es menor que %d”,x,y);

Nótese que para el segmento else de la segunda estructura ya no se evalua si x es menor que y, puesto que como no es ni mayor ni igual, entonces sólo queda que x sea menor que y.

En todas las estructuras de control podemos tener enunciados compuestos, es decir, un conjunto de más de un enunciado dentro de una estructura de control. Los enunciados compuestos se deben encerrar entre llaves “{}” (recordemos el concepto de bloque visto con anterioridad).

Ejemplo:

if (calificacion >= 7)
      printf(“Aprobado\n”);
else
{
printf(“Reprobado\n”);
printf(“El alumno debe recursar la materia\n”;
}

Esto indica que si calificacion no es mayor o igual a 7 se imprimirán ambas cosas: “Reprobado” y “El alumno debe recursar la materia”. Si esto mismo se hubiera escrito sin utilizar llaves, la expresión “El alumno debe recursar materia” se hubiera impreso independientemente del valor de calificacion, debido a que tanto la parte de if como la parte de else de la estructura están esperando un solo enunciado.


6.1. Estructura de selección if (condicional)


Estructuras de control
Por lo regular los enunciados en un programa son ejecutados uno después del otro, en el orden en que aparecen escritos, a lo que se conoce como ejecución secuencial, sin embargo se puede transferir el control a otro enunciado que no sea el siguiente mediante estructuras de control.

Todos los programas pueden ser escritos en base a sólo tres tipos de estructuras de control: estructura de secuencia, estructura de selección y estructura de repetición. En la práctica veremos que estas estructuras de control se pueden apilar (poner una enseguida de otra), o anidar (una dentro de otra).

Estructura de selección if
La estructura if es una estructura de selección, ya que se usa para elegir entre cursos alternativos de acción. La sintaxis de la estructura if es la siguiente

if (condicion)
      enunciado;

Esto quiere decir: Si la condición es verdadera ejecuta el enunciado.

Ejemplo en pseudocódigo:
    Si la calificación es mayor o igual a 7
             imprimir “Aprobado”

Ejemplo en lenguaje C
    if (calificacion >= 7)
            printf(“Aprobado\n”);

Este segmento dará lugar a que, durante la ejecución del programa, si la variable llamada calificación contiene un valor mayor a 7 se imprimirá “Aprobado”, de lo contrario (si la condición es falsa) el control del programa continuará con el siguiente enunciado sin imprimir “Aprobado”.

/* Un programa que encuentra la relación entre dos números: */
#include (stdio.h)
#include (conio.h)
main( )
{
int entero1, entero2;
printf(“Introduzca un número\n”);
scanf(“%d”, &entero1);
printf(“Introduzca otro número\n”);
scanf(“%d”, &entero2);
if (entero1 > entero2)
        printf(“%d es mayor que %d\n”,entero1,entero2);
if (entero1==entero2)
        printf(“%d es igual a %d\n”, entero1,entero2);
if (entero1 ( entero2)         
        printf(“%d es menor que %d\n”, entero1, entero2);
getch ( );
return 0;
}

En los ejemplos anteriores hemos visto como podemos o no ejecutar un enunciado en base a la certeza o falsedad de una condición, sin embargo en ocasiones será necesario ejecutar o no más de un enunciado conforme a una condición. Para ello se utilizan los símbolos { }, que como ya se ha visto indican el fin y el término de un bloque.

/* Un programa que indica cuando se ha introducido un
número par y muestra el resultado de su división entre 2 */

#include (stdio.h)
#include (conio.h)
main( )
{
int entero1;
printf(“Introduzca un número\n”);
scanf(“%d”, &entero1);
if (entero1 % 2 == 0)
    {
      printf(“%d es un número par\n”,entero1);
      printf(“%d dividido entre 2 es = %d\n”,entero1, entero1/2);
    }
getch ( );
return 0;
}



5.2. Variables estáticas, externas estáticas y de registro

Pendiente


 

5.1. Variables externas y locales


Pendiente 

4.6. Precedencia de los operadores


En C las expresiones lógicas dan como resultado siempre un entero igual a 1 ó 0, de manera inversa si se manejan expresiones cien por ciento algebraicas un valor resultante igual a cero equivaldrá a falso y un valor resultante diferente de cero (puede ser incluso un valor negativo) indicará verdadero. Es posible tener expresiones que contengan tanto operadores aritméticos como operadores lógicos. Las reglas de precedencia se muestra a continuación. Los operadores están en orden de precedencia, siendo el más importante el primero.

()
* / %
+ -
< <= > >=
== !=
&&
||

También en el uso exclusivo de operadores lógicos es posible utilizar paréntesis para agrupar expresiones para que tengan mayor precedencia sobre otras.

Ejemplo de expresiones lógicas.

(x==y) || (z!=5)
!(x<5)>= (y>=7)
(x>4) && (y>=6)
!((z<=8)&&(y>4))

Resolver para x=0; y=-1; z=3




4.2. Operadores de igualdad y relacionales

 
Expresiones y operadores lógicos
Los enunciados ejecutables de C, llevan a cabo ya sea acciones o toman decisiones. Un programa puede tomar decisiones basado en la veracidad o falsedad de alguna declaración conocida como condición. Algunas segmentos de programa se basan en condiciones, existiendo enunciados que se ejecutarán dependiendo de la veracidad o falsedad de una condición.

Las condiciones se forman utilizando operadores de igualdad y operadores relacionales (en conjunto conocidos como operadores lógicos). El resultado de usar estos operadores da siempre como resultado un valor de verdadero o falso. Los operadores lógicos se muestran en la siguiente tabla:

Operador         Operador            Ejemplo             Siganificado
algebraico        en C++                 en C++              en C++


Operador de igualdad

    =                  ==                        x == y                x igual a y
                        !=                          x != y                 x diferente a y

Operadores relacionales
 >                   >                           x > y                 x mayor que y
 <                   <                           x (  y                 x menor que y
                       >=                        x >= y              x mayor o igual a y
                       <=                        x <= y              x menor o igual a y

Operadores lógicos
  ~                   !                           !x                      No es x ( “no x”)
  y                   &&                       p && q              p y q
  o                   ||                          p || q                p ò q



4.1. Operadores aritméticos


Expresiones y operadores aritméticos.
La mayor parte de los programas necesitan ejecutar cálculos aritméticos. Los operadores aritméticos que se pueden utilizar en C se presentan en la siguiente tabla:

Suma                      +
Resta                       -
Multiplicación        *
División                  /
Módulo*               %

* El modulo se describe como el residuo de una división entre enteros. P. ej. utilizando el operador de C: 12 % 7 = 5, es decir si dividimos 12 entre 7 el resultado es 1 y el residuo (el módulo) es 5.

Las expresiones aritméticas en C deben ser escritas un una línea continua, para facilitar la escritura de programas.

Los paréntesis se utilizan en las expresiones en C de manera muy similar a como se usan en las expresiones algebraicas. Por ejemplo para multiplicar a por la suma de b + c escribimos:
a * (b + c)

C calcula las expresiones aritméticas en una secuencia determinada por las reglas de precedencia de operadores que siguen:

1. Primero se calculan expresiones o porciones de expresiones contenidas dentro de pares de paréntesis. Entonces, los paréntesis pueden ser utilizados para obligar a un orden de evaluación en cualquier secuencia deseada por el programador. Se dice que los paréntesis están en el “más alto nivel de precedencia”. En el caso de paréntesis anidados o incrustados, se evalúa primero la expresión en el par de paréntesis más interno.

2. A continuación, se calculan las operaciones de multiplicación, división y módulo. Si una expresión contiene varias multiplicaciones, divisiones y módulos, la evaluación avanzará de izquierda a derecha. Se dice que la multiplicación, división y módulo tienen el mismo nivel de precedencia.

3. Por último se calculan las operaciones de suma y resta. Si una expresión contiene varias operaciones de suma y de resta, la evaluación avanzará de izquierda a derecha. La suma y la resta también tienen el mismo nivel de precedencia.




 

martes, 6 de febrero de 2007

3.3. Definición de variables carácter


Tipo caracter y su formateo
Se ha visto como declarar, desplegar y capturar un solo caracter, pero en algunos casos será necesario utilizar cadenas de caracteres o, lo que se conoce como strings. En lenguaje C, los strings tienen un trato muy diferente a otros lenguajes de programación, ya que no representan un tipo de datos básico, sino un conjunto de caracteres, es decir, una serie de datos tipo char.

Son ejemplos de declaración de string los siguientes:

char cadena1[20]; /*Representa un string de 20 caracteres
char cadena2[]=”Universidad de Guanajuato”; /* String de la longitud de lo que se le está asignando.*/

Un ejemplo sencillo de manejo de strings se presenta a continuación:

#include (stdio.h)
#include (conio.h)
main()
{
char cadena[]=”Universidad de Guanajuato”;
clrscr;
printf(“%s\n”, cadena);
scanf(“%s”, &cadena);
printf(“%s\n”, cadena);
return 0;

}

En este ejemplo se declara cadena como un string y se le asigna “Universidad de Guanajuato”, que es lo que despliega el primer enunciado printf, después se captura otro string, y se le asigna a la variable cadena, lo que se haya introducido se despliega en el segundo enunciado printf.

Sin embargo hay que tener cuidado, pues la especificación %s en scanf lee una cadena de longitud arbitraria terminada con un espacio en blanco, por lo que en el programa anterior si se lee una cadena como “Esto es así”, la variable cadena únicamente contendrá el string “Esto”, que aparece antes del primer espacio en blanco, pero si se introduce “Esto_es_así”, todo el string estará asignado a la variable cadena.

En seguida se presenta otro ejemplo de strings:

#include (stdio.h)
#include (conio.h)
main()
{
char cadena[8];
clrscr;
scanf(“%s”, &cadena);
printf(“%s\n”, cadena);
return 0;

}

En este caso, para que el programa no tenga ningún problema no se deben introducir más de nueve caracteres para la variable cadena, puesto que se ha declarado de esa longitud, es decir, con caracteres de 0 a 8.


 

3.2. Definición de constantes simbólicas y literales


En un programa es muy normal usar constantes (numéricas, cadenas...). Si estas constantes las usamos directamente en el programa, el programa funcionará, pero es más recomendable usar constantes simbólicas, de forma que las definimos al principio del programa y luego las usamos cuando haga falta. Así, conseguimos principalmente dos ventajas:

Los programas se hacen más legibles: Es más legible usar la constante simbólica PI como el valor de p que usar 3.14 en su lugar:

Volumen_Esfera = 4/3. * PI * pow(radio,3);

Los programas serán más fáciles de modificar: Si en un momento dado necesitamos usar PI con más decimales (3.141592) sólo tenemos que cambiar la definición, y no tenemos que cambiar todas las ocurrencias de 3.14 por 3.141592 que sería más costoso y podemos olvidarnos alguna.

En C, las constantes simbólicas se suelen poner usando una órden al Preprocesador de C, quedando definidas desde el lugar en que se definen hasta el final del fichero (o hasta que expresamente se indique). Su formato general es:

#define CONSTANTE valor

que se encarga de cambiar todas las ocurrencias de CONSTANTE por el valor indicado en la segunda palabra (valor). Este cambio lo realiza el preprocesador de C, antes de empezar la compilación. Por ejemplo:

#define PI 3.141592

Por convenio, las macros se suelen poner completamente en mayúsculas y las variables no, de forma que leyendo el programa podamos saber rápidamente qué es cada cosa. En general, se deben usar constantes simbólicas en constantes que aparezcan más de una vez en el programa referidas a un mismo ente que pueda variar ocasionalmente. Obsérvese, que aunque el valor de p es constante, podemos variar su precisión, por lo que es recomendable usar una constante simbólica en este caso, sobre todo si se va a usar en más de una ocasión en nuestro programa. Puede no resultar muy útil dedicar una constante para el número de meses del año, por ejemplo, ya que ese valor es absolutamente inalterable.


 

3.1. Nombre y definición de los diferentes tipos de variables



Tipos de datos y formateo
C proporciona varios tipos de datos fundamentales, cada uno de ellos tiene un rango de validez o de valores que puede tomar.

Tipo                   Validez

unsigned char    0 a 255
char                     -128 a 127
enum                   -32,768 a 32,767
unsigned int       0 a 65,535
short int              -32,768 a 32,767
int                        -32,768 a 32,767
unsigned long     0 a 4,294,967,295
long                      -2,147,483,648 a 2,147,483,647
float                     3.4 * (10**-38) a 3.4 * (10**+38)
double                 1.7 * (10**-308) a 1.7 * (10**+308)
long double         3.4 * (10**-4932) a 1.1 * (10**+4932)

Las palabras con las que se declaran los tipos son palabras reservadas de lenguaje C, y no pueden ser utilizadas como nombres de variables.

Tipo entero y su formateo
Los tipos enteros sirven para representar números enteros, y es el tipo por omisión en las declaraciones en Turbo C++. Los tipos de datos en los que se pueden almacenar enteros son int, short int (también declarado como short), unsigned int (también declarado como unsigned), long y unsigned long.

Los números enteros pueden ser desplegados en varios formatos, los caracteres de formato para impresión de enteros se muestran a continuación:

%d  -Número entero.
%i   -Número entero.
%u  -Entero sin signo
%x  -Entero hexadecimal con minúsculas.
%X  -Entero hexadecimal con mayúsculas.
%o   -Entero octal.
%ld  -long o unsigned long
%hd -Funciona para cualquiera.

Tipo numérico de punto flotante y su formateo.
Los tipos flotantes almacenan números con punto decimal siendo el de mayor rango el long double. Los tipos flotantes son float, double y long double.

Para dar formato a los números flotantes podemos utilizar los siguientes caracteres de formato:

%e  -Notación exponencial con minúsculas
%E  -Notación exponencial con mayúsculas
%f   -Con punto flotante
%G  -%f o %E, el que resulte más corto
%g   -%f ó %e, el que resulte más corto.

 

viernes, 2 de febrero de 2007

2.2. Pseudocódigo y diagramas de flujo


Pseudocódigo
Un pseudocódigo o falso lenguaje, es una serie de normas léxicas y gramaticales parecidas a la mayoría de los lenguajes de programación, pero sin llegar a la rigidez de sintaxis de estos ni a la fluidez del lenguaje coloquial. Esto permite codificar un programa con mayor agilidad que en cualquier lenguaje de programación, con la misma validez semántica, normalmente se utiliza en las fases de análisis o diseño de Software, o en el estudio de un algoritmo. Forma parte de las distintas herramientas de la ingeniería de software.

No hay ningún compilador o intérprete de pseudocódigo informático, y por tanto no puede ser ejecutado en un ordenador, pero las similitudes con la mayoría de los lenguajes informáticos lo hacen fácilmente convertible.

El pseudocódigo describe un algoritmo utilizando una mezcla de frases en lenguaje común, instrucciones de programación y palabras clave que definen las estructuras básicas. Su objetivo es permitir que el programador se centre en los aspectos lógicos de la solución, evitando las reglas de sintaxis de los lenguajes de programación convencionales.

No siendo el pseudocódigo un lenguaje formal, varían de un programador a otro, es decir, no hay una estructura semántica ni arquitectura estándar. Es una herramienta ágil para el estudio y diseño de aplicaciones, veamos un ejemplo, que podríamos definir como: lenguaje imperativo, de tercera generación, según el método de programación estructurada.

Ejemplo de pseudocódico
Se presenta el algoritmo para encontrar el máximo de un conjunto de enteros positivos. Se basa en recorrer una vez cada uno de los elementos, comparándolo con un valor concreto (el máximo entero encontrado hasta ahora). En el caso de que el elemento actual sea mayor que el máximo, se le asigna su valor al máximo.

El algoritmo escrito de una manera más formal, esto es, en pseudocódigo tendría el siguiente aspecto:

ALGORITMO Maximo
ENTRADAS: Un conjunto no vacío de enteros C.
SALIDAS: El mayor número en el conjunto C.

maximo ← -∞
PARA CADA elemento EN el conjunto C, HACER
SI valor_del_elemento > maximo, HACER
maximo ← valor_del_elemento
DEVUELVE maximo

Sobre la notación:
"←" representa la asignación entre dos objetos. Por ejemplo, maximo ← valor_del_elemento significa que el objeto maximo cambia su valor por el de valor_del_elemento.

"DEVUELVE" termina el algoritmo y devuelve el valor a su derecha (en este caso maximo).

Diagramas de flujo
Los diagramas de flujo representan la forma más tradicional para especificar los detalles algorítmicos de un proceso. Se utilizan principalmente en programación, economía y procesos industriales; estos diagramas utilizan una serie de símbolos con significados especiales. Son la representación gráfica de los pasos de un proceso, que se realiza para entender mejor al mismo. Son modelos tecnológicos utilizados para comprender los rudimentos de la programación lineal.

Otra definición del diagrama de flujo es la siguiente:
"Es un esquema para representar gráficamente un algoritmo. Se basan en la utilización de diversos símbolos para representar operaciones específicas. Se les llama diagramas de flujo porque los símbolos utilizados se conectan por medio de flechas para indicar la secuencia de operación. Para hacer comprensibles los diagramas a todas las personas, los símbolos se someten a una normalización; es decir, se hicieron símbolos casi universales, ya que, en un principio cada usuario podría tener sus propios símbolos para representar sus procesos en forma de Diagrama de Flujo. Esto trajo como consecuencia que sólo aquel que conocía sus símbolos, los podía interpretar. La simbología utilizada para la elaboración de diagramas de flujo es variable y debe ajustarse a un patrón definido previamente."

Principales símbolos
Estandarizados según ISO 5807
No es indispensable usar un tipo especial de símbolos para crear un diagrama de flujo, pero existen algunos ampliamente utilizados por lo que es adecuado conocerlos y utilizarlos, ampliando así las posibilidades de crear un diagrama más claro y comprensible para crear un proceso lógico y con opciones múltiples adecuadas.

Reglas
De acuerdo al estándar ISO, los símbolos e incluso las flechas deben de tener ciertas características para estar dentro del estándar. En el caso de los círculos de conexión se debe usar sólo cuando se conecta con un proceso contenido dentro de la misma hoja.

a) Existe siempre un camino que permite llegar a una solución
b) Existe un único inicio del proceso
c) Existe un único punto de fin para el proceso de flujo, salvo del rombo que indica una     comparación con dos caminos posibles y además una gran ayuda
d) Evite sumideros infinitos, burbujas que tienen entradas pero no salidas.
e) Evite las burbujas de generación espontánea, que tienen salidas sin tener entradas, porque      son sumamente sospechosas y generalmente incorrectas.
f) Tenga cuidado con los flujos y procesos no etiquetados. Esto suele ser un indicio de falta de     esmero, pero puede esconder un error aún más grave: a veces el analista no etiqueta un flujo o     un proceso porque simplemente no se le ocurre algún nombre razonable.



2.1. Formulación de algoritmos


Un algoritmo es un conjunto finito de instrucciones o pasos que sirven para ejecutar una tarea y/o resolver un problema. De un modo más formal, un algoritmo es una secuencia finita de operaciones realizables, no ambiguas, cuya ejecución da una solución de un problema en un tiempo finito.

El término algoritmo no está exclusivamente relacionado con la matemática, ciencias de la computación o informática. En realidad, en la vida cotidiana empleamos algoritmos en multitud de ocasiones para resolver diversos problemas. Algunos ejemplos son el uso de una lavadora (se siguen las instrucciones). También existen ejemplos de índole matemática, como el algoritmo de la división para calcular el cociente de dos números, el algoritmo de Euclides para calcular el máximo común divisor de dos enteros positivos, o incluso el método de Gauss para resolver Sistema lineal de ecuaciones.

Concepto de algoritmo
La definición de algoritmo aún no cuenta con la formalidad científica que podría ser ideal para la matemática y las ciencias de la computación (donde los algoritmos son esenciales pero a falta de formalidad no pueden incluirse fácilmente en las demostraciones formales de estas ciencias). Sin embargo, si existe un concepto intuitivo de algoritmo.

Un algoritmo es un sistema por el cual se llega a una solución, teniendo en cuenta que debe ser definido, finito y preciso. Por preciso entendemos que cada paso a seguir tiene un orden; finito implica que tiene un determinado número de pasos, o sea, que tiene un fin; y definido, que si se sigue el mismo proceso más de una vez llegaremos al mismo resultado.

Otras definiciones de algoritmo
Secuencia de pasos computacionales que transforman una entrada en una salida (efecto caja negra) Herramienta computacional para resolver un determinado problema, en el cual, debe estar bien especificada la relación entre la entrada y la salida. El algoritmo materializa (efectúa) dicha relación. Un algoritmo es un resolvedor de un problema determinado.

Para solucionar computacionalmente un problema debemos:
1. Seleccionar un modelo matemático – computacional adecuado para el problema (representación del modelo)

2. Concebir con respecto a dicho modelo un algoritmo que dé solución al algoritmo (diseño del algoritmo)

3. Programar el algoritmo en algún lenguaje de programación y ejecutar el programa en una computadora (programación del algoritmo)

Estructura Básica:
a) inicio

b) variables(operaciones básicas)

c) ingresar datos

d) proceso de operaciones

e) mostrar resultados

f) fin