Copy Link
Add to Bookmark
Report

2-8: Como programar en C en muchos pasos (II)

eZine's profile picture
Published in 
0ri0n Team Venezuela
 · 5 Oct 2024

El_Max_5
max-5@0ri0n.org


Saludos, nos volvemos a ver en esta segunda entrega, bueno, en esta segunda parte de este curso de programacion en C vamos a trabajar con los que es Operadores, Sentencias de Control y Funciones, Cualquier Pregunta, Opinion Referencia, Correccion enviarmela por correo, Ok ... Bueno Empecemos ...

II.- Operadores y Sentencias de Control

1.- Operadores


Existen siete tipos de operadores: aritmeticos, relacionales, logicos, de negacion, de incremento, de decremento y de bits.

a.- Aritmeticos


Son:

      *       multiplicacion 
/ division
+ suma
- resta
% division en modulo

Los cuatro primeros actuan de acuerdo a lo señalado. El quinto da el resto de la division de dos enteros.

Ejemplo:

 #include <stdio.h> 
#include <stdlib.h>

main()
{
double fgrados, cgrados;
char respuesta[128];

printf("Conversion de grados Fahrenheit a grados Celsius\n\n");
printf("Grados Fahrenheit? ");
gets(respuesta);
fgrados = atof(respuesta);
cgrados = ((fgrados - 32.0) * 5.0) / 9.0;
printf("Grados Celsius = %f\n", cgrados);
return 0;
}

Para su uso en expresiones debera tomarse en cuenta su precedencia:

 (a + b * c) = (a + ( b * c )) 
(a + b * c) ? ((a + b ) * c))

b.- Operadores Relacionales

Producen cierto (?????o falso (0) como resultado. Son:

 <       >       == 
<= >= !=

Tienen un nivel de precedencia menor que los operadores aritmeticos. Es asi que 10 > 1+ 12 se evalua como 10 > (1+12) y da por resultado un falso.

c.- Operadores Logicos


Son && y || y combinan las expresiones relacionales de acuerdo al "y" logico y "o" logico:

 (A < B) && (B < C)              cierto si A < B y B < C 
(A < B) || (B < C) cierto si A < B o B < C

d.- Operador Negacion

Invierte el resultado de cualquier expresion logica. Es un operador unitario

 !( A< B) es equivalente a A >= B

e.- Operadores de Incremento ++ y Decremento --


En vez de usar:

 i = i + 1;

puede usarse:

 i = i++;

De la misma manera:

 i = i - 1;

puede sustituirse por:

 i = i--;

Ademas:

 j = i++;

asigna el valor no modificado de "i" a "j" e incrementa el valor de "i" de 1.
Si el valor de "i" es 7, al ejecutarse esta sentencia "j" vale 7 e i 8. Si se coloca el operador antes de la variable:

 j = ++i;

i y j tendran el mismo valor. Es decir que:

 j = i ++; equivale a: j = i; i++;

mientras que:

 j = ++i; a: ++i; j = i;

Ejemplo:

 1       #include <stdio.h> 
2
3 main()
4 {
5 int a, b, c, v, k;
6
7 printf("Teclear un valor entero: ");
8 scanf("%d", &v);
9 k = v;
10 printf("\n Antes Durante Despues\n");
11 v = k; a = v; b = v++; c = v; printf("v++%8d%8d%8d\n", a, b, c);
12 v = k; a = v; b = v--; c = v; printf("v--%8d%8d%8d\n", a, b, c);
13 v = k; a = v; b = ++v; c = v; printf("++v%8d%8d%8d\n", a, b, c);
14 v = k; a = v; b = --v; c = v; printf("--v%8d%8d%8d\n", a, b, c);
15 return 0;
16 }

En este programa la linea 8 permite leer el valor decimal del entero tecleado y almacenarlo en v. La expresion &v pasa la direccion de v a scanf(). A excepcion de las cadenas, los argumentos tienen siempre que pasarse a scanf() por su direccion.


f.- Operadores de Asignacion


Se usan en vez de los operadores aritmeticos para ayudar al compilador en la generacion de un codigo mas eficiente:

 cuenta += 10            /* cuenta = cuenta + 10 */ 
cuenta *= 2 /* cuenta = cuenta * 2 */
cuenta /= 3 /* cuenta = cuenta / 3 */
cuenta %= 16 /* cuenta = cuenta % 16 */

g.- Precedencias


La tabla siguiente resume las precedencias entre los operadores del C Nivel Operadores:

 --------------------------------------------------------------------------- 
| Nivel | Operadores | Orden de Evaluacion |
---------------------------------------------------------------------------
| 1 | () . [] | izquierdo a derecha |
| 2 | * & ! - ++ -- + - (molde) sizeof | derecha a izquierda |
| 3 | * / % | izquierdo a derecha |
| 4 | + - | izquierdo a derecha |
| 5 | << >> | izquierdo a derecha |
| 6 | < <= > >= | izquierdo a derecha |
| 7 | == != | izquierdo a derecha |
| 8 | & | izquierdo a derecha |
| 9 | ^ | izquierdo a derecha |
| 10 | | | izquierdo a derecha |
| 11 | && | izquierdo a derecha |
| 12 | || | izquierdo a derecha |
| 13 | ? : | derecha a izquierda |
| 14 | = *= /= += -= %= <<= >>= &= ^= |= | derecha a izquierda |
| 15 | , | izquierdo a derecha |
---------------------------------------------------------------------------

2.- Sentencias de Control

a.- Sentencia if


Su forma general es: if (expresion) sentencia;

Si la expresion es cierta (??????entonces se ejecuta la sentencia?

Puede tambien usarse:

 if (expresion) { 
sentencia1;
sentencia2;
}

if (expresion == valor) {
sentencia1;
sentencia2;
}

Ejemplo:

 1       #include <stdio.h> 
2
3 main()
4 {
5 int numero;
6 int okay;
7
8 printf("Teclear un numero entre 1 y 10: ");
9 scanf("%d", &numero);
10 okay = (1 <= numero) && (numero <= 10);
11 if (!okay)
12 printf("Respuesta incorrecta!\n");
13 return okay;
14 }

La linea 10 asigna a okay el resultado, cierto o falso de (1<= numero) && (numero <= 10). Okay contiene entonces 0 o un valor diferente de 0.

La linea 11 examina la expresion !okay. Si okay es igual a falso, !okay es igual a cierto y se produce el mensaje de error de la linea 12.

Se podria haber utilizado:

 if ((1 <= numero) && (numero<=10)) 
printf("Este numero no puede aceptarse !\n");

b.- La sentencia else


Puede usarse para ejecutar otra alternativa:

 if (expresion) 
sentencia1;
else
sentencia2;

Podemos tener tambien:

 if (expresion) { 
sentencia1;
sentencia2;
} else {
sentencia3;
sentencia4;
}

Podemos anidar los ifs:

 if (expresion1) { 
sentencia1;
sentencia2;
else if (expresion2) {
sentencia3;
sentencia4;
} else {
sentencia5;
sentencia6;
}

Sin embargo, para mayor claridad no es recomendable abusar de los if's anidados.

Ejemplo:

#include <stdio.h> 
main()
{
int bisiesto;
int an;

printf("Detector de año bisiesto\n");
printf("Año? ");
scanf("%d", &an);
if (an > 0) {
if ((an % 100) == 0)
bisiesto = ((an % 400) == 0);
else
bisiesto = ((an % 4) == 0);
if (bisiesto)
printf("%d es un año bisiesto\n", an);
else
printf("%d no es un año bisiesto\n", an);
}
return 0;
}

JUEGO: El ejemplo presenta un error. Trate de corregirlo.

#include <stdio.h> 

main()
{
int numero;

printf("Numero (1 ... 10)? ");
scanf("%d", &numero);
if (numero >= 1)
if (numero > 10)
printf("Error: numero > 10\n");
else
printf("Error: numero < 1\n");
return 0;
}

En C existe una regla muy sencilla. La sentencia else se refiere al if precedente mas proximo que no tenga asociada una sentencia else.

Otra regla importante es que nunca debe confiarse en la sangria para controlar la logica de un programa.


c.- Expresion Condicional


En vez de usar:

 if (expresion1) 
expresion2;
else
expresion3;

puede utilizarse:

 expresion1 ? expresion2 : expresion3;

Por ejemplo:

 if (selecMenu == 'S') 
valor = 100;
else
valor = 0;

se sustituye por:

 valor = (selecMenu == 'S') ? 100 : 0;

La ventaja de usar esta expresion es que se evita tener dos referencias de la misma variable.


d.- Sentencia switch


Esta representa una alternativa al uso de los ifs anidados. Su forma general es:

 switch (expresion) { 
case val1:
sentencia1;
break;
case val2:
sentencia2;
break;
case val3:
sentencia3;
break;
default:
sentenciaPorDefecto;
}

La sentencia break permite salir de inmediato del switch. Si no se pusiera despues de sentencia2, se ejecutarian todas las sentencias que siguen a case val2:, es decir las sentencias sentencia2 , sentencia3 y sentenciaPorDefecto. Algunos programadores se aprovechan de esto y omiten colocar un break a proposito para que se ejecuten varias sentencias del switch. Sin embargo, se desaconseja esta practica.

Ejemplo:

 1       #include <stdio.h> 
2 #include <ctype.h>
3
4 main()
5 {
6 int selec;
7
8 printf("Menu: A(gregar B(orrar S(ortear Sa(lir: ");
9 selec = toupper(getchar());
10 switch (selec) {
11 case 'A':
12 printf("Selecciono Agregar\n");
13 break;
14 case 'B':
15 printf("Selecciono Borrar\n");
16 break;
17 case 'S':
18 printf("Selecciono Sortear\n");
19 break;
20 case 'L':
21 printf("Selecciono Salir\n");
22 break;
23 default:
24 printf("\nSeleccion Ilegal !!!\n");
25 }
26 return selec;
27 }

La linea 9 llama a una funcion getchar() que lee un caracter tecleado. La funcion toupper() convierte el caracter a mayuscula.

e.- Sentencia while


Constituye una de las tres sentencias que permiten crear un bucle para repetir una accion. Su forma general es:

 while (expresion) { 
sentencia1;
sentencia2;
........
}

Cada sentencia se ejecuta repitidas veces mientras la expresion es cierta. Debe, por consiguiente, existir una sentencia que afecte el valor de la expresion para que se termine de ejecutar el bucle.

Ejemplo:

 1       #include <stdio.h> 
2
3 main()
4 {
5 int contador;
6
7 printf("contador con while\n");
8 contador = 1;
9 while (contador <= 10) {
10 printf("%d\n", contador);
11 contador++;
12 }
13 return 0;
14 }

La linea 8 inicializa el valor de la variable de control contador mientras que la linea 11 la incrementa, asegurando asi que la sentencia termine.

Agregar una linea para chequear el valor de contador cuando termina la sentencia while.

Verificar lo que pasa si la expresion es (contador < 10) asi como si se inicializa el contador con el valor 11.

Esta ultima prueba ilustra una propiedad importante de la sentencia while: no se ejecuta si la expresion de control es inicialmente falsa.

Ejemplo:

 #include <stdio.h> 

main()
{
int c;

printf("alfabeto con while\n");
c = 'A';
while (c <= 'Z') {
printf("%c", c);
c++;
}
return 0;
}

f.- Sentencia do - while


Su forma general es:

 do { 
sentencia1;
sentencia2;
.......
} while (expresion);

Esta sentencia se ejecuta completamente por lo menos una vez ya que la expresion de control se chequea a final del bucle.

Ejemplo:

#include <stdio.h> 
main()
{
int contador;

printf("contador con do-while\n");
contador = 0;
do
{
contador++;
printf("%d\n", contador);
} while (contador < 10);
return 0;
}

Agregar una linea para chequear el valor del contador en posiciones estrategicas. Observar que en este caso la expresion (contador < 10) termina correctamente el bucle despues de mostrar el decimo valor. Es importante entender el porque en este caso la expresion (contador <= 10) no funcionaria.

Ejemplo:

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

printf("alfabeto con do-while\n");
c = 'A' - 1;
do {
c++;
printf("%c", c);
} while (c < 'Z');
return 0;
}

g.- Sentencia for


Cuando se conoce o cuando el programa puede calcular el numero de veces que debe ejecutarse la sentencia es preferible usar una sentencia for. Su forma general es:

 for (expresion1; expresion2 ; expresion3) { 
sentencia;
}

Ejemplo:

 for (i = 1; i <= 10; i++) 
printf("i == %d\n",i);

lo que es equivalente a:

 i = 1; 
while ( i <= 10) {
printf("i == %d\n",i);
i++;
}

Ejemplo:

 1       #include <stdio.h> 
2
3 main()
4 {
5 unsigned char c;
6
7 for (c = 32; (c < 254); c++) {
8 if ((c % 32) == 0) printf("\n");
9 printf("%c", c);
10 }
11 printf("\n");
12 return 0;
13 }

En la linea 7 se inicializa la variable de control c al valor ASCII 32, es decir un blanco. Cuando el resto de la division de c por 32 es 0, la sentencia if provoca un cambio de linea.

La sentencia for (;;) ; permite crear un bucle infinito que se terminara solamente cuando un evento externo, tal como, una señal de interrupcion, obliga al procesador a ejecutar algun otro codigo.


h.- Sentencia break


Permite interrumpir un bucle while, do - while o for en ejecucion.

Ejemplo:

 #include <stdio.h> 

main()
{
int contador;

printf("\n\nbucle for:\n");
for (contador = 1; contador <= 10; contador++) {
if (contador > 5) break;
printf("%d\n", contador);
}

printf("\n\nbucle while:\n");
contador = 1;
while (contador <= 10) {
if (contador > 5) break;
printf("%d\n", contador);
contador++;
}

printf("\n\nbucle do/while:\n");
contador = 1;
do {
if (contador > 5) break;
printf("%d\n", contador);
contador++;
} while (contador <= 10);

return 0;
}

La sentencia break puede tambien usarse para terminar una sentencia for infinita:

 for (;;) { 
if (expresion)
break;
}

i.- Sentencia continue


Obliga a un bucle a iniciar su proxima iteracion al principio del bucle.

Ejemplo:

#include <stdio.h> 
main()
{
int contador;

printf("\n Empezando el bucle for que contiene continue...\n");
for (contador = 1; contador <= 10; contador++) {
if (contador > 5) continue;
printf("%d\n", contador);
}
printf("Despues del bucle for, contador = %d\n", contador);

printf("\n\nEmpezando el bucle for que contiene break...\n");
for (contador = 1; contador <= 10; contador++) {
if (contador > 5) break;
printf("%d\n", contador);
}
printf("Despues del bucle for, contador = %d\n", contador);
return 0;
}

j.- Sentencia goto


Se usa asociada a una etiqueta constituida por un identificador seguido de ":". Cuando se ejecuta el programa, esta provoca un salto a la sentencia que sigue inmediatamente a la etiqueta.

Resulta dificil depurar un programa que utilice un exceso de gotos. Ademas de esto, el compilador tiene problemas para optimizar los gotos. Se recomienda, en consecuencia, limitarse en su uso o no usarla.

Ejemplo:

#include <stdio.h> 

main()
{
int contador = 1;

TOP:
printf("%d\n", contador);
contador++;
if (contador <= 10) goto TOP;
return 0;
}

k.- exit()


Normalmente la ejecucion de un programa se termina despues de ejecutarse la ultima sentencia que se encuentra en main(). Generalmente esta sentencia es:

 return valor;

Otra manera de terminar la ejecucion es llamando a la funcion exit(), definida en stdlib.h

Ejemplo:

#include <stdio.h> 
#include <stdlib.h>
#include <ctype.h>
main()
{
char respuesta;

printf("\nTeclear S para Si, N para No: ");
respuesta = toupper(getchar());
if (respuesta == 'Y')
exit(1);
else
exit(0);
printf("esta sentencia no se ejecuta nunca!\n");
}

Este programa puede usarse en cualquier archivo batch que necesite de una respuesta si/no del usuario. Por ejemplo, crear el archivo batch prueba.bat para probarlo

 prueba.bat 
echo off
goto PRINCIPIO
:SI
echo Contesta si !
:PRINCIPIO
echo.
echo Quiere seguir?

Ejm 2:

if errorlevel == 1 goto SI
echo Contesta no !

III.- Funciones

Un programa C esta constituido por una funcion main() y otras funciones mas cuya tarea es muy especifica. Generalmente, se asigna a cada funcion una tarea muy bien definida. Al escribir las funciones se recomienda la mayor simplicidad.

1.- Funciones que no devuelven valores

El ejemplo siguiente muestra la manera correcta de escribir y usar las funciones.

Ejemplo:

 1       #include <stdio.h> 
2
3 void Cuenta(void);
4 void CuentaAlReves(void);
5
6 main()
7 {
8 Cuenta();
9 CuentaAlReves();
10 return 0;
11 }
12
13 void Cuenta(void)
14 {
15 int i;
16
17 printf("\n\nContando hasta 10\n");
18 for (i = 1; i <= 10; i++)
19 printf("%4d", i);
20 }
21
22 void CuentaAlReves(void)
23 {
24 int i;
25
26 printf("\n\nContando al reves desde 10\n");
27 for (i = 10; i >= 1; i--)
28 printf("%4d", i);
29 }

Las lineas 3 - 4 declaran los prototipos de las funciones, o sea, el esquema que indica al compilador el nombre y la forma de cada funcion del programa. Por ejemplo, en la linea 3 cuenta es el nombre de la funcion. Puesto que la funcion no devuelve un valor, se usa antes del nombre la palabra void. Ademas dentro de los parentesis tambien se coloca void para indicar al compilador que la funcion no requiere de parametros. Cuenta es la forma mas sencilla de funcion: no devuelve nada y no necesita parametros de entrada.

La linea 8 llama a la funcion. Con esta simple sentencia se ejecuta la funcion.

En alguna parte del programa, despues de la declaracion de la funcion, pero no dentro de otra funcion, debe definirse la funcion. Para eso, se coloca el encabezado rigurosamente identico a la declaracion de la funcion pero sin el ";" , y a continuacion el bloque de definicion que puede contener declaraciones de variables.

Cualquier variable declarada dentro de una funcion es local a la funcion. Su tiempo de vida es igual al tiempo de actividad de la funcion.

En el ejemplo, las variables i definidas en las lineas 15 y 24 son dos variables diferentes.

2.- Funciones que devuelven un valor

En el ejemplo anterior se utiliza una funcion que devuelve un valor entero para indicar la respuesta del usuario cuando se le pregunta si quiere salir de la aplicacion. Esta funcion se declara como una funcion que devuelve un valor entero y no requiere argumentos.

#include <stdio.h> 
#include <ctype.h>
#define FALSO 0
#define CIERTO 1

int Saliendo(void);

main()
{
int i = 0;
int salir = FALSO;

printf("Salir\n");
while (!salir)
{
i++;
printf("i == %d\n", i);
salir = Saliendo();
}
return 0;
}

int Saliendo(void)
{
int c;

printf("Otro valor? (s/n) ");
do
{
c = toupper(getchar());
} while ((c != 'S') && (c != 'N'));
return (c == 'N');
}

El ejemplo anterior usa una funcion que devuelve un valor real. Este ejemplo muestra ademas como colocar las directivas #include y #define en un archivo de cabecera unidades.h. Todas estas declaraciones podrian haberse colocado al principio del programa, sin embargo, al colocarse en un archivo aparte, pueden utilizarse en cualquier otro programa.

 Unidades.h 
#include <conio.h>

#define FALSO 0
#define CIERTO 1
#define CENT_POR_PULG 2.54;

/* Prototipos de Funciones */

void MuestraMenu(void);
int SelecMenu(void);
double PideValor(void);
void PulgadasACentimetros(void);

Ejemplo:

 1       #include <stdio.h> 
2 #include "c:\conversi.h"
3
4 main()
5 {
6 int saliendo = FALSO;
7
8 printf("Bienvenido al Programa de Conversion de Unidades\n");
9 while (!saliendo) {
10 MuestraMenu();
11 switch(SelecMenu()) {
12 case 1:
13 PulgadasACentimetros();
14 break;
15 case 9:
16 saliendo = CIERTO;
17 break;
18 default:
19 printf("\nError en la Seleccion!\a\n");
20 }
21 }
22 return 0;
23 }
24
25 /* Definicion de las funciones */
26
27 void MuestraMenu(void)
28 {
29 printf("\nMenu\n");
30 printf("----\n");
31 printf("1 -- Pulgadas a centimetros\n");
32 printf("2 -- Centimetros a pulgadas\n");
33 printf("3 -- Pies a metros\n");
34 printf("4 -- Metros a pies\n");
35 printf("5 -- Millas a kilometros\n");
36 printf("6 -- Kilometros a millas\n");
37 printf("9 -- Salir\n");
38 }
39
40 int SelecMenu(void)
41 {
42 printf("\nSeleccion? (No presione ENTER!): ");
43 return (getche() - '0');
44 }
45
46 double PideValor(void)
47 {
48 double valor;
49
50 printf("\nIndique el valor que desea convertir? ");
51 scanf("%lf", &valor);
52 return valor;
53 }
54
54 void PulgadasACentimetros(void)
55 {
56 double valor;
57 double resultado;
58
59 printf("\nPulgadas a Centimetros\n");
60 valor = PideValor();
61 resultado = valor * CENT_POR_PULG;
62 printf("%.3f pulgadas == %.3f centimetros\n", valor, resultado);
63 }

La linea 43 llama a la funcion getche() que capta la presion de una tecla sin necesidad de presionar Enter por parte del usuario. Sustrayendo el valor ASCII del caracter 0 convierte el caracter a su valor decimal entre 0 y 9.

El valor devuelto por una funcion puede tener cualquiera de los tipos definidos anteriormente.

3.- Errores mas comunes cometidas con las funciones

  • Ausencia de return: si la funcion no esta declarada con void y no posee un return en su definicion, el compilador avisa del error.
  • Falta de un return: este error es comun cuando se usa la sentencia if.
  • Ausencia de prototipo: en este caso se considera que la funcion devuelve un valor entero; sin embargo, es preferible no contar con esta regla.
  • efectos laterales: el caso mas frecuente es cuando la funcion modifica el valor de una o varias variables globales.

El tercer tipo de error es comun en los programas viejos. main(), por ejemplo, devuelve un valor entero y podria declararse int main(). En realidad es por eso que se ha señalado anteriormente que main() deberia siempre contener una sentencia return.

El ejemplo Anterior ilustra el cuarto error que probablemente es el mas dificil de detectar.

 #include <stdio.h> 

int Par(void);
int Impar(void);

int i = 1;

main()
{
while (i < 20) {
printf("%2d", i);
if (Par())
printf(" : is par");
printf("\n");
i++;
}
return 0;
}

int Par(void)
{
i++;
return Impar();
}

int Impar(void)
{
return (i % 2);
}

4.- Variables Locales

Las variables declaradas dentro de las funciones son locales a estas funciones. Esto significa que no existen afuera de ellas.

Cuando se llama a una funcion, esta reserva espacio en la pila para almacenar sus variables locales. Cuando se termina la ejecucion de la funcion, esta borra el espacio de la pila que se ha reservado, borrando al mismo tiempo cualquier valor almacenado.

Si dos funciones independientes declaran una variable local, mientras una funcion no llame a la otra, las dos variables pueden muy bien usar el mismo espacio de memoria, claro, no al mismo tiempo. Se asegura asi un uso racional de la memoria.

El siguiente ejemplo ilustra estos conceptos. Aun cuando las dos funciones utilizan el mismo nombre de variable no se produce ningun conflicto. La funcion1 llama a la funcion2 pero esta ultima no cambia el contenido de la variable de la funcion1 ya que para la funcion2 la variable declarada en la funcion1 no existe.

 1       #include <stdio.h> 
2 #include <conio.h>
3
4 void Pause(void);
5 void Funcion1(void);
6 void Funcion2(void);
7
8 main()
9 {
10 Funcion1();
11 return 0;
12 }
13
14 void Pause(void)
15 {
16 printf("Presionar la <barra espaciadora> para continuar...");
17 while (getch() != ' ') ;
18 }
19
20 void Funcion1(void)
21 {
22 char s[15] = "Puerto La Cruz\n";
23
24 printf("\nLa funcion # 1 empieza. s = %s", s);
25 Pause();
26 Funcion2();
27 printf("\nDe regreso a la funcion #1. s = %s", s);
28 }
29
30 void Funcion2(void)
31 {
32 char s[15] = "Valencia\n";
33
33 printf("\nLa funcion # 2 empieza. s = %s", s);
34 Pause();
35 }

La funcion getch() de la linea 17 es muy parecida a la funcion getche() utilizada en otro ejemplo, pero no muestra la respuesta del usuario en la pantalla.


Variable registro

Las variables register se almacenan directamente en un registro del CPU. Ya que no es obligatorio que un registro este disponible, se sugiere que la variable se almacene en un registro. Esto se hace para aumentar la velocidad de las operaciones. Estas variables son ideales para el control de bucles. Solo las variables locales pueden declararse con register. Nunca una variable global puede ser especificada como register.


Variable Volatil

Puede usarse el modificador volatile en la declaracion de la variable para señalar que la variable no puede almacenarse en un registro del CPU. Se indica tambien al compilador que se abstenga de proceder a cualquier tipo de optimizacion al manipular esta variable.

Tipicamente, se utilizan estas variables cuando se usan valores que deben ser modificados por una rutina de interrupcion que opera independientemente del programa.


Variable Externa

Al declarar una variable se describe su tipo. Al definirla, se reserva un espacio para almacenar su valor. Un programa puede declarar un numero ilimitado de veces una variable, pero solo puede definirla una vez.

Cuando un programa esta constituido por varios archivos, las funciones de un modulo pueden hacer referencia a las variables definidas en otro modulo. Las variables definidas en un modulo diferente de donde se usan se llaman externas. Por ejemplo, si se define en el modulo A una variable:

 int afuera;

y si una funcion de un modulo B necesita usar esta variable, debera declararse en B:

 extern int afuera;

El ejemplo siguiente contiene dos archivos, EXTERNA1.C y EXTERNA2.C. Antes de compilarlos, se crea un proyecto EXTERNA1.PRJ, se agrega los dos archivos y se compila y ejecuta con Ctrl + F9.

#include <stdio.h> 

void GetFloat(void);
float f;

main()
{
GetFloat();
printf("Valor del numero real = %f\n", f);
return 0;
}


#include <stdio.h>

void GetFloat(void)
{
extern float f;
printf("Teclear un numero real: ");
scanf("%f", &f);
}

Variable Estatica

Como ya se ha mencionado, las variables locales no mantienen su valor entre dos llamadas a la funcion. Sin embargo, a veces, es necesario definir variables que mantienen su valor entre dos llamadas a las funciones. En este caso se declaran como static.

Ejemplo:

#include <stdio.h> 

int Proximo1(void);
int Proximo2(void);

main()
{
int i;

printf("\nLlamando a Proximo1():\n");
for (i = 1; i <= 10; i++)
printf(" %d", Proximo1());
printf("\nLlamando a Proximo2():\n");
for (i = 1; i <= 10; i++)
printf(" %d", Proximo2());
return 0;
}

int Proximo1(void)
{
static int valor = 1;

return valor++;
}

int Proximo2(void)
{
int valor = 1;

return valor++;
}

5.- Parametros y Argumentos

 double cubo(double r);       /* r es un parametro. */ 
x = cubo(y); /* y es un argumento */

double cubo(double r)
{
return r * r * r;
}

Los parametros se inicializan con el valor de los argumentos que se pasan a la funcion. Estos parametros reciben una copia de los valores pasados como argumentos y el valor de estos ultimos no se cambia. Es decir que la sentencia:

 Q = Costo(x,y,z)

garantiza no cambiar los valores de x, y, z

Ejemplo:

 #include <stdio.h> 
#include <ctype.h>
#include <conio.h>

#define MAXLIN 12
#define MAXCOL 8

void Inicializa(void);
double Costo(double tiempo, double potencia, double costoUnitario);
void ImprimaTabla(void);
int Terminado(void);
double iniciaHoras;
double incrementoHorario;
double iniciaWatts;
double incrementoWatts;
double costoPorKwh;

main()
{
do {
Inicializa();
ImprimaTabla();
} while (!Terminado());
return 0;
}

void Inicializa(void)
{
puts("Costo del consumo electrico\n");
printf("Numero Inicial de Horas .. ? ");
scanf("%lf", &iniciaHoras);
printf("Incremento Horario.......... ? ");
scanf("%lf", &incrementoHorario);
printf("Numero inicial de Watts .. ? ");
scanf("%lf", &iniciaWatts);
printf("incremento para Watts........... ? ");
scanf("%lf", &incrementoWatts);
printf("Costo del kilowatt hora (KWH)? ");
scanf("%lf", &costoPorKwh);
}

double Costo(double tiempo, double potencia, double costoUnitario)
{
return costoUnitario * (potencia*0.001 * tiempo);
}

void ImprimaTabla(void)
{
int linea, col;
double horas, watts;

printf("\nHrs/Watts");
watts = iniciaWatts;
for (col = 1; col <= MAXCOL; col++) {
printf("%8.0f", watts);
watts += incrementoWatts;
}

horas = iniciaHoras;
for (linea = 1; linea <= MAXLIN; linea++) {
printf("\n%6.1f - ", horas);
watts = iniciaWatts;
for (col = 1; col <= MAXCOL; col++) {
printf("%8.2f", Costo(horas, watts, costoPorKwh));
watts += incrementoWatts;
}
horas += incrementoHorario;
}
printf("\n\nCosto del consumo electrico @ Bs.%.4f por KWH\n", costoPorKwh);
}

int Terminado(void)
{
int respuesta;

printf("\nOtra tabla (s/n) ? ");
respuesta = getch();
putchar(respuesta);
putchar('\n');
return (toupper(respuesta) != 'S');
}

En este ejemplo, la funcion putchar() se usa para mostrar un solo caracter.

El prototipo de una funcion puede omitir los nombres de los parametros:

 double Costo (double, double, double);

Sin embargo, la definicion de la funcion debe incluir los nombres de los parametros:

 double Costo(double tiempo, double potencia, double costoUnitario) 
{
return costoUnitario* (potencia * 0.001 * tiempo);
}

Puesto que los parametros se tratan como variables locales preinicializadas, estos pueden declararse con los modificadores register, volatile y const.

6.- Recursividad

Cuando una funcion se llama a si mismo, se habla de una funcion recursiva:

 double Factorial (int numero) 
{
if (numero > 1)
return numero * Factorial(numero - 1);
return 1;
}

Ejemplo:

#include <stdio.h> 

void Recuenta(int max);

main()
{
Recuenta(10);
return 0;
}

void Recuenta(int max)
{
if (max > 1)
Recuenta(max - 1);
printf("%4d", max);
}

Un caso menos comun de recursividad es cuando una funcion llama a otra que a su vez llama a la primera funcion.

Ejemplo:

 #include <stdio.h> 

void A(int c);
void B(int c);

main()
{
A('Z');
puts("");
return 0;
}

void A(int c)
{
if (c > 'A')
B(c);
putchar(c);
}

void B(int c)
{
A(--c);
}

Es importante resaltar que, a cada llamada de la funcion, los parametros se almacenan en la pila, es decir que la recursividad consume el espacio de la pila y podria hasta gotarlo.

Tambien las llamadas a una funcion consumen tiempo. Un programa que no utiliza funciones recursivas puede ejecutarse mas rapidamente que un programa equivalente utilizando funciones recursivas.

7.- Modificadores de Funcion

Por defecto, una funcion es externa. Para limitar el uso de la funcion al modulo donde se define, debe declararse como static. Pueden utilizarse tambien los modificadores siguientes:

pascal

Con este modificador las funciones son responsables de eliminar de la pila los valores de los argumentos alli colocados por la llamada a la funcion.

_fastcall
---------
Pasa los argumentos en registros en vez de la pila.

interrupt
---------
Declara a una funcion como rutina de interrupcion.

near
----
La funcion puede llamarse solamente a partir del mismo segmento de memoria.

far
---
La funcion puede llamarse a partir de cualquier segemento de memoria.

huge
----
Lo mismo que far.

8.- Compilacion condicional

Se utilisa #ifdef para chequear si una constante simbolica existe:

 # ifdef DEPURANDO 
sentencia1;
# elif PRUEBABETA
sentencia2;
# else
sentencia3;
#endif
#ifndef BUFFER
#define BUFFER 255
#endif

para evitar incluir varias veces el mismo archivo de cabecera:

 #if !defined(___DEFS_H) 
#include <_defs.h>
#endif

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT