You are on page 1of 17

Introducción al Lenguaje C

Ismael Potolicchio

22 de marzo de 2018

Técnicas Digitales II
Departamento de Electrotecnia
Facultad de Ingenierı́a
Índice
1. Introducción al Lenguaje C 1
1.1. ¿Por qué utilizarlo en microcontroladores? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2. Primer programa en C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

2. El preprocesador 2

3. Variables, identificadores y tipos de datos 2

4. Operadores 3
4.1. Operadores aritméticos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
4.2. Operadores de asignación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
4.3. Operadores de incremento y decremento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
4.4. Operadores relacionales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
4.5. Operadores lógicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
4.6. Operadores de manejo de bits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
4.7. Prioridad de ejecución . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
4.8. Conversión de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

5. Estructuras de control 8
5.1. Estructuras condicionales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
5.1.1. Estructura alternativa if-else . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
5.1.2. Estructura de selección switch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
5.2. Estructuras repetitivas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
5.2.1. Estructura while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
5.2.2. Estructura do-while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
5.2.3. Estructura for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
5.3. Transferencias o saltos incondicionales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
5.3.1. Break . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
5.3.2. Continue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
5.3.3. Go to . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
5.3.4. Return . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

6. Funciones 12
6.1. Prototipos de funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

2
1. Introducción al Lenguaje C
El lenguaje de programación C fue creado por Dennis Ritchie en 1972 en Bell Telephone Laboratories, con
el objetivo de reescribir un sistema operativo, el UNIX, en un lenguaje de alto nivel, para poder adaptarlo
(portarlo) a diferentes arquitecturas. Por este motivo sus creadores se propusieron metas de diseño especiales,
tales como:

Posibilidad de acceder al “bajo nivel” (poder utilizar todos los recursos del hardware).

Código generado eficiente en memoria y tiempo (programas pequeños y veloces).

Compilador portable (implementable en todas las arquitecturas).

La primera definición oficial del lenguaje fue dada en 1978 por Brian Kernighan y Dennis Ritchie en su libro
“El lenguaje de programación C”. Este lenguaje fue llamado “C K&R”. En 1983 se creó el comité ANSI que
en 1988 estableció el standard ANSI C, con algunas reformas sobre el C K&R. Simultáneamente Kernighan y
Ritchie publicaron la segunda edición de su libro, describiendo la mayor parte de las caracterı́sticas del ANSI
C. Actualmente existen implementaciones de C para todas las arquitecturas y sistemas operativos, y es uno de
los lenguajes más utilizado para la programación de sistemas.

1.1. ¿Por qué utilizarlo en microcontroladores?


Principalmente se lo utiliza en la programación de microcontroladores dado que la mayorı́a de los fabricantes
proveen compiladores que soportan este lenguaje. Además, el lenguaje C permite abstraerse del hardware y a
la vez, si se requiere, acceder a él al mismo nivel que Assembler. Una de las mayores desventajas de C es que
es menos eficiente que este último, es decir que un programa en C ocupa más memoria en el microcontrolador
que un programa hecho en Assembler.
Si bien el lenguaje C fue pensado y diseñado para ser portable entre las distintas arquitecturas de computadoras
(recordar que fue desarrollado para programar el sistema operativo UNIX), esto no sucede con los distintos
compiladores de diferentes fabricantes de microcontroladores. Cada fabricante establece dentro de su registros
y estructuras únicas para cada microcontrolador por lo que las bibliotecas no son portables entre compiladores.

1.2. Primer programa en C


En la figura 1 se puede ver un programa en C muy sencillo. Este sirve para calcular el área de un cı́rculo.

Figura 1: Estructura de un programa básico en C.

1
Obviando las dos primeras lı́neas del programa anterior, se puede observar que el mismo comienza con la
función main () cuyo cuerpo principal es un conjunto de sentencias delimitadas por dos llaves, una inmediata-
mente después de la declaración main () “{”, y otra que finaliza el listado “}”. Dentro de este listado existe
la declaración de dos variables en punto flotante: radio y area. Esta sentencia, como todas las del lenguaje C,
finaliza con “;”. Este sı́mbolo le indica al compilador el final de una lı́nea de código y el inicio de la siguiente.
Luego, viene una lı́nea de comentarios. Estos sirven para documentar el código, explicar que hace alguna sen-
tencia, etc. Existen los comentarios de lı́nea simple, los cuales comienzan con “//”, como ası́ también los de
múltiples lı́neas, que comienzan con “/*” y finalizan con “*/”. Posteriormente se realiza la asignación de un
valor a la variable radio para luego calcular el valor del área de un cı́rculo. Finalmente, se imprime por pantalla
el valor del área, utilizando la función printf().

2. El preprocesador
El compilador C tiene un componente auxiliar llamado preprocesador, que actúa en la primera etapa del
proceso de compilación. Su misión es buscar en el texto del programa entregado al compilador ciertas órdenes,
llamadas directivas, que le indican que debe realizar alguna tarea a nivel de texto. Esto puede significar incluir
archivos headers, reemplazar cadenas de caracteres, entre otras. Una vez realizadas estas tareas, el preprocesador
entrega el texto resultante al resto de las etapas de compilación.Se listan a continuación las directivas más usadas.

#define: Si una misma constante o expresión aparece repetida varias veces en un texto, y es posible que
su valor deba cambiarse en algún momento, es muy conveniente definirla con un sı́mbolo y especificar su
valor sólo una vez. Para esto se puede utilizar la directiva #define. En el ejemplo de la figura 1 se utiliza
para definir el valor de PI.

#include: Se utiliza para incluir el texto de un archivo dentro de otro. Es decir, el preprocesador sustituye
la lı́nea #include header1, por el contenido del archivo header1. En el ejemplo de la figura 1, se utiliza
esta directiva para incluir el archivo stdio.h, el cual nos permite luego hacer uso de la función printf().

Las directivas pueden aparecer en cualquier lugar del programa, pero sus efectos se ponen en vigor recién a
partir del punto del programa en que aparecen y hasta el final del programa. Es decir, un sı́mbolo sólo puede
utilizarse después de la aparición de la directiva que la define, y no antes. Las directivas para incluir archivos
suelen darse al principio de los programas, porque en general se desea que su efecto alcance a todo el archivo
en el cual se están incluyendo. Por esta razón los archivos preparados para ser incluı́dos se llaman archivos de
cabecera o headers.

3. Variables, identificadores y tipos de datos


Una variable es un espacio de memoria reservado (para el caso de los microcontroladores, en la memoria
del mismo) para contener valores que pueden cambiar durante la ejecución de un programa. Un identificador
es el nombre que se le asigna a una variable. Adicionalmente, una variable se clasifica según el tipo de dato,
que es lo que le otorga dos caracterı́sticas muy importantes: el tamaño que va a ocupar y el tipo de valores que
puede almacenar. Se dice que una variable se declara cuando se le asigna un tipo de dato y un identificador.
Siempre se debe declarar una variable antes de utilizarla. En la figura 1 se declaran dos variables: radio y area,
las cuales son del tipo float, es decir que dentro de ellas se pueden almacenar valores reales o punto flotante. Los
identificadores o nombres de variables deben cumplir ciertas condiciones, las cuales se listan a continuación:

El primer carácter debe ser alguno de los siguientes: “A” a “Z” o“a” a “z” o “ ”.

Los siguientes caracteres pueden ser: “A” a “Z” o“a” a “z” o “1” a “9” o “ ”.

Se debe respetar la sensibilidad a las mayúsculas y minúsculas.

No utilizar palabras reservadas, las cuales se muestran en la tabla 1.

2
auto double int struct
break else long switch
case enum register typedef
char extern return union
const float short unsigned
continue for signed void
default goto sizeof volatile
do if static while

Tabla 1: Palabras reservadas en C.

En la tabla 2 se observan los tipos de datos fundamentales que se pueden asignar a las variables y su tamaño
en bits.

TIPO DESCRIPCIÓN BITS


char caracter simple 8
int entero 16
float número de punto flotante de precisión simple 32
double número de punto flotante de precisión doble 64

Tabla 2: Tipos de datos.

A su vez, al declarar una variable, se puede agregar un cualificador, el cual es un modificador del tipo
de dato. Este cualificador cambia el rango de la variable y la signa. En la tabla 3 se muestran las posibles
combinaciones entre tipos de datos fundamentales y cualificadores. Las variables definidas como punto flotante
no llevan cualificadores.

TIPOS DE VARIABLES MÍNIMO MÁXIMO BITS


unsigned char 0 255 8
char , signed char -128 127 8
unsigned short int 0 65535 16
short int, signed short int -32768 32767 16
unsigned int 0 65535 16
int, signed int -32768 32767 16
unsigned long int 0 2ˆ32 -1 32
long int, signed long int -2ˆ31 2ˆ31 -1 32
unsigned long long int 0 2ˆ64 -1 64
long long int, signed long long int -2ˆ63 2ˆ63 -1 64

Tabla 3: Tipo de datos fundamentales combinados con cualificadores.

Siempre debe declararse una variable antes de utilizarla. La forma de hacerlo es asignarle un tipo y un
identificador, tal como se muestra a continuación:

unsigned char Estado;


signed char Buffer[40];
unsigned int indice;
float vector[3];

4. Operadores
Un operador es un sı́mbolo que denota una operación aritmética, lógica u otra operación particular. Cada
operación se realiza sobre uno o más operandos y se caracteriza por la prioridad de ejecución respecto de otra

3
operación y por la asociatividad. Los operadores se clasifican según el tipo de operación que realizan y sobre
qué actúan.

4.1. Operadores aritméticos


Se utilizan en las operaciones aritméticas y siempre devuelven resultados numéricos.

OPERADOR OPERACIÓN
+ adición
- resta
* multiplicación
/ división
% resto de la división

Tabla 4: Operadores aritméticos

char a,b,c,d,e,f; // Se declararan 3 caracteres a, b, c


a = 5; // se inicializa a
b = 4; // se inicializa b
c = a + b; // c = 9
d = a * b; // d = 20
e = b / 2; // e = 2
f = b % 2; // f = 0

4.2. Operadores de asignación


Hay dos tipos de operadores de asignación en el lenguaje C: el operador simple, el cual asigna valores a
variables. Se representa con el caracter “=”. Por ejemplo: a = 8. Por otro lado, también existen los operadores
compuestos, que son especı́ficos para el lenguaje C. Consisten en dos caracteres como se muestra en la tabla 5.
Se utilizan para simplificar la sintaxis y habilitar la ejecución más rápida.

OPERADOR EJEMPLO EXPRESIÓN EQUIVALENTE


+= a += 8 a=a+8
-= a -= 8 a=a-8
*= a *= 8 a=a*8
/= a /= 8 a=a/8
%= a %= 8 a = a% 8

Tabla 5: Operadores de asignación

char a = 5,b = 2; // Se declara e inicializa la variable a


a += 10; // a = a + 10 = 15
b *= 10; // b = b * 10 = 20
b -= 1; // b = b - 1 = 1

4.3. Operadores de incremento y decremento


Las operaciones de incremento y decremento por 1 se denotan con “++” y “- -”. Estos caracteres pueden
preceder o seguir a una variable. En el primer caso, la variable x será incrementada antes de ser utilizada en la
expresión. En el segundo, la variable se utilizará en la expresión antes de ser aumentada. Lo mismo se aplica a
la operación de decremento.

4
OPERADOR EJEMPLO DESCRIPCIÓN
++a Variable “a” es incrementada en 1 y luego usada
++
a++ Variable “a” es usada y luego incrementada por 1
- -b Variable “b” es decrementada en 1 y luego usada
--
b- - Variable “b” es usada y luego incrementada por 1

Tabla 6: Operadores de incremento y decremento

char a, b, c;
a = b = 5;
c = 1 + a++; // c = 6
b = ++c + a; // b = 7 + 6 = 13

4.4. Operadores relacionales


Los operadores relacionales se utilizan en con el propósito de comparar dos valores. En C, si una expresión
es evaluada como falsa, el operador devuelve “0”, mientras que si una operación es evaluada como verdadera,
devuelve “1”. Estos operadores se utilizan en expresiones del tipo “si la expresión es evaluada como verdadera,
entonces...”

OPERADOR DESCRIPCIÓN EJEMPLO CONDICIÓN DE VERACIDAD


> mayor que b>a si “b” es mayor que “a”
>= mayor o igual que b>=a si “b” es mayor o igual que “a”
< menor que b<a si “b” es menor que “a”
<= menor o igual que b<=a si “b” es menor o igual que “a”
== igual que b==a si “b” igual que “a”
!= distinto que b! =a si “b” es distinto de “a”

Tabla 7: Operadores de relacionales

char prop;
char var = 5;
prop = var < 10; // Expresión es evaluada como verdadera, prop = 1

4.5. Operadores lógicos


Hay tres tipos de operaciones lógicas en el lenguaje C: Y (AND) lógico, O (OR) lógico y negación (NOT)
lógica. Los operadores lógicos devuelven verdadero (“1” lógico) si la expresión evaluada es distinta de cero. En
caso contrario, devuelve falso (“0” lógico) si la expresión evaluada equivale a cero. Por ejemplo: 1 && 0 equivale
a realizar una operación lógica AND entre una expresión verdadera (1) y una expresión falsa (0). El resultado
en este caso será un “0” lógico, o sea, falso.

OPERADOR FUNCIÓN LÓGICA


&& AND
|| OR
! NOT

Tabla 8: Operadores lógicos

5
4.6. Operadores de manejo de bits
A diferencia de las operaciones lógicas que se realizan sobre expresiones, las operaciones de manejo de bits
se realizan sobre los bits de un operando. Se enumeran en la siguiente tabla:

OPERADOR DESCRIPCIÓN EJEMPLO RESULTADO


∼ Complemento a uno a=∼b b=5 a=-5
<< Desplazamiento a la izquierda a = b << 2 b=11110011 a=11001100
>> Desplazamiento a la derecha a = b >> 2 b=11110011 a=00111100
& Y lógico para bits c=a & b a=11100011 b=11001100 c=11000000
| O lógico para bits c=a | b a=11100011 b=11001100 c=11101111
ˆ EXOR lógico para bits c=a ˆ b a=11100011 b=11001100 c=00101111

Tabla 9: Operadores de manejo de bits

Se debe destacar que el resultado de la operación de desplazamiento a la derecha depende del signo de la
variable. En caso de que el operando se aplique a una variable sin signo o positiva, se introducirán los ceros en
el espacio vacı́o creado por desplazamiento. Si se aplica a una variable con signo negativo, se introducirá un 1
para mantener el signo correcto de la variable.

4.7. Prioridad de ejecución


Los operadores se agrupan por medio de paréntesis. Si es necesario, se pueden utilizar los paréntesis múltiples.
La prioridad de ejecución se muestran en la siguiente tabla:

PRIORIDAD OPERADORES
Alta ()[]− > .
! + + − − ∗ P untero&P untero
∗/ %
+−
<<>>
<<=>>=
==! =
&
ˆ
|
&&
||
?:
Baja =+=−=∗=/=/=

Tabla 10: Prioridad de ejecución

Los operadores que se encuentran en un renglón superior de la tabla tienen prioridad de ejecución sobre los
que se encuentran en un renglón inferior. En una expresión compleja, formada por varias subexpresiones conec-
tadas por operadores, es peligroso hacer depender el resultado del orden de evaluación de las subexpresiones. Si
los operadores tienen la misma prioridad, la evaluación se hace de izquierda a derecha, pero en caso contrario
el orden de evaluación no queda definido. Por ejemplo, en la expresión:

v = w * x / ++y + z / y;

Se puede contar con que primeramente se ejecutará w *x y sólo entonces x / ++y, porque los operadores de
multiplicación y división tienen la misma prioridad, pero no se puede asegurar que w * x / ++y sea evaluado
antes o después de z / y, lo que hace que el resultado de esta expresión sea indefinido en C. El remedio es
secuencializar la ejecución dividiendo las expresiones en sentencias:

6
a = w * x / ++y;
b = a + z / y;

Lo mostrado en el código anterior es una buena práctica de programación. Se recomienda separar las sucesivas
aplicaciones de operadores en varias lı́neas de código, con el objetivo de establecer de manera clara cuál es el
orden de prioridad a realizar, además de evitar realizar operaciones no deseadas por la asociativadad dada por
el lenguaje C. Otro ejemplo de un resultado erróneo se muestra a continuación:

char a, b, res;
a = 10;
b = 100;
res = a*(a + b); // resultado = 1100
res = a*a + b; // resultado = 200

Mientras que la expresión que da como resultado 1100 es la correcta, la que da 200 no lo es. La solución más
sencilla es la utilización de paréntesis para agrupar operaciones, como ya se mencionó

4.8. Conversión de datos


Existe la probabilidad de que al realizar una operación en C, el tipo de dato del resultado no coincida con
el tipo de dato de las variables intervinientes en la operación. Un claro ejemplo de esto es la división: si se
dividen dos números enteros definidos como tipo “char”, probablemente el resultado no sea un valor entero.
Si dos operandos de diferente tipo de dato se utilizan en una operación aritmética, el tipo de dato de menor
prioridad se convierte temporalmente al de mayor prioridad, para ası́ poder realizar la operación. La prioridad
de los tipos de datos se muestra a continuación:

Figura 2: Conversión de datos.

Se muestra un ejemplo sencillo de esto en el siguiente código:

char a;
float b,res;
...
res=a+b; //a se convierte temporalmente a float para realizar la suma

Sin embargo, debe procurarse definir de manera correcta el tipo de dato de la variable en donde se almacenará
el resultado.

char a,res;
float b;
... //a se convierte temporalmente a float para realizar la suma
res=a+b; //pero como res es de tipo char, el resultado se trunca.

Observese lo que sucede en la porción de código anterior. Si b=20.5, y a=11, res terminará valiendo 31, lo
que es similar a aplicar una función “parte entera” implı́citamente. Pero si la parte entera de b excede el rango
del tipo de dato de a, por ejemplo si b=534.53, el resultado en res no tendrá lógica aparente. Esto es ası́ dado
que el lenguaje C conserva los dı́gitos menos significativos durante este tipo de conversión.
Este tipo de conversión o promoción se denomina implı́cita o forzada. Existe otro tipo de conversión, la explı́cita.
Esta es realizada cuando se hace referencia a la misma mediante una operación dentro del código. Para realizarla
se utiliza el operador “cast”:

7
char a,b;
float res;
...
res=(float) a/b; //se aplica cast a ‘‘a’’ antes de realizar la división

Para evitar caer en resultados erróneos, deben tenerse en cuenta las siguientes pautas:

Ante una determinada operación, es primordial conocer qué tipo de dato tendrá el resultado de la misma.
Entonces, la declaración de la variable resultado debe ser congruente con esto.

Es tarea de la persona que escribe el código realizar las verificaciones pertinenentes cuando sea posible,
dado que el compilador no generará un error de compilación ante una conversión o promoción implı́cita.
En determinados casos puede realizar una advertencia, pero el código compilará de manera satisfactoria.

En el caso que sea imposible hacer que dos operandos sean del mismo tipo, debe aplicarse un cast para
promover el operando de menor prioridad, al de mayor prioridad.

5. Estructuras de control
5.1. Estructuras condicionales
Las condiciones dentro de un código permiten ejecutar una o varias lı́neas de programa dependiendo de la
validez de una expresión. En otras palabras, las condiciones se utilizan para la toma de decisiones del tipo “Si se
cumple la condición (...), se debe hacer (...). De lo contrario, si la condición no se cumple, se debe hacer (...)”.
En el caso del lenguaje C, las estructuras condicionales no difieren de las incluı́das en Fortran, Basic, Pascal o
Matlab.

5.1.1. Estructura alternativa if-else

La expresión if se puede utilizar sola o asociada a la expresión else.

if(expresión)
{
sentencia;
sentencia;
}

Si el resultado de la expresión encerrada entre paréntesis es verdadero, las sentencias encerradas entre llaves
se realizan y el programa continúa con la ejecución. Si el resultado de la expresión es falso, las sentencias dentro
de las llaves no se realizan y el programa continúa inmediatamente con la ejecución. Si no se colocan las llaves,
un resultado verdadero en la evaluación de la expresión hace que se ejecute solo la sentencia que se encuentra
por debajo del if. Si no se cumple la expresión, esto es, da un resultado falso, se salta la primer lı́nea de código
por debajo del if y se continúa con la ejecución del programa.

if(expresión)
{
sentencia;
sentencia;
}
else
{
sentencia;
sentencia;
}

8
Cuando se agrega la expresión else, se ejecutan las sentencias dentro de las llaves que prosiguen al else en
caso de que la expresión evaluada sea falsa. Si no se colocan las llaves, la ejecución se sucede de la misma manera
que la expuesta anteriormente para el if.

5.1.2. Estructura de selección switch

A diferencia de la estructura if-else que selecciona entre dos opciones en el programa, la estructura switch
permite elegir entre varias opciones. La misma se muestra a continuación:

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 estructura switch se ejecuta de la siguiente manera: primero se evalúa la variable selector y se compara
con el valor de 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. 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
case 1:case 2:case 3:case 4:case 5: LCD_message = ’Dı́a laborable’; break;//múltiples case
case 6:case 7: LCD_message = ’Fin de semana’; break; //ejecutan la misma sentencia.
default: LCD_message_1 = ’Elija un dı́a de la semana’; break;
}

La sentencia break es muy importante, ya que el comportamiento normal de una estructura switch es eje-
cutarlo todo desde la coincidencia de la variable selector con el case correspondiente, hasta el final. Por ello,
si no se quiere que se ejecute más de un conjunto de sentencias de un case, deben colocarse break al final de
cada bloque. Es decir, las etiquetas case son puntos de entrada de la ejecución, y no implican que al acabarse
el bloque case la ejecución salte al final del bloque switch.

5.2. Estructuras repetitivas


5.2.1. Estructura while

El bucle while sirve para ejecutar código reiteradas veces mientras se cumpla una determinada condición.
La cantidad de veces que el programa repita el código dependerá de la condición impuesta. Esta condición es

9
similiar a la que se utiliza en el bloue if. Primero se evalúa la condición. Si el resultado es verdadero, se ejecuta
el bloque de código. Luego se vuelve a evaluar la condición, y en caso de dar verdadera se vuelve a ejecutar el
bloque. El bucle se corta cuando la condición da falsa.

while(expresión)
{
sentencia;
...
sentencia;
}

Un tipo especial de 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 siempre dentro del bucle:

while(1)
{ // En vez de "while(1)", se puede escribir "while(true)"
... // Expresiones encerradas entre llaves se ejecutarán
... // repetidamente (bucle infinito)
}

5.2.2. Estructura do-while

Es muy parecida a la estructura anterior. Pero tiene una pequeña diferencia: en un bucle while, la compro-
bación de la expresión se hace al principio de cada ciclo. En cambio, en el do-while, se hace al final.

do
{
sentencias;
...
}while (condicion);

La expresión condicion se ejecuta al final del bucle, lo que significa que el bloque de código dentro del do se
ejecuta como mı́nimo una vez sin reparar en la veracidad o no de la condición. Si el resultado es verdadero, el
procedimiento se repite.

5.2.3. Estructura for

Este esta estructura sirve en los casos que se necesita que un bloque de sentencias se repita una cantidad de
veces previamente conocida. Esta estructura repetitiva se escribe como sigue:

for(expresióninicial; expresióndecondición; cambiarexpresión)


{
sentencia;
...
}

expresioninicial es una o más sentencias, separadas por comas, que se ejecutan una única vez al entrar al
lazo.

expresiondecondicion es una expresión lógica, que se comprueba al principio de cada iteración. Mientras
resulte verdadera se continúa ejecutando el bucle.

cambiarexpresion es una o más sentencias, separadas por comas, que se realizan al final de cada ejecución
del cuerpo de la iteración.

10
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 realiza en la declaración. La expresioninicial especifica la variable
inicial del bucle, que más tarde se compara con la expresiondecondicion antes de entrar al bucle. Las operaciones
dentro del bucle se ejecutan repetidamente y después de cada iteración el valor de la expresioninicial varı́a de
acuerdo con la regla cambiarexpresion. La iteración continúa hasta que la expresiondecondicion es falsa.

for(k=0; k<5; k++) // La variable k se incrementa 5 veces (de 1 a 4) y


{
sentencias; // cada vez se repite la expresión sentencias;
...
}

En el ejemplo anterior, la operación se ejecutará cinco veces. Luego, al comprobarse que la expresión k¡5 es
falsa (después de 5 iteraciones k=5), el programa saldrá del bucle for.

5.3. Transferencias o saltos incondicionales


5.3.1. Break

A veces es necesario detener la ejecución de una estructura de control, salir de la misma y continuar con la
ejecución del programa. La sentencia break se puede utilizar dentro de cualquier estructura repetitiva (while, for,
do-while) y en la estructura switch también. En éstas la sentencia break se utiliza para salir de la estructura switch
si la condición case es verdadera. Por otro lado, en las estructuras repetitivas causa la inmediata culminación
del bucle, incluso si la condición de salida no se ha cumplido.

5.3.2. Continue

Se utiliza dentro de las estructuras repetitivas para saltar una iteración. A diferencia de la sentencia break,
el programa se queda dentro del bucle y las iteraciones continúan.

5.3.3. Go to

Permite hacer un salto absoluto a otro punto en el programa (“Go to” o “ir a”). Esta caracterı́stica se debe
utilizar con precaución dentro de C ya que su ejecución causa 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 dos puntos(:).

...
if(CO2_sensor==1) 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

Esta sentencia se muestra solo a modo ilustrativo. No está permitido su uso dentro de este curso dado
que va en contra de las buenas prácticas de programación. Su implementación no permite hacer una lectura y
seguimiento fluı́do del código. Adicionalmente existen estructuras con las que pueden resolverse los casos que se
resolverı́an con go to.

11
5.3.4. Return

Se utiliza para devolver el control al programa principal luego de ejecutar una porción de código perteneciente
a una función. Se volverá sobre esta sentencia más adelante durante este mismo apunte.

6. Funciones
Una función es una porción de código que se programa para desarrollar una tarea especı́fica. El objetivo
principal de la utilización de funciones dentro de C es el de hacer un código más ordenado y legible, a la vez que
se simplifica el problema a resolver dividiéndolo en varios procedimientos más sencillos. Las funciones dentro
de C son, conceptualmente, similares a las funciones vistas en el análisis matemático. Para ejemplificar esto, se
considera el siguiente ejemplo:

F (x) = x2 + 3x − 4

En C, el acto de escribir la función se denomina “Declaración”. Si a esta función matemática le asignamos


un valor en x, por ejemplo x=4, nos va a devolver un valor en f, o sea 24. En C, darle un valor de entrada a una
función se denomina “pasar un argumento” o “argumento de entrada”. Cuando la función se ejecuta, puede o
no generar un valor de salida, lo que se denomina “devolver un argumento” o “argumento de salida”. Entonces,
las funciones en C tienen argumentos de entrada (se le dan como valores de entrada a la función, previos a su
ejecución) y argumentos de salida (los entrega la función una vez que se ejecutó).
Todo programa hecho en C consta de, al menos, una función. El comienzo de la función main() es el punto de
entrada al código, por lo que la misma debe estar simpre presente. Si el compilador no encuentra esta función,
el programa no compilará.
En la siguiente porción de código se muestra la sintaxis genérica de una función:

tipo de dato nombrefuncion (tipo de dato a,tipo de dato b,...,tipo de dato n)


{
sentencias;

return expresion;

Como se deduce a partir del ejemplo anterior y tal como se mencinó al inicio de esta sección, las funciones
pueden tener argumentos de entrada, los cuales van entre parentesis a la derecha del nombre de la función.
Además, pueden tener argumentos de salida, los cuales se especifican con la expresión return. El tipo de dato
del argumento de salida se especifica a la izquierda del nombre de la función.
En el siguiente ejemplo se muestra el código de una función para calgular el área de un rectángulo, a partir de
conocer los datos de su base y altura:

float AreaRectangulo(float base,float altura)


{
float area; //declaro la variable que contendrá el valor del área

area = base * altura;

return area;
}

Debe tenerse en cuenta que el tipo de dato del argumento de salida debe ser el mismo que el tipo de dato
de la variable que se quiere retornar.

12
6.1. Prototipos de funciones
Tal como ocurre con las variables, el uso de una función debe estar precedido por su declaración. Un ejemplo
de esto se muestra en el siguiente código:

int a = 5, b = 10, c; //se declaran tres variables

int maximo(int x, int y) //se declara la función maximo.


{
unsigned int valor;

if(x >= y)
{
valor = x;
}
else
{
valor = y;
}
return valor;
}

void main(void)
{
c = maximo(a, b); //se llama la función maximo dentro del mail().
printf("El maximo is %d\n", c)
}

Otra posibilidad es que en vez de declarar la función completa antes de usarla, se declare solo su prototipo.
Esto hace que el compilador “sepa” que la función existe y que debe buscar su declaración en los archivos del
proyecto. Se reescribe el código del ejemplo anterior, pero con la utilización de prototipo.

int a = 5, b = 10, c; //se declaran tres variables

int maximo(int x, int y); //prototipo de la función maximo.

void main(void)
{
c = maximo(a, b); //se llama la función maximo dentro del mail().
printf("El maximo is %d\n", c)
}

int maximo(int x, int y) //se declara la función maximo, luego de haber sido usada.
{
unsigned int valor;

if(x >= y)
{
valor = x;
}
else
{
valor = y;

13
}
return valor;
}

14
Referencias
[1] Eduardo Grosclaude, Lenguaje C. Universidad Nacional del Comahue (2001).

[2] Carlos Canal, Gustavo Monte, Programación en C sobre PIC24. Capı́tulo de C. SASE 2014.

[3] Mc Electronics, Programación en Lenguaje C. Diapositivas del curso online (2008).

[4] Programación en C. Wikilibros https://es.wikibooks.org/wiki/Programación en C (2018).

15

You might also like