Está en la página 1de 16

ESTRUCTURAS DE CONTROL

ESTRUCTURAS CONDICIONALES
Las condiciones son ingredientes comunes de un programa. Las condiciones
permiten ejecutar una o varias sentencias dependiendo de validez de una
expresión. En otras palabras, ‘Si se cumple la condición (...), se debe hacer
(...). De lo contrario, si la condición no se cumple, se debe hacer (...)’. Los
operandos condicionales if-else y switch se utilizan en las operaciones
condicionales. Una sentencia condicional puede ser seguida por una sola
sentencia o por un bloque de sentencias a ser ejecutadas.

OPERADOR CONDICIONAL if-else


El operador if se puede utilizar solo o asociado al operador else (if-else).
Ejemplo del operador if:
if(expresión) operación;

Si el resultado de la expresión encerrada entre paréntesis es verdadero


(distinto de 0) la operación se realiza y el programa continúa con la ejecución.
Si el resultado de la expresión es falso (0), la operación no se realiza y el
programa continúa inmediatamente con la ejecución. Como hemos
mencionado, la otra forma combina tanto el operador if como el else:
if(expresión) operación1 else operación2;

Si el resultado de la expresión es verdadero (distinto de 0), se


realiza operación1, de lo contrario se realiza la operación2. Después de realizar
una de las operaciones, el programa continúa con la ejecución. La sentencia if-
else se parece a lo siguiente:
if(expresión)
operación1
else
operación2

Si operación1 u operación2 está compuesta, escriba una lista de sentencias


encerradas entre llaves. Por ejemplo:
if(expresión) {
... //
... // operación1
...} //
else
operación2

El operador if-else se puede sustituir por el operador condicional '?:':


(expresión1)? expresión2 : expresión3

Si el valor de la expresión1 es distinto de 0 (verdadero), el resultado de la


expresión entera será equivalente al resultado obtenido de laexpresión2. De lo
contrario, si la expresión1 es 0 (falso), el resultado de la expresión entera será
equivalente al resultado obtenido de laexpresión3. Por ejemplo:
maximum = (a>b)? a : b // A la variable maximum se le asigna el
// valor de la variable mayor(a o b)
Operador Switch
A diferencia de la sentencia if-else que selecciona entre dos opciones en el
programa, el operador switch permite elegir entre varias opciones. La sintaxis
de la sentencia switch es:
switch (selector) // Selector es de tipo char o int
{
case constante1:
operación1 // El grupo de operadores que se ejecutan si
... // el selector y la constante1 son equivalentes

break;

case constante2:

operación2 // El grupo de operadores se ejecuta si


... // el selector y la constante2 son equivalentes

break;
...
default:

operación_esperada // El grupo de operadores que se ejecuta si


... // ninguna constante equivale al selector
break;
}

La operación switch se ejecuta de la siguiente manera: primero se ejecuta el


selector y se compara con la constante1. Si coinciden, las sentencias que
pertenecen a ese bloque se ejecutan hasta llegar a la palabra clave break o
hasta el final de la operación switch. Si no coinciden, el selector se compara
con la constante2. Si coinciden, las sentencias que pertenecen a ese bloque se
ejecutan hasta llegar a la palabra clave break etc. Si el selector no coincide con
ninguna constante, se ejecutarán las operaciones que siguen al operador
default. También es posible comparar una expresión con un grupo de
constantes. Si coincide con alguna de ellas, se ejecutarán las operaciones
apropiadas:
switch (días) // La variable días representa un día de la semana.
{ // Es necesario determinar si es un día laborable o no lo es
case1:case2:case3:case4:case5: LCD_message = 'Día laborable'; break;
case6:case7: LCD_message = 'Fin de semana'; break;
default:LCD_message_1 = 'Elija un día de la semana'; break;
}

La palabra clave de C ‘break’ se puede utilizar en cualquier tipo de bloques. Al


utilizar ‘break’, es posible salir de un bloque aunque la condición para su final
no se haya cumplido. Se puede utilizar para terminar un bucle infinito, o para
forzar un bucle a terminar antes de lo normal.

BUCLES
A menudo es necesario repetir una cierta operación un par de veces en el
programa. Un conjunto de comandos que se repiten es denominado un bucle
de programa. Cuántas veces se ejecutará, es decir cuánto tiempo el programa
se quedará en el bucle, depende de las condiciones de salir del bucle.

Bucle While
El bucle while se parece a lo siguiente:
while(expresión){
comandos
...
}

Los comandos se ejecutan repetidamente (el programa se queda en el bucle)


hasta que la expresión llegue a ser falsa. Si la expresión es falsa en la entrada
del bucle, entonces el bucle no se ejecutará y el programa continuará desde el
fin del bucle while. Un tipo especial del bucle de programa es un bucle infinito.
Se forma si la condición sigue sin cambios dentro del bucle. La ejecución es
simple en este caso ya que el resultado entre llaves es siempre verdadero
(1=verdadero), lo que significa que el programa se queda en el mismo bucle:
while(1){ // En vez de "while(1)", se puede escribir "while(true)"
... // Expresiones encerradas entre llaves se ejecutarán
... // repetidamente (bucle infinito)
}

Bucle For
El bucle for se parece a lo siguiente:
for(expresión_inicial; expresión_de_condición; cambiar_expresión) {
operaciones
...
}

La ejecución de esta secuencia de programa es similar al bucle while, salvo que


en este caso el proceso de especificar el valor inicial (inicialización) se realice
en la declaración. La expresión_ inicial especifica la variable inicial del bucle,
que más tarde se compara con la expresión_ de_condición antes de entrar al
bucle. Las operaciones dentro del bucle se ejecutan repetidamente y después
de cada iteración el valor de la expresión_inicial se incrementa de acuerdo con
la regla cambiar_expresión. La iteración continúa hasta que la
expresión_de_condición llegue a ser falsa.
for(k=0; k<5; k++) // La variable k se incrementa 5 veces (de 1 a 4) y
operación // cada vez se repite la expresión operación
...

La operación se ejecutará cinco veces. Luego, al comprobar se valida que la


expresión k<5 sea falsa (después de 5 iteraciones k=5) y el programa saldrá
del bucle for.

Bucle Do-while
El bucle do-while se parece a lo siguiente:
do
operación
while (cambiar_condición);
La expresión cambiar_condición se ejecuta al final del bucle, que significa que
operación se ejecuta como mínimo una vez sin reparar en que si la condición
es verdadera o falsa. Si el resultado es distinto de 0 (verdadero), el
procedimiento se repite. Todos los siguientes ejemplos son equivalentes. Esta
parte del código visualiza "hello" en un LCD 10 veces con un retardo de un
segundo. Note que en este ejemplo se utilizan funciones predefinidas, que se
encuentran en las librerías del compilador mikroC PRO for PIC. No obstante le
aconsejamos que no trate de entenderlas en detalle. Su comportamiento
general dentro del bucle se explica por medio de los comentarios.
i = 0; // Inicialización del contador

while (i<10) { // Condición


Lcd_Out(1,3,"hello"); // Visualizar “hello” en el LCD
Delay_ms(1000); // Retardo de 1000 ms
Lcd_Cmd(_LCD_CLEAR); // Borrar el LCD
Delay_ms(500); // Retardo de 500ms
i++; // Contador se incrementa
}
for(i=0; i<10; i++) { // Inicialización, condición, incremento
Lcd_Out(1,3,"hello"); // Visualizar “hello” en el LCD
Delay_ms(1000); // Retardo de 1000 ms
Lcd_Cmd(_LCD_CLEAR); // Borrar el LCD
Delay_ms(500); // Retardo de 500ms
}
i = 0; // Inicialización del contador
do {
Lcd_Out(1,3,"hello"); // Visualizar “hello” en el LCD
Delay_ms(1000); // Retardo de 1000 ms
Lcd_Cmd(_LCD_CLEAR); // Borrar LCD
Delay_ms(500); // Retardo de 500ms
i++; // Contador se incrementa
}
while (i<10); // Condición

SENTENCIAS DE SALTO

SENTENCIA BREAK
A veces es necesario detener y salir de un bucle dentro de su cuerpo. La
sentencia break se puede utilizar dentro de cualquier bucle (while, for, do
while) y en las sentencias switch también. En éstas la sentencia break se
utiliza para salir de las sentencias switch si la condición case es verdadera. En
este ejemplo, “Esperar” está parpadeando en la pantalla LCD hasta que el
programa detecte un uno lógico en el pin 0 del puerto PORTA.
while(1){ // Bucle infinito
if(PORTA.F0 == 1) // Probar si el estado lógico del pin 0 del puerto
break; // PORTA es 1; si equivale, salir del bucle
Lcd_Out(1,3,"Esperar"); // Visualizar “Esperar” en el LCD
Delay_ms(1000); // Retardo de 1000 ms
Lcd_Cmd(_LCD_CLEAR); // Borrar LCD
Delay_ms(500); // Retardo de 500ms
}
SENTENCIA CONTINUE
La sentencia continue colocada dentro de un bucle se utiliza para saltar una
iteración. A diferencia de la sentencia break, el programa se queda dentro del
bucle y las iteraciones continúan.
// Si x=7, puede ocurrir una división por 0.
// continue se utiliza aquí para evitar esta situación.
x=1;
while (x<=10) {
if (x == 7) { // saltar x=7 para evitar división por 0
Lcd_Cmd(_LCD_CLEAR);
Lcd_Out(1,3,"Division by 0");
Delay_ms(1000);
x++;
continue; // Después de esta línea, saltar a la sentencia while con x=8
}

a = 1/(x-7); // Esta división generará un error si x=7

/* Muchas operaciones pueden ocurrir aquí */

Lcd_Out(1,3,"Division is OK"); // Poner este mensaje en el LCD


Delay_ms(1000);
x++;
}

SENTENCIA GOTO
La sentencia goto le permite hacer un salto absoluto al otro punto en el
programa. Esta característica se debe utilizar con precaución ya que su
ejecución puede causar un salto incondicional sin hacer caso a todos los tipos
de limitaciones de anidación. El punto destino es identificado por una etiqueta,
utilizada como un argumento para la sentencia goto. Una etiqueta consiste en
un identificador válido seguido por un colon (:).
...
if(CO2_sensor) goto aire acondicionado; // Si se consta que el valor
... // de la variable CO2_sensor =1
// hacer salto a la línea de programa
// Aire acondicionado
...
Aire acondicionado: // Desde aquí sigue la parte del código que se
ejecutará
// en caso de una concentración de CO2 demasiado
alta
... // en el ambiente

TIPOS DE DATOS AVANZADOS


MATRICES
Una matriz es una lista de elementos del mismo tipo colocados en localidades
de memoria contiguas. Cada elemento es referenciado por un índice. Para
declarar una matriz, es necesario especificar el tipo de sus elementos
(denominado tipo de matriz), su nombre y el número de sus elementos
encerrados entre corchetes. Todos los elementos de una matriz tienen el
mismo tipo.
tipo_de_matriz nombre_de_matriz [nº_de_elementos];

Los elementos de una matriz se identifican por su posición. En C, el índice va


desde 0 (el primer elemento de una matriz) a N-1 (N es el número de
elementos contenidos en una matriz). El compilador tiene que “saber” cuántas
localidades de memoria debe alojar al declarar una matriz. El tamaño de una
matiz no puede ser una variable. Por eso, se pueden utilizar dos métodos:
// método 1
int display [3]; // Declaración de la matriz display capaz de contener 3 enteros
// método 2
const DÍGITOS = 5;
char Matriz_nueva[DÍGITOS]; // Declaración de la matriz Matriz_nueva
// capaz de contener 5 enteros

Una matriz se puede inicializar a la vez que se declara, o más tarde en el


programa. En ambos casos, este paso se realiza al utilizar llaves:

int array_1[3] = {10,1,100};

Para leer o modificar un elemento de matriz del ejemplo anterior, basta con
introducir su índice encerrado entre corchetes:
/* Se supone que a ha sido declarado anteriormente como un entero */

a = array_1[0]; // A la variable a se le asigna el valor del miembro de matriz

// con índice 0 (a = 10)


array_1[2] = 20; // Miembro de matriz array_1[2] es modificado (nuevo valor es 20)

El siguiente programa cambia el orden de los elementos de una matriz. Note


que el índice se puede expresar mediante variables y operaciones básicas.
void main() {
const MUESTRAS_DE_AGUA = 4; // Valor de la constante MUESTRAS_DE_AGUA es 4
int i, temp; // Variables i y temp son de tipo int
int profunidad_de_sonda [MUESTRAS_DE_AGUA] = {24,25,1,1987};// Todos

// los miembros de la matriz profundidad


// de sonda son de tipo int

for(i=0;i<(MUESTRAS_DE_AGUA/2);i++){ // Bucle se ejecuta 2 veces


temp = profundiad_de_sonda [i]; // temp se utiliza para guardar un valor
// temporalmente
profundiad_de_sonda [i] = profundiad_de_sonda [MUESTRAS_DE_AGUA-1-i];
profundiad_de_sonda [MUESTRAS_DE_AGUA-1-i] = temp;
}

// Aquí tenemos: profundidad_de_sonda [MUESTRAS_DE_AGUA] = {1987,1,25,24}


}
MATRICES BIDIMENSIONALES
Aparte de las matrices unidimensionales que se pueden interpretar como una
lista de valores, el lenguaje C le permite declarar matrices multidimensionales.
En esta parte vamos a describir sólo las matrices bidimensionales, también
denominadas tablas o matrices. Una matriz bidimensional se declara al
especificar el tipo de dato de matriz, el nombre de matriz y el tamaño de cada
dimensión.
tipo_de_matriz nombre_de_matriz [número_de_filas] [número_de_columnas];

En la declaración de esta matriz número_de_filas y número_de_columnas


representan el número de filas y columnas en las que consiste una tabla,
respectivamente. Vea la siguiente matriz bidimensional:
int Tabla [3][4]; // Tabla se define de modo que tenga 3 filas y 4 columnas

Esta matriz se puede representar en la forma de una tabla. 


tabla[0][0] tabla[0][1] tabla[0][2] tabla[0][3]

tabla[1][0] tabla[1][1] tabla[1][2] tabla[1][3]

tabla[2][0] tabla[2][1] tabla[2][2] tabla[2][3]


 Similar a las matrices unidimesionales, es posible asignar los valores a los
elementos de una tabla en la línea de declaración. La asignación debe ser
realizada línea a línea como en el siguiente ejemplo. Como hemos visto
anteriormente, esta matriz tiene dos filas y tres columnas:
int Tabla [2][3]= { {3,42,1},{7,7,19} };

La matriz anterior se puede representar también en la forma de una tabla de


valores: 
3 42 1

7 7 19

PUNTEROS
Un puntero es una variable destinada a recibir una dirección. Un puntero
“apunta” a una localidad de memoria, referenciada por una dirección. En C, la
dirección de un objeto se puede obtener por medio un operador unitario &.
Para acceder al contenido de la memoria en una dirección específica (también
llamado objeto apuntado), se utiliza un operador de indirección (*).
'&n' es la dirección de la localidad de memoria 'n'. '*(&n)' es el contenido de la
dirección '(&n)', o sea de 'n'. Para declarar un puntero, se debe que especificar
el tipo de la variable apuntada:
tipo_de_variable *puntero;

En esta etapa, el puntero mi_puntero apunta al valor almacenado en esta


localidad de memoria, o sea, a un valor desconocido. Así que, una inicialización
es muy recomendable:
puntero = &variable;

Ahora, puntero contiene la dirección de variable. Para acceder al contenido de


la variable apuntada, debe utilizar ‘*’. El siguiente ejemplo muestra el
contenido de memoria dependiendo de la acción realizada por medio del
puntero.

Los punteros son muy útiles para manejar las matrices. En este caso, un
puntero se utilizará para apuntar al primer elemento de una matriz. Debido al
hecho de que es posible realizar operaciones básicas sobre los punteros
(aritmética de punteros), es fácil manejar los elementos de una matriz. Fíjese
en la diferencia entre ‘*v+1’ y ‘*(v+1)’ en el siguiente ejemplo:
short int voltio[3] = {0,5,10};
short int *v;
v = &(voltio[0]); // v contiene la dirección de voltio[0]
*(v+1) = 2; // voltio[1] = 2
voltio[2] = *v+1; // tab[2] = 1 (tab[0] + 1)
*(v+2) = *(v+1); // voltio[2] = 2
v++; // v contiene la dirección de voltio[1]
*v = 1; // voltio[1] = 1

 Los punteros también pueden ser declarados con el prefijo ‘const’. En este caso, su valor no puede
ser modificado después de la inicialización, similar a una constante.
 A diferencia de C, el mikroC no admite alojamiento dinámico.

ESTRUCTURAS
Ya hemos visto cómo agrupar los elementos dentro de matrices. No obstante,
al utilizar este método todos los elementos deben ser del mismo tipo. Al utilizar
estructuras, es posible agrupar diferentes tipos de variables bajo el mismo
nombre. Las variables dentro de una estructura se le denominan los miembros
de la estructura. Las estructuras de datos se declaran al utilizar la siguiente
sintaxis:
struct nombre_de_estructura {
tipo1_de_miembro1 miembro1;
tipo2_de_miembro2 miembro2;
tipo3_de_miembro3 miembro3;
..
};

No es posible inicializar variables dentro de la declaración de la estructura de


datos:
struct generador {
int voltaje;
char corriente;
};

Entonces, podrá definir los objetos denominados ‘turbina’ en el código. A cada


uno de estos tres objetos (turbinas) se le asignan las variables ‘corriente’ y
‘voltaje’.
struct generadores turbina_1, turbina_2, turbina_3;

Para acceder a las variables, es preciso utilizar el operador '.'


turbina_3.voltaje = 150;
turbina_3.corriente = 12;

Por supuesto, igual que al utilizar los punteros, todavía se le permite realizar
operaciones por medio de operadores y sentencias definidos en las partes
anteriores. Si está familiarizado con el lenguaje C, recuerde que mikroC no
admite la inicialización de los miembros de estructura por medio de las llaves.
Por ejemplo, ‘conjunto_1 ={15,‘m’};’ devuelve un error en mikroC.

FUNCIONES

Una función es una subrutina que contiene una lista de sentencias a realizar.
La idea principal es dividir un programa en varias partes utilizando estas
funciones para resolver el problema inicial con más facilidad. Además, las
funciones nos permiten utilizar las destrezas y el conocimiento de otros
programadores. Una función se ejecuta cada vez que se llame dentro de otra
función. En C, un programa contiene como mínimo una función, la función
main(), aunque el número de funciones es normalmente mayor. Al utilizar
funciones el código se hace más corto ya que es posible llamar una función
tantas veces como se necesite. En C, el código normalmente consiste en
muchas funciones. No obstante, en caso de que su programa sea muy corto y
simple, puede escribir todas las sentencias dentro de la función principal.

FUNCIÓN PRINCIPAL
La función principal main() es una función particular puesto que es la que se
ejecuta al iniciar el programa. Además, el programa termina una vez
completada la ejecución de esta función. El compilador reconoce
automáticamente esta función y no es posible llamarla por otra función. La
sintaxis de esta función es la siguiente:
void main (void) {

/* el primer 'void' significa que main no devuelve ningún valor. El segundo


'void' significa que no recibe ningún valor. Note que el compilador
también admite la siguiente sintaxis: 'main()' o 'void main()' o
'main(void)' */

..

/* --- Introduzca su programa aquí --- */

.
};

Esto significa que f es una función que recibe un número real x como
parámetro y devuelve 2*x-y. La misma función en C se parece a lo siguiente:
float f (float x, float y) // variables flotantes x y y se pueden utilizar en f
{
float r; // declarar r para almacenar el resultado
r = 2*x - y; // almacenar el resultado del cálculo en r
return r; // devolver el valor de r
}

Cada función debe ser declarada apropiadamente para poder interpretarla


correctamente durante el proceso de compilación. La declaración contiene los
siguientes elementos:
 Tipo de resultado (valor devuelto): tipo de dato del valor devuelto
 Nombre de función: es un identificador que hace posible llamar a una función.
 Declaración de parámetros se parece a la declaración de variable regular (por ejemplo: float x).
Cada parámetro consiste en una variable, constante, puntero o matriz, precedidos por la etiqueta de
tipo de dato. Se utilizan para pasar la información a la función al llamarla. Los parámetros
diferentes están delimitados por comas.
 Cuerpo de función: bloque de sentencias dentro de llaves
Una función se parece a lo siguiente:
tipo_de_resultado nombre_de_función (tipo argumento1, tipo argumento2,...)
{
Sentencia;
Sentencia;
...
return ...
}

Note que una función no necesita parámetros (función main() por ejemplo),
pero debe estar entre paréntesis. En caso contrario, el compilador
malinterpretaría la función. Para hacerlo más claro, puede sustituir el espacio
en blanco encerrado entre paréntesis por la palabra clave void: main (void).

VALOR DEVUELTO
Una función puede devolver un valor (esto no es obligatorio) por medio de la
palabra clave return. Al llegar a return, la función evalúa un valor (puede ser
una expresión) y lo devuelve a la línea de programa desde la que fue llamada.
return r; // Devolver el valor contenido en r
return (2*x - y); // Devolver el valor de la expresión 2*x-y
Una función no puede devolver más de un valor, pero puede devolver un
puntero o una estructura. Tenga cuidado al utilizar matrices y punteros. El
siguiente ejemplo es un error típico:
int *reverse(int *tab) // Esta función debe devolver una matriz r
{ // cuyo contenido está en orden inverso con
// respecto a la matriz tab
int r[DIM]; // Declaración de una nueva matriz denominada r
int i;
for(i=0;i<DIM;i++) // Bucle que copia el contenido de tab en r
r[i] = tab[DIM-1-i]; // al invertir el orden

return r; // Devolver el valor r


}

En realidad, el compilador reserva memoria para el almacenamiento de


variables de la función reverse sólo durante su ejecución. Una vez completada
la ejecución de reverse, la localidad de memoria para la variable i o para la
matriz r ya no está reservada. Esto significa que la dirección que contiene los
valores de i o r[] está libre para introducir datos nuevos. Concretamente, la
función devuelve sólo el valor &r[0], así que sólo el primer elemento de la
matriz tab será almacenado en la memoria. Las demás localidades de
memoria, tales como &tab[1], &tab[2], etc. serán consideradas por el
compilador como espacios en blanco, o sea, estarán listas para recibir los
nuevos valores. Para escribir esta función es necesario pasar la matriz r []
como parámetro (vea la subsección Pasar los parámetros). La función puede
contener más de una sentencia return. En este caso, al ejecutar la primera
sentencia return, la función devuelve el valor correspondiente y se detiene la
ejecución de la función.
float abs (float x, float y) // Devolver el valor absoluto de 2*x-y
{
if ((2*x - y) >= 0)
return (2*x - y);
else
return (-2*x + y);
}

Si la función no devuelve ningún valor, la palabra void debe ser utilizada como
un tipo de resultado en la declaración. En este caso, la sentencia return no
debe ser seguida por ninguna expresión. Puede ser omitida como en el
siguiente ejemplo:
void wait_1 (unsigned int a)
{
cnt ++; // Incremento de una variable global cnt
Delay_ms(a) ; // Ejecución de la función Delay_ms
} // Note que Delay_ms no devuelve nada

DECLARAR PROTOTIPOS DE FUNCIONES


Para utilizar una función, el compilador debe ser consciente de su presencia en
el programa. En la programación en C, los programadores normalmente
primero escriben la función main() y luego las funciones adicionales. Para
avisar al compilador de la presencia de las funciones adicionales, se requiere
declarar los prototipos de funciones en el principio de programa antes de la
función main(). Un prototipo de función está compuesto por:
 tipo de resultado
 nombre de función
 tipos de parámetros
 un punto y coma (;)
El prototipo de la función main no necesita ser declarado.
float f (float, float);

/* no es obligatorio escribir los nombres de los parámetros. Este prototipo


informa al compilador: en el programa se utilizará la función f,
que utiliza dos parámetros de tipo float y devuelve el resultado del tipo
float. */

LLAMAR UNA FUNCIÓN


Mientras una función es definida y su prototipo declarado, se puede utilizar en
culquier parte de programa. Sin embargo, como la funciónmain es 'raiz' del
programa, no puede ser llamada de ninguna parte de programa. Para ejecutar
una función, es necesario escribir su nombre y los parámetros asociados. Vea
los siguientes ejemplos:
float resultado,a,b; // resultado,a,b,time deben coincidir con los tipos
// definidos
int time = 100; // en la declaración de las funciones f y wait_1
a = 10.54;
b = 5.2;
resultado = f(a,b); // Ejecutar la función f por medio de los parámetros a y b

// El valor devuelto se le asigna a la variable resultado


pausa_1(tiempo); // Ejecutar la función pausa_1 por medio de la variable tiempo
funciónX(); // Ejecutar la función funciónX (sin parámetros)

Cuando se llama una función, el programa salta a la función llamada, la


ejecuta, después vuelve a la línea desde la que fue llamada.

PASAR LOS PARÁMETROS


Al llamar una función, se le pasan los parámetros. En C existen dos formas
diferentes para pasar parámetros a una función. El primer método,
denominado ‘paso por valor’, es el más fácil. En este caso, los parámetros se
pueden considerar como variables locales de la función. Cuando se llama una
función, el valor de cada parámetro se copia a un nuevo espacio de memoria
reservado durante la ejecución de la función. Como los parámetros se
consideran como variables locales por el compilador, sus valores pueden ser
modificados dentro de la función, pero sus modificaciones no se quedan en la
memoria una vez completada la ejecución de la función. Tenga en cuenta de
que la función devuelve un valor, y no una variable. Además, se crean copias
de los valores de los parámetros, por lo que sus nombres en la función f
pueden ser diferentes de los parámetros utilizados en la main(). La mayor
desventaja del ‘paso por el valor’ es que la única interacción que una función
tiene con el resto del programa es el valor devuelto de un solo resultado (o la
modificación de las variables globales). El otro método, denominado 'paso por
dirección' le permite sobrepasar este problema. En vez de enviar el valor de
una variable al llamar a función, se debe enviar la dirección de memoria del
valor. Entonces, la función llamada será capaz de modificar el contenido de
esta localidad de memoria.
// Función 'sort'ordena los miembros de la matriz por valor ascendente
// y devuelve el miembro con máximo valor

int sort(int *); // Prototipo de función


const SIZE = 5; // Número de miembros a ordenar

void main() {
int maximum, input[SIZE] = {5,10,3,12,0}; // Declaración de variables en la matriz
maximum = sort(input); // Llamar a función y asignarle el máximo
// valor a la variable maximum
}

int sort(int *sequence) {


int i, temp, permut; // Declaración de variables
permut = 1; // Bandera de bit indica que se ha hecho una permutación

while(permut!=0) { // Quedarse en el bucle hasta reinicar la bandera


permut = 0; // Bandera reiniciada
for(i=0;i<SIZE-1;i++) { // Comparar y oredenar los miembros de la
// matriz (dos a dos)
if(sequence [i] > sequence[i+1]){
temp = sequence [i];
sequence[i] = sequence[i+1];
sequence[i+1] = temp;
permut = 1; // Se ha hecho una permutación, bandera de bit
//se pone a uno
}
}
}

return sequence[SIZE-1]; // Devolver el valor del último miembro

} // que es al mismo tiempo el miembro con el máximo valor

En este ejemplo, por medio de una función se realizan dos operaciones: ordena
los miembros de la matriz por valor asdendente y devuelve el máximo valor.
Para utilizar una matriz en una función es necesario asignar la dirección a la
matriz (o a su primer miembro). Vea el siguiente ejemplo:
float método_1(int[]); // Declaración de prototipo de la función Método_1
float método_2(int*); // Declaración de prototipo de la función Método_2

const NÚMERO_DE_MEDICIONES = 7; // Número de los miembros de la matriz

void main()
{
double promedio1, promedio2; // Declaración de las variables promedio1
// y promedio2
int voltaje [NÚMERO_DE_MEDICIONES] = {7,8,3,5,6,1,9}; // Declaración de la
// matriz voltaje
promedio1 = método_1(&voltaje[0]); // Parámetro de la función es la dirección
// del primer miembro
promedio2 = método_2(voltaje); // Parámetro de la función es la dirección de
// la matriz
}
//××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
float método_1(int voltaje[]) // Inicio de la función método_1
{
int i, suma; // Declaración de las variables locales i y suma

for(i=0;i<NÚMERO_DE_MEDICIONES;i++) // Cálculo del valor promedio de voltaje


suma += voltaje[i]; // Es posible utilizar *(voltaje+i)en vez de
voltaje[i]

return(suma/NÚMERO_DE_MEDICIONES);
}

//××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
float método_2 (int *voltaje) //Inicio de la función método_2
{
int i, suma; // Declaración de las variables locales i y suma

for(i=0;i<NÚMERO_DE_MEDICIONES;i++) // Cálculo del valor promedio de voltaje


suma += *(voltaje+i); // Es posible utilizar voltaje[i] en vez de
*(voltaje+i)

return(suma/NÚMERO_DE_MEDICIONES);
}

Las funciones 'método_1' y 'método_2' son completamente equivalentes. Las dos


devuelven el valor promedio de la matriz 'voltaje[]'. Después de declararla, la dirección
del primer miembro se puede escribir como 'voltaje' o '&voltaje[0]'.

CARACTERÍSTICAS PRINCIPALES DEL PREPROCESADOR


El preprocesador es un programa que procesa el código antes de que pase por el
compilador. Funciona bajo el control de las líneas de comando del preprocesador
denominadas directivas. Las directivas del preprocesador se colocan en el código
fuente, normalmente en el principio del archivo. Antes de pasar por el compilador, el
código fuente se examina por el preprocesador que detecta y ejecuta todas las
directivas del preprocesador. Las directivas del preprocesador siguen a una regla de la
sintaxis especial, empiezan por un símbolo ‘#’ y no requieren ningún punto y coma al
final (;).

DIRECTIVAS DEL PREPROCESADOR


La siguiente tabla contiene un conjunto de directivas del preprocesador
frecuentemente utilizadas: Las directivas del preprocesador se pueden dividir en tres
categorías: 

DIRECTIV
FUNCIONES
AS

#include Define una sustitución de macro

#undef Quita una definición de nombre de macro

#define Especifica un archivo a ser incluido

#ifdef Prueba para definición de macro


#endif Especificar el final de #if

#ifndef Prueba si una macro no está definida

#if Prueba las condiciones de compilar

#else Especifica alternativas cuando la prueba de #if falla

#elif Especifica alternativas cuando más de dos condiciones se necesitan

 Definiciones de macro
 Inclusiones de archivos
 Control de compilación
Ahora, vamos a presentar sólo las directivas del preprocesador utilizadas con más
frecuencia. Sin embargo, no es necesario saber todas ellas para programar
microcontroladores. Sólo tenga en cuenta que el preprocesador es una herramienta
muy poderosa para los programadores avanzados en C, especialmente para el control
de compilación.

DIRECTIVAS DEL PREPROCESADOR PARA DEFINIR MACROS


Por medio de los macros es posible definir las constantes y ejecutar funciones básicas.
Una sustitución de macro es un proceso en el que un identificador del programa se
sustituye por una cadena predefinida. El preprocesador sustituye cada ocurrencia del
identificador en el código fuente por una cadena. Después de la sustitución, el código
será compilado normalmente. Esto significa que el código sustituido debe respetar la
sintaxis del mikroC. La acción se realiza por medio de la directiva '#define'.
#define PI 3.14159 // Sustitución simple, PI será sustituido por
// el valor 3.14159 en todas las partes del programa

También puede utilizar los parámetros para realizar substituciones más


complejas:
#define VOLUMEN (D,H) (((D/2)*(D/2)*PI))*H // Macro con parámetros

Entonces, en el código, la siguiente sentencia:


Tanque_1 = VOLUMEN (Diámetro,altura);

será sustituida por:


Tanque_1 = (((Diámetro/2)*(Diámetro/2)*PI)*altura;

Por medio de la directiva #undef es posible quitar una definición de nombre de macro.
Así se especifica que la substitución que se ha definido anteriormente ya no va ocurrir
en el siguiente código. Esto es útil cuando usted quiere restringir la definición sólo a
una parte particular del programa.
#undef TANQUE // Quitar la definición del macro VOLUMEN

INCLUSIÓN DE ARCHIVOS
La directiva de preprocesador #include copia un archivo específico en el código fuente.
El código incluido debe observar la sintaxis de C para ser compilado correctamente.
Hay dos formas de escribir estas directivas. En el primer ejemplo, sólo el nombre de
archivo se especifica, así que el preprocesador lo buscará dentro del archivo include.
En el segundo ejemplo, se especifica la ruta entera, así que el archivo estará
directamente incluido (este método es más rápido).
#include <nombre_de_archivo> // Se especifica sólo el nombre del archivo
#include "C:\Ruta\nombre_de_archivo.h" // Se especifica la localidad
// exacta del archivo

También podría gustarte