Você está na página 1de 112

PROCESO LTDA.

Tecnologia Que Capacita

Curso de Lenguaje C

Por: Anibal G. Martinez Arcia


Ingeniero de Sistemas (UNAL)
E-Mail: anibal_m@hotmail.com
VARIABLES, CONSTANTES, OPERADORES Y EXPRESIONES

IDENTIFICADORES

Un identificador está constituído de caracteres alfabéticos y


numéricos, además es posible hacer uso del caracter subrayado.
El primer caracter del identificador debe ser obligatoriamente una
letra o un subrayado.

Para el lenguaje C las letras minúsculas son totalmente diferentes de


las mayúsculas.

Son significativos los primeros 32 caracteres (TURBO C - Microsoft C).

Son significativos los primeros 8 caracteres (Latice C Ver. 3.0 y


UNIX C).

Toda palabra reservada se escribe en minúscula.

TIPOS DE DATOS (Microsoft C)

Tipo Significado bits Rango


char caracter 8 - a
128 127
int entero 16 -3276 a 3276
8 7
float flotante 32 -3.4e+48 a 3.4e+48
double doble 64 -1.7e+308 a 1.7e+308
void vacio 0 sin valor

MODIFICADORES DE TIPO

Los modificadores o calificadores de tipo, se aplican a los enteros y


caracter.sin embargo es posible aplicar long al tipo de datos double.

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 1


char 8 -128 a 127
signed char 8 -128 a 127
unsigned char 8 0 a 255
int 16 -32768 a 32767
short 16 -32768 a 32767
unsigned int 16 0 a 65535
long int 32 -2147483648 a 2147483647
unsigned long 32 0 a 4294967295

long equivale a long int


unsigned equivale a unsigned int
unsigned long equivale a unsigned long int

DECLARACION DE VARIABLES

Formato: tipo lista_de_variables;


tipo variable1 [,variable2, ... variable_n];

Ejemplo:
int a, b; float f, g; double d;
char ch; long l, k; signed char ca;

SITIOS DONDE SE DECLARAN VARIABLES

1. Fuera de todas las funciones incluyendo main().


2. Dentro de una función.
3. En los parámetros formales de una función.

EJEMPLOS DE CONSTANTES
char 'a' '\n' '9'
int 12000 -354
long 1236377 -6775774
unsigned 292999 0
float o double 12432.89 -0.89 1.0E100

CONSTANTES HEXADECIMALES Y OCTALES

Las constantes hexadecimales comienzan por: 0x (cero x).


Una constante octal comienza por : 0 (cero).

Ejemplo:
int h; int oc;
h=0xFF /* 255 en decimal */
oc=011 /* 9 en decimal */

CONSTANTES DE CADENA

Las constantes de cadena se entrecomillan con comilla doble (").

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 2


Las constantes de caracter se entrecomillan con comilla simple (').

Ejemplo: "Esto es una cadena"


"a"
'a'

Nota: "a" es diferente de 'a'

La representación de 'a' como caracter y "a" como cadena en la memoria


seria:
caracter cadena
a a\0

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 3


CONSTANTES DE BARRA INVERTIDA

\b Retroceso
\a Alarma
\f Alimentación de página
\n Nueva linea
\r Retorno de carro
\t Tabulador horizontal
\" Doble comilla
\' Comilla simple
\\ Barra invertida
\v Tabulador vertical (Impresora)
\x Constante hexadecimal
\N Constante octal donde N es una
constante octal

Ejemplo: ch = '\n'

INICIALIZACION DE VARIABLES

Formato: tipo variable = constante;

Ejemplo : char ch = 'a';


float f = 123.675;

CONSTANTES SIMBOLICAS

#define nombre_constante valor

Ejemplo:
#define PI 3.1416
#define ERR_1 printf("Error 26\n")

OPERADORES

Operadores aritméticos
+ Suma
- Resta
* Multiplicación
/ División
% Modulo
++ Incremento
-- decremento
() Agrupar

Precedencia
++ -- ()
* / %
+ -

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 4


Operadores relacionales y lógicos:

Operadores de relación :
> >= < <=
== !=

Operadores lógicos :
&& || !

and or not

Presedencia de los operadores relacionales y lógicos


!
> >= < <=
== !=
&&
||
Ejemplo de algunas expresiones:

1 && !0 || 1 /* resulta 1 */
1 && !(0 || 1) /* resulta 0 */
El operador sizeof() : Devuelve el tamaño de un tipo de dato o
de una variable en bytes.

EXPRESIONES

Conversión de tipo
char y short ............. int
float ................. double

Ejemplo:
char ch;
int i;
float f;
double d;

r = (ch / i) + (f * d) - (f + i);
| | | | | |
int double float
| | |
| / /
\ / /
\ / /
double
|
double

CAST : Forza a una expresión a ser de un tipo específico.


Formato:

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 5


(tipo) expresión

Ejemplo:
int x; float r;
x = 35;
r = (float) x / 2; /* resulta 17.5 */
r = (float) (x / 2) /* resulta 17.0 */

OPERADORES Y EXPRESIONES DE ASIGNACION

Formato :
variable op= exp;

op es uno de los siguientes operadores:


+ - * / % << >> & ^ | ~

Ejemplo :
x *= y + 1; a -= 4;

y es equivalente a :

x = x * (y + 1); a = a - 4;

TABLA COMPLETA DE PRESEDENCIA DE OPERADORES

() [] -> . ....... Izq. a derecha


! ~ ++ -- (tipo) * & sizeof ..... " " "
* / % ........ " " "
<< >> ........ " " "
< <= > >= ........ " " "
== != ........ " " "
& ........ " " "
^ ........ " " "
| ........ " " "
&& ........ " " "
|| ........ " " "
?: ........ Derecha a izq.
= += -= etc. ........ " " "
, ........ Izq. a derecha

ENTRADA Y SALIDA DE CONSOLA FORMATEADA

printf() : Escribe datos en diversos formatos, por lo tanto se


denomina también salida formateada.
printf() escribe datos en la consola.

Formato:
printf("cadena_de_ctrl", lista_de_argumentos);

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 6


cadena_de_ctrl : Comienza con un signo de porcentaje (%) y luego le
sigue el código de formato.

lista_de_argumentos : Son variables, constantes o expresiones a


visualizar.

Tabla de ordenes de formato de printf()


-------------------------------------------------------
Codigo Significado
-------------------------------------------------------
%c visualiza un caracter
%d visualiza decimal
%i visualiza decimal
%e visualiza en notación cientifica
%f visualiza datos en punto flotante
%g usa %e ó %f la que sea más corta
%o visualiza octal
%s visualiza cadena de caracteres
%u visualiza decimal sin signo
%x visualiza hexadecimal
%% imprime signo %
%p visualiza un puntero

Ejemplo:
printf("Datos %c %d %s\n", 'a', 100, "caracteres");

/* visuliza : Datos a 100 caracteres */

/*****
*
* suma de valores
*
*****/

main()
{
int a, b;

a = 10; b = 40;

printf("Suma de a + b = %d\n", a+b);


}

ESPECIFICADOR DE ANCHO DE CAMPO

Completa la salida con blancos o ceros para asegurar que es al menos


la longitud mínima.

Si una cadena o número es mayor que el mínimo ancho especificado, esta


se imprimirá completa.

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 7


El relleno por defecto es blanco. Si se desea un relleno con ceros se
debe poner cero antes del especificador de ancho de campo.

Ejemplo:
printf("%05d", 48); /* visualiza :00048 */
printf("%5d", 48); /* visualiza : 48 */

Si se desea especificar posiciones decimales para un valor en punto


flotante, se pone un punto decimal seguido por el número de decimales.

Ejemplo:
printf("%10.2f", 123.1283);
/* visualiza : 123.12 */

Nota : Tenga en cuenta que el valor que aparece antes del punto
especifica el ancho total de campo incluyendo las posiciones decimales
y el punto decimal. Lo anterior se podría leer como campo de tamaño
diez de los cuales siete se tomarán para la parte entera, dos para
decimales y uno para el punto.

Por defecto toda salida formateada se justifica a la derecha; si se


desea un efecto contrario entonces se debe colocar un guión después
del signo porciento.
Ejemplo:
printf("%-5d", 48); /* visualiza :48 */
printf("%-5.2f", 48); /* visualiza :48.00 */

Cuando se usa el punto en una cadena; el valor que le sigue al punto


indica el máximo ancho de la cadena.

Ejemplo:
printf("%5.7s", "José perez");

El cinco indica que la cadena tendrá al menos cinco caracteres y un


máximo de siete.

Si la cadena es más larga que el ancho máximo especificado, los


caracteres adicionales se truncan por la derecha.

Ejercicio:

/*****
*
* formateo de la salida
*
*****/

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 8


main()
{
int i = 100;
float f = 3.5;

printf("i = %4d, f = %2.2f\n", i, f);


}
MODIFICADORES DE FORMATO PARA printf() QUE PERMITEN VISUALIZAR ENTEROS
CORTOS Y LARGOS

l ................... dato long


h ................... dato short

Los anteriores modificadores se pueden aplicar a los códigos de


formato : d, i, o, u y x.

Ejemplo :
printf("%ld", p); /* visuliza un long int */

scanf() : Función de entrada de propósito general que lee la corriente


stdin.

Formato :
scanf("cadena_de_ctrl", lista_de_argumentos);

cadena_de_ctrl : Consta de tres clasificaciones de caracteres:

1. Especificadores de formato
2. Caracteres de espacio en blanco
3. Caracteres de no espacio en blanco

El código de formato le dice a scanf() que tipo de datos se lee a


continuación.

Tabla de códigos de formato de scanf()


---------------------------------------------------
Codigo Significado
---------------------------------------------------
%c lee un caracter
%d lee un decimal entero
%i lee un decimal entero
%e lee un número en punto flotante
%f lee un número en punto flotante
%o lee un número octal
%s lee una cadena
%x lee un número hexadecimal
%p lee un puntero

Un caracter de espacio en blanco en la cadena de control provoca que


scanf() salte sobre uno o más caracteres de espacio en blanco tabulado

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 9


o return en la corriente de entrada.

Ejemplo:
scanf("%d %f %s", &i, &f, &str);
/* la entrada podria ser: 20 3.5 maria */

Un caracter de no espacio en blanco provoca que scanf() lea y descarte


un caracter que no encaje.

Ejemplo:
scanf("%d,%d", &x, &y);
/* la entrada podria ser : 20,50 */

Si no se encuentra el caracter especificado terminará scanf().

Supresión de la asignación con *.

Si en un scanf() se especifica el caracter %*, el campo de entrada no


será tomado en cuenta.

Ejemplo:
scanf("%d%*c%d", &x, &y);
/* la entrada podria ser :20/40 */
/* x = 20 y = 40 */

En las ordenes de formato se puede especificar el modificador máximo


ancho de campo.

Ejemplo :
scanf("20s", str); /* lee máximo 20 caracteres */
Si la entrada tiene más de 20 caracteres, el siguiente scanf() o
cualquier llamada a una posterior entrada comenzará donde quedó la
anterior.

Sea cuidadoso, la entrada para un campo puede terminar antes de


completar la longitud máxima de la misma al encontrar un espacio en
blanco. scanf() se moverá al próximo campo.

Ejemplo:
scanf("%2d %f %*d %2s", &i, &f, &nom);
/* al leer :5674 139 49abc74 quedará:
i = 56 f = 74.00 saltará 139 nom = "49" */

La siguiente llamada a cualquier función de entrada comenzará a partir


de a.

EJERCICIOS DE APLICACION

Desarrolle una serie de ejercicios para poner en práctica todo lo

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 10


estudiado hasta el momento.

Programas ejemplo

/*****
*
* lee un valor y devuelve su cuadrado
*
*****/

main()
{
int a;

printf("Teclea un valor :"); scanf("%d", &a);


printf("Cuadrado de %d es igual a %d\n", a, a*a);
}

/*****
*
* conversion de grados celcius a fahrenheit
* C = (5/9)(f-32)
*
*****/

main()
{
float fahr, celcius;

printf("Gardos fahrenheit :"); scanf("%f", &fahr);


celcius = (5.0 / 9.0) * (fahr -32);
printf("%6.2f grados fahrenheit equivalen a %6.2f celcius\n",
fahr, celcius);
}

ARCHIVOS DE INCLUSION O CABECERA

Los archivos de inclusión contienen definiciones y declaraciones que


pueden ser incorporados en un programa específico que así lo requiera.

Para llamar un archivo de inclusión o cabecera es necesario hacer uso


de la directiva #include la cuál tiene el siguiente formato:

#include nombre_de_archivo_cabecera

Donde nombre_de_archivo_cabecera es el nombre de un archivo que


contiene las declaraciones y definiciones para un propósito
específico. Este archivo se distingue por tener la extención .h.

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 11


El nombre_de_archivo_cabecera se debe encerrar entre comillas (" ") o
signos menor y mayor que (< >).

Ejemplo:
#include "stdio.h"
#include <stdio.h>

Las comillas le dicen a C que busque primero en el directorio de


trabajo actual el archivo de inclusión, si no lo encuentra, busca
entonces en el directorio especificado en la linea de ordenes, y
finalmente si aún no lo ha encontrado, entonces busca en el directorio
standard que se halla definido durante la instalación.

Si el archivo de inclusión se encierra entre signos menor y mayor qué,


el compilador busca primero en el directorio especificado en la linea
de ordenes. si no lo encuentra busca entonces en el directorio
standard. Jamás busca en el directorio de trabajo.

Sí en la inclusión se especifica nombre de ruta o camino, entonces


busca en dicho directorio.

Ejemplo :
#include "c:\cabercera\stdio.h"
#include <c:\include\ctype.h>

Dentro de un archivo cabecera se pueden tener otros #include anidados.

ENTRADA Y SALIDA DE CONSOLA

Para el uso de estas funciones es necesario incluir el archivo


"stdio.h".

Función getchar() : Lee un caracter desde el teclado; espera por


el retorno de carro.
Función getche() : Lee un caracter del teclado; no espera por
retorno de carro.
Función getch() : Leé un caracter del teclado, no hace eco y
no espera por retorno de carro.
Función putchar() : Escribe un caracter en la pantalla.
Función gets() : Lee una cadena desde el teclado.
Función puts() : Escribe una cadena en la pantalla.
Función cprintf() : Escribe caracter formateado.
Funcion kbhit() : Espera por la pulsación de una tecla.
Función fgets() : Lee una cadena de tamaño específico y la
almacena en una variable.
Función fputs() : Función contraria a fgets().

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 12


Ejemplo:
#include "stdio.h"
main()
{
char ch;

printf("Digita un caracter :");ch=getche();


printf("%c\n", toupper(ch));
}

SENTENCIAS DE CONTROL

La sentencia if() / ?:

Formato:
if(<expL>) sentencia;
[else sentencia; ]

Cuando se desea ejecutar un grupo de instrucciones en un if() es


necesario formar un bloque usando llaves.

Ejemplo:
if(<expL>) {
sentencia_1;
sentencia_2;
.
.
sentencia_n;
}
----------------------------
if(<expL>)
sentencia;
else {
sentencia_1;
sentencia_2;
.
.
sentencia_n;
}
-----------------------------
if(<expL>) {
sentencia_1;
.
.
sentencia_n;
}
else {
sentencia_1;
.
.
sentencia_n;

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 13


}

?: Formato:
(<expL>) ? <exp1> : <exp2>
<expL> :Es la condición a ser evaluada.
<exp1> :Se ejecuta si <expL> es verdadera.
<exp2> :Se ejecuta si <expL> es falsa.

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 14


Ejemplo:
z = (a > b) ? a : b;
m = (mes > 6) ? 8 : 2;

#include "stdio.h"
main() /* convierte letra a tipo contrario */
{
char ch;

puts("Digita un caracter :");ch=getche();


printf("%c\n",(islower(ch) ? toupper(ch) :tolower(ch));
}

if() else if()

if(<expL>)
sentencia;
else if(<expL>)
sentencia;
else if(<expL>)
sentencia;
.
.
.
else
sentencia;

LA EXPRESION CONDICIONAL

Cuando el resultado de una condición es verdadero su valor es uno y


cuándo éste es falso su valor es cero. De esta manera una expresión
condicional podría tener el siguiente aspecto:

if(co)
sentencia;
else
sentencia;

co será evaluado como verdadero si su valor es diferente de cero, de


lo contrario será falso.

Ejemplo:

main()
{
int i
printf("Numero entero :"); scanf("%d", &i);
if(i)
printf("%d\n", i/2);
else
printf("No puedo dividir por cero\n");

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 15


}

LA SENTENCIA switch()

Seleciona entre varias alternativas dependiendo del valor de una


variable.
Formato:
switch(<var>) {
case constante_1:
secuencia_de_sentencias
break;

case constante_2:
secuencia_de_sentencias
break;
.
.
.
default :
secuencia_de_sentencias
}

Ejemplo:

SENTENCIAS switch() ANIDADAS

Se pueden anidar sentencias switch() con el fin de implementar rutinas


donde las opciones tienen subdivisiones.

BUCLES

EL BUCLE for()

Formato:
for(inicialización; <expL>; variación) sentencia;

inicialización : Es normalmente una asignación para dar un valor


inicial a la variable controladora de ciclo.

<expL> : La expresión lógica determina hasta cuando ha de repetir el


bucle.

variación : Forma o manera en que debe cambiar la variable del ciclo.

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 16


Ejemplo: #define MAXN 10
main()
{
int i;

for(i=0; i<MAXN; i++) printf("%d ",i);


}

main()
{
int i;

for (i = 10; i > 0; i--) printf("%d ",i);


}

main()
{
int x;

for(x=0; x<10; x +=2) printf("%d ", x);


}

main()
{
int x, y;

for(x=0, y=0; x<10; x++, y++)


printf("x=%d, y=%d\n", x, y);
}

#include <stdio.h>
main()
{
char ch;

for(;;) {
printf(Digita un caracter :"); ch=getche();
if(ch=='$') break; /* rompe el ciclo */
}
}

main()
{
int x;

for(x=0; x != 100;) {
printf("Introduce un número 100 para salir");
scanf("%d",&x);

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 17


}
}

#include <stdio.h>
#include <ctype.h>
main()
{
int i, j, resp;
char done = ' ';

for(i=1; i<=100 && done != 'N'; i++) {


for(j=1; j<=10; j++) {
printf("Cuánto es %d + %d ?",i, j);
scanf("%d",&resp);
if(resp != i+j)
printf("\nErrado\n");
else
printf("\nOk\n");
}
printf("Sigue (S/N)? ");
done = toupper(getche());
}
}

BUCLES for() SIN CUERPO

Un bucle sin cuerpo consiste en colocar en el sitio donde vá la


sentencia un punto y coma.

Ejemplo:
for(t=0; t<NMAX; ++t)
;

EL BUCLE while()

Desarrolla un ciclo mientras una condición sea verdadera.

Formato: while (<expL>) sentencia;

Ejemplo:
#define FIN '*'
#include <stdio.h>

main()
{
char ch = '\0';
while(ch != FIN) ch=getche();
}

#include "stdio.h"

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 18


main()
{
int c;

while((c=getchar()) != EOF)
putchar(c);
}
#include "stdio.h"

main()
{
int c, nc=1;

printf("%4d :", nc);


while((c=getchar()) != EOF) {
if(c == '\n') {
++nc;
putchar(c);
printf("%4d :",nc);

} else
putchar(c);
}
}

EL BUCLE do/while()

Ejecuta un grupo de instrucciones al menos una vez miéntras se cumpla


una condición debido a que el chequeo de la condición se lleva a cabo
al final del bloque de instrucciones.

Formato :
do {
sentencia;
.
.
.
} while(<expL>);

Ejemplo:
#include <stdio.h>

main()
{
char opc;

printf("Desea seguir (S/N) ? ");

do {
opc=toupper(getche());

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 19


} while(opc != 'S' && opc != 'N');
}

LA SENTENCIA continue

continue : obliga a ejecutar la siguiente iteración y salta


cualquier código entre medias.

Ejemplo:
main() /* imprime nros. pares */
{
int x;

for(x=1; x<100; x++)


if(x%2)
continue;
printf("%d\n", x);
}

ETIQUETAS y goto

Una etiqueta es un nombre de identificador válido para C que termina


en dos puntos (:).

Una etiqueta debe estar en la misma función donde está el goto que la
utiliza.

Ejemplo:

loop:
x++;
if (x<100) goto loop;

goto puede ser apropiado cuando se desea salir de varios niveles de


anidación.

ARRAYS Y CADENAS

Arrays unidimensionales:

Formato: tipo nombre_array[<expN>] [,nombre_array[<expN>],...];

Los índices de los arrays deben arrancar desde cero (0) yá que el
primer elemento comienza en esa posición.

Ejemplo: #define N 10
main()
{
int i, tem, j=N-1, a[N];

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 20


for(i=0; i<N; ++i)
a[i]= i;

for(i=0; i< N/2; i++, j--) {


tem = a[i];
a[i] = a[j];
a[j] = tem;
}
for(i=0; i<N; i++)
printf("%d ",a[i]);
}
Nota: El lenguaje C no hará comprobaciones de contornos en los arrays
por lo tanto es reponsabilidad del programador el manejo
adecuado de los arreglos evitando el desbordamiento de los
mismos escribiendo o leyendo fuera de los limites.

CADENAS O STRING

Una cadena es un arreglo de tipo caracter.

Ejemplo:
char nombre[30];
/* declara la variable nombre de 30 caracteres */

Toda cadena de caracteres termina en un nulo '\0'.

Ejemplo:
#define TM 5
#include "stdio.h"

main()
{
char s[TM];
puts("Escribe hola");
gets(s);
printf("%s\n", s);
}

La cadena s quedará así en memoria:

/* convierte una cadena en mayúscula */


#include <stdio.h>
#include <ctype.h>

main()
{
char string[80];

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 21


int i;

printf("Introduce una frase en minúscula :");


gets(string);

for(i=0; string[i]; i++)


cprintf("%c", toupper(string[i]));
}

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 22


#include "stdio.h"

main()
{
char s[80];
int i;

printf("Escribe una frase :"); gets(s);

for(i=0; s[i]; i++)


printf("%c", (s[i] == ' ') ? '\n' : s[i]);
}

FUNCIONES DE CADENA DE LA BIBLIOTECA

Estas funciones se hallan definidas en el archivo "string.h".

strcpy() :Copia el contenido de la cadena origen en la cadena destino.

Formato : strcpy(destino, origen);

Ejemplo:
#include "string.h"
main()
{
char a[80];

strcpy(a, "hola mundo");


printf("%s\n", a);
}

strcat() :Concatena dos cadenas.

Formato : strcat(cadena1, cadena2);

Concatena la cadena2 al final de la cadena1.

Ejemplo:
#include <string.h>
#include <stdio.h>

main()
{
char a1[80], a2[40];

strcpy(a1,"cartagena");
strcpy(a2," colombia");
strcat(a1, a2);

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 23


puts(a1);
}
strcmp() :Compara dos cadenas y devuelve cero si son iguales.

Formato : strcmp(cadena1, cadena2);

Si cadena1 es mayor que cadena2 devuelve un valor mayor que cero.


Si cadena1 es menor que cadena2 devuelve un valor negativo.

Ejemplo:
#include <string.h>
#include <stdio.h>

main()
{
char s[80];

puts("Password :"); gets(s);


if((strcmp(s, "pass")) == 0)
puts("Ok...");
else {
puts("Password equivocado");
exit(0);
}
}

strlen() :Devuelve la longitud de una cadena.

Formato : strlen(cadena);

Ejemplo :
#include <string.h>
#include <stdio.h>
main()
{
int s[80];

strcpy(s, "Hello...");
printf("%d\n", strlen(s));
getche();
}

strchr()
strstr() :Ver su funcionalidad luego de haber tratado el tema de
punteros.

FUNCIONES DE CARACTER

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 24


Las funciones de caracter hacen uso de el archivo cabecera "ctype.h".

isalnum() Devuelve diferente de cero (0) si el caracter es una


letra o un dígito.

Formato :isalnum(ch);
Ejemplo :
#include <stdio.h>
#include <ctype.h>

main()
{
char ch;

for(;;) {
ch=getche();
if(ch==' ')
break;
if(isalnum(ch)) printf("%c\n",ch);
}
}

iscntrl() :Devuelve diferente de cero (0) si el caracter es un


caracter de control. Los caracteres de control estan
comprendidos entre 0 ... 0x1F y 0x7F (DEL).

Formato : iscntrl(ch);

Ejemplo : #include <ctype.h>


#include <stdio.h>

main()
{
char ch;

for(;;) {
ch=getche();
if(ch==' ')
break;
if(iscntrl(ch)) printf("%c\n");
}
}

isdigit() :Devuelve diferente de cero (0) si el caracter es un


dígito.

Formato : isdigit(ch);

Ejemplo :
#include <ctype.h>

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 25


#include <stdio.h>

main()
{
char ch;

for(;;) {
ch=getche();
if(ch==' ')
break;
if(isdigit(ch))
printf("%c\n", ch);
}
}

isgraph() :Devuelve diferente de cero si el caracter es imprimible y


distinto de espacio.

Formato : isgraph(ch);

islower() :Devuelve diferente de cero si se trata de un caracter


minúscula.

Formato : islower(ch);

isupper() :Devuelve diferente de cero si el caracter es mayúscula.

Formato : isupper(ch);

isprint() : Devuelve diferente de cero si el caracter es imprimible


incluyendo el espacio.

Formato : isprint(ch);

ispunct() :Devuelve diferente de cero si el caracter es un caracter de


puntuación. Nos referimos a un caracter de puntuación como todos
aquellos diferentes de los alfabéticos y numéricos.

Formato : ispunt(ch);

isspace() :Devuelve diferente de cero si el caracter es un espacio.

Formato : isspace(ch);

Ejemplo :
#include <ctype.h>
#include <stdio.h>
#define NMAX 80

main()
{

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 26


char s[NMAX];
int i;

printf("Introduce una frase :"); gets(s);


for(i=0; s[i]; ++i)
printf("%c", (isspace(s[i]) ? '\n' : s[i]);
}

isxdigit() :Devuelve diferente de cero si el caracter es un


dígito hexadecimal. Un dígito hexadecimal es:
0 ... 9 A ... F, a ... f.

Formato : isxdigit(ch);

ARRAYS BIDIMENSIONALES

Formato : tipo nombre_array[nro_filas][nro_col];

Ejemplo : int a[2][4];

Define un arreglo con la siguiente estructura:

0 1 2 3

Haciendo uso de la siguiente fórmula podemos averiguar el número de


bytes de memoria usados por un array:

bytes = filas * columnas * sizeof(tipo_de_datos)

Ejemplo : 2 * 10 * 2 = 40 bytes

Ejemplo :
#define NMAX 4

main()
{
int a[NMAX][NMAX], i, x;

for(i=0; i<NMAX; i++)


for(x=0; x<NMAX; x++)
a[i][x] = i * x;
for(i=0; i<NMAX; ++i)
printf("%d ", a[i][i]);
}

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 27


ARRAYS DE CADENAS

Ejemplo : char lineas[30][80];

Define un array de 30 cadenas cada una con un máximo de 80 caracteres.

Para acceder a una cadena individualmente, se especifica el indice de


la fila.

Ejemplo : gets(lineas[0]);

ARRAYS DE MULTIPLES DIMENSIONES

Formato : tipo nombre_array[<expN1>][<expN2>][expN3>]...[expNn>];

Ejemplo : int a[2][3][3];

INICIALIZACION DE ARRAYS

En lenguaje C se pueden inicializar arrays globales.


Para inicializar un array local, es necesario declararlo como static.

Formato :

especificador de tipo nombre_de_array[<expN1>]...[<expNn>] = {


lista_de_valores};

lista_de_valores :Es una lista de constantes que son del tipo


compatible con el tipo base del array separada por comas.

Ejemplo : int i[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

Los arrays de cadenas permiten ser inicializados según el siguiente


formato:

char nombre_de_array[<expN>] = "cadena";


Ejemplo : char str[6] = "hola";

char str1[6] = {'h','o','l','a','\0'};

Ejemplo : int pad[10][2] = {


1, 1,
2, 4,
3, 5,
6, 4,
8, 9,
1, 0,
4, 6,
7, 6,

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 28


8, 5,
0, 3
};

INICIALIZACION DE ARRAYS SIN TAMAÑO

Ejemplos :

char e1[] = "Error de lectura";


char e2[] = "Archivo no hallado";
char e3[] = "Datos no disponibles";

Se puede verificar el tamaño en bytes de cualquiera de las anteriores


cadenas así:

printf("%s tiene %d caracteres\n", e1, sizeof(e1));

Para arrays multidimensionales se deben especificar todas las


dimensiones excepto la de más a la izquierda.

Ejemplo : int datos[][2] = {


1, 3,
5, 6,
7, 4,
9, 1,
0, 8,
4, 0,
5, 8
};

MODOS DE ALMACENAMIENTO (ESPECIFICADORES DE ALMACENAMIENTO)

Formato: especificador tipo_name

Variables Automáticas: Toda variable declarada dentro de una (auto)


función por defecto es automática.
Si se desea dejar clara la intención se emplea la palabra auto al
frente de la declaración de variable. Toda variable local es
automática. Cuándo no se especifíca ninguna clase de almacenamiento,
se supone que la variable es automática.

Ejemplo:
main()
{
auto int a, b;
auto char ch;
auto float f= 4.5;
}

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 29


Variables Estáticas : Son variables locales a la función o bloque
donde fueron declaradas . La diferencia radica en que sus valores
persisten entre llamadas, de tal manera que encontraremos en ellas
cada vez que entremos al bloque o función, el último valor almacenado,
la última vez que se llamó la función.
Las variables estáticas que no se inicializan, contienen un valor 0 la
primera vez, o nulo si es tipo char.
Normalmente las variables que contienen valores fijos para una
determinada función, se declaran y se inicializan static.

Ejemplo
main()
{
cuenta();
cuenta();
cuenta();
}

cuenta()
{
static int x=0;
printf("%d\n",x);
x++;
}

Variables Externas: Las variables que se declaran fuera de una


(extern) función son consideradas externas, pero además se pueden
declarar variables externas dentro de una función que la emplea
utilizando la palabra extern. Cuando una variable es declarada en
archivos diferentes también se puede declarar extern para indicar que
yá esa variable fue declarada en el primer archivo. Las variables
extern son el medio para establecer comunicación entre módulos
compilados separadamente.

Ejemplo:
int a=4;
main()
{
printf("%d\n",a);
func();
}
func()
{
printf("%d\n",a);
}

extern int x;
main()

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 30


{
extern int x;
.
}

Ejemplo:

int i; /* variables externas */


char ch;
main()
{
extern int i; /* fue declarada extern */
auto char ch; /*no es ch extern */

Ejemplo:
int i;
main()
{
int i;
.
.
.
}

otra()
{
auto int i;
}

Variables registro: Son variables que se almacenan en registros de


C.P.U por lo tanto serán rápidas a diferencia de variables
almacenadas en memoria.

No debemos declarar demasiadas variables registro para evitar que el


compilador nos coloque las que no puedan almacenarse en C.P.U en
memoria como cualquier otra variable.
Nunca debe tomar la dirección de una variable register recuerde que
residen en registros de la C.P.U y no en RAM. Las variables register
son siempre enteras.

Ejemplo:
main()
{
register int a,b;
.
.
.
}

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 31


Ejemplo:

main()
{
register int i_rápida;
.
.
.
}

MODIFICADORES DE ACCESO

Formato: modificador tipo var_name;

CONST : Son variables que no pueden ser cambiadas por el programa


durante la ejecución.
Es posible darles un valor inicial.

Ejemplo:

Const float f=48.5

FUNCIONES

Una función se puede definir como un subprograma la cuál nos permite


descomponer un programa en sus mínimos componentes.

Para definir una función se debe hacer uso de un identificador de tipo


válido con el cuál daremos nombre a la función, luego se deben colocar
dentro de parentesis los argumentos si es que existen. Cuando los
argumentos no existen los parentesis deben quedar vacíos. Debemos
recordar que los argumentos deben definirse del tipo de datos válidos
que se ha pasado a la función.

Formato de una función:


tipo_de_función nombre_función(lista_de_argumentos);
declaración de argumentos_o_parámetros;
{
cuerpo_de_la_función
}

Por defecto toda función devuelve un valor entero a menos que se


especifique otra cosa.

SALIENDO DE UNA FUNCION

Existen dos formas de salir de una función:


1. Al encontrar la última llave que cierra la función.
2. Haciendo uso de la sentencia return.

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 32


Cuando una función encuentra la última llave de la misma o cuando
encuentra una sentencia return automáticamente termina la ejecución.

LA SENTENCIA return

return puede terminar una función sin retornar ningún valor. En caso
de que la función devuelva algún valor, la expresión o el valor debe
ser colocado al frente de return.

LLAMANDO A UNA FUNCION

Para llamar a una función se escribe en sitio adecuado el nombre de la


función seguido de parentesis abierto y cerrado. Si se pasan
parámetros, estos deben colocarse dentro de los parentesis separados
por coma.

Ejemplo:
main()
{
int a = 10, b = 20;

printf("suma de a + b = %d\n", suma(a, b));


}

suma(x, y)
int x, y;
{
return(x + y);
}

Ejemplo :

main()
{
int a = 10, b = 20;

printf("%d\n", max(a, b));


}

max(x, y)
int x, y;
{
return((x > y) ? x : y);
}

Ejemplo:

main()
{

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 33


int x=10;

imprime_cadena(x);
}

imprime_cadena(n);
int n;
{
int i;

for(i=0; i<n; ++i)


printf("%c", 45);
}

PARAMETROS POR VALOR

Se le conoce como paso de parámetros por valor al hecho de enviar


valores a una función, estos valores serán recibidos en variables
temporales de tal manera que si se llevan a cabo modificaciones, los
cambios no se reflejaran en las variables originales.

Ejemplo:

main()
{
printf("%d\n", power(4, 2));
}

power(n, x)
int n, x;
{
int p;

for(p=1; x>0; x--)


p *= n;
return(p);
}

/* funcion xtolower() */

xtolower(s)
char ch;
{
if(s > 65 && s < 91)
s += 32;
return(s);
}

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 34


AMBITO DE LAS VARIABLES

Una variable puede ser conocida solo dentro de una función especifíca
lo cuál no debe crear conflictos con otras variables que tienen el
mismo nombre dentro de otras funciones.

FUNCIONES Y ARRAYS

Es posible pasar elementos individuales o un array completo a una


función lo cuál se ilustrará a continuación:

/*****
*
* ejemplo de una clasificacion de array por metodo de shell
* y busqueda binaria.
*
*****/
#define SALIDA 0
#define MAXNUM 10

int lista[MAXNUM] = {1, 5, 4, 2, 8, 3, 9, 10, 7, 6};

main() /* main program */


{
int x, a, index;

/* mostrar valores del array en desoreden */


puts("lista desordenada ...");
for(x = 0; x < MAXNUM; x++)
printf("%d ", lista[x]);
cprintf("%c", '\n');

shell(lista, MAXNUM); /* clasificar lista */

/* mostrar valores del array ya ordenados */


puts("lista ordenada ...");
for(x = 0; x < MAXNUM; x++)
printf("%d ", lista[x]);
cprintf("%c", '\n');

/* buscar un valor dado en el array lista hasta SALIDA */


puts("\nvalor a buscar");
scanf("%d", &a);
while(a != SALIDA) {
index = binary(a, lista, MAXNUM);
printf("\n%d\n", (index != -1) ? lista[index] : index);
scanf("%d", &a);
}

} /* end of main() */

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 35


/*****
*
* udf shell(v, n)
* clasifica un array de enteros por metodo de shell
*
*****/

shell(v, n)
int v[], n;
{
int gap, i, j, tem;

for(gap = n/2; gap > 0; gap /= 2)


for(i = gap; i < n; ++i)
for(j = i-gap; j>=0 && v[j]>v[j + gap]; j -= gap) {
tem = v[j];
v[j] = v[j + gap];
v[j + gap] = tem;
}
} /* end of function shell */

/*****
*
* udf binary(x, v, n)
* busqueda binaria
* busca a x en v[0]...v[n-1]
*
*****/

binary(x, v, n)
int x, v[], n;
{
int low, high, mid;

low = 0;
high = n - 1;
while(low <= high) {
mid = (low + high) / 2;
if(x < v[mid])
high = mid - 1;
else if(x > v[mid])
low = mid + 1;
else
return(mid); /* lo encontro */
}
return(-1); /* x no fue hallado */

} /* end of function binary() */

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 36


val(s)
char s[];
{
int i, n;

n = 0;
for(i = 0; s[i] >= '0' && s[i] <= '9'; ++i)
n = 10 * n + s[i] - '0';
return(n);
}

FUNCIONES QUE DEVUELVEN VALORES NO ENTEROS

Para crear funciones que devuelven valores no enteros, se deben tener


en cuenta los dos siguientes pasos:
1. Se debe especificar el tipo de función.
2. Se identifica el tipo de función antes del primer llamado.

Formato:
tipo nombre_de_función();

Ejemplo:

float suma(); /* identificamos la función */


main()
{
float a, b;
a=35.8; b=56.5;
printf("%f", suma(a, b));
}

float suma(x, y)
float x, y;
{
return(x + y);
}

FUNCIONES DE TIPO void

Una función se declara de tipo void para evitar que la misma devuelva
algún valor.

Ejemplo:
void imprime_col(s)
char s[];
{
int i;
for(i=0; s[i]; ++i)

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 37


printf("%c\n", s[i]);
}
PROTOTIPOS DE FUNCION

Se le conoce con el nombre de prototipos de función al hecho de


declarar el número y tipo de parámetros en una función.

Al hacer uso de los prototipos de función, se habilita al lenguaje C


para que haga una comprobación rigurosa.

Nota : No son parte del original UNIX.

PUNTEROS

Son variables que contienen la dirección de memoria de otra variable.

Ejemplo:

Localización de memoria Variable


+-------+
1000 --------------------> | 003 | --+
+-------+ |
1001 --------------------> | | |
+-------+ |
1002 --------------------> | | |
+-------+ |
1003 --------------------> | | <-+
+-------+
1004 --------------------> | |
+-------+
1005 --------------------> | |
+-------+

MEMORIA

Formato:
tipo *nombre_de_variable;

Ejemplo:
int *m;
char *ch;

OPERADORES DE PUNTERO

*, &

El signo (&) indica la dirección de memoria apuntada.


El signo (*) indica el valor contenido en la dirección apuntada.

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 38


IMPORTANCIA DEL TIPO BASE DE UN PUNTERO

Es importante tener en cuenta el tipo base para definir un puntero yá


que de acuerdo a ello en un incremento o decremento determina el
número de posiciones a avanzar o retroceder.

Un puntero sólo permite operaciones de suma y resta.

Ejemplo:
/* sumando a un puntero */
main()
{
int arr1[5], *p1, i;
float arr2[5], *p2;

for(i = 0; i < 5; i++) {


arr1[i] = i;
arr2[i] = i;
}
p1 = arr1;
p2 = arr2;
for(i = 0; i < 5; i++)
printf("valor punteros + %d = %u %u\n", i, p1+i, p2+i);
}

El resultado del anterior programa podria ser:

valor punteros + 0 = 2708 2720


valor punteros + 1 = 2710 2724
valor punteros + 2 = 2712 2728
valor punteros + 3 = 2714 2732
valor punteros + 4 = 2716 2736

esto se debe a que cada puntero int es de dos bytes y cada puntero
float es de cuatro bytes y al sumarle una unidad, simplemente
direcciona la posición de comienzo del próximo elemento de su tipo en
la memoria.

ARITMETICA DE PUNTEROS

Anteriormente se dijo que las únicas operaciones aritméticas que se


pueden llevar a cabo son suma y resta.

Si se ha definido pt como puntero, pt++ ó ++pt hace que pt apunte al


siguiente elemento y pt += i hace que pt apunte al i-esimo elemento.
Si pt apunta al a[0]
*(pt+1) se refiere al contenido de a[1].

*++pt es equivalente a lo anterior.

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 39


a + 2 == &a[2] /* se trata de la misma dirección */
*(a + 2) == a[2] /* se trata del mismo valor */

*(a + 2) /* tercer elemento de a */


*a + 2 /* suma 2 al valor del primer elemento */

OPERACIONES QUE SE PUDEN REALIZAR CON PUNTEROS

1. ASIGNACION. Se puede asignar una dirección de memoria a un


puntero. Comunmente se usa con el nombre de un array o con el
signo &.

2. ACCEDER AL VALOR GUARDADO EN UNA DIRECCION DE MEMORIA. El


operador * devuelve el valor almacenado en una posición de memoria
apuntada.

3. SE PUEDE OBTENER DIRECCION DE UN PUNTERO. Es posible obtener la


dirección de memoria de un puntero. Con el operador & podemos
hallar la dirección de un puntero.

4. INCREMENTAR UN PUNTERO. Yá sabemos que al incrementar un


puntero obtenemos la dirección del próximo elemento de su tipo.

5. DECREMENTO. Al decrementar un puntero retrocedemos o señalamos a


la posición de memoria del anterior elemento de su tipo.

APUNTADORES Y ARGUMENTOS DE FUNCIONES

La única forma de pasar a una función parámetros por referencia, es


haciendo uso de punteros. Si deseamos que una función llamada altere
las variables pasadas a ella, debemos pasar la dirección de memoria de
dicha variable.

Ejemplo:

main() /* demostracion de parámetros por referencia */


{
int a = 10, b = 20;

printf("Valores actuales de a=%d, b=%d\n", a, b);


swap(&a, &b);
printf("Valores de a=%d, b=%d después del llamado a swap\n",a,b);

/*****
*
* funcion swap()
* intercambia valores de variables
*

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 40


*****/
swap(x, y)
int *x, *y;
{
int tem;

tem = *x;
*x = *y;
*y = tem;
}

APUNTADORES Y ARRAYS

Existe una estrecha relación entre arreglos y apuntadores que es


posible acceder a un arreglo mediante un indice o mediante un puntero.
Aunque es más rápido acceder a un arreglo usando punteros, puede ser
más difícil de entender para un programador iniciado.

A continuación mostramos algunas formas de acceder al primer elemento


de un arreglo versión puntero.

int a[10], *pt;

pt = &a[0]; /* copia en pt la dirección de memoria de a[0] */

Otra forma podria ser:

pt = a; /* copia en pt la dirección de memoria de a[0] */

PASANDO ARRAYS A FUNCIONES

Al pasar un array a una función, realmente estamos pasando la


dirección de memoria del primer elemento.

Ejemplo:

#define NMAX 10

main() /* imprime los valores de un array */


{
int a[NMAX], i;

for(i=0; i<NMAX; i++)


a[i]=i;
display(a);
}

display(s)
int s[];
{
int j;

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 41


for(j=0; j<NMAX; j++)
printf("%d ",s[j]);
getche();
}
/****
*
* invierte un array
*
****/

void _areverse();
#include "stdio.h"
#define NMAX 4

main()
{
int a[NMAX], i;

for(i=0; i<NMAX; i++)


a[i] = i;

_areverse(a);

for(i=0; i<NMAX; i++)


printf("%d\n",a[i]);

printf("........%d\n",sizeof(a));
getche();
}

void _areverse(x)
int x[];
{
int j = NMAX / 2, l = NMAX - 1, t, k;

printf("------ %d\n",sizeof(x));
for(k=0; k<j; k++, l--) {
t=x[k];
x[k]=x[l];
x[l]=t;
}
}

int media();

main()
{
int arr[5], x;

for(x = 0; x < 5; x++)

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 42


arr[x] = x;
printf("La media aritmetica es %d\n", media(arr, 5));
}
/*****
*
* media(array, n)
*
*****/

int media(a_vlrs, n)
int *a_vlrs, n;
{
int i;
int suma;

if(n > 0) {
for(i = 0, suma = 0; i < n; ++i)
suma += *(a_vlrs + i);
return((int) (suma / n));
}
else {
printf("Elementos no hallados\n");
return(0);
}
}

Observe que *a_vlrs es un puntero al primer elemento del array y


además pudo haberse declarado como a_vlrs[].

ARREGLOS DE APUNTADORES

Al hacer una declaración como la siguiente :

char *lineas[MAX_LINE];

se obtiene un array de apuntadores, o cuando hacemos declaraciones


como:

char s[]; ó char *s;

INICIALIZACION DE ARREGLOS DE APUNTADORES

A continuación encontramos un ejemplo de arrays de apuntadores y su


inicialización.

Ejemplo :

/* encontrando el nombre del mes a partir de su numero */

char *month_name();

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 43


main()
{
int x = 6;

printf("mes de %s\n", month_name(x));


}

/*****
*
* month_name(n)
* devuelve el nombre del mes
*
*****/

char *month_name(n)
int n;
{
static char *name[] = {
"mes fuera de rango",
"Enero",
"Febrero",
"Marzo",
"Abril",
"Mayo",
"Junio",
"Julio",
"Agosto",
"Septiembre",
"Octubre",
"Noviembre",
"Diciembre"
};
return((n < 1 || n > 12) ? name[0] : name[n]);
}

APUNTADORES A CARACTERES Y FUNCIONES

Una constantes de cadena como :

"Hola mundo..."

es un arreglo de caracteres a la cuál el compilador añade internamente


el caracter terminador nulo (\0). De esta manera es posible que un
programa pueda encontrar el final de la cadena.

Ejemplo :

main() /* demostración de apuntadores a caracteres */


{
char *mensaje = "esto es una prueba";

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 44


while(*mensaje)
printf("%c", *mensaje++);
}
El tamaño de una cadena es uno más que el número de caracteres que
aparecen entre comillas.
Si hacemos uso de una función como la siguiente en un programa:

printf("El poder del lenguaje C\n")l

La función printf recibe un puntero de tipo caracter al primer


elemento de la cadena de caracteres.

También es posible declarar variables como punteros a cadenas como:

char *mensaje;
Luego es posible hacer una asignación de la siguiente forma:

mensaje = "error de e/s";

Recuerde que mensaje no contiene la copia de la cadena, sino que


apunta al primer caracter de la cadena. El lenguaje C no tiene manera
de manipular cadenas como una entidad.

Ejemplos:

main() /* demostración de apuntadores a caracteres */


{
char *mensaje = "esto es una prueba";

printf("%s\n", mensaje);
}

#include "stdio.h"
main() /* ejemplo de strcpy() */
{
char a[20];

strcpy(a, "cadena de prueba");


puts(a);
}

/*****
*
* funcion xstrcpy()
* copia cadena origen en destino
*
*****/

xstrcpy(dest, orig)

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 45


char *dest, *orig;
{
while(*dest++ = *orig++)
;
}

FUNCIONES DE TIPO PUNTERO

Otra de las posibilidades que tenemos al programar en lenguaje C es


hacer uso de funciones que devuelven punteros.

Ejemplo:

/*****
*
* STRING.C
* devuelve n caracteres
*
*****/

char *string();

main()
{
printf("%s", string('*', 5));
}

/*****
*
* string(<expC>, <expN>)
*
*****/

char *string(ch, n)
char ch;
int n;
{
int i;
char x_str[200];

for(i=0; i<n; ++i)


x_str[i]=ch;

x_str[i]='\0';
return(x_str);
}

LOS ARGUMENTOS DE main()

La función main() tiene 3 argumentos de los cuales estudiaremos dos.


Estos argumentos hacen posible que un programa permita argumentos al

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 46


momento de ejecutarlo.

Los dos argumento más importantes de main() son argv y argc que
estudiaremos a continuación.

argv : Es un arreglo de punteros de tipo char donde cada uno señala


al comienzo de cada argumento dado al frente del nombre de un programa
al momento de ejecutarlo.

argc : Es un contador de tipo int que nos dice cuántos argumentos


fueron pasados a main().

Ejemplo:

/* visualiza argumentos */
main(argc, argv)
int argc;
char *argv[];
{
while(--argc > 0)
printf("%s%c", *++argv, (argc > 1) ? ' ' : '\n');
}

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 47


ASIGNACION DINAMICA DE MEMORIA

malloc y free

malloc: Asigna memoria del montículo

Formato:
void *malloc (unsigned int n)

n :tamaño de la memoria a asignar


Devuelve el puntero al primer Byte.
Si no hay suficiente memoria disponible se produce un fallo y
devuelve nulo

Ejemplo:
float *f;
f=(float *) malloc (sizeof(float));
if (!f) {
printf ("error de asignación \n");
exit (1);
}

free: Devuelve o libera la memoria previamente asignada.

Formato:
free (void *p);

Recomendación: Incluye el archivo "stdlib.h".

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 48


Ejemplo:

#include "stdlib.h"

main() /* demostración de asignación dinámica */


{
int *p,t;
p= (int *) malloc (40 * sizeof (int));
if (!p) {
printf ("error de asignación \n");
exit (1);
}

for(t=0; t<40;++t) *(p++)=t ;


for( t=0; t<40; ++t) printf("%d ",*(p+t));
}

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 49


ESTRUCTURAS

Una estructura se puede definir como un conjunto de campos los cuales


conforman una unidad de información.

Cada campo o miembro de la estructura puede ser de diferente tipo.

Formato:

struct [identificador] {
tipo identificador;
.
.
.
}[identificador[,identificador, ...]];

Ejemplo:

struct usr {
int nro_usr;
char nombre[35];
float cuota;
} reg_usr;

Otra posible forma seria:

struct usr {
int nro_usr;
char nombre[35];
float cuota;
};

struct usr reg_usr;

ESTRUCTURAS ANIDADAS

Una estructura puede contener miembros compuestos por otras


estructuras en tal caso se dice que hay una estructura anidada.

Ejemplo:

struct date {
int day;
int month;
int year;
};

struct usr_date {
int nro_usr;
char nombre[35];

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 50


struct date date_in;
struct date date_out;
} reg_usr;
REFERENCIANDO MIEMBROS DE UNA ESTRUCTURA

Para referenciar los miembros de una estructura es necesario hacer uso


de el operador punto (.) ó flecha (->).

Ejemplo:

reg_usr.nro_usr = 453;

printf("%s\n", reg_usr.nombre);

reg_usr.date_in.day = 15;

Los miembros de una estructura pueden ser apuntadores.

Ejemplo:

struct usr {
char *name;
char *keyword;
};

/* Un ejemplo más */
struct data {
int ident;
char *text;
} Xdat;

main()
{
Xdat.ident = 454;
Xdat.text = "cadena";

printf("%d %s\n",Xdat.ident, Xdat.text);

ARRAYS DE ESTRUCTURAS

Es posible crear arreglos de estructuras, a continuación ilustramos


este aspecto.

#define NMAX 100

struct key {
int nro;
char *keyword;
} lst_key[NMAX];

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 51


En el ejemplo anterior se ha declarado un array de 100 estructuras.

INICIALIZACION DE ESTRUCTURAS

/***
* programa de demostracion de inicializacion
* (arrays de estructuras)
*
*/

struct date {
char *cmonth;
int nmonth;
} month[12] = { "Ene", 1,
"Feb", 2,
"Mar", 3,
"Abr", 4,
"May", 5,
"Jun", 6,
"Jul", 7,
"Ago", 8,
"Sep", 9,
"Oct",10,
"Nov",11,
"Dic",12
};

main()
{
int i;

for(i = 0; i <= 11; ++i)


printf("%s %2d\n", month[i].cmonth, month[i].nmonth);

PASO DE ESTRUCTURAS Y MIEMBROS DE ESTRUCTURA A NUNA FUNCION

PASANDO ELEMENTOS INDIVIDUALES A UNA FUNCION

De igual manera que se pasa una varible no estructurada a una función


es posible pasar cada campo simple de una estructura.

Ejemplo:

/***
* demostracion de estructuras
* pasando elementos de una estructura a una funcion

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 52


* pasa parametros por referencia
*/

/* intercambio de valores de los campos de una estructura */

main()
{
static struct {
int a;
int b;
} d = { 4, 8};

printf("a = %d b = %d antes del cambio\n", d.a, d.b);


swap(&d.a, &d.b);
printf("a = %d b = %d despues del cambio\n", d.a, d.b);
}

/***
* udf swap()
* recibe : punteros a cada campo de estructura
* devuelve: datos intercambiados
*/

swap(x, y)
int *x, *y;
{
int t;

t = *x;
*x = *y;
*y = t;
}

PUNTEROS A ESTRUCTURAS

Para pasar una estructura a una función se puede proceder enviando


cada uno de sus elementos individualmente o enviando un apuntador a la
estructura.

Ejemplo:

/***
* demostracion del paso de estructuras a una funcion
*/

#include <stdio.h>

struct {
char *name;
int nro_cta;
float saldo;

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 53


} reg;

main()
{
void ajuste(struct reg *pt); /* prototipo */

static struct reg usr = { "Maria",


3423,
555860.5
};

printf("%10s %4d %9.2f\n", usr.name, usr.nro_cta, usr.saldo);


ajuste(&usr);
printf("%10s %4d %9.2f\n", usr.name, usr.nro_cta, usr.saldo);
}

/***
* udf ajuste()
*/

void ajuste(struct reg *pt)


{
pt->name = "Seferino";
pt->nro_cta = 5000;
pt->saldo = 2000;
}

El operador flecha ( -> ) es comunmente usado cuando se trabaja con


punteros a estructuras ya que es más comodo que la notación
(*varest).miembro.

ESTRUCTURAS AUTOREFERENCIALES

Una estructura es autoreferencial cuando uno de sus miembros es


Este tipo de estructura es utilizado para creación de estructuras de
datos tales como listas.

Ejemplo:

/***
* crea una lista
*/

#include <stdio.h>
#define LOCALIZAR (struct nodo *) malloc(sizeof(struct nodo))

struct nodo {
int info;
struct nodo *sig;
};

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 54


main()
{
struct nodo *cab, *q;
int i = 10;

cab = NULL;
while(i > 0){
q = LOCALIZAR;
q->info = i;
q->sig = cab;
cab = q;
i--;
}
}

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 55


TIPOS DE DATOS DEFINIDOS POR EL USUARIO typedef

typedef es usado para definir nuevos tipos de datos que los


programadores requieren con frecuencia para dar mayor claridad en
cuanto a documentación de un programa.

Ejemplo:

typedef int ENTERO;

y luego declarar:

ENTERO a, i, j;

Ejemplo:

typedef char *CADENA;

y luego declarar:

CADENA ch, lineas[NMAX];

Ejemplo:

typedef struct usr {


int nro;
char name[35];
} REGISTRO;

REGISTRO usr_reg;

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 56


CAMPOS BIT

Los campos bit son un medio adecuado para manipular datos bit a bit en
un byte.

Existen varias razones que hacen de los campos bit una herramienta de
programación de extrema utilidad. Algunas de estas razones son las
siguientes:

Los campos bit nos permiten almacenar en un mismo byte datos de tipo
booleano (Verdadero/Falso) lo cual significa un ahorro de espacio.

Algunos dispositivos transmiten información codificada en bits de un


byte.

Es posible encriptar información manipulando los bits de cada byte


para hacer de esta manera un encriptado más eficiente e impenetrable.

El formato para la definición de campos bit es:

struct [identificador] {
tipo identificador : longitud;
.
.
.
}[identificador [, identificador, ...]];

Ejemplo:

struct bits {
unsigned a: 1;
unsigned b: 1;
unsigned c: 1;
unsigned d: 1;
unsigned e: 1;
unsigned f: 1;
unsigned g: 1;
unsigned h: 1;
} byte;

Usted puede apreciar que los campos bit son declarados como unsigned
debido a que cada bit de la palabra debe ser 1 ó 0 sin tener en cuenta
el signo.

Algunos compiladores ordenan los campos bit de derecha a izquierda


mientras que otros lo hacen en sentido contrario.

Nosotros asumiremos la ordenación de derecha a izquierda.

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 57


En el ejemplo anterior los campos bits pueden ilustrarse así:

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

-------------------- h g f e d c b a
Sin usar

podriamos declarar otra estructura de campos bit como:

struct {
unsigned a : 1;
unsigned b : 1;
unsigned c : 5;
unsigned d : 2;
unsigned e : 3;
unsigned f : 4;
} word;

En este ejemplo estamos haciendo uso de toda la palabra y podriamos


esquematizarla así:

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

---------- ------- ----- ------------ b a


f e d c

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 58


UNIONES

Las uniones se tratan de estructuras donde el mismo area de


almacenamiento es compartido por varios miembros.

Ejemplo :

union word {
char w[2];
int i;
0 Xword;

Esto podria ser esquematizado de la siguiente manera:

Xword
+------------------+
w
-------+--------
w[0] w[1]
+------+------+
i
+-----------------+

A continuación mostramos un ejemplo que cubre uniones y campos bit:

/***
* toma caracteres del teclado y los visualiza en binario (ASCII)
*/

#include <stdio.h>
#include <conio.h>

/* estructura de campos bit (un byte) */


struct byte {
unsigned a : 1;
unsigned b : 1;
unsigned c : 1;
unsigned d : 1;
unsigned e : 1;
unsigned f : 1;
unsigned g : 1;
unsigned h : 1;
};

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 59


/* se comparte la misma area de memoria
como un caracter (ch) o como ocho bits que
pueden manejarse individualmente (bit)
*/

union bits {
char ch;
struct byte bit;
} ascii;

void decodifica(union bits b); /* prototipo */

main()
{
while((ascii.ch = getche()) != 'q') {
printf(": ");
decodifica(ascii);
}
}

/***
* udf decodifica()
* recibe : union del tipo bits
* devuelve : nada
*/

void decodifica(union bits b)


{
printf("%d ", (b.bit.h) ? 1 : 0);
printf("%d ", (b.bit.g) ? 1 : 0);
printf("%d ", (b.bit.f) ? 1 : 0);
printf("%d ", (b.bit.e) ? 1 : 0);
printf("%d ", (b.bit.d) ? 1 : 0);
printf("%d ", (b.bit.c) ? 1 : 0);
printf("%d ", (b.bit.b) ? 1 : 0);
printf("%d ", (b.bit.a) ? 1 : 0);
printf("\n");
}

/***
* demostracion de campos bit
*/

#include <stdio.h>

main()
{
unsigned m, d, a;

static struct {
unsigned a : 2;

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 60


unsigned b : 2;
unsigned c : 3;
unsigned d : 1;
} cbit = { 3, 5, 7, 1};

printf("%d %d %d %d\n", cbit.d, cbit.c, cbit.b, cbit.a);


/* salida : 1 7 1 3 */
}

Analice la salida del anterior programa. Preste atención especial en


el contenido del campo b.

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 61


ENUMERACIONES

La enumeración es un tipo de datos similar a la estructura o la unión.


Sin embargo sus miembros son constantes con valores establecidos.

Formato:

enum [identificador] {
identificador,
.
.
.
} [identificador [,identificador,...]];

Ejemplo:

enum colores {negro,


azul,
cyan,
verde,
magenta,
rojo,
blanco,
amarillo
};

enum colores fondo, primerplano;

Se puede hacer la misma definición de la siguiente forma:

enum {negro,
azul,
cyan,
verde,
magenta,
rojo,
blanco,
amarillo
} fondo, primerplano;

Automaticamente los valores para cada constante de la enumeración


serian:

negro 0
azul 1
cyan 2
verde 3
magenta 4
rojo 5
blanco 6
amarillo 7

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 62


Los valores automaticos que se le asignan a las constantes de la
enumeración pueden ser modificados.
Ejemplo:

enum {negro,
azul = 4,
cyan,
verde,
magenta,
rojo,
blanco,
amarillo
} fondo, primerplano;

Los valores para las constantes de enumeración son ahora:

negro 0
azul 4
cyan 5
verde 6
magenta 7
rojo 8
blanco 9
amarillo 10

Podriamos hacer asignaciónes como las siguientes;

primerplano = blanco;

Es posible condicionar las costantes de enumeración:

if(fondo == azul)
primerplano = blanco;
else
primerplano = azul;

Otra forma valida podria ser:

switch(fondo) {
case negro:
primerplano = blanco;
break;

case azul:
cyan:
verde:
magenta:
rojo:
primerplano = amarillo;

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 63


break;

case blanco:
primerplano = negro;
break;

case amarillo:
primerplano = azul;
break;

default:
puts("Error en selección del color de fondo");
}

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 64


OPERADORES AVANZADOS

OPERADORES DE BITS

En algunas aplicaciones puede ser necesario el manejo de los bits


individuales de una palabra. Frecuentemente se hace uso del lenguaje
Ensamblador para tal proposito. Sin embargo el lenguaje C dispone de
un conjunto de operadores que manipulan eficientemente los bits.

OPERADOR DE COMPLEMENTO A UNO (~)

Este operador se aplica a un solo operando y su función es la de negar


es decir, los bits que estan en uno (1) se convierten en cero (0) y
los bits cero (0) se combierten en uno(1). El operando debe ser un
entero (char, int, long, unsigned, short).

Ejemplo:

OPERADOR LOGICO Y (&) A NIVEL DE BITS

Da como resultado un uno (1) si el bit del primer operando y el


segundo operando es uno (1). En otro caso el resultado sera cero (0).

Ejemplo:

OPERADOR LOGICO O (|) A NIVEL DE BITS

Da como resultado un uno (1) si por lo menos el bit del primero o


segundo operando esta en uno (1).

Ejemplo:

OPERADOR LOGICO O EXCLUSIVO (^) A NIVEL DE BITS

Da como resultado un uno (1) si el bit del primer oprando esta en uno
(1) y el bit del segundo operando esta en cero (0) o lo contrario. En
cualquier otro caso da como resultado cero (0).

Ejemplo:

OPERADOR DE DESPLAZAMIENTO DE BITS A LA DERECHA ( >> )

Desplza o mueve todos los bits a la derecha el número de posiciones


especificado.

Si el oprando es de tipo unsigned se asegura que las posiciones a la


izquierda se llenaran con cero (0).

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 65


Ejemplo:

OPERADOR DE DESPLAZAMIENTO A LA IZQUIERDA ( << )

Desplza o mueve todos los bits a la izquierda el número de posiciones


especificado.

Ejemplo:
ENTRADA Y SALIDA (ARCHIVOS)

/***
* copia cualquier archivo
*/

#include <stdio.h>
#include <stdlib.h>

main(argc, argv)
int argc;
char *argv[];
{
FILE *in, *out;
char ch;

if(argc != 3){
puts("Error en parametros...");
exit(1);
}

if((in=fopen(argv[1],"rb"))==NULL) {
puts("No puedo abrir archivo...");
exit(1);
}

if((out=fopen(argv[2],"wb"))==NULL) {
puts("No puedo abrir archivo...");
exit(1);
}

while(!feof(in))
putc(getc(in), out);

fclose(in); fclose(out);
}

/***
*
* las funciones fgets() y fputs()

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 66


* char *fgets(char *str, FILE *fp);
* char *fputs(char *str, int long, FILE *fp);
*----------------------------------------------------------
* fgets() : lee una cadena desde la corriente especificada
* hasta que encuentra el caracter de nueva linea
* fputs() : escribe una cadena en la corruente especificada
*/

#define TAM 100


#include <stdio.h>
#include <string.h>

main(argc, argv)
int argc;
char *argv[];
{
FILE *fp;
int x;
char Xstring[TAM];

if(argc != 2){
puts("Uso : prog <file>");
exit(1);
}

if((fp=fopen(argv[1], "w"))==NULL){
puts("Error en apertura de datos");
exit(1);
}

printf("-=> "); gets(Xstring);

while(strlen(Xstring) != 0){
fputs(Xstring, fp);
printf("-=> "); gets(Xstring);
}
fclose(fp);
}

/***
*
* las funciones fgets() y fputs()
* char *fgets(char *str, FILE *fp);
* char *fputs(char *str, int long, FILE *fp);
*----------------------------------------------------------
* fgets() : lee una cadena desde la corriente especificada
* hasta que encuentra el caracter de nueva linea
* fputs() : escribe una cadena en la corruente especificada
*/

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 67


#define TAM 100
#include <stdio.h>
#include <string.h>

main(argc, argv)
int argc;
char *argv[];
{
FILE *fp;
int x;
char Xstring[TAM];

if(argc != 2){
puts("Uso : prog <file>");
exit(1);
}

if((fp=fopen(argv[1], "r"))==NULL){
puts("Error en apertura de datos");
exit(1);
}

while((fgets(Xstring, TAM, fp)) != NULL)


printf("%s", Xstring);

fclose(fp);
}

/***
*
* la funcion fseek()
* int fseek(FILE *fp, long num_bytes, int origen);
* establece el localizador de posicion en un byte especifico
* num_byte : numero de bytes desde el origen a alcanzar la nueva
* posicion
*
* origen :
* comienzo del archivo SEEK_SET 0
* posicion actual SEEK_CUR 1
* fin de archivo SEEK_END 2
*/

#include <stdio.h>
#define SIZE 20

main()
{
FILE *fp;

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 68


char ch;

if((fp = fopen("texto", "rb")) == NULL){


puts("Error en apertura de archivo");
exit(1);
}

fseek(fp, SIZE, 0);


ch = getc(fp);
putchar(ch);

fclose(fp);
}

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 69


INTERRUPCIONES

LA ROM-BIOS

Está activa durante todo el tiempo que esté trabajando el computador.


La ROM-BIOS proporciona todos los servicios fundamentales que se
necesitan para que puedan llevarse a cabo todas las operaciones del
computador. Por lo general el BIOS controla los dispositivos
perifericos tales como la pantalla, el teclado y controladores de
disco. Dentro del BIOS se encuentran los programas encargados de
realizar el control de dispositivos.

Los programas residentes en BIOS transforman un simple comando de


un programa en toda la secuencia de pasos necesarios para que se
desarrolle en forma efectiva dicha acción. ROM-BIOS guarda ademas
la hora y el dia.

VECTORES DE INTERRUPCION

Los computadores IBM PC como todos los basados en la familia de


microprocesadores 8086 de INTEL se controlan a traves del uso de
interrupciones, que se pueden generar o bien por hardware o bien por
software. Cada vez que se necesita un servicio se debe indicar en la
interrupcion el número asociado a ella.

Cuando ocurre una interrupción, el control del computador pasa a


la rutina de tratamiento de la interrupcion.

Las direcciones segmentadas utilizadas para localizar la rutinas de


tratamiento de interrupciones se llaman vectores de interrupcion.

Los vectores de interrupcion se establecen en el momento en que se


carga el sistema operativo.

Las interrupciones quedan almacenadas en RAM como tablas formando una


especie de pares de palabras, con la porcion de la direccion relativa,
en primer lugar, y la porcion del segmento en segundo
lugar.

El programa de gestion de la interrupción se llama cargando su


dirección segmentada en el registro que controla el flujo del programa
: Registro CS (segmento de codigo) y el registro IP (puntero de
instrucciones) o par CS:IP.

Cada interrupción tiene un grupo asociado de opciones. Las


interrupciones del PC se pueden dividir en siete categorias las cuales
son:
1. Microprocesador
2. Hardware
3. Software
4. DOS

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 70


5. BASIC
6. Direccionamiento
7. Generales
INTERRUPCIONES DEL MICROPROCESADOR: Se conocen tambien como
interrupciones logicas, estan integradas en el propio microprocesador,
cuatro de ellas son (0, 1, 3, 4) son generadas por el propio
microprocesador.

La interrupcion 2 o interrupcion no enmascarable se activa mediante


una señal que envia un dispositivo externo.

INTERRUPCIONES HARDWARE : Estan implementadas en el hardware del PC.


Ocho de estas interrupciones estan cableadas en el interior del
microprocesador, o en la placa principal (tarjeta madre) y no pueden
ser modificadas. Todas las interrupciones hardware son supervisadas
por el chip 8259A PIC. Los codigos reservados son 2, 8, 9 y del 11 al
15.

INTERRUPCIONES SOFTWARE : Estan incorporadas dentro del diseño del PC


y son parte de los programas de la ROM-BIOS. Las rutinas del BIOS no
pueden cambiarse, pero los vectores que aputan a esas rutinas pueden
ser alteradas para que apunten a rutinas diferentes. Los codigos
reservados son: 5, 16 al 28 y 72.

INTERRUPCIONES DOS : Se encuentran siempre disponibles cuando el DOS


esta en uso. Algunos lenguajes y programas hacen uso de estos
servicios a traves de interrupciones DOS para manejar sus operaciones
basicas de entrada y salda del disco. Los codigos reservados van del
32 al 255 (se aconseja usar del 32 al 96 el resto no conviene
tocarlos).

INTERRUPCIONES BASIC : Son asignadas por el BASIC y estan disponibles


cuando se utiliza BASIC. Los codigos reservados van del 128 al 240.

INTERRUPCIONES DE DIRECIONAMIENTO : Son una parte de la tabla de los


vectores de interrupcion y se utilizan para almacenar direcciones
segmentadas. No hay rutinas de tratamiento asociadas a estas
interrupciones. En particular estan asociadas con tres tablas muy
importantes :

1. La inicialización de video
2. La tabla base de disco
3. La tabla de caracteres graficos

Estas tablas contienen parametros que utiliza la ROM-BIOS en


procedimientos de puesta en marcha y ademas para la generacion de
caracteres graficos. Los codigos reservados van del 29 al 31, 68 y el
73 (78 y 63 solo para PCJr).

INTERRUPCIONES DE USO GENERAL : Están establecidas para los programas


para su uso temporal. Los codigos reservados van del 96

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 71


al 103.

Los vectores de interrupción estan almacenados en las localizaciones


más bajas de memoria.

La primera localización de memoria contiene el vector para la


interrupcion numero 0 (cero) y asi sucesivamente.

Para encontrar la localización de cualquiera interrupcion se


multiplica el numero de interrupción por cuatro, debido a que cada
vector tiene una longitud de dos palabras. por ejemplo el vector para
interrupcion 5 (interrupcion de servicio de escritura en pantalla)
tendra el byte de direccion relativa 20 (5 x 4 =20).
Con la ayuda del depuador del sistema DEBUG y dando este valor en
hexadecimal podemos examinar el vector de interrupcion del mismo.

Ejemplo:
20 decimal es igual a 14 hexadecimal
de esta manera podriamos escribir:

DEBUG <cr>
D 0000:0014 L 4 <cr>

La respuesta seria:

54 FF 00 F0

Convirtiendo este resultado en una direccion segmentada y teniendo en


cuenta el almacenamiento "back word" (palabra invertida), se puede
apreciar que el vector de interrupcion para el punto de entrada en la
ROM de la rutina es F000:FF54.

EL MICROPROCESADOR 8088

El 8088 es un microprocesador de 16 bits (CPU).


El 8088 controla las operaciones basicas del ordenador, envia y recibe
señales de control, direcciones de memoria y datos de una parte a otra
del computador a traves de la red electronica de interconecciones
llamadas bus.
A lo largo del bus se encuentran los puertos de E/S, las diversas
memorias y los chips de soporte.

Dentro del 8088 existen 14 registros, que proporcionan un area


edecuada para poder realizar la transferencia de los datos y su
procesamieto. Los 14 registros del 8088 forman una memoria de 28 bytes
y pueden almacenar datos, direcciones de memoria, punteros de
instrucción e indicadores de estado y control.

LOS CHIPS DE SOPORTE

El microprocesador por si solo no es capaz de controlar todo el

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 72


computador para lo cual delega algunas funciones a otros chips,
pudiendo de esta manera encargarse de su propio trabajo.
Aunque existen muchos chips de soporte en nuestro estudio solo
trataremos el controlador de interrupciones 8259.

EL CONTROLADOR 8259 (Controlador de interrupciones)

Este chip supervisa la realización de las interrupciones. Las


interrupciones son señales enviadas a la CPU por el hardware para
requerir su atención, o responder a alguan acción.
Este chip intercepta las señales, determina su nivel de prioridad con
relación a otras señales que se esten recibiendo y activa una señal de
interrupción de la CPU en función de su desición. En cuanto la CPU
recibe la señal de interrupción, llama a un programa especifico
asociado con el dispositivo periferico involucrado en el proceso. Es
este programa el que llevará a cabo la acción especifica. Luego de
haber terminado la ejecución de la rutina llamada en la interrupción,
el control vuelve nuevamente al sitio donde estaba cuando ocurrio la
interrupción.
Hay tres categorias principales de interrupciones.

Interrupciones generadas por la circuiteria del ordenador en respuesta


a algun acontecimiento, tal como la pulsación de una tecla. Estas
interrupciones son manejadas por el chip 8259, el cual le dá prioridad
en orden de importancia antes de enviarlas a la CPU.
Interrupciones generadas por la CPU como resultado de alguna operación
inusual producida por el programa por ejemplo división por cero.
Interrupciones generadas por los programas como un camino para invocar
servicios almacenados en ROM o RAM estas interrupciones reciben el
nombre de interrupciones por software y serán nuestro tema principal
para lograr algunas funciones como el borrado de la pantalla y otras
en nuestro curso de lenguaje C.

Es posible crear nuevas rutinas de interrupción y hacer que los


vectores de interrupción apunten a ellas para que así puedan ser
ejecutadas en el momento que se requieran.
Las interrupciones guardan automaticamente los valores contenidos en
los registros (CS) e (IP). De esta forma el computador puede volver al
sitio donde estaba cuando se produjo la interrupción.

COMO DIRECCIONA LA MEMORIA EL 8088?

El 8088 direcciona la memoria de tres maneras:


-Forma directa o indirecta
-A traves de punteros.
-Mediante interrupciones

La memoria puede ser utilizada para leer o escribir.


Los datos se almacenan en localizaciones que se identifican a traves
de un número llamado dirección de memoria.
Se puede acceder directamente a la memoria por medio del chip 8237A, o

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 73


controlador de acceso directo a memoria (DMA) o indirectamente a
traves de los registros internos del 8088. El controlador de disco y
puertos en serie pueden acceder directamente a la memoria a traves del
controlador (DMA) el resto de dispositivos transfiere datos a y desde
la memoria haciendo uso de registros del 8088.

USO DE LOS RECURSOS DEL SISTEMA

Permiten:

1. Acceso directo a los recursos del sistema operativo.


2. Acceso al entorno del computador.
3. Acceso a rutinas standard de biblioteca.
4. Manejar una función por uno mismo.

FAMILIA DE MICROPROCESADORES INTEL 8086

Contiene 14 registros en los que pone la información para procesar o


el programa de control.

Los registros se dividen en 4 categorias:


1. De proposito general.
2. De base de puntero indice.
3. De segmento.
4. De proposito especial.

Cada registro tiene una longitud de 16 bits (2 Bytes).

1. Registros de proposito general


Son registros de trabajo de la CPU. En ellos se ponen los valores para
su procesamiento. El procesamiento incluye : Sumar, restar,
multiplicar, dividir, comparaciones, bifurcaciones.
A cada registro de proposito general se accede de dos formas:
-Como registro de 16 bits.
-Como registro de 8 bits.

2. Registros base de puntero e indice.


Proporcionan soporte a cosas como direccionamiento relativo, puntero
de pila e instrucciones para mover un bloque.

3. Registros de segmento.
Soportan el esquema de memoria segmentada del 8086.
CS :Segmento de codigo actual.
DS :Segmento de datos actual.
ES :Segmento extra.
ES :Segmento de pila.

4. Registros de proposito especial.


Registro de indicadores. Guardan el estado de la CPU.
Registro puntero de instrucciones. Apunta a la siguiente instrucción
en la CPU.

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 74


UNA VISION DETALLADA DE LOS REGISTROS DEL 8088.

Registros de proposito general

Registros de puntero e indice

SP SI
Puntero de pila Puntero indice

BP DI
Puntero base Indice destino

Registros de segmento

CS SS
Segmento de codigo Segmento de pila

DS ES
Segmento de dato Segmento extra
registros de proposito especial

IP
Registro indice Puntero de instrucciones

Las interrupciones del 8086 y PC-DOS

Una interrupción es un tipo de instrucción especial que provoca la


parada en la ejecución del programa, guarada el estado actual del
sistema en la pila y salta a la rutina de manejo de la interrupción
que se determina por el número de interrupción.
Luego regresa de vuelta de la interrupción y reanuda la ejecución del
programa.
Existen dos tipos de interrupción:
1. Por hardware
2. Por software

La instrucción INT es usada para llevar a cabo interrupciones.

Ejemplo : INT 21h

El número de interrupción es usado para hallar el manejador de


adecuado de interrupción.

Se reserva el primer Kilo Byte de memoria para usarlo con una tabla de

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 75


vectores de interrupcón. Esa tabla contiene las direcciones de los
manejadores de interrupción, en forma de segmento/desplazamiento.

Cada dirección requiere de cuatro Bytes.


256 vectores de interrupción. INT 5 -=> 5 x 4 = 20 0014h.
El sistema operativo ha asignado una serie de estos vectores para usar
con el ROM-BIOS y DOS.
Mediante interrupciones accedemos a funciones del sistema operativo.
La función accedida es determinada por el registro AH, la información
adicional se pasa en los registros AL, AX, CX y DX.
El sistema operativo PC-DOS se divide en ROM-BIOS y DOS.

/***
* INTER1.C
* interrupcion ROM-BIOS 19h
* activacion de la rutina de arranque del sistema
* (bootstrap)
*-------------------------------------------------
* Objetivo : Utilizo frecuentemente esta interrupcion para dos
* cosas:
* 1. El inmediato cierre de las operaciones del
* computador cuando se encuentra una situacion
* intolerable, por ejemplo el intento de copia de
* un software.
* 2. Para hacer un arranque del sistema sin hacer
* las operaciones de reset y restart.
*/

#include <dos.h>

void boot();

main()
{
boot();
}

void boot()
{
union REGS r;

int86(0x19, &r, &r);


}

/***
* INTER2.C
* interrupcion DOS (21h)
* Servicio : 35h Captar el vector de interrupcion

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 76


* Entrada:
* AH = 35
* AL = nro de interrupcion
* Salida:
* ES Segmento
* BX Desplazamiento
*-------------------------------------------------
*/

#include <dos.h>

void showvec();

main()
{
showvec();
}

void showvec()
{
int i;
union REGS r;
struct SREGS sr;

for(i = 0; i < 256; ++i){


r.h.ah = 0x35;
r.h.al = i;
intdosx(&r, &r, &sr);
printf("Interrupcion %3d, Segmento %8x Offset %8x\n",
i, sr.es, r.x.bx);
}
}

/***
* INTER3.C
* interrupcion DOS (21h)
* escribir caracteres en la impresora
*-------------------------------------------------
* Entrada:
* AH = 5h
* AL = caracter
* Devuelve:
* none
*/

#include <dos.h>

void escricar();

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 77


char *output = "prueba";
main()
{
while(*output)
escricar(*output);
}

void escricar(c)
int c;
{
union REGS r;

r.h.ah = 0x5;
r.h.al = c;
intdos(&r, &r);
}

/***
* INTER4.C
* interrupcion ROM-BIOS 13h
* sistema de disco
* servicio : 1
* obtiene status del disco
*-------------------------------------------------
* Entrada:
* AH = 1
* Devuelve:
* AL : 1 comando incorrecto
* 2 marca de direccion no encontrada
* 3 intento de escritura en disco protegido
* 4 sector no encontrado
* 6 disco retirado
* 8 rebasar el limite del DMA
* 9 DMA mas alla de los 64K
* 10 mal CRC
* 20 fallo del controlador NEC
* 40 falo de busqueda
* 80 time out
*/

#include <dos.h>

drive_st();

main()
{
int i;

i = drive_st();

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 78


printf("%d\n", i);
}

drive_st()
{
union REGS r;

r.h.ah = 0x1;
return(int86(0x13, &r, &r));
}

/* WHEREX.C obtiene la columna actual del cursor */


/* Uso : wherex(); */
/* Ejemplo : x = wherex(); */

#include <dos.h>

union REGS regs;

wherex()
{
regs.h.ah = 3; /* obtener posicion del cursor */
regs.h.bh = 0; /* para la pagina 0 */
int86(0x10, &regs, &regs);
return(regs.h.dl); /* columna actual */
}

/* WHEREY.C obtiene la fila actual del cursor */


/* Uso : wherey(); */
/* Ejemplo : y = wherey(); */

#include <dos.h>

union REGS regs;

wherey()
{
regs.h.ah = 3; /* obtener posicion del cursor */
regs.h.bh = 0; /* para la pagina 0 */
int86(0x10, &regs, &regs);
return(regs.h.dh); /* fila actual */
}

/* GOTOXY.C posiciona el cursor en un sitio de la pantalla */


/* Uso : gotoxy(x, y); */

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 79


/* Ejemplo : gotoxy(10, 2); col 10, fil 2 */

#include "dos.h"

gotoxy(col, row)
int col, row;
{
union REGS regs;

regs.h.ah = 2; /* establece la posicion del cursor */


regs.h.bh = 0; /* pagina de video 0 */
regs.h.dh = row; /* fila */
regs.h.dl = col; /* columna */
int86(0x10, &regs, &regs);
}

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 80


EL SISTEMA EXTENDIDO DE CLIPPER

Este capitulo contiene toda la información que usted necesita para


escribir funciones de usuario en otros lenguajes como C o Assembler.

Temas a cubrir:

1. Descripción del sistema extendido de Clipper

2. Sumario de funciones extendidas

3. Haciendo la interface con C

4. Ejemplo de funciones C

5. Compilando y enlazando sus funciones C

6. Ejercicios de demostración

DESCRIPCION DEL SISTEMA EXTENDIDO DE CLIPPER

La arquitectura abierta de Clipper permite escribir funciones en otros


lenguajes y ademas dispone de herramientas para pasar y recibir
parametros a o desde dichas funciones.
Las funciones pueden ser llamadas desde cualquier programa Clipper que
así lo requiera. Por ejemplo, el valor que devuelve una función puede
ser almacenado en una variable, empleado en un calculo o desplegado en
la pantalla.

Ejemplo:

Xvar_mem = funcion(<exp>)

Es posible escribir funciones en Lenguaje C o Assembler 8088 mediante


el sistema extendido de Clipper, luego puede enlazar estas funciones a
sus programas de aplicacion Clipper compilados de antemano.

Las funciones escritas en C o Assembler pueden ser usadas para obtener


la información necesaria por un programa Clipper o para realizar
alguna tarea procedimental. No se debe interntar hacer manejo de
archivos usando funciones de entrada y salida como fopen(), open(),
printf() etc. como tampoco es posible acceder a la estructura de los
archivos de base de datos atravez de la forma convencional. Para
lograr todo lo anterior se debe hacer uso de las interrupciones del
DOS.

Las funciones de usuario creadas en C o Assembler deben ser llamadas


usando el mismo nombre con el cual fueron declaradas. No se permiten
abreviaturas sin embargo la función puede ser llamada usando
minusculas o mayusculas.

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 81


Estas funciones de usuario pueden ser declaradas explicitamente en el
programa de aplicación o declaradas EXTERNAL al momento de compilarlas
para luego ser incluidas como simbolos al momento de enlazarlas. Las
funciones de usuario en un REPORT, LABEL FORMs o expresión INDEX,
deben ser declaradas como EXTERNAL.

Ejemplo:

EXTERNAL func_1, func_2

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 82


SUMARIO DE FUNCIONES EXTENDIDAS

Tipo de dato Prototipo C Assembler


Clipper
________________________________________________________________
character char*_parc(int [,int]) __PARC
datechar *_pards(int [,int]) __PARDS
logicalint _parl(int [,int]) __PARL
numericint _parni(int [,int]) __PARNI
numericlong _parnl(int [,int]) __PARNL
numericdouble _parnd(int [,int]) __PARND

int _parclen(int [,int]) __PARLEN


int _parcsiz(int [,int]) __PARCSIZ
int _retclen(int) __RETCLEN

charactervoid_retc(char*) __RETC
datevoid _retds(char*) __RETDS
logicalvoid _retl(int) __RETL
numericvoid _retni(int) __RETNI
numericvoid _retnl(long) __RETNL
numericvoid _retnd(double) __RETND
(no return value)void_ret(void) __RET

HACIENDO LA INTERFACE CON C

Clipper permite la escritura de funciones de usuario en Lenguaje C


mediante sistema extendido. Este mecanismo es el camino para llamar
funciones especializadas que soportan el paso de parametros en ambos
sentidos Clipper a C, C a Clipper.

Estas funciones se hallan en la libreria Clipper. Las funciones de


usuario en C pueden ser declaradas despues de incluir el archivo
NANDEF.H y EXTEND.H. En estos archivos se encuentran las declaraciones
y definiciones necesarias para escribir funciones de usuario en C.

RECIBIENDO PARAMETROS EN C

El concepto de parametros formales C desaparece de este punto. Todos


los parametros pueden ser accedidos usando las funciones _par().

DEVOLVIENDO VALORES DESDE C

Las funciones _ret() son usadas para devolver valores a Clipper.


Estas funciones como toda función solo devuelven un valor. El uso de
una de las funciones _ret depende del tipo de dato que se quiera
devolver.

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 83


EJEMPLO DE FUNCIONES C

Este es el esquema de una funcion de usuario tipica para enlazar con


Clipper.

En C:

CLIPPER <function_name>()
/* parametros formales C omitidos */
{
<declaración de variables locales>

if (<parametros son validos>


{
<codigo a ejecutar>
}
else
{
<codigo a ejecutar para parametros indefinidos>
return;
}
}

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 84


En Clipper:

DECLARE arr[3]
arr[1] = "Devorah"
arr[2] = 456.56
arr[3] = CTOD("09/01/87")
Arrfunc(arr)

En C:

#include "extend.h" /* Declaras Sistema Extendido */


#include "stdio.h"/* libreria standard io */
#include "math.h"/* libreria standard math */

CLIPPER arrfunc() /* especifica CLIPPER */


/* typedef void pascal */
{
int i;

for (x = 1; x <= 3; ++x)


{
/* variables string */
if (_parinfa(1, x) == CHARACTER)
{
cprintf("%s\n", _parc(1, x));
}

/* entero o de punto flotante */


if (_parinfa(1,X) == NUMERIC)
{
cprintf("%f\n", _parnd(1, x));
}
else
/* fecha */
if (_parinfa(1, x) == DATE)
{
cprintf("%s\n", _pards(1, i));
}
}
_ret();
}

Nota: El uso de cprintf() es unicamente para proposito de


demostracion. Le recomiendo que toda la entrada y salida la realice
desde Clipper o la haga mediante el uso de interrupciones.

COMPILANDO Y ENLAZANDO SUS FUNCIONES C

Si la función o funciones que desaean enlazar con sus programas


Clipper fueron escritas en Microsoft C 5.0, es necesario que la
compilación se haga estableciendo los switchs de compilación adecuados

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 85


los cuales se describen a continuación:

CL /c /AL /Zl /Oalt /FPa /Gs <nombre_archivo>.c


Donde:

CL = Invoca el compilador CL.EXE


/c = Compilar sin hacer enlace
/AL = Genera codigo para modelo largo de memoria (L)arge
/Zl = No hace busqueda en las librerias por defecto
(l)ibrary-search
/Oalt = control de optimización

Donde:

a = No chequea alias
l = Habilita la optimización de los loop
t = Ejecuta a la maxima velocidad

/FPa = Manejo de punto flotante usando la libreria alterna.


(a)lternate library
/Gs = Quita las llamadas a rutinas para chequeo de pila
(s)tack-checking routine

Para Microsoft Quick C la compilación es la siguiente:

QCL /c /AL /Zl /Oalt /FPi /Gs <nombre_archivo>.c

/FPi = Manejo de punto flotante emulada por software si no está


presente el 8087 en caso de encontrarlo, este será utilizado.
/FPi87 = Manejo de punto flotante por Hardware 8087.

ENLACE DE UNA FUNCION C CON UN PROGRAMA CLIPPER

Para hacer el enlace se debe usar el enlazador que más le simpatice.


Particularmente me gusta trabajar con TURBO LINK de Borland (TLINK).

Ejemplo:

Suponga que desea enlazar una función C que se encuentra en un archivo


llamado udf_c.obj con un programa Clipper que se encuentra en el
archivo prog.obj. Imagine ademas que Clipper se encuentra en el
directorio CLIPPER que se desprende del raiz:

Las librerias Quick C se encuentran en el directorio QC25\LIB,


entonces la linea de orden podria ser:

TLINK prog + udf_c,,,\CLIPPER\CLIPPER+\CLIPPER\EXTEND+\QC25\LIB\LLIBCE

MACROS C PREDEFINIDOS

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 86


Para simplificar la sintaxis y hacer más legible el codigo, se ha
colocado en el archivo EXTEND.H una serie de macros que permiten hacer
el chequeo o validación de los parametros pasados a la función de
usuario:

#defines en EXTEND.H

Tipo Devuelve
-------------------------------------
indefinido = UNDEF
caracter = CHARACTER
numerico = NUMERIC
logico = LOGICAL
fecha = DATE
por referencia = MPTR
memo = MEMO
arreglo = ARRAY

MACROS C INTERFACE PREDEFINIDOS

EXTEND.H MacroDefinido como


------------------------------------------------------
PCOUNT(_parinfo(0))
ISCHAR(order) (_parinfo(order) & CHARACTER)
ISNUM(order) (_parinfo(order) & NUMERIC)
ISLOG(order) (_parinfo(order) & LOGICAL)
ISDATE(order) (_parinfo(order) & DATE)
ISMEMO(order) (_parinfo(order) & MEMO)
ISBYREF(order) (_parinfo(order) & MPTR)
ISARRAY(order) (_parinfo(order) & ARRAY)
ALENGTH(order) (_parinfa(order, 0))

En una función de usuario, usted puede usar el macro PCOUNT y


cualquiera de los macros IS<tipo> para determinar cuantos parametros
se han pasado y de que tipo. Esto le permite validar para asegurarse
de que si se han pasado los parametros correctos y el número esperado.

REFERENCIA - FUNCIONES C INTERFACE DEL SISTEMA EXTENDIDO

_parc()

Pasa un puntero a una cadena de caracteres Clipper.

Sintaxis de uso:

#include <extend.h>

char *_parc(order, index)

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 87


int order; Sitio que ocupa el parametro en la lista de parametros
pasados desde Clipper.

int index; Indice para parametros tipo array.

Descripción:

_parc() es usado para recibir parametros caracter que se pasan desde


Clipper.
Si se pasa parametro por valor, se hará una copia de tipo char *. Si
se pasa parametro por referencia, estará trabajando sobre el parametro
actual Clipper (La misma dirección de memoria).

_parclen()

Devuelve la longitud de una cadena en caracteres.

Sintaxis de uso:

#include <extend.h>

int _parclen(order, index)

int order; Sitio que ocupa el parametro en la lista de parametros


pasados desde Clipper.

int index; Indice para parametros tipo array.

Descripción:

_parclen() devuelve la longitud de una cadena de caracteres pasada


desde Clipper.

_parclen() Obtiene la longitud de la cadena sin contar el terminador


nulo.
_parcsiz()

Devuelve el tamaño de una cadena.

Sintaxis de uso:

#include <extend.h>

int _parcsiz(order, index)

int order; Sitio que ocupa el parametro en la lista de parametros


pasados desde Clipper.

int index; Indice para parametros tipo array.

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 88


Descripción:

_parcsiz() Devuelve el número de bytes en memoria que ocupa una cadena


especifica incluyendo el terminador nulo.
_parsize() Devuelve cero para cuando se pasan constantes.
Ejemplo:

DO <proces> WITH "ABC"

_pards()

Pasa un puntero caracter a una fecha Clipper.

Sintaxis de uso:

#include <extend.h>

char *_pards(order, index)

int order; sitio que ocupa el parametro en la lista de parametros


pasados desde Clipper.

int index; Indice para parametros tipo array.

Descripción:

_pards() Pasa un puntero char * a una fecha que se recibe desde


Clipper. La fecha queda representada como una cadena en el formato
YYYYMMDD.

_parinfa()

Permite chequear tipos de elementos de un arreglo que se ha pasado


como parametro.

Sintaxis de uso:

#include <extend.h>

int _parinfa(order, index)

int order; Sitio que ocupa el parametro en la lista de parametros


pasados desde Clipper.

int index;Indice para parametros tipo array.

Descripción:

_parinfa() Devuelve el tipo al cual pertenece un elemento de un


arreglo. _parinfa(<n>, 0) devuelve el número de elementos del array.

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 89


Ejemplo:

La siguiente función, arrfunc(), toma un array definido en Clipper y


muestra todos los elementos formateados de acuerdo al tipo de dato.

En Clipper:

DECLARE array[2]
array[1] = "Devorah"
array[2] = 456.56
ArrFunc(array)

En C:

for (x = 1; x <= _parinfa(1, 0); ++x)

{ /* variables string */
if (_parinfa(1, x) == CHARACTER)
{
cprintf("%s\n", _parc(1, x));
}

/* entero o punto flotante */


if (_parinfa(1, x) == NUMERIC)
{
cprintf("%f\n", _parnd(1, x));
}
}

_parinfo()

Chequea el tipo de parametro.

Sintaxis de uso:

#include <extend.h>

int _parinfo(order)

int order; Sitio que ocupa el parametro en la lista de parametros


pasados desde Clipper.parameters to type-check

Descripción:

_parinfo() Es usado para chequear el tipo de parametro pasado.


_parinfo(0) Devuelve el número de parametros pasados y _parinfo(<n>)
Devuelve el tipo de parametro <n> donde <n> es la posición en la lista

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 90


de parametros. El valor devuelto es uno de los siguientes:

/* _parinfo types from extend.h*/


#define UNDEF 0
#define CHARACTER 1
#define NUMERIC 2
#define LOGICAL 4
#define DATE 8
#define ALIAS 16
#define MPTR 32
#define MEMO 64
#define WORD 128
#define ARRAY 512

Ejemplo:

La siguiente función de usuario, cfunc(), recibe cuatro parametros


desde Clipper, un tipo caracter, un tipo numerico, un tipo logico y un
tipo fecha; declara las variables C que deben recibir los valore, y
despues valida los parametros:

CLIPPER cfunc()
{
char *parm1;
double parm2;
int parm3; /* logico declarado como int */
char *parm4; /* fecha declarado como char (YYYYMMDD) */

if (PCOUNT == 4 && ISCHAR(1) && ISNUM(2) && ISLOG(3) && ISDATE(4))

{
<codigo a ejecutar si los parametros son validos>
}
else
{
<codigo a ejecutar si los parametros son invalidos>
}

_parl()

Pasa un entero como valor lógico, 1 = .T., 0 = .F.

Sintaxis de uso:

#include <extend.h>

int _parl(order, index)

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 91


int order; Sitio que ocupa el parametro en la lista de parametros
pasados desde Clipper.

int index;Indice para parametros tipo array.

Description:

_parl() Recibe un parametro lógico desde Clipper y lo combierte en


entero donde (1 = .T. and 0 = .F.).

_parnd()

Pasa un dato numerico doble.

Sintaxis de uso:

#include <extend.h>
double _parnd(order, index)

int order;Sitio que ocupa el parametro en la lista de parametros


pasados desde Clipper.

int index; Indice para parametros tipo array.

Descripción:

_parnd() Recibe un parametro numerico desde Clipper y lo convierte en


doble.

_parni()

Pasa un dato numerico entero.

Sintaxis de uso:

#include <extend.h>

int _parni(order, index)

int order; Sitio que ocupa el parametro en la lista de parametros


pasados desde Clipper.

int index;Indice para parametros tipo array.

Descripción:

_parni() Recibe un dato numerico entero desde Clipper y lo convierte


en entero.

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 92


_parnl()

Pasa un dato numerico largo.

Sintaxis de uso:

#include <extend.h>

long _parnl(order, index)

int order; Sitio que ocupa el parametro en la lista de parametros


pasados desde Clipper.
int index; Indice para parametros tipo array.

Descripción:

_parnl() Recibe un parametro numerico desde Clipper y lo convierte en


largo (long).

_exmgrab()

Asigna memoria.

Sintaxis de uso:

#include <extend.h>

unsigned char* _exmgrab(bytes)

unsigned int bytes; Tamaño de la memoria a asignar.

Descripción:

_exmgrab() Asigna memoria del tamaño solicitado. Si la asignación


tiene exito, devuelve un puntero char * a la dirección de comienzo de
la memoria asignada; de otra manera, devuelve NULL.

Ejemplo:

size = 512
buff = _exmgrab(size)/* asignar memoria */
if (buff)/* si todo salio bien (!null) */
check = TRUE;

_exmback() Libera la memoria asignada por _exmgrab().

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 93


Ejemplo:

size = 512
buff = _exmgrab(size)/* asigna memoria */
if (buff)/* si todo salio bien (!null) */
check = TRUE;
if (check)
_exmback(buff, size);/* libera memoria */

_exmback()

Libera la memoria asignada.

Sintaxis uso:

#include <extend.h>

void * _exmback(pointer, bytes)

unsigned char *pointer; Puntero de _exmgrab()


unsigned intbytes; Tamaño pasado a _exmgrab()

Descripción:

Libera la memoria asignada por _exmgrab().

DEVOLVIENDO VALORES DESDE C

_ret()

No devuelve ningun valor a Clipper:

#include <extend.h>

void _ret(void)

Descripción:

_ret() No devuelve ningun valor a Clipper. Es utilizado en funciones


que devuelven nada. Funciones procedimentales.

_retc()

Pasa una cadena de caracteres a Clipper.

Sintaxis de uso:

#include <extend.h>

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 94


void _retc(string)

char *string; Puntero a string

Descripción:

_retc() Devuelve una cadena de caracteres a Clipper.

_retclen()

Pasa la longitud de un string a Clipper.

Sintaxis de uso:

#include <extend.h>

void _retclen(string, int)

char *string; Cadena de caracteres a la cual se le quiere calcular su


longitud.
int; longitud de la cadena.

Descripción:

_retclen() Devuelve la longitud de una cadena incluyendo CHR(0)s.

_retds()

Pasa una cadena fecha a Clipper convirtiendola en tipo DATE

Sintaxis de uso:

#include <extend.h>

void _retds(string)

char *string; Fecha como cadena (YYYYMMDD)

Descripción:

_retds() Pasa a Clipper una cadena como fecha char* YYYYMMDD. La


cadena es convertida al formato DATE de Clipper.

_retl()

Pasa un entero a Clipper como valor lógiico.

Sintaxis de uso:

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 95


#include <extend.h>

void _retl(flag)

int flag; Valor Boolean

Descripción:

_retl() Pasa a unentero a Clipper como un valor lógico, donde 1 es


true (.T.) y 0 es false (.F.).

_retnd()

Pasa un double a Clipper.

Sintaxis de uso:

#include <extend.h>

void _retnd(x);

double x; Expresión numerica

Descripción:

_retnd() Pasa un double a Clipper. El valor es convertido al tipo


NUMERIC de Clipper.

_retni()

Pasa un entero a Clipper.

Sintaxis de uso:

#include <extend.h>

void _retni(n)

int n; Expresión numerica

Descripción:

_retni() pasa un entero a Clipper como dato NUMERIC.

_retnl()

Pasa un dato numerico largo a Clipper.

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 96


Sintaxis de uso:

#include <extend.h>

void _retnl(n)

long n; Expresión numerica long

Descripción:

_retnl() Pasa un entero largo a Clipper como dato de tipo NUMERIC.

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 97


EJERCICIOS DE DEMOSTRACION

/***
*
* DIRE.C
* Funciones de usuario para manejo de directorios.
* Nota : Para enlazar con CLIPPPER/SUMMER '87.
* Estas funciones deben ser compiladas con Microsoft C 5.0 .
* Fecha: Cartagena, Noviembre 22 De 1991.
* Copyright (c) 1991. Anibal G. Martinez Arcia.
* (Especialista en Lenguaje C).
*
*
*
*---------------------------------------------------------------
* Contenido:
* ==========
* FUNCION PROPOSITO
*---------------------------------------------------------------
* get_drive() Obtiene la unidad por defecto.
* set_drive() Establece la unidad por defecto.
* makedir() Crea directorio.
* changedir() Cambia de directorio.
*/

#include <dos.h>
#include <nandef.h>
#include <extend.h>
#include <direct.h>
/***
* get_drive()
* Int DOS. (21h).
* servicio 19h. Captar unidad de disco actual.
* AH : 19h
* AL : devuelve unidad de disco actual
* : 0 = A, 1 = B, 2 = C, Etc.
* Proposito : Captar unidad de disco actual.
* Ej. Uso : var = get_drive()
*
*/
CLIPPER get_drive()
{
static char *drv_name[] = {"A:", "B:", "C:", "D:", "E:", "F:"};

union REGS r;

r.h.ah = 0x19;
intdos(&r, &r);
_retc(drv_name[r.h.al]);
}

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 98


/****
* set_drive()
* Int DOS. (21h).
* Servicio 0Eh. Selecciona la unidad de disco implicita.
* AH : 0xE
* DL : Unidad de disco deseada 0=A, 1=B, 2=C, etc.
* AL : Salida -> numero total de unidades de disco
* presente.
* Proposito : Establecer unidad de disco implicita.
* Ej. Uso : set_drive(1)
*/
CLIPPER set_drive()
{
int drive = _parni(1);

union REGS regs;

regs.h.ah = 0x0E;
regs.h.dl = drive;
intdos(&regs, &regs);
/* return(regs.h.al); */
_ret(); /* no debuelva nada */
}

/***
* makedir(<path>)
* Proposito : Crear directorio.
* Recibe : Path.
* Devuelve : 0 = Exito. -1 = Error.
* Ej. Uso : var = makedir("\usr")
*/
CLIPPER makedir()
{
int error;
char *path = _parc(1);

error = mkdir(path);
_retni(error);
}

/***
* changedir(<path>)
* Proposito : Cambiar de directorio.
* Recibe : Path.
* Devuleve : 0 = exito. -1 = Error.
* Uso : vas = changedir("\usr")
*/
CLIPPER changedir()
{

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 99


char *path = _parc(1);
int error;

error = chdir(path);
_retni(error);
}

/***
*
* STRING.C
* Funciones de usuario para manejo de cadenas.
* Nota : Para enlazar con CLIPPPER/SUMMER '87.
* Estas funciones deben ser compiladas con Microsoft C 5.0 .
* Fecha: Cartagena, Noviembre 22 De 1991.
* Copyright (c) 1991. Anibal G. Martinez Arcia.
* (Especialista en Lenguaje C).
*
*
*
*-------------------------------------------------------------
* Contenido:
* ==========
* FUNCION PROPOSITO
*-------------------------------------------------------------
* cnt_cadena() Devuelve el numero de veces que una subcadena se *
encuentra en una cadena.
*/

#include <dos.h>
#include <nandef.h>
#include <extend.h>

/***
* cnt_cadena(<expC1>, <expC2>)
* Proposito : Devuelve el numero de veces que una subcadena se
* encuentra
* en una cadena.
* <expC1> : Cadena.
* <expC2> : Subcadena.
* Ej. Uso : var = cnt_cadena("esto es una prueba", "es")
*/
CLIPPER cnt_cadena()
{
char *string = _parc(1); /* cadena */
char *sub_string = _parc(2); /* subcadena */
int i, j, k, conta = 0;

for(i = 0; string[i]; i++)


for(j = i, k = 0; sub_string[k] == string[j]; k++, j++)
if(sub_string[k+1]){
conta++; /* encontro la cadena y se incrementa */

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 100


break;
/* inicia busqueda de la siguiente ocurrencia */
}
_retni(conta);
}

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 101


/***
* examplec.c
*
* Example "C" functions using the CLIPPER Extend interface.
*
* The CLIPPER callable functions are.....
*
* SOUNDEX()
* STUFF()
* DISKSPACE()
*
**/

/***
* SOUNDEX()
* kevin j. shepherd, NANTUCKET Corporation.
* 09/14/87
*
* Produces a code based on the "Soundex" method originally
* eveloped by M.K. Odell and R.C. Russell. Algorithm can
* be found on page 392 of Knuths' book 'Sorting and
* Searching', volume 3 of 'The Art of Computer
* Programming", Addison/Wesley publisher.
*
* code = SOUNDEX(name)
*
* code - character string.
* name - character string.
*
* Non-alphabetic characters in input stream will cause the
* function to abort and return a NULL pointer.
*
**/

#include "nandef.h"
#include "extend.h"

#define ISALPHA(c) ((c) >= 'a' && (c) <= 'z' ||


(c) >= 'A' && (c) <= 'Z')
#define UPPER(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 32 : (c))

#define MAX_OMITS 9 /** characters to be ignored **/


#define MAX_GROUPS 6
/** +1 for NULL pointer in static declare/init **/
#define MAX_DIGITS 4 /** number of digits in code sequence **/
#define CODE_ALLOC 5 /** size of code sequence **/

static byte omit_letter[MAX_OMITS] = " AEHIOUWY";


static byte *code_group[MAX_GROUPS + 1] = {
"BFPV",

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 102


"CGJKQSXZ",
"DT",
"L",
"MN",
"R",
NULL
};
extern Boolean name_2_code();
extern byte translate();
extern Boolean omit();

/***
*
* soundex()
* kjs
* 09/14/87
*
* Main soundex function, does param checking, allocation,
* string prep, and deallocation.
*
**/

CLIPPER SOUNDEX()

{
Boolean error;

quant i;
quant name_size;

byte *name;
byte *code;

code = NULL;
error = (PCOUNT != 1 || !ISCHAR(1) || _parclen(1) == 0);

if (!error)
{
name = _parc(1);
name_size = (quant)(_parclen(1) + 1);
/** +1 for NIL byte **/
code = _exmgrab(name_size >= CODE_ALLOC
? name_size : CODE_ALLOC);
/** make uppercase **/
for (i = 0; i < name_size; i++)
name[i] = UPPER(name[i]);

error = name_2_code(name, name_size, code);


}

if (!error)

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 103


_retc(code);
else
_retc("");
if (code)
_exmback(code, name_size >= CODE_ALLOC
? name_size : CODE_ALLOC);
}

/***
*
* name_2_code()
* kjs
* 09/14/87
*
* Converts a name into 4 unit code (alpha, digit, digit, digit)
* as per the SOUNDEX method rules.
*
* error = name_2_code(source, source_size, target)
*
**/

Boolean name_2_code(source, source_size, target)

byte *source;
quant source_size;
byte *target;

{
Boolean error;

quant i;
quant j;

error = FALSE;

/** first character not translated **/


target[0] = source[0];
i = 1;
j = 1;

/** copy while filtering unwanted characters **/


while (i < (source_size - 1) && !error)
{
if ((target[j - 1] != source[i]) && !omit(source[i]))
{
error = !ISALPHA(source[i]);

if (!error)
{
target[j] = source[i];
j++;

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 104


}
}

i++;
}

/** truncate string **/


if (j > MAX_DIGITS)
j = MAX_DIGITS;

target[j] = NIL;
if (!error)
{
/** translation **/
for (i = 1; i < j; i++)
target[i] = translate(target[i]);

/** zero fill **/


for (i = j; i < MAX_DIGITS; i++)
target[i] = '0';

target[i] = NIL;
}

return (error);
}

/***
*
* translate()
*
* Translates a character into a code digit.
*
* digit = translate(chr)
*
**/

byte translate(chr)

byte chr;

{
Boolean found;

quant i;
quant j;

byte digit;

found = FALSE;

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 105


i = 0;
j = 0;

digit = NIL;

/** scan groups until match is found **/


while (i < MAX_GROUPS && !found)
{
/** scan the list of character in this group **/
j = 0;
while (j < strlen(code_group[i]) && !found)
{
found = (chr == code_group[i][j]);
j++;
}

if (!found)
i++;
}

digit = (i + 1) + 48; /** convert the subscript to asci **/

return (digit);
}

/***
*
* omit()
*
* Check the character if it is on the omit list.
*
* status = omit(chr)
*
**/

Boolean omit(chr)

byte chr;

{
quant i;

Boolean found;

found = FALSE;

for (i = 0; (i < MAX_OMITS && !found); i++)


found = (chr == omit_letter[i]);

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 106


return (found);
}

/***
* STUFF()
* kevin j. shepherd, NANTUCKET Corporation.
* 09/13/87
*
* Replace LENGTH number of characters in SOURCE starting at START
* with the entire MODIFIER string.
*
* target = STUFF(source, start, length, modifier)
*
* target - character string.
* source - character string.
* start - numeric.
* length - numeric.
* modifier - character string.
*
**/
CLIPPER STUFF()
{
quant i;
quant j;
quant s_max;
quant m_max;
quant buffer_size;

quant start;
quant length;

byte *source;
byte *modifier;
byte *buffer;

/** parameter OK? **/


if (PCOUNT == 4 && ISCHAR(1) && ISNUM(2) && ISNUM(3)
&& ISCHAR(4) &&
_parclen(1) + _parclen(4) > 0)
{
/** local copies **/
source = _parc(1);
modifier = _parc(4);
start = (quant)(_parnl(2) >= 0 ? _parnl(2) : 0);
length = (quant)(_parnl(3) >= 0 ? _parnl(3) : 0);

/** string sizes **/


s_max = (quant)_parclen(1);
m_max = (quant)_parclen(4);

/** allocate a work buffer. **/

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 107


buffer_size = _parclen(1) + _parclen(4) + 1;
buffer = _exmgrab(buffer_size);

/** adjust dBASE string base values to 'C'


base, off-by-one, yea! **/
start = (start > 0 ? start - 1 : 0);

/** get first part of source string. **/


j = 0;
while (j < start && j < s_max)
{
buffer[j] = source[j];
j++;
}

/** insert **/


i = 0;
while (i < m_max)
{
buffer[j] = modifier[i];
j++;
i++;
}

/** copy the rest of the source string. **/


i = start + length;
while (i < s_max)
{
buffer[j] = source[i];
j++;
i++;
}

buffer[j] = NIL;

_retclen(buffer, j);

_exmback(buffer, buffer_size);
}
else
{
_retc("");
}
}

/***
* DISKSPACE()
* Tom Rettig, Brian Russell
* 11/01/85
*

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 108


* Bytes of empty space on a disk drive. The drive is specified
* by the drive_code parameter. DRIVE_CODE is a numeric
* from 0 to n. 0 is the default if code is omitted and
* indicates the currently selected drive. 1 to n reference
* drives A to x.
*
* count = DISKSPACE([drive_code])
*
* count - numeric.
* drive_code - numeric.
*
* Placed in the public domain by Tom Rettig Associates.
*
**/

#define DEFAULT 0

CLIPPER DISKSPACE()
{
struct /* structure to hold disk info */
{
unsigned no_clusts; /* number of free clusters */
unsigned secs_clusts; /* sectors per cluster */
unsigned clusts_drv; /* total clusters per drive */
} drv_info;

/* if there is one parameter and it is numeric */


if (PCOUNT == 1 && ISNUM(1))
{
_dspace(_parni(1), &drv_info); /* specified drive */
}
else
_dspace(DEFAULT, &drv_info); /* default drive */

/* bytes ::= number of clusters times sectors


per cluster times 512 */
_retnl(512L * (long)drv_info.secs_clusts *
(long)drv_info.no_clusts);
}

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 109


ARCHIVOS ENCABEZADO DEL SISTEMA EXTENDIDO
/***
* nandef.h
*
* Nantucket defines
*/

#define FALSE 0
#define TRUE 1

#define NIL '\0'


#define NULL 0L

typedef unsigned char byte;


typedef unsigned int quant;
typedef int Boolean;

/***
*extend.h
*
*DEFINEs and EXTERNs for interfacing with Clipper from C.
*
*Large model C only (double word pointers to code and data)
*
*Copyright (c) Nantucket Corporation 1987
*/

#define CLIPPERvoid pascal

/* _parinfo types */
#define UNDEF 0
#define CHARACTER 1
#define NUMERIC 2
#define LOGICAL 4
#define DATE 8
#define ALIAS 16
#define MPTR 32
/* or'ed with type when passed by reference */
#define MEMO 64
#define WORD 128
#define ARRAY 512 /* parameter count/type */
extern int _parinfo(int);
extern int _parinfa(int, int);

/* parameter values */
extern char *_parc(int, ...);
extern int _parcsiz(int, ...);
extern int _parclen(int, ...);
extern int _parni(int, ...);
extern long _parnl(int, ...);

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 110


extern double _parnd(int, ...);
extern int _parl(int, ...);
extern char *_pards(int, ...);
/* one and only one of the _ret?? functions must used */

/* Clipper-function return values */


extern void _retc(char *);
extern void _retclen(char *, int);
extern void _retni(int);
extern void _retnl(long);
extern void _retnd(double);
extern void _retl(int);
extern void _retds(char *);

/* procedure (DO) return */


extern void _ret(void);

/* allocate memory */
/* parameter: requested size in bytes */
/* returns: far pointer to memory or NULL */
extern unsigned char *_exmgrab(unsigned);

/* free allocated memory */


/* parameters: pointer from _exmgrab(),
same size passed to _exmgrab() */
extern void _exmback(unsigned char *, unsigned);

/* misc. */
extern unsigned strlen(unsigned char *);

/* parameter check macros */


#define PCOUNT(_parinfo(0))
#define ISCHAR(n)(_parinfo(n) & CHARACTER)
#define ISNUM(n)(_parinfo(n) & NUMERIC)
#define ISLOG(n)(_parinfo(n) & LOGICAL)
#define ISDATE(n)(_parinfo(n) & DATE)
#define ISMEMO(n)(_parinfo(n) & MEMO)
#define ISBYREF(n)(_parinfo(n) & MPTR)
#define ISARRAY(n)(_parinfo(n) & ARRAY)
#define ALENGTH(n)(_parinfa(n, 0))

/* Header structure */
typedef struct
{
byte signature;/* 03 = dbf, 83 dbf+dbt */
byte ymd[3]; /* y+1900 m d */
long last_rec;
quant data_off;
quant rec_size;

Curso de Lenguaje C - Por: Ing.Anibal Martinez Arcia. 111


byte pad[20];
} DBF_HEADER;

extern DBF_HEADER *_dbfhead();


extern int _dbfopen();

Curso de Lenguaje C - Por: Anibal Martinez Arcia. 112

Você também pode gostar