miércoles, 30 de mayo de 2012

Las Funciones Getchar y Putchar

La función getchar recibe un carácter, mientras que la función putchar imprime un carácter. Este par de funciones son más útiles de lo que parece. Permiten manipular de distintas maneras archivos y caracteres. El siguiente programa es un clásico. Recibe carácter por carácter la entrada del usuario (puede ser un número, una cadena, un archivo) con la función getchar y lo imprime con la función putchar.


/*+++++++++++++++++++++++++++++++++++++++++
  * ESTE PROGRAMA LEE E IMPRIME UNA CADENA + 
  * CARACTER POR CARACTER                  +
  * +++++++++++++++++++++++++++++++++++++++*/

 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  *                                                       +
  *                   ALGORITMO                           +
  * Solicitar una cadena                                  +
  *                                                       +
  + Recibe un caracter                                    +
  * Mientras (el caracter recibido no sea fin de archivo) +
  * { // Abre mientras                                    +
  * Imprime el siguiente caracter                         +
  * Incrementa en uno el numero de caracteres             +
  * Recibe el siguiente caracter                          +
  * }  // Cierra mientras                                 +
  *                                                       +
  *++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

  #include <stdio.h>
  
  int main()
  {  /* Abre main */
  int c;

  printf("\nEste programa recibe e imprime una cadena de caracteres ");
  printf("caracter por caracter.\nPor favor introduzca la cadena: \n");

  while(EOF != (c = getchar()))
  putchar(c);
  
  return 0;
  } /* Cierra main */

_____________________________________________________________________________________________
Ahora hagamos un análisis del programa línea por línea para revisar cada instrucción

/*+++++++++++++++++++++++++++++++++++++++++
  * ESTE PROGRAMA LEE E IMPRIME UNA CADENA + 
  * CARACTER POR CARACTER                  +
  * +++++++++++++++++++++++++++++++++++++++*/

 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  *                                                       +
  *                   ALGORITMO                           +
  * Solicitar una cadena                                  +
  *                                                       +
  + Recibe un caracter                                    +
  * Mientras (el caracter recibido no sea fin de archivo) +
  * { // Abre mientras                                    +
  * Imprime el siguiente caracter                         +
  * Incrementa en uno el numero de caracteres             +
  * Recibe el siguiente caracter                          +
  * }  // Cierra mientras                                 +
  *                                                       +
  *++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

Este par de comentarios indican de qué va el programa.

#include <stdio.h>

Un encabezado que indica que se usará entrada y salida estándar. Además de eso, en este programa se hace uso de otro contenido de este encabezado: la definición del valor del carácter que indica el fin de archivo EOF (End of File)

int main()

Recuerde que en C la unidad básica de programación es la función. El nombre main es también un buen nombre para esta función. main se llamaba la función principal en el lenguaje de programación B, del cual evolucionó el lenguaje C.

{  /* Abre main */

Los corchetes se utilizan en cualquier parte donde pueda ponerse una instrucción simple (salvo en el operador ternario). En el caso de la función main (en realidad en cualquier definición de función) las llaves son obligatorias. NO es correcto escribir un programa como éste:

int main()

return 0;

Un programa con una función main vacía debe escribirse así

main()
{

}

Éste es el programa más corto que puede escribirse en el lenguaje C. Sólo consta de 8 caracteres. Sobra decirlo: el programa no hace nada, pero sintácticamente está bien. Es prescindible el encabezado stdio.h, la instrucción return y el tipo int. No son prescindibles el nombre main, los paréntesis después del nombre, ni las llaves. Todos los cuerpos de las funciones deben estar contenidos en llaves.

int c;

Esta declaración de variable reserva espacio para un tipo entero. La variable, c, será utilizada para almacenar temporalmente cada uno de los caracteres. El tipo de datos char es el tipo adecuado para almacenar caracteres. ¿Por qué se utiliza entonces el tipo int? Porque c también debe guardar el valor de EOF, el fin de archivo, el cual generalmente es -1 (véase este programa). Dado que los tipos char son enteros sin signo, al declarar a la variable c como tipo char, no se podría distinguir el fin de archivo.

printf("\nEste programa recibe e imprime una cadena de caracteres ");
printf("caracter por caracter.\nPor favor introduzca la cadena: \n");

Este par de líneas printf son un mensaje para el usuario.

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

Esta es una forma muy compacta de escribir código. Dentro de la condición de while ocurren varias cosas, y ellas tienen que ver con el orden de precedencia de los operadores. Lo que está dentro de los paréntesis externos, sea lo que sea; se evalúa como una expresión booleana. Si no es una expresión booleana, entonces se convierte explícitamente a una, esto quiere decir que si el valor de dicha expresión es 0, entonces se toma como "falso" y no se realiza el cuerpo de if y por otra parte, el compilador tomará como "verdadero" todo valor distinto de 0, y en ese caso se ejecuta el cuerpo de la instrucción while. Lo primero que "ve" el compilador dentro de los paréntesis externos es una condición:
EOF != (expresion) ¿Qué es EOF? EOF es el caracter que indica el fin del archivo. En los sistemas Unix el fin de archivo es Ctrl D, en tanto que en los sistemas windows es Ctrl C. Si usa un sistema distinto, deberá averiguar cuál es la combinación de teclas que indican EOF. EOF tiene un valor determinado por la plataforma en la que programe. Este valor tiene que ser tal que no se pueda confundir con cualquier carácter válido (como a, b, c, \t, etc). Generalmente se trata de un número negativo (-1). La condición dentro de los paréntesis de while dice "mientras el carácter leído sea distinto de EOF, realiza este cuerpo de instrucciones". Pero ¿qué hay a la derecha del operador relacional !=? Este operador es un operador "izquierdo", toma el valor de la izquierda y lo compara con el de la derecha. A su derecha, y entre paréntesis aparece la expresión x = getchar() ¿Por qué aparece esta expresión entre paréntesis? Porque la precedencia del operador relacional != es superior a la del operador de asignación =. De no haber paréntesis, el compilador primero compararía el valor de c con EOF y luego trataría de asignar el valor de getchar() a la cantidad que se encuentra a la izquierda de =, lo cual provocará un error en la compilación; en este caso los paréntesis son necesarios. Por lo tanto, después de evaluar el valor de EOF, el compilador evalúa la expresión c = getchar(), y aquí se encuentra una expresión que contiene al operador = de asignación. La asociatividad de = es de derecha a izquierda, primero se evalúa la expresión a la derecha y eso se le asigna a la variable c. Pero la expresión de la derecha es una invocación de la función getchar(), definida en el encabezado stdio.h Esa función lo que hace es recibir un carácter de la entrada. La sintaxis general de la función getchar es la siguiente:

int getchar(void)

La función retorna un entero (el valor del carácter leído) y no recibe ningún parámetro. Este valor entero se asigna a la variable c, que se ha declarado previamente como tipo int. Y es ese valor, el de c, el que se compara con EOF. Si el carácter leído es distinto a EOF, entonces se lee el siguiente y así. Se trata pues de un ciclo while controlado por centinela.

putchar(c);

El cuerpo de while consta de una sola instrucción: la función putchar, la cual recibe un entero y retorna también un entero. Esos int son los valores de un carácter. La forma general de la función putchar es la siguiente:

int putchar(int caracter);

En este programa, putchar(c) simplemente envía a la salida estándar el carácter que getchar() acaba de leer.

return 0;

La instrucción return 0; como en todos los programas, indica que se ha terminado el programa satisfactoriamente.

} /* Cierra main */

Esta llave indica el fin del cuerpo de main. Muchas veces le va a ocurrir que hay cuerpos de instrucciones que contienen llaves sin cerrar. Para evitar esto, créese el buen hábito de cerrar el cuerpo antes de escribir las instrucciones. También acostúmbrese a indicar, en cada caso, a qué instrucción corresponden las llaves.
_______________________________________________________________________________________________
Lo que aprendió:
El significado de EOF
La función getchar()
La función putchar()
_______________________________________________________________________________________________
Esta entrada forma parte del Curso de C con Programas Explicados Línea por Línea
Índice
Entrada Anterior
Entrada Siguiente

domingo, 27 de mayo de 2012

Los Encabezados #include y #define

Consideremos el siguiente programa

/*Encabezados al inicio del programa*/
 #include <stdio.h>
 #define PI 3.14159
 
 int main()
 { /*Abre main */
 printf("\nPI = %f es la razon perimetro/diametro para cualquier circulo\n", PI);
 
 /*#define en #include se puden colocar en cualquier lugar en el programa */
 #define C 300000
 printf("La velocidad de la luz es C = %d km/s\n\n", C);

 return 0;
 } /*Cierra main*/

El compilador de C inlcuye un preprocesador. Cuando se incluye una linea del tipo #define PI 3.14159, el preprocesador sustituye en el código (salvo en los lugares en los que aparezca entre comillas dobles " ") cada aparición de la cadena PI por el valor flotante 3.14159. Esto vuelve al programa mucho más fácil de modificar. Si acaso necesitamos una precisión mayor para cálculos futuros, bastará con aumentar los decimales sólo en el encabezado. Piense en el caso en el que en vez de la constante simbólica PI apareciera 3.14159. Para modificar el valor tendríamos que cambiar todas las ocurrencias del número. En un programa grande esto puede representar miles de líneas. Una constante simbólica debe ir justo después de #define, por norma (pero no como una obligación) su nombre debe ir en mayúsculas y a continuación debe debe definirse su "valor", observe que no hay punto y coma (;) al final de la definición. En realidad, en el preprocesamiento la constante simbólica no tiene un valor propiamente dicho. Sólo se indica por qué literales o números deben sustituirse las apariciones en el código de la variable (en el programa siguiente aparece una definición de printf mediante una constante simbólica) La definición puede hacerse en cualquier parte del programa y a partir de ahí será válido invocarla con su nombre. Por convención y simplicidad (tampoco por obligación) los encabezados de definición se incluyen siempre al principio del programa. La línea #define C 300000 define una constante simbólica en medio de la función main.La siguiente línea hace uso de esa constante y el uso es válido.
Sea ahora el siguiente programa, el cual es bastante parecido al anterior:

 #include <stdio.h>
 #define C 300000
 #define PI 3.14159 
 #define p printf

 int main()
 { /* Abre main */
 
 p("\nLa velocidad de la luz C = %d", C);
 p("\nEl valor de PI: %f", PI);
 p("\nDe esta manera el codigo se encripta.\n");
 
 return 0;
 } /* Cierra main*/
 

Aquí no solamente se ha definido mediante constantes simbólicas PI y C, sino también la cadena printf, de tal manera que en el cuerpo de main no se escribe printf, sino p, cada vez que se quiere imprimir un mensaje. Ésta es una forma poco recomendable de escribir un programa, porque se está encriptando y complicando el código, lo cual va a dificultar que nosotros mismos, los creadores del programa, no podamos leerlo en un futuro. Sin embargo, tampoco es algo que esté prohibido. Cada recomendación debe considerarse para el caso particular que nos ocupe. Una bonita excepción a la presente recomendación puede verse en éste código, que es un compilador de C escrito en 3301 caracteres de lenguaje C por el programador francés Fabrice Bellard. Observe la ausencia total de comentarios en ese archivo. Bellard define, con constantes simbólicas, las instrucciones if, else, while, return, etc, de tal manera que logra compactar el código a niveles ilegibles para humanos. Sin embargo, el propósito de Bellard se cumple: el código es bastante pequeño. Las primeras versiones de Unix (un sistema operativo escrito en lenguaje C) eran también muy ligeras. Con fines menos generosos, algunos programadores que se dedican a escribir virus de computadoras, también requieren que su código sea muy compacto. En estos casos el espacio de memoria ocupado por el archivo es más importante que facilidad con la cual éste se pueda modificar.

 #include <stdio.h>
 #define C 300000
 #define PI 3.14159 
 #define p printf

Todos los encabezados anteriores definen constantes simbólicas o (en el caso de #include <stdio.h>) le informan al preprocesador que debe incluir los contenidos de archivos ( <stdio.h> ). Todos ellos se pueden guardar en un archivo llamado Encabezado.h, y llamarlos mediante una instrucción #include como en el siguiente programa:

#include "Encabezado.h"

 int main()
 { /* Abre main */
 
 p("\nLa velocidad de la luz C = %d", C);
 p("\nEl valor de PI: %f", PI);
 p("\nDe esta manera el codigo se encripta.\n");
 
 return 0;
 } /* Cierra main*/

Otra de las funciones del preprocesador es enlazar archivos. Para llevar a cabo estos enlaces, se debe indicar el nombre de los archivos mediante una línea como #include "Encabezado.h" Si el archivo es uno de los "preempacados" en el compilador, como stdio, o math, entonces sólo se indican entre paréntesis angulares y terminados con la extensión .h; si son archivos definidos por el usuario, deben incluirse entre comillas dobles (" "). El nombre de los archivos de encabezado definidos por el usuario deben guardarse en el mismo directorio (carpeta) en el que guardamos el programa que los llama y por convención (no por obligación) se guardan también con la extensión .h (indica que se trata de un header)
________________________________________________________________________________________________
Esta entrada forma parte del Curso de C con Programas Explicados Línea por Línea
Índice

viernes, 25 de mayo de 2012

Impresión de un Cheque en C

El problema principal en este programa consiste en recibir un número entero e imprimir su valor en palabras. Por ejemplo, si el monto por el cual ha de pagarse el cheque es de 567, se debe de escribir el número y aparte, entre paréntesis, escribir (Quinientos Sesenta y Siete). Tal vez lo más interesante, en cuanto a la sintaxis, sea el uso de la función strcpy, la cual toma como argumentos un par de cadenas y asigna el contenido de la segunda en la primera. En el archivo aparece el algoritmo en seudocódigo como comentario, este es fácil de entender y escribir en cualquier otro lenguaje de programación. Este programa sólo funciona con números menores o iguales a 10000, pero es relativamente fácil modificarlo para poder trabajar con cifras más grandes.
Éste problema aparece en el libro de Deitel, pero fue uno de los lectores de este blog quien me pidió por correo el programa, enviándome un código bastante confuso, el cual yo corregí y modifiqué; sin embargo, la idea de usar la función strcopy es de él. Le agradezco desde aquí.
Una ejecución del programa da la siguiente salida:

Este programa imprime un cheque.

Introduzca el dia (numero): 
Introduzca el mes (nombre): 
Introduzca el anio:

Por favor introduzca el nombre del beneficiario: 
Por favor introduzca el apellido paterno del beneficiario: 
Por favor introduzca el apellido materno del beneficiario: 
Por favor introduzca el monto.

=====================================================================================

      BANCO CENTRAL DE MEXICO
  
  Sucursal Plaza Revolucion, Mexico, D.F.         22/Febrero/1986

   

  Paguese este cheque a: Elisa Hernandez Hernandez 
  Por la cantidad de: 5671 (Cinco Milseiscientos  setenta y un pesos.)



        ____________________________
         Firma

=====================================================================================




/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 *                                                                                          +
 * ESTE PROGRAMA IMPRIME UN CHEQUE. PARA ESTO RECIBE EL NOMBRE DEL BENEFICIARIO, LA FECHA   +
 * Y EL MONTO DEL CHEQUE.                                                                   +
 * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 *                                                                                          +
 *                                    ALGORITMO:                                            +
 * Recibir el nombre de usuario                                                             +
 * Recibir la fecha                                                                         +
 * Recibir el monto                                                                         +
 *                                                                                          +
 * Imprimir los datos generales del cheque                                                  +
 * Imprimir el nombre del beneficiario                                                      +
 * Imprimir la el monto en numeros                                                          +
 * Llamar a una funcion que imprima en palabras el monto se envia el numero, se recibe el   +
 * control                                                                                  +
 *                                                                                          +
 * Funcion Imprimir ( recibe numero )                                                       +
 *                                                                                          +
 * Definir los arreglos:                                                                    +
 * Unidades { "Cero", "Uno", "Dos",....."Diez"}                                             +
 * Especiales {"", "", "", "",......"once", "doce", "trece", "catorce", "quince"}           + 
 * Decenas {"", "diez", "veinte", "treinta", ..........., "noventa", "cien"}                +
 * Decenascomp {"", "dieci", "veinti", "treinta y", "cuarenta y", ......., "noventa y "}    +
 * Centenas {"", "cientos", "doscientos", "trescientos", ............, "novecientos" }      +
 * Millares {"". "Mil", "Dos mil", "Tres mil",.....,"Diez Mil"}                             +
 * letras {"   "}                                                                           +
 *                                                                                          +
 * Si el numero < 10                                                                        +
 *                                                                                          +
 *   Imprimr la correspondiente entrada del arreglo Unidades                                +
 *                                                                                          +
 * De lo contrario                                                                          +
 *                                                                                          +
 *   Si el numero esta entre 11 y 15                                                        +
 *   Imprimir la correspondiente entrada del arreglo Especiales                             +
 *                                                                                          +
 *   De lo contrario                                                                        +
 *   millar = numero/1000;                                                                  +
 *   centena = (numero - 1000*millar)/100;                                                  +
 *   decena = (numero - 1000*millar - 100*centena)/10;                                      +
 *   unidad = numero%10;                                                                    +
 *                                                                                          +
 *   Imprimir la correspondiente entrada del arreglo Millares                               +
 *   Imprimir la correspondiente entrada del arreglo Centenas                               +
 *   Imprimir la correspondiente entrada del arreglo Decenas                                +
 *   (Si hay unidades, debe imprimirse la entrada de Decenascomp)                           +
 *   Imprimir la correspondiente entrada del arreglo Unidades                               +
 *                                                                                          +
 * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include <stdio.h>
#include <string.h>

void Imprimir(int );

/*////////////////////////////////////////////////////////////////////////////
// MAIN
////////////////////////////////////////////////////////////////////////////*/

int main()
{     /*Abre main*/
char Nombre[20];
char Paterno[20];
char Materno[20];
int monto;
int dia, anio;
char Mes[15];

printf("\nEste programa imprime un cheque.\n");
printf("\nIntroduzca el dia (numero): ");
scanf("%d", &dia); 
printf("\nIntroduzca el mes (nombre): ");
scanf("%s", Mes);
printf("\nIntroduzca el anio:\n");
scanf("%d", &anio);

printf("\nPor favor introduzca el nombre del beneficiario: ");
scanf("%s", Nombre);
printf("\nPor favor introduzca el apellido paterno del beneficiario: ");
scanf("%s", Paterno);
printf("\nPor favor introduzca el apellido materno del beneficiario: ");
scanf("%s", Materno);
printf("\nPor favor introduzca el monto.\n");
scanf("%d", &monto);

printf("\n=====================================================================================\n");
printf("\n  \t\t\t\tBANCO CENTRAL DE MEXICO\n  ");
printf("\n  Sucursal Plaza Revolucion, Mexico, D.F.\t\t\t\t %d/%s/%d\n", dia, Mes, anio);
printf("\n   \n\n\t\tPaguese este cheque a: %s %s %s ", Nombre, Paterno, Materno);
printf("\n  Por la cantidad de: %d (", monto);
Imprimir(monto);
printf(" pesos.)\n");
printf("\n\n\n\t\t\t\t\t\t\t ____________________________\n");
printf("\t\t\t\t\t\t\t\t\tFirma\n");
printf("\n=====================================================================================\n");
return 0;
}     /*Cierra main */


/*//////////////////////////////////////////////////////////////////////////////////
// FUNCION IMPRIMIR
//////////////////////////////////////////////////////////////////////////////////*/

void Imprimir(int numero)
{

char unidades[][10]={"cero","un","dos","tres","cuatro","cinco","seis","siete","ocho","nueve"};
char especiales[][10]={"","","","","","","","","","","","once","doce","trece","catorce","quince"};
char decenas[][10]={"","diez","veinte","treinta","cuarenta","cincuenta","sesenta","setenta","ochenta","noventa","cien"};
char decenascomp [][13]={"","dieci","veinti","treinta y ","cuarenta y ","cincuenta y ","sesenta y ","setenta y ","ochenta y ","noventa y "};
char centenas[][15]={"","Ciento","doscientos", "trescientos", "cuatrocientos", "quinientos", "seiscientos", "setecientos", "ochocientos", "novecientos"};
char millares[][15] = {"", "Mil", "Dos Mils", "Tres Mil", "Cuatro Mil", "Cinco Mil", "Seis Mil", "Siete Mil", "Ocho Mil", "Nueve Mil", "Diez Mil"};
char letras[16];
int unidad,decena, centena, millar;

if(numero<10)
{
strcpy(letras,unidades[numero]);
printf("%s",letras);
}

else
   
switch(numero)
 
{      /* Abre switch */
case 11:
case 12:
case 13:
case 14:
case 15:

strcpy(letras,especiales[numero]);
printf("%s",letras);
break;

default:
millar = numero/1000;
centena = (numero - 1000*millar)/100;
decena = (numero - 1000*millar - 100*centena)/10;
unidad = numero%10;

strcpy(letras, millares[millar]);
printf("%s",letras);
 
strcpy(letras,centenas[centena]);
printf("%s ", letras);
if( 0 == unidad )
{  /* Abre if */
strcpy(letras,decenas[decena]);
printf(" %s", letras);
} /* Cierra if*/
  
else /*si hay unidades*/
{  /* Abre else */

if ( ((10*decena + unidad) >= 11) && ((10*decena + unidad) <= 15) )
{    /*Abre if*/
strcpy(letras, especiales[10 + unidad]);
printf("%s ", letras);
} /*Cierra if*/
else
{  /*Abre else anidado */
strcpy(letras,decenascomp[decena]);
printf(" %s", letras);
strcpy(letras, unidades[unidad]);
printf("%s", letras);
} /*Cierra else anidado*/
} /*Cierra else */
break;
 
}  /* Cierra switch */
 
return;
}

jueves, 24 de mayo de 2012

Estructuras de Control III: La Instrucción While

______________________________________________________________________________________________
CICLO WHILE CONTROLADO POR CENTINELA.
______________________________________________________________________________________________
Suponga que usted quiere calcular el promedio de las calificaciones de un alumno. No sabe a priori el número de calificaciones que va a recibir. Incluso puede que tenga que calcular el promedio de varios alumnos con distintas calificaciones cada uno. La instrucción de repetición while es una de las principales estructuras de la programación estructurada. While es similar a if en cuanto a que consta de una condición booleana (o que se convierte explícitamente a una) y tiene un cuerpo de instrucciones que han de realizarse si la condición se evalúa como verdadera. Sin embargo, el cuerpo de while se realiza no una vez sino tantas veces como la condición resulte ser cierta. Presumiblemente, en el cuerpo de instrucciones se modificará la condición en el momento oportuno, aunque formalmente la sintaxis de la instrucción no lo requiere. Así que bien podría crearse un ciclo infinito si la condición permanece verdadera de manera infinita. Por ejemplo, en el caso de calcular el promedio, usted no sabe cuántas calificaciones tiene que recibir. Debe recibir tantas como materias haya cursado el alumno. Cada vez usted debe recibir la calificación, sumar el número recibido a la suma acumulada de las calificaciones y aumentar el contador de calificaciones en 1. Al final el promedio será la suma acumulada de calificaciones dividida entre el número de calificaciones. ¿Pero cuándo dejará el programa de realizar ese cuerpo de instrucciones? La respuesta es que debe de hacerse hasta que usted le indique, mediante el teclado, que el final ha llegado. Una manera simple es indicar en el programa que si la calificación recibida es un número negativo, entonces el fin del programa ha llegado. ¿Por qué una calificación negativa? Porque ningún alumno obtiene una calificación negativa en un curso por muy malo que sea. La menor calificación es 0. Así que si usted teclea un número negativo, ese valor puede ser tomado como la bandera que indique el fin del ciclo while. Esta forma de controlar un ciclo while se llama por centinela. La instrucción o cuerpo de instrucciones se realizará mientras la condición sea verdadera.
Para ver al ciclo while en acción, escriba, compile y ejecute el siguiente programa:

/*++++++++++++++++++++++++++++++++++++++++++
 +                                          +
 + Este programa recibe calificaciones de   +
 + un alumno e imprime su promedio          +
 +                                          +
 +++++++++++++++++++++++++++++++++++++++++++*/

 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 *                                                                   +
 +                           ALGORITMO:                              +
 + Pedir al usuario la calificacion de la primera materia            +
 + Recibe el numero de horas                                         +
 +                                                                   +
 + Mientras la calificacion es un numero > 0                         +
 + Suma la calificacion actual a la suma acumulada de calificaciones +
 + Incrementa el numero de calificaciones en 1                       +
 + Repetir los pasos anteriores hasta que el numero de horas sea     +
 + negativo                                                          +
 +                                                                   +
 + El promedio del alumno es la suma acumulada de calificaciones     +
 + dividida entre el numero de calificaciones                        + 
 +                                                                   +
 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

 #include <stdio.h>
 
 int main()

 {      /* Abre main */
 int materias = 0;
 int calificacion = 0;
 int suma = 0;
 float promedio = 0; 
 /* Declarar antes de usar */
 
 printf("\nEste programa recibe las calificaciones de un alumno ");
 printf("y calcula e imprime el promedio.\n");
 printf("\nIntroduzca la calificacion de la primera materia: (negativo para terminar)\n");
 scanf("%d", &calificacion);
 printf("\nCalificacion = %d", calificacion); 
 
 while ( 0 < calificacion )
 {     /* Abre while */
 suma = suma + calificacion;
 materias = materias + 1;   
 printf("\nIntroduzca la calificacion de la siguiente materia: (negativo para terminar)\n");
 scanf("%d", &calificacion);
 }     /* Cierra while */ 

 if ( 0 != materias )
 promedio = (float)suma/materias;
 else
 promedio = 0;

 printf("\nEl promedio de este estudiante es: %.3f \n", promedio);
 
 }      /* Cierra main */

____________________________________________________________________________________________
Ahora hagamos un análisis del programa línea por línea para revisar cada instrucción

/*++++++++++++++++++++++++++++++++++++++++++
 +                                          +
 + Este programa recibe calificaciones de   +
 + un alumno e imprime su promedio          +
 +                                          +
 +++++++++++++++++++++++++++++++++++++++++++*/

 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 *                                                                   +
 +                           ALGORITMO:                              +
 + Pedir al usuario la calificacion de la primera materia            +
 + Recibe el numero de horas                                         +
 +                                                                   +
 + Mientras la calificacion es un numero > 0                         +
 + Suma la calificacion actual a la suma acumulada de calificaciones +
 + Incrementa el numero de calificaciones en 1                       +
 + Repetir los pasos anteriores hasta que el numero de horas sea     +
 + negativo                                                          +
 +                                                                   +
 + El promedio del alumno es la suma acumulada de calificaciones     +
 + dividida entre el numero de calificaciones                        + 
 +                                                                   +
 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

Estos dos recuadros son un par de comentarios. En C los comentarios empiezan con /* y terminan con */, aunque la mayoría de los compiladores también aceptarán como comentario todo lo que se encuentre a continuación de // y hasta el siguiente salto de línea. En el primer recuadro aparece el propósito general del programa, que es calcular el promedio de calificaciones de un alumno. En el segundo recuadro aparece el algoritmo en seudocódigo. Un algoritmo es una receta que hay que seguir para llevar a cabo una tarea. Los algoritmos para computadoras no admiten ambigüedades. Éste algoritmo en seudocódigo es un mensaje para el programador. De inmediato puede determinar qué hace el programa y decidir si el método le satisface o no. La mayoría de los códigos con los que se encuentre en su vida de programador van a tener pocos comentarios. Ésto se debe a la idea generalizada que tienen muchos programadores de que no hacen falta. Los programas de éste curso sí tienen el algoritmo en seudocódigo al principio, y los que usted escriba también deberían tenerlo.

#include <stdio.h>
 

Casi todos sus programas en C van a llevar este encabezado. Le indica al preprocesador que incluya el contenido del archivo stdio (salida y entrada estándar).

int main()

C es un lenguaje de propósito general. No es un lenguaje visual, tampoco fue diseñado para programar aplicaciones web. En C la unidad básica de programación es la función, de la misma manera que en los lenguajes orientados a objetos la unidad básica es la clase. En C lo fundamental es lo que ha de hacerse con los datos, en tanto que en la programación orientada a objetos (en C++, por ejemplo) lo principal son los datos. Los programas en C están compuestos de funciones. Todos deben tener al menos una: la función main.

{      /* Abre main */

main es un cuerpo de instrucciones. Cualquier cuerpo de instrucciones empieza con una llave izquierda.

int materias = 0;
int calificacion = 0;
int suma = 0;
float promedio = 0; 
/* Declarar antes de usar */

Las primeras cuatro líneas son declaraciones de variables. Estamos reservando espacios de memoria para almacenar números enteros (en el caso de materias, calificacion y suma) y un número de punto flotante (promedio). Las variables se pueden declarar en cualquier parte dentro de la función main, siempre y cuando ésto se haga antes de usarlas. A estas variables se les ha asignado un valor (0 en todos los casos). Es recomendable asignar valores a las variables cada vez que se declaran; aunque ésto no es obligatorio, sí es conveniente. Cada vez que se declara una variable, ésta obtiene un valor "basura". Hacer referencia a esa variable, suponiendo de manera errónea que se le ha asignado un valor válido, por ejemplo, mediante la función printf, produce un error no fatal (un error que no detiene la ejecución del programa, y por lo tanto hace que el usuario pueda suponer, también de manera errónea, que el programa hace su tarea correctamente).
El operador de asignación (=) tiene una asociatividad de derecha a izquierda, esto es, toma el valor a la derecha y lo asigna a la variable de la izquierda; es también un operador de muy baja precedencia, esto es, si en un programa en C usted observa una instrucción como esta: x = y + 1; entonces puede estar seguro que primero se realizará la suma y después la asignación: la precedencia del operador + es superior a la del operador =. Pronto veremos más sobre la precedencia y la asociatividad de los operadores en C.
¿Por qué declaramos a la constante promedio como tipo float? Los números float son números con parte decimal (números con punto flotante). Como queremos que la calificación final del alumno sea la más justa posible, tenemos que tomar el promedio como un número con decimales. Si nosotros declaramos promedio como tipo entero, entonces al hacer la división, suma/calificaciones, el resultado se truncará NO al entero inferior, sino al entero más cercano a 0.
La última línea es un comentario, que nos advierte que hay que declarar las variables antes de usarlas.

printf("\nEste programa recibe las calificaciones de un alumno ");
printf("y calcula e imprime el promedio.\n"); 
 

Un mensaje para el usuario. Si el usuario no tiene acceso al código, y no somos explícitos en cuanto a lo que queremos de él, entonces estará en problemas. Es conveniente indicar siempre que sea posible el propósito general del programa en un mensaje general.

printf("\nIntroduzca la calificacion de la primera materia: (negativo para terminar)\n"); 

Un mensaje pidiendo la primera calificación.

scanf("%d", &calificacion); 

y a continuación se recibe.

printf("\nCalificacion = %d", calificacion);  

Este printf es totalmente prescindible, sólo se imprime la calificación que el usuario acaba de introducir.

while ( 0 < calificacion ) 

while, en inglés, significa literalmente "mientras", un buen nombre para la instrucción. La condición entre paréntesis evalúa que el valor de la calificación sea mayor que 0. El cuerpo de while se ejecutará si la condición entre paréntesis se cumple y mientras ésta sea verdadera.

{     /* Abre while */ 

El cuerpo de instrucciones se limita por llaves. Si no hay llaves, while toma por instrucción la inmediata siguiente. También es posible no tener un cuerpo de instrucciones, lo cual se obtiene cuando al final de los paréntesis que contienen la condición aparece un punto y coma.

suma = suma + calificacion; 

Probablemente sea necesario un conocimiento mínimo de qué es y cómo funciona el modelo teórico de una computadora para entender bien esta instrucción. Ante todo no hay que confundirla con una ecuación algebraica. El operador de asignación =, como se ha dicho, es un operador de baja precedencia y con un asociatividad de derecha a izquierda. Primero se realiza la suma, se toma el valor guardado en la variable "calificacion" (el operador + también tiene una asociatividad de derecha a izquierda) y se suma con el valor almacenado en la variable "suma", esta cantidad, que la computadora guarda en una memoria temporal interna, es asignada luego a la variable "suma", borrando la cantidad almacenada previamente. Los nombres de variables no son más que eso, nombres para identificar un espacio de memoria en el cual se almacenan datos. Esos espacios de memoria con frecuencia cambian, durante la ejecución de un programa, el contenido que almacenan, aunque el espacio en sí sigue teniendo el mismo tamaño (tipo de datos) y nombre (nombre declarado de la variable).

materias = materias + 1;  

Esta expresión es sintácticamente igual a la precedente. Primero, 1 se suma al valor almacenado en la variable "materias" y luego ese resultado se almacena en la variable "materias", borrando el valor anterior.

printf("\nIntroduzca la calificacion de la siguiente materia: (negativo para terminar)\n");
scanf("%d", &calificacion);


 }     /* Cierra while */ 

En la mayoría de los lenguajes de programación "modernos", las llaves {} son utilizadas para delimitar cuerpos de instrucción. Lenguajes muy viejos, como Ada, Cobol o Fortran, no limitan cuerpos de instrucción de esta manera, lo cual, a mi gusto, los hace más difíciles de leer.
Esta llave indica el fin del cuerpo de instrucciones while.

if ( 0 != materias )

Este es un condicional if. La condición es: ¿el número de calificaciones es diferente de 0? La forma de escribir la condición es similar a if (materias != 0). ¿Por qué se escribe entonces de la forma en que aparece en el programa? Para evitar una asignación en el segundo caso si se olvida escribir el signo !.

promedio = (float)suma/materias;

Esta asignación es simple. Se realiza la división suma/materias y se le asigna el resultado a la variable "promedio". ¿Por qué aparece la sentencia (float)? Porque las variables "suma" y "materias" son las dos de tipo int. Cuando realizamos operaciones aritméticas con variables del mismo tipo de datos, el resultado conserva el tipo. Por ejemplo al dividir suma (una variable entera) entre materias (una variable también entera) el resultado no tiene más que ser un entero. Sin embargo, "suma" podría no ser múltiplo de "materias", o, en otras palabras, suma/materias podría ser un número con decimales. En ausencia de (float) esto truncaría el valor de la división NO al entero más pequeño, sino al más cercano a 0 (ésta convención es una norma que usan C y C++ derivada del lenguaje Fortran). A pesar de que el lado derecho de la expresión es un tipo int y el izquierdo es un float, esto no crea ningún conflicto. Es posible asignar un valor entero a un float, ya que el compilador de C realiza una transformación automática de tipos (la expresión de la derecha se convierte al tipo de la izquierda). Sin embargo, lo contrario no es cierto: no se puede asignar un valor float a un entero. En general es posible asignar un valor "pequeño" a un tipo "grande", pero no al revés. La razón por la cual aparece (float) antes de suma es porque con esa instrucción convertimos explícitamente suma a tipo float y dado que sólo se puede operar con tipos iguales, el compilador convierte "calificaciones" implícitamente a float. Así que ahora la división se realiza entre dos tipos float y por lo tanto el resultado es un float de orígen que incluye números decimales. Ése resultado se almacena en la variable promedio.

else
promedio = 0;

La razón de if-else en este caso es evitar una división entre 0. Si no se ha introducido ninguna calificación, ocurrirá un error no fatal. En programación, como en aritmética, no se debe dividir entre 0 y se debe evitar que esto ocurra.

printf("\nEl promedio de este estudiante es: %.3f \n", promedio);

La función printf imprime el promedio calculado. Lo único nuevo aquí es "%.3f". Para imprimir una variable float, basta con escribir "%f", tal como para imprimir un entero basta con "%d". Si sólo escribimos "%f", se imprimirá un número con 6 decimales por defecto. Esto puede ser demasiado para los fines de una calificación. Por esta razón se utiliza "%.3f", esto hace que los decimales que se impriman sean solamente 3. La siguiente tabla muestra que si quiere obtener una precisión de 4 decimales deberá escribir "%.4f", etc. Usted puede producir un número tan grande como cifras decimales quiera, pero deberá tener en cuenta que la precisión real del número depende del tamaño de la memoria en la que se almacena el tipo de datos float (vuelva a leer la entrada La Representación en complemento a dos), así que después de cierta número de cifras decimales,las siguientes serán 0.

___________________________________________________________
|         ENUNCIADO                        |      PRODUCE   |
|__________________________________________|________________|
|printf("%f". VariableFlotante);           |      1.000000  | 
|printf("%.1f", VariableFlotante);         |      1.0       |
|printf("%.2f", VariableFlotante);         |      1.00      |
|printf("%.3f", VariableFlotante);         |      1.000     | 
|printf("%.4f", VariableFlotante);         |      1.0000    |
|printf("%.4f", VariableFlotante);         |      1.00000   |
|__________________________________________|________________|


}      /* Cierra main */

Esta llave cierra el cuerpo de main, lo cual indica el fin del programa.
_____________________________________________________________________________________________
CICLO WHILE CONTROLADO POR CONTADOR
_____________________________________________________________________________________________
Vamos a considerar una pequeña variante del programa anterior. Supongamos que sabemos cuántas materias ha cursado nuestro alumno y, por lo tanto, cuántas calificaciones vamos a recibir. Sean por caso 10. En ese caso el programa es modificado sólo un poco, para quedar de la siguiente manera:

/*++++++++++++++++++++++++++++++++++++++++++
 +                                          +
 + Este programa recibe calificaciones de   +
 + 1 alumnos e imprime su promedio          +
 +                                          +
 +++++++++++++++++++++++++++++++++++++++++++*/

 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 *                                                                   +
 +                           ALGORITMO:                              +
 +                                                                   +
 + Establece el numero de calificaciones en 0                        +
 +                                                                   + 
 + Mientras el numero de calificaciones sea menor a 10               +
 + {                                                                 + 
 + Pedir al usuario la calificacion de la siguiente                  +
 + Recibe la calificacion                                            +
 + Suma la calificacion actual a la suma acumulada de calificaciones +
 + Incrementa el numero de calificaciones en 1                       +
 + }                                                                 +
 +                                                                   +
 + El promedio del alumno es la suma acumulada de calificaciones     +
 + dividida entre el numero de calificaciones                        + 
 +                                                                   +
 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

 #include <stdio.h>
 
 int main()

 {      /* Abre main */
 int ContadorMaterias = 0;
 int calificacion = 0;
 int suma = 0;
 float promedio = 0; 
 /* Declarar antes de usar */
 
 printf("\nEste programa recibe las calificaciones de 10 materias de un alumno ");
 printf("\ny calcula e imprime el promedio.\n");
 
 while ( 10 > ContadorMaterias )
 {     /* Abre while */
 ContadorMaterias = ContadorMaterias + 1;
 printf("\nIntroduzca la calificacion de la materia %d: \n", ContadorMaterias);
 scanf("%d", &calificacion);

 suma = suma + calificacion;
 
 }     /* Cierra while */ 

 if ( 0 != ContadorMaterias )
 promedio = (float)suma/ContadorMaterias;
 else
 promedio = 0;

 printf("\nEl promedio de este estudiante es: %.3f \n", promedio);
 
 }      /* Cierra main */

Como ya se ha comentado arriba las instrucciones, vamos a concentrarnos en la diferencia. La condición en while es un poco distinta:

while ( 10 > ContadorMaterias )

La variable ContadorMaterias realiza la misma tarea que en el programa de arriba realizó la variable materias. Como ahora sabemos de antemano cuántas veces se tienen que realizar el cuerpo de instrucciones (recibir las calificaciones, aumentar el número de materias, etc) ésa condición se escribe entre paréntesis. Mientras el contador de materias sea menor que 10, se incrementará en 1 la variable ContadorMaterias y se pedirá la siguiente calificación, etc. Esta forma de controlar el ciclo while se llama por contador. El ciclo se realiza tantas veces como lo indique el contador. Es importante ver que cuando la variable ContadorMaterias se definió, se le asignó el valor 0. Dentro del cuerpo de while, y antes de hacer cualquier otra cosa, se incrementa su número en 1. Por esta razón en la condición se pide que 10 > ContadorMaterias, no >=. Si la variable se hubiera iniciado en 1, entonces la condición sí sería >= y el incremento se daría al final del cuerpo de instrucciones. Es muy común cometer errores por defecto o exceso en 1 cuando se controla un ciclo while por contador.
_____________________________________________________________________________________________
Lo que aprendió:
El uso de la instrucción while
Cómo controlar un while con centinela
Cómo controlar un while con contador
La precedencia del operador =
La precedencia del operador +
Imprimir números flotantes con precisión.
_____________________________________________________________________________________________
Esta entrada forma parte del Curso De C Con Programas Explicados Línea Por Línea
Índice
Entrada Anterior
Entrada Siguiente

miércoles, 16 de mayo de 2012

Un Compilador de C en 3301 Caracteres de C

El siguiente programa es un compilador de C escrito en el propio lenguaje C. Fue hecho por Fabrice Bellard y yo lo descargué gracias a un tweet de Miguel de Icaza. Que quién es Bellard, pues uno de los mejores programadores del mundo. Su logro más conocido es el récord por calcular la mayor cantidad de decimales de pi (2.7 billones, millones de millones) en 131 días con una computadora de las siguientes características:
Procesador Intel Core i7 frecuencia CPU 2.93 GHz
6 Gb de RAM
7,5 TB de disco duro (5 discos 1,5 TB Seagate Barracuda 7200.11 en RAID 0)
Una lista de sus logros aparece: aquí

Fabrice Bellard y Miguel de Icaza


#include <stdio.h>
#define k *(int*)
#define a if(
#define c ad()
#define i else
#define p while(
#define x *(char*)
#define b ==
#define V =calloc(1,99999)
#define f ()
#define J return
#define l ae(
#define n e)
#define u d!=
#define F int 
#define y (j)
#define r m=
#define t +4
F d,z,C,h,P,K,ac,q,G,v,Q,R,D,L,W,M;
E(n{
x D++=e;
}
o f{
a L){
h=x L++;
a h b 2){
L=0;
h=W;
}
}
i h=fgetc(Q);
}
X f{
J isalnum(h)|h b 95;
}
Y f{
a h b 92){
o f;
a h b 110)h=10;
}
}
c{
F e,j,m;
p isspace(h)|h b 35){
a h b 35){
o f;
c;
a d b 536){
c;
E(32);
k d=1;
k(d t)=D;
}
p h!=10){
E(h);
o f;
}
E(h);
E(2);
}
o f;
}
C=0;
d=h;
a X f){
E(32);
M=D;
p X f){
E(h);
o f;
}
a isdigit(d)){
z=strtol(M,0,0);
d=2;
}
i{
x D=32;
d=strstr(R,M-1)-R;
x D=0;
d=d*8+256;
a d>536){
d=P+d;
a k d b 1){
L=k(d t);
W=h;
o f;
c;
}
}
}
}
i{
o f;
a d b 39){
d=2;
Y f;
z=h;
o f;
o f;
}
i a d b 47&h b 42){
o f;
p h){
p h!=42)o f;
o f;
a h b 47)h=0;
}
o f;
c;
}
i{
e="++#m--%am*@R<^1c/@%[_[H3c%@%[_[H3c+@.B#d-@%:_^BKd<<Z/03e>>`/03e<=0f>=/f<@.f>@1f==&g!='g&&k||#l&@.BCh^@.BSi|@.B+j~@/%Yd!@&d*@b";
p j=x e++){
r x e++;
z=0;
p(C=x e++-98)<0)z=z*64+C+64;
a j b d&(m b h|m b 64)){
a m b h){
o f;
d=1;
}
break;
}
}
}
}
}
l g){
p g&&g!=-1){
x q++=g;
g=g>>8;
}
}
A(n{
F g;
p n{
g=k e;
k e=q-e-4;
e=g;
}
}
s(g,n{
l g);
k q=e;
e=q;
q=q t;
J e;
}
H(n{
s(184,n;
}
B(n{
J s(233,n;
}
S(j,n{
l 1032325);
J s(132+j,n;
}
Z(n{
l 49465);
H(0);
l 15);
l e+144);
l 192);
}
N(j,n{
l j+131);
s((e<512)<<7|5,n;
}
T y{
F g,e,m,aa;
g=1;
a d b 34){
H(v);
p h!=34){
Y f;
x v++=h;
o f;
}
x v=0;
v=v t&-4;
o f;
c;
}
i{
aa=C;
r z;
e=d;
c;
a e b 2){
H(m);
}
i a aa b 2){
T(0);
s(185,0);
a e b 33)Z(m);
i l m);
}
i a e b 40){
w f;
c;
}
i a e b 42){
c;
e=d;
c;
c;
a d b 42){
c;
c;
c;
c;
e=0;
}
c;
T(0);
a d b 61){
c;
l 80);
w f;
l 89);
l 392+(e b 256));
}
i a n{
a e b 256)l 139);
i l 48655);
q++;
}
}
i a e b 38){
N(10,k d);
c;
}
i{
g=k e;
a!g)g=dlsym(0,M);
a d b 61&j){
c;
w f;
N(6,g);
}
i a u 40){
N(8,g);
a C b 11){
N(0,g);
l z);
c;
}
}
}
}
a d b 40){
a g b 1)l 80);
r s(60545,0);
c;
j=0;
p u 41){
w f;
s(2393225,j);
a d b 44)c;
j=j t;
}
k r j;
c;
a!g){
e=e t;
k e=s(232,k n;
}
i a g b 1){
s(2397439,j);
j=j t;
}
i{
s(232,g-q-5);
}
a j)s(50305,j);
}
}
O y{
F e,g,m;
a j--b 1)T(1);
i{
O y;
r 0;
p j b C){
g=d;
e=z;
c;
a j>8){
r S(e,m);
O y;
}
i{
l 80);
O y;
l 89);
a j b 4|j b 5){
Z(n;
}
i{
l n;
a g b 37)l 146);
}
}
}
a m&&j>8){
r S(e,m);
H(e^1);
B(5);
A(m);
H(n;
}
}
}
w f{
O(11);
}
U f{
w f;
J S(0,0);
}
I y{
F m,g,e;
a d b 288){
c;
c;
r U f;
c;
I y;
a d b 312){
c;
g=B(0);
A(m);
I y;
A(g);
}
i{
A(m);
}
}
i a d b 352|d b 504){
e=d;
c;
c;
a e b 352){
g=q;
r U f;
}
i{
a u 59)w f;
c;
g=q;
r 0;
a u 59)r U f;
c;
a u 41){
e=B(0);
w f;
B(g-q-5);
A(n;
g=e t;
}
}
c;
I(&m);
B(g-q-5);
A(m);
}
i a d b 123){
c;
ab(1);
p u 125)I y;
c;
}
i{
a d b 448){
c;
a u 59)w f;
K=B(K);
}
i a d b 400){
c;
k j=B(k j);
}
i a u 59)w f;
c;
}
}
ab y{
F m;
p d b 256|u-1&!j){
a d b 256){
c;
p u 59){
a j){
G=G t;
k d=-G;
}
i{
k d=v;
v=v t;
}
c;
a d b 44)c;
}
c;
}
i{
A(k(d t));
k d=q;
c;
c;
r 8;
p u 41){
k d=m;
r m t;
c;
a d b 44)c;
}
c;
K=G=0;
l 15042901);
r s(60545,0);
I(0);
A(K);
l 50121);
k r G;
}
}
}
main(g,n{
Q=stdin;
a g-->1){
e=e t;
Q=fopen(k e,"r");
}
D=strcpy(R V," int if else while break return for define main ")+48;
v V;
q=ac V;
P V;
o f;
c;
ab(0);
J(*(int(*)f)k(P+592))(g,n;
}

jueves, 10 de mayo de 2012

El Operador Ternario ? : en C

El lenguaje de programación C proporciona una instrucción equivalente a la estructura de selección if else, el operador ternario ? : La estructura de esta instrucción es la siguiente:

Expresión1 ? Expresión2 : Expresión 3

La Expresión 1 se evalúa primero. Se trata de una expresión booleana, si no lo és, se convierte explícitamente en una. Esta sólo adopta los valores 'verdadero' o 'falso'; al igual que en el condicional if, cualquier cosa distinta de 0 se considera 'verdadero', en este caso se realiza la Expresión 2, pero no la Expresión 3. Si la Expresión 1 se evalúa como 'Falso', entoncesse realiza la Expresión 3, pero no la Expresión 2. Las expresiones 2 y 3 tienen que ser expresiones simples, no se admite un cuerpo de instrucciones agrupadas en corchetes y separadas por punto y coma.
El programa a continuación hace uso de esta expresión condicional.
Cópielo y ejecútelo.

/*+++++++++++++++++++++++++++++++++++++++++++++++++++
  *                                                 *
  * SE USA EL OPERADOR TERNARIO     ? :             *
  *                                                 *
  *+++++++++++++++++++++++++++++++++++++++++++++++++*/

 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++
  *                    ALGORITMO                         +
  *   1) Pedir un numero al usuario.                     +
  *   2) Recibir el numero                               +
  *   3) Si el numero es mayor que 0:                    +
  *         Imprimir "El numero es positivo"             +
  *      De lo contrario:                                +
  *         Imprimir "El numero no es positivo"          + 
  *                                                      +
  *++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

 /*////////////////////////////////////////////////////////////////
 // MAIN
 ////////////////////////////////////////////////////////////////*/

  #include <stdio.h>
  
  int main(void)
  {            /* Abre main */
  int x;
  printf("\nPor favor introduzca un numero entero:\n");
  scanf("%d", &x);
  
  printf( ( 0 < x) ? "\nEl numero es positivo\n":"\nEl numero no es positivo\n");
  
  return 0; 
  }            /* Cierra main */

______________________________________________________________________________________
Ahora hagamos un análisis del programa línea por línea para revisar cada instrucción.

/*+++++++++++++++++++++++++++++++++++++++++++++++++++
  *                                                 *
  * SE USA EL OPERADOR TERNARIO     ? :             *
  *                                                 *
  *+++++++++++++++++++++++++++++++++++++++++++++++++*/

 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++
  *                    ALGORITMO                         +
  *   1) Pedir un numero al usuario.                     +
  *   2) Recibir el numero                               +
  *   3) Si el numero es mayor que 0:                    +
  *         Imprimir "El numero es positivo"             +
  *      De lo contrario:                                +
  *         Imprimir "El numero no es positivo"          + 
  *                                                      +
  *++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

 /*////////////////////////////////////////////////////////////////
 // MAIN
 ////////////////////////////////////////////////////////////////*/

Estas línea contienen tres comentarios, iniciados con /* y terminados con */ El primero de ellos indica qué hace el programa, y éste se limita a ser un ejemplo básico de uso del operador ternario ? : El segundo comentario indica el algoritmo en seudocódigo del programa; son los pasos que realiza el programa; el tercero es una indicación de que empieza la función main.

 #include <stdio.h>

stdio.h significa "standard input-output header". La terminación .h es usada para identificar nombres de encabezados. Debe aparecer siempre en los programas que usan entrada y salida estándar.

int main(void)

Un encabezado de función incluye primero el tipo de datos que la función retorna. La función main retorna un entero, esa es la razón por la cual aparece la palabra int al principio de la línea. Algunas funciones retornan tipos float, tipos double, etc. Main sólo retorna tipos int. main es el nombre de la función. Si el compilador no encuentra en todo el archivo una función llamada main, no ejecuta nada. El control del programa empieza con la primera instrucción de la función main. Entre paréntesis aparece una palabra reservada nueva: void En el encabezado de una función, además aparecer el tipo de retorno y el nombre de la función, aparece, entre paréntesis, el tipo de datos que retorna dicha función. La función puede no retornar un valor, sino solamente el control del programa justo al punto desde donde fue invocada. En esos casos es práctica común escribir la palabra void (vacío) para declarar que no se retorna un dato.

{            /* Abre main */
  

Esta línea es conocida: { abre el bloque main. Algunos lenguajes, como Fortran, no usan llaves para delimitar los bloques de instrucciones, en esos lenguajes la lectura del código por parte del programador es bastante más difícil. C y lenguajes derivados limitan bloques con llaves {}.

 printf("\nPor favor introduzca un numero entero:\n");
 scanf("%d", &x);

Pedir y recibir un número del usuario son un par de instrucciones rutinarias a estas alturas. Con la función scanf podemos recibir más de un número a la vez, como lo veremos pronto.

printf( ( 0 < x) ? "\nEl numero es positivo\n":"\nEl numero no es positivo\n");
   

Observe cómo dentro de la función printf se toma una decisión. Si el número es mayor que 0 (0 < x), entonces se realiza la instrucción que aparece después de ? y antes de : se imprime el mensaje "El número es positivo."; de lo contrario se realiza la siguiente instrucción, la que se encuentra después de : se imprime "El numero no es positivo". Es incorrecto tratar de hacer esto con una instrucción if-else. Una línea como esta
printf( if ( 0 < x)  "\nEl numero es positivo\n" else "\nEl numero no es positivo\n");

Produce (en mi compilador, cc) el siguiente mensaje de error:

OperadorTernario.c: En la función ‘main’:
OperadorTernario.c:34:11: error: expected expression before ‘if’


Sin embargo, la instrucción también pudo haberse escrito de la siguiente forma:

(0 < x)? printf("\nEl numero es positivo\n"):printf("\nEl numero no es positivo.\n");

Observe la ausencia de punto y coma (;) después de printf. Expresión 2 y Expresión 3 son expresiones simples. Usted puede colocar instrucciones encerradas dentro de corchetes {} en cualquier parte donde pueda ir una instrucción simple, esa es una de las características de la programación estructurada. Pero NO en este caso. Tratar de convertir las instrucciones simples 2 y 3 a bloques no es aceptado por el compilador.
Uno de los principales usos de el operador ternario es tomar decisiones en una asignación. La siguiente línea

y = (x > 0) ? 1 : 0;

asigna el valor de 1 a la variable y en el caso de que la variable x sea positiva, de lo contrario le asigna 0. Los paréntesis en la Expresión 1 son opcionales, pero muy recomendables. El orden de precedencia de el operador ternario es muy bajo, pero superior a la asignación (=). Sin embargo, los dos operadores se evalúan de derecha a izquierda. En la línea anterior primero se evalúa x > 0 ? 1 : 0 y el resultado de esa expresión es el que se asigna a y. Los paréntesis hacen que el usuario entienda mejor qué hace la línea. Tenga mucho cuidado en observar que los tipos de datos en Expresión 2 y Expresión 3 sean iguales. Si no lo son, el compilador realizará conversiones de tipo que dependen de las reglas de conversión de tipos del lenguaje C. Estas conversiones pueden producir errores difíciles de detectar. NO declare tipos distintos para Expresión 2 y Expresión 3.

return 0; 
 }            /* Cierra main */

Este par de líneas indican el fin del programa.
_______________________________________________________________________________________________
Lo que aprendió:
El uso de printf con el operador ternario ? :
Asignaciones con el operador ternario ? :
El orden de precedencia del operador ternario ? :
_______________________________________________________________________________________________
Esta página forma parte del Curso de C con Programas Explicados Línea por Línea
Índice
Entrada Anterior
Entrada Siguiente
Related Posts Plugin for WordPress, Blogger...