CI-2125 Programación en Lenguaje C PDF
CI-2125 Programación en Lenguaje C PDF
CI-2125 Programación en Lenguaje C PDF
Lenguaje C
2012
ii
Prólogo
El objetivo de esta guía es dar un enfoque práctico a lo que se enseña en el curso de
Computación I de la Universidad Simón Bolívar, ilustrar un poco el proceso mental que se sigue al
momento de generar un programa en solución a un problema planteado. He tratado de cubrir
todos los ejemplos posibles para cada uno de los temas planteados; sin embargo, siempre
existirán pequeñas dudas que solo podrán ser resueltas por medio de la práctica constante.
Esta guía no busca ser una referencia formal y mucho menos un sustituto a los textos
recomendados para el curso; su intención es la de brindar un apoyo adicional que facilite la
comprensión de los temas enseñados en él.
Finalmente me gustaría agradecer a la Prof. Maruja Ortega y el Prof. Roger Clotet, quienes
fueran mis profesores durante los cursos de Computación I y II en la Universidad Simón Bolívar,
por mostrarme lo divertido que puede ser el mundo de los algoritmos y la programación. Y al Prof.
Leonid Tineo, por abrirme las puertas como preparador del Departamento de Computación y
Tecnología de la Información.
Juan P. Ruiz N.
Marzo, 2012
iii
Índice
1. Conceptos Básicos .............................. 1
4. Estructuras Condicionales . . . . . . . . . . . . . . . . . . . . . . . . . 17
5. Estructuras Iterativas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
iv
v
Conceptos Básicos
La pregunta más razonable en este punto sería algo así: “Pero… ¿Nuestra computadora
puede entender lo que escribimos?”. La respuesta corta es NO, la computadora habla un lenguaje
muy particular conocido como lenguaje de máquina, el cual está compuesto por instrucciones en
código binario.
Tú Chino Mandarín
1
Importante: Code::Blocks viene en dos versiones, la primera incluye el compilador GCC, la segunda
no incluye compilador. Para poder compilar los programas escritos dentro del IDE es necesario
descargar la versión con compilador incluido (aproximadamente 70MB).
Una vez escrito nuestro código fuente debemos saber cómo compilarlo utilizando
Code::Blocks.
Al realizar estos pasos se abrirá una ventana con la consola de Windows ejecutando
nuestro nuevo programa.
2
Algoritmos Secuenciales
La programación, sin importar el área de aplicación, fue creada para generar soluciones a
problemas de automatización de tareas, reduciendo cualquier operación a tan solo entrada y
salida de datos, liberando de trabajo al ser humano. Al conjunto de pasos para solucionar dicho
problema se le llama Algoritmo.
Procesador de
Entrada: N Salida: N2
alimentos: N*N
Los pasos básicos para el diseño de un algoritmo valido son los siguientes:
3
b. Salidas: Tipo y propiedades que deben cumplir los valores resultantes expresados
en términos de los datos de entrada (Postcondición).
4
Estructura de un programa en C
Ahora que ya conocemos toda la base teórica necesaria echémosle un vistazo a nuestro
primer programa:
/* Mi Primer Programa */
int main(){
int numero;
numero = 2+2;
return 0;
1. /* Mi Primer Programa */
/* Esto también
Es
Un
Comentario valido */
5
La segunda manera de realizar un comentario es con el uso de doble barras // al inicio del
texto que deseamos que el compilador ignore. La diferencia entre método y el anterior es que en
este caso el compilador solo interpretará como comentario lo que siga después de la doble barra y
por el resto de la línea, sin la posibilidad de realizar saltos.
// Esto es un Comentario
Esto NO es un comentario
2. int main(){
Esta línea es muy especial, ya que la encontraras en todos los programas de C, así como en
muchos otros lenguajes de programación. Se trata de la declaración de una función, en este caso
la función principal del programa. La palabra reservada int se refiere al valor de retorno de la
función como un número de la familia de los enteros (integer), mientras que la palabra main se
refiere al nombre propio de la función.
En un principio todos los programas que escribas en C deben poseer esta línea, ya que es la que
le indica al compilador donde iniciar el programa, y en su debido momento también le indicará
donde terminar.
3. int numero;
Este es nuestro primer encuentro con una instrucción, en este caso en particular con una
instrucción de declaración de variable. Con esta línea le estamos indicando al compilador que
usaremos una variable llamada “numero” en la cual almacenaremos valores del tipo entero.
Adicionalmente, toda instrucción debe finalizar con punto y coma.
4. numero = 2+2;
Otra instrucción, esta vez estamos diciéndole al compilador que sume 2+2 y guarde el
resultado dentro de “numero”. No haré demasiado énfasis en esto por ahora, profundizaremos en
las declaraciones y asignaciones en el próximo capítulo.
5. return 0;
Nuevamente nos encontramos con una instrucción esta vez utilizamos la palabra reservada
return la cual indica al programa que debe abandonar la ejecución de la función y continuar a
partir del punto en el que se realizó la llamada. El 0 es el valor de retorno de la función. Por
convención, cuando “main” devuelve un valor 0 indicamos que todo está correcto en el programa.
Un valor distinto normalmente indica un error en la ejecución.
6
6. }
Con esta llave le estamos indicando al programa que finalizamos la función “main”. Las llaves
suelen indicar el inicio y final de una función o una instrucción, aunque también pueden tener
otros usos que más adelante veremos.
El único problema con este programa es, si obedecieron a la introducción de esta guía y
corrieron a probarlo, habrán notado que no hace absolutamente nada. Está bien, suma
correctamente dos más dos y guarda el resultado, pero nosotros no podemos verlo. Para eso hace
falta trabajar con entradas y salidas de datos, las cuales veremos en un par de capítulos.
int main(){ //Inicio del bloque principal del programa, función main
//
int numero; //Declaración de variables
//
//
numero = 2+2; //Secuencia de instrucciones
//
7
Variables y Operadores
Variables
Desde el punto de vista de un programador y sin adentrarnos en lo filosófico del asunto, una
variable es un elemento cuyo valor puede cambiar a lo largo de la ejecución del programa. Desde
el punto de vista de nuestra computadora, una variable es un espacio dentro de la memoria que
nos permite almacenar información relativa al programa que estamos desarrollando. El origen de
dicha memoria no es de nuestra incumbencia.
Para el resto de la guía las definiciones de sintaxis se realizaran con la siguiente convención. La
información entre corchetes [] indicarán una palabra reservada que cumplirá la función que se
indica dentro de los corchetes. La información entre <> corresponden a un texto que tomara la
función de lo que se indica en su interior. Los doble corchetes [[ ]] indicarán una parte opcional en
la sintaxis.
El identificador será el nombre por el que nos referiremos a la variable, será una secuencia de
caracteres (letras, números y “_”) que distingue entre mayúsculas y minúsculas y debe comenzar
por una letra o el carácter “_”.
El tipo se refiere a la clase de valores que será capaz de tomar la variable. Los tipos existentes
son:
8
Adicionalmente, la sintaxis nos permite declarar más de una variable del mismo tipo en una
sola instrucción; basta con separar los identificadores de cada variable con una coma y por
supuesto nunca olvidar el “;” al finalizar la instrucción.
Ejemplos:
int variable;
float MiIndice, _Pi = 3,14;
char Dia,Mes,Ano;
short edad1,edad2,edad3;
Operadores
Los operadores son elementos que generan ciertos cálculos al utilizarlos en conjunto con las
variables. Como es de esperarse, entre ellos encontraremos los mismos utilizados en las
matemáticas; sin embargo, contaremos con unos cuantos adicionales. Existen cuatro tipos de
operadores: Aritméticos, de Asignación, Lógicos y Relacionales.
Aritméticos: Asignación:
• + Suma • = Asignación
• - Resta • - = Resta y asignación
• * Multiplicación • * =Multiplicación y asignación
• / División • / =División y asignación
• % Resto de la división • %= Resto y asignación
9
Lógicos: Relacionales:
Adicionalmente, existe una prioridad por parte del compilador al realizar las operaciones que
es muy importante tener en cuenta, para así poder evitar errores de cálculos al momento de
escribir un programa.
Prioridad de operadores:
• ()
• !
• *, /, %
• + , -
• < , <= , > , >=
• == , !=
• &&
• ||
Importante: En caso de que existan en una instrucción más de un operador con la misma
prioridad, entre ellos, la prioridad será mayor para el que se encuentre más a la izquierda.
Al ver los operadores, es normal sentirse tentado a utilizarlos de la misma manera que estamos
acostumbrados dentro del mundo de las matemáticas. Sin embargo, existen situaciones especiales
para cada uno de los operadores, que hace falta aclarar antes de lanzarnos de lleno a utilizarlos en
la vida real. Vayamos uno por uno.
10
//Sintaxis de operadores aritméticos
<expresión> + <expresión>
<expresión> - <expresión>
<expresión> * <expresión>
<expresión> / <expresión>
<expresión> % <expresión>
Cuando realizamos la división utilizando variables enteras, el resultado será solo la parte entera
del resultado final, teniendo la posibilidad de obtener el residuo utilizando el operador %. Cuando
en la división a menos uno de las variables utilizadas es real, obtendremos como resultado un
número real, el cual incluirá una cantidad considerable de los decimales del resultado final.
División:
• 5/2 ---------> 2
• 5%2 ---------> 1
• 5.0/2 -------> 2.5
• 5/2.0 -------> 2.5
• 5.0/2.0 ----->2.5
Dejando los operadores aritméticos claros hablemos ahora del operador Asignación. Vimos que
en el caso de los operadores aritméticos estos operaban de izquierda a derecha, pero en el caso
del operador = tendremos lo contrario; él operará de derecha a izquierda, tomando todo lo que se
encuentre a su derecha y almacenándolo a la variable a su izquierda.
Es normal confundir al operador asignación con su versión matemática, es por esto que
debemos tener claro que no estamos hablando de una igualdad, sino de una asignación; por lo
tanto, cuando decimos que “x = 1+2” no estamos diciendo que “x” es igual a 3, sino que “x”
11
AHORA será igual a 3, sin importar su valor anterior. Esto hace posible decir cosas como “x = x+1”;
lo que en matemáticas te llevaría a ser condenado al exilio, aquí solo significa que al valor de “x” le
sumamos 1 y se lo asignamos a “x” nuevamente. Consideremos el ejemplo siguiente:
//Operadores de asignación
int a=10, b=0;
b = a;
b = b + 1;
Vemos que la primera instrucción declara dos variables a y b a las cuales les asigna los valores
10 y 0 respectivamente. Luego le asignamos a “b” el contenido de “a” y finalmente le asignamos a
“b” el contenido de “b + 1”, lo cual dejaría como valores finales de “a” y “b”, 10 y 11
respectivamente. No dejes que la frustración te consuma, si no entiendes estos resultados
inmediatamente mira atentamente a la hoja por dos minutos.
Una vez entendido el operador asignación podemos hablar del resto de los operadores de
asignación. Para todos ellos la formula es la misma:
//Expresión equivalente
Algunos ejemplos:
a += b => a = a + b
a *= b => a = a * b
a -= b => a = a – b
a /= b => a = a / b
12
Instrucciones de Entrada y Salida
A pesar de todo lo que se ha aprendido hasta ahora, aun no hemos sido capaces de observar
personalmente el comportamiento de nuestros programas, sabemos que funcionan, sabemos
cómo funcionan, pero no podemos verlo. Para esto hace falta usar las funciones de entrada y
salida de datos que nos proporciona muy gentilmente C. Pero para empezar a hablar de ellas
primero hace falta hablar un poco sobre las instrucciones al preprocesador.
#include Nos permite incluir un archivo fuente externo nuestro programa, esto nos
permite agregar a nuestro código funciones creadas previamente tanto por nosotros como
por terceros, evitándonos así mucho trabajando.
#define Esta instrucción nos permite definir constantes numéricas para su uso dentro del
programa.
variable = NUMERO +1; //Ejemplo de eso de una constante declarada por define
13
//Sintaxis para el uso de printf
#include <stdio.h> //Necesario para su uso, solo es requerida su inclusión
//una vez por código fuente
Luego vemos que la instrucción de escritura comienza con “printf(“ y termina con “);”, esta es
básicamente la estructura de cualquier función en el lenguaje C, pero ya llegaremos a ese punto.
Vemos que dentro de los paréntesis de nuestra función “printf();” tenemos una secuencia de
control escrita entre comillas, con esto le indicamos al compilador cual es la estructura de la frase
que queremos imprimir en pantalla. Dentro de la secuencia de control podemos colocar tanto
texto como ciertos modificadores que se encargarán de darle forma a la salida:
Modificadores
%f ->Numero Real
%c ->Caracter
Cada modificador tiene su uso específico. Empecemos con el “\n”, este modificador le indica al
compilador que debe insertar un salto de línea dentro de la frase que queremos imprimir. Los
modificadores “%d”,”%f” y “%c” le indican al compilador que, en el lugar donde ellos están, se
debe colocar un dato del tipo que ellos indiquen. La pregunta es ¿Cómo sabe el compilador de
dónde sacará estos datos?, sencillo, se los damos nosotros por medio de la lista de variables que
se introduce justo después de la secuencia de control, y el compilador se encargará de ir
sustituyéndolas en los modificadores, exactamente en el mismo orden de aparición.
14
Código Fuente Consola
printf(“Hola\nMundo!”); Hola
Mundo!
Como se puede apreciar la sintaxis para lectura es prácticamente igual que la de escritura,
la única diferencia que existe es que esta vez se debe agregar un ampersand “&” antes de cada
variable donde deseemos almacenar los valores leídos. El resto de la sintaxis se mantiene,
incluyendo los modificadores.
15
Código Fuente
#include <stdio.h>
int main(){
Con esto finaliza la primera parte de la guía, los invito a probar por ustedes mismos cada
una de las cosas que se les ha enseñado hasta el momento, asegurándose de entender muy bien el
funcionamiento de cada una, usando el printf y scanf como apoyo para interactuar con su
programa y observar detalladamente lo que ocurre.
16
Estructuras Condicionales
No Condición Sí
Acción 2 Acción 1
if (<condición>)
{Acción 1}
else
{Acción 2}
El uso de esta instrucción es de la forma siguiente. Se utilizan las palabras reservadas por
el lenguaje C, if y else, para determinar el bloque de instrucciones a seguir en el caso de cumplirse
o no, respectivamente, la condición bajo la cláusula if. La condición por motivos obvios siempre
debe estar presente; sin embargo, la cláusula else puede o no ser incluida.
Si durante la corrida del programa el compilador no encuentra una clausula else, en caso
de no cumplirse la condición dentro del if, el programa continuará su camino como si el
condicional no existiese. En el caso de encontrarse la cláusula else, entonces el programa
procederá a ejecutar las instrucciones bajo esta si la condición no se cumple.
17
Puede parecer un poco enredado a primera vista, pero una vez vistos un par de ejemplos
todo quedará más claro.
Todas las condiciones que necesiten ser escritas en el lenguaje C deben ser escritas
mediante el uso de operadores lógicos y relacionales, los cuales fueron presentados durante la
sección de operadores. En esta oportunidad se explicará el funcionamiento de los mismos.
Cuando se escribe una expresión de condición se espera tener como resultado si la misma
es Verdadera o por el contrario, es Falsa. Estos dos posibles resultados son representados por
medio de los llamados “Valores Booleanos”, que en el mundo de la programación conocemos
como TRUE y FALSE.
Cuando utilizamos variables relacionales para establecer una relación entre variables y/o
constantes lo que obtenemos como resultado a estas expresiones es un valor booleano. Por
ejemplo, si tenemos la expresión “2<3” obtendremos como resultado un “TRUE”; sin embargo, si
tenemos la expresión “3<2” nuestro resultado será “FALSE”. Lo mismo ocurre para el resto de los
operadores relacionales.
Ahora solo nos queda un último punto por aclarar, los operadores lógicos. ¿Qué sucede si
necesito que se cumplan no una, sino dos condiciones simultáneamente para poder realizar una
acción? Podrían simplemente colocar un if dentro de otro y así se estarían verificando ambas
condiciones, pero existe una forma mucho más fácil.
Los operadores lógicos no trabajan con números o letras propiamente, sino con valores
booleanos, y operan de la siguiente manera:
Tabla de la Verdad
A B A&&B A||B !A !B
FALSE FALSE FALSE FALSE TRUE TRUE
FALSE TRUE FALSE TRUE TRUE FALSE
TRUE FALSE FALSE TRUE FALSE TRUE
TRUE TRUE TRUE TRUE FALSE FALSE
18
La explicación detrás de esta tabla es bastante sencilla y se puede deducir por los nombres
de los operadores. Esto queda de su parte.
Una buena manera de designar un valor determinado para las los valores booleanos, es
por medio de la definición de constantes en nuestro programa. Las constantes en lenguaje C
utilizando la directiva al preprocesador “define”.
#define TRUE 1
#define FALSE 0
#define N 10
#define A 5
#define B 20
Una vez definida una constante, esta es válida por el resto del programa, y se utiliza como
cualquier otro valor dentro de él.
int n;
n = TRUE;
n = N;
n = A + B;
19
Instrucciones: switch, case, default, break
Existen casos en los que las posibilidades de un condicional son más que verdaderas o
falsas. Supongamos que somos Sheldon Cooper y necesitamos saber qué actividad nos toca en
función del día actual. Para resolver este problema la mejor opción es almacenar en una variable
el día actual de la semana y utilizar un switch para determinar qué actividad corresponde.
Switch
2
1 d
El switch acepta una variable como entrada y define un case, con su respectivo bloque de
acciones, para cada posible valor que podría tomar dicha variable. El caso default nos permitirá
determinar que debe hacer el switch para los casos no determinados por la lista de case.
//Sintaxis Switch
switch(<Variable>)
{
case <Valor1>: <Acciones1>
break;
Hay una consideración adicional cuando trabajamos con la instrucción switch. Una vez que
el switch encuentra el caso correspondiente al valor actual de la variable, procederá no solo a
ejecutar las acciones de dicho caso, sino las acciones de todos los casos posteriores hasta
encontrarse con la instrucción break. El break se encargará de cortar el ciclo y sacar al programa
de la instrucción switch.
De la misma manera, para asignar a varios case el mismo bloque de acciones, basta con
colocar un caso tras otro, no colocando el bloque de acciones sino hasta llegar al último caso:
20
switch(<Variable>)
{
case <Valor1>:
case <Valor2>: <Acciones2>
break;
En este ejemplo el switch ejecutará las mismas acciones tanto si el valor es <Valor1> como
<Valor2>. A continuación algunas posibilidades del switch.
int entero;
char caracter;
switch(entero)
{
case 1: entero += 1;
printf(“%d”, entero);
break;
default: printf(“%d”,2);
}
switch(caracter)
{
case ‘a’: printf(“Hola”);
break;
21
Estructuras Iterativas
Los ciclos son casos especiales de los condicionales. Esta vez las acciones se realizarán
tantas veces como sea necesario hasta que la condición deje de cumplirse. Las condiciones
tendrán la misma estructura que en el caso de los condicionales.
No Condición Sí
Acciones
Una de las cosas más importantes a tener en cuenta cuando utilizamos un ciclo es la
siguiente. Siempre debemos incluir dentro de las acciones alguna instrucción que rompa con la
condición y nos permita salir del bucle. Recuerden que una de las condiciones para la realización
de un algoritmo es la finitud.
El lenguaje C nos brinda tres instrucciones distintas para realizar ciclos, while, for,
do…while. Cada una tiene una situación de uso distinta, pero en el fondo todas funcionan de la
misma manera.
while(<condición>)
{Acciones}
22
//Sintaxis de la instrucción do… while
do
{Acciones}
while(<condición>);
int main(){
int contador=1;
int main(){
int i;
23
Veamos ahora la sintaxis del do…while. La diferencia entre esta y las otras dos estructuras
es evidente. El “do…while” nos permitirá realizar las acciones listadas bajo la instrucción do al
menos una vez antes de verificar la condición while. La Utilidad de esto puede no parecer
importante, pero lo es; el caso más inmediato de uso necesario de esta instrucción es en la
realización de un “menú”. Cuando tenemos interacciones con el usuario que incluyen su elección
entre varias opciones, siempre querremos imprimir las opciones antes de verificar su decisión.
Acciones
No Condición Sí
int main(){
int contador=1;
do{
printf(“ %d ”, contador);
contador += 1;
}
while(contador < 10) //Noten que la condición cambia, ya que al llegar a 10
//ya la impresión se ha realizado
}
24
Funciones y Alcance de Variables
Cuando hablábamos de los pasos para crear un algoritmo, uno de los pasos más importantes
era el análisis descendente. Dijimos que el análisis descendente era la subdivisión del problema
principal en pequeños problemas más sencillos, los cuales pudiéramos resolver utilizando
estructuras algorítmicas simples. Por lo general nos encontraremos que estas tareas simples será
necesario realizarlas más de una vez durante el desarrollo de nuestro programa. Sin embargo,
existe un problema enorme con esto.
Los programadores nos caracterizamos por ser las personas más flojas del universo, lo cual
tiene mucho sentido si pensamos en que nuestra tarea es crear programas que hagan las cosas
por nosotros. Así que lo más sensato sería que los creadores de nuestro querido C nos dieran una
herramienta para solucionar el problema de tener que escribir una y otra vez las mismas líneas de
código. Por suerte, ellos piensan en todo, y nos tienen una solución maravillosa a la cual llamarón
“funciones”.
Las funciones son un conjunto de instrucciones, diseñadas para realizar una tarea específica.
Adicionalmente, la sintaxis de las funciones nos permitirá especificar un conjunto de parámetros
de entrada y un parámetro de salida. Espero que no hayan olvidado el ejemplo del procesador de
alimentos.
El tipo de salida podrá ser cualquiera de los tipos de datos simples que ya conocemos. El
nombre de la función cumplirá con las reglas que ya especificamos para los identificadores.
Finalmente, la especificación de los parámetros cumplirá con las mismas reglas de la declaración
de variables.
25
La instrucción return es utilizada dentro de las funciones para indicar cuál será el valor de
salida de la función. Las funciones pueden ser declaradas tanto con un tipo de salida como con
parámetros del tipo void.
Las funciones tienen un lugar especial dentro de nuestro código fuente, que más que una
obligación es una formalidad creada por motivos de orden. Esta convención exige que todas las
declaraciones de funciones se encuentren al final del código fuente, justo después de la función
principal main. Sin embargo, existe un problema con esto, y es que C es un lenguaje secuencial, lo
cual implica que para poder utilizar una función en un punto especifico del programa, es necesario
que C conozca la existencia de dicha función en ese punto. Entonces, si todas las declaraciones de
funciones se encuentran luego de la función main, ¿cómo podremos hacer uso de ellas?.
Como ya les dije antes, nuestros amigos de C pensaron en todo, y para este caso crearon las
llamadas “Definiciones de funciones”. La definición de una función no es más que un prototipo,
un modelo de declaración de función que se coloca al inicio del programa, justo después de las
instrucciones de preprocesador.
Como ven, para definir una función no hace falta más que la línea principal de la declaración,
sin necesidad de colocar las acciones. Un detalle importante es que la definición lleva un punto y
coma al final, mientras que la declaración no.
int main ()
{
int numero = 20;
HolaMundo(numero); //Uso de la función HolaMundo
}
26
Alcance de variables
Con la introducción de las funciones se nos abre el camino a toda una nueva ciencia conocida
como el alcance de variables. En el lenguaje C toda variable que se declara se encuentra limitada al
ambiente donde fue declarada. De momento existen dos posibles ambientes de declaración de
una variable.
Ambiente Global
Ambiente Local
Las variables declaradas en el ambiente global son conocidas como variables globales, y
podrán ser accesibles y modificables desde cualquier punto de nuestro programa. Si declaramos
una variable dentro de una función, ya sea la función main o cualquier otra que hayamos creado,
la variable será conocida como variable local y será solo accesible dentro de la función en la que
se ha declarado.
Dos funciones diferentes pueden tener variables con el mismo nombre, sin embargo cada una
será independiente de la otra. Adicionalmente, las variables locales solo existirán durante la
ejecución de la función en la que fueron declaradas, mientras que las variables globales durarán
durante toda la ejecución del programa.
Si una variable local puede ser declarada utilizando el mismo nombre que una variable local;
en ese caso, todos los cambios que ocurran sobre esa variable dentro de la función serán
manejados por la variable local, permaneciendo la global intacta.
Pasaje de parámetros
Cuando insertamos valores dentro de los parámetros de entrada en una función, estamos
realizando un pasaje de parámetros. Existen dos tipos de pasaje de parámetros: Por valor y por
referencia.
27
Hasta ahora hemos realizado solo pasaje de parámetros por valor. Sin embargo, existen
tareas para las cuales este tipo de pasaje nos resulta muy limitado. Los invito como ejercicio a
realizar una función que nos permita intercambiar los valores contenidos en dos variables
distintas. Cuando hayan intentado lo suficiente pueden continuar leyendo.
Para poder hablar del pasaje de parámetros por referencia hace falta primero realizar una
introducción a los Apuntadores.
Apuntadores
Bajo esta convención tenemos cinco variables, y cada una de ellas tiene su propio nombre. De
esta manera, Var0 se encuentra en una cajita de nombre “0x0” y la Var4 se encuentra en una
cajita de nombre “0x4”.
[Tipo] *<Nombre>;
//Ejemplos
int *a;
float *b,*c,d; //En esta declaración, solo b y c son punteros, d no debido a
//que no contiene un * antes de su nombre.
char *punt;
28
Existen además dos operadores exclusivos para trabajar con apuntadores.
//Operadores de punteros
El operador & nos permitirá obtener la dirección de memoria de una variable y asignársela a
un puntero. Mientras que el operador * nos permitirá acceder al contenido de la variable
apuntada por el puntero; este operador es totalmente independiente del asterisco utilizado para
declarar al puntero.
Si mezclamos estos operadores con todos los que ya conocemos, tendremos una infinidad de
instrucciones, que nos permitirán realizar prácticamente todo los que nos venga a la cabeza.
int main(){
int a=3, b=8; //Declaramos dos variables a y b con valores 3 y 8
int *z,*p; //Declaramos dos punteros z y p
z=&a //Guardamos el nombre de la cajita de a en z
p=z //Copiamos el contenido de z en p
/*En este punto tanto p como z están apuntando a la misma cajita que contiene
el valor de a */
Con esto finaliza la pequeña introducción al infinito mundo de los apuntadores. Los invito a
probar distintas instrucciones utilizando operadores hasta comprender completamente cómo se
comportan antes de seguir avanzando.
Para finalizar el capítulo ya solo nos resta hablar de cómo funciona el pasaje por referencia.
Ya dijimos que cuando una variable es declarada dentro de una función esta será destruida al
finalizar la llamada a la función, y nuestra única manera de conservar el valor de alguna de ellas es
por medio de la instrucción return. Sin embargo, ¿qué sucede cuando necesitamos conservar más
de un valor durante una llamada a una función?. La solución más obvia es crear variables globales,
pero esto no siempre es conveniente. La segunda opción es utilizar pasaje por referencia.
29
El pasaje por referencia ocurre cuando en vez de pasar el valor de una variable como
parámetro, lo que le damos a la función es la dirección de memoria que almacena a dicho valor.
De esta manera, todos los cambios ocurrirán directamente en la cajita de memoria
correspondiente a la variable local del ambiente que realizó la llamada a la función, conservando
así todos los cambios realizados a las variables pasadas por referencia.
Este último tema puede resultar infinitamente confuso; es por esto que recomiendo leer el
último párrafo una y otra vez hasta que se comprenda cada oración, y luego practicar el
comportamiento de una función específica para ambos tipos de pasaje de parámetros.
int main ()
{
int num1 = 4, num2 = 6;
Intercambio(&num1,&num2); //Notemos que no hace falta declarar punteros
//Basta con pasar la dirección de memoria y
//esta se almacenará en el puntero que
//declaramos como parámetro
}
30
Tipos de Datos Estructurados
De manera muy resumida, los tipos de datos estructurados son aquellos formados por la
agrupación de tipos de datos simples; como lo son int, float, y char. Los tipos de datos
estructurados más comunes son los vectores, matrices, cadenas de caracteres y estructuras. En lo
que resta de la guía hablaremos de estos tipos y como utilizarlos.
Arreglos (Vectores)
Los arreglos son el tipo de datos estructurados más sencillo que existe. Los arreglos nos
permiten agrupar datos del mismo tipo básico bajo un mismo identificador. Cada arreglo tendrá
un tamaño definido fijo, el cual se determina durante la declaración; este tamaño es el que
determinará cuantas variables contendrá nuestro arreglo.
int A[20];
Para acceder a los distintos datos almacenados dentro de nuestro arreglo se hace uso de un
subíndice, el cual indicará la posición del dato al que queremos acceder. Las posiciones en los
arreglos van desde cero (siendo este el primer dato) hasta n-1 (siendo n el tamaño del arreglo). El
error más común al momento de trabajar con arreglos es olvidar que el índice del primer
elemento es [0] y no [1]. Por ejemplo, si declaráramos un arreglo de 5 posiciones llamado A,
gráficamente se vería de esta manera.
31
Var1 Var2 Var3 Var4 Var5
int B[5];
int A[10];
int i;
for(i=0;i<10;i+=1) A[i]=0;
int V[10];
int i;
for(i=0;i<10;i+=1){
printf(“introduce V[%d]”,i);
scanf(“%d”,&V[i]);
}
32
Arreglos Bidimensionales (Matrices)
Un arreglo bidimensional se comporta de la misma manera que una matriz; en donde los
subíndices serán la fila y la columna a la que queramos acceder. El siguiente ejemplo ilustra
gráficamente un arreglo bidimensional declarado como “int A[3][5]”.
int A[3][5];
int i,j;
for(i=0;i<3;i+=1)
for(j=0;j<5;j+=1) A[i][j]=0;
33
Cadena de Caracteres (Strings)
Las cadenas de caracteres son casos especiales de arreglos unidimensionales, en los que el
tipo de datos recibido es char. C tiene un tratamiento especial para estos arreglos a los cuales
denominamos Strings.
Quizá la consideración más importante a tener cuando trabajamos con Strings es la siguiente:
C inserta al final de cada cadena de caracteres un cero, indicando el final de la misma; de esta
manera podemos tener frases de menor tamaño al del arreglo y C siempre sabrá donde terminar.
Veamos los ejemplos.
//Manejo de Strings en C
char Nombre[] = “maria”; //En este caso, el string tendrá tamaño 6, las
//5 letras de “maria” más el carácter nulo
/* Lectura y escritura */
printf(“%s”,Nombre);
scanf(“%s”,Nombre);
34
Estructuras
Finalmente llegamos al tipo de datos estructurados más complejo. Las estructuras nos
permitirán unir no solo los tipos de datos simples, sino también arreglos multidimensionales y
hasta otras estructuras. Cada estructura que definamos puede tener un número infinito de
variables internas, cada una de las cuales puede ser de un tipo distinto.
struct <Identificador>
{
[tipo] <nombre_objeto>;
[tipo] <nombre_objeto>;
[tipo] <nombre_objeto>;
...
} <objeto_estructura>;
Luego de declarada la estructura, si hemos especificado un nombre para ella, se puede utilizar
como cualquier otro tipo.
struct persona
{
char Nombre[10];
char dirección [20];
int anoNacimiento;
} fulanito;
fulanito.anoNacimiento = 1991;
fulanito.Nombre = “Fulano”;
35
La asignación entre estructuras está permitida solo si son del mismo tipo.
fulano = fulanito;
//Inicialización de estructuras
struct A{
int x;
struct c{
char c;
char d;
}y;
int z;
};
36