You are on page 1of 16

Básicamente los lenguajes de programación pueden dividirse en: lenguajes

máquina, lenguajes ensambladores, y lenguajes de alto nivel.

Las computadoras sólo pueden entender directamente el lenguaje


máquina, que es el lenguaje de una computadora en particular, o sea, son
dependientes de la máquina que los ejecuta. Estos lenguajes son difíciles de
manejar por los humanos, convirtiendo la tarea de programar en algo tedioso y
difícil.

Los lenguajes ensambladores son una forma más sencilla de escribir en


lenguaje máquina. Básicamente reemplazan por palabras en inglés las
instrucciones del lenguaje máquina (que son cadenas de números). Igualmente
continúa siendo tediosa este tipo de programación, por lo tanto, tiempo después, se
desarrollaron los lenguajes de alto nivel.

En los lenguajes de alto nivel se pueden escribir enunciados que resumen


decenas o cientos de instrucciones en lenguaje máquina. Se utilizan
enunciados en inglés sencillos y nociones matemáticas básicas. El código generado
en un lenguaje de alto nivel debe ser traducido para que puedan ser ejecutados por
las computadoras; el programa encargado de esta traducción se denomina
compilador.
El lenguaje de programación C evolucionó a partir de los lenguajes BCPL y B. El
primero desarrollado en el año 1967 con el objetivo de escribir software y
compiladores de sistemas operativos.

En tanto, Dennis Ritchie, trabajó el lenguaje B para convertirlo en C. Al principio


sirvió para desarrollar el sistema operativo UNIX, luego se extendería a todo tipo de
sistemas y programas.

Una ventaja de C es su portabilidad, siempre y cuando se escriba con cuidado y


siguiendo el estándar ANSI/ISO 9899.

En cuanto a C++, es el lenguaje C pero orientado a objetos, considerado mucho


más productivo.

Vea el siguiente código fuente programado en C, imprime en pantalla “Hola


Mundo”:

/* Nuestro primer trabajo en C */


main()
{
printf(“Hola Mundo\n”);
}

La primera línea del programa es un comentario con inicio /* y final */, es obviado
por el compilador, así que no se ejecuta.

Luego sigue la línea main(), la cual es una función y forma parte de todo programa
escrito en C. Por lo tanto, todo lenguaje comienza a ejecutarse a partir de esa
función que traducida significa “principal”.

Las llaves dan inicio { y cierre } a la función principal, tampoco nunca deben faltar.
El contenido entre llaves se denomina bloque.

Dentro del bloque encontramos la función printf(), que es la que imprime en


pantalla un texto. La función debe recibir algo para imprimir, en este caso es una
oración, que en programación se llama cadena de caracteres. Las comillas no se
imprimen, solamente determinan el inicio y el fin de esa cadena.
Esta función imprime en pantalla: Hola Mundo.

¿Qué hay de \n al final de la cadena?. La barra invertida \ se denomina carácter de


escape, el cual indica que debe interpretarse de otra manera el carácter que le
sigue a la derecha, en este caso n. El compilador interpreta a la secuencia de
escape \n como un salto de línea o nueva línea (un ENTER al final de la cadena).
Existen otras secuencias de escape en C que se ven en el siguiente capítulo,
además se explica cómo hacer si se quiere imprimir en pantalla una barra invertida
sin que se interprete como un carácter de escape y también cómo hacer para
imprimir en pantalla una comilla (y que no sea interpretada como final o inicio de
cadena)

Finalmente la sentencia termina en un punto y coma. Toda sentencia en C debe


terminar con un punto y coma.

Veamos algunos ejemplos para aclarar dudas:

main()
{
printf(“Hola”);
printf(“Mundo\n”);
}

Esto imprime en pantalla también: HolaMundo, porque la primer línea en printf no


posee una secuencia de escape que le diga que existe un salto de línea. Ni tampoco
la primera línea posee un espacio final.

En tanto, el siguiente código mostraría en pantalla:


Hola
Mundo

main()
{
printf(“Hola\nMundo\n”);
}

Existen diferentes secuencias de escape en C. Para saber qué es una secuencia de


escape, diríjase al capítulo anterior.

\n Nueva línea. Coloca el cursor en el principio de la siguiente línea.


\t Tabulador horizontal. Mueve el cursor al siguiente tabulador.
\r Retorno de carro. Coloca el cursor hacia el principio de la línea actual.
\a Alerta. Suena la beep del sistema.
\\ Imprime la diagonal invertida. Una sola diagonal sería interpretada como un
carácter de escape.
\” Imprime la doble comilla. Sin la diagonal invertida, se interpretaría como un inicio
o un fin de una cadena.

Lo que haremos en el siguiente programa es pedirle al usuario dos números, para


luego sumarlos y mostrar el resultado en pantalla.

#include <stdio.h>

main()
{
int numero1, numero2, total;
printf(“Ingrese el primer entero\n”);
scanf(“%d”, &numero1);
printf(“Ingrese el segundo entero\n”);
scanf(“%d”, &numero2);

total = numero1 + numero2;


printf(“El resultado de la suma es: %d”, total);

return 0;
}

La primera línea incluye una directriz del preprocesador C. Toda línea que comienza
con el numeral #, es preprocesada antes de que el programa compile. Lo que hace
#include <stdio.h> es incluir la librería estándar stdio.h en nuestro programa.
Una librería es un grupo de funciones, información o declaraciones (que ya vienen
con C o que hemos creado nosotros), y se incluyen para que puedan ser usadas en
nuestro programa.

Si bien es opcional la inclusión de esta librería, se recomienda incluirla siempre que


se utilicen funciones de entrada o salida. Esto ayuda al compilador a verificar las
funciones y localizar errores y advertirles de los mismos.

Luego sigue la función principal main(), e inmediatamente la declaración de


variables:
int numero1, numero2, total;

Una variable almacena información de un tipo definido para luego ser usada en el
programa. En este caso estamos declarando tres variables llamadas numero1,
numero2 y total del tipo número entero (int). Por lo tanto, dentro de estas
variables sólo podrán almacenarse números enteros. Si quisiéramos definir una
variable que contenga números racionales, se debería declarar así: float
racional1.

Las variables toman el nombre que queramos, aunque se recomienda utilizar un


nombre que indique claramente qué se almacenará dentro de ellas. Además hay
ciertas restricciones en los nombres que puede tomar una variable. Por ejemplo,
una variable no puede comenzar con el signo _, ni con números. También hay que
aclarar que el lenguaje C es sensible a mayúsculas y minúsculas, por lo tanto
entero1 y Entero1, son interpretados como variables diferentes.

En C las variables deben declararse inmediatamente al inicio de una función.

Luego se imprime en pantalla Ingrese el primer entero:


printf(“Ingrese el primer entero\n”);

La siguiente línea:
scanf(“%d”, &numero1);

La función scanf se encarga de esperar una entrada a través del teclado por parte
del usuario. En este caso el usuario debería ingresar un entero para que sea válido.
Vemos que dentro de la función scanf hay dos argumentos (los datos que recibe
una función, también llamado parámetros). Cada argumento se separa por una
coma. El primer argumento “%d”, indica el tipo de dato que debe ingresar el
usuario. En este caso el especificador de conversión %d está indicando que debe
recibirse un número entero. El carácter especial % es un carácter de escape como
la barra invertida. Luego el carácter d indica que se recibe un entero.

Luego está el otro argumento &numero1, que es la variable que hemos definido y
que guardará el primer número ingresado. El uso de ampersand & delante de
nuestra variable será aclarado más adelante. Por el momento sólo piense que indica
la dirección de memoria en donde se almacena la variable.

En definitiva, esa línea de código esperará a que el usuario ingrese un número


desde el teclado. Luego se repite la misma operación para el segundo número.

La próxima línea es bastante obvia, y suma el valor almacenado en la variable


numero1 más el valor de la variable numero2, y lo almacena en total:
total = numero1 + numero2;

Aclaración: aquí el signo de igualdad = en realidad es usado como asignación. O


sea, dentro de la variable total se guardará el resultado de la fórmula que está
hacia la derecha

Finalmente se imprime el resultado de la suma con la línea:


printf(“El resultado de la suma es: %d”, total);

Aquí la función printf tiene dos argumentos. El primero imprime la cadena de texto,
y el segundo argumento, la variable que debe ser impresa en pantalla
inmediatamente después del primer texto.

El especificador de conversión %d, indica que se deberá imprimir un entero


inmediatamente al final de la cadena, este entero será la variable total.

Finalmente, la última línea del bloque indica al sistema operativo que se ha


ejecutado con éxito el programa:
return 0;

A continuación se verán los distintos operadores aritméticos de C

Los operadores aritméticos en C son:


Suma +
Resta -
Multiplicación *
División /
Modulo %

En C pueden operarse entre variables o números:

numero1 = 4;
total = 3 + numero1;
total = total * total;

La variable total almacena el numero 49.

También pueden utilizarse el uso de paréntesis en las fórmulas matemáticas para


cuestiones de precedencia.

En tanto, los operadores lógicos (que se usarán más adelante) son:


== operador de igualdad en C
!= operador de desigualdad
> mayor
< menor
>= mayor o igual
<= menor o igual

Ejemplo de uso:
resultado = 20 >= 2;
Almacena en la variable resultado el valor lógico TRUE (verdadero), porque la
sentencia es verdadera, 20 es mayor o igual a 2.

Los operadores lógicos tienen muchos usos que veremos más adelante.

Los operadores aritméticos en C son:


Suma +
Resta -
Multiplicación *
División /
Modulo %

En C pueden operarse entre variables o números:

numero1 = 4;
total = 3 + numero1;
total = total * total;

La variable total almacena el numero 49.

También pueden utilizarse el uso de paréntesis en las fórmulas matemáticas para


cuestiones de precedencia.

En tanto, los operadores lógicos (que se usarán más adelante) son:


== operador de igualdad en C
!= operador de desigualdad
> mayor
< menor
>= mayor o igual
<= menor o igual

Ejemplo de uso:
resultado = 20 >= 2;

Almacena en la variable resultado el valor lógico TRUE (verdadero), porque la


sentencia es verdadera, 20 es mayor o igual a 2.

Los operadores lógicos tienen muchos usos que veremos más adelante.

Las estructuras de control permiten controlar el flujo de ejecución de las


instrucciones en un código. Con estas estructuras, el programador puede
determinar el orden y las veces que se ejecutarán las instrucciones que están
dentro de estas estructuras.

Originalmente las líneas de código (las instrucciones) eran ejecutadas siempre


secuencialmente, o sea, una después de la otra. Se utilizaba la función GOTO para
alterar el orden de ejecución. Con esta función se podía ir de un lado para el otro en
el código. Esta función traía grandes problemas en el desarrollo de programas,
como falta de claridad, errores, etc., por lo que se enunciaron tres estructuras de
control que permitirían desarrollar cualquier programa: estructura de secuencia,
estructuras de selección y estructuras de repetición.

La estructura de secuencia es la que venimos trabajando desde el principio. Es la


ejecución de una instrucción tras otra en secuencia.

Las estructuras de selección son aquellas que permiten, bajo una condición,
ejecutar distintos códigos. La más simple es la estructura de selección IF. Se da una
condición que puede ser verdadera o falsa, y se ejecuta un código u otro
dependiendo del resultado de esa condición en tiempo de ejecución. También está
la estructura de selección SWITCH que, dependiendo de un valor, ejecutará
distintos códigos.

Luego están las estructuras de repetición, las cuales repiten un código cierta
cantidad de veces hasta que se cumpla o deje de cumplir una condición. Son
ejemplos de estas estructuras en C los WHILE, los FOR, etc.

El funcionamiento de esta estructura es sencillo. Se evalúa una condición, si es


verdadera ejecuta un código, si es falsa, ejecuta otro código (o continúa con la
ejecución del programa).

if (condición)
ejecuta esto si la condición es verdadera
else
ejecuta esto si la condición es falsa

Ejemplo de la estructura de selección if en C

int edad;
printf(“Ingrese su edad: \n”);
scanf(“%d”, &edad);

if (edad>=18)
{
printf(“Usted es mayor de edad. \n”);
}
else
{
printf(“Usted es menor de edad. \n”);
};

En este ejemplo, declaramos una variable llamada edad de tipo entero. Luego
imprimimos en pantalla Ingrese su edad, y con la función scanf esperamos que el
usuario ingrese un número entero.

Luego entra en juego la estructura de selección if. Si la condición numero>=18


evalúa verdadero (true), se imprime en pantalla Usted es mayor de edad. En
cambio, si se evalúa en falso (false), se imprime en pantalla Usted es menor de
edad. Luego continúa con la carga del programa.

Puede obviarse la instrucción else si se desea.

if (condición)
{
ejecuta esto sólo si la condición es verdadera
};

La condición siempre debe devolver un valor de verdad o falsedad. Aquí se utilizan


los operadores lógicos.

La estructura switch permite elegir ejecutar diferentes códigos dependiendo de un


valor.

switch (valor) {
case ‘1’: ejecuta esto si valor es 1
break;
case ‘2’: ejecuta esto si valor es 2
break;
case ‘3’: ejecuta esto si valor es 3
break;
default: ejecuta esto si valor no es ninguno de los anteriores
break;
};

Cada case puede ejecutar múltiples líneas de código. Todos deben terminan con un
break, que indica que debe seguirse la ejecución del programa luego de ejecutar las
líneas superiores. La ejecución continúa luego de la estructura switch. El caso
default se ejecuta si no hubo coincidencia entre el contenido de valor y los case
superiores.

Un ejemplo del uso de la estructura switch en C:

int hijos;
printf(“Ingrese la cantidad de hijos que usted tiene: \n”);
scanf(“%d”, &hijos);

switch (hijos) {
case ‘0’:
printf(“No le corresponde asignación familiar por hijo\n”);
break;
case ‘1’:
printf(“Le corresponden 50usd de asignación familiar por su único
hijo\n”);
break;
case ‘2’:
printf(“Le corresponden 75usd de asignación familiar por sus dos
hijos\n”);
break;
default:
printf(“Le corresponden 100usd de asignación familiar por tener más
de dos hijos\n”);
break;
};

Se define la variable del tipo entero hijos, se le pide al usuario que ingrese el
número de hijos que posee y luego entra en acción la estructura switch, actuando
de diferentes formas dependiendo del valor de la variable hijos en tiempo de
ejecución.

Esta estructura de repetición le permite al programador especificar las veces que se


repita una acción mientras una condición se mantenga verdadera. La forma del
while es:

while (condición)
{
bloque de instrucciones
};

Mientras la condición se mantenga verdadera, se ejecutará X cantidad de veces el


bloque de instrucciones dentro de las llaves. Es necesario que alguna vez la
condición se haga falsa, pues de lo contrario se entraría en un ciclo infinito de
repeticiones y el programa se consideraría bloqueado. Por lo tanto es necesario que
en el bloque de instrucciones dentro de la estructura while se ejecute alguna
acción que en algún momento haga que la condición sea falsa.
Veamos un ejemplo para ver funcionar la estructura de repetición while:

int num;

num = 0;
while (num<=10)
{
printf(“Repetición numero %d\n”, num);
num = num + 1;
};

El código anterior imprimirá en pantalla:

Repetición numero 0
Repetición numero 1
Repetición numero 2
Repetición numero 3
Repetición numero 4
Repetición numero 5
Repetición numero 6
Repetición numero 7
Repetición numero 8
Repetición numero 9
Repetición numero 10

¿Por qué? Vemos que iniciamos la variable del tipo entero num en cero. Luego, se
evalúa por primera vez si es menor o igual a 10, al ser verdadera, se ejecuta el
bloque dentro del while por primera vez. Se imprime Repetición numero 0, pues
el valor dentro de num es cero. Luego el proceso se repite hasta que num con
valor 10 se le suma 1, y toma el valor 11. Se evalúa la condición del while y se
determina que NO se cumple, por lo tanto, salta el bloque y sigue la ejecución del
programa.

La estructura for sirve para repetir un código dependiendo de un contador. Veamos


un ejemplo:

int contador;

for (contador = 1; contador<=10; contador++)


{
printf(“Repetición numero %d\n”, contador);
};

Primero se crea la variable contador de tipo entero (será la variable de control en


el for). Luego se ejecuta la estructura for iniciando la variable contador en 1. Luego
se verifica que se cumple la condición contador<=10 y se ejecuta el bloque dentro
de la estructura, o sea, imprime en pantalla Repetición número 1.

Luego la variable contador es incrementada en uno con la expresión contador++


y el ciclo se inicia otra vez. La variable contador ahora vale 2, por lo tanto se
verifica la condición y se vuelve a ejecutar el código. Este proceso se ejecuta hasta
que contador toma el número 11 y la condición se hace falsa y no ejecuta el
bloque.

Este código imprimirá en pantalla lo siguiente:

Repetición numero 1
Repetición numero 2
Repetición numero 3
Repetición numero 4
Repetición numero 5
Repetición numero 6
Repetición numero 7
Repetición numero 8
Repetición numero 9
Repetición numero 10

Las tres expresiones que componen la estructura for en C son opcionales, por lo
tanto se pueden omitir en ciertos casos. Si se omite la primera (la inicialización de
la variable de control), significa que la variable se inicializa en otra parte del
programa. Si se omite la segunda expresión, la estructura for entraría en un ciclo
infinito, lo cual es considerado un error. Si se omite la tercera expresión significa
que la variable de control es calculada dentro del bloque de for.

La tercera expresión puede ser tanto un incremento como un decremento en uno o


más. También puede ser más compleja agregando más instrucciones con el uso de
la coma. Por ejemplo:

for (contador = 1; contador<=10; suma += contador, contador += 2)

Como vemos, la tercera expresión no sólo suma contador de dos en dos sino que
además en cada repetición ejecuta la operación suma += contador.

Esta estructura de repetición es similar a la estructura while. En while la condición


para que se repita el bloque de instrucciones se evalúa desde el principio del ciclo
de repeticiones, en cambio, en la estructura do-while, al principio se ejecuta el
bloque y luego se evalúa la condición para ver si se sigue ejecutando o no. Esto
significa que el bloque se ejecutará por lo menos una vez.

La forma de esta estructura es:

do {
bloque de enunciados
} while (condición);

Veamos un ejemplo en donde se imprimen los números del 1 al 10 usando esta


estructura. Al final también se imprime en pantalla el valor contenido en la variable
principal a fin de mostrar cuál es su valor final.

num = 1;
do {
printf(“%d\n”, num);
num = num + 1;

} while (num<=10);

printf(“La variable num vale: %d\n”, num);

Esto imprime en pantalla:

1
2
3
4
5
6
7
8
9
10
La variable num vale: 11

Los enunciados break y continue son utilizados para modificar el flujo de control
dentro de un programa.

El break utilizado dentro de las estructuras de control causa la inmediata salida de


dicha estructura (por lo tanto no sigue repitiéndose el bloque y continúa la
ejecución de las instrucciones que le siguen a la estructura de control).

Veamos un ejemplo del uso de break:

int num;

num = 1;
while (num <= 10)
{
if (num == 5)
{
break;
};

printf(“%d - ”, num);
num = num + 1;
};

El código anterior imprime:


1–2–3–4–

Lo que sucede es que cuando la variable num toma el valor 5, la condición del
while se cumple, al ingresar al bloque se evalúa en la estructura if si num es igual
a 5 y se ejecuta el break saliendo del bloque while. Num termina valiendo 5 pues
jamás se ejecuta la suma num = num + 1.

Por otra parte, el enunciado continue, dentro de las estructuras de repetición, al


ser ejecutado salta las instrucciones que siguen en el bloque y ejecuta la siguiente
repetición en el ciclo. Veamos un ejemplo para aclarar el funcionamiento de
continue:

int num;

num = 0;
while (num <= 7)
{
num = num + 1;
if (num == 5) {
continue;
};
printf(“%d - ”, num);
};

El código anterior imprime en pantalla:

1–2–3–4–6–7

Como vemos, en una de las repeticiones se saltea la impresión del número 5.

Algunos programadores dicen que el uso del break y del continue dentro de las
estructuras de control (excepto el break en la estructura switch) viola las normas
de la programación estructurada. Lo cierto es que no es necesario el uso de break
y continue si se utilizan las estructuras correctas
Ya habíamos visto algunos operadores que resultaban en un verdadero (true) o un
falso (false) al usarse con números o variables, estos eran:

== operador de igualdad en C
!= operador de desigualdad
> mayor
< menor
>= mayor o igual
<= menor o igual

Con estos se pueden construir expresiones sencillas como: numero <= 7,


dependiendo del valor de la variable numero esa expresión puede ser verdadera o
falsa. Este tipo de expresiones se utilizan para las condiciones en las estructuras de
repetición y de selección.

Pero es posible construir expresiones más complejas utilizando otros operadores


lógicos:
&& ( Y lógico)
// (O lógico)
! (NO lógico o negación lógica)

Veamos qué significan cada uno de ellos:

valor = (expresion1 && expresion2)


En este caso si expresion1 y expresion2 son verdaderas, valor resulta verdadero
(true).
Si alguna o ambas de las expresiones son falsas, valor resulta en falso (false).

valor = (expresion1 // expresion2)


En este caso si ambas expresiones son verdaderas, valor resulta verdadero.
Si una de las expresiones es verdadera y la otra falsa, valor resulta verdadero.
Si las dos expresiones son falsas, valor resulta falso.

valor = (!expresion1)
En este caso si la expresión es verdadera, valor resulta falso.
Si la expresión es falsa, valor resulta falso.

Se puede usar && de la siguiente manera:


if (edad >= 12 && edad <= 20)
{
printf(“Usted es adolescente”);
}
Existe un consejo de los expertos en programación que se resume en la frase
“divide y vencerás”. Esto significa que siempre es conveniente construir programas
a partir de piezas menores (módulos) que luego trabajarán en conjunto para lograr
los objetivos de las aplicaciones.

Los módulos en C se llaman funciones. Existen dos tipos de funciones con las que se
arman programas: las que son creadas por los usuarios y los paquetes de funciones
predefinidos disponibles en la biblioteca estándar de C. Estos últimos contienen
cientos de funciones básicas para el cálculo de funciones matemáticas,
manipulación de cadenas de caracteres, funciones de entrada-salida, etc. Son
funciones que suelen usarse frecuentemente en la construcción de programas y, al
estar predefinidas, ahorran tiempo a los programadores. Por eso es útil
familiarizarse con las funciones de la biblioteca estándar de C, pues al conocer
estas funciones podremos ahorrarnos de escribir mucho código, además cuentan
con la ventaja de ser altamente eficientes y generalmente portables.
En tanto las funciones creadas por el programador son aquellas escritas para
resolver tareas que generalmente no están en la biblioteca estándar y sirven para
cumplir con el propósito del programa a crearse.

Las funciones son invocadas mediante una llamada de función; esto se logra
escribiendo el nombre de la función y la información de entrada necesaria
(parámetros o argumentos) para que ésta pueda lograr su cometido. Ya hemos
visto ejemplos de funciones con sus parámetros, por ejemplo: printf(“Hola
Mundo\n”); Allí se está llamando a la función printf con el argumento “Hola
Mundo\n”, que es una cadena. El resultado es la impresión en pantalla del ese
texto.

Anteriormente dijimos que los programas en C comienzan indefectiblemente desde


la función main(). Ésta es la función principal y es el hilo conductor en la ejecución
de un programa. Desde esta función se pueden llamar otras funciones para realizar
tareas, y esas funciones a su vez pueden invocar otras funciones y así
sucesivamente. Por lo general cuando una función termina su trabajo se retorna a
la función que la llamó, siguiendo la ejecución de esta.

Los programadores pueden escribir y usar sus propias funciones. Veamos a


continuación un ejemplo para saber cómo definir funciones en C. El siguiente
programa pide que ingrese un número entero y calcula el cuadrado de dicho
número.

#include <stdio.h>

int cuadrado(int);

main()
{
int numero;

printf(“Ingrese un entero: ”);


scanf(“%d”, &numero);

printf(“\nResultado: %d”, cuadrado(numero));


return 0;
}

int cuadrado(int y)
{
int resultado;

resultado = y * y;
return resultado;
}

En este programa hemos creado la función llamada cuadrado que recibe un entero
para calcular el cuadrado de dicho número. Analizaremos paso por paso el
programa anterior.
Se incluye la librería stdio.h porque utilizamos las funciones printf y scanf. A
continuación se hace el prototipado de nuestra función cuadrado. Es necesario
escribir el prototipo de todas las funciones que creemos. En este caso el prototipo
es: int cuadrado(int);

El primer int a la izquierda significa que la función devolverá como respuesta a su


ejecución un entero. Luego le sigue el nombre que le hemos puesto a la función, en
este caso cuadrado, y al final, entre paréntesis, los tipos de datos de los
parámetros que recibirá la función. En este caso sólo se recibirá un parámetro
(argumento) que es del tipo int (entero). Más adelante profundizamos en los
prototipos de funciones.

Se abre el programa principal main() y luego se crea la variable de tipo entero


numero. Luego se pide al usuario que ingrese un entero que se almacena en la
variable numero.

Al final se llama a la función printf y dentro de esta, se llama a la función que


hemos creado nosotros: cuadrado(numero). Lo que hace ahora es ejecutar la
función definida más abajo con el parámetro numero. Esta función calcula el
cuadrado de dicho número y retorna el resultado (un entero), que luego se
imprimirá en pantalla (por la función printf dentro del main).

Finalmente, fuera del main(), se define la función cuadrado que necesitamos. En


el próximo capítulo se especifica cómo se debe definir una función en C
La forma genérica de definir funciones en C es:

tipo-valor-regreso nombre-de-función (parámetros)


{
declaraciones

enunciados
}

El tipo-valor-regreso es el tipo de dato resultado de llamar a la función, puede ser


un entero, una cadena, un carácter, etc. o también puede ser void que indica que
esa función no devolverá ningún valor. El nombre-de-función es un identificador o
nombre válido. Por lo general se aconseja poner un nombre corto que especifique lo
que hace esa función. Luego están los parámetros: una lista, separada por comas,
que especifica los datos que se espera recibir. Si se escribe void se entiende que
esa función no necesita ningún parámetro.

La función tiene un cuerpo o bloque, donde están las declaraciones y los


enunciados. En las declaraciones se especifican variables que ámbito local, o sea,
sólo podrán ser usadas dentro de esa función. No se deben declarar las variables
que llegan por parámetro. No se pueden definir funciones dentro de otra función,
pero sí se puede llamar a una función dentro de otra función (incluso se puede
llamar a sí misma, es el caso de las funciones recursivas).

Dentro del enunciado de las funciones se debe regresar el control al punto desde
donde se invocó a dicha función. En el caso de las funciones que no regresen
resultados, estas finalizan cuando termina de ejecutarse la última línea de la
función o cuando se llega al enunciado return. Si la función devuelve un resultado,
se debe especificar cuál siguiendo la siguiente forma: return expresión;

Es necesario aclarar que para cada definición de función es necesario un prototipo


de función. En el próximo capítulo explicamos cómo se hacen los prototipos de
funciones.

Para terminar el tema debemos recordar, como consejo, que la mejor práctica al
programar es modularizar o sea, crear múltiples funciones simples que trabajarán
juntas para crear un programa complejo.

Un prototipo de función le da información importante al compilador. En el prototipo


se indican el tipo de dato que retorna la función, el número, tipo y orden de
parámetros que recibe la misma. El compilador utiliza los prototipos para verificar
las llamadas a funciones. Antes el prototipado no existía y el compilador no podía
detectar ciertos errores.

Veamos un ejemplo de un prototipo de función:

int maximo(int, int, int);

Este prototipo indica que la función de nombre máximo retorna como resultado un
valor de tipo entero. Además informa que la función debe ser llamada con tres
parámetros del tipo entero también.

El prototipo también sirve para la coerción de argumentos, o sea, si la función es


llamada con valores de otro tipo diferentes a los definidos en el prototipo de esa
función, el compilador tratará de convertir esos valores a los tipos de datos
correspondientes declarados en el prototipo (esto funcionará siempre y cuando sea
posible la conversión entre esos tipos de datos). Por ejemplo, si la función espera un
entero y recibe un decimal, intentará convertir ese decimal al entero truncando la
parte decimal, lo cual puede generar errores si la exactitud de ese dato es
importante. Por esta razón se debe tener mucho cuidado en la coerción de tipos
automática.

El prototipado de funciones puede omitirse cuando se programa; el compilador


formará el prototipo dependiendo de la primera aparición de la función. También,
por omisión, el compilador asume que toda función regresa un valor del tipo entero
de forma predeterminada.

Hay dos formas de llamar a funciones en C, por valor o por referencia. Cuando los
parámetros de una función son pasados por valor, los parámetros son copiados y
esas copias son pasadas a la función; esto significa que los valores originales no se
modifican. En otras palabras, las modificaciones que se les hagan a las copias
dentro de la función llamada no afectan los valores originales de las variables con
las cuales se llamó la función.

Por otra parte, cuando los parámetros son pasados por referencia, puede alterar los
valores originales de las variables con las cuales se ha llamado la función (si es que
los altera en la función).

Por defecto todas las llamadas a funciones son por valor, a menos que se
especifique lo contrario.

Este tema será ampliado más adelante

El alcance de un identificador es la porción del código en el cual dicho identificador


puede ser “visto” y, por lo tanto, referenciado. Un identificador puede ser una
variable, una etiqueta, un prototipo, una definición de función, etc.

En otras palabras, las reglas de alcance definen hasta dónde un identificador puede
ser usado.

Existen cuatro alcances posibles para un identificador: alcance de función, alcance


de archivo, alcance de bloque y alcance del prototipo de función.

*El único identificador que tiene alcance de función, o sea, sólo es visible y
referenciable dentro de una función, son las etiquetas.

*En tanto, aquellos identificadores declarados fuera de cualquier función tienen


alcance de archivo, o sea, esos identificadores son conocidos desde la línea que son
declarados hasta el fin del código. Por ejemplo, las variables globales, las
definiciones de funciones y los prototipos de funciones que son colocados fuera de
una función, pueden ser referenciados desde el punto donde son definidos en
adelante.

*Los identificadores que son declarados dentro de un bloque (como puede serlo una
función), sólo tienen alcance de bloque, por lo tanto sólo son visibles dentro de ese
bloque y sus bloques anidados (si es que los hay). Por ejemplo, las variables locales
declaradas dentro de una función sólo son visibles dentro de esa función. Lo mismo
para los parámetros de dicha función, que son tratados como variables locales.

Si en un bloque se define una variable con el mismo nombre de una variable


declarada en un bloque que lo anida (llamada variable externa), la variable externa
permanece oculta y no altera la variable local.

*Los únicos identificadores con alcance de prototipo de función son aquellos que se
utilizan en la lista de parámetros del prototipo de una función.

Hasta el momento, las únicas funciones que hemos estudiado han sido llamadas
desde otra función; pero es posible crear funciones que puedan llamarse a sí
mismas, estas son llamadas: funciones recursivas.

Una función puede ser recursiva tanto de forma directa (si es llamada a sí misma) o
de forma indirecta (si llama a una función que luego la llama).

Existen algunos problemas que pueden ser resueltos de forma más eficiente (o su
resolución puede ser más naturalmente pensada) utilizando funciones recursivas.

Una función recursiva puede dar origen a un típico problema en programación, la


recursión infinita, que es cuando una función se llama a sí misma infinitas veces.
Esto detiene el normal funcionamiento de un programa.

Para que esto no suceda una función recursiva debe ser muy bien pensada.
Principalmente una función recursiva debe saber resolver el caso más simple,
llamado caso base. Si la función es llamada con el caso base, inmediatamente
retorna el resultado (no necesita volver a llamarse a sí misma para poder
resolverlo).

Si la función es llamada con un caso más complejo, las sucesivas llamadas a sí


mismas irán virtualmente descomponiendo ese caso hasta llegar a un caso base,
para luego determinar el resultado final de la función. Para entender mejor el
concepto de función recursiva expondremos un caso sencillo: cálculo del factorial
de un número.

El factorial de un número es una función matemática que tiene la siguiente fórmula:


n! = n * (n – 1)!

O sea, el factorial (simbolizado con un signo de exclamación) de un número n


resulta de multiplicar el mismo número por el factorial de ese número menos uno.
De esta manera se va restando hasta llegar al caso base que es el factorial de 1 y
su resultado es 1. Por ejemplo, el factorial de 5 es: 5! = 5 * 4!
el factorial de 4 es: 4! = 4 * 3!
el factorial de 3 es: 3! = 3 * 2!
el factorial de 2 es: 2! = 2 * 1!
el factorial de 1 es: 1! = 1
Como se ve, el factorial de uno es el caso base (el caso más simple conocido).
En definitiva, el factorial de 5 es: 5! = 5 * 4 * 3 * 2 * 1

El cálculo de factorial es posible hacerlo tanto con una estructura de control como
usando una función recursiva. El código de la función recursiva puede ser:

int factorial(int numero)


{
if (numero == 1)
return 1;
else

return (numero * factorial(numero – 1));


}

Por ejemplo, al llamar a la función de la siguiente forma: factorial(5), lo que hará


es verificar si el número pasado es el caso base (o sea, si es 1). Si es así, retorna el
resultado, o sea, 1. En el caso de que el número no sea 1, devuelve el resultado de
multiplicar ese número por la llamada a factorial (a sí misma) con número restado
en 1.

Se iniciará la ejecución de la función pero esta vez con el número 4. Este proceso se
repetirá tantas veces como sea necesario hasta que la variable numero sea el caso
base, o sea 1. Una vez que se llega al caso base, comienza a calcular el factorial (de
atrás hacia adelante).

You might also like