1. PYTHON
Universidad Nacional de
Ingenieria
Centro de Tecnologias de
Informacion y
Comunicaciones
Facultad de Ciencias
Abraham Zamudio Ch.
Abraham Zamudio 1
2. PYTHON
Clase 3
Abraham Zamudio Ch.
Abraham Zamudio Chauca
abraham.zamudio@gmail.com
Abraham Zamudio 2
6. El Lenguaje C
● Es un lenguaje de programación de alto nivel, de propósito
general, sintácticamente económico.
● Proximidad a la máquina.
● Potente.
● Su estructura sintáctica y semántica está edificada sobre
conceptos tales como:
● estructuras sencillas,
● jerarquía de bloques y
● control de flujo de datos.
● Instrucciones similares a expresiones algebraicas.
● Buen conjunto de operadores.
● Fácil de aprender.
Abraham Zamudio 6
8. Estructura de un programa en C
Generalmente, un programa en C tiene la
siguiente estructura:
● Comandos para el preprocesador (CPP).
● Definiciones de tipo de datos de las variables
(definición de variables globales).
● Prototipos de funciones (define el nombre de la
función, el tipo que retorna y los parámetros que
recibe, aunque pueden aparecer sólo los tipos
de éstos).
● Funciones (incluyendo la función main()).
Abraham Zamudio 8
9. Estructura de un programa en C
/*
Programa de Ejemplo
Fecha_
Autor_
*/
#include ____
#define ____
typedef ____
[Prototipos]
int main(void)
{
[variables] /* descripcion */
[instrucciones]
return 0;
} Abraham Zamudio 9
10. Estructura de una función en C
Cada función debe contener:
● Un encabezado de la función, que está
compuesta por el nombre de ésta, seguido de
una lista opcional de argumentos encerrados
entre paréntesis y el tipo de dato que retorna.
● Una lista de declaración de argumentos.
● Una o más instrucciones, que conforman el
cuerpo de la función.
Abraham Zamudio 10
12. El Preprocesador de C
El preprocesador tiene más o menos su propio lenguaje el cual
puede ser una herrramienta muy poderosa para el programador.
Todas las directivas de preprocesador o comandos inician con un
#.
Las ventajas que tiene usar el preprocesador son:
● los programas son más fáciles de desarrollar,
● son más fáciles de leer,
● son más fáciles de modificar
● y el código de C es más transportable entre diferentes
arquitecturas de máquinas.
Abraham Zamudio 12
13. El Preprocesador de C
#define
El preprocesador también permite configurar el lenguaje. Por
ejemplo, para cambiar a las sentencias de bloque de código {
... } delimitadores que haya inventado el programador como
inicio ... fin se puede hacer:
#define inicio {
#define fin }
Durante la compilación todas las ocurrencias de inicio y fin
serán reemplazadas por su correspondiente { o } delimitador
y las siguientes étapas de compilación de C no encontrarán
ninguna diferencia.
Abraham Zamudio 13
14. El Preprocesador de C
#define
La directiva #define se usa para definir constantes
o cualquier sustitución de macro. Su formato es el
siguiente:
#define <nombre de macro> <nombre de reemplazo>
Por ejemplo:
#define FALSO 0
#define VERDADERO !FALSO
Abraham Zamudio 14
15. El Preprocesador de C
#define
La directiva #define tiene otra poderosa característica: el nombre
de macro puede tener argumentos. Cada vez que el compilador
encuentra el nombre de macro, los argumentos reales
encontrados en el programa reemplazan los argumentos
asociados con el nombre de la macro. Por ejemplo:
#include <stdio.h>
#define MIN(a,b) (a < b) ? a : b Cambia este pequeño
programa, usa argc y argv para
main() ingresar los argumentos de MIN
{ por teclado
int x=125, y=20;
printf("EL minimo es %dn", MIN(x,y) );
}
Abraham Zamudio 15
16. El Preprocesador de C
#define
Otros ejemplos usando #define pueden ser:
#define Deg_a_Rad(X) (X*M_PI/180.0)
/*
Convierte grados sexagesimales a radianes,
M_PI es el valor de pi y esta definida en la
biblioteca math.h
*/
Abraham Zamudio 16
17. El Preprocesador de C
#undef
Se usa #undef para quitar una definición de
nombre de macro que se haya definido
previamente. El formato general es:
#undef <nombre de macro>
El uso principal de #undef es permitir localizar los
nombres de macros sólo en las secciones de
código que los necesiten.
Abraham Zamudio 17
18. El Preprocesador de C
#include
La directiva del preprocesador #include instruye al
compilador para incluir otro archivo fuente que
esta dado con esta directiva y de esta forma
compilar otro archivo fuente. El archivo fuente que
se leerá se debe encerrar entre comillas dobles o
paréntesis de ángulo. Por ejemplo:
#include <archivo>
#include "archivo"
Abraham Zamudio 18
19. El Preprocesador de C
#include
Cuando se indica <archivo> se le dice al compilador que
busque donde estan los archivos incluidos o ``include'' del
sistema. Usualmente los sistemas con UNIX guardan los
archivos en el directorio /usr/include.
Si se usa la forma "archivo" es buscado en el directorio
actual, es decir, donde el programa esta siendo ejecutado.
Los archivos incluidos usualmente contienen los prototipos
de las funciones y las declaraciones de los archivos cabecera
(header files) y no tienen código de C (algoritmos).
Abraham Zamudio 19
20. El Preprocesador de C
#if (Inclusión condicional)
La directiva #if evalua una expresión constante
entera. Siempre se debe terminar con #endif para
delimitir el fin de esta sentencia.
Se pueden así mismo evaluar otro código en caso
se cumpla otra condición, o bien, cuando no se
cumple ninguna usando #elif o #else
respectivamente.
Abraham Zamudio 20
21. El Preprocesador de C
#if (Inclusión condicional)
#if k-expresion-1
<seccion-1>
#elif k-expresion-2
<seccion-2>
...
#elif k-expresion-n
<seccion-n>
#else
<seccion-final>
#endif
Abraham Zamudio 21
22. El Preprocesador de C
#if (Inclusión condicional)
Por ejemplo :
#define MEX 0
#define EUA 1
#define FRAN 2
#define PAIS_ACTIVO MEX
#if PAIS_ACTIVO == MEX
char moneda[]="pesos";
#elif PAIS_ACTIVO == EUA
char moneda[]="dolar";
#else
char moneda[]="franco";
#endif
Abraham Zamudio 22
23. Lectura de Datos desde la
consola
● El prototipo de la función main que se utiliza comúnmente es:
int main( void )
● La rutina main no admite ningún parámetro.
● Sin embargo existe otro posible prototipo para esta función:
● int main( int argc, char **argv ) o int main( int argc, char *argv[] )
Donde:
● int argc: Este parámetro contiene el número de argumentos con
los que el programa ha sido llamado, incluyendo mismo nombre
del programa (binario).
● char **argv: Array de punteros a punteros de cadenas de
caracteres.
● Ejemplo:
● ps –eo pid,ppid,stat,command
● La función main es llamada por el Sistema Operativo
(específicamentepor el kernel).
Abraham Zamudio 23
25. Primer Ejemplo (C)
#include <stdio.h>
main(int argc, char *argv[])
{
int i,n;
/*Control de numero de argumentos. Es un control habitual en todo programa Unix que debe aceptar un numero determinado de argumentos. */
if (argc < 1) {
fprintf(stderr,"argv: utilización argv arg1 arg2 arg3 arg4 ...n");
return 0;
}
/* Visualiza todos los argumentos. Cada componente de argv es una tira. El primer componente es el nombre del programa que se ejecuta */
for (i=0;i<argc;i++)
printf("El argumento %d es %sn",i,argv[i]);
printf("n");
}
Abraham Zamudio 25
26. Segundo Ejemplo (C)
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int i;
char **p;
puts("-------------");
puts("forma 1: n");
for (i = 0; i < argc; i++)
printf("argv[%d]=%sn", i, argv[i]);
puts("-------------");
puts("forma 2: n");
for (p = argv; *p != NULL; p++)
printf("argv[%ld]=%sn", (long) (p - argv), *p);
puts("-------------");
return EXIT_SUCCESS;
}
Abraham Zamudio 26
27. Tercer Ejemplo (C)
#include <fcntl.h>
main(argc,argv)
int argc;
char * argv[];{
char buffer[16],c;
int l,f1,f2,i;
f1=0;f2=1;
switch(argc){
case 3: f2=open(argv[2],O_WRONLY|O_CREAT);
case 2: f1=open(argv[1],O_RDONLY);
break;
case 1: break;
default: perror("Error: demasiados argumentos");
return 0;
}
while((l=read(f1,buffer,sizeof(buffer)))>0){
for(i=0;i<l;i++){
c = (char)buffer[i];
if (islower(c))
buffer[i]=(char)toupper((int)buffer[i]);
else if (isupper(c))
buffer[i]=(char)tolower((int)buffer[i]);
}
write(f2,buffer,l);
}
}
Abraham Zamudio 27
28. #include <stdio.h>
#include <stdlib.h>
#include <math.h>
int calcula ( float, float );
int main(){
float a, b;
Elimina printf y
int mcd;
printf("Programa que calcula el MCD de dos numeros:nn");
printf("Inserta a: ");
scanf("%f", &a);
scanf usando
printf("Inserta b: ");
scanf("%f", &b);
mcd= calcula (a , b);
printf("El mcd de a y b es %dnn", mcd);
argc y argv
getchar ();
return 0;
}
int calcula ( float a, float b )
{
float r, rmcd = 0;
do
{
r = fmod ( a, b );
if ( r == 0 )
b = rmcd;
else
{
a = b;
b = r;
rmcd = b;
}
} while ( r != 0 );
return ( rmcd );
}
Abraham Zamudio 28
29. Memoria dinámica: malloc y free
Los variables y vectores en C ocupan un tamaño prefijado,
no pueden variarlo durante la ejecución del programa.
Por medio de punteros se puede reservar o liberar memoria
dinámicamente, es decir, según se necesite. Para ello existen
varias funciones estándares, de la biblioteca <stdlib.h>x
La función malloc sirve para solicitar un bloque de memoria
del tamaño suministrado como parámetro. Devuelve un
puntero a la zona de memoria concedida:
Abraham Zamudio 29
30. Memoria dinámica: malloc y free
void* malloc ( unsigned numero_de_bytes );
El tamaño se especifica en bytes. Se garantiza que la zona
de memoria concedida no está ocupada por ninguna otra
variable ni otra zona devuelta por malloc.
Si malloc es incapaz de conceder el bloque (p.ej. no hay
memoria suficiente), devuelve un puntero nulo.
Abraham Zamudio 30
31. Memoria dinámica: malloc y free
void *malloc(size_t size);
Lo anterior indica que regresará un apuntador del
tipo void *, el cual es el inicio en memoria de la
porción reservada de tamaño size. Si no puede
reservar esa cantidad de memoria la función
regresa un apuntador nulo o NULL
Dado que void * es regresado, C asume que el
apuntador puede ser convertido a cualquier tipo.
El tipo de argumento size_t esta definido en la
cabecera stddef.h y es un tipo entero sin signo.
Abraham Zamudio 31
32. Memoria dinámica: malloc y free
char *cp;
cp = (char *) malloc(100);
Intenta obtener 100 bytes y asignarlos a la
dirección de inicio a cp.
Es usual usar la función sizeof() para indicar el
número de bytes, por ejemplo:
int *ip;
ip = (int *) malloc(100 * sizeof(int) );
Abraham Zamudio 32
33. Memoria dinámica: malloc y free
El compilador de C requiere hacer una conversión
del tipo. La forma de lograr la coerción (cast) es
usando (char *) y (int *), que permite convertir un
apuntador void a un apuntador tipo char e int
respectivamente. Hacer la conversión al tipo de
apuntador correcto asegura que la aritmética con
el apuntador funcionará de forma correcta.
s una buena práctica usar sizeof() aún si se
conoce el tamaño actual del dato que se requiere,
-- ya que de esta forma el código se hace
independiente del dispositivo (portabilidad).
Abraham Zamudio 33
34. Memoria dinámica: malloc y free
(sizeof)
La función sizeof() puede ser usada para encontrar el tamaño de
cualquier tipo de dato, variable o estructura. Simplemente se debe
proporcionar uno de los anteriores como argumento a la función.
Por lo tanto:
int i;
struct COORD {float x,y,z};
struct COORD *pt;
sizeof(int), sizeof(i), sizeof(struct COORD) son tambien sentencias
correctas.
Abraham Zamudio 34
35. Memoria dinámica: malloc
(sizeof)
En el siguiente ejemplo se reserva memoria para la variable ip, en
donde se emplea la relación que existe entre apuntadores y
arreglos, para manejar la memoria reservada como un arreglo. Por
ejemplo, se pueden hacer cosas como:
main()
{
int *ip, i;
ip = (int *) malloc(100 * sizeof(int) );
ip[0] = 1000;
for (i=0; i<100; ++i)
scanf("%d",ip++);
}
Abraham Zamudio 35
36. #include <stdio.h>
int main(void)
{
Malloc rulez !!!!!
float *bufferFloat;
int num, i;
/*Lee el numero de datos que se van a introducir y despues pide los valores*/
printf ("nCuántos valores va a introducir? ");
scanf ("%d", &num);
bufferFloat = (float *) malloc (sizeof(float) * num);
for (i=0;i<num;i++)
{
printf ("Introduzca el valor numero %d: ", i+1);
scanf ("%f", (bufferFloat + i));
}
for (i=0;i<num;i++)
{
printf ("El valor numero %d que introdujo fue ----> %fn", i+1, *(bufferFloat+i));
}
free(bufferFloat);
return 0;
}
Abraham Zamudio 36
37. Librerias (C)
Las librerías son archivos que contienen código
objeto agrupado en funciones o subrutinas que
pueden ser utilizadas por otros programas.
Estos archivos tienen una estructura especial
dependiendo del tipo de librería que se trate.
Abraham Zamudio 37
38. Librerias (C)
El ejemplo mas popular de librerías en Unix es la libc, que es
la librería estándar de funciones C, y contiene subrutinas
utilizables para operaciones de entrada y salida.
La notación estándar de la librería es:
● libpalabra.extensión
● palabra: diferencia unas librerías de otras, dando una
idea de qué tipo de funciones contiene.
● extensión: indica el tipo de librería, la cual puede ser
estática (.a) o dinámica o compartida (.so).
Abraham Zamudio 38
39. Librerias (C)
Se pueden destacar dos formas de utilización de las
librerías:
● Para utilización local, es decir, como un elemento mas
del desarrollo de una aplicación.
● Son de fácil mantención.
● Como un paquete de funciones desarrolladas por un
fabricante.
● No es posible modificarlas.
● En general, el sistema conoce su ubicación.
Abraham Zamudio 39
40. Librerias (C)
Las librerías de utilización local deben ser
registradas en alguna variable de ambiente del
sistema para indicar su ubicación, por ejemplo,
LD_LIBRARY_PATH.
$echo $ LD_LIBRARY_PATH
Abraham Zamudio 40
41. Librerias del Sistema
● libc. Librería estándar de C.
● Entrada y salida estándar: scanf, printf, getchar, que utiliza el
archivo cabecera stdio.h.
● Funciones de manipulación de caracteres y string: strcpy,
strlen, etc.
● Fechas: ctime, etc.
● Llamadas al sistema: como fork().
● Linux utiliza Glic, la librería C GNU.
● libm. Librería de funciones matemáticas: cos, sin, exp, etc.
● libX11. Librería interfaz gráfica para el sistema X, con funciones
como xterm, xload, etc.
● libGL: librería de OpenGL.
● libpthread: librería de POSIX threads.
Abraham Zamudio 41
42. Makefiles (1º Acto)
El comando de linux make nos ayuda a compilar
nuestros programas. Presenta muchas ventajas
para programas grandes, en los que hay muchos
ficheros fuente (muchos .c y muchos .h)
repartidos por varios directorios. Principalmente
aporta dos ventajas:
Abraham Zamudio 42
43. Makefiles (1º Acto)
●Es capaz de saber qué cosas hay que recompilar. Si cuando
estamos depurando nuestro programa tocamos un fichero fuente,
al compilar con make sólo se recompilaran aquellos ficheros que
dependan del que hemos tocado. Si compilamos a mano con gcc,
(o el compilador que sea), o tenemos en la cabeza esas
dependencias para compilar sólo lo que hace falta, o lo
compilamos todo. Si el proyecto es grande, se nos olvidará
alguna dependencia o nos pasaremos horas compilando.
●Nos guarda los comandos de compilación con todos sus
parámetros para encontrar librerías, ficheros de cabecera (.h),
etc, etc. No tendremos que escribir largas líneas de compilación
con montones de opciones que debemos saber de memoria o, al
menos, sólo tendremos que hacerlo una vez.
Abraham Zamudio 43
45. Makefiles (1º Acto)
Lo compilaremos de la forma habitual.
$ gcc HolaMundo.c -o HolaMundo
Abraham Zamudio 45
46. Makefiles (1º Acto)
Lo probamos y ¡funciona!. Nada espectacular
hasta ahora. Vuelve a compilarlo con el mismo
comando. Se vuelve a compilar y sigue
funcionando.
Veamos ahora con make. Si haces
$ make HolaMundo
Abraham Zamudio 46
47. Makefiles (1º Acto)
Pues make te dirá que no hay nada que hacer.
Primera diferencia con compilar a mano. Como el
programa ya está hecho, make no hace nada.
Esto, en un programa de muchas líneas de
código que tarda varios minutos en compilar, es
una gran ventaja.
Abraham Zamudio 47
48. Makefiles (1º Acto)
Borra el ejecutable y vuelve a hacer make
$ rm HolaMundo
$ make HolaMundo
Abraham Zamudio 48
49. Makefiles (2º Acto)
Crear dos directorios :
● PRINCIPAL : HolaMundo.c
● FUNCION1 : texto1.h
Abraham Zamudio 49
51. Makefiles (2º Acto)
Ahora nos metemos en el directorio PRINCIPAL y
hacemos, como antes make HolaMundo. Como
es de esperar, obtenemos un error. No sabe
encontrar el fichero texto.h, puesto que no está en
los directorios por defecto de búsqueda de
ficheros .h.
Abraham Zamudio 51
52. Makefiles (2º Acto)
Una variable bastante interesante es CFLAGS
(CPPFLAGS para el compilador de C++). Esta variable
puede contener las opciones que queramos que se
pasen al compilador. Por ejemplo, si hacermos
$ CFLAGS=-g; export CFLAGS
$ make HolaMundo
veremos cómo al compilar el fichero HolaMundo se le
pasa al compilador la opción -g (para poder meter luego
el debugger).
Abraham Zamudio 52
53. Makefiles (2º Acto)
Una de las opciones que se puede pasar al
compilador es la opción -I, que nos permite poner
paths de busqueda para ficheros de cabecera
(.h). En nuestro ejemplo, y usando un path
relativo, deberíamos poner algo así como
-I../FUNCION1. Vamos a ello:
$ CFLAGS=-I../FUNCION1; export CFLAGS
$ make HolaMundo
Abraham Zamudio 53
54. Makefiles (3º Acto)
Pongamos ahora en el directorio FUNCION1 dos
ficheros. Un funcion1.h y un funcion1.c. El
contenido de estos ficheros sería:
funcion1.h funcion1.c
void escribeHolaMundo(); #include <stdio.h>
void escribeHolaMundo()
{
El fichero texto.h podemos printf ("Hola Mundon");
borrarlo porque ya no nos servirá }
más.
Abraham Zamudio 54
55. Makefiles (3º Acto)
En cuanto al programa en el directorio
PRINCIPAL, lo modificamos para que ponga esto:
HolaMundo.c
#include <funcion1.h>
main()
{
escribeHolaMundo ();
}
Abraham Zamudio 55
56. Makefiles (3º Acto)
Desde el directorio PRINCIPAL ponemos nuestra variable
CFLAGS como antes y hacemos el make.
$ CFLAGS=-I../FUNCION1; export CLFAGS
$ make HolaMundo
Obtenemos otra vez un error. make compila el fichero
HolaMundo.c, no compila el fichero funcion1.c y obtenemos
un error. Esto ya es demasiado para resolverlo con variables
de entorno. En el momento que tenemos dos ficheros .c para
construir un único ejecutable, necesitamos decirle a make
cuáles son los ficheros que debe compilar.
Abraham Zamudio 56
58. Creando Makefiles
●objetivo es lo que queremos construir. Puede ser el nombre de un ejecutable,
el nombre de una librería o cualquier palabra que nos inventemos. Para
nuestro ejemplo, podemos poner que nuestro objetivo es el nombre de nuestro
ejecutable, es decir HolaMundo.
●dependencia<i> es el nombre de otro objetivo que debe hacerse antes que el
nuestro o bien ficheros de los que depende nuestro objetivo. En nuestro
ejemplo, las dependencias serían nuestros ficheros fuente HolaMundo.c,
../FUNCION1/funcion1.h y ../FUNCION1/funcion1.c ya que para hacer el
ejecutable necesitamos todos esos fuentes y si los tocamos, posiblemente
debamos rehacer el ejecutable.
●<tab> es un tabulador. Es importante que ahi pongamos un tabulador, porque
si no el fichero no se lee correctamente.
●comando<i> es lo que se tiene que ejecutar para construir nuestro objetivo. Se
irán ejecutando estos comandos en secuencia. Puede ser cualquier comando
de shell válido. (cc, rm, cp, ls, o incluso un script que nos hayamos hecho). En
nuestro ejemplo, sería cc HolaMundo.c -o HolaMundo.
Abraham Zamudio 58
59. Creando Makefiles
HolaMundo: HolaMundo.c ../FUNCION1/funcion1.c ../FUNCION1/funcion1.h
gcc -I../FUNCION1 HolaMundo.c ../FUNCION1/funcion1.c -o HolaMundo
Ahora, después de borrar el ejecutable, si hacemos make (a secas, sin parámetro), se
volverá a compilar nuestro programa. Si a make no le ponemos parámetro, buscará un
fichero Makefile y dentro de él hará el primer objetivo que encuentre. En nuestro caso, el
único que hay es HolaMundo.
Abraham Zamudio 59