You are on page 1of 56

i

PROGRAMACIN DE
COMPUTADORES EN
LENGUAJE C

Departamento de Ingeniera de Sistemas


Universidad Tecnolgica de Pereira
2004

ii

TABLA DE CONTENIDO
Pgina
1. FUNCIONES EN LENGUAJE C
1.1 Tipos de parmetros recibidos por una funcin
1.1.1 Parmetros por valor
1.1.2 Parmetros por referencia
2. ESTRUCTURAS
2.1 Estructuras Anidadas
3. PUNTEROS O APUNTADORES
3.1 Declaracin de un puntero
3.2 Operadores Monarios * y &
3.3 Usos de los punteros
3.4 Problemas Comunes con los Punteros
3.5 Aritmtica de Punteros
3.6 Relacin entre punteros y arreglos
3.7 Punteros a estructuras
3.8 Punteros a punteros
3.9 Punteros a funciones
4. METODOS DE ORDENACIN
4.1 Ordenacin Burbuja
4.2 Ordenacin por Seleccin
4.3 Ordenacin por Insercin
4.4 Ordenacin Shell
4.5 Ordenacin rpida usando qsort()
5. METODOS DE BSQUEDA
5.1 Bsqueda secuencial o lineal
5.2 Bsqueda binaria

iii

6. ARCHIVOS EN LENGUAJE C
6.1 Funcin fopen( )
6.2 Funcin fclose( )
6.3 Manejo de archivos mediante fwrite() y fread()
6.3.1 Funcion fwrite( )
6.3.2 Funcin fread( )
6.3.3 Funcin ftell( )
6.3.4 Funcin fseek( )
6.4 Archivos con formato
6.5 Archivos de caracteres
6.5.1 Funcin fputc()
6.5.2 Funcion fgetc()
7. MANEJO DEL PUERTO PARALELO CON LENGUAJE C
7.1 Breve historia del puerto paralelo
7.2 Tipos de puerto paralelo
7.2.1 Puerto paralelo estndar (Standard Parallel Port - SPP)
7.2.2 Puerto Paralelo PS/2 (Bidireccional Simple)
7.2.3 Puerto paralelo mejorado (Enhanced Parallel Port - EPP)
7.2.4 Puerto paralelo de capacidad extendida (ECP)
7.2.5 Puertos multi-modo
7.3 Que es un puerto?
7.3.1 Descripcin de pines del puerto paralelo
7.3.2 Direcciones del puerto
7.3.3 Como encontrar puertos existentes
7.4 Funciones de Turbo C para el manejo de puertos
7.4.1 Funcin inportb
7.4.2 Funcin outportb
BIBLIOGRAFIA

1. FUNCIONES EN LENGUAJE C
Las funciones son subprogramas que pueden ser ejecutados dentro del programa principal
o dentro de otras funciones, lo cual resulta muy til para realizar procedimientos que se
repiten comnmente. Una funcin para el manejo de cadenas de caracteres muy utilizado es
strlen(), la cual devuelve la longitud de una cadena de caracteres.
El formato general para crear una funcin es el siguiente:
tipo_devuelto nombre_funcion(tipo1 parametro1,tipo2 parametro2,)
{
instrucciones;
return(variable);
}

Donde:
tipo_devuelto:

El tipo de dato devuelto por la funcin, por ejemplo int o float. Si la


funcin no devuelve ningn valor, tipo_devuelto es void.

nombre_funcion: El nombre que el programador le da a la funcin.


tipo1, tipo2 :

El tipo de parmetros recibidos por la funcin. Si la funcin no


recibe parmetros se utiliza void.

parametrox:

El nombre del parmetro x.

Ejemplo 1.1:
Realizar una funcin que reciba una cadena de caracteres y devuelva su longitud.
int longitud(char *cadena)
{
int i=0;
while(cadena[i]!='\0')
i++;
return i;
}

Es importante anotar que una funcin permite devolver solo un valor pero puede recibir
tantos parmetros como se necesiten. Sin embargo, por medio de parmetros pasados por
referencia a una funcin, esta puede devolver dos o ms valores.

Universidad Tecnolgica de Pereira 2004

1.1 Tipos de parmetros recibidos por una funcin


Uno de los aspectos ms interesantes del uso de funciones es la forma como los parmetros
son entregados a estas. Existen dos formas:
Parmetros por valor
Parmetros por referencia
1.1.1 Parmetros por valor
Un parmetro por valor es una variable que se enva a una funcin y que a pesar de ser
modificada dentro de la misma, conserva su valor fuera de esta (programa princiapal). Las
funciones que reciben nicamente parmetros por referencia solo devuelven un valor.
Ejemplo 1.2:
La siguiente funcin recibe dos parmetros de tipo entero e intercambia sus valores.
void cambiar(int x, int y)
{
int z;
z=x;
x=y;
y=z;
}

Suponiendo que dos variables a=10 y b=6 son pasadas a la funcin, entonces las variables
x, y terminan con los valores 6 y 10 respectivamente, cumpliendo de esta forma el
propsito de la funcin pero solo dentro de esta. Sin embargo, los valores de las variables a
y b no son modificados y se dice que fueron pasados por valor.
1.1.2 Parmetros por referencia
En contraste con los parmetros por valor, un parmetro por referencia es aquel dato que
una vez pasado y utilizado por una funcin, cambia de valor. Un tpico parmetro por
referencia son los arreglos, ya que una vez se realizan cambios en el arreglo dentro de una
funcin, estos cambios se vuelven permanentes.
Ejemplo 1.3:
El objetivo de este ejemplo es intercambiar los valores de dos variables por medio de una
funcin de igual forma como se hizo en el Ejemplo 1.2, pero esta vez utilizando parmetros
por referencia.

Universidad Tecnolgica de Pereira 2004

#include<conio.h>
#include<stdio.h>
void cambiar(int *x, int *y)
{
int z;
z=*x;
*x=*y;
*y=z;
}
void main()
{
int a,b;
printf("entre a: ");
scanf("%d",&a);
printf("entre b: ");
scanf("%d",&b);
cambiar(&a,&b);
printf("a=%d b=%d",a,b);
getch();
}

En las primeras lneas de este programa se solicita al usuario dos valores para las variables
a y b. Suponiendo que a=5 y b=8, despus de hacer un llamado a la funcin cambiar()
en el programa principal los valores de a y b son 8 y 5 respectivamente.
Ejemplo 1.4:
La siguiente funcin recibe una cadena de caracteres y devuelve el nmero de vocales y el
nmero de consonantes que hay en esta cadena.
void letras(char *cadena,int *voc,int *cons)
{
int i;
*voc=0;
*cons=0;
for(i=0;cadena[i]!='\0';i++)
{
if(cadena[i]=='a'||cadena[i]=='e'||cadena[i]=='i'
||cadena[i]=='o'||cadena[i]=='u')
(*voc)++;
else
if(cadena[i]>='a'&&cadena[i]<='z')
(*cons)++;
}
}

Universidad Tecnolgica de Pereira 2004

2. ESTRUCTURAS
Una estructura es un conjunto de variables de diferente tipo agrupadas bajo un mismo
nombre y definidas por el programador, lo que facilita el manejo de los datos contenidos en
esta. El formato general para declarar un tipo de estructura en lenguaje C es el siguiente:
struct nombre_tipo_estructura
{
tipo_dato_1 miembro_1;
tipo dato_2 miembro_2;
. . .
tipo_dato_N miembro_N;
}instancia_1,instancia_2,... instancia_M;

Es importante anotar que nombre_tipo_estructuta es solo un tipo de datos como lo


son, por ejemplo, las palabras reservadas int o float. As que si se desean crear
variables de tipo estructura (instancias), sus nombres deben ser escritos inmediatamente
despus de la definicin del tipo de estructura o declaradas as:
struct nombre_tipo_estructura nombre_variable;
2.1 Estructuras Anidadas
Una estructura anidada es aquella que se encuentra dentro de otra estructura. Al momento
de anidar dos estructuras se debe tener en cuenta que la estructura que se va anidar est
definida primero (antes) que aquella estructura que va a alojarla.
Ejemplo 2.1:
struct fecha
{
int anno;
int mes;
int dia;
};
struct alumno
{
char nombre[40];
char cedula[14];
struct fecha ingreso;
};

Ejemplo 2.2:
Suponga que se utiliza una estructura para almacenar la hora, minutos y segundos de algn
evento en particular. Construya una funcin que reciba dos estructuras A y B de dicho tipo
como parmetros y devuelva 1 si el evento B ocurri primero que el evento A, devuelva -1
de lo contrario y devuelva 0 si los dos eventos ocurrieron al mismo tiempo.

Universidad Tecnolgica de Pereira 2004

struct hora
{
int hh;
int mm;
int ss;
};
int primero(struct hora a,struct hora b)
{
if(a.hh > b.hh)
return 1;
else if(a.hh < b.hh)
return -1;
else if(a.mm > b.mm)
return 1;
else if(a.mm < b.mm)
return -1;
else if (a.ss > b.ss)
return 1;
else if (a.ss < b.ss)
return -1;
else
return 0;
}

Ejemplo 2.3:
Desarrollar un programa que lea desde el teclado el nombre y la hora de entrada
(HH/MM/SS) en formato 24horas de un conjunto de empleados, los cuales se encuentran
almacenados en un arreglo de estructuras y muestre en pantalla el empleado que lleg
primero en la lista. Sugerencia: Utilice la funcin creada en el Ejemplo 2.2.
#include<conio.h>
#include<stdio.h>
#include<iostream.h>
struct hora
{
int hh;
int mm;
int ss;
};
struct empleado
{
char nombre[40];
struct hora tiempo;
};
struct empleado lista[100];

Universidad Tecnolgica de Pereira 2004

Continuacin Ejemplo 2.3


int ingresar(struct empleado a[])
{
int n,i;
clrscr();
printf("Empleados a almacenar?: ");
scanf("%d",&n);
for(i=0;i<n;i++)
{
printf("Nombre empleado %d: ",i);
cin.getline(a[i].nombre,40);
printf("Hora Entrada (HH MM SS): ");
scanf("%d %d %d",
&a[i].tiempo.hh,&a[i].tiempo.mm,&a[i].tiempo.ss);
}
return n;
}
int primero(struct hora a,struct hora b)
{
if(a.hh > b.hh)
return 1;
else if(a.hh < b.hh)
return -1;
else if(a.mm > b.mm)
return 1;
else if(a.mm < b.mm)
return -1;
else if (a.ss > b.ss)
return 1;
else if (a.ss < b.ss)
return -1;
else
return 0;
}
void hallar_primero(struct empleado lista[],int tam)
{
struct empleado elprimero;
elprimero=lista[0];
for(int i=1;i<tam;i++)
{
if(primero(lista[i].tiempo,elprimero.tiempo)==-1)
elprimero=lista[i];
}
printf("%s Entro Primero",elprimero.nombre);
printf("a las %d:%d:%d
",elprimero.tiempo.hh,elprimero.tiempo.mm,elprimero.tiempo.ss
);
getch();
}

Universidad Tecnolgica de Pereira 2004

Continuacin Ejemplo 2.3


void main()
{
int N;
N=ingresar(lista);
hallar_primero(lista,N);
}

Ejemplo 2.4:
Implementar un programa en lenguaje C para realizar operaciones bsicas (suma, resta,
multiplicacin, divisin) con nmeros complejos en formato rectangular utilizando un tipo
de estructura llamada complejo compuesta por dos campos para almacenar la parte real y
la parte imaginaria de dicho nmero complejo.
(a + jb) + (c + jd ) = (a + c) + j (b + d )
(a + jb) (c + jd ) = (a c) + j (b d )
(a + jb) * (c + jd ) = (ac bd ) + j (ad + bc)
(a + jb) /(c + jd ) = (ac + bd ) /(c 2 + d 2 ) + j (bc ad ) /(c 2 + d 2 )
#include<conio.h>
#include<stdio.h>
typedef struct complejo
{
float r;
float i;
};
void suma(complejo A,complejo B, complejo *R)
{
R->r=(A.r+B.r);
R->i=(A.i+B.i);
}
void resta(complejo A,complejo B, complejo *R)
{
R->r=(A.r-B.r);
R->i=(A.i-B.i);
}
void producto(complejo A,complejo B, complejo *R)
{
R->r=A.r*B.r-A.i*B.i;
R->i=A.r*B.i+A.i*B.r;
}

Universidad Tecnolgica de Pereira 2004

Continuacin Ejemplo 2.4


void division(complejo A,complejo B, complejo *R)
{
R->r=(A.r*B.r+A.i*B.i)/(B.r*B.r+B.i*B.i);
R->i=(A.i*B.r-A.r*B.i)/(B.r*B.r+B.i*B.i);
}
void leer(complejo *A,char n)
{
float re,im;
printf("Complejo %c?:",n);
scanf("%f %f",&re,&im);
A->r=re;
A->i=im;
}
char mostrar(complejo A,char o)
{
char resp;
if(A.i<0)
printf("A %c B = %0.2f %0.2fj\n",o,A.r,A.i);
else
printf("A %c B = %0.2f+%0.2fj\n",o,A.r,A.i);
printf("Desea continuar (S/N)?: ");
resp=getch();
return(resp);
}
int menu(void)
{
int opcion;
printf("\n1. Suma\n");
printf("2. Resta\n");
printf("3. Multiplicacion\n");
printf("4. Division\n");
printf("Entre una opcion: ");
scanf("%d",&opcion);
printf("\n");
return(opcion);
}

Universidad Tecnolgica de Pereira 2004

Continuacin Ejemplo 2.4


void main()
{
char r;
int opcion;
complejo A,B,R;
do
{
clrscr();
leer(&A,'A');
leer(&B,'B');
opcion=menu();
switch(opcion)
{
case 1: suma(A,B,&R);
r=mostrar(R,'+');
break;
case 2: resta(A,B,&R);
r=mostrar(R,'-');
break;
case 3: producto(A,B,&R);
r=mostrar(R,'*');
break;
case 4: division(A,B,&R);
r=mostrar(R,'/');
}
}
while(r=='s'||r=='S');

Universidad Tecnolgica de Pereira 2004

10

3. PUNTEROS O APUNTADORES
Antes de explicar el concepto de puntero es conveniente repasar la organizacin de la
memoria de un computador.

Figura 3.1. Memoria de un computador.

Como se aprecia en la Figura 3.1, la memoria de un computador se mide en bytes los cuales
estn ubicados en una determinada direccin o posicin dentro de esta memoria. En el caso
de lenguaje C, por ejemplo, las variables de tipo entero ocupan dos bytes en alguna
posicin (direccin) de la memoria, los cuales a su vez se identifican bajo un solo nombre,
de tal forma que el programador no tenga que preocuparse por la direccin de memoria
donde se almacena el valor que representa esa variable.
int x : se reservan dos bytes de memoria bajo el nombre x.
As pues, una variable es un conjunto de bytes agrupados bajo un mismo nombre. Entonces
que es un puntero? Un puntero es una variable que contiene la direccin de memoria donde
se encuentra almacenada otra variable de cualquier tipo.
3.1 Declaracin de un puntero
La declaracin un puntero en lenguaje C es muy simple y se siguen prcticamente las
mismas normas que para declarar una variable normal. Primero se digita el tipo de dato al
cual va a apuntar el puntero, seguido por un asterisco y el nombre del puntero.
tipo_dato * nombre_puntero;
Como se mencion anteriormente, los punteros pueden apuntar a variables de cualquier
tipo. He aqu algunos ejemplos de declaracin de punteros.
char * puntero_char;
float * p;
int * pint;

Universidad Tecnolgica de Pereira 2004

11

En este caso se declararon tres punteros, el primero de ellos se llama puntero_char y


puede apuntar o almacenar la direccin de memoria de una variable tipo char. De igual
forma los punteros p y pint almacenan direcciones de memoria de variables de tipo real y
entero respectivamente.
3.2 Operadores Monarios * y &
Ningn tratamiento de punteros en lenguaje C estara completo sin un estudio de los
operadores monarios. El primero de ellos, el *, puede causar un poco de confusin ya que
se utiliza tanto para declarar punteros (como se explic en la seccin anterior), como para
extraer el contenido de una posicin de memoria. El segundo de ellos, el & (ampersand), se
utiliza para extraer la direccin de memoria donde se encuentra una variable.
void main()
{
int a,b;
//lnea 1
int *pa;
//lnea 2
a=56;
//lnea 3
pa=&a;
//lnea 4
b=*pa-4;
//lnea 5
printf("a=%d b=%d",*pa,b); //lnea 6
}

En la primera lnea del programa anterior se declaran un par de variables a y b. En la


segunda lnea se aprecia una de las formas de utilizar el operador *, esto es, para declarar
un puntero llamado pa. A continuacin en la lnea 3, se asigna un valor de 56 a la variable
a cuya direccin es almacenada en el puntero pa mediante el operador & en la lnea 4, por
lo cual se dice que el puntero pa apunta a la variable a. Por ltimo en la lnea 5 se utiliza el
operador * esta vez para averiguar el valor almacenado en la posicin de memoria a la cual
apunta pa, lo que produce que se muestre en pantalla a=56 y b=52.
3.3 Usos de los punteros
Los punteros son una de las herramientas ms poderosas con las que un programador puede
contar, pero a la vez son una de las formas ms fciles de generar errores en los programas
si no son usados adecuadamente. Los punteros han encontrado aplicacin principalmente en
las siguientes reas:
Asignacin dinmica de memoria.
Paso de parmetros por referencia a funciones.
Mejoramiento de la eficiencia de los programas.
3.4 Problemas Comunes con los Punteros
A continuacin se mostrarn cuatro de los errores ms comunes que se cometen cuando se
utilizan punteros en un programa.

Universidad Tecnolgica de Pereira 2004

12

1. No inicializacin de apuntadores : Por no inicializacin de un apuntador se debe


entender el no asignarle un valor o direccin de memoria antes de empezar a utilizarlo.
Como cualquier otra variable, el apuntador puede almacenar un valor arbitrario al
momento de ser declarado que podra ser la direccin de memoria de alguna otra
variable actualmente en uso. Por esto, cuando el puntero es utilizado puede modificar el
valor de otra variable o detener la ejecucin del programa sin una aparente razn. Vale
la pena anotar que este tipo de errores son difciles de detectar ya que no se produce
ningn tipo de error en tiempo de compilacin. Veamos el siguiente programa.
void main()
{
int x,y;
//lnea 1
int *px;
//lnea 2
y=253;
//lnea 3
*px=y-21;
//lnea 4
printf("x=%d y=%d",x,y); //lnea 5
}

En este programa existe un error en la lnea 4, ya que el puntero px est siendo utilizado
antes de que este apunte a una variable, que en este caso debera ser la variable x. El
problema se soluciona inicializando el puntero px tal como se muestra a continuacin:
void main()
{
int x,y;
//lnea 1
int *px;
//lnea 2
y=253;
//lnea 3
px=&x;
//lnea 4
*px=y-21;
//lnea 5
printf("x=%d y=%d",x,y); //lnea 6
}

2. Inicializacin de un puntero sin el operador & : Este error consiste en tratar de


inicializar un puntero con el valor de una variable ya sea porque se omiti
deliberadamente o se olvid el operador &, lo que produce un error en tiempo de
compilacin.
void main()
{
float x;
//lnea
float *px; //lnea
x=78.236;
//lnea
px=x;
//lnea
printf("x=%f",*px);
}

1
2
3
4
//lnea 5

En este caso la lnea 4 es la que genera el error, debido a que el compilador espera que
al puntero px le sea asignada una direccin de memoria y no el valor de la variable x.
Este error se corrige aadiendo el operador & justo antes de la variable x.

Universidad Tecnolgica de Pereira 2004

13

3. Inicializacin de un puntero por medio de una variable de diferente tipo al del


apuntador: En este tipo de errores el programador trata de asignarle al apuntador la
direccin de memoria de una variable que es de otro tipo diferente al del apuntador. En
otras palabras los apuntadores solo pueden apuntar a las variables del mismo tipo que se
utiliz al momento de declarar el apuntador.
void main()
{
int x, *p;
float y;
y=258.56;
p=&y ;
printf("y= %f",y);
}

//lnea
//lnea
//lnea
//lnea

1
2
3
4

En este ejemplo el puntero p fue declarado para que apuntara a una variable de tipo
entero y sin embargo en la lnea 3 se intenta asignarle la direccin de memoria de la
variable y que es de tipo real, lo que produce un error al momento de compilar el
programa.
4. Asignacin de punteros de diferente tipo: A pesar de que en lenguaje C se permite
asignar el valor de un puntero a otro del mismo tipo, esto no es posible entre punteros
de diferente tipo.
void main()
{
int x, *px;
//lnea 1
float y, *py;
//lnea 2
x=56;
//lnea 3
y=45.789;
//lnea 4
py=&y;
//lnea 5
px=py;
//lnea 6
printf(x=%d y=%f,x,*px); //lnea 7
}

En las lneas 1 y 2, los punteros px y py fueron declarados para apuntar a variables de


tipo entero y real respectivamente, por lo que la asignacin de la lnea 6 es incorrecta y
se genera un error. Este error se corrige declarando al puntero px de tipo float.
3.5 Aritmtica de Punteros
En lenguaje C se pueden efectuar dos operaciones aritmticas sobre los punteros, la suma y
la resta.

Universidad Tecnolgica de Pereira 2004

14

void main()
{
int x[3]={4,6,8};
int *px;
px=x;
printf("px=%p *px=%d \n",px,*px);
px++;
printf("px=%p *px=%d \n",px,*px);
getch();
}

Suponiendo que los tres datos enteros x[0],x[1],x[2] se encuentran en las direcciones
de memoria 0xFFA1, 0xFFA3 y 0xFFA5 respectivamente, el valor inicial del puntero px
es 0xFFA1. Una vez se ejecuta la instruccin px++ el nuevo valor de px es 0xFFA3, ya
que el incremento se realiza en base al nmero de bytes del tipo de variable al cual apunta
px, y no de uno en uno como podra esperarse.
3.6 Relacin entre punteros y arreglos
Existe una relacin estrecha entre un puntero y un arreglo. Despus de todo, el nombre de
un arreglo es un puntero al primer elemento de dicho arreglo. Por lo ejemplo:
float q[]={5,2,3};

La instruccin anterior declara un arreglo q y lo inicializa con los valores 5,2 y 3. La


direccin del primer elemento (5) se encuentra en el nombre del arreglo y es equivalente a
&q[0]. Existen varias formas de acceder a los elementos de un arreglo.
1. Usando aritmtica de punteros:
// Este programa calcula el promedio de
// los elementos de un arreglo
void main()
{
int w[]={5,7,8,11,18,3};
int *pw;
float prom=0;
pw = w;
for(int i=0;i<6;i++)
prom+=*(pw+i);
prom=prom/6;
printf(Promedio=%f,prom);
}

Universidad Tecnolgica de Pereira 2004

15

2. Indexando un puntero:
void main()
{

int w[]={5,7,8,11,18,3};
int *pw;
float prom=0;
pw = w;
for(int i=0;i<6;i++)
prom+=pw[i];
prom=prom/6;
printf(Promedio=%f,prom);

}
3.7 Punteros a estructuras
Cuando se declara un tipo de estructura es conveniente utilizar la palabra typedef para
crear un sinnimo de dicho tipo de estructura con el propsito de simplificar la escritura y
entendimiento de los programas por parte del programador.
typedef struct Nombre_Estructura
{
Datos_Miembro;
};

Habiendo utilizado typedef, la declaracin de un puntero a una estructura se realiza de


igual forma que para un puntero de cualquier otro tipo:
Nombre_Estructura * Puntero;

Por ejemplo:
typedef struct hora
{
int hh,mm,ss;
};
hora *p;

Observe que se ha declarado un tipo de estructura llamado hora por medio de typedef,
lo que permite la utilizacin de la palabra hora como si fuera cualquier palabra reservada
int o float predefinidas. El puntero p se declara para apuntar a una estructura tipo
hora. Ahora bien, suponga que se desea leer la hora actual desde el teclado y almacenarla
en una estructura tipo hora por medio de un apuntador, entonces:
hora hactual;
p=&hactual;
printf(Entre hora (hh/mm/ss): );
scanf(%d %d %d: &p->hh,&p->mm,&p->ss);

Universidad Tecnolgica de Pereira 2004

16

El primer paso fue inicializar el apuntador p con la direccin de la estructura hactual.


Ntese la forma como se accede a los elementos de la estructura por medio del puntero p.
Notacin 1
p->hh : Dato almacenado en hh
Notacin 2
(*p).hh

: Dato almacenado en hh

En la segunda notacin para acceder a los datos miembro de hactual, es necesario


utilizar los parntesis debido a la mayor jerarqua del operador punto (.). Para comprender
mejor como utilizar punteros con estructuras anidadas se realiza el siguiente ejemplo que
consiste en un programa que lee el nombre y la hora de entrada de una persona y luego
muestra estos datos en pantalla.
Ejemplo 3.1:
#include<conio.h>
#include<stdio.h>
#include<iostream.h>
typedef struct hora
{
int hh,mm,ss;
};
typedef struct persona
{
char nombre[30];
hora entrada;
};
persona w;
persona *q;
void main()
{
clrscr();
q=&w;
printf("Entre nombre: ");
scanf("%s",q->nombre);
printf("Hora entrada: ");
scanf("%d %d %d",&q->entrada.hh,&q->entrada.mm,
&q->entrada.ss);
printf("Hora = %d %d
%d",(*q).entrada.hh,(*q).entrada.mm,(*q).entrada.ss);
getch();
}

Las estructuras tambin pueden tener como miembro a uno o varios punteros a estructuras
del mismo tipo. Por ejemplo, la estructura alumno definida a continuacin tiene un
puntero de tipo alumno, lo que significa que este tipo de estructuras se pueden enlazar entre
si.

Universidad Tecnolgica de Pereira 2004

17

typedef struct alumno


{
char nombre[30];
char codigo[12];
alumno *siguiente;
};

Ejemplo 3.2:
El siguiente programa lee informacin acerca de un conjunto de alumnos incluida la fecha
de ingreso y la almacena temporalmente en un arreglo de estructuras creado
dinmicamente. Luego a travs de la funcin encontrar_antiguo() halla el alumno
mas antiguo del arreglo.
#include<conio.h>
#include<stdio.h>
#include<iostream.h>
#include<alloc.h>
typedef struct fecha
{
int dia,mes,anno;
};
typedef struct alumno
{
char nombre[30];
fecha ing;};
int primero(fecha,fecha);
void encontrar_antiguo(alumno *,int);
void main()
{
alumno *p;
int N;
printf("No. Alumnos ?: ");
scanf("%d",&N);
p=(alumno*)malloc(N*sizeof(alumno));
for(int i=0;i<N;i++)
{
printf("NOMBRE: ");
scanf("%s",(p+i)->nombre);
printf("FECHA ING (DD/MM/AA): ");
scanf("%d %d %d",&(p+i)->ing.dia,&(p+i)->ing.mes,
&(p+i)->ing.anno);
}
encontrar_antiguo(p,N);
}

Universidad Tecnolgica de Pereira 2004

18

void encontrar_antiguo(alumno *vector,int n)


{
alumno prim;
prim=vector[0];
for(int i=1;i<n;i++)
{
if(primero(prim.ing,(vector+i)->ing)==1)
prim=*(vector+i);
}
printf("%s ingreso primero",prim.nombre);
getch();
}
int primero(fecha a,fecha b)
{
if(a.anno>b.anno) return(1);
else if (a.anno<b.anno) return(-1);
else if(a.mes>b.mes) return(1);
else if (a.mes<b.mes) return(-1);
else if(a.dia>b.dia) return(1);
else if (a.dia<b.dia) return(-1);
else return(0);
}

3.8 Punteros a punteros


Un puntero a otro puntero es una variable que contiene la direccin de memoria donde se
encuentra otro puntero que a su vez apunta a otra variable (tipo puntero inclusive). En
general, los punteros pueden ser declarados con diferentes niveles, por ejemplo, un puntero
px que apunta a una variable entera x es un puntero de primer nivel, mientras que si un
puntero ppx se define para apuntar a un puntero del mismo tipo que px, se dice entonces
que ppx es un puntero de segundo nivel y as sucesivamente.
Se debe tener en cuenta que no puede haber asignacin directa entre punteros de diferente
nivel ya que en realidad corresponden a tipos de datos diferentes.
Uno de los usos principales de los punteros a punteros es el paso de punteros por referencia
a funciones. Esto resulta muy til cuando se trabaja con estructuras de datos dinmicas
como las listas enlazadas.
Ejemplo 3.3:
void main()
{
int r,*q,**p;
// lnea 1
r=50;
// lnea 2
q=&r;
// lnea 3
p=&q;
// lnea 4
printf("r=%d *q=%d **p=%d",r,*q,**p); // lnea 5
getch();
}

Universidad Tecnolgica de Pereira 2004

19

Figura 3.2. Punteros a Punteros

En el Ejemplo 3.3, p es un apuntador de segundo nivel y q es un puntero de primer nivel.


Suponiendo que las variables p, q, r ocupan las direcciones de memoria ilustradas en la
Figura 3.2, q almacena por lo tanto la direccin de memoria que ocupa r (0x1F1B). En la
lnea 4 se inicializa el puntero p con la direccin de memoria que ocupa q, y como
resultado se muestra el valor 50 en pantalla. Se concluye entonces que la variable r se
puede representar a travs de los punteros p y q como *q y **p respectivamente.
3.9 Punteros a Funciones
Al igual que una variable, una funcin ocupa posiciones de memoria donde se almacenan
temporalmente las instrucciones de la misma. La forma de declarar un puntero a una
funcin es la siguiente:
Tipo_Devuelto (*Nombre_Puntero)(Tipo1, Tipo2 , )

Donde Tipo_Devuelto representa el tipo de datos devuelto por la funcin a la cual


apunta el puntero declarado, mientras que Tipo1, Tipo2, representan el tipo de
parmetros que la funcin recibe. Por ejemplo, suponga que se tiene una funcin que recibe
las longitudes de los lados de un tringulo. La funcin debe devolver 1 si es posible crear
un tringulo con los lados de longitudes dadas, lo cual es posible verificando que la suma
de las longitudes de los lados menores sea menor que la longitud del lado mayor. La
funcin devuelve 0 de lo contrario.
float verificar(float a,float b,float c)
{
if(a>b&&a>c)
{
if((b+c)>a)
return 1.0;
else
return 0.0;
}
else
{
if(b>a&&b>c)
{
if((a+c)>b)
return 1.0;

Universidad Tecnolgica de Pereira 2004

20

else
return 0.0;
}
else
{
if((a+b)>c)
return 1.0;
else
return 0.0;
}
}

Suponga adems que con base en las longitudes de los lados del tringulo se desea calcular
el permetro y el rea del mismo.
float perimetro(float a, float b, float c)
{
return(a+b+c);
}
float area(float a,float b, float c)
{
float s;
s=(a+b+c)/2.0;
return(pow((s*(s-a)*(s-b)*(s-c)),0.5));
}

Ntese entonces que las tres funciones verificar(), area() y permetro(),


reciben el mismo nmero de parmetros y del mismo tipo y devuelven un dato de tipo real.
Por lo tanto en este caso se puede utilizar un puntero para ejecutar cualquiera de las
funciones, tal y como se muestra en el siguiente programa.
void main()
{
float x,y,z;
float (*p)(float,float,float);
printf("Entre lados: ");
scanf("%f %f %f",&x,&y,&z);
p=verificar;
if(p(x,y,z)==1)
{
p=perimetro;
printf("Permetro = %.2f\n",p(x,y,z));
p=area;
printf("Area = %.2f",p(x,y,z));
getch();
}
else{
printf("No es posible crear triangulo!"); }
getch();
}

Universidad Tecnolgica de Pereira 2004

21

4. MTODOS DE ORDENACIN
4.1 Ordenacin Burbuja
Este es tal vez uno de los mtodos de ordenacin ms populares el cual utiliza
comparaciones sucesivas entre los elementos adyacentes de un arreglo. El mtodo
comienza con la comparacin de los dos primeros elementos del arreglo, los cuales son
intercambiados si se encuentran en el orden contrario. Luego se realizan las comparaciones
del segundo y tercer elemento, cuarto y quinto y as sucesivamente hasta realizar la
comparacin del penltimo y ltimo elemento del arreglo, realizando intercambio cada vez
que los elementos estn en el orden incorrecto. Se deben realizar N iteraciones para ordenar
completamente el arreglo.
void burbuja(int *x,int n)
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n-1-i;j++)
{
if(x[j]>x[j+1])
cambiar(x+j,x+j+1);
}
}
}

El mtodo no es muy eficiente ya que el nmero de comparaciones siempre ser el mismo


ya sea que el arreglo est ordenado o desordenado. Se puede comprobar que el nmero de
comparaciones en funcin del tamao del arreglo es:
No. de comparaciones = N * (N-1) /2
4.2 Ordenacin por Seleccin
Este mtodo consiste en hallar el menor de los N elementos del arreglo y almacenarlo en la
primera posicin del mismo. Luego se encuentra el menor de los (N-1) elementos restantes
y se almacena en la segunda posicin del arreglo. El proceso contina hasta que solo
quedan los dos ltimos elementos del arreglo por ordenar. A continuacin se muestra uno
de los posibles algoritmos desarrollado en lenguaje C.

Universidad Tecnolgica de Pereira 2004

22

void seleccion(int *x,int n)


{
int i,j,pos,menor;
for(i=0;i<n-1;i++)
{
menor=x[i];
pos=i;
for(j=i+1;j<n;j++)
{
if(x[j]<menor)
{
menor=x[j];
pos=j;
}
}
cambiar(&x[i],&x[pos]);
}
}

Para este tipo de ordenacin el nmero de comparaciones es n(n-1)/2 lo mismo que para
la ordenacin burbuja. Sin embargo el nmero de cambios es menor para la ordenacin por
seleccin para el caso promedio.
4.3 Ordenacin por Insercin
El procedimiento para ordenar un arreglo por el mtodo de ordenacin por insercin es el
siguiente. Primero se ordenan los dos primeros elementos del arreglo. Luego se inserta el
tercer elemento en alguna posicin entre la posicin 1 y 2 de acuerdo al valor de dicho
elemento y se desplazan los elementos que sean necesarios. Posteriormente se toma el
cuarto elemento y se inserta entre las posiciones 1 a 3 de acuerdo a su valor. La ordenacin
termina cuando se toma el ltimo elemento del arreglo y se inserta entre las posiciones 1 a
N-1, quedando la lista totalmente ordenada.
Se muestra a continuacin una de las posibles formas de implementar este algoritmo en
lenguaje C.
void insercion(int *arreglo,int n)
{
register int i,j;
for(i=1;i<n;i++)
{
j=i;
while(j>0&&(arreglo[j]<arreglo[j-1]))
{
cambiar(arreglo+j,arreglo+j-1);
j--;
}
}
}
Universidad Tecnolgica de Pereira 2004

23

En el caso de ordenacin por insercin el nmero comparaciones depende de cmo se


encuentra ordenada la lista inicialmente. La Tabla 4.1 muestra el nmero de comparaciones
requeridas para ordenar la lista para tres casos tpicos.
CASO
Lista ordenada
Caso medio
Lista completamente desordenada

COMPARACIONES
n-1
2
(n + n - 2)/4
(n2 +3n -4)/2

Tabla 4.1

Se deduce que la ordenacin por seleccin se comporta naturalmente, es decir, que trabaja
poco cuando el arreglo est casi ordenado y trabaja mucho cuando el arreglo est
totalmente desordenado. Por lo anterior, este mtodo es muy til para aplicaciones donde la
informacin se encuentra prcticamente ordenada.
4.4 Ordenacin Shell
Esta ordenacin debe su nombre a su inventor Donald L. Shell.
El mtodo general de ordenacin Shell se basa en la ordenacin por insercin. El mtodo es
el siguiente:
Se calcula el intervalo inicial por medio de interv=n/2 donde n es el nmero de
elementos del arreglo a ordenar.
Luego se ordenan todos aquellos elementos separados por una distancia dada por
interv. Ejemplo: Se ordenan arreglo[0] y arreglo[interv],
arreglo[1]
y
arreglo[1+interv],
arreglo[2]
y
arreglo[2+interv], y as sucesivamente hasta llegar a arreglo[ninterv-1] y arreglo[n-1].
En el momento en que dos elementos deban ser cambiados, se realiza una ordenacin
por insercin hacia atrs con aquellos elementos separados una distancia interv.
El valor del intervalo (interv) para la siguiente pasada se calcula como la mitad del
anterior, es decir interv=interv/2. El proceso se repite hasta que interv=1.
De acuerdo a estudios realizados por investigadores del tema de la ordenacin, el tiempo de
ejecucin es proporcional a n1.2, donde n es el tamao del arreglo. La eficiencia de la
ordenacin Shell depende del intervalo que se use. Se deben evitar valores de intervalos
potencia de 2. Sin embargo, si se escogieran estos valores, aun as el algoritmo funcionara.

Universidad Tecnolgica de Pereira 2004

24

La siguiente funcin muestra la implementacin del algoritmo de ordenacin Shell en


lenguaje C.
void shell(int *arreglo,int n)
{
int aux,i,j,interv;
interv=n/2;
while(interv>0)
{
for(i=0;i<n-interv;i++)
{
j=i;
while(j>=0&&arreglo[j]>arreglo[j+interv])
{
aux=arreglo[j];
arreglo[j]=arreglo[j+interv];
arreglo[j+interv]=aux;
j=j-interv;
}
}
interv=interv/2;
}
}

4.5 Ordenacin rpida usando qsort()


Esta funcin permite ordenar un arreglo por medio del mtodo de ordenacin rpida,
tambin conocido como Quick Sort. A continuacin se muestra la forma como esta funcin
est declarada, de tal forma que se puedan conocer el tipo y el nmero de parmetros que
esta funcin recibe.
void qsort(void *Primero, size_t NoElem,size_t Ancho,
int(*FComp)(constvoid *, const void *));

Donde:

: Es un puntero al primer elemento del arreglo a ordenar.


NoElem
: Nmero de elementos que tiene el arreglo a ordenar.
Ancho
: El nmero de Bytes que ocupa cada uno de los elementos del arreglo.
Fcomp
: Puntero a la funcin de comparacin la cual compara dos elementos y
devuelve un valor de acuerdo a esos dos valores.
Primero

A pesar de que esta funcin facilita la ordenacin, es necesario utilizar sus parmetros
correctamente. Por ejemplo, ntese que el puntero Primero ha sido declarado como void*,
es decir que esta funcin recibe como primer parmetro un puntero que puede almacenar la
direccin de una variable de cualquier tipo. Otro parmetro de especial cuidado es FComp, el
cual es en realidad un apuntador a una funcin creada por el programador para determinar
la forma como se van a ordenar (ascendente o descendentemente) los elementos del arreglo.

Universidad Tecnolgica de Pereira 2004

25

Al igual que Primero, en Fcomp se debe realizar cast a las variables cuyos tipos no
coincidan con los establecidos.
Ejemplo 4.1:
Ordenar un arreglo de nmeros enteros por medio de la funcin qsort().
#include<conio.h>
#include<stdio.h>
#include<stdlib.h>
int compa(const void *a,const void *b)
{
if(*((int*)a)<*((int*)b))
return(1);
else if(*((int*)a)>*((int*)b))
return(-1);
else
return(0);
}
void main()
{
int x[]={8,2,6,4,10,3};
qsort((void*)x,6,sizeof(x[0]),compa);
getchar();
}

Ejemplo 4.2:
Ordenar de forma ascendente por nombre un arreglo de estructuras del tipo alumno
mostrado a continuacin, por medio de la funcin qsort().
typedef alumno
{
char nombre[30];
char codigo[12];
}

#include<conio.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int fnombre(const void *x,const void *y)
{
return(strcmp(((alumno*)x)->nombre,((alumno*)y)->nombre));
}

Universidad Tecnolgica de Pereira 2004

26

Continuacin Ejemplo 4.2


int fcodigo(const void *x,const void *y)
{
return(strcmp(((alumno*)x)->codigo,((alumno*)y)->codigo));
}
void main()
{
int opcion;
alumno lista[]={{"JUAN","1234"},{"ANTONIO","1236"},
{"ANA","1478"},{"NESTOR","1239"}};
printf("1. Ordenar por nombre\n");
printf("2. Ordenar por codigo\n");
scanf("%d",&opcion);
switch(opcion)
{
case 1: qsort((void*)lista,4,sizeof(lista[0]),fnombre);
break;
case 2: qsort((void*)lista,4,sizeof(lista[0]),fcodigo);
}
for(int i=0;i<4;i++)
{
printf("%10s %10s \n",lista[i].nombre,lista[i].codigo);
}
getchar();
}

En el programa anterior la parte de mayor inters son las funciones fnombre y fcodigo, las
cuales le transfieren al programador el control de la forma como se deben ordenar los
elementos del arreglo lista. Para empezar, ntese que los parmetros de ambas funciones
son de tipo void*, lo que hace necesario realizar cast a estos punteros cada vez que se
desreferencien. Esto se debe a que el compilador requiere saber de que tipo (tamao) son
las variables a las cuales apuntan dichos punteros. Despus de realizar cast a los punteros,
estos se utilizan de igual forma que los punteros de otro tipo.
Ejercicio sugerido: Ordenar un arreglo de cadenas (matriz de caracteres) utilizando la
funcin qsort().
Ejemplo 4.3:
Crear una funcin para calcular la suma de los elementos de un arreglo de nmeros reales.
Luego crear otra funcin que calcule el promedio de los elementos de un arreglo utilizando
para ello la funcin anterior como parmetro de la ltima funcin.
#include<conio.h>
#include<stdio.h>
#include<string.h>

Universidad Tecnolgica de Pereira 2004

27

#include<stdlib.h>
float sumatoria(float *arreglo,int tam)
{
float suma=0;
for(int i=0;i<tam;i++)
suma+=arreglo[i];
return(suma);
}
float promedio(float *vector,int t,float(*fsuma)(float*,int))
{
float prom;
prom=(fsuma(vector,t))/t;
return(prom);
}
void main()
{
float x[4]={4.5,2.4,7.8,-1.5};
float res;
res=promedio(x,4,sumatoria);
printf("El promedio de los elementos es: %0.3f",res);
getchar();
}

Universidad Tecnolgica de Pereira 2004

28

5. METODOS DE BUSQUEDA
La bsqueda junto con la ordenacin son dos de las acciones que ms se realizan en
sistemas informticos permitiendo que la informacin almacenada en bases de datos,
archivos, listas, etc, sea consultada eficazmente por medio de una clave de bsqueda. Para
ello existen dos mtodos de bsqueda los cuales se estudian a continuacin, cuya seleccin
depende del grado del ordenamiento que tenga un archivo o lista.
5.1 Bsqueda secuencial o lineal
Esta bsqueda consiste en consultar o examinar uno a uno los elementos de un arreglo
desde el principio hasta que se encuentra el elemento deseado que contiene la clave de
bsqueda. Si no se encuentra dicho elemento se muestra un mensaje o se devuelve un valor
correspondiente a la posicin dentro del arreglo o a la direccin de memoria donde se
encuentra almacenado el registro buscado. En este tipo de ordenacin el arreglo o archivo
puede encontrarse desordenado. Sin embargo, cuando el tamao del arreglo es muy grande,
el tiempo de bsqueda tambin puede serlo. En el peor de los casos se deben examinar n
elementos, en el mejor de los casos se examinara un registro y en el caso promedio se
examinan n/2 registros.
Ejemplo 5.1
Realizar una funcin para la bsqueda secuencial en un arreglo de estructuras de tipo
producto. Esta funcin debe recibir como parmetros: el arreglo en el que se va a realizar la
bsqueda, su tamao, una variable entera que indica el criterio de bsqueda (1 = Bsqueda
por producto, 2 = Bsqueda por cdigo) y la clave. Esta ltima debe ser por lo tanto un
puntero tipo void.
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<string.h>
typedef struct producto
{
char item[40];
int codigo;
float precio;
};

Universidad Tecnolgica de Pereira 2004

29

Continuacin Ejemplo 5.1


producto *busqueda_lineal(producto *vector,int tam,
int tipo, void *clave)
{
int i;
switch(tipo)
{
case 1:for(i=0;i<tam;i++)
if(strcmp(vector[i].item,(char*)clave)==0)
return(&vector[i]);
return(NULL);
break;
case 2:for(i=0;i<tam;i++)
if(vector[i].codigo==*(int*)clave)
return(&vector[i]);
return(NULL);
break;
case 3:for(i=0;i<tam;i++)
if(vector[i].precio==*(float*)clave)
return(&vector[i]);
return(NULL);
}
}
void main()
{
void *key;
producto *p;
int opcion;
producto lista[]={{"Peras",123,1580.3},{"Jabn",124,1789.3},
{"Naranja",125,7056.38}};
clrscr();
printf("1. Bsqueda por producto \n");
printf("2. Bsqueda por codigo\n");
printf("Elija opcion: ");
scanf("%d",&opcion);
switch(opcion)
{
case 1: printf("Entre nombre producto: ");
key=malloc(40);
scanf("%s",key);
p=busqueda_lineal(lista,3,1,key);
if(p==NULL)
printf("Producto no se encuentra!");
else
printf("%s %d %.3f",p->item,p->codigo,
p->precio);
getchar();
break;

Universidad Tecnolgica de Pereira 2004

30

Continuacin Ejemplo 5.1


case 2: printf("Entre codigo producto: ");
key=malloc(sizeof(int));
scanf("%d",key);
p=busqueda_lineal(lista,3,2,key);
if(p==NULL)
printf("Codigo no se encuentra!");
else
printf("%s %d %.3f",p->item,p->codigo,
p->precio);
getchar();
break;
}
getchar();
}

5.2 Bsqueda binaria


En la bsqueda binaria el arreglo o archivo donde se desea realizar la bsqueda debe estar
ordenado. Esto se debe a que el mtodo consiste en comparar inicialmente a la clave de
bsqueda con el elemento del arreglo que se encuentra en la mitad de dicho arreglo. Si la
clave es mayor (numrica o alfabticamente) significa que el elemento deseado puede
encontrarse despus del elemento del medio, es decir en la segunda mitad. De lo contrario,
significa que el elemento deseado podra encontrarse antes del elemento del medio o sea la
primera mitad del arreglo. Despus de esta primera comparacin puede descartarse una de
las mitades y realizarse el mismo procedimiento de bsqueda descrito en la mitad restante
hasta encontrar el elemento deseado.
Ejemplo 5.2:
Realizar una funcin en lenguaje C para la bsqueda binaria por tem en un arreglo de
estructuras tipo producto que inicialmente se encuentra desordenado. La funcin debe
devolver la direccin del elemento deseado si este se encuentra en el arreglo, de lo contrario
debe devolver NULL.
#include<conio.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct producto
{
char item[40];
int codigo;
float precio;
};

Universidad Tecnolgica de Pereira 2004

31

Continuacin Ejemplo 5.2


producto *busqueda_binaria(producto *vector, int tam,
char *clave)
{
int li,ls,m;
li=0;
ls=tam-1;
while(ls>=li)
{
m=(li+ls)/2;
if(strcmp(clave,vector[m].item)>0)
{
li=m+1;
}
else if(strcmp(clave,vector[m].item)<0)
{
ls=m-1;
}
else
{
return(&vector[m]);
}
}
return(NULL);
}
int compa(const void *a,const void *b)
{
return(strcmp((*(producto*)a).item,(*(producto*)b).item));
}
void main()
{
char nombre[40];
producto *p;
producto lista[]={{"regla",258,420.8},{"borrador",428,789.4},
{"lapiz",145,500.3},{"cinta",290,788.5}};
clrscr();
printf("Nombre producto a buscar: ");
scanf("%s",nombre);
qsort((void*)lista,4,sizeof(producto),compa);
p=busqueda_binaria(lista,4,nombre);
if(p==NULL)
printf("Producto no se encuentra!");
else
printf("%s %d %0.2f",p->item,p->codigo,p->precio);
getchar();
}

Ejercicios Sugeridos:

Realizar el ejercicio anterior usando la funcin predefinida bsearch().

Universidad Tecnolgica de Pereira 2004

32

Crear una funcin en lenguaje C para realizar una bsqueda binaria en un arreglo de
estructuras tipo producto como el descrito anteriormente, esta vez permitiendo que la
clave de bsqueda sea de cualquier tipo (int, float, char*, etc.). Sugerencia: Usar
un puntero tipo void.

Universidad Tecnolgica de Pereira 2004

33

6. ARCHIVOS EN LENGUAJE C
Los archivos pueden ser de dos tipos, binarios o de texto. En los primeros la informacin es
almacenada de tal forma que si se abren con un editor de texto sus datos no son
reconocibles por el lector. En contraste, los archivos de texto permiten una lectura directa
de toda la informacin en ellos contenida.
En lenguaje C existen tres formas de crear un archivo. La primera de ellas consiste en leer o
escribir los datos en el archivo caracter a caracter. La segunda consiste en almacenar esos
mismos datos en forma de registros del mismo tamao escritos / ledos uno a la vez. Por
ltimo se pueden tener archivos con formato, es decir archivos cuyos datos pueden ser
almacenados con cierto formato especificado por el programador y cuya informacin puede
ser leda por medio de editores de texto.
El procedimiento general para leer o escribir en un archivo es el siguiente:
1.
2.
3.
4.

Abrir el archivo.
Si la apertura es exitosa ir a 3, de lo contrario finalizar.
Leer o escribir en el archivo.
Cerrar el archivo.

6.1 Funcin fopen( )


Como se explic anteriormente, el primer paso para empezar a trabajar con un archivo es su
apertura. La funcin que realiza esta tarea en lenguaje C es fopen() y su prototipo se
muestra a continuacin.
FILE *fopen(const char *Nombre_Archivo, const char *Modo)

En donde:
Nombre_Archivo:
Modo:

Cadena que representa el nombre y la ruta del archivo que se desea


abrir.
Cadena que representa el modo en el cual se va a abrir el archivo.

El modos de apertura puede ser uno de los siguientes:


"r"

Abre un archivo existente para lectura solamente.

"w"

Abre el archivo para escritura. Si un archivo con el mismo nombre existe, este ser
borrado.

"a"

Abre un archivo existente para aadir informacin al final. Se crear un nuevo


archivo si no existe un archivo con ese nombre.

"r+"

Abre un archivo existente tanto para lectura como para escritura.

Universidad Tecnolgica de Pereira 2004

34

"w+"

Abre un archivo para lectura y escritura. Si existe un archivo con el mismo nombre
ser sobrescrito.

"a+"

Abre un archivo tanto para leer como para aadir datos. Se crear un archivo si no
existe un archivo con ese nombre.

6.2 Funcin fclose( )


Esta funcin permite cerrar un archivo. A pesar de ser una funcin fcil de usar que tiene,
es de gran importancia ya que si se pasa por alto, los cambios realizados en un archivo que
ha sido modificado no se realizaran.
int fclose(FILE *stream);

6.3 Manejo de archivos mediante fwrite() y fread()


Los archivos generados por medio de estas funciones son archivos binarios y deben ser
ledos / escritos generalmente estructura por estructura. A continuacin se explican los
parmetros de cada una de estas funciones y la forma como funcionan.
6.3.1 Funcion fwrite( )
Esta funcin permite almacenar datos en un archivo registro por registro (estructura por
estructura). La funcin devuelve el numero de elementos guardados exitosamente y esta
declarada as:
size_t fwrite(void *Puntero, size_t Tamano, size_t N,

FILE*Archivo);

Donde:
Puntero: Apunta al inicio del bloque de memoria (estructura o estructuras) que se desea

almacenar.
Tamano:

Longitud en Bytes de cada una de las estructuras a almacenar.

N:

Numero de estructuras (registros) a almacenar a partir de la direccin a la cual


apunta Puntero.

Archivo: Puntero tipo FILE al inicio del archivo.

6.3.2 Funcin fread( )


Esta funcin permite leer desde un archivo registro por registro. La funcin devuelve el
nmero de elementos ledos exitosamente.

Universidad Tecnolgica de Pereira 2004

35

size_t fread(void *Puntero, size_t Tamano, size_t N, FILE *Archivo);


Puntero: Apunta al bloque de memoria donde los datos ledos desde el archivo van a ser

almacenados.
Tamano:

Representa la longitud (en Bytes) de cada uno de los elementos ledos.

N:

Numero de elementos (estructuras o registros) a leer desde el archivo.

Archivo: Puntero tipo FILE al inicio del archivo que se va a leer.

Ejemplo 6.1:
Realizar un programa para administrar la informacin de los productos vendidos por un
supermercado. La informacin requerida para cada producto es la siguiente: nombre,
cdigo y precio. El programa debe contar adems con un men con las opciones para
adicionar producto, buscar producto (por nombre, cdigo), listar todos los productos y
editar producto.
#include<conio.h>
#include<stdio.h>
#include<iostream.h>
#include<string.h>
typedef struct producto
{
char item[40];
int codigo;
float precio;
};
void adicionar()
{
producto t;
FILE *archivo;
clrscr();
printf("ADICIONAR REGISTRO\n");
printf("Entre nombre del producto: ");
cin.getline(t.item,40);
printf("Entre codigo del producto: ");
scanf("%d",&t.codigo);
printf("Entre precio del producto: ");
scanf("%f",&t.precio);
archivo=fopen("c:\\tipo.txt","a");

Universidad Tecnolgica de Pereira 2004

36

Continuacin Ejemplo 6.1


if(archivo==NULL)
{
printf("Error al abrir archivo!");
getchar();
}
else
{
fwrite(&t,sizeof(producto),1,archivo);
printf("Registro almacenado exitosamente...");
getchar();
}
fclose(archivo);
}
void listar()
{
FILE *archivo;
producto temp;
clrscr();
printf("LISTADO DE PRODUCTOS\n\n");
if((archivo=fopen("c:\\tipo.txt","r"))==NULL)
{
printf("Error al abrir archivo!");
getchar();
}
else
{
while((fread(&temp,sizeof(producto),1,archivo))!=0)
{
printf("Nombre: %s\n",temp.item);
printf("Codigo: %d\n",temp.codigo);
printf("Precio: %.2f\n",temp.precio);
printf("---------------------\n\n");
}
printf("Presione ENTER para ir al Menu...");
getchar();
getchar();
}
fclose(archivo);
}
void busqueda()
{
int opcion;
FILE *A;
producto reg;
char clave1[40];
int clave2;
int encontrado;
clrscr();
printf("BUSQUEDA DE PRODUCTOS\n\n");
printf("1. Busqueda por nombre\n");
printf("2. Busqueda por codigo\n");
printf("Elija una opcion: ");
Universidad Tecnolgica de Pereira 2004

37

Continuacin Ejemplo 6.1


scanf("%d",&opcion);
if((A=fopen("c:\\tipo.txt","r"))==NULL)
{
printf("Error al abrir archivo!");
getchar();
}
else
{
switch(opcion)
{
case 1:printf("Entre nombre del producto: ");
cin.getline(clave1,40);
encontrado=0;
while((fread(&reg,sizeof(producto),1,A))!=0)
{
if(strcmp(reg.item,clave1)==0)
{
printf("Nombre: %s\n",reg.item);
printf("Codigo: %d\n",reg.codigo);
printf("Precio: %.2f\n",reg.precio);
printf("---------------------\n\n");
encontrado=1;
}

}
if(!encontrado)
printf("Producto no se encuentra!\n");
printf("Presione ENTER para ir al Menu...");
getchar();
getchar();
break;
case 2:printf("Entre codigo del producto: ");
scanf("%d",&clave2);
encontrado=0;
while((fread(&reg,sizeof(producto),1,A))!=0)
{
if(reg.codigo==clave2)
{
printf("Nombre: %s\n",reg.item);
printf("Codigo: %d\n",reg.codigo);
printf("Precio: %.2f\n",reg.precio);
printf("---------------------\n\n");
encontrado=1;
}
}
if(!encontrado)
printf("Producto no se encuentra!\n");
printf("Presione ENTER para ir al Menu...");
getchar();
getchar();
}

}
fclose(A);
}

Universidad Tecnolgica de Pereira 2004

38

Continuacin Ejemplo 6.1


void editar()
{
int c,enc;
FILE *archivo;
producto t;
long byte,anterior,actual;
clrscr();
printf("EDITAR PRODUCTO\n\n");
printf("Entre codigo del producto: ");
scanf("%d",&c);
if((archivo=fopen("c:\\tipo.txt","r+"))==NULL)
{
printf("Error al abrir archivo");
getchar();
}
else
{
enc=0;
anterior=0;
while(fread(&t,sizeof(producto),1,archivo)!=0)
{
actual=ftell(archivo);
if(t.codigo==c)
{
enc=1;
break;
}
anterior=actual;
}
if(!enc)
{
printf("Codigo no se encuentra! ");
getchar();
}
else
{
printf("DATOS ACTUALES\n\n");
printf("Nombre: %s\n",t.item);
printf("Codigo: %d\n",t.codigo);
printf("Precio: %.2f\n",t.precio);
printf("---------------------\n\n");
printf("INGRESE DATOS NUEVOS\n");
printf("Entre nombre del producto: ");
cin.getline(t.item,40);
printf("Entre codigo del producto: ");
scanf("%d",&t.codigo);
printf("Entre precio del producto: ");
scanf("%f",&t.precio);
byte=ftell(archivo);
fseek(archivo,anterior,0);
fwrite(&t,sizeof(producto),1,archivo);
printf("Datos almacenados exitosamente...");
getchar();
getchar();
Universidad Tecnolgica de Pereira 2004

39

}
}
fclose(archivo);
}
int menu()
{
int opc;
clrscr();
printf("MENU DE OPCIONES\n\n");
printf("1. Adicionar producto\n");
printf("2. Listar todos los productos\n");
printf("3. Busqueda de productos\n");
printf("4. Editar producto\n");
printf("5. Salir\n");
printf("Elija una opcion:");
scanf("%d",&opc);
return(opc);
}
void main()
{
int o;
clrscr();
do
{
o=menu();
switch(o)
{
case 1:adicionar();break;
case 2:listar();break;
case 3:busqueda();break;
case 4:editar();
}
}
while(o!=5);
}

En el programa anterior fue necesario contar con funciones para el borrado y la edicin de
los registros de un archivo, lo cual requiere el uso de la funciones ftell() y fseek()que
se explican a continuacin.
6.3.3 Funcin ftell( )
Esta funcin permite conocer la posicin del puntero de archivo en un momento
determinado, lo cual resulta muy til en el caso de edicin de registros. La funcin es
declarada as:
long ftell(FILE * Archivo)

Vale la pena observar que el valor de la posicin del puntero de archivo devuelto est dado
en bytes desde el inicio del archivo y no en nmero de registros.

Universidad Tecnolgica de Pereira 2004

40

6.3.4 Funcin fseek( )


La funcin fseek() permite posicionar el puntero de archivo en un registro del mismo.
int fseek(FILE *Archivo, long Byte, int desde_donde)

El primer parmetro de esta funcin es el puntero de archivo, mientras que el parmetro


Byte indica la posicin (en bytes) a donde se debe llevar el puntero archivo desde la
posicin indicada por desde_donde, el cual puede tomar uno de los tres valores siguientes:
Constante
SEEK_SET
SEEK_CUR
SEEK_END

Valor
Descripcin
0
Posiciona el puntero desde el inicio del archivo
1
Posiciona el puntero desde la posicin actual
2
Posiciona el puntero desde el final del archivo

6.4 Archivos con formato


En los archivos con formato el programador puede elegir la forma como sus datos pueden
ser almacenados en un archivo. Por ejemplo, los nmeros reales pueden ser almacenados
con determinado nmero de dgitos o las cadenas con un determinado nmero de
caracteres. Las funciones principales para el manejo de este tipo de archivos son
fprintf() y fscanf() y no deben ser utilizadas junto con fwrite() y fread() debido
a la diferencia de formatos presentes entre los dos.
Las funciones fprintf() y fscanf() se utilizan de la misma forma que las funciones
printf() y scanf(), solo que incluyendo un parmetro adicional que corresponde al
puntero de archivo.
int fprintf(FILE *Archivo, const char *cadena_control)
int fscanf(FILE *Archivo, const char *cadena_control)

Ejemplo 6.2:
Realizar un programa como el del Ejemplo 6.1 pero utilizando archivos con formato.
#include<conio.h>
#include<stdio.h>
#include<iostream.h>
#include<stdlib.h>
typedef struct producto
{
char item[40];
int codigo;
float precio;
char distri[40];
};

Universidad Tecnolgica de Pereira 2004

41

Continuacin Ejemplo 6.2


void adicionar()
{
FILE *A;
producto t;
clrscr();
printf("ADICIONAR PRODUCTO\n");
printf("Nombre: ");
cin.getline(t.item,40);
printf("Codigo: ");
scanf("%d",&t.codigo);
printf("Precio: ");
scanf("%f",&t.precio);
printf("Distribuidor: ");
cin.getline(t.distri,40);
A=fopen("c:\\t\\forma.txt","a");
if(A==NULL)
{
printf("Error al abrir archivo!");
getchar();
}
else
{
fprintf(A,"%s\t%d\t%f\t%s\n",t.item,t.codigo,t.precio,
t.distri);
printf("Producto almacenado exitosamente ...");
getchar();
}
fclose(A);
}
void listar()
{
FILE *Archivo;
producto t;
clrscr();
printf("LISTANDO PRODUCTOS\n");
Archivo=fopen("c:\\t\\forma.txt","r");
if(Archivo==NULL)
{
printf("Error al abrir archivo!");
getchar();
}
else
{
while(fscanf(Archivo,"%s %d %f %s",&t.item,&t.codigo,
&t.precio,&t.distri)!=EOF)
{
printf("Nombre: %s\n",t.item);
printf("Codigo: %d\n",t.codigo);
printf("Precio: %f\n",t.precio);
printf("Distribuidor: %s\n\n",t.distri);
}
getchar();
getchar();
Universidad Tecnolgica de Pereira 2004

42

}
fclose(Archivo);
}
void buscar()
{
FILE *A;
producto t;
int enc,cod;
clrscr();
printf("BUSQUEDA DE PRODUCTOS\n");
printf("Entre codigo del producto: ");
scanf("%d",&cod);
A=fopen("c:\\t\\forma.txt","r");
if(A==NULL)
{
printf("Error al abrir archivo!");
getchar();
}
else
{
enc=0;
while(fscanf(A,"%s %d %f %s",&t.item,&t.codigo,
&t.precio,&t.distri)!=EOF)
{
if(t.codigo==cod)
{
enc=1;
break;
}
}
if(enc)
{
printf("Nombre: %s\n",t.item);
printf("Codigo: %d\n",t.codigo);
printf("Precio: %f\n",t.precio);
printf("Distribuidor: %s\n",t.distri);
}
else
{
printf("Codigo no se encuentra!");
}
getchar();
getchar();
}
}

Universidad Tecnolgica de Pereira 2004

43

Continuacin Ejemplo 6.2


int menu()
{
int opcion;
clrscr();
printf("
MENU PRINCIPAL\n");
printf("1. Adicionar un producto\n");
printf("2. Listar productos\n");
printf("3. Buscar producto\n");
printf("4. Salir\n");
printf("Entre una opcion: ");
scanf("%d",&opcion);
return(opcion);
}
void main()
{
int o;
do
{
o=menu();
switch(o)
{
case 1: adicionar();
break;
case 2: listar();
break;
case 3: buscar();
}
}
while(o!=4);
}

6.5 Archivos de Texto o de Caracteres


En este tipo de archivos los datos son almacenados en y ledos desde el archivo caracter por
caracter. El procedimiento para manipular este tipo de archivos es el mismo que se sigui
para los otros tipos de archivos vistos. Sin embargo, las funciones utilizadas varan por lo
cual se describirn las principales a continuacin.
6.5.1 Funcin fputc( )
int fputc(int caracter, FILE *Archivo)

Por medio de esta funcin se puede escribir un caracter en un archivo. Recibe dos
parmetros, el primero de ellos es el caracter que se desea almacenar y el segundo es el
puntero al archivo. Cuando la operacin de escribir es exitosa retorna el caracter, de lo
contrario retorna EOF.

Universidad Tecnolgica de Pereira 2004

44

6.5.2 Funcin fgetc( )


int fgetc(FILE *Archivo)

Esta funcin permite leer un caracter desde un archivo. Como nico parmetro recibe el
puntero de archivo y devuelve carcter ledo. Cuando se llega al final del archivo retorna
EOF.
Ejemplo 6.3:
Realizar un programa que permita guardar en un archivo de caracteres un vector de cadenas
de caracteres (matriz de caracteres).
#include<conio.h>
#include<stdio.h>
void main()
{
FILE *archivo;
char car;
char vector[][20]={"pedro","juan","andrea","jhon"};
archivo=fopen("c:\\t\\texto.txt","w");
if(archivo!=NULL)
{
for(int i=0;i<4;i++)
{
for(int j=0;vector[i][j];j++)
fputc(vector[i][j],archivo);
fputc(' ',archivo);
}
}
fclose(archivo);
printf("Cadenas guardadas exitosamente\n\n");
printf("Este es el contenido del archivo: \n");
archivo=fopen("c:\\t\\texto.txt","r");
if(archivo!=NULL)
{
while((car=fgetc(archivo))!=EOF)
{
putchar(car);
if(car==' ')
printf("\n");
}
}
fclose(archivo);
printf("presione ENTER para terminar...");
getchar();
}

Ejercicio Sugerido:
Escribir un programa en lenguaje C para contar las palabras de un archivo de texto el cual
puede tener varias lneas de diferentes longitudes.
Universidad Tecnolgica de Pereira 2004

45

7. MANEJO DEL PUERTO PARALELO CON LENGUAJE C


El objetivo de esta seccin es explicar como utilizar el puerto paralelo del computador
desde un punto de vista prctico. Para esto se implementarn algunas prcticas que se
podrn realizar por medio de un cable conectado al puerto paralelo, un protoboard, algunos
resistores, LEDs de colores y un motor paso a paso.
7.1 Breve historia del puerto paralelo
Cuando IBM present el PC en 1981, el puerto paralelo de la impresora fue introducido
como una alternativa al puerto serial como un medio para controlar el alto desempeo de
las ltimas impresoras de punto. El puerto paralelo tena la capacidad de transferir 8 bits de
datos al mismo tiempo mientras que el puerto serial transmita uno al tiempo. A medida que
la tecnologa progres y se increment la necesidad de una mayor conectividad externa, el
puerto paralelo se convirti en el medio por el cual se poda conectar a perifricos de mayor
desempeo. Estos perifricos ahora varan desde unidades de disco porttiles, adaptadores
de red, reproductores de CD, etc.
7.2 Tipos de puerto paralelo
A medida que el diseo del PC evolucion, varios fabricantes introdujeron versiones
mejoradas del puerto paralelo. Los nuevos tipos de puerto son compatibles con el diseo
original pero tiene nuevas caractersticas especialmente mayor velocidad. Estos se explican
a continuacin.
7.2.1 Puerto paralelo estndar (Standard Parallel Port - SPP)
El puerto paralelo en el computador IBM PC original es llamado comnmente puerto
paralelo estndar a pesar de que el puerto original no tena un estndar mas all de los
diagramas y documentacin del IBM PC. El puerto paralelo estndar puede transferir ocho
bits al tiempo. Sin embargo no tiene un puerto de entrada de 8 bits lo cual obliga a utilizarlo
en el modo Nibble, es decir 4 bits a la vez. A pesar de ser lento, el modo Nibble se ha
vuelto una forma popular de utilizar el puerto paralelo como entrada.
7.2.2 Puerto Paralelo PS/2 (Bidireccional Simple)
Una de las primeras mejoras al puerto paralelo fue el puerto bidireccional de datos PS/2. El
puerto bidireccional permite a los perifricos transferir 8 bits al PC al mismo tiempo. El
trmino PS/2 se adopt para referirse a cualquier puerto paralelo que tuviera un puerto
bidireccional pero que no soportara los modos EPP o ECP que se describen a continuacin.
El modo Byte es un protocolo de transferencia de datos a 8 bits que pueden utilizar los
puertos tipo PS/2 para transferir datos de un perifrico al computador.

Universidad Tecnolgica de Pereira 2004

46

7.2.3 Puerto paralelo mejorado (Enhanced Parallel Port - EPP)


El puerto paralelo mejorado (EPP) fue desarrollado inicialmente por el fabricante de chips
Intel, el fabricante de PCs Zenith y Xircom quienes fabrican productos de red para el puerto
paralelo. Como en el puerto tipo PS/2, las lneas de datos son bidireccionales. Un EPP
puede leer o escribir un byte de datos en un ciclo del bus de datos de expansin ISA, es
decir cerca de 1 microsegundo incluyendo handshaking, comparado con los cuatro ciclos
para un puerto SPP o de tipo PS/2. Un puerto paralelo tipo EPP puede cambiar de direccin
rpidamente lo cual resulta muy til cuando se utiliza con unidades de disco u otros
dispositivos que transfieren datos en ambas direcciones. Un puerto EPP puede adems
emular a un SPP y algunas veces a un puerto tipo PS/2.
7.2.4 Puerto paralelo de capacidad extendida (Extended Capabilities Port - ECP)
El puerto paralelo ECP fue primero desarrollado por Hewlett Packard y Microsoft. De igual
forma que el puerto EPP, el puerto ECP es bidireccional y puede transferir datos a la
velocidad del bus ISA. Los puertos ECP tienen buffers y soportan transferencias DMA
(Direct Memory Access) y compresin de datos. Los puertos ECP son tiles para
impresoras, scanners y otro tipo de perifricos que transfieren bloques de datos grandes. Un
puerto ECP puede adems emular a un puerto SPP o de tipo PS/2 lo mismo que a puertos
EPP.
7.2.5 Puertos multi-modo
Muchos puertos ms recientes son multi-modo los cuales pueden emular algunos o todos
los tipos de puertos antes mencionados. Estos a menudo incluyen opciones de
configuracin que puede hacer disponibles todos los tipos de puertos o permitir ciertos
modos mientras se bloquean otros.
7.3 Que es un puerto?
En el mundo de los computadores un puerto es un conjunto de lneas que el
microprocesador (o CPU) utiliza para intercambiar datos con otros componentes. Los usos
tpicos de los puertos son las comunicaciones con impresoras, ratones, modems, teclados o
cualquier componente excepto la memoria del sistema. La mayora de puertos son digitales,
es decir que cada bit puede ser 1 o 0. Un puerto paralelo transfiere mltiples bits al tiempo
mientras que un puerto serial transfiere solo uno a la vez (aunque puede transferir en ambos
sentidos).
Lo primero que se debe conocer es la distribucin y la funcin de cada uno de los 25 pines
del puerto paralelo adems de su respectiva posicin de memoria. La siguiente tabla
muestra las direcciones de memoria de los puertos LPT1, LPT2 y LPT3.

Universidad Tecnolgica de Pereira 2004

47

Direccin del puerto en


hexadecimal
LPT1
LPT2
LPT3
3BC
378
278

3BD

379

279

3BE

37A

27A

Bits en
Byte (N)

DB-25
Pin

Entrada
o Salida

0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7*
0*
1*
2
3*
4
5
6
7

2
3
4
5
6
7
8
9
N/A
N/A
N/A
15
13
12
10
11
1
14
16
17
N/A
N/A
N/A
N/A

Salida
Salida
Salida
Salida
Salida
Salida
Salida
Salida
Entrada
Entrada
Entrada
Entrada
Entrada
Salida
Salida
Salida
Salida
-

*Lneas invertidas

Tabla 7.1 Descripcin de los puertos LPT1, LPT2 y LPT3


7.3.1 Descripcin de pines del puerto paralelo

Figura 7.1. Conector DB-25 hembra.


Universidad Tecnolgica de Pereira 2004

48

8 Lneas de salida a las cuales se accede a travs del puerto DATA (DATA Port).
5 Lneas de entrada (una invertida) a las cuales se accede a travs del puerto STATUS
(STATUS Port).
4 Lneas de salida (tres invertidas) a las cuales se accede a travs del puerto CONTROL
(CONTROL Port).
Las restantes 8 lneas van a tierra.

Inicialmente, el puerto paralelo fue concebido como un puerto de salida de datos. Sin
embargo varias modificaciones se han realizado a lo largo de los aos y es posible contar
hoy da con puertos paralelos bidireccionales en la mayora de computadores.
7.3.2 Direcciones del puerto
El puerto paralelo estndar usa tres direcciones contiguas, usualmente en uno de estos tres
rangos
3BCh, 3BDh, 3BEh
378h, 379h, 37Ah -> Rango ms comn
278h, 279h, 27Ah
La primera direccin del rango es la direccin base del puerto tambin conocida como la
direccin del registro DATA. La segunda direccin del rango corresponde al registro
STATUS y la tercera al registro CONTROL.
Los puertos EPP y ECP reservan direcciones adicionales para cada puerto. Un puerto EPP
adiciona cinco registros desde direccin base + 3 hasta direccin base + 7 y un puerto ECP
adiciona tres registros desde direccin base + 400h hasta direccin base + 402h. Por
ejemplo, para una direccin base igual a 378h, los registros del puerto EPP estn desde
37Bh hasta 37Fh.
En los primeros PC el puerto paralelo tena la direccin base en 3BCh. Sin embargo en
nuevos sistemas el puerto paralelo se encuentra en la direccin 378h.
A menudo Windows y DOS se refieren al primer puerto en orden numrico como LPT1, al
segundo como LPT2 y al tercero como LPT3. As que al reiniciar el PC, LPT1 corresponde
a 378h, o bien podra ser cualquiera de las tres direcciones. LPT2, si existe, podra estar en
la direccin 378h o 278h y LPT3 solo puede estar en 278h. Varias tcnicas de
configuracin podran cambiar esta asignacin as que no todos los sistemas seguirn esta
convencin. LPT significa Line Printer (impresora de lnea) lo cual refleja el uso inicial que
se le daba a este tipo de puerto.

Universidad Tecnolgica de Pereira 2004

49

7.3.3 Como encontrar puertos existentes


Los sistemas operativos Windows y DOS incluyen utilidades para encontrar los puertos
existentes del PC y para examinar otros recursos del sistema. En Windows 95, se debe
hacer click en Panel de Control, Sistema, Administrador de Dispositivos y por ltimo
Puertos para ver la direccin asignada, as como el nivel de interrupcin (IRQ) y el canal
DMA. En Windows 3.1 o DOS se puede utilizar Microsoft's Diagnostic (msd.exe) para ver
este tipo de informacin.

Figura 7.2. Como encontrar las caractersticas de los puertos.


7.4 Funciones de Turbo C para el manejo de puertos
Estas son las funciones que permiten la entrada y salida de datos por cualquier puerto del
computador (serial, paralelo, etc.). Las ms utilizadas son inportb y outportb y se describen
a continuacin.
7.4.1 Funcin inportb
Esta funcin permite leer un byte desde cualquier puerto. A continuacin se muestra el
prototipo de esta funcin.
unsigned char inportb(int puerto)

Universidad Tecnolgica de Pereira 2004

50

Como se observa del prototipo, esta funcin devuelve el byte ledo como un dato de tipo
carcter sin signo y recibe como nico parmetro la direccin del puerto desde donde se
desea leer.
7.4.2 Funcin outportb
La funcin outportb permite escribir un byte en un puerto dado. El prototipo de esta funcin
es el siguiente.
void outportb(int puerto, unsigned char valor)

Donde puerto corresponde a la direccin del puerto donde se desea escribir el dato
guardado en la variable valor.
Ejemplo 7.1:
Escribir un programa en lenguaje C para generar una secuencia de encendido de los LEDs
conectados al puerto paralelo LPT1 del computador (direccin de memoria = 0x3BC).
#include<dos.h>
#include<stdio.h>
#include<conio.h>
#include<math.h>
#define LPT1 0x378
void main()
{
int i;
clrscr();
printf("Presione cualquier tecla para terminar ...");
i=0;
while(!kbhit())
{
outportb(LPT1,pow(2,i));
delay(500); /* retardo de 500ms */
i++;
if(i==8)
i=0;
}
}

Ejemplo 7.2:
En este ejemplo se controlar un motor paso a paso (MPAP) por medio del puerto paralelo
LPT1 que se conectar a este por medio de un arreglo de transistores Darlington del
circuito integrado ULN2803. Para hacer que el motor gire es necesario aplicar la siguiente
secuencia binaria 1010 1001- 0101-0110 para manejo de dos fases (10-9-5-6 en base 10)
o 1000-0001-0100-0010 (8-1-4-2 en base 10) para manejo por ola.

Universidad Tecnolgica de Pereira 2004

51

#include<dos.h>
#include<conio.h>
#include<stdio.h>
#define LPT1 0x378
void secuencia1(int ms,char sentido)
{
/*Secuencia bajo torque*/
switch(sentido)
{
case 'i':
case 'I':
outportb(LPT1,0x08);
delay(ms);
outportb(LPT1,0x01);
delay(ms);
outportb(LPT1,0x04);
delay(ms);
outportb(LPT1,0x02);
delay(ms);
break;
case 'd':
case 'D':
outportb(LPT1,0x02);
delay(ms);
outportb(LPT1,0x04);
delay(ms);
outportb(LPT1,0x01);
delay(ms);
outportb(LPT1,0x08);
delay(ms);
break;
}

void secuencia2(int ms,char sentido)


{
/*Secuencia alto torque*/
switch(sentido)
{
case 'i':
case 'I':
outportb(LPT1,0x0A);
delay(ms);
outportb(LPT1,0x09);
delay(ms);
outportb(LPT1,0x05);
delay(ms);
outportb(LPT1,0x06);
delay(ms);
break;

Universidad Tecnolgica de Pereira 2004

52

Continuacin Ejemplo 7.2


case 'd':
case 'D':
outportb(LPT1,0x06);
delay(ms);
outportb(LPT1,0x05);
delay(ms);
outportb(LPT1,0x09);
delay(ms);
outportb(LPT1,0x0A);
delay(ms);
break;
}

void main()
{
char sentido;
int vueltas,veces;
float t_paso,tiempo;
clrscr();
printf("Sentido de giro del motor (Izquierda=I Derecha=D)
?:");
sentido=getche();
printf("\nCuantas vueltas desea realizar?: ");
scanf("%d",&vueltas);
veces=100*vueltas/4;
printf("En cuantos segundos debe dar estas vueltas? :");
scanf("%f",&tiempo);
t_paso=1000*tiempo/(vueltas*100);
/*Para un motor con paso = 3.6 grados*/
for(int i=1;i<=veces;i++)
secuencia2(t_paso,sentido);
}

Universidad Tecnolgica de Pereira 2004

53

BIBLIOGRAFIA
[1] BECERRA S., Csar, Lenguaje C El Nuevo Concepto, Editorial Kimpres Ltda., ISBN:
958-96880-4-7.
[2] AXELSON, Jan, Parallel Port Complete: Programming, Interfacing & Using the PC'S
Parallel Printer Port, Independent Publishers Group, ISBN: 0965081915.

Universidad Tecnolgica de Pereira 2004

You might also like