El lenguaje de programación C (Transparencias) (C) Javier Miranda 1996-2004 Reservados todos los derechos Esta colección de transparencias forma parte del contenido del libro “Diseño de Software con C y UNIX (Volumen 1)”, J.Miranda (1996), con ISBN 84-87526-45-4. 18 de febrero de 2004 18 de febrero de 2004 Transp. 1 Historia 1965: Multics (MIT, General Electric, Laboratorios Bell). 1968: Thompson desarrolla Unix para DEC PDP-7 (8k, sin software). 1969: Thompson crea B. 1970: Thompson continua desarrollo de Unix sobre DEC PDP-11 (24k). 1971: Unix comienza a tener usuarios. Thompson desarrolla de NB. 1973: Creación de C. Thompson reescribe Unix en C. Instala C en otras arquitecturas. 1978: The C programming language. Kernighan, Ritchie. Johnson desarrolla pcc. 1979: Johnson desarrolla lint. 1983: Creación comite para creación del estándar de C. 1989: C se convierte en estándar ISO/IEC 9899-1990 1986: Stroustrup crea C++. 18 de febrero de 2004 Transp. 2 El compilador de C Fichero fuente Preprocesador Otros ficheros (include) Compilador Ensamblador Fichero objeto Bibliotecas del sistema Enlazador Fichero ejecutable Ficheros objeto del usuario 18 de febrero de 2004 Transp. 3 El preprocesador de C #define * Macros simples #define NUM 15 /* Numero de elementos */ #define TOTAL 2*NUM/4 #define MENSAJE "El lenguaje C" * Macros con parámetros #define INTERCAMBIA(X,Y) {\\ int tmp = X;\\ X=Y;\\ Y=X;} * Operador # #define ESCRIBE(X) printf(#X "=%d",X) #undef #define NUM 15 . . . #undef NUM #define NUM 34 18 de febrero de 2004 Transp. 4 El preprocesador de C Compilación condicional (#if #ifdef #ifndef #else #elif #endif) #define DEBUG 1 #define INTEL ... ... int OUT(...) { #ifdef INTEL ... #endif #ifdef VAX ... #endif ... } int distancia(...) { ... #if DEBUG printf(...); #endif ... } #include #include "fichero.h" #include <fichero.h> #line #line 300 "PRUEBA.PAS" ... ... #line 301 18 de febrero de 2004 Transp. 5 Introducción /* Ejemplo de introduccion a la programacion en C */ #include <stdio.h> int Suma (a,b) int a,b; { int tmp; tmp = a + b; return tmp; } void Resta(a,b,Resultado) int a,b; int *Resultado; { *Resultado = a - b; } int main() { int a,b = 0; int Respuesta; scanf("%d %d", &a, &b); Respuesta = Suma(a,b); printf("La suma de %d y %d es %d ", a, b, Respuesta); Resta(a, b, &Respuesta); printf("y la resta es %d\n", Respuesta); exit (0); } 18 de febrero de 2004 Transp. 6 Tipos de datos y constantes char Tipos de datos int cualificadores float short long unsigned double char ascii octal Salto de línea (LF) \n Tabulador horizontal \t Tabulador vertical \v Retorno de carro (CR) \r decimal Salto de página (FF) \f octal Alarma \a hexadecimal Barra invertida \\ Interrogación \? Apóstrofo \’ Comillas \" hexadecimal string Constantes int float Secuencias de escape 18 de febrero de 2004 Transp. 7 Operadores Operadores Aritméticos + − * / % Relacionales < <= > >= == != Lógicos && || ! nivel bits & | ^ << >> ~ Autoincremento, autodecremento Asignación Múltiple Operador coma Precedencia de operadores ( ) [ ] −> . ! ~ ++ −− + − * & (tipo) sizeof() * / % + − << >> < <= > >= == != & ^ | && || ?: = += −= etc. , a=b=c=d Compuesta Expresión condicional ++ −− a op= b e1 ? e2 : e3 e1 , e2 Asociatividad 18 de febrero de 2004 Transp. 8 Ejemplo con operadores main() { int a,b,c,d,e,max,abs; char c; } a = - b + c * d / (e % f); /* Aritmeticos */ a = ((b > c) == (d <= e)); /* Relacionales */ a = ! ( (a && b) || c ); /* Logicos */ a = ~ ( (a & b) | c); /* Logicos nivel bit */ a++; b = ++a; c = a++; d = a--; /* Autoincremento */ /* Autodecremento */ a = b = c = d+e; a += 2; a /= b + c; /* Asignacion multiple */ /* Asignacion compuesta */ max = (b>c) ? b : c ; abs = (a>0) ? a : -a ; /* Expresion condicional*/ a = (b=2,c=3); /* Operador coma */ a = sizeof(b); /* Operador "sizeof()" */ c = (char) a; d = (int) c + d; d = (int) (c+d); /* Conversion de tipos */ 18 de febrero de 2004 Transp. 9 Control de flujo Control de flujo * if (expresión) sentencia [else sentencia] * switch (expresión) { { case expresión−constante: sentencia } [ default: sentencia ] } * while (expresión) sentencia * do * for (expresión−1; expresión−2; expresión−3) sentencia * break * continue * goto sentencia while (expresión) 18 de febrero de 2004 Transp. 10 Funciones int f1(s) char s[]; { float f2(int,float); /* Formato K&R */ ... if (...) return(0); ... } float f2(int a, float b) { ... if (a>0) f2(a,b); ... } main() { ... } /* Formato ANSI-C */ 18 de febrero de 2004 Transp. 11 Variables Fichero 1: int a,b; extern char c; static char d; /* Externa */ /* Externa definida en otro fichero */ /* Estatica externa */ int f1() { int c; static char d; extern float e; /* Externa */ /* Automatica */ /* Interna estatica */ /* Externa definida en otro fichero */ ... } Fichero 2: char c; float e; /* Externa */ /* Externa */ static int f2() { register i; /* Externa estatica */ ... { int i; ... } ... } /* Registro */ /* Automatica */ 18 de febrero de 2004 Transp. 12 EJEMPLO.ADA package ejemplo is a,b,c:integer; function f1(x,y:integer) return integer; ... end ejemplo; package body ejemplo is d,e:integer; function f1(x,y:integer) return integer is aux:integer; begin ... end; procedure p1(z:character) is begin ... for i in 1..N loop ... end loop; ... end; end; EJEMPLO.C int a,b,c; static int d,e; int f1(int x,y) { int aux; ... } static void p1(char z) { ... { register i; for (i=1;i<n;i++) { ... } } ... } 18 de febrero de 2004 Transp. 13 Entrada/Salida #include <stdio.h> main() { char ch = \’{A}’; char *p = &ch; int n = 1234; int m = 0; float f = 3.1416; char s1[50],s2[50],s3[50]; /* Entrada/Salida basica */ putchar(’\n’); ch=getchar(); /* Entrada/Salida formateada */ printf("Entero %d, Octal %o, Hexadecimal %x, ",n,n,n); printf("Caracter \’%c\’, ",ch); printf("Doble %f, Puntero %p\n",f,p); printf("Introduce un numero: "); scanf("%d",&n); ch=getchar(); printf("Correcto (S/N) ?"); ch=getchar(); sprintf(s1,"Pongo %d en la string",n); sscanf(s1,"%s %d %s",s2,&n,s3); printf("%s %d %s\n",s2,n,s3); } 18 de febrero de 2004 Transp. 14 Estructuras de datos Sinónimo (alias) typedef int longitud; typedef char string; ... longitud maxlen,auxlen; string nombre[20]; int maxlen,auxlen; char nombre[20]; Enumerado Declaración enum boolean {FALSE,TRUE}; enum meses {ENE = 1, FEB, MAR, ABR, MAY, JUN, JUL, AGO, SEP, OCT, NOV, DIC }; enum escapes {NEWLINE = ’\n’, BACKSPACE = ’\b’}; boolean b; meses tabla[23]; Acceso b = FALSE; tabla[12] = OCT; 18 de febrero de 2004 Transp. 15 Estructuras de datos Array Declaración int a[25] char s[]="123"; int lista[3] /*char s[]={’1’,’2’,’3’,’\0’}*/ = {12,4,-2}; int tabla[2][4] = { {1,2,3,4}, {5,6,7,8} }; Acceso s[0] lista[2] tabla[i][j] 18 de febrero de 2004 Transp. 16 Estructuras de datos Estructura (Registro) Declaración struct { int id; char nombre[20]; struct { int dia; int mes; int anyo; } fecha_ingreso; } x,empleados[30]; struct fecha { int dia; int mes; int anyo; } struct info { int id; char nombre[20]; struct fecha fecha_ingreso; } struct info x,empleados[30]; Acceso x.id empleados[i].nombre; empleados[i].fecha_ingreso.dia 18 de febrero de 2004 Transp. 17 Estructuras de datos Union union u_tag int float char } { i; f; c; Campos de bit #define INTERRUPCION 1 #define DMA 2 #define MOTOR_ON 4 main() { int control; flags |= INTERRUPCION; flags &= ~DMA); } struct { unsigned interrupcion :1; unsigned dma :1; unsigned motor_on :1; } control; main() { control.interrupcion = 1; control.dma = 0; } 18 de febrero de 2004 Transp. 18 Punteros void swap(px,py) int *px,*py; { int tmp; tmp = *px; *px = *py; *py = tmp; } main() { int x,y; int *p1; int *p2 = 0; int **p3; void swap(); x /* NULL */ = 27; p1 = &x; y = *p1; y = *p1 + 1; printf("%d\n", *p1); *p1 = 0; *p1 += 1; (*p1)++; if (p2 != p1) p2 = p1; *p3 = p1; swap(&y,*p3); } 18 de febrero de 2004 Transp. 19 Punteros: arrays y funciones struct registro_persona { char nombre[15]; int dia,mes,anyo; } void f(tabla); int tabla[2][4]; { ... } /* int tabla[][4] o int(*tabla)[4] */ main() { struct registro_persona tabla[18]; struct registro_persona *ptr, aux; int matriz[2][4]; int i; int (*fnc)(); ptr = &tabla; aux = *ptr; aux = *(ptr+3); ptr++; i = ptr->dia; f(matriz); fnc = &f; (*fnc)(matriz); } /* Cuidado con (*ptr+3) */ /* (*ptr).dia */ 18 de febrero de 2004 Transp. 20 Punteros: strlen() strlen(s) char s[]; { int n; /* VERSION 1 */ for (n=0; s[n] != ’\0’; n++); return(n); } strlen(s) char *s; { int n; /* VERSION 2 */ for (n=0; *s != ’\0’; s++, n++); return(n); } strlen(s) /* VERSION 3 */ char *s; { char *p = s; while (*p != ’\0’) p++; return(p-s); } strlen(s) /* VERSION 4 */ char *s; { char *p = s; while (*p) p++; return(p-s); } 18 de febrero de 2004 Transp. 21 Parámetros lı́nea comandos main(argc, argv) int argc; char *argv[]; { int i; /* Version 1 */ for (i=1;i<argc;i++) /* Procesar argv[i] */ } main(argc, argv) /* Version 2 */ int argc; char **argv; { while (--argc) { /* Procesar *argv */ /* argv++ */ } } 18 de febrero de 2004 Transp. 22 Tratamiento de ficheros #include <stdio.h> main(int argc, char *argv[]) { FILE *f1,*f2; int c; if (argc != 3) { fprintf(stderr,"Sintaxis: copy exit(1); } if ( (f1 = fopen(argv[1],"r")) == fprintf(stderr,"ERROR: Fichero exit(2); } if ( (f2 = fopen(argv[2],"w")) == fprintf(stderr,"ERROR:No puedo exit(2); } while ( (c= getc(f1)) != EOF ) putc(c,f2); fclose(f1); fclose(f2); } origen destino\n"); NULL) { ’%s’ inexistente.",argv[1]); NULL) { crear ’%s’.",argv[1]); 18 de febrero de 2004 Transp. 23 Errores frecuentes de los programadores de C 1. Realizar una comparación con =. if (i=3) return 1; else return 0; 2. Anidar comentarios. /* Comento este fragmento de codigo if (a==4) /* Si elijo la opcion 4 */ f(a); */ 3. Añadir ; al final de una sentencia de control de flujo. while (i<100); s=s+a[i]; 4. Indentar mal el programa. if (a) if (b) f(); else g(); if (a) j = 1; k = 0; int* ptr1, ptr2; 5. Utilizar mal los operadores de autoincremento/autodecremento. a[i++] = i++; 6. Equivocar el orden de evaluación de expresiones. if (fp=fopen(fichero,"r") == NULL) return (NULL); 18 de febrero de 2004 Transp. 24 Errores frecuentes de los programadores de C 7. Pasar el valor de una variable en vez de su dirección. scanf("%d",i); 8. Sobrepasar el lı́mite de un array. 9. Confundir “\n” con’\n’. 10. Declarar mal los parámetros de una función. invertir(str) { char *str; ... } 11. Especificar un directorio mediante .̃ fopen("~/datos.dat","r"); 12. Utilizar un puntero sin haberle asignado memoria. char *respuesta; ... gets(respuesta); 18 de febrero de 2004 Transp. 25 ¿ Dónde está el error ? Programa 1: #include <stdio.h> #include <stdlib.h> main() { int i; for (i=0;i<10;i=i+1); printf("i vale %d\n",i); } Programa 2: #include <stdio.h> #include <stdlib.h> main() { int i,numeros[10]; for (i=1;i<=10;i++) numeros[i]=i; for (i=1;i<=10;i++) printf("numeros[%d]=%d\n", i, numeros[i]); } 18 de febrero de 2004 Transp. 26 ¿ Dónde está el error ? Programa 3: #include <stdio.h> #include <stdlib.h> main() { int i; for (i=0;i<10;i=i+1) if (i=2) printf("i vale 2\n"); else printf("i no vale 2\n"); } Programa 4: #include <stdio.h> #include <stdlib.h> main() { int i; for (i=0;i<10;i=i+1) switch (i) { case 0: printf("i vale 0\n"); case 1: printf("i vale 1\n"); default: printf("i es mayor que 1\n"); } } 18 de febrero de 2004 Transp. 27 Programación de estructuras de datos dinámicas con C Existen dos formas de declarar el nodo: • Método 1: struct nodo { int info; struct nodo *siguiente; } • Método 2: typedef struct nodo Nodo; typedef Nodo *PtrNodo; struct nodo { int info; PtrNodo siguiente; }; Debe utilizarse la biblioteca stdlib (#include<stdlib>) para tener acceso a: void *malloc(int Numero_bytes) void free(void *p) 18 de febrero de 2004 Transp. 28 Pila (LIFO) #define PILA_VACIA -99999 PtrNodo top = NULL; void Push(int n) { PtrNodo p; p = (PtrNodo) malloc (sizeof(Nodo)); p->info = n; p->siguiente = top; top = p; } int Pop() { int aux_n; PtrNodo aux_p; if (top) { aux_n = top->info; aux_p = top; top = top->siguiente; free(aux_p); return(aux_n); } return(PILA_VACIA); } 18 de febrero de 2004 Transp. 29 Cola (FIFO) #define COLA_VACIA -99999 PtrNodo primero, ultimo = NULL; void Insertar(int n) { PtrNodo p; p = (PtrNodo) malloc p->info = n; p->siguiente = NULL; if (!primero) ultimo = primero else { ultimo->siguiente ultimo } (sizeof(Nodo)); = p; = p; = p; } int Extraer() { int n; PtrNodo p_aux; if (!primero) return(COLA_VACIA); else { n = primero->info; p_aux = primero->siguiente; free(primero); primero = p_aux; if (!primero) ultimo=NULL; /* La cola queda vacia */ return(n); } } 18 de febrero de 2004 Transp. 30 Lista simplemente encadenada PtrNodo primero=NULL; void Insertar(int n) { PtrNodo aux_p, anterior, nuevo; nuevo = (PtrNodo) malloc (sizeof(Nodo)); nuevo->info = n; if (!primero) { /*Lista vacia*/ nuevo->siguiente=NULL; primero = nuevo; return; } else { anterior = NULL; aux_p = primero; while (aux_p) { if (aux_p->info < n) { /*Busqueda*/ anterior = aux_p; aux_p = aux_p->siguiente; } else if (!anterior) { /*Ins. principio*/ nuevo->siguiente = primero; primero = nuevo; return; } else { anterior->siguiente = nuevo; /*Ins. medio*/ nuevo->siguiente = aux_p; return; } } anterior->siguiente = nuevo; /* Ins. final */ nuevo->siguiente = NULL; return; } } 18 de febrero de 2004 Transp. 31 Lista simplemente encadenada PtrNodo Buscar(int n,PtrNodo *anterior) { PtrNodo aux_p; *anterior=NULL; if (!primero) return(NULL); aux_p = primero; while (aux_p->info != n) { *anterior = aux_p; aux_p = aux_p->siguiente; if (!aux_p) return(NULL); } return(aux_p); } int Borrar(int n) { PtrNodo aux_p,anterior; aux_p = Buscar(n, &anterior); if (!aux_p) return (0); if (!anterior) { /*Era el primero*/ primero = aux_p->siguiente; free(aux_p); } else { /*No era el primero*/ anterior->siguiente = aux_p->siguiente; free(aux_p); } return(1); } 18 de febrero de 2004 Transp. 32 Lista doblemente encadenada PtrNodo primero, ultimo = NULL; Insertar(int n) { PtrNodo aux_p, anterior, nuevo; nuevo = (PtrNodo) malloc (sizeof(Nodo)); nuevo->info = n; if (!primero) { /* Lista vacia /* nuevo->izquierda = NULL; nuevo->derecha = NULL; primero = nuevo; ultimo = nuevo; return; } aux_p = primero; while(aux_p) if (aux_p->info < n) aux_p = aux_p->next; else if (aux_p == primero) { /* Ins. al principio */ nuevo->izquierda = NULL; nuevo->derecha = primero; primero->izquierda = nuevo; primero = nuevo; return; } else { /* Ins. en medio */ nuevo->izquierda = aux_p->izquierda; nuevo->derecha = aux_p; aux_p->izquierda = nuevo; nuevo->izquierda->derecha=nuevo; return; } ultimo->derecha = nuevo; /* Ins. al final */ nuevo->izquierda = ultimo; nuevo->derecha = NULL; ultimo = nuevo; return; } 18 de febrero de 2004 Transp. 33 Arbol binario Recorrido in order iterativo void r_in_order (PtrNodo p) { PtrNodo PILA[MAX_NODOS]; do { while (p) { Push(p); p=p->left; } p=Pop; visitar(p); p=p->right; } while (PILA<>{0}); } Recorrido in order recursivo void r_in_order (PtrNodo p) { if (p->left) r_in_order(p->left); printf("%d ",p->info); if (p->right) r_in_order(p->right); } /*Visitar(p)*/ 18 de febrero de 2004 Transp. 34 Arbol binario int Insertar(int n) { PtrNodo padre,nuevo,aux_p; int dir; nuevo = (PtrNodo) malloc (sizeof(Nodo)); nuevo->info = n; nuevo->izquierda = NULL; nuevo->derecha = NULL; if (!raiz) { /*Arbol vacio*/ raiz = nuevo; return(1); } aux_p = raiz; do { if (n == aux_p->info) free(nuevo); return(0); /*clave duplicada*/ else { padre=aux_p; if (n < aux_p->info) { aux_p = aux_p->izquierda; dir=0; } else { aux_p = aux_p->derecha; dir=1; } } } while (aux_p); if (dir == 0) padre->izquierda=nuevo; else padre->derecha=nuevo; return(1); }